summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS4
-rw-r--r--Documentation/ABI/testing/sysfs-bus-mei7
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb6
-rw-r--r--Documentation/ABI/testing/sysfs-class-net-mesh8
-rw-r--r--Documentation/ABI/testing/sysfs-devices-lpss_ltr44
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power_resources_wakeup13
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu12
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-isku12
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure105
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-acpi26
-rw-r--r--Documentation/DocBook/80211.tmpl2
-rw-r--r--Documentation/DocBook/device-drivers.tmpl2
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml52
-rw-r--r--Documentation/DocBook/media/v4l/common.xml14
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml24
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml87
-rw-r--r--Documentation/DocBook/media/v4l/io.xml6
-rw-r--r--Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml10
-rw-r--r--Documentation/DocBook/media/v4l/subdev-formats.xml206
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml19
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml9
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml223
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml29
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml240
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enuminput.xml5
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enumoutput.xml5
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml113
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml9
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml78
-rw-r--r--Documentation/DocBook/media_api.tmpl1
-rw-r--r--Documentation/RCU/checklist.txt26
-rw-r--r--Documentation/RCU/lockdep.txt5
-rw-r--r--Documentation/RCU/rcubarrier.txt15
-rw-r--r--Documentation/RCU/stallwarn.txt33
-rw-r--r--Documentation/RCU/whatisRCU.txt4
-rw-r--r--Documentation/SubmittingPatches9
-rw-r--r--Documentation/arm/sunxi/clocks.txt56
-rw-r--r--Documentation/backlight/lp855x-driver.txt7
-rw-r--r--Documentation/cgroups/00-INDEX2
-rw-r--r--Documentation/cgroups/cgroups.txt3
-rw-r--r--Documentation/cgroups/devices.txt70
-rw-r--r--Documentation/cgroups/memory.txt72
-rw-r--r--Documentation/cgroups/net_cls.txt34
-rw-r--r--Documentation/clk.txt15
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt9
-rw-r--r--Documentation/cpu-freq/governors.txt27
-rw-r--r--Documentation/cpuidle/driver.txt6
-rw-r--r--Documentation/device-mapper/dm-raid.txt84
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-adc.txt13
-rw-r--r--Documentation/devicetree/bindings/arm/msm/ssbi.txt18
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt60
-rw-r--r--Documentation/devicetree/bindings/ata/imx-pata.txt17
-rw-r--r--Documentation/devicetree/bindings/clock/axi-clkgen.txt22
-rw-r--r--Documentation/devicetree/bindings/clock/fixed-factor-clock.txt24
-rw-r--r--Documentation/devicetree/bindings/clock/silabs,si5351.txt114
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt151
-rw-r--r--Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt65
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt2
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt28
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio.txt6
-rw-r--r--Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt29
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt2
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt2
-rw-r--r--Documentation/devicetree/bindings/iio/iio-bindings.txt97
-rw-r--r--Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt16
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/auo_pixcir_ts.txt30
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt24
-rw-r--r--Documentation/devicetree/bindings/leds/tca6507.txt2
-rw-r--r--Documentation/devicetree/bindings/marvell.txt3
-rw-r--r--Documentation/devicetree/bindings/media/coda.txt30
-rw-r--r--Documentation/devicetree/bindings/media/exynos-fimc-lite.txt14
-rw-r--r--Documentation/devicetree/bindings/media/exynos4-fimc-is.txt49
-rw-r--r--Documentation/devicetree/bindings/media/samsung-fimc.txt197
-rw-r--r--Documentation/devicetree/bindings/media/samsung-mipi-csis.txt81
-rw-r--r--Documentation/devicetree/bindings/media/video-interfaces.txt228
-rw-r--r--Documentation/devicetree/bindings/metag/meta-intc.txt2
-rw-r--r--Documentation/devicetree/bindings/mfd/mc13xxx.txt36
-rw-r--r--Documentation/devicetree/bindings/misc/sram.txt16
-rw-r--r--Documentation/devicetree/bindings/net/can/atmel-can.txt14
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt16
-rw-r--r--Documentation/devicetree/bindings/net/dsa/dsa.txt91
-rw-r--r--Documentation/devicetree/bindings/net/marvell-orion-mdio.txt4
-rw-r--r--Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt109
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt3
-rw-r--r--Documentation/devicetree/bindings/power_supply/power_supply.txt23
-rw-r--r--Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt2
-rw-r--r--Documentation/devicetree/bindings/power_supply/tps65090.txt17
-rw-r--r--Documentation/devicetree/bindings/regulator/max8952.txt52
-rw-r--r--Documentation/devicetree/bindings/regulator/max8997-regulator.txt2
-rw-r--r--Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt15
-rw-r--r--Documentation/devicetree/bindings/serio/snps-arc_ps2.txt16
-rw-r--r--Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt22
-rw-r--r--Documentation/devicetree/bindings/spi/fsl-spi.txt3
-rw-r--r--Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt26
-rw-r--r--Documentation/devicetree/bindings/spi/spi-samsung.txt8
-rw-r--r--Documentation/devicetree/bindings/staging/dwc2.txt15
-rw-r--r--Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt2
-rw-r--r--Documentation/devicetree/bindings/tty/serial/of-serial.txt4
-rw-r--r--Documentation/devicetree/bindings/usb/ci13xxx-imx.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/ehci-omap.txt32
-rw-r--r--Documentation/devicetree/bindings/usb/ohci-omap3.txt15
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt40
-rw-r--r--Documentation/devicetree/bindings/usb/samsung-usbphy.txt78
-rw-r--r--Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt34
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt2
-rw-r--r--Documentation/devicetree/bindings/video/backlight/lp855x.txt41
-rw-r--r--Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt27
-rw-r--r--Documentation/devicetree/bindings/video/via,vt8500-fb.txt48
-rw-r--r--Documentation/devicetree/bindings/video/wm,wm8505-fb.txt32
-rw-r--r--Documentation/dma-buf-sharing.txt13
-rw-r--r--Documentation/filesystems/ext4.txt21
-rw-r--r--Documentation/filesystems/vfat.txt26
-rw-r--r--Documentation/hwmon/ab850022
-rw-r--r--Documentation/hwmon/abx50028
-rw-r--r--Documentation/hwmon/adt741047
-rw-r--r--Documentation/hwmon/lm2506634
-rw-r--r--Documentation/hwmon/lm9523436
-rw-r--r--Documentation/hwmon/ltc2978143
-rw-r--r--Documentation/hwmon/nct6775188
-rw-r--r--Documentation/hwmon/sht152
-rw-r--r--Documentation/hwmon/tmp40125
-rw-r--r--Documentation/hwmon/zl61002
-rw-r--r--Documentation/ia64/err_inject.txt2
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/iostats.txt2
-rw-r--r--Documentation/kdump/kdump.txt1
-rw-r--r--Documentation/kernel-parameters.txt108
-rw-r--r--Documentation/md.txt16
-rw-r--r--Documentation/misc-devices/mei/mei-client-bus.txt138
-rw-r--r--Documentation/networking/ieee802154.txt5
-rw-r--r--Documentation/networking/ip-sysctl.txt53
-rw-r--r--Documentation/networking/netlink_mmap.txt339
-rw-r--r--Documentation/networking/packet_mmap.txt368
-rw-r--r--Documentation/networking/stmmac.txt45
-rw-r--r--Documentation/pinctrl.txt112
-rw-r--r--Documentation/printk-formats.txt2
-rw-r--r--Documentation/s390/s390dbf.txt3
-rw-r--r--Documentation/scsi/LICENSE.qla2xxx2
-rw-r--r--Documentation/security/Smack.txt11
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt5
-rw-r--r--Documentation/sysctl/vm.txt50
-rw-r--r--Documentation/sysrq.txt20
-rw-r--r--Documentation/this_cpu_ops.txt205
-rw-r--r--Documentation/trace/ftrace.txt2097
-rw-r--r--Documentation/trace/tracepoints.txt15
-rw-r--r--Documentation/trace/uprobetracer.txt114
-rw-r--r--Documentation/usb/power-management.txt10
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx3
-rw-r--r--Documentation/video4linux/CARDLIST.tuner3
-rw-r--r--Documentation/video4linux/si476x.txt187
-rw-r--r--Documentation/virtual/virtio-spec.txt6
-rw-r--r--Documentation/vm/overcommit-accounting8
-rw-r--r--Documentation/x86/x86_64/boot-options.txt14
-rw-r--r--Documentation/x86/x86_64/mm.txt4
-rw-r--r--MAINTAINERS246
-rw-r--r--Makefile9
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/alpha/Kconfig1
-rw-r--r--arch/alpha/Makefile2
-rw-r--r--arch/alpha/include/asm/floppy.h2
-rw-r--r--arch/alpha/include/asm/linkage.h4
-rw-r--r--arch/alpha/include/asm/thread_info.h2
-rw-r--r--arch/alpha/include/asm/unistd.h12
-rw-r--r--arch/alpha/include/uapi/asm/socket.h2
-rw-r--r--arch/alpha/kernel/irq.c7
-rw-r--r--arch/alpha/kernel/irq_alpha.c10
-rw-r--r--arch/alpha/kernel/process.c20
-rw-r--r--arch/alpha/kernel/smp.c3
-rw-r--r--arch/alpha/kernel/sys_nautilus.c10
-rw-r--r--arch/alpha/kernel/sys_titan.c14
-rw-r--r--arch/alpha/kernel/traps.c7
-rw-r--r--arch/alpha/mm/init.c24
-rw-r--r--arch/alpha/mm/numa.c3
-rw-r--r--arch/arc/include/asm/dma-mapping.h2
-rw-r--r--arch/arc/include/asm/elf.h3
-rw-r--r--arch/arc/include/asm/entry.h2
-rw-r--r--arch/arc/include/asm/irqflags.h12
-rw-r--r--arch/arc/include/asm/kgdb.h6
-rw-r--r--arch/arc/include/asm/ptrace.h2
-rw-r--r--arch/arc/include/asm/syscalls.h2
-rw-r--r--arch/arc/include/uapi/asm/ptrace.h4
-rw-r--r--arch/arc/kernel/disasm.c2
-rw-r--r--arch/arc/kernel/entry.S27
-rw-r--r--arch/arc/kernel/kgdb.c1
-rw-r--r--arch/arc/kernel/process.c27
-rw-r--r--arch/arc/kernel/setup.c4
-rw-r--r--arch/arc/kernel/smp.c2
-rw-r--r--arch/arc/kernel/stacktrace.c7
-rw-r--r--arch/arc/kernel/sys.c2
-rw-r--r--arch/arc/kernel/troubleshoot.c3
-rw-r--r--arch/arc/mm/init.c23
-rw-r--r--arch/arc/plat-arcfpga/Kconfig2
-rw-r--r--arch/arm/Kconfig42
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi2
-rw-r--r--arch/arm/boot/dts/armada-370-mirabox.dts2
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi6
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi40
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi40
-rw-r--r--arch/arm/boot/dts/at91sam9263ek.dts10
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi10
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi40
-rw-r--r--arch/arm/boot/dts/at91sam9m10g45ek.dts10
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi40
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts10
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi40
-rw-r--r--arch/arm/boot/dts/at91sam9x5ek.dtsi10
-rw-r--r--arch/arm/boot/dts/dbx5x0.dtsi4
-rw-r--r--arch/arm/boot/dts/imx28-m28evk.dts1
-rw-r--r--arch/arm/boot/dts/imx28-sps1.dts1
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi1
-rw-r--r--arch/arm/boot/dts/kirkwood-goflexnet.dts1
-rw-r--r--arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts14
-rw-r--r--arch/arm/boot/dts/msm8660-surf.dts6
-rw-r--r--arch/arm/boot/dts/msm8960-cdp.dts6
-rw-r--r--arch/arm/boot/dts/orion5x.dtsi9
-rw-r--r--arch/arm/boot/dts/spear1310.dtsi4
-rw-r--r--arch/arm/boot/dts/spear1340.dtsi4
-rw-r--r--arch/arm/boot/dts/spear310.dtsi4
-rw-r--r--arch/arm/boot/dts/spear320.dtsi4
-rw-r--r--arch/arm/boot/dts/vt8500-bv07.dts34
-rw-r--r--arch/arm/boot/dts/vt8500.dtsi4
-rw-r--r--arch/arm/boot/dts/wm8505-ref.dts34
-rw-r--r--arch/arm/boot/dts/wm8505.dtsi4
-rw-r--r--arch/arm/boot/dts/wm8650-mid.dts36
-rw-r--r--arch/arm/boot/dts/wm8650.dtsi4
-rw-r--r--arch/arm/boot/dts/wm8850-w70v2.dts40
-rw-r--r--arch/arm/boot/dts/wm8850.dtsi4
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig1
-rw-r--r--arch/arm/configs/kirkwood_defconfig1
-rw-r--r--arch/arm/configs/lpc32xx_defconfig1
-rw-r--r--arch/arm/configs/mxs_defconfig1
-rw-r--r--arch/arm/configs/omap1_defconfig1
-rw-r--r--arch/arm/include/asm/delay.h2
-rw-r--r--arch/arm/include/asm/glue-cache.h8
-rw-r--r--arch/arm/include/asm/hardware/iop3xx.h2
-rw-r--r--arch/arm/include/asm/highmem.h7
-rw-r--r--arch/arm/include/asm/mmu_context.h2
-rw-r--r--arch/arm/include/asm/pgtable-3level.h2
-rw-r--r--arch/arm/include/asm/pgtable.h9
-rw-r--r--arch/arm/include/asm/system_misc.h3
-rw-r--r--arch/arm/include/asm/tlbflush.h26
-rw-r--r--arch/arm/include/asm/unistd.h8
-rw-r--r--arch/arm/kernel/early_printk.c17
-rw-r--r--arch/arm/kernel/entry-common.S12
-rw-r--r--arch/arm/kernel/etm.c2
-rw-r--r--arch/arm/kernel/head.S2
-rw-r--r--arch/arm/kernel/hw_breakpoint.c8
-rw-r--r--arch/arm/kernel/perf_event.c5
-rw-r--r--arch/arm/kernel/process.c108
-rw-r--r--arch/arm/kernel/sched_clock.c4
-rw-r--r--arch/arm/kernel/setup.c27
-rw-r--r--arch/arm/kernel/smp.c5
-rw-r--r--arch/arm/kernel/smp_tlb.c66
-rw-r--r--arch/arm/kernel/tcm.c1
-rw-r--r--arch/arm/kernel/topology.c2
-rw-r--r--arch/arm/kernel/traps.c7
-rw-r--r--arch/arm/kvm/arm.c3
-rw-r--r--arch/arm/kvm/coproc.c4
-rw-r--r--arch/arm/kvm/vgic.c35
-rw-r--r--arch/arm/lib/delay.c8
-rw-r--r--arch/arm/mach-at91/at91sam9260.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c2
-rw-r--r--arch/arm/mach-at91/at91sam9n12.c2
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c2
-rw-r--r--arch/arm/mach-at91/cpuidle.c18
-rw-r--r--arch/arm/mach-bcm/Kconfig1
-rw-r--r--arch/arm/mach-bcm/board_bcm.c7
-rw-r--r--arch/arm/mach-cns3xxx/core.c16
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/cns3xxx.h16
-rw-r--r--arch/arm/mach-davinci/Makefile1
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c71
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c166
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c8
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c2
-rw-r--r--arch/arm/mach-davinci/cpuidle.c29
-rw-r--r--arch/arm/mach-davinci/davinci.h11
-rw-r--r--arch/arm/mach-davinci/dm355.c174
-rw-r--r--arch/arm/mach-davinci/dm365.c195
-rw-r--r--arch/arm/mach-davinci/dm644x.c11
-rw-r--r--arch/arm/mach-davinci/pm_domain.c2
-rw-r--r--arch/arm/mach-ep93xx/include/mach/uncompress.h10
-rw-r--r--arch/arm/mach-exynos/Kconfig2
-rw-r--r--arch/arm/mach-exynos/cpuidle.c1
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c27
-rw-r--r--arch/arm/mach-exynos/setup-usb-phy.c8
-rw-r--r--arch/arm/mach-gemini/idle.c4
-rw-r--r--arch/arm/mach-gemini/irq.c4
-rw-r--r--arch/arm/mach-highbank/hotplug.c10
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/clk-busy.c2
-rw-r--r--arch/arm/mach-imx/clk-imx35.c2
-rw-r--r--arch/arm/mach-imx/clk-imx6q.c3
-rw-r--r--arch/arm/mach-imx/common.h2
-rw-r--r--arch/arm/mach-imx/cpufreq.c8
-rw-r--r--arch/arm/mach-imx/cpuidle-imx5.c37
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c26
-rw-r--r--arch/arm/mach-imx/cpuidle.c80
-rw-r--r--arch/arm/mach-imx/cpuidle.h10
-rw-r--r--arch/arm/mach-imx/hotplug.c12
-rw-r--r--arch/arm/mach-imx/pm-imx5.c30
-rw-r--r--arch/arm/mach-imx/src.c12
-rw-r--r--arch/arm/mach-integrator/Makefile1
-rw-r--r--arch/arm/mach-ixp4xx/common.c3
-rw-r--r--arch/arm/mach-kirkwood/board-iomega_ix2_200.c7
-rw-r--r--arch/arm/mach-kirkwood/guruplug-setup.c2
-rw-r--r--arch/arm/mach-kirkwood/openrd-setup.c1
-rw-r--r--arch/arm/mach-kirkwood/rd88f6281-setup.c1
-rw-r--r--arch/arm/mach-mmp/aspenite.c6
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c6
-rw-r--r--arch/arm/mach-msm/timer.c5
-rw-r--r--arch/arm/mach-mvebu/irq-armada-370-xp.c26
-rw-r--r--arch/arm/mach-omap1/clock_data.c12
-rw-r--r--arch/arm/mach-omap1/pm.c6
-rw-r--r--arch/arm/mach-omap2/cclock44xx_data.c20
-rw-r--r--arch/arm/mach-omap2/common.h8
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c52
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c84
-rw-r--r--arch/arm/mach-omap2/io.c18
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c14
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c14
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c7
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c12
-rw-r--r--arch/arm/mach-omap2/pm.c14
-rw-r--r--arch/arm/mach-omap2/pm44xx.c4
-rw-r--r--arch/arm/mach-omap2/timer.c4
-rw-r--r--arch/arm/mach-orion5x/board-dt.c3
-rw-r--r--arch/arm/mach-orion5x/common.c2
-rw-r--r--arch/arm/mach-pxa/Makefile6
-rw-r--r--arch/arm/mach-pxa/include/mach/generic.h1
-rw-r--r--arch/arm/mach-s3c24xx/clock-s3c2440.c5
-rw-r--r--arch/arm/mach-s3c24xx/common.c5
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq.c8
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/irqs.h4
-rw-r--r--arch/arm/mach-s3c24xx/irq.c2
-rw-r--r--arch/arm/mach-s3c64xx/cpuidle.c15
-rw-r--r--arch/arm/mach-s3c64xx/setup-usb-phy.c4
-rw-r--r--arch/arm/mach-s5pv210/setup-usb-phy.c4
-rw-r--r--arch/arm/mach-sa1100/Kconfig26
-rw-r--r--arch/arm/mach-sa1100/Makefile3
-rw-r--r--arch/arm/mach-sa1100/include/mach/generic.h1
-rw-r--r--arch/arm/mach-shark/core.c3
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c15
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c8
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c12
-rw-r--r--arch/arm/mach-shmobile/cpuidle.c23
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h3
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c6
-rw-r--r--arch/arm/mach-shmobile/suspend.c6
-rw-r--r--arch/arm/mach-tegra/Kconfig8
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra114.c28
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c72
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c29
-rw-r--r--arch/arm/mach-ux500/board-mop500-regulators.c774
-rw-r--r--arch/arm/mach-ux500/board-mop500-regulators.h7
-rw-r--r--arch/arm/mach-ux500/board-mop500-sdi.c1
-rw-r--r--arch/arm/mach-ux500/board-mop500.c17
-rw-r--r--arch/arm/mach-ux500/board-mop500.h1
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c5
-rw-r--r--arch/arm/mach-ux500/cpuidle.c58
-rw-r--r--arch/arm/mach-vexpress/Kconfig3
-rw-r--r--arch/arm/mach-vexpress/Makefile2
-rw-r--r--arch/arm/mach-vexpress/v2m.c13
-rw-r--r--arch/arm/mach-w90x900/dev.c3
-rw-r--r--arch/arm/mm/Kconfig5
-rw-r--r--arch/arm/mm/Makefile1
-rw-r--r--arch/arm/mm/cache-feroceon-l2.c1
-rw-r--r--arch/arm/mm/cache-l2x0.c11
-rw-r--r--arch/arm/mm/cache-v3.S137
-rw-r--r--arch/arm/mm/cache-v4.S2
-rw-r--r--arch/arm/mm/context.c3
-rw-r--r--arch/arm/mm/init.c50
-rw-r--r--arch/arm/mm/mmu.c75
-rw-r--r--arch/arm/mm/proc-arm740.S30
-rw-r--r--arch/arm/mm/proc-arm920.S2
-rw-r--r--arch/arm/mm/proc-arm926.S2
-rw-r--r--arch/arm/mm/proc-mohawk.S2
-rw-r--r--arch/arm/mm/proc-sa1100.S2
-rw-r--r--arch/arm/mm/proc-syms.c2
-rw-r--r--arch/arm/mm/proc-v6.S2
-rw-r--r--arch/arm/mm/proc-v7.S19
-rw-r--r--arch/arm/mm/proc-xsc3.S2
-rw-r--r--arch/arm/mm/proc-xscale.S2
-rw-r--r--arch/arm/mm/tcm.h (renamed from arch/arm/kernel/tcm.h)0
-rw-r--r--arch/arm/net/bpf_jit_32.c5
-rw-r--r--arch/arm/plat-orion/common.c54
-rw-r--r--arch/arm/plat-samsung/devs.c10
-rw-r--r--arch/arm/plat-samsung/include/plat/fb.h50
-rw-r--r--arch/arm/plat-samsung/include/plat/regs-serial.h282
-rw-r--r--arch/arm/plat-samsung/include/plat/usb-phy.h5
-rw-r--r--arch/arm64/Kconfig11
-rw-r--r--arch/arm64/boot/dts/Makefile2
-rw-r--r--arch/arm64/boot/dts/foundation-v8.dts230
-rw-r--r--arch/arm64/boot/dts/rtsm_ve-aemv8a.dts159
-rw-r--r--arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi234
-rw-r--r--arch/arm64/boot/dts/skeleton.dtsi13
-rw-r--r--arch/arm64/configs/defconfig4
-rw-r--r--arch/arm64/include/asm/Kbuild2
-rw-r--r--arch/arm64/include/asm/bitops.h18
-rw-r--r--arch/arm64/include/asm/cmpxchg.h3
-rw-r--r--arch/arm64/include/asm/compat.h22
-rw-r--r--arch/arm64/include/asm/cputype.h30
-rw-r--r--arch/arm64/include/asm/esr.h55
-rw-r--r--arch/arm64/include/asm/exception.h1
-rw-r--r--arch/arm64/include/asm/hardirq.h5
-rw-r--r--arch/arm64/include/asm/io.h4
-rw-r--r--arch/arm64/include/asm/irq.h1
-rw-r--r--arch/arm64/include/asm/smp_plat.h (renamed from arch/arm64/lib/bitops.c)25
-rw-r--r--arch/arm64/include/asm/string.h37
-rw-r--r--arch/arm64/kernel/arm64ksyms.c21
-rw-r--r--arch/arm64/kernel/early_printk.c35
-rw-r--r--arch/arm64/kernel/entry.S53
-rw-r--r--arch/arm64/kernel/head.S4
-rw-r--r--arch/arm64/kernel/irq.c19
-rw-r--r--arch/arm64/kernel/process.c58
-rw-r--r--arch/arm64/kernel/setup.c12
-rw-r--r--arch/arm64/kernel/smp.c115
-rw-r--r--arch/arm64/kernel/smp_psci.c5
-rw-r--r--arch/arm64/kernel/sys32.S7
-rw-r--r--arch/arm64/kernel/traps.c7
-rw-r--r--arch/arm64/lib/Makefile4
-rw-r--r--arch/arm64/lib/bitops.S68
-rw-r--r--arch/arm64/lib/memchr.S44
-rw-r--r--arch/arm64/lib/memcpy.S53
-rw-r--r--arch/arm64/lib/memmove.S57
-rw-r--r--arch/arm64/lib/memset.S53
-rw-r--r--arch/arm64/lib/strchr.S42
-rw-r--r--arch/arm64/lib/strrchr.S43
-rw-r--r--arch/arm64/mm/fault.c6
-rw-r--r--arch/arm64/mm/init.c26
-rw-r--r--arch/arm64/mm/mmu.c15
-rw-r--r--arch/avr32/Kconfig13
-rw-r--r--arch/avr32/configs/atngw100_defconfig2
-rw-r--r--arch/avr32/configs/atngw100_evklcd100_defconfig2
-rw-r--r--arch/avr32/configs/atngw100_evklcd101_defconfig2
-rw-r--r--arch/avr32/configs/atngw100_mrmt_defconfig2
-rw-r--r--arch/avr32/configs/atngw100mkii_defconfig2
-rw-r--r--arch/avr32/configs/atngw100mkii_evklcd100_defconfig2
-rw-r--r--arch/avr32/configs/atngw100mkii_evklcd101_defconfig2
-rw-r--r--arch/avr32/configs/atstk1002_defconfig2
-rw-r--r--arch/avr32/configs/atstk1003_defconfig2
-rw-r--r--arch/avr32/configs/atstk1004_defconfig2
-rw-r--r--arch/avr32/configs/atstk1006_defconfig2
-rw-r--r--arch/avr32/configs/favr-32_defconfig2
-rw-r--r--arch/avr32/configs/hammerhead_defconfig2
-rw-r--r--arch/avr32/configs/mimc200_defconfig2
-rw-r--r--arch/avr32/include/asm/io.h4
-rw-r--r--arch/avr32/include/asm/unistd.h8
-rw-r--r--arch/avr32/include/uapi/asm/socket.h2
-rw-r--r--arch/avr32/kernel/process.c26
-rw-r--r--arch/avr32/kernel/time.c9
-rw-r--r--arch/avr32/mach-at32ap/Makefile1
-rw-r--r--arch/avr32/mach-at32ap/include/mach/pm.h24
-rw-r--r--arch/avr32/mach-at32ap/pm-at32ap700x.S7
-rw-r--r--arch/avr32/mm/init.c24
-rw-r--r--arch/blackfin/include/asm/bfin_sport3.h2
-rw-r--r--arch/blackfin/include/asm/unistd.h8
-rw-r--r--arch/blackfin/kernel/dumpstack.c1
-rw-r--r--arch/blackfin/kernel/early_printk.c2
-rw-r--r--arch/blackfin/kernel/process.c32
-rw-r--r--arch/blackfin/kernel/trace.c2
-rw-r--r--arch/blackfin/mach-bf609/boards/ezkit.c8
-rw-r--r--arch/blackfin/mach-common/Makefile1
-rw-r--r--arch/blackfin/mach-common/smp.c2
-rw-r--r--arch/blackfin/mm/init.c22
-rw-r--r--arch/c6x/include/asm/irqflags.h2
-rw-r--r--arch/c6x/kernel/process.c28
-rw-r--r--arch/c6x/kernel/traps.c10
-rw-r--r--arch/c6x/mm/init.c30
-rw-r--r--arch/cris/arch-v10/kernel/process.c6
-rw-r--r--arch/cris/arch-v32/kernel/process.c15
-rw-r--r--arch/cris/arch-v32/kernel/smp.c4
-rw-r--r--arch/cris/arch-v32/mach-a3/Makefile1
-rw-r--r--arch/cris/arch-v32/mach-fs/Makefile1
-rw-r--r--arch/cris/include/asm/processor.h7
-rw-r--r--arch/cris/include/asm/unistd.h8
-rw-r--r--arch/cris/include/uapi/asm/socket.h2
-rw-r--r--arch/cris/kernel/process.c49
-rw-r--r--arch/cris/kernel/traps.c7
-rw-r--r--arch/cris/mm/init.c16
-rw-r--r--arch/frv/include/asm/unistd.h10
-rw-r--r--arch/frv/include/uapi/asm/socket.h2
-rw-r--r--arch/frv/kernel/process.c27
-rw-r--r--arch/frv/kernel/traps.c14
-rw-r--r--arch/frv/mm/init.c38
-rw-r--r--arch/h8300/include/asm/linkage.h2
-rw-r--r--arch/h8300/include/asm/unistd.h7
-rw-r--r--arch/h8300/include/uapi/asm/socket.h2
-rw-r--r--arch/h8300/kernel/process.c37
-rw-r--r--arch/h8300/kernel/traps.c7
-rw-r--r--arch/h8300/mm/init.c30
-rw-r--r--arch/hexagon/Kconfig33
-rw-r--r--arch/hexagon/Makefile17
-rw-r--r--arch/hexagon/include/asm/Kbuild2
-rw-r--r--arch/hexagon/include/asm/atomic.h22
-rw-r--r--arch/hexagon/include/asm/elf.h23
-rw-r--r--arch/hexagon/include/asm/hexagon_vm.h56
-rw-r--r--arch/hexagon/include/asm/io.h16
-rw-r--r--arch/hexagon/include/asm/mem-layout.h28
-rw-r--r--arch/hexagon/include/asm/page.h12
-rw-r--r--arch/hexagon/include/asm/processor.h51
-rw-r--r--arch/hexagon/include/asm/vm_mmu.h11
-rw-r--r--arch/hexagon/include/uapi/asm/ptrace.h5
-rw-r--r--arch/hexagon/include/uapi/asm/registers.h17
-rw-r--r--arch/hexagon/include/uapi/asm/signal.h4
-rw-r--r--arch/hexagon/include/uapi/asm/unistd.h3
-rw-r--r--arch/hexagon/include/uapi/asm/user.h6
-rw-r--r--arch/hexagon/kernel/Makefile2
-rw-r--r--arch/hexagon/kernel/asm-offsets.c5
-rw-r--r--arch/hexagon/kernel/dma.c27
-rw-r--r--arch/hexagon/kernel/head.S107
-rw-r--r--arch/hexagon/kernel/kgdb.c4
-rw-r--r--arch/hexagon/kernel/process.c65
-rw-r--r--arch/hexagon/kernel/ptrace.c26
-rw-r--r--arch/hexagon/kernel/setup.c9
-rw-r--r--arch/hexagon/kernel/signal.c45
-rw-r--r--arch/hexagon/kernel/smp.c2
-rw-r--r--arch/hexagon/kernel/topology.c52
-rw-r--r--arch/hexagon/kernel/traps.c44
-rw-r--r--arch/hexagon/kernel/vm_entry.S282
-rw-r--r--arch/hexagon/kernel/vm_events.c6
-rw-r--r--arch/hexagon/kernel/vm_vectors.S4
-rw-r--r--arch/hexagon/kernel/vmlinux.lds.S12
-rw-r--r--arch/hexagon/mm/init.c35
-rw-r--r--arch/hexagon/mm/vm_fault.c4
-rw-r--r--arch/ia64/Kconfig9
-rw-r--r--arch/ia64/hp/sim/simserial.c16
-rw-r--r--arch/ia64/include/asm/futex.h5
-rw-r--r--arch/ia64/include/asm/hugetlb.h1
-rw-r--r--arch/ia64/include/asm/irqflags.h1
-rw-r--r--arch/ia64/include/asm/linkage.h4
-rw-r--r--arch/ia64/include/asm/mca.h1
-rw-r--r--arch/ia64/include/asm/numa.h5
-rw-r--r--arch/ia64/include/asm/thread_info.h2
-rw-r--r--arch/ia64/include/asm/unistd.h10
-rw-r--r--arch/ia64/include/uapi/asm/socket.h2
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/cpufreq/Kconfig29
-rw-r--r--arch/ia64/kernel/cpufreq/Makefile2
-rw-r--r--arch/ia64/kernel/fsys.S49
-rw-r--r--arch/ia64/kernel/iosapic.c34
-rw-r--r--arch/ia64/kernel/irq.c8
-rw-r--r--arch/ia64/kernel/mca.c37
-rw-r--r--arch/ia64/kernel/mca_drv.c2
-rw-r--r--arch/ia64/kernel/perfmon.c14
-rw-r--r--arch/ia64/kernel/process.c95
-rw-r--r--arch/ia64/kernel/setup.c1
-rw-r--r--arch/ia64/kernel/smpboot.c2
-rw-r--r--arch/ia64/kvm/vtlb.c2
-rw-r--r--arch/ia64/mm/contig.c2
-rw-r--r--arch/ia64/mm/discontig.c9
-rw-r--r--arch/ia64/mm/init.c23
-rw-r--r--arch/ia64/mm/ioremap.c14
-rw-r--r--arch/ia64/mm/numa.c20
-rw-r--r--arch/ia64/pci/pci.c11
-rw-r--r--arch/ia64/sn/kernel/tiocx.c5
-rw-r--r--arch/m32r/include/asm/unistd.h10
-rw-r--r--arch/m32r/include/uapi/asm/socket.h2
-rw-r--r--arch/m32r/kernel/process.c20
-rw-r--r--arch/m32r/kernel/smpboot.c2
-rw-r--r--arch/m32r/kernel/traps.c15
-rw-r--r--arch/m32r/mm/init.c26
-rw-r--r--arch/m68k/Kconfig.bus10
-rw-r--r--arch/m68k/Kconfig.devices24
-rw-r--r--arch/m68k/atari/ataints.c152
-rw-r--r--arch/m68k/atari/config.c239
-rw-r--r--arch/m68k/include/asm/atarihw.h6
-rw-r--r--arch/m68k/include/asm/atariints.h11
-rw-r--r--arch/m68k/include/asm/cmpxchg.h3
-rw-r--r--arch/m68k/include/asm/delay.h23
-rw-r--r--arch/m68k/include/asm/gpio.h20
-rw-r--r--arch/m68k/include/asm/io_mm.h136
-rw-r--r--arch/m68k/include/asm/irq.h6
-rw-r--r--arch/m68k/include/asm/raw_io.h109
-rw-r--r--arch/m68k/include/asm/string.h14
-rw-r--r--arch/m68k/include/asm/unistd.h8
-rw-r--r--arch/m68k/kernel/process.c32
-rw-r--r--arch/m68k/kernel/setup_mm.c6
-rw-r--r--arch/m68k/kernel/traps.c12
-rw-r--r--arch/m68k/lib/string.c2
-rw-r--r--arch/m68k/mm/init.c24
-rw-r--r--arch/metag/Kconfig4
-rw-r--r--arch/metag/Makefile2
-rw-r--r--arch/metag/boot/dts/Makefile10
-rw-r--r--arch/metag/configs/meta1_defconfig1
-rw-r--r--arch/metag/configs/meta2_defconfig1
-rw-r--r--arch/metag/configs/meta2_smp_defconfig1
-rw-r--r--arch/metag/include/asm/metag_mem.h3
-rw-r--r--arch/metag/include/asm/thread_info.h2
-rw-r--r--arch/metag/include/uapi/asm/Kbuild1
-rw-r--r--arch/metag/include/uapi/asm/ech.h15
-rw-r--r--arch/metag/kernel/cachepart.c16
-rw-r--r--arch/metag/kernel/da.c2
-rw-r--r--arch/metag/kernel/head.S8
-rw-r--r--arch/metag/kernel/perf/perf_event.c74
-rw-r--r--arch/metag/kernel/process.c37
-rw-r--r--arch/metag/kernel/ptrace.c34
-rw-r--r--arch/metag/kernel/setup.c1
-rw-r--r--arch/metag/kernel/smp.c117
-rw-r--r--arch/metag/kernel/traps.c6
-rw-r--r--arch/metag/mm/Kconfig3
-rw-r--r--arch/metag/mm/init.c31
-rw-r--r--arch/metag/oprofile/Makefile17
-rw-r--r--arch/metag/oprofile/backtrace.c63
-rw-r--r--arch/metag/oprofile/backtrace.h6
-rw-r--r--arch/metag/oprofile/common.c66
-rw-r--r--arch/microblaze/Kconfig4
-rw-r--r--arch/microblaze/include/asm/processor.h5
-rw-r--r--arch/microblaze/include/asm/setup.h1
-rw-r--r--arch/microblaze/include/asm/thread_info.h1
-rw-r--r--arch/microblaze/include/asm/unistd.h8
-rw-r--r--arch/microblaze/kernel/early_printk.c26
-rw-r--r--arch/microblaze/kernel/process.c67
-rw-r--r--arch/microblaze/kernel/traps.c6
-rw-r--r--arch/microblaze/mm/init.c34
-rw-r--r--arch/mips/Kconfig20
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c5
-rw-r--r--arch/mips/bcm63xx/dev-spi.c11
-rw-r--r--arch/mips/bcm63xx/nvram.c7
-rw-r--r--arch/mips/bcm63xx/setup.c2
-rw-r--r--arch/mips/cavium-octeon/setup.c5
-rw-r--r--arch/mips/include/asm/hugetlb.h1
-rw-r--r--arch/mips/include/asm/linkage.h3
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h1
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h4
-rw-r--r--arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h4
-rw-r--r--arch/mips/include/asm/mipsregs.h209
-rw-r--r--arch/mips/include/asm/page.h2
-rw-r--r--arch/mips/include/asm/signal.h2
-rw-r--r--arch/mips/include/asm/unistd.h8
-rw-r--r--arch/mips/include/uapi/asm/signal.h8
-rw-r--r--arch/mips/include/uapi/asm/socket.h2
-rw-r--r--arch/mips/kernel/Makefile27
-rw-r--r--arch/mips/kernel/cpu-probe.c13
-rw-r--r--arch/mips/kernel/cpufreq/Kconfig41
-rw-r--r--arch/mips/kernel/cpufreq/Makefile5
-rw-r--r--arch/mips/kernel/early_printk.c12
-rw-r--r--arch/mips/kernel/linux32.c119
-rw-r--r--arch/mips/kernel/mcount.S11
-rw-r--r--arch/mips/kernel/proc.c2
-rw-r--r--arch/mips/kernel/process.c48
-rw-r--r--arch/mips/kernel/scall64-n32.S8
-rw-r--r--arch/mips/kernel/scall64-o32.S6
-rw-r--r--arch/mips/kernel/smp.c2
-rw-r--r--arch/mips/kernel/traps.c17
-rw-r--r--arch/mips/lib/bitops.c16
-rw-r--r--arch/mips/lib/csum_partial.S4
-rw-r--r--arch/mips/mm/c-r4k.c6
-rw-r--r--arch/mips/mm/init.c37
-rw-r--r--arch/mips/mm/sc-mips.c6
-rw-r--r--arch/mips/pci/pci-alchemy.c4
-rw-r--r--arch/mips/pci/pci.c8
-rw-r--r--arch/mips/sgi-ip27/ip27-memory.c4
-rw-r--r--arch/mn10300/include/asm/thread_info.h2
-rw-r--r--arch/mn10300/include/asm/unistd.h10
-rw-r--r--arch/mn10300/include/uapi/asm/socket.h2
-rw-r--r--arch/mn10300/kernel/process.c71
-rw-r--r--arch/mn10300/kernel/smp.c7
-rw-r--r--arch/mn10300/kernel/traps.c11
-rw-r--r--arch/mn10300/mm/init.c23
-rw-r--r--arch/openrisc/Kconfig3
-rw-r--r--arch/openrisc/include/asm/thread_info.h2
-rw-r--r--arch/openrisc/kernel/Makefile2
-rw-r--r--arch/openrisc/kernel/idle.c73
-rw-r--r--arch/openrisc/kernel/process.c1
-rw-r--r--arch/openrisc/kernel/traps.c11
-rw-r--r--arch/openrisc/mm/init.c27
-rw-r--r--arch/parisc/Kconfig1
-rw-r--r--arch/parisc/Kconfig.debug14
-rw-r--r--arch/parisc/Makefile6
-rw-r--r--arch/parisc/include/asm/cacheflush.h5
-rw-r--r--arch/parisc/include/asm/pgtable.h47
-rw-r--r--arch/parisc/include/asm/thread_info.h2
-rw-r--r--arch/parisc/include/asm/uaccess.h14
-rw-r--r--arch/parisc/include/asm/unistd.h8
-rw-r--r--arch/parisc/include/uapi/asm/socket.h2
-rw-r--r--arch/parisc/kernel/cache.c5
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c2
-rw-r--r--arch/parisc/kernel/process.c22
-rw-r--r--arch/parisc/kernel/smp.c2
-rw-r--r--arch/parisc/kernel/sys_parisc32.c41
-rw-r--r--arch/parisc/kernel/syscall_table.S8
-rw-r--r--arch/parisc/kernel/traps.c10
-rw-r--r--arch/parisc/lib/Makefile3
-rw-r--r--arch/parisc/lib/ucmpdi2.c25
-rw-r--r--arch/parisc/mm/init.c25
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/include/asm/hugetlb.h1
-rw-r--r--arch/powerpc/include/asm/linkage.h13
-rw-r--r--arch/powerpc/include/asm/systbl.h10
-rw-r--r--arch/powerpc/include/asm/thread_info.h2
-rw-r--r--arch/powerpc/include/asm/unistd.h6
-rw-r--r--arch/powerpc/include/asm/uprobes.h1
-rw-r--r--arch/powerpc/include/uapi/asm/linkage.h6
-rw-r--r--arch/powerpc/include/uapi/asm/socket.h2
-rw-r--r--arch/powerpc/kernel/crash_dump.c5
-rw-r--r--arch/powerpc/kernel/entry_64.S4
-rw-r--r--arch/powerpc/kernel/epapr_paravirt.c6
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S144
-rw-r--r--arch/powerpc/kernel/fadump.c5
-rw-r--r--arch/powerpc/kernel/idle.c89
-rw-r--r--arch/powerpc/kernel/kvm.c7
-rw-r--r--arch/powerpc/kernel/nvram_64.c3
-rw-r--r--arch/powerpc/kernel/process.c16
-rw-r--r--arch/powerpc/kernel/signal_32.c2
-rw-r--r--arch/powerpc/kernel/signal_64.c2
-rw-r--r--arch/powerpc/kernel/smp.c2
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c109
-rw-r--r--arch/powerpc/kernel/tm.S2
-rw-r--r--arch/powerpc/kernel/udbg.c6
-rw-r--r--arch/powerpc/kernel/uprobes.c29
-rw-r--r--arch/powerpc/kvm/book3s_pr.c2
-rw-r--r--arch/powerpc/kvm/e500.h24
-rw-r--r--arch/powerpc/kvm/e500_mmu_host.c84
-rw-r--r--arch/powerpc/kvm/e500mc.c7
-rw-r--r--arch/powerpc/mm/init_64.c11
-rw-r--r--arch/powerpc/mm/mem.c35
-rw-r--r--arch/powerpc/mm/numa.c10
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c12
-rw-r--r--arch/powerpc/platforms/44x/Kconfig2
-rw-r--r--arch/powerpc/platforms/512x/Kconfig2
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_shared.c5
-rw-r--r--arch/powerpc/platforms/cell/Kconfig26
-rw-r--r--arch/powerpc/platforms/cell/Makefile3
-rw-r--r--arch/powerpc/platforms/chrp/pegasos_eth.c20
-rw-r--r--arch/powerpc/platforms/pasemi/cpufreq.c5
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c14
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c5
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c12
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c8
-rw-r--r--arch/powerpc/platforms/pseries/processor_idle.c34
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c16
-rw-r--r--arch/powerpc/xmon/xmon.c2
-rw-r--r--arch/s390/Kconfig15
-rw-r--r--arch/s390/Kconfig.debug14
-rw-r--r--arch/s390/Makefile10
-rw-r--r--arch/s390/hypfs/hypfs_dbfs.c4
-rw-r--r--arch/s390/include/asm/bitops.h117
-rw-r--r--arch/s390/include/asm/ccwdev.h3
-rw-r--r--arch/s390/include/asm/cio.h2
-rw-r--r--arch/s390/include/asm/compat.h57
-rw-r--r--arch/s390/include/asm/elf.h23
-rw-r--r--arch/s390/include/asm/hugetlb.h56
-rw-r--r--arch/s390/include/asm/io.h4
-rw-r--r--arch/s390/include/asm/pci.h1
-rw-r--r--arch/s390/include/asm/pci_debug.h9
-rw-r--r--arch/s390/include/asm/pci_insn.h203
-rw-r--r--arch/s390/include/asm/pci_io.h16
-rw-r--r--arch/s390/include/asm/pgtable.h105
-rw-r--r--arch/s390/include/asm/processor.h3
-rw-r--r--arch/s390/include/asm/ptrace.h6
-rw-r--r--arch/s390/include/asm/syscall.h1
-rw-r--r--arch/s390/include/asm/thread_info.h6
-rw-r--r--arch/s390/include/asm/unistd.h8
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h20
-rw-r--r--arch/s390/include/uapi/asm/socket.h2
-rw-r--r--arch/s390/include/uapi/asm/statfs.h63
-rw-r--r--arch/s390/kernel/Makefile17
-rw-r--r--arch/s390/kernel/asm-offsets.c1
-rw-r--r--arch/s390/kernel/compat_linux.c86
-rw-r--r--arch/s390/kernel/compat_linux.h5
-rw-r--r--arch/s390/kernel/compat_signal.c2
-rw-r--r--arch/s390/kernel/compat_wrapper.S64
-rw-r--r--arch/s390/kernel/dis.c9
-rw-r--r--arch/s390/kernel/dumpstack.c212
-rw-r--r--arch/s390/kernel/entry.S39
-rw-r--r--arch/s390/kernel/entry.h1
-rw-r--r--arch/s390/kernel/entry64.S43
-rw-r--r--arch/s390/kernel/irq.c2
-rw-r--r--arch/s390/kernel/machine_kexec.c30
-rw-r--r--arch/s390/kernel/process.c32
-rw-r--r--arch/s390/kernel/setup.c9
-rw-r--r--arch/s390/kernel/smp.c18
-rw-r--r--arch/s390/kernel/suspend.c31
-rw-r--r--arch/s390/kernel/swsusp_asm64.S29
-rw-r--r--arch/s390/kernel/sys_s390.c14
-rw-r--r--arch/s390/kernel/syscalls.S18
-rw-r--r--arch/s390/kernel/traps.c250
-rw-r--r--arch/s390/kernel/vtime.c5
-rw-r--r--arch/s390/kvm/trace.h4
-rw-r--r--arch/s390/lib/Makefile1
-rw-r--r--arch/s390/lib/uaccess_pt.c83
-rw-r--r--arch/s390/lib/usercopy.c8
-rw-r--r--arch/s390/mm/cmm.c8
-rw-r--r--arch/s390/mm/fault.c9
-rw-r--r--arch/s390/mm/hugetlbpage.c2
-rw-r--r--arch/s390/mm/init.c45
-rw-r--r--arch/s390/mm/pageattr.c24
-rw-r--r--arch/s390/mm/pgtable.c235
-rw-r--r--arch/s390/mm/vmem.c15
-rw-r--r--arch/s390/net/bpf_jit_comp.c3
-rw-r--r--arch/s390/oprofile/init.c1
-rw-r--r--arch/s390/pci/Makefile4
-rw-r--r--arch/s390/pci/pci.c153
-rw-r--r--arch/s390/pci/pci_clp.c13
-rw-r--r--arch/s390/pci/pci_debug.c7
-rw-r--r--arch/s390/pci/pci_dma.c9
-rw-r--r--arch/s390/pci/pci_insn.c202
-rw-r--r--arch/s390/pci/pci_msi.c10
-rw-r--r--arch/score/kernel/process.c18
-rw-r--r--arch/score/kernel/traps.c12
-rw-r--r--arch/score/mm/init.c33
-rw-r--r--arch/sh/Kconfig22
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c4
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c2
-rw-r--r--arch/sh/include/asm/hugetlb.h1
-rw-r--r--arch/sh/include/asm/suspend.h4
-rw-r--r--arch/sh/include/asm/thread_info.h2
-rw-r--r--arch/sh/include/asm/unistd.h8
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c101
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm.c3
-rw-r--r--arch/sh/kernel/dumpstack.c6
-rw-r--r--arch/sh/kernel/idle.c101
-rw-r--r--arch/sh/kernel/process_32.c6
-rw-r--r--arch/sh/kernel/process_64.c1
-rw-r--r--arch/sh/kernel/sh_bios.c4
-rw-r--r--arch/sh/kernel/smp.c2
-rw-r--r--arch/sh/mm/init.c26
-rw-r--r--arch/sparc/Kconfig26
-rw-r--r--arch/sparc/include/asm/Kbuild5
-rw-r--r--arch/sparc/include/asm/cputime.h6
-rw-r--r--arch/sparc/include/asm/emergency-restart.h6
-rw-r--r--arch/sparc/include/asm/hugetlb.h1
-rw-r--r--arch/sparc/include/asm/mutex.h9
-rw-r--r--arch/sparc/include/asm/pgtable_64.h1
-rw-r--r--arch/sparc/include/asm/serial.h6
-rw-r--r--arch/sparc/include/asm/smp_32.h5
-rw-r--r--arch/sparc/include/asm/switch_to_64.h3
-rw-r--r--arch/sparc/include/asm/thread_info_32.h2
-rw-r--r--arch/sparc/include/asm/thread_info_64.h2
-rw-r--r--arch/sparc/include/asm/tlbflush_64.h37
-rw-r--r--arch/sparc/include/asm/unistd.h8
-rw-r--r--arch/sparc/include/uapi/asm/Kbuild1
-rw-r--r--arch/sparc/include/uapi/asm/socket.h2
-rw-r--r--arch/sparc/include/uapi/asm/types.h17
-rw-r--r--arch/sparc/kernel/Makefile3
-rw-r--r--arch/sparc/kernel/hvtramp.S3
-rw-r--r--arch/sparc/kernel/process_32.c44
-rw-r--r--arch/sparc/kernel/process_64.c55
-rw-r--r--arch/sparc/kernel/smp_32.c2
-rw-r--r--arch/sparc/kernel/smp_64.c43
-rw-r--r--arch/sparc/kernel/sys32.S4
-rw-r--r--arch/sparc/kernel/sys_sparc32.c75
-rw-r--r--arch/sparc/kernel/sys_sparc_64.c6
-rw-r--r--arch/sparc/kernel/systbls_64.S8
-rw-r--r--arch/sparc/kernel/trampoline_64.S3
-rw-r--r--arch/sparc/kernel/traps_64.c7
-rw-r--r--arch/sparc/lib/Makefile1
-rw-r--r--arch/sparc/lib/bitext.c6
-rw-r--r--arch/sparc/mm/init_32.c12
-rw-r--r--arch/sparc/mm/init_64.c7
-rw-r--r--arch/sparc/mm/iommu.c2
-rw-r--r--arch/sparc/mm/srmmu.c4
-rw-r--r--arch/sparc/mm/tlb.c39
-rw-r--r--arch/sparc/mm/tsb.c57
-rw-r--r--arch/sparc/mm/ultra.S119
-rw-r--r--arch/sparc/net/bpf_jit_comp.c6
-rw-r--r--arch/tile/Kconfig26
-rw-r--r--arch/tile/include/asm/atomic.h21
-rw-r--r--arch/tile/include/asm/hugetlb.h1
-rw-r--r--arch/tile/include/asm/irqflags.h10
-rw-r--r--arch/tile/include/asm/ptrace.h3
-rw-r--r--arch/tile/include/asm/syscall.h6
-rw-r--r--arch/tile/include/asm/syscalls.h6
-rw-r--r--arch/tile/include/asm/thread_info.h10
-rw-r--r--arch/tile/include/asm/uaccess.h7
-rw-r--r--arch/tile/include/uapi/asm/unistd.h2
-rw-r--r--arch/tile/kernel/compat.c6
-rw-r--r--arch/tile/kernel/early_printk.c27
-rw-r--r--arch/tile/kernel/intvec_32.S10
-rw-r--r--arch/tile/kernel/intvec_64.S24
-rw-r--r--arch/tile/kernel/process.c68
-rw-r--r--arch/tile/kernel/ptrace.c39
-rw-r--r--arch/tile/kernel/setup.c25
-rw-r--r--arch/tile/kernel/smpboot.c4
-rw-r--r--arch/tile/kernel/time.c6
-rw-r--r--arch/tile/lib/uaccess.c8
-rw-r--r--arch/tile/mm/pgtable.c7
-rw-r--r--arch/um/drivers/chan_kern.c6
-rw-r--r--arch/um/drivers/line.c8
-rw-r--r--arch/um/kernel/early_printk.c8
-rw-r--r--arch/um/kernel/mem.c26
-rw-r--r--arch/um/kernel/process.c27
-rw-r--r--arch/um/kernel/sysrq.c12
-rw-r--r--arch/um/sys-ppc/sysrq.c2
-rw-r--r--arch/unicore32/kernel/Makefile1
-rw-r--r--arch/unicore32/kernel/early_printk.c12
-rw-r--r--arch/unicore32/kernel/process.c27
-rw-r--r--arch/unicore32/kernel/traps.c6
-rw-r--r--arch/unicore32/mm/init.c31
-rw-r--r--arch/unicore32/mm/ioremap.c17
-rw-r--r--arch/x86/Kconfig95
-rw-r--r--arch/x86/Kconfig.debug16
-rw-r--r--arch/x86/boot/compressed/Makefile5
-rw-r--r--arch/x86/boot/compressed/eboot.c47
-rw-r--r--arch/x86/boot/compressed/head_64.S2
-rw-r--r--arch/x86/ia32/Makefile3
-rw-r--r--arch/x86/ia32/ia32_aout.c1
-rw-r--r--arch/x86/ia32/ipc32.c54
-rw-r--r--arch/x86/ia32/sys_ia32.c37
-rw-r--r--arch/x86/include/asm/bug.h3
-rw-r--r--arch/x86/include/asm/cmpxchg.h2
-rw-r--r--arch/x86/include/asm/context_tracking.h21
-rw-r--r--arch/x86/include/asm/cpufeature.h23
-rw-r--r--arch/x86/include/asm/efi.h7
-rw-r--r--arch/x86/include/asm/fixmap.h7
-rw-r--r--arch/x86/include/asm/hugetlb.h1
-rw-r--r--arch/x86/include/asm/hypervisor.h16
-rw-r--r--arch/x86/include/asm/mce.h4
-rw-r--r--arch/x86/include/asm/msr.h14
-rw-r--r--arch/x86/include/asm/page_64_types.h1
-rw-r--r--arch/x86/include/asm/paravirt.h9
-rw-r--r--arch/x86/include/asm/paravirt_types.h4
-rw-r--r--arch/x86/include/asm/perf_event_p4.h62
-rw-r--r--arch/x86/include/asm/pgtable_types.h1
-rw-r--r--arch/x86/include/asm/processor.h25
-rw-r--r--arch/x86/include/asm/suspend_32.h1
-rw-r--r--arch/x86/include/asm/suspend_64.h3
-rw-r--r--arch/x86/include/asm/sys_ia32.h12
-rw-r--r--arch/x86/include/asm/syscall.h4
-rw-r--r--arch/x86/include/asm/syscalls.h4
-rw-r--r--arch/x86/include/asm/thread_info.h2
-rw-r--r--arch/x86/include/asm/tlb.h2
-rw-r--r--arch/x86/include/asm/unistd.h8
-rw-r--r--arch/x86/include/asm/uprobes.h1
-rw-r--r--arch/x86/include/asm/xen/hypercall.h4
-rw-r--r--arch/x86/include/uapi/asm/bootparam.h1
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h6
-rw-r--r--arch/x86/kernel/acpi/sleep.c2
-rw-r--r--arch/x86/kernel/acpi/wakeup_32.S5
-rw-r--r--arch/x86/kernel/alternative.c2
-rw-r--r--arch/x86/kernel/amd_nb.c5
-rw-r--r--arch/x86/kernel/aperture_64.c2
-rw-r--r--arch/x86/kernel/apm_32.c1
-rw-r--r--arch/x86/kernel/cpu/Makefile9
-rw-r--r--arch/x86/kernel/cpu/amd.c48
-rw-r--r--arch/x86/kernel/cpu/bugs.c34
-rw-r--r--arch/x86/kernel/cpu/common.c4
-rw-r--r--arch/x86/kernel/cpu/cyrix.c5
-rw-r--r--arch/x86/kernel/cpu/intel.c34
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c39
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_intel.c25
-rw-r--r--arch/x86/kernel/cpu/mkcapflags.pl48
-rw-r--r--arch/x86/kernel/cpu/mkcapflags.sh41
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c18
-rw-r--r--arch/x86/kernel/cpu/perf_event.c89
-rw-r--r--arch/x86/kernel/cpu/perf_event.h56
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c138
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_uncore.c547
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c58
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c185
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c876
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h64
-rw-r--r--arch/x86/kernel/cpu/perf_event_knc.c4
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c9
-rw-r--r--arch/x86/kernel/cpu/perf_event_p6.c2
-rw-r--r--arch/x86/kernel/cpu/proc.c6
-rw-r--r--arch/x86/kernel/cpu/scattered.c3
-rw-r--r--arch/x86/kernel/doublefault_32.c2
-rw-r--r--arch/x86/kernel/dumpstack.c28
-rw-r--r--arch/x86/kernel/dumpstack_32.c4
-rw-r--r--arch/x86/kernel/dumpstack_64.c6
-rw-r--r--arch/x86/kernel/early_printk.c21
-rw-r--r--arch/x86/kernel/head64.c6
-rw-r--r--arch/x86/kernel/kprobes/core.c6
-rw-r--r--arch/x86/kernel/kvm.c8
-rw-r--r--arch/x86/kernel/microcode_core_early.c38
-rw-r--r--arch/x86/kernel/paravirt.c26
-rw-r--r--arch/x86/kernel/process.c131
-rw-r--r--arch/x86/kernel/process_32.c2
-rw-r--r--arch/x86/kernel/process_64.c1
-rw-r--r--arch/x86/kernel/quirks.c18
-rw-r--r--arch/x86/kernel/rtc.c69
-rw-r--r--arch/x86/kernel/setup.c49
-rw-r--r--arch/x86/kernel/smpboot.c2
-rw-r--r--arch/x86/kernel/tls.c14
-rw-r--r--arch/x86/kernel/traps.c77
-rw-r--r--arch/x86/kernel/tsc.c6
-rw-r--r--arch/x86/kernel/uprobes.c29
-rw-r--r--arch/x86/kernel/vmlinux.lds.S4
-rw-r--r--arch/x86/kvm/lapic.c2
-rw-r--r--arch/x86/kvm/svm.c2
-rw-r--r--arch/x86/kvm/vmx.c2
-rw-r--r--arch/x86/kvm/x86.c13
-rw-r--r--arch/x86/lguest/Kconfig3
-rw-r--r--arch/x86/lguest/boot.c1
-rw-r--r--arch/x86/lib/checksum_32.S2
-rw-r--r--arch/x86/lib/memcpy_32.c6
-rw-r--r--arch/x86/lib/memcpy_64.S2
-rw-r--r--arch/x86/lib/memmove_64.S6
-rw-r--r--arch/x86/lib/usercopy_32.c6
-rw-r--r--arch/x86/mm/amdtopology.c3
-rw-r--r--arch/x86/mm/fault.c16
-rw-r--r--arch/x86/mm/highmem_32.c1
-rw-r--r--arch/x86/mm/init.c5
-rw-r--r--arch/x86/mm/init_32.c10
-rw-r--r--arch/x86/mm/init_64.c75
-rw-r--r--arch/x86/mm/ioremap.c7
-rw-r--r--arch/x86/mm/numa.c9
-rw-r--r--arch/x86/mm/pageattr-test.c7
-rw-r--r--arch/x86/mm/pageattr.c21
-rw-r--r--arch/x86/mm/pgtable.c7
-rw-r--r--arch/x86/net/bpf_jit_comp.c9
-rw-r--r--arch/x86/pci/common.c11
-rw-r--r--arch/x86/pci/xen.c6
-rw-r--r--arch/x86/platform/efi/efi.c211
-rw-r--r--arch/x86/platform/mrst/mrst.c3
-rw-r--r--arch/x86/platform/mrst/vrtc.c44
-rw-r--r--arch/x86/platform/olpc/olpc-xo1-sci.c4
-rw-r--r--arch/x86/platform/uv/uv_time.c3
-rw-r--r--arch/x86/power/cpu.c13
-rw-r--r--arch/x86/syscalls/syscall_32.tbl10
-rw-r--r--arch/x86/tools/Makefile1
-rw-r--r--arch/x86/tools/relocs.c783
-rw-r--r--arch/x86/tools/relocs.h36
-rw-r--r--arch/x86/tools/relocs_32.c17
-rw-r--r--arch/x86/tools/relocs_64.c17
-rw-r--r--arch/x86/tools/relocs_common.c76
-rw-r--r--arch/x86/um/tls_32.c5
-rw-r--r--arch/x86/xen/Kconfig2
-rw-r--r--arch/x86/xen/enlighten.c58
-rw-r--r--arch/x86/xen/mmu.c20
-rw-r--r--arch/x86/xen/smp.c23
-rw-r--r--arch/x86/xen/spinlock.c25
-rw-r--r--arch/x86/xen/time.c13
-rw-r--r--arch/xtensa/include/asm/unistd.h8
-rw-r--r--arch/xtensa/include/uapi/asm/socket.h2
-rw-r--r--arch/xtensa/kernel/process.c14
-rw-r--r--arch/xtensa/kernel/traps.c10
-rw-r--r--arch/xtensa/mm/init.c21
-rw-r--r--block/blk-cgroup.h2
-rw-r--r--block/blk-core.c1
-rw-r--r--block/blk-flush.c2
-rw-r--r--block/blk-sysfs.c2
-rw-r--r--block/genhd.c3
-rw-r--r--crypto/algif_hash.c2
-rw-r--r--crypto/algif_skcipher.c1
-rw-r--r--crypto/async_tx/raid6test.c9
-rw-r--r--crypto/gcm.c17
-rw-r--r--drivers/Kconfig6
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/acpi/Kconfig15
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_i2c.c2
-rw-r--r--drivers/acpi/acpi_lpss.c292
-rw-r--r--drivers/acpi/acpi_memhotplug.c328
-rw-r--r--drivers/acpi/acpi_pad.c2
-rw-r--r--drivers/acpi/acpi_platform.c40
-rw-r--r--drivers/acpi/acpica/Makefile2
-rw-r--r--drivers/acpi/acpica/acglobal.h5
-rw-r--r--drivers/acpi/acpica/aclocal.h29
-rw-r--r--drivers/acpi/acpica/acmacros.h6
-rw-r--r--drivers/acpi/acpica/acnamesp.h29
-rw-r--r--drivers/acpi/acpica/acpredef.h1305
-rw-r--r--drivers/acpi/acpica/acutils.h28
-rw-r--r--drivers/acpi/acpica/dsutils.c10
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/evevent.c12
-rw-r--r--drivers/acpi/acpica/evgpe.c6
-rw-r--r--drivers/acpi/acpica/evsci.c4
-rw-r--r--drivers/acpi/acpica/evxface.c21
-rw-r--r--drivers/acpi/acpica/evxfevnt.c12
-rw-r--r--drivers/acpi/acpica/exoparg2.c11
-rw-r--r--drivers/acpi/acpica/exprep.c4
-rw-r--r--drivers/acpi/acpica/exutils.c4
-rw-r--r--drivers/acpi/acpica/hwacpi.c20
-rw-r--r--drivers/acpi/acpica/nsconvert.c443
-rw-r--r--drivers/acpi/acpica/nseval.c26
-rw-r--r--drivers/acpi/acpica/nspredef.c213
-rw-r--r--drivers/acpi/acpica/nsprepkg.c10
-rw-r--r--drivers/acpi/acpica/nsrepair.c381
-rw-r--r--drivers/acpi/acpica/nsrepair2.c16
-rw-r--r--drivers/acpi/acpica/nsutils.c8
-rw-r--r--drivers/acpi/acpica/psargs.c2
-rw-r--r--drivers/acpi/acpica/rscalc.c6
-rw-r--r--drivers/acpi/acpica/rsdump.c8
-rw-r--r--drivers/acpi/acpica/rslist.c8
-rw-r--r--drivers/acpi/acpica/rsxface.c8
-rw-r--r--drivers/acpi/acpica/tbfadt.c4
-rw-r--r--drivers/acpi/acpica/tbxface.c22
-rw-r--r--drivers/acpi/acpica/utaddress.c4
-rw-r--r--drivers/acpi/acpica/utcache.c18
-rw-r--r--drivers/acpi/acpica/utdelete.c96
-rw-r--r--drivers/acpi/acpica/utexcep.c26
-rw-r--r--drivers/acpi/acpica/utglobal.c2
-rw-r--r--drivers/acpi/acpica/utmutex.c9
-rw-r--r--drivers/acpi/acpica/utosi.c26
-rw-r--r--drivers/acpi/acpica/utpredef.c399
-rw-r--r--drivers/acpi/acpica/utxface.c17
-rw-r--r--drivers/acpi/apei/cper.c2
-rw-r--r--drivers/acpi/battery.c2
-rw-r--r--drivers/acpi/bus.c5
-rw-r--r--drivers/acpi/button.c1
-rw-r--r--drivers/acpi/container.c152
-rw-r--r--drivers/acpi/device_pm.c39
-rw-r--r--drivers/acpi/fan.c8
-rw-r--r--drivers/acpi/internal.h21
-rw-r--r--drivers/acpi/osl.c4
-rw-r--r--drivers/acpi/pci_link.c1
-rw-r--r--drivers/acpi/pci_root.c137
-rw-r--r--drivers/acpi/pci_slot.c170
-rw-r--r--drivers/acpi/power.c60
-rw-r--r--drivers/acpi/processor_idle.c14
-rw-r--r--drivers/acpi/processor_thermal.c24
-rw-r--r--drivers/acpi/processor_throttling.c3
-rw-r--r--drivers/acpi/scan.c532
-rw-r--r--drivers/acpi/sleep.c8
-rw-r--r--drivers/acpi/sysfs.c66
-rw-r--r--drivers/acpi/thermal.c16
-rw-r--r--drivers/acpi/video.c318
-rw-r--r--drivers/acpi/video_detect.c25
-rw-r--r--drivers/ata/ahci.c10
-rw-r--r--drivers/ata/ata_piix.c14
-rw-r--r--drivers/ata/libata-acpi.c82
-rw-r--r--drivers/ata/libata-core.c6
-rw-r--r--drivers/ata/libata-scsi.c15
-rw-r--r--drivers/ata/pata_at32.c13
-rw-r--r--drivers/ata/pata_imx.c36
-rw-r--r--drivers/ata/pata_legacy.c2
-rw-r--r--drivers/ata/pata_octeon_cf.c2
-rw-r--r--drivers/ata/pata_pcmcia.c14
-rw-r--r--drivers/ata/pata_pdc2027x.c2
-rw-r--r--drivers/ata/sata_fsl.c57
-rw-r--r--drivers/ata/sata_highbank.c4
-rw-r--r--drivers/ata/sata_rcar.c7
-rw-r--r--drivers/atm/he.c2
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c81
-rw-r--r--drivers/base/core.c28
-rw-r--r--drivers/base/cpu.c39
-rw-r--r--drivers/base/dd.c6
-rw-r--r--drivers/base/devres.c74
-rw-r--r--drivers/base/devtmpfs.c28
-rw-r--r--drivers/base/dma-buf.c169
-rw-r--r--drivers/base/memory.c49
-rw-r--r--drivers/base/node.c8
-rw-r--r--drivers/base/platform.c24
-rw-r--r--drivers/base/power/domain.c6
-rw-r--r--drivers/base/power/generic_ops.c2
-rw-r--r--drivers/base/power/main.c2
-rw-r--r--drivers/base/power/opp.c1
-rw-r--r--drivers/base/power/qos.c60
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/base/regmap/internal.h40
-rw-r--r--drivers/base/regmap/regcache-lzo.c6
-rw-r--r--drivers/base/regmap/regcache-rbtree.c102
-rw-r--r--drivers/base/regmap/regcache.c196
-rw-r--r--drivers/base/regmap/regmap-debugfs.c94
-rw-r--r--drivers/base/regmap/regmap-irq.c3
-rw-r--r--drivers/base/regmap/regmap.c98
-rw-r--r--drivers/bcma/core.c8
-rw-r--r--drivers/bcma/driver_chipcommon.c5
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c34
-rw-r--r--drivers/bcma/main.c5
-rw-r--r--drivers/bcma/scan.c16
-rw-r--r--drivers/bcma/sprom.c1
-rw-r--r--drivers/block/Kconfig4
-rw-r--r--drivers/block/aoe/aoechr.c3
-rw-r--r--drivers/block/aoe/aoecmd.c3
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/drbd/drbd_receiver.c5
-rw-r--r--drivers/block/loop.c10
-rw-r--r--drivers/block/mg_disk.c4
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c331
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h18
-rw-r--r--drivers/block/nbd.c2
-rw-r--r--drivers/block/rbd.c50
-rw-r--r--drivers/block/rsxx/Makefile2
-rw-r--r--drivers/block/rsxx/config.c8
-rw-r--r--drivers/block/rsxx/core.c237
-rw-r--r--drivers/block/rsxx/cregs.c112
-rw-r--r--drivers/block/rsxx/dma.c239
-rw-r--r--drivers/block/rsxx/rsxx.h6
-rw-r--r--drivers/block/rsxx/rsxx_cfg.h2
-rw-r--r--drivers/block/rsxx/rsxx_priv.h34
-rw-r--r--drivers/block/xen-blkback/blkback.c68
-rw-r--r--drivers/block/xen-blkback/common.h40
-rw-r--r--drivers/block/xen-blkback/xenbus.c14
-rw-r--r--drivers/block/xen-blkfront.c154
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/bluetooth/bluecard_cs.c15
-rw-r--r--drivers/bluetooth/bt3c_cs.c15
-rw-r--r--drivers/bluetooth/btmrvl_debugfs.c266
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c49
-rw-r--r--drivers/bluetooth/btuart_cs.c15
-rw-r--r--drivers/bluetooth/btusb.c418
-rw-r--r--drivers/bluetooth/dtl1_cs.c15
-rw-r--r--drivers/bluetooth/hci_h4.c3
-rw-r--r--drivers/bluetooth/hci_ldisc.c15
-rw-r--r--drivers/char/applicom.c4
-rw-r--r--drivers/char/hpet.c14
-rw-r--r--drivers/char/hw_random/core.c9
-rw-r--r--drivers/char/hw_random/mxc-rnga.c13
-rw-r--r--drivers/char/hw_random/tx4939-rng.c13
-rw-r--r--drivers/char/random.c1
-rw-r--r--drivers/char/tile-srom.c2
-rw-r--r--drivers/char/tpm/tpm.c31
-rw-r--r--drivers/char/tpm/tpm.h3
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c180
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.c64
-rw-r--r--drivers/char/tpm/tpm_ppi.c14
-rw-r--r--drivers/char/virtio_console.c44
-rw-r--r--drivers/clk/Kconfig18
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/clk-axi-clkgen.c331
-rw-r--r--drivers/clk/clk-composite.c210
-rw-r--r--drivers/clk/clk-divider.c5
-rw-r--r--drivers/clk/clk-fixed-factor.c36
-rw-r--r--drivers/clk/clk-mux.c50
-rw-r--r--drivers/clk/clk-prima2.c2
-rw-r--r--drivers/clk/clk-si5351.c1510
-rw-r--r--drivers/clk/clk-si5351.h155
-rw-r--r--drivers/clk/clk-vt8500.c2
-rw-r--r--drivers/clk/clk-zynq.c1
-rw-r--r--drivers/clk/clk.c406
-rw-r--r--drivers/clk/mvebu/clk-core.c8
-rw-r--r--drivers/clk/mvebu/clk-cpu.c17
-rw-r--r--drivers/clk/mvebu/clk-cpu.h22
-rw-r--r--drivers/clk/mvebu/clk.c6
-rw-r--r--drivers/clk/mxs/clk.c1
-rw-r--r--drivers/clk/spear/spear1340_clock.c18
-rw-r--r--drivers/clk/sunxi/Makefile5
-rw-r--r--drivers/clk/sunxi/clk-factors.c180
-rw-r--r--drivers/clk/sunxi/clk-factors.h27
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c469
-rw-r--r--drivers/clk/tegra/clk-tegra20.c2
-rw-r--r--drivers/clk/tegra/clk.h27
-rw-r--r--drivers/clk/ux500/Makefile1
-rw-r--r--drivers/clk/ux500/abx500-clk.c71
-rw-r--r--drivers/clk/ux500/clk-prcmu.c136
-rw-r--r--drivers/clk/ux500/clk-sysctrl.c221
-rw-r--r--drivers/clk/ux500/clk.h34
-rw-r--r--drivers/clk/versatile/Makefile2
-rw-r--r--drivers/clk/versatile/clk-sp810.c188
-rw-r--r--drivers/clk/versatile/clk-vexpress.c49
-rw-r--r--drivers/clk/x86/Makefile2
-rw-r--r--drivers/clk/x86/clk-lpss.c99
-rw-r--r--drivers/clk/x86/clk-lpss.h36
-rw-r--r--drivers/clk/x86/clk-lpt.c40
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/bcm_kona_timer.c211
-rw-r--r--drivers/clocksource/sunxi_timer.c4
-rw-r--r--drivers/connector/cn_proc.c25
-rw-r--r--drivers/connector/connector.c12
-rw-r--r--drivers/cpufreq/Kconfig89
-rw-r--r--drivers/cpufreq/Kconfig.arm148
-rw-r--r--drivers/cpufreq/Kconfig.powerpc18
-rw-r--r--drivers/cpufreq/Kconfig.x8617
-rw-r--r--drivers/cpufreq/Makefile41
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c13
-rw-r--r--drivers/cpufreq/amd_freq_sensitivity.c148
-rw-r--r--drivers/cpufreq/arm_big_little.c278
-rw-r--r--drivers/cpufreq/arm_big_little.h40
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c107
-rw-r--r--drivers/cpufreq/at32ap-cpufreq.c (renamed from arch/avr32/mach-at32ap/cpufreq.c)5
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c (renamed from arch/blackfin/mach-common/cpufreq.c)79
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c42
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c11
-rw-r--r--drivers/cpufreq/cpufreq.c145
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c244
-rw-r--r--drivers/cpufreq/cpufreq_governor.c291
-rw-r--r--drivers/cpufreq/cpufreq_governor.h134
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c363
-rw-r--r--drivers/cpufreq/cpufreq_stats.c12
-rw-r--r--drivers/cpufreq/cris-artpec3-cpufreq.c (renamed from arch/cris/arch-v32/mach-a3/cpufreq.c)20
-rw-r--r--drivers/cpufreq/cris-etraxfs-cpufreq.c (renamed from arch/cris/arch-v32/mach-fs/cpufreq.c)17
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c (renamed from arch/arm/mach-davinci/cpufreq.c)35
-rw-r--r--drivers/cpufreq/dbx500-cpufreq.c22
-rw-r--r--drivers/cpufreq/e_powersaver.c11
-rw-r--r--drivers/cpufreq/elanfreq.c10
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c9
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c481
-rw-r--r--drivers/cpufreq/gx-suspmod.c11
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c (renamed from arch/ia64/kernel/cpufreq/acpi-cpufreq.c)23
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c12
-rw-r--r--drivers/cpufreq/integrator-cpufreq.c (renamed from arch/arm/mach-integrator/cpu.c)8
-rw-r--r--drivers/cpufreq/intel_pstate.c56
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c18
-rw-r--r--drivers/cpufreq/longhaul.c18
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c (renamed from arch/mips/kernel/cpufreq/loongson2_cpufreq.c)11
-rw-r--r--drivers/cpufreq/maple-cpufreq.c5
-rw-r--r--drivers/cpufreq/omap-cpufreq.c34
-rw-r--r--drivers/cpufreq/p4-clockmod.c13
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c5
-rw-r--r--drivers/cpufreq/powernow-k6.c12
-rw-r--r--drivers/cpufreq/powernow-k7.c10
-rw-r--r--drivers/cpufreq/powernow-k8.c19
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c (renamed from arch/powerpc/platforms/cell/cbe_cpufreq.c)8
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.h (renamed from arch/powerpc/platforms/cell/cbe_cpufreq.h)4
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq_pervasive.c (renamed from arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c)2
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq_pmi.c (renamed from arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c)2
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c (renamed from arch/arm/mach-pxa/cpufreq-pxa2xx.c)12
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c (renamed from arch/arm/mach-pxa/cpufreq-pxa3xx.c)10
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c5
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c7
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c5
-rw-r--r--drivers/cpufreq/sa1100-cpufreq.c (renamed from arch/arm/mach-sa1100/cpu-sa1100.c)8
-rw-r--r--drivers/cpufreq/sa1110-cpufreq.c (renamed from arch/arm/mach-sa1100/cpu-sa1110.c)8
-rw-r--r--drivers/cpufreq/sc520_freq.c10
-rw-r--r--drivers/cpufreq/sh-cpufreq.c (renamed from arch/sh/kernel/cpufreq.c)22
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c (renamed from arch/sparc/kernel/us2e_cpufreq.c)19
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c (renamed from arch/sparc/kernel/us3_cpufreq.c)19
-rw-r--r--drivers/cpufreq/spear-cpufreq.c7
-rw-r--r--drivers/cpufreq/speedstep-centrino.c28
-rw-r--r--drivers/cpufreq/speedstep-ich.c12
-rw-r--r--drivers/cpufreq/speedstep-smi.c5
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c (renamed from arch/arm/mach-tegra/cpu-tegra.c)17
-rw-r--r--drivers/cpufreq/unicore2-cpufreq.c (renamed from arch/unicore32/kernel/cpu-ucv2.c)7
-rw-r--r--drivers/cpuidle/Kconfig6
-rw-r--r--drivers/cpuidle/Makefile2
-rw-r--r--drivers/cpuidle/cpuidle-calxeda.c57
-rw-r--r--drivers/cpuidle/cpuidle-kirkwood.c29
-rw-r--r--drivers/cpuidle/cpuidle.c153
-rw-r--r--drivers/cpuidle/driver.c31
-rw-r--r--drivers/crypto/caam/caamalg.c27
-rw-r--r--drivers/crypto/caam/compat.h1
-rw-r--r--drivers/crypto/caam/ctrl.c2
-rw-r--r--drivers/crypto/talitos.c30
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c2
-rw-r--r--drivers/dma/Kconfig1
-rw-r--r--drivers/dma/at_hdmac.c9
-rw-r--r--drivers/dma/dw_dmac.c23
-rw-r--r--drivers/dma/dw_dmac_regs.h1
-rw-r--r--drivers/dma/ioat/dca.c11
-rw-r--r--drivers/dma/omap-dma.c20
-rw-r--r--drivers/dma/pl330.c38
-rw-r--r--drivers/edac/amd64_edac.c65
-rw-r--r--drivers/edac/amd64_edac.h4
-rw-r--r--drivers/edac/i7300_edac.c19
-rw-r--r--drivers/edac/sb_edac.c53
-rw-r--r--drivers/eisa/eisa-bus.c82
-rw-r--r--drivers/eisa/pci_eisa.c72
-rw-r--r--drivers/extcon/extcon-arizona.c498
-rw-r--r--drivers/extcon/extcon-max77693.c111
-rw-r--r--drivers/extcon/extcon-max8997.c68
-rw-r--r--drivers/firewire/Kconfig6
-rw-r--r--drivers/firewire/net.c462
-rw-r--r--drivers/firmware/Kconfig36
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/dmi_scan.c137
-rw-r--r--drivers/firmware/efi/Kconfig39
-rw-r--r--drivers/firmware/efi/Makefile6
-rw-r--r--drivers/firmware/efi/efi-pstore.c252
-rw-r--r--drivers/firmware/efi/efi.c134
-rw-r--r--drivers/firmware/efi/efivars.c617
-rw-r--r--drivers/firmware/efi/vars.c1041
-rw-r--r--drivers/firmware/efivars.c2172
-rw-r--r--drivers/firmware/google/gsmi.c31
-rw-r--r--drivers/firmware/memmap.c9
-rw-r--r--drivers/gpio/gpio-ich.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c2
-rw-r--r--drivers/gpio/gpio-pl061.c125
-rw-r--r--drivers/gpio/gpio-pxa.c7
-rw-r--r--drivers/gpio/gpio-stmpe.c15
-rw-r--r--drivers/gpio/gpiolib-of.c15
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c8
-rw-r--r--drivers/gpu/drm/drm_fops.c6
-rw-r--r--drivers/gpu/drm/drm_modes.c20
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c40
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c5
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c4
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c13
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c26
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c2
-rw-r--r--drivers/gpu/drm/tilcdc/Kconfig3
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c2
-rw-r--r--drivers/gpu/drm/udl/udl_connector.c4
-rw-r--r--drivers/hid/Kconfig117
-rw-r--r--drivers/hid/Makefile5
-rw-r--r--drivers/hid/hid-apple.c5
-rw-r--r--drivers/hid/hid-appleir.c352
-rw-r--r--drivers/hid/hid-axff.c6
-rw-r--r--drivers/hid/hid-core.c76
-rw-r--r--drivers/hid/hid-debug.c36
-rw-r--r--drivers/hid/hid-dr.c8
-rw-r--r--drivers/hid/hid-emsff.c6
-rw-r--r--drivers/hid/hid-gaff.c10
-rw-r--r--drivers/hid/hid-holtekff.c4
-rw-r--r--drivers/hid/hid-icade.c2
-rw-r--r--drivers/hid/hid-ids.h20
-rw-r--r--drivers/hid/hid-input.c77
-rw-r--r--drivers/hid/hid-kye.c4
-rw-r--r--drivers/hid/hid-lenovo-tpkbd.c6
-rw-r--r--drivers/hid/hid-lg2ff.c6
-rw-r--r--drivers/hid/hid-lg3ff.c6
-rw-r--r--drivers/hid/hid-lg4ff.c20
-rw-r--r--drivers/hid/hid-lgff.c8
-rw-r--r--drivers/hid/hid-logitech-dj.c53
-rw-r--r--drivers/hid/hid-logitech-dj.h1
-rw-r--r--drivers/hid/hid-magicmouse.c30
-rw-r--r--drivers/hid/hid-microsoft.c2
-rw-r--r--drivers/hid/hid-multitouch.c275
-rw-r--r--drivers/hid/hid-ntrig.c10
-rw-r--r--drivers/hid/hid-picolcd.h6
-rw-r--r--drivers/hid/hid-picolcd_backlight.c4
-rw-r--r--drivers/hid/hid-picolcd_cir.c2
-rw-r--r--drivers/hid/hid-picolcd_core.c8
-rw-r--r--drivers/hid/hid-picolcd_debugfs.c2
-rw-r--r--drivers/hid/hid-picolcd_fb.c12
-rw-r--r--drivers/hid/hid-picolcd_lcd.c4
-rw-r--r--drivers/hid/hid-picolcd_leds.c4
-rw-r--r--drivers/hid/hid-pl.c6
-rw-r--r--drivers/hid/hid-prodikeys.c3
-rw-r--r--drivers/hid/hid-roccat-isku.c17
-rw-r--r--drivers/hid/hid-roccat-isku.h4
-rw-r--r--drivers/hid/hid-roccat-kone.c3
-rw-r--r--drivers/hid/hid-roccat-kone.h1
-rw-r--r--drivers/hid/hid-roccat-konepure.c304
-rw-r--r--drivers/hid/hid-roccat-konepure.h72
-rw-r--r--drivers/hid/hid-roccat.c2
-rw-r--r--drivers/hid/hid-sensor-hub.c12
-rw-r--r--drivers/hid/hid-sjoy.c6
-rw-r--r--drivers/hid/hid-speedlink.c2
-rw-r--r--drivers/hid/hid-steelseries.c16
-rw-r--r--drivers/hid/hid-thingm.c1
-rw-r--r--drivers/hid/hid-tmff.c6
-rw-r--r--drivers/hid/hid-wiimote-core.c43
-rw-r--r--drivers/hid/hid-zpff.c6
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c31
-rw-r--r--drivers/hid/usbhid/hid-core.c49
-rw-r--r--drivers/hid/usbhid/hid-pidff.c80
-rw-r--r--drivers/hid/usbhid/hid-quirks.c2
-rw-r--r--drivers/hid/usbhid/hiddev.c8
-rw-r--r--drivers/hid/usbhid/usbhid.h3
-rw-r--r--drivers/hv/Kconfig2
-rw-r--r--drivers/hv/Makefile2
-rw-r--r--drivers/hv/channel_mgmt.c11
-rw-r--r--drivers/hv/hv.c5
-rw-r--r--drivers/hv/hv_balloon.c544
-rw-r--r--drivers/hv/hv_snapshot.c287
-rw-r--r--drivers/hv/hv_util.c10
-rw-r--r--drivers/hv/ring_buffer.c1
-rw-r--r--drivers/hwmon/Kconfig70
-rw-r--r--drivers/hwmon/Makefile6
-rw-r--r--drivers/hwmon/ab8500.c206
-rw-r--r--drivers/hwmon/abituguru.c11
-rw-r--r--drivers/hwmon/abituguru3.c10
-rw-r--r--drivers/hwmon/abx500.c491
-rw-r--r--drivers/hwmon/abx500.h69
-rw-r--r--drivers/hwmon/ad7314.c7
-rw-r--r--drivers/hwmon/adm1021.c11
-rw-r--r--drivers/hwmon/adm1026.c53
-rw-r--r--drivers/hwmon/adm1029.c9
-rw-r--r--drivers/hwmon/adm9240.c9
-rw-r--r--drivers/hwmon/ads7871.c42
-rw-r--r--drivers/hwmon/adt7310.c123
-rw-r--r--drivers/hwmon/adt7410.c442
-rw-r--r--drivers/hwmon/adt7411.c10
-rw-r--r--drivers/hwmon/adt7x10.c511
-rw-r--r--drivers/hwmon/adt7x10.h37
-rw-r--r--drivers/hwmon/applesmc.c2
-rw-r--r--drivers/hwmon/asb100.c23
-rw-r--r--drivers/hwmon/asc7621.c56
-rw-r--r--drivers/hwmon/coretemp.c3
-rw-r--r--drivers/hwmon/da9052-hwmon.c14
-rw-r--r--drivers/hwmon/da9055-hwmon.c4
-rw-r--r--drivers/hwmon/dme1737.c68
-rw-r--r--drivers/hwmon/f71805f.c3
-rw-r--r--drivers/hwmon/fam15h_power.c4
-rw-r--r--drivers/hwmon/fschmd.c9
-rw-r--r--drivers/hwmon/gl518sm.c5
-rw-r--r--drivers/hwmon/gpio-fan.c106
-rw-r--r--drivers/hwmon/ibmaem.c21
-rw-r--r--drivers/hwmon/ibmpex.c17
-rw-r--r--drivers/hwmon/iio_hwmon.c (renamed from drivers/staging/iio/iio_hwmon.c)8
-rw-r--r--drivers/hwmon/ina2xx.c16
-rw-r--r--drivers/hwmon/it87.c24
-rw-r--r--drivers/hwmon/k8temp.c4
-rw-r--r--drivers/hwmon/lm78.c10
-rw-r--r--drivers/hwmon/lm80.c5
-rw-r--r--drivers/hwmon/lm85.c4
-rw-r--r--drivers/hwmon/lm93.c74
-rw-r--r--drivers/hwmon/lm95234.c769
-rw-r--r--drivers/hwmon/ltc4151.c12
-rw-r--r--drivers/hwmon/ltc4215.c46
-rw-r--r--drivers/hwmon/ltc4245.c116
-rw-r--r--drivers/hwmon/ltc4261.c38
-rw-r--r--drivers/hwmon/max6697.c209
-rw-r--r--drivers/hwmon/mc13783-adc.c13
-rw-r--r--drivers/hwmon/nct6775.c4191
-rw-r--r--drivers/hwmon/ntc_thermistor.c353
-rw-r--r--drivers/hwmon/pc87360.c25
-rw-r--r--drivers/hwmon/pc87427.c13
-rw-r--r--drivers/hwmon/pmbus/Kconfig6
-rw-r--r--drivers/hwmon/pmbus/lm25066.c414
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c170
-rw-r--r--drivers/hwmon/s3c-hwmon.c19
-rw-r--r--drivers/hwmon/sch56xx-common.c12
-rw-r--r--drivers/hwmon/sis5595.c5
-rw-r--r--drivers/hwmon/thmc50.c7
-rw-r--r--drivers/hwmon/tmp102.c4
-rw-r--r--drivers/hwmon/tmp401.c728
-rw-r--r--drivers/hwmon/tmp421.c7
-rw-r--r--drivers/hwmon/via686a.c47
-rw-r--r--drivers/hwmon/vt1211.c23
-rw-r--r--drivers/hwmon/vt8231.c5
-rw-r--r--drivers/hwmon/w83627ehf.c31
-rw-r--r--drivers/hwmon/w83781d.c36
-rw-r--r--drivers/hwmon/w83791d.c4
-rw-r--r--drivers/hwmon/w83792d.c13
-rw-r--r--drivers/hwmon/w83793.c8
-rw-r--r--drivers/hwmon/w83795.c9
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c2
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c1
-rw-r--r--drivers/i2c/busses/i2c-puv3.c2
-rw-r--r--drivers/idle/intel_idle.c5
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c24
-rw-r--r--drivers/iio/accel/kxsd9.c6
-rw-r--r--drivers/iio/accel/st_accel_buffer.c2
-rw-r--r--drivers/iio/adc/Kconfig20
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/ad7266.c12
-rw-r--r--drivers/iio/adc/ad7298.c10
-rw-r--r--drivers/iio/adc/ad7476.c10
-rw-r--r--drivers/iio/adc/ad7887.c8
-rw-r--r--drivers/iio/adc/ad7923.c383
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c2
-rw-r--r--drivers/iio/adc/at91_adc.c98
-rw-r--r--drivers/iio/adc/exynos_adc.c452
-rw-r--r--drivers/iio/adc/lp8788_adc.c4
-rw-r--r--drivers/iio/adc/max1363.c9
-rw-r--r--drivers/iio/adc/ti-adc081c.c4
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c2
-rw-r--r--drivers/iio/adc/viperboard_adc.c2
-rw-r--r--drivers/iio/amplifiers/ad8366.c2
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c4
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_spi.c11
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_trigger.c2
-rw-r--r--drivers/iio/dac/ad5064.c4
-rw-r--r--drivers/iio/dac/ad5360.c10
-rw-r--r--drivers/iio/dac/ad5380.c8
-rw-r--r--drivers/iio/dac/ad5421.c10
-rw-r--r--drivers/iio/dac/ad5446.c4
-rw-r--r--drivers/iio/dac/ad5449.c4
-rw-r--r--drivers/iio/dac/ad5504.c4
-rw-r--r--drivers/iio/dac/ad5624r_spi.c4
-rw-r--r--drivers/iio/dac/ad5686.c6
-rw-r--r--drivers/iio/dac/ad5755.c10
-rw-r--r--drivers/iio/dac/ad5764.c10
-rw-r--r--drivers/iio/dac/ad5791.c6
-rw-r--r--drivers/iio/dac/max517.c4
-rw-r--r--drivers/iio/dac/mcp4725.c4
-rw-r--r--drivers/iio/frequency/ad9523.c8
-rw-r--r--drivers/iio/gyro/adis16080.c22
-rw-r--r--drivers/iio/gyro/adis16136.c13
-rw-r--r--drivers/iio/gyro/adxrs450.c22
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c24
-rw-r--r--drivers/iio/gyro/itg3200_buffer.c4
-rw-r--r--drivers/iio/gyro/itg3200_core.c13
-rw-r--r--drivers/iio/gyro/st_gyro_buffer.c2
-rw-r--r--drivers/iio/iio_core.h1
-rw-r--r--drivers/iio/imu/adis16400_core.c49
-rw-r--r--drivers/iio/imu/adis16480.c32
-rw-r--r--drivers/iio/imu/adis_trigger.c4
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c10
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c5
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c4
-rw-r--r--drivers/iio/industrialio-core.c35
-rw-r--r--drivers/iio/industrialio-event.c29
-rw-r--r--drivers/iio/inkern.c171
-rw-r--r--drivers/iio/light/adjd_s311.c4
-rw-r--r--drivers/iio/light/hid-sensor-als.c8
-rw-r--r--drivers/iio/light/lm3533-als.c6
-rw-r--r--drivers/iio/light/tsl2563.c10
-rw-r--r--drivers/iio/light/vcnl4000.c6
-rw-r--r--drivers/iio/magnetometer/Kconfig11
-rw-r--r--drivers/iio/magnetometer/Makefile1
-rw-r--r--drivers/iio/magnetometer/ak8975.c (renamed from drivers/staging/iio/magnetometer/ak8975.c)73
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c24
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/Makefile1
-rw-r--r--drivers/infiniband/hw/amso1100/c2.h1
-rw-r--r--drivers/infiniband/hw/amso1100/c2_qp.c3
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c68
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c34
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h14
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c155
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c15
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c113
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h11
-rw-r--r--drivers/infiniband/hw/mlx4/cm.c4
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c2
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c14
-rw-r--r--drivers/infiniband/hw/qib/qib_sd7220.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c4
-rw-r--r--drivers/infiniband/ulp/isert/Kconfig5
-rw-r--r--drivers/infiniband/ulp/isert/Makefile2
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c2281
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h138
-rw-r--r--drivers/infiniband/ulp/isert/isert_proto.h47
-rw-r--r--drivers/input/input-mt.c8
-rw-r--r--drivers/input/keyboard/amikbd.c14
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c12
-rw-r--r--drivers/input/keyboard/imx_keypad.c77
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c12
-rw-r--r--drivers/input/keyboard/tegra-kbc.c89
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/ad714x-i2c.c2
-rw-r--r--drivers/input/misc/ad714x-spi.c2
-rw-r--r--drivers/input/misc/adxl34x-i2c.c2
-rw-r--r--drivers/input/misc/adxl34x-spi.c8
-rw-r--r--drivers/input/misc/ims-pcu.c1901
-rw-r--r--drivers/input/misc/mma8450.c6
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c12
-rw-r--r--drivers/input/mouse/alps.c12
-rw-r--r--drivers/input/mouse/amimouse.c14
-rw-r--r--drivers/input/mouse/trackpoint.c249
-rw-r--r--drivers/input/mouse/trackpoint.h4
-rw-r--r--drivers/input/serio/Kconfig10
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/apbps2.c228
-rw-r--r--drivers/input/serio/arc_ps2.c14
-rw-r--r--drivers/input/serio/at32psif.c13
-rw-r--r--drivers/input/serio/q40kbd.c13
-rw-r--r--drivers/input/tablet/wacom_wac.c8
-rw-r--r--drivers/input/touchscreen/ad7877.c10
-rw-r--r--drivers/input/touchscreen/ads7846.c4
-rw-r--r--drivers/input/touchscreen/atmel-wm97xx.c12
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c226
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c3
-rw-r--r--drivers/input/touchscreen/eeti_ts.c3
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c12
-rw-r--r--drivers/input/touchscreen/st1232.c77
-rw-r--r--drivers/input/touchscreen/wm9712.c28
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c11
-rw-r--r--drivers/iommu/Kconfig2
-rw-r--r--drivers/iommu/amd_iommu.c36
-rw-r--r--drivers/iommu/amd_iommu_init.c42
-rw-r--r--drivers/iommu/amd_iommu_types.h11
-rw-r--r--drivers/iommu/dmar.c3
-rw-r--r--drivers/iommu/irq_remapping.c1
-rw-r--r--drivers/ipack/carriers/tpci200.c14
-rw-r--r--drivers/ipack/ipack.c36
-rw-r--r--drivers/irqchip/irq-gic.c3
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/isdn/capi/capi.c7
-rw-r--r--drivers/isdn/capi/capidrv.c3
-rw-r--r--drivers/isdn/divert/isdn_divert.c8
-rw-r--r--drivers/isdn/gigaset/interface.c6
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c14
-rw-r--r--drivers/isdn/hisax/avma1_cs.c14
-rw-r--r--drivers/isdn/hisax/elsa_cs.c14
-rw-r--r--drivers/isdn/hisax/fsm.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c14
-rw-r--r--drivers/isdn/hisax/teles_cs.c14
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c4
-rw-r--r--drivers/isdn/mISDN/socket.c1
-rw-r--r--drivers/isdn/sc/init.c4
-rw-r--r--drivers/lguest/page_tables.c2
-rw-r--r--drivers/md/bitmap.c4
-rw-r--r--drivers/md/dm-cache-target.c51
-rw-r--r--drivers/md/dm-raid.c111
-rw-r--r--drivers/md/dm.c1
-rw-r--r--drivers/md/md.c235
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/raid1.c8
-rw-r--r--drivers/md/raid10.c24
-rw-r--r--drivers/md/raid5.c27
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/common/b2c2/flexcop-fe-tuner.c4
-rw-r--r--drivers/media/common/cypress_firmware.c (renamed from drivers/media/usb/dvb-usb-v2/cypress_firmware.c)82
-rw-r--r--drivers/media/common/cypress_firmware.h (renamed from drivers/media/usb/dvb-usb-v2/cypress_firmware.h)9
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c4
-rw-r--r--drivers/media/common/siano/Kconfig12
-rw-r--r--drivers/media/common/siano/Makefile5
-rw-r--r--drivers/media/common/siano/sms-cards.c115
-rw-r--r--drivers/media/common/siano/sms-cards.h14
-rw-r--r--drivers/media/common/siano/smscoreapi.c1298
-rw-r--r--drivers/media/common/siano/smscoreapi.h1007
-rw-r--r--drivers/media/common/siano/smsdvb-debugfs.c551
-rw-r--r--drivers/media/common/siano/smsdvb-main.c1230
-rw-r--r--drivers/media/common/siano/smsdvb.c1078
-rw-r--r--drivers/media/common/siano/smsdvb.h130
-rw-r--r--drivers/media/common/siano/smsendian.c44
-rw-r--r--drivers/media/common/siano/smsir.h1
-rw-r--r--drivers/media/dvb-core/demux.h39
-rw-r--r--drivers/media/dvb-core/dmxdev.c5
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h3
-rw-r--r--drivers/media/dvb-core/dvb_demux.c30
-rw-r--r--drivers/media/dvb-core/dvb_demux.h4
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c333
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h4
-rw-r--r--drivers/media/dvb-core/dvb_net.c12
-rw-r--r--drivers/media/dvb-frontends/Kconfig2
-rw-r--r--drivers/media/dvb-frontends/a8293.h5
-rw-r--r--drivers/media/dvb-frontends/af9013.h4
-rw-r--r--drivers/media/dvb-frontends/af9033.c138
-rw-r--r--drivers/media/dvb-frontends/af9033.h20
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h1506
-rw-r--r--drivers/media/dvb-frontends/atbm8830.h4
-rw-r--r--drivers/media/dvb-frontends/au8522.h4
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c125
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h6
-rw-r--r--drivers/media/dvb-frontends/cx22702.h4
-rw-r--r--drivers/media/dvb-frontends/cx24113.h5
-rw-r--r--drivers/media/dvb-frontends/cx24116.h4
-rw-r--r--drivers/media/dvb-frontends/cx24123.c28
-rw-r--r--drivers/media/dvb-frontends/cx24123.h4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r.h4
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_core.c3
-rw-r--r--drivers/media/dvb-frontends/cxd2820r_t2.c17
-rw-r--r--drivers/media/dvb-frontends/dib0090.c434
-rw-r--r--drivers/media/dvb-frontends/dib3000mc.h5
-rw-r--r--drivers/media/dvb-frontends/dib7000m.h5
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c17
-rw-r--r--drivers/media/dvb-frontends/dib7000p.h12
-rw-r--r--drivers/media/dvb-frontends/dib8000.c2268
-rw-r--r--drivers/media/dvb-frontends/dib8000.h6
-rw-r--r--drivers/media/dvb-frontends/dibx000_common.h3
-rw-r--r--drivers/media/dvb-frontends/drxd.h4
-rw-r--r--drivers/media/dvb-frontends/drxk.h4
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c309
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.h2
-rw-r--r--drivers/media/dvb-frontends/drxk_map.h3
-rw-r--r--drivers/media/dvb-frontends/ds3000.h4
-rw-r--r--drivers/media/dvb-frontends/dvb_dummy_fe.h4
-rw-r--r--drivers/media/dvb-frontends/ec100.h4
-rw-r--r--drivers/media/dvb-frontends/hd29l2.h4
-rw-r--r--drivers/media/dvb-frontends/isl6421.c28
-rw-r--r--drivers/media/dvb-frontends/isl6421.h4
-rw-r--r--drivers/media/dvb-frontends/it913x-fe.h4
-rw-r--r--drivers/media/dvb-frontends/ix2505v.h4
-rw-r--r--drivers/media/dvb-frontends/lg2160.h8
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.h4
-rw-r--r--drivers/media/dvb-frontends/lgs8gl5.h4
-rw-r--r--drivers/media/dvb-frontends/lgs8gxx.h4
-rw-r--r--drivers/media/dvb-frontends/lnbh24.h5
-rw-r--r--drivers/media/dvb-frontends/lnbp21.h5
-rw-r--r--drivers/media/dvb-frontends/lnbp22.h5
-rw-r--r--drivers/media/dvb-frontends/m88rs2000.h4
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c507
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h12
-rw-r--r--drivers/media/dvb-frontends/rtl2830.h4
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c85
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h5
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h28
-rw-r--r--drivers/media/dvb-frontends/s5h1409.h4
-rw-r--r--drivers/media/dvb-frontends/s5h1411.h4
-rw-r--r--drivers/media/dvb-frontends/s5h1432.h4
-rw-r--r--drivers/media/dvb-frontends/s921.h4
-rw-r--r--drivers/media/dvb-frontends/si21xx.h4
-rw-r--r--drivers/media/dvb-frontends/stb6000.h4
-rw-r--r--drivers/media/dvb-frontends/stv0288.h4
-rw-r--r--drivers/media/dvb-frontends/stv0367.h4
-rw-r--r--drivers/media/dvb-frontends/stv0900.h4
-rw-r--r--drivers/media/dvb-frontends/stv090x.c22
-rw-r--r--drivers/media/dvb-frontends/stv6110.h4
-rw-r--r--drivers/media/dvb-frontends/tda10048.h4
-rw-r--r--drivers/media/dvb-frontends/tda10071.h4
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.h6
-rw-r--r--drivers/media/dvb-frontends/ts2020.h4
-rw-r--r--drivers/media/dvb-frontends/zl10036.h4
-rw-r--r--drivers/media/dvb-frontends/zl10039.h5
-rw-r--r--drivers/media/firewire/firedtv-dvb.c14
-rw-r--r--drivers/media/i2c/Kconfig70
-rw-r--r--drivers/media/i2c/Makefile8
-rw-r--r--drivers/media/i2c/ad9389b.c2
-rw-r--r--drivers/media/i2c/adp1653.c4
-rw-r--r--drivers/media/i2c/adv7180.c4
-rw-r--r--drivers/media/i2c/adv7183.c2
-rw-r--r--drivers/media/i2c/adv7604.c2
-rw-r--r--drivers/media/i2c/ak881x.c2
-rw-r--r--drivers/media/i2c/cs5345.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c6
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c14
-rw-r--r--drivers/media/i2c/m52790.c2
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c2
-rw-r--r--drivers/media/i2c/msp3400-driver.c4
-rw-r--r--drivers/media/i2c/mt9m032.c48
-rw-r--r--drivers/media/i2c/mt9p031.c58
-rw-r--r--drivers/media/i2c/mt9v011.c2
-rw-r--r--drivers/media/i2c/ov7640.c (renamed from drivers/staging/media/go7007/wis-ov7640.c)70
-rw-r--r--drivers/media/i2c/ov7670.c2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c23
-rw-r--r--drivers/media/i2c/saa6588.c2
-rw-r--r--drivers/media/i2c/saa7115.c80
-rw-r--r--drivers/media/i2c/saa7127.c2
-rw-r--r--drivers/media/i2c/saa717x.c4
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c4
-rw-r--r--drivers/media/i2c/soc_camera/Kconfig2
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c11
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c21
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c2
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c2
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c2
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c2
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c2
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c2
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c2
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c2
-rw-r--r--drivers/media/i2c/sony-btf-mpx.c399
-rw-r--r--drivers/media/i2c/tda7432.c276
-rw-r--r--drivers/media/i2c/tda9840.c2
-rw-r--r--drivers/media/i2c/ths7303.c351
-rw-r--r--drivers/media/i2c/tvaudio.c6
-rw-r--r--drivers/media/i2c/tvp514x.c163
-rw-r--r--drivers/media/i2c/tvp5150.c2
-rw-r--r--drivers/media/i2c/tvp7002.c184
-rw-r--r--drivers/media/i2c/tw2804.c453
-rw-r--r--drivers/media/i2c/tw9903.c279
-rw-r--r--drivers/media/i2c/tw9906.c247
-rw-r--r--drivers/media/i2c/uda1342.c (renamed from drivers/staging/media/go7007/wis-uda1342.c)83
-rw-r--r--drivers/media/i2c/upd64031a.c4
-rw-r--r--drivers/media/i2c/upd64083.c2
-rw-r--r--drivers/media/i2c/vp27smpx.c2
-rw-r--r--drivers/media/i2c/vs6624.c2
-rw-r--r--drivers/media/i2c/wm8775.c2
-rw-r--r--drivers/media/media-device.c111
-rw-r--r--drivers/media/media-devnode.c31
-rw-r--r--drivers/media/mmc/siano/smssdio.c27
-rw-r--r--drivers/media/parport/pms.c4
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c21
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c1246
-rw-r--r--drivers/media/pci/bt8xx/bttv-i2c.c8
-rw-r--r--drivers/media/pci/bt8xx/bttv-input.c30
-rw-r--r--drivers/media/pci/bt8xx/bttv.h3
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h38
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c6
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c2
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c52
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.h4
-rw-r--r--drivers/media/pci/cx23885/altera-ci.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.h2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c14
-rw-r--r--drivers/media/pci/cx23885/cx23885.h2
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c2
-rw-r--r--drivers/media/pci/cx25821/Kconfig7
-rw-r--r--drivers/media/pci/cx25821/Makefile7
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c83
-rw-r--r--drivers/media/pci/cx25821/cx25821-audio-upstream.c43
-rw-r--r--drivers/media/pci/cx25821/cx25821-cards.c23
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c133
-rw-r--r--drivers/media/pci/cx25821/cx25821-gpio.c1
-rw-r--r--drivers/media/pci/cx25821/cx25821-i2c.c3
-rw-r--r--drivers/media/pci/cx25821/cx25821-medusa-video.c46
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c800
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h138
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream.c519
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c1822
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.h125
-rw-r--r--drivers/media/pci/cx25821/cx25821.h304
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c8
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c30
-rw-r--r--drivers/media/pci/cx88/cx88-core.c12
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c16
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c10
-rw-r--r--drivers/media/pci/cx88/cx88-video.c35
-rw-r--r--drivers/media/pci/cx88/cx88.h5
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/pci/ivtv/ivtv-firmware.c4
-rw-r--r--drivers/media/pci/ivtv/ivtv-gpio.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c57
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.h6
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c3
-rw-r--r--drivers/media/pci/meye/meye.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c94
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c31
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c189
-rw-r--r--drivers/media/pci/saa7134/saa7134.h11
-rw-r--r--drivers/media/pci/saa7146/mxb.c9
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-encoder.c14
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c12
-rw-r--r--drivers/media/pci/sta2x11/Kconfig1
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c18
-rw-r--r--drivers/media/pci/ttpci/av7110.c6
-rw-r--r--drivers/media/pci/ttpci/av7110_v4l.c4
-rw-r--r--drivers/media/pci/ttpci/budget.c12
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c4
-rw-r--r--drivers/media/platform/Kconfig5
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c13
-rw-r--r--drivers/media/platform/coda.c50
-rw-r--r--drivers/media/platform/davinci/Kconfig103
-rw-r--r--drivers/media/platform/davinci/Makefile17
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc.c49
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc_regs.h2
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc.c57
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc_regs.h2
-rw-r--r--drivers/media/platform/davinci/isif.c30
-rw-r--r--drivers/media/platform/davinci/isif_regs.h4
-rw-r--r--drivers/media/platform/davinci/vpbe.c16
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c17
-rw-r--r--drivers/media/platform/davinci/vpbe_osd.c3
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c36
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c62
-rw-r--r--drivers/media/platform/davinci/vpif.c32
-rw-r--r--drivers/media/platform/davinci/vpif.h2
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c12
-rw-r--r--drivers/media/platform/davinci/vpif_display.c16
-rw-r--r--drivers/media/platform/davinci/vpss.c36
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c8
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c5
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.c1
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig (renamed from drivers/media/platform/s5p-fimc/Kconfig)21
-rw-r--r--drivers/media/platform/exynos4-is/Makefile (renamed from drivers/media/platform/s5p-fimc/Makefile)5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c (renamed from drivers/media/platform/s5p-fimc/fimc-capture.c)411
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c (renamed from drivers/media/platform/s5p-fimc/fimc-core.c)318
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h (renamed from drivers/media/platform/s5p-fimc/fimc-core.h)86
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-command.h137
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.c272
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-errno.h248
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c126
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.h15
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.c900
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-param.h1020
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.c243
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-regs.h164
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.c305
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-sensor.h89
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c1007
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.h345
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c703
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h181
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c (renamed from drivers/media/platform/s5p-fimc/fimc-lite-reg.c)12
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.h (renamed from drivers/media/platform/s5p-fimc/fimc-lite-reg.h)8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c (renamed from drivers/media/platform/s5p-fimc/fimc-lite.c)430
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h (renamed from drivers/media/platform/s5p-fimc/fimc-lite.h)20
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c (renamed from drivers/media/platform/s5p-fimc/fimc-m2m.c)40
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c (renamed from drivers/media/platform/s5p-fimc/fimc-reg.c)87
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.h (renamed from drivers/media/platform/s5p-fimc/fimc-reg.h)27
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c (renamed from drivers/media/platform/s5p-fimc/fimc-mdevice.c)764
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h (renamed from drivers/media/platform/s5p-fimc/fimc-mdevice.h)54
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c (renamed from drivers/media/platform/s5p-fimc/mipi-csis.c)169
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.h (renamed from drivers/media/platform/s5p-fimc/mipi-csis.h)1
-rw-r--r--drivers/media/platform/fsl-viu.c6
-rw-r--r--drivers/media/platform/m2m-deinterlace.c5
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c4
-rw-r--r--drivers/media/platform/mem2mem_testdev.c12
-rw-r--r--drivers/media/platform/mx2_emmaprp.c5
-rw-r--r--drivers/media/platform/omap/omap_vout.c14
-rw-r--r--drivers/media/platform/omap3isp/isp.c277
-rw-r--r--drivers/media/platform/omap3isp/isp.h22
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c16
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c36
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c21
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c12
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c12
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c76
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c112
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c124
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c129
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c55
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c52
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c3
-rw-r--r--drivers/media/platform/sh_veu.c20
-rw-r--r--drivers/media/platform/sh_vou.c27
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c16
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c17
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c8
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c3
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c6
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c12
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c12
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c9
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c48
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c46
-rw-r--r--drivers/media/platform/timblogiw.c8
-rw-r--r--drivers/media/platform/via-camera.c2
-rw-r--r--drivers/media/platform/vino.c10
-rw-r--r--drivers/media/platform/vivi.c10
-rw-r--r--drivers/media/radio/Kconfig16
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/dsbr100.c4
-rw-r--r--drivers/media/radio/radio-cadet.c48
-rw-r--r--drivers/media/radio/radio-isa.c15
-rw-r--r--drivers/media/radio/radio-keene.c8
-rw-r--r--drivers/media/radio/radio-ma901.c15
-rw-r--r--drivers/media/radio/radio-miropcm20.c12
-rw-r--r--drivers/media/radio/radio-mr800.c14
-rw-r--r--drivers/media/radio/radio-rtrack2.c5
-rw-r--r--drivers/media/radio/radio-sf16fmi.c4
-rw-r--r--drivers/media/radio/radio-shark.c2
-rw-r--r--drivers/media/radio/radio-shark2.c2
-rw-r--r--drivers/media/radio/radio-si4713.c204
-rw-r--r--drivers/media/radio/radio-si476x.c1599
-rw-r--r--drivers/media/radio/radio-tea5764.c4
-rw-r--r--drivers/media/radio/radio-tea5777.c9
-rw-r--r--drivers/media/radio/radio-timb.c4
-rw-r--r--drivers/media/radio/radio-wl1273.c4
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c4
-rw-r--r--drivers/media/radio/si4713-i2c.c1049
-rw-r--r--drivers/media/radio/si4713-i2c.h66
-rw-r--r--drivers/media/radio/tef6862.c4
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c8
-rw-r--r--drivers/media/rc/Kconfig2
-rw-r--r--drivers/media/rc/ene_ir.c1
-rw-r--r--drivers/media/rc/imon.c46
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c2
-rw-r--r--drivers/media/rc/ir-lirc-codec.c2
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c2
-rw-r--r--drivers/media/rc/ir-nec-decoder.c2
-rw-r--r--drivers/media/rc/ir-raw.c2
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c6
-rw-r--r--drivers/media/rc/ir-rc5-sz-decoder.c2
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c2
-rw-r--r--drivers/media/rc/ir-rx51.c4
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c2
-rw-r--r--drivers/media/rc/ir-sony-decoder.c8
-rw-r--r--drivers/media/rc/ite-cir.c1
-rw-r--r--drivers/media/rc/keymaps/Makefile3
-rw-r--r--drivers/media/rc/keymaps/rc-reddo.c86
-rw-r--r--drivers/media/rc/mceusb.c11
-rw-r--r--drivers/media/rc/nuvoton-cir.c1
-rw-r--r--drivers/media/rc/rc-core-priv.h1
-rw-r--r--drivers/media/rc/rc-main.c46
-rw-r--r--drivers/media/rc/redrat3.c457
-rw-r--r--drivers/media/rc/ttusbir.c1
-rw-r--r--drivers/media/rc/winbond-cir.c1
-rw-r--r--drivers/media/tuners/Kconfig14
-rw-r--r--drivers/media/tuners/Makefile2
-rw-r--r--drivers/media/tuners/e4000.h4
-rw-r--r--drivers/media/tuners/fc0011.h4
-rw-r--r--drivers/media/tuners/fc0012.h4
-rw-r--r--drivers/media/tuners/fc0013.h4
-rw-r--r--drivers/media/tuners/fc2580.h4
-rw-r--r--drivers/media/tuners/max2165.h5
-rw-r--r--drivers/media/tuners/mc44s803.h5
-rw-r--r--drivers/media/tuners/mxl5005s.h5
-rw-r--r--drivers/media/tuners/r820t.c2355
-rw-r--r--drivers/media/tuners/r820t.h59
-rw-r--r--drivers/media/tuners/tda18212.h4
-rw-r--r--drivers/media/tuners/tda18218.h4
-rw-r--r--drivers/media/tuners/tda18271-fe.c9
-rw-r--r--drivers/media/tuners/tda827x.c10
-rw-r--r--drivers/media/tuners/tda827x.h3
-rw-r--r--drivers/media/tuners/tda8290.c75
-rw-r--r--drivers/media/tuners/tda8290.h12
-rw-r--r--drivers/media/tuners/tda9887.c14
-rw-r--r--drivers/media/tuners/tua9001.h4
-rw-r--r--drivers/media/tuners/tuner-simple.c5
-rw-r--r--drivers/media/tuners/tuner-types.c69
-rw-r--r--drivers/media/tuners/tuner-xc2028.c3
-rw-r--r--drivers/media/tuners/tuner_it913x.c447
-rw-r--r--drivers/media/tuners/tuner_it913x.h45
-rw-r--r--drivers/media/tuners/tuner_it913x_priv.h78
-rw-r--r--drivers/media/tuners/xc5000.c20
-rw-r--r--drivers/media/tuners/xc5000.h4
-rw-r--r--drivers/media/usb/au0828/au0828-core.c61
-rw-r--r--drivers/media/usb/au0828/au0828-video.c299
-rw-r--r--drivers/media/usb/au0828/au0828.h7
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c1182
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c8
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c85
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c59
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c4
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c25
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c601
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h55
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig8
-rw-r--r--drivers/media/usb/dvb-usb-v2/Makefile5
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c79
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c600
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.h49
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c48
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.h3
-rw-r--r--drivers/media/usb/dvb-usb-v2/az6007.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h9
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c311
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c43
-rw-r--r--drivers/media/usb/dvb-usb-v2/it913x.c1
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h5
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c36
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h1
-rw-r--r--drivers/media/usb/dvb-usb-v2/usb_urb.c36
-rw-r--r--drivers/media/usb/dvb-usb/cinergyT2-fe.c3
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c465
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c5
-rw-r--r--drivers/media/usb/dvb-usb/dw2102.c19
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c10
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c2
-rw-r--r--drivers/media/usb/em28xx/Kconfig1
-rw-r--r--drivers/media/usb/em28xx/Makefile2
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c434
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c366
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c45
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c125
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c691
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h35
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c415
-rw-r--r--drivers/media/usb/em28xx/em28xx.h231
-rw-r--r--drivers/media/usb/gspca/autogain_functions.h183
-rw-r--r--drivers/media/usb/gspca/benq.c2
-rw-r--r--drivers/media/usb/gspca/conex.c12
-rw-r--r--drivers/media/usb/gspca/cpia1.c33
-rw-r--r--drivers/media/usb/gspca/etoms.c12
-rw-r--r--drivers/media/usb/gspca/gl860/gl860.c224
-rw-r--r--drivers/media/usb/gspca/gspca.c240
-rw-r--r--drivers/media/usb/gspca/gspca.h70
-rw-r--r--drivers/media/usb/gspca/jeilinj.c2
-rw-r--r--drivers/media/usb/gspca/konica.c28
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_bridge.h27
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_core.c22
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.c404
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.c312
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.h3
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.c469
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.c471
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.c352
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.h2
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.c291
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.h9
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_sensor.h3
-rw-r--r--drivers/media/usb/gspca/mr97310a.c8
-rw-r--r--drivers/media/usb/gspca/ov519.c81
-rw-r--r--drivers/media/usb/gspca/ov534.c2
-rw-r--r--drivers/media/usb/gspca/pac207.c2
-rw-r--r--drivers/media/usb/gspca/pac7302.c9
-rw-r--r--drivers/media/usb/gspca/pac7311.c5
-rw-r--r--drivers/media/usb/gspca/pac_common.h2
-rw-r--r--drivers/media/usb/gspca/sn9c2028.c4
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c2
-rw-r--r--drivers/media/usb/gspca/sonixb.c22
-rw-r--r--drivers/media/usb/gspca/sonixj.c556
-rw-r--r--drivers/media/usb/gspca/spca1528.c4
-rw-r--r--drivers/media/usb/gspca/spca500.c36
-rw-r--r--drivers/media/usb/gspca/spca501.c44
-rw-r--r--drivers/media/usb/gspca/spca505.c42
-rw-r--r--drivers/media/usb/gspca/spca508.c41
-rw-r--r--drivers/media/usb/gspca/spca561.c70
-rw-r--r--drivers/media/usb/gspca/sq905.c2
-rw-r--r--drivers/media/usb/gspca/sq905c.c6
-rw-r--r--drivers/media/usb/gspca/sq930x.c4
-rw-r--r--drivers/media/usb/gspca/stv0680.c14
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c17
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c8
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c14
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c2
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c10
-rw-r--r--drivers/media/usb/gspca/sunplus.c27
-rw-r--r--drivers/media/usb/gspca/vc032x.c9
-rw-r--r--drivers/media/usb/gspca/w996Xcf.c5
-rw-r--r--drivers/media/usb/gspca/zc3xx.c3
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-core.c15
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c945
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h19
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c10
-rw-r--r--drivers/media/usb/pwc/pwc-if.c1
-rw-r--r--drivers/media/usb/s2255/s2255drv.c441
-rw-r--r--drivers/media/usb/siano/smsusb.c158
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c14
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c309
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.h8
-rw-r--r--drivers/media/usb/tlg2300/pd-common.h26
-rw-r--r--drivers/media/usb/tlg2300/pd-main.c16
-rw-r--r--drivers/media/usb/tlg2300/pd-radio.c229
-rw-r--r--drivers/media/usb/tlg2300/pd-video.c303
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c16
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c10
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c20
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c10
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c2
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c1
-rw-r--r--drivers/media/v4l2-core/Kconfig1
-rw-r--r--drivers/media/v4l2-core/Makefile5
-rw-r--r--drivers/media/v4l2-core/tuner-core.c72
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c54
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c25
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c219
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c34
-rw-r--r--drivers/media/v4l2-core/v4l2-of.c266
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c130
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c32
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c8
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c25
-rw-r--r--drivers/media/v4l2-core/videobuf2-vmalloc.c4
-rw-r--r--drivers/memory/emif.c141
-rw-r--r--drivers/memory/tegra30-mc.c2
-rw-r--r--drivers/memstick/host/r592.c8
-rw-r--r--drivers/message/i2o/i2o_config.c10
-rw-r--r--drivers/mfd/Kconfig2
-rw-r--r--drivers/mfd/ab3100-core.c1
-rw-r--r--drivers/mfd/ab8500-core.c544
-rw-r--r--drivers/mfd/ab8500-debugfs.c1741
-rw-r--r--drivers/mfd/ab8500-gpadc.c559
-rw-r--r--drivers/mfd/ab8500-sysctrl.c98
-rw-r--r--drivers/mfd/pm8921-core.c14
-rw-r--r--drivers/mfd/wm5102-tables.c8
-rw-r--r--drivers/misc/Kconfig21
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/apds9802als.c25
-rw-r--r--drivers/misc/apds990x.c9
-rw-r--r--drivers/misc/arm-charlcd.c13
-rw-r--r--drivers/misc/atmel_pwm.c12
-rw-r--r--drivers/misc/bh1770glc.c7
-rw-r--r--drivers/misc/bh1780gli.c10
-rw-r--r--drivers/misc/cs5535-mfgpt.c41
-rw-r--r--drivers/misc/dummy-irq.c59
-rw-r--r--drivers/misc/eeprom/at25.c4
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c6
-rw-r--r--drivers/misc/ep93xx_pwm.c13
-rw-r--r--drivers/misc/fsa9480.c19
-rw-r--r--drivers/misc/isl29003.c19
-rw-r--r--drivers/misc/lattice-ecp3-config.c2
-rw-r--r--drivers/misc/mei/Kconfig5
-rw-r--r--drivers/misc/mei/Makefile9
-rw-r--r--drivers/misc/mei/amthif.c27
-rw-r--r--drivers/misc/mei/bus.c528
-rw-r--r--drivers/misc/mei/client.c140
-rw-r--r--drivers/misc/mei/client.h7
-rw-r--r--drivers/misc/mei/debugfs.c143
-rw-r--r--drivers/misc/mei/hbm.c91
-rw-r--r--drivers/misc/mei/hbm.h25
-rw-r--r--drivers/misc/mei/hw-me.c161
-rw-r--r--drivers/misc/mei/hw-me.h6
-rw-r--r--drivers/misc/mei/init.c86
-rw-r--r--drivers/misc/mei/interrupt.c246
-rw-r--r--drivers/misc/mei/main.c127
-rw-r--r--drivers/misc/mei/mei_dev.h167
-rw-r--r--drivers/misc/mei/nfc.c554
-rw-r--r--drivers/misc/mei/pci-me.c99
-rw-r--r--drivers/misc/mei/wd.c4
-rw-r--r--drivers/misc/sram.c121
-rw-r--r--drivers/misc/tsl2550.c21
-rw-r--r--drivers/misc/vmw_vmci/Kconfig2
-rw-r--r--drivers/misc/vmw_vmci/vmci_datagram.c4
-rw-r--r--drivers/mmc/card/sdio_uart.c13
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mmc/host/sdricoh_cs.c20
-rw-r--r--drivers/mtd/mtdchar.c59
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/appletalk/Kconfig18
-rw-r--r--drivers/net/arcnet/com20020_cs.c14
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c172
-rw-r--r--drivers/net/bonding/bond_sysfs.c92
-rw-r--r--drivers/net/caif/Kconfig7
-rw-r--r--drivers/net/caif/Makefile4
-rw-r--r--drivers/net/caif/caif_hsi.c7
-rw-r--r--drivers/net/caif/caif_serial.c8
-rw-r--r--drivers/net/caif/caif_shm_u5500.c128
-rw-r--r--drivers/net/caif/caif_shmcore.c747
-rw-r--r--drivers/net/caif/caif_spi.c6
-rw-r--r--drivers/net/caif/caif_spi_slave.c3
-rw-r--r--drivers/net/can/Kconfig2
-rw-r--r--drivers/net/can/at91_can.c76
-rw-r--r--drivers/net/can/bfin_can.c4
-rw-r--r--drivers/net/can/mcp251x.c75
-rw-r--r--drivers/net/can/sja1000/Kconfig1
-rw-r--r--drivers/net/can/sja1000/ems_pci.c6
-rw-r--r--drivers/net/can/sja1000/ems_pcmcia.c19
-rw-r--r--drivers/net/can/sja1000/kvaser_pci.c4
-rw-r--r--drivers/net/can/sja1000/peak_pci.c2
-rw-r--r--drivers/net/can/sja1000/peak_pcmcia.c21
-rw-r--r--drivers/net/can/sja1000/plx_pci.c12
-rw-r--r--drivers/net/can/sja1000/sja1000.c126
-rw-r--r--drivers/net/can/sja1000/sja1000.h68
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c31
-rw-r--r--drivers/net/can/softing/softing_cs.c16
-rw-r--r--drivers/net/ethernet/3com/3c509.c2
-rw-r--r--drivers/net/ethernet/3com/3c574_cs.c14
-rw-r--r--drivers/net/ethernet/3com/3c589_cs.c14
-rw-r--r--drivers/net/ethernet/3com/typhoon.c6
-rw-r--r--drivers/net/ethernet/8390/ax88796.c2
-rw-r--r--drivers/net/ethernet/8390/axnet_cs.c14
-rw-r--r--drivers/net/ethernet/8390/pcnet_cs.c14
-rw-r--r--drivers/net/ethernet/adaptec/starfire.c10
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c6
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c24
-rw-r--r--drivers/net/ethernet/alteon/acenic.c4
-rw-r--r--drivers/net/ethernet/amd/7990.c2
-rw-r--r--drivers/net/ethernet/amd/a2065.c1
-rw-r--r--drivers/net/ethernet/amd/am79c961a.c1
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c6
-rw-r--r--drivers/net/ethernet/amd/ariadne.c1
-rw-r--r--drivers/net/ethernet/amd/atarilance.c6
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c1
-rw-r--r--drivers/net/ethernet/amd/declance.c2
-rw-r--r--drivers/net/ethernet/amd/mvme147.c4
-rw-r--r--drivers/net/ethernet/amd/ni65.c2
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c14
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c1
-rw-r--r--drivers/net/ethernet/amd/sun3lance.c7
-rw-r--r--drivers/net/ethernet/amd/sunlance.c9
-rw-r--r--drivers/net/ethernet/apple/macmace.c16
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_hw.c2
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c24
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e.h3
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c42
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c21
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c21
-rw-r--r--drivers/net/ethernet/atheros/atlx/atlx.c10
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c73
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c84
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.h1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c19
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h58
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c375
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h47
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c377
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h91
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h252
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c258
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h16
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c356
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c79
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h21
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c351
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h27
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c77
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c126
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h9
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c4
-rw-r--r--drivers/net/ethernet/broadcom/cnic_if.h3
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c5
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c919
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h30
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c17
-rw-r--r--drivers/net/ethernet/cadence/at91_ether.c80
-rw-r--r--drivers/net/ethernet/cadence/macb.c84
-rw-r--r--drivers/net/ethernet/cadence/macb.h2
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c18
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/sge.c9
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c20
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h55
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c819
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c93
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c256
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h64
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h98
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h40
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/adapter.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c75
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h24
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c14
-rw-r--r--drivers/net/ethernet/cirrus/cs89x0.c74
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c13
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.c4
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.h4
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c6
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_dev.c3
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c231
-rw-r--r--drivers/net/ethernet/davicom/dm9000.h11
-rw-r--r--drivers/net/ethernet/dec/tulip/xircom_cb.c9
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c7
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h14
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c257
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h103
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c177
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h9
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c308
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h2
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c22
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c8
-rw-r--r--drivers/net/ethernet/freescale/Makefile3
-rw-r--r--drivers/net/ethernet/freescale/fec.h10
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c (renamed from drivers/net/ethernet/freescale/fec.c)288
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c16
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c7
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c17
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c176
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h8
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c29
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c6
-rw-r--r--drivers/net/ethernet/freescale/gianfar_sysfs.c2
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c881
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth_ethtool.c24
-rw-r--r--drivers/net/ethernet/fujitsu/fmvj18x_cs.c16
-rw-r--r--drivers/net/ethernet/i825xx/82596.c8
-rw-r--r--drivers/net/ethernet/i825xx/lib82596.c6
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c28
-rw-r--r--drivers/net/ethernet/ibm/emac/debug.c2
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c9
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c6
-rw-r--r--drivers/net/ethernet/intel/e100.c36
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c20
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c47
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c131
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c38
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h27
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h21
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c240
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h4
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c408
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.h11
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c37
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c350
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/param.c62
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c134
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c3
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c261
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h50
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h60
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c156
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.h4
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c124
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.h17
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.c11
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mbx.h52
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c27
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c261
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_regs.h53
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h141
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c354
-rw-r--r--drivers/net/ethernet/intel/igb/igb_hwmon.c29
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c1529
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c61
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c18
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c44
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c110
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c63
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c39
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c186
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c21
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c31
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h20
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c1
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c121
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c7
-rw-r--r--drivers/net/ethernet/jme.c6
-rw-r--r--drivers/net/ethernet/marvell/Kconfig8
-rw-r--r--drivers/net/ethernet/marvell/Makefile2
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c378
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c142
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c32
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c27
-rw-r--r--drivers/net/ethernet/marvell/sky2.c13
-rw-r--r--drivers/net/ethernet/marvell/sky2.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/Makefile2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c204
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cq.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c151
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c30
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c239
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c33
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_selftest.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c31
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c38
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c79
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c51
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h38
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h26
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c129
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.c20
-rw-r--r--drivers/net/ethernet/micrel/ks8851.c55
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c32
-rw-r--r--drivers/net/ethernet/microchip/enc28j60.c4
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c12
-rw-r--r--drivers/net/ethernet/natsemi/jazzsonic.c12
-rw-r--r--drivers/net/ethernet/natsemi/macsonic.c12
-rw-r--r--drivers/net/ethernet/natsemi/ns83820.c4
-rw-r--r--drivers/net/ethernet/natsemi/sonic.c1
-rw-r--r--drivers/net/ethernet/natsemi/xtsonic.c12
-rw-r--r--drivers/net/ethernet/neterion/s2io.c10
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c14
-rw-r--r--drivers/net/ethernet/netx-eth.c2
-rw-r--r--drivers/net/ethernet/nuvoton/w90p910_ether.c20
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c64
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c4
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c23
-rw-r--r--drivers/net/ethernet/pasemi/pasemi_mac.c5
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig10
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h5
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c4
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c222
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/Makefile4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h129
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c520
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h204
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c107
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c75
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c125
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c63
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h10
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c107
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c371
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h263
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c1954
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c1780
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c259
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c2
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c70
-rw-r--r--drivers/net/ethernet/rdc/r6040.c12
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c8
-rw-r--r--drivers/net/ethernet/realtek/8139too.c2
-rw-r--r--drivers/net/ethernet/realtek/atp.c2
-rw-r--r--drivers/net/ethernet/realtek/r8169.c323
-rw-r--r--drivers/net/ethernet/renesas/Kconfig3
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c438
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h222
-rw-r--r--drivers/net/ethernet/s6gmac.c16
-rw-r--r--drivers/net/ethernet/seeq/ether3.c22
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.c2
-rw-r--r--drivers/net/ethernet/sfc/Kconfig2
-rw-r--r--drivers/net/ethernet/sfc/efx.c267
-rw-r--r--drivers/net/ethernet/sfc/efx.h14
-rw-r--r--drivers/net/ethernet/sfc/enum.h12
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c4
-rw-r--r--drivers/net/ethernet/sfc/falcon.c17
-rw-r--r--drivers/net/ethernet/sfc/filter.c249
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c2
-rw-r--r--drivers/net/ethernet/sfc/mcdi_pcol.h1
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h97
-rw-r--r--drivers/net/ethernet/sfc/nic.c94
-rw-r--r--drivers/net/ethernet/sfc/ptp.c116
-rw-r--r--drivers/net/ethernet/sfc/rx.c793
-rw-r--r--drivers/net/ethernet/sfc/siena.c25
-rw-r--r--drivers/net/ethernet/sgi/meth.c5
-rw-r--r--drivers/net/ethernet/sis/sis900.c41
-rw-r--r--drivers/net/ethernet/smsc/Kconfig4
-rw-r--r--drivers/net/ethernet/smsc/smc9194.c2
-rw-r--r--drivers/net/ethernet/smsc/smc91c92_cs.c14
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c2
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c2
-rw-r--r--drivers/net/ethernet/smsc/smsc9420.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c92
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h199
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs.h51
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/descs_com.h43
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h81
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c168
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c31
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c31
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c30
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c151
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc_core.c1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c89
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c40
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h73
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c156
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c148
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c1340
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c211
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h74
-rw-r--r--drivers/net/ethernet/sun/niu.c2
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c4
-rw-r--r--drivers/net/ethernet/sun/sunhme.c13
-rw-r--r--drivers/net/ethernet/sun/sunqe.c5
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c17
-rw-r--r--drivers/net/ethernet/ti/cpsw.c334
-rw-r--r--drivers/net/ethernet/ti/cpts.c2
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c31
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.h2
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c56
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c1
-rw-r--r--drivers/net/ethernet/ti/tlan.c5
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c240
-rw-r--r--drivers/net/ethernet/toshiba/spider_net.c7
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c21
-rw-r--r--drivers/net/ethernet/via/via-rhine.c17
-rw-r--r--drivers/net/ethernet/via/via-velocity.c15
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c4
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c33
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c25
-rw-r--r--drivers/net/ethernet/xircom/xirc2ps_cs.c17
-rw-r--r--drivers/net/fddi/defxx.c9
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hyperv/netvsc.c17
-rw-r--r--drivers/net/hyperv/netvsc_drv.c4
-rw-r--r--drivers/net/hyperv/rndis_filter.c14
-rw-r--r--drivers/net/ieee802154/at86rf230.c151
-rw-r--r--drivers/net/ieee802154/fakehard.c21
-rw-r--r--drivers/net/ieee802154/mrf24j40.c41
-rw-r--r--drivers/net/ifb.c3
-rw-r--r--drivers/net/irda/ali-ircc.c6
-rw-r--r--drivers/net/irda/au1k_ir.c18
-rw-r--r--drivers/net/irda/bfin_sir.c3
-rw-r--r--drivers/net/irda/nsc-ircc.c6
-rw-r--r--drivers/net/irda/pxaficp_ir.c4
-rw-r--r--drivers/net/irda/smsc-ircc2.c17
-rw-r--r--drivers/net/irda/via-ircc.c6
-rw-r--r--drivers/net/irda/w83977af_ir.c7
-rw-r--r--drivers/net/macvlan.c29
-rw-r--r--drivers/net/macvtap.c2
-rw-r--r--drivers/net/phy/lxt.c2
-rw-r--r--drivers/net/phy/marvell.c127
-rw-r--r--drivers/net/phy/mdio-gpio.c12
-rw-r--r--drivers/net/phy/mdio-octeon.c107
-rw-r--r--drivers/net/phy/micrel.c41
-rw-r--r--drivers/net/phy/phy.c66
-rw-r--r--drivers/net/phy/spi_ks8995.c8
-rw-r--r--drivers/net/phy/vitesse.c3
-rw-r--r--drivers/net/plip/plip.c2
-rw-r--r--drivers/net/ppp/ppp_async.c2
-rw-r--r--drivers/net/ppp/ppp_synctty.c55
-rw-r--r--drivers/net/team/Kconfig12
-rw-r--r--drivers/net/team/Makefile1
-rw-r--r--drivers/net/team/team.c45
-rw-r--r--drivers/net/team/team_mode_broadcast.c14
-rw-r--r--drivers/net/team/team_mode_random.c71
-rw-r--r--drivers/net/team/team_mode_roundrobin.c36
-rw-r--r--drivers/net/tun.c20
-rw-r--r--drivers/net/usb/asix_devices.c6
-rw-r--r--drivers/net/usb/ax88179_178a.c12
-rw-r--r--drivers/net/usb/cdc_ether.c5
-rw-r--r--drivers/net/usb/cdc_mbim.c11
-rw-r--r--drivers/net/usb/cdc_ncm.c18
-rw-r--r--drivers/net/usb/dm9601.c7
-rw-r--r--drivers/net/usb/hso.c20
-rw-r--r--drivers/net/usb/mcs7830.c6
-rw-r--r--drivers/net/usb/pegasus.c447
-rw-r--r--drivers/net/usb/pegasus.h11
-rw-r--r--drivers/net/usb/qmi_wwan.c109
-rw-r--r--drivers/net/usb/sierra_net.c3
-rw-r--r--drivers/net/usb/smsc75xx.c18
-rw-r--r--drivers/net/usb/smsc95xx.c6
-rw-r--r--drivers/net/usb/usbnet.c45
-rw-r--r--drivers/net/veth.c3
-rw-r--r--drivers/net/virtio_net.c14
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c17
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c5
-rw-r--r--drivers/net/vxlan.c546
-rw-r--r--drivers/net/wireless/adm8211.c3
-rw-r--r--drivers/net/wireless/airo_cs.c14
-rw-r--r--drivers/net/wireless/at76c50x-usb.c4
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c16
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c6
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h3
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c20
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/trace.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/Kconfig9
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile5
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c15
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h3
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c72
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h11
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_mbox.c21
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c15
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c116
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c41
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c16
-rw-r--r--drivers/net/wireless/ath/ath6kl/target.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/trace.c23
-rw-r--r--drivers/net/wireless/ath/ath6kl/trace.h332
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c5
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c38
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c92
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h49
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h9
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.c53
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.h27
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c18
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c198
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h14
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c41
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c177
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c137
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h8
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.c4
-rw-r--r--drivers/net/wireless/ath/carl9170/mac.c8
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c11
-rw-r--r--drivers/net/wireless/ath/carl9170/phy.c85
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c69
-rw-r--r--drivers/net/wireless/ath/hw.c6
-rw-r--r--drivers/net/wireless/ath/key.c9
-rw-r--r--drivers/net/wireless/ath/reg.h4
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile4
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c33
-rw-r--r--drivers/net/wireless/ath/wil6210/dbg_hexdump.h20
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c58
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c25
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c60
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c36
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h49
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h17
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c154
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h363
-rw-r--r--drivers/net/wireless/atmel_cs.c14
-rw-r--r--drivers/net/wireless/b43/Kconfig6
-rw-r--r--drivers/net/wireless/b43/b43.h10
-rw-r--r--drivers/net/wireless/b43/dma.c74
-rw-r--r--drivers/net/wireless/b43/main.c38
-rw-r--r--drivers/net/wireless/b43/pcmcia.c4
-rw-r--r--drivers/net/wireless/b43/phy_ht.c708
-rw-r--r--drivers/net/wireless/b43/phy_ht.h83
-rw-r--r--drivers/net/wireless/b43/phy_lcn.c5
-rw-r--r--drivers/net/wireless/b43/phy_lp.c16
-rw-r--r--drivers/net/wireless/b43/phy_n.c727
-rw-r--r--drivers/net/wireless/b43/phy_n.h146
-rw-r--r--drivers/net/wireless/b43/radio_2056.c6
-rw-r--r--drivers/net/wireless/b43/radio_2059.c39
-rw-r--r--drivers/net/wireless/b43/radio_2059.h14
-rw-r--r--drivers/net/wireless/b43/sdio.h4
-rw-r--r--drivers/net/wireless/b43/tables_nphy.c101
-rw-r--r--drivers/net/wireless/b43/tables_nphy.h29
-rw-r--r--drivers/net/wireless/b43/tables_phy_lcn.c6
-rw-r--r--drivers/net/wireless/b43legacy/dma.c8
-rw-r--r--drivers/net/wireless/b43legacy/main.c9
-rw-r--r--drivers/net/wireless/brcm80211/Kconfig14
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/Makefile6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c269
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c176
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/btcoex.c497
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/btcoex.h29
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h41
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h15
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c34
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c33
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c80
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h55
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c148
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c800
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.c25
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c2067
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h33
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/p2p.c288
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c369
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h101
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c22
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h101
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c647
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h25
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/Makefile7
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/channel.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/d11.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/led.c126
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/led.h36
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c361
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h4
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c377
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.h25
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c40
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c404
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c14
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c64
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.c54
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pmu.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h17
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/Makefile9
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/d11.c162
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/utils.c37
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h2
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_d11.h145
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_utils.h27
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_wifi.h28
-rw-r--r--drivers/net/wireless/brcm80211/include/chipcommon.h14
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c15
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c32
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945-rs.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945.c4
-rw-r--r--drivers/net/wireless/iwlegacy/3945.h4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c65
-rw-r--r--drivers/net/wireless/iwlegacy/4965-rs.c5
-rw-r--r--drivers/net/wireless/iwlegacy/4965.c2
-rw-r--r--drivers/net/wireless/iwlegacy/common.c26
-rw-r--r--drivers/net/wireless/iwlegacy/common.h11
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig11
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile3
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/agn.h10
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/calib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/calib.h2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/commands.h3
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/debugfs.c42
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c10
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/lib.c27
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c32
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c6
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c29
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/sta.c5
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/testmode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c60
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/ucode.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c (renamed from drivers/net/wireless/iwlwifi/pcie/1000.c)1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c (renamed from drivers/net/wireless/iwlwifi/pcie/2000.c)1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c (renamed from drivers/net/wireless/iwlwifi/pcie/5000.c)1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c (renamed from drivers/net/wireless/iwlwifi/pcie/6000.c)1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c (renamed from drivers/net/wireless/iwlwifi/pcie/7000.c)63
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h49
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-read.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-read.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.c15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c51
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-op-mode.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/binding.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/bt-coex.c589
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c267
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c257
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h319
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h53
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h66
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h83
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/led.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c87
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c119
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h59
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c145
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c48
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c14
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c117
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c50
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c99
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.c50
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/time-event.h5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c28
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c9
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/cfg.h115
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c6
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c38
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c15
-rw-r--r--drivers/net/wireless/libertas/if_cs.c25
-rw-r--r--drivers/net/wireless/libertas_tf/main.c8
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c125
-rw-r--r--drivers/net/wireless/mwifiex/11ac.c43
-rw-r--r--drivers/net/wireless/mwifiex/11ac.h17
-rw-r--r--drivers/net/wireless/mwifiex/11n.c22
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c14
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c2
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c258
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c39
-rw-r--r--drivers/net/wireless/mwifiex/decl.h11
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c70
-rw-r--r--drivers/net/wireless/mwifiex/fw.h83
-rw-r--r--drivers/net/wireless/mwifiex/init.c33
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h31
-rw-r--r--drivers/net/wireless/mwifiex/join.c23
-rw-r--r--drivers/net/wireless/mwifiex/main.c15
-rw-r--r--drivers/net/wireless/mwifiex/main.h23
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c217
-rw-r--r--drivers/net/wireless/mwifiex/scan.c48
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c83
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c6
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c30
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c2
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c55
-rw-r--r--drivers/net/wireless/mwifiex/util.c6
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c208
-rw-r--r--drivers/net/wireless/mwifiex/wmm.h3
-rw-r--r--drivers/net/wireless/mwl8k.c167
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c16
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c2
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c16
-rw-r--r--drivers/net/wireless/p54/fwio.c4
-rw-r--r--drivers/net/wireless/p54/main.c6
-rw-r--r--drivers/net/wireless/p54/p54spi.c6
-rw-r--r--drivers/net/wireless/p54/txrx.c4
-rw-r--r--drivers/net/wireless/ray_cs.c8
-rw-r--r--drivers/net/wireless/rndis_wlan.c5
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig14
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c324
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c354
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c35
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h103
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c1489
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c378
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c111
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h95
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c24
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c25
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00leds.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c19
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mmio.c216
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mmio.h119
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c190
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h88
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c57
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h15
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00soc.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c44
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c551
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c32
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/dev.c4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/grf5101.c3
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/max2820.c2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/rtl8225.c3
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180/sa2400.c3
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/rtl8225.c3
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig9
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile1
-rw-r--r--drivers/net/wireless/rtlwifi/base.c383
-rw-r--r--drivers/net/wireless/rtlwifi/base.h14
-rw-r--r--drivers/net/wireless/rtlwifi/core.c221
-rw-r--r--drivers/net/wireless/rtlwifi/debug.c5
-rw-r--r--drivers/net/wireless/rtlwifi/debug.h13
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.c53
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.h1
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c150
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h2
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c330
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/Makefile16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/def.h324
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c1794
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.h326
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.c830
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/fw.h301
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.c2530
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/hw.h68
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/led.c157
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/led.h38
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/phy.c2202
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/phy.h236
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c109
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h327
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c140
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h97
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/reg.h2258
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/rf.c467
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/rf.h46
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/sw.c400
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/sw.h36
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/table.c643
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/table.h47
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.c817
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.h795
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c105
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c99
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c118
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/reg.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c328
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c10
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c32
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/phy.c40
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/reg.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/sw.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/def.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c49
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c150
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.h3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.c61
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c300
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.c88
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.h6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.c97
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/fw.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/hw.c70
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/led.c22
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/sw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.c14
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c226
-rw-r--r--drivers/net/wireless/rtlwifi/usb.h5
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h224
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c5
-rw-r--r--drivers/net/wireless/ti/wl1251/sdio.c4
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c4
-rw-r--r--drivers/net/wireless/ti/wl12xx/cmd.c2
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c1
-rw-r--r--drivers/net/wireless/ti/wl12xx/wl12xx.h2
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.c6
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c25
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h29
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h4
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c29
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.h16
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c32
-rw-r--r--drivers/net/wireless/ti/wlcore/debug.h33
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c3
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c9
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c205
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c39
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h3
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h29
-rw-r--r--drivers/net/wireless/wl3501_cs.c14
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c4
-rw-r--r--drivers/net/xen-netback/netback.c316
-rw-r--r--drivers/net/xen-netfront.c47
-rw-r--r--drivers/nfc/Kconfig10
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/mei_phy.c164
-rw-r--r--drivers/nfc/mei_phy.h30
-rw-r--r--drivers/nfc/microread/Kconfig2
-rw-r--r--drivers/nfc/microread/mei.c159
-rw-r--r--drivers/nfc/pn533.c653
-rw-r--r--drivers/nfc/pn544/Kconfig13
-rw-r--r--drivers/nfc/pn544/Makefile2
-rw-r--r--drivers/nfc/pn544/mei.c121
-rw-r--r--drivers/of/base.c1
-rw-r--r--drivers/of/of_mdio.c64
-rw-r--r--drivers/parport/parport_amiga.c15
-rw-r--r--drivers/parport/parport_cs.c14
-rw-r--r--drivers/parport/parport_gsc.c4
-rw-r--r--drivers/parport/parport_sunbpp.c5
-rw-r--r--drivers/parport/procfs.c6
-rw-r--r--drivers/pci/bus.c14
-rw-r--r--drivers/pci/hotplug/Kconfig7
-rw-r--r--drivers/pci/hotplug/acpiphp.h35
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c30
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c415
-rw-r--r--drivers/pci/hotplug/cpci_hotplug.h44
-rw-r--r--drivers/pci/hotplug/cpqphp.h70
-rw-r--r--drivers/pci/hotplug/cpqphp_nvram.h12
-rw-r--r--drivers/pci/hotplug/ibmphp.h66
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c15
-rw-r--r--drivers/pci/hotplug/pciehp.h22
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c2
-rw-r--r--drivers/pci/hotplug/rpadlpar.h8
-rw-r--r--drivers/pci/hotplug/rpaphp.h16
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c12
-rw-r--r--drivers/pci/hotplug/shpchp.h26
-rw-r--r--drivers/pci/hotplug/shpchp_sysfs.c2
-rw-r--r--drivers/pci/iov.c41
-rw-r--r--drivers/pci/msi.c180
-rw-r--r--drivers/pci/msi.h24
-rw-r--r--drivers/pci/pci-acpi.c45
-rw-r--r--drivers/pci/pci-driver.c5
-rw-r--r--drivers/pci/pci-sysfs.c2
-rw-r--r--drivers/pci/pci.c25
-rw-r--r--drivers/pci/pci.h89
-rw-r--r--drivers/pci/pcie/Kconfig2
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c10
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c4
-rw-r--r--drivers/pci/pcie/pme.c2
-rw-r--r--drivers/pci/pcie/portdrv.h18
-rw-r--r--drivers/pci/pcie/portdrv_acpi.c1
-rw-r--r--drivers/pci/pcie/portdrv_pci.c30
-rw-r--r--drivers/pci/probe.c15
-rw-r--r--drivers/pci/quirks.c148
-rw-r--r--drivers/pci/remove.c4
-rw-r--r--drivers/pci/rom.c67
-rw-r--r--drivers/pci/setup-bus.c4
-rw-r--r--drivers/pci/setup-res.c2
-rw-r--r--drivers/pci/slot.c7
-rw-r--r--drivers/pinctrl/Kconfig25
-rw-r--r--drivers/pinctrl/Makefile5
-rw-r--r--drivers/pinctrl/core.c359
-rw-r--r--drivers/pinctrl/core.h8
-rw-r--r--drivers/pinctrl/devicetree.c19
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c39
-rw-r--r--drivers/pinctrl/pinconf-generic.c20
-rw-r--r--drivers/pinctrl/pinconf.c335
-rw-r--r--drivers/pinctrl/pinconf.h8
-rw-r--r--drivers/pinctrl/pinctrl-ab8500.c5
-rw-r--r--drivers/pinctrl/pinctrl-ab8505.c7
-rw-r--r--drivers/pinctrl/pinctrl-ab8540.c5
-rw-r--r--drivers/pinctrl/pinctrl-ab9540.c7
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c18
-rw-r--r--drivers/pinctrl/pinctrl-at91.c27
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c6
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c9
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c36
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h16
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c159
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-imx.c6
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c4
-rw-r--r--drivers/pinctrl/pinctrl-mmp2.c722
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c6
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c4
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-stn8815.c2
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c16
-rw-r--r--drivers/pinctrl/pinctrl-pxa168.c651
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c227
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.h262
-rw-r--r--drivers/pinctrl/pinctrl-pxa910.c1007
-rw-r--r--drivers/pinctrl/pinctrl-s3c64xx.c816
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c105
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h42
-rw-r--r--drivers/pinctrl/pinctrl-single.c515
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c14
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c986
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c6
-rw-r--r--drivers/pinctrl/pinctrl-u300.c6
-rw-r--r--drivers/pinctrl/pinctrl-xway.c2
-rw-r--r--drivers/pinctrl/pinmux.c8
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c4
-rw-r--r--drivers/platform/x86/hp-wmi.c4
-rw-r--r--drivers/platform/x86/sony-laptop.c3
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c10
-rw-r--r--drivers/pnp/isapnp/core.c11
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c1
-rw-r--r--drivers/pnp/pnpbios/proc.c5
-rw-r--r--drivers/power/88pm860x_charger.c2
-rw-r--r--drivers/power/Kconfig16
-rw-r--r--drivers/power/Makefile4
-rw-r--r--drivers/power/ab8500_bmdata.c140
-rw-r--r--drivers/power/ab8500_btemp.c80
-rw-r--r--drivers/power/ab8500_charger.c699
-rw-r--r--drivers/power/ab8500_fg.c501
-rw-r--r--drivers/power/abx500_chargalg.c455
-rw-r--r--drivers/power/charger-manager.c3
-rw-r--r--drivers/power/da9030_battery.c6
-rw-r--r--drivers/power/da9052-battery.c5
-rw-r--r--drivers/power/ds2760_battery.c4
-rw-r--r--drivers/power/ds2780_battery.c7
-rw-r--r--drivers/power/ds2782_battery.c23
-rw-r--r--drivers/power/goldfish_battery.c2
-rw-r--r--drivers/power/gpio-charger.c5
-rw-r--r--drivers/power/isp1704_charger.c5
-rw-r--r--drivers/power/lp8788-charger.c8
-rw-r--r--drivers/power/max17040_battery.c20
-rw-r--r--drivers/power/max8903_charger.c4
-rw-r--r--drivers/power/max8925_power.c5
-rw-r--r--drivers/power/max8997_charger.c9
-rw-r--r--drivers/power/max8998_charger.c5
-rw-r--r--drivers/power/pcf50633-charger.c7
-rw-r--r--drivers/power/pda_power.c14
-rw-r--r--drivers/power/pm2301_charger.c393
-rw-r--r--drivers/power/pm2301_charger.h23
-rw-r--r--drivers/power/power_supply_core.c187
-rw-r--r--drivers/power/reset/Kconfig7
-rw-r--r--drivers/power/reset/Makefile3
-rw-r--r--drivers/power/reset/vexpress-poweroff.c (renamed from arch/arm/mach-vexpress/reset.c)9
-rw-r--r--drivers/power/rx51_battery.c8
-rw-r--r--drivers/power/s3c_adc_battery.c7
-rw-r--r--drivers/power/sbs-battery.c22
-rw-r--r--drivers/power/test_power.c31
-rw-r--r--drivers/power/tps65090-charger.c320
-rw-r--r--drivers/power/twl4030_charger.c12
-rw-r--r--drivers/power/wm831x_backup.c10
-rw-r--r--drivers/pps/Kconfig6
-rw-r--r--drivers/pps/kc.c6
-rw-r--r--drivers/ptp/ptp_clock.c38
-rw-r--r--drivers/ptp/ptp_pch.c29
-rw-r--r--drivers/regulator/88pm8607.c36
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ab3100.c236
-rw-r--r--drivers/regulator/ab8500-ext.c407
-rw-r--r--drivers/regulator/ab8500.c2662
-rw-r--r--drivers/regulator/arizona-ldo1.c2
-rw-r--r--drivers/regulator/as3711-regulator.c67
-rw-r--r--drivers/regulator/core.c220
-rw-r--r--drivers/regulator/dbx500-prcmu.h2
-rw-r--r--drivers/regulator/fan53555.c4
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/lp3972.c2
-rw-r--r--drivers/regulator/lp872x.c3
-rw-r--r--drivers/regulator/lp8788-buck.c2
-rw-r--r--drivers/regulator/lp8788-ldo.c157
-rw-r--r--drivers/regulator/max1586.c5
-rw-r--r--drivers/regulator/max77686.c32
-rw-r--r--drivers/regulator/max8649.c45
-rw-r--r--drivers/regulator/max8660.c3
-rw-r--r--drivers/regulator/max8925-regulator.c5
-rw-r--r--drivers/regulator/max8952.c75
-rw-r--r--drivers/regulator/max8973-regulator.c10
-rw-r--r--drivers/regulator/max8997.c4
-rw-r--r--drivers/regulator/max8998.c9
-rw-r--r--drivers/regulator/mc13783-regulator.c44
-rw-r--r--drivers/regulator/mc13892-regulator.c46
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c17
-rw-r--r--drivers/regulator/mc13xxx.h4
-rw-r--r--drivers/regulator/palmas-regulator.c365
-rw-r--r--drivers/regulator/rc5t583-regulator.c6
-rw-r--r--drivers/regulator/s5m8767.c8
-rw-r--r--drivers/regulator/tps62360-regulator.c2
-rw-r--r--drivers/regulator/tps65023-regulator.c48
-rw-r--r--drivers/regulator/tps6507x-regulator.c1
-rw-r--r--drivers/regulator/tps6524x-regulator.c4
-rw-r--r--drivers/regulator/tps6586x-regulator.c7
-rw-r--r--drivers/regulator/tps65910-regulator.c4
-rw-r--r--drivers/regulator/tps80031-regulator.c45
-rw-r--r--drivers/regulator/twl-regulator.c34
-rw-r--r--drivers/regulator/wm8994-regulator.c61
-rw-r--r--drivers/remoteproc/Kconfig2
-rw-r--r--drivers/remoteproc/remoteproc_core.c8
-rw-r--r--drivers/remoteproc/ste_modem_rproc.c7
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c4
-rw-r--r--drivers/rtc/Kconfig4
-rw-r--r--drivers/rtc/class.c70
-rw-r--r--drivers/rtc/rtc-88pm80x.c5
-rw-r--r--drivers/rtc/rtc-88pm860x.c29
-rw-r--r--drivers/rtc/rtc-ab3100.c21
-rw-r--r--drivers/rtc/rtc-ab8500.c18
-rw-r--r--drivers/rtc/rtc-at32ap700x.c39
-rw-r--r--drivers/rtc/rtc-at91rm9200.c100
-rw-r--r--drivers/rtc/rtc-at91rm9200.h1
-rw-r--r--drivers/rtc/rtc-at91sam9.c57
-rw-r--r--drivers/rtc/rtc-au1xxx.c18
-rw-r--r--drivers/rtc/rtc-bfin.c34
-rw-r--r--drivers/rtc/rtc-bq32k.c5
-rw-r--r--drivers/rtc/rtc-bq4802.c29
-rw-r--r--drivers/rtc/rtc-cmos.c4
-rw-r--r--drivers/rtc/rtc-coh901331.c42
-rw-r--r--drivers/rtc/rtc-da9052.c5
-rw-r--r--drivers/rtc/rtc-da9055.c5
-rw-r--r--drivers/rtc/rtc-davinci.c24
-rw-r--r--drivers/rtc/rtc-dm355evm.c7
-rw-r--r--drivers/rtc/rtc-ds1216.c44
-rw-r--r--drivers/rtc/rtc-ds1286.c49
-rw-r--r--drivers/rtc/rtc-ds1302.c22
-rw-r--r--drivers/rtc/rtc-ds1305.c35
-rw-r--r--drivers/rtc/rtc-ds1307.c74
-rw-r--r--drivers/rtc/rtc-ds1374.c35
-rw-r--r--drivers/rtc/rtc-ds1390.c15
-rw-r--r--drivers/rtc/rtc-ds1511.c8
-rw-r--r--drivers/rtc/rtc-ds1553.c6
-rw-r--r--drivers/rtc/rtc-ds1672.c8
-rw-r--r--drivers/rtc/rtc-ds1742.c8
-rw-r--r--drivers/rtc/rtc-ds2404.c12
-rw-r--r--drivers/rtc/rtc-ds3232.c25
-rw-r--r--drivers/rtc/rtc-ds3234.c9
-rw-r--r--drivers/rtc/rtc-efi.c19
-rw-r--r--drivers/rtc/rtc-em3027.c7
-rw-r--r--drivers/rtc/rtc-ep93xx.c11
-rw-r--r--drivers/rtc/rtc-fm3130.c11
-rw-r--r--drivers/rtc/rtc-generic.c21
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c7
-rw-r--r--drivers/rtc/rtc-imxdi.c23
-rw-r--r--drivers/rtc/rtc-isl12022.c30
-rw-r--r--drivers/rtc/rtc-lp8788.c5
-rw-r--r--drivers/rtc/rtc-lpc32xx.c5
-rw-r--r--drivers/rtc/rtc-ls1x.c5
-rw-r--r--drivers/rtc/rtc-m41t80.c16
-rw-r--r--drivers/rtc/rtc-m41t93.c11
-rw-r--r--drivers/rtc/rtc-m41t94.c11
-rw-r--r--drivers/rtc/rtc-m48t35.c42
-rw-r--r--drivers/rtc/rtc-m48t86.c11
-rw-r--r--drivers/rtc/rtc-max6900.c9
-rw-r--r--drivers/rtc/rtc-max6902.c29
-rw-r--r--drivers/rtc/rtc-max77686.c73
-rw-r--r--drivers/rtc/rtc-max8907.c20
-rw-r--r--drivers/rtc/rtc-max8925.c26
-rw-r--r--drivers/rtc/rtc-max8997.c19
-rw-r--r--drivers/rtc/rtc-max8998.c18
-rw-r--r--drivers/rtc/rtc-mc13xxx.c23
-rw-r--r--drivers/rtc/rtc-msm6242.c45
-rw-r--r--drivers/rtc/rtc-mv.c23
-rw-r--r--drivers/rtc/rtc-mxc.c15
-rw-r--r--drivers/rtc/rtc-nuc900.c72
-rw-r--r--drivers/rtc/rtc-omap.c81
-rw-r--r--drivers/rtc/rtc-palmas.c19
-rw-r--r--drivers/rtc/rtc-pcap.c53
-rw-r--r--drivers/rtc/rtc-pcf2123.c12
-rw-r--r--drivers/rtc/rtc-pcf50633.c15
-rw-r--r--drivers/rtc/rtc-pcf8523.c6
-rw-r--r--drivers/rtc/rtc-pcf8563.c28
-rw-r--r--drivers/rtc/rtc-pcf8583.c24
-rw-r--r--drivers/rtc/rtc-ps3.c16
-rw-r--r--drivers/rtc/rtc-puv3.c27
-rw-r--r--drivers/rtc/rtc-pxa.c24
-rw-r--r--drivers/rtc/rtc-r9701.c9
-rw-r--r--drivers/rtc/rtc-rc5t583.c19
-rw-r--r--drivers/rtc/rtc-rp5c01.c39
-rw-r--r--drivers/rtc/rtc-rs5c313.c6
-rw-r--r--drivers/rtc/rtc-rs5c348.c12
-rw-r--r--drivers/rtc/rtc-rs5c372.c30
-rw-r--r--drivers/rtc/rtc-rv3029c2.c16
-rw-r--r--drivers/rtc/rtc-rx4581.c9
-rw-r--r--drivers/rtc/rtc-rx8581.c8
-rw-r--r--drivers/rtc/rtc-s35390a.c14
-rw-r--r--drivers/rtc/rtc-s3c.c37
-rw-r--r--drivers/rtc/rtc-sa1100.c29
-rw-r--r--drivers/rtc/rtc-sh.c22
-rw-r--r--drivers/rtc/rtc-snvs.c6
-rw-r--r--drivers/rtc/rtc-spear.c23
-rw-r--r--drivers/rtc/rtc-starfire.c23
-rw-r--r--drivers/rtc/rtc-stk17ta8.c6
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c51
-rw-r--r--drivers/rtc/rtc-sun4v.c22
-rw-r--r--drivers/rtc/rtc-tegra.c64
-rw-r--r--drivers/rtc/rtc-test.c10
-rw-r--r--drivers/rtc/rtc-tile.c9
-rw-r--r--drivers/rtc/rtc-tps6586x.c14
-rw-r--r--drivers/rtc/rtc-tps65910.c13
-rw-r--r--drivers/rtc/rtc-tps80031.c11
-rw-r--r--drivers/rtc/rtc-twl.c16
-rw-r--r--drivers/rtc/rtc-tx4939.c19
-rw-r--r--drivers/rtc/rtc-v3020.c13
-rw-r--r--drivers/rtc/rtc-vt8500.c8
-rw-r--r--drivers/rtc/rtc-wm831x.c6
-rw-r--r--drivers/rtc/rtc-wm8350.c19
-rw-r--r--drivers/rtc/rtc-x1205.c14
-rw-r--r--drivers/s390/block/dasd.c172
-rw-r--r--drivers/s390/block/dasd_devmap.c3
-rw-r--r--drivers/s390/block/dasd_eckd.c344
-rw-r--r--drivers/s390/block/dasd_int.h10
-rw-r--r--drivers/s390/block/dasd_ioctl.c31
-rw-r--r--drivers/s390/block/scm_blk.c14
-rw-r--r--drivers/s390/block/scm_blk_cluster.c6
-rw-r--r--drivers/s390/block/scm_drv.c2
-rw-r--r--drivers/s390/char/con3215.c4
-rw-r--r--drivers/s390/char/monreader.c3
-rw-r--r--drivers/s390/char/raw3270.c6
-rw-r--r--drivers/s390/char/sclp_cmd.c4
-rw-r--r--drivers/s390/char/sclp_tty.c9
-rw-r--r--drivers/s390/char/sclp_vt220.c8
-rw-r--r--drivers/s390/char/tty3270.c16
-rw-r--r--drivers/s390/char/zcore.c2
-rw-r--r--drivers/s390/cio/chp.c22
-rw-r--r--drivers/s390/cio/chp.h2
-rw-r--r--drivers/s390/cio/chsc.c11
-rw-r--r--drivers/s390/cio/cio.c160
-rw-r--r--drivers/s390/cio/cio.h11
-rw-r--r--drivers/s390/cio/css.c114
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device.c139
-rw-r--r--drivers/s390/cio/device.h2
-rw-r--r--drivers/s390/cio/device_ops.c22
-rw-r--r--drivers/s390/cio/idset.c2
-rw-r--r--drivers/s390/kvm/virtio_ccw.c6
-rw-r--r--drivers/s390/net/qeth_core.h7
-rw-r--r--drivers/s390/net/qeth_core_main.c27
-rw-r--r--drivers/s390/net/qeth_l2_main.c15
-rw-r--r--drivers/s390/net/qeth_l3_main.c35
-rw-r--r--drivers/sbus/char/bbc_i2c.c4
-rw-r--r--drivers/scsi/aacraid/aacraid.h6
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/src.c26
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c2
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h23
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c41
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c22
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c9
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h12
-rw-r--r--drivers/scsi/csiostor/Makefile3
-rw-r--r--drivers/scsi/csiostor/csio_hw.c564
-rw-r--r--drivers/scsi/csiostor/csio_hw.h47
-rw-r--r--drivers/scsi/csiostor/csio_hw_chip.h175
-rw-r--r--drivers/scsi/csiostor/csio_hw_t4.c403
-rw-r--r--drivers/scsi/csiostor/csio_hw_t5.c397
-rw-r--r--drivers/scsi/csiostor/csio_init.c48
-rw-r--r--drivers/scsi/csiostor/csio_init.h29
-rw-r--r--drivers/scsi/csiostor/csio_lnode.h2
-rw-r--r--drivers/scsi/csiostor/csio_mb.c12
-rw-r--r--drivers/scsi/csiostor/csio_rnode.c10
-rw-r--r--drivers/scsi/csiostor/csio_rnode.h2
-rw-r--r--drivers/scsi/csiostor/csio_wr.c60
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c17
-rw-r--r--drivers/scsi/fcoe/fcoe.c17
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c64
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c2
-rw-r--r--drivers/scsi/ipr.c13
-rw-r--r--drivers/scsi/isci/init.c6
-rw-r--r--drivers/scsi/iscsi_tcp.c18
-rw-r--r--drivers/scsi/libfc/fc_disc.c26
-rw-r--r--drivers/scsi/libiscsi.c4
-rw-r--r--drivers/scsi/libsas/sas_expander.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c12
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c1109
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c21
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c74
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c106
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c24
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c1
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c118
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c4
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c2
-rw-r--r--drivers/scsi/mvsas/mv_init.c6
-rw-r--r--drivers/scsi/mvumi.c4
-rw-r--r--drivers/scsi/mvumi.h1
-rw-r--r--drivers/scsi/osd/osd_initiator.c2
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c154
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c30
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h237
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h50
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c56
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h41
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c67
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c20
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c68
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c3476
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.h510
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c212
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c19
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.c28
-rw-r--r--drivers/scsi/qla4xxx/ql4_83xx.h10
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h19
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h38
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h9
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c47
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c120
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c21
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c1731
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h2
-rw-r--r--drivers/scsi/scsi_netlink.c4
-rw-r--r--drivers/scsi/scsi_transport_fc.c21
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c1072
-rw-r--r--drivers/scsi/st.c8
-rw-r--r--drivers/spi/Kconfig33
-rw-r--r--drivers/spi/Makefile3
-rw-r--r--drivers/spi/spi-atmel.c728
-rw-r--r--drivers/spi/spi-bcm2835.c422
-rw-r--r--drivers/spi/spi-bcm63xx.c81
-rw-r--r--drivers/spi/spi-fsl-cpm.c387
-rw-r--r--drivers/spi/spi-fsl-cpm.h43
-rw-r--r--drivers/spi/spi-fsl-lib.c8
-rw-r--r--drivers/spi/spi-fsl-lib.h15
-rw-r--r--drivers/spi/spi-fsl-spi.c601
-rw-r--r--drivers/spi/spi-fsl-spi.h72
-rw-r--r--drivers/spi/spi-gpio.c2
-rw-r--r--drivers/spi/spi-mpc512x-psc.c43
-rw-r--r--drivers/spi/spi-mxs.c1
-rw-r--r--drivers/spi/spi-oc-tiny.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c43
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c6
-rw-r--r--drivers/spi/spi-pxa2xx.c15
-rw-r--r--drivers/spi/spi-s3c64xx.c333
-rw-r--r--drivers/spi/spi-sh-msiof.c4
-rw-r--r--drivers/spi/spi-sirf.c2
-rw-r--r--drivers/spi/spi-tegra114.c1246
-rw-r--r--drivers/spi/spi-tegra20-sflash.c41
-rw-r--r--drivers/spi/spi-tegra20-slink.c109
-rw-r--r--drivers/spi/spi-topcliff-pch.c16
-rw-r--r--drivers/spi/spi.c25
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/ssb/driver_chipcommon.c2
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c85
-rw-r--r--drivers/ssb/driver_mipscore.c25
-rw-r--r--drivers/ssb/driver_pcicore.c15
-rw-r--r--drivers/ssb/embedded.c5
-rw-r--r--drivers/ssb/main.c51
-rw-r--r--drivers/ssb/pci.c120
-rw-r--r--drivers/ssb/pcmcia.c46
-rw-r--r--drivers/ssb/scan.c31
-rw-r--r--drivers/ssb/sprom.c4
-rw-r--r--drivers/ssb/ssb_private.h19
-rw-r--r--drivers/ssbi/Kconfig16
-rw-r--r--drivers/ssbi/Makefile1
-rw-r--r--drivers/ssbi/ssbi.c379
-rw-r--r--drivers/staging/Kconfig10
-rw-r--r--drivers/staging/Makefile6
-rw-r--r--drivers/staging/android/Kconfig29
-rw-r--r--drivers/staging/android/Makefile2
-rw-r--r--drivers/staging/android/ashmem.c66
-rw-r--r--drivers/staging/android/ashmem.h7
-rw-r--r--drivers/staging/android/binder.c138
-rw-r--r--drivers/staging/android/binder.h8
-rw-r--r--drivers/staging/android/logger.c196
-rw-r--r--drivers/staging/android/logger.h40
-rw-r--r--drivers/staging/android/lowmemorykiller.c9
-rw-r--r--drivers/staging/android/sw_sync.c264
-rw-r--r--drivers/staging/android/sw_sync.h58
-rw-r--r--drivers/staging/android/sync.c1017
-rw-r--r--drivers/staging/android/sync.h426
-rw-r--r--drivers/staging/android/trace/sync.h82
-rw-r--r--drivers/staging/bcm/Bcmchar.c2
-rw-r--r--drivers/staging/bcm/InterfaceDld.c32
-rw-r--r--drivers/staging/bcm/PHSModule.c1906
-rw-r--r--drivers/staging/bcm/nvm.c14
-rw-r--r--drivers/staging/ccg/Kconfig25
-rw-r--r--drivers/staging/ccg/Makefile2
-rw-r--r--drivers/staging/ccg/TODO6
-rw-r--r--drivers/staging/ccg/ccg.c1292
-rw-r--r--drivers/staging/ccg/composite.c1688
-rw-r--r--drivers/staging/ccg/composite.h395
-rw-r--r--drivers/staging/ccg/config.c158
-rw-r--r--drivers/staging/ccg/epautoconf.c393
-rw-r--r--drivers/staging/ccg/f_acm.c814
-rw-r--r--drivers/staging/ccg/f_fs.c2454
-rw-r--r--drivers/staging/ccg/f_mass_storage.c3135
-rw-r--r--drivers/staging/ccg/f_rndis.c918
-rw-r--r--drivers/staging/ccg/gadget_chips.h150
-rw-r--r--drivers/staging/ccg/ndis.h47
-rw-r--r--drivers/staging/ccg/rndis.c1175
-rw-r--r--drivers/staging/ccg/rndis.h222
-rw-r--r--drivers/staging/ccg/storage_common.c893
-rw-r--r--drivers/staging/ccg/sysfs-class-ccg_usb158
-rw-r--r--drivers/staging/ccg/u_ether.c986
-rw-r--r--drivers/staging/ccg/u_ether.h154
-rw-r--r--drivers/staging/ccg/u_serial.c1339
-rw-r--r--drivers/staging/ccg/u_serial.h65
-rw-r--r--drivers/staging/ccg/usbstring.c71
-rw-r--r--drivers/staging/comedi/Kconfig60
-rw-r--r--drivers/staging/comedi/comedi_buf.c18
-rw-r--r--drivers/staging/comedi/comedi_fops.c545
-rw-r--r--drivers/staging/comedi/comedi_internal.h5
-rw-r--r--drivers/staging/comedi/comedi_pci.c34
-rw-r--r--drivers/staging/comedi/comedidev.h31
-rw-r--r--drivers/staging/comedi/drivers.c182
-rw-r--r--drivers/staging/comedi/drivers/8255.c23
-rw-r--r--drivers/staging/comedi/drivers/8255.h1
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c210
-rw-r--r--drivers/staging/comedi/drivers/Makefile9
-rw-r--r--drivers/staging/comedi/drivers/acl7225b.c141
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c34
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h5
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c20
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c15
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c23
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c66
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c20
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c69
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1710.c64
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c18
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c18
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c52
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c55
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c15
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c300
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.c6
-rw-r--r--drivers/staging/comedi/drivers/addi_watchdog.h1
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c63
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c95
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c346
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c64
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c19
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c48
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c142
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c20
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c409
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c178
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c22
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c26
-rw-r--r--drivers/staging/comedi/drivers/am9513.h79
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c1980
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.h95
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_common.c1271
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200_pci.c486
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c91
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c303
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c21
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c26
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci263.c127
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c39
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c98
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c970
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c96
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c16
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c19
-rw-r--r--drivers/staging/comedi/drivers/comedi_fc.c6
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c29
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c2
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c21
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c40
-rw-r--r--drivers/staging/comedi/drivers/das08.c3
-rw-r--r--drivers/staging/comedi/drivers/das08.h1
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c1
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c14
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c13
-rw-r--r--drivers/staging/comedi/drivers/das16.c67
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c46
-rw-r--r--drivers/staging/comedi/drivers/das1800.c92
-rw-r--r--drivers/staging/comedi/drivers/das6402.c27
-rw-r--r--drivers/staging/comedi/drivers/das800.c999
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c28
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c36
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c29
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c22
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c29
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c22
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c59
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c103
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c30
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c15
-rw-r--r--drivers/staging/comedi/drivers/fl512.c31
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c30
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c23
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c4
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c18
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c21
-rw-r--r--drivers/staging/comedi/drivers/me4000.c213
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c84
-rw-r--r--drivers/staging/comedi/drivers/mite.c76
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c39
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c45
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c82
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c394
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c144
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c64
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c47
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c24
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c29
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c30
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c2448
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h30
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_pci.c142
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c355
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c68
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c2056
-rw-r--r--drivers/staging/comedi/drivers/ni_stc.h4
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c30
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c37
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c21
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c36
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c26
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c65
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c180
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c481
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c31
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c22
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c26
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c26
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c26
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c26
-rw-r--r--drivers/staging/comedi/drivers/plx9052.h106
-rw-r--r--drivers/staging/comedi/drivers/poc.c34
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c716
-rw-r--r--drivers/staging/comedi/drivers/rtd520.h381
-rw-r--r--drivers/staging/comedi/drivers/rti800.c575
-rw-r--r--drivers/staging/comedi/drivers/rti802.c21
-rw-r--r--drivers/staging/comedi/drivers/s526.c22
-rw-r--r--drivers/staging/comedi/drivers/s626.c1211
-rw-r--r--drivers/staging/comedi/drivers/s626.h101
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c895
-rw-r--r--drivers/staging/comedi/drivers/skel.c136
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c2
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c64
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c408
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c2
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c12
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c12
-rw-r--r--drivers/staging/comedi/range.c22
-rw-r--r--drivers/staging/cptm1217/clearpad_tm1217.c16
-rw-r--r--drivers/staging/csr/bh.c2
-rw-r--r--drivers/staging/csr/csr_log.h6
-rw-r--r--drivers/staging/csr/csr_sdio.h24
-rw-r--r--drivers/staging/csr/csr_time.c8
-rw-r--r--drivers/staging/csr/csr_wifi_fsm.h6
-rw-r--r--drivers/staging/csr/csr_wifi_hip_card_sdio.c8
-rw-r--r--drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c10
-rw-r--r--drivers/staging/csr/csr_wifi_hip_chiphelper.h4
-rw-r--r--drivers/staging/csr/csr_wifi_hip_unifi.h20
-rw-r--r--drivers/staging/csr/drv.c4
-rw-r--r--drivers/staging/csr/netdev.c2
-rw-r--r--drivers/staging/csr/sdio_mmc.c3
-rw-r--r--drivers/staging/csr/sme_native.c2
-rw-r--r--drivers/staging/csr/sme_wext.c3
-rw-r--r--drivers/staging/csr/unifi_pdu_processing.c20
-rw-r--r--drivers/staging/csr/unifi_sme.c2
-rw-r--r--drivers/staging/cxt1e1/pmcc4_drv.c1
-rw-r--r--drivers/staging/dgrp/dgrp_common.h2
-rw-r--r--drivers/staging/dgrp/dgrp_dpa_ops.c1
-rw-r--r--drivers/staging/dgrp/dgrp_driver.c6
-rw-r--r--drivers/staging/dgrp/dgrp_net_ops.c2
-rw-r--r--drivers/staging/dgrp/dgrp_sysfs.c30
-rw-r--r--drivers/staging/dwc2/Kconfig54
-rw-r--r--drivers/staging/dwc2/Makefile25
-rw-r--r--drivers/staging/dwc2/core.c2759
-rw-r--r--drivers/staging/dwc2/core.h662
-rw-r--r--drivers/staging/dwc2/core_intr.c505
-rw-r--r--drivers/staging/dwc2/hcd.c2981
-rw-r--r--drivers/staging/dwc2/hcd.h765
-rw-r--r--drivers/staging/dwc2/hcd_ddma.c1196
-rw-r--r--drivers/staging/dwc2/hcd_intr.c2130
-rw-r--r--drivers/staging/dwc2/hcd_queue.c677
-rw-r--r--drivers/staging/dwc2/hw.h811
-rw-r--r--drivers/staging/dwc2/pci.c180
-rw-r--r--drivers/staging/dwc2/platform.c145
-rw-r--r--drivers/staging/et131x/et131x.c5
-rw-r--r--drivers/staging/fwserial/fwserial.c16
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c47
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c1
-rw-r--r--drivers/staging/gdm72xx/netlink_k.c13
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.c1
-rw-r--r--drivers/staging/iio/Documentation/trigger.txt3
-rw-r--r--drivers/staging/iio/Kconfig8
-rw-r--r--drivers/staging/iio/Makefile2
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c8
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c2
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c8
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c4
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c26
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c9
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c11
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c6
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c5
-rw-r--r--drivers/staging/iio/adc/Kconfig7
-rw-r--r--drivers/staging/iio/adc/Makefile1
-rw-r--r--drivers/staging/iio/adc/ad7280a.c12
-rw-r--r--drivers/staging/iio/adc/ad7291.c10
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c4
-rw-r--r--drivers/staging/iio/adc/ad799x.h7
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c417
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c16
-rw-r--r--drivers/staging/iio/adc/adt7410.c1102
-rw-r--r--drivers/staging/iio/adc/lpc32xx_adc.c2
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c12
-rw-r--r--drivers/staging/iio/adc/spear_adc.c4
-rw-r--r--drivers/staging/iio/addac/adt7316.c26
-rw-r--r--drivers/staging/iio/cdc/ad7150.c8
-rw-r--r--drivers/staging/iio/cdc/ad7152.c32
-rw-r--r--drivers/staging/iio/cdc/ad7746.c48
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c11
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c4
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c4
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c44
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c10
-rw-r--r--drivers/staging/iio/light/isl29018.c8
-rw-r--r--drivers/staging/iio/light/isl29028.c10
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c40
-rw-r--r--drivers/staging/iio/magnetometer/Kconfig11
-rw-r--r--drivers/staging/iio/magnetometer/Makefile1
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c4
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c60
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c6
-rw-r--r--drivers/staging/iio/resolver/ad2s1200.c4
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c4
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c2
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c8
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c6
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c12
-rw-r--r--drivers/staging/iio/trigger/iio-trig-sysfs.c4
-rw-r--r--drivers/staging/imx-drm/Kconfig7
-rw-r--r--drivers/staging/imx-drm/Makefile1
-rw-r--r--drivers/staging/imx-drm/TODO3
-rw-r--r--drivers/staging/imx-drm/imx-drm-core.c15
-rw-r--r--drivers/staging/imx-drm/imx-drm.h14
-rw-r--r--drivers/staging/imx-drm/imx-tve.c755
-rw-r--r--drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h6
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-common.c3
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dc.c64
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-di.c100
-rw-r--r--drivers/staging/imx-drm/ipu-v3/ipu-dp.c1
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c11
-rw-r--r--drivers/staging/imx-drm/parallel-display.c12
-rw-r--r--drivers/staging/line6/pod.c3
-rw-r--r--drivers/staging/media/as102/Makefile2
-rw-r--r--drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c3
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c10
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c24
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c26
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h2
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c11
-rw-r--r--drivers/staging/media/go7007/Kconfig103
-rw-r--r--drivers/staging/media/go7007/Makefile23
-rw-r--r--drivers/staging/media/go7007/README142
-rw-r--r--drivers/staging/media/go7007/go7007-driver.c390
-rw-r--r--drivers/staging/media/go7007/go7007-fw.c88
-rw-r--r--drivers/staging/media/go7007/go7007-i2c.c21
-rw-r--r--drivers/staging/media/go7007/go7007-loader.c144
-rw-r--r--drivers/staging/media/go7007/go7007-priv.h104
-rw-r--r--drivers/staging/media/go7007/go7007-usb.c394
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c1747
-rw-r--r--drivers/staging/media/go7007/go7007.h74
-rw-r--r--drivers/staging/media/go7007/s2250-board.c171
-rw-r--r--drivers/staging/media/go7007/s2250-loader.c169
-rw-r--r--drivers/staging/media/go7007/s2250-loader.h24
-rw-r--r--drivers/staging/media/go7007/saa7134-go7007.c171
-rw-r--r--drivers/staging/media/go7007/snd-go7007.c11
-rw-r--r--drivers/staging/media/go7007/wis-i2c.h42
-rw-r--r--drivers/staging/media/go7007/wis-saa7113.c324
-rw-r--r--drivers/staging/media/go7007/wis-saa7115.c457
-rw-r--r--drivers/staging/media/go7007/wis-sony-tuner.c707
-rw-r--r--drivers/staging/media/go7007/wis-tw2804.c348
-rw-r--r--drivers/staging/media/go7007/wis-tw9903.c328
-rw-r--r--drivers/staging/media/lirc/lirc_sir.c10
-rw-r--r--drivers/staging/media/solo6x10/Kconfig3
-rw-r--r--drivers/staging/media/solo6x10/Makefile4
-rw-r--r--drivers/staging/media/solo6x10/TODO39
-rw-r--r--drivers/staging/media/solo6x10/core.c321
-rw-r--r--drivers/staging/media/solo6x10/offsets.h74
-rw-r--r--drivers/staging/media/solo6x10/osd-font.h154
-rw-r--r--drivers/staging/media/solo6x10/p2m.c306
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-core.c709
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-disp.c (renamed from drivers/staging/media/solo6x10/disp.c)129
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-eeprom.c154
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-enc.c (renamed from drivers/staging/media/solo6x10/enc.c)239
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-g723.c (renamed from drivers/staging/media/solo6x10/g723.c)94
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-gpio.c (renamed from drivers/staging/media/solo6x10/gpio.c)13
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-i2c.c (renamed from drivers/staging/media/solo6x10/i2c.c)26
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-jpeg.h94
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-offsets.h85
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-p2m.c333
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-regs.h (renamed from drivers/staging/media/solo6x10/registers.h)88
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-tw28.c (renamed from drivers/staging/media/solo6x10/tw28.c)187
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-tw28.h (renamed from drivers/staging/media/solo6x10/tw28.h)12
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c1385
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2.c734
-rw-r--r--drivers/staging/media/solo6x10/solo6x10.h265
-rw-r--r--drivers/staging/media/solo6x10/v4l2-enc.c1829
-rw-r--r--drivers/staging/media/solo6x10/v4l2.c961
-rw-r--r--drivers/staging/net/Kconfig38
-rw-r--r--drivers/staging/net/Makefile5
-rw-r--r--drivers/staging/net/TODO5
-rw-r--r--drivers/staging/net/pc300-falc-lh.h1238
-rw-r--r--drivers/staging/net/pc300.h436
-rw-r--r--drivers/staging/net/pc300_drv.c3670
-rw-r--r--drivers/staging/net/pc300_tty.c1079
-rw-r--r--drivers/staging/netlogic/Kconfig7
-rw-r--r--drivers/staging/netlogic/Makefile1
-rw-r--r--drivers/staging/netlogic/TODO12
-rw-r--r--drivers/staging/netlogic/platform_net.c223
-rw-r--r--drivers/staging/netlogic/platform_net.h46
-rw-r--r--drivers/staging/netlogic/xlr_net.c1114
-rw-r--r--drivers/staging/netlogic/xlr_net.h1099
-rw-r--r--drivers/staging/nvec/Kconfig10
-rw-r--r--drivers/staging/nvec/nvec.c8
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c4
-rw-r--r--drivers/staging/omap-thermal/Makefile5
-rw-r--r--drivers/staging/omap-thermal/TODO28
-rw-r--r--drivers/staging/omap-thermal/omap-bandgap.c1174
-rw-r--r--drivers/staging/omap-thermal/omap-bandgap.h432
-rw-r--r--drivers/staging/omap-thermal/omap-thermal-common.c338
-rw-r--r--drivers/staging/omap-thermal/omap5-thermal.c297
-rw-r--r--drivers/staging/ozwpan/ozcdev.c1
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.h77
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c8
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.h108
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c2
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.h1
-rw-r--r--drivers/staging/rts5139/trace.h24
-rw-r--r--drivers/staging/sb105x/sb_mp_register.h4
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.c4
-rw-r--r--drivers/staging/sb105x/sb_pci_mp.h2
-rw-r--r--drivers/staging/sep/sep_crypto.c4
-rw-r--r--drivers/staging/sep/sep_driver_config.h2
-rw-r--r--drivers/staging/sep/sep_main.c9
-rw-r--r--drivers/staging/sep/sep_trace_events.h11
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c7
-rw-r--r--drivers/staging/silicom/bpctl_mod.c10
-rw-r--r--drivers/staging/silicom/bypasslib/bypass.c94
-rw-r--r--drivers/staging/slicoss/slicoss.c133
-rw-r--r--drivers/staging/sm7xxfb/sm7xxfb.c10
-rw-r--r--drivers/staging/speakup/kobjects.c14
-rw-r--r--drivers/staging/speakup/main.c2
-rw-r--r--drivers/staging/speakup/selection.c2
-rw-r--r--drivers/staging/speakup/speakup.h7
-rw-r--r--drivers/staging/speakup/varhandlers.c102
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c2
-rw-r--r--drivers/staging/ti-soc-thermal/Kconfig (renamed from drivers/staging/omap-thermal/Kconfig)22
-rw-r--r--drivers/staging/ti-soc-thermal/Makefile5
-rw-r--r--drivers/staging/ti-soc-thermal/TODO12
-rw-r--r--drivers/staging/ti-soc-thermal/omap4-thermal-data.c (renamed from drivers/staging/omap-thermal/omap4-thermal.c)86
-rw-r--r--drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h175
-rw-r--r--drivers/staging/ti-soc-thermal/omap5-thermal-data.c359
-rw-r--r--drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h200
-rw-r--r--drivers/staging/ti-soc-thermal/ti-bandgap.c1546
-rw-r--r--drivers/staging/ti-soc-thermal/ti-bandgap.h403
-rw-r--r--drivers/staging/ti-soc-thermal/ti-thermal-common.c367
-rw-r--r--drivers/staging/ti-soc-thermal/ti-thermal.h (renamed from drivers/staging/omap-thermal/omap-thermal.h)61
-rw-r--r--drivers/staging/ti-soc-thermal/ti_soc_thermal.txt (renamed from drivers/staging/omap-thermal/omap_bandgap.txt)36
-rw-r--r--drivers/staging/tidspbridge/rmgr/proc.c12
-rw-r--r--drivers/staging/tidspbridge/rmgr/strm.c6
-rw-r--r--drivers/staging/usbip/stub_dev.c38
-rw-r--r--drivers/staging/usbip/stub_main.c34
-rw-r--r--drivers/staging/usbip/stub_rx.c100
-rw-r--r--drivers/staging/usbip/usbip_common.c2
-rw-r--r--drivers/staging/usbip/userspace/README4
-rw-r--r--drivers/staging/usbip/userspace/doc/usbip.84
-rw-r--r--drivers/staging/usbip/userspace/libsrc/names.c521
-rw-r--r--drivers/staging/usbip/userspace/libsrc/names.h24
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.c28
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.h11
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c40
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_attach.c12
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_detach.c2
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_list.c12
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.c6
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.h4
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c15
-rw-r--r--drivers/staging/usbip/vhci.h1
-rw-r--r--drivers/staging/usbip/vhci_hcd.c5
-rw-r--r--drivers/staging/usbip/vhci_rx.c56
-rw-r--r--drivers/staging/vme/devices/vme_user.c4
-rw-r--r--drivers/staging/vt6655/80211hdr.h71
-rw-r--r--drivers/staging/vt6655/80211mgr.c1166
-rw-r--r--drivers/staging/vt6655/80211mgr.h698
-rw-r--r--drivers/staging/vt6655/IEEE11h.c115
-rw-r--r--drivers/staging/vt6655/IEEE11h.h6
-rw-r--r--drivers/staging/vt6655/aes_ccmp.c563
-rw-r--r--drivers/staging/vt6655/baseband.c4855
-rw-r--r--drivers/staging/vt6655/baseband.h56
-rw-r--r--drivers/staging/vt6655/bssdb.c2665
-rw-r--r--drivers/staging/vt6655/bssdb.h411
-rw-r--r--drivers/staging/vt6655/card.c2842
-rw-r--r--drivers/staging/vt6655/card.h137
-rw-r--r--drivers/staging/vt6655/channel.c767
-rw-r--r--drivers/staging/vt6655/channel.h16
-rw-r--r--drivers/staging/vt6655/country.h238
-rw-r--r--drivers/staging/vt6655/datarate.c469
-rw-r--r--drivers/staging/vt6655/datarate.h49
-rw-r--r--drivers/staging/vt6655/desc.h504
-rw-r--r--drivers/staging/vt6655/device.h999
-rw-r--r--drivers/staging/vt6655/device_cfg.h31
-rw-r--r--drivers/staging/vt6655/device_main.c4792
-rw-r--r--drivers/staging/vt6655/dpc.c2425
-rw-r--r--drivers/staging/vt6655/dpc.h11
-rw-r--r--drivers/staging/vt6655/hostap.c690
-rw-r--r--drivers/staging/vt6655/hostap.h4
-rw-r--r--drivers/staging/vt6655/iocmd.h246
-rw-r--r--drivers/staging/vt6655/ioctl.c16
-rw-r--r--drivers/staging/vt6655/ioctl.h16
-rw-r--r--drivers/staging/vt6655/iowpa.h54
-rw-r--r--drivers/staging/vt6655/iwctl.c2213
-rw-r--r--drivers/staging/vt6655/iwctl.h208
-rw-r--r--drivers/staging/vt6655/key.c1150
-rw-r--r--drivers/staging/vt6655/key.h171
-rw-r--r--drivers/staging/vt6655/mac.c1657
-rw-r--r--drivers/staging/vt6655/mac.h773
-rw-r--r--drivers/staging/vt6655/mib.c698
-rw-r--r--drivers/staging/vt6655/mib.h507
-rw-r--r--drivers/staging/vt6655/michael.c164
-rw-r--r--drivers/staging/vt6655/michael.h8
-rw-r--r--drivers/staging/vt6655/power.c484
-rw-r--r--drivers/staging/vt6655/power.h33
-rw-r--r--drivers/staging/vt6655/rc4.c78
-rw-r--r--drivers/staging/vt6655/rc4.h6
-rw-r--r--drivers/staging/vt6655/rf.c1480
-rw-r--r--drivers/staging/vt6655/rf.h26
-rw-r--r--drivers/staging/vt6655/rxtx.c5545
-rw-r--r--drivers/staging/vt6655/rxtx.h56
-rw-r--r--drivers/staging/vt6655/srom.c269
-rw-r--r--drivers/staging/vt6655/srom.h60
-rw-r--r--drivers/staging/vt6655/tcrc.c163
-rw-r--r--drivers/staging/vt6655/tcrc.h3
-rw-r--r--drivers/staging/vt6655/tether.c50
-rw-r--r--drivers/staging/vt6655/tether.h42
-rw-r--r--drivers/staging/vt6655/tkip.c331
-rw-r--r--drivers/staging/vt6655/tkip.h15
-rw-r--r--drivers/staging/vt6655/tmacro.h2
-rw-r--r--drivers/staging/vt6655/ttype.h14
-rw-r--r--drivers/staging/vt6655/upc.h187
-rw-r--r--drivers/staging/vt6655/vntwifi.c925
-rw-r--r--drivers/staging/vt6655/vntwifi.h278
-rw-r--r--drivers/staging/vt6655/wcmd.c1747
-rw-r--r--drivers/staging/vt6655/wcmd.h118
-rw-r--r--drivers/staging/vt6655/wctl.c244
-rw-r--r--drivers/staging/vt6655/wctl.h76
-rw-r--r--drivers/staging/vt6655/wmgr.c8006
-rw-r--r--drivers/staging/vt6655/wmgr.h552
-rw-r--r--drivers/staging/vt6655/wpa.c340
-rw-r--r--drivers/staging/vt6655/wpa.h23
-rw-r--r--drivers/staging/vt6655/wpa2.c504
-rw-r--r--drivers/staging/vt6655/wpa2.h29
-rw-r--r--drivers/staging/vt6655/wpactl.c903
-rw-r--r--drivers/staging/vt6655/wpactl.h8
-rw-r--r--drivers/staging/vt6655/wroute.c257
-rw-r--r--drivers/staging/vt6655/wroute.h5
-rw-r--r--drivers/staging/vt6656/80211hdr.h130
-rw-r--r--drivers/staging/vt6656/80211mgr.c224
-rw-r--r--drivers/staging/vt6656/80211mgr.h335
-rw-r--r--drivers/staging/vt6656/TODO2
-rw-r--r--drivers/staging/vt6656/aes_ccmp.c131
-rw-r--r--drivers/staging/vt6656/aes_ccmp.h13
-rw-r--r--drivers/staging/vt6656/baseband.c183
-rw-r--r--drivers/staging/vt6656/baseband.h23
-rw-r--r--drivers/staging/vt6656/bssdb.c70
-rw-r--r--drivers/staging/vt6656/bssdb.h124
-rw-r--r--drivers/staging/vt6656/card.c127
-rw-r--r--drivers/staging/vt6656/card.h18
-rw-r--r--drivers/staging/vt6656/channel.c53
-rw-r--r--drivers/staging/vt6656/channel.h14
-rw-r--r--drivers/staging/vt6656/control.c10
-rw-r--r--drivers/staging/vt6656/control.h10
-rw-r--r--drivers/staging/vt6656/country.h1
-rw-r--r--drivers/staging/vt6656/datarate.c85
-rw-r--r--drivers/staging/vt6656/datarate.h27
-rw-r--r--drivers/staging/vt6656/desc.h230
-rw-r--r--drivers/staging/vt6656/device.h56
-rw-r--r--drivers/staging/vt6656/device_cfg.h2
-rw-r--r--drivers/staging/vt6656/dpc.c262
-rw-r--r--drivers/staging/vt6656/dpc.h9
-rw-r--r--drivers/staging/vt6656/firmware.c17
-rw-r--r--drivers/staging/vt6656/firmware.h9
-rw-r--r--drivers/staging/vt6656/hostap.c29
-rw-r--r--drivers/staging/vt6656/hostap.h9
-rw-r--r--drivers/staging/vt6656/int.c27
-rw-r--r--drivers/staging/vt6656/int.h46
-rw-r--r--drivers/staging/vt6656/iocmd.h18
-rw-r--r--drivers/staging/vt6656/iowpa.h13
-rw-r--r--drivers/staging/vt6656/iwctl.c27
-rw-r--r--drivers/staging/vt6656/iwctl.h8
-rw-r--r--drivers/staging/vt6656/key.c111
-rw-r--r--drivers/staging/vt6656/key.h43
-rw-r--r--drivers/staging/vt6656/mac.c132
-rw-r--r--drivers/staging/vt6656/mac.h19
-rw-r--r--drivers/staging/vt6656/main_usb.c63
-rw-r--r--drivers/staging/vt6656/mib.c131
-rw-r--r--drivers/staging/vt6656/mib.h294
-rw-r--r--drivers/staging/vt6656/michael.c49
-rw-r--r--drivers/staging/vt6656/michael.h12
-rw-r--r--drivers/staging/vt6656/power.c13
-rw-r--r--drivers/staging/vt6656/power.h12
-rw-r--r--drivers/staging/vt6656/rc4.c22
-rw-r--r--drivers/staging/vt6656/rc4.h10
-rw-r--r--drivers/staging/vt6656/rf.c49
-rw-r--r--drivers/staging/vt6656/rf.h10
-rw-r--r--drivers/staging/vt6656/rndis.h90
-rw-r--r--drivers/staging/vt6656/rxtx.c610
-rw-r--r--drivers/staging/vt6656/rxtx.h691
-rw-r--r--drivers/staging/vt6656/srom.h71
-rw-r--r--drivers/staging/vt6656/tcrc.c28
-rw-r--r--drivers/staging/vt6656/tcrc.h20
-rw-r--r--drivers/staging/vt6656/tether.c53
-rw-r--r--drivers/staging/vt6656/tether.h61
-rw-r--r--drivers/staging/vt6656/tkip.c37
-rw-r--r--drivers/staging/vt6656/tkip.h22
-rw-r--r--drivers/staging/vt6656/tmacro.h14
-rw-r--r--drivers/staging/vt6656/ttype.h55
-rw-r--r--drivers/staging/vt6656/usbpipe.c29
-rw-r--r--drivers/staging/vt6656/usbpipe.h9
-rw-r--r--drivers/staging/vt6656/wcmd.c63
-rw-r--r--drivers/staging/vt6656/wcmd.h18
-rw-r--r--drivers/staging/vt6656/wctl.c56
-rw-r--r--drivers/staging/vt6656/wctl.h49
-rw-r--r--drivers/staging/vt6656/wmgr.c228
-rw-r--r--drivers/staging/vt6656/wmgr.h35
-rw-r--r--drivers/staging/vt6656/wpa.c32
-rw-r--r--drivers/staging/vt6656/wpa.h16
-rw-r--r--drivers/staging/vt6656/wpa2.c165
-rw-r--r--drivers/staging/vt6656/wpa2.h17
-rw-r--r--drivers/staging/vt6656/wpactl.c33
-rw-r--r--drivers/staging/vt6656/wpactl.h10
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c51
-rw-r--r--drivers/staging/wlan-ng/prism2usb.c12
-rw-r--r--drivers/staging/xgifb/vb_def.h4
-rw-r--r--drivers/staging/xgifb/vb_init.c64
-rw-r--r--drivers/staging/xgifb/vb_setmode.c4
-rw-r--r--drivers/staging/xgifb/vb_struct.h16
-rw-r--r--drivers/staging/xgifb/vb_table.h98
-rw-r--r--drivers/staging/zcache/Kconfig24
-rw-r--r--drivers/staging/zcache/Makefile2
-rw-r--r--drivers/staging/zcache/TODO9
-rw-r--r--drivers/staging/zcache/debug.c107
-rw-r--r--drivers/staging/zcache/debug.h305
-rw-r--r--drivers/staging/zcache/ramster.h6
-rw-r--r--drivers/staging/zcache/ramster/debug.c66
-rw-r--r--drivers/staging/zcache/ramster/debug.h145
-rw-r--r--drivers/staging/zcache/ramster/nodemanager.c9
-rw-r--r--drivers/staging/zcache/ramster/ramster.c170
-rw-r--r--drivers/staging/zcache/ramster/ramster.h2
-rw-r--r--drivers/staging/zcache/ramster/ramster_nodemanager.h2
-rw-r--r--drivers/staging/zcache/tmem.c6
-rw-r--r--drivers/staging/zcache/tmem.h8
-rw-r--r--drivers/staging/zcache/zbud.c7
-rw-r--r--drivers/staging/zcache/zcache-main.c590
-rw-r--r--drivers/staging/zcache/zcache.h2
-rw-r--r--drivers/staging/zram/zram_drv.c5
-rw-r--r--drivers/staging/zsmalloc/Kconfig2
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c7
-rw-r--r--drivers/target/iscsi/Makefile3
-rw-r--r--drivers/target/iscsi/iscsi_target.c1182
-rw-r--r--drivers/target/iscsi/iscsi_target.h3
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c28
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c98
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h26
-rw-r--r--drivers/target/iscsi/iscsi_target_device.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c13
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c472
-rw-r--r--drivers/target/iscsi/iscsi_target_login.h6
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c194
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.h11
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c87
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h16
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_transport.c55
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c53
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h1
-rw-r--r--drivers/target/target_core_alua.c3
-rw-r--r--drivers/target/target_core_file.c122
-rw-r--r--drivers/target/target_core_iblock.c108
-rw-r--r--drivers/target/target_core_sbc.c85
-rw-r--r--drivers/target/target_core_transport.c17
-rw-r--r--drivers/target/tcm_fc/tfc_io.c9
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c9
-rw-r--r--drivers/tty/amiserial.c14
-rw-r--r--drivers/tty/cyclades.c10
-rw-r--r--drivers/tty/ehv_bytechan.c6
-rw-r--r--drivers/tty/hvc/hvsi.c7
-rw-r--r--drivers/tty/ipwireless/hardware.c3
-rw-r--r--drivers/tty/moxa.c19
-rw-r--r--drivers/tty/mxser.c12
-rw-r--r--drivers/tty/n_gsm.c10
-rw-r--r--drivers/tty/n_tty.c172
-rw-r--r--drivers/tty/nozomi.c15
-rw-r--r--drivers/tty/pty.c16
-rw-r--r--drivers/tty/rocket.c66
-rw-r--r--drivers/tty/serial/68328serial.c9
-rw-r--r--drivers/tty/serial/8250/8250.h7
-rw-r--r--drivers/tty/serial/8250/8250_core.c (renamed from drivers/tty/serial/8250/8250.c)24
-rw-r--r--drivers/tty/serial/8250/8250_dma.c52
-rw-r--r--drivers/tty/serial/8250/8250_dw.c194
-rw-r--r--drivers/tty/serial/8250/8250_pci.c13
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c12
-rw-r--r--drivers/tty/serial/8250/Kconfig17
-rw-r--r--drivers/tty/serial/8250/Makefile8
-rw-r--r--drivers/tty/serial/8250/serial_cs.c14
-rw-r--r--drivers/tty/serial/amba-pl011.c181
-rw-r--r--drivers/tty/serial/arc_uart.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c11
-rw-r--r--drivers/tty/serial/bfin_uart.c23
-rw-r--r--drivers/tty/serial/crisv10.c168
-rw-r--r--drivers/tty/serial/crisv10.h14
-rw-r--r--drivers/tty/serial/icom.c3
-rw-r--r--drivers/tty/serial/ifx6x60.c80
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c6
-rw-r--r--drivers/tty/serial/max3100.c24
-rw-r--r--drivers/tty/serial/max310x.c24
-rw-r--r--drivers/tty/serial/mrst_max3110.c19
-rw-r--r--drivers/tty/serial/msm_serial_hs.c2
-rw-r--r--drivers/tty/serial/msm_smd_tty.c14
-rw-r--r--drivers/tty/serial/mxs-auart.c6
-rw-r--r--drivers/tty/serial/of_serial.c17
-rw-r--r--drivers/tty/serial/omap-serial.c11
-rw-r--r--drivers/tty/serial/pch_uart.c103
-rw-r--r--drivers/tty/serial/samsung.c63
-rw-r--r--drivers/tty/serial/samsung.h4
-rw-r--r--drivers/tty/serial/sccnxp.c23
-rw-r--r--drivers/tty/serial/serial-tegra.c9
-rw-r--r--drivers/tty/serial/serial_core.c4
-rw-r--r--drivers/tty/serial/sh-sci.h2
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c2
-rw-r--r--drivers/tty/serial/sunsab.c2
-rw-r--r--drivers/tty/serial/sunzilog.c2
-rw-r--r--drivers/tty/serial/vt8500_serial.c7
-rw-r--r--drivers/tty/serial/xilinx_uartps.c5
-rw-r--r--drivers/tty/synclink.c5
-rw-r--r--drivers/tty/synclink_gt.c2
-rw-r--r--drivers/tty/synclinkmp.c2
-rw-r--r--drivers/tty/sysrq.c91
-rw-r--r--drivers/tty/tty_buffer.c22
-rw-r--r--drivers/tty/tty_io.c188
-rw-r--r--drivers/tty/tty_ioctl.c120
-rw-r--r--drivers/tty/tty_ldisc.c326
-rw-r--r--drivers/tty/tty_port.c111
-rw-r--r--drivers/tty/vt/consolemap.c3
-rw-r--r--drivers/uio/uio.c1
-rw-r--r--drivers/usb/Kconfig25
-rw-r--r--drivers/usb/Makefile4
-rw-r--r--drivers/usb/atm/Kconfig2
-rw-r--r--drivers/usb/atm/usbatm.c6
-rw-r--r--drivers/usb/chipidea/Makefile2
-rw-r--r--drivers/usb/chipidea/ci.h19
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.c12
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.h3
-rw-r--r--drivers/usb/chipidea/ci13xxx_pci.c6
-rw-r--r--drivers/usb/chipidea/core.c66
-rw-r--r--drivers/usb/chipidea/debug.c888
-rw-r--r--drivers/usb/chipidea/debug.h34
-rw-r--r--drivers/usb/chipidea/udc.c299
-rw-r--r--drivers/usb/chipidea/udc.h4
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c261
-rw-r--r--drivers/usb/chipidea/usbmisc_imx6q.c162
-rw-r--r--drivers/usb/class/Kconfig6
-rw-r--r--drivers/usb/class/cdc-acm.c52
-rw-r--r--drivers/usb/class/cdc-acm.h1
-rw-r--r--drivers/usb/class/cdc-wdm.c19
-rw-r--r--drivers/usb/class/usbtmc.c26
-rw-r--r--drivers/usb/core/Kconfig36
-rw-r--r--drivers/usb/core/devio.c2
-rw-r--r--drivers/usb/core/driver.c25
-rw-r--r--drivers/usb/core/generic.c2
-rw-r--r--drivers/usb/core/hcd-pci.c214
-rw-r--r--drivers/usb/core/hcd.c18
-rw-r--r--drivers/usb/core/hub.c136
-rw-r--r--drivers/usb/core/port.c5
-rw-r--r--drivers/usb/core/quirks.c16
-rw-r--r--drivers/usb/core/sysfs.c4
-rw-r--r--drivers/usb/core/urb.c5
-rw-r--r--drivers/usb/core/usb-acpi.c8
-rw-r--r--drivers/usb/core/usb.c7
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/dwc3/Kconfig1
-rw-r--r--drivers/usb/dwc3/core.c201
-rw-r--r--drivers/usb/dwc3/core.h72
-rw-r--r--drivers/usb/dwc3/debugfs.c52
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c98
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c245
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c38
-rw-r--r--drivers/usb/dwc3/ep0.c33
-rw-r--r--drivers/usb/dwc3/gadget.c321
-rw-r--r--drivers/usb/gadget/Kconfig21
-rw-r--r--drivers/usb/gadget/Makefile13
-rw-r--r--drivers/usb/gadget/acm_ms.c15
-rw-r--r--drivers/usb/gadget/amd5536udc.c16
-rw-r--r--drivers/usb/gadget/amd5536udc.h1
-rw-r--r--drivers/usb/gadget/at91_udc.c14
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c44
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h6
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c23
-rw-r--r--drivers/usb/gadget/cdc2.c31
-rw-r--r--drivers/usb/gadget/composite.c1
-rw-r--r--drivers/usb/gadget/configfs.c1003
-rw-r--r--drivers/usb/gadget/dummy_hcd.c19
-rw-r--r--drivers/usb/gadget/ether.c20
-rw-r--r--drivers/usb/gadget/f_acm.c137
-rw-r--r--drivers/usb/gadget/f_ecm.c4
-rw-r--r--drivers/usb/gadget/f_eem.c3
-rw-r--r--drivers/usb/gadget/f_ncm.c4
-rw-r--r--drivers/usb/gadget/f_obex.c227
-rw-r--r--drivers/usb/gadget/f_rndis.c3
-rw-r--r--drivers/usb/gadget/f_serial.c174
-rw-r--r--drivers/usb/gadget/f_sourcesink.c4
-rw-r--r--drivers/usb/gadget/f_subset.c4
-rw-r--r--drivers/usb/gadget/f_uvc.c262
-rw-r--r--drivers/usb/gadget/f_uvc.h12
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c18
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c83
-rw-r--r--drivers/usb/gadget/fusb300_udc.c46
-rw-r--r--drivers/usb/gadget/fusb300_udc.h2
-rw-r--r--drivers/usb/gadget/g_ffs.c35
-rw-r--r--drivers/usb/gadget/goku_udc.c20
-rw-r--r--drivers/usb/gadget/goku_udc.h3
-rw-r--r--drivers/usb/gadget/imx_udc.c16
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c51
-rw-r--r--drivers/usb/gadget/m66592-udc.c17
-rw-r--r--drivers/usb/gadget/multi.c33
-rw-r--r--drivers/usb/gadget/mv_u3d_core.c65
-rw-r--r--drivers/usb/gadget/mv_udc.h3
-rw-r--r--drivers/usb/gadget/mv_udc_core.c117
-rw-r--r--drivers/usb/gadget/ncm.c13
-rw-r--r--drivers/usb/gadget/net2272.c25
-rw-r--r--drivers/usb/gadget/net2280.c25
-rw-r--r--drivers/usb/gadget/nokia.c95
-rw-r--r--drivers/usb/gadget/omap_udc.c21
-rw-r--r--drivers/usb/gadget/pch_udc.c21
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c16
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c51
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c14
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c78
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c16
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c15
-rw-r--r--drivers/usb/gadget/serial.c59
-rw-r--r--drivers/usb/gadget/u_ether.c32
-rw-r--r--drivers/usb/gadget/u_ether.h27
-rw-r--r--drivers/usb/gadget/u_serial.h1
-rw-r--r--drivers/usb/gadget/udc-core.c90
-rw-r--r--drivers/usb/gadget/uvc.h3
-rw-r--r--drivers/usb/gadget/uvc_queue.c538
-rw-r--r--drivers/usb/gadget/uvc_queue.h32
-rw-r--r--drivers/usb/gadget/uvc_v4l2.c71
-rw-r--r--drivers/usb/gadget/uvc_video.c31
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/Kconfig217
-rw-r--r--drivers/usb/host/Makefile6
-rw-r--r--drivers/usb/host/ehci-atmel.c88
-rw-r--r--drivers/usb/host/ehci-dbg.c15
-rw-r--r--drivers/usb/host/ehci-fsl.c9
-rw-r--r--drivers/usb/host/ehci-hcd.c107
-rw-r--r--drivers/usb/host/ehci-hub.c23
-rw-r--r--drivers/usb/host/ehci-msm.c91
-rw-r--r--drivers/usb/host/ehci-mv.c56
-rw-r--r--drivers/usb/host/ehci-mxc.c10
-rw-r--r--drivers/usb/host/ehci-omap.c331
-rw-r--r--drivers/usb/host/ehci-orion.c86
-rw-r--r--drivers/usb/host/ehci-pci.c14
-rw-r--r--drivers/usb/host/ehci-platform.c36
-rw-r--r--drivers/usb/host/ehci-ps3.c1
-rw-r--r--drivers/usb/host/ehci-q.c241
-rw-r--r--drivers/usb/host/ehci-s5p.c180
-rw-r--r--drivers/usb/host/ehci-sched.c42
-rw-r--r--drivers/usb/host/ehci-sh.c5
-rw-r--r--drivers/usb/host/ehci-spear.c119
-rw-r--r--drivers/usb/host/ehci-tegra.c34
-rw-r--r--drivers/usb/host/ehci-timer.c72
-rw-r--r--drivers/usb/host/ehci-vt8500.c150
-rw-r--r--drivers/usb/host/ehci.h16
-rw-r--r--drivers/usb/host/ohci-exynos.c14
-rw-r--r--drivers/usb/host/ohci-hcd.c136
-rw-r--r--drivers/usb/host/ohci-hub.c6
-rw-r--r--drivers/usb/host/ohci-omap3.c24
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/sl811_cs.c15
-rw-r--r--drivers/usb/host/u132-hcd.c9
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci-mem.c52
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c61
-rw-r--r--drivers/usb/host/xhci.c40
-rw-r--r--drivers/usb/host/xhci.h9
-rw-r--r--drivers/usb/image/Kconfig4
-rw-r--r--drivers/usb/misc/Kconfig21
-rw-r--r--drivers/usb/misc/appledisplay.c1
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/sisusbvga/Kconfig2
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c2
-rw-r--r--drivers/usb/misc/usb3503.c13
-rw-r--r--drivers/usb/misc/uss720.c2
-rw-r--r--drivers/usb/mon/Kconfig1
-rw-r--r--drivers/usb/musb/Kconfig8
-rw-r--r--drivers/usb/musb/am35x.c8
-rw-r--r--drivers/usb/musb/blackfin.c6
-rw-r--r--drivers/usb/musb/cppi_dma.c17
-rw-r--r--drivers/usb/musb/da8xx.c8
-rw-r--r--drivers/usb/musb/davinci.c4
-rw-r--r--drivers/usb/musb/musb_core.c71
-rw-r--r--drivers/usb/musb/musb_dsps.c14
-rw-r--r--drivers/usb/musb/musb_gadget.c156
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c6
-rw-r--r--drivers/usb/musb/musb_host.c119
-rw-r--r--drivers/usb/musb/musb_virthub.c4
-rw-r--r--drivers/usb/musb/omap2430.c32
-rw-r--r--drivers/usb/musb/tusb6010.c14
-rw-r--r--drivers/usb/musb/ux500.c106
-rw-r--r--drivers/usb/musb/ux500_dma.c24
-rw-r--r--drivers/usb/otg/Kconfig141
-rw-r--r--drivers/usb/otg/Makefile24
-rw-r--r--drivers/usb/otg/ab8500-usb.c596
-rw-r--r--drivers/usb/phy/Kconfig181
-rw-r--r--drivers/usb/phy/Makefile35
-rw-r--r--drivers/usb/phy/isp1301.c71
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c924
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c (renamed from drivers/usb/otg/fsl_otg.c)34
-rw-r--r--drivers/usb/phy/phy-fsl-usb.h (renamed from drivers/usb/otg/fsl_otg.h)0
-rw-r--r--drivers/usb/phy/phy-fsm-usb.c (renamed from drivers/usb/otg/otg_fsm.c)4
-rw-r--r--drivers/usb/phy/phy-fsm-usb.h (renamed from drivers/usb/otg/otg_fsm.h)0
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c (renamed from drivers/usb/otg/gpio_vbus.c)9
-rw-r--r--drivers/usb/phy/phy-isp1301-omap.c (renamed from drivers/usb/otg/isp1301_omap.c)10
-rw-r--r--drivers/usb/phy/phy-isp1301.c162
-rw-r--r--drivers/usb/phy/phy-msm-usb.c (renamed from drivers/usb/otg/msm_otg.c)0
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.c (renamed from drivers/usb/phy/mv_u3d_phy.c)4
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.h (renamed from drivers/usb/phy/mv_u3d_phy.h)0
-rw-r--r--drivers/usb/phy/phy-mv-usb.c (renamed from drivers/usb/otg/mv_otg.c)30
-rw-r--r--drivers/usb/phy/phy-mv-usb.h (renamed from drivers/usb/otg/mv_otg.h)3
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c (renamed from drivers/usb/otg/mxs-phy.c)41
-rw-r--r--drivers/usb/phy/phy-nop.c (renamed from drivers/usb/otg/nop-usb-xceiv.c)143
-rw-r--r--drivers/usb/phy/phy-omap-control.c (renamed from drivers/usb/phy/omap-control-usb.c)0
-rw-r--r--drivers/usb/phy/phy-omap-usb2.c (renamed from drivers/usb/phy/omap-usb2.c)0
-rw-r--r--drivers/usb/phy/phy-omap-usb3.c (renamed from drivers/usb/phy/omap-usb3.c)0
-rw-r--r--drivers/usb/phy/phy-rcar-usb.c (renamed from drivers/usb/phy/rcar-phy.c)0
-rw-r--r--drivers/usb/phy/phy-samsung-usb.c236
-rw-r--r--drivers/usb/phy/phy-samsung-usb.h327
-rw-r--r--drivers/usb/phy/phy-samsung-usb2.c509
-rw-r--r--drivers/usb/phy/phy-samsung-usb3.c347
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c (renamed from drivers/usb/phy/tegra_usb_phy.c)13
-rw-r--r--drivers/usb/phy/phy-twl4030-usb.c (renamed from drivers/usb/otg/twl4030-usb.c)178
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c (renamed from drivers/usb/otg/twl6030-usb.c)15
-rw-r--r--drivers/usb/phy/phy-ulpi-viewport.c (renamed from drivers/usb/otg/ulpi_viewport.c)0
-rw-r--r--drivers/usb/phy/phy-ulpi.c (renamed from drivers/usb/otg/ulpi.c)0
-rw-r--r--drivers/usb/phy/phy.c (renamed from drivers/usb/otg/otg.c)64
-rw-r--r--drivers/usb/phy/samsung-usbphy.c928
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig2
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c1
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h2
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c24
-rw-r--r--drivers/usb/serial/Kconfig19
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ark3116.c87
-rw-r--r--drivers/usb/serial/bus.c5
-rw-r--r--drivers/usb/serial/ch341.c30
-rw-r--r--drivers/usb/serial/cp210x.c6
-rw-r--r--drivers/usb/serial/cyberjack.c19
-rw-r--r--drivers/usb/serial/cypress_m8.c94
-rw-r--r--drivers/usb/serial/digi_acceleport.c112
-rw-r--r--drivers/usb/serial/f81232.c13
-rw-r--r--drivers/usb/serial/ftdi_sio.c145
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h11
-rw-r--r--drivers/usb/serial/garmin_gps.c10
-rw-r--r--drivers/usb/serial/generic.c144
-rw-r--r--drivers/usb/serial/io_edgeport.c104
-rw-r--r--drivers/usb/serial/io_tables.h12
-rw-r--r--drivers/usb/serial/io_ti.c98
-rw-r--r--drivers/usb/serial/iuu_phoenix.c21
-rw-r--r--drivers/usb/serial/keyspan.c139
-rw-r--r--drivers/usb/serial/keyspan_pda.c25
-rw-r--r--drivers/usb/serial/kl5kusb105.c30
-rw-r--r--drivers/usb/serial/kobil_sct.c103
-rw-r--r--drivers/usb/serial/mct_u232.c131
-rw-r--r--drivers/usb/serial/metro-usb.c5
-rw-r--r--drivers/usb/serial/mos7720.c76
-rw-r--r--drivers/usb/serial/mos7840.c164
-rw-r--r--drivers/usb/serial/omninet.c81
-rw-r--r--drivers/usb/serial/opticon.c18
-rw-r--r--drivers/usb/serial/option.c17
-rw-r--r--drivers/usb/serial/oti6858.c30
-rw-r--r--drivers/usb/serial/pl2303.c39
-rw-r--r--drivers/usb/serial/quatech2.c114
-rw-r--r--drivers/usb/serial/sierra.c47
-rw-r--r--drivers/usb/serial/spcp8x5.c301
-rw-r--r--drivers/usb/serial/ssu100.c100
-rw-r--r--drivers/usb/serial/symbolserial.c130
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c170
-rw-r--r--drivers/usb/serial/usb-serial.c235
-rw-r--r--drivers/usb/serial/usb_wwan.c25
-rw-r--r--drivers/usb/serial/visor.c16
-rw-r--r--drivers/usb/serial/wishbone-serial.c95
-rw-r--r--drivers/usb/storage/Kconfig7
-rw-r--r--drivers/usb/storage/alauda.c101
-rw-r--r--drivers/usb/storage/cypress_atacb.c18
-rw-r--r--drivers/usb/storage/datafab.c59
-rw-r--r--drivers/usb/storage/debug.c36
-rw-r--r--drivers/usb/storage/debug.h23
-rw-r--r--drivers/usb/storage/ene_ub6250.c86
-rw-r--r--drivers/usb/storage/freecom.c85
-rw-r--r--drivers/usb/storage/initializers.c10
-rw-r--r--drivers/usb/storage/isd200.c295
-rw-r--r--drivers/usb/storage/jumpshot.c69
-rw-r--r--drivers/usb/storage/karma.c6
-rw-r--r--drivers/usb/storage/onetouch.c4
-rw-r--r--drivers/usb/storage/option_ms.c23
-rw-r--r--drivers/usb/storage/realtek_cr.c127
-rw-r--r--drivers/usb/storage/scsiglue.c13
-rw-r--r--drivers/usb/storage/sddr09.c146
-rw-r--r--drivers/usb/storage/sddr55.c86
-rw-r--r--drivers/usb/storage/shuttle_usbat.c119
-rw-r--r--drivers/usb/storage/sierra_ms.c43
-rw-r--r--drivers/usb/storage/transport.c181
-rw-r--r--drivers/usb/storage/usb.c117
-rw-r--r--drivers/usb/usb-common.c47
-rw-r--r--drivers/usb/usb-skeleton.c32
-rw-r--r--drivers/usb/wusbcore/Kconfig2
-rw-r--r--drivers/uwb/rsv.c4
-rw-r--r--drivers/vfio/pci/vfio_pci.c13
-rw-r--r--drivers/vhost/net.c74
-rw-r--r--drivers/vhost/tcm_vhost.c457
-rw-r--r--drivers/vhost/tcm_vhost.h13
-rw-r--r--drivers/vhost/vhost.c3
-rw-r--r--drivers/video/Kconfig68
-rw-r--r--drivers/video/Makefile9
-rw-r--r--drivers/video/amifb.c16
-rw-r--r--drivers/video/atmel_lcdfb.c13
-rw-r--r--drivers/video/auo_k1900fb.c11
-rw-r--r--drivers/video/auo_k1901fb.c11
-rw-r--r--drivers/video/auo_k190x.c237
-rw-r--r--drivers/video/backlight/Kconfig9
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/adp5520_bl.c28
-rw-r--r--drivers/video/backlight/adp8860_bl.c23
-rw-r--r--drivers/video/backlight/adp8870_bl.c33
-rw-r--r--drivers/video/backlight/ams369fg06.c21
-rw-r--r--drivers/video/backlight/as3711_bl.c118
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c14
-rw-r--r--drivers/video/backlight/corgi_lcd.c18
-rw-r--r--drivers/video/backlight/da903x_bl.c30
-rw-r--r--drivers/video/backlight/ep93xx_bl.c20
-rw-r--r--drivers/video/backlight/generic_bl.c6
-rw-r--r--drivers/video/backlight/hp680_bl.c18
-rw-r--r--drivers/video/backlight/ili922x.c555
-rw-r--r--drivers/video/backlight/ili9320.c26
-rw-r--r--drivers/video/backlight/ili9320.h2
-rw-r--r--drivers/video/backlight/jornada720_bl.c18
-rw-r--r--drivers/video/backlight/jornada720_lcd.c21
-rw-r--r--drivers/video/backlight/kb3886_bl.c18
-rw-r--r--drivers/video/backlight/l4f00242t03.c27
-rw-r--r--drivers/video/backlight/ld9040.c20
-rw-r--r--drivers/video/backlight/lm3533_bl.c22
-rw-r--r--drivers/video/backlight/lms501kf03.c22
-rw-r--r--drivers/video/backlight/locomolcd.c16
-rw-r--r--drivers/video/backlight/lp855x_bl.c105
-rw-r--r--drivers/video/backlight/ltv350qv.c18
-rw-r--r--drivers/video/backlight/omap1_bl.c26
-rw-r--r--drivers/video/backlight/platform_lcd.c12
-rw-r--r--drivers/video/backlight/s6e63m0.c20
-rw-r--r--drivers/video/backlight/tdo24m.c18
-rw-r--r--drivers/video/backlight/tosa_bl.c18
-rw-r--r--drivers/video/backlight/tosa_lcd.c18
-rw-r--r--drivers/video/backlight/tps65217_bl.c15
-rw-r--r--drivers/video/backlight/vgg2432a4.c18
-rw-r--r--drivers/video/console/fbcon_cw.c3
-rw-r--r--drivers/video/controlfb.c50
-rw-r--r--drivers/video/ep93xx-fb.c18
-rw-r--r--drivers/video/exynos/exynos_dp_core.c4
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi.c10
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_common.c2
-rw-r--r--drivers/video/exynos/exynos_mipi_dsi_lowlevel.c2
-rw-r--r--drivers/video/fb-puv3.c14
-rw-r--r--drivers/video/fbmem.c36
-rw-r--r--drivers/video/fbmon.c16
-rw-r--r--drivers/video/fsl-diu-fb.c157
-rw-r--r--drivers/video/gbefb.c4
-rw-r--r--drivers/video/goldfishfb.c2
-rw-r--r--drivers/video/hyperv_fb.c829
-rw-r--r--drivers/video/matrox/matroxfb_maven.c16
-rw-r--r--drivers/video/mmp/core.c2
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.h479
-rw-r--r--drivers/video/of_display_timing.c19
-rw-r--r--drivers/video/of_videomode.c2
-rw-r--r--drivers/video/omap/Kconfig11
-rw-r--r--drivers/video/omap/omapfb_main.c2
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c13
-rw-r--r--drivers/video/omap2/dss/dss_features.c6
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c30
-rw-r--r--drivers/video/omap2/vrfb.c13
-rw-r--r--drivers/video/ps3fb.c18
-rw-r--r--drivers/video/s1d13xxxfb.c2
-rw-r--r--drivers/video/s3c-fb.c3
-rw-r--r--drivers/video/sa1100fb.c16
-rw-r--r--drivers/video/sgivwfb.c20
-rw-r--r--drivers/video/sh_mipi_dsi.c12
-rw-r--r--drivers/video/sh_mobile_hdmi.c12
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c1
-rw-r--r--drivers/video/smscufx.c6
-rw-r--r--drivers/video/ssd1307fb.c4
-rw-r--r--drivers/video/udlfb.c6
-rw-r--r--drivers/video/uvesafb.c5
-rw-r--r--drivers/video/vermilion/vermilion.c14
-rw-r--r--drivers/video/vfb.c7
-rw-r--r--drivers/video/videomode.c36
-rw-r--r--drivers/video/vt8500lcdfb.c55
-rw-r--r--drivers/video/wm8505fb.c145
-rw-r--r--drivers/video/wmt_ge_rops.h23
-rw-r--r--drivers/w1/masters/mxc_w1.c6
-rw-r--r--drivers/w1/slaves/Kconfig10
-rw-r--r--drivers/w1/slaves/w1_bq27000.c4
-rw-r--r--drivers/w1/slaves/w1_ds2408.c25
-rw-r--r--drivers/w1/slaves/w1_ds2760.c3
-rw-r--r--drivers/w1/slaves/w1_ds2780.c3
-rw-r--r--drivers/w1/slaves/w1_ds2781.c3
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/xen/Kconfig6
-rw-r--r--drivers/xen/events.c72
-rw-r--r--drivers/xen/fallback.c3
-rw-r--r--drivers/xen/tmem.c55
-rw-r--r--drivers/xen/xen-acpi-processor.c85
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c59
-rw-r--r--drivers/xen/xen-selfballoon.c13
-rw-r--r--firmware/Makefile2
-rw-r--r--firmware/qlogic/sd7220.fw.ihex (renamed from firmware/intel/sd7220.fw.ihex)0
-rw-r--r--fs/Kconfig1
-rw-r--r--fs/Kconfig.binfmt14
-rw-r--r--fs/Makefile9
-rw-r--r--fs/aio.c4
-rw-r--r--fs/befs/btree.c3
-rw-r--r--fs/binfmt_aout.c1
-rw-r--r--fs/binfmt_elf.c7
-rw-r--r--fs/binfmt_elf_fdpic.c2
-rw-r--r--fs/binfmt_misc.c24
-rw-r--r--fs/bio.c2
-rw-r--r--fs/block_dev.c9
-rw-r--r--fs/btrfs/ctree.c30
-rw-r--r--fs/btrfs/disk-io.c14
-rw-r--r--fs/btrfs/extent-tree.c84
-rw-r--r--fs/btrfs/extent_io.c33
-rw-r--r--fs/btrfs/extent_io.h2
-rw-r--r--fs/btrfs/file-item.c6
-rw-r--r--fs/btrfs/file.c9
-rw-r--r--fs/btrfs/inode.c22
-rw-r--r--fs/btrfs/ordered-data.c2
-rw-r--r--fs/btrfs/qgroup.c3
-rw-r--r--fs/btrfs/scrub.c3
-rw-r--r--fs/btrfs/send.c10
-rw-r--r--fs/btrfs/tree-log.c48
-rw-r--r--fs/btrfs/volumes.c13
-rw-r--r--fs/buffer.c16
-rw-r--r--fs/cifs/connect.c16
-rw-r--r--fs/compat.c121
-rw-r--r--fs/coredump.c84
-rw-r--r--fs/dcache.c4
-rw-r--r--fs/dcookies.c15
-rw-r--r--fs/direct-io.c31
-rw-r--r--fs/dlm/lowcomms.c2
-rw-r--r--fs/dlm/plock.c18
-rw-r--r--fs/efivarfs/Kconfig12
-rw-r--r--fs/efivarfs/Makefile7
-rw-r--r--fs/efivarfs/file.c106
-rw-r--r--fs/efivarfs/inode.c174
-rw-r--r--fs/efivarfs/internal.h22
-rw-r--r--fs/efivarfs/super.c270
-rw-r--r--fs/eventpoll.c175
-rw-r--r--fs/exec.c17
-rw-r--r--fs/ext3/super.c1
-rw-r--r--fs/ext4/Kconfig3
-rw-r--r--fs/ext4/balloc.c53
-rw-r--r--fs/ext4/dir.c20
-rw-r--r--fs/ext4/ext4.h101
-rw-r--r--fs/ext4/ext4_extents.h5
-rw-r--r--fs/ext4/ext4_jbd2.c8
-rw-r--r--fs/ext4/ext4_jbd2.h12
-rw-r--r--fs/ext4/extents.c533
-rw-r--r--fs/ext4/fsync.c3
-rw-r--r--fs/ext4/ialloc.c88
-rw-r--r--fs/ext4/indirect.c477
-rw-r--r--fs/ext4/inline.c178
-rw-r--r--fs/ext4/inode.c580
-rw-r--r--fs/ext4/ioctl.c218
-rw-r--r--fs/ext4/mballoc.c253
-rw-r--r--fs/ext4/migrate.c62
-rw-r--r--fs/ext4/mmp.c6
-rw-r--r--fs/ext4/move_extent.c73
-rw-r--r--fs/ext4/namei.c48
-rw-r--r--fs/ext4/page-io.c280
-rw-r--r--fs/ext4/resize.c16
-rw-r--r--fs/ext4/super.c131
-rw-r--r--fs/ext4/xattr.c13
-rw-r--r--fs/ext4/xattr.h1
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/gc.c2
-rw-r--r--fs/f2fs/super.c2
-rw-r--r--fs/fat/dir.c23
-rw-r--r--fs/fat/fat.h40
-rw-r--r--fs/fat/file.c5
-rw-r--r--fs/fat/inode.c74
-rw-r--r--fs/fat/nfs.c221
-rw-r--r--fs/fs-writeback.c1
-rw-r--r--fs/fscache/stats.c2
-rw-r--r--fs/gfs2/aops.c2
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/file.c5
-rw-r--r--fs/gfs2/glock.c32
-rw-r--r--fs/gfs2/glock.h1
-rw-r--r--fs/gfs2/glops.c4
-rw-r--r--fs/gfs2/incore.h20
-rw-r--r--fs/gfs2/inode.c188
-rw-r--r--fs/gfs2/lock_dlm.c39
-rw-r--r--fs/gfs2/log.c104
-rw-r--r--fs/gfs2/lops.c32
-rw-r--r--fs/gfs2/lops.h5
-rw-r--r--fs/gfs2/meta_io.c2
-rw-r--r--fs/gfs2/rgrp.c56
-rw-r--r--fs/gfs2/rgrp.h2
-rw-r--r--fs/gfs2/super.c2
-rw-r--r--fs/gfs2/trace_gfs2.h11
-rw-r--r--fs/gfs2/trans.c7
-rw-r--r--fs/hfs/bfind.c10
-rw-r--r--fs/hfs/bitmap.c4
-rw-r--r--fs/hfs/bnode.c39
-rw-r--r--fs/hfs/brec.c19
-rw-r--r--fs/hfs/btree.c31
-rw-r--r--fs/hfs/catalog.c24
-rw-r--r--fs/hfs/dir.c20
-rw-r--r--fs/hfs/extent.c68
-rw-r--r--fs/hfs/hfs_fs.h22
-rw-r--r--fs/hfs/inode.c15
-rw-r--r--fs/hfs/mdb.c23
-rw-r--r--fs/hfs/super.c47
-rw-r--r--fs/hfsplus/attributes.c26
-rw-r--r--fs/hfsplus/bfind.c14
-rw-r--r--fs/hfsplus/bitmap.c13
-rw-r--r--fs/hfsplus/bnode.c36
-rw-r--r--fs/hfsplus/brec.c14
-rw-r--r--fs/hfsplus/btree.c29
-rw-r--r--fs/hfsplus/catalog.c11
-rw-r--r--fs/hfsplus/dir.c14
-rw-r--r--fs/hfsplus/extents.c55
-rw-r--r--fs/hfsplus/hfsplus_fs.h20
-rw-r--r--fs/hfsplus/inode.c4
-rw-r--r--fs/hfsplus/options.c22
-rw-r--r--fs/hfsplus/super.c56
-rw-r--r--fs/hfsplus/wrapper.c8
-rw-r--r--fs/hfsplus/xattr.c41
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--fs/inode.c2
-rw-r--r--fs/jbd/commit.c25
-rw-r--r--fs/jbd/journal.c2
-rw-r--r--fs/jbd2/commit.c50
-rw-r--r--fs/jbd2/journal.c33
-rw-r--r--fs/jbd2/transaction.c9
-rw-r--r--fs/lockd/clntlock.c3
-rw-r--r--fs/lockd/clntproc.c3
-rw-r--r--fs/namespace.c55
-rw-r--r--fs/nfs/callback.c3
-rw-r--r--fs/nfs/callback_proc.c2
-rw-r--r--fs/nfs/client.c2
-rw-r--r--fs/nfs/delegation.c121
-rw-r--r--fs/nfs/delegation.h5
-rw-r--r--fs/nfs/dir.c2
-rw-r--r--fs/nfs/file.c9
-rw-r--r--fs/nfs/inode.c8
-rw-r--r--fs/nfs/internal.h7
-rw-r--r--fs/nfs/nfs4_fs.h16
-rw-r--r--fs/nfs/nfs4client.c75
-rw-r--r--fs/nfs/nfs4filelayout.c34
-rw-r--r--fs/nfs/nfs4namespace.c43
-rw-r--r--fs/nfs/nfs4proc.c558
-rw-r--r--fs/nfs/nfs4state.c149
-rw-r--r--fs/nfs/nfs4super.c2
-rw-r--r--fs/nfs/nfs4xdr.c176
-rw-r--r--fs/nfs/objlayout/objio_osd.c2
-rw-r--r--fs/nfs/objlayout/objlayout.h2
-rw-r--r--fs/nfs/pagelist.c53
-rw-r--r--fs/nfs/pnfs.c2
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/super.c83
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/nfs4state.c7
-rw-r--r--fs/nfsd/nfs4xdr.c26
-rw-r--r--fs/nilfs2/inode.c17
-rw-r--r--fs/nilfs2/mdt.c19
-rw-r--r--fs/nilfs2/page.c70
-rw-r--r--fs/nilfs2/page.h3
-rw-r--r--fs/notify/fanotify/fanotify_user.c17
-rw-r--r--fs/notify/inotify/inotify_user.c14
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c6
-rw-r--r--fs/ocfs2/ioctl.c22
-rw-r--r--fs/ocfs2/move_extents.c53
-rw-r--r--fs/open.c52
-rw-r--r--fs/pnode.c6
-rw-r--r--fs/pnode.h1
-rw-r--r--fs/proc/Makefile2
-rw-r--r--fs/proc/array.c1
-rw-r--r--fs/proc/base.c105
-rw-r--r--fs/proc/internal.h21
-rw-r--r--fs/proc/kcore.c9
-rw-r--r--fs/proc/meminfo.c1
-rw-r--r--fs/proc/mmu.c60
-rw-r--r--fs/proc/root.c4
-rw-r--r--fs/read_write.c73
-rw-r--r--fs/read_write.h3
-rw-r--r--fs/reiserfs/xattr.c4
-rw-r--r--fs/signalfd.c31
-rw-r--r--fs/splice.c22
-rw-r--r--fs/sync.c26
-rw-r--r--fs/sysfs/dir.c58
-rw-r--r--fs/sysfs/mount.c4
-rw-r--r--fs/ubifs/super.c12
-rw-r--r--fs/ufs/util.c3
-rw-r--r--include/Kbuild3
-rw-r--r--include/acpi/acexcep.h461
-rw-r--r--include/acpi/acoutput.h53
-rw-r--r--include/acpi/acpi_bus.h33
-rw-r--r--include/acpi/acpi_drivers.h1
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/acpi/actbl2.h47
-rw-r--r--include/acpi/actbl3.h55
-rw-r--r--include/acpi/actypes.h16
-rw-r--r--include/asm-generic/hugetlb.h40
-rw-r--r--include/asm-generic/pgtable.h10
-rw-r--r--include/asm-generic/tlb.h7
-rw-r--r--include/asm-generic/unistd.h17
-rw-r--r--include/linux/acpi.h13
-rw-r--r--include/linux/amba/serial.h3
-rw-r--r--include/linux/async.h13
-rw-r--r--include/linux/ata.h2
-rw-r--r--include/linux/bcma/bcma.h55
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h6
-rw-r--r--include/linux/bcma/bcma_regs.h1
-rw-r--r--include/linux/blk_types.h3
-rw-r--r--include/linux/blktrace_api.h1
-rw-r--r--include/linux/bootmem.h1
-rw-r--r--include/linux/buffer_head.h5
-rw-r--r--include/linux/capability.h2
-rw-r--r--include/linux/cgroup.h178
-rw-r--r--include/linux/cleancache.h4
-rw-r--r--include/linux/clk-private.h2
-rw-r--r--include/linux/clk-provider.h63
-rw-r--r--include/linux/clk.h8
-rw-r--r--include/linux/clk/sunxi.h22
-rw-r--r--include/linux/clockchips.h44
-rw-r--r--include/linux/clocksource.h1
-rw-r--r--include/linux/cn_proc.h4
-rw-r--r--include/linux/compat.h55
-rw-r--r--include/linux/compiler-gcc4.h2
-rw-r--r--include/linux/compiler.h6
-rw-r--r--include/linux/console.h1
-rw-r--r--include/linux/context_tracking.h24
-rw-r--r--include/linux/cpu.h16
-rw-r--r--include/linux/cpufreq.h21
-rw-r--r--include/linux/cpuidle.h23
-rw-r--r--include/linux/cpumask.h15
-rw-r--r--include/linux/cpuset.h1
-rw-r--r--include/linux/ctype.h6
-rw-r--r--include/linux/debug_locks.h6
-rw-r--r--include/linux/devfreq.h16
-rw-r--r--include/linux/device.h25
-rw-r--r--include/linux/dma-buf.h16
-rw-r--r--include/linux/dmi.h2
-rw-r--r--include/linux/efi.h99
-rw-r--r--include/linux/evm.h2
-rw-r--r--include/linux/exportfs.h11
-rw-r--r--include/linux/filter.h15
-rw-r--r--include/linux/freezer.h3
-rw-r--r--include/linux/frontswap.h36
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/fs_struct.h2
-rw-r--r--include/linux/fsnotify_backend.h1
-rw-r--r--include/linux/ftrace.h11
-rw-r--r--include/linux/ftrace_event.h111
-rw-r--r--include/linux/genalloc.h18
-rw-r--r--include/linux/hid-debug.h6
-rw-r--r--include/linux/hid.h101
-rw-r--r--include/linux/hrtimer.h5
-rw-r--r--include/linux/huge_mm.h11
-rw-r--r--include/linux/hugetlb.h4
-rw-r--r--include/linux/hyperv.h80
-rw-r--r--include/linux/icmpv6.h18
-rw-r--r--include/linux/idr.h2
-rw-r--r--include/linux/ieee80211.h125
-rw-r--r--include/linux/if_arp.h12
-rw-r--r--include/linux/if_team.h25
-rw-r--r--include/linux/if_vlan.h56
-rw-r--r--include/linux/iio/adc/ad_sigma_delta.h6
-rw-r--r--include/linux/iio/common/st_sensors.h5
-rw-r--r--include/linux/iio/gyro/itg3200.h2
-rw-r--r--include/linux/iio/iio.h79
-rw-r--r--include/linux/iio/imu/adis.h34
-rw-r--r--include/linux/iio/trigger.h26
-rw-r--r--include/linux/ima.h4
-rw-r--r--include/linux/input/auo-pixcir-ts.h4
-rw-r--r--include/linux/input/mt.h1
-rw-r--r--include/linux/integrity.h2
-rw-r--r--include/linux/ioport.h4
-rw-r--r--include/linux/ipack.h42
-rw-r--r--include/linux/ipc_namespace.h2
-rw-r--r--include/linux/jbd2.h4
-rw-r--r--include/linux/jiffies.h1
-rw-r--r--include/linux/journal-head.h11
-rw-r--r--include/linux/kernel.h72
-rw-r--r--include/linux/kexec.h2
-rw-r--r--include/linux/kmod.h17
-rw-r--r--include/linux/kprobes.h6
-rw-r--r--include/linux/kthread.h1
-rw-r--r--include/linux/ktime.h18
-rw-r--r--include/linux/kvm_host.h2
-rw-r--r--include/linux/kvm_types.h1
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/linkage.h18
-rw-r--r--include/linux/list_bl.h5
-rw-r--r--include/linux/math64.h19
-rw-r--r--include/linux/mei_cl_bus.h44
-rw-r--r--include/linux/memory.h17
-rw-r--r--include/linux/memory_hotplug.h4
-rw-r--r--include/linux/mfd/abx500.h27
-rw-r--r--include/linux/mfd/abx500/ab8500-bm.h61
-rw-r--r--include/linux/mfd/abx500/ab8500-gpadc.h74
-rw-r--r--include/linux/mfd/abx500/ab8500-sysctrl.h6
-rw-r--r--include/linux/mfd/abx500/ab8500.h14
-rw-r--r--include/linux/mfd/abx500/ux500_chargalg.h7
-rw-r--r--include/linux/mfd/arizona/core.h3
-rw-r--r--include/linux/mfd/arizona/pdata.h21
-rw-r--r--include/linux/mfd/arizona/registers.h4
-rw-r--r--include/linux/mfd/max77693-private.h23
-rw-r--r--include/linux/mfd/palmas.h24
-rw-r--r--include/linux/mfd/tps65090.h5
-rw-r--r--include/linux/mfd/tps65217.h1
-rw-r--r--include/linux/micrel_phy.h1
-rw-r--r--include/linux/mlx4/cmd.h6
-rw-r--r--include/linux/mlx4/cq.h16
-rw-r--r--include/linux/mlx4/device.h13
-rw-r--r--include/linux/mm.h85
-rw-r--r--include/linux/mman.h4
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/mod_devicetable.h9
-rw-r--r--include/linux/mount.h2
-rw-r--r--include/linux/msi.h23
-rw-r--r--include/linux/mutex.h3
-rw-r--r--include/linux/mv643xx_eth.h1
-rw-r--r--include/linux/net.h4
-rw-r--r--include/linux/netdev_features.h27
-rw-r--r--include/linux/netdevice.h83
-rw-r--r--include/linux/netfilter.h5
-rw-r--r--include/linux/netfilter/ipset/ip_set.h126
-rw-r--r--include/linux/netfilter/ipset/ip_set_ahash.h1225
-rw-r--r--include/linux/netfilter/ipset/ip_set_bitmap.h6
-rw-r--r--include/linux/netfilter/ipset/ip_set_timeout.h102
-rw-r--r--include/linux/netfilter/ipset/pfxlen.h9
-rw-r--r--include/linux/netfilter/nfnetlink.h11
-rw-r--r--include/linux/netlink.h11
-rw-r--r--include/linux/netpoll.h2
-rw-r--r--include/linux/nfs_fs.h8
-rw-r--r--include/linux/nfs_fs_sb.h3
-rw-r--r--include/linux/nfs_xdr.h27
-rw-r--r--include/linux/notifier.h5
-rw-r--r--include/linux/of_net.h10
-rw-r--r--include/linux/openvswitch.h431
-rw-r--r--include/linux/pagemap.h2
-rw-r--r--include/linux/pci-acpi.h29
-rw-r--r--include/linux/pci-aspm.h20
-rw-r--r--include/linux/pci-ats.h26
-rw-r--r--include/linux/pci.h123
-rw-r--r--include/linux/pci_hotplug.h12
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/pcieport_if.h4
-rw-r--r--include/linux/perf_event.h24
-rw-r--r--include/linux/phy.h10
-rw-r--r--include/linux/pid_namespace.h4
-rw-r--r--include/linux/pinctrl/pinconf.h6
-rw-r--r--include/linux/pinctrl/pinctrl.h6
-rw-r--r--include/linux/platform_data/brcmfmac-sdio.h124
-rw-r--r--include/linux/platform_data/clk-lpss.h18
-rw-r--r--include/linux/platform_data/coda.h18
-rw-r--r--include/linux/platform_data/cpsw.h2
-rw-r--r--include/linux/platform_data/dwc3-omap.h4
-rw-r--r--include/linux/platform_data/emif_plat.h1
-rw-r--r--include/linux/platform_data/lp855x.h15
-rw-r--r--include/linux/platform_data/mv_usb.h2
-rw-r--r--include/linux/platform_data/ntc_thermistor.h10
-rw-r--r--include/linux/platform_data/serial-sccnxp.h4
-rw-r--r--include/linux/platform_data/si5351.h114
-rw-r--r--include/linux/platform_data/spi-s3c64xx.h3
-rw-r--r--include/linux/platform_data/st1232_pdata.h13
-rw-r--r--include/linux/platform_data/video-vt8500lcdfb.h31
-rw-r--r--include/linux/platform_data/video_s3c.h54
-rw-r--r--include/linux/platform_device.h25
-rw-r--r--include/linux/pm2301_charger.h2
-rw-r--r--include/linux/posix-timers.h1
-rw-r--r--include/linux/power/ab8500.h16
-rw-r--r--include/linux/power_supply.h6
-rw-r--r--include/linux/preempt.h22
-rw-r--r--include/linux/printk.h22
-rw-r--r--include/linux/ramfs.h8
-rw-r--r--include/linux/rculist_bl.h2
-rw-r--r--include/linux/rcupdate.h1
-rw-r--r--include/linux/regmap.h1
-rw-r--r--include/linux/regulator/ab8500.h217
-rw-r--r--include/linux/regulator/consumer.h14
-rw-r--r--include/linux/regulator/driver.h9
-rw-r--r--include/linux/regulator/max8952.h10
-rw-r--r--include/linux/relay.h3
-rw-r--r--include/linux/res_counter.h2
-rw-r--r--include/linux/ring_buffer.h6
-rw-r--r--include/linux/rtc.h6
-rw-r--r--include/linux/rtnetlink.h9
-rw-r--r--include/linux/sched.h275
-rw-r--r--include/linux/sctp.h6
-rw-r--r--include/linux/security.h22
-rw-r--r--include/linux/serial_s3c.h260
-rw-r--r--include/linux/sh_eth.h1
-rw-r--r--include/linux/signal.h4
-rw-r--r--include/linux/skbuff.h102
-rw-r--r--include/linux/smp.h1
-rw-r--r--include/linux/sock_diag.h3
-rw-r--r--include/linux/socket.h1
-rw-r--r--include/linux/spi/at86rf230.h14
-rw-r--r--include/linux/spi/spi-tegra.h40
-rw-r--r--include/linux/spi/spi.h8
-rw-r--r--include/linux/spinlock_up.h29
-rw-r--r--include/linux/ssb/ssb.h60
-rw-r--r--include/linux/ssb/ssb_driver_chipcommon.h2
-rw-r--r--include/linux/ssb/ssb_regs.h10
-rw-r--r--include/linux/ssbi.h38
-rw-r--r--include/linux/string_helpers.h58
-rw-r--r--include/linux/sunrpc/auth.h9
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--include/linux/sunrpc/gss_api.h30
-rw-r--r--include/linux/sunrpc/xprt.h5
-rw-r--r--include/linux/swap.h10
-rw-r--r--include/linux/swiotlb.h1
-rw-r--r--include/linux/syscalls.h156
-rw-r--r--include/linux/tcp.h21
-rw-r--r--include/linux/time.h3
-rw-r--r--include/linux/timekeeper_internal.h9
-rw-r--r--include/linux/timex.h7
-rw-r--r--include/linux/trace_clock.h1
-rw-r--r--include/linux/tty.h41
-rw-r--r--include/linux/tty_ldisc.h132
-rw-r--r--include/linux/ucs2_string.h14
-rw-r--r--include/linux/uprobes.h8
-rw-r--r--include/linux/usb.h13
-rw-r--r--include/linux/usb/cdc-wdm.h2
-rw-r--r--include/linux/usb/ch9.h9
-rw-r--r--include/linux/usb/composite.h3
-rw-r--r--include/linux/usb/dwc3-omap.h6
-rw-r--r--include/linux/usb/gadget.h11
-rw-r--r--include/linux/usb/gadget_configfs.h110
-rw-r--r--include/linux/usb/hcd.h8
-rw-r--r--include/linux/usb/musb-ux500.h31
-rw-r--r--include/linux/usb/nop-usb-xceiv.h5
-rw-r--r--include/linux/usb/otg.h9
-rw-r--r--include/linux/usb/phy.h33
-rw-r--r--include/linux/usb/renesas_usbhs.h6
-rw-r--r--include/linux/usb/serial.h12
-rw-r--r--include/linux/usb/tegra_usb_phy.h10
-rw-r--r--include/linux/usb/usbnet.h2
-rw-r--r--include/linux/user_namespace.h4
-rw-r--r--include/linux/vexpress.h3
-rw-r--r--include/linux/virtio.h6
-rw-r--r--include/linux/vm_sockets.h23
-rw-r--r--include/linux/vmalloc.h34
-rw-r--r--include/linux/vmpressure.h47
-rw-r--r--include/linux/vmstat.h7
-rw-r--r--include/linux/workqueue.h171
-rw-r--r--include/media/davinci/dm355_ccdc.h6
-rw-r--r--include/media/davinci/dm644x_ccdc.h24
-rw-r--r--include/media/davinci/vpbe.h2
-rw-r--r--include/media/davinci/vpbe_types.h3
-rw-r--r--include/media/media-devnode.h1
-rw-r--r--include/media/mt9p031.h2
-rw-r--r--include/media/omap3isp.h10
-rw-r--r--include/media/rc-core.h2
-rw-r--r--include/media/rc-map.h1
-rw-r--r--include/media/s5p_fimc.h64
-rw-r--r--include/media/saa7115.h32
-rw-r--r--include/media/si476x.h37
-rw-r--r--include/media/soc_camera.h7
-rw-r--r--include/media/soc_mediabus.h3
-rw-r--r--include/media/ths7303.h42
-rw-r--r--include/media/tuner.h6
-rw-r--r--include/media/uda1342.h29
-rw-r--r--include/media/v4l2-chip-ident.h11
-rw-r--r--include/media/v4l2-common.h1
-rw-r--r--include/media/v4l2-ctrls.h29
-rw-r--r--include/media/v4l2-device.h13
-rw-r--r--include/media/v4l2-ioctl.h22
-rw-r--r--include/media/v4l2-of.h111
-rw-r--r--include/media/v4l2-subdev.h25
-rw-r--r--include/media/videobuf-dma-contig.h10
-rw-r--r--include/media/videobuf2-core.h11
-rw-r--r--include/net/addrconf.h1
-rw-r--r--include/net/af_unix.h8
-rw-r--r--include/net/bluetooth/bluetooth.h17
-rw-r--r--include/net/bluetooth/hci.h30
-rw-r--r--include/net/bluetooth/hci_core.h128
-rw-r--r--include/net/bluetooth/l2cap.h15
-rw-r--r--include/net/bluetooth/rfcomm.h6
-rw-r--r--include/net/caif/caif_dev.h2
-rw-r--r--include/net/caif/caif_device.h2
-rw-r--r--include/net/caif/caif_hsi.h1
-rw-r--r--include/net/caif/caif_layer.h2
-rw-r--r--include/net/caif/caif_shm.h26
-rw-r--r--include/net/caif/cfcnfg.h2
-rw-r--r--include/net/caif/cfctrl.h2
-rw-r--r--include/net/caif/cffrml.h2
-rw-r--r--include/net/caif/cfmuxl.h2
-rw-r--r--include/net/caif/cfpkt.h2
-rw-r--r--include/net/caif/cfserl.h2
-rw-r--r--include/net/caif/cfsrvl.h2
-rw-r--r--include/net/cfg80211.h164
-rw-r--r--include/net/cls_cgroup.h4
-rw-r--r--include/net/dn_fib.h28
-rw-r--r--include/net/firewire.h25
-rw-r--r--include/net/genetlink.h1
-rw-r--r--include/net/gre.h51
-rw-r--r--include/net/ieee802154_netdev.h5
-rw-r--r--include/net/if_inet6.h4
-rw-r--r--include/net/inet_connection_sock.h5
-rw-r--r--include/net/inet_frag.h24
-rw-r--r--include/net/ip6_tunnel.h21
-rw-r--r--include/net/ip_tunnels.h177
-rw-r--r--include/net/ip_vs.h140
-rw-r--r--include/net/ipip.h87
-rw-r--r--include/net/ipv6.h22
-rw-r--r--include/net/irda/irlmp.h3
-rw-r--r--include/net/iucv/af_iucv.h8
-rw-r--r--include/net/mac80211.h224
-rw-r--r--include/net/net_namespace.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h2
-rw-r--r--include/net/netfilter/nf_conntrack_core.h1
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h4
-rw-r--r--include/net/netfilter/nf_log.h14
-rw-r--r--include/net/netfilter/nf_queue.h6
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--include/net/netns/netfilter.h18
-rw-r--r--include/net/netprio_cgroup.h4
-rw-r--r--include/net/nfc/nfc.h2
-rw-r--r--include/net/request_sock.h10
-rw-r--r--include/net/rtnetlink.h2
-rw-r--r--include/net/scm.h16
-rw-r--r--include/net/sctp/checksum.h2
-rw-r--r--include/net/sctp/constants.h1
-rw-r--r--include/net/sctp/sctp.h2
-rw-r--r--include/net/sctp/structs.h20
-rw-r--r--include/net/sctp/ulpqueue.h1
-rw-r--r--include/net/secure_seq.h1
-rw-r--r--include/net/sock.h6
-rw-r--r--include/net/tcp.h146
-rw-r--r--include/net/xfrm.h1
-rw-r--r--include/pcmcia/ds.h12
-rw-r--r--include/scsi/Kbuild1
-rw-r--r--include/scsi/iscsi_if.h117
-rw-r--r--include/scsi/libfc.h3
-rw-r--r--include/scsi/libiscsi.h1
-rw-r--r--include/scsi/scsi_transport_iscsi.h151
-rw-r--r--[-rwxr-xr-x]include/sound/max98090.h0
-rw-r--r--include/sound/pcm.h2
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/target/iscsi/iscsi_transport.h83
-rw-r--r--include/target/target_core_backend.h4
-rw-r--r--include/target/target_core_fabric.h2
-rw-r--r--include/trace/events/block.h8
-rw-r--r--include/trace/events/ext4.h16
-rw-r--r--include/trace/events/filemap.h58
-rw-r--r--include/trace/events/jbd2.h21
-rw-r--r--include/trace/events/printk.h25
-rw-r--r--include/trace/events/rcu.h55
-rw-r--r--include/trace/events/regmap.h48
-rw-r--r--include/trace/events/sched.h2
-rw-r--r--include/trace/events/timer.h10
-rw-r--r--include/trace/ftrace.h49
-rw-r--r--include/uapi/asm-generic/socket.h2
-rw-r--r--include/uapi/linux/Kbuild2
-rw-r--r--include/uapi/linux/caif/caif_socket.h2
-rw-r--r--include/uapi/linux/caif/if_caif.h2
-rw-r--r--include/uapi/linux/cn_proc.h10
-rw-r--r--include/uapi/linux/connector.h5
-rw-r--r--include/uapi/linux/dvb/dmx.h2
-rw-r--r--include/uapi/linux/elf.h1
-rw-r--r--include/uapi/linux/filter.h3
-rw-r--r--include/uapi/linux/fs.h1
-rw-r--r--include/uapi/linux/fuse.h436
-rw-r--r--include/uapi/linux/if_ether.h3
-rw-r--r--include/uapi/linux/if_link.h7
-rw-r--r--include/uapi/linux/if_packet.h29
-rw-r--r--include/uapi/linux/input.h5
-rw-r--r--include/uapi/linux/ip_vs.h4
-rw-r--r--include/uapi/linux/magic.h1
-rw-r--r--include/uapi/linux/media.h2
-rw-r--r--include/uapi/linux/neighbour.h3
-rw-r--r--include/uapi/linux/netfilter/ipset/ip_set.h36
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_queue.h10
-rw-r--r--include/uapi/linux/netfilter/xt_NFQUEUE.h9
-rw-r--r--include/uapi/linux/netfilter/xt_set.h9
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_frag.h4
-rw-r--r--include/uapi/linux/netlink.h34
-rw-r--r--include/uapi/linux/netlink_diag.h52
-rw-r--r--include/uapi/linux/nfc.h19
-rw-r--r--include/uapi/linux/nl80211.h156
-rw-r--r--include/uapi/linux/openvswitch.h456
-rw-r--r--include/uapi/linux/packet_diag.h5
-rw-r--r--include/uapi/linux/pci_regs.h30
-rw-r--r--include/uapi/linux/perf_event.h71
-rw-r--r--include/uapi/linux/pkt_sched.h1
-rw-r--r--include/uapi/linux/ptrace.h12
-rw-r--r--include/uapi/linux/rfkill.h2
-rw-r--r--include/uapi/linux/sctp.h (renamed from include/net/sctp/user.h)84
-rw-r--r--include/uapi/linux/snmp.h8
-rw-r--r--include/uapi/linux/tcp.h26
-rw-r--r--include/uapi/linux/time.h6
-rw-r--r--include/uapi/linux/usb/cdc-wdm.h21
-rw-r--r--include/uapi/linux/usb/ch9.h4
-rw-r--r--include/uapi/linux/v4l2-controls.h28
-rw-r--r--include/uapi/linux/v4l2-dv-timings.h18
-rw-r--r--include/uapi/linux/v4l2-mediabus.h6
-rw-r--r--include/uapi/linux/videodev2.h111
-rw-r--r--include/uapi/linux/vm_sockets.h23
-rw-r--r--include/uapi/linux/xfrm.h3
-rw-r--r--include/video/auo_k190xfb.h3
-rw-r--r--include/video/display_timing.h57
-rw-r--r--include/video/platform_lcd.h1
-rw-r--r--include/video/videomode.h18
-rw-r--r--include/xen/events.h3
-rw-r--r--include/xen/interface/io/blkif.h10
-rw-r--r--include/xen/interface/io/netif.h19
-rw-r--r--include/xen/interface/physdev.h6
-rw-r--r--include/xen/tmem.h8
-rw-r--r--init/Kconfig154
-rw-r--r--init/do_mounts_initrd.c8
-rw-r--r--init/main.c53
-rw-r--r--ipc/compat.c174
-rw-r--r--ipc/mqueue.c12
-rw-r--r--ipc/msg.c123
-rw-r--r--ipc/msgutil.c110
-rw-r--r--ipc/sem.c553
-rw-r--r--ipc/shm.c2
-rw-r--r--ipc/syscall.c6
-rw-r--r--ipc/util.c165
-rw-r--r--ipc/util.h19
-rw-r--r--kernel/.gitignore1
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/async.c40
-rw-r--r--kernel/audit.c22
-rw-r--r--kernel/audit.h3
-rw-r--r--kernel/audit_tree.c2
-rw-r--r--kernel/auditfilter.c4
-rw-r--r--kernel/auditsc.c14
-rw-r--r--kernel/capability.c24
-rw-r--r--kernel/cgroup.c780
-rw-r--r--kernel/compat.c84
-rw-r--r--kernel/cpu/Makefile1
-rw-r--r--kernel/cpu/idle.c116
-rw-r--r--kernel/cpuset.c143
-rw-r--r--kernel/debug/debug_core.c2
-rw-r--r--kernel/events/core.c62
-rw-r--r--kernel/events/internal.h2
-rw-r--r--kernel/events/ring_buffer.c22
-rw-r--r--kernel/events/uprobes.c300
-rw-r--r--kernel/exit.c7
-rw-r--r--kernel/extable.c6
-rw-r--r--kernel/fork.c7
-rw-r--r--kernel/hrtimer.c29
-rw-r--r--kernel/kexec.c161
-rw-r--r--kernel/kmod.c98
-rw-r--r--kernel/kprobes.c19
-rw-r--r--kernel/kthread.c111
-rw-r--r--kernel/lockdep.c46
-rw-r--r--kernel/mutex.c151
-rw-r--r--kernel/panic.c6
-rw-r--r--kernel/pid.c11
-rw-r--r--kernel/pid_namespace.c5
-rw-r--r--kernel/posix-timers.c121
-rw-r--r--kernel/power/poweroff.c2
-rw-r--r--kernel/power/suspend.c22
-rw-r--r--kernel/printk.c97
-rw-r--r--kernel/ptrace.c80
-rw-r--r--kernel/range.c3
-rw-r--r--kernel/rcutree.c260
-rw-r--r--kernel/rcutree.h41
-rw-r--r--kernel/rcutree_plugin.h601
-rw-r--r--kernel/rcutree_trace.c2
-rw-r--r--kernel/relay.c14
-rw-r--r--kernel/resource.c198
-rw-r--r--kernel/rtmutex-tester.c5
-rw-r--r--kernel/sched/Makefile1
-rw-r--r--kernel/sched/clock.c26
-rw-r--r--kernel/sched/core.c322
-rw-r--r--kernel/sched/cpuacct.c296
-rw-r--r--kernel/sched/cpuacct.h17
-rw-r--r--kernel/sched/cputime.c216
-rw-r--r--kernel/sched/fair.c148
-rw-r--r--kernel/sched/features.h7
-rw-r--r--kernel/sched/idle_task.c16
-rw-r--r--kernel/sched/sched.h219
-rw-r--r--kernel/seccomp.c2
-rw-r--r--kernel/semaphore.c8
-rw-r--r--kernel/signal.c13
-rw-r--r--kernel/smp.c91
-rw-r--r--kernel/smpboot.c14
-rw-r--r--kernel/softirq.c6
-rw-r--r--kernel/sys.c238
-rw-r--r--kernel/sys_ni.c3
-rw-r--r--kernel/sysctl.c15
-rw-r--r--kernel/test_kprobes.c2
-rw-r--r--kernel/time.c11
-rw-r--r--kernel/time/ntp.c105
-rw-r--r--kernel/time/ntp_internal.h12
-rw-r--r--kernel/time/tick-broadcast.c239
-rw-r--r--kernel/time/tick-common.c2
-rw-r--r--kernel/time/tick-internal.h5
-rw-r--r--kernel/time/tick-sched.c4
-rw-r--r--kernel/time/timekeeping.c396
-rw-r--r--kernel/time/timer_list.c104
-rw-r--r--kernel/timer.c143
-rw-r--r--kernel/trace/Kconfig49
-rw-r--r--kernel/trace/blktrace.c30
-rw-r--r--kernel/trace/ftrace.c152
-rw-r--r--kernel/trace/ring_buffer.c500
-rw-r--r--kernel/trace/trace.c2209
-rw-r--r--kernel/trace/trace.h149
-rw-r--r--kernel/trace/trace_branch.c8
-rw-r--r--kernel/trace/trace_clock.c10
-rw-r--r--kernel/trace/trace_entries.h23
-rw-r--r--kernel/trace/trace_events.c1397
-rw-r--r--kernel/trace/trace_events_filter.c34
-rw-r--r--kernel/trace/trace_export.c4
-rw-r--r--kernel/trace/trace_functions.c207
-rw-r--r--kernel/trace/trace_functions_graph.c12
-rw-r--r--kernel/trace/trace_irqsoff.c85
-rw-r--r--kernel/trace/trace_kdb.c12
-rw-r--r--kernel/trace/trace_mmiotrace.c12
-rw-r--r--kernel/trace/trace_output.c119
-rw-r--r--kernel/trace/trace_output.h4
-rw-r--r--kernel/trace/trace_sched_switch.c8
-rw-r--r--kernel/trace/trace_sched_wakeup.c87
-rw-r--r--kernel/trace/trace_selftest.c51
-rw-r--r--kernel/trace/trace_stack.c78
-rw-r--r--kernel/trace/trace_stat.c2
-rw-r--r--kernel/trace/trace_syscalls.c90
-rw-r--r--kernel/trace/trace_uprobe.c203
-rw-r--r--kernel/tracepoint.c21
-rw-r--r--kernel/uid16.c55
-rw-r--r--kernel/user.c2
-rw-r--r--kernel/user_namespace.c33
-rw-r--r--kernel/watchdog.c5
-rw-r--r--kernel/workqueue.c2907
-rw-r--r--kernel/workqueue_internal.h19
-rw-r--r--lib/Kconfig3
-rw-r--r--lib/Kconfig.debug25
-rw-r--r--lib/Makefile7
-rw-r--r--lib/argv_split.c87
-rw-r--r--lib/decompress.c2
-rw-r--r--lib/div64.c19
-rw-r--r--lib/dump_stack.c11
-rw-r--r--lib/dynamic_debug.c49
-rw-r--r--lib/fault-inject.c2
-rw-r--r--lib/genalloc.c81
-rw-r--r--lib/idr.c27
-rw-r--r--lib/int_sqrt.c32
-rw-r--r--lib/kobject.c9
-rw-r--r--lib/list_sort.c2
-rw-r--r--lib/rbtree_test.c9
-rw-r--r--lib/show_mem.c3
-rw-r--r--lib/string_helpers.c133
-rw-r--r--lib/swiotlb.c19
-rw-r--r--lib/test-string_helpers.c103
-rw-r--r--lib/ucs2_string.c51
-rw-r--r--lib/usercopy.c (renamed from arch/sparc/lib/usercopy.c)4
-rw-r--r--lib/uuid.c8
-rw-r--r--lib/vsprintf.c18
-rw-r--r--mm/Kconfig8
-rw-r--r--mm/Makefile2
-rw-r--r--mm/bounce.c21
-rw-r--r--mm/cleancache.c265
-rw-r--r--mm/fadvise.c18
-rw-r--r--mm/filemap.c34
-rw-r--r--mm/fremap.c12
-rw-r--r--mm/frontswap.c156
-rw-r--r--mm/huge_memory.c77
-rw-r--r--mm/hugetlb.c55
-rw-r--r--mm/madvise.c31
-rw-r--r--mm/memblock.c12
-rw-r--r--mm/memcontrol.c338
-rw-r--r--mm/memory-failure.c4
-rw-r--r--mm/memory.c61
-rw-r--r--mm/memory_hotplug.c93
-rw-r--r--mm/migrate.c24
-rw-r--r--mm/mlock.c11
-rw-r--r--mm/mmap.c202
-rw-r--r--mm/nobootmem.c6
-rw-r--r--mm/nommu.c83
-rw-r--r--mm/page-writeback.c4
-rw-r--r--mm/page_alloc.c78
-rw-r--r--mm/page_io.c36
-rw-r--r--mm/readahead.c9
-rw-r--r--mm/rmap.c3
-rw-r--r--mm/shmem.c5
-rw-r--r--mm/slab.c8
-rw-r--r--mm/slub.c9
-rw-r--r--mm/sparse-vmemmap.c27
-rw-r--r--mm/sparse.c82
-rw-r--r--mm/swap.c11
-rw-r--r--mm/swap_state.c6
-rw-r--r--mm/swapfile.c19
-rw-r--r--mm/vmalloc.c218
-rw-r--r--mm/vmpressure.c374
-rw-r--r--mm/vmscan.c16
-rw-r--r--mm/vmstat.c6
-rw-r--r--net/802/garp.c4
-rw-r--r--net/802/mrp.c4
-rw-r--r--net/8021q/Kconfig2
-rw-r--r--net/8021q/vlan.c97
-rw-r--r--net/8021q/vlan.h58
-rw-r--r--net/8021q/vlan_core.c80
-rw-r--r--net/8021q/vlan_dev.c11
-rw-r--r--net/8021q/vlan_gvrp.c4
-rw-r--r--net/8021q/vlan_mvrp.c4
-rw-r--r--net/8021q/vlan_netlink.c32
-rw-r--r--net/Kconfig1
-rw-r--r--net/appletalk/ddp.c2
-rw-r--r--net/atm/common.c2
-rw-r--r--net/atm/lec.h2
-rw-r--r--net/ax25/af_ax25.c1
-rw-r--r--net/batman-adv/Kconfig14
-rw-r--r--net/batman-adv/Makefile3
-rw-r--r--net/batman-adv/bat_iv_ogm.c5
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c2
-rw-r--r--net/batman-adv/debugfs.c18
-rw-r--r--net/batman-adv/distributed-arp-table.c22
-rw-r--r--net/batman-adv/gateway_client.c2
-rw-r--r--net/batman-adv/hard-interface.c66
-rw-r--r--net/batman-adv/hard-interface.h13
-rw-r--r--net/batman-adv/main.c21
-rw-r--r--net/batman-adv/main.h17
-rw-r--r--net/batman-adv/network-coding.c1822
-rw-r--r--net/batman-adv/network-coding.h123
-rw-r--r--net/batman-adv/originator.c10
-rw-r--r--net/batman-adv/packet.h33
-rw-r--r--net/batman-adv/routing.c97
-rw-r--r--net/batman-adv/send.c5
-rw-r--r--net/batman-adv/soft-interface.c288
-rw-r--r--net/batman-adv/soft-interface.h3
-rw-r--r--net/batman-adv/sysfs.c22
-rw-r--r--net/batman-adv/translation-table.c31
-rw-r--r--net/batman-adv/types.h136
-rw-r--r--net/batman-adv/unicast.c6
-rw-r--r--net/batman-adv/vis.c8
-rw-r--r--net/bluetooth/a2mp.c6
-rw-r--r--net/bluetooth/af_bluetooth.c22
-rw-r--r--net/bluetooth/bnep/netdev.c2
-rw-r--r--net/bluetooth/bnep/sock.c4
-rw-r--r--net/bluetooth/cmtp/sock.c4
-rw-r--r--net/bluetooth/hci_conn.c42
-rw-r--r--net/bluetooth/hci_core.c901
-rw-r--r--net/bluetooth/hci_event.c781
-rw-r--r--net/bluetooth/hci_sock.c9
-rw-r--r--net/bluetooth/hci_sysfs.c21
-rw-r--r--net/bluetooth/hidp/core.c994
-rw-r--r--net/bluetooth/hidp/hidp.h67
-rw-r--r--net/bluetooth/hidp/sock.c26
-rw-r--r--net/bluetooth/l2cap_core.c134
-rw-r--r--net/bluetooth/l2cap_sock.c10
-rw-r--r--net/bluetooth/mgmt.c703
-rw-r--r--net/bluetooth/rfcomm/core.c167
-rw-r--r--net/bluetooth/rfcomm/sock.c4
-rw-r--r--net/bluetooth/sco.c53
-rw-r--r--net/bluetooth/smp.c2
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/bridge/br_fdb.c30
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/bridge/br_mdb.c4
-rw-r--r--net/bridge/br_multicast.c2
-rw-r--r--net/bridge/br_netfilter.c3
-rw-r--r--net/bridge/br_netlink.c21
-rw-r--r--net/bridge/br_private.h1
-rw-r--r--net/bridge/br_stp.c9
-rw-r--r--net/bridge/br_stp_if.c1
-rw-r--r--net/bridge/br_vlan.c20
-rw-r--r--net/bridge/netfilter/ebt_log.c44
-rw-r--r--net/bridge/netfilter/ebt_nflog.c5
-rw-r--r--net/bridge/netfilter/ebt_ulog.c132
-rw-r--r--net/bridge/netfilter/ebtable_broute.c4
-rw-r--r--net/bridge/netfilter/ebtables.c2
-rw-r--r--net/caif/caif_dev.c11
-rw-r--r--net/caif/caif_socket.c26
-rw-r--r--net/caif/caif_usb.c6
-rw-r--r--net/caif/cfcnfg.c21
-rw-r--r--net/caif/cfctrl.c16
-rw-r--r--net/caif/cfdbgl.c2
-rw-r--r--net/caif/cfdgml.c2
-rw-r--r--net/caif/cffrml.c6
-rw-r--r--net/caif/cfmuxl.c6
-rw-r--r--net/caif/cfpkt_skbuff.c10
-rw-r--r--net/caif/cfrfml.c6
-rw-r--r--net/caif/cfserl.c6
-rw-r--r--net/caif/cfsrvl.c15
-rw-r--r--net/caif/cfutill.c2
-rw-r--r--net/caif/cfveil.c2
-rw-r--r--net/caif/cfvidl.c2
-rw-r--r--net/caif/chnl_net.c10
-rw-r--r--net/can/af_can.c30
-rw-r--r--net/can/gw.c11
-rw-r--r--net/can/raw.c5
-rw-r--r--net/core/datagram.c26
-rw-r--r--net/core/dev.c131
-rw-r--r--net/core/dev_addr_lists.c210
-rw-r--r--net/core/dst.c9
-rw-r--r--net/core/ethtool.c29
-rw-r--r--net/core/fib_rules.c4
-rw-r--r--net/core/filter.c5
-rw-r--r--net/core/flow.c44
-rw-r--r--net/core/flow_dissector.c68
-rw-r--r--net/core/neighbour.c55
-rw-r--r--net/core/net-procfs.c2
-rw-r--r--net/core/netpoll.c22
-rw-r--r--net/core/pktgen.c42
-rw-r--r--net/core/rtnetlink.c186
-rw-r--r--net/core/scm.c24
-rw-r--r--net/core/secure_seq.c4
-rw-r--r--net/core/skbuff.c93
-rw-r--r--net/core/sock.c22
-rw-r--r--net/core/sock_diag.c33
-rw-r--r--net/core/utils.c5
-rw-r--r--net/dcb/dcbevent.c1
-rw-r--r--net/dcb/dcbnl.c2
-rw-r--r--net/dccp/ipv4.c5
-rw-r--r--net/dccp/ipv6.c5
-rw-r--r--net/decnet/dn_dev.c4
-rw-r--r--net/decnet/dn_fib.c203
-rw-r--r--net/decnet/dn_route.c43
-rw-r--r--net/decnet/dn_table.c45
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c12
-rw-r--r--net/dsa/dsa.c233
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/ieee802154/6lowpan.c142
-rw-r--r--net/ieee802154/6lowpan.h7
-rw-r--r--net/ieee802154/dgram.c10
-rw-r--r--net/ieee802154/netlink.c8
-rw-r--r--net/ieee802154/nl-mac.c25
-rw-r--r--net/ipv4/Kconfig7
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/af_inet.c15
-rw-r--r--net/ipv4/arp.c27
-rw-r--r--net/ipv4/devinet.c149
-rw-r--r--net/ipv4/esp4.c6
-rw-r--r--net/ipv4/fib_frontend.c10
-rw-r--r--net/ipv4/gre.c5
-rw-r--r--net/ipv4/icmp.c4
-rw-r--r--net/ipv4/inet_connection_sock.c2
-rw-r--r--net/ipv4/inet_diag.c10
-rw-r--r--net/ipv4/inet_fragment.c84
-rw-r--r--net/ipv4/inet_lro.c5
-rw-r--r--net/ipv4/ip_fragment.c45
-rw-r--r--net/ipv4/ip_gre.c1517
-rw-r--r--net/ipv4/ip_input.c4
-rw-r--r--net/ipv4/ip_output.c3
-rw-r--r--net/ipv4/ip_tunnel.c1035
-rw-r--r--net/ipv4/ip_vti.c42
-rw-r--r--net/ipv4/ipcomp.c1
-rw-r--r--net/ipv4/ipconfig.c13
-rw-r--r--net/ipv4/ipip.c748
-rw-r--r--net/ipv4/ipmr.c12
-rw-r--r--net/ipv4/netfilter.c15
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv4/netfilter/arp_tables.c1
-rw-r--r--net/ipv4/netfilter/arptable_filter.c4
-rw-r--r--net/ipv4/netfilter/ip_tables.c10
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c134
-rw-r--r--net/ipv4/netfilter/ipt_rpfilter.c8
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c9
-rw-r--r--net/ipv4/netfilter/iptable_nat.c23
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c1
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c1
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c9
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c1
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c2
-rw-r--r--net/ipv4/ping.c5
-rw-r--r--net/ipv4/proc.c13
-rw-r--r--net/ipv4/route.c2
-rw-r--r--net/ipv4/syncookies.c7
-rw-r--r--net/ipv4/sysctl_net_ipv4.c18
-rw-r--r--net/ipv4/tcp.c287
-rw-r--r--net/ipv4/tcp_input.c669
-rw-r--r--net/ipv4/tcp_ipv4.c123
-rw-r--r--net/ipv4/tcp_memcontrol.c3
-rw-r--r--net/ipv4/tcp_minisocks.c51
-rw-r--r--net/ipv4/tcp_output.c386
-rw-r--r--net/ipv4/tcp_timer.c21
-rw-r--r--net/ipv4/tcp_westwood.c2
-rw-r--r--net/ipv4/udp.c132
-rw-r--r--net/ipv4/udp_diag.c10
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c8
-rw-r--r--net/ipv6/Kconfig2
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c259
-rw-r--r--net/ipv6/addrconf_core.c19
-rw-r--r--net/ipv6/addrlabel.c12
-rw-r--r--net/ipv6/af_inet6.c7
-rw-r--r--net/ipv6/datagram.c20
-rw-r--r--net/ipv6/icmp.c41
-rw-r--r--net/ipv6/inet6_connection_sock.c10
-rw-r--r--net/ipv6/ip6_flowlabel.c11
-rw-r--r--net/ipv6/ip6_gre.c62
-rw-r--r--net/ipv6/ip6_icmp.c47
-rw-r--r--net/ipv6/ip6_input.c12
-rw-r--r--net/ipv6/ip6_offload.c4
-rw-r--r--net/ipv6/ip6_output.c7
-rw-r--r--net/ipv6/ip6_tunnel.c16
-rw-r--r--net/ipv6/ip6mr.c10
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/netfilter.c12
-rw-r--r--net/ipv6/netfilter/Kconfig2
-rw-r--r--net/ipv6/netfilter/ip6_tables.c4
-rw-r--r--net/ipv6/netfilter/ip6t_NPT.c13
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c2
-rw-r--r--net/ipv6/netfilter/ip6t_rpfilter.c8
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c9
-rw-r--r--net/ipv6/netfilter/ip6table_nat.c23
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c8
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c7
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c22
-rw-r--r--net/ipv6/proc.c4
-rw-r--r--net/ipv6/raw.c9
-rw-r--r--net/ipv6/reassembly.c35
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/ipv6/sit.c41
-rw-r--r--net/ipv6/syncookies.c3
-rw-r--r--net/ipv6/tcp_ipv6.c76
-rw-r--r--net/ipv6/udp.c34
-rw-r--r--net/ipv6/udp_offload.c8
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c7
-rw-r--r--net/irda/af_irda.c7
-rw-r--r--net/irda/ircomm/ircomm_core.c2
-rw-r--r--net/irda/ircomm/ircomm_tty.c2
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c6
-rw-r--r--net/irda/iriap.c3
-rw-r--r--net/irda/irlmp.c12
-rw-r--r--net/iucv/af_iucv.c39
-rw-r--r--net/key/af_key.c1
-rw-r--r--net/l2tp/l2tp_core.c2
-rw-r--r--net/l2tp/l2tp_ip6.c1
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/mac80211/cfg.c241
-rw-r--r--net/mac80211/chan.c71
-rw-r--r--net/mac80211/debugfs_key.c10
-rw-r--r--net/mac80211/debugfs_netdev.c33
-rw-r--r--net/mac80211/debugfs_sta.c33
-rw-r--r--net/mac80211/driver-ops.h67
-rw-r--r--net/mac80211/ht.c52
-rw-r--r--net/mac80211/ibss.c175
-rw-r--r--net/mac80211/ieee80211_i.h90
-rw-r--r--net/mac80211/iface.c212
-rw-r--r--net/mac80211/key.c208
-rw-r--r--net/mac80211/key.h18
-rw-r--r--net/mac80211/main.c159
-rw-r--r--net/mac80211/mesh.c73
-rw-r--r--net/mac80211/mesh.h15
-rw-r--r--net/mac80211/mesh_hwmp.c28
-rw-r--r--net/mac80211/mesh_pathtbl.c56
-rw-r--r--net/mac80211/mesh_plink.c43
-rw-r--r--net/mac80211/mlme.c584
-rw-r--r--net/mac80211/offchannel.c39
-rw-r--r--net/mac80211/pm.c132
-rw-r--r--net/mac80211/rate.c324
-rw-r--r--net/mac80211/rc80211_minstrel.c342
-rw-r--r--net/mac80211/rc80211_minstrel.h34
-rw-r--r--net/mac80211/rc80211_minstrel_debugfs.c16
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c273
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h8
-rw-r--r--net/mac80211/rx.c99
-rw-r--r--net/mac80211/scan.c20
-rw-r--r--net/mac80211/sta_info.c48
-rw-r--r--net/mac80211/sta_info.h11
-rw-r--r--net/mac80211/trace.h97
-rw-r--r--net/mac80211/tx.c163
-rw-r--r--net/mac80211/util.c224
-rw-r--r--net/mac80211/vht.c212
-rw-r--r--net/mac802154/mac802154.h5
-rw-r--r--net/mac802154/mac_cmd.c1
-rw-r--r--net/mac802154/mib.c21
-rw-r--r--net/mac802154/tx.c29
-rw-r--r--net/mac802154/wpan.c4
-rw-r--r--net/netfilter/core.c30
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_gen.h277
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c411
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c620
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c414
-rw-r--r--net/netfilter/ipset/ip_set_core.c41
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h1100
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c344
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c362
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c368
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c451
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c384
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c460
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c438
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c622
-rw-r--r--net/netfilter/ipvs/ip_vs_app.c31
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c312
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c88
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c702
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c86
-rw-r--r--net/netfilter/ipvs/ip_vs_est.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_ftp.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c115
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c190
-rw-r--r--net/netfilter/ipvs/ip_vs_lc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_nq.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_pe.c55
-rw-r--r--net/netfilter/ipvs/ip_vs_pe_sip.c10
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c38
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c40
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_udp.c33
-rw-r--r--net/netfilter/ipvs/ip_vs_rr.c64
-rw-r--r--net/netfilter/ipvs/ip_vs_sched.c63
-rw-r--r--net/netfilter/ipvs/ip_vs_sed.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c86
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c56
-rw-r--r--net/netfilter/ipvs/ip_vs_wlc.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_wrr.c176
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c1050
-rw-r--r--net/netfilter/nf_conntrack_amanda.c1
-rw-r--r--net/netfilter/nf_conntrack_core.c60
-rw-r--r--net/netfilter/nf_conntrack_ecache.c8
-rw-r--r--net/netfilter/nf_conntrack_expect.c9
-rw-r--r--net/netfilter/nf_conntrack_ftp.c1
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c1
-rw-r--r--net/netfilter/nf_conntrack_helper.c3
-rw-r--r--net/netfilter/nf_conntrack_irc.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c100
-rw-r--r--net/netfilter/nf_conntrack_pptp.c2
-rw-r--r--net/netfilter/nf_conntrack_proto.c1
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c9
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c1
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c3
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c20
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c7
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c8
-rw-r--r--net/netfilter/nf_conntrack_sip.c6
-rw-r--r--net/netfilter/nf_conntrack_standalone.c18
-rw-r--r--net/netfilter/nf_conntrack_tftp.c2
-rw-r--r--net/netfilter/nf_log.c206
-rw-r--r--net/netfilter/nf_nat_amanda.c1
-rw-r--r--net/netfilter/nf_nat_core.c50
-rw-r--r--net/netfilter/nf_nat_helper.c1
-rw-r--r--net/netfilter/nf_nat_proto_sctp.c5
-rw-r--r--net/netfilter/nf_queue.c148
-rw-r--r--net/netfilter/nfnetlink.c27
-rw-r--r--net/netfilter/nfnetlink_acct.c2
-rw-r--r--net/netfilter/nfnetlink_log.c199
-rw-r--r--net/netfilter/nfnetlink_queue_core.c439
-rw-r--r--net/netfilter/x_tables.c1
-rw-r--r--net/netfilter/xt_LOG.c52
-rw-r--r--net/netfilter/xt_NFQUEUE.c63
-rw-r--r--net/netfilter/xt_TCPMSS.c1
-rw-r--r--net/netfilter/xt_conntrack.c1
-rw-r--r--net/netfilter/xt_hashlimit.c1
-rw-r--r--net/netfilter/xt_limit.c1
-rw-r--r--net/netfilter/xt_osf.c6
-rw-r--r--net/netfilter/xt_set.c94
-rw-r--r--net/netlink/Kconfig19
-rw-r--r--net/netlink/Makefile3
-rw-r--r--net/netlink/af_netlink.c900
-rw-r--r--net/netlink/af_netlink.h82
-rw-r--r--net/netlink/diag.c227
-rw-r--r--net/netlink/genetlink.c119
-rw-r--r--net/netrom/af_netrom.c3
-rw-r--r--net/nfc/Kconfig2
-rw-r--r--net/nfc/Makefile6
-rw-r--r--net/nfc/core.c43
-rw-r--r--net/nfc/llcp.h (renamed from net/nfc/llcp/llcp.h)39
-rw-r--r--net/nfc/llcp/Kconfig7
-rw-r--r--net/nfc/llcp_commands.c (renamed from net/nfc/llcp/commands.c)229
-rw-r--r--net/nfc/llcp_core.c (renamed from net/nfc/llcp/llcp.c)249
-rw-r--r--net/nfc/llcp_sock.c (renamed from net/nfc/llcp/sock.c)180
-rw-r--r--net/nfc/netlink.c175
-rw-r--r--net/nfc/nfc.h60
-rw-r--r--net/openvswitch/actions.c6
-rw-r--r--net/openvswitch/datapath.c451
-rw-r--r--net/openvswitch/datapath.h72
-rw-r--r--net/openvswitch/dp_notify.c82
-rw-r--r--net/openvswitch/flow.c10
-rw-r--r--net/openvswitch/flow.h21
-rw-r--r--net/openvswitch/vport-internal_dev.c22
-rw-r--r--net/openvswitch/vport-netdev.c15
-rw-r--r--net/openvswitch/vport-netdev.h1
-rw-r--r--net/openvswitch/vport.c58
-rw-r--r--net/openvswitch/vport.h21
-rw-r--r--net/packet/af_packet.c302
-rw-r--r--net/packet/diag.c27
-rw-r--r--net/packet/internal.h10
-rw-r--r--net/phonet/pn_netlink.c4
-rw-r--r--net/rfkill/core.c4
-rw-r--r--net/rfkill/rfkill-gpio.c7
-rw-r--r--net/rfkill/rfkill-regulator.c2
-rw-r--r--net/rose/af_rose.c1
-rw-r--r--net/sched/act_api.c2
-rw-r--r--net/sched/act_csum.c39
-rw-r--r--net/sched/act_ipt.c33
-rw-r--r--net/sched/cls_api.c14
-rw-r--r--net/sched/cls_flow.c2
-rw-r--r--net/sched/cls_fw.c2
-rw-r--r--net/sched/em_ipset.c2
-rw-r--r--net/sched/sch_api.c44
-rw-r--r--net/sched/sch_cbq.c5
-rw-r--r--net/sched/sch_choke.c2
-rw-r--r--net/sched/sch_fq_codel.c2
-rw-r--r--net/sched/sch_generic.c2
-rw-r--r--net/sched/sch_htb.c31
-rw-r--r--net/sctp/associola.c28
-rw-r--r--net/sctp/bind_addr.c7
-rw-r--r--net/sctp/endpointola.c14
-rw-r--r--net/sctp/inqueue.c7
-rw-r--r--net/sctp/output.c5
-rw-r--r--net/sctp/outqueue.c11
-rw-r--r--net/sctp/probe.c2
-rw-r--r--net/sctp/proc.c12
-rw-r--r--net/sctp/protocol.c2
-rw-r--r--net/sctp/socket.c8
-rw-r--r--net/sctp/ssnmap.c23
-rw-r--r--net/sctp/transport.c1
-rw-r--r--net/sctp/ulpqueue.c3
-rw-r--r--net/socket.c23
-rw-r--r--net/sunrpc/Kconfig2
-rw-r--r--net/sunrpc/auth.c75
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c3
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c6
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c4
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c119
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c4
-rw-r--r--net/sunrpc/cache.c1
-rw-r--r--net/sunrpc/clnt.c54
-rw-r--r--net/sunrpc/xprt.c61
-rw-r--r--net/sunrpc/xprtsock.c14
-rw-r--r--net/tipc/Kconfig7
-rw-r--r--net/tipc/Makefile2
-rw-r--r--net/tipc/bcast.c4
-rw-r--r--net/tipc/bearer.c7
-rw-r--r--net/tipc/bearer.h16
-rw-r--r--net/tipc/core.c12
-rw-r--r--net/tipc/discover.c2
-rw-r--r--net/tipc/eth_media.c39
-rw-r--r--net/tipc/ib_media.c387
-rw-r--r--net/tipc/netlink.c6
-rw-r--r--net/tipc/socket.c7
-rw-r--r--net/unix/af_unix.c51
-rw-r--r--net/unix/garbage.c12
-rw-r--r--net/vmw_vsock/af_vsock.c12
-rw-r--r--net/vmw_vsock/vmci_transport.c50
-rw-r--r--net/vmw_vsock/vmci_transport.h3
-rw-r--r--net/vmw_vsock/vsock_addr.c10
-rw-r--r--net/vmw_vsock/vsock_addr.h2
-rw-r--r--net/wireless/ap.c62
-rw-r--r--net/wireless/core.c141
-rw-r--r--net/wireless/core.h28
-rw-r--r--net/wireless/mesh.c15
-rw-r--r--net/wireless/mlme.c235
-rw-r--r--net/wireless/nl80211.c2188
-rw-r--r--net/wireless/nl80211.h68
-rw-r--r--net/wireless/rdev-ops.h44
-rw-r--r--net/wireless/reg.c8
-rw-r--r--net/wireless/scan.c24
-rw-r--r--net/wireless/sme.c36
-rw-r--r--net/wireless/sysfs.c25
-rw-r--r--net/wireless/trace.h86
-rw-r--r--net/wireless/util.c30
-rw-r--r--net/wireless/wext-sme.c6
-rw-r--r--net/xfrm/xfrm_policy.c23
-rw-r--r--net/xfrm/xfrm_replay.c66
-rw-r--r--net/xfrm/xfrm_state.c1
-rw-r--r--net/xfrm/xfrm_user.c17
-rw-r--r--samples/hidraw/hid-example.c3
-rwxr-xr-xscripts/checkpatch.pl34
-rwxr-xr-xscripts/decodecode8
-rwxr-xr-xscripts/get_maintainer.pl2
-rw-r--r--scripts/kconfig/menu.c27
-rw-r--r--scripts/kconfig/streamline_config.pl26
-rw-r--r--scripts/mod/devicetable-offsets.c3
-rw-r--r--scripts/mod/file2alias.c12
-rw-r--r--security/capability.c9
-rw-r--r--security/device_cgroup.c267
-rw-r--r--security/integrity/ima/ima_main.c14
-rw-r--r--security/keys/request_key.c13
-rw-r--r--security/security.c9
-rw-r--r--security/selinux/hooks.c50
-rw-r--r--security/selinux/netlink.c3
-rw-r--r--security/smack/smack.h5
-rw-r--r--security/smack/smack_access.c2
-rw-r--r--security/smack/smack_lsm.c4
-rw-r--r--security/smack/smackfs.c254
-rw-r--r--security/tomoyo/tomoyo.c5
-rw-r--r--security/yama/yama_lsm.c4
-rw-r--r--sound/core/pcm_native.c12
-rw-r--r--sound/i2c/other/tea575x-tuner.c6
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/hda_generic.c2
-rw-r--r--sound/pci/hda/hda_intel.c6
-rw-r--r--sound/pci/hda/patch_hdmi.c2
-rw-r--r--sound/pci/hda/patch_realtek.c4
-rw-r--r--sound/pci/mixart/mixart.c2
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c15
-rw-r--r--sound/pcmcia/vx/vxpocket.c14
-rw-r--r--sound/soc/codecs/arizona.c33
-rw-r--r--sound/soc/codecs/arizona.h3
-rw-r--r--[-rwxr-xr-x]sound/soc/codecs/max98090.c0
-rw-r--r--[-rwxr-xr-x]sound/soc/codecs/max98090.h0
-rw-r--r--sound/soc/codecs/si476x.c1
-rw-r--r--sound/soc/codecs/wm5102.c10
-rw-r--r--sound/soc/codecs/wm5110.c8
-rw-r--r--sound/soc/codecs/wm8903.c2
-rw-r--r--sound/soc/codecs/wm8974.c2
-rw-r--r--sound/soc/codecs/wm_adsp.c5
-rw-r--r--sound/soc/fsl/imx-ssi.c5
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c2
-rw-r--r--sound/soc/samsung/i2s.c17
-rw-r--r--sound/soc/sh/dma-sh7760.c4
-rw-r--r--sound/soc/soc-compress.c14
-rw-r--r--sound/soc/soc-core.c10
-rw-r--r--sound/soc/soc-dapm.c14
-rw-r--r--sound/soc/spear/spear_pcm.c12
-rw-r--r--sound/soc/tegra/tegra_pcm.c24
-rw-r--r--sound/soc/ux500/Kconfig4
-rw-r--r--sound/usb/clock.c45
-rw-r--r--sound/usb/mixer_quirks.c4
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--tools/Makefile23
-rw-r--r--tools/hv/hv_kvp_daemon.c16
-rw-r--r--tools/hv/hv_vss_daemon.c249
-rw-r--r--tools/lib/lk/Makefile35
-rw-r--r--tools/lib/lk/debugfs.c (renamed from tools/perf/util/debugfs.c)49
-rw-r--r--tools/lib/lk/debugfs.h29
-rw-r--r--tools/net/Makefile15
-rw-r--r--tools/net/bpf_jit_disasm.c199
-rw-r--r--tools/perf/Documentation/perf-annotate.txt3
-rw-r--r--tools/perf/Documentation/perf-mem.txt48
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt6
-rw-r--r--tools/perf/Documentation/perf-stat.txt12
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile61
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c5
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/sparc/util/dwarf-regs.c2
-rw-r--r--tools/perf/arch/x86/util/dwarf-regs.c2
-rw-r--r--tools/perf/builtin-annotate.c25
-rw-r--r--tools/perf/builtin-diff.c7
-rw-r--r--tools/perf/builtin-kvm.c2
-rw-r--r--tools/perf/builtin-mem.c242
-rw-r--r--tools/perf/builtin-probe.c2
-rw-r--r--tools/perf/builtin-record.c15
-rw-r--r--tools/perf/builtin-report.c150
-rw-r--r--tools/perf/builtin-sched.c1
-rw-r--r--tools/perf/builtin-stat.c398
-rw-r--r--tools/perf/builtin-top.c9
-rw-r--r--tools/perf/builtin-trace.c28
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt15
-rw-r--r--tools/perf/config/feature-tests.mak12
-rw-r--r--tools/perf/perf.c12
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/tests/attr.c11
-rw-r--r--tools/perf/tests/attr.py5
-rw-r--r--tools/perf/tests/attr/base-record1
-rw-r--r--tools/perf/tests/attr/base-stat1
-rw-r--r--tools/perf/tests/attr/test-record-C013
-rw-r--r--tools/perf/tests/attr/test-stat-C09
-rw-r--r--tools/perf/tests/bp_signal.c186
-rw-r--r--tools/perf/tests/bp_signal_overflow.c126
-rw-r--r--tools/perf/tests/builtin-test.c16
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c4
-rw-r--r--tools/perf/tests/hists_link.c6
-rw-r--r--tools/perf/tests/mmap-basic.c4
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c10
-rw-r--r--tools/perf/tests/parse-events.c6
-rw-r--r--tools/perf/tests/perf-record.c9
-rw-r--r--tools/perf/tests/sw-clock.c119
-rw-r--r--tools/perf/tests/task-exit.c123
-rw-r--r--tools/perf/tests/tests.h4
-rw-r--r--tools/perf/ui/browser.c9
-rw-r--r--tools/perf/ui/browser.h1
-rw-r--r--tools/perf/ui/browsers/annotate.c158
-rw-r--r--tools/perf/ui/browsers/hists.c7
-rw-r--r--tools/perf/ui/browsers/map.c60
-rw-r--r--tools/perf/ui/browsers/scripts.c1
-rw-r--r--tools/perf/ui/gtk/annotate.c26
-rw-r--r--tools/perf/ui/gtk/hists.c7
-rw-r--r--tools/perf/ui/hist.c7
-rw-r--r--tools/perf/ui/tui/setup.c21
-rw-r--r--tools/perf/ui/ui.h2
-rw-r--r--tools/perf/util/annotate.c262
-rw-r--r--tools/perf/util/annotate.h51
-rw-r--r--tools/perf/util/cpumap.c86
-rw-r--r--tools/perf/util/cpumap.h12
-rw-r--r--tools/perf/util/debugfs.h12
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c73
-rw-r--r--tools/perf/util/evlist.h9
-rw-r--r--tools/perf/util/evsel.c32
-rw-r--r--tools/perf/util/evsel.h25
-rw-r--r--tools/perf/util/header.c15
-rw-r--r--tools/perf/util/hist.c110
-rw-r--r--tools/perf/util/hist.h28
-rw-r--r--tools/perf/util/machine.c64
-rw-r--r--tools/perf/util/machine.h4
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/session.c20
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/setup.py3
-rw-r--r--tools/perf/util/sort.c414
-rw-r--r--tools/perf/util/sort.h12
-rw-r--r--tools/perf/util/symbol-elf.c9
-rw-r--r--tools/perf/util/symbol.c1
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread_map.h5
-rw-r--r--tools/perf/util/trace-event-info.c380
-rw-r--r--tools/perf/util/trace-event-parse.c37
-rw-r--r--tools/perf/util/trace-event-read.c473
-rw-r--r--tools/perf/util/trace-event.h6
-rw-r--r--tools/perf/util/util.c27
-rw-r--r--tools/perf/util/util.h9
-rw-r--r--tools/power/cpupower/debug/i386/intel_gsic.c2
-rw-r--r--tools/power/x86/turbostat/turbostat.c5
-rw-r--r--tools/scripts/Makefile.include6
-rwxr-xr-xtools/testing/ktest/ktest.pl14
-rw-r--r--tools/testing/selftests/Makefile9
-rw-r--r--tools/testing/selftests/net/.gitignore3
-rw-r--r--tools/testing/selftests/net/Makefile19
-rw-r--r--tools/testing/selftests/net/psock_fanout.c312
-rw-r--r--tools/testing/selftests/net/psock_lib.h127
-rw-r--r--tools/testing/selftests/net/psock_tpacket.c824
-rw-r--r--tools/testing/selftests/net/run_afpackettests26
-rw-r--r--tools/testing/selftests/net/run_netsocktests12
-rw-r--r--tools/testing/selftests/net/socket.c92
-rw-r--r--tools/testing/selftests/ptrace/Makefile10
-rw-r--r--tools/testing/selftests/ptrace/peeksiginfo.c214
-rw-r--r--tools/testing/selftests/soft-dirty/Makefile10
-rw-r--r--tools/testing/selftests/soft-dirty/soft-dirty.c114
-rw-r--r--tools/vm/Makefile17
-rw-r--r--tools/vm/page-types.c85
-rw-r--r--virt/kvm/kvm_main.c47
6080 files changed, 316219 insertions, 200566 deletions
diff --git a/CREDITS b/CREDITS
index afaa7cec6ea5..206d0fcf07a5 100644
--- a/CREDITS
+++ b/CREDITS
@@ -761,6 +761,10 @@ S: Northampton
S: NN1 3QT
S: United Kingdom
+N: Massimo Dal Zotto
+E: dz@debian.org
+D: i8k Dell laptop SMM driver
+
N: Uwe Dannowski
E: Uwe.Dannowski@ira.uka.de
W: http://i30www.ira.uka.de/~dannowsk/
diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei
new file mode 100644
index 000000000000..2066f0bbd453
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-mei
@@ -0,0 +1,7 @@
+What: /sys/bus/mei/devices/.../modalias
+Date: March 2013
+KernelVersion: 3.10
+Contact: Samuel Ortiz <sameo@linux.intel.com>
+ linux-mei@linux.intel.com
+Description: Stores the same MODALIAS value emitted by uevent
+ Format: mei:<mei device name>
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index c8baaf53594a..f093e59cbe5f 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -32,7 +32,7 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
- If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+ If CONFIG_PM_RUNTIME is enabled then this file
is present. When read, it returns the total time (in msec)
that the USB device has been connected to the machine. This
file is read-only.
@@ -45,7 +45,7 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
- If CONFIG_PM and CONFIG_USB_SUSPEND are enabled, then this file
+ If CONFIG_PM_RUNTIME is enabled then this file
is present. When read, it returns the total time (in msec)
that the USB device has been active, i.e. not in a suspended
state. This file is read-only.
@@ -187,7 +187,7 @@ What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
Date: September 2011
Contact: Andiry Xu <andiry.xu@amd.com>
Description:
- If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
+ If CONFIG_PM_RUNTIME is set and a USB 2.0 lpm-capable device
is plugged in to a xHCI host which support link PM, it will
perform a LPM test; if the test is passed and host supports
USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
diff --git a/Documentation/ABI/testing/sysfs-class-net-mesh b/Documentation/ABI/testing/sysfs-class-net-mesh
index bc41da61608d..bdcd8b4e38f2 100644
--- a/Documentation/ABI/testing/sysfs-class-net-mesh
+++ b/Documentation/ABI/testing/sysfs-class-net-mesh
@@ -67,6 +67,14 @@ Description:
Defines the penalty which will be applied to an
originator message's tq-field on every hop.
+What: /sys/class/net/<mesh_iface>/mesh/network_coding
+Date: Nov 2012
+Contact: Martin Hundeboll <martin@hundeboll.net>
+Description:
+ Controls whether Network Coding (using some magic
+ to send fewer wifi packets but still the same
+ content) is enabled or not.
+
What: /sys/class/net/<mesh_iface>/mesh/orig_interval
Date: May 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
diff --git a/Documentation/ABI/testing/sysfs-devices-lpss_ltr b/Documentation/ABI/testing/sysfs-devices-lpss_ltr
new file mode 100644
index 000000000000..ea9298d9bbaf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-lpss_ltr
@@ -0,0 +1,44 @@
+What: /sys/devices/.../lpss_ltr/
+Date: March 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../lpss_ltr/ directory is only present for
+ devices included into the Intel Lynxpoint Low Power Subsystem
+ (LPSS). If present, it contains attributes containing the LTR
+ mode and the values of LTR registers of the device.
+
+What: /sys/devices/.../lpss_ltr/ltr_mode
+Date: March 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../lpss_ltr/ltr_mode attribute contains an
+ integer number (0 or 1) indicating whether or not the devices'
+ LTR functionality is working in the software mode (1).
+
+ This attribute is read-only. If the device's runtime PM status
+ is not "active", attempts to read from this attribute cause
+ -EAGAIN to be returned.
+
+What: /sys/devices/.../lpss_ltr/auto_ltr
+Date: March 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../lpss_ltr/auto_ltr attribute contains the
+ current value of the device's AUTO_LTR register (raw)
+ represented as an 8-digit hexadecimal number.
+
+ This attribute is read-only. If the device's runtime PM status
+ is not "active", attempts to read from this attribute cause
+ -EAGAIN to be returned.
+
+What: /sys/devices/.../lpss_ltr/sw_ltr
+Date: March 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../lpss_ltr/auto_ltr attribute contains the
+ current value of the device's SW_LTR register (raw) represented
+ as an 8-digit hexadecimal number.
+
+ This attribute is read-only. If the device's runtime PM status
+ is not "active", attempts to read from this attribute cause
+ -EAGAIN to be returned.
diff --git a/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup
new file mode 100644
index 000000000000..e0588feeb6e1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-power_resources_wakeup
@@ -0,0 +1,13 @@
+What: /sys/devices/.../power_resources_wakeup/
+Date: April 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../power_resources_wakeup/ directory is only
+ present for device objects representing ACPI device nodes that
+ require ACPI power resources for wakeup signaling.
+
+ If present, it contains symbolic links to device directories
+ representing ACPI power resources that need to be turned on for
+ the given device node to be able to signal wakeup. The names of
+ the links are the same as the names of the directories they
+ point to.
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 9c978dcae07d..2447698aed41 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -173,3 +173,15 @@ Description: Processor frequency boosting control
Boosting allows the CPU and the firmware to run at a frequency
beyound it's nominal limit.
More details can be found in Documentation/cpu-freq/boost.txt
+
+
+What: /sys/devices/system/cpu/cpu#/crash_notes
+ /sys/devices/system/cpu/cpu#/crash_notes_size
+Date: April 2013
+Contact: kexec@lists.infradead.org
+Description: address and size of the percpu note.
+
+ crash_notes: the physical address of the memory that holds the
+ note of cpu#.
+
+ crash_notes_size: size of the note of cpu#.
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
index 9eca5a182e64..c601d0f2ac46 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-isku
@@ -101,7 +101,8 @@ 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.
+ 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
@@ -141,3 +142,12 @@ Description: When written, this file lets one trigger easyshift functionality
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-konepure b/Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure
new file mode 100644
index 000000000000..41a9b7fbfc79
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-konepure
@@ -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
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index dd930c8db41f..ce9bee98b43b 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -18,6 +18,32 @@ Description:
yoffset: The number of pixels between the top of the screen
and the top edge of the image.
+What: /sys/firmware/acpi/hotplug/
+Date: February 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ There are separate hotplug profiles for different classes of
+ devices supported by ACPI, such as containers, memory modules,
+ processors, PCI root bridges etc. A hotplug profile for a given
+ class of devices is a collection of settings defining the way
+ that class of devices will be handled by the ACPI core hotplug
+ code. Those profiles are represented in sysfs as subdirectories
+ of /sys/firmware/acpi/hotplug/.
+
+ The following setting is available to user space for each
+ hotplug profile:
+
+ enabled: If set, the ACPI core will handle notifications of
+ hotplug events associated with the given class of
+ devices and will allow those devices to be ejected with
+ the help of the _EJ0 control method. Unsetting it
+ effectively disables hotplug for the correspoinding
+ class of devices.
+
+ The value of the above attribute is an integer number: 1 (set)
+ or 0 (unset). Attempts to write any other values to it will
+ cause -EINVAL to be returned.
+
What: /sys/firmware/acpi/interrupts/
Date: February 2008
Contact: Len Brown <lenb@kernel.org>
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 284ced7a228f..0f6a3edcd44b 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -437,7 +437,7 @@
</section>
!Finclude/net/mac80211.h ieee80211_get_buffered_bc
!Finclude/net/mac80211.h ieee80211_beacon_get
-!Finclude/net/mac80211.h ieee80211_sta_eosp_irqsafe
+!Finclude/net/mac80211.h ieee80211_sta_eosp
!Finclude/net/mac80211.h ieee80211_frame_release_type
!Finclude/net/mac80211.h ieee80211_sta_ps_transition
!Finclude/net/mac80211.h ieee80211_sta_ps_transition_ni
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 7514dbf0a679..c36892c072da 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -227,7 +227,7 @@ X!Isound/sound_firmware.c
<chapter id="uart16x50">
<title>16x50 UART Driver</title>
!Edrivers/tty/serial/serial_core.c
-!Edrivers/tty/serial/8250/8250.c
+!Edrivers/tty/serial/8250/8250_core.c
</chapter>
<chapter id="fbdev">
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 4a5eaeed0b9e..a9b15e34c5b2 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -1,6 +1,6 @@
<section id="FE_GET_SET_PROPERTY">
<title><constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant></title>
-<para>This section describes the DVB version 5 extention of the DVB-API, also
+<para>This section describes the DVB version 5 extension of the DVB-API, also
called "S2API", as this API were added to provide support for DVB-S2. It was
designed to be able to replace the old frontend API. Yet, the DISEQC and
the capability ioctls weren't implemented yet via the new way.</para>
@@ -903,14 +903,12 @@ enum fe_interleaving {
<constant>svalue</constant> is for signed values of the measure (dB measures)
and <constant>uvalue</constant> is for unsigned values (counters, relative scale)</para></listitem>
<listitem><para><constant>scale</constant> - Scale for the value. It can be:</para>
- <section id = "fecap-scale-params">
- <itemizedlist mark='bullet'>
+ <itemizedlist mark='bullet' id="fecap-scale-params">
<listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition)</para></listitem>
<listitem><para><constant>FE_SCALE_DECIBEL</constant> - parameter is a signed value, measured in 1/1000 dB</para></listitem>
<listitem><para><constant>FE_SCALE_RELATIVE</constant> - parameter is a unsigned value, where 0 means 0% and 65535 means 100%.</para></listitem>
<listitem><para><constant>FE_SCALE_COUNTER</constant> - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time.</para></listitem>
</itemizedlist>
- </section>
</listitem>
</itemizedlist>
<section id="DTV-STAT-SIGNAL-STRENGTH">
@@ -918,9 +916,9 @@ enum fe_interleaving {
<para>Indicates the signal strength level at the analog part of the tuner or of the demod.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative.</listitem>
- <listitem><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_DECIBEL</constant> - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative.</para></listitem>
+ <listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-CNR">
@@ -928,9 +926,9 @@ enum fe_interleaving {
<para>Indicates the Signal to Noise ratio for the main carrier.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.0001 dB units.</listitem>
- <listitem><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_DECIBEL</constant> - Signal/Noise ratio is in 0.0001 dB units.</para></listitem>
+ <listitem><para><constant>FE_SCALE_RELATIVE</constant> - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-PRE-ERROR-BIT-COUNT">
@@ -943,8 +941,8 @@ enum fe_interleaving {
The frontend may reset it when a channel/transponder is tuned.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted before the inner coding.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted before the inner coding.</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-PRE-TOTAL-BIT-COUNT">
@@ -952,14 +950,14 @@ enum fe_interleaving {
<para>Measures the amount of bits received before the inner code block, during the same period as
<link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
<para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
- as the frontend may need to manually restart the measurement, loosing some data between each measurement interval.</para>
+ as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
<para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
The frontend may reset it when a channel/transponder is tuned.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
- <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link>.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
+ <link linkend="DTV-STAT-PRE-ERROR-BIT-COUNT"><constant>DTV_STAT_PRE_ERROR_BIT_COUNT</constant></link>.</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-POST-ERROR-BIT-COUNT">
@@ -972,8 +970,8 @@ enum fe_interleaving {
The frontend may reset it when a channel/transponder is tuned.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted after the inner coding.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error bits counted after the inner coding.</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-POST-TOTAL-BIT-COUNT">
@@ -981,14 +979,14 @@ enum fe_interleaving {
<para>Measures the amount of bits received after the inner coding, during the same period as
<link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link> measurement was taken.</para>
<para>It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream,
- as the frontend may need to manually restart the measurement, loosing some data between each measurement interval.</para>
+ as the frontend may need to manually restart the measurement, losing some data between each measurement interval.</para>
<para>This measurement is monotonically increased, as the frontend gets more bit count measurements.
The frontend may reset it when a channel/transponder is tuned.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
- <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link>.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of bits counted while measuring
+ <link linkend="DTV-STAT-POST-ERROR-BIT-COUNT"><constant>DTV_STAT_POST_ERROR_BIT_COUNT</constant></link>.</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-ERROR-BLOCK-COUNT">
@@ -998,8 +996,8 @@ enum fe_interleaving {
The frontend may reset it when a channel/transponder is tuned.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of error blocks counted after the outer coding.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of error blocks counted after the outer coding.</para></listitem>
</itemizedlist>
</section>
<section id="DTV-STAT-TOTAL-BLOCK-COUNT">
@@ -1011,9 +1009,9 @@ enum fe_interleaving {
by <link linkend="DTV-STAT-TOTAL-BLOCK-COUNT"><constant>DTV-STAT-TOTAL-BLOCK-COUNT</constant></link>.</para>
<para>Possible scales for this metric are:</para>
<itemizedlist mark='bullet'>
- <listitem><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</listitem>
- <listitem><constant>FE_SCALE_COUNTER</constant> - Number of blocks counted while measuring
- <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>.</listitem>
+ <listitem><para><constant>FE_SCALE_NOT_AVAILABLE</constant> - it failed to measure it, or the measurement was not complete yet.</para></listitem>
+ <listitem><para><constant>FE_SCALE_COUNTER</constant> - Number of blocks counted while measuring
+ <link linkend="DTV-STAT-ERROR-BLOCK-COUNT"><constant>DTV_STAT_ERROR_BLOCK_COUNT</constant></link>.</para></listitem>
</itemizedlist>
</section>
</section>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index ae06afbbb3a9..1ddf354aa997 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -750,15 +750,6 @@ header can be used to get the timings of the formats in the <xref linkend="cea86
<xref linkend="vesadmt" /> standards.
</para>
</listitem>
- <listitem>
- <para>DV Presets: Digital Video (DV) presets (<emphasis role="bold">deprecated</emphasis>).
- These are IDs representing a
-video timing at the input/output. Presets are pre-defined timings implemented
-by the hardware according to video standards. A __u32 data type is used to represent
-a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
-to support as many different presets as needed. This API is deprecated in favor of the DV Timings
-API.</para>
- </listitem>
</itemizedlist>
<para>To enumerate and query the attributes of the DV timings supported by a device,
applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls.
@@ -766,11 +757,6 @@ API.</para>
&VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the
&VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications
use the &VIDIOC-QUERY-DV-TIMINGS; ioctl.</para>
- <para>To enumerate and query the attributes of DV presets supported by a device,
-applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
-applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
-&VIDIOC-S-DV-PRESET; ioctl. To detect the preset as seen by the video receiver applications
-use the &VIDIOC-QUERY-DV-PRESET; ioctl.</para>
<para>Applications can make use of the <xref linkend="input-capabilities" /> and
<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
video timings for the device.</para>
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index 104a1a2b8849..f43542ae2981 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2310,6 +2310,9 @@ more information.</para>
<listitem>
<para>Added FM Modulator (FM TX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_TX</constant> and their Control IDs.</para>
</listitem>
+<listitem>
+ <para>Added FM Receiver (FM RX) Extended Control Class: <constant>V4L2_CTRL_CLASS_FM_RX</constant> and their Control IDs.</para>
+ </listitem>
<listitem>
<para>Added Remote Controller chapter, describing the default Remote Controller mapping for media devices.</para>
</listitem>
@@ -2493,6 +2496,23 @@ that used it. It was originally scheduled for removal in 2.6.35.
</orderedlist>
</section>
+ <section>
+ <title>V4L2 in Linux 3.10</title>
+ <orderedlist>
+ <listitem>
+ <para>Removed obsolete and unused DV_PRESET ioctls
+ VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and
+ VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability
+ flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS.
+ </para>
+ </listitem>
+ <listitem>
+ <para>Added new debugging ioctl &VIDIOC-DBG-G-CHIP-INFO;.
+ </para>
+ </listitem>
+ </orderedlist>
+ </section>
+
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>
@@ -2625,8 +2645,8 @@ interfaces and should not be implemented in new drivers.</para>
<xref linkend="extended-controls" />.</para>
</listitem>
<listitem>
- <para>&VIDIOC-G-DV-PRESET;, &VIDIOC-S-DV-PRESET;, &VIDIOC-ENUM-DV-PRESETS; and
- &VIDIOC-QUERY-DV-PRESET; ioctls. Use the DV Timings API (<xref linkend="dv-timings" />).</para>
+ <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_ENUM_DV_PRESETS and
+ VIDIOC_QUERY_DV_PRESET ioctls. Use the DV Timings API (<xref linkend="dv-timings" />).</para>
</listitem>
<listitem>
<para><constant>VIDIOC_SUBDEV_G_CROP</constant> and
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 9e8f85498678..8d7a77928d49 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -2300,6 +2300,12 @@ Possible values are:</entry>
</row>
<row><entry></entry></row>
<row>
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row><row><entry spanname="descr">Repeat the video sequence headers. Repeating these
+headers makes random access to the video stream easier. Applicable to the MPEG1, 2 and 4 encoder.</entry>
+ </row>
+ <row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER</constant>&nbsp;</entry>
<entry>boolean</entry>
</row><row><entry spanname="descr">Enabled the deblocking post processing filter for MPEG4 decoder.
@@ -3136,6 +3142,13 @@ giving priority to the center of the metered area.</entry>
<entry><constant>V4L2_EXPOSURE_METERING_SPOT</constant>&nbsp;</entry>
<entry>Measure only very small area at the center of the frame.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_MATRIX</constant>&nbsp;</entry>
+ <entry>A multi-zone metering. The light intensity is measured
+in several points of the frame and the the results are combined. The
+algorithm of the zones selection and their significance in calculating the
+final value is device dependant.</entry>
+ </row>
</tbody>
</entrytbl>
</row>
@@ -3848,7 +3861,7 @@ in Hz. The range and step are driver-specific.</entry>
</row>
<row>
<entry spanname="id"><constant>V4L2_CID_TUNE_PREEMPHASIS</constant>&nbsp;</entry>
- <entry>integer</entry>
+ <entry>enum v4l2_preemphasis</entry>
</row>
<row id="v4l2-preemphasis"><entry spanname="descr">Configures the pre-emphasis value for broadcasting.
A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
@@ -4687,4 +4700,76 @@ interface and may change in the future.</para>
</table>
</section>
+
+ <section id="fm-rx-controls">
+ <title>FM Receiver Control Reference</title>
+
+ <para>The FM Receiver (FM_RX) class includes controls for common features of
+ FM Reception capable devices.</para>
+
+ <table pgwide="1" frame="none" id="fm-rx-control-id">
+ <title>FM_RX Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_FM_RX_CLASS</constant>&nbsp;</entry>
+ <entry>class</entry>
+ </row><row><entry spanname="descr">The FM_RX class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_RDS_RECEPTION</constant>&nbsp;</entry>
+ <entry>boolean</entry>
+ </row><row><entry spanname="descr">Enables/disables RDS
+ reception by the radio tuner</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_TUNE_DEEMPHASIS</constant>&nbsp;</entry>
+ <entry>enum v4l2_deemphasis</entry>
+ </row>
+ <row id="v4l2-deemphasis"><entry spanname="descr">Configures the de-emphasis value for reception.
+A de-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
+Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_deemphasis
+defines possible values for de-emphasis. Here they are:</entry>
+ </row><row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_DEEMPHASIS_DISABLED</constant>&nbsp;</entry>
+ <entry>No de-emphasis is applied.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_DEEMPHASIS_50_uS</constant>&nbsp;</entry>
+ <entry>A de-emphasis of 50 uS is used.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_DEEMPHASIS_75_uS</constant>&nbsp;</entry>
+ <entry>A de-emphasis of 75 uS is used.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
</section>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index e6c58559ca6b..2c4c068dde83 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -1145,6 +1145,12 @@ in which case caches have not been used.</entry>
same clock outside V4L2, use
<function>clock_gettime(2)</function> .</entry>
</row>
+ <row>
+ <entry><constant>V4L2_BUF_FLAG_TIMESTAMP_COPY</constant></entry>
+ <entry>0x4000</entry>
+ <entry>The CAPTURE buffer timestamp has been taken from the
+ corresponding OUTPUT buffer. This flag applies only to mem2mem devices.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
index 576b68b33f2c..116c301656e0 100644
--- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
+++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml
@@ -272,6 +272,16 @@
<entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_LENS</constant></entry>
<entry>Lens controller</entry>
</row>
+ <row>
+ <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_DECODER</constant></entry>
+ <entry>Video decoder, the basic function of the video decoder is to
+ accept analogue video from a wide variety of sources such as
+ broadcast, DVD players, cameras and video cassette recorders, in
+ either NTSC, PAL or HD format and still occasionally SECAM, separate
+ it into its component parts, luminance and chrominance, and output
+ it in some digital video standard, with appropriate embedded timing
+ signals.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
index cc51372ed5e0..adc61982df7b 100644
--- a/Documentation/DocBook/media/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
@@ -93,19 +93,35 @@
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
<title>RGB formats</title>
- <tgroup cols="11">
+ <tgroup cols="27">
<colspec colname="id" align="left" />
<colspec colname="code" align="center"/>
<colspec colname="bit" />
- <colspec colnum="4" colname="b07" align="center" />
- <colspec colnum="5" colname="b06" align="center" />
- <colspec colnum="6" colname="b05" align="center" />
- <colspec colnum="7" colname="b04" align="center" />
- <colspec colnum="8" colname="b03" align="center" />
- <colspec colnum="9" colname="b02" align="center" />
- <colspec colnum="10" colname="b01" align="center" />
- <colspec colnum="11" colname="b00" align="center" />
- <spanspec namest="b07" nameend="b00" spanname="b0" />
+ <colspec colnum="4" colname="b23" align="center" />
+ <colspec colnum="5" colname="b22" align="center" />
+ <colspec colnum="6" colname="b21" align="center" />
+ <colspec colnum="7" colname="b20" align="center" />
+ <colspec colnum="8" colname="b19" align="center" />
+ <colspec colnum="9" colname="b18" align="center" />
+ <colspec colnum="10" colname="b17" align="center" />
+ <colspec colnum="11" colname="b16" align="center" />
+ <colspec colnum="12" colname="b15" align="center" />
+ <colspec colnum="13" colname="b14" align="center" />
+ <colspec colnum="14" colname="b13" align="center" />
+ <colspec colnum="15" colname="b12" align="center" />
+ <colspec colnum="16" colname="b11" align="center" />
+ <colspec colnum="17" colname="b10" align="center" />
+ <colspec colnum="18" colname="b09" align="center" />
+ <colspec colnum="19" colname="b08" align="center" />
+ <colspec colnum="20" colname="b07" align="center" />
+ <colspec colnum="21" colname="b06" align="center" />
+ <colspec colnum="22" colname="b05" align="center" />
+ <colspec colnum="23" colname="b04" align="center" />
+ <colspec colnum="24" colname="b03" align="center" />
+ <colspec colnum="25" colname="b02" align="center" />
+ <colspec colnum="26" colname="b01" align="center" />
+ <colspec colnum="27" colname="b00" align="center" />
+ <spanspec namest="b23" nameend="b00" spanname="b0" />
<thead>
<row>
<entry>Identifier</entry>
@@ -117,6 +133,22 @@
<entry></entry>
<entry></entry>
<entry>Bit</entry>
+ <entry>23</entry>
+ <entry>22</entry>
+ <entry>21</entry>
+ <entry>20</entry>
+ <entry>19</entry>
+ <entry>18</entry>
+ <entry>17</entry>
+ <entry>16</entry>
+ <entry>15</entry>
+ <entry>14</entry>
+ <entry>13</entry>
+ <entry>12</entry>
+ <entry>11</entry>
+ <entry>10</entry>
+ <entry>9</entry>
+ <entry>8</entry>
<entry>7</entry>
<entry>6</entry>
<entry>5</entry>
@@ -132,6 +164,7 @@
<entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
<entry>0x1001</entry>
<entry></entry>
+ &dash-ent-16;
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
@@ -145,6 +178,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
@@ -158,6 +192,7 @@
<entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
<entry>0x1002</entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>3</subscript></entry>
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
@@ -171,6 +206,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>0</entry>
<entry>0</entry>
<entry>0</entry>
@@ -184,6 +220,7 @@
<entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
<entry>0x1003</entry>
<entry></entry>
+ &dash-ent-16;
<entry>0</entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
@@ -197,6 +234,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -210,6 +248,7 @@
<entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
<entry>0x1004</entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -223,6 +262,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>0</entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
@@ -236,6 +276,7 @@
<entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
<entry>0x1005</entry>
<entry></entry>
+ &dash-ent-16;
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
@@ -249,6 +290,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -262,6 +304,7 @@
<entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
<entry>0x1006</entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -275,6 +318,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>b<subscript>4</subscript></entry>
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
@@ -288,6 +332,7 @@
<entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
<entry>0x1007</entry>
<entry></entry>
+ &dash-ent-16;
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
@@ -301,6 +346,7 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -314,6 +360,7 @@
<entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
<entry>0x1008</entry>
<entry></entry>
+ &dash-ent-16;
<entry>g<subscript>2</subscript></entry>
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
@@ -327,6 +374,27 @@
<entry></entry>
<entry></entry>
<entry></entry>
+ &dash-ent-16;
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB666-1X18">
+ <entry>V4L2_MBUS_FMT_RGB666_1X18</entry>
+ <entry>0x1009</entry>
+ <entry></entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>5</subscript></entry>
<entry>r<subscript>4</subscript></entry>
<entry>r<subscript>3</subscript></entry>
<entry>r<subscript>2</subscript></entry>
@@ -335,6 +403,124 @@
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB888-1X24">
+ <entry>V4L2_MBUS_FMT_RGB888_1X24</entry>
+ <entry>0x100a</entry>
+ <entry></entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB888-2X12-BE">
+ <entry>V4L2_MBUS_FMT_RGB888_2X12_BE</entry>
+ <entry>0x100b</entry>
+ <entry></entry>
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row id="V4L2-MBUS-FMT-RGB888-2X12-LE">
+ <entry>V4L2_MBUS_FMT_RGB888_2X12_LE</entry>
+ <entry>0x100c</entry>
+ <entry></entry>
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>g<subscript>3</subscript></entry>
+ <entry>g<subscript>2</subscript></entry>
+ <entry>g<subscript>1</subscript></entry>
+ <entry>g<subscript>0</subscript></entry>
+ <entry>b<subscript>7</subscript></entry>
+ <entry>b<subscript>6</subscript></entry>
+ <entry>b<subscript>5</subscript></entry>
+ <entry>b<subscript>4</subscript></entry>
+ <entry>b<subscript>3</subscript></entry>
+ <entry>b<subscript>2</subscript></entry>
+ <entry>b<subscript>1</subscript></entry>
+ <entry>b<subscript>0</subscript></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ &dash-ent-10;
+ <entry>-</entry>
+ <entry>-</entry>
+ <entry>r<subscript>7</subscript></entry>
+ <entry>r<subscript>6</subscript></entry>
+ <entry>r<subscript>5</subscript></entry>
+ <entry>r<subscript>4</subscript></entry>
+ <entry>r<subscript>3</subscript></entry>
+ <entry>r<subscript>2</subscript></entry>
+ <entry>r<subscript>1</subscript></entry>
+ <entry>r<subscript>0</subscript></entry>
+ <entry>g<subscript>7</subscript></entry>
+ <entry>g<subscript>6</subscript></entry>
+ <entry>g<subscript>5</subscript></entry>
+ <entry>g<subscript>4</subscript></entry>
</row>
</tbody>
</tgroup>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index a3cce18384e9..bfc93cdcf696 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -124,6 +124,7 @@ Remote Controller chapter.</contrib>
<year>2010</year>
<year>2011</year>
<year>2012</year>
+ <year>2013</year>
<holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
Pawel Osciak</holder>
@@ -140,12 +141,22 @@ structs, ioctls) must be noted in more detail in the history chapter
applications. -->
<revision>
+ <revnumber>3.10</revnumber>
+ <date>2013-03-25</date>
+ <authorinitials>hv</authorinitials>
+ <revremark>Remove obsolete and unused DV_PRESET ioctls:
+ VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and
+ VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability
+ flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_INFO.
+ </revremark>
+ </revision>
+
+ <revision>
<revnumber>3.9</revnumber>
<date>2012-12-03</date>
<authorinitials>sa, sn</authorinitials>
<revremark>Added timestamp types to v4l2_buffer.
- Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control
- event changes flag, see <xref linkend="changes-flags"/>.
+ Added V4L2_EVENT_CTRL_CH_RANGE control event changes flag.
</revremark>
</revision>
@@ -537,6 +548,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-create-bufs;
&sub-cropcap;
&sub-dbg-g-chip-ident;
+ &sub-dbg-g-chip-info;
&sub-dbg-g-register;
&sub-decoder-cmd;
&sub-dqevent;
@@ -544,7 +556,6 @@ and discussions on the V4L mailing list.</revremark>
&sub-encoder-cmd;
&sub-enumaudio;
&sub-enumaudioout;
- &sub-enum-dv-presets;
&sub-enum-dv-timings;
&sub-enum-fmt;
&sub-enum-framesizes;
@@ -558,7 +569,6 @@ and discussions on the V4L mailing list.</revremark>
&sub-g-audioout;
&sub-g-crop;
&sub-g-ctrl;
- &sub-g-dv-preset;
&sub-g-dv-timings;
&sub-g-enc-index;
&sub-g-ext-ctrls;
@@ -582,7 +592,6 @@ and discussions on the V4L mailing list.</revremark>
&sub-querybuf;
&sub-querycap;
&sub-queryctrl;
- &sub-query-dv-preset;
&sub-query-dv-timings;
&sub-querystd;
&sub-reqbufs;
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml
index 4ecd966808de..921e18550d26 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml
@@ -200,10 +200,10 @@ the values from <xref linkend="chip-ids" />.</entry>
&cs-def;
<tbody valign="top">
<row>
- <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
+ <entry><constant>V4L2_CHIP_MATCH_BRIDGE</constant></entry>
<entry>0</entry>
<entry>Match the nth chip on the card, zero for the
- host chip. Does not match &i2c; chips.</entry>
+ bridge chip. Does not match sub-devices.</entry>
</row>
<row>
<entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
@@ -220,6 +220,11 @@ the values from <xref linkend="chip-ids" />.</entry>
<entry>3</entry>
<entry>Match the nth anciliary AC97 chip.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
+ <entry>4</entry>
+ <entry>Match the nth sub-device. Can't be used with this ioctl.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
new file mode 100644
index 000000000000..e1cece6c5de1
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
@@ -0,0 +1,223 @@
+<refentry id="vidioc-dbg-g-chip-info">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_DBG_G_CHIP_INFO</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_DBG_G_CHIP_INFO</refname>
+ <refpurpose>Identify the chips on a TV card</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_dbg_chip_info
+*<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_DBG_G_CHIP_INFO</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <note>
+ <title>Experimental</title>
+
+ <para>This is an <link
+linkend="experimental">experimental</link> interface and may change in
+the future.</para>
+ </note>
+
+ <para>For driver debugging purposes this ioctl allows test
+applications to query the driver about the chips present on the TV
+card. Regular applications must not use it. When you found a chip
+specific bug, please contact the linux-media mailing list (&v4l-ml;)
+so it can be fixed.</para>
+
+ <para>Additionally the Linux kernel must be compiled with the
+<constant>CONFIG_VIDEO_ADV_DEBUG</constant> option to enable this ioctl.</para>
+
+ <para>To query the driver applications must initialize the
+<structfield>match.type</structfield> and
+<structfield>match.addr</structfield> or <structfield>match.name</structfield>
+fields of a &v4l2-dbg-chip-info;
+and call <constant>VIDIOC_DBG_G_CHIP_INFO</constant> with a pointer to
+this structure. On success the driver stores information about the
+selected chip in the <structfield>name</structfield> and
+<structfield>flags</structfield> fields. On failure the structure
+remains unchanged.</para>
+
+ <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_BRIDGE</constant>,
+<structfield>match.addr</structfield> selects the nth bridge 'chip'
+on the TV card. You can enumerate all chips by starting at zero and
+incrementing <structfield>match.addr</structfield> by one until
+<constant>VIDIOC_DBG_G_CHIP_INFO</constant> fails with an &EINVAL;.
+The number zero always selects the bridge chip itself, &eg; the chip
+connected to the PCI or USB bus. Non-zero numbers identify specific
+parts of the bridge chip such as an AC97 register block.</para>
+
+ <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_SUBDEV</constant>,
+<structfield>match.addr</structfield> selects the nth sub-device. This
+allows you to enumerate over all sub-devices.</para>
+
+ <para>On success, the <structfield>name</structfield> field will
+contain a chip name and the <structfield>flags</structfield> field will
+contain <constant>V4L2_CHIP_FL_READABLE</constant> if the driver supports
+reading registers from the device or <constant>V4L2_CHIP_FL_WRITABLE</constant>
+if the driver supports writing registers to the device.</para>
+
+ <para>We recommended the <application>v4l2-dbg</application>
+utility over calling this ioctl directly. It is available from the
+LinuxTV v4l-dvb repository; see <ulink
+url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+access instructions.</para>
+
+ <!-- Note for convenience vidioc-dbg-g-register.sgml
+ contains a duplicate of this table. -->
+ <table pgwide="1" frame="none" id="name-v4l2-dbg-match">
+ <title>struct <structname>v4l2_dbg_match</structname></title>
+ <tgroup cols="4">
+ &cs-ustr;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>type</structfield></entry>
+ <entry>See <xref linkend="name-chip-match-types" /> for a list of
+possible types.</entry>
+ </row>
+ <row>
+ <entry>union</entry>
+ <entry>(anonymous)</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>addr</structfield></entry>
+ <entry>Match a chip by this number, interpreted according
+to the <structfield>type</structfield> field.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>char</entry>
+ <entry><structfield>name[32]</structfield></entry>
+ <entry>Match a chip by this name, interpreted according
+to the <structfield>type</structfield> field.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-dbg-chip-info">
+ <title>struct <structname>v4l2_dbg_chip_info</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>struct v4l2_dbg_match</entry>
+ <entry><structfield>match</structfield></entry>
+ <entry>How to match the chip, see <xref linkend="name-v4l2-dbg-match" />.</entry>
+ </row>
+ <row>
+ <entry>char</entry>
+ <entry><structfield>name[32]</structfield></entry>
+ <entry>The name of the chip.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry>Set by the driver. If <constant>V4L2_CHIP_FL_READABLE</constant>
+is set, then the driver supports reading registers from the device. If
+<constant>V4L2_CHIP_FL_WRITABLE</constant> is set, then it supports writing registers.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved[8]</structfield></entry>
+ <entry>Reserved fields, both application and driver must set these to 0.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <!-- Note for convenience vidioc-dbg-g-register.sgml
+ contains a duplicate of this table. -->
+ <table pgwide="1" frame="none" id="name-chip-match-types">
+ <title>Chip Match Types</title>
+ <tgroup cols="3">
+ &cs-def;
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_BRIDGE</constant></entry>
+ <entry>0</entry>
+ <entry>Match the nth chip on the card, zero for the
+ bridge chip. Does not match sub-devices.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
+ <entry>1</entry>
+ <entry>Match an &i2c; chip by its driver name. Can't be used with this ioctl.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_I2C_ADDR</constant></entry>
+ <entry>2</entry>
+ <entry>Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_AC97</constant></entry>
+ <entry>3</entry>
+ <entry>Match the nth anciliary AC97 chip. Can't be used with this ioctl.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
+ <entry>4</entry>
+ <entry>Match the nth sub-device.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The <structfield>match_type</structfield> is invalid or
+no device could be matched.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
index a44aebc7997a..d13bac9e2445 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
@@ -87,7 +87,7 @@ written into the register.</para>
<para>To read a register applications must initialize the
<structfield>match.type</structfield>,
-<structfield>match.chip</structfield> or <structfield>match.name</structfield> and
+<structfield>match.addr</structfield> or <structfield>match.name</structfield> and
<structfield>reg</structfield> fields, and call
<constant>VIDIOC_DBG_G_REGISTER</constant> with a pointer to this
structure. On success the driver stores the register value in the
@@ -95,11 +95,11 @@ structure. On success the driver stores the register value in the
unchanged.</para>
<para>When <structfield>match.type</structfield> is
-<constant>V4L2_CHIP_MATCH_HOST</constant>,
-<structfield>match.addr</structfield> selects the nth non-&i2c; chip
+<constant>V4L2_CHIP_MATCH_BRIDGE</constant>,
+<structfield>match.addr</structfield> selects the nth non-sub-device chip
on the TV card. The number zero always selects the host chip, &eg; the
chip connected to the PCI or USB bus. You can find out which chips are
-present with the &VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
+present with the &VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
<para>When <structfield>match.type</structfield> is
<constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant>,
@@ -109,7 +109,7 @@ For instance
supported by the saa7127 driver, regardless of its &i2c; bus address.
When multiple chips supported by the same driver are present, the
effect of these ioctls is undefined. Again with the
-&VIDIOC-DBG-G-CHIP-IDENT; ioctl you can find out which &i2c; chips are
+&VIDIOC-DBG-G-CHIP-INFO; ioctl you can find out which &i2c; chips are
present.</para>
<para>When <structfield>match.type</structfield> is
@@ -122,19 +122,23 @@ bus address.</para>
<structfield>match.addr</structfield> selects the nth AC97 chip
on the TV card.</para>
+ <para>When <structfield>match.type</structfield> is
+<constant>V4L2_CHIP_MATCH_SUBDEV</constant>,
+<structfield>match.addr</structfield> selects the nth sub-device.</para>
+
<note>
<title>Success not guaranteed</title>
<para>Due to a flaw in the Linux &i2c; bus driver these ioctls may
return successfully without actually reading or writing a register. To
-catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-IDENT;
+catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-INFO;
call confirming the presence of the selected &i2c; chip.</para>
</note>
<para>These ioctls are optional, not all drivers may support them.
However when a driver supports these ioctls it must also support
-&VIDIOC-DBG-G-CHIP-IDENT;. Conversely it may support
-<constant>VIDIOC_DBG_G_CHIP_IDENT</constant> but not these ioctls.</para>
+&VIDIOC-DBG-G-CHIP-INFO;. Conversely it may support
+<constant>VIDIOC_DBG_G_CHIP_INFO</constant> but not these ioctls.</para>
<para><constant>VIDIOC_DBG_G_REGISTER</constant> and
<constant>VIDIOC_DBG_S_REGISTER</constant> were introduced in Linux
@@ -217,10 +221,10 @@ register.</entry>
&cs-def;
<tbody valign="top">
<row>
- <entry><constant>V4L2_CHIP_MATCH_HOST</constant></entry>
+ <entry><constant>V4L2_CHIP_MATCH_BRIDGE</constant></entry>
<entry>0</entry>
<entry>Match the nth chip on the card, zero for the
- host chip. Does not match &i2c; chips.</entry>
+ bridge chip. Does not match sub-devices.</entry>
</row>
<row>
<entry><constant>V4L2_CHIP_MATCH_I2C_DRIVER</constant></entry>
@@ -237,6 +241,11 @@ register.</entry>
<entry>3</entry>
<entry>Match the nth anciliary AC97 chip.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_CHIP_MATCH_SUBDEV</constant></entry>
+ <entry>4</entry>
+ <entry>Match the nth sub-device.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
deleted file mode 100644
index fced5fb0dbf0..000000000000
--- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
+++ /dev/null
@@ -1,240 +0,0 @@
-<refentry id="vidioc-enum-dv-presets">
- <refmeta>
- <refentrytitle>ioctl VIDIOC_ENUM_DV_PRESETS</refentrytitle>
- &manvol;
- </refmeta>
-
- <refnamediv>
- <refname>VIDIOC_ENUM_DV_PRESETS</refname>
- <refpurpose>Enumerate supported Digital Video presets</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <funcsynopsis>
- <funcprototype>
- <funcdef>int <function>ioctl</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>int <parameter>request</parameter></paramdef>
- <paramdef>struct v4l2_dv_enum_preset *<parameter>argp</parameter></paramdef>
- </funcprototype>
- </funcsynopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Arguments</title>
-
- <variablelist>
- <varlistentry>
- <term><parameter>fd</parameter></term>
- <listitem>
- <para>&fd;</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>request</parameter></term>
- <listitem>
- <para>VIDIOC_ENUM_DV_PRESETS</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>argp</parameter></term>
- <listitem>
- <para></para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Description</title>
-
- <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
- New drivers and applications should use &VIDIOC-ENUM-DV-TIMINGS; instead.
- </para>
-
- <para>To query the attributes of a DV preset, applications initialize the
-<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
-and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
-structure. Drivers fill the rest of the structure or return an
-&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported,
-applications shall begin at index zero, incrementing by one until the
-driver returns <errorcode>EINVAL</errorcode>. Drivers may enumerate a
-different set of DV presets after switching the video input or
-output.</para>
-
- <table pgwide="1" frame="none" id="v4l2-dv-enum-preset">
- <title>struct <structname>v4l2_dv_enum_presets</structname></title>
- <tgroup cols="3">
- &cs-str;
- <tbody valign="top">
- <row>
- <entry>__u32</entry>
- <entry><structfield>index</structfield></entry>
- <entry>Number of the DV preset, set by the
-application.</entry>
- </row>
- <row>
- <entry>__u32</entry>
- <entry><structfield>preset</structfield></entry>
- <entry>This field identifies one of the DV preset values listed in <xref linkend="v4l2-dv-presets-vals"/>.</entry>
- </row>
- <row>
- <entry>__u8</entry>
- <entry><structfield>name</structfield>[24]</entry>
- <entry>Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is
-intended for the user.</entry>
- </row>
- <row>
- <entry>__u32</entry>
- <entry><structfield>width</structfield></entry>
- <entry>Width of the active video in pixels for the DV preset.</entry>
- </row>
- <row>
- <entry>__u32</entry>
- <entry><structfield>height</structfield></entry>
- <entry>Height of the active video in lines for the DV preset.</entry>
- </row>
- <row>
- <entry>__u32</entry>
- <entry><structfield>reserved</structfield>[4]</entry>
- <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table pgwide="1" frame="none" id="v4l2-dv-presets-vals">
- <title>struct <structname>DV Presets</structname></title>
- <tgroup cols="3">
- &cs-str;
- <tbody valign="top">
- <row>
- <entry>Preset</entry>
- <entry>Preset value</entry>
- <entry>Description</entry>
- </row>
- <row>
- <entry></entry>
- <entry></entry>
- <entry></entry>
- </row>
- <row>
- <entry>V4L2_DV_INVALID</entry>
- <entry>0</entry>
- <entry>Invalid preset value.</entry>
- </row>
- <row>
- <entry>V4L2_DV_480P59_94</entry>
- <entry>1</entry>
- <entry>720x480 progressive video at 59.94 fps as per BT.1362.</entry>
- </row>
- <row>
- <entry>V4L2_DV_576P50</entry>
- <entry>2</entry>
- <entry>720x576 progressive video at 50 fps as per BT.1362.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P24</entry>
- <entry>3</entry>
- <entry>1280x720 progressive video at 24 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P25</entry>
- <entry>4</entry>
- <entry>1280x720 progressive video at 25 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P30</entry>
- <entry>5</entry>
- <entry>1280x720 progressive video at 30 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P50</entry>
- <entry>6</entry>
- <entry>1280x720 progressive video at 50 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P59_94</entry>
- <entry>7</entry>
- <entry>1280x720 progressive video at 59.94 fps as per SMPTE 274M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_720P60</entry>
- <entry>8</entry>
- <entry>1280x720 progressive video at 60 fps as per SMPTE 274M/296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080I29_97</entry>
- <entry>9</entry>
- <entry>1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080I30</entry>
- <entry>10</entry>
- <entry>1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080I25</entry>
- <entry>11</entry>
- <entry>1920x1080 interlaced video at 25 fps as per BT.1120.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080I50</entry>
- <entry>12</entry>
- <entry>1920x1080 interlaced video at 50 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080I60</entry>
- <entry>13</entry>
- <entry>1920x1080 interlaced video at 60 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080P24</entry>
- <entry>14</entry>
- <entry>1920x1080 progressive video at 24 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080P25</entry>
- <entry>15</entry>
- <entry>1920x1080 progressive video at 25 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080P30</entry>
- <entry>16</entry>
- <entry>1920x1080 progressive video at 30 fps as per SMPTE 296M.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080P50</entry>
- <entry>17</entry>
- <entry>1920x1080 progressive video at 50 fps as per BT.1120.</entry>
- </row>
- <row>
- <entry>V4L2_DV_1080P60</entry>
- <entry>18</entry>
- <entry>1920x1080 progressive video at 60 fps as per BT.1120.</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </refsect1>
-
- <refsect1>
- &return-value;
-
- <variablelist>
- <varlistentry>
- <term><errorcode>EINVAL</errorcode></term>
- <listitem>
- <para>The &v4l2-dv-enum-preset; <structfield>index</structfield>
-is out of bounds.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><errorcode>ENODATA</errorcode></term>
- <listitem>
- <para>Digital video presets are not supported for this input or output.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
index 3c9a81305ad4..493a39a8ef21 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
@@ -278,11 +278,6 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
&cs-def;
<tbody valign="top">
<row>
- <entry><constant>V4L2_IN_CAP_PRESETS</constant></entry>
- <entry>0x00000001</entry>
- <entry>This input supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
- </row>
- <row>
<entry><constant>V4L2_IN_CAP_DV_TIMINGS</constant></entry>
<entry>0x00000002</entry>
<entry>This input supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
index f4ab0798545d..2654e097df39 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
@@ -163,11 +163,6 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
&cs-def;
<tbody valign="top">
<row>
- <entry><constant>V4L2_OUT_CAP_PRESETS</constant></entry>
- <entry>0x00000001</entry>
- <entry>This output supports setting DV presets by using VIDIOC_S_DV_PRESET.</entry>
- </row>
- <row>
<entry><constant>V4L2_OUT_CAP_DV_TIMINGS</constant></entry>
<entry>0x00000002</entry>
<entry>This output supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
deleted file mode 100644
index b9ea37634f6c..000000000000
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<refentry id="vidioc-g-dv-preset">
- <refmeta>
- <refentrytitle>ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</refentrytitle>
- &manvol;
- </refmeta>
-
- <refnamediv>
- <refname>VIDIOC_G_DV_PRESET</refname>
- <refname>VIDIOC_S_DV_PRESET</refname>
- <refpurpose>Query or select the DV preset of the current input or output</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <funcsynopsis>
- <funcprototype>
- <funcdef>int <function>ioctl</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>int <parameter>request</parameter></paramdef>
- <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
- </funcprototype>
- </funcsynopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Arguments</title>
-
- <variablelist>
- <varlistentry>
- <term><parameter>fd</parameter></term>
- <listitem>
- <para>&fd;</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>request</parameter></term>
- <listitem>
- <para>VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>argp</parameter></term>
- <listitem>
- <para></para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Description</title>
-
- <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
- New drivers and applications should use &VIDIOC-G-DV-TIMINGS; and &VIDIOC-S-DV-TIMINGS;
- instead.
- </para>
-
- <para>To query and select the current DV preset, applications
-use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
-ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
-Applications must zero the reserved array in &v4l2-dv-preset;.
-<constant>VIDIOC_G_DV_PRESET</constant> returns a dv preset in the field
-<structfield>preset</structfield> of &v4l2-dv-preset;.</para>
-
- <para><constant>VIDIOC_S_DV_PRESET</constant> accepts a pointer to a &v4l2-dv-preset;
-that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;.
-If the preset is not supported, it returns an &EINVAL; </para>
- </refsect1>
-
- <refsect1>
- &return-value;
-
- <variablelist>
- <varlistentry>
- <term><errorcode>EINVAL</errorcode></term>
- <listitem>
- <para>This ioctl is not supported, or the
-<constant>VIDIOC_S_DV_PRESET</constant>,<constant>VIDIOC_S_DV_PRESET</constant> parameter was unsuitable.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><errorcode>ENODATA</errorcode></term>
- <listitem>
- <para>Digital video presets are not supported for this input or output.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><errorcode>EBUSY</errorcode></term>
- <listitem>
- <para>The device is busy and therefore can not change the preset.</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <table pgwide="1" frame="none" id="v4l2-dv-preset">
- <title>struct <structname>v4l2_dv_preset</structname></title>
- <tgroup cols="3">
- &cs-str;
- <tbody valign="top">
- <row>
- <entry>__u32</entry>
- <entry><structfield>preset</structfield></entry>
- <entry>Preset value to represent the digital video timings</entry>
- </row>
- <row>
- <entry>__u32</entry>
- <entry><structfield>reserved[4]</structfield></entry>
- <entry>Reserved fields for future use</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index 4e16112df992..b3bb9575b2e0 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -319,6 +319,15 @@ These controls are described in <xref
processing controls. These controls are described in <xref
linkend="image-process-controls" />.</entry>
</row>
+
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_FM_RX</constant></entry>
+ <entry>0xa10000</entry>
+ <entry>The class containing FM Receiver (FM RX) controls.
+These controls are described in <xref
+ linkend="fm-rx-controls" />.</entry>
+ </row>
+
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
deleted file mode 100644
index 68b49d09e245..000000000000
--- a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
+++ /dev/null
@@ -1,78 +0,0 @@
-<refentry id="vidioc-query-dv-preset">
- <refmeta>
- <refentrytitle>ioctl VIDIOC_QUERY_DV_PRESET</refentrytitle>
- &manvol;
- </refmeta>
-
- <refnamediv>
- <refname>VIDIOC_QUERY_DV_PRESET</refname>
- <refpurpose>Sense the DV preset received by the current
-input</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <funcsynopsis>
- <funcprototype>
- <funcdef>int <function>ioctl</function></funcdef>
- <paramdef>int <parameter>fd</parameter></paramdef>
- <paramdef>int <parameter>request</parameter></paramdef>
- <paramdef>struct v4l2_dv_preset *<parameter>argp</parameter></paramdef>
- </funcprototype>
- </funcsynopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Arguments</title>
-
- <variablelist>
- <varlistentry>
- <term><parameter>fd</parameter></term>
- <listitem>
- <para>&fd;</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>request</parameter></term>
- <listitem>
- <para>VIDIOC_QUERY_DV_PRESET</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><parameter>argp</parameter></term>
- <listitem>
- <para></para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Description</title>
-
- <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
- New drivers and applications should use &VIDIOC-QUERY-DV-TIMINGS; instead.
- </para>
-
- <para>The hardware may be able to detect the current DV preset
-automatically, similar to sensing the video standard. To do so, applications
-call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
-&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
-returned in the preset field of &v4l2-dv-preset;. If the preset could not be
-detected because there was no signal, or the signal was unreliable, or the
-signal did not map to a supported preset, then the value V4L2_DV_INVALID is
-returned.</para>
- </refsect1>
-
- <refsect1>
- &return-value;
-
- <variablelist>
- <varlistentry>
- <term><errorcode>ENODATA</errorcode></term>
- <listitem>
- <para>Digital video presets are not supported for this input or output.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-</refentry>
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 1f6593deb995..6a8b7158697f 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -23,6 +23,7 @@
<!-- LinuxTV v4l-dvb repository. -->
<!ENTITY v4l-dvb "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
<!ENTITY dash-ent-10 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
+<!ENTITY dash-ent-16 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
]>
<book id="media_api">
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 31ef8fe07f82..79e789b8b8ea 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -217,9 +217,14 @@ over a rather long period of time, but improvements are always welcome!
whether the increased speed is worth it.
8. Although synchronize_rcu() is slower than is call_rcu(), it
- usually results in simpler code. So, unless update performance
- is critically important or the updaters cannot block,
- synchronize_rcu() should be used in preference to call_rcu().
+ usually results in simpler code. So, unless update performance is
+ critically important, the updaters cannot block, or the latency of
+ synchronize_rcu() is visible from userspace, synchronize_rcu()
+ should be used in preference to call_rcu(). Furthermore,
+ kfree_rcu() usually results in even simpler code than does
+ synchronize_rcu() without synchronize_rcu()'s multi-millisecond
+ latency. So please take advantage of kfree_rcu()'s "fire and
+ forget" memory-freeing capabilities where it applies.
An especially important property of the synchronize_rcu()
primitive is that it automatically self-limits: if grace periods
@@ -268,7 +273,8 @@ over a rather long period of time, but improvements are always welcome!
e. Periodically invoke synchronize_rcu(), permitting a limited
number of updates per grace period.
- The same cautions apply to call_rcu_bh() and call_rcu_sched().
+ The same cautions apply to call_rcu_bh(), call_rcu_sched(),
+ call_srcu(), and kfree_rcu().
9. All RCU list-traversal primitives, which include
rcu_dereference(), list_for_each_entry_rcu(), and
@@ -296,9 +302,9 @@ over a rather long period of time, but improvements are always welcome!
all currently executing rcu_read_lock()-protected RCU read-side
critical sections complete. It does -not- necessarily guarantee
that all currently running interrupts, NMIs, preempt_disable()
- code, or idle loops will complete. Therefore, if you do not have
- rcu_read_lock()-protected read-side critical sections, do -not-
- use synchronize_rcu().
+ code, or idle loops will complete. Therefore, if your
+ read-side critical sections are protected by something other
+ than rcu_read_lock(), do -not- use synchronize_rcu().
Similarly, disabling preemption is not an acceptable substitute
for rcu_read_lock(). Code that attempts to use preemption
@@ -401,9 +407,9 @@ over a rather long period of time, but improvements are always welcome!
read-side critical sections. It is the responsibility of the
RCU update-side primitives to deal with this.
-17. Use CONFIG_PROVE_RCU, CONFIG_DEBUG_OBJECTS_RCU_HEAD, and
- the __rcu sparse checks to validate your RCU code. These
- can help find problems as follows:
+17. Use CONFIG_PROVE_RCU, CONFIG_DEBUG_OBJECTS_RCU_HEAD, and the
+ __rcu sparse checks (enabled by CONFIG_SPARSE_RCU_POINTER) to
+ validate your RCU code. These can help find problems as follows:
CONFIG_PROVE_RCU: check that accesses to RCU-protected data
structures are carried out under the proper RCU
diff --git a/Documentation/RCU/lockdep.txt b/Documentation/RCU/lockdep.txt
index a102d4b3724b..cd83d2348fef 100644
--- a/Documentation/RCU/lockdep.txt
+++ b/Documentation/RCU/lockdep.txt
@@ -64,6 +64,11 @@ checking of rcu_dereference() primitives:
but retain the compiler constraints that prevent duplicating
or coalescsing. This is useful when when testing the
value of the pointer itself, for example, against NULL.
+ rcu_access_index(idx):
+ Return the value of the index and omit all barriers, but
+ retain the compiler constraints that prevent duplicating
+ or coalescsing. This is useful when when testing the
+ value of the index itself, for example, against -1.
The rcu_dereference_check() check expression can be any boolean
expression, but would normally include a lockdep expression. However,
diff --git a/Documentation/RCU/rcubarrier.txt b/Documentation/RCU/rcubarrier.txt
index 38428c125135..2e319d1b9ef2 100644
--- a/Documentation/RCU/rcubarrier.txt
+++ b/Documentation/RCU/rcubarrier.txt
@@ -79,7 +79,20 @@ complete. Pseudo-code using rcu_barrier() is as follows:
2. Execute rcu_barrier().
3. Allow the module to be unloaded.
-The rcutorture module makes use of rcu_barrier in its exit function
+There are also rcu_barrier_bh(), rcu_barrier_sched(), and srcu_barrier()
+functions for the other flavors of RCU, and you of course must match
+the flavor of rcu_barrier() with that of call_rcu(). If your module
+uses multiple flavors of call_rcu(), then it must also use multiple
+flavors of rcu_barrier() when unloading that module. For example, if
+it uses call_rcu_bh(), call_srcu() on srcu_struct_1, and call_srcu() on
+srcu_struct_2(), then the following three lines of code will be required
+when unloading:
+
+ 1 rcu_barrier_bh();
+ 2 srcu_barrier(&srcu_struct_1);
+ 3 srcu_barrier(&srcu_struct_2);
+
+The rcutorture module makes use of rcu_barrier() in its exit function
as follows:
1 static void
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index 1927151b386b..e38b8df3d727 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -92,14 +92,14 @@ If the CONFIG_RCU_CPU_STALL_INFO kernel configuration parameter is set,
more information is printed with the stall-warning message, for example:
INFO: rcu_preempt detected stall on CPU
- 0: (63959 ticks this GP) idle=241/3fffffffffffffff/0
+ 0: (63959 ticks this GP) idle=241/3fffffffffffffff/0 softirq=82/543
(t=65000 jiffies)
In kernels with CONFIG_RCU_FAST_NO_HZ, even more information is
printed:
INFO: rcu_preempt detected stall on CPU
- 0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 drain=0 . timer not pending
+ 0: (64628 ticks this GP) idle=dd5/3fffffffffffffff/0 softirq=82/543 last_accelerate: a345/d342 nonlazy_posted: 25 .D
(t=65000 jiffies)
The "(64628 ticks this GP)" indicates that this CPU has taken more
@@ -116,13 +116,28 @@ number between the two "/"s is the value of the nesting, which will
be a small positive number if in the idle loop and a very large positive
number (as shown above) otherwise.
-For CONFIG_RCU_FAST_NO_HZ kernels, the "drain=0" indicates that the CPU is
-not in the process of trying to force itself into dyntick-idle state, the
-"." indicates that the CPU has not given up forcing RCU into dyntick-idle
-mode (it would be "H" otherwise), and the "timer not pending" indicates
-that the CPU has not recently forced RCU into dyntick-idle mode (it
-would otherwise indicate the number of microseconds remaining in this
-forced state).
+The "softirq=" portion of the message tracks the number of RCU softirq
+handlers that the stalled CPU has executed. The number before the "/"
+is the number that had executed since boot at the time that this CPU
+last noted the beginning of a grace period, which might be the current
+(stalled) grace period, or it might be some earlier grace period (for
+example, if the CPU might have been in dyntick-idle mode for an extended
+time period. The number after the "/" is the number that have executed
+since boot until the current time. If this latter number stays constant
+across repeated stall-warning messages, it is possible that RCU's softirq
+handlers are no longer able to execute on this CPU. This can happen if
+the stalled CPU is spinning with interrupts are disabled, or, in -rt
+kernels, if a high-priority process is starving RCU's softirq handler.
+
+For CONFIG_RCU_FAST_NO_HZ kernels, the "last_accelerate:" prints the
+low-order 16 bits (in hex) of the jiffies counter when this CPU last
+invoked rcu_try_advance_all_cbs() from rcu_needs_cpu() or last invoked
+rcu_accelerate_cbs() from rcu_prepare_for_idle(). The "nonlazy_posted:"
+prints the number of non-lazy callbacks posted since the last call to
+rcu_needs_cpu(). Finally, an "L" indicates that there are currently
+no non-lazy callbacks ("." is printed otherwise, as shown above) and
+"D" indicates that dyntick-idle processing is enabled ("." is printed
+otherwise, for example, if disabled via the "nohz=" kernel boot parameter).
Multiple Warnings From One Stall
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 0cc7820967f4..10df0b82f459 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -265,9 +265,9 @@ rcu_dereference()
rcu_read_lock();
p = rcu_dereference(head.next);
rcu_read_unlock();
- x = p->address;
+ x = p->address; /* BUG!!! */
rcu_read_lock();
- y = p->data;
+ y = p->data; /* BUG!!! */
rcu_read_unlock();
Holding a reference from one RCU read-side critical section
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index aa0c1e63f050..6e97e73d87b5 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -420,7 +420,7 @@ person it names. This tag documents that potentially interested parties
have been included in the discussion
-14) Using Reported-by:, Tested-by: and Reviewed-by:
+14) Using Reported-by:, Tested-by:, Reviewed-by: and Suggested-by:
If this patch fixes a problem reported by somebody else, consider adding a
Reported-by: tag to credit the reporter for their contribution. Please
@@ -468,6 +468,13 @@ done on the patch. Reviewed-by: tags, when supplied by reviewers known to
understand the subject area and to perform thorough reviews, will normally
increase the likelihood of your patch getting into the kernel.
+A Suggested-by: tag indicates that the patch idea is suggested by the person
+named and ensures credit to the person for the idea. Please note that this
+tag should not be added without the reporter's permission, especially if the
+idea was not posted in a public forum. That said, if we diligently credit our
+idea reporters, they will, hopefully, be inspired to help us again in the
+future.
+
15) The canonical patch format
diff --git a/Documentation/arm/sunxi/clocks.txt b/Documentation/arm/sunxi/clocks.txt
new file mode 100644
index 000000000000..e09a88aa3136
--- /dev/null
+++ b/Documentation/arm/sunxi/clocks.txt
@@ -0,0 +1,56 @@
+Frequently asked questions about the sunxi clock system
+=======================================================
+
+This document contains useful bits of information that people tend to ask
+about the sunxi clock system, as well as accompanying ASCII art when adequate.
+
+Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
+ system?
+
+A: The 24MHz oscillator allows gating to save power. Indeed, if gated
+ carelessly the system would stop functioning, but with the right
+ steps, one can gate it and keep the system running. Consider this
+ simplified suspend example:
+
+ While the system is operational, you would see something like
+
+ 24MHz 32kHz
+ |
+ PLL1
+ \
+ \_ CPU Mux
+ |
+ [CPU]
+
+ When you are about to suspend, you switch the CPU Mux to the 32kHz
+ oscillator:
+
+ 24Mhz 32kHz
+ | |
+ PLL1 |
+ /
+ CPU Mux _/
+ |
+ [CPU]
+
+ Finally you can gate the main oscillator
+
+ 32kHz
+ |
+ |
+ /
+ CPU Mux _/
+ |
+ [CPU]
+
+Q: Were can I learn more about the sunxi clocks?
+
+A: The linux-sunxi wiki contains a page documenting the clock registers,
+ you can find it at
+
+ http://linux-sunxi.org/A10/CCM
+
+ The authoritative source for information at this time is the ccmu driver
+ released by Allwinner, you can find it at
+
+ https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
diff --git a/Documentation/backlight/lp855x-driver.txt b/Documentation/backlight/lp855x-driver.txt
index 18b06ca038ea..1c732f0c6758 100644
--- a/Documentation/backlight/lp855x-driver.txt
+++ b/Documentation/backlight/lp855x-driver.txt
@@ -32,14 +32,10 @@ Platform data for lp855x
For supporting platform specific data, the lp855x platform data can be used.
* name : Backlight driver name. If it is not defined, default name is set.
-* mode : Brightness control mode. PWM or register based.
* device_control : Value of DEVICE CONTROL register.
* initial_brightness : Initial value of backlight brightness.
* period_ns : Platform specific PWM period value. unit is nano.
Only valid when brightness is pwm input mode.
-* load_new_rom_data :
- 0 : use default configuration data
- 1 : update values of eeprom or eprom registers on loading driver
* size_program : Total size of lp855x_rom_data.
* rom_data : List of new eeprom/eprom registers.
@@ -54,10 +50,8 @@ static struct lp855x_rom_data lp8552_eeprom_arr[] = {
static struct lp855x_platform_data lp8552_pdata = {
.name = "lcd-bl",
- .mode = REGISTER_BASED,
.device_control = I2C_CONFIG(LP8552),
.initial_brightness = INITIAL_BRT,
- .load_new_rom_data = 1,
.size_program = ARRAY_SIZE(lp8552_eeprom_arr),
.rom_data = lp8552_eeprom_arr,
};
@@ -65,7 +59,6 @@ static struct lp855x_platform_data lp8552_pdata = {
example 2) lp8556 platform data : pwm input mode with default rom data
static struct lp855x_platform_data lp8556_pdata = {
- .mode = PWM_BASED,
.device_control = PWM_CONFIG(LP8556),
.initial_brightness = INITIAL_BRT,
.period_ns = 1000000,
diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX
index f5635a09c3f6..bc461b6425a7 100644
--- a/Documentation/cgroups/00-INDEX
+++ b/Documentation/cgroups/00-INDEX
@@ -18,6 +18,8 @@ memcg_test.txt
- Memory Resource Controller; implementation details.
memory.txt
- Memory Resource Controller; design, accounting, interface, testing.
+net_cls.txt
+ - Network classifier cgroups details and usages.
net_prio.txt
- Network priority cgroups details and usages.
resource_counter.txt
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index bcf1a00b06a1..638bf17ff869 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -442,7 +442,7 @@ You can attach the current shell task by echoing 0:
You can use the cgroup.procs file instead of the tasks file to move all
threads in a threadgroup at once. Echoing the PID of any task in a
threadgroup to cgroup.procs causes all tasks in that threadgroup to be
-be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
+attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
in the writing task's threadgroup.
Note: Since every task is always a member of exactly one cgroup in each
@@ -580,6 +580,7 @@ propagation along the hierarchy. See the comment on
cgroup_for_each_descendant_pre() for details.
void css_offline(struct cgroup *cgrp);
+(cgroup_mutex held by caller)
This is the counterpart of css_online() and called iff css_online()
has succeeded on @cgrp. This signifies the beginning of the end of
diff --git a/Documentation/cgroups/devices.txt b/Documentation/cgroups/devices.txt
index 16624a7f8222..3c1095ca02ea 100644
--- a/Documentation/cgroups/devices.txt
+++ b/Documentation/cgroups/devices.txt
@@ -13,9 +13,7 @@ either an integer or * for all. Access is a composition of r
The root device cgroup starts with rwm to 'all'. A child device
cgroup gets a copy of the parent. Administrators can then remove
devices from the whitelist or add new entries. A child cgroup can
-never receive a device access which is denied by its parent. However
-when a device access is removed from a parent it will not also be
-removed from the child(ren).
+never receive a device access which is denied by its parent.
2. User Interface
@@ -50,3 +48,69 @@ task to a new cgroup. (Again we'll probably want to change that).
A cgroup may not be granted more permissions than the cgroup's
parent has.
+
+4. Hierarchy
+
+device cgroups maintain hierarchy by making sure a cgroup never has more
+access permissions than its parent. Every time an entry is written to
+a cgroup's devices.deny file, all its children will have that entry removed
+from their whitelist and all the locally set whitelist entries will be
+re-evaluated. In case one of the locally set whitelist entries would provide
+more access than the cgroup's parent, it'll be removed from the whitelist.
+
+Example:
+ A
+ / \
+ B
+
+ group behavior exceptions
+ A allow "b 8:* rwm", "c 116:1 rw"
+ B deny "c 1:3 rwm", "c 116:2 rwm", "b 3:* rwm"
+
+If a device is denied in group A:
+ # echo "c 116:* r" > A/devices.deny
+it'll propagate down and after revalidating B's entries, the whitelist entry
+"c 116:2 rwm" will be removed:
+
+ group whitelist entries denied devices
+ A all "b 8:* rwm", "c 116:* rw"
+ B "c 1:3 rwm", "b 3:* rwm" all the rest
+
+In case parent's exceptions change and local exceptions are not allowed
+anymore, they'll be deleted.
+
+Notice that new whitelist entries will not be propagated:
+ A
+ / \
+ B
+
+ group whitelist entries denied devices
+ A "c 1:3 rwm", "c 1:5 r" all the rest
+ B "c 1:3 rwm", "c 1:5 r" all the rest
+
+when adding "c *:3 rwm":
+ # echo "c *:3 rwm" >A/devices.allow
+
+the result:
+ group whitelist entries denied devices
+ A "c *:3 rwm", "c 1:5 r" all the rest
+ B "c 1:3 rwm", "c 1:5 r" all the rest
+
+but now it'll be possible to add new entries to B:
+ # echo "c 2:3 rwm" >B/devices.allow
+ # echo "c 50:3 r" >B/devices.allow
+or even
+ # echo "c *:3 rwm" >B/devices.allow
+
+Allowing or denying all by writing 'a' to devices.allow or devices.deny will
+not be possible once the device cgroups has children.
+
+4.1 Hierarchy (internal implementation)
+
+device cgroups is implemented internally using a behavior (ALLOW, DENY) and a
+list of exceptions. The internal state is controlled using the same user
+interface to preserve compatibility with the previous whitelist-only
+implementation. Removal or addition of exceptions that will reduce the access
+to devices will be propagated down the hierarchy.
+For every propagated exception, the effective rules will be re-evaluated based
+on current parent's access rules.
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index 8b8c28b9864c..09027a9fece5 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -40,6 +40,7 @@ Features:
- soft limit
- moving (recharging) account at moving a task is selectable.
- usage threshold notifier
+ - memory pressure notifier
- oom-killer disable knob and oom-notifier
- Root cgroup has no limit controls.
@@ -65,6 +66,7 @@ Brief summary of control files.
memory.stat # show various statistics
memory.use_hierarchy # set/show hierarchical account enabled
memory.force_empty # trigger forced move charge to parent
+ memory.pressure_level # set memory pressure notifications
memory.swappiness # set/show swappiness parameter of vmscan
(See sysctl's vm.swappiness)
memory.move_charge_at_immigrate # set/show controls of moving charges
@@ -194,7 +196,7 @@ the cgroup that brought it in -- this will happen on memory pressure).
But see section 8.2: when moving a task to another cgroup, its pages may
be recharged to the new cgroup, if move_charge_at_immigrate has been chosen.
-Exception: If CONFIG_CGROUP_CGROUP_MEMCG_SWAP is not used.
+Exception: If CONFIG_MEMCG_SWAP is not used.
When you do swapoff and make swapped-out pages of shmem(tmpfs) to
be backed into memory in force, charges for pages are accounted against the
caller of swapoff rather than the users of shmem.
@@ -762,7 +764,73 @@ At reading, current status of OOM is shown.
under_oom 0 or 1 (if 1, the memory cgroup is under OOM, tasks may
be stopped.)
-11. TODO
+11. Memory Pressure
+
+The pressure level notifications can be used to monitor the memory
+allocation cost; based on the pressure, applications can implement
+different strategies of managing their memory resources. The pressure
+levels are defined as following:
+
+The "low" level means that the system is reclaiming memory for new
+allocations. Monitoring this reclaiming activity might be useful for
+maintaining cache level. Upon notification, the program (typically
+"Activity Manager") might analyze vmstat and act in advance (i.e.
+prematurely shutdown unimportant services).
+
+The "medium" level means that the system is experiencing medium memory
+pressure, the system might be making swap, paging out active file caches,
+etc. Upon this event applications may decide to further analyze
+vmstat/zoneinfo/memcg or internal memory usage statistics and free any
+resources that can be easily reconstructed or re-read from a disk.
+
+The "critical" level means that the system is actively thrashing, it is
+about to out of memory (OOM) or even the in-kernel OOM killer is on its
+way to trigger. Applications should do whatever they can to help the
+system. It might be too late to consult with vmstat or any other
+statistics, so it's advisable to take an immediate action.
+
+The events are propagated upward until the event is handled, i.e. the
+events are not pass-through. Here is what this means: for example you have
+three cgroups: A->B->C. Now you set up an event listener on cgroups A, B
+and C, and suppose group C experiences some pressure. In this situation,
+only group C will receive the notification, i.e. groups A and B will not
+receive it. This is done to avoid excessive "broadcasting" of messages,
+which disturbs the system and which is especially bad if we are low on
+memory or thrashing. So, organize the cgroups wisely, or propagate the
+events manually (or, ask us to implement the pass-through events,
+explaining why would you need them.)
+
+The file memory.pressure_level is only used to setup an eventfd. To
+register a notification, an application must:
+
+- create an eventfd using eventfd(2);
+- open memory.pressure_level;
+- write string like "<event_fd> <fd of memory.pressure_level> <level>"
+ to cgroup.event_control.
+
+Application will be notified through eventfd when memory pressure is at
+the specific level (or higher). Read/write operations to
+memory.pressure_level are no implemented.
+
+Test:
+
+ Here is a small script example that makes a new cgroup, sets up a
+ memory limit, sets up a notification in the cgroup and then makes child
+ cgroup experience a critical pressure:
+
+ # cd /sys/fs/cgroup/memory/
+ # mkdir foo
+ # cd foo
+ # cgroup_event_listener memory.pressure_level low &
+ # echo 8000000 > memory.limit_in_bytes
+ # echo 8000000 > memory.memsw.limit_in_bytes
+ # echo $$ > tasks
+ # dd if=/dev/zero | read x
+
+ (Expect a bunch of notifications, and eventually, the oom-killer will
+ trigger.)
+
+12. TODO
1. Add support for accounting huge pages (as a separate controller)
2. Make per-cgroup scanner reclaim not-shared pages first
diff --git a/Documentation/cgroups/net_cls.txt b/Documentation/cgroups/net_cls.txt
new file mode 100644
index 000000000000..9face6bb578a
--- /dev/null
+++ b/Documentation/cgroups/net_cls.txt
@@ -0,0 +1,34 @@
+Network classifier cgroup
+-------------------------
+
+The Network classifier cgroup provides an interface to
+tag network packets with a class identifier (classid).
+
+The Traffic Controller (tc) can be used to assign
+different priorities to packets from different cgroups.
+
+Creating a net_cls cgroups instance creates a net_cls.classid file.
+This net_cls.classid value is initialized to 0.
+
+You can write hexadecimal values to net_cls.classid; the format for these
+values is 0xAAAABBBB; AAAA is the major handle number and BBBB
+is the minor handle number.
+Reading net_cls.classid yields a decimal result.
+
+Example:
+mkdir /sys/fs/cgroup/net_cls
+mount -t cgroup -onet_cls net_cls /sys/fs/cgroup/net_cls
+mkdir /sys/fs/cgroup/net_cls/0
+echo 0x100001 > /sys/fs/cgroup/net_cls/0/net_cls.classid
+ - setting a 10:1 handle.
+
+cat /sys/fs/cgroup/net_cls/0/net_cls.classid
+1048577
+
+configuring tc:
+tc qdisc add dev eth0 root handle 10: htb
+
+tc class add dev eth0 parent 10: classid 10:1 htb rate 40mbit
+ - creating traffic class 10:1
+
+tc filter add dev eth0 parent 10: protocol ip prio 10 handle 1: cgroup
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index 1943fae014fd..b9911c27f496 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -174,9 +174,9 @@ int clk_foo_enable(struct clk_hw *hw)
};
Below is a matrix detailing which clk_ops are mandatory based upon the
-hardware capbilities of that clock. A cell marked as "y" means
+hardware capabilities of that clock. A cell marked as "y" means
mandatory, a cell marked as "n" implies that either including that
-callback is invalid or otherwise uneccesary. Empty cells are either
+callback is invalid or otherwise unnecessary. Empty cells are either
optional or must be evaluated on a case-by-case basis.
clock hardware characteristics
@@ -231,3 +231,14 @@ To better enforce this policy, always follow this simple rule: any
statically initialized clock data MUST be defined in a separate file
from the logic that implements its ops. Basically separate the logic
from the data and all is well.
+
+ Part 6 - Disabling clock gating of unused clocks
+
+Sometimes during development it can be useful to be able to bypass the
+default disabling of unused clocks. For example, if drivers aren't enabling
+clocks properly but rely on them being on from the bootloader, bypassing
+the disabling means that the driver will remain functional while the issues
+are sorted out.
+
+To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
+kernel.
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index 72f70b16d299..a3585eac83b6 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -108,8 +108,9 @@ policy->governor must contain the "default policy" for
cpufreq_driver.target is called with
these values.
-For setting some of these values, the frequency table helpers might be
-helpful. See the section 2 for more information on them.
+For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the
+frequency table helpers might be helpful. See the section 2 for more information
+on them.
SMP systems normally have same clock source for a group of cpus. For these the
.init() would be called only once for the first online cpu. Here the .init()
@@ -184,10 +185,10 @@ the reference implementation in drivers/cpufreq/longrun.c
As most cpufreq processors only allow for being set to a few specific
frequencies, a "frequency table" with some functions might assist in
some work of the processor driver. Such a "frequency table" consists
-of an array of struct cpufreq_freq_table entries, with any value in
+of an array of struct cpufreq_frequency_table entries, with any value in
"index" you want to use, and the corresponding frequency in
"frequency". At the end of the table, you need to add a
-cpufreq_freq_table entry with frequency set to CPUFREQ_TABLE_END. And
+cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END. And
if you want to skip one entry in the table, set the frequency to
CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending
order.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index c7a2eb8450c2..66f9cc310686 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -167,6 +167,27 @@ of load evaluation and helping the CPU stay at its top speed when truly
busy, rather than shifting back and forth in speed. This tunable has no
effect on behavior at lower speeds/lower CPU loads.
+powersave_bias: this parameter takes a value between 0 to 1000. It
+defines the percentage (times 10) value of the target frequency that
+will be shaved off of the target. For example, when set to 100 -- 10%,
+when ondemand governor would have targeted 1000 MHz, it will target
+1000 MHz - (10% of 1000 MHz) = 900 MHz instead. This is set to 0
+(disabled) by default.
+When AMD frequency sensitivity powersave bias driver --
+drivers/cpufreq/amd_freq_sensitivity.c is loaded, this parameter
+defines the workload frequency sensitivity threshold in which a lower
+frequency is chosen instead of ondemand governor's original target.
+The frequency sensitivity is a hardware reported (on AMD Family 16h
+Processors and above) value between 0 to 100% that tells software how
+the performance of the workload running on a CPU will change when
+frequency changes. A workload with sensitivity of 0% (memory/IO-bound)
+will not perform any better on higher core frequency, whereas a
+workload with sensitivity of 100% (CPU-bound) will perform better
+higher the frequency. When the driver is loaded, this is set to 400
+by default -- for CPUs running workloads with sensitivity value below
+40%, a lower frequency is chosen. Unloading the driver or writing 0
+will disable this feature.
+
2.5 Conservative
----------------
@@ -191,6 +212,12 @@ governor but for the opposite direction. For example when set to its
default value of '20' it means that if the CPU usage needs to be below
20% between samples to have the frequency decreased.
+sampling_down_factor: similar functionality as in "ondemand" governor.
+But in "conservative", it controls the rate at which the kernel makes
+a decision on when to decrease the frequency while running in any
+speed. Load for frequency increase is still evaluated every
+sampling rate.
+
3. The Governor Interface in the CPUfreq Core
=============================================
diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt
index 7a9e09ece931..1b0d81d92583 100644
--- a/Documentation/cpuidle/driver.txt
+++ b/Documentation/cpuidle/driver.txt
@@ -15,11 +15,17 @@ has mechanisms in place to support actual entry-exit into CPU idle states.
cpuidle driver initializes the cpuidle_device structure for each CPU device
and registers with cpuidle using cpuidle_register_device.
+If all the idle states are the same, the wrapper function cpuidle_register
+could be used instead.
+
It can also support the dynamic changes (like battery <-> AC), by using
cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device,
cpuidle_resume_and_unlock.
Interfaces:
+extern int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus);
+extern int cpuidle_unregister(struct cpuidle_driver *drv);
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt
index b428556197c9..e9192283e5a5 100644
--- a/Documentation/device-mapper/dm-raid.txt
+++ b/Documentation/device-mapper/dm-raid.txt
@@ -1,10 +1,13 @@
dm-raid
--------
+=======
The device-mapper RAID (dm-raid) target provides a bridge from DM to MD.
It allows the MD RAID drivers to be accessed using a device-mapper
interface.
+
+Mapping Table Interface
+-----------------------
The target is named "raid" and it accepts the following parameters:
<raid_type> <#raid_params> <raid_params> \
@@ -47,7 +50,7 @@ The target is named "raid" and it accepts the following parameters:
followed by optional parameters (in any order):
[sync|nosync] Force or prevent RAID initialization.
- [rebuild <idx>] Rebuild drive number idx (first drive is 0).
+ [rebuild <idx>] Rebuild drive number 'idx' (first drive is 0).
[daemon_sleep <ms>]
Interval between runs of the bitmap daemon that
@@ -56,9 +59,9 @@ The target is named "raid" and it accepts the following parameters:
[min_recovery_rate <kB/sec/disk>] Throttle RAID initialization
[max_recovery_rate <kB/sec/disk>] Throttle RAID initialization
- [write_mostly <idx>] Drive index is write-mostly
- [max_write_behind <sectors>] See '-write-behind=' (man mdadm)
- [stripe_cache <sectors>] Stripe cache size (higher RAIDs only)
+ [write_mostly <idx>] Mark drive index 'idx' write-mostly.
+ [max_write_behind <sectors>] See '--write-behind=' (man mdadm)
+ [stripe_cache <sectors>] Stripe cache size (RAID 4/5/6 only)
[region_size <sectors>]
The region_size multiplied by the number of regions is the
logical size of the array. The bitmap records the device
@@ -122,7 +125,7 @@ The target is named "raid" and it accepts the following parameters:
given for both the metadata and data drives for a given position.
-Example tables
+Example Tables
--------------
# RAID4 - 4 data drives, 1 parity (no metadata devices)
# No metadata devices specified to hold superblock/bitmap info
@@ -141,26 +144,70 @@ Example tables
raid4 4 2048 sync min_recovery_rate 20 \
5 8:17 8:18 8:33 8:34 8:49 8:50 8:65 8:66 8:81 8:82
+
+Status Output
+-------------
'dmsetup table' displays the table used to construct the mapping.
The optional parameters are always printed in the order listed
above with "sync" or "nosync" always output ahead of the other
arguments, regardless of the order used when originally loading the table.
Arguments that can be repeated are ordered by value.
-'dmsetup status' yields information on the state and health of the
-array.
-The output is as follows:
+
+'dmsetup status' yields information on the state and health of the array.
+The output is as follows (normally a single line, but expanded here for
+clarity):
1: <s> <l> raid \
-2: <raid_type> <#devices> <1 health char for each dev> <resync_ratio>
+2: <raid_type> <#devices> <health_chars> \
+3: <sync_ratio> <sync_action> <mismatch_cnt>
Line 1 is the standard output produced by device-mapper.
-Line 2 is produced by the raid target, and best explained by example:
- 0 1960893648 raid raid4 5 AAAAA 2/490221568
+Line 2 & 3 are produced by the raid target and are best explained by example:
+ 0 1960893648 raid raid4 5 AAAAA 2/490221568 init 0
Here we can see the RAID type is raid4, there are 5 devices - all of
-which are 'A'live, and the array is 2/490221568 complete with recovery.
-Faulty or missing devices are marked 'D'. Devices that are out-of-sync
-are marked 'a'.
-
+which are 'A'live, and the array is 2/490221568 complete with its initial
+recovery. Here is a fuller description of the individual fields:
+ <raid_type> Same as the <raid_type> used to create the array.
+ <health_chars> One char for each device, indicating: 'A' = alive and
+ in-sync, 'a' = alive but not in-sync, 'D' = dead/failed.
+ <sync_ratio> The ratio indicating how much of the array has undergone
+ the process described by 'sync_action'. If the
+ 'sync_action' is "check" or "repair", then the process
+ of "resync" or "recover" can be considered complete.
+ <sync_action> One of the following possible states:
+ idle - No synchronization action is being performed.
+ frozen - The current action has been halted.
+ resync - Array is undergoing its initial synchronization
+ or is resynchronizing after an unclean shutdown
+ (possibly aided by a bitmap).
+ recover - A device in the array is being rebuilt or
+ replaced.
+ check - A user-initiated full check of the array is
+ being performed. All blocks are read and
+ checked for consistency. The number of
+ discrepancies found are recorded in
+ <mismatch_cnt>. No changes are made to the
+ array by this action.
+ repair - The same as "check", but discrepancies are
+ corrected.
+ reshape - The array is undergoing a reshape.
+ <mismatch_cnt> The number of discrepancies found between mirror copies
+ in RAID1/10 or wrong parity values found in RAID4/5/6.
+ This value is valid only after a "check" of the array
+ is performed. A healthy array has a 'mismatch_cnt' of 0.
+
+Message Interface
+-----------------
+The dm-raid target will accept certain actions through the 'message' interface.
+('man dmsetup' for more information on the message interface.) These actions
+include:
+ "idle" - Halt the current sync action.
+ "frozen" - Freeze the current sync action.
+ "resync" - Initiate/continue a resync.
+ "recover"- Initiate/continue a recover process.
+ "check" - Initiate a check (i.e. a "scrub") of the array.
+ "repair" - Initiate a repair of the array.
+ "reshape"- Currently unsupported (-EINVAL).
Version History
---------------
@@ -171,4 +218,7 @@ Version History
1.3.1 Allow device replacement/rebuild for RAID 10
1.3.2 Fix/improve redundancy checking for RAID10
1.4.0 Non-functional change. Removes arg from mapping function.
-1.4.1 Add RAID10 "far" and "offset" algorithm support.
+1.4.1 RAID10 fix redundancy validation checks (commit 55ebbb5).
+1.4.2 Add RAID10 "far" and "offset" algorithm support.
+1.5.0 Add message interface to allow manipulation of the sync_action.
+ New status (STATUSTYPE_INFO) fields: sync_action and mismatch_cnt.
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
index c63097d6afeb..16769d9cedd6 100644
--- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -14,9 +14,19 @@ Required properties:
- atmel,adc-status-register: Offset of the Interrupt Status Register
- atmel,adc-trigger-register: Offset of the Trigger Register
- atmel,adc-vref: Reference voltage in millivolts for the conversions
+ - atmel,adc-res: List of resolution in bits supported by the ADC. List size
+ must be two at least.
+ - atmel,adc-res-names: Contains one identifier string for each resolution
+ in atmel,adc-res property. "lowres" and "highres"
+ identifiers are required.
Optional properties:
- atmel,adc-use-external: Boolean to enable of external triggers
+ - atmel,adc-use-res: String corresponding to an identifier from
+ atmel,adc-res-names property. If not specified, the highest
+ resolution will be used.
+ - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
+ - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
Optional trigger Nodes:
- Required properties:
@@ -40,6 +50,9 @@ adc0: adc@fffb0000 {
atmel,adc-trigger-register = <0x08>;
atmel,adc-use-external;
atmel,adc-vref = <3300>;
+ atmel,adc-res = <8 10>;
+ atmel,adc-res-names = "lowres", "highres";
+ atmel,adc-use-res = "lowres";
trigger@0 {
trigger-name = "external-rising";
diff --git a/Documentation/devicetree/bindings/arm/msm/ssbi.txt b/Documentation/devicetree/bindings/arm/msm/ssbi.txt
new file mode 100644
index 000000000000..54fd5ced3401
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/ssbi.txt
@@ -0,0 +1,18 @@
+* Qualcomm SSBI
+
+Some Qualcomm MSM devices contain a point-to-point serial bus used to
+communicate with a limited range of devices (mostly power management
+chips).
+
+These require the following properties:
+
+- compatible: "qcom,ssbi"
+
+- qcom,controller-type
+ indicates the SSBI bus variant the controller should use to talk
+ with the slave device. This should be one of "ssbi", "ssbi2", or
+ "pmic-arbiter". The type chosen is determined by the attached
+ slave.
+
+The slave device should be the single child node of the ssbi device
+with a compatible field.
diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
new file mode 100644
index 000000000000..47ada1dff216
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt
@@ -0,0 +1,60 @@
+Samsung Exynos Analog to Digital Converter bindings
+
+The devicetree bindings are for the new ADC driver written for
+Exynos4 and upward SoCs from Samsung.
+
+New driver handles the following
+1. Supports ADC IF found on EXYNOS4412/EXYNOS5250
+ and future SoCs from Samsung
+2. Add ADC driver under iio/adc framework
+3. Also adds the Documentation for device tree bindings
+
+Required properties:
+- compatible: Must be "samsung,exynos-adc-v1"
+ for exynos4412/5250 controllers.
+ Must be "samsung,exynos-adc-v2" for
+ future controllers.
+- reg: Contains ADC register address range (base address and
+ length) and the address of the phy enable register.
+- interrupts: Contains the interrupt information for the timer. The
+ format is being dependent on which interrupt controller
+ the Samsung device uses.
+- #io-channel-cells = <1>; As ADC has multiple outputs
+- clocks From common clock binding: handle to adc clock.
+- clock-names From common clock binding: Shall be "adc".
+- vdd-supply VDD input supply.
+
+Note: child nodes can be added for auto probing from device tree.
+
+Example: adding device info in dtsi file
+
+adc: adc@12D10000 {
+ compatible = "samsung,exynos-adc-v1";
+ reg = <0x12D10000 0x100>, <0x10040718 0x4>;
+ interrupts = <0 106 0>;
+ #io-channel-cells = <1>;
+ io-channel-ranges;
+
+ clocks = <&clock 303>;
+ clock-names = "adc";
+
+ vdd-supply = <&buck5_reg>;
+};
+
+
+Example: Adding child nodes in dts file
+
+adc@12D10000 {
+
+ /* NTC thermistor is a hwmon device */
+ ncp15wb473@0 {
+ compatible = "ntc,ncp15wb473";
+ pullup-uV = <1800000>;
+ pullup-ohm = <47000>;
+ pulldown-ohm = <0>;
+ io-channels = <&adc 4>;
+ };
+};
+
+Note: Does not apply to ADC driver under arch/arm/plat-samsung/
+Note: The child node can be added under the adc node or separately.
diff --git a/Documentation/devicetree/bindings/ata/imx-pata.txt b/Documentation/devicetree/bindings/ata/imx-pata.txt
new file mode 100644
index 000000000000..e38d73414b0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/imx-pata.txt
@@ -0,0 +1,17 @@
+* Freescale i.MX PATA Controller
+
+Required properties:
+- compatible: "fsl,imx27-pata"
+- reg: Address range of the PATA Controller
+- interrupts: The interrupt of the PATA Controller
+- clocks: the clocks for the PATA Controller
+
+Example:
+
+ pata: pata@83fe0000 {
+ compatible = "fsl,imx51-pata", "fsl,imx27-pata";
+ reg = <0x83fe0000 0x4000>;
+ interrupts = <70>;
+ clocks = <&clks 161>;
+ status = "disabled";
+ };
diff --git a/Documentation/devicetree/bindings/clock/axi-clkgen.txt b/Documentation/devicetree/bindings/clock/axi-clkgen.txt
new file mode 100644
index 000000000000..028b493e97ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/axi-clkgen.txt
@@ -0,0 +1,22 @@
+Binding for the axi-clkgen clock generator
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "adi,axi-clkgen".
+- #clock-cells : from common clock binding; Should always be set to 0.
+- reg : Address and length of the axi-clkgen register set.
+- clocks : Phandle and clock specifier for the parent clock.
+
+Optional properties:
+- clock-output-names : From common clock binding.
+
+Example:
+ clock@0xff000000 {
+ compatible = "adi,axi-clkgen";
+ #clock-cells = <0>;
+ reg = <0xff000000 0x1000>;
+ clocks = <&osc 1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt
new file mode 100644
index 000000000000..5757f9abfc26
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/fixed-factor-clock.txt
@@ -0,0 +1,24 @@
+Binding for simple fixed factor rate clock sources.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "fixed-factor-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clock-div: fixed divider.
+- clock-mult: fixed multiplier.
+- clocks: parent clock.
+
+Optional properties:
+- clock-output-names : From common clock binding.
+
+Example:
+ clock {
+ compatible = "fixed-factor-clock";
+ clocks = <&parentclk>;
+ #clock-cells = <0>;
+ div = <2>;
+ mult = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
new file mode 100644
index 000000000000..cc374651662c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
@@ -0,0 +1,114 @@
+Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator.
+
+Reference
+[1] Si5351A/B/C Data Sheet
+ http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
+
+The Si5351a/b/c are programmable i2c clock generators with upto 8 output
+clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
+3 output clocks are accessible. The internal structure of the clock
+generators can be found in [1].
+
+==I2C device node==
+
+Required properties:
+- compatible: shall be one of "silabs,si5351{a,a-msop,b,c}".
+- reg: i2c device address, shall be 0x60 or 0x61.
+- #clock-cells: from common clock binding; shall be set to 1.
+- clocks: from common clock binding; list of parent clock
+ handles, shall be xtal reference clock or xtal and clkin for
+ si5351c only.
+- #address-cells: shall be set to 1.
+- #size-cells: shall be set to 0.
+
+Optional properties:
+- silabs,pll-source: pair of (number, source) for each pll. Allows
+ to overwrite clock source of pll A (number=0) or B (number=1).
+
+==Child nodes==
+
+Each of the clock outputs can be overwritten individually by
+using a child node to the I2C device node. If a child node for a clock
+output is not set, the eeprom configuration is not overwritten.
+
+Required child node properties:
+- reg: number of clock output.
+
+Optional child node properties:
+- silabs,clock-source: source clock of the output divider stage N, shall be
+ 0 = multisynth N
+ 1 = multisynth 0 for output clocks 0-3, else multisynth4
+ 2 = xtal
+ 3 = clkin (si5351c only)
+- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}.
+- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
+ divider.
+- silabs,pll-master: boolean, multisynth can change pll frequency.
+
+==Example==
+
+/* 25MHz reference crystal */
+ref25: ref25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+};
+
+i2c-master-node {
+
+ /* Si5351a msop10 i2c clock generator */
+ si5351a: clock-generator@60 {
+ compatible = "silabs,si5351a-msop";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+
+ /* connect xtal input to 25MHz reference */
+ clocks = <&ref25>;
+
+ /* connect xtal input as source of pll0 and pll1 */
+ silabs,pll-source = <0 0>, <1 0>;
+
+ /*
+ * overwrite clkout0 configuration with:
+ * - 8mA output drive strength
+ * - pll0 as clock source of multisynth0
+ * - multisynth0 as clock source of output divider
+ * - multisynth0 can change pll0
+ * - set initial clock frequency of 74.25MHz
+ */
+ clkout0 {
+ reg = <0>;
+ silabs,drive-strength = <8>;
+ silabs,multisynth-source = <0>;
+ silabs,clock-source = <0>;
+ silabs,pll-master;
+ clock-frequency = <74250000>;
+ };
+
+ /*
+ * overwrite clkout1 configuration with:
+ * - 4mA output drive strength
+ * - pll1 as clock source of multisynth1
+ * - multisynth1 as clock source of output divider
+ * - multisynth1 can change pll1
+ */
+ clkout1 {
+ reg = <1>;
+ silabs,drive-strength = <4>;
+ silabs,multisynth-source = <1>;
+ silabs,clock-source = <0>;
+ pll-master;
+ };
+
+ /*
+ * overwrite clkout2 configuration with:
+ * - xtal as clock source of output divider
+ */
+ clkout2 {
+ reg = <2>;
+ silabs,clock-source = <2>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
new file mode 100644
index 000000000000..729f52426fe1
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -0,0 +1,151 @@
+Device Tree Clock bindings for arch-sunxi
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of the following:
+ "allwinner,sun4i-osc-clk" - for a gatable oscillator
+ "allwinner,sun4i-pll1-clk" - for the main PLL clock
+ "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
+ "allwinner,sun4i-axi-clk" - for the AXI clock
+ "allwinner,sun4i-axi-gates-clk" - for the AXI gates
+ "allwinner,sun4i-ahb-clk" - for the AHB clock
+ "allwinner,sun4i-ahb-gates-clk" - for the AHB gates
+ "allwinner,sun4i-apb0-clk" - for the APB0 clock
+ "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
+ "allwinner,sun4i-apb1-clk" - for the APB1 clock
+ "allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
+ "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates
+
+Required properties for all clocks:
+- reg : shall be the control register address for the clock.
+- clocks : shall be the input parent clock(s) phandle for the clock
+- #clock-cells : from common clock binding; shall be set to 0 except for
+ "allwinner,sun4i-*-gates-clk" where it shall be set to 1
+
+Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
+- clock-output-names : the corresponding gate names that the clock controls
+
+For example:
+
+osc24M: osc24M@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&osc24M_fixed>;
+};
+
+pll1: pll1@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+};
+
+cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>;
+};
+
+
+
+Gate clock outputs
+
+The "allwinner,sun4i-*-gates-clk" clocks provide several gatable outputs;
+their corresponding offsets as present on sun4i are listed below. Note that
+some of these gates are not present on sun5i.
+
+ * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+ DRAM 0
+
+ * AHB gates ("allwinner,sun4i-ahb-gates-clk")
+
+ USB0 0
+ EHCI0 1
+ OHCI0 2*
+ EHCI1 3
+ OHCI1 4*
+ SS 5
+ DMA 6
+ BIST 7
+ MMC0 8
+ MMC1 9
+ MMC2 10
+ MMC3 11
+ MS 12**
+ NAND 13
+ SDRAM 14
+
+ ACE 16
+ EMAC 17
+ TS 18
+
+ SPI0 20
+ SPI1 21
+ SPI2 22
+ SPI3 23
+ PATA 24
+ SATA 25**
+ GPS 26*
+
+ VE 32
+ TVD 33
+ TVE0 34
+ TVE1 35
+ LCD0 36
+ LCD1 37
+
+ CSI0 40
+ CSI1 41
+
+ HDMI 43
+ DE_BE0 44
+ DE_BE1 45
+ DE_FE0 46
+ DE_FE1 47
+
+ MP 50
+
+ MALI400 52
+
+ * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
+
+ CODEC 0
+ SPDIF 1*
+ AC97 2
+ IIS 3
+
+ PIO 5
+ IR0 6
+ IR1 7
+
+ KEYPAD 10
+
+ * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
+
+ I2C0 0
+ I2C1 1
+ I2C2 2
+
+ CAN 4
+ SCR 5
+ PS20 6
+ PS21 7
+
+ UART0 16
+ UART1 17
+ UART2 18
+ UART3 19
+ UART4 20
+ UART5 21
+ UART6 22
+ UART7 23
+
+Notation:
+ [*]: The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
new file mode 100644
index 000000000000..0715695e94a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt
@@ -0,0 +1,65 @@
+Generic ARM big LITTLE cpufreq driver's DT glue
+-----------------------------------------------
+
+This is DT specific glue layer for generic cpufreq driver for big LITTLE
+systems.
+
+Both required and optional properties listed below must be defined
+under node /cpus/cpu@x. Where x is the first cpu inside a cluster.
+
+FIXME: Cpus should boot in the order specified in DT and all cpus for a cluster
+must be present contiguously. Generic DT driver will check only node 'x' for
+cpu:x.
+
+Required properties:
+- operating-points: Refer to Documentation/devicetree/bindings/power/opp.txt
+ for details
+
+Optional properties:
+- clock-latency: Specify the possible maximum transition latency for clock,
+ in unit of nanoseconds.
+
+Examples:
+
+cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a15";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ operating-points = <
+ /* kHz uV */
+ 792000 1100000
+ 396000 950000
+ 198000 850000
+ >;
+ clock-latency = <61036>; /* two CLK32 periods */
+ };
+
+ cpu@1 {
+ compatible = "arm,cortex-a15";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+
+ cpu@100 {
+ compatible = "arm,cortex-a7";
+ reg = <100>;
+ next-level-cache = <&L2>;
+ operating-points = <
+ /* kHz uV */
+ 792000 950000
+ 396000 750000
+ 198000 450000
+ >;
+ clock-latency = <61036>; /* two CLK32 periods */
+ };
+
+ cpu@101 {
+ compatible = "arm,cortex-a7";
+ reg = <101>;
+ next-level-cache = <&L2>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
index 4416ccc33472..051f764bedb8 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -32,7 +32,7 @@ cpus {
396000 950000
198000 850000
>;
- transition-latency = <61036>; /* two CLK32 periods */
+ clock-latency = <61036>; /* two CLK32 periods */
};
cpu@1 {
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt
new file mode 100644
index 000000000000..caff1a57436f
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-exynos5440.txt
@@ -0,0 +1,28 @@
+
+Exynos5440 cpufreq driver
+-------------------
+
+Exynos5440 SoC cpufreq driver for CPU frequency scaling.
+
+Required properties:
+- interrupts: Interrupt to know the completion of cpu frequency change.
+- operating-points: Table of frequencies and voltage CPU could be transitioned into,
+ in the decreasing order. Frequency should be in KHz units and voltage
+ should be in microvolts.
+
+Optional properties:
+- clock-latency: Clock monitor latency in microsecond.
+
+All the required listed above must be defined under node cpufreq.
+
+Example:
+--------
+ cpufreq@160000 {
+ compatible = "samsung,exynos5440-cpufreq";
+ reg = <0x160000 0x1000>;
+ interrupts = <0 57 0>;
+ operating-points = <
+ 1000000 975000
+ 800000 925000>;
+ clock-latency = <100000>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index a33628759d36..d933af370697 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -98,7 +98,7 @@ announce the pinrange to the pin ctrl subsystem. For example,
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
reg = <0x1460 0x18>;
gpio-controller;
- gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
+ gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
}
@@ -107,8 +107,8 @@ where,
Next values specify the base pin and number of pins for the range
handled by 'qe_pio_e' gpio. In the given example from base pin 20 to
- pin 29 under pinctrl1 and pin 50 to pin 69 under pinctrl2 is handled
- by this gpio controller.
+ pin 29 under pinctrl1 with gpio offset 0 and pin 50 to pin 69 under
+ pinctrl2 with gpio offset 10 is handled by this gpio controller.
The pinctrl node must have "#gpio-range-cells" property to show number of
arguments to pass with phandle from gpio controllers node.
diff --git a/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
new file mode 100644
index 000000000000..c6f66674f19c
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/ntc_thermistor.txt
@@ -0,0 +1,29 @@
+NTC Thermistor hwmon sensors
+-------------------------------
+
+Requires node properties:
+- "compatible" value : one of
+ "ntc,ncp15wb473"
+ "ntc,ncp18wb473"
+ "ntc,ncp21wb473"
+ "ntc,ncp03wb473"
+ "ntc,ncp15wl333"
+- "pullup-uv" Pull up voltage in micro volts
+- "pullup-ohm" Pull up resistor value in ohms
+- "pulldown-ohm" Pull down resistor value in ohms
+- "connected-positive" Always ON, If not specified.
+ Status change is possible.
+- "io-channels" Channel node of ADC to be used for
+ conversion.
+
+Read more about iio bindings at
+ Documentation/devicetree/bindings/iio/iio-bindings.txt
+
+Example:
+ ncp15wb473@0 {
+ compatible = "ntc,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <47000>;
+ pulldown-ohm = <0>;
+ io-channels = <&adc 3>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
index f98d4c5b5cca..296eb4536129 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
@@ -26,7 +26,7 @@ Required for all cases except "samsung,s3c2440-hdmiphy-i2c":
- pinctrl-names: Should contain only one value - "default".
Optional properties:
- - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not
+ - samsung,i2c-slave-addr: Slave address in multi-master environment. If not
specified, default value is 0.
- samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not
specified, the default value in Hz is 100000.
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 446859fcdca4..ad6a73852f08 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -35,6 +35,8 @@ fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51
fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller
fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec
+infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
+infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
diff --git a/Documentation/devicetree/bindings/iio/iio-bindings.txt b/Documentation/devicetree/bindings/iio/iio-bindings.txt
new file mode 100644
index 000000000000..0b447d9ad196
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/iio-bindings.txt
@@ -0,0 +1,97 @@
+This binding is derived from clock bindings, and based on suggestions
+from Lars-Peter Clausen [1].
+
+Sources of IIO channels can be represented by any node in the device
+tree. Those nodes are designated as IIO providers. IIO consumer
+nodes use a phandle and IIO specifier pair to connect IIO provider
+outputs to IIO inputs. Similar to the gpio specifiers, an IIO
+specifier is an array of one or more cells identifying the IIO
+output on a device. The length of an IIO specifier is defined by the
+value of a #io-channel-cells property in the IIO provider node.
+
+[1] http://marc.info/?l=linux-iio&m=135902119507483&w=2
+
+==IIO providers==
+
+Required properties:
+#io-channel-cells: Number of cells in an IIO specifier; Typically 0 for nodes
+ with a single IIO output and 1 for nodes with multiple
+ IIO outputs.
+
+Example for a simple configuration with no trigger:
+
+ adc: voltage-sensor@35 {
+ compatible = "maxim,max1139";
+ reg = <0x35>;
+ #io-channel-cells = <1>;
+ };
+
+Example for a configuration with trigger:
+
+ adc@35 {
+ compatible = "some-vendor,some-adc";
+ reg = <0x35>;
+
+ adc1: iio-device@0 {
+ #io-channel-cells = <1>;
+ /* other properties */
+ };
+ adc2: iio-device@1 {
+ #io-channel-cells = <1>;
+ /* other properties */
+ };
+ };
+
+==IIO consumers==
+
+Required properties:
+io-channels: List of phandle and IIO specifier pairs, one pair
+ for each IIO input to the device. Note: if the
+ IIO provider specifies '0' for #io-channel-cells,
+ then only the phandle portion of the pair will appear.
+
+Optional properties:
+io-channel-names:
+ List of IIO input name strings sorted in the same
+ order as the io-channels property. Consumers drivers
+ will use io-channel-names to match IIO input names
+ with IIO specifiers.
+io-channel-ranges:
+ Empty property indicating that child nodes can inherit named
+ IIO channels from this node. Useful for bus nodes to provide
+ and IIO channel to their children.
+
+For example:
+
+ device {
+ io-channels = <&adc 1>, <&ref 0>;
+ io-channel-names = "vcc", "vdd";
+ };
+
+This represents a device with two IIO inputs, named "vcc" and "vdd".
+The vcc channel is connected to output 1 of the &adc device, and the
+vdd channel is connected to output 0 of the &ref device.
+
+==Example==
+
+ adc: max1139@35 {
+ compatible = "maxim,max1139";
+ reg = <0x35>;
+ #io-channel-cells = <1>;
+ };
+
+ ...
+
+ iio_hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 0>, <&adc 1>, <&adc 2>,
+ <&adc 3>, <&adc 4>, <&adc 5>,
+ <&adc 6>, <&adc 7>, <&adc 8>,
+ <&adc 9>;
+ };
+
+ some_consumer {
+ compatible = "some-consumer";
+ io-channels = <&adc 10>, <&adc 11>;
+ io-channel-names = "adc1", "adc2";
+ };
diff --git a/Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt b/Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt
new file mode 100644
index 000000000000..3029c5694cf6
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt
@@ -0,0 +1,16 @@
+Aeroflex Gaisler APBPS2 PS/2 Core, supporting Keyboard or Mouse.
+
+The APBPS2 PS/2 core is available in the GRLIB VHDL IP core library.
+
+Note: In the ordinary environment for the APBPS2 core, a LEON SPARC system,
+these properties are built from information in the AMBA plug&play and from
+bootloader settings.
+
+Required properties:
+
+- name : Should be "GAISLER_APBPS2" or "01_060"
+- reg : Address and length of the register set for the device
+- interrupts : Interrupt numbers for this device
+
+For further information look in the documentation for the GLIB IP core library:
+http://www.gaisler.com/products/grlib/grip.pdf
diff --git a/Documentation/devicetree/bindings/input/touchscreen/auo_pixcir_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/auo_pixcir_ts.txt
new file mode 100644
index 000000000000..f40f21c642b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/auo_pixcir_ts.txt
@@ -0,0 +1,30 @@
+* AUO in-cell touchscreen controller using Pixcir sensors
+
+Required properties:
+- compatible: must be "auo,auo_pixcir_ts"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- gpios: gpios the chip is connected to
+ first one is the interrupt gpio and second one the reset gpio
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Example:
+
+ i2c@00000000 {
+ /* ... */
+
+ auo_pixcir_ts@5c {
+ compatible = "auo,auo_pixcir_ts";
+ reg = <0x5c>;
+ interrupts = <2 0>;
+
+ gpios = <&gpf 2 0 2>, /* INT */
+ <&gpf 5 1 0>; /* RST */
+
+ x-size = <800>;
+ y-size = <600>;
+ };
+
+ /* ... */
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt
new file mode 100644
index 000000000000..64ad48b824a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/sitronix-st1232.txt
@@ -0,0 +1,24 @@
+* Sitronix st1232 touchscreen controller
+
+Required properties:
+- compatible: must be "sitronix,st1232"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+
+Optional properties:
+- gpios: a phandle to the reset GPIO
+
+Example:
+
+ i2c@00000000 {
+ /* ... */
+
+ touchscreen@55 {
+ compatible = "sitronix,st1232";
+ reg = <0x55>;
+ interrupts = <2 0>;
+ gpios = <&gpio1 166 0>;
+ };
+
+ /* ... */
+ };
diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt
index 2b6693b972fb..80ff3dfb1f32 100644
--- a/Documentation/devicetree/bindings/leds/tca6507.txt
+++ b/Documentation/devicetree/bindings/leds/tca6507.txt
@@ -1,4 +1,4 @@
-LEDs conected to tca6507
+LEDs connected to tca6507
Required properties:
- compatible : should be : "ti,tca6507".
diff --git a/Documentation/devicetree/bindings/marvell.txt b/Documentation/devicetree/bindings/marvell.txt
index f1533d91953a..f7a0da6b4022 100644
--- a/Documentation/devicetree/bindings/marvell.txt
+++ b/Documentation/devicetree/bindings/marvell.txt
@@ -115,6 +115,9 @@ prefixed with the string "marvell,", for Marvell Technology Group Ltd.
- compatible : "marvell,mv64360-eth-block"
- reg : Offset and length of the register set for this block
+ Optional properties:
+ - clocks : Phandle to the clock control device and gate bit
+
Example Discovery Ethernet block node:
ethernet-block@2000 {
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/media/coda.txt b/Documentation/devicetree/bindings/media/coda.txt
new file mode 100644
index 000000000000..2865d04e4030
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/coda.txt
@@ -0,0 +1,30 @@
+Chips&Media Coda multi-standard codec IP
+========================================
+
+Coda codec IPs are present in i.MX SoCs in various versions,
+called VPU (Video Processing Unit).
+
+Required properties:
+- compatible : should be "fsl,<chip>-src" for i.MX SoCs:
+ (a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27
+ (b) "fsl,imx53-vpu" for CODA7541 present in i.MX53
+ (c) "fsl,imx6q-vpu" for CODA960 present in i.MX6q
+- reg: should be register base and length as documented in the
+ SoC reference manual
+- interrupts : Should contain the VPU interrupt. For CODA960,
+ a second interrupt is needed for the MJPEG unit.
+- clocks : Should contain the ahb and per clocks, in the order
+ determined by the clock-names property.
+- clock-names : Should be "ahb", "per"
+- iram : phandle pointing to the SRAM device node
+
+Example:
+
+vpu: vpu@63ff4000 {
+ compatible = "fsl,imx53-vpu";
+ reg = <0x63ff4000 0x1000>;
+ interrupts = <9>;
+ clocks = <&clks 63>, <&clks 63>;
+ clock-names = "ahb", "per";
+ iram = <&ocram>;
+};
diff --git a/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt
new file mode 100644
index 000000000000..3f62adfb3e0b
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt
@@ -0,0 +1,14 @@
+Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE)
+
+Required properties:
+
+- compatible : should be "samsung,exynos4212-fimc" for Exynos4212 and
+ Exynos4412 SoCs;
+- reg : physical base address and size of the device memory mapped
+ registers;
+- interrupts : should contain FIMC-LITE interrupt;
+- clocks : FIMC LITE gate clock should be specified in this property.
+- clock-names : should contain "flite" entry.
+
+Each FIMC device should have an alias in the aliases node, in the form of
+fimc-lite<n>, where <n> is an integer specifying the IP block instance.
diff --git a/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt
new file mode 100644
index 000000000000..55c9ad6f9599
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt
@@ -0,0 +1,49 @@
+Exynos4x12 SoC series Imaging Subsystem (FIMC-IS)
+
+The FIMC-IS is a subsystem for processing image signal from an image sensor.
+The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5
+processor, ISP, DRC and FD IP blocks and peripheral devices such as UART, I2C
+and SPI bus controllers, PWM and ADC.
+
+fimc-is node
+------------
+
+Required properties:
+- compatible : should be "samsung,exynos4212-fimc-is" for Exynos4212 and
+ Exynos4412 SoCs;
+- reg : physical base address and length of the registers set;
+- interrupts : must contain two FIMC-IS interrupts, in order: ISP0, ISP1;
+- clocks : list of clock specifiers, corresponding to entries in
+ clock-names property;
+- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1"
+ "mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "uart",
+ "ispdiv0", "ispdiv1", "mcuispdiv0", "mcuispdiv1", "aclk200",
+ "div_aclk200", "aclk400mcuisp", "div_aclk400mcuisp" entries,
+ matching entries in the clocks property.
+pmu subnode
+-----------
+
+Required properties:
+ - reg : must contain PMU physical base address and size of the register set.
+
+The following are the FIMC-IS peripheral device nodes and can be specified
+either standalone or as the fimc-is node child nodes.
+
+i2c-isp (ISP I2C bus controller) nodes
+------------------------------------------
+
+Required properties:
+
+- compatible : should be "samsung,exynos4212-i2c-isp" for Exynos4212 and
+ Exynos4412 SoCs;
+- reg : physical base address and length of the registers set;
+- clocks : must contain gate clock specifier for this controller;
+- clock-names : must contain "i2c_isp" entry.
+
+For the above nodes it is required to specify a pinctrl state named "default",
+according to the pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt.
+
+Device tree nodes of the image sensors' controlled directly by the FIMC-IS
+firmware must be child nodes of their corresponding ISP I2C bus controller node.
+The data link of these image sensors must be specified using the common video
+interfaces bindings, defined in video-interfaces.txt.
diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt
new file mode 100644
index 000000000000..51c776b7f7a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt
@@ -0,0 +1,197 @@
+Samsung S5P/EXYNOS SoC Camera Subsystem (FIMC)
+----------------------------------------------
+
+The S5P/Exynos SoC Camera subsystem comprises of multiple sub-devices
+represented by separate device tree nodes. Currently this includes: FIMC (in
+the S5P SoCs series known as CAMIF), MIPI CSIS, FIMC-LITE and FIMC-IS (ISP).
+
+The sub-subdevices are defined as child nodes of the common 'camera' node which
+also includes common properties of the whole subsystem not really specific to
+any single sub-device, like common camera port pins or the CAMCLK clock outputs
+for external image sensors attached to an SoC.
+
+Common 'camera' node
+--------------------
+
+Required properties:
+
+- compatible : must be "samsung,fimc", "simple-bus"
+- clocks : list of clock specifiers, corresponding to entries in
+ the clock-names property;
+- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0",
+ "pxl_async1" entries, matching entries in the clocks property.
+
+The pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt must be used
+to define a required pinctrl state named "default" and optional pinctrl states:
+"idle", "active-a", active-b". These optional states can be used to switch the
+camera port pinmux at runtime. The "idle" state should configure both the camera
+ports A and B into high impedance state, especially the CAMCLK clock output
+should be inactive. For the "active-a" state the camera port A must be activated
+and the port B deactivated and for the state "active-b" it should be the other
+way around.
+
+The 'camera' node must include at least one 'fimc' child node.
+
+'fimc' device nodes
+-------------------
+
+Required properties:
+
+- compatible: "samsung,s5pv210-fimc" for S5PV210, "samsung,exynos4210-fimc"
+ for Exynos4210 and "samsung,exynos4212-fimc" for Exynos4x12 SoCs;
+- reg: physical base address and length of the registers set for the device;
+- interrupts: should contain FIMC interrupt;
+- clocks: list of clock specifiers, must contain an entry for each required
+ entry in clock-names;
+- clock-names: must contain "fimc", "sclk_fimc" entries.
+- samsung,pix-limits: an array of maximum supported image sizes in pixels, for
+ details refer to Table 2-1 in the S5PV210 SoC User Manual; The meaning of
+ each cell is as follows:
+ 0 - scaler input horizontal size,
+ 1 - input horizontal size for the scaler bypassed,
+ 2 - REAL_WIDTH without input rotation,
+ 3 - REAL_HEIGHT with input rotation,
+- samsung,sysreg: a phandle to the SYSREG node.
+
+Each FIMC device should have an alias in the aliases node, in the form of
+fimc<n>, where <n> is an integer specifying the IP block instance.
+
+Optional properties:
+
+- clock-frequency: maximum FIMC local clock (LCLK) frequency;
+- samsung,min-pix-sizes: an array specyfing minimum image size in pixels at
+ the FIMC input and output DMA, in the first and second cell respectively.
+ Default value when this property is not present is <16 16>;
+- samsung,min-pix-alignment: minimum supported image height alignment (first
+ cell) and the horizontal image offset (second cell). The values are in pixels
+ and default to <2 1> when this property is not present;
+- samsung,mainscaler-ext: a boolean property indicating whether the FIMC IP
+ supports extended image size and has CIEXTEN register;
+- samsung,rotators: a bitmask specifying whether this IP has the input and
+ the output rotator. Bits 4 and 0 correspond to input and output rotator
+ respectively. If a rotator is present its corresponding bit should be set.
+ Default value when this property is not specified is 0x11.
+- samsung,cam-if: a bolean property indicating whether the IP block includes
+ the camera input interface.
+- samsung,isp-wb: this property must be present if the IP block has the ISP
+ writeback input.
+- samsung,lcd-wb: this property must be present if the IP block has the LCD
+ writeback input.
+
+
+'parallel-ports' node
+---------------------
+
+This node should contain child 'port' nodes specifying active parallel video
+input ports. It includes camera A and camera B inputs. 'reg' property in the
+port nodes specifies data input - 0, 1 indicates input A, B respectively.
+
+Optional properties
+
+- samsung,camclk-out : specifies clock output for remote sensor,
+ 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT;
+
+Image sensor nodes
+------------------
+
+The sensor device nodes should be added to their control bus controller (e.g.
+I2C0) nodes and linked to a port node in the csis or the parallel-ports node,
+using the common video interfaces bindings, defined in video-interfaces.txt.
+The implementation of this bindings requires clock-frequency property to be
+present in the sensor device nodes.
+
+Example:
+
+ aliases {
+ fimc0 = &fimc_0;
+ };
+
+ /* Parallel bus IF sensor */
+ i2c_0: i2c@13860000 {
+ s5k6aa: sensor@3c {
+ compatible = "samsung,s5k6aafx";
+ reg = <0x3c>;
+ vddio-supply = <...>;
+
+ clock-frequency = <24000000>;
+ clocks = <...>;
+ clock-names = "mclk";
+
+ port {
+ s5k6aa_ep: endpoint {
+ remote-endpoint = <&fimc0_ep>;
+ bus-width = <8>;
+ hsync-active = <0>;
+ vsync-active = <1>;
+ pclk-sample = <1>;
+ };
+ };
+ };
+ };
+
+ /* MIPI CSI-2 bus IF sensor */
+ s5c73m3: sensor@0x1a {
+ compatible = "samsung,s5c73m3";
+ reg = <0x1a>;
+ vddio-supply = <...>;
+
+ clock-frequency = <24000000>;
+ clocks = <...>;
+ clock-names = "mclk";
+
+ port {
+ s5c73m3_1: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csis0_ep>;
+ };
+ };
+ };
+
+ camera {
+ compatible = "samsung,fimc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&cam_port_a_clk_active>;
+
+ /* parallel camera ports */
+ parallel-ports {
+ /* camera A input */
+ port@0 {
+ reg = <0>;
+ fimc0_ep: endpoint {
+ remote-endpoint = <&s5k6aa_ep>;
+ bus-width = <8>;
+ hsync-active = <0>;
+ vsync-active = <1>;
+ pclk-sample = <1>;
+ };
+ };
+ };
+
+ fimc_0: fimc@11800000 {
+ compatible = "samsung,exynos4210-fimc";
+ reg = <0x11800000 0x1000>;
+ interrupts = <0 85 0>;
+ status = "okay";
+ };
+
+ csis_0: csis@11880000 {
+ compatible = "samsung,exynos4210-csis";
+ reg = <0x11880000 0x1000>;
+ interrupts = <0 78 0>;
+ /* camera C input */
+ port@3 {
+ reg = <3>;
+ csis0_ep: endpoint {
+ remote-endpoint = <&s5c73m3_ep>;
+ data-lanes = <1 2 3 4>;
+ samsung,csis-hs-settle = <12>;
+ };
+ };
+ };
+ };
+
+The MIPI-CSIS device binding is defined in samsung-mipi-csis.txt.
diff --git a/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt
new file mode 100644
index 000000000000..5f8e28e2484f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt
@@ -0,0 +1,81 @@
+Samsung S5P/EXYNOS SoC series MIPI CSI-2 receiver (MIPI CSIS)
+-------------------------------------------------------------
+
+Required properties:
+
+- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110),
+ "samsung,exynos4210-csis" for Exynos4210 (S5PC210),
+ "samsung,exynos4212-csis" for Exynos4212/Exynos4412
+ SoC series;
+- reg : offset and length of the register set for the device;
+- interrupts : should contain MIPI CSIS interrupt; the format of the
+ interrupt specifier depends on the interrupt controller;
+- bus-width : maximum number of data lanes supported (SoC specific);
+- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V);
+- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V);
+- clocks : list of clock specifiers, corresponding to entries in
+ clock-names property;
+- clock-names : must contain "csis", "sclk_csis" entries, matching entries
+ in the clocks property.
+
+Optional properties:
+
+- clock-frequency : The IP's main (system bus) clock frequency in Hz, default
+ value when this property is not specified is 166 MHz;
+- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present
+ external clock from CMU will be used, or the bus clock if
+ if it's not specified.
+
+The device node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in Documentation/devicetree/bindings/
+media/video-interfaces.txt. The following are properties specific to those nodes.
+
+port node
+---------
+
+- reg : (required) must be 3 for camera C input (CSIS0) or 4 for
+ camera D input (CSIS1);
+
+endpoint node
+-------------
+
+- data-lanes : (required) an array specifying active physical MIPI-CSI2
+ data input lanes and their mapping to logical lanes; the
+ array's content is unused, only its length is meaningful;
+
+- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time;
+
+
+Example:
+
+ reg0: regulator@0 {
+ };
+
+ reg1: regulator@1 {
+ };
+
+/* SoC properties */
+
+ csis_0: csis@11880000 {
+ compatible = "samsung,exynos4210-csis";
+ reg = <0x11880000 0x1000>;
+ interrupts = <0 78 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+/* Board properties */
+
+ csis_0: csis@11880000 {
+ clock-frequency = <166000000>;
+ vddio-supply = <&reg0>;
+ vddcore-supply = <&reg1>;
+ port {
+ reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */
+ csis0_ep: endpoint {
+ remote-endpoint = <...>;
+ data-lanes = <1>, <2>;
+ samsung,csis-hs-settle = <12>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
new file mode 100644
index 000000000000..e022d2dc4962
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
@@ -0,0 +1,228 @@
+Common bindings for video receiver and transmitter interfaces
+
+General concept
+---------------
+
+Video data pipelines usually consist of external devices, e.g. camera sensors,
+controlled over an I2C, SPI or UART bus, and SoC internal IP blocks, including
+video DMA engines and video data processors.
+
+SoC internal blocks are described by DT nodes, placed similarly to other SoC
+blocks. External devices are represented as child nodes of their respective
+bus controller nodes, e.g. I2C.
+
+Data interfaces on all video devices are described by their child 'port' nodes.
+Configuration of a port depends on other devices participating in the data
+transfer and is described by 'endpoint' subnodes.
+
+device {
+ ...
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ ...
+ endpoint@0 { ... };
+ endpoint@1 { ... };
+ };
+ port@1 { ... };
+ };
+};
+
+If a port can be configured to work with more than one remote device on the same
+bus, an 'endpoint' child node must be provided for each of them. If more than
+one port is present in a device node or there is more than one endpoint at a
+port, or port node needs to be associated with a selected hardware interface,
+a common scheme using '#address-cells', '#size-cells' and 'reg' properties is
+used.
+
+All 'port' nodes can be grouped under optional 'ports' node, which allows to
+specify #address-cells, #size-cells properties independently for the 'port'
+and 'endpoint' nodes and any child device nodes a device might have.
+
+Two 'endpoint' nodes are linked with each other through their 'remote-endpoint'
+phandles. An endpoint subnode of a device contains all properties needed for
+configuration of this device for data exchange with other device. In most
+cases properties at the peer 'endpoint' nodes will be identical, however they
+might need to be different when there is any signal modifications on the bus
+between two devices, e.g. there are logic signal inverters on the lines.
+
+It is allowed for multiple endpoints at a port to be active simultaneously,
+where supported by a device. For example, in case where a data interface of
+a device is partitioned into multiple data busses, e.g. 16-bit input port
+divided into two separate ITU-R BT.656 8-bit busses. In such case bus-width
+and data-shift properties can be used to assign physical data lines to each
+endpoint node (logical bus).
+
+
+Required properties
+-------------------
+
+If there is more than one 'port' or more than one 'endpoint' node or 'reg'
+property is present in port and/or endpoint nodes the following properties
+are required in a relevant parent node:
+
+ - #address-cells : number of cells required to define port/endpoint
+ identifier, should be 1.
+ - #size-cells : should be zero.
+
+Optional endpoint properties
+----------------------------
+
+- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node.
+- slave-mode: a boolean property indicating that the link is run in slave mode.
+ The default when this property is not specified is master mode. In the slave
+ mode horizontal and vertical synchronization signals are provided to the
+ slave device (data source) by the master device (data sink). In the master
+ mode the data source device is also the source of the synchronization signals.
+- bus-width: number of data lines actively used, valid for the parallel busses.
+- data-shift: on the parallel data busses, if bus-width is used to specify the
+ number of data lines, data-shift can be used to specify which data lines are
+ used, e.g. "bus-width=<8>; data-shift=<2>;" means, that lines 9:2 are used.
+- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively.
+- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively.
+ Note, that if HSYNC and VSYNC polarities are not specified, embedded
+ synchronization may be required, where supported.
+- data-active: similar to HSYNC and VSYNC, specifies data line polarity.
+- field-even-active: field signal level during the even field data transmission.
+- pclk-sample: sample data on rising (1) or falling (0) edge of the pixel clock
+ signal.
+- data-lanes: an array of physical data lane indexes. Position of an entry
+ determines the logical lane number, while the value of an entry indicates
+ physical lane, e.g. for 2-lane MIPI CSI-2 bus we could have
+ "data-lanes = <1 2>;", assuming the clock lane is on hardware lane 0.
+ This property is valid for serial busses only (e.g. MIPI CSI-2).
+- clock-lanes: an array of physical clock lane indexes. Position of an entry
+ determines the logical lane number, while the value of an entry indicates
+ physical lane, e.g. for a MIPI CSI-2 bus we could have "clock-lanes = <0>;",
+ which places the clock lane on hardware lane 0. This property is valid for
+ serial busses only (e.g. MIPI CSI-2). Note that for the MIPI CSI-2 bus this
+ array contains only one entry.
+- clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous
+ clock mode.
+
+
+Example
+-------
+
+The example snippet below describes two data pipelines. ov772x and imx074 are
+camera sensors with a parallel and serial (MIPI CSI-2) video bus respectively.
+Both sensors are on the I2C control bus corresponding to the i2c0 controller
+node. ov772x sensor is linked directly to the ceu0 video host interface.
+imx074 is linked to ceu0 through the MIPI CSI-2 receiver (csi2). ceu0 has a
+(single) DMA engine writing captured data to memory. ceu0 node has a single
+'port' node which may indicate that at any time only one of the following data
+pipelines can be active: ov772x -> ceu0 or imx074 -> csi2 -> ceu0.
+
+ ceu0: ceu@0xfe910000 {
+ compatible = "renesas,sh-mobile-ceu";
+ reg = <0xfe910000 0xa0>;
+ interrupts = <0x880>;
+
+ mclk: master_clock {
+ compatible = "renesas,ceu-clock";
+ #clock-cells = <1>;
+ clock-frequency = <50000000>; /* Max clock frequency */
+ clock-output-names = "mclk";
+ };
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Parallel bus endpoint */
+ ceu0_1: endpoint@1 {
+ reg = <1>; /* Local endpoint # */
+ remote = <&ov772x_1_1>; /* Remote phandle */
+ bus-width = <8>; /* Used data lines */
+ data-shift = <2>; /* Lines 9:2 are used */
+
+ /* If hsync-active/vsync-active are missing,
+ embedded BT.656 sync is used */
+ hsync-active = <0>; /* Active low */
+ vsync-active = <0>; /* Active low */
+ data-active = <1>; /* Active high */
+ pclk-sample = <1>; /* Rising */
+ };
+
+ /* MIPI CSI-2 bus endpoint */
+ ceu0_0: endpoint@0 {
+ reg = <0>;
+ remote = <&csi2_2>;
+ };
+ };
+ };
+
+ i2c0: i2c@0xfff20000 {
+ ...
+ ov772x_1: camera@0x21 {
+ compatible = "omnivision,ov772x";
+ reg = <0x21>;
+ vddio-supply = <&regulator1>;
+ vddcore-supply = <&regulator2>;
+
+ clock-frequency = <20000000>;
+ clocks = <&mclk 0>;
+ clock-names = "xclk";
+
+ port {
+ /* With 1 endpoint per port no need for addresses. */
+ ov772x_1_1: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&ceu0_1>;
+ hsync-active = <1>;
+ vsync-active = <0>; /* Who came up with an
+ inverter here ?... */
+ data-active = <1>;
+ pclk-sample = <1>;
+ };
+ };
+ };
+
+ imx074: camera@0x1a {
+ compatible = "sony,imx074";
+ reg = <0x1a>;
+ vddio-supply = <&regulator1>;
+ vddcore-supply = <&regulator2>;
+
+ clock-frequency = <30000000>; /* Shared clock with ov772x_1 */
+ clocks = <&mclk 0>;
+ clock-names = "sysclk"; /* Assuming this is the
+ name in the datasheet */
+ port {
+ imx074_1: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2>;
+ remote-endpoint = <&csi2_1>;
+ };
+ };
+ };
+ };
+
+ csi2: csi2@0xffc90000 {
+ compatible = "renesas,sh-mobile-csi2";
+ reg = <0xffc90000 0x1000>;
+ interrupts = <0x17a0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ compatible = "renesas,csi2c"; /* One of CSI2I and CSI2C. */
+ reg = <1>; /* CSI-2 PHY #1 of 2: PHY_S,
+ PHY_M has port address 0,
+ is unused. */
+ csi2_1: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <2 1>;
+ remote-endpoint = <&imx074_1>;
+ };
+ };
+ port@2 {
+ reg = <2>; /* port 2: link to the CEU */
+
+ csi2_2: endpoint {
+ remote-endpoint = <&ceu0_0>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/metag/meta-intc.txt b/Documentation/devicetree/bindings/metag/meta-intc.txt
index 8c47dcbfabc6..80994adab392 100644
--- a/Documentation/devicetree/bindings/metag/meta-intc.txt
+++ b/Documentation/devicetree/bindings/metag/meta-intc.txt
@@ -12,7 +12,7 @@ Required properties:
handle 32 interrupt sources).
- interrupt-controller: The presence of this property identifies the node
- as an interupt controller. No property value shall be defined.
+ 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.
diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
index baf07987ae68..abd9e3cb2db7 100644
--- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt
+++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
@@ -10,10 +10,40 @@ Optional properties:
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
-- regulators : Contain the regulator nodes. The MC13892 regulators are
- bound using their names as listed below with their registers and bits
- for enabling.
+- regulators : Contain the regulator nodes. The regulators are bound using
+ their names as listed below with their registers and bits for enabling.
+MC13783 regulators:
+ sw1a : regulator SW1A (register 24, bit 0)
+ sw1b : regulator SW1B (register 25, bit 0)
+ sw2a : regulator SW2A (register 26, bit 0)
+ sw2b : regulator SW2B (register 27, bit 0)
+ sw3 : regulator SW3 (register 29, bit 20)
+ vaudio : regulator VAUDIO (register 32, bit 0)
+ viohi : regulator VIOHI (register 32, bit 3)
+ violo : regulator VIOLO (register 32, bit 6)
+ vdig : regulator VDIG (register 32, bit 9)
+ vgen : regulator VGEN (register 32, bit 12)
+ vrfdig : regulator VRFDIG (register 32, bit 15)
+ vrfref : regulator VRFREF (register 32, bit 18)
+ vrfcp : regulator VRFCP (register 32, bit 21)
+ vsim : regulator VSIM (register 33, bit 0)
+ vesim : regulator VESIM (register 33, bit 3)
+ vcam : regulator VCAM (register 33, bit 6)
+ vrfbg : regulator VRFBG (register 33, bit 9)
+ vvib : regulator VVIB (register 33, bit 11)
+ vrf1 : regulator VRF1 (register 33, bit 12)
+ vrf2 : regulator VRF2 (register 33, bit 15)
+ vmmc1 : regulator VMMC1 (register 33, bit 18)
+ vmmc2 : regulator VMMC2 (register 33, bit 21)
+ gpo1 : regulator GPO1 (register 34, bit 6)
+ gpo2 : regulator GPO2 (register 34, bit 8)
+ gpo3 : regulator GPO3 (register 34, bit 10)
+ gpo4 : regulator GPO4 (register 34, bit 12)
+ pwgt1spi : regulator PWGT1SPI (register 34, bit 15)
+ pwgt2spi : regulator PWGT2SPI (register 34, bit 16)
+
+MC13892 regulators:
vcoincell : regulator VCOINCELL (register 13, bit 23)
sw1 : regulator SW1 (register 24, bit 0)
sw2 : regulator SW2 (register 25, bit 0)
diff --git a/Documentation/devicetree/bindings/misc/sram.txt b/Documentation/devicetree/bindings/misc/sram.txt
new file mode 100644
index 000000000000..4d0a00e453a8
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/sram.txt
@@ -0,0 +1,16 @@
+Generic on-chip SRAM
+
+Simple IO memory regions to be managed by the genalloc API.
+
+Required properties:
+
+- compatible : mmio-sram
+
+- reg : SRAM iomem address range
+
+Example:
+
+sram: sram@5c000000 {
+ compatible = "mmio-sram";
+ reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */
+};
diff --git a/Documentation/devicetree/bindings/net/can/atmel-can.txt b/Documentation/devicetree/bindings/net/can/atmel-can.txt
new file mode 100644
index 000000000000..72cf0c5daff4
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/atmel-can.txt
@@ -0,0 +1,14 @@
+* AT91 CAN *
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9263-can" or "atmel,at91sam9x5-can"
+ - reg: Should contain CAN controller registers location and length
+ - interrupts: Should contain IRQ line for the CAN controller
+
+Example:
+
+ can0: can@f000c000 {
+ compatbile = "atmel,at91sam9x5-can";
+ reg = <0xf000c000 0x300>;
+ interrupts = <40 4 5>
+ };
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index ecfdf756d10f..4f2ca6b4a182 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -15,16 +15,22 @@ Required properties:
- mac_control : Specifies Default MAC control register content
for the specific platform
- slaves : Specifies number for slaves
-- cpts_active_slave : Specifies the slave to use for time stamping
+- active_slave : Specifies the slave to use for time stamping,
+ ethtool and SIOCGMIIPHY
- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds
- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds
-- phy_id : Specifies slave phy id
-- mac-address : Specifies slave MAC address
Optional properties:
- ti,hwmods : Must be "cpgmac0"
- no_bd_ram : Must be 0 or 1
- dual_emac : Specifies Switch to act as Dual EMAC
+
+Slave Properties:
+Required properties:
+- phy_id : Specifies slave phy id
+- mac-address : Specifies slave MAC address
+
+Optional properties:
- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
Note: "ti,hwmods" field is used to fetch the base address and irq
@@ -47,7 +53,7 @@ Examples:
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
- cpts_active_slave = <0>;
+ active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
cpsw_emac0: slave@0 {
@@ -73,7 +79,7 @@ Examples:
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
- cpts_active_slave = <0>;
+ active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
cpsw_emac0: slave@0 {
diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
new file mode 100644
index 000000000000..49f4f7ae3f51
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
@@ -0,0 +1,91 @@
+Marvell Distributed Switch Architecture Device Tree Bindings
+------------------------------------------------------------
+
+Required properties:
+- compatible : Should be "marvell,dsa"
+- #address-cells : Must be 2, first cell is the address on the MDIO bus
+ and second cell is the address in the switch tree.
+ Second cell is used only when cascading/chaining.
+- #size-cells : Must be 0
+- dsa,ethernet : Should be a phandle to a valid Ethernet device node
+- dsa,mii-bus : Should be a phandle to a valid MDIO bus device node
+
+Optionnal properties:
+- interrupts : property with a value describing the switch
+ interrupt number (not supported by the driver)
+
+A DSA node can contain multiple switch chips which are therefore child nodes of
+the parent DSA node. The maximum number of allowed child nodes is 4
+(DSA_MAX_SWITCHES).
+Each of these switch child nodes should have the following required properties:
+
+- reg : Describes the switch address on the MII bus
+- #address-cells : Must be 1
+- #size-cells : Must be 0
+
+A switch may have multiple "port" children nodes
+
+Each port children node must have the following mandatory properties:
+- reg : Describes the port address in the switch
+- label : Describes the label associated with this port, special
+ labels are "cpu" to indicate a CPU port and "dsa" to
+ indicate an uplink/downlink port.
+
+Note that a port labelled "dsa" will imply checking for the uplink phandle
+described below.
+
+Optionnal property:
+- link : Should be a phandle to another switch's DSA port.
+ This property is only used when switches are being
+ chained/cascaded together.
+
+Example:
+
+ dsa@0 {
+ compatible = "marvell,dsa";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ interrupts = <10>;
+ dsa,ethernet = <&ethernet0>;
+ dsa,mii-bus = <&mii_bus0>;
+
+ switch@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <16 0>; /* MDIO address 16, switch 0 in tree */
+
+ port@0 {
+ reg = <0>;
+ label = "lan1";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan2";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "cpu";
+ };
+
+ switch0uplink: port@6 {
+ reg = <6>;
+ label = "dsa";
+ link = <&switch1uplink>;
+ };
+ };
+
+ switch@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <17 1>; /* MDIO address 17, switch 1 in tree */
+
+ switch1uplink: port@0 {
+ reg = <0>;
+ label = "dsa";
+ link = <&switch0uplink>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
index 34e7aafa321c..9417e54c26c0 100644
--- a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
+++ b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
@@ -9,6 +9,10 @@ Required properties:
- compatible: "marvell,orion-mdio"
- reg: address and length of the SMI register
+Optional properties:
+- interrupts: interrupt line number for the SMI error/done interrupt
+- clocks: Phandle to the clock control device and gate bit
+
The child nodes of the MDIO driver are the individual PHY devices
connected to this MDIO bus. They must have a "reg" property given the
PHY address on the MDIO bus.
diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
index bc50899e0c81..648d60eb9fd8 100644
--- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
@@ -1,6 +1,6 @@
* Atmel AT91 Pinmux Controller
-The AT91 Pinmux Controler, enables the IC
+The AT91 Pinmux Controller, enables the IC
to share one PAD to several functional blocks. The sharing is done by
multiplexing the PAD input/output signals. For each PAD there are up to
8 muxing options (called periph modes). Since different modules require
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
index 8edc20e1b09e..2569866c692f 100644
--- a/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
@@ -5,7 +5,7 @@ controller, and pinmux/control device.
Required properties:
- compatible: "brcm,bcm2835-gpio"
-- reg: Should contain the physical address of the GPIO module's registes.
+- reg: Should contain the physical address of the GPIO module's registers.
- gpio-controller: Marks the device node as a GPIO controller.
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify optional parameters:
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 2c81e45f1374..08f0c3d01575 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -1,7 +1,9 @@
One-register-per-pin type device tree based pinctrl driver
Required properties:
-- compatible : "pinctrl-single"
+- compatible : "pinctrl-single" or "pinconf-single".
+ "pinctrl-single" means that pinconf isn't supported.
+ "pinconf-single" means that generic pinconf is supported.
- reg : offset and length of the register set for the mux registers
@@ -14,9 +16,61 @@ Optional properties:
- pinctrl-single,function-off : function off mode for disabled state if
available and same for all registers; if not specified, disabling of
pin functions is ignored
+
- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
more than one pin
+- pinctrl-single,drive-strength : array of value that are used to configure
+ drive strength in the pinmux register. They're value of drive strength
+ current and drive strength mask.
+
+ /* drive strength current, mask */
+ pinctrl-single,power-source = <0x30 0xf0>;
+
+- pinctrl-single,bias-pullup : array of value that are used to configure the
+ input bias pullup in the pinmux register.
+
+ /* input, enabled pullup bits, disabled pullup bits, mask */
+ pinctrl-single,bias-pullup = <0 1 0 1>;
+
+- pinctrl-single,bias-pulldown : array of value that are used to configure the
+ input bias pulldown in the pinmux register.
+
+ /* input, enabled pulldown bits, disabled pulldown bits, mask */
+ pinctrl-single,bias-pulldown = <2 2 0 2>;
+
+ * Two bits to control input bias pullup and pulldown: User should use
+ pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. One bit means
+ pullup, and the other one bit means pulldown.
+ * Three bits to control input bias enable, pullup and pulldown. User should
+ use pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. Input bias
+ enable bit should be included in pullup or pulldown bits.
+ * Although driver could set PIN_CONFIG_BIAS_DISABLE, there's no property as
+ pinctrl-single,bias-disable. Because pinctrl single driver could implement
+ it by calling pulldown, pullup disabled.
+
+- pinctrl-single,input-schmitt : array of value that are used to configure
+ input schmitt in the pinmux register. In some silicons, there're two input
+ schmitt value (rising-edge & falling-edge) in the pinmux register.
+
+ /* input schmitt value, mask */
+ pinctrl-single,input-schmitt = <0x30 0x70>;
+
+- pinctrl-single,input-schmitt-enable : array of value that are used to
+ configure input schmitt enable or disable in the pinmux register.
+
+ /* input, enable bits, disable bits, mask */
+ pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>;
+
+- pinctrl-single,gpio-range : list of value that are used to configure a GPIO
+ range. They're value of subnode phandle, pin base in pinctrl device, pin
+ number in this range, GPIO function value of this GPIO range.
+ The number of parameters is depend on #pinctrl-single,gpio-range-cells
+ property.
+
+ /* pin base, nr pins & gpio function */
+ pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>;
+
This driver assumes that there is only one register for each pin (unless the
pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
specified in the pinctrl-bindings.txt document in this directory.
@@ -42,6 +96,20 @@ Where 0xdc is the offset from the pinctrl register base address for the
device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to
be used when applying this change to the register.
+
+Optional sub-node: In case some pins could be configured as GPIO in the pinmux
+register, those pins could be defined as a GPIO range. This sub-node is required
+by pinctrl-single,gpio-range property.
+
+Required properties in sub-node:
+- #pinctrl-single,gpio-range-cells : the number of parameters after phandle in
+ pinctrl-single,gpio-range property.
+
+ range: gpio-range {
+ #pinctrl-single,gpio-range-cells = <3>;
+ };
+
+
Example:
/* SoC common file */
@@ -58,7 +126,7 @@ pmx_core: pinmux@4a100040 {
/* second controller instance for pins in wkup domain */
pmx_wkup: pinmux@4a31e040 {
- compatible = "pinctrl-single;
+ compatible = "pinctrl-single";
reg = <0x4a31e040 0x0038>;
#address-cells = <1>;
#size-cells = <0>;
@@ -76,6 +144,29 @@ control_devconf0: pinmux@48002274 {
pinctrl-single,function-mask = <0x5F>;
};
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux@d401e000 {
+ compatible = "pinconf-single";
+ reg = <0xd401e000 0x0330>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <7>;
+
+ /* sparse GPIO range could be supported */
+ pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1
+ &range 12 1 0 &range 13 29 1
+ &range 43 1 0 &range 44 49 1
+ &range 94 1 1 &range 96 2 1>;
+
+ range: gpio-range {
+ #pinctrl-single,gpio-range-cells = <3>;
+ };
+};
+
+
/* board specific .dts file */
&pmx_core {
@@ -96,6 +187,15 @@ control_devconf0: pinmux@48002274 {
>;
};
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ 0x208 0 /* UART0_RXD (IOCFG138) */
+ 0x20c 0 /* UART0_TXD (IOCFG139) */
+ >;
+ pinctrl-single,bias-pulldown = <0 2 2>;
+ pinctrl-single,bias-pullup = <0 1 1>;
+ };
+
/* map uart2 pins */
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
@@ -122,6 +222,11 @@ control_devconf0: pinmux@48002274 {
};
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+};
+
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_pins>;
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 4598a47aa0cd..c70fca146e91 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -7,6 +7,7 @@ on-chip controllers onto these pads.
Required Properties:
- compatible: should be one of the following.
+ - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller,
- "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller.
- "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
- "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
@@ -105,6 +106,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
- compatible: identifies the type of the external wakeup interrupt controller
The possible values are:
+ - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller
+ found on Samsung S3C64xx SoCs,
- samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
found on Samsung Exynos4210 SoC.
- interrupt-parent: phandle of the interrupt parent to which the external
diff --git a/Documentation/devicetree/bindings/power_supply/power_supply.txt b/Documentation/devicetree/bindings/power_supply/power_supply.txt
new file mode 100644
index 000000000000..8391bfa0edac
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/power_supply.txt
@@ -0,0 +1,23 @@
+Power Supply Core Support
+
+Optional Properties:
+ - power-supplies : This property is added to a supply in order to list the
+ devices which supply it power, referenced by their phandles.
+
+Example:
+
+ usb-charger: power@e {
+ compatible = "some,usb-charger";
+ ...
+ };
+
+ ac-charger: power@c {
+ compatible = "some,ac-charger";
+ ...
+ };
+
+ battery@b {
+ compatible = "some,battery";
+ ...
+ power-supplies = <&usb-charger>, <&ac-charger>;
+ };
diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
index 9a599d27bd75..0347d8350d94 100644
--- a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
+++ b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt
@@ -2,7 +2,7 @@
QNAP NAS devices have a microcontroller controlling the main power
supply. This microcontroller is connected to UART1 of the Kirkwood and
-Orion5x SoCs. Sending the charactor 'A', at 19200 baud, tells the
+Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the
microcontroller to turn the power off. This driver adds a handler to
pm_power_off which is called to turn the power off.
diff --git a/Documentation/devicetree/bindings/power_supply/tps65090.txt b/Documentation/devicetree/bindings/power_supply/tps65090.txt
new file mode 100644
index 000000000000..8e5e0d3910df
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/tps65090.txt
@@ -0,0 +1,17 @@
+TPS65090 Frontend PMU with Switchmode Charger
+
+Required Properties:
+-compatible: "ti,tps65090-charger"
+
+Optional Properties:
+-ti,enable-low-current-chrg: Enables charging when a low current is detected
+ while the default logic is to stop charging.
+
+This node is a subnode of the tps65090 PMIC.
+
+Example:
+
+ tps65090-charger {
+ compatible = "ti,tps65090-charger";
+ ti,enable-low-current-chrg;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/max8952.txt b/Documentation/devicetree/bindings/regulator/max8952.txt
new file mode 100644
index 000000000000..866fcdd0f4eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/max8952.txt
@@ -0,0 +1,52 @@
+Maxim MAX8952 voltage regulator
+
+Required properties:
+- compatible: must be equal to "maxim,max8952"
+- reg: I2C slave address, usually 0x60
+- max8952,dvs-mode-microvolt: array of 4 integer values defining DVS voltages
+ in microvolts. All values must be from range <770000, 1400000>
+- any required generic properties defined in regulator.txt
+
+Optional properties:
+- max8952,vid-gpios: array of two GPIO pins used for DVS voltage selection
+- max8952,en-gpio: GPIO used to control enable status of regulator
+- max8952,default-mode: index of default DVS voltage, from <0, 3> range
+- max8952,sync-freq: sync frequency, must be one of following values:
+ - 0: 26 MHz
+ - 1: 13 MHz
+ - 2: 19.2 MHz
+ Defaults to 26 MHz if not specified.
+- max8952,ramp-speed: voltage ramp speed, must be one of following values:
+ - 0: 32mV/us
+ - 1: 16mV/us
+ - 2: 8mV/us
+ - 3: 4mV/us
+ - 4: 2mV/us
+ - 5: 1mV/us
+ - 6: 0.5mV/us
+ - 7: 0.25mV/us
+ Defaults to 32mV/us if not specified.
+- any available generic properties defined in regulator.txt
+
+Example:
+
+ vdd_arm_reg: pmic@60 {
+ compatible = "maxim,max8952";
+ reg = <0x60>;
+
+ /* max8952-specific properties */
+ max8952,vid-gpios = <&gpx0 3 0>, <&gpx0 4 0>;
+ max8952,en-gpio = <&gpx0 1 0>;
+ max8952,default-mode = <0>;
+ max8952,dvs-mode-microvolt = <1250000>, <1200000>,
+ <1050000>, <950000>;
+ max8952,sync-freq = <0>;
+ max8952,ramp-speed = <0>;
+
+ /* generic regulator properties */
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <770000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/max8997-regulator.txt b/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
index 9fd69a18b0ba..9e5e51d78868 100644
--- a/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
@@ -28,7 +28,7 @@ Required properties:
safe operating voltage).
If either of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional
- property is specified, then all the eigth voltage values for the
+ property is specified, then all the eight voltage values for the
'max8997,pmic-buck[1/2/5]-dvs-voltage' should be specified.
Optional properties:
diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt
new file mode 100644
index 000000000000..2a3feabd3b22
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt
@@ -0,0 +1,15 @@
+Atmel AT91RM9200 Real Time Clock
+
+Required properties:
+- compatible: should be: "atmel,at91rm9200-rtc"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- interrupts: rtc alarm/event interrupt
+
+Example:
+
+rtc@fffffe00 {
+ compatible = "atmel,at91rm9200-rtc";
+ reg = <0xfffffe00 0x100>;
+ interrupts = <1 4 7>;
+};
diff --git a/Documentation/devicetree/bindings/serio/snps-arc_ps2.txt b/Documentation/devicetree/bindings/serio/snps-arc_ps2.txt
new file mode 100644
index 000000000000..38c2f21e8044
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/snps-arc_ps2.txt
@@ -0,0 +1,16 @@
+* ARC PS/2 driver: PS/2 block used in some ARC FPGA's & nSIM OSCI model
+
+Required properties:
+- compatible : "snps,arc_ps2"
+- reg : offset and length (always 0x14) of registers
+- interrupts : interrupt
+- interrupt-names : name of interrupt, must be "arc_ps2_irq"
+
+Example:
+
+serio@c9000400 {
+ compatible = "snps,arc_ps2";
+ reg = <0xc9000400 0x14>;
+ interrupts = <13>;
+ interrupt-names = "arc_ps2_irq";
+}
diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt
new file mode 100644
index 000000000000..8bf89c643640
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt
@@ -0,0 +1,22 @@
+Broadcom BCM2835 SPI0 controller
+
+The BCM2835 contains two forms of SPI master controller, one known simply as
+SPI0, and the other known as the "Universal SPI Master"; part of the
+auxilliary block. This binding applies to the SPI0 controller.
+
+Required properties:
+- compatible: Should be "brcm,bcm2835-spi".
+- reg: Should contain register location and length.
+- interrupts: Should contain interrupt.
+- clocks: The clock feeding the SPI controller.
+
+Example:
+
+spi@20204000 {
+ compatible = "brcm,bcm2835-spi";
+ reg = <0x7e204000 0x1000>;
+ interrupts = <2 22>;
+ clocks = <&clk_spi>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/fsl-spi.txt b/Documentation/devicetree/bindings/spi/fsl-spi.txt
index 777abd7399d5..b032dd76e9d2 100644
--- a/Documentation/devicetree/bindings/spi/fsl-spi.txt
+++ b/Documentation/devicetree/bindings/spi/fsl-spi.txt
@@ -4,7 +4,7 @@ Required properties:
- cell-index : QE SPI subblock index.
0: QE subblock SPI1
1: QE subblock SPI2
-- compatible : should be "fsl,spi".
+- compatible : should be "fsl,spi" or "aeroflexgaisler,spictrl".
- mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
- reg : Offset and length of the register set for the device
- interrupts : <a b> where a is the interrupt number and b is a
@@ -14,6 +14,7 @@ Required properties:
controller you have.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.
+- clock-frequency : input clock frequency to non FSL_SOC cores
Optional properties:
- gpios : specifies the gpio pins to be used for chipselects.
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
new file mode 100644
index 000000000000..91ff771c7e77
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
@@ -0,0 +1,26 @@
+NVIDIA Tegra114 SPI controller.
+
+Required properties:
+- compatible : should be "nvidia,tegra114-spi".
+- reg: Should contain SPI registers location and length.
+- interrupts: Should contain SPI interrupts.
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+ request selector for this SPI controller.
+- This is also require clock named "spi" as per binding document
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Recommended properties:
+- spi-max-frequency: Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+Example:
+
+spi@7000d600 {
+ compatible = "nvidia,tegra114-spi";
+ reg = <0x7000d600 0x200>;
+ interrupts = <0 82 0x04>;
+ nvidia,dma-request-selector = <&apbdma 16>;
+ spi-max-frequency = <25000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt
index a15ffeddfba4..86aa061f069f 100644
--- a/Documentation/devicetree/bindings/spi/spi-samsung.txt
+++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt
@@ -31,9 +31,6 @@ Required Board Specific Properties:
- #address-cells: should be 1.
- #size-cells: should be 0.
-- gpios: The gpio specifier for clock, mosi and miso interface lines (in the
- order specified). The format of the gpio specifier depends on the gpio
- controller.
Optional Board Specific Properties:
@@ -86,9 +83,8 @@ Example:
spi_0: spi@12d20000 {
#address-cells = <1>;
#size-cells = <0>;
- gpios = <&gpa2 4 2 3 0>,
- <&gpa2 6 2 3 0>,
- <&gpa2 7 2 3 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_bus>;
w25q80bw@0 {
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/staging/dwc2.txt b/Documentation/devicetree/bindings/staging/dwc2.txt
new file mode 100644
index 000000000000..1a1b7cfa4845
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/dwc2.txt
@@ -0,0 +1,15 @@
+Platform DesignWare HS OTG USB 2.0 controller
+-----------------------------------------------------
+
+Required properties:
+- compatible : "snps,dwc2"
+- reg : Should contain 1 register range (address and length)
+- interrupts : Should contain 1 interrupt
+
+Example:
+
+ usb@101c0000 {
+ compatible = "ralink,rt3050-usb, snps,dwc2";
+ reg = <0x101c0000 40000>;
+ interrupts = <18>;
+ };
diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index 07654f0338b6..8071ac20d4b3 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -26,7 +26,7 @@ Required properties:
- crtc: the crtc this display is connected to, see below
Optional properties:
- interface_pix_fmt: How this display is connected to the
- crtc. Currently supported types: "rgb24", "rgb565"
+ crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
- edid: verbatim EDID data block describing attached display.
- ddc: phandle describing the i2c bus handling the display data
channel
diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
index 8f01cb190f25..1928a3e83cd0 100644
--- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
+++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
@@ -33,6 +33,10 @@ Optional properties:
RTAS and should not be registered.
- no-loopback-test: set to indicate that the port does not implements loopback
test mode
+- fifo-size: the fifo size of the UART.
+- auto-flow-control: one way to enable automatic flow control support. The
+ driver is allowed to detect support for the capability even without this
+ property.
Example:
diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
index 5778b9c83bd8..1c04a4c9515f 100644
--- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
+++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
@@ -11,6 +11,7 @@ Optional properties:
that indicate usb controller index
- vbus-supply: regulator for vbus
- disable-over-current: disable over current detect
+- external-vbus-divider: enables off-chip resistor divider for Vbus
Examples:
usb@02184000 { /* USB OTG */
@@ -20,4 +21,5 @@ usb@02184000 { /* USB OTG */
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
disable-over-current;
+ external-vbus-divider;
};
diff --git a/Documentation/devicetree/bindings/usb/ehci-omap.txt b/Documentation/devicetree/bindings/usb/ehci-omap.txt
new file mode 100644
index 000000000000..485a9a1efa7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ehci-omap.txt
@@ -0,0 +1,32 @@
+OMAP HS USB EHCI controller
+
+This device is usually the child of the omap-usb-host
+Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+
+Required properties:
+
+- compatible: should be "ti,ehci-omap"
+- reg: should contain one register range i.e. start and length
+- interrupts: description of the interrupt line
+
+Optional properties:
+
+- phys: list of phandles to PHY nodes.
+ This property is required if at least one of the ports are in
+ PHY mode i.e. OMAP_EHCI_PORT_MODE_PHY
+
+To specify the port mode, see
+Documentation/devicetree/bindings/mfd/omap-usb-host.txt
+
+Example for OMAP4:
+
+usbhsehci: ehci@4a064c00 {
+ compatible = "ti,ehci-omap", "usb-ehci";
+ reg = <0x4a064c00 0x400>;
+ interrupts = <0 77 0x4>;
+};
+
+&usbhsehci {
+ phys = <&hsusb1_phy 0 &hsusb3_phy>;
+};
+
diff --git a/Documentation/devicetree/bindings/usb/ohci-omap3.txt b/Documentation/devicetree/bindings/usb/ohci-omap3.txt
new file mode 100644
index 000000000000..14ab42812a8e
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ohci-omap3.txt
@@ -0,0 +1,15 @@
+OMAP HS USB OHCI controller (OMAP3 and later)
+
+Required properties:
+
+- compatible: should be "ti,ohci-omap3"
+- reg: should contain one register range i.e. start and length
+- interrupts: description of the interrupt line
+
+Example for OMAP4:
+
+usbhsohci: ohci@4a064800 {
+ compatible = "ti,ohci-omap3", "usb-ohci";
+ reg = <0x4a064800 0x400>;
+ interrupts = <0 76 0x4>;
+};
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index 1ef0ce71f8fa..662f0f1d2315 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -8,10 +8,10 @@ OMAP MUSB GLUE
and disconnect.
- multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting.
- - num_eps : Specifies the number of endpoints. This is also a
+ - num-eps : Specifies the number of endpoints. This is also a
MUSB configuration-specific setting. Should be set to "16"
- - ram_bits : Specifies the ram address size. Should be set to "12"
- - interface_type : This is a board specific setting to describe the type of
+ - ram-bits : Specifies the ram address size. Should be set to "12"
+ - interface-type : This is a board specific setting to describe the type of
interface between the controller and the phy. It should be "0" or "1"
specifying ULPI and UTMI respectively.
- mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
@@ -29,18 +29,46 @@ usb_otg_hs: usb_otg_hs@4a0ab000 {
ti,hwmods = "usb_otg_hs";
ti,has-mailbox;
multipoint = <1>;
- num_eps = <16>;
- ram_bits = <12>;
+ num-eps = <16>;
+ ram-bits = <12>;
ctrl-module = <&omap_control_usb>;
};
Board specific device node entry
&usb_otg_hs {
- interface_type = <1>;
+ interface-type = <1>;
mode = <3>;
power = <50>;
};
+OMAP DWC3 GLUE
+ - compatible : Should be "ti,dwc3"
+ - ti,hwmods : Should be "usb_otg_ss"
+ - reg : Address and length of the register set for the device.
+ - interrupts : The irq number of this device that is used to interrupt the
+ MPU
+ - #address-cells, #size-cells : Must be present if the device has sub-nodes
+ - utmi-mode : controls the source of UTMI/PIPE status for VBUS and OTG ID.
+ It should be set to "1" for HW mode and "2" for SW mode.
+ - ranges: the child address space are mapped 1:1 onto the parent address space
+
+Sub-nodes:
+The dwc3 core should be added as subnode to omap dwc3 glue.
+- dwc3 :
+ The binding details of dwc3 can be found in:
+ Documentation/devicetree/bindings/usb/dwc3.txt
+
+omap_dwc3 {
+ compatible = "ti,dwc3";
+ ti,hwmods = "usb_otg_ss";
+ reg = <0x4a020000 0x1ff>;
+ interrupts = <0 93 4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ utmi-mode = <2>;
+ ranges;
+};
+
OMAP CONTROL USB
Required properties:
diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
index 033194934f64..33fd3543f3f8 100644
--- a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
+++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt
@@ -1,20 +1,25 @@
-* Samsung's usb phy transceiver
+SAMSUNG USB-PHY controllers
-The Samsung's phy transceiver is used for controlling usb phy for
-s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers
-across Samsung SOCs.
+** 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
-developement generic PHY driver.
+development generic PHY driver.
Required properties:
Exynos4210:
-- compatible : should be "samsung,exynos4210-usbphy"
+- 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-usbphy"
+- compatible : should be "samsung,exynos5250-usb2phy"
- reg : base physical address of the phy registers and length of memory mapped
region.
@@ -44,12 +49,69 @@ Example:
usbphy@125B0000 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "samsung,exynos4210-usbphy";
+ 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>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
new file mode 100644
index 000000000000..d7e272671c7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/usb-nop-xceiv.txt
@@ -0,0 +1,34 @@
+USB NOP PHY
+
+Required properties:
+- compatible: should be usb-nop-xceiv
+
+Optional properties:
+- clocks: phandle to the PHY clock. Use as per Documentation/devicetree
+ /bindings/clock/clock-bindings.txt
+ This property is required if clock-frequency is specified.
+
+- clock-names: Should be "main_clk"
+
+- clock-frequency: the clock frequency (in Hz) that the PHY clock must
+ be configured to.
+
+- vcc-supply: phandle to the regulator that provides RESET to the PHY.
+
+- reset-supply: phandle to the regulator that provides power to the PHY.
+
+Example:
+
+ hsusb1_phy {
+ compatible = "usb-nop-xceiv";
+ clock-frequency = <19200000>;
+ clocks = <&osc 0>;
+ clock-names = "main_clk";
+ vcc-supply = <&hsusb1_vcc_regulator>;
+ reset-supply = <&hsusb1_reset_regulator>;
+ };
+
+hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
+and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
+hsusb1_vcc_regulator provides power to the PHY and hsusb1_reset_regulator
+controls RESET.
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 19e1ef73ab0d..4d1919bf2332 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -5,6 +5,7 @@ using them to avoid name-space collisions.
ad Avionic Design GmbH
adi Analog Devices, Inc.
+aeroflexgaisler Aeroflex Gaisler AB
ak Asahi Kasei Corp.
amcc Applied Micro Circuits Corporation (APM, formally AMCC)
apm Applied Micro Circuits Corporation (APM)
@@ -48,6 +49,7 @@ samsung Samsung Semiconductor
sbs Smart Battery System
schindler Schindler
sil Silicon Image
+silabs Silicon Laboratories
simtek
sirf SiRF Technology, Inc.
snps Synopsys, Inc.
diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
new file mode 100644
index 000000000000..1482103d288f
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
@@ -0,0 +1,41 @@
+lp855x bindings
+
+Required properties:
+ - compatible: "ti,lp8550", "ti,lp8551", "ti,lp8552", "ti,lp8553",
+ "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)
+
+Example:
+
+ /* 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>;
+
+ 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/tps65217-backlight.txt b/Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt
new file mode 100644
index 000000000000..5fb9279ac287
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/tps65217-backlight.txt
@@ -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>;
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt
index c870b6478ec8..2871e218a0fb 100644
--- a/Documentation/devicetree/bindings/video/via,vt8500-fb.txt
+++ b/Documentation/devicetree/bindings/video/via,vt8500-fb.txt
@@ -5,58 +5,32 @@ Required properties:
- compatible : "via,vt8500-fb"
- reg : Should contain 1 register ranges(address and length)
- interrupts : framebuffer controller interrupt
-- display: a phandle pointing to the display node
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
-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.
+Required subnodes:
+- display-timings: see display-timing.txt for information
Example:
- fb@d800e400 {
+ fb@d8050800 {
compatible = "via,vt8500-fb";
reg = <0xd800e400 0x400>;
interrupts = <12>;
- display = <&display>;
- default-mode = <&mode0>;
- };
-
-VIA VT8500 Display
------------------------------------------------------
-Required properties (as per of_videomode_helper):
-
- - 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: displayclock in Hz
- - bpp: lcd panel bit-depth.
- <16> for RGB565, <32> for RGB888
-
-Optional properties (as per of_videomode_helper):
- - width-mm, height-mm: Display dimensions in mm
- - hsync-active-high (bool): Hsync pulse is active high
- - vsync-active-high (bool): Vsync pulse is active high
- - interlaced (bool): This is an interlaced mode
- - doublescan (bool): This is a doublescan mode
+ bits-per-pixel = <16>;
-Example:
- display: display@0 {
- modes {
- mode0: mode@0 {
+ display-timings {
+ native-mode = <&timing0>;
+ timing0: 800x480 {
+ clock-frequency = <0>; /* unused but required */
hactive = <800>;
vactive = <480>;
- hback-porch = <88>;
hfront-porch = <40>;
+ hback-porch = <88>;
hsync-len = <0>;
vback-porch = <32>;
vfront-porch = <11>;
vsync-len = <1>;
- clock = <0>; /* unused but required */
- bpp = <16>; /* non-standard but required */
};
};
};
+
diff --git a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
index 3d325e1d11ee..0bcadb2840a5 100644
--- a/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
+++ b/Documentation/devicetree/bindings/video/wm,wm8505-fb.txt
@@ -4,20 +4,30 @@ Wondermedia WM8505 Framebuffer
Required properties:
- compatible : "wm,wm8505-fb"
- reg : Should contain 1 register ranges(address and length)
-- via,display: a phandle pointing to the display node
+- bits-per-pixel : bit depth of framebuffer (16 or 32)
-Required nodes:
-- display: a display node is required to initialize the lcd panel
- This should be in the board dts. See definition in
- Documentation/devicetree/bindings/video/via,vt8500-fb.txt
-- default-mode: a videomode node as specified in
- Documentation/devicetree/bindings/video/via,vt8500-fb.txt
+Required subnodes:
+- display-timings: see display-timing.txt for information
Example:
- fb@d8050800 {
+ fb@d8051700 {
compatible = "wm,wm8505-fb";
- reg = <0xd8050800 0x200>;
- display = <&display>;
- default-mode = <&mode0>;
+ 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/dma-buf-sharing.txt b/Documentation/dma-buf-sharing.txt
index 4966b1be42ac..0b23261561d2 100644
--- a/Documentation/dma-buf-sharing.txt
+++ b/Documentation/dma-buf-sharing.txt
@@ -52,14 +52,23 @@ The dma_buf buffer sharing API usage contains the following steps:
associated with this buffer.
Interface:
- struct dma_buf *dma_buf_export(void *priv, struct dma_buf_ops *ops,
- size_t size, int flags)
+ struct dma_buf *dma_buf_export_named(void *priv, struct dma_buf_ops *ops,
+ size_t size, int flags,
+ const char *exp_name)
If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a
pointer to the same. It also associates an anonymous file with this buffer,
so it can be exported. On failure to allocate the dma_buf object, it returns
NULL.
+ 'exp_name' is the name of exporter - to facilitate information while
+ debugging.
+
+ Exporting modules which do not wish to provide any specific name may use the
+ helper define 'dma_buf_export()', with the same arguments as above, but
+ without the last argument; a __FILE__ pre-processor directive will be
+ inserted in place of 'exp_name' instead.
+
2. Userspace gets a handle to pass around to potential buffer-users
Userspace entity requests for a file-descriptor (fd) which is a handle to the
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index 34ea4f1fa6ea..f7cbf574a875 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -494,6 +494,17 @@ Files in /sys/fs/ext4/<devname>
session_write_kbytes This file is read-only and shows the number of
kilobytes of data that have been written to this
filesystem since it was mounted.
+
+ reserved_clusters This is RW file and contains number of reserved
+ clusters in the file system which will be used
+ in the specific situations to avoid costly
+ zeroout, unexpected ENOSPC, or possible data
+ loss. The default is 2% or 4096 clusters,
+ whichever is smaller and this can be changed
+ however it can never exceed number of clusters
+ in the file system. If there is not enough space
+ for the reserved space when mounting the file
+ mount will _not_ fail.
..............................................................................
Ioctls
@@ -587,6 +598,16 @@ Table of Ext4 specific ioctls
bitmaps and inode table, the userspace tool thus
just passes the new number of blocks.
+EXT4_IOC_SWAP_BOOT Swap i_blocks and associated attributes
+ (like i_blocks, i_size, i_flags, ...) from
+ the specified inode with inode
+ EXT4_BOOT_LOADER_INO (#5). This is typically
+ used to store a boot loader in a secure part of
+ the filesystem, where it can't be changed by a
+ normal user by accident.
+ The data blocks of the previous boot loader
+ will be associated with the given inode.
+
..............................................................................
References
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index d230dd9c99b0..4a93e98b290a 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -150,12 +150,28 @@ discard -- If set, issues discard/TRIM commands to the block
device when blocks are freed. This is useful for SSD devices
and sparse/thinly-provisoned LUNs.
-nfs -- This option maintains an index (cache) of directory
- inodes by i_logstart which is used by the nfs-related code to
- improve look-ups.
+nfs=stale_rw|nostale_ro
+ Enable this only if you want to export the FAT filesystem
+ over NFS.
+
+ stale_rw: This option maintains an index (cache) of directory
+ inodes by i_logstart which is used by the nfs-related code to
+ improve look-ups. Full file operations (read/write) over NFS is
+ supported but with cache eviction at NFS server, this could
+ result in ESTALE issues.
+
+ nostale_ro: This option bases the inode number and filehandle
+ on the on-disk location of a file in the MS-DOS directory entry.
+ This ensures that ESTALE will not be returned after a file is
+ evicted from the inode cache. However, it means that operations
+ such as rename, create and unlink could cause filehandles that
+ previously pointed at one file to point at a different file,
+ potentially causing data corruption. For this reason, this
+ option also mounts the filesystem readonly.
+
+ To maintain backward compatibility, '-o nfs' is also accepted,
+ defaulting to stale_rw
- Enable this only if you want to export the FAT filesystem
- over NFS
<bool>: 0,1,yes,no,true,false
diff --git a/Documentation/hwmon/ab8500 b/Documentation/hwmon/ab8500
new file mode 100644
index 000000000000..cf169c8ef4e3
--- /dev/null
+++ b/Documentation/hwmon/ab8500
@@ -0,0 +1,22 @@
+Kernel driver ab8500
+====================
+
+Supported chips:
+ * ST-Ericsson AB8500
+ Prefix: 'ab8500'
+ Addresses scanned: -
+ Datasheet: http://www.stericsson.com/developers/documentation.jsp
+
+Authors:
+ Martin Persson <martin.persson@stericsson.com>
+ Hongbo Zhang <hongbo.zhang@linaro.org>
+
+Description
+-----------
+
+See also Documentation/hwmon/abx500. This is the ST-Ericsson AB8500 specific
+driver.
+
+Currently only the AB8500 internal sensor and one external sensor for battery
+temperature are monitored. Other GPADC channels can also be monitored if needed
+in future.
diff --git a/Documentation/hwmon/abx500 b/Documentation/hwmon/abx500
new file mode 100644
index 000000000000..319a058cec7c
--- /dev/null
+++ b/Documentation/hwmon/abx500
@@ -0,0 +1,28 @@
+Kernel driver abx500
+====================
+
+Supported chips:
+ * ST-Ericsson ABx500 series
+ Prefix: 'abx500'
+ Addresses scanned: -
+ Datasheet: http://www.stericsson.com/developers/documentation.jsp
+
+Authors:
+ Martin Persson <martin.persson@stericsson.com>
+ Hongbo Zhang <hongbo.zhang@linaro.org>
+
+Description
+-----------
+
+Every ST-Ericsson Ux500 SOC consists of both ABx500 and DBx500 physically,
+this is kernel hwmon driver for ABx500.
+
+There are some GPADCs inside ABx500 which are designed for connecting to
+thermal sensors, and there is also a thermal sensor inside ABx500 too, which
+raises interrupt when critical temperature reached.
+
+This abx500 is a common layer which can monitor all of the sensors, every
+specific abx500 chip has its special configurations in its own file, e.g. some
+sensors can be configured invisible if they are not available on that chip, and
+the corresponding gpadc_addr should be set to 0, thus this sensor won't be
+polled.
diff --git a/Documentation/hwmon/adt7410 b/Documentation/hwmon/adt7410
index 58150c480e56..9817941e5f19 100644
--- a/Documentation/hwmon/adt7410
+++ b/Documentation/hwmon/adt7410
@@ -12,29 +12,42 @@ Supported chips:
Addresses scanned: None
Datasheet: Publicly available at the Analog Devices website
http://www.analog.com/static/imported-files/data_sheets/ADT7420.pdf
+ * Analog Devices ADT7310
+ Prefix: 'adt7310'
+ Addresses scanned: None
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/static/imported-files/data_sheets/ADT7310.pdf
+ * Analog Devices ADT7320
+ Prefix: 'adt7320'
+ Addresses scanned: None
+ Datasheet: Publicly available at the Analog Devices website
+ http://www.analog.com/static/imported-files/data_sheets/ADT7320.pdf
Author: Hartmut Knaack <knaack.h@gmx.de>
Description
-----------
-The ADT7410 is a temperature sensor with rated temperature range of -55°C to
-+150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
-of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
-indicate that a minimum or maximum temperature set point has been exceeded, as
-well as a critical temperature (CT) pin to indicate that the critical
-temperature set point has been exceeded. Both pins can be set up with a common
-hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
-pins can individually set to be active-low or active-high, while the whole
-device can either run in comparator mode or interrupt mode. The ADT7410
-supports continous temperature sampling, as well as sampling one temperature
-value per second or even justget one sample on demand for power saving.
-Besides, it can completely power down its ADC, if power management is
-required.
-
-The ADT7420 is register compatible, the only differences being the package,
-a slightly narrower operating temperature range (-40°C to +150°C), and a
-better accuracy (0.25°C instead of 0.50°C.)
+The ADT7310/ADT7410 is a temperature sensor with rated temperature range of
+-55°C to +150°C. It has a high accuracy of +/-0.5°C and can be operated at a
+resolution of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an
+INT pin to indicate that a minimum or maximum temperature set point has been
+exceeded, as well as a critical temperature (CT) pin to indicate that the
+critical temperature set point has been exceeded. Both pins can be set up with a
+common hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events.
+Both pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410 supports
+continuous temperature sampling, as well as sampling one temperature value per
+second or even just get one sample on demand for power saving. Besides, it can
+completely power down its ADC, if power management is required.
+
+The ADT7320/ADT7420 is register compatible, the only differences being the
+package, a slightly narrower operating temperature range (-40°C to +150°C), and
+a better accuracy (0.25°C instead of 0.50°C.)
+
+The difference between the ADT7310/ADT7320 and ADT7410/ADT7420 is the control
+interface, the ADT7310 and ADT7320 use SPI while the ADT7410 and ADT7420 use
+I2C.
Configuration Notes
-------------------
diff --git a/Documentation/hwmon/lm25066 b/Documentation/hwmon/lm25066
index 26025e419d35..c1b57d72efc3 100644
--- a/Documentation/hwmon/lm25066
+++ b/Documentation/hwmon/lm25066
@@ -1,7 +1,13 @@
-Kernel driver max8688
+Kernel driver lm25066
=====================
Supported chips:
+ * TI LM25056
+ Prefix: 'lm25056'
+ Addresses scanned: -
+ Datasheets:
+ http://www.ti.com/lit/gpn/lm25056
+ http://www.ti.com/lit/gpn/lm25056a
* National Semiconductor LM25066
Prefix: 'lm25066'
Addresses scanned: -
@@ -25,8 +31,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
-This driver supports hardware montoring for National Semiconductor LM25066,
-LM5064, and LM5064 Power Management, Monitoring, Control, and Protection ICs.
+This driver supports hardware montoring for National Semiconductor / TI LM25056,
+LM25066, LM5064, and LM5064 Power Management, Monitoring, Control, and
+Protection ICs.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus for details on PMBus client drivers.
@@ -60,14 +67,19 @@ in1_max Maximum input voltage.
in1_min_alarm Input voltage low alarm.
in1_max_alarm Input voltage high alarm.
-in2_label "vout1"
-in2_input Measured output voltage.
-in2_average Average measured output voltage.
-in2_min Minimum output voltage.
-in2_min_alarm Output voltage low alarm.
-
-in3_label "vout2"
-in3_input Measured voltage on vaux pin
+in2_label "vmon"
+in2_input Measured voltage on VAUX pin
+in2_min Minimum VAUX voltage (LM25056 only).
+in2_max Maximum VAUX voltage (LM25056 only).
+in2_min_alarm VAUX voltage low alarm (LM25056 only).
+in2_max_alarm VAUX voltage high alarm (LM25056 only).
+
+in3_label "vout1"
+ Not supported on LM25056.
+in3_input Measured output voltage.
+in3_average Average measured output voltage.
+in3_min Minimum output voltage.
+in3_min_alarm Output voltage low alarm.
curr1_label "iin"
curr1_input Measured input current.
diff --git a/Documentation/hwmon/lm95234 b/Documentation/hwmon/lm95234
new file mode 100644
index 000000000000..a0e95ddfd372
--- /dev/null
+++ b/Documentation/hwmon/lm95234
@@ -0,0 +1,36 @@
+Kernel driver lm95234
+=====================
+
+Supported chips:
+ * National Semiconductor / Texas Instruments LM95234
+ Addresses scanned: I2C 0x18, 0x4d, 0x4e
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/product/lm95234
+
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
+Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
+the temperature of four remote diodes as well as its own temperature.
+The four remote diodes can be external devices such as microprocessors,
+graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
+beta compensation technology allows sensing of 90 nm or 65 nm process
+thermal diodes accurately.
+
+All temperature values are given in millidegrees Celsius. Temperature
+is provided within a range of -127 to +255 degrees (+127.875 degrees for
+the internal sensor). Resolution depends on temperature input and range.
+
+Each sensor has its own maximum limit, but the hysteresis is common to all
+channels. The hysteresis is configurable with the tem1_max_hyst attribute and
+affects the hysteresis on all channels. The first two external sensors also
+have a critical limit.
+
+The lm95234 driver can change its update interval to a fixed set of values.
+It will round up to the next selectable interval. See the datasheet for exact
+values. Reading sensor values more often will do no harm, but will return
+'old' values.
diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978
index e4d75c606c97..dc0d08c61305 100644
--- a/Documentation/hwmon/ltc2978
+++ b/Documentation/hwmon/ltc2978
@@ -2,6 +2,10 @@ Kernel driver ltc2978
=====================
Supported chips:
+ * Linear Technology LTC2974
+ Prefix: 'ltc2974'
+ Addresses scanned: -
+ Datasheet: http://www.linear.com/product/ltc2974
* Linear Technology LTC2978
Prefix: 'ltc2978'
Addresses scanned: -
@@ -10,6 +14,10 @@ Supported chips:
Prefix: 'ltc3880'
Addresses scanned: -
Datasheet: http://www.linear.com/product/ltc3880
+ * Linear Technology LTC3883
+ Prefix: 'ltc3883'
+ Addresses scanned: -
+ Datasheet: http://www.linear.com/product/ltc3883
Author: Guenter Roeck <linux@roeck-us.net>
@@ -17,9 +25,9 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
-The LTC2978 is an octal power supply monitor, supervisor, sequencer and
-margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous
-step-down switching regulator controller.
+LTC2974 is a quad digital power supply manager. LTC2978 is an octal power supply
+monitor. LTC3880 is a dual output poly-phase step-down DC/DC controller. LTC3883
+is a single phase step-down DC/DC controller.
Usage Notes
@@ -41,63 +49,90 @@ Sysfs attributes
in1_label "vin"
in1_input Measured input voltage.
in1_min Minimum input voltage.
-in1_max Maximum input voltage.
-in1_lcrit Critical minimum input voltage.
+in1_max Maximum input voltage. LTC2974 and LTC2978 only.
+in1_lcrit Critical minimum input voltage. LTC2974 and LTC2978
+ only.
in1_crit Critical maximum input voltage.
in1_min_alarm Input voltage low alarm.
-in1_max_alarm Input voltage high alarm.
-in1_lcrit_alarm Input voltage critical low alarm.
+in1_max_alarm Input voltage high alarm. LTC2974 and LTC2978 only.
+in1_lcrit_alarm Input voltage critical low alarm. LTC2974 and LTC2978
+ only.
in1_crit_alarm Input voltage critical high alarm.
-in1_lowest Lowest input voltage. LTC2978 only.
+in1_lowest Lowest input voltage. LTC2974 and LTC2978 only.
in1_highest Highest input voltage.
-in1_reset_history Reset history. Writing into this attribute will reset
- history for all attributes.
-
-in[2-9]_label "vout[1-8]". Channels 3 to 9 on LTC2978 only.
-in[2-9]_input Measured output voltage.
-in[2-9]_min Minimum output voltage.
-in[2-9]_max Maximum output voltage.
-in[2-9]_lcrit Critical minimum output voltage.
-in[2-9]_crit Critical maximum output voltage.
-in[2-9]_min_alarm Output voltage low alarm.
-in[2-9]_max_alarm Output voltage high alarm.
-in[2-9]_lcrit_alarm Output voltage critical low alarm.
-in[2-9]_crit_alarm Output voltage critical high alarm.
-in[2-9]_lowest Lowest output voltage. LTC2978 only.
-in[2-9]_highest Lowest output voltage.
-in[2-9]_reset_history Reset history. Writing into this attribute will reset
- history for all attributes.
-
-temp[1-3]_input Measured temperature.
+in1_reset_history Reset input voltage history.
+
+in[N]_label "vout[1-8]".
+ LTC2974: N=2-5
+ LTC2978: N=2-9
+ LTC3880: N=2-3
+ LTC3883: N=2
+in[N]_input Measured output voltage.
+in[N]_min Minimum output voltage.
+in[N]_max Maximum output voltage.
+in[N]_lcrit Critical minimum output voltage.
+in[N]_crit Critical maximum output voltage.
+in[N]_min_alarm Output voltage low alarm.
+in[N]_max_alarm Output voltage high alarm.
+in[N]_lcrit_alarm Output voltage critical low alarm.
+in[N]_crit_alarm Output voltage critical high alarm.
+in[N]_lowest Lowest output voltage. LTC2974 and LTC2978 only.
+in[N]_highest Highest output voltage.
+in[N]_reset_history Reset output voltage history.
+
+temp[N]_input Measured temperature.
+ On LTC2974, temp[1-4] report external temperatures,
+ and temp5 reports the chip temperature.
On LTC2978, only one temperature measurement is
- supported and reflects the internal temperature.
+ supported and reports the chip temperature.
On LTC3880, temp1 and temp2 report external
- temperatures, and temp3 reports the internal
- temperature.
-temp[1-3]_min Mimimum temperature.
-temp[1-3]_max Maximum temperature.
-temp[1-3]_lcrit Critical low temperature.
-temp[1-3]_crit Critical high temperature.
-temp[1-3]_min_alarm Chip temperature low alarm.
-temp[1-3]_max_alarm Chip temperature high alarm.
-temp[1-3]_lcrit_alarm Chip temperature critical low alarm.
-temp[1-3]_crit_alarm Chip temperature critical high alarm.
-temp[1-3]_lowest Lowest measured temperature. LTC2978 only.
-temp[1-3]_highest Highest measured temperature.
-temp[1-3]_reset_history Reset history. Writing into this attribute will reset
- history for all attributes.
-
-power[1-2]_label "pout[1-2]". LTC3880 only.
-power[1-2]_input Measured power.
-
-curr1_label "iin". LTC3880 only.
+ temperatures, and temp3 reports the chip temperature.
+ On LTC3883, temp1 reports an external temperature,
+ and temp2 reports the chip temperature.
+temp[N]_min Mimimum temperature. LTC2974 and LTC2978 only.
+temp[N]_max Maximum temperature.
+temp[N]_lcrit Critical low temperature.
+temp[N]_crit Critical high temperature.
+temp[N]_min_alarm Temperature low alarm. LTC2974 and LTC2978 only.
+temp[N]_max_alarm Temperature high alarm.
+temp[N]_lcrit_alarm Temperature critical low alarm.
+temp[N]_crit_alarm Temperature critical high alarm.
+temp[N]_lowest Lowest measured temperature. LTC2974 and LTC2978 only.
+ Not supported for chip temperature sensor on LTC2974.
+temp[N]_highest Highest measured temperature. Not supported for chip
+ temperature sensor on LTC2974.
+temp[N]_reset_history Reset temperature history. Not supported for chip
+ temperature sensor on LTC2974.
+
+power1_label "pin". LTC3883 only.
+power1_input Measured input power.
+
+power[N]_label "pout[1-4]".
+ LTC2974: N=1-4
+ LTC2978: Not supported
+ LTC3880: N=1-2
+ LTC3883: N=2
+power[N]_input Measured output power.
+
+curr1_label "iin". LTC3880 and LTC3883 only.
curr1_input Measured input current.
curr1_max Maximum input current.
curr1_max_alarm Input current high alarm.
-
-curr[2-3]_label "iout[1-2]". LTC3880 only.
-curr[2-3]_input Measured input current.
-curr[2-3]_max Maximum input current.
-curr[2-3]_crit Critical input current.
-curr[2-3]_max_alarm Input current high alarm.
-curr[2-3]_crit_alarm Input current critical high alarm.
+curr1_highest Highest input current. LTC3883 only.
+curr1_reset_history Reset input current history. LTC3883 only.
+
+curr[N]_label "iout[1-4]".
+ LTC2974: N=1-4
+ LTC2978: not supported
+ LTC3880: N=2-3
+ LTC3883: N=2
+curr[N]_input Measured output current.
+curr[N]_max Maximum output current.
+curr[N]_crit Critical high output current.
+curr[N]_lcrit Critical low output current. LTC2974 only.
+curr[N]_max_alarm Output current high alarm.
+curr[N]_crit_alarm Output current critical high alarm.
+curr[N]_lcrit_alarm Output current critical low alarm. LTC2974 only.
+curr[N]_lowest Lowest output current. LTC2974 only.
+curr[N]_highest Highest output current.
+curr[N]_reset_history Reset output current history.
diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775
new file mode 100644
index 000000000000..4e9ef60e8c6c
--- /dev/null
+++ b/Documentation/hwmon/nct6775
@@ -0,0 +1,188 @@
+Note
+====
+
+This driver supersedes the NCT6775F and NCT6776F support in the W83627EHF
+driver.
+
+Kernel driver NCT6775
+=====================
+
+Supported chips:
+ * Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
+ Prefix: 'nct6775'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT5577D/NCT6776D/NCT6776F
+ Prefix: 'nct6776'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT5532D/NCT6779D
+ Prefix: 'nct6779'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+
+Authors:
+ Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D
+and compatible super I/O chips.
+
+The chips support up to 25 temperature monitoring sources. Up to 6 of those are
+direct temperature sensor inputs, the others are special sources such as PECI,
+PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources
+can be monitored and compared against minimum, maximum, and critical
+temperatures. The driver reports up to 10 of the temperatures to the user.
+There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
+one VID, alarms with beep warnings (control unimplemented), and some automatic
+fan regulation strategies (plus manual fan control mode).
+
+The temperature sensor sources on all chips are configurable. The configured
+source for each of the temperature sensors is provided in tempX_label.
+
+Temperatures are measured in degrees Celsius and measurement resolution is
+either 1 degC or 0.5 degC, depending on the temperature source and
+configuration. An alarm is triggered when the temperature gets higher than
+the high limit; it stays on until the temperature falls below the hysteresis
+value. Alarms are only supported for temp1 to temp6, depending on the chip type.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. On
+NCT6775F, fan readings can be divided by a programmable divider (1, 2, 4, 8,
+16, 32, 64 or 128) to give the readings more range or accuracy; the other chips
+do not have a fan speed divider. The driver sets the most suitable fan divisor
+itself; specifically, it increases the divider value each time a fan speed
+reading returns an invalid value, and it reduces it if the fan speed reading
+is lower than optimal. Some fans might not be present because they share pins
+with other functions.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+The driver supports automatic fan control mode known as Thermal Cruise.
+In this mode, the chip attempts to keep the measured temperature in a
+predefined temperature range. If the temperature goes out of range, fan
+is driven slower/faster to reach the predefined range again.
+
+The mode works for fan1-fan5.
+
+sysfs attributes
+----------------
+
+pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range:
+ 0 (lowest speed) to 255 (full)
+
+pwm[1-5]_enable - this file controls mode of fan/temperature control:
+ * 0 Fan control disabled (fans set to maximum speed)
+ * 1 Manual mode, write to pwm[0-5] any value 0-255
+ * 2 "Thermal Cruise" mode
+ * 3 "Fan Speed Cruise" mode
+ * 4 "Smart Fan III" mode (NCT6775F only)
+ * 5 "Smart Fan IV" mode
+
+pwm[1-5]_mode - controls if output is PWM or DC level
+ * 0 DC output
+ * 1 PWM output
+
+Common fan control attributes
+-----------------------------
+
+pwm[1-5]_temp_sel Temperature source. Value is temperature sensor index.
+ For example, select '1' for temp1_input.
+pwm[1-5]_weight_temp_sel
+ Secondary temperature source. Value is temperature
+ sensor index. For example, select '1' for temp1_input.
+ Set to 0 to disable secondary temperature control.
+
+If secondary temperature functionality is enabled, it is controlled with the
+following attributes.
+
+pwm[1-5]_weight_duty_step
+ Duty step size.
+pwm[1-5]_weight_temp_step
+ Temperature step size. With each step over
+ temp_step_base, the value of weight_duty_step is added
+ to the current pwm value.
+pwm[1-5]_weight_temp_step_base
+ Temperature at which secondary temperature control kicks
+ in.
+pwm[1-5]_weight_temp_step_tol
+ Temperature step tolerance.
+
+Thermal Cruise mode (2)
+-----------------------
+
+If the temperature is in the range defined by:
+
+pwm[1-5]_target_temp Target temperature, unit millidegree Celsius
+ (range 0 - 127000)
+pwm[1-5]_temp_tolerance
+ Target temperature tolerance, unit millidegree Celsius
+
+there are no changes to fan speed. Once the temperature leaves the interval, fan
+speed increases (if temperature is higher that desired) or decreases (if
+temperature is lower than desired), using the following limits and time
+intervals.
+
+pwm[1-5]_start fan pwm start value (range 1 - 255), to start fan
+ when the temperature is above defined range.
+pwm[1-5]_floor lowest fan pwm (range 0 - 255) if temperature is below
+ the defined range. If set to 0, the fan is expected to
+ stop if the temperature is below the defined range.
+pwm[1-5]_step_up_time milliseconds before fan speed is increased
+pwm[1-5]_step_down_time milliseconds before fan speed is decreased
+pwm[1-5]_stop_time how many milliseconds must elapse to switch
+ corresponding fan off (when the temperature was below
+ defined range).
+
+Speed Cruise mode (3)
+---------------------
+
+This modes tries to keep the fan speed constant.
+
+fan[1-5]_target Target fan speed
+fan[1-5]_tolerance
+ Target speed tolerance
+
+
+Untested; use at your own risk.
+
+Smart Fan IV mode (5)
+---------------------
+
+This mode offers multiple slopes to control the fan speed. The slopes can be
+controlled by setting the pwm and temperature attributes. When the temperature
+rises, the chip will calculate the DC/PWM output based on the current slope.
+There are up to seven data points depending on the chip type. Subsequent data
+points should be set to higher temperatures and higher pwm values to achieve
+higher fan speeds with increasing temperature. The last data point reflects
+critical temperature mode, in which the fans should run at full speed.
+
+pwm[1-5]_auto_point[1-7]_pwm
+ pwm value to be set if temperature reaches matching
+ temperature range.
+pwm[1-5]_auto_point[1-7]_temp
+ Temperature over which the matching pwm is enabled.
+pwm[1-5]_temp_tolerance
+ Temperature tolerance, unit millidegree Celsius
+pwm[1-5]_crit_temp_tolerance
+ Temperature tolerance for critical temperature,
+ unit millidegree Celsius
+
+pwm[1-5]_step_up_time milliseconds before fan speed is increased
+pwm[1-5]_step_down_time milliseconds before fan speed is decreased
+
+Usage Notes
+-----------
+
+On various ASUS boards with NCT6776F, it appears that CPUTIN is not really
+connected to anything and floats, or that it is connected to some non-standard
+temperature measurement device. As a result, the temperature reported on CPUTIN
+will not reflect a usable value. It often reports unreasonably high
+temperatures, and in some cases the reported temperature declines if the actual
+temperature increases (similar to the raw PECI temperature value - see PECI
+specification for details). CPUTIN should therefore be be ignored on ASUS
+boards. The CPU temperature on ASUS boards is reported from PECI 0.
diff --git a/Documentation/hwmon/sht15 b/Documentation/hwmon/sht15
index 02850bdfac18..778987d1856f 100644
--- a/Documentation/hwmon/sht15
+++ b/Documentation/hwmon/sht15
@@ -40,7 +40,7 @@ bits for humidity, or 12 bits for temperature and 8 bits for humidity.
The humidity calibration coefficients are programmed into an OTP memory on the
chip. These coefficients are used to internally calibrate the signals from the
sensors. Disabling the reload of those coefficients allows saving 10ms for each
-measurement and decrease power consumption, while loosing on precision.
+measurement and decrease power consumption, while losing on precision.
Some options may be set directly in the sht15_platform_data structure
or via sysfs attributes.
diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401
index 9fc447249212..f91e3fa7e5ec 100644
--- a/Documentation/hwmon/tmp401
+++ b/Documentation/hwmon/tmp401
@@ -8,8 +8,16 @@ Supported chips:
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
* Texas Instruments TMP411
Prefix: 'tmp411'
- Addresses scanned: I2C 0x4c
+ Addresses scanned: I2C 0x4c, 0x4d, 0x4e
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
+ * Texas Instruments TMP431
+ Prefix: 'tmp431'
+ Addresses scanned: I2C 0x4c, 0x4d
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp431.html
+ * Texas Instruments TMP432
+ Prefix: 'tmp432'
+ Addresses scanned: I2C 0x4c, 0x4d
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
Authors:
Hans de Goede <hdegoede@redhat.com>
@@ -18,19 +26,19 @@ Authors:
Description
-----------
-This driver implements support for Texas Instruments TMP401 and
-TMP411 chips. These chips implements one remote and one local
-temperature sensor. Temperature is measured in degrees
+This driver implements support for Texas Instruments TMP401, TMP411,
+TMP431, and TMP432 chips. These chips implement one or two remote and
+one local temperature sensors. Temperature is measured in degrees
Celsius. Resolution of the remote sensor is 0.0625 degree. Local
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
supported by the driver so far, so using the default resolution of 0.5
degree).
The driver provides the common sysfs-interface for temperatures (see
-/Documentation/hwmon/sysfs-interface under Temperatures).
+Documentation/hwmon/sysfs-interface under Temperatures).
-The TMP411 chip is compatible with TMP401. It provides some additional
-features.
+The TMP411 and TMP431 chips are compatible with TMP401. TMP411 provides
+some additional features.
* Minimum and Maximum temperature measured since power-on, chip-reset
@@ -40,3 +48,6 @@ features.
Exported via sysfs attribute temp_reset_history. Writing 1 to this
file triggers a reset.
+
+TMP432 is compatible with TMP401 and TMP431. It supports two external
+temperature sensors.
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100
index 756b57c6b73e..33908a4d68ff 100644
--- a/Documentation/hwmon/zl6100
+++ b/Documentation/hwmon/zl6100
@@ -125,7 +125,7 @@ in2_label "vmon"
in2_input Measured voltage on VMON (ZL2004) or VDRV (ZL9101M,
ZL9117M) pin. Reported voltage is 16x the voltage on the
pin (adjusted internally by the chip).
-in2_lcrit Critical minumum VMON/VDRV Voltage.
+in2_lcrit Critical minimum VMON/VDRV Voltage.
in2_crit Critical maximum VMON/VDRV voltage.
in2_lcrit_alarm VMON/VDRV voltage critical low alarm.
in2_crit_alarm VMON/VDRV voltage critical high alarm.
diff --git a/Documentation/ia64/err_inject.txt b/Documentation/ia64/err_inject.txt
index 223e4f0582d0..9f651c181429 100644
--- a/Documentation/ia64/err_inject.txt
+++ b/Documentation/ia64/err_inject.txt
@@ -882,7 +882,7 @@ int err_inj()
cpu=parameters[i].cpu;
k = cpu%64;
j = cpu/64;
- mask[j]=1<<k;
+ mask[j] = 1UL << k;
if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
perror("Error sched_setaffinity:");
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 3210540f8bd3..237acab169dd 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -131,6 +131,7 @@ Code Seq#(hex) Include File Comments
'H' 40-4F sound/hdspm.h conflict!
'H' 40-4F sound/hdsp.h conflict!
'H' 90 sound/usb/usx2y/usb_stream.h
+'H' A0 uapi/linux/usb/cdc-wdm.h
'H' C0-F0 net/bluetooth/hci.h conflict!
'H' C0-DF net/bluetooth/hidp/hidp.h conflict!
'H' C0-DF net/bluetooth/cmtp/cmtp.h conflict!
diff --git a/Documentation/iostats.txt b/Documentation/iostats.txt
index c76c21d87e85..65f694f2d1c9 100644
--- a/Documentation/iostats.txt
+++ b/Documentation/iostats.txt
@@ -71,6 +71,8 @@ Field 4 -- # of milliseconds spent reading
measured from __make_request() to end_that_request_last()).
Field 5 -- # of writes completed
This is the total number of writes completed successfully.
+Field 6 -- # of writes merged
+ See the description of field 2.
Field 7 -- # of sectors written
This is the total number of sectors written successfully.
Field 8 -- # of milliseconds spent writing
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 13f1aa09b938..9c7fd988e299 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -297,6 +297,7 @@ Boot into System Kernel
On ia64, 256M@256M is a generous value that typically works.
The region may be automatically placed on ia64, see the
dump-capture kernel config option notes above.
+ If use sparse memory, the size should be rounded to GRANULE boundaries.
On s390x, typically use "crashkernel=xxM". The value of xx is dependent
on the memory consumption of the kdump system. In general this is not
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4609e81dbc37..8c01a0218a1e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -44,6 +44,7 @@ parameter is applicable:
AVR32 AVR32 architecture is enabled.
AX25 Appropriate AX.25 support is enabled.
BLACKFIN Blackfin architecture is enabled.
+ CLK Common clock infrastructure is enabled.
DRM Direct Rendering Management support is enabled.
DYNAMIC_DEBUG Build in debug messages and enable them at runtime
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
@@ -320,6 +321,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
on: enable for both 32- and 64-bit processes
off: disable for both 32- and 64-bit processes
+ alloc_snapshot [FTRACE]
+ Allocate the ftrace snapshot buffer on boot up when the
+ main buffer is allocated. This is handy if debugging
+ and you need to use tracing_snapshot() on boot up, and
+ do not want to use tracing_snapshot_alloc() as it needs
+ to be done where GFP_KERNEL allocations are allowed.
+
amd_iommu= [HW,X86-64]
Pass parameters to the AMD IOMMU driver in the system.
Possible values are:
@@ -465,6 +473,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
cio_ignore= [S390]
See Documentation/s390/CommonIO for details.
+ clk_ignore_unused
+ [CLK]
+ Keep all clocks already enabled by bootloader on,
+ even if no driver has claimed them. This is useful
+ for debug and development, but should not be
+ needed on a platform with proper driver support.
+ For more information, see Documentation/clk.txt.
clock= [BUGS=X86-32, HW] gettimeofday clocksource override.
[Deprecated]
@@ -596,9 +611,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
is selected automatically. Check
Documentation/kdump/kdump.txt for further details.
- crashkernel_low=size[KMG]
- [KNL, x86] parts under 4G.
-
crashkernel=range1:size1[,range2:size2,...][@offset]
[KNL] Same as above, but depends on the memory
in the running system. The syntax of range is
@@ -606,6 +618,26 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
a memory unit (amount[KMG]). See also
Documentation/kdump/kdump.txt for an example.
+ crashkernel=size[KMG],high
+ [KNL, x86_64] range could be above 4G. Allow kernel
+ to allocate physical memory region from top, so could
+ be above 4G if system have more than 4G ram installed.
+ Otherwise memory region will be allocated below 4G, if
+ available.
+ It will be ignored if crashkernel=X is specified.
+ crashkernel=size[KMG],low
+ [KNL, x86_64] range under 4G. When crashkernel=X,high
+ is passed, kernel could allocate physical memory region
+ above 4G, that cause second kernel crash on system
+ that require some amount of low memory, e.g. swiotlb
+ requires at least 64M+32K low memory. Kernel would
+ try to allocate 72M below 4G automatically.
+ This one let user to specify own low range under 4G
+ for second kernel instead.
+ 0: to disable low allocation.
+ It will be ignored when crashkernel=X,high is not used
+ or memory reserved is below 4G.
+
cs89x0_dma= [HW,NET]
Format: <dma>
@@ -757,19 +789,31 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
(mmio) or 32-bit (mmio32).
The options are the same as for ttyS, above.
- earlyprintk= [X86,SH,BLACKFIN]
+ earlyprintk= [X86,SH,BLACKFIN,ARM]
earlyprintk=vga
earlyprintk=xen
earlyprintk=serial[,ttySn[,baudrate]]
+ earlyprintk=serial[,0x...[,baudrate]]
earlyprintk=ttySn[,baudrate]
earlyprintk=dbgp[debugController#]
+ earlyprintk is useful when the kernel crashes before
+ the normal console is initialized. It is not enabled by
+ default because it has some cosmetic problems.
+
Append ",keep" to not disable it when the real console
takes over.
Only vga or serial or usb debug port at a time.
- Currently only ttyS0 and ttyS1 are supported.
+ Currently only ttyS0 and ttyS1 may be specified by
+ name. Other I/O ports may be explicitly specified
+ on some architectures (x86 and arm at least) by
+ replacing ttySn with an I/O port address, like this:
+ earlyprintk=serial,0x1008,115200
+ You can find the port for a given device in
+ /proc/tty/driver/serial:
+ 2: uart:ST16650V2 port:00001008 irq:18 ...
Interaction with the standard serial driver is not
very good.
@@ -788,6 +832,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
edd= [EDD]
Format: {"off" | "on" | "skip[mbr]"}
+ efi_no_storage_paranoia [EFI; X86]
+ Using this parameter you can use more than 50% of
+ your efi variable storage. Use this parameter only if
+ you are really sure that your UEFI does sane gc and
+ fulfills the spec otherwise your board may brick.
+
eisa_irq_edge= [PARISC,HW]
See header of drivers/parisc/eisa.c.
@@ -1625,7 +1675,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
module.sig_enforce
[KNL] When CONFIG_MODULE_SIG is set, this means that
modules without (valid) signatures will fail to load.
- Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
+ Note that if CONFIG_MODULE_SIG_FORCE is set, that
is always true, so this option does nothing.
mousedev.tap_time=
@@ -1974,8 +2024,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
noreplace-smp [X86-32,SMP] Don't replace SMP instructions
with UP alternatives
- noresidual [PPC] Don't use residual data on PReP machines.
-
nordrand [X86] Disable the direct use of the RDRAND
instruction even if it is supported by the
processor. RDRAND is still available to user
@@ -2461,9 +2509,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
In kernels built with CONFIG_RCU_NOCB_CPU=y, set
the specified list of CPUs to be no-callback CPUs.
Invocation of these CPUs' RCU callbacks will
- be offloaded to "rcuoN" kthreads created for
- that purpose. This reduces OS jitter on the
+ be offloaded to "rcuox/N" kthreads created for
+ that purpose, where "x" is "b" for RCU-bh, "p"
+ for RCU-preempt, and "s" for RCU-sched, and "N"
+ is the CPU number. This reduces OS jitter on the
offloaded CPUs, which can be useful for HPC and
+
real-time workloads. It can also improve energy
efficiency for asymmetric multiprocessors.
@@ -2487,6 +2538,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
leaf rcu_node structure. Useful for very large
systems.
+ rcutree.jiffies_till_first_fqs= [KNL,BOOT]
+ Set delay from grace-period initialization to
+ first attempt to force quiescent states.
+ Units are jiffies, minimum value is zero,
+ and maximum value is HZ.
+
+ rcutree.jiffies_till_next_fqs= [KNL,BOOT]
+ Set delay between subsequent attempts to force
+ quiescent states. Units are jiffies, minimum
+ value is one, and maximum value is HZ.
+
rcutree.qhimark= [KNL,BOOT]
Set threshold of queued
RCU callbacks over which batch limiting is disabled.
@@ -2501,16 +2563,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rcutree.rcu_cpu_stall_timeout= [KNL,BOOT]
Set timeout for RCU CPU stall warning messages.
- rcutree.jiffies_till_first_fqs= [KNL,BOOT]
- Set delay from grace-period initialization to
- first attempt to force quiescent states.
- Units are jiffies, minimum value is zero,
- and maximum value is HZ.
+ rcutree.rcu_idle_gp_delay= [KNL,BOOT]
+ Set wakeup interval for idle CPUs that have
+ RCU callbacks (RCU_FAST_NO_HZ=y).
- rcutree.jiffies_till_next_fqs= [KNL,BOOT]
- Set delay between subsequent attempts to force
- quiescent states. Units are jiffies, minimum
- value is one, and maximum value is HZ.
+ rcutree.rcu_idle_lazy_gp_delay= [KNL,BOOT]
+ Set wakeup interval for idle CPUs that have
+ only "lazy" RCU callbacks (RCU_FAST_NO_HZ=y).
+ Lazy RCU callbacks are those which RCU can
+ prove do nothing more than free memory.
rcutorture.fqs_duration= [KNL,BOOT]
Set duration of force_quiescent_state bursts.
@@ -3222,6 +3283,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
or other driver-specific files in the
Documentation/watchdog/ directory.
+ workqueue.disable_numa
+ By default, all work items queued to unbound
+ workqueues are affine to the NUMA nodes they're
+ issued on, which results in better behavior in
+ general. If NUMA affinity needs to be disabled for
+ whatever reason, this option can be used. Note
+ that this also can be controlled per-workqueue for
+ workqueues visible under /sys/bus/workqueue/.
+
x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of
default x2apic cluster mode on platforms
supporting x2apic.
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 993fba37b7d1..e0ddd327632d 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -119,7 +119,7 @@ device to add.
The array is started with the RUN_ARRAY ioctl.
Once started, new devices can be added. They should have an
-appropriate superblock written to them, and then passed be in with
+appropriate superblock written to them, and then be passed in with
ADD_NEW_DISK.
Devices that have failed or are not yet active can be detached from an
@@ -131,7 +131,7 @@ Specific Rules that apply to format-0 super block arrays, and
-------------------------------------------------------------
An array can be 'created' by describing the array (level, chunksize
-etc) in a SET_ARRAY_INFO ioctl. This must has major_version==0 and
+etc) in a SET_ARRAY_INFO ioctl. This must have major_version==0 and
raid_disks != 0.
Then uninitialized devices can be added with ADD_NEW_DISK. The
@@ -426,7 +426,7 @@ Each directory contains:
offset
This gives the location in the device (in sectors from the
start) where data from the array will be stored. Any part of
- the device before this offset us not touched, unless it is
+ the device before this offset is not touched, unless it is
used for storing metadata (Formats 1.1 and 1.2).
size
@@ -440,7 +440,7 @@ Each directory contains:
When the device is not 'in_sync', this records the number of
sectors from the start of the device which are known to be
correct. This is normally zero, but during a recovery
- operation is will steadily increase, and if the recovery is
+ operation it will steadily increase, and if the recovery is
interrupted, restoring this value can cause recovery to
avoid repeating the earlier blocks. With v1.x metadata, this
value is saved and restored automatically.
@@ -468,7 +468,7 @@ Each directory contains:
-An active md device will also contain and entry for each active device
+An active md device will also contain an entry for each active device
in the array. These are named
rdNN
@@ -482,7 +482,7 @@ will show 'in_sync' on every line.
-Active md devices for levels that support data redundancy (1,4,5,6)
+Active md devices for levels that support data redundancy (1,4,5,6,10)
also have
sync_action
@@ -494,7 +494,7 @@ also have
failed/missing device
idle - nothing is happening
check - A full check of redundancy was requested and is
- happening. This reads all block and checks
+ happening. This reads all blocks and checks
them. A repair may also happen for some raid
levels.
repair - A full check and repair is happening. This is
@@ -522,7 +522,7 @@ also have
degraded
This contains a count of the number of devices by which the
- arrays is degraded. So an optimal array with show '0'. A
+ arrays is degraded. So an optimal array will show '0'. A
single failed/missing drive will show '1', etc.
This file responds to select/poll, any increase or decrease
in the count of missing devices will trigger an event.
diff --git a/Documentation/misc-devices/mei/mei-client-bus.txt b/Documentation/misc-devices/mei/mei-client-bus.txt
new file mode 100644
index 000000000000..f83910a8ce76
--- /dev/null
+++ b/Documentation/misc-devices/mei/mei-client-bus.txt
@@ -0,0 +1,138 @@
+Intel(R) Management Engine (ME) Client bus API
+===============================================
+
+
+Rationale
+=========
+MEI misc character device is useful for dedicated applications to send and receive
+data to the many FW appliance found in Intel's ME from the user space.
+However for some of the ME functionalities it make sense to leverage existing software
+stack and expose them through existing kernel subsystems.
+
+In order to plug seamlessly into the kernel device driver model we add kernel virtual
+bus abstraction on top of the MEI driver. This allows implementing linux kernel drivers
+for the various MEI features as a stand alone entities found in their respective subsystem.
+Existing device drivers can even potentially be re-used by adding an MEI CL bus layer to
+the existing code.
+
+
+MEI CL bus API
+===========
+A driver implementation for an MEI Client is very similar to existing bus
+based device drivers. The driver registers itself as an MEI CL bus driver through
+the mei_cl_driver structure:
+
+struct mei_cl_driver {
+ struct device_driver driver;
+ const char *name;
+
+ const struct mei_cl_device_id *id_table;
+
+ int (*probe)(struct mei_cl_device *dev, const struct mei_cl_id *id);
+ int (*remove)(struct mei_cl_device *dev);
+};
+
+struct mei_cl_id {
+ char name[MEI_NAME_SIZE];
+ kernel_ulong_t driver_info;
+};
+
+The mei_cl_id structure allows the driver to bind itself against a device name.
+
+To actually register a driver on the ME Client bus one must call the mei_cl_add_driver()
+API. This is typically called at module init time.
+
+Once registered on the ME Client bus, a driver will typically try to do some I/O on
+this bus and this should be done through the mei_cl_send() and mei_cl_recv()
+routines. The latter is synchronous (blocks and sleeps until data shows up).
+In order for drivers to be notified of pending events waiting for them (e.g.
+an Rx event) they can register an event handler through the
+mei_cl_register_event_cb() routine. Currently only the MEI_EVENT_RX event
+will trigger an event handler call and the driver implementation is supposed
+to call mei_recv() from the event handler in order to fetch the pending
+received buffers.
+
+
+Example
+=======
+As a theoretical example let's pretend the ME comes with a "contact" NFC IP.
+The driver init and exit routines for this device would look like:
+
+#define CONTACT_DRIVER_NAME "contact"
+
+static struct mei_cl_device_id contact_mei_cl_tbl[] = {
+ { CONTACT_DRIVER_NAME, },
+
+ /* required last entry */
+ { }
+};
+MODULE_DEVICE_TABLE(mei_cl, contact_mei_cl_tbl);
+
+static struct mei_cl_driver contact_driver = {
+ .id_table = contact_mei_tbl,
+ .name = CONTACT_DRIVER_NAME,
+
+ .probe = contact_probe,
+ .remove = contact_remove,
+};
+
+static int contact_init(void)
+{
+ int r;
+
+ r = mei_cl_driver_register(&contact_driver);
+ if (r) {
+ pr_err(CONTACT_DRIVER_NAME ": driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void __exit contact_exit(void)
+{
+ mei_cl_driver_unregister(&contact_driver);
+}
+
+module_init(contact_init);
+module_exit(contact_exit);
+
+And the driver's simplified probe routine would look like that:
+
+int contact_probe(struct mei_cl_device *dev, struct mei_cl_device_id *id)
+{
+ struct contact_driver *contact;
+
+ [...]
+ mei_cl_enable_device(dev);
+
+ mei_cl_register_event_cb(dev, contact_event_cb, contact);
+
+ return 0;
+ }
+
+In the probe routine the driver first enable the MEI device and then registers
+an ME bus event handler which is as close as it can get to registering a
+threaded IRQ handler.
+The handler implementation will typically call some I/O routine depending on
+the pending events:
+
+#define MAX_NFC_PAYLOAD 128
+
+static void contact_event_cb(struct mei_cl_device *dev, u32 events,
+ void *context)
+{
+ struct contact_driver *contact = context;
+
+ if (events & BIT(MEI_EVENT_RX)) {
+ u8 payload[MAX_NFC_PAYLOAD];
+ int payload_size;
+
+ payload_size = mei_recv(dev, payload, MAX_NFC_PAYLOAD);
+ if (payload_size <= 0)
+ return;
+
+ /* Hook to the NFC subsystem */
+ nfc_hci_recv_frame(contact->hdev, payload, payload_size);
+ }
+}
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt
index 703cf4370c79..67a9cb259d40 100644
--- a/Documentation/networking/ieee802154.txt
+++ b/Documentation/networking/ieee802154.txt
@@ -71,8 +71,9 @@ submits skb to qdisc), so if you need something from that cb later, you should
store info in the skb->data on your own.
To hook the MLME interface you have to populate the ml_priv field of your
-net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are
-required.
+net_device with a pointer to struct ieee802154_mlme_ops instance. The fields
+assoc_req, assoc_resp, disassoc_req, start_req, and scan_req are optional.
+All other fields are required.
We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index dc2dc87d2557..f98ca633b528 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -29,7 +29,7 @@ route/max_size - INTEGER
neigh/default/gc_thresh1 - INTEGER
Minimum number of entries to keep. Garbage collector will not
purge entries if there are fewer than this number.
- Default: 256
+ Default: 128
neigh/default/gc_thresh3 - INTEGER
Maximum number of neighbor entries allowed. Increase this
@@ -175,14 +175,6 @@ tcp_congestion_control - STRING
is inherited.
[see setsockopt(listenfd, SOL_TCP, TCP_CONGESTION, "name" ...) ]
-tcp_cookie_size - INTEGER
- Default size of TCP Cookie Transactions (TCPCT) option, that may be
- overridden on a per socket basis by the TCPCT socket option.
- Values greater than the maximum (16) are interpreted as the maximum.
- Values greater than zero and less than the minimum (8) are interpreted
- as the minimum. Odd values are interpreted as the next even value.
- Default: 0 (off).
-
tcp_dsack - BOOLEAN
Allows TCP to send "duplicate" SACKs.
@@ -190,7 +182,9 @@ tcp_early_retrans - INTEGER
Enable Early Retransmit (ER), per RFC 5827. ER lowers the threshold
for triggering fast retransmit when the amount of outstanding data is
small and when no previously unsent data can be transmitted (such
- that limited transmit could be used).
+ that limited transmit could be used). Also controls the use of
+ Tail loss probe (TLP) that converts RTOs occuring due to tail
+ losses into fast recovery (draft-dukkipati-tcpm-tcp-loss-probe-01).
Possible values:
0 disables ER
1 enables ER
@@ -198,7 +192,9 @@ tcp_early_retrans - INTEGER
by a fourth of RTT. This mitigates connection falsely
recovers when network has a small degree of reordering
(less than 3 packets).
- Default: 2
+ 3 enables delayed ER and TLP.
+ 4 enables TLP only.
+ Default: 3
tcp_ecn - INTEGER
Control use of Explicit Congestion Notification (ECN) by TCP.
@@ -229,36 +225,13 @@ tcp_fin_timeout - INTEGER
Default: 60 seconds
tcp_frto - INTEGER
- Enables Forward RTO-Recovery (F-RTO) defined in RFC4138.
+ Enables Forward RTO-Recovery (F-RTO) defined in RFC5682.
F-RTO is an enhanced recovery algorithm for TCP retransmission
- timeouts. It is particularly beneficial in wireless environments
- where packet loss is typically due to random radio interference
- rather than intermediate router congestion. F-RTO is sender-side
- only modification. Therefore it does not require any support from
- the peer.
-
- If set to 1, basic version is enabled. 2 enables SACK enhanced
- F-RTO if flow uses SACK. The basic version can be used also when
- SACK is in use though scenario(s) with it exists where F-RTO
- interacts badly with the packet counting of the SACK enabled TCP
- flow.
-
-tcp_frto_response - INTEGER
- When F-RTO has detected that a TCP retransmission timeout was
- spurious (i.e, the timeout would have been avoided had TCP set a
- longer retransmission timeout), TCP has several options what to do
- next. Possible values are:
- 0 Rate halving based; a smooth and conservative response,
- results in halved cwnd and ssthresh after one RTT
- 1 Very conservative response; not recommended because even
- though being valid, it interacts poorly with the rest of
- Linux TCP, halves cwnd and ssthresh immediately
- 2 Aggressive response; undoes congestion control measures
- that are now known to be unnecessary (ignoring the
- possibility of a lost retransmission that would require
- TCP to be more cautious), cwnd and ssthresh are restored
- to the values prior timeout
- Default: 0 (rate halving based)
+ timeouts. It is particularly beneficial in networks where the
+ RTT fluctuates (e.g., wireless). F-RTO is sender-side only
+ modification. It does not require any support from the peer.
+
+ By default it's enabled with a non-zero value. 0 disables F-RTO.
tcp_keepalive_time - INTEGER
How often TCP sends out keepalive messages when keepalive is enabled.
diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
new file mode 100644
index 000000000000..1c2dab409625
--- /dev/null
+++ b/Documentation/networking/netlink_mmap.txt
@@ -0,0 +1,339 @@
+This file documents how to use memory mapped I/O with netlink.
+
+Author: Patrick McHardy <kaber@trash.net>
+
+Overview
+--------
+
+Memory mapped netlink I/O can be used to increase throughput and decrease
+overhead of unicast receive and transmit operations. Some netlink subsystems
+require high throughput, these are mainly the netfilter subsystems
+nfnetlink_queue and nfnetlink_log, but it can also help speed up large
+dump operations of f.i. the routing database.
+
+Memory mapped netlink I/O used two circular ring buffers for RX and TX which
+are mapped into the processes address space.
+
+The RX ring is used by the kernel to directly construct netlink messages into
+user-space memory without copying them as done with regular socket I/O,
+additionally as long as the ring contains messages no recvmsg() or poll()
+syscalls have to be issued by user-space to get more message.
+
+The TX ring is used to process messages directly from user-space memory, the
+kernel processes all messages contained in the ring using a single sendmsg()
+call.
+
+Usage overview
+--------------
+
+In order to use memory mapped netlink I/O, user-space needs three main changes:
+
+- ring setup
+- conversion of the RX path to get messages from the ring instead of recvmsg()
+- conversion of the TX path to construct messages into the ring
+
+Ring setup is done using setsockopt() to provide the ring parameters to the
+kernel, then a call to mmap() to map the ring into the processes address space:
+
+- setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &params, sizeof(params));
+- setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &params, sizeof(params));
+- ring = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
+
+Usage of either ring is optional, but even if only the RX ring is used the
+mapping still needs to be writable in order to update the frame status after
+processing.
+
+Conversion of the reception path involves calling poll() on the file
+descriptor, once the socket is readable the frames from the ring are
+processsed in order until no more messages are available, as indicated by
+a status word in the frame header.
+
+On kernel side, in order to make use of memory mapped I/O on receive, the
+originating netlink subsystem needs to support memory mapped I/O, otherwise
+it will use an allocated socket buffer as usual and the contents will be
+ copied to the ring on transmission, nullifying most of the performance gains.
+Dumps of kernel databases automatically support memory mapped I/O.
+
+Conversion of the transmit path involves changing message contruction to
+use memory from the TX ring instead of (usually) a buffer declared on the
+stack and setting up the frame header approriately. Optionally poll() can
+be used to wait for free frames in the TX ring.
+
+Structured and definitions for using memory mapped I/O are contained in
+<linux/netlink.h>.
+
+RX and TX rings
+----------------
+
+Each ring contains a number of continous memory blocks, containing frames of
+fixed size dependant on the parameters used for ring setup.
+
+Ring: [ block 0 ]
+ [ frame 0 ]
+ [ frame 1 ]
+ [ block 1 ]
+ [ frame 2 ]
+ [ frame 3 ]
+ ...
+ [ block n ]
+ [ frame 2 * n ]
+ [ frame 2 * n + 1 ]
+
+The blocks are only visible to the kernel, from the point of view of user-space
+the ring just contains the frames in a continous memory zone.
+
+The ring parameters used for setting up the ring are defined as follows:
+
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+Frames are grouped into blocks, where each block is a continous region of memory
+and holds nm_block_size / nm_frame_size frames. The total number of frames in
+the ring is nm_frame_nr. The following invariants hold:
+
+- frames_per_block = nm_block_size / nm_frame_size
+
+- nm_frame_nr = frames_per_block * nm_block_nr
+
+Some parameters are constrained, specifically:
+
+- nm_block_size must be a multiple of the architectures memory page size.
+ The getpagesize() function can be used to get the page size.
+
+- nm_frame_size must be equal or larger to NL_MMAP_HDRLEN, IOW a frame must be
+ able to hold at least the frame header
+
+- nm_frame_size must be smaller or equal to nm_block_size
+
+- nm_frame_size must be a multiple of NL_MMAP_MSG_ALIGNMENT
+
+- nm_frame_nr must equal the actual number of frames as specified above.
+
+When the kernel can't allocate phsyically continous memory for a ring block,
+it will fall back to use physically discontinous memory. This might affect
+performance negatively, in order to avoid this the nm_frame_size parameter
+should be chosen to be as small as possible for the required frame size and
+the number of blocks should be increased instead.
+
+Ring frames
+------------
+
+Each frames contain a frame header, consisting of a synchronization word and some
+meta-data, and the message itself.
+
+Frame: [ header message ]
+
+The frame header is defined as follows:
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+- nm_status is used for synchronizing processing between the kernel and user-
+ space and specifies ownership of the frame as well as the operation to perform
+
+- nm_len contains the length of the message contained in the data area
+
+- nm_group specified the destination multicast group of message
+
+- nm_pid, nm_uid and nm_gid contain the netlink pid, UID and GID of the sending
+ process. These values correspond to the data available using SOCK_PASSCRED in
+ the SCM_CREDENTIALS cmsg.
+
+The possible values in the status word are:
+
+- NL_MMAP_STATUS_UNUSED:
+ RX ring: frame belongs to the kernel and contains no message
+ for user-space. Approriate action is to invoke poll()
+ to wait for new messages.
+
+ TX ring: frame belongs to user-space and can be used for
+ message construction.
+
+- NL_MMAP_STATUS_RESERVED:
+ RX ring only: frame is currently used by the kernel for message
+ construction and contains no valid message yet.
+ Appropriate action is to invoke poll() to wait for
+ new messages.
+
+- NL_MMAP_STATUS_VALID:
+ RX ring: frame contains a valid message. Approriate action is
+ to process the message and release the frame back to
+ the kernel by setting the status to
+ NL_MMAP_STATUS_UNUSED or queue the frame by setting the
+ status to NL_MMAP_STATUS_SKIP.
+
+ TX ring: the frame contains a valid message from user-space to
+ be processed by the kernel. After completing processing
+ the kernel will release the frame back to user-space by
+ setting the status to NL_MMAP_STATUS_UNUSED.
+
+- NL_MMAP_STATUS_COPY:
+ RX ring only: a message is ready to be processed but could not be
+ stored in the ring, either because it exceeded the
+ frame size or because the originating subsystem does
+ not support memory mapped I/O. Appropriate action is
+ to invoke recvmsg() to receive the message and release
+ the frame back to the kernel by setting the status to
+ NL_MMAP_STATUS_UNUSED.
+
+- NL_MMAP_STATUS_SKIP:
+ RX ring only: user-space queued the message for later processing, but
+ processed some messages following it in the ring. The
+ kernel should skip this frame when looking for unused
+ frames.
+
+The data area of a frame begins at a offset of NL_MMAP_HDRLEN relative to the
+frame header.
+
+TX limitations
+--------------
+
+Kernel processing usually involves validation of the message received by
+user-space, then processing its contents. The kernel must assure that
+userspace is not able to modify the message contents after they have been
+validated. In order to do so, the message is copied from the ring frame
+to an allocated buffer if either of these conditions is false:
+
+- only a single mapping of the ring exists
+- the file descriptor is not shared between processes
+
+This means that for threaded programs, the kernel will fall back to copying.
+
+Example
+-------
+
+Ring setup:
+
+ unsigned int block_size = 16 * getpagesize();
+ struct nl_mmap_req req = {
+ .nm_block_size = block_size,
+ .nm_block_nr = 64,
+ .nm_frame_size = 16384,
+ .nm_frame_nr = 64 * block_size / 16384,
+ };
+ unsigned int ring_size;
+ void *rx_ring, *tx_ring;
+
+ /* Configure ring parameters */
+ if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+ exit(1);
+ if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+ exit(1)
+
+ /* Calculate size of each invididual ring */
+ ring_size = req.nm_block_nr * req.nm_block_size;
+
+ /* Map RX/TX rings. The TX ring is located after the RX ring */
+ rx_ring = mmap(NULL, 2 * ring_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+ if ((long)rx_ring == -1L)
+ exit(1);
+ tx_ring = rx_ring + ring_size:
+
+Message reception:
+
+This example assumes some ring parameters of the ring setup are available.
+
+ unsigned int frame_offset = 0;
+ struct nl_mmap_hdr *hdr;
+ struct nlmsghdr *nlh;
+ unsigned char buf[16384];
+ ssize_t len;
+
+ while (1) {
+ struct pollfd pfds[1];
+
+ pfds[0].fd = fd;
+ pfds[0].events = POLLIN | POLLERR;
+ pfds[0].revents = 0;
+
+ if (poll(pfds, 1, -1) < 0 && errno != -EINTR)
+ exit(1);
+
+ /* Check for errors. Error handling omitted */
+ if (pfds[0].revents & POLLERR)
+ <handle error>
+
+ /* If no new messages, poll again */
+ if (!(pfds[0].revents & POLLIN))
+ continue;
+
+ /* Process all frames */
+ while (1) {
+ /* Get next frame header */
+ hdr = rx_ring + frame_offset;
+
+ if (hdr->nm_status == NL_MMAP_STATUS_VALID)
+ /* Regular memory mapped frame */
+ nlh = (void *hdr) + NL_MMAP_HDRLEN;
+ len = hdr->nm_len;
+
+ /* Release empty message immediately. May happen
+ * on error during message construction.
+ */
+ if (len == 0)
+ goto release;
+ } else if (hdr->nm_status == NL_MMAP_STATUS_COPY) {
+ /* Frame queued to socket receive queue */
+ len = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
+ if (len <= 0)
+ break;
+ nlh = buf;
+ } else
+ /* No more messages to process, continue polling */
+ break;
+
+ process_msg(nlh);
+release:
+ /* Release frame back to the kernel */
+ hdr->nm_status = NL_MMAP_STATUS_UNUSED;
+
+ /* Advance frame offset to next frame */
+ frame_offset = (frame_offset + frame_size) % ring_size;
+ }
+ }
+
+Message transmission:
+
+This example assumes some ring parameters of the ring setup are available.
+A single message is constructed and transmitted, to send multiple messages
+at once they would be constructed in consecutive frames before a final call
+to sendto().
+
+ unsigned int frame_offset = 0;
+ struct nl_mmap_hdr *hdr;
+ struct nlmsghdr *nlh;
+ struct sockaddr_nl addr = {
+ .nl_family = AF_NETLINK,
+ };
+
+ hdr = tx_ring + frame_offset;
+ if (hdr->nm_status != NL_MMAP_STATUS_UNUSED)
+ /* No frame available. Use poll() to avoid. */
+ exit(1);
+
+ nlh = (void *)hdr + NL_MMAP_HDRLEN;
+
+ /* Build message */
+ build_message(nlh);
+
+ /* Fill frame header: length and status need to be set */
+ hdr->nm_len = nlh->nlmsg_len;
+ hdr->nm_status = NL_MMAP_STATUS_VALID;
+
+ if (sendto(fd, NULL, 0, 0, &addr, sizeof(addr)) < 0)
+ exit(1);
+
+ /* Advance frame offset to next frame */
+ frame_offset = (frame_offset + frame_size) % ring_size;
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 94444b152fbc..23dd80e82b8e 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -685,14 +685,342 @@ int main(int argc, char **argp)
}
-------------------------------------------------------------------------------
++ AF_PACKET TPACKET_V3 example
+-------------------------------------------------------------------------------
+
+AF_PACKET's TPACKET_V3 ring buffer can be configured to use non-static frame
+sizes by doing it's own memory management. It is based on blocks where polling
+works on a per block basis instead of per ring as in TPACKET_V2 and predecessor.
+
+It is said that TPACKET_V3 brings the following benefits:
+ *) ~15 - 20% reduction in CPU-usage
+ *) ~20% increase in packet capture rate
+ *) ~2x increase in packet density
+ *) Port aggregation analysis
+ *) Non static frame size to capture entire packet payload
+
+So it seems to be a good candidate to be used with packet fanout.
+
+Minimal example code by Daniel Borkmann based on Chetan Loke's lolpcap (compile
+it with gcc -Wall -O2 blob.c, and try things like "./a.out eth0", etc.):
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <poll.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
+#define BLOCK_SIZE (1 << 22)
+#define FRAME_SIZE 2048
+
+#define NUM_BLOCKS 64
+#define NUM_FRAMES ((BLOCK_SIZE * NUM_BLOCKS) / FRAME_SIZE)
+
+#define BLOCK_RETIRE_TOV_IN_MS 64
+#define BLOCK_PRIV_AREA_SZ 13
+
+#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
+
+#define BLOCK_STATUS(x) ((x)->h1.block_status)
+#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts)
+#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt)
+#define BLOCK_LEN(x) ((x)->h1.blk_len)
+#define BLOCK_SNUM(x) ((x)->h1.seq_num)
+#define BLOCK_O2PRIV(x) ((x)->offset_to_priv)
+#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x)))
+#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc)))
+#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri)))
+
+#ifndef likely
+# define likely(x) __builtin_expect(!!(x), 1)
+#endif
+#ifndef unlikely
+# define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+
+struct block_desc {
+ uint32_t version;
+ uint32_t offset_to_priv;
+ struct tpacket_hdr_v1 h1;
+};
+
+struct ring {
+ struct iovec *rd;
+ uint8_t *map;
+ struct tpacket_req3 req;
+};
+
+static unsigned long packets_total = 0, bytes_total = 0;
+static sig_atomic_t sigint = 0;
+
+void sighandler(int num)
+{
+ sigint = 1;
+}
+
+static int setup_socket(struct ring *ring, char *netdev)
+{
+ int err, i, fd, v = TPACKET_V3;
+ struct sockaddr_ll ll;
+
+ fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (fd < 0) {
+ perror("socket");
+ exit(1);
+ }
+
+ err = setsockopt(fd, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
+ if (err < 0) {
+ perror("setsockopt");
+ exit(1);
+ }
+
+ memset(&ring->req, 0, sizeof(ring->req));
+ ring->req.tp_block_size = BLOCK_SIZE;
+ ring->req.tp_frame_size = FRAME_SIZE;
+ ring->req.tp_block_nr = NUM_BLOCKS;
+ ring->req.tp_frame_nr = NUM_FRAMES;
+ ring->req.tp_retire_blk_tov = BLOCK_RETIRE_TOV_IN_MS;
+ ring->req.tp_sizeof_priv = BLOCK_PRIV_AREA_SZ;
+ ring->req.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH;
+
+ err = setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &ring->req,
+ sizeof(ring->req));
+ if (err < 0) {
+ perror("setsockopt");
+ exit(1);
+ }
+
+ ring->map = mmap(NULL, ring->req.tp_block_size * ring->req.tp_block_nr,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
+ fd, 0);
+ if (ring->map == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ ring->rd = malloc(ring->req.tp_block_nr * sizeof(*ring->rd));
+ assert(ring->rd);
+ for (i = 0; i < ring->req.tp_block_nr; ++i) {
+ ring->rd[i].iov_base = ring->map + (i * ring->req.tp_block_size);
+ ring->rd[i].iov_len = ring->req.tp_block_size;
+ }
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = PF_PACKET;
+ ll.sll_protocol = htons(ETH_P_ALL);
+ ll.sll_ifindex = if_nametoindex(netdev);
+ ll.sll_hatype = 0;
+ ll.sll_pkttype = 0;
+ ll.sll_halen = 0;
+
+ err = bind(fd, (struct sockaddr *) &ll, sizeof(ll));
+ if (err < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+ return fd;
+}
+
+#ifdef __checked
+static uint64_t prev_block_seq_num = 0;
+
+void assert_block_seq_num(struct block_desc *pbd)
+{
+ if (unlikely(prev_block_seq_num + 1 != BLOCK_SNUM(pbd))) {
+ printf("prev_block_seq_num:%"PRIu64", expected seq:%"PRIu64" != "
+ "actual seq:%"PRIu64"\n", prev_block_seq_num,
+ prev_block_seq_num + 1, (uint64_t) BLOCK_SNUM(pbd));
+ exit(1);
+ }
+
+ prev_block_seq_num = BLOCK_SNUM(pbd);
+}
+
+static void assert_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
+{
+ if (BLOCK_NUM_PKTS(pbd)) {
+ if (unlikely(bytes != BLOCK_LEN(pbd))) {
+ printf("block:%u with %upackets, expected len:%u != actual len:%u\n",
+ block_num, BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd));
+ exit(1);
+ }
+ } else {
+ if (unlikely(BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(BLOCK_PRIV_AREA_SZ))) {
+ printf("block:%u, expected len:%lu != actual len:%u\n",
+ block_num, BLOCK_HDR_LEN, BLOCK_LEN(pbd));
+ exit(1);
+ }
+ }
+}
+
+static void assert_block_header(struct block_desc *pbd, const int block_num)
+{
+ uint32_t block_status = BLOCK_STATUS(pbd);
+
+ if (unlikely((block_status & TP_STATUS_USER) == 0)) {
+ printf("block:%u, not in TP_STATUS_USER\n", block_num);
+ exit(1);
+ }
+
+ assert_block_seq_num(pbd);
+}
+#else
+static inline void assert_block_header(struct block_desc *pbd, const int block_num)
+{
+}
+static void assert_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
+{
+}
+#endif
+
+static void display(struct tpacket3_hdr *ppd)
+{
+ struct ethhdr *eth = (struct ethhdr *) ((uint8_t *) ppd + ppd->tp_mac);
+ struct iphdr *ip = (struct iphdr *) ((uint8_t *) eth + ETH_HLEN);
+
+ if (eth->h_proto == htons(ETH_P_IP)) {
+ struct sockaddr_in ss, sd;
+ char sbuff[NI_MAXHOST], dbuff[NI_MAXHOST];
+
+ memset(&ss, 0, sizeof(ss));
+ ss.sin_family = PF_INET;
+ ss.sin_addr.s_addr = ip->saddr;
+ getnameinfo((struct sockaddr *) &ss, sizeof(ss),
+ sbuff, sizeof(sbuff), NULL, 0, NI_NUMERICHOST);
+
+ memset(&sd, 0, sizeof(sd));
+ sd.sin_family = PF_INET;
+ sd.sin_addr.s_addr = ip->daddr;
+ getnameinfo((struct sockaddr *) &sd, sizeof(sd),
+ dbuff, sizeof(dbuff), NULL, 0, NI_NUMERICHOST);
+
+ printf("%s -> %s, ", sbuff, dbuff);
+ }
+
+ printf("rxhash: 0x%x\n", ppd->hv1.tp_rxhash);
+}
+
+static void walk_block(struct block_desc *pbd, const int block_num)
+{
+ int num_pkts = BLOCK_NUM_PKTS(pbd), i;
+ unsigned long bytes = 0;
+ unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(BLOCK_PRIV_AREA_SZ);
+ struct tpacket3_hdr *ppd;
+
+ assert_block_header(pbd, block_num);
+
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd));
+ for (i = 0; i < num_pkts; ++i) {
+ bytes += ppd->tp_snaplen;
+ if (ppd->tp_next_offset)
+ bytes_with_padding += ppd->tp_next_offset;
+ else
+ bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
+
+ display(ppd);
+
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset);
+ __sync_synchronize();
+ }
+
+ assert_block_len(pbd, bytes_with_padding, block_num);
+
+ packets_total += num_pkts;
+ bytes_total += bytes;
+}
+
+void flush_block(struct block_desc *pbd)
+{
+ BLOCK_STATUS(pbd) = TP_STATUS_KERNEL;
+ __sync_synchronize();
+}
+
+static void teardown_socket(struct ring *ring, int fd)
+{
+ munmap(ring->map, ring->req.tp_block_size * ring->req.tp_block_nr);
+ free(ring->rd);
+ close(fd);
+}
+
+int main(int argc, char **argp)
+{
+ int fd, err;
+ socklen_t len;
+ struct ring ring;
+ struct pollfd pfd;
+ unsigned int block_num = 0;
+ struct block_desc *pbd;
+ struct tpacket_stats_v3 stats;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s INTERFACE\n", argp[0]);
+ return EXIT_FAILURE;
+ }
+
+ signal(SIGINT, sighandler);
+
+ memset(&ring, 0, sizeof(ring));
+ fd = setup_socket(&ring, argp[argc - 1]);
+ assert(fd > 0);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ while (likely(!sigint)) {
+ pbd = (struct block_desc *) ring.rd[block_num].iov_base;
+retry_block:
+ if ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0) {
+ poll(&pfd, 1, -1);
+ goto retry_block;
+ }
+
+ walk_block(pbd, block_num);
+ flush_block(pbd);
+ block_num = (block_num + 1) % NUM_BLOCKS;
+ }
+
+ len = sizeof(stats);
+ err = getsockopt(fd, SOL_PACKET, PACKET_STATISTICS, &stats, &len);
+ if (err < 0) {
+ perror("getsockopt");
+ exit(1);
+ }
+
+ fflush(stdout);
+ printf("\nReceived %u packets, %lu bytes, %u dropped, freeze_q_cnt: %u\n",
+ stats.tp_packets, bytes_total, stats.tp_drops,
+ stats.tp_freeze_q_cnt);
+
+ teardown_socket(&ring, fd);
+ return 0;
+}
+
+-------------------------------------------------------------------------------
+ PACKET_TIMESTAMP
-------------------------------------------------------------------------------
The PACKET_TIMESTAMP setting determines the source of the timestamp in
-the packet meta information. If your NIC is capable of timestamping
-packets in hardware, you can request those hardware timestamps to used.
-Note: you may need to enable the generation of hardware timestamps with
-SIOCSHWTSTAMP.
+the packet meta information for mmap(2)ed RX_RING and TX_RINGs. If your
+NIC is capable of timestamping packets in hardware, you can request those
+hardware timestamps to be used. Note: you may need to enable the generation
+of hardware timestamps with SIOCSHWTSTAMP (see related information from
+Documentation/networking/timestamping.txt).
PACKET_TIMESTAMP accepts the same integer bit field as
SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE
@@ -704,8 +1032,36 @@ SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
req |= SOF_TIMESTAMPING_SYS_HARDWARE;
setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
-If PACKET_TIMESTAMP is not set, a software timestamp generated inside
-the networking stack is used (the behavior before this setting was added).
+For the mmap(2)ed ring buffers, such timestamps are stored in the
+tpacket{,2,3}_hdr structure's tp_sec and tp_{n,u}sec members. To determine
+what kind of timestamp has been reported, the tp_status field is binary |'ed
+with the following possible bits ...
+
+ TP_STATUS_TS_SYS_HARDWARE
+ TP_STATUS_TS_RAW_HARDWARE
+ TP_STATUS_TS_SOFTWARE
+
+... that are equivalent to its SOF_TIMESTAMPING_* counterparts. For the
+RX_RING, if none of those 3 are set (i.e. PACKET_TIMESTAMP is not set),
+then this means that a software fallback was invoked *within* PF_PACKET's
+processing code (less precise).
+
+Getting timestamps for the TX_RING works as follows: i) fill the ring frames,
+ii) call sendto() e.g. in blocking mode, iii) wait for status of relevant
+frames to be updated resp. the frame handed over to the application, iv) walk
+through the frames to pick up the individual hw/sw timestamps.
+
+Only (!) if transmit timestamping is enabled, then these bits are combined
+with binary | with TP_STATUS_AVAILABLE, so you must check for that in your
+application (e.g. !(tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING))
+in a first step to see if the frame belongs to the application, and then
+one can extract the type of timestamp in a second step from tp_status)!
+
+If you don't care about them, thus having it disabled, checking for
+TP_STATUS_AVAILABLE resp. TP_STATUS_WRONG_FORMAT is sufficient. If in the
+TX_RING part only TP_STATUS_AVAILABLE is set, then the tp_sec and tp_{n,u}sec
+members do not contain a valid value. For TX_RINGs, by default no timestamp
+is generated!
See include/linux/net_tstamp.h and Documentation/networking/timestamping
for more information on hardware timestamps.
diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt
index f9fa6db40a52..654d2e55c8cb 100644
--- a/Documentation/networking/stmmac.txt
+++ b/Documentation/networking/stmmac.txt
@@ -1,6 +1,6 @@
STMicroelectronics 10/100/1000 Synopsys Ethernet driver
-Copyright (C) 2007-2010 STMicroelectronics Ltd
+Copyright (C) 2007-2013 STMicroelectronics Ltd
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
This is the driver for the MAC 10/100/1000 on-chip Ethernet controllers
@@ -10,7 +10,7 @@ Currently this network device driver is for all STM embedded MAC/GMAC
(i.e. 7xxx/5xxx SoCs), SPEAr (arm), Loongson1B (mips) and XLINX XC2V3000
FF1152AMT0221 D1215994A VIRTEX FPGA board.
-DWC Ether MAC 10/100/1000 Universal version 3.60a (and older) and DWC Ether
+DWC Ether MAC 10/100/1000 Universal version 3.70a (and older) and DWC Ether
MAC 10/100 Universal version 4.0 have been used for developing this driver.
This driver supports both the platform bus and PCI.
@@ -32,6 +32,8 @@ The kernel configuration option is STMMAC_ETH:
watchdog: transmit timeout (in milliseconds);
flow_ctrl: Flow control ability [on/off];
pause: Flow Control Pause Time;
+ eee_timer: tx EEE timer;
+ chain_mode: select chain mode instead of ring.
3) Command line options
Driver parameters can be also passed in command line by using:
@@ -164,12 +166,12 @@ Where:
o bus_setup: perform HW setup of the bus. For example, on some ST platforms
this field is used to configure the AMBA bridge to generate more
efficient STBus traffic.
- o init/exit: callbacks used for calling a custom initialisation;
+ o init/exit: callbacks used for calling a custom initialization;
this is sometime necessary on some platforms (e.g. ST boxes)
where the HW needs to have set some PIO lines or system cfg
registers.
o custom_cfg/custom_data: this is a custom configuration that can be passed
- while initialising the resources.
+ while initializing the resources.
o bsp_priv: another private poiter.
For MDIO bus The we have:
@@ -273,6 +275,8 @@ reset procedure etc).
o norm_desc.c: functions for handling normal descriptors;
o chain_mode.c/ring_mode.c:: functions to manage RING/CHAINED modes;
o mmc_core.c/mmc.h: Management MAC Counters;
+ o stmmac_hwtstamp.c: HW timestamp support for PTP
+ o stmmac_ptp.c: PTP 1588 clock
5) Debug Information
@@ -326,6 +330,35 @@ To enter in Tx LPI mode the driver needs to have a software timer
that enable and disable the LPI mode when there is nothing to be
transmitted.
-7) TODO:
+7) Extended descriptors
+The extended descriptors give us information about the receive Ethernet payload
+when it is carrying PTP packets or TCP/UDP/ICMP over IP.
+These are not available on GMAC Synopsys chips older than the 3.50.
+At probe time the driver will decide if these can be actually used.
+This support also is mandatory for PTPv2 because the extra descriptors 6 and 7
+are used for saving the hardware timestamps.
+
+8) Precision Time Protocol (PTP)
+The driver supports the IEEE 1588-2002, Precision Time Protocol (PTP),
+which enables precise synchronization of clocks in measurement and
+control systems implemented with technologies such as network
+communication.
+
+In addition to the basic timestamp features mentioned in IEEE 1588-2002
+Timestamps, new GMAC cores support the advanced timestamp features.
+IEEE 1588-2008 that can be enabled when configure the Kernel.
+
+9) SGMII/RGMII supports
+New GMAC devices provide own way to manage RGMII/SGMII.
+This information is available at run-time by looking at the
+HW capability register. This means that the stmmac can manage
+auto-negotiation and link status w/o using the PHYLIB stuff
+In fact, the HW provides a subset of extended registers to
+restart the ANE, verify Full/Half duplex mode and Speed.
+Also thanks to these registers it is possible to look at the
+Auto-negotiated Link Parter Ability.
+
+10) TODO:
o XGMAC is not supported.
- o Add the PTP - precision time protocol
+ o Complete the TBI & RTBI support.
+ o extened VLAN support for 3.70a SYNP GMAC.
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index a2b57e0a1db0..447fd4cd54ec 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -736,6 +736,13 @@ All the above functions are mandatory to implement for a pinmux driver.
Pin control interaction with the GPIO subsystem
===============================================
+Note that the following implies that the use case is to use a certain pin
+from the Linux kernel using the API in <linux/gpio.h> with gpio_request()
+and similar functions. There are cases where you may be using something
+that your datasheet calls "GPIO mode" but actually is just an electrical
+configuration for a certain device. See the section below named
+"GPIO mode pitfalls" for more details on this scenario.
+
The public pinmux API contains two functions named pinctrl_request_gpio()
and pinctrl_free_gpio(). These two functions shall *ONLY* be called from
gpiolib-based drivers as part of their gpio_request() and
@@ -774,6 +781,111 @@ obtain the function "gpioN" where "N" is the global GPIO pin number if no
special GPIO-handler is registered.
+GPIO mode pitfalls
+==================
+
+Sometime the developer may be confused by a datasheet talking about a pin
+being possible to set into "GPIO mode". It appears that what hardware
+engineers mean with "GPIO mode" is not necessarily the use case that is
+implied in the kernel interface <linux/gpio.h>: a pin that you grab from
+kernel code and then either listen for input or drive high/low to
+assert/deassert some external line.
+
+Rather hardware engineers think that "GPIO mode" means that you can
+software-control a few electrical properties of the pin that you would
+not be able to control if the pin was in some other mode, such as muxed in
+for a device.
+
+Example: a pin is usually muxed in to be used as a UART TX line. But during
+system sleep, we need to put this pin into "GPIO mode" and ground it.
+
+If you make a 1-to-1 map to the GPIO subsystem for this pin, you may start
+to think that you need to come up with something real complex, that the
+pin shall be used for UART TX and GPIO at the same time, that you will grab
+a pin control handle and set it to a certain state to enable UART TX to be
+muxed in, then twist it over to GPIO mode and use gpio_direction_output()
+to drive it low during sleep, then mux it over to UART TX again when you
+wake up and maybe even gpio_request/gpio_free as part of this cycle. This
+all gets very complicated.
+
+The solution is to not think that what the datasheet calls "GPIO mode"
+has to be handled by the <linux/gpio.h> interface. Instead view this as
+a certain pin config setting. Look in e.g. <linux/pinctrl/pinconf-generic.h>
+and you find this in the documentation:
+
+ PIN_CONFIG_OUTPUT: this will configure the pin in output, use argument
+ 1 to indicate high level, argument 0 to indicate low level.
+
+So it is perfectly possible to push a pin into "GPIO mode" and drive the
+line low as part of the usual pin control map. So for example your UART
+driver may look like this:
+
+#include <linux/pinctrl/consumer.h>
+
+struct pinctrl *pinctrl;
+struct pinctrl_state *pins_default;
+struct pinctrl_state *pins_sleep;
+
+pins_default = pinctrl_lookup_state(uap->pinctrl, PINCTRL_STATE_DEFAULT);
+pins_sleep = pinctrl_lookup_state(uap->pinctrl, PINCTRL_STATE_SLEEP);
+
+/* Normal mode */
+retval = pinctrl_select_state(pinctrl, pins_default);
+/* Sleep mode */
+retval = pinctrl_select_state(pinctrl, pins_sleep);
+
+And your machine configuration may look like this:
+--------------------------------------------------
+
+static unsigned long uart_default_mode[] = {
+ PIN_CONF_PACKED(PIN_CONFIG_DRIVE_PUSH_PULL, 0),
+};
+
+static unsigned long uart_sleep_mode[] = {
+ PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, 0),
+};
+
+static struct pinctrl_map __initdata pinmap[] = {
+ PIN_MAP_MUX_GROUP("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
+ "u0_group", "u0"),
+ PIN_MAP_CONFIGS_PIN("uart", PINCTRL_STATE_DEFAULT, "pinctrl-foo",
+ "UART_TX_PIN", uart_default_mode),
+ PIN_MAP_MUX_GROUP("uart", PINCTRL_STATE_SLEEP, "pinctrl-foo",
+ "u0_group", "gpio-mode"),
+ PIN_MAP_CONFIGS_PIN("uart", PINCTRL_STATE_SLEEP, "pinctrl-foo",
+ "UART_TX_PIN", uart_sleep_mode),
+};
+
+foo_init(void) {
+ pinctrl_register_mappings(pinmap, ARRAY_SIZE(pinmap));
+}
+
+Here the pins we want to control are in the "u0_group" and there is some
+function called "u0" that can be enabled on this group of pins, and then
+everything is UART business as usual. But there is also some function
+named "gpio-mode" that can be mapped onto the same pins to move them into
+GPIO mode.
+
+This will give the desired effect without any bogus interaction with the
+GPIO subsystem. It is just an electrical configuration used by that device
+when going to sleep, it might imply that the pin is set into something the
+datasheet calls "GPIO mode" but that is not the point: it is still used
+by that UART device to control the pins that pertain to that very UART
+driver, putting them into modes needed by the UART. GPIO in the Linux
+kernel sense are just some 1-bit line, and is a different use case.
+
+How the registers are poked to attain the push/pull and output low
+configuration and the muxing of the "u0" or "gpio-mode" group onto these
+pins is a question for the driver.
+
+Some datasheets will be more helpful and refer to the "GPIO mode" as
+"low power mode" rather than anything to do with GPIO. This often means
+the same thing electrically speaking, but in this latter case the
+software engineers will usually quickly identify that this is some
+specific muxing/configuration rather than anything related to the GPIO
+API.
+
+
Board/machine configuration
==================================
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 6e953564de03..3af5ae6c9c11 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -17,6 +17,8 @@ Symbols/Function Pointers:
%pF versatile_init+0x0/0x110
%pf versatile_init
%pS versatile_init+0x0/0x110
+ %pSR versatile_init+0x9/0x110
+ (with __builtin_extract_return_addr() translation)
%ps versatile_init
%pB prev_fn_of_versatile_init+0x88/0x88
diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt
index ae66f9b90a25..fcaf0b4efba2 100644
--- a/Documentation/s390/s390dbf.txt
+++ b/Documentation/s390/s390dbf.txt
@@ -143,7 +143,8 @@ Parameter: id: handle for debug log
Return Value: none
-Description: frees memory for a debug log
+Description: frees memory for a debug log and removes all registered debug
+ views.
Must not be called within an interrupt handler
---------------------------------------------------------------------------
diff --git a/Documentation/scsi/LICENSE.qla2xxx b/Documentation/scsi/LICENSE.qla2xxx
index 27a91cf43d6d..5020b7b5a244 100644
--- a/Documentation/scsi/LICENSE.qla2xxx
+++ b/Documentation/scsi/LICENSE.qla2xxx
@@ -1,4 +1,4 @@
-Copyright (c) 2003-2012 QLogic Corporation
+Copyright (c) 2003-2013 QLogic Corporation
QLogic Linux FC-FCoE Driver
This program includes a device driver for Linux 3.x.
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt
index 8a177e4b6e21..7a2d30c132e3 100644
--- a/Documentation/security/Smack.txt
+++ b/Documentation/security/Smack.txt
@@ -117,6 +117,17 @@ access2
ambient
This contains the Smack label applied to unlabeled network
packets.
+change-rule
+ This interface allows modification of existing access control rules.
+ The format accepted on write is:
+ "%s %s %s %s"
+ where the first string is the subject label, the second the
+ object label, the third the access to allow and the fourth the
+ access to deny. The access strings may contain only the characters
+ "rwxat-". If a rule for a given subject and object exists it will be
+ modified by enabling the permissions in the third string and disabling
+ those in the fourth string. If there is no such rule it will be
+ created using the access specified in the third and the fourth strings.
cipso
This interface allows a specific CIPSO header to be assigned
to a Smack label. The format accepted on write is:
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 4499bd948860..95731a08f257 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -890,9 +890,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
power_save - Automatic power-saving timeout (in second, 0 =
disable)
- power_save_controller - Support runtime D3 of HD-audio controller
- (-1 = on for supported chip (default), false = off,
- true = force to on even for unsupported hardware)
+ power_save_controller - Reset HD-audio controller in power-saving mode
+ (default = on)
align_buffer_size - Force rounding of buffer/period sizes to multiples
of 128 bytes. This is more efficient in terms of memory
access but isn't required by the HDA spec and prevents
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 078701fdbd4d..dcc75a9ed919 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -18,6 +18,7 @@ files can be found in mm/swap.c.
Currently, these files are in /proc/sys/vm:
+- admin_reserve_kbytes
- block_dump
- compact_memory
- dirty_background_bytes
@@ -53,11 +54,41 @@ Currently, these files are in /proc/sys/vm:
- percpu_pagelist_fraction
- stat_interval
- swappiness
+- user_reserve_kbytes
- vfs_cache_pressure
- zone_reclaim_mode
==============================================================
+admin_reserve_kbytes
+
+The amount of free memory in the system that should be reserved for users
+with the capability cap_sys_admin.
+
+admin_reserve_kbytes defaults to min(3% of free pages, 8MB)
+
+That should provide enough for the admin to log in and kill a process,
+if necessary, under the default overcommit 'guess' mode.
+
+Systems running under overcommit 'never' should increase this to account
+for the full Virtual Memory Size of programs used to recover. Otherwise,
+root may not be able to log in to recover the system.
+
+How do you calculate a minimum useful reserve?
+
+sshd or login + bash (or some other shell) + top (or ps, kill, etc.)
+
+For overcommit 'guess', we can sum resident set sizes (RSS).
+On x86_64 this is about 8MB.
+
+For overcommit 'never', we can take the max of their virtual sizes (VSZ)
+and add the sum of their RSS.
+On x86_64 this is about 128MB.
+
+Changing this takes effect whenever an application requests memory.
+
+==============================================================
+
block_dump
block_dump enables block I/O debugging when set to a nonzero value. More
@@ -542,6 +573,7 @@ memory until it actually runs out.
When this flag is 2, the kernel uses a "never overcommit"
policy that attempts to prevent any overcommit of memory.
+Note that user_reserve_kbytes affects this policy.
This feature can be very useful because there are a lot of
programs that malloc() huge amounts of memory "just-in-case"
@@ -645,6 +677,24 @@ The default value is 60.
==============================================================
+- user_reserve_kbytes
+
+When overcommit_memory is set to 2, "never overommit" mode, reserve
+min(3% of current process size, user_reserve_kbytes) of free memory.
+This is intended to prevent a user from starting a single memory hogging
+process, such that they cannot recover (kill the hog).
+
+user_reserve_kbytes defaults to min(3% of the current process size, 128MB).
+
+If this is reduced to zero, then the user will be allowed to allocate
+all free memory with a single process, minus admin_reserve_kbytes.
+Any subsequent attempts to execute a command will result in
+"fork: Cannot allocate memory".
+
+Changing this takes effect whenever an application requests memory.
+
+==============================================================
+
vfs_cache_pressure
------------------
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index 2a4cdda4828e..8cb4d7842a5f 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -129,9 +129,9 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
* Okay, so what can I use them for?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Well, un'R'aw is very handy when your X server or a svgalib program crashes.
+Well, unraw(r) is very handy when your X server or a svgalib program crashes.
-sa'K' (Secure Access Key) is useful when you want to be sure there is no
+sak(k) (Secure Access Key) is useful when you want to be sure there is no
trojan program running at console which could grab your password
when you would try to login. It will kill all programs on given console,
thus letting you make sure that the login prompt you see is actually
@@ -143,20 +143,20 @@ IMPORTANT: such. :IMPORTANT
useful when you want to exit a program that will not let you switch consoles.
(For example, X or a svgalib program.)
-re'B'oot is good when you're unable to shut down. But you should also 'S'ync
-and 'U'mount first.
+reboot(b) is good when you're unable to shut down. But you should also
+sync(s) and umount(u) first.
-'C'rash can be used to manually trigger a crashdump when the system is hung.
+crash(c) can be used to manually trigger a crashdump when the system is hung.
Note that this just triggers a crash if there is no dump mechanism available.
-'S'ync is great when your system is locked up, it allows you to sync your
+sync(s) is great when your system is locked up, it allows you to sync your
disks and will certainly lessen the chance of data loss and fscking. Note
that the sync hasn't taken place until you see the "OK" and "Done" appear
on the screen. (If the kernel is really in strife, you may not ever get the
OK or Done message...)
-'U'mount is basically useful in the same ways as 'S'ync. I generally 'S'ync,
-'U'mount, then re'B'oot when my system locks. It's saved me many a fsck.
+umount(u) is basically useful in the same ways as sync(s). I generally sync(s),
+umount(u), then reboot(b) when my system locks. It's saved me many a fsck.
Again, the unmount (remount read-only) hasn't taken place until you see the
"OK" and "Done" message appear on the screen.
@@ -165,11 +165,11 @@ kernel messages you do not want to see. Selecting '0' will prevent all but
the most urgent kernel messages from reaching your console. (They will
still be logged if syslogd/klogd are alive, though.)
-t'E'rm and k'I'll are useful if you have some sort of runaway process you
+term(e) and kill(i) are useful if you have some sort of runaway process you
are unable to kill any other way, especially if it's spawning other
processes.
-"'J'ust thaw it" is useful if your system becomes unresponsive due to a frozen
+"just thaw it(j)" is useful if your system becomes unresponsive due to a frozen
(probably root) filesystem via the FIFREEZE ioctl.
* Sometimes SysRq seems to get 'stuck' after using it, what can I do?
diff --git a/Documentation/this_cpu_ops.txt b/Documentation/this_cpu_ops.txt
new file mode 100644
index 000000000000..1a4ce7e3e05f
--- /dev/null
+++ b/Documentation/this_cpu_ops.txt
@@ -0,0 +1,205 @@
+this_cpu operations
+-------------------
+
+this_cpu operations are a way of optimizing access to per cpu
+variables associated with the *currently* executing processor through
+the use of segment registers (or a dedicated register where the cpu
+permanently stored the beginning of the per cpu area for a specific
+processor).
+
+The this_cpu operations add a per cpu variable offset to the processor
+specific percpu base and encode that operation in the instruction
+operating on the per cpu variable.
+
+This means there are no atomicity issues between the calculation of
+the offset and the operation on the data. Therefore it is not
+necessary to disable preempt or interrupts to ensure that the
+processor is not changed between the calculation of the address and
+the operation on the data.
+
+Read-modify-write operations are of particular interest. Frequently
+processors have special lower latency instructions that can operate
+without the typical synchronization overhead but still provide some
+sort of relaxed atomicity guarantee. The x86 for example can execute
+RMV (Read Modify Write) instructions like inc/dec/cmpxchg without the
+lock prefix and the associated latency penalty.
+
+Access to the variable without the lock prefix is not synchronized but
+synchronization is not necessary since we are dealing with per cpu
+data specific to the currently executing processor. Only the current
+processor should be accessing that variable and therefore there are no
+concurrency issues with other processors in the system.
+
+On x86 the fs: or the gs: segment registers contain the base of the
+per cpu area. It is then possible to simply use the segment override
+to relocate a per cpu relative address to the proper per cpu area for
+the processor. So the relocation to the per cpu base is encoded in the
+instruction via a segment register prefix.
+
+For example:
+
+ DEFINE_PER_CPU(int, x);
+ int z;
+
+ z = this_cpu_read(x);
+
+results in a single instruction
+
+ mov ax, gs:[x]
+
+instead of a sequence of calculation of the address and then a fetch
+from that address which occurs with the percpu operations. Before
+this_cpu_ops such sequence also required preempt disable/enable to
+prevent the kernel from moving the thread to a different processor
+while the calculation is performed.
+
+The main use of the this_cpu operations has been to optimize counter
+operations.
+
+ this_cpu_inc(x)
+
+results in the following single instruction (no lock prefix!)
+
+ inc gs:[x]
+
+instead of the following operations required if there is no segment
+register.
+
+ int *y;
+ int cpu;
+
+ cpu = get_cpu();
+ y = per_cpu_ptr(&x, cpu);
+ (*y)++;
+ put_cpu();
+
+Note that these operations can only be used on percpu data that is
+reserved for a specific processor. Without disabling preemption in the
+surrounding code this_cpu_inc() will only guarantee that one of the
+percpu counters is correctly incremented. However, there is no
+guarantee that the OS will not move the process directly before or
+after the this_cpu instruction is executed. In general this means that
+the value of the individual counters for each processor are
+meaningless. The sum of all the per cpu counters is the only value
+that is of interest.
+
+Per cpu variables are used for performance reasons. Bouncing cache
+lines can be avoided if multiple processors concurrently go through
+the same code paths. Since each processor has its own per cpu
+variables no concurrent cacheline updates take place. The price that
+has to be paid for this optimization is the need to add up the per cpu
+counters when the value of the counter is needed.
+
+
+Special operations:
+-------------------
+
+ y = this_cpu_ptr(&x)
+
+Takes the offset of a per cpu variable (&x !) and returns the address
+of the per cpu variable that belongs to the currently executing
+processor. this_cpu_ptr avoids multiple steps that the common
+get_cpu/put_cpu sequence requires. No processor number is
+available. Instead the offset of the local per cpu area is simply
+added to the percpu offset.
+
+
+
+Per cpu variables and offsets
+-----------------------------
+
+Per cpu variables have *offsets* to the beginning of the percpu
+area. They do not have addresses although they look like that in the
+code. Offsets cannot be directly dereferenced. The offset must be
+added to a base pointer of a percpu area of a processor in order to
+form a valid address.
+
+Therefore the use of x or &x outside of the context of per cpu
+operations is invalid and will generally be treated like a NULL
+pointer dereference.
+
+In the context of per cpu operations
+
+ x is a per cpu variable. Most this_cpu operations take a cpu
+ variable.
+
+ &x is the *offset* a per cpu variable. this_cpu_ptr() takes
+ the offset of a per cpu variable which makes this look a bit
+ strange.
+
+
+
+Operations on a field of a per cpu structure
+--------------------------------------------
+
+Let's say we have a percpu structure
+
+ struct s {
+ int n,m;
+ };
+
+ DEFINE_PER_CPU(struct s, p);
+
+
+Operations on these fields are straightforward
+
+ this_cpu_inc(p.m)
+
+ z = this_cpu_cmpxchg(p.m, 0, 1);
+
+
+If we have an offset to struct s:
+
+ struct s __percpu *ps = &p;
+
+ z = this_cpu_dec(ps->m);
+
+ z = this_cpu_inc_return(ps->n);
+
+
+The calculation of the pointer may require the use of this_cpu_ptr()
+if we do not make use of this_cpu ops later to manipulate fields:
+
+ struct s *pp;
+
+ pp = this_cpu_ptr(&p);
+
+ pp->m--;
+
+ z = pp->n++;
+
+
+Variants of this_cpu ops
+-------------------------
+
+this_cpu ops are interrupt safe. Some architecture do not support
+these per cpu local operations. In that case the operation must be
+replaced by code that disables interrupts, then does the operations
+that are guaranteed to be atomic and then reenable interrupts. Doing
+so is expensive. If there are other reasons why the scheduler cannot
+change the processor we are executing on then there is no reason to
+disable interrupts. For that purpose the __this_cpu operations are
+provided. For example.
+
+ __this_cpu_inc(x);
+
+Will increment x and will not fallback to code that disables
+interrupts on platforms that cannot accomplish atomicity through
+address relocation and a Read-Modify-Write operation in the same
+instruction.
+
+
+
+&this_cpu_ptr(pp)->n vs this_cpu_ptr(&pp->n)
+--------------------------------------------
+
+The first operation takes the offset and forms an address and then
+adds the offset of the n field.
+
+The second one first adds the two offsets and then does the
+relocation. IMHO the second form looks cleaner and has an easier time
+with (). The second form also is consistent with the way
+this_cpu_read() and friends are used.
+
+
+Christoph Lameter, April 3rd, 2013
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index a372304aef10..bfe8c29b1f1d 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -8,6 +8,7 @@ Copyright 2008 Red Hat Inc.
Reviewers: Elias Oltmanns, Randy Dunlap, Andrew Morton,
John Kacur, and David Teigland.
Written for: 2.6.28-rc2
+Updated for: 3.10
Introduction
------------
@@ -17,13 +18,16 @@ designers of systems to find what is going on inside the kernel.
It can be used for debugging or analyzing latencies and
performance issues that take place outside of user-space.
-Although ftrace is the function tracer, it also includes an
-infrastructure that allows for other types of tracing. Some of
-the tracers that are currently in ftrace include a tracer to
-trace context switches, the time it takes for a high priority
-task to run after it was woken up, the time interrupts are
-disabled, and more (ftrace allows for tracer plugins, which
-means that the list of tracers can always grow).
+Although ftrace is typically considered the function tracer, it
+is really a frame work of several assorted tracing utilities.
+There's latency tracing to examine what occurs between interrupts
+disabled and enabled, as well as for preemption and from a time
+a task is woken to the task is actually scheduled in.
+
+One of the most common uses of ftrace is the event tracing.
+Through out the kernel is hundreds of static event points that
+can be enabled via the debugfs file system to see what is
+going on in certain parts of the kernel.
Implementation Details
@@ -61,7 +65,7 @@ the extended "/sys/kernel/debug/tracing" path name.
That's it! (assuming that you have ftrace configured into your kernel)
-After mounting the debugfs, you can see a directory called
+After mounting debugfs, you can see a directory called
"tracing". This directory contains the control and output files
of ftrace. Here is a list of some of the key files:
@@ -84,7 +88,9 @@ of ftrace. Here is a list of some of the key files:
This sets or displays whether writing to the trace
ring buffer is enabled. Echo 0 into this file to disable
- the tracer or 1 to enable it.
+ the tracer or 1 to enable it. Note, this only disables
+ writing to the ring buffer, the tracing overhead may
+ still be occurring.
trace:
@@ -109,7 +115,15 @@ of ftrace. Here is a list of some of the key files:
This file lets the user control the amount of data
that is displayed in one of the above output
- files.
+ files. Options also exist to modify how a tracer
+ or events work (stack traces, timestamps, etc).
+
+ options:
+
+ This is a directory that has a file for every available
+ trace option (also in trace_options). Options may also be set
+ or cleared by writing a "1" or "0" respectively into the
+ corresponding file with the option name.
tracing_max_latency:
@@ -121,10 +135,17 @@ of ftrace. Here is a list of some of the key files:
latency is greater than the value in this
file. (in microseconds)
+ tracing_thresh:
+
+ Some latency tracers will record a trace whenever the
+ latency is greater than the number in this file.
+ Only active when the file contains a number greater than 0.
+ (in microseconds)
+
buffer_size_kb:
This sets or displays the number of kilobytes each CPU
- buffer can hold. The tracer buffers are the same size
+ buffer holds. By default, the trace buffers are the same size
for each CPU. The displayed number is the size of the
CPU buffer and not total size of all buffers. The
trace buffers are allocated in pages (blocks of memory
@@ -133,16 +154,30 @@ of ftrace. Here is a list of some of the key files:
than requested, the rest of the page will be used,
making the actual allocation bigger than requested.
( Note, the size may not be a multiple of the page size
- due to buffer management overhead. )
+ due to buffer management meta-data. )
- This can only be updated when the current_tracer
- is set to "nop".
+ buffer_total_size_kb:
+
+ This displays the total combined size of all the trace buffers.
+
+ free_buffer:
+
+ If a process is performing the tracing, and the ring buffer
+ should be shrunk "freed" when the process is finished, even
+ if it were to be killed by a signal, this file can be used
+ for that purpose. On close of this file, the ring buffer will
+ be resized to its minimum size. Having a process that is tracing
+ also open this file, when the process exits its file descriptor
+ for this file will be closed, and in doing so, the ring buffer
+ will be "freed".
+
+ It may also stop tracing if disable_on_free option is set.
tracing_cpumask:
This is a mask that lets the user only trace
- on specified CPUS. The format is a hex string
- representing the CPUS.
+ on specified CPUs. The format is a hex string
+ representing the CPUs.
set_ftrace_filter:
@@ -183,6 +218,261 @@ of ftrace. Here is a list of some of the key files:
"set_ftrace_notrace". (See the section "dynamic ftrace"
below for more details.)
+ enabled_functions:
+
+ This file is more for debugging ftrace, but can also be useful
+ in seeing if any function has a callback attached to it.
+ Not only does the trace infrastructure use ftrace function
+ trace utility, but other subsystems might too. This file
+ displays all functions that have a callback attached to them
+ as well as the number of callbacks that have been attached.
+ Note, a callback may also call multiple functions which will
+ not be listed in this count.
+
+ If the callback registered to be traced by a function with
+ the "save regs" attribute (thus even more overhead), a 'R'
+ will be displayed on the same line as the function that
+ is returning registers.
+
+ function_profile_enabled:
+
+ When set it will enable all functions with either the function
+ tracer, or if enabled, the function graph tracer. It will
+ keep a histogram of the number of functions that were called
+ and if run with the function graph tracer, it will also keep
+ track of the time spent in those functions. The histogram
+ content can be displayed in the files:
+
+ trace_stats/function<cpu> ( function0, function1, etc).
+
+ trace_stats:
+
+ A directory that holds different tracing stats.
+
+ kprobe_events:
+
+ Enable dynamic trace points. See kprobetrace.txt.
+
+ kprobe_profile:
+
+ Dynamic trace points stats. See kprobetrace.txt.
+
+ max_graph_depth:
+
+ Used with the function graph tracer. This is the max depth
+ it will trace into a function. Setting this to a value of
+ one will show only the first kernel function that is called
+ from user space.
+
+ printk_formats:
+
+ This is for tools that read the raw format files. If an event in
+ the ring buffer references a string (currently only trace_printk()
+ does this), only a pointer to the string is recorded into the buffer
+ and not the string itself. This prevents tools from knowing what
+ that string was. This file displays the string and address for
+ the string allowing tools to map the pointers to what the
+ strings were.
+
+ saved_cmdlines:
+
+ Only the pid of the task is recorded in a trace event unless
+ the event specifically saves the task comm as well. Ftrace
+ makes a cache of pid mappings to comms to try to display
+ comms for events. If a pid for a comm is not listed, then
+ "<...>" is displayed in the output.
+
+ snapshot:
+
+ This displays the "snapshot" buffer and also lets the user
+ take a snapshot of the current running trace.
+ See the "Snapshot" section below for more details.
+
+ stack_max_size:
+
+ When the stack tracer is activated, this will display the
+ maximum stack size it has encountered.
+ See the "Stack Trace" section below.
+
+ stack_trace:
+
+ This displays the stack back trace of the largest stack
+ that was encountered when the stack tracer is activated.
+ See the "Stack Trace" section below.
+
+ stack_trace_filter:
+
+ This is similar to "set_ftrace_filter" but it limits what
+ functions the stack tracer will check.
+
+ trace_clock:
+
+ Whenever an event is recorded into the ring buffer, a
+ "timestamp" is added. This stamp comes from a specified
+ clock. By default, ftrace uses the "local" clock. This
+ clock is very fast and strictly per cpu, but on some
+ systems it may not be monotonic with respect to other
+ CPUs. In other words, the local clocks may not be in sync
+ with local clocks on other CPUs.
+
+ Usual clocks for tracing:
+
+ # cat trace_clock
+ [local] global counter x86-tsc
+
+ local: Default clock, but may not be in sync across CPUs
+
+ global: This clock is in sync with all CPUs but may
+ be a bit slower than the local clock.
+
+ counter: This is not a clock at all, but literally an atomic
+ counter. It counts up one by one, but is in sync
+ with all CPUs. This is useful when you need to
+ know exactly the order events occurred with respect to
+ each other on different CPUs.
+
+ uptime: This uses the jiffies counter and the time stamp
+ is relative to the time since boot up.
+
+ perf: This makes ftrace use the same clock that perf uses.
+ Eventually perf will be able to read ftrace buffers
+ and this will help out in interleaving the data.
+
+ x86-tsc: Architectures may define their own clocks. For
+ example, x86 uses its own TSC cycle clock here.
+
+ To set a clock, simply echo the clock name into this file.
+
+ echo global > trace_clock
+
+ trace_marker:
+
+ This is a very useful file for synchronizing user space
+ with events happening in the kernel. Writing strings into
+ this file will be written into the ftrace buffer.
+
+ It is useful in applications to open this file at the start
+ of the application and just reference the file descriptor
+ for the file.
+
+ void trace_write(const char *fmt, ...)
+ {
+ va_list ap;
+ char buf[256];
+ int n;
+
+ if (trace_fd < 0)
+ return;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, 256, fmt, ap);
+ va_end(ap);
+
+ write(trace_fd, buf, n);
+ }
+
+ start:
+
+ trace_fd = open("trace_marker", WR_ONLY);
+
+ uprobe_events:
+
+ Add dynamic tracepoints in programs.
+ See uprobetracer.txt
+
+ uprobe_profile:
+
+ Uprobe statistics. See uprobetrace.txt
+
+ instances:
+
+ This is a way to make multiple trace buffers where different
+ events can be recorded in different buffers.
+ See "Instances" section below.
+
+ events:
+
+ This is the trace event directory. It holds event tracepoints
+ (also known as static tracepoints) that have been compiled
+ into the kernel. It shows what event tracepoints exist
+ and how they are grouped by system. There are "enable"
+ files at various levels that can enable the tracepoints
+ when a "1" is written to them.
+
+ See events.txt for more information.
+
+ per_cpu:
+
+ This is a directory that contains the trace per_cpu information.
+
+ per_cpu/cpu0/buffer_size_kb:
+
+ The ftrace buffer is defined per_cpu. That is, there's a separate
+ buffer for each CPU to allow writes to be done atomically,
+ and free from cache bouncing. These buffers may have different
+ size buffers. This file is similar to the buffer_size_kb
+ file, but it only displays or sets the buffer size for the
+ specific CPU. (here cpu0).
+
+ per_cpu/cpu0/trace:
+
+ This is similar to the "trace" file, but it will only display
+ the data specific for the CPU. If written to, it only clears
+ the specific CPU buffer.
+
+ per_cpu/cpu0/trace_pipe
+
+ This is similar to the "trace_pipe" file, and is a consuming
+ read, but it will only display (and consume) the data specific
+ for the CPU.
+
+ per_cpu/cpu0/trace_pipe_raw
+
+ For tools that can parse the ftrace ring buffer binary format,
+ the trace_pipe_raw file can be used to extract the data
+ from the ring buffer directly. With the use of the splice()
+ system call, the buffer data can be quickly transferred to
+ a file or to the network where a server is collecting the
+ data.
+
+ Like trace_pipe, this is a consuming reader, where multiple
+ reads will always produce different data.
+
+ per_cpu/cpu0/snapshot:
+
+ This is similar to the main "snapshot" file, but will only
+ snapshot the current CPU (if supported). It only displays
+ the content of the snapshot for a given CPU, and if
+ written to, only clears this CPU buffer.
+
+ per_cpu/cpu0/snapshot_raw:
+
+ Similar to the trace_pipe_raw, but will read the binary format
+ from the snapshot buffer for the given CPU.
+
+ per_cpu/cpu0/stats:
+
+ This displays certain stats about the ring buffer:
+
+ entries: The number of events that are still in the buffer.
+
+ overrun: The number of lost events due to overwriting when
+ the buffer was full.
+
+ commit overrun: Should always be zero.
+ This gets set if so many events happened within a nested
+ event (ring buffer is re-entrant), that it fills the
+ buffer and starts dropping events.
+
+ bytes: Bytes actually read (not overwritten).
+
+ oldest event ts: The oldest timestamp in the buffer
+
+ now ts: The current timestamp
+
+ dropped events: Events lost due to overwrite option being off.
+
+ read events: The number of events read.
The Tracers
-----------
@@ -234,11 +524,6 @@ Here is the list of current tracers that may be configured.
RT tasks (as the current "wakeup" does). This is useful
for those interested in wake up timings of RT tasks.
- "hw-branch-tracer"
-
- Uses the BTS CPU feature on x86 CPUs to traces all
- branches executed.
-
"nop"
This is the "trace nothing" tracer. To remove all
@@ -261,70 +546,100 @@ Here is an example of the output format of the file "trace"
--------
# tracer: function
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
- bash-4251 [01] 10152.583854: path_put <-path_walk
- bash-4251 [01] 10152.583855: dput <-path_put
- bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput
+# entries-in-buffer/entries-written: 140080/250280 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ bash-1977 [000] .... 17284.993652: sys_close <-system_call_fastpath
+ bash-1977 [000] .... 17284.993653: __close_fd <-sys_close
+ bash-1977 [000] .... 17284.993653: _raw_spin_lock <-__close_fd
+ sshd-1974 [003] .... 17284.993653: __srcu_read_unlock <-fsnotify
+ bash-1977 [000] .... 17284.993654: add_preempt_count <-_raw_spin_lock
+ bash-1977 [000] ...1 17284.993655: _raw_spin_unlock <-__close_fd
+ bash-1977 [000] ...1 17284.993656: sub_preempt_count <-_raw_spin_unlock
+ bash-1977 [000] .... 17284.993657: filp_close <-__close_fd
+ bash-1977 [000] .... 17284.993657: dnotify_flush <-filp_close
+ sshd-1974 [003] .... 17284.993658: sys_select <-system_call_fastpath
--------
A header is printed with the tracer name that is represented by
-the trace. In this case the tracer is "function". Then a header
-showing the format. Task name "bash", the task PID "4251", the
-CPU that it was running on "01", the timestamp in <secs>.<usecs>
-format, the function name that was traced "path_put" and the
-parent function that called this function "path_walk". The
-timestamp is the time at which the function was entered.
+the trace. In this case the tracer is "function". Then it shows the
+number of events in the buffer as well as the total number of entries
+that were written. The difference is the number of entries that were
+lost due to the buffer filling up (250280 - 140080 = 110200 events
+lost).
+
+The header explains the content of the events. Task name "bash", the task
+PID "1977", the CPU that it was running on "000", the latency format
+(explained below), the timestamp in <secs>.<usecs> format, the
+function name that was traced "sys_close" and the parent function that
+called this function "system_call_fastpath". The timestamp is the time
+at which the function was entered.
Latency trace format
--------------------
-When the latency-format option is enabled, the trace file gives
-somewhat more information to see why a latency happened.
-Here is a typical trace.
+When the latency-format option is enabled or when one of the latency
+tracers is set, the trace file gives somewhat more information to see
+why a latency happened. Here is a typical trace.
# tracer: irqsoff
#
-irqsoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 97 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: swapper-0 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: apic_timer_interrupt
- => ended at: do_softirq
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- <idle>-0 0d..1 0us+: trace_hardirqs_off_thunk (apic_timer_interrupt)
- <idle>-0 0d.s. 97us : __do_softirq (do_softirq)
- <idle>-0 0d.s1 98us : trace_hardirqs_on (do_softirq)
+# irqsoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 259 us, #4/4, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: ps-6143 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: __lock_task_sighand
+# => ended at: _raw_spin_unlock_irqrestore
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ ps-6143 2d... 0us!: trace_hardirqs_off <-__lock_task_sighand
+ ps-6143 2d..1 259us+: trace_hardirqs_on <-_raw_spin_unlock_irqrestore
+ ps-6143 2d..1 263us+: time_hardirqs_on <-_raw_spin_unlock_irqrestore
+ ps-6143 2d..1 306us : <stack trace>
+ => trace_hardirqs_on_caller
+ => trace_hardirqs_on
+ => _raw_spin_unlock_irqrestore
+ => do_task_stat
+ => proc_tgid_stat
+ => proc_single_show
+ => seq_read
+ => vfs_read
+ => sys_read
+ => system_call_fastpath
This shows that the current tracer is "irqsoff" tracing the time
-for which interrupts were disabled. It gives the trace version
-and the version of the kernel upon which this was executed on
-(2.6.26-rc8). Then it displays the max latency in microsecs (97
-us). The number of trace entries displayed and the total number
-recorded (both are three: #3/3). The type of preemption that was
-used (PREEMPT). VP, KP, SP, and HP are always zero and are
-reserved for later use. #P is the number of online CPUS (#P:2).
+for which interrupts were disabled. It gives the trace version (which
+never changes) and the version of the kernel upon which this was executed on
+(3.10). Then it displays the max latency in microseconds (259 us). The number
+of trace entries displayed and the total number (both are four: #4/4).
+VP, KP, SP, and HP are always zero and are reserved for later use.
+#P is the number of online CPUs (#P:4).
The task is the process that was running when the latency
-occurred. (swapper pid: 0).
+occurred. (ps pid: 6143).
The start and stop (the functions in which the interrupts were
disabled and enabled respectively) that caused the latencies:
- apic_timer_interrupt is where the interrupts were disabled.
- do_softirq is where they were enabled again.
+ __lock_task_sighand is where the interrupts were disabled.
+ _raw_spin_unlock_irqrestore is where they were enabled again.
The next lines after the header are the trace itself. The header
explains which is which.
@@ -367,16 +682,43 @@ The above is mostly meaningful for kernel developers.
The rest is the same as the 'trace' file.
+ Note, the latency tracers will usually end with a back trace
+ to easily find where the latency occurred.
trace_options
-------------
-The trace_options file is used to control what gets printed in
-the trace output. To see what is available, simply cat the file:
+The trace_options file (or the options directory) is used to control
+what gets printed in the trace output, or manipulate the tracers.
+To see what is available, simply cat the file:
cat trace_options
- print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
- noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
+print-parent
+nosym-offset
+nosym-addr
+noverbose
+noraw
+nohex
+nobin
+noblock
+nostacktrace
+trace_printk
+noftrace_preempt
+nobranch
+annotate
+nouserstacktrace
+nosym-userobj
+noprintk-msg-only
+context-info
+latency-format
+sleep-time
+graph-time
+record-cmd
+overwrite
+nodisable_on_free
+irq-info
+markers
+function-trace
To disable one of the options, echo in the option prepended with
"no".
@@ -428,13 +770,34 @@ Here are the available options:
bin - This will print out the formats in raw binary.
- block - TBD (needs update)
+ block - When set, reading trace_pipe will not block when polled.
stacktrace - This is one of the options that changes the trace
itself. When a trace is recorded, so is the stack
of functions. This allows for back traces of
trace sites.
+ trace_printk - Can disable trace_printk() from writing into the buffer.
+
+ branch - Enable branch tracing with the tracer.
+
+ annotate - It is sometimes confusing when the CPU buffers are full
+ and one CPU buffer had a lot of events recently, thus
+ a shorter time frame, were another CPU may have only had
+ a few events, which lets it have older events. When
+ the trace is reported, it shows the oldest events first,
+ and it may look like only one CPU ran (the one with the
+ oldest events). When the annotate option is set, it will
+ display when a new CPU buffer started:
+
+ <idle>-0 [001] dNs4 21169.031481: wake_up_idle_cpu <-add_timer_on
+ <idle>-0 [001] dNs4 21169.031482: _raw_spin_unlock_irqrestore <-add_timer_on
+ <idle>-0 [001] .Ns4 21169.031484: sub_preempt_count <-_raw_spin_unlock_irqrestore
+##### CPU 2 buffer started ####
+ <idle>-0 [002] .N.1 21169.031484: rcu_idle_exit <-cpu_idle
+ <idle>-0 [001] .Ns3 21169.031484: _raw_spin_unlock <-clocksource_watchdog
+ <idle>-0 [001] .Ns3 21169.031485: sub_preempt_count <-_raw_spin_unlock
+
userstacktrace - This option changes the trace. It records a
stacktrace of the current userspace thread.
@@ -451,9 +814,13 @@ Here are the available options:
a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0
x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
- sched-tree - trace all tasks that are on the runqueue, at
- every scheduling event. Will add overhead if
- there's a lot of tasks running at once.
+
+ printk-msg-only - When set, trace_printk()s will only show the format
+ and not their parameters (if trace_bprintk() or
+ trace_bputs() was used to save the trace_printk()).
+
+ context-info - Show only the event data. Hides the comm, PID,
+ timestamp, CPU, and other useful data.
latency-format - This option changes the trace. When
it is enabled, the trace displays
@@ -461,31 +828,61 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6]
latencies, as described in "Latency
trace format".
+ sleep-time - When running function graph tracer, to include
+ the time a task schedules out in its function.
+ When enabled, it will account time the task has been
+ scheduled out as part of the function call.
+
+ graph-time - When running function graph tracer, to include the
+ time to call nested functions. When this is not set,
+ the time reported for the function will only include
+ the time the function itself executed for, not the time
+ for functions that it called.
+
+ record-cmd - When any event or tracer is enabled, a hook is enabled
+ in the sched_switch trace point to fill comm cache
+ with mapped pids and comms. But this may cause some
+ overhead, and if you only care about pids, and not the
+ name of the task, disabling this option can lower the
+ impact of tracing.
+
overwrite - This controls what happens when the trace buffer is
full. If "1" (default), the oldest events are
discarded and overwritten. If "0", then the newest
events are discarded.
+ (see per_cpu/cpu0/stats for overrun and dropped)
-ftrace_enabled
---------------
+ disable_on_free - When the free_buffer is closed, tracing will
+ stop (tracing_on set to 0).
-The following tracers (listed below) give different output
-depending on whether or not the sysctl ftrace_enabled is set. To
-set ftrace_enabled, one can either use the sysctl function or
-set it via the proc file system interface.
+ irq-info - Shows the interrupt, preempt count, need resched data.
+ When disabled, the trace looks like:
- sysctl kernel.ftrace_enabled=1
+# tracer: function
+#
+# entries-in-buffer/entries-written: 144405/9452052 #P:4
+#
+# TASK-PID CPU# TIMESTAMP FUNCTION
+# | | | | |
+ <idle>-0 [002] 23636.756054: ttwu_do_activate.constprop.89 <-try_to_wake_up
+ <idle>-0 [002] 23636.756054: activate_task <-ttwu_do_activate.constprop.89
+ <idle>-0 [002] 23636.756055: enqueue_task <-activate_task
- or
- echo 1 > /proc/sys/kernel/ftrace_enabled
+ markers - When set, the trace_marker is writable (only by root).
+ When disabled, the trace_marker will error with EINVAL
+ on write.
+
+
+ function-trace - The latency tracers will enable function tracing
+ if this option is enabled (default it is). When
+ it is disabled, the latency tracers do not trace
+ functions. This keeps the overhead of the tracer down
+ when performing latency tests.
-To disable ftrace_enabled simply replace the '1' with '0' in the
-above commands.
+ Note: Some tracers have their own options. They only appear
+ when the tracer is active.
-When ftrace_enabled is set the tracers will also record the
-functions that are within the trace. The descriptions of the
-tracers will also show an example with ftrace enabled.
irqsoff
@@ -506,95 +903,133 @@ new trace is saved.
To reset the maximum, echo 0 into tracing_max_latency. Here is
an example:
+ # echo 0 > options/function-trace
# echo irqsoff > current_tracer
- # echo latency-format > trace_options
- # echo 0 > tracing_max_latency
# echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
# ls -ltr
[...]
# echo 0 > tracing_on
# cat trace
# tracer: irqsoff
#
-irqsoff latency trace v1.1.5 on 2.6.26
---------------------------------------------------------------------
- latency: 12 us, #3/3, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: bash-3730 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: sys_setpgid
- => ended at: sys_setpgid
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- bash-3730 1d... 0us : _write_lock_irq (sys_setpgid)
- bash-3730 1d..1 1us+: _write_unlock_irq (sys_setpgid)
- bash-3730 1d..2 14us : trace_hardirqs_on (sys_setpgid)
-
-
-Here we see that that we had a latency of 12 microsecs (which is
-very good). The _write_lock_irq in sys_setpgid disabled
-interrupts. The difference between the 12 and the displayed
-timestamp 14us occurred because the clock was incremented
+# irqsoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 16 us, #4/4, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: swapper/0-0 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: run_timer_softirq
+# => ended at: run_timer_softirq
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ <idle>-0 0d.s2 0us+: _raw_spin_lock_irq <-run_timer_softirq
+ <idle>-0 0dNs3 17us : _raw_spin_unlock_irq <-run_timer_softirq
+ <idle>-0 0dNs3 17us+: trace_hardirqs_on <-run_timer_softirq
+ <idle>-0 0dNs3 25us : <stack trace>
+ => _raw_spin_unlock_irq
+ => run_timer_softirq
+ => __do_softirq
+ => call_softirq
+ => do_softirq
+ => irq_exit
+ => smp_apic_timer_interrupt
+ => apic_timer_interrupt
+ => rcu_idle_exit
+ => cpu_idle
+ => rest_init
+ => start_kernel
+ => x86_64_start_reservations
+ => x86_64_start_kernel
+
+Here we see that that we had a latency of 16 microseconds (which is
+very good). The _raw_spin_lock_irq in run_timer_softirq disabled
+interrupts. The difference between the 16 and the displayed
+timestamp 25us occurred because the clock was incremented
between the time of recording the max latency and the time of
recording the function that had that latency.
-Note the above example had ftrace_enabled not set. If we set the
-ftrace_enabled, we get a much larger output:
+Note the above example had function-trace not set. If we set
+function-trace, we get a much larger output:
+
+ with echo 1 > options/function-trace
# tracer: irqsoff
#
-irqsoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 50 us, #101/101, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: ls-4339 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: __alloc_pages_internal
- => ended at: __alloc_pages_internal
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- ls-4339 0...1 0us+: get_page_from_freelist (__alloc_pages_internal)
- ls-4339 0d..1 3us : rmqueue_bulk (get_page_from_freelist)
- ls-4339 0d..1 3us : _spin_lock (rmqueue_bulk)
- ls-4339 0d..1 4us : add_preempt_count (_spin_lock)
- ls-4339 0d..2 4us : __rmqueue (rmqueue_bulk)
- ls-4339 0d..2 5us : __rmqueue_smallest (__rmqueue)
- ls-4339 0d..2 5us : __mod_zone_page_state (__rmqueue_smallest)
- ls-4339 0d..2 6us : __rmqueue (rmqueue_bulk)
- ls-4339 0d..2 6us : __rmqueue_smallest (__rmqueue)
- ls-4339 0d..2 7us : __mod_zone_page_state (__rmqueue_smallest)
- ls-4339 0d..2 7us : __rmqueue (rmqueue_bulk)
- ls-4339 0d..2 8us : __rmqueue_smallest (__rmqueue)
+# irqsoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 71 us, #168/168, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: bash-2042 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: ata_scsi_queuecmd
+# => ended at: ata_scsi_queuecmd
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ bash-2042 3d... 0us : _raw_spin_lock_irqsave <-ata_scsi_queuecmd
+ bash-2042 3d... 0us : add_preempt_count <-_raw_spin_lock_irqsave
+ bash-2042 3d..1 1us : ata_scsi_find_dev <-ata_scsi_queuecmd
+ bash-2042 3d..1 1us : __ata_scsi_find_dev <-ata_scsi_find_dev
+ bash-2042 3d..1 2us : ata_find_dev.part.14 <-__ata_scsi_find_dev
+ bash-2042 3d..1 2us : ata_qc_new_init <-__ata_scsi_queuecmd
+ bash-2042 3d..1 3us : ata_sg_init <-__ata_scsi_queuecmd
+ bash-2042 3d..1 4us : ata_scsi_rw_xlat <-__ata_scsi_queuecmd
+ bash-2042 3d..1 4us : ata_build_rw_tf <-ata_scsi_rw_xlat
[...]
- ls-4339 0d..2 46us : __rmqueue_smallest (__rmqueue)
- ls-4339 0d..2 47us : __mod_zone_page_state (__rmqueue_smallest)
- ls-4339 0d..2 47us : __rmqueue (rmqueue_bulk)
- ls-4339 0d..2 48us : __rmqueue_smallest (__rmqueue)
- ls-4339 0d..2 48us : __mod_zone_page_state (__rmqueue_smallest)
- ls-4339 0d..2 49us : _spin_unlock (rmqueue_bulk)
- ls-4339 0d..2 49us : sub_preempt_count (_spin_unlock)
- ls-4339 0d..1 50us : get_page_from_freelist (__alloc_pages_internal)
- ls-4339 0d..2 51us : trace_hardirqs_on (__alloc_pages_internal)
-
-
-
-Here we traced a 50 microsecond latency. But we also see all the
+ bash-2042 3d..1 67us : delay_tsc <-__delay
+ bash-2042 3d..1 67us : add_preempt_count <-delay_tsc
+ bash-2042 3d..2 67us : sub_preempt_count <-delay_tsc
+ bash-2042 3d..1 67us : add_preempt_count <-delay_tsc
+ bash-2042 3d..2 68us : sub_preempt_count <-delay_tsc
+ bash-2042 3d..1 68us+: ata_bmdma_start <-ata_bmdma_qc_issue
+ bash-2042 3d..1 71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
+ bash-2042 3d..1 71us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
+ bash-2042 3d..1 72us+: trace_hardirqs_on <-ata_scsi_queuecmd
+ bash-2042 3d..1 120us : <stack trace>
+ => _raw_spin_unlock_irqrestore
+ => ata_scsi_queuecmd
+ => scsi_dispatch_cmd
+ => scsi_request_fn
+ => __blk_run_queue_uncond
+ => __blk_run_queue
+ => blk_queue_bio
+ => generic_make_request
+ => submit_bio
+ => submit_bh
+ => __ext3_get_inode_loc
+ => ext3_iget
+ => ext3_lookup
+ => lookup_real
+ => __lookup_hash
+ => walk_component
+ => lookup_last
+ => path_lookupat
+ => filename_lookup
+ => user_path_at_empty
+ => user_path_at
+ => vfs_fstatat
+ => vfs_stat
+ => sys_newstat
+ => system_call_fastpath
+
+
+Here we traced a 71 microsecond latency. But we also see all the
functions that were called during that time. Note that by
enabling function tracing, we incur an added overhead. This
overhead may extend the latency times. But nevertheless, this
@@ -614,120 +1049,122 @@ Like the irqsoff tracer, it records the maximum latency for
which preemption was disabled. The control of preemptoff tracer
is much like the irqsoff tracer.
+ # echo 0 > options/function-trace
# echo preemptoff > current_tracer
- # echo latency-format > trace_options
- # echo 0 > tracing_max_latency
# echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
# ls -ltr
[...]
# echo 0 > tracing_on
# cat trace
# tracer: preemptoff
#
-preemptoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 29 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: do_IRQ
- => ended at: __do_softirq
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- sshd-4261 0d.h. 0us+: irq_enter (do_IRQ)
- sshd-4261 0d.s. 29us : _local_bh_enable (__do_softirq)
- sshd-4261 0d.s1 30us : trace_preempt_on (__do_softirq)
+# preemptoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 46 us, #4/4, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: sshd-1991 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: do_IRQ
+# => ended at: do_IRQ
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ sshd-1991 1d.h. 0us+: irq_enter <-do_IRQ
+ sshd-1991 1d..1 46us : irq_exit <-do_IRQ
+ sshd-1991 1d..1 47us+: trace_preempt_on <-do_IRQ
+ sshd-1991 1d..1 52us : <stack trace>
+ => sub_preempt_count
+ => irq_exit
+ => do_IRQ
+ => ret_from_intr
This has some more changes. Preemption was disabled when an
-interrupt came in (notice the 'h'), and was enabled while doing
-a softirq. (notice the 's'). But we also see that interrupts
-have been disabled when entering the preempt off section and
-leaving it (the 'd'). We do not know if interrupts were enabled
-in the mean time.
+interrupt came in (notice the 'h'), and was enabled on exit.
+But we also see that interrupts have been disabled when entering
+the preempt off section and leaving it (the 'd'). We do not know if
+interrupts were enabled in the mean time or shortly after this
+was over.
# tracer: preemptoff
#
-preemptoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 63 us, #87/87, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: remove_wait_queue
- => ended at: __do_softirq
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- sshd-4261 0d..1 0us : _spin_lock_irqsave (remove_wait_queue)
- sshd-4261 0d..1 1us : _spin_unlock_irqrestore (remove_wait_queue)
- sshd-4261 0d..1 2us : do_IRQ (common_interrupt)
- sshd-4261 0d..1 2us : irq_enter (do_IRQ)
- sshd-4261 0d..1 2us : idle_cpu (irq_enter)
- sshd-4261 0d..1 3us : add_preempt_count (irq_enter)
- sshd-4261 0d.h1 3us : idle_cpu (irq_enter)
- sshd-4261 0d.h. 4us : handle_fasteoi_irq (do_IRQ)
+# preemptoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 83 us, #241/241, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: bash-1994 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: wake_up_new_task
+# => ended at: task_rq_unlock
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ bash-1994 1d..1 0us : _raw_spin_lock_irqsave <-wake_up_new_task
+ bash-1994 1d..1 0us : select_task_rq_fair <-select_task_rq
+ bash-1994 1d..1 1us : __rcu_read_lock <-select_task_rq_fair
+ bash-1994 1d..1 1us : source_load <-select_task_rq_fair
+ bash-1994 1d..1 1us : source_load <-select_task_rq_fair
[...]
- sshd-4261 0d.h. 12us : add_preempt_count (_spin_lock)
- sshd-4261 0d.h1 12us : ack_ioapic_quirk_irq (handle_fasteoi_irq)
- sshd-4261 0d.h1 13us : move_native_irq (ack_ioapic_quirk_irq)
- sshd-4261 0d.h1 13us : _spin_unlock (handle_fasteoi_irq)
- sshd-4261 0d.h1 14us : sub_preempt_count (_spin_unlock)
- sshd-4261 0d.h1 14us : irq_exit (do_IRQ)
- sshd-4261 0d.h1 15us : sub_preempt_count (irq_exit)
- sshd-4261 0d..2 15us : do_softirq (irq_exit)
- sshd-4261 0d... 15us : __do_softirq (do_softirq)
- sshd-4261 0d... 16us : __local_bh_disable (__do_softirq)
- sshd-4261 0d... 16us+: add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s4 20us : add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s4 21us : sub_preempt_count (local_bh_enable)
- sshd-4261 0d.s5 21us : sub_preempt_count (local_bh_enable)
+ bash-1994 1d..1 12us : irq_enter <-smp_apic_timer_interrupt
+ bash-1994 1d..1 12us : rcu_irq_enter <-irq_enter
+ bash-1994 1d..1 13us : add_preempt_count <-irq_enter
+ bash-1994 1d.h1 13us : exit_idle <-smp_apic_timer_interrupt
+ bash-1994 1d.h1 13us : hrtimer_interrupt <-smp_apic_timer_interrupt
+ bash-1994 1d.h1 13us : _raw_spin_lock <-hrtimer_interrupt
+ bash-1994 1d.h1 14us : add_preempt_count <-_raw_spin_lock
+ bash-1994 1d.h2 14us : ktime_get_update_offsets <-hrtimer_interrupt
[...]
- sshd-4261 0d.s6 41us : add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s6 42us : sub_preempt_count (local_bh_enable)
- sshd-4261 0d.s7 42us : sub_preempt_count (local_bh_enable)
- sshd-4261 0d.s5 43us : add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s5 43us : sub_preempt_count (local_bh_enable_ip)
- sshd-4261 0d.s6 44us : sub_preempt_count (local_bh_enable_ip)
- sshd-4261 0d.s5 44us : add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s5 45us : sub_preempt_count (local_bh_enable)
+ bash-1994 1d.h1 35us : lapic_next_event <-clockevents_program_event
+ bash-1994 1d.h1 35us : irq_exit <-smp_apic_timer_interrupt
+ bash-1994 1d.h1 36us : sub_preempt_count <-irq_exit
+ bash-1994 1d..2 36us : do_softirq <-irq_exit
+ bash-1994 1d..2 36us : __do_softirq <-call_softirq
+ bash-1994 1d..2 36us : __local_bh_disable <-__do_softirq
+ bash-1994 1d.s2 37us : add_preempt_count <-_raw_spin_lock_irq
+ bash-1994 1d.s3 38us : _raw_spin_unlock <-run_timer_softirq
+ bash-1994 1d.s3 39us : sub_preempt_count <-_raw_spin_unlock
+ bash-1994 1d.s2 39us : call_timer_fn <-run_timer_softirq
[...]
- sshd-4261 0d.s. 63us : _local_bh_enable (__do_softirq)
- sshd-4261 0d.s1 64us : trace_preempt_on (__do_softirq)
+ bash-1994 1dNs2 81us : cpu_needs_another_gp <-rcu_process_callbacks
+ bash-1994 1dNs2 82us : __local_bh_enable <-__do_softirq
+ bash-1994 1dNs2 82us : sub_preempt_count <-__local_bh_enable
+ bash-1994 1dN.2 82us : idle_cpu <-irq_exit
+ bash-1994 1dN.2 83us : rcu_irq_exit <-irq_exit
+ bash-1994 1dN.2 83us : sub_preempt_count <-irq_exit
+ bash-1994 1.N.1 84us : _raw_spin_unlock_irqrestore <-task_rq_unlock
+ bash-1994 1.N.1 84us+: trace_preempt_on <-task_rq_unlock
+ bash-1994 1.N.1 104us : <stack trace>
+ => sub_preempt_count
+ => _raw_spin_unlock_irqrestore
+ => task_rq_unlock
+ => wake_up_new_task
+ => do_fork
+ => sys_clone
+ => stub_clone
The above is an example of the preemptoff trace with
-ftrace_enabled set. Here we see that interrupts were disabled
+function-trace set. Here we see that interrupts were not disabled
the entire time. The irq_enter code lets us know that we entered
an interrupt 'h'. Before that, the functions being traced still
show that it is not in an interrupt, but we can see from the
functions themselves that this is not the case.
-Notice that __do_softirq when called does not have a
-preempt_count. It may seem that we missed a preempt enabling.
-What really happened is that the preempt count is held on the
-thread's stack and we switched to the softirq stack (4K stacks
-in effect). The code does not copy the preempt count, but
-because interrupts are disabled, we do not need to worry about
-it. Having a tracer like this is good for letting people know
-what really happens inside the kernel.
-
-
preemptirqsoff
--------------
@@ -762,38 +1199,57 @@ tracer.
Again, using this trace is much like the irqsoff and preemptoff
tracers.
+ # echo 0 > options/function-trace
# echo preemptirqsoff > current_tracer
- # echo latency-format > trace_options
- # echo 0 > tracing_max_latency
# echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
# ls -ltr
[...]
# echo 0 > tracing_on
# cat trace
# tracer: preemptirqsoff
#
-preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 293 us, #3/3, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: ls-4860 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: apic_timer_interrupt
- => ended at: __do_softirq
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- ls-4860 0d... 0us!: trace_hardirqs_off_thunk (apic_timer_interrupt)
- ls-4860 0d.s. 294us : _local_bh_enable (__do_softirq)
- ls-4860 0d.s1 294us : trace_preempt_on (__do_softirq)
-
+# preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 100 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: ls-2230 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: ata_scsi_queuecmd
+# => ended at: ata_scsi_queuecmd
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ ls-2230 3d... 0us+: _raw_spin_lock_irqsave <-ata_scsi_queuecmd
+ ls-2230 3...1 100us : _raw_spin_unlock_irqrestore <-ata_scsi_queuecmd
+ ls-2230 3...1 101us+: trace_preempt_on <-ata_scsi_queuecmd
+ ls-2230 3...1 111us : <stack trace>
+ => sub_preempt_count
+ => _raw_spin_unlock_irqrestore
+ => ata_scsi_queuecmd
+ => scsi_dispatch_cmd
+ => scsi_request_fn
+ => __blk_run_queue_uncond
+ => __blk_run_queue
+ => blk_queue_bio
+ => generic_make_request
+ => submit_bio
+ => submit_bh
+ => ext3_bread
+ => ext3_dir_bread
+ => htree_dirblock_to_tree
+ => ext3_htree_fill_tree
+ => ext3_readdir
+ => vfs_readdir
+ => sys_getdents
+ => system_call_fastpath
The trace_hardirqs_off_thunk is called from assembly on x86 when
@@ -802,105 +1258,158 @@ function tracing, we do not know if interrupts were enabled
within the preemption points. We do see that it started with
preemption enabled.
-Here is a trace with ftrace_enabled set:
-
+Here is a trace with function-trace set:
# tracer: preemptirqsoff
#
-preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 105 us, #183/183, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: sshd-4261 (uid:0 nice:0 policy:0 rt_prio:0)
- -----------------
- => started at: write_chan
- => ended at: __do_softirq
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- ls-4473 0.N.. 0us : preempt_schedule (write_chan)
- ls-4473 0dN.1 1us : _spin_lock (schedule)
- ls-4473 0dN.1 2us : add_preempt_count (_spin_lock)
- ls-4473 0d..2 2us : put_prev_task_fair (schedule)
-[...]
- ls-4473 0d..2 13us : set_normalized_timespec (ktime_get_ts)
- ls-4473 0d..2 13us : __switch_to (schedule)
- sshd-4261 0d..2 14us : finish_task_switch (schedule)
- sshd-4261 0d..2 14us : _spin_unlock_irq (finish_task_switch)
- sshd-4261 0d..1 15us : add_preempt_count (_spin_lock_irqsave)
- sshd-4261 0d..2 16us : _spin_unlock_irqrestore (hrtick_set)
- sshd-4261 0d..2 16us : do_IRQ (common_interrupt)
- sshd-4261 0d..2 17us : irq_enter (do_IRQ)
- sshd-4261 0d..2 17us : idle_cpu (irq_enter)
- sshd-4261 0d..2 18us : add_preempt_count (irq_enter)
- sshd-4261 0d.h2 18us : idle_cpu (irq_enter)
- sshd-4261 0d.h. 18us : handle_fasteoi_irq (do_IRQ)
- sshd-4261 0d.h. 19us : _spin_lock (handle_fasteoi_irq)
- sshd-4261 0d.h. 19us : add_preempt_count (_spin_lock)
- sshd-4261 0d.h1 20us : _spin_unlock (handle_fasteoi_irq)
- sshd-4261 0d.h1 20us : sub_preempt_count (_spin_unlock)
-[...]
- sshd-4261 0d.h1 28us : _spin_unlock (handle_fasteoi_irq)
- sshd-4261 0d.h1 29us : sub_preempt_count (_spin_unlock)
- sshd-4261 0d.h2 29us : irq_exit (do_IRQ)
- sshd-4261 0d.h2 29us : sub_preempt_count (irq_exit)
- sshd-4261 0d..3 30us : do_softirq (irq_exit)
- sshd-4261 0d... 30us : __do_softirq (do_softirq)
- sshd-4261 0d... 31us : __local_bh_disable (__do_softirq)
- sshd-4261 0d... 31us+: add_preempt_count (__local_bh_disable)
- sshd-4261 0d.s4 34us : add_preempt_count (__local_bh_disable)
+# preemptirqsoff latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 161 us, #339/339, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: ls-2269 (uid:0 nice:0 policy:0 rt_prio:0)
+# -----------------
+# => started at: schedule
+# => ended at: mutex_unlock
+#
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+kworker/-59 3...1 0us : __schedule <-schedule
+kworker/-59 3d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
+kworker/-59 3d..1 1us : add_preempt_count <-_raw_spin_lock_irq
+kworker/-59 3d..2 1us : deactivate_task <-__schedule
+kworker/-59 3d..2 1us : dequeue_task <-deactivate_task
+kworker/-59 3d..2 2us : update_rq_clock <-dequeue_task
+kworker/-59 3d..2 2us : dequeue_task_fair <-dequeue_task
+kworker/-59 3d..2 2us : update_curr <-dequeue_task_fair
+kworker/-59 3d..2 2us : update_min_vruntime <-update_curr
+kworker/-59 3d..2 3us : cpuacct_charge <-update_curr
+kworker/-59 3d..2 3us : __rcu_read_lock <-cpuacct_charge
+kworker/-59 3d..2 3us : __rcu_read_unlock <-cpuacct_charge
+kworker/-59 3d..2 3us : update_cfs_rq_blocked_load <-dequeue_task_fair
+kworker/-59 3d..2 4us : clear_buddies <-dequeue_task_fair
+kworker/-59 3d..2 4us : account_entity_dequeue <-dequeue_task_fair
+kworker/-59 3d..2 4us : update_min_vruntime <-dequeue_task_fair
+kworker/-59 3d..2 4us : update_cfs_shares <-dequeue_task_fair
+kworker/-59 3d..2 5us : hrtick_update <-dequeue_task_fair
+kworker/-59 3d..2 5us : wq_worker_sleeping <-__schedule
+kworker/-59 3d..2 5us : kthread_data <-wq_worker_sleeping
+kworker/-59 3d..2 5us : put_prev_task_fair <-__schedule
+kworker/-59 3d..2 6us : pick_next_task_fair <-pick_next_task
+kworker/-59 3d..2 6us : clear_buddies <-pick_next_task_fair
+kworker/-59 3d..2 6us : set_next_entity <-pick_next_task_fair
+kworker/-59 3d..2 6us : update_stats_wait_end <-set_next_entity
+ ls-2269 3d..2 7us : finish_task_switch <-__schedule
+ ls-2269 3d..2 7us : _raw_spin_unlock_irq <-finish_task_switch
+ ls-2269 3d..2 8us : do_IRQ <-ret_from_intr
+ ls-2269 3d..2 8us : irq_enter <-do_IRQ
+ ls-2269 3d..2 8us : rcu_irq_enter <-irq_enter
+ ls-2269 3d..2 9us : add_preempt_count <-irq_enter
+ ls-2269 3d.h2 9us : exit_idle <-do_IRQ
[...]
- sshd-4261 0d.s3 43us : sub_preempt_count (local_bh_enable_ip)
- sshd-4261 0d.s4 44us : sub_preempt_count (local_bh_enable_ip)
- sshd-4261 0d.s3 44us : smp_apic_timer_interrupt (apic_timer_interrupt)
- sshd-4261 0d.s3 45us : irq_enter (smp_apic_timer_interrupt)
- sshd-4261 0d.s3 45us : idle_cpu (irq_enter)
- sshd-4261 0d.s3 46us : add_preempt_count (irq_enter)
- sshd-4261 0d.H3 46us : idle_cpu (irq_enter)
- sshd-4261 0d.H3 47us : hrtimer_interrupt (smp_apic_timer_interrupt)
- sshd-4261 0d.H3 47us : ktime_get (hrtimer_interrupt)
+ ls-2269 3d.h3 20us : sub_preempt_count <-_raw_spin_unlock
+ ls-2269 3d.h2 20us : irq_exit <-do_IRQ
+ ls-2269 3d.h2 21us : sub_preempt_count <-irq_exit
+ ls-2269 3d..3 21us : do_softirq <-irq_exit
+ ls-2269 3d..3 21us : __do_softirq <-call_softirq
+ ls-2269 3d..3 21us+: __local_bh_disable <-__do_softirq
+ ls-2269 3d.s4 29us : sub_preempt_count <-_local_bh_enable_ip
+ ls-2269 3d.s5 29us : sub_preempt_count <-_local_bh_enable_ip
+ ls-2269 3d.s5 31us : do_IRQ <-ret_from_intr
+ ls-2269 3d.s5 31us : irq_enter <-do_IRQ
+ ls-2269 3d.s5 31us : rcu_irq_enter <-irq_enter
[...]
- sshd-4261 0d.H3 81us : tick_program_event (hrtimer_interrupt)
- sshd-4261 0d.H3 82us : ktime_get (tick_program_event)
- sshd-4261 0d.H3 82us : ktime_get_ts (ktime_get)
- sshd-4261 0d.H3 83us : getnstimeofday (ktime_get_ts)
- sshd-4261 0d.H3 83us : set_normalized_timespec (ktime_get_ts)
- sshd-4261 0d.H3 84us : clockevents_program_event (tick_program_event)
- sshd-4261 0d.H3 84us : lapic_next_event (clockevents_program_event)
- sshd-4261 0d.H3 85us : irq_exit (smp_apic_timer_interrupt)
- sshd-4261 0d.H3 85us : sub_preempt_count (irq_exit)
- sshd-4261 0d.s4 86us : sub_preempt_count (irq_exit)
- sshd-4261 0d.s3 86us : add_preempt_count (__local_bh_disable)
+ ls-2269 3d.s5 31us : rcu_irq_enter <-irq_enter
+ ls-2269 3d.s5 32us : add_preempt_count <-irq_enter
+ ls-2269 3d.H5 32us : exit_idle <-do_IRQ
+ ls-2269 3d.H5 32us : handle_irq <-do_IRQ
+ ls-2269 3d.H5 32us : irq_to_desc <-handle_irq
+ ls-2269 3d.H5 33us : handle_fasteoi_irq <-handle_irq
[...]
- sshd-4261 0d.s1 98us : sub_preempt_count (net_rx_action)
- sshd-4261 0d.s. 99us : add_preempt_count (_spin_lock_irq)
- sshd-4261 0d.s1 99us+: _spin_unlock_irq (run_timer_softirq)
- sshd-4261 0d.s. 104us : _local_bh_enable (__do_softirq)
- sshd-4261 0d.s. 104us : sub_preempt_count (_local_bh_enable)
- sshd-4261 0d.s. 105us : _local_bh_enable (__do_softirq)
- sshd-4261 0d.s1 105us : trace_preempt_on (__do_softirq)
-
-
-This is a very interesting trace. It started with the preemption
-of the ls task. We see that the task had the "need_resched" bit
-set via the 'N' in the trace. Interrupts were disabled before
-the spin_lock at the beginning of the trace. We see that a
-schedule took place to run sshd. When the interrupts were
-enabled, we took an interrupt. On return from the interrupt
-handler, the softirq ran. We took another interrupt while
-running the softirq as we see from the capital 'H'.
+ ls-2269 3d.s5 158us : _raw_spin_unlock_irqrestore <-rtl8139_poll
+ ls-2269 3d.s3 158us : net_rps_action_and_irq_enable.isra.65 <-net_rx_action
+ ls-2269 3d.s3 159us : __local_bh_enable <-__do_softirq
+ ls-2269 3d.s3 159us : sub_preempt_count <-__local_bh_enable
+ ls-2269 3d..3 159us : idle_cpu <-irq_exit
+ ls-2269 3d..3 159us : rcu_irq_exit <-irq_exit
+ ls-2269 3d..3 160us : sub_preempt_count <-irq_exit
+ ls-2269 3d... 161us : __mutex_unlock_slowpath <-mutex_unlock
+ ls-2269 3d... 162us+: trace_hardirqs_on <-mutex_unlock
+ ls-2269 3d... 186us : <stack trace>
+ => __mutex_unlock_slowpath
+ => mutex_unlock
+ => process_output
+ => n_tty_write
+ => tty_write
+ => vfs_write
+ => sys_write
+ => system_call_fastpath
+
+This is an interesting trace. It started with kworker running and
+scheduling out and ls taking over. But as soon as ls released the
+rq lock and enabled interrupts (but not preemption) an interrupt
+triggered. When the interrupt finished, it started running softirqs.
+But while the softirq was running, another interrupt triggered.
+When an interrupt is running inside a softirq, the annotation is 'H'.
wakeup
------
+One common case that people are interested in tracing is the
+time it takes for a task that is woken to actually wake up.
+Now for non Real-Time tasks, this can be arbitrary. But tracing
+it none the less can be interesting.
+
+Without function tracing:
+
+ # echo 0 > options/function-trace
+ # echo wakeup > current_tracer
+ # echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
+ # chrt -f 5 sleep 1
+ # echo 0 > tracing_on
+ # cat trace
+# tracer: wakeup
+#
+# wakeup latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 15 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: kworker/3:1H-312 (uid:0 nice:-20 policy:0 rt_prio:0)
+# -----------------
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ <idle>-0 3dNs7 0us : 0:120:R + [003] 312:100:R kworker/3:1H
+ <idle>-0 3dNs7 1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
+ <idle>-0 3d..3 15us : __schedule <-schedule
+ <idle>-0 3d..3 15us : 0:120:R ==> [003] 312:100:R kworker/3:1H
+
+The tracer only traces the highest priority task in the system
+to avoid tracing the normal circumstances. Here we see that
+the kworker with a nice priority of -20 (not very nice), took
+just 15 microseconds from the time it woke up, to the time it
+ran.
+
+Non Real-Time tasks are not that interesting. A more interesting
+trace is to concentrate only on Real-Time tasks.
+
+wakeup_rt
+---------
+
In a Real-Time environment it is very important to know the
wakeup time it takes for the highest priority task that is woken
up to the time that it executes. This is also known as "schedule
@@ -914,124 +1423,229 @@ Real-Time environments are interested in the worst case latency.
That is the longest latency it takes for something to happen,
and not the average. We can have a very fast scheduler that may
only have a large latency once in a while, but that would not
-work well with Real-Time tasks. The wakeup tracer was designed
+work well with Real-Time tasks. The wakeup_rt tracer was designed
to record the worst case wakeups of RT tasks. Non-RT tasks are
not recorded because the tracer only records one worst case and
tracing non-RT tasks that are unpredictable will overwrite the
-worst case latency of RT tasks.
+worst case latency of RT tasks (just run the normal wakeup
+tracer for a while to see that effect).
Since this tracer only deals with RT tasks, we will run this
slightly differently than we did with the previous tracers.
Instead of performing an 'ls', we will run 'sleep 1' under
'chrt' which changes the priority of the task.
- # echo wakeup > current_tracer
- # echo latency-format > trace_options
- # echo 0 > tracing_max_latency
+ # echo 0 > options/function-trace
+ # echo wakeup_rt > current_tracer
# echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
# chrt -f 5 sleep 1
# echo 0 > tracing_on
# cat trace
# tracer: wakeup
#
-wakeup latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 4 us, #2/2, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: sleep-4901 (uid:0 nice:0 policy:1 rt_prio:5)
- -----------------
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
- <idle>-0 1d.h4 0us+: try_to_wake_up (wake_up_process)
- <idle>-0 1d..4 4us : schedule (cpu_idle)
-
-
-Running this on an idle system, we see that it only took 4
-microseconds to perform the task switch. Note, since the trace
-marker in the schedule is before the actual "switch", we stop
-the tracing when the recorded task is about to schedule in. This
-may change if we add a new marker at the end of the scheduler.
-
-Notice that the recorded task is 'sleep' with the PID of 4901
+# tracer: wakeup_rt
+#
+# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 5 us, #4/4, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: sleep-2389 (uid:0 nice:0 policy:1 rt_prio:5)
+# -----------------
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ <idle>-0 3d.h4 0us : 0:120:R + [003] 2389: 94:R sleep
+ <idle>-0 3d.h4 1us+: ttwu_do_activate.constprop.87 <-try_to_wake_up
+ <idle>-0 3d..3 5us : __schedule <-schedule
+ <idle>-0 3d..3 5us : 0:120:R ==> [003] 2389: 94:R sleep
+
+
+Running this on an idle system, we see that it only took 5 microseconds
+to perform the task switch. Note, since the trace point in the schedule
+is before the actual "switch", we stop the tracing when the recorded task
+is about to schedule in. This may change if we add a new marker at the
+end of the scheduler.
+
+Notice that the recorded task is 'sleep' with the PID of 2389
and it has an rt_prio of 5. This priority is user-space priority
and not the internal kernel priority. The policy is 1 for
SCHED_FIFO and 2 for SCHED_RR.
-Doing the same with chrt -r 5 and ftrace_enabled set.
+Note, that the trace data shows the internal priority (99 - rtprio).
-# tracer: wakeup
+ <idle>-0 3d..3 5us : 0:120:R ==> [003] 2389: 94:R sleep
+
+The 0:120:R means idle was running with a nice priority of 0 (120 - 20)
+and in the running state 'R'. The sleep task was scheduled in with
+2389: 94:R. That is the priority is the kernel rtprio (99 - 5 = 94)
+and it too is in the running state.
+
+Doing the same with chrt -r 5 and function-trace set.
+
+ echo 1 > options/function-trace
+
+# tracer: wakeup_rt
#
-wakeup latency trace v1.1.5 on 2.6.26-rc8
---------------------------------------------------------------------
- latency: 50 us, #60/60, CPU#1 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:2)
- -----------------
- | task: sleep-4068 (uid:0 nice:0 policy:2 rt_prio:5)
- -----------------
-
-# _------=> CPU#
-# / _-----=> irqs-off
-# | / _----=> need-resched
-# || / _---=> hardirq/softirq
-# ||| / _--=> preempt-depth
-# |||| /
-# ||||| delay
-# cmd pid ||||| time | caller
-# \ / ||||| \ | /
-ksoftirq-7 1d.H3 0us : try_to_wake_up (wake_up_process)
-ksoftirq-7 1d.H4 1us : sub_preempt_count (marker_probe_cb)
-ksoftirq-7 1d.H3 2us : check_preempt_wakeup (try_to_wake_up)
-ksoftirq-7 1d.H3 3us : update_curr (check_preempt_wakeup)
-ksoftirq-7 1d.H3 4us : calc_delta_mine (update_curr)
-ksoftirq-7 1d.H3 5us : __resched_task (check_preempt_wakeup)
-ksoftirq-7 1d.H3 6us : task_wake_up_rt (try_to_wake_up)
-ksoftirq-7 1d.H3 7us : _spin_unlock_irqrestore (try_to_wake_up)
-[...]
-ksoftirq-7 1d.H2 17us : irq_exit (smp_apic_timer_interrupt)
-ksoftirq-7 1d.H2 18us : sub_preempt_count (irq_exit)
-ksoftirq-7 1d.s3 19us : sub_preempt_count (irq_exit)
-ksoftirq-7 1..s2 20us : rcu_process_callbacks (__do_softirq)
-[...]
-ksoftirq-7 1..s2 26us : __rcu_process_callbacks (rcu_process_callbacks)
-ksoftirq-7 1d.s2 27us : _local_bh_enable (__do_softirq)
-ksoftirq-7 1d.s2 28us : sub_preempt_count (_local_bh_enable)
-ksoftirq-7 1.N.3 29us : sub_preempt_count (ksoftirqd)
-ksoftirq-7 1.N.2 30us : _cond_resched (ksoftirqd)
-ksoftirq-7 1.N.2 31us : __cond_resched (_cond_resched)
-ksoftirq-7 1.N.2 32us : add_preempt_count (__cond_resched)
-ksoftirq-7 1.N.2 33us : schedule (__cond_resched)
-ksoftirq-7 1.N.2 33us : add_preempt_count (schedule)
-ksoftirq-7 1.N.3 34us : hrtick_clear (schedule)
-ksoftirq-7 1dN.3 35us : _spin_lock (schedule)
-ksoftirq-7 1dN.3 36us : add_preempt_count (_spin_lock)
-ksoftirq-7 1d..4 37us : put_prev_task_fair (schedule)
-ksoftirq-7 1d..4 38us : update_curr (put_prev_task_fair)
-[...]
-ksoftirq-7 1d..5 47us : _spin_trylock (tracing_record_cmdline)
-ksoftirq-7 1d..5 48us : add_preempt_count (_spin_trylock)
-ksoftirq-7 1d..6 49us : _spin_unlock (tracing_record_cmdline)
-ksoftirq-7 1d..6 49us : sub_preempt_count (_spin_unlock)
-ksoftirq-7 1d..4 50us : schedule (__cond_resched)
-
-The interrupt went off while running ksoftirqd. This task runs
-at SCHED_OTHER. Why did not we see the 'N' set early? This may
-be a harmless bug with x86_32 and 4K stacks. On x86_32 with 4K
-stacks configured, the interrupt and softirq run with their own
-stack. Some information is held on the top of the task's stack
-(need_resched and preempt_count are both stored there). The
-setting of the NEED_RESCHED bit is done directly to the task's
-stack, but the reading of the NEED_RESCHED is done by looking at
-the current stack, which in this case is the stack for the hard
-interrupt. This hides the fact that NEED_RESCHED has been set.
-We do not see the 'N' until we switch back to the task's
-assigned stack.
+# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 29 us, #85/85, CPU#3 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: sleep-2448 (uid:0 nice:0 policy:1 rt_prio:5)
+# -----------------
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ <idle>-0 3d.h4 1us+: 0:120:R + [003] 2448: 94:R sleep
+ <idle>-0 3d.h4 2us : ttwu_do_activate.constprop.87 <-try_to_wake_up
+ <idle>-0 3d.h3 3us : check_preempt_curr <-ttwu_do_wakeup
+ <idle>-0 3d.h3 3us : resched_task <-check_preempt_curr
+ <idle>-0 3dNh3 4us : task_woken_rt <-ttwu_do_wakeup
+ <idle>-0 3dNh3 4us : _raw_spin_unlock <-try_to_wake_up
+ <idle>-0 3dNh3 4us : sub_preempt_count <-_raw_spin_unlock
+ <idle>-0 3dNh2 5us : ttwu_stat <-try_to_wake_up
+ <idle>-0 3dNh2 5us : _raw_spin_unlock_irqrestore <-try_to_wake_up
+ <idle>-0 3dNh2 6us : sub_preempt_count <-_raw_spin_unlock_irqrestore
+ <idle>-0 3dNh1 6us : _raw_spin_lock <-__run_hrtimer
+ <idle>-0 3dNh1 6us : add_preempt_count <-_raw_spin_lock
+ <idle>-0 3dNh2 7us : _raw_spin_unlock <-hrtimer_interrupt
+ <idle>-0 3dNh2 7us : sub_preempt_count <-_raw_spin_unlock
+ <idle>-0 3dNh1 7us : tick_program_event <-hrtimer_interrupt
+ <idle>-0 3dNh1 7us : clockevents_program_event <-tick_program_event
+ <idle>-0 3dNh1 8us : ktime_get <-clockevents_program_event
+ <idle>-0 3dNh1 8us : lapic_next_event <-clockevents_program_event
+ <idle>-0 3dNh1 8us : irq_exit <-smp_apic_timer_interrupt
+ <idle>-0 3dNh1 9us : sub_preempt_count <-irq_exit
+ <idle>-0 3dN.2 9us : idle_cpu <-irq_exit
+ <idle>-0 3dN.2 9us : rcu_irq_exit <-irq_exit
+ <idle>-0 3dN.2 10us : rcu_eqs_enter_common.isra.45 <-rcu_irq_exit
+ <idle>-0 3dN.2 10us : sub_preempt_count <-irq_exit
+ <idle>-0 3.N.1 11us : rcu_idle_exit <-cpu_idle
+ <idle>-0 3dN.1 11us : rcu_eqs_exit_common.isra.43 <-rcu_idle_exit
+ <idle>-0 3.N.1 11us : tick_nohz_idle_exit <-cpu_idle
+ <idle>-0 3dN.1 12us : menu_hrtimer_cancel <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 12us : ktime_get <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 12us : tick_do_update_jiffies64 <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 13us : update_cpu_load_nohz <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 13us : _raw_spin_lock <-update_cpu_load_nohz
+ <idle>-0 3dN.1 13us : add_preempt_count <-_raw_spin_lock
+ <idle>-0 3dN.2 13us : __update_cpu_load <-update_cpu_load_nohz
+ <idle>-0 3dN.2 14us : sched_avg_update <-__update_cpu_load
+ <idle>-0 3dN.2 14us : _raw_spin_unlock <-update_cpu_load_nohz
+ <idle>-0 3dN.2 14us : sub_preempt_count <-_raw_spin_unlock
+ <idle>-0 3dN.1 15us : calc_load_exit_idle <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 15us : touch_softlockup_watchdog <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 15us : hrtimer_cancel <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 15us : hrtimer_try_to_cancel <-hrtimer_cancel
+ <idle>-0 3dN.1 16us : lock_hrtimer_base.isra.18 <-hrtimer_try_to_cancel
+ <idle>-0 3dN.1 16us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
+ <idle>-0 3dN.1 16us : add_preempt_count <-_raw_spin_lock_irqsave
+ <idle>-0 3dN.2 17us : __remove_hrtimer <-remove_hrtimer.part.16
+ <idle>-0 3dN.2 17us : hrtimer_force_reprogram <-__remove_hrtimer
+ <idle>-0 3dN.2 17us : tick_program_event <-hrtimer_force_reprogram
+ <idle>-0 3dN.2 18us : clockevents_program_event <-tick_program_event
+ <idle>-0 3dN.2 18us : ktime_get <-clockevents_program_event
+ <idle>-0 3dN.2 18us : lapic_next_event <-clockevents_program_event
+ <idle>-0 3dN.2 19us : _raw_spin_unlock_irqrestore <-hrtimer_try_to_cancel
+ <idle>-0 3dN.2 19us : sub_preempt_count <-_raw_spin_unlock_irqrestore
+ <idle>-0 3dN.1 19us : hrtimer_forward <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 20us : ktime_add_safe <-hrtimer_forward
+ <idle>-0 3dN.1 20us : ktime_add_safe <-hrtimer_forward
+ <idle>-0 3dN.1 20us : hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
+ <idle>-0 3dN.1 20us : __hrtimer_start_range_ns <-hrtimer_start_range_ns
+ <idle>-0 3dN.1 21us : lock_hrtimer_base.isra.18 <-__hrtimer_start_range_ns
+ <idle>-0 3dN.1 21us : _raw_spin_lock_irqsave <-lock_hrtimer_base.isra.18
+ <idle>-0 3dN.1 21us : add_preempt_count <-_raw_spin_lock_irqsave
+ <idle>-0 3dN.2 22us : ktime_add_safe <-__hrtimer_start_range_ns
+ <idle>-0 3dN.2 22us : enqueue_hrtimer <-__hrtimer_start_range_ns
+ <idle>-0 3dN.2 22us : tick_program_event <-__hrtimer_start_range_ns
+ <idle>-0 3dN.2 23us : clockevents_program_event <-tick_program_event
+ <idle>-0 3dN.2 23us : ktime_get <-clockevents_program_event
+ <idle>-0 3dN.2 23us : lapic_next_event <-clockevents_program_event
+ <idle>-0 3dN.2 24us : _raw_spin_unlock_irqrestore <-__hrtimer_start_range_ns
+ <idle>-0 3dN.2 24us : sub_preempt_count <-_raw_spin_unlock_irqrestore
+ <idle>-0 3dN.1 24us : account_idle_ticks <-tick_nohz_idle_exit
+ <idle>-0 3dN.1 24us : account_idle_time <-account_idle_ticks
+ <idle>-0 3.N.1 25us : sub_preempt_count <-cpu_idle
+ <idle>-0 3.N.. 25us : schedule <-cpu_idle
+ <idle>-0 3.N.. 25us : __schedule <-preempt_schedule
+ <idle>-0 3.N.. 26us : add_preempt_count <-__schedule
+ <idle>-0 3.N.1 26us : rcu_note_context_switch <-__schedule
+ <idle>-0 3.N.1 26us : rcu_sched_qs <-rcu_note_context_switch
+ <idle>-0 3dN.1 27us : rcu_preempt_qs <-rcu_note_context_switch
+ <idle>-0 3.N.1 27us : _raw_spin_lock_irq <-__schedule
+ <idle>-0 3dN.1 27us : add_preempt_count <-_raw_spin_lock_irq
+ <idle>-0 3dN.2 28us : put_prev_task_idle <-__schedule
+ <idle>-0 3dN.2 28us : pick_next_task_stop <-pick_next_task
+ <idle>-0 3dN.2 28us : pick_next_task_rt <-pick_next_task
+ <idle>-0 3dN.2 29us : dequeue_pushable_task <-pick_next_task_rt
+ <idle>-0 3d..3 29us : __schedule <-preempt_schedule
+ <idle>-0 3d..3 30us : 0:120:R ==> [003] 2448: 94:R sleep
+
+This isn't that big of a trace, even with function tracing enabled,
+so I included the entire trace.
+
+The interrupt went off while when the system was idle. Somewhere
+before task_woken_rt() was called, the NEED_RESCHED flag was set,
+this is indicated by the first occurrence of the 'N' flag.
+
+Latency tracing and events
+--------------------------
+As function tracing can induce a much larger latency, but without
+seeing what happens within the latency it is hard to know what
+caused it. There is a middle ground, and that is with enabling
+events.
+
+ # echo 0 > options/function-trace
+ # echo wakeup_rt > current_tracer
+ # echo 1 > events/enable
+ # echo 1 > tracing_on
+ # echo 0 > tracing_max_latency
+ # chrt -f 5 sleep 1
+ # echo 0 > tracing_on
+ # cat trace
+# tracer: wakeup_rt
+#
+# wakeup_rt latency trace v1.1.5 on 3.8.0-test+
+# --------------------------------------------------------------------
+# latency: 6 us, #12/12, CPU#2 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:4)
+# -----------------
+# | task: sleep-5882 (uid:0 nice:0 policy:1 rt_prio:5)
+# -----------------
+#
+# _------=> CPU#
+# / _-----=> irqs-off
+# | / _----=> need-resched
+# || / _---=> hardirq/softirq
+# ||| / _--=> preempt-depth
+# |||| / delay
+# cmd pid ||||| time | caller
+# \ / ||||| \ | /
+ <idle>-0 2d.h4 0us : 0:120:R + [002] 5882: 94:R sleep
+ <idle>-0 2d.h4 0us : ttwu_do_activate.constprop.87 <-try_to_wake_up
+ <idle>-0 2d.h4 1us : sched_wakeup: comm=sleep pid=5882 prio=94 success=1 target_cpu=002
+ <idle>-0 2dNh2 1us : hrtimer_expire_exit: hrtimer=ffff88007796feb8
+ <idle>-0 2.N.2 2us : power_end: cpu_id=2
+ <idle>-0 2.N.2 3us : cpu_idle: state=4294967295 cpu_id=2
+ <idle>-0 2dN.3 4us : hrtimer_cancel: hrtimer=ffff88007d50d5e0
+ <idle>-0 2dN.3 4us : hrtimer_start: hrtimer=ffff88007d50d5e0 function=tick_sched_timer expires=34311211000000 softexpires=34311211000000
+ <idle>-0 2.N.2 5us : rcu_utilization: Start context switch
+ <idle>-0 2.N.2 5us : rcu_utilization: End context switch
+ <idle>-0 2d..3 6us : __schedule <-schedule
+ <idle>-0 2d..3 6us : 0:120:R ==> [002] 5882: 94:R sleep
+
function
--------
@@ -1039,6 +1653,7 @@ function
This tracer is the function tracer. Enabling the function tracer
can be done from the debug file system. Make sure the
ftrace_enabled is set; otherwise this tracer is a nop.
+See the "ftrace_enabled" section below.
# sysctl kernel.ftrace_enabled=1
# echo function > current_tracer
@@ -1048,23 +1663,23 @@ ftrace_enabled is set; otherwise this tracer is a nop.
# cat trace
# tracer: function
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
- bash-4003 [00] 123.638713: finish_task_switch <-schedule
- bash-4003 [00] 123.638714: _spin_unlock_irq <-finish_task_switch
- bash-4003 [00] 123.638714: sub_preempt_count <-_spin_unlock_irq
- bash-4003 [00] 123.638715: hrtick_set <-schedule
- bash-4003 [00] 123.638715: _spin_lock_irqsave <-hrtick_set
- bash-4003 [00] 123.638716: add_preempt_count <-_spin_lock_irqsave
- bash-4003 [00] 123.638716: _spin_unlock_irqrestore <-hrtick_set
- bash-4003 [00] 123.638717: sub_preempt_count <-_spin_unlock_irqrestore
- bash-4003 [00] 123.638717: hrtick_clear <-hrtick_set
- bash-4003 [00] 123.638718: sub_preempt_count <-schedule
- bash-4003 [00] 123.638718: sub_preempt_count <-preempt_schedule
- bash-4003 [00] 123.638719: wait_for_completion <-__stop_machine_run
- bash-4003 [00] 123.638719: wait_for_common <-wait_for_completion
- bash-4003 [00] 123.638720: _spin_lock_irq <-wait_for_common
- bash-4003 [00] 123.638720: add_preempt_count <-_spin_lock_irq
+# entries-in-buffer/entries-written: 24799/24799 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ bash-1994 [002] .... 3082.063030: mutex_unlock <-rb_simple_write
+ bash-1994 [002] .... 3082.063031: __mutex_unlock_slowpath <-mutex_unlock
+ bash-1994 [002] .... 3082.063031: __fsnotify_parent <-fsnotify_modify
+ bash-1994 [002] .... 3082.063032: fsnotify <-fsnotify_modify
+ bash-1994 [002] .... 3082.063032: __srcu_read_lock <-fsnotify
+ bash-1994 [002] .... 3082.063032: add_preempt_count <-__srcu_read_lock
+ bash-1994 [002] ...1 3082.063032: sub_preempt_count <-__srcu_read_lock
+ bash-1994 [002] .... 3082.063033: __srcu_read_unlock <-fsnotify
[...]
@@ -1214,79 +1829,19 @@ int main (int argc, char **argv)
return 0;
}
+Or this simple script!
-hw-branch-tracer (x86 only)
----------------------------
-
-This tracer uses the x86 last branch tracing hardware feature to
-collect a branch trace on all cpus with relatively low overhead.
-
-The tracer uses a fixed-size circular buffer per cpu and only
-traces ring 0 branches. The trace file dumps that buffer in the
-following format:
-
-# tracer: hw-branch-tracer
-#
-# CPU# TO <- FROM
- 0 scheduler_tick+0xb5/0x1bf <- task_tick_idle+0x5/0x6
- 2 run_posix_cpu_timers+0x2b/0x72a <- run_posix_cpu_timers+0x25/0x72a
- 0 scheduler_tick+0x139/0x1bf <- scheduler_tick+0xed/0x1bf
- 0 scheduler_tick+0x17c/0x1bf <- scheduler_tick+0x148/0x1bf
- 2 run_posix_cpu_timers+0x9e/0x72a <- run_posix_cpu_timers+0x5e/0x72a
- 0 scheduler_tick+0x1b6/0x1bf <- scheduler_tick+0x1aa/0x1bf
-
-
-The tracer may be used to dump the trace for the oops'ing cpu on
-a kernel oops into the system log. To enable this,
-ftrace_dump_on_oops must be set. To set ftrace_dump_on_oops, one
-can either use the sysctl function or set it via the proc system
-interface.
-
- sysctl kernel.ftrace_dump_on_oops=n
-
-or
-
- echo n > /proc/sys/kernel/ftrace_dump_on_oops
-
-If n = 1, ftrace will dump buffers of all CPUs, if n = 2 ftrace will
-only dump the buffer of the CPU that triggered the oops.
-
-Here's an example of such a dump after a null pointer
-dereference in a kernel module:
-
-[57848.105921] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
-[57848.106019] IP: [<ffffffffa0000006>] open+0x6/0x14 [oops]
-[57848.106019] PGD 2354e9067 PUD 2375e7067 PMD 0
-[57848.106019] Oops: 0002 [#1] SMP
-[57848.106019] last sysfs file: /sys/devices/pci0000:00/0000:00:1e.0/0000:20:05.0/local_cpus
-[57848.106019] Dumping ftrace buffer:
-[57848.106019] ---------------------------------
-[...]
-[57848.106019] 0 chrdev_open+0xe6/0x165 <- cdev_put+0x23/0x24
-[57848.106019] 0 chrdev_open+0x117/0x165 <- chrdev_open+0xfa/0x165
-[57848.106019] 0 chrdev_open+0x120/0x165 <- chrdev_open+0x11c/0x165
-[57848.106019] 0 chrdev_open+0x134/0x165 <- chrdev_open+0x12b/0x165
-[57848.106019] 0 open+0x0/0x14 [oops] <- chrdev_open+0x144/0x165
-[57848.106019] 0 page_fault+0x0/0x30 <- open+0x6/0x14 [oops]
-[57848.106019] 0 error_entry+0x0/0x5b <- page_fault+0x4/0x30
-[57848.106019] 0 error_kernelspace+0x0/0x31 <- error_entry+0x59/0x5b
-[57848.106019] 0 error_sti+0x0/0x1 <- error_kernelspace+0x2d/0x31
-[57848.106019] 0 page_fault+0x9/0x30 <- error_sti+0x0/0x1
-[57848.106019] 0 do_page_fault+0x0/0x881 <- page_fault+0x1a/0x30
-[...]
-[57848.106019] 0 do_page_fault+0x66b/0x881 <- is_prefetch+0x1ee/0x1f2
-[57848.106019] 0 do_page_fault+0x6e0/0x881 <- do_page_fault+0x67a/0x881
-[57848.106019] 0 oops_begin+0x0/0x96 <- do_page_fault+0x6e0/0x881
-[57848.106019] 0 trace_hw_branch_oops+0x0/0x2d <- oops_begin+0x9/0x96
-[...]
-[57848.106019] 0 ds_suspend_bts+0x2a/0xe3 <- ds_suspend_bts+0x1a/0xe3
-[57848.106019] ---------------------------------
-[57848.106019] CPU 0
-[57848.106019] Modules linked in: oops
-[57848.106019] Pid: 5542, comm: cat Tainted: G W 2.6.28 #23
-[57848.106019] RIP: 0010:[<ffffffffa0000006>] [<ffffffffa0000006>] open+0x6/0x14 [oops]
-[57848.106019] RSP: 0018:ffff880235457d48 EFLAGS: 00010246
-[...]
+------
+#!/bin/bash
+
+debugfs=`sed -ne 's/^debugfs \(.*\) debugfs.*/\1/p' /proc/mounts`
+echo nop > $debugfs/tracing/current_tracer
+echo 0 > $debugfs/tracing/tracing_on
+echo $$ > $debugfs/tracing/set_ftrace_pid
+echo function > $debugfs/tracing/current_tracer
+echo 1 > $debugfs/tracing/tracing_on
+exec "$@"
+------
function graph tracer
@@ -1473,16 +2028,18 @@ starts of pointing to a simple return. (Enabling FTRACE will
include the -pg switch in the compiling of the kernel.)
At compile time every C file object is run through the
-recordmcount.pl script (located in the scripts directory). This
-script will process the C object using objdump to find all the
-locations in the .text section that call mcount. (Note, only the
-.text section is processed, since processing other sections like
-.init.text may cause races due to those sections being freed).
+recordmcount program (located in the scripts directory). This
+program will parse the ELF headers in the C object to find all
+the locations in the .text section that call mcount. (Note, only
+white listed .text sections are processed, since processing other
+sections like .init.text may cause races due to those sections
+being freed unexpectedly).
A new section called "__mcount_loc" is created that holds
references to all the mcount call sites in the .text section.
-This section is compiled back into the original object. The
-final linker will add all these references into a single table.
+The recordmcount program re-links this section back into the
+original object. The final linking stage of the kernel will add all these
+references into a single table.
On boot up, before SMP is initialized, the dynamic ftrace code
scans this table and updates all the locations into nops. It
@@ -1493,13 +2050,25 @@ unloaded, it also removes its functions from the ftrace function
list. This is automatic in the module unload code, and the
module author does not need to worry about it.
-When tracing is enabled, kstop_machine is called to prevent
-races with the CPUS executing code being modified (which can
-cause the CPU to do undesirable things), and the nops are
+When tracing is enabled, the process of modifying the function
+tracepoints is dependent on architecture. The old method is to use
+kstop_machine to prevent races with the CPUs executing code being
+modified (which can cause the CPU to do undesirable things, especially
+if the modified code crosses cache (or page) boundaries), and the nops are
patched back to calls. But this time, they do not call mcount
(which is just a function stub). They now call into the ftrace
infrastructure.
+The new method of modifying the function tracepoints is to place
+a breakpoint at the location to be modified, sync all CPUs, modify
+the rest of the instruction not covered by the breakpoint. Sync
+all CPUs again, and then remove the breakpoint with the finished
+version to the ftrace call site.
+
+Some archs do not even need to monkey around with the synchronization,
+and can just slap the new code on top of the old without any
+problems with other CPUs executing it at the same time.
+
One special side-effect to the recording of the functions being
traced is that we can now selectively choose which functions we
wish to trace and which ones we want the mcount calls to remain
@@ -1530,20 +2099,28 @@ mutex_lock
If I am only interested in sys_nanosleep and hrtimer_interrupt:
- # echo sys_nanosleep hrtimer_interrupt \
- > set_ftrace_filter
+ # echo sys_nanosleep hrtimer_interrupt > set_ftrace_filter
# echo function > current_tracer
# echo 1 > tracing_on
# usleep 1
# echo 0 > tracing_on
# cat trace
-# tracer: ftrace
+# tracer: function
+#
+# entries-in-buffer/entries-written: 5/5 #P:4
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
- usleep-4134 [00] 1317.070017: hrtimer_interrupt <-smp_apic_timer_interrupt
- usleep-4134 [00] 1317.070111: sys_nanosleep <-syscall_call
- <idle>-0 [00] 1317.070115: hrtimer_interrupt <-smp_apic_timer_interrupt
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ usleep-2665 [001] .... 4186.475355: sys_nanosleep <-system_call_fastpath
+ <idle>-0 [001] d.h1 4186.475409: hrtimer_interrupt <-smp_apic_timer_interrupt
+ usleep-2665 [001] d.h1 4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
+ <idle>-0 [003] d.h1 4186.475426: hrtimer_interrupt <-smp_apic_timer_interrupt
+ <idle>-0 [002] d.h1 4186.475427: hrtimer_interrupt <-smp_apic_timer_interrupt
To see which functions are being traced, you can cat the file:
@@ -1571,20 +2148,25 @@ Note: It is better to use quotes to enclose the wild cards,
Produces:
-# tracer: ftrace
+# tracer: function
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
- bash-4003 [00] 1480.611794: hrtimer_init <-copy_process
- bash-4003 [00] 1480.611941: hrtimer_start <-hrtick_set
- bash-4003 [00] 1480.611956: hrtimer_cancel <-hrtick_clear
- bash-4003 [00] 1480.611956: hrtimer_try_to_cancel <-hrtimer_cancel
- <idle>-0 [00] 1480.612019: hrtimer_get_next_event <-get_next_timer_interrupt
- <idle>-0 [00] 1480.612025: hrtimer_get_next_event <-get_next_timer_interrupt
- <idle>-0 [00] 1480.612032: hrtimer_get_next_event <-get_next_timer_interrupt
- <idle>-0 [00] 1480.612037: hrtimer_get_next_event <-get_next_timer_interrupt
- <idle>-0 [00] 1480.612382: hrtimer_get_next_event <-get_next_timer_interrupt
-
+# entries-in-buffer/entries-written: 897/897 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ <idle>-0 [003] dN.1 4228.547803: hrtimer_cancel <-tick_nohz_idle_exit
+ <idle>-0 [003] dN.1 4228.547804: hrtimer_try_to_cancel <-hrtimer_cancel
+ <idle>-0 [003] dN.2 4228.547805: hrtimer_force_reprogram <-__remove_hrtimer
+ <idle>-0 [003] dN.1 4228.547805: hrtimer_forward <-tick_nohz_idle_exit
+ <idle>-0 [003] dN.1 4228.547805: hrtimer_start_range_ns <-hrtimer_start_expires.constprop.11
+ <idle>-0 [003] d..1 4228.547858: hrtimer_get_next_event <-get_next_timer_interrupt
+ <idle>-0 [003] d..1 4228.547859: hrtimer_start <-__tick_nohz_idle_enter
+ <idle>-0 [003] d..2 4228.547860: hrtimer_force_reprogram <-__rem
Notice that we lost the sys_nanosleep.
@@ -1651,19 +2233,29 @@ traced.
Produces:
-# tracer: ftrace
+# tracer: function
+#
+# entries-in-buffer/entries-written: 39608/39608 #P:4
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
- bash-4043 [01] 115.281644: finish_task_switch <-schedule
- bash-4043 [01] 115.281645: hrtick_set <-schedule
- bash-4043 [01] 115.281645: hrtick_clear <-hrtick_set
- bash-4043 [01] 115.281646: wait_for_completion <-__stop_machine_run
- bash-4043 [01] 115.281647: wait_for_common <-wait_for_completion
- bash-4043 [01] 115.281647: kthread_stop <-stop_machine_run
- bash-4043 [01] 115.281648: init_waitqueue_head <-kthread_stop
- bash-4043 [01] 115.281648: wake_up_process <-kthread_stop
- bash-4043 [01] 115.281649: try_to_wake_up <-wake_up_process
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ bash-1994 [000] .... 4342.324896: file_ra_state_init <-do_dentry_open
+ bash-1994 [000] .... 4342.324897: open_check_o_direct <-do_last
+ bash-1994 [000] .... 4342.324897: ima_file_check <-do_last
+ bash-1994 [000] .... 4342.324898: process_measurement <-ima_file_check
+ bash-1994 [000] .... 4342.324898: ima_get_action <-process_measurement
+ bash-1994 [000] .... 4342.324898: ima_match_policy <-ima_get_action
+ bash-1994 [000] .... 4342.324899: do_truncate <-do_last
+ bash-1994 [000] .... 4342.324899: should_remove_suid <-do_truncate
+ bash-1994 [000] .... 4342.324899: notify_change <-do_truncate
+ bash-1994 [000] .... 4342.324900: current_fs_time <-notify_change
+ bash-1994 [000] .... 4342.324900: current_kernel_time <-current_fs_time
+ bash-1994 [000] .... 4342.324900: timespec_trunc <-current_fs_time
We can see that there's no more lock or preempt tracing.
@@ -1729,6 +2321,28 @@ this special filter via:
echo > set_graph_function
+ftrace_enabled
+--------------
+
+Note, the proc sysctl ftrace_enable is a big on/off switch for the
+function tracer. By default it is enabled (when function tracing is
+enabled in the kernel). If it is disabled, all function tracing is
+disabled. This includes not only the function tracers for ftrace, but
+also for any other uses (perf, kprobes, stack tracing, profiling, etc).
+
+Please disable this with care.
+
+This can be disable (and enabled) with:
+
+ sysctl kernel.ftrace_enabled=0
+ sysctl kernel.ftrace_enabled=1
+
+ or
+
+ echo 0 > /proc/sys/kernel/ftrace_enabled
+ echo 1 > /proc/sys/kernel/ftrace_enabled
+
+
Filter commands
---------------
@@ -1763,12 +2377,58 @@ The following commands are supported:
echo '__schedule_bug:traceoff:5' > set_ftrace_filter
+ To always disable tracing when __schedule_bug is hit:
+
+ echo '__schedule_bug:traceoff' > set_ftrace_filter
+
These commands are cumulative whether or not they are appended
to set_ftrace_filter. To remove a command, prepend it by '!'
and drop the parameter:
+ echo '!__schedule_bug:traceoff:0' > set_ftrace_filter
+
+ The above removes the traceoff command for __schedule_bug
+ that have a counter. To remove commands without counters:
+
echo '!__schedule_bug:traceoff' > set_ftrace_filter
+- snapshot
+ Will cause a snapshot to be triggered when the function is hit.
+
+ echo 'native_flush_tlb_others:snapshot' > set_ftrace_filter
+
+ To only snapshot once:
+
+ echo 'native_flush_tlb_others:snapshot:1' > set_ftrace_filter
+
+ To remove the above commands:
+
+ echo '!native_flush_tlb_others:snapshot' > set_ftrace_filter
+ echo '!native_flush_tlb_others:snapshot:0' > set_ftrace_filter
+
+- enable_event/disable_event
+ These commands can enable or disable a trace event. Note, because
+ function tracing callbacks are very sensitive, when these commands
+ are registered, the trace point is activated, but disabled in
+ a "soft" mode. That is, the tracepoint will be called, but
+ just will not be traced. The event tracepoint stays in this mode
+ as long as there's a command that triggers it.
+
+ echo 'try_to_wake_up:enable_event:sched:sched_switch:2' > \
+ set_ftrace_filter
+
+ The format is:
+
+ <function>:enable_event:<system>:<event>[:count]
+ <function>:disable_event:<system>:<event>[:count]
+
+ To remove the events commands:
+
+
+ echo '!try_to_wake_up:enable_event:sched:sched_switch:0' > \
+ set_ftrace_filter
+ echo '!schedule:disable_event:sched:sched_switch' > \
+ set_ftrace_filter
trace_pipe
----------
@@ -1787,28 +2447,31 @@ different. The trace is live.
# cat trace
# tracer: function
#
-# TASK-PID CPU# TIMESTAMP FUNCTION
-# | | | | |
+# entries-in-buffer/entries-written: 0/0 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
#
# cat /tmp/trace.out
- bash-4043 [00] 41.267106: finish_task_switch <-schedule
- bash-4043 [00] 41.267106: hrtick_set <-schedule
- bash-4043 [00] 41.267107: hrtick_clear <-hrtick_set
- bash-4043 [00] 41.267108: wait_for_completion <-__stop_machine_run
- bash-4043 [00] 41.267108: wait_for_common <-wait_for_completion
- bash-4043 [00] 41.267109: kthread_stop <-stop_machine_run
- bash-4043 [00] 41.267109: init_waitqueue_head <-kthread_stop
- bash-4043 [00] 41.267110: wake_up_process <-kthread_stop
- bash-4043 [00] 41.267110: try_to_wake_up <-wake_up_process
- bash-4043 [00] 41.267111: select_task_rq_rt <-try_to_wake_up
+ bash-1994 [000] .... 5281.568961: mutex_unlock <-rb_simple_write
+ bash-1994 [000] .... 5281.568963: __mutex_unlock_slowpath <-mutex_unlock
+ bash-1994 [000] .... 5281.568963: __fsnotify_parent <-fsnotify_modify
+ bash-1994 [000] .... 5281.568964: fsnotify <-fsnotify_modify
+ bash-1994 [000] .... 5281.568964: __srcu_read_lock <-fsnotify
+ bash-1994 [000] .... 5281.568964: add_preempt_count <-__srcu_read_lock
+ bash-1994 [000] ...1 5281.568965: sub_preempt_count <-__srcu_read_lock
+ bash-1994 [000] .... 5281.568965: __srcu_read_unlock <-fsnotify
+ bash-1994 [000] .... 5281.568967: sys_dup2 <-system_call_fastpath
Note, reading the trace_pipe file will block until more input is
-added. By changing the tracer, trace_pipe will issue an EOF. We
-needed to set the function tracer _before_ we "cat" the
-trace_pipe file.
-
+added.
trace entries
-------------
@@ -1817,31 +2480,50 @@ Having too much or not enough data can be troublesome in
diagnosing an issue in the kernel. The file buffer_size_kb is
used to modify the size of the internal trace buffers. The
number listed is the number of entries that can be recorded per
-CPU. To know the full size, multiply the number of possible CPUS
+CPU. To know the full size, multiply the number of possible CPUs
with the number of entries.
# cat buffer_size_kb
1408 (units kilobytes)
-Note, to modify this, you must have tracing completely disabled.
-To do that, echo "nop" into the current_tracer. If the
-current_tracer is not set to "nop", an EINVAL error will be
-returned.
+Or simply read buffer_total_size_kb
+
+ # cat buffer_total_size_kb
+5632
+
+To modify the buffer, simple echo in a number (in 1024 byte segments).
- # echo nop > current_tracer
# echo 10000 > buffer_size_kb
# cat buffer_size_kb
10000 (units kilobytes)
-The number of pages which will be allocated is limited to a
-percentage of available memory. Allocating too much will produce
-an error.
+It will try to allocate as much as possible. If you allocate too
+much, it can cause Out-Of-Memory to trigger.
# echo 1000000000000 > buffer_size_kb
-bash: echo: write error: Cannot allocate memory
# cat buffer_size_kb
85
+The per_cpu buffers can be changed individually as well:
+
+ # echo 10000 > per_cpu/cpu0/buffer_size_kb
+ # echo 100 > per_cpu/cpu1/buffer_size_kb
+
+When the per_cpu buffers are not the same, the buffer_size_kb
+at the top level will just show an X
+
+ # cat buffer_size_kb
+X
+
+This is where the buffer_total_size_kb is useful:
+
+ # cat buffer_total_size_kb
+12916
+
+Writing to the top level buffer_size_kb will reset all the buffers
+to be the same again.
+
Snapshot
--------
CONFIG_TRACER_SNAPSHOT makes a generic snapshot feature
@@ -1925,7 +2607,188 @@ bash: echo: write error: Device or resource busy
# cat snapshot
cat: snapshot: Device or resource busy
+
+Instances
+---------
+In the debugfs tracing directory is a directory called "instances".
+This directory can have new directories created inside of it using
+mkdir, and removing directories with rmdir. The directory created
+with mkdir in this directory will already contain files and other
+directories after it is created.
+
+ # mkdir instances/foo
+ # ls instances/foo
+buffer_size_kb buffer_total_size_kb events free_buffer per_cpu
+set_event snapshot trace trace_clock trace_marker trace_options
+trace_pipe tracing_on
+
+As you can see, the new directory looks similar to the tracing directory
+itself. In fact, it is very similar, except that the buffer and
+events are agnostic from the main director, or from any other
+instances that are created.
+
+The files in the new directory work just like the files with the
+same name in the tracing directory except the buffer that is used
+is a separate and new buffer. The files affect that buffer but do not
+affect the main buffer with the exception of trace_options. Currently,
+the trace_options affect all instances and the top level buffer
+the same, but this may change in future releases. That is, options
+may become specific to the instance they reside in.
+
+Notice that none of the function tracer files are there, nor is
+current_tracer and available_tracers. This is because the buffers
+can currently only have events enabled for them.
+
+ # mkdir instances/foo
+ # mkdir instances/bar
+ # mkdir instances/zoot
+ # echo 100000 > buffer_size_kb
+ # echo 1000 > instances/foo/buffer_size_kb
+ # echo 5000 > instances/bar/per_cpu/cpu1/buffer_size_kb
+ # echo function > current_trace
+ # echo 1 > instances/foo/events/sched/sched_wakeup/enable
+ # echo 1 > instances/foo/events/sched/sched_wakeup_new/enable
+ # echo 1 > instances/foo/events/sched/sched_switch/enable
+ # echo 1 > instances/bar/events/irq/enable
+ # echo 1 > instances/zoot/events/syscalls/enable
+ # cat trace_pipe
+CPU:2 [LOST 11745 EVENTS]
+ bash-2044 [002] .... 10594.481032: _raw_spin_lock_irqsave <-get_page_from_freelist
+ bash-2044 [002] d... 10594.481032: add_preempt_count <-_raw_spin_lock_irqsave
+ bash-2044 [002] d..1 10594.481032: __rmqueue <-get_page_from_freelist
+ bash-2044 [002] d..1 10594.481033: _raw_spin_unlock <-get_page_from_freelist
+ bash-2044 [002] d..1 10594.481033: sub_preempt_count <-_raw_spin_unlock
+ bash-2044 [002] d... 10594.481033: get_pageblock_flags_group <-get_pageblock_migratetype
+ bash-2044 [002] d... 10594.481034: __mod_zone_page_state <-get_page_from_freelist
+ bash-2044 [002] d... 10594.481034: zone_statistics <-get_page_from_freelist
+ bash-2044 [002] d... 10594.481034: __inc_zone_state <-zone_statistics
+ bash-2044 [002] d... 10594.481034: __inc_zone_state <-zone_statistics
+ bash-2044 [002] .... 10594.481035: arch_dup_task_struct <-copy_process
+[...]
+
+ # cat instances/foo/trace_pipe
+ bash-1998 [000] d..4 136.676759: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
+ bash-1998 [000] dN.4 136.676760: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
+ <idle>-0 [003] d.h3 136.676906: sched_wakeup: comm=rcu_preempt pid=9 prio=120 success=1 target_cpu=003
+ <idle>-0 [003] d..3 136.676909: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=rcu_preempt next_pid=9 next_prio=120
+ rcu_preempt-9 [003] d..3 136.676916: sched_switch: prev_comm=rcu_preempt prev_pid=9 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
+ bash-1998 [000] d..4 136.677014: sched_wakeup: comm=kworker/0:1 pid=59 prio=120 success=1 target_cpu=000
+ bash-1998 [000] dN.4 136.677016: sched_wakeup: comm=bash pid=1998 prio=120 success=1 target_cpu=000
+ bash-1998 [000] d..3 136.677018: sched_switch: prev_comm=bash prev_pid=1998 prev_prio=120 prev_state=R+ ==> next_comm=kworker/0:1 next_pid=59 next_prio=120
+ kworker/0:1-59 [000] d..4 136.677022: sched_wakeup: comm=sshd pid=1995 prio=120 success=1 target_cpu=001
+ kworker/0:1-59 [000] d..3 136.677025: sched_switch: prev_comm=kworker/0:1 prev_pid=59 prev_prio=120 prev_state=S ==> next_comm=bash next_pid=1998 next_prio=120
+[...]
+
+ # cat instances/bar/trace_pipe
+ migration/1-14 [001] d.h3 138.732674: softirq_raise: vec=3 [action=NET_RX]
+ <idle>-0 [001] dNh3 138.732725: softirq_raise: vec=3 [action=NET_RX]
+ bash-1998 [000] d.h1 138.733101: softirq_raise: vec=1 [action=TIMER]
+ bash-1998 [000] d.h1 138.733102: softirq_raise: vec=9 [action=RCU]
+ bash-1998 [000] ..s2 138.733105: softirq_entry: vec=1 [action=TIMER]
+ bash-1998 [000] ..s2 138.733106: softirq_exit: vec=1 [action=TIMER]
+ bash-1998 [000] ..s2 138.733106: softirq_entry: vec=9 [action=RCU]
+ bash-1998 [000] ..s2 138.733109: softirq_exit: vec=9 [action=RCU]
+ sshd-1995 [001] d.h1 138.733278: irq_handler_entry: irq=21 name=uhci_hcd:usb4
+ sshd-1995 [001] d.h1 138.733280: irq_handler_exit: irq=21 ret=unhandled
+ sshd-1995 [001] d.h1 138.733281: irq_handler_entry: irq=21 name=eth0
+ sshd-1995 [001] d.h1 138.733283: irq_handler_exit: irq=21 ret=handled
+[...]
+
+ # cat instances/zoot/trace
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 18996/18996 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID CPU# |||| TIMESTAMP FUNCTION
+# | | | |||| | |
+ bash-1998 [000] d... 140.733501: sys_write -> 0x2
+ bash-1998 [000] d... 140.733504: sys_dup2(oldfd: a, newfd: 1)
+ bash-1998 [000] d... 140.733506: sys_dup2 -> 0x1
+ bash-1998 [000] d... 140.733508: sys_fcntl(fd: a, cmd: 1, arg: 0)
+ bash-1998 [000] d... 140.733509: sys_fcntl -> 0x1
+ bash-1998 [000] d... 140.733510: sys_close(fd: a)
+ bash-1998 [000] d... 140.733510: sys_close -> 0x0
+ bash-1998 [000] d... 140.733514: sys_rt_sigprocmask(how: 0, nset: 0, oset: 6e2768, sigsetsize: 8)
+ bash-1998 [000] d... 140.733515: sys_rt_sigprocmask -> 0x0
+ bash-1998 [000] d... 140.733516: sys_rt_sigaction(sig: 2, act: 7fff718846f0, oact: 7fff71884650, sigsetsize: 8)
+ bash-1998 [000] d... 140.733516: sys_rt_sigaction -> 0x0
+
+You can see that the trace of the top most trace buffer shows only
+the function tracing. The foo instance displays wakeups and task
+switches.
+
+To remove the instances, simply delete their directories:
+
+ # rmdir instances/foo
+ # rmdir instances/bar
+ # rmdir instances/zoot
+
+Note, if a process has a trace file open in one of the instance
+directories, the rmdir will fail with EBUSY.
+
+
+Stack trace
-----------
+Since the kernel has a fixed sized stack, it is important not to
+waste it in functions. A kernel developer must be conscience of
+what they allocate on the stack. If they add too much, the system
+can be in danger of a stack overflow, and corruption will occur,
+usually leading to a system panic.
+
+There are some tools that check this, usually with interrupts
+periodically checking usage. But if you can perform a check
+at every function call that will become very useful. As ftrace provides
+a function tracer, it makes it convenient to check the stack size
+at every function call. This is enabled via the stack tracer.
+
+CONFIG_STACK_TRACER enables the ftrace stack tracing functionality.
+To enable it, write a '1' into /proc/sys/kernel/stack_tracer_enabled.
+
+ # echo 1 > /proc/sys/kernel/stack_tracer_enabled
+
+You can also enable it from the kernel command line to trace
+the stack size of the kernel during boot up, by adding "stacktrace"
+to the kernel command line parameter.
+
+After running it for a few minutes, the output looks like:
+
+ # cat stack_max_size
+2928
+
+ # cat stack_trace
+ Depth Size Location (18 entries)
+ ----- ---- --------
+ 0) 2928 224 update_sd_lb_stats+0xbc/0x4ac
+ 1) 2704 160 find_busiest_group+0x31/0x1f1
+ 2) 2544 256 load_balance+0xd9/0x662
+ 3) 2288 80 idle_balance+0xbb/0x130
+ 4) 2208 128 __schedule+0x26e/0x5b9
+ 5) 2080 16 schedule+0x64/0x66
+ 6) 2064 128 schedule_timeout+0x34/0xe0
+ 7) 1936 112 wait_for_common+0x97/0xf1
+ 8) 1824 16 wait_for_completion+0x1d/0x1f
+ 9) 1808 128 flush_work+0xfe/0x119
+ 10) 1680 16 tty_flush_to_ldisc+0x1e/0x20
+ 11) 1664 48 input_available_p+0x1d/0x5c
+ 12) 1616 48 n_tty_poll+0x6d/0x134
+ 13) 1568 64 tty_poll+0x64/0x7f
+ 14) 1504 880 do_select+0x31e/0x511
+ 15) 624 400 core_sys_select+0x177/0x216
+ 16) 224 96 sys_select+0x91/0xb9
+ 17) 128 128 system_call_fastpath+0x16/0x1b
+
+Note, if -mfentry is being used by gcc, functions get traced before
+they set up the stack frame. This means that leaf level functions
+are not tested by the stack tracer when -mfentry is used.
+
+Currently, -mfentry is used by gcc 4.6.0 and above on x86 only.
+
+---------
More details can be found in the source code, in the
kernel/trace/*.c files.
diff --git a/Documentation/trace/tracepoints.txt b/Documentation/trace/tracepoints.txt
index c0e1ceed75a4..da49437d5aeb 100644
--- a/Documentation/trace/tracepoints.txt
+++ b/Documentation/trace/tracepoints.txt
@@ -81,7 +81,6 @@ tracepoint_synchronize_unregister() must be called before the end of
the module exit function to make sure there is no caller left using
the probe. This, and the fact that preemption is disabled around the
probe call, make sure that probe removal and module unload are safe.
-See the "Probe example" section below for a sample probe module.
The tracepoint mechanism supports inserting multiple instances of the
same tracepoint, but a single definition must be made of a given
@@ -100,17 +99,3 @@ core kernel image or in modules.
If the tracepoint has to be used in kernel modules, an
EXPORT_TRACEPOINT_SYMBOL_GPL() or EXPORT_TRACEPOINT_SYMBOL() can be
used to export the defined tracepoints.
-
-* Probe / tracepoint example
-
-See the example provided in samples/tracepoints
-
-Compile them with your kernel. They are built during 'make' (not
-'make modules') when CONFIG_SAMPLE_TRACEPOINTS=m.
-
-Run, as root :
-modprobe tracepoint-sample (insmod order is not important)
-modprobe tracepoint-probe-sample
-cat /proc/tracepoint-sample (returns an expected error)
-rmmod tracepoint-sample tracepoint-probe-sample
-dmesg
diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt
index 24ce6823a09e..d9c3e682312c 100644
--- a/Documentation/trace/uprobetracer.txt
+++ b/Documentation/trace/uprobetracer.txt
@@ -1,6 +1,8 @@
- Uprobe-tracer: Uprobe-based Event Tracing
- =========================================
- Documentation written by Srikar Dronamraju
+ Uprobe-tracer: Uprobe-based Event Tracing
+ =========================================
+
+ Documentation written by Srikar Dronamraju
+
Overview
--------
@@ -13,78 +15,94 @@ current_tracer. Instead of that, add probe points via
/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
However unlike kprobe-event tracer, the uprobe event interface expects the
-user to calculate the offset of the probepoint in the object
+user to calculate the offset of the probepoint in the object.
Synopsis of uprobe_tracer
-------------------------
- p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe
+ p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a uprobe
+ r[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a return uprobe (uretprobe)
+ -:[GRP/]EVENT : Clear uprobe or uretprobe event
- GRP : Group name. If omitted, use "uprobes" for it.
- EVENT : Event name. If omitted, the event name is generated
- based on SYMBOL+offs.
- PATH : path to an executable or a library.
- SYMBOL[+offs] : Symbol+offset where the probe is inserted.
+ GRP : Group name. If omitted, "uprobes" is the default value.
+ EVENT : Event name. If omitted, the event name is generated based
+ on SYMBOL+offs.
+ PATH : Path to an executable or a library.
+ SYMBOL[+offs] : Symbol+offset where the probe is inserted.
- FETCHARGS : Arguments. Each probe can have up to 128 args.
- %REG : Fetch register REG
+ FETCHARGS : Arguments. Each probe can have up to 128 args.
+ %REG : Fetch register REG
Event Profiling
---------------
- You can check the total number of probe hits and probe miss-hits via
+You can check the total number of probe hits and probe miss-hits via
/sys/kernel/debug/tracing/uprobe_profile.
- The first column is event name, the second is the number of probe hits,
+The first column is event name, the second is the number of probe hits,
the third is the number of probe miss-hits.
Usage examples
--------------
-To add a probe as a new event, write a new definition to uprobe_events
-as below.
+ * Add a probe as a new uprobe event, write a new definition to uprobe_events
+as below: (sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash)
+
+ echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
+
+ * Add a probe as a new uretprobe event:
+
+ echo 'r: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
+
+ * Unset registered event:
- echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
+ echo '-:bash_0x4245c0' >> /sys/kernel/debug/tracing/uprobe_events
- This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash
+ * Print out the events that are registered:
- echo > /sys/kernel/debug/tracing/uprobe_events
+ cat /sys/kernel/debug/tracing/uprobe_events
- This clears all probe points.
+ * Clear all events:
-The following example shows how to dump the instruction pointer and %ax
-a register at the probed text address. Here we are trying to probe
-function zfree in /bin/zsh
+ echo > /sys/kernel/debug/tracing/uprobe_events
+
+Following example shows how to dump the instruction pointer and %ax register
+at the probed text address. Probe zfree function in /bin/zsh:
# cd /sys/kernel/debug/tracing/
- # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
+ # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
# objdump -T /bin/zsh | grep -w zfree
0000000000446420 g DF .text 0000000000000012 Base zfree
-0x46420 is the offset of zfree in object /bin/zsh that is loaded at
-0x00400000. Hence the command to probe would be :
+ 0x46420 is the offset of zfree in object /bin/zsh that is loaded at
+ 0x00400000. Hence the command to uprobe would be:
+
+ # echo 'p:zfree_entry /bin/zsh:0x46420 %ip %ax' > uprobe_events
+
+ And the same for the uretprobe would be:
- # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
+ # echo 'r:zfree_exit /bin/zsh:0x46420 %ip %ax' >> uprobe_events
-Please note: User has to explicitly calculate the offset of the probepoint
+Please note: User has to explicitly calculate the offset of the probe-point
in the object. We can see the events that are registered by looking at the
uprobe_events file.
# cat uprobe_events
- p:uprobes/p_zsh_0x46420 /bin/zsh:0x00046420 arg1=%ip arg2=%ax
+ p:uprobes/zfree_entry /bin/zsh:0x00046420 arg1=%ip arg2=%ax
+ r:uprobes/zfree_exit /bin/zsh:0x00046420 arg1=%ip arg2=%ax
-The format of events can be seen by viewing the file events/uprobes/p_zsh_0x46420/format
+Format of events can be seen by viewing the file events/uprobes/zfree_entry/format
- # cat events/uprobes/p_zsh_0x46420/format
- name: p_zsh_0x46420
+ # cat events/uprobes/zfree_entry/format
+ name: zfree_entry
ID: 922
format:
- field:unsigned short common_type; offset:0; size:2; signed:0;
- field:unsigned char common_flags; offset:2; size:1; signed:0;
- field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
- field:int common_pid; offset:4; size:4; signed:1;
- field:int common_padding; offset:8; size:4; signed:1;
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+ field:int common_padding; offset:8; size:4; signed:1;
- field:unsigned long __probe_ip; offset:12; size:4; signed:0;
- field:u32 arg1; offset:16; size:4; signed:0;
- field:u32 arg2; offset:20; size:4; signed:0;
+ field:unsigned long __probe_ip; offset:12; size:4; signed:0;
+ field:u32 arg1; offset:16; size:4; signed:0;
+ field:u32 arg2; offset:20; size:4; signed:0;
print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2
@@ -94,6 +112,7 @@ events, you need to enable it by:
# echo 1 > events/uprobes/enable
Lets disable the event after sleeping for some time.
+
# sleep 20
# echo 0 > events/uprobes/enable
@@ -104,10 +123,11 @@ And you can see the traced information via /sys/kernel/debug/tracing/trace.
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
- zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
- zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
- zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
- zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
-
-Each line shows us probes were triggered for a pid 24842 with ip being
-0x446421 and contents of ax register being 79.
+ zsh-24842 [006] 258544.995456: zfree_entry: (0x446420) arg1=446420 arg2=79
+ zsh-24842 [007] 258545.000270: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0
+ zsh-24842 [002] 258545.043929: zfree_entry: (0x446420) arg1=446420 arg2=79
+ zsh-24842 [004] 258547.046129: zfree_exit: (0x446540 <- 0x446420) arg1=446540 arg2=0
+
+Output shows us uprobe was triggered for a pid 24842 with ip being 0x446420
+and contents of ax register being 79. And uretprobe was triggered with ip at
+0x446540 with counterpart function entry at 0x446420.
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index 4204eb01fd38..1392b61d6ebe 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -33,6 +33,10 @@ built with CONFIG_USB_SUSPEND enabled (which depends on
CONFIG_PM_RUNTIME). System PM support is present only if the kernel
was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
+(Starting with the 3.10 kernel release, dynamic PM support for USB is
+present whenever the kernel was built with CONFIG_PM_RUNTIME enabled.
+The CONFIG_USB_SUSPEND option has been eliminated.)
+
What is Remote Wakeup?
----------------------
@@ -206,10 +210,8 @@ initialized to 5. (The idle-delay values for already existing devices
will not be affected.)
Setting the initial default idle-delay to -1 will prevent any
-autosuspend of any USB device. This is a simple alternative to
-disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
-added benefit of allowing you to enable autosuspend for selected
-devices.
+autosuspend of any USB device. This has the benefit of allowing you
+then to enable autosuspend for selected devices.
Warnings
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 3f12865b2a88..e81864405102 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -76,7 +76,7 @@
76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
77 -> EM2874 Leadership ISDBT (em2874)
78 -> PCTV nanoStick T2 290e (em28174)
- 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad]
+ 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad,0ccd:10b6]
80 -> PCTV DVB-S2 Stick (460e) (em28174)
81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605]
82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2]
@@ -85,3 +85,4 @@
85 -> PCTV QuatroStick (510e) (em2884) [2304:0242]
86 -> PCTV QuatroStick nano (520e) (em2884) [2013:0251]
87 -> Terratec Cinergy HTC USB XS (em2884) [0ccd:008e,0ccd:00ac]
+ 88 -> C3 Tech Digital Duo HDTV/SDTV USB (em2884) [1b80:e755]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index c83f6e418879..5b83a3ff15c2 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -86,3 +86,6 @@ tuner=85 - Philips FQ1236 MK5
tuner=86 - Tena TNF5337 MFD
tuner=87 - Xceive 4000 tuner
tuner=88 - Xceive 5000C tuner
+tuner=89 - Sony PAL+SECAM (BTF-PG472Z)
+tuner=90 - Sony NTSC-M-JP (BTF-PK467Z)
+tuner=91 - Sony NTSC-M (BTF-PB463Z)
diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt
new file mode 100644
index 000000000000..d1a08db2cbd9
--- /dev/null
+++ b/Documentation/video4linux/si476x.txt
@@ -0,0 +1,187 @@
+SI476x Driver Readme
+------------------------------------------------
+ Copyright (C) 2013 Andrey Smirnov <andrew.smirnov@gmail.com>
+
+TODO for the driver
+------------------------------
+
+- According to the SiLabs' datasheet it is possible to update the
+ firmware of the radio chip in the run-time, thus bringing it to the
+ most recent version. Unfortunately I couldn't find any mentioning of
+ the said firmware update for the old chips that I tested the driver
+ against, so for chips like that the driver only exposes the old
+ functionality.
+
+
+Parameters exposed over debugfs
+-------------------------------
+SI476x allow user to get multiple characteristics that can be very
+useful for EoL testing/RF performance estimation, parameters that have
+very little to do with V4L2 subsystem. Such parameters are exposed via
+debugfs and can be accessed via regular file I/O operations.
+
+The drivers exposes following files:
+
+* /sys/kernel/debug/<device-name>/acf
+ This file contains ACF(Automatically Controlled Features) status
+ information. The contents of the file is binary data of the
+ following layout:
+
+ Offset | Name | Description
+ ====================================================================
+ 0x00 | blend_int | Flag, set when stereo separation has
+ | | crossed below the blend threshold
+ --------------------------------------------------------------------
+ 0x01 | hblend_int | Flag, set when HiBlend cutoff
+ | | frequency is lower than threshold
+ --------------------------------------------------------------------
+ 0x02 | hicut_int | Flag, set when HiCut cutoff
+ | | frequency is lower than threshold
+ --------------------------------------------------------------------
+ 0x03 | chbw_int | Flag, set when channel filter
+ | | bandwidth is less than threshold
+ --------------------------------------------------------------------
+ 0x04 | softmute_int | Flag indicating that softmute
+ | | attenuation has increased above
+ | | softmute threshold
+ --------------------------------------------------------------------
+ 0x05 | smute | 0 - Audio is not soft muted
+ | | 1 - Audio is soft muted
+ --------------------------------------------------------------------
+ 0x06 | smattn | Soft mute attenuation level in dB
+ --------------------------------------------------------------------
+ 0x07 | chbw | Channel filter bandwidth in kHz
+ --------------------------------------------------------------------
+ 0x08 | hicut | HiCut cutoff frequency in units of
+ | | 100Hz
+ --------------------------------------------------------------------
+ 0x09 | hiblend | HiBlend cutoff frequency in units
+ | | of 100 Hz
+ --------------------------------------------------------------------
+ 0x10 | pilot | 0 - Stereo pilot is not present
+ | | 1 - Stereo pilot is present
+ --------------------------------------------------------------------
+ 0x11 | stblend | Stereo blend in %
+ --------------------------------------------------------------------
+
+
+* /sys/kernel/debug/<device-name>/rds_blckcnt
+ This file contains statistics about RDS receptions. It's binary data
+ has the following layout:
+
+ Offset | Name | Description
+ ====================================================================
+ 0x00 | expected | Number of expected RDS blocks
+ --------------------------------------------------------------------
+ 0x02 | received | Number of received RDS blocks
+ --------------------------------------------------------------------
+ 0x04 | uncorrectable | Number of uncorrectable RDS blocks
+ --------------------------------------------------------------------
+
+* /sys/kernel/debug/<device-name>/agc
+ This file contains information about parameters pertaining to
+ AGC(Automatic Gain Control)
+
+ The layout is:
+ Offset | Name | Description
+ ====================================================================
+ 0x00 | mxhi | 0 - FM Mixer PD high threshold is
+ | | not tripped
+ | | 1 - FM Mixer PD high threshold is
+ | | tripped
+ --------------------------------------------------------------------
+ 0x01 | mxlo | ditto for FM Mixer PD low
+ --------------------------------------------------------------------
+ 0x02 | lnahi | ditto for FM LNA PD high
+ --------------------------------------------------------------------
+ 0x03 | lnalo | ditto for FM LNA PD low
+ --------------------------------------------------------------------
+ 0x04 | fmagc1 | FMAGC1 attenuator resistance
+ | | (see datasheet for more detail)
+ --------------------------------------------------------------------
+ 0x05 | fmagc2 | ditto for FMAGC2
+ --------------------------------------------------------------------
+ 0x06 | pgagain | PGA gain in dB
+ --------------------------------------------------------------------
+ 0x07 | fmwblang | FM/WB LNA Gain in dB
+ --------------------------------------------------------------------
+
+* /sys/kernel/debug/<device-name>/rsq
+ This file contains information about parameters pertaining to
+ RSQ(Received Signal Quality)
+
+ The layout is:
+ Offset | Name | Description
+ ====================================================================
+ 0x00 | multhint | 0 - multipath value has not crossed
+ | | the Multipath high threshold
+ | | 1 - multipath value has crossed
+ | | the Multipath high threshold
+ --------------------------------------------------------------------
+ 0x01 | multlint | ditto for Multipath low threshold
+ --------------------------------------------------------------------
+ 0x02 | snrhint | 0 - received signal's SNR has not
+ | | crossed high threshold
+ | | 1 - received signal's SNR has
+ | | crossed high threshold
+ --------------------------------------------------------------------
+ 0x03 | snrlint | ditto for low threshold
+ --------------------------------------------------------------------
+ 0x04 | rssihint | ditto for RSSI high threshold
+ --------------------------------------------------------------------
+ 0x05 | rssilint | ditto for RSSI low threshold
+ --------------------------------------------------------------------
+ 0x06 | bltf | Flag indicating if seek command
+ | | reached/wrapped seek band limit
+ --------------------------------------------------------------------
+ 0x07 | snr_ready | Indicates that SNR metrics is ready
+ --------------------------------------------------------------------
+ 0x08 | rssiready | ditto for RSSI metrics
+ --------------------------------------------------------------------
+ 0x09 | injside | 0 - Low-side injection is being used
+ | | 1 - High-side injection is used
+ --------------------------------------------------------------------
+ 0x10 | afcrl | Flag indicating if AFC rails
+ --------------------------------------------------------------------
+ 0x11 | valid | Flag indicating if channel is valid
+ --------------------------------------------------------------------
+ 0x12 | readfreq | Current tuned frequency
+ --------------------------------------------------------------------
+ 0x14 | freqoff | Singed frequency offset in units of
+ | | 2ppm
+ --------------------------------------------------------------------
+ 0x15 | rssi | Signed value of RSSI in dBuV
+ --------------------------------------------------------------------
+ 0x16 | snr | Signed RF SNR in dB
+ --------------------------------------------------------------------
+ 0x17 | issi | Signed Image Strength Signal
+ | | indicator
+ --------------------------------------------------------------------
+ 0x18 | lassi | Signed Low side adjacent Channel
+ | | Strength indicator
+ --------------------------------------------------------------------
+ 0x19 | hassi | ditto fpr High side
+ --------------------------------------------------------------------
+ 0x20 | mult | Multipath indicator
+ --------------------------------------------------------------------
+ 0x21 | dev | Frequency deviation
+ --------------------------------------------------------------------
+ 0x24 | assi | Adjascent channel SSI
+ --------------------------------------------------------------------
+ 0x25 | usn | Ultrasonic noise indicator
+ --------------------------------------------------------------------
+ 0x26 | pilotdev | Pilot deviation in units of 100 Hz
+ --------------------------------------------------------------------
+ 0x27 | rdsdev | ditto for RDS
+ --------------------------------------------------------------------
+ 0x28 | assidev | ditto for ASSI
+ --------------------------------------------------------------------
+ 0x29 | strongdev | Frequency deviation
+ --------------------------------------------------------------------
+ 0x30 | rdspi | RDS PI code
+ --------------------------------------------------------------------
+
+* /sys/kernel/debug/<device-name>/rsq_primary
+ This file contains information about parameters pertaining to
+ RSQ(Received Signal Quality) for primary tuner only. Layout is as
+ the one above.
diff --git a/Documentation/virtual/virtio-spec.txt b/Documentation/virtual/virtio-spec.txt
index 0d6ec85481cb..eb094039b50d 100644
--- a/Documentation/virtual/virtio-spec.txt
+++ b/Documentation/virtual/virtio-spec.txt
@@ -1389,7 +1389,7 @@ segmentation, if both guests are amenable.
Packets are transmitted by placing them in the transmitq, and
buffers for incoming packets are placed in the receiveq. In each
-case, the packet itself is preceeded by a header:
+case, the packet itself is preceded by a header:
struct virtio_net_hdr {
@@ -1631,7 +1631,7 @@ struct virtio_net_ctrl_mac {
The device can filter incoming packets by any number of
destination MAC addresses.[footnote:
-Since there are no guarentees, it can use a hash filter
+Since there are no guarantees, it can use a hash filter
orsilently switch to allmulti or promiscuous mode if it is given
too many addresses.
] This table is set using the class VIRTIO_NET_CTRL_MAC and the
@@ -1822,7 +1822,7 @@ the FLUSH and FLUSH_OUT types are equivalent, the device does not
distinguish between them
]). If the device has VIRTIO_BLK_F_BARRIER feature the high bit
(VIRTIO_BLK_T_BARRIER) indicates that this request acts as a
-barrier and that all preceeding requests must be complete before
+barrier and that all preceding requests must be complete before
this one, and all following requests must not be started until
this is complete. Note that a barrier does not flush caches in
the underlying backend device in host, and thus does not serve as
diff --git a/Documentation/vm/overcommit-accounting b/Documentation/vm/overcommit-accounting
index 706d7ed9d8d2..8eaa2fc4b8fa 100644
--- a/Documentation/vm/overcommit-accounting
+++ b/Documentation/vm/overcommit-accounting
@@ -8,7 +8,9 @@ The Linux kernel supports the following overcommit handling modes
default.
1 - Always overcommit. Appropriate for some scientific
- applications.
+ applications. Classic example is code using sparse arrays
+ and just relying on the virtual memory consisting almost
+ entirely of zero pages.
2 - Don't overcommit. The total address space commit
for the system is not permitted to exceed swap + a
@@ -18,6 +20,10 @@ The Linux kernel supports the following overcommit handling modes
pages but will receive errors on memory allocation as
appropriate.
+ Useful for applications that want to guarantee their
+ memory allocations will be available in the future
+ without having to initialize every page.
+
The overcommit policy is set via the sysctl `vm.overcommit_memory'.
The overcommit percentage is set via `vm.overcommit_ratio'.
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index e015a83c3996..e9e8ddbbf376 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -91,20 +91,6 @@ APICs
apicmaintimer. Useful when your PIT timer is totally
broken.
-Early Console
-
- syntax: earlyprintk=vga
- earlyprintk=serial[,ttySn[,baudrate]]
-
- The early console is useful when the kernel crashes before the
- normal console is initialized. It is not enabled by
- default because it has some cosmetic problems.
- Append ,keep to not disable it when the real console takes over.
- Only vga or serial at a time, not both.
- Currently only ttyS0 and ttyS1 are supported.
- Interaction with the standard serial driver is not very good.
- The VGA output is eventually overwritten by the real console.
-
Timing
notsc
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
index d6498e3cd713..881582f75c9c 100644
--- a/Documentation/x86/x86_64/mm.txt
+++ b/Documentation/x86/x86_64/mm.txt
@@ -13,7 +13,9 @@ ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
... unused hole ...
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
-ffffffffa0000000 - fffffffffff00000 (=1536 MB) module mapping space
+ffffffffa0000000 - ffffffffff5fffff (=1525 MB) module mapping space
+ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
+ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole
The direct mapping covers all memory in the system up to the highest
memory address (this means in some cases it can also include PCI memory
diff --git a/MAINTAINERS b/MAINTAINERS
index 72b08438d536..ee468fac7dbf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -90,6 +90,9 @@ Descriptions of section entries:
F: drivers/net/* all files in drivers/net, but not below
F: */net/* all files in "any top level directory"/net
One pattern per line. Multiple F: lines acceptable.
+ N: Files and directories with regex patterns.
+ N: [^a-z]tegra all files whose path contains the word tegra
+ One pattern per line. Multiple N: lines acceptable.
X: Files and directories that are NOT maintained, same rules as F:
Files exclusions are tested before file matches.
Can be useful for excluding a specific subdirectory, for instance:
@@ -97,13 +100,12 @@ Descriptions of section entries:
X: net/ipv6/
matches all files in and below net excluding net/ipv6/
K: Keyword perl extended regex pattern to match content in a
- patch or file, or an affected filename. For instance:
+ patch or file. For instance:
K: of_get_profile
- matches patch or file content, or filenames, that contain
- "of_get_profile"
+ matches patches or files that contain "of_get_profile"
K: \b(printk|pr_(info|err))\b
- matches patch or file content, or filenames, that contain one or
- more of the words printk, pr_info or pr_err
+ matches patches or files that contain one or more of the words
+ printk, pr_info or pr_err
One regex pattern per line. Multiple K: lines acceptable.
Note: For the hard of thinking, this list is meant to remain in alphabetical
@@ -1031,6 +1033,7 @@ F: drivers/mmc/host/msm_sdcc.h
F: drivers/tty/serial/msm_serial.h
F: drivers/tty/serial/msm_serial.c
F: drivers/*/pm8???-*
+F: drivers/ssbi/
F: include/linux/mfd/pm8xxx/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
S: Maintained
@@ -1764,7 +1767,7 @@ F: arch/arm/configs/bcm2835_defconfig
F: drivers/*/*bcm2835*
BROADCOM TG3 GIGABIT ETHERNET DRIVER
-M: Matt Carlson <mcarlson@broadcom.com>
+M: Nithin Nayak Sujir <nsujir@broadcom.com>
M: Michael Chan <mchan@broadcom.com>
L: netdev@vger.kernel.org
S: Supported
@@ -1886,7 +1889,7 @@ F: Documentation/video4linux/cafe_ccic
F: drivers/media/platform/marvell-ccic/
CAIF NETWORK LAYER
-M: Sjur Braendeland <sjur.brandeland@stericsson.com>
+M: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no>
L: netdev@vger.kernel.org
S: Supported
F: Documentation/networking/caif/
@@ -2200,12 +2203,34 @@ F: drivers/net/ethernet/ti/cpmac.c
CPU FREQUENCY DRIVERS
M: Rafael J. Wysocki <rjw@sisk.pl>
+M: Viresh Kumar <viresh.kumar@linaro.org>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org
S: Maintained
+T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
F: drivers/cpufreq/
F: include/linux/cpufreq.h
+CPU FREQUENCY DRIVERS - ARM BIG LITTLE
+M: Viresh Kumar <viresh.kumar@linaro.org>
+M: Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+L: cpufreq@vger.kernel.org
+L: linux-pm@vger.kernel.org
+W: http://www.arm.com/products/processors/technologies/biglittleprocessing.php
+S: Maintained
+F: drivers/cpufreq/arm_big_little.h
+F: drivers/cpufreq/arm_big_little.c
+F: drivers/cpufreq/arm_big_little_dt.c
+
+CPUIDLE DRIVERS
+M: Rafael J. Wysocki <rjw@sisk.pl>
+M: Daniel Lezcano <daniel.lezcano@linaro.org>
+L: linux-pm@vger.kernel.org
+S: Maintained
+T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+F: drivers/cpuidle/*
+F: include/linux/cpuidle.h
+
CPUID/MSR DRIVER
M: "H. Peter Anvin" <hpa@zytor.com>
S: Maintained
@@ -2284,7 +2309,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Maintained
-F: drivers/media/i2c/cx2341x*
+F: drivers/media/common/cx2341x*
F: include/media/cx2341x*
CX88 VIDEO4LINUX DRIVER
@@ -2367,6 +2392,16 @@ W: http://www.cyclades.com/
S: Orphan
F: drivers/net/wan/pc300*
+CYPRESS_FIRMWARE MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/media/common/cypress_firmware*
+
CYTTSP TOUCHSCREEN DRIVER
M: Javier Martinez Canillas <javier@dowhile0.org>
L: linux-input@vger.kernel.org
@@ -2441,9 +2476,7 @@ S: Maintained
F: drivers/platform/x86/dell-laptop.c
DELL LAPTOP SMM DRIVER
-M: Massimo Dal Zotto <dz@debian.org>
-W: http://www.debian.org/~dz/i8k/
-S: Maintained
+S: Orphan
F: drivers/char/i8k.c
F: include/uapi/linux/i8k.h
@@ -2458,6 +2491,12 @@ M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained
F: drivers/platform/x86/dell-wmi.c
+DESIGNWARE USB2 DRD IP DRIVER
+M: Paul Zimmerman <paulz@synopsys.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/staging/dwc2/
+
DESIGNWARE USB3 DRD IP DRIVER
M: Felipe Balbi <balbi@ti.com>
L: linux-usb@vger.kernel.org
@@ -2731,7 +2770,7 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/usb/dvb-usb/cxusb*
-DVB_USB_CYPRESS_FIRMWARE MEDIA DRIVER
+DVB_USB_EC168 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
@@ -2739,17 +2778,16 @@ W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
-F: drivers/media/usb/dvb-usb-v2/cypress_firmware*
+F: drivers/media/usb/dvb-usb-v2/ec168*
-DVB_USB_EC168 MEDIA DRIVER
+DVB_USB_GL861 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
-W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
-F: drivers/media/usb/dvb-usb-v2/ec168*
+F: drivers/media/usb/dvb-usb-v2/gl861*
DVB_USB_MXL111SF MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
@@ -2987,9 +3025,18 @@ F: arch/ia64/kernel/efi.c
F: arch/x86/boot/compressed/eboot.[ch]
F: arch/x86/include/asm/efi.h
F: arch/x86/platform/efi/*
-F: drivers/firmware/efivars.c
+F: drivers/firmware/efi/*
F: include/linux/efi*.h
+EFI VARIABLE FILESYSTEM
+M: Matthew Garrett <matthew.garrett@nebula.com>
+M: Jeremy Kerr <jk@ozlabs.org>
+M: Matt Fleming <matt.fleming@intel.com>
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mfleming/efi.git
+L: linux-efi@vger.kernel.org
+S: Maintained
+F: fs/efivarfs/
+
EFIFB FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
M: Peter Jones <pjones@redhat.com>
@@ -3242,6 +3289,12 @@ F: Documentation/firmware_class/
F: drivers/base/firmware*.c
F: include/linux/firmware.h
+FLASHSYSTEM DRIVER (IBM FlashSystem 70/80 PCI SSD Flash Card)
+M: Joshua Morris <josh.h.morris@us.ibm.com>
+M: Philip Kelleher <pjk1939@linux.vnet.ibm.com>
+S: Maintained
+F: drivers/block/rsxx/
+
FLOPPY DRIVER
M: Jiri Kosina <jkosina@suse.cz>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git
@@ -3502,7 +3555,7 @@ F: drivers/isdn/gigaset/
F: include/uapi/linux/gigaset_dev.h
GPIO SUBSYSTEM
-M: Grant Likely <grant.likely@secretlab.ca>
+M: Grant Likely <grant.likely@linaro.org>
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
T: git git://git.secretlab.ca/git/linux-2.6.git
@@ -3587,6 +3640,14 @@ W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
S: Maintained
F: drivers/platform/x86/hdaps.c
+HDPVR USB VIDEO ENCODER DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/usb/hdpvr
+
HWPOISON MEMORY FAILURE HANDLING
M: Andi Kleen <andi@firstfloor.org>
L: linux-mm@kvack.org
@@ -4335,7 +4396,7 @@ F: drivers/irqchip/
IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
M: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-M: Grant Likely <grant.likely@secretlab.ca>
+M: Grant Likely <grant.likely@linaro.org>
T: git git://git.secretlab.ca/git/linux-2.6.git irqdomain/next
S: Maintained
F: Documentation/IRQ-domain.txt
@@ -4416,6 +4477,16 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/it913x-fe*
+IT913X MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/media/tuners/it913x*
+
IVTV VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
@@ -4822,11 +4893,8 @@ F: arch/powerpc/platforms/40x/
F: arch/powerpc/platforms/44x/
LINUX FOR POWERPC EMBEDDED XILINX VIRTEX
-M: Grant Likely <grant.likely@secretlab.ca>
-W: http://wiki.secretlab.ca/index.php/Linux_on_Xilinx_Virtex
L: linuxppc-dev@lists.ozlabs.org
-T: git git://git.secretlab.ca/git/linux-2.6.git
-S: Maintained
+S: Unmaintained
F: arch/powerpc/*/*virtex*
F: arch/powerpc/*/*/*virtex*
@@ -4935,6 +5003,12 @@ W: logfs.org
S: Maintained
F: fs/logfs/
+LPC32XX MACHINE SUPPORT
+M: Roland Stigge <stigge@antcom.de>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-lpc32xx/
+
LSILOGIC MPT FUSION DRIVERS (FC/SAS/SPI)
M: Nagalakshmi Nandigama <Nagalakshmi.Nandigama@lsi.com>
M: Sreekanth Reddy <Sreekanth.Reddy@lsi.com>
@@ -5059,9 +5133,8 @@ S: Maintained
F: drivers/net/ethernet/marvell/sk*
MARVELL LIBERTAS WIRELESS DRIVER
-M: Dan Williams <dcbw@redhat.com>
L: libertas-dev@lists.infradead.org
-S: Maintained
+S: Orphan
F: drivers/net/wireless/libertas/
MARVELL MV643XX ETHERNET DRIVER
@@ -5401,6 +5474,13 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/NCR_D700.*
+NCT6775 HARDWARE MONITOR DRIVER
+M: Guenter Roeck <linux@roeck-us.net>
+L: lm-sensors@lm-sensors.org
+S: Maintained
+F: Documentation/hwmon/nct6775
+F: drivers/hwmon/nct6775.c
+
NETEFFECT IWARP RNIC DRIVER (IW_NES)
M: Faisal Latif <faisal.latif@intel.com>
L: linux-rdma@vger.kernel.org
@@ -5563,6 +5643,7 @@ F: include/uapi/linux/if_*
F: include/uapi/linux/netdevice.h
NETXEN (1/10) GbE SUPPORT
+M: Manish Chopra <manish.chopra@qlogic.com>
M: Sony Chacko <sony.chacko@qlogic.com>
M: Rajesh Borundia <rajesh.borundia@qlogic.com>
L: netdev@vger.kernel.org
@@ -5831,7 +5912,7 @@ F: Documentation/i2c/busses/i2c-ocores
F: drivers/i2c/busses/i2c-ocores.c
OPEN FIRMWARE AND FLATTENED DEVICE TREE
-M: Grant Likely <grant.likely@secretlab.ca>
+M: Grant Likely <grant.likely@linaro.org>
M: Rob Herring <rob.herring@calxeda.com>
L: devicetree-discuss@lists.ozlabs.org (moderated for non-subscribers)
W: http://fdt.secretlab.ca
@@ -6186,7 +6267,7 @@ S: Supported
F: drivers/scsi/pmcraid.*
PMC SIERRA PM8001 DRIVER
-M: jack_wang@usish.com
+M: xjtuwjp@gmail.com
M: lindar_liu@usish.com
L: linux-scsi@vger.kernel.org
S: Supported
@@ -6209,7 +6290,7 @@ F: include/linux/power_supply.h
F: drivers/power/
PNP SUPPORT
-M: Adam Belay <abelay@mit.edu>
+M: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
M: Bjorn Helgaas <bhelgaas@google.com>
S: Maintained
F: drivers/pnp/
@@ -6319,11 +6400,12 @@ S: Maintained
T: git git://git.infradead.org/users/cbou/linux-pstore.git
F: fs/pstore/
F: include/linux/pstore*
-F: drivers/firmware/efivars.c
+F: drivers/firmware/efi/efi-pstore.c
F: drivers/acpi/apei/erst.c
PTP HARDWARE CLOCK SUPPORT
M: Richard Cochran <richardcochran@gmail.com>
+L: netdev@vger.kernel.org
S: Maintained
W: http://linuxptp.sourceforge.net/
F: Documentation/ABI/testing/sysfs-ptp
@@ -6455,6 +6537,7 @@ S: Supported
F: drivers/net/ethernet/qlogic/qlcnic/
QLOGIC QLGE 10Gb ETHERNET DRIVER
+M: Shahed Shaikh <shahed.shaikh@qlogic.com>
M: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
M: Ron Mercer <ron.mercer@qlogic.com>
M: linux-driver@qlogic.com
@@ -6551,12 +6634,6 @@ S: Maintained
F: Documentation/blockdev/ramdisk.txt
F: drivers/block/brd.c
-RAMSAM DRIVER (IBM RamSan 70/80 PCI SSD Flash Card)
-M: Joshua Morris <josh.h.morris@us.ibm.com>
-M: Philip Kelleher <pjk1939@linux.vnet.ibm.com>
-S: Maintained
-F: drivers/block/rsxx/
-
RANDOM NUMBER DRIVER
M: Theodore Ts'o" <tytso@mit.edu>
S: Maintained
@@ -6625,7 +6702,7 @@ S: Supported
F: fs/reiserfs/
REGISTER MAP ABSTRACTION
-M: Mark Brown <broonie@opensource.wolfsonmicro.com>
+M: Mark Brown <broonie@kernel.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
S: Supported
F: drivers/base/regmap/
@@ -6686,6 +6763,16 @@ T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
F: drivers/media/dvb-frontends/rtl2830*
+RTL2832 MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/media/dvb-frontends/rtl2832*
+
RTL8180 WIRELESS DRIVER
M: "John W. Linville" <linville@tuxdriver.com>
L: linux-wireless@vger.kernel.org
@@ -6788,7 +6875,7 @@ L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
-F: Documentation/video4linux/saa7134/
+F: Documentation/video4linux/*.saa7134
F: drivers/media/pci/saa7134/
SAA7146 VIDEO4LINUX-2 DRIVER
@@ -6881,9 +6968,8 @@ F: drivers/clocksource
TLG2300 VIDEO4LINUX-2 DRIVER
M: Huang Shijie <shijie8@gmail.com>
-M: Kang Yong <kangyong@telegent.com>
-M: Zhang Xiaobing <xbzhang@telegent.com>
-S: Supported
+M: Hans Verkuil <hverkuil@xs4all.nl>
+S: Odd Fixes
F: drivers/media/usb/tlg2300
SC1200 WDT DRIVER
@@ -6951,7 +7037,6 @@ F: drivers/scsi/st*
SCTP PROTOCOL
M: Vlad Yasevich <vyasevich@gmail.com>
-M: Sridhar Samudrala <sri@us.ibm.com>
M: Neil Horman <nhorman@tuxdriver.com>
L: linux-sctp@vger.kernel.org
W: http://lksctp.sourceforge.net
@@ -7130,17 +7215,43 @@ F: drivers/media/radio/si470x/radio-si470x-common.c
F: drivers/media/radio/si470x/radio-si470x.h
F: drivers/media/radio/si470x/radio-si470x-usb.c
+SI4713 FM RADIO TRANSMITTER I2C DRIVER
+M: Eduardo Valentin <edubezval@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/radio/si4713-i2c.?
+
+SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
+M: Eduardo Valentin <edubezval@gmail.com>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/radio/radio-si4713.h
+
+SIANO DVB DRIVER
+M: Mauro Carvalho Chehab <mchehab@redhat.com>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org
+T: git git://linuxtv.org/media_tree.git
+S: Odd fixes
+F: drivers/media/common/siano/
+F: drivers/media/dvb/siano/
+F: drivers/media/usb/siano/
+F: drivers/media/mmc/siano
+
SH_VEU V4L2 MEM2MEM DRIVER
M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/platform/sh_veu.c
-F: include/media/sh_veu.h
SH_VOU V4L2 OUTPUT DRIVER
M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
L: linux-media@vger.kernel.org
-S: Maintained
+S: Odd Fixes
F: drivers/media/platform/sh_vou.c
F: include/media/sh_vou.h
@@ -7182,14 +7293,13 @@ F: arch/arm/mach-davinci
F: drivers/i2c/busses/i2c-davinci.c
TI DAVINCI SERIES MEDIA DRIVER
-M: Manjunath Hadli <manjunath.hadli@ti.com>
-M: Prabhakar Lad <prabhakar.lad@ti.com>
+M: Lad, Prabhakar <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
L: davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
-S: Supported
+S: Maintained
F: drivers/media/platform/davinci/
F: include/media/davinci/
@@ -7374,7 +7484,7 @@ F: sound/
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
M: Liam Girdwood <lgirdwood@gmail.com>
-M: Mark Brown <broonie@opensource.wolfsonmicro.com>
+M: Mark Brown <broonie@kernel.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://alsa-project.org/main/index.php/ASoC
@@ -7462,11 +7572,11 @@ S: Maintained
F: drivers/clk/spear/
SPI SUBSYSTEM
-M: Grant Likely <grant.likely@secretlab.ca>
-M: Mark Brown <broonie@opensource.wolfsonmicro.com>
+M: Mark Brown <broonie@kernel.org>
+M: Grant Likely <grant.likely@linaro.org>
L: spi-devel-general@lists.sourceforge.net
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
Q: http://patchwork.kernel.org/project/spi-devel-general/list/
-T: git git://git.secretlab.ca/git/linux-2.6.git
S: Maintained
F: Documentation/spi/
F: drivers/spi/
@@ -7561,6 +7671,11 @@ M: David Täht <d@teklibre.com>
S: Odd Fixes
F: drivers/staging/frontier/
+STAGING - GO7007 MPEG CODEC
+M: Hans Verkuil <hans.verkuil@cisco.com>
+S: Maintained
+F: drivers/staging/media/go7007/
+
STAGING - INDUSTRIAL IO
M: Jonathan Cameron <jic23@cam.ac.uk>
L: linux-iio@vger.kernel.org
@@ -7611,8 +7726,8 @@ S: Odd Fixes
F: drivers/staging/sm7xxfb/
STAGING - SOFTLOGIC 6x10 MPEG CODEC
-M: Ben Collins <bcollins@bluecherry.net>
-S: Odd Fixes
+M: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
+S: Supported
F: drivers/staging/media/solo6x10/
STAGING - SPEAKUP CONSOLE SPEECH DRIVER
@@ -7706,9 +7821,10 @@ F: include/linux/swiotlb.h
SYNOPSYS ARC ARCHITECTURE
M: Vineet Gupta <vgupta@synopsys.com>
-L: linux-snps-arc@vger.kernel.org
S: Supported
F: arch/arc/
+F: Documentation/devicetree/bindings/arc/
+F: drivers/tty/serial/arc-uart.c
SYSV FILESYSTEM
M: Christoph Hellwig <hch@infradead.org>
@@ -7876,7 +7992,7 @@ L: linux-tegra@vger.kernel.org
Q: http://patchwork.ozlabs.org/project/linux-tegra/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra.git
S: Supported
-K: (?i)[^a-z]tegra
+N: [^a-z]tegra
TEHUTI ETHERNET DRIVER
M: Andy Gospodarek <andy@greyhouse.net>
@@ -7919,6 +8035,12 @@ T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
S: Maintained
F: drivers/platform/x86/thinkpad_acpi.c
+TI BANDGAP AND THERMAL DRIVER
+M: Eduardo Valentin <eduardo.valentin@ti.com>
+L: linux-pm@vger.kernel.org
+S: Maintained
+F: drivers/staging/omap-thermal/
+
TI FLASH MEDIA INTERFACE DRIVER
M: Alex Dubov <oakad@yahoo.com>
S: Maintained
@@ -8356,9 +8478,10 @@ S: Maintained
F: drivers/usb/serial/option.c
USB PEGASUS DRIVER
-M: Petko Manolov <petkan@users.sourceforge.net>
+M: Petko Manolov <petkan@nucleusys.com>
L: linux-usb@vger.kernel.org
L: netdev@vger.kernel.org
+T: git git://git.code.sf.net/p/pegasus2/git
W: http://pegasus2.sourceforge.net/
S: Maintained
F: drivers/net/usb/pegasus.*
@@ -8378,9 +8501,10 @@ S: Supported
F: drivers/usb/class/usblp.c
USB RTL8150 DRIVER
-M: Petko Manolov <petkan@users.sourceforge.net>
+M: Petko Manolov <petkan@nucleusys.com>
L: linux-usb@vger.kernel.org
L: netdev@vger.kernel.org
+T: git git://git.code.sf.net/p/pegasus2/git
W: http://pegasus2.sourceforge.net/
S: Maintained
F: drivers/net/usb/rtl8150.c
@@ -8514,7 +8638,7 @@ F: drivers/usb/gadget/*uvc*.c
F: drivers/usb/gadget/webcam.c
USB WIRELESS RNDIS DRIVER (rndis_wlan)
-M: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+M: Jussi Kivilinna <jussi.kivilinna@iki.fi>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/rndis_wlan.c
@@ -8706,8 +8830,8 @@ F: drivers/scsi/vmw_pvscsi.c
F: drivers/scsi/vmw_pvscsi.h
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-M: Liam Girdwood <lrg@ti.com>
-M: Mark Brown <broonie@opensource.wolfsonmicro.com>
+M: Liam Girdwood <lgirdwood@gmail.com>
+M: Mark Brown <broonie@kernel.org>
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?p=48
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
@@ -8970,9 +9094,7 @@ S: Maintained
F: drivers/net/ethernet/xilinx/xilinx_axienet*
XILINX SYSTEMACE DRIVER
-M: Grant Likely <grant.likely@secretlab.ca>
-W: http://www.secretlab.ca/
-S: Maintained
+S: Unmaintained
F: drivers/block/xsysace.c
XILINX UARTLITE SERIAL DRIVER
diff --git a/Makefile b/Makefile
index 54d2b2a0fef0..d3528f6aa938 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 9
SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION =
NAME = Unicycling Gorilla
# *DOCUMENTATION*
@@ -513,7 +513,8 @@ ifeq ($(KBUILD_EXTMOD),)
# Carefully list dependencies so we do not try to build scripts twice
# in parallel
PHONY += scripts
-scripts: scripts_basic include/config/auto.conf include/config/tristate.conf
+scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
+ asm-generic
$(Q)$(MAKE) $(build)=$(@)
# Objects we will link into vmlinux / subdirs we need to visit
@@ -1331,11 +1332,11 @@ kernelversion:
# Clear a bunch of variables before executing the submake
tools/: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/
tools/%: FORCE
$(Q)mkdir -p $(objtree)/tools
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ $*
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $*
# Single targets
# ---------------------------------------------------------------------------
diff --git a/arch/Kconfig b/arch/Kconfig
index 1455579791ec..99f0e17df429 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -157,9 +157,6 @@ config ARCH_USE_BUILTIN_BSWAP
instructions should set this. And it shouldn't hurt to set it
on architectures that don't have such instructions.
-config HAVE_SYSCALL_WRAPPERS
- bool
-
config KRETPROBES
def_bool y
depends on KPROBES && HAVE_KRETPROBES
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 8a33ba01301f..8629127640cf 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -4,7 +4,6 @@ config ALPHA
select HAVE_AOUT
select HAVE_IDE
select HAVE_OPROFILE
- select HAVE_SYSCALL_WRAPPERS
select HAVE_PCSPKR_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_DMA_ATTRS
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 4759fe751aa1..2cc3cc519c54 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -12,7 +12,7 @@ NM := $(NM) -B
LDFLAGS_vmlinux := -static -N #-relax
CHECKFLAGS += -D__alpha__ -m64
-cflags-y := -pipe -mno-fp-regs -ffixed-8 -msmall-data
+cflags-y := -pipe -mno-fp-regs -ffixed-8
cflags-y += $(call cc-option, -fno-jump-tables)
cpuflags-$(CONFIG_ALPHA_EV4) := -mcpu=ev4
diff --git a/arch/alpha/include/asm/floppy.h b/arch/alpha/include/asm/floppy.h
index 46cefbd50e73..bae97eb19d26 100644
--- a/arch/alpha/include/asm/floppy.h
+++ b/arch/alpha/include/asm/floppy.h
@@ -26,7 +26,7 @@
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
#define fd_cacheflush(addr,size) /* nothing */
#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt,\
- IRQF_DISABLED, "floppy", NULL)
+ 0, "floppy", NULL)
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
#ifdef CONFIG_PCI
diff --git a/arch/alpha/include/asm/linkage.h b/arch/alpha/include/asm/linkage.h
index 291c2d01c44f..7cfd06e8c935 100644
--- a/arch/alpha/include/asm/linkage.h
+++ b/arch/alpha/include/asm/linkage.h
@@ -1,6 +1,8 @@
#ifndef __ASM_LINKAGE_H
#define __ASM_LINKAGE_H
-/* Nothing to see here... */
+#define cond_syscall(x) asm(".weak\t" #x "\n" #x " = sys_ni_syscall")
+#define SYSCALL_ALIAS(alias, name) \
+ asm ( #alias " = " #name "\n\t.globl " #alias)
#endif
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 1f8c72959fb6..52cd2a4a3ff4 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -95,8 +95,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define TS_POLLING 0x0010 /* idle task polling need_resched,
skip sending interrupt */
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index 6d6fe7ab5473..43baee17acdf 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -18,16 +18,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/* "Conditional" syscalls. What we want is
-
- __attribute__((weak,alias("sys_ni_syscall")))
-
- but that raises the problem of what type to give the symbol. If we use
- a prototype, it'll conflict with the definition given in this file and
- others. If we use __typeof, we discover that not all symbols actually
- have declarations. If we use no prototype, then we get warnings from
- -Wstrict-prototypes. Ho hum. */
-
-#define cond_syscall(x) asm(".weak\t" #x "\n" #x " = sys_ni_syscall")
-
#endif /* _ALPHA_UNISTD_H */
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index c5195524d1ef..eee6ea76bdaf 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -79,4 +79,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 2872accd2215..7b2be251c30f 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -117,13 +117,6 @@ handle_irq(int irq)
return;
}
- /*
- * From here we must proceed with IPL_MAX. Note that we do not
- * explicitly enable interrupts afterwards - some MILO PALcode
- * (namely LX164 one) seems to have severe problems with RTI
- * at IPL 0.
- */
- local_irq_disable();
irq_enter();
generic_handle_irq_desc(irq, desc);
irq_exit();
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 772ddfdb71a8..f433fc11877a 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -45,6 +45,14 @@ do_entInt(unsigned long type, unsigned long vector,
unsigned long la_ptr, struct pt_regs *regs)
{
struct pt_regs *old_regs;
+
+ /*
+ * Disable interrupts during IRQ handling.
+ * Note that there is no matching local_irq_enable() due to
+ * severe problems with RTI at IPL0 and some MILO PALcode
+ * (namely LX164).
+ */
+ local_irq_disable();
switch (type) {
case 0:
#ifdef CONFIG_SMP
@@ -62,7 +70,6 @@ do_entInt(unsigned long type, unsigned long vector,
{
long cpu;
- local_irq_disable();
smp_percpu_timer_interrupt(regs);
cpu = smp_processor_id();
if (cpu != boot_cpuid) {
@@ -222,7 +229,6 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED,
.name = "timer",
};
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 63d27fb9b023..ab80a80d38a2 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -46,25 +46,6 @@
void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);
-void
-cpu_idle(void)
-{
- current_thread_info()->status |= TS_POLLING;
-
- while (1) {
- /* FIXME -- EV6 and LCA45 know how to power down
- the CPU. */
-
- rcu_idle_enter();
- while (!need_resched())
- cpu_relax();
-
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
-
struct halt_info {
int mode;
char *restart_cmd;
@@ -194,6 +175,7 @@ machine_power_off(void)
void
show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_DEFAULT);
dik_show_regs(regs, NULL);
}
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 9603bc234b47..7b60834fb4b2 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -167,8 +167,7 @@ smp_callin(void)
cpuid, current, current->active_mm));
preempt_disable();
- /* Do nothing. */
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/* Wait until hwrpb->txrdy is clear for cpu. Return -1 on timeout. */
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 4d4c046f708d..1d4aabfcf9a1 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -185,9 +185,12 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr)
mb();
}
-extern void free_reserved_mem(void *, void *);
extern void pcibios_claim_one_bus(struct pci_bus *);
+static struct resource irongate_io = {
+ .name = "Irongate PCI IO",
+ .flags = IORESOURCE_IO,
+};
static struct resource irongate_mem = {
.name = "Irongate PCI MEM",
.flags = IORESOURCE_MEM,
@@ -209,6 +212,7 @@ nautilus_init_pci(void)
irongate = pci_get_bus_and_slot(0, 0);
bus->self = irongate;
+ bus->resource[0] = &irongate_io;
bus->resource[1] = &irongate_mem;
pci_bus_size_bridges(bus);
@@ -234,8 +238,8 @@ nautilus_init_pci(void)
if (pci_mem < memtop)
memtop = pci_mem;
if (memtop > alpha_mv.min_mem_address) {
- free_reserved_mem(__va(alpha_mv.min_mem_address),
- __va(memtop));
+ free_reserved_area((unsigned long)__va(alpha_mv.min_mem_address),
+ (unsigned long)__va(memtop), 0, NULL);
printk("nautilus_init_pci: %ldk freed\n",
(memtop - alpha_mv.min_mem_address) >> 10);
}
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index 5cf4a481b8c5..a53cf03f49d5 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -280,15 +280,15 @@ titan_late_init(void)
* all reported to the kernel as machine checks, so the handler
* is a nop so it can be called to count the individual events.
*/
- titan_request_irq(63+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(63+16, titan_intr_nop, 0,
"CChip Error", NULL);
- titan_request_irq(62+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(62+16, titan_intr_nop, 0,
"PChip 0 H_Error", NULL);
- titan_request_irq(61+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(61+16, titan_intr_nop, 0,
"PChip 1 H_Error", NULL);
- titan_request_irq(60+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(60+16, titan_intr_nop, 0,
"PChip 0 C_Error", NULL);
- titan_request_irq(59+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(59+16, titan_intr_nop, 0,
"PChip 1 C_Error", NULL);
/*
@@ -348,9 +348,9 @@ privateer_init_pci(void)
* Hook a couple of extra err interrupts that the
* common titan code won't.
*/
- titan_request_irq(53+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(53+16, titan_intr_nop, 0,
"NMI", NULL);
- titan_request_irq(50+16, titan_intr_nop, IRQF_DISABLED,
+ titan_request_irq(50+16, titan_intr_nop, 0,
"Temperature Warning", NULL);
/*
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 4037461a6493..affccb959a9e 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -169,13 +169,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
dik_show_trace(sp);
}
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
void
die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
{
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 1ad6ca74bed2..0ba85ee4a466 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -31,6 +31,7 @@
#include <asm/console.h>
#include <asm/tlb.h>
#include <asm/setup.h>
+#include <asm/sections.h>
extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -281,8 +282,6 @@ printk_memory_info(void)
{
unsigned long codesize, reservedpages, datasize, initsize, tmp;
extern int page_is_ram(unsigned long) __init;
- extern char _text, _etext, _data, _edata;
- extern char __init_begin, __init_end;
/* printk all informations */
reservedpages = 0;
@@ -318,32 +317,15 @@ mem_init(void)
#endif /* CONFIG_DISCONTIGMEM */
void
-free_reserved_mem(void *start, void *end)
-{
- void *__start = start;
- for (; __start < end; __start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(__start));
- init_page_count(virt_to_page(__start));
- free_page((long)__start);
- totalram_pages++;
- }
-}
-
-void
free_initmem(void)
{
- extern char __init_begin, __init_end;
-
- free_reserved_mem(&__init_begin, &__init_end);
- printk ("Freeing unused kernel memory: %ldk freed\n",
- (&__init_end - &__init_begin) >> 10);
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
void
free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_mem((void *)start, (void *)end);
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 3973ae395772..33885048fa36 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -17,6 +17,7 @@
#include <asm/hwrpb.h>
#include <asm/pgalloc.h>
+#include <asm/sections.h>
pg_data_t node_data[MAX_NUMNODES];
EXPORT_SYMBOL(node_data);
@@ -325,8 +326,6 @@ void __init mem_init(void)
{
unsigned long codesize, reservedpages, datasize, initsize, pfn;
extern int page_is_ram(unsigned long) __init;
- extern char _text, _etext, _data, _edata;
- extern char __init_begin, __init_end;
unsigned long nid, i;
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
diff --git a/arch/arc/include/asm/dma-mapping.h b/arch/arc/include/asm/dma-mapping.h
index 31f77aec0823..45b8e0cea176 100644
--- a/arch/arc/include/asm/dma-mapping.h
+++ b/arch/arc/include/asm/dma-mapping.h
@@ -126,7 +126,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg,
int i;
for_each_sg(sg, s, nents, i)
- sg->dma_address = dma_map_page(dev, sg_page(s), s->offset,
+ s->dma_address = dma_map_page(dev, sg_page(s), s->offset,
s->length, dir);
return nents;
diff --git a/arch/arc/include/asm/elf.h b/arch/arc/include/asm/elf.h
index f4c8d36ebecb..a26282857683 100644
--- a/arch/arc/include/asm/elf.h
+++ b/arch/arc/include/asm/elf.h
@@ -72,7 +72,4 @@ extern int elf_check_arch(const struct elf32_hdr *);
*/
#define ELF_PLATFORM (NULL)
-#define SET_PERSONALITY(ex) \
- set_personality(PER_LINUX | (current->personality & (~PER_MASK)))
-
#endif
diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h
index 23daa326fc9b..eb2ae53187d9 100644
--- a/arch/arc/include/asm/entry.h
+++ b/arch/arc/include/asm/entry.h
@@ -415,7 +415,7 @@
*-------------------------------------------------------------*/
.macro SAVE_ALL_EXCEPTION marker
- st \marker, [sp, 8]
+ st \marker, [sp, 8] /* orig_r8 */
st r0, [sp, 4] /* orig_r0, needed only for sys calls */
/* Restore r9 used to code the early prologue */
diff --git a/arch/arc/include/asm/irqflags.h b/arch/arc/include/asm/irqflags.h
index ccd84806b62f..eac071668201 100644
--- a/arch/arc/include/asm/irqflags.h
+++ b/arch/arc/include/asm/irqflags.h
@@ -39,7 +39,7 @@ static inline long arch_local_irq_save(void)
" flag.nz %0 \n"
: "=r"(temp), "=r"(flags)
: "n"((STATUS_E1_MASK | STATUS_E2_MASK))
- : "cc");
+ : "memory", "cc");
return flags;
}
@@ -53,7 +53,8 @@ static inline void arch_local_irq_restore(unsigned long flags)
__asm__ __volatile__(
" flag %0 \n"
:
- : "r"(flags));
+ : "r"(flags)
+ : "memory");
}
/*
@@ -73,7 +74,8 @@ static inline void arch_local_irq_disable(void)
" and %0, %0, %1 \n"
" flag %0 \n"
: "=&r"(temp)
- : "n"(~(STATUS_E1_MASK | STATUS_E2_MASK)));
+ : "n"(~(STATUS_E1_MASK | STATUS_E2_MASK))
+ : "memory");
}
/*
@@ -85,7 +87,9 @@ static inline long arch_local_save_flags(void)
__asm__ __volatile__(
" lr %0, [status32] \n"
- : "=&r"(temp));
+ : "=&r"(temp)
+ :
+ : "memory");
return temp;
}
diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h
index f3c4934f0ca9..4930957ca3d3 100644
--- a/arch/arc/include/asm/kgdb.h
+++ b/arch/arc/include/asm/kgdb.h
@@ -13,7 +13,7 @@
#ifdef CONFIG_KGDB
-#include <asm/user.h>
+#include <asm/ptrace.h>
/* to ensure compatibility with Linux 2.6.35, we don't implement the get/set
* register API yet */
@@ -53,9 +53,7 @@ enum arc700_linux_regnums {
};
#else
-static inline void kgdb_trap(struct pt_regs *regs, int param)
-{
-}
+#define kgdb_trap(regs, param)
#endif
#endif /* __ARC_KGDB_H__ */
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 8ae783d20a81..6179de7e07c2 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -123,7 +123,7 @@ static inline long regs_return_value(struct pt_regs *regs)
#define orig_r8_IS_SCALL 0x0001
#define orig_r8_IS_SCALL_RESTARTED 0x0002
#define orig_r8_IS_BRKPT 0x0004
-#define orig_r8_IS_EXCPN 0x0004
+#define orig_r8_IS_EXCPN 0x0008
#define orig_r8_IS_IRQ1 0x0010
#define orig_r8_IS_IRQ2 0x0020
diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h
index e53a5340ba4f..dd785befe7fd 100644
--- a/arch/arc/include/asm/syscalls.h
+++ b/arch/arc/include/asm/syscalls.h
@@ -16,8 +16,6 @@
#include <linux/types.h>
int sys_clone_wrapper(int, int, int, int, int);
-int sys_fork_wrapper(void);
-int sys_vfork_wrapper(void);
int sys_cacheflush(uint32_t, uint32_t uint32_t);
int sys_arc_settls(void *);
int sys_arc_gettls(void);
diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h
index 6afa4f702075..30333cec0fef 100644
--- a/arch/arc/include/uapi/asm/ptrace.h
+++ b/arch/arc/include/uapi/asm/ptrace.h
@@ -28,14 +28,14 @@
*/
struct user_regs_struct {
- struct scratch {
+ struct {
long pad;
long bta, lp_start, lp_end, lp_count;
long status32, ret, blink, fp, gp;
long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
long sp;
} scratch;
- struct callee {
+ struct {
long pad;
long r25, r24, r23, r22, r21, r20;
long r19, r18, r17, r16, r15, r14, r13;
diff --git a/arch/arc/kernel/disasm.c b/arch/arc/kernel/disasm.c
index 2f390289a792..d14764ae2c60 100644
--- a/arch/arc/kernel/disasm.c
+++ b/arch/arc/kernel/disasm.c
@@ -535,4 +535,4 @@ int __kprobes disasm_next_pc(unsigned long pc, struct pt_regs *regs,
return instr.is_branch;
}
-#endif /* CONFIG_KGDB || CONFIG_MISALIGN_ACCESS || CONFIG_KPROBES */
+#endif /* CONFIG_KGDB || CONFIG_ARC_MISALIGN_ACCESS || CONFIG_KPROBES */
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index ef6800ba2f03..91eeab81f52d 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -452,7 +452,7 @@ tracesys:
; using ERET won't work since next-PC has already committed
lr r12, [efa]
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11
- st r12, [r11, THREAD_FAULT_ADDR]
+ st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address
; PRE Sys Call Ptrace hook
mov r0, sp ; pt_regs needed
@@ -792,31 +792,6 @@ ARC_EXIT ret_from_fork
;################### Special Sys Call Wrappers ##########################
-; TBD: call do_fork directly from here
-ARC_ENTRY sys_fork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_fork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_fork_wrapper
-
-ARC_ENTRY sys_vfork_wrapper
- SAVE_CALLEE_SAVED_USER
- bl @sys_vfork
- DISCARD_CALLEE_SAVED_USER
-
- GET_CURR_THR_INFO_FLAGS r10
- btst r10, TIF_SYSCALL_TRACE
- bnz tracesys_exit
-
- b ret_from_system_call
-ARC_EXIT sys_vfork_wrapper
-
ARC_ENTRY sys_clone_wrapper
SAVE_CALLEE_SAVED_USER
bl @sys_clone
diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c
index 2888ba5be47e..52bdc83c1495 100644
--- a/arch/arc/kernel/kgdb.c
+++ b/arch/arc/kernel/kgdb.c
@@ -9,6 +9,7 @@
*/
#include <linux/kgdb.h>
+#include <linux/sched.h>
#include <asm/disasm.h>
#include <asm/cacheflush.h>
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index 0a7531d99294..cad66851e0c4 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -41,37 +41,12 @@ SYSCALL_DEFINE0(arc_gettls)
return task_thread_info(current)->thr_ptr;
}
-static inline void arch_idle(void)
+void arch_cpu_idle(void)
{
/* sleep, but enable all interrupts before committing */
__asm__("sleep 0x3");
}
-void cpu_idle(void)
-{
- /* Since we SLEEP in idle loop, TIF_POLLING_NRFLAG can't be set */
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
-doze:
- local_irq_disable();
- if (!need_resched()) {
- arch_idle();
- goto doze;
- } else {
- local_irq_enable();
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
- schedule_preempt_disabled();
- }
-}
-
asmlinkage void ret_from_fork(void);
/* Layout of Child kernel mode stack as setup at the end of this function is
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index dc0f968dae0a..2d95ac07df7b 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -232,10 +232,8 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
n += scnprintf(buf + n, len - n, "\n");
-#ifdef _ASM_GENERIC_UNISTD_H
n += scnprintf(buf + n, len - n,
- "OS ABI [v2]\t: asm-generic/{unistd,stat,fcntl}\n");
-#endif
+ "OS ABI [v3]\t: no-legacy-syscalls\n");
return buf;
}
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 3af3e06dcf02..5c7fd603d216 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -141,7 +141,7 @@ void __cpuinit start_kernel_secondary(void)
local_irq_enable();
preempt_disable();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/*
diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
index a63ff842564b..ca0207b9d5b6 100644
--- a/arch/arc/kernel/stacktrace.c
+++ b/arch/arc/kernel/stacktrace.c
@@ -220,13 +220,6 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_stacktrace(tsk, NULL);
}
-/* Expected by Rest of kernel code */
-void dump_stack(void)
-{
- show_stacktrace(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
/* Another API expected by schedular, shows up in "ps" as Wait Channel
* Ofcourse just returning schedule( ) would be pointless so unwind until
* the function is not in schedular code
diff --git a/arch/arc/kernel/sys.c b/arch/arc/kernel/sys.c
index f6bdd07583f3..9d6c1ca26af6 100644
--- a/arch/arc/kernel/sys.c
+++ b/arch/arc/kernel/sys.c
@@ -6,8 +6,6 @@
#include <asm/syscalls.h>
#define sys_clone sys_clone_wrapper
-#define sys_fork sys_fork_wrapper
-#define sys_vfork sys_vfork_wrapper
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 7c10873c311f..0aec01985bf9 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -71,7 +71,7 @@ void print_task_path_n_nm(struct task_struct *tsk, char *buf)
}
done:
- pr_info("%s, TGID %u\n", path_nm, tsk->tgid);
+ pr_info("Path: %s\n", path_nm);
}
EXPORT_SYMBOL(print_task_path_n_nm);
@@ -163,6 +163,7 @@ void show_regs(struct pt_regs *regs)
return;
print_task_path_n_nm(tsk, buf);
+ show_regs_print_info(KERN_INFO);
if (current->thread.cause_code)
show_ecr_verbose(regs);
diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c
index caf797de23fc..727d4794ea0f 100644
--- a/arch/arc/mm/init.c
+++ b/arch/arc/mm/init.c
@@ -144,37 +144,18 @@ void __init mem_init(void)
PAGES_TO_KB(reserved_pages));
}
-static void __init free_init_pages(const char *what, unsigned long begin,
- unsigned long end)
-{
- unsigned long addr;
-
- pr_info("Freeing %s: %ldk [%lx] to [%lx]\n",
- what, TO_KB(end - begin), begin, end);
-
- /* need to check that the page we free is not a partial page */
- for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
-}
-
/*
* free_initmem: Free all the __init memory.
*/
void __init_refok free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)__init_begin,
- (unsigned long)__init_end);
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory", start, end);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/arc/plat-arcfpga/Kconfig b/arch/arc/plat-arcfpga/Kconfig
index b41e786cdbc0..295cefeb25d3 100644
--- a/arch/arc/plat-arcfpga/Kconfig
+++ b/arch/arc/plat-arcfpga/Kconfig
@@ -53,7 +53,7 @@ menuconfig ARC_HAS_BVCI_LAT_UNIT
bool "BVCI Bus Latency Unit"
depends on ARC_BOARD_ML509 || ARC_BOARD_ANGEL4
help
- IP to add artifical latency to BVCI Bus Based FPGA builds.
+ IP to add artificial latency to BVCI Bus Based FPGA builds.
The default latency (even worst case) for FPGA is non-realistic
(~10 SDRAM, ~5 SSRAM).
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 13b739469c51..006f9838dd43 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -15,6 +15,7 @@ config ARM
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_IDLE_POLL_SETUP
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select HARDIRQS_SW_RESEND
@@ -549,6 +550,8 @@ config ARCH_IXP4XX
select GENERIC_CLOCKEVENTS
select MIGHT_HAVE_PCI
select NEED_MACH_IO_H
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_DESC
help
Support for Intel's IXP4XX (XScale) family of processors.
@@ -1183,9 +1186,9 @@ config ARM_NR_BANKS
default 8
config IWMMXT
- bool "Enable iWMMXt support"
+ bool "Enable iWMMXt support" if !CPU_PJ4
depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4
- default y if PXA27x || PXA3xx || ARCH_MMP
+ default y if PXA27x || PXA3xx || ARCH_MMP || CPU_PJ4
help
Enable support for iWMMXt context switching at run time if
running on a CPU that supports it.
@@ -1439,6 +1442,16 @@ config ARM_ERRATA_775420
to deadlock. This workaround puts DSB before executing ISB if
an abort may occur on cache maintenance.
+config ARM_ERRATA_798181
+ bool "ARM errata: TLBI/DSB failure on Cortex-A15"
+ depends on CPU_V7 && SMP
+ help
+ On Cortex-A15 (r0p0..r3p2) the TLBI*IS/DSB operations are not
+ adequately shooting down all use of the old entries. This
+ option enables the Linux kernel workaround for this erratum
+ which sends an IPI to the CPUs that are running the same ASID
+ as the one being invalidated.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -2150,7 +2163,6 @@ endmenu
menu "CPU Power Management"
if ARCH_HAS_CPUFREQ
-
source "drivers/cpufreq/Kconfig"
config CPU_FREQ_IMX
@@ -2160,30 +2172,6 @@ config CPU_FREQ_IMX
help
This enables the CPUfreq driver for i.MX CPUs.
-config CPU_FREQ_SA1100
- bool
-
-config CPU_FREQ_SA1110
- bool
-
-config CPU_FREQ_INTEGRATOR
- tristate "CPUfreq driver for ARM Integrator CPUs"
- depends on ARCH_INTEGRATOR && CPU_FREQ
- default y
- help
- This enables the CPUfreq driver for ARM Integrator CPUs.
-
- For details, take a look at <file:Documentation/cpu-freq>.
-
- If in doubt, say Y.
-
-config CPU_FREQ_PXA
- bool
- depends on CPU_FREQ && ARCH_PXA && PXA25x
- default y
- select CPU_FREQ_DEFAULT_GOV_USERSPACE
- select CPU_FREQ_TABLE
-
config CPU_FREQ_S3C
bool
help
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 0957645b73af..91fe4f148f80 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -349,7 +349,7 @@
rx_descs = <64>;
mac_control = <0x20>;
slaves = <2>;
- cpts_active_slave = <0>;
+ active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
reg = <0x4a100000 0x800
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index dd0c57dd9f30..3234875824dc 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -54,7 +54,7 @@
};
mvsdio@d00d4000 {
- pinctrl-0 = <&sdio_pins2>;
+ pinctrl-0 = <&sdio_pins3>;
pinctrl-names = "default";
status = "okay";
/*
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 8188d138020e..a195debb67d3 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -59,6 +59,12 @@
"mpp50", "mpp51", "mpp52";
marvell,function = "sd0";
};
+
+ sdio_pins3: sdio-pins3 {
+ marvell,pins = "mpp48", "mpp49", "mpp50",
+ "mpp51", "mpp52", "mpp53";
+ marvell,function = "sd0";
+ };
};
gpio0: gpio@d0018100 {
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index cb7bcc51608d..39253b9aedd1 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -322,6 +322,24 @@
};
};
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <0 0 0x1 0x0 /* PA0 periph A SPI0_MISO pin */
+ 0 1 0x1 0x0 /* PA1 periph A SPI0_MOSI pin */
+ 0 2 0x1 0x0>; /* PA2 periph A SPI0_SPCK pin */
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <1 0 0x1 0x0 /* PB0 periph A SPI1_MISO pin */
+ 1 1 0x1 0x0 /* PB1 periph A SPI1_MOSI pin */
+ 1 2 0x1 0x0>; /* PB2 periph A SPI1_SPCK pin */
+ };
+ };
+
pioA: gpio@fffff400 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x200>;
@@ -471,6 +489,28 @@
status = "disabled";
};
+ spi0: spi@fffc8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffc8000 0x200>;
+ interrupts = <12 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ status = "disabled";
+ };
+
+ spi1: spi@fffcc000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffcc000 0x200>;
+ interrupts = <13 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ status = "disabled";
+ };
+
adc0: adc@fffe0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffe0000 0x100>;
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 271d4de026e9..94b58ab2cc08 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -303,6 +303,24 @@
};
};
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <0 0 0x2 0x0 /* PA0 periph B SPI0_MISO pin */
+ 0 1 0x2 0x0 /* PA1 periph B SPI0_MOSI pin */
+ 0 2 0x2 0x0>; /* PA2 periph B SPI0_SPCK pin */
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <1 12 0x1 0x0 /* PB12 periph A SPI1_MISO pin */
+ 1 13 0x1 0x0 /* PB13 periph A SPI1_MOSI pin */
+ 1 14 0x1 0x0>; /* PB14 periph A SPI1_SPCK pin */
+ };
+ };
+
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff200 0x200>;
@@ -462,6 +480,28 @@
reg = <0xfffffd40 0x10>;
status = "disabled";
};
+
+ spi0: spi@fffa4000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffa4000 0x200>;
+ interrupts = <14 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ status = "disabled";
+ };
+
+ spi1: spi@fffa8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffa8000 0x200>;
+ interrupts = <15 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
index 1eb08728f527..a14e424b2e81 100644
--- a/arch/arm/boot/dts/at91sam9263ek.dts
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -79,6 +79,16 @@
};
};
};
+
+ spi0: spi@fffa4000 {
+ status = "okay";
+ cs-gpios = <&pioA 5 0>, <0>, <0>, <0>;
+ mtd_dataflash@0 {
+ compatible = "atmel,at45", "atmel,dataflash";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index da15e83e7f17..23d1f468f27f 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -96,6 +96,16 @@
status = "okay";
pinctrl-0 = <&pinctrl_ssc0_tx>;
};
+
+ spi0: spi@fffc8000 {
+ status = "okay";
+ cs-gpios = <0>, <&pioC 11 0>, <0>, <0>;
+ mtd_dataflash@0 {
+ compatible = "atmel,at45", "atmel,dataflash";
+ spi-max-frequency = <50000000>;
+ reg = <1>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 6b1d4cab24c2..cfdf429578b5 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -322,6 +322,24 @@
};
};
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <1 0 0x1 0x0 /* PB0 periph A SPI0_MISO pin */
+ 1 1 0x1 0x0 /* PB1 periph A SPI0_MOSI pin */
+ 1 2 0x1 0x0>; /* PB2 periph A SPI0_SPCK pin */
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <1 14 0x1 0x0 /* PB14 periph A SPI1_MISO pin */
+ 1 15 0x1 0x0 /* PB15 periph A SPI1_MOSI pin */
+ 1 16 0x1 0x0>; /* PB16 periph A SPI1_SPCK pin */
+ };
+ };
+
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff200 0x200>;
@@ -531,6 +549,28 @@
reg = <0xfffffd40 0x10>;
status = "disabled";
};
+
+ spi0: spi@fffa4000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffa4000 0x200>;
+ interrupts = <14 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ status = "disabled";
+ };
+
+ spi1: spi@fffa8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xfffa8000 0x200>;
+ interrupts = <15 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index 20c31913c270..92c52a7d70bc 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -102,6 +102,16 @@
};
};
};
+
+ spi0: spi@fffa4000{
+ status = "okay";
+ cs-gpios = <&pioB 3 0>, <0>, <0>, <0>;
+ mtd_dataflash@0 {
+ compatible = "atmel,at45", "atmel,dataflash";
+ spi-max-frequency = <13000000>;
+ reg = <0>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 7750f98dd764..b2961f1ea51b 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -261,6 +261,24 @@
};
};
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <0 11 0x1 0x0 /* PA11 periph A SPI0_MISO pin */
+ 0 12 0x1 0x0 /* PA12 periph A SPI0_MOSI pin */
+ 0 13 0x1 0x0>; /* PA13 periph A SPI0_SPCK pin */
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <0 21 0x2 0x0 /* PA21 periph B SPI1_MISO pin */
+ 0 22 0x2 0x0 /* PA22 periph B SPI1_MOSI pin */
+ 0 23 0x2 0x0>; /* PA23 periph B SPI1_SPCK pin */
+ };
+ };
+
pioA: gpio@fffff400 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x200>;
@@ -373,6 +391,28 @@
#size-cells = <0>;
status = "disabled";
};
+
+ spi0: spi@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0000000 0x100>;
+ interrupts = <13 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ status = "disabled";
+ };
+
+ spi1: spi@f0004000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0004000 0x100>;
+ interrupts = <14 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index d400f8de4387..34c842b1efb2 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -67,6 +67,16 @@
};
};
};
+
+ spi0: spi@f0000000 {
+ status = "okay";
+ cs-gpios = <&pioA 14 0>, <0>, <0>, <0>;
+ m25p80@0 {
+ compatible = "atmel,at25df321a";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index a98c0d50fbbe..347b438d47fa 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -343,6 +343,24 @@
};
};
+ spi0 {
+ pinctrl_spi0: spi0-0 {
+ atmel,pins =
+ <0 11 0x1 0x0 /* PA11 periph A SPI0_MISO pin */
+ 0 12 0x1 0x0 /* PA12 periph A SPI0_MOSI pin */
+ 0 13 0x1 0x0>; /* PA13 periph A SPI0_SPCK pin */
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1: spi1-0 {
+ atmel,pins =
+ <0 21 0x2 0x0 /* PA21 periph B SPI1_MISO pin */
+ 0 22 0x2 0x0 /* PA22 periph B SPI1_MOSI pin */
+ 0 23 0x2 0x0>; /* PA23 periph B SPI1_SPCK pin */
+ };
+ };
+
pioA: gpio@fffff400 {
compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
reg = <0xfffff400 0x200>;
@@ -529,6 +547,28 @@
trigger-value = <0x6>;
};
};
+
+ spi0: spi@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0000000 0x100>;
+ interrupts = <13 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0>;
+ status = "disabled";
+ };
+
+ spi1: spi@f0004000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "atmel,at91rm9200-spi";
+ reg = <0xf0004000 0x100>;
+ interrupts = <14 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index 8a7cf1d9cf5d..09f5e667ca7a 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -84,6 +84,16 @@
};
};
};
+
+ spi0: spi@f0000000 {
+ status = "okay";
+ cs-gpios = <&pioA 14 0>, <0>, <0>, <0>;
+ m25p80@0 {
+ compatible = "atmel,at25df321a";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+ };
+ };
};
usb0: ohci@00600000 {
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 9de93096601a..aaa63d0a8096 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -191,8 +191,8 @@
prcmu: prcmu@80157000 {
compatible = "stericsson,db8500-prcmu";
- reg = <0x80157000 0x1000>;
- reg-names = "prcmu";
+ reg = <0x80157000 0x1000>, <0x801b0000 0x8000>, <0x801b8000 0x1000>;
+ reg-names = "prcmu", "prcmu-tcpm", "prcmu-tcdm";
interrupts = <0 47 0x4>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts
index 6ce3d17c3a29..fd36e1cca104 100644
--- a/arch/arm/boot/dts/imx28-m28evk.dts
+++ b/arch/arm/boot/dts/imx28-m28evk.dts
@@ -152,7 +152,6 @@
i2c0: i2c@80058000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
- clock-frequency = <400000>;
status = "okay";
sgtl5000: codec@0a {
diff --git a/arch/arm/boot/dts/imx28-sps1.dts b/arch/arm/boot/dts/imx28-sps1.dts
index e6cde8aa7fff..6c6a5442800a 100644
--- a/arch/arm/boot/dts/imx28-sps1.dts
+++ b/arch/arm/boot/dts/imx28-sps1.dts
@@ -70,7 +70,6 @@
i2c0: i2c@80058000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
- clock-frequency = <400000>;
status = "okay";
rtc: rtc@51 {
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 06ec460b4581..281a223591ff 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -91,6 +91,7 @@
compatible = "arm,cortex-a9-twd-timer";
reg = <0x00a00600 0x20>;
interrupts = <1 13 0xf01>;
+ clocks = <&clks 15>;
};
L2: l2-cache@00a02000 {
diff --git a/arch/arm/boot/dts/kirkwood-goflexnet.dts b/arch/arm/boot/dts/kirkwood-goflexnet.dts
index bd83b8fc7c83..c3573be7b92c 100644
--- a/arch/arm/boot/dts/kirkwood-goflexnet.dts
+++ b/arch/arm/boot/dts/kirkwood-goflexnet.dts
@@ -77,6 +77,7 @@
};
nand@3000000 {
+ chip-delay = <40>;
status = "okay";
partition@0 {
diff --git a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
index 93c3afbef9ee..3694e94f6e99 100644
--- a/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
+++ b/arch/arm/boot/dts/kirkwood-iomega_ix2_200.dts
@@ -96,11 +96,11 @@
marvell,function = "gpio";
};
pmx_led_rebuild_brt_ctrl_1: pmx-led-rebuild-brt-ctrl-1 {
- marvell,pins = "mpp44";
+ marvell,pins = "mpp46";
marvell,function = "gpio";
};
pmx_led_rebuild_brt_ctrl_2: pmx-led-rebuild-brt-ctrl-2 {
- marvell,pins = "mpp45";
+ marvell,pins = "mpp47";
marvell,function = "gpio";
};
@@ -157,14 +157,14 @@
gpios = <&gpio0 16 0>;
linux,default-trigger = "default-on";
};
- health_led1 {
+ rebuild_led {
+ label = "status:white:rebuild_led";
+ gpios = <&gpio1 4 0>;
+ };
+ health_led {
label = "status:red:health_led";
gpios = <&gpio1 5 0>;
};
- health_led2 {
- label = "status:white:health_led";
- gpios = <&gpio1 4 0>;
- };
backup_led {
label = "status:blue:backup_led";
gpios = <&gpio0 15 0>;
diff --git a/arch/arm/boot/dts/msm8660-surf.dts b/arch/arm/boot/dts/msm8660-surf.dts
index 31f2157cd7d7..67f8670c4d6a 100644
--- a/arch/arm/boot/dts/msm8660-surf.dts
+++ b/arch/arm/boot/dts/msm8660-surf.dts
@@ -38,4 +38,10 @@
<0x19c00000 0x1000>;
interrupts = <0 195 0x0>;
};
+
+ qcom,ssbi@500000 {
+ compatible = "qcom,ssbi";
+ reg = <0x500000 0x1000>;
+ qcom,controller-type = "pmic-arbiter";
+ };
};
diff --git a/arch/arm/boot/dts/msm8960-cdp.dts b/arch/arm/boot/dts/msm8960-cdp.dts
index 9e621b5ad3dd..c9b09a813a4b 100644
--- a/arch/arm/boot/dts/msm8960-cdp.dts
+++ b/arch/arm/boot/dts/msm8960-cdp.dts
@@ -38,4 +38,10 @@
<0x16400000 0x1000>;
interrupts = <0 154 0x0>;
};
+
+ qcom,ssbi@500000 {
+ compatible = "qcom,ssbi";
+ reg = <0x500000 0x1000>;
+ qcom,controller-type = "pmic-arbiter";
+ };
};
diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi
index 8aad00f81ed9..f7bec3b1ba32 100644
--- a/arch/arm/boot/dts/orion5x.dtsi
+++ b/arch/arm/boot/dts/orion5x.dtsi
@@ -13,6 +13,9 @@
compatible = "marvell,orion5x";
interrupt-parent = <&intc>;
+ aliases {
+ gpio0 = &gpio0;
+ };
intc: interrupt-controller {
compatible = "marvell,orion-intc", "marvell,intc";
interrupt-controller;
@@ -32,7 +35,9 @@
#gpio-cells = <2>;
gpio-controller;
reg = <0x10100 0x40>;
- ngpio = <32>;
+ ngpios = <32>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
interrupts = <6>, <7>, <8>, <9>;
};
@@ -91,7 +96,7 @@
reg = <0x90000 0x10000>,
<0xf2200000 0x800>;
reg-names = "regs", "sram";
- interrupts = <22>;
+ interrupts = <28>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi
index 1513c1927cc8..122ae94076c8 100644
--- a/arch/arm/boot/dts/spear1310.dtsi
+++ b/arch/arm/boot/dts/spear1310.dtsi
@@ -89,7 +89,7 @@
pinmux: pinmux@e0700000 {
compatible = "st,spear1310-pinmux";
reg = <0xe0700000 0x1000>;
- #gpio-range-cells = <2>;
+ #gpio-range-cells = <3>;
};
apb {
@@ -212,7 +212,7 @@
interrupt-controller;
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pinmux 0 246>;
+ gpio-ranges = <&pinmux 0 0 246>;
status = "disabled";
st-plgpio,ngpio = <246>;
diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi
index 34da11aa6795..c511c4772efd 100644
--- a/arch/arm/boot/dts/spear1340.dtsi
+++ b/arch/arm/boot/dts/spear1340.dtsi
@@ -63,7 +63,7 @@
pinmux: pinmux@e0700000 {
compatible = "st,spear1340-pinmux";
reg = <0xe0700000 0x1000>;
- #gpio-range-cells = <2>;
+ #gpio-range-cells = <3>;
};
pwm: pwm@e0180000 {
@@ -127,7 +127,7 @@
interrupt-controller;
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pinmux 0 252>;
+ gpio-ranges = <&pinmux 0 0 252>;
status = "disabled";
st-plgpio,ngpio = <250>;
diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi
index ab45b8c81982..95372080eea6 100644
--- a/arch/arm/boot/dts/spear310.dtsi
+++ b/arch/arm/boot/dts/spear310.dtsi
@@ -25,7 +25,7 @@
pinmux: pinmux@b4000000 {
compatible = "st,spear310-pinmux";
reg = <0xb4000000 0x1000>;
- #gpio-range-cells = <2>;
+ #gpio-range-cells = <3>;
};
fsmc: flash@44000000 {
@@ -102,7 +102,7 @@
interrupt-controller;
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pinmux 0 102>;
+ gpio-ranges = <&pinmux 0 0 102>;
status = "disabled";
st-plgpio,ngpio = <102>;
diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi
index caa5520b1fd4..ffea342aeec9 100644
--- a/arch/arm/boot/dts/spear320.dtsi
+++ b/arch/arm/boot/dts/spear320.dtsi
@@ -24,7 +24,7 @@
pinmux: pinmux@b3000000 {
compatible = "st,spear320-pinmux";
reg = <0xb3000000 0x1000>;
- #gpio-range-cells = <2>;
+ #gpio-range-cells = <3>;
};
clcd@90000000 {
@@ -130,7 +130,7 @@
interrupt-controller;
gpio-controller;
#gpio-cells = <2>;
- gpio-ranges = <&pinmux 0 102>;
+ gpio-ranges = <&pinmux 0 0 102>;
status = "disabled";
st-plgpio,ngpio = <102>;
diff --git a/arch/arm/boot/dts/vt8500-bv07.dts b/arch/arm/boot/dts/vt8500-bv07.dts
index 567cf4e8ab84..877b33afa7ed 100644
--- a/arch/arm/boot/dts/vt8500-bv07.dts
+++ b/arch/arm/boot/dts/vt8500-bv07.dts
@@ -11,26 +11,22 @@
/ {
model = "Benign BV07 Netbook";
+};
- /*
- * Display node is based on Sascha Hauer's patch on dri-devel.
- * Added a bpp property to calculate the size of the framebuffer
- * until the binding is formalized.
- */
- display: display@0 {
- modes {
- mode0: mode@0 {
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hfront-porch = <40>;
- hsync-len = <0>;
- vback-porch = <32>;
- vfront-porch = <11>;
- vsync-len = <1>;
- clock = <0>; /* unused but required */
- bpp = <16>; /* non-standard but required */
- };
+&fb {
+ 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/arch/arm/boot/dts/vt8500.dtsi b/arch/arm/boot/dts/vt8500.dtsi
index cf31ced46602..68c8dc644383 100644
--- a/arch/arm/boot/dts/vt8500.dtsi
+++ b/arch/arm/boot/dts/vt8500.dtsi
@@ -98,12 +98,10 @@
interrupts = <43>;
};
- fb@d800e400 {
+ fb: fb@d8050800 {
compatible = "via,vt8500-fb";
reg = <0xd800e400 0x400>;
interrupts = <12>;
- display = <&display>;
- default-mode = <&mode0>;
};
ge_rops@d8050400 {
diff --git a/arch/arm/boot/dts/wm8505-ref.dts b/arch/arm/boot/dts/wm8505-ref.dts
index fd4e248074c6..edd2cec3d37f 100644
--- a/arch/arm/boot/dts/wm8505-ref.dts
+++ b/arch/arm/boot/dts/wm8505-ref.dts
@@ -11,26 +11,22 @@
/ {
model = "Wondermedia WM8505 Netbook";
+};
- /*
- * Display node is based on Sascha Hauer's patch on dri-devel.
- * Added a bpp property to calculate the size of the framebuffer
- * until the binding is formalized.
- */
- display: display@0 {
- modes {
- mode0: mode@0 {
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hfront-porch = <40>;
- hsync-len = <0>;
- vback-porch = <32>;
- vfront-porch = <11>;
- vsync-len = <1>;
- clock = <0>; /* unused but required */
- bpp = <32>; /* non-standard but required */
- };
+&fb {
+ bits-per-pixel = <32>;
+ 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/arch/arm/boot/dts/wm8505.dtsi b/arch/arm/boot/dts/wm8505.dtsi
index e74a1c0fb9a2..bcf668d31b28 100644
--- a/arch/arm/boot/dts/wm8505.dtsi
+++ b/arch/arm/boot/dts/wm8505.dtsi
@@ -128,11 +128,9 @@
interrupts = <0>;
};
- fb@d8050800 {
+ fb: fb@d8050800 {
compatible = "wm,wm8505-fb";
reg = <0xd8050800 0x200>;
- display = <&display>;
- default-mode = <&mode0>;
};
ge_rops@d8050400 {
diff --git a/arch/arm/boot/dts/wm8650-mid.dts b/arch/arm/boot/dts/wm8650-mid.dts
index cefd938f842f..61671a0d9ede 100644
--- a/arch/arm/boot/dts/wm8650-mid.dts
+++ b/arch/arm/boot/dts/wm8650-mid.dts
@@ -11,26 +11,24 @@
/ {
model = "Wondermedia WM8650-MID Tablet";
+};
+
+&fb {
+ bits-per-pixel = <16>;
- /*
- * Display node is based on Sascha Hauer's patch on dri-devel.
- * Added a bpp property to calculate the size of the framebuffer
- * until the binding is formalized.
- */
- display: display@0 {
- modes {
- mode0: mode@0 {
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hfront-porch = <40>;
- hsync-len = <0>;
- vback-porch = <32>;
- vfront-porch = <11>;
- vsync-len = <1>;
- clock = <0>; /* unused but required */
- bpp = <16>; /* non-standard but required */
- };
+ 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/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi
index db3c0a12e052..9313407bbc30 100644
--- a/arch/arm/boot/dts/wm8650.dtsi
+++ b/arch/arm/boot/dts/wm8650.dtsi
@@ -128,11 +128,9 @@
interrupts = <43>;
};
- fb@d8050800 {
+ fb: fb@d8050800 {
compatible = "wm,wm8505-fb";
reg = <0xd8050800 0x200>;
- display = <&display>;
- default-mode = <&mode0>;
};
ge_rops@d8050400 {
diff --git a/arch/arm/boot/dts/wm8850-w70v2.dts b/arch/arm/boot/dts/wm8850-w70v2.dts
index fcc660c89540..32d22532cd6c 100644
--- a/arch/arm/boot/dts/wm8850-w70v2.dts
+++ b/arch/arm/boot/dts/wm8850-w70v2.dts
@@ -15,28 +15,6 @@
/ {
model = "Wondermedia WM8850-W70v2 Tablet";
- /*
- * Display node is based on Sascha Hauer's patch on dri-devel.
- * Added a bpp property to calculate the size of the framebuffer
- * until the binding is formalized.
- */
- display: display@0 {
- modes {
- mode0: mode@0 {
- hactive = <800>;
- vactive = <480>;
- hback-porch = <88>;
- hfront-porch = <40>;
- hsync-len = <0>;
- vback-porch = <32>;
- vfront-porch = <11>;
- vsync-len = <1>;
- clock = <0>; /* unused but required */
- bpp = <16>; /* non-standard but required */
- };
- };
- };
-
backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 50000 1>; /* duty inverted */
@@ -45,3 +23,21 @@
default-brightness-level = <5>;
};
};
+
+&fb {
+ 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/arch/arm/boot/dts/wm8850.dtsi b/arch/arm/boot/dts/wm8850.dtsi
index e8cbfdc87bba..7149cd13e3b9 100644
--- a/arch/arm/boot/dts/wm8850.dtsi
+++ b/arch/arm/boot/dts/wm8850.dtsi
@@ -135,11 +135,9 @@
};
};
- fb@d8051700 {
+ fb: fb@d8051700 {
compatible = "wm,wm8505-fb";
reg = <0xd8051700 0x200>;
- display = <&display>;
- default-mode = <&mode0>;
};
ge_rops@d8050400 {
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index e36b01025321..088d6c11a0fa 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -188,6 +188,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MXC=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
+CONFIG_USB_PHY=y
CONFIG_USB_MXS_PHY=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
index 13482ea58b09..93f3794ba5cb 100644
--- a/arch/arm/configs/kirkwood_defconfig
+++ b/arch/arm/configs/kirkwood_defconfig
@@ -56,7 +56,6 @@ CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CPU_IDLE=y
-CONFIG_CPU_IDLE_KIRKWOOD=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index 92386b20bd09..afa7249fac6e 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -134,6 +134,7 @@ CONFIG_SND_DEBUG_VERBOSE=y
# CONFIG_SND_SPI is not set
CONFIG_SND_SOC=y
CONFIG_USB=y
+CONFIG_USB_PHY=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_USB_GADGET=y
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
index 6a99e30f81d2..87924d671115 100644
--- a/arch/arm/configs/mxs_defconfig
+++ b/arch/arm/configs/mxs_defconfig
@@ -120,6 +120,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_STORAGE=y
+CONFIG_USB_PHY=y
CONFIG_USB_MXS_PHY=y
CONFIG_MMC=y
CONFIG_MMC_MXS=y
diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig
index 42eab9a2a0fd..7e0ebb64a7f9 100644
--- a/arch/arm/configs/omap1_defconfig
+++ b/arch/arm/configs/omap1_defconfig
@@ -195,6 +195,7 @@ CONFIG_SND_SOC=y
CONFIG_SND_OMAP_SOC=y
# CONFIG_USB_HID is not set
CONFIG_USB=y
+CONFIG_USB_PHY=y
CONFIG_USB_DEBUG=y
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h
index 720799fd3a81..dff714d886d5 100644
--- a/arch/arm/include/asm/delay.h
+++ b/arch/arm/include/asm/delay.h
@@ -24,7 +24,7 @@ extern struct arm_delay_ops {
void (*delay)(unsigned long);
void (*const_udelay)(unsigned long);
void (*udelay)(unsigned long);
- bool const_clock;
+ unsigned long ticks_per_jiffy;
} arm_delay_ops;
#define __delay(n) arm_delay_ops.delay(n)
diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h
index cca9f15704ed..ea289e1435e7 100644
--- a/arch/arm/include/asm/glue-cache.h
+++ b/arch/arm/include/asm/glue-cache.h
@@ -19,14 +19,6 @@
#undef _CACHE
#undef MULTI_CACHE
-#if defined(CONFIG_CPU_CACHE_V3)
-# ifdef _CACHE
-# define MULTI_CACHE 1
-# else
-# define _CACHE v3
-# endif
-#endif
-
#if defined(CONFIG_CPU_CACHE_V4)
# ifdef _CACHE
# define MULTI_CACHE 1
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index 02fe2fbe2477..ed94b1a366ae 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -37,7 +37,7 @@ extern int iop3xx_get_init_atu(void);
* IOP3XX processor registers
*/
#define IOP3XX_PERIPHERAL_PHYS_BASE 0xffffe000
-#define IOP3XX_PERIPHERAL_VIRT_BASE 0xfeffe000
+#define IOP3XX_PERIPHERAL_VIRT_BASE 0xfedfe000
#define IOP3XX_PERIPHERAL_SIZE 0x00002000
#define IOP3XX_PERIPHERAL_UPPER_PA (IOP3XX_PERIPHERAL_PHYS_BASE +\
IOP3XX_PERIPHERAL_SIZE - 1)
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index 8c5e828f484d..91b99abe7a95 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -41,6 +41,13 @@ extern void kunmap_high(struct page *page);
#endif
#endif
+/*
+ * Needed to be able to broadcast the TLB invalidation for kmap.
+ */
+#ifdef CONFIG_ARM_ERRATA_798181
+#undef ARCH_NEEDS_KMAP_HIGH_GET
+#endif
+
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
extern void *kmap_high_get(struct page *page);
#else
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index 863a6611323c..a7b85e0d0cc1 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -27,6 +27,8 @@ void __check_vmalloc_seq(struct mm_struct *mm);
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
#define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; })
+DECLARE_PER_CPU(atomic64_t, active_asids);
+
#else /* !CONFIG_CPU_HAS_ASID */
#ifdef CONFIG_MMU
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 6ef8afd1b64c..86b8fe398b95 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -111,7 +111,7 @@
#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
#define L_PTE_S2_MT_WRITEBACK (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
#define L_PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[1] */
-#define L_PTE_S2_RDWR (_AT(pteval_t, 2) << 6) /* HAP[2:1] */
+#define L_PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
/*
* Hyp-mode PL2 PTE definitions for LPAE.
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 80d6fc4dbe4a..9bcd262a9008 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -61,6 +61,15 @@ extern void __pgd_error(const char *file, int line, pgd_t);
#define FIRST_USER_ADDRESS PAGE_SIZE
/*
+ * Use TASK_SIZE as the ceiling argument for free_pgtables() and
+ * free_pgd_range() to avoid freeing the modules pmd when LPAE is enabled (pmd
+ * page shared between user and kernel).
+ */
+#ifdef CONFIG_ARM_LPAE
+#define USER_PGTABLES_CEILING TASK_SIZE
+#endif
+
+/*
* The pgprot_* and protection_map entries will be fixed up in runtime
* to include the cachable and bufferable bits based on memory policy,
* as well as any architecture dependent bits like global/ASID and SMP
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 5a85f148b607..21a23e378bbe 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -21,9 +21,6 @@ extern void (*arm_pm_idle)(void);
extern unsigned int user_debug;
-extern void disable_hlt(void);
-extern void enable_hlt(void);
-
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_ARM_SYSTEM_MISC_H */
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index 4db8c8820f0d..ab865e65a84c 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -14,7 +14,6 @@
#include <asm/glue.h>
-#define TLB_V3_PAGE (1 << 0)
#define TLB_V4_U_PAGE (1 << 1)
#define TLB_V4_D_PAGE (1 << 2)
#define TLB_V4_I_PAGE (1 << 3)
@@ -22,7 +21,6 @@
#define TLB_V6_D_PAGE (1 << 5)
#define TLB_V6_I_PAGE (1 << 6)
-#define TLB_V3_FULL (1 << 8)
#define TLB_V4_U_FULL (1 << 9)
#define TLB_V4_D_FULL (1 << 10)
#define TLB_V4_I_FULL (1 << 11)
@@ -52,7 +50,6 @@
* =============
*
* We have the following to choose from:
- * v3 - ARMv3
* v4 - ARMv4 without write buffer
* v4wb - ARMv4 with write buffer without I TLB flush entry instruction
* v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
@@ -330,7 +327,6 @@ static inline void local_flush_tlb_all(void)
if (tlb_flag(TLB_WB))
dsb();
- tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero);
tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero);
tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero);
@@ -351,9 +347,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
if (tlb_flag(TLB_WB))
dsb();
- if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
+ if (possible_tlb_flags & (TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) {
if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) {
- tlb_op(TLB_V3_FULL, "c6, c0, 0", zero);
tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero);
tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero);
tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero);
@@ -385,9 +380,8 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
if (tlb_flag(TLB_WB))
dsb();
- if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
+ if (possible_tlb_flags & (TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) &&
cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) {
- tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr);
tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr);
tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr);
tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr);
@@ -418,7 +412,6 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
if (tlb_flag(TLB_WB))
dsb();
- tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr);
tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr);
tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr);
tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr);
@@ -450,6 +443,21 @@ static inline void local_flush_bp_all(void)
isb();
}
+#ifdef CONFIG_ARM_ERRATA_798181
+static inline void dummy_flush_tlb_a15_erratum(void)
+{
+ /*
+ * Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0.
+ */
+ asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
+ dsb();
+}
+#else
+static inline void dummy_flush_tlb_a15_erratum(void)
+{
+}
+#endif
+
/*
* flush_pmd_entry
*
diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index e4ddfb39ca34..141baa3f9a72 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -44,14 +44,6 @@
#define __ARCH_WANT_SYS_CLONE
/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
-/*
* Unimplemented (or alternatively implemented) syscalls
*/
#define __IGNORE_fadvise64_64
diff --git a/arch/arm/kernel/early_printk.c b/arch/arm/kernel/early_printk.c
index 85aa2b292692..43076536965c 100644
--- a/arch/arm/kernel/early_printk.c
+++ b/arch/arm/kernel/early_printk.c
@@ -29,28 +29,17 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
early_write(s, n);
}
-static struct console early_console = {
+static struct console early_console_dev = {
.name = "earlycon",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
-asmlinkage void early_printk(const char *fmt, ...)
-{
- char buf[512];
- int n;
- va_list ap;
-
- va_start(ap, fmt);
- n = vscnprintf(buf, sizeof(buf), fmt, ap);
- early_write(buf, n);
- va_end(ap);
-}
-
static int __init setup_early_printk(char *buf)
{
- register_console(&early_console);
+ early_console = &early_console_dev;
+ register_console(&early_console_dev);
return 0;
}
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 3248cde504ed..fefd7f971437 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -276,7 +276,13 @@ ENDPROC(ftrace_graph_caller_old)
*/
.macro mcount_enter
+/*
+ * This pad compensates for the push {lr} at the call site. Note that we are
+ * unable to unwind through a function which does not otherwise save its lr.
+ */
+ UNWIND(.pad #4)
stmdb sp!, {r0-r3, lr}
+ UNWIND(.save {r0-r3, lr})
.endm
.macro mcount_get_lr reg
@@ -289,6 +295,7 @@ ENDPROC(ftrace_graph_caller_old)
.endm
ENTRY(__gnu_mcount_nc)
+UNWIND(.fnstart)
#ifdef CONFIG_DYNAMIC_FTRACE
mov ip, lr
ldmia sp!, {lr}
@@ -296,17 +303,22 @@ ENTRY(__gnu_mcount_nc)
#else
__mcount
#endif
+UNWIND(.fnend)
ENDPROC(__gnu_mcount_nc)
#ifdef CONFIG_DYNAMIC_FTRACE
ENTRY(ftrace_caller)
+UNWIND(.fnstart)
__ftrace_caller
+UNWIND(.fnend)
ENDPROC(ftrace_caller)
#endif
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
+UNWIND(.fnstart)
__ftrace_graph_caller
+UNWIND(.fnend)
ENDPROC(ftrace_graph_caller)
#endif
diff --git a/arch/arm/kernel/etm.c b/arch/arm/kernel/etm.c
index 9b6de8c988f3..8ff0ecdc637f 100644
--- a/arch/arm/kernel/etm.c
+++ b/arch/arm/kernel/etm.c
@@ -254,7 +254,7 @@ static void sysrq_etm_dump(int key)
static struct sysrq_key_op sysrq_etm_op = {
.handler = sysrq_etm_dump,
- .help_msg = "ETM buffer dump",
+ .help_msg = "etm-buffer-dump(v)",
.action_msg = "etm",
};
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index e0eb9a1cae77..8bac553fe213 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -267,7 +267,7 @@ __create_page_tables:
addne r6, r6, #1 << SECTION_SHIFT
strne r6, [r3]
-#if defined(CONFIG_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8)
+#if defined(CONFIG_ARM_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8)
sub r4, r4, #4 @ Fixup page table pointer
@ for 64-bit descriptors
#endif
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index 96093b75ab90..1fd749ee4a1b 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -966,7 +966,7 @@ static void reset_ctrl_regs(void *unused)
}
if (err) {
- pr_warning("CPU %d debug is powered down!\n", cpu);
+ pr_warn_once("CPU %d debug is powered down!\n", cpu);
cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
return;
}
@@ -987,7 +987,7 @@ clear_vcr:
isb();
if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
- pr_warning("CPU %d failed to disable vector catch\n", cpu);
+ pr_warn_once("CPU %d failed to disable vector catch\n", cpu);
return;
}
@@ -1007,7 +1007,7 @@ clear_vcr:
}
if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
- pr_warning("CPU %d failed to clear debug register pairs\n", cpu);
+ pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu);
return;
}
@@ -1043,7 +1043,7 @@ static int dbg_cpu_pm_notify(struct notifier_block *self, unsigned long action,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata dbg_cpu_pm_nb = {
+static struct notifier_block dbg_cpu_pm_nb = {
.notifier_call = dbg_cpu_pm_notify,
};
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 146157dfe27c..8c3094d0f7b7 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -253,7 +253,10 @@ validate_event(struct pmu_hw_events *hw_events,
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct pmu *leader_pmu = event->group_leader->pmu;
- if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
+ if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
+ return 1;
+
+ if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
return 1;
return armpmu->get_event_idx(hw_events, event) >= 0;
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 047d3e40e470..ae58d3b37d9d 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -57,38 +57,6 @@ static const char *isa_modes[] = {
"ARM" , "Thumb" , "Jazelle", "ThumbEE"
};
-static volatile int hlt_counter;
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- hlt_counter--;
- BUG_ON(hlt_counter < 0);
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-
-__setup("nohlt", nohlt_setup);
-__setup("hlt", hlt_setup);
-
extern void call_with_stack(void (*fn)(void *), void *arg, void *sp);
typedef void (*phys_reset_t)(unsigned long);
@@ -172,54 +140,38 @@ static void default_idle(void)
local_irq_enable();
}
-/*
- * The idle thread.
- * We always respect 'hlt_counter' to prevent low power idle.
- */
-void cpu_idle(void)
+void arch_cpu_idle_prepare(void)
{
local_fiq_enable();
+}
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- ledtrig_cpu(CPU_LED_IDLE_START);
- while (!need_resched()) {
-#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
+void arch_cpu_idle_enter(void)
+{
+ ledtrig_cpu(CPU_LED_IDLE_START);
+#ifdef CONFIG_PL310_ERRATA_769419
+ wmb();
#endif
+}
- /*
- * We need to disable interrupts here
- * to ensure we don't miss a wakeup call.
- */
- local_irq_disable();
-#ifdef CONFIG_PL310_ERRATA_769419
- wmb();
+void arch_cpu_idle_exit(void)
+{
+ ledtrig_cpu(CPU_LED_IDLE_END);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
+}
#endif
- if (hlt_counter) {
- local_irq_enable();
- cpu_relax();
- } else if (!need_resched()) {
- stop_critical_timings();
- if (cpuidle_idle_call())
- default_idle();
- start_critical_timings();
- /*
- * default_idle functions must always
- * return with IRQs enabled.
- */
- WARN_ON(irqs_disabled());
- } else
- local_irq_enable();
- }
- ledtrig_cpu(CPU_LED_IDLE_END);
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+
+/*
+ * Called from the core idle loop.
+ */
+void arch_cpu_idle(void)
+{
+ if (cpuidle_idle_call())
+ default_idle();
}
static char reboot_mode = 'h';
@@ -273,11 +225,8 @@ void __show_regs(struct pt_regs *regs)
unsigned long flags;
char buf[64];
- printk("CPU: %d %s (%s %.*s)\n",
- raw_smp_processor_id(), print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
+ show_regs_print_info(KERN_DEFAULT);
+
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", regs->ARM_lr);
printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n"
@@ -332,7 +281,6 @@ void __show_regs(struct pt_regs *regs)
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
__show_regs(regs);
dump_stack();
}
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index bd6f56b9ec21..59d2adb764a9 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -45,12 +45,12 @@ static u32 notrace jiffy_sched_clock_read(void)
static u32 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
-static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
+static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
{
return (cyc * mult) >> shift;
}
-static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
+static unsigned long long notrace cyc_to_sched_clock(u32 cyc, u32 mask)
{
u64 epoch_ns;
u32 epoch_cyc;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 3f6cbb2e3eda..234e339196c0 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -56,7 +56,6 @@
#include <asm/virt.h>
#include "atags.h"
-#include "tcm.h"
#if defined(CONFIG_FPE_NWFPE) || defined(CONFIG_FPE_FASTFPE)
@@ -353,6 +352,23 @@ void __init early_print(const char *str, ...)
printk("%s", buf);
}
+static void __init cpuid_init_hwcaps(void)
+{
+ unsigned int divide_instrs;
+
+ if (cpu_architecture() < CPU_ARCH_ARMv7)
+ return;
+
+ divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24;
+
+ switch (divide_instrs) {
+ case 2:
+ elf_hwcap |= HWCAP_IDIVA;
+ case 1:
+ elf_hwcap |= HWCAP_IDIVT;
+ }
+}
+
static void __init feat_v6_fixup(void)
{
int id = read_cpuid_id();
@@ -483,8 +499,11 @@ static void __init setup_processor(void)
snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
list->elf_name, ENDIANNESS);
elf_hwcap = list->elf_hwcap;
+
+ cpuid_init_hwcaps();
+
#ifndef CONFIG_ARM_THUMB
- elf_hwcap &= ~HWCAP_THUMB;
+ elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
#endif
feat_v6_fixup();
@@ -524,7 +543,7 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
size -= start & ~PAGE_MASK;
bank->start = PAGE_ALIGN(start);
-#ifndef CONFIG_LPAE
+#ifndef CONFIG_ARM_LPAE
if (bank->start + size < bank->start) {
printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
"32-bit physical address space\n", (long long)start);
@@ -778,8 +797,6 @@ void __init setup_arch(char **cmdline_p)
reserve_crashkernel();
- tcm_init();
-
#ifdef CONFIG_MULTI_IRQ_HANDLER
handle_arch_irq = mdesc->handle_irq;
#endif
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 79078edbb9bc..4619177bcfe6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -336,7 +336,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* OK, it's off to the idle thread for us
*/
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_cpus_done(unsigned int max_cpus)
@@ -673,9 +673,6 @@ static int cpufreq_callback(struct notifier_block *nb,
if (freq->flags & CPUFREQ_CONST_LOOPS)
return NOTIFY_OK;
- if (arm_delay_ops.const_clock)
- return NOTIFY_OK;
-
if (!per_cpu(l_p_j_ref, cpu)) {
per_cpu(l_p_j_ref, cpu) =
per_cpu(cpu_data, cpu).loops_per_jiffy;
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c
index bd0300531399..e82e1d248772 100644
--- a/arch/arm/kernel/smp_tlb.c
+++ b/arch/arm/kernel/smp_tlb.c
@@ -12,6 +12,7 @@
#include <asm/smp_plat.h>
#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
/**********************************************************************/
@@ -69,12 +70,72 @@ static inline void ipi_flush_bp_all(void *ignored)
local_flush_bp_all();
}
+#ifdef CONFIG_ARM_ERRATA_798181
+static int erratum_a15_798181(void)
+{
+ unsigned int midr = read_cpuid_id();
+
+ /* Cortex-A15 r0p0..r3p2 affected */
+ if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
+ return 0;
+ return 1;
+}
+#else
+static int erratum_a15_798181(void)
+{
+ return 0;
+}
+#endif
+
+static void ipi_flush_tlb_a15_erratum(void *arg)
+{
+ dmb();
+}
+
+static void broadcast_tlb_a15_erratum(void)
+{
+ if (!erratum_a15_798181())
+ return;
+
+ dummy_flush_tlb_a15_erratum();
+ smp_call_function_many(cpu_online_mask, ipi_flush_tlb_a15_erratum,
+ NULL, 1);
+}
+
+static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
+{
+ int cpu;
+ cpumask_t mask = { CPU_BITS_NONE };
+
+ if (!erratum_a15_798181())
+ return;
+
+ dummy_flush_tlb_a15_erratum();
+ for_each_online_cpu(cpu) {
+ if (cpu == smp_processor_id())
+ continue;
+ /*
+ * We only need to send an IPI if the other CPUs are running
+ * the same ASID as the one being invalidated. There is no
+ * need for locking around the active_asids check since the
+ * switch_mm() function has at least one dmb() (as required by
+ * this workaround) in case a context switch happens on
+ * another CPU after the condition below.
+ */
+ if (atomic64_read(&mm->context.id) ==
+ atomic64_read(&per_cpu(active_asids, cpu)))
+ cpumask_set_cpu(cpu, &mask);
+ }
+ smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
+}
+
void flush_tlb_all(void)
{
if (tlb_ops_need_broadcast())
on_each_cpu(ipi_flush_tlb_all, NULL, 1);
else
local_flush_tlb_all();
+ broadcast_tlb_a15_erratum();
}
void flush_tlb_mm(struct mm_struct *mm)
@@ -83,6 +144,7 @@ void flush_tlb_mm(struct mm_struct *mm)
on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
else
local_flush_tlb_mm(mm);
+ broadcast_tlb_mm_a15_erratum(mm);
}
void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
@@ -95,6 +157,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
&ta, 1);
} else
local_flush_tlb_page(vma, uaddr);
+ broadcast_tlb_mm_a15_erratum(vma->vm_mm);
}
void flush_tlb_kernel_page(unsigned long kaddr)
@@ -105,6 +168,7 @@ void flush_tlb_kernel_page(unsigned long kaddr)
on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
} else
local_flush_tlb_kernel_page(kaddr);
+ broadcast_tlb_a15_erratum();
}
void flush_tlb_range(struct vm_area_struct *vma,
@@ -119,6 +183,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
&ta, 1);
} else
local_flush_tlb_range(vma, start, end);
+ broadcast_tlb_mm_a15_erratum(vma->vm_mm);
}
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
@@ -130,6 +195,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
} else
local_flush_tlb_kernel_range(start, end);
+ broadcast_tlb_a15_erratum();
}
void flush_bp_all(void)
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c
index 30ae6bb4a310..f50f19e5c138 100644
--- a/arch/arm/kernel/tcm.c
+++ b/arch/arm/kernel/tcm.c
@@ -17,7 +17,6 @@
#include <asm/mach/map.h>
#include <asm/memory.h>
#include <asm/system_info.h>
-#include "tcm.h"
static struct gen_pool *tcm_pool;
static bool dtcm_present;
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 79282ebcd939..f10316b4ecdc 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -100,7 +100,7 @@ static void __init parse_dt_topology(void)
int alloc_size, cpu = 0;
alloc_size = nr_cpu_ids * sizeof(struct cpu_capacity);
- cpu_capacity = (struct cpu_capacity *)kzalloc(alloc_size, GFP_NOWAIT);
+ cpu_capacity = kzalloc(alloc_size, GFP_NOWAIT);
while ((cn = of_find_node_by_type(cn, "cpu"))) {
const u32 *rate, *reg;
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 1c089119b2d7..18b32e8e4497 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -204,13 +204,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
}
#endif
-void dump_stack(void)
-{
- dump_backtrace(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
dump_backtrace(NULL, tsk);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 5a936988eb24..842098d78f58 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -201,6 +201,7 @@ int kvm_dev_ioctl_check_extension(long ext)
break;
case KVM_CAP_ARM_SET_DEVICE_ADDR:
r = 1;
+ break;
case KVM_CAP_NR_VCPUS:
r = num_online_cpus();
break;
@@ -613,7 +614,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers)
|| !arm_exit_handlers[hsr_ec]) {
- kvm_err("Unkown exception class: %#08lx, "
+ kvm_err("Unknown exception class: %#08lx, "
"hsr: %#08x\n", hsr_ec,
(unsigned int)vcpu->arch.hsr);
BUG();
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 4ea9a982269c..7bed7556077a 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -79,11 +79,11 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
u32 val;
int cpu;
- cpu = get_cpu();
-
if (!p->is_write)
return read_from_write_only(vcpu, p);
+ cpu = get_cpu();
+
cpumask_setall(&vcpu->arch.require_dcache_flush);
cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index c9a17316e9fe..0e4cfe123b38 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -883,8 +883,7 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
lr, irq, vgic_cpu->vgic_lr[lr]);
BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
vgic_cpu->vgic_lr[lr] |= GICH_LR_PENDING_BIT;
-
- goto out;
+ return true;
}
/* Try to use another LR for this interrupt */
@@ -898,7 +897,6 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
vgic_cpu->vgic_irq_lr_map[irq] = lr;
set_bit(lr, vgic_cpu->lr_used);
-out:
if (!vgic_irq_is_edge(vcpu, irq))
vgic_cpu->vgic_lr[lr] |= GICH_LR_EOI;
@@ -1018,21 +1016,6 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
kvm_debug("MISR = %08x\n", vgic_cpu->vgic_misr);
- /*
- * We do not need to take the distributor lock here, since the only
- * action we perform is clearing the irq_active_bit for an EOIed
- * level interrupt. There is a potential race with
- * the queuing of an interrupt in __kvm_vgic_flush_hwstate(), where we
- * check if the interrupt is already active. Two possibilities:
- *
- * - The queuing is occurring on the same vcpu: cannot happen,
- * as we're already in the context of this vcpu, and
- * executing the handler
- * - The interrupt has been migrated to another vcpu, and we
- * ignore this interrupt for this run. Big deal. It is still
- * pending though, and will get considered when this vcpu
- * exits.
- */
if (vgic_cpu->vgic_misr & GICH_MISR_EOI) {
/*
* Some level interrupts have been EOIed. Clear their
@@ -1054,6 +1037,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
} else {
vgic_cpu_irq_clear(vcpu, irq);
}
+
+ /*
+ * Despite being EOIed, the LR may not have
+ * been marked as empty.
+ */
+ set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr);
+ vgic_cpu->vgic_lr[lr] &= ~GICH_LR_ACTIVE_BIT;
}
}
@@ -1064,9 +1054,8 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
}
/*
- * Sync back the VGIC state after a guest run. We do not really touch
- * the distributor here (the irq_pending_on_cpu bit is safe to set),
- * so there is no need for taking its lock.
+ * Sync back the VGIC state after a guest run. The distributor lock is
+ * needed so we don't get preempted in the middle of the state processing.
*/
static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
{
@@ -1112,10 +1101,14 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
if (!irqchip_in_kernel(vcpu->kvm))
return;
+ spin_lock(&dist->lock);
__kvm_vgic_sync_hwstate(vcpu);
+ spin_unlock(&dist->lock);
}
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
index 6b93f6a1a3c7..64dbfa57204a 100644
--- a/arch/arm/lib/delay.c
+++ b/arch/arm/lib/delay.c
@@ -58,7 +58,7 @@ static void __timer_delay(unsigned long cycles)
static void __timer_const_udelay(unsigned long xloops)
{
unsigned long long loops = xloops;
- loops *= loops_per_jiffy;
+ loops *= arm_delay_ops.ticks_per_jiffy;
__timer_delay(loops >> UDELAY_SHIFT);
}
@@ -73,11 +73,13 @@ void __init register_current_timer_delay(const struct delay_timer *timer)
pr_info("Switching to timer-based delay loop\n");
delay_timer = timer;
lpj_fine = timer->freq / HZ;
- loops_per_jiffy = lpj_fine;
+
+ /* cpufreq may scale loops_per_jiffy, so keep a private copy */
+ arm_delay_ops.ticks_per_jiffy = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
- arm_delay_ops.const_clock = true;
+
delay_calibrated = true;
} else {
pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index b67cd5374117..44199bc2c665 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -232,6 +232,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffc8000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffcc000.spi", &spi1_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index d3addee43d8d..2ec5efea3f03 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -262,6 +262,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index 5dfc8fd87103..ccd078355eed 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -172,6 +172,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0000000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi1_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 44a9a62dcc13..a200d8a17123 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -237,6 +237,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0000000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi1_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index 0c6381516a5a..48f1228c611c 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -27,8 +27,6 @@
#define AT91_MAX_STATES 2
-static DEFINE_PER_CPU(struct cpuidle_device, at91_cpuidle_device);
-
/* Actual code that puts the SoC in different idle states */
static int at91_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
@@ -47,7 +45,6 @@ static int at91_enter_idle(struct cpuidle_device *dev,
static struct cpuidle_driver at91_idle_driver = {
.name = "at91_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = at91_enter_idle,
@@ -61,20 +58,9 @@ static struct cpuidle_driver at91_idle_driver = {
};
/* Initialize CPU idle by registering the idle states */
-static int at91_init_cpuidle(void)
+static int __init at91_init_cpuidle(void)
{
- struct cpuidle_device *device;
-
- device = &per_cpu(at91_cpuidle_device, smp_processor_id());
- device->state_count = AT91_MAX_STATES;
-
- cpuidle_register_driver(&at91_idle_driver);
-
- if (cpuidle_register_device(device)) {
- printk(KERN_ERR "at91_init_cpuidle: Failed registering\n");
- return -EIO;
- }
- return 0;
+ return cpuidle_register(&at91_idle_driver, NULL);
}
device_initcall(at91_init_cpuidle);
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index bf02471d7e7c..f11289519c39 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -6,6 +6,7 @@ config ARCH_BCM
select ARM_ERRATA_764369 if SMP
select ARM_GIC
select CPU_V7
+ select CLKSRC_OF
select GENERIC_CLOCKEVENTS
select GENERIC_TIME
select GPIO_BCM
diff --git a/arch/arm/mach-bcm/board_bcm.c b/arch/arm/mach-bcm/board_bcm.c
index f0f9abafad29..259593540477 100644
--- a/arch/arm/mach-bcm/board_bcm.c
+++ b/arch/arm/mach-bcm/board_bcm.c
@@ -16,14 +16,11 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/irqchip.h>
+#include <linux/clocksource.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-static void timer_init(void)
-{
-}
-
static void __init board_init(void)
{
@@ -35,7 +32,7 @@ static const char * const bcm11351_dt_compat[] = { "bcm,bcm11351", NULL, };
DT_MACHINE_START(BCM11351_DT, "Broadcom Application Processor")
.init_irq = irqchip_init,
- .init_time = timer_init,
+ .init_time = clocksource_of_init,
.init_machine = board_init,
.dt_compat = bcm11351_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-cns3xxx/core.c b/arch/arm/mach-cns3xxx/core.c
index e698f26cc0cb..52e4bb5cf12d 100644
--- a/arch/arm/mach-cns3xxx/core.c
+++ b/arch/arm/mach-cns3xxx/core.c
@@ -22,19 +22,9 @@
static struct map_desc cns3xxx_io_desc[] __initdata = {
{
- .virtual = CNS3XXX_TC11MP_TWD_BASE_VIRT,
- .pfn = __phys_to_pfn(CNS3XXX_TC11MP_TWD_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT,
- .pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_CPU_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT,
- .pfn = __phys_to_pfn(CNS3XXX_TC11MP_GIC_DIST_BASE),
- .length = SZ_4K,
+ .virtual = CNS3XXX_TC11MP_SCU_BASE_VIRT,
+ .pfn = __phys_to_pfn(CNS3XXX_TC11MP_SCU_BASE),
+ .length = SZ_8K,
.type = MT_DEVICE,
}, {
.virtual = CNS3XXX_TIMER1_2_3_BASE_VIRT,
diff --git a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
index 191c8e57f289..b1021aafa481 100644
--- a/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
+++ b/arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
@@ -94,10 +94,10 @@
#define RTC_INTR_STS_OFFSET 0x34
#define CNS3XXX_MISC_BASE 0x76000000 /* Misc Control */
-#define CNS3XXX_MISC_BASE_VIRT 0xFFF07000 /* Misc Control */
+#define CNS3XXX_MISC_BASE_VIRT 0xFB000000 /* Misc Control */
#define CNS3XXX_PM_BASE 0x77000000 /* Power Management Control */
-#define CNS3XXX_PM_BASE_VIRT 0xFFF08000
+#define CNS3XXX_PM_BASE_VIRT 0xFB001000
#define PM_CLK_GATE_OFFSET 0x00
#define PM_SOFT_RST_OFFSET 0x04
@@ -109,7 +109,7 @@
#define PM_PLL_HM_PD_OFFSET 0x1C
#define CNS3XXX_UART0_BASE 0x78000000 /* UART 0 */
-#define CNS3XXX_UART0_BASE_VIRT 0xFFF09000
+#define CNS3XXX_UART0_BASE_VIRT 0xFB002000
#define CNS3XXX_UART1_BASE 0x78400000 /* UART 1 */
#define CNS3XXX_UART1_BASE_VIRT 0xFFF0A000
@@ -130,7 +130,7 @@
#define CNS3XXX_I2S_BASE_VIRT 0xFFF10000
#define CNS3XXX_TIMER1_2_3_BASE 0x7C800000 /* Timer */
-#define CNS3XXX_TIMER1_2_3_BASE_VIRT 0xFFF10800
+#define CNS3XXX_TIMER1_2_3_BASE_VIRT 0xFB003000
#define TIMER1_COUNTER_OFFSET 0x00
#define TIMER1_AUTO_RELOAD_OFFSET 0x04
@@ -227,16 +227,16 @@
* Testchip peripheral and fpga gic regions
*/
#define CNS3XXX_TC11MP_SCU_BASE 0x90000000 /* IRQ, Test chip */
-#define CNS3XXX_TC11MP_SCU_BASE_VIRT 0xFF000000
+#define CNS3XXX_TC11MP_SCU_BASE_VIRT 0xFB004000
#define CNS3XXX_TC11MP_GIC_CPU_BASE 0x90000100 /* Test chip interrupt controller CPU interface */
-#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT 0xFF000100
+#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x100)
#define CNS3XXX_TC11MP_TWD_BASE 0x90000600
-#define CNS3XXX_TC11MP_TWD_BASE_VIRT 0xFF000600
+#define CNS3XXX_TC11MP_TWD_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x600)
#define CNS3XXX_TC11MP_GIC_DIST_BASE 0x90001000 /* Test chip interrupt controller distributor */
-#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT 0xFF001000
+#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x1000)
#define CNS3XXX_TC11MP_L220_BASE 0x92002000 /* L220 registers */
#define CNS3XXX_TC11MP_L220_BASE_VIRT 0xFF002000
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index fb5c1aa98a63..dd1ffccc75e9 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -37,7 +37,6 @@ obj-$(CONFIG_MACH_MITYOMAPL138) += board-mityomapl138.o
obj-$(CONFIG_MACH_OMAPL138_HAWKBOARD) += board-omapl138-hawk.o
# Power Management
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_SUSPEND) += pm.o sleep.o
obj-$(CONFIG_HAVE_CLK) += pm_domain.o
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 147b8e1a4407..886481c12173 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -242,6 +242,73 @@ static struct vpfe_config vpfe_cfg = {
.ccdc = "DM355 CCDC",
};
+/* venc standards timings */
+static struct vpbe_enc_mode_info dm355evm_enc_preset_timing[] = {
+ {
+ .name = "ntsc",
+ .timings_type = VPBE_ENC_STD,
+ .std_id = V4L2_STD_NTSC,
+ .interlaced = 1,
+ .xres = 720,
+ .yres = 480,
+ .aspect = {11, 10},
+ .fps = {30000, 1001},
+ .left_margin = 0x79,
+ .upper_margin = 0x10,
+ },
+ {
+ .name = "pal",
+ .timings_type = VPBE_ENC_STD,
+ .std_id = V4L2_STD_PAL,
+ .interlaced = 1,
+ .xres = 720,
+ .yres = 576,
+ .aspect = {54, 59},
+ .fps = {25, 1},
+ .left_margin = 0x7E,
+ .upper_margin = 0x16
+ },
+};
+
+#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
+
+/*
+ * The outputs available from VPBE + ecnoders. Keep the
+ * the order same as that of encoders. First those from venc followed by that
+ * from encoders. Index in the output refers to index on a particular encoder.
+ * Driver uses this index to pass it to encoder when it supports more than
+ * one output. Application uses index of the array to set an output.
+ */
+static struct vpbe_output dm355evm_vpbe_outputs[] = {
+ {
+ .output = {
+ .index = 0,
+ .name = "Composite",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .std = VENC_STD_ALL,
+ .capabilities = V4L2_OUT_CAP_STD,
+ },
+ .subdev_name = DM355_VPBE_VENC_SUBDEV_NAME,
+ .default_mode = "ntsc",
+ .num_modes = ARRAY_SIZE(dm355evm_enc_preset_timing),
+ .modes = dm355evm_enc_preset_timing,
+ .if_params = V4L2_MBUS_FMT_FIXED,
+ },
+};
+
+static struct vpbe_config dm355evm_display_cfg = {
+ .module_name = "dm355-vpbe-display",
+ .i2c_adapter_id = 1,
+ .osd = {
+ .module_name = DM355_VPBE_OSD_SUBDEV_NAME,
+ },
+ .venc = {
+ .module_name = DM355_VPBE_VENC_SUBDEV_NAME,
+ },
+ .num_outputs = ARRAY_SIZE(dm355evm_vpbe_outputs),
+ .outputs = dm355evm_vpbe_outputs,
+};
+
static struct platform_device *davinci_evm_devices[] __initdata = {
&dm355evm_dm9000,
&davinci_nand_device,
@@ -253,8 +320,6 @@ static struct davinci_uart_config uart_config __initdata = {
static void __init dm355_evm_map_io(void)
{
- /* setup input configuration for VPFE input devices */
- dm355_set_vpfe_config(&vpfe_cfg);
dm355_init();
}
@@ -344,6 +409,8 @@ static __init void dm355_evm_init(void)
davinci_setup_mmc(0, &dm355evm_mmc_config);
davinci_setup_mmc(1, &dm355evm_mmc_config);
+ dm355_init_video(&vpfe_cfg, &dm355evm_display_cfg);
+
dm355_init_spi0(BIT(0), dm355_evm_spi_info,
ARRAY_SIZE(dm355_evm_spi_info));
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index c2d4958a0cb6..2a6674356585 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -27,6 +27,7 @@
#include <linux/input.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
+#include <linux/v4l2-dv-timings.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,6 +40,7 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/keyscan-davinci.h>
+#include <media/ths7303.h>
#include <media/tvp514x.h>
#include "davinci.h"
@@ -374,6 +376,166 @@ static struct vpfe_config vpfe_cfg = {
.ccdc = "ISIF",
};
+/* venc standards timings */
+static struct vpbe_enc_mode_info dm365evm_enc_std_timing[] = {
+ {
+ .name = "ntsc",
+ .timings_type = VPBE_ENC_STD,
+ .std_id = V4L2_STD_NTSC,
+ .interlaced = 1,
+ .xres = 720,
+ .yres = 480,
+ .aspect = {11, 10},
+ .fps = {30000, 1001},
+ .left_margin = 0x79,
+ .upper_margin = 0x10,
+ },
+ {
+ .name = "pal",
+ .timings_type = VPBE_ENC_STD,
+ .std_id = V4L2_STD_PAL,
+ .interlaced = 1,
+ .xres = 720,
+ .yres = 576,
+ .aspect = {54, 59},
+ .fps = {25, 1},
+ .left_margin = 0x7E,
+ .upper_margin = 0x16,
+ },
+};
+
+/* venc dv timings */
+static struct vpbe_enc_mode_info dm365evm_enc_preset_timing[] = {
+ {
+ .name = "480p59_94",
+ .timings_type = VPBE_ENC_DV_TIMINGS,
+ .dv_timings = V4L2_DV_BT_CEA_720X480P59_94,
+ .interlaced = 0,
+ .xres = 720,
+ .yres = 480,
+ .aspect = {1, 1},
+ .fps = {5994, 100},
+ .left_margin = 0x8F,
+ .upper_margin = 0x2D,
+ },
+ {
+ .name = "576p50",
+ .timings_type = VPBE_ENC_DV_TIMINGS,
+ .dv_timings = V4L2_DV_BT_CEA_720X576P50,
+ .interlaced = 0,
+ .xres = 720,
+ .yres = 576,
+ .aspect = {1, 1},
+ .fps = {50, 1},
+ .left_margin = 0x8C,
+ .upper_margin = 0x36,
+ },
+ {
+ .name = "720p60",
+ .timings_type = VPBE_ENC_DV_TIMINGS,
+ .dv_timings = V4L2_DV_BT_CEA_1280X720P60,
+ .interlaced = 0,
+ .xres = 1280,
+ .yres = 720,
+ .aspect = {1, 1},
+ .fps = {60, 1},
+ .left_margin = 0x117,
+ .right_margin = 70,
+ .upper_margin = 38,
+ .lower_margin = 3,
+ .hsync_len = 80,
+ .vsync_len = 5,
+ },
+ {
+ .name = "1080i60",
+ .timings_type = VPBE_ENC_DV_TIMINGS,
+ .dv_timings = V4L2_DV_BT_CEA_1920X1080I60,
+ .interlaced = 1,
+ .xres = 1920,
+ .yres = 1080,
+ .aspect = {1, 1},
+ .fps = {30, 1},
+ .left_margin = 0xc9,
+ .right_margin = 80,
+ .upper_margin = 30,
+ .lower_margin = 3,
+ .hsync_len = 88,
+ .vsync_len = 5,
+ },
+};
+
+#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)
+
+/*
+ * The outputs available from VPBE + ecnoders. Keep the
+ * the order same as that of encoders. First those from venc followed by that
+ * from encoders. Index in the output refers to index on a particular
+ * encoder.Driver uses this index to pass it to encoder when it supports more
+ * than one output. Application uses index of the array to set an output.
+ */
+static struct vpbe_output dm365evm_vpbe_outputs[] = {
+ {
+ .output = {
+ .index = 0,
+ .name = "Composite",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .std = VENC_STD_ALL,
+ .capabilities = V4L2_OUT_CAP_STD,
+ },
+ .subdev_name = DM365_VPBE_VENC_SUBDEV_NAME,
+ .default_mode = "ntsc",
+ .num_modes = ARRAY_SIZE(dm365evm_enc_std_timing),
+ .modes = dm365evm_enc_std_timing,
+ .if_params = V4L2_MBUS_FMT_FIXED,
+ },
+ {
+ .output = {
+ .index = 1,
+ .name = "Component",
+ .type = V4L2_OUTPUT_TYPE_ANALOG,
+ .capabilities = V4L2_OUT_CAP_DV_TIMINGS,
+ },
+ .subdev_name = DM365_VPBE_VENC_SUBDEV_NAME,
+ .default_mode = "480p59_94",
+ .num_modes = ARRAY_SIZE(dm365evm_enc_preset_timing),
+ .modes = dm365evm_enc_preset_timing,
+ .if_params = V4L2_MBUS_FMT_FIXED,
+ },
+};
+
+/*
+ * Amplifiers on the board
+ */
+struct ths7303_platform_data ths7303_pdata = {
+ .ch_1 = 3,
+ .ch_2 = 3,
+ .ch_3 = 3,
+ .init_enable = 1,
+};
+
+static struct amp_config_info vpbe_amp = {
+ .module_name = "ths7303",
+ .is_i2c = 1,
+ .board_info = {
+ I2C_BOARD_INFO("ths7303", 0x2c),
+ .platform_data = &ths7303_pdata,
+ }
+};
+
+static struct vpbe_config dm365evm_display_cfg = {
+ .module_name = "dm365-vpbe-display",
+ .i2c_adapter_id = 1,
+ .amp = &vpbe_amp,
+ .osd = {
+ .module_name = DM365_VPBE_OSD_SUBDEV_NAME,
+ },
+ .venc = {
+ .module_name = DM365_VPBE_VENC_SUBDEV_NAME,
+ },
+ .num_outputs = ARRAY_SIZE(dm365evm_vpbe_outputs),
+ .outputs = dm365evm_vpbe_outputs,
+};
+
static void __init evm_init_i2c(void)
{
davinci_init_i2c(&i2c_pdata);
@@ -564,8 +726,6 @@ static struct davinci_uart_config uart_config __initdata = {
static void __init dm365_evm_map_io(void)
{
- /* setup input configuration for VPFE input devices */
- dm365_set_vpfe_config(&vpfe_cfg);
dm365_init();
}
@@ -597,6 +757,8 @@ static __init void dm365_evm_init(void)
davinci_setup_mmc(0, &dm365evm_mmc_config);
+ dm365_init_video(&vpfe_cfg, &dm365evm_display_cfg);
+
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 71735e7797cc..745280d4144c 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -622,7 +622,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
{
.name = "ntsc",
.timings_type = VPBE_ENC_STD,
- .std_id = V4L2_STD_525_60,
+ .std_id = V4L2_STD_NTSC,
.interlaced = 1,
.xres = 720,
.yres = 480,
@@ -634,7 +634,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
{
.name = "pal",
.timings_type = VPBE_ENC_STD,
- .std_id = V4L2_STD_625_50,
+ .std_id = V4L2_STD_PAL,
.interlaced = 1,
.xres = 720,
.yres = 576,
@@ -649,7 +649,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = {
static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = {
{
.name = "480p59_94",
- .timings_type = VPBE_ENC_CUSTOM_TIMINGS,
+ .timings_type = VPBE_ENC_DV_TIMINGS,
.dv_timings = V4L2_DV_BT_CEA_720X480P59_94,
.interlaced = 0,
.xres = 720,
@@ -661,7 +661,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = {
},
{
.name = "576p50",
- .timings_type = VPBE_ENC_CUSTOM_TIMINGS,
+ .timings_type = VPBE_ENC_DV_TIMINGS,
.dv_timings = V4L2_DV_BT_CEA_720X576P50,
.interlaced = 0,
.xres = 720,
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index de7adff324dc..fc4871ac1c2c 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -514,7 +514,7 @@ static const struct vpif_output dm6467_ch0_outputs[] = {
.index = 1,
.name = "Component",
.type = V4L2_OUTPUT_TYPE_ANALOG,
- .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS,
+ .capabilities = V4L2_OUT_CAP_DV_TIMINGS,
},
.subdev_name = "adv7343",
.output_route = ADV7343_COMPONENT_ID,
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index 5ac9e9384b15..36aef3a7dedb 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -25,7 +25,6 @@
#define DAVINCI_CPUIDLE_MAX_STATES 2
-static DEFINE_PER_CPU(struct cpuidle_device, davinci_cpuidle_device);
static void __iomem *ddr2_reg_base;
static bool ddr2_pdown;
@@ -50,14 +49,10 @@ static void davinci_save_ddr_power(int enter, bool pdown)
/* Actual code that puts the SoC in different idle states */
static int davinci_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+ struct cpuidle_driver *drv, int index)
{
davinci_save_ddr_power(1, ddr2_pdown);
-
- index = cpuidle_wrap_enter(dev, drv, index,
- arm_cpuidle_simple_enter);
-
+ cpu_do_idle();
davinci_save_ddr_power(0, ddr2_pdown);
return index;
@@ -66,7 +61,6 @@ static int davinci_enter_idle(struct cpuidle_device *dev,
static struct cpuidle_driver davinci_idle_driver = {
.name = "cpuidle-davinci",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = davinci_enter_idle,
@@ -81,12 +75,8 @@ static struct cpuidle_driver davinci_idle_driver = {
static int __init davinci_cpuidle_probe(struct platform_device *pdev)
{
- int ret;
- struct cpuidle_device *device;
struct davinci_cpuidle_config *pdata = pdev->dev.platform_data;
- device = &per_cpu(davinci_cpuidle_device, smp_processor_id());
-
if (!pdata) {
dev_err(&pdev->dev, "cannot get platform data\n");
return -ENOENT;
@@ -96,20 +86,7 @@ static int __init davinci_cpuidle_probe(struct platform_device *pdev)
ddr2_pdown = pdata->ddr2_pdown;
- ret = cpuidle_register_driver(&davinci_idle_driver);
- if (ret) {
- dev_err(&pdev->dev, "failed to register driver\n");
- return ret;
- }
-
- ret = cpuidle_register_device(device);
- if (ret) {
- dev_err(&pdev->dev, "failed to register device\n");
- cpuidle_unregister_driver(&davinci_idle_driver);
- return ret;
- }
-
- return 0;
+ return cpuidle_register(&davinci_idle_driver, NULL);
}
static struct platform_driver davinci_cpuidle_driver = {
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
index 12d544befcfa..1ab3df423dac 100644
--- a/arch/arm/mach-davinci/davinci.h
+++ b/arch/arm/mach-davinci/davinci.h
@@ -36,12 +36,19 @@
#include <media/davinci/vpbe_osd.h>
#define DAVINCI_SYSTEM_MODULE_BASE 0x01c40000
+#define SYSMOD_VDAC_CONFIG 0x2c
#define SYSMOD_VIDCLKCTL 0x38
#define SYSMOD_VPSS_CLKCTL 0x44
#define SYSMOD_VDD3P3VPWDN 0x48
#define SYSMOD_VSCLKDIS 0x6c
#define SYSMOD_PUPDCTL1 0x7c
+/* VPSS CLKCTL bit definitions */
+#define VPSS_MUXSEL_EXTCLK_ENABLE BIT(1)
+#define VPSS_VENCCLKEN_ENABLE BIT(3)
+#define VPSS_DACCLKEN_ENABLE BIT(4)
+#define VPSS_PLLC2SYSCLK5_ENABLE BIT(5)
+
extern void __iomem *davinci_sysmod_base;
#define DAVINCI_SYSMOD_VIRT(x) (davinci_sysmod_base + (x))
void davinci_map_sysmod(void);
@@ -74,7 +81,7 @@ void __init dm355_init(void);
void dm355_init_spi0(unsigned chipselect_mask,
const struct spi_board_info *info, unsigned len);
void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
-void dm355_set_vpfe_config(struct vpfe_config *cfg);
+int dm355_init_video(struct vpfe_config *, struct vpbe_config *);
/* DM365 function declarations */
void __init dm365_init(void);
@@ -84,7 +91,7 @@ void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
void __init dm365_init_rtc(void);
void dm365_init_spi0(unsigned chipselect_mask,
const struct spi_board_info *info, unsigned len);
-void dm365_set_vpfe_config(struct vpfe_config *cfg);
+int dm365_init_video(struct vpfe_config *, struct vpbe_config *);
/* DM644x function declarations */
void __init dm644x_init(void);
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index b49c3b77d55e..bf9a9d4ad9f5 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -35,6 +35,8 @@
#include "asp.h"
#define DM355_UART2_BASE (IO_PHYS + 0x206000)
+#define DM355_OSD_BASE (IO_PHYS + 0x70200)
+#define DM355_VENC_BASE (IO_PHYS + 0x70400)
/*
* Device specific clocks
@@ -345,8 +347,8 @@ static struct clk_lookup dm355_clks[] = {
CLK(NULL, "pll1_aux", &pll1_aux_clk),
CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp),
CLK(NULL, "vpss_dac", &vpss_dac_clk),
- CLK(NULL, "vpss_master", &vpss_master_clk),
- CLK(NULL, "vpss_slave", &vpss_slave_clk),
+ CLK("vpss", "master", &vpss_master_clk),
+ CLK("vpss", "slave", &vpss_slave_clk),
CLK(NULL, "clkout1", &clkout1_clk),
CLK(NULL, "clkout2", &clkout2_clk),
CLK(NULL, "pll2", &pll2_clk),
@@ -744,11 +746,146 @@ static struct platform_device vpfe_capture_dev = {
},
};
-void dm355_set_vpfe_config(struct vpfe_config *cfg)
+static struct resource dm355_osd_resources[] = {
+ {
+ .start = DM355_OSD_BASE,
+ .end = DM355_OSD_BASE + 0x17f,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device dm355_osd_dev = {
+ .name = DM355_VPBE_OSD_SUBDEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm355_osd_resources),
+ .resource = dm355_osd_resources,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource dm355_venc_resources[] = {
+ {
+ .start = IRQ_VENCINT,
+ .end = IRQ_VENCINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* venc registers io space */
+ {
+ .start = DM355_VENC_BASE,
+ .end = DM355_VENC_BASE + 0x17f,
+ .flags = IORESOURCE_MEM,
+ },
+ /* VDAC config register io space */
+ {
+ .start = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG,
+ .end = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource dm355_v4l2_disp_resources[] = {
+ {
+ .start = IRQ_VENCINT,
+ .end = IRQ_VENCINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* venc registers io space */
+ {
+ .start = DM355_VENC_BASE,
+ .end = DM355_VENC_BASE + 0x17f,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static int dm355_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type,
+ int field)
+{
+ switch (if_type) {
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ davinci_cfg_reg(DM355_VOUT_FIELD_G70);
+ break;
+ case V4L2_MBUS_FMT_YUYV10_1X20:
+ if (field)
+ davinci_cfg_reg(DM355_VOUT_FIELD);
+ else
+ davinci_cfg_reg(DM355_VOUT_FIELD_G70);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ davinci_cfg_reg(DM355_VOUT_COUTL_EN);
+ davinci_cfg_reg(DM355_VOUT_COUTH_EN);
+
+ return 0;
+}
+
+static int dm355_venc_setup_clock(enum vpbe_enc_timings_type type,
+ unsigned int pclock)
{
- vpfe_capture_dev.dev.platform_data = cfg;
+ void __iomem *vpss_clk_ctrl_reg;
+
+ vpss_clk_ctrl_reg = DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL);
+
+ switch (type) {
+ case VPBE_ENC_STD:
+ writel(VPSS_DACCLKEN_ENABLE | VPSS_VENCCLKEN_ENABLE,
+ vpss_clk_ctrl_reg);
+ break;
+ case VPBE_ENC_DV_TIMINGS:
+ if (pclock > 27000000)
+ /*
+ * For HD, use external clock source since we cannot
+ * support HD mode with internal clocks.
+ */
+ writel(VPSS_MUXSEL_EXTCLK_ENABLE, vpss_clk_ctrl_reg);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
}
+static struct platform_device dm355_vpbe_display = {
+ .name = "vpbe-v4l2",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm355_v4l2_disp_resources),
+ .resource = dm355_v4l2_disp_resources,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+struct venc_platform_data dm355_venc_pdata = {
+ .setup_pinmux = dm355_vpbe_setup_pinmux,
+ .setup_clock = dm355_venc_setup_clock,
+};
+
+static struct platform_device dm355_venc_dev = {
+ .name = DM355_VPBE_VENC_SUBDEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm355_venc_resources),
+ .resource = dm355_venc_resources,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = (void *)&dm355_venc_pdata,
+ },
+};
+
+static struct platform_device dm355_vpbe_dev = {
+ .name = "vpbe_controller",
+ .id = -1,
+ .dev = {
+ .dma_mask = &vpfe_capture_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
/*----------------------------------------------------------------------*/
static struct map_desc dm355_io_desc[] = {
@@ -868,19 +1005,36 @@ void __init dm355_init(void)
davinci_map_sysmod();
}
+int __init dm355_init_video(struct vpfe_config *vpfe_cfg,
+ struct vpbe_config *vpbe_cfg)
+{
+ if (vpfe_cfg || vpbe_cfg)
+ platform_device_register(&dm355_vpss_device);
+
+ if (vpfe_cfg) {
+ vpfe_capture_dev.dev.platform_data = vpfe_cfg;
+ platform_device_register(&dm355_ccdc_dev);
+ platform_device_register(&vpfe_capture_dev);
+ }
+
+ if (vpbe_cfg) {
+ dm355_vpbe_dev.dev.platform_data = vpbe_cfg;
+ platform_device_register(&dm355_osd_dev);
+ platform_device_register(&dm355_venc_dev);
+ platform_device_register(&dm355_vpbe_dev);
+ platform_device_register(&dm355_vpbe_display);
+ }
+
+ return 0;
+}
+
static int __init dm355_init_devices(void)
{
if (!cpu_is_davinci_dm355())
return 0;
- /* Add ccdc clock aliases */
- clk_add_alias("master", dm355_ccdc_dev.name, "vpss_master", NULL);
- clk_add_alias("slave", dm355_ccdc_dev.name, "vpss_master", NULL);
davinci_cfg_reg(DM355_INT_EDMA_CC);
platform_device_register(&dm355_edma_device);
- platform_device_register(&dm355_vpss_device);
- platform_device_register(&dm355_ccdc_dev);
- platform_device_register(&vpfe_capture_dev);
return 0;
}
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 6c3980540be0..ff771ceac3f1 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -39,16 +39,13 @@
#include "asp.h"
#define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */
-
-/* Base of key scan register bank */
-#define DM365_KEYSCAN_BASE 0x01c69400
-
#define DM365_RTC_BASE 0x01c69000
-
+#define DM365_KEYSCAN_BASE 0x01c69400
+#define DM365_OSD_BASE 0x01c71c00
+#define DM365_VENC_BASE 0x01c71e00
#define DAVINCI_DM365_VC_BASE 0x01d0c000
#define DAVINCI_DMA_VC_TX 2
#define DAVINCI_DMA_VC_RX 3
-
#define DM365_EMAC_BASE 0x01d07000
#define DM365_EMAC_MDIO_BASE (DM365_EMAC_BASE + 0x4000)
#define DM365_EMAC_CNTRL_OFFSET 0x0000
@@ -257,6 +254,12 @@ static struct clk vpss_master_clk = {
.flags = CLK_PSC,
};
+static struct clk vpss_slave_clk = {
+ .name = "vpss_slave",
+ .parent = &pll1_sysclk5,
+ .lpsc = DAVINCI_LPSC_VPSSSLV,
+};
+
static struct clk arm_clk = {
.name = "arm_clk",
.parent = &pll2_sysclk2,
@@ -449,7 +452,8 @@ static struct clk_lookup dm365_clks[] = {
CLK(NULL, "pll2_sysclk8", &pll2_sysclk8),
CLK(NULL, "pll2_sysclk9", &pll2_sysclk9),
CLK(NULL, "vpss_dac", &vpss_dac_clk),
- CLK(NULL, "vpss_master", &vpss_master_clk),
+ CLK("vpss", "master", &vpss_master_clk),
+ CLK("vpss", "slave", &vpss_slave_clk),
CLK(NULL, "arm", &arm_clk),
CLK(NULL, "uart0", &uart0_clk),
CLK(NULL, "uart1", &uart1_clk),
@@ -1226,6 +1230,173 @@ static struct platform_device dm365_isif_dev = {
},
};
+static struct resource dm365_osd_resources[] = {
+ {
+ .start = DM365_OSD_BASE,
+ .end = DM365_OSD_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 dm365_video_dma_mask = DMA_BIT_MASK(32);
+
+static struct platform_device dm365_osd_dev = {
+ .name = DM365_VPBE_OSD_SUBDEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm365_osd_resources),
+ .resource = dm365_osd_resources,
+ .dev = {
+ .dma_mask = &dm365_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+static struct resource dm365_venc_resources[] = {
+ {
+ .start = IRQ_VENCINT,
+ .end = IRQ_VENCINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* venc registers io space */
+ {
+ .start = DM365_VENC_BASE,
+ .end = DM365_VENC_BASE + 0x177,
+ .flags = IORESOURCE_MEM,
+ },
+ /* vdaccfg registers io space */
+ {
+ .start = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG,
+ .end = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource dm365_v4l2_disp_resources[] = {
+ {
+ .start = IRQ_VENCINT,
+ .end = IRQ_VENCINT,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* venc registers io space */
+ {
+ .start = DM365_VENC_BASE,
+ .end = DM365_VENC_BASE + 0x177,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static int dm365_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type,
+ int field)
+{
+ switch (if_type) {
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ davinci_cfg_reg(DM365_VOUT_FIELD_G81);
+ davinci_cfg_reg(DM365_VOUT_COUTL_EN);
+ davinci_cfg_reg(DM365_VOUT_COUTH_EN);
+ break;
+ case V4L2_MBUS_FMT_YUYV10_1X20:
+ if (field)
+ davinci_cfg_reg(DM365_VOUT_FIELD);
+ else
+ davinci_cfg_reg(DM365_VOUT_FIELD_G81);
+ davinci_cfg_reg(DM365_VOUT_COUTL_EN);
+ davinci_cfg_reg(DM365_VOUT_COUTH_EN);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dm365_venc_setup_clock(enum vpbe_enc_timings_type type,
+ unsigned int pclock)
+{
+ void __iomem *vpss_clkctl_reg;
+ u32 val;
+
+ vpss_clkctl_reg = DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL);
+
+ switch (type) {
+ case VPBE_ENC_STD:
+ val = VPSS_VENCCLKEN_ENABLE | VPSS_DACCLKEN_ENABLE;
+ break;
+ case VPBE_ENC_DV_TIMINGS:
+ if (pclock <= 27000000) {
+ val = VPSS_VENCCLKEN_ENABLE | VPSS_DACCLKEN_ENABLE;
+ } else {
+ /* set sysclk4 to output 74.25 MHz from pll1 */
+ val = VPSS_PLLC2SYSCLK5_ENABLE | VPSS_DACCLKEN_ENABLE |
+ VPSS_VENCCLKEN_ENABLE;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(val, vpss_clkctl_reg);
+
+ return 0;
+}
+
+static struct platform_device dm365_vpbe_display = {
+ .name = "vpbe-v4l2",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm365_v4l2_disp_resources),
+ .resource = dm365_v4l2_disp_resources,
+ .dev = {
+ .dma_mask = &dm365_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+struct venc_platform_data dm365_venc_pdata = {
+ .setup_pinmux = dm365_vpbe_setup_pinmux,
+ .setup_clock = dm365_venc_setup_clock,
+};
+
+static struct platform_device dm365_venc_dev = {
+ .name = DM365_VPBE_VENC_SUBDEV_NAME,
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm365_venc_resources),
+ .resource = dm365_venc_resources,
+ .dev = {
+ .dma_mask = &dm365_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = (void *)&dm365_venc_pdata,
+ },
+};
+
+static struct platform_device dm365_vpbe_dev = {
+ .name = "vpbe_controller",
+ .id = -1,
+ .dev = {
+ .dma_mask = &dm365_video_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+int __init dm365_init_video(struct vpfe_config *vpfe_cfg,
+ struct vpbe_config *vpbe_cfg)
+{
+ if (vpfe_cfg || vpbe_cfg)
+ platform_device_register(&dm365_vpss_device);
+
+ if (vpfe_cfg) {
+ vpfe_capture_dev.dev.platform_data = vpfe_cfg;
+ platform_device_register(&dm365_isif_dev);
+ platform_device_register(&vpfe_capture_dev);
+ }
+ if (vpbe_cfg) {
+ dm365_vpbe_dev.dev.platform_data = vpbe_cfg;
+ platform_device_register(&dm365_osd_dev);
+ platform_device_register(&dm365_venc_dev);
+ platform_device_register(&dm365_vpbe_dev);
+ platform_device_register(&dm365_vpbe_display);
+ }
+
+ return 0;
+}
+
static int __init dm365_init_devices(void)
{
if (!cpu_is_davinci_dm365())
@@ -1239,16 +1410,6 @@ static int __init dm365_init_devices(void)
clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev),
NULL, &dm365_emac_device.dev);
- /* Add isif clock alias */
- clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL);
- platform_device_register(&dm365_vpss_device);
- platform_device_register(&dm365_isif_dev);
- platform_device_register(&vpfe_capture_dev);
return 0;
}
postcore_initcall(dm365_init_devices);
-
-void dm365_set_vpfe_config(struct vpfe_config *cfg)
-{
- vpfe_capture_dev.dev.platform_data = cfg;
-}
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index db1dd92e00af..c2a9273330bf 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -300,8 +300,8 @@ static struct clk_lookup dm644x_clks[] = {
CLK(NULL, "dsp", &dsp_clk),
CLK(NULL, "arm", &arm_clk),
CLK(NULL, "vicp", &vicp_clk),
- CLK(NULL, "vpss_master", &vpss_master_clk),
- CLK(NULL, "vpss_slave", &vpss_slave_clk),
+ CLK("vpss", "master", &vpss_master_clk),
+ CLK("vpss", "slave", &vpss_slave_clk),
CLK(NULL, "arm", &arm_clk),
CLK(NULL, "uart0", &uart0_clk),
CLK(NULL, "uart1", &uart1_clk),
@@ -706,7 +706,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type,
v |= DM644X_VPSS_DACCLKEN;
writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
break;
- case VPBE_ENC_CUSTOM_TIMINGS:
+ case VPBE_ENC_DV_TIMINGS:
if (pclock <= 27000000) {
v |= DM644X_VPSS_DACCLKEN;
writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
@@ -901,11 +901,6 @@ int __init dm644x_init_video(struct vpfe_config *vpfe_cfg,
dm644x_vpfe_dev.dev.platform_data = vpfe_cfg;
platform_device_register(&dm644x_ccdc_dev);
platform_device_register(&dm644x_vpfe_dev);
- /* Add ccdc clock aliases */
- clk_add_alias("master", dm644x_ccdc_dev.name,
- "vpss_master", NULL);
- clk_add_alias("slave", dm644x_ccdc_dev.name,
- "vpss_slave", NULL);
}
if (vpbe_cfg) {
diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c
index c90250e3bef8..6b98413cebd6 100644
--- a/arch/arm/mach-davinci/pm_domain.c
+++ b/arch/arm/mach-davinci/pm_domain.c
@@ -53,7 +53,7 @@ static struct dev_pm_domain davinci_pm_domain = {
static struct pm_clk_notifier_block platform_bus_notifier = {
.pm_domain = &davinci_pm_domain,
- .con_ids = { "fck", NULL, },
+ .con_ids = { "fck", "master", "slave", NULL },
};
static int __init davinci_pm_runtime_init(void)
diff --git a/arch/arm/mach-ep93xx/include/mach/uncompress.h b/arch/arm/mach-ep93xx/include/mach/uncompress.h
index d2afb4dd82ab..b5cc77d2380b 100644
--- a/arch/arm/mach-ep93xx/include/mach/uncompress.h
+++ b/arch/arm/mach-ep93xx/include/mach/uncompress.h
@@ -47,9 +47,13 @@ static void __raw_writel(unsigned int value, unsigned int ptr)
static inline void putc(int c)
{
- /* Transmit fifo not full? */
- while (__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)
- ;
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ /* Transmit fifo not full? */
+ if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF))
+ break;
+ }
__raw_writeb(c, PHYS_UART_DATA);
}
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 70f94c87479d..d5dde0727339 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -72,10 +72,12 @@ config SOC_EXYNOS5440
bool "SAMSUNG EXYNOS5440"
default y
depends on ARCH_EXYNOS5
+ select ARCH_HAS_OPP
select ARM_ARCH_TIMER
select AUTO_ZRELADDR
select PINCTRL
select PINCTRL_EXYNOS5440
+ select PM_OPP
help
Enable EXYNOS5440 SoC support
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index fcfe0251aa3e..498a7a23e260 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -58,7 +58,6 @@ static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
static struct cpuidle_driver exynos4_idle_driver = {
.name = "exynos4_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
};
/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index 497fcb793dc1..d28c7fbaba2d 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -97,6 +97,19 @@ static struct s3c2410_uartcfg universal_uartcfgs[] __initdata = {
static struct regulator_consumer_supply max8952_consumer =
REGULATOR_SUPPLY("vdd_arm", NULL);
+static struct regulator_init_data universal_max8952_reg_data = {
+ .constraints = {
+ .name = "VARM_1.2V",
+ .min_uV = 770000,
+ .max_uV = 1400000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &max8952_consumer,
+};
+
static struct max8952_platform_data universal_max8952_pdata __initdata = {
.gpio_vid0 = EXYNOS4_GPX0(3),
.gpio_vid1 = EXYNOS4_GPX0(4),
@@ -105,19 +118,7 @@ static struct max8952_platform_data universal_max8952_pdata __initdata = {
.dvs_mode = { 48, 32, 28, 18 }, /* 1.25, 1.20, 1.05, 0.95V */
.sync_freq = 0, /* default: fastest */
.ramp_speed = 0, /* default: fastest */
-
- .reg_data = {
- .constraints = {
- .name = "VARM_1.2V",
- .min_uV = 770000,
- .max_uV = 1400000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
- .always_on = 1,
- .boot_on = 1,
- },
- .num_consumer_supplies = 1,
- .consumer_supplies = &max8952_consumer,
- },
+ .reg_data = &universal_max8952_reg_data,
};
static struct regulator_consumer_supply lp3974_buck1_consumer =
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index b81cc569a8dd..6af40662a449 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -204,9 +204,9 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return exynos4210_usb_phy0_init(pdev);
- else if (type == S5P_USB_PHY_HOST)
+ else if (type == USB_PHY_TYPE_HOST)
return exynos4210_usb_phy1_init(pdev);
return -EINVAL;
@@ -214,9 +214,9 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return exynos4210_usb_phy0_exit(pdev);
- else if (type == S5P_USB_PHY_HOST)
+ else if (type == USB_PHY_TYPE_HOST)
return exynos4210_usb_phy1_exit(pdev);
return -EINVAL;
diff --git a/arch/arm/mach-gemini/idle.c b/arch/arm/mach-gemini/idle.c
index 92bbd6bb600a..87dff4f5059e 100644
--- a/arch/arm/mach-gemini/idle.c
+++ b/arch/arm/mach-gemini/idle.c
@@ -13,9 +13,11 @@ static void gemini_idle(void)
* will never wakeup... Acctualy it is not very good to enable
* interrupts first since scheduler can miss a tick, but there is
* no other way around this. Platforms that needs it for power saving
- * should call enable_hlt() in init code, since by default it is
+ * should enable it in init code, since by default it is
* disabled.
*/
+
+ /* FIXME: Enabling interrupts here is racy! */
local_irq_enable();
cpu_do_idle();
}
diff --git a/arch/arm/mach-gemini/irq.c b/arch/arm/mach-gemini/irq.c
index 020852d3bdd8..6d8f6d1669ff 100644
--- a/arch/arm/mach-gemini/irq.c
+++ b/arch/arm/mach-gemini/irq.c
@@ -15,6 +15,8 @@
#include <linux/stddef.h>
#include <linux/list.h>
#include <linux/sched.h>
+#include <linux/cpu.h>
+
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/system_misc.h>
@@ -77,7 +79,7 @@ void __init gemini_init_irq(void)
* Disable the idle handler by default since it is buggy
* For more info see arch/arm/mach-gemini/idle.c
*/
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
request_resource(&iomem_resource, &irq_resource);
diff --git a/arch/arm/mach-highbank/hotplug.c b/arch/arm/mach-highbank/hotplug.c
index f30c52843396..890cae23c12a 100644
--- a/arch/arm/mach-highbank/hotplug.c
+++ b/arch/arm/mach-highbank/hotplug.c
@@ -28,13 +28,11 @@ extern void secondary_startup(void);
*/
void __ref highbank_cpu_die(unsigned int cpu)
{
- flush_cache_all();
-
highbank_set_cpu_jump(cpu, phys_to_virt(0));
- highbank_set_core_pwr();
- cpu_do_idle();
+ flush_cache_louis();
+ highbank_set_core_pwr();
- /* We should never return from idle */
- panic("highbank: cpu %d unexpectedly exit from shutdown\n", cpu);
+ while (1)
+ cpu_do_idle();
}
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index c4ce0906d76a..cb70961b6239 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
ifeq ($(CONFIG_CPU_IDLE),y)
-obj-y += cpuidle.o
+obj-$(CONFIG_SOC_IMX5) += cpuidle-imx5.o
obj-$(CONFIG_SOC_IMX6Q) += cpuidle-imx6q.o
endif
diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c
index 1ab91b5209e6..85b728cc27ab 100644
--- a/arch/arm/mach-imx/clk-busy.c
+++ b/arch/arm/mach-imx/clk-busy.c
@@ -169,7 +169,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
busy->mux.reg = reg;
busy->mux.shift = shift;
- busy->mux.width = width;
+ busy->mux.mask = BIT(width) - 1;
busy->mux.lock = &imx_ccm_lock;
busy->mux_ops = &clk_mux_ops;
diff --git a/arch/arm/mach-imx/clk-imx35.c b/arch/arm/mach-imx/clk-imx35.c
index e13a8fa5e62c..2193c834f55c 100644
--- a/arch/arm/mach-imx/clk-imx35.c
+++ b/arch/arm/mach-imx/clk-imx35.c
@@ -257,6 +257,7 @@ int __init mx35_clocks_init(void)
clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
clk_register_clkdev(clk[nfc_div], NULL, "imx25-nand.0");
clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
+ clk_register_clkdev(clk[admux_gate], "audmux", NULL);
clk_prepare_enable(clk[spba_gate]);
clk_prepare_enable(clk[gpio1_gate]);
@@ -265,6 +266,7 @@ int __init mx35_clocks_init(void)
clk_prepare_enable(clk[iim_gate]);
clk_prepare_enable(clk[emi_gate]);
clk_prepare_enable(clk[max_gate]);
+ clk_prepare_enable(clk[iomuxc_gate]);
/*
* SCC is needed to boot via mmc after a watchdog reset. The clock code
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 2f9ff93a4e61..d38e54f5b6d7 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -115,7 +115,7 @@ static const char *gpu2d_core_sels[] = { "axi", "pll3_usb_otg", "pll2_pfd0_352m"
static const char *gpu3d_core_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd2_396m", };
static const char *gpu3d_shader_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll2_pfd1_594m", "pll2_pfd9_720m", };
static const char *ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", "pll3_120m", "pll3_pfd1_540m", };
-static const char *ldb_di_sels[] = { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_pfd1_540m", };
+static const char *ldb_di_sels[] = { "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "mmdc_ch1_axi", "pll3_usb_otg", };
static const char *ipu_di_pre_sels[] = { "mmdc_ch0_axi", "pll3_usb_otg", "pll5_video", "pll2_pfd0_352m", "pll2_pfd2_396m", "pll3_pfd1_540m", };
static const char *ipu1_di0_sels[] = { "ipu1_di0_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
static const char *ipu1_di1_sels[] = { "ipu1_di1_pre", "dummy", "dummy", "ldb_di0", "ldb_di1", };
@@ -443,7 +443,6 @@ int __init mx6q_clocks_init(void)
clk_register_clkdev(clk[gpt_ipg], "ipg", "imx-gpt.0");
clk_register_clkdev(clk[gpt_ipg_per], "per", "imx-gpt.0");
- clk_register_clkdev(clk[twd], NULL, "smp_twd");
clk_register_clkdev(clk[cko1_sel], "cko1_sel", NULL);
clk_register_clkdev(clk[ahb], "ahb", NULL);
clk_register_clkdev(clk[cko1], "cko1", NULL);
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 5a800bfcec5b..5bf4a97ab241 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -110,6 +110,8 @@ void tzic_handle_irq(struct pt_regs *);
extern void imx_enable_cpu(int cpu, bool enable);
extern void imx_set_cpu_jump(int cpu, void *jump_addr);
+extern u32 imx_get_cpu_arg(int cpu);
+extern void imx_set_cpu_arg(int cpu, u32 arg);
extern void v7_cpu_resume(void);
extern u32 *pl310_get_save_ptr(void);
#ifdef CONFIG_SMP
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
index d8c75c3c925d..387dc4cceca2 100644
--- a/arch/arm/mach-imx/cpufreq.c
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -87,13 +87,12 @@ static int mxc_set_target(struct cpufreq_policy *policy,
freqs.old = clk_get_rate(cpu_clk) / 1000;
freqs.new = freq_Hz / 1000;
- freqs.cpu = 0;
freqs.flags = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
ret = set_cpu_freq(freq_Hz);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
}
@@ -145,14 +144,11 @@ static int mxc_cpufreq_init(struct cpufreq_policy *policy)
imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
policy->cur = clk_get_rate(cpu_clk) / 1000;
- policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
- policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
/* Manual states, that PLL stabilizes in two CLK32 periods */
policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
-
if (ret < 0) {
printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n",
__func__, ret);
diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c
new file mode 100644
index 000000000000..5a47e3c6172f
--- /dev/null
+++ b/arch/arm/mach-imx/cpuidle-imx5.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <asm/system_misc.h>
+
+static int imx5_cpuidle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ arm_pm_idle();
+ return index;
+}
+
+static struct cpuidle_driver imx5_cpuidle_driver = {
+ .name = "imx5_cpuidle",
+ .owner = THIS_MODULE,
+ .states[0] = {
+ .enter = imx5_cpuidle_enter,
+ .exit_latency = 2,
+ .target_residency = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "IMX5 SRPG",
+ .desc = "CPU state retained,powered off",
+ },
+ .state_count = 1,
+};
+
+int __init imx5_cpuidle_init(void)
+{
+ return cpuidle_register(&imx5_cpuidle_driver, NULL);
+}
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index d533e2695f0e..23ddfb693b2d 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -6,7 +6,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/clockchips.h>
#include <linux/cpuidle.h>
#include <linux/module.h>
#include <asm/cpuidle.h>
@@ -21,10 +20,6 @@ static DEFINE_SPINLOCK(master_lock);
static int imx6q_enter_wait(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
- int cpu = dev->cpu;
-
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
-
if (atomic_inc_return(&master) == num_online_cpus()) {
/*
* With this lock, we prevent other cpu to exit and enter
@@ -43,26 +38,13 @@ idle:
cpu_do_idle();
done:
atomic_dec(&master);
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
return index;
}
-/*
- * For each cpu, setup the broadcast timer because local timer
- * stops for the states other than WFI.
- */
-static void imx6q_setup_broadcast_timer(void *arg)
-{
- int cpu = smp_processor_id();
-
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
static struct cpuidle_driver imx6q_cpuidle_driver = {
.name = "imx6q_cpuidle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states = {
/* WFI */
ARM_CPUIDLE_WFI_STATE,
@@ -70,7 +52,8 @@ static struct cpuidle_driver imx6q_cpuidle_driver = {
{
.exit_latency = 50,
.target_residency = 75,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_TIMER_STOP,
.enter = imx6q_enter_wait,
.name = "WAIT",
.desc = "Clock off",
@@ -88,8 +71,5 @@ int __init imx6q_cpuidle_init(void)
/* Set chicken bit to get a reliable WAIT mode support */
imx6q_set_chicken_bit();
- /* Configure the broadcast timer on each cpu */
- on_each_cpu(imx6q_setup_broadcast_timer, NULL, 1);
-
- return imx_cpuidle_init(&imx6q_cpuidle_driver);
+ return cpuidle_register(&imx6q_cpuidle_driver, NULL);
}
diff --git a/arch/arm/mach-imx/cpuidle.c b/arch/arm/mach-imx/cpuidle.c
deleted file mode 100644
index d4cb511a44a8..000000000000
--- a/arch/arm/mach-imx/cpuidle.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- * Copyright 2012 Linaro Ltd.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/cpuidle.h>
-#include <linux/err.h>
-#include <linux/hrtimer.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-static struct cpuidle_device __percpu * imx_cpuidle_devices;
-
-static void __init imx_cpuidle_devices_uninit(void)
-{
- int cpu_id;
- struct cpuidle_device *dev;
-
- for_each_possible_cpu(cpu_id) {
- dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
- cpuidle_unregister_device(dev);
- }
-
- free_percpu(imx_cpuidle_devices);
-}
-
-int __init imx_cpuidle_init(struct cpuidle_driver *drv)
-{
- struct cpuidle_device *dev;
- int cpu_id, ret;
-
- if (drv->state_count > CPUIDLE_STATE_MAX) {
- pr_err("%s: state_count exceeds maximum\n", __func__);
- return -EINVAL;
- }
-
- ret = cpuidle_register_driver(drv);
- if (ret) {
- pr_err("%s: Failed to register cpuidle driver with error: %d\n",
- __func__, ret);
- return ret;
- }
-
- imx_cpuidle_devices = alloc_percpu(struct cpuidle_device);
- if (imx_cpuidle_devices == NULL) {
- ret = -ENOMEM;
- goto unregister_drv;
- }
-
- /* initialize state data for each cpuidle_device */
- for_each_possible_cpu(cpu_id) {
- dev = per_cpu_ptr(imx_cpuidle_devices, cpu_id);
- dev->cpu = cpu_id;
- dev->state_count = drv->state_count;
-
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("%s: Failed to register cpu %u, error: %d\n",
- __func__, cpu_id, ret);
- goto uninit;
- }
- }
-
- return 0;
-
-uninit:
- imx_cpuidle_devices_uninit();
-
-unregister_drv:
- cpuidle_unregister_driver(drv);
- return ret;
-}
diff --git a/arch/arm/mach-imx/cpuidle.h b/arch/arm/mach-imx/cpuidle.h
index e092d1359d94..786f98ecc145 100644
--- a/arch/arm/mach-imx/cpuidle.h
+++ b/arch/arm/mach-imx/cpuidle.h
@@ -10,18 +10,16 @@
* http://www.gnu.org/copyleft/gpl.html
*/
-#include <linux/cpuidle.h>
-
#ifdef CONFIG_CPU_IDLE
-extern int imx_cpuidle_init(struct cpuidle_driver *drv);
+extern int imx5_cpuidle_init(void);
extern int imx6q_cpuidle_init(void);
#else
-static inline int imx_cpuidle_init(struct cpuidle_driver *drv)
+static inline int imx5_cpuidle_init(void)
{
- return -ENODEV;
+ return 0;
}
static inline int imx6q_cpuidle_init(void)
{
- return -ENODEV;
+ return 0;
}
#endif
diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c
index 7bc5fe15dda2..361a253e2b63 100644
--- a/arch/arm/mach-imx/hotplug.c
+++ b/arch/arm/mach-imx/hotplug.c
@@ -46,11 +46,23 @@ static inline void cpu_enter_lowpower(void)
void imx_cpu_die(unsigned int cpu)
{
cpu_enter_lowpower();
+ /*
+ * We use the cpu jumping argument register to sync with
+ * imx_cpu_kill() which is running on cpu0 and waiting for
+ * the register being cleared to kill the cpu.
+ */
+ imx_set_cpu_arg(cpu, ~0);
cpu_do_idle();
}
int imx_cpu_kill(unsigned int cpu)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ while (imx_get_cpu_arg(cpu) == 0)
+ if (time_after(jiffies, timeout))
+ return 0;
imx_enable_cpu(cpu, false);
+ imx_set_cpu_arg(cpu, 0);
return 1;
}
diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c
index f67fd7ee8127..82e79c658eb2 100644
--- a/arch/arm/mach-imx/pm-imx5.c
+++ b/arch/arm/mach-imx/pm-imx5.c
@@ -149,33 +149,6 @@ static void imx5_pm_idle(void)
imx5_cpu_do_idle();
}
-static int imx5_cpuidle_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int idx)
-{
- int ret;
-
- ret = imx5_cpu_do_idle();
- if (ret < 0)
- return ret;
-
- return idx;
-}
-
-static struct cpuidle_driver imx5_cpuidle_driver = {
- .name = "imx5_cpuidle",
- .owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
- .states[0] = {
- .enter = imx5_cpuidle_enter,
- .exit_latency = 2,
- .target_residency = 1,
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .name = "IMX5 SRPG",
- .desc = "CPU state retained,powered off",
- },
- .state_count = 1,
-};
-
static int __init imx5_pm_common_init(void)
{
int ret;
@@ -193,8 +166,7 @@ static int __init imx5_pm_common_init(void)
/* Set the registers to the default cpu idle state. */
mx5_cpu_lp_set(IMX5_DEFAULT_CPU_IDLE_STATE);
- imx_cpuidle_init(&imx5_cpuidle_driver);
- return 0;
+ return imx5_cpuidle_init();
}
void __init imx51_pm_init(void)
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
index e15f1555c59b..09a742f8c7ab 100644
--- a/arch/arm/mach-imx/src.c
+++ b/arch/arm/mach-imx/src.c
@@ -43,6 +43,18 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
src_base + SRC_GPR1 + cpu * 8);
}
+u32 imx_get_cpu_arg(int cpu)
+{
+ cpu = cpu_logical_map(cpu);
+ return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
+}
+
+void imx_set_cpu_arg(int cpu, u32 arg)
+{
+ cpu = cpu_logical_map(cpu);
+ writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
+}
+
void imx_src_prepare_restart(void)
{
u32 val;
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
index 5521d18bf19a..d14d6b76f4c2 100644
--- a/arch/arm/mach-integrator/Makefile
+++ b/arch/arm/mach-integrator/Makefile
@@ -9,5 +9,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
obj-$(CONFIG_PCI) += pci_v3.o pci.o
-obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o
obj-$(CONFIG_INTEGRATOR_IMPD1) += impd1.o
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 1dbeb7c99d58..6600cff6bd92 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/export.h>
#include <linux/gpio.h>
+#include <linux/cpu.h>
#include <mach/udc.h>
#include <mach/hardware.h>
@@ -239,7 +240,7 @@ void __init ixp4xx_init_irq(void)
* ixp4xx does not implement the XScale PWRMODE register
* so it must not call cpu_do_idle().
*/
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
/* Route all sources to IRQ instead of FIQ */
*IXP4XX_ICLR = 0x0;
diff --git a/arch/arm/mach-kirkwood/board-iomega_ix2_200.c b/arch/arm/mach-kirkwood/board-iomega_ix2_200.c
index f655b2637b0e..e5f70415905a 100644
--- a/arch/arm/mach-kirkwood/board-iomega_ix2_200.c
+++ b/arch/arm/mach-kirkwood/board-iomega_ix2_200.c
@@ -20,10 +20,15 @@ static struct mv643xx_eth_platform_data iomega_ix2_200_ge00_data = {
.duplex = DUPLEX_FULL,
};
+static struct mv643xx_eth_platform_data iomega_ix2_200_ge01_data = {
+ .phy_addr = MV643XX_ETH_PHY_ADDR(11),
+};
+
void __init iomega_ix2_200_init(void)
{
/*
* Basic setup. Needs to be called early.
*/
- kirkwood_ge01_init(&iomega_ix2_200_ge00_data);
+ kirkwood_ge00_init(&iomega_ix2_200_ge00_data);
+ kirkwood_ge01_init(&iomega_ix2_200_ge01_data);
}
diff --git a/arch/arm/mach-kirkwood/guruplug-setup.c b/arch/arm/mach-kirkwood/guruplug-setup.c
index 1c6e736cbbf8..08dd739aa709 100644
--- a/arch/arm/mach-kirkwood/guruplug-setup.c
+++ b/arch/arm/mach-kirkwood/guruplug-setup.c
@@ -53,6 +53,8 @@ static struct mv_sata_platform_data guruplug_sata_data = {
static struct mvsdio_platform_data guruplug_mvsdio_data = {
/* unfortunately the CD signal has not been connected */
+ .gpio_card_detect = -1,
+ .gpio_write_protect = -1,
};
static struct gpio_led guruplug_led_pins[] = {
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index 8ddd69fdc937..6a6eb548307d 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -55,6 +55,7 @@ static struct mv_sata_platform_data openrd_sata_data = {
static struct mvsdio_platform_data openrd_mvsdio_data = {
.gpio_card_detect = 29, /* MPP29 used as SD card detect */
+ .gpio_write_protect = -1,
};
static unsigned int openrd_mpp_config[] __initdata = {
diff --git a/arch/arm/mach-kirkwood/rd88f6281-setup.c b/arch/arm/mach-kirkwood/rd88f6281-setup.c
index c7d93b48926b..d24223166e06 100644
--- a/arch/arm/mach-kirkwood/rd88f6281-setup.c
+++ b/arch/arm/mach-kirkwood/rd88f6281-setup.c
@@ -69,6 +69,7 @@ static struct mv_sata_platform_data rd88f6281_sata_data = {
static struct mvsdio_platform_data rd88f6281_mvsdio_data = {
.gpio_card_detect = 28,
+ .gpio_write_protect = -1,
};
static unsigned int rd88f6281_mpp_config[] __initdata = {
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 9f64d5632e07..76901f4ce611 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -223,13 +223,7 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
};
#if defined(CONFIG_USB_EHCI_MV)
-static char *pxa168_sph_clock_name[] = {
- [0] = "PXA168-USBCLK",
-};
-
static struct mv_usb_platform_data pxa168_sph_pdata = {
- .clknum = 1,
- .clkname = pxa168_sph_clock_name,
.mode = MV_USB_MODE_HOST,
.phy_init = pxa_usb_phy_init,
.phy_deinit = pxa_usb_phy_deinit,
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 22a9058f9f4d..6528a5fa6a26 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -162,13 +162,7 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
#ifdef CONFIG_USB_SUPPORT
#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
-static char *pxa910_usb_clock_name[] = {
- [0] = "U2OCLK",
-};
-
static struct mv_usb_platform_data ttc_usb_pdata = {
- .clknum = 1,
- .clkname = pxa910_usb_clock_name,
.vbus = NULL,
.mode = MV_USB_MODE_OTG,
.otg_force_a_bus_req = 1,
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 2969027f02fa..f9fd77e8f1f5 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -62,7 +62,10 @@ static int msm_timer_set_next_event(unsigned long cycles,
{
u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
- writel_relaxed(0, event_base + TIMER_CLEAR);
+ ctrl &= ~TIMER_ENABLE_EN;
+ writel_relaxed(ctrl, event_base + TIMER_ENABLE);
+
+ writel_relaxed(ctrl, event_base + TIMER_CLEAR);
writel_relaxed(cycles, event_base + TIMER_MATCH_VAL);
writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE);
return 0;
diff --git a/arch/arm/mach-mvebu/irq-armada-370-xp.c b/arch/arm/mach-mvebu/irq-armada-370-xp.c
index 274ff58271de..830139a3e2ba 100644
--- a/arch/arm/mach-mvebu/irq-armada-370-xp.c
+++ b/arch/arm/mach-mvebu/irq-armada-370-xp.c
@@ -44,6 +44,8 @@
#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
+#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5)
+
#define ACTIVE_DOORBELLS (8)
static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -55,40 +57,30 @@ static struct irq_domain *armada_370_xp_mpic_domain;
/*
* In SMP mode:
* For shared global interrupts, mask/unmask global enable bit
- * For CPU interrtups, mask/unmask the calling CPU's bit
+ * For CPU interrupts, mask/unmask the calling CPU's bit
*/
static void armada_370_xp_irq_mask(struct irq_data *d)
{
-#ifdef CONFIG_SMP
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
+ if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
writel(hwirq, main_int_base +
ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
else
writel(hwirq, per_cpu_int_base +
ARMADA_370_XP_INT_SET_MASK_OFFS);
-#else
- writel(irqd_to_hwirq(d),
- per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
-#endif
}
static void armada_370_xp_irq_unmask(struct irq_data *d)
{
-#ifdef CONFIG_SMP
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
+ if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
writel(hwirq, main_int_base +
ARMADA_370_XP_INT_SET_ENABLE_OFFS);
else
writel(hwirq, per_cpu_int_base +
ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
-#else
- writel(irqd_to_hwirq(d),
- per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
-#endif
}
#ifdef CONFIG_SMP
@@ -144,10 +136,14 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
unsigned int virq, irq_hw_number_t hw)
{
armada_370_xp_irq_mask(irq_get_irq_data(virq));
- writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
+ if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
+ writel(hw, per_cpu_int_base +
+ ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+ else
+ writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
irq_set_status_flags(virq, IRQ_LEVEL);
- if (hw < ARMADA_370_XP_MAX_PER_CPU_IRQS) {
+ if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) {
irq_set_percpu_devid(virq);
irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
handle_percpu_devid_irq);
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
index cb7c6ae2e3fc..6c4f766365a2 100644
--- a/arch/arm/mach-omap1/clock_data.c
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -543,15 +543,6 @@ static struct clk usb_dc_ck = {
/* Direct from ULPD, no parent */
.rate = 48000000,
.enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
- .enable_bit = USB_REQ_EN_SHIFT,
-};
-
-static struct clk usb_dc_ck7xx = {
- .name = "usb_dc_ck",
- .ops = &clkops_generic,
- /* Direct from ULPD, no parent */
- .rate = 48000000,
- .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
.enable_bit = SOFT_USB_OTG_DPLL_REQ_SHIFT,
};
@@ -727,8 +718,7 @@ static struct omap_clk omap_clks[] = {
CLK(NULL, "usb_clko", &usb_clko, CK_16XX | CK_1510 | CK_310),
CLK(NULL, "usb_hhc_ck", &usb_hhc_ck1510, CK_1510 | CK_310),
CLK(NULL, "usb_hhc_ck", &usb_hhc_ck16xx, CK_16XX),
- CLK(NULL, "usb_dc_ck", &usb_dc_ck, CK_16XX),
- CLK(NULL, "usb_dc_ck", &usb_dc_ck7xx, CK_7XX),
+ CLK(NULL, "usb_dc_ck", &usb_dc_ck, CK_16XX | CK_7XX),
CLK(NULL, "mclk", &mclk_1510, CK_1510 | CK_310),
CLK(NULL, "mclk", &mclk_16xx, CK_16XX),
CLK(NULL, "bclk", &bclk_1510, CK_1510 | CK_310),
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index ff72d297a172..dd712f109738 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -44,6 +44,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/atomic.h>
+#include <linux/cpu.h>
#include <asm/fncpy.h>
#include <asm/system_misc.h>
@@ -580,8 +581,7 @@ static void omap_pm_init_debugfs(void)
static int omap_pm_prepare(void)
{
/* We cannot sleep in idle until we have resumed */
- disable_hlt();
-
+ cpu_idle_poll_ctrl(true);
return 0;
}
@@ -617,7 +617,7 @@ static int omap_pm_enter(suspend_state_t state)
static void omap_pm_finish(void)
{
- enable_hlt();
+ cpu_idle_poll_ctrl(false);
}
diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c
index 3d58f335f173..0c6834ae1fc4 100644
--- a/arch/arm/mach-omap2/cclock44xx_data.c
+++ b/arch/arm/mach-omap2/cclock44xx_data.c
@@ -52,6 +52,13 @@
*/
#define OMAP4_DPLL_ABE_DEFFREQ 98304000
+/*
+ * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section
+ * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred
+ * locked frequency for the USB DPLL is 960MHz.
+ */
+#define OMAP4_DPLL_USB_DEFFREQ 960000000
+
/* Root clocks */
DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0);
@@ -1011,6 +1018,10 @@ DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK,
hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
+DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0,
+ OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+ OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL);
+
DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0,
OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
@@ -1538,6 +1549,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "per_mcbsp4_gfclk", &per_mcbsp4_gfclk, CK_443X),
CLK(NULL, "hsmmc1_fclk", &hsmmc1_fclk, CK_443X),
CLK(NULL, "hsmmc2_fclk", &hsmmc2_fclk, CK_443X),
+ CLK(NULL, "ocp2scp_usb_phy_phy_48m", &ocp2scp_usb_phy_phy_48m, CK_443X),
CLK(NULL, "sha2md5_fck", &sha2md5_fck, CK_443X),
CLK(NULL, "slimbus1_fclk_1", &slimbus1_fclk_1, CK_443X),
CLK(NULL, "slimbus1_fclk_0", &slimbus1_fclk_0, CK_443X),
@@ -1705,5 +1717,13 @@ int __init omap4xxx_clk_init(void)
if (rc)
pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+ /*
+ * Lock USB DPLL on OMAP4 devices so that the L3INIT power
+ * domain can transition to retention state when not in use.
+ */
+ rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ);
+ if (rc)
+ pr_err("%s: failed to configure USB DPLL!\n", __func__);
+
return 0;
}
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 40f4a03d728f..14522d077c88 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -249,7 +249,6 @@ extern int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state);
extern int omap4_finish_suspend(unsigned long cpu_state);
extern void omap4_cpu_resume(void);
extern int omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state);
-extern u32 omap4_mpuss_read_prev_context_state(void);
#else
static inline int omap4_enter_lowpower(unsigned int cpu,
unsigned int power_state)
@@ -277,10 +276,6 @@ static inline int omap4_finish_suspend(unsigned long cpu_state)
static inline void omap4_cpu_resume(void)
{}
-static inline u32 omap4_mpuss_read_prev_context_state(void)
-{
- return 0;
-}
#endif
struct omap_sdrc_params;
@@ -293,5 +288,8 @@ extern void omap_reserve(void);
struct omap_hwmod;
extern int omap_dss_reset(struct omap_hwmod *);
+/* SoC specific clock initializer */
+extern int (*omap_clk_init)(void);
+
#endif /* __ASSEMBLER__ */
#endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 80392fca86c6..cca045c95fbf 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -26,6 +26,7 @@
#include <linux/cpuidle.h>
#include <linux/export.h>
#include <linux/cpu_pm.h>
+#include <asm/cpuidle.h>
#include "powerdomain.h"
#include "clockdomain.h"
@@ -99,11 +100,15 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
},
};
-/* Private functions */
-
-static int __omap3_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+/**
+ * omap3_enter_idle - Programs OMAP3 to enter the specified state
+ * @dev: cpuidle device
+ * @drv: cpuidle driver
+ * @index: the index of state to be entered
+ */
+static int omap3_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
{
struct omap3_idle_statedata *cx = &omap3_idle_data[index];
@@ -149,22 +154,6 @@ return_sleep_time:
}
/**
- * omap3_enter_idle - Programs OMAP3 to enter the specified state
- * @dev: cpuidle device
- * @drv: cpuidle driver
- * @index: the index of state to be entered
- *
- * Called from the CPUidle framework to program the device to the
- * specified target state selected by the governor.
- */
-static inline int omap3_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
-{
- return cpuidle_wrap_enter(dev, drv, index, __omap3_enter_idle);
-}
-
-/**
* next_valid_state - Find next valid C-state
* @dev: cpuidle device
* @drv: cpuidle driver
@@ -271,11 +260,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
return ret;
}
-static DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
-
static struct cpuidle_driver omap3_idle_driver = {
- .name = "omap3_idle",
- .owner = THIS_MODULE,
+ .name = "omap3_idle",
+ .owner = THIS_MODULE,
.states = {
{
.enter = omap3_enter_idle_bm,
@@ -348,8 +335,6 @@ static struct cpuidle_driver omap3_idle_driver = {
*/
int __init omap3_idle_init(void)
{
- struct cpuidle_device *dev;
-
mpu_pd = pwrdm_lookup("mpu_pwrdm");
core_pd = pwrdm_lookup("core_pwrdm");
per_pd = pwrdm_lookup("per_pwrdm");
@@ -358,16 +343,5 @@ int __init omap3_idle_init(void)
if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
return -ENODEV;
- cpuidle_register_driver(&omap3_idle_driver);
-
- dev = &per_cpu(omap3_idle_dev, smp_processor_id());
- dev->cpu = 0;
-
- if (cpuidle_register_device(dev)) {
- printk(KERN_ERR "%s: CPUidle register device failed\n",
- __func__);
- return -EIO;
- }
-
- return 0;
+ return cpuidle_register(&omap3_idle_driver, NULL);
}
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index d639aef0deda..5a286b56205e 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -1,7 +1,7 @@
/*
- * OMAP4 CPU idle Routines
+ * OMAP4+ CPU idle Routines
*
- * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011-2013 Texas Instruments, Inc.
* Santosh Shilimkar <santosh.shilimkar@ti.com>
* Rajendra Nayak <rnayak@ti.com>
*
@@ -14,8 +14,8 @@
#include <linux/cpuidle.h>
#include <linux/cpu_pm.h>
#include <linux/export.h>
-#include <linux/clockchips.h>
+#include <asm/cpuidle.h>
#include <asm/proc-fns.h>
#include "common.h"
@@ -24,13 +24,13 @@
#include "clockdomain.h"
/* Machine specific information */
-struct omap4_idle_statedata {
+struct idle_statedata {
u32 cpu_state;
u32 mpu_logic_state;
u32 mpu_state;
};
-static struct omap4_idle_statedata omap4_idle_data[] = {
+static struct idle_statedata omap4_idle_data[] = {
{
.cpu_state = PWRDM_POWER_ON,
.mpu_state = PWRDM_POWER_ON,
@@ -53,11 +53,12 @@ static struct clockdomain *cpu_clkdm[NR_CPUS];
static atomic_t abort_barrier;
static bool cpu_done[NR_CPUS];
+static struct idle_statedata *state_ptr = &omap4_idle_data[0];
/* Private functions */
/**
- * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions
+ * omap_enter_idle_[simple/coupled] - OMAP4PLUS cpuidle entry functions
* @dev: cpuidle device
* @drv: cpuidle driver
* @index: the index of state to be entered
@@ -66,7 +67,7 @@ static bool cpu_done[NR_CPUS];
* specified low power state selected by the governor.
* Returns the amount of time spent in the low power state.
*/
-static int omap4_enter_idle_simple(struct cpuidle_device *dev,
+static int omap_enter_idle_simple(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
@@ -77,12 +78,11 @@ static int omap4_enter_idle_simple(struct cpuidle_device *dev,
return index;
}
-static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
+static int omap_enter_idle_coupled(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct omap4_idle_statedata *cx = &omap4_idle_data[index];
- int cpu_id = smp_processor_id();
+ struct idle_statedata *cx = state_ptr + index;
local_fiq_disable();
@@ -109,8 +109,6 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
}
}
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id);
-
/*
* Call idle CPU PM enter notifier chain so that
* VFP and per CPU interrupt context is saved.
@@ -149,11 +147,10 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev,
* Call idle CPU cluster PM exit notifier chain
* to restore GIC and wakeupgen context.
*/
- if (omap4_mpuss_read_prev_context_state())
+ if ((cx->mpu_state == PWRDM_POWER_RET) &&
+ (cx->mpu_logic_state == PWRDM_POWER_OFF))
cpu_cluster_pm_exit();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
-
fail:
cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
cpu_done[dev->cpu] = false;
@@ -163,49 +160,38 @@ fail:
return index;
}
-/*
- * For each cpu, setup the broadcast timer because local timers
- * stops for the states above C1.
- */
-static void omap_setup_broadcast_timer(void *arg)
-{
- int cpu = smp_processor_id();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
-static DEFINE_PER_CPU(struct cpuidle_device, omap4_idle_dev);
-
static struct cpuidle_driver omap4_idle_driver = {
.name = "omap4_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states = {
{
/* C1 - CPU0 ON + CPU1 ON + MPU ON */
.exit_latency = 2 + 2,
.target_residency = 5,
.flags = CPUIDLE_FLAG_TIME_VALID,
- .enter = omap4_enter_idle_simple,
+ .enter = omap_enter_idle_simple,
.name = "C1",
- .desc = "MPUSS ON"
+ .desc = "CPUx ON, MPUSS ON"
},
{
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
.exit_latency = 328 + 440,
.target_residency = 960,
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
- .enter = omap4_enter_idle_coupled,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
+ CPUIDLE_FLAG_TIMER_STOP,
+ .enter = omap_enter_idle_coupled,
.name = "C2",
- .desc = "MPUSS CSWR",
+ .desc = "CPUx OFF, MPUSS CSWR",
},
{
/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
.exit_latency = 460 + 518,
.target_residency = 1100,
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
- .enter = omap4_enter_idle_coupled,
+ .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
+ CPUIDLE_FLAG_TIMER_STOP,
+ .enter = omap_enter_idle_coupled,
.name = "C3",
- .desc = "MPUSS OSWR",
+ .desc = "CPUx OFF, MPUSS OSWR",
},
},
.state_count = ARRAY_SIZE(omap4_idle_data),
@@ -215,16 +201,13 @@ static struct cpuidle_driver omap4_idle_driver = {
/* Public functions */
/**
- * omap4_idle_init - Init routine for OMAP4 idle
+ * omap4_idle_init - Init routine for OMAP4+ idle
*
- * Registers the OMAP4 specific cpuidle driver to the cpuidle
+ * Registers the OMAP4+ specific cpuidle driver to the cpuidle
* framework with the valid set of states.
*/
int __init omap4_idle_init(void)
{
- struct cpuidle_device *dev;
- unsigned int cpu_id = 0;
-
mpu_pd = pwrdm_lookup("mpu_pwrdm");
cpu_pd[0] = pwrdm_lookup("cpu0_pwrdm");
cpu_pd[1] = pwrdm_lookup("cpu1_pwrdm");
@@ -236,22 +219,5 @@ int __init omap4_idle_init(void)
if (!cpu_clkdm[0] || !cpu_clkdm[1])
return -ENODEV;
- /* Configure the broadcast timer on each cpu */
- on_each_cpu(omap_setup_broadcast_timer, NULL, 1);
-
- for_each_cpu(cpu_id, cpu_online_mask) {
- dev = &per_cpu(omap4_idle_dev, cpu_id);
- dev->cpu = cpu_id;
-#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
- dev->coupled_cpus = *cpu_online_mask;
-#endif
- cpuidle_register_driver(&omap4_idle_driver);
-
- if (cpuidle_register_device(dev)) {
- pr_err("%s: CPUidle register failed\n", __func__);
- return -EIO;
- }
- }
-
- return 0;
+ return cpuidle_register(&omap4_idle_driver, cpu_online_mask);
}
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 2c3fdd65387b..5c445ca1e271 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -55,6 +55,12 @@
#include "prm44xx.h"
/*
+ * omap_clk_init: points to a function that does the SoC-specific
+ * clock initializations
+ */
+int (*omap_clk_init)(void);
+
+/*
* The machine specific code may provide the extra mapping besides the
* default mapping provided here.
*/
@@ -397,7 +403,7 @@ void __init omap2420_init_early(void)
omap242x_clockdomains_init();
omap2420_hwmod_init();
omap_hwmod_init_postsetup();
- omap2420_clk_init();
+ omap_clk_init = omap2420_clk_init;
}
void __init omap2420_init_late(void)
@@ -427,7 +433,7 @@ void __init omap2430_init_early(void)
omap243x_clockdomains_init();
omap2430_hwmod_init();
omap_hwmod_init_postsetup();
- omap2430_clk_init();
+ omap_clk_init = omap2430_clk_init;
}
void __init omap2430_init_late(void)
@@ -462,7 +468,7 @@ void __init omap3_init_early(void)
omap3xxx_clockdomains_init();
omap3xxx_hwmod_init();
omap_hwmod_init_postsetup();
- omap3xxx_clk_init();
+ omap_clk_init = omap3xxx_clk_init;
}
void __init omap3430_init_early(void)
@@ -500,7 +506,7 @@ void __init ti81xx_init_early(void)
omap3xxx_clockdomains_init();
omap3xxx_hwmod_init();
omap_hwmod_init_postsetup();
- omap3xxx_clk_init();
+ omap_clk_init = omap3xxx_clk_init;
}
void __init omap3_init_late(void)
@@ -568,7 +574,7 @@ void __init am33xx_init_early(void)
am33xx_clockdomains_init();
am33xx_hwmod_init();
omap_hwmod_init_postsetup();
- am33xx_clk_init();
+ omap_clk_init = am33xx_clk_init;
}
#endif
@@ -593,7 +599,7 @@ void __init omap4430_init_early(void)
omap44xx_clockdomains_init();
omap44xx_hwmod_init();
omap_hwmod_init_postsetup();
- omap4xxx_clk_init();
+ omap_clk_init = omap4xxx_clk_init;
}
void __init omap4430_init_late(void)
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 8bcb64bcdcdb..e80327b6c81f 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -139,20 +139,6 @@ static inline void cpu_clear_prev_logic_pwrst(unsigned int cpu_id)
}
}
-/**
- * omap4_mpuss_read_prev_context_state:
- * Function returns the MPUSS previous context state
- */
-u32 omap4_mpuss_read_prev_context_state(void)
-{
- u32 reg;
-
- reg = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
- OMAP4430_PRM_MPU_INST, OMAP4_RM_MPU_MPU_CONTEXT_OFFSET);
- reg &= OMAP4430_LOSTCONTEXT_DFF_MASK;
- return reg;
-}
-
/*
* Store the CPU cluster state for L2X0 low power operations.
*/
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index c2c798c08c2b..e512253601c8 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -138,6 +138,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
+#include <linux/cpu.h>
#include <asm/system_misc.h>
@@ -1368,7 +1369,9 @@ static void _enable_sysc(struct omap_hwmod *oh)
}
if (sf & SYSC_HAS_MIDLEMODE) {
- if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+ if (oh->flags & HWMOD_FORCE_MSTANDBY) {
+ idlemode = HWMOD_IDLEMODE_FORCE;
+ } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
idlemode = HWMOD_IDLEMODE_NO;
} else {
if (sf & SYSC_HAS_ENAWAKEUP)
@@ -1440,7 +1443,8 @@ static void _idle_sysc(struct omap_hwmod *oh)
}
if (sf & SYSC_HAS_MIDLEMODE) {
- if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+ if ((oh->flags & HWMOD_SWSUP_MSTANDBY) ||
+ (oh->flags & HWMOD_FORCE_MSTANDBY)) {
idlemode = HWMOD_IDLEMODE_FORCE;
} else {
if (sf & SYSC_HAS_ENAWAKEUP)
@@ -2154,7 +2158,7 @@ static int _enable(struct omap_hwmod *oh)
if (soc_ops.enable_module)
soc_ops.enable_module(oh);
if (oh->flags & HWMOD_BLOCK_WFI)
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
if (soc_ops.update_context_lost)
soc_ops.update_context_lost(oh);
@@ -2218,7 +2222,7 @@ static int _idle(struct omap_hwmod *oh)
_del_initiator_dep(oh, mpu_oh);
if (oh->flags & HWMOD_BLOCK_WFI)
- enable_hlt();
+ cpu_idle_poll_ctrl(false);
if (soc_ops.disable_module)
soc_ops.disable_module(oh);
@@ -2328,7 +2332,7 @@ static int _shutdown(struct omap_hwmod *oh)
_del_initiator_dep(oh, mpu_oh);
/* XXX what about the other system initiators here? dma, dsp */
if (oh->flags & HWMOD_BLOCK_WFI)
- enable_hlt();
+ cpu_idle_poll_ctrl(false);
if (soc_ops.disable_module)
soc_ops.disable_module(oh);
_disable_clocks(oh);
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index d43d9b608eda..d5dc935f6060 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -427,8 +427,8 @@ struct omap_hwmod_omap4_prcm {
*
* HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out
* of idle, rather than relying on module smart-idle
- * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out
- * of standby, rather than relying on module smart-standby
+ * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and
+ * out of standby, rather than relying on module smart-standby
* HWMOD_INIT_NO_RESET: don't reset this module at boot - important for
* SDRAM controller, etc. XXX probably belongs outside the main hwmod file
* XXX Should be HWMOD_SETUP_NO_RESET
@@ -459,6 +459,10 @@ struct omap_hwmod_omap4_prcm {
* correctly, or this is being abused to deal with some PM latency
* issues -- but we're currently suffering from a shortage of
* folks who are able to track these issues down properly.
+ * HWMOD_FORCE_MSTANDBY: Always keep MIDLEMODE bits cleared so that device
+ * is kept in force-standby mode. Failing to do so causes PM problems
+ * with musb on OMAP3630 at least. Note that musb has a dedicated register
+ * to control MSTANDBY signal when MIDLEMODE is set to force-standby.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -471,6 +475,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_16BIT_REG (1 << 8)
#define HWMOD_EXT_OPT_MAIN_CLK (1 << 9)
#define HWMOD_BLOCK_WFI (1 << 10)
+#define HWMOD_FORCE_MSTANDBY (1 << 11)
/*
* omap_hwmod._int_flags definitions
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index ac7e03ec952f..5112d04e7b79 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -1707,9 +1707,14 @@ static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
* Erratum ID: i479 idle_req / idle_ack mechanism potentially
* broken when autoidle is enabled
* workaround is to disable the autoidle bit at module level.
+ *
+ * Enabling the device in any other MIDLEMODE setting but force-idle
+ * causes core_pwrdm not enter idle states at least on OMAP3630.
+ * Note that musb has OTG_FORCESTDBY register that controls MSTANDBY
+ * signal when MIDLEMODE is set to force-idle.
*/
.flags = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
- | HWMOD_SWSUP_MSTANDBY,
+ | HWMOD_FORCE_MSTANDBY,
};
/* usb_otg_hs */
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 0e47d2e1687c..eaba9dc91a0d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -2719,7 +2719,17 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
.name = "ocp2scp_usb_phy",
.class = &omap44xx_ocp2scp_hwmod_class,
.clkdm_name = "l3_init_clkdm",
- .main_clk = "func_48m_fclk",
+ /*
+ * ocp2scp_usb_phy_phy_48m is provided by the OMAP4 PRCM IP
+ * block as an "optional clock," and normally should never be
+ * specified as the main_clk for an OMAP IP block. However it
+ * turns out that this clock is actually the main clock for
+ * the ocp2scp_usb_phy IP block:
+ * http://lists.infradead.org/pipermail/linux-arm-kernel/2012-September/119943.html
+ * So listing ocp2scp_usb_phy_phy_48m as a main_clk here seems
+ * to be the best workaround.
+ */
+ .main_clk = "ocp2scp_usb_phy_phy_48m",
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET,
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 673a4c1d1d76..e742118fcfd2 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -218,7 +218,7 @@ static int omap_pm_enter(suspend_state_t suspend_state)
static int omap_pm_begin(suspend_state_t state)
{
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
if (cpu_is_omap34xx())
omap_prcm_irq_prepare();
return 0;
@@ -226,8 +226,7 @@ static int omap_pm_begin(suspend_state_t state)
static void omap_pm_end(void)
{
- enable_hlt();
- return;
+ cpu_idle_poll_ctrl(false);
}
static void omap_pm_finish(void)
@@ -265,6 +264,12 @@ static void __init omap4_init_voltages(void)
omap2_set_init_voltage("iva", "dpll_iva_m5x2_ck", "iva");
}
+static inline void omap_init_cpufreq(void)
+{
+ struct platform_device_info devinfo = { .name = "omap-cpufreq", };
+ platform_device_register_full(&devinfo);
+}
+
static int __init omap2_common_pm_init(void)
{
if (!of_have_populated_dt())
@@ -294,6 +299,9 @@ int __init omap2_common_pm_late_init(void)
/* Smartreflex device init */
omap_devinit_smartreflex();
+
+ /* cpufreq dummy device instantiation */
+ omap_init_cpufreq();
}
#ifdef CONFIG_SUSPEND
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index ea62e75ef21d..152a10cf4f1d 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -126,8 +126,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
* omap_default_idle - OMAP4 default ilde routine.'
*
* Implements OMAP4 memory, IO ordering requirements which can't be addressed
- * with default cpu_do_idle() hook. Used by all CPUs with !CONFIG_CPUIDLE and
- * by secondary CPU with CONFIG_CPUIDLE.
+ * with default cpu_do_idle() hook. Used by all CPUs with !CONFIG_CPU_IDLE and
+ * by secondary CPU with CONFIG_CPU_IDLE.
*/
static void omap_default_idle(void)
{
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 2bdd4cf17a8f..f62b509ed08d 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -547,6 +547,8 @@ static inline void __init realtime_counter_init(void)
clksrc_nr, clksrc_src) \
void __init omap##name##_gptimer_timer_init(void) \
{ \
+ if (omap_clk_init) \
+ omap_clk_init(); \
omap_dmtimer_init(); \
omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src); \
@@ -556,6 +558,8 @@ void __init omap##name##_gptimer_timer_init(void) \
clksrc_nr, clksrc_src) \
void __init omap##name##_sync32k_timer_init(void) \
{ \
+ if (omap_clk_init) \
+ omap_clk_init(); \
omap_dmtimer_init(); \
omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
/* Enable the use of clocksource="gp_timer" kernel parameter */ \
diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c
index 35a8014529ca..94fbb815680c 100644
--- a/arch/arm/mach-orion5x/board-dt.c
+++ b/arch/arm/mach-orion5x/board-dt.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/cpu.h>
#include <asm/system_misc.h>
#include <asm/mach/arch.h>
#include <mach/orion5x.h>
@@ -52,7 +53,7 @@ static void __init orion5x_dt_init(void)
*/
if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {
printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n");
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
}
if (of_machine_is_compatible("lacie,ethernet-disk-mini-v2"))
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index d068f1431c40..ad71c8a03ffd 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -293,7 +293,7 @@ void __init orion5x_init(void)
*/
if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {
printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n");
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
}
/*
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 12c500558387..648867a8caa8 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -7,12 +7,6 @@ obj-y += clock.o devices.o generic.o irq.o \
time.o reset.o
obj-$(CONFIG_PM) += pm.o sleep.o standby.o
-ifeq ($(CONFIG_CPU_FREQ),y)
-obj-$(CONFIG_PXA25x) += cpufreq-pxa2xx.o
-obj-$(CONFIG_PXA27x) += cpufreq-pxa2xx.o
-obj-$(CONFIG_PXA3xx) += cpufreq-pxa3xx.o
-endif
-
# Generic drivers that other drivers may depend upon
# SoC-specific code
diff --git a/arch/arm/mach-pxa/include/mach/generic.h b/arch/arm/mach-pxa/include/mach/generic.h
new file mode 100644
index 000000000000..665542e0c9e2
--- /dev/null
+++ b/arch/arm/mach-pxa/include/mach/generic.h
@@ -0,0 +1 @@
+#include "../../generic.h"
diff --git a/arch/arm/mach-s3c24xx/clock-s3c2440.c b/arch/arm/mach-s3c24xx/clock-s3c2440.c
index 04b87ec92537..1069b5680826 100644
--- a/arch/arm/mach-s3c24xx/clock-s3c2440.c
+++ b/arch/arm/mach-s3c24xx/clock-s3c2440.c
@@ -123,6 +123,11 @@ static struct clk s3c2440_clk_ac97 = {
.ctrlbit = S3C2440_CLKCON_AC97,
};
+#define S3C24XX_VA_UART0 (S3C_VA_UART)
+#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 )
+#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 )
+#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 )
+
static unsigned long s3c2440_fclk_n_getrate(struct clk *clk)
{
unsigned long ucon0, ucon1, ucon2, divisor;
diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c
index 6bcf87f65f9e..92e609440c57 100644
--- a/arch/arm/mach-s3c24xx/common.c
+++ b/arch/arm/mach-s3c24xx/common.c
@@ -239,6 +239,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
/* Serial port registrations */
+#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
+#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
+#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 )
+#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 )
+
static struct resource s3c2410_uart0_resource[] = {
[0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K),
[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \
diff --git a/arch/arm/mach-s3c24xx/cpufreq.c b/arch/arm/mach-s3c24xx/cpufreq.c
index 5f181e733eee..3c0e78ede0da 100644
--- a/arch/arm/mach-s3c24xx/cpufreq.c
+++ b/arch/arm/mach-s3c24xx/cpufreq.c
@@ -204,7 +204,6 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
freqs.old = cpu_cur.freq;
freqs.new = cpu_new.freq;
- freqs.freqs.cpu = 0;
freqs.freqs.old = cpu_cur.freq.armclk / 1000;
freqs.freqs.new = cpu_new.freq.armclk / 1000;
@@ -218,9 +217,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
/* start the frequency change */
-
- if (policy)
- cpufreq_notify_transition(&freqs.freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_PRECHANGE);
/* If hclk is staying the same, then we do not need to
* re-write the IO or the refresh timings whilst we are changing
@@ -264,8 +261,7 @@ static int s3c_cpufreq_settarget(struct cpufreq_policy *policy,
local_irq_restore(flags);
/* notify everyone we've done this */
- if (policy)
- cpufreq_notify_transition(&freqs.freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs.freqs, CPUFREQ_POSTCHANGE);
s3c_freq_dbg("%s: finished\n", __func__);
return 0;
diff --git a/arch/arm/mach-s3c24xx/include/mach/irqs.h b/arch/arm/mach-s3c24xx/include/mach/irqs.h
index b7a9f4d469e8..1e73f5fa8659 100644
--- a/arch/arm/mach-s3c24xx/include/mach/irqs.h
+++ b/arch/arm/mach-s3c24xx/include/mach/irqs.h
@@ -188,10 +188,8 @@
#if defined(CONFIG_CPU_S3C2416)
#define NR_IRQS (IRQ_S3C2416_I2S1 + 1)
-#elif defined(CONFIG_CPU_S3C2443)
-#define NR_IRQS (IRQ_S3C2443_AC97+1)
#else
-#define NR_IRQS (IRQ_S3C2440_AC97+1)
+#define NR_IRQS (IRQ_S3C2443_AC97 + 1)
#endif
/* compatibility define. */
diff --git a/arch/arm/mach-s3c24xx/irq.c b/arch/arm/mach-s3c24xx/irq.c
index cb9f5e011e73..d8ba9bee4c7e 100644
--- a/arch/arm/mach-s3c24xx/irq.c
+++ b/arch/arm/mach-s3c24xx/irq.c
@@ -500,7 +500,7 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
base = (void *)0xfd000000;
intc->reg_mask = base + 0xa4;
- intc->reg_pending = base + 0x08;
+ intc->reg_pending = base + 0xa8;
irq_num = 20;
irq_start = S3C2410_IRQ(32);
irq_offset = 4;
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
index ead5fab0dbb5..3c8ab07c2012 100644
--- a/arch/arm/mach-s3c64xx/cpuidle.c
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -40,12 +40,9 @@ static int s3c64xx_enter_idle(struct cpuidle_device *dev,
return index;
}
-static DEFINE_PER_CPU(struct cpuidle_device, s3c64xx_cpuidle_device);
-
static struct cpuidle_driver s3c64xx_cpuidle_driver = {
.name = "s3c64xx_cpuidle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states = {
{
.enter = s3c64xx_enter_idle,
@@ -61,16 +58,6 @@ static struct cpuidle_driver s3c64xx_cpuidle_driver = {
static int __init s3c64xx_init_cpuidle(void)
{
- int ret;
-
- cpuidle_register_driver(&s3c64xx_cpuidle_driver);
-
- ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
- if (ret) {
- pr_err("Failed to register cpuidle device: %d\n", ret);
- return ret;
- }
-
- return 0;
+ return cpuidle_register(&s3c64xx_cpuidle_driver, NULL);
}
device_initcall(s3c64xx_init_cpuidle);
diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c
index c8174d95339b..ca960bda02fd 100644
--- a/arch/arm/mach-s3c64xx/setup-usb-phy.c
+++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c
@@ -76,7 +76,7 @@ static int s3c_usb_otgphy_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return s3c_usb_otgphy_init(pdev);
return -EINVAL;
@@ -84,7 +84,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return s3c_usb_otgphy_exit(pdev);
return -EINVAL;
diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c
index 356a0900af03..b2ee5333f89c 100644
--- a/arch/arm/mach-s5pv210/setup-usb-phy.c
+++ b/arch/arm/mach-s5pv210/setup-usb-phy.c
@@ -80,7 +80,7 @@ static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return s5pv210_usb_otgphy_init(pdev);
return -EINVAL;
@@ -88,7 +88,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_DEVICE)
+ if (type == USB_PHY_TYPE_DEVICE)
return s5pv210_usb_otgphy_exit(pdev);
return -EINVAL;
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
index ca14dbdcfb22..04f9784ff0ed 100644
--- a/arch/arm/mach-sa1100/Kconfig
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -4,7 +4,7 @@ menu "SA11x0 Implementations"
config SA1100_ASSABET
bool "Assabet"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
help
Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
Microprocessor Development Board (also known as the Assabet).
@@ -20,7 +20,7 @@ config ASSABET_NEPONSET
config SA1100_CERF
bool "CerfBoard"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
help
The Intrinsyc CerfBoard is based on the StrongARM 1110 (Discontinued).
More information is available at:
@@ -47,7 +47,7 @@ endchoice
config SA1100_COLLIE
bool "Sharp Zaurus SL5500"
- # FIXME: select CPU_FREQ_SA11x0
+ # FIXME: select ARM_SA11x0_CPUFREQ
select SHARP_LOCOMO
select SHARP_PARAM
select SHARP_SCOOP
@@ -56,7 +56,7 @@ config SA1100_COLLIE
config SA1100_H3100
bool "Compaq iPAQ H3100"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
select HTC_EGPIO
help
Say Y here if you intend to run this kernel on the Compaq iPAQ
@@ -67,7 +67,7 @@ config SA1100_H3100
config SA1100_H3600
bool "Compaq iPAQ H3600/H3700"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
select HTC_EGPIO
help
Say Y here if you intend to run this kernel on the Compaq iPAQ
@@ -78,7 +78,7 @@ config SA1100_H3600
config SA1100_BADGE4
bool "HP Labs BadgePAD 4"
- select CPU_FREQ_SA1100
+ select ARM_SA1100_CPUFREQ
select SA1111
help
Say Y here if you want to build a kernel for the HP Laboratories
@@ -86,7 +86,7 @@ config SA1100_BADGE4
config SA1100_JORNADA720
bool "HP Jornada 720"
- # FIXME: select CPU_FREQ_SA11x0
+ # FIXME: select ARM_SA11x0_CPUFREQ
select SA1111
help
Say Y here if you want to build a kernel for the HP Jornada 720
@@ -105,14 +105,14 @@ config SA1100_JORNADA720_SSP
config SA1100_HACKKIT
bool "HackKit Core CPU Board"
- select CPU_FREQ_SA1100
+ select ARM_SA1100_CPUFREQ
help
Say Y here to support the HackKit Core CPU Board
<http://hackkit.eletztrick.de>;
config SA1100_LART
bool "LART"
- select CPU_FREQ_SA1100
+ select ARM_SA1100_CPUFREQ
help
Say Y here if you are using the Linux Advanced Radio Terminal
(also known as the LART). See <http://www.lartmaker.nl/> for
@@ -120,7 +120,7 @@ config SA1100_LART
config SA1100_NANOENGINE
bool "nanoEngine"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
select PCI
select PCI_NANOENGINE
help
@@ -130,7 +130,7 @@ config SA1100_NANOENGINE
config SA1100_PLEB
bool "PLEB"
- select CPU_FREQ_SA1100
+ select ARM_SA1100_CPUFREQ
help
Say Y here if you are using version 1 of the Portable Linux
Embedded Board (also known as PLEB).
@@ -139,7 +139,7 @@ config SA1100_PLEB
config SA1100_SHANNON
bool "Shannon"
- select CPU_FREQ_SA1100
+ select ARM_SA1100_CPUFREQ
help
The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
limited edition webphone produced by Philips. The Shannon is a SA1100
@@ -148,7 +148,7 @@ config SA1100_SHANNON
config SA1100_SIMPAD
bool "Simpad"
- select CPU_FREQ_SA1110
+ select ARM_SA1110_CPUFREQ
help
The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 1aed9e70465d..2732eef48966 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -8,9 +8,6 @@ obj-m :=
obj-n :=
obj- :=
-obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o
-obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o
-
# Specific board support
obj-$(CONFIG_SA1100_ASSABET) += assabet.o
obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
diff --git a/arch/arm/mach-sa1100/include/mach/generic.h b/arch/arm/mach-sa1100/include/mach/generic.h
new file mode 100644
index 000000000000..665542e0c9e2
--- /dev/null
+++ b/arch/arm/mach-sa1100/include/mach/generic.h
@@ -0,0 +1 @@
+#include "../../generic.h"
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index b63dec848195..153555724988 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/serial_8250.h>
#include <linux/io.h>
+#include <linux/cpu.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -130,7 +131,7 @@ static void __init shark_timer_init(void)
static void shark_init_early(void)
{
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
}
MACHINE_START(SHARK, "Shark")
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index f2ec0777cfbe..881e5c0e41dd 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/input.h>
+#include <linux/platform_data/st1232_pdata.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
@@ -169,7 +170,7 @@ static int usbhsf_get_id(struct platform_device *pdev)
return USBHS_GADGET;
}
-static void usbhsf_power_ctrl(struct platform_device *pdev,
+static int usbhsf_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@@ -223,6 +224,8 @@ static void usbhsf_power_ctrl(struct platform_device *pdev,
clk_disable(priv->pci); /* usb work around */
clk_disable(priv->usb24); /* usb work around */
}
+
+ return 0;
}
static int usbhsf_get_vbus(struct platform_device *pdev)
@@ -239,7 +242,7 @@ static irqreturn_t usbhsf_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static void usbhsf_hardware_exit(struct platform_device *pdev)
+static int usbhsf_hardware_exit(struct platform_device *pdev)
{
struct usbhsf_private *priv = usbhsf_get_priv(pdev);
@@ -264,6 +267,8 @@ static void usbhsf_hardware_exit(struct platform_device *pdev)
priv->usbh_base = NULL;
free_irq(IRQ7, pdev);
+
+ return 0;
}
static int usbhsf_hardware_init(struct platform_device *pdev)
@@ -878,10 +883,15 @@ static struct platform_device i2c_gpio_device = {
};
/* I2C */
+static struct st1232_pdata st1232_i2c0_pdata = {
+ .reset_gpio = 166,
+};
+
static struct i2c_board_info i2c0_devices[] = {
{
I2C_BOARD_INFO("st1232-ts", 0x55),
.irq = evt2irq(0x0340),
+ .platform_data = &st1232_i2c0_pdata,
},
{
I2C_BOARD_INFO("wm8978", 0x1a),
@@ -1005,7 +1015,6 @@ static void __init eva_init(void)
/* Touchscreen */
gpio_request(GPIO_FN_IRQ10, NULL); /* TP_INT */
- gpio_request_one(GPIO_PORT166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */
/* GETHER */
gpio_request(GPIO_FN_ET_CRS, NULL);
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 7f3a6b7e7b7c..a385f570bbfc 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -155,12 +155,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
return !((1 << 7) & __raw_readw(priv->cr2));
}
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
{
struct usbhs_private *priv = usbhs_get_priv(pdev);
/* init phy */
__raw_writew(0x8a0a, priv->cr2);
+
+ return 0;
}
static int usbhs_get_id(struct platform_device *pdev)
@@ -202,7 +204,7 @@ static int usbhs_hardware_init(struct platform_device *pdev)
return 0;
}
-static void usbhs_hardware_exit(struct platform_device *pdev)
+static int usbhs_hardware_exit(struct platform_device *pdev)
{
struct usbhs_private *priv = usbhs_get_priv(pdev);
@@ -210,6 +212,8 @@ static void usbhs_hardware_exit(struct platform_device *pdev)
__raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->phy);
free_irq(IRQ15, pdev);
+
+ return 0;
}
static u32 usbhs_pipe_cfg[] = {
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index db968a585ff0..979237c18dad 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -596,12 +596,14 @@ static int usbhs_get_vbus(struct platform_device *pdev)
return usbhs_is_connected(usbhs_get_priv(pdev));
}
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
{
struct usbhs_private *priv = usbhs_get_priv(pdev);
/* init phy */
__raw_writew(0x8a0a, priv->usbcrcaddr);
+
+ return 0;
}
static int usbhs0_get_id(struct platform_device *pdev)
@@ -628,11 +630,13 @@ static int usbhs0_hardware_init(struct platform_device *pdev)
return 0;
}
-static void usbhs0_hardware_exit(struct platform_device *pdev)
+static int usbhs0_hardware_exit(struct platform_device *pdev)
{
struct usbhs_private *priv = usbhs_get_priv(pdev);
cancel_delayed_work_sync(&priv->work);
+
+ return 0;
}
static struct usbhs_private usbhs0_private = {
@@ -735,7 +739,7 @@ static int usbhs1_hardware_init(struct platform_device *pdev)
return 0;
}
-static void usbhs1_hardware_exit(struct platform_device *pdev)
+static int usbhs1_hardware_exit(struct platform_device *pdev)
{
struct usbhs_private *priv = usbhs_get_priv(pdev);
@@ -743,6 +747,8 @@ static void usbhs1_hardware_exit(struct platform_device *pdev)
__raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
free_irq(IRQ8, pdev);
+
+ return 0;
}
static int usbhs1_get_id(struct platform_device *pdev)
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
index 9e050268cde4..0afeb5c7061c 100644
--- a/arch/arm/mach-shmobile/cpuidle.c
+++ b/arch/arm/mach-shmobile/cpuidle.c
@@ -16,39 +16,22 @@
#include <asm/cpuidle.h>
#include <asm/io.h>
-int shmobile_enter_wfi(struct cpuidle_device *dev, struct cpuidle_driver *drv,
- int index)
-{
- cpu_do_idle();
- return 0;
-}
-
-static struct cpuidle_device shmobile_cpuidle_dev;
static struct cpuidle_driver shmobile_cpuidle_default_driver = {
.name = "shmobile_cpuidle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
- .states[0].enter = shmobile_enter_wfi,
.safe_state_index = 0, /* C1 */
.state_count = 1,
};
static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver;
-void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv)
+void __init shmobile_cpuidle_set_driver(struct cpuidle_driver *drv)
{
cpuidle_drv = drv;
}
-int shmobile_cpuidle_init(void)
+int __init shmobile_cpuidle_init(void)
{
- struct cpuidle_device *dev = &shmobile_cpuidle_dev;
-
- cpuidle_register_driver(cpuidle_drv);
-
- dev->state_count = cpuidle_drv->state_count;
- cpuidle_register_device(dev);
-
- return 0;
+ return cpuidle_register(cpuidle_drv, NULL);
}
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index e48606d8a2be..362f9b2d2c02 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -13,9 +13,6 @@ extern int shmobile_clk_init(void);
extern void shmobile_handle_irq_intc(struct pt_regs *);
extern struct platform_suspend_ops shmobile_suspend_ops;
struct cpuidle_driver;
-struct cpuidle_device;
-extern int shmobile_enter_wfi(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index);
extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv);
extern void sh7372_init_irq(void);
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index a0826a48dd08..dec9293bb90d 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -410,11 +410,9 @@ static int sh7372_enter_a4s(struct cpuidle_device *dev,
static struct cpuidle_driver sh7372_cpuidle_driver = {
.name = "sh7372_cpuidle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.state_count = 5,
.safe_state_index = 0, /* C1 */
.states[0] = ARM_CPUIDLE_WFI_STATE,
- .states[0].enter = shmobile_enter_wfi,
.states[1] = {
.name = "C2",
.desc = "Core Standby Mode",
@@ -450,12 +448,12 @@ static struct cpuidle_driver sh7372_cpuidle_driver = {
},
};
-static void sh7372_cpuidle_init(void)
+static void __init sh7372_cpuidle_init(void)
{
shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver);
}
#else
-static void sh7372_cpuidle_init(void) {}
+static void __init sh7372_cpuidle_init(void) {}
#endif
#ifdef CONFIG_SUSPEND
diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c
index 47d83f7a70b6..5d92b5dd486b 100644
--- a/arch/arm/mach-shmobile/suspend.c
+++ b/arch/arm/mach-shmobile/suspend.c
@@ -12,6 +12,8 @@
#include <linux/suspend.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/cpu.h>
+
#include <asm/io.h>
#include <asm/system_misc.h>
@@ -23,13 +25,13 @@ static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
static int shmobile_suspend_begin(suspend_state_t state)
{
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
return 0;
}
static void shmobile_suspend_end(void)
{
- enable_hlt();
+ cpu_idle_poll_ctrl(false);
}
struct platform_suspend_ops shmobile_suspend_ops = {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index d1c4893894ce..dbc653ea851c 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -18,8 +18,8 @@ config ARCH_TEGRA_2x_SOC
select PL310_ERRATA_727915 if CACHE_L2X0
select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT
- select USB_ULPI if USB
- select USB_ULPI_VIEWPORT if USB_SUPPORT
+ select USB_ULPI if USB_PHY
+ select USB_ULPI_VIEWPORT if USB_PHY
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -37,8 +37,8 @@ config ARCH_TEGRA_3x_SOC
select PINCTRL_TEGRA30
select PL310_ERRATA_769419 if CACHE_L2X0
select USB_ARCH_HAS_EHCI if USB_SUPPORT
- select USB_ULPI if USB
- select USB_ULPI_VIEWPORT if USB_SUPPORT
+ select USB_ULPI if USB_PHY
+ select USB_ULPI_VIEWPORT if USB_PHY
help
Support for NVIDIA Tegra T30 processor family, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f6b46ae2b7f8..09b578f9eb84 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -24,7 +24,6 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
endif
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
index 0f4e8c483b34..1d1c6023f4a2 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra114.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -23,39 +23,13 @@
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.state_count = 1,
.states = {
[0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
},
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
int __init tegra114_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, NULL);
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 825ced4f7a40..590ec25855dd 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -43,32 +43,33 @@ static atomic_t abort_barrier;
static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index);
+#define TEGRA20_MAX_STATES 2
+#else
+#define TEGRA20_MAX_STATES 1
#endif
-static struct cpuidle_state tegra_idle_states[] = {
- [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
-#ifdef CONFIG_PM_SLEEP
- [1] = {
- .enter = tegra20_idle_lp2_coupled,
- .exit_latency = 5000,
- .target_residency = 10000,
- .power_usage = 0,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_COUPLED,
- .name = "powered-down",
- .desc = "CPU power gated",
- },
-#endif
-};
-
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE_PWR(600),
+#ifdef CONFIG_PM_SLEEP
+ {
+ .enter = tegra20_idle_lp2_coupled,
+ .exit_latency = 5000,
+ .target_residency = 10000,
+ .power_usage = 0,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_COUPLED,
+ .name = "powered-down",
+ .desc = "CPU power gated",
+ },
+#endif
+ },
+ .state_count = TEGRA20_MAX_STATES,
+ .safe_state_index = 0,
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_SMP
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -217,39 +218,8 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
int __init tegra20_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
#ifdef CONFIG_PM_SLEEP
tegra_tear_down_cpu = tegra20_tear_down_cpu;
#endif
-
- drv->state_count = ARRAY_SIZE(tegra_idle_states);
- memcpy(drv->states, tegra_idle_states,
- drv->state_count * sizeof(drv->states[0]));
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
- dev->coupled_cpus = *cpu_possible_mask;
-#endif
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 8b50cf4ddd6f..36dc2befa9d8 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -43,7 +43,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
static struct cpuidle_driver tegra_idle_driver = {
.name = "tegra_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
#ifdef CONFIG_PM_SLEEP
.state_count = 2,
#else
@@ -65,8 +64,6 @@ static struct cpuidle_driver tegra_idle_driver = {
},
};
-static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
-
#ifdef CONFIG_PM_SLEEP
static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
@@ -157,32 +154,8 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
int __init tegra30_cpuidle_init(void)
{
- int ret;
- unsigned int cpu;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &tegra_idle_driver;
-
#ifdef CONFIG_PM_SLEEP
tegra_tear_down_cpu = tegra30_tear_down_cpu;
#endif
-
- ret = cpuidle_register_driver(&tegra_idle_driver);
- if (ret) {
- pr_err("CPUidle driver registration failed\n");
- return ret;
- }
-
- for_each_possible_cpu(cpu) {
- dev = &per_cpu(tegra_idle_device, cpu);
- dev->cpu = cpu;
-
- dev->state_count = drv->state_count;
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("CPU%u: CPUidle device registration failed\n",
- cpu);
- return ret;
- }
- }
- return 0;
+ return cpuidle_register(&tegra_idle_driver, NULL);
}
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
index 2a17bc506cff..ff3c9f016591 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.c
+++ b/arch/arm/mach-ux500/board-mop500-regulators.c
@@ -5,6 +5,7 @@
*
* Authors: Sundar Iyer <sundar.iyer@stericsson.com>
* Bengt Jonsson <bengt.g.jonsson@stericsson.com>
+ * Daniel Willerud <daniel.willerud@stericsson.com>
*
* MOP500 board specific initialization for regulators
*/
@@ -12,6 +13,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
#include "board-mop500-regulators.h"
+#include "id.h"
static struct regulator_consumer_supply gpio_en_3v3_consumers[] = {
REGULATOR_SUPPLY("vdd33a", "smsc911x.0"),
@@ -53,21 +55,37 @@ struct regulator_init_data tps61052_regulator = {
};
static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
- /* External displays, connector on board 2v5 power supply */
- REGULATOR_SUPPLY("vaux12v5", "mcde.0"),
+ /* Main display, u8500 R3 uib */
+ REGULATOR_SUPPLY("vddi", "mcde_disp_sony_acx424akp.0"),
+ /* Main display, u8500 uib and ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.0"),
+ /* Secondary display, ST uib */
+ REGULATOR_SUPPLY("vdd1", "samsung_s6d16d0.1"),
/* SFH7741 proximity sensor */
REGULATOR_SUPPLY("vcc", "gpio-keys.0"),
/* BH1780GLS ambient light sensor */
REGULATOR_SUPPLY("vcc", "2-0029"),
/* lsm303dlh accelerometer */
- REGULATOR_SUPPLY("vdd", "3-0018"),
+ REGULATOR_SUPPLY("vdd", "2-0018"),
+ /* lsm303dlhc accelerometer */
+ REGULATOR_SUPPLY("vdd", "2-0019"),
/* lsm303dlh magnetometer */
- REGULATOR_SUPPLY("vdd", "3-001e"),
+ REGULATOR_SUPPLY("vdd", "2-001e"),
/* Rohm BU21013 Touchscreen devices */
REGULATOR_SUPPLY("avdd", "3-005c"),
REGULATOR_SUPPLY("avdd", "3-005d"),
/* Synaptics RMI4 Touchscreen device */
REGULATOR_SUPPLY("vdd", "3-004b"),
+ /* L3G4200D Gyroscope device */
+ REGULATOR_SUPPLY("vdd", "2-0068"),
+ /* Ambient light sensor device */
+ REGULATOR_SUPPLY("vdd", "3-0029"),
+ /* Pressure sensor device */
+ REGULATOR_SUPPLY("vdd", "2-005c"),
+ /* Cypress TrueTouch Touchscreen device */
+ REGULATOR_SUPPLY("vcpin", "spi8.0"),
+ /* Camera device */
+ REGULATOR_SUPPLY("vaux12v5", "mmio_camera"),
};
static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
@@ -75,18 +93,50 @@ static struct regulator_consumer_supply ab8500_vaux2_consumers[] = {
REGULATOR_SUPPLY("vmmc", "sdi4"),
/* AB8500 audio codec */
REGULATOR_SUPPLY("vcc-N2158", "ab8500-codec.0"),
+ /* AB8500 accessory detect 1 */
+ REGULATOR_SUPPLY("vcc-N2158", "ab8500-acc-det.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vcc-N2158", "mcde_tv_ab8500.4"),
+ /* AV8100 HDMI device */
+ REGULATOR_SUPPLY("vcc-N2158", "av8100_hdmi.3"),
};
static struct regulator_consumer_supply ab8500_vaux3_consumers[] = {
+ REGULATOR_SUPPLY("v-SD-STM", "stm"),
/* External MMC slot power */
REGULATOR_SUPPLY("vmmc", "sdi0"),
};
+static struct regulator_consumer_supply ab8505_vaux4_consumers[] = {
+};
+
+static struct regulator_consumer_supply ab8505_vaux5_consumers[] = {
+};
+
+static struct regulator_consumer_supply ab8505_vaux6_consumers[] = {
+};
+
+static struct regulator_consumer_supply ab8505_vaux8_consumers[] = {
+ /* AB8500 audio codec device */
+ REGULATOR_SUPPLY("v-aux8", NULL),
+};
+
+static struct regulator_consumer_supply ab8505_vadc_consumers[] = {
+ /* Internal general-purpose ADC */
+ REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
+ /* ADC for charger */
+ REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
+};
+
static struct regulator_consumer_supply ab8500_vtvout_consumers[] = {
/* TV-out DENC supply */
REGULATOR_SUPPLY("vtvout", "ab8500-denc.0"),
/* Internal general-purpose ADC */
REGULATOR_SUPPLY("vddadc", "ab8500-gpadc.0"),
+ /* ADC for charger */
+ REGULATOR_SUPPLY("vddadc", "ab8500-charger.0"),
+ /* AB8500 Tv-out device */
+ REGULATOR_SUPPLY("vtvout", "mcde_tv_ab8500.4"),
};
static struct regulator_consumer_supply ab8500_vaud_consumers[] = {
@@ -114,77 +164,90 @@ static struct regulator_consumer_supply ab8500_vintcore_consumers[] = {
REGULATOR_SUPPLY("v-intcore", NULL),
/* USB Transceiver */
REGULATOR_SUPPLY("vddulpivio18", "ab8500-usb.0"),
+ /* Handled by abx500 clk driver */
+ REGULATOR_SUPPLY("v-intcore", "abx500-clk.0"),
+};
+
+static struct regulator_consumer_supply ab8505_usb_consumers[] = {
+ /* HS USB OTG physical interface */
+ REGULATOR_SUPPLY("v-ape", NULL),
};
static struct regulator_consumer_supply ab8500_vana_consumers[] = {
- /* External displays, connector on board, 1v8 power supply */
- REGULATOR_SUPPLY("vsmps2", "mcde.0"),
+ /* DB8500 DSI */
+ REGULATOR_SUPPLY("vdddsi1v2", "mcde"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "b2r2_1_core"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.0"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.1"),
+ REGULATOR_SUPPLY("vdddsi1v2", "dsilink.2"),
+ /* DB8500 CSI */
+ REGULATOR_SUPPLY("vddcsi1v2", "mmio_camera"),
};
/* ab8500 regulator register initialization */
-struct ab8500_regulator_reg_init
-ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
+static struct ab8500_regulator_reg_init ab8500_reg_init[] = {
/*
* VanaRequestCtrl = HP/LP depending on VxRequest
* VextSupply1RequestCtrl = HP/LP depending on VxRequest
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL2, 0xf0, 0x00),
/*
* VextSupply2RequestCtrl = HP/LP depending on VxRequest
* VextSupply3RequestCtrl = HP/LP depending on VxRequest
* Vaux1RequestCtrl = HP/LP depending on VxRequest
* Vaux2RequestCtrl = HP/LP depending on VxRequest
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL3, 0xff, 0x00),
/*
* Vaux3RequestCtrl = HP/LP depending on VxRequest
* SwHPReq = Control through SWValid disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUREQUESTCTRL4, 0x07, 0x00),
/*
* VanaSysClkReq1HPValid = disabled
* Vaux1SysClkReq1HPValid = disabled
* Vaux2SysClkReq1HPValid = disabled
* Vaux3SysClkReq1HPValid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
/*
* VextSupply1SysClkReq1HPValid = disabled
* VextSupply2SysClkReq1HPValid = disabled
* VextSupply3SysClkReq1HPValid = SysClkReq1 controlled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x40),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQ1HPVALID2, 0x70, 0x40),
/*
* VanaHwHPReq1Valid = disabled
* Vaux1HwHPreq1Valid = disabled
* Vaux2HwHPReq1Valid = disabled
* Vaux3HwHPReqValid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq1Valid = disabled
* VextSupply2HwHPReq1Valid = disabled
* VextSupply3HwHPReq1Valid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ1VALID2, 0x07, 0x00),
/*
* VanaHwHPReq2Valid = disabled
* Vaux1HwHPReq2Valid = disabled
* Vaux2HwHPReq2Valid = disabled
* Vaux3HwHPReq2Valid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID1, 0xe8, 0x00),
/*
* VextSupply1HwHPReq2Valid = disabled
* VextSupply2HwHPReq2Valid = disabled
* VextSupply3HwHPReq2Valid = HWReq2 controlled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x04),
+ INIT_REGULATOR_REGISTER(AB8500_REGUHWHPREQ2VALID2, 0x07, 0x04),
/*
* VanaSwHPReqValid = disabled
* Vaux1SwHPReqValid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID1, 0xa0, 0x00),
/*
* Vaux2SwHPReqValid = disabled
* Vaux3SwHPReqValid = disabled
@@ -192,7 +255,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
* VextSupply2SwHPReqValid = disabled
* VextSupply3SwHPReqValid = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSWHPREQVALID2, 0x1f, 0x00),
/*
* SysClkReq2Valid1 = SysClkReq2 controlled
* SysClkReq3Valid1 = disabled
@@ -202,7 +265,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
* SysClkReq7Valid1 = disabled
* SysClkReq8Valid1 = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0x2a),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID1, 0xfe, 0x2a),
/*
* SysClkReq2Valid2 = disabled
* SysClkReq3Valid2 = disabled
@@ -212,7 +275,7 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
* SysClkReq7Valid2 = disabled
* SysClkReq8Valid2 = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0x20),
+ INIT_REGULATOR_REGISTER(AB8500_REGUSYSCLKREQVALID2, 0xfe, 0x20),
/*
* VTVoutEna = disabled
* Vintcore12Ena = disabled
@@ -220,66 +283,62 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
* Vintcore12LP = inactive (HP)
* VTVoutLP = inactive (HP)
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0x10),
+ INIT_REGULATOR_REGISTER(AB8500_REGUMISC1, 0xfe, 0x10),
/*
* VaudioEna = disabled
* VdmicEna = disabled
* Vamic1Ena = disabled
* Vamic2Ena = disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_VAUDIOSUPPLY, 0x1e, 0x00),
/*
* Vamic1_dzout = high-Z when Vamic1 is disabled
* Vamic2_dzout = high-Z when Vamic2 is disabled
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL1VAMIC, 0x03, 0x00),
/*
- * VPll = Hw controlled
+ * VPll = Hw controlled (NOTE! PRCMU bits)
* VanaRegu = force off
*/
- INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x02),
+ INIT_REGULATOR_REGISTER(AB8500_VPLLVANAREGU, 0x0f, 0x02),
/*
* VrefDDREna = disabled
* VrefDDRSleepMode = inactive (no pulldown)
*/
- INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_VREFDDR, 0x03, 0x00),
/*
- * VextSupply1Regu = HW control
- * VextSupply2Regu = HW control
- * VextSupply3Regu = HW control
+ * VextSupply1Regu = force LP
+ * VextSupply2Regu = force OFF
+ * VextSupply3Regu = force HP (-> STBB2=LP and TPS=LP)
* ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
* ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
*/
- INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0x2a),
+ INIT_REGULATOR_REGISTER(AB8500_EXTSUPPLYREGU, 0xff, 0x13),
/*
* Vaux1Regu = force HP
* Vaux2Regu = force off
*/
- INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x01),
+ INIT_REGULATOR_REGISTER(AB8500_VAUX12REGU, 0x0f, 0x01),
/*
- * Vaux3regu = force off
+ * Vaux3Regu = force off
*/
- INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3REGU, 0x03, 0x00),
/*
- * Vsmps1 = 1.15V
+ * Vaux1Sel = 2.8 V
*/
- INIT_REGULATOR_REGISTER(AB8500_VSMPS1SEL1, 0x24),
- /*
- * Vaux1Sel = 2.5 V
- */
- INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x08),
+ INIT_REGULATOR_REGISTER(AB8500_VAUX1SEL, 0x0f, 0x0C),
/*
* Vaux2Sel = 2.9 V
*/
- INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0d),
+ INIT_REGULATOR_REGISTER(AB8500_VAUX2SEL, 0x0f, 0x0d),
/*
* Vaux3Sel = 2.91 V
*/
- INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07),
+ INIT_REGULATOR_REGISTER(AB8500_VRF1VAUX3SEL, 0x07, 0x07),
/*
* VextSupply12LP = disabled (no LP)
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRL2SPARE, 0x01, 0x00),
/*
* Vaux1Disch = short discharge time
* Vaux2Disch = short discharge time
@@ -288,33 +347,26 @@ ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS] = {
* VTVoutDisch = short discharge time
* VaudioDisch = short discharge time
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH, 0xfc, 0x00),
/*
* VanaDisch = short discharge time
* VdmicPullDownEna = pulldown disabled when Vdmic is disabled
* VdmicDisch = short discharge time
*/
- INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x00),
+ INIT_REGULATOR_REGISTER(AB8500_REGUCTRLDISCH2, 0x16, 0x00),
};
/* AB8500 regulators */
-struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
+static struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
/* supplies to the display/camera */
[AB8500_LDO_AUX1] = {
.constraints = {
.name = "V-DISPLAY",
- .min_uV = 2500000,
- .max_uV = 2900000,
+ .min_uV = 2800000,
+ .max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
REGULATOR_CHANGE_STATUS,
.boot_on = 1, /* display is on at boot */
- /*
- * This voltage cannot be disabled right now because
- * it is somehow affecting the external MMC
- * functionality, though that typically will use
- * AUX3.
- */
- .always_on = 1,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
.consumer_supplies = ab8500_vaux1_consumers,
@@ -326,7 +378,10 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS,
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
.consumer_supplies = ab8500_vaux2_consumers,
@@ -338,7 +393,10 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
.min_uV = 1100000,
.max_uV = 3300000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
- REGULATOR_CHANGE_STATUS,
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
.consumer_supplies = ab8500_vaux3_consumers,
@@ -392,18 +450,614 @@ struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = {
[AB8500_LDO_INTCORE] = {
.constraints = {
.name = "V-INTCORE",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .min_uV = 1250000,
+ .max_uV = 1350000,
+ .input_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_DRMS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
.consumer_supplies = ab8500_vintcore_consumers,
},
- /* supply for U8500 CSI/DSI, VANA LDO */
+ /* supply for U8500 CSI-DSI, VANA LDO */
[AB8500_LDO_ANA] = {
.constraints = {
- .name = "V-CSI/DSI",
+ .name = "V-CSI-DSI",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
.consumer_supplies = ab8500_vana_consumers,
},
};
+
+/* supply for VextSupply3 */
+static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
+ /* SIM supply for 3 V SIM cards */
+ REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
+};
+
+/* extended configuration for VextSupply2, only used for HREFP_V20 boards */
+static struct ab8500_ext_regulator_cfg ab8500_ext_supply2 = {
+ .hwreq = true,
+};
+
+/*
+ * AB8500 external regulators
+ */
+static struct regulator_init_data ab8500_ext_regulators[] = {
+ /* fixed Vbat supplies VSMPS1_EXT_1V8 */
+ [AB8500_EXT_SUPPLY1] = {
+ .constraints = {
+ .name = "ab8500-ext-supply1",
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .initial_mode = REGULATOR_MODE_IDLE,
+ .boot_on = 1,
+ .always_on = 1,
+ },
+ },
+ /* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
+ [AB8500_EXT_SUPPLY2] = {
+ .constraints = {
+ .name = "ab8500-ext-supply2",
+ .min_uV = 1360000,
+ .max_uV = 1360000,
+ },
+ },
+ /* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
+ [AB8500_EXT_SUPPLY3] = {
+ .constraints = {
+ .name = "ab8500-ext-supply3",
+ .min_uV = 3400000,
+ .max_uV = 3400000,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies =
+ ARRAY_SIZE(ab8500_ext_supply3_consumers),
+ .consumer_supplies = ab8500_ext_supply3_consumers,
+ },
+};
+
+/* ab8505 regulator register initialization */
+static struct ab8500_regulator_reg_init ab8505_reg_init[] = {
+ /*
+ * VarmRequestCtrl
+ * VsmpsCRequestCtrl
+ * VsmpsARequestCtrl
+ * VsmpsBRequestCtrl
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL1, 0x00, 0x00),
+ /*
+ * VsafeRequestCtrl
+ * VpllRequestCtrl
+ * VanaRequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL2, 0x30, 0x00),
+ /*
+ * Vaux1RequestCtrl = HP/LP depending on VxRequest
+ * Vaux2RequestCtrl = HP/LP depending on VxRequest
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL3, 0xf0, 0x00),
+ /*
+ * Vaux3RequestCtrl = HP/LP depending on VxRequest
+ * SwHPReq = Control through SWValid disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUREQUESTCTRL4, 0x07, 0x00),
+ /*
+ * VsmpsASysClkReq1HPValid
+ * VsmpsBSysClkReq1HPValid
+ * VsafeSysClkReq1HPValid
+ * VanaSysClkReq1HPValid = disabled
+ * VpllSysClkReq1HPValid
+ * Vaux1SysClkReq1HPValid = disabled
+ * Vaux2SysClkReq1HPValid = disabled
+ * Vaux3SysClkReq1HPValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID1, 0xe8, 0x00),
+ /*
+ * VsmpsCSysClkReq1HPValid
+ * VarmSysClkReq1HPValid
+ * VbbSysClkReq1HPValid
+ * VsmpsMSysClkReq1HPValid
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQ1HPVALID2, 0x00, 0x00),
+ /*
+ * VsmpsAHwHPReq1Valid
+ * VsmpsBHwHPReq1Valid
+ * VsafeHwHPReq1Valid
+ * VanaHwHPReq1Valid = disabled
+ * VpllHwHPReq1Valid
+ * Vaux1HwHPreq1Valid = disabled
+ * Vaux2HwHPReq1Valid = disabled
+ * Vaux3HwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID1, 0xe8, 0x00),
+ /*
+ * VsmpsMHwHPReq1Valid
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ1VALID2, 0x00, 0x00),
+ /*
+ * VsmpsAHwHPReq2Valid
+ * VsmpsBHwHPReq2Valid
+ * VsafeHwHPReq2Valid
+ * VanaHwHPReq2Valid = disabled
+ * VpllHwHPReq2Valid
+ * Vaux1HwHPReq2Valid = disabled
+ * Vaux2HwHPReq2Valid = disabled
+ * Vaux3HwHPReq2Valid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID1, 0xe8, 0x00),
+ /*
+ * VsmpsMHwHPReq2Valid
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUHWHPREQ2VALID2, 0x00, 0x00),
+ /**
+ * VsmpsCSwHPReqValid
+ * VarmSwHPReqValid
+ * VsmpsASwHPReqValid
+ * VsmpsBSwHPReqValid
+ * VsafeSwHPReqValid
+ * VanaSwHPReqValid
+ * VanaSwHPReqValid = disabled
+ * VpllSwHPReqValid
+ * Vaux1SwHPReqValid = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID1, 0xa0, 0x00),
+ /*
+ * Vaux2SwHPReqValid = disabled
+ * Vaux3SwHPReqValid = disabled
+ * VsmpsMSwHPReqValid
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSWHPREQVALID2, 0x03, 0x00),
+ /*
+ * SysClkReq2Valid1 = SysClkReq2 controlled
+ * SysClkReq3Valid1 = disabled
+ * SysClkReq4Valid1 = SysClkReq4 controlled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID1, 0x0e, 0x0a),
+ /*
+ * SysClkReq2Valid2 = disabled
+ * SysClkReq3Valid2 = disabled
+ * SysClkReq4Valid2 = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUSYSCLKREQVALID2, 0x0e, 0x00),
+ /*
+ * Vaux4SwHPReqValid
+ * Vaux4HwHPReq2Valid
+ * Vaux4HwHPReq1Valid
+ * Vaux4SysClkReq1HPValid
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUVAUX4REQVALID, 0x00, 0x00),
+ /*
+ * VadcEna = disabled
+ * VintCore12Ena = disabled
+ * VintCore12Sel = 1.25 V
+ * VintCore12LP = inactive (HP)
+ * VadcLP = inactive (HP)
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUMISC1, 0xfe, 0x10),
+ /*
+ * VaudioEna = disabled
+ * Vaux8Ena = disabled
+ * Vamic1Ena = disabled
+ * Vamic2Ena = disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUDIOSUPPLY, 0x1e, 0x00),
+ /*
+ * Vamic1_dzout = high-Z when Vamic1 is disabled
+ * Vamic2_dzout = high-Z when Vamic2 is disabled
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUCTRL1VAMIC, 0x03, 0x00),
+ /*
+ * VsmpsARegu
+ * VsmpsASelCtrl
+ * VsmpsAAutoMode
+ * VsmpsAPWMMode
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSAREGU, 0x00, 0x00),
+ /*
+ * VsmpsBRegu
+ * VsmpsBSelCtrl
+ * VsmpsBAutoMode
+ * VsmpsBPWMMode
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSBREGU, 0x00, 0x00),
+ /*
+ * VsafeRegu
+ * VsafeSelCtrl
+ * VsafeAutoMode
+ * VsafePWMMode
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSAFEREGU, 0x00, 0x00),
+ /*
+ * VPll = Hw controlled (NOTE! PRCMU bits)
+ * VanaRegu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VPLLVANAREGU, 0x0f, 0x02),
+ /*
+ * VextSupply1Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
+ * VextSupply2Regu = force OFF (OTP_ExtSupply12LPnPolarity 1)
+ * VextSupply3Regu = force OFF (OTP_ExtSupply3LPnPolarity 0)
+ * ExtSupply2Bypass = ExtSupply12LPn ball is 0 when Ena is 0
+ * ExtSupply3Bypass = ExtSupply3LPn ball is 0 when Ena is 0
+ */
+ INIT_REGULATOR_REGISTER(AB8505_EXTSUPPLYREGU, 0xff, 0x30),
+ /*
+ * Vaux1Regu = force HP
+ * Vaux2Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX12REGU, 0x0f, 0x01),
+ /*
+ * Vaux3Regu = force off
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3REGU, 0x03, 0x00),
+ /*
+ * VsmpsASel1
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL1, 0x00, 0x00),
+ /*
+ * VsmpsASel2
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL2, 0x00, 0x00),
+ /*
+ * VsmpsASel3
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSASEL3, 0x00, 0x00),
+ /*
+ * VsmpsBSel1
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL1, 0x00, 0x00),
+ /*
+ * VsmpsBSel2
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL2, 0x00, 0x00),
+ /*
+ * VsmpsBSel3
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSMPSBSEL3, 0x00, 0x00),
+ /*
+ * VsafeSel1
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSAFESEL1, 0x00, 0x00),
+ /*
+ * VsafeSel2
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSAFESEL2, 0x00, 0x00),
+ /*
+ * VsafeSel3
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VSAFESEL3, 0x00, 0x00),
+ /*
+ * Vaux1Sel = 2.8 V
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX1SEL, 0x0f, 0x0C),
+ /*
+ * Vaux2Sel = 2.9 V
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX2SEL, 0x0f, 0x0d),
+ /*
+ * Vaux3Sel = 2.91 V
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VRF1VAUX3SEL, 0x07, 0x07),
+ /*
+ * Vaux4RequestCtrl
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX4REQCTRL, 0x00, 0x00),
+ /*
+ * Vaux4Regu
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX4REGU, 0x00, 0x00),
+ /*
+ * Vaux4Sel
+ */
+ INIT_REGULATOR_REGISTER(AB8505_VAUX4SEL, 0x00, 0x00),
+ /*
+ * Vaux1Disch = short discharge time
+ * Vaux2Disch = short discharge time
+ * Vaux3Disch = short discharge time
+ * Vintcore12Disch = short discharge time
+ * VTVoutDisch = short discharge time
+ * VaudioDisch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH, 0xfc, 0x00),
+ /*
+ * VanaDisch = short discharge time
+ * Vaux8PullDownEna = pulldown disabled when Vaux8 is disabled
+ * Vaux8Disch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH2, 0x16, 0x00),
+ /*
+ * Vaux4Disch = short discharge time
+ */
+ INIT_REGULATOR_REGISTER(AB8505_REGUCTRLDISCH3, 0x01, 0x00),
+ /*
+ * Vaux5Sel
+ * Vaux5LP
+ * Vaux5Ena
+ * Vaux5Disch
+ * Vaux5DisSfst
+ * Vaux5DisPulld
+ */
+ INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX5, 0x00, 0x00),
+ /*
+ * Vaux6Sel
+ * Vaux6LP
+ * Vaux6Ena
+ * Vaux6DisPulld
+ */
+ INIT_REGULATOR_REGISTER(AB8505_CTRLVAUX6, 0x00, 0x00),
+};
+
+struct regulator_init_data ab8505_regulators[AB8505_NUM_REGULATORS] = {
+ /* supplies to the display/camera */
+ [AB8505_LDO_AUX1] = {
+ .constraints = {
+ .name = "V-DISPLAY",
+ .min_uV = 2800000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS,
+ .boot_on = 1, /* display is on at boot */
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux1_consumers),
+ .consumer_supplies = ab8500_vaux1_consumers,
+ },
+ /* supplies to the on-board eMMC */
+ [AB8505_LDO_AUX2] = {
+ .constraints = {
+ .name = "V-eMMC1",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux2_consumers),
+ .consumer_supplies = ab8500_vaux2_consumers,
+ },
+ /* supply for VAUX3, supplies to SDcard slots */
+ [AB8505_LDO_AUX3] = {
+ .constraints = {
+ .name = "V-MMC-SD",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaux3_consumers),
+ .consumer_supplies = ab8500_vaux3_consumers,
+ },
+ /* supply for VAUX4, supplies to NFC and standalone secure element */
+ [AB8505_LDO_AUX4] = {
+ .constraints = {
+ .name = "V-NFC-SE",
+ .min_uV = 1100000,
+ .max_uV = 3300000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux4_consumers),
+ .consumer_supplies = ab8505_vaux4_consumers,
+ },
+ /* supply for VAUX5, supplies to TBD */
+ [AB8505_LDO_AUX5] = {
+ .constraints = {
+ .name = "V-AUX5",
+ .min_uV = 1050000,
+ .max_uV = 2790000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux5_consumers),
+ .consumer_supplies = ab8505_vaux5_consumers,
+ },
+ /* supply for VAUX6, supplies to TBD */
+ [AB8505_LDO_AUX6] = {
+ .constraints = {
+ .name = "V-AUX6",
+ .min_uV = 1050000,
+ .max_uV = 2790000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux6_consumers),
+ .consumer_supplies = ab8505_vaux6_consumers,
+ },
+ /* supply for gpadc, ADC LDO */
+ [AB8505_LDO_ADC] = {
+ .constraints = {
+ .name = "V-ADC",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_vadc_consumers),
+ .consumer_supplies = ab8505_vadc_consumers,
+ },
+ /* supply for ab8500-vaudio, VAUDIO LDO */
+ [AB8505_LDO_AUDIO] = {
+ .constraints = {
+ .name = "V-AUD",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vaud_consumers),
+ .consumer_supplies = ab8500_vaud_consumers,
+ },
+ /* supply for v-anamic1 VAMic1-LDO */
+ [AB8505_LDO_ANAMIC1] = {
+ .constraints = {
+ .name = "V-AMIC1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic1_consumers),
+ .consumer_supplies = ab8500_vamic1_consumers,
+ },
+ /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+ [AB8505_LDO_ANAMIC2] = {
+ .constraints = {
+ .name = "V-AMIC2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vamic2_consumers),
+ .consumer_supplies = ab8500_vamic2_consumers,
+ },
+ /* supply for v-aux8, VAUX8 LDO */
+ [AB8505_LDO_AUX8] = {
+ .constraints = {
+ .name = "V-AUX8",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_vaux8_consumers),
+ .consumer_supplies = ab8505_vaux8_consumers,
+ },
+ /* supply for v-intcore12, VINTCORE12 LDO */
+ [AB8505_LDO_INTCORE] = {
+ .constraints = {
+ .name = "V-INTCORE",
+ .min_uV = 1250000,
+ .max_uV = 1350000,
+ .input_uV = 1800000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_DRMS,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vintcore_consumers),
+ .consumer_supplies = ab8500_vintcore_consumers,
+ },
+ /* supply for LDO USB */
+ [AB8505_LDO_USB] = {
+ .constraints = {
+ .name = "V-USB",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_IDLE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8505_usb_consumers),
+ .consumer_supplies = ab8505_usb_consumers,
+ },
+ /* supply for U8500 CSI-DSI, VANA LDO */
+ [AB8505_LDO_ANA] = {
+ .constraints = {
+ .name = "V-CSI-DSI",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ab8500_vana_consumers),
+ .consumer_supplies = ab8500_vana_consumers,
+ },
+};
+
+struct ab8500_regulator_platform_data ab8500_regulator_plat_data = {
+ .reg_init = ab8500_reg_init,
+ .num_reg_init = ARRAY_SIZE(ab8500_reg_init),
+ .regulator = ab8500_regulators,
+ .num_regulator = ARRAY_SIZE(ab8500_regulators),
+ .ext_regulator = ab8500_ext_regulators,
+ .num_ext_regulator = ARRAY_SIZE(ab8500_ext_regulators),
+};
+
+/* Use the AB8500 init settings for AB8505 as they are the same right now */
+struct ab8500_regulator_platform_data ab8505_regulator_plat_data = {
+ .reg_init = ab8505_reg_init,
+ .num_reg_init = ARRAY_SIZE(ab8505_reg_init),
+ .regulator = ab8505_regulators,
+ .num_regulator = ARRAY_SIZE(ab8505_regulators),
+};
+
+static void ab8500_modify_reg_init(int id, u8 mask, u8 value)
+{
+ int i;
+
+ if (cpu_is_u8520()) {
+ for (i = ARRAY_SIZE(ab8505_reg_init) - 1; i >= 0; i--) {
+ if (ab8505_reg_init[i].id == id) {
+ u8 initval = ab8505_reg_init[i].value;
+ initval = (initval & ~mask) | (value & mask);
+ ab8505_reg_init[i].value = initval;
+
+ BUG_ON(mask & ~ab8505_reg_init[i].mask);
+ return;
+ }
+ }
+ } else {
+ for (i = ARRAY_SIZE(ab8500_reg_init) - 1; i >= 0; i--) {
+ if (ab8500_reg_init[i].id == id) {
+ u8 initval = ab8500_reg_init[i].value;
+ initval = (initval & ~mask) | (value & mask);
+ ab8500_reg_init[i].value = initval;
+
+ BUG_ON(mask & ~ab8500_reg_init[i].mask);
+ return;
+ }
+ }
+ }
+
+ BUG_ON(1);
+}
+
+void mop500_regulator_init(void)
+{
+ struct regulator_init_data *regulator;
+
+ /*
+ * Temporarily turn on Vaux2 on 8520 machine
+ */
+ if (cpu_is_u8520()) {
+ /* Vaux2 initialized to be on */
+ ab8500_modify_reg_init(AB8505_VAUX12REGU, 0x0f, 0x05);
+ }
+
+ /*
+ * Handle AB8500_EXT_SUPPLY2 on HREFP_V20_V50 boards (do it for
+ * all HREFP_V20 boards)
+ */
+ if (cpu_is_u8500v20()) {
+ /* VextSupply2RequestCtrl = HP/OFF depending on VxRequest */
+ ab8500_modify_reg_init(AB8500_REGUREQUESTCTRL3, 0x01, 0x01);
+
+ /* VextSupply2SysClkReq1HPValid = SysClkReq1 controlled */
+ ab8500_modify_reg_init(AB8500_REGUSYSCLKREQ1HPVALID2,
+ 0x20, 0x20);
+
+ /* VextSupply2 = force HP at initialization */
+ ab8500_modify_reg_init(AB8500_EXTSUPPLYREGU, 0x0c, 0x04);
+
+ /* enable VextSupply2 during platform active */
+ regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
+ regulator->constraints.always_on = 1;
+
+ /* disable VextSupply2 in suspend */
+ regulator = &ab8500_ext_regulators[AB8500_EXT_SUPPLY2];
+ regulator->constraints.state_mem.disabled = 1;
+ regulator->constraints.state_standby.disabled = 1;
+
+ /* enable VextSupply2 HW control (used in suspend) */
+ regulator->driver_data = (void *)&ab8500_ext_supply2;
+ }
+}
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h
index 78a0642a2206..9bece38fe933 100644
--- a/arch/arm/mach-ux500/board-mop500-regulators.h
+++ b/arch/arm/mach-ux500/board-mop500-regulators.h
@@ -14,10 +14,11 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>
-extern struct ab8500_regulator_reg_init
-ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS];
-extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS];
+extern struct ab8500_regulator_platform_data ab8500_regulator_plat_data;
+extern struct ab8500_regulator_platform_data ab8505_regulator_plat_data;
extern struct regulator_init_data tps61052_regulator;
extern struct regulator_init_data gpio_en_3v3_regulator;
+void mop500_regulator_init(void);
+
#endif
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
index 051b62c27102..7f2cb6c5e2c1 100644
--- a/arch/arm/mach-ux500/board-mop500-sdi.c
+++ b/arch/arm/mach-ux500/board-mop500-sdi.c
@@ -81,7 +81,6 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
#endif
struct mmci_platform_data mop500_sdi0_data = {
- .ios_handler = mop500_sdi0_ios_handler,
.ocr_mask = MMC_VDD_29_30,
.f_max = 50000000,
.capabilities = MMC_CAP_4_BIT_DATA |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index b03457881c4b..ce672378a830 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-nomadik.h>
@@ -198,10 +199,7 @@ static struct platform_device snowball_sbnet_dev = {
struct ab8500_platform_data ab8500_platdata = {
.irq_base = MOP500_AB8500_IRQ_BASE,
- .regulator_reg_init = ab8500_regulator_reg_init,
- .num_regulator_reg_init = ARRAY_SIZE(ab8500_regulator_reg_init),
- .regulator = ab8500_regulators,
- .num_regulator = ARRAY_SIZE(ab8500_regulators),
+ .regulator = &ab8500_regulator_plat_data,
.gpio = &ab8500_gpio_pdata,
.codec = &ab8500_codec_pdata,
};
@@ -439,6 +437,15 @@ static void mop500_prox_deactivate(struct device *dev)
regulator_put(prox_regulator);
}
+void mop500_snowball_ethernet_clock_enable(void)
+{
+ struct clk *clk;
+
+ clk = clk_get_sys("fsmc", NULL);
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+}
+
static struct cryp_platform_data u8500_cryp1_platform_data = {
.mem_to_engine = {
.dir = STEDMA40_MEM_TO_PERIPH,
@@ -683,6 +690,8 @@ static void __init snowball_init_machine(void)
mop500_audio_init(parent);
mop500_uart_init(parent);
+ mop500_snowball_ethernet_clock_enable();
+
/* This board has full regulator constraints */
regulator_has_full_constraints();
}
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
index eaa605f5d90d..d38951be70df 100644
--- a/arch/arm/mach-ux500/board-mop500.h
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -104,6 +104,7 @@ void __init mop500_pinmaps_init(void);
void __init snowball_pinmaps_init(void);
void __init hrefv60_pinmaps_init(void);
void mop500_audio_init(struct device *parent);
+void mop500_snowball_ethernet_clock_enable(void);
int __init mop500_uib_init(void);
void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 19235cf7bbe3..f1a581844372 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -312,9 +312,10 @@ static void __init u8500_init_machine(void)
/* Pinmaps must be in place before devices register */
if (of_machine_is_compatible("st-ericsson,mop500"))
mop500_pinmaps_init();
- else if (of_machine_is_compatible("calaosystems,snowball-a9500"))
+ else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
snowball_pinmaps_init();
- else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
+ mop500_snowball_ethernet_clock_enable();
+ } else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
hrefv60_pinmaps_init();
else if (of_machine_is_compatible("st-ericsson,ccu9540")) {}
/* TODO: Add pinmaps for ccu9540 board. */
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
index ce9149302cc3..488e07472d98 100644
--- a/arch/arm/mach-ux500/cpuidle.c
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/cpuidle.h>
-#include <linux/clockchips.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
#include <linux/smp.h>
@@ -22,7 +21,6 @@
static atomic_t master = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(master_lock);
-static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device);
static inline int ux500_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
@@ -30,8 +28,6 @@ static inline int ux500_enter_idle(struct cpuidle_device *dev,
int this_cpu = smp_processor_id();
bool recouple = false;
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu);
-
if (atomic_inc_return(&master) == num_online_cpus()) {
/* With this lock, we prevent the other cpu to exit and enter
@@ -91,22 +87,20 @@ out:
spin_unlock(&master_lock);
}
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
-
return index;
}
static struct cpuidle_driver ux500_idle_driver = {
.name = "ux500_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states = {
ARM_CPUIDLE_WFI_STATE,
{
.enter = ux500_enter_idle,
.exit_latency = 70,
.target_residency = 260,
- .flags = CPUIDLE_FLAG_TIME_VALID,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_TIMER_STOP,
.name = "ApIdle",
.desc = "ARM Retention",
},
@@ -115,59 +109,13 @@ static struct cpuidle_driver ux500_idle_driver = {
.state_count = 2,
};
-/*
- * For each cpu, setup the broadcast timer because we will
- * need to migrate the timers for the states >= ApIdle.
- */
-static void ux500_setup_broadcast_timer(void *arg)
-{
- int cpu = smp_processor_id();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
-}
-
int __init ux500_idle_init(void)
{
- int ret, cpu;
- struct cpuidle_device *device;
-
/* Configure wake up reasons */
prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
PRCMU_WAKEUP(ABB));
- /*
- * Configure the timer broadcast for each cpu, that must
- * be done from the cpu context, so we use a smp cross
- * call with 'on_each_cpu'.
- */
- on_each_cpu(ux500_setup_broadcast_timer, NULL, 1);
-
- ret = cpuidle_register_driver(&ux500_idle_driver);
- if (ret) {
- printk(KERN_ERR "failed to register ux500 idle driver\n");
- return ret;
- }
-
- for_each_online_cpu(cpu) {
- device = &per_cpu(ux500_cpuidle_device, cpu);
- device->cpu = cpu;
- ret = cpuidle_register_device(device);
- if (ret) {
- printk(KERN_ERR "Failed to register cpuidle "
- "device for cpu%d\n", cpu);
- goto out_unregister;
- }
- }
-out:
- return ret;
-
-out_unregister:
- for_each_online_cpu(cpu) {
- device = &per_cpu(ux500_cpuidle_device, cpu);
- cpuidle_unregister_device(device);
- }
-
- cpuidle_unregister_driver(&ux500_idle_driver);
- goto out;
+ return cpuidle_register(&ux500_idle_driver, NULL);
}
device_initcall(ux500_idle_init);
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 52d315b792c8..0f1c5e53fb27 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -17,6 +17,9 @@ config ARCH_VEXPRESS
select NO_IOPORT
select PLAT_VERSATILE
select PLAT_VERSATILE_CLCD
+ select POWER_RESET
+ select POWER_RESET_VEXPRESS
+ select POWER_SUPPLY
select REGULATOR_FIXED_VOLTAGE if REGULATOR
select VEXPRESS_CONFIG
help
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 80b64971fbdd..42703e8b4d3b 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -4,7 +4,7 @@
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-versatile/include
-obj-y := v2m.o reset.o
+obj-y := v2m.o
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 915683cb67d6..eb2b3a627f03 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -21,6 +21,8 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/vexpress.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
#include <asm/arch_timer.h>
#include <asm/mach-types.h>
@@ -361,8 +363,6 @@ static void __init v2m_init(void)
for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
amba_device_register(v2m_amba_devs[i], &iomem_resource);
- pm_power_off = vexpress_power_off;
-
ct_desc->init_tile();
}
@@ -374,7 +374,6 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.init_irq = v2m_init_irq,
.init_time = v2m_timer_init,
.init_machine = v2m_init,
- .restart = vexpress_restart,
MACHINE_END
static struct map_desc v2m_rs1_io_desc __initdata = {
@@ -433,7 +432,7 @@ static void __init v2m_dt_timer_init(void)
{
struct device_node *node = NULL;
- vexpress_clk_of_init();
+ of_clk_init(NULL);
do {
node = of_find_compatible_node(node, NULL, "arm,sp804");
@@ -441,6 +440,10 @@ static void __init v2m_dt_timer_init(void)
if (node) {
pr_info("Using SP804 '%s' as a clock & events source\n",
node->full_name);
+ WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
+ "timclken1"), "v2m-timer0", "sp804"));
+ WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
+ "timclken2"), "v2m-timer1", "sp804"));
v2m_sp804_init(of_iomap(node, 0),
irq_of_parse_and_map(node, 0));
}
@@ -464,7 +467,6 @@ static void __init v2m_dt_init(void)
{
l2x0_of_init(0x00400000, 0xfe0fffff);
of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
- pm_power_off = vexpress_power_off;
}
static const char * const v2m_dt_match[] __initconst = {
@@ -481,5 +483,4 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
.init_irq = irqchip_init,
.init_time = v2m_dt_timer_init,
.init_machine = v2m_dt_init,
- .restart = vexpress_restart,
MACHINE_END
diff --git a/arch/arm/mach-w90x900/dev.c b/arch/arm/mach-w90x900/dev.c
index 7abdb9645c5b..e65a80a1ac75 100644
--- a/arch/arm/mach-w90x900/dev.c
+++ b/arch/arm/mach-w90x900/dev.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/cpu.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/mtd.h>
@@ -531,7 +532,7 @@ static struct platform_device *nuc900_public_dev[] __initdata = {
void __init nuc900_board_init(struct platform_device **device, int size)
{
- disable_hlt();
+ cpu_idle_poll_ctrl(true);
platform_add_devices(device, size);
platform_add_devices(nuc900_public_dev, ARRAY_SIZE(nuc900_public_dev));
spi_register_board_info(nuc900_spi_board_info,
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 025d17328730..4045c4931a30 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -43,7 +43,7 @@ config CPU_ARM740T
depends on !MMU
select CPU_32v4T
select CPU_ABRT_LV4T
- select CPU_CACHE_V3 # although the core is v4t
+ select CPU_CACHE_V4
select CPU_CP15_MPU
select CPU_PABRT_LEGACY
help
@@ -469,9 +469,6 @@ config CPU_PABRT_V7
bool
# The cache model
-config CPU_CACHE_V3
- bool
-
config CPU_CACHE_V4
bool
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 4e333fa2756f..9e51be96f635 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -33,7 +33,6 @@ obj-$(CONFIG_CPU_PABRT_LEGACY) += pabort-legacy.o
obj-$(CONFIG_CPU_PABRT_V6) += pabort-v6.o
obj-$(CONFIG_CPU_PABRT_V7) += pabort-v7.o
-obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o
obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o
obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o
obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o
diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c
index dd3d59122cc3..48bc3c0a87ce 100644
--- a/arch/arm/mm/cache-feroceon-l2.c
+++ b/arch/arm/mm/cache-feroceon-l2.c
@@ -343,6 +343,7 @@ void __init feroceon_l2_init(int __l2_wt_override)
outer_cache.inv_range = feroceon_l2_inv_range;
outer_cache.clean_range = feroceon_l2_clean_range;
outer_cache.flush_range = feroceon_l2_flush_range;
+ outer_cache.inv_all = l2_inv_all;
enable_l2();
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c2f37390308a..c465faca51b0 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -299,7 +299,7 @@ static void l2x0_unlock(u32 cache_id)
int lockregs;
int i;
- switch (cache_id) {
+ switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L310:
lockregs = 8;
break;
@@ -333,15 +333,14 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
if (cache_id_part_number_from_dt)
cache_id = cache_id_part_number_from_dt;
else
- cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID)
- & L2X0_CACHE_ID_PART_MASK;
+ cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
aux &= aux_mask;
aux |= aux_val;
/* Determine the number of ways */
- switch (cache_id) {
+ switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
case L2X0_CACHE_ID_PART_L310:
if (aux & (1 << 16))
ways = 16;
@@ -725,7 +724,6 @@ static const struct l2x0_of_data pl310_data = {
.flush_all = l2x0_flush_all,
.inv_all = l2x0_inv_all,
.disable = l2x0_disable,
- .set_debug = pl310_set_debug,
},
};
@@ -814,9 +812,8 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
data->save();
of_init = true;
- l2x0_init(l2x0_base, aux_val, aux_mask);
-
memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache));
+ l2x0_init(l2x0_base, aux_val, aux_mask);
return 0;
}
diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S
deleted file mode 100644
index 8a3fadece8d3..000000000000
--- a/arch/arm/mm/cache-v3.S
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * linux/arch/arm/mm/cache-v3.S
- *
- * Copyright (C) 1997-2002 Russell king
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/page.h>
-#include "proc-macros.S"
-
-/*
- * flush_icache_all()
- *
- * Unconditionally clean and invalidate the entire icache.
- */
-ENTRY(v3_flush_icache_all)
- mov pc, lr
-ENDPROC(v3_flush_icache_all)
-
-/*
- * flush_user_cache_all()
- *
- * Invalidate all cache entries in a particular address
- * space.
- *
- * - mm - mm_struct describing address space
- */
-ENTRY(v3_flush_user_cache_all)
- /* FALLTHROUGH */
-/*
- * flush_kern_cache_all()
- *
- * Clean and invalidate the entire cache.
- */
-ENTRY(v3_flush_kern_cache_all)
- /* FALLTHROUGH */
-
-/*
- * flush_user_cache_range(start, end, flags)
- *
- * Invalidate a range of cache entries in the specified
- * address space.
- *
- * - start - start address (may not be aligned)
- * - end - end address (exclusive, may not be aligned)
- * - flags - vma_area_struct flags describing address space
- */
-ENTRY(v3_flush_user_cache_range)
- mov ip, #0
- mcreq p15, 0, ip, c7, c0, 0 @ flush ID cache
- mov pc, lr
-
-/*
- * coherent_kern_range(start, end)
- *
- * Ensure coherency between the Icache and the Dcache in the
- * region described by start. If you have non-snooping
- * Harvard caches, you need to implement this function.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v3_coherent_kern_range)
- /* FALLTHROUGH */
-
-/*
- * coherent_user_range(start, end)
- *
- * Ensure coherency between the Icache and the Dcache in the
- * region described by start. If you have non-snooping
- * Harvard caches, you need to implement this function.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v3_coherent_user_range)
- mov r0, #0
- mov pc, lr
-
-/*
- * flush_kern_dcache_area(void *page, size_t size)
- *
- * Ensure no D cache aliasing occurs, either with itself or
- * the I cache
- *
- * - addr - kernel address
- * - size - region size
- */
-ENTRY(v3_flush_kern_dcache_area)
- /* FALLTHROUGH */
-
-/*
- * dma_flush_range(start, end)
- *
- * Clean and invalidate the specified virtual address range.
- *
- * - start - virtual start address
- * - end - virtual end address
- */
-ENTRY(v3_dma_flush_range)
- mov r0, #0
- mcr p15, 0, r0, c7, c0, 0 @ flush ID cache
- mov pc, lr
-
-/*
- * dma_unmap_area(start, size, dir)
- * - start - kernel virtual start address
- * - size - size of region
- * - dir - DMA direction
- */
-ENTRY(v3_dma_unmap_area)
- teq r2, #DMA_TO_DEVICE
- bne v3_dma_flush_range
- /* FALLTHROUGH */
-
-/*
- * dma_map_area(start, size, dir)
- * - start - kernel virtual start address
- * - size - size of region
- * - dir - DMA direction
- */
-ENTRY(v3_dma_map_area)
- mov pc, lr
-ENDPROC(v3_dma_unmap_area)
-ENDPROC(v3_dma_map_area)
-
- .globl v3_flush_kern_cache_louis
- .equ v3_flush_kern_cache_louis, v3_flush_kern_cache_all
-
- __INITDATA
-
- @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
- define_cache_functions v3
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index 43e5d77be677..a7ba68f59f0c 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -58,7 +58,7 @@ ENTRY(v4_flush_kern_cache_all)
ENTRY(v4_flush_user_cache_range)
#ifdef CONFIG_CPU_CP15
mov ip, #0
- mcreq p15, 0, ip, c7, c7, 0 @ flush ID cache
+ mcr p15, 0, ip, c7, c7, 0 @ flush ID cache
mov pc, lr
#else
/* FALLTHROUGH */
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index a5a4b2bc42ba..2ac37372ef52 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -48,7 +48,7 @@ static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION);
static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS);
-static DEFINE_PER_CPU(atomic64_t, active_asids);
+DEFINE_PER_CPU(atomic64_t, active_asids);
static DEFINE_PER_CPU(u64, reserved_asids);
static cpumask_t tlb_flush_pending;
@@ -215,6 +215,7 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
local_flush_bp_all();
local_flush_tlb_all();
+ dummy_flush_tlb_a15_erratum();
}
atomic64_set(&per_cpu(active_asids, cpu), asid);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index ad722f1208a5..9a5cdc01fcdf 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -99,6 +99,9 @@ void show_mem(unsigned int filter)
printk("Mem-info:\n");
show_free_areas(filter);
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
+
for_each_bank (i, mi) {
struct membank *bank = &mi->bank[i];
unsigned int pfn1, pfn2;
@@ -424,24 +427,6 @@ void __init bootmem_init(void)
max_pfn = max_high - PHYS_PFN_OFFSET;
}
-static inline int free_area(unsigned long pfn, unsigned long end, char *s)
-{
- unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
-
- for (; pfn < end; pfn++) {
- struct page *page = pfn_to_page(pfn);
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- pages++;
- }
-
- if (size && s)
- printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
-
- return pages;
-}
-
/*
* Poison init memory with an undefined instruction (ARM) or a branch to an
* undefined instruction (Thumb).
@@ -534,6 +519,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
#endif
}
+#ifdef CONFIG_HIGHMEM
+static inline void free_area_high(unsigned long pfn, unsigned long end)
+{
+ for (; pfn < end; pfn++)
+ free_highmem_page(pfn_to_page(pfn));
+}
+#endif
+
static void __init free_highpages(void)
{
#ifdef CONFIG_HIGHMEM
@@ -569,8 +562,7 @@ static void __init free_highpages(void)
if (res_end > end)
res_end = end;
if (res_start != start)
- totalhigh_pages += free_area(start, res_start,
- NULL);
+ free_area_high(start, res_start);
start = res_end;
if (start == end)
break;
@@ -578,9 +570,8 @@ static void __init free_highpages(void)
/* And now free anything which remains */
if (start < end)
- totalhigh_pages += free_area(start, end, NULL);
+ free_area_high(start, end);
}
- totalram_pages += totalhigh_pages;
#endif
}
@@ -609,8 +600,7 @@ void __init mem_init(void)
#ifdef CONFIG_SA1111
/* now that our DMA memory is actually so designated, we can free it */
- totalram_pages += free_area(PHYS_PFN_OFFSET,
- __phys_to_pfn(__pa(swapper_pg_dir)), NULL);
+ free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, 0, NULL);
#endif
free_highpages();
@@ -738,16 +728,12 @@ void free_initmem(void)
extern char __tcm_start, __tcm_end;
poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
- totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)),
- __phys_to_pfn(__pa(&__tcm_end)),
- "TCM link");
+ free_reserved_area(&__tcm_start, &__tcm_end, 0, "TCM link");
#endif
poison_init_mem(__init_begin, __init_end - __init_begin);
if (!machine_is_integrator() && !machine_is_cintegrator())
- totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
- __phys_to_pfn(__pa(__init_end)),
- "init");
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -758,9 +744,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
{
if (!keep_initrd) {
poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
- totalram_pages += free_area(__phys_to_pfn(__pa(start)),
- __phys_to_pfn(__pa(end)),
- "initrd");
+ free_reserved_area(start, end, 0, "initrd");
}
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index e95a996ab78f..a84ff763ac39 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -34,6 +34,7 @@
#include <asm/mach/pci.h>
#include "mm.h"
+#include "tcm.h"
/*
* empty_zero_page is a special page that is used for
@@ -598,39 +599,60 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
} while (pte++, addr += PAGE_SIZE, addr != end);
}
-static void __init alloc_init_section(pud_t *pud, unsigned long addr,
- unsigned long end, phys_addr_t phys,
- const struct mem_type *type)
+static void __init map_init_section(pmd_t *pmd, unsigned long addr,
+ unsigned long end, phys_addr_t phys,
+ const struct mem_type *type)
{
- pmd_t *pmd = pmd_offset(pud, addr);
-
+#ifndef CONFIG_ARM_LPAE
/*
- * Try a section mapping - end, addr and phys must all be aligned
- * to a section boundary. Note that PMDs refer to the individual
- * L1 entries, whereas PGDs refer to a group of L1 entries making
- * up one logical pointer to an L2 table.
+ * In classic MMU format, puds and pmds are folded in to
+ * the pgds. pmd_offset gives the PGD entry. PGDs refer to a
+ * group of L1 entries making up one logical pointer to
+ * an L2 table (2MB), where as PMDs refer to the individual
+ * L1 entries (1MB). Hence increment to get the correct
+ * offset for odd 1MB sections.
+ * (See arch/arm/include/asm/pgtable-2level.h)
*/
- if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
- pmd_t *p = pmd;
-
-#ifndef CONFIG_ARM_LPAE
- if (addr & SECTION_SIZE)
- pmd++;
+ if (addr & SECTION_SIZE)
+ pmd++;
#endif
+ do {
+ *pmd = __pmd(phys | type->prot_sect);
+ phys += SECTION_SIZE;
+ } while (pmd++, addr += SECTION_SIZE, addr != end);
- do {
- *pmd = __pmd(phys | type->prot_sect);
- phys += SECTION_SIZE;
- } while (pmd++, addr += SECTION_SIZE, addr != end);
+ flush_pmd_entry(pmd);
+}
- flush_pmd_entry(p);
- } else {
+static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
+ unsigned long end, phys_addr_t phys,
+ const struct mem_type *type)
+{
+ pmd_t *pmd = pmd_offset(pud, addr);
+ unsigned long next;
+
+ do {
/*
- * No need to loop; pte's aren't interested in the
- * individual L1 entries.
+ * With LPAE, we must loop over to map
+ * all the pmds for the given range.
*/
- alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
- }
+ next = pmd_addr_end(addr, end);
+
+ /*
+ * Try a section mapping - addr, next and phys must all be
+ * aligned to a section boundary.
+ */
+ if (type->prot_sect &&
+ ((addr | next | phys) & ~SECTION_MASK) == 0) {
+ map_init_section(pmd, addr, next, phys, type);
+ } else {
+ alloc_init_pte(pmd, addr, next,
+ __phys_to_pfn(phys), type);
+ }
+
+ phys += next - addr;
+
+ } while (pmd++, addr = next, addr != end);
}
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
@@ -641,7 +663,7 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
do {
next = pud_addr_end(addr, end);
- alloc_init_section(pud, addr, next, phys, type);
+ alloc_init_pmd(pud, addr, next, phys, type);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
@@ -1256,6 +1278,7 @@ void __init paging_init(struct machine_desc *mdesc)
dma_contiguous_remap();
devicemaps_init(mdesc);
kmap_init();
+ tcm_init();
top_pmd = pmd_off_k(0xffff0000);
diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
index dc5de5d53f20..fde2d2a794cf 100644
--- a/arch/arm/mm/proc-arm740.S
+++ b/arch/arm/mm/proc-arm740.S
@@ -77,24 +77,27 @@ __arm740_setup:
mcr p15, 0, r0, c6, c0 @ set area 0, default
ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
- ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
- mov r2, #10 @ 11 is the minimum (4KB)
-1: add r2, r2, #1 @ area size *= 2
- mov r1, r1, lsr #1
+ ldr r3, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
+ mov r4, #10 @ 11 is the minimum (4KB)
+1: add r4, r4, #1 @ area size *= 2
+ movs r3, r3, lsr #1
bne 1b @ count not zero r-shift
- orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, r4, lsl #1 @ the area register value
orr r0, r0, #1 @ set enable bit
mcr p15, 0, r0, c6, c1 @ set area 1, RAM
ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
- ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
- mov r2, #10 @ 11 is the minimum (4KB)
-1: add r2, r2, #1 @ area size *= 2
- mov r1, r1, lsr #1
+ ldr r3, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
+ cmp r3, #0
+ moveq r0, #0
+ beq 2f
+ mov r4, #10 @ 11 is the minimum (4KB)
+1: add r4, r4, #1 @ area size *= 2
+ movs r3, r3, lsr #1
bne 1b @ count not zero r-shift
- orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, r4, lsl #1 @ the area register value
orr r0, r0, #1 @ set enable bit
- mcr p15, 0, r0, c6, c2 @ set area 2, ROM/FLASH
+2: mcr p15, 0, r0, c6, c2 @ set area 2, ROM/FLASH
mov r0, #0x06
mcr p15, 0, r0, c2, c0 @ Region 1&2 cacheable
@@ -137,13 +140,14 @@ __arm740_proc_info:
.long 0x41807400
.long 0xfffffff0
.long 0
+ .long 0
b __arm740_setup
.long cpu_arch_name
.long cpu_elf_name
- .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT
.long cpu_arm740_name
.long arm740_processor_functions
.long 0
.long 0
- .long v3_cache_fns @ cache model
+ .long v4_cache_fns @ cache model
.size __arm740_proc_info, . - __arm740_proc_info
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 2c3b9421ab5e..2556cf1c2da1 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -387,7 +387,7 @@ ENTRY(cpu_arm920_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm920_suspend_size
.equ cpu_arm920_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_arm920_do_suspend)
stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index f1803f7e2972..344c8a548cc0 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -402,7 +402,7 @@ ENTRY(cpu_arm926_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/plat-s3c24xx/sleep.S */
.globl cpu_arm926_suspend_size
.equ cpu_arm926_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_arm926_do_suspend)
stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index 82f9cdc751d6..0b60dd3d742a 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -350,7 +350,7 @@ ENTRY(cpu_mohawk_set_pte_ext)
.globl cpu_mohawk_suspend_size
.equ cpu_mohawk_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_mohawk_do_suspend)
stmfd sp!, {r4 - r9, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 3aa0da11fd84..d92dfd081429 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -172,7 +172,7 @@ ENTRY(cpu_sa1100_set_pte_ext)
.globl cpu_sa1100_suspend_size
.equ cpu_sa1100_suspend_size, 4 * 3
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_sa1100_do_suspend)
stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c3, c0, 0 @ domain ID
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
index 3e6210b4d6d4..054b491ff764 100644
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -17,7 +17,9 @@
#ifndef MULTI_CPU
EXPORT_SYMBOL(cpu_dcache_clean_area);
+#ifdef CONFIG_MMU
EXPORT_SYMBOL(cpu_set_pte_ext);
+#endif
#else
EXPORT_SYMBOL(processor);
#endif
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index bcaaa8de9325..5c07ee4fe3eb 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -138,7 +138,7 @@ ENTRY(cpu_v6_set_pte_ext)
/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
.globl cpu_v6_suspend_size
.equ cpu_v6_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v6_do_suspend)
stmfd sp!, {r4 - r9, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 3a3c015f8d5c..f584d3f5b37c 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -420,7 +420,7 @@ __v7_pj4b_proc_info:
__v7_ca7mp_proc_info:
.long 0x410fc070
.long 0xff0ffff0
- __v7_proc __v7_ca7mp_setup, hwcaps = HWCAP_IDIV
+ __v7_proc __v7_ca7mp_setup
.size __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info
/*
@@ -430,10 +430,25 @@ __v7_ca7mp_proc_info:
__v7_ca15mp_proc_info:
.long 0x410fc0f0
.long 0xff0ffff0
- __v7_proc __v7_ca15mp_setup, hwcaps = HWCAP_IDIV
+ __v7_proc __v7_ca15mp_setup
.size __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
/*
+ * Qualcomm Inc. Krait processors.
+ */
+ .type __krait_proc_info, #object
+__krait_proc_info:
+ .long 0x510f0400 @ Required ID value
+ .long 0xff0ffc00 @ Mask for ID
+ /*
+ * Some Krait processors don't indicate support for SDIV and UDIV
+ * instructions in the ARM instruction set, even though they actually
+ * do support them.
+ */
+ __v7_proc __v7_setup, hwcaps = HWCAP_IDIV
+ .size __krait_proc_info, . - __krait_proc_info
+
+ /*
* Match any ARMv7 processor core.
*/
.type __v7_proc_info, #object
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index eb93d6487f35..e8efd83b6f25 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -413,7 +413,7 @@ ENTRY(cpu_xsc3_set_pte_ext)
.globl cpu_xsc3_suspend_size
.equ cpu_xsc3_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_xsc3_do_suspend)
stmfd sp!, {r4 - r9, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 25510361aa18..e766f889bfd6 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -528,7 +528,7 @@ ENTRY(cpu_xscale_set_pte_ext)
.globl cpu_xscale_suspend_size
.equ cpu_xscale_suspend_size, 4 * 6
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_xscale_do_suspend)
stmfd sp!, {r4 - r9, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
diff --git a/arch/arm/kernel/tcm.h b/arch/arm/mm/tcm.h
index 8015ad434a40..8015ad434a40 100644
--- a/arch/arm/kernel/tcm.h
+++ b/arch/arm/mm/tcm.h
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index a0bd8a755bdf..1a643ee8e082 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -918,9 +918,8 @@ void bpf_jit_compile(struct sk_filter *fp)
#endif
if (bpf_jit_enable > 1)
- print_hex_dump(KERN_INFO, "BPF JIT code: ",
- DUMP_PREFIX_ADDRESS, 16, 4, ctx.target,
- alloc_size, false);
+ /* there are 2 passes here */
+ bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
fp->bpf_func = (void *)ctx.target;
out:
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index 2d4b6414609f..251f827271e9 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -238,6 +238,7 @@ static __init void ge_complete(
struct mv643xx_eth_shared_platform_data *orion_ge_shared_data,
struct resource *orion_ge_resource, unsigned long irq,
struct platform_device *orion_ge_shared,
+ struct platform_device *orion_ge_mvmdio,
struct mv643xx_eth_platform_data *eth_data,
struct platform_device *orion_ge)
{
@@ -247,6 +248,8 @@ static __init void ge_complete(
orion_ge->dev.platform_data = eth_data;
platform_device_register(orion_ge_shared);
+ if (orion_ge_mvmdio)
+ platform_device_register(orion_ge_mvmdio);
platform_device_register(orion_ge);
}
@@ -258,8 +261,6 @@ struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
static struct resource orion_ge00_shared_resources[] = {
{
.name = "ge00 base",
- }, {
- .name = "ge00 err irq",
},
};
@@ -271,6 +272,19 @@ static struct platform_device orion_ge00_shared = {
},
};
+static struct resource orion_ge_mvmdio_resources[] = {
+ {
+ .name = "ge00 mvmdio base",
+ }, {
+ .name = "ge00 mvmdio err irq",
+ },
+};
+
+static struct platform_device orion_ge_mvmdio = {
+ .name = "orion-mdio",
+ .id = -1,
+};
+
static struct resource orion_ge00_resources[] = {
{
.name = "ge00 irq",
@@ -295,26 +309,25 @@ void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
unsigned int tx_csum_limit)
{
fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, irq_err);
+ mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
+ fill_resources(&orion_ge_mvmdio, orion_ge_mvmdio_resources,
+ mapbase + 0x2004, 0x84 - 1, irq_err);
orion_ge00_shared_data.tx_csum_limit = tx_csum_limit;
ge_complete(&orion_ge00_shared_data,
orion_ge00_resources, irq, &orion_ge00_shared,
+ &orion_ge_mvmdio,
eth_data, &orion_ge00);
}
/*****************************************************************************
* GE01
****************************************************************************/
-struct mv643xx_eth_shared_platform_data orion_ge01_shared_data = {
- .shared_smi = &orion_ge00_shared,
-};
+struct mv643xx_eth_shared_platform_data orion_ge01_shared_data;
static struct resource orion_ge01_shared_resources[] = {
{
.name = "ge01 base",
- }, {
- .name = "ge01 err irq",
- },
+ }
};
static struct platform_device orion_ge01_shared = {
@@ -349,26 +362,23 @@ void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned int tx_csum_limit)
{
fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, irq_err);
+ mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
orion_ge01_shared_data.tx_csum_limit = tx_csum_limit;
ge_complete(&orion_ge01_shared_data,
orion_ge01_resources, irq, &orion_ge01_shared,
+ NULL,
eth_data, &orion_ge01);
}
/*****************************************************************************
* GE10
****************************************************************************/
-struct mv643xx_eth_shared_platform_data orion_ge10_shared_data = {
- .shared_smi = &orion_ge00_shared,
-};
+struct mv643xx_eth_shared_platform_data orion_ge10_shared_data;
static struct resource orion_ge10_shared_resources[] = {
{
.name = "ge10 base",
- }, {
- .name = "ge10 err irq",
- },
+ }
};
static struct platform_device orion_ge10_shared = {
@@ -402,24 +412,21 @@ void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long irq_err)
{
fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, irq_err);
+ mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
ge_complete(&orion_ge10_shared_data,
orion_ge10_resources, irq, &orion_ge10_shared,
+ NULL,
eth_data, &orion_ge10);
}
/*****************************************************************************
* GE11
****************************************************************************/
-struct mv643xx_eth_shared_platform_data orion_ge11_shared_data = {
- .shared_smi = &orion_ge00_shared,
-};
+struct mv643xx_eth_shared_platform_data orion_ge11_shared_data;
static struct resource orion_ge11_shared_resources[] = {
{
.name = "ge11 base",
- }, {
- .name = "ge11 err irq",
},
};
@@ -454,9 +461,10 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long irq_err)
{
fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
- mapbase + 0x2000, SZ_16K - 1, irq_err);
+ mapbase + 0x2000, SZ_16K - 1, NO_IRQ);
ge_complete(&orion_ge11_shared_data,
orion_ge11_resources, irq, &orion_ge11_shared,
+ NULL,
eth_data, &orion_ge11);
}
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 51afedda9ab6..03db14d8ace9 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/amba/pl330.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
@@ -1552,6 +1553,9 @@ void __init s3c64xx_spi0_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi0_cfg_gpio;
+#ifdef CONFIG_PL330_DMA
+ pd.filter = pl330_filter;
+#endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0);
}
@@ -1590,6 +1594,9 @@ void __init s3c64xx_spi1_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi1_cfg_gpio;
+#ifdef CONFIG_PL330_DMA
+ pd.filter = pl330_filter;
+#endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi1);
}
@@ -1628,6 +1635,9 @@ void __init s3c64xx_spi2_set_platdata(int (*cfg_gpio)(void), int src_clk_nr,
pd.num_cs = num_cs;
pd.src_clk_nr = src_clk_nr;
pd.cfg_gpio = (cfg_gpio) ? cfg_gpio : s3c64xx_spi2_cfg_gpio;
+#ifdef CONFIG_PL330_DMA
+ pd.filter = pl330_filter;
+#endif
s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi2);
}
diff --git a/arch/arm/plat-samsung/include/plat/fb.h b/arch/arm/plat-samsung/include/plat/fb.h
index b885322717a1..9ae507270785 100644
--- a/arch/arm/plat-samsung/include/plat/fb.h
+++ b/arch/arm/plat-samsung/include/plat/fb.h
@@ -15,55 +15,7 @@
#ifndef __PLAT_S3C_FB_H
#define __PLAT_S3C_FB_H __FILE__
-/* S3C_FB_MAX_WIN
- * Set to the maximum number of windows that any of the supported hardware
- * can use. Since the platform data uses this for an array size, having it
- * set to the maximum of any version of the hardware can do is safe.
- */
-#define S3C_FB_MAX_WIN (5)
-
-/**
- * struct s3c_fb_pd_win - per window setup data
- * @xres : The window X size.
- * @yres : The window Y size.
- * @virtual_x: The virtual X size.
- * @virtual_y: The virtual Y size.
- */
-struct s3c_fb_pd_win {
- unsigned short default_bpp;
- unsigned short max_bpp;
- unsigned short xres;
- unsigned short yres;
- unsigned short virtual_x;
- unsigned short virtual_y;
-};
-
-/**
- * struct s3c_fb_platdata - S3C driver platform specific information
- * @setup_gpio: Setup the external GPIO pins to the right state to transfer
- * the data from the display system to the connected display
- * device.
- * @vidcon0: The base vidcon0 values to control the panel data format.
- * @vidcon1: The base vidcon1 values to control the panel data output.
- * @vtiming: Video timing when connected to a RGB type panel.
- * @win: The setup data for each hardware window, or NULL for unused.
- * @display_mode: The LCD output display mode.
- *
- * The platform data supplies the video driver with all the information
- * it requires to work with the display(s) attached to the machine. It
- * controls the initial mode, the number of display windows (0 is always
- * the base framebuffer) that are initialised etc.
- *
- */
-struct s3c_fb_platdata {
- void (*setup_gpio)(void);
-
- struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN];
- struct fb_videomode *vtiming;
-
- u32 vidcon0;
- u32 vidcon1;
-};
+#include <linux/platform_data/video_s3c.h>
/**
* s3c_fb_set_platdata() - Setup the FB device with platform data.
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h
index 29c26a818842..f05f2afa440d 100644
--- a/arch/arm/plat-samsung/include/plat/regs-serial.h
+++ b/arch/arm/plat-samsung/include/plat/regs-serial.h
@@ -1,281 +1 @@
-/* arch/arm/plat-samsung/include/plat/regs-serial.h
- *
- * From linux/include/asm-arm/hardware/serial_s3c2410.h
- *
- * Internal header file for Samsung S3C2410 serial ports (UART0-2)
- *
- * Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *
- * Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk)
- *
- * Adapted from:
- *
- * Internal header file for MX1ADS serial ports (UART1 & 2)
- *
- * Copyright (C) 2002 Shane Nay (shane@minirl.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef __ASM_ARM_REGS_SERIAL_H
-#define __ASM_ARM_REGS_SERIAL_H
-
-#define S3C24XX_VA_UART0 (S3C_VA_UART)
-#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 )
-#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 )
-#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 )
-
-#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
-#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
-#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 )
-#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 )
-
-#define S3C2410_URXH (0x24)
-#define S3C2410_UTXH (0x20)
-#define S3C2410_ULCON (0x00)
-#define S3C2410_UCON (0x04)
-#define S3C2410_UFCON (0x08)
-#define S3C2410_UMCON (0x0C)
-#define S3C2410_UBRDIV (0x28)
-#define S3C2410_UTRSTAT (0x10)
-#define S3C2410_UERSTAT (0x14)
-#define S3C2410_UFSTAT (0x18)
-#define S3C2410_UMSTAT (0x1C)
-
-#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3))
-
-#define S3C2410_LCON_CS5 (0x0)
-#define S3C2410_LCON_CS6 (0x1)
-#define S3C2410_LCON_CS7 (0x2)
-#define S3C2410_LCON_CS8 (0x3)
-#define S3C2410_LCON_CSMASK (0x3)
-
-#define S3C2410_LCON_PNONE (0x0)
-#define S3C2410_LCON_PEVEN (0x5 << 3)
-#define S3C2410_LCON_PODD (0x4 << 3)
-#define S3C2410_LCON_PMASK (0x7 << 3)
-
-#define S3C2410_LCON_STOPB (1<<2)
-#define S3C2410_LCON_IRM (1<<6)
-
-#define S3C2440_UCON_CLKMASK (3<<10)
-#define S3C2440_UCON_CLKSHIFT (10)
-#define S3C2440_UCON_PCLK (0<<10)
-#define S3C2440_UCON_UCLK (1<<10)
-#define S3C2440_UCON_PCLK2 (2<<10)
-#define S3C2440_UCON_FCLK (3<<10)
-#define S3C2443_UCON_EPLL (3<<10)
-
-#define S3C6400_UCON_CLKMASK (3<<10)
-#define S3C6400_UCON_CLKSHIFT (10)
-#define S3C6400_UCON_PCLK (0<<10)
-#define S3C6400_UCON_PCLK2 (2<<10)
-#define S3C6400_UCON_UCLK0 (1<<10)
-#define S3C6400_UCON_UCLK1 (3<<10)
-
-#define S3C2440_UCON2_FCLK_EN (1<<15)
-#define S3C2440_UCON0_DIVMASK (15 << 12)
-#define S3C2440_UCON1_DIVMASK (15 << 12)
-#define S3C2440_UCON2_DIVMASK (7 << 12)
-#define S3C2440_UCON_DIVSHIFT (12)
-
-#define S3C2412_UCON_CLKMASK (3<<10)
-#define S3C2412_UCON_CLKSHIFT (10)
-#define S3C2412_UCON_UCLK (1<<10)
-#define S3C2412_UCON_USYSCLK (3<<10)
-#define S3C2412_UCON_PCLK (0<<10)
-#define S3C2412_UCON_PCLK2 (2<<10)
-
-#define S3C2410_UCON_CLKMASK (1 << 10)
-#define S3C2410_UCON_CLKSHIFT (10)
-#define S3C2410_UCON_UCLK (1<<10)
-#define S3C2410_UCON_SBREAK (1<<4)
-
-#define S3C2410_UCON_TXILEVEL (1<<9)
-#define S3C2410_UCON_RXILEVEL (1<<8)
-#define S3C2410_UCON_TXIRQMODE (1<<2)
-#define S3C2410_UCON_RXIRQMODE (1<<0)
-#define S3C2410_UCON_RXFIFO_TOI (1<<7)
-#define S3C2443_UCON_RXERR_IRQEN (1<<6)
-#define S3C2443_UCON_LOOPBACK (1<<5)
-
-#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
- S3C2410_UCON_RXILEVEL | \
- S3C2410_UCON_TXIRQMODE | \
- S3C2410_UCON_RXIRQMODE | \
- S3C2410_UCON_RXFIFO_TOI)
-
-#define S3C2410_UFCON_FIFOMODE (1<<0)
-#define S3C2410_UFCON_TXTRIG0 (0<<6)
-#define S3C2410_UFCON_RXTRIG8 (1<<4)
-#define S3C2410_UFCON_RXTRIG12 (2<<4)
-
-/* S3C2440 FIFO trigger levels */
-#define S3C2440_UFCON_RXTRIG1 (0<<4)
-#define S3C2440_UFCON_RXTRIG8 (1<<4)
-#define S3C2440_UFCON_RXTRIG16 (2<<4)
-#define S3C2440_UFCON_RXTRIG32 (3<<4)
-
-#define S3C2440_UFCON_TXTRIG0 (0<<6)
-#define S3C2440_UFCON_TXTRIG16 (1<<6)
-#define S3C2440_UFCON_TXTRIG32 (2<<6)
-#define S3C2440_UFCON_TXTRIG48 (3<<6)
-
-#define S3C2410_UFCON_RESETBOTH (3<<1)
-#define S3C2410_UFCON_RESETTX (1<<2)
-#define S3C2410_UFCON_RESETRX (1<<1)
-
-#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
- S3C2410_UFCON_TXTRIG0 | \
- S3C2410_UFCON_RXTRIG8 )
-
-#define S3C2410_UMCOM_AFC (1<<4)
-#define S3C2410_UMCOM_RTS_LOW (1<<0)
-
-#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */
-#define S3C2412_UMCON_AFC_56 (1<<5)
-#define S3C2412_UMCON_AFC_48 (2<<5)
-#define S3C2412_UMCON_AFC_40 (3<<5)
-#define S3C2412_UMCON_AFC_32 (4<<5)
-#define S3C2412_UMCON_AFC_24 (5<<5)
-#define S3C2412_UMCON_AFC_16 (6<<5)
-#define S3C2412_UMCON_AFC_8 (7<<5)
-
-#define S3C2410_UFSTAT_TXFULL (1<<9)
-#define S3C2410_UFSTAT_RXFULL (1<<8)
-#define S3C2410_UFSTAT_TXMASK (15<<4)
-#define S3C2410_UFSTAT_TXSHIFT (4)
-#define S3C2410_UFSTAT_RXMASK (15<<0)
-#define S3C2410_UFSTAT_RXSHIFT (0)
-
-/* UFSTAT S3C2443 same as S3C2440 */
-#define S3C2440_UFSTAT_TXFULL (1<<14)
-#define S3C2440_UFSTAT_RXFULL (1<<6)
-#define S3C2440_UFSTAT_TXSHIFT (8)
-#define S3C2440_UFSTAT_RXSHIFT (0)
-#define S3C2440_UFSTAT_TXMASK (63<<8)
-#define S3C2440_UFSTAT_RXMASK (63)
-
-#define S3C2410_UTRSTAT_TXE (1<<2)
-#define S3C2410_UTRSTAT_TXFE (1<<1)
-#define S3C2410_UTRSTAT_RXDR (1<<0)
-
-#define S3C2410_UERSTAT_OVERRUN (1<<0)
-#define S3C2410_UERSTAT_FRAME (1<<2)
-#define S3C2410_UERSTAT_BREAK (1<<3)
-#define S3C2443_UERSTAT_PARITY (1<<1)
-
-#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
- S3C2410_UERSTAT_FRAME | \
- S3C2410_UERSTAT_BREAK)
-
-#define S3C2410_UMSTAT_CTS (1<<0)
-#define S3C2410_UMSTAT_DeltaCTS (1<<2)
-
-#define S3C2443_DIVSLOT (0x2C)
-
-/* S3C64XX interrupt registers. */
-#define S3C64XX_UINTP 0x30
-#define S3C64XX_UINTSP 0x34
-#define S3C64XX_UINTM 0x38
-
-#define S3C64XX_UINTM_RXD (0)
-#define S3C64XX_UINTM_TXD (2)
-#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
-#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
-
-/* Following are specific to S5PV210 */
-#define S5PV210_UCON_CLKMASK (1<<10)
-#define S5PV210_UCON_CLKSHIFT (10)
-#define S5PV210_UCON_PCLK (0<<10)
-#define S5PV210_UCON_UCLK (1<<10)
-
-#define S5PV210_UFCON_TXTRIG0 (0<<8)
-#define S5PV210_UFCON_TXTRIG4 (1<<8)
-#define S5PV210_UFCON_TXTRIG8 (2<<8)
-#define S5PV210_UFCON_TXTRIG16 (3<<8)
-#define S5PV210_UFCON_TXTRIG32 (4<<8)
-#define S5PV210_UFCON_TXTRIG64 (5<<8)
-#define S5PV210_UFCON_TXTRIG128 (6<<8)
-#define S5PV210_UFCON_TXTRIG256 (7<<8)
-
-#define S5PV210_UFCON_RXTRIG1 (0<<4)
-#define S5PV210_UFCON_RXTRIG4 (1<<4)
-#define S5PV210_UFCON_RXTRIG8 (2<<4)
-#define S5PV210_UFCON_RXTRIG16 (3<<4)
-#define S5PV210_UFCON_RXTRIG32 (4<<4)
-#define S5PV210_UFCON_RXTRIG64 (5<<4)
-#define S5PV210_UFCON_RXTRIG128 (6<<4)
-#define S5PV210_UFCON_RXTRIG256 (7<<4)
-
-#define S5PV210_UFSTAT_TXFULL (1<<24)
-#define S5PV210_UFSTAT_RXFULL (1<<8)
-#define S5PV210_UFSTAT_TXMASK (255<<16)
-#define S5PV210_UFSTAT_TXSHIFT (16)
-#define S5PV210_UFSTAT_RXMASK (255<<0)
-#define S5PV210_UFSTAT_RXSHIFT (0)
-
-#define S3C2410_UCON_CLKSEL0 (1 << 0)
-#define S3C2410_UCON_CLKSEL1 (1 << 1)
-#define S3C2410_UCON_CLKSEL2 (1 << 2)
-#define S3C2410_UCON_CLKSEL3 (1 << 3)
-
-/* Default values for s5pv210 UCON and UFCON uart registers */
-#define S5PV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
- S3C2410_UCON_RXILEVEL | \
- S3C2410_UCON_TXIRQMODE | \
- S3C2410_UCON_RXIRQMODE | \
- S3C2410_UCON_RXFIFO_TOI | \
- S3C2443_UCON_RXERR_IRQEN)
-
-#define S5PV210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
- S5PV210_UFCON_TXTRIG4 | \
- S5PV210_UFCON_RXTRIG4)
-
-#ifndef __ASSEMBLY__
-
-/* configuration structure for per-machine configurations for the
- * serial port
- *
- * the pointer is setup by the machine specific initialisation from the
- * arch/arm/mach-s3c2410/ directory.
-*/
-
-struct s3c2410_uartcfg {
- unsigned char hwport; /* hardware port number */
- unsigned char unused;
- unsigned short flags;
- upf_t uart_flags; /* default uart flags */
- unsigned int clk_sel;
-
- unsigned int has_fracval;
-
- unsigned long ucon; /* value of ucon for port */
- unsigned long ulcon; /* value of ulcon for port */
- unsigned long ufcon; /* value of ufcon for port */
-};
-
-/* s3c24xx_uart_devs
- *
- * this is exported from the core as we cannot use driver_register(),
- * or platform_add_device() before the console_initcall()
-*/
-
-extern struct platform_device *s3c24xx_uart_devs[4];
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __ASM_ARM_REGS_SERIAL_H */
-
+#include <linux/serial_s3c.h>
diff --git a/arch/arm/plat-samsung/include/plat/usb-phy.h b/arch/arm/plat-samsung/include/plat/usb-phy.h
index 959bcdb03a25..ab34dfadb7f9 100644
--- a/arch/arm/plat-samsung/include/plat/usb-phy.h
+++ b/arch/arm/plat-samsung/include/plat/usb-phy.h
@@ -11,10 +11,7 @@
#ifndef __PLAT_SAMSUNG_USB_PHY_H
#define __PLAT_SAMSUNG_USB_PHY_H __FILE__
-enum s5p_usb_phy_type {
- S5P_USB_PHY_DEVICE,
- S5P_USB_PHY_HOST,
-};
+#include <linux/usb/samsung_usb_phy.h>
extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9b6d19f74078..73b6e764034c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -99,7 +99,16 @@ source "init/Kconfig"
source "kernel/Kconfig.freezer"
-menu "System Type"
+menu "Platform selection"
+
+config ARCH_VEXPRESS
+ bool "ARMv8 software model (Versatile Express)"
+ select ARCH_REQUIRE_GPIOLIB
+ select COMMON_CLK_VERSATILE
+ select VEXPRESS_CONFIG
+ help
+ This enables support for the ARMv8 software model (Versatile
+ Express).
endmenu
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 32ac0aef0068..68457e9e0975 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -1,3 +1,5 @@
+dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
+
targets += dtbs
targets += $(dtb-y)
diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts
new file mode 100644
index 000000000000..198682b6de31
--- /dev/null
+++ b/arch/arm64/boot/dts/foundation-v8.dts
@@ -0,0 +1,230 @@
+/*
+ * ARM Ltd.
+ *
+ * ARMv8 Foundation model DTS
+ */
+
+/dts-v1/;
+
+/ {
+ model = "Foundation-v8A";
+ compatible = "arm,foundation-aarch64", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x1>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x2>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x3>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0 0x80000000>,
+ <0x00000008 0x80000000 0 0x80000000>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x0 0x2c001000 0 0x1000>,
+ <0x0 0x2c002000 0 0x1000>,
+ <0x0 0x2c004000 0 0x2000>,
+ <0x0 0x2c006000 0 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xff01>,
+ <1 14 0xff01>,
+ <1 11 0xff01>,
+ <1 10 0xff01>;
+ clock-frequency = <100000000>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <0 60 4>,
+ <0 61 4>,
+ <0 62 4>,
+ <0 63 4>;
+ };
+
+ smb {
+ compatible = "arm,vexpress,v2m-p1", "simple-bus";
+ arm,v2m-memory-map = "rs1";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #size-cells = <1>;
+
+ ranges = <0 0 0 0x08000000 0x04000000>,
+ <1 0 0 0x14000000 0x04000000>,
+ <2 0 0 0x18000000 0x04000000>,
+ <3 0 0 0x1c000000 0x04000000>,
+ <4 0 0 0x0c000000 0x04000000>,
+ <5 0 0 0x10000000 0x04000000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 0 4>,
+ <0 0 1 &gic 0 1 4>,
+ <0 0 2 &gic 0 2 4>,
+ <0 0 3 &gic 0 3 4>,
+ <0 0 4 &gic 0 4 4>,
+ <0 0 5 &gic 0 5 4>,
+ <0 0 6 &gic 0 6 4>,
+ <0 0 7 &gic 0 7 4>,
+ <0 0 8 &gic 0 8 4>,
+ <0 0 9 &gic 0 9 4>,
+ <0 0 10 &gic 0 10 4>,
+ <0 0 11 &gic 0 11 4>,
+ <0 0 12 &gic 0 12 4>,
+ <0 0 13 &gic 0 13 4>,
+ <0 0 14 &gic 0 14 4>,
+ <0 0 15 &gic 0 15 4>,
+ <0 0 16 &gic 0 16 4>,
+ <0 0 17 &gic 0 17 4>,
+ <0 0 18 &gic 0 18 4>,
+ <0 0 19 &gic 0 19 4>,
+ <0 0 20 &gic 0 20 4>,
+ <0 0 21 &gic 0 21 4>,
+ <0 0 22 &gic 0 22 4>,
+ <0 0 23 &gic 0 23 4>,
+ <0 0 24 &gic 0 24 4>,
+ <0 0 25 &gic 0 25 4>,
+ <0 0 26 &gic 0 26 4>,
+ <0 0 27 &gic 0 27 4>,
+ <0 0 28 &gic 0 28 4>,
+ <0 0 29 &gic 0 29 4>,
+ <0 0 30 &gic 0 30 4>,
+ <0 0 31 &gic 0 31 4>,
+ <0 0 32 &gic 0 32 4>,
+ <0 0 33 &gic 0 33 4>,
+ <0 0 34 &gic 0 34 4>,
+ <0 0 35 &gic 0 35 4>,
+ <0 0 36 &gic 0 36 4>,
+ <0 0 37 &gic 0 37 4>,
+ <0 0 38 &gic 0 38 4>,
+ <0 0 39 &gic 0 39 4>,
+ <0 0 40 &gic 0 40 4>,
+ <0 0 41 &gic 0 41 4>,
+ <0 0 42 &gic 0 42 4>;
+
+ ethernet@2,02000000 {
+ compatible = "smsc,lan91c111";
+ reg = <2 0x02000000 0x10000>;
+ interrupts = <15>;
+ };
+
+ v2m_clk24mhz: clk24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "v2m:clk24mhz";
+ };
+
+ v2m_refclk1mhz: refclk1mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000>;
+ clock-output-names = "v2m:refclk1mhz";
+ };
+
+ v2m_refclk32khz: refclk32khz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "v2m:refclk32khz";
+ };
+
+ iofpga@3,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x200000>;
+
+ v2m_sysreg: sysreg@010000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x010000 0x1000>;
+ };
+
+ v2m_serial0: uart@090000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x090000 0x1000>;
+ interrupts = <5>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial1: uart@0a0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0a0000 0x1000>;
+ interrupts = <6>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial2: uart@0b0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0b0000 0x1000>;
+ interrupts = <7>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial3: uart@0c0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0c0000 0x1000>;
+ interrupts = <8>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ virtio_block@0130000 {
+ compatible = "virtio,mmio";
+ reg = <0x130000 0x1000>;
+ interrupts = <42>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts
new file mode 100644
index 000000000000..572005ea2217
--- /dev/null
+++ b/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts
@@ -0,0 +1,159 @@
+/*
+ * ARM Ltd. Fast Models
+ *
+ * Architecture Envelope Model (AEM) ARMv8-A
+ * ARMAEMv8AMPCT
+ *
+ * RTSM_VE_AEMv8A.lisa
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+ model = "RTSM_VE_AEMv8A";
+ compatible = "arm,rtsm_ve,aemv8a", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ chosen { };
+
+ aliases {
+ serial0 = &v2m_serial0;
+ serial1 = &v2m_serial1;
+ serial2 = &v2m_serial2;
+ serial3 = &v2m_serial3;
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x0>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x1>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x2>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,armv8";
+ reg = <0x0 0x3>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x8000fff8>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0 0x80000000>,
+ <0x00000008 0x80000000 0 0x80000000>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x0 0x2c001000 0 0x1000>,
+ <0x0 0x2c002000 0 0x1000>,
+ <0x0 0x2c004000 0 0x2000>,
+ <0x0 0x2c006000 0 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xff01>,
+ <1 14 0xff01>,
+ <1 11 0xff01>,
+ <1 10 0xff01>;
+ clock-frequency = <100000000>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <0 60 4>,
+ <0 61 4>,
+ <0 62 4>,
+ <0 63 4>;
+ };
+
+ smb {
+ compatible = "simple-bus";
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0x08000000 0x04000000>,
+ <1 0 0 0x14000000 0x04000000>,
+ <2 0 0 0x18000000 0x04000000>,
+ <3 0 0 0x1c000000 0x04000000>,
+ <4 0 0 0x0c000000 0x04000000>,
+ <5 0 0 0x10000000 0x04000000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 63>;
+ interrupt-map = <0 0 0 &gic 0 0 4>,
+ <0 0 1 &gic 0 1 4>,
+ <0 0 2 &gic 0 2 4>,
+ <0 0 3 &gic 0 3 4>,
+ <0 0 4 &gic 0 4 4>,
+ <0 0 5 &gic 0 5 4>,
+ <0 0 6 &gic 0 6 4>,
+ <0 0 7 &gic 0 7 4>,
+ <0 0 8 &gic 0 8 4>,
+ <0 0 9 &gic 0 9 4>,
+ <0 0 10 &gic 0 10 4>,
+ <0 0 11 &gic 0 11 4>,
+ <0 0 12 &gic 0 12 4>,
+ <0 0 13 &gic 0 13 4>,
+ <0 0 14 &gic 0 14 4>,
+ <0 0 15 &gic 0 15 4>,
+ <0 0 16 &gic 0 16 4>,
+ <0 0 17 &gic 0 17 4>,
+ <0 0 18 &gic 0 18 4>,
+ <0 0 19 &gic 0 19 4>,
+ <0 0 20 &gic 0 20 4>,
+ <0 0 21 &gic 0 21 4>,
+ <0 0 22 &gic 0 22 4>,
+ <0 0 23 &gic 0 23 4>,
+ <0 0 24 &gic 0 24 4>,
+ <0 0 25 &gic 0 25 4>,
+ <0 0 26 &gic 0 26 4>,
+ <0 0 27 &gic 0 27 4>,
+ <0 0 28 &gic 0 28 4>,
+ <0 0 29 &gic 0 29 4>,
+ <0 0 30 &gic 0 30 4>,
+ <0 0 31 &gic 0 31 4>,
+ <0 0 32 &gic 0 32 4>,
+ <0 0 33 &gic 0 33 4>,
+ <0 0 34 &gic 0 34 4>,
+ <0 0 35 &gic 0 35 4>,
+ <0 0 36 &gic 0 36 4>,
+ <0 0 37 &gic 0 37 4>,
+ <0 0 38 &gic 0 38 4>,
+ <0 0 39 &gic 0 39 4>,
+ <0 0 40 &gic 0 40 4>,
+ <0 0 41 &gic 0 41 4>,
+ <0 0 42 &gic 0 42 4>;
+
+ /include/ "rtsm_ve-motherboard.dtsi"
+ };
+};
diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
new file mode 100644
index 000000000000..b45e5f39f577
--- /dev/null
+++ b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
@@ -0,0 +1,234 @@
+/*
+ * ARM Ltd. Fast Models
+ *
+ * Versatile Express (VE) system model
+ * Motherboard component
+ *
+ * VEMotherBoard.lisa
+ */
+
+ motherboard {
+ arm,v2m-memory-map = "rs1";
+ compatible = "arm,vexpress,v2m-p1", "simple-bus";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #size-cells = <1>;
+ #interrupt-cells = <1>;
+ ranges;
+
+ flash@0,00000000 {
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ reg = <0 0x00000000 0x04000000>,
+ <4 0x00000000 0x04000000>;
+ bank-width = <4>;
+ };
+
+ vram@2,00000000 {
+ compatible = "arm,vexpress-vram";
+ reg = <2 0x00000000 0x00800000>;
+ };
+
+ ethernet@2,02000000 {
+ compatible = "smsc,lan91c111";
+ reg = <2 0x02000000 0x10000>;
+ interrupts = <15>;
+ };
+
+ v2m_clk24mhz: clk24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "v2m:clk24mhz";
+ };
+
+ v2m_refclk1mhz: refclk1mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000>;
+ clock-output-names = "v2m:refclk1mhz";
+ };
+
+ v2m_refclk32khz: refclk32khz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "v2m:refclk32khz";
+ };
+
+ iofpga@3,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x200000>;
+
+ v2m_sysreg: sysreg@010000 {
+ compatible = "arm,vexpress-sysreg";
+ reg = <0x010000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ v2m_sysctl: sysctl@020000 {
+ compatible = "arm,sp810", "arm,primecell";
+ reg = <0x020000 0x1000>;
+ clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>;
+ clock-names = "refclk", "timclk", "apb_pclk";
+ #clock-cells = <1>;
+ clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
+ };
+
+ aaci@040000 {
+ compatible = "arm,pl041", "arm,primecell";
+ reg = <0x040000 0x1000>;
+ interrupts = <11>;
+ clocks = <&v2m_clk24mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ mmci@050000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x050000 0x1000>;
+ interrupts = <9 10>;
+ cd-gpios = <&v2m_sysreg 0 0>;
+ wp-gpios = <&v2m_sysreg 1 0>;
+ max-frequency = <12000000>;
+ vmmc-supply = <&v2m_fixed_3v3>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "mclk", "apb_pclk";
+ };
+
+ kmi@060000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x060000 0x1000>;
+ interrupts = <12>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi@070000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x070000 0x1000>;
+ interrupts = <13>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ v2m_serial0: uart@090000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x090000 0x1000>;
+ interrupts = <5>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial1: uart@0a0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0a0000 0x1000>;
+ interrupts = <6>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial2: uart@0b0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0b0000 0x1000>;
+ interrupts = <7>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ v2m_serial3: uart@0c0000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0c0000 0x1000>;
+ interrupts = <8>;
+ clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ wdt@0f0000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0f0000 0x1000>;
+ interrupts = <0>;
+ clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>;
+ clock-names = "wdogclk", "apb_pclk";
+ };
+
+ v2m_timer01: timer@110000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x110000 0x1000>;
+ interrupts = <2>;
+ clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>;
+ clock-names = "timclken1", "timclken2", "apb_pclk";
+ };
+
+ v2m_timer23: timer@120000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x120000 0x1000>;
+ interrupts = <3>;
+ clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>;
+ clock-names = "timclken1", "timclken2", "apb_pclk";
+ };
+
+ rtc@170000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x170000 0x1000>;
+ interrupts = <4>;
+ clocks = <&v2m_clk24mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ clcd@1f0000 {
+ compatible = "arm,pl111", "arm,primecell";
+ reg = <0x1f0000 0x1000>;
+ interrupts = <14>;
+ clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>;
+ clock-names = "clcdclk", "apb_pclk";
+ };
+ };
+
+ v2m_fixed_3v3: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ mcc {
+ compatible = "arm,vexpress,config-bus", "simple-bus";
+ arm,vexpress,config-bridge = <&v2m_sysreg>;
+
+ v2m_oscclk1: osc@1 {
+ /* CLCD clock */
+ compatible = "arm,vexpress-osc";
+ arm,vexpress-sysreg,func = <1 1>;
+ freq-range = <23750000 63500000>;
+ #clock-cells = <0>;
+ clock-output-names = "v2m:oscclk1";
+ };
+
+ reset@0 {
+ compatible = "arm,vexpress-reset";
+ arm,vexpress-sysreg,func = <5 0>;
+ };
+
+ muxfpga@0 {
+ compatible = "arm,vexpress-muxfpga";
+ arm,vexpress-sysreg,func = <7 0>;
+ };
+
+ shutdown@0 {
+ compatible = "arm,vexpress-shutdown";
+ arm,vexpress-sysreg,func = <8 0>;
+ };
+
+ reboot@0 {
+ compatible = "arm,vexpress-reboot";
+ arm,vexpress-sysreg,func = <9 0>;
+ };
+
+ dvimode@0 {
+ compatible = "arm,vexpress-dvimode";
+ arm,vexpress-sysreg,func = <11 0>;
+ };
+ };
+ };
diff --git a/arch/arm64/boot/dts/skeleton.dtsi b/arch/arm64/boot/dts/skeleton.dtsi
new file mode 100644
index 000000000000..38ead821bb42
--- /dev/null
+++ b/arch/arm64/boot/dts/skeleton.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Skeleton device tree; the bare minimum needed to boot; just include and
+ * add a compatible value. The bootloader will typically populate the memory
+ * node.
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ chosen { };
+ aliases { };
+ memory { device_type = "memory"; reg = <0 0 0>; };
+};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 09bef29f3a09..8d9696adb440 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -23,6 +23,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_VEXPRESS=y
CONFIG_SMP=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_CMDLINE="console=ttyAMA0"
@@ -47,11 +48,14 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
CONFIG_MII=y
+CONFIG_SMC91X=y
# CONFIG_WLAN is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
CONFIG_FB=y
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index e5fe4f99fe10..79a642d199f2 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -39,7 +39,6 @@ generic-y += shmbuf.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
-generic-y += string.h
generic-y += switch_to.h
generic-y += swab.h
generic-y += termbits.h
@@ -49,4 +48,5 @@ generic-y += trace_clock.h
generic-y += types.h
generic-y += unaligned.h
generic-y += user.h
+generic-y += vga.h
generic-y += xor.h
diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h
index 5e693073b030..aa5b59d6ba43 100644
--- a/arch/arm64/include/asm/bitops.h
+++ b/arch/arm64/include/asm/bitops.h
@@ -32,6 +32,16 @@
#error only <linux/bitops.h> can be included directly
#endif
+/*
+ * Little endian assembly atomic bitops.
+ */
+extern void set_bit(int nr, volatile unsigned long *p);
+extern void clear_bit(int nr, volatile unsigned long *p);
+extern void change_bit(int nr, volatile unsigned long *p);
+extern int test_and_set_bit(int nr, volatile unsigned long *p);
+extern int test_and_clear_bit(int nr, volatile unsigned long *p);
+extern int test_and_change_bit(int nr, volatile unsigned long *p);
+
#include <asm-generic/bitops/builtin-__ffs.h>
#include <asm-generic/bitops/builtin-ffs.h>
#include <asm-generic/bitops/builtin-__fls.h>
@@ -45,9 +55,13 @@
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
-#include <asm-generic/bitops/atomic.h>
#include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/le.h>
-#include <asm-generic/bitops/ext2-atomic.h>
+
+/*
+ * Ext2 is defined to use little-endian byte ordering.
+ */
+#define ext2_set_bit_atomic(lock, nr, p) test_and_set_bit_le(nr, p)
+#define ext2_clear_bit_atomic(lock, nr, p) test_and_clear_bit_le(nr, p)
#endif /* __ASM_BITOPS_H */
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index 968b5cbfc260..8a8ce0e73a38 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -170,4 +170,7 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
(unsigned long)(n), \
sizeof(*(ptr))))
+#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
+#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
+
#endif /* __ASM_CMPXCHG_H */
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 618b450e5a1d..899af807ef0f 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -35,14 +35,16 @@ typedef s32 compat_clock_t;
typedef s32 compat_pid_t;
typedef u32 __compat_uid_t;
typedef u32 __compat_gid_t;
+typedef u16 __compat_uid16_t;
+typedef u16 __compat_gid16_t;
typedef u32 __compat_uid32_t;
typedef u32 __compat_gid32_t;
-typedef u32 compat_mode_t;
+typedef u16 compat_mode_t;
typedef u32 compat_ino_t;
typedef u32 compat_dev_t;
typedef s32 compat_off_t;
typedef s64 compat_loff_t;
-typedef s16 compat_nlink_t;
+typedef s32 compat_nlink_t;
typedef u16 compat_ipc_pid_t;
typedef s32 compat_daddr_t;
typedef u32 compat_caddr_t;
@@ -50,9 +52,11 @@ typedef __kernel_fsid_t compat_fsid_t;
typedef s32 compat_key_t;
typedef s32 compat_timer_t;
+typedef s16 compat_short_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
typedef s64 compat_s64;
+typedef u16 compat_ushort_t;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
typedef u64 compat_u64;
@@ -72,20 +76,20 @@ struct compat_stat {
compat_dev_t st_dev;
compat_ino_t st_ino;
compat_mode_t st_mode;
- compat_nlink_t st_nlink;
- __compat_uid32_t st_uid;
- __compat_gid32_t st_gid;
+ compat_ushort_t st_nlink;
+ __compat_uid16_t st_uid;
+ __compat_gid16_t st_gid;
compat_dev_t st_rdev;
compat_off_t st_size;
compat_off_t st_blksize;
compat_off_t st_blocks;
compat_time_t st_atime;
- u32 st_atime_nsec;
+ compat_ulong_t st_atime_nsec;
compat_time_t st_mtime;
- u32 st_mtime_nsec;
+ compat_ulong_t st_mtime_nsec;
compat_time_t st_ctime;
- u32 st_ctime_nsec;
- u32 __unused4[2];
+ compat_ulong_t st_ctime_nsec;
+ compat_ulong_t __unused4[2];
};
struct compat_flock {
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index ef54125e6c1e..cf2749488cd4 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -17,6 +17,7 @@
#define __ASM_CPUTYPE_H
#define ID_MIDR_EL1 "midr_el1"
+#define ID_MPIDR_EL1 "mpidr_el1"
#define ID_CTR_EL0 "ctr_el0"
#define ID_AA64PFR0_EL1 "id_aa64pfr0_el1"
@@ -25,12 +26,24 @@
#define ID_AA64ISAR0_EL1 "id_aa64isar0_el1"
#define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1"
+#define INVALID_HWID ULONG_MAX
+
+#define MPIDR_HWID_BITMASK 0xff00ffffff
+
#define read_cpuid(reg) ({ \
u64 __val; \
asm("mrs %0, " reg : "=r" (__val)); \
__val; \
})
+#define ARM_CPU_IMP_ARM 0x41
+
+#define ARM_CPU_PART_AEM_V8 0xD0F0
+#define ARM_CPU_PART_FOUNDATION 0xD000
+#define ARM_CPU_PART_CORTEX_A57 0xD070
+
+#ifndef __ASSEMBLY__
+
/*
* The CPU ID never changes at run time, so we might as well tell the
* compiler that it's constant. Use this function to read the CPU ID
@@ -41,9 +54,26 @@ static inline u32 __attribute_const__ read_cpuid_id(void)
return read_cpuid(ID_MIDR_EL1);
}
+static inline u64 __attribute_const__ read_cpuid_mpidr(void)
+{
+ return read_cpuid(ID_MPIDR_EL1);
+}
+
+static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
+{
+ return (read_cpuid_id() & 0xFF000000) >> 24;
+}
+
+static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
+{
+ return (read_cpuid_id() & 0xFFF0);
+}
+
static inline u32 __attribute_const__ read_cpuid_cachetype(void)
{
return read_cpuid(ID_CTR_EL0);
}
+#endif /* __ASSEMBLY__ */
+
#endif
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
new file mode 100644
index 000000000000..78834123a32e
--- /dev/null
+++ b/arch/arm64/include/asm/esr.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ESR_H
+#define __ASM_ESR_H
+
+#define ESR_EL1_EC_SHIFT (26)
+#define ESR_EL1_IL (1U << 25)
+
+#define ESR_EL1_EC_UNKNOWN (0x00)
+#define ESR_EL1_EC_WFI (0x01)
+#define ESR_EL1_EC_CP15_32 (0x03)
+#define ESR_EL1_EC_CP15_64 (0x04)
+#define ESR_EL1_EC_CP14_MR (0x05)
+#define ESR_EL1_EC_CP14_LS (0x06)
+#define ESR_EL1_EC_FP_ASIMD (0x07)
+#define ESR_EL1_EC_CP10_ID (0x08)
+#define ESR_EL1_EC_CP14_64 (0x0C)
+#define ESR_EL1_EC_ILL_ISS (0x0E)
+#define ESR_EL1_EC_SVC32 (0x11)
+#define ESR_EL1_EC_SVC64 (0x15)
+#define ESR_EL1_EC_SYS64 (0x18)
+#define ESR_EL1_EC_IABT_EL0 (0x20)
+#define ESR_EL1_EC_IABT_EL1 (0x21)
+#define ESR_EL1_EC_PC_ALIGN (0x22)
+#define ESR_EL1_EC_DABT_EL0 (0x24)
+#define ESR_EL1_EC_DABT_EL1 (0x25)
+#define ESR_EL1_EC_SP_ALIGN (0x26)
+#define ESR_EL1_EC_FP_EXC32 (0x28)
+#define ESR_EL1_EC_FP_EXC64 (0x2C)
+#define ESR_EL1_EC_SERRROR (0x2F)
+#define ESR_EL1_EC_BREAKPT_EL0 (0x30)
+#define ESR_EL1_EC_BREAKPT_EL1 (0x31)
+#define ESR_EL1_EC_SOFTSTP_EL0 (0x32)
+#define ESR_EL1_EC_SOFTSTP_EL1 (0x33)
+#define ESR_EL1_EC_WATCHPT_EL0 (0x34)
+#define ESR_EL1_EC_WATCHPT_EL1 (0x35)
+#define ESR_EL1_EC_BKPT32 (0x38)
+#define ESR_EL1_EC_BRK64 (0x3C)
+
+#endif /* __ASM_ESR_H */
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h
index ac63519b7b90..0303705fcad6 100644
--- a/arch/arm64/include/asm/exception.h
+++ b/arch/arm64/include/asm/exception.h
@@ -19,5 +19,6 @@
#define __ASM_EXCEPTION_H
#define __exception __attribute__((section(".exception.text")))
+#define __exception_irq_entry __exception
#endif /* __ASM_EXCEPTION_H */
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 507546353d62..990c051e7829 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -49,4 +49,9 @@ static inline void ack_bad_irq(unsigned int irq)
extern void handle_IRQ(unsigned int, struct pt_regs *);
+/*
+ * No arch-specific IRQ flags.
+ */
+#define set_irq_flags(irq, flags)
+
#endif /* __ASM_HARDIRQ_H */
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 57f12c991de2..2e12258aa7e4 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -92,10 +92,12 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; })
#define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; })
#define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; })
+#define readq_relaxed(c) ({ u64 __v = le64_to_cpu((__force __le64)__raw_readq(c)); __v; })
#define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c)))
#define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c)))
#define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c)))
+#define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)cpu_to_le64(v),(c)))
/*
* I/O memory access primitives. Reads are ordered relative to any
@@ -105,10 +107,12 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+#define readq(c) ({ u64 __v = readq_relaxed(c); __iormb(); __v; })
#define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); })
#define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); })
#define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); })
+#define writeq(v,c) ({ __iowmb(); writeq_relaxed((v),(c)); })
/*
* I/O port access primitives.
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index a4e1cad3202a..0332fc077f6e 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -4,5 +4,6 @@
#include <asm-generic/irq.h>
extern void (*handle_arch_irq)(struct pt_regs *);
+extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
#endif
diff --git a/arch/arm64/lib/bitops.c b/arch/arm64/include/asm/smp_plat.h
index aa4965e60acc..ed43a0d2b1b2 100644
--- a/arch/arm64/lib/bitops.c
+++ b/arch/arm64/include/asm/smp_plat.h
@@ -1,7 +1,9 @@
/*
- * Copyright (C) 2012 ARM Limited
+ * Definitions specific to SMP platforms.
*
- * This program is free software; you can redistribute it and/or modify
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
@@ -14,12 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/atomic.h>
+#ifndef __ASM_SMP_PLAT_H
+#define __ASM_SMP_PLAT_H
+
+#include <asm/types.h>
+
+/*
+ * Logical CPU mapping.
+ */
+extern u64 __cpu_logical_map[NR_CPUS];
+#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
-#ifdef CONFIG_SMP
-arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
- [0 ... (ATOMIC_HASH_SIZE-1)] = __ARCH_SPIN_LOCK_UNLOCKED
-};
-#endif
+#endif /* __ASM_SMP_PLAT_H */
diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h
new file mode 100644
index 000000000000..3ee8b303d9a9
--- /dev/null
+++ b/arch/arm64/include/asm/string.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_STRING_H
+#define __ASM_STRING_H
+
+#define __HAVE_ARCH_STRRCHR
+extern char *strrchr(const char *, int c);
+
+#define __HAVE_ARCH_STRCHR
+extern char *strchr(const char *, int c);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMCHR
+extern void *memchr(const void *, int, __kernel_size_t);
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *, int, __kernel_size_t);
+
+#endif
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index aa3e948f7885..7df1aad29b67 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -39,10 +39,21 @@ EXPORT_SYMBOL(__copy_from_user);
EXPORT_SYMBOL(__copy_to_user);
EXPORT_SYMBOL(__clear_user);
- /* bitops */
-#ifdef CONFIG_SMP
-EXPORT_SYMBOL(__atomic_hash);
-#endif
-
/* physical memory */
EXPORT_SYMBOL(memstart_addr);
+
+ /* string / mem functions */
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+
+ /* atomic bitops */
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_change_bit);
diff --git a/arch/arm64/kernel/early_printk.c b/arch/arm64/kernel/early_printk.c
index 7e320a2edb9b..ac974f48a7a2 100644
--- a/arch/arm64/kernel/early_printk.c
+++ b/arch/arm64/kernel/early_printk.c
@@ -24,6 +24,7 @@
#include <linux/io.h>
#include <linux/amba/serial.h>
+#include <linux/serial_reg.h>
static void __iomem *early_base;
static void (*printch)(char ch);
@@ -40,6 +41,37 @@ static void pl011_printch(char ch)
;
}
+/*
+ * Semihosting-based debug console
+ */
+static void smh_printch(char ch)
+{
+ asm volatile("mov x1, %0\n"
+ "mov x0, #3\n"
+ "hlt 0xf000\n"
+ : : "r" (&ch) : "x0", "x1", "memory");
+}
+
+/*
+ * 8250/16550 (8-bit aligned registers) single character TX.
+ */
+static void uart8250_8bit_printch(char ch)
+{
+ while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE))
+ ;
+ writeb_relaxed(ch, early_base + UART_TX);
+}
+
+/*
+ * 8250/16550 (32-bit aligned registers) single character TX.
+ */
+static void uart8250_32bit_printch(char ch)
+{
+ while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE))
+ ;
+ writel_relaxed(ch, early_base + (UART_TX << 2));
+}
+
struct earlycon_match {
const char *name;
void (*printch)(char ch);
@@ -47,6 +79,9 @@ struct earlycon_match {
static const struct earlycon_match earlycon_match[] __initconst = {
{ .name = "pl011", .printch = pl011_printch, },
+ { .name = "smh", .printch = smh_printch, },
+ { .name = "uart8250-8bit", .printch = uart8250_8bit_printch, },
+ { .name = "uart8250-32bit", .printch = uart8250_32bit_printch, },
{}
};
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 514d6098dbee..c7e047049f2c 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -24,6 +24,7 @@
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/errno.h>
+#include <asm/esr.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
#include <asm/unistd32.h>
@@ -239,18 +240,18 @@ ENDPROC(el1_error_invalid)
el1_sync:
kernel_entry 1
mrs x1, esr_el1 // read the syndrome register
- lsr x24, x1, #26 // exception class
- cmp x24, #0x25 // data abort in EL1
+ lsr x24, x1, #ESR_EL1_EC_SHIFT // exception class
+ cmp x24, #ESR_EL1_EC_DABT_EL1 // data abort in EL1
b.eq el1_da
- cmp x24, #0x18 // configurable trap
+ cmp x24, #ESR_EL1_EC_SYS64 // configurable trap
b.eq el1_undef
- cmp x24, #0x26 // stack alignment exception
+ cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception
b.eq el1_sp_pc
- cmp x24, #0x22 // pc alignment exception
+ cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception
b.eq el1_sp_pc
- cmp x24, #0x00 // unknown exception in EL1
+ cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL1
b.eq el1_undef
- cmp x24, #0x30 // debug exception in EL1
+ cmp x24, #ESR_EL1_EC_BREAKPT_EL1 // debug exception in EL1
b.ge el1_dbg
b el1_inv
el1_da:
@@ -346,27 +347,27 @@ el1_preempt:
el0_sync:
kernel_entry 0
mrs x25, esr_el1 // read the syndrome register
- lsr x24, x25, #26 // exception class
- cmp x24, #0x15 // SVC in 64-bit state
+ lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class
+ cmp x24, #ESR_EL1_EC_SVC64 // SVC in 64-bit state
b.eq el0_svc
adr lr, ret_from_exception
- cmp x24, #0x24 // data abort in EL0
+ cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0
b.eq el0_da
- cmp x24, #0x20 // instruction abort in EL0
+ cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0
b.eq el0_ia
- cmp x24, #0x07 // FP/ASIMD access
+ cmp x24, #ESR_EL1_EC_FP_ASIMD // FP/ASIMD access
b.eq el0_fpsimd_acc
- cmp x24, #0x2c // FP/ASIMD exception
+ cmp x24, #ESR_EL1_EC_FP_EXC64 // FP/ASIMD exception
b.eq el0_fpsimd_exc
- cmp x24, #0x18 // configurable trap
+ cmp x24, #ESR_EL1_EC_SYS64 // configurable trap
b.eq el0_undef
- cmp x24, #0x26 // stack alignment exception
+ cmp x24, #ESR_EL1_EC_SP_ALIGN // stack alignment exception
b.eq el0_sp_pc
- cmp x24, #0x22 // pc alignment exception
+ cmp x24, #ESR_EL1_EC_PC_ALIGN // pc alignment exception
b.eq el0_sp_pc
- cmp x24, #0x00 // unknown exception in EL0
+ cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL0
b.eq el0_undef
- cmp x24, #0x30 // debug exception in EL0
+ cmp x24, #ESR_EL1_EC_BREAKPT_EL0 // debug exception in EL0
b.ge el0_dbg
b el0_inv
@@ -375,21 +376,21 @@ el0_sync:
el0_sync_compat:
kernel_entry 0, 32
mrs x25, esr_el1 // read the syndrome register
- lsr x24, x25, #26 // exception class
- cmp x24, #0x11 // SVC in 32-bit state
+ lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class
+ cmp x24, #ESR_EL1_EC_SVC32 // SVC in 32-bit state
b.eq el0_svc_compat
adr lr, ret_from_exception
- cmp x24, #0x24 // data abort in EL0
+ cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0
b.eq el0_da
- cmp x24, #0x20 // instruction abort in EL0
+ cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0
b.eq el0_ia
- cmp x24, #0x07 // FP/ASIMD access
+ cmp x24, #ESR_EL1_EC_FP_ASIMD // FP/ASIMD access
b.eq el0_fpsimd_acc
- cmp x24, #0x28 // FP/ASIMD exception
+ cmp x24, #ESR_EL1_EC_FP_EXC32 // FP/ASIMD exception
b.eq el0_fpsimd_exc
- cmp x24, #0x00 // unknown exception in EL0
+ cmp x24, #ESR_EL1_EC_UNKNOWN // unknown exception in EL0
b.eq el0_undef
- cmp x24, #0x30 // debug exception in EL0
+ cmp x24, #ESR_EL1_EC_BREAKPT_EL0 // debug exception in EL0
b.ge el0_dbg
b el0_inv
el0_svc_compat:
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0a0a49756826..53dcae49e729 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -26,6 +26,7 @@
#include <asm/assembler.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
+#include <asm/cputype.h>
#include <asm/memory.h>
#include <asm/thread_info.h>
#include <asm/pgtable-hwdef.h>
@@ -229,7 +230,8 @@ ENTRY(secondary_holding_pen)
bl __calc_phys_offset // x24=phys offset
bl el2_setup // Drop to EL1
mrs x0, mpidr_el1
- and x0, x0, #15 // CPU number
+ ldr x1, =MPIDR_HWID_BITMASK
+ and x0, x0, x1
adr x1, 1b
ldp x2, x3, [x1]
sub x1, x1, x2
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 0373c6609eaf..ecb3354292ed 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -25,7 +25,7 @@
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/init.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
@@ -67,18 +67,17 @@ void handle_IRQ(unsigned int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}
-/*
- * Interrupt controllers supported by the kernel.
- */
-static const struct of_device_id intctrl_of_match[] __initconst = {
- /* IRQ controllers { .compatible, .data } info to go here */
- {}
-};
+void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
+{
+ if (handle_arch_irq)
+ return;
+
+ handle_arch_irq = handle_irq;
+}
void __init init_IRQ(void)
{
- of_irq_init(intctrl_of_match);
-
+ irqchip_init();
if (!handle_arch_irq)
panic("No interrupt controller found.");
}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 0337cdb0667b..f4919721f7dd 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -84,11 +84,15 @@ EXPORT_SYMBOL_GPL(pm_power_off);
void (*pm_restart)(const char *cmd);
EXPORT_SYMBOL_GPL(pm_restart);
+void arch_cpu_idle_prepare(void)
+{
+ local_fiq_enable();
+}
/*
* This is our default idle handler.
*/
-static void default_idle(void)
+void arch_cpu_idle(void)
{
/*
* This should do all the clock switching and wait for interrupt
@@ -98,43 +102,6 @@ static void default_idle(void)
local_irq_enable();
}
-/*
- * The idle thread.
- * We always respect 'hlt_counter' to prevent low power idle.
- */
-void cpu_idle(void)
-{
- local_fiq_enable();
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched()) {
- /*
- * We need to disable interrupts here to ensure
- * we don't miss a wakeup call.
- */
- local_irq_disable();
- if (!need_resched()) {
- stop_critical_timings();
- default_idle();
- start_critical_timings();
- /*
- * default_idle functions should always return
- * with IRQs enabled.
- */
- WARN_ON(irqs_disabled());
- } else {
- local_irq_enable();
- }
- }
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
void machine_shutdown(void)
{
#ifdef CONFIG_SMP
@@ -178,11 +145,7 @@ void __show_regs(struct pt_regs *regs)
{
int i;
- printk("CPU: %d %s (%s %.*s)\n",
- raw_smp_processor_id(), print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
+ show_regs_print_info(KERN_DEFAULT);
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", regs->regs[30]);
printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n",
@@ -199,7 +162,6 @@ void __show_regs(struct pt_regs *regs)
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm);
__show_regs(regs);
}
@@ -311,11 +273,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
fpsimd_thread_switch(next);
tls_thread_switch(next);
hw_breakpoint_thread_switch(next);
+ contextidr_thread_switch(next);
+
+ /*
+ * Complete any pending TLB or cache maintenance on this CPU in case
+ * the thread migrates to a different CPU.
+ */
+ dsb();
/* the actual thread switch */
last = cpu_switch_to(prev, next);
- contextidr_thread_switch(next);
return last;
}
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 113db863f832..6a9a53292590 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -32,6 +32,7 @@
#include <linux/kexec.h>
#include <linux/crash_dump.h>
#include <linux/root_dev.h>
+#include <linux/clk-provider.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
@@ -46,6 +47,7 @@
#include <asm/cputable.h>
#include <asm/sections.h>
#include <asm/setup.h>
+#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/traps.h>
@@ -240,6 +242,8 @@ static void __init request_standard_resources(void)
}
}
+u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID };
+
void __init setup_arch(char **cmdline_p)
{
setup_processor();
@@ -264,6 +268,7 @@ void __init setup_arch(char **cmdline_p)
psci_init();
+ cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
@@ -277,6 +282,13 @@ void __init setup_arch(char **cmdline_p)
#endif
}
+static int __init arm64_of_clk_init(void)
+{
+ of_clk_init(NULL);
+ return 0;
+}
+arch_initcall(arm64_of_clk_init);
+
static DEFINE_PER_CPU(struct cpu, cpu_data);
static int __init topology_init(void)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index bdd34597254b..5d54e3717bf8 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -43,6 +43,7 @@
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/processor.h>
+#include <asm/smp_plat.h>
#include <asm/sections.h>
#include <asm/tlbflush.h>
#include <asm/ptrace.h>
@@ -53,7 +54,7 @@
* where to place its SVC stack
*/
struct secondary_data secondary_data;
-volatile unsigned long secondary_holding_pen_release = -1;
+volatile unsigned long secondary_holding_pen_release = INVALID_HWID;
enum ipi_msg_type {
IPI_RESCHEDULE,
@@ -70,7 +71,7 @@ static DEFINE_RAW_SPINLOCK(boot_lock);
* in coherency or not. This is necessary for the hotplug code to work
* reliably.
*/
-static void __cpuinit write_pen_release(int val)
+static void __cpuinit write_pen_release(u64 val)
{
void *start = (void *)&secondary_holding_pen_release;
unsigned long size = sizeof(secondary_holding_pen_release);
@@ -96,7 +97,7 @@ static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
/*
* Update the pen release flag.
*/
- write_pen_release(cpu);
+ write_pen_release(cpu_logical_map(cpu));
/*
* Send an event, causing the secondaries to read pen_release.
@@ -105,7 +106,7 @@ static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
- if (secondary_holding_pen_release == -1UL)
+ if (secondary_holding_pen_release == INVALID_HWID)
break;
udelay(10);
}
@@ -116,7 +117,7 @@ static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
raw_spin_unlock(&boot_lock);
- return secondary_holding_pen_release != -1 ? -ENOSYS : 0;
+ return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
}
static DECLARE_COMPLETION(cpu_running);
@@ -190,7 +191,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
* Let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
- write_pen_release(-1);
+ write_pen_release(INVALID_HWID);
/*
* Synchronise with the boot thread.
@@ -216,7 +217,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
/*
* OK, it's off to the idle thread for us
*/
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_cpus_done(unsigned int max_cpus)
@@ -244,11 +245,11 @@ static const struct smp_enable_ops *smp_enable_ops[NR_CPUS];
static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
{
- const struct smp_enable_ops *ops = enable_ops[0];
+ const struct smp_enable_ops **ops = enable_ops;
- while (ops) {
- if (!strcmp(name, ops->name))
- return ops;
+ while (*ops) {
+ if (!strcmp(name, (*ops)->name))
+ return *ops;
ops++;
}
@@ -257,15 +258,80 @@ static const struct smp_enable_ops * __init smp_get_enable_ops(const char *name)
}
/*
- * Enumerate the possible CPU set from the device tree.
+ * Enumerate the possible CPU set from the device tree and build the
+ * cpu logical map array containing MPIDR values related to logical
+ * cpus. Assumes that cpu_logical_map(0) has already been initialized.
*/
void __init smp_init_cpus(void)
{
const char *enable_method;
struct device_node *dn = NULL;
- int cpu = 0;
+ int i, cpu = 1;
+ bool bootcpu_valid = false;
while ((dn = of_find_node_by_type(dn, "cpu"))) {
+ const u32 *cell;
+ u64 hwid;
+
+ /*
+ * A cpu node with missing "reg" property is
+ * considered invalid to build a cpu_logical_map
+ * entry.
+ */
+ cell = of_get_property(dn, "reg", NULL);
+ if (!cell) {
+ pr_err("%s: missing reg property\n", dn->full_name);
+ goto next;
+ }
+ hwid = of_read_number(cell, of_n_addr_cells(dn));
+
+ /*
+ * Non affinity bits must be set to 0 in the DT
+ */
+ if (hwid & ~MPIDR_HWID_BITMASK) {
+ pr_err("%s: invalid reg property\n", dn->full_name);
+ goto next;
+ }
+
+ /*
+ * Duplicate MPIDRs are a recipe for disaster. Scan
+ * all initialized entries and check for
+ * duplicates. If any is found just ignore the cpu.
+ * cpu_logical_map was initialized to INVALID_HWID to
+ * avoid matching valid MPIDR values.
+ */
+ for (i = 1; (i < cpu) && (i < NR_CPUS); i++) {
+ if (cpu_logical_map(i) == hwid) {
+ pr_err("%s: duplicate cpu reg properties in the DT\n",
+ dn->full_name);
+ goto next;
+ }
+ }
+
+ /*
+ * The numbering scheme requires that the boot CPU
+ * must be assigned logical id 0. Record it so that
+ * the logical map built from DT is validated and can
+ * be used.
+ */
+ if (hwid == cpu_logical_map(0)) {
+ if (bootcpu_valid) {
+ pr_err("%s: duplicate boot cpu reg property in DT\n",
+ dn->full_name);
+ goto next;
+ }
+
+ bootcpu_valid = true;
+
+ /*
+ * cpu_logical_map has already been
+ * initialized and the boot cpu doesn't need
+ * the enable-method so continue without
+ * incrementing cpu.
+ */
+ continue;
+ }
+
if (cpu >= NR_CPUS)
goto next;
@@ -274,22 +340,24 @@ void __init smp_init_cpus(void)
*/
enable_method = of_get_property(dn, "enable-method", NULL);
if (!enable_method) {
- pr_err("CPU %d: missing enable-method property\n", cpu);
+ pr_err("%s: missing enable-method property\n",
+ dn->full_name);
goto next;
}
smp_enable_ops[cpu] = smp_get_enable_ops(enable_method);
if (!smp_enable_ops[cpu]) {
- pr_err("CPU %d: invalid enable-method property: %s\n",
- cpu, enable_method);
+ pr_err("%s: invalid enable-method property: %s\n",
+ dn->full_name, enable_method);
goto next;
}
if (smp_enable_ops[cpu]->init_cpu(dn, cpu))
goto next;
- set_cpu_possible(cpu, true);
+ pr_debug("cpu logical map 0x%llx\n", hwid);
+ cpu_logical_map(cpu) = hwid;
next:
cpu++;
}
@@ -298,6 +366,19 @@ next:
if (cpu > NR_CPUS)
pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n",
cpu, NR_CPUS);
+
+ if (!bootcpu_valid) {
+ pr_err("DT missing boot CPU MPIDR, not enabling secondaries\n");
+ return;
+ }
+
+ /*
+ * All the cpus that made it to the cpu_logical_map have been
+ * validated so set them as possible cpus.
+ */
+ for (i = 0; i < NR_CPUS; i++)
+ if (cpu_logical_map(i) != INVALID_HWID)
+ set_cpu_possible(i, true);
}
void __init smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm64/kernel/smp_psci.c b/arch/arm64/kernel/smp_psci.c
index 112091684c22..0c533301be77 100644
--- a/arch/arm64/kernel/smp_psci.c
+++ b/arch/arm64/kernel/smp_psci.c
@@ -21,6 +21,7 @@
#include <linux/smp.h>
#include <asm/psci.h>
+#include <asm/smp_plat.h>
static int __init smp_psci_init_cpu(struct device_node *dn, int cpu)
{
@@ -36,7 +37,7 @@ static int __init smp_psci_prepare_cpu(int cpu)
return -ENODEV;
}
- err = psci_ops.cpu_on(cpu, __pa(secondary_holding_pen));
+ err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_holding_pen));
if (err) {
pr_err("psci: failed to boot CPU%d (%d)\n", cpu, err);
return err;
@@ -47,6 +48,6 @@ static int __init smp_psci_prepare_cpu(int cpu)
const struct smp_enable_ops smp_psci_ops __initconst = {
.name = "psci",
- .init_cpu = smp_psci_init_cpu,
+ .init_cpu = smp_psci_init_cpu,
.prepare_cpu = smp_psci_prepare_cpu,
};
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S
index 9416d045a687..db01aa978c41 100644
--- a/arch/arm64/kernel/sys32.S
+++ b/arch/arm64/kernel/sys32.S
@@ -84,13 +84,6 @@ compat_sys_readahead_wrapper:
b sys_readahead
ENDPROC(compat_sys_readahead_wrapper)
-compat_sys_lookup_dcookie:
- orr x0, x0, x1, lsl #32
- mov w1, w2
- mov w2, w3
- b sys_lookup_dcookie
-ENDPROC(compat_sys_lookup_dcookie)
-
compat_sys_fadvise64_64_wrapper:
mov w6, w1
orr x1, x2, x3, lsl #32
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index b3c5f628bdb4..61d7dd29f756 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -167,13 +167,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
}
}
-void dump_stack(void)
-{
- dump_backtrace(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
dump_backtrace(NULL, tsk);
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile
index 2fb7f6092aae..59acc0ef0462 100644
--- a/arch/arm64/lib/Makefile
+++ b/arch/arm64/lib/Makefile
@@ -1,4 +1,6 @@
lib-y := bitops.o delay.o \
strncpy_from_user.o strnlen_user.o clear_user.o \
copy_from_user.o copy_to_user.o copy_in_user.o \
- copy_page.o clear_page.o
+ copy_page.o clear_page.o \
+ memchr.o memcpy.o memmove.o memset.o \
+ strchr.o strrchr.o
diff --git a/arch/arm64/lib/bitops.S b/arch/arm64/lib/bitops.S
new file mode 100644
index 000000000000..36216d30cb9a
--- /dev/null
+++ b/arch/arm64/lib/bitops.S
@@ -0,0 +1,68 @@
+/*
+ * Based on arch/arm/lib/bitops.h
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * x0: bits 5:0 bit offset
+ * bits 63:6 word offset
+ * x1: address
+ */
+ .macro bitop, name, instr
+ENTRY( \name )
+ and x3, x0, #63 // Get bit offset
+ eor x0, x0, x3 // Clear low bits
+ mov x2, #1
+ add x1, x1, x0, lsr #3 // Get word offset
+ lsl x3, x2, x3 // Create mask
+1: ldxr x2, [x1]
+ \instr x2, x2, x3
+ stxr w0, x2, [x1]
+ cbnz w0, 1b
+ ret
+ENDPROC(\name )
+ .endm
+
+ .macro testop, name, instr
+ENTRY( \name )
+ and x3, x0, #63 // Get bit offset
+ eor x0, x0, x3 // Clear low bits
+ mov x2, #1
+ add x1, x1, x0, lsr #3 // Get word offset
+ lsl x4, x2, x3 // Create mask
+1: ldaxr x2, [x1]
+ lsr x0, x2, x3 // Save old value of bit
+ \instr x2, x2, x4 // toggle bit
+ stlxr w5, x2, [x1]
+ cbnz w5, 1b
+ and x0, x0, #1
+3: ret
+ENDPROC(\name )
+ .endm
+
+/*
+ * Atomic bit operations.
+ */
+ bitop change_bit, eor
+ bitop clear_bit, bic
+ bitop set_bit, orr
+
+ testop test_and_change_bit, eor
+ testop test_and_clear_bit, bic
+ testop test_and_set_bit, orr
diff --git a/arch/arm64/lib/memchr.S b/arch/arm64/lib/memchr.S
new file mode 100644
index 000000000000..8636b7549163
--- /dev/null
+++ b/arch/arm64/lib/memchr.S
@@ -0,0 +1,44 @@
+/*
+ * Based on arch/arm/lib/memchr.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Find a character in an area of memory.
+ *
+ * Parameters:
+ * x0 - buf
+ * x1 - c
+ * x2 - n
+ * Returns:
+ * x0 - address of first occurrence of 'c' or 0
+ */
+ENTRY(memchr)
+ and w1, w1, #0xff
+1: subs x2, x2, #1
+ b.mi 2f
+ ldrb w3, [x0], #1
+ cmp w3, w1
+ b.ne 1b
+ sub x0, x0, #1
+ ret
+2: mov x0, #0
+ ret
+ENDPROC(memchr)
diff --git a/arch/arm64/lib/memcpy.S b/arch/arm64/lib/memcpy.S
new file mode 100644
index 000000000000..27b5003609b6
--- /dev/null
+++ b/arch/arm64/lib/memcpy.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Copy a buffer from src to dest (alignment handled by the hardware)
+ *
+ * Parameters:
+ * x0 - dest
+ * x1 - src
+ * x2 - n
+ * Returns:
+ * x0 - dest
+ */
+ENTRY(memcpy)
+ mov x4, x0
+ subs x2, x2, #8
+ b.mi 2f
+1: ldr x3, [x1], #8
+ subs x2, x2, #8
+ str x3, [x4], #8
+ b.pl 1b
+2: adds x2, x2, #4
+ b.mi 3f
+ ldr w3, [x1], #4
+ sub x2, x2, #4
+ str w3, [x4], #4
+3: adds x2, x2, #2
+ b.mi 4f
+ ldrh w3, [x1], #2
+ sub x2, x2, #2
+ strh w3, [x4], #2
+4: adds x2, x2, #1
+ b.mi 5f
+ ldrb w3, [x1]
+ strb w3, [x4]
+5: ret
+ENDPROC(memcpy)
diff --git a/arch/arm64/lib/memmove.S b/arch/arm64/lib/memmove.S
new file mode 100644
index 000000000000..b79fdfa42d39
--- /dev/null
+++ b/arch/arm64/lib/memmove.S
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Move a buffer from src to test (alignment handled by the hardware).
+ * If dest <= src, call memcpy, otherwise copy in reverse order.
+ *
+ * Parameters:
+ * x0 - dest
+ * x1 - src
+ * x2 - n
+ * Returns:
+ * x0 - dest
+ */
+ENTRY(memmove)
+ cmp x0, x1
+ b.ls memcpy
+ add x4, x0, x2
+ add x1, x1, x2
+ subs x2, x2, #8
+ b.mi 2f
+1: ldr x3, [x1, #-8]!
+ subs x2, x2, #8
+ str x3, [x4, #-8]!
+ b.pl 1b
+2: adds x2, x2, #4
+ b.mi 3f
+ ldr w3, [x1, #-4]!
+ sub x2, x2, #4
+ str w3, [x4, #-4]!
+3: adds x2, x2, #2
+ b.mi 4f
+ ldrh w3, [x1, #-2]!
+ sub x2, x2, #2
+ strh w3, [x4, #-2]!
+4: adds x2, x2, #1
+ b.mi 5f
+ ldrb w3, [x1, #-1]
+ strb w3, [x4, #-1]
+5: ret
+ENDPROC(memmove)
diff --git a/arch/arm64/lib/memset.S b/arch/arm64/lib/memset.S
new file mode 100644
index 000000000000..87e4a68fbbbc
--- /dev/null
+++ b/arch/arm64/lib/memset.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Fill in the buffer with character c (alignment handled by the hardware)
+ *
+ * Parameters:
+ * x0 - buf
+ * x1 - c
+ * x2 - n
+ * Returns:
+ * x0 - buf
+ */
+ENTRY(memset)
+ mov x4, x0
+ and w1, w1, #0xff
+ orr w1, w1, w1, lsl #8
+ orr w1, w1, w1, lsl #16
+ orr x1, x1, x1, lsl #32
+ subs x2, x2, #8
+ b.mi 2f
+1: str x1, [x4], #8
+ subs x2, x2, #8
+ b.pl 1b
+2: adds x2, x2, #4
+ b.mi 3f
+ sub x2, x2, #4
+ str w1, [x4], #4
+3: adds x2, x2, #2
+ b.mi 4f
+ sub x2, x2, #2
+ strh w1, [x4], #2
+4: adds x2, x2, #1
+ b.mi 5f
+ strb w1, [x4]
+5: ret
+ENDPROC(memset)
diff --git a/arch/arm64/lib/strchr.S b/arch/arm64/lib/strchr.S
new file mode 100644
index 000000000000..dae0cf5591f9
--- /dev/null
+++ b/arch/arm64/lib/strchr.S
@@ -0,0 +1,42 @@
+/*
+ * Based on arch/arm/lib/strchr.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Find the first occurrence of a character in a string.
+ *
+ * Parameters:
+ * x0 - str
+ * x1 - c
+ * Returns:
+ * x0 - address of first occurrence of 'c' or 0
+ */
+ENTRY(strchr)
+ and w1, w1, #0xff
+1: ldrb w2, [x0], #1
+ cmp w2, w1
+ ccmp w2, wzr, #4, ne
+ b.ne 1b
+ sub x0, x0, #1
+ cmp w2, w1
+ csel x0, x0, xzr, eq
+ ret
+ENDPROC(strchr)
diff --git a/arch/arm64/lib/strrchr.S b/arch/arm64/lib/strrchr.S
new file mode 100644
index 000000000000..61eabd9a289a
--- /dev/null
+++ b/arch/arm64/lib/strrchr.S
@@ -0,0 +1,43 @@
+/*
+ * Based on arch/arm/lib/strrchr.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ * Copyright (C) 2013 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Find the last occurrence of a character in a string.
+ *
+ * Parameters:
+ * x0 - str
+ * x1 - c
+ * Returns:
+ * x0 - address of last occurrence of 'c' or 0
+ */
+ENTRY(strrchr)
+ mov x3, #0
+ and w1, w1, #0xff
+1: ldrb w2, [x0], #1
+ cbz w2, 2f
+ cmp w2, w1
+ b.ne 1b
+ sub x3, x0, #1
+ b 1b
+2: mov x0, x3
+ ret
+ENDPROC(strrchr)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index afadae6682ed..52638171d6fd 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -57,16 +57,16 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
pmd_t *pmd;
pte_t *pte;
- if (pgd_none_or_clear_bad(pgd))
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
break;
pud = pud_offset(pgd, addr);
- if (pud_none_or_clear_bad(pud))
+ if (pud_none(*pud) || pud_bad(*pud))
break;
pmd = pmd_offset(pud, addr);
printk(", *pmd=%016llx", pmd_val(*pmd));
- if (pmd_none_or_clear_bad(pmd))
+ if (pmd_none(*pmd) || pmd_bad(*pmd))
break;
pte = pte_offset_map(pmd, addr);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 800aac306a08..f497ca77925a 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -197,24 +197,6 @@ void __init bootmem_init(void)
max_pfn = max_low_pfn = max;
}
-static inline int free_area(unsigned long pfn, unsigned long end, char *s)
-{
- unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
-
- for (; pfn < end; pfn++) {
- struct page *page = pfn_to_page(pfn);
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- pages++;
- }
-
- if (size && s)
- pr_info("Freeing %s memory: %dK\n", s, size);
-
- return pages;
-}
-
/*
* Poison init memory with an undefined instruction (0x0).
*/
@@ -405,9 +387,7 @@ void __init mem_init(void)
void free_initmem(void)
{
poison_init_mem(__init_begin, __init_end - __init_begin);
- totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
- __phys_to_pfn(__pa(__init_end)),
- "init");
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -418,9 +398,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
{
if (!keep_initrd) {
poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
- totalram_pages += free_area(__phys_to_pfn(__pa(start)),
- __phys_to_pfn(__pa(end)),
- "initrd");
+ free_reserved_area(start, end, 0, "initrd");
}
}
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 224b44ab534e..eeecc9c8ed68 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -261,7 +261,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
{
unsigned long size, mask;
- bool page64k = IS_ENABLED(ARM64_64K_PAGES);
+ bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES);
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
@@ -391,17 +391,14 @@ int kern_addr_valid(unsigned long addr)
}
#ifdef CONFIG_SPARSEMEM_VMEMMAP
#ifdef CONFIG_ARM64_64K_PAGES
-int __meminit vmemmap_populate(struct page *start_page,
- unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
- return vmemmap_populate_basepages(start_page, size, node);
+ return vmemmap_populate_basepages(start, end, node);
}
#else /* !CONFIG_ARM64_64K_PAGES */
-int __meminit vmemmap_populate(struct page *start_page,
- unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
- unsigned long addr = (unsigned long)start_page;
- unsigned long end = (unsigned long)(start_page + size);
+ unsigned long addr = start;
unsigned long next;
pgd_t *pgd;
pud_t *pud;
@@ -434,7 +431,7 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0;
}
#endif /* CONFIG_ARM64_64K_PAGES */
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
{
}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index c1a868d398bd..22c40308360b 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -250,20 +250,7 @@ config ARCH_SUSPEND_POSSIBLE
def_bool y
menu "CPU Frequency scaling"
-
source "drivers/cpufreq/Kconfig"
-
-config CPU_FREQ_AT32AP
- bool "CPU frequency driver for AT32AP"
- depends on CPU_FREQ && PLATFORM_AT32AP
- default n
- help
- This enables the CPU frequency driver for AT32AP processors.
-
- For details, take a look in <file:Documentation/cpu-freq>.
-
- If in doubt, say N.
-
endmenu
endmenu
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
index f4025db184ff..d5aff36ade92 100644
--- a/arch/avr32/configs/atngw100_defconfig
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atngw100_evklcd100_defconfig b/arch/avr32/configs/atngw100_evklcd100_defconfig
index c76a49b9e9d0..4abcf435d599 100644
--- a/arch/avr32/configs/atngw100_evklcd100_defconfig
+++ b/arch/avr32/configs/atngw100_evklcd100_defconfig
@@ -28,7 +28,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atngw100_evklcd101_defconfig b/arch/avr32/configs/atngw100_evklcd101_defconfig
index 2d8ab089a64e..18f3fa0470ff 100644
--- a/arch/avr32/configs/atngw100_evklcd101_defconfig
+++ b/arch/avr32/configs/atngw100_evklcd101_defconfig
@@ -27,7 +27,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atngw100_mrmt_defconfig b/arch/avr32/configs/atngw100_mrmt_defconfig
index b189e0cab04b..06e389cfcd12 100644
--- a/arch/avr32/configs/atngw100_mrmt_defconfig
+++ b/arch/avr32/configs/atngw100_mrmt_defconfig
@@ -23,7 +23,7 @@ CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/avr32/configs/atngw100mkii_defconfig b/arch/avr32/configs/atngw100mkii_defconfig
index 2e4de42a53c4..2518a1368d7c 100644
--- a/arch/avr32/configs/atngw100mkii_defconfig
+++ b/arch/avr32/configs/atngw100mkii_defconfig
@@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig
index fad3cd22dfd3..245ef6bd0fa6 100644
--- a/arch/avr32/configs/atngw100mkii_evklcd100_defconfig
+++ b/arch/avr32/configs/atngw100mkii_evklcd100_defconfig
@@ -29,7 +29,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig
index 29986230aaa5..fa6cbac6e418 100644
--- a/arch/avr32/configs/atngw100mkii_evklcd101_defconfig
+++ b/arch/avr32/configs/atngw100mkii_evklcd101_defconfig
@@ -28,7 +28,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
index a582465e1cef..bbd5131021a5 100644
--- a/arch/avr32/configs/atstk1002_defconfig
+++ b/arch/avr32/configs/atstk1002_defconfig
@@ -25,7 +25,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atstk1003_defconfig b/arch/avr32/configs/atstk1003_defconfig
index 57a79df2ce5d..c1cd726f9012 100644
--- a/arch/avr32/configs/atstk1003_defconfig
+++ b/arch/avr32/configs/atstk1003_defconfig
@@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atstk1004_defconfig b/arch/avr32/configs/atstk1004_defconfig
index 1a49bd8c6340..754ae56b2767 100644
--- a/arch/avr32/configs/atstk1004_defconfig
+++ b/arch/avr32/configs/atstk1004_defconfig
@@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/atstk1006_defconfig b/arch/avr32/configs/atstk1006_defconfig
index 206a1b67f763..58589d8cc0ac 100644
--- a/arch/avr32/configs/atstk1006_defconfig
+++ b/arch/avr32/configs/atstk1006_defconfig
@@ -26,7 +26,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_NET=y
CONFIG_PACKET=y
diff --git a/arch/avr32/configs/favr-32_defconfig b/arch/avr32/configs/favr-32_defconfig
index 0421498d666b..57788a42ff83 100644
--- a/arch/avr32/configs/favr-32_defconfig
+++ b/arch/avr32/configs/favr-32_defconfig
@@ -27,7 +27,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/avr32/configs/hammerhead_defconfig b/arch/avr32/configs/hammerhead_defconfig
index 82f24eb251bd..ba7c31e269cb 100644
--- a/arch/avr32/configs/hammerhead_defconfig
+++ b/arch/avr32/configs/hammerhead_defconfig
@@ -31,7 +31,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/avr32/configs/mimc200_defconfig b/arch/avr32/configs/mimc200_defconfig
index 1bee51f22154..0a8bfdc420e0 100644
--- a/arch/avr32/configs/mimc200_defconfig
+++ b/arch/avr32/configs/mimc200_defconfig
@@ -24,7 +24,7 @@ CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_STAT is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_CPU_FREQ_AT32AP=y
+CONFIG_AVR32_AT32AP_CPUFREQ=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h
index cf60d0a9f176..fc6483f83ccc 100644
--- a/arch/avr32/include/asm/io.h
+++ b/arch/avr32/include/asm/io.h
@@ -165,6 +165,10 @@ BUILDIO_IOPORT(l, u32)
#define readw_be __raw_readw
#define readl_be __raw_readl
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
+
#define writeb_be __raw_writeb
#define writew_be __raw_writew
#define writel_be __raw_writel
diff --git a/arch/avr32/include/asm/unistd.h b/arch/avr32/include/asm/unistd.h
index dc4d5a931112..c1eb080e45fe 100644
--- a/arch/avr32/include/asm/unistd.h
+++ b/arch/avr32/include/asm/unistd.h
@@ -41,12 +41,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
-
#endif /* __ASM_AVR32_UNISTD_H */
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 51c6401582ea..37401f535126 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* __ASM_AVR32_SOCKET_H */
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index fd78f58ea79a..e7b61494c312 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -30,18 +30,9 @@ EXPORT_SYMBOL(pm_power_off);
* This file handles the architecture-dependent parts of process handling..
*/
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched())
- cpu_idle_sleep();
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+ cpu_enter_idle();
}
void machine_halt(void)
@@ -213,14 +204,6 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
}
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_trace_log_lvl(current, &stack, NULL, "");
-}
-EXPORT_SYMBOL(dump_stack);
-
static const char *cpu_modes[] = {
"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
"Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
@@ -232,6 +215,8 @@ void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
unsigned long lr = regs->lr;
unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;
+ show_regs_print_info(log_lvl);
+
if (!user_mode(regs)) {
sp = (unsigned long)regs + FRAME_SIZE_FULL;
@@ -269,9 +254,6 @@ void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
regs->sr & SR_I0M ? '0' : '.',
regs->sr & SR_GM ? 'G' : 'g');
printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
- printk("%sProcess: %s [%d] (task: %p thread: %p)\n",
- log_lvl, current->comm, current->pid, current,
- task_thread_info(current));
}
void show_regs(struct pt_regs *regs)
diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
index 05ad29112ff4..869a1c6ffeee 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -12,6 +12,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/time.h>
+#include <linux/cpu.h>
#include <asm/sysreg.h>
@@ -87,13 +88,17 @@ static void comparator_mode(enum clock_event_mode mode,
pr_debug("%s: start\n", evdev->name);
/* FALLTHROUGH */
case CLOCK_EVT_MODE_RESUME:
- cpu_disable_idle_sleep();
+ /*
+ * If we're using the COUNT and COMPARE registers we
+ * need to force idle poll.
+ */
+ cpu_idle_poll_ctrl(true);
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
sysreg_write(COMPARE, 0);
pr_debug("%s: stop\n", evdev->name);
- cpu_enable_idle_sleep();
+ cpu_idle_poll_ctrl(false);
break;
default:
BUG();
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index 514c9a9b009a..fc09ec4bc725 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,7 +1,6 @@
obj-y += pdc.o clock.o intc.o extint.o pio.o hsmc.o
obj-y += hmatrix.o
obj-$(CONFIG_CPU_AT32AP700X) += at32ap700x.o pm-at32ap700x.o
-obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
obj-$(CONFIG_PM) += pm.o
ifeq ($(CONFIG_PM_DEBUG),y)
diff --git a/arch/avr32/mach-at32ap/include/mach/pm.h b/arch/avr32/mach-at32ap/include/mach/pm.h
index 979b355b77b6..f29ff2cd23d3 100644
--- a/arch/avr32/mach-at32ap/include/mach/pm.h
+++ b/arch/avr32/mach-at32ap/include/mach/pm.h
@@ -21,30 +21,6 @@
extern void cpu_enter_idle(void);
extern void cpu_enter_standby(unsigned long sdramc_base);
-extern bool disable_idle_sleep;
-
-static inline void cpu_disable_idle_sleep(void)
-{
- disable_idle_sleep = true;
-}
-
-static inline void cpu_enable_idle_sleep(void)
-{
- disable_idle_sleep = false;
-}
-
-static inline void cpu_idle_sleep(void)
-{
- /*
- * If we're using the COUNT and COMPARE registers for
- * timekeeping, we can't use the IDLE state.
- */
- if (disable_idle_sleep)
- cpu_relax();
- else
- cpu_enter_idle();
-}
-
void intc_set_suspend_handler(unsigned long offset);
#endif
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S
index f868f4ce761b..1c8e4e6bff03 100644
--- a/arch/avr32/mach-at32ap/pm-at32ap700x.S
+++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
@@ -18,13 +18,6 @@
/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
#define PM_BASE -0x100000
- .section .bss, "wa", @nobits
- .global disable_idle_sleep
- .type disable_idle_sleep, @object
-disable_idle_sleep:
- .int 4
- .size disable_idle_sleep, . - disable_idle_sleep
-
/* Keep this close to the irq handlers */
.section .irq.text, "ax", @progbits
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index 2798c2d4a1cf..e66e8406f992 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -146,34 +146,14 @@ void __init mem_init(void)
initsize >> 10);
}
-static inline void free_area(unsigned long addr, unsigned long end, char *s)
-{
- unsigned int size = (end - addr) >> 10;
-
- for (; addr < end; addr += PAGE_SIZE) {
- struct page *page = virt_to_page(addr);
- ClearPageReserved(page);
- init_page_count(page);
- free_page(addr);
- totalram_pages++;
- }
-
- if (size && s)
- printk(KERN_INFO "Freeing %s memory: %dK (%lx - %lx)\n",
- s, size, end - (size << 10), end);
-}
-
void free_initmem(void)
{
- free_area((unsigned long)__init_begin, (unsigned long)__init_end,
- "init");
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
-
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_area(start, end, "initrd");
+ free_reserved_area(start, end, 0, "initrd");
}
-
#endif
diff --git a/arch/blackfin/include/asm/bfin_sport3.h b/arch/blackfin/include/asm/bfin_sport3.h
index 03c00220d69b..d82f5fa0ad9f 100644
--- a/arch/blackfin/include/asm/bfin_sport3.h
+++ b/arch/blackfin/include/asm/bfin_sport3.h
@@ -41,7 +41,7 @@
#define SPORT_CTL_LAFS 0x00020000 /* Late Transmit frame select */
#define SPORT_CTL_RJUST 0x00040000 /* Right Justified mode select */
#define SPORT_CTL_FSED 0x00080000 /* External frame sync edge select */
-#define SPORT_CTL_TFIEN 0x00100000 /* Transmit finish interrrupt enable select */
+#define SPORT_CTL_TFIEN 0x00100000 /* Transmit finish interrupt enable select */
#define SPORT_CTL_GCLKEN 0x00200000 /* Gated clock mode select */
#define SPORT_CTL_SPENSEC 0x01000000 /* Enable secondary channel */
#define SPORT_CTL_SPTRAN 0x02000000 /* Data direction control */
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h
index 04e83ea8d5cc..c35414bdf7bd 100644
--- a/arch/blackfin/include/asm/unistd.h
+++ b/arch/blackfin/include/asm/unistd.h
@@ -20,12 +20,4 @@
#define __ARCH_WANT_SYS_NICE
#define __ARCH_WANT_SYS_VFORK
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t_" #x "\n\t.set\t_" #x ",_sys_ni_syscall");
-
#endif /* __ASM_BFIN_UNISTD_H */
diff --git a/arch/blackfin/kernel/dumpstack.c b/arch/blackfin/kernel/dumpstack.c
index 5cfbaa298211..95ba6d9e9a3d 100644
--- a/arch/blackfin/kernel/dumpstack.c
+++ b/arch/blackfin/kernel/dumpstack.c
@@ -168,6 +168,7 @@ void dump_stack(void)
#endif
trace_buffer_save(tflags);
dump_bfin_trace_buffer();
+ dump_stack_print_info(KERN_DEFAULT);
show_stack(current, &stack);
trace_buffer_restore(tflags);
}
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 84ed8375113c..61fbd2de993d 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -25,8 +25,6 @@ extern struct console *bfin_earlyserial_init(unsigned int port,
extern struct console *bfin_jc_early_init(void);
#endif
-static struct console *early_console;
-
/* Default console */
#define DEFAULT_PORT 0
#define DEFAULT_CFLAG CS8|B57600
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 9782c0329c14..4aa5545c4fde 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -46,15 +46,14 @@ EXPORT_SYMBOL(pm_power_off);
* The idle loop on BFIN
*/
#ifdef CONFIG_IDLE_L1
-static void default_idle(void)__attribute__((l1_text));
-void cpu_idle(void)__attribute__((l1_text));
+void arch_cpu_idle(void)__attribute__((l1_text));
#endif
/*
* This is our default idle handler. We need to disable
* interrupts here to ensure we don't miss a wakeup call.
*/
-static void default_idle(void)
+void arch_cpu_idle(void)
{
#ifdef CONFIG_IPIPE
ipipe_suspend_domain();
@@ -66,31 +65,12 @@ static void default_idle(void)
hard_local_irq_enable();
}
-/*
- * The idle thread. We try to conserve power, while trying to keep
- * overall latency low. The architecture specific idle is passed
- * a value to indicate the level of "idleness" of the system.
- */
-void cpu_idle(void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
-
#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
-#endif
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched())
- default_idle();
- rcu_idle_exit();
- tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
}
+#endif
/*
* Do necessary setup to start up a newly executed thread.
diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c
index f7f7a18abca9..c36efa0c7163 100644
--- a/arch/blackfin/kernel/trace.c
+++ b/arch/blackfin/kernel/trace.c
@@ -853,6 +853,8 @@ void show_regs(struct pt_regs *fp)
unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic();
pr_notice("\n");
+ show_regs_print_info(KERN_NOTICE);
+
if (CPUID != bfin_cpuid())
pr_notice("Compiled for cpu family 0x%04x (Rev %d), "
"but running on:0x%04x (Rev %d)\n",
diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c
index 61c1f47a4bf2..97d701639585 100644
--- a/arch/blackfin/mach-bf609/boards/ezkit.c
+++ b/arch/blackfin/mach-bf609/boards/ezkit.c
@@ -936,19 +936,19 @@ static struct v4l2_input adv7842_inputs[] = {
.index = 2,
.name = "Component",
.type = V4L2_INPUT_TYPE_CAMERA,
- .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS,
+ .capabilities = V4L2_IN_CAP_DV_TIMINGS,
},
{
.index = 3,
.name = "VGA",
.type = V4L2_INPUT_TYPE_CAMERA,
- .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS,
+ .capabilities = V4L2_IN_CAP_DV_TIMINGS,
},
{
.index = 4,
.name = "HDMI",
.type = V4L2_INPUT_TYPE_CAMERA,
- .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS,
+ .capabilities = V4L2_IN_CAP_DV_TIMINGS,
},
};
@@ -1074,7 +1074,7 @@ static struct v4l2_output adv7511_outputs[] = {
.index = 0,
.name = "HDMI",
.type = V4L2_INPUT_TYPE_CAMERA,
- .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS,
+ .capabilities = V4L2_OUT_CAP_DV_TIMINGS,
},
};
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index 75f0ba29ebb9..675466d490d4 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_PM) += pm.o
ifneq ($(CONFIG_BF60x),y)
obj-$(CONFIG_PM) += dpmc_modes.o
endif
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index bb61ae4986e4..1bc2ce6f3c94 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -335,7 +335,7 @@ void __cpuinit secondary_start_kernel(void)
*/
calibrate_delay();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_prepare_boot_cpu(void)
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index 9cb85537bd2b..82d01a71207f 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -103,7 +103,7 @@ void __init mem_init(void)
max_mapnr = num_physpages = MAP_NR(high_memory);
printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", num_physpages);
- /* This will put all memory onto the freelists. */
+ /* This will put all low memory onto the freelists. */
totalram_pages = free_all_bootmem();
reservedpages = 0;
@@ -129,24 +129,11 @@ void __init mem_init(void)
initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
}
-static void __init free_init_pages(const char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
- /* next to check that the page we free is not a partial page */
- for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
-}
-
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
#ifndef CONFIG_MPU
- free_init_pages("initrd memory", start, end);
+ free_reserved_area(start, end, 0, "initrd");
#endif
}
#endif
@@ -154,10 +141,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
void __init_refok free_initmem(void)
{
#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
- free_init_pages("unused kernel memory",
- (unsigned long)(&__init_begin),
- (unsigned long)(&__init_end));
-
+ free_initmem_default(0);
if (memory_start == (unsigned long)(&__init_end))
memory_start = (unsigned long)(&__init_begin);
#endif
diff --git a/arch/c6x/include/asm/irqflags.h b/arch/c6x/include/asm/irqflags.h
index cf78e09e18c3..2c71d5634ec2 100644
--- a/arch/c6x/include/asm/irqflags.h
+++ b/arch/c6x/include/asm/irqflags.h
@@ -27,7 +27,7 @@ static inline unsigned long arch_local_save_flags(void)
/* set interrupt enabled status */
static inline void arch_local_irq_restore(unsigned long flags)
{
- asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags));
+ asm volatile (" mvc .s2 %0,CSR\n" : : "b"(flags) : "memory");
}
/* unconditionally enable interrupts */
diff --git a/arch/c6x/kernel/process.c b/arch/c6x/kernel/process.c
index 6434df476f77..57d2ea8d1977 100644
--- a/arch/c6x/kernel/process.c
+++ b/arch/c6x/kernel/process.c
@@ -33,7 +33,7 @@ extern asmlinkage void ret_from_kernel_thread(void);
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
-static void c6x_idle(void)
+void arch_cpu_idle(void)
{
unsigned long tmp;
@@ -49,32 +49,6 @@ static void c6x_idle(void)
: "=b"(tmp));
}
-/*
- * The idle loop for C64x
- */
-void cpu_idle(void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (1) {
- local_irq_disable();
- if (need_resched()) {
- local_irq_enable();
- break;
- }
- c6x_idle(); /* enables local irqs */
- }
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
-}
-
static void halt_loop(void)
{
printk(KERN_EMERG "System Halted, OK to turn off power\n");
diff --git a/arch/c6x/kernel/traps.c b/arch/c6x/kernel/traps.c
index 1be74e5b4788..dcc2c2f6d67c 100644
--- a/arch/c6x/kernel/traps.c
+++ b/arch/c6x/kernel/traps.c
@@ -31,6 +31,7 @@ void __init trap_init(void)
void show_regs(struct pt_regs *regs)
{
pr_err("\n");
+ show_regs_print_info(KERN_ERR);
pr_err("PC: %08lx SP: %08lx\n", regs->pc, regs->sp);
pr_err("Status: %08lx ORIG_A4: %08lx\n", regs->csr, regs->orig_a4);
pr_err("A0: %08lx B0: %08lx\n", regs->a0, regs->b0);
@@ -67,15 +68,6 @@ void show_regs(struct pt_regs *regs)
pr_err("A31: %08lx B31: %08lx\n", regs->a31, regs->b31);
}
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_stack(current, &stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
-
void die(char *str, struct pt_regs *fp, int nr)
{
console_verbose();
diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c
index 89395f09648a..a9fcd89b251b 100644
--- a/arch/c6x/mm/init.c
+++ b/arch/c6x/mm/init.c
@@ -77,37 +77,11 @@ void __init mem_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- pages++;
- }
- printk(KERN_INFO "Freeing initrd memory: %luk freed\n",
- (pages * PAGE_SIZE) >> 10);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
void __init free_initmem(void)
{
- unsigned long addr;
-
- /*
- * The following code should be cool even if these sections
- * are not page aligned.
- */
- addr = PAGE_ALIGN((unsigned long)(__init_begin));
-
- /* next to check that the page we free is not a partial page */
- for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
- addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing unused kernel memory: %dK freed\n",
- (int) ((addr - PAGE_ALIGN((long) &__init_begin)) >> 10));
+ free_initmem_default(0);
}
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index b1018750cffb..753e9a03cf87 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -30,8 +30,9 @@ void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */
void default_idle(void)
{
#ifdef CONFIG_ETRAX_GPIO
- etrax_gpio_wake_up_check();
+ etrax_gpio_wake_up_check();
#endif
+ local_irq_enable();
}
/*
@@ -175,6 +176,9 @@ unsigned long get_wchan(struct task_struct *p)
void show_regs(struct pt_regs * regs)
{
unsigned long usp = rdusp();
+
+ show_regs_print_info(KERN_DEFAULT);
+
printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
regs->irp, regs->srp, regs->dccr, usp, regs->mof );
printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index 2b23ef0e4452..cebd32e2a8fb 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -20,18 +20,12 @@
extern void stop_watchdog(void);
-extern int cris_hlt_counter;
-
/* We use this if we don't have any better idle routine. */
void default_idle(void)
{
- local_irq_disable();
- if (!need_resched() && !cris_hlt_counter) {
- /* Halt until exception. */
- __asm__ volatile("ei \n\t"
- "halt ");
- }
- local_irq_enable();
+ /* Halt until exception. */
+ __asm__ volatile("ei \n\t"
+ "halt ");
}
/*
@@ -170,6 +164,9 @@ get_wchan(struct task_struct *p)
void show_regs(struct pt_regs * regs)
{
unsigned long usp = rdusp();
+
+ show_regs_print_info(KERN_DEFAULT);
+
printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
regs->erp, regs->srp, regs->ccs, usp, regs->mof);
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 04a16edd5401..cdd12028de0c 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -145,8 +145,6 @@ smp_boot_one_cpu(int cpuid, struct task_struct idle)
* specific stuff such as the local timer and the MMU. */
void __init smp_callin(void)
{
- extern void cpu_idle(void);
-
int cpu = cpu_now_booting;
reg_intr_vect_rw_mask vect_mask = {0};
@@ -170,7 +168,7 @@ void __init smp_callin(void)
local_irq_enable();
set_cpu_online(cpu, true);
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/* Stop execution on this CPU.*/
diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile
index d366e0891988..18a227196a41 100644
--- a/arch/cris/arch-v32/mach-a3/Makefile
+++ b/arch/cris/arch-v32/mach-a3/Makefile
@@ -3,7 +3,6 @@
#
obj-y := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
clean:
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile
index d366e0891988..18a227196a41 100644
--- a/arch/cris/arch-v32/mach-fs/Makefile
+++ b/arch/cris/arch-v32/mach-fs/Makefile
@@ -3,7 +3,6 @@
#
obj-y := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
clean:
diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h
index 675823f70c0f..c0a29b96b92b 100644
--- a/arch/cris/include/asm/processor.h
+++ b/arch/cris/include/asm/processor.h
@@ -65,13 +65,6 @@ static inline void release_thread(struct task_struct *dead_task)
#define cpu_relax() barrier()
-/*
- * disable hlt during certain critical i/o operations
- */
-#define HAVE_DISABLE_HLT
-void disable_hlt(void);
-void enable_hlt(void);
-
void default_idle(void);
#endif /* __ASM_CRIS_PROCESSOR_H */
diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h
index be57a988bfb9..0ff3f6889842 100644
--- a/arch/cris/include/asm/unistd.h
+++ b/arch/cris/include/asm/unistd.h
@@ -34,12 +34,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _ASM_CRIS_UNISTD_H_ */
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index 50692b738c75..ba409c9947bc 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -74,6 +74,8 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 104ff4dd9b98..b78498eb079b 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -29,59 +29,14 @@
//#define DEBUG
-/*
- * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if
- * there would ever be a halt sequence (for power save when idle) with
- * some largish delay when halting or resuming *and* a driver that can't
- * afford that delay. The hlt_counter would then be checked before
- * executing the halt sequence, and the driver marks the unhaltable
- * region by enable_hlt/disable_hlt.
- */
-
-int cris_hlt_counter=0;
-
-void disable_hlt(void)
-{
- cris_hlt_counter++;
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- cris_hlt_counter--;
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
extern void default_idle(void);
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-
-void cpu_idle (void)
+void arch_cpu_idle(void)
{
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched()) {
- /*
- * Mark this as an RCU critical section so that
- * synchronize_kernel() in the unload path waits
- * for our completion.
- */
- default_idle();
- }
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
+ default_idle();
}
void hard_reset_now (void);
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c
index a11ad3229f8c..0ffda73734f5 100644
--- a/arch/cris/kernel/traps.c
+++ b/arch/cris/kernel/traps.c
@@ -147,13 +147,6 @@ show_stack(void)
#endif
void
-dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
-void
set_nmi_handler(void (*handler)(struct pt_regs *))
{
nmi_handler = handler;
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index d72ab58fd83e..9ac80946dada 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -12,12 +12,10 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <asm/tlb.h>
+#include <asm/sections.h>
unsigned long empty_zero_page;
-extern char _stext, _edata, _etext; /* From linkerscript */
-extern char __init_begin, __init_end;
-
void __init
mem_init(void)
{
@@ -67,15 +65,5 @@ mem_init(void)
void
free_initmem(void)
{
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n",
- (unsigned long)((&__init_end - &__init_begin) >> 10));
+ free_initmem_default(0);
}
diff --git a/arch/frv/include/asm/unistd.h b/arch/frv/include/asm/unistd.h
index 4cfcc7bba25a..70ec7293dce7 100644
--- a/arch/frv/include/asm/unistd.h
+++ b/arch/frv/include/asm/unistd.h
@@ -31,14 +31,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif
-
#endif /* _ASM_UNISTD_H_ */
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 595391f0f98c..31dbb5d8e13d 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -72,5 +72,7 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 23916b2a12a2..5d40aeb7712e 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -59,29 +59,12 @@ static void core_sleep_idle(void)
mb();
}
-void (*idle)(void) = core_sleep_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched()) {
- check_pgt_cache();
-
- if (!frv_dma_inprogress && idle)
- idle();
- }
- rcu_idle_exit();
-
- schedule_preempt_disabled();
- }
+ if (!frv_dma_inprogress)
+ core_sleep_idle();
+ else
+ local_irq_enable();
}
void machine_restart(char * __unused)
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 5cfd1420b091..4bff48c19d29 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -466,17 +466,6 @@ asmlinkage void compound_exception(unsigned long esfr1,
BUG();
} /* end compound_exception() */
-/*****************************************************************************/
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
void show_stack(struct task_struct *task, unsigned long *sp)
{
}
@@ -508,6 +497,7 @@ void show_regs(struct pt_regs *regs)
int loop;
printk("\n");
+ show_regs_print_info(KERN_DEFAULT);
printk("Frame: @%08lx [%s]\n",
(unsigned long) regs,
@@ -522,8 +512,6 @@ void show_regs(struct pt_regs *regs)
else
printk(" | ");
}
-
- printk("Process %s (pid: %d)\n", current->comm, current->pid);
}
void die_if_kernel(const char *str, ...)
diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c
index 92e97b0894a6..dee354fa6b64 100644
--- a/arch/frv/mm/init.c
+++ b/arch/frv/mm/init.c
@@ -122,7 +122,7 @@ void __init mem_init(void)
#endif
int codek = 0, datak = 0;
- /* this will put all memory onto the freelists */
+ /* this will put all low memory onto the freelists */
totalram_pages = free_all_bootmem();
#ifdef CONFIG_MMU
@@ -131,14 +131,8 @@ void __init mem_init(void)
datapages++;
#ifdef CONFIG_HIGHMEM
- for (pfn = num_physpages - 1; pfn >= num_mappedpages; pfn--) {
- struct page *page = &mem_map[pfn];
-
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- }
+ for (pfn = num_physpages - 1; pfn >= num_mappedpages; pfn--)
+ free_highmem_page(&mem_map[pfn]);
#endif
codek = ((unsigned long) &_etext - (unsigned long) &_stext) >> 10;
@@ -168,21 +162,7 @@ void __init mem_init(void)
void free_initmem(void)
{
#if defined(CONFIG_RAMKERNEL) && !defined(CONFIG_PROTECT_KERNEL)
- unsigned long start, end, addr;
-
- start = PAGE_ALIGN((unsigned long) &__init_begin); /* round up */
- end = ((unsigned long) &__init_end) & PAGE_MASK; /* round down */
-
- /* next to check that the page we free is not a partial page */
- for (addr = start; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
-
- printk("Freeing unused kernel memory: %ldKiB freed (0x%lx - 0x%lx)\n",
- (end - start) >> 10, start, end);
+ free_initmem_default(0);
#endif
} /* end free_initmem() */
@@ -193,14 +173,6 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- pages++;
- }
- printk("Freeing initrd memory: %dKiB freed\n", (pages * PAGE_SIZE) >> 10);
+ free_reserved_area(start, end, 0, "initrd");
} /* end free_initrd_mem() */
#endif
diff --git a/arch/h8300/include/asm/linkage.h b/arch/h8300/include/asm/linkage.h
index 6f4df7d46180..1d81604fb0ad 100644
--- a/arch/h8300/include/asm/linkage.h
+++ b/arch/h8300/include/asm/linkage.h
@@ -2,7 +2,5 @@
#define _H8300_LINKAGE_H
#undef SYMBOL_NAME_LABEL
-#undef SYMBOL_NAME
#define SYMBOL_NAME_LABEL(_name_) _##_name_##:
-#define SYMBOL_NAME(_name_) _##_name_
#endif
diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h
index 6721856d841b..ab671ecf5196 100644
--- a/arch/h8300/include/asm/unistd.h
+++ b/arch/h8300/include/asm/unistd.h
@@ -33,11 +33,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- */
-#define cond_syscall(name) \
- asm (".weak\t_" #name "\n" \
- ".set\t_" #name ",_sys_ni_syscall");
-
#endif /* _ASM_H8300_UNISTD_H_ */
diff --git a/arch/h8300/include/uapi/asm/socket.h b/arch/h8300/include/uapi/asm/socket.h
index 43e32621da7d..5d1c6d0870e6 100644
--- a/arch/h8300/include/uapi/asm/socket.h
+++ b/arch/h8300/include/uapi/asm/socket.h
@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index b609f63f1590..1a744ab7e7e5 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -53,40 +53,13 @@ asmlinkage void ret_from_kernel_thread(void);
* The idle loop on an H8/300..
*/
#if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
-static void default_idle(void)
+void arch_cpu_idle(void)
{
- local_irq_disable();
- if (!need_resched()) {
- local_irq_enable();
- /* XXX: race here! What if need_resched() gets set now? */
- __asm__("sleep");
- } else
- local_irq_enable();
-}
-#else
-static void default_idle(void)
-{
- cpu_relax();
+ local_irq_enable();
+ /* XXX: race here! What if need_resched() gets set now? */
+ __asm__("sleep");
}
#endif
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- idle();
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
-}
void machine_restart(char * __unused)
{
@@ -110,6 +83,8 @@ void machine_power_off(void)
void show_regs(struct pt_regs * regs)
{
+ show_regs_print_info(KERN_DEFAULT);
+
printk("\nPC: %08lx Status: %02x",
regs->pc, regs->ccr);
printk("\nORIG_ER0: %08lx ER0: %08lx ER1: %08lx",
diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c
index 7833aa3e7c7d..cfe494dbe3da 100644
--- a/arch/h8300/kernel/traps.c
+++ b/arch/h8300/kernel/traps.c
@@ -164,10 +164,3 @@ void show_trace_task(struct task_struct *tsk)
{
show_stack(tsk,(unsigned long *)tsk->thread.esp0);
}
-
-void dump_stack(void)
-{
- show_stack(NULL,NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
index 981e25094b1a..ff349d70a29b 100644
--- a/arch/h8300/mm/init.c
+++ b/arch/h8300/mm/init.c
@@ -139,7 +139,7 @@ void __init mem_init(void)
start_mem = PAGE_ALIGN(start_mem);
max_mapnr = num_physpages = MAP_NR(high_memory);
- /* this will put all memory onto the freelists */
+ /* this will put all low memory onto the freelists */
totalram_pages = free_all_bootmem();
codek = (_etext - _stext) >> 10;
@@ -161,15 +161,7 @@ void __init mem_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- pages++;
- }
- printk ("Freeing initrd memory: %dk freed\n", pages);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
@@ -177,23 +169,7 @@ void
free_initmem(void)
{
#ifdef CONFIG_RAMKERNEL
- unsigned long addr;
-/*
- * the following code should be cool even if these sections
- * are not page aligned.
- */
- addr = PAGE_ALIGN((unsigned long)(__init_begin));
- /* next to check that the page we free is not a partial page */
- for (; addr + PAGE_SIZE < (unsigned long)__init_end; addr +=PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
- (addr - PAGE_ALIGN((long) __init_begin)) >> 10,
- (int)(PAGE_ALIGN((unsigned long)__init_begin)),
- (int)(addr - PAGE_SIZE));
+ free_initmem_default(0);
#endif
}
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index e4decc6b8947..04dff5bdcbf7 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -29,21 +29,17 @@ config HEXAGON
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST
select MODULES_USE_ELF_RELA
+ select GENERIC_CPU_DEVICES
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
---help---
Qualcomm Hexagon is a processor architecture designed for high
performance and low power across a wide variety of applications.
-config HEXAGON_ARCH_V1
- bool
-
-config HEXAGON_ARCH_V2
- bool
-
-config HEXAGON_ARCH_V3
- bool
-
-config HEXAGON_ARCH_V4
- bool
+config HEXAGON_PHYS_OFFSET
+ def_bool y
+ ---help---
+ Platforms that don't load the kernel at zero set this.
config FRAME_POINTER
def_bool y
@@ -81,9 +77,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
def_bool y
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
@@ -103,14 +96,14 @@ choice
config HEXAGON_COMET
bool "Comet Board"
- select HEXAGON_ARCH_V2
---help---
Support for the Comet platform.
endchoice
-config HEXAGON_VM
- def_bool y
+config HEXAGON_ARCH_VERSION
+ int "Architecture version"
+ default 2
config CMDLINE
string "Default kernel command string"
@@ -122,12 +115,6 @@ config CMDLINE
minimum, you should specify the memory size and the root device
(e.g., mem=64M root=/dev/nfs).
-config HEXAGON_ANGEL_TRAPS
- bool "Use Angel Traps"
- default n
- ---help---
- Enable angel debug traps (for printk's).
-
config SMP
bool "Multi-Processing support"
---help---
diff --git a/arch/hexagon/Makefile b/arch/hexagon/Makefile
index d00d900b2566..207711a0fd0c 100644
--- a/arch/hexagon/Makefile
+++ b/arch/hexagon/Makefile
@@ -15,20 +15,9 @@ KBUILD_CFLAGS += -fno-short-enums
# LDFLAGS_MODULE += -shared
CFLAGS_MODULE += -mlong-calls
-cflags-$(CONFIG_HEXAGON_ARCH_V1) += $(call cc-option,-mv1)
-cflags-$(CONFIG_HEXAGON_ARCH_V2) += $(call cc-option,-mv2)
-cflags-$(CONFIG_HEXAGON_ARCH_V3) += $(call cc-option,-mv3)
-cflags-$(CONFIG_HEXAGON_ARCH_V4) += $(call cc-option,-mv4)
-
-aflags-$(CONFIG_HEXAGON_ARCH_V1) += $(call cc-option,-mv1)
-aflags-$(CONFIG_HEXAGON_ARCH_V2) += $(call cc-option,-mv2)
-aflags-$(CONFIG_HEXAGON_ARCH_V3) += $(call cc-option,-mv3)
-aflags-$(CONFIG_HEXAGON_ARCH_V4) += $(call cc-option,-mv4)
-
-ldflags-$(CONFIG_HEXAGON_ARCH_V1) += $(call cc-option,-mv1)
-ldflags-$(CONFIG_HEXAGON_ARCH_V2) += $(call cc-option,-mv2)
-ldflags-$(CONFIG_HEXAGON_ARCH_V3) += $(call cc-option,-mv3)
-ldflags-$(CONFIG_HEXAGON_ARCH_V4) += $(call cc-option,-mv4)
+cflags-y += $(call cc-option,-mv${CONFIG_HEXAGON_ARCH_VERSION})
+aflags-y += $(call cc-option,-mv${CONFIG_HEXAGON_ARCH_VERSION})
+ldflags-y += $(call cc-option,-mv${CONFIG_HEXAGON_ARCH_VERSION})
KBUILD_CFLAGS += $(cflags-y)
KBUILD_AFLAGS += $(aflags-y)
diff --git a/arch/hexagon/include/asm/Kbuild b/arch/hexagon/include/asm/Kbuild
index bdb54ceb53bc..1da17caac23c 100644
--- a/arch/hexagon/include/asm/Kbuild
+++ b/arch/hexagon/include/asm/Kbuild
@@ -25,7 +25,6 @@ generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += local64.h
generic-y += local.h
-generic-y += local.h
generic-y += mman.h
generic-y += msgbuf.h
generic-y += pci.h
@@ -41,6 +40,7 @@ generic-y += sembuf.h
generic-y += shmbuf.h
generic-y += shmparam.h
generic-y += siginfo.h
+generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
generic-y += statfs.h
diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h
index 468fbb0781cd..8a64ff2337f6 100644
--- a/arch/hexagon/include/asm/atomic.h
+++ b/arch/hexagon/include/asm/atomic.h
@@ -1,7 +1,7 @@
/*
* Atomic operations for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
@@ -117,35 +117,37 @@ static inline int atomic_sub_return(int i, atomic_t *v)
#define atomic_sub(i, v) atomic_sub_return(i, (v))
/**
- * atomic_add_unless - add unless the number is a given value
+ * __atomic_add_unless - add unless the number is a given value
* @v: pointer to value
* @a: amount to add
* @u: unless value is equal to u
*
- * Returns 1 if the add happened, 0 if it didn't.
+ * Returns old value.
+ *
*/
+
static inline int __atomic_add_unless(atomic_t *v, int a, int u)
{
- int output, __oldval;
+ int __oldval;
+ register int tmp;
+
asm volatile(
"1: %0 = memw_locked(%2);"
" {"
" p3 = cmp.eq(%0, %4);"
" if (p3.new) jump:nt 2f;"
- " %0 = add(%0, %3);"
- " %1 = #0;"
+ " %1 = add(%0, %3);"
" }"
- " memw_locked(%2, p3) = %0;"
+ " memw_locked(%2, p3) = %1;"
" {"
" if !p3 jump 1b;"
- " %1 = #1;"
" }"
"2:"
- : "=&r" (__oldval), "=&r" (output)
+ : "=&r" (__oldval), "=&r" (tmp)
: "r" (v), "r" (a), "r" (u)
: "memory", "p3"
);
- return output;
+ return __oldval;
}
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
diff --git a/arch/hexagon/include/asm/elf.h b/arch/hexagon/include/asm/elf.h
index 1f14e082588e..e1b933a0e121 100644
--- a/arch/hexagon/include/asm/elf.h
+++ b/arch/hexagon/include/asm/elf.h
@@ -1,7 +1,7 @@
/*
* ELF definitions for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -104,6 +104,16 @@ typedef unsigned long elf_fpregset_t;
* Bypass the whole "regsets" thing for now and use the define.
*/
+#if CONFIG_HEXAGON_ARCH_VERSION >= 4
+#define CS_COPYREGS(DEST,REGS) \
+do {\
+ DEST.cs0 = REGS->cs0;\
+ DEST.cs1 = REGS->cs1;\
+} while (0)
+#else
+#define CS_COPYREGS(DEST,REGS)
+#endif
+
#define ELF_CORE_COPY_REGS(DEST, REGS) \
do { \
DEST.r0 = REGS->r00; \
@@ -148,13 +158,12 @@ do { \
DEST.p3_0 = REGS->preds; \
DEST.gp = REGS->gp; \
DEST.ugp = REGS->ugp; \
- DEST.pc = pt_elr(REGS); \
+ CS_COPYREGS(DEST,REGS); \
+ DEST.pc = pt_elr(REGS); \
DEST.cause = pt_cause(REGS); \
DEST.badva = pt_badva(REGS); \
} while (0);
-
-
/*
* This is used to ensure we don't load something for the wrong architecture.
* Checks the machine and ABI type.
@@ -168,15 +177,15 @@ do { \
#define ELF_DATA ELFDATA2LSB
#define ELF_ARCH EM_HEXAGON
-#ifdef CONFIG_HEXAGON_ARCH_V2
+#if CONFIG_HEXAGON_ARCH_VERSION == 2
#define ELF_CORE_EFLAGS 0x1
#endif
-#ifdef CONFIG_HEXAGON_ARCH_V3
+#if CONFIG_HEXAGON_ARCH_VERSION == 3
#define ELF_CORE_EFLAGS 0x2
#endif
-#ifdef CONFIG_HEXAGON_ARCH_V4
+#if CONFIG_HEXAGON_ARCH_VERSION == 4
#define ELF_CORE_EFLAGS 0x3
#endif
diff --git a/arch/hexagon/include/asm/hexagon_vm.h b/arch/hexagon/include/asm/hexagon_vm.h
index c144bee6cabe..67bb6d6f3337 100644
--- a/arch/hexagon/include/asm/hexagon_vm.h
+++ b/arch/hexagon/include/asm/hexagon_vm.h
@@ -1,7 +1,7 @@
/*
* Declarations for to Hexagon Virtal Machine.
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -31,10 +31,26 @@
* for tracing/debugging.
*/
-/*
- * Lets make this stuff visible only if configured,
- * so we can unconditionally include the file.
- */
+#define HVM_TRAP1_VMVERSION 0
+#define HVM_TRAP1_VMRTE 1
+#define HVM_TRAP1_VMSETVEC 2
+#define HVM_TRAP1_VMSETIE 3
+#define HVM_TRAP1_VMGETIE 4
+#define HVM_TRAP1_VMINTOP 5
+#define HVM_TRAP1_VMCLRMAP 10
+#define HVM_TRAP1_VMNEWMAP 11
+#define HVM_TRAP1_FORMERLY_VMWIRE 12
+#define HVM_TRAP1_VMCACHE 13
+#define HVM_TRAP1_VMGETTIME 14
+#define HVM_TRAP1_VMSETTIME 15
+#define HVM_TRAP1_VMWAIT 16
+#define HVM_TRAP1_VMYIELD 17
+#define HVM_TRAP1_VMSTART 18
+#define HVM_TRAP1_VMSTOP 19
+#define HVM_TRAP1_VMVPID 20
+#define HVM_TRAP1_VMSETREGS 21
+#define HVM_TRAP1_VMGETREGS 22
+#define HVM_TRAP1_VMTIMEROP 24
#ifndef __ASSEMBLY__
@@ -175,31 +191,19 @@ static inline long __vmintop_clear(long i)
#else /* Only assembly code should reference these */
-#define HVM_TRAP1_VMRTE 1
-#define HVM_TRAP1_VMSETVEC 2
-#define HVM_TRAP1_VMSETIE 3
-#define HVM_TRAP1_VMGETIE 4
-#define HVM_TRAP1_VMINTOP 5
-#define HVM_TRAP1_VMCLRMAP 10
-#define HVM_TRAP1_VMNEWMAP 11
-#define HVM_TRAP1_FORMERLY_VMWIRE 12
-#define HVM_TRAP1_VMCACHE 13
-#define HVM_TRAP1_VMGETTIME 14
-#define HVM_TRAP1_VMSETTIME 15
-#define HVM_TRAP1_VMWAIT 16
-#define HVM_TRAP1_VMYIELD 17
-#define HVM_TRAP1_VMSTART 18
-#define HVM_TRAP1_VMSTOP 19
-#define HVM_TRAP1_VMVPID 20
-#define HVM_TRAP1_VMSETREGS 21
-#define HVM_TRAP1_VMGETREGS 22
-
#endif /* __ASSEMBLY__ */
/*
* Constants for virtual instruction parameters and return values
*/
+/* vmnewmap arguments */
+
+#define VM_TRANS_TYPE_LINEAR 0
+#define VM_TRANS_TYPE_TABLE 1
+#define VM_TLB_INVALIDATE_FALSE 0
+#define VM_TLB_INVALIDATE_TRUE 1
+
/* vmsetie arguments */
#define VM_INT_DISABLE 0
@@ -224,6 +228,8 @@ static inline long __vmintop_clear(long i)
#define HVM_VMEST_UM_MSK 1
#define HVM_VMEST_IE_SFT 30
#define HVM_VMEST_IE_MSK 1
+#define HVM_VMEST_SS_SFT 29
+#define HVM_VMEST_SS_MSK 1
#define HVM_VMEST_EVENTNUM_SFT 16
#define HVM_VMEST_EVENTNUM_MSK 0xff
#define HVM_VMEST_CAUSE_SFT 0
@@ -260,6 +266,8 @@ static inline long __vmintop_clear(long i)
#define HVM_GE_C_INVI 0x15
#define HVM_GE_C_PRIVI 0x1B
#define HVM_GE_C_XMAL 0x1C
+#define HVM_GE_C_WREG 0x1D
+#define HVM_GE_C_PCAL 0x1E
#define HVM_GE_C_RMAL 0x20
#define HVM_GE_C_WMAL 0x21
#define HVM_GE_C_RPROT 0x22
diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h
index e527cfeff5ba..1b7698e19139 100644
--- a/arch/hexagon/include/asm/io.h
+++ b/arch/hexagon/include/asm/io.h
@@ -1,7 +1,7 @@
/*
* IO definitions for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -40,6 +40,8 @@
#define IO_SPACE_LIMIT 0xffff
#define _IO_BASE ((void __iomem *)0xfe000000)
+#define IOMEM(x) ((void __force __iomem *)(x))
+
extern int remap_area_pages(unsigned long start, unsigned long phys_addr,
unsigned long end, unsigned long flags);
@@ -176,6 +178,18 @@ static inline void writel(u32 data, volatile void __iomem *addr)
#define __raw_readl readl
/*
+ * http://comments.gmane.org/gmane.linux.ports.arm.kernel/117626
+ */
+
+#define readb_relaxed __raw_readb
+#define readw_relaxed __raw_readw
+#define readl_relaxed __raw_readl
+
+#define writeb_relaxed __raw_writeb
+#define writew_relaxed __raw_writew
+#define writel_relaxed __raw_writel
+
+/*
* Need an mtype somewhere in here, for cache type deals?
* This is probably too long for an inline.
*/
diff --git a/arch/hexagon/include/asm/mem-layout.h b/arch/hexagon/include/asm/mem-layout.h
index af16e977c55e..60556f8c45d8 100644
--- a/arch/hexagon/include/asm/mem-layout.h
+++ b/arch/hexagon/include/asm/mem-layout.h
@@ -1,7 +1,7 @@
/*
* Memory layout definitions for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -32,16 +32,25 @@
#define PAGE_OFFSET _AC(0xc0000000, UL)
/*
- * LOAD_ADDRESS is the physical/linear address of where in memory
- * the kernel gets loaded. The 12 least significant bits must be zero (0)
- * due to limitations on setting the EVB
- *
+ * Compiling for a platform that needs a crazy physical offset
+ * (like if the memory starts at 1GB and up) means we need
+ * an actual PHYS_OFFSET. Should be set up in head.S.
*/
-#ifndef LOAD_ADDRESS
-#define LOAD_ADDRESS 0x00000000
+#ifdef CONFIG_HEXAGON_PHYS_OFFSET
+#ifndef __ASSEMBLY__
+extern unsigned long __phys_offset;
+#endif
+#define PHYS_OFFSET __phys_offset
+#endif
+
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET 0
#endif
+#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
+#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET
+
#define TASK_SIZE (PAGE_OFFSET)
/* not sure how these are used yet */
@@ -55,7 +64,7 @@ enum fixed_addresses {
__end_of_fixed_addresses
};
-#define MIN_KERNEL_SEG 0x300 /* From 0xc0000000 */
+#define MIN_KERNEL_SEG (PAGE_OFFSET >> PGDIR_SHIFT) /* L1 shift is 22 bits */
extern int max_kernel_seg;
/*
@@ -63,8 +72,7 @@ extern int max_kernel_seg;
* supposed to be based on the amount of physical memory available
*/
-#define VMALLOC_START (PAGE_OFFSET + VMALLOC_OFFSET + \
- (unsigned long)high_memory)
+#define VMALLOC_START ((unsigned long) __va(high_memory + VMALLOC_OFFSET))
/* Gap between physical ram and vmalloc space for guard purposes. */
#define VMALLOC_OFFSET PAGE_SIZE
diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h
index 692adc213429..93f5669b4aa1 100644
--- a/arch/hexagon/include/asm/page.h
+++ b/arch/hexagon/include/asm/page.h
@@ -1,7 +1,7 @@
/*
* Page management definitions for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -96,8 +96,8 @@ typedef struct page *pgtable_t;
* MIPS says they're only used during mem_init.
* also, check if we need a PHYS_OFFSET.
*/
-#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
-#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x) - PHYS_OFFSET + PAGE_OFFSET))
/* The "page frame" descriptor is defined in linux/mm.h */
struct page;
@@ -140,6 +140,11 @@ static inline void clear_page(void *page)
*/
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
+
+#define page_to_virt(page) __va(page_to_phys(page))
+
/*
* For port to Hexagon Virtual Machine, MAYBE we check for attempts
* to reference reserved HVM space, but in any case, the VM will be
@@ -147,6 +152,7 @@ static inline void clear_page(void *page)
*/
#define kern_addr_valid(addr) (1)
+#include <asm/mem-layout.h>
#include <asm-generic/memory_model.h>
/* XXX Todo: implement assembly-optimized version of getorder. */
#include <asm-generic/getorder.h>
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h
index 6dd5d3706869..45a825402f63 100644
--- a/arch/hexagon/include/asm/processor.h
+++ b/arch/hexagon/include/asm/processor.h
@@ -1,7 +1,7 @@
/*
* Process/processor support for the Hexagon architecture
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -100,12 +100,49 @@ extern unsigned long get_wchan(struct task_struct *p);
*/
struct hexagon_switch_stack {
- unsigned long long r1716;
- unsigned long long r1918;
- unsigned long long r2120;
- unsigned long long r2322;
- unsigned long long r2524;
- unsigned long long r2726;
+ union {
+ struct {
+ unsigned long r16;
+ unsigned long r17;
+ };
+ unsigned long long r1716;
+ };
+ union {
+ struct {
+ unsigned long r18;
+ unsigned long r19;
+ };
+ unsigned long long r1918;
+ };
+ union {
+ struct {
+ unsigned long r20;
+ unsigned long r21;
+ };
+ unsigned long long r2120;
+ };
+ union {
+ struct {
+ unsigned long r22;
+ unsigned long r23;
+ };
+ unsigned long long r2322;
+ };
+ union {
+ struct {
+ unsigned long r24;
+ unsigned long r25;
+ };
+ unsigned long long r2524;
+ };
+ union {
+ struct {
+ unsigned long r26;
+ unsigned long r27;
+ };
+ unsigned long long r2726;
+ };
+
unsigned long fp;
unsigned long lr;
};
diff --git a/arch/hexagon/include/asm/vm_mmu.h b/arch/hexagon/include/asm/vm_mmu.h
index 9a94de7969bb..096537d8f4c5 100644
--- a/arch/hexagon/include/asm/vm_mmu.h
+++ b/arch/hexagon/include/asm/vm_mmu.h
@@ -1,7 +1,7 @@
/*
* Hexagon VM page table entry definitions
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2011,2013 The Linux Foundation. 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 and
@@ -68,14 +68,13 @@
#define __HEXAGON_C_WB 0x0 /* Write-back, no L2 */
#define __HEXAGON_C_WT 0x1 /* Write-through, no L2 */
+#define __HEXAGON_C_UNC 0x6 /* Uncached memory */
+#if CONFIG_HEXAGON_ARCH_VERSION >= 2
#define __HEXAGON_C_DEV 0x4 /* Device register space */
-#define __HEXAGON_C_WT_L2 0x5 /* Write-through, with L2 */
-/* this really should be #if CONFIG_HEXAGON_ARCH = 2 but that's not defined */
-#if defined(CONFIG_HEXAGON_COMET) || defined(CONFIG_QDSP6_ST1)
-#define __HEXAGON_C_UNC __HEXAGON_C_DEV
#else
-#define __HEXAGON_C_UNC 0x6 /* Uncached memory */
+#define __HEXAGON_C_DEV __HEXAGON_C_UNC
#endif
+#define __HEXAGON_C_WT_L2 0x5 /* Write-through, with L2 */
#define __HEXAGON_C_WB_L2 0x7 /* Write-back, with L2 */
/*
diff --git a/arch/hexagon/include/uapi/asm/ptrace.h b/arch/hexagon/include/uapi/asm/ptrace.h
index 1ffce0c6ee07..065e5b32313f 100644
--- a/arch/hexagon/include/uapi/asm/ptrace.h
+++ b/arch/hexagon/include/uapi/asm/ptrace.h
@@ -36,4 +36,9 @@ extern const char *regs_query_register_name(unsigned int offset);
((struct pt_regs *) \
((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
+#if CONFIG_HEXAGON_ARCH_VERSION >= 4
+#define arch_has_single_step() (1)
+#endif
+
+
#endif
diff --git a/arch/hexagon/include/uapi/asm/registers.h b/arch/hexagon/include/uapi/asm/registers.h
index c20406f63b5c..487d6ceca5e7 100644
--- a/arch/hexagon/include/uapi/asm/registers.h
+++ b/arch/hexagon/include/uapi/asm/registers.h
@@ -57,10 +57,17 @@ struct pt_regs {
};
union {
struct {
- unsigned long gp;
unsigned long ugp;
+ unsigned long gp;
};
- long long int ugpgp;
+ long long int gpugp;
+ };
+ union {
+ struct {
+ unsigned long cs0;
+ unsigned long cs1;
+ };
+ long long int cs1cs0;
};
/*
* Be extremely careful with rearranging these, if at all. Some code
@@ -204,9 +211,11 @@ struct pt_regs {
#define pt_psp(regs) ((regs)->hvmer.vmpsp)
#define pt_badva(regs) ((regs)->hvmer.vmbadva)
+#define pt_set_singlestep(regs) ((regs)->hvmer.vmest |= (1<<HVM_VMEST_SS_SFT))
+#define pt_clr_singlestep(regs) ((regs)->hvmer.vmest &= ~(1<<HVM_VMEST_SS_SFT))
+
#define pt_set_rte_sp(regs, sp) do {\
- pt_psp(regs) = (sp);\
- (regs)->SP = (unsigned long) &((regs)->hvmer);\
+ pt_psp(regs) = (regs)->SP = (sp);\
} while (0)
#define pt_set_kmode(regs) \
diff --git a/arch/hexagon/include/uapi/asm/signal.h b/arch/hexagon/include/uapi/asm/signal.h
index 939556817d34..98106e55ad4f 100644
--- a/arch/hexagon/include/uapi/asm/signal.h
+++ b/arch/hexagon/include/uapi/asm/signal.h
@@ -19,8 +19,12 @@
#ifndef _ASM_SIGNAL_H
#define _ASM_SIGNAL_H
+#include <uapi/asm/registers.h>
+
extern unsigned long __rt_sigtramp_template[2];
+void do_signal(struct pt_regs *regs);
+
#include <asm-generic/signal.h>
#endif
diff --git a/arch/hexagon/include/uapi/asm/unistd.h b/arch/hexagon/include/uapi/asm/unistd.h
index 4a87cc47075c..ffee405d6803 100644
--- a/arch/hexagon/include/uapi/asm/unistd.h
+++ b/arch/hexagon/include/uapi/asm/unistd.h
@@ -27,6 +27,9 @@
*/
#define sys_mmap2 sys_mmap_pgoff
+#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_FORK
#include <asm-generic/unistd.h>
diff --git a/arch/hexagon/include/uapi/asm/user.h b/arch/hexagon/include/uapi/asm/user.h
index cef13ee1413f..3dae94d9ced7 100644
--- a/arch/hexagon/include/uapi/asm/user.h
+++ b/arch/hexagon/include/uapi/asm/user.h
@@ -55,9 +55,15 @@ struct user_regs_struct {
unsigned long pc;
unsigned long cause;
unsigned long badva;
+#if CONFIG_HEXAGON_ARCH_VERSION < 4
unsigned long pad1; /* pad out to 48 words total */
unsigned long pad2; /* pad out to 48 words total */
unsigned long pad3; /* pad out to 48 words total */
+#else
+ unsigned long cs0;
+ unsigned long cs1;
+ unsigned long pad1; /* pad out to 48 words total */
+#endif
};
#endif
diff --git a/arch/hexagon/kernel/Makefile b/arch/hexagon/kernel/Makefile
index 6c19501b487c..29fc933a7722 100644
--- a/arch/hexagon/kernel/Makefile
+++ b/arch/hexagon/kernel/Makefile
@@ -1,6 +1,6 @@
extra-y := head.o vmlinux.lds
-obj-$(CONFIG_SMP) += smp.o topology.o
+obj-$(CONFIG_SMP) += smp.o
obj-y += setup.o irq_cpu.o traps.o syscalltab.o signal.o time.o
obj-y += process.o trampoline.o reset.o ptrace.o vdso.o
diff --git a/arch/hexagon/kernel/asm-offsets.c b/arch/hexagon/kernel/asm-offsets.c
index 2d5e84d3b00d..308be68d4fb3 100644
--- a/arch/hexagon/kernel/asm-offsets.c
+++ b/arch/hexagon/kernel/asm-offsets.c
@@ -5,7 +5,7 @@
* Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -44,7 +44,8 @@ int main(void)
COMMENT("Hexagon pt_regs definitions");
OFFSET(_PT_SYSCALL_NR, pt_regs, syscall_nr);
- OFFSET(_PT_UGPGP, pt_regs, ugpgp);
+ OFFSET(_PT_GPUGP, pt_regs, gpugp);
+ OFFSET(_PT_CS1CS0, pt_regs, cs1cs0);
OFFSET(_PT_R3130, pt_regs, r3130);
OFFSET(_PT_R2928, pt_regs, r2928);
OFFSET(_PT_R2726, pt_regs, r2726);
diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c
index 65c7bdcf565e..b74f9bae31a3 100644
--- a/arch/hexagon/kernel/dma.c
+++ b/arch/hexagon/kernel/dma.c
@@ -1,7 +1,7 @@
/*
* DMA implementation for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -23,12 +23,18 @@
#include <linux/genalloc.h>
#include <asm/dma-mapping.h>
#include <linux/module.h>
+#include <asm/page.h>
struct dma_map_ops *dma_ops;
EXPORT_SYMBOL(dma_ops);
int bad_dma_address; /* globals are automatically initialized to zero */
+static inline void *dma_addr_to_virt(dma_addr_t dma_addr)
+{
+ return phys_to_virt((unsigned long) dma_addr);
+}
+
int dma_supported(struct device *dev, u64 mask)
{
if (mask == DMA_BIT_MASK(32))
@@ -60,6 +66,12 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
{
void *ret;
+ /*
+ * Our max_low_pfn should have been backed off by 16MB in
+ * mm/init.c to create DMA coherent space. Use that as the VA
+ * for the pool.
+ */
+
if (coherent_pool == NULL) {
coherent_pool = gen_pool_create(PAGE_SHIFT, -1);
@@ -67,7 +79,7 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
panic("Can't create %s() memory pool!", __func__);
else
gen_pool_add(coherent_pool,
- (PAGE_OFFSET + (max_low_pfn << PAGE_SHIFT)),
+ pfn_to_virt(max_low_pfn),
hexagon_coherent_pool_size, -1);
}
@@ -75,7 +87,7 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
if (ret) {
memset(ret, 0, size);
- *dma_addr = (dma_addr_t) (ret - PAGE_OFFSET);
+ *dma_addr = (dma_addr_t) virt_to_phys(ret);
} else
*dma_addr = ~0;
@@ -118,8 +130,8 @@ static int hexagon_map_sg(struct device *hwdev, struct scatterlist *sg,
s->dma_length = s->length;
- flush_dcache_range(PAGE_OFFSET + s->dma_address,
- PAGE_OFFSET + s->dma_address + s->length);
+ flush_dcache_range(dma_addr_to_virt(s->dma_address),
+ dma_addr_to_virt(s->dma_address + s->length));
}
return nents;
@@ -149,11 +161,6 @@ static inline void dma_sync(void *addr, size_t size,
}
}
-static inline void *dma_addr_to_virt(dma_addr_t dma_addr)
-{
- return phys_to_virt((unsigned long) dma_addr);
-}
-
/**
* hexagon_map_page() - maps an address for device DMA
* @dev: pointer to DMA device
diff --git a/arch/hexagon/kernel/head.S b/arch/hexagon/kernel/head.S
index d859402c73ba..b9b63d085db2 100644
--- a/arch/hexagon/kernel/head.S
+++ b/arch/hexagon/kernel/head.S
@@ -1,7 +1,7 @@
/*
* Early kernel startup code for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,9 @@
#include <asm/mem-layout.h>
#include <asm/vm_mmu.h>
#include <asm/page.h>
+#include <asm/hexagon_vm.h>
+
+#define SEGTABLE_ENTRIES #0x0e0
__INIT
ENTRY(stext)
@@ -43,40 +46,93 @@ ENTRY(stext)
* Symbol is kernel segment address, but we need
* the logical/physical address.
*/
- r24 = asl(r24, #2)
- r24 = lsr(r24, #2)
+ r25 = pc;
+ r2.h = #0xffc0;
+ r2.l = #0x0000;
+ r25 = and(r2,r25); /* R25 holds PHYS_OFFSET now */
+ r1.h = #HI(PAGE_OFFSET);
+ r1.l = #LO(PAGE_OFFSET);
+ r24 = sub(r24,r1); /* swapper_pg_dir - PAGE_OFFSET */
+ r24 = add(r24,r25); /* + PHYS_OFFSET */
- r0 = r24
+ r0 = r24; /* aka __pa(swapper_pg_dir) */
/*
- * Initialize a 16MB PTE to make the virtual and physical
+ * Initialize page dir to make the virtual and physical
* addresses where the kernel was loaded be identical.
+ * Done in 4MB chunks.
*/
#define PTE_BITS ( __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X \
| __HEXAGON_C_WB_L2 << 6 \
| __HVM_PDE_S_4MB)
- r1 = pc
- r2.H = #0xffc0
- r2.L = #0x0000
- r1 = and(r1,r2) /* round PC to 4MB boundary */
+ /*
+ * Get number of VA=PA entries; only really needed for jump
+ * to hyperspace; gets blown away immediately after
+ */
+
+ {
+ r1.l = #LO(_end);
+ r2.l = #LO(stext);
+ r3 = #1;
+ }
+ {
+ r1.h = #HI(_end);
+ r2.h = #HI(stext);
+ r3 = asl(r3, #22);
+ }
+ {
+ r1 = sub(r1, r2);
+ r3 = add(r3, #-1);
+ } /* r1 = _end - stext */
+ r1 = add(r1, r3); /* + (4M-1) */
+ r26 = lsr(r1, #22); /* / 4M = # of entries */
+
+ r1 = r25;
+ r2.h = #0xffc0;
+ r2.l = #0x0000; /* round back down to 4MB boundary */
+ r1 = and(r1,r2);
r2 = lsr(r1, #22) /* 4MB page number */
r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */
r0 = add(r0,r2) /* r0 = address of correct PTE */
r2 = #PTE_BITS
r1 = add(r1,r2) /* r1 = 4MB PTE for the first entry */
r2.h = #0x0040
- r2.l = #0x0000 /* 4MB */
- memw(r0 ++ #4) = r1
- r1 = add(r1, r2)
+ r2.l = #0x0000 /* 4MB increments */
+ loop0(1f,r26);
+1:
memw(r0 ++ #4) = r1
+ { r1 = add(r1, r2); } :endloop0
+
+ /* Also need to overwrite the initial 0xc0000000 entries */
+ /* PAGE_OFFSET >> (4MB shift - 4 bytes per entry shift) */
+ R1.H = #HI(PAGE_OFFSET >> (22 - 2))
+ R1.L = #LO(PAGE_OFFSET >> (22 - 2))
+
+ r0 = add(r1, r24); /* advance to 0xc0000000 entry */
+ r1 = r25;
+ r2.h = #0xffc0;
+ r2.l = #0x0000; /* round back down to 4MB boundary */
+ r1 = and(r1,r2); /* for huge page */
+ r2 = #PTE_BITS
+ r1 = add(r1,r2);
+ r2.h = #0x0040
+ r2.l = #0x0000 /* 4MB increments */
- r0 = r24
+ loop0(1f,SEGTABLE_ENTRIES);
+1:
+ memw(r0 ++ #4) = r1;
+ { r1 = add(r1,r2); } :endloop0
+
+ r0 = r24;
/*
* The subroutine wrapper around the virtual instruction touches
* no memory, so we should be able to use it even here.
+ * Note that in this version, R1 and R2 get "clobbered"; see
+ * vm_ops.S
*/
+ r1 = #VM_TRANS_TYPE_TABLE
call __vmnewmap;
/* Jump into virtual address range. */
@@ -90,17 +146,29 @@ ENTRY(stext)
__head_s_vaddr_target:
/*
* Tear down VA=PA translation now that we are running
- * in the desgnated kernel segments.
+ * in kernel virtual space.
*/
r0 = #__HVM_PDE_S_INVALID
- r1 = r24
- loop0(1f,#0x100)
+
+ r1.h = #0xffc0;
+ r1.l = #0x0000;
+ r2 = r25; /* phys_offset */
+ r2 = and(r1,r2);
+
+ r1.l = #lo(swapper_pg_dir)
+ r1.h = #hi(swapper_pg_dir)
+ r2 = lsr(r2, #22) /* 4MB page number */
+ r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */
+ r1 = add(r1,r2);
+ loop0(1f,r26)
+
1:
{
memw(R1 ++ #4) = R0
}:endloop0
r0 = r24
+ r1 = #VM_TRANS_TYPE_TABLE
call __vmnewmap
/* Go ahead and install the trap0 return so angel calls work */
@@ -143,6 +211,13 @@ __head_s_vaddr_target:
r2 = sub(r2,r0);
call memset;
+ /* Set PHYS_OFFSET; should be in R25 */
+#ifdef CONFIG_HEXAGON_PHYS_OFFSET
+ r0.l = #LO(__phys_offset);
+ r0.h = #HI(__phys_offset);
+ memw(r0) = r25;
+#endif
+
/* Time to make the doughnuts. */
call start_kernel
diff --git a/arch/hexagon/kernel/kgdb.c b/arch/hexagon/kernel/kgdb.c
index 344645370646..82d5c2593323 100644
--- a/arch/hexagon/kernel/kgdb.c
+++ b/arch/hexagon/kernel/kgdb.c
@@ -1,7 +1,7 @@
/*
* arch/hexagon/kernel/kgdb.c - Hexagon KGDB Support
*
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2012, The Linux Foundation. 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 and
@@ -70,6 +70,8 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
{ "lc1", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc1)},
{ " gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)},
{ "ugp", GDB_SIZEOF_REG, offsetof(struct pt_regs, ugp)},
+ { "cs0", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs0)},
+ { "cs1", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs1)},
{ "psp", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmpsp)},
{ "elr", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmel)},
{ "est", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmest)},
diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c
index 06ae9ffcabd5..0a0dd5c05b46 100644
--- a/arch/hexagon/kernel/process.c
+++ b/arch/hexagon/kernel/process.c
@@ -24,6 +24,7 @@
#include <linux/tick.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/tracehook.h>
/*
* Program thread launch. Often defined as a macro in processor.h,
@@ -51,28 +52,11 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
* If hardware or VM offer wait termination even though interrupts
* are disabled.
*/
-static void default_idle(void)
+void arch_cpu_idle(void)
{
__vmwait();
-}
-
-void (*idle_sleep)(void) = default_idle;
-
-void cpu_idle(void)
-{
- while (1) {
- tick_nohz_idle_enter();
- local_irq_disable();
- while (!need_resched()) {
- idle_sleep();
- /* interrupts wake us up, but aren't serviced */
- local_irq_enable(); /* service interrupt */
- local_irq_disable();
- }
- local_irq_enable();
- tick_nohz_idle_exit();
- schedule();
- }
+ /* interrupts wake us up, but irqs are still disabled */
+ local_irq_enable();
}
/*
@@ -112,7 +96,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
if (unlikely(p->flags & PF_KTHREAD)) {
memset(childregs, 0, sizeof(struct pt_regs));
/* r24 <- fn, r25 <- arg */
- ss->r2524 = usp | ((u64)arg << 32);
+ ss->r24 = usp;
+ ss->r25 = arg;
pt_set_kmode(childregs);
return 0;
}
@@ -202,3 +187,41 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
{
return 0;
}
+
+
+/*
+ * Called on the exit path of event entry; see vm_entry.S
+ *
+ * Interrupts will already be disabled.
+ *
+ * Returns 0 if there's no need to re-check for more work.
+ */
+
+int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
+{
+ if (!(thread_info_flags & _TIF_WORK_MASK)) {
+ return 0;
+ } /* shortcut -- no work to be done */
+
+ local_irq_enable();
+
+ if (thread_info_flags & _TIF_NEED_RESCHED) {
+ schedule();
+ return 1;
+ }
+
+ if (thread_info_flags & _TIF_SIGPENDING) {
+ do_signal(regs);
+ return 1;
+ }
+
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ return 1;
+ }
+
+ /* Should not even reach here */
+ panic("%s: bad thread_info flags 0x%08x\n", __func__,
+ thread_info_flags);
+}
diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c
index 670b1b0bee63..de829eb7f185 100644
--- a/arch/hexagon/kernel/ptrace.c
+++ b/arch/hexagon/kernel/ptrace.c
@@ -1,7 +1,7 @@
/*
* Ptrace support for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -32,6 +32,21 @@
#include <asm/user.h>
+#if arch_has_single_step()
+/* Both called from ptrace_resume */
+void user_enable_single_step(struct task_struct *child)
+{
+ pt_set_singlestep(task_pt_regs(child));
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ pt_clr_singlestep(task_pt_regs(child));
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+#endif
+
static int genregs_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
@@ -76,6 +91,10 @@ static int genregs_get(struct task_struct *target,
dummy = pt_cause(regs);
ONEXT(&dummy, cause);
ONEXT(&pt_badva(regs), badva);
+#if CONFIG_HEXAGON_ARCH_VERSION >=4
+ ONEXT(&regs->cs0, cs0);
+ ONEXT(&regs->cs1, cs1);
+#endif
/* Pad the rest with zeros, if needed */
if (!ret)
@@ -123,6 +142,11 @@ static int genregs_set(struct task_struct *target,
INEXT(&bucket, cause);
INEXT(&bucket, badva);
+#if CONFIG_HEXAGON_ARCH_VERSION >=4
+ INEXT(&regs->cs0, cs0);
+ INEXT(&regs->cs1, cs1);
+#endif
+
/* Ignore the rest, if needed */
if (!ret)
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
diff --git a/arch/hexagon/kernel/setup.c b/arch/hexagon/kernel/setup.c
index 94a387835008..bfe13311d70d 100644
--- a/arch/hexagon/kernel/setup.c
+++ b/arch/hexagon/kernel/setup.c
@@ -1,7 +1,7 @@
/*
* Arch related setup for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -68,6 +68,8 @@ void __init setup_arch(char **cmdline_p)
*/
__vmsetvec(_K_VM_event_vector);
+ printk(KERN_INFO "PHYS_OFFSET=0x%08x\n", PHYS_OFFSET);
+
/*
* Simulator has a few differences from the hardware.
* For now, check uninitialized-but-mapped memory
@@ -128,6 +130,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
{
int cpu = (unsigned long) v - 1;
+#ifdef CONFIG_SMP
+ if (!cpu_online(cpu))
+ return 0;
+#endif
+
seq_printf(m, "processor\t: %d\n", cpu);
seq_printf(m, "model name\t: Hexagon Virtual Machine\n");
seq_printf(m, "BogoMips\t: %lu.%02lu\n",
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 60fa2ca3202b..d7c73874b515 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -1,7 +1,7 @@
/*
* Signal support for Hexagon processor
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -41,6 +41,10 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
{
unsigned long sp = regs->r29;
+ /* check if we would overflow the alt stack */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
+ return (void __user __force *)-1UL;
+
/* Switch to signal stack if appropriate */
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
sp = current->sas_ss_sp + current->sas_ss_size;
@@ -66,7 +70,10 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
err |= __put_user(regs->preds, &sc->sc_regs.p3_0);
err |= __put_user(regs->gp, &sc->sc_regs.gp);
err |= __put_user(regs->ugp, &sc->sc_regs.ugp);
-
+#if CONFIG_HEXAGON_ARCH_VERSION >= 4
+ err |= __put_user(regs->cs0, &sc->sc_regs.cs0);
+ err |= __put_user(regs->cs1, &sc->sc_regs.cs1);
+#endif
tmp = pt_elr(regs); err |= __put_user(tmp, &sc->sc_regs.pc);
tmp = pt_cause(regs); err |= __put_user(tmp, &sc->sc_regs.cause);
tmp = pt_badva(regs); err |= __put_user(tmp, &sc->sc_regs.badva);
@@ -93,7 +100,10 @@ static int restore_sigcontext(struct pt_regs *regs,
err |= __get_user(regs->preds, &sc->sc_regs.p3_0);
err |= __get_user(regs->gp, &sc->sc_regs.gp);
err |= __get_user(regs->ugp, &sc->sc_regs.ugp);
-
+#if CONFIG_HEXAGON_ARCH_VERSION >= 4
+ err |= __get_user(regs->cs0, &sc->sc_regs.cs0);
+ err |= __get_user(regs->cs1, &sc->sc_regs.cs1);
+#endif
err |= __get_user(tmp, &sc->sc_regs.pc); pt_set_elr(regs, tmp);
return err;
@@ -193,7 +203,7 @@ static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
/*
* Called from return-from-event code.
*/
-static void do_signal(struct pt_regs *regs)
+void do_signal(struct pt_regs *regs)
{
struct k_sigaction sigact;
siginfo_t info;
@@ -210,8 +220,9 @@ static void do_signal(struct pt_regs *regs)
}
/*
- * If we came from a system call, handle the restart.
+ * No (more) signals; if we came from a system call, handle the restart.
*/
+
if (regs->syscall_nr >= 0) {
switch (regs->r00) {
case -ERESTARTNOHAND:
@@ -234,17 +245,6 @@ no_restart:
restore_saved_sigmask();
}
-void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
-{
- if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(regs);
-
- if (thread_info_flags & _TIF_NOTIFY_RESUME) {
- clear_thread_flag(TIF_NOTIFY_RESUME);
- tracehook_notify_resume(regs);
- }
-}
-
/*
* Architecture-specific wrappers for signal-related system calls
*/
@@ -272,21 +272,12 @@ asmlinkage int sys_rt_sigreturn(void)
/* Restore the user's stack as well */
pt_psp(regs) = regs->r29;
- /*
- * Leave a trace in the stack frame that this was a sigreturn.
- * If the system call is to replay, we've already restored the
- * number in the GPR slot and it will be regenerated on the
- * new system call trap entry. Note that if restore_sigcontext()
- * did something other than a bulk copy of the pt_regs struct,
- * we could avoid this assignment by simply not overwriting
- * regs->syscall_nr.
- */
- regs->syscall_nr = __NR_rt_sigreturn;
+ regs->syscall_nr = -1;
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
- return 0;
+ return regs->r00;
badframe:
force_sig(SIGSEGV, current);
diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c
index 8e095dffd070..0e364ca43198 100644
--- a/arch/hexagon/kernel/smp.c
+++ b/arch/hexagon/kernel/smp.c
@@ -184,7 +184,7 @@ void __cpuinit start_secondary(void)
local_irq_enable();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
diff --git a/arch/hexagon/kernel/topology.c b/arch/hexagon/kernel/topology.c
deleted file mode 100644
index 352f27e809fd..000000000000
--- a/arch/hexagon/kernel/topology.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * CPU topology for Hexagon
- *
- * Copyright (c) 2010-2011, The Linux Foundation. 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 and
- * only 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 Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <linux/cpu.h>
-#include <linux/cpumask.h>
-#include <linux/init.h>
-#include <linux/node.h>
-#include <linux/nodemask.h>
-#include <linux/percpu.h>
-
-/* Swiped from MIPS. */
-
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
-static int __init topology_init(void)
-{
- int i, ret;
-
- for_each_present_cpu(i) {
-
- /*
- * register_cpu takes a per_cpu pointer and
- * just points it at another per_cpu struct...
- */
-
- ret = register_cpu(&per_cpu(cpu_devices, i), i);
- if (ret)
- printk(KERN_WARNING "topology_init: register_cpu %d "
- "failed (%d)\n", i, ret);
- }
-
- return 0;
-}
-
-subsys_initcall(topology_init);
diff --git a/arch/hexagon/kernel/traps.c b/arch/hexagon/kernel/traps.c
index be5e2dd9c9d3..7858663352b9 100644
--- a/arch/hexagon/kernel/traps.c
+++ b/arch/hexagon/kernel/traps.c
@@ -1,7 +1,7 @@
/*
* Kernel traps/events for Hexagon processor
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -65,6 +65,10 @@ static const char *ex_name(int ex)
return "Write protection fault";
case HVM_GE_C_XMAL:
return "Misaligned instruction";
+ case HVM_GE_C_WREG:
+ return "Multiple writes to same register in packet";
+ case HVM_GE_C_PCAL:
+ return "Program counter values that are not properly aligned";
case HVM_GE_C_RMAL:
return "Misaligned data load";
case HVM_GE_C_WMAL:
@@ -191,14 +195,6 @@ void show_stack(struct task_struct *task, unsigned long *fp)
do_show_stack(task, fp, 0);
}
-void dump_stack(void)
-{
- unsigned long *fp;
- asm("%0 = r30" : "=r" (fp));
- show_stack(current, fp);
-}
-EXPORT_SYMBOL(dump_stack);
-
int die(const char *str, struct pt_regs *regs, long err)
{
static struct {
@@ -324,6 +320,12 @@ void do_genex(struct pt_regs *regs)
case HVM_GE_C_XMAL:
misaligned_instruction(regs);
break;
+ case HVM_GE_C_WREG:
+ illegal_instruction(regs);
+ break;
+ case HVM_GE_C_PCAL:
+ misaligned_instruction(regs);
+ break;
case HVM_GE_C_RMAL:
misaligned_data_load(regs);
break;
@@ -356,7 +358,6 @@ long sys_syscall(void)
void do_trap0(struct pt_regs *regs)
{
- unsigned long syscallret = 0;
syscall_fn syscall;
switch (pt_cause(regs)) {
@@ -396,21 +397,11 @@ void do_trap0(struct pt_regs *regs)
} else {
syscall = (syscall_fn)
(sys_call_table[regs->syscall_nr]);
- syscallret = syscall(regs->r00, regs->r01,
+ regs->r00 = syscall(regs->r00, regs->r01,
regs->r02, regs->r03,
regs->r04, regs->r05);
}
- /*
- * If it was a sigreturn system call, don't overwrite
- * r0 value in stack frame with return value.
- *
- * __NR_sigreturn doesn't seem to exist in new unistd.h
- */
-
- if (regs->syscall_nr != __NR_rt_sigreturn)
- regs->r00 = syscallret;
-
/* allow strace to get the syscall return state */
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE)))
tracehook_report_syscall_exit(regs, 0);
@@ -452,3 +443,14 @@ void do_machcheck(struct pt_regs *regs)
/* Halt and catch fire */
__vmstop();
}
+
+/*
+ * Treat this like the old 0xdb trap.
+ */
+
+void do_debug_exception(struct pt_regs *regs)
+{
+ regs->hvmer.vmest &= ~HVM_VMEST_CAUSE_MSK;
+ regs->hvmer.vmest |= (TRAP_DEBUG << HVM_VMEST_CAUSE_SFT);
+ do_trap0(regs);
+}
diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S
index 425e50c694f7..e3086185fc9f 100644
--- a/arch/hexagon/kernel/vm_entry.S
+++ b/arch/hexagon/kernel/vm_entry.S
@@ -1,7 +1,7 @@
/*
* Event entry/exit for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -45,48 +45,88 @@
* number in the case where we decode a system call (trap0(#1)).
*/
+#if CONFIG_HEXAGON_ARCH_VERSION < 4
#define save_pt_regs()\
- memd(R0 + #_PT_R3130) = R31:30; \
+ memd(R0 + #_PT_R3130) = R31:30; \
+ { memw(R0 + #_PT_R2928) = R28; \
+ R31 = memw(R0 + #_PT_ER_VMPSP); }\
+ { memw(R0 + #(_PT_R2928 + 4)) = R31; \
+ R31 = ugp; } \
+ { memd(R0 + #_PT_R2726) = R27:26; \
+ R30 = gp ; } \
+ memd(R0 + #_PT_R2524) = R25:24; \
+ memd(R0 + #_PT_R2322) = R23:22; \
+ memd(R0 + #_PT_R2120) = R21:20; \
+ memd(R0 + #_PT_R1918) = R19:18; \
+ memd(R0 + #_PT_R1716) = R17:16; \
+ memd(R0 + #_PT_R1514) = R15:14; \
+ memd(R0 + #_PT_R1312) = R13:12; \
+ { memd(R0 + #_PT_R1110) = R11:10; \
+ R15 = lc0; } \
+ { memd(R0 + #_PT_R0908) = R9:8; \
+ R14 = sa0; } \
+ { memd(R0 + #_PT_R0706) = R7:6; \
+ R13 = lc1; } \
+ { memd(R0 + #_PT_R0504) = R5:4; \
+ R12 = sa1; } \
+ { memd(R0 + #_PT_GPUGP) = R31:30; \
+ R11 = m1; \
+ R2.H = #HI(_THREAD_SIZE); } \
+ { memd(R0 + #_PT_LC0SA0) = R15:14; \
+ R10 = m0; \
+ R2.L = #LO(_THREAD_SIZE); } \
+ { memd(R0 + #_PT_LC1SA1) = R13:12; \
+ R15 = p3:0; \
+ R2 = neg(R2); } \
+ { memd(R0 + #_PT_M1M0) = R11:10; \
+ R14 = usr; \
+ R2 = and(R0,R2); } \
+ { memd(R0 + #_PT_PREDSUSR) = R15:14; \
+ THREADINFO_REG = R2; } \
+ { r24 = memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS); \
+ memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R0; \
+ R2 = #-1; } \
+ { memw(R0 + #_PT_SYSCALL_NR) = R2; \
+ R30 = #0; }
+#else
+/* V4+ */
+/* the # ## # syntax inserts a literal ## */
+#define save_pt_regs()\
+ { memd(R0 + #_PT_R3130) = R31:30; \
+ R30 = memw(R0 + #_PT_ER_VMPSP); }\
{ memw(R0 + #_PT_R2928) = R28; \
- R31 = memw(R0 + #_PT_ER_VMPSP); }\
- { memw(R0 + #(_PT_R2928 + 4)) = R31; \
- R31 = ugp; } \
- { memd(R0 + #_PT_R2726) = R27:26; \
- R30 = gp ; } \
- memd(R0 + #_PT_R2524) = R25:24; \
- memd(R0 + #_PT_R2322) = R23:22; \
- memd(R0 + #_PT_R2120) = R21:20; \
- memd(R0 + #_PT_R1918) = R19:18; \
- memd(R0 + #_PT_R1716) = R17:16; \
- memd(R0 + #_PT_R1514) = R15:14; \
- memd(R0 + #_PT_R1312) = R13:12; \
+ memw(R0 + #(_PT_R2928 + 4)) = R30; }\
+ { R31:30 = C11:10; \
+ memd(R0 + #_PT_R2726) = R27:26; \
+ memd(R0 + #_PT_R2524) = R25:24; }\
+ { memd(R0 + #_PT_R2322) = R23:22; \
+ memd(R0 + #_PT_R2120) = R21:20; }\
+ { memd(R0 + #_PT_R1918) = R19:18; \
+ memd(R0 + #_PT_R1716) = R17:16; }\
+ { memd(R0 + #_PT_R1514) = R15:14; \
+ memd(R0 + #_PT_R1312) = R13:12; \
+ R17:16 = C13:12; }\
{ memd(R0 + #_PT_R1110) = R11:10; \
- R15 = lc0; } \
- { memd(R0 + #_PT_R0908) = R9:8; \
- R14 = sa0; } \
+ memd(R0 + #_PT_R0908) = R9:8; \
+ R15:14 = C1:0; } \
{ memd(R0 + #_PT_R0706) = R7:6; \
- R13 = lc1; } \
- { memd(R0 + #_PT_R0504) = R5:4; \
- R12 = sa1; } \
- { memd(R0 + #_PT_UGPGP) = R31:30; \
- R11 = m1; \
- R2.H = #HI(_THREAD_SIZE); } \
- { memd(R0 + #_PT_LC0SA0) = R15:14; \
- R10 = m0; \
- R2.L = #LO(_THREAD_SIZE); } \
- { memd(R0 + #_PT_LC1SA1) = R13:12; \
- R15 = p3:0; \
- R2 = neg(R2); } \
+ memd(R0 + #_PT_R0504) = R5:4; \
+ R13:12 = C3:2; } \
+ { memd(R0 + #_PT_GPUGP) = R31:30; \
+ memd(R0 + #_PT_LC0SA0) = R15:14; \
+ R11:10 = C7:6; }\
+ { THREADINFO_REG = and(R0, # ## #-_THREAD_SIZE); \
+ memd(R0 + #_PT_LC1SA1) = R13:12; \
+ R15 = p3:0; }\
{ memd(R0 + #_PT_M1M0) = R11:10; \
- R14 = usr; \
- R2 = and(R0,R2); } \
- { memd(R0 + #_PT_PREDSUSR) = R15:14; \
- THREADINFO_REG = R2; } \
+ memw(R0 + #_PT_PREDSUSR + 4) = R15; }\
{ r24 = memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS); \
memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R0; \
R2 = #-1; } \
{ memw(R0 + #_PT_SYSCALL_NR) = R2; \
+ memd(R0 + #_PT_CS1CS0) = R17:16; \
R30 = #0; }
+#endif
/*
* Restore registers and thread_info.regs state. THREADINFO_REG
@@ -94,6 +134,7 @@
* preserved. Don't restore R29 (SP) until later.
*/
+#if CONFIG_HEXAGON_ARCH_VERSION < 4
#define restore_pt_regs() \
{ memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R24; \
R15:14 = memd(R0 + #_PT_PREDSUSR); } \
@@ -121,11 +162,44 @@
R23:22 = memd(R0 + #_PT_R2322); } \
{ R25:24 = memd(R0 + #_PT_R2524); \
R27:26 = memd(R0 + #_PT_R2726); } \
- R31:30 = memd(R0 + #_PT_UGPGP); \
+ R31:30 = memd(R0 + #_PT_GPUGP); \
{ R28 = memw(R0 + #_PT_R2928); \
ugp = R31; } \
{ R31:30 = memd(R0 + #_PT_R3130); \
gp = R30; }
+#else
+/* V4+ */
+#define restore_pt_regs() \
+ { memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R24; \
+ R15:14 = memd(R0 + #_PT_PREDSUSR); } \
+ { R11:10 = memd(R0 + #_PT_M1M0); \
+ R13:12 = memd(R0 + #_PT_LC1SA1); \
+ p3:0 = R15; } \
+ { R15:14 = memd(R0 + #_PT_LC0SA0); \
+ R3:2 = memd(R0 + #_PT_R0302); \
+ usr = R14; } \
+ { R5:4 = memd(R0 + #_PT_R0504); \
+ R7:6 = memd(R0 + #_PT_R0706); \
+ C7:6 = R11:10; }\
+ { R9:8 = memd(R0 + #_PT_R0908); \
+ R11:10 = memd(R0 + #_PT_R1110); \
+ C3:2 = R13:12; }\
+ { R13:12 = memd(R0 + #_PT_R1312); \
+ R15:14 = memd(R0 + #_PT_R1514); \
+ C1:0 = R15:14; }\
+ { R17:16 = memd(R0 + #_PT_R1716); \
+ R19:18 = memd(R0 + #_PT_R1918); } \
+ { R21:20 = memd(R0 + #_PT_R2120); \
+ R23:22 = memd(R0 + #_PT_R2322); } \
+ { R25:24 = memd(R0 + #_PT_R2524); \
+ R27:26 = memd(R0 + #_PT_R2726); } \
+ R31:30 = memd(R0 + #_PT_CS1CS0); \
+ { C13:12 = R31:30; \
+ R31:30 = memd(R0 + #_PT_GPUGP) ; \
+ R28 = memw(R0 + #_PT_R2928); }\
+ { C11:10 = R31:30; \
+ R31:30 = memd(R0 + #_PT_R3130); }
+#endif
/*
* Clears off enough space for the rest of pt_regs; evrec is a part
@@ -139,6 +213,7 @@
* Need to save off R0, R1, R2, R3 immediately.
*/
+#if CONFIG_HEXAGON_ARCH_VERSION < 4
#define vm_event_entry(CHandler) \
{ \
R29 = add(R29, #-(_PT_REGS_SIZE)); \
@@ -158,6 +233,34 @@
R1.H = #HI(CHandler); \
jump event_dispatch; \
}
+#else
+/* V4+ */
+/* turn on I$ prefetch early */
+/* the # ## # syntax inserts a literal ## */
+#define vm_event_entry(CHandler) \
+ { \
+ R29 = add(R29, #-(_PT_REGS_SIZE)); \
+ memd(R29 + #(_PT_R0100 + -_PT_REGS_SIZE)) = R1:0; \
+ memd(R29 + #(_PT_R0302 + -_PT_REGS_SIZE)) = R3:2; \
+ R0 = usr; \
+ } \
+ { \
+ memw(R29 + #_PT_PREDSUSR) = R0; \
+ R0 = setbit(R0, #16); \
+ } \
+ usr = R0; \
+ R1:0 = G1:0; \
+ { \
+ memd(R29 + #_PT_ER_VMEL) = R1:0; \
+ R1 = # ## #(CHandler); \
+ R3:2 = G3:2; \
+ } \
+ { \
+ R0 = R29; \
+ memd(R29 + #_PT_ER_VMPSP) = R3:2; \
+ jump event_dispatch; \
+ }
+#endif
.text
/*
@@ -171,6 +274,9 @@ event_dispatch:
callr r1
/*
+ * Coming back from the C-world, our thread info pointer
+ * should be in the designated register (usually R19)
+ *
* If we were in kernel mode, we don't need to check scheduler
* or signals if CONFIG_PREEMPT is not set. If set, then it has
* to jump to a need_resched kind of block.
@@ -183,69 +289,68 @@ event_dispatch:
#endif
/* "Nested control path" -- if the previous mode was kernel */
- R0 = memw(R29 + #_PT_ER_VMEST);
- P0 = tstbit(R0, #HVM_VMEST_UM_SFT);
- if !P0 jump restore_all;
- /*
- * Returning from system call, normally coming back from user mode
- */
-return_from_syscall:
- /* Disable interrupts while checking TIF */
- R0 = #VM_INT_DISABLE
- trap1(#HVM_TRAP1_VMSETIE)
-
- /*
- * Coming back from the C-world, our thread info pointer
- * should be in the designated register (usually R19)
- */
- R1.L = #LO(_TIF_ALLWORK_MASK)
{
- R1.H = #HI(_TIF_ALLWORK_MASK);
- R0 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS);
+ R0 = memw(R29 + #_PT_ER_VMEST);
+ R16.L = #LO(do_work_pending);
+ }
+ {
+ P0 = tstbit(R0, #HVM_VMEST_UM_SFT);
+ if (!P0.new) jump:nt restore_all;
+ R16.H = #HI(do_work_pending);
+ R0 = #VM_INT_DISABLE;
}
/*
- * Compare against the "return to userspace" _TIF_WORK_MASK
+ * Check also the return from fork/system call, normally coming back from
+ * user mode
+ *
+ * R16 needs to have do_work_pending, and R0 should have VM_INT_DISABLE
*/
- R1 = and(R1,R0);
- { P0 = cmp.eq(R1,#0); if (!P0.new) jump:t work_pending;}
- jump restore_all; /* we're outta here! */
-work_pending:
+check_work_pending:
+ /* Disable interrupts while checking TIF */
+ trap1(#HVM_TRAP1_VMSETIE)
{
- P0 = tstbit(R1, #TIF_NEED_RESCHED);
- if (!P0.new) jump:nt work_notifysig;
+ R0 = R29; /* regs should still be at top of stack */
+ R1 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS);
+ callr R16;
}
- call schedule
- jump return_from_syscall; /* check for more work */
-work_notifysig:
- /* this is the part that's kind of fuzzy. */
- R1 = and(R0, #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME));
- P0 = cmp.eq(R1, #0);
- if P0 jump restore_all
- R1 = R0; /* unsigned long thread_info_flags */
- R0 = R29; /* regs should still be at top of stack */
- call do_notify_resume
+ {
+ P0 = cmp.eq(R0, #0); if (!P0.new) jump:nt check_work_pending;
+ R0 = #VM_INT_DISABLE;
+ }
restore_all:
- /* Disable interrupts, if they weren't already, before reg restore. */
- R0 = #VM_INT_DISABLE
+ /*
+ * Disable interrupts, if they weren't already, before reg restore.
+ * R0 gets preloaded with #VM_INT_DISABLE before we get here.
+ */
trap1(#HVM_TRAP1_VMSETIE)
/* do the setregs here for VM 0.5 */
/* R29 here should already be pointing at pt_regs */
- R1:0 = memd(R29 + #_PT_ER_VMEL);
- R3:2 = memd(R29 + #_PT_ER_VMPSP);
+ {
+ R1:0 = memd(R29 + #_PT_ER_VMEL);
+ R3:2 = memd(R29 + #_PT_ER_VMPSP);
+ }
+#if CONFIG_HEXAGON_ARCH_VERSION < 4
trap1(#HVM_TRAP1_VMSETREGS);
+#else
+ G1:0 = R1:0;
+ G3:2 = R3:2;
+#endif
R0 = R29
restore_pt_regs()
- R1:0 = memd(R29 + #_PT_R0100);
- R29 = add(R29, #_PT_REGS_SIZE);
+ {
+ R1:0 = memd(R29 + #_PT_R0100);
+ R29 = add(R29, #_PT_REGS_SIZE);
+ }
trap1(#HVM_TRAP1_VMRTE)
/* Notreached */
+
.globl _K_enter_genex
_K_enter_genex:
vm_event_entry(do_genex)
@@ -262,12 +367,27 @@ _K_enter_trap0:
_K_enter_machcheck:
vm_event_entry(do_machcheck)
+ .globl _K_enter_debug
+_K_enter_debug:
+ vm_event_entry(do_debug_exception)
.globl ret_from_fork
ret_from_fork:
- call schedule_tail
- P0 = cmp.eq(R24, #0);
- if P0 jump return_from_syscall
- R0 = R25;
- callr R24
- jump return_from_syscall
+ {
+ call schedule_tail
+ R16.H = #HI(do_work_pending);
+ }
+ {
+ P0 = cmp.eq(R24, #0);
+ R16.L = #LO(do_work_pending);
+ R0 = #VM_INT_DISABLE;
+ }
+ if P0 jump check_work_pending
+ {
+ R0 = R25;
+ callr R24
+ }
+ {
+ jump check_work_pending
+ R0 = #VM_INT_DISABLE;
+ }
diff --git a/arch/hexagon/kernel/vm_events.c b/arch/hexagon/kernel/vm_events.c
index 9b5a4a295a68..741aaa917cda 100644
--- a/arch/hexagon/kernel/vm_events.c
+++ b/arch/hexagon/kernel/vm_events.c
@@ -1,7 +1,7 @@
/*
* Mostly IRQ support for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012, The Linux Foundation. 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 and
@@ -33,6 +33,8 @@
*/
void show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_EMERG);
+
printk(KERN_EMERG "restart_r0: \t0x%08lx syscall_nr: %ld\n",
regs->restart_r0, regs->syscall_nr);
printk(KERN_EMERG "preds: \t\t0x%08lx\n", regs->preds);
@@ -42,6 +44,8 @@ void show_regs(struct pt_regs *regs)
regs->lc1, regs->sa1, regs->m1);
printk(KERN_EMERG "gp: \t0x%08lx ugp: 0x%08lx usr: 0x%08lx\n",
regs->gp, regs->ugp, regs->usr);
+ printk(KERN_EMERG "cs0: \t0x%08lx cs1: 0x%08lx\n",
+ regs->cs0, regs->cs1);
printk(KERN_EMERG "r0: \t0x%08lx %08lx %08lx %08lx\n", regs->r00,
regs->r01,
regs->r02,
diff --git a/arch/hexagon/kernel/vm_vectors.S b/arch/hexagon/kernel/vm_vectors.S
index 620f42cc582a..791a7422dde4 100644
--- a/arch/hexagon/kernel/vm_vectors.S
+++ b/arch/hexagon/kernel/vm_vectors.S
@@ -1,7 +1,7 @@
/*
* Event jump tables
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2012,2013, The Linux Foundation. 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 and
@@ -41,7 +41,7 @@ _K_VM_event_vector:
jump 1b; /* Reset */
jump _K_enter_machcheck;
jump _K_enter_genex;
- jump 1b; /* 3 Rsvd */
+ jump _K_enter_debug;
jump 1b; /* 4 Rsvd */
jump _K_enter_trap0;
jump 1b; /* 6 Rsvd */
diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S
index 14e793f6abbf..44d8c47bae2f 100644
--- a/arch/hexagon/kernel/vmlinux.lds.S
+++ b/arch/hexagon/kernel/vmlinux.lds.S
@@ -1,7 +1,7 @@
/*
* Linker script for Hexagon kernel
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -18,8 +18,6 @@
* 02110-1301, USA.
*/
-#define LOAD_OFFSET PAGE_OFFSET
-
#include <asm-generic/vmlinux.lds.h>
#include <asm/asm-offsets.h> /* Most of the kernel defines are here */
#include <asm/mem-layout.h> /* except for page_offset */
@@ -36,13 +34,9 @@ See asm-generic/sections.h for seemingly required labels.
#define PAGE_SIZE _PAGE_SIZE
-/* This LOAD_OFFSET is temporary for debugging on the simulator; it may change
- for hypervisor pseudo-physical memory. */
-
-
SECTIONS
{
- . = PAGE_OFFSET + LOAD_ADDRESS;
+ . = PAGE_OFFSET;
__init_begin = .;
HEAD_TEXT_SECTION
@@ -52,7 +46,7 @@ SECTIONS
. = ALIGN(_PAGE_SIZE);
_stext = .;
- .text : AT(ADDR(.text) - LOAD_OFFSET) {
+ .text : AT(ADDR(.text)) {
_text = .;
TEXT_TEXT
SCHED_TEXT
diff --git a/arch/hexagon/mm/init.c b/arch/hexagon/mm/init.c
index 69ffcfd28794..2561d259a296 100644
--- a/arch/hexagon/mm/init.c
+++ b/arch/hexagon/mm/init.c
@@ -1,7 +1,7 @@
/*
* Memory subsystem initialization for Hexagon
*
- * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 and
@@ -31,9 +31,10 @@
* Define a startpg just past the end of the kernel image and a lastpg
* that corresponds to the end of real or simulated platform memory.
*/
-#define bootmem_startpg (PFN_UP(((unsigned long) _end) - PAGE_OFFSET))
+#define bootmem_startpg (PFN_UP(((unsigned long) _end) - PAGE_OFFSET + PHYS_OFFSET))
-unsigned long bootmem_lastpg; /* Should be set by platform code */
+unsigned long bootmem_lastpg; /* Should be set by platform code */
+unsigned long __phys_offset; /* physical kernel offset >> 12 */
/* Set as variable to limit PMD copies */
int max_kernel_seg = 0x303;
@@ -44,7 +45,6 @@ unsigned long zero_page_mask;
/* indicate pfn's of high memory */
unsigned long highstart_pfn, highend_pfn;
-/* struct mmu_gather defined in asm-generic.h; */
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
/* Default cache attribute for newly created page tables */
@@ -71,7 +71,7 @@ void __init mem_init(void)
{
/* No idea where this is actually declared. Seems to evade LXR. */
totalram_pages += free_all_bootmem();
- num_physpages = bootmem_lastpg; /* seriously, what? */
+ num_physpages = bootmem_lastpg-ARCH_PFN_OFFSET;
printk(KERN_INFO "totalram_pages = %ld\n", totalram_pages);
@@ -193,6 +193,9 @@ void __init setup_arch_memory(void)
* This needs to change for highmem setups.
*/
+ /* Prior to this, bootmem_lastpg is actually mem size */
+ bootmem_lastpg += ARCH_PFN_OFFSET;
+
/* Memory size needs to be a multiple of 16M */
bootmem_lastpg = PFN_DOWN((bootmem_lastpg << PAGE_SHIFT) &
~((BIG_KERNEL_PAGE_SIZE) - 1));
@@ -201,12 +204,15 @@ void __init setup_arch_memory(void)
* Reserve the top DMA_RESERVE bytes of RAM for DMA (uncached)
* memory allocation
*/
- bootmap_size = init_bootmem(bootmem_startpg, bootmem_lastpg -
- PFN_DOWN(DMA_RESERVED_BYTES));
+
+ max_low_pfn = bootmem_lastpg - PFN_DOWN(DMA_RESERVED_BYTES);
+ min_low_pfn = ARCH_PFN_OFFSET;
+ bootmap_size = init_bootmem_node(NODE_DATA(0), bootmem_startpg, min_low_pfn, max_low_pfn);
printk(KERN_INFO "bootmem_startpg: 0x%08lx\n", bootmem_startpg);
printk(KERN_INFO "bootmem_lastpg: 0x%08lx\n", bootmem_lastpg);
printk(KERN_INFO "bootmap_size: %d\n", bootmap_size);
+ printk(KERN_INFO "min_low_pfn: 0x%08lx\n", min_low_pfn);
printk(KERN_INFO "max_low_pfn: 0x%08lx\n", max_low_pfn);
/*
@@ -221,14 +227,17 @@ void __init setup_arch_memory(void)
/* this actually only goes to the end of the first gig */
segtable_end = segtable + (1<<(30-22));
- /* Move forward to the start of empty pages */
- segtable += bootmem_lastpg >> (22-PAGE_SHIFT);
+ /*
+ * Move forward to the start of empty pages; take into account
+ * phys_offset shift.
+ */
+ segtable += (bootmem_lastpg-ARCH_PFN_OFFSET)>>(22-PAGE_SHIFT);
{
- int i;
+ int i;
- for (i = 1 ; i <= DMA_RESERVE ; i++)
- segtable[-i] = ((segtable[-i] & __HVM_PTE_PGMASK_4MB)
+ for (i = 1 ; i <= DMA_RESERVE ; i++)
+ segtable[-i] = ((segtable[-i] & __HVM_PTE_PGMASK_4MB)
| __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X
| __HEXAGON_C_UNC << 6
| __HVM_PDE_S_4MB);
@@ -256,7 +265,7 @@ void __init setup_arch_memory(void)
* Free all the memory that wasn't taken up by the bootmap, the DMA
* reserve, or kernel itself.
*/
- free_bootmem(PFN_PHYS(bootmem_startpg)+bootmap_size,
+ free_bootmem(PFN_PHYS(bootmem_startpg) + bootmap_size,
PFN_PHYS(bootmem_lastpg - bootmem_startpg) - bootmap_size -
DMA_RESERVED_BYTES);
diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c
index 308ef0ce648b..1bd276dbec7d 100644
--- a/arch/hexagon/mm/vm_fault.c
+++ b/arch/hexagon/mm/vm_fault.c
@@ -147,7 +147,7 @@ good_area:
}
info.si_errno = 0;
info.si_addr = (void __user *)address;
- force_sig_info(info.si_code, &info, current);
+ force_sig_info(info.si_signo, &info, current);
return;
bad_area:
@@ -158,7 +158,7 @@ bad_area:
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void *)address;
- force_sig_info(SIGSEGV, &info, current);
+ force_sig_info(info.si_signo, &info, current);
return;
}
/* Kernel-mode fault falls through */
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 9a02f71c6b1f..d393f841ff5a 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -110,6 +110,7 @@ config DMI
config EFI
bool
+ select UCS2_STRING
default y
config SCHED_OMIT_FRAME_POINTER
@@ -187,7 +188,7 @@ config IA64_DIG
config IA64_DIG_VTD
bool "DIG+Intel+IOMMU"
- select DMAR
+ select INTEL_IOMMU
select PCI_MSI
config IA64_HP_ZX1
@@ -591,9 +592,9 @@ source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"
if PM
-
-source "arch/ia64/kernel/cpufreq/Kconfig"
-
+menu "CPU Frequency scaling"
+source "drivers/cpufreq/Kconfig"
+endmenu
endif
endmenu
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index da2f319fb71d..e70cadec7ce6 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -142,8 +142,7 @@ static void transmit_chars(struct tty_struct *tty, struct serial_state *info,
goto out;
}
- if (info->xmit.head == info->xmit.tail || tty->stopped ||
- tty->hw_stopped) {
+ if (info->xmit.head == info->xmit.tail || tty->stopped) {
#ifdef SIMSERIAL_DEBUG
printk("transmit_chars: head=%d, tail=%d, stopped=%d\n",
info->xmit.head, info->xmit.tail, tty->stopped);
@@ -181,7 +180,7 @@ static void rs_flush_chars(struct tty_struct *tty)
struct serial_state *info = tty->driver_data;
if (info->xmit.head == info->xmit.tail || tty->stopped ||
- tty->hw_stopped || !info->xmit.buf)
+ !info->xmit.buf)
return;
transmit_chars(tty, info, NULL);
@@ -217,7 +216,7 @@ static int rs_write(struct tty_struct * tty,
* Hey, we transmit directly from here in our case
*/
if (CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) &&
- !tty->stopped && !tty->hw_stopped)
+ !tty->stopped)
transmit_chars(tty, info, NULL);
return ret;
@@ -325,14 +324,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- }
-}
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
@@ -481,7 +472,6 @@ static const struct tty_operations hp_ops = {
.throttle = rs_throttle,
.unthrottle = rs_unthrottle,
.send_xchar = rs_send_xchar,
- .set_termios = rs_set_termios,
.hangup = rs_hangup,
.proc_fops = &rs_proc_fops,
};
diff --git a/arch/ia64/include/asm/futex.h b/arch/ia64/include/asm/futex.h
index d2bf1fd5e44f..76acbcd5c060 100644
--- a/arch/ia64/include/asm/futex.h
+++ b/arch/ia64/include/asm/futex.h
@@ -106,16 +106,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
return -EFAULT;
{
- register unsigned long r8 __asm ("r8");
+ register unsigned long r8 __asm ("r8") = 0;
unsigned long prev;
__asm__ __volatile__(
" mf;; \n"
- " mov %0=r0 \n"
" mov ar.ccv=%4;; \n"
"[1:] cmpxchg4.acq %1=[%2],%3,ar.ccv \n"
" .xdata4 \"__ex_table\", 1b-., 2f-. \n"
"[2:]"
- : "=r" (r8), "=r" (prev)
+ : "+r" (r8), "=&r" (prev)
: "r" (uaddr), "r" (newval),
"rO" ((long) (unsigned) oldval)
: "memory");
diff --git a/arch/ia64/include/asm/hugetlb.h b/arch/ia64/include/asm/hugetlb.h
index 94eaa5bd5d0c..aa910054b8e7 100644
--- a/arch/ia64/include/asm/hugetlb.h
+++ b/arch/ia64/include/asm/hugetlb.h
@@ -2,6 +2,7 @@
#define _ASM_IA64_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr,
diff --git a/arch/ia64/include/asm/irqflags.h b/arch/ia64/include/asm/irqflags.h
index 2b68d856dc78..1bf2cf2f4ab4 100644
--- a/arch/ia64/include/asm/irqflags.h
+++ b/arch/ia64/include/asm/irqflags.h
@@ -89,6 +89,7 @@ static inline bool arch_irqs_disabled(void)
static inline void arch_safe_halt(void)
{
+ arch_local_irq_enable();
ia64_pal_halt_light(); /* PAL_HALT_LIGHT */
}
diff --git a/arch/ia64/include/asm/linkage.h b/arch/ia64/include/asm/linkage.h
index ef22a45c1890..787575701f1c 100644
--- a/arch/ia64/include/asm/linkage.h
+++ b/arch/ia64/include/asm/linkage.h
@@ -11,4 +11,8 @@
#endif
+#define cond_syscall(x) asm(".weak\t" #x "#\n" #x "#\t=\tsys_ni_syscall#")
+#define SYSCALL_ALIAS(alias, name) \
+ asm ( #alias "# = " #name "#\n\t.globl " #alias "#")
+
#endif
diff --git a/arch/ia64/include/asm/mca.h b/arch/ia64/include/asm/mca.h
index 43f96ab18fa0..8c7096168716 100644
--- a/arch/ia64/include/asm/mca.h
+++ b/arch/ia64/include/asm/mca.h
@@ -143,6 +143,7 @@ extern unsigned long __per_cpu_mca[NR_CPUS];
extern int cpe_vector;
extern int ia64_cpe_irq;
extern void ia64_mca_init(void);
+extern void ia64_mca_irq_init(void);
extern void ia64_mca_cpu_init(void *);
extern void ia64_os_mca_dispatch(void);
extern void ia64_os_mca_dispatch_end(void);
diff --git a/arch/ia64/include/asm/numa.h b/arch/ia64/include/asm/numa.h
index 2e27ef175652..2db0a6c6daa5 100644
--- a/arch/ia64/include/asm/numa.h
+++ b/arch/ia64/include/asm/numa.h
@@ -67,14 +67,13 @@ extern int paddr_to_nid(unsigned long paddr);
extern void map_cpu_to_node(int cpu, int nid);
extern void unmap_cpu_from_node(int cpu, int nid);
-
+extern void numa_clear_node(int cpu);
#else /* !CONFIG_NUMA */
#define map_cpu_to_node(cpu, nid) do{}while(0)
#define unmap_cpu_from_node(cpu, nid) do{}while(0)
-
#define paddr_to_nid(addr) 0
-
+#define numa_clear_node(cpu) do { } while (0)
#endif /* CONFIG_NUMA */
#endif /* _ASM_IA64_NUMA_H */
diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
index 020d655ed082..cade13dd0299 100644
--- a/arch/ia64/include/asm/thread_info.h
+++ b/arch/ia64/include/asm/thread_info.h
@@ -131,8 +131,6 @@ struct thread_info {
#define TS_POLLING 1 /* true if in idle loop and not sleeping */
#define TS_RESTORE_SIGMASK 2 /* restore signal mask in do_signal() */
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index 096373800f73..afd45e0d552e 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -46,15 +46,5 @@ asmlinkage unsigned long sys_mmap2(
struct pt_regs;
asmlinkage long sys_ia64_pipe(void);
-/*
- * "Conditional" syscalls
- *
- * Note, this macro can only be used in the file which defines sys_ni_syscall, i.e., in
- * kernel/sys_ni.c. This version causes warnings because the declaration isn't a
- * proper prototype, but we can't use __typeof__ either, because not all cond_syscall()
- * declarations have prototypes at the moment.
- */
-#define cond_syscall(x) asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall")))
-
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_UNISTD_H */
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index c567adc8bea5..6b4329f18b29 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -81,4 +81,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index d959c84904be..20678a9ed11a 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -23,7 +23,6 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o
obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
diff --git a/arch/ia64/kernel/cpufreq/Kconfig b/arch/ia64/kernel/cpufreq/Kconfig
deleted file mode 100644
index 2d9d5279b981..000000000000
--- a/arch/ia64/kernel/cpufreq/Kconfig
+++ /dev/null
@@ -1,29 +0,0 @@
-
-#
-# CPU Frequency scaling
-#
-
-menu "CPU Frequency scaling"
-
-source "drivers/cpufreq/Kconfig"
-
-if CPU_FREQ
-
-comment "CPUFreq processor drivers"
-
-config IA64_ACPI_CPUFREQ
- tristate "ACPI Processor P-States driver"
- select CPU_FREQ_TABLE
- depends on ACPI_PROCESSOR
- help
- This driver adds a CPUFreq driver which utilizes the ACPI
- Processor Performance States.
-
- For details, take a look at <file:Documentation/cpu-freq/>.
-
- If in doubt, say N.
-
-endif # CPU_FREQ
-
-endmenu
-
diff --git a/arch/ia64/kernel/cpufreq/Makefile b/arch/ia64/kernel/cpufreq/Makefile
deleted file mode 100644
index 4838f2a57c7a..000000000000
--- a/arch/ia64/kernel/cpufreq/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_IA64_ACPI_CPUFREQ) += acpi-cpufreq.o
-
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index c4cd45d97749..abc6dee3799c 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -90,53 +90,6 @@ ENTRY(fsys_getpid)
FSYS_RETURN
END(fsys_getpid)
-ENTRY(fsys_getppid)
- .prologue
- .altrp b6
- .body
- add r17=IA64_TASK_GROUP_LEADER_OFFSET,r16
- ;;
- ld8 r17=[r17] // r17 = current->group_leader
- add r9=TI_FLAGS+IA64_TASK_SIZE,r16
- ;;
-
- ld4 r9=[r9]
- add r17=IA64_TASK_REAL_PARENT_OFFSET,r17 // r17 = &current->group_leader->real_parent
- ;;
- and r9=TIF_ALLWORK_MASK,r9
-
-1: ld8 r18=[r17] // r18 = current->group_leader->real_parent
- ;;
- cmp.ne p8,p0=0,r9
- add r8=IA64_TASK_TGID_OFFSET,r18 // r8 = &current->group_leader->real_parent->tgid
- ;;
-
- /*
- * The .acq is needed to ensure that the read of tgid has returned its data before
- * we re-check "real_parent".
- */
- ld4.acq r8=[r8] // r8 = current->group_leader->real_parent->tgid
-#ifdef CONFIG_SMP
- /*
- * Re-read current->group_leader->real_parent.
- */
- ld8 r19=[r17] // r19 = current->group_leader->real_parent
-(p8) br.spnt.many fsys_fallback_syscall
- ;;
- cmp.ne p6,p0=r18,r19 // did real_parent change?
- mov r19=0 // i must not leak kernel bits...
-(p6) br.cond.spnt.few 1b // yes -> redo the read of tgid and the check
- ;;
- mov r17=0 // i must not leak kernel bits...
- mov r18=0 // i must not leak kernel bits...
-#else
- mov r17=0 // i must not leak kernel bits...
- mov r18=0 // i must not leak kernel bits...
- mov r19=0 // i must not leak kernel bits...
-#endif
- FSYS_RETURN
-END(fsys_getppid)
-
ENTRY(fsys_set_tid_address)
.prologue
.altrp b6
@@ -614,7 +567,7 @@ paravirt_fsyscall_table:
data8 0 // chown
data8 0 // lseek // 1040
data8 fsys_getpid // getpid
- data8 fsys_getppid // getppid
+ data8 0 // getppid
data8 0 // mount
data8 0 // umount
data8 0 // setuid // 1045
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index ee33c3aaa2fc..19f107be734e 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -76,7 +76,7 @@
* PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ
*
* Note: The term "IRQ" is loosely used everywhere in Linux kernel to
- * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ
+ * describe interrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ
* (isa_irq) is the only exception in this source code.
*/
@@ -1010,6 +1010,26 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
return 0;
}
+static int
+iosapic_delete_rte(unsigned int irq, unsigned int gsi)
+{
+ struct iosapic_rte_info *rte, *temp;
+
+ list_for_each_entry_safe(rte, temp, &iosapic_intr_info[irq].rtes,
+ rte_list) {
+ if (rte->iosapic->gsi_base + rte->rte_index == gsi) {
+ if (rte->refcnt)
+ return -EBUSY;
+
+ list_del(&rte->rte_list);
+ kfree(rte);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
{
int num_rte, err, index;
@@ -1069,7 +1089,7 @@ int iosapic_init(unsigned long phys_addr, unsigned int gsi_base)
int iosapic_remove(unsigned int gsi_base)
{
- int index, err = 0;
+ int i, irq, index, err = 0;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
@@ -1087,6 +1107,16 @@ int iosapic_remove(unsigned int gsi_base)
goto out;
}
+ for (i = gsi_base; i < gsi_base + iosapic_lists[index].num_rte; i++) {
+ irq = __gsi_to_irq(i);
+ if (irq < 0)
+ continue;
+
+ err = iosapic_delete_rte(irq, i);
+ if (err)
+ goto out;
+ }
+
iounmap(iosapic_lists[index].addr);
iosapic_free(index);
out:
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index ad69606613eb..f2c418281130 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -23,6 +23,8 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <asm/mca.h>
+
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves.
@@ -83,6 +85,12 @@ bool is_affinity_mask_valid(const struct cpumask *cpumask)
#endif /* CONFIG_SMP */
+int __init arch_early_irq_init(void)
+{
+ ia64_mca_irq_init();
+ return 0;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
unsigned int vectors_in_migration[NR_IRQS];
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 65bf9cd39044..d7396dbb07bb 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -2074,22 +2074,16 @@ ia64_mca_init(void)
printk(KERN_INFO "MCA related initialization done\n");
}
+
/*
- * ia64_mca_late_init
- *
- * Opportunity to setup things that require initialization later
- * than ia64_mca_init. Setup a timer to poll for CPEs if the
- * platform doesn't support an interrupt driven mechanism.
- *
- * Inputs : None
- * Outputs : Status
+ * These pieces cannot be done in ia64_mca_init() because it is called before
+ * early_irq_init() which would wipe out our percpu irq registrations. But we
+ * cannot leave them until ia64_mca_late_init() because by then all the other
+ * processors have been brought online and have set their own CMC vectors to
+ * point at a non-existant action. Called from arch_early_irq_init().
*/
-static int __init
-ia64_mca_late_init(void)
+void __init ia64_mca_irq_init(void)
{
- if (!mca_init)
- return 0;
-
/*
* Configure the CMCI/P vector and handler. Interrupts for CMC are
* per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
@@ -2108,6 +2102,23 @@ ia64_mca_late_init(void)
/* Setup the CPEI/P handler */
register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
#endif
+}
+
+/*
+ * ia64_mca_late_init
+ *
+ * Opportunity to setup things that require initialization later
+ * than ia64_mca_init. Setup a timer to poll for CPEs if the
+ * platform doesn't support an interrupt driven mechanism.
+ *
+ * Inputs : None
+ * Outputs : Status
+ */
+static int __init
+ia64_mca_late_init(void)
+{
+ if (!mca_init)
+ return 0;
register_hotcpu_notifier(&mca_cpu_notifier);
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 9392e021c93b..94f8bf777afa 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -349,7 +349,7 @@ init_record_index_pools(void)
/* - 3 - */
slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1;
- slidx_pool.buffer = (slidx_list_t *)
+ slidx_pool.buffer =
kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL);
return slidx_pool.buffer ? 0 : -ENOMEM;
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 2eda28414abb..9ea25fce06d5 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -42,6 +42,7 @@
#include <linux/completion.h>
#include <linux/tracehook.h>
#include <linux/slab.h>
+#include <linux/cpu.h>
#include <asm/errno.h>
#include <asm/intrinsics.h>
@@ -1322,8 +1323,6 @@ out:
}
EXPORT_SYMBOL(pfm_unregister_buffer_fmt);
-extern void update_pal_halt_status(int);
-
static int
pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
{
@@ -1371,9 +1370,9 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
cpu));
/*
- * disable default_idle() to go to PAL_HALT
+ * Force idle() into poll mode
*/
- update_pal_halt_status(0);
+ cpu_idle_poll_ctrl(true);
UNLOCK_PFS(flags);
@@ -1430,11 +1429,8 @@ pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu)
is_syswide,
cpu));
- /*
- * if possible, enable default_idle() to go into PAL_HALT
- */
- if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0)
- update_pal_halt_status(1);
+ /* Undo forced polling. Last session reenables pal_halt */
+ cpu_idle_poll_ctrl(false);
UNLOCK_PFS(flags);
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index e34f565f595a..55d4ba47a907 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -96,21 +96,13 @@ show_stack (struct task_struct *task, unsigned long *sp)
}
void
-dump_stack (void)
-{
- show_stack(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-void
show_regs (struct pt_regs *regs)
{
unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri;
print_modules();
- printk("\nPid: %d, CPU %d, comm: %20s\n", task_pid_nr(current),
- smp_processor_id(), current->comm);
+ printk("\n");
+ show_regs_print_info(KERN_DEFAULT);
printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s (%s)\n",
regs->cr_ipsr, regs->cr_ifs, ip, print_tainted(),
init_utsname()->release);
@@ -209,41 +201,13 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
local_irq_disable(); /* force interrupt disable */
}
-static int pal_halt = 1;
-static int can_do_pal_halt = 1;
-
static int __init nohalt_setup(char * str)
{
- pal_halt = can_do_pal_halt = 0;
+ cpu_idle_poll_ctrl(true);
return 1;
}
__setup("nohalt", nohalt_setup);
-void
-update_pal_halt_status(int status)
-{
- can_do_pal_halt = pal_halt && status;
-}
-
-/*
- * We use this if we don't have any better idle routine..
- */
-void
-default_idle (void)
-{
- local_irq_enable();
- while (!need_resched()) {
- if (can_do_pal_halt) {
- local_irq_disable();
- if (!need_resched()) {
- safe_halt();
- }
- local_irq_enable();
- } else
- cpu_relax();
- }
-}
-
#ifdef CONFIG_HOTPLUG_CPU
/* We don't actually take CPU down, just spin without interrupts. */
static inline void play_dead(void)
@@ -270,50 +234,29 @@ static inline void play_dead(void)
}
#endif /* CONFIG_HOTPLUG_CPU */
-void __attribute__((noreturn))
-cpu_idle (void)
+void arch_cpu_idle_dead(void)
+{
+ play_dead();
+}
+
+void arch_cpu_idle(void)
{
void (*mark_idle)(int) = ia64_mark_idle;
- int cpu = smp_processor_id();
-
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- if (can_do_pal_halt) {
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we
- * test NEED_RESCHED:
- */
- smp_mb();
- } else {
- current_thread_info()->status |= TS_POLLING;
- }
- if (!need_resched()) {
- void (*idle)(void);
#ifdef CONFIG_SMP
- min_xtp();
+ min_xtp();
#endif
- rmb();
- if (mark_idle)
- (*mark_idle)(1);
-
- if (!idle)
- idle = default_idle;
- (*idle)();
- if (mark_idle)
- (*mark_idle)(0);
+ rmb();
+ if (mark_idle)
+ (*mark_idle)(1);
+
+ safe_halt();
+
+ if (mark_idle)
+ (*mark_idle)(0);
#ifdef CONFIG_SMP
- normal_xtp();
+ normal_xtp();
#endif
- }
- rcu_idle_exit();
- schedule_preempt_disabled();
- check_pgt_cache();
- if (cpu_is_offline(cpu))
- play_dead();
- }
}
void
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 2029cc0d2fc6..13bfdd22afc8 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -1063,6 +1063,7 @@ check_bugs (void)
static int __init run_dmi_scan(void)
{
dmi_scan_machine();
+ dmi_set_dump_stack_arch_desc();
return 0;
}
core_initcall(run_dmi_scan);
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 500f1e4d9f9d..8d87168d218d 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -455,7 +455,7 @@ start_secondary (void *unused)
preempt_disable();
smp_callin();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
return 0;
}
diff --git a/arch/ia64/kvm/vtlb.c b/arch/ia64/kvm/vtlb.c
index 4332f7ee5203..a7869f8f49a6 100644
--- a/arch/ia64/kvm/vtlb.c
+++ b/arch/ia64/kvm/vtlb.c
@@ -256,7 +256,7 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte)
"srlz.d;;"
"ssm psr.i;;"
"srlz.d;;"
- : "=r"(ret) : "r"(iha), "r"(pte):"memory");
+ : "=&r"(ret) : "r"(iha), "r"(pte) : "memory");
return ret;
}
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 80dab509dfb0..67c59ebec899 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -47,6 +47,8 @@ void show_mem(unsigned int filter)
printk(KERN_INFO "Mem-info:\n");
show_free_areas(filter);
printk(KERN_INFO "Node memory in pages:\n");
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
for_each_online_pgdat(pgdat) {
unsigned long present;
unsigned long flags;
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index c2e955ee79a8..ae4db4bd6d97 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -623,6 +623,8 @@ void show_mem(unsigned int filter)
printk(KERN_INFO "Mem-info:\n");
show_free_areas(filter);
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
printk(KERN_INFO "Node memory in pages:\n");
for_each_online_pgdat(pgdat) {
unsigned long present;
@@ -817,13 +819,12 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
#endif
#ifdef CONFIG_SPARSEMEM_VMEMMAP
-int __meminit vmemmap_populate(struct page *start_page,
- unsigned long size, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
- return vmemmap_populate_basepages(start_page, size, node);
+ return vmemmap_populate_basepages(start, end, node);
}
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
{
}
#endif
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 20bc967c7209..d1fe4b402601 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -154,25 +154,14 @@ ia64_init_addr_space (void)
void
free_initmem (void)
{
- unsigned long addr, eaddr;
-
- addr = (unsigned long) ia64_imva(__init_begin);
- eaddr = (unsigned long) ia64_imva(__init_end);
- while (addr < eaddr) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- ++totalram_pages;
- addr += PAGE_SIZE;
- }
- printk(KERN_INFO "Freeing unused kernel memory: %ldkB freed\n",
- (__init_end - __init_begin) >> 10);
+ free_reserved_area((unsigned long)ia64_imva(__init_begin),
+ (unsigned long)ia64_imva(__init_end),
+ 0, "unused kernel");
}
void __init
free_initrd_mem (unsigned long start, unsigned long end)
{
- struct page *page;
/*
* EFI uses 4KB pages while the kernel can use 4KB or bigger.
* Thus EFI and the kernel may have different page sizes. It is
@@ -213,11 +202,7 @@ free_initrd_mem (unsigned long start, unsigned long end)
for (; start < end; start += PAGE_SIZE) {
if (!virt_addr_valid(start))
continue;
- page = virt_to_page(start);
- ClearPageReserved(page);
- init_page_count(page);
- free_page(start);
- ++totalram_pages;
+ free_reserved_page(virt_to_page(start));
}
}
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
index 3dccdd8eb275..43964cde6214 100644
--- a/arch/ia64/mm/ioremap.c
+++ b/arch/ia64/mm/ioremap.c
@@ -16,7 +16,7 @@
#include <asm/meminit.h>
static inline void __iomem *
-__ioremap (unsigned long phys_addr)
+__ioremap_uc(unsigned long phys_addr)
{
return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
}
@@ -24,7 +24,11 @@ __ioremap (unsigned long phys_addr)
void __iomem *
early_ioremap (unsigned long phys_addr, unsigned long size)
{
- return __ioremap(phys_addr);
+ u64 attr;
+ attr = kern_mem_attribute(phys_addr, size);
+ if (attr & EFI_MEMORY_WB)
+ return (void __iomem *) phys_to_virt(phys_addr);
+ return __ioremap_uc(phys_addr);
}
void __iomem *
@@ -47,7 +51,7 @@ ioremap (unsigned long phys_addr, unsigned long size)
if (attr & EFI_MEMORY_WB)
return (void __iomem *) phys_to_virt(phys_addr);
else if (attr & EFI_MEMORY_UC)
- return __ioremap(phys_addr);
+ return __ioremap_uc(phys_addr);
/*
* Some chipsets don't support UC access to memory. If
@@ -93,7 +97,7 @@ ioremap (unsigned long phys_addr, unsigned long size)
return (void __iomem *) (offset + (char __iomem *)addr);
}
- return __ioremap(phys_addr);
+ return __ioremap_uc(phys_addr);
}
EXPORT_SYMBOL(ioremap);
@@ -103,7 +107,7 @@ ioremap_nocache (unsigned long phys_addr, unsigned long size)
if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
return NULL;
- return __ioremap(phys_addr);
+ return __ioremap_uc(phys_addr);
}
EXPORT_SYMBOL(ioremap_nocache);
diff --git a/arch/ia64/mm/numa.c b/arch/ia64/mm/numa.c
index 3efea7d0a351..4248492b9321 100644
--- a/arch/ia64/mm/numa.c
+++ b/arch/ia64/mm/numa.c
@@ -61,18 +61,36 @@ paddr_to_nid(unsigned long paddr)
int __meminit __early_pfn_to_nid(unsigned long pfn)
{
int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec;
+ /*
+ * NOTE: The following SMP-unsafe globals are only used early in boot
+ * when the kernel is running single-threaded.
+ */
+ static int __meminitdata last_ssec, last_esec;
+ static int __meminitdata last_nid;
+
+ if (section >= last_ssec && section < last_esec)
+ return last_nid;
for (i = 0; i < num_node_memblks; i++) {
ssec = node_memblk[i].start_paddr >> PA_SECTION_SHIFT;
esec = (node_memblk[i].start_paddr + node_memblk[i].size +
((1L << PA_SECTION_SHIFT) - 1)) >> PA_SECTION_SHIFT;
- if (section >= ssec && section < esec)
+ if (section >= ssec && section < esec) {
+ last_ssec = ssec;
+ last_esec = esec;
+ last_nid = node_memblk[i].nid;
return node_memblk[i].nid;
+ }
}
return -1;
}
+void __cpuinit numa_clear_node(int cpu)
+{
+ unmap_cpu_from_node(cpu, NUMA_NO_NODE);
+}
+
#ifdef CONFIG_MEMORY_HOTPLUG
/*
* SRAT information is stored in node_memblk[], then we can use SRAT
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 60532ab27346..de1474ff0bc5 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/slab.h>
@@ -458,6 +459,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
platform_pci_fixup_bus(b);
}
+void pcibios_add_bus(struct pci_bus *bus)
+{
+ acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+ acpi_pci_remove_bus(bus);
+}
+
void pcibios_set_master (struct pci_dev *dev)
{
/* No special bus mastering setup handling */
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 14c1711238c0..e35f6485c1fd 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -490,11 +490,14 @@ static int __init tiocx_init(void)
{
cnodeid_t cnodeid;
int found_tiocx_device = 0;
+ int err;
if (!ia64_platform_is("sn2"))
return 0;
- bus_register(&tiocx_bus_type);
+ err = bus_register(&tiocx_bus_type);
+ if (err)
+ return err;
for (cnodeid = 0; cnodeid < num_cnodes; cnodeid++) {
nasid_t nasid;
diff --git a/arch/m32r/include/asm/unistd.h b/arch/m32r/include/asm/unistd.h
index 555629b05267..59db80193454 100644
--- a/arch/m32r/include/asm/unistd.h
+++ b/arch/m32r/include/asm/unistd.h
@@ -48,14 +48,4 @@
#define __IGNORE_getresgid
#define __IGNORE_chown
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif
-
#endif /* _ASM_M32R_UNISTD_H */
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index 519afa2755db..2a3b59e0e171 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index bde899e155d3..e69221d581d5 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -47,24 +47,6 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle (void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- cpu_relax();
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
void machine_restart(char *__unused)
{
#if defined(CONFIG_PLAT_MAPPI3)
@@ -91,6 +73,8 @@ void machine_power_off(void)
void show_regs(struct pt_regs * regs)
{
printk("\n");
+ show_regs_print_info(KERN_DEFAULT);
+
printk("BPC[%08lx]:PSW[%08lx]:LR [%08lx]:FP [%08lx]\n", \
regs->bpc, regs->psw, regs->lr, regs->fp);
printk("BBPC[%08lx]:BBPSW[%08lx]:SPU[%08lx]:SPI[%08lx]\n", \
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 13168a769f8f..0ac558adc605 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -432,7 +432,7 @@ int __init start_secondary(void *unused)
*/
local_flush_tlb_all();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
return 0;
}
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index 3bcb207e5b6d..a7a424f852e4 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -132,10 +132,8 @@ static void show_trace(struct task_struct *task, unsigned long *stack)
printk("Call Trace: ");
while (!kstack_end(stack)) {
addr = *stack++;
- if (__kernel_text_address(addr)) {
- printk("[<%08lx>] ", addr);
- print_symbol("%s\n", addr);
- }
+ if (__kernel_text_address(addr))
+ printk("[<%08lx>] %pSR\n", addr, (void *)addr);
}
printk("\n");
}
@@ -169,15 +167,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(task, sp);
}
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_trace(current, &stack);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
static void show_registers(struct pt_regs *regs)
{
int i = 0;
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
index 78b660e903da..ab4cbce91a9b 100644
--- a/arch/m32r/mm/init.c
+++ b/arch/m32r/mm/init.c
@@ -28,10 +28,7 @@
#include <asm/mmu_context.h>
#include <asm/setup.h>
#include <asm/tlb.h>
-
-/* References to section boundaries */
-extern char _text, _etext, _edata;
-extern char __init_begin, __init_end;
+#include <asm/sections.h>
pgd_t swapper_pg_dir[1024];
@@ -184,17 +181,7 @@ void __init mem_init(void)
*======================================================================*/
void free_initmem(void)
{
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", \
- (int)(&__init_end - &__init_begin) >> 10);
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -204,13 +191,6 @@ void free_initmem(void)
*======================================================================*/
void free_initrd_mem(unsigned long start, unsigned long end)
{
- unsigned long p;
- for (p = start; p < end; p += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(p));
- init_page_count(virt_to_page(p));
- free_page(p);
- totalram_pages++;
- }
- printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/m68k/Kconfig.bus b/arch/m68k/Kconfig.bus
index 93ef0346b209..675b087198f6 100644
--- a/arch/m68k/Kconfig.bus
+++ b/arch/m68k/Kconfig.bus
@@ -45,6 +45,16 @@ config ISA
(MCA) or VESA. ISA is an older system, now being displaced by PCI;
newer boards don't support it. If you have ISA, say Y, otherwise N.
+config ATARI_ROM_ISA
+ bool "Atari ROM port ISA adapter support"
+ depends on ATARI
+ help
+ This option enables support for the ROM port ISA adapter used to
+ operate ISA cards on Atari. Only 8 bit cards are supported, and
+ no interrupt lines are connected.
+ The only driver currently using this adapter is the EtherNEC
+ driver for RTL8019AS based NE2000 compatible network cards.
+
config GENERIC_ISA_DMA
def_bool ISA
diff --git a/arch/m68k/Kconfig.devices b/arch/m68k/Kconfig.devices
index 4bc945dfe467..d163991c5717 100644
--- a/arch/m68k/Kconfig.devices
+++ b/arch/m68k/Kconfig.devices
@@ -55,6 +55,30 @@ config NFETH
which will emulate a regular ethernet device while presenting an
ethertap device to the host system.
+config ATARI_ETHERNAT
+ bool "Atari EtherNAT Ethernet support"
+ depends on ATARI
+ ---help---
+ Say Y to include support for the EtherNAT network adapter for the
+ CT/60 extension port.
+
+ To compile the actual ethernet driver, choose Y or M for the SMC91X
+ option in the network device section; the module will be called smc91x.
+
+config ATARI_ETHERNEC
+ bool "Atari EtherNEC Ethernet support"
+ depends on ATARI_ROM_ISA
+ ---help---
+ Say Y to include support for the EtherNEC network adapter for the
+ ROM port. The driver works by polling instead of interrupts, so it
+ is quite slow.
+
+ This driver also suppports the ethernet part of the NetUSBee ROM
+ port combined Ethernet/USB adapter.
+
+ To compile the actual ethernet driver, choose Y or M in for the NE2000
+ option in the network device section; the module will be called ne.
+
endmenu
menu "Character devices"
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 3f41092d1b70..20cde4e9fc77 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -49,6 +49,7 @@
#include <asm/atari_stdma.h>
#include <asm/irq.h>
#include <asm/entry.h>
+#include <asm/io.h>
/*
@@ -122,6 +123,136 @@ static struct irq_chip atari_irq_chip = {
};
/*
+ * ST-MFP timer D chained interrupts - each driver gets its own timer
+ * interrupt instance.
+ */
+
+struct mfptimerbase {
+ volatile struct MFP *mfp;
+ unsigned char mfp_mask, mfp_data;
+ unsigned short int_mask;
+ int handler_irq, mfptimer_irq, server_irq;
+ char *name;
+} stmfp_base = {
+ .mfp = &st_mfp,
+ .int_mask = 0x0,
+ .handler_irq = IRQ_MFP_TIMD,
+ .mfptimer_irq = IRQ_MFP_TIMER1,
+ .name = "MFP Timer D"
+};
+
+static irqreturn_t mfptimer_handler(int irq, void *dev_id)
+{
+ struct mfptimerbase *base = dev_id;
+ int mach_irq;
+ unsigned char ints;
+
+ mach_irq = base->mfptimer_irq;
+ ints = base->int_mask;
+ for (; ints; mach_irq++, ints >>= 1) {
+ if (ints & 1)
+ generic_handle_irq(mach_irq);
+ }
+ return IRQ_HANDLED;
+}
+
+
+static void atari_mfptimer_enable(struct irq_data *data)
+{
+ int mfp_num = data->irq - IRQ_MFP_TIMER1;
+ stmfp_base.int_mask |= 1 << mfp_num;
+ atari_enable_irq(IRQ_MFP_TIMD);
+}
+
+static void atari_mfptimer_disable(struct irq_data *data)
+{
+ int mfp_num = data->irq - IRQ_MFP_TIMER1;
+ stmfp_base.int_mask &= ~(1 << mfp_num);
+ if (!stmfp_base.int_mask)
+ atari_disable_irq(IRQ_MFP_TIMD);
+}
+
+static struct irq_chip atari_mfptimer_chip = {
+ .name = "timer_d",
+ .irq_enable = atari_mfptimer_enable,
+ .irq_disable = atari_mfptimer_disable,
+};
+
+
+/*
+ * EtherNAT CPLD interrupt handling
+ * CPLD interrupt register is at phys. 0x80000023
+ * Need this mapped in at interrupt startup time
+ * Possibly need this mapped on demand anyway -
+ * EtherNAT USB driver needs to disable IRQ before
+ * startup!
+ */
+
+static unsigned char *enat_cpld;
+
+static unsigned int atari_ethernat_startup(struct irq_data *data)
+{
+ int enat_num = 140 - data->irq + 1;
+
+ m68k_irq_startup(data);
+ /*
+ * map CPLD interrupt register
+ */
+ if (!enat_cpld)
+ enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+ /*
+ * do _not_ enable the USB chip interrupt here - causes interrupt storm
+ * and triggers dead interrupt watchdog
+ * Need to reset the USB chip to a sane state in early startup before
+ * removing this hack
+ */
+ if (enat_num == 1)
+ *enat_cpld |= 1 << enat_num;
+
+ return 0;
+}
+
+static void atari_ethernat_enable(struct irq_data *data)
+{
+ int enat_num = 140 - data->irq + 1;
+ /*
+ * map CPLD interrupt register
+ */
+ if (!enat_cpld)
+ enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+ *enat_cpld |= 1 << enat_num;
+}
+
+static void atari_ethernat_disable(struct irq_data *data)
+{
+ int enat_num = 140 - data->irq + 1;
+ /*
+ * map CPLD interrupt register
+ */
+ if (!enat_cpld)
+ enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
+ *enat_cpld &= ~(1 << enat_num);
+}
+
+static void atari_ethernat_shutdown(struct irq_data *data)
+{
+ int enat_num = 140 - data->irq + 1;
+ if (enat_cpld) {
+ *enat_cpld &= ~(1 << enat_num);
+ iounmap(enat_cpld);
+ enat_cpld = NULL;
+ }
+}
+
+static struct irq_chip atari_ethernat_chip = {
+ .name = "ethernat",
+ .irq_startup = atari_ethernat_startup,
+ .irq_shutdown = atari_ethernat_shutdown,
+ .irq_enable = atari_ethernat_enable,
+ .irq_disable = atari_ethernat_disable,
+};
+
+/*
* void atari_init_IRQ (void)
*
* Parameters: None
@@ -198,6 +329,27 @@ void __init atari_init_IRQ(void)
/* Initialize the PSG: all sounds off, both ports output */
sound_ym.rd_data_reg_sel = 7;
sound_ym.wd_data = 0xff;
+
+ m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq,
+ IRQ_MFP_TIMER1, 8);
+
+ /* prepare timer D data for use as poll interrupt */
+ /* set Timer D data Register - needs to be > 0 */
+ st_mfp.tim_dt_d = 254; /* < 100 Hz */
+ /* start timer D, div = 1:100 */
+ st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6;
+
+ /* request timer D dispatch handler */
+ if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
+ stmfp_base.name, &stmfp_base))
+ pr_err("Couldn't register %s interrupt\n", stmfp_base.name);
+
+ /*
+ * EtherNAT ethernet / USB interrupt handlers
+ */
+
+ m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq,
+ 139, 2);
}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 037c11c99331..fb2d0bd9b3ad 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -31,6 +31,8 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/usb/isp116x.h>
#include <linux/vt_kern.h>
#include <linux/module.h>
@@ -655,3 +657,240 @@ static void atari_get_hardware_list(struct seq_file *m)
ATARIHW_ANNOUNCE(VME, "VME Bus");
ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
}
+
+/*
+ * MSch: initial platform device support for Atari,
+ * required for EtherNAT/EtherNEC/NetUSBee drivers
+ */
+
+#if defined(CONFIG_ATARI_ETHERNAT) || defined(CONFIG_ATARI_ETHERNEC)
+static void isp1160_delay(struct device *dev, int delay)
+{
+ ndelay(delay);
+}
+#endif
+
+#ifdef CONFIG_ATARI_ETHERNAT
+/*
+ * EtherNAT: SMC91C111 Ethernet chipset, handled by smc91x driver
+ */
+
+#define ATARI_ETHERNAT_IRQ 140
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .name = "smc91x-regs",
+ .start = ATARI_ETHERNAT_PHYS_ADDR,
+ .end = ATARI_ETHERNAT_PHYS_ADDR + 0xfffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "smc91x-irq",
+ .start = ATARI_ETHERNAT_IRQ,
+ .end = ATARI_ETHERNAT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+/*
+ * ISP 1160 - using the isp116x-hcd module
+ */
+
+#define ATARI_USB_PHYS_ADDR 0x80000012
+#define ATARI_USB_IRQ 139
+
+static struct resource isp1160_resources[] = {
+ [0] = {
+ .name = "isp1160-data",
+ .start = ATARI_USB_PHYS_ADDR,
+ .end = ATARI_USB_PHYS_ADDR + 0x1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "isp1160-regs",
+ .start = ATARI_USB_PHYS_ADDR + 0x4,
+ .end = ATARI_USB_PHYS_ADDR + 0x5,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "isp1160-irq",
+ .start = ATARI_USB_IRQ,
+ .end = ATARI_USB_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
+static struct isp116x_platform_data isp1160_platform_data = {
+ /* Enable internal resistors on downstream ports */
+ .sel15Kres = 1,
+ /* On-chip overcurrent protection */
+ .oc_enable = 1,
+ /* INT output polarity */
+ .int_act_high = 1,
+ /* INT edge or level triggered */
+ .int_edge_triggered = 0,
+
+ /* WAKEUP pin connected - NOT SUPPORTED */
+ /* .remote_wakeup_connected = 0, */
+ /* Wakeup by devices on usb bus enabled */
+ .remote_wakeup_enable = 0,
+ .delay = isp1160_delay,
+};
+
+static struct platform_device isp1160_device = {
+ .name = "isp116x-hcd",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(isp1160_resources),
+ .resource = isp1160_resources,
+ .dev = {
+ .platform_data = &isp1160_platform_data,
+ },
+};
+
+static struct platform_device *atari_ethernat_devices[] __initdata = {
+ &smc91x_device,
+ &isp1160_device
+};
+#endif /* CONFIG_ATARI_ETHERNAT */
+
+#ifdef CONFIG_ATARI_ETHERNEC
+/*
+ * EtherNEC: RTL8019 (NE2000 compatible) Ethernet chipset,
+ * handled by ne.c driver
+ */
+
+#define ATARI_ETHERNEC_PHYS_ADDR 0xfffa0000
+#define ATARI_ETHERNEC_BASE 0x300
+#define ATARI_ETHERNEC_IRQ IRQ_MFP_TIMER1
+
+static struct resource rtl8019_resources[] = {
+ [0] = {
+ .name = "rtl8019-regs",
+ .start = ATARI_ETHERNEC_BASE,
+ .end = ATARI_ETHERNEC_BASE + 0x20 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .name = "rtl8019-irq",
+ .start = ATARI_ETHERNEC_IRQ,
+ .end = ATARI_ETHERNEC_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtl8019_device = {
+ .name = "ne",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtl8019_resources),
+ .resource = rtl8019_resources,
+};
+
+/*
+ * NetUSBee: ISP1160 USB host adapter via ROM-port adapter
+ */
+
+#define ATARI_NETUSBEE_PHYS_ADDR 0xfffa8000
+#define ATARI_NETUSBEE_BASE 0x340
+#define ATARI_NETUSBEE_IRQ IRQ_MFP_TIMER2
+
+static struct resource netusbee_resources[] = {
+ [0] = {
+ .name = "isp1160-data",
+ .start = ATARI_NETUSBEE_BASE,
+ .end = ATARI_NETUSBEE_BASE + 0x1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "isp1160-regs",
+ .start = ATARI_NETUSBEE_BASE + 0x20,
+ .end = ATARI_NETUSBEE_BASE + 0x21,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "isp1160-irq",
+ .start = ATARI_NETUSBEE_IRQ,
+ .end = ATARI_NETUSBEE_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* (DataBusWidth16|AnalogOCEnable|DREQOutputPolarity|DownstreamPort15KRSel ) */
+static struct isp116x_platform_data netusbee_platform_data = {
+ /* Enable internal resistors on downstream ports */
+ .sel15Kres = 1,
+ /* On-chip overcurrent protection */
+ .oc_enable = 1,
+ /* INT output polarity */
+ .int_act_high = 1,
+ /* INT edge or level triggered */
+ .int_edge_triggered = 0,
+
+ /* WAKEUP pin connected - NOT SUPPORTED */
+ /* .remote_wakeup_connected = 0, */
+ /* Wakeup by devices on usb bus enabled */
+ .remote_wakeup_enable = 0,
+ .delay = isp1160_delay,
+};
+
+static struct platform_device netusbee_device = {
+ .name = "isp116x-hcd",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(netusbee_resources),
+ .resource = netusbee_resources,
+ .dev = {
+ .platform_data = &netusbee_platform_data,
+ },
+};
+
+static struct platform_device *atari_netusbee_devices[] __initdata = {
+ &rtl8019_device,
+ &netusbee_device
+};
+#endif /* CONFIG_ATARI_ETHERNEC */
+
+int __init atari_platform_init(void)
+{
+ int rv = 0;
+
+ if (!MACH_IS_ATARI)
+ return -ENODEV;
+
+#ifdef CONFIG_ATARI_ETHERNAT
+ {
+ unsigned char *enatc_virt;
+ enatc_virt = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0xf);
+ if (hwreg_present(enatc_virt)) {
+ rv = platform_add_devices(atari_ethernat_devices,
+ ARRAY_SIZE(atari_ethernat_devices));
+ }
+ iounmap(enatc_virt);
+ }
+#endif
+
+#ifdef CONFIG_ATARI_ETHERNEC
+ {
+ int error;
+ unsigned char *enec_virt;
+ enec_virt = (unsigned char *)ioremap((ATARI_ETHERNEC_PHYS_ADDR), 0xf);
+ if (hwreg_present(enec_virt)) {
+ error = platform_add_devices(atari_netusbee_devices,
+ ARRAY_SIZE(atari_netusbee_devices));
+ if (error && !rv)
+ rv = error;
+ }
+ iounmap(enec_virt);
+ }
+#endif
+
+ return rv;
+}
+
+arch_initcall(atari_platform_init);
diff --git a/arch/m68k/include/asm/atarihw.h b/arch/m68k/include/asm/atarihw.h
index c0cb36350775..d887050e6da6 100644
--- a/arch/m68k/include/asm/atarihw.h
+++ b/arch/m68k/include/asm/atarihw.h
@@ -805,5 +805,11 @@ struct MSTE_RTC {
#define mste_rtc ((*(volatile struct MSTE_RTC *)MSTE_RTC_BAS))
+/*
+** EtherNAT add-on card for Falcon - combined ethernet and USB adapter
+*/
+
+#define ATARI_ETHERNAT_PHYS_ADDR 0x80000000
+
#endif /* linux/atarihw.h */
diff --git a/arch/m68k/include/asm/atariints.h b/arch/m68k/include/asm/atariints.h
index 5fc13bdf9044..953e0ac6855e 100644
--- a/arch/m68k/include/asm/atariints.h
+++ b/arch/m68k/include/asm/atariints.h
@@ -32,7 +32,7 @@
#define VME_SOURCE_BASE 56
#define VME_MAX_SOURCES 16
-#define NUM_ATARI_SOURCES (VME_SOURCE_BASE+VME_MAX_SOURCES-STMFP_SOURCE_BASE)
+#define NUM_ATARI_SOURCES 141
/* convert vector number to int source number */
#define IRQ_VECTOR_TO_SOURCE(v) ((v) - ((v) < 0x20 ? 0x18 : (0x40-8)))
@@ -94,6 +94,15 @@
#define IRQ_SCCA_RX (52)
#define IRQ_SCCA_SPCOND (54)
+/* shared MFP timer D interrupts - hires timer for EtherNEC et al. */
+#define IRQ_MFP_TIMER1 (64)
+#define IRQ_MFP_TIMER2 (65)
+#define IRQ_MFP_TIMER3 (66)
+#define IRQ_MFP_TIMER4 (67)
+#define IRQ_MFP_TIMER5 (68)
+#define IRQ_MFP_TIMER6 (69)
+#define IRQ_MFP_TIMER7 (70)
+#define IRQ_MFP_TIMER8 (71)
#define INT_CLK 24576 /* CLK while int_clk =2.456MHz and divide = 100 */
#define INT_TICKS 246 /* to make sched_time = 99.902... HZ */
diff --git a/arch/m68k/include/asm/cmpxchg.h b/arch/m68k/include/asm/cmpxchg.h
index 5c81d0eae5cf..bc755bc620ad 100644
--- a/arch/m68k/include/asm/cmpxchg.h
+++ b/arch/m68k/include/asm/cmpxchg.h
@@ -124,6 +124,9 @@ static inline unsigned long __cmpxchg(volatile void *p, unsigned long old,
#define cmpxchg_local(ptr, o, n) \
((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \
(unsigned long)(n), sizeof(*(ptr))))
+
+#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
+
#else
/*
diff --git a/arch/m68k/include/asm/delay.h b/arch/m68k/include/asm/delay.h
index 12d8fe4f1d30..d28fa8fe26fe 100644
--- a/arch/m68k/include/asm/delay.h
+++ b/arch/m68k/include/asm/delay.h
@@ -92,5 +92,28 @@ static inline void __udelay(unsigned long usecs)
#define udelay(n) (__builtin_constant_p(n) ? \
((n) > 20000 ? __bad_udelay() : __const_udelay(n)) : __udelay(n))
+/*
+ * nanosecond delay:
+ *
+ * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6) is the number of loops
+ * per microsecond
+ *
+ * 1000 / ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6) is the number of
+ * nanoseconds per loop
+ *
+ * So n / ( 1000 / ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6) ) would
+ * be the number of loops for n nanoseconds
+ */
+
+/*
+ * The simpler m68k and ColdFire processors do not have a 32*32->64
+ * multiply instruction. So we need to handle them a little differently.
+ * We use a bit of shifting and a single 32*32->32 multiply to get close.
+ * This is a macro so that the const version can factor out the first
+ * multiply and shift.
+ */
+#define HZSCALE (268435456 / (1000000 / HZ))
+
+#define ndelay(n) __delay(DIV_ROUND_UP((n) * ((((HZSCALE) >> 11) * (loops_per_jiffy >> 11)) >> 6), 1000));
#endif /* defined(_M68K_DELAY_H) */
diff --git a/arch/m68k/include/asm/gpio.h b/arch/m68k/include/asm/gpio.h
index 4395ffc51fdb..8cc83431805b 100644
--- a/arch/m68k/include/asm/gpio.h
+++ b/arch/m68k/include/asm/gpio.h
@@ -86,4 +86,24 @@ static inline int gpio_cansleep(unsigned gpio)
return gpio < MCFGPIO_PIN_MAX ? 0 : __gpio_cansleep(gpio);
}
+static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
+{
+ int err;
+
+ err = gpio_request(gpio, label);
+ if (err)
+ return err;
+
+ if (flags & GPIOF_DIR_IN)
+ err = gpio_direction_input(gpio);
+ else
+ err = gpio_direction_output(gpio,
+ (flags & GPIOF_INIT_HIGH) ? 1 : 0);
+
+ if (err)
+ gpio_free(gpio);
+
+ return err;
+}
+
#endif
diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h
index a6686d26fe17..ffdf54f44bc6 100644
--- a/arch/m68k/include/asm/io_mm.h
+++ b/arch/m68k/include/asm/io_mm.h
@@ -63,6 +63,23 @@
#endif
#endif /* AMIGA_PCMCIA */
+#ifdef CONFIG_ATARI_ROM_ISA
+
+#define enec_isa_read_base 0xfffa0000
+#define enec_isa_write_base 0xfffb0000
+
+#define ENEC_ISA_IO_B(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x7F)<<9))
+#define ENEC_ISA_IO_W(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x7F)<<9))
+#define ENEC_ISA_MEM_B(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x7F)<<9))
+#define ENEC_ISA_MEM_W(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x7F)<<9))
+
+#ifndef MULTI_ISA
+#define MULTI_ISA 0
+#else
+#undef MULTI_ISA
+#define MULTI_ISA 1
+#endif
+#endif /* ATARI_ROM_ISA */
#if defined(CONFIG_PCI) && defined(CONFIG_COLDFIRE)
@@ -111,14 +128,15 @@ void mcf_pci_outsl(u32 addr, const u32 *buf, u32 len);
#define readw(addr) in_le16(addr)
#define writew(v, addr) out_le16((addr), (v))
-#elif defined(CONFIG_ISA)
+#elif defined(CONFIG_ISA) || defined(CONFIG_ATARI_ROM_ISA)
#if MULTI_ISA == 0
#undef MULTI_ISA
#endif
-#define ISA_TYPE_Q40 (1)
-#define ISA_TYPE_AG (2)
+#define ISA_TYPE_Q40 (1)
+#define ISA_TYPE_AG (2)
+#define ISA_TYPE_ENEC (3)
#if defined(CONFIG_Q40) && !defined(MULTI_ISA)
#define ISA_TYPE ISA_TYPE_Q40
@@ -128,6 +146,10 @@ void mcf_pci_outsl(u32 addr, const u32 *buf, u32 len);
#define ISA_TYPE ISA_TYPE_AG
#define ISA_SEX 1
#endif
+#if defined(CONFIG_ATARI_ROM_ISA) && !defined(MULTI_ISA)
+#define ISA_TYPE ISA_TYPE_ENEC
+#define ISA_SEX 0
+#endif
#ifdef MULTI_ISA
extern int isa_type;
@@ -152,6 +174,9 @@ static inline u8 __iomem *isa_itb(unsigned long addr)
#ifdef CONFIG_AMIGA_PCMCIA
case ISA_TYPE_AG: return (u8 __iomem *)AG_ISA_IO_B(addr);
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ case ISA_TYPE_ENEC: return (u8 __iomem *)ENEC_ISA_IO_B(addr);
+#endif
default: return NULL; /* avoid warnings, just in case */
}
}
@@ -165,6 +190,9 @@ static inline u16 __iomem *isa_itw(unsigned long addr)
#ifdef CONFIG_AMIGA_PCMCIA
case ISA_TYPE_AG: return (u16 __iomem *)AG_ISA_IO_W(addr);
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ case ISA_TYPE_ENEC: return (u16 __iomem *)ENEC_ISA_IO_W(addr);
+#endif
default: return NULL; /* avoid warnings, just in case */
}
}
@@ -188,6 +216,9 @@ static inline u8 __iomem *isa_mtb(unsigned long addr)
#ifdef CONFIG_AMIGA_PCMCIA
case ISA_TYPE_AG: return (u8 __iomem *)addr;
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ case ISA_TYPE_ENEC: return (u8 __iomem *)ENEC_ISA_MEM_B(addr);
+#endif
default: return NULL; /* avoid warnings, just in case */
}
}
@@ -201,6 +232,9 @@ static inline u16 __iomem *isa_mtw(unsigned long addr)
#ifdef CONFIG_AMIGA_PCMCIA
case ISA_TYPE_AG: return (u16 __iomem *)addr;
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ case ISA_TYPE_ENEC: return (u16 __iomem *)ENEC_ISA_MEM_W(addr);
+#endif
default: return NULL; /* avoid warnings, just in case */
}
}
@@ -222,6 +256,36 @@ static inline u16 __iomem *isa_mtw(unsigned long addr)
(ISA_SEX ? out_be16(isa_mtw((unsigned long)(p)),(val)) \
: out_le16(isa_mtw((unsigned long)(p)),(val)))
+#ifdef CONFIG_ATARI_ROM_ISA
+#define isa_rom_inb(port) rom_in_8(isa_itb(port))
+#define isa_rom_inw(port) \
+ (ISA_SEX ? rom_in_be16(isa_itw(port)) \
+ : rom_in_le16(isa_itw(port)))
+
+#define isa_rom_outb(val, port) rom_out_8(isa_itb(port), (val))
+#define isa_rom_outw(val, port) \
+ (ISA_SEX ? rom_out_be16(isa_itw(port), (val)) \
+ : rom_out_le16(isa_itw(port), (val)))
+
+#define isa_rom_readb(p) rom_in_8(isa_mtb((unsigned long)(p)))
+#define isa_rom_readw(p) \
+ (ISA_SEX ? rom_in_be16(isa_mtw((unsigned long)(p))) \
+ : rom_in_le16(isa_mtw((unsigned long)(p))))
+#define isa_rom_readw_swap(p) \
+ (ISA_SEX ? rom_in_le16(isa_mtw((unsigned long)(p))) \
+ : rom_in_be16(isa_mtw((unsigned long)(p))))
+#define isa_rom_readw_raw(p) rom_in_be16(isa_mtw((unsigned long)(p)))
+
+#define isa_rom_writeb(val, p) rom_out_8(isa_mtb((unsigned long)(p)), (val))
+#define isa_rom_writew(val, p) \
+ (ISA_SEX ? rom_out_be16(isa_mtw((unsigned long)(p)), (val)) \
+ : rom_out_le16(isa_mtw((unsigned long)(p)), (val)))
+#define isa_rom_writew_swap(val, p) \
+ (ISA_SEX ? rom_out_le16(isa_mtw((unsigned long)(p)), (val)) \
+ : rom_out_be16(isa_mtw((unsigned long)(p)), (val)))
+#define isa_rom_writew_raw(val, p) rom_out_be16(isa_mtw((unsigned long)(p)), (val))
+#endif /* CONFIG_ATARI_ROM_ISA */
+
static inline void isa_delay(void)
{
switch(ISA_TYPE)
@@ -232,6 +296,9 @@ static inline void isa_delay(void)
#ifdef CONFIG_AMIGA_PCMCIA
case ISA_TYPE_AG: break;
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ case ISA_TYPE_ENEC: break;
+#endif
default: break; /* avoid warnings */
}
}
@@ -263,6 +330,29 @@ static inline void isa_delay(void)
raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+#ifdef CONFIG_ATARI_ROM_ISA
+#define isa_rom_inb_p(p) ({ u8 _v = isa_rom_inb(p); isa_delay(); _v; })
+#define isa_rom_inw_p(p) ({ u16 _v = isa_rom_inw(p); isa_delay(); _v; })
+#define isa_rom_outb_p(v, p) ({ isa_rom_outb((v), (p)); isa_delay(); })
+#define isa_rom_outw_p(v, p) ({ isa_rom_outw((v), (p)); isa_delay(); })
+
+#define isa_rom_insb(port, buf, nr) raw_rom_insb(isa_itb(port), (u8 *)(buf), (nr))
+
+#define isa_rom_insw(port, buf, nr) \
+ (ISA_SEX ? raw_rom_insw(isa_itw(port), (u16 *)(buf), (nr)) : \
+ raw_rom_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
+#define isa_rom_outsb(port, buf, nr) raw_rom_outsb(isa_itb(port), (u8 *)(buf), (nr))
+
+#define isa_rom_outsw(port, buf, nr) \
+ (ISA_SEX ? raw_rom_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \
+ raw_rom_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+#endif /* CONFIG_ATARI_ROM_ISA */
+
+#endif /* CONFIG_ISA || CONFIG_ATARI_ROM_ISA */
+
+
+#if defined(CONFIG_ISA) && !defined(CONFIG_ATARI_ROM_ISA)
#define inb isa_inb
#define inb_p isa_inb_p
#define outb isa_outb
@@ -285,9 +375,43 @@ static inline void isa_delay(void)
#define readw isa_readw
#define writeb isa_writeb
#define writew isa_writew
+#endif /* CONFIG_ISA && !CONFIG_ATARI_ROM_ISA */
-#else /* CONFIG_ISA */
-
+#ifdef CONFIG_ATARI_ROM_ISA
+/*
+ * kernel with both ROM port ISA and IDE compiled in, those have
+ * conflicting defs for in/out. Simply consider port < 1024
+ * ROM port ISA and everything else regular ISA for IDE. read,write defined
+ * below.
+ */
+#define inb(port) ((port) < 1024 ? isa_rom_inb(port) : in_8(port))
+#define inb_p(port) ((port) < 1024 ? isa_rom_inb_p(port) : in_8(port))
+#define inw(port) ((port) < 1024 ? isa_rom_inw(port) : in_le16(port))
+#define inw_p(port) ((port) < 1024 ? isa_rom_inw_p(port) : in_le16(port))
+#define inl isa_inl
+#define inl_p isa_inl_p
+
+#define outb(val, port) ((port) < 1024 ? isa_rom_outb((val), (port)) : out_8((port), (val)))
+#define outb_p(val, port) ((port) < 1024 ? isa_rom_outb_p((val), (port)) : out_8((port), (val)))
+#define outw(val, port) ((port) < 1024 ? isa_rom_outw((val), (port)) : out_le16((port), (val)))
+#define outw_p(val, port) ((port) < 1024 ? isa_rom_outw_p((val), (port)) : out_le16((port), (val)))
+#define outl isa_outl
+#define outl_p isa_outl_p
+
+#define insb(port, buf, nr) ((port) < 1024 ? isa_rom_insb((port), (buf), (nr)) : isa_insb((port), (buf), (nr)))
+#define insw(port, buf, nr) ((port) < 1024 ? isa_rom_insw((port), (buf), (nr)) : isa_insw((port), (buf), (nr)))
+#define insl isa_insl
+#define outsb(port, buf, nr) ((port) < 1024 ? isa_rom_outsb((port), (buf), (nr)) : isa_outsb((port), (buf), (nr)))
+#define outsw(port, buf, nr) ((port) < 1024 ? isa_rom_outsw((port), (buf), (nr)) : isa_outsw((port), (buf), (nr)))
+#define outsl isa_outsl
+
+#define readb(addr) in_8(addr)
+#define writeb(val, addr) out_8((addr), (val))
+#define readw(addr) in_le16(addr)
+#define writew(val, addr) out_le16((addr), (val))
+#endif /* CONFIG_ATARI_ROM_ISA */
+
+#if !defined(CONFIG_ISA) && !defined(CONFIG_ATARI_ROM_ISA)
/*
* We need to define dummy functions for GENERIC_IOMAP support.
*/
@@ -319,7 +443,7 @@ static inline void isa_delay(void)
#define readw(addr) in_le16(addr)
#define writew(val,addr) out_le16((addr),(val))
-#endif /* CONFIG_ISA */
+#endif /* !CONFIG_ISA && !CONFIG_ATARI_ROM_ISA */
#define readl(addr) in_le32(addr)
#define writel(val,addr) out_le32((addr),(val))
diff --git a/arch/m68k/include/asm/irq.h b/arch/m68k/include/asm/irq.h
index c1155f0e22cc..81ca118d58af 100644
--- a/arch/m68k/include/asm/irq.h
+++ b/arch/m68k/include/asm/irq.h
@@ -6,12 +6,16 @@
* different m68k hosts compiled into the kernel.
* Currently the Atari has 72 and the Amiga 24, but if both are
* supported in the kernel it is better to make room for 72.
+ * With EtherNAT add-on card on Atari, the highest interrupt
+ * number is 140 so NR_IRQS needs to be 141.
*/
#if defined(CONFIG_COLDFIRE)
#define NR_IRQS 256
#elif defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
#define NR_IRQS 200
-#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#elif defined(CONFIG_ATARI)
+#define NR_IRQS 141
+#elif defined(CONFIG_MAC)
#define NR_IRQS 72
#elif defined(CONFIG_Q40)
#define NR_IRQS 43
diff --git a/arch/m68k/include/asm/raw_io.h b/arch/m68k/include/asm/raw_io.h
index d9eb9834ccc8..932faa35655b 100644
--- a/arch/m68k/include/asm/raw_io.h
+++ b/arch/m68k/include/asm/raw_io.h
@@ -10,7 +10,7 @@
#ifdef __KERNEL__
-#include <asm/types.h>
+#include <asm/byteorder.h>
/* Values for nocacheflag and cmode */
@@ -60,6 +60,57 @@ extern void __iounmap(void *addr, unsigned long size);
#define __raw_writew(val,addr) out_be16((addr),(val))
#define __raw_writel(val,addr) out_be32((addr),(val))
+/*
+ * Atari ROM port (cartridge port) ISA adapter, used for the EtherNEC NE2000
+ * network card driver.
+ * The ISA adapter connects address lines A9-A13 to ISA address lines A0-A4,
+ * and hardwires the rest of the ISA addresses for a base address of 0x300.
+ *
+ * Data lines D8-D15 are connected to ISA data lines D0-D7 for reading.
+ * For writes, address lines A1-A8 are latched to ISA data lines D0-D7
+ * (meaning the bit pattern on A1-A8 can be read back as byte).
+ *
+ * Read and write operations are distinguished by the base address used:
+ * reads are from the ROM A side range, writes are through the B side range
+ * addresses (A side base + 0x10000).
+ *
+ * Reads and writes are byte only.
+ *
+ * 16 bit reads and writes are necessary for the NetUSBee adapter's USB
+ * chipset - 16 bit words are read straight off the ROM port while 16 bit
+ * reads are split into two byte writes. The low byte is latched to the
+ * NetUSBee buffer by a read from the _read_ window (with the data pattern
+ * asserted as A1-A8 address pattern). The high byte is then written to the
+ * write range as usual, completing the write cycle.
+ */
+
+#if defined(CONFIG_ATARI_ROM_ISA)
+#define rom_in_8(addr) \
+ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; })
+#define rom_in_be16(addr) \
+ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v; })
+#define rom_in_le16(addr) \
+ ({ u16 __v = le16_to_cpu(*(__force volatile u16 *) (addr)); __v; })
+
+#define rom_out_8(addr, b) \
+ ({u8 __w, __v = (b); u32 _addr = ((u32) (addr)); \
+ __w = ((*(__force volatile u8 *) ((_addr | 0x10000) + (__v<<1)))); })
+#define rom_out_be16(addr, w) \
+ ({u16 __w, __v = (w); u32 _addr = ((u32) (addr)); \
+ __w = ((*(__force volatile u16 *) ((_addr & 0xFFFF0000UL) + ((__v & 0xFF)<<1)))); \
+ __w = ((*(__force volatile u16 *) ((_addr | 0x10000) + ((__v >> 8)<<1)))); })
+#define rom_out_le16(addr, w) \
+ ({u16 __w, __v = (w); u32 _addr = ((u32) (addr)); \
+ __w = ((*(__force volatile u16 *) ((_addr & 0xFFFF0000UL) + ((__v >> 8)<<1)))); \
+ __w = ((*(__force volatile u16 *) ((_addr | 0x10000) + ((__v & 0xFF)<<1)))); })
+
+#define raw_rom_inb rom_in_8
+#define raw_rom_inw rom_in_be16
+
+#define raw_rom_outb(val, port) rom_out_8((port), (val))
+#define raw_rom_outw(val, port) rom_out_be16((port), (val))
+#endif /* CONFIG_ATARI_ROM_ISA */
+
static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
{
unsigned int i;
@@ -342,6 +393,62 @@ static inline void raw_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
: "d0", "a0", "a1", "d6");
}
+
+#if defined(CONFIG_ATARI_ROM_ISA)
+static inline void raw_rom_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ *buf++ = rom_in_8(port);
+}
+
+static inline void raw_rom_outsb(volatile u8 __iomem *port, const u8 *buf,
+ unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ rom_out_8(port, *buf++);
+}
+
+static inline void raw_rom_insw(volatile u16 __iomem *port, u16 *buf,
+ unsigned int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ *buf++ = rom_in_be16(port);
+}
+
+static inline void raw_rom_outsw(volatile u16 __iomem *port, const u16 *buf,
+ unsigned int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ rom_out_be16(port, *buf++);
+}
+
+static inline void raw_rom_insw_swapw(volatile u16 __iomem *port, u16 *buf,
+ unsigned int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ *buf++ = rom_in_le16(port);
+}
+
+static inline void raw_rom_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
+ unsigned int nr)
+{
+ unsigned int i;
+
+ for (i = 0; i < nr; i++)
+ rom_out_le16(port, *buf++);
+}
+#endif /* CONFIG_ATARI_ROM_ISA */
+
#endif /* __KERNEL__ */
#endif /* _RAW_IO_H */
diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h
index 32198454da70..9aea9f11fa25 100644
--- a/arch/m68k/include/asm/string.h
+++ b/arch/m68k/include/asm/string.h
@@ -4,15 +4,6 @@
#include <linux/types.h>
#include <linux/compiler.h>
-static inline size_t __kernel_strlen(const char *s)
-{
- const char *sc;
-
- for (sc = s; *sc++; )
- ;
- return sc - s - 1;
-}
-
static inline char *__kernel_strcpy(char *dest, const char *src)
{
char *xdest = dest;
@@ -27,11 +18,6 @@ static inline char *__kernel_strcpy(char *dest, const char *src)
#ifndef __IN_STRING_C
-#define __HAVE_ARCH_STRLEN
-#define strlen(s) (__builtin_constant_p(s) ? \
- __builtin_strlen(s) : \
- __kernel_strlen(s))
-
#define __HAVE_ARCH_STRNLEN
static inline size_t strnlen(const char *s, size_t count)
{
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 6cd92671ca5e..014f288fc813 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -32,12 +32,4 @@
#define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _ASM_M68K_UNISTD_H_ */
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index d538694ad208..c55ff719fa72 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -51,40 +51,16 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
return sw->retpc;
}
-/*
- * The idle loop on an m68k..
- */
-static void default_idle(void)
+void arch_cpu_idle(void)
{
- if (!need_resched())
#if defined(MACH_ATARI_ONLY)
- /* block out HSYNC on the atari (falcon) */
- __asm__("stop #0x2200" : : : "cc");
+ /* block out HSYNC on the atari (falcon) */
+ __asm__("stop #0x2200" : : : "cc");
#else
- __asm__("stop #0x2000" : : : "cc");
+ __asm__("stop #0x2000" : : : "cc");
#endif
}
-void (*idle)(void) = default_idle;
-
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- idle();
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
void machine_restart(char * __unused)
{
if (mach_reset)
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
index 80cfbe56ea32..e67e53159573 100644
--- a/arch/m68k/kernel/setup_mm.c
+++ b/arch/m68k/kernel/setup_mm.c
@@ -381,6 +381,12 @@ void __init setup_arch(char **cmdline_p)
isa_sex = 1;
}
#endif
+#ifdef CONFIG_ATARI_ROM_ISA
+ if (MACH_IS_ATARI) {
+ isa_type = ISA_TYPE_ENEC;
+ isa_sex = 0;
+ }
+#endif
#endif
}
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index f32ab22e7ed3..88fcd8c70e7b 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -992,18 +992,6 @@ void show_stack(struct task_struct *task, unsigned long *stack)
}
/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_trace(&stack);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-/*
* The vector number returned in the frame pointer may also contain
* the "fs" (Fault Status) bits on ColdFire. These are in the bottom
* 2 bits, and upper 2 bits. So we need to mask out the real vector
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
index b9a57abfad08..4d61fa8a112c 100644
--- a/arch/m68k/lib/string.c
+++ b/arch/m68k/lib/string.c
@@ -17,6 +17,6 @@ EXPORT_SYMBOL(strcpy);
char *strcat(char *dest, const char *src)
{
- return __kernel_strcpy(dest + __kernel_strlen(dest), src);
+ return __kernel_strcpy(dest + strlen(dest), src);
}
EXPORT_SYMBOL(strcat);
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 519aad8fa812..1af2ca3411f6 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -110,18 +110,7 @@ void __init paging_init(void)
void free_initmem(void)
{
#ifndef CONFIG_MMU_SUN3
- unsigned long addr;
-
- addr = (unsigned long) __init_begin;
- for (; addr < ((unsigned long) __init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- pr_notice("Freeing unused kernel memory: %luk freed (0x%x - 0x%x)\n",
- (addr - (unsigned long) __init_begin) >> 10,
- (unsigned int) __init_begin, (unsigned int) __init_end);
+ free_initmem_default(0);
#endif /* CONFIG_MMU_SUN3 */
}
@@ -213,15 +202,6 @@ void __init mem_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- pages++;
- }
- pr_notice("Freeing initrd memory: %dk freed\n",
- pages << (PAGE_SHIFT - 10));
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index afc8973d1488..b06b41861aac 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -25,6 +25,7 @@ config METAG
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_MOD_ARCH_SPECIFIC
+ select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HAVE_SYSCALL_TRACEPOINTS
select IRQ_DOMAIN
@@ -209,6 +210,9 @@ config METAG_PERFCOUNTER_IRQS
When disabled, Performance Counters information will be collected
based on Timer Interrupt.
+config HW_PERF_EVENTS
+ def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS
+
config METAG_DA
bool "DA support"
help
diff --git a/arch/metag/Makefile b/arch/metag/Makefile
index 81bd6a1c7483..b566116b171b 100644
--- a/arch/metag/Makefile
+++ b/arch/metag/Makefile
@@ -49,6 +49,8 @@ core-y += arch/metag/mm/
libs-y += arch/metag/lib/
libs-y += arch/metag/tbx/
+drivers-$(CONFIG_OPROFILE) += arch/metag/oprofile/
+
boot := arch/metag/boot
boot_targets += uImage
diff --git a/arch/metag/boot/dts/Makefile b/arch/metag/boot/dts/Makefile
index e0b5afd8bde8..dbd95217733a 100644
--- a/arch/metag/boot/dts/Makefile
+++ b/arch/metag/boot/dts/Makefile
@@ -4,13 +4,17 @@ dtb-y += skeleton.dtb
builtindtb-y := skeleton
ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"")
- builtindtb-y := $(CONFIG_METAG_BUILTIN_DTB_NAME)
+ builtindtb-y := $(patsubst "%",%,$(CONFIG_METAG_BUILTIN_DTB_NAME))
endif
-obj-$(CONFIG_METAG_BUILTIN_DTB) += $(patsubst "%",%,$(builtindtb-y)).dtb.o
+
+dtb-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb
+obj-$(CONFIG_METAG_BUILTIN_DTB) += $(builtindtb-y).dtb.o
targets += dtbs
targets += $(dtb-y)
+.SECONDARY: $(obj)/$(builtindtb-y).dtb.S
+
dtbs: $(addprefix $(obj)/, $(dtb-y))
-clean-files += *.dtb
+clean-files += *.dtb *.dtb.S
diff --git a/arch/metag/configs/meta1_defconfig b/arch/metag/configs/meta1_defconfig
index c35a75e8ecfe..01cd67e4403d 100644
--- a/arch/metag/configs/meta1_defconfig
+++ b/arch/metag/configs/meta1_defconfig
@@ -1,6 +1,5 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_defconfig b/arch/metag/configs/meta2_defconfig
index fb3148410183..643392ba7ed5 100644
--- a/arch/metag/configs/meta2_defconfig
+++ b/arch/metag/configs/meta2_defconfig
@@ -1,7 +1,6 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/configs/meta2_smp_defconfig b/arch/metag/configs/meta2_smp_defconfig
index 6c7b777ac276..f3306737da20 100644
--- a/arch/metag/configs/meta2_smp_defconfig
+++ b/arch/metag/configs/meta2_smp_defconfig
@@ -1,7 +1,6 @@
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=13
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_KALLSYMS_ALL=y
diff --git a/arch/metag/include/asm/metag_mem.h b/arch/metag/include/asm/metag_mem.h
index 3f7b54d8ccac..aa5a076df439 100644
--- a/arch/metag/include/asm/metag_mem.h
+++ b/arch/metag/include/asm/metag_mem.h
@@ -700,6 +700,9 @@
#define SYSC_xCPARTG_AND_S 8
#define SYSC_xCPARTL_OR_BITS 0x000F0000 /* Ors into top 4 bits */
#define SYSC_xCPARTL_OR_S 16
+#ifdef METAC_2_1
+#define SYSC_DCPART_GCON_BIT 0x00100000 /* Coherent shared local */
+#endif /* METAC_2_1 */
#define SYSC_xCPARTG_OR_BITS 0x0F000000 /* Ors into top 4 bits */
#define SYSC_xCPARTG_OR_S 24
#define SYSC_CWRMODE_BIT 0x80000000 /* Write cache mode bit */
diff --git a/arch/metag/include/asm/thread_info.h b/arch/metag/include/asm/thread_info.h
index 0ecd34d8b5f6..7c4a33006142 100644
--- a/arch/metag/include/asm/thread_info.h
+++ b/arch/metag/include/asm/thread_info.h
@@ -150,6 +150,4 @@ static inline int kstack_end(void *addr)
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/metag/include/uapi/asm/Kbuild b/arch/metag/include/uapi/asm/Kbuild
index 876c71f866de..84e09feb4d54 100644
--- a/arch/metag/include/uapi/asm/Kbuild
+++ b/arch/metag/include/uapi/asm/Kbuild
@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
header-y += byteorder.h
+header-y += ech.h
header-y += ptrace.h
header-y += resource.h
header-y += sigcontext.h
diff --git a/arch/metag/include/uapi/asm/ech.h b/arch/metag/include/uapi/asm/ech.h
new file mode 100644
index 000000000000..ac94d1cf9be4
--- /dev/null
+++ b/arch/metag/include/uapi/asm/ech.h
@@ -0,0 +1,15 @@
+#ifndef _UAPI_METAG_ECH_H
+#define _UAPI_METAG_ECH_H
+
+/*
+ * These bits can be set in the top half of the D0.8 register when DSP context
+ * switching is enabled, in order to support partial DSP context save/restore.
+ */
+
+#define TBICTX_XEXT_BIT 0x1000 /* Enable extended context save */
+#define TBICTX_XTDP_BIT 0x0800 /* DSP accumulators/RAM/templates */
+#define TBICTX_XHL2_BIT 0x0400 /* Hardware loops */
+#define TBICTX_XAXX_BIT 0x0200 /* Extended AX registers (A*.4-7) */
+#define TBICTX_XDX8_BIT 0x0100 /* Extended DX registers (D*.8-15) */
+
+#endif /* _UAPI_METAG_ECH_H */
diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index 3a589dfb966b..954548b1bea8 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -24,15 +24,21 @@
unsigned int get_dcache_size(void)
{
unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
- return 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
- >> METAC_CORECFG2_DCSZ_S);
+ unsigned int sz = 0x1000 << ((config2 & METAC_CORECFG2_DCSZ_BITS)
+ >> METAC_CORECFG2_DCSZ_S);
+ if (config2 & METAC_CORECFG2_DCSMALL_BIT)
+ sz >>= 6;
+ return sz;
}
unsigned int get_icache_size(void)
{
unsigned int config2 = metag_in32(METAC_CORE_CONFIG2);
- return 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
- >> METAC_CORE_C2ICSZ_S);
+ unsigned int sz = 0x1000 << ((config2 & METAC_CORE_C2ICSZ_BITS)
+ >> METAC_CORE_C2ICSZ_S);
+ if (config2 & METAC_CORECFG2_ICSMALL_BIT)
+ sz >>= 6;
+ return sz;
}
unsigned int get_global_dcache_size(void)
@@ -61,7 +67,7 @@ static unsigned int get_thread_cache_size(unsigned int cache, int thread_id)
return 0;
#if PAGE_OFFSET >= LINGLOBAL_BASE
/* Checking for global cache */
- cache_size = (cache == DCACHE ? get_global_dache_size() :
+ cache_size = (cache == DCACHE ? get_global_dcache_size() :
get_global_icache_size());
offset = 8;
#else
diff --git a/arch/metag/kernel/da.c b/arch/metag/kernel/da.c
index 52aabb658fde..a35dbed6fffa 100644
--- a/arch/metag/kernel/da.c
+++ b/arch/metag/kernel/da.c
@@ -5,12 +5,14 @@
*/
+#include <linux/export.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <asm/da.h>
#include <asm/metag_mem.h>
bool _metag_da_present;
+EXPORT_SYMBOL_GPL(_metag_da_present);
int __init metag_da_probe(void)
{
diff --git a/arch/metag/kernel/head.S b/arch/metag/kernel/head.S
index 969dffabc03a..713f71d1bdfe 100644
--- a/arch/metag/kernel/head.S
+++ b/arch/metag/kernel/head.S
@@ -1,6 +1,7 @@
! Copyright 2005,2006,2007,2009 Imagination Technologies
#include <linux/init.h>
+#include <asm/metag_mem.h>
#include <generated/asm-offsets.h>
#undef __exit
@@ -48,6 +49,13 @@ __exit:
.global _secondary_startup
.type _secondary_startup,function
_secondary_startup:
+#if CONFIG_PAGE_OFFSET < LINGLOBAL_BASE
+ ! In case GCOn has just been turned on we need to fence any writes that
+ ! the boot thread might have performed prior to coherency taking effect.
+ MOVT D0Re0,#HI(LINSYSEVENT_WR_ATOMIC_UNLOCK)
+ MOV D1Re0,#0
+ SETD [D0Re0], D1Re0
+#endif
MOVT A0StP,#HI(_secondary_data_stack)
ADD A0StP,A0StP,#LO(_secondary_data_stack)
GETD A0StP,[A0StP]
diff --git a/arch/metag/kernel/perf/perf_event.c b/arch/metag/kernel/perf/perf_event.c
index a876d5ff3897..366569425c52 100644
--- a/arch/metag/kernel/perf/perf_event.c
+++ b/arch/metag/kernel/perf/perf_event.c
@@ -22,9 +22,9 @@
#include <linux/slab.h>
#include <asm/core_reg.h>
-#include <asm/hwthread.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/processor.h>
#include "perf_event.h"
@@ -40,10 +40,10 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
/* PMU admin */
const char *perf_pmu_name(void)
{
- if (metag_pmu)
- return metag_pmu->pmu.name;
+ if (!metag_pmu)
+ return NULL;
- return NULL;
+ return metag_pmu->name;
}
EXPORT_SYMBOL_GPL(perf_pmu_name);
@@ -171,6 +171,7 @@ static int metag_pmu_event_init(struct perf_event *event)
switch (event->attr.type) {
case PERF_TYPE_HARDWARE:
case PERF_TYPE_HW_CACHE:
+ case PERF_TYPE_RAW:
err = _hw_perf_event_init(event);
break;
@@ -211,9 +212,10 @@ again:
/*
* Calculate the delta and add it to the counter.
*/
- delta = new_raw_count - prev_raw_count;
+ delta = (new_raw_count - prev_raw_count) & MAX_PERIOD;
local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
}
int metag_pmu_event_set_period(struct perf_event *event,
@@ -223,6 +225,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
s64 period = hwc->sample_period;
int ret = 0;
+ /* The period may have been changed */
+ if (unlikely(period != hwc->last_period))
+ left += period - hwc->last_period;
+
if (unlikely(left <= -period)) {
left = period;
local64_set(&hwc->period_left, left);
@@ -240,8 +246,10 @@ int metag_pmu_event_set_period(struct perf_event *event,
if (left > (s64)metag_pmu->max_period)
left = metag_pmu->max_period;
- if (metag_pmu->write)
- metag_pmu->write(idx, (u64)(-left) & MAX_PERIOD);
+ if (metag_pmu->write) {
+ local64_set(&hwc->prev_count, -(s32)left);
+ metag_pmu->write(idx, -left & MAX_PERIOD);
+ }
perf_event_update_userpage(event);
@@ -549,6 +557,10 @@ static int _hw_perf_event_init(struct perf_event *event)
if (err)
return err;
break;
+
+ case PERF_TYPE_RAW:
+ mapping = attr->config;
+ break;
}
/* Return early if the event is unsupported */
@@ -610,15 +622,13 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
WARN_ONCE((config != 0x100),
"invalid configuration (%d) for counter (%d)\n",
config, idx);
-
- /* Reset the cycle count */
- __core_reg_set(TXTACTCYC, 0);
+ local64_set(&event->prev_count, __core_reg_get(TXTACTCYC));
goto unlock;
}
/* Check for a core internal or performance channel event. */
if (tmp) {
- void *perf_addr = (void *)PERF_COUNT(idx);
+ void *perf_addr;
/*
* Anything other than a cycle count will write the low-
@@ -632,9 +642,14 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
case 0xf0:
perf_addr = (void *)PERF_CHAN(idx);
break;
+
+ default:
+ perf_addr = NULL;
+ break;
}
- metag_out32((tmp & 0x0f), perf_addr);
+ if (perf_addr)
+ metag_out32((config & 0x0f), perf_addr);
/*
* Now we use the high nibble as the performance event to
@@ -643,13 +658,21 @@ static void metag_pmu_enable_counter(struct hw_perf_event *event, int idx)
config = tmp >> 4;
}
- /*
- * Enabled counters start from 0. Early cores clear the count on
- * write but newer cores don't, so we make sure that the count is
- * set to 0.
- */
tmp = ((config & 0xf) << 28) |
- ((1 << 24) << cpu_2_hwthread_id[get_cpu()]);
+ ((1 << 24) << hard_processor_id());
+ if (metag_pmu->max_period)
+ /*
+ * Cores supporting overflow interrupts may have had the counter
+ * set to a specific value that needs preserving.
+ */
+ tmp |= metag_in32(PERF_COUNT(idx)) & 0x00ffffff;
+ else
+ /*
+ * Older cores reset the counter on write, so prev_count needs
+ * resetting too so we can calculate a correct delta.
+ */
+ local64_set(&event->prev_count, 0);
+
metag_out32(tmp, PERF_COUNT(idx));
unlock:
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
@@ -693,9 +716,8 @@ static u64 metag_pmu_read_counter(int idx)
{
u32 tmp = 0;
- /* The act of reading the cycle counter also clears it */
if (METAG_INST_COUNTER == idx) {
- __core_reg_swap(TXTACTCYC, tmp);
+ tmp = __core_reg_get(TXTACTCYC);
goto out;
}
@@ -764,10 +786,16 @@ static irqreturn_t metag_pmu_counter_overflow(int irq, void *dev)
/*
* Enable the counter again once core overflow processing has
- * completed.
+ * completed. Note the counter value may have been modified while it was
+ * inactive to set it up ready for the next interrupt.
*/
- if (!perf_event_overflow(event, &sampledata, regs))
+ if (!perf_event_overflow(event, &sampledata, regs)) {
+ __global_lock2(flags);
+ counter = (counter & 0xff000000) |
+ (metag_in32(PERF_COUNT(idx)) & 0x00ffffff);
metag_out32(counter, PERF_COUNT(idx));
+ __global_unlock2(flags);
+ }
return IRQ_HANDLED;
}
@@ -830,7 +858,7 @@ static int __init init_hw_perf_events(void)
metag_pmu->max_period = 0;
}
- metag_pmu->name = "Meta 2";
+ metag_pmu->name = "meta2";
metag_pmu->version = version;
metag_pmu->pmu = pmu;
}
diff --git a/arch/metag/kernel/process.c b/arch/metag/kernel/process.c
index c6efe62e5b76..483dff986a23 100644
--- a/arch/metag/kernel/process.c
+++ b/arch/metag/kernel/process.c
@@ -22,6 +22,7 @@
#include <linux/pm.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
+#include <linux/smp.h>
#include <asm/core_reg.h>
#include <asm/user_gateway.h>
#include <asm/tcm.h>
@@ -31,7 +32,7 @@
/*
* Wait for the next interrupt and enable local interrupts
*/
-static inline void arch_idle(void)
+void arch_cpu_idle(void)
{
int tmp;
@@ -59,36 +60,12 @@ static inline void arch_idle(void)
: "r" (get_trigger_mask()));
}
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched()) {
- /*
- * We need to disable interrupts here to ensure we don't
- * miss a wakeup call.
- */
- local_irq_disable();
- if (!need_resched()) {
#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
-#endif
- arch_idle();
- } else {
- local_irq_enable();
- }
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
}
+#endif
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
@@ -152,6 +129,8 @@ void show_regs(struct pt_regs *regs)
"D1.7 "
};
+ show_regs_print_info(KERN_INFO);
+
pr_info(" pt_regs @ %p\n", regs);
pr_info(" SaveMask = 0x%04hx\n", regs->ctx.SaveMask);
pr_info(" Flags = 0x%04hx (%c%c%c%c)\n", regs->ctx.Flags,
diff --git a/arch/metag/kernel/ptrace.c b/arch/metag/kernel/ptrace.c
index 47a8828615a5..7563628822bd 100644
--- a/arch/metag/kernel/ptrace.c
+++ b/arch/metag/kernel/ptrace.c
@@ -288,10 +288,36 @@ static int metag_rp_state_set(struct task_struct *target,
return metag_rp_state_copyin(regs, pos, count, kbuf, ubuf);
}
+static int metag_tls_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ void __user *tls = target->thread.tls_ptr;
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+}
+
+static int metag_tls_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ void __user *tls;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+ if (ret)
+ return ret;
+
+ target->thread.tls_ptr = tls;
+ return ret;
+}
+
enum metag_regset {
REGSET_GENERAL,
REGSET_CBUF,
REGSET_READPIPE,
+ REGSET_TLS,
};
static const struct user_regset metag_regsets[] = {
@@ -319,6 +345,14 @@ static const struct user_regset metag_regsets[] = {
.get = metag_rp_state_get,
.set = metag_rp_state_set,
},
+ [REGSET_TLS] = {
+ .core_note_type = NT_METAG_TLS,
+ .n = 1,
+ .size = sizeof(void *),
+ .align = sizeof(void *),
+ .get = metag_tls_get,
+ .set = metag_tls_set,
+ },
};
static const struct user_regset_view user_metag_view = {
diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c
index 879246170aec..4f5726f1a55b 100644
--- a/arch/metag/kernel/setup.c
+++ b/arch/metag/kernel/setup.c
@@ -124,6 +124,7 @@ struct machine_desc *machine_desc __initdata;
u8 cpu_2_hwthread_id[NR_CPUS] __read_mostly = {
[0 ... NR_CPUS-1] = BAD_HWTHREAD_ID
};
+EXPORT_SYMBOL_GPL(cpu_2_hwthread_id);
/*
* Map a hardware thread ID to a Linux CPU number
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index 4b6d1f14df32..f443ec9a7cbe 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -28,6 +28,8 @@
#include <asm/cachepart.h>
#include <asm/core_reg.h>
#include <asm/cpu.h>
+#include <asm/global_lock.h>
+#include <asm/metag_mem.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -37,6 +39,9 @@
#include <asm/hwthread.h>
#include <asm/traps.h>
+#define SYSC_DCPART(n) (SYSC_DCPART0 + SYSC_xCPARTn_STRIDE * (n))
+#define SYSC_ICPART(n) (SYSC_ICPART0 + SYSC_xCPARTn_STRIDE * (n))
+
DECLARE_PER_CPU(PTBI, pTBI);
void *secondary_data_stack;
@@ -99,6 +104,114 @@ int __cpuinit boot_secondary(unsigned int thread, struct task_struct *idle)
return 0;
}
+/**
+ * describe_cachepart_change: describe a change to cache partitions.
+ * @thread: Hardware thread number.
+ * @label: Label of cache type, e.g. "dcache" or "icache".
+ * @sz: Total size of the cache.
+ * @old: Old cache partition configuration (*CPART* register).
+ * @new: New cache partition configuration (*CPART* register).
+ *
+ * If the cache partition has changed, prints a message to the log describing
+ * those changes.
+ */
+static __cpuinit void describe_cachepart_change(unsigned int thread,
+ const char *label,
+ unsigned int sz,
+ unsigned int old,
+ unsigned int new)
+{
+ unsigned int lor1, land1, gor1, gand1;
+ unsigned int lor2, land2, gor2, gand2;
+ unsigned int diff = old ^ new;
+
+ if (!diff)
+ return;
+
+ pr_info("Thread %d: %s partition changed:", thread, label);
+ if (diff & (SYSC_xCPARTL_OR_BITS | SYSC_xCPARTL_AND_BITS)) {
+ lor1 = (old & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
+ lor2 = (new & SYSC_xCPARTL_OR_BITS) >> SYSC_xCPARTL_OR_S;
+ land1 = (old & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+ land2 = (new & SYSC_xCPARTL_AND_BITS) >> SYSC_xCPARTL_AND_S;
+ pr_cont(" L:%#x+%#x->%#x+%#x",
+ (lor1 * sz) >> 4,
+ ((land1 + 1) * sz) >> 4,
+ (lor2 * sz) >> 4,
+ ((land2 + 1) * sz) >> 4);
+ }
+ if (diff & (SYSC_xCPARTG_OR_BITS | SYSC_xCPARTG_AND_BITS)) {
+ gor1 = (old & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
+ gor2 = (new & SYSC_xCPARTG_OR_BITS) >> SYSC_xCPARTG_OR_S;
+ gand1 = (old & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+ gand2 = (new & SYSC_xCPARTG_AND_BITS) >> SYSC_xCPARTG_AND_S;
+ pr_cont(" G:%#x+%#x->%#x+%#x",
+ (gor1 * sz) >> 4,
+ ((gand1 + 1) * sz) >> 4,
+ (gor2 * sz) >> 4,
+ ((gand2 + 1) * sz) >> 4);
+ }
+ if (diff & SYSC_CWRMODE_BIT)
+ pr_cont(" %sWR",
+ (new & SYSC_CWRMODE_BIT) ? "+" : "-");
+ if (diff & SYSC_DCPART_GCON_BIT)
+ pr_cont(" %sGCOn",
+ (new & SYSC_DCPART_GCON_BIT) ? "+" : "-");
+ pr_cont("\n");
+}
+
+/**
+ * setup_smp_cache: ensure cache coherency for new SMP thread.
+ * @thread: New hardware thread number.
+ *
+ * Ensures that coherency is enabled and that the threads share the same cache
+ * partitions.
+ */
+static __cpuinit void setup_smp_cache(unsigned int thread)
+{
+ unsigned int this_thread, lflags;
+ unsigned int dcsz, dcpart_this, dcpart_old, dcpart_new;
+ unsigned int icsz, icpart_old, icpart_new;
+
+ /*
+ * Copy over the current thread's cache partition configuration to the
+ * new thread so that they share cache partitions.
+ */
+ __global_lock2(lflags);
+ this_thread = hard_processor_id();
+ /* Share dcache partition */
+ dcpart_this = metag_in32(SYSC_DCPART(this_thread));
+ dcpart_old = metag_in32(SYSC_DCPART(thread));
+ dcpart_new = dcpart_this;
+#if PAGE_OFFSET < LINGLOBAL_BASE
+ /*
+ * For the local data cache to be coherent the threads must also have
+ * GCOn enabled.
+ */
+ dcpart_new |= SYSC_DCPART_GCON_BIT;
+ metag_out32(dcpart_new, SYSC_DCPART(this_thread));
+#endif
+ metag_out32(dcpart_new, SYSC_DCPART(thread));
+ /* Share icache partition too */
+ icpart_new = metag_in32(SYSC_ICPART(this_thread));
+ icpart_old = metag_in32(SYSC_ICPART(thread));
+ metag_out32(icpart_new, SYSC_ICPART(thread));
+ __global_unlock2(lflags);
+
+ /*
+ * Log if the cache partitions were altered so the user is aware of any
+ * potential unintentional cache wastage.
+ */
+ dcsz = get_dcache_size();
+ icsz = get_dcache_size();
+ describe_cachepart_change(this_thread, "dcache", dcsz,
+ dcpart_this, dcpart_new);
+ describe_cachepart_change(thread, "dcache", dcsz,
+ dcpart_old, dcpart_new);
+ describe_cachepart_change(thread, "icache", icsz,
+ icpart_old, icpart_new);
+}
+
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
{
unsigned int thread = cpu_2_hwthread_id[cpu];
@@ -108,6 +221,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
flush_tlb_all();
+ setup_smp_cache(thread);
+
/*
* Tell the secondary CPU where to find its idle thread's stack.
*/
@@ -297,7 +412,7 @@ asmlinkage void secondary_start_kernel(void)
/*
* OK, it's off to the idle thread for us
*/
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_cpus_done(unsigned int max_cpus)
diff --git a/arch/metag/kernel/traps.c b/arch/metag/kernel/traps.c
index 8961f247b500..2ceeaae5b199 100644
--- a/arch/metag/kernel/traps.c
+++ b/arch/metag/kernel/traps.c
@@ -987,9 +987,3 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
show_trace(tsk, sp, NULL);
}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/metag/mm/Kconfig b/arch/metag/mm/Kconfig
index 975f2f4e3ecf..794f26a187f9 100644
--- a/arch/metag/mm/Kconfig
+++ b/arch/metag/mm/Kconfig
@@ -98,9 +98,6 @@ config MAX_ACTIVE_REGIONS
default "2" if SPARSEMEM
default "1"
-config ARCH_POPULATES_NODE_MAP
- def_bool y
-
config ARCH_SELECT_MEMORY_MODEL
def_bool y
diff --git a/arch/metag/mm/init.c b/arch/metag/mm/init.c
index 504a398d5f8b..d05b8455c44c 100644
--- a/arch/metag/mm/init.c
+++ b/arch/metag/mm/init.c
@@ -380,14 +380,8 @@ void __init mem_init(void)
#ifdef CONFIG_HIGHMEM
unsigned long tmp;
- for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
- struct page *page = pfn_to_page(tmp);
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
- }
- totalram_pages += totalhigh_pages;
+ for (tmp = highstart_pfn; tmp < highend_pfn; tmp++)
+ free_highmem_page(pfn_to_page(tmp));
num_physpages += totalhigh_pages;
#endif /* CONFIG_HIGHMEM */
@@ -412,32 +406,15 @@ void __init mem_init(void)
return;
}
-static void free_init_pages(char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
-
- for (addr = begin; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
- }
- pr_info("Freeing %s: %luk freed\n", what, (end - begin) >> 10);
-}
-
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)(&__init_begin),
- (unsigned long)(&__init_end));
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- end = end & PAGE_MASK;
- free_init_pages("initrd memory", start, end);
+ free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
}
#endif
diff --git a/arch/metag/oprofile/Makefile b/arch/metag/oprofile/Makefile
new file mode 100644
index 000000000000..c9639d4734d6
--- /dev/null
+++ b/arch/metag/oprofile/Makefile
@@ -0,0 +1,17 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+oprofile-core-y += buffer_sync.o
+oprofile-core-y += cpu_buffer.o
+oprofile-core-y += event_buffer.o
+oprofile-core-y += oprof.o
+oprofile-core-y += oprofile_files.o
+oprofile-core-y += oprofile_stats.o
+oprofile-core-y += oprofilefs.o
+oprofile-core-y += timer_int.o
+oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o
+
+oprofile-y += backtrace.o
+oprofile-y += common.o
+oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y))
+
+ccflags-y += -Werror
diff --git a/arch/metag/oprofile/backtrace.c b/arch/metag/oprofile/backtrace.c
new file mode 100644
index 000000000000..7cc3f37cb40e
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010-2013 Imagination Technologies Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/stacktrace.h>
+
+#include "backtrace.h"
+
+static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth)
+{
+ while (depth-- && access_ok(VERIFY_READ, fp, 8)) {
+ unsigned long addr;
+ unsigned long __user *fpnew;
+ if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr)))
+ break;
+ addr -= 4;
+
+ oprofile_add_trace(addr);
+
+ /* stack grows up, so frame pointers must decrease */
+ if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew)))
+ break;
+ if (fpnew >= fp)
+ break;
+ fp = fpnew;
+ }
+}
+
+static int kernel_backtrace_frame(struct stackframe *frame, void *data)
+{
+ unsigned int *depth = data;
+
+ oprofile_add_trace(frame->pc);
+
+ /* decrement depth and stop if we reach 0 */
+ if ((*depth)-- == 0)
+ return 1;
+
+ /* otherwise onto the next frame */
+ return 0;
+}
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+ if (user_mode(regs)) {
+ unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0;
+ user_backtrace_fp((unsigned long __user __force *)fp, depth);
+ } else {
+ struct stackframe frame;
+ frame.fp = regs->ctx.AX[1].U0; /* A0FrP */
+ frame.sp = user_stack_pointer(regs); /* A0StP */
+ frame.lr = 0; /* from stack */
+ frame.pc = regs->ctx.CurrPC; /* PC */
+ walk_stackframe(&frame, &kernel_backtrace_frame, &depth);
+ }
+}
diff --git a/arch/metag/oprofile/backtrace.h b/arch/metag/oprofile/backtrace.h
new file mode 100644
index 000000000000..c0fcc4265abb
--- /dev/null
+++ b/arch/metag/oprofile/backtrace.h
@@ -0,0 +1,6 @@
+#ifndef _METAG_OPROFILE_BACKTRACE_H
+#define _METAG_OPROFILE_BACKTRACE_H
+
+void metag_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+#endif
diff --git a/arch/metag/oprofile/common.c b/arch/metag/oprofile/common.c
new file mode 100644
index 000000000000..ba26152b3c00
--- /dev/null
+++ b/arch/metag/oprofile/common.c
@@ -0,0 +1,66 @@
+/*
+ * arch/metag/oprofile/common.c
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * Based on arch/sh/oprofile/common.c:
+ *
+ * Copyright (C) 2003 - 2010 Paul Mundt
+ *
+ * Based on arch/mips/oprofile/common.c:
+ *
+ * Copyright (C) 2004, 2005 Ralf Baechle
+ * Copyright (C) 2005 MIPS Technologies, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/oprofile.h>
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
+#include "backtrace.h"
+
+#ifdef CONFIG_HW_PERF_EVENTS
+/*
+ * This will need to be reworked when multiple PMUs are supported.
+ */
+static char *metag_pmu_op_name;
+
+char *op_name_from_perf_id(void)
+{
+ return metag_pmu_op_name;
+}
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+ ops->backtrace = metag_backtrace;
+
+ if (perf_num_counters() == 0)
+ return -ENODEV;
+
+ metag_pmu_op_name = kasprintf(GFP_KERNEL, "metag/%s",
+ perf_pmu_name());
+ if (unlikely(!metag_pmu_op_name))
+ return -ENOMEM;
+
+ return oprofile_perf_init(ops);
+}
+
+void oprofile_arch_exit(void)
+{
+ oprofile_perf_exit();
+ kfree(metag_pmu_op_name);
+}
+#else
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+ ops->backtrace = metag_backtrace;
+ /* fall back to timer interrupt PC sampling */
+ return -ENODEV;
+}
+void oprofile_arch_exit(void) {}
+#endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 1323fa2530eb..54237af0b07c 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -26,6 +26,7 @@ config MICROBLAZE
select GENERIC_CPU_DEVICES
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
+ select GENERIC_IDLE_POLL_SETUP
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS
@@ -38,9 +39,6 @@ config RWSEM_GENERIC_SPINLOCK
config ZONE_DMA
def_bool y
-config ARCH_POPULATES_NODE_MAP
- def_bool y
-
config RWSEM_XCHGADD_ALGORITHM
bool
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index 0759153e8117..d6e0ffea28b6 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -22,7 +22,6 @@
extern const struct seq_operations cpuinfo_op;
# define cpu_relax() barrier()
-# define cpu_sleep() do {} while (0)
#define task_pt_regs(tsk) \
(((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
@@ -160,10 +159,6 @@ unsigned long get_wchan(struct task_struct *p);
# define STACK_TOP TASK_SIZE
# define STACK_TOP_MAX STACK_TOP
-void disable_hlt(void);
-void enable_hlt(void);
-void default_idle(void);
-
#ifdef CONFIG_DEBUG_FS
extern struct dentry *of_debugfs_root;
#endif
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index 0e0b0a5ec756..f05df5630c84 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/arch/microblaze/include/asm/setup.h
@@ -46,7 +46,6 @@ void machine_shutdown(void);
void machine_halt(void);
void machine_power_off(void);
-void free_init_pages(char *what, unsigned long begin, unsigned long end);
extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
diff --git a/arch/microblaze/include/asm/thread_info.h b/arch/microblaze/include/asm/thread_info.h
index 008f30433d22..de26ea6373de 100644
--- a/arch/microblaze/include/asm/thread_info.h
+++ b/arch/microblaze/include/asm/thread_info.h
@@ -182,7 +182,6 @@ static inline bool test_and_clear_restore_sigmask(void)
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
#endif
#endif /* __KERNEL__ */
diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h
index b3778391d9cc..6dece2d002dc 100644
--- a/arch/microblaze/include/asm/unistd.h
+++ b/arch/microblaze/include/asm/unistd.h
@@ -37,13 +37,5 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_FORK
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
-
#endif /* __ASSEMBLY__ */
#endif /* _ASM_MICROBLAZE_UNISTD_H */
diff --git a/arch/microblaze/kernel/early_printk.c b/arch/microblaze/kernel/early_printk.c
index 60dcacc68038..365f2d53f1b2 100644
--- a/arch/microblaze/kernel/early_printk.c
+++ b/arch/microblaze/kernel/early_printk.c
@@ -21,7 +21,6 @@
#include <asm/setup.h>
#include <asm/prom.h>
-static u32 early_console_initialized;
static u32 base_addr;
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
@@ -109,27 +108,11 @@ static struct console early_serial_uart16550_console = {
};
#endif /* CONFIG_SERIAL_8250_CONSOLE */
-static struct console *early_console;
-
-void early_printk(const char *fmt, ...)
-{
- char buf[512];
- int n;
- va_list ap;
-
- if (early_console_initialized) {
- va_start(ap, fmt);
- n = vscnprintf(buf, 512, fmt, ap);
- early_console->write(early_console, buf, n);
- va_end(ap);
- }
-}
-
int __init setup_early_printk(char *opt)
{
int version = 0;
- if (early_console_initialized)
+ if (early_console)
return 1;
base_addr = of_early_console(&version);
@@ -159,7 +142,6 @@ int __init setup_early_printk(char *opt)
}
register_console(early_console);
- early_console_initialized = 1;
return 0;
}
return 1;
@@ -169,7 +151,7 @@ int __init setup_early_printk(char *opt)
* only for early console because of performance degression */
void __init remap_early_printk(void)
{
- if (!early_console_initialized || !early_console)
+ if (!early_console)
return;
pr_info("early_printk_console remapping from 0x%x to ", base_addr);
base_addr = (u32) ioremap(base_addr, PAGE_SIZE);
@@ -194,9 +176,9 @@ void __init remap_early_printk(void)
void __init disable_early_printk(void)
{
- if (!early_console_initialized || !early_console)
+ if (!early_console)
return;
pr_warn("disabling early console\n");
unregister_console(early_console);
- early_console_initialized = 0;
+ early_console = NULL;
}
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index fa0ea609137c..a55893807274 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -20,6 +20,8 @@
void show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_INFO);
+
pr_info(" Registers dump: mode=%X\r\n", regs->pt_mode);
pr_info(" r1=%08lX, r2=%08lX, r3=%08lX, r4=%08lX\n",
regs->r1, regs->r2, regs->r3, regs->r4);
@@ -44,71 +46,6 @@ void show_regs(struct pt_regs *regs)
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
-static int hlt_counter = 1;
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-EXPORT_SYMBOL(enable_hlt);
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-__setup("nohlt", nohlt_setup);
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-__setup("hlt", hlt_setup);
-
-void default_idle(void)
-{
- if (likely(hlt_counter)) {
- local_irq_disable();
- stop_critical_timings();
- cpu_relax();
- start_critical_timings();
- local_irq_enable();
- } else {
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb__after_clear_bit();
- local_irq_disable();
- while (!need_resched())
- cpu_sleep();
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
- }
-}
-
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched())
- default_idle();
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
- schedule_preempt_disabled();
- check_pgt_cache();
- }
-}
-
void flush_thread(void)
{
}
diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c
index 30e6b5004a6a..cb619533a192 100644
--- a/arch/microblaze/kernel/traps.c
+++ b/arch/microblaze/kernel/traps.c
@@ -75,9 +75,3 @@ void show_stack(struct task_struct *task, unsigned long *sp)
debug_show_held_locks(task);
}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 8f8b367c079e..4ec137d13ad7 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -82,13 +82,9 @@ static unsigned long highmem_setup(void)
/* FIXME not sure about */
if (memblock_is_reserved(pfn << PAGE_SHIFT))
continue;
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
+ free_highmem_page(page);
reservedpages++;
}
- totalram_pages += totalhigh_pages;
pr_info("High memory: %luk\n",
totalhigh_pages << (PAGE_SHIFT-10));
@@ -236,40 +232,16 @@ void __init setup_memory(void)
paging_init();
}
-void free_init_pages(char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
-
- for (addr = begin; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- pr_info("Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
-}
-
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- pages++;
- }
- pr_notice("Freeing initrd memory: %dk freed\n",
- (int)(pages * (PAGE_SIZE / 1024)));
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)(&__init_begin),
- (unsigned long)(&__init_end));
+ free_initmem_default(0);
}
void __init mem_init(void)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index cd2e21ff562a..e5f3794744f1 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -18,7 +18,7 @@ config MIPS
select HAVE_KRETPROBES
select HAVE_DEBUG_KMEMLEAK
select ARCH_BINFMT_ELF_RANDOMIZE_PIE
- select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+ select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
select RTC_LIB if !MACH_LOONGSON
select GENERIC_ATOMIC64 if !64BIT
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -404,6 +404,8 @@ config PMC_MSP
select IRQ_CPU
select SERIAL_8250
select SERIAL_8250_CONSOLE
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_DESC
help
This adds support for the PMC-Sierra family of Multi-Service
Processor System-On-A-Chips. These parts include a number
@@ -657,7 +659,7 @@ config SNI_RM
bool "SNI RM200/300/400"
select FW_ARC if CPU_LITTLE_ENDIAN
select FW_ARC32 if CPU_LITTLE_ENDIAN
- select SNIPROM if CPU_BIG_ENDIAN
+ select FW_SNIPROM if CPU_BIG_ENDIAN
select ARCH_MAY_HAVE_PC_FDC
select BOOT_ELF32
select CEVT_R4K
@@ -1144,7 +1146,7 @@ config DEFAULT_SGI_PARTITION
config FW_ARC32
bool
-config SNIPROM
+config FW_SNIPROM
bool
config BOOT_ELF32
@@ -1433,6 +1435,7 @@ config CPU_CAVIUM_OCTEON
select CPU_SUPPORTS_HUGEPAGES
select LIBFDT
select USE_OF
+ select USB_EHCI_BIG_ENDIAN_MMIO
help
The Cavium Octeon processor is a highly integrated chip containing
many ethernet hardware widgets for networking tasks. The processor
@@ -1493,7 +1496,6 @@ config CPU_XLP
select CPU_SUPPORTS_32BIT_KERNEL
select CPU_SUPPORTS_64BIT_KERNEL
select CPU_SUPPORTS_HIGHMEM
- select CPU_HAS_LLSC
select WEAK_ORDERING
select WEAK_REORDERING_BEYOND_LLSC
select CPU_HAS_PREFETCH
@@ -1737,7 +1739,6 @@ config 32BIT
config 64BIT
bool "64-bit kernel"
depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL
- select HAVE_SYSCALL_WRAPPERS
help
Select this option if you want to build a 64-bit kernel.
@@ -2539,7 +2540,14 @@ source "kernel/power/Kconfig"
endmenu
-source "arch/mips/kernel/cpufreq/Kconfig"
+config MIPS_EXTERNAL_TIMER
+ bool
+
+if CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
+menu "CPU Power Management"
+source "drivers/cpufreq/Kconfig"
+endmenu
+endif
source "net/Kconfig"
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index ed1949c29508..9aa7d44898ed 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -745,10 +745,7 @@ void __init board_prom_init(void)
strcpy(cfe_version, "unknown");
printk(KERN_INFO PFX "CFE version: %s\n", cfe_version);
- if (bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET)) {
- printk(KERN_ERR PFX "invalid nvram checksum\n");
- return;
- }
+ bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
board_name = bcm63xx_nvram_get_name();
/* find board by name */
diff --git a/arch/mips/bcm63xx/dev-spi.c b/arch/mips/bcm63xx/dev-spi.c
index f1c9c3e2f678..e97fd60e92ef 100644
--- a/arch/mips/bcm63xx/dev-spi.c
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -85,20 +85,9 @@ static struct platform_device bcm63xx_spi_device = {
int __init bcm63xx_spi_register(void)
{
- struct clk *periph_clk;
-
if (BCMCPU_IS_6328() || BCMCPU_IS_6345())
return -ENODEV;
- periph_clk = clk_get(NULL, "periph");
- if (IS_ERR(periph_clk)) {
- pr_err("unable to get periph clock\n");
- return -ENODEV;
- }
-
- /* Set bus frequency */
- spi_pdata.speed_hz = clk_get_rate(periph_clk);
-
spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
spi_resources[0].end = spi_resources[0].start;
spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
diff --git a/arch/mips/bcm63xx/nvram.c b/arch/mips/bcm63xx/nvram.c
index 620611680839..a4b8864f9307 100644
--- a/arch/mips/bcm63xx/nvram.c
+++ b/arch/mips/bcm63xx/nvram.c
@@ -38,7 +38,7 @@ struct bcm963xx_nvram {
static struct bcm963xx_nvram nvram;
static int mac_addr_used;
-int __init bcm63xx_nvram_init(void *addr)
+void __init bcm63xx_nvram_init(void *addr)
{
unsigned int check_len;
u32 crc, expected_crc;
@@ -60,9 +60,8 @@ int __init bcm63xx_nvram_init(void *addr)
crc = crc32_le(~0, (u8 *)&nvram, check_len);
if (crc != expected_crc)
- return -EINVAL;
-
- return 0;
+ pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
+ expected_crc, crc);
}
u8 *bcm63xx_nvram_get_name(void)
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c
index 314231be788c..35e18e98beb9 100644
--- a/arch/mips/bcm63xx/setup.c
+++ b/arch/mips/bcm63xx/setup.c
@@ -157,4 +157,4 @@ int __init bcm63xx_register_devices(void)
return board_register_devices();
}
-device_initcall(bcm63xx_register_devices);
+arch_initcall(bcm63xx_register_devices);
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index c594a3d4f743..b0baa299f899 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -174,7 +174,10 @@ static int octeon_kexec_prepare(struct kimage *image)
static void octeon_generic_shutdown(void)
{
- int cpu, i;
+ int i;
+#ifdef CONFIG_SMP
+ int cpu;
+#endif
struct cvmx_bootmem_desc *bootmem_desc;
void *named_block_array_ptr;
diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h
index ef99db994c2f..fe0d15d32660 100644
--- a/arch/mips/include/asm/hugetlb.h
+++ b/arch/mips/include/asm/hugetlb.h
@@ -10,6 +10,7 @@
#define __ASM_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h
index e9a940d1b0c6..2767dda9e309 100644
--- a/arch/mips/include/asm/linkage.h
+++ b/arch/mips/include/asm/linkage.h
@@ -6,5 +6,8 @@
#endif
#define __weak __attribute__((weak))
+#define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall")
+#define SYSCALL_ALIAS(alias, name) \
+ asm ( #alias " = " #name "\n\t.globl " #alias)
#endif
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
index c9bae1362606..b0184cf02575 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
@@ -13,7 +13,6 @@ struct bcm63xx_spi_pdata {
unsigned int msg_ctl_width;
int bus_num;
int num_chipselect;
- u32 speed_hz;
};
enum bcm63xx_regs_spi {
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
index 62d6a3b4d3b7..4e0b6bc1165e 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
@@ -9,10 +9,8 @@
*
* Initialized the local nvram copy from the target address and checks
* its checksum.
- *
- * Returns 0 on success.
*/
-int __init bcm63xx_nvram_init(void *nvram);
+void bcm63xx_nvram_init(void *nvram);
/**
* bcm63xx_nvram_get_name() - returns the board name according to nvram
diff --git a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h
index d9c828419037..193c0912d38e 100644
--- a/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h
@@ -28,11 +28,7 @@
/* #define cpu_has_prefetch ? */
#define cpu_has_mcheck 1
/* #define cpu_has_ejtag ? */
-#ifdef CONFIG_CPU_HAS_LLSC
#define cpu_has_llsc 1
-#else
-#define cpu_has_llsc 0
-#endif
/* #define cpu_has_vtag_icache ? */
/* #define cpu_has_dc_aliases ? */
/* #define cpu_has_ic_fills_f_dc ? */
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 12b70c25906a..0da44d422f5b 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -1166,7 +1166,10 @@ do { \
unsigned int __dspctl; \
\
__asm__ __volatile__( \
+ " .set push \n" \
+ " .set dsp \n" \
" rddsp %0, %x1 \n" \
+ " .set pop \n" \
: "=r" (__dspctl) \
: "i" (mask)); \
__dspctl; \
@@ -1175,30 +1178,198 @@ do { \
#define wrdsp(val, mask) \
do { \
__asm__ __volatile__( \
+ " .set push \n" \
+ " .set dsp \n" \
" wrdsp %0, %x1 \n" \
+ " .set pop \n" \
: \
: "r" (val), "i" (mask)); \
} while (0)
-#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;})
-#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;})
-#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;})
-#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;})
-
-#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;})
-#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;})
-#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;})
-#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;})
-
-#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x))
-#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x))
-#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x))
-#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x))
-
-#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x))
-#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x))
-#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x))
-#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x))
+#define mflo0() \
+({ \
+ long mflo0; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mflo %0, $ac0 \n" \
+ " .set pop \n" \
+ : "=r" (mflo0)); \
+ mflo0; \
+})
+
+#define mflo1() \
+({ \
+ long mflo1; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mflo %0, $ac1 \n" \
+ " .set pop \n" \
+ : "=r" (mflo1)); \
+ mflo1; \
+})
+
+#define mflo2() \
+({ \
+ long mflo2; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mflo %0, $ac2 \n" \
+ " .set pop \n" \
+ : "=r" (mflo2)); \
+ mflo2; \
+})
+
+#define mflo3() \
+({ \
+ long mflo3; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mflo %0, $ac3 \n" \
+ " .set pop \n" \
+ : "=r" (mflo3)); \
+ mflo3; \
+})
+
+#define mfhi0() \
+({ \
+ long mfhi0; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mfhi %0, $ac0 \n" \
+ " .set pop \n" \
+ : "=r" (mfhi0)); \
+ mfhi0; \
+})
+
+#define mfhi1() \
+({ \
+ long mfhi1; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mfhi %0, $ac1 \n" \
+ " .set pop \n" \
+ : "=r" (mfhi1)); \
+ mfhi1; \
+})
+
+#define mfhi2() \
+({ \
+ long mfhi2; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mfhi %0, $ac2 \n" \
+ " .set pop \n" \
+ : "=r" (mfhi2)); \
+ mfhi2; \
+})
+
+#define mfhi3() \
+({ \
+ long mfhi3; \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mfhi %0, $ac3 \n" \
+ " .set pop \n" \
+ : "=r" (mfhi3)); \
+ mfhi3; \
+})
+
+
+#define mtlo0(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mtlo %0, $ac0 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mtlo1(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mtlo %0, $ac1 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mtlo2(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mtlo %0, $ac2 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mtlo3(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mtlo %0, $ac3 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mthi0(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mthi %0, $ac0 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mthi1(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mthi %0, $ac1 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mthi2(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mthi %0, $ac2 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
+
+#define mthi3(x) \
+({ \
+ __asm__( \
+ " .set push \n" \
+ " .set dsp \n" \
+ " mthi %0, $ac3 \n" \
+ " .set pop \n" \
+ : \
+ : "r" (x)); \
+})
#else
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 99fc547af9d3..eab99e536b5c 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -31,7 +31,7 @@
#define PAGE_SHIFT 16
#endif
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE - 1))
+#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
#define HPAGE_SHIFT (PAGE_SHIFT + PAGE_SHIFT - 3)
diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h
index 197f6367c201..8efe5a9e2c3e 100644
--- a/arch/mips/include/asm/signal.h
+++ b/arch/mips/include/asm/signal.h
@@ -21,6 +21,6 @@
#include <asm/sigcontext.h>
#include <asm/siginfo.h>
-#define __ARCH_HAS_ODD_SIGACTION
+#define __ARCH_HAS_IRIX_SIGACTION
#endif /* _ASM_SIGNAL_H */
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 64f661e32879..63c9c886173a 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -63,12 +63,4 @@
#endif /* !__ASSEMBLY__ */
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall")
-
#endif /* _ASM_UNISTD_H */
diff --git a/arch/mips/include/uapi/asm/signal.h b/arch/mips/include/uapi/asm/signal.h
index d6b18b4d0f3a..addb9f556b71 100644
--- a/arch/mips/include/uapi/asm/signal.h
+++ b/arch/mips/include/uapi/asm/signal.h
@@ -72,6 +72,12 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */
*
* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
* Unix names RESETHAND and NODEFER respectively.
+ *
+ * SA_RESTORER used to be defined as 0x04000000 but only the O32 ABI ever
+ * supported its use and no libc was using it, so the entire sa-restorer
+ * functionality was removed with lmo commit 39bffc12c3580ab for 2.5.48
+ * retaining only the SA_RESTORER definition as a reminder to avoid
+ * accidental reuse of the mask bit.
*/
#define SA_ONSTACK 0x08000000
#define SA_RESETHAND 0x80000000
@@ -84,8 +90,6 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */
#define SA_NOMASK SA_NODEFER
#define SA_ONESHOT SA_RESETHAND
-#define SA_RESTORER 0x04000000 /* Only for o32 */
-
#define MINSIGSTKSZ 2048
#define SIGSTKSZ 8192
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 47132f44c955..3b211507be7f 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -90,4 +90,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index f81d98f6184c..520a908d45d6 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -92,37 +92,22 @@ CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/n
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
-obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
-
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
#
-# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe
-# to enable DSP assembler support here even if the MIPS Release 2 CPU we
-# are targetting does not support DSP because all code-paths making use of
-# it properly check that the running CPU *actually does* support these
-# instructions.
+# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
+# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
+# here because the compiler may use DSP ASE instructions (such as lwx) in
+# code paths where we cannot check that the CPU we are running on supports it.
+# Proper abstraction using HAVE_AS_DSP and macros is done in
+# arch/mips/include/asm/mipsregs.h.
#
ifeq ($(CONFIG_CPU_MIPSR2), y)
CFLAGS_DSP = -DHAVE_AS_DSP
-#
-# Check if assembler supports DSP ASE
-#
-ifeq ($(call cc-option-yn,-mdsp), y)
-CFLAGS_DSP += -mdsp
-endif
-
-#
-# Check if assembler supports DSP ASE Rev2
-#
-ifeq ($(call cc-option-yn,-mdspr2), y)
-CFLAGS_DSP += -mdspr2
-endif
-
CFLAGS_signal.o = $(CFLAGS_DSP)
CFLAGS_signal32.o = $(CFLAGS_DSP)
CFLAGS_process.o = $(CFLAGS_DSP)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 6bfccc227a95..5fe66a0c3224 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -580,6 +580,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->tlbsize = 48;
break;
case PRID_IMP_VR41XX:
+ set_isa(c, MIPS_CPU_ISA_III);
+ c->options = R4K_OPTS;
+ c->tlbsize = 32;
switch (c->processor_id & 0xf0) {
case PRID_REV_VR4111:
c->cputype = CPU_VR4111;
@@ -604,6 +607,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "NEC VR4131";
} else {
c->cputype = CPU_VR4133;
+ c->options |= MIPS_CPU_LLSC;
__cpu_name[cpu] = "NEC VR4133";
}
break;
@@ -613,9 +617,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "NEC Vr41xx";
break;
}
- set_isa(c, MIPS_CPU_ISA_III);
- c->options = R4K_OPTS;
- c->tlbsize = 32;
break;
case PRID_IMP_R4300:
c->cputype = CPU_R4300;
@@ -1226,10 +1227,8 @@ __cpuinit void cpu_probe(void)
if (c->options & MIPS_CPU_FPU) {
c->fpu_id = cpu_get_fpu_id();
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
+ if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+ MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
if (c->fpu_id & MIPS_FPIR_3D)
c->ases |= MIPS_ASE_MIPS3D;
}
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
deleted file mode 100644
index 58c601eee6fd..000000000000
--- a/arch/mips/kernel/cpufreq/Kconfig
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# CPU Frequency scaling
-#
-
-config MIPS_EXTERNAL_TIMER
- bool
-
-config MIPS_CPUFREQ
- bool
- default y
- depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
-
-if MIPS_CPUFREQ
-
-menu "CPU Frequency scaling"
-
-source "drivers/cpufreq/Kconfig"
-
-if CPU_FREQ
-
-comment "CPUFreq processor drivers"
-
-config LOONGSON2_CPUFREQ
- tristate "Loongson2 CPUFreq Driver"
- select CPU_FREQ_TABLE
- depends on MIPS_CPUFREQ
- help
- This option adds a CPUFreq driver for loongson processors which
- support software configurable cpu frequency.
-
- Loongson2F and it's successors support this feature.
-
- For details, take a look at <file:Documentation/cpu-freq/>.
-
- If in doubt, say N.
-
-endif # CPU_FREQ
-
-endmenu
-
-endif # MIPS_CPUFREQ
diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile
deleted file mode 100644
index 05a5715ee38c..000000000000
--- a/arch/mips/kernel/cpufreq/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the Linux/MIPS cpufreq.
-#
-
-obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 9e6440eaa455..505cb77d1280 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -7,7 +7,9 @@
* Copyright (C) 2007 MIPS Technologies, Inc.
* written by Ralf Baechle (ralf@linux-mips.org)
*/
+#include <linux/kernel.h>
#include <linux/console.h>
+#include <linux/printk.h>
#include <linux/init.h>
#include <asm/setup.h>
@@ -24,20 +26,18 @@ static void early_console_write(struct console *con, const char *s, unsigned n)
}
}
-static struct console early_console = {
+static struct console early_console_prom = {
.name = "early",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1
};
-static int early_console_initialized __initdata;
-
void __init setup_early_printk(void)
{
- if (early_console_initialized)
+ if (early_console)
return;
- early_console_initialized = 1;
+ early_console = &early_console_prom;
- register_console(&early_console);
+ register_console(&early_console_prom);
}
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 8eeee1c860c0..d1d576b765f5 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -119,99 +119,6 @@ SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
}
-#ifdef CONFIG_SYSVIPC
-
-SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
- unsigned long, ptr, unsigned long, fifth)
-{
- int version, err;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- err = sys_semtimedop(first, compat_ptr(ptr), second, NULL);
- break;
- case SEMTIMEDOP:
- err = compat_sys_semtimedop(first, compat_ptr(ptr), second,
- compat_ptr(fifth));
- break;
- case SEMGET:
- err = sys_semget(first, second, third);
- break;
- case SEMCTL:
- err = compat_sys_semctl(first, second, third, compat_ptr(ptr));
- break;
- case MSGSND:
- err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
- break;
- case MSGRCV:
- err = compat_sys_msgrcv(first, second, fifth, third,
- version, compat_ptr(ptr));
- break;
- case MSGGET:
- err = sys_msgget((key_t) first, second);
- break;
- case MSGCTL:
- err = compat_sys_msgctl(first, second, compat_ptr(ptr));
- break;
- case SHMAT:
- err = compat_sys_shmat(first, second, third, version,
- compat_ptr(ptr));
- break;
- case SHMDT:
- err = sys_shmdt(compat_ptr(ptr));
- break;
- case SHMGET:
- err = sys_shmget(first, (unsigned)second, third);
- break;
- case SHMCTL:
- err = compat_sys_shmctl(first, second, compat_ptr(ptr));
- break;
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-
-#else
-
-SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third,
- u32, ptr, u32, fifth)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSVIPC */
-
-#ifdef CONFIG_MIPS32_N32
-SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg)
-{
- /* compat_sys_semctl expects a pointer to union semun */
- u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
- if (put_user(arg, uptr))
- return -EFAULT;
- return compat_sys_semctl(semid, semnum, cmd, uptr);
-}
-
-SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz,
- int, msgflg)
-{
- return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
-}
-
-SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
- int, msgtyp, int, msgflg)
-{
- return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
- compat_ptr(msgp));
-}
-#endif
-
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
{
unsigned int p = personality & 0xffffffff;
@@ -226,26 +133,6 @@ SYSCALL_DEFINE1(32_personality, unsigned long, personality)
return ret;
}
-SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
- compat_off_t __user *, offset, s32, count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
-
- return ret;
-}
-
asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3,
size_t count)
{
@@ -279,12 +166,6 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2,
merge_64(len_a4, len_a5));
}
-asmlinkage long sys32_lookup_dcookie(u32 a0, u32 a1, char __user *buf,
- size_t len)
-{
- return sys_lookup_dcookie(merge_64(a0, a1), buf, len);
-}
-
SYSCALL_DEFINE6(32_fanotify_mark, int, fanotify_fd, unsigned int, flags,
u64, a3, u64, a4, int, dfd, const char __user *, pathname)
{
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
index 165867673357..33d067148e61 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -46,10 +46,9 @@
PTR_L a5, PT_R9(sp)
PTR_L a6, PT_R10(sp)
PTR_L a7, PT_R11(sp)
-#else
- PTR_ADDIU sp, PT_SIZE
#endif
-.endm
+ PTR_ADDIU sp, PT_SIZE
+ .endm
.macro RETURN_BACK
jr ra
@@ -68,7 +67,11 @@ NESTED(ftrace_caller, PT_SIZE, ra)
.globl _mcount
_mcount:
b ftrace_stub
- addiu sp,sp,8
+#ifdef CONFIG_32BIT
+ addiu sp,sp,8
+#else
+ nop
+#endif
/* When tracing is activated, it calls ftrace_caller+8 (aka here) */
lw t1, function_trace_stop
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 135c4aadccbe..7a54f74b7818 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -67,7 +67,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (cpu_has_mips_r) {
seq_printf(m, "isa\t\t\t:");
if (cpu_has_mips_1)
- seq_printf(m, "%s", "mips1");
+ seq_printf(m, "%s", " mips1");
if (cpu_has_mips_2)
seq_printf(m, "%s", " mips2");
if (cpu_has_mips_3)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 3be4405c2d14..cfc742d75b7f 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -41,44 +41,26 @@
#include <asm/inst.h>
#include <asm/stacktrace.h>
-/*
- * The idle thread. There's no useful work to be done, so just try to conserve
- * power and have a low exit latency (ie sit in a loop waiting for somebody to
- * say that they'd like to reschedule)
- */
-void __noreturn cpu_idle(void)
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
{
- int cpu;
-
- /* CPU is going idle. */
- cpu = smp_processor_id();
+ /* What the heck is this check doing ? */
+ if (!cpu_isset(smp_processor_id(), cpu_callin_map))
+ play_dead();
+}
+#endif
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched() && cpu_online(cpu)) {
+void arch_cpu_idle(void)
+{
#ifdef CONFIG_MIPS_MT_SMTC
- extern void smtc_idle_loop_hook(void);
+ extern void smtc_idle_loop_hook(void);
- smtc_idle_loop_hook();
+ smtc_idle_loop_hook();
#endif
-
- if (cpu_wait) {
- /* Don't trace irqs off for idle */
- stop_critical_timings();
- (*cpu_wait)();
- start_critical_timings();
- }
- }
-#ifdef CONFIG_HOTPLUG_CPU
- if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map))
- play_dead();
-#endif
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+ if (cpu_wait)
+ (*cpu_wait)();
+ else
+ local_irq_enable();
}
asmlinkage void ret_from_fork(void);
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 693d60b0855f..edcb6594e7b5 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -143,7 +143,7 @@ EXPORT(sysn32_call_table)
PTR compat_sys_setitimer
PTR sys_alarm
PTR sys_getpid
- PTR sys_32_sendfile
+ PTR compat_sys_sendfile
PTR sys_socket /* 6040 */
PTR sys_connect
PTR sys_accept
@@ -168,11 +168,11 @@ EXPORT(sysn32_call_table)
PTR sys_newuname
PTR sys_semget
PTR sys_semop
- PTR sys_n32_semctl
+ PTR compat_sys_semctl
PTR sys_shmdt /* 6065 */
PTR sys_msgget
- PTR sys_n32_msgsnd
- PTR sys_n32_msgrcv
+ PTR compat_sys_msgsnd
+ PTR compat_sys_msgrcv
PTR compat_sys_msgctl
PTR compat_sys_fcntl /* 6070 */
PTR sys_flock
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index af8887f779f1..103bfe570fe8 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -309,7 +309,7 @@ sys_call_table:
PTR compat_sys_wait4
PTR sys_swapoff /* 4115 */
PTR compat_sys_sysinfo
- PTR sys_32_ipc
+ PTR compat_sys_ipc
PTR sys_fsync
PTR sys32_sigreturn
PTR __sys_clone /* 4120 */
@@ -399,7 +399,7 @@ sys_call_table:
PTR sys_capget
PTR sys_capset /* 4205 */
PTR compat_sys_sigaltstack
- PTR sys_32_sendfile
+ PTR compat_sys_sendfile
PTR sys_ni_syscall
PTR sys_ni_syscall
PTR sys_mips_mmap2 /* 4210 */
@@ -439,7 +439,7 @@ sys_call_table:
PTR compat_sys_io_submit
PTR sys_io_cancel /* 4245 */
PTR sys_exit_group
- PTR sys32_lookup_dcookie
+ PTR compat_sys_lookup_dcookie
PTR sys_epoll_create
PTR sys_epoll_ctl
PTR sys_epoll_wait /* 4250 */
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 66bf4e22d9b9..aee04af213c5 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -139,7 +139,7 @@ asmlinkage __cpuinit void start_secondary(void)
WARN_ON_ONCE(!irqs_disabled());
mp_ops->smp_finish();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/*
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index a200b5bdbb87..25225515451f 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -206,19 +206,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_stacktrace(task, &regs);
}
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- struct pt_regs regs;
-
- prepare_frametrace(&regs);
- show_backtrace(current, &regs);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
static void show_code(unsigned int __user *pc)
{
long i;
@@ -244,7 +231,7 @@ static void __show_regs(const struct pt_regs *regs)
unsigned int cause = regs->cp0_cause;
int i;
- printk("Cpu %d\n", smp_processor_id());
+ show_regs_print_info(KERN_DEFAULT);
/*
* Saved main processor registers
@@ -1571,7 +1558,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
#ifdef CONFIG_64BIT
status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
#endif
- if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
+ if (current_cpu_data.isa_level & MIPS_CPU_ISA_IV)
status_set |= ST0_XX;
if (cpu_has_dsp)
status_set |= ST0_MX;
diff --git a/arch/mips/lib/bitops.c b/arch/mips/lib/bitops.c
index 81f1dcfdcab8..a64daee740ee 100644
--- a/arch/mips/lib/bitops.c
+++ b/arch/mips/lib/bitops.c
@@ -90,12 +90,12 @@ int __mips_test_and_set_bit(unsigned long nr,
unsigned bit = nr & SZLONG_MASK;
unsigned long mask;
unsigned long flags;
- unsigned long res;
+ int res;
a += nr >> SZLONG_LOG;
mask = 1UL << bit;
raw_local_irq_save(flags);
- res = (mask & *a);
+ res = (mask & *a) != 0;
*a |= mask;
raw_local_irq_restore(flags);
return res;
@@ -116,12 +116,12 @@ int __mips_test_and_set_bit_lock(unsigned long nr,
unsigned bit = nr & SZLONG_MASK;
unsigned long mask;
unsigned long flags;
- unsigned long res;
+ int res;
a += nr >> SZLONG_LOG;
mask = 1UL << bit;
raw_local_irq_save(flags);
- res = (mask & *a);
+ res = (mask & *a) != 0;
*a |= mask;
raw_local_irq_restore(flags);
return res;
@@ -141,12 +141,12 @@ int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
unsigned bit = nr & SZLONG_MASK;
unsigned long mask;
unsigned long flags;
- unsigned long res;
+ int res;
a += nr >> SZLONG_LOG;
mask = 1UL << bit;
raw_local_irq_save(flags);
- res = (mask & *a);
+ res = (mask & *a) != 0;
*a &= ~mask;
raw_local_irq_restore(flags);
return res;
@@ -166,12 +166,12 @@ int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
unsigned bit = nr & SZLONG_MASK;
unsigned long mask;
unsigned long flags;
- unsigned long res;
+ int res;
a += nr >> SZLONG_LOG;
mask = 1UL << bit;
raw_local_irq_save(flags);
- res = (mask & *a);
+ res = (mask & *a) != 0;
*a ^= mask;
raw_local_irq_restore(flags);
return res;
diff --git a/arch/mips/lib/csum_partial.S b/arch/mips/lib/csum_partial.S
index 507147aebd41..a6adffbb4e5f 100644
--- a/arch/mips/lib/csum_partial.S
+++ b/arch/mips/lib/csum_partial.S
@@ -270,7 +270,7 @@ LEAF(csum_partial)
#endif
/* odd buffer alignment? */
-#ifdef CPU_MIPSR2
+#ifdef CONFIG_CPU_MIPSR2
wsbh v1, sum
movn sum, v1, t7
#else
@@ -670,7 +670,7 @@ EXC( sb t0, NBYTES-2(dst), .Ls_exc)
addu sum, v1
#endif
-#ifdef CPU_MIPSR2
+#ifdef CONFIG_CPU_MIPSR2
wsbh v1, sum
movn sum, v1, odd
#else
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index ecca559b8d7b..2078915eacb9 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1247,10 +1247,8 @@ static void __cpuinit setup_scache(void)
return;
default:
- if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
- c->isa_level == MIPS_CPU_ISA_M32R2 ||
- c->isa_level == MIPS_CPU_ISA_M64R1 ||
- c->isa_level == MIPS_CPU_ISA_M64R2) {
+ if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+ MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
#ifdef CONFIG_MIPS_CPU_SCACHE
if (mips_sc_init ()) {
scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 60547b7fe2ff..9b973e0af9cb 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -78,10 +78,9 @@ EXPORT_SYMBOL_GPL(empty_zero_page);
/*
* Not static inline because used by IP27 special magic initialization code
*/
-unsigned long setup_zero_pages(void)
+void setup_zero_pages(void)
{
- unsigned int order;
- unsigned long size;
+ unsigned int order, i;
struct page *page;
if (cpu_has_vce)
@@ -95,15 +94,10 @@ unsigned long setup_zero_pages(void)
page = virt_to_page((void *)empty_zero_page);
split_page(page, order);
- while (page < virt_to_page((void *)(empty_zero_page + (PAGE_SIZE << order)))) {
- SetPageReserved(page);
- page++;
- }
-
- size = PAGE_SIZE << order;
- zero_page_mask = (size - 1) & PAGE_MASK;
+ for (i = 0; i < (1 << order); i++, page++)
+ mark_page_reserved(page);
- return 1UL << order;
+ zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK;
}
#ifdef CONFIG_MIPS_MT_SMTC
@@ -381,7 +375,7 @@ void __init mem_init(void)
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
totalram_pages += free_all_bootmem();
- totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */
+ setup_zero_pages(); /* Setup zeroed pages. */
reservedpages = ram = 0;
for (tmp = 0; tmp < max_low_pfn; tmp++)
@@ -400,12 +394,8 @@ void __init mem_init(void)
SetPageReserved(page);
continue;
}
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
+ free_highmem_page(page);
}
- totalram_pages += totalhigh_pages;
num_physpages += totalhigh_pages;
#endif
@@ -441,11 +431,8 @@ void free_init_pages(const char *what, unsigned long begin, unsigned long end)
struct page *page = pfn_to_page(pfn);
void *addr = phys_to_virt(PFN_PHYS(pfn));
- ClearPageReserved(page);
- init_page_count(page);
memset(addr, POISON_FREE_INITMEM, PAGE_SIZE);
- __free_page(page);
- totalram_pages++;
+ free_reserved_page(page);
}
printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
}
@@ -453,18 +440,14 @@ void free_init_pages(const char *what, unsigned long begin, unsigned long end)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory",
- virt_to_phys((void *)start),
- virt_to_phys((void *)end));
+ free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
}
#endif
void __init_refok free_initmem(void)
{
prom_free_prom_memory();
- free_init_pages("unused kernel memory",
- __pa_symbol(&__init_begin),
- __pa_symbol(&__init_end));
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifndef CONFIG_MIPS_PGD_C0_CONTEXT
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 93d937b4b1ba..df96da7e939b 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -98,10 +98,8 @@ static inline int __init mips_sc_probe(void)
c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
/* Ignore anything but MIPSxx processors */
- if (c->isa_level != MIPS_CPU_ISA_M32R1 &&
- c->isa_level != MIPS_CPU_ISA_M32R2 &&
- c->isa_level != MIPS_CPU_ISA_M64R1 &&
- c->isa_level != MIPS_CPU_ISA_M64R2)
+ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+ MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)))
return 0;
/* Does this MIPS32/MIPS64 CPU have a config2 register? */
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index 38a80c83fd67..d1faece21b6a 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -19,7 +19,7 @@
#include <asm/mach-au1x00/au1000.h>
#include <asm/tlbmisc.h>
-#ifdef CONFIG_DEBUG_PCI
+#ifdef CONFIG_PCI_DEBUG
#define DBG(x...) printk(KERN_DEBUG x)
#else
#define DBG(x...) do {} while (0)
@@ -162,7 +162,7 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
if (status & (1 << 29)) {
*data = 0xffffffff;
error = -1;
- DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d",
+ DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d\n",
access_type, bus->number, device);
} else if ((status >> 28) & 0xf) {
DBG("alchemy-pci: PCI ERR detected: dev %d, status %lx\n",
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 0872f12f268d..594e60d6a43b 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -115,7 +115,6 @@ static void pcibios_scanbus(struct pci_controller *hose)
pci_bus_assign_resources(bus);
pci_enable_bridges(bus);
}
- bus->dev.of_node = hose->of_node;
}
}
@@ -169,6 +168,13 @@ void pci_load_of_ranges(struct pci_controller *hose, struct device_node *node)
}
}
}
+
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus)
+{
+ struct pci_controller *hose = bus->sysdata;
+
+ return of_node_get(hose->of_node);
+}
#endif
static DEFINE_MUTEX(pci_scan_mutex);
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 3505d08ff2fd..5f2bddb1860e 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -457,7 +457,7 @@ void __init prom_free_prom_memory(void)
/* We got nothing to free here ... */
}
-extern unsigned long setup_zero_pages(void);
+extern void setup_zero_pages(void);
void __init paging_init(void)
{
@@ -492,7 +492,7 @@ void __init mem_init(void)
totalram_pages += free_all_bootmem_node(NODE_DATA(node));
}
- totalram_pages -= setup_zero_pages(); /* This comes from node 0 */
+ setup_zero_pages(); /* This comes from node 0 */
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
diff --git a/arch/mn10300/include/asm/thread_info.h b/arch/mn10300/include/asm/thread_info.h
index f90062b0622d..224b4262486d 100644
--- a/arch/mn10300/include/asm/thread_info.h
+++ b/arch/mn10300/include/asm/thread_info.h
@@ -165,8 +165,6 @@ void arch_release_thread_info(struct thread_info *ti);
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/mn10300/include/asm/unistd.h b/arch/mn10300/include/asm/unistd.h
index 7f9d9adfa51e..9d4e2d1ef90e 100644
--- a/arch/mn10300/include/asm/unistd.h
+++ b/arch/mn10300/include/asm/unistd.h
@@ -45,14 +45,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
-#endif
-
#endif /* _ASM_UNISTD_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index 5c7c7c988544..b4ce844c9391 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -72,4 +72,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 84f4e97e3074..3707da583d05 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -50,77 +50,19 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
-#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
-/*
- * we use this if we don't have any better idle routine
- */
-static void default_idle(void)
-{
- local_irq_disable();
- if (!need_resched())
- safe_halt();
- else
- local_irq_enable();
-}
-
-#else /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */
/*
* On SMP it's slightly faster (but much more power-consuming!)
* to poll the ->work.need_resched flag instead of waiting for the
* cross-CPU IPI to arrive. Use this option with caution.
+ *
+ * tglx: No idea why this depends on HOTPLUG_CPU !?!
*/
-static inline void poll_idle(void)
-{
- int oldval;
-
- local_irq_enable();
-
- /*
- * Deal with another CPU just having chosen a thread to
- * run here:
- */
- oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
- if (!oldval) {
- set_thread_flag(TIF_POLLING_NRFLAG);
- while (!need_resched())
- cpu_relax();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- } else {
- set_need_resched();
- }
-}
-#endif /* !CONFIG_SMP || CONFIG_HOTPLUG_CPU */
-
-/*
- * the idle thread
- * - there's no useful work to be done, so just try to conserve power and have
- * a low exit latency (ie sit in a loop waiting for somebody to say that
- * they'd like to reschedule)
- */
-void cpu_idle(void)
+#if !defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
+void arch_cpu_idle(void)
{
- /* endless idle loop with no priority at all */
- for (;;) {
- rcu_idle_enter();
- while (!need_resched()) {
- void (*idle)(void);
-
- smp_rmb();
- if (!idle) {
-#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
- idle = poll_idle;
-#else /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
- idle = default_idle;
-#endif /* CONFIG_SMP && !CONFIG_HOTPLUG_CPU */
- }
- idle();
- }
- rcu_idle_exit();
-
- schedule_preempt_disabled();
- }
+ safe_halt();
}
+#endif
void release_segments(struct mm_struct *mm)
{
@@ -155,6 +97,7 @@ void machine_power_off(void)
void show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_DEFAULT);
}
/*
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index 5d7e152a23b7..a17f9c9c14c9 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -675,7 +675,7 @@ int __init start_secondary(void *unused)
#ifdef CONFIG_GENERIC_CLOCKEVENTS
init_clockevents();
#endif
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
return 0;
}
@@ -935,8 +935,6 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
int timeout;
#ifdef CONFIG_HOTPLUG_CPU
- if (num_online_cpus() == 1)
- disable_hlt();
if (sleep_mode[cpu])
run_wakeup_cpu(cpu);
#endif /* CONFIG_HOTPLUG_CPU */
@@ -1003,9 +1001,6 @@ int __cpu_disable(void)
void __cpu_die(unsigned int cpu)
{
run_sleep_cpu(cpu);
-
- if (num_online_cpus() == 1)
- enable_hlt();
}
#ifdef CONFIG_MN10300_CACHE_ENABLED
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c
index b900e5afa0ae..a7a987c7954f 100644
--- a/arch/mn10300/kernel/traps.c
+++ b/arch/mn10300/kernel/traps.c
@@ -294,17 +294,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
}
/*
- * the architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_stack(current, &stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
-/*
* dump the register file in the specified exception frame
*/
void show_registers_only(struct pt_regs *regs)
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index e57e5bc23562..5a8ace63a6b4 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -139,30 +139,11 @@ void __init mem_init(void)
}
/*
- *
- */
-void free_init_pages(char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr;
-
- for (addr = begin; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- memset((void *) addr, 0xcc, PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
-}
-
-/*
* recycle memory containing stuff only required for initialisation
*/
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long) &__init_begin,
- (unsigned long) &__init_end);
+ free_initmem_default(POISON_FREE_INITMEM);
}
/*
@@ -171,6 +152,6 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory", start, end);
+ free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
}
#endif
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 9ab3bf2eca8d..81b9ddbc9166 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -55,9 +55,6 @@ config TRACE_IRQFLAGS_SUPPORT
config GENERIC_CSUM
def_bool y
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
source "init/Kconfig"
diff --git a/arch/openrisc/include/asm/thread_info.h b/arch/openrisc/include/asm/thread_info.h
index 07f3212422ad..d797acc901e4 100644
--- a/arch/openrisc/include/asm/thread_info.h
+++ b/arch/openrisc/include/asm/thread_info.h
@@ -128,8 +128,6 @@ register struct thread_info *current_thread_info_reg asm("r10");
/* For OpenRISC, this is anything in the LSW other than syscall trace */
#define _TIF_WORK_MASK (0xff & ~(_TIF_SYSCALL_TRACE|_TIF_SINGLESTEP))
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile
index 35f92ce51c24..ec6d9d37cefd 100644
--- a/arch/openrisc/kernel/Makefile
+++ b/arch/openrisc/kernel/Makefile
@@ -4,7 +4,7 @@
extra-y := head.o vmlinux.lds
-obj-y := setup.o idle.o or32_ksyms.o process.o dma.o \
+obj-y := setup.o or32_ksyms.o process.o dma.o \
traps.o time.o irq.o entry.o ptrace.o signal.o \
sys_call_table.o
diff --git a/arch/openrisc/kernel/idle.c b/arch/openrisc/kernel/idle.c
deleted file mode 100644
index 5e8a3b6d6bc6..000000000000
--- a/arch/openrisc/kernel/idle.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * OpenRISC idle.c
- *
- * Linux architectural port borrowing liberally from similar works of
- * others. All original copyrights apply as per the original source
- * declaration.
- *
- * Modifications for the OpenRISC architecture:
- * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
- * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
- *
- * 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.
- *
- * Idle daemon for or32. Idle daemon will handle any action
- * that needs to be taken when the system becomes idle.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/tick.h>
-
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/mmu.h>
-#include <asm/cache.h>
-#include <asm/pgalloc.h>
-
-void (*powersave) (void) = NULL;
-
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched()) {
- check_pgt_cache();
- rmb();
-
- clear_thread_flag(TIF_POLLING_NRFLAG);
-
- local_irq_disable();
- /* Don't trace irqs off for idle */
- stop_critical_timings();
- if (!need_resched() && powersave != NULL)
- powersave();
- start_critical_timings();
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
-}
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index 00c233bf0d06..386af258591d 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -90,6 +90,7 @@ void show_regs(struct pt_regs *regs)
{
extern void show_registers(struct pt_regs *regs);
+ show_regs_print_info(KERN_DEFAULT);
/* __PHX__ cleanup this mess */
show_registers(regs);
}
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index 5cce396016d0..3d3f6062f49c 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -105,17 +105,6 @@ void show_trace_task(struct task_struct *tsk)
*/
}
-/*
- * The architecture-independent backtrace generator
- */
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_stack(current, &stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
void show_registers(struct pt_regs *regs)
{
int i;
diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c
index e7fdc50c4bf0..b3cbc6703837 100644
--- a/arch/openrisc/mm/init.c
+++ b/arch/openrisc/mm/init.c
@@ -43,6 +43,7 @@
#include <asm/kmap_types.h>
#include <asm/fixmap.h>
#include <asm/tlbflush.h>
+#include <asm/sections.h>
int mem_init_done;
@@ -201,9 +202,6 @@ void __init paging_init(void)
/* References to section boundaries */
-extern char _stext, _etext, _edata, __bss_start, _end;
-extern char __init_begin, __init_end;
-
static int __init free_pages_init(void)
{
int reservedpages, pfn;
@@ -263,30 +261,11 @@ void __init mem_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
- (end - start) >> 10);
-
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
void free_initmem(void)
{
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n",
- ((unsigned long)&__init_end -
- (unsigned long)&__init_begin) >> 10);
+ free_initmem_default(0);
}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 0339181bf3ac..433e75a2ee9a 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -1,5 +1,6 @@
config PARISC
def_bool y
+ select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
select HAVE_IDE
select HAVE_OPROFILE
select HAVE_FUNCTION_TRACER if 64BIT
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
index 7305ac8f7f5b..bc989e522a04 100644
--- a/arch/parisc/Kconfig.debug
+++ b/arch/parisc/Kconfig.debug
@@ -12,18 +12,4 @@ config DEBUG_RODATA
portion of the kernel code won't be covered by a TLB anymore.
If in doubt, say "N".
-config DEBUG_STRICT_USER_COPY_CHECKS
- bool "Strict copy size checks"
- depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
- ---help---
- Enabling this option turns a certain set of sanity checks for user
- copy operations into compile time failures.
-
- The copy_from_user() etc checks are there to help test if there
- are sufficient security checks on the length argument of
- the copy operation, by having gcc prove that the argument is
- within bounds.
-
- If unsure, or if you run an older (pre 4.4) gcc, say N.
-
endmenu
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 01d95e2f0581..113e28206503 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -65,8 +65,10 @@ ifndef CONFIG_FUNCTION_TRACER
endif
# Use long jumps instead of long branches (needed if your linker fails to
-# link a too big vmlinux executable)
-cflags-$(CONFIG_MLONGCALLS) += -mlong-calls
+# link a too big vmlinux executable). Not enabled for building modules.
+ifdef CONFIG_MLONGCALLS
+KBUILD_CFLAGS_KERNEL += -mlong-calls
+endif
# select which processor to optimise for
cflags-$(CONFIG_PA7100) += -march=1.1 -mschedule=7100
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index 79f694f3ad9b..f0e2784e7cca 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -140,7 +140,10 @@ static inline void *kmap(struct page *page)
return page_address(page);
}
-#define kunmap(page) kunmap_parisc(page_address(page))
+static inline void kunmap(struct page *page)
+{
+ kunmap_parisc(page_address(page));
+}
static inline void *kmap_atomic(struct page *page)
{
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 7df49fad29f9..1e40d7f86be3 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -16,6 +16,8 @@
#include <asm/processor.h>
#include <asm/cache.h>
+extern spinlock_t pa_dbit_lock;
+
/*
* kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
* memory. For the return value to be meaningful, ADDR must be >=
@@ -44,8 +46,11 @@ extern void purge_tlb_entries(struct mm_struct *, unsigned long);
#define set_pte_at(mm, addr, ptep, pteval) \
do { \
+ unsigned long flags; \
+ spin_lock_irqsave(&pa_dbit_lock, flags); \
set_pte(ptep, pteval); \
purge_tlb_entries(mm, addr); \
+ spin_unlock_irqrestore(&pa_dbit_lock, flags); \
} while (0)
#endif /* !__ASSEMBLY__ */
@@ -435,48 +440,46 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
-#ifdef CONFIG_SMP
+ pte_t pte;
+ unsigned long flags;
+
if (!pte_young(*ptep))
return 0;
- return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), &pte_val(*ptep));
-#else
- pte_t pte = *ptep;
- if (!pte_young(pte))
+
+ spin_lock_irqsave(&pa_dbit_lock, flags);
+ pte = *ptep;
+ if (!pte_young(pte)) {
+ spin_unlock_irqrestore(&pa_dbit_lock, flags);
return 0;
- set_pte_at(vma->vm_mm, addr, ptep, pte_mkold(pte));
+ }
+ set_pte(ptep, pte_mkold(pte));
+ purge_tlb_entries(vma->vm_mm, addr);
+ spin_unlock_irqrestore(&pa_dbit_lock, flags);
return 1;
-#endif
}
-extern spinlock_t pa_dbit_lock;
-
struct mm_struct;
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
pte_t old_pte;
+ unsigned long flags;
- spin_lock(&pa_dbit_lock);
+ spin_lock_irqsave(&pa_dbit_lock, flags);
old_pte = *ptep;
pte_clear(mm,addr,ptep);
- spin_unlock(&pa_dbit_lock);
+ purge_tlb_entries(mm, addr);
+ spin_unlock_irqrestore(&pa_dbit_lock, flags);
return old_pte;
}
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
-#ifdef CONFIG_SMP
- unsigned long new, old;
-
- do {
- old = pte_val(*ptep);
- new = pte_val(pte_wrprotect(__pte (old)));
- } while (cmpxchg((unsigned long *) ptep, old, new) != old);
+ unsigned long flags;
+ spin_lock_irqsave(&pa_dbit_lock, flags);
+ set_pte(ptep, pte_wrprotect(*ptep));
purge_tlb_entries(mm, addr);
-#else
- pte_t old_pte = *ptep;
- set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
-#endif
+ spin_unlock_irqrestore(&pa_dbit_lock, flags);
}
#define pte_same(A,B) (pte_val(A) == pte_val(B))
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index d1fb79a36f3d..6182832e5b6c 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -77,8 +77,6 @@ struct thread_info {
#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
_TIF_BLOCKSTEP)
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* __KERNEL__ */
#endif /* _ASM_PARISC_THREAD_INFO_H */
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index 4ba2c93770f1..e0a82358517e 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -181,30 +181,24 @@ struct exception_data {
#if !defined(CONFIG_64BIT)
#define __put_kernel_asm64(__val,ptr) do { \
- u64 __val64 = (u64)(__val); \
- u32 hi = (__val64) >> 32; \
- u32 lo = (__val64) & 0xffffffff; \
__asm__ __volatile__ ( \
"\n1:\tstw %2,0(%1)" \
- "\n2:\tstw %3,4(%1)\n\t" \
+ "\n2:\tstw %R2,4(%1)\n\t" \
ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
: "=r"(__pu_err) \
- : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
+ : "r"(ptr), "r"(__val), "0"(__pu_err) \
: "r1"); \
} while (0)
#define __put_user_asm64(__val,ptr) do { \
- u64 __val64 = (u64)(__val); \
- u32 hi = (__val64) >> 32; \
- u32 lo = (__val64) & 0xffffffff; \
__asm__ __volatile__ ( \
"\n1:\tstw %2,0(%%sr3,%1)" \
- "\n2:\tstw %3,4(%%sr3,%1)\n\t" \
+ "\n2:\tstw %R2,4(%%sr3,%1)\n\t" \
ASM_EXCEPTIONTABLE_ENTRY(1b,fixup_put_user_skip_2)\
ASM_EXCEPTIONTABLE_ENTRY(2b,fixup_put_user_skip_1)\
: "=r"(__pu_err) \
- : "r"(ptr), "r"(hi), "r"(lo), "0"(__pu_err) \
+ : "r"(ptr), "r"(__val), "0"(__pu_err) \
: "r1"); \
} while (0)
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index ae9a46cbfd92..74d835820ee7 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -170,12 +170,4 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#undef STR
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _ASM_PARISC_UNISTD_H_ */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index 526e4b9aece0..70c512a386f7 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -71,6 +71,8 @@
#define SO_LOCK_FILTER 0x4025
+#define SO_SELECT_ERR_QUEUE 0x4026
+
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 4b12890642eb..83ded26cad06 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -421,14 +421,11 @@ void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
/* Note: purge_tlb_entries can be called at startup with
no context. */
- /* Disable preemption while we play with %sr1. */
- preempt_disable();
- mtsp(mm->context, 1);
purge_tlb_start(flags);
+ mtsp(mm->context, 1);
pdtlb(addr);
pitlb(addr);
purge_tlb_end(flags);
- preempt_enable();
}
EXPORT_SYMBOL(purge_tlb_entries);
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 6795dc6c995f..568b2c61ea02 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -120,11 +120,13 @@ extern void __ashrdi3(void);
extern void __ashldi3(void);
extern void __lshrdi3(void);
extern void __muldi3(void);
+extern void __ucmpdi2(void);
EXPORT_SYMBOL(__ashrdi3);
EXPORT_SYMBOL(__ashldi3);
EXPORT_SYMBOL(__lshrdi3);
EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
asmlinkage void * __canonicalize_funcptr_for_compare(void *);
EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index d13507246c5d..55f92b614182 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -59,28 +59,6 @@
#include <asm/unwind.h>
#include <asm/sections.h>
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
-{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- barrier();
- rcu_idle_exit();
- schedule_preempt_disabled();
- check_pgt_cache();
- }
-}
-
-
#define COMMAND_GLOBAL F_EXTEND(0xfffe0030)
#define CMD_RESET 5 /* reset any module */
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 6266730efd61..fd1bb1519c2b 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -329,7 +329,7 @@ void __init smp_callin(void)
local_irq_enable(); /* Interrupts have been off until now */
- cpu_idle(); /* Wait for timer to schedule some work */
+ cpu_startup_entry(CPUHP_ONLINE);
/* NOTREACHED */
panic("smp_callin() AAAAaaaaahhhh....\n");
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 051c8b90231f..f517e08e7f0d 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -60,47 +60,6 @@ asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
return -ENOSYS;
}
-/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, with the
- * corresponding cast to a signed int to insure that the proper conversion
- * (sign extension) between the register representation of a signed int (msr in
- * 32-bit mode) and the register representation of a signed int (msr in 64-bit
- * mode) is performed.
- */
-asmlinkage long sys32_sendfile(u32 out_fd, u32 in_fd,
- compat_off_t __user *offset, compat_size_t count)
-{
- return compat_sys_sendfile((int)out_fd, (int)in_fd, offset, count);
-}
-
-asmlinkage long sys32_sendfile64(u32 out_fd, u32 in_fd,
- compat_loff_t __user *offset, compat_size_t count)
-{
- return sys_sendfile64((int)out_fd, (int)in_fd,
- (loff_t __user *)offset, count);
-}
-
-asmlinkage long sys32_semctl(int semid, int semnum, int cmd, union semun arg)
-{
- union semun u;
-
- if (cmd == SETVAL) {
- /* Ugh. arg is a union of int,ptr,ptr,ptr, so is 8 bytes.
- * The int should be in the first 4, but our argument
- * frobbing has left it in the last 4.
- */
- u.val = *((int *)&arg + 1);
- return sys_semctl (semid, semnum, cmd, u);
- }
- return sys_semctl (semid, semnum, cmd, arg);
-}
-
-long sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
- size_t len)
-{
- return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
- buf, len);
-}
-
asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi,
u32 mask_lo, int fd,
const char __user *pathname)
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index f57dc137b8dd..0c9107285e66 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -198,7 +198,7 @@
ENTRY_SAME(madvise)
ENTRY_SAME(clone_wrapper) /* 120 */
ENTRY_SAME(setdomainname)
- ENTRY_DIFF(sendfile)
+ ENTRY_COMP(sendfile)
/* struct sockaddr... */
ENTRY_SAME(recvfrom)
/* struct timex contains longs */
@@ -282,7 +282,7 @@
ENTRY_COMP(recvmsg)
ENTRY_SAME(semop) /* 185 */
ENTRY_SAME(semget)
- ENTRY_DIFF(semctl)
+ ENTRY_COMP(semctl)
ENTRY_COMP(msgsnd)
ENTRY_COMP(msgrcv)
ENTRY_SAME(msgget) /* 190 */
@@ -304,7 +304,7 @@
ENTRY_SAME(gettid)
ENTRY_OURS(readahead)
ENTRY_SAME(tkill)
- ENTRY_DIFF(sendfile64)
+ ENTRY_COMP(sendfile64)
ENTRY_COMP(futex) /* 210 */
ENTRY_COMP(sched_setaffinity)
ENTRY_COMP(sched_getaffinity)
@@ -318,7 +318,7 @@
ENTRY_SAME(alloc_hugepages) /* 220 */
ENTRY_SAME(free_hugepages)
ENTRY_SAME(exit_group)
- ENTRY_DIFF(lookup_dcookie)
+ ENTRY_COMP(lookup_dcookie)
ENTRY_SAME(epoll_create)
ENTRY_SAME(epoll_ctl) /* 225 */
ENTRY_SAME(epoll_wait)
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index aeb8f8f2c07a..f702bff0bed9 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -126,6 +126,8 @@ void show_regs(struct pt_regs *regs)
user = user_mode(regs);
level = user ? KERN_DEBUG : KERN_CRIT;
+ show_regs_print_info(level);
+
print_gr(level, regs);
for (i = 0; i < 8; i += 4)
@@ -158,14 +160,6 @@ void show_regs(struct pt_regs *regs)
}
}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
static void do_show_stack(struct unwind_frame_info *info)
{
int i = 1;
diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile
index 5f2e6904d14a..5651536ac733 100644
--- a/arch/parisc/lib/Makefile
+++ b/arch/parisc/lib/Makefile
@@ -2,6 +2,7 @@
# Makefile for parisc-specific library files
#
-lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o
+lib-y := lusercopy.o bitops.o checksum.o io.o memset.o fixup.o memcpy.o \
+ ucmpdi2.o
obj-y := iomap.o
diff --git a/arch/parisc/lib/ucmpdi2.c b/arch/parisc/lib/ucmpdi2.c
new file mode 100644
index 000000000000..149c016f32c5
--- /dev/null
+++ b/arch/parisc/lib/ucmpdi2.c
@@ -0,0 +1,25 @@
+#include <linux/module.h>
+
+union ull_union {
+ unsigned long long ull;
+ struct {
+ unsigned int high;
+ unsigned int low;
+ } ui;
+};
+
+int __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+ union ull_union au = {.ull = a};
+ union ull_union bu = {.ull = b};
+
+ if (au.ui.high < bu.ui.high)
+ return 0;
+ else if (au.ui.high > bu.ui.high)
+ return 2;
+ if (au.ui.low < bu.ui.low)
+ return 0;
+ else if (au.ui.low > bu.ui.low)
+ return 2;
+ return 1;
+}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 3ac462de53a4..157b931e7b09 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -505,7 +505,6 @@ static void __init map_pages(unsigned long start_vaddr,
void free_initmem(void)
{
- unsigned long addr;
unsigned long init_begin = (unsigned long)__init_begin;
unsigned long init_end = (unsigned long)__init_end;
@@ -533,19 +532,10 @@ void free_initmem(void)
* pages are no-longer executable */
flush_icache_range(init_begin, init_end);
- for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- num_physpages++;
- totalram_pages++;
- }
+ num_physpages += free_initmem_default(0);
/* set up a new led state on systems shipped LED State panel */
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
-
- printk(KERN_INFO "Freeing unused kernel memory: %luk freed\n",
- (init_end - init_begin) >> 10);
}
@@ -697,6 +687,8 @@ void show_mem(unsigned int filter)
printk(KERN_INFO "Mem-info:\n");
show_free_areas(filter);
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
#ifndef CONFIG_DISCONTIGMEM
i = max_mapnr;
while (i-- > 0) {
@@ -1107,15 +1099,6 @@ void flush_tlb_all(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (start >= end)
- return;
- printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- num_physpages++;
- totalram_pages++;
- }
+ num_physpages += free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ea5bb045983a..a0259edae5c9 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -114,7 +114,6 @@ config PPC
select USE_GENERIC_SMP_HELPERS if SMP
select HAVE_OPROFILE
select HAVE_DEBUG_KMEMLEAK
- select HAVE_SYSCALL_WRAPPERS if PPC64
select GENERIC_ATOMIC64 if PPC32
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select HAVE_PERF_EVENTS
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index 62e11a32c4c2..4fcbd6b14a3a 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -3,6 +3,7 @@
#ifdef CONFIG_HUGETLB_PAGE
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
extern struct kmem_cache *hugepte_cache;
diff --git a/arch/powerpc/include/asm/linkage.h b/arch/powerpc/include/asm/linkage.h
new file mode 100644
index 000000000000..b36f650a13ff
--- /dev/null
+++ b/arch/powerpc/include/asm/linkage.h
@@ -0,0 +1,13 @@
+#ifndef _ASM_POWERPC_LINKAGE_H
+#define _ASM_POWERPC_LINKAGE_H
+
+#ifdef CONFIG_PPC64
+#define cond_syscall(x) \
+ asm ("\t.weak " #x "\n\t.set " #x ", sys_ni_syscall\n" \
+ "\t.weak ." #x "\n\t.set ." #x ", .sys_ni_syscall\n")
+#define SYSCALL_ALIAS(alias, name) \
+ asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \
+ "\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
+#endif
+
+#endif /* _ASM_POWERPC_LINKAGE_H */
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index ebbec52d21bd..43523fe0d8b4 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -190,7 +190,7 @@ SYSCALL_SPU(getcwd)
SYSCALL_SPU(capget)
SYSCALL_SPU(capset)
COMPAT_SYS(sigaltstack)
-SYSX_SPU(sys_sendfile,compat_sys_sendfile_wrapper,sys_sendfile)
+COMPAT_SYS_SPU(sendfile)
SYSCALL(ni_syscall)
SYSCALL(ni_syscall)
PPC_SYS(vfork)
@@ -230,7 +230,7 @@ COMPAT_SYS_SPU(sched_setaffinity)
COMPAT_SYS_SPU(sched_getaffinity)
SYSCALL(ni_syscall)
SYSCALL(ni_syscall)
-SYSX(sys_ni_syscall,compat_sys_sendfile64_wrapper,sys_sendfile64)
+SYS32ONLY(sendfile64)
COMPAT_SYS_SPU(io_setup)
SYSCALL_SPU(io_destroy)
COMPAT_SYS_SPU(io_getevents)
@@ -239,7 +239,7 @@ SYSCALL_SPU(io_cancel)
SYSCALL(set_tid_address)
SYSX_SPU(sys_fadvise64,ppc32_fadvise64,sys_fadvise64)
SYSCALL(exit_group)
-SYSX(sys_lookup_dcookie,ppc32_lookup_dcookie,sys_lookup_dcookie)
+COMPAT_SYS(lookup_dcookie)
SYSCALL_SPU(epoll_create)
SYSCALL_SPU(epoll_ctl)
SYSCALL_SPU(epoll_wait)
@@ -273,8 +273,8 @@ COMPAT_SYS(mq_timedreceive)
COMPAT_SYS(mq_notify)
COMPAT_SYS(mq_getsetattr)
COMPAT_SYS(kexec_load)
-COMPAT_SYS(add_key)
-COMPAT_SYS(request_key)
+SYSCALL(add_key)
+SYSCALL(request_key)
COMPAT_SYS(keyctl)
COMPAT_SYS(waitid)
SYSCALL(ioprio_set)
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 406b7b9a1341..8ceea14d6fe4 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -182,8 +182,6 @@ static inline bool test_thread_local_flags(unsigned int flags)
#define is_32bit_task() (1)
#endif
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 1487f0f12293..3ca819f541bf 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -56,11 +56,5 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- */
-#define cond_syscall(x) \
- asmlinkage long x (void) __attribute__((weak,alias("sys_ni_syscall")))
-
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_UNISTD_H_ */
diff --git a/arch/powerpc/include/asm/uprobes.h b/arch/powerpc/include/asm/uprobes.h
index b532060d0916..23016020915e 100644
--- a/arch/powerpc/include/asm/uprobes.h
+++ b/arch/powerpc/include/asm/uprobes.h
@@ -51,4 +51,5 @@ extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
#endif /* _ASM_UPROBES_H */
diff --git a/arch/powerpc/include/uapi/asm/linkage.h b/arch/powerpc/include/uapi/asm/linkage.h
deleted file mode 100644
index e1c4ac1cc4ba..000000000000
--- a/arch/powerpc/include/uapi/asm/linkage.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_POWERPC_LINKAGE_H
-#define _ASM_POWERPC_LINKAGE_H
-
-/* Nothing to see here... */
-
-#endif /* _ASM_POWERPC_LINKAGE_H */
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index a26dcaece509..a36daf3c6f9a 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -79,4 +79,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index b3ba5163eae2..9ec3fe174cba 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -150,10 +150,7 @@ void crash_free_reserved_phys_range(unsigned long begin, unsigned long end)
if (addr <= rtas_end && ((addr + PAGE_SIZE) > rtas_start))
continue;
- ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
- init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
- free_page((unsigned long)__va(addr));
- totalram_pages++;
+ free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
}
}
#endif
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 256c5bf0adb7..04d69c4a5ac2 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -304,7 +304,7 @@ syscall_exit_work:
subi r12,r12,TI_FLAGS
4: /* Anything else left to do? */
- SET_DEFAULT_THREAD_PPR(r3, r9) /* Set thread.ppr = 3 */
+ SET_DEFAULT_THREAD_PPR(r3, r10) /* Set thread.ppr = 3 */
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
beq .ret_from_except_lite
@@ -657,7 +657,7 @@ resume_kernel:
/* Clear _TIF_EMULATE_STACK_STORE flag */
lis r11,_TIF_EMULATE_STACK_STORE@h
addi r5,r9,TI_FLAGS
- ldarx r4,0,r5
+0: ldarx r4,0,r5
andc r4,r4,r11
stdcx. r4,0,r5
bne- 0b
diff --git a/arch/powerpc/kernel/epapr_paravirt.c b/arch/powerpc/kernel/epapr_paravirt.c
index f3eab8594d9f..d44a571e45a7 100644
--- a/arch/powerpc/kernel/epapr_paravirt.c
+++ b/arch/powerpc/kernel/epapr_paravirt.c
@@ -23,8 +23,10 @@
#include <asm/code-patching.h>
#include <asm/machdep.h>
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
extern void epapr_ev_idle(void);
extern u32 epapr_ev_idle_start[];
+#endif
bool epapr_paravirt_enabled;
@@ -47,11 +49,15 @@ static int __init epapr_paravirt_init(void)
for (i = 0; i < (len / 4); i++) {
patch_instruction(epapr_hypercall_start + i, insts[i]);
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
patch_instruction(epapr_ev_idle_start + i, insts[i]);
+#endif
}
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
if (of_get_property(hyper_node, "has-idle", NULL))
ppc_md.power_save = epapr_ev_idle;
+#endif
epapr_paravirt_enabled = true;
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 200afa5bcfb7..56bd92362ce1 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1066,78 +1066,6 @@ unrecov_user_slb:
#endif /* __DISABLED__ */
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r12 contain the saved SRR1, SRR0 is still ready for return
- * r3 has the faulting address
- * r9 - r13 are saved in paca->exslb.
- * r3 is saved in paca->slb_r3
- * We assume we aren't going to take any exceptions during this procedure.
- */
-_GLOBAL(slb_miss_realmode)
- mflr r10
-#ifdef CONFIG_RELOCATABLE
- mtctr r11
-#endif
-
- stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
- std r10,PACA_EXSLB+EX_LR(r13) /* save LR */
-
- bl .slb_allocate_realmode
-
- /* All done -- return from exception. */
-
- ld r10,PACA_EXSLB+EX_LR(r13)
- ld r3,PACA_EXSLB+EX_R3(r13)
- lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
-
- mtlr r10
-
- andi. r10,r12,MSR_RI /* check for unrecoverable exception */
- beq- 2f
-
-.machine push
-.machine "power4"
- mtcrf 0x80,r9
- mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
-.machine pop
-
- RESTORE_PPR_PACA(PACA_EXSLB, r9)
- ld r9,PACA_EXSLB+EX_R9(r13)
- ld r10,PACA_EXSLB+EX_R10(r13)
- ld r11,PACA_EXSLB+EX_R11(r13)
- ld r12,PACA_EXSLB+EX_R12(r13)
- ld r13,PACA_EXSLB+EX_R13(r13)
- rfid
- b . /* prevent speculative execution */
-
-2: mfspr r11,SPRN_SRR0
- ld r10,PACAKBASE(r13)
- LOAD_HANDLER(r10,unrecov_slb)
- mtspr SPRN_SRR0,r10
- ld r10,PACAKMSR(r13)
- mtspr SPRN_SRR1,r10
- rfid
- b .
-
-unrecov_slb:
- EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
- DISABLE_INTS
- bl .save_nvgprs
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .unrecoverable_exception
- b 1b
-
-
-#ifdef CONFIG_PPC_970_NAP
-power4_fixup_nap:
- andc r9,r9,r10
- std r9,TI_LOCAL_FLAGS(r11)
- ld r10,_LINK(r1) /* make idle task do the */
- std r10,_NIP(r1) /* equivalent of a blr */
- blr
-#endif
-
.align 7
.globl alignment_common
alignment_common:
@@ -1336,6 +1264,78 @@ _GLOBAL(opal_mc_secondary_handler)
/*
+ * r13 points to the PACA, r9 contains the saved CR,
+ * r12 contain the saved SRR1, SRR0 is still ready for return
+ * r3 has the faulting address
+ * r9 - r13 are saved in paca->exslb.
+ * r3 is saved in paca->slb_r3
+ * We assume we aren't going to take any exceptions during this procedure.
+ */
+_GLOBAL(slb_miss_realmode)
+ mflr r10
+#ifdef CONFIG_RELOCATABLE
+ mtctr r11
+#endif
+
+ stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
+ std r10,PACA_EXSLB+EX_LR(r13) /* save LR */
+
+ bl .slb_allocate_realmode
+
+ /* All done -- return from exception. */
+
+ ld r10,PACA_EXSLB+EX_LR(r13)
+ ld r3,PACA_EXSLB+EX_R3(r13)
+ lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
+
+ mtlr r10
+
+ andi. r10,r12,MSR_RI /* check for unrecoverable exception */
+ beq- 2f
+
+.machine push
+.machine "power4"
+ mtcrf 0x80,r9
+ mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
+.machine pop
+
+ RESTORE_PPR_PACA(PACA_EXSLB, r9)
+ ld r9,PACA_EXSLB+EX_R9(r13)
+ ld r10,PACA_EXSLB+EX_R10(r13)
+ ld r11,PACA_EXSLB+EX_R11(r13)
+ ld r12,PACA_EXSLB+EX_R12(r13)
+ ld r13,PACA_EXSLB+EX_R13(r13)
+ rfid
+ b . /* prevent speculative execution */
+
+2: mfspr r11,SPRN_SRR0
+ ld r10,PACAKBASE(r13)
+ LOAD_HANDLER(r10,unrecov_slb)
+ mtspr SPRN_SRR0,r10
+ ld r10,PACAKMSR(r13)
+ mtspr SPRN_SRR1,r10
+ rfid
+ b .
+
+unrecov_slb:
+ EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
+ DISABLE_INTS
+ bl .save_nvgprs
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unrecoverable_exception
+ b 1b
+
+
+#ifdef CONFIG_PPC_970_NAP
+power4_fixup_nap:
+ andc r9,r9,r10
+ std r9,TI_LOCAL_FLAGS(r11)
+ ld r10,_LINK(r1) /* make idle task do the */
+ std r10,_NIP(r1) /* equivalent of a blr */
+ blr
+#endif
+
+/*
* Hash table stuff
*/
.align 7
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 06c8202a69cf..2230fd0ca3e4 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -1045,10 +1045,7 @@ static void fadump_release_memory(unsigned long begin, unsigned long end)
if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
continue;
- ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
- init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
- free_page((unsigned long)__va(addr));
- totalram_pages++;
+ free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
}
}
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index ea78761aa169..939ea7ef0dc8 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -33,11 +33,6 @@
#include <asm/runlatch.h>
#include <asm/smp.h>
-#ifdef CONFIG_HOTPLUG_CPU
-#define cpu_should_die() cpu_is_offline(smp_processor_id())
-#else
-#define cpu_should_die() 0
-#endif
unsigned long cpuidle_disable = IDLE_NO_OVERRIDE;
EXPORT_SYMBOL(cpuidle_disable);
@@ -50,64 +45,38 @@ static int __init powersave_off(char *arg)
}
__setup("powersave=off", powersave_off);
-/*
- * The body of the idle task.
- */
-void cpu_idle(void)
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
{
- set_thread_flag(TIF_POLLING_NRFLAG);
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched() && !cpu_should_die()) {
- ppc64_runlatch_off();
-
- if (ppc_md.power_save) {
- clear_thread_flag(TIF_POLLING_NRFLAG);
- /*
- * smp_mb is so clearing of TIF_POLLING_NRFLAG
- * is ordered w.r.t. need_resched() test.
- */
- smp_mb();
- local_irq_disable();
-
- /* Don't trace irqs off for idle */
- stop_critical_timings();
-
- /* check again after disabling irqs */
- if (!need_resched() && !cpu_should_die())
- ppc_md.power_save();
-
- start_critical_timings();
-
- /* Some power_save functions return with
- * interrupts enabled, some don't.
- */
- if (irqs_disabled())
- local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- } else {
- /*
- * Go into low thread priority and possibly
- * low power mode.
- */
- HMT_low();
- HMT_very_low();
- }
- }
+ sched_preempt_enable_no_resched();
+ cpu_die();
+}
+#endif
- HMT_medium();
- ppc64_runlatch_on();
- rcu_idle_exit();
- tick_nohz_idle_exit();
- if (cpu_should_die()) {
- sched_preempt_enable_no_resched();
- cpu_die();
- }
- schedule_preempt_disabled();
+void arch_cpu_idle(void)
+{
+ ppc64_runlatch_off();
+
+ if (ppc_md.power_save) {
+ ppc_md.power_save();
+ /*
+ * Some power_save functions return with
+ * interrupts enabled, some don't.
+ */
+ if (irqs_disabled())
+ local_irq_enable();
+ } else {
+ local_irq_enable();
+ /*
+ * Go into low thread priority and possibly
+ * low power mode.
+ */
+ HMT_low();
+ HMT_very_low();
}
+
+ HMT_medium();
+ ppc64_runlatch_on();
}
int powersave_nap;
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index a61b133c4f99..6782221d49bd 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -756,12 +756,7 @@ static __init void kvm_free_tmp(void)
end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
/* Free the tmp space we don't need */
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
+ free_reserved_area(start, end, 0, NULL);
}
static int __init kvm_guest_init(void)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index bec1e930ed73..48fbc2b97e95 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -511,8 +511,7 @@ int __init nvram_scan_partitions(void)
"detected: 0-length partition\n");
goto out;
}
- tmp_part = (struct nvram_partition *)
- kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+ tmp_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
err = -ENOMEM;
if (!tmp_part) {
printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 59dd545fdde1..13a8d9d0b5cb 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -555,10 +555,12 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
new->thread.regs->msr |=
(MSR_FP | new->thread.fpexc_mode);
}
+#ifdef CONFIG_ALTIVEC
if (msr & MSR_VEC) {
do_load_up_transact_altivec(&new->thread);
new->thread.regs->msr |= MSR_VEC;
}
+#endif
/* We may as well turn on VSX too since all the state is restored now */
if (msr & MSR_VSX)
new->thread.regs->msr |= MSR_VSX;
@@ -829,6 +831,8 @@ void show_regs(struct pt_regs * regs)
{
int i, trap;
+ show_regs_print_info(KERN_DEFAULT);
+
printk("NIP: "REG" LR: "REG" CTR: "REG"\n",
regs->nip, regs->link, regs->ctr);
printk("REGS: %p TRAP: %04lx %s (%s)\n",
@@ -848,12 +852,6 @@ void show_regs(struct pt_regs * regs)
#else
printk("DAR: "REG", DSISR: %08lx\n", regs->dar, regs->dsisr);
#endif
- printk("TASK = %p[%d] '%s' THREAD: %p",
- current, task_pid_nr(current), current->comm, task_thread_info(current));
-
-#ifdef CONFIG_SMP
- printk(" CPU: %d", raw_smp_processor_id());
-#endif /* CONFIG_SMP */
for (i = 0; i < 32; i++) {
if ((i % REGS_PER_LINE) == 0)
@@ -1360,12 +1358,6 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
} while (count++ < kstack_depth_to_print);
}
-void dump_stack(void)
-{
- show_stack(current, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
#ifdef CONFIG_PPC64
/* Called with hard IRQs off */
void __ppc64_runlatch_on(void)
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 3acb28e245b4..95068bf569ad 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -866,10 +866,12 @@ static long restore_tm_user_regs(struct pt_regs *regs,
do_load_up_transact_fpu(&current->thread);
regs->msr |= (MSR_FP | current->thread.fpexc_mode);
}
+#ifdef CONFIG_ALTIVEC
if (msr & MSR_VEC) {
do_load_up_transact_altivec(&current->thread);
regs->msr |= MSR_VEC;
}
+#endif
return 0;
}
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 995f8543cb57..c1794286098c 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -522,10 +522,12 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
do_load_up_transact_fpu(&current->thread);
regs->msr |= (MSR_FP | current->thread.fpexc_mode);
}
+#ifdef CONFIG_ALTIVEC
if (msr & MSR_VEC) {
do_load_up_transact_altivec(&current->thread);
regs->msr |= MSR_VEC;
}
+#endif
return err;
}
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 76bd9da8cb71..ee7ac5e6e28a 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -669,7 +669,7 @@ __cpuinit void start_secondary(void *unused)
local_irq_enable();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
BUG();
}
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index d0bafc0cdf06..cd6e19d263b3 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -61,91 +61,6 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
}
-#ifdef CONFIG_SYSVIPC
-long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
- u32 fifth)
-{
- int version;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
-
- case SEMTIMEDOP:
- if (fifth)
- /* sign extend semid */
- return compat_sys_semtimedop((int)first,
- compat_ptr(ptr), second,
- compat_ptr(fifth));
- /* else fall through for normal semop() */
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- /* sign extend semid */
- return sys_semtimedop((int)first, compat_ptr(ptr), second,
- NULL);
- case SEMGET:
- /* sign extend key, nsems */
- return sys_semget((int)first, (int)second, third);
- case SEMCTL:
- /* sign extend semid, semnum */
- return compat_sys_semctl((int)first, (int)second, third,
- compat_ptr(ptr));
-
- case MSGSND:
- /* sign extend msqid */
- return compat_sys_msgsnd((int)first, (int)second, third,
- compat_ptr(ptr));
- case MSGRCV:
- /* sign extend msqid, msgtyp */
- return compat_sys_msgrcv((int)first, second, (int)fifth,
- third, version, compat_ptr(ptr));
- case MSGGET:
- /* sign extend key */
- return sys_msgget((int)first, second);
- case MSGCTL:
- /* sign extend msqid */
- return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
-
- case SHMAT:
- /* sign extend shmid */
- return compat_sys_shmat((int)first, second, third, version,
- compat_ptr(ptr));
- case SHMDT:
- return sys_shmdt(compat_ptr(ptr));
- case SHMGET:
- /* sign extend key_t */
- return sys_shmget((int)first, second, third);
- case SHMCTL:
- /* sign extend shmid */
- return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
-
- default:
- return -ENOSYS;
- }
-
- return -ENOSYS;
-}
-#endif
-
-/* Note: it is necessary to treat out_fd and in_fd as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long compat_sys_sendfile_wrapper(u32 out_fd, u32 in_fd,
- compat_off_t __user *offset, u32 count)
-{
- return compat_sys_sendfile((int)out_fd, (int)in_fd, offset, count);
-}
-
-asmlinkage long compat_sys_sendfile64_wrapper(u32 out_fd, u32 in_fd,
- compat_loff_t __user *offset, u32 count)
-{
- return sys_sendfile((int)out_fd, (int)in_fd,
- (off_t __user *)offset, count);
-}
-
unsigned long compat_sys_mmap2(unsigned long addr, size_t len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
@@ -195,13 +110,6 @@ asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long h
return sys_ftruncate(fd, (high << 32) | low);
}
-long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf,
- size_t len)
-{
- return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
- buf, len);
-}
-
long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low,
size_t len, int advice)
{
@@ -209,23 +117,6 @@ long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low,
advice);
}
-asmlinkage long compat_sys_add_key(const char __user *_type,
- const char __user *_description,
- const void __user *_payload,
- u32 plen,
- u32 ringid)
-{
- return sys_add_key(_type, _description, _payload, plen, ringid);
-}
-
-asmlinkage long compat_sys_request_key(const char __user *_type,
- const char __user *_description,
- const char __user *_callout_info,
- u32 destringid)
-{
- return sys_request_key(_type, _description, _callout_info, destringid);
-}
-
asmlinkage long compat_sys_sync_file_range2(int fd, unsigned int flags,
unsigned offset_hi, unsigned offset_lo,
unsigned nbytes_hi, unsigned nbytes_lo)
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 84dbace657ce..2da67e7a16d5 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -309,6 +309,7 @@ _GLOBAL(tm_recheckpoint)
or r5, r6, r5 /* Set MSR.FP+.VSX/.VEC */
mtmsr r5
+#ifdef CONFIG_ALTIVEC
/* FP and VEC registers: These are recheckpointed from thread.fpr[]
* and thread.vr[] respectively. The thread.transact_fpr[] version
* is more modern, and will be loaded subsequently by any FPUnavailable
@@ -323,6 +324,7 @@ _GLOBAL(tm_recheckpoint)
REST_32VRS(0, r5, r3) /* r5 scratch, r3 THREAD ptr */
ld r5, THREAD_VRSAVE(r3)
mtspr SPRN_VRSAVE, r5
+#endif
dont_restore_vec:
andi. r0, r4, MSR_FP
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index f9748498fe58..13b867093499 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -156,15 +156,13 @@ static struct console udbg_console = {
.index = 0,
};
-static int early_console_initialized;
-
/*
* Called by setup_system after ppc_md->probe and ppc_md->early_init.
* Call it again after setting udbg_putc in ppc_md->setup_arch.
*/
void __init register_early_udbg_console(void)
{
- if (early_console_initialized)
+ if (early_console)
return;
if (!udbg_putc)
@@ -174,7 +172,7 @@ void __init register_early_udbg_console(void)
printk(KERN_INFO "early console immortal !\n");
udbg_console.flags &= ~CON_BOOT;
}
- early_console_initialized = 1;
+ early_console = &udbg_console;
register_console(&udbg_console);
}
diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
index bc77834dbf43..59f419b935f2 100644
--- a/arch/powerpc/kernel/uprobes.c
+++ b/arch/powerpc/kernel/uprobes.c
@@ -31,6 +31,16 @@
#define UPROBE_TRAP_NR UINT_MAX
/**
+ * is_trap_insn - check if the instruction is a trap variant
+ * @insn: instruction to be checked.
+ * Returns true if @insn is a trap variant.
+ */
+bool is_trap_insn(uprobe_opcode_t *insn)
+{
+ return (is_trap(*insn));
+}
+
+/**
* arch_uprobe_analyze_insn
* @mm: the probed address space.
* @arch_uprobe: the probepoint information.
@@ -43,12 +53,6 @@ int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
if (addr & 0x03)
return -EINVAL;
- /*
- * We currently don't support a uprobe on an already
- * existing breakpoint instruction underneath
- */
- if (is_trap(auprobe->ainsn))
- return -ENOTSUPP;
return 0;
}
@@ -188,3 +192,16 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
return false;
}
+
+unsigned long
+arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
+{
+ unsigned long orig_ret_vaddr;
+
+ orig_ret_vaddr = regs->link;
+
+ /* Replace the return addr with trampoline addr */
+ regs->link = trampoline_vaddr;
+
+ return orig_ret_vaddr;
+}
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 5e93438afb06..dbdc15aa8127 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1039,7 +1039,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
if (!vcpu_book3s)
goto out;
- vcpu_book3s->shadow_vcpu = (struct kvmppc_book3s_shadow_vcpu *)
+ vcpu_book3s->shadow_vcpu =
kzalloc(sizeof(*vcpu_book3s->shadow_vcpu), GFP_KERNEL);
if (!vcpu_book3s->shadow_vcpu)
goto free_vcpu;
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
index 41cefd43655f..33db48a8ce24 100644
--- a/arch/powerpc/kvm/e500.h
+++ b/arch/powerpc/kvm/e500.h
@@ -26,17 +26,20 @@
#define E500_PID_NUM 3
#define E500_TLB_NUM 2
-#define E500_TLB_VALID 1
-#define E500_TLB_BITMAP 2
+/* entry is mapped somewhere in host TLB */
+#define E500_TLB_VALID (1 << 0)
+/* TLB1 entry is mapped by host TLB1, tracked by bitmaps */
+#define E500_TLB_BITMAP (1 << 1)
+/* TLB1 entry is mapped by host TLB0 */
#define E500_TLB_TLB0 (1 << 2)
struct tlbe_ref {
- pfn_t pfn;
- unsigned int flags; /* E500_TLB_* */
+ pfn_t pfn; /* valid only for TLB0, except briefly */
+ unsigned int flags; /* E500_TLB_* */
};
struct tlbe_priv {
- struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */
+ struct tlbe_ref ref;
};
#ifdef CONFIG_KVM_E500V2
@@ -63,17 +66,6 @@ struct kvmppc_vcpu_e500 {
unsigned int gtlb_nv[E500_TLB_NUM];
- /*
- * information associated with each host TLB entry --
- * TLB1 only for now. If/when guest TLB1 entries can be
- * mapped with host TLB0, this will be used for that too.
- *
- * We don't want to use this for guest TLB0 because then we'd
- * have the overhead of doing the translation again even if
- * the entry is still in the guest TLB (e.g. we swapped out
- * and back, and our host TLB entries got evicted).
- */
- struct tlbe_ref *tlb_refs[E500_TLB_NUM];
unsigned int host_tlb1_nv;
u32 svr;
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index a222edfb9a9b..1c6a9d729df4 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -193,8 +193,11 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref;
/* Don't bother with unmapped entries */
- if (!(ref->flags & E500_TLB_VALID))
- return;
+ if (!(ref->flags & E500_TLB_VALID)) {
+ WARN(ref->flags & (E500_TLB_BITMAP | E500_TLB_TLB0),
+ "%s: flags %x\n", __func__, ref->flags);
+ WARN_ON(tlbsel == 1 && vcpu_e500->g2h_tlb1_map[esel]);
+ }
if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) {
u64 tmp = vcpu_e500->g2h_tlb1_map[esel];
@@ -248,7 +251,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
pfn_t pfn)
{
ref->pfn = pfn;
- ref->flags = E500_TLB_VALID;
+ ref->flags |= E500_TLB_VALID;
if (tlbe_is_writable(gtlbe))
kvm_set_pfn_dirty(pfn);
@@ -257,6 +260,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
{
if (ref->flags & E500_TLB_VALID) {
+ /* FIXME: don't log bogus pfn for TLB1 */
trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
ref->flags = 0;
}
@@ -274,36 +278,23 @@ static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
{
- int tlbsel = 0;
- int i;
-
- for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
- struct tlbe_ref *ref =
- &vcpu_e500->gtlb_priv[tlbsel][i].ref;
- kvmppc_e500_ref_release(ref);
- }
-}
-
-static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
-{
- int stlbsel = 1;
+ int tlbsel;
int i;
- kvmppc_e500_tlbil_all(vcpu_e500);
-
- for (i = 0; i < host_tlb_params[stlbsel].entries; i++) {
- struct tlbe_ref *ref =
- &vcpu_e500->tlb_refs[stlbsel][i];
- kvmppc_e500_ref_release(ref);
+ for (tlbsel = 0; tlbsel <= 1; tlbsel++) {
+ for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
+ struct tlbe_ref *ref =
+ &vcpu_e500->gtlb_priv[tlbsel][i].ref;
+ kvmppc_e500_ref_release(ref);
+ }
}
-
- clear_tlb_privs(vcpu_e500);
}
void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
- clear_tlb_refs(vcpu_e500);
+ kvmppc_e500_tlbil_all(vcpu_e500);
+ clear_tlb_privs(vcpu_e500);
clear_tlb1_bitmap(vcpu_e500);
}
@@ -458,8 +449,6 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);
}
- /* Drop old ref and setup new one. */
- kvmppc_e500_ref_release(ref);
kvmppc_e500_ref_setup(ref, gtlbe, pfn);
kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
@@ -507,14 +496,15 @@ static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,
if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))
vcpu_e500->host_tlb1_nv = 0;
- vcpu_e500->tlb_refs[1][sesel] = *ref;
- vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
- vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
if (vcpu_e500->h2g_tlb1_rmap[sesel]) {
- unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel];
+ unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel] - 1;
vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel);
}
- vcpu_e500->h2g_tlb1_rmap[sesel] = esel;
+
+ vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
+ vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
+ vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1;
+ WARN_ON(!(ref->flags & E500_TLB_VALID));
return sesel;
}
@@ -526,13 +516,12 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
struct kvm_book3e_206_tlb_entry *stlbe, int esel)
{
- struct tlbe_ref ref;
+ struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[1][esel].ref;
int sesel;
int r;
- ref.flags = 0;
r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe,
- &ref);
+ ref);
if (r)
return r;
@@ -544,7 +533,7 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
}
/* Otherwise map into TLB1 */
- sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, &ref, esel);
+ sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, ref, esel);
write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel);
return 0;
@@ -565,7 +554,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
case 0:
priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
- /* Triggers after clear_tlb_refs or on initial mapping */
+ /* Triggers after clear_tlb_privs or on initial mapping */
if (!(priv->ref.flags & E500_TLB_VALID)) {
kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
} else {
@@ -665,35 +654,16 @@ int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500)
host_tlb_params[0].entries / host_tlb_params[0].ways;
host_tlb_params[1].sets = 1;
- vcpu_e500->tlb_refs[0] =
- kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries,
- GFP_KERNEL);
- if (!vcpu_e500->tlb_refs[0])
- goto err;
-
- vcpu_e500->tlb_refs[1] =
- kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries,
- GFP_KERNEL);
- if (!vcpu_e500->tlb_refs[1])
- goto err;
-
vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) *
host_tlb_params[1].entries,
GFP_KERNEL);
if (!vcpu_e500->h2g_tlb1_rmap)
- goto err;
+ return -EINVAL;
return 0;
-
-err:
- kfree(vcpu_e500->tlb_refs[0]);
- kfree(vcpu_e500->tlb_refs[1]);
- return -EINVAL;
}
void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)
{
kfree(vcpu_e500->h2g_tlb1_rmap);
- kfree(vcpu_e500->tlb_refs[0]);
- kfree(vcpu_e500->tlb_refs[1]);
}
diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c
index 1f89d26e65fb..2f4baa074b2e 100644
--- a/arch/powerpc/kvm/e500mc.c
+++ b/arch/powerpc/kvm/e500mc.c
@@ -108,6 +108,8 @@ void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr)
{
}
+static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu);
+
void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
@@ -136,8 +138,11 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
mtspr(SPRN_GDEAR, vcpu->arch.shared->dar);
mtspr(SPRN_GESR, vcpu->arch.shared->esr);
- if (vcpu->arch.oldpir != mfspr(SPRN_PIR))
+ if (vcpu->arch.oldpir != mfspr(SPRN_PIR) ||
+ __get_cpu_var(last_vcpu_on_cpu) != vcpu) {
kvmppc_e500_tlbil_all(vcpu_e500);
+ __get_cpu_var(last_vcpu_on_cpu) = vcpu;
+ }
kvmppc_load_guest_fp(vcpu);
}
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 7e2246fb2f31..5a535b73ea18 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -263,19 +263,14 @@ static __meminit void vmemmap_list_populate(unsigned long phys,
vmemmap_list = vmem_back;
}
-int __meminit vmemmap_populate(struct page *start_page,
- unsigned long nr_pages, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
- unsigned long start = (unsigned long)start_page;
- unsigned long end = (unsigned long)(start_page + nr_pages);
unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;
/* Align to the page size of the linear mapping. */
start = _ALIGN_DOWN(start, page_size);
- pr_debug("vmemmap_populate page %p, %ld pages, node %d\n",
- start_page, nr_pages, node);
- pr_debug(" -> map %lx..%lx\n", start, end);
+ pr_debug("vmemmap_populate %lx..%lx, node %d\n", start, end, node);
for (; start < end; start += page_size) {
void *p;
@@ -298,7 +293,7 @@ int __meminit vmemmap_populate(struct page *start_page,
return 0;
}
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
{
}
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index f1f7409a4183..cd76c454942f 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -352,13 +352,9 @@ void __init mem_init(void)
struct page *page = pfn_to_page(pfn);
if (memblock_is_reserved(paddr))
continue;
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
+ free_highmem_page(page);
reservedpages--;
}
- totalram_pages += totalhigh_pages;
printk(KERN_DEBUG "High memory: %luk\n",
totalhigh_pages << (PAGE_SHIFT-10));
}
@@ -405,39 +401,14 @@ void __init mem_init(void)
void free_initmem(void)
{
- unsigned long addr;
-
ppc_md.progress = ppc_printk_progress;
-
- addr = (unsigned long)__init_begin;
- for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
- memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- pr_info("Freeing unused kernel memory: %luk freed\n",
- ((unsigned long)__init_end -
- (unsigned long)__init_begin) >> 10);
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- if (start >= end)
- return;
-
- start = _ALIGN_DOWN(start, PAGE_SIZE);
- end = _ALIGN_UP(end, PAGE_SIZE);
- pr_info("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
-
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index bba87ca2b4d7..fa33c546e778 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -22,6 +22,7 @@
#include <linux/pfn.h>
#include <linux/cpuset.h>
#include <linux/node.h>
+#include <linux/slab.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/smp.h>
@@ -62,14 +63,11 @@ static int distance_lookup_table[MAX_NUMNODES][MAX_DISTANCE_REF_POINTS];
*/
static void __init setup_node_to_cpumask_map(void)
{
- unsigned int node, num = 0;
+ unsigned int node;
/* setup nr_node_ids if not done yet */
- if (nr_node_ids == MAX_NUMNODES) {
- for_each_node_mask(node, node_possible_map)
- num = node;
- nr_node_ids = num + 1;
- }
+ if (nr_node_ids == MAX_NUMNODES)
+ setup_nr_node_ids();
/* allocate the map */
for (node = 0; node < nr_node_ids; node++)
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index e834f1ec23c8..c427ae36374a 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -671,16 +671,12 @@ void bpf_jit_compile(struct sk_filter *fp)
}
if (bpf_jit_enable > 1)
- pr_info("flen=%d proglen=%u pass=%d image=%p\n",
- flen, proglen, pass, image);
+ /* Note that we output the base address of the code_base
+ * rather than image, since opcodes are in code_base.
+ */
+ bpf_jit_dump(flen, proglen, pass, code_base);
if (image) {
- if (bpf_jit_enable > 1)
- print_hex_dump(KERN_ERR, "JIT code: ",
- DUMP_PREFIX_ADDRESS,
- 16, 1, code_base,
- proglen, false);
-
bpf_flush_icache(code_base, code_base + (proglen/4));
/* Function descriptor nastiness: Address + TOC */
((u64 *)image)[0] = (u64)code_base;
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 0effe9f5a1ea..7be93367d92f 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -274,6 +274,8 @@ config 440EPX
select IBM_EMAC_EMAC4
select IBM_EMAC_RGMII
select IBM_EMAC_ZMII
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_DESC
config 440GRX
bool
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index c16999802ecf..381a592826a2 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -7,6 +7,8 @@ config PPC_MPC512x
select PPC_PCI_CHOICE
select FSL_PCI if PCI
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_DESC
config MPC5121_ADS
bool "Freescale MPC5121E ADS"
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index d30235b7e3f7..db6ac389ef8c 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -172,12 +172,9 @@ static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
static inline void mpc512x_free_bootmem(struct page *page)
{
- __ClearPageReserved(page);
BUG_ON(PageTail(page));
BUG_ON(atomic_read(&page->_count) > 1);
- atomic_set(&page->_count, 1);
- __free_page(page);
- totalram_pages++;
+ free_reserved_page(page);
}
void mpc512x_release_bootmem(void)
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 53aaefeb3386..9978f594cac0 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -113,34 +113,10 @@ config CBE_THERM
default m
depends on CBE_RAS && SPU_BASE
-config CBE_CPUFREQ
- tristate "CBE frequency scaling"
- depends on CBE_RAS && CPU_FREQ
- default m
- help
- This adds the cpufreq driver for Cell BE processors.
- For details, take a look at <file:Documentation/cpu-freq/>.
- If you don't have such processor, say N
-
-config CBE_CPUFREQ_PMI_ENABLE
- bool "CBE frequency scaling using PMI interface"
- depends on CBE_CPUFREQ
- default n
- help
- Select this, if you want to use the PMI interface
- to switch frequencies. Using PMI, the
- processor will not only be able to run at lower speed,
- but also at lower core voltage.
-
-config CBE_CPUFREQ_PMI
- tristate
- depends on CBE_CPUFREQ_PMI_ENABLE
- default CBE_CPUFREQ
-
config PPC_PMI
tristate
default y
- depends on CBE_CPUFREQ_PMI || PPC_IBM_CELL_POWERBUTTON
+ depends on CPU_FREQ_CBE_PMI || PPC_IBM_CELL_POWERBUTTON
help
PMI (Platform Management Interrupt) is a way to
communicate with the BMC (Baseboard Management Controller).
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index a4a89350bcfc..fe053e7c73ee 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -5,9 +5,6 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += iommu.o setup.o spider-pic.o \
obj-$(CONFIG_CBE_RAS) += ras.o
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
-obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o
-obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o
-cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o
obj-$(CONFIG_CBE_CPUFREQ_SPU_GOVERNOR) += cpufreq_spudemand.o
obj-$(CONFIG_PPC_IBM_CELL_POWERBUTTON) += cbe_powerbutton.o
diff --git a/arch/powerpc/platforms/chrp/pegasos_eth.c b/arch/powerpc/platforms/chrp/pegasos_eth.c
index 039fc8e82199..2b4dc6abde6c 100644
--- a/arch/powerpc/platforms/chrp/pegasos_eth.c
+++ b/arch/powerpc/platforms/chrp/pegasos_eth.c
@@ -47,6 +47,25 @@ static struct platform_device mv643xx_eth_shared_device = {
.resource = mv643xx_eth_shared_resources,
};
+/*
+ * The orion mdio driver only covers shared + 0x4 up to shared + 0x84 - 1
+ */
+static struct resource mv643xx_eth_mvmdio_resources[] = {
+ [0] = {
+ .name = "ethernet mdio base",
+ .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS + 0x4,
+ .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + 0x83,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device mv643xx_eth_mvmdio_device = {
+ .name = "orion-mdio",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mv643xx_eth_mvmdio_resources),
+ .resource = mv643xx_eth_shared_resources,
+};
+
static struct resource mv643xx_eth_port1_resources[] = {
[0] = {
.name = "eth port1 irq",
@@ -82,6 +101,7 @@ static struct platform_device eth_port1_device = {
static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
&mv643xx_eth_shared_device,
+ &mv643xx_eth_mvmdio_device,
&eth_port1_device,
};
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
index 890f30e70f98..be1e7958909e 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -273,10 +273,9 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = pas_freqs[pas_astate_new].frequency;
- freqs.cpu = policy->cpu;
mutex_lock(&pas_switch_mutex);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
policy->cpu,
@@ -288,7 +287,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
for_each_online_cpu(i)
set_astate(i, pas_astate_new);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&pas_switch_mutex);
ppc_proc_freq = freqs.new * 1000ul;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 311b804353b1..3104fad82480 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -335,7 +335,8 @@ static int pmu_set_cpu_speed(int low_speed)
return 0;
}
-static int do_set_cpu_speed(int speed_mode, int notify)
+static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode,
+ int notify)
{
struct cpufreq_freqs freqs;
unsigned long l3cr;
@@ -343,13 +344,12 @@ static int do_set_cpu_speed(int speed_mode, int notify)
freqs.old = cur_freq;
freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
- freqs.cpu = smp_processor_id();
if (freqs.old == freqs.new)
return 0;
if (notify)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (speed_mode == CPUFREQ_LOW &&
cpu_has_feature(CPU_FTR_L3CR)) {
l3cr = _get_L3CR();
@@ -366,7 +366,7 @@ static int do_set_cpu_speed(int speed_mode, int notify)
_set_L3CR(prev_l3cr);
}
if (notify)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
return 0;
@@ -393,7 +393,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
target_freq, relation, &newstate))
return -EINVAL;
- rc = do_set_cpu_speed(newstate, 1);
+ rc = do_set_cpu_speed(policy, newstate, 1);
ppc_proc_freq = cur_freq * 1000ul;
return rc;
@@ -442,7 +442,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy)
no_schedule = 1;
sleep_freq = cur_freq;
if (cur_freq == low_freq && !is_pmu_based)
- do_set_cpu_speed(CPUFREQ_HIGH, 0);
+ do_set_cpu_speed(policy, CPUFREQ_HIGH, 0);
return 0;
}
@@ -458,7 +458,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
* is that we force a switch to whatever it was, which is
* probably high speed due to our suspend() routine
*/
- do_set_cpu_speed(sleep_freq == low_freq ?
+ do_set_cpu_speed(policy, sleep_freq == low_freq ?
CPUFREQ_LOW : CPUFREQ_HIGH, 0);
ppc_proc_freq = cur_freq * 1000ul;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 9650c6029c82..7ba423431cfe 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -339,11 +339,10 @@ static int g5_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
freqs.new = g5_cpu_freqs[newstate].frequency;
- freqs.cpu = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
rc = g5_switch_freq(newstate);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&g5_switch_mutex);
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 2372c609fa2b..9a432de363b8 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -72,6 +72,7 @@ unsigned long memory_block_size_bytes(void)
return get_memblock_size();
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
{
unsigned long start, start_pfn;
@@ -153,6 +154,17 @@ static int pseries_remove_memory(struct device_node *np)
ret = pseries_remove_memblock(base, lmb_size);
return ret;
}
+#else
+static inline int pseries_remove_memblock(unsigned long base,
+ unsigned int memblock_size)
+{
+ return -EOPNOTSUPP;
+}
+static inline int pseries_remove_memory(struct device_node *np)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
static int pseries_add_memory(struct device_node *np)
{
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 0da39fed355a..299731e9036b 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -186,7 +186,13 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
(0x1UL << 4), &dummy1, &dummy2);
if (lpar_rc == H_SUCCESS)
return i;
- BUG_ON(lpar_rc != H_NOT_FOUND);
+
+ /*
+ * The test for adjunct partition is performed before the
+ * ANDCOND test. H_RESOURCE may be returned, so we need to
+ * check for that as well.
+ */
+ BUG_ON(lpar_rc != H_NOT_FOUND && lpar_rc != H_RESOURCE);
slot_offset++;
slot_offset &= 0x7;
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c
index 4d806b419606..4644efa06941 100644
--- a/arch/powerpc/platforms/pseries/processor_idle.c
+++ b/arch/powerpc/platforms/pseries/processor_idle.c
@@ -23,8 +23,8 @@
#include "pseries.h"
struct cpuidle_driver pseries_idle_driver = {
- .name = "pseries_idle",
- .owner = THIS_MODULE,
+ .name = "pseries_idle",
+ .owner = THIS_MODULE,
};
#define MAX_IDLE_STATE_COUNT 2
@@ -33,10 +33,8 @@ static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
static struct cpuidle_device __percpu *pseries_cpuidle_devices;
static struct cpuidle_state *cpuidle_state_table;
-static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before)
+static inline void idle_loop_prolog(unsigned long *in_purr)
{
-
- *kt_before = ktime_get();
*in_purr = mfspr(SPRN_PURR);
/*
* Indicate to the HV that we are idle. Now would be
@@ -45,12 +43,10 @@ static inline void idle_loop_prolog(unsigned long *in_purr, ktime_t *kt_before)
get_lppaca()->idle = 1;
}
-static inline s64 idle_loop_epilog(unsigned long in_purr, ktime_t kt_before)
+static inline void idle_loop_epilog(unsigned long in_purr)
{
get_lppaca()->wait_state_cycles += mfspr(SPRN_PURR) - in_purr;
get_lppaca()->idle = 0;
-
- return ktime_to_us(ktime_sub(ktime_get(), kt_before));
}
static int snooze_loop(struct cpuidle_device *dev,
@@ -58,10 +54,9 @@ static int snooze_loop(struct cpuidle_device *dev,
int index)
{
unsigned long in_purr;
- ktime_t kt_before;
int cpu = dev->cpu;
- idle_loop_prolog(&in_purr, &kt_before);
+ idle_loop_prolog(&in_purr);
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
@@ -75,8 +70,8 @@ static int snooze_loop(struct cpuidle_device *dev,
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb();
- dev->last_residency =
- (int)idle_loop_epilog(in_purr, kt_before);
+ idle_loop_epilog(in_purr);
+
return index;
}
@@ -102,9 +97,8 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
int index)
{
unsigned long in_purr;
- ktime_t kt_before;
- idle_loop_prolog(&in_purr, &kt_before);
+ idle_loop_prolog(&in_purr);
get_lppaca()->donate_dedicated_cpu = 1;
ppc64_runlatch_off();
@@ -112,8 +106,9 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
check_and_cede_processor();
get_lppaca()->donate_dedicated_cpu = 0;
- dev->last_residency =
- (int)idle_loop_epilog(in_purr, kt_before);
+
+ idle_loop_epilog(in_purr);
+
return index;
}
@@ -122,9 +117,8 @@ static int shared_cede_loop(struct cpuidle_device *dev,
int index)
{
unsigned long in_purr;
- ktime_t kt_before;
- idle_loop_prolog(&in_purr, &kt_before);
+ idle_loop_prolog(&in_purr);
/*
* Yield the processor to the hypervisor. We return if
@@ -135,8 +129,8 @@ static int shared_cede_loop(struct cpuidle_device *dev,
*/
check_and_cede_processor();
- dev->last_residency =
- (int)idle_loop_epilog(in_purr, kt_before);
+ idle_loop_epilog(in_purr);
+
return index;
}
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index 0f6af41ebb44..4a25c26f0bf4 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -214,15 +214,27 @@ static struct platform_device * __init mv64x60_eth_register_shared_pdev(
struct device_node *np, int id)
{
struct platform_device *pdev;
- struct resource r[1];
+ struct resource r[2];
int err;
err = of_address_to_resource(np, 0, &r[0]);
if (err)
return ERR_PTR(err);
+ /* register an orion mdio bus driver */
+ r[1].start = r[0].start + 0x4;
+ r[1].end = r[0].start + 0x84 - 1;
+ r[1].flags = IORESOURCE_MEM;
+
+ if (id == 0) {
+ pdev = platform_device_register_simple("orion-mdio", -1, &r[1], 1);
+ if (!pdev)
+ return pdev;
+ }
+
pdev = platform_device_register_simple(MV643XX_ETH_SHARED_NAME, id,
- r, 1);
+ &r[0], 1);
+
return pdev;
}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 13f85defabed..3e34cd224b7c 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2947,7 +2947,7 @@ static void sysrq_handle_xmon(int key)
static struct sysrq_key_op sysrq_xmon_op = {
.handler = sysrq_handle_xmon,
- .help_msg = "Xmon",
+ .help_msg = "xmon(x)",
.action_msg = "Entering xmon",
};
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index eb8fb629f00b..2c9789da0e24 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -91,6 +91,7 @@ config S390
select ARCH_INLINE_WRITE_UNLOCK_BH
select ARCH_INLINE_WRITE_UNLOCK_IRQ
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
+ select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
select ARCH_SAVE_PAGE_KEYS if HIBERNATION
select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT
@@ -131,7 +132,6 @@ config S390
select HAVE_PERF_EVENTS
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_SYSCALL_TRACEPOINTS
- select HAVE_SYSCALL_WRAPPERS
select HAVE_UID16 if 32BIT
select HAVE_VIRT_CPU_ACCOUNTING
select VIRT_TO_BUS
@@ -375,19 +375,6 @@ config PACK_STACK
Say Y if you are unsure.
-config SMALL_STACK
- def_bool n
- prompt "Use 8kb for kernel stack instead of 16kb"
- depends on PACK_STACK && 64BIT && !LOCKDEP
- help
- If you say Y here and the compiler supports the -mkernel-backchain
- option the kernel will use a smaller kernel stack size. The reduced
- size is 8kb instead of 16kb. This allows to run more threads on a
- system and reduces the pressure on the memory management for higher
- order page allocations.
-
- Say N if you are unsure.
-
config CHECK_STACK
def_bool y
prompt "Detect kernel stack overflow"
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
index fc32a2df4974..c56878e1245f 100644
--- a/arch/s390/Kconfig.debug
+++ b/arch/s390/Kconfig.debug
@@ -17,20 +17,6 @@ config STRICT_DEVMEM
If you are unsure, say Y.
-config DEBUG_STRICT_USER_COPY_CHECKS
- def_bool n
- prompt "Strict user copy size checks"
- ---help---
- Enabling this option turns a certain set of sanity checks for user
- copy operations into compile time warnings.
-
- The copy_from_user() etc checks are there to help test if there
- are sufficient security checks on the length argument of
- the copy operation, by having gcc prove that the argument is
- within bounds.
-
- If unsure, or if you run an older (pre 4.4) gcc, say N.
-
config S390_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 7e3ce78d4290..a7d68a467ce8 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -55,22 +55,12 @@ cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls
ifeq ($(call cc-option-yn,-mkernel-backchain),y)
cflags-$(CONFIG_PACK_STACK) += -mkernel-backchain -D__PACK_STACK
aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
-cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-ifdef CONFIG_SMALL_STACK
-STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
-endif
endif
# new style option for packed stacks
ifeq ($(call cc-option-yn,-mpacked-stack),y)
cflags-$(CONFIG_PACK_STACK) += -mpacked-stack -D__PACK_STACK
aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
-cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
-ifdef CONFIG_SMALL_STACK
-STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
-endif
endif
ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c
index 9fd4a40c6752..bb5dd496614f 100644
--- a/arch/s390/hypfs/hypfs_dbfs.c
+++ b/arch/s390/hypfs/hypfs_dbfs.c
@@ -105,9 +105,7 @@ void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df)
int hypfs_dbfs_init(void)
{
dbfs_dir = debugfs_create_dir("s390_hypfs", NULL);
- if (IS_ERR(dbfs_dir))
- return PTR_ERR(dbfs_dir);
- return 0;
+ return PTR_RET(dbfs_dir);
}
void hypfs_dbfs_exit(void)
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index 15422933c60b..4d8604e311f3 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -61,8 +61,6 @@ extern const char _sb_findmap[];
#ifndef CONFIG_64BIT
-#define __BITOPS_ALIGN 3
-#define __BITOPS_WORDSIZE 32
#define __BITOPS_OR "or"
#define __BITOPS_AND "nr"
#define __BITOPS_XOR "xr"
@@ -81,8 +79,6 @@ extern const char _sb_findmap[];
#else /* CONFIG_64BIT */
-#define __BITOPS_ALIGN 7
-#define __BITOPS_WORDSIZE 64
#define __BITOPS_OR "ogr"
#define __BITOPS_AND "ngr"
#define __BITOPS_XOR "xgr"
@@ -101,8 +97,7 @@ extern const char _sb_findmap[];
#endif /* CONFIG_64BIT */
-#define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE)
-#define __BITOPS_BARRIER() asm volatile("" : : : "memory")
+#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
#ifdef CONFIG_SMP
/*
@@ -114,9 +109,9 @@ static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make OR mask */
- mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+ mask = 1UL << (nr & (BITS_PER_LONG - 1));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_OR);
}
@@ -130,9 +125,9 @@ static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make AND mask */
- mask = ~(1UL << (nr & (__BITOPS_WORDSIZE - 1)));
+ mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_AND);
}
@@ -146,9 +141,9 @@ static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make XOR mask */
- mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+ mask = 1UL << (nr & (BITS_PER_LONG - 1));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_XOR);
}
@@ -163,12 +158,12 @@ test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make OR/test mask */
- mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+ mask = 1UL << (nr & (BITS_PER_LONG - 1));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_OR);
- __BITOPS_BARRIER();
+ barrier();
return (old & mask) != 0;
}
@@ -182,12 +177,12 @@ test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make AND/test mask */
- mask = ~(1UL << (nr & (__BITOPS_WORDSIZE - 1)));
+ mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_AND);
- __BITOPS_BARRIER();
+ barrier();
return (old ^ new) != 0;
}
@@ -201,12 +196,12 @@ test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr;
/* calculate address for CS */
- addr += (nr ^ (nr & (__BITOPS_WORDSIZE - 1))) >> 3;
+ addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
/* make XOR/test mask */
- mask = 1UL << (nr & (__BITOPS_WORDSIZE - 1));
+ mask = 1UL << (nr & (BITS_PER_LONG - 1));
/* Do the atomic update. */
__BITOPS_LOOP(old, new, addr, mask, __BITOPS_XOR);
- __BITOPS_BARRIER();
+ barrier();
return (old & mask) != 0;
}
#endif /* CONFIG_SMP */
@@ -218,7 +213,7 @@ static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
asm volatile(
" oc %O0(1,%R0),%1"
: "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
@@ -229,7 +224,7 @@ __constant_set_bit(const unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
*(unsigned char *) addr |= 1 << (nr & 7);
}
@@ -246,7 +241,7 @@ __clear_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
asm volatile(
" nc %O0(1,%R0),%1"
: "=Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc" );
@@ -257,7 +252,7 @@ __constant_clear_bit(const unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
*(unsigned char *) addr &= ~(1 << (nr & 7));
}
@@ -273,7 +268,7 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
asm volatile(
" xc %O0(1,%R0),%1"
: "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" );
@@ -284,7 +279,7 @@ __constant_change_bit(const unsigned long nr, volatile unsigned long *ptr)
{
unsigned long addr;
- addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
*(unsigned char *) addr ^= 1 << (nr & 7);
}
@@ -302,7 +297,7 @@ test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
unsigned char ch;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
ch = *(unsigned char *) addr;
asm volatile(
" oc %O0(1,%R0),%1"
@@ -321,7 +316,7 @@ test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
unsigned char ch;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
ch = *(unsigned char *) addr;
asm volatile(
" nc %O0(1,%R0),%1"
@@ -340,7 +335,7 @@ test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
unsigned char ch;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
ch = *(unsigned char *) addr;
asm volatile(
" xc %O0(1,%R0),%1"
@@ -376,7 +371,7 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr
unsigned long addr;
unsigned char ch;
- addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
+ addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
ch = *(volatile unsigned char *) addr;
return (ch >> (nr & 7)) & 1;
}
@@ -384,7 +379,7 @@ static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr
static inline int
__constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
return (((volatile char *) addr)
- [(nr^(__BITOPS_WORDSIZE-8))>>3] & (1<<(nr&7))) != 0;
+ [(nr^(BITS_PER_LONG-8))>>3] & (1<<(nr&7))) != 0;
}
#define test_bit(nr,addr) \
@@ -693,18 +688,18 @@ static inline int find_next_bit_left(const unsigned long *addr,
if (offset >= size)
return size;
- bit = offset & (__BITOPS_WORDSIZE - 1);
+ bit = offset & (BITS_PER_LONG - 1);
offset -= bit;
size -= offset;
- p = addr + offset / __BITOPS_WORDSIZE;
+ p = addr + offset / BITS_PER_LONG;
if (bit) {
set = __flo_word(0, *p & (~0UL << bit));
if (set >= size)
return size + offset;
- if (set < __BITOPS_WORDSIZE)
+ if (set < BITS_PER_LONG)
return set + offset;
- offset += __BITOPS_WORDSIZE;
- size -= __BITOPS_WORDSIZE;
+ offset += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
p++;
}
return offset + find_first_bit_left(p, size);
@@ -736,22 +731,22 @@ static inline int find_next_zero_bit (const unsigned long * addr,
if (offset >= size)
return size;
- bit = offset & (__BITOPS_WORDSIZE - 1);
+ bit = offset & (BITS_PER_LONG - 1);
offset -= bit;
size -= offset;
- p = addr + offset / __BITOPS_WORDSIZE;
+ p = addr + offset / BITS_PER_LONG;
if (bit) {
/*
- * __ffz_word returns __BITOPS_WORDSIZE
+ * __ffz_word returns BITS_PER_LONG
* if no zero bit is present in the word.
*/
set = __ffz_word(bit, *p >> bit);
if (set >= size)
return size + offset;
- if (set < __BITOPS_WORDSIZE)
+ if (set < BITS_PER_LONG)
return set + offset;
- offset += __BITOPS_WORDSIZE;
- size -= __BITOPS_WORDSIZE;
+ offset += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
p++;
}
return offset + find_first_zero_bit(p, size);
@@ -773,22 +768,22 @@ static inline int find_next_bit (const unsigned long * addr,
if (offset >= size)
return size;
- bit = offset & (__BITOPS_WORDSIZE - 1);
+ bit = offset & (BITS_PER_LONG - 1);
offset -= bit;
size -= offset;
- p = addr + offset / __BITOPS_WORDSIZE;
+ p = addr + offset / BITS_PER_LONG;
if (bit) {
/*
- * __ffs_word returns __BITOPS_WORDSIZE
+ * __ffs_word returns BITS_PER_LONG
* if no one bit is present in the word.
*/
set = __ffs_word(0, *p & (~0UL << bit));
if (set >= size)
return size + offset;
- if (set < __BITOPS_WORDSIZE)
+ if (set < BITS_PER_LONG)
return set + offset;
- offset += __BITOPS_WORDSIZE;
- size -= __BITOPS_WORDSIZE;
+ offset += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
p++;
}
return offset + find_first_bit(p, size);
@@ -843,22 +838,22 @@ static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
if (offset >= size)
return size;
- bit = offset & (__BITOPS_WORDSIZE - 1);
+ bit = offset & (BITS_PER_LONG - 1);
offset -= bit;
size -= offset;
- p = addr + offset / __BITOPS_WORDSIZE;
+ p = addr + offset / BITS_PER_LONG;
if (bit) {
/*
- * s390 version of ffz returns __BITOPS_WORDSIZE
+ * s390 version of ffz returns BITS_PER_LONG
* if no zero bit is present in the word.
*/
set = __ffz_word(bit, __load_ulong_le(p, 0) >> bit);
if (set >= size)
return size + offset;
- if (set < __BITOPS_WORDSIZE)
+ if (set < BITS_PER_LONG)
return set + offset;
- offset += __BITOPS_WORDSIZE;
- size -= __BITOPS_WORDSIZE;
+ offset += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
p++;
}
return offset + find_first_zero_bit_le(p, size);
@@ -885,22 +880,22 @@ static inline int find_next_bit_le(void *vaddr, unsigned long size,
if (offset >= size)
return size;
- bit = offset & (__BITOPS_WORDSIZE - 1);
+ bit = offset & (BITS_PER_LONG - 1);
offset -= bit;
size -= offset;
- p = addr + offset / __BITOPS_WORDSIZE;
+ p = addr + offset / BITS_PER_LONG;
if (bit) {
/*
- * s390 version of ffz returns __BITOPS_WORDSIZE
+ * s390 version of ffz returns BITS_PER_LONG
* if no zero bit is present in the word.
*/
set = __ffs_word(0, __load_ulong_le(p, 0) & (~0UL << bit));
if (set >= size)
return size + offset;
- if (set < __BITOPS_WORDSIZE)
+ if (set < BITS_PER_LONG)
return set + offset;
- offset += __BITOPS_WORDSIZE;
- size -= __BITOPS_WORDSIZE;
+ offset += BITS_PER_LONG;
+ size -= BITS_PER_LONG;
p++;
}
return offset + find_first_bit_le(p, size);
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index e6061617a50b..f201af8be580 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -220,7 +220,8 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
extern struct ccw_device *ccw_device_probe_console(void);
-extern int ccw_device_force_console(void);
+extern void ccw_device_wait_idle(struct ccw_device *);
+extern int ccw_device_force_console(struct ccw_device *);
int ccw_device_siosl(struct ccw_device *);
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index ad2b924167d7..ffb898961c8d 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -296,8 +296,6 @@ static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
return 0;
}
-extern void wait_cons_dev(void);
-
extern void css_schedule_reprobe(void);
extern void reipl_ccw_dev(struct ccw_dev_id *id);
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index f8c6df6cd1f0..c1e7c646727c 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -70,6 +70,22 @@ typedef u32 compat_ulong_t;
typedef u64 compat_u64;
typedef u32 compat_uptr_t;
+typedef struct {
+ u32 mask;
+ u32 addr;
+} __aligned(8) psw_compat_t;
+
+typedef struct {
+ psw_compat_t psw;
+ u32 gprs[NUM_GPRS];
+ u32 acrs[NUM_ACRS];
+ u32 orig_gpr2;
+} s390_compat_regs;
+
+typedef struct {
+ u32 gprs_high[NUM_GPRS];
+} s390_compat_regs_high;
+
struct compat_timespec {
compat_time_t tv_sec;
s32 tv_nsec;
@@ -124,18 +140,33 @@ struct compat_flock64 {
};
struct compat_statfs {
- s32 f_type;
- s32 f_bsize;
- s32 f_blocks;
- s32 f_bfree;
- s32 f_bavail;
- s32 f_files;
- s32 f_ffree;
+ u32 f_type;
+ u32 f_bsize;
+ u32 f_blocks;
+ u32 f_bfree;
+ u32 f_bavail;
+ u32 f_files;
+ u32 f_ffree;
+ compat_fsid_t f_fsid;
+ u32 f_namelen;
+ u32 f_frsize;
+ u32 f_flags;
+ u32 f_spare[4];
+};
+
+struct compat_statfs64 {
+ u32 f_type;
+ u32 f_bsize;
+ u64 f_blocks;
+ u64 f_bfree;
+ u64 f_bavail;
+ u64 f_files;
+ u64 f_ffree;
compat_fsid_t f_fsid;
- s32 f_namelen;
- s32 f_frsize;
- s32 f_flags;
- s32 f_spare[5];
+ u32 f_namelen;
+ u32 f_frsize;
+ u32 f_flags;
+ u32 f_spare[4];
};
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
@@ -248,8 +279,6 @@ static inline int is_compat_task(void)
return is_32bit_task();
}
-#endif
-
static inline void __user *arch_compat_alloc_user_space(long len)
{
unsigned long stack;
@@ -260,6 +289,8 @@ static inline void __user *arch_compat_alloc_user_space(long len)
return (void __user *) (stack - len);
}
+#endif
+
struct compat_ipc64_perm {
compat_key_t key;
__compat_uid32_t uid;
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 1bfdf24b85a2..78f4f8711d58 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -119,6 +119,8 @@
*/
#include <asm/ptrace.h>
+#include <asm/compat.h>
+#include <asm/syscall.h>
#include <asm/user.h>
typedef s390_fp_regs elf_fpregset_t;
@@ -180,18 +182,31 @@ extern unsigned long elf_hwcap;
extern char elf_platform[];
#define ELF_PLATFORM (elf_platform)
-#ifdef CONFIG_64BIT
+#ifndef CONFIG_COMPAT
+#define SET_PERSONALITY(ex) \
+do { \
+ set_personality(PER_LINUX | \
+ (current->personality & (~PER_MASK))); \
+ current_thread_info()->sys_call_table = \
+ (unsigned long) &sys_call_table; \
+} while (0)
+#else /* CONFIG_COMPAT */
#define SET_PERSONALITY(ex) \
do { \
if (personality(current->personality) != PER_LINUX32) \
set_personality(PER_LINUX | \
(current->personality & ~PER_MASK)); \
- if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
+ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) { \
set_thread_flag(TIF_31BIT); \
- else \
+ current_thread_info()->sys_call_table = \
+ (unsigned long) &sys_call_table_emu; \
+ } else { \
clear_thread_flag(TIF_31BIT); \
+ current_thread_info()->sys_call_table = \
+ (unsigned long) &sys_call_table; \
+ } \
} while (0)
-#endif /* CONFIG_64BIT */
+#endif /* CONFIG_COMPAT */
#define STACK_RND_MASK 0x7ffUL
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index 593753ee07f3..bd90359d6d22 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -114,7 +114,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
#define huge_ptep_set_wrprotect(__mm, __addr, __ptep) \
({ \
pte_t __pte = huge_ptep_get(__ptep); \
- if (pte_write(__pte)) { \
+ if (huge_pte_write(__pte)) { \
huge_ptep_invalidate(__mm, __addr, __ptep); \
set_huge_pte_at(__mm, __addr, __ptep, \
huge_pte_wrprotect(__pte)); \
@@ -127,4 +127,58 @@ static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
huge_ptep_invalidate(vma->vm_mm, address, ptep);
}
+static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
+{
+ pte_t pte;
+ pmd_t pmd;
+
+ pmd = mk_pmd_phys(page_to_phys(page), pgprot);
+ pte_val(pte) = pmd_val(pmd);
+ return pte;
+}
+
+static inline int huge_pte_write(pte_t pte)
+{
+ pmd_t pmd;
+
+ pmd_val(pmd) = pte_val(pte);
+ return pmd_write(pmd);
+}
+
+static inline int huge_pte_dirty(pte_t pte)
+{
+ /* No dirty bit in the segment table entry. */
+ return 0;
+}
+
+static inline pte_t huge_pte_mkwrite(pte_t pte)
+{
+ pmd_t pmd;
+
+ pmd_val(pmd) = pte_val(pte);
+ pte_val(pte) = pmd_val(pmd_mkwrite(pmd));
+ return pte;
+}
+
+static inline pte_t huge_pte_mkdirty(pte_t pte)
+{
+ /* No dirty bit in the segment table entry. */
+ return pte;
+}
+
+static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
+{
+ pmd_t pmd;
+
+ pmd_val(pmd) = pte_val(pte);
+ pte_val(pte) = pmd_val(pmd_modify(pmd, newprot));
+ return pte;
+}
+
+static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pmd_clear((pmd_t *) ptep);
+}
+
#endif /* _ASM_S390_HUGETLB_H */
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index 27cb32185ce1..379d96e2105e 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -50,10 +50,6 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
#define ioremap_nocache(addr, size) ioremap(addr, size)
#define ioremap_wc ioremap_nocache
-/* TODO: s390 cannot support io_remap_pfn_range... */
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
- remap_pfn_range(vma, vaddr, pfn, size, prot)
-
static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
{
return (void __iomem *) offset;
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 05333b7f0469..6c1801235db9 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -140,6 +140,7 @@ static inline bool zdev_enabled(struct zpci_dev *zdev)
struct zpci_dev *zpci_alloc_device(void);
int zpci_create_device(struct zpci_dev *);
int zpci_enable_device(struct zpci_dev *);
+int zpci_disable_device(struct zpci_dev *);
void zpci_stop_device(struct zpci_dev *);
void zpci_free_device(struct zpci_dev *);
int zpci_scan_device(struct zpci_dev *);
diff --git a/arch/s390/include/asm/pci_debug.h b/arch/s390/include/asm/pci_debug.h
index 6bbec4265b6e..1ca5d1047c71 100644
--- a/arch/s390/include/asm/pci_debug.h
+++ b/arch/s390/include/asm/pci_debug.h
@@ -7,14 +7,11 @@ extern debug_info_t *pci_debug_msg_id;
extern debug_info_t *pci_debug_err_id;
#ifdef CONFIG_PCI_DEBUG
-#define zpci_dbg(fmt, args...) \
- do { \
- if (pci_debug_msg_id->level >= 2) \
- debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\
- } while (0)
+#define zpci_dbg(imp, fmt, args...) \
+ debug_sprintf_event(pci_debug_msg_id, imp, fmt, ##args)
#else /* !CONFIG_PCI_DEBUG */
-#define zpci_dbg(fmt, args...) do { } while (0)
+#define zpci_dbg(imp, fmt, args...) do { } while (0)
#endif
#define zpci_err(text...) \
diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h
index 1486a98d5dad..e6a2bdd4d705 100644
--- a/arch/s390/include/asm/pci_insn.h
+++ b/arch/s390/include/asm/pci_insn.h
@@ -1,10 +1,6 @@
#ifndef _ASM_S390_PCI_INSN_H
#define _ASM_S390_PCI_INSN_H
-#include <linux/delay.h>
-
-#define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
-
/* Load/Store status codes */
#define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4
#define ZPCI_PCI_ST_FUNC_IN_ERR 8
@@ -82,199 +78,12 @@ struct zpci_fib {
u64 reserved7;
} __packed;
-/* Modify PCI Function Controls */
-static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
-{
- u8 cc;
-
- asm volatile (
- " .insn rxy,0xe300000000d0,%[req],%[fib]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
- : : "cc");
- *status = req >> 24 & 0xff;
- return cc;
-}
-
-static inline int mpcifc_instr(u64 req, struct zpci_fib *fib)
-{
- u8 cc, status;
-
- do {
- cc = __mpcifc(req, fib, &status);
- if (cc == 2)
- msleep(ZPCI_INSN_BUSY_DELAY);
- } while (cc == 2);
-
- if (cc)
- printk_once(KERN_ERR "%s: error cc: %d status: %d\n",
- __func__, cc, status);
- return (cc) ? -EIO : 0;
-}
-
-/* Refresh PCI Translations */
-static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
-{
- register u64 __addr asm("2") = addr;
- register u64 __range asm("3") = range;
- u8 cc;
-
- asm volatile (
- " .insn rre,0xb9d30000,%[fn],%[addr]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [fn] "+d" (fn)
- : [addr] "d" (__addr), "d" (__range)
- : "cc");
- *status = fn >> 24 & 0xff;
- return cc;
-}
-
-static inline int rpcit_instr(u64 fn, u64 addr, u64 range)
-{
- u8 cc, status;
-
- do {
- cc = __rpcit(fn, addr, range, &status);
- if (cc == 2)
- udelay(ZPCI_INSN_BUSY_DELAY);
- } while (cc == 2);
-
- if (cc)
- printk_once(KERN_ERR "%s: error cc: %d status: %d dma_addr: %Lx size: %Lx\n",
- __func__, cc, status, addr, range);
- return (cc) ? -EIO : 0;
-}
-
-/* Store PCI function controls */
-static inline u8 __stpcifc(u32 handle, u8 space, struct zpci_fib *fib, u8 *status)
-{
- u64 fn = (u64) handle << 32 | space << 16;
- u8 cc;
-
- asm volatile (
- " .insn rxy,0xe300000000d4,%[fn],%[fib]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [fn] "+d" (fn), [fib] "=m" (*fib)
- : : "cc");
- *status = fn >> 24 & 0xff;
- return cc;
-}
-
-/* Set Interruption Controls */
-static inline void sic_instr(u16 ctl, char *unused, u8 isc)
-{
- asm volatile (
- " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
- : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
-}
-
-/* PCI Load */
-static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
-{
- register u64 __req asm("2") = req;
- register u64 __offset asm("3") = offset;
- u64 __data;
- u8 cc;
-
- asm volatile (
- " .insn rre,0xb9d20000,%[data],%[req]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [data] "=d" (__data), [req] "+d" (__req)
- : "d" (__offset)
- : "cc");
- *status = __req >> 24 & 0xff;
- *data = __data;
- return cc;
-}
-
-static inline int pcilg_instr(u64 *data, u64 req, u64 offset)
-{
- u8 cc, status;
-
- do {
- cc = __pcilg(data, req, offset, &status);
- if (cc == 2)
- udelay(ZPCI_INSN_BUSY_DELAY);
- } while (cc == 2);
-
- if (cc) {
- printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
- __func__, cc, status, req, offset);
- /* TODO: on IO errors set data to 0xff...
- * here or in users of pcilg (le conversion)?
- */
- }
- return (cc) ? -EIO : 0;
-}
-
-/* PCI Store */
-static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status)
-{
- register u64 __req asm("2") = req;
- register u64 __offset asm("3") = offset;
- u8 cc;
-
- asm volatile (
- " .insn rre,0xb9d00000,%[data],%[req]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [req] "+d" (__req)
- : "d" (__offset), [data] "d" (data)
- : "cc");
- *status = __req >> 24 & 0xff;
- return cc;
-}
-
-static inline int pcistg_instr(u64 data, u64 req, u64 offset)
-{
- u8 cc, status;
-
- do {
- cc = __pcistg(data, req, offset, &status);
- if (cc == 2)
- udelay(ZPCI_INSN_BUSY_DELAY);
- } while (cc == 2);
-
- if (cc)
- printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
- __func__, cc, status, req, offset);
- return (cc) ? -EIO : 0;
-}
-
-/* PCI Store Block */
-static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
-{
- u8 cc;
-
- asm volatile (
- " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
- " ipm %[cc]\n"
- " srl %[cc],28\n"
- : [cc] "=d" (cc), [req] "+d" (req)
- : [offset] "d" (offset), [data] "Q" (*data)
- : "cc");
- *status = req >> 24 & 0xff;
- return cc;
-}
-
-static inline int pcistb_instr(const u64 *data, u64 req, u64 offset)
-{
- u8 cc, status;
-
- do {
- cc = __pcistb(data, req, offset, &status);
- if (cc == 2)
- udelay(ZPCI_INSN_BUSY_DELAY);
- } while (cc == 2);
- if (cc)
- printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
- __func__, cc, status, req, offset);
- return (cc) ? -EIO : 0;
-}
+int s390pci_mod_fc(u64 req, struct zpci_fib *fib);
+int s390pci_refresh_trans(u64 fn, u64 addr, u64 range);
+int s390pci_load(u64 *data, u64 req, u64 offset);
+int s390pci_store(u64 data, u64 req, u64 offset);
+int s390pci_store_block(const u64 *data, u64 req, u64 offset);
+void set_irq_ctrl(u16 ctl, char *unused, u8 isc);
#endif
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h
index 5fd81f31d6c7..83a9caa6ae53 100644
--- a/arch/s390/include/asm/pci_io.h
+++ b/arch/s390/include/asm/pci_io.h
@@ -36,7 +36,7 @@ static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \
u64 data; \
int rc; \
\
- rc = pcilg_instr(&data, req, ZPCI_OFFSET(addr)); \
+ rc = s390pci_load(&data, req, ZPCI_OFFSET(addr)); \
if (rc) \
data = -1ULL; \
return (RETTYPE) data; \
@@ -50,7 +50,7 @@ static inline void zpci_write_##VALTYPE(VALTYPE val, \
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
u64 data = (VALTYPE) val; \
\
- pcistg_instr(data, req, ZPCI_OFFSET(addr)); \
+ s390pci_store(data, req, ZPCI_OFFSET(addr)); \
}
zpci_read(8, u64)
@@ -83,15 +83,18 @@ static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len
val = 0; /* let FW report error */
break;
}
- return pcistg_instr(val, req, offset);
+ return s390pci_store(val, req, offset);
}
static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
{
u64 data;
- u8 cc;
+ int cc;
+
+ cc = s390pci_load(&data, req, offset);
+ if (cc)
+ goto out;
- cc = pcilg_instr(&data, req, offset);
switch (len) {
case 1:
*((u8 *) dst) = (u8) data;
@@ -106,12 +109,13 @@ static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
*((u64 *) dst) = (u64) data;
break;
}
+out:
return cc;
}
static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
{
- return pcistb_instr(data, req, offset);
+ return s390pci_store_block(data, req, offset);
}
static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 4a2930844d43..b4622915bd15 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -57,6 +57,10 @@ extern unsigned long zero_page_mask;
(((unsigned long)(vaddr)) &zero_page_mask))))
#define __HAVE_COLOR_ZERO_PAGE
+/* TODO: s390 cannot support io_remap_pfn_range... */
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
#endif /* !__ASSEMBLY__ */
/*
@@ -344,6 +348,7 @@ extern unsigned long MODULES_END;
#define _REGION3_ENTRY_CO 0x100 /* change-recording override */
/* Bits in the segment table entry */
+#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */
#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */
#define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */
@@ -419,6 +424,13 @@ extern unsigned long MODULES_END;
#define __S110 PAGE_RW
#define __S111 PAGE_RW
+/*
+ * Segment entry (large page) protection definitions.
+ */
+#define SEGMENT_NONE __pgprot(_HPAGE_TYPE_NONE)
+#define SEGMENT_RO __pgprot(_HPAGE_TYPE_RO)
+#define SEGMENT_RW __pgprot(_HPAGE_TYPE_RW)
+
static inline int mm_exclusive(struct mm_struct *mm)
{
return likely(mm == current->active_mm &&
@@ -759,6 +771,8 @@ void gmap_disable(struct gmap *gmap);
int gmap_map_segment(struct gmap *gmap, unsigned long from,
unsigned long to, unsigned long length);
int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
+unsigned long __gmap_translate(unsigned long address, struct gmap *);
+unsigned long gmap_translate(unsigned long address, struct gmap *);
unsigned long __gmap_fault(unsigned long address, struct gmap *);
unsigned long gmap_fault(unsigned long address, struct gmap *);
void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
@@ -907,26 +921,6 @@ static inline pte_t pte_mkspecial(pte_t pte)
#ifdef CONFIG_HUGETLB_PAGE
static inline pte_t pte_mkhuge(pte_t pte)
{
- /*
- * PROT_NONE needs to be remapped from the pte type to the ste type.
- * The HW invalid bit is also different for pte and ste. The pte
- * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
- * bit, so we don't have to clear it.
- */
- if (pte_val(pte) & _PAGE_INVALID) {
- if (pte_val(pte) & _PAGE_SWT)
- pte_val(pte) |= _HPAGE_TYPE_NONE;
- pte_val(pte) |= _SEGMENT_ENTRY_INV;
- }
- /*
- * Clear SW pte bits, there are no SW bits in a segment table entry.
- */
- pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX | _PAGE_SWC |
- _PAGE_SWR | _PAGE_SWW);
- /*
- * Also set the change-override bit because we don't need dirty bit
- * tracking for hugetlbfs pages.
- */
pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
return pte;
}
@@ -1271,31 +1265,7 @@ static inline void __pmd_idte(unsigned long address, pmd_t *pmdp)
}
}
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
-#define SEGMENT_NONE __pgprot(_HPAGE_TYPE_NONE)
-#define SEGMENT_RO __pgprot(_HPAGE_TYPE_RO)
-#define SEGMENT_RW __pgprot(_HPAGE_TYPE_RW)
-
-#define __HAVE_ARCH_PGTABLE_DEPOSIT
-extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable);
-
-#define __HAVE_ARCH_PGTABLE_WITHDRAW
-extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm);
-
-static inline int pmd_trans_splitting(pmd_t pmd)
-{
- return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT;
-}
-
-static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp, pmd_t entry)
-{
- if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
- pmd_val(entry) |= _SEGMENT_ENTRY_CO;
- *pmdp = entry;
-}
-
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLB_PAGE)
static inline unsigned long massage_pgprot_pmd(pgprot_t pgprot)
{
/*
@@ -1316,10 +1286,11 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
return pmd;
}
-static inline pmd_t pmd_mkhuge(pmd_t pmd)
+static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot)
{
- pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE;
- return pmd;
+ pmd_t __pmd;
+ pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot);
+ return __pmd;
}
static inline pmd_t pmd_mkwrite(pmd_t pmd)
@@ -1329,6 +1300,34 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
pmd_val(pmd) &= ~_SEGMENT_ENTRY_RO;
return pmd;
}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+#define __HAVE_ARCH_PGTABLE_DEPOSIT
+extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable);
+
+#define __HAVE_ARCH_PGTABLE_WITHDRAW
+extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm);
+
+static inline int pmd_trans_splitting(pmd_t pmd)
+{
+ return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT;
+}
+
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t entry)
+{
+ if (!(pmd_val(entry) & _SEGMENT_ENTRY_INV) && MACHINE_HAS_EDAT1)
+ pmd_val(entry) |= _SEGMENT_ENTRY_CO;
+ *pmdp = entry;
+}
+
+static inline pmd_t pmd_mkhuge(pmd_t pmd)
+{
+ pmd_val(pmd) |= _SEGMENT_ENTRY_LARGE;
+ return pmd;
+}
static inline pmd_t pmd_wrprotect(pmd_t pmd)
{
@@ -1425,13 +1424,6 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
}
}
-static inline pmd_t mk_pmd_phys(unsigned long physpage, pgprot_t pgprot)
-{
- pmd_t __pmd;
- pmd_val(__pmd) = physpage + massage_pgprot_pmd(pgprot);
- return __pmd;
-}
-
#define pfn_pmd(pfn, pgprot) mk_pmd_phys(__pa((pfn) << PAGE_SHIFT), (pgprot))
#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot))
@@ -1531,7 +1523,8 @@ extern int s390_enable_sie(void);
/*
* No page table caches to initialise
*/
-#define pgtable_cache_init() do { } while (0)
+static inline void pgtable_cache_init(void) { }
+static inline void check_pgt_cache(void) { }
#include <asm-generic/pgtable.h>
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 94e749c90230..6b499870662f 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -161,7 +161,8 @@ extern unsigned long thread_saved_pc(struct task_struct *t);
extern void show_code(struct pt_regs *regs);
extern void print_fn_code(unsigned char *code, unsigned long len);
-extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]);
+extern int insn_to_mnemonic(unsigned char *instruction, char *buf,
+ unsigned int len);
unsigned long get_wchan(struct task_struct *p);
#define task_pt_regs(tsk) ((struct pt_regs *) \
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 3ee5da3bc10c..559512a455da 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -9,9 +9,7 @@
#include <uapi/asm/ptrace.h>
#ifndef __ASSEMBLY__
-#ifndef __s390x__
-#else /* __s390x__ */
-#endif /* __s390x__ */
+
extern long psw_kernel_bits;
extern long psw_user_bits;
@@ -77,8 +75,6 @@ struct per_struct_kernel {
#define PER_CONTROL_SUSPENSION 0x00400000UL
#define PER_CONTROL_ALTERATION 0x00200000UL
-#ifdef __s390x__
-#endif /* __s390x__ */
/*
* These are defined as per linux/ptrace.h, which see.
*/
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index fe7b99759e12..cd29d2f4e4f3 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -23,6 +23,7 @@
* type here is what we want [need] for both 32 bit and 64 bit systems.
*/
extern const unsigned int sys_call_table[];
+extern const unsigned int sys_call_table_emu[];
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index 9e2cfe0349c3..eb5f64d26d06 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -14,13 +14,8 @@
#define THREAD_ORDER 1
#define ASYNC_ORDER 1
#else /* CONFIG_64BIT */
-#ifndef __SMALL_STACK
#define THREAD_ORDER 2
#define ASYNC_ORDER 2
-#else
-#define THREAD_ORDER 1
-#define ASYNC_ORDER 1
-#endif
#endif /* CONFIG_64BIT */
#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
@@ -41,6 +36,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
+ unsigned long sys_call_table; /* System call table address */
unsigned int cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */
struct restart_block restart_block;
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index a6667a952969..651886353551 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -54,12 +54,4 @@
#define __ARCH_WANT_SYS_VFORK
#define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _ASM_S390_UNISTD_H_ */
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index a5ca214b34fd..3aa9f1ec5b29 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -215,12 +215,6 @@ typedef struct
unsigned long addr;
} __attribute__ ((aligned(8))) psw_t;
-typedef struct
-{
- __u32 mask;
- __u32 addr;
-} __attribute__ ((aligned(8))) psw_compat_t;
-
#ifndef __s390x__
#define PSW_MASK_PER 0x40000000UL
@@ -295,20 +289,6 @@ typedef struct
unsigned long orig_gpr2;
} s390_regs;
-typedef struct
-{
- psw_compat_t psw;
- __u32 gprs[NUM_GPRS];
- __u32 acrs[NUM_ACRS];
- __u32 orig_gpr2;
-} s390_compat_regs;
-
-typedef struct
-{
- __u32 gprs_high[NUM_GPRS];
-} s390_compat_regs_high;
-
-
/*
* Now for the user space program event recording (trace) definitions.
* The following structures are used only for the ptrace interface, don't
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index f99eea7fff0f..2dacb306835c 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -78,4 +78,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/statfs.h b/arch/s390/include/uapi/asm/statfs.h
index 5acca0a34c20..a61d538756f2 100644
--- a/arch/s390/include/uapi/asm/statfs.h
+++ b/arch/s390/include/uapi/asm/statfs.h
@@ -7,9 +7,6 @@
#ifndef _S390_STATFS_H
#define _S390_STATFS_H
-#ifndef __s390x__
-#include <asm-generic/statfs.h>
-#else
/*
* We can't use <asm-generic/statfs.h> because in 64-bit mode
* we mix ints of different sizes in our struct statfs.
@@ -21,49 +18,33 @@ typedef __kernel_fsid_t fsid_t;
#endif
struct statfs {
- int f_type;
- int f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
+ unsigned int f_type;
+ unsigned int f_bsize;
+ unsigned long f_blocks;
+ unsigned long f_bfree;
+ unsigned long f_bavail;
+ unsigned long f_files;
+ unsigned long f_ffree;
__kernel_fsid_t f_fsid;
- int f_namelen;
- int f_frsize;
- int f_flags;
- int f_spare[4];
+ unsigned int f_namelen;
+ unsigned int f_frsize;
+ unsigned int f_flags;
+ unsigned int f_spare[4];
};
struct statfs64 {
- int f_type;
- int f_bsize;
- long f_blocks;
- long f_bfree;
- long f_bavail;
- long f_files;
- long f_ffree;
+ unsigned int f_type;
+ unsigned int f_bsize;
+ unsigned long f_blocks;
+ unsigned long f_bfree;
+ unsigned long f_bavail;
+ unsigned long f_files;
+ unsigned long f_ffree;
__kernel_fsid_t f_fsid;
- int f_namelen;
- int f_frsize;
- int f_flags;
- int f_spare[4];
+ unsigned int f_namelen;
+ unsigned int f_frsize;
+ unsigned int f_flags;
+ unsigned int f_spare[4];
};
-struct compat_statfs64 {
- __u32 f_type;
- __u32 f_bsize;
- __u64 f_blocks;
- __u64 f_bfree;
- __u64 f_bavail;
- __u64 f_files;
- __u64 f_ffree;
- __kernel_fsid_t f_fsid;
- __u32 f_namelen;
- __u32 f_frsize;
- __u32 f_flags;
- __u32 f_spare[4];
-};
-
-#endif /* __s390x__ */
#endif
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 2ac311ef5c9b..1386fcaf4ef6 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -14,16 +14,25 @@ endif
CFLAGS_smp.o := -Wno-nonnull
#
+# Disable tailcall optimizations for stack / callchain walking functions
+# since this might generate broken code when accessing register 15 and
+# passing its content to other functions.
+#
+CFLAGS_stacktrace.o += -fno-optimize-sibling-calls
+CFLAGS_dumpstack.o += -fno-optimize-sibling-calls
+
+#
# Pass UTS_MACHINE for user_regset definition
#
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
-obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
- processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
- debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
- sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
+obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o
+obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
+obj-y += debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o
+obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
+obj-y += dumpstack.o
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index fface87056eb..7a82f9f70100 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -35,6 +35,7 @@ int main(void)
DEFINE(__TI_task, offsetof(struct thread_info, task));
DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
DEFINE(__TI_flags, offsetof(struct thread_info, flags));
+ DEFINE(__TI_sysc_table, offsetof(struct thread_info, sys_call_table));
DEFINE(__TI_cpu, offsetof(struct thread_info, cpu));
DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count));
DEFINE(__TI_user_timer, offsetof(struct thread_info, user_timer));
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 19f26de27fae..8b6e4f5288a2 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -288,51 +288,13 @@ asmlinkage long sys32_getegid16(void)
return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
}
-/*
- * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
- *
- * This is really horribly ugly.
- */
#ifdef CONFIG_SYSVIPC
-asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
+COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
+ unsigned long, third, compat_uptr_t, ptr)
{
if (call >> 16) /* hack for backward compatibility */
return -EINVAL;
- switch (call) {
- case SEMTIMEDOP:
- return compat_sys_semtimedop(first, compat_ptr(ptr),
- second, compat_ptr(third));
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- return sys_semtimedop(first, compat_ptr(ptr),
- second, NULL);
- case SEMGET:
- return sys_semget(first, second, third);
- case SEMCTL:
- return compat_sys_semctl(first, second, third,
- compat_ptr(ptr));
- case MSGSND:
- return compat_sys_msgsnd(first, second, third,
- compat_ptr(ptr));
- case MSGRCV:
- return compat_sys_msgrcv(first, second, 0, third,
- 0, compat_ptr(ptr));
- case MSGGET:
- return sys_msgget((key_t) first, second);
- case MSGCTL:
- return compat_sys_msgctl(first, second, compat_ptr(ptr));
- case SHMAT:
- return compat_sys_shmat(first, second, third,
- 0, compat_ptr(ptr));
- case SHMDT:
- return sys_shmdt(compat_ptr(ptr));
- case SHMGET:
- return sys_shmget(first, (unsigned)second, third);
- case SHMCTL:
- return compat_sys_shmctl(first, second, compat_ptr(ptr));
- }
-
- return -ENOSYS;
+ return compat_sys_ipc(call, first, second, third, ptr, third);
}
#endif
@@ -373,48 +335,6 @@ asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 coun
return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
}
-asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, size_t count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd,
- offset ? (off_t __force __user *) &of : NULL, count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
-
- return ret;
-}
-
-asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
- compat_loff_t __user *offset, s32 count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- loff_t lof;
-
- if (offset && get_user(lof, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile64(out_fd, in_fd,
- offset ? (loff_t __force __user *) &lof : NULL,
- count);
- set_fs(old_fs);
-
- if (offset && put_user(lof, offset))
- return -EFAULT;
-
- return ret;
-}
-
struct stat64_emu31 {
unsigned long long st_dev;
unsigned int __pad1;
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 00d92a5a6f6c..976518c0592a 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -94,7 +94,6 @@ long sys32_getuid16(void);
long sys32_geteuid16(void);
long sys32_getgid16(void);
long sys32_getegid16(void);
-long sys32_ipc(u32 call, int first, int second, int third, u32 ptr);
long sys32_truncate64(const char __user * path, unsigned long high,
unsigned long low);
long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low);
@@ -106,10 +105,6 @@ long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
size_t count, u32 poshi, u32 poslo);
compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count);
-long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
- size_t count);
-long sys32_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset,
- s32 count);
long sys32_stat64(const char __user * filename, struct stat64_emu31 __user * statbuf);
long sys32_lstat64(const char __user * filename,
struct stat64_emu31 __user * statbuf);
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 6de049fbe62d..c439ac9ced09 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -362,6 +362,7 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
/* set extra registers only for synchronous signals */
regs->gprs[4] = regs->int_code & 127;
regs->gprs[5] = regs->int_parm_long;
+ regs->gprs[6] = task_thread_info(current)->last_break;
}
/* Place signal number on stack to allow backtrace from handler. */
@@ -421,6 +422,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (__force __u64) &frame->info;
regs->gprs[4] = (__force __u64) &frame->uc;
+ regs->gprs[5] = task_thread_info(current)->last_break;
return 0;
give_sigsegv:
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 4d720a6a6b25..2d72d9e96c15 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -258,11 +258,6 @@ ENTRY(sys32_mmap2_wrapper)
llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
jg sys32_mmap2 # branch to system call
-ENTRY(compat_sys_getrusage_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct rusage_emu31 *
- jg compat_sys_getrusage # branch to system call
-
ENTRY(compat_sys_gettimeofday_wrapper)
llgtr %r2,%r2 # struct timeval_emu31 *
llgtr %r3,%r3 # struct timezone *
@@ -393,14 +388,6 @@ ENTRY(compat_sys_sysinfo_wrapper)
llgtr %r2,%r2 # struct sysinfo_emu31 *
jg compat_sys_sysinfo # branch to system call
-ENTRY(sys32_ipc_wrapper)
- llgfr %r2,%r2 # uint
- lgfr %r3,%r3 # int
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- llgfr %r6,%r6 # u32
- jg sys32_ipc # branch to system call
-
ENTRY(sys32_fsync_wrapper)
llgfr %r2,%r2 # unsigned int
jg sys_fsync # branch to system call
@@ -666,13 +653,6 @@ ENTRY(sys32_capset_wrapper)
llgtr %r3,%r3 # const cap_user_data_t
jg sys_capset # branch to system call
-ENTRY(sys32_sendfile_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # __kernel_off_emu31_t *
- llgfr %r5,%r5 # size_t
- jg sys32_sendfile # branch to system call
-
#sys32_vfork_wrapper # done in vfork_glue
ENTRY(sys32_truncate64_wrapper)
@@ -938,13 +918,6 @@ ENTRY(sys_epoll_wait_wrapper)
lgfr %r5,%r5 # int
jg sys_epoll_wait # branch to system call
-ENTRY(sys32_lookup_dcookie_wrapper)
- sllg %r2,%r2,32 # get high word of 64bit dcookie
- or %r2,%r3 # get low word of 64bit dcookie
- llgtr %r3,%r4 # char *
- llgfr %r4,%r5 # size_t
- jg sys_lookup_dcookie
-
ENTRY(sys32_fadvise64_wrapper)
lgfr %r2,%r2 # int
sllg %r3,%r3,32 # get high word of 64bit loff_t
@@ -1264,29 +1237,12 @@ ENTRY(sys_tee_wrapper)
llgfr %r5,%r5 # unsigned int
jg sys_tee
-ENTRY(compat_sys_vmsplice_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_iovec *
- llgfr %r4,%r4 # unsigned int
- llgfr %r5,%r5 # unsigned int
- jg compat_sys_vmsplice
-
ENTRY(sys_getcpu_wrapper)
llgtr %r2,%r2 # unsigned *
llgtr %r3,%r3 # unsigned *
llgtr %r4,%r4 # struct getcpu_cache *
jg sys_getcpu
-ENTRY(compat_sys_epoll_pwait_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct compat_epoll_event *
- lgfr %r4,%r4 # int
- lgfr %r5,%r5 # int
- llgtr %r6,%r6 # compat_sigset_t *
- llgf %r0,164(%r15) # compat_size_t
- stg %r0,160(%r15)
- jg compat_sys_epoll_pwait
-
ENTRY(compat_sys_utimes_wrapper)
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct compat_timeval *
@@ -1299,12 +1255,6 @@ ENTRY(compat_sys_utimensat_wrapper)
lgfr %r5,%r5 # int
jg compat_sys_utimensat
-ENTRY(compat_sys_signalfd_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_sigset_t *
- llgfr %r4,%r4 # compat_size_t
- jg compat_sys_signalfd
-
ENTRY(sys_eventfd_wrapper)
llgfr %r2,%r2 # unsigned int
jg sys_eventfd
@@ -1323,13 +1273,6 @@ ENTRY(sys_timerfd_create_wrapper)
lgfr %r3,%r3 # int
jg sys_timerfd_create
-ENTRY(compat_sys_signalfd4_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # compat_sigset_t *
- llgfr %r4,%r4 # compat_size_t
- lgfr %r5,%r5 # int
- jg compat_sys_signalfd4
-
ENTRY(sys_eventfd2_wrapper)
llgfr %r2,%r2 # unsigned int
lgfr %r3,%r3 # int
@@ -1361,13 +1304,6 @@ ENTRY(sys32_readahead_wrapper)
lgfr %r5,%r5 # s32
jg sys32_readahead # branch to system call
-ENTRY(sys32_sendfile64_wrapper)
- lgfr %r2,%r2 # int
- lgfr %r3,%r3 # int
- llgtr %r4,%r4 # compat_loff_t *
- lgfr %r5,%r5 # s32
- jg sys32_sendfile64 # branch to system call
-
ENTRY(sys_tkill_wrapper)
lgfr %r2,%r2 # pid_t
lgfr %r3,%r3 # int
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 3ad5e9540160..7f4a4a8c847c 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1696,14 +1696,15 @@ static struct insn *find_insn(unsigned char *code)
* insn_to_mnemonic - decode an s390 instruction
* @instruction: instruction to decode
* @buf: buffer to fill with mnemonic
+ * @len: length of buffer
*
* Decode the instruction at @instruction and store the corresponding
- * mnemonic into @buf.
+ * mnemonic into @buf of length @len.
* @buf is left unchanged if the instruction could not be decoded.
* Returns:
* %0 on success, %-ENOENT if the instruction was not found.
*/
-int insn_to_mnemonic(unsigned char *instruction, char buf[8])
+int insn_to_mnemonic(unsigned char *instruction, char *buf, unsigned int len)
{
struct insn *insn;
@@ -1711,10 +1712,10 @@ int insn_to_mnemonic(unsigned char *instruction, char buf[8])
if (!insn)
return -ENOENT;
if (insn->name[0] == '\0')
- snprintf(buf, 8, "%s",
+ snprintf(buf, len, "%s",
long_insn_name[(int) insn->name[1]]);
else
- snprintf(buf, 8, "%.5s", insn->name);
+ snprintf(buf, len, "%.5s", insn->name);
return 0;
}
EXPORT_SYMBOL_GPL(insn_to_mnemonic);
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c
new file mode 100644
index 000000000000..298297477257
--- /dev/null
+++ b/arch/s390/kernel/dumpstack.c
@@ -0,0 +1,212 @@
+/*
+ * Stack dumping functions
+ *
+ * Copyright IBM Corp. 1999, 2013
+ */
+
+#include <linux/kallsyms.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/utsname.h>
+#include <linux/export.h>
+#include <linux/kdebug.h>
+#include <linux/ptrace.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/debug.h>
+#include <asm/ipl.h>
+
+#ifndef CONFIG_64BIT
+#define LONG "%08lx "
+#define FOURLONG "%08lx %08lx %08lx %08lx\n"
+static int kstack_depth_to_print = 12;
+#else /* CONFIG_64BIT */
+#define LONG "%016lx "
+#define FOURLONG "%016lx %016lx %016lx %016lx\n"
+static int kstack_depth_to_print = 20;
+#endif /* CONFIG_64BIT */
+
+/*
+ * For show_trace we have tree different stack to consider:
+ * - the panic stack which is used if the kernel stack has overflown
+ * - the asynchronous interrupt stack (cpu related)
+ * - the synchronous kernel stack (process related)
+ * The stack trace can start at any of the three stack and can potentially
+ * touch all of them. The order is: panic stack, async stack, sync stack.
+ */
+static unsigned long
+__show_trace(unsigned long sp, unsigned long low, unsigned long high)
+{
+ struct stack_frame *sf;
+ struct pt_regs *regs;
+
+ while (1) {
+ sp = sp & PSW_ADDR_INSN;
+ if (sp < low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+ print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
+ /* Follow the backchain. */
+ while (1) {
+ low = sp;
+ sp = sf->back_chain & PSW_ADDR_INSN;
+ if (!sp)
+ break;
+ if (sp <= low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+ print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
+ }
+ /* Zero backchain detected, check for interrupt frame. */
+ sp = (unsigned long) (sf + 1);
+ if (sp <= low || sp > high - sizeof(*regs))
+ return sp;
+ regs = (struct pt_regs *) sp;
+ printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
+ print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
+ low = sp;
+ sp = regs->gprs[15];
+ }
+}
+
+static void show_trace(struct task_struct *task, unsigned long *stack)
+{
+ register unsigned long __r15 asm ("15");
+ unsigned long sp;
+
+ sp = (unsigned long) stack;
+ if (!sp)
+ sp = task ? task->thread.ksp : __r15;
+ printk("Call Trace:\n");
+#ifdef CONFIG_CHECK_STACK
+ sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
+ S390_lowcore.panic_stack);
+#endif
+ sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack);
+ if (task)
+ __show_trace(sp, (unsigned long) task_stack_page(task),
+ (unsigned long) task_stack_page(task) + THREAD_SIZE);
+ else
+ __show_trace(sp, S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE);
+ if (!task)
+ task = current;
+ debug_show_held_locks(task);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ register unsigned long *__r15 asm ("15");
+ unsigned long *stack;
+ int i;
+
+ if (!sp)
+ stack = task ? (unsigned long *) task->thread.ksp : __r15;
+ else
+ stack = sp;
+
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ if ((i * sizeof(long) % 32) == 0)
+ printk("%s ", i == 0 ? "" : "\n");
+ printk(LONG, *stack++);
+ }
+ printk("\n");
+ show_trace(task, sp);
+}
+
+static void show_last_breaking_event(struct pt_regs *regs)
+{
+#ifdef CONFIG_64BIT
+ printk("Last Breaking-Event-Address:\n");
+ printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
+ print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
+#endif
+}
+
+static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
+{
+ return (regs->psw.mask & bits) / ((~bits + 1) & bits);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+ char *mode;
+
+ mode = user_mode(regs) ? "User" : "Krnl";
+ printk("%s PSW : %p %p",
+ mode, (void *) regs->psw.mask,
+ (void *) regs->psw.addr);
+ print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
+ printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
+ "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
+ mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
+ mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
+ mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
+ mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
+ mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
+#ifdef CONFIG_64BIT
+ printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
+#endif
+ printk("\n%s GPRS: " FOURLONG, mode,
+ regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
+ printk(" " FOURLONG,
+ regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
+ printk(" " FOURLONG,
+ regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
+ printk(" " FOURLONG,
+ regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
+ show_code(regs);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ show_regs_print_info(KERN_DEFAULT);
+ show_registers(regs);
+ /* Show stack backtrace if pt_regs is from kernel mode */
+ if (!user_mode(regs))
+ show_trace(NULL, (unsigned long *) regs->gprs[15]);
+ show_last_breaking_event(regs);
+}
+
+static DEFINE_SPINLOCK(die_lock);
+
+void die(struct pt_regs *regs, const char *str)
+{
+ static int die_counter;
+
+ oops_enter();
+ lgr_info_log();
+ debug_stop_all();
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ bust_spinlocks(1);
+ printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+ printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+ printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ printk("DEBUG_PAGEALLOC");
+#endif
+ printk("\n");
+ notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
+ print_modules();
+ show_regs(regs);
+ bust_spinlocks(0);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+ spin_unlock_irq(&die_lock);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+ if (panic_on_oops)
+ panic("Fatal exception: panic_on_oops");
+ oops_exit();
+ do_exit(SIGSEGV);
+}
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 94feff7d6132..4d5e6f8a7978 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -45,6 +45,7 @@ _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
+STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
#define BASED(name) name-system_call(%r13)
@@ -97,10 +98,10 @@ STACK_SIZE = 1 << STACK_SHIFT
sra %r14,\shift
jnz 1f
CHECK_STACK 1<<\shift,\savearea
+ ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 2f
1: l %r15,\stack # load target stack
-2: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
+2: la %r11,STACK_FRAME_OVERHEAD(%r15)
.endm
.macro ADD64 high,low,timer
@@ -150,7 +151,7 @@ ENTRY(__switch_to)
l %r4,__THREAD_info(%r2) # get thread_info of prev
l %r5,__THREAD_info(%r3) # get thread_info of next
lr %r15,%r5
- ahi %r15,STACK_SIZE # end of kernel stack of next
+ ahi %r15,STACK_INIT # end of kernel stack of next
st %r3,__LC_CURRENT # store task struct of next
st %r5,__LC_THREAD_INFO # store thread info of next
st %r15,__LC_KERNEL_STACK # store end of kernel stack
@@ -178,7 +179,6 @@ sysc_stm:
l %r13,__LC_SVC_NEW_PSW+4
sysc_per:
l %r15,__LC_KERNEL_STACK
- ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
sysc_vtime:
UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER
@@ -188,6 +188,7 @@ sysc_vtime:
mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
sysc_do_svc:
oi __TI_flags+3(%r12),_TIF_SYSCALL
+ l %r10,__TI_sysc_table(%r12) # 31 bit system call table
lh %r8,__PT_INT_CODE+2(%r11)
sla %r8,2 # shift and test for svc0
jnz sysc_nr_ok
@@ -198,7 +199,6 @@ sysc_do_svc:
lr %r8,%r1
sla %r8,2
sysc_nr_ok:
- l %r10,BASED(.Lsys_call_table) # 31 bit system call table
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
st %r2,__PT_ORIG_GPR2(%r11)
st %r7,STACK_FRAME_OVERHEAD(%r15)
@@ -359,11 +359,11 @@ ENTRY(pgm_check_handler)
tm __LC_PGM_ILC+3,0x80 # check for per exception
jnz pgm_svcper # -> single stepped svc
0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
+ ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 2f
1: UPDATE_VTIME %r14,%r15,__LC_SYNC_ENTER_TIMER
l %r15,__LC_KERNEL_STACK
-2: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
+2: la %r11,STACK_FRAME_OVERHEAD(%r15)
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC
stm %r8,%r9,__PT_PSW(%r11)
@@ -485,7 +485,6 @@ io_work:
#
io_work_user:
l %r1,__LC_KERNEL_STACK
- ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1)
la %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -646,7 +645,6 @@ mcck_skip:
tm __PT_PSW+1(%r11),0x01 # returning to user ?
jno mcck_return
l %r1,__LC_KERNEL_STACK # switch to kernel stack
- ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1)
la %r11,STACK_FRAME_OVERHEAD(%r15)
@@ -674,6 +672,7 @@ mcck_panic:
sra %r14,PAGE_SHIFT
jz 0f
l %r15,__LC_PANIC_STACK
+ j mcck_skip
0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j mcck_skip
@@ -714,12 +713,10 @@ ENTRY(restart_int_handler)
*/
stack_overflow:
l %r15,__LC_PANIC_STACK # change to panic stack
- ahi %r15,-__PT_SIZE # create pt_regs
- stm %r0,%r7,__PT_R0(%r15)
- stm %r8,%r9,__PT_PSW(%r15)
+ la %r11,STACK_FRAME_OVERHEAD(%r15)
+ stm %r0,%r7,__PT_R0(%r11)
+ stm %r8,%r9,__PT_PSW(%r11)
mvc __PT_R8(32,%r11),0(%r14)
- lr %r15,%r11
- ahi %r15,-STACK_FRAME_OVERHEAD
l %r1,BASED(1f)
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
lr %r2,%r11 # pass pointer to pt_regs
@@ -799,15 +796,14 @@ cleanup_system_call:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
# set up saved register 11
l %r15,__LC_KERNEL_STACK
- ahi %r15,-__PT_SIZE
- st %r15,12(%r11) # r11 pt_regs pointer
+ la %r9,STACK_FRAME_OVERHEAD(%r15)
+ st %r9,12(%r11) # r11 pt_regs pointer
# fill pt_regs
- mvc __PT_R8(32,%r15),__LC_SAVE_AREA_SYNC
- stm %r0,%r7,__PT_R0(%r15)
- mvc __PT_PSW(8,%r15),__LC_SVC_OLD_PSW
- mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC
+ mvc __PT_R8(32,%r9),__LC_SAVE_AREA_SYNC
+ stm %r0,%r7,__PT_R0(%r9)
+ mvc __PT_PSW(8,%r9),__LC_SVC_OLD_PSW
+ mvc __PT_INT_CODE(4,%r9),__LC_SVC_ILC
# setup saved register 15
- ahi %r15,-STACK_FRAME_OVERHEAD
st %r15,28(%r11) # r15 stack pointer
# set new psw address and exit
l %r9,BASED(cleanup_table+4) # sysc_do_svc + 0x80000000
@@ -910,7 +906,6 @@ cleanup_idle_wait:
.Ltrace_enter: .long do_syscall_trace_enter
.Ltrace_exit: .long do_syscall_trace_exit
.Lschedule_tail: .long schedule_tail
-.Lsys_call_table: .long sys_call_table
.Lsysc_per: .long sysc_per + 0x80000000
#ifdef CONFIG_TRACE_IRQFLAGS
.Lhardirqs_on: .long trace_hardirqs_on_caller
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index c3a736a3ed44..aa0ab02e9595 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -7,6 +7,7 @@
#include <asm/cputime.h>
extern void *restart_stack;
+extern unsigned long suspend_zero_pages;
void system_call(void);
void pgm_check_handler(void);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 2e6d60c55f90..4c17eece707e 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -39,6 +39,7 @@ __PT_R15 = __PT_GPRS + 120
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
+STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_PER_TRAP )
@@ -124,10 +125,10 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
srag %r14,%r14,\shift
jnz 1f
CHECK_STACK 1<<\shift,\savearea
+ aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 2f
1: lg %r15,\stack # load target stack
-2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
+2: la %r11,STACK_FRAME_OVERHEAD(%r15)
.endm
.macro UPDATE_VTIME scratch,enter_timer
@@ -177,7 +178,7 @@ ENTRY(__switch_to)
lg %r4,__THREAD_info(%r2) # get thread_info of prev
lg %r5,__THREAD_info(%r3) # get thread_info of next
lgr %r15,%r5
- aghi %r15,STACK_SIZE # end of kernel stack of next
+ aghi %r15,STACK_INIT # end of kernel stack of next
stg %r3,__LC_CURRENT # store task struct of next
stg %r5,__LC_THREAD_INFO # store thread info of next
stg %r15,__LC_KERNEL_STACK # store end of kernel stack
@@ -203,10 +204,8 @@ sysc_stmg:
stmg %r8,%r15,__LC_SAVE_AREA_SYNC
lg %r10,__LC_LAST_BREAK
lg %r12,__LC_THREAD_INFO
- larl %r13,system_call
sysc_per:
lg %r15,__LC_KERNEL_STACK
- aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs
sysc_vtime:
UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER
@@ -217,6 +216,7 @@ sysc_vtime:
mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC
sysc_do_svc:
oi __TI_flags+7(%r12),_TIF_SYSCALL
+ lg %r10,__TI_sysc_table(%r12) # address of system call table
llgh %r8,__PT_INT_CODE+2(%r11)
slag %r8,%r8,2 # shift and test for svc 0
jnz sysc_nr_ok
@@ -227,13 +227,6 @@ sysc_do_svc:
sth %r1,__PT_INT_CODE+2(%r11)
slag %r8,%r1,2
sysc_nr_ok:
- larl %r10,sys_call_table # 64 bit system call table
-#ifdef CONFIG_COMPAT
- tm __TI_flags+5(%r12),(_TIF_31BIT>>16)
- jno sysc_noemu
- larl %r10,sys_call_table_emu # 31 bit system call table
-sysc_noemu:
-#endif
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
stg %r2,__PT_ORIG_GPR2(%r11)
stg %r7,STACK_FRAME_OVERHEAD(%r15)
@@ -389,6 +382,7 @@ ENTRY(pgm_check_handler)
tm __LC_PGM_ILC+3,0x80 # check for per exception
jnz pgm_svcper # -> single stepped svc
0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC
+ aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
j 2f
1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER
LAST_BREAK %r14
@@ -398,8 +392,7 @@ ENTRY(pgm_check_handler)
tm __LC_PGM_ILC+2,0x02 # check for transaction abort
jz 2f
mvc __THREAD_trap_tdb(256,%r14),0(%r13)
-2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
- la %r11,STACK_FRAME_OVERHEAD(%r15)
+2: la %r11,STACK_FRAME_OVERHEAD(%r15)
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
stmg %r8,%r9,__PT_PSW(%r11)
@@ -526,7 +519,6 @@ io_work:
#
io_work_user:
lg %r1,__LC_KERNEL_STACK
- aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
la %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -688,7 +680,6 @@ mcck_skip:
tm __PT_PSW+1(%r11),0x01 # returning to user ?
jno mcck_return
lg %r1,__LC_KERNEL_STACK # switch to kernel stack
- aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11)
xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1)
la %r11,STACK_FRAME_OVERHEAD(%r1)
@@ -755,14 +746,12 @@ ENTRY(restart_int_handler)
* Setup a pt_regs so that show_trace can provide a good call trace.
*/
stack_overflow:
- lg %r11,__LC_PANIC_STACK # change to panic stack
- aghi %r11,-__PT_SIZE # create pt_regs
+ lg %r15,__LC_PANIC_STACK # change to panic stack
+ la %r11,STACK_FRAME_OVERHEAD(%r15)
stmg %r0,%r7,__PT_R0(%r11)
stmg %r8,%r9,__PT_PSW(%r11)
mvc __PT_R8(64,%r11),0(%r14)
stg %r10,__PT_ORIG_GPR2(%r11) # store last break to orig_gpr2
- lgr %r15,%r11
- aghi %r15,-STACK_FRAME_OVERHEAD
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
lgr %r2,%r11 # pass pointer to pt_regs
jg kernel_stack_overflow
@@ -846,15 +835,14 @@ cleanup_system_call:
mvc __TI_last_break(8,%r12),16(%r11)
0: # set up saved register r11
lg %r15,__LC_KERNEL_STACK
- aghi %r15,-__PT_SIZE
- stg %r15,24(%r11) # r11 pt_regs pointer
+ la %r9,STACK_FRAME_OVERHEAD(%r15)
+ stg %r9,24(%r11) # r11 pt_regs pointer
# fill pt_regs
- mvc __PT_R8(64,%r15),__LC_SAVE_AREA_SYNC
- stmg %r0,%r7,__PT_R0(%r15)
- mvc __PT_PSW(16,%r15),__LC_SVC_OLD_PSW
- mvc __PT_INT_CODE(4,%r15),__LC_SVC_ILC
+ mvc __PT_R8(64,%r9),__LC_SAVE_AREA_SYNC
+ stmg %r0,%r7,__PT_R0(%r9)
+ mvc __PT_PSW(16,%r9),__LC_SVC_OLD_PSW
+ mvc __PT_INT_CODE(4,%r9),__LC_SVC_ILC
# setup saved register r15
- aghi %r15,-STACK_FRAME_OVERHEAD
stg %r15,56(%r11) # r15 stack pointer
# set new psw address and exit
larl %r9,sysc_do_svc
@@ -1011,6 +999,7 @@ sys_call_table:
#ifdef CONFIG_COMPAT
#define SYSCALL(esa,esame,emu) .long emu
+ .globl sys_call_table_emu
sys_call_table_emu:
#include "syscalls.S"
#undef SYSCALL
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index 1580af3db31a..f7fb58903f6a 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -33,7 +33,7 @@ struct irq_class {
};
/*
- * The list of "main" irq classes on s390. This is the list of interrrupts
+ * The list of "main" irq classes on s390. This is the list of interrupts
* that appear both in /proc/stat ("intr" line) and /proc/interrupts.
* Historically only external and I/O interrupts have been part of /proc/stat.
* We can't add the split external and I/O sub classes since the first field
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index b3de27700016..ac2178161ec3 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -13,6 +13,7 @@
#include <linux/reboot.h>
#include <linux/ftrace.h>
#include <linux/debug_locks.h>
+#include <linux/suspend.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
@@ -67,6 +68,35 @@ void setup_regs(void)
memcpy((void *) SAVE_AREA_BASE, (void *) sa, sizeof(struct save_area));
}
+/*
+ * PM notifier callback for kdump
+ */
+static int machine_kdump_pm_cb(struct notifier_block *nb, unsigned long action,
+ void *ptr)
+{
+ switch (action) {
+ case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ if (crashk_res.start)
+ crash_map_reserved_pages();
+ break;
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ if (crashk_res.start)
+ crash_unmap_reserved_pages();
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+static int __init machine_kdump_pm_init(void)
+{
+ pm_notifier(machine_kdump_pm_cb, 0);
+ return 0;
+}
+arch_initcall(machine_kdump_pm_init);
#endif
/*
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 536d64579d9a..2bc3eddae34a 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -61,18 +61,8 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
return sf->gprs[8];
}
-/*
- * The idle loop on a S390...
- */
-static void default_idle(void)
+void arch_cpu_idle(void)
{
- if (cpu_is_offline(smp_processor_id()))
- cpu_die();
- local_irq_disable();
- if (need_resched()) {
- local_irq_enable();
- return;
- }
local_mcck_disable();
if (test_thread_flag(TIF_MCCK_PENDING)) {
local_mcck_enable();
@@ -83,19 +73,15 @@ static void default_idle(void)
vtime_stop_cpu();
}
-void cpu_idle(void)
+void arch_cpu_idle_exit(void)
{
- for (;;) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched() && !test_thread_flag(TIF_MCCK_PENDING))
- default_idle();
- rcu_idle_exit();
- tick_nohz_idle_exit();
- if (test_thread_flag(TIF_MCCK_PENDING))
- s390_handle_mcck();
- schedule_preempt_disabled();
- }
+ if (test_thread_flag(TIF_MCCK_PENDING))
+ s390_handle_mcck();
+}
+
+void arch_cpu_idle_dead(void)
+{
+ cpu_die();
}
extern void __kprobes kernel_thread_starter(void);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 29268859d8ee..0f419c5765c8 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -377,11 +377,14 @@ static void __init setup_lowcore(void)
PSW_MASK_DAT | PSW_MASK_MCHECK;
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
lc->clock_comparator = -1ULL;
- lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
+ lc->kernel_stack = ((unsigned long) &init_thread_union)
+ + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->async_stack = (unsigned long)
- __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
+ __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0)
+ + ASYNC_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->panic_stack = (unsigned long)
- __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0)
+ + PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
lc->thread_info = (unsigned long) &init_thread_union;
lc->machine_flags = S390_lowcore.machine_flags;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 549c9d173c0f..8074cb4b7cbf 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -181,8 +181,10 @@ static int __cpuinit pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
lc = pcpu->lowcore;
memcpy(lc, &S390_lowcore, 512);
memset((char *) lc + 512, 0, sizeof(*lc) - 512);
- lc->async_stack = pcpu->async_stack + ASYNC_SIZE;
- lc->panic_stack = pcpu->panic_stack + PAGE_SIZE;
+ lc->async_stack = pcpu->async_stack + ASYNC_SIZE
+ - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
+ lc->panic_stack = pcpu->panic_stack + PAGE_SIZE
+ - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->cpu_nr = cpu;
#ifndef CONFIG_64BIT
if (MACHINE_HAS_IEEE) {
@@ -253,7 +255,8 @@ static void pcpu_attach_task(struct pcpu *pcpu, struct task_struct *tsk)
struct _lowcore *lc = pcpu->lowcore;
struct thread_info *ti = task_thread_info(tsk);
- lc->kernel_stack = (unsigned long) task_stack_page(tsk) + THREAD_SIZE;
+ lc->kernel_stack = (unsigned long) task_stack_page(tsk)
+ + THREAD_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
lc->thread_info = (unsigned long) task_thread_info(tsk);
lc->current_task = (unsigned long) tsk;
lc->user_timer = ti->user_timer;
@@ -711,8 +714,7 @@ static void __cpuinit smp_start_secondary(void *cpuvoid)
set_cpu_online(smp_processor_id(), true);
inc_irq_stat(CPU_RST);
local_irq_enable();
- /* cpu_idle will call schedule for us */
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/* Upping and downing of CPUs */
@@ -810,8 +812,10 @@ void __init smp_prepare_boot_cpu(void)
pcpu->state = CPU_STATE_CONFIGURED;
pcpu->address = boot_cpu_address;
pcpu->lowcore = (struct _lowcore *)(unsigned long) store_prefix();
- pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE;
- pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE;
+ pcpu->async_stack = S390_lowcore.async_stack - ASYNC_SIZE
+ + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
+ pcpu->panic_stack = S390_lowcore.panic_stack - PAGE_SIZE
+ + STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
S390_lowcore.percpu_offset = __per_cpu_offset[0];
smp_cpu_set_polarization(0, POLARIZATION_UNKNOWN);
set_cpu_present(0, true);
diff --git a/arch/s390/kernel/suspend.c b/arch/s390/kernel/suspend.c
index aa1494d0e380..c479d2f9605b 100644
--- a/arch/s390/kernel/suspend.c
+++ b/arch/s390/kernel/suspend.c
@@ -41,6 +41,7 @@ struct page_key_data {
static struct page_key_data *page_key_data;
static struct page_key_data *page_key_rp, *page_key_wp;
static unsigned long page_key_rx, page_key_wx;
+unsigned long suspend_zero_pages;
/*
* For each page in the hibernation image one additional byte is
@@ -149,6 +150,36 @@ int pfn_is_nosave(unsigned long pfn)
return 0;
}
+/*
+ * PM notifier callback for suspend
+ */
+static int suspend_pm_cb(struct notifier_block *nb, unsigned long action,
+ void *ptr)
+{
+ switch (action) {
+ case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ suspend_zero_pages = __get_free_pages(GFP_KERNEL, LC_ORDER);
+ if (!suspend_zero_pages)
+ return NOTIFY_BAD;
+ break;
+ case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ free_pages(suspend_zero_pages, LC_ORDER);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+static int __init suspend_pm_init(void)
+{
+ pm_notifier(suspend_pm_cb, 0);
+ return 0;
+}
+arch_initcall(suspend_pm_init);
+
void save_processor_state(void)
{
/* swsusp_arch_suspend() actually saves all cpu register contents.
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index d4ca4e0617b5..c487be4cfc81 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -36,8 +36,8 @@ ENTRY(swsusp_arch_suspend)
/* Store prefix register on stack */
stpx __SF_EMPTY(%r15)
- /* Save prefix register contents for lowcore */
- llgf %r4,__SF_EMPTY(%r15)
+ /* Save prefix register contents for lowcore copy */
+ llgf %r10,__SF_EMPTY(%r15)
/* Get pointer to save area */
lghi %r1,0x1000
@@ -91,7 +91,18 @@ ENTRY(swsusp_arch_suspend)
xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
spx __SF_EMPTY(%r15)
+ /* Save absolute zero pages */
+ larl %r2,suspend_zero_pages
+ lg %r2,0(%r2)
+ lghi %r4,0
+ lghi %r3,2*PAGE_SIZE
+ lghi %r5,2*PAGE_SIZE
+1: mvcle %r2,%r4,0
+ jo 1b
+
+ /* Copy lowcore to absolute zero lowcore */
lghi %r2,0
+ lgr %r4,%r10
lghi %r3,2*PAGE_SIZE
lghi %r5,2*PAGE_SIZE
1: mvcle %r2,%r4,0
@@ -248,8 +259,20 @@ restore_registers:
/* Load old stack */
lg %r15,0x2f8(%r13)
+ /* Save prefix register */
+ mvc __SF_EMPTY(4,%r15),0x318(%r13)
+
+ /* Restore absolute zero pages */
+ lghi %r2,0
+ larl %r4,suspend_zero_pages
+ lg %r4,0(%r4)
+ lghi %r3,2*PAGE_SIZE
+ lghi %r5,2*PAGE_SIZE
+1: mvcle %r2,%r4,0
+ jo 1b
+
/* Restore prefix register */
- spx 0x318(%r13)
+ spx __SF_EMPTY(%r15)
/* Activate DAT */
stosm __SF_EMPTY(%r15),0x04
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index d0964d22adb5..23eb222c1658 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -132,19 +132,9 @@ SYSCALL_DEFINE1(s390_fadvise64_64, struct fadvise64_64_args __user *, args)
* to
* %r2: fd, %r3: mode, %r4/%r5: offset, 96(%r15)-103(%r15): len
*/
-SYSCALL_DEFINE(s390_fallocate)(int fd, int mode, loff_t offset,
- u32 len_high, u32 len_low)
+SYSCALL_DEFINE5(s390_fallocate, int, fd, int, mode, loff_t, offset,
+ u32, len_high, u32, len_low)
{
return sys_fallocate(fd, mode, offset, ((u64)len_high << 32) | len_low);
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_s390_fallocate(long fd, long mode, loff_t offset,
- long len_high, long len_low)
-{
- return SYSC_s390_fallocate((int) fd, (int) mode, offset,
- (u32) len_high, (u32) len_low);
-}
-SYSCALL_ALIAS(sys_s390_fallocate, SyS_s390_fallocate);
-#endif
-
#endif
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 84e8b1a6bfcb..9f214e992eed 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -85,7 +85,7 @@ SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
-SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage_wrapper)
+SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage)
SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
@@ -118,14 +118,14 @@ SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
NI_SYSCALL /* old uname syscall */
-SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,sys32_lookup_dcookie_wrapper) /* 110 */
+SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,compat_sys_lookup_dcookie) /* 110 */
SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
NI_SYSCALL /* old "idle" system call */
NI_SYSCALL /* vm86old for i386 */
SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4)
SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
-SYSCALL(sys_s390_ipc,sys_s390_ipc,sys32_ipc_wrapper)
+SYSCALL(sys_s390_ipc,sys_s390_ipc,compat_sys_s390_ipc)
SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */
@@ -195,7 +195,7 @@ SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
SYSCALL(sys_sigaltstack,sys_sigaltstack,compat_sys_sigaltstack)
-SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
+SYSCALL(sys_sendfile,sys_sendfile64,compat_sys_sendfile)
NI_SYSCALL /* streams1 */
NI_SYSCALL /* streams2 */
SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */
@@ -231,7 +231,7 @@ SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */
SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
SYSCALL(sys_readahead,sys_readahead,sys32_readahead_wrapper)
-SYSCALL(sys_sendfile64,sys_ni_syscall,sys32_sendfile64_wrapper)
+SYSCALL(sys_sendfile64,sys_ni_syscall,compat_sys_sendfile64)
SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */
SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
@@ -317,20 +317,20 @@ SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list)
SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
-SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper)
+SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice)
NI_SYSCALL /* 310 sys_move_pages */
SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
-SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait_wrapper)
+SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait)
SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
SYSCALL(sys_s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
-SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
+SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd)
NI_SYSCALL /* 317 old sys_timer_fd */
SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime) /* 320 */
SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime)
-SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4_wrapper)
+SYSCALL(sys_signalfd4,sys_signalfd4,compat_sys_signalfd4)
SYSCALL(sys_eventfd2,sys_eventfd2,sys_eventfd2_wrapper)
SYSCALL(sys_inotify_init1,sys_inotify_init1,sys_inotify_init1_wrapper)
SYSCALL(sys_pipe2,sys_pipe2,sys_pipe2_wrapper) /* 325 */
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 13dd63fba367..c5762324d9ee 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -12,49 +12,16 @@
* 'Traps.c' handles hardware traps and faults after we have saved some
* state in 'asm.s'.
*/
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
#include <linux/ptrace.h>
-#include <linux/timer.h>
+#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/kdebug.h>
-#include <linux/kallsyms.h>
-#include <linux/reboot.h>
-#include <linux/kprobes.h>
-#include <linux/bug.h>
-#include <linux/utsname.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-#include <asm/mathemu.h>
-#include <asm/cpcmd.h>
-#include <asm/lowcore.h>
-#include <asm/debug.h>
-#include <asm/ipl.h>
#include "entry.h"
int show_unhandled_signals = 1;
-#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
-
-#ifndef CONFIG_64BIT
-#define LONG "%08lx "
-#define FOURLONG "%08lx %08lx %08lx %08lx\n"
-static int kstack_depth_to_print = 12;
-#else /* CONFIG_64BIT */
-#define LONG "%016lx "
-#define FOURLONG "%016lx %016lx %016lx %016lx\n"
-static int kstack_depth_to_print = 20;
-#endif /* CONFIG_64BIT */
-
static inline void __user *get_trap_ip(struct pt_regs *regs)
{
#ifdef CONFIG_64BIT
@@ -72,215 +39,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs)
#endif
}
-/*
- * For show_trace we have tree different stack to consider:
- * - the panic stack which is used if the kernel stack has overflown
- * - the asynchronous interrupt stack (cpu related)
- * - the synchronous kernel stack (process related)
- * The stack trace can start at any of the three stack and can potentially
- * touch all of them. The order is: panic stack, async stack, sync stack.
- */
-static unsigned long
-__show_trace(unsigned long sp, unsigned long low, unsigned long high)
-{
- struct stack_frame *sf;
- struct pt_regs *regs;
-
- while (1) {
- sp = sp & PSW_ADDR_INSN;
- if (sp < low || sp > high - sizeof(*sf))
- return sp;
- sf = (struct stack_frame *) sp;
- printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
- print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
- /* Follow the backchain. */
- while (1) {
- low = sp;
- sp = sf->back_chain & PSW_ADDR_INSN;
- if (!sp)
- break;
- if (sp <= low || sp > high - sizeof(*sf))
- return sp;
- sf = (struct stack_frame *) sp;
- printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
- print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
- }
- /* Zero backchain detected, check for interrupt frame. */
- sp = (unsigned long) (sf + 1);
- if (sp <= low || sp > high - sizeof(*regs))
- return sp;
- regs = (struct pt_regs *) sp;
- printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
- print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
- low = sp;
- sp = regs->gprs[15];
- }
-}
-
-static void show_trace(struct task_struct *task, unsigned long *stack)
-{
- register unsigned long __r15 asm ("15");
- unsigned long sp;
-
- sp = (unsigned long) stack;
- if (!sp)
- sp = task ? task->thread.ksp : __r15;
- printk("Call Trace:\n");
-#ifdef CONFIG_CHECK_STACK
- sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
- S390_lowcore.panic_stack);
-#endif
- sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
- S390_lowcore.async_stack);
- if (task)
- __show_trace(sp, (unsigned long) task_stack_page(task),
- (unsigned long) task_stack_page(task) + THREAD_SIZE);
- else
- __show_trace(sp, S390_lowcore.thread_info,
- S390_lowcore.thread_info + THREAD_SIZE);
- if (!task)
- task = current;
- debug_show_held_locks(task);
-}
-
-void show_stack(struct task_struct *task, unsigned long *sp)
-{
- register unsigned long * __r15 asm ("15");
- unsigned long *stack;
- int i;
-
- if (!sp)
- stack = task ? (unsigned long *) task->thread.ksp : __r15;
- else
- stack = sp;
-
- for (i = 0; i < kstack_depth_to_print; i++) {
- if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
- break;
- if ((i * sizeof(long) % 32) == 0)
- printk("%s ", i == 0 ? "" : "\n");
- printk(LONG, *stack++);
- }
- printk("\n");
- show_trace(task, sp);
-}
-
-static void show_last_breaking_event(struct pt_regs *regs)
-{
-#ifdef CONFIG_64BIT
- printk("Last Breaking-Event-Address:\n");
- printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
- print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
-#endif
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- printk("CPU: %d %s %s %.*s\n",
- task_thread_info(current)->cpu, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
- printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
- current->comm, current->pid, current,
- (void *) current->thread.ksp);
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
-static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
-{
- return (regs->psw.mask & bits) / ((~bits + 1) & bits);
-}
-
-void show_registers(struct pt_regs *regs)
-{
- char *mode;
-
- mode = user_mode(regs) ? "User" : "Krnl";
- printk("%s PSW : %p %p",
- mode, (void *) regs->psw.mask,
- (void *) regs->psw.addr);
- print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
- printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
- "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
- mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
- mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
- mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
- mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
- mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
-#ifdef CONFIG_64BIT
- printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
-#endif
- printk("\n%s GPRS: " FOURLONG, mode,
- regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
- printk(" " FOURLONG,
- regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
- printk(" " FOURLONG,
- regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
- printk(" " FOURLONG,
- regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
-
- show_code(regs);
-}
-
-void show_regs(struct pt_regs *regs)
-{
- printk("CPU: %d %s %s %.*s\n",
- task_thread_info(current)->cpu, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
- printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
- current->comm, current->pid, current,
- (void *) current->thread.ksp);
- show_registers(regs);
- /* Show stack backtrace if pt_regs is from kernel mode */
- if (!user_mode(regs))
- show_trace(NULL, (unsigned long *) regs->gprs[15]);
- show_last_breaking_event(regs);
-}
-
-static DEFINE_SPINLOCK(die_lock);
-
-void die(struct pt_regs *regs, const char *str)
-{
- static int die_counter;
-
- oops_enter();
- lgr_info_log();
- debug_stop_all();
- console_verbose();
- spin_lock_irq(&die_lock);
- bust_spinlocks(1);
- printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter);
-#ifdef CONFIG_PREEMPT
- printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
- printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
- printk("DEBUG_PAGEALLOC");
-#endif
- printk("\n");
- notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV);
- print_modules();
- show_regs(regs);
- bust_spinlocks(0);
- add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
- spin_unlock_irq(&die_lock);
- if (in_interrupt())
- panic("Fatal exception in interrupt");
- if (panic_on_oops)
- panic("Fatal exception: panic_on_oops");
- oops_exit();
- do_exit(SIGSEGV);
-}
-
static inline void report_user_fault(struct pt_regs *regs, int signr)
{
if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index a0042acbd989..3fb09359eda6 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -158,8 +158,6 @@ void __kprobes vtime_stop_cpu(void)
unsigned long psw_mask;
trace_hardirqs_on();
- /* Don't trace preempt off for idle. */
- stop_critical_timings();
/* Wait for external, I/O or machine check interrupt. */
psw_mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_DAT |
@@ -169,9 +167,6 @@ void __kprobes vtime_stop_cpu(void)
/* Call the assembler magic in entry.S */
psw_idle(idle, psw_mask);
- /* Reenable preemption tracer. */
- start_critical_timings();
-
/* Account time spent with enabled wait psw loaded as idle time. */
idle->sequence++;
smp_wmb();
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
index 2b29e62351d3..c2f582bb1cb2 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/trace.h
@@ -67,7 +67,7 @@ TRACE_EVENT(kvm_s390_sie_fault,
#define sie_intercept_code \
{0x04, "Instruction"}, \
{0x08, "Program interruption"}, \
- {0x0C, "Instruction and program interuption"}, \
+ {0x0C, "Instruction and program interruption"}, \
{0x10, "External request"}, \
{0x14, "External interruption"}, \
{0x18, "I/O request"}, \
@@ -117,7 +117,7 @@ TRACE_EVENT(kvm_s390_intercept_instruction,
__entry->instruction,
insn_to_mnemonic((unsigned char *)
&__entry->instruction,
- __entry->insn) ?
+ __entry->insn, sizeof(__entry->insn)) ?
"unknown" : __entry->insn)
);
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index 6ab0d0b5cec8..20b0e97a7df2 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -3,7 +3,6 @@
#
lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
-obj-y += usercopy.o
obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
obj-$(CONFIG_64BIT) += mem64.o
lib-$(CONFIG_64BIT) += uaccess_mvcos.o
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index dff631d34b45..466fb3383960 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -77,42 +77,69 @@ static size_t copy_in_kernel(size_t count, void __user *to,
* >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address
* contains the (negative) exception code.
*/
-static __always_inline unsigned long follow_table(struct mm_struct *mm,
- unsigned long addr, int write)
+#ifdef CONFIG_64BIT
+static unsigned long follow_table(struct mm_struct *mm,
+ unsigned long address, int write)
{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *ptep;
+ unsigned long *table = (unsigned long *)__pa(mm->pgd);
+
+ switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
+ case _ASCE_TYPE_REGION1:
+ table = table + ((address >> 53) & 0x7ff);
+ if (unlikely(*table & _REGION_ENTRY_INV))
+ return -0x39UL;
+ table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+ case _ASCE_TYPE_REGION2:
+ table = table + ((address >> 42) & 0x7ff);
+ if (unlikely(*table & _REGION_ENTRY_INV))
+ return -0x3aUL;
+ table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+ case _ASCE_TYPE_REGION3:
+ table = table + ((address >> 31) & 0x7ff);
+ if (unlikely(*table & _REGION_ENTRY_INV))
+ return -0x3bUL;
+ table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+ case _ASCE_TYPE_SEGMENT:
+ table = table + ((address >> 20) & 0x7ff);
+ if (unlikely(*table & _SEGMENT_ENTRY_INV))
+ return -0x10UL;
+ if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) {
+ if (write && (*table & _SEGMENT_ENTRY_RO))
+ return -0x04UL;
+ return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) +
+ (address & ~_SEGMENT_ENTRY_ORIGIN_LARGE);
+ }
+ table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
+ }
+ table = table + ((address >> 12) & 0xff);
+ if (unlikely(*table & _PAGE_INVALID))
+ return -0x11UL;
+ if (write && (*table & _PAGE_RO))
+ return -0x04UL;
+ return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
+}
- pgd = pgd_offset(mm, addr);
- if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
- return -0x3aUL;
+#else /* CONFIG_64BIT */
- pud = pud_offset(pgd, addr);
- if (pud_none(*pud) || unlikely(pud_bad(*pud)))
- return -0x3bUL;
+static unsigned long follow_table(struct mm_struct *mm,
+ unsigned long address, int write)
+{
+ unsigned long *table = (unsigned long *)__pa(mm->pgd);
- pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd))
+ table = table + ((address >> 20) & 0x7ff);
+ if (unlikely(*table & _SEGMENT_ENTRY_INV))
return -0x10UL;
- if (pmd_large(*pmd)) {
- if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO))
- return -0x04UL;
- return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK);
- }
- if (unlikely(pmd_bad(*pmd)))
- return -0x10UL;
-
- ptep = pte_offset_map(pmd, addr);
- if (!pte_present(*ptep))
+ table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
+ table = table + ((address >> 12) & 0xff);
+ if (unlikely(*table & _PAGE_INVALID))
return -0x11UL;
- if (write && (!pte_write(*ptep) || !pte_dirty(*ptep)))
+ if (write && (*table & _PAGE_RO))
return -0x04UL;
-
- return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);
+ return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
}
+#endif /* CONFIG_64BIT */
+
static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
size_t n, int write_user)
{
@@ -197,7 +224,7 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
static size_t clear_user_pt(size_t n, void __user *to)
{
- void *zpage = &empty_zero_page;
+ void *zpage = (void *) empty_zero_page;
long done, size, ret;
done = 0;
diff --git a/arch/s390/lib/usercopy.c b/arch/s390/lib/usercopy.c
deleted file mode 100644
index 14b363fec8a2..000000000000
--- a/arch/s390/lib/usercopy.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <linux/module.h>
-#include <linux/bug.h>
-
-void copy_from_user_overflow(void)
-{
- WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index 479e94282910..9d84a1feefef 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -458,12 +458,10 @@ static int __init cmm_init(void)
if (rc)
goto out_pm;
cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
- rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
- if (rc)
- goto out_kthread;
- return 0;
+ if (!IS_ERR(cmm_thread_ptr))
+ return 0;
-out_kthread:
+ rc = PTR_ERR(cmm_thread_ptr);
unregister_pm_notifier(&cmm_power_notifier);
out_pm:
unregister_oom_notifier(&cmm_oom_nb);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2fb9e63b8fc4..047c3e4c59a2 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -395,8 +395,13 @@ void __kprobes do_protection_exception(struct pt_regs *regs)
int fault;
trans_exc_code = regs->int_parm_long;
- /* Protection exception is suppressing, decrement psw address. */
- regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
+ /*
+ * Protection exceptions are suppressing, decrement psw address.
+ * The exception to this rule are aborted transactions, for these
+ * the PSW already points to the correct location.
+ */
+ if (!(regs->int_code & 0x200))
+ regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
/*
* Check for low-address protection. This needs to be treated
* as a special case because the translation exception code
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index 532525ec88c1..121089d57802 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -39,7 +39,7 @@ int arch_prepare_hugepage(struct page *page)
if (!ptep)
return -ENOMEM;
- pte = mk_pte(page, PAGE_RW);
+ pte_val(pte) = addr;
for (i = 0; i < PTRS_PER_PTE; i++) {
set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte);
pte_val(pte) += PAGE_SIZE;
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 49ce6bb2c641..0b09b2342302 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -42,11 +42,10 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
unsigned long empty_zero_page, zero_page_mask;
EXPORT_SYMBOL(empty_zero_page);
-static unsigned long __init setup_zero_pages(void)
+static void __init setup_zero_pages(void)
{
struct cpuid cpu_id;
unsigned int order;
- unsigned long size;
struct page *page;
int i;
@@ -63,10 +62,18 @@ static unsigned long __init setup_zero_pages(void)
break;
case 0x2097: /* z10 */
case 0x2098: /* z10 */
- default:
+ case 0x2817: /* z196 */
+ case 0x2818: /* z196 */
order = 2;
break;
+ case 0x2827: /* zEC12 */
+ default:
+ order = 5;
+ break;
}
+ /* Limit number of empty zero pages for small memory sizes */
+ if (order > 2 && totalram_pages <= 16384)
+ order = 2;
empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
if (!empty_zero_page)
@@ -75,14 +82,11 @@ static unsigned long __init setup_zero_pages(void)
page = virt_to_page((void *) empty_zero_page);
split_page(page, order);
for (i = 1 << order; i > 0; i--) {
- SetPageReserved(page);
+ mark_page_reserved(page);
page++;
}
- size = PAGE_SIZE << order;
- zero_page_mask = (size - 1) & PAGE_MASK;
-
- return 1UL << order;
+ zero_page_mask = ((PAGE_SIZE << order) - 1) & PAGE_MASK;
}
/*
@@ -139,7 +143,7 @@ void __init mem_init(void)
/* this will put all low memory onto the freelists */
totalram_pages += free_all_bootmem();
- totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */
+ setup_zero_pages(); /* Setup zeroed pages. */
reservedpages = 0;
@@ -158,34 +162,15 @@ void __init mem_init(void)
PFN_ALIGN((unsigned long)&_eshared) - 1);
}
-void free_init_pages(char *what, unsigned long begin, unsigned long end)
-{
- unsigned long addr = begin;
-
- if (begin >= end)
- return;
- for (; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- memset((void *)(addr & PAGE_MASK), POISON_FREE_INITMEM,
- PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
-}
-
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
- (unsigned long)&__init_begin,
- (unsigned long)&__init_end);
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory", start, end);
+ free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
}
#endif
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index d21040ed5e59..80adfbf75065 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -9,31 +9,25 @@
#include <asm/pgtable.h>
#include <asm/page.h>
+static inline unsigned long sske_frame(unsigned long addr, unsigned char skey)
+{
+ asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0"
+ : [addr] "+a" (addr) : [skey] "d" (skey));
+ return addr;
+}
+
void storage_key_init_range(unsigned long start, unsigned long end)
{
- unsigned long boundary, function, size;
+ unsigned long boundary, size;
while (start < end) {
- if (MACHINE_HAS_EDAT2) {
- /* set storage keys for a 2GB frame */
- function = 0x22000 | PAGE_DEFAULT_KEY;
- size = 1UL << 31;
- boundary = (start + size) & ~(size - 1);
- if (boundary <= end) {
- do {
- start = pfmf(function, start);
- } while (start < boundary);
- continue;
- }
- }
if (MACHINE_HAS_EDAT1) {
/* set storage keys for a 1MB frame */
- function = 0x21000 | PAGE_DEFAULT_KEY;
size = 1UL << 20;
boundary = (start + size) & ~(size - 1);
if (boundary <= end) {
do {
- start = pfmf(function, start);
+ start = sske_frame(start, PAGE_DEFAULT_KEY);
} while (start < boundary);
continue;
}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index ae44d2a34313..bd954e96f51c 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -379,75 +379,183 @@ out_unmap:
}
EXPORT_SYMBOL_GPL(gmap_map_segment);
-/*
- * this function is assumed to be called with mmap_sem held
- */
-unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
+static unsigned long *gmap_table_walk(unsigned long address, struct gmap *gmap)
{
- unsigned long *table, vmaddr, segment;
- struct mm_struct *mm;
- struct gmap_pgtable *mp;
- struct gmap_rmap *rmap;
- struct vm_area_struct *vma;
- struct page *page;
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
+ unsigned long *table;
- current->thread.gmap_addr = address;
- mm = gmap->mm;
- /* Walk the gmap address space page table */
table = gmap->table + ((address >> 53) & 0x7ff);
if (unlikely(*table & _REGION_ENTRY_INV))
- return -EFAULT;
+ return ERR_PTR(-EFAULT);
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + ((address >> 42) & 0x7ff);
if (unlikely(*table & _REGION_ENTRY_INV))
- return -EFAULT;
+ return ERR_PTR(-EFAULT);
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + ((address >> 31) & 0x7ff);
if (unlikely(*table & _REGION_ENTRY_INV))
- return -EFAULT;
+ return ERR_PTR(-EFAULT);
table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
table = table + ((address >> 20) & 0x7ff);
+ return table;
+}
+
+/**
+ * __gmap_translate - translate a guest address to a user space address
+ * @address: guest address
+ * @gmap: pointer to guest mapping meta data structure
+ *
+ * Returns user space address which corresponds to the guest address or
+ * -EFAULT if no such mapping exists.
+ * This function does not establish potentially missing page table entries.
+ * The mmap_sem of the mm that belongs to the address space must be held
+ * when this function gets called.
+ */
+unsigned long __gmap_translate(unsigned long address, struct gmap *gmap)
+{
+ unsigned long *segment_ptr, vmaddr, segment;
+ struct gmap_pgtable *mp;
+ struct page *page;
+ current->thread.gmap_addr = address;
+ segment_ptr = gmap_table_walk(address, gmap);
+ if (IS_ERR(segment_ptr))
+ return PTR_ERR(segment_ptr);
/* Convert the gmap address to an mm address. */
- segment = *table;
- if (likely(!(segment & _SEGMENT_ENTRY_INV))) {
+ segment = *segment_ptr;
+ if (!(segment & _SEGMENT_ENTRY_INV)) {
page = pfn_to_page(segment >> PAGE_SHIFT);
mp = (struct gmap_pgtable *) page->index;
return mp->vmaddr | (address & ~PMD_MASK);
} else if (segment & _SEGMENT_ENTRY_RO) {
vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
- vma = find_vma(mm, vmaddr);
- if (!vma || vma->vm_start > vmaddr)
- return -EFAULT;
-
- /* Walk the parent mm page table */
- pgd = pgd_offset(mm, vmaddr);
- pud = pud_alloc(mm, pgd, vmaddr);
- if (!pud)
- return -ENOMEM;
- pmd = pmd_alloc(mm, pud, vmaddr);
- if (!pmd)
- return -ENOMEM;
- if (!pmd_present(*pmd) &&
- __pte_alloc(mm, vma, pmd, vmaddr))
- return -ENOMEM;
- /* pmd now points to a valid segment table entry. */
- rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT);
- if (!rmap)
- return -ENOMEM;
- /* Link gmap segment table entry location to page table. */
- page = pmd_page(*pmd);
- mp = (struct gmap_pgtable *) page->index;
- rmap->entry = table;
- spin_lock(&mm->page_table_lock);
+ return vmaddr | (address & ~PMD_MASK);
+ }
+ return -EFAULT;
+}
+EXPORT_SYMBOL_GPL(__gmap_translate);
+
+/**
+ * gmap_translate - translate a guest address to a user space address
+ * @address: guest address
+ * @gmap: pointer to guest mapping meta data structure
+ *
+ * Returns user space address which corresponds to the guest address or
+ * -EFAULT if no such mapping exists.
+ * This function does not establish potentially missing page table entries.
+ */
+unsigned long gmap_translate(unsigned long address, struct gmap *gmap)
+{
+ unsigned long rc;
+
+ down_read(&gmap->mm->mmap_sem);
+ rc = __gmap_translate(address, gmap);
+ up_read(&gmap->mm->mmap_sem);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(gmap_translate);
+
+static int gmap_connect_pgtable(unsigned long segment,
+ unsigned long *segment_ptr,
+ struct gmap *gmap)
+{
+ unsigned long vmaddr;
+ struct vm_area_struct *vma;
+ struct gmap_pgtable *mp;
+ struct gmap_rmap *rmap;
+ struct mm_struct *mm;
+ struct page *page;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ mm = gmap->mm;
+ vmaddr = segment & _SEGMENT_ENTRY_ORIGIN;
+ vma = find_vma(mm, vmaddr);
+ if (!vma || vma->vm_start > vmaddr)
+ return -EFAULT;
+ /* Walk the parent mm page table */
+ pgd = pgd_offset(mm, vmaddr);
+ pud = pud_alloc(mm, pgd, vmaddr);
+ if (!pud)
+ return -ENOMEM;
+ pmd = pmd_alloc(mm, pud, vmaddr);
+ if (!pmd)
+ return -ENOMEM;
+ if (!pmd_present(*pmd) &&
+ __pte_alloc(mm, vma, pmd, vmaddr))
+ return -ENOMEM;
+ /* pmd now points to a valid segment table entry. */
+ rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT);
+ if (!rmap)
+ return -ENOMEM;
+ /* Link gmap segment table entry location to page table. */
+ page = pmd_page(*pmd);
+ mp = (struct gmap_pgtable *) page->index;
+ rmap->entry = segment_ptr;
+ spin_lock(&mm->page_table_lock);
+ if (*segment_ptr == segment) {
list_add(&rmap->list, &mp->mapper);
- spin_unlock(&mm->page_table_lock);
/* Set gmap segment table entry to page table. */
- *table = pmd_val(*pmd) & PAGE_MASK;
- return vmaddr | (address & ~PMD_MASK);
+ *segment_ptr = pmd_val(*pmd) & PAGE_MASK;
+ rmap = NULL;
+ }
+ spin_unlock(&mm->page_table_lock);
+ kfree(rmap);
+ return 0;
+}
+
+static void gmap_disconnect_pgtable(struct mm_struct *mm, unsigned long *table)
+{
+ struct gmap_rmap *rmap, *next;
+ struct gmap_pgtable *mp;
+ struct page *page;
+ int flush;
+
+ flush = 0;
+ spin_lock(&mm->page_table_lock);
+ page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+ mp = (struct gmap_pgtable *) page->index;
+ list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
+ *rmap->entry =
+ _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
+ list_del(&rmap->list);
+ kfree(rmap);
+ flush = 1;
+ }
+ spin_unlock(&mm->page_table_lock);
+ if (flush)
+ __tlb_flush_global();
+}
+
+/*
+ * this function is assumed to be called with mmap_sem held
+ */
+unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
+{
+ unsigned long *segment_ptr, segment;
+ struct gmap_pgtable *mp;
+ struct page *page;
+ int rc;
+
+ current->thread.gmap_addr = address;
+ segment_ptr = gmap_table_walk(address, gmap);
+ if (IS_ERR(segment_ptr))
+ return -EFAULT;
+ /* Convert the gmap address to an mm address. */
+ while (1) {
+ segment = *segment_ptr;
+ if (!(segment & _SEGMENT_ENTRY_INV)) {
+ /* Page table is present */
+ page = pfn_to_page(segment >> PAGE_SHIFT);
+ mp = (struct gmap_pgtable *) page->index;
+ return mp->vmaddr | (address & ~PMD_MASK);
+ }
+ if (!(segment & _SEGMENT_ENTRY_RO))
+ /* Nothing mapped in the gmap address space. */
+ break;
+ rc = gmap_connect_pgtable(segment, segment_ptr, gmap);
+ if (rc)
+ return rc;
}
return -EFAULT;
}
@@ -511,29 +619,6 @@ void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
}
EXPORT_SYMBOL_GPL(gmap_discard);
-void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table)
-{
- struct gmap_rmap *rmap, *next;
- struct gmap_pgtable *mp;
- struct page *page;
- int flush;
-
- flush = 0;
- spin_lock(&mm->page_table_lock);
- page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
- mp = (struct gmap_pgtable *) page->index;
- list_for_each_entry_safe(rmap, next, &mp->mapper, list) {
- *rmap->entry =
- _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO | mp->vmaddr;
- list_del(&rmap->list);
- kfree(rmap);
- flush = 1;
- }
- spin_unlock(&mm->page_table_lock);
- if (flush)
- __tlb_flush_global();
-}
-
static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
unsigned long vmaddr)
{
@@ -586,8 +671,8 @@ static inline void page_table_free_pgste(unsigned long *table)
{
}
-static inline void gmap_unmap_notifier(struct mm_struct *mm,
- unsigned long *table)
+static inline void gmap_disconnect_pgtable(struct mm_struct *mm,
+ unsigned long *table)
{
}
@@ -653,7 +738,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
unsigned int bit, mask;
if (mm_has_pgste(mm)) {
- gmap_unmap_notifier(mm, table);
+ gmap_disconnect_pgtable(mm, table);
return page_table_free_pgste(table);
}
/* Free 1K/2K page table fragment of a 4K page */
@@ -696,7 +781,7 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table)
mm = tlb->mm;
if (mm_has_pgste(mm)) {
- gmap_unmap_notifier(mm, table);
+ gmap_disconnect_pgtable(mm, table);
table = (unsigned long *) (__pa(table) | FRAG_MASK);
tlb_remove_table(tlb, table);
return;
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index ffab84db6907..35837054f734 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -191,19 +191,16 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
/*
* Add a backed mem_map array to the virtual mem_map array.
*/
-int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
{
- unsigned long address, start_addr, end_addr;
+ unsigned long address = start;
pgd_t *pg_dir;
pud_t *pu_dir;
pmd_t *pm_dir;
pte_t *pt_dir;
int ret = -ENOMEM;
- start_addr = (unsigned long) start;
- end_addr = (unsigned long) (start + nr);
-
- for (address = start_addr; address < end_addr;) {
+ for (address = start; address < end;) {
pg_dir = pgd_offset_k(address);
if (pgd_none(*pg_dir)) {
pu_dir = vmem_pud_alloc();
@@ -262,14 +259,14 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
}
address += PAGE_SIZE;
}
- memset(start, 0, nr * sizeof(struct page));
+ memset((void *)start, 0, end - start);
ret = 0;
out:
- flush_tlb_kernel_range(start_addr, end_addr);
+ flush_tlb_kernel_range(start, end);
return ret;
}
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
{
}
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 0972e91cced2..82f165f8078c 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -747,10 +747,9 @@ void bpf_jit_compile(struct sk_filter *fp)
if (!bpf_jit_enable)
return;
- addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL);
+ addrs = kcalloc(fp->len, sizeof(*addrs), GFP_KERNEL);
if (addrs == NULL)
return;
- memset(addrs, 0, fp->len * sizeof(*addrs));
memset(&jit, 0, sizeof(cjit));
memset(&cjit, 0, sizeof(cjit));
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
index 584b93674ea4..ffeb17ce7f31 100644
--- a/arch/s390/oprofile/init.c
+++ b/arch/s390/oprofile/init.c
@@ -440,6 +440,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
switch (id.machine) {
case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
+ case 0x2827: ops->cpu_type = "s390/zEC12"; break;
default: return -ENODEV;
}
}
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile
index f0f426a113ce..086a2e37935d 100644
--- a/arch/s390/pci/Makefile
+++ b/arch/s390/pci/Makefile
@@ -2,5 +2,5 @@
# Makefile for the s390 PCI subsystem.
#
-obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \
- pci_sysfs.o pci_event.o pci_debug.o
+obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o pci_sysfs.o \
+ pci_event.o pci_debug.o pci_insn.o
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 27b4c17855b9..e6f15b5d8b7d 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -99,9 +99,6 @@ static int __read_mostly aisb_max;
static struct kmem_cache *zdev_irq_cache;
static struct kmem_cache *zdev_fmb_cache;
-debug_info_t *pci_debug_msg_id;
-debug_info_t *pci_debug_err_id;
-
static inline int irq_to_msi_nr(unsigned int irq)
{
return irq & ZPCI_MSI_MASK;
@@ -179,7 +176,7 @@ static int zpci_register_airq(struct zpci_dev *zdev, unsigned int aisb,
fib->aisb = (u64) bucket->aisb + aisb / 8;
fib->aisbo = aisb & ZPCI_MSI_MASK;
- rc = mpcifc_instr(req, fib);
+ rc = s390pci_mod_fc(req, fib);
pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi);
free_page((unsigned long) fib);
@@ -209,7 +206,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
fib->iota = args->iota;
fib->fmb_addr = args->fmb_addr;
- rc = mpcifc_instr(req, fib);
+ rc = s390pci_mod_fc(req, fib);
free_page((unsigned long) fib);
return rc;
}
@@ -249,10 +246,9 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev)
if (zdev->fmb)
return -EINVAL;
- zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL);
+ zdev->fmb = kmem_cache_zalloc(zdev_fmb_cache, GFP_KERNEL);
if (!zdev->fmb)
return -ENOMEM;
- memset(zdev->fmb, 0, sizeof(*zdev->fmb));
WARN_ON((u64) zdev->fmb & 0xf);
args.fmb_addr = virt_to_phys(zdev->fmb);
@@ -284,12 +280,12 @@ static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
u64 data;
int rc;
- rc = pcilg_instr(&data, req, offset);
- data = data << ((8 - len) * 8);
- data = le64_to_cpu(data);
- if (!rc)
+ rc = s390pci_load(&data, req, offset);
+ if (!rc) {
+ data = data << ((8 - len) * 8);
+ data = le64_to_cpu(data);
*val = (u32) data;
- else
+ } else
*val = 0xffffffff;
return rc;
}
@@ -302,7 +298,7 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)
data = cpu_to_le64(data);
data = data >> ((8 - len) * 8);
- rc = pcistg_instr(data, req, offset);
+ rc = s390pci_store(data, req, offset);
return rc;
}
@@ -409,20 +405,28 @@ static int pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val)
{
struct zpci_dev *zdev = get_zdev_by_bus(bus);
+ int ret;
if (!zdev || devfn != ZPCI_DEVFN)
- return 0;
- return zpci_cfg_load(zdev, where, val, size);
+ ret = -ENODEV;
+ else
+ ret = zpci_cfg_load(zdev, where, val, size);
+
+ return ret;
}
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
struct zpci_dev *zdev = get_zdev_by_bus(bus);
+ int ret;
if (!zdev || devfn != ZPCI_DEVFN)
- return 0;
- return zpci_cfg_store(zdev, where, val, size);
+ ret = -ENODEV;
+ else
+ ret = zpci_cfg_store(zdev, where, val, size);
+
+ return ret;
}
static struct pci_ops pci_root_ops = {
@@ -474,7 +478,7 @@ scan:
}
/* enable interrupts again */
- sic_instr(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+ set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
/* check again to not lose initiative */
rmb();
@@ -596,19 +600,6 @@ static void zpci_map_resources(struct zpci_dev *zdev)
}
};
-static void zpci_unmap_resources(struct pci_dev *pdev)
-{
- resource_size_t len;
- int i;
-
- for (i = 0; i < PCI_BAR_COUNT; i++) {
- len = pci_resource_len(pdev, i);
- if (!len)
- continue;
- pci_iounmap(pdev, (void *) pdev->resource[i].start);
- }
-};
-
struct zpci_dev *zpci_alloc_device(void)
{
struct zpci_dev *zdev;
@@ -636,32 +627,6 @@ void zpci_free_device(struct zpci_dev *zdev)
kfree(zdev);
}
-/* Called on removal of pci_dev, leaves zpci and bus device */
-static void zpci_remove_device(struct pci_dev *pdev)
-{
- struct zpci_dev *zdev = get_zdev(pdev);
-
- dev_info(&pdev->dev, "Removing device %u\n", zdev->domain);
- zdev->state = ZPCI_FN_STATE_CONFIGURED;
- zpci_dma_exit_device(zdev);
- zpci_fmb_disable_device(zdev);
- zpci_sysfs_remove_device(&pdev->dev);
- zpci_unmap_resources(pdev);
- list_del(&zdev->entry); /* can be called from init */
- zdev->pdev = NULL;
-}
-
-static void zpci_scan_devices(void)
-{
- struct zpci_dev *zdev;
-
- mutex_lock(&zpci_list_lock);
- list_for_each_entry(zdev, &zpci_list, entry)
- if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
- zpci_scan_device(zdev);
- mutex_unlock(&zpci_list_lock);
-}
-
/*
* Too late for any s390 specific setup, since interrupts must be set up
* already which requires DMA setup too and the pci scan will access the
@@ -688,12 +653,6 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask)
return 0;
}
-void pcibios_disable_device(struct pci_dev *pdev)
-{
- zpci_remove_device(pdev);
- pdev->sysdata = NULL;
-}
-
int pcibios_add_platform_entries(struct pci_dev *pdev)
{
return zpci_sysfs_add_device(&pdev->dev);
@@ -789,7 +748,7 @@ static int __init zpci_irq_init(void)
spin_lock_init(&bucket->lock);
/* set summary to 1 to be called every time for the ISC */
*zpci_irq_si = 1;
- sic_instr(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
+ set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
return 0;
out_ai:
@@ -872,7 +831,19 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)
spin_unlock(&zpci_iomap_lock);
}
-static int zpci_create_device_bus(struct zpci_dev *zdev)
+int pcibios_add_device(struct pci_dev *pdev)
+{
+ struct zpci_dev *zdev = get_zdev(pdev);
+
+ zdev->pdev = pdev;
+ zpci_debug_init_device(zdev);
+ zpci_fmb_enable_device(zdev);
+ zpci_map_resources(zdev);
+
+ return 0;
+}
+
+static int zpci_scan_bus(struct zpci_dev *zdev)
{
struct resource *res;
LIST_HEAD(resources);
@@ -909,8 +880,8 @@ static int zpci_create_device_bus(struct zpci_dev *zdev)
pci_add_resource(&resources, res);
}
- zdev->bus = pci_create_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
- zdev, &resources);
+ zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
+ zdev, &resources);
if (!zdev->bus)
return -EIO;
@@ -959,6 +930,13 @@ out:
}
EXPORT_SYMBOL_GPL(zpci_enable_device);
+int zpci_disable_device(struct zpci_dev *zdev)
+{
+ zpci_dma_exit_device(zdev);
+ return clp_disable_fh(zdev);
+}
+EXPORT_SYMBOL_GPL(zpci_disable_device);
+
int zpci_create_device(struct zpci_dev *zdev)
{
int rc;
@@ -967,9 +945,16 @@ int zpci_create_device(struct zpci_dev *zdev)
if (rc)
goto out;
- rc = zpci_create_device_bus(zdev);
+ if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
+ rc = zpci_enable_device(zdev);
+ if (rc)
+ goto out_free;
+
+ zdev->state = ZPCI_FN_STATE_ONLINE;
+ }
+ rc = zpci_scan_bus(zdev);
if (rc)
- goto out_bus;
+ goto out_disable;
mutex_lock(&zpci_list_lock);
list_add_tail(&zdev->entry, &zpci_list);
@@ -977,21 +962,12 @@ int zpci_create_device(struct zpci_dev *zdev)
hotplug_ops->create_slot(zdev);
mutex_unlock(&zpci_list_lock);
- if (zdev->state == ZPCI_FN_STATE_STANDBY)
- return 0;
-
- rc = zpci_enable_device(zdev);
- if (rc)
- goto out_start;
return 0;
-out_start:
- mutex_lock(&zpci_list_lock);
- list_del(&zdev->entry);
- if (hotplug_ops)
- hotplug_ops->remove_slot(zdev);
- mutex_unlock(&zpci_list_lock);
-out_bus:
+out_disable:
+ if (zdev->state == ZPCI_FN_STATE_ONLINE)
+ zpci_disable_device(zdev);
+out_free:
zpci_free_domain(zdev);
out:
return rc;
@@ -1016,15 +992,9 @@ int zpci_scan_device(struct zpci_dev *zdev)
goto out;
}
- zpci_debug_init_device(zdev);
- zpci_fmb_enable_device(zdev);
- zpci_map_resources(zdev);
pci_bus_add_devices(zdev->bus);
- /* now that pdev was added to the bus mark it as used */
- zdev->state = ZPCI_FN_STATE_ONLINE;
return 0;
-
out:
zpci_dma_exit_device(zdev);
clp_disable_fh(zdev);
@@ -1087,13 +1057,13 @@ void zpci_deregister_hp_ops(void)
}
EXPORT_SYMBOL_GPL(zpci_deregister_hp_ops);
-unsigned int s390_pci_probe = 1;
+unsigned int s390_pci_probe;
EXPORT_SYMBOL_GPL(s390_pci_probe);
char * __init pcibios_setup(char *str)
{
- if (!strcmp(str, "off")) {
- s390_pci_probe = 0;
+ if (!strcmp(str, "on")) {
+ s390_pci_probe = 1;
return NULL;
}
return str;
@@ -1138,7 +1108,6 @@ static int __init pci_base_init(void)
if (rc)
goto out_find;
- zpci_scan_devices();
return 0;
out_find:
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index f339fe2feb15..bd34359d1546 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <asm/pci_debug.h>
#include <asm/pci_clp.h>
/*
@@ -144,6 +145,7 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)
struct zpci_dev *zdev;
int rc;
+ zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, configured);
zdev = zpci_alloc_device();
if (IS_ERR(zdev))
return PTR_ERR(zdev);
@@ -204,8 +206,8 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)
if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)
*fh = rrb->response.fh;
else {
- pr_err("Set PCI FN failed with response: %x cc: %d\n",
- rrb->response.hdr.rsp, rc);
+ zpci_dbg(0, "SPF fh:%x, cc:%d, resp:%x\n", *fh, rc,
+ rrb->response.hdr.rsp);
rc = -EIO;
}
clp_free_block(rrb);
@@ -221,6 +223,8 @@ int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as)
if (!rc)
/* Success -> store enabled handle in zdev */
zdev->fh = fh;
+
+ zpci_dbg(3, "ena fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
return rc;
}
@@ -237,9 +241,8 @@ int clp_disable_fh(struct zpci_dev *zdev)
if (!rc)
/* Success -> store disabled handle in zdev */
zdev->fh = fh;
- else
- dev_err(&zdev->pdev->dev,
- "Failed to disable fn handle: 0x%x\n", fh);
+
+ zpci_dbg(3, "dis fid:%x, fh:%x, rc:%d\n", zdev->fid, zdev->fh, rc);
return rc;
}
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index a5d07bc2a547..771b82359af4 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -11,12 +11,17 @@
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/export.h>
#include <linux/pci.h>
#include <asm/debug.h>
#include <asm/pci_dma.h>
static struct dentry *debugfs_root;
+debug_info_t *pci_debug_msg_id;
+EXPORT_SYMBOL_GPL(pci_debug_msg_id);
+debug_info_t *pci_debug_err_id;
+EXPORT_SYMBOL_GPL(pci_debug_err_id);
static char *pci_perf_names[] = {
/* hardware counters */
@@ -168,7 +173,6 @@ int __init zpci_debug_init(void)
return -EINVAL;
debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
debug_set_level(pci_debug_msg_id, 3);
- zpci_dbg("Debug view initialized\n");
/* error log */
pci_debug_err_id = debug_register("pci_error", 2, 1, 16);
@@ -176,7 +180,6 @@ int __init zpci_debug_init(void)
return -EINVAL;
debug_register_view(pci_debug_err_id, &debug_hex_ascii_view);
debug_set_level(pci_debug_err_id, 6);
- zpci_err("Debug view initialized\n");
debugfs_root = debugfs_create_dir("pci", NULL);
return 0;
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index a547419907c3..f8e69d5bc0a9 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -169,8 +169,9 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
* needs to be redone!
*/
goto no_refresh;
- rc = rpcit_instr((u64) zdev->fh << 32, start_dma_addr,
- nr_pages * PAGE_SIZE);
+
+ rc = s390pci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
+ nr_pages * PAGE_SIZE);
no_refresh:
spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
@@ -268,8 +269,6 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
int flags = ZPCI_PTE_VALID;
dma_addr_t dma_addr;
- WARN_ON_ONCE(offset > PAGE_SIZE);
-
/* This rounds up number of pages based on size and offset */
nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
@@ -291,7 +290,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages);
- return dma_addr + offset;
+ return dma_addr + (offset & ~PAGE_MASK);
}
out_free:
diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c
new file mode 100644
index 000000000000..22eeb9d7ffeb
--- /dev/null
+++ b/arch/s390/pci/pci_insn.c
@@ -0,0 +1,202 @@
+/*
+ * s390 specific pci instructions
+ *
+ * Copyright IBM Corp. 2013
+ */
+
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/pci_insn.h>
+#include <asm/processor.h>
+
+#define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
+
+/* Modify PCI Function Controls */
+static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
+{
+ u8 cc;
+
+ asm volatile (
+ " .insn rxy,0xe300000000d0,%[req],%[fib]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
+ : : "cc");
+ *status = req >> 24 & 0xff;
+ return cc;
+}
+
+int s390pci_mod_fc(u64 req, struct zpci_fib *fib)
+{
+ u8 cc, status;
+
+ do {
+ cc = __mpcifc(req, fib, &status);
+ if (cc == 2)
+ msleep(ZPCI_INSN_BUSY_DELAY);
+ } while (cc == 2);
+
+ if (cc)
+ printk_once(KERN_ERR "%s: error cc: %d status: %d\n",
+ __func__, cc, status);
+ return (cc) ? -EIO : 0;
+}
+
+/* Refresh PCI Translations */
+static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
+{
+ register u64 __addr asm("2") = addr;
+ register u64 __range asm("3") = range;
+ u8 cc;
+
+ asm volatile (
+ " .insn rre,0xb9d30000,%[fn],%[addr]\n"
+ " ipm %[cc]\n"
+ " srl %[cc],28\n"
+ : [cc] "=d" (cc), [fn] "+d" (fn)
+ : [addr] "d" (__addr), "d" (__range)
+ : "cc");
+ *status = fn >> 24 & 0xff;
+ return cc;
+}
+
+int s390pci_refresh_trans(u64 fn, u64 addr, u64 range)
+{
+ u8 cc, status;
+
+ do {
+ cc = __rpcit(fn, addr, range, &status);
+ if (cc == 2)
+ udelay(ZPCI_INSN_BUSY_DELAY);
+ } while (cc == 2);
+
+ if (cc)
+ printk_once(KERN_ERR "%s: error cc: %d status: %d dma_addr: %Lx size: %Lx\n",
+ __func__, cc, status, addr, range);
+ return (cc) ? -EIO : 0;
+}
+
+/* Set Interruption Controls */
+void set_irq_ctrl(u16 ctl, char *unused, u8 isc)
+{
+ asm volatile (
+ " .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
+ : : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
+}
+
+/* PCI Load */
+static inline int __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
+{
+ register u64 __req asm("2") = req;
+ register u64 __offset asm("3") = offset;
+ int cc = -ENXIO;
+ u64 __data;
+
+ asm volatile (
+ " .insn rre,0xb9d20000,%[data],%[req]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : [cc] "+d" (cc), [data] "=d" (__data), [req] "+d" (__req)
+ : "d" (__offset)
+ : "cc");
+ *status = __req >> 24 & 0xff;
+ if (!cc)
+ *data = __data;
+
+ return cc;
+}
+
+int s390pci_load(u64 *data, u64 req, u64 offset)
+{
+ u8 status;
+ int cc;
+
+ do {
+ cc = __pcilg(data, req, offset, &status);
+ if (cc == 2)
+ udelay(ZPCI_INSN_BUSY_DELAY);
+ } while (cc == 2);
+
+ if (cc)
+ printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
+ __func__, cc, status, req, offset);
+ return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_load);
+
+/* PCI Store */
+static inline int __pcistg(u64 data, u64 req, u64 offset, u8 *status)
+{
+ register u64 __req asm("2") = req;
+ register u64 __offset asm("3") = offset;
+ int cc = -ENXIO;
+
+ asm volatile (
+ " .insn rre,0xb9d00000,%[data],%[req]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : [cc] "+d" (cc), [req] "+d" (__req)
+ : "d" (__offset), [data] "d" (data)
+ : "cc");
+ *status = __req >> 24 & 0xff;
+ return cc;
+}
+
+int s390pci_store(u64 data, u64 req, u64 offset)
+{
+ u8 status;
+ int cc;
+
+ do {
+ cc = __pcistg(data, req, offset, &status);
+ if (cc == 2)
+ udelay(ZPCI_INSN_BUSY_DELAY);
+ } while (cc == 2);
+
+ if (cc)
+ printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
+ __func__, cc, status, req, offset);
+ return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_store);
+
+/* PCI Store Block */
+static inline int __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
+{
+ int cc = -ENXIO;
+
+ asm volatile (
+ " .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
+ "0: ipm %[cc]\n"
+ " srl %[cc],28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : [cc] "+d" (cc), [req] "+d" (req)
+ : [offset] "d" (offset), [data] "Q" (*data)
+ : "cc");
+ *status = req >> 24 & 0xff;
+ return cc;
+}
+
+int s390pci_store_block(const u64 *data, u64 req, u64 offset)
+{
+ u8 status;
+ int cc;
+
+ do {
+ cc = __pcistb(data, req, offset, &status);
+ if (cc == 2)
+ udelay(ZPCI_INSN_BUSY_DELAY);
+ } while (cc == 2);
+
+ if (cc)
+ printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
+ __func__, cc, status, req, offset);
+ return (cc > 0) ? -EIO : cc;
+}
+EXPORT_SYMBOL_GPL(s390pci_store_block);
diff --git a/arch/s390/pci/pci_msi.c b/arch/s390/pci/pci_msi.c
index 0297931335e1..b097aed05a9b 100644
--- a/arch/s390/pci/pci_msi.c
+++ b/arch/s390/pci/pci_msi.c
@@ -18,8 +18,9 @@
/* mapping of irq numbers to msi_desc */
static struct hlist_head *msi_hash;
-static unsigned int msihash_shift = 6;
-#define msi_hashfn(nr) hash_long(nr, msihash_shift)
+static const unsigned int msi_hash_bits = 8;
+#define MSI_HASH_BUCKETS (1U << msi_hash_bits)
+#define msi_hashfn(nr) hash_long(nr, msi_hash_bits)
static DEFINE_SPINLOCK(msi_map_lock);
@@ -74,6 +75,7 @@ int zpci_setup_msi_irq(struct zpci_dev *zdev, struct msi_desc *msi,
map->irq = nr;
map->msi = msi;
zdev->msi_map[nr & ZPCI_MSI_MASK] = map;
+ INIT_HLIST_NODE(&map->msi_chain);
pr_debug("%s hashing irq: %u to bucket nr: %llu\n",
__func__, nr, msi_hashfn(nr));
@@ -125,11 +127,11 @@ int __init zpci_msihash_init(void)
{
unsigned int i;
- msi_hash = kmalloc(256 * sizeof(*msi_hash), GFP_KERNEL);
+ msi_hash = kmalloc(MSI_HASH_BUCKETS * sizeof(*msi_hash), GFP_KERNEL);
if (!msi_hash)
return -ENOMEM;
- for (i = 0; i < (1U << msihash_shift); i++)
+ for (i = 0; i < MSI_HASH_BUCKETS; i++)
INIT_HLIST_HEAD(&msi_hash[i]);
return 0;
}
diff --git a/arch/score/kernel/process.c b/arch/score/kernel/process.c
index 79568466b578..f4c6d02421d3 100644
--- a/arch/score/kernel/process.c
+++ b/arch/score/kernel/process.c
@@ -41,24 +41,6 @@ void machine_halt(void) {}
/* If or when software machine-power-off is implemented, add code here. */
void machine_power_off(void) {}
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void __noreturn cpu_idle(void)
-{
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- barrier();
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
-}
-
void ret_from_fork(void);
void ret_from_kernel_thread(void);
diff --git a/arch/score/kernel/traps.c b/arch/score/kernel/traps.c
index 0e46fb19a848..1517a7dcd6d9 100644
--- a/arch/score/kernel/traps.c
+++ b/arch/score/kernel/traps.c
@@ -117,6 +117,8 @@ static void show_code(unsigned int *pc)
*/
void show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_DEFAULT);
+
printk("r0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
regs->regs[0], regs->regs[1], regs->regs[2], regs->regs[3],
regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
@@ -149,16 +151,6 @@ static void show_registers(struct pt_regs *regs)
printk(KERN_NOTICE "\n");
}
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- show_stack(current_thread_info()->task,
- (long *) get_irq_regs()->regs[0]);
-}
-EXPORT_SYMBOL(dump_stack);
-
void __die(const char *str, struct pt_regs *regs, const char *file,
const char *func, unsigned long line)
{
diff --git a/arch/score/mm/init.c b/arch/score/mm/init.c
index 8b6f796c6ade..d8f988a37d16 100644
--- a/arch/score/mm/init.c
+++ b/arch/score/mm/init.c
@@ -43,7 +43,7 @@ EXPORT_SYMBOL_GPL(empty_zero_page);
static struct kcore_list kcore_mem, kcore_vmalloc;
-static unsigned long setup_zero_page(void)
+static void setup_zero_page(void)
{
struct page *page;
@@ -52,9 +52,7 @@ static unsigned long setup_zero_page(void)
panic("Oh boy, that early out of memory?");
page = virt_to_page((void *) empty_zero_page);
- SetPageReserved(page);
-
- return 1UL;
+ mark_page_reserved(page);
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -84,7 +82,7 @@ void __init mem_init(void)
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
totalram_pages += free_all_bootmem();
- totalram_pages -= setup_zero_page(); /* Setup zeroed pages. */
+ setup_zero_page(); /* Setup zeroed pages. */
reservedpages = 0;
for (tmp = 0; tmp < max_low_pfn; tmp++)
@@ -109,37 +107,16 @@ void __init mem_init(void)
}
#endif /* !CONFIG_NEED_MULTIPLE_NODES */
-static void free_init_pages(const char *what, unsigned long begin, unsigned long end)
-{
- unsigned long pfn;
-
- for (pfn = PFN_UP(begin); pfn < PFN_DOWN(end); pfn++) {
- struct page *page = pfn_to_page(pfn);
- void *addr = phys_to_virt(PFN_PHYS(pfn));
-
- ClearPageReserved(page);
- init_page_count(page);
- memset(addr, POISON_FREE_INITMEM, PAGE_SIZE);
- __free_page(page);
- totalram_pages++;
- }
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
-}
-
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_init_pages("initrd memory",
- virt_to_phys((void *) start),
- virt_to_phys((void *) end));
+ free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
}
#endif
void __init_refok free_initmem(void)
{
- free_init_pages("unused kernel memory",
- __pa(&__init_begin),
- __pa(&__init_end));
+ free_initmem_default(POISON_FREE_INITMEM);
}
unsigned long pgd_current;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 5e859633ce69..78d8ace57272 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -33,6 +33,7 @@ config SUPERH
select GENERIC_ATOMIC64
select GENERIC_IRQ_SHOW
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_IDLE_POLL_SETUP
select GENERIC_CLOCKEVENTS
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
select GENERIC_STRNCPY_FROM_USER
@@ -148,9 +149,6 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
def_bool n
-config ARCH_HAS_DEFAULT_IDLE
- def_bool y
-
config NO_IOPORT
def_bool !PCI
depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \
@@ -624,25 +622,7 @@ config SH_CLK_CPG_LEGACY
endmenu
menu "CPU Frequency scaling"
-
source "drivers/cpufreq/Kconfig"
-
-config SH_CPU_FREQ
- tristate "SuperH CPU Frequency driver"
- depends on CPU_FREQ
- select CPU_FREQ_TABLE
- help
- This adds the cpufreq driver for SuperH. Any CPU that supports
- clock rate rounding through the clock framework can use this
- driver. While it will make the kernel slightly larger, this is
- harmless for CPUs that don't support rate rounding. The driver
- will also generate a notice in the boot log before disabling
- itself if the CPU in question is not capable of rate rounding.
-
- For details, take a look at <file:Documentation/cpu-freq>.
-
- If unsure, say N.
-
endmenu
source "arch/sh/drivers/Kconfig"
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index aaff7671101b..764530c85aa9 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -254,11 +254,13 @@ static int usbhs_get_id(struct platform_device *pdev)
return gpio_get_value(GPIO_PTB3);
}
-static void usbhs_phy_reset(struct platform_device *pdev)
+static int usbhs_phy_reset(struct platform_device *pdev)
{
/* enable vbus if HOST */
if (!gpio_get_value(GPIO_PTB3))
gpio_set_value(GPIO_PTB5, 1);
+
+ return 0;
}
static struct renesas_usbhs_platform_info usbhs_info = {
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index c2c85f6cd738..a162a7f86b2e 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -35,7 +35,7 @@ static unsigned int nr_ports;
static struct sh7786_pcie_hwops {
int (*core_init)(void);
- async_func_ptr *port_init_hw;
+ async_func_t port_init_hw;
} *sh7786_pcie_hwops;
static struct resource sh7786_pci0_resources[] = {
diff --git a/arch/sh/include/asm/hugetlb.h b/arch/sh/include/asm/hugetlb.h
index b3808c7d67b2..699255d6d1c6 100644
--- a/arch/sh/include/asm/hugetlb.h
+++ b/arch/sh/include/asm/hugetlb.h
@@ -3,6 +3,7 @@
#include <asm/cacheflush.h>
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h
index e14567a7e9a1..70ae0b2888ab 100644
--- a/arch/sh/include/asm/suspend.h
+++ b/arch/sh/include/asm/suspend.h
@@ -14,9 +14,9 @@ struct swsusp_arch_regs {
void sh_mobile_call_standby(unsigned long mode);
#ifdef CONFIG_CPU_IDLE
-void sh_mobile_setup_cpuidle(void);
+int sh_mobile_setup_cpuidle(void);
#else
-static inline void sh_mobile_setup_cpuidle(void) {}
+static inline int sh_mobile_setup_cpuidle(void) { return 0; }
#endif
/* notifier chains for pre/post sleep hooks */
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index 7d5ac4e48485..45a93669289d 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -207,8 +207,6 @@ static inline bool test_and_clear_restore_sigmask(void)
return true;
}
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h
index 5e90fa2b7eed..e77816c4b9bc 100644
--- a/arch/sh/include/asm/unistd.h
+++ b/arch/sh/include/asm/unistd.h
@@ -30,12 +30,4 @@
# define __ARCH_WANT_SYS_VFORK
# define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-# define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#include <uapi/asm/unistd.h>
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index f259b37874e9..261c8bfd75ce 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -31,7 +31,6 @@ obj-$(CONFIG_VSYSCALL) += vsyscall/
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
obj-$(CONFIG_KGDB) += kgdb.o
-obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_MODULES) += sh_ksyms_$(BITS).o module.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index 1ddc876d3b26..d30622592116 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -51,70 +51,53 @@ static int cpuidle_sleep_enter(struct cpuidle_device *dev,
return k;
}
-static struct cpuidle_device cpuidle_dev;
static struct cpuidle_driver cpuidle_driver = {
- .name = "sh_idle",
- .owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
+ .name = "sh_idle",
+ .owner = THIS_MODULE,
+ .states = {
+ {
+ .exit_latency = 1,
+ .target_residency = 1 * 2,
+ .power_usage = 3,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = cpuidle_sleep_enter,
+ .name = "C1",
+ .desc = "SuperH Sleep Mode",
+ },
+ {
+ .exit_latency = 100,
+ .target_residency = 1 * 2,
+ .power_usage = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = cpuidle_sleep_enter,
+ .name = "C2",
+ .desc = "SuperH Sleep Mode [SF]",
+ .disabled = true,
+ },
+ {
+ .exit_latency = 2300,
+ .target_residency = 1 * 2,
+ .power_usage = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = cpuidle_sleep_enter,
+ .name = "C3",
+ .desc = "SuperH Mobile Standby Mode [SF]",
+ .disabled = true,
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = 3,
};
-void sh_mobile_setup_cpuidle(void)
+int __init sh_mobile_setup_cpuidle(void)
{
- struct cpuidle_device *dev = &cpuidle_dev;
- struct cpuidle_driver *drv = &cpuidle_driver;
- struct cpuidle_state *state;
- int i;
+ int ret;
+ if (sh_mobile_sleep_supported & SUSP_SH_SF)
+ cpuidle_driver.states[1].disabled = false;
- for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
- drv->states[i].name[0] = '\0';
- drv->states[i].desc[0] = '\0';
- }
+ if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
+ cpuidle_driver.states[2].disabled = false;
- i = CPUIDLE_DRIVER_STATE_START;
-
- state = &drv->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
- strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);
- state->exit_latency = 1;
- state->target_residency = 1 * 2;
- state->power_usage = 3;
- state->flags = 0;
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->enter = cpuidle_sleep_enter;
-
- drv->safe_state_index = i-1;
-
- if (sh_mobile_sleep_supported & SUSP_SH_SF) {
- state = &drv->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
- strncpy(state->desc, "SuperH Sleep Mode [SF]",
- CPUIDLE_DESC_LEN);
- state->exit_latency = 100;
- state->target_residency = 1 * 2;
- state->power_usage = 1;
- state->flags = 0;
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->enter = cpuidle_sleep_enter;
- }
-
- if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
- state = &drv->states[i++];
- snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
- strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
- CPUIDLE_DESC_LEN);
- state->exit_latency = 2300;
- state->target_residency = 1 * 2;
- state->power_usage = 1;
- state->flags = 0;
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
- state->enter = cpuidle_sleep_enter;
- }
-
- drv->state_count = i;
- dev->state_count = i;
-
- cpuidle_register_driver(&cpuidle_driver);
-
- cpuidle_register_device(dev);
+ return cpuidle_register(&cpuidle_driver);
}
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c
index 08d27fac8d08..ac37b7234f85 100644
--- a/arch/sh/kernel/cpu/shmobile/pm.c
+++ b/arch/sh/kernel/cpu/shmobile/pm.c
@@ -150,8 +150,7 @@ static const struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
suspend_set_ops(&sh_pm_ops);
- sh_mobile_setup_cpuidle();
- return 0;
+ return sh_mobile_setup_cpuidle();
}
late_initcall(sh_pm_init);
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
index 7617dc4129ac..b959f5592604 100644
--- a/arch/sh/kernel/dumpstack.c
+++ b/arch/sh/kernel/dumpstack.c
@@ -158,9 +158,3 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
(unsigned long)task_stack_page(tsk));
show_trace(tsk, sp, NULL);
}
-
-void dump_stack(void)
-{
- show_stack(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 3d5a1b387cc0..2ea4483fd722 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -24,98 +24,24 @@
static void (*sh_idle)(void);
-static int hlt_counter;
-
-static int __init nohlt_setup(char *__unused)
-{
- hlt_counter = 1;
- return 1;
-}
-__setup("nohlt", nohlt_setup);
-
-static int __init hlt_setup(char *__unused)
-{
- hlt_counter = 0;
- return 1;
-}
-__setup("hlt", hlt_setup);
-
-static inline int hlt_works(void)
-{
- return !hlt_counter;
-}
-
-/*
- * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->work.need_resched flag instead of waiting for the
- * cross-CPU IPI to arrive. Use this option with caution.
- */
-static void poll_idle(void)
+void default_idle(void)
{
+ set_bl_bit();
local_irq_enable();
- while (!need_resched())
- cpu_relax();
+ /* Isn't this racy ? */
+ cpu_sleep();
+ clear_bl_bit();
}
-void default_idle(void)
+void arch_cpu_idle_dead(void)
{
- if (hlt_works()) {
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb__after_clear_bit();
-
- set_bl_bit();
- if (!need_resched()) {
- local_irq_enable();
- cpu_sleep();
- } else
- local_irq_enable();
-
- set_thread_flag(TIF_POLLING_NRFLAG);
- clear_bl_bit();
- } else
- poll_idle();
+ play_dead();
}
-/*
- * The idle thread. There's no useful work to be done, so just try to conserve
- * power and have a low exit latency (ie sit in a loop waiting for somebody to
- * say that they'd like to reschedule)
- */
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- unsigned int cpu = smp_processor_id();
-
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched()) {
- check_pgt_cache();
- rmb();
-
- if (cpu_is_offline(cpu))
- play_dead();
-
- local_irq_disable();
- /* Don't trace irqs off for idle */
- stop_critical_timings();
- if (cpuidle_idle_call())
- sh_idle();
- /*
- * Sanity check to ensure that sh_idle() returns
- * with IRQs enabled
- */
- WARN_ON(irqs_disabled());
- start_critical_timings();
- }
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+ if (cpuidle_idle_call())
+ sh_idle();
}
void __init select_idle_routine(void)
@@ -123,13 +49,8 @@ void __init select_idle_routine(void)
/*
* If a platform has set its own idle routine, leave it alone.
*/
- if (sh_idle)
- return;
-
- if (hlt_works())
+ if (!sh_idle)
sh_idle = default_idle;
- else
- sh_idle = poll_idle;
}
void stop_this_cpu(void *unused)
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 73eb66fc6253..ebd3933005b4 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -32,11 +32,7 @@
void show_regs(struct pt_regs * regs)
{
printk("\n");
- printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm);
- printk("CPU : %d \t\t%s (%s %.*s)\n\n",
- smp_processor_id(), print_tainted(), init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
+ show_regs_print_info(KERN_DEFAULT);
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("PR is at %s\n", regs->pr);
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index e611c85144b1..174d124b419e 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -40,6 +40,7 @@ void show_regs(struct pt_regs *regs)
unsigned long long ah, al, bh, bl, ch, cl;
printk("\n");
+ show_regs_print_info(KERN_DEFAULT);
ah = (regs->pc) >> 32;
al = (regs->pc) & 0xffffffff;
diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c
index 47475cca068a..fe584e516964 100644
--- a/arch/sh/kernel/sh_bios.c
+++ b/arch/sh/kernel/sh_bios.c
@@ -104,6 +104,7 @@ void sh_bios_vbr_reload(void)
);
}
+#ifdef CONFIG_EARLY_PRINTK
/*
* Print a string through the BIOS
*/
@@ -144,8 +145,6 @@ static struct console bios_console = {
.index = -1,
};
-static struct console *early_console;
-
static int __init setup_early_printk(char *buf)
{
int keep_early = 0;
@@ -170,3 +169,4 @@ static int __init setup_early_printk(char *buf)
return 0;
}
early_param("earlyprintk", setup_early_printk);
+#endif
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 2062aa88af41..45696451f0ea 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -203,7 +203,7 @@ asmlinkage void __cpuinit start_secondary(void)
set_cpu_online(cpu, true);
per_cpu(cpu_state, cpu) = CPU_ONLINE;
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
extern struct {
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 105794037143..20f9ead650d3 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -417,15 +417,13 @@ void __init mem_init(void)
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
- unsigned long node_pages = 0;
void *node_high_memory;
num_physpages += pgdat->node_present_pages;
if (pgdat->node_spanned_pages)
- node_pages = free_all_bootmem_node(pgdat);
+ totalram_pages += free_all_bootmem_node(pgdat);
- totalram_pages += node_pages;
node_high_memory = (void *)__va((pgdat->node_start_pfn +
pgdat->node_spanned_pages) <<
@@ -501,31 +499,13 @@ void __init mem_init(void)
void free_initmem(void)
{
- unsigned long addr;
-
- addr = (unsigned long)(&__init_begin);
- for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk("Freeing unused kernel memory: %ldk freed\n",
- ((unsigned long)&__init_end -
- (unsigned long)&__init_begin) >> 10);
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- unsigned long p;
- for (p = start; p < end; p += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(p));
- init_page_count(virt_to_page(p));
- free_page(p);
- totalram_pages++;
- }
- printk("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 3d361f236308..f5041d741dea 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -62,7 +62,6 @@ config SPARC64
select HAVE_RCU_TABLE_FREE if SMP
select HAVE_MEMBLOCK
select HAVE_MEMBLOCK_NODE_MAP
- select HAVE_SYSCALL_WRAPPERS
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
@@ -254,29 +253,6 @@ config HOTPLUG_CPU
if SPARC64
source "drivers/cpufreq/Kconfig"
-
-config US3_FREQ
- tristate "UltraSPARC-III CPU Frequency driver"
- depends on CPU_FREQ
- select CPU_FREQ_TABLE
- help
- This adds the CPUFreq driver for UltraSPARC-III processors.
-
- For details, take a look at <file:Documentation/cpu-freq>.
-
- If in doubt, say N.
-
-config US2E_FREQ
- tristate "UltraSPARC-IIe CPU Frequency driver"
- depends on CPU_FREQ
- select CPU_FREQ_TABLE
- help
- This adds the CPUFreq driver for UltraSPARC-IIe processors.
-
- For details, take a look at <file:Documentation/cpu-freq>.
-
- If in doubt, say N.
-
endif
config US3_MC
@@ -407,6 +383,8 @@ config SERIAL_CONSOLE
config SPARC_LEON
bool "Sparc Leon processor family"
depends on SPARC32
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_DESC
---help---
If you say Y here if you are running on a SPARC-LEON processor.
The LEON processor is a synthesizable VHDL model of the
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index e26d430ce2fd..ff18e3cfb6b1 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -2,11 +2,16 @@
generic-y += clkdev.h
+generic-y += cputime.h
generic-y += div64.h
+generic-y += emergency-restart.h
generic-y += exec.h
generic-y += local64.h
+generic-y += mutex.h
generic-y += irq_regs.h
generic-y += local.h
generic-y += module.h
+generic-y += serial.h
generic-y += trace_clock.h
+generic-y += types.h
generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/cputime.h b/arch/sparc/include/asm/cputime.h
deleted file mode 100644
index 1a642b81e019..000000000000
--- a/arch/sparc/include/asm/cputime.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_CPUTIME_H
-#define __SPARC_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __SPARC_CPUTIME_H */
diff --git a/arch/sparc/include/asm/emergency-restart.h b/arch/sparc/include/asm/emergency-restart.h
deleted file mode 100644
index 108d8c48e42e..000000000000
--- a/arch/sparc/include/asm/emergency-restart.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/sparc/include/asm/hugetlb.h b/arch/sparc/include/asm/hugetlb.h
index 7eb57d245044..e4cab465b81f 100644
--- a/arch/sparc/include/asm/hugetlb.h
+++ b/arch/sparc/include/asm/hugetlb.h
@@ -2,6 +2,7 @@
#define _ASM_SPARC64_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
diff --git a/arch/sparc/include/asm/mutex.h b/arch/sparc/include/asm/mutex.h
deleted file mode 100644
index 458c1f7fbc18..000000000000
--- a/arch/sparc/include/asm/mutex.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 08fcce90316b..7619f2f792af 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -915,6 +915,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
}
+#include <asm/tlbflush.h>
#include <asm-generic/pgtable.h>
/* We provide our own get_unmapped_area to cope with VA holes and
diff --git a/arch/sparc/include/asm/serial.h b/arch/sparc/include/asm/serial.h
deleted file mode 100644
index f90d61c28059..000000000000
--- a/arch/sparc/include/asm/serial.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __SPARC_SERIAL_H
-#define __SPARC_SERIAL_H
-
-#define BASE_BAUD ( 1843200 / 16 )
-
-#endif /* __SPARC_SERIAL_H */
diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h
index b73da3c5f10a..3c8917f054de 100644
--- a/arch/sparc/include/asm/smp_32.h
+++ b/arch/sparc/include/asm/smp_32.h
@@ -36,7 +36,6 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long);
void cpu_panic(void);
-extern void smp4m_irq_rotate(int cpu);
/*
* General functions that each host system must provide.
@@ -46,7 +45,6 @@ void sun4m_init_smp(void);
void sun4d_init_smp(void);
void smp_callin(void);
-void smp_boot_cpus(void);
void smp_store_cpu_info(int);
void smp_resched_interrupt(void);
@@ -107,9 +105,6 @@ extern int hard_smp_processor_id(void);
#define raw_smp_processor_id() (current_thread_info()->cpu)
-#define prof_multiplier(__cpu) cpu_data(__cpu).multiplier
-#define prof_counter(__cpu) cpu_data(__cpu).counter
-
void smp_setup_cpu_possible_map(void);
#endif /* !(__ASSEMBLY__) */
diff --git a/arch/sparc/include/asm/switch_to_64.h b/arch/sparc/include/asm/switch_to_64.h
index cad36f56fa03..c7de3323819c 100644
--- a/arch/sparc/include/asm/switch_to_64.h
+++ b/arch/sparc/include/asm/switch_to_64.h
@@ -18,8 +18,7 @@ do { \
* and 2 stores in this critical code path. -DaveM
*/
#define switch_to(prev, next, last) \
-do { flush_tlb_pending(); \
- save_and_clear_fpu(); \
+do { save_and_clear_fpu(); \
/* If you are tempted to conditionalize the following */ \
/* so that ASI is only written if it changes, think again. */ \
__asm__ __volatile__("wr %%g0, %0, %%asi" \
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h
index 25849ae3e900..dd3807599bb9 100644
--- a/arch/sparc/include/asm/thread_info_32.h
+++ b/arch/sparc/include/asm/thread_info_32.h
@@ -132,8 +132,6 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define _TIF_DO_NOTIFY_RESUME_MASK (_TIF_NOTIFY_RESUME | \
_TIF_SIGPENDING)
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h
index 269bd92313df..d5e504251079 100644
--- a/arch/sparc/include/asm/thread_info_64.h
+++ b/arch/sparc/include/asm/thread_info_64.h
@@ -256,8 +256,6 @@ static inline bool test_and_clear_restore_sigmask(void)
return true;
}
-#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
-
#define thread32_stack_is_64bit(__SP) (((__SP) & 0x1) != 0)
#define test_thread_64bit_stack(__SP) \
((test_thread_flag(TIF_32BIT) && !thread32_stack_is_64bit(__SP)) ? \
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index 2ef463494153..f0d6a9700f4c 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -11,24 +11,40 @@
struct tlb_batch {
struct mm_struct *mm;
unsigned long tlb_nr;
+ unsigned long active;
unsigned long vaddrs[TLB_BATCH_NR];
};
extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
extern void flush_tsb_user(struct tlb_batch *tb);
+extern void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr);
/* TLB flush operations. */
-extern void flush_tlb_pending(void);
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long vmaddr)
+{
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
-#define flush_tlb_range(vma,start,end) \
- do { (void)(start); flush_tlb_pending(); } while (0)
-#define flush_tlb_page(vma,addr) flush_tlb_pending()
-#define flush_tlb_mm(mm) flush_tlb_pending()
+extern void flush_tlb_pending(void);
+extern void arch_enter_lazy_mmu_mode(void);
+extern void arch_leave_lazy_mmu_mode(void);
+#define arch_flush_lazy_mmu_mode() do {} while (0)
/* Local cpu only. */
extern void __flush_tlb_all(void);
-
+extern void __flush_tlb_page(unsigned long context, unsigned long vaddr);
extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);
#ifndef CONFIG_SMP
@@ -38,15 +54,24 @@ do { flush_tsb_kernel_range(start,end); \
__flush_tlb_kernel_range(start,end); \
} while (0)
+static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
+{
+ __flush_tlb_page(CTX_HWBITS(mm->context), vaddr);
+}
+
#else /* CONFIG_SMP */
extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);
#define flush_tlb_kernel_range(start, end) \
do { flush_tsb_kernel_range(start,end); \
smp_flush_tlb_kernel_range(start, end); \
} while (0)
+#define global_flush_tlb_page(mm, vaddr) \
+ smp_flush_tlb_page(mm, vaddr)
+
#endif /* ! CONFIG_SMP */
#endif /* _SPARC64_TLBFLUSH_H */
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 5356810bd7e7..dfa53fdd5cbc 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -45,12 +45,4 @@
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/uapi/asm/Kbuild b/arch/sparc/include/uapi/asm/Kbuild
index ce175aff71b7..b5843ee09fb5 100644
--- a/arch/sparc/include/uapi/asm/Kbuild
+++ b/arch/sparc/include/uapi/asm/Kbuild
@@ -44,7 +44,6 @@ header-y += swab.h
header-y += termbits.h
header-y += termios.h
header-y += traps.h
-header-y += types.h
header-y += uctx.h
header-y += unistd.h
header-y += utrap.h
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index cbbad74b2e06..89f49b68a21c 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -68,6 +68,8 @@
#define SO_LOCK_FILTER 0x0028
+#define SO_SELECT_ERR_QUEUE 0x0029
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/arch/sparc/include/uapi/asm/types.h b/arch/sparc/include/uapi/asm/types.h
deleted file mode 100644
index 383d156cde9c..000000000000
--- a/arch/sparc/include/uapi/asm/types.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _SPARC_TYPES_H
-#define _SPARC_TYPES_H
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue. However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-
-#if defined(__sparc__)
-
-#include <asm-generic/int-ll64.h>
-
-#endif /* defined(__sparc__) */
-
-#endif /* defined(_SPARC_TYPES_H) */
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 6cf591b7e1c6..5276fd4e9d03 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -102,9 +102,6 @@ obj-$(CONFIG_PCI_MSI) += pci_msi.o
obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
-# sparc64 cpufreq
-obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
-obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
obj-$(CONFIG_US3_MC) += chmc.o
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S
index 9365432904d6..605c960b2fa6 100644
--- a/arch/sparc/kernel/hvtramp.S
+++ b/arch/sparc/kernel/hvtramp.S
@@ -128,8 +128,7 @@ hv_cpu_startup:
call smp_callin
nop
- call cpu_idle
- mov 0, %o0
+
call cpu_panic
nop
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 62eede13831a..fdd819dfdacf 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -64,23 +64,12 @@ extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
struct task_struct *last_task_used_math = NULL;
struct thread_info *current_set[NR_CPUS];
-/*
- * the idle loop on a Sparc... ;)
- */
-void cpu_idle(void)
+/* Idle loop support. */
+void arch_cpu_idle(void)
{
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- /* endless idle loop with no priority at all */
- for (;;) {
- while (!need_resched()) {
- if (sparc_idle)
- (*sparc_idle)();
- else
- cpu_relax();
- }
- schedule_preempt_disabled();
- }
+ if (sparc_idle)
+ (*sparc_idle)();
+ local_irq_enable();
}
/* XXX cli/sti -> local_irq_xxx here, check this works once SMP is fixed. */
@@ -123,6 +112,8 @@ void show_regs(struct pt_regs *r)
{
struct reg_window32 *rw = (struct reg_window32 *) r->u_regs[14];
+ show_regs_print_info(KERN_DEFAULT);
+
printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx %s\n",
r->psr, r->pc, r->npc, r->y, print_tainted());
printk("PC: <%pS>\n", (void *) r->pc);
@@ -153,11 +144,13 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
struct reg_window32 *rw;
int count = 0;
- if (tsk != NULL)
- task_base = (unsigned long) task_stack_page(tsk);
- else
- task_base = (unsigned long) current_thread_info();
+ if (!tsk)
+ tsk = current;
+ if (tsk == current && !_ksp)
+ __asm__ __volatile__("mov %%fp, %0" : "=r" (_ksp));
+
+ task_base = (unsigned long) task_stack_page(tsk);
fp = (unsigned long) _ksp;
do {
/* Bogus frame pointer? */
@@ -173,17 +166,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
printk("\n");
}
-void dump_stack(void)
-{
- unsigned long *ksp;
-
- __asm__ __volatile__("mov %%fp, %0"
- : "=r" (ksp));
- show_stack(current, ksp);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
/*
* Note: sparc64 has a pretty intricated thread_saved_pc, check it out.
*/
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index cdb80b2adbe0..baebab215492 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -52,20 +52,17 @@
#include "kstack.h"
-static void sparc64_yield(int cpu)
+/* Idle loop support on sparc64. */
+void arch_cpu_idle(void)
{
if (tlb_type != hypervisor) {
touch_nmi_watchdog();
- return;
- }
-
- clear_thread_flag(TIF_POLLING_NRFLAG);
- smp_mb__after_clear_bit();
-
- while (!need_resched() && !cpu_is_offline(cpu)) {
+ } else {
unsigned long pstate;
- /* Disable interrupts. */
+ /* The sun4v sleeping code requires that we have PSTATE.IE cleared over
+ * the cpu sleep hypervisor call.
+ */
__asm__ __volatile__(
"rdpr %%pstate, %0\n\t"
"andn %0, %1, %0\n\t"
@@ -73,7 +70,7 @@ static void sparc64_yield(int cpu)
: "=&r" (pstate)
: "i" (PSTATE_IE));
- if (!need_resched() && !cpu_is_offline(cpu))
+ if (!need_resched() && !cpu_is_offline(smp_processor_id()))
sun4v_cpu_yield();
/* Re-enable interrupts. */
@@ -84,36 +81,16 @@ static void sparc64_yield(int cpu)
: "=&r" (pstate)
: "i" (PSTATE_IE));
}
-
- set_thread_flag(TIF_POLLING_NRFLAG);
+ local_irq_enable();
}
-/* The idle loop on sparc64. */
-void cpu_idle(void)
-{
- int cpu = smp_processor_id();
-
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while(1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
-
- while (!need_resched() && !cpu_is_offline(cpu))
- sparc64_yield(cpu);
-
- rcu_idle_exit();
- tick_nohz_idle_exit();
-
#ifdef CONFIG_HOTPLUG_CPU
- if (cpu_is_offline(cpu)) {
- sched_preempt_enable_no_resched();
- cpu_play_dead();
- }
-#endif
- schedule_preempt_disabled();
- }
+void arch_cpu_idle_dead()
+{
+ sched_preempt_enable_no_resched();
+ cpu_play_dead();
}
+#endif
#ifdef CONFIG_COMPAT
static void show_regwindow32(struct pt_regs *regs)
@@ -186,6 +163,8 @@ static void show_regwindow(struct pt_regs *regs)
void show_regs(struct pt_regs *regs)
{
+ show_regs_print_info(KERN_DEFAULT);
+
printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x %s\n", regs->tstate,
regs->tpc, regs->tnpc, regs->y, print_tainted());
printk("TPC: <%pS>\n", (void *) regs->tpc);
@@ -315,7 +294,7 @@ static void sysrq_handle_globreg(int key)
static struct sysrq_key_op sparc_globalreg_op = {
.handler = sysrq_handle_globreg,
- .help_msg = "global-regs(Y)",
+ .help_msg = "global-regs(y)",
.action_msg = "Show Global CPU Regs",
};
@@ -385,7 +364,7 @@ static void sysrq_handle_globpmu(int key)
static struct sysrq_key_op sparc_globalpmu_op = {
.handler = sysrq_handle_globpmu,
- .help_msg = "global-pmu(X)",
+ .help_msg = "global-pmu(x)",
.action_msg = "Show Global PMU Regs",
};
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index 9e7e6d718367..e3f2b81c23f1 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -369,7 +369,7 @@ void __cpuinit sparc_start_secondary(void *arg)
local_irq_enable();
wmb();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
/* We should never reach here! */
BUG();
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 537eb66abd06..77539eda928c 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -127,6 +127,8 @@ void __cpuinit smp_callin(void)
/* idle thread is expected to have preempt disabled */
preempt_disable();
+
+ cpu_startup_entry(CPUHP_ONLINE);
}
void cpu_panic(void)
@@ -849,7 +851,7 @@ void smp_tsb_sync(struct mm_struct *mm)
}
extern unsigned long xcall_flush_tlb_mm;
-extern unsigned long xcall_flush_tlb_pending;
+extern unsigned long xcall_flush_tlb_page;
extern unsigned long xcall_flush_tlb_kernel_range;
extern unsigned long xcall_fetch_glob_regs;
extern unsigned long xcall_fetch_glob_pmu;
@@ -1074,23 +1076,56 @@ local_flush_and_out:
put_cpu();
}
+struct tlb_pending_info {
+ unsigned long ctx;
+ unsigned long nr;
+ unsigned long *vaddrs;
+};
+
+static void tlb_pending_func(void *info)
+{
+ struct tlb_pending_info *t = info;
+
+ __flush_tlb_pending(t->ctx, t->nr, t->vaddrs);
+}
+
void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)
{
u32 ctx = CTX_HWBITS(mm->context);
+ struct tlb_pending_info info;
int cpu = get_cpu();
+ info.ctx = ctx;
+ info.nr = nr;
+ info.vaddrs = vaddrs;
+
if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
else
- smp_cross_call_masked(&xcall_flush_tlb_pending,
- ctx, nr, (unsigned long) vaddrs,
- mm_cpumask(mm));
+ smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
+ &info, 1);
__flush_tlb_pending(ctx, nr, vaddrs);
put_cpu();
}
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
+{
+ unsigned long context = CTX_HWBITS(mm->context);
+ int cpu = get_cpu();
+
+ if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
+ cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
+ else
+ smp_cross_call_masked(&xcall_flush_tlb_page,
+ context, vaddr, 0,
+ mm_cpumask(mm));
+ __flush_tlb_page(context, vaddr);
+
+ put_cpu();
+}
+
void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
start &= PAGE_MASK;
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index 240a3cecc11e..2e680b5245c9 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -36,7 +36,6 @@ STUB: sra REG1, 0, REG1; \
jmpl %g1 + %lo(SYSCALL), %g0; \
sra REG3, 0, REG3
-SIGN1(sys32_getrusage, compat_sys_getrusage, %o0)
SIGN1(sys32_readahead, compat_sys_readahead, %o0)
SIGN2(sys32_fadvise64, compat_sys_fadvise64, %o0, %o4)
SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)
@@ -46,12 +45,9 @@ SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
SIGN1(sys32_mq_open, compat_sys_mq_open, %o1)
SIGN1(sys32_select, compat_sys_select, %o0)
SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)
-SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1)
SIGN1(sys32_recvfrom, compat_sys_recvfrom, %o0)
SIGN1(sys32_recvmsg, compat_sys_recvmsg, %o0)
SIGN1(sys32_sendmsg, compat_sys_sendmsg, %o0)
-SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5)
-SIGN1(sys32_vmsplice, compat_sys_vmsplice, %o0)
.globl sys32_mmap2
sys32_mmap2:
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index f38f2280fade..3d0ddbc005fe 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -49,71 +49,6 @@
#include <asm/mmu_context.h>
#include <asm/compat_signal.h>
-#ifdef CONFIG_SYSVIPC
-asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
-{
- int version;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMTIMEDOP:
- if (fifth)
- /* sign extend semid */
- return compat_sys_semtimedop((int)first,
- compat_ptr(ptr), second,
- compat_ptr(fifth));
- /* else fall through for normal semop() */
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- /* sign extend semid */
- return sys_semtimedop((int)first, compat_ptr(ptr), second,
- NULL);
- case SEMGET:
- /* sign extend key, nsems */
- return sys_semget((int)first, (int)second, third);
- case SEMCTL:
- /* sign extend semid, semnum */
- return compat_sys_semctl((int)first, (int)second, third,
- compat_ptr(ptr));
-
- case MSGSND:
- /* sign extend msqid */
- return compat_sys_msgsnd((int)first, (int)second, third,
- compat_ptr(ptr));
- case MSGRCV:
- /* sign extend msqid, msgtyp */
- return compat_sys_msgrcv((int)first, second, (int)fifth,
- third, version, compat_ptr(ptr));
- case MSGGET:
- /* sign extend key */
- return sys_msgget((int)first, second);
- case MSGCTL:
- /* sign extend msqid */
- return compat_sys_msgctl((int)first, second, compat_ptr(ptr));
-
- case SHMAT:
- /* sign extend shmid */
- return compat_sys_shmat((int)first, second, third, version,
- compat_ptr(ptr));
- case SHMDT:
- return sys_shmdt(compat_ptr(ptr));
- case SHMGET:
- /* sign extend key_t */
- return sys_shmget((int)first, second, third);
- case SHMCTL:
- /* sign extend shmid */
- return compat_sys_shmctl((int)first, second, compat_ptr(ptr));
-
- default:
- return -ENOSYS;
- }
-
- return -ENOSYS;
-}
-#endif
-
asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
{
if ((int)high < 0)
@@ -303,15 +238,7 @@ long compat_sys_fadvise64_64(int fd,
advice);
}
-long sys32_lookup_dcookie(unsigned long cookie_high,
- unsigned long cookie_low,
- char __user *buf, size_t len)
-{
- return sys_lookup_dcookie((cookie_high << 32) | cookie_low,
- buf, len);
-}
-
-long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags)
+long sys32_sync_file_range(unsigned int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, unsigned int flags)
{
return sys_sync_file_range(fd,
(off_high << 32) | off_low,
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
index 708bc29d36a8..2daaaa6eda23 100644
--- a/arch/sparc/kernel/sys_sparc_64.c
+++ b/arch/sparc/kernel/sys_sparc_64.c
@@ -353,7 +353,7 @@ SYSCALL_DEFINE6(sparc_ipc, unsigned int, call, int, first, unsigned long, second
case SEMCTL: {
err = sys_semctl(first, second,
(int)third | IPC_64,
- (union semun) ptr);
+ (unsigned long) ptr);
goto out;
}
default:
@@ -470,10 +470,6 @@ SYSCALL_DEFINE2(64_munmap, unsigned long, addr, size_t, len)
return vm_munmap(addr, len);
}
-
-extern unsigned long do_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr);
SYSCALL_DEFINE5(64_mremap, unsigned long, addr, unsigned long, old_len,
unsigned long, new_len, unsigned long, flags,
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 088134834dab..8fd932080215 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -23,9 +23,9 @@ sys_call_table32:
/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod
/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, compat_sys_lseek
/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, compat_sys_sigaltstack, sys_pause
+/*25*/ .word compat_sys_vmsplice, compat_sys_ptrace, sys_alarm, compat_sys_sigaltstack, sys_pause
/*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice
- .word sys_chown, sys_sync, sys_kill, compat_sys_newstat, sys32_sendfile
+ .word sys_chown, sys_sync, sys_kill, compat_sys_newstat, compat_sys_sendfile
/*40*/ .word compat_sys_newlstat, sys_dup, sys_sparc_pipe, compat_sys_times, sys_getuid
.word sys_umount, sys_setgid16, sys_getgid16, sys_signal, sys_geteuid16
/*50*/ .word sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl
@@ -41,7 +41,7 @@ sys_call_table32:
/*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending
.word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
/*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
- .word sys_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
+ .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
/*120*/ .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
.word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
/*130*/ .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
@@ -59,7 +59,7 @@ sys_call_table32:
/*190*/ .word sys_init_module, sys_sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
.word sys_epoll_wait, sys_ioprio_set, sys_getppid, compat_sys_sparc_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
- .word sys32_readahead, sys32_socketcall, sys_syslog, sys32_lookup_dcookie, sys32_fadvise64
+ .word sys32_readahead, sys32_socketcall, sys_syslog, compat_sys_lookup_dcookie, sys32_fadvise64
/*210*/ .word sys32_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, compat_sys_sysinfo
.word compat_sys_ipc, sys32_sigreturn, sys_clone, sys_ioprio_get, compat_sys_adjtimex
/*220*/ .word compat_sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
diff --git a/arch/sparc/kernel/trampoline_64.S b/arch/sparc/kernel/trampoline_64.S
index da1b781b5e65..2e973a26fbda 100644
--- a/arch/sparc/kernel/trampoline_64.S
+++ b/arch/sparc/kernel/trampoline_64.S
@@ -407,8 +407,7 @@ after_lock_tlb:
call smp_callin
nop
- call cpu_idle
- mov 0, %o0
+
call cpu_panic
nop
1: b,a,pt %xcc, 1b
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c
index 8d38ca97aa23..b3f833ab90eb 100644
--- a/arch/sparc/kernel/traps_64.c
+++ b/arch/sparc/kernel/traps_64.c
@@ -2350,13 +2350,6 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
} while (++count < 16);
}
-void dump_stack(void)
-{
- show_stack(current, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
{
unsigned long fp = rw->ins[6];
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 8410065f2862..dbe119b63b48 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -45,4 +45,3 @@ obj-y += iomap.o
obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o
obj-y += ksyms.o
obj-$(CONFIG_SPARC64) += PeeCeeI.o
-obj-y += usercopy.o
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 48d00e72ce15..8ec4e9c0251a 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -119,11 +119,7 @@ void bit_map_clear(struct bit_map *t, int offset, int len)
void bit_map_init(struct bit_map *t, unsigned long *map, int size)
{
-
- if ((size & 07) != 0)
- BUG();
- memset(map, 0, size>>3);
-
+ bitmap_zero(map, size);
memset(t, 0, sizeof *t);
spin_lock_init(&t->lock);
t->map = map;
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 48e0c030e8f5..4490c397bb5b 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -282,14 +282,8 @@ static void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
printk("mapping high region %08lx - %08lx\n", start_pfn, end_pfn);
#endif
- for (tmp = start_pfn; tmp < end_pfn; tmp++) {
- struct page *page = pfn_to_page(tmp);
-
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
- }
+ for (tmp = start_pfn; tmp < end_pfn; tmp++)
+ free_highmem_page(pfn_to_page(tmp));
}
void __init mem_init(void)
@@ -347,8 +341,6 @@ void __init mem_init(void)
map_high_region(start_pfn, end_pfn);
}
- totalram_pages += totalhigh_pages;
-
codepages = (((unsigned long) &_etext) - ((unsigned long)&_start));
codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
datapages = (((unsigned long) &_edata) - ((unsigned long)&_etext));
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 1588d33d5492..6ac99d64a13c 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -2181,10 +2181,9 @@ unsigned long vmemmap_table[VMEMMAP_SIZE];
static long __meminitdata addr_start, addr_end;
static int __meminitdata node_start;
-int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
+int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
+ int node)
{
- unsigned long vstart = (unsigned long) start;
- unsigned long vend = (unsigned long) (start + nr);
unsigned long phys_start = (vstart - VMEMMAP_BASE);
unsigned long phys_end = (vend - VMEMMAP_BASE);
unsigned long addr = phys_start & VMEMMAP_CHUNK_MASK;
@@ -2236,7 +2235,7 @@ void __meminit vmemmap_populate_print_last(void)
}
}
-void vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void vmemmap_free(unsigned long start, unsigned long end)
{
}
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 0f4f7191fbba..28f96f27c768 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -34,7 +34,7 @@
#define IOMMU_RNGE IOMMU_RNGE_256MB
#define IOMMU_START 0xF0000000
#define IOMMU_WINSIZE (256*1024*1024U)
-#define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 265KB */
+#define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 256KB */
#define IOMMU_ORDER 6 /* 4096 * (1<<6) */
/* srmmu.c */
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index c38bb72e3e80..036c2797dece 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -280,7 +280,9 @@ static void __init srmmu_nocache_init(void)
SRMMU_NOCACHE_ALIGN_MAX, 0UL);
memset(srmmu_nocache_pool, 0, srmmu_nocache_size);
- srmmu_nocache_bitmap = __alloc_bootmem(bitmap_bits >> 3, SMP_CACHE_BYTES, 0UL);
+ srmmu_nocache_bitmap =
+ __alloc_bootmem(BITS_TO_LONGS(bitmap_bits) * sizeof(long),
+ SMP_CACHE_BYTES, 0UL);
bit_map_init(&srmmu_nocache_map, srmmu_nocache_bitmap, bitmap_bits);
srmmu_swapper_pg_dir = __srmmu_get_nocache(SRMMU_PGD_TABLE_SIZE, SRMMU_PGD_TABLE_SIZE);
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index ba6ae7ffdc2c..83d89bcb44af 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -24,11 +24,17 @@ static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
void flush_tlb_pending(void)
{
struct tlb_batch *tb = &get_cpu_var(tlb_batch);
+ struct mm_struct *mm = tb->mm;
- if (tb->tlb_nr) {
- flush_tsb_user(tb);
+ if (!tb->tlb_nr)
+ goto out;
- if (CTX_VALID(tb->mm->context)) {
+ flush_tsb_user(tb);
+
+ if (CTX_VALID(mm->context)) {
+ if (tb->tlb_nr == 1) {
+ global_flush_tlb_page(mm, tb->vaddrs[0]);
+ } else {
#ifdef CONFIG_SMP
smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
&tb->vaddrs[0]);
@@ -37,12 +43,30 @@ void flush_tlb_pending(void)
tb->tlb_nr, &tb->vaddrs[0]);
#endif
}
- tb->tlb_nr = 0;
}
+ tb->tlb_nr = 0;
+
+out:
put_cpu_var(tlb_batch);
}
+void arch_enter_lazy_mmu_mode(void)
+{
+ struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+ tb->active = 1;
+}
+
+void arch_leave_lazy_mmu_mode(void)
+{
+ struct tlb_batch *tb = &__get_cpu_var(tlb_batch);
+
+ if (tb->tlb_nr)
+ flush_tlb_pending();
+ tb->active = 0;
+}
+
static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
bool exec)
{
@@ -60,6 +84,12 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
nr = 0;
}
+ if (!tb->active) {
+ global_flush_tlb_page(mm, vaddr);
+ flush_tsb_user_page(mm, vaddr);
+ goto out;
+ }
+
if (nr == 0)
tb->mm = mm;
@@ -68,6 +98,7 @@ static void tlb_batch_add_one(struct mm_struct *mm, unsigned long vaddr,
if (nr >= TLB_BATCH_NR)
flush_tlb_pending();
+out:
put_cpu_var(tlb_batch);
}
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 428982b9becf..2cc3bce5ee91 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -7,11 +7,10 @@
#include <linux/preempt.h>
#include <linux/slab.h>
#include <asm/page.h>
-#include <asm/tlbflush.h>
-#include <asm/tlb.h>
-#include <asm/mmu_context.h>
#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
#include <asm/tsb.h>
+#include <asm/tlb.h>
#include <asm/oplib.h>
extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
@@ -46,23 +45,27 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
}
}
-static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
- unsigned long tsb, unsigned long nentries)
+static void __flush_tsb_one_entry(unsigned long tsb, unsigned long v,
+ unsigned long hash_shift,
+ unsigned long nentries)
{
- unsigned long i;
+ unsigned long tag, ent, hash;
- for (i = 0; i < tb->tlb_nr; i++) {
- unsigned long v = tb->vaddrs[i];
- unsigned long tag, ent, hash;
+ v &= ~0x1UL;
+ hash = tsb_hash(v, hash_shift, nentries);
+ ent = tsb + (hash * sizeof(struct tsb));
+ tag = (v >> 22UL);
- v &= ~0x1UL;
+ tsb_flush(ent, tag);
+}
- hash = tsb_hash(v, hash_shift, nentries);
- ent = tsb + (hash * sizeof(struct tsb));
- tag = (v >> 22UL);
+static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
+ unsigned long tsb, unsigned long nentries)
+{
+ unsigned long i;
- tsb_flush(ent, tag);
- }
+ for (i = 0; i < tb->tlb_nr; i++)
+ __flush_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, nentries);
}
void flush_tsb_user(struct tlb_batch *tb)
@@ -90,6 +93,30 @@ void flush_tsb_user(struct tlb_batch *tb)
spin_unlock_irqrestore(&mm->context.lock, flags);
}
+void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr)
+{
+ unsigned long nentries, base, flags;
+
+ spin_lock_irqsave(&mm->context.lock, flags);
+
+ base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
+ nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
+ if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+ base = __pa(base);
+ __flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries);
+
+#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
+ if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
+ base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
+ nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
+ if (tlb_type == cheetah_plus || tlb_type == hypervisor)
+ base = __pa(base);
+ __flush_tsb_one_entry(base, vaddr, HPAGE_SHIFT, nentries);
+ }
+#endif
+ spin_unlock_irqrestore(&mm->context.lock, flags);
+}
+
#define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_8K
#define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_8K
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S
index f8e13d421fcb..432aa0cb1b38 100644
--- a/arch/sparc/mm/ultra.S
+++ b/arch/sparc/mm/ultra.S
@@ -53,6 +53,33 @@ __flush_tlb_mm: /* 18 insns */
nop
.align 32
+ .globl __flush_tlb_page
+__flush_tlb_page: /* 22 insns */
+ /* %o0 = context, %o1 = vaddr */
+ rdpr %pstate, %g7
+ andn %g7, PSTATE_IE, %g2
+ wrpr %g2, %pstate
+ mov SECONDARY_CONTEXT, %o4
+ ldxa [%o4] ASI_DMMU, %g2
+ stxa %o0, [%o4] ASI_DMMU
+ andcc %o1, 1, %g0
+ andn %o1, 1, %o3
+ be,pn %icc, 1f
+ or %o3, 0x10, %o3
+ stxa %g0, [%o3] ASI_IMMU_DEMAP
+1: stxa %g0, [%o3] ASI_DMMU_DEMAP
+ membar #Sync
+ stxa %g2, [%o4] ASI_DMMU
+ sethi %hi(KERNBASE), %o4
+ flush %o4
+ retl
+ wrpr %g7, 0x0, %pstate
+ nop
+ nop
+ nop
+ nop
+
+ .align 32
.globl __flush_tlb_pending
__flush_tlb_pending: /* 26 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
@@ -203,6 +230,31 @@ __cheetah_flush_tlb_mm: /* 19 insns */
retl
wrpr %g7, 0x0, %pstate
+__cheetah_flush_tlb_page: /* 22 insns */
+ /* %o0 = context, %o1 = vaddr */
+ rdpr %pstate, %g7
+ andn %g7, PSTATE_IE, %g2
+ wrpr %g2, 0x0, %pstate
+ wrpr %g0, 1, %tl
+ mov PRIMARY_CONTEXT, %o4
+ ldxa [%o4] ASI_DMMU, %g2
+ srlx %g2, CTX_PGSZ1_NUC_SHIFT, %o3
+ sllx %o3, CTX_PGSZ1_NUC_SHIFT, %o3
+ or %o0, %o3, %o0 /* Preserve nucleus page size fields */
+ stxa %o0, [%o4] ASI_DMMU
+ andcc %o1, 1, %g0
+ be,pn %icc, 1f
+ andn %o1, 1, %o3
+ stxa %g0, [%o3] ASI_IMMU_DEMAP
+1: stxa %g0, [%o3] ASI_DMMU_DEMAP
+ membar #Sync
+ stxa %g2, [%o4] ASI_DMMU
+ sethi %hi(KERNBASE), %o4
+ flush %o4
+ wrpr %g0, 0, %tl
+ retl
+ wrpr %g7, 0x0, %pstate
+
__cheetah_flush_tlb_pending: /* 27 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
rdpr %pstate, %g7
@@ -269,6 +321,20 @@ __hypervisor_flush_tlb_mm: /* 10 insns */
retl
nop
+__hypervisor_flush_tlb_page: /* 11 insns */
+ /* %o0 = context, %o1 = vaddr */
+ mov %o0, %g2
+ mov %o1, %o0 /* ARG0: vaddr + IMMU-bit */
+ mov %g2, %o1 /* ARG1: mmu context */
+ mov HV_MMU_ALL, %o2 /* ARG2: flags */
+ srlx %o0, PAGE_SHIFT, %o0
+ sllx %o0, PAGE_SHIFT, %o0
+ ta HV_MMU_UNMAP_ADDR_TRAP
+ brnz,pn %o0, __hypervisor_tlb_tl0_error
+ mov HV_MMU_UNMAP_ADDR_TRAP, %o1
+ retl
+ nop
+
__hypervisor_flush_tlb_pending: /* 16 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
sllx %o1, 3, %g1
@@ -339,6 +405,13 @@ cheetah_patch_cachetlbops:
call tlb_patch_one
mov 19, %o2
+ sethi %hi(__flush_tlb_page), %o0
+ or %o0, %lo(__flush_tlb_page), %o0
+ sethi %hi(__cheetah_flush_tlb_page), %o1
+ or %o1, %lo(__cheetah_flush_tlb_page), %o1
+ call tlb_patch_one
+ mov 22, %o2
+
sethi %hi(__flush_tlb_pending), %o0
or %o0, %lo(__flush_tlb_pending), %o0
sethi %hi(__cheetah_flush_tlb_pending), %o1
@@ -397,10 +470,9 @@ xcall_flush_tlb_mm: /* 21 insns */
nop
nop
- .globl xcall_flush_tlb_pending
-xcall_flush_tlb_pending: /* 21 insns */
- /* %g5=context, %g1=nr, %g7=vaddrs[] */
- sllx %g1, 3, %g1
+ .globl xcall_flush_tlb_page
+xcall_flush_tlb_page: /* 17 insns */
+ /* %g5=context, %g1=vaddr */
mov PRIMARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g2
srlx %g2, CTX_PGSZ1_NUC_SHIFT, %g4
@@ -408,20 +480,16 @@ xcall_flush_tlb_pending: /* 21 insns */
or %g5, %g4, %g5
mov PRIMARY_CONTEXT, %g4
stxa %g5, [%g4] ASI_DMMU
-1: sub %g1, (1 << 3), %g1
- ldx [%g7 + %g1], %g5
- andcc %g5, 0x1, %g0
+ andcc %g1, 0x1, %g0
be,pn %icc, 2f
-
- andn %g5, 0x1, %g5
+ andn %g1, 0x1, %g5
stxa %g0, [%g5] ASI_IMMU_DEMAP
2: stxa %g0, [%g5] ASI_DMMU_DEMAP
membar #Sync
- brnz,pt %g1, 1b
- nop
stxa %g2, [%g4] ASI_DMMU
retry
nop
+ nop
.globl xcall_flush_tlb_kernel_range
xcall_flush_tlb_kernel_range: /* 25 insns */
@@ -656,15 +724,13 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
membar #Sync
retry
- .globl __hypervisor_xcall_flush_tlb_pending
-__hypervisor_xcall_flush_tlb_pending: /* 21 insns */
- /* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4,g6=scratch */
- sllx %g1, 3, %g1
+ .globl __hypervisor_xcall_flush_tlb_page
+__hypervisor_xcall_flush_tlb_page: /* 17 insns */
+ /* %g5=ctx, %g1=vaddr */
mov %o0, %g2
mov %o1, %g3
mov %o2, %g4
-1: sub %g1, (1 << 3), %g1
- ldx [%g7 + %g1], %o0 /* ARG0: virtual address */
+ mov %g1, %o0 /* ARG0: virtual address */
mov %g5, %o1 /* ARG1: mmu context */
mov HV_MMU_ALL, %o2 /* ARG2: flags */
srlx %o0, PAGE_SHIFT, %o0
@@ -673,8 +739,6 @@ __hypervisor_xcall_flush_tlb_pending: /* 21 insns */
mov HV_MMU_UNMAP_ADDR_TRAP, %g6
brnz,a,pn %o0, __hypervisor_tlb_xcall_error
mov %o0, %g5
- brnz,pt %g1, 1b
- nop
mov %g2, %o0
mov %g3, %o1
mov %g4, %o2
@@ -757,6 +821,13 @@ hypervisor_patch_cachetlbops:
call tlb_patch_one
mov 10, %o2
+ sethi %hi(__flush_tlb_page), %o0
+ or %o0, %lo(__flush_tlb_page), %o0
+ sethi %hi(__hypervisor_flush_tlb_page), %o1
+ or %o1, %lo(__hypervisor_flush_tlb_page), %o1
+ call tlb_patch_one
+ mov 11, %o2
+
sethi %hi(__flush_tlb_pending), %o0
or %o0, %lo(__flush_tlb_pending), %o0
sethi %hi(__hypervisor_flush_tlb_pending), %o1
@@ -788,12 +859,12 @@ hypervisor_patch_cachetlbops:
call tlb_patch_one
mov 21, %o2
- sethi %hi(xcall_flush_tlb_pending), %o0
- or %o0, %lo(xcall_flush_tlb_pending), %o0
- sethi %hi(__hypervisor_xcall_flush_tlb_pending), %o1
- or %o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1
+ sethi %hi(xcall_flush_tlb_page), %o0
+ or %o0, %lo(xcall_flush_tlb_page), %o0
+ sethi %hi(__hypervisor_xcall_flush_tlb_page), %o1
+ or %o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1
call tlb_patch_one
- mov 21, %o2
+ mov 17, %o2
sethi %hi(xcall_flush_tlb_kernel_range), %o0
or %o0, %lo(xcall_flush_tlb_kernel_range), %o0
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index 3109ca684a99..d36a85ebb5e0 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -795,13 +795,9 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
}
if (bpf_jit_enable > 1)
- pr_err("flen=%d proglen=%u pass=%d image=%p\n",
- flen, proglen, pass, image);
+ bpf_jit_dump(flen, proglen, pass, image);
if (image) {
- if (bpf_jit_enable > 1)
- print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
- 16, 1, image, proglen, false);
bpf_flush_icache(image, image + proglen);
fp->bpf_func = (void *)image;
}
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 25877aebc685..5b6a40dd5556 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -16,12 +16,15 @@ config TILE
select GENERIC_PENDING_IRQ if SMP
select GENERIC_IRQ_SHOW
select HAVE_DEBUG_BUGVERBOSE
- select HAVE_SYSCALL_WRAPPERS if TILEGX
select VIRT_TO_BUS
select SYS_HYPERVISOR
+ select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
+ select HAVE_ARCH_TRACEHOOK
+ select HAVE_SYSCALL_TRACEPOINTS
+ select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
@@ -40,9 +43,6 @@ config MMU
config GENERIC_CSUM
def_bool y
-config SEMAPHORE_SLEEPERS
- def_bool y
-
config HAVE_ARCH_ALLOC_REMAP
def_bool y
@@ -67,12 +67,6 @@ config HUGETLB_SUPER_PAGES
config RWSEM_GENERIC_SPINLOCK
def_bool y
-# We have a very flat architecture from a migration point of view,
-# so save boot time by presetting this (particularly useful on tile-sim).
-config DEFAULT_MIGRATION_COST
- int
- default "10000000"
-
# We only support gcc 4.4 and above, so this should work.
config ARCH_SUPPORTS_OPTIMIZED_INLINING
def_bool y
@@ -114,13 +108,6 @@ config STRICT_DEVMEM
config SMP
def_bool y
-# Allow checking for compile-time determined overflow errors in
-# copy_from_user(). There are still unprovable places in the
-# generic code as of 2.6.34, so this option is not really compatible
-# with -Werror, which is more useful in general.
-config DEBUG_COPY_FROM_USER
- def_bool n
-
config HVC_TILE
depends on TTY
select HVC_DRIVER
@@ -420,11 +407,6 @@ endmenu
menu "Executable file formats"
-# only elf supported
-config KCORE_ELF
- def_bool y
- depends on PROC_FS
-
source "fs/Kconfig.binfmt"
endmenu
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
index f2461429a4a4..e71387ab20ca 100644
--- a/arch/tile/include/asm/atomic.h
+++ b/arch/tile/include/asm/atomic.h
@@ -131,4 +131,25 @@ static inline int atomic_read(const atomic_t *v)
#include <asm/atomic_64.h>
#endif
+#ifndef __ASSEMBLY__
+
+static inline long long atomic64_dec_if_positive(atomic64_t *v)
+{
+ long long c, old, dec;
+
+ c = atomic64_read(v);
+ for (;;) {
+ dec = c - 1;
+ if (unlikely(dec < 0))
+ break;
+ old = atomic64_cmpxchg((v), c, dec);
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return dec;
+}
+
+#endif /* __ASSEMBLY__ */
+
#endif /* _ASM_TILE_ATOMIC_H */
diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h
index 0f885af2b621..3257733003f8 100644
--- a/arch/tile/include/asm/hugetlb.h
+++ b/arch/tile/include/asm/hugetlb.h
@@ -16,6 +16,7 @@
#define _ASM_TILE_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
index 241c0bb60b12..c96f9bbb760d 100644
--- a/arch/tile/include/asm/irqflags.h
+++ b/arch/tile/include/asm/irqflags.h
@@ -40,7 +40,15 @@
#include <asm/percpu.h>
#include <arch/spr_def.h>
-/* Set and clear kernel interrupt masks. */
+/*
+ * Set and clear kernel interrupt masks.
+ *
+ * NOTE: __insn_mtspr() is a compiler builtin marked as a memory
+ * clobber. We rely on it being equivalent to a compiler barrier in
+ * this code since arch_local_irq_save() and friends must act as
+ * compiler barriers. This compiler semantic is baked into enough
+ * places that the compiler will maintain it going forward.
+ */
#if CHIP_HAS_SPLIT_INTR_MASK()
#if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 || INT_MEM_ERROR >= 32
# error Fix assumptions about which word various interrupts are in
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h
index 2e83fc1b9467..fd412260aff7 100644
--- a/arch/tile/include/asm/ptrace.h
+++ b/arch/tile/include/asm/ptrace.h
@@ -44,7 +44,8 @@ typedef unsigned long pt_reg_t;
struct pt_regs *get_pt_regs(struct pt_regs *);
/* Trace the current syscall. */
-extern void do_syscall_trace(void);
+extern int do_syscall_trace_enter(struct pt_regs *regs);
+extern void do_syscall_trace_exit(struct pt_regs *regs);
#define arch_has_single_step() (1)
diff --git a/arch/tile/include/asm/syscall.h b/arch/tile/include/asm/syscall.h
index d35e0dcb67b1..9644b88f133d 100644
--- a/arch/tile/include/asm/syscall.h
+++ b/arch/tile/include/asm/syscall.h
@@ -22,6 +22,12 @@
#include <linux/err.h>
#include <arch/abi.h>
+/* The array of function pointers for syscalls. */
+extern void *sys_call_table[];
+#ifdef CONFIG_COMPAT
+extern void *compat_sys_call_table[];
+#endif
+
/*
* Only the low 32 bits of orig_r0 are meaningful, so we return int.
* This importantly ignores the high bits on 64-bit, so comparisons
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
index 78886e2417a6..07b298450ef2 100644
--- a/arch/tile/include/asm/syscalls.h
+++ b/arch/tile/include/asm/syscalls.h
@@ -24,12 +24,6 @@
#include <linux/types.h>
#include <linux/compat.h>
-/* The array of function pointers for syscalls. */
-extern void *sys_call_table[];
-#ifdef CONFIG_COMPAT
-extern void *compat_sys_call_table[];
-#endif
-
/*
* Note that by convention, any syscall which requires the current
* register set takes an additional "struct pt_regs *" pointer; a
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
index e9c670d7a7fe..d1733dee98a2 100644
--- a/arch/tile/include/asm/thread_info.h
+++ b/arch/tile/include/asm/thread_info.h
@@ -124,6 +124,7 @@ extern void _cpu_idle(void);
#define TIF_SECCOMP 6 /* secure computing */
#define TIF_MEMDIE 7 /* OOM killer at work */
#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
+#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
@@ -134,12 +135,19 @@ extern void _cpu_idle(void);
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_MEMDIE (1<<TIF_MEMDIE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
/* Work to do on any return to user space. */
#define _TIF_ALLWORK_MASK \
(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\
_TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
+/* Work to do at syscall entry. */
+#define _TIF_SYSCALL_ENTRY_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
+
+/* Work to do at syscall exit. */
+#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT)
+
/*
* Thread-synchronous status.
*
@@ -153,8 +161,6 @@ extern void _cpu_idle(void);
#define TS_POLLING 0x0004 /* in idle loop but not sleeping */
#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal */
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h
index 9ab078a4605d..8a082bc6bca5 100644
--- a/arch/tile/include/asm/uaccess.h
+++ b/arch/tile/include/asm/uaccess.h
@@ -395,7 +395,12 @@ _copy_from_user(void *to, const void __user *from, unsigned long n)
return n;
}
-#ifdef CONFIG_DEBUG_COPY_FROM_USER
+#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS
+/*
+ * There are still unprovable places in the generic code as of 2.6.34, so this
+ * option is not really compatible with -Werror, which is more useful in
+ * general.
+ */
extern void copy_from_user_overflow(void)
__compiletime_warning("copy_from_user() size is not provably correct");
diff --git a/arch/tile/include/uapi/asm/unistd.h b/arch/tile/include/uapi/asm/unistd.h
index cd7b6dd9d471..3866397aaf5a 100644
--- a/arch/tile/include/uapi/asm/unistd.h
+++ b/arch/tile/include/uapi/asm/unistd.h
@@ -20,6 +20,8 @@
/* Use the standard ABI for syscalls. */
#include <asm-generic/unistd.h>
+#define NR_syscalls __NR_syscalls
+
/* Additional Tilera-specific syscalls. */
#define __NR_cacheflush (__NR_arch_specific_syscall + 1)
__SYSCALL(__NR_cacheflush, sys_cacheflush)
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index 6ea4cdb3c6a0..ed378416b86a 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -56,12 +56,6 @@ COMPAT_SYSCALL_DEFINE6(pwrite64, unsigned int, fd, char __user *, ubuf,
return sys_pwrite64(fd, ubuf, count, ((loff_t)high << 32) | low);
}
-COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, low, u32, high,
- char __user *, buf, size_t, len)
-{
- return sys_lookup_dcookie(((loff_t)high << 32) | low, buf, len);
-}
-
COMPAT_SYSCALL_DEFINE6(sync_file_range2, int, fd, unsigned int, flags,
u32, offset_lo, u32, offset_hi,
u32, nbytes_lo, u32, nbytes_hi)
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
index afb9c9a0d887..34d72a151bf3 100644
--- a/arch/tile/kernel/early_printk.c
+++ b/arch/tile/kernel/early_printk.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/string.h>
#include <linux/irqflags.h>
+#include <linux/printk.h>
#include <asm/setup.h>
#include <hv/hypervisor.h>
@@ -33,25 +34,8 @@ static struct console early_hv_console = {
};
/* Direct interface for emergencies */
-static struct console *early_console = &early_hv_console;
-static int early_console_initialized;
static int early_console_complete;
-static void early_vprintk(const char *fmt, va_list ap)
-{
- char buf[512];
- int n = vscnprintf(buf, sizeof(buf), fmt, ap);
- early_console->write(early_console, buf, n);
-}
-
-void early_printk(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- early_vprintk(fmt, ap);
- va_end(ap);
-}
-
void early_panic(const char *fmt, ...)
{
va_list ap;
@@ -69,14 +53,13 @@ static int __initdata keep_early;
static int __init setup_early_printk(char *str)
{
- if (early_console_initialized)
+ if (early_console)
return 1;
if (str != NULL && strncmp(str, "keep", 4) == 0)
keep_early = 1;
early_console = &early_hv_console;
- early_console_initialized = 1;
register_console(early_console);
return 0;
@@ -85,12 +68,12 @@ static int __init setup_early_printk(char *str)
void __init disable_early_printk(void)
{
early_console_complete = 1;
- if (!early_console_initialized || !early_console)
+ if (!early_console)
return;
if (!keep_early) {
early_printk("disabling early console\n");
unregister_console(early_console);
- early_console_initialized = 0;
+ early_console = NULL;
} else {
early_printk("keeping early console\n");
}
@@ -98,7 +81,7 @@ void __init disable_early_printk(void)
void warn_early_printk(void)
{
- if (early_console_complete || early_console_initialized)
+ if (early_console_complete || early_console)
return;
early_printk("\
Machine shutting down before console output is fully initialized.\n\
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index f212bf7cea86..cb52d66343ed 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -1201,7 +1201,10 @@ handle_syscall:
lw r30, r31
andi r30, r30, _TIF_SYSCALL_TRACE
bzt r30, .Lrestore_syscall_regs
- jal do_syscall_trace
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_syscall_trace_enter
+ }
FEEDBACK_REENTER(handle_syscall)
/*
@@ -1252,7 +1255,10 @@ handle_syscall:
lw r30, r31
andi r30, r30, _TIF_SYSCALL_TRACE
bzt r30, 1f
- jal do_syscall_trace
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_syscall_trace_exit
+ }
FEEDBACK_REENTER(handle_syscall)
1: {
movei r30, 0 /* not an NMI */
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 4ea080902654..85d483957027 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -1000,13 +1000,19 @@ handle_syscall:
/* Trace syscalls, if requested. */
addi r31, r31, THREAD_INFO_FLAGS_OFFSET
- ld r30, r31
- andi r30, r30, _TIF_SYSCALL_TRACE
+ {
+ ld r30, r31
+ moveli r32, _TIF_SYSCALL_ENTRY_WORK
+ }
+ and r30, r30, r32
{
addi r30, r31, THREAD_INFO_STATUS_OFFSET - THREAD_INFO_FLAGS_OFFSET
beqzt r30, .Lrestore_syscall_regs
}
- jal do_syscall_trace
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_syscall_trace_enter
+ }
FEEDBACK_REENTER(handle_syscall)
/*
@@ -1071,13 +1077,19 @@ handle_syscall:
FEEDBACK_REENTER(handle_syscall)
/* Do syscall trace again, if requested. */
- ld r30, r31
- andi r0, r30, _TIF_SYSCALL_TRACE
+ {
+ ld r30, r31
+ moveli r32, _TIF_SYSCALL_EXIT_WORK
+ }
+ and r0, r30, r32
{
andi r0, r30, _TIF_SINGLESTEP
beqzt r0, 1f
}
- jal do_syscall_trace
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_syscall_trace_exit
+ }
FEEDBACK_REENTER(handle_syscall)
andi r0, r30, _TIF_SINGLESTEP
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index caf93ae11793..8ac304484f98 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -40,13 +40,11 @@
#include <arch/abi.h>
#include <arch/sim_def.h>
-
/*
* Use the (x86) "idle=poll" option to prefer low latency when leaving the
* idle loop over low power while in the idle loop, e.g. if we have
* one thread per core and we want to get threads out of futex waits fast.
*/
-static int no_idle_nap;
static int __init idle_setup(char *str)
{
if (!str)
@@ -54,64 +52,19 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
pr_info("using polling idle threads.\n");
- no_idle_nap = 1;
- } else if (!strcmp(str, "halt"))
- no_idle_nap = 0;
- else
- return -1;
-
- return 0;
+ cpu_idle_poll_ctrl(true);
+ return 0;
+ } else if (!strcmp(str, "halt")) {
+ return 0;
+ }
+ return -1;
}
early_param("idle", idle_setup);
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- int cpu = smp_processor_id();
-
-
- current_thread_info()->status |= TS_POLLING;
-
- if (no_idle_nap) {
- while (1) {
- while (!need_resched())
- cpu_relax();
- schedule();
- }
- }
-
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched()) {
- if (cpu_is_offline(cpu))
- BUG(); /* no HOTPLUG_CPU */
-
- local_irq_disable();
- __get_cpu_var(irq_stat).idle_timestamp = jiffies;
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we
- * test NEED_RESCHED:
- */
- smp_mb();
-
- if (!need_resched())
- _cpu_idle();
- else
- local_irq_enable();
- current_thread_info()->status |= TS_POLLING;
- }
- rcu_idle_exit();
- tick_nohz_idle_exit();
- schedule_preempt_disabled();
- }
+ __get_cpu_var(irq_stat).idle_timestamp = jiffies;
+ _cpu_idle();
}
/*
@@ -620,8 +573,7 @@ void show_regs(struct pt_regs *regs)
int i;
pr_err("\n");
- pr_err(" Pid: %d, comm: %20s, CPU: %d\n",
- tsk->pid, tsk->comm, smp_processor_id());
+ show_regs_print_info(KERN_ERR);
#ifdef __tilegx__
for (i = 0; i < 51; i += 3)
pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT" r%-2d: "REGFMT"\n",
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
index 9835312d5a91..0f83ed4602b2 100644
--- a/arch/tile/kernel/ptrace.c
+++ b/arch/tile/kernel/ptrace.c
@@ -21,9 +21,13 @@
#include <linux/uaccess.h>
#include <linux/regset.h>
#include <linux/elf.h>
+#include <linux/tracehook.h>
#include <asm/traps.h>
#include <arch/chip.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
void user_enable_single_step(struct task_struct *child)
{
set_tsk_thread_flag(child, TIF_SINGLESTEP);
@@ -246,29 +250,26 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
}
#endif
-void do_syscall_trace(void)
+int do_syscall_trace_enter(struct pt_regs *regs)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
+ if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+ if (tracehook_report_syscall_entry(regs))
+ regs->regs[TREG_SYSCALL_NR] = -1;
+ }
- if (!(current->ptrace & PT_PTRACED))
- return;
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]);
- /*
- * The 0x80 provides a way for the tracing parent to distinguish
- * between a syscall stop and SIGTRAP delivery
- */
- ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+ return regs->regs[TREG_SYSCALL_NR];
+}
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+void do_syscall_trace_exit(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, 0);
+
+ if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
+ trace_sys_exit(regs, regs->regs[0]);
}
void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index d1e15f7b59c6..7a5aa1a7864e 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -1004,15 +1004,8 @@ void __cpuinit setup_cpu(int boot)
#ifdef CONFIG_BLK_DEV_INITRD
-/*
- * Note that the kernel can potentially support other compression
- * techniques than gz, though we don't do so by default. If we ever
- * decide to do so we can either look for other filename extensions,
- * or just allow a file with this name to be compressed with an
- * arbitrary compressor (somewhat counterintuitively).
- */
static int __initdata set_initramfs_file;
-static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
+static char __initdata initramfs_file[128] = "initramfs";
static int __init setup_initramfs_file(char *str)
{
@@ -1026,9 +1019,9 @@ static int __init setup_initramfs_file(char *str)
early_param("initramfs_file", setup_initramfs_file);
/*
- * We look for an "initramfs.cpio.gz" file in the hvfs.
- * If there is one, we allocate some memory for it and it will be
- * unpacked to the initramfs.
+ * We look for a file called "initramfs" in the hvfs. If there is one, we
+ * allocate some memory for it and it will be unpacked to the initramfs.
+ * If it's compressed, the initd code will uncompress it first.
*/
static void __init load_hv_initrd(void)
{
@@ -1038,10 +1031,16 @@ static void __init load_hv_initrd(void)
fd = hv_fs_findfile((HV_VirtAddr) initramfs_file);
if (fd == HV_ENOENT) {
- if (set_initramfs_file)
+ if (set_initramfs_file) {
pr_warning("No such hvfs initramfs file '%s'\n",
initramfs_file);
- return;
+ return;
+ } else {
+ /* Try old backwards-compatible name. */
+ fd = hv_fs_findfile((HV_VirtAddr)"initramfs.cpio.gz");
+ if (fd == HV_ENOENT)
+ return;
+ }
}
BUG_ON(fd < 0);
stat = hv_fs_fstat(fd);
diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c
index e686c5ac90be..44bab29bf2f3 100644
--- a/arch/tile/kernel/smpboot.c
+++ b/arch/tile/kernel/smpboot.c
@@ -207,9 +207,7 @@ void __cpuinit online_secondary(void)
/* Set up tile-timer clock-event device on this cpu */
setup_tile_timer();
- preempt_enable();
-
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
index f6f50f2a5e37..5ac397ec6986 100644
--- a/arch/tile/kernel/time.c
+++ b/arch/tile/kernel/time.c
@@ -230,6 +230,10 @@ int setup_profiling_timer(unsigned int multiplier)
*/
cycles_t ns2cycles(unsigned long nsecs)
{
- struct clock_event_device *dev = &__get_cpu_var(tile_timer);
+ /*
+ * We do not have to disable preemption here as each core has the same
+ * clock frequency.
+ */
+ struct clock_event_device *dev = &__raw_get_cpu_var(tile_timer);
return ((u64)nsecs * dev->mult) >> dev->shift;
}
diff --git a/arch/tile/lib/uaccess.c b/arch/tile/lib/uaccess.c
index f8d398c9ee7f..030abe3ee4f1 100644
--- a/arch/tile/lib/uaccess.c
+++ b/arch/tile/lib/uaccess.c
@@ -22,11 +22,3 @@ int __range_ok(unsigned long addr, unsigned long size)
is_arch_mappable_range(addr, size));
}
EXPORT_SYMBOL(__range_ok);
-
-#ifdef CONFIG_DEBUG_COPY_FROM_USER
-void copy_from_user_overflow(void)
-{
- WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
-#endif
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index b3b4972c2451..dfd63ce87327 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
@@ -592,12 +592,7 @@ void iounmap(volatile void __iomem *addr_in)
in parallel. Reuse of the virtual address is prevented by
leaving it in the global lists until we're done with it.
cpa takes care of the direct mappings. */
- read_lock(&vmlist_lock);
- for (p = vmlist; p; p = p->next) {
- if (p->addr == addr)
- break;
- }
- read_unlock(&vmlist_lock);
+ p = find_vm_area((void *)addr);
if (!p) {
pr_err("iounmap: bad address %p\n", addr);
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 80b47cb71e0a..acbe6c67afba 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -568,11 +568,7 @@ void chan_interrupt(struct line *line, int irq)
reactivate_fd(chan->fd, irq);
if (err == -EIO) {
if (chan->primary) {
- struct tty_struct *tty = tty_port_tty_get(&line->port);
- if (tty != NULL) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&line->port, false);
if (line->chan_out != chan)
close_one_chan(line->chan_out, 1);
}
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index be541cf69fd2..8035145f043b 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -248,7 +248,6 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
- struct tty_struct *tty;
int err;
/*
@@ -267,12 +266,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
}
spin_unlock(&line->lock);
- tty = tty_port_tty_get(&line->port);
- if (tty == NULL)
- return IRQ_NONE;
-
- tty_wakeup(tty);
- tty_kref_put(tty);
+ tty_port_tty_wakeup(&line->port);
return IRQ_HANDLED;
}
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
index 49480f092456..4a0800bc37b2 100644
--- a/arch/um/kernel/early_printk.c
+++ b/arch/um/kernel/early_printk.c
@@ -16,7 +16,7 @@ static void early_console_write(struct console *con, const char *s, unsigned int
um_early_printk(s, n);
}
-static struct console early_console = {
+static struct console early_console_dev = {
.name = "earlycon",
.write = early_console_write,
.flags = CON_BOOT,
@@ -25,8 +25,10 @@ static struct console early_console = {
static int __init setup_early_printk(char *buf)
{
- register_console(&early_console);
-
+ if (!early_console) {
+ early_console = &early_console_dev;
+ register_console(&early_console_dev);
+ }
return 0;
}
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 5abcbfbe7e25..9df292b270a8 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -42,17 +42,12 @@ static unsigned long brk_end;
static void setup_highmem(unsigned long highmem_start,
unsigned long highmem_len)
{
- struct page *page;
unsigned long highmem_pfn;
int i;
highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
- for (i = 0; i < highmem_len >> PAGE_SHIFT; i++) {
- page = &mem_map[highmem_pfn + i];
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- }
+ for (i = 0; i < highmem_len >> PAGE_SHIFT; i++)
+ free_highmem_page(&mem_map[highmem_pfn + i]);
}
#endif
@@ -73,18 +68,13 @@ void __init mem_init(void)
totalram_pages = free_all_bootmem();
max_low_pfn = totalram_pages;
#ifdef CONFIG_HIGHMEM
- totalhigh_pages = highmem >> PAGE_SHIFT;
- totalram_pages += totalhigh_pages;
+ setup_highmem(end_iomem, highmem);
#endif
num_physpages = totalram_pages;
max_pfn = totalram_pages;
printk(KERN_INFO "Memory: %luk available\n",
nr_free_pages() << (PAGE_SHIFT-10));
kmalloc_ok = 1;
-
-#ifdef CONFIG_HIGHMEM
- setup_highmem(end_iomem, highmem);
-#endif
}
/*
@@ -254,15 +244,7 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (start < end)
- printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
- (end - start) >> 10);
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- totalram_pages++;
- }
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index b462b13c5bae..bbcef522bcb1 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -210,33 +210,14 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
kmalloc_ok = save_kmalloc_ok;
}
-void default_idle(void)
+void arch_cpu_idle(void)
{
unsigned long long nsecs;
- while (1) {
- /* endless idle loop with no priority at all */
-
- /*
- * although we are an idle CPU, we do not want to
- * get into the scheduler unnecessarily.
- */
- if (need_resched())
- schedule();
-
- tick_nohz_idle_enter();
- rcu_idle_enter();
- nsecs = disable_timer();
- idle_sleep(nsecs);
- rcu_idle_exit();
- tick_nohz_idle_exit();
- }
-}
-
-void cpu_idle(void)
-{
cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
- default_idle();
+ nsecs = disable_timer();
+ idle_sleep(nsecs);
+ local_irq_enable();
}
int __cant_sleep(void) {
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index e562ff80409a..7d101a2a1541 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -35,18 +35,6 @@ void show_trace(struct task_struct *task, unsigned long * stack)
}
#endif
-/*
- * stack dumps generator - this is used by arch-independent code.
- * And this is identical to i386 currently.
- */
-void dump_stack(void)
-{
- unsigned long stack;
-
- show_trace(current, &stack);
-}
-EXPORT_SYMBOL(dump_stack);
-
/*Stolen from arch/i386/kernel/traps.c */
static const int kstack_depth_to_print = 24;
diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c
index f889449f9285..1ff1ad7f27da 100644
--- a/arch/um/sys-ppc/sysrq.c
+++ b/arch/um/sys-ppc/sysrq.c
@@ -11,6 +11,8 @@
void show_regs(struct pt_regs_subarch *regs)
{
printk("\n");
+ show_regs_print_info(KERN_DEFAULT);
+
printk("show_regs(): insert regs here.\n");
#if 0
printk("\n");
diff --git a/arch/unicore32/kernel/Makefile b/arch/unicore32/kernel/Makefile
index fa497e0efe5a..607a72f2ae35 100644
--- a/arch/unicore32/kernel/Makefile
+++ b/arch/unicore32/kernel/Makefile
@@ -9,7 +9,6 @@ obj-y += setup.o signal.o sys.o stacktrace.o traps.o
obj-$(CONFIG_MODULES) += ksyms.o module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
-obj-$(CONFIG_CPU_FREQ) += cpu-ucv2.o
obj-$(CONFIG_UNICORE_FPU_F64) += fpu-ucf64.o
# obj-y for architecture PKUnity v3
diff --git a/arch/unicore32/kernel/early_printk.c b/arch/unicore32/kernel/early_printk.c
index 3922255f1fa8..9be0d5d02a9a 100644
--- a/arch/unicore32/kernel/early_printk.c
+++ b/arch/unicore32/kernel/early_printk.c
@@ -33,21 +33,17 @@ static struct console early_ocd_console = {
.index = -1,
};
-/* Direct interface for emergencies */
-static struct console *early_console = &early_ocd_console;
-
-static int __initdata keep_early;
-
static int __init setup_early_printk(char *buf)
{
- if (!buf)
+ int keep_early;
+
+ if (!buf || early_console)
return 0;
if (strstr(buf, "keep"))
keep_early = 1;
- if (!strncmp(buf, "ocd", 3))
- early_console = &early_ocd_console;
+ early_console = &early_ocd_console;
if (keep_early)
early_console->flags &= ~CON_BOOT;
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index 872d7e22d847..c9447691bdac 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -45,25 +45,10 @@ static const char * const processor_modes[] = {
"UK18", "UK19", "UK1A", "EXTN", "UK1C", "UK1D", "UK1E", "SUSR"
};
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- /* endless idle loop with no priority at all */
- while (1) {
- tick_nohz_idle_enter();
- rcu_idle_enter();
- while (!need_resched()) {
- local_irq_disable();
- stop_critical_timings();
- cpu_do_idle();
- local_irq_enable();
- start_critical_timings();
- }
- rcu_idle_exit();
- tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
+ cpu_do_idle();
+ local_irq_enable();
}
static char reboot_mode = 'h';
@@ -159,11 +144,7 @@ void __show_regs(struct pt_regs *regs)
unsigned long flags;
char buf[64];
- printk(KERN_DEFAULT "CPU: %d %s (%s %.*s)\n",
- raw_smp_processor_id(), print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
+ show_regs_print_info(KERN_DEFAULT);
print_symbol("PC is at %s\n", instruction_pointer(regs));
print_symbol("LR is at %s\n", regs->UCreg_lr);
printk(KERN_DEFAULT "pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n"
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index 0870b68d2ad9..c54e32410ead 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -170,12 +170,6 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
c_backtrace(fp, mode);
}
-void dump_stack(void)
-{
- dump_backtrace(NULL, NULL);
-}
-EXPORT_SYMBOL(dump_stack);
-
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
dump_backtrace(NULL, tsk);
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c
index de186bde8975..63df12d71ce3 100644
--- a/arch/unicore32/mm/init.c
+++ b/arch/unicore32/mm/init.c
@@ -66,6 +66,9 @@ void show_mem(unsigned int filter)
printk(KERN_DEFAULT "Mem-info:\n");
show_free_areas(filter);
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
+
for_each_bank(i, mi) {
struct membank *bank = &mi->bank[i];
unsigned int pfn1, pfn2;
@@ -313,24 +316,6 @@ void __init bootmem_init(void)
max_pfn = max_high - PHYS_PFN_OFFSET;
}
-static inline int free_area(unsigned long pfn, unsigned long end, char *s)
-{
- unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10);
-
- for (; pfn < end; pfn++) {
- struct page *page = pfn_to_page(pfn);
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- pages++;
- }
-
- if (size && s)
- printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
-
- return pages;
-}
-
static inline void
free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
@@ -404,9 +389,9 @@ void __init mem_init(void)
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
- /* this will put all unused low memory onto the freelists */
free_unused_memmap(&meminfo);
+ /* this will put all unused low memory onto the freelists */
totalram_pages += free_all_bootmem();
reserved_pages = free_pages = 0;
@@ -491,9 +476,7 @@ void __init mem_init(void)
void free_initmem(void)
{
- totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
- __phys_to_pfn(__pa(__init_end)),
- "init");
+ free_initmem_default(0);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -503,9 +486,7 @@ static int keep_initrd;
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (!keep_initrd)
- totalram_pages += free_area(__phys_to_pfn(__pa(start)),
- __phys_to_pfn(__pa(end)),
- "initrd");
+ free_reserved_area(start, end, 0, "initrd");
}
static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/unicore32/mm/ioremap.c b/arch/unicore32/mm/ioremap.c
index b7a605597b08..13068ee22f33 100644
--- a/arch/unicore32/mm/ioremap.c
+++ b/arch/unicore32/mm/ioremap.c
@@ -235,7 +235,7 @@ EXPORT_SYMBOL(__uc32_ioremap_cached);
void __uc32_iounmap(volatile void __iomem *io_addr)
{
void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr);
- struct vm_struct **p, *tmp;
+ struct vm_struct *vm;
/*
* If this is a section based mapping we need to handle it
@@ -244,17 +244,10 @@ void __uc32_iounmap(volatile void __iomem *io_addr)
* all the mappings before the area can be reclaimed
* by someone else.
*/
- write_lock(&vmlist_lock);
- for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
- if ((tmp->flags & VM_IOREMAP) && (tmp->addr == addr)) {
- if (tmp->flags & VM_UNICORE_SECTION_MAPPING) {
- unmap_area_sections((unsigned long)tmp->addr,
- tmp->size);
- }
- break;
- }
- }
- write_unlock(&vmlist_lock);
+ vm = find_vm_area(addr);
+ if (vm && (vm->flags & VM_IOREMAP) &&
+ (vm->flags & VM_UNICORE_SECTION_MAPPING))
+ unmap_area_sections((unsigned long)vm->addr, vm->size);
vunmap(addr);
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 70c0f3da0476..5db2117ae288 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -20,6 +20,7 @@ config X86_64
### Arch settings
config X86
def_bool y
+ select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
select HAVE_AOUT if X86_32
select HAVE_UNSTABLE_SCHED_CLOCK
select ARCH_SUPPORTS_NUMA_BALANCING
@@ -120,6 +121,7 @@ config X86
select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
select OLD_SIGACTION if X86_32
select COMPAT_OLD_SIGACTION if IA32_EMULATION
+ select RTC_LIB
config INSTRUCTION_DECODER
def_bool y
@@ -188,9 +190,6 @@ config GENERIC_CALIBRATE_DELAY
config ARCH_HAS_CPU_RELAX
def_bool y
-config ARCH_HAS_DEFAULT_IDLE
- def_bool y
-
config ARCH_HAS_CACHE_LINE_SIZE
def_bool y
@@ -389,7 +388,7 @@ config X86_NUMACHIP
config X86_VSMP
bool "ScaleMP vSMP"
- select PARAVIRT_GUEST
+ select HYPERVISOR_GUEST
select PARAVIRT
depends on X86_64 && PCI
depends on X86_EXTENDED_PLATFORM
@@ -596,44 +595,17 @@ config SCHED_OMIT_FRAME_POINTER
If in doubt, say "Y".
-menuconfig PARAVIRT_GUEST
- bool "Paravirtualized guest support"
- ---help---
- Say Y here to get to see options related to running Linux under
- various hypervisors. This option alone does not add any kernel code.
-
- If you say N, all options in this submenu will be skipped and disabled.
-
-if PARAVIRT_GUEST
-
-config PARAVIRT_TIME_ACCOUNTING
- bool "Paravirtual steal time accounting"
- select PARAVIRT
- default n
+menuconfig HYPERVISOR_GUEST
+ bool "Linux guest support"
---help---
- Select this option to enable fine granularity task steal time
- accounting. Time spent executing other tasks in parallel with
- the current vCPU is discounted from the vCPU power. To account for
- that, there can be a small performance impact.
-
- If in doubt, say N here.
-
-source "arch/x86/xen/Kconfig"
+ Say Y here to enable options for running Linux under various hyper-
+ visors. This option enables basic hypervisor detection and platform
+ setup.
-config KVM_GUEST
- bool "KVM Guest support (including kvmclock)"
- select PARAVIRT
- select PARAVIRT
- select PARAVIRT_CLOCK
- default y if PARAVIRT_GUEST
- ---help---
- This option enables various optimizations for running under the KVM
- hypervisor. It includes a paravirtualized clock, so that instead
- of relying on a PIT (or probably other) emulation by the
- underlying device model, the host provides the guest with
- timing infrastructure such as time of day, and system time
+ If you say N, all options in this submenu will be skipped and
+ disabled, and Linux guest support won't be built in.
-source "arch/x86/lguest/Kconfig"
+if HYPERVISOR_GUEST
config PARAVIRT
bool "Enable paravirtualization code"
@@ -643,6 +615,13 @@ config PARAVIRT
over full virtualization. However, when run without a hypervisor
the kernel is theoretically slower and slightly larger.
+config PARAVIRT_DEBUG
+ bool "paravirt-ops debugging"
+ depends on PARAVIRT && DEBUG_KERNEL
+ ---help---
+ Enable to debug paravirt_ops internals. Specifically, BUG if
+ a paravirt_op is missing when it is called.
+
config PARAVIRT_SPINLOCKS
bool "Paravirtualization layer for spinlocks"
depends on PARAVIRT && SMP
@@ -656,17 +635,38 @@ config PARAVIRT_SPINLOCKS
If you are unsure how to answer this question, answer N.
-config PARAVIRT_CLOCK
- bool
+source "arch/x86/xen/Kconfig"
-endif
+config KVM_GUEST
+ bool "KVM Guest support (including kvmclock)"
+ depends on PARAVIRT
+ select PARAVIRT_CLOCK
+ default y
+ ---help---
+ This option enables various optimizations for running under the KVM
+ hypervisor. It includes a paravirtualized clock, so that instead
+ of relying on a PIT (or probably other) emulation by the
+ underlying device model, the host provides the guest with
+ timing infrastructure such as time of day, and system time
-config PARAVIRT_DEBUG
- bool "paravirt-ops debugging"
- depends on PARAVIRT && DEBUG_KERNEL
+source "arch/x86/lguest/Kconfig"
+
+config PARAVIRT_TIME_ACCOUNTING
+ bool "Paravirtual steal time accounting"
+ depends on PARAVIRT
+ default n
---help---
- Enable to debug paravirt_ops internals. Specifically, BUG if
- a paravirt_op is missing when it is called.
+ Select this option to enable fine granularity task steal time
+ accounting. Time spent executing other tasks in parallel with
+ the current vCPU is discounted from the vCPU power. To account for
+ that, there can be a small performance impact.
+
+ If in doubt, say N here.
+
+config PARAVIRT_CLOCK
+ bool
+
+endif #HYPERVISOR_GUEST
config NO_BOOTMEM
def_bool y
@@ -1549,6 +1549,7 @@ config X86_SMAP
config EFI
bool "EFI runtime service support"
depends on ACPI
+ select UCS2_STRING
---help---
This enables the kernel to use EFI runtime services that are
available (such as the EFI variable services).
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index b322f124ee3c..c198b7e13e7b 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -131,7 +131,7 @@ config DOUBLEFAULT
config DEBUG_TLBFLUSH
bool "Set upper limit of TLB entries to flush one-by-one"
- depends on DEBUG_KERNEL && (X86_64 || X86_INVLPG)
+ depends on DEBUG_KERNEL
---help---
X86-only for now.
@@ -292,20 +292,6 @@ config OPTIMIZE_INLINING
If unsure, say N.
-config DEBUG_STRICT_USER_COPY_CHECKS
- bool "Strict copy size checks"
- depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
- ---help---
- Enabling this option turns a certain set of sanity checks for user
- copy operations into compile time failures.
-
- The copy_from_user() etc checks are there to help test if there
- are sufficient security checks on the length argument of
- the copy operation, by having gcc prove that the argument is
- within bounds.
-
- If unsure, or if you run an older (pre 4.4) gcc, say N.
-
config DEBUG_NMI_SELFTEST
bool "NMI Selftest"
depends on DEBUG_KERNEL && X86_LOCAL_APIC
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 8a84501acb1b..5ef205c5f37b 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -4,7 +4,7 @@
# create a compressed vmlinux image from the original vmlinux
#
-targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo head_$(BITS).o misc.o string.o cmdline.o early_serial_console.o piggy.o
+targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
@@ -29,7 +29,6 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
$(obj)/piggy.o
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
-$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone
ifeq ($(CONFIG_EFI_STUB), y)
VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
@@ -43,7 +42,7 @@ OBJCOPYFLAGS_vmlinux.bin := -R .comment -S
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
-targets += vmlinux.bin.all vmlinux.relocs
+targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs
CMD_RELOCS = arch/x86/tools/relocs
quiet_cmd_relocs = RELOCS $@
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index c205035a6b96..35ee62fccf98 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -251,6 +251,51 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
*size = len;
}
+static efi_status_t setup_efi_vars(struct boot_params *params)
+{
+ struct setup_data *data;
+ struct efi_var_bootdata *efidata;
+ u64 store_size, remaining_size, var_size;
+ efi_status_t status;
+
+ if (sys_table->runtime->hdr.revision < EFI_2_00_SYSTEM_TABLE_REVISION)
+ return EFI_UNSUPPORTED;
+
+ data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+ while (data && data->next)
+ data = (struct setup_data *)(unsigned long)data->next;
+
+ status = efi_call_phys4((void *)sys_table->runtime->query_variable_info,
+ EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS, &store_size,
+ &remaining_size, &var_size);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ status = efi_call_phys3(sys_table->boottime->allocate_pool,
+ EFI_LOADER_DATA, sizeof(*efidata), &efidata);
+
+ if (status != EFI_SUCCESS)
+ return status;
+
+ efidata->data.type = SETUP_EFI_VARS;
+ efidata->data.len = sizeof(struct efi_var_bootdata) -
+ sizeof(struct setup_data);
+ efidata->data.next = 0;
+ efidata->store_size = store_size;
+ efidata->remaining_size = remaining_size;
+ efidata->max_var_size = var_size;
+
+ if (data)
+ data->next = (unsigned long)efidata;
+ else
+ params->hdr.setup_data = (unsigned long)efidata;
+
+}
+
static efi_status_t setup_efi_pci(struct boot_params *params)
{
efi_pci_io_protocol *pci;
@@ -1157,6 +1202,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
setup_graphics(boot_params);
+ setup_efi_vars(boot_params);
+
setup_efi_pci(boot_params);
status = efi_call_phys3(sys_table->boottime->allocate_pool,
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index c1d383d1fb7e..16f24e6dad79 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -52,7 +52,7 @@ ENTRY(startup_32)
jnz 1f
cli
- movl $(__KERNEL_DS), %eax
+ movl $(__BOOT_DS), %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
diff --git a/arch/x86/ia32/Makefile b/arch/x86/ia32/Makefile
index 455646e0e532..e785b422b766 100644
--- a/arch/x86/ia32/Makefile
+++ b/arch/x86/ia32/Makefile
@@ -5,9 +5,6 @@
obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_signal.o
obj-$(CONFIG_IA32_EMULATION) += nosyscall.o syscall_ia32.o
-sysv-$(CONFIG_SYSVIPC) := ipc32.o
-obj-$(CONFIG_IA32_EMULATION) += $(sysv-y)
-
obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
audit-class-$(CONFIG_AUDIT) := audit.o
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 03d721cbbc32..805078e08013 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -162,7 +162,6 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file,
fs = get_fs();
set_fs(KERNEL_DS);
has_dumped = 1;
- current->flags |= PF_DUMPCORE;
strncpy(dump.u_comm, current->comm, sizeof(current->comm));
dump.u_ar0 = offsetof(struct user32, regs);
dump.signal = signr;
diff --git a/arch/x86/ia32/ipc32.c b/arch/x86/ia32/ipc32.c
deleted file mode 100644
index 29cdcd02ead3..000000000000
--- a/arch/x86/ia32/ipc32.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/syscalls.h>
-#include <linux/time.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/ipc.h>
-#include <linux/compat.h>
-#include <asm/sys_ia32.h>
-
-asmlinkage long sys32_ipc(u32 call, int first, int second, int third,
- compat_uptr_t ptr, u32 fifth)
-{
- int version;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- /* struct sembuf is the same on 32 and 64bit :)) */
- return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
- case SEMTIMEDOP:
- return compat_sys_semtimedop(first, compat_ptr(ptr), second,
- compat_ptr(fifth));
- case SEMGET:
- return sys_semget(first, second, third);
- case SEMCTL:
- return compat_sys_semctl(first, second, third, compat_ptr(ptr));
-
- case MSGSND:
- return compat_sys_msgsnd(first, second, third, compat_ptr(ptr));
- case MSGRCV:
- return compat_sys_msgrcv(first, second, fifth, third,
- version, compat_ptr(ptr));
- case MSGGET:
- return sys_msgget((key_t) first, second);
- case MSGCTL:
- return compat_sys_msgctl(first, second, compat_ptr(ptr));
-
- case SHMAT:
- return compat_sys_shmat(first, second, third, version,
- compat_ptr(ptr));
- case SHMDT:
- return sys_shmdt(compat_ptr(ptr));
- case SHMGET:
- return sys_shmget(first, (unsigned)second, third);
- case SHMCTL:
- return compat_sys_shmctl(first, second, compat_ptr(ptr));
- }
- return -ENOSYS;
-}
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index ad7a20cbc699..4e4907c67d92 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -166,12 +166,6 @@ asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg)
a.offset>>PAGE_SHIFT);
}
-asmlinkage long sys32_mprotect(unsigned long start, size_t len,
- unsigned long prot)
-{
- return sys_mprotect(start, len, prot);
-}
-
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
int options)
{
@@ -194,35 +188,10 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
}
-asmlinkage long sys32_sendfile(int out_fd, int in_fd,
- compat_off_t __user *offset, s32 count)
-{
- mm_segment_t old_fs = get_fs();
- int ret;
- off_t of;
-
- if (offset && get_user(of, offset))
- return -EFAULT;
-
- set_fs(KERNEL_DS);
- ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
- count);
- set_fs(old_fs);
-
- if (offset && put_user(of, offset))
- return -EFAULT;
- return ret;
-}
-
/*
* Some system calls that need sign extended arguments. This could be
* done by a generic wrapper.
*/
-long sys32_kill(int pid, int sig)
-{
- return sys_kill(pid, sig);
-}
-
long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high,
__u32 len_low, __u32 len_high, int advice)
{
@@ -246,12 +215,6 @@ long sys32_vm86_warning(void)
return -ENOSYS;
}
-long sys32_lookup_dcookie(u32 addr_low, u32 addr_high,
- char __user *buf, size_t len)
-{
- return sys_lookup_dcookie(((u64)addr_high << 32) | addr_low, buf, len);
-}
-
asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi,
size_t count)
{
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 11e1152222d0..2f03ff018d36 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -37,7 +37,4 @@ do { \
#include <asm-generic/bug.h>
-
-extern void show_regs_common(void);
-
#endif /* _ASM_X86_BUG_H */
diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h
index 8d871eaddb66..d47786acb016 100644
--- a/arch/x86/include/asm/cmpxchg.h
+++ b/arch/x86/include/asm/cmpxchg.h
@@ -35,7 +35,7 @@ extern void __add_wrong_size(void)
/*
* An exchange-type operation, which takes a value and a pointer, and
- * returns a the old value.
+ * returns the old value.
*/
#define __xchg_op(ptr, arg, op, lock) \
({ \
diff --git a/arch/x86/include/asm/context_tracking.h b/arch/x86/include/asm/context_tracking.h
index 1616562683e9..1fe49704b146 100644
--- a/arch/x86/include/asm/context_tracking.h
+++ b/arch/x86/include/asm/context_tracking.h
@@ -1,31 +1,10 @@
#ifndef _ASM_X86_CONTEXT_TRACKING_H
#define _ASM_X86_CONTEXT_TRACKING_H
-#ifndef __ASSEMBLY__
-#include <linux/context_tracking.h>
-#include <asm/ptrace.h>
-
-static inline void exception_enter(struct pt_regs *regs)
-{
- user_exit();
-}
-
-static inline void exception_exit(struct pt_regs *regs)
-{
-#ifdef CONFIG_CONTEXT_TRACKING
- if (user_mode(regs))
- user_enter();
-#endif
-}
-
-#else /* __ASSEMBLY__ */
-
#ifdef CONFIG_CONTEXT_TRACKING
# define SCHEDULE_USER call schedule_user
#else
# define SCHEDULE_USER call schedule
#endif
-#endif /* !__ASSEMBLY__ */
-
#endif
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 93fe929d1cee..8010ebc5705f 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -9,6 +9,7 @@
#endif
#define NCAPINTS 10 /* N 32-bit words worth of info */
+#define NBUGINTS 1 /* N 32-bit bug flags */
/*
* Note: If the comment begins with a quoted string, that string is used
@@ -100,6 +101,7 @@
#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
#define X86_FEATURE_EAGER_FPU (3*32+29) /* "eagerfpu" Non lazy FPU restore */
+#define X86_FEATURE_NONSTOP_TSC_S3 (3*32+30) /* TSC doesn't stop in S3 state */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
@@ -168,6 +170,7 @@
#define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */
#define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */
#define X86_FEATURE_PERFCTR_NB (6*32+24) /* NB performance counter extensions */
+#define X86_FEATURE_PERFCTR_L2 (6*32+28) /* L2 performance counter extensions */
/*
* Auxiliary flags: Linux defined - For features scattered in various
@@ -182,6 +185,7 @@
#define X86_FEATURE_PTS (7*32+ 6) /* Intel Package Thermal Status */
#define X86_FEATURE_DTHERM (7*32+ 7) /* Digital Thermal Sensor */
#define X86_FEATURE_HW_PSTATE (7*32+ 8) /* AMD HW-PState */
+#define X86_FEATURE_PROC_FEEDBACK (7*32+ 9) /* AMD ProcFeedbackInterface */
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW (8*32+ 0) /* Intel TPR Shadow */
@@ -216,6 +220,17 @@
#define X86_FEATURE_ADX (9*32+19) /* The ADCX and ADOX instructions */
#define X86_FEATURE_SMAP (9*32+20) /* Supervisor Mode Access Prevention */
+/*
+ * BUG word(s)
+ */
+#define X86_BUG(x) (NCAPINTS*32 + (x))
+
+#define X86_BUG_F00F X86_BUG(0) /* Intel F00F */
+#define X86_BUG_FDIV X86_BUG(1) /* FPU FDIV */
+#define X86_BUG_COMA X86_BUG(2) /* Cyrix 6x86 coma */
+#define X86_BUG_AMD_TLB_MMATCH X86_BUG(3) /* AMD Erratum 383 */
+#define X86_BUG_AMD_APIC_C1E X86_BUG(4) /* AMD Erratum 400 */
+
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
#include <asm/asm.h>
@@ -311,6 +326,7 @@ extern const char * const x86_power_flags[32];
#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
#define cpu_has_perfctr_nb boot_cpu_has(X86_FEATURE_PERFCTR_NB)
+#define cpu_has_perfctr_l2 boot_cpu_has(X86_FEATURE_PERFCTR_L2)
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
@@ -401,6 +417,13 @@ static __always_inline __pure bool __static_cpu_has(u16 bit)
#define static_cpu_has(bit) boot_cpu_has(bit)
#endif
+#define cpu_has_bug(c, bit) cpu_has(c, (bit))
+#define set_cpu_bug(c, bit) set_cpu_cap(c, (bit))
+#define clear_cpu_bug(c, bit) clear_cpu_cap(c, (bit));
+
+#define static_cpu_has_bug(bit) static_cpu_has((bit))
+#define boot_cpu_has_bug(bit) cpu_has_bug(&boot_cpu_data, (bit))
+
#endif /* defined(__KERNEL__) && !defined(__ASSEMBLY__) */
#endif /* _ASM_X86_CPUFEATURE_H */
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 60c89f30c727..2fb5d5884e23 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -102,6 +102,13 @@ extern void efi_call_phys_epilog(void);
extern void efi_unmap_memmap(void);
extern void efi_memory_uc(u64 addr, unsigned long size);
+struct efi_var_bootdata {
+ struct setup_data data;
+ u64 store_size;
+ u64 remaining_size;
+ u64 max_var_size;
+};
+
#ifdef CONFIG_EFI
static inline bool efi_is_native(void)
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index a09c28571064..0dc7d9e21c34 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -104,12 +104,7 @@ enum fixed_addresses {
FIX_LI_PCIA, /* Lithium PCI Bridge A */
FIX_LI_PCIB, /* Lithium PCI Bridge B */
#endif
-#ifdef CONFIG_X86_F00F_BUG
- FIX_F00F_IDT, /* Virtual mapping for IDT */
-#endif
-#ifdef CONFIG_X86_CYCLONE_TIMER
- FIX_CYCLONE_TIMER, /*cyclone timer register*/
-#endif
+ FIX_RO_IDT, /* Virtual mapping for read-only IDT */
#ifdef CONFIG_X86_32
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
diff --git a/arch/x86/include/asm/hugetlb.h b/arch/x86/include/asm/hugetlb.h
index bdd35dbd0605..a8091216963b 100644
--- a/arch/x86/include/asm/hugetlb.h
+++ b/arch/x86/include/asm/hugetlb.h
@@ -2,6 +2,7 @@
#define _ASM_X86_HUGETLB_H
#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
static inline int is_hugepage_only_range(struct mm_struct *mm,
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 86095ed14135..2d4b5e6107cd 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -20,13 +20,11 @@
#ifndef _ASM_X86_HYPERVISOR_H
#define _ASM_X86_HYPERVISOR_H
+#ifdef CONFIG_HYPERVISOR_GUEST
+
#include <asm/kvm_para.h>
#include <asm/xen/hypervisor.h>
-extern void init_hypervisor(struct cpuinfo_x86 *c);
-extern void init_hypervisor_platform(void);
-extern bool hypervisor_x2apic_available(void);
-
/*
* x86 hypervisor information
*/
@@ -55,4 +53,12 @@ extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
extern const struct hypervisor_x86 x86_hyper_xen_hvm;
extern const struct hypervisor_x86 x86_hyper_kvm;
-#endif
+extern void init_hypervisor(struct cpuinfo_x86 *c);
+extern void init_hypervisor_platform(void);
+extern bool hypervisor_x2apic_available(void);
+#else
+static inline void init_hypervisor(struct cpuinfo_x86 *c) { }
+static inline void init_hypervisor_platform(void) { }
+static inline bool hypervisor_x2apic_available(void) { return false; }
+#endif /* CONFIG_HYPERVISOR_GUEST */
+#endif /* _ASM_X86_HYPERVISOR_H */
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index f4076af1f4ed..fa5f71e021d5 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -146,13 +146,13 @@ DECLARE_PER_CPU(struct device *, mce_device);
void mce_intel_feature_init(struct cpuinfo_x86 *c);
void cmci_clear(void);
void cmci_reenable(void);
-void cmci_rediscover(int dying);
+void cmci_rediscover(void);
void cmci_recheck(void);
#else
static inline void mce_intel_feature_init(struct cpuinfo_x86 *c) { }
static inline void cmci_clear(void) {}
static inline void cmci_reenable(void) {}
-static inline void cmci_rediscover(int dying) {}
+static inline void cmci_rediscover(void) {}
static inline void cmci_recheck(void) {}
#endif
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 9264802e2824..cb7502852acb 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -137,11 +137,11 @@ static inline unsigned long long native_read_pmc(int counter)
* pointer indirection), this allows gcc to optimize better
*/
-#define rdmsr(msr, val1, val2) \
+#define rdmsr(msr, low, high) \
do { \
u64 __val = native_read_msr((msr)); \
- (void)((val1) = (u32)__val); \
- (void)((val2) = (u32)(__val >> 32)); \
+ (void)((low) = (u32)__val); \
+ (void)((high) = (u32)(__val >> 32)); \
} while (0)
static inline void wrmsr(unsigned msr, unsigned low, unsigned high)
@@ -162,12 +162,12 @@ static inline int wrmsr_safe(unsigned msr, unsigned low, unsigned high)
}
/* rdmsr with exception handling */
-#define rdmsr_safe(msr, p1, p2) \
+#define rdmsr_safe(msr, low, high) \
({ \
int __err; \
u64 __val = native_read_msr_safe((msr), &__err); \
- (*p1) = (u32)__val; \
- (*p2) = (u32)(__val >> 32); \
+ (*low) = (u32)__val; \
+ (*high) = (u32)(__val >> 32); \
__err; \
})
@@ -208,7 +208,7 @@ do { \
#define wrmsrl_safe(msr, val) wrmsr_safe((msr), (u32)(val), \
(u32)((val) >> 32))
-#define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2))
+#define write_tsc(low, high) wrmsr(MSR_IA32_TSC, (low), (high))
#define write_rdtscp_aux(val) wrmsr(MSR_TSC_AUX, (val), 0)
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 8b491e66eaa8..6c896fbe21db 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -48,6 +48,5 @@
* arch/x86/kernel/head_64.S), and it is mapped here:
*/
#define KERNEL_IMAGE_SIZE (512 * 1024 * 1024)
-#define KERNEL_IMAGE_START _AC(0xffffffff80000000, UL)
#endif /* _ASM_X86_PAGE_64_DEFS_H */
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 5edd1742cfd0..cfdc9ee4c900 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -262,10 +262,6 @@ static inline void set_ldt(const void *addr, unsigned entries)
{
PVOP_VCALL2(pv_cpu_ops.set_ldt, addr, entries);
}
-static inline void store_gdt(struct desc_ptr *dtr)
-{
- PVOP_VCALL1(pv_cpu_ops.store_gdt, dtr);
-}
static inline void store_idt(struct desc_ptr *dtr)
{
PVOP_VCALL1(pv_cpu_ops.store_idt, dtr);
@@ -703,7 +699,10 @@ static inline void arch_leave_lazy_mmu_mode(void)
PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave);
}
-void arch_flush_lazy_mmu_mode(void);
+static inline void arch_flush_lazy_mmu_mode(void)
+{
+ PVOP_VCALL0(pv_mmu_ops.lazy_mode.flush);
+}
static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
phys_addr_t phys, pgprot_t flags)
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 142236ed83af..0db1fcac668c 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -91,6 +91,7 @@ struct pv_lazy_ops {
/* Set deferred update mode, used for batching operations. */
void (*enter)(void);
void (*leave)(void);
+ void (*flush)(void);
};
struct pv_time_ops {
@@ -122,7 +123,7 @@ struct pv_cpu_ops {
void (*load_tr_desc)(void);
void (*load_gdt)(const struct desc_ptr *);
void (*load_idt)(const struct desc_ptr *);
- void (*store_gdt)(struct desc_ptr *);
+ /* store_gdt has been removed. */
void (*store_idt)(struct desc_ptr *);
void (*set_ldt)(const void *desc, unsigned entries);
unsigned long (*store_tr)(void);
@@ -679,6 +680,7 @@ void paravirt_end_context_switch(struct task_struct *next);
void paravirt_enter_lazy_mmu(void);
void paravirt_leave_lazy_mmu(void);
+void paravirt_flush_lazy_mmu(void);
void _paravirt_nop(void);
u32 _paravirt_ident_32(u32);
diff --git a/arch/x86/include/asm/perf_event_p4.h b/arch/x86/include/asm/perf_event_p4.h
index 4f7e67e2345e..85e13ccf15c4 100644
--- a/arch/x86/include/asm/perf_event_p4.h
+++ b/arch/x86/include/asm/perf_event_p4.h
@@ -24,45 +24,45 @@
#define ARCH_P4_CNTRVAL_MASK ((1ULL << ARCH_P4_CNTRVAL_BITS) - 1)
#define ARCH_P4_UNFLAGGED_BIT ((1ULL) << (ARCH_P4_CNTRVAL_BITS - 1))
-#define P4_ESCR_EVENT_MASK 0x7e000000U
+#define P4_ESCR_EVENT_MASK 0x7e000000ULL
#define P4_ESCR_EVENT_SHIFT 25
-#define P4_ESCR_EVENTMASK_MASK 0x01fffe00U
+#define P4_ESCR_EVENTMASK_MASK 0x01fffe00ULL
#define P4_ESCR_EVENTMASK_SHIFT 9
-#define P4_ESCR_TAG_MASK 0x000001e0U
+#define P4_ESCR_TAG_MASK 0x000001e0ULL
#define P4_ESCR_TAG_SHIFT 5
-#define P4_ESCR_TAG_ENABLE 0x00000010U
-#define P4_ESCR_T0_OS 0x00000008U
-#define P4_ESCR_T0_USR 0x00000004U
-#define P4_ESCR_T1_OS 0x00000002U
-#define P4_ESCR_T1_USR 0x00000001U
+#define P4_ESCR_TAG_ENABLE 0x00000010ULL
+#define P4_ESCR_T0_OS 0x00000008ULL
+#define P4_ESCR_T0_USR 0x00000004ULL
+#define P4_ESCR_T1_OS 0x00000002ULL
+#define P4_ESCR_T1_USR 0x00000001ULL
#define P4_ESCR_EVENT(v) ((v) << P4_ESCR_EVENT_SHIFT)
#define P4_ESCR_EMASK(v) ((v) << P4_ESCR_EVENTMASK_SHIFT)
#define P4_ESCR_TAG(v) ((v) << P4_ESCR_TAG_SHIFT)
-#define P4_CCCR_OVF 0x80000000U
-#define P4_CCCR_CASCADE 0x40000000U
-#define P4_CCCR_OVF_PMI_T0 0x04000000U
-#define P4_CCCR_OVF_PMI_T1 0x08000000U
-#define P4_CCCR_FORCE_OVF 0x02000000U
-#define P4_CCCR_EDGE 0x01000000U
-#define P4_CCCR_THRESHOLD_MASK 0x00f00000U
+#define P4_CCCR_OVF 0x80000000ULL
+#define P4_CCCR_CASCADE 0x40000000ULL
+#define P4_CCCR_OVF_PMI_T0 0x04000000ULL
+#define P4_CCCR_OVF_PMI_T1 0x08000000ULL
+#define P4_CCCR_FORCE_OVF 0x02000000ULL
+#define P4_CCCR_EDGE 0x01000000ULL
+#define P4_CCCR_THRESHOLD_MASK 0x00f00000ULL
#define P4_CCCR_THRESHOLD_SHIFT 20
-#define P4_CCCR_COMPLEMENT 0x00080000U
-#define P4_CCCR_COMPARE 0x00040000U
-#define P4_CCCR_ESCR_SELECT_MASK 0x0000e000U
+#define P4_CCCR_COMPLEMENT 0x00080000ULL
+#define P4_CCCR_COMPARE 0x00040000ULL
+#define P4_CCCR_ESCR_SELECT_MASK 0x0000e000ULL
#define P4_CCCR_ESCR_SELECT_SHIFT 13
-#define P4_CCCR_ENABLE 0x00001000U
-#define P4_CCCR_THREAD_SINGLE 0x00010000U
-#define P4_CCCR_THREAD_BOTH 0x00020000U
-#define P4_CCCR_THREAD_ANY 0x00030000U
-#define P4_CCCR_RESERVED 0x00000fffU
+#define P4_CCCR_ENABLE 0x00001000ULL
+#define P4_CCCR_THREAD_SINGLE 0x00010000ULL
+#define P4_CCCR_THREAD_BOTH 0x00020000ULL
+#define P4_CCCR_THREAD_ANY 0x00030000ULL
+#define P4_CCCR_RESERVED 0x00000fffULL
#define P4_CCCR_THRESHOLD(v) ((v) << P4_CCCR_THRESHOLD_SHIFT)
#define P4_CCCR_ESEL(v) ((v) << P4_CCCR_ESCR_SELECT_SHIFT)
#define P4_GEN_ESCR_EMASK(class, name, bit) \
- class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT)
+ class##__##name = ((1ULL << bit) << P4_ESCR_EVENTMASK_SHIFT)
#define P4_ESCR_EMASK_BIT(class, name) class##__##name
/*
@@ -107,7 +107,7 @@
* P4_PEBS_CONFIG_MASK and related bits on
* modification.)
*/
-#define P4_CONFIG_ALIASABLE (1 << 9)
+#define P4_CONFIG_ALIASABLE (1ULL << 9)
/*
* The bits we allow to pass for RAW events
@@ -784,17 +784,17 @@ enum P4_ESCR_EMASKS {
* Note we have UOP and PEBS bits reserved for now
* just in case if we will need them once
*/
-#define P4_PEBS_CONFIG_ENABLE (1 << 7)
-#define P4_PEBS_CONFIG_UOP_TAG (1 << 8)
-#define P4_PEBS_CONFIG_METRIC_MASK 0x3f
-#define P4_PEBS_CONFIG_MASK 0xff
+#define P4_PEBS_CONFIG_ENABLE (1ULL << 7)
+#define P4_PEBS_CONFIG_UOP_TAG (1ULL << 8)
+#define P4_PEBS_CONFIG_METRIC_MASK 0x3FLL
+#define P4_PEBS_CONFIG_MASK 0xFFLL
/*
* mem: Only counters MSR_IQ_COUNTER4 (16) and
* MSR_IQ_COUNTER5 (17) are allowed for PEBS sampling
*/
-#define P4_PEBS_ENABLE 0x02000000U
-#define P4_PEBS_ENABLE_UOP_TAG 0x01000000U
+#define P4_PEBS_ENABLE 0x02000000ULL
+#define P4_PEBS_ENABLE_UOP_TAG 0x01000000ULL
#define p4_config_unpack_metric(v) (((u64)(v)) & P4_PEBS_CONFIG_METRIC_MASK)
#define p4_config_unpack_pebs(v) (((u64)(v)) & P4_PEBS_CONFIG_MASK)
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 567b5d0632b2..e6423002c10b 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -351,7 +351,6 @@ static inline void update_page_count(int level, unsigned long pages) { }
* as a pte too.
*/
extern pte_t *lookup_address(unsigned long address, unsigned int *level);
-extern int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase);
extern phys_addr_t slow_virt_to_phys(void *__address);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 3270116b1488..22224b3b43bb 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -91,9 +91,6 @@ struct cpuinfo_x86 {
/* Problems on some 486Dx4's and old 386's: */
char hard_math;
char rfu;
- char fdiv_bug;
- char f00f_bug;
- char coma_bug;
char pad0;
#else
/* Number of 4K pages in DTLB/ITLB combined(in pages): */
@@ -107,7 +104,7 @@ struct cpuinfo_x86 {
__u32 extended_cpuid_level;
/* Maximum supported CPUID level, -1=no CPUID: */
int cpuid_level;
- __u32 x86_capability[NCAPINTS];
+ __u32 x86_capability[NCAPINTS + NBUGINTS];
char x86_vendor_id[16];
char x86_model_id[64];
/* in KB - valid for CPUS which support this call: */
@@ -973,26 +970,6 @@ unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,
return ratio;
}
-/*
- * AMD errata checking
- */
-#ifdef CONFIG_CPU_SUP_AMD
-extern const int amd_erratum_383[];
-extern const int amd_erratum_400[];
-extern bool cpu_has_amd_erratum(const int *);
-
-#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
-#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
-#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
- ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
-#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
-#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
-#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
-
-#else
-#define cpu_has_amd_erratum(x) (false)
-#endif /* CONFIG_CPU_SUP_AMD */
-
extern unsigned long arch_align_stack(unsigned long sp);
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h
index 487055c8c1aa..f6064b7385b0 100644
--- a/arch/x86/include/asm/suspend_32.h
+++ b/arch/x86/include/asm/suspend_32.h
@@ -15,7 +15,6 @@ struct saved_context {
unsigned long cr0, cr2, cr3, cr4;
u64 misc_enable;
bool misc_enable_saved;
- struct desc_ptr gdt;
struct desc_ptr idt;
u16 ldt;
u16 tss;
diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h
index 09b0bf104156..97b84e08a211 100644
--- a/arch/x86/include/asm/suspend_64.h
+++ b/arch/x86/include/asm/suspend_64.h
@@ -25,9 +25,6 @@ struct saved_context {
u64 misc_enable;
bool misc_enable_saved;
unsigned long efer;
- u16 gdt_pad;
- u16 gdt_limit;
- unsigned long gdt_base;
u16 idt_pad;
u16 idt_limit;
unsigned long idt_base;
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index 8459efc39686..0ef202e232d6 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -30,23 +30,14 @@ asmlinkage long sys32_fstatat(unsigned int, const char __user *,
struct stat64 __user *, int);
struct mmap_arg_struct32;
asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *);
-asmlinkage long sys32_mprotect(unsigned long, size_t, unsigned long);
-
-asmlinkage long sys32_alarm(unsigned int);
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
-asmlinkage long sys32_sysfs(int, u32, u32);
asmlinkage long sys32_pread(unsigned int, char __user *, u32, u32, u32);
asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
-asmlinkage long sys32_personality(unsigned long);
-asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
-
-long sys32_kill(int, int);
long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int);
long sys32_vm86_warning(void);
-long sys32_lookup_dcookie(u32, u32, char __user *, size_t);
asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t);
asmlinkage long sys32_sync_file_range(int, unsigned, unsigned,
@@ -59,9 +50,6 @@ asmlinkage long sys32_fallocate(int, int, unsigned,
asmlinkage long sys32_sigreturn(void);
asmlinkage long sys32_rt_sigreturn(void);
-/* ia32/ipc32.c */
-asmlinkage long sys32_ipc(u32, int, int, int, compat_uptr_t, u32);
-
asmlinkage long sys32_fanotify_mark(int, unsigned int, u32, u32, int,
const char __user *);
diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h
index 1ace47b62592..2e188d68397c 100644
--- a/arch/x86/include/asm/syscall.h
+++ b/arch/x86/include/asm/syscall.h
@@ -29,13 +29,13 @@ extern const unsigned long sys_call_table[];
*/
static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
- return regs->orig_ax & __SYSCALL_MASK;
+ return regs->orig_ax;
}
static inline void syscall_rollback(struct task_struct *task,
struct pt_regs *regs)
{
- regs->ax = regs->orig_ax & __SYSCALL_MASK;
+ regs->ax = regs->orig_ax;
}
static inline long syscall_get_error(struct task_struct *task,
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h
index 6cf0a9cc60cd..5f87b35fd2ef 100644
--- a/arch/x86/include/asm/syscalls.h
+++ b/arch/x86/include/asm/syscalls.h
@@ -27,8 +27,8 @@ asmlinkage int sys_modify_ldt(int, void __user *, unsigned long);
long sys_rt_sigreturn(void);
/* kernel/tls.c */
-asmlinkage int sys_set_thread_area(struct user_desc __user *);
-asmlinkage int sys_get_thread_area(struct user_desc __user *);
+asmlinkage long sys_set_thread_area(struct user_desc __user *);
+asmlinkage long sys_get_thread_area(struct user_desc __user *);
/* X86_32 only */
#ifdef CONFIG_X86_32
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 2cd056e3ada3..a1df6e84691f 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -241,8 +241,6 @@ static inline struct thread_info *current_thread_info(void)
skip sending interrupt */
#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
-#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
-
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
diff --git a/arch/x86/include/asm/tlb.h b/arch/x86/include/asm/tlb.h
index 4fef20773b8f..c7797307fc2b 100644
--- a/arch/x86/include/asm/tlb.h
+++ b/arch/x86/include/asm/tlb.h
@@ -7,7 +7,7 @@
#define tlb_flush(tlb) \
{ \
- if (tlb->fullmm == 0) \
+ if (!tlb->fullmm && !tlb->need_flush_all) \
flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end, 0UL); \
else \
flush_tlb_mm_range(tlb->mm, 0UL, TLB_FLUSH_ALL, 0UL); \
diff --git a/arch/x86/include/asm/unistd.h b/arch/x86/include/asm/unistd.h
index 3d5df1c4447f..c2a48139c340 100644
--- a/arch/x86/include/asm/unistd.h
+++ b/arch/x86/include/asm/unistd.h
@@ -50,12 +50,4 @@
# define __ARCH_WANT_SYS_VFORK
# define __ARCH_WANT_SYS_CLONE
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-# define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
#endif /* _ASM_X86_UNISTD_H */
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index 8ff8be7835ab..6e5197910fd8 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -55,4 +55,5 @@ extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs);
#endif /* _ASM_UPROBES_H */
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index c20d1ce62dc6..e709884d0ef9 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str)
return _hypercall3(int, console_io, cmd, count, str);
}
-extern int __must_check HYPERVISOR_physdev_op_compat(int, void *);
+extern int __must_check xen_physdev_op_compat(int, void *);
static inline int
HYPERVISOR_physdev_op(int cmd, void *arg)
{
int rc = _hypercall2(int, physdev_op, cmd, arg);
if (unlikely(rc == -ENOSYS))
- rc = HYPERVISOR_physdev_op_compat(cmd, arg);
+ rc = xen_physdev_op_compat(cmd, arg);
return rc;
}
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index c15ddaf90710..08744242b8d2 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -6,6 +6,7 @@
#define SETUP_E820_EXT 1
#define SETUP_DTB 2
#define SETUP_PCI 3
+#define SETUP_EFI_VARS 4
/* ram_size flags */
#define RAMDISK_IMAGE_START_MASK 0x07FF
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index 892ce40a7470..b5757885d7a4 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -44,6 +44,7 @@
#define SNB_C1_AUTO_UNDEMOTE (1UL << 27)
#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
+#define MSR_PLATFORM_INFO 0x000000ce
#define MSR_MTRRcap 0x000000fe
#define MSR_IA32_BBL_CR_CTL 0x00000119
#define MSR_IA32_BBL_CR_CTL3 0x0000011e
@@ -71,6 +72,7 @@
#define MSR_IA32_PEBS_ENABLE 0x000003f1
#define MSR_IA32_DS_AREA 0x00000600
#define MSR_IA32_PERF_CAPABILITIES 0x00000345
+#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6
#define MSR_MTRRfix64K_00000 0x00000250
#define MSR_MTRRfix16K_80000 0x00000258
@@ -194,6 +196,10 @@
#define MSR_AMD64_IBSBRTARGET 0xc001103b
#define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */
+/* Fam 16h MSRs */
+#define MSR_F16H_L2I_PERF_CTL 0xc0010230
+#define MSR_F16H_L2I_PERF_CTR 0xc0010231
+
/* Fam 15h MSRs */
#define MSR_F15H_PERF_CTL 0xc0010200
#define MSR_F15H_PERF_CTR 0xc0010201
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index 0532f5d6e4ef..b44577bc9744 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -46,7 +46,7 @@ int acpi_suspend_lowlevel(void)
header->pmode_behavior = 0;
#ifndef CONFIG_64BIT
- store_gdt((struct desc_ptr *)&header->pmode_gdt);
+ native_store_gdt((struct desc_ptr *)&header->pmode_gdt);
if (!rdmsr_safe(MSR_EFER,
&header->pmode_efer_low,
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index 13ab720573e3..d1daa66ab162 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -1,4 +1,4 @@
- .section .text..page_aligned
+ .text
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page_types.h>
@@ -18,7 +18,6 @@ wakeup_pmode_return:
movw %ax, %gs
# reload the gdt, as we need the full 32 bit address
- lgdt saved_gdt
lidt saved_idt
lldt saved_ldt
ljmp $(__KERNEL_CS), $1f
@@ -44,7 +43,6 @@ bogus_magic:
save_registers:
- sgdt saved_gdt
sidt saved_idt
sldt saved_ldt
str saved_tss
@@ -93,7 +91,6 @@ ENTRY(saved_magic) .long 0
ENTRY(saved_eip) .long 0
# saved registers
-saved_gdt: .long 0,0
saved_idt: .long 0,0
saved_ldt: .long 0
saved_tss: .long 0
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index ef5ccca79a6c..c15cf9a25e27 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -271,7 +271,7 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
replacement = (u8 *)&a->repl_offset + a->repl_offset;
BUG_ON(a->replacementlen > a->instrlen);
BUG_ON(a->instrlen > sizeof(insnbuf));
- BUG_ON(a->cpuid >= NCAPINTS*32);
+ BUG_ON(a->cpuid >= (NCAPINTS + NBUGINTS) * 32);
if (!boot_cpu_has(a->cpuid))
continue;
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index aadf3359e2a7..3048ded1b598 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -20,12 +20,14 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{}
};
EXPORT_SYMBOL(amd_nb_misc_ids);
-static struct pci_device_id amd_nb_link_ids[] = {
+static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{}
};
@@ -81,7 +83,6 @@ int amd_cache_northbridges(void)
next_northbridge(link, amd_nb_link_ids);
}
- /* some CPU families (e.g. family 0x11) do not support GART */
if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
boot_cpu_data.x86 == 0x15)
amd_northbridges.flags |= AMD_NB_GART;
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index d5fd66f0d4cd..fd972a3e4cbb 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -87,7 +87,7 @@ static u32 __init allocate_aperture(void)
*/
addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR,
aper_size, aper_size);
- if (!addr || addr + aper_size > GART_MAX_ADDR) {
+ if (!addr) {
printk(KERN_ERR
"Cannot allocate aperture memory hole (%lx,%uK)\n",
addr, aper_size>>10);
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 66b5faffe14a..53a4e2744846 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -373,7 +373,6 @@ static int apm_cpu_idle(struct cpuidle_device *dev,
static struct cpuidle_driver apm_idle_driver = {
.name = "apm_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states = {
{ /* entry 0 is for polling */ },
{ /* entry 1 is for APM idle */
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index a0e067d3d96c..b0684e4a73aa 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -14,7 +14,6 @@ CFLAGS_common.o := $(nostackp)
obj-y := intel_cacheinfo.o scattered.o topology.o
obj-y += proc.o capflags.o powerflags.o common.o
-obj-y += vmware.o hypervisor.o mshyperv.o
obj-y += rdrand.o
obj-y += match.o
@@ -31,7 +30,7 @@ obj-$(CONFIG_CPU_SUP_UMC_32) += umc.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
ifdef CONFIG_PERF_EVENTS
-obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o
+obj-$(CONFIG_CPU_SUP_AMD) += perf_event_amd.o perf_event_amd_uncore.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o
obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_uncore.o
@@ -42,11 +41,13 @@ obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o perf_event_amd_ibs.o
+obj-$(CONFIG_HYPERVISOR_GUEST) += vmware.o hypervisor.o mshyperv.o
+
quiet_cmd_mkcapflags = MKCAP $@
- cmd_mkcapflags = $(PERL) $(srctree)/$(src)/mkcapflags.pl $< $@
+ cmd_mkcapflags = $(CONFIG_SHELL) $(srctree)/$(src)/mkcapflags.sh $< $@
cpufeature = $(src)/../../include/asm/cpufeature.h
targets += capflags.c
-$(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.pl FORCE
+$(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.sh FORCE
$(call if_changed,mkcapflags)
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index fa96eb0d02fb..5013a48d1aff 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -20,11 +20,11 @@
static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
{
- struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
u32 gprs[8] = { 0 };
int err;
- WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+ WARN_ONCE((boot_cpu_data.x86 != 0xf),
+ "%s should only be used on K8!\n", __func__);
gprs[1] = msr;
gprs[7] = 0x9c5a203a;
@@ -38,10 +38,10 @@ static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p)
static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val)
{
- struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
u32 gprs[8] = { 0 };
- WARN_ONCE((c->x86 != 0xf), "%s should only be used on K8!\n", __func__);
+ WARN_ONCE((boot_cpu_data.x86 != 0xf),
+ "%s should only be used on K8!\n", __func__);
gprs[0] = (u32)val;
gprs[1] = msr;
@@ -192,11 +192,11 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
/* Athlon 660/661 is valid. */
if ((c->x86_model == 6) && ((c->x86_mask == 0) ||
(c->x86_mask == 1)))
- goto valid_k7;
+ return;
/* Duron 670 is valid */
if ((c->x86_model == 7) && (c->x86_mask == 0))
- goto valid_k7;
+ return;
/*
* Athlon 662, Duron 671, and Athlon >model 7 have capability
@@ -209,7 +209,7 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
((c->x86_model == 7) && (c->x86_mask >= 1)) ||
(c->x86_model > 7))
if (cpu_has_mp)
- goto valid_k7;
+ return;
/* If we get here, not a certified SMP capable AMD system. */
@@ -220,9 +220,6 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
WARN_ONCE(1, "WARNING: This combination of AMD"
" processors is not suitable for SMP.\n");
add_taint(TAINT_UNSAFE_SMP, LOCKDEP_NOW_UNRELIABLE);
-
-valid_k7:
- ;
}
static void __cpuinit init_amd_k7(struct cpuinfo_x86 *c)
@@ -513,6 +510,10 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
#endif
}
+static const int amd_erratum_383[];
+static const int amd_erratum_400[];
+static bool cpu_has_amd_erratum(const int *erratum);
+
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
u32 dummy;
@@ -727,8 +728,14 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
rdmsrl_safe(MSR_AMD64_BU_CFG2, &value);
value &= ~(1ULL << 24);
wrmsrl_safe(MSR_AMD64_BU_CFG2, value);
+
+ if (cpu_has_amd_erratum(amd_erratum_383))
+ set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH);
}
+ if (cpu_has_amd_erratum(amd_erratum_400))
+ set_cpu_bug(c, X86_BUG_AMD_APIC_C1E);
+
rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
}
@@ -847,8 +854,7 @@ cpu_dev_register(amd_cpu_dev);
* AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that
* have an OSVW id assigned, which it takes as first argument. Both take a
* variable number of family-specific model-stepping ranges created by
- * AMD_MODEL_RANGE(). Each erratum also has to be declared as extern const
- * int[] in arch/x86/include/asm/processor.h.
+ * AMD_MODEL_RANGE().
*
* Example:
*
@@ -858,16 +864,22 @@ cpu_dev_register(amd_cpu_dev);
* AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0));
*/
-const int amd_erratum_400[] =
+#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 }
+#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 }
+#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \
+ ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end))
+#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff)
+#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff)
+#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff)
+
+static const int amd_erratum_400[] =
AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf),
AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf));
-EXPORT_SYMBOL_GPL(amd_erratum_400);
-const int amd_erratum_383[] =
+static const int amd_erratum_383[] =
AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf));
-EXPORT_SYMBOL_GPL(amd_erratum_383);
-bool cpu_has_amd_erratum(const int *erratum)
+static bool cpu_has_amd_erratum(const int *erratum)
{
struct cpuinfo_x86 *cpu = __this_cpu_ptr(&cpu_info);
int osvw_id = *erratum++;
@@ -908,5 +920,3 @@ bool cpu_has_amd_erratum(const int *erratum)
return false;
}
-
-EXPORT_SYMBOL_GPL(cpu_has_amd_erratum);
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index af6455e3fcc9..4112be9a4659 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -59,7 +59,7 @@ static void __init check_fpu(void)
* trap_init() enabled FXSR and company _before_ testing for FP
* problems here.
*
- * Test for the divl bug..
+ * Test for the divl bug: http://en.wikipedia.org/wiki/Fdiv_bug
*/
__asm__("fninit\n\t"
"fldl %1\n\t"
@@ -75,26 +75,12 @@ static void __init check_fpu(void)
kernel_fpu_end();
- boot_cpu_data.fdiv_bug = fdiv_bug;
- if (boot_cpu_data.fdiv_bug)
+ if (fdiv_bug) {
+ set_cpu_bug(&boot_cpu_data, X86_BUG_FDIV);
pr_warn("Hmm, FPU with FDIV bug\n");
+ }
}
-/*
- * Check whether we are able to run this kernel safely on SMP.
- *
- * - i386 is no longer supported.
- * - In order to run on anything without a TSC, we need to be
- * compiled for a i486.
- */
-
-static void __init check_config(void)
-{
- if (boot_cpu_data.x86 < 4)
- panic("Kernel requires i486+ for 'invlpg' and other features");
-}
-
-
void __init check_bugs(void)
{
identify_boot_cpu();
@@ -102,7 +88,17 @@ void __init check_bugs(void)
pr_info("CPU: ");
print_cpu_info(&boot_cpu_data);
#endif
- check_config();
+
+ /*
+ * Check whether we are able to run this kernel safely on SMP.
+ *
+ * - i386 is no longer supported.
+ * - In order to run on anything without a TSC, we need to be
+ * compiled for a i486.
+ */
+ if (boot_cpu_data.x86 < 4)
+ panic("Kernel requires i486+ for 'invlpg' and other features");
+
init_utsname()->machine[1] =
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
alternative_instructions();
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d814772c5bed..22018f70a671 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -920,6 +920,10 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
/* AND the already accumulated flags with these */
for (i = 0; i < NCAPINTS; i++)
boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
+
+ /* OR, i.e. replicate the bug flags */
+ for (i = NCAPINTS; i < NCAPINTS + NBUGINTS; i++)
+ c->x86_capability[i] |= boot_cpu_data.x86_capability[i];
}
/* Init Machine Check Exception if available. */
diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
index 4fbd384fb645..d048d5ca43c1 100644
--- a/arch/x86/kernel/cpu/cyrix.c
+++ b/arch/x86/kernel/cpu/cyrix.c
@@ -249,7 +249,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
/* Emulate MTRRs using Cyrix's ARRs. */
set_cpu_cap(c, X86_FEATURE_CYRIX_ARR);
/* 6x86's contain this bug */
- c->coma_bug = 1;
+ set_cpu_bug(c, X86_BUG_COMA);
break;
case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */
@@ -317,7 +317,8 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
/* Enable MMX extensions (App note 108) */
setCx86_old(CX86_CCR7, getCx86_old(CX86_CCR7)|1);
} else {
- c->coma_bug = 1; /* 6x86MX, it has the bug. */
+ /* A 6x86MX - it has the bug. */
+ set_cpu_bug(c, X86_BUG_COMA);
}
tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 1905ce98bee0..9b0c441c03f5 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -96,6 +96,18 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
sched_clock_stable = 1;
}
+ /* Penwell and Cloverview have the TSC which doesn't sleep on S3 */
+ if (c->x86 == 6) {
+ switch (c->x86_model) {
+ case 0x27: /* Penwell */
+ case 0x35: /* Cloverview */
+ set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC_S3);
+ break;
+ default:
+ break;
+ }
+ }
+
/*
* There is a known erratum on Pentium III and Core Solo
* and Core Duo CPUs.
@@ -164,20 +176,6 @@ int __cpuinit ppro_with_ram_bug(void)
return 0;
}
-#ifdef CONFIG_X86_F00F_BUG
-static void __cpuinit trap_init_f00f_bug(void)
-{
- __set_fixmap(FIX_F00F_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
-
- /*
- * Update the IDT descriptor and reload the IDT so that
- * it uses the read-only mapped virtual address.
- */
- idt_descr.address = fix_to_virt(FIX_F00F_IDT);
- load_idt(&idt_descr);
-}
-#endif
-
static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c)
{
/* calling is from identify_secondary_cpu() ? */
@@ -206,16 +204,14 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
/*
* All current models of Pentium and Pentium with MMX technology CPUs
* have the F0 0F bug, which lets nonprivileged users lock up the
- * system.
- * Note that the workaround only should be initialized once...
+ * system. Announce that the fault handler will be checking for it.
*/
- c->f00f_bug = 0;
+ clear_cpu_bug(c, X86_BUG_F00F);
if (!paravirt_enabled() && c->x86 == 5) {
static int f00f_workaround_enabled;
- c->f00f_bug = 1;
+ set_cpu_bug(c, X86_BUG_F00F);
if (!f00f_workaround_enabled) {
- trap_init_f00f_bug();
printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
f00f_workaround_enabled = 1;
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 7bc126346ace..9239504b41cb 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -2358,7 +2358,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
if (action == CPU_POST_DEAD) {
/* intentionally ignoring frozen here */
- cmci_rediscover(cpu);
+ cmci_rediscover();
}
return NOTIFY_OK;
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 1ac581f38dfa..9cb52767999a 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -33,7 +33,6 @@
#include <asm/mce.h>
#include <asm/msr.h>
-#define NR_BANKS 6
#define NR_BLOCKS 9
#define THRESHOLD_MAX 0xFFF
#define INT_TYPE_APIC 0x00020000
@@ -57,12 +56,7 @@ static const char * const th_names[] = {
"execution_unit",
};
-static DEFINE_PER_CPU(struct threshold_bank * [NR_BANKS], threshold_banks);
-
-static unsigned char shared_bank[NR_BANKS] = {
- 0, 0, 0, 0, 1
-};
-
+static DEFINE_PER_CPU(struct threshold_bank **, threshold_banks);
static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */
static void amd_threshold_interrupt(void);
@@ -79,6 +73,12 @@ struct thresh_restart {
u16 old_limit;
};
+static inline bool is_shared_bank(int bank)
+{
+ /* Bank 4 is for northbridge reporting and is thus shared */
+ return (bank == 4);
+}
+
static const char * const bank4_names(struct threshold_block *b)
{
switch (b->address) {
@@ -214,7 +214,7 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
unsigned int bank, block;
int offset = -1;
- for (bank = 0; bank < NR_BANKS; ++bank) {
+ for (bank = 0; bank < mca_cfg.banks; ++bank) {
for (block = 0; block < NR_BLOCKS; ++block) {
if (block == 0)
address = MSR_IA32_MC0_MISC + bank * 4;
@@ -276,7 +276,7 @@ static void amd_threshold_interrupt(void)
mce_setup(&m);
/* assume first bank caused it */
- for (bank = 0; bank < NR_BANKS; ++bank) {
+ for (bank = 0; bank < mca_cfg.banks; ++bank) {
if (!(per_cpu(bank_map, m.cpu) & (1 << bank)))
continue;
for (block = 0; block < NR_BLOCKS; ++block) {
@@ -467,7 +467,7 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
u32 low, high;
int err;
- if ((bank >= NR_BANKS) || (block >= NR_BLOCKS))
+ if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS))
return 0;
if (rdmsr_safe_on_cpu(cpu, address, &low, &high))
@@ -575,7 +575,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
const char *name = th_names[bank];
int err = 0;
- if (shared_bank[bank]) {
+ if (is_shared_bank(bank)) {
nb = node_to_amd_nb(amd_get_nb_id(cpu));
/* threshold descriptor already initialized on this node? */
@@ -609,7 +609,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
per_cpu(threshold_banks, cpu)[bank] = b;
- if (shared_bank[bank]) {
+ if (is_shared_bank(bank)) {
atomic_set(&b->cpus, 1);
/* nb is already initialized, see above */
@@ -635,9 +635,17 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)
static __cpuinit int threshold_create_device(unsigned int cpu)
{
unsigned int bank;
+ struct threshold_bank **bp;
int err = 0;
- for (bank = 0; bank < NR_BANKS; ++bank) {
+ bp = kzalloc(sizeof(struct threshold_bank *) * mca_cfg.banks,
+ GFP_KERNEL);
+ if (!bp)
+ return -ENOMEM;
+
+ per_cpu(threshold_banks, cpu) = bp;
+
+ for (bank = 0; bank < mca_cfg.banks; ++bank) {
if (!(per_cpu(bank_map, cpu) & (1 << bank)))
continue;
err = threshold_create_bank(cpu, bank);
@@ -691,7 +699,7 @@ static void threshold_remove_bank(unsigned int cpu, int bank)
if (!b->blocks)
goto free_out;
- if (shared_bank[bank]) {
+ if (is_shared_bank(bank)) {
if (!atomic_dec_and_test(&b->cpus)) {
__threshold_remove_blocks(b);
per_cpu(threshold_banks, cpu)[bank] = NULL;
@@ -719,11 +727,12 @@ static void threshold_remove_device(unsigned int cpu)
{
unsigned int bank;
- for (bank = 0; bank < NR_BANKS; ++bank) {
+ for (bank = 0; bank < mca_cfg.banks; ++bank) {
if (!(per_cpu(bank_map, cpu) & (1 << bank)))
continue;
threshold_remove_bank(cpu, bank);
}
+ kfree(per_cpu(threshold_banks, cpu));
}
/* get notified when a cpu comes on/off */
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index 402c454fbff0..ae1697c2afe3 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -285,39 +285,24 @@ void cmci_clear(void)
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
-static long cmci_rediscover_work_func(void *arg)
+static void cmci_rediscover_work_func(void *arg)
{
int banks;
/* Recheck banks in case CPUs don't all have the same */
if (cmci_supported(&banks))
cmci_discover(banks);
-
- return 0;
}
-/*
- * After a CPU went down cycle through all the others and rediscover
- * Must run in process context.
- */
-void cmci_rediscover(int dying)
+/* After a CPU went down cycle through all the others and rediscover */
+void cmci_rediscover(void)
{
- int cpu, banks;
+ int banks;
if (!cmci_supported(&banks))
return;
- for_each_online_cpu(cpu) {
- if (cpu == dying)
- continue;
-
- if (cpu == smp_processor_id()) {
- cmci_rediscover_work_func(NULL);
- continue;
- }
-
- work_on_cpu(cpu, cmci_rediscover_work_func, NULL);
- }
+ on_each_cpu(cmci_rediscover_work_func, NULL, 1);
}
/*
diff --git a/arch/x86/kernel/cpu/mkcapflags.pl b/arch/x86/kernel/cpu/mkcapflags.pl
deleted file mode 100644
index 091972ef49de..000000000000
--- a/arch/x86/kernel/cpu/mkcapflags.pl
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Generate the x86_cap_flags[] array from include/asm-x86/cpufeature.h
-#
-
-($in, $out) = @ARGV;
-
-open(IN, "< $in\0") or die "$0: cannot open: $in: $!\n";
-open(OUT, "> $out\0") or die "$0: cannot create: $out: $!\n";
-
-print OUT "#ifndef _ASM_X86_CPUFEATURE_H\n";
-print OUT "#include <asm/cpufeature.h>\n";
-print OUT "#endif\n";
-print OUT "\n";
-print OUT "const char * const x86_cap_flags[NCAPINTS*32] = {\n";
-
-%features = ();
-$err = 0;
-
-while (defined($line = <IN>)) {
- if ($line =~ /^\s*\#\s*define\s+(X86_FEATURE_(\S+))\s+(.*)$/) {
- $macro = $1;
- $feature = "\L$2";
- $tail = $3;
- if ($tail =~ /\/\*\s*\"([^"]*)\".*\*\//) {
- $feature = "\L$1";
- }
-
- next if ($feature eq '');
-
- if ($features{$feature}++) {
- print STDERR "$in: duplicate feature name: $feature\n";
- $err++;
- }
- printf OUT "\t%-32s = \"%s\",\n", "[$macro]", $feature;
- }
-}
-print OUT "};\n";
-
-close(IN);
-close(OUT);
-
-if ($err) {
- unlink($out);
- exit(1);
-}
-
-exit(0);
diff --git a/arch/x86/kernel/cpu/mkcapflags.sh b/arch/x86/kernel/cpu/mkcapflags.sh
new file mode 100644
index 000000000000..2bf616505499
--- /dev/null
+++ b/arch/x86/kernel/cpu/mkcapflags.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+#
+# Generate the x86_cap_flags[] array from include/asm/cpufeature.h
+#
+
+IN=$1
+OUT=$2
+
+TABS="$(printf '\t\t\t\t\t')"
+trap 'rm "$OUT"' EXIT
+
+(
+ echo "#ifndef _ASM_X86_CPUFEATURE_H"
+ echo "#include <asm/cpufeature.h>"
+ echo "#endif"
+ echo ""
+ echo "const char * const x86_cap_flags[NCAPINTS*32] = {"
+
+ # Iterate through any input lines starting with #define X86_FEATURE_
+ sed -n -e 's/\t/ /g' -e 's/^ *# *define *X86_FEATURE_//p' $IN |
+ while read i
+ do
+ # Name is everything up to the first whitespace
+ NAME="$(echo "$i" | sed 's/ .*//')"
+
+ # If the /* comment */ starts with a quote string, grab that.
+ VALUE="$(echo "$i" | sed -n 's@.*/\* *\("[^"]*"\).*\*/@\1@p')"
+ [ -z "$VALUE" ] && VALUE="\"$NAME\""
+ [ "$VALUE" == '""' ] && continue
+
+ # Name is uppercase, VALUE is all lowercase
+ VALUE="$(echo "$VALUE" | tr A-Z a-z)"
+
+ TABCOUNT=$(( ( 5*8 - 14 - $(echo "$NAME" | wc -c) ) / 8 ))
+ printf "\t[%s]%.*s = %s,\n" \
+ "X86_FEATURE_$NAME" "$TABCOUNT" "$TABS" "$VALUE"
+ done
+ echo "};"
+) > $OUT
+
+trap - EXIT
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index a7d26d83fb70..8f4be53ea04b 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -35,13 +35,6 @@ static bool __init ms_hyperv_platform(void)
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
return false;
- /*
- * Xen emulates Hyper-V to support enlightened Windows.
- * Check to see first if we are on a Xen Hypervisor.
- */
- if (xen_cpuid_base())
- return false;
-
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
@@ -82,12 +75,6 @@ static void __init ms_hyperv_init_platform(void)
if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
-#if IS_ENABLED(CONFIG_HYPERV)
- /*
- * Setup the IDT for hypervisor callback.
- */
- alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
-#endif
}
const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
@@ -103,6 +90,11 @@ static irq_handler_t vmbus_isr;
void hv_register_vmbus_handler(int irq, irq_handler_t handler)
{
+ /*
+ * Setup the IDT for hypervisor callback.
+ */
+ alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
+
vmbus_irq = irq;
vmbus_isr = handler;
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index bf0f01aea994..1025f3c99d20 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -180,8 +180,9 @@ static void release_pmc_hardware(void) {}
static bool check_hw_exists(void)
{
- u64 val, val_new = ~0;
- int i, reg, ret = 0;
+ u64 val, val_fail, val_new= ~0;
+ int i, reg, reg_fail, ret = 0;
+ int bios_fail = 0;
/*
* Check to see if the BIOS enabled any of the counters, if so
@@ -192,8 +193,11 @@ static bool check_hw_exists(void)
ret = rdmsrl_safe(reg, &val);
if (ret)
goto msr_fail;
- if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
- goto bios_fail;
+ if (val & ARCH_PERFMON_EVENTSEL_ENABLE) {
+ bios_fail = 1;
+ val_fail = val;
+ reg_fail = reg;
+ }
}
if (x86_pmu.num_counters_fixed) {
@@ -202,8 +206,11 @@ static bool check_hw_exists(void)
if (ret)
goto msr_fail;
for (i = 0; i < x86_pmu.num_counters_fixed; i++) {
- if (val & (0x03 << i*4))
- goto bios_fail;
+ if (val & (0x03 << i*4)) {
+ bios_fail = 1;
+ val_fail = val;
+ reg_fail = reg;
+ }
}
}
@@ -221,14 +228,13 @@ static bool check_hw_exists(void)
if (ret || val != val_new)
goto msr_fail;
- return true;
-
-bios_fail:
/*
* We still allow the PMU driver to operate:
*/
- printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n");
- printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg, val);
+ if (bios_fail) {
+ printk(KERN_CONT "Broken BIOS detected, complain to your hardware vendor.\n");
+ printk(KERN_ERR FW_BUG "the BIOS has corrupted hw-PMU resources (MSR %x is %Lx)\n", reg_fail, val_fail);
+ }
return true;
@@ -1316,9 +1322,16 @@ static struct attribute_group x86_pmu_format_group = {
*/
static void __init filter_events(struct attribute **attrs)
{
+ struct device_attribute *d;
+ struct perf_pmu_events_attr *pmu_attr;
int i, j;
for (i = 0; attrs[i]; i++) {
+ d = (struct device_attribute *)attrs[i];
+ pmu_attr = container_of(d, struct perf_pmu_events_attr, attr);
+ /* str trumps id */
+ if (pmu_attr->event_str)
+ continue;
if (x86_pmu.event_map(i))
continue;
@@ -1330,22 +1343,45 @@ static void __init filter_events(struct attribute **attrs)
}
}
-static ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
+/* Merge two pointer arrays */
+static __init struct attribute **merge_attr(struct attribute **a, struct attribute **b)
+{
+ struct attribute **new;
+ int j, i;
+
+ for (j = 0; a[j]; j++)
+ ;
+ for (i = 0; b[i]; i++)
+ j++;
+ j++;
+
+ new = kmalloc(sizeof(struct attribute *) * j, GFP_KERNEL);
+ if (!new)
+ return NULL;
+
+ j = 0;
+ for (i = 0; a[i]; i++)
+ new[j++] = a[i];
+ for (i = 0; b[i]; i++)
+ new[j++] = b[i];
+ new[j] = NULL;
+
+ return new;
+}
+
+ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
char *page)
{
struct perf_pmu_events_attr *pmu_attr = \
container_of(attr, struct perf_pmu_events_attr, attr);
-
u64 config = x86_pmu.event_map(pmu_attr->id);
- return x86_pmu.events_sysfs_show(page, config);
-}
-#define EVENT_VAR(_id) event_attr_##_id
-#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
+ /* string trumps id */
+ if (pmu_attr->event_str)
+ return sprintf(page, "%s", pmu_attr->event_str);
-#define EVENT_ATTR(_name, _id) \
- PMU_EVENT_ATTR(_name, EVENT_VAR(_id), PERF_COUNT_HW_##_id, \
- events_sysfs_show)
+ return x86_pmu.events_sysfs_show(page, config);
+}
EVENT_ATTR(cpu-cycles, CPU_CYCLES );
EVENT_ATTR(instructions, INSTRUCTIONS );
@@ -1459,16 +1495,27 @@ static int __init init_hw_perf_events(void)
unconstrained = (struct event_constraint)
__EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
- 0, x86_pmu.num_counters, 0);
+ 0, x86_pmu.num_counters, 0, 0);
x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
x86_pmu_format_group.attrs = x86_pmu.format_attrs;
+ if (x86_pmu.event_attrs)
+ x86_pmu_events_group.attrs = x86_pmu.event_attrs;
+
if (!x86_pmu.events_sysfs_show)
x86_pmu_events_group.attrs = &empty_attrs;
else
filter_events(x86_pmu_events_group.attrs);
+ if (x86_pmu.cpu_events) {
+ struct attribute **tmp;
+
+ tmp = merge_attr(x86_pmu_events_group.attrs, x86_pmu.cpu_events);
+ if (!WARN_ON(!tmp))
+ x86_pmu_events_group.attrs = tmp;
+ }
+
pr_info("... version: %d\n", x86_pmu.version);
pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
pr_info("... generic registers: %d\n", x86_pmu.num_counters);
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 7f5c75c2afdd..ba9aadfa683b 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -46,6 +46,7 @@ enum extra_reg_type {
EXTRA_REG_RSP_0 = 0, /* offcore_response_0 */
EXTRA_REG_RSP_1 = 1, /* offcore_response_1 */
EXTRA_REG_LBR = 2, /* lbr_select */
+ EXTRA_REG_LDLAT = 3, /* ld_lat_threshold */
EXTRA_REG_MAX /* number of entries needed */
};
@@ -59,7 +60,13 @@ struct event_constraint {
u64 cmask;
int weight;
int overlap;
+ int flags;
};
+/*
+ * struct event_constraint flags
+ */
+#define PERF_X86_EVENT_PEBS_LDLAT 0x1 /* ld+ldlat data address sampling */
+#define PERF_X86_EVENT_PEBS_ST 0x2 /* st data address sampling */
struct amd_nb {
int nb_id; /* NorthBridge id */
@@ -170,16 +177,17 @@ struct cpu_hw_events {
void *kfree_on_online;
};
-#define __EVENT_CONSTRAINT(c, n, m, w, o) {\
+#define __EVENT_CONSTRAINT(c, n, m, w, o, f) {\
{ .idxmsk64 = (n) }, \
.code = (c), \
.cmask = (m), \
.weight = (w), \
.overlap = (o), \
+ .flags = f, \
}
#define EVENT_CONSTRAINT(c, n, m) \
- __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0)
+ __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0, 0)
/*
* The overlap flag marks event constraints with overlapping counter
@@ -203,7 +211,7 @@ struct cpu_hw_events {
* and its counter masks must be kept at a minimum.
*/
#define EVENT_CONSTRAINT_OVERLAP(c, n, m) \
- __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1)
+ __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1, 0)
/*
* Constraint on the Event code.
@@ -231,6 +239,14 @@ struct cpu_hw_events {
#define INTEL_UEVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+#define INTEL_PLD_CONSTRAINT(c, n) \
+ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
+
+#define INTEL_PST_CONSTRAINT(c, n) \
+ __EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK, \
+ HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
+
#define EVENT_CONSTRAINT_END \
EVENT_CONSTRAINT(0, 0, 0)
@@ -260,12 +276,22 @@ struct extra_reg {
.msr = (ms), \
.config_mask = (m), \
.valid_mask = (vm), \
- .idx = EXTRA_REG_##i \
+ .idx = EXTRA_REG_##i, \
}
#define INTEL_EVENT_EXTRA_REG(event, msr, vm, idx) \
EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT, vm, idx)
+#define INTEL_UEVENT_EXTRA_REG(event, msr, vm, idx) \
+ EVENT_EXTRA_REG(event, msr, ARCH_PERFMON_EVENTSEL_EVENT | \
+ ARCH_PERFMON_EVENTSEL_UMASK, vm, idx)
+
+#define INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(c) \
+ INTEL_UEVENT_EXTRA_REG(c, \
+ MSR_PEBS_LD_LAT_THRESHOLD, \
+ 0xffff, \
+ LDLAT)
+
#define EVENT_EXTRA_END EVENT_EXTRA_REG(0, 0, 0, 0, RSP_0)
union perf_capabilities {
@@ -355,8 +381,10 @@ struct x86_pmu {
*/
int attr_rdpmc;
struct attribute **format_attrs;
+ struct attribute **event_attrs;
ssize_t (*events_sysfs_show)(char *page, u64 config);
+ struct attribute **cpu_events;
/*
* CPU Hotplug hooks
@@ -421,6 +449,23 @@ do { \
#define ERF_NO_HT_SHARING 1
#define ERF_HAS_RSP_1 2
+#define EVENT_VAR(_id) event_attr_##_id
+#define EVENT_PTR(_id) &event_attr_##_id.attr.attr
+
+#define EVENT_ATTR(_name, _id) \
+static struct perf_pmu_events_attr EVENT_VAR(_id) = { \
+ .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \
+ .id = PERF_COUNT_HW_##_id, \
+ .event_str = NULL, \
+};
+
+#define EVENT_ATTR_STR(_name, v, str) \
+static struct perf_pmu_events_attr event_attr_##v = { \
+ .attr = __ATTR(_name, 0444, events_sysfs_show, NULL), \
+ .id = 0, \
+ .event_str = str, \
+};
+
extern struct x86_pmu x86_pmu __read_mostly;
DECLARE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
@@ -628,6 +673,9 @@ int p6_pmu_init(void);
int knc_pmu_init(void);
+ssize_t events_sysfs_show(struct device *dev, struct device_attribute *attr,
+ char *page);
+
#else /* CONFIG_CPU_SUP_INTEL */
static inline void reserve_ds_buffers(void)
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index dfdab42aed27..7e28d9467bb4 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -132,14 +132,11 @@ static u64 amd_pmu_event_map(int hw_event)
return amd_perfmon_event_map[hw_event];
}
-static struct event_constraint *amd_nb_event_constraint;
-
/*
* Previously calculated offsets
*/
static unsigned int event_offsets[X86_PMC_IDX_MAX] __read_mostly;
static unsigned int count_offsets[X86_PMC_IDX_MAX] __read_mostly;
-static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly;
/*
* Legacy CPUs:
@@ -147,14 +144,10 @@ static unsigned int rdpmc_indexes[X86_PMC_IDX_MAX] __read_mostly;
*
* CPUs with core performance counter extensions:
* 6 counters starting at 0xc0010200 each offset by 2
- *
- * CPUs with north bridge performance counter extensions:
- * 4 additional counters starting at 0xc0010240 each offset by 2
- * (indexed right above either one of the above core counters)
*/
static inline int amd_pmu_addr_offset(int index, bool eventsel)
{
- int offset, first, base;
+ int offset;
if (!index)
return index;
@@ -167,23 +160,7 @@ static inline int amd_pmu_addr_offset(int index, bool eventsel)
if (offset)
return offset;
- if (amd_nb_event_constraint &&
- test_bit(index, amd_nb_event_constraint->idxmsk)) {
- /*
- * calculate the offset of NB counters with respect to
- * base eventsel or perfctr
- */
-
- first = find_first_bit(amd_nb_event_constraint->idxmsk,
- X86_PMC_IDX_MAX);
-
- if (eventsel)
- base = MSR_F15H_NB_PERF_CTL - x86_pmu.eventsel;
- else
- base = MSR_F15H_NB_PERF_CTR - x86_pmu.perfctr;
-
- offset = base + ((index - first) << 1);
- } else if (!cpu_has_perfctr_core)
+ if (!cpu_has_perfctr_core)
offset = index;
else
offset = index << 1;
@@ -196,36 +173,6 @@ static inline int amd_pmu_addr_offset(int index, bool eventsel)
return offset;
}
-static inline int amd_pmu_rdpmc_index(int index)
-{
- int ret, first;
-
- if (!index)
- return index;
-
- ret = rdpmc_indexes[index];
-
- if (ret)
- return ret;
-
- if (amd_nb_event_constraint &&
- test_bit(index, amd_nb_event_constraint->idxmsk)) {
- /*
- * according to the mnual, ECX value of the NB counters is
- * the index of the NB counter (0, 1, 2 or 3) plus 6
- */
-
- first = find_first_bit(amd_nb_event_constraint->idxmsk,
- X86_PMC_IDX_MAX);
- ret = index - first + 6;
- } else
- ret = index;
-
- rdpmc_indexes[index] = ret;
-
- return ret;
-}
-
static int amd_core_hw_config(struct perf_event *event)
{
if (event->attr.exclude_host && event->attr.exclude_guest)
@@ -245,34 +192,6 @@ static int amd_core_hw_config(struct perf_event *event)
}
/*
- * NB counters do not support the following event select bits:
- * Host/Guest only
- * Counter mask
- * Invert counter mask
- * Edge detect
- * OS/User mode
- */
-static int amd_nb_hw_config(struct perf_event *event)
-{
- /* for NB, we only allow system wide counting mode */
- if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
- return -EINVAL;
-
- if (event->attr.exclude_user || event->attr.exclude_kernel ||
- event->attr.exclude_host || event->attr.exclude_guest)
- return -EINVAL;
-
- event->hw.config &= ~(ARCH_PERFMON_EVENTSEL_USR |
- ARCH_PERFMON_EVENTSEL_OS);
-
- if (event->hw.config & ~(AMD64_RAW_EVENT_MASK_NB |
- ARCH_PERFMON_EVENTSEL_INT))
- return -EINVAL;
-
- return 0;
-}
-
-/*
* AMD64 events are detected based on their event codes.
*/
static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc)
@@ -285,11 +204,6 @@ static inline int amd_is_nb_event(struct hw_perf_event *hwc)
return (hwc->config & 0xe0) == 0xe0;
}
-static inline int amd_is_perfctr_nb_event(struct hw_perf_event *hwc)
-{
- return amd_nb_event_constraint && amd_is_nb_event(hwc);
-}
-
static inline int amd_has_nb(struct cpu_hw_events *cpuc)
{
struct amd_nb *nb = cpuc->amd_nb;
@@ -315,9 +229,6 @@ static int amd_pmu_hw_config(struct perf_event *event)
if (event->attr.type == PERF_TYPE_RAW)
event->hw.config |= event->attr.config & AMD64_RAW_EVENT_MASK;
- if (amd_is_perfctr_nb_event(&event->hw))
- return amd_nb_hw_config(event);
-
return amd_core_hw_config(event);
}
@@ -341,19 +252,6 @@ static void __amd_put_nb_event_constraints(struct cpu_hw_events *cpuc,
}
}
-static void amd_nb_interrupt_hw_config(struct hw_perf_event *hwc)
-{
- int core_id = cpu_data(smp_processor_id()).cpu_core_id;
-
- /* deliver interrupts only to this core */
- if (hwc->config & ARCH_PERFMON_EVENTSEL_INT) {
- hwc->config |= AMD64_EVENTSEL_INT_CORE_ENABLE;
- hwc->config &= ~AMD64_EVENTSEL_INT_CORE_SEL_MASK;
- hwc->config |= (u64)(core_id) <<
- AMD64_EVENTSEL_INT_CORE_SEL_SHIFT;
- }
-}
-
/*
* AMD64 NorthBridge events need special treatment because
* counter access needs to be synchronized across all cores
@@ -441,9 +339,6 @@ __amd_get_nb_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *ev
if (new == -1)
return &emptyconstraint;
- if (amd_is_perfctr_nb_event(hwc))
- amd_nb_interrupt_hw_config(hwc);
-
return &nb->event_constraints[new];
}
@@ -543,8 +438,7 @@ amd_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
if (!(amd_has_nb(cpuc) && amd_is_nb_event(&event->hw)))
return &unconstrained;
- return __amd_get_nb_event_constraints(cpuc, event,
- amd_nb_event_constraint);
+ return __amd_get_nb_event_constraints(cpuc, event, NULL);
}
static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
@@ -643,9 +537,6 @@ static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09,
static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0);
static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0);
-static struct event_constraint amd_NBPMC96 = EVENT_CONSTRAINT(0, 0x3C0, 0);
-static struct event_constraint amd_NBPMC74 = EVENT_CONSTRAINT(0, 0xF0, 0);
-
static struct event_constraint *
amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event)
{
@@ -711,8 +602,8 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
return &amd_f15_PMC20;
}
case AMD_EVENT_NB:
- return __amd_get_nb_event_constraints(cpuc, event,
- amd_nb_event_constraint);
+ /* moved to perf_event_amd_uncore.c */
+ return &emptyconstraint;
default:
return &emptyconstraint;
}
@@ -738,7 +629,6 @@ static __initconst const struct x86_pmu amd_pmu = {
.eventsel = MSR_K7_EVNTSEL0,
.perfctr = MSR_K7_PERFCTR0,
.addr_offset = amd_pmu_addr_offset,
- .rdpmc_index = amd_pmu_rdpmc_index,
.event_map = amd_pmu_event_map,
.max_events = ARRAY_SIZE(amd_perfmon_event_map),
.num_counters = AMD64_NUM_COUNTERS,
@@ -790,23 +680,6 @@ static int setup_perfctr_core(void)
return 0;
}
-static int setup_perfctr_nb(void)
-{
- if (!cpu_has_perfctr_nb)
- return -ENODEV;
-
- x86_pmu.num_counters += AMD64_NUM_COUNTERS_NB;
-
- if (cpu_has_perfctr_core)
- amd_nb_event_constraint = &amd_NBPMC96;
- else
- amd_nb_event_constraint = &amd_NBPMC74;
-
- printk(KERN_INFO "perf: AMD northbridge performance counters detected\n");
-
- return 0;
-}
-
__init int amd_pmu_init(void)
{
/* Performance-monitoring supported from K7 and later: */
@@ -817,7 +690,6 @@ __init int amd_pmu_init(void)
setup_event_constraints();
setup_perfctr_core();
- setup_perfctr_nb();
/* Events are common for all AMDs */
memcpy(hw_cache_event_ids, amd_hw_cache_event_ids,
diff --git a/arch/x86/kernel/cpu/perf_event_amd_uncore.c b/arch/x86/kernel/cpu/perf_event_amd_uncore.c
new file mode 100644
index 000000000000..c0c661adf03e
--- /dev/null
+++ b/arch/x86/kernel/cpu/perf_event_amd_uncore.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Jacob Shin <jacob.shin@amd.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/perf_event.h>
+#include <linux/percpu.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+
+#include <asm/cpufeature.h>
+#include <asm/perf_event.h>
+#include <asm/msr.h>
+
+#define NUM_COUNTERS_NB 4
+#define NUM_COUNTERS_L2 4
+#define MAX_COUNTERS NUM_COUNTERS_NB
+
+#define RDPMC_BASE_NB 6
+#define RDPMC_BASE_L2 10
+
+#define COUNTER_SHIFT 16
+
+struct amd_uncore {
+ int id;
+ int refcnt;
+ int cpu;
+ int num_counters;
+ int rdpmc_base;
+ u32 msr_base;
+ cpumask_t *active_mask;
+ struct pmu *pmu;
+ struct perf_event *events[MAX_COUNTERS];
+ struct amd_uncore *free_when_cpu_online;
+};
+
+static struct amd_uncore * __percpu *amd_uncore_nb;
+static struct amd_uncore * __percpu *amd_uncore_l2;
+
+static struct pmu amd_nb_pmu;
+static struct pmu amd_l2_pmu;
+
+static cpumask_t amd_nb_active_mask;
+static cpumask_t amd_l2_active_mask;
+
+static bool is_nb_event(struct perf_event *event)
+{
+ return event->pmu->type == amd_nb_pmu.type;
+}
+
+static bool is_l2_event(struct perf_event *event)
+{
+ return event->pmu->type == amd_l2_pmu.type;
+}
+
+static struct amd_uncore *event_to_amd_uncore(struct perf_event *event)
+{
+ if (is_nb_event(event) && amd_uncore_nb)
+ return *per_cpu_ptr(amd_uncore_nb, event->cpu);
+ else if (is_l2_event(event) && amd_uncore_l2)
+ return *per_cpu_ptr(amd_uncore_l2, event->cpu);
+
+ return NULL;
+}
+
+static void amd_uncore_read(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ u64 prev, new;
+ s64 delta;
+
+ /*
+ * since we do not enable counter overflow interrupts,
+ * we do not have to worry about prev_count changing on us
+ */
+
+ prev = local64_read(&hwc->prev_count);
+ rdpmcl(hwc->event_base_rdpmc, new);
+ local64_set(&hwc->prev_count, new);
+ delta = (new << COUNTER_SHIFT) - (prev << COUNTER_SHIFT);
+ delta >>= COUNTER_SHIFT;
+ local64_add(delta, &event->count);
+}
+
+static void amd_uncore_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (flags & PERF_EF_RELOAD)
+ wrmsrl(hwc->event_base, (u64)local64_read(&hwc->prev_count));
+
+ hwc->state = 0;
+ wrmsrl(hwc->config_base, (hwc->config | ARCH_PERFMON_EVENTSEL_ENABLE));
+ perf_event_update_userpage(event);
+}
+
+static void amd_uncore_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+
+ wrmsrl(hwc->config_base, hwc->config);
+ hwc->state |= PERF_HES_STOPPED;
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ amd_uncore_read(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static int amd_uncore_add(struct perf_event *event, int flags)
+{
+ int i;
+ struct amd_uncore *uncore = event_to_amd_uncore(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ /* are we already assigned? */
+ if (hwc->idx != -1 && uncore->events[hwc->idx] == event)
+ goto out;
+
+ for (i = 0; i < uncore->num_counters; i++) {
+ if (uncore->events[i] == event) {
+ hwc->idx = i;
+ goto out;
+ }
+ }
+
+ /* if not, take the first available counter */
+ hwc->idx = -1;
+ for (i = 0; i < uncore->num_counters; i++) {
+ if (cmpxchg(&uncore->events[i], NULL, event) == NULL) {
+ hwc->idx = i;
+ break;
+ }
+ }
+
+out:
+ if (hwc->idx == -1)
+ return -EBUSY;
+
+ hwc->config_base = uncore->msr_base + (2 * hwc->idx);
+ hwc->event_base = uncore->msr_base + 1 + (2 * hwc->idx);
+ hwc->event_base_rdpmc = uncore->rdpmc_base + hwc->idx;
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ amd_uncore_start(event, PERF_EF_RELOAD);
+
+ return 0;
+}
+
+static void amd_uncore_del(struct perf_event *event, int flags)
+{
+ int i;
+ struct amd_uncore *uncore = event_to_amd_uncore(event);
+ struct hw_perf_event *hwc = &event->hw;
+
+ amd_uncore_stop(event, PERF_EF_UPDATE);
+
+ for (i = 0; i < uncore->num_counters; i++) {
+ if (cmpxchg(&uncore->events[i], event, NULL) == event)
+ break;
+ }
+
+ hwc->idx = -1;
+}
+
+static int amd_uncore_event_init(struct perf_event *event)
+{
+ struct amd_uncore *uncore;
+ struct hw_perf_event *hwc = &event->hw;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /*
+ * NB and L2 counters (MSRs) are shared across all cores that share the
+ * same NB / L2 cache. Interrupts can be directed to a single target
+ * core, however, event counts generated by processes running on other
+ * cores cannot be masked out. So we do not support sampling and
+ * per-thread events.
+ */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EINVAL;
+
+ /* NB and L2 counters do not have usr/os/guest/host bits */
+ if (event->attr.exclude_user || event->attr.exclude_kernel ||
+ event->attr.exclude_host || event->attr.exclude_guest)
+ return -EINVAL;
+
+ /* and we do not enable counter overflow interrupts */
+ hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
+ hwc->idx = -1;
+
+ if (event->cpu < 0)
+ return -EINVAL;
+
+ uncore = event_to_amd_uncore(event);
+ if (!uncore)
+ return -ENODEV;
+
+ /*
+ * since request can come in to any of the shared cores, we will remap
+ * to a single common cpu.
+ */
+ event->cpu = uncore->cpu;
+
+ return 0;
+}
+
+static ssize_t amd_uncore_attr_show_cpumask(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int n;
+ cpumask_t *active_mask;
+ struct pmu *pmu = dev_get_drvdata(dev);
+
+ if (pmu->type == amd_nb_pmu.type)
+ active_mask = &amd_nb_active_mask;
+ else if (pmu->type == amd_l2_pmu.type)
+ active_mask = &amd_l2_active_mask;
+ else
+ return 0;
+
+ n = cpulist_scnprintf(buf, PAGE_SIZE - 2, active_mask);
+ buf[n++] = '\n';
+ buf[n] = '\0';
+ return n;
+}
+static DEVICE_ATTR(cpumask, S_IRUGO, amd_uncore_attr_show_cpumask, NULL);
+
+static struct attribute *amd_uncore_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+static struct attribute_group amd_uncore_attr_group = {
+ .attrs = amd_uncore_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-7,32-35");
+PMU_FORMAT_ATTR(umask, "config:8-15");
+
+static struct attribute *amd_uncore_format_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ NULL,
+};
+
+static struct attribute_group amd_uncore_format_group = {
+ .name = "format",
+ .attrs = amd_uncore_format_attr,
+};
+
+static const struct attribute_group *amd_uncore_attr_groups[] = {
+ &amd_uncore_attr_group,
+ &amd_uncore_format_group,
+ NULL,
+};
+
+static struct pmu amd_nb_pmu = {
+ .attr_groups = amd_uncore_attr_groups,
+ .name = "amd_nb",
+ .event_init = amd_uncore_event_init,
+ .add = amd_uncore_add,
+ .del = amd_uncore_del,
+ .start = amd_uncore_start,
+ .stop = amd_uncore_stop,
+ .read = amd_uncore_read,
+};
+
+static struct pmu amd_l2_pmu = {
+ .attr_groups = amd_uncore_attr_groups,
+ .name = "amd_l2",
+ .event_init = amd_uncore_event_init,
+ .add = amd_uncore_add,
+ .del = amd_uncore_del,
+ .start = amd_uncore_start,
+ .stop = amd_uncore_stop,
+ .read = amd_uncore_read,
+};
+
+static struct amd_uncore * __cpuinit amd_uncore_alloc(unsigned int cpu)
+{
+ return kzalloc_node(sizeof(struct amd_uncore), GFP_KERNEL,
+ cpu_to_node(cpu));
+}
+
+static void __cpuinit amd_uncore_cpu_up_prepare(unsigned int cpu)
+{
+ struct amd_uncore *uncore;
+
+ if (amd_uncore_nb) {
+ uncore = amd_uncore_alloc(cpu);
+ uncore->cpu = cpu;
+ uncore->num_counters = NUM_COUNTERS_NB;
+ uncore->rdpmc_base = RDPMC_BASE_NB;
+ uncore->msr_base = MSR_F15H_NB_PERF_CTL;
+ uncore->active_mask = &amd_nb_active_mask;
+ uncore->pmu = &amd_nb_pmu;
+ *per_cpu_ptr(amd_uncore_nb, cpu) = uncore;
+ }
+
+ if (amd_uncore_l2) {
+ uncore = amd_uncore_alloc(cpu);
+ uncore->cpu = cpu;
+ uncore->num_counters = NUM_COUNTERS_L2;
+ uncore->rdpmc_base = RDPMC_BASE_L2;
+ uncore->msr_base = MSR_F16H_L2I_PERF_CTL;
+ uncore->active_mask = &amd_l2_active_mask;
+ uncore->pmu = &amd_l2_pmu;
+ *per_cpu_ptr(amd_uncore_l2, cpu) = uncore;
+ }
+}
+
+static struct amd_uncore *
+__cpuinit amd_uncore_find_online_sibling(struct amd_uncore *this,
+ struct amd_uncore * __percpu *uncores)
+{
+ unsigned int cpu;
+ struct amd_uncore *that;
+
+ for_each_online_cpu(cpu) {
+ that = *per_cpu_ptr(uncores, cpu);
+
+ if (!that)
+ continue;
+
+ if (this == that)
+ continue;
+
+ if (this->id == that->id) {
+ that->free_when_cpu_online = this;
+ this = that;
+ break;
+ }
+ }
+
+ this->refcnt++;
+ return this;
+}
+
+static void __cpuinit amd_uncore_cpu_starting(unsigned int cpu)
+{
+ unsigned int eax, ebx, ecx, edx;
+ struct amd_uncore *uncore;
+
+ if (amd_uncore_nb) {
+ uncore = *per_cpu_ptr(amd_uncore_nb, cpu);
+ cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+ uncore->id = ecx & 0xff;
+
+ uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_nb);
+ *per_cpu_ptr(amd_uncore_nb, cpu) = uncore;
+ }
+
+ if (amd_uncore_l2) {
+ unsigned int apicid = cpu_data(cpu).apicid;
+ unsigned int nshared;
+
+ uncore = *per_cpu_ptr(amd_uncore_l2, cpu);
+ cpuid_count(0x8000001d, 2, &eax, &ebx, &ecx, &edx);
+ nshared = ((eax >> 14) & 0xfff) + 1;
+ uncore->id = apicid - (apicid % nshared);
+
+ uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_l2);
+ *per_cpu_ptr(amd_uncore_l2, cpu) = uncore;
+ }
+}
+
+static void __cpuinit uncore_online(unsigned int cpu,
+ struct amd_uncore * __percpu *uncores)
+{
+ struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
+
+ kfree(uncore->free_when_cpu_online);
+ uncore->free_when_cpu_online = NULL;
+
+ if (cpu == uncore->cpu)
+ cpumask_set_cpu(cpu, uncore->active_mask);
+}
+
+static void __cpuinit amd_uncore_cpu_online(unsigned int cpu)
+{
+ if (amd_uncore_nb)
+ uncore_online(cpu, amd_uncore_nb);
+
+ if (amd_uncore_l2)
+ uncore_online(cpu, amd_uncore_l2);
+}
+
+static void __cpuinit uncore_down_prepare(unsigned int cpu,
+ struct amd_uncore * __percpu *uncores)
+{
+ unsigned int i;
+ struct amd_uncore *this = *per_cpu_ptr(uncores, cpu);
+
+ if (this->cpu != cpu)
+ return;
+
+ /* this cpu is going down, migrate to a shared sibling if possible */
+ for_each_online_cpu(i) {
+ struct amd_uncore *that = *per_cpu_ptr(uncores, i);
+
+ if (cpu == i)
+ continue;
+
+ if (this == that) {
+ perf_pmu_migrate_context(this->pmu, cpu, i);
+ cpumask_clear_cpu(cpu, that->active_mask);
+ cpumask_set_cpu(i, that->active_mask);
+ that->cpu = i;
+ break;
+ }
+ }
+}
+
+static void __cpuinit amd_uncore_cpu_down_prepare(unsigned int cpu)
+{
+ if (amd_uncore_nb)
+ uncore_down_prepare(cpu, amd_uncore_nb);
+
+ if (amd_uncore_l2)
+ uncore_down_prepare(cpu, amd_uncore_l2);
+}
+
+static void __cpuinit uncore_dead(unsigned int cpu,
+ struct amd_uncore * __percpu *uncores)
+{
+ struct amd_uncore *uncore = *per_cpu_ptr(uncores, cpu);
+
+ if (cpu == uncore->cpu)
+ cpumask_clear_cpu(cpu, uncore->active_mask);
+
+ if (!--uncore->refcnt)
+ kfree(uncore);
+ *per_cpu_ptr(amd_uncore_nb, cpu) = NULL;
+}
+
+static void __cpuinit amd_uncore_cpu_dead(unsigned int cpu)
+{
+ if (amd_uncore_nb)
+ uncore_dead(cpu, amd_uncore_nb);
+
+ if (amd_uncore_l2)
+ uncore_dead(cpu, amd_uncore_l2);
+}
+
+static int __cpuinit
+amd_uncore_cpu_notifier(struct notifier_block *self, unsigned long action,
+ void *hcpu)
+{
+ unsigned int cpu = (long)hcpu;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_UP_PREPARE:
+ amd_uncore_cpu_up_prepare(cpu);
+ break;
+
+ case CPU_STARTING:
+ amd_uncore_cpu_starting(cpu);
+ break;
+
+ case CPU_ONLINE:
+ amd_uncore_cpu_online(cpu);
+ break;
+
+ case CPU_DOWN_PREPARE:
+ amd_uncore_cpu_down_prepare(cpu);
+ break;
+
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ amd_uncore_cpu_dead(cpu);
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block amd_uncore_cpu_notifier_block __cpuinitdata = {
+ .notifier_call = amd_uncore_cpu_notifier,
+ .priority = CPU_PRI_PERF + 1,
+};
+
+static void __init init_cpu_already_online(void *dummy)
+{
+ unsigned int cpu = smp_processor_id();
+
+ amd_uncore_cpu_starting(cpu);
+ amd_uncore_cpu_online(cpu);
+}
+
+static int __init amd_uncore_init(void)
+{
+ unsigned int cpu;
+ int ret = -ENODEV;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ return -ENODEV;
+
+ if (!cpu_has_topoext)
+ return -ENODEV;
+
+ if (cpu_has_perfctr_nb) {
+ amd_uncore_nb = alloc_percpu(struct amd_uncore *);
+ perf_pmu_register(&amd_nb_pmu, amd_nb_pmu.name, -1);
+
+ printk(KERN_INFO "perf: AMD NB counters detected\n");
+ ret = 0;
+ }
+
+ if (cpu_has_perfctr_l2) {
+ amd_uncore_l2 = alloc_percpu(struct amd_uncore *);
+ perf_pmu_register(&amd_l2_pmu, amd_l2_pmu.name, -1);
+
+ printk(KERN_INFO "perf: AMD L2I counters detected\n");
+ ret = 0;
+ }
+
+ if (ret)
+ return -ENODEV;
+
+ get_online_cpus();
+ /* init cpus already online before registering for hotplug notifier */
+ for_each_online_cpu(cpu) {
+ amd_uncore_cpu_up_prepare(cpu);
+ smp_call_function_single(cpu, init_cpu_already_online, NULL, 1);
+ }
+
+ register_cpu_notifier(&amd_uncore_cpu_notifier_block);
+ put_online_cpus();
+
+ return 0;
+}
+device_initcall(amd_uncore_init);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index dab7580c47ae..ffd6050a1de4 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -81,6 +81,7 @@ static struct event_constraint intel_nehalem_event_constraints[] __read_mostly =
static struct extra_reg intel_nehalem_extra_regs[] __read_mostly =
{
INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
+ INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
EVENT_EXTRA_END
};
@@ -108,6 +109,8 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly =
INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */
INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
+ INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_DISPATCH */
+ INTEL_UEVENT_CONSTRAINT(0x02a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
EVENT_CONSTRAINT_END
};
@@ -136,6 +139,7 @@ static struct extra_reg intel_westmere_extra_regs[] __read_mostly =
{
INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff, RSP_0),
INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff, RSP_1),
+ INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x100b),
EVENT_EXTRA_END
};
@@ -153,11 +157,34 @@ static struct event_constraint intel_gen_event_constraints[] __read_mostly =
};
static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
- INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffffffffull, RSP_0),
- INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffffffffull, RSP_1),
+ INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
+ INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3f807f8fffull, RSP_1),
+ INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
+ INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
+ EVENT_EXTRA_END
+};
+
+static struct extra_reg intel_snbep_extra_regs[] __read_mostly = {
+ INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0x3fffff8fffull, RSP_0),
+ INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0x3fffff8fffull, RSP_1),
EVENT_EXTRA_END
};
+EVENT_ATTR_STR(mem-loads, mem_ld_nhm, "event=0x0b,umask=0x10,ldlat=3");
+EVENT_ATTR_STR(mem-loads, mem_ld_snb, "event=0xcd,umask=0x1,ldlat=3");
+EVENT_ATTR_STR(mem-stores, mem_st_snb, "event=0xcd,umask=0x2");
+
+struct attribute *nhm_events_attrs[] = {
+ EVENT_PTR(mem_ld_nhm),
+ NULL,
+};
+
+struct attribute *snb_events_attrs[] = {
+ EVENT_PTR(mem_ld_snb),
+ EVENT_PTR(mem_st_snb),
+ NULL,
+};
+
static u64 intel_pmu_event_map(int hw_event)
{
return intel_perfmon_event_map[hw_event];
@@ -1392,8 +1419,11 @@ x86_get_event_constraints(struct cpu_hw_events *cpuc, struct perf_event *event)
if (x86_pmu.event_constraints) {
for_each_event_constraint(c, x86_pmu.event_constraints) {
- if ((event->hw.config & c->cmask) == c->code)
+ if ((event->hw.config & c->cmask) == c->code) {
+ /* hw.flags zeroed at initialization */
+ event->hw.flags |= c->flags;
return c;
+ }
}
}
@@ -1438,6 +1468,7 @@ intel_put_shared_regs_event_constraints(struct cpu_hw_events *cpuc,
static void intel_put_event_constraints(struct cpu_hw_events *cpuc,
struct perf_event *event)
{
+ event->hw.flags = 0;
intel_put_shared_regs_event_constraints(cpuc, event);
}
@@ -1761,6 +1792,8 @@ static void intel_pmu_flush_branch_stack(void)
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
+PMU_FORMAT_ATTR(ldlat, "config1:0-15");
+
static struct attribute *intel_arch3_formats_attr[] = {
&format_attr_event.attr,
&format_attr_umask.attr,
@@ -1771,6 +1804,7 @@ static struct attribute *intel_arch3_formats_attr[] = {
&format_attr_cmask.attr,
&format_attr_offcore_rsp.attr, /* XXX do NHM/WSM + SNB breakout */
+ &format_attr_ldlat.attr, /* PEBS load latency */
NULL,
};
@@ -2031,6 +2065,8 @@ __init int intel_pmu_init(void)
x86_pmu.enable_all = intel_pmu_nhm_enable_all;
x86_pmu.extra_regs = intel_nehalem_extra_regs;
+ x86_pmu.cpu_events = nhm_events_attrs;
+
/* UOPS_ISSUED.STALLED_CYCLES */
intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
@@ -2074,6 +2110,8 @@ __init int intel_pmu_init(void)
x86_pmu.extra_regs = intel_westmere_extra_regs;
x86_pmu.er_flags |= ERF_HAS_RSP_1;
+ x86_pmu.cpu_events = nhm_events_attrs;
+
/* UOPS_ISSUED.STALLED_CYCLES */
intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
@@ -2097,11 +2135,16 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_snb_event_constraints;
x86_pmu.pebs_constraints = intel_snb_pebs_event_constraints;
x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
- x86_pmu.extra_regs = intel_snb_extra_regs;
+ if (boot_cpu_data.x86_model == 45)
+ x86_pmu.extra_regs = intel_snbep_extra_regs;
+ else
+ x86_pmu.extra_regs = intel_snb_extra_regs;
/* all extra regs are per-cpu when HT is on */
x86_pmu.er_flags |= ERF_HAS_RSP_1;
x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+ x86_pmu.cpu_events = snb_events_attrs;
+
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
@@ -2123,11 +2166,16 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_ivb_event_constraints;
x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
- x86_pmu.extra_regs = intel_snb_extra_regs;
+ if (boot_cpu_data.x86_model == 62)
+ x86_pmu.extra_regs = intel_snbep_extra_regs;
+ else
+ x86_pmu.extra_regs = intel_snb_extra_regs;
/* all extra regs are per-cpu when HT is on */
x86_pmu.er_flags |= ERF_HAS_RSP_1;
x86_pmu.er_flags |= ERF_NO_HT_SHARING;
+ x86_pmu.cpu_events = snb_events_attrs;
+
/* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] =
X86_CONFIG(.event=0x0e, .umask=0x01, .inv=1, .cmask=1);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index b05a575d56f4..60250f687052 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -24,6 +24,130 @@ struct pebs_record_32 {
*/
+union intel_x86_pebs_dse {
+ u64 val;
+ struct {
+ unsigned int ld_dse:4;
+ unsigned int ld_stlb_miss:1;
+ unsigned int ld_locked:1;
+ unsigned int ld_reserved:26;
+ };
+ struct {
+ unsigned int st_l1d_hit:1;
+ unsigned int st_reserved1:3;
+ unsigned int st_stlb_miss:1;
+ unsigned int st_locked:1;
+ unsigned int st_reserved2:26;
+ };
+};
+
+
+/*
+ * Map PEBS Load Latency Data Source encodings to generic
+ * memory data source information
+ */
+#define P(a, b) PERF_MEM_S(a, b)
+#define OP_LH (P(OP, LOAD) | P(LVL, HIT))
+#define SNOOP_NONE_MISS (P(SNOOP, NONE) | P(SNOOP, MISS))
+
+static const u64 pebs_data_source[] = {
+ P(OP, LOAD) | P(LVL, MISS) | P(LVL, L3) | P(SNOOP, NA),/* 0x00:ukn L3 */
+ OP_LH | P(LVL, L1) | P(SNOOP, NONE), /* 0x01: L1 local */
+ OP_LH | P(LVL, LFB) | P(SNOOP, NONE), /* 0x02: LFB hit */
+ OP_LH | P(LVL, L2) | P(SNOOP, NONE), /* 0x03: L2 hit */
+ OP_LH | P(LVL, L3) | P(SNOOP, NONE), /* 0x04: L3 hit */
+ OP_LH | P(LVL, L3) | P(SNOOP, MISS), /* 0x05: L3 hit, snoop miss */
+ OP_LH | P(LVL, L3) | P(SNOOP, HIT), /* 0x06: L3 hit, snoop hit */
+ OP_LH | P(LVL, L3) | P(SNOOP, HITM), /* 0x07: L3 hit, snoop hitm */
+ OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HIT), /* 0x08: L3 miss snoop hit */
+ OP_LH | P(LVL, REM_CCE1) | P(SNOOP, HITM), /* 0x09: L3 miss snoop hitm*/
+ OP_LH | P(LVL, LOC_RAM) | P(SNOOP, HIT), /* 0x0a: L3 miss, shared */
+ OP_LH | P(LVL, REM_RAM1) | P(SNOOP, HIT), /* 0x0b: L3 miss, shared */
+ OP_LH | P(LVL, LOC_RAM) | SNOOP_NONE_MISS,/* 0x0c: L3 miss, excl */
+ OP_LH | P(LVL, REM_RAM1) | SNOOP_NONE_MISS,/* 0x0d: L3 miss, excl */
+ OP_LH | P(LVL, IO) | P(SNOOP, NONE), /* 0x0e: I/O */
+ OP_LH | P(LVL, UNC) | P(SNOOP, NONE), /* 0x0f: uncached */
+};
+
+static u64 precise_store_data(u64 status)
+{
+ union intel_x86_pebs_dse dse;
+ u64 val = P(OP, STORE) | P(SNOOP, NA) | P(LVL, L1) | P(TLB, L2);
+
+ dse.val = status;
+
+ /*
+ * bit 4: TLB access
+ * 1 = stored missed 2nd level TLB
+ *
+ * so it either hit the walker or the OS
+ * otherwise hit 2nd level TLB
+ */
+ if (dse.st_stlb_miss)
+ val |= P(TLB, MISS);
+ else
+ val |= P(TLB, HIT);
+
+ /*
+ * bit 0: hit L1 data cache
+ * if not set, then all we know is that
+ * it missed L1D
+ */
+ if (dse.st_l1d_hit)
+ val |= P(LVL, HIT);
+ else
+ val |= P(LVL, MISS);
+
+ /*
+ * bit 5: Locked prefix
+ */
+ if (dse.st_locked)
+ val |= P(LOCK, LOCKED);
+
+ return val;
+}
+
+static u64 load_latency_data(u64 status)
+{
+ union intel_x86_pebs_dse dse;
+ u64 val;
+ int model = boot_cpu_data.x86_model;
+ int fam = boot_cpu_data.x86;
+
+ dse.val = status;
+
+ /*
+ * use the mapping table for bit 0-3
+ */
+ val = pebs_data_source[dse.ld_dse];
+
+ /*
+ * Nehalem models do not support TLB, Lock infos
+ */
+ if (fam == 0x6 && (model == 26 || model == 30
+ || model == 31 || model == 46)) {
+ val |= P(TLB, NA) | P(LOCK, NA);
+ return val;
+ }
+ /*
+ * bit 4: TLB access
+ * 0 = did not miss 2nd level TLB
+ * 1 = missed 2nd level TLB
+ */
+ if (dse.ld_stlb_miss)
+ val |= P(TLB, MISS) | P(TLB, L2);
+ else
+ val |= P(TLB, HIT) | P(TLB, L1) | P(TLB, L2);
+
+ /*
+ * bit 5: locked prefix
+ */
+ if (dse.ld_locked)
+ val |= P(LOCK, LOCKED);
+
+ return val;
+}
+
struct pebs_record_core {
u64 flags, ip;
u64 ax, bx, cx, dx;
@@ -314,10 +438,11 @@ int intel_pmu_drain_bts_buffer(void)
if (top <= at)
return 0;
+ memset(&regs, 0, sizeof(regs));
+
ds->bts_index = ds->bts_buffer_base;
perf_sample_data_init(&data, 0, event->hw.last_period);
- regs.ip = 0;
/*
* Prepare a generic sample, i.e. fill in the invariant fields.
@@ -364,7 +489,7 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
};
struct event_constraint intel_nehalem_pebs_event_constraints[] = {
- INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
+ INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */
@@ -379,7 +504,7 @@ struct event_constraint intel_nehalem_pebs_event_constraints[] = {
};
struct event_constraint intel_westmere_pebs_event_constraints[] = {
- INTEL_EVENT_CONSTRAINT(0x0b, 0xf), /* MEM_INST_RETIRED.* */
+ INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */
@@ -399,7 +524,8 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {
INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */
+ INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
+ INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */
INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -413,7 +539,8 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
INTEL_UEVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */
INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.* */
+ INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
+ INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */
INTEL_EVENT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -430,8 +557,10 @@ struct event_constraint *intel_pebs_constraints(struct perf_event *event)
if (x86_pmu.pebs_constraints) {
for_each_event_constraint(c, x86_pmu.pebs_constraints) {
- if ((event->hw.config & c->cmask) == c->code)
+ if ((event->hw.config & c->cmask) == c->code) {
+ event->hw.flags |= c->flags;
return c;
+ }
}
}
@@ -446,6 +575,11 @@ void intel_pmu_pebs_enable(struct perf_event *event)
hwc->config &= ~ARCH_PERFMON_EVENTSEL_INT;
cpuc->pebs_enabled |= 1ULL << hwc->idx;
+
+ if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT)
+ cpuc->pebs_enabled |= 1ULL << (hwc->idx + 32);
+ else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST)
+ cpuc->pebs_enabled |= 1ULL << 63;
}
void intel_pmu_pebs_disable(struct perf_event *event)
@@ -558,20 +692,51 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
struct pt_regs *iregs, void *__pebs)
{
/*
- * We cast to pebs_record_core since that is a subset of
- * both formats and we don't use the other fields in this
- * routine.
+ * We cast to pebs_record_nhm to get the load latency data
+ * if extra_reg MSR_PEBS_LD_LAT_THRESHOLD used
*/
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
- struct pebs_record_core *pebs = __pebs;
+ struct pebs_record_nhm *pebs = __pebs;
struct perf_sample_data data;
struct pt_regs regs;
+ u64 sample_type;
+ int fll, fst;
if (!intel_pmu_save_and_restart(event))
return;
+ fll = event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT;
+ fst = event->hw.flags & PERF_X86_EVENT_PEBS_ST;
+
perf_sample_data_init(&data, 0, event->hw.last_period);
+ data.period = event->hw.last_period;
+ sample_type = event->attr.sample_type;
+
+ /*
+ * if PEBS-LL or PreciseStore
+ */
+ if (fll || fst) {
+ if (sample_type & PERF_SAMPLE_ADDR)
+ data.addr = pebs->dla;
+
+ /*
+ * Use latency for weight (only avail with PEBS-LL)
+ */
+ if (fll && (sample_type & PERF_SAMPLE_WEIGHT))
+ data.weight = pebs->lat;
+
+ /*
+ * data.data_src encodes the data source
+ */
+ if (sample_type & PERF_SAMPLE_DATA_SRC) {
+ if (fll)
+ data.data_src.val = load_latency_data(pebs->dse);
+ else
+ data.data_src.val = precise_store_data(pebs->dse);
+ }
+ }
+
/*
* We use the interrupt regs as a base because the PEBS record
* does not contain a full regs set, specifically it seems to
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index b43200dbfe7e..d0f9e5aa2151 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -17,6 +17,9 @@ static struct event_constraint constraint_fixed =
static struct event_constraint constraint_empty =
EVENT_CONSTRAINT(0, 0, 0);
+#define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \
+ ((1ULL << (n)) - 1)))
+
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
@@ -31,9 +34,13 @@ DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
DEFINE_UNCORE_FORMAT_ATTR(filter_band0, filter_band0, "config1:0-7");
DEFINE_UNCORE_FORMAT_ATTR(filter_band1, filter_band1, "config1:8-15");
DEFINE_UNCORE_FORMAT_ATTR(filter_band2, filter_band2, "config1:16-23");
@@ -110,6 +117,21 @@ static void uncore_put_constraint(struct intel_uncore_box *box, struct perf_even
reg1->alloc = 0;
}
+static u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx)
+{
+ struct intel_uncore_extra_reg *er;
+ unsigned long flags;
+ u64 config;
+
+ er = &box->shared_regs[idx];
+
+ raw_spin_lock_irqsave(&er->lock, flags);
+ config = er->config;
+ raw_spin_unlock_irqrestore(&er->lock, flags);
+
+ return config;
+}
+
/* Sandy Bridge-EP uncore support */
static struct intel_uncore_type snbep_uncore_cbox;
static struct intel_uncore_type snbep_uncore_pcu;
@@ -205,7 +227,7 @@ static void snbep_uncore_msr_enable_event(struct intel_uncore_box *box, struct p
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
if (reg1->idx != EXTRA_REG_NONE)
- wrmsrl(reg1->reg, reg1->config);
+ wrmsrl(reg1->reg, uncore_shared_reg_config(box, 0));
wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
}
@@ -226,29 +248,6 @@ static void snbep_uncore_msr_init_box(struct intel_uncore_box *box)
wrmsrl(msr, SNBEP_PMON_BOX_CTL_INT);
}
-static int snbep_uncore_hw_config(struct intel_uncore_box *box, struct perf_event *event)
-{
- struct hw_perf_event *hwc = &event->hw;
- struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
-
- if (box->pmu->type == &snbep_uncore_cbox) {
- reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
- SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
- reg1->config = event->attr.config1 &
- SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK;
- } else {
- if (box->pmu->type == &snbep_uncore_pcu) {
- reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
- reg1->config = event->attr.config1 & SNBEP_PCU_MSR_PMON_BOX_FILTER_MASK;
- } else {
- return 0;
- }
- }
- reg1->idx = 0;
-
- return 0;
-}
-
static struct attribute *snbep_uncore_formats_attr[] = {
&format_attr_event.attr,
&format_attr_umask.attr,
@@ -345,16 +344,16 @@ static struct attribute_group snbep_uncore_qpi_format_group = {
.attrs = snbep_uncore_qpi_formats_attr,
};
+#define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \
+ .init_box = snbep_uncore_msr_init_box, \
+ .disable_box = snbep_uncore_msr_disable_box, \
+ .enable_box = snbep_uncore_msr_enable_box, \
+ .disable_event = snbep_uncore_msr_disable_event, \
+ .enable_event = snbep_uncore_msr_enable_event, \
+ .read_counter = uncore_msr_read_counter
+
static struct intel_uncore_ops snbep_uncore_msr_ops = {
- .init_box = snbep_uncore_msr_init_box,
- .disable_box = snbep_uncore_msr_disable_box,
- .enable_box = snbep_uncore_msr_enable_box,
- .disable_event = snbep_uncore_msr_disable_event,
- .enable_event = snbep_uncore_msr_enable_event,
- .read_counter = uncore_msr_read_counter,
- .get_constraint = uncore_get_constraint,
- .put_constraint = uncore_put_constraint,
- .hw_config = snbep_uncore_hw_config,
+ SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
};
static struct intel_uncore_ops snbep_uncore_pci_ops = {
@@ -372,6 +371,7 @@ static struct event_constraint snbep_uncore_cbox_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x04, 0x3),
UNCORE_EVENT_CONSTRAINT(0x05, 0x3),
UNCORE_EVENT_CONSTRAINT(0x07, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
UNCORE_EVENT_CONSTRAINT(0x12, 0x3),
UNCORE_EVENT_CONSTRAINT(0x13, 0x3),
@@ -421,6 +421,14 @@ static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x24, 0x3),
UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2a, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2b, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
UNCORE_EVENT_CONSTRAINT(0x30, 0x3),
UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
UNCORE_EVENT_CONSTRAINT(0x32, 0x3),
@@ -428,6 +436,8 @@ static struct event_constraint snbep_uncore_r3qpi_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
EVENT_CONSTRAINT_END
};
@@ -446,6 +456,145 @@ static struct intel_uncore_type snbep_uncore_ubox = {
.format_group = &snbep_uncore_ubox_format_group,
};
+static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
+ SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+ SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x2),
+ EVENT_EXTRA_END
+};
+
+static void snbep_cbox_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+ int i;
+
+ if (uncore_box_is_fake(box))
+ return;
+
+ for (i = 0; i < 5; i++) {
+ if (reg1->alloc & (0x1 << i))
+ atomic_sub(1 << (i * 6), &er->ref);
+ }
+ reg1->alloc = 0;
+}
+
+static struct event_constraint *
+__snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event,
+ u64 (*cbox_filter_mask)(int fields))
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+ int i, alloc = 0;
+ unsigned long flags;
+ u64 mask;
+
+ if (reg1->idx == EXTRA_REG_NONE)
+ return NULL;
+
+ raw_spin_lock_irqsave(&er->lock, flags);
+ for (i = 0; i < 5; i++) {
+ if (!(reg1->idx & (0x1 << i)))
+ continue;
+ if (!uncore_box_is_fake(box) && (reg1->alloc & (0x1 << i)))
+ continue;
+
+ mask = cbox_filter_mask(0x1 << i);
+ if (!__BITS_VALUE(atomic_read(&er->ref), i, 6) ||
+ !((reg1->config ^ er->config) & mask)) {
+ atomic_add(1 << (i * 6), &er->ref);
+ er->config &= ~mask;
+ er->config |= reg1->config & mask;
+ alloc |= (0x1 << i);
+ } else {
+ break;
+ }
+ }
+ raw_spin_unlock_irqrestore(&er->lock, flags);
+ if (i < 5)
+ goto fail;
+
+ if (!uncore_box_is_fake(box))
+ reg1->alloc |= alloc;
+
+ return 0;
+fail:
+ for (; i >= 0; i--) {
+ if (alloc & (0x1 << i))
+ atomic_sub(1 << (i * 6), &er->ref);
+ }
+ return &constraint_empty;
+}
+
+static u64 snbep_cbox_filter_mask(int fields)
+{
+ u64 mask = 0;
+
+ if (fields & 0x1)
+ mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_TID;
+ if (fields & 0x2)
+ mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_NID;
+ if (fields & 0x4)
+ mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE;
+ if (fields & 0x8)
+ mask |= SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC;
+
+ return mask;
+}
+
+static struct event_constraint *
+snbep_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ return __snbep_cbox_get_constraint(box, event, snbep_cbox_filter_mask);
+}
+
+static int snbep_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct extra_reg *er;
+ int idx = 0;
+
+ for (er = snbep_uncore_cbox_extra_regs; er->msr; er++) {
+ if (er->event != (event->hw.config & er->config_mask))
+ continue;
+ idx |= er->idx;
+ }
+
+ if (idx) {
+ reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+ SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+ reg1->config = event->attr.config1 & snbep_cbox_filter_mask(idx);
+ reg1->idx = idx;
+ }
+ return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_cbox_ops = {
+ SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+ .hw_config = snbep_cbox_hw_config,
+ .get_constraint = snbep_cbox_get_constraint,
+ .put_constraint = snbep_cbox_put_constraint,
+};
+
static struct intel_uncore_type snbep_uncore_cbox = {
.name = "cbox",
.num_counters = 4,
@@ -458,10 +607,104 @@ static struct intel_uncore_type snbep_uncore_cbox = {
.msr_offset = SNBEP_CBO_MSR_OFFSET,
.num_shared_regs = 1,
.constraints = snbep_uncore_cbox_constraints,
- .ops = &snbep_uncore_msr_ops,
+ .ops = &snbep_uncore_cbox_ops,
.format_group = &snbep_uncore_cbox_format_group,
};
+static u64 snbep_pcu_alter_er(struct perf_event *event, int new_idx, bool modify)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+ u64 config = reg1->config;
+
+ if (new_idx > reg1->idx)
+ config <<= 8 * (new_idx - reg1->idx);
+ else
+ config >>= 8 * (reg1->idx - new_idx);
+
+ if (modify) {
+ hwc->config += new_idx - reg1->idx;
+ reg1->config = config;
+ reg1->idx = new_idx;
+ }
+ return config;
+}
+
+static struct event_constraint *
+snbep_pcu_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+ unsigned long flags;
+ int idx = reg1->idx;
+ u64 mask, config1 = reg1->config;
+ bool ok = false;
+
+ if (reg1->idx == EXTRA_REG_NONE ||
+ (!uncore_box_is_fake(box) && reg1->alloc))
+ return NULL;
+again:
+ mask = 0xff << (idx * 8);
+ raw_spin_lock_irqsave(&er->lock, flags);
+ if (!__BITS_VALUE(atomic_read(&er->ref), idx, 8) ||
+ !((config1 ^ er->config) & mask)) {
+ atomic_add(1 << (idx * 8), &er->ref);
+ er->config &= ~mask;
+ er->config |= config1 & mask;
+ ok = true;
+ }
+ raw_spin_unlock_irqrestore(&er->lock, flags);
+
+ if (!ok) {
+ idx = (idx + 1) % 4;
+ if (idx != reg1->idx) {
+ config1 = snbep_pcu_alter_er(event, idx, false);
+ goto again;
+ }
+ return &constraint_empty;
+ }
+
+ if (!uncore_box_is_fake(box)) {
+ if (idx != reg1->idx)
+ snbep_pcu_alter_er(event, idx, true);
+ reg1->alloc = 1;
+ }
+ return NULL;
+}
+
+static void snbep_pcu_put_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct intel_uncore_extra_reg *er = &box->shared_regs[0];
+
+ if (uncore_box_is_fake(box) || !reg1->alloc)
+ return;
+
+ atomic_sub(1 << (reg1->idx * 8), &er->ref);
+ reg1->alloc = 0;
+}
+
+static int snbep_pcu_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+ int ev_sel = hwc->config & SNBEP_PMON_CTL_EV_SEL_MASK;
+
+ if (ev_sel >= 0xb && ev_sel <= 0xe) {
+ reg1->reg = SNBEP_PCU_MSR_PMON_BOX_FILTER;
+ reg1->idx = ev_sel - 0xb;
+ reg1->config = event->attr.config1 & (0xff << reg1->idx);
+ }
+ return 0;
+}
+
+static struct intel_uncore_ops snbep_uncore_pcu_ops = {
+ SNBEP_UNCORE_MSR_OPS_COMMON_INIT(),
+ .hw_config = snbep_pcu_hw_config,
+ .get_constraint = snbep_pcu_get_constraint,
+ .put_constraint = snbep_pcu_put_constraint,
+};
+
static struct intel_uncore_type snbep_uncore_pcu = {
.name = "pcu",
.num_counters = 4,
@@ -472,7 +715,7 @@ static struct intel_uncore_type snbep_uncore_pcu = {
.event_mask = SNBEP_PCU_MSR_PMON_RAW_EVENT_MASK,
.box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL,
.num_shared_regs = 1,
- .ops = &snbep_uncore_msr_ops,
+ .ops = &snbep_uncore_pcu_ops,
.format_group = &snbep_uncore_pcu_format_group,
};
@@ -544,55 +787,63 @@ static struct intel_uncore_type snbep_uncore_r3qpi = {
SNBEP_UNCORE_PCI_COMMON_INIT(),
};
+enum {
+ SNBEP_PCI_UNCORE_HA,
+ SNBEP_PCI_UNCORE_IMC,
+ SNBEP_PCI_UNCORE_QPI,
+ SNBEP_PCI_UNCORE_R2PCIE,
+ SNBEP_PCI_UNCORE_R3QPI,
+};
+
static struct intel_uncore_type *snbep_pci_uncores[] = {
- &snbep_uncore_ha,
- &snbep_uncore_imc,
- &snbep_uncore_qpi,
- &snbep_uncore_r2pcie,
- &snbep_uncore_r3qpi,
+ [SNBEP_PCI_UNCORE_HA] = &snbep_uncore_ha,
+ [SNBEP_PCI_UNCORE_IMC] = &snbep_uncore_imc,
+ [SNBEP_PCI_UNCORE_QPI] = &snbep_uncore_qpi,
+ [SNBEP_PCI_UNCORE_R2PCIE] = &snbep_uncore_r2pcie,
+ [SNBEP_PCI_UNCORE_R3QPI] = &snbep_uncore_r3qpi,
NULL,
};
static DEFINE_PCI_DEVICE_TABLE(snbep_uncore_pci_ids) = {
{ /* Home Agent */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_HA),
- .driver_data = (unsigned long)&snbep_uncore_ha,
+ .driver_data = SNBEP_PCI_UNCORE_HA,
},
{ /* MC Channel 0 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC0),
- .driver_data = (unsigned long)&snbep_uncore_imc,
+ .driver_data = SNBEP_PCI_UNCORE_IMC,
},
{ /* MC Channel 1 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC1),
- .driver_data = (unsigned long)&snbep_uncore_imc,
+ .driver_data = SNBEP_PCI_UNCORE_IMC,
},
{ /* MC Channel 2 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC2),
- .driver_data = (unsigned long)&snbep_uncore_imc,
+ .driver_data = SNBEP_PCI_UNCORE_IMC,
},
{ /* MC Channel 3 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_IMC3),
- .driver_data = (unsigned long)&snbep_uncore_imc,
+ .driver_data = SNBEP_PCI_UNCORE_IMC,
},
{ /* QPI Port 0 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI0),
- .driver_data = (unsigned long)&snbep_uncore_qpi,
+ .driver_data = SNBEP_PCI_UNCORE_QPI,
},
{ /* QPI Port 1 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_QPI1),
- .driver_data = (unsigned long)&snbep_uncore_qpi,
+ .driver_data = SNBEP_PCI_UNCORE_QPI,
},
- { /* P2PCIe */
+ { /* R2PCIe */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R2PCIE),
- .driver_data = (unsigned long)&snbep_uncore_r2pcie,
+ .driver_data = SNBEP_PCI_UNCORE_R2PCIE,
},
{ /* R3QPI Link 0 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI0),
- .driver_data = (unsigned long)&snbep_uncore_r3qpi,
+ .driver_data = SNBEP_PCI_UNCORE_R3QPI,
},
{ /* R3QPI Link 1 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_UNC_R3QPI1),
- .driver_data = (unsigned long)&snbep_uncore_r3qpi,
+ .driver_data = SNBEP_PCI_UNCORE_R3QPI,
},
{ /* end: all zeroes */ }
};
@@ -605,7 +856,7 @@ static struct pci_driver snbep_uncore_pci_driver = {
/*
* build pci bus to socket mapping
*/
-static int snbep_pci2phy_map_init(void)
+static int snbep_pci2phy_map_init(int devid)
{
struct pci_dev *ubox_dev = NULL;
int i, bus, nodeid;
@@ -614,9 +865,7 @@ static int snbep_pci2phy_map_init(void)
while (1) {
/* find the UBOX device */
- ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX,
- ubox_dev);
+ ubox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, ubox_dev);
if (!ubox_dev)
break;
bus = ubox_dev->bus->number;
@@ -639,7 +888,7 @@ static int snbep_pci2phy_map_init(void)
break;
}
}
- };
+ }
if (ubox_dev)
pci_dev_put(ubox_dev);
@@ -648,6 +897,440 @@ static int snbep_pci2phy_map_init(void)
}
/* end of Sandy Bridge-EP uncore support */
+/* IvyTown uncore support */
+static void ivt_uncore_msr_init_box(struct intel_uncore_box *box)
+{
+ unsigned msr = uncore_msr_box_ctl(box);
+ if (msr)
+ wrmsrl(msr, IVT_PMON_BOX_CTL_INT);
+}
+
+static void ivt_uncore_pci_init_box(struct intel_uncore_box *box)
+{
+ struct pci_dev *pdev = box->pci_dev;
+
+ pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, IVT_PMON_BOX_CTL_INT);
+}
+
+#define IVT_UNCORE_MSR_OPS_COMMON_INIT() \
+ .init_box = ivt_uncore_msr_init_box, \
+ .disable_box = snbep_uncore_msr_disable_box, \
+ .enable_box = snbep_uncore_msr_enable_box, \
+ .disable_event = snbep_uncore_msr_disable_event, \
+ .enable_event = snbep_uncore_msr_enable_event, \
+ .read_counter = uncore_msr_read_counter
+
+static struct intel_uncore_ops ivt_uncore_msr_ops = {
+ IVT_UNCORE_MSR_OPS_COMMON_INIT(),
+};
+
+static struct intel_uncore_ops ivt_uncore_pci_ops = {
+ .init_box = ivt_uncore_pci_init_box,
+ .disable_box = snbep_uncore_pci_disable_box,
+ .enable_box = snbep_uncore_pci_enable_box,
+ .disable_event = snbep_uncore_pci_disable_event,
+ .enable_event = snbep_uncore_pci_enable_event,
+ .read_counter = snbep_uncore_pci_read_counter,
+};
+
+#define IVT_UNCORE_PCI_COMMON_INIT() \
+ .perf_ctr = SNBEP_PCI_PMON_CTR0, \
+ .event_ctl = SNBEP_PCI_PMON_CTL0, \
+ .event_mask = IVT_PMON_RAW_EVENT_MASK, \
+ .box_ctl = SNBEP_PCI_PMON_BOX_CTL, \
+ .ops = &ivt_uncore_pci_ops, \
+ .format_group = &ivt_uncore_format_group
+
+static struct attribute *ivt_uncore_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_edge.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh8.attr,
+ NULL,
+};
+
+static struct attribute *ivt_uncore_ubox_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_edge.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh5.attr,
+ NULL,
+};
+
+static struct attribute *ivt_uncore_cbox_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_edge.attr,
+ &format_attr_tid_en.attr,
+ &format_attr_thresh8.attr,
+ &format_attr_filter_tid.attr,
+ &format_attr_filter_link.attr,
+ &format_attr_filter_state2.attr,
+ &format_attr_filter_nid2.attr,
+ &format_attr_filter_opc2.attr,
+ NULL,
+};
+
+static struct attribute *ivt_uncore_pcu_formats_attr[] = {
+ &format_attr_event_ext.attr,
+ &format_attr_occ_sel.attr,
+ &format_attr_edge.attr,
+ &format_attr_thresh5.attr,
+ &format_attr_occ_invert.attr,
+ &format_attr_occ_edge.attr,
+ &format_attr_filter_band0.attr,
+ &format_attr_filter_band1.attr,
+ &format_attr_filter_band2.attr,
+ &format_attr_filter_band3.attr,
+ NULL,
+};
+
+static struct attribute *ivt_uncore_qpi_formats_attr[] = {
+ &format_attr_event_ext.attr,
+ &format_attr_umask.attr,
+ &format_attr_edge.attr,
+ &format_attr_thresh8.attr,
+ NULL,
+};
+
+static struct attribute_group ivt_uncore_format_group = {
+ .name = "format",
+ .attrs = ivt_uncore_formats_attr,
+};
+
+static struct attribute_group ivt_uncore_ubox_format_group = {
+ .name = "format",
+ .attrs = ivt_uncore_ubox_formats_attr,
+};
+
+static struct attribute_group ivt_uncore_cbox_format_group = {
+ .name = "format",
+ .attrs = ivt_uncore_cbox_formats_attr,
+};
+
+static struct attribute_group ivt_uncore_pcu_format_group = {
+ .name = "format",
+ .attrs = ivt_uncore_pcu_formats_attr,
+};
+
+static struct attribute_group ivt_uncore_qpi_format_group = {
+ .name = "format",
+ .attrs = ivt_uncore_qpi_formats_attr,
+};
+
+static struct intel_uncore_type ivt_uncore_ubox = {
+ .name = "ubox",
+ .num_counters = 2,
+ .num_boxes = 1,
+ .perf_ctr_bits = 44,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = SNBEP_U_MSR_PMON_CTR0,
+ .event_ctl = SNBEP_U_MSR_PMON_CTL0,
+ .event_mask = IVT_U_MSR_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = SNBEP_U_MSR_PMON_UCLK_FIXED_CTR,
+ .fixed_ctl = SNBEP_U_MSR_PMON_UCLK_FIXED_CTL,
+ .ops = &ivt_uncore_msr_ops,
+ .format_group = &ivt_uncore_ubox_format_group,
+};
+
+static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
+ SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+ SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x2335, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4135, 0xffff, 0x18),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4335, 0xffff, 0x18),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4435, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4835, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4a35, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x5035, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x8135, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x8335, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0136, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x0336, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x2336, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4136, 0xffff, 0x18),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4336, 0xffff, 0x18),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4436, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4836, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4a36, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x5036, 0xffff, 0x8),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x8136, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x8336, 0xffff, 0x10),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x4037, 0x40ff, 0x8),
+ EVENT_EXTRA_END
+};
+
+static u64 ivt_cbox_filter_mask(int fields)
+{
+ u64 mask = 0;
+
+ if (fields & 0x1)
+ mask |= IVT_CB0_MSR_PMON_BOX_FILTER_TID;
+ if (fields & 0x2)
+ mask |= IVT_CB0_MSR_PMON_BOX_FILTER_LINK;
+ if (fields & 0x4)
+ mask |= IVT_CB0_MSR_PMON_BOX_FILTER_STATE;
+ if (fields & 0x8)
+ mask |= IVT_CB0_MSR_PMON_BOX_FILTER_NID;
+ if (fields & 0x10)
+ mask |= IVT_CB0_MSR_PMON_BOX_FILTER_OPC;
+
+ return mask;
+}
+
+static struct event_constraint *
+ivt_cbox_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ return __snbep_cbox_get_constraint(box, event, ivt_cbox_filter_mask);
+}
+
+static int ivt_cbox_hw_config(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct extra_reg *er;
+ int idx = 0;
+
+ for (er = ivt_uncore_cbox_extra_regs; er->msr; er++) {
+ if (er->event != (event->hw.config & er->config_mask))
+ continue;
+ idx |= er->idx;
+ }
+
+ if (idx) {
+ reg1->reg = SNBEP_C0_MSR_PMON_BOX_FILTER +
+ SNBEP_CBO_MSR_OFFSET * box->pmu->pmu_idx;
+ reg1->config = event->attr.config1 & ivt_cbox_filter_mask(idx);
+ reg1->idx = idx;
+ }
+ return 0;
+}
+
+static void ivt_cbox_enable_event(struct intel_uncore_box *box, struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
+
+ if (reg1->idx != EXTRA_REG_NONE) {
+ u64 filter = uncore_shared_reg_config(box, 0);
+ wrmsrl(reg1->reg, filter & 0xffffffff);
+ wrmsrl(reg1->reg + 6, filter >> 32);
+ }
+
+ wrmsrl(hwc->config_base, hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops ivt_uncore_cbox_ops = {
+ .init_box = ivt_uncore_msr_init_box,
+ .disable_box = snbep_uncore_msr_disable_box,
+ .enable_box = snbep_uncore_msr_enable_box,
+ .disable_event = snbep_uncore_msr_disable_event,
+ .enable_event = ivt_cbox_enable_event,
+ .read_counter = uncore_msr_read_counter,
+ .hw_config = ivt_cbox_hw_config,
+ .get_constraint = ivt_cbox_get_constraint,
+ .put_constraint = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type ivt_uncore_cbox = {
+ .name = "cbox",
+ .num_counters = 4,
+ .num_boxes = 15,
+ .perf_ctr_bits = 44,
+ .event_ctl = SNBEP_C0_MSR_PMON_CTL0,
+ .perf_ctr = SNBEP_C0_MSR_PMON_CTR0,
+ .event_mask = IVT_CBO_MSR_PMON_RAW_EVENT_MASK,
+ .box_ctl = SNBEP_C0_MSR_PMON_BOX_CTL,
+ .msr_offset = SNBEP_CBO_MSR_OFFSET,
+ .num_shared_regs = 1,
+ .constraints = snbep_uncore_cbox_constraints,
+ .ops = &ivt_uncore_cbox_ops,
+ .format_group = &ivt_uncore_cbox_format_group,
+};
+
+static struct intel_uncore_ops ivt_uncore_pcu_ops = {
+ IVT_UNCORE_MSR_OPS_COMMON_INIT(),
+ .hw_config = snbep_pcu_hw_config,
+ .get_constraint = snbep_pcu_get_constraint,
+ .put_constraint = snbep_pcu_put_constraint,
+};
+
+static struct intel_uncore_type ivt_uncore_pcu = {
+ .name = "pcu",
+ .num_counters = 4,
+ .num_boxes = 1,
+ .perf_ctr_bits = 48,
+ .perf_ctr = SNBEP_PCU_MSR_PMON_CTR0,
+ .event_ctl = SNBEP_PCU_MSR_PMON_CTL0,
+ .event_mask = IVT_PCU_MSR_PMON_RAW_EVENT_MASK,
+ .box_ctl = SNBEP_PCU_MSR_PMON_BOX_CTL,
+ .num_shared_regs = 1,
+ .ops = &ivt_uncore_pcu_ops,
+ .format_group = &ivt_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *ivt_msr_uncores[] = {
+ &ivt_uncore_ubox,
+ &ivt_uncore_cbox,
+ &ivt_uncore_pcu,
+ NULL,
+};
+
+static struct intel_uncore_type ivt_uncore_ha = {
+ .name = "ha",
+ .num_counters = 4,
+ .num_boxes = 2,
+ .perf_ctr_bits = 48,
+ IVT_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivt_uncore_imc = {
+ .name = "imc",
+ .num_counters = 4,
+ .num_boxes = 8,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
+ .fixed_ctl = SNBEP_MC_CHy_PCI_PMON_FIXED_CTL,
+ IVT_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivt_uncore_qpi = {
+ .name = "qpi",
+ .num_counters = 4,
+ .num_boxes = 3,
+ .perf_ctr_bits = 48,
+ .perf_ctr = SNBEP_PCI_PMON_CTR0,
+ .event_ctl = SNBEP_PCI_PMON_CTL0,
+ .event_mask = IVT_QPI_PCI_PMON_RAW_EVENT_MASK,
+ .box_ctl = SNBEP_PCI_PMON_BOX_CTL,
+ .ops = &ivt_uncore_pci_ops,
+ .format_group = &ivt_uncore_qpi_format_group,
+};
+
+static struct intel_uncore_type ivt_uncore_r2pcie = {
+ .name = "r2pcie",
+ .num_counters = 4,
+ .num_boxes = 1,
+ .perf_ctr_bits = 44,
+ .constraints = snbep_uncore_r2pcie_constraints,
+ IVT_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct intel_uncore_type ivt_uncore_r3qpi = {
+ .name = "r3qpi",
+ .num_counters = 3,
+ .num_boxes = 2,
+ .perf_ctr_bits = 44,
+ .constraints = snbep_uncore_r3qpi_constraints,
+ IVT_UNCORE_PCI_COMMON_INIT(),
+};
+
+enum {
+ IVT_PCI_UNCORE_HA,
+ IVT_PCI_UNCORE_IMC,
+ IVT_PCI_UNCORE_QPI,
+ IVT_PCI_UNCORE_R2PCIE,
+ IVT_PCI_UNCORE_R3QPI,
+};
+
+static struct intel_uncore_type *ivt_pci_uncores[] = {
+ [IVT_PCI_UNCORE_HA] = &ivt_uncore_ha,
+ [IVT_PCI_UNCORE_IMC] = &ivt_uncore_imc,
+ [IVT_PCI_UNCORE_QPI] = &ivt_uncore_qpi,
+ [IVT_PCI_UNCORE_R2PCIE] = &ivt_uncore_r2pcie,
+ [IVT_PCI_UNCORE_R3QPI] = &ivt_uncore_r3qpi,
+ NULL,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ivt_uncore_pci_ids) = {
+ { /* Home Agent 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe30),
+ .driver_data = IVT_PCI_UNCORE_HA,
+ },
+ { /* Home Agent 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe38),
+ .driver_data = IVT_PCI_UNCORE_HA,
+ },
+ { /* MC0 Channel 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb4),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC0 Channel 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb5),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC0 Channel 3 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb0),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC0 Channel 4 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xeb1),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC1 Channel 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef4),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC1 Channel 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef5),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC1 Channel 3 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef0),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* MC1 Channel 4 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xef1),
+ .driver_data = IVT_PCI_UNCORE_IMC,
+ },
+ { /* QPI0 Port 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe32),
+ .driver_data = IVT_PCI_UNCORE_QPI,
+ },
+ { /* QPI0 Port 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe33),
+ .driver_data = IVT_PCI_UNCORE_QPI,
+ },
+ { /* QPI1 Port 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3a),
+ .driver_data = IVT_PCI_UNCORE_QPI,
+ },
+ { /* R2PCIe */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe34),
+ .driver_data = IVT_PCI_UNCORE_R2PCIE,
+ },
+ { /* R3QPI0 Link 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe36),
+ .driver_data = IVT_PCI_UNCORE_R3QPI,
+ },
+ { /* R3QPI0 Link 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe37),
+ .driver_data = IVT_PCI_UNCORE_R3QPI,
+ },
+ { /* R3QPI1 Link 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe3e),
+ .driver_data = IVT_PCI_UNCORE_R3QPI,
+ },
+ { /* end: all zeroes */ }
+};
+
+static struct pci_driver ivt_uncore_pci_driver = {
+ .name = "ivt_uncore",
+ .id_table = ivt_uncore_pci_ids,
+};
+/* end of IvyTown uncore support */
+
/* Sandy Bridge uncore support */
static void snb_uncore_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
{
@@ -808,9 +1491,6 @@ static struct intel_uncore_type *nhm_msr_uncores[] = {
/* end of Nehalem uncore support */
/* Nehalem-EX uncore support */
-#define __BITS_VALUE(x, i, n) ((typeof(x))(((x) >> ((i) * (n))) & \
- ((1ULL << (n)) - 1)))
-
DEFINE_UNCORE_FORMAT_ATTR(event5, event, "config:1-5");
DEFINE_UNCORE_FORMAT_ATTR(counter, counter, "config:6-7");
DEFINE_UNCORE_FORMAT_ATTR(match, match, "config1:0-63");
@@ -1161,7 +1841,7 @@ static struct extra_reg nhmex_uncore_mbox_extra_regs[] = {
};
/* Nehalem-EX or Westmere-EX ? */
-bool uncore_nhmex;
+static bool uncore_nhmex;
static bool nhmex_mbox_get_shared_reg(struct intel_uncore_box *box, int idx, u64 config)
{
@@ -1239,7 +1919,7 @@ static void nhmex_mbox_put_shared_reg(struct intel_uncore_box *box, int idx)
atomic_sub(1 << (idx * 8), &er->ref);
}
-u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
+static u64 nhmex_mbox_alter_er(struct perf_event *event, int new_idx, bool modify)
{
struct hw_perf_event *hwc = &event->hw;
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
@@ -1554,7 +2234,7 @@ static struct intel_uncore_type nhmex_uncore_mbox = {
.format_group = &nhmex_uncore_mbox_format_group,
};
-void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
+static void nhmex_rbox_alter_er(struct intel_uncore_box *box, struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
struct hw_perf_event_extra *reg1 = &hwc->extra_reg;
@@ -1724,21 +2404,6 @@ static int nhmex_rbox_hw_config(struct intel_uncore_box *box, struct perf_event
return 0;
}
-static u64 nhmex_rbox_shared_reg_config(struct intel_uncore_box *box, int idx)
-{
- struct intel_uncore_extra_reg *er;
- unsigned long flags;
- u64 config;
-
- er = &box->shared_regs[idx];
-
- raw_spin_lock_irqsave(&er->lock, flags);
- config = er->config;
- raw_spin_unlock_irqrestore(&er->lock, flags);
-
- return config;
-}
-
static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
@@ -1759,7 +2424,7 @@ static void nhmex_rbox_msr_enable_event(struct intel_uncore_box *box, struct per
case 2:
case 3:
wrmsrl(NHMEX_R_MSR_PORTN_QLX_CFG(port),
- nhmex_rbox_shared_reg_config(box, 2 + (idx / 6) * 5));
+ uncore_shared_reg_config(box, 2 + (idx / 6) * 5));
break;
case 4:
wrmsrl(NHMEX_R_MSR_PORTN_XBR_SET1_MM_CFG(port),
@@ -2285,7 +2950,7 @@ out:
return ret;
}
-int uncore_pmu_event_init(struct perf_event *event)
+static int uncore_pmu_event_init(struct perf_event *event)
{
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
@@ -2438,7 +3103,7 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
type->unconstrainted = (struct event_constraint)
__EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
- 0, type->num_counters, 0);
+ 0, type->num_counters, 0, 0);
for (i = 0; i < type->num_boxes; i++) {
pmus[i].func_id = -1;
@@ -2556,6 +3221,8 @@ static void uncore_pci_remove(struct pci_dev *pdev)
if (WARN_ON_ONCE(phys_id != box->phys_id))
return;
+ pci_set_drvdata(pdev, NULL);
+
raw_spin_lock(&uncore_box_lock);
list_del(&box->list);
raw_spin_unlock(&uncore_box_lock);
@@ -2574,11 +3241,7 @@ static void uncore_pci_remove(struct pci_dev *pdev)
static int uncore_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- struct intel_uncore_type *type;
-
- type = (struct intel_uncore_type *)id->driver_data;
-
- return uncore_pci_add(type, pdev);
+ return uncore_pci_add(pci_uncores[id->driver_data], pdev);
}
static int __init uncore_pci_init(void)
@@ -2587,12 +3250,19 @@ static int __init uncore_pci_init(void)
switch (boot_cpu_data.x86_model) {
case 45: /* Sandy Bridge-EP */
- ret = snbep_pci2phy_map_init();
+ ret = snbep_pci2phy_map_init(0x3ce0);
if (ret)
return ret;
pci_uncores = snbep_pci_uncores;
uncore_pci_driver = &snbep_uncore_pci_driver;
break;
+ case 62: /* IvyTown */
+ ret = snbep_pci2phy_map_init(0x0e1e);
+ if (ret)
+ return ret;
+ pci_uncores = ivt_pci_uncores;
+ uncore_pci_driver = &ivt_uncore_pci_driver;
+ break;
default:
return 0;
}
@@ -2622,6 +3292,21 @@ static void __init uncore_pci_exit(void)
}
}
+/* CPU hot plug/unplug are serialized by cpu_add_remove_lock mutex */
+static LIST_HEAD(boxes_to_free);
+
+static void __cpuinit uncore_kfree_boxes(void)
+{
+ struct intel_uncore_box *box;
+
+ while (!list_empty(&boxes_to_free)) {
+ box = list_entry(boxes_to_free.next,
+ struct intel_uncore_box, list);
+ list_del(&box->list);
+ kfree(box);
+ }
+}
+
static void __cpuinit uncore_cpu_dying(int cpu)
{
struct intel_uncore_type *type;
@@ -2636,7 +3321,7 @@ static void __cpuinit uncore_cpu_dying(int cpu)
box = *per_cpu_ptr(pmu->box, cpu);
*per_cpu_ptr(pmu->box, cpu) = NULL;
if (box && atomic_dec_and_test(&box->refcnt))
- kfree(box);
+ list_add(&box->list, &boxes_to_free);
}
}
}
@@ -2666,8 +3351,11 @@ static int __cpuinit uncore_cpu_starting(int cpu)
if (exist && exist->phys_id == phys_id) {
atomic_inc(&exist->refcnt);
*per_cpu_ptr(pmu->box, cpu) = exist;
- kfree(box);
- box = NULL;
+ if (box) {
+ list_add(&box->list,
+ &boxes_to_free);
+ box = NULL;
+ }
break;
}
}
@@ -2806,6 +3494,10 @@ static int
case CPU_DYING:
uncore_cpu_dying(cpu);
break;
+ case CPU_ONLINE:
+ case CPU_DEAD:
+ uncore_kfree_boxes();
+ break;
default:
break;
}
@@ -2871,6 +3563,12 @@ static int __init uncore_cpu_init(void)
nhmex_uncore_cbox.num_boxes = max_cores;
msr_uncores = nhmex_msr_uncores;
break;
+ case 62: /* IvyTown */
+ if (ivt_uncore_cbox.num_boxes > max_cores)
+ ivt_uncore_cbox.num_boxes = max_cores;
+ msr_uncores = ivt_msr_uncores;
+ break;
+
default:
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index e68a4550e952..f9528917f6e8 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -76,7 +76,7 @@
#define SNBEP_PMON_CTL_UMASK_MASK 0x0000ff00
#define SNBEP_PMON_CTL_RST (1 << 17)
#define SNBEP_PMON_CTL_EDGE_DET (1 << 18)
-#define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21) /* only for QPI */
+#define SNBEP_PMON_CTL_EV_SEL_EXT (1 << 21)
#define SNBEP_PMON_CTL_EN (1 << 22)
#define SNBEP_PMON_CTL_INVERT (1 << 23)
#define SNBEP_PMON_CTL_TRESH_MASK 0xff000000
@@ -148,9 +148,20 @@
#define SNBEP_C0_MSR_PMON_CTL0 0xd10
#define SNBEP_C0_MSR_PMON_BOX_CTL 0xd04
#define SNBEP_C0_MSR_PMON_BOX_FILTER 0xd14
-#define SNBEP_CB0_MSR_PMON_BOX_FILTER_MASK 0xfffffc1f
#define SNBEP_CBO_MSR_OFFSET 0x20
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_TID 0x1f
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_NID 0x3fc00
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_STATE 0x7c0000
+#define SNBEP_CB0_MSR_PMON_BOX_FILTER_OPC 0xff800000
+
+#define SNBEP_CBO_EVENT_EXTRA_REG(e, m, i) { \
+ .event = (e), \
+ .msr = SNBEP_C0_MSR_PMON_BOX_FILTER, \
+ .config_mask = (m), \
+ .idx = (i) \
+}
+
/* SNB-EP PCU register */
#define SNBEP_PCU_MSR_PMON_CTR0 0xc36
#define SNBEP_PCU_MSR_PMON_CTL0 0xc30
@@ -160,6 +171,55 @@
#define SNBEP_PCU_MSR_CORE_C3_CTR 0x3fc
#define SNBEP_PCU_MSR_CORE_C6_CTR 0x3fd
+/* IVT event control */
+#define IVT_PMON_BOX_CTL_INT (SNBEP_PMON_BOX_CTL_RST_CTRL | \
+ SNBEP_PMON_BOX_CTL_RST_CTRS)
+#define IVT_PMON_RAW_EVENT_MASK (SNBEP_PMON_CTL_EV_SEL_MASK | \
+ SNBEP_PMON_CTL_UMASK_MASK | \
+ SNBEP_PMON_CTL_EDGE_DET | \
+ SNBEP_PMON_CTL_TRESH_MASK)
+/* IVT Ubox */
+#define IVT_U_MSR_PMON_GLOBAL_CTL 0xc00
+#define IVT_U_PMON_GLOBAL_FRZ_ALL (1 << 31)
+#define IVT_U_PMON_GLOBAL_UNFRZ_ALL (1 << 29)
+
+#define IVT_U_MSR_PMON_RAW_EVENT_MASK \
+ (SNBEP_PMON_CTL_EV_SEL_MASK | \
+ SNBEP_PMON_CTL_UMASK_MASK | \
+ SNBEP_PMON_CTL_EDGE_DET | \
+ SNBEP_U_MSR_PMON_CTL_TRESH_MASK)
+/* IVT Cbo */
+#define IVT_CBO_MSR_PMON_RAW_EVENT_MASK (IVT_PMON_RAW_EVENT_MASK | \
+ SNBEP_CBO_PMON_CTL_TID_EN)
+
+#define IVT_CB0_MSR_PMON_BOX_FILTER_TID (0x1fULL << 0)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_LINK (0xfULL << 5)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_STATE (0x3fULL << 17)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_NID (0xffffULL << 32)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_OPC (0x1ffULL << 52)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_C6 (0x1ULL << 61)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_NC (0x1ULL << 62)
+#define IVT_CB0_MSR_PMON_BOX_FILTER_IOSC (0x1ULL << 63)
+
+/* IVT home agent */
+#define IVT_HA_PCI_PMON_CTL_Q_OCC_RST (1 << 16)
+#define IVT_HA_PCI_PMON_RAW_EVENT_MASK \
+ (IVT_PMON_RAW_EVENT_MASK | \
+ IVT_HA_PCI_PMON_CTL_Q_OCC_RST)
+/* IVT PCU */
+#define IVT_PCU_MSR_PMON_RAW_EVENT_MASK \
+ (SNBEP_PMON_CTL_EV_SEL_MASK | \
+ SNBEP_PMON_CTL_EV_SEL_EXT | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+ SNBEP_PMON_CTL_EDGE_DET | \
+ SNBEP_PCU_MSR_PMON_CTL_TRESH_MASK | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
+/* IVT QPI */
+#define IVT_QPI_PCI_PMON_RAW_EVENT_MASK \
+ (IVT_PMON_RAW_EVENT_MASK | \
+ SNBEP_PMON_CTL_EV_SEL_EXT)
+
/* NHM-EX event control */
#define NHMEX_PMON_CTL_EV_SEL_MASK 0x000000ff
#define NHMEX_PMON_CTL_UMASK_MASK 0x0000ff00
diff --git a/arch/x86/kernel/cpu/perf_event_knc.c b/arch/x86/kernel/cpu/perf_event_knc.c
index 4b7731bf23a8..838fa8772c62 100644
--- a/arch/x86/kernel/cpu/perf_event_knc.c
+++ b/arch/x86/kernel/cpu/perf_event_knc.c
@@ -17,7 +17,7 @@ static const u64 knc_perfmon_event_map[] =
[PERF_COUNT_HW_BRANCH_MISSES] = 0x002b,
};
-static __initconst u64 knc_hw_cache_event_ids
+static const u64 __initconst knc_hw_cache_event_ids
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
@@ -284,7 +284,7 @@ static struct attribute *intel_knc_formats_attr[] = {
NULL,
};
-static __initconst struct x86_pmu knc_pmu = {
+static const struct x86_pmu knc_pmu __initconst = {
.name = "knc",
.handle_irq = knc_pmu_handle_irq,
.disable_all = knc_pmu_disable_all,
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index 92c7e39a079f..3486e6660357 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -895,8 +895,8 @@ static void p4_pmu_disable_pebs(void)
* So at moment let leave metrics turned on forever -- it's
* ok for now but need to be revisited!
*
- * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, (u64)0);
- * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, (u64)0);
+ * (void)wrmsrl_safe(MSR_IA32_PEBS_ENABLE, 0);
+ * (void)wrmsrl_safe(MSR_P4_PEBS_MATRIX_VERT, 0);
*/
}
@@ -910,8 +910,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event)
* asserted again and again
*/
(void)wrmsrl_safe(hwc->config_base,
- (u64)(p4_config_unpack_cccr(hwc->config)) &
- ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
+ p4_config_unpack_cccr(hwc->config) & ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED);
}
static void p4_pmu_disable_all(void)
@@ -957,7 +956,7 @@ static void p4_pmu_enable_event(struct perf_event *event)
u64 escr_addr, cccr;
bind = &p4_event_bind_map[idx];
- escr_addr = (u64)bind->escr_msr[thread];
+ escr_addr = bind->escr_msr[thread];
/*
* - we dont support cascaded counters yet
diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c
index 4820c232a0b9..b1e2fe115323 100644
--- a/arch/x86/kernel/cpu/perf_event_p6.c
+++ b/arch/x86/kernel/cpu/perf_event_p6.c
@@ -19,7 +19,7 @@ static const u64 p6_perfmon_event_map[] =
};
-static u64 p6_hw_cache_event_ids
+static const u64 __initconst p6_hw_cache_event_ids
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index e280253f6f94..37a198bd48c8 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -34,9 +34,9 @@ static void show_cpuinfo_misc(struct seq_file *m, struct cpuinfo_x86 *c)
"fpu_exception\t: %s\n"
"cpuid level\t: %d\n"
"wp\t\t: %s\n",
- c->fdiv_bug ? "yes" : "no",
- c->f00f_bug ? "yes" : "no",
- c->coma_bug ? "yes" : "no",
+ static_cpu_has_bug(X86_BUG_FDIV) ? "yes" : "no",
+ static_cpu_has_bug(X86_BUG_F00F) ? "yes" : "no",
+ static_cpu_has_bug(X86_BUG_COMA) ? "yes" : "no",
c->hard_math ? "yes" : "no",
c->hard_math ? "yes" : "no",
c->cpuid_level,
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index ee8e9abc859f..d92b5dad15dd 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -39,8 +39,9 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
{ X86_FEATURE_XSAVEOPT, CR_EAX, 0, 0x0000000d, 1 },
- { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
+ { X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
+ { X86_FEATURE_PROC_FEEDBACK, CR_EDX,11, 0x80000007, 0 },
{ X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 },
{ X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 },
{ X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a, 0 },
diff --git a/arch/x86/kernel/doublefault_32.c b/arch/x86/kernel/doublefault_32.c
index 37250fe490b1..155a13f33ed8 100644
--- a/arch/x86/kernel/doublefault_32.c
+++ b/arch/x86/kernel/doublefault_32.c
@@ -20,7 +20,7 @@ static void doublefault_fn(void)
struct desc_ptr gdt_desc = {0, 0};
unsigned long gdt, tss;
- store_gdt(&gdt_desc);
+ native_store_gdt(&gdt_desc);
gdt = gdt_desc.address;
printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index c8797d55b245..deb6421c9e69 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -176,26 +176,20 @@ void show_trace(struct task_struct *task, struct pt_regs *regs,
void show_stack(struct task_struct *task, unsigned long *sp)
{
- show_stack_log_lvl(task, NULL, sp, 0, "");
-}
-
-/*
- * The architecture-independent dump_stack generator
- */
-void dump_stack(void)
-{
- unsigned long bp;
+ unsigned long bp = 0;
unsigned long stack;
- bp = stack_frame(current, NULL);
- printk("Pid: %d, comm: %.20s %s %s %.*s\n",
- current->pid, current->comm, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
- show_trace(NULL, NULL, &stack, bp);
+ /*
+ * Stack frames below this one aren't interesting. Don't show them
+ * if we're printing for %current.
+ */
+ if (!sp && (!task || task == current)) {
+ sp = &stack;
+ bp = stack_frame(current, NULL);
+ }
+
+ show_stack_log_lvl(task, NULL, sp, bp, "");
}
-EXPORT_SYMBOL(dump_stack);
static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED;
static int die_owner = -1;
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 1038a417ea53..f2a1770ca176 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -86,11 +86,9 @@ void show_regs(struct pt_regs *regs)
{
int i;
+ show_regs_print_info(KERN_EMERG);
__show_regs(regs, !user_mode_vm(regs));
- pr_emerg("Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)\n",
- TASK_COMM_LEN, current->comm, task_pid_nr(current),
- current_thread_info(), current, task_thread_info(current));
/*
* When in-kernel, we also print out the stack and code at the
* time of the fault..
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index b653675d5288..addb207dab92 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -249,14 +249,10 @@ void show_regs(struct pt_regs *regs)
{
int i;
unsigned long sp;
- const int cpu = smp_processor_id();
- struct task_struct *cur = current;
sp = regs->sp;
- printk("CPU %d ", cpu);
+ show_regs_print_info(KERN_DEFAULT);
__show_regs(regs, 1);
- printk(KERN_DEFAULT "Process %s (pid: %d, threadinfo %p, task %p)\n",
- cur->comm, cur->pid, task_thread_info(cur), cur);
/*
* When in-kernel, we also print out the stack and code at the
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 9b9f18b49918..d15f575a861b 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -169,25 +169,9 @@ static struct console early_serial_console = {
.index = -1,
};
-/* Direct interface for emergencies */
-static struct console *early_console = &early_vga_console;
-static int __initdata early_console_initialized;
-
-asmlinkage void early_printk(const char *fmt, ...)
-{
- char buf[512];
- int n;
- va_list ap;
-
- va_start(ap, fmt);
- n = vscnprintf(buf, sizeof(buf), fmt, ap);
- early_console->write(early_console, buf, n);
- va_end(ap);
-}
-
static inline void early_console_register(struct console *con, int keep_early)
{
- if (early_console->index != -1) {
+ if (con->index != -1) {
printk(KERN_CRIT "ERROR: earlyprintk= %s already used\n",
con->name);
return;
@@ -207,9 +191,8 @@ static int __init setup_early_printk(char *buf)
if (!buf)
return 0;
- if (early_console_initialized)
+ if (early_console)
return 0;
- early_console_initialized = 1;
keep = (strstr(buf, "keep") != NULL);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index c5e403f6d869..101ac1a9263e 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -144,10 +144,10 @@ void __init x86_64_start_kernel(char * real_mode_data)
* Build-time sanity checks on the kernel image and module
* area mappings. (these are purely build-time and produce no code)
*/
- BUILD_BUG_ON(MODULES_VADDR < KERNEL_IMAGE_START);
- BUILD_BUG_ON(MODULES_VADDR-KERNEL_IMAGE_START < KERNEL_IMAGE_SIZE);
+ BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map);
+ BUILD_BUG_ON(MODULES_VADDR - __START_KERNEL_map < KERNEL_IMAGE_SIZE);
BUILD_BUG_ON(MODULES_LEN + KERNEL_IMAGE_SIZE > 2*PUD_SIZE);
- BUILD_BUG_ON((KERNEL_IMAGE_START & ~PMD_MASK) != 0);
+ BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0);
BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0);
BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));
BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 7bfe318d3d8a..9895a9a41380 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -353,7 +353,11 @@ int __kprobes __copy_instruction(u8 *dest, u8 *src)
* have given.
*/
newdisp = (u8 *) src + (s64) insn.displacement.value - (u8 *) dest;
- BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */
+ if ((s64) (s32) newdisp != newdisp) {
+ pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp);
+ pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", src, dest, insn.displacement.value);
+ return 0;
+ }
disp = (u8 *) dest + insn_offset_displacement(&insn);
*(s32 *) disp = (s32) newdisp;
}
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index b686a904d7c3..cd6d9a5a42f6 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -20,6 +20,7 @@
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*/
+#include <linux/context_tracking.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kvm_para.h>
@@ -43,7 +44,6 @@
#include <asm/apicdef.h>
#include <asm/hypervisor.h>
#include <asm/kvm_guest.h>
-#include <asm/context_tracking.h>
static int kvmapf = 1;
@@ -254,16 +254,18 @@ EXPORT_SYMBOL_GPL(kvm_read_and_reset_pf_reason);
dotraplinkage void __kprobes
do_async_page_fault(struct pt_regs *regs, unsigned long error_code)
{
+ enum ctx_state prev_state;
+
switch (kvm_read_and_reset_pf_reason()) {
default:
do_page_fault(regs, error_code);
break;
case KVM_PV_REASON_PAGE_NOT_PRESENT:
/* page is swapped out by the host. */
- exception_enter(regs);
+ prev_state = exception_enter();
exit_idle();
kvm_async_pf_task_wait((u32)read_cr2());
- exception_exit(regs);
+ exception_exit(prev_state);
break;
case KVM_PV_REASON_PAGE_READY:
rcu_irq_enter();
diff --git a/arch/x86/kernel/microcode_core_early.c b/arch/x86/kernel/microcode_core_early.c
index 577db8417d15..833d51d6ee06 100644
--- a/arch/x86/kernel/microcode_core_early.c
+++ b/arch/x86/kernel/microcode_core_early.c
@@ -45,9 +45,6 @@ static int __cpuinit x86_vendor(void)
u32 eax = 0x00000000;
u32 ebx, ecx = 0, edx;
- if (!have_cpuid_p())
- return X86_VENDOR_UNKNOWN;
-
native_cpuid(&eax, &ebx, &ecx, &edx);
if (CPUID_IS(CPUID_INTEL1, CPUID_INTEL2, CPUID_INTEL3, ebx, ecx, edx))
@@ -59,18 +56,45 @@ static int __cpuinit x86_vendor(void)
return X86_VENDOR_UNKNOWN;
}
+static int __cpuinit x86_family(void)
+{
+ u32 eax = 0x00000001;
+ u32 ebx, ecx = 0, edx;
+ int x86;
+
+ native_cpuid(&eax, &ebx, &ecx, &edx);
+
+ x86 = (eax >> 8) & 0xf;
+ if (x86 == 15)
+ x86 += (eax >> 20) & 0xff;
+
+ return x86;
+}
+
void __init load_ucode_bsp(void)
{
- int vendor = x86_vendor();
+ int vendor, x86;
+
+ if (!have_cpuid_p())
+ return;
- if (vendor == X86_VENDOR_INTEL)
+ vendor = x86_vendor();
+ x86 = x86_family();
+
+ if (vendor == X86_VENDOR_INTEL && x86 >= 6)
load_ucode_intel_bsp();
}
void __cpuinit load_ucode_ap(void)
{
- int vendor = x86_vendor();
+ int vendor, x86;
+
+ if (!have_cpuid_p())
+ return;
+
+ vendor = x86_vendor();
+ x86 = x86_family();
- if (vendor == X86_VENDOR_INTEL)
+ if (vendor == X86_VENDOR_INTEL && x86 >= 6)
load_ucode_intel_ap();
}
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 17fff18a1031..cd6de64cc480 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -263,6 +263,18 @@ void paravirt_leave_lazy_mmu(void)
leave_lazy(PARAVIRT_LAZY_MMU);
}
+void paravirt_flush_lazy_mmu(void)
+{
+ preempt_disable();
+
+ if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+ arch_leave_lazy_mmu_mode();
+ arch_enter_lazy_mmu_mode();
+ }
+
+ preempt_enable();
+}
+
void paravirt_start_context_switch(struct task_struct *prev)
{
BUG_ON(preemptible());
@@ -292,18 +304,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
return this_cpu_read(paravirt_lazy_mode);
}
-void arch_flush_lazy_mmu_mode(void)
-{
- preempt_disable();
-
- if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
- arch_leave_lazy_mmu_mode();
- arch_enter_lazy_mmu_mode();
- }
-
- preempt_enable();
-}
-
struct pv_info pv_info = {
.name = "bare hardware",
.paravirt_enabled = 0,
@@ -360,7 +360,6 @@ struct pv_cpu_ops pv_cpu_ops = {
.set_ldt = native_set_ldt,
.load_gdt = native_load_gdt,
.load_idt = native_load_idt,
- .store_gdt = native_store_gdt,
.store_idt = native_store_idt,
.store_tr = native_store_tr,
.load_tls = native_load_tls,
@@ -475,6 +474,7 @@ struct pv_mmu_ops pv_mmu_ops = {
.lazy_mode = {
.enter = paravirt_nop,
.leave = paravirt_nop,
+ .flush = paravirt_nop,
},
.set_fixmap = native_set_fixmap,
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 14ae10031ff0..607af0d4d5ef 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -121,30 +121,6 @@ void exit_thread(void)
drop_fpu(me);
}
-void show_regs_common(void)
-{
- const char *vendor, *product, *board;
-
- vendor = dmi_get_system_info(DMI_SYS_VENDOR);
- if (!vendor)
- vendor = "";
- product = dmi_get_system_info(DMI_PRODUCT_NAME);
- if (!product)
- product = "";
-
- /* Board Name is optional */
- board = dmi_get_system_info(DMI_BOARD_NAME);
-
- printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s %s%s%s\n",
- current->pid, current->comm, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version,
- vendor, product,
- board ? "/" : "",
- board ? board : "");
-}
-
void flush_thread(void)
{
struct task_struct *tsk = current;
@@ -301,13 +277,7 @@ void exit_idle(void)
}
#endif
-/*
- * The idle thread. There's no useful work to be
- * done, so just try to conserve power and have a
- * low exit latency (ie sit in a loop waiting for
- * somebody to say that they'd like to reschedule)
- */
-void cpu_idle(void)
+void arch_cpu_idle_prepare(void)
{
/*
* If we're the non-boot CPU, nothing set the stack canary up
@@ -317,71 +287,40 @@ void cpu_idle(void)
* canaries already on the stack wont ever trigger).
*/
boot_init_stack_canary();
- current_thread_info()->status |= TS_POLLING;
-
- while (1) {
- tick_nohz_idle_enter();
-
- while (!need_resched()) {
- rmb();
-
- if (cpu_is_offline(smp_processor_id()))
- play_dead();
-
- /*
- * Idle routines should keep interrupts disabled
- * from here on, until they go to idle.
- * Otherwise, idle callbacks can misfire.
- */
- local_touch_nmi();
- local_irq_disable();
-
- enter_idle();
-
- /* Don't trace irqs off for idle */
- stop_critical_timings();
-
- /* enter_idle() needs rcu for notifiers */
- rcu_idle_enter();
+}
- if (cpuidle_idle_call())
- x86_idle();
+void arch_cpu_idle_enter(void)
+{
+ local_touch_nmi();
+ enter_idle();
+}
- rcu_idle_exit();
- start_critical_timings();
+void arch_cpu_idle_exit(void)
+{
+ __exit_idle();
+}
- /* In many cases the interrupt that ended idle
- has already called exit_idle. But some idle
- loops can be woken up without interrupt. */
- __exit_idle();
- }
+void arch_cpu_idle_dead(void)
+{
+ play_dead();
+}
- tick_nohz_idle_exit();
- preempt_enable_no_resched();
- schedule();
- preempt_disable();
- }
+/*
+ * Called from the generic idle code.
+ */
+void arch_cpu_idle(void)
+{
+ if (cpuidle_idle_call())
+ x86_idle();
}
/*
- * We use this if we don't have any better
- * idle routine..
+ * We use this if we don't have any better idle routine..
*/
void default_idle(void)
{
trace_cpu_idle_rcuidle(1, smp_processor_id());
- current_thread_info()->status &= ~TS_POLLING;
- /*
- * TS_POLLING-cleared state must be visible before we
- * test NEED_RESCHED:
- */
- smp_mb();
-
- if (!need_resched())
- safe_halt(); /* enables interrupts racelessly */
- else
- local_irq_enable();
- current_thread_info()->status |= TS_POLLING;
+ safe_halt();
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
}
#ifdef CONFIG_APM_MODULE
@@ -411,20 +350,6 @@ void stop_this_cpu(void *dummy)
halt();
}
-/*
- * On SMP it's slightly faster (but much more power-consuming!)
- * to poll the ->work.need_resched flag instead of waiting for the
- * cross-CPU IPI to arrive. Use this option with caution.
- */
-static void poll_idle(void)
-{
- trace_cpu_idle_rcuidle(0, smp_processor_id());
- local_irq_enable();
- while (!need_resched())
- cpu_relax();
- trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
-}
-
bool amd_e400_c1e_detected;
EXPORT_SYMBOL(amd_e400_c1e_detected);
@@ -489,13 +414,13 @@ static void amd_e400_idle(void)
void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
- if (x86_idle == poll_idle && smp_num_siblings > 1)
+ if (boot_option_idle_override == IDLE_POLL && smp_num_siblings > 1)
pr_warn_once("WARNING: polling idle and HT enabled, performance may degrade\n");
#endif
- if (x86_idle)
+ if (x86_idle || boot_option_idle_override == IDLE_POLL)
return;
- if (cpu_has_amd_erratum(amd_erratum_400)) {
+ if (cpu_has_bug(c, X86_BUG_AMD_APIC_C1E)) {
/* E400: APIC timer interrupt does not wake up CPU from C1e */
pr_info("using AMD E400 aware idle routine\n");
x86_idle = amd_e400_idle;
@@ -517,8 +442,8 @@ static int __init idle_setup(char *str)
if (!strcmp(str, "poll")) {
pr_info("using polling idle threads\n");
- x86_idle = poll_idle;
boot_option_idle_override = IDLE_POLL;
+ cpu_idle_poll_ctrl(true);
} else if (!strcmp(str, "halt")) {
/*
* When the boot option of idle=halt is added, halt is
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index b5a8905785e6..7305f7dfc7ab 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -84,8 +84,6 @@ void __show_regs(struct pt_regs *regs, int all)
savesegment(gs, gs);
}
- show_regs_common();
-
printk(KERN_DEFAULT "EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n",
(u16)regs->cs, regs->ip, regs->flags,
smp_processor_id());
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 0f49677da51e..355ae06dbf94 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -62,7 +62,6 @@ void __show_regs(struct pt_regs *regs, int all)
unsigned int fsindex, gsindex;
unsigned int ds, cs, es;
- show_regs_common();
printk(KERN_DEFAULT "RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip);
printk_address(regs->ip, 1);
printk(KERN_DEFAULT "RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss,
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 26ee48a33dc4..04ee1e2e4c02 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -354,18 +354,22 @@ static void ati_force_hpet_resume(void)
static u32 ati_ixp4x0_rev(struct pci_dev *dev)
{
- u32 d;
- u8 b;
+ int err = 0;
+ u32 d = 0;
+ u8 b = 0;
- pci_read_config_byte(dev, 0xac, &b);
+ err = pci_read_config_byte(dev, 0xac, &b);
b &= ~(1<<5);
- pci_write_config_byte(dev, 0xac, b);
- pci_read_config_dword(dev, 0x70, &d);
+ err |= pci_write_config_byte(dev, 0xac, b);
+ err |= pci_read_config_dword(dev, 0x70, &d);
d |= 1<<8;
- pci_write_config_dword(dev, 0x70, d);
- pci_read_config_dword(dev, 0x8, &d);
+ err |= pci_write_config_dword(dev, 0x70, d);
+ err |= pci_read_config_dword(dev, 0x8, &d);
d &= 0xff;
dev_printk(KERN_DEBUG, &dev->dev, "SB4X0 revision 0x%x\n", d);
+
+ WARN_ON_ONCE(err);
+
return d;
}
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 2e8f3d3b5641..198eb201ed3b 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -13,6 +13,7 @@
#include <asm/x86_init.h>
#include <asm/time.h>
#include <asm/mrst.h>
+#include <asm/rtc.h>
#ifdef CONFIG_X86_32
/*
@@ -36,70 +37,24 @@ EXPORT_SYMBOL(rtc_lock);
* nowtime is written into the registers of the CMOS clock, it will
* jump to the next second precisely 500 ms later. Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you'll only notice that after reboot!
*/
int mach_set_rtc_mmss(unsigned long nowtime)
{
- int real_seconds, real_minutes, cmos_minutes;
- unsigned char save_control, save_freq_select;
- unsigned long flags;
+ struct rtc_time tm;
int retval = 0;
- spin_lock_irqsave(&rtc_lock, flags);
-
- /* tell the clock it's being set */
- save_control = CMOS_READ(RTC_CONTROL);
- CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
- /* stop and reset prescaler */
- save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
- CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
- cmos_minutes = CMOS_READ(RTC_MINUTES);
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
- cmos_minutes = bcd2bin(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- /* correct for half hour time zone */
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30;
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- real_seconds = bin2bcd(real_seconds);
- real_minutes = bin2bcd(real_minutes);
- }
- CMOS_WRITE(real_seconds, RTC_SECONDS);
- CMOS_WRITE(real_minutes, RTC_MINUTES);
+ rtc_time_to_tm(nowtime, &tm);
+ if (!rtc_valid_tm(&tm)) {
+ retval = set_rtc_time(&tm);
+ if (retval)
+ printk(KERN_ERR "%s: RTC write failed with error %d\n",
+ __FUNCTION__, retval);
} else {
- printk_once(KERN_NOTICE
- "set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
+ printk(KERN_ERR
+ "%s: Invalid RTC value: write of %lx to RTC failed\n",
+ __FUNCTION__, nowtime);
+ retval = -EINVAL;
}
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_WRITE(save_control, RTC_CONTROL);
- CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
- spin_unlock_irqrestore(&rtc_lock, flags);
-
return retval;
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 90d8cc930f5e..56f7fcfe7fa2 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -82,7 +82,6 @@
#include <asm/timer.h>
#include <asm/i8259.h>
#include <asm/sections.h>
-#include <asm/dmi.h>
#include <asm/io_apic.h>
#include <asm/ist.h>
#include <asm/setup_arch.h>
@@ -173,12 +172,10 @@ static struct resource bss_resource = {
/* cpu data as detected by the assembly code in head.S */
struct cpuinfo_x86 new_cpu_data __cpuinitdata = {
.wp_works_ok = -1,
- .fdiv_bug = -1,
};
/* common cpu data for all cpus */
struct cpuinfo_x86 boot_cpu_data __read_mostly = {
.wp_works_ok = -1,
- .fdiv_bug = -1,
};
EXPORT_SYMBOL(boot_cpu_data);
@@ -507,11 +504,14 @@ static void __init memblock_x86_reserve_range_setup_data(void)
/*
* Keep the crash kernel below this limit. On 32 bits earlier kernels
* would limit the kernel to the low 512 MiB due to mapping restrictions.
+ * On 64bit, old kexec-tools need to under 896MiB.
*/
#ifdef CONFIG_X86_32
-# define CRASH_KERNEL_ADDR_MAX (512 << 20)
+# define CRASH_KERNEL_ADDR_LOW_MAX (512 << 20)
+# define CRASH_KERNEL_ADDR_HIGH_MAX (512 << 20)
#else
-# define CRASH_KERNEL_ADDR_MAX MAXMEM
+# define CRASH_KERNEL_ADDR_LOW_MAX (896UL<<20)
+# define CRASH_KERNEL_ADDR_HIGH_MAX MAXMEM
#endif
static void __init reserve_crashkernel_low(void)
@@ -521,19 +521,35 @@ static void __init reserve_crashkernel_low(void)
unsigned long long low_base = 0, low_size = 0;
unsigned long total_low_mem;
unsigned long long base;
+ bool auto_set = false;
int ret;
total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT));
+ /* crashkernel=Y,low */
ret = parse_crashkernel_low(boot_command_line, total_low_mem,
&low_size, &base);
- if (ret != 0 || low_size <= 0)
- return;
+ if (ret != 0) {
+ /*
+ * two parts from lib/swiotlb.c:
+ * swiotlb size: user specified with swiotlb= or default.
+ * swiotlb overflow buffer: now is hardcoded to 32k.
+ * We round it to 8M for other buffers that
+ * may need to stay low too.
+ */
+ low_size = swiotlb_size_or_default() + (8UL<<20);
+ auto_set = true;
+ } else {
+ /* passed with crashkernel=0,low ? */
+ if (!low_size)
+ return;
+ }
low_base = memblock_find_in_range(low_size, (1ULL<<32),
low_size, alignment);
if (!low_base) {
- pr_info("crashkernel low reservation failed - No suitable area found.\n");
+ if (!auto_set)
+ pr_info("crashkernel low reservation failed - No suitable area found.\n");
return;
}
@@ -554,14 +570,22 @@ static void __init reserve_crashkernel(void)
const unsigned long long alignment = 16<<20; /* 16M */
unsigned long long total_mem;
unsigned long long crash_size, crash_base;
+ bool high = false;
int ret;
total_mem = memblock_phys_mem_size();
+ /* crashkernel=XM */
ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base);
- if (ret != 0 || crash_size <= 0)
- return;
+ if (ret != 0 || crash_size <= 0) {
+ /* crashkernel=X,high */
+ ret = parse_crashkernel_high(boot_command_line, total_mem,
+ &crash_size, &crash_base);
+ if (ret != 0 || crash_size <= 0)
+ return;
+ high = true;
+ }
/* 0 means: find the address automatically */
if (crash_base <= 0) {
@@ -569,7 +593,9 @@ static void __init reserve_crashkernel(void)
* kexec want bzImage is below CRASH_KERNEL_ADDR_MAX
*/
crash_base = memblock_find_in_range(alignment,
- CRASH_KERNEL_ADDR_MAX, crash_size, alignment);
+ high ? CRASH_KERNEL_ADDR_HIGH_MAX :
+ CRASH_KERNEL_ADDR_LOW_MAX,
+ crash_size, alignment);
if (!crash_base) {
pr_info("crashkernel reservation failed - No suitable area found.\n");
@@ -970,6 +996,7 @@ void __init setup_arch(char **cmdline_p)
efi_init();
dmi_scan_machine();
+ dmi_set_dump_stack_arch_desc();
/*
* VMware detection requires dmi to be available, so this
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 9f190a2a00e9..9c73b51817e4 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -284,7 +284,7 @@ notrace static void __cpuinit start_secondary(void *unused)
x86_cpuinit.setup_percpu_clockev();
wmb();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
void __init smp_store_boot_cpu_info(void)
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index 9d9d2f9e77a5..f7fec09e3e3a 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -3,13 +3,13 @@
#include <linux/sched.h>
#include <linux/user.h>
#include <linux/regset.h>
+#include <linux/syscalls.h>
#include <asm/uaccess.h>
#include <asm/desc.h>
#include <asm/ldt.h>
#include <asm/processor.h>
#include <asm/proto.h>
-#include <asm/syscalls.h>
#include "tls.h"
@@ -89,11 +89,9 @@ int do_set_thread_area(struct task_struct *p, int idx,
return 0;
}
-asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
+SYSCALL_DEFINE1(set_thread_area, struct user_desc __user *, u_info)
{
- int ret = do_set_thread_area(current, -1, u_info, 1);
- asmlinkage_protect(1, ret, u_info);
- return ret;
+ return do_set_thread_area(current, -1, u_info, 1);
}
@@ -139,11 +137,9 @@ int do_get_thread_area(struct task_struct *p, int idx,
return 0;
}
-asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
+SYSCALL_DEFINE1(get_thread_area, struct user_desc __user *, u_info)
{
- int ret = do_get_thread_area(current, -1, u_info);
- asmlinkage_protect(1, ret, u_info);
- return ret;
+ return do_get_thread_area(current, -1, u_info);
}
int regset_tls_active(struct task_struct *target,
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 68bda7a84159..772e2a846dec 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/context_tracking.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/spinlock.h>
@@ -55,8 +56,7 @@
#include <asm/i387.h>
#include <asm/fpu-internal.h>
#include <asm/mce.h>
-#include <asm/context_tracking.h>
-
+#include <asm/fixmap.h>
#include <asm/mach_traps.h>
#ifdef CONFIG_X86_64
@@ -176,34 +176,38 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
#define DO_ERROR(trapnr, signr, str, name) \
dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{ \
- exception_enter(regs); \
+ enum ctx_state prev_state; \
+ \
+ prev_state = exception_enter(); \
if (notify_die(DIE_TRAP, str, regs, error_code, \
trapnr, signr) == NOTIFY_STOP) { \
- exception_exit(regs); \
+ exception_exit(prev_state); \
return; \
} \
conditional_sti(regs); \
do_trap(trapnr, signr, str, regs, error_code, NULL); \
- exception_exit(regs); \
+ exception_exit(prev_state); \
}
#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{ \
siginfo_t info; \
+ enum ctx_state prev_state; \
+ \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
info.si_addr = (void __user *)siaddr; \
- exception_enter(regs); \
+ prev_state = exception_enter(); \
if (notify_die(DIE_TRAP, str, regs, error_code, \
trapnr, signr) == NOTIFY_STOP) { \
- exception_exit(regs); \
+ exception_exit(prev_state); \
return; \
} \
conditional_sti(regs); \
do_trap(trapnr, signr, str, regs, error_code, &info); \
- exception_exit(regs); \
+ exception_exit(prev_state); \
}
DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -226,14 +230,16 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
/* Runs on IST stack */
dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
{
- exception_enter(regs);
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
preempt_conditional_sti(regs);
do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
preempt_conditional_cli(regs);
}
- exception_exit(regs);
+ exception_exit(prev_state);
}
dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -241,7 +247,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
static const char str[] = "double fault";
struct task_struct *tsk = current;
- exception_enter(regs);
+ exception_enter();
/* Return not checked because double check cannot be ignored */
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
@@ -261,8 +267,9 @@ dotraplinkage void __kprobes
do_general_protection(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk;
+ enum ctx_state prev_state;
- exception_enter(regs);
+ prev_state = exception_enter();
conditional_sti(regs);
#ifdef CONFIG_X86_32
@@ -300,12 +307,14 @@ do_general_protection(struct pt_regs *regs, long error_code)
force_sig(SIGSEGV, tsk);
exit:
- exception_exit(regs);
+ exception_exit(prev_state);
}
/* May run on IST stack. */
dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
{
+ enum ctx_state prev_state;
+
#ifdef CONFIG_DYNAMIC_FTRACE
/*
* ftrace must be first, everything else may cause a recursive crash.
@@ -315,7 +324,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
ftrace_int3_handler(regs))
return;
#endif
- exception_enter(regs);
+ prev_state = exception_enter();
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
SIGTRAP) == NOTIFY_STOP)
@@ -336,7 +345,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
preempt_conditional_cli(regs);
debug_stack_usage_dec();
exit:
- exception_exit(regs);
+ exception_exit(prev_state);
}
#ifdef CONFIG_X86_64
@@ -393,11 +402,12 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
{
struct task_struct *tsk = current;
+ enum ctx_state prev_state;
int user_icebp = 0;
unsigned long dr6;
int si_code;
- exception_enter(regs);
+ prev_state = exception_enter();
get_debugreg(dr6, 6);
@@ -467,7 +477,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
debug_stack_usage_dec();
exit:
- exception_exit(regs);
+ exception_exit(prev_state);
}
/*
@@ -561,17 +571,21 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)
dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
{
- exception_enter(regs);
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
math_error(regs, error_code, X86_TRAP_MF);
- exception_exit(regs);
+ exception_exit(prev_state);
}
dotraplinkage void
do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
{
- exception_enter(regs);
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
math_error(regs, error_code, X86_TRAP_XF);
- exception_exit(regs);
+ exception_exit(prev_state);
}
dotraplinkage void
@@ -639,7 +653,9 @@ EXPORT_SYMBOL_GPL(math_state_restore);
dotraplinkage void __kprobes
do_device_not_available(struct pt_regs *regs, long error_code)
{
- exception_enter(regs);
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
BUG_ON(use_eager_fpu());
#ifdef CONFIG_MATH_EMULATION
@@ -650,7 +666,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
info.regs = regs;
math_emulate(&info);
- exception_exit(regs);
+ exception_exit(prev_state);
return;
}
#endif
@@ -658,15 +674,16 @@ do_device_not_available(struct pt_regs *regs, long error_code)
#ifdef CONFIG_X86_32
conditional_sti(regs);
#endif
- exception_exit(regs);
+ exception_exit(prev_state);
}
#ifdef CONFIG_X86_32
dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
{
siginfo_t info;
+ enum ctx_state prev_state;
- exception_enter(regs);
+ prev_state = exception_enter();
local_irq_enable();
info.si_signo = SIGILL;
@@ -678,7 +695,7 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
&info);
}
- exception_exit(regs);
+ exception_exit(prev_state);
}
#endif
@@ -753,6 +770,14 @@ void __init trap_init(void)
#endif
/*
+ * Set the IDT descriptor to a fixed read-only location, so that the
+ * "sidt" instruction will not leak the location of the kernel, and
+ * to defend the IDT against arbitrary memory write vulnerabilities.
+ * It will be reloaded in cpu_init() */
+ __set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
+ idt_descr.address = fix_to_virt(FIX_RO_IDT);
+
+ /*
* Should be a barrier for any external CPU state:
*/
cpu_init();
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 4b9ea101fe3b..098b3cfda72e 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -768,7 +768,8 @@ static cycle_t read_tsc(struct clocksource *cs)
static void resume_tsc(struct clocksource *cs)
{
- clocksource_tsc.cycle_last = 0;
+ if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
+ clocksource_tsc.cycle_last = 0;
}
static struct clocksource clocksource_tsc = {
@@ -939,6 +940,9 @@ static int __init init_tsc_clocksource(void)
clocksource_tsc.flags &= ~CLOCK_SOURCE_IS_CONTINUOUS;
}
+ if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
+ clocksource_tsc.flags |= CLOCK_SOURCE_SUSPEND_NONSTOP;
+
/*
* Trust the results of the earlier calibration on systems
* exporting a reliable TSC.
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 0ba4cfb4f412..2ed845928b5f 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -697,3 +697,32 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
send_sig(SIGTRAP, current, 0);
return ret;
}
+
+unsigned long
+arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs)
+{
+ int rasize, ncopied;
+ unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
+
+ rasize = is_ia32_task() ? 4 : 8;
+ ncopied = copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize);
+ if (unlikely(ncopied))
+ return -1;
+
+ /* check whether address has been already hijacked */
+ if (orig_ret_vaddr == trampoline_vaddr)
+ return orig_ret_vaddr;
+
+ ncopied = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize);
+ if (likely(!ncopied))
+ return orig_ret_vaddr;
+
+ if (ncopied != rasize) {
+ pr_err("uprobe: return address clobbered: pid=%d, %%sp=%#lx, "
+ "%%ip=%#lx\n", current->pid, regs->sp, regs->ip);
+
+ force_sig_info(SIGSEGV, SEND_SIG_FORCED, current);
+ }
+
+ return -1;
+}
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 22a1530146a8..10c4f3006afd 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -94,10 +94,6 @@ SECTIONS
_text = .;
/* bootstrapping code */
HEAD_TEXT
-#ifdef CONFIG_X86_32
- . = ALIGN(PAGE_SIZE);
- *(.text..page_aligned)
-#endif
. = ALIGN(8);
_stext = .;
TEXT_TEXT
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 02b51dd4e4ad..f77df1c5de6e 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1857,7 +1857,7 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
if (!pv_eoi_enabled(vcpu))
return 0;
return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data,
- addr);
+ addr, sizeof(u8));
}
void kvm_lapic_init(void)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e1b1ce21bc00..7d39d70647e3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -555,7 +555,7 @@ static void svm_init_erratum_383(void)
int err;
u64 val;
- if (!cpu_has_amd_erratum(amd_erratum_383))
+ if (!static_cpu_has_bug(X86_BUG_AMD_TLB_MMATCH))
return;
/* Use _safe variants to not break nested virtualization */
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 6667042714cc..867b81037f96 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2459,7 +2459,7 @@ static int hardware_enable(void *garbage)
ept_sync_global();
}
- store_gdt(&__get_cpu_var(host_gdt));
+ native_store_gdt(&__get_cpu_var(host_gdt));
return 0;
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f19ac0aca60d..e1721324c271 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1823,7 +1823,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
return 0;
}
- if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa))
+ if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa,
+ sizeof(u32)))
return 1;
vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
@@ -1952,12 +1953,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
gpa_offset = data & ~(PAGE_MASK | 1);
- /* Check that the address is 32-byte aligned. */
- if (gpa_offset & (sizeof(struct pvclock_vcpu_time_info) - 1))
- break;
-
if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
- &vcpu->arch.pv_time, data & ~1ULL))
+ &vcpu->arch.pv_time, data & ~1ULL,
+ sizeof(struct pvclock_vcpu_time_info)))
vcpu->arch.pv_time_enabled = false;
else
vcpu->arch.pv_time_enabled = true;
@@ -1977,7 +1975,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 1;
if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.st.stime,
- data & KVM_STEAL_VALID_BITS))
+ data & KVM_STEAL_VALID_BITS,
+ sizeof(struct kvm_steal_time)))
return 1;
vcpu->arch.st.msr_val = data;
diff --git a/arch/x86/lguest/Kconfig b/arch/x86/lguest/Kconfig
index 29043d2048a0..4a0890f815c4 100644
--- a/arch/x86/lguest/Kconfig
+++ b/arch/x86/lguest/Kconfig
@@ -1,7 +1,6 @@
config LGUEST_GUEST
bool "Lguest guest support"
- select PARAVIRT
- depends on X86_32
+ depends on X86_32 && PARAVIRT
select TTY
select VIRTUALIZATION
select VIRTIO
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 1cbd89ca5569..7114c63f047d 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -1334,6 +1334,7 @@ __init void lguest_init(void)
pv_mmu_ops.read_cr3 = lguest_read_cr3;
pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode;
+ pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu;
pv_mmu_ops.pte_update = lguest_pte_update;
pv_mmu_ops.pte_update_defer = lguest_pte_update;
diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S
index 2af5df3ade7c..e78b8eee6615 100644
--- a/arch/x86/lib/checksum_32.S
+++ b/arch/x86/lib/checksum_32.S
@@ -61,7 +61,7 @@ ENTRY(csum_partial)
testl $3, %esi # Check alignment.
jz 2f # Jump if alignment is ok.
testl $1, %esi # Check alignment.
- jz 10f # Jump if alignment is boundary of 2bytes.
+ jz 10f # Jump if alignment is boundary of 2 bytes.
# buf is odd
dec %ecx
diff --git a/arch/x86/lib/memcpy_32.c b/arch/x86/lib/memcpy_32.c
index b908a59eccf5..e78761d6b7f8 100644
--- a/arch/x86/lib/memcpy_32.c
+++ b/arch/x86/lib/memcpy_32.c
@@ -26,7 +26,7 @@ void *memmove(void *dest, const void *src, size_t n)
char *ret = dest;
__asm__ __volatile__(
- /* Handle more 16bytes in loop */
+ /* Handle more 16 bytes in loop */
"cmp $0x10, %0\n\t"
"jb 1f\n\t"
@@ -51,7 +51,7 @@ void *memmove(void *dest, const void *src, size_t n)
"sub $0x10, %0\n\t"
/*
- * We gobble 16byts forward in each loop.
+ * We gobble 16 bytes forward in each loop.
*/
"3:\n\t"
"sub $0x10, %0\n\t"
@@ -117,7 +117,7 @@ void *memmove(void *dest, const void *src, size_t n)
"sub $0x10, %0\n\t"
/*
- * We gobble 16byts backward in each loop.
+ * We gobble 16 bytes backward in each loop.
*/
"7:\n\t"
"sub $0x10, %0\n\t"
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index 1c273be7c97e..56313a326188 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -98,7 +98,7 @@ ENTRY(memcpy)
subq $0x20, %rdx
/*
* At most 3 ALU operations in one cycle,
- * so append NOPS in the same 16bytes trunk.
+ * so append NOPS in the same 16 bytes trunk.
*/
.p2align 4
.Lcopy_backward_loop:
diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S
index ee164610ec46..65268a6104f4 100644
--- a/arch/x86/lib/memmove_64.S
+++ b/arch/x86/lib/memmove_64.S
@@ -27,7 +27,7 @@
ENTRY(memmove)
CFI_STARTPROC
- /* Handle more 32bytes in loop */
+ /* Handle more 32 bytes in loop */
mov %rdi, %rax
cmp $0x20, %rdx
jb 1f
@@ -56,7 +56,7 @@ ENTRY(memmove)
3:
sub $0x20, %rdx
/*
- * We gobble 32byts forward in each loop.
+ * We gobble 32 bytes forward in each loop.
*/
5:
sub $0x20, %rdx
@@ -122,7 +122,7 @@ ENTRY(memmove)
addq %rdx, %rdi
subq $0x20, %rdx
/*
- * We gobble 32byts backward in each loop.
+ * We gobble 32 bytes backward in each loop.
*/
8:
subq $0x20, %rdx
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index f0312d746402..3eb18acd0e40 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -689,9 +689,3 @@ _copy_from_user(void *to, const void __user *from, unsigned long n)
return n;
}
EXPORT_SYMBOL(_copy_from_user);
-
-void copy_from_user_overflow(void)
-{
- WARN(1, "Buffer overflow detected!\n");
-}
-EXPORT_SYMBOL(copy_from_user_overflow);
diff --git a/arch/x86/mm/amdtopology.c b/arch/x86/mm/amdtopology.c
index 5247d01329ca..2ca15b59fb3f 100644
--- a/arch/x86/mm/amdtopology.c
+++ b/arch/x86/mm/amdtopology.c
@@ -130,9 +130,8 @@ int __init amd_numa_init(void)
}
limit >>= 16;
- limit <<= 24;
- limit |= (1<<24)-1;
limit++;
+ limit <<= 24;
if (limit > end)
limit = end;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 2b97525246d4..654be4ae3047 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -13,12 +13,12 @@
#include <linux/perf_event.h> /* perf_sw_event */
#include <linux/hugetlb.h> /* hstate_index_to_shift */
#include <linux/prefetch.h> /* prefetchw */
+#include <linux/context_tracking.h> /* exception_enter(), ... */
#include <asm/traps.h> /* dotraplinkage, ... */
#include <asm/pgalloc.h> /* pgd_*(), ... */
#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */
#include <asm/fixmap.h> /* VSYSCALL_START */
-#include <asm/context_tracking.h> /* exception_enter(), ... */
/*
* Page fault error code bits:
@@ -378,10 +378,12 @@ static noinline __kprobes int vmalloc_fault(unsigned long address)
if (pgd_none(*pgd_ref))
return -1;
- if (pgd_none(*pgd))
+ if (pgd_none(*pgd)) {
set_pgd(pgd, *pgd_ref);
- else
+ arch_flush_lazy_mmu_mode();
+ } else {
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
+ }
/*
* Below here mismatches are bugs because these lower tables
@@ -555,7 +557,7 @@ static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
/*
* Pentium F0 0F C7 C8 bug workaround:
*/
- if (boot_cpu_data.f00f_bug) {
+ if (boot_cpu_has_bug(X86_BUG_F00F)) {
nr = (address - idt_descr.address) >> 3;
if (nr == 6) {
@@ -1222,7 +1224,9 @@ good_area:
dotraplinkage void __kprobes
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
- exception_enter(regs);
+ enum ctx_state prev_state;
+
+ prev_state = exception_enter();
__do_page_fault(regs, error_code);
- exception_exit(regs);
+ exception_exit(prev_state);
}
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 6f31ee56c008..252b8f5489ba 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -137,5 +137,4 @@ void __init set_highmem_pages_init(void)
add_highpages_with_active_regions(nid, zone_start_pfn,
zone_end_pfn);
}
- totalram_pages += totalhigh_pages;
}
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 59b7fc453277..fdc5dca14fb3 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -515,11 +515,8 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
for (; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
+ free_reserved_page(virt_to_page(addr));
}
#endif
}
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 2d19001151d5..3ac7e319918d 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -427,14 +427,6 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-static void __init add_one_highpage_init(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalhigh_pages++;
-}
-
void __init add_highpages_with_active_regions(int nid,
unsigned long start_pfn, unsigned long end_pfn)
{
@@ -448,7 +440,7 @@ void __init add_highpages_with_active_regions(int nid,
start_pfn, end_pfn);
for ( ; pfn < e_pfn; pfn++)
if (pfn_valid(pfn))
- add_one_highpage_init(pfn_to_page(pfn));
+ free_highmem_page(pfn_to_page(pfn));
}
}
#else
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 24ceda0101bb..bb00c4672ad6 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -1012,14 +1012,12 @@ remove_pagetable(unsigned long start, unsigned long end, bool direct)
flush_tlb_all();
}
-void __ref vmemmap_free(struct page *memmap, unsigned long nr_pages)
+void __ref vmemmap_free(unsigned long start, unsigned long end)
{
- unsigned long start = (unsigned long)memmap;
- unsigned long end = (unsigned long)(memmap + nr_pages);
-
remove_pagetable(start, end, false);
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static void __meminit
kernel_physical_mapping_remove(unsigned long start, unsigned long end)
{
@@ -1029,7 +1027,6 @@ kernel_physical_mapping_remove(unsigned long start, unsigned long end)
remove_pagetable(start, end, true);
}
-#ifdef CONFIG_MEMORY_HOTREMOVE
int __ref arch_remove_memory(u64 start, u64 size)
{
unsigned long start_pfn = start >> PAGE_SHIFT;
@@ -1068,10 +1065,9 @@ void __init mem_init(void)
/* clear_bss() already clear the empty_zero_page */
- reservedpages = 0;
-
- /* this will put all low memory onto the freelists */
register_page_bootmem_info();
+
+ /* this will put all memory onto the freelists */
totalram_pages = free_all_bootmem();
absent_pages = absent_pages_in_range(0, max_pfn);
@@ -1286,18 +1282,17 @@ static long __meminitdata addr_start, addr_end;
static void __meminitdata *p_start, *p_end;
static int __meminitdata node_start;
-int __meminit
-vmemmap_populate(struct page *start_page, unsigned long size, int node)
+static int __meminit vmemmap_populate_hugepages(unsigned long start,
+ unsigned long end, int node)
{
- unsigned long addr = (unsigned long)start_page;
- unsigned long end = (unsigned long)(start_page + size);
+ unsigned long addr;
unsigned long next;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
- for (; addr < end; addr = next) {
- void *p = NULL;
+ for (addr = start; addr < end; addr = next) {
+ next = pmd_addr_end(addr, end);
pgd = vmemmap_pgd_populate(addr, node);
if (!pgd)
@@ -1307,31 +1302,14 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
if (!pud)
return -ENOMEM;
- if (!cpu_has_pse) {
- next = (addr + PAGE_SIZE) & PAGE_MASK;
- pmd = vmemmap_pmd_populate(pud, addr, node);
-
- if (!pmd)
- return -ENOMEM;
-
- p = vmemmap_pte_populate(pmd, addr, node);
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd)) {
+ void *p;
- if (!p)
- return -ENOMEM;
-
- addr_end = addr + PAGE_SIZE;
- p_end = p + PAGE_SIZE;
- } else {
- next = pmd_addr_end(addr, end);
-
- pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd)) {
+ p = vmemmap_alloc_block_buf(PMD_SIZE, node);
+ if (p) {
pte_t entry;
- p = vmemmap_alloc_block_buf(PMD_SIZE, node);
- if (!p)
- return -ENOMEM;
-
entry = pfn_pte(__pa(p) >> PAGE_SHIFT,
PAGE_KERNEL_LARGE);
set_pmd(pmd, __pmd(pte_val(entry)));
@@ -1348,15 +1326,32 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
addr_end = addr + PMD_SIZE;
p_end = p + PMD_SIZE;
- } else
- vmemmap_verify((pte_t *)pmd, node, addr, next);
+ continue;
+ }
+ } else if (pmd_large(*pmd)) {
+ vmemmap_verify((pte_t *)pmd, node, addr, next);
+ continue;
}
-
+ pr_warn_once("vmemmap: falling back to regular page backing\n");
+ if (vmemmap_populate_basepages(addr, next, node))
+ return -ENOMEM;
}
- sync_global_pgds((unsigned long)start_page, end - 1);
return 0;
}
+int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
+{
+ int err;
+
+ if (cpu_has_pse)
+ err = vmemmap_populate_hugepages(start, end, node);
+ else
+ err = vmemmap_populate_basepages(start, end, node);
+ if (!err)
+ sync_global_pgds(start, end - 1);
+ return err;
+}
+
#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HAVE_BOOTMEM_INFO_NODE)
void register_page_bootmem_memmap(unsigned long section_nr,
struct page *start_page, unsigned long size)
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 78fe3f1ac49f..9a1e6583910c 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -282,12 +282,7 @@ void iounmap(volatile void __iomem *addr)
in parallel. Reuse of the virtual address is prevented by
leaving it in the global lists until we're done with it.
cpa takes care of the direct mappings. */
- read_lock(&vmlist_lock);
- for (p = vmlist; p; p = p->next) {
- if (p->addr == (void __force *)addr)
- break;
- }
- read_unlock(&vmlist_lock);
+ p = find_vm_area((void __force *)addr);
if (!p) {
printk(KERN_ERR "iounmap: bad address %p\n", addr);
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 72fe01e9e414..a71c4e207679 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -114,14 +114,11 @@ void numa_clear_node(int cpu)
*/
void __init setup_node_to_cpumask_map(void)
{
- unsigned int node, num = 0;
+ unsigned int node;
/* setup nr_node_ids if not done yet */
- if (nr_node_ids == MAX_NUMNODES) {
- for_each_node_mask(node, node_possible_map)
- num = node;
- nr_node_ids = num + 1;
- }
+ if (nr_node_ids == MAX_NUMNODES)
+ setup_nr_node_ids();
/* allocate the map */
for (node = 0; node < nr_node_ids; node++)
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index b0086567271c..d0b1773d9d2e 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -68,7 +68,7 @@ static int print_split(struct split_state *s)
s->gpg++;
i += GPS/PAGE_SIZE;
} else if (level == PG_LEVEL_2M) {
- if (!(pte_val(*pte) & _PAGE_PSE)) {
+ if ((pte_val(*pte) & _PAGE_PRESENT) && !(pte_val(*pte) & _PAGE_PSE)) {
printk(KERN_ERR
"%lx level %d but not PSE %Lx\n",
addr, level, (u64)pte_val(*pte));
@@ -130,13 +130,12 @@ static int pageattr_test(void)
}
failed += print_split(&sa);
- srandom32(100);
for (i = 0; i < NTEST; i++) {
- unsigned long pfn = random32() % max_pfn_mapped;
+ unsigned long pfn = prandom_u32() % max_pfn_mapped;
addr[i] = (unsigned long)__va(pfn << PAGE_SHIFT);
- len[i] = random32() % 100;
+ len[i] = prandom_u32() % 100;
len[i] = min_t(unsigned long, len[i], max_pfn_mapped - pfn - 1);
if (len[i] == 0)
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 091934e1d0d9..bb32480c2d71 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -467,7 +467,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
* We are safe now. Check whether the new pgprot is the same:
*/
old_pte = *kpte;
- old_prot = new_prot = req_prot = pte_pgprot(old_pte);
+ old_prot = req_prot = pte_pgprot(old_pte);
pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);
@@ -478,12 +478,12 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
* a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL
* for the ancient hardware that doesn't support it.
*/
- if (pgprot_val(new_prot) & _PAGE_PRESENT)
- pgprot_val(new_prot) |= _PAGE_PSE | _PAGE_GLOBAL;
+ if (pgprot_val(req_prot) & _PAGE_PRESENT)
+ pgprot_val(req_prot) |= _PAGE_PSE | _PAGE_GLOBAL;
else
- pgprot_val(new_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL);
+ pgprot_val(req_prot) &= ~(_PAGE_PSE | _PAGE_GLOBAL);
- new_prot = canon_pgprot(new_prot);
+ req_prot = canon_pgprot(req_prot);
/*
* old_pte points to the large page base address. So we need
@@ -542,13 +542,14 @@ out_unlock:
return do_split;
}
-int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
+static int
+__split_large_page(pte_t *kpte, unsigned long address, struct page *base)
{
+ pte_t *pbase = (pte_t *)page_address(base);
unsigned long pfn, pfninc = 1;
unsigned int i, level;
pte_t *tmp;
pgprot_t ref_prot;
- struct page *base = virt_to_page(pbase);
spin_lock(&pgd_lock);
/*
@@ -633,7 +634,6 @@ int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
static int split_large_page(pte_t *kpte, unsigned long address)
{
- pte_t *pbase;
struct page *base;
if (!debug_pagealloc)
@@ -644,8 +644,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
if (!base)
return -ENOMEM;
- pbase = (pte_t *)page_address(base);
- if (__split_large_page(kpte, address, pbase))
+ if (__split_large_page(kpte, address, base))
__free_page(base);
return 0;
@@ -1413,6 +1412,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
* but that can deadlock->flush only current cpu:
*/
__flush_tlb_all();
+
+ arch_flush_lazy_mmu_mode();
}
#ifdef CONFIG_HIBERNATION
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 193350b51f90..17fda6a8b3c2 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -58,6 +58,13 @@ void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte)
void ___pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd)
{
paravirt_release_pmd(__pa(pmd) >> PAGE_SHIFT);
+ /*
+ * NOTE! For PAE, any changes to the top page-directory-pointer-table
+ * entries need a full cr3 reload to flush.
+ */
+#ifdef CONFIG_X86_PAE
+ tlb->need_flush_all = 1;
+#endif
tlb_remove_page(tlb, virt_to_page(pmd));
}
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 3cbe45381bbb..f66b54086ce5 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -725,17 +725,12 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
}
oldproglen = proglen;
}
+
if (bpf_jit_enable > 1)
- pr_err("flen=%d proglen=%u pass=%d image=%p\n",
- flen, proglen, pass, image);
+ bpf_jit_dump(flen, proglen, pass, image);
if (image) {
- if (bpf_jit_enable > 1)
- print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
- 16, 1, image, proglen, false);
-
bpf_flush_icache(image, image + proglen);
-
fp->bpf_func = (void *)image;
}
out:
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 901177d75ff5..305c68b8d538 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/dmi.h>
@@ -170,6 +171,16 @@ void pcibios_fixup_bus(struct pci_bus *b)
pcibios_fixup_device_resources(dev);
}
+void pcibios_add_bus(struct pci_bus *bus)
+{
+ acpi_pci_add_bus(bus);
+}
+
+void pcibios_remove_bus(struct pci_bus *bus)
+{
+ acpi_pci_remove_bus(bus);
+}
+
/*
* Only use DMI information to set this if nothing was passed
* on the kernel command line (which was parsed earlier).
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 94e76620460f..4a9be6ddf054 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -177,7 +177,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
goto error;
i = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) {
- irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
+ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i],
(type == PCI_CAP_ID_MSIX) ?
"pcifront-msi-x" :
"pcifront-msi",
@@ -244,7 +244,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
dev_dbg(&dev->dev,
"xen: msi already bound to pirq=%d\n", pirq);
}
- irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
+ irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq,
(type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi",
DOMID_SELF);
@@ -326,7 +326,7 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
}
ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
- map_irq.pirq, map_irq.index,
+ map_irq.pirq,
(type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi",
domid);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 55ea7dfb5b3c..55856b2310d3 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -42,6 +42,7 @@
#include <linux/io.h>
#include <linux/reboot.h>
#include <linux/bcd.h>
+#include <linux/ucs2_string.h>
#include <asm/setup.h>
#include <asm/efi.h>
@@ -49,9 +50,17 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/x86_init.h>
+#include <asm/rtc.h>
#define EFI_DEBUG 1
+/*
+ * There's some additional metadata associated with each
+ * variable. Intel's reference implementation is 60 bytes - bump that
+ * to account for potential alignment constraints
+ */
+#define VAR_METADATA_SIZE 64
+
struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR,
@@ -70,6 +79,13 @@ struct efi_memory_map memmap;
static struct efi efi_phys __initdata;
static efi_system_table_t efi_systab __initdata;
+static u64 efi_var_store_size;
+static u64 efi_var_remaining_size;
+static u64 efi_var_max_var_size;
+static u64 boot_used_size;
+static u64 boot_var_size;
+static u64 active_size;
+
unsigned long x86_efi_facility;
/*
@@ -99,6 +115,15 @@ static int __init setup_add_efi_memmap(char *arg)
}
early_param("add_efi_memmap", setup_add_efi_memmap);
+static bool efi_no_storage_paranoia;
+
+static int __init setup_storage_paranoia(char *arg)
+{
+ efi_no_storage_paranoia = true;
+ return 0;
+}
+early_param("efi_no_storage_paranoia", setup_storage_paranoia);
+
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{
@@ -163,8 +188,53 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
efi_char16_t *name,
efi_guid_t *vendor)
{
- return efi_call_virt3(get_next_variable,
- name_size, name, vendor);
+ efi_status_t status;
+ static bool finished = false;
+ static u64 var_size;
+
+ status = efi_call_virt3(get_next_variable,
+ name_size, name, vendor);
+
+ if (status == EFI_NOT_FOUND) {
+ finished = true;
+ if (var_size < boot_used_size) {
+ boot_var_size = boot_used_size - var_size;
+ active_size += boot_var_size;
+ } else {
+ printk(KERN_WARNING FW_BUG "efi: Inconsistent initial sizes\n");
+ }
+ }
+
+ if (boot_used_size && !finished) {
+ unsigned long size;
+ u32 attr;
+ efi_status_t s;
+ void *tmp;
+
+ s = virt_efi_get_variable(name, vendor, &attr, &size, NULL);
+
+ if (s != EFI_BUFFER_TOO_SMALL || !size)
+ return status;
+
+ tmp = kmalloc(size, GFP_ATOMIC);
+
+ if (!tmp)
+ return status;
+
+ s = virt_efi_get_variable(name, vendor, &attr, &size, tmp);
+
+ if (s == EFI_SUCCESS && (attr & EFI_VARIABLE_NON_VOLATILE)) {
+ var_size += size;
+ var_size += ucs2_strsize(name, 1024);
+ active_size += size;
+ active_size += VAR_METADATA_SIZE;
+ active_size += ucs2_strsize(name, 1024);
+ }
+
+ kfree(tmp);
+ }
+
+ return status;
}
static efi_status_t virt_efi_set_variable(efi_char16_t *name,
@@ -173,9 +243,34 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
unsigned long data_size,
void *data)
{
- return efi_call_virt5(set_variable,
- name, vendor, attr,
- data_size, data);
+ efi_status_t status;
+ u32 orig_attr = 0;
+ unsigned long orig_size = 0;
+
+ status = virt_efi_get_variable(name, vendor, &orig_attr, &orig_size,
+ NULL);
+
+ if (status != EFI_BUFFER_TOO_SMALL)
+ orig_size = 0;
+
+ status = efi_call_virt5(set_variable,
+ name, vendor, attr,
+ data_size, data);
+
+ if (status == EFI_SUCCESS) {
+ if (orig_size) {
+ active_size -= orig_size;
+ active_size -= ucs2_strsize(name, 1024);
+ active_size -= VAR_METADATA_SIZE;
+ }
+ if (data_size) {
+ active_size += data_size;
+ active_size += ucs2_strsize(name, 1024);
+ active_size += VAR_METADATA_SIZE;
+ }
+ }
+
+ return status;
}
static efi_status_t virt_efi_query_variable_info(u32 attr,
@@ -259,10 +354,10 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
int efi_set_rtc_mmss(unsigned long nowtime)
{
- int real_seconds, real_minutes;
efi_status_t status;
efi_time_t eft;
efi_time_cap_t cap;
+ struct rtc_time tm;
status = efi.get_time(&eft, &cap);
if (status != EFI_SUCCESS) {
@@ -270,13 +365,20 @@ int efi_set_rtc_mmss(unsigned long nowtime)
return -1;
}
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
- real_minutes += 30;
- real_minutes %= 60;
- eft.minute = real_minutes;
- eft.second = real_seconds;
+ rtc_time_to_tm(nowtime, &tm);
+ if (!rtc_valid_tm(&tm)) {
+ eft.year = tm.tm_year + 1900;
+ eft.month = tm.tm_mon + 1;
+ eft.day = tm.tm_mday;
+ eft.minute = tm.tm_min;
+ eft.second = tm.tm_sec;
+ eft.nanosecond = 0;
+ } else {
+ printk(KERN_ERR
+ "%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
+ __FUNCTION__, nowtime);
+ return -1;
+ }
status = efi.set_time(&eft);
if (status != EFI_SUCCESS) {
@@ -352,24 +454,25 @@ static void __init do_add_efi_memmap(void)
int __init efi_memblock_x86_reserve_range(void)
{
+ struct efi_info *e = &boot_params.efi_info;
unsigned long pmap;
#ifdef CONFIG_X86_32
/* Can't handle data above 4GB at this time */
- if (boot_params.efi_info.efi_memmap_hi) {
+ if (e->efi_memmap_hi) {
pr_err("Memory map is above 4GB, disabling EFI.\n");
return -EINVAL;
}
- pmap = boot_params.efi_info.efi_memmap;
+ pmap = e->efi_memmap;
#else
- pmap = (boot_params.efi_info.efi_memmap |
- ((__u64)boot_params.efi_info.efi_memmap_hi<<32));
+ pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
#endif
- memmap.phys_map = (void *)pmap;
- memmap.nr_map = boot_params.efi_info.efi_memmap_size /
- boot_params.efi_info.efi_memdesc_size;
- memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
- memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
+ memmap.phys_map = (void *)pmap;
+ memmap.nr_map = e->efi_memmap_size /
+ e->efi_memdesc_size;
+ memmap.desc_size = e->efi_memdesc_size;
+ memmap.desc_version = e->efi_memdesc_version;
+
memblock_reserve(pmap, memmap.nr_map * memmap.desc_size);
return 0;
@@ -683,6 +786,9 @@ void __init efi_init(void)
char vendor[100] = "unknown";
int i = 0;
void *tmp;
+ struct setup_data *data;
+ struct efi_var_bootdata *efi_var_data;
+ u64 pa_data;
#ifdef CONFIG_X86_32
if (boot_params.efi_info.efi_systab_hi ||
@@ -700,6 +806,22 @@ void __init efi_init(void)
if (efi_systab_init(efi_phys.systab))
return;
+ pa_data = boot_params.hdr.setup_data;
+ while (pa_data) {
+ data = early_ioremap(pa_data, sizeof(*efi_var_data));
+ if (data->type == SETUP_EFI_VARS) {
+ efi_var_data = (struct efi_var_bootdata *)data;
+
+ efi_var_store_size = efi_var_data->store_size;
+ efi_var_remaining_size = efi_var_data->remaining_size;
+ efi_var_max_var_size = efi_var_data->max_var_size;
+ }
+ pa_data = data->next;
+ early_iounmap(data, sizeof(*efi_var_data));
+ }
+
+ boot_used_size = efi_var_store_size - efi_var_remaining_size;
+
set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
/*
@@ -1000,3 +1122,48 @@ u64 efi_mem_attributes(unsigned long phys_addr)
}
return 0;
}
+
+/*
+ * Some firmware has serious problems when using more than 50% of the EFI
+ * variable store, i.e. it triggers bugs that can brick machines. Ensure that
+ * we never use more than this safe limit.
+ *
+ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
+ * store.
+ */
+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+{
+ efi_status_t status;
+ u64 storage_size, remaining_size, max_size;
+
+ status = efi.query_variable_info(attributes, &storage_size,
+ &remaining_size, &max_size);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ if (!max_size && remaining_size > size)
+ printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
+ " is returning MaxVariableSize=0\n");
+ /*
+ * Some firmware implementations refuse to boot if there's insufficient
+ * space in the variable store. We account for that by refusing the
+ * write if permitting it would reduce the available space to under
+ * 50%. However, some firmware won't reclaim variable space until
+ * after the used (not merely the actively used) space drops below
+ * a threshold. We can approximate that case with the value calculated
+ * above. If both the firmware and our calculations indicate that the
+ * available space would drop below 50%, refuse the write.
+ */
+
+ if (!storage_size || size > remaining_size ||
+ (max_size && size > max_size))
+ return EFI_OUT_OF_RESOURCES;
+
+ if (!efi_no_storage_paranoia &&
+ ((active_size + size + VAR_METADATA_SIZE > storage_size / 2) &&
+ (remaining_size - size < storage_size / 2)))
+ return EFI_OUT_OF_RESOURCES;
+
+ return EFI_SUCCESS;
+}
+EXPORT_SYMBOL_GPL(efi_query_variable_store);
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index e31bcd8f2eee..a0a0a4389bbd 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -356,8 +356,7 @@ static int __init sfi_parse_gpio(struct sfi_table_header *table)
num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
pentry = (struct sfi_gpio_table_entry *)sb->pentry;
- gpio_table = (struct sfi_gpio_table_entry *)
- kmalloc(num * sizeof(*pentry), GFP_KERNEL);
+ gpio_table = kmalloc(num * sizeof(*pentry), GFP_KERNEL);
if (!gpio_table)
return -1;
memcpy(gpio_table, pentry, num * sizeof(*pentry));
diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c
index 225bd0f0f675..d62b0a3b5c14 100644
--- a/arch/x86/platform/mrst/vrtc.c
+++ b/arch/x86/platform/mrst/vrtc.c
@@ -85,27 +85,35 @@ unsigned long vrtc_get_time(void)
return mktime(year, mon, mday, hour, min, sec);
}
-/* Only care about the minutes and seconds */
int vrtc_set_mmss(unsigned long nowtime)
{
- int real_sec, real_min;
unsigned long flags;
- int vrtc_min;
-
- spin_lock_irqsave(&rtc_lock, flags);
- vrtc_min = vrtc_cmos_read(RTC_MINUTES);
-
- real_sec = nowtime % 60;
- real_min = nowtime / 60;
- if (((abs(real_min - vrtc_min) + 15)/30) & 1)
- real_min += 30;
- real_min %= 60;
-
- vrtc_cmos_write(real_sec, RTC_SECONDS);
- vrtc_cmos_write(real_min, RTC_MINUTES);
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return 0;
+ struct rtc_time tm;
+ int year;
+ int retval = 0;
+
+ rtc_time_to_tm(nowtime, &tm);
+ if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) {
+ /*
+ * tm.year is the number of years since 1900, and the
+ * vrtc need the years since 1972.
+ */
+ year = tm.tm_year - 72;
+ spin_lock_irqsave(&rtc_lock, flags);
+ vrtc_cmos_write(year, RTC_YEAR);
+ vrtc_cmos_write(tm.tm_mon, RTC_MONTH);
+ vrtc_cmos_write(tm.tm_mday, RTC_DAY_OF_MONTH);
+ vrtc_cmos_write(tm.tm_hour, RTC_HOURS);
+ vrtc_cmos_write(tm.tm_min, RTC_MINUTES);
+ vrtc_cmos_write(tm.tm_sec, RTC_SECONDS);
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ } else {
+ printk(KERN_ERR
+ "%s: Invalid vRTC value: write of %lx to vRTC failed\n",
+ __FUNCTION__, nowtime);
+ retval = -EINVAL;
+ }
+ return retval;
}
void __init mrst_rtc_init(void)
diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c
index 74704be7b1fe..9a2e590dd202 100644
--- a/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -460,7 +460,6 @@ static int setup_power_button(struct platform_device *pdev)
static void free_power_button(void)
{
input_unregister_device(power_button_idev);
- input_free_device(power_button_idev);
}
static int setup_ebook_switch(struct platform_device *pdev)
@@ -491,7 +490,6 @@ static int setup_ebook_switch(struct platform_device *pdev)
static void free_ebook_switch(void)
{
input_unregister_device(ebook_switch_idev);
- input_free_device(ebook_switch_idev);
}
static int setup_lid_switch(struct platform_device *pdev)
@@ -526,6 +524,7 @@ static int setup_lid_switch(struct platform_device *pdev)
err_create_attr:
input_unregister_device(lid_switch_idev);
+ lid_switch_idev = NULL;
err_register:
input_free_device(lid_switch_idev);
return r;
@@ -535,7 +534,6 @@ static void free_lid_switch(void)
{
device_remove_file(&lid_switch_idev->dev, &dev_attr_lid_wake_mode);
input_unregister_device(lid_switch_idev);
- input_free_device(lid_switch_idev);
}
static int xo1_sci_probe(struct platform_device *pdev)
diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c
index 98718f604eb6..5c86786bbfd2 100644
--- a/arch/x86/platform/uv/uv_time.c
+++ b/arch/x86/platform/uv/uv_time.c
@@ -159,10 +159,9 @@ static __init int uv_rtc_allocate_timers(void)
{
int cpu;
- blade_info = kmalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL);
+ blade_info = kzalloc(uv_possible_blades * sizeof(void *), GFP_KERNEL);
if (!blade_info)
return -ENOMEM;
- memset(blade_info, 0, uv_possible_blades * sizeof(void *));
for_each_present_cpu(cpu) {
int nid = cpu_to_node(cpu);
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 3c68768d7a75..6d6e907cee46 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -62,11 +62,9 @@ static void __save_processor_state(struct saved_context *ctxt)
* descriptor tables
*/
#ifdef CONFIG_X86_32
- store_gdt(&ctxt->gdt);
store_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- store_gdt((struct desc_ptr *)&ctxt->gdt_limit);
store_idt((struct desc_ptr *)&ctxt->idt_limit);
#endif
store_tr(ctxt->tr);
@@ -135,7 +133,10 @@ static void fix_processor_context(void)
{
int cpu = smp_processor_id();
struct tss_struct *t = &per_cpu(init_tss, cpu);
-
+#ifdef CONFIG_X86_64
+ struct desc_struct *desc = get_cpu_gdt_table(cpu);
+ tss_desc tss;
+#endif
set_tss_desc(cpu, t); /*
* This just modifies memory; should not be
* necessary. But... This is necessary, because
@@ -144,7 +145,9 @@ static void fix_processor_context(void)
*/
#ifdef CONFIG_X86_64
- get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9;
+ memcpy(&tss, &desc[GDT_ENTRY_TSS], sizeof(tss_desc));
+ tss.type = 0x9; /* The available 64-bit TSS (see AMD vol 2, pg 91 */
+ write_gdt_entry(desc, GDT_ENTRY_TSS, &tss, DESC_TSS);
syscall_init(); /* This sets MSR_*STAR and related */
#endif
@@ -183,11 +186,9 @@ static void __restore_processor_state(struct saved_context *ctxt)
* ltr is done i fix_processor_context().
*/
#ifdef CONFIG_X86_32
- load_gdt(&ctxt->gdt);
load_idt(&ctxt->idt);
#else
/* CONFIG_X86_64 */
- load_gdt((const struct desc_ptr *)&ctxt->gdt_limit);
load_idt((const struct desc_ptr *)&ctxt->idt_limit);
#endif
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index e6d55f0064df..d0d59bfbccce 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -43,7 +43,7 @@
34 i386 nice sys_nice
35 i386 ftime
36 i386 sync sys_sync
-37 i386 kill sys_kill sys32_kill
+37 i386 kill sys_kill
38 i386 rename sys_rename
39 i386 mkdir sys_mkdir
40 i386 rmdir sys_rmdir
@@ -123,7 +123,7 @@
114 i386 wait4 sys_wait4 compat_sys_wait4
115 i386 swapoff sys_swapoff
116 i386 sysinfo sys_sysinfo compat_sys_sysinfo
-117 i386 ipc sys_ipc sys32_ipc
+117 i386 ipc sys_ipc compat_sys_ipc
118 i386 fsync sys_fsync
119 i386 sigreturn sys_sigreturn stub32_sigreturn
120 i386 clone sys_clone stub32_clone
@@ -131,7 +131,7 @@
122 i386 uname sys_newuname
123 i386 modify_ldt sys_modify_ldt
124 i386 adjtimex sys_adjtimex compat_sys_adjtimex
-125 i386 mprotect sys_mprotect sys32_mprotect
+125 i386 mprotect sys_mprotect
126 i386 sigprocmask sys_sigprocmask compat_sys_sigprocmask
127 i386 create_module
128 i386 init_module sys_init_module
@@ -193,7 +193,7 @@
184 i386 capget sys_capget
185 i386 capset sys_capset
186 i386 sigaltstack sys_sigaltstack compat_sys_sigaltstack
-187 i386 sendfile sys_sendfile sys32_sendfile
+187 i386 sendfile sys_sendfile compat_sys_sendfile
188 i386 getpmsg
189 i386 putpmsg
190 i386 vfork sys_vfork stub32_vfork
@@ -259,7 +259,7 @@
250 i386 fadvise64 sys_fadvise64 sys32_fadvise64
# 251 is available for reuse (was briefly sys_set_zone_reclaim)
252 i386 exit_group sys_exit_group
-253 i386 lookup_dcookie sys_lookup_dcookie sys32_lookup_dcookie
+253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
254 i386 epoll_create sys_epoll_create
255 i386 epoll_ctl sys_epoll_ctl
256 i386 epoll_wait sys_epoll_wait
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index bae601f900ef..e8120346903b 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -39,4 +39,5 @@ $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/ina
HOST_EXTRACFLAGS += -I$(srctree)/tools/include
hostprogs-y += relocs
+relocs-objs := relocs_32.o relocs_64.o relocs_common.o
relocs: $(obj)/relocs
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 79d67bd507fa..590be1090892 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -1,43 +1,36 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <elf.h>
-#include <byteswap.h>
-#define USE_BSD
-#include <endian.h>
-#include <regex.h>
-#include <tools/le_byteshift.h>
-
-static void die(char *fmt, ...);
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-static Elf32_Ehdr ehdr;
-static unsigned long reloc_count, reloc_idx;
-static unsigned long *relocs;
-static unsigned long reloc16_count, reloc16_idx;
-static unsigned long *relocs16;
+/* This is included from relocs_32/64.c */
+
+#define ElfW(type) _ElfW(ELF_BITS, type)
+#define _ElfW(bits, type) __ElfW(bits, type)
+#define __ElfW(bits, type) Elf##bits##_##type
+
+#define Elf_Addr ElfW(Addr)
+#define Elf_Ehdr ElfW(Ehdr)
+#define Elf_Phdr ElfW(Phdr)
+#define Elf_Shdr ElfW(Shdr)
+#define Elf_Sym ElfW(Sym)
+
+static Elf_Ehdr ehdr;
+
+struct relocs {
+ uint32_t *offset;
+ unsigned long count;
+ unsigned long size;
+};
+
+static struct relocs relocs16;
+static struct relocs relocs32;
+static struct relocs relocs64;
struct section {
- Elf32_Shdr shdr;
+ Elf_Shdr shdr;
struct section *link;
- Elf32_Sym *symtab;
- Elf32_Rel *reltab;
+ Elf_Sym *symtab;
+ Elf_Rel *reltab;
char *strtab;
};
static struct section *secs;
-enum symtype {
- S_ABS,
- S_REL,
- S_SEG,
- S_LIN,
- S_NSYMTYPES
-};
-
static const char * const sym_regex_kernel[S_NSYMTYPES] = {
/*
* Following symbols have been audited. There values are constant and do
@@ -49,6 +42,9 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"^(xen_irq_disable_direct_reloc$|"
"xen_save_fl_direct_reloc$|"
"VDSO|"
+#if ELF_BITS == 64
+ "__vvar_page|"
+#endif
"__crc_)",
/*
@@ -72,6 +68,11 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__end_rodata|"
"__initramfs_start|"
"(jiffies|jiffies_64)|"
+#if ELF_BITS == 64
+ "__per_cpu_load|"
+ "init_per_cpu__.*|"
+ "__end_rodata_hpage_align|"
+#endif
"_end)$"
};
@@ -132,15 +133,6 @@ static void regex_init(int use_real_mode)
}
}
-static void die(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- exit(1);
-}
-
static const char *sym_type(unsigned type)
{
static const char *type_name[] = {
@@ -198,6 +190,24 @@ static const char *rel_type(unsigned type)
{
static const char *type_name[] = {
#define REL_TYPE(X) [X] = #X
+#if ELF_BITS == 64
+ REL_TYPE(R_X86_64_NONE),
+ REL_TYPE(R_X86_64_64),
+ REL_TYPE(R_X86_64_PC32),
+ REL_TYPE(R_X86_64_GOT32),
+ REL_TYPE(R_X86_64_PLT32),
+ REL_TYPE(R_X86_64_COPY),
+ REL_TYPE(R_X86_64_GLOB_DAT),
+ REL_TYPE(R_X86_64_JUMP_SLOT),
+ REL_TYPE(R_X86_64_RELATIVE),
+ REL_TYPE(R_X86_64_GOTPCREL),
+ REL_TYPE(R_X86_64_32),
+ REL_TYPE(R_X86_64_32S),
+ REL_TYPE(R_X86_64_16),
+ REL_TYPE(R_X86_64_PC16),
+ REL_TYPE(R_X86_64_8),
+ REL_TYPE(R_X86_64_PC8),
+#else
REL_TYPE(R_386_NONE),
REL_TYPE(R_386_32),
REL_TYPE(R_386_PC32),
@@ -213,6 +223,7 @@ static const char *rel_type(unsigned type)
REL_TYPE(R_386_PC8),
REL_TYPE(R_386_16),
REL_TYPE(R_386_PC16),
+#endif
#undef REL_TYPE
};
const char *name = "unknown type rel type name";
@@ -240,7 +251,7 @@ static const char *sec_name(unsigned shndx)
return name;
}
-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
{
const char *name;
name = "<noname>";
@@ -253,15 +264,42 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
return name;
}
+static Elf_Sym *sym_lookup(const char *symname)
+{
+ int i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ long nsyms;
+ char *strtab;
+ Elf_Sym *symtab;
+ Elf_Sym *sym;
+
+ if (sec->shdr.sh_type != SHT_SYMTAB)
+ continue;
+ nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
+ symtab = sec->symtab;
+ strtab = sec->link->strtab;
+
+ for (sym = symtab; --nsyms >= 0; sym++) {
+ if (!sym->st_name)
+ continue;
+ if (strcmp(symname, strtab + sym->st_name) == 0)
+ return sym;
+ }
+ }
+ return 0;
+}
#if BYTE_ORDER == LITTLE_ENDIAN
#define le16_to_cpu(val) (val)
#define le32_to_cpu(val) (val)
+#define le64_to_cpu(val) (val)
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define le16_to_cpu(val) bswap_16(val)
#define le32_to_cpu(val) bswap_32(val)
+#define le64_to_cpu(val) bswap_64(val)
#endif
static uint16_t elf16_to_cpu(uint16_t val)
@@ -274,6 +312,23 @@ static uint32_t elf32_to_cpu(uint32_t val)
return le32_to_cpu(val);
}
+#define elf_half_to_cpu(x) elf16_to_cpu(x)
+#define elf_word_to_cpu(x) elf32_to_cpu(x)
+
+#if ELF_BITS == 64
+static uint64_t elf64_to_cpu(uint64_t val)
+{
+ return le64_to_cpu(val);
+}
+#define elf_addr_to_cpu(x) elf64_to_cpu(x)
+#define elf_off_to_cpu(x) elf64_to_cpu(x)
+#define elf_xword_to_cpu(x) elf64_to_cpu(x)
+#else
+#define elf_addr_to_cpu(x) elf32_to_cpu(x)
+#define elf_off_to_cpu(x) elf32_to_cpu(x)
+#define elf_xword_to_cpu(x) elf32_to_cpu(x)
+#endif
+
static void read_ehdr(FILE *fp)
{
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@@ -283,8 +338,8 @@ static void read_ehdr(FILE *fp)
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
die("No ELF magic\n");
}
- if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
- die("Not a 32 bit executable\n");
+ if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
+ die("Not a %d bit executable\n", ELF_BITS);
}
if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
die("Not a LSB ELF executable\n");
@@ -293,36 +348,36 @@ static void read_ehdr(FILE *fp)
die("Unknown ELF version\n");
}
/* Convert the fields to native endian */
- ehdr.e_type = elf16_to_cpu(ehdr.e_type);
- ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
- ehdr.e_version = elf32_to_cpu(ehdr.e_version);
- ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
- ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
- ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
- ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
- ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
- ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
- ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
- ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
- ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
- ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
+ ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
+ ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
+ ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
+ ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
+ ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
+ ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
+ ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
+ ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
+ ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
+ ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
+ ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
+ ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
+ ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
die("Unsupported ELF header type\n");
}
- if (ehdr.e_machine != EM_386) {
- die("Not for x86\n");
+ if (ehdr.e_machine != ELF_MACHINE) {
+ die("Not for %s\n", ELF_MACHINE_NAME);
}
if (ehdr.e_version != EV_CURRENT) {
die("Unknown ELF version\n");
}
- if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+ if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) {
die("Bad Elf header size\n");
}
- if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+ if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
die("Bad program header entry\n");
}
- if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+ if (ehdr.e_shentsize != sizeof(Elf_Shdr)) {
die("Bad section header entry\n");
}
if (ehdr.e_shstrndx >= ehdr.e_shnum) {
@@ -333,7 +388,7 @@ static void read_ehdr(FILE *fp)
static void read_shdrs(FILE *fp)
{
int i;
- Elf32_Shdr shdr;
+ Elf_Shdr shdr;
secs = calloc(ehdr.e_shnum, sizeof(struct section));
if (!secs) {
@@ -349,16 +404,16 @@ static void read_shdrs(FILE *fp)
if (fread(&shdr, sizeof shdr, 1, fp) != 1)
die("Cannot read ELF section headers %d/%d: %s\n",
i, ehdr.e_shnum, strerror(errno));
- sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
- sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
- sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
- sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
- sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
- sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
- sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
- sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
- sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
- sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
+ sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
+ sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
+ sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
+ sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
+ sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
+ sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
+ sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
+ sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
+ sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
+ sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
if (sec->shdr.sh_link < ehdr.e_shnum)
sec->link = &secs[sec->shdr.sh_link];
}
@@ -412,12 +467,12 @@ static void read_symtabs(FILE *fp)
die("Cannot read symbol table: %s\n",
strerror(errno));
}
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym = &sec->symtab[j];
- sym->st_name = elf32_to_cpu(sym->st_name);
- sym->st_value = elf32_to_cpu(sym->st_value);
- sym->st_size = elf32_to_cpu(sym->st_size);
- sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+ Elf_Sym *sym = &sec->symtab[j];
+ sym->st_name = elf_word_to_cpu(sym->st_name);
+ sym->st_value = elf_addr_to_cpu(sym->st_value);
+ sym->st_size = elf_xword_to_cpu(sym->st_size);
+ sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
}
}
}
@@ -428,7 +483,7 @@ static void read_relocs(FILE *fp)
int i,j;
for (i = 0; i < ehdr.e_shnum; i++) {
struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_REL) {
+ if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec->reltab = malloc(sec->shdr.sh_size);
@@ -445,10 +500,13 @@ static void read_relocs(FILE *fp)
die("Cannot read symbol table: %s\n",
strerror(errno));
}
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel = &sec->reltab[j];
- rel->r_offset = elf32_to_cpu(rel->r_offset);
- rel->r_info = elf32_to_cpu(rel->r_info);
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+ Elf_Rel *rel = &sec->reltab[j];
+ rel->r_offset = elf_addr_to_cpu(rel->r_offset);
+ rel->r_info = elf_xword_to_cpu(rel->r_info);
+#if (SHT_REL_TYPE == SHT_RELA)
+ rel->r_addend = elf_xword_to_cpu(rel->r_addend);
+#endif
}
}
}
@@ -457,6 +515,13 @@ static void read_relocs(FILE *fp)
static void print_absolute_symbols(void)
{
int i;
+ const char *format;
+
+ if (ELF_BITS == 64)
+ format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
+ else
+ format = "%5d %08"PRIx32" %5"PRId32" %10s %10s %12s %s\n";
+
printf("Absolute symbols\n");
printf(" Num: Value Size Type Bind Visibility Name\n");
for (i = 0; i < ehdr.e_shnum; i++) {
@@ -468,19 +533,19 @@ static void print_absolute_symbols(void)
continue;
}
sym_strtab = sec->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
- Elf32_Sym *sym;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+ Elf_Sym *sym;
const char *name;
sym = &sec->symtab[j];
name = sym_name(sym_strtab, sym);
if (sym->st_shndx != SHN_ABS) {
continue;
}
- printf("%5d %08x %5d %10s %10s %12s %s\n",
+ printf(format,
j, sym->st_value, sym->st_size,
- sym_type(ELF32_ST_TYPE(sym->st_info)),
- sym_bind(ELF32_ST_BIND(sym->st_info)),
- sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+ sym_type(ELF_ST_TYPE(sym->st_info)),
+ sym_bind(ELF_ST_BIND(sym->st_info)),
+ sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
name);
}
}
@@ -490,14 +555,20 @@ static void print_absolute_symbols(void)
static void print_absolute_relocs(void)
{
int i, printed = 0;
+ const char *format;
+
+ if (ELF_BITS == 64)
+ format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64" %s\n";
+ else
+ format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32" %s\n";
for (i = 0; i < ehdr.e_shnum; i++) {
struct section *sec = &secs[i];
struct section *sec_applies, *sec_symtab;
char *sym_strtab;
- Elf32_Sym *sh_symtab;
+ Elf_Sym *sh_symtab;
int j;
- if (sec->shdr.sh_type != SHT_REL) {
+ if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec_symtab = sec->link;
@@ -507,12 +578,12 @@ static void print_absolute_relocs(void)
}
sh_symtab = sec_symtab->symtab;
sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+ Elf_Rel *rel;
+ Elf_Sym *sym;
const char *name;
rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
name = sym_name(sym_strtab, sym);
if (sym->st_shndx != SHN_ABS) {
continue;
@@ -542,10 +613,10 @@ static void print_absolute_relocs(void)
printed = 1;
}
- printf("%08x %08x %10s %08x %s\n",
+ printf(format,
rel->r_offset,
rel->r_info,
- rel_type(ELF32_R_TYPE(rel->r_info)),
+ rel_type(ELF_R_TYPE(rel->r_info)),
sym->st_value,
name);
}
@@ -555,19 +626,34 @@ static void print_absolute_relocs(void)
printf("\n");
}
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
- int use_real_mode)
+static void add_reloc(struct relocs *r, uint32_t offset)
+{
+ if (r->count == r->size) {
+ unsigned long newsize = r->size + 50000;
+ void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
+
+ if (!mem)
+ die("realloc of %ld entries for relocs failed\n",
+ newsize);
+ r->offset = mem;
+ r->size = newsize;
+ }
+ r->offset[r->count++] = offset;
+}
+
+static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
+ Elf_Sym *sym, const char *symname))
{
int i;
/* Walk through the relocations */
for (i = 0; i < ehdr.e_shnum; i++) {
char *sym_strtab;
- Elf32_Sym *sh_symtab;
+ Elf_Sym *sh_symtab;
struct section *sec_applies, *sec_symtab;
int j;
struct section *sec = &secs[i];
- if (sec->shdr.sh_type != SHT_REL) {
+ if (sec->shdr.sh_type != SHT_REL_TYPE) {
continue;
}
sec_symtab = sec->link;
@@ -577,101 +663,281 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
}
sh_symtab = sec_symtab->symtab;
sym_strtab = sec_symtab->link->strtab;
- for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
- Elf32_Rel *rel;
- Elf32_Sym *sym;
- unsigned r_type;
- const char *symname;
- int shn_abs;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+ Elf_Rel *rel = &sec->reltab[j];
+ Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
+ const char *symname = sym_name(sym_strtab, sym);
- rel = &sec->reltab[j];
- sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
- r_type = ELF32_R_TYPE(rel->r_info);
-
- shn_abs = sym->st_shndx == SHN_ABS;
-
- switch (r_type) {
- case R_386_NONE:
- case R_386_PC32:
- case R_386_PC16:
- case R_386_PC8:
- /*
- * NONE can be ignored and and PC relative
- * relocations don't need to be adjusted.
- */
- break;
+ process(sec, rel, sym, symname);
+ }
+ }
+}
- case R_386_16:
- symname = sym_name(sym_strtab, sym);
- if (!use_real_mode)
- goto bad;
- if (shn_abs) {
- if (is_reloc(S_ABS, symname))
- break;
- else if (!is_reloc(S_SEG, symname))
- goto bad;
- } else {
- if (is_reloc(S_LIN, symname))
- goto bad;
- else
- break;
- }
- visit(rel, sym);
- break;
+/*
+ * The .data..percpu section is a special case for x86_64 SMP kernels.
+ * It is used to initialize the actual per_cpu areas and to provide
+ * definitions for the per_cpu variables that correspond to their offsets
+ * within the percpu area. Since the values of all of the symbols need
+ * to be offsets from the start of the per_cpu area the virtual address
+ * (sh_addr) of .data..percpu is 0 in SMP kernels.
+ *
+ * This means that:
+ *
+ * Relocations that reference symbols in the per_cpu area do not
+ * need further relocation (since the value is an offset relative
+ * to the start of the per_cpu area that does not change).
+ *
+ * Relocations that apply to the per_cpu area need to have their
+ * offset adjusted by by the value of __per_cpu_load to make them
+ * point to the correct place in the loaded image (because the
+ * virtual address of .data..percpu is 0).
+ *
+ * For non SMP kernels .data..percpu is linked as part of the normal
+ * kernel data and does not require special treatment.
+ *
+ */
+static int per_cpu_shndx = -1;
+Elf_Addr per_cpu_load_addr;
- case R_386_32:
- symname = sym_name(sym_strtab, sym);
- if (shn_abs) {
- if (is_reloc(S_ABS, symname))
- break;
- else if (!is_reloc(S_REL, symname))
- goto bad;
- } else {
- if (use_real_mode &&
- !is_reloc(S_LIN, symname))
- break;
- }
- visit(rel, sym);
- break;
- default:
- die("Unsupported relocation type: %s (%d)\n",
- rel_type(r_type), r_type);
+static void percpu_init(void)
+{
+ int i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ ElfW(Sym) *sym;
+ if (strcmp(sec_name(i), ".data..percpu"))
+ continue;
+
+ if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */
+ return;
+
+ sym = sym_lookup("__per_cpu_load");
+ if (!sym)
+ die("can't find __per_cpu_load\n");
+
+ per_cpu_shndx = i;
+ per_cpu_load_addr = sym->st_value;
+ return;
+ }
+}
+
+#if ELF_BITS == 64
+
+/*
+ * Check to see if a symbol lies in the .data..percpu section.
+ * For some as yet not understood reason the "__init_begin"
+ * symbol which immediately preceeds the .data..percpu section
+ * also shows up as it it were part of it so we do an explict
+ * check for that symbol name and ignore it.
+ */
+static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
+{
+ return (sym->st_shndx == per_cpu_shndx) &&
+ strcmp(symname, "__init_begin");
+}
+
+
+static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
+ const char *symname)
+{
+ unsigned r_type = ELF64_R_TYPE(rel->r_info);
+ ElfW(Addr) offset = rel->r_offset;
+ int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+ if (sym->st_shndx == SHN_UNDEF)
+ return 0;
+
+ /*
+ * Adjust the offset if this reloc applies to the percpu section.
+ */
+ if (sec->shdr.sh_info == per_cpu_shndx)
+ offset += per_cpu_load_addr;
+
+ switch (r_type) {
+ case R_X86_64_NONE:
+ case R_X86_64_PC32:
+ /*
+ * NONE can be ignored and PC relative relocations don't
+ * need to be adjusted.
+ */
+ break;
+
+ case R_X86_64_32:
+ case R_X86_64_32S:
+ case R_X86_64_64:
+ /*
+ * References to the percpu area don't need to be adjusted.
+ */
+ if (is_percpu_sym(sym, symname))
+ break;
+
+ if (shn_abs) {
+ /*
+ * Whitelisted absolute symbols do not require
+ * relocation.
+ */
+ if (is_reloc(S_ABS, symname))
break;
- bad:
- symname = sym_name(sym_strtab, sym);
- die("Invalid %s %s relocation: %s\n",
- shn_abs ? "absolute" : "relative",
- rel_type(r_type), symname);
- }
+
+ die("Invalid absolute %s relocation: %s\n",
+ rel_type(r_type), symname);
+ break;
}
+
+ /*
+ * Relocation offsets for 64 bit kernels are output
+ * as 32 bits and sign extended back to 64 bits when
+ * the relocations are processed.
+ * Make sure that the offset will fit.
+ */
+ if ((int32_t)offset != (int64_t)offset)
+ die("Relocation offset doesn't fit in 32 bits\n");
+
+ if (r_type == R_X86_64_64)
+ add_reloc(&relocs64, offset);
+ else
+ add_reloc(&relocs32, offset);
+ break;
+
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ break;
}
+
+ return 0;
}
-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+#else
+
+static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+ const char *symname)
{
- if (ELF32_R_TYPE(rel->r_info) == R_386_16)
- reloc16_count++;
- else
- reloc_count++;
+ unsigned r_type = ELF32_R_TYPE(rel->r_info);
+ int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+ switch (r_type) {
+ case R_386_NONE:
+ case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
+ /*
+ * NONE can be ignored and PC relative relocations don't
+ * need to be adjusted.
+ */
+ break;
+
+ case R_386_32:
+ if (shn_abs) {
+ /*
+ * Whitelisted absolute symbols do not require
+ * relocation.
+ */
+ if (is_reloc(S_ABS, symname))
+ break;
+
+ die("Invalid absolute %s relocation: %s\n",
+ rel_type(r_type), symname);
+ break;
+ }
+
+ add_reloc(&relocs32, rel->r_offset);
+ break;
+
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ break;
+ }
+
+ return 0;
}
-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+ const char *symname)
{
- /* Remember the address that needs to be adjusted. */
- if (ELF32_R_TYPE(rel->r_info) == R_386_16)
- relocs16[reloc16_idx++] = rel->r_offset;
- else
- relocs[reloc_idx++] = rel->r_offset;
+ unsigned r_type = ELF32_R_TYPE(rel->r_info);
+ int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+ switch (r_type) {
+ case R_386_NONE:
+ case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
+ /*
+ * NONE can be ignored and PC relative relocations don't
+ * need to be adjusted.
+ */
+ break;
+
+ case R_386_16:
+ if (shn_abs) {
+ /*
+ * Whitelisted absolute symbols do not require
+ * relocation.
+ */
+ if (is_reloc(S_ABS, symname))
+ break;
+
+ if (is_reloc(S_SEG, symname)) {
+ add_reloc(&relocs16, rel->r_offset);
+ break;
+ }
+ } else {
+ if (!is_reloc(S_LIN, symname))
+ break;
+ }
+ die("Invalid %s %s relocation: %s\n",
+ shn_abs ? "absolute" : "relative",
+ rel_type(r_type), symname);
+ break;
+
+ case R_386_32:
+ if (shn_abs) {
+ /*
+ * Whitelisted absolute symbols do not require
+ * relocation.
+ */
+ if (is_reloc(S_ABS, symname))
+ break;
+
+ if (is_reloc(S_REL, symname)) {
+ add_reloc(&relocs32, rel->r_offset);
+ break;
+ }
+ } else {
+ if (is_reloc(S_LIN, symname))
+ add_reloc(&relocs32, rel->r_offset);
+ break;
+ }
+ die("Invalid %s %s relocation: %s\n",
+ shn_abs ? "absolute" : "relative",
+ rel_type(r_type), symname);
+ break;
+
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ break;
+ }
+
+ return 0;
}
+#endif
+
static int cmp_relocs(const void *va, const void *vb)
{
- const unsigned long *a, *b;
+ const uint32_t *a, *b;
a = va; b = vb;
return (*a == *b)? 0 : (*a > *b)? 1 : -1;
}
-static int write32(unsigned int v, FILE *f)
+static void sort_relocs(struct relocs *r)
+{
+ qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
+}
+
+static int write32(uint32_t v, FILE *f)
{
unsigned char buf[4];
@@ -679,33 +945,40 @@ static int write32(unsigned int v, FILE *f)
return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
}
+static int write32_as_text(uint32_t v, FILE *f)
+{
+ return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
+}
+
static void emit_relocs(int as_text, int use_real_mode)
{
int i;
- /* Count how many relocations I have and allocate space for them. */
- reloc_count = 0;
- walk_relocs(count_reloc, use_real_mode);
- relocs = malloc(reloc_count * sizeof(relocs[0]));
- if (!relocs) {
- die("malloc of %d entries for relocs failed\n",
- reloc_count);
- }
+ int (*write_reloc)(uint32_t, FILE *) = write32;
+ int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+ const char *symname);
+
+#if ELF_BITS == 64
+ if (!use_real_mode)
+ do_reloc = do_reloc64;
+ else
+ die("--realmode not valid for a 64-bit ELF file");
+#else
+ if (!use_real_mode)
+ do_reloc = do_reloc32;
+ else
+ do_reloc = do_reloc_real;
+#endif
- relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
- if (!relocs16) {
- die("malloc of %d entries for relocs16 failed\n",
- reloc16_count);
- }
/* Collect up the relocations */
- reloc_idx = 0;
- walk_relocs(collect_reloc, use_real_mode);
+ walk_relocs(do_reloc);
- if (reloc16_count && !use_real_mode)
+ if (relocs16.count && !use_real_mode)
die("Segment relocations found but --realmode not specified\n");
/* Order the relocations for more efficient processing */
- qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
- qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
+ sort_relocs(&relocs16);
+ sort_relocs(&relocs32);
+ sort_relocs(&relocs64);
/* Print the relocations */
if (as_text) {
@@ -714,114 +987,60 @@ static void emit_relocs(int as_text, int use_real_mode)
*/
printf(".section \".data.reloc\",\"a\"\n");
printf(".balign 4\n");
- if (use_real_mode) {
- printf("\t.long %lu\n", reloc16_count);
- for (i = 0; i < reloc16_count; i++)
- printf("\t.long 0x%08lx\n", relocs16[i]);
- printf("\t.long %lu\n", reloc_count);
- for (i = 0; i < reloc_count; i++) {
- printf("\t.long 0x%08lx\n", relocs[i]);
- }
- } else {
- /* Print a stop */
- printf("\t.long 0x%08lx\n", (unsigned long)0);
- for (i = 0; i < reloc_count; i++) {
- printf("\t.long 0x%08lx\n", relocs[i]);
- }
- }
-
- printf("\n");
+ write_reloc = write32_as_text;
}
- else {
- if (use_real_mode) {
- write32(reloc16_count, stdout);
- for (i = 0; i < reloc16_count; i++)
- write32(relocs16[i], stdout);
- write32(reloc_count, stdout);
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++)
- write32(relocs[i], stdout);
- } else {
+ if (use_real_mode) {
+ write_reloc(relocs16.count, stdout);
+ for (i = 0; i < relocs16.count; i++)
+ write_reloc(relocs16.offset[i], stdout);
+
+ write_reloc(relocs32.count, stdout);
+ for (i = 0; i < relocs32.count; i++)
+ write_reloc(relocs32.offset[i], stdout);
+ } else {
+ if (ELF_BITS == 64) {
/* Print a stop */
- write32(0, stdout);
+ write_reloc(0, stdout);
/* Now print each relocation */
- for (i = 0; i < reloc_count; i++) {
- write32(relocs[i], stdout);
- }
+ for (i = 0; i < relocs64.count; i++)
+ write_reloc(relocs64.offset[i], stdout);
}
+
+ /* Print a stop */
+ write_reloc(0, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < relocs32.count; i++)
+ write_reloc(relocs32.offset[i], stdout);
}
}
-static void usage(void)
-{
- die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
-}
+#if ELF_BITS == 64
+# define process process_64
+#else
+# define process process_32
+#endif
-int main(int argc, char **argv)
+void process(FILE *fp, int use_real_mode, int as_text,
+ int show_absolute_syms, int show_absolute_relocs)
{
- int show_absolute_syms, show_absolute_relocs;
- int as_text, use_real_mode;
- const char *fname;
- FILE *fp;
- int i;
-
- show_absolute_syms = 0;
- show_absolute_relocs = 0;
- as_text = 0;
- use_real_mode = 0;
- fname = NULL;
- for (i = 1; i < argc; i++) {
- char *arg = argv[i];
- if (*arg == '-') {
- if (strcmp(arg, "--abs-syms") == 0) {
- show_absolute_syms = 1;
- continue;
- }
- if (strcmp(arg, "--abs-relocs") == 0) {
- show_absolute_relocs = 1;
- continue;
- }
- if (strcmp(arg, "--text") == 0) {
- as_text = 1;
- continue;
- }
- if (strcmp(arg, "--realmode") == 0) {
- use_real_mode = 1;
- continue;
- }
- }
- else if (!fname) {
- fname = arg;
- continue;
- }
- usage();
- }
- if (!fname) {
- usage();
- }
regex_init(use_real_mode);
- fp = fopen(fname, "r");
- if (!fp) {
- die("Cannot open %s: %s\n",
- fname, strerror(errno));
- }
read_ehdr(fp);
read_shdrs(fp);
read_strtabs(fp);
read_symtabs(fp);
read_relocs(fp);
+ if (ELF_BITS == 64)
+ percpu_init();
if (show_absolute_syms) {
print_absolute_symbols();
- goto out;
+ return;
}
if (show_absolute_relocs) {
print_absolute_relocs();
- goto out;
+ return;
}
emit_relocs(as_text, use_real_mode);
-out:
- fclose(fp);
- return 0;
}
diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h
new file mode 100644
index 000000000000..07cdb1eca4fa
--- /dev/null
+++ b/arch/x86/tools/relocs.h
@@ -0,0 +1,36 @@
+#ifndef RELOCS_H
+#define RELOCS_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+#include <regex.h>
+#include <tools/le_byteshift.h>
+
+void die(char *fmt, ...);
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+enum symtype {
+ S_ABS,
+ S_REL,
+ S_SEG,
+ S_LIN,
+ S_NSYMTYPES
+};
+
+void process_32(FILE *fp, int use_real_mode, int as_text,
+ int show_absolute_syms, int show_absolute_relocs);
+void process_64(FILE *fp, int use_real_mode, int as_text,
+ int show_absolute_syms, int show_absolute_relocs);
+
+#endif /* RELOCS_H */
diff --git a/arch/x86/tools/relocs_32.c b/arch/x86/tools/relocs_32.c
new file mode 100644
index 000000000000..b2ade2bb4162
--- /dev/null
+++ b/arch/x86/tools/relocs_32.c
@@ -0,0 +1,17 @@
+#include "relocs.h"
+
+#define ELF_BITS 32
+
+#define ELF_MACHINE EM_386
+#define ELF_MACHINE_NAME "i386"
+#define SHT_REL_TYPE SHT_REL
+#define Elf_Rel ElfW(Rel)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_R_SYM(val) ELF32_R_SYM(val)
+#define ELF_R_TYPE(val) ELF32_R_TYPE(val)
+#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o)
+#define ELF_ST_BIND(o) ELF32_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
+
+#include "relocs.c"
diff --git a/arch/x86/tools/relocs_64.c b/arch/x86/tools/relocs_64.c
new file mode 100644
index 000000000000..56b61b743c4c
--- /dev/null
+++ b/arch/x86/tools/relocs_64.c
@@ -0,0 +1,17 @@
+#include "relocs.h"
+
+#define ELF_BITS 64
+
+#define ELF_MACHINE EM_X86_64
+#define ELF_MACHINE_NAME "x86_64"
+#define SHT_REL_TYPE SHT_RELA
+#define Elf_Rel Elf64_Rela
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_R_SYM(val) ELF64_R_SYM(val)
+#define ELF_R_TYPE(val) ELF64_R_TYPE(val)
+#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o)
+#define ELF_ST_BIND(o) ELF64_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
+
+#include "relocs.c"
diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c
new file mode 100644
index 000000000000..44d396823a53
--- /dev/null
+++ b/arch/x86/tools/relocs_common.c
@@ -0,0 +1,76 @@
+#include "relocs.h"
+
+void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+static void usage(void)
+{
+ die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+ int show_absolute_syms, show_absolute_relocs;
+ int as_text, use_real_mode;
+ const char *fname;
+ FILE *fp;
+ int i;
+ unsigned char e_ident[EI_NIDENT];
+
+ show_absolute_syms = 0;
+ show_absolute_relocs = 0;
+ as_text = 0;
+ use_real_mode = 0;
+ fname = NULL;
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+ if (*arg == '-') {
+ if (strcmp(arg, "--abs-syms") == 0) {
+ show_absolute_syms = 1;
+ continue;
+ }
+ if (strcmp(arg, "--abs-relocs") == 0) {
+ show_absolute_relocs = 1;
+ continue;
+ }
+ if (strcmp(arg, "--text") == 0) {
+ as_text = 1;
+ continue;
+ }
+ if (strcmp(arg, "--realmode") == 0) {
+ use_real_mode = 1;
+ continue;
+ }
+ }
+ else if (!fname) {
+ fname = arg;
+ continue;
+ }
+ usage();
+ }
+ if (!fname) {
+ usage();
+ }
+ fp = fopen(fname, "r");
+ if (!fp) {
+ die("Cannot open %s: %s\n", fname, strerror(errno));
+ }
+ if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) {
+ die("Cannot read %s: %s", fname, strerror(errno));
+ }
+ rewind(fp);
+ if (e_ident[EI_CLASS] == ELFCLASS64)
+ process_64(fp, use_real_mode, as_text,
+ show_absolute_syms, show_absolute_relocs);
+ else
+ process_32(fp, use_real_mode, as_text,
+ show_absolute_syms, show_absolute_relocs);
+ fclose(fp);
+ return 0;
+}
diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c
index 5f5feff3d24c..80ffa5b9982d 100644
--- a/arch/x86/um/tls_32.c
+++ b/arch/x86/um/tls_32.c
@@ -5,6 +5,7 @@
#include <linux/percpu.h>
#include <linux/sched.h>
+#include <linux/syscalls.h>
#include <asm/uaccess.h>
#include <os.h>
#include <skas.h>
@@ -274,7 +275,7 @@ clear:
goto out;
}
-int sys_set_thread_area(struct user_desc __user *user_desc)
+SYSCALL_DEFINE1(set_thread_area, struct user_desc __user *, user_desc)
{
struct user_desc info;
int idx, ret;
@@ -322,7 +323,7 @@ int ptrace_set_thread_area(struct task_struct *child, int idx,
return set_tls_entry(child, &info, idx, 0);
}
-int sys_get_thread_area(struct user_desc __user *user_desc)
+SYSCALL_DEFINE1(get_thread_area, struct user_desc __user *, user_desc)
{
struct user_desc info;
int idx, ret;
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig
index 131dacd2748a..1a3c76505649 100644
--- a/arch/x86/xen/Kconfig
+++ b/arch/x86/xen/Kconfig
@@ -4,7 +4,7 @@
config XEN
bool "Xen guest support"
- select PARAVIRT
+ depends on PARAVIRT
select PARAVIRT_CLOCK
select XEN_HAVE_PVMMU
depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS)
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index c8e1c7b95c3b..53d4f680c9b5 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/gfp.h>
#include <linux/memblock.h>
+#include <linux/edd.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -1220,7 +1221,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.alloc_ldt = xen_alloc_ldt,
.free_ldt = xen_free_ldt,
- .store_gdt = native_store_gdt,
.store_idt = native_store_idt,
.store_tr = xen_store_tr,
@@ -1306,6 +1306,55 @@ static const struct machine_ops xen_machine_ops __initconst = {
.emergency_restart = xen_emergency_restart,
};
+static void __init xen_boot_params_init_edd(void)
+{
+#if IS_ENABLED(CONFIG_EDD)
+ struct xen_platform_op op;
+ struct edd_info *edd_info;
+ u32 *mbr_signature;
+ unsigned nr;
+ int ret;
+
+ edd_info = boot_params.eddbuf;
+ mbr_signature = boot_params.edd_mbr_sig_buffer;
+
+ op.cmd = XENPF_firmware_info;
+
+ op.u.firmware_info.type = XEN_FW_DISK_INFO;
+ for (nr = 0; nr < EDDMAXNR; nr++) {
+ struct edd_info *info = edd_info + nr;
+
+ op.u.firmware_info.index = nr;
+ info->params.length = sizeof(info->params);
+ set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
+ &info->params);
+ ret = HYPERVISOR_dom0_op(&op);
+ if (ret)
+ break;
+
+#define C(x) info->x = op.u.firmware_info.u.disk_info.x
+ C(device);
+ C(version);
+ C(interface_support);
+ C(legacy_max_cylinder);
+ C(legacy_max_head);
+ C(legacy_sectors_per_track);
+#undef C
+ }
+ boot_params.eddbuf_entries = nr;
+
+ op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
+ for (nr = 0; nr < EDD_MBR_SIG_MAX; nr++) {
+ op.u.firmware_info.index = nr;
+ ret = HYPERVISOR_dom0_op(&op);
+ if (ret)
+ break;
+ mbr_signature[nr] = op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
+ }
+ boot_params.edd_mbr_sig_buf_entries = nr;
+#endif
+}
+
/*
* Set up the GDT and segment registers for -fstack-protector. Until
* we do this, we have to be careful not to call any stack-protected
@@ -1508,6 +1557,8 @@ asmlinkage void __init xen_start_kernel(void)
/* Avoid searching for BIOS MP tables */
x86_init.mpparse.find_smp_config = x86_init_noop;
x86_init.mpparse.get_smp_config = x86_init_uint_noop;
+
+ xen_boot_params_init_edd();
}
#ifdef CONFIG_PCI
/* PCI BIOS service won't work from a PV guest. */
@@ -1589,8 +1640,11 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
switch (action) {
case CPU_UP_PREPARE:
xen_vcpu_setup(cpu);
- if (xen_have_vector_callback)
+ if (xen_have_vector_callback) {
xen_init_lock_cpu(cpu);
+ if (xen_feature(XENFEAT_hvm_safe_pvclock))
+ xen_setup_timer(cpu);
+ }
break;
default:
break;
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index e8e34938c57d..fdc3ba28ca38 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1467,8 +1467,6 @@ static void __init xen_write_cr3_init(unsigned long cr3)
__xen_write_cr3(true, cr3);
xen_mc_issue(PARAVIRT_LAZY_CPU); /* interrupts restored */
-
- pv_mmu_ops.write_cr3 = &xen_write_cr3;
}
#endif
@@ -1750,14 +1748,18 @@ static void *m2v(phys_addr_t maddr)
}
/* Set the page permissions on an identity-mapped pages */
-static void set_page_prot(void *addr, pgprot_t prot)
+static void set_page_prot_flags(void *addr, pgprot_t prot, unsigned long flags)
{
unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
pte_t pte = pfn_pte(pfn, prot);
- if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
+ if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, flags))
BUG();
}
+static void set_page_prot(void *addr, pgprot_t prot)
+{
+ return set_page_prot_flags(addr, prot, UVMF_NONE);
+}
#ifdef CONFIG_X86_32
static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
{
@@ -1841,12 +1843,12 @@ static void __init check_pt_base(unsigned long *pt_base, unsigned long *pt_end,
unsigned long addr)
{
if (*pt_base == PFN_DOWN(__pa(addr))) {
- set_page_prot((void *)addr, PAGE_KERNEL);
+ set_page_prot_flags((void *)addr, PAGE_KERNEL, UVMF_INVLPG);
clear_page((void *)addr);
(*pt_base)++;
}
if (*pt_end == PFN_DOWN(__pa(addr))) {
- set_page_prot((void *)addr, PAGE_KERNEL);
+ set_page_prot_flags((void *)addr, PAGE_KERNEL, UVMF_INVLPG);
clear_page((void *)addr);
(*pt_end)--;
}
@@ -2041,9 +2043,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
switch (idx) {
case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
-#ifdef CONFIG_X86_F00F_BUG
- case FIX_F00F_IDT:
-#endif
+ case FIX_RO_IDT:
#ifdef CONFIG_X86_32
case FIX_WP_TEST:
case FIX_VDSO:
@@ -2122,6 +2122,7 @@ static void __init xen_post_allocator_init(void)
#endif
#ifdef CONFIG_X86_64
+ pv_mmu_ops.write_cr3 = &xen_write_cr3;
SetPagePinned(virt_to_page(level3_user_vsyscall));
#endif
xen_mark_init_mm_pinned();
@@ -2197,6 +2198,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.lazy_mode = {
.enter = paravirt_enter_lazy_mmu,
.leave = xen_leave_lazy_mmu,
+ .flush = paravirt_flush_lazy_mmu,
},
.set_fixmap = xen_set_fixmap,
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 09ea61d2e02f..8ff37995d54e 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -95,7 +95,7 @@ static void __cpuinit cpu_bringup(void)
static void __cpuinit cpu_bringup_and_idle(void)
{
cpu_bringup();
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
static int xen_smp_intr_init(unsigned int cpu)
@@ -144,6 +144,13 @@ static int xen_smp_intr_init(unsigned int cpu)
goto fail;
per_cpu(xen_callfuncsingle_irq, cpu) = rc;
+ /*
+ * The IRQ worker on PVHVM goes through the native path and uses the
+ * IPI mechanism.
+ */
+ if (xen_hvm_domain())
+ return 0;
+
callfunc_name = kasprintf(GFP_KERNEL, "irqwork%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_IRQ_WORK_VECTOR,
cpu,
@@ -167,6 +174,9 @@ static int xen_smp_intr_init(unsigned int cpu)
if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
NULL);
+ if (xen_hvm_domain())
+ return rc;
+
if (per_cpu(xen_irq_work, cpu) >= 0)
unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
@@ -418,7 +428,7 @@ static int xen_cpu_disable(void)
static void xen_cpu_die(unsigned int cpu)
{
- while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+ while (xen_pv_domain() && HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/10);
}
@@ -426,7 +436,8 @@ static void xen_cpu_die(unsigned int cpu)
unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+ if (!xen_hvm_domain())
+ unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
xen_uninit_lock_cpu(cpu);
xen_teardown_timer(cpu);
}
@@ -657,11 +668,7 @@ static int __cpuinit xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
static void xen_hvm_cpu_die(unsigned int cpu)
{
- unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+ xen_cpu_die(cpu);
native_cpu_die(cpu);
}
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index f7a080ef0354..8b54603ce816 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -364,6 +364,16 @@ void __cpuinit xen_init_lock_cpu(int cpu)
int irq;
const char *name;
+ WARN(per_cpu(lock_kicker_irq, cpu) > 0, "spinlock on CPU%d exists on IRQ%d!\n",
+ cpu, per_cpu(lock_kicker_irq, cpu));
+
+ /*
+ * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+ * (xen: disable PV spinlocks on HVM)
+ */
+ if (xen_hvm_domain())
+ return;
+
name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
cpu,
@@ -382,11 +392,26 @@ void __cpuinit xen_init_lock_cpu(int cpu)
void xen_uninit_lock_cpu(int cpu)
{
+ /*
+ * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+ * (xen: disable PV spinlocks on HVM)
+ */
+ if (xen_hvm_domain())
+ return;
+
unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+ per_cpu(lock_kicker_irq, cpu) = -1;
}
void __init xen_init_spinlocks(void)
{
+ /*
+ * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
+ * (xen: disable PV spinlocks on HVM)
+ */
+ if (xen_hvm_domain())
+ return;
+
BUILD_BUG_ON(sizeof(struct xen_spinlock) > sizeof(arch_spinlock_t));
pv_lock_ops.spin_is_locked = xen_spin_is_locked;
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 0296a9522501..3d88bfdf9e1c 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -377,7 +377,7 @@ static const struct clock_event_device xen_vcpuop_clockevent = {
static const struct clock_event_device *xen_clockevent =
&xen_timerop_clockevent;
-static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events) = { .irq = -1 };
static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
{
@@ -401,6 +401,9 @@ void xen_setup_timer(int cpu)
struct clock_event_device *evt;
int irq;
+ evt = &per_cpu(xen_clock_events, cpu);
+ WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
+
printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
name = kasprintf(GFP_KERNEL, "timer%d", cpu);
@@ -413,7 +416,6 @@ void xen_setup_timer(int cpu)
IRQF_FORCE_RESUME,
name, NULL);
- evt = &per_cpu(xen_clock_events, cpu);
memcpy(evt, xen_clockevent, sizeof(*evt));
evt->cpumask = cpumask_of(cpu);
@@ -426,6 +428,7 @@ void xen_teardown_timer(int cpu)
BUG_ON(cpu == 0);
evt = &per_cpu(xen_clock_events, cpu);
unbind_from_irqhandler(evt->irq, NULL);
+ evt->irq = -1;
}
void xen_setup_cpu_clockevents(void)
@@ -497,7 +500,11 @@ static void xen_hvm_setup_cpu_clockevents(void)
{
int cpu = smp_processor_id();
xen_setup_runstate_info(cpu);
- xen_setup_timer(cpu);
+ /*
+ * xen_setup_timer(cpu) - snprintf is bad in atomic context. Hence
+ * doing it xen_hvm_cpu_notify (which gets called by smp_init during
+ * early bootup and also during CPU hotplug events).
+ */
xen_setup_cpu_clockevents();
}
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index c38834de9ac7..cb4c2ce8d447 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -4,14 +4,6 @@
#define __ARCH_WANT_SYS_CLONE
#include <uapi/asm/unistd.h>
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
-
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_UTIME
#define __ARCH_WANT_SYS_LLSEEK
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index 35905cb6e419..a8f44f50e651 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -83,4 +83,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 5cd82e9f601c..1c85323f01d7 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -105,19 +105,9 @@ void coprocessor_flush_all(struct thread_info *ti)
/*
* Powermanagement idle function, if any is provided by the platform.
*/
-
-void cpu_idle(void)
+void arch_cpu_idle(void)
{
- local_irq_enable();
-
- /* endless idle loop with no priority at all */
- while (1) {
- rcu_idle_enter();
- while (!need_resched())
- platform_idle();
- rcu_idle_exit();
- schedule_preempt_disabled();
- }
+ platform_idle();
}
/*
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index 923db5c15278..458186dab5dc 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -383,6 +383,8 @@ void show_regs(struct pt_regs * regs)
{
int i, wmask;
+ show_regs_print_info(KERN_DEFAULT);
+
wmask = regs->wmask & ~1;
for (i = 0; i < 16; i++) {
@@ -481,14 +483,6 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(task, stack);
}
-void dump_stack(void)
-{
- show_stack(current, NULL);
-}
-
-EXPORT_SYMBOL(dump_stack);
-
-
void show_code(unsigned int *pc)
{
long i;
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 7a5156ffebb6..bba125b4bb06 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -208,32 +208,17 @@ void __init mem_init(void)
highmemsize >> 10);
}
-void
-free_reserved_mem(void *start, void *end)
-{
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page((unsigned long)start);
- totalram_pages++;
- }
-}
-
#ifdef CONFIG_BLK_DEV_INITRD
extern int initrd_is_mapped;
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (initrd_is_mapped) {
- free_reserved_mem((void*)start, (void*)end);
- printk ("Freeing initrd memory: %ldk freed\n",(end-start)>>10);
- }
+ if (initrd_is_mapped)
+ free_reserved_area(start, end, 0, "initrd");
}
#endif
void free_initmem(void)
{
- free_reserved_mem(__init_begin, __init_end);
- printk("Freeing unused kernel memory: %zuk freed\n",
- (__init_end - __init_begin) >> 10);
+ free_initmem_default(0);
}
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index f2b292925ccd..4e595ee8c915 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -247,9 +247,7 @@ static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen)
{
int ret;
- rcu_read_lock();
ret = cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);
- rcu_read_unlock();
if (ret)
strncpy(buf, "<unavailable>", buflen);
return ret;
diff --git a/block/blk-core.c b/block/blk-core.c
index 074b758efc42..7c288358a745 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -39,6 +39,7 @@
EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
+EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete);
EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug);
DEFINE_IDA(blk_queue_ida);
diff --git a/block/blk-flush.c b/block/blk-flush.c
index db8f1b507857..cc2b827a853c 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -444,7 +444,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
* copied from blk_rq_pos(rq).
*/
if (error_sector)
- *error_sector = bio->bi_sector;
+ *error_sector = bio->bi_sector;
if (!bio_flagged(bio, BIO_UPTODATE))
ret = -EIO;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 6206a934eb8c..5efc5a647183 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -229,6 +229,8 @@ queue_store_##name(struct request_queue *q, const char *page, size_t count) \
unsigned long val; \
ssize_t ret; \
ret = queue_var_store(&val, page, count); \
+ if (ret < 0) \
+ return ret; \
if (neg) \
val = !val; \
\
diff --git a/block/genhd.c b/block/genhd.c
index 3c001fba80c7..20625eed5511 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1111,7 +1111,8 @@ struct class block_class = {
.name = "block",
};
-static char *block_devnode(struct device *dev, umode_t *mode)
+static char *block_devnode(struct device *dev, umode_t *mode,
+ kuid_t *uid, kgid_t *gid)
{
struct gendisk *disk = dev_to_disk(dev);
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index ef5356cd280a..0262210cad38 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -161,6 +161,8 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
else if (len < ds)
msg->msg_flags |= MSG_TRUNC;
+ msg->msg_namelen = 0;
+
lock_sock(sk);
if (ctx->more) {
ctx->more = 0;
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 6a6dfc062d2a..a1c4f0a55583 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -432,6 +432,7 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
long copied = 0;
lock_sock(sk);
+ msg->msg_namelen = 0;
for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
iovlen--, iov++) {
unsigned long seglen = iov->iov_len;
diff --git a/crypto/async_tx/raid6test.c b/crypto/async_tx/raid6test.c
index aa2b0270ed16..4a92bac744dc 100644
--- a/crypto/async_tx/raid6test.c
+++ b/crypto/async_tx/raid6test.c
@@ -46,15 +46,10 @@ static void callback(void *param)
static void makedata(int disks)
{
- int i, j;
+ int i;
for (i = 0; i < disks; i++) {
- for (j = 0; j < PAGE_SIZE/sizeof(u32); j += sizeof(u32)) {
- u32 *p = page_address(data[i]) + j;
-
- *p = random32();
- }
-
+ prandom_bytes(page_address(data[i]), PAGE_SIZE);
dataptrs[i] = data[i];
}
}
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 137ad1ec5438..13ccbda34ff9 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -44,6 +44,7 @@ struct crypto_rfc4543_ctx {
struct crypto_rfc4543_req_ctx {
u8 auth_tag[16];
+ u8 assocbuf[32];
struct scatterlist cipher[1];
struct scatterlist payload[2];
struct scatterlist assoc[2];
@@ -1133,9 +1134,19 @@ static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req,
scatterwalk_crypto_chain(payload, dst, vdst == req->iv + 8, 2);
assoclen += 8 + req->cryptlen - (enc ? 0 : authsize);
- sg_init_table(assoc, 2);
- sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
- req->assoc->offset);
+ if (req->assoc->length == req->assoclen) {
+ sg_init_table(assoc, 2);
+ sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
+ req->assoc->offset);
+ } else {
+ BUG_ON(req->assoclen > sizeof(rctx->assocbuf));
+
+ scatterwalk_map_and_copy(rctx->assocbuf, req->assoc, 0,
+ req->assoclen, 0);
+
+ sg_init_table(assoc, 2);
+ sg_set_buf(assoc, rctx->assocbuf, req->assoclen);
+ }
scatterwalk_crypto_chain(assoc, payload, 0, 2);
aead_request_set_tfm(subreq, ctx->child);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 202fa6d051b9..8d96238549fa 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
+source "drivers/ssbi/Kconfig"
+
source "drivers/hsi/Kconfig"
source "drivers/pps/Kconfig"
@@ -118,6 +120,8 @@ source "drivers/vfio/Kconfig"
source "drivers/vlynq/Kconfig"
+source "drivers/virt/Kconfig"
+
source "drivers/virtio/Kconfig"
source "drivers/hv/Kconfig"
@@ -142,8 +146,6 @@ source "drivers/remoteproc/Kconfig"
source "drivers/rpmsg/Kconfig"
-source "drivers/virt/Kconfig"
-
source "drivers/devfreq/Kconfig"
source "drivers/extcon/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index dce39a95fa71..33360de63650 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -79,7 +79,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/
-obj-$(CONFIG_USB_OTG_UTILS) += usb/
+obj-$(CONFIG_USB_PHY) += usb/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_PCI) += usb/
obj-$(CONFIG_USB_GADGET) += usb/
@@ -114,6 +114,7 @@ obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_ARCH_SHMOBILE) += sh/
+obj-$(CONFIG_SSBI) += ssbi/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 92ed9692c47e..100bd724f648 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -298,14 +298,6 @@ config ACPI_DEBUG
Documentation/kernel-parameters.txt to control the type and
amount of debug output.
-config ACPI_DEBUG_FUNC_TRACE
- bool "Additionally enable ACPI function tracing"
- default n
- depends on ACPI_DEBUG
- help
- ACPI Debug Statements slow down ACPI processing. Function trace
- is about half of the penalty and is rarely useful.
-
config ACPI_PCI_SLOT
bool "PCI slot detection driver"
depends on SYSFS
@@ -334,7 +326,7 @@ config X86_PM_TIMER
config ACPI_CONTAINER
bool "Container and Module Devices"
- default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
+ default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU)
help
This driver supports ACPI Container and Module devices (IDs
ACPI0004, PNP0A05, and PNP0A06).
@@ -345,9 +337,8 @@ config ACPI_CONTAINER
the module will be called container.
config ACPI_HOTPLUG_MEMORY
- tristate "Memory Hotplug"
+ bool "Memory Hotplug"
depends on MEMORY_HOTPLUG
- default n
help
This driver supports ACPI memory hotplug. The driver
fields notifications on ACPI memory devices (PNP0C80),
@@ -396,7 +387,7 @@ config ACPI_CUSTOM_METHOD
config ACPI_BGRT
bool "Boottime Graphics Resource Table support"
- depends on EFI
+ depends on EFI && X86
help
This driver adds support for exposing the ACPI Boottime Graphics
Resource Table, which allows the operating system to obtain
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 474fcfeba66c..ecb743bf05a5 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -39,6 +39,7 @@ acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y += csrt.o
+acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o
acpi-y += acpi_platform.o
acpi-y += power.o
acpi-y += event.o
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
index 82045e3f5cac..a82c7626aa9b 100644
--- a/drivers/acpi/acpi_i2c.c
+++ b/drivers/acpi/acpi_i2c.c
@@ -90,7 +90,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adapter)
acpi_handle handle;
acpi_status status;
- handle = ACPI_HANDLE(&adapter->dev);
+ handle = ACPI_HANDLE(adapter->dev.parent);
if (!handle)
return;
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
new file mode 100644
index 000000000000..b1c95422ce74
--- /dev/null
+++ b/drivers/acpi/acpi_lpss.c
@@ -0,0 +1,292 @@
+/*
+ * ACPI support for Intel Lynxpoint LPSS.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.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/acpi.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/clk-lpss.h>
+#include <linux/pm_runtime.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("acpi_lpss");
+
+#define LPSS_CLK_SIZE 0x04
+#define LPSS_LTR_SIZE 0x18
+
+/* Offsets relative to LPSS_PRIVATE_OFFSET */
+#define LPSS_GENERAL 0x08
+#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
+#define LPSS_SW_LTR 0x10
+#define LPSS_AUTO_LTR 0x14
+
+struct lpss_device_desc {
+ bool clk_required;
+ const char *clk_parent;
+ bool ltr_required;
+ unsigned int prv_offset;
+};
+
+struct lpss_private_data {
+ void __iomem *mmio_base;
+ resource_size_t mmio_size;
+ struct clk *clk;
+ const struct lpss_device_desc *dev_desc;
+};
+
+static struct lpss_device_desc lpt_dev_desc = {
+ .clk_required = true,
+ .clk_parent = "lpss_clk",
+ .prv_offset = 0x800,
+ .ltr_required = true,
+};
+
+static struct lpss_device_desc lpt_sdio_dev_desc = {
+ .prv_offset = 0x1000,
+ .ltr_required = true,
+};
+
+static const struct acpi_device_id acpi_lpss_device_ids[] = {
+ /* Lynxpoint LPSS devices */
+ { "INT33C0", (unsigned long)&lpt_dev_desc },
+ { "INT33C1", (unsigned long)&lpt_dev_desc },
+ { "INT33C2", (unsigned long)&lpt_dev_desc },
+ { "INT33C3", (unsigned long)&lpt_dev_desc },
+ { "INT33C4", (unsigned long)&lpt_dev_desc },
+ { "INT33C5", (unsigned long)&lpt_dev_desc },
+ { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
+ { "INT33C7", },
+
+ { }
+};
+
+static int is_memory(struct acpi_resource *res, void *not_used)
+{
+ struct resource r;
+ return !acpi_dev_resource_memory(res, &r);
+}
+
+/* LPSS main clock device. */
+static struct platform_device *lpss_clk_dev;
+
+static inline void lpt_register_clock_device(void)
+{
+ lpss_clk_dev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
+}
+
+static int register_device_clock(struct acpi_device *adev,
+ struct lpss_private_data *pdata)
+{
+ const struct lpss_device_desc *dev_desc = pdata->dev_desc;
+
+ if (!lpss_clk_dev)
+ lpt_register_clock_device();
+
+ if (!dev_desc->clk_parent || !pdata->mmio_base
+ || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
+ return -ENODATA;
+
+ pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev),
+ dev_desc->clk_parent, 0,
+ pdata->mmio_base + dev_desc->prv_offset,
+ 0, 0, NULL);
+ if (IS_ERR(pdata->clk))
+ return PTR_ERR(pdata->clk);
+
+ clk_register_clkdev(pdata->clk, NULL, dev_name(&adev->dev));
+ return 0;
+}
+
+static int acpi_lpss_create_device(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ struct lpss_device_desc *dev_desc;
+ struct lpss_private_data *pdata;
+ struct resource_list_entry *rentry;
+ struct list_head resource_list;
+ int ret;
+
+ dev_desc = (struct lpss_device_desc *)id->driver_data;
+ if (!dev_desc)
+ return acpi_create_platform_device(adev, id);
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL);
+ if (ret < 0)
+ goto err_out;
+
+ list_for_each_entry(rentry, &resource_list, node)
+ if (resource_type(&rentry->res) == IORESOURCE_MEM) {
+ pdata->mmio_size = resource_size(&rentry->res);
+ pdata->mmio_base = ioremap(rentry->res.start,
+ pdata->mmio_size);
+ pdata->dev_desc = dev_desc;
+ break;
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (dev_desc->clk_required) {
+ ret = register_device_clock(adev, pdata);
+ if (ret) {
+ /*
+ * Skip the device, but don't terminate the namespace
+ * scan.
+ */
+ kfree(pdata);
+ return 0;
+ }
+ }
+
+ adev->driver_data = pdata;
+ ret = acpi_create_platform_device(adev, id);
+ if (ret > 0)
+ return ret;
+
+ adev->driver_data = NULL;
+
+ err_out:
+ kfree(pdata);
+ return ret;
+}
+
+static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
+{
+ struct acpi_device *adev;
+ struct lpss_private_data *pdata;
+ unsigned long flags;
+ int ret;
+
+ ret = acpi_bus_get_device(ACPI_HANDLE(dev), &adev);
+ if (WARN_ON(ret))
+ return ret;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+ if (pm_runtime_suspended(dev)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ pdata = acpi_driver_data(adev);
+ if (WARN_ON(!pdata || !pdata->mmio_base)) {
+ ret = -ENODEV;
+ goto out;
+ }
+ *val = readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
+
+ out:
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+ return ret;
+}
+
+static ssize_t lpss_ltr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ u32 ltr_value = 0;
+ unsigned int reg;
+ int ret;
+
+ reg = strcmp(attr->attr.name, "auto_ltr") ? LPSS_SW_LTR : LPSS_AUTO_LTR;
+ ret = lpss_reg_read(dev, reg, &ltr_value);
+ if (ret)
+ return ret;
+
+ return snprintf(buf, PAGE_SIZE, "%08x\n", ltr_value);
+}
+
+static ssize_t lpss_ltr_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 ltr_mode = 0;
+ char *outstr;
+ int ret;
+
+ ret = lpss_reg_read(dev, LPSS_GENERAL, &ltr_mode);
+ if (ret)
+ return ret;
+
+ outstr = (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) ? "sw" : "auto";
+ return sprintf(buf, "%s\n", outstr);
+}
+
+static DEVICE_ATTR(auto_ltr, S_IRUSR, lpss_ltr_show, NULL);
+static DEVICE_ATTR(sw_ltr, S_IRUSR, lpss_ltr_show, NULL);
+static DEVICE_ATTR(ltr_mode, S_IRUSR, lpss_ltr_mode_show, NULL);
+
+static struct attribute *lpss_attrs[] = {
+ &dev_attr_auto_ltr.attr,
+ &dev_attr_sw_ltr.attr,
+ &dev_attr_ltr_mode.attr,
+ NULL,
+};
+
+static struct attribute_group lpss_attr_group = {
+ .attrs = lpss_attrs,
+ .name = "lpss_ltr",
+};
+
+static int acpi_lpss_platform_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct platform_device *pdev = to_platform_device(data);
+ struct lpss_private_data *pdata;
+ struct acpi_device *adev;
+ const struct acpi_device_id *id;
+ int ret = 0;
+
+ id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
+ if (!id || !id->driver_data)
+ return 0;
+
+ if (acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
+ return 0;
+
+ pdata = acpi_driver_data(adev);
+ if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
+ return 0;
+
+ if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
+ dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
+ return 0;
+ }
+
+ if (action == BUS_NOTIFY_ADD_DEVICE)
+ ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group);
+ else if (action == BUS_NOTIFY_DEL_DEVICE)
+ sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+
+ return ret;
+}
+
+static struct notifier_block acpi_lpss_nb = {
+ .notifier_call = acpi_lpss_platform_notify,
+};
+
+static struct acpi_scan_handler lpss_handler = {
+ .ids = acpi_lpss_device_ids,
+ .attach = acpi_lpss_create_device,
+};
+
+void __init acpi_lpss_init(void)
+{
+ if (!lpt_clk_init()) {
+ bus_register_notifier(&platform_bus_type, &acpi_lpss_nb);
+ acpi_scan_add_handler(&lpss_handler);
+ }
+}
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index da1f82b445e0..5e6301e94920 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -1,5 +1,7 @@
/*
- * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
+ * Copyright (C) 2004, 2013 Intel Corporation
+ * Author: Naveen B S <naveen.b.s@intel.com>
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* All rights reserved.
*
@@ -25,14 +27,10 @@
* ranges.
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/memory_hotplug.h>
-#include <linux/slab.h>
#include <linux/acpi.h>
-#include <acpi/acpi_drivers.h>
+#include <linux/memory_hotplug.h>
+
+#include "internal.h"
#define ACPI_MEMORY_DEVICE_CLASS "memory"
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
@@ -44,32 +42,28 @@
#define PREFIX "ACPI:memory_hp:"
ACPI_MODULE_NAME("acpi_memhotplug");
-MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
-MODULE_DESCRIPTION("Hotplug Mem Driver");
-MODULE_LICENSE("GPL");
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
#define MEMORY_POWER_OFF_STATE 2
-static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device);
+static int acpi_memory_device_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used);
+static void acpi_memory_device_remove(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, memory_device_ids);
-static struct acpi_driver acpi_memory_device_driver = {
- .name = "acpi_memhotplug",
- .class = ACPI_MEMORY_DEVICE_CLASS,
+static struct acpi_scan_handler memory_device_handler = {
.ids = memory_device_ids,
- .ops = {
- .add = acpi_memory_device_add,
- .remove = acpi_memory_device_remove,
- },
+ .attach = acpi_memory_device_add,
+ .detach = acpi_memory_device_remove,
+ .hotplug = {
+ .enabled = true,
+ },
};
struct acpi_memory_info {
@@ -79,7 +73,6 @@ struct acpi_memory_info {
unsigned short caching; /* memory cache attribute */
unsigned short write_protect; /* memory read/write attribute */
unsigned int enabled:1;
- unsigned int failed:1;
};
struct acpi_memory_device {
@@ -153,48 +146,6 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}
-static int acpi_memory_get_device(acpi_handle handle,
- struct acpi_memory_device **mem_device)
-{
- struct acpi_device *device = NULL;
- int result = 0;
-
- acpi_scan_lock_acquire();
-
- acpi_bus_get_device(handle, &device);
- if (device)
- goto end;
-
- /*
- * Now add the notified device. This creates the acpi_device
- * and invokes .add function
- */
- result = acpi_bus_scan(handle);
- if (result) {
- acpi_handle_warn(handle, "ACPI namespace scan failed\n");
- result = -EINVAL;
- goto out;
- }
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- acpi_handle_warn(handle, "Missing device object\n");
- result = -EINVAL;
- goto out;
- }
-
- end:
- *mem_device = acpi_driver_data(device);
- if (!(*mem_device)) {
- dev_err(&device->dev, "driver data not found\n");
- result = -ENODEV;
- goto out;
- }
-
- out:
- acpi_scan_lock_release();
- return result;
-}
-
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
{
unsigned long long current_status;
@@ -249,13 +200,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
* returns -EEXIST. If add_memory() returns the other error, it
* means that this memory block is not used by the kernel.
*/
- if (result && result != -EEXIST) {
- info->failed = 1;
+ if (result && result != -EEXIST)
continue;
- }
- if (!result)
- info->enabled = 1;
+ info->enabled = 1;
+
/*
* Add num_enable even if add_memory() returns -EEXIST, so the
* device is bound to this driver.
@@ -286,16 +235,8 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
nid = acpi_get_node(mem_device->device->handle);
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
- if (info->failed)
- /* The kernel does not use this memory block */
- continue;
-
if (!info->enabled)
- /*
- * The kernel uses this memory block, but it may be not
- * managed by us.
- */
- return -EBUSY;
+ continue;
if (nid < 0)
nid = memory_add_physaddr_to_nid(info->start_addr);
@@ -310,95 +251,21 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
return result;
}
-static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
-{
- struct acpi_memory_device *mem_device;
- struct acpi_device *device;
- struct acpi_eject_event *ej_event = NULL;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
- acpi_status status;
-
- switch (event) {
- case ACPI_NOTIFY_BUS_CHECK:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "\nReceived BUS CHECK notification for device\n"));
- /* Fall Through */
- case ACPI_NOTIFY_DEVICE_CHECK:
- if (event == ACPI_NOTIFY_DEVICE_CHECK)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "\nReceived DEVICE CHECK notification for device\n"));
- if (acpi_memory_get_device(handle, &mem_device)) {
- acpi_handle_err(handle, "Cannot find driver data\n");
- break;
- }
-
- ost_code = ACPI_OST_SC_SUCCESS;
- break;
-
- case ACPI_NOTIFY_EJECT_REQUEST:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "\nReceived EJECT REQUEST notification for device\n"));
-
- status = AE_ERROR;
- acpi_scan_lock_acquire();
-
- if (acpi_bus_get_device(handle, &device)) {
- acpi_handle_err(handle, "Device doesn't exist\n");
- goto unlock;
- }
- mem_device = acpi_driver_data(device);
- if (!mem_device) {
- acpi_handle_err(handle, "Driver Data is NULL\n");
- goto unlock;
- }
-
- ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
- if (!ej_event) {
- pr_err(PREFIX "No memory, dropping EJECT\n");
- goto unlock;
- }
-
- get_device(&device->dev);
- ej_event->device = device;
- ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- /* The eject is carried out asynchronously. */
- status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- ej_event);
- if (ACPI_FAILURE(status)) {
- put_device(&device->dev);
- kfree(ej_event);
- }
-
- unlock:
- acpi_scan_lock_release();
- if (ACPI_SUCCESS(status))
- return;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
-
- /* non-hotplug event; possibly handled by other handler */
- return;
- }
-
- /* Inform firmware that the hotplug operation has completed */
- (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-}
-
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
{
if (!mem_device)
return;
acpi_memory_free_device_resources(mem_device);
+ mem_device->device->driver_data = NULL;
kfree(mem_device);
}
-static int acpi_memory_device_add(struct acpi_device *device)
+static int acpi_memory_device_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
+ struct acpi_memory_device *mem_device;
int result;
- struct acpi_memory_device *mem_device = NULL;
-
if (!device)
return -EINVAL;
@@ -423,147 +290,36 @@ static int acpi_memory_device_add(struct acpi_device *device)
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
- pr_debug("%s\n", acpi_device_name(device));
+ result = acpi_memory_check_device(mem_device);
+ if (result) {
+ acpi_memory_device_free(mem_device);
+ return 0;
+ }
- if (!acpi_memory_check_device(mem_device)) {
- /* call add_memory func */
- result = acpi_memory_enable_device(mem_device);
- if (result) {
- dev_err(&device->dev,
- "Error in acpi_memory_enable_device\n");
- acpi_memory_device_free(mem_device);
- }
+ result = acpi_memory_enable_device(mem_device);
+ if (result) {
+ dev_err(&device->dev, "acpi_memory_enable_device() error\n");
+ acpi_memory_device_free(mem_device);
+ return -ENODEV;
}
- return result;
+
+ dev_dbg(&device->dev, "Memory device configured by ACPI\n");
+ return 1;
}
-static int acpi_memory_device_remove(struct acpi_device *device)
+static void acpi_memory_device_remove(struct acpi_device *device)
{
- struct acpi_memory_device *mem_device = NULL;
- int result;
+ struct acpi_memory_device *mem_device;
if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ return;
mem_device = acpi_driver_data(device);
-
- result = acpi_memory_remove_memory(mem_device);
- if (result)
- return result;
-
+ acpi_memory_remove_memory(mem_device);
acpi_memory_device_free(mem_device);
-
- return 0;
-}
-
-/*
- * Helper function to check for memory device
- */
-static acpi_status is_memory_device(acpi_handle handle)
-{
- char *hardware_id;
- acpi_status status;
- struct acpi_device_info *info;
-
- status = acpi_get_object_info(handle, &info);
- if (ACPI_FAILURE(status))
- return status;
-
- if (!(info->valid & ACPI_VALID_HID)) {
- kfree(info);
- return AE_ERROR;
- }
-
- hardware_id = info->hardware_id.string;
- if ((hardware_id == NULL) ||
- (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
- status = AE_ERROR;
-
- kfree(info);
- return status;
-}
-
-static acpi_status
-acpi_memory_register_notify_handler(acpi_handle handle,
- u32 level, void *ctxt, void **retv)
-{
- acpi_status status;
-
-
- status = is_memory_device(handle);
- if (ACPI_FAILURE(status))
- return AE_OK; /* continue */
-
- status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- acpi_memory_device_notify, NULL);
- /* continue */
- return AE_OK;
-}
-
-static acpi_status
-acpi_memory_deregister_notify_handler(acpi_handle handle,
- u32 level, void *ctxt, void **retv)
-{
- acpi_status status;
-
-
- status = is_memory_device(handle);
- if (ACPI_FAILURE(status))
- return AE_OK; /* continue */
-
- status = acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_memory_device_notify);
-
- return AE_OK; /* continue */
-}
-
-static int __init acpi_memory_device_init(void)
-{
- int result;
- acpi_status status;
-
-
- result = acpi_bus_register_driver(&acpi_memory_device_driver);
-
- if (result < 0)
- return -ENODEV;
-
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- acpi_memory_register_notify_handler, NULL,
- NULL, NULL);
-
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
- acpi_bus_unregister_driver(&acpi_memory_device_driver);
- return -ENODEV;
- }
-
- return 0;
}
-static void __exit acpi_memory_device_exit(void)
+void __init acpi_memory_hotplug_init(void)
{
- acpi_status status;
-
-
- /*
- * Adding this to un-install notification handlers for all the device
- * handles.
- */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- acpi_memory_deregister_notify_handler, NULL,
- NULL, NULL);
-
- if (ACPI_FAILURE(status))
- ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
-
- acpi_bus_unregister_driver(&acpi_memory_device_driver);
-
- return;
+ acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
}
-
-module_init(acpi_memory_device_init);
-module_exit(acpi_memory_device_exit);
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 31de1043eea0..27bb6a91de5f 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -236,7 +236,7 @@ static int create_power_saving_task(void)
ps_tsks[ps_tsk_num] = kthread_run(power_saving_thread,
(void *)(unsigned long)ps_tsk_num,
"acpi_pad/%d", ps_tsk_num);
- rc = IS_ERR(ps_tsks[ps_tsk_num]) ? PTR_ERR(ps_tsks[ps_tsk_num]) : 0;
+ rc = PTR_RET(ps_tsks[ps_tsk_num]);
if (!rc)
ps_tsk_num++;
else
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 26fce4b8a632..fafec5ddf17f 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -22,9 +22,6 @@
ACPI_MODULE_NAME("platform");
-/* Flags for acpi_create_platform_device */
-#define ACPI_PLATFORM_CLK BIT(0)
-
/*
* The following ACPI IDs are known to be suitable for representing as
* platform devices.
@@ -33,33 +30,9 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
{ "PNP0D40" },
- /* Haswell LPSS devices */
- { "INT33C0", ACPI_PLATFORM_CLK },
- { "INT33C1", ACPI_PLATFORM_CLK },
- { "INT33C2", ACPI_PLATFORM_CLK },
- { "INT33C3", ACPI_PLATFORM_CLK },
- { "INT33C4", ACPI_PLATFORM_CLK },
- { "INT33C5", ACPI_PLATFORM_CLK },
- { "INT33C6", ACPI_PLATFORM_CLK },
- { "INT33C7", ACPI_PLATFORM_CLK },
-
{ }
};
-static int acpi_create_platform_clks(struct acpi_device *adev)
-{
- static struct platform_device *pdev;
-
- /* Create Lynxpoint LPSS clocks */
- if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
- pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
- }
-
- return 0;
-}
-
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
@@ -71,10 +44,9 @@ static int acpi_create_platform_clks(struct acpi_device *adev)
*
* Name of the platform device will be the same as @adev's.
*/
-static int acpi_create_platform_device(struct acpi_device *adev,
- const struct acpi_device_id *id)
+int acpi_create_platform_device(struct acpi_device *adev,
+ const struct acpi_device_id *id)
{
- unsigned long flags = id->driver_data;
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
@@ -83,14 +55,6 @@ static int acpi_create_platform_device(struct acpi_device *adev,
struct resource *resources;
int count;
- if (flags & ACPI_PLATFORM_CLK) {
- int ret = acpi_create_platform_clks(adev);
- if (ret) {
- dev_err(&adev->dev, "failed to create clocks\n");
- return ret;
- }
- }
-
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
return 0;
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index a1b9bf5085a2..7ddf29eca9f5 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -83,6 +83,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
acpi-y += \
nsaccess.o \
nsalloc.o \
+ nsconvert.o \
nsdump.o \
nseval.o \
nsinit.o \
@@ -160,6 +161,7 @@ acpi-y += \
utobject.o \
utosi.o \
utownerid.o \
+ utpredef.o \
utresrc.o \
utstate.o \
utstring.o \
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index ecb49927b817..07160928ca25 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -224,6 +224,7 @@ ACPI_EXTERN u8 acpi_gbl_global_lock_pending;
*/
ACPI_EXTERN acpi_spinlock acpi_gbl_gpe_lock; /* For GPE data structs and registers */
ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
+ACPI_EXTERN acpi_spinlock acpi_gbl_reference_count_lock;
/* Mutex for _OSI support */
@@ -413,10 +414,12 @@ ACPI_EXTERN u8 acpi_gbl_db_output_flags;
#ifdef ACPI_DISASSEMBLER
-u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_ignore_noop_operator, FALSE);
ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
+ACPI_EXTERN u8 acpi_gbl_num_external_methods;
+ACPI_EXTERN u32 acpi_gbl_resolved_external_methods;
ACPI_EXTERN struct acpi_external_list *acpi_gbl_external_list;
ACPI_EXTERN struct acpi_external_file *acpi_gbl_external_file_list;
#endif
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 805f419086ab..d5bfbd331bfd 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -294,6 +294,8 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */
#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF
+#pragma pack(1)
+
/*
* Information structure for ACPI predefined names.
* Each entry in the table contains the following items:
@@ -304,7 +306,7 @@ acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state);
*/
struct acpi_name_info {
char name[ACPI_NAME_SIZE];
- u8 param_count;
+ u16 argument_list;
u8 expected_btypes;
};
@@ -327,7 +329,7 @@ struct acpi_package_info {
u8 count1;
u8 object_type2;
u8 count2;
- u8 reserved;
+ u16 reserved;
};
/* Used for ACPI_PTYPE2_FIXED */
@@ -336,6 +338,7 @@ struct acpi_package_info2 {
u8 type;
u8 count;
u8 object_type[4];
+ u8 reserved;
};
/* Used for ACPI_PTYPE1_OPTION */
@@ -345,7 +348,7 @@ struct acpi_package_info3 {
u8 count;
u8 object_type[2];
u8 tail_object_type;
- u8 reserved;
+ u16 reserved;
};
union acpi_predefined_info {
@@ -355,6 +358,10 @@ union acpi_predefined_info {
struct acpi_package_info3 ret_info3;
};
+/* Reset to default packing */
+
+#pragma pack()
+
/* Data block used during object validation */
struct acpi_predefined_data {
@@ -363,6 +370,7 @@ struct acpi_predefined_data {
union acpi_operand_object *parent_package;
struct acpi_namespace_node *node;
u32 flags;
+ u32 return_btype;
u8 node_flags;
};
@@ -371,6 +379,20 @@ struct acpi_predefined_data {
#define ACPI_OBJECT_REPAIRED 1
#define ACPI_OBJECT_WRAPPED 2
+/* Return object auto-repair info */
+
+typedef acpi_status(*acpi_object_converter) (union acpi_operand_object
+ *original_object,
+ union acpi_operand_object
+ **converted_object);
+
+struct acpi_simple_repair_info {
+ char name[ACPI_NAME_SIZE];
+ u32 unexpected_btypes;
+ u32 package_index;
+ acpi_object_converter object_converter;
+};
+
/*
* Bitmapped return value types
* Note: the actual data types must be contiguous, a loop in nspredef.c
@@ -1037,6 +1059,7 @@ struct acpi_external_list {
u16 length;
u8 type;
u8 flags;
+ u8 resolved;
};
/* Values for Flags field above */
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index ed7943b9044f..53666bd9193d 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -322,10 +322,12 @@
* where a pointer to an object of type union acpi_operand_object can also
* appear. This macro is used to distinguish them.
*
- * The "Descriptor" field is the first field in both structures.
+ * The "DescriptorType" field is the second field in both structures.
*/
+#define ACPI_GET_DESCRIPTOR_PTR(d) (((union acpi_descriptor *)(void *)(d))->common.common_pointer)
+#define ACPI_SET_DESCRIPTOR_PTR(d, p) (((union acpi_descriptor *)(void *)(d))->common.common_pointer = (p))
#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type)
-#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t)
+#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = (t))
/*
* Macros for the master AML opcode table
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 02cd5482ff8b..d2e491876bc0 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -167,6 +167,29 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent);
int acpi_ns_compare_names(char *name1, char *name2);
/*
+ * nsconvert - Dynamic object conversion routines
+ */
+acpi_status
+acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object);
+
+acpi_status
+acpi_ns_convert_to_string(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object);
+
+acpi_status
+acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object);
+
+acpi_status
+acpi_ns_convert_to_unicode(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object);
+
+acpi_status
+acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object);
+
+/*
* nsdump - Namespace dump/print utilities
*/
#ifdef ACPI_FUTURE_USAGE
@@ -208,10 +231,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status return_status,
union acpi_operand_object **return_object);
-const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
- acpi_namespace_node
- *node);
-
void
acpi_ns_check_parameter_count(char *pathname,
struct acpi_namespace_node *node,
@@ -289,7 +308,7 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node,
* predefined methods/objects
*/
acpi_status
-acpi_ns_repair_object(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_predefined_data *data,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr);
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 752cc40cdc1e..b22b70944fd6 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -56,7 +56,7 @@
* object type
* count
*
- * ACPI_PTYPE1_VAR: Variable-length length:
+ * ACPI_PTYPE1_VAR: Variable-length length. Zero-length package is allowed:
* object type (Int/Buf/Ref)
*
* ACPI_PTYPE1_OPTION: Package has some required and some optional elements
@@ -66,14 +66,16 @@
* 2) PTYPE2 packages contain a Variable-length number of sub-packages. Each
* of the different types describe the contents of each of the sub-packages.
*
- * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types:
+ * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types. Zero-length
+ * parent package is allowed:
* object type
* count
* object type
* count
* (Used for _ALR,_MLS,_PSS,_TRT,_TSS)
*
- * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element:
+ * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element.
+ * Zero-length parent package is allowed:
* object type
* (Used for _CSD,_PSD,_TSD)
*
@@ -84,17 +86,19 @@
* count
* (Used for _CST)
*
- * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length
+ * ACPI_PTYPE2_FIXED: Each subpackage is of Fixed-length. Zero-length
+ * parent package is allowed.
* (Used for _PRT)
*
- * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length
+ * ACPI_PTYPE2_MIN: Each subpackage has a Variable-length but minimum length.
+ * Zero-length parent package is allowed:
* (Used for _HPX)
*
* ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length
* (Used for _ART, _FPS)
*
* ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements
- * followed by an optional element
+ * followed by an optional element. Zero-length parent package is allowed.
* object type
* count
* object type
@@ -116,8 +120,47 @@ enum acpi_return_package_types {
ACPI_PTYPE2_FIX_VAR = 10
};
+/* Support macros for users of the predefined info table */
+
+#define METHOD_PREDEF_ARGS_MAX 4
+#define METHOD_ARG_BIT_WIDTH 3
+#define METHOD_ARG_MASK 0x0007
+#define ARG_COUNT_IS_MINIMUM 0x8000
+#define METHOD_MAX_ARG_TYPE ACPI_TYPE_PACKAGE
+
+#define METHOD_GET_COUNT(arg_list) (arg_list & METHOD_ARG_MASK)
+#define METHOD_GET_NEXT_ARG(arg_list) (arg_list >> METHOD_ARG_BIT_WIDTH)
+
+/* Macros used to build the predefined info table */
+
+#define METHOD_0ARGS 0
+#define METHOD_1ARGS(a1) (1 | (a1 << 3))
+#define METHOD_2ARGS(a1,a2) (2 | (a1 << 3) | (a2 << 6))
+#define METHOD_3ARGS(a1,a2,a3) (3 | (a1 << 3) | (a2 << 6) | (a3 << 9))
+#define METHOD_4ARGS(a1,a2,a3,a4) (4 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12))
+
+#define METHOD_RETURNS(type) (type)
+#define METHOD_NO_RETURN_VALUE 0
+
+#define PACKAGE_INFO(a,b,c,d,e,f) {{{(a),(b),(c),(d)}, ((((u16)(f)) << 8) | (e)), 0}}
+
+/* Support macros for the resource descriptor info table */
+
+#define WIDTH_1 0x0001
+#define WIDTH_2 0x0002
+#define WIDTH_3 0x0004
+#define WIDTH_8 0x0008
+#define WIDTH_16 0x0010
+#define WIDTH_32 0x0020
+#define WIDTH_64 0x0040
+#define VARIABLE_DATA 0x0080
+#define NUM_RESOURCE_WIDTHS 8
+
+#define WIDTH_ADDRESS WIDTH_16 | WIDTH_32 | WIDTH_64
+
#ifdef ACPI_CREATE_PREDEFINED_TABLE
-/*
+/******************************************************************************
+ *
* Predefined method/object information table.
*
* These are the names that can actually be evaluated via acpi_evaluate_object.
@@ -125,23 +168,24 @@ enum acpi_return_package_types {
*
* 1) Predefined/Reserved names that are never evaluated via
* acpi_evaluate_object:
- * _Lxx and _Exx GPE methods
- * _Qxx EC methods
- * _T_x compiler temporary variables
+ * _Lxx and _Exx GPE methods
+ * _Qxx EC methods
+ * _T_x compiler temporary variables
+ * _Wxx wake events
*
* 2) Predefined names that never actually exist within the AML code:
- * Predefined resource descriptor field names
+ * Predefined resource descriptor field names
*
* 3) Predefined names that are implemented within ACPICA:
- * _OSI
- *
- * 4) Some predefined names that are not documented within the ACPI spec.
- * _WDG, _WED
+ * _OSI
*
* The main entries in the table each contain the following items:
*
* name - The ACPI reserved name
- * param_count - Number of arguments to the method
+ * argument_list - Contains (in 16 bits), the number of required
+ * arguments to the method (3 bits), and a 3-bit type
+ * field for each argument (up to 4 arguments). The
+ * METHOD_?ARGS macros generate the correct packed data.
* expected_btypes - Allowed type(s) for the return value.
* 0 means that no return value is expected.
*
@@ -151,256 +195,511 @@ enum acpi_return_package_types {
* overall size of the stored data.
*
* Note: The additional braces are intended to promote portability.
- */
-static const union acpi_predefined_info predefined_names[] = {
- {{"_AC0", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC1", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC2", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC3", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC4", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC5", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC6", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC7", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC8", 0, ACPI_RTYPE_INTEGER}},
- {{"_AC9", 0, ACPI_RTYPE_INTEGER}},
- {{"_ADR", 0, ACPI_RTYPE_INTEGER}},
- {{"_AEI", 0, ACPI_RTYPE_BUFFER}},
- {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL4", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL5", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL6", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL7", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL8", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_AL9", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_ALC", 0, ACPI_RTYPE_INTEGER}},
- {{"_ALI", 0, ACPI_RTYPE_INTEGER}},
- {{"_ALP", 0, ACPI_RTYPE_INTEGER}},
- {{"_ALR", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2 (Ints) */
- {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2,0}, 0,0}},
-
- {{"_ALT", 0, ACPI_RTYPE_INTEGER}},
- {{"_ART", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */
- {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER},
- 11, 0}},
-
- {{"_BBN", 0, ACPI_RTYPE_INTEGER}},
- {{"_BCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
-
- {{"_BCM", 1, 0}},
- {{"_BCT", 1, ACPI_RTYPE_INTEGER}},
- {{"_BDN", 0, ACPI_RTYPE_INTEGER}},
- {{"_BFS", 1, 0}},
- {{"_BIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (9 Int),(4 Str) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9, ACPI_RTYPE_STRING}, 4, 0}},
-
- {{"_BIX", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int),(4 Str) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, ACPI_RTYPE_STRING}, 4,
- 0}},
-
- {{"_BLT", 3, 0}},
- {{"_BMA", 1, ACPI_RTYPE_INTEGER}},
- {{"_BMC", 1, 0}},
- {{"_BMD", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (5 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
-
- {{"_BMS", 1, ACPI_RTYPE_INTEGER}},
- {{"_BQC", 0, ACPI_RTYPE_INTEGER}},
- {{"_BST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
-
- {{"_BTM", 1, ACPI_RTYPE_INTEGER}},
- {{"_BTP", 1, 0}},
- {{"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* See PCI firmware spec 3.0 */
- {{"_CDM", 0, ACPI_RTYPE_INTEGER}},
- {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0}, 0,
- 0}},
-
- {{"_CLS", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
-
- {{"_CPC", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Bufs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0, 0}, 0,
- 0}},
-
- {{"_CRS", 0, ACPI_RTYPE_BUFFER}},
- {{"_CRT", 0, ACPI_RTYPE_INTEGER}},
- {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */
- {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
-
- {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
- {{{ACPI_PTYPE2_PKG_COUNT, ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,
- 0}},
-
- {{"_CWS", 1, ACPI_RTYPE_INTEGER}},
- {{"_DCK", 1, ACPI_RTYPE_INTEGER}},
- {{"_DCS", 0, ACPI_RTYPE_INTEGER}},
- {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}},
- {{"_DDN", 0, ACPI_RTYPE_STRING}},
- {{"_DEP", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
-
- {{"_DGS", 0, ACPI_RTYPE_INTEGER}},
- {{"_DIS", 0, 0}},
-
- {{"_DLM", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */
- {{{ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1,
- ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER}, 0, 0}},
-
- {{"_DMA", 0, ACPI_RTYPE_BUFFER}},
- {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
-
- {{"_DOS", 1, 0}},
- {{"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */
- {{"_DSS", 1, 0}},
- {{"_DSW", 3, 0}},
- {{"_DTI", 1, 0}},
- {{"_EC_", 0, ACPI_RTYPE_INTEGER}},
- {{"_EDL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs)*/
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_EJ0", 1, 0}},
- {{"_EJ1", 1, 0}},
- {{"_EJ2", 1, 0}},
- {{"_EJ3", 1, 0}},
- {{"_EJ4", 1, 0}},
- {{"_EJD", 0, ACPI_RTYPE_STRING}},
- {{"_EVT", 1, 0}},
- {{"_FDE", 0, ACPI_RTYPE_BUFFER}},
- {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}},
-
- {{"_FDM", 1, 0}},
- {{"_FIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0}, 0, 0}},
-
- {{"_FIX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}},
-
- {{"_FPS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */
- {{{ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 5, 0}, 0, 0}},
-
- {{"_FSL", 1, 0}},
- {{"_FST", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}},
-
- {{"_GAI", 0, ACPI_RTYPE_INTEGER}},
- {{"_GCP", 0, ACPI_RTYPE_INTEGER}},
- {{"_GHL", 0, ACPI_RTYPE_INTEGER}},
- {{"_GLK", 0, ACPI_RTYPE_INTEGER}},
- {{"_GPD", 0, ACPI_RTYPE_INTEGER}},
- {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */
- {{"_GRT", 0, ACPI_RTYPE_BUFFER}},
- {{"_GSB", 0, ACPI_RTYPE_INTEGER}},
- {{"_GTF", 0, ACPI_RTYPE_BUFFER}},
- {{"_GTM", 0, ACPI_RTYPE_BUFFER}},
- {{"_GTS", 1, 0}},
- {{"_GWS", 1, ACPI_RTYPE_INTEGER}},
- {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
- {{"_HOT", 0, ACPI_RTYPE_INTEGER}},
- {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
+ *
+ * Note2: Table is used by the kernel-resident subsystem, the iASL compiler,
+ * and the acpi_help utility.
+ *
+ * TBD: _PRT - currently ignore reversed entries. Attempt to fix in nsrepair.
+ * Possibly fixing package elements like _BIF, etc.
+ *
+ *****************************************************************************/
+
+const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
+ {{"_AC0", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC1", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC2", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC3", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC4", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC5", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC6", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC7", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC8", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AC9", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ADR", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_AEI", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_AL0", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL1", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL2", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL3", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL4", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL5", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL6", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL7", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL8", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_AL9", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_ALC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ALI", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ALP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ALR", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 (Ints) */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
+
+ {{"_ALT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ART", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Ref/11 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_REFERENCE, 2,
+ ACPI_RTYPE_INTEGER, 11, 0),
+
+ {{"_BBN", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BCL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0),
+
+ {{"_BCM", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_BCT", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BDN", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BFS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_BIF", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (9 Int),(4 Str) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 9,
+ ACPI_RTYPE_STRING, 4, 0),
+
+ {{"_BIX", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int),(4 Str) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,
+ ACPI_RTYPE_STRING, 4, 0),
+
+ {{"_BLT",
+ METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_BMA", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BMC", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_BMD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (5 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+
+ {{"_BMS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BQC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BST", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
+
+ {{"_BTM", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_BTP", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_CBA", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See PCI firmware spec 3.0 */
+
+ {{"_CDM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_CID", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Strs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,
+ 0, 0, 0),
+
+ {{"_CLS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0),
+
+ {{"_CPC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,
+ 0, 0, 0),
+
+ {{"_CRS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_CRT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_CSD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n-1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0),
+
+ {{"_CST", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2_PKG_COUNT, ACPI_RTYPE_BUFFER, 1,
+ ACPI_RTYPE_INTEGER, 3, 0),
+
+ {{"_CWS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_DCK", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_DCS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_DDC", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER)}},
+
+ {{"_DDN", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_STRING)}},
+
+ {{"_DEP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_DGS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_DIS", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_DLM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */
+ PACKAGE_INFO(ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1,
+ ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER, 0, 0),
+
+ {{"_DMA", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_DOD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0),
+
+ {{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_DSM",
+ METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
+ ACPI_TYPE_PACKAGE),
+ METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
+
+ {{"_DSS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_DSW",
+ METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_DTI", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EC_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_EDL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_EJ0", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EJ1", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EJ2", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EJ3", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EJ4", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_EJD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_STRING)}},
+
+ {{"_ERR",
+ METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_STRING, ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* Internal use only, used by ACPICA test suites */
+
+ {{"_EVT", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_FDE", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_FDI", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (16 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0),
+
+ {{"_FDM", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_FIF", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
+
+ {{"_FIX", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0),
+
+ {{"_FPS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (5 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+
+ {{"_FSL", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_FST", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0, 0, 0),
+
+ {{"_GAI", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GCP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GHL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GLK", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GPD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GPE", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* _GPE method, not _GPE scope */
+
+ {{"_GRT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_GSB", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_GTF", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_GTM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_GTS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_GWS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_HID", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}},
+
+ {{"_HOT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_HPP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
/*
- * For _HPX, a single package is returned, containing a Variable-length number
+ * For _HPX, a single package is returned, containing a variable-length number
* of sub-packages. Each sub-package contains a PCI record setting.
* There are several different type of record settings, of different
* lengths, but all elements of all settings are Integers.
*/
- {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */
- {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
-
- {{"_HRV", 0, ACPI_RTYPE_INTEGER}},
- {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
- {{"_INI", 0, 0}},
- {{"_IRC", 0, 0}},
- {{"_LCK", 1, 0}},
- {{"_LID", 0, ACPI_RTYPE_INTEGER}},
- {{"_MAT", 0, ACPI_RTYPE_BUFFER}},
- {{"_MBM", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (8 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0}, 0, 0}},
-
- {{"_MLS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */
- {{{ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER}, 1, 0}},
-
- {{"_MSG", 1, 0}},
- {{"_MSM", 4, ACPI_RTYPE_INTEGER}},
- {{"_NTT", 0, ACPI_RTYPE_INTEGER}},
- {{"_OFF", 0, 0}},
- {{"_ON_", 0, 0}},
- {{"_OS_", 0, ACPI_RTYPE_STRING}},
- {{"_OSC", 4, ACPI_RTYPE_BUFFER}},
- {{"_OST", 3, 0}},
- {{"_PAI", 1, ACPI_RTYPE_INTEGER}},
- {{"_PCL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_PCT", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}},
-
- {{"_PDC", 1, 0}},
- {{"_PDL", 0, ACPI_RTYPE_INTEGER}},
- {{"_PIC", 1, 0}},
- {{"_PIF", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int),(3 Str) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, ACPI_RTYPE_STRING}, 3, 0}},
-
- {{"_PLD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Bufs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0,0}, 0,0}},
-
- {{"_PMC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (11 Int),(3 Str) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11, ACPI_RTYPE_STRING}, 3,
- 0}},
-
- {{"_PMD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
-
- {{"_PMM", 0, ACPI_RTYPE_INTEGER}},
- {{"_PPC", 0, ACPI_RTYPE_INTEGER}},
- {{"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* See dig64 spec */
- {{"_PR0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_PR1", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_PR2", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_PR3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
-
- {{"_PRE", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
-
- {{"_PRL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}},
-
- {{"_PRS", 0, ACPI_RTYPE_BUFFER}},
+ {{"_HPX", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (var Ints) */
+ PACKAGE_INFO(ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+
+ {{"_HRV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_IFT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */
+
+ {{"_INI", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_IRC", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_LCK", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_LID", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_MAT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_MBM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (8 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 8, 0, 0, 0),
+
+ {{"_MLS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (1 Str/1 Buf) */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1, ACPI_RTYPE_BUFFER, 1,
+ 0),
+
+ {{"_MSG", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_MSM",
+ METHOD_4ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
+ ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_NTT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_OFF", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_ON_", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_OS_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_STRING)}},
+
+ {{"_OSC",
+ METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
+ ACPI_TYPE_BUFFER),
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_OST",
+ METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_BUFFER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PAI", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PCL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PCT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0),
+
+ {{"_PDC", METHOD_1ARGS(ACPI_TYPE_BUFFER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PDL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PIC", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PIF", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (3 Int),(3 Str) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3,
+ ACPI_RTYPE_STRING, 3, 0),
+
+ {{"_PLD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Bufs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0),
+
+ {{"_PMC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (11 Int),(3 Str) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 11,
+ ACPI_RTYPE_STRING, 3, 0),
+
+ {{"_PMD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PMM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PPC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PPE", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See dig64 spec */
+
+ {{"_PR0", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PR1", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PR2", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PR3", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PRE", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PRL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PRS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
/*
* For _PRT, many BIOSs reverse the 3rd and 4th Package elements (Source
@@ -410,47 +709,89 @@ static const union acpi_predefined_info predefined_names[] = {
* warning, add the ACPI_RTYPE_REFERENCE type to the 4th element (index 3)
* in the statement below.
*/
- {{"_PRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */
- {{{ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER,ACPI_RTYPE_INTEGER},
- ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE,
- ACPI_RTYPE_INTEGER}},
-
- {{"_PRW", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */
- {{{ACPI_PTYPE1_OPTION, 2, ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE,
- ACPI_RTYPE_INTEGER}, ACPI_RTYPE_REFERENCE,0}},
-
- {{"_PS0", 0, 0}},
- {{"_PS1", 0, 0}},
- {{"_PS2", 0, 0}},
- {{"_PS3", 0, 0}},
- {{"_PSC", 0, ACPI_RTYPE_INTEGER}},
- {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */
- {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}},
-
- {{"_PSE", 1, 0}},
- {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_PSR", 0, ACPI_RTYPE_INTEGER}},
- {{"_PSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (6 Int) */
- {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6,0}, 0,0}},
-
- {{"_PSV", 0, ACPI_RTYPE_INTEGER}},
- {{"_PSW", 1, 0}},
- {{"_PTC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Buf) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2,0}, 0,0}},
-
- {{"_PTP", 2, ACPI_RTYPE_INTEGER}},
- {{"_PTS", 1, 0}},
- {{"_PUR", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (2 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0}, 0, 0}},
-
- {{"_PXM", 0, ACPI_RTYPE_INTEGER}},
- {{"_REG", 2, 0}},
- {{"_REV", 0, ACPI_RTYPE_INTEGER}},
- {{"_RMV", 0, ACPI_RTYPE_INTEGER}},
- {{"_ROM", 2, ACPI_RTYPE_BUFFER}},
- {{"_RTV", 0, ACPI_RTYPE_INTEGER}},
+ {{"_PRT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (4): Int,Int,Int/Ref,Int */
+ PACKAGE_INFO(ACPI_PTYPE2_FIXED, 4, ACPI_RTYPE_INTEGER,
+ ACPI_RTYPE_INTEGER,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE,
+ ACPI_RTYPE_INTEGER),
+
+ {{"_PRW", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: Pkg/Int,Int,[Variable-length Refs] (Pkg is Ref/Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_OPTION, 2,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE,
+ ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0),
+
+ {{"_PS0", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PS1", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PS2", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PS3", METHOD_0ARGS,
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PSC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PSD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (5 Int) with count */
+ PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0),
+
+ {{"_PSE", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PSL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_PSR", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PSS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each (6 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0),
+
+ {{"_PSV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PSW", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PTC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Buf) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0),
+
+ {{"_PTP", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_PTS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_PUR", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
+
+ {{"_PXM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_REG", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_REV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_RMV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_ROM", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_RTV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
/*
* For _S0_ through _S5_, the ACPI spec defines a return Package
@@ -458,111 +799,285 @@ static const union acpi_predefined_info predefined_names[] = {
* Allow this by making the objects "Variable-length length", but all elements
* must be Integers.
*/
- {{"_S0_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S1_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S2_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S3_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S4_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S5_", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (1 Int) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1,0}, 0,0}},
-
- {{"_S1D", 0, ACPI_RTYPE_INTEGER}},
- {{"_S2D", 0, ACPI_RTYPE_INTEGER}},
- {{"_S3D", 0, ACPI_RTYPE_INTEGER}},
- {{"_S4D", 0, ACPI_RTYPE_INTEGER}},
- {{"_S0W", 0, ACPI_RTYPE_INTEGER}},
- {{"_S1W", 0, ACPI_RTYPE_INTEGER}},
- {{"_S2W", 0, ACPI_RTYPE_INTEGER}},
- {{"_S3W", 0, ACPI_RTYPE_INTEGER}},
- {{"_S4W", 0, ACPI_RTYPE_INTEGER}},
- {{"_SBS", 0, ACPI_RTYPE_INTEGER}},
- {{"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */
- /* Note: the 3-arg definition may be removed for ACPI 4.0 */
- {{"_SDD", 1, 0}},
- {{"_SEG", 0, ACPI_RTYPE_INTEGER}},
- {{"_SHL", 1, ACPI_RTYPE_INTEGER}},
- {{"_SLI", 0, ACPI_RTYPE_BUFFER}},
- {{"_SPD", 1, ACPI_RTYPE_INTEGER}},
- {{"_SRS", 1, 0}},
- {{"_SRT", 1, ACPI_RTYPE_INTEGER}},
- {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */
- {{"_SST", 1, 0}},
- {{"_STA", 0, ACPI_RTYPE_INTEGER}},
- {{"_STM", 3, 0}},
- {{"_STP", 2, ACPI_RTYPE_INTEGER}},
- {{"_STR", 0, ACPI_RTYPE_BUFFER}},
- {{"_STV", 2, ACPI_RTYPE_INTEGER}},
- {{"_SUB", 0, ACPI_RTYPE_STRING}},
- {{"_SUN", 0, ACPI_RTYPE_INTEGER}},
- {{"_SWS", 0, ACPI_RTYPE_INTEGER}},
- {{"_TC1", 0, ACPI_RTYPE_INTEGER}},
- {{"_TC2", 0, ACPI_RTYPE_INTEGER}},
- {{"_TDL", 0, ACPI_RTYPE_INTEGER}},
- {{"_TIP", 1, ACPI_RTYPE_INTEGER}},
- {{"_TIV", 1, ACPI_RTYPE_INTEGER}},
- {{"_TMP", 0, ACPI_RTYPE_INTEGER}},
- {{"_TPC", 0, ACPI_RTYPE_INTEGER}},
- {{"_TPT", 1, 0}},
- {{"_TRT", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 2 Ref/6 Int */
- {{{ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER}, 6, 0}},
-
- {{"_TSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5 Int with count */
- {{{ACPI_PTYPE2_COUNT,ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
-
- {{"_TSP", 0, ACPI_RTYPE_INTEGER}},
- {{"_TSS", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each 5 Int */
- {{{ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5,0}, 0,0}},
-
- {{"_TST", 0, ACPI_RTYPE_INTEGER}},
- {{"_TTS", 1, 0}},
- {{"_TZD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */
- {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}},
-
- {{"_TZM", 0, ACPI_RTYPE_REFERENCE}},
- {{"_TZP", 0, ACPI_RTYPE_INTEGER}},
- {{"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
- {{"_UPC", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4,0}, 0,0}},
-
- {{"_UPD", 0, ACPI_RTYPE_INTEGER}},
- {{"_UPP", 0, ACPI_RTYPE_INTEGER}},
- {{"_VPO", 0, ACPI_RTYPE_INTEGER}},
+ {{"_S0_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S1_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S2_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S3_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S4_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S5_", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0),
+
+ {{"_S1D", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S2D", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S3D", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S4D", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S0W", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S1W", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S2W", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S3W", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_S4W", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SBS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SCP", METHOD_1ARGS(ACPI_TYPE_INTEGER) | ARG_COUNT_IS_MINIMUM,
+ METHOD_NO_RETURN_VALUE}}, /* Acpi 1.0 allowed 1 integer arg. Acpi 3.0 expanded to 3 args. Allow both. */
+
+ {{"_SDD", METHOD_1ARGS(ACPI_TYPE_BUFFER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_SEG", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SHL", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SLI", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_SPD", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SRS", METHOD_1ARGS(ACPI_TYPE_BUFFER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_SRT", METHOD_1ARGS(ACPI_TYPE_BUFFER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SRV", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}}, /* See IPMI spec */
+
+ {{"_SST", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_STA", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_STM",
+ METHOD_3ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER, ACPI_TYPE_BUFFER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_STP", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_STR", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_STV", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SUB", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_STRING)}},
+
+ {{"_SUN", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_SWS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TC1", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TC2", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TDL", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TIP", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TIV", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TMP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TPC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TPT", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_TRT", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 2 Ref/6 Int */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, ACPI_RTYPE_INTEGER,
+ 6, 0),
+
+ {{"_TSD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */
+ PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+
+ {{"_TSP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TSS", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int */
+ PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
+
+ {{"_TST", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_TTS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_NO_RETURN_VALUE}},
+
+ {{"_TZD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
+ PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
+
+ {{"_TZM", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_REFERENCE)}},
+
+ {{"_TZP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_UID", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING)}},
+
+ {{"_UPC", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
+
+ {{"_UPD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_UPP", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
+ {{"_VPO", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
/* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */
- {{"_WAK", 1,
- ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
- {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */
+ {{"_WAK", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER |
+ ACPI_RTYPE_PACKAGE)}},
+ PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0), /* Fixed-length (2 Int), but is optional */
/* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */
- {{"_WDG", 0, ACPI_RTYPE_BUFFER}},
- {{"_WED", 1,
- ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}},
+ {{"_WDG", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
+
+ {{"_WED", METHOD_1ARGS(ACPI_TYPE_INTEGER),
+ METHOD_RETURNS(ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
+ ACPI_RTYPE_BUFFER)}},
- {{{0, 0, 0, 0}, 0, 0}} /* Table terminator */
+ PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */
};
+#else
+extern const union acpi_predefined_info acpi_gbl_predefined_methods[];
+#endif
-#if 0
+#if (defined ACPI_CREATE_RESOURCE_TABLE && defined ACPI_APPLICATION)
+/******************************************************************************
+ *
+ * Predefined names for use in Resource Descriptors. These names do not
+ * appear in the global Predefined Name table (since these names never
+ * appear in actual AML byte code, only in the original ASL)
+ *
+ * Note: Used by iASL compiler and acpi_help utility only.
+ *
+ *****************************************************************************/
- /* This is an internally implemented control method, no need to check */
-{ {
-"_OSI", 1, ACPI_RTYPE_INTEGER}},
+const union acpi_predefined_info acpi_gbl_resource_names[] = {
+ {{"_ADR", WIDTH_16 | WIDTH_64, 0}},
+ {{"_ALN", WIDTH_8 | WIDTH_16 | WIDTH_32, 0}},
+ {{"_ASI", WIDTH_8, 0}},
+ {{"_ASZ", WIDTH_8, 0}},
+ {{"_ATT", WIDTH_64, 0}},
+ {{"_BAS", WIDTH_16 | WIDTH_32, 0}},
+ {{"_BM_", WIDTH_1, 0}},
+ {{"_DBT", WIDTH_16, 0}}, /* Acpi 5.0 */
+ {{"_DEC", WIDTH_1, 0}},
+ {{"_DMA", WIDTH_8, 0}},
+ {{"_DPL", WIDTH_1, 0}}, /* Acpi 5.0 */
+ {{"_DRS", WIDTH_16, 0}}, /* Acpi 5.0 */
+ {{"_END", WIDTH_1, 0}}, /* Acpi 5.0 */
+ {{"_FLC", WIDTH_2, 0}}, /* Acpi 5.0 */
+ {{"_GRA", WIDTH_ADDRESS, 0}},
+ {{"_HE_", WIDTH_1, 0}},
+ {{"_INT", WIDTH_16 | WIDTH_32, 0}},
+ {{"_IOR", WIDTH_2, 0}}, /* Acpi 5.0 */
+ {{"_LEN", WIDTH_8 | WIDTH_ADDRESS, 0}},
+ {{"_LIN", WIDTH_8, 0}}, /* Acpi 5.0 */
+ {{"_LL_", WIDTH_1, 0}},
+ {{"_MAF", WIDTH_1, 0}},
+ {{"_MAX", WIDTH_ADDRESS, 0}},
+ {{"_MEM", WIDTH_2, 0}},
+ {{"_MIF", WIDTH_1, 0}},
+ {{"_MIN", WIDTH_ADDRESS, 0}},
+ {{"_MOD", WIDTH_1, 0}}, /* Acpi 5.0 */
+ {{"_MTP", WIDTH_2, 0}},
+ {{"_PAR", WIDTH_8, 0}}, /* Acpi 5.0 */
+ {{"_PHA", WIDTH_1, 0}}, /* Acpi 5.0 */
+ {{"_PIN", WIDTH_16, 0}}, /* Acpi 5.0 */
+ {{"_PPI", WIDTH_8, 0}}, /* Acpi 5.0 */
+ {{"_POL", WIDTH_1 | WIDTH_2, 0}}, /* Acpi 5.0 */
+ {{"_RBO", WIDTH_8, 0}},
+ {{"_RBW", WIDTH_8, 0}},
+ {{"_RNG", WIDTH_1, 0}},
+ {{"_RT_", WIDTH_8, 0}}, /* Acpi 3.0 */
+ {{"_RW_", WIDTH_1, 0}},
+ {{"_RXL", WIDTH_16, 0}}, /* Acpi 5.0 */
+ {{"_SHR", WIDTH_2, 0}},
+ {{"_SIZ", WIDTH_2, 0}},
+ {{"_SLV", WIDTH_1, 0}}, /* Acpi 5.0 */
+ {{"_SPE", WIDTH_32, 0}}, /* Acpi 5.0 */
+ {{"_STB", WIDTH_2, 0}}, /* Acpi 5.0 */
+ {{"_TRA", WIDTH_ADDRESS, 0}},
+ {{"_TRS", WIDTH_1, 0}},
+ {{"_TSF", WIDTH_8, 0}}, /* Acpi 3.0 */
+ {{"_TTP", WIDTH_1, 0}},
+ {{"_TXL", WIDTH_16, 0}}, /* Acpi 5.0 */
+ {{"_TYP", WIDTH_2 | WIDTH_16, 0}},
+ {{"_VEN", VARIABLE_DATA, 0}}, /* Acpi 5.0 */
+ PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */
+};
- /* TBD: */
- _PRT - currently ignore reversed entries. attempt to fix here?
- think about possibly fixing package elements like _BIF, etc.
+static const union acpi_predefined_info acpi_gbl_scope_names[] = {
+ {{"_GPE", 0, 0}},
+ {{"_PR_", 0, 0}},
+ {{"_SB_", 0, 0}},
+ {{"_SI_", 0, 0}},
+ {{"_TZ_", 0, 0}},
+ PACKAGE_INFO(0, 0, 0, 0, 0, 0) /* Table terminator */
+};
+#else
+extern const union acpi_predefined_info acpi_gbl_resource_names[];
#endif
#endif
-#endif
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 0082fa0a6139..202f4f12d3e2 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -113,9 +113,10 @@ struct acpi_pkg_info {
u32 num_packages;
};
+/* Object reference counts */
+
#define REF_INCREMENT (u16) 0
#define REF_DECREMENT (u16) 1
-#define REF_FORCE_DELETE (u16) 2
/* acpi_ut_dump_buffer */
@@ -421,7 +422,7 @@ acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
*/
acpi_status acpi_ut_initialize_interfaces(void);
-void acpi_ut_interface_terminate(void);
+acpi_status acpi_ut_interface_terminate(void);
acpi_status acpi_ut_install_interface(acpi_string interface_name);
@@ -432,6 +433,26 @@ struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name);
acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
/*
+ * utpredef - support for predefined names
+ */
+const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union
+ acpi_predefined_info
+ *this_name);
+
+const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name);
+
+const union acpi_predefined_info *acpi_ut_match_resource_name(char *name);
+
+void
+acpi_ut_display_predefined_method(char *buffer,
+ const union acpi_predefined_info *this_name,
+ u8 multi_line);
+
+void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes);
+
+u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types);
+
+/*
* utstate - Generic state creation/cache routines
*/
void
@@ -483,7 +504,8 @@ acpi_ut_short_divide(u64 in_dividend,
/*
* utmisc
*/
-const char *acpi_ut_validate_exception(acpi_status status);
+const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status
+ status);
u8 acpi_ut_is_pci_root_bridge(char *id);
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 4d8c992a51d8..99778997c35a 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -178,7 +178,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
if (!op) {
ACPI_ERROR((AE_INFO, "Null Op"));
- return_VALUE(TRUE);
+ return_UINT8(TRUE);
}
/*
@@ -210,7 +210,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
"At Method level, result of [%s] not used\n",
acpi_ps_get_opcode_name(op->common.
aml_opcode)));
- return_VALUE(FALSE);
+ return_UINT8(FALSE);
}
/* Get info on the parent. The root_op is AML_SCOPE */
@@ -219,7 +219,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
if (parent_info->class == AML_CLASS_UNKNOWN) {
ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
- return_VALUE(FALSE);
+ return_UINT8(FALSE);
}
/*
@@ -307,7 +307,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
- return_VALUE(TRUE);
+ return_UINT8(TRUE);
result_not_used:
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -316,7 +316,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
acpi_ps_get_opcode_name(op->common.parent->common.
aml_opcode), op));
- return_VALUE(FALSE);
+ return_UINT8(FALSE);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 44f8325c2bae..e2199a947470 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -693,7 +693,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
default:
ACPI_ERROR((AE_INFO,
- "Unimplemented opcode, class=0x%X type=0x%X Opcode=-0x%X Op=%p",
+ "Unimplemented opcode, class=0x%X type=0x%X Opcode=0x%X Op=%p",
op_class, op_type, op->common.aml_opcode,
op));
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index b8ea0b26cde3..83cd45f4a870 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -257,6 +257,8 @@ u32 acpi_ev_fixed_event_detect(void)
*
* DESCRIPTION: Clears the status bit for the requested event, calls the
* handler that previously registered for the event.
+ * NOTE: If there is no handler for the event, the event is
+ * disabled to prevent further interrupts.
*
******************************************************************************/
@@ -271,17 +273,17 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
status_register_id, ACPI_CLEAR_STATUS);
/*
- * Make sure we've got a handler. If not, report an error. The event is
- * disabled to prevent further interrupts.
+ * Make sure that a handler exists. If not, report an error
+ * and disable the event to prevent further interrupts.
*/
- if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
+ if (!acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_write_bit_register(acpi_gbl_fixed_event_info[event].
enable_register_id,
ACPI_DISABLE_EVENT);
ACPI_ERROR((AE_INFO,
- "No installed handler for fixed event [0x%08X]",
- event));
+ "No installed handler for fixed event - %s (%u), disabling",
+ acpi_ut_get_event_name(event), event));
return (ACPI_INTERRUPT_NOT_HANDLED);
}
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index b9adb9a7ed85..a493b528f8f9 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -707,7 +707,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to clear GPE%02X", gpe_number));
- return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
+ return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
}
@@ -724,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to disable GPE%02X", gpe_number));
- return_VALUE(ACPI_INTERRUPT_NOT_HANDLED);
+ return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
/*
@@ -784,7 +784,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
break;
}
- return_VALUE(ACPI_INTERRUPT_HANDLED);
+ return_UINT32(ACPI_INTERRUPT_HANDLED);
}
#endif /* !ACPI_REDUCED_HARDWARE */
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index f4b43bede015..b905acf7aacd 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -89,7 +89,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
*/
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
- return_VALUE(interrupt_handled);
+ return_UINT32(interrupt_handled);
}
/*******************************************************************************
@@ -120,7 +120,7 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
- return_VALUE(interrupt_handled);
+ return_UINT32(interrupt_handled);
}
/******************************************************************************
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index ddffd6847914..ca5fba99c33b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -467,9 +467,9 @@ acpi_install_fixed_event_handler(u32 event,
return_ACPI_STATUS(status);
}
- /* Don't allow two handlers. */
+ /* Do not allow multiple handlers */
- if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
+ if (acpi_gbl_fixed_event_handlers[event].handler) {
status = AE_ALREADY_EXISTS;
goto cleanup;
}
@@ -483,8 +483,9 @@ acpi_install_fixed_event_handler(u32 event,
if (ACPI_SUCCESS(status))
status = acpi_enable_event(event, 0);
if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO, "Could not enable fixed event 0x%X",
- event));
+ ACPI_WARNING((AE_INFO,
+ "Could not enable fixed event - %s (%u)",
+ acpi_ut_get_event_name(event), event));
/* Remove the handler */
@@ -492,7 +493,8 @@ acpi_install_fixed_event_handler(u32 event,
acpi_gbl_fixed_event_handlers[event].context = NULL;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Enabled fixed event %X, Handler=%p\n", event,
+ "Enabled fixed event %s (%X), Handler=%p\n",
+ acpi_ut_get_event_name(event), event,
handler));
}
@@ -544,11 +546,12 @@ acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
- "Could not write to fixed event enable register 0x%X",
- event));
+ "Could not disable fixed event - %s (%u)",
+ acpi_ut_get_event_name(event), event));
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
- event));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Disabled fixed event - %s (%X)\n",
+ acpi_ut_get_event_name(event), event));
}
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index d6e4e42316db..7039606a0ba8 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -74,6 +74,12 @@ acpi_status acpi_enable(void)
return_ACPI_STATUS(AE_NO_ACPI_TABLES);
}
+ /* If the Hardware Reduced flag is set, machine is always in acpi mode */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
/* Check current mode */
if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
@@ -126,6 +132,12 @@ acpi_status acpi_disable(void)
ACPI_FUNCTION_TRACE(acpi_disable);
+ /* If the Hardware Reduced flag is set, machine is always in acpi mode */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"System is already in legacy (non-ACPI) mode\n"));
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index e491e46f17df..b0838a4ea53e 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -257,7 +257,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
union acpi_operand_object *return_desc = NULL;
u64 index;
acpi_status status = AE_OK;
- acpi_size length;
+ acpi_size length = 0;
ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R,
acpi_ps_get_opcode_name(walk_state->opcode));
@@ -320,7 +320,6 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
* NOTE: A length of zero is ok, and will create a zero-length, null
* terminated string.
*/
- length = 0;
while ((length < operand[0]->buffer.length) &&
(length < operand[1]->integer.value) &&
(operand[0]->buffer.pointer[length])) {
@@ -376,6 +375,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_STRING:
if (index >= operand[0]->string.length) {
+ length = operand[0]->string.length;
status = AE_AML_STRING_LIMIT;
}
@@ -386,6 +386,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_BUFFER:
if (index >= operand[0]->buffer.length) {
+ length = operand[0]->buffer.length;
status = AE_AML_BUFFER_LIMIT;
}
@@ -396,6 +397,7 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
case ACPI_TYPE_PACKAGE:
if (index >= operand[0]->package.count) {
+ length = operand[0]->package.count;
status = AE_AML_PACKAGE_LIMIT;
}
@@ -414,8 +416,9 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Index (0x%8.8X%8.8X) is beyond end of object",
- ACPI_FORMAT_UINT64(index)));
+ "Index (0x%X%8.8X) is beyond end of object (length 0x%X)",
+ ACPI_FORMAT_UINT64(index),
+ (u32)length));
goto cleanup;
}
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index d6eab81f54fb..6b728aef2dca 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -276,7 +276,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
/* Invalid field access type */
ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
- return_VALUE(0);
+ return_UINT32(0);
}
if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) {
@@ -289,7 +289,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
}
*return_byte_alignment = byte_alignment;
- return_VALUE(bit_length);
+ return_UINT32(bit_length);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index b205cbb4b50c..99dc7b287d55 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -340,7 +340,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
/* u64 is unsigned, so we don't worry about a '-' prefix */
if (value == 0) {
- return_VALUE(1);
+ return_UINT32(1);
}
current_value = value;
@@ -354,7 +354,7 @@ static u32 acpi_ex_digits_needed(u64 value, u32 base)
num_digits++;
}
- return_VALUE(num_digits);
+ return_UINT32(num_digits);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index deb3f61e2bd1..579c3a53ac87 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -66,6 +66,12 @@ acpi_status acpi_hw_set_mode(u32 mode)
ACPI_FUNCTION_TRACE(hw_set_mode);
+ /* If the Hardware Reduced flag is set, machine is always in acpi mode */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
@@ -146,23 +152,29 @@ u32 acpi_hw_get_mode(void)
ACPI_FUNCTION_TRACE(hw_get_mode);
+ /* If the Hardware Reduced flag is set, machine is always in acpi mode */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_UINT32(ACPI_SYS_MODE_ACPI);
+ }
+
/*
* ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
* system does not support mode transition.
*/
if (!acpi_gbl_FADT.smi_command) {
- return_VALUE(ACPI_SYS_MODE_ACPI);
+ return_UINT32(ACPI_SYS_MODE_ACPI);
}
status = acpi_read_bit_register(ACPI_BITREG_SCI_ENABLE, &value);
if (ACPI_FAILURE(status)) {
- return_VALUE(ACPI_SYS_MODE_LEGACY);
+ return_UINT32(ACPI_SYS_MODE_LEGACY);
}
if (value) {
- return_VALUE(ACPI_SYS_MODE_ACPI);
+ return_UINT32(ACPI_SYS_MODE_ACPI);
} else {
- return_VALUE(ACPI_SYS_MODE_LEGACY);
+ return_UINT32(ACPI_SYS_MODE_LEGACY);
}
}
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
new file mode 100644
index 000000000000..8f79a9d2d50e
--- /dev/null
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -0,0 +1,443 @@
+/******************************************************************************
+ *
+ * Module Name: nsconvert - Object conversions for objects returned by
+ * predefined methods
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+#include "acpredef.h"
+#include "amlresrc.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsconvert")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_integer
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_status status;
+ u64 value = 0;
+ u32 i;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_STRING:
+
+ /* String-to-Integer conversion */
+
+ status = acpi_ut_strtoul64(original_object->string.pointer,
+ ACPI_ANY_BASE, &value);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
+
+ if (original_object->buffer.length > 8) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Extract each buffer byte to create the integer */
+
+ for (i = 0; i < original_object->buffer.length; i++) {
+ value |=
+ ((u64)original_object->buffer.
+ pointer[i] << (i * 8));
+ }
+ break;
+
+ default:
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ new_object = acpi_ut_create_integer_object(value);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_string
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_string(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_size length;
+ acpi_status status;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ /*
+ * Integer-to-String conversion. Commonly, convert
+ * an integer of value 0 to a NULL string. The last element of
+ * _BIF and _BIX packages occasionally need this fix.
+ */
+ if (original_object->integer.value == 0) {
+
+ /* Allocate a new NULL string object */
+
+ new_object = acpi_ut_create_string_object(0);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+ } else {
+ status =
+ acpi_ex_convert_to_string(original_object,
+ &new_object,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ /*
+ * Buffer-to-String conversion. Use a to_string
+ * conversion, no transform performed on the buffer data. The best
+ * example of this is the _BIF method, where the string data from
+ * the battery is often (incorrectly) returned as buffer object(s).
+ */
+ length = 0;
+ while ((length < original_object->buffer.length) &&
+ (original_object->buffer.pointer[length])) {
+ length++;
+ }
+
+ /* Allocate a new string object */
+
+ new_object = acpi_ut_create_string_object(length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the raw buffer data with no transform. String is already NULL
+ * terminated at Length+1.
+ */
+ ACPI_MEMCPY(new_object->string.pointer,
+ original_object->buffer.pointer, length);
+ break;
+
+ default:
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_buffer
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ acpi_status status;
+ union acpi_operand_object **elements;
+ u32 *dword_buffer;
+ u32 count;
+ u32 i;
+
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ /*
+ * Integer-to-Buffer conversion.
+ * Convert the Integer to a packed-byte buffer. _MAT and other
+ * objects need this sometimes, if a read has been performed on a
+ * Field object that is less than or equal to the global integer
+ * size (32 or 64 bits).
+ */
+ status =
+ acpi_ex_convert_to_buffer(original_object, &new_object);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ /* String-to-Buffer conversion. Simple data copy */
+
+ new_object =
+ acpi_ut_create_buffer_object(original_object->string.
+ length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY(new_object->buffer.pointer,
+ original_object->string.pointer,
+ original_object->string.length);
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ /*
+ * This case is often seen for predefined names that must return a
+ * Buffer object with multiple DWORD integers within. For example,
+ * _FDE and _GTM. The Package can be converted to a Buffer.
+ */
+
+ /* All elements of the Package must be integers */
+
+ elements = original_object->package.elements;
+ count = original_object->package.count;
+
+ for (i = 0; i < count; i++) {
+ if ((!*elements) ||
+ ((*elements)->common.type != ACPI_TYPE_INTEGER)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+ elements++;
+ }
+
+ /* Create the new buffer object to replace the Package */
+
+ new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the package elements (integers) to the buffer as DWORDs */
+
+ elements = original_object->package.elements;
+ dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
+
+ for (i = 0; i < count; i++) {
+ *dword_buffer = (u32)(*elements)->integer.value;
+ dword_buffer++;
+ elements++;
+ }
+ break;
+
+ default:
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_unicode
+ *
+ * PARAMETERS: original_object - ASCII String Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful.
+ *
+ * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_unicode(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ char *ascii_string;
+ u16 *unicode_buffer;
+ u32 unicode_length;
+ u32 i;
+
+ if (!original_object) {
+ return (AE_OK);
+ }
+
+ /* If a Buffer was returned, it must be at least two bytes long */
+
+ if (original_object->common.type == ACPI_TYPE_BUFFER) {
+ if (original_object->buffer.length < 2) {
+ return (AE_AML_OPERAND_VALUE);
+ }
+
+ *return_object = NULL;
+ return (AE_OK);
+ }
+
+ /*
+ * The original object is an ASCII string. Convert this string to
+ * a unicode buffer.
+ */
+ ascii_string = original_object->string.pointer;
+ unicode_length = (original_object->string.length * 2) + 2;
+
+ /* Create a new buffer object for the Unicode data */
+
+ new_object = acpi_ut_create_buffer_object(unicode_length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ unicode_buffer = ACPI_CAST_PTR(u16, new_object->buffer.pointer);
+
+ /* Convert ASCII to Unicode */
+
+ for (i = 0; i < original_object->string.length; i++) {
+ unicode_buffer[i] = (u16)ascii_string[i];
+ }
+
+ *return_object = new_object;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_to_resource
+ *
+ * PARAMETERS: original_object - Object to be converted
+ * return_object - Where the new converted object is returned
+ *
+ * RETURN: Status. AE_OK if conversion was successful
+ *
+ * DESCRIPTION: Attempt to convert a Integer object to a resource_template
+ * Buffer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_convert_to_resource(union acpi_operand_object *original_object,
+ union acpi_operand_object **return_object)
+{
+ union acpi_operand_object *new_object;
+ u8 *buffer;
+
+ /*
+ * We can fix the following cases for an expected resource template:
+ * 1. No return value (interpreter slack mode is disabled)
+ * 2. A "Return (Zero)" statement
+ * 3. A "Return empty buffer" statement
+ *
+ * We will return a buffer containing a single end_tag
+ * resource descriptor.
+ */
+ if (original_object) {
+ switch (original_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+
+ /* We can only repair an Integer==0 */
+
+ if (original_object->integer.value) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ if (original_object->buffer.length) {
+
+ /* Additional checks can be added in the future */
+
+ *return_object = NULL;
+ return (AE_OK);
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+ default:
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+ }
+
+ /* Create the new buffer object for the resource descriptor */
+
+ new_object = acpi_ut_create_buffer_object(2);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ buffer = ACPI_CAST_PTR(u8, new_object->buffer.pointer);
+
+ /* Initialize the Buffer with a single end_tag descriptor */
+
+ buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE);
+ buffer[1] = 0x00;
+
+ *return_object = new_object;
+ return (AE_OK);
+}
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index 1538f3eb2a8f..b61db69d5675 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -98,17 +98,21 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
info->return_object = NULL;
info->param_count = 0;
- /*
- * Get the actual namespace node for the target object. Handles these cases:
- *
- * 1) Null node, Pathname (absolute path)
- * 2) Node, Pathname (path relative to Node)
- * 3) Node, Null Pathname
- */
- status = acpi_ns_get_node(info->prefix_node, info->pathname,
- ACPI_NS_NO_UPSEARCH, &info->resolved_node);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (!info->resolved_node) {
+ /*
+ * Get the actual namespace node for the target object if we need to.
+ * Handles these cases:
+ *
+ * 1) Null node, Pathname (absolute path)
+ * 2) Node, Pathname (path relative to Node)
+ * 3) Node, Null Pathname
+ */
+ status = acpi_ns_get_node(info->prefix_node, info->pathname,
+ ACPI_NS_NO_UPSEARCH,
+ &info->resolved_node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
/*
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 224c30053401..8a52916148cb 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -76,19 +76,7 @@ static acpi_status
acpi_ns_check_reference(struct acpi_predefined_data *data,
union acpi_operand_object *return_object);
-static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes);
-
-/*
- * Names for the types that can be returned by the predefined objects.
- * Used for warning messages. Must be in the same order as the ACPI_RTYPEs
- */
-static const char *acpi_rtype_names[] = {
- "/Integer",
- "/String",
- "/Buffer",
- "/Package",
- "/Reference",
-};
+static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
/*******************************************************************************
*
@@ -112,7 +100,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
acpi_status return_status,
union acpi_operand_object **return_object_ptr)
{
- union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
const union acpi_predefined_info *predefined;
char *pathname;
@@ -120,7 +107,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* Match the name for this method/object against the predefined list */
- predefined = acpi_ns_check_for_predefined_name(node);
+ predefined = acpi_ut_match_predefined_method(node->name.ascii);
/* Get the full pathname to the object, for use in warning messages */
@@ -152,25 +139,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
}
/*
- * If there is no return value, check if we require a return value for
- * this predefined name. Either one return value is expected, or none,
- * for both methods and other objects.
- *
- * Exit now if there is no return object. Warning if one was expected.
- */
- if (!return_object) {
- if ((predefined->info.expected_btypes) &&
- (!(predefined->info.expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_WARN_PREDEFINED((AE_INFO, pathname,
- ACPI_WARN_ALWAYS,
- "Missing expected return value"));
-
- status = AE_AML_NO_RETURN_VALUE;
- }
- goto cleanup;
- }
-
- /*
* Return value validation and possible repair.
*
* 1) Don't perform return value validation/repair if this feature
@@ -310,8 +278,10 @@ acpi_ns_check_parameter_count(char *pathname,
* Validate the user-supplied parameter count.
* Allow two different legal argument counts (_SCP, etc.)
*/
- required_params_current = predefined->info.param_count & 0x0F;
- required_params_old = predefined->info.param_count >> 4;
+ required_params_current =
+ predefined->info.argument_list & METHOD_ARG_MASK;
+ required_params_old =
+ predefined->info.argument_list >> METHOD_ARG_BIT_WIDTH;
if (user_param_count != ACPI_UINT32_MAX) {
if ((user_param_count != required_params_current) &&
@@ -340,52 +310,6 @@ acpi_ns_check_parameter_count(char *pathname,
/*******************************************************************************
*
- * FUNCTION: acpi_ns_check_for_predefined_name
- *
- * PARAMETERS: node - Namespace node for the method/object
- *
- * RETURN: Pointer to entry in predefined table. NULL indicates not found.
- *
- * DESCRIPTION: Check an object name against the predefined object list.
- *
- ******************************************************************************/
-
-const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
- acpi_namespace_node
- *node)
-{
- const union acpi_predefined_info *this_name;
-
- /* Quick check for a predefined name, first character must be underscore */
-
- if (node->name.ascii[0] != '_') {
- return (NULL);
- }
-
- /* Search info table for a predefined method/object name */
-
- this_name = predefined_names;
- while (this_name->info.name[0]) {
- if (ACPI_COMPARE_NAME(node->name.ascii, this_name->info.name)) {
- return (this_name);
- }
-
- /*
- * Skip next entry in the table if this name returns a Package
- * (next entry contains the package info)
- */
- if (this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) {
- this_name++;
- }
-
- this_name++;
- }
-
- return (NULL); /* Not found */
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_check_object_type
*
* PARAMETERS: data - Pointer to validation data structure
@@ -410,28 +334,12 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
- u32 return_btype;
char type_buffer[48]; /* Room for 5 types */
- /*
- * If we get a NULL return_object here, it is a NULL package element.
- * Since all extraneous NULL package elements were removed earlier by a
- * call to acpi_ns_remove_null_elements, this is an unexpected NULL element.
- * We will attempt to repair it.
- */
- if (!return_object) {
- status = acpi_ns_repair_null_element(data, expected_btypes,
- package_index,
- return_object_ptr);
- if (ACPI_SUCCESS(status)) {
- return (AE_OK); /* Repair was successful */
- }
- goto type_error_exit;
- }
-
/* A Namespace node should not get here, but make sure */
- if (ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
+ if (return_object &&
+ ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
"Invalid return type - Found a Namespace node [%4.4s] type %s",
return_object->node.name.ascii,
@@ -448,59 +356,31 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
* from all of the predefined names (including elements of returned
* packages)
*/
- switch (return_object->common.type) {
- case ACPI_TYPE_INTEGER:
- return_btype = ACPI_RTYPE_INTEGER;
- break;
-
- case ACPI_TYPE_BUFFER:
- return_btype = ACPI_RTYPE_BUFFER;
- break;
-
- case ACPI_TYPE_STRING:
- return_btype = ACPI_RTYPE_STRING;
- break;
+ data->return_btype = acpi_ns_get_bitmapped_type(return_object);
+ if (data->return_btype == ACPI_RTYPE_ANY) {
- case ACPI_TYPE_PACKAGE:
- return_btype = ACPI_RTYPE_PACKAGE;
- break;
-
- case ACPI_TYPE_LOCAL_REFERENCE:
- return_btype = ACPI_RTYPE_REFERENCE;
- break;
-
- default:
/* Not one of the supported objects, must be incorrect */
-
goto type_error_exit;
}
- /* Is the object one of the expected types? */
-
- if (return_btype & expected_btypes) {
-
- /* For reference objects, check that the reference type is correct */
-
- if (return_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {
- status = acpi_ns_check_reference(data, return_object);
- }
+ /* For reference objects, check that the reference type is correct */
+ if ((data->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
+ status = acpi_ns_check_reference(data, return_object);
return (status);
}
- /* Type mismatch -- attempt repair of the returned object */
+ /* Attempt simple repair of the returned object if necessary */
- status = acpi_ns_repair_object(data, expected_btypes,
+ status = acpi_ns_simple_repair(data, expected_btypes,
package_index, return_object_ptr);
- if (ACPI_SUCCESS(status)) {
- return (AE_OK); /* Repair was successful */
- }
+ return (status);
type_error_exit:
/* Create a string with all expected types for this predefined object */
- acpi_ns_get_expected_types(type_buffer, expected_btypes);
+ acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
@@ -558,36 +438,55 @@ acpi_ns_check_reference(struct acpi_predefined_data *data,
/*******************************************************************************
*
- * FUNCTION: acpi_ns_get_expected_types
+ * FUNCTION: acpi_ns_get_bitmapped_type
*
- * PARAMETERS: buffer - Pointer to where the string is returned
- * expected_btypes - Bitmap of expected return type(s)
+ * PARAMETERS: return_object - Object returned from method/obj evaluation
*
- * RETURN: Buffer is populated with type names.
+ * RETURN: Object return type. ACPI_RTYPE_ANY indicates that the object
+ * type is not supported. ACPI_RTYPE_NONE indicates that no
+ * object was returned (return_object is NULL).
*
- * DESCRIPTION: Translate the expected types bitmap into a string of ascii
- * names of expected types, for use in warning messages.
+ * DESCRIPTION: Convert object type into a bitmapped object return type.
*
******************************************************************************/
-static void acpi_ns_get_expected_types(char *buffer, u32 expected_btypes)
+static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object)
{
- u32 this_rtype;
- u32 i;
- u32 j;
+ u32 return_btype;
- j = 1;
- buffer[0] = 0;
- this_rtype = ACPI_RTYPE_INTEGER;
+ if (!return_object) {
+ return (ACPI_RTYPE_NONE);
+ }
- for (i = 0; i < ACPI_NUM_RTYPES; i++) {
+ /* Map acpi_object_type to internal bitmapped type */
- /* If one of the expected types, concatenate the name of this type */
+ switch (return_object->common.type) {
+ case ACPI_TYPE_INTEGER:
+ return_btype = ACPI_RTYPE_INTEGER;
+ break;
- if (expected_btypes & this_rtype) {
- ACPI_STRCAT(buffer, &acpi_rtype_names[i][j]);
- j = 0; /* Use name separator from now on */
- }
- this_rtype <<= 1; /* Next Rtype */
+ case ACPI_TYPE_BUFFER:
+ return_btype = ACPI_RTYPE_BUFFER;
+ break;
+
+ case ACPI_TYPE_STRING:
+ return_btype = ACPI_RTYPE_STRING;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ return_btype = ACPI_RTYPE_PACKAGE;
+ break;
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return_btype = ACPI_RTYPE_REFERENCE;
+ break;
+
+ default:
+ /* Not one of the supported objects, must be incorrect */
+
+ return_btype = ACPI_RTYPE_ANY;
+ break;
}
+
+ return (return_btype);
}
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index a40155467d2e..77cdd539de16 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -112,9 +112,15 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
elements = return_object->package.elements;
count = return_object->package.count;
- /* The package must have at least one element, else invalid */
-
+ /*
+ * Most packages must have at least one element. The only exception
+ * is the variable-length package (ACPI_PTYPE1_VAR).
+ */
if (!count) {
+ if (package->ret_info.type == ACPI_PTYPE1_VAR) {
+ return (AE_OK);
+ }
+
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
"Return Package has no elements (empty)"));
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 9e833353c06a..18f02e4ece01 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -46,6 +46,7 @@
#include "acnamesp.h"
#include "acinterp.h"
#include "acpredef.h"
+#include "amlresrc.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsrepair")
@@ -71,6 +72,11 @@ ACPI_MODULE_NAME("nsrepair")
* Buffer -> String
* Buffer -> Package of Integers
* Package -> Package of one Package
+ *
+ * Additional conversions that are available:
+ * Convert a null return or zero return value to an end_tag descriptor
+ * Convert an ASCII string to a Unicode buffer
+ *
* An incorrect standalone object is wrapped with required outer package
*
* Additional possible repairs:
@@ -78,21 +84,51 @@ ACPI_MODULE_NAME("nsrepair")
*
******************************************************************************/
/* Local prototypes */
-static acpi_status
-acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object);
-
-static acpi_status
-acpi_ns_convert_to_string(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object);
+static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
+ acpi_namespace_node
+ *node,
+ u32
+ return_btype,
+ u32
+ package_index);
-static acpi_status
-acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object);
+/*
+ * Special but simple repairs for some names.
+ *
+ * 2nd argument: Unexpected types that can be repaired
+ */
+static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
+ /* Resource descriptor conversions */
+
+ {"_CRS",
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
+ ACPI_RTYPE_NONE,
+ ACPI_NOT_PACKAGE_ELEMENT,
+ acpi_ns_convert_to_resource},
+ {"_DMA",
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
+ ACPI_RTYPE_NONE,
+ ACPI_NOT_PACKAGE_ELEMENT,
+ acpi_ns_convert_to_resource},
+ {"_PRS",
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
+ ACPI_RTYPE_NONE,
+ ACPI_NOT_PACKAGE_ELEMENT,
+ acpi_ns_convert_to_resource},
+
+ /* Unicode conversions */
+
+ {"_MLS", ACPI_RTYPE_STRING, 1,
+ acpi_ns_convert_to_unicode},
+ {"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER,
+ ACPI_NOT_PACKAGE_ELEMENT,
+ acpi_ns_convert_to_unicode},
+ {{0, 0, 0, 0}, 0, 0, NULL} /* Table terminator */
+};
/*******************************************************************************
*
- * FUNCTION: acpi_ns_repair_object
+ * FUNCTION: acpi_ns_simple_repair
*
* PARAMETERS: data - Pointer to validation data structure
* expected_btypes - Object types expected
@@ -110,16 +146,54 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
******************************************************************************/
acpi_status
-acpi_ns_repair_object(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_predefined_data *data,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
- union acpi_operand_object *new_object;
+ union acpi_operand_object *new_object = NULL;
acpi_status status;
+ const struct acpi_simple_repair_info *predefined;
+
+ ACPI_FUNCTION_NAME(ns_simple_repair);
+
+ /*
+ * Special repairs for certain names that are in the repair table.
+ * Check if this name is in the list of repairable names.
+ */
+ predefined = acpi_ns_match_simple_repair(data->node,
+ data->return_btype,
+ package_index);
+ if (predefined) {
+ if (!return_object) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
+ }
+
+ status =
+ predefined->object_converter(return_object, &new_object);
+ if (ACPI_FAILURE(status)) {
+
+ /* A fatal error occurred during a conversion */
+
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During return object analysis"));
+ return (status);
+ }
+ if (new_object) {
+ goto object_repaired;
+ }
+ }
- ACPI_FUNCTION_NAME(ns_repair_object);
+ /*
+ * Do not perform simple object repair unless the return type is not
+ * expected.
+ */
+ if (data->return_btype & expected_btypes) {
+ return (AE_OK);
+ }
/*
* At this point, we know that the type of the returned object was not
@@ -127,6 +201,24 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
* repair the object by converting it to one of the expected object
* types for this predefined name.
*/
+
+ /*
+ * If there is no return value, check if we require a return value for
+ * this predefined name. Either one return value is expected, or none,
+ * for both methods and other objects.
+ *
+ * Exit now if there is no return object. Warning if one was expected.
+ */
+ if (!return_object) {
+ if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
+ ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ ACPI_WARN_ALWAYS,
+ "Missing expected return value"));
+
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+ }
+
if (expected_btypes & ACPI_RTYPE_INTEGER) {
status = acpi_ns_convert_to_integer(return_object, &new_object);
if (ACPI_SUCCESS(status)) {
@@ -216,254 +308,51 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
return (AE_OK);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_convert_to_integer
- *
- * PARAMETERS: original_object - Object to be converted
- * return_object - Where the new converted object is returned
- *
- * RETURN: Status. AE_OK if conversion was successful.
- *
- * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object)
-{
- union acpi_operand_object *new_object;
- acpi_status status;
- u64 value = 0;
- u32 i;
-
- switch (original_object->common.type) {
- case ACPI_TYPE_STRING:
-
- /* String-to-Integer conversion */
-
- status = acpi_ut_strtoul64(original_object->string.pointer,
- ACPI_ANY_BASE, &value);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
-
- case ACPI_TYPE_BUFFER:
-
- /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
-
- if (original_object->buffer.length > 8) {
- return (AE_AML_OPERAND_TYPE);
- }
-
- /* Extract each buffer byte to create the integer */
-
- for (i = 0; i < original_object->buffer.length; i++) {
- value |=
- ((u64) original_object->buffer.
- pointer[i] << (i * 8));
- }
- break;
-
- default:
- return (AE_AML_OPERAND_TYPE);
- }
-
- new_object = acpi_ut_create_integer_object(value);
- if (!new_object) {
- return (AE_NO_MEMORY);
- }
-
- *return_object = new_object;
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_convert_to_string
- *
- * PARAMETERS: original_object - Object to be converted
- * return_object - Where the new converted object is returned
- *
- * RETURN: Status. AE_OK if conversion was successful.
- *
- * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_ns_convert_to_string(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object)
-{
- union acpi_operand_object *new_object;
- acpi_size length;
- acpi_status status;
-
- switch (original_object->common.type) {
- case ACPI_TYPE_INTEGER:
- /*
- * Integer-to-String conversion. Commonly, convert
- * an integer of value 0 to a NULL string. The last element of
- * _BIF and _BIX packages occasionally need this fix.
- */
- if (original_object->integer.value == 0) {
-
- /* Allocate a new NULL string object */
-
- new_object = acpi_ut_create_string_object(0);
- if (!new_object) {
- return (AE_NO_MEMORY);
- }
- } else {
- status =
- acpi_ex_convert_to_string(original_object,
- &new_object,
- ACPI_IMPLICIT_CONVERT_HEX);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
- break;
-
- case ACPI_TYPE_BUFFER:
- /*
- * Buffer-to-String conversion. Use a to_string
- * conversion, no transform performed on the buffer data. The best
- * example of this is the _BIF method, where the string data from
- * the battery is often (incorrectly) returned as buffer object(s).
- */
- length = 0;
- while ((length < original_object->buffer.length) &&
- (original_object->buffer.pointer[length])) {
- length++;
- }
-
- /* Allocate a new string object */
-
- new_object = acpi_ut_create_string_object(length);
- if (!new_object) {
- return (AE_NO_MEMORY);
- }
-
- /*
- * Copy the raw buffer data with no transform. String is already NULL
- * terminated at Length+1.
- */
- ACPI_MEMCPY(new_object->string.pointer,
- original_object->buffer.pointer, length);
- break;
-
- default:
- return (AE_AML_OPERAND_TYPE);
- }
-
- *return_object = new_object;
- return (AE_OK);
-}
-
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_ns_convert_to_buffer
+ * FUNCTION: acpi_ns_match_simple_repair
*
- * PARAMETERS: original_object - Object to be converted
- * return_object - Where the new converted object is returned
+ * PARAMETERS: node - Namespace node for the method/object
+ * return_btype - Object type that was returned
+ * package_index - Index of object within parent package (if
+ * applicable - ACPI_NOT_PACKAGE_ELEMENT
+ * otherwise)
*
- * RETURN: Status. AE_OK if conversion was successful.
+ * RETURN: Pointer to entry in repair table. NULL indicates not found.
*
- * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
+ * DESCRIPTION: Check an object name against the repairable object list.
*
- ******************************************************************************/
+ *****************************************************************************/
-static acpi_status
-acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
- union acpi_operand_object **return_object)
+static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
+ acpi_namespace_node
+ *node,
+ u32
+ return_btype,
+ u32
+ package_index)
{
- union acpi_operand_object *new_object;
- acpi_status status;
- union acpi_operand_object **elements;
- u32 *dword_buffer;
- u32 count;
- u32 i;
+ const struct acpi_simple_repair_info *this_name;
- switch (original_object->common.type) {
- case ACPI_TYPE_INTEGER:
- /*
- * Integer-to-Buffer conversion.
- * Convert the Integer to a packed-byte buffer. _MAT and other
- * objects need this sometimes, if a read has been performed on a
- * Field object that is less than or equal to the global integer
- * size (32 or 64 bits).
- */
- status =
- acpi_ex_convert_to_buffer(original_object, &new_object);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- break;
+ /* Search info table for a repairable predefined method/object name */
- case ACPI_TYPE_STRING:
+ this_name = acpi_object_repair_info;
+ while (this_name->object_converter) {
+ if (ACPI_COMPARE_NAME(node->name.ascii, this_name->name)) {
- /* String-to-Buffer conversion. Simple data copy */
-
- new_object =
- acpi_ut_create_buffer_object(original_object->string.
- length);
- if (!new_object) {
- return (AE_NO_MEMORY);
- }
+ /* Check if we can actually repair this name/type combination */
- ACPI_MEMCPY(new_object->buffer.pointer,
- original_object->string.pointer,
- original_object->string.length);
- break;
-
- case ACPI_TYPE_PACKAGE:
- /*
- * This case is often seen for predefined names that must return a
- * Buffer object with multiple DWORD integers within. For example,
- * _FDE and _GTM. The Package can be converted to a Buffer.
- */
-
- /* All elements of the Package must be integers */
-
- elements = original_object->package.elements;
- count = original_object->package.count;
-
- for (i = 0; i < count; i++) {
- if ((!*elements) ||
- ((*elements)->common.type != ACPI_TYPE_INTEGER)) {
- return (AE_AML_OPERAND_TYPE);
+ if ((return_btype & this_name->unexpected_btypes) &&
+ (package_index == this_name->package_index)) {
+ return (this_name);
}
- elements++;
- }
-
- /* Create the new buffer object to replace the Package */
- new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
- if (!new_object) {
- return (AE_NO_MEMORY);
+ return (NULL);
}
-
- /* Copy the package elements (integers) to the buffer as DWORDs */
-
- elements = original_object->package.elements;
- dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
-
- for (i = 0; i < count; i++) {
- *dword_buffer = (u32) (*elements)->integer.value;
- dword_buffer++;
- elements++;
- }
- break;
-
- default:
- return (AE_AML_OPERAND_TYPE);
+ this_name++;
}
- *return_object = new_object;
- return (AE_OK);
+ return (NULL); /* Name was not found in the repair table */
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index ba4d98287c6a..149e9b9c2c1b 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -66,9 +66,9 @@ typedef struct acpi_repair_info {
/* Local prototypes */
-static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
- acpi_namespace_node
- *node);
+static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
+ acpi_namespace_node
+ *node);
static acpi_status
acpi_ns_repair_ALR(struct acpi_predefined_data *data,
@@ -175,7 +175,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
/* Check if this name is in the list of repairable names */
- predefined = acpi_ns_match_repairable_name(node);
+ predefined = acpi_ns_match_complex_repair(node);
if (!predefined) {
return (validate_status);
}
@@ -186,7 +186,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
/******************************************************************************
*
- * FUNCTION: acpi_ns_match_repairable_name
+ * FUNCTION: acpi_ns_match_complex_repair
*
* PARAMETERS: node - Namespace node for the method/object
*
@@ -196,9 +196,9 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
*
*****************************************************************************/
-static const struct acpi_repair_info *acpi_ns_match_repairable_name(struct
- acpi_namespace_node
- *node)
+static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
+ acpi_namespace_node
+ *node)
{
const struct acpi_repair_info *this_name;
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 686420df684f..2808586fad30 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -112,10 +112,10 @@ acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
if (!node) {
ACPI_WARNING((AE_INFO, "Null Node parameter"));
- return_VALUE(ACPI_TYPE_ANY);
+ return_UINT8(ACPI_TYPE_ANY);
}
- return_VALUE(node->type);
+ return_UINT8(node->type);
}
/*******************************************************************************
@@ -140,10 +140,10 @@ u32 acpi_ns_local(acpi_object_type type)
/* Type code out of range */
ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
- return_VALUE(ACPI_NS_NORMAL);
+ return_UINT32(ACPI_NS_NORMAL);
}
- return_VALUE(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
+ return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index f51308cdbc65..9f25a3d4e992 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -108,7 +108,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state)
/* Byte 0 is a special case, either bits [0:3] or [0:5] are used */
package_length |= (aml[0] & byte_zero_mask);
- return_VALUE(package_length);
+ return_UINT32(package_length);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 7816d4eef04e..72077fa1eea5 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -202,6 +202,12 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE);
}
+ /* Sanity check the length. It must not be zero, or we loop forever */
+
+ if (!resource->length) {
+ return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
/* Get the base size of the (external stream) resource descriptor */
total_size = acpi_gbl_aml_resource_sizes[resource->type];
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index cab51445189d..b5fc0db2e87b 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -385,6 +385,14 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list)
return;
}
+ /* Sanity check the length. It must not be zero, or we loop forever */
+
+ if (!resource_list->length) {
+ acpi_os_printf
+ ("Invalid zero length descriptor in resource list\n");
+ return;
+ }
+
/* Dump the resource descriptor */
if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index ee2e206fc6c8..6053aa182093 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -178,6 +178,14 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
return_ACPI_STATUS(AE_BAD_DATA);
}
+ /* Sanity check the length. It must not be zero, or we loop forever */
+
+ if (!resource->length) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid zero length descriptor in resource list\n"));
+ return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
/* Perform the conversion */
if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 15d6eaef0e28..c0e5d2d3ce67 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -563,13 +563,19 @@ acpi_walk_resource_buffer(struct acpi_buffer * buffer,
while (resource < resource_end) {
- /* Sanity check the resource */
+ /* Sanity check the resource type */
if (resource->type > ACPI_RESOURCE_TYPE_MAX) {
status = AE_AML_INVALID_RESOURCE_TYPE;
break;
}
+ /* Sanity check the length. It must not be zero, or we loop forever */
+
+ if (!resource->length) {
+ return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
/* Invoke the user function, abort on any error returned */
status = user_function(resource, context);
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 74181bf181ec..33b00d22300a 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -559,8 +559,12 @@ static void acpi_tb_validate_fadt(void)
/*
* For each extended field, check for length mismatch between the
* legacy length field and the corresponding 64-bit X length field.
+ * Note: If the legacy length field is > 0xFF bits, ignore this
+ * check. (GPE registers can be larger than the 64-bit GAS structure
+ * can accomodate, 0xFF bits).
*/
if (address64->address &&
+ (ACPI_MUL_8(length) <= ACPI_UINT8_MAX) &&
(address64->bit_width != ACPI_MUL_8(length))) {
ACPI_BIOS_WARNING((AE_INFO,
"32/64X length mismatch in FADT/%s: %u/%u",
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index b35a5e6d653a..ad11162482ff 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Module Name: tbxface - ACPI table oriented external interfaces
+ * Module Name: tbxface - ACPI table-oriented external interfaces
*
*****************************************************************************/
@@ -80,7 +80,7 @@ acpi_status acpi_allocate_root_table(u32 initial_table_count)
* array is dynamically allocated.
* initial_table_count - Size of initial_table_array, in number of
* struct acpi_table_desc structures
- * allow_realloc - Flag to tell Table Manager if resize of
+ * allow_resize - Flag to tell Table Manager if resize of
* pre-allocated array is allowed. Ignored
* if initial_table_array is NULL.
*
@@ -107,8 +107,8 @@ acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
ACPI_FUNCTION_TRACE(acpi_initialize_tables);
/*
- * Set up the Root Table Array
- * Allocate the table array if requested
+ * Setup the Root Table Array and allocate the table array
+ * if requested
*/
if (!initial_table_array) {
status = acpi_allocate_root_table(initial_table_count);
@@ -305,9 +305,10 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
* instance - Which instance (for SSDTs)
* out_table - Where the pointer to the table is returned
*
- * RETURN: Status and pointer to table
+ * RETURN: Status and pointer to the requested table
*
- * DESCRIPTION: Finds and verifies an ACPI table.
+ * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the
+ * RSDT/XSDT.
*
******************************************************************************/
acpi_status
@@ -375,9 +376,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
* PARAMETERS: table_index - Table index
* table - Where the pointer to the table is returned
*
- * RETURN: Status and pointer to the table
+ * RETURN: Status and pointer to the requested table
*
- * DESCRIPTION: Obtain a table by an index into the global table list.
+ * DESCRIPTION: Obtain a table by an index into the global table list. Used
+ * internally also.
*
******************************************************************************/
acpi_status
@@ -432,7 +434,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
*
* RETURN: Status
*
- * DESCRIPTION: Install table event handler
+ * DESCRIPTION: Install a global table event handler.
*
******************************************************************************/
acpi_status
@@ -479,7 +481,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
*
* RETURN: Status
*
- * DESCRIPTION: Remove table event handler
+ * DESCRIPTION: Remove a table event handler
*
******************************************************************************/
acpi_status acpi_remove_table_handler(acpi_table_handler handler)
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index 698b9d385516..e0a2e2779c2e 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -214,7 +214,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
- return_VALUE(0);
+ return_UINT32(0);
}
range_info = acpi_gbl_address_range_list[space_id];
@@ -256,7 +256,7 @@ acpi_ut_check_address_range(acpi_adr_space_type space_id,
range_info = range_info->next;
}
- return_VALUE(overlap_count);
+ return_UINT32(overlap_count);
}
/*******************************************************************************
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index e0e8579deaac..a877a9647fd9 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -85,7 +85,6 @@ acpi_os_create_cache(char *cache_name,
/* Populate the cache object and return it */
ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list));
- cache->link_offset = 8;
cache->list_name = cache_name;
cache->object_size = object_size;
cache->max_depth = max_depth;
@@ -108,7 +107,7 @@ acpi_os_create_cache(char *cache_name,
acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
{
- char *next;
+ void *next;
acpi_status status;
ACPI_FUNCTION_ENTRY();
@@ -128,10 +127,7 @@ acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
/* Delete and unlink one cached state object */
- next = *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)cache->
- list_head)[cache->
- link_offset])));
+ next = ACPI_GET_DESCRIPTOR_PTR(cache->list_head);
ACPI_FREE(cache->list_head);
cache->list_head = next;
@@ -221,10 +217,7 @@ acpi_os_release_object(struct acpi_memory_list * cache, void *object)
/* Put the object at the head of the cache list */
- *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)object)[cache->
- link_offset]))) =
- cache->list_head;
+ ACPI_SET_DESCRIPTOR_PTR(object, cache->list_head);
cache->list_head = object;
cache->current_depth++;
@@ -272,10 +265,7 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
/* There is an object available, use it */
object = cache->list_head;
- cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)
- object)[cache->
- link_offset])));
+ cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object);
cache->current_depth--;
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 2541de420249..29b930250b6f 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -359,19 +359,20 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
* FUNCTION: acpi_ut_update_ref_count
*
* PARAMETERS: object - Object whose ref count is to be updated
- * action - What to do
+ * action - What to do (REF_INCREMENT or REF_DECREMENT)
*
- * RETURN: New ref count
+ * RETURN: None. Sets new reference count within the object
*
- * DESCRIPTION: Modify the ref count and return it.
+ * DESCRIPTION: Modify the reference count for an internal acpi object
*
******************************************************************************/
static void
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
{
- u16 count;
- u16 new_count;
+ u16 original_count;
+ u16 new_count = 0;
+ acpi_cpu_flags lock_flags;
ACPI_FUNCTION_NAME(ut_update_ref_count);
@@ -379,76 +380,79 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
return;
}
- count = object->common.reference_count;
- new_count = count;
-
/*
- * Perform the reference count action (increment, decrement, force delete)
+ * Always get the reference count lock. Note: Interpreter and/or
+ * Namespace is not always locked when this function is called.
*/
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
+ original_count = object->common.reference_count;
+
+ /* Perform the reference count action (increment, decrement) */
+
switch (action) {
case REF_INCREMENT:
- new_count++;
+ new_count = original_count + 1;
object->common.reference_count = new_count;
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
+
+ /* The current reference count should never be zero here */
+
+ if (!original_count) {
+ ACPI_WARNING((AE_INFO,
+ "Obj %p, Reference Count was zero before increment\n",
+ object));
+ }
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, [Incremented]\n",
- object, new_count));
+ "Obj %p Type %.2X Refs %.2X [Incremented]\n",
+ object, object->common.type, new_count));
break;
case REF_DECREMENT:
- if (count < 1) {
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
- object, new_count));
-
- new_count = 0;
- } else {
- new_count--;
+ /* The current reference count must be non-zero */
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, [Decremented]\n",
- object, new_count));
+ if (original_count) {
+ new_count = original_count - 1;
+ object->common.reference_count = new_count;
}
- if (object->common.type == ACPI_TYPE_METHOD) {
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Method Obj %p Refs=%X, [Decremented]\n",
- object, new_count));
- }
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
- object->common.reference_count = new_count;
- if (new_count == 0) {
- acpi_ut_delete_internal_obj(object);
+ if (!original_count) {
+ ACPI_WARNING((AE_INFO,
+ "Obj %p, Reference Count is already zero, cannot decrement\n",
+ object));
}
- break;
-
- case REF_FORCE_DELETE:
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, Force delete! (Set to 0)\n",
- object, count));
+ "Obj %p Type %.2X Refs %.2X [Decremented]\n",
+ object, object->common.type, new_count));
- new_count = 0;
- object->common.reference_count = new_count;
- acpi_ut_delete_internal_obj(object);
+ /* Actually delete the object on a reference count of zero */
+
+ if (new_count == 0) {
+ acpi_ut_delete_internal_obj(object);
+ }
break;
default:
- ACPI_ERROR((AE_INFO, "Unknown action (0x%X)", action));
- break;
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
+ ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
+ action));
+ return;
}
/*
* Sanity check the reference count, for debug purposes only.
* (A deleted object will have a huge reference count)
*/
- if (count > ACPI_MAX_REFERENCE_COUNT) {
+ if (new_count > ACPI_MAX_REFERENCE_COUNT) {
ACPI_WARNING((AE_INFO,
- "Large Reference Count (0x%X) in object %p",
- count, object));
+ "Large Reference Count (0x%X) in object %p, Type=0x%.2X",
+ new_count, object, object->common.type));
}
}
@@ -458,8 +462,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
*
* PARAMETERS: object - Increment ref count for this object
* and all sub-objects
- * action - Either REF_INCREMENT or REF_DECREMENT or
- * REF_FORCE_DELETE
+ * action - Either REF_INCREMENT or REF_DECREMENT
*
* RETURN: Status
*
@@ -714,7 +717,6 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
/*
* Allow a NULL pointer to be passed in, just ignore it. This saves
* each caller from having to check. Also, ignore NS nodes.
- *
*/
if (!object ||
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index a0ab7c02e87c..b543a144941a 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -64,7 +64,7 @@ ACPI_MODULE_NAME("utexcep")
******************************************************************************/
const char *acpi_format_exception(acpi_status status)
{
- const char *exception = NULL;
+ const struct acpi_exception_info *exception;
ACPI_FUNCTION_ENTRY();
@@ -76,10 +76,10 @@ const char *acpi_format_exception(acpi_status status)
ACPI_ERROR((AE_INFO,
"Unknown exception code: 0x%8.8X", status));
- exception = "UNKNOWN_STATUS_CODE";
+ return ("UNKNOWN_STATUS_CODE");
}
- return (ACPI_CAST_PTR(const char, exception));
+ return (exception->name);
}
ACPI_EXPORT_SYMBOL(acpi_format_exception)
@@ -97,10 +97,10 @@ ACPI_EXPORT_SYMBOL(acpi_format_exception)
* an ASCII string.
*
******************************************************************************/
-const char *acpi_ut_validate_exception(acpi_status status)
+const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status status)
{
u32 sub_status;
- const char *exception = NULL;
+ const struct acpi_exception_info *exception = NULL;
ACPI_FUNCTION_ENTRY();
@@ -113,35 +113,35 @@ const char *acpi_ut_validate_exception(acpi_status status)
case AE_CODE_ENVIRONMENTAL:
if (sub_status <= AE_CODE_ENV_MAX) {
- exception = acpi_gbl_exception_names_env[sub_status];
+ exception = &acpi_gbl_exception_names_env[sub_status];
}
break;
case AE_CODE_PROGRAMMER:
if (sub_status <= AE_CODE_PGM_MAX) {
- exception = acpi_gbl_exception_names_pgm[sub_status];
+ exception = &acpi_gbl_exception_names_pgm[sub_status];
}
break;
case AE_CODE_ACPI_TABLES:
if (sub_status <= AE_CODE_TBL_MAX) {
- exception = acpi_gbl_exception_names_tbl[sub_status];
+ exception = &acpi_gbl_exception_names_tbl[sub_status];
}
break;
case AE_CODE_AML:
if (sub_status <= AE_CODE_AML_MAX) {
- exception = acpi_gbl_exception_names_aml[sub_status];
+ exception = &acpi_gbl_exception_names_aml[sub_status];
}
break;
case AE_CODE_CONTROL:
if (sub_status <= AE_CODE_CTRL_MAX) {
- exception = acpi_gbl_exception_names_ctrl[sub_status];
+ exception = &acpi_gbl_exception_names_ctrl[sub_status];
}
break;
@@ -149,5 +149,9 @@ const char *acpi_ut_validate_exception(acpi_status status)
break;
}
- return (ACPI_CAST_PTR(const char, exception));
+ if (!exception || !exception->name) {
+ return (NULL);
+ }
+
+ return (exception);
}
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index ffecf4b4f0dd..f736448a8606 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -359,6 +359,8 @@ acpi_status acpi_ut_init_globals(void)
#ifdef ACPI_DISASSEMBLER
acpi_gbl_external_list = NULL;
+ acpi_gbl_num_external_methods = 0;
+ acpi_gbl_resolved_external_methods = 0;
#endif
#ifdef ACPI_DEBUG_OUTPUT
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 22feb99b8e35..08c323245584 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -81,7 +81,7 @@ acpi_status acpi_ut_mutex_initialize(void)
}
}
- /* Create the spinlocks for use at interrupt level */
+ /* Create the spinlocks for use at interrupt level or for speed */
status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
if (ACPI_FAILURE (status)) {
@@ -93,7 +93,13 @@ acpi_status acpi_ut_mutex_initialize(void)
return_ACPI_STATUS (status);
}
+ status = acpi_os_create_lock(&acpi_gbl_reference_count_lock);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
/* Mutex for _OSI support */
+
status = acpi_os_create_mutex(&acpi_gbl_osi_mutex);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -136,6 +142,7 @@ void acpi_ut_mutex_terminate(void)
acpi_os_delete_lock(acpi_gbl_gpe_lock);
acpi_os_delete_lock(acpi_gbl_hardware_lock);
+ acpi_os_delete_lock(acpi_gbl_reference_count_lock);
/* Delete the reader/writer lock */
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 36a7d361d7cb..b15acebb96a1 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -108,9 +108,14 @@ static struct acpi_interface_info acpi_default_supported_interfaces[] = {
acpi_status acpi_ut_initialize_interfaces(void)
{
+ acpi_status status;
u32 i;
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
/* Link the static list of supported interfaces */
@@ -132,20 +137,24 @@ acpi_status acpi_ut_initialize_interfaces(void)
*
* PARAMETERS: None
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Delete all interfaces in the global list. Sets
* acpi_gbl_supported_interfaces to NULL.
*
******************************************************************************/
-void acpi_ut_interface_terminate(void)
+acpi_status acpi_ut_interface_terminate(void)
{
+ acpi_status status;
struct acpi_interface_info *next_interface;
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
- next_interface = acpi_gbl_supported_interfaces;
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ next_interface = acpi_gbl_supported_interfaces;
while (next_interface) {
acpi_gbl_supported_interfaces = next_interface->next;
@@ -160,6 +169,7 @@ void acpi_ut_interface_terminate(void)
}
acpi_os_release_mutex(acpi_gbl_osi_mutex);
+ return (AE_OK);
}
/*******************************************************************************
@@ -315,6 +325,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
union acpi_operand_object *return_desc;
struct acpi_interface_info *interface_info;
acpi_interface_handler interface_handler;
+ acpi_status status;
u32 return_value;
ACPI_FUNCTION_TRACE(ut_osi_implementation);
@@ -336,7 +347,10 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state * walk_state)
/* Default return value is 0, NOT SUPPORTED */
return_value = 0;
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
/* Lookup the interface in the global _OSI list */
diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c
new file mode 100644
index 000000000000..29459479148f
--- /dev/null
+++ b/drivers/acpi/acpica/utpredef.c
@@ -0,0 +1,399 @@
+/******************************************************************************
+ *
+ * Module Name: utpredef - support functions for predefined names
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acpredef.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utpredef")
+
+/*
+ * Names for the types that can be returned by the predefined objects.
+ * Used for warning messages. Must be in the same order as the ACPI_RTYPEs
+ */
+static const char *ut_rtype_names[] = {
+ "/Integer",
+ "/String",
+ "/Buffer",
+ "/Package",
+ "/Reference",
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_next_predefined_method
+ *
+ * PARAMETERS: this_name - Entry in the predefined method/name table
+ *
+ * RETURN: Pointer to next entry in predefined table.
+ *
+ * DESCRIPTION: Get the next entry in the predefine method table. Handles the
+ * cases where a package info entry follows a method name that
+ * returns a package.
+ *
+ ******************************************************************************/
+
+const union acpi_predefined_info *acpi_ut_get_next_predefined_method(const union
+ acpi_predefined_info
+ *this_name)
+{
+
+ /*
+ * Skip next entry in the table if this name returns a Package
+ * (next entry contains the package info)
+ */
+ if ((this_name->info.expected_btypes & ACPI_RTYPE_PACKAGE) &&
+ (this_name->info.expected_btypes != ACPI_RTYPE_ALL)) {
+ this_name++;
+ }
+
+ this_name++;
+ return (this_name);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_match_predefined_method
+ *
+ * PARAMETERS: name - Name to find
+ *
+ * RETURN: Pointer to entry in predefined table. NULL indicates not found.
+ *
+ * DESCRIPTION: Check an object name against the predefined object list.
+ *
+ ******************************************************************************/
+
+const union acpi_predefined_info *acpi_ut_match_predefined_method(char *name)
+{
+ const union acpi_predefined_info *this_name;
+
+ /* Quick check for a predefined name, first character must be underscore */
+
+ if (name[0] != '_') {
+ return (NULL);
+ }
+
+ /* Search info table for a predefined method/object name */
+
+ this_name = acpi_gbl_predefined_methods;
+ while (this_name->info.name[0]) {
+ if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
+ return (this_name);
+ }
+
+ this_name = acpi_ut_get_next_predefined_method(this_name);
+ }
+
+ return (NULL); /* Not found */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_expected_return_types
+ *
+ * PARAMETERS: buffer - Where the formatted string is returned
+ * expected_Btypes - Bitfield of expected data types
+ *
+ * RETURN: Formatted string in Buffer.
+ *
+ * DESCRIPTION: Format the expected object types into a printable string.
+ *
+ ******************************************************************************/
+
+void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes)
+{
+ u32 this_rtype;
+ u32 i;
+ u32 j;
+
+ j = 1;
+ buffer[0] = 0;
+ this_rtype = ACPI_RTYPE_INTEGER;
+
+ for (i = 0; i < ACPI_NUM_RTYPES; i++) {
+
+ /* If one of the expected types, concatenate the name of this type */
+
+ if (expected_btypes & this_rtype) {
+ ACPI_STRCAT(buffer, &ut_rtype_names[i][j]);
+ j = 0; /* Use name separator from now on */
+ }
+
+ this_rtype <<= 1; /* Next Rtype */
+ }
+}
+
+/*******************************************************************************
+ *
+ * The remaining functions are used by iASL and acpi_help only
+ *
+ ******************************************************************************/
+
+#if (defined ACPI_ASL_COMPILER || defined ACPI_HELP_APP)
+#include <stdio.h>
+#include <string.h>
+
+/* Local prototypes */
+
+static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types);
+
+/* Types that can be returned externally by a predefined name */
+
+static const char *ut_external_type_names[] = /* Indexed by ACPI_TYPE_* */
+{
+ ", UNSUPPORTED-TYPE",
+ ", Integer",
+ ", String",
+ ", Buffer",
+ ", Package"
+};
+
+/* Bit widths for resource descriptor predefined names */
+
+static const char *ut_resource_type_names[] = {
+ "/1",
+ "/2",
+ "/3",
+ "/8",
+ "/16",
+ "/32",
+ "/64",
+ "/variable",
+};
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_match_resource_name
+ *
+ * PARAMETERS: name - Name to find
+ *
+ * RETURN: Pointer to entry in the resource table. NULL indicates not
+ * found.
+ *
+ * DESCRIPTION: Check an object name against the predefined resource
+ * descriptor object list.
+ *
+ ******************************************************************************/
+
+const union acpi_predefined_info *acpi_ut_match_resource_name(char *name)
+{
+ const union acpi_predefined_info *this_name;
+
+ /* Quick check for a predefined name, first character must be underscore */
+
+ if (name[0] != '_') {
+ return (NULL);
+ }
+
+ /* Search info table for a predefined method/object name */
+
+ this_name = acpi_gbl_resource_names;
+ while (this_name->info.name[0]) {
+ if (ACPI_COMPARE_NAME(name, this_name->info.name)) {
+ return (this_name);
+ }
+
+ this_name++;
+ }
+
+ return (NULL); /* Not found */
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_display_predefined_method
+ *
+ * PARAMETERS: buffer - Scratch buffer for this function
+ * this_name - Entry in the predefined method/name table
+ * multi_line - TRUE if output should be on >1 line
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Display information about a predefined method. Number and
+ * type of the input arguments, and expected type(s) for the
+ * return value, if any.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_display_predefined_method(char *buffer,
+ const union acpi_predefined_info *this_name,
+ u8 multi_line)
+{
+ u32 arg_count;
+
+ /*
+ * Get the argument count and the string buffer
+ * containing all argument types
+ */
+ arg_count = acpi_ut_get_argument_types(buffer,
+ this_name->info.argument_list);
+
+ if (multi_line) {
+ printf(" ");
+ }
+
+ printf("%4.4s Requires %s%u argument%s",
+ this_name->info.name,
+ (this_name->info.argument_list & ARG_COUNT_IS_MINIMUM) ?
+ "(at least) " : "", arg_count, arg_count != 1 ? "s" : "");
+
+ /* Display the types for any arguments */
+
+ if (arg_count > 0) {
+ printf(" (%s)", buffer);
+ }
+
+ if (multi_line) {
+ printf("\n ");
+ }
+
+ /* Get the return value type(s) allowed */
+
+ if (this_name->info.expected_btypes) {
+ acpi_ut_get_expected_return_types(buffer,
+ this_name->info.
+ expected_btypes);
+ printf(" Return value types: %s\n", buffer);
+ } else {
+ printf(" No return value\n");
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_argument_types
+ *
+ * PARAMETERS: buffer - Where to return the formatted types
+ * argument_types - Types field for this method
+ *
+ * RETURN: count - the number of arguments required for this method
+ *
+ * DESCRIPTION: Format the required data types for this method (Integer,
+ * String, Buffer, or Package) and return the required argument
+ * count.
+ *
+ ******************************************************************************/
+
+static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
+{
+ u16 this_argument_type;
+ u16 sub_index;
+ u16 arg_count;
+ u32 i;
+
+ *buffer = 0;
+ sub_index = 2;
+
+ /* First field in the types list is the count of args to follow */
+
+ arg_count = (argument_types & METHOD_ARG_MASK);
+ argument_types >>= METHOD_ARG_BIT_WIDTH;
+
+ if (arg_count > METHOD_PREDEF_ARGS_MAX) {
+ printf("**** Invalid argument count (%u) "
+ "in predefined info structure\n", arg_count);
+ return (arg_count);
+ }
+
+ /* Get each argument from the list, convert to ascii, store to buffer */
+
+ for (i = 0; i < arg_count; i++) {
+ this_argument_type = (argument_types & METHOD_ARG_MASK);
+ if (!this_argument_type
+ || (this_argument_type > METHOD_MAX_ARG_TYPE)) {
+ printf("**** Invalid argument type (%u) "
+ "in predefined info structure\n",
+ this_argument_type);
+ return (arg_count);
+ }
+
+ strcat(buffer,
+ ut_external_type_names[this_argument_type] + sub_index);
+
+ /* Shift to next argument type field */
+
+ argument_types >>= METHOD_ARG_BIT_WIDTH;
+ sub_index = 0;
+ }
+
+ return (arg_count);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_resource_bit_width
+ *
+ * PARAMETERS: buffer - Where the formatted string is returned
+ * types - Bitfield of expected data types
+ *
+ * RETURN: Count of return types. Formatted string in Buffer.
+ *
+ * DESCRIPTION: Format the resource bit widths into a printable string.
+ *
+ ******************************************************************************/
+
+u32 acpi_ut_get_resource_bit_width(char *buffer, u16 types)
+{
+ u32 i;
+ u16 sub_index;
+ u32 found;
+
+ *buffer = 0;
+ sub_index = 1;
+ found = 0;
+
+ for (i = 0; i < NUM_RESOURCE_WIDTHS; i++) {
+ if (types & 1) {
+ strcat(buffer, &(ut_resource_type_names[i][sub_index]));
+ sub_index = 0;
+ found++;
+ }
+
+ types >>= 1;
+ }
+
+ return (found);
+}
+#endif
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 48efb446258c..6505774f223e 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -287,7 +287,10 @@ acpi_status acpi_install_interface(acpi_string interface_name)
return (AE_BAD_PARAMETER);
}
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
/* Check if the interface name is already in the global list */
@@ -336,7 +339,10 @@ acpi_status acpi_remove_interface(acpi_string interface_name)
return (AE_BAD_PARAMETER);
}
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
status = acpi_ut_remove_interface(interface_name);
@@ -362,9 +368,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_interface)
****************************************************************************/
acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
{
- acpi_status status = AE_OK;
+ acpi_status status;
- (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
if (handler && acpi_gbl_interface_handler) {
status = AE_ALREADY_EXISTS;
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index 1e5d8a40101e..fefc2ca7cc3e 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -405,7 +405,7 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
return rc;
data_len = estatus->data_length;
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
- while (data_len > sizeof(*gdata)) {
+ while (data_len >= sizeof(*gdata)) {
gedata_len = gdata->error_data_length;
if (gedata_len > data_len - sizeof(*gdata))
return -EINVAL;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 169ced7e540d..e7100459ac4a 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -146,7 +146,7 @@ struct acpi_battery {
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat)
-inline int acpi_battery_present(struct acpi_battery *battery)
+static inline int acpi_battery_present(struct acpi_battery *battery)
{
return battery->device->status.battery_present;
}
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 01708a165368..292de3cab9cc 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -288,13 +288,12 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
}
out_success:
context->ret.length = out_obj->buffer.length;
- context->ret.pointer = kmalloc(context->ret.length, GFP_KERNEL);
+ context->ret.pointer = kmemdup(out_obj->buffer.pointer,
+ context->ret.length, GFP_KERNEL);
if (!context->ret.pointer) {
status = AE_NO_MEMORY;
goto out_kfree;
}
- memcpy(context->ret.pointer, out_obj->buffer.pointer,
- context->ret.length);
status = AE_OK;
out_kfree:
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5d57cd513f4f..d2e617b5b3f6 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
+#include <acpi/button.h>
#define PREFIX "ACPI: "
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 5523ba7d764d..e23151667655 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -1,12 +1,12 @@
/*
- * acpi_container.c - ACPI Generic Container Driver
- * ($Revision: )
+ * container.c - ACPI Generic Container Driver
*
* Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
* Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
* Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
- * Copyright (C) 2004 Intel Corp.
* Copyright (C) 2004 FUJITSU LIMITED
+ * Copyright (C) 2004, 2013 Intel Corp.
+ * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -26,14 +26,11 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
+#include "internal.h"
+
+#include "internal.h"
#define PREFIX "ACPI: "
@@ -50,141 +47,20 @@ static const struct acpi_device_id container_device_ids[] = {
static int container_device_attach(struct acpi_device *device,
const struct acpi_device_id *not_used)
{
- /*
- * FIXME: This is necessary, so that acpi_eject_store() doesn't return
- * -ENODEV for containers.
- */
+ /* This is necessary for container hotplug to work. */
return 1;
}
-static struct acpi_scan_handler container_device_handler = {
+static struct acpi_scan_handler container_handler = {
.ids = container_device_ids,
.attach = container_device_attach,
+ .hotplug = {
+ .enabled = true,
+ .mode = AHM_CONTAINER,
+ },
};
-static int is_device_present(acpi_handle handle)
-{
- acpi_handle temp;
- acpi_status status;
- unsigned long long sta;
-
-
- status = acpi_get_handle(handle, "_STA", &temp);
- if (ACPI_FAILURE(status))
- return 1; /* _STA not found, assume device present */
-
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status))
- return 0; /* Firmware error */
-
- return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
-}
-
-static void container_notify_cb(acpi_handle handle, u32 type, void *context)
-{
- struct acpi_device *device = NULL;
- int result;
- int present;
- acpi_status status;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
- acpi_scan_lock_acquire();
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- /* Fall through */
- case ACPI_NOTIFY_DEVICE_CHECK:
- pr_debug("Container driver received %s event\n",
- (type == ACPI_NOTIFY_BUS_CHECK) ?
- "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
-
- present = is_device_present(handle);
- status = acpi_bus_get_device(handle, &device);
- if (!present) {
- if (ACPI_SUCCESS(status)) {
- /* device exist and this is a remove request */
- device->flags.eject_pending = 1;
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- goto out;
- }
- break;
- }
-
- if (!ACPI_FAILURE(status) || device)
- break;
-
- result = acpi_bus_scan(handle);
- if (result) {
- acpi_handle_warn(handle, "Failed to add container\n");
- break;
- }
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- acpi_handle_warn(handle, "Missing device object\n");
- break;
- }
-
- kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
- ost_code = ACPI_OST_SC_SUCCESS;
- break;
-
- case ACPI_NOTIFY_EJECT_REQUEST:
- if (!acpi_bus_get_device(handle, &device) && device) {
- device->flags.eject_pending = 1;
- kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- goto out;
- }
- break;
-
- default:
- /* non-hotplug event; possibly handled by other handler */
- goto out;
- }
-
- /* Inform firmware that the hotplug operation has completed */
- (void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
-
- out:
- acpi_scan_lock_release();
-}
-
-static bool is_container(acpi_handle handle)
-{
- struct acpi_device_info *info;
- bool ret = false;
-
- if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
- return false;
-
- if (info->valid & ACPI_VALID_HID) {
- const struct acpi_device_id *id;
-
- for (id = container_device_ids; id->id[0]; id++) {
- ret = !strcmp((char *)id->id, info->hardware_id.string);
- if (ret)
- break;
- }
- }
- kfree(info);
- return ret;
-}
-
-static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
- u32 lvl, void *ctxt,
- void **retv)
-{
- if (is_container(handle))
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- container_notify_cb, NULL);
-
- return AE_OK;
-}
-
void __init acpi_container_init(void)
{
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
- acpi_container_register_notify_handler, NULL,
- NULL, NULL);
-
- acpi_scan_add_handler(&container_device_handler);
+ acpi_scan_add_handler_with_hotplug(&container_handler, "container");
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index dd314ef9bff1..96de787e6104 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -145,27 +145,36 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
}
/*
- * Get the device's power state either directly (via _PSC) or
- * indirectly (via power resources).
+ * Get the device's power state from power resources settings and _PSC,
+ * if available.
*/
+ if (device->power.flags.power_resources) {
+ int error = acpi_power_get_inferred_state(device, &result);
+ if (error)
+ return error;
+ }
if (device->power.flags.explicit_get) {
+ acpi_handle handle = device->handle;
unsigned long long psc;
- acpi_status status = acpi_evaluate_integer(device->handle,
- "_PSC", NULL, &psc);
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc);
if (ACPI_FAILURE(status))
return -ENODEV;
- result = psc;
- }
- /* The test below covers ACPI_STATE_UNKNOWN too. */
- if (result <= ACPI_STATE_D2) {
- ; /* Do nothing. */
- } else if (device->power.flags.power_resources) {
- int error = acpi_power_get_inferred_state(device, &result);
- if (error)
- return error;
- } else if (result == ACPI_STATE_D3_HOT) {
- result = ACPI_STATE_D3;
+ /*
+ * The power resources settings may indicate a power state
+ * shallower than the actual power state of the device.
+ *
+ * Moreover, on systems predating ACPI 4.0, if the device
+ * doesn't depend on any power resources and _PSC returns 3,
+ * that means "power off". We need to maintain compatibility
+ * with those systems.
+ */
+ if (psc > result && psc < ACPI_STATE_D3_COLD)
+ result = psc;
+ else if (result == ACPI_STATE_UNKNOWN)
+ result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
}
/*
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index f815da82c765..8d1c0105e113 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -174,9 +174,13 @@ static int acpi_fan_add(struct acpi_device *device)
static int acpi_fan_remove(struct acpi_device *device)
{
- struct thermal_cooling_device *cdev = acpi_driver_data(device);
+ struct thermal_cooling_device *cdev;
+
+ if (!device)
+ return -EINVAL;
- if (!device || !cdev)
+ cdev = acpi_driver_data(device);
+ if (!cdev)
return -EINVAL;
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3c94a732b4b3..6f1afd9118c8 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -41,6 +41,17 @@ void acpi_container_init(void);
#else
static inline void acpi_container_init(void) {}
#endif
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+void acpi_memory_hotplug_init(void);
+#else
+static inline void acpi_memory_hotplug_init(void) {}
+#endif
+
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+ const char *name);
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+ const char *hotplug_profile_name);
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val);
#ifdef CONFIG_DEBUG_FS
extern struct dentry *acpi_debugfs_dir;
@@ -48,6 +59,11 @@ int acpi_debugfs_init(void);
#else
static inline void acpi_debugfs_init(void) { return; }
#endif
+#ifdef CONFIG_X86_INTEL_LPSS
+void acpi_lpss_init(void);
+#else
+static inline void acpi_lpss_init(void) {}
+#endif
/* --------------------------------------------------------------------------
Device Node Initialization / Removal
@@ -60,7 +76,7 @@ int acpi_device_add(struct acpi_device *device,
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta);
void acpi_device_add_finalize(struct acpi_device *device);
-void acpi_free_ids(struct acpi_device *device);
+void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
/* --------------------------------------------------------------------------
Power Resource
@@ -131,4 +147,7 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;
+int acpi_create_platform_device(struct acpi_device *adev,
+ const struct acpi_device_id *id);
+
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 586e7e993d3d..e72186340fec 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -641,7 +641,7 @@ void __init acpi_initrd_override(void *data, size_t size)
* Both memblock_reserve and e820_add_region (via arch_reserve_mem_area)
* works fine.
*/
- memblock_reserve(acpi_tables_addr, acpi_tables_addr + all_tables_size);
+ memblock_reserve(acpi_tables_addr, all_tables_size);
arch_reserve_mem_area(acpi_tables_addr, all_tables_size);
p = early_ioremap(acpi_tables_addr, all_tables_size);
@@ -1555,7 +1555,7 @@ int acpi_check_resource_conflict(const struct resource *res)
else
space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
- length = res->end - res->start + 1;
+ length = resource_size(res);
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO)
warn = 1;
clash = acpi_check_address_range(space_id, res->start, length, warn);
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index ab764ed34a50..2652a614deeb 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -354,6 +354,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
}
resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+ resource->end.length = sizeof(struct acpi_resource);
/* Attempt to set the resource */
status = acpi_set_current_resources(link->device->handle, &buffer);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 0ac546d5e53f..1dd6f6c85874 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -65,44 +65,12 @@ static struct acpi_scan_handler pci_root_handler = {
.detach = acpi_pci_root_remove,
};
-/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
+/* Lock to protect both acpi_pci_roots lists */
static DEFINE_MUTEX(acpi_pci_root_lock);
static LIST_HEAD(acpi_pci_roots);
-static LIST_HEAD(acpi_pci_drivers);
static DEFINE_MUTEX(osc_lock);
-int acpi_pci_register_driver(struct acpi_pci_driver *driver)
-{
- int n = 0;
- struct acpi_pci_root *root;
-
- mutex_lock(&acpi_pci_root_lock);
- list_add_tail(&driver->node, &acpi_pci_drivers);
- if (driver->add)
- list_for_each_entry(root, &acpi_pci_roots, node) {
- driver->add(root);
- n++;
- }
- mutex_unlock(&acpi_pci_root_lock);
-
- return n;
-}
-EXPORT_SYMBOL(acpi_pci_register_driver);
-
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
-{
- struct acpi_pci_root *root;
-
- mutex_lock(&acpi_pci_root_lock);
- list_del(&driver->node);
- if (driver->remove)
- list_for_each_entry(root, &acpi_pci_roots, node)
- driver->remove(root);
- mutex_unlock(&acpi_pci_root_lock);
-}
-EXPORT_SYMBOL(acpi_pci_unregister_driver);
-
/**
* acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
* @handle - the ACPI CA node in question.
@@ -201,8 +169,8 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
*control &= OSC_PCI_CONTROL_MASKS;
capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
} else {
- /* Run _OSC query for all possible controls. */
- capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
+ /* Run _OSC query only with existing controls. */
+ capbuf[OSC_CONTROL_TYPE] = root->osc_control_set;
}
status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
@@ -413,9 +381,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
acpi_status status;
int result;
struct acpi_pci_root *root;
- struct acpi_pci_driver *driver;
u32 flags, base_flags;
- bool is_osc_granted = false;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
@@ -476,6 +442,30 @@ static int acpi_pci_root_add(struct acpi_device *device,
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
acpi_pci_osc_support(root, flags);
+ /*
+ * TBD: Need PCI interface for enumeration/configuration of roots.
+ */
+
+ mutex_lock(&acpi_pci_root_lock);
+ list_add_tail(&root->node, &acpi_pci_roots);
+ mutex_unlock(&acpi_pci_root_lock);
+
+ /*
+ * Scan the Root Bridge
+ * --------------------
+ * Must do this prior to any attempt to bind the root device, as the
+ * PCI namespace does not get created until this call is made (and
+ * thus the root bridge's pci_dev does not exist).
+ */
+ root->bus = pci_acpi_scan_root(root);
+ if (!root->bus) {
+ printk(KERN_ERR PREFIX
+ "Bus %04x:%02x not present in PCI namespace\n",
+ root->segment, (unsigned int)root->secondary.start);
+ result = -ENODEV;
+ goto out_del_root;
+ }
+
/* Indicate support for various _OSC capabilities. */
if (pci_ext_cfg_avail())
flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
@@ -494,6 +484,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
flags = base_flags;
}
}
+
if (!pcie_ports_disabled
&& (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
@@ -514,54 +505,28 @@ static int acpi_pci_root_add(struct acpi_device *device,
status = acpi_pci_osc_control_set(device->handle, &flags,
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
if (ACPI_SUCCESS(status)) {
- is_osc_granted = true;
dev_info(&device->dev,
"ACPI _OSC control (0x%02x) granted\n", flags);
+ if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
+ /*
+ * We have ASPM control, but the FADT indicates
+ * that it's unsupported. Clear it.
+ */
+ pcie_clear_aspm(root->bus);
+ }
} else {
- is_osc_granted = false;
dev_info(&device->dev,
"ACPI _OSC request failed (%s), "
"returned control mask: 0x%02x\n",
acpi_format_exception(status), flags);
+ pr_info("ACPI _OSC control for PCIe not granted, "
+ "disabling ASPM\n");
+ pcie_no_aspm();
}
} else {
dev_info(&device->dev,
- "Unable to request _OSC control "
- "(_OSC support mask: 0x%02x)\n", flags);
- }
-
- /*
- * TBD: Need PCI interface for enumeration/configuration of roots.
- */
-
- mutex_lock(&acpi_pci_root_lock);
- list_add_tail(&root->node, &acpi_pci_roots);
- mutex_unlock(&acpi_pci_root_lock);
-
- /*
- * Scan the Root Bridge
- * --------------------
- * Must do this prior to any attempt to bind the root device, as the
- * PCI namespace does not get created until this call is made (and
- * thus the root bridge's pci_dev does not exist).
- */
- root->bus = pci_acpi_scan_root(root);
- if (!root->bus) {
- printk(KERN_ERR PREFIX
- "Bus %04x:%02x not present in PCI namespace\n",
- root->segment, (unsigned int)root->secondary.start);
- result = -ENODEV;
- goto out_del_root;
- }
-
- /* ASPM setting */
- if (is_osc_granted) {
- if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM)
- pcie_clear_aspm(root->bus);
- } else {
- pr_info("ACPI _OSC control for PCIe not granted, "
- "disabling ASPM\n");
- pcie_no_aspm();
+ "Unable to request _OSC control "
+ "(_OSC support mask: 0x%02x)\n", flags);
}
pci_acpi_add_bus_pm_notifier(device, root->bus);
@@ -573,12 +538,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
pci_assign_unassigned_bus_resources(root->bus);
}
- mutex_lock(&acpi_pci_root_lock);
- list_for_each_entry(driver, &acpi_pci_drivers, node)
- if (driver->add)
- driver->add(root);
- mutex_unlock(&acpi_pci_root_lock);
-
/* need to after hot-added ioapic is registered */
if (system_state != SYSTEM_BOOTING)
pci_enable_bridges(root->bus);
@@ -599,16 +558,9 @@ end:
static void acpi_pci_root_remove(struct acpi_device *device)
{
struct acpi_pci_root *root = acpi_driver_data(device);
- struct acpi_pci_driver *driver;
pci_stop_root_bus(root->bus);
- mutex_lock(&acpi_pci_root_lock);
- list_for_each_entry_reverse(driver, &acpi_pci_drivers, node)
- if (driver->remove)
- driver->remove(root);
- mutex_unlock(&acpi_pci_root_lock);
-
device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device);
@@ -646,6 +598,7 @@ static void handle_root_bridge_insertion(acpi_handle handle)
static void handle_root_bridge_removal(struct acpi_device *device)
{
+ acpi_status status;
struct acpi_eject_event *ej_event;
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
@@ -661,7 +614,9 @@ static void handle_root_bridge_removal(struct acpi_device *device)
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_bus_hot_remove_device(ej_event);
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+ if (ACPI_FAILURE(status))
+ kfree(ej_event);
}
static void _handle_hotplug_event_root(struct work_struct *work)
@@ -676,8 +631,9 @@ static void _handle_hotplug_event_root(struct work_struct *work)
handle = hp_work->handle;
type = hp_work->type;
- root = acpi_pci_find_root(handle);
+ acpi_scan_lock_acquire();
+ root = acpi_pci_find_root(handle);
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) {
@@ -711,6 +667,7 @@ static void _handle_hotplug_event_root(struct work_struct *work)
break;
}
+ acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
kfree(buffer.pointer);
}
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index cd1434eb1de8..033d1179bdb5 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -9,6 +9,9 @@
* Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P.
* Alex Chiang <achiang@hp.com>
*
+ * Copyright (C) 2013 Huawei Tech. Co., Ltd.
+ * Jiang Liu <jiang.liu@huawei.com>
+ *
* 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.
@@ -28,10 +31,9 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/list.h>
#include <linux/pci.h>
#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
#include <linux/dmi.h>
static bool debug;
@@ -61,20 +63,12 @@ ACPI_MODULE_NAME("pci_slot");
#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
struct acpi_pci_slot {
- acpi_handle root_handle; /* handle of the root bridge */
struct pci_slot *pci_slot; /* corresponding pci_slot */
struct list_head list; /* node in the list of slots */
};
-static int acpi_pci_slot_add(struct acpi_pci_root *root);
-static void acpi_pci_slot_remove(struct acpi_pci_root *root);
-
static LIST_HEAD(slot_list);
static DEFINE_MUTEX(slot_list_lock);
-static struct acpi_pci_driver acpi_pci_slot_driver = {
- .add = acpi_pci_slot_add,
- .remove = acpi_pci_slot_remove,
-};
static int
check_slot(acpi_handle handle, unsigned long long *sun)
@@ -113,21 +107,8 @@ out:
return device;
}
-struct callback_args {
- acpi_walk_callback user_function; /* only for walk_p2p_bridge */
- struct pci_bus *pci_bus;
- acpi_handle root_handle;
-};
-
/*
- * register_slot
- *
- * Called once for each SxFy object in the namespace. Don't worry about
- * calling pci_create_slot multiple times for the same pci_bus:device,
- * since each subsequent call simply bumps the refcount on the pci_slot.
- *
- * The number of calls to pci_destroy_slot from unregister_slot is
- * symmetrical.
+ * Check whether handle has an associated slot and create PCI slot if it has.
*/
static acpi_status
register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -137,13 +118,22 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
char name[SLOT_NAME_SIZE];
struct acpi_pci_slot *slot;
struct pci_slot *pci_slot;
- struct callback_args *parent_context = context;
- struct pci_bus *pci_bus = parent_context->pci_bus;
+ struct pci_bus *pci_bus = context;
device = check_slot(handle, &sun);
if (device < 0)
return AE_OK;
+ /*
+ * There may be multiple PCI functions associated with the same slot.
+ * Check whether PCI slot has already been created for this PCI device.
+ */
+ list_for_each_entry(slot, &slot_list, list) {
+ pci_slot = slot->pci_slot;
+ if (pci_slot->bus == pci_bus && pci_slot->number == device)
+ return AE_OK;
+ }
+
slot = kmalloc(sizeof(*slot), GFP_KERNEL);
if (!slot) {
err("%s: cannot allocate memory\n", __func__);
@@ -158,12 +148,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
- slot->root_handle = parent_context->root_handle;
slot->pci_slot = pci_slot;
- INIT_LIST_HEAD(&slot->list);
- mutex_lock(&slot_list_lock);
list_add(&slot->list, &slot_list);
- mutex_unlock(&slot_list_lock);
get_device(&pci_bus->dev);
@@ -173,131 +159,24 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-/*
- * walk_p2p_bridge - discover and walk p2p bridges
- * @handle: points to an acpi_pci_root
- * @context: p2p_bridge_context pointer
- *
- * Note that when we call ourselves recursively, we pass a different
- * value of pci_bus in the child_context.
- */
-static acpi_status
-walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- int device, function;
- unsigned long long adr;
- acpi_status status;
- acpi_handle dummy_handle;
- acpi_walk_callback user_function;
-
- struct pci_dev *dev;
- struct pci_bus *pci_bus;
- struct callback_args child_context;
- struct callback_args *parent_context = context;
-
- pci_bus = parent_context->pci_bus;
- user_function = parent_context->user_function;
-
- status = acpi_get_handle(handle, "_ADR", &dummy_handle);
- if (ACPI_FAILURE(status))
- return AE_OK;
-
- status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
- if (ACPI_FAILURE(status))
- return AE_OK;
-
- device = (adr >> 16) & 0xffff;
- function = adr & 0xffff;
-
- dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
- if (!dev || !dev->subordinate)
- goto out;
-
- child_context.pci_bus = dev->subordinate;
- child_context.user_function = user_function;
- child_context.root_handle = parent_context->root_handle;
-
- dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- user_function, NULL, &child_context, NULL);
- if (ACPI_FAILURE(status))
- goto out;
-
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- walk_p2p_bridge, NULL, &child_context, NULL);
-out:
- pci_dev_put(dev);
- return AE_OK;
-}
-
-/*
- * walk_root_bridge - generic root bridge walker
- * @root: poiner of an acpi_pci_root
- * @user_function: user callback for slot objects
- *
- * Call user_function for all objects underneath this root bridge.
- * Walk p2p bridges underneath us and call user_function on those too.
- */
-static int
-walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
-{
- acpi_status status;
- acpi_handle handle = root->device->handle;
- struct pci_bus *pci_bus = root->bus;
- struct callback_args context;
-
- context.pci_bus = pci_bus;
- context.user_function = user_function;
- context.root_handle = handle;
-
- dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- user_function, NULL, &context, NULL);
- if (ACPI_FAILURE(status))
- return status;
-
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- walk_p2p_bridge, NULL, &context, NULL);
- if (ACPI_FAILURE(status))
- err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
-
- return status;
-}
-
-/*
- * acpi_pci_slot_add
- * @handle: points to an acpi_pci_root
- */
-static int
-acpi_pci_slot_add(struct acpi_pci_root *root)
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
{
- acpi_status status;
-
- status = walk_root_bridge(root, register_slot);
- if (ACPI_FAILURE(status))
- err("%s: register_slot failure - %d\n", __func__, status);
-
- return status;
+ mutex_lock(&slot_list_lock);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ register_slot, NULL, bus, NULL);
+ mutex_unlock(&slot_list_lock);
}
-/*
- * acpi_pci_slot_remove
- * @handle: points to an acpi_pci_root
- */
-static void
-acpi_pci_slot_remove(struct acpi_pci_root *root)
+void acpi_pci_slot_remove(struct pci_bus *bus)
{
struct acpi_pci_slot *slot, *tmp;
- struct pci_bus *pbus;
- acpi_handle handle = root->device->handle;
mutex_lock(&slot_list_lock);
list_for_each_entry_safe(slot, tmp, &slot_list, list) {
- if (slot->root_handle == handle) {
+ if (slot->pci_slot->bus == bus) {
list_del(&slot->list);
- pbus = slot->pci_slot->bus;
pci_destroy_slot(slot->pci_slot);
- put_device(&pbus->dev);
+ put_device(&bus->dev);
kfree(slot);
}
}
@@ -332,5 +211,4 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
void __init acpi_pci_slot_init(void)
{
dmi_check_system(acpi_pci_slot_dmi_table);
- acpi_pci_register_driver(&acpi_pci_slot_driver);
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 34f5ef11d427..f962047c6c85 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -459,57 +459,79 @@ static struct attribute_group attr_groups[] = {
},
};
-static void acpi_power_hide_list(struct acpi_device *adev, int state)
+static struct attribute_group wakeup_attr_group = {
+ .name = "power_resources_wakeup",
+ .attrs = attrs,
+};
+
+static void acpi_power_hide_list(struct acpi_device *adev,
+ struct list_head *resources,
+ struct attribute_group *attr_group)
{
- struct acpi_device_power_state *ps = &adev->power.states[state];
struct acpi_power_resource_entry *entry;
- if (list_empty(&ps->resources))
+ if (list_empty(resources))
return;
- list_for_each_entry_reverse(entry, &ps->resources, node) {
+ list_for_each_entry_reverse(entry, resources, node) {
struct acpi_device *res_dev = &entry->resource->device;
sysfs_remove_link_from_group(&adev->dev.kobj,
- attr_groups[state].name,
+ attr_group->name,
dev_name(&res_dev->dev));
}
- sysfs_remove_group(&adev->dev.kobj, &attr_groups[state]);
+ sysfs_remove_group(&adev->dev.kobj, attr_group);
}
-static void acpi_power_expose_list(struct acpi_device *adev, int state)
+static void acpi_power_expose_list(struct acpi_device *adev,
+ struct list_head *resources,
+ struct attribute_group *attr_group)
{
- struct acpi_device_power_state *ps = &adev->power.states[state];
struct acpi_power_resource_entry *entry;
int ret;
- if (list_empty(&ps->resources))
+ if (list_empty(resources))
return;
- ret = sysfs_create_group(&adev->dev.kobj, &attr_groups[state]);
+ ret = sysfs_create_group(&adev->dev.kobj, attr_group);
if (ret)
return;
- list_for_each_entry(entry, &ps->resources, node) {
+ list_for_each_entry(entry, resources, node) {
struct acpi_device *res_dev = &entry->resource->device;
ret = sysfs_add_link_to_group(&adev->dev.kobj,
- attr_groups[state].name,
+ attr_group->name,
&res_dev->dev.kobj,
dev_name(&res_dev->dev));
if (ret) {
- acpi_power_hide_list(adev, state);
+ acpi_power_hide_list(adev, resources, attr_group);
break;
}
}
}
+static void acpi_power_expose_hide(struct acpi_device *adev,
+ struct list_head *resources,
+ struct attribute_group *attr_group,
+ bool expose)
+{
+ if (expose)
+ acpi_power_expose_list(adev, resources, attr_group);
+ else
+ acpi_power_hide_list(adev, resources, attr_group);
+}
+
void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
{
struct acpi_device_power_state *ps;
struct acpi_power_resource_entry *entry;
int state;
+ if (adev->wakeup.flags.valid)
+ acpi_power_expose_hide(adev, &adev->wakeup.resources,
+ &wakeup_attr_group, add);
+
if (!adev->power.flags.power_resources)
return;
@@ -523,12 +545,10 @@ void acpi_power_add_remove_device(struct acpi_device *adev, bool add)
acpi_power_remove_dependent(resource, adev);
}
- for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
- if (add)
- acpi_power_expose_list(adev, state);
- else
- acpi_power_hide_list(adev, state);
- }
+ for (state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++)
+ acpi_power_expose_hide(adev,
+ &adev->power.states[state].resources,
+ &attr_groups[state], add);
}
int acpi_power_wakeup_list_init(struct list_head *list, int *system_level_p)
@@ -824,7 +844,7 @@ static void acpi_release_power_resource(struct device *dev)
list_del(&resource->list_node);
mutex_unlock(&power_resource_list_lock);
- acpi_free_ids(device);
+ acpi_free_pnp_ids(&device->pnp);
kfree(resource);
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index fc95308e9a11..f0df2c9434d2 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -66,7 +66,8 @@ module_param(latency_factor, uint, 0644);
static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
-static struct acpi_processor_cx *acpi_cstate[CPUIDLE_STATE_MAX];
+static DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX],
+ acpi_cstate);
static int disabled_by_idle_boot_param(void)
{
@@ -722,7 +723,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct acpi_processor_cx *cx = acpi_cstate[index];
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
pr = __this_cpu_read(processors);
@@ -745,7 +746,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
*/
static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
{
- struct acpi_processor_cx *cx = acpi_cstate[index];
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
ACPI_FLUSH_CPU_CACHE();
@@ -775,7 +776,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct acpi_processor_cx *cx = acpi_cstate[index];
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
pr = __this_cpu_read(processors);
@@ -833,7 +834,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
- struct acpi_processor_cx *cx = acpi_cstate[index];
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
pr = __this_cpu_read(processors);
@@ -917,7 +918,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
struct cpuidle_driver acpi_idle_driver = {
.name = "acpi_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
};
/**
@@ -960,7 +960,7 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
!(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
continue;
#endif
- acpi_cstate[count] = cx;
+ per_cpu(acpi_cstate[count], dev->cpu) = cx;
count++;
if (count == CPUIDLE_STATE_MAX)
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 641b5450a0db..e8e652710e65 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -218,9 +218,13 @@ processor_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct acpi_device *device = cdev->devdata;
- struct acpi_processor *pr = acpi_driver_data(device);
+ struct acpi_processor *pr;
- if (!device || !pr)
+ if (!device)
+ return -EINVAL;
+
+ pr = acpi_driver_data(device);
+ if (!pr)
return -EINVAL;
*state = acpi_processor_max_state(pr);
@@ -232,9 +236,13 @@ processor_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *cur_state)
{
struct acpi_device *device = cdev->devdata;
- struct acpi_processor *pr = acpi_driver_data(device);
+ struct acpi_processor *pr;
- if (!device || !pr)
+ if (!device)
+ return -EINVAL;
+
+ pr = acpi_driver_data(device);
+ if (!pr)
return -EINVAL;
*cur_state = cpufreq_get_cur_state(pr->id);
@@ -248,11 +256,15 @@ processor_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct acpi_device *device = cdev->devdata;
- struct acpi_processor *pr = acpi_driver_data(device);
+ struct acpi_processor *pr;
int result = 0;
int max_pstate;
- if (!device || !pr)
+ if (!device)
+ return -EINVAL;
+
+ pr = acpi_driver_data(device);
+ if (!pr)
return -EINVAL;
max_pstate = cpufreq_get_max_state(pr->id);
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 1d02b7b5ade0..e7dd2c1fee79 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -211,9 +211,10 @@ err_ret:
*/
void acpi_processor_throttling_init(void)
{
- if (acpi_processor_update_tsd_coord())
+ if (acpi_processor_update_tsd_coord()) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Assume no T-state coordination\n"));
+ }
return;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 5e7e991717d7..fe158fd4f1df 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -63,6 +63,19 @@ int acpi_scan_add_handler(struct acpi_scan_handler *handler)
return 0;
}
+int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
+ const char *hotplug_profile_name)
+{
+ int error;
+
+ error = acpi_scan_add_handler(handler);
+ if (error)
+ return error;
+
+ acpi_sysfs_add_hotplug_profile(&handler->hotplug, hotplug_profile_name);
+ return 0;
+}
+
/*
* Creates hid/cid(s) string needed for modalias and uevent
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -107,32 +120,20 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
+static int acpi_scan_hot_remove(struct acpi_device *device)
{
- struct acpi_eject_event *ej_event = context;
- struct acpi_device *device = ej_event->device;
acpi_handle handle = device->handle;
- acpi_handle temp;
+ acpi_handle not_used;
struct acpi_object_list arg_list;
union acpi_object arg;
- acpi_status status = AE_OK;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
- mutex_lock(&acpi_scan_lock);
+ acpi_status status;
+ unsigned long long sta;
/* If there is no handle, the device node has been unregistered. */
- if (!device->handle) {
+ if (!handle) {
dev_dbg(&device->dev, "ACPI handle missing\n");
put_device(&device->dev);
- goto out;
+ return -EINVAL;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -143,7 +144,7 @@ void acpi_bus_hot_remove_device(void *context)
put_device(&device->dev);
device = NULL;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &not_used))) {
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
@@ -161,18 +162,205 @@ void acpi_bus_hot_remove_device(void *context)
*/
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
- if (status != AE_NOT_FOUND)
- acpi_handle_warn(handle, "Eject failed\n");
+ if (status == AE_NOT_FOUND) {
+ return -ENODEV;
+ } else {
+ acpi_handle_warn(handle, "Eject failed (0x%x)\n",
+ status);
+ return -EIO;
+ }
+ }
- /* Tell the firmware the hot-remove operation has failed. */
- acpi_evaluate_hotplug_ost(handle, ej_event->event,
- ost_code, NULL);
+ /*
+ * Verify if eject was indeed successful. If not, log an error
+ * message. No need to call _OST since _EJ0 call was made OK.
+ */
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_warn(handle,
+ "Status check after eject failed (0x%x)\n", status);
+ } else if (sta & ACPI_STA_DEVICE_ENABLED) {
+ acpi_handle_warn(handle,
+ "Eject incomplete - status 0x%llx\n", sta);
+ }
+
+ return 0;
+}
+
+static void acpi_bus_device_eject(void *context)
+{
+ acpi_handle handle = context;
+ struct acpi_device *device = NULL;
+ struct acpi_scan_handler *handler;
+ u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+ mutex_lock(&acpi_scan_lock);
+
+ acpi_bus_get_device(handle, &device);
+ if (!device)
+ goto err_out;
+
+ handler = device->handler;
+ if (!handler || !handler->hotplug.enabled) {
+ ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+ goto err_out;
+ }
+ acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
+ ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+ if (handler->hotplug.mode == AHM_CONTAINER) {
+ device->flags.eject_pending = true;
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
+ } else {
+ int error;
+
+ get_device(&device->dev);
+ error = acpi_scan_hot_remove(device);
+ if (error)
+ goto err_out;
}
out:
mutex_unlock(&acpi_scan_lock);
- kfree(context);
return;
+
+ err_out:
+ acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, ost_code,
+ NULL);
+ goto out;
+}
+
+static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
+{
+ struct acpi_device *device = NULL;
+ u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+ int error;
+
+ mutex_lock(&acpi_scan_lock);
+
+ acpi_bus_get_device(handle, &device);
+ if (device) {
+ dev_warn(&device->dev, "Attempt to re-insert\n");
+ goto out;
+ }
+ acpi_evaluate_hotplug_ost(handle, ost_source,
+ ACPI_OST_SC_INSERT_IN_PROGRESS, NULL);
+ error = acpi_bus_scan(handle);
+ if (error) {
+ acpi_handle_warn(handle, "Namespace scan failure\n");
+ goto out;
+ }
+ error = acpi_bus_get_device(handle, &device);
+ if (error) {
+ acpi_handle_warn(handle, "Missing device node object\n");
+ goto out;
+ }
+ ost_code = ACPI_OST_SC_SUCCESS;
+ if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER)
+ kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
+
+ out:
+ acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
+ mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_bus_check(void *context)
+{
+ acpi_scan_bus_device_check((acpi_handle)context,
+ ACPI_NOTIFY_BUS_CHECK);
+}
+
+static void acpi_scan_device_check(void *context)
+{
+ acpi_scan_bus_device_check((acpi_handle)context,
+ ACPI_NOTIFY_DEVICE_CHECK);
+}
+
+static void acpi_hotplug_unsupported(acpi_handle handle, u32 type)
+{
+ u32 ost_status;
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ acpi_handle_debug(handle,
+ "ACPI_NOTIFY_BUS_CHECK event: unsupported\n");
+ ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
+ break;
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ acpi_handle_debug(handle,
+ "ACPI_NOTIFY_DEVICE_CHECK event: unsupported\n");
+ ost_status = ACPI_OST_SC_INSERT_NOT_SUPPORTED;
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ acpi_handle_debug(handle,
+ "ACPI_NOTIFY_EJECT_REQUEST event: unsupported\n");
+ ost_status = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
+ break;
+ default:
+ /* non-hotplug event; possibly handled by other handler */
+ return;
+ }
+
+ acpi_evaluate_hotplug_ost(handle, type, ost_status, NULL);
+}
+
+static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
+{
+ acpi_osd_exec_callback callback;
+ struct acpi_scan_handler *handler = data;
+ acpi_status status;
+
+ if (!handler->hotplug.enabled)
+ return acpi_hotplug_unsupported(handle, type);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+ callback = acpi_scan_bus_check;
+ break;
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+ callback = acpi_scan_device_check;
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+ callback = acpi_bus_device_eject;
+ break;
+ default:
+ /* non-hotplug event; possibly handled by other handler */
+ return;
+ }
+ status = acpi_os_hotplug_execute(callback, handle);
+ if (ACPI_FAILURE(status))
+ acpi_evaluate_hotplug_ost(handle, type,
+ ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+ NULL);
+}
+
+/**
+ * acpi_bus_hot_remove_device: hot-remove a device and its children
+ * @context: struct acpi_eject_event pointer (freed in this func)
+ *
+ * Hot-remove a device and its children. This function frees up the
+ * memory space passed by arg context, so that the caller may call
+ * this function asynchronously through acpi_os_hotplug_execute().
+ */
+void acpi_bus_hot_remove_device(void *context)
+{
+ struct acpi_eject_event *ej_event = context;
+ struct acpi_device *device = ej_event->device;
+ acpi_handle handle = device->handle;
+ int error;
+
+ mutex_lock(&acpi_scan_lock);
+
+ error = acpi_scan_hot_remove(device);
+ if (error && handle)
+ acpi_evaluate_hotplug_ost(handle, ej_event->event,
+ ACPI_OST_SC_NON_SPECIFIC_FAILURE,
+ NULL);
+
+ mutex_unlock(&acpi_scan_lock);
+ kfree(context);
}
EXPORT_SYMBOL(acpi_bus_hot_remove_device);
@@ -206,51 +394,61 @@ static ssize_t
acpi_eject_store(struct device *d, struct device_attribute *attr,
const char *buf, size_t count)
{
- int ret = count;
- acpi_status status;
- acpi_object_type type = 0;
struct acpi_device *acpi_device = to_acpi_device(d);
struct acpi_eject_event *ej_event;
+ acpi_object_type not_used;
+ acpi_status status;
+ u32 ost_source;
+ int ret;
- if ((!count) || (buf[0] != '1')) {
+ if (!count || buf[0] != '1')
return -EINVAL;
- }
- if (!acpi_device->driver && !acpi_device->handler) {
- ret = -ENODEV;
- goto err;
- }
- status = acpi_get_type(acpi_device->handle, &type);
- if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
- ret = -ENODEV;
- goto err;
- }
- ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
- if (!ej_event) {
- ret = -ENOMEM;
- goto err;
- }
+ if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled)
+ && !acpi_device->driver)
+ return -ENODEV;
+
+ status = acpi_get_type(acpi_device->handle, &not_used);
+ if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
+ return -ENODEV;
+
+ mutex_lock(&acpi_scan_lock);
- get_device(&acpi_device->dev);
- ej_event->device = acpi_device;
if (acpi_device->flags.eject_pending) {
- /* event originated from ACPI eject notification */
- ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
+ /* ACPI eject notification event. */
+ ost_source = ACPI_NOTIFY_EJECT_REQUEST;
acpi_device->flags.eject_pending = 0;
} else {
- /* event originated from user */
- ej_event->event = ACPI_OST_EC_OSPM_EJECT;
- (void) acpi_evaluate_hotplug_ost(acpi_device->handle,
- ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+ /* Eject initiated by user space. */
+ ost_source = ACPI_OST_EC_OSPM_EJECT;
}
-
+ ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
+ if (!ej_event) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+ acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+ ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+ ej_event->device = acpi_device;
+ ej_event->event = ost_source;
+ get_device(&acpi_device->dev);
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
if (ACPI_FAILURE(status)) {
put_device(&acpi_device->dev);
kfree(ej_event);
+ ret = status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN;
+ goto err_out;
}
-err:
+ ret = count;
+
+ out:
+ mutex_unlock(&acpi_scan_lock);
return ret;
+
+ err_out:
+ acpi_evaluate_hotplug_ost(acpi_device->handle, ost_source,
+ ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+ goto out;
}
static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
@@ -376,7 +574,7 @@ static int acpi_device_setup_files(struct acpi_device *dev)
goto end;
}
- if (dev->flags.bus_address)
+ if (dev->pnp.type.bus_address)
result = device_create_file(&dev->dev, &dev_attr_adr);
if (dev->pnp.unique_id)
result = device_create_file(&dev->dev, &dev_attr_uid);
@@ -449,7 +647,7 @@ static void acpi_device_remove_files(struct acpi_device *dev)
if (dev->pnp.unique_id)
device_remove_file(&dev->dev, &dev_attr_uid);
- if (dev->flags.bus_address)
+ if (dev->pnp.type.bus_address)
device_remove_file(&dev->dev, &dev_attr_adr);
device_remove_file(&dev->dev, &dev_attr_modalias);
device_remove_file(&dev->dev, &dev_attr_hid);
@@ -512,17 +710,6 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
-void acpi_free_ids(struct acpi_device *device)
-{
- struct acpi_hardware_id *id, *tmp;
-
- list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) {
- kfree(id->id);
- kfree(id);
- }
- kfree(device->pnp.unique_id);
-}
-
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
@@ -543,7 +730,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
- acpi_free_ids(acpi_dev);
+ acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
}
@@ -1256,19 +1443,17 @@ static void acpi_device_get_busid(struct acpi_device *device)
}
/*
- * acpi_bay_match - see if a device is an ejectable driver bay
+ * acpi_bay_match - see if an acpi object is an ejectable driver bay
*
* If an acpi object is ejectable and has one of the ACPI ATA methods defined,
* then we can safely call it an ejectable drive bay
*/
-static int acpi_bay_match(struct acpi_device *device){
+static int acpi_bay_match(acpi_handle handle)
+{
acpi_status status;
- acpi_handle handle;
acpi_handle tmp;
acpi_handle phandle;
- handle = device->handle;
-
status = acpi_get_handle(handle, "_EJ0", &tmp);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -1292,12 +1477,12 @@ static int acpi_bay_match(struct acpi_device *device){
}
/*
- * acpi_dock_match - see if a device has a _DCK method
+ * acpi_dock_match - see if an acpi object has a _DCK method
*/
-static int acpi_dock_match(struct acpi_device *device)
+static int acpi_dock_match(acpi_handle handle)
{
acpi_handle tmp;
- return acpi_get_handle(device->handle, "_DCK", &tmp);
+ return acpi_get_handle(handle, "_DCK", &tmp);
}
const char *acpi_device_hid(struct acpi_device *device)
@@ -1312,7 +1497,7 @@ const char *acpi_device_hid(struct acpi_device *device)
}
EXPORT_SYMBOL(acpi_device_hid);
-static void acpi_add_id(struct acpi_device *device, const char *dev_id)
+static void acpi_add_id(struct acpi_device_pnp *pnp, const char *dev_id)
{
struct acpi_hardware_id *id;
@@ -1326,7 +1511,8 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
return;
}
- list_add_tail(&id->list, &device->pnp.ids);
+ list_add_tail(&id->list, &pnp->ids);
+ pnp->type.hardware_id = 1;
}
/*
@@ -1334,7 +1520,7 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
* lacks the SMBUS01 HID and the methods do not have the necessary "_"
* prefix. Work around this.
*/
-static int acpi_ibm_smbus_match(struct acpi_device *device)
+static int acpi_ibm_smbus_match(acpi_handle handle)
{
acpi_handle h_dummy;
struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -1344,7 +1530,7 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
return -ENODEV;
/* Look for SMBS object */
- result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
+ result = acpi_get_name(handle, ACPI_SINGLE_NAME, &path);
if (result)
return result;
@@ -1355,48 +1541,50 @@ static int acpi_ibm_smbus_match(struct acpi_device *device)
/* Does it have the necessary (but misnamed) methods? */
result = -ENODEV;
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "SBI", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(handle, "SBR", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(handle, "SBW", &h_dummy)))
result = 0;
out:
kfree(path.pointer);
return result;
}
-static void acpi_device_set_id(struct acpi_device *device)
+static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
+ int device_type)
{
acpi_status status;
struct acpi_device_info *info;
struct acpi_pnp_device_id_list *cid_list;
int i;
- switch (device->device_type) {
+ switch (device_type) {
case ACPI_BUS_TYPE_DEVICE:
- if (ACPI_IS_ROOT_DEVICE(device)) {
- acpi_add_id(device, ACPI_SYSTEM_HID);
+ if (handle == ACPI_ROOT_OBJECT) {
+ acpi_add_id(pnp, ACPI_SYSTEM_HID);
break;
}
- status = acpi_get_object_info(device->handle, &info);
+ status = acpi_get_object_info(handle, &info);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__);
+ pr_err(PREFIX "%s: Error reading device info\n",
+ __func__);
return;
}
if (info->valid & ACPI_VALID_HID)
- acpi_add_id(device, info->hardware_id.string);
+ acpi_add_id(pnp, info->hardware_id.string);
if (info->valid & ACPI_VALID_CID) {
cid_list = &info->compatible_id_list;
for (i = 0; i < cid_list->count; i++)
- acpi_add_id(device, cid_list->ids[i].string);
+ acpi_add_id(pnp, cid_list->ids[i].string);
}
if (info->valid & ACPI_VALID_ADR) {
- device->pnp.bus_address = info->address;
- device->flags.bus_address = 1;
+ pnp->bus_address = info->address;
+ pnp->type.bus_address = 1;
}
if (info->valid & ACPI_VALID_UID)
- device->pnp.unique_id = kstrdup(info->unique_id.string,
+ pnp->unique_id = kstrdup(info->unique_id.string,
GFP_KERNEL);
kfree(info);
@@ -1405,40 +1593,50 @@ static void acpi_device_set_id(struct acpi_device *device)
* Some devices don't reliably have _HIDs & _CIDs, so add
* synthetic HIDs to make sure drivers can find them.
*/
- if (acpi_is_video_device(device))
- acpi_add_id(device, ACPI_VIDEO_HID);
- else if (ACPI_SUCCESS(acpi_bay_match(device)))
- acpi_add_id(device, ACPI_BAY_HID);
- else if (ACPI_SUCCESS(acpi_dock_match(device)))
- acpi_add_id(device, ACPI_DOCK_HID);
- else if (!acpi_ibm_smbus_match(device))
- acpi_add_id(device, ACPI_SMBUS_IBM_HID);
- else if (list_empty(&device->pnp.ids) &&
- ACPI_IS_ROOT_DEVICE(device->parent)) {
- acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
- strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
- strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
+ if (acpi_is_video_device(handle))
+ acpi_add_id(pnp, ACPI_VIDEO_HID);
+ else if (ACPI_SUCCESS(acpi_bay_match(handle)))
+ acpi_add_id(pnp, ACPI_BAY_HID);
+ else if (ACPI_SUCCESS(acpi_dock_match(handle)))
+ acpi_add_id(pnp, ACPI_DOCK_HID);
+ else if (!acpi_ibm_smbus_match(handle))
+ acpi_add_id(pnp, ACPI_SMBUS_IBM_HID);
+ else if (list_empty(&pnp->ids) && handle == ACPI_ROOT_OBJECT) {
+ acpi_add_id(pnp, ACPI_BUS_HID); /* \_SB, LNXSYBUS */
+ strcpy(pnp->device_name, ACPI_BUS_DEVICE_NAME);
+ strcpy(pnp->device_class, ACPI_BUS_CLASS);
}
break;
case ACPI_BUS_TYPE_POWER:
- acpi_add_id(device, ACPI_POWER_HID);
+ acpi_add_id(pnp, ACPI_POWER_HID);
break;
case ACPI_BUS_TYPE_PROCESSOR:
- acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID);
+ acpi_add_id(pnp, ACPI_PROCESSOR_OBJECT_HID);
break;
case ACPI_BUS_TYPE_THERMAL:
- acpi_add_id(device, ACPI_THERMAL_HID);
+ acpi_add_id(pnp, ACPI_THERMAL_HID);
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
- acpi_add_id(device, ACPI_BUTTON_HID_POWERF);
+ acpi_add_id(pnp, ACPI_BUTTON_HID_POWERF);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
- acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF);
+ acpi_add_id(pnp, ACPI_BUTTON_HID_SLEEPF);
break;
}
}
+void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
+{
+ struct acpi_hardware_id *id, *tmp;
+
+ list_for_each_entry_safe(id, tmp, &pnp->ids, list) {
+ kfree(id->id);
+ kfree(id);
+ }
+ kfree(pnp->unique_id);
+}
+
void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta)
{
@@ -1448,7 +1646,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->parent = acpi_bus_get_parent(handle);
STRUCT_TO_INT(device->status) = sta;
acpi_device_get_busid(device);
- acpi_device_set_id(device);
+ acpi_set_pnp_ids(handle, &device->pnp, type);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device_initialize(&device->dev);
@@ -1536,6 +1734,75 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type,
return 0;
}
+static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
+ char *idstr,
+ const struct acpi_device_id **matchid)
+{
+ const struct acpi_device_id *devid;
+
+ for (devid = handler->ids; devid->id[0]; devid++)
+ if (!strcmp((char *)devid->id, idstr)) {
+ if (matchid)
+ *matchid = devid;
+
+ return true;
+ }
+
+ return false;
+}
+
+static struct acpi_scan_handler *acpi_scan_match_handler(char *idstr,
+ const struct acpi_device_id **matchid)
+{
+ struct acpi_scan_handler *handler;
+
+ list_for_each_entry(handler, &acpi_scan_handlers_list, list_node)
+ if (acpi_scan_handler_matching(handler, idstr, matchid))
+ return handler;
+
+ return NULL;
+}
+
+void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
+{
+ if (!!hotplug->enabled == !!val)
+ return;
+
+ mutex_lock(&acpi_scan_lock);
+
+ hotplug->enabled = val;
+
+ mutex_unlock(&acpi_scan_lock);
+}
+
+static void acpi_scan_init_hotplug(acpi_handle handle, int type)
+{
+ struct acpi_device_pnp pnp = {};
+ struct acpi_hardware_id *hwid;
+ struct acpi_scan_handler *handler;
+
+ INIT_LIST_HEAD(&pnp.ids);
+ acpi_set_pnp_ids(handle, &pnp, type);
+
+ if (!pnp.type.hardware_id)
+ return;
+
+ /*
+ * This relies on the fact that acpi_install_notify_handler() will not
+ * install the same notify handler routine twice for the same handle.
+ */
+ list_for_each_entry(hwid, &pnp.ids, list) {
+ handler = acpi_scan_match_handler(hwid->id, NULL);
+ if (handler) {
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ acpi_hotplug_notify_cb, handler);
+ break;
+ }
+ }
+
+ acpi_free_pnp_ids(&pnp);
+}
+
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
@@ -1558,6 +1825,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
+ acpi_scan_init_hotplug(handle, type);
+
if (!(sta & ACPI_STA_DEVICE_PRESENT) &&
!(sta & ACPI_STA_DEVICE_FUNCTIONING)) {
struct acpi_device_wakeup wakeup;
@@ -1583,42 +1852,26 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
-static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
+static int acpi_scan_attach_handler(struct acpi_device *device)
{
- struct acpi_scan_handler *handler;
+ struct acpi_hardware_id *hwid;
+ int ret = 0;
- list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+ list_for_each_entry(hwid, &device->pnp.ids, list) {
const struct acpi_device_id *devid;
+ struct acpi_scan_handler *handler;
- for (devid = handler->ids; devid->id[0]; devid++) {
- int ret;
-
- if (strcmp((char *)devid->id, id))
- continue;
-
+ handler = acpi_scan_match_handler(hwid->id, &devid);
+ if (handler) {
ret = handler->attach(device, devid);
if (ret > 0) {
device->handler = handler;
- return ret;
+ break;
} else if (ret < 0) {
- return ret;
+ break;
}
}
}
- return 0;
-}
-
-static int acpi_scan_attach_handler(struct acpi_device *device)
-{
- struct acpi_hardware_id *hwid;
- int ret = 0;
-
- list_for_each_entry(hwid, &device->pnp.ids, list) {
- ret = acpi_scan_do_attach_handler(device, hwid->id);
- if (ret)
- break;
-
- }
return ret;
}
@@ -1788,9 +2041,10 @@ int __init acpi_scan_init(void)
acpi_pci_root_init();
acpi_pci_link_init();
acpi_platform_init();
+ acpi_lpss_init();
acpi_csrt_init();
acpi_container_init();
- acpi_pci_slot_init();
+ acpi_memory_hotplug_init();
mutex_lock(&acpi_scan_lock);
/*
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 24213033fbae..9c1a435d10e6 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -193,6 +193,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
{
.callback = init_nvs_nosave,
+ .ident = "Sony Vaio VGN-FW21M",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"),
+ },
+ },
+ {
+ .callback = init_nvs_nosave,
.ident = "Sony Vaio VPCEB17FX",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index 41c0504470db..fcae5fa2e1b3 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -7,6 +7,8 @@
#include <linux/moduleparam.h>
#include <acpi/acpi_drivers.h>
+#include "internal.h"
+
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("sysfs");
@@ -249,6 +251,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
static LIST_HEAD(acpi_table_attr_list);
static struct kobject *tables_kobj;
static struct kobject *dynamic_tables_kobj;
+static struct kobject *hotplug_kobj;
struct acpi_table_attr {
struct bin_attribute attr;
@@ -716,6 +719,67 @@ acpi_show_profile(struct device *dev, struct device_attribute *attr,
static const struct device_attribute pm_profile_attr =
__ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL);
+static ssize_t hotplug_enabled_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+
+ return sprintf(buf, "%d\n", hotplug->enabled);
+}
+
+static ssize_t hotplug_enabled_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct acpi_hotplug_profile *hotplug = to_acpi_hotplug_profile(kobj);
+ unsigned int val;
+
+ if (kstrtouint(buf, 10, &val) || val > 1)
+ return -EINVAL;
+
+ acpi_scan_hotplug_enabled(hotplug, val);
+ return size;
+}
+
+static struct kobj_attribute hotplug_enabled_attr =
+ __ATTR(enabled, S_IRUGO | S_IWUSR, hotplug_enabled_show,
+ hotplug_enabled_store);
+
+static struct attribute *hotplug_profile_attrs[] = {
+ &hotplug_enabled_attr.attr,
+ NULL
+};
+
+static struct kobj_type acpi_hotplug_profile_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_attrs = hotplug_profile_attrs,
+};
+
+void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
+ const char *name)
+{
+ int error;
+
+ if (!hotplug_kobj)
+ goto err_out;
+
+ kobject_init(&hotplug->kobj, &acpi_hotplug_profile_ktype);
+ error = kobject_set_name(&hotplug->kobj, "%s", name);
+ if (error)
+ goto err_out;
+
+ hotplug->kobj.parent = hotplug_kobj;
+ error = kobject_add(&hotplug->kobj, hotplug_kobj, NULL);
+ if (error)
+ goto err_out;
+
+ kobject_uevent(&hotplug->kobj, KOBJ_ADD);
+ return;
+
+ err_out:
+ pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
+}
+
int __init acpi_sysfs_init(void)
{
int result;
@@ -723,6 +787,8 @@ int __init acpi_sysfs_init(void)
result = acpi_tables_sysfs_init();
if (result)
return result;
+
+ hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
return result;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 8470771e5eae..a33821ca3895 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -723,9 +723,19 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
return -EINVAL;
if (type == THERMAL_TRIP_ACTIVE) {
- /* aggressive active cooling */
- *trend = THERMAL_TREND_RAISING;
- return 0;
+ unsigned long trip_temp;
+ unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature,
+ tz->kelvin_offset);
+ if (thermal_get_trip_temp(thermal, trip, &trip_temp))
+ return -EINVAL;
+
+ if (temp > trip_temp) {
+ *trend = THERMAL_TREND_RAISING;
+ return 0;
+ } else {
+ /* Fall back on default trend */
+ return -EINVAL;
+ }
}
/*
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 313f959413dc..c3932d0876e0 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -167,7 +167,8 @@ struct acpi_video_device_flags {
u8 dvi:1;
u8 bios:1;
u8 unknown:1;
- u8 reserved:2;
+ u8 notify:1;
+ u8 reserved:1;
};
struct acpi_video_device_cap {
@@ -222,7 +223,7 @@ static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level);
static int acpi_video_device_lcd_get_level_current(
struct acpi_video_device *device,
- unsigned long long *level, int init);
+ unsigned long long *level, bool raw);
static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static int acpi_video_switch_brightness(struct acpi_video_device *device,
@@ -236,7 +237,7 @@ static int acpi_video_get_brightness(struct backlight_device *bd)
struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd);
- if (acpi_video_device_lcd_get_level_current(vd, &cur_level, 0))
+ if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
return -EINVAL;
for (i = 2; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level)
@@ -281,7 +282,7 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig
unsigned long long level;
int offset;
- if (acpi_video_device_lcd_get_level_current(video, &level, 0))
+ if (acpi_video_device_lcd_get_level_current(video, &level, false))
return -EINVAL;
for (offset = 2; offset < video->brightness->count; offset++)
if (level == video->brightness->levels[offset]) {
@@ -447,12 +448,45 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13 - 2000 Notebook PC"),
},
},
+ {
+ .callback = video_ignore_initial_backlight,
+ .ident = "HP Pavilion dm4",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dm4 Notebook PC"),
+ },
+ },
{}
};
+static unsigned long long
+acpi_video_bqc_value_to_level(struct acpi_video_device *device,
+ unsigned long long bqc_value)
+{
+ unsigned long long level;
+
+ if (device->brightness->flags._BQC_use_index) {
+ /*
+ * _BQC returns an index that doesn't account for
+ * the first 2 items with special meaning, so we need
+ * to compensate for that by offsetting ourselves
+ */
+ if (device->brightness->flags._BCL_reversed)
+ bqc_value = device->brightness->count - 3 - bqc_value;
+
+ level = device->brightness->levels[bqc_value + 2];
+ } else {
+ level = bqc_value;
+ }
+
+ level += bqc_offset_aml_bug_workaround;
+
+ return level;
+}
+
static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
- unsigned long long *level, int init)
+ unsigned long long *level, bool raw)
{
acpi_status status = AE_OK;
int i;
@@ -463,29 +497,30 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
status = acpi_evaluate_integer(device->dev->handle, buf,
NULL, level);
if (ACPI_SUCCESS(status)) {
- if (device->brightness->flags._BQC_use_index) {
- if (device->brightness->flags._BCL_reversed)
- *level = device->brightness->count
- - 3 - (*level);
- *level = device->brightness->levels[*level + 2];
-
+ if (raw) {
+ /*
+ * Caller has indicated he wants the raw
+ * value returned by _BQC, so don't furtherly
+ * mess with the value.
+ */
+ return 0;
}
- *level += bqc_offset_aml_bug_workaround;
+
+ *level = acpi_video_bqc_value_to_level(device, *level);
+
for (i = 2; i < device->brightness->count; i++)
if (device->brightness->levels[i] == *level) {
device->brightness->curr = *level;
return 0;
}
- if (!init) {
- /*
- * BQC returned an invalid level.
- * Stop using it.
- */
- ACPI_WARNING((AE_INFO,
- "%s returned an invalid level",
- buf));
- device->cap._BQC = device->cap._BCQ = 0;
- }
+ /*
+ * BQC returned an invalid level.
+ * Stop using it.
+ */
+ ACPI_WARNING((AE_INFO,
+ "%s returned an invalid level",
+ buf));
+ device->cap._BQC = device->cap._BCQ = 0;
} else {
/* Fixme:
* should we return an error or ignore this failure?
@@ -598,6 +633,56 @@ acpi_video_cmp_level(const void *a, const void *b)
}
/*
+ * Decides if _BQC/_BCQ for this system is usable
+ *
+ * We do this by changing the level first and then read out the current
+ * brightness level, if the value does not match, find out if it is using
+ * index. If not, clear the _BQC/_BCQ capability.
+ */
+static int acpi_video_bqc_quirk(struct acpi_video_device *device,
+ int max_level, int current_level)
+{
+ struct acpi_video_device_brightness *br = device->brightness;
+ int result;
+ unsigned long long level;
+ int test_level;
+
+ /* don't mess with existing known broken systems */
+ if (bqc_offset_aml_bug_workaround)
+ return 0;
+
+ /*
+ * Some systems always report current brightness level as maximum
+ * through _BQC, we need to test another value for them.
+ */
+ test_level = current_level == max_level ? br->levels[2] : max_level;
+
+ result = acpi_video_device_lcd_set_level(device, test_level);
+ if (result)
+ return result;
+
+ result = acpi_video_device_lcd_get_level_current(device, &level, true);
+ if (result)
+ return result;
+
+ if (level != test_level) {
+ /* buggy _BQC found, need to find out if it uses index */
+ if (level < br->count) {
+ if (br->flags._BCL_reversed)
+ level = br->count - 3 - level;
+ if (br->levels[level + 2] == test_level)
+ br->flags._BQC_use_index = 1;
+ }
+
+ if (!br->flags._BQC_use_index)
+ device->cap._BQC = device->cap._BCQ = 0;
+ }
+
+ return 0;
+}
+
+
+/*
* Arg:
* device : video output device (LCD, CRT, ..)
*
@@ -703,42 +788,36 @@ acpi_video_init_brightness(struct acpi_video_device *device)
if (!device->cap._BQC)
goto set_level;
- result = acpi_video_device_lcd_get_level_current(device, &level_old, 1);
- if (result)
- goto out_free_levels;
-
- /*
- * Set the level to maximum and check if _BQC uses indexed value
- */
- result = acpi_video_device_lcd_set_level(device, max_level);
+ result = acpi_video_device_lcd_get_level_current(device,
+ &level_old, true);
if (result)
goto out_free_levels;
- result = acpi_video_device_lcd_get_level_current(device, &level, 0);
+ result = acpi_video_bqc_quirk(device, max_level, level_old);
if (result)
goto out_free_levels;
+ /*
+ * cap._BQC may get cleared due to _BQC is found to be broken
+ * in acpi_video_bqc_quirk, so check again here.
+ */
+ if (!device->cap._BQC)
+ goto set_level;
- br->flags._BQC_use_index = (level == max_level ? 0 : 1);
-
- if (!br->flags._BQC_use_index) {
+ if (use_bios_initial_backlight) {
+ level = acpi_video_bqc_value_to_level(device, level_old);
/*
- * Set the backlight to the initial state.
- * On some buggy laptops, _BQC returns an uninitialized value
- * when invoked for the first time, i.e. level_old is invalid.
- * set the backlight to max_level in this case
+ * On some buggy laptops, _BQC returns an uninitialized
+ * value when invoked for the first time, i.e.
+ * level_old is invalid (no matter whether it's a level
+ * or an index). Set the backlight to max_level in this case.
*/
- if (use_bios_initial_backlight) {
- for (i = 2; i < br->count; i++)
- if (level_old == br->levels[i])
- level = level_old;
- }
- goto set_level;
+ for (i = 2; i < br->count; i++)
+ if (level_old == br->levels[i])
+ break;
+ if (i == br->count)
+ level = max_level;
}
- if (br->flags._BCL_reversed)
- level_old = (br->count - 1) - level_old;
- level = br->levels[level_old];
-
set_level:
result = acpi_video_device_lcd_set_level(device, level);
if (result)
@@ -996,53 +1075,51 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute;
- if (!device || !video)
- return -EINVAL;
-
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
- if (ACPI_SUCCESS(status)) {
-
- data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
- device->driver_data = data;
-
- data->device_id = device_id;
- data->video = video;
- data->dev = device;
+ /* Some device omits _ADR, we skip them instead of fail */
+ if (ACPI_FAILURE(status))
+ return 0;
- attribute = acpi_video_get_device_attr(video, device_id);
+ data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
- if((attribute != NULL) && attribute->device_id_scheme) {
- switch (attribute->display_type) {
- case ACPI_VIDEO_DISPLAY_CRT:
- data->flags.crt = 1;
- break;
- case ACPI_VIDEO_DISPLAY_TV:
- data->flags.tvout = 1;
- break;
- case ACPI_VIDEO_DISPLAY_DVI:
- data->flags.dvi = 1;
- break;
- case ACPI_VIDEO_DISPLAY_LCD:
- data->flags.lcd = 1;
- break;
- default:
- data->flags.unknown = 1;
- break;
- }
- if(attribute->bios_can_detect)
- data->flags.bios = 1;
- } else {
- /* Check for legacy IDs */
- device_type = acpi_video_get_device_type(video,
- device_id);
- /* Ignore bits 16 and 18-20 */
- switch (device_type & 0xffe2ffff) {
+ strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+ device->driver_data = data;
+
+ data->device_id = device_id;
+ data->video = video;
+ data->dev = device;
+
+ attribute = acpi_video_get_device_attr(video, device_id);
+
+ if((attribute != NULL) && attribute->device_id_scheme) {
+ switch (attribute->display_type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ data->flags.tvout = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ data->flags.dvi = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ data->flags.lcd = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+ if(attribute->bios_can_detect)
+ data->flags.bios = 1;
+ } else {
+ /* Check for legacy IDs */
+ device_type = acpi_video_get_device_type(video, device_id);
+ /* Ignore bits 16 and 18-20 */
+ switch (device_type & 0xffe2ffff) {
case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
data->flags.crt = 1;
break;
@@ -1054,34 +1131,24 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
break;
default:
data->flags.unknown = 1;
- }
}
+ }
- acpi_video_device_bind(video, data);
- acpi_video_device_find_cap(data);
-
- status = acpi_install_notify_handler(device->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_video_device_notify,
- data);
- if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX
- "Error installing notify handler\n");
- if(data->brightness)
- kfree(data->brightness->levels);
- kfree(data->brightness);
- kfree(data);
- return -ENODEV;
- }
+ acpi_video_device_bind(video, data);
+ acpi_video_device_find_cap(data);
- mutex_lock(&video->device_list_lock);
- list_add_tail(&data->entry, &video->video_device_list);
- mutex_unlock(&video->device_list_lock);
+ status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_video_device_notify, data);
+ if (ACPI_FAILURE(status))
+ dev_err(&device->dev, "Error installing notify handler\n");
+ else
+ data->flags.notify = 1;
- return 0;
- }
+ mutex_lock(&video->device_list_lock);
+ list_add_tail(&data->entry, &video->video_device_list);
+ mutex_unlock(&video->device_list_lock);
- return -ENOENT;
+ return status;
}
/*
@@ -1268,7 +1335,8 @@ acpi_video_switch_brightness(struct acpi_video_device *device, int event)
goto out;
result = acpi_video_device_lcd_get_level_current(device,
- &level_current, 0);
+ &level_current,
+ false);
if (result)
goto out;
@@ -1373,9 +1441,8 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (status) {
- printk(KERN_WARNING PREFIX
- "Can't attach device\n");
- continue;
+ dev_err(&dev->dev, "Can't attach device\n");
+ break;
}
}
return status;
@@ -1388,13 +1455,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
if (!device || !device->video)
return -ENOENT;
- status = acpi_remove_notify_handler(device->dev->handle,
- ACPI_DEVICE_NOTIFY,
- acpi_video_device_notify);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING PREFIX
- "Can't remove video notify handler\n");
+ if (device->flags.notify) {
+ status = acpi_remove_notify_handler(device->dev->handle,
+ ACPI_DEVICE_NOTIFY, acpi_video_device_notify);
+ if (ACPI_FAILURE(status))
+ dev_err(&device->dev->dev,
+ "Can't remove video notify handler\n");
}
+
if (device->backlight) {
backlight_device_unregister(device->backlight);
device->backlight = NULL;
@@ -1676,7 +1744,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
error = acpi_video_bus_get_devices(video, device);
if (error)
- goto err_free_video;
+ goto err_put_video;
video->input = input = input_allocate_device();
if (!input) {
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 4ac2593234e7..66f67626f02e 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -67,40 +67,37 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
return 0;
}
-/* Returns true if the device is a video device which can be handled by
- * video.ko.
+/* Returns true if the ACPI object is a video device which can be
+ * handled by video.ko.
* The device will get a Linux specific CID added in scan.c to
* identify the device as an ACPI graphics device
* Be aware that the graphics device may not be physically present
* Use acpi_video_get_capabilities() to detect general ACPI video
* capabilities of present cards
*/
-long acpi_is_video_device(struct acpi_device *device)
+long acpi_is_video_device(acpi_handle handle)
{
acpi_handle h_dummy;
long video_caps = 0;
- if (!device)
- return 0;
-
/* Is this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) ||
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_DOD", &h_dummy)) ||
+ ACPI_SUCCESS(acpi_get_handle(handle, "_DOS", &h_dummy)))
video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
/* Is this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_ROM", &h_dummy)))
video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
/* Is this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(handle, "_SPD", &h_dummy)))
video_caps |= ACPI_VIDEO_DEVICE_POSTING;
/* Only check for backlight functionality if one of the above hit. */
if (video_caps)
- acpi_walk_namespace(ACPI_TYPE_DEVICE, device->handle,
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
&video_caps, NULL);
@@ -127,7 +124,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
if (!dev)
return AE_OK;
pci_dev_put(dev);
- *cap |= acpi_is_video_device(acpi_dev);
+ *cap |= acpi_is_video_device(handle);
}
return AE_OK;
}
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 6a67b07de494..251e57d38942 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -415,17 +415,17 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* Marvell */
{ PCI_VDEVICE(MARVELL, 0x6145), board_ahci_mv }, /* 6145 */
{ PCI_VDEVICE(MARVELL, 0x6121), board_ahci_mv }, /* 6121 */
- { PCI_DEVICE(0x1b4b, 0x9123),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9123),
.class = PCI_CLASS_STORAGE_SATA_AHCI,
.class_mask = 0xffffff,
.driver_data = board_ahci_yes_fbs }, /* 88se9128 */
- { PCI_DEVICE(0x1b4b, 0x9125),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
- { PCI_DEVICE(0x1b4b, 0x917a),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
- { PCI_DEVICE(0x1b4b, 0x9192),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
- { PCI_DEVICE(0x1b4b, 0x91a3),
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
.driver_data = board_ahci_yes_fbs },
/* Promise */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index ffdd32d22602..2f48123d74c4 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -150,6 +150,7 @@ enum piix_controller_ids {
tolapai_sata,
piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */
ich8_sata_snb,
+ ich8_2port_sata_snb,
};
struct piix_map_db {
@@ -304,7 +305,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller IDE (Lynx Point) */
{ 0x8086, 0x8c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
/* SATA Controller IDE (Lynx Point) */
- { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ { 0x8086, 0x8c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
/* SATA Controller IDE (Lynx Point) */
{ 0x8086, 0x8c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (Lynx Point-LP) */
@@ -439,6 +440,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich8m_apple_sata] = &ich8m_apple_map_db,
[tolapai_sata] = &tolapai_map_db,
[ich8_sata_snb] = &ich8_map_db,
+ [ich8_2port_sata_snb] = &ich8_2port_map_db,
};
static struct pci_bits piix_enable_bits[] = {
@@ -1242,6 +1244,16 @@ static struct ata_port_info piix_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &piix_sata_ops,
},
+
+ [ich8_2port_sata_snb] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR
+ | PIIX_FLAG_PIO16,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
};
#define AHCI_PCI_BAR 5
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 8a52dab412e2..87f2f395d79a 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -17,7 +17,6 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
#include <scsi/scsi_device.h>
#include "libata.h"
@@ -61,7 +60,8 @@ acpi_handle ata_ap_acpi_handle(struct ata_port *ap)
if (ap->flags & ATA_FLAG_ACPI_SATA)
return NULL;
- return acpi_get_child(DEVICE_ACPI_HANDLE(ap->host->dev), ap->port_no);
+ return ap->scsi_host ?
+ DEVICE_ACPI_HANDLE(&ap->scsi_host->shost_gendev) : NULL;
}
EXPORT_SYMBOL(ata_ap_acpi_handle);
@@ -77,7 +77,7 @@ acpi_handle ata_dev_acpi_handle(struct ata_device *dev)
acpi_integer adr;
struct ata_port *ap = dev->link->ap;
- if (dev->flags & ATA_DFLAG_ACPI_DISABLED)
+ if (libata_noacpi || dev->flags & ATA_DFLAG_ACPI_DISABLED)
return NULL;
if (ap->flags & ATA_FLAG_ACPI_SATA) {
@@ -240,28 +240,15 @@ void ata_acpi_dissociate(struct ata_host *host)
}
}
-/**
- * ata_acpi_gtm - execute _GTM
- * @ap: target ATA port
- * @gtm: out parameter for _GTM result
- *
- * Evaluate _GTM and store the result in @gtm.
- *
- * LOCKING:
- * EH context.
- *
- * RETURNS:
- * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
- */
-int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
+static int __ata_acpi_gtm(struct ata_port *ap, acpi_handle handle,
+ struct ata_acpi_gtm *gtm)
{
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
union acpi_object *out_obj;
acpi_status status;
int rc = 0;
- status = acpi_evaluate_object(ata_ap_acpi_handle(ap), "_GTM", NULL,
- &output);
+ status = acpi_evaluate_object(handle, "_GTM", NULL, &output);
rc = -ENOENT;
if (status == AE_NOT_FOUND)
@@ -295,6 +282,27 @@ int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
return rc;
}
+/**
+ * ata_acpi_gtm - execute _GTM
+ * @ap: target ATA port
+ * @gtm: out parameter for _GTM result
+ *
+ * Evaluate _GTM and store the result in @gtm.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
+ */
+int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm)
+{
+ if (ata_ap_acpi_handle(ap))
+ return __ata_acpi_gtm(ap, ata_ap_acpi_handle(ap), gtm);
+ else
+ return -EINVAL;
+}
+
EXPORT_SYMBOL_GPL(ata_acpi_gtm);
/**
@@ -1020,38 +1028,6 @@ void ata_acpi_on_disable(struct ata_device *dev)
ata_acpi_clear_gtf(dev);
}
-static void ata_acpi_register_power_resource(struct ata_device *dev)
-{
- struct scsi_device *sdev = dev->sdev;
- acpi_handle handle;
-
- handle = ata_dev_acpi_handle(dev);
- if (handle)
- acpi_dev_pm_add_dependent(handle, &sdev->sdev_gendev);
-}
-
-static void ata_acpi_unregister_power_resource(struct ata_device *dev)
-{
- struct scsi_device *sdev = dev->sdev;
- acpi_handle handle;
-
- handle = ata_dev_acpi_handle(dev);
- if (handle)
- acpi_dev_pm_remove_dependent(handle, &sdev->sdev_gendev);
-}
-
-void ata_acpi_bind(struct ata_device *dev)
-{
- ata_acpi_register_power_resource(dev);
- if (zpodd_dev_enabled(dev))
- dev_pm_qos_expose_flags(&dev->sdev->sdev_gendev, 0);
-}
-
-void ata_acpi_unbind(struct ata_device *dev)
-{
- ata_acpi_unregister_power_resource(dev);
-}
-
static int compat_pci_ata(struct ata_port *ap)
{
struct device *dev = ap->tdev.parent;
@@ -1071,7 +1047,7 @@ static int compat_pci_ata(struct ata_port *ap)
static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
{
- if (ap->flags & ATA_FLAG_ACPI_SATA)
+ if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA)
return -ENODEV;
*handle = acpi_get_child(DEVICE_ACPI_HANDLE(ap->tdev.parent),
@@ -1080,7 +1056,7 @@ static int ata_acpi_bind_host(struct ata_port *ap, acpi_handle *handle)
if (!*handle)
return -ENODEV;
- if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
+ if (__ata_acpi_gtm(ap, *handle, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
return 0;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 497adea1f0d6..63c743baf920 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2329,7 +2329,7 @@ int ata_dev_configure(struct ata_device *dev)
* from SATA Settings page of Identify Device Data Log.
*/
if (ata_id_has_devslp(dev->id)) {
- u8 sata_setting[ATA_SECT_SIZE];
+ u8 *sata_setting = ap->sector_buf;
int i, j;
dev->flags |= ATA_DFLAG_DEVSLP;
@@ -2439,6 +2439,9 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);
+ if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48)
+ dev->max_sectors = ATA_MAX_SECTORS_LBA48;
+
if (ap->ops->dev_config)
ap->ops->dev_config(dev);
@@ -4100,6 +4103,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
{ "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
+ { "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },
/* Devices we expect to fail diagnostics */
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 318b41358187..dd310b27b24c 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -49,6 +49,7 @@
#include <linux/hdreg.h>
#include <linux/uaccess.h>
#include <linux/suspend.h>
+#include <linux/pm_qos.h>
#include <asm/unaligned.h>
#include "libata.h"
@@ -532,8 +533,8 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key == 0 &&
- sshdr.asc == 0 && sshdr.ascq == 0)
+ if (sshdr.sense_key == RECOVERED_ERROR &&
+ sshdr.asc == 0 && sshdr.ascq == 0x1d)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
@@ -618,8 +619,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key == 0 &&
- sshdr.asc == 0 && sshdr.ascq == 0)
+ if (sshdr.sense_key == RECOVERED_ERROR &&
+ sshdr.asc == 0 && sshdr.ascq == 0x1d)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
@@ -2126,7 +2127,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
memcpy(&rbuf[8], "linux ", 8);
memcpy(&rbuf[16], "libata ", 16);
memcpy(&rbuf[32], DRV_VERSION, 4);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
/* we don't store the ATA device signature, so we fake it */
@@ -3668,7 +3668,9 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
if (!IS_ERR(sdev)) {
dev->sdev = sdev;
scsi_device_put(sdev);
- ata_acpi_bind(dev);
+ if (zpodd_dev_enabled(dev))
+ dev_pm_qos_expose_flags(
+ &sdev->sdev_gendev, 0);
} else {
dev->sdev = NULL;
}
@@ -3767,7 +3769,6 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
if (zpodd_dev_enabled(dev))
zpodd_exit(dev);
- ata_acpi_unbind(dev);
/* clearing dev->sdev is protected by host lock */
sdev = dev->sdev;
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
index 36f189c7ee8c..8d493b4a0961 100644
--- a/drivers/ata/pata_at32.c
+++ b/drivers/ata/pata_at32.c
@@ -393,18 +393,7 @@ static struct platform_driver pata_at32_driver = {
},
};
-static int __init pata_at32_init(void)
-{
- return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
-}
-
-static void __exit pata_at32_exit(void)
-{
- platform_driver_unregister(&pata_at32_driver);
-}
-
-module_init(pata_at32_init);
-module_exit(pata_at32_exit);
+module_platform_driver_probe(pata_at32_driver, pata_at32_probe);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index 40849445a9dc..aa3d166e02eb 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -37,7 +37,7 @@
struct pata_imx_priv {
struct clk *clk;
/* timings/interrupt/control regs */
- u8 *host_regs;
+ void __iomem *host_regs;
u32 ata_ctl;
};
@@ -98,6 +98,7 @@ static int pata_imx_probe(struct platform_device *pdev)
struct pata_imx_priv *priv;
int irq = 0;
struct resource *io_res;
+ int ret;
io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (io_res == NULL)
@@ -112,7 +113,7 @@ static int pata_imx_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- priv->clk = clk_get(&pdev->dev, NULL);
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "Failed to get clock\n");
return PTR_ERR(priv->clk);
@@ -121,8 +122,10 @@ static int pata_imx_probe(struct platform_device *pdev)
clk_prepare_enable(priv->clk);
host = ata_host_alloc(&pdev->dev, 1);
- if (!host)
- goto free_priv;
+ if (!host) {
+ ret = -ENOMEM;
+ goto err;
+ }
host->private_data = priv;
ap = host->ports[0];
@@ -135,7 +138,8 @@ static int pata_imx_probe(struct platform_device *pdev)
resource_size(io_res));
if (!priv->host_regs) {
dev_err(&pdev->dev, "failed to map IO/CTL base\n");
- goto free_priv;
+ ret = -EBUSY;
+ goto err;
}
ap->ioaddr.cmd_addr = priv->host_regs + PATA_IMX_DRIVE_DATA;
@@ -158,13 +162,17 @@ static int pata_imx_probe(struct platform_device *pdev)
priv->host_regs + PATA_IMX_ATA_INT_EN);
/* activate */
- return ata_host_activate(host, irq, ata_sff_interrupt, 0,
+ ret = ata_host_activate(host, irq, ata_sff_interrupt, 0,
&pata_imx_sht);
-free_priv:
+ if (ret)
+ goto err;
+
+ return 0;
+err:
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- return -ENOMEM;
+
+ return ret;
}
static int pata_imx_remove(struct platform_device *pdev)
@@ -177,7 +185,6 @@ static int pata_imx_remove(struct platform_device *pdev)
__raw_writel(0, priv->host_regs + PATA_IMX_ATA_INT_EN);
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
return 0;
}
@@ -223,11 +230,20 @@ static const struct dev_pm_ops pata_imx_pm_ops = {
};
#endif
+static const struct of_device_id imx_pata_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-pata",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct platform_driver pata_imx_driver = {
.probe = pata_imx_probe,
.remove = pata_imx_remove,
.driver = {
.name = DRV_NAME,
+ .of_match_table = imx_pata_dt_ids,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pata_imx_pm_ops,
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 4fe9d2138d48..be816428b430 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -542,7 +542,7 @@ static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
u8 sysclk;
/* Get the clock */
- sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
+ sysclk = (opti_syscfg(0xAC) & 0xC0) >> 6; /* BIOS set */
/* Enter configuration mode */
ioread16(ap->ioaddr.error_addr);
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
index ff2e57f3b597..e73bef3093d2 100644
--- a/drivers/ata/pata_octeon_cf.c
+++ b/drivers/ata/pata_octeon_cf.c
@@ -926,7 +926,7 @@ static int octeon_cf_probe(struct platform_device *pdev)
goto free_cf_port;
}
cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
- res_cs1->end - res_cs1->start + 1);
+ resource_size(res_cs1));
if (!cs1)
goto free_cf_port;
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 958238dda8fc..40254f4df584 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -387,21 +387,9 @@ static struct pcmcia_driver pcmcia_driver = {
.probe = pcmcia_init_one,
.remove = pcmcia_remove_one,
};
-
-static int __init pcmcia_init(void)
-{
- return pcmcia_register_driver(&pcmcia_driver);
-}
-
-static void __exit pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&pcmcia_driver);
-}
+module_pcmcia_driver(pcmcia_driver);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-
-module_init(pcmcia_init);
-module_exit(pcmcia_exit);
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 3f94a886bb35..c76e65927b0e 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -63,7 +63,9 @@ enum {
};
static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
static int pdc2027x_reinit_one(struct pci_dev *pdev);
+#endif
static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 608f82fed632..d40e403e82dd 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -285,6 +285,7 @@ struct sata_fsl_host_priv {
int irq;
int data_snoop;
struct device_attribute intr_coalescing;
+ struct device_attribute rx_watermark;
};
static void fsl_sata_set_irq_coalescing(struct ata_host *host,
@@ -311,7 +312,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host,
intr_coalescing_ticks = ticks;
spin_unlock(&host->lock);
- DPRINTK("intrrupt coalescing, count = 0x%x, ticks = %x\n",
+ DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n",
intr_coalescing_count, intr_coalescing_ticks);
DPRINTK("ICC register status: (hcr base: 0x%x) = 0x%x\n",
hcr_base, ioread32(hcr_base + ICC));
@@ -343,6 +344,48 @@ static ssize_t fsl_sata_intr_coalescing_store(struct device *dev,
return strlen(buf);
}
+static ssize_t fsl_sata_rx_watermark_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned int rx_watermark;
+ unsigned long flags;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *csr_base = host_priv->csr_base;
+
+ spin_lock_irqsave(&host->lock, flags);
+ rx_watermark = ioread32(csr_base + TRANSCFG);
+ rx_watermark &= 0x1f;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return sprintf(buf, "%d\n", rx_watermark);
+}
+
+static ssize_t fsl_sata_rx_watermark_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned int rx_watermark;
+ unsigned long flags;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *csr_base = host_priv->csr_base;
+ u32 temp;
+
+ if (sscanf(buf, "%d", &rx_watermark) != 1) {
+ printk(KERN_ERR "fsl-sata: wrong parameter format.\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+ temp = ioread32(csr_base + TRANSCFG);
+ temp &= 0xffffffe0;
+ iowrite32(temp | rx_watermark, csr_base + TRANSCFG);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+ return strlen(buf);
+}
+
static inline unsigned int sata_fsl_tag(unsigned int tag,
void __iomem *hcr_base)
{
@@ -1500,6 +1543,17 @@ static int sata_fsl_probe(struct platform_device *ofdev)
if (retval)
goto error_exit_with_cleanup;
+ host_priv->rx_watermark.show = fsl_sata_rx_watermark_show;
+ host_priv->rx_watermark.store = fsl_sata_rx_watermark_store;
+ sysfs_attr_init(&host_priv->rx_watermark.attr);
+ host_priv->rx_watermark.attr.name = "rx_watermark";
+ host_priv->rx_watermark.attr.mode = S_IRUGO | S_IWUSR;
+ retval = device_create_file(host->dev, &host_priv->rx_watermark);
+ if (retval) {
+ device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+ goto error_exit_with_cleanup;
+ }
+
return 0;
error_exit_with_cleanup:
@@ -1522,6 +1576,7 @@ static int sata_fsl_remove(struct platform_device *ofdev)
struct sata_fsl_host_priv *host_priv = host->private_data;
device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
+ device_remove_file(&ofdev->dev, &host_priv->rx_watermark);
ata_host_detach(host);
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 5dba77ccaa0b..b20aa96b958d 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -251,7 +251,7 @@ static const struct ata_port_info ahci_highbank_port_info = {
};
static struct scsi_host_template ahci_highbank_platform_sht = {
- AHCI_SHT("highbank-ahci"),
+ AHCI_SHT("sata_highbank"),
};
static const struct of_device_id ahci_of_match[] = {
@@ -418,7 +418,7 @@ static int ahci_highbank_resume(struct device *dev)
}
#endif
-SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
+static SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
ahci_highbank_suspend, ahci_highbank_resume);
static struct platform_driver ahci_highbank_driver = {
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index caf33f620c35..4799868bd733 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -17,6 +17,7 @@
#include <linux/libata.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/err.h>
#define DRV_NAME "sata_rcar"
@@ -799,9 +800,9 @@ static int sata_rcar_probe(struct platform_device *pdev)
host->private_data = priv;
- priv->base = devm_request_and_ioremap(&pdev->dev, mem);
- if (!priv->base) {
- ret = -EADDRNOTAVAIL;
+ priv->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
goto cleanup;
}
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index d6891267f5bb..507362a76a73 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -1055,7 +1055,7 @@ static int he_start(struct atm_dev *dev)
he_writel(he_dev, 0x0, RESET_CNTL);
he_writel(he_dev, 0xff, RESET_CNTL);
- udelay(16*1000); /* 16 ms */
+ msleep(16); /* 16 ms */
status = he_readl(he_dev, RESET_CNTL);
if ((status & BOARD_RST_STATUS) == 0) {
hprintk("reset failed\n");
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 6ee17bb391a9..b8bdfe61daa6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -101,6 +101,8 @@ static inline int hypervisor_init(void) { return 0; }
extern int platform_bus_init(void);
extern void cpu_dev_init(void);
+struct kobject *virtual_device_parent(struct device *dev);
+
extern int bus_add_device(struct device *dev);
extern void bus_probe_device(struct device *dev);
extern void bus_remove_device(struct device *dev);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 519865b53f76..1a68f947ded8 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -898,18 +898,18 @@ static ssize_t bus_uevent_store(struct bus_type *bus,
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
/**
- * __bus_register - register a driver-core subsystem
+ * bus_register - register a driver-core subsystem
* @bus: bus to register
- * @key: lockdep class key
*
* Once we have that, we register the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the subsystem.
*/
-int __bus_register(struct bus_type *bus, struct lock_class_key *key)
+int bus_register(struct bus_type *bus)
{
int retval;
struct subsys_private *priv;
+ struct lock_class_key *key = &bus->lock_key;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
@@ -981,7 +981,7 @@ out:
bus->p = NULL;
return retval;
}
-EXPORT_SYMBOL_GPL(__bus_register);
+EXPORT_SYMBOL_GPL(bus_register);
/**
* bus_unregister - remove a bus from the system
@@ -1205,26 +1205,10 @@ static void system_root_device_release(struct device *dev)
{
kfree(dev);
}
-/**
- * subsys_system_register - register a subsystem at /sys/devices/system/
- * @subsys: system subsystem
- * @groups: default attributes for the root device
- *
- * All 'system' subsystems have a /sys/devices/system/<name> root device
- * with the name of the subsystem. The root device can carry subsystem-
- * wide attributes. All registered devices are below this single root
- * device and are named after the subsystem with a simple enumeration
- * number appended. The registered devices are not explicitely named;
- * only 'id' in the device needs to be set.
- *
- * Do not use this interface for anything new, it exists for compatibility
- * with bad ideas only. New subsystems should use plain subsystems; and
- * add the subsystem-wide attributes should be added to the subsystem
- * directory itself and not some create fake root-device placed in
- * /sys/devices/system/<name>.
- */
-int subsys_system_register(struct bus_type *subsys,
- const struct attribute_group **groups)
+
+static int subsys_register(struct bus_type *subsys,
+ const struct attribute_group **groups,
+ struct kobject *parent_of_root)
{
struct device *dev;
int err;
@@ -1243,7 +1227,7 @@ int subsys_system_register(struct bus_type *subsys,
if (err < 0)
goto err_name;
- dev->kobj.parent = &system_kset->kobj;
+ dev->kobj.parent = parent_of_root;
dev->groups = groups;
dev->release = system_root_device_release;
@@ -1263,8 +1247,55 @@ err_dev:
bus_unregister(subsys);
return err;
}
+
+/**
+ * subsys_system_register - register a subsystem at /sys/devices/system/
+ * @subsys: system subsystem
+ * @groups: default attributes for the root device
+ *
+ * All 'system' subsystems have a /sys/devices/system/<name> root device
+ * with the name of the subsystem. The root device can carry subsystem-
+ * wide attributes. All registered devices are below this single root
+ * device and are named after the subsystem with a simple enumeration
+ * number appended. The registered devices are not explicitely named;
+ * only 'id' in the device needs to be set.
+ *
+ * Do not use this interface for anything new, it exists for compatibility
+ * with bad ideas only. New subsystems should use plain subsystems; and
+ * add the subsystem-wide attributes should be added to the subsystem
+ * directory itself and not some create fake root-device placed in
+ * /sys/devices/system/<name>.
+ */
+int subsys_system_register(struct bus_type *subsys,
+ const struct attribute_group **groups)
+{
+ return subsys_register(subsys, groups, &system_kset->kobj);
+}
EXPORT_SYMBOL_GPL(subsys_system_register);
+/**
+ * subsys_virtual_register - register a subsystem at /sys/devices/virtual/
+ * @subsys: virtual subsystem
+ * @groups: default attributes for the root device
+ *
+ * All 'virtual' subsystems have a /sys/devices/system/<name> root device
+ * with the name of the subystem. The root device can carry subsystem-wide
+ * attributes. All registered devices are below this single root device.
+ * There's no restriction on device naming. This is for kernel software
+ * constructs which need sysfs interface.
+ */
+int subsys_virtual_register(struct bus_type *subsys,
+ const struct attribute_group **groups)
+{
+ struct kobject *virtual_dir;
+
+ virtual_dir = virtual_device_parent(NULL);
+ if (!virtual_dir)
+ return -ENOMEM;
+
+ return subsys_register(subsys, groups, virtual_dir);
+}
+
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 56536f4b0f6b..016312437577 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -283,15 +283,21 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
const char *tmp;
const char *name;
umode_t mode = 0;
+ kuid_t uid = GLOBAL_ROOT_UID;
+ kgid_t gid = GLOBAL_ROOT_GID;
add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
- name = device_get_devnode(dev, &mode, &tmp);
+ name = device_get_devnode(dev, &mode, &uid, &gid, &tmp);
if (name) {
add_uevent_var(env, "DEVNAME=%s", name);
- kfree(tmp);
if (mode)
add_uevent_var(env, "DEVMODE=%#o", mode & 0777);
+ if (!uid_eq(uid, GLOBAL_ROOT_UID))
+ add_uevent_var(env, "DEVUID=%u", from_kuid(&init_user_ns, uid));
+ if (!gid_eq(gid, GLOBAL_ROOT_GID))
+ add_uevent_var(env, "DEVGID=%u", from_kgid(&init_user_ns, gid));
+ kfree(tmp);
}
}
@@ -563,8 +569,15 @@ int device_create_file(struct device *dev,
const struct device_attribute *attr)
{
int error = 0;
- if (dev)
+
+ if (dev) {
+ WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
+ "Write permission without 'store'\n");
+ WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
+ "Read permission without 'show'\n");
error = sysfs_create_file(&dev->kobj, &attr->attr);
+ }
+
return error;
}
@@ -690,7 +703,7 @@ void device_initialize(struct device *dev)
set_dev_node(dev, -1);
}
-static struct kobject *virtual_device_parent(struct device *dev)
+struct kobject *virtual_device_parent(struct device *dev)
{
static struct kobject *virtual_dir = NULL;
@@ -1274,6 +1287,8 @@ static struct device *next_device(struct klist_iter *i)
* device_get_devnode - path of device node file
* @dev: device
* @mode: returned file access mode
+ * @uid: returned file owner
+ * @gid: returned file group
* @tmp: possibly allocated string
*
* Return the relative path of a possible device node.
@@ -1282,7 +1297,8 @@ static struct device *next_device(struct klist_iter *i)
* freed by the caller.
*/
const char *device_get_devnode(struct device *dev,
- umode_t *mode, const char **tmp)
+ umode_t *mode, kuid_t *uid, kgid_t *gid,
+ const char **tmp)
{
char *s;
@@ -1290,7 +1306,7 @@ const char *device_get_devnode(struct device *dev,
/* the device type may provide a specific name */
if (dev->type && dev->type->devnode)
- *tmp = dev->type->devnode(dev, mode);
+ *tmp = dev->type->devnode(dev, mode, uid, gid);
if (*tmp)
return *tmp;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index fb10728f6372..3d48fc887ef4 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -25,6 +25,15 @@ EXPORT_SYMBOL_GPL(cpu_subsys);
static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
#ifdef CONFIG_HOTPLUG_CPU
+static void change_cpu_under_node(struct cpu *cpu,
+ unsigned int from_nid, unsigned int to_nid)
+{
+ int cpuid = cpu->dev.id;
+ unregister_cpu_under_node(cpuid, from_nid);
+ register_cpu_under_node(cpuid, to_nid);
+ cpu->node_id = to_nid;
+}
+
static ssize_t show_online(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -39,17 +48,29 @@ static ssize_t __ref store_online(struct device *dev,
const char *buf, size_t count)
{
struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = cpu->dev.id;
+ int from_nid, to_nid;
ssize_t ret;
cpu_hotplug_driver_lock();
switch (buf[0]) {
case '0':
- ret = cpu_down(cpu->dev.id);
+ ret = cpu_down(cpuid);
if (!ret)
kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
break;
case '1':
- ret = cpu_up(cpu->dev.id);
+ from_nid = cpu_to_node(cpuid);
+ ret = cpu_up(cpuid);
+
+ /*
+ * When hot adding memory to memoryless node and enabling a cpu
+ * on the node, node number of the cpu may internally change.
+ */
+ to_nid = cpu_to_node(cpuid);
+ if (from_nid != to_nid)
+ change_cpu_under_node(cpu, from_nid, to_nid);
+
if (!ret)
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
break;
@@ -132,6 +153,17 @@ static ssize_t show_crash_notes(struct device *dev, struct device_attribute *att
return rc;
}
static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL);
+
+static ssize_t show_crash_notes_size(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t rc;
+
+ rc = sprintf(buf, "%zu\n", sizeof(note_buf_t));
+ return rc;
+}
+static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL);
#endif
/*
@@ -259,6 +291,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
#ifdef CONFIG_KEXEC
if (!error)
error = device_create_file(&cpu->dev, &dev_attr_crash_notes);
+ if (!error)
+ error = device_create_file(&cpu->dev,
+ &dev_attr_crash_notes_size);
#endif
return error;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index bb5645ea0282..35fa36898916 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -380,7 +380,7 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
- pm_runtime_idle(dev);
+ pm_request_idle(dev);
return ret;
}
@@ -428,7 +428,7 @@ int device_attach(struct device *dev)
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
- pm_runtime_idle(dev);
+ pm_request_idle(dev);
}
out_unlock:
device_unlock(dev);
@@ -499,7 +499,7 @@ static void __device_release_driver(struct device *dev)
BUS_NOTIFY_UNBIND_DRIVER,
dev);
- pm_runtime_put_sync(dev);
+ pm_runtime_put(dev);
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 668390664764..507379e7b763 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -671,6 +671,80 @@ int devres_release_group(struct device *dev, void *id)
EXPORT_SYMBOL_GPL(devres_release_group);
/*
+ * Custom devres actions allow inserting a simple function call
+ * into the teadown sequence.
+ */
+
+struct action_devres {
+ void *data;
+ void (*action)(void *);
+};
+
+static int devm_action_match(struct device *dev, void *res, void *p)
+{
+ struct action_devres *devres = res;
+ struct action_devres *target = p;
+
+ return devres->action == target->action &&
+ devres->data == target->data;
+}
+
+static void devm_action_release(struct device *dev, void *res)
+{
+ struct action_devres *devres = res;
+
+ devres->action(devres->data);
+}
+
+/**
+ * devm_add_action() - add a custom action to list of managed resources
+ * @dev: Device that owns the action
+ * @action: Function that should be called
+ * @data: Pointer to data passed to @action implementation
+ *
+ * This adds a custom action to the list of managed resources so that
+ * it gets executed as part of standard resource unwinding.
+ */
+int devm_add_action(struct device *dev, void (*action)(void *), void *data)
+{
+ struct action_devres *devres;
+
+ devres = devres_alloc(devm_action_release,
+ sizeof(struct action_devres), GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ devres->data = data;
+ devres->action = action;
+
+ devres_add(dev, devres);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_add_action);
+
+/**
+ * devm_remove_action() - removes previously added custom action
+ * @dev: Device that owns the action
+ * @action: Function implementing the action
+ * @data: Pointer to data passed to @action implementation
+ *
+ * Removes instance of @action previously added by devm_add_action().
+ * Both action and data should match one of the existing entries.
+ */
+void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
+{
+ struct action_devres devres = {
+ .data = data,
+ .action = action,
+ };
+
+ WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match,
+ &devres));
+
+}
+EXPORT_SYMBOL_GPL(devm_remove_action);
+
+/*
* Managed kzalloc/kfree
*/
static void devm_kzalloc_release(struct device *dev, void *res)
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 01fc5b07f951..7413d065906b 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -24,6 +24,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/kthread.h>
+#include "base.h"
static struct task_struct *thread;
@@ -41,6 +42,8 @@ static struct req {
int err;
const char *name;
umode_t mode; /* 0 => delete */
+ kuid_t uid;
+ kgid_t gid;
struct device *dev;
} *requests;
@@ -85,7 +88,9 @@ int devtmpfs_create_node(struct device *dev)
return 0;
req.mode = 0;
- req.name = device_get_devnode(dev, &req.mode, &tmp);
+ req.uid = GLOBAL_ROOT_UID;
+ req.gid = GLOBAL_ROOT_GID;
+ req.name = device_get_devnode(dev, &req.mode, &req.uid, &req.gid, &tmp);
if (!req.name)
return -ENOMEM;
@@ -121,7 +126,7 @@ int devtmpfs_delete_node(struct device *dev)
if (!thread)
return 0;
- req.name = device_get_devnode(dev, NULL, &tmp);
+ req.name = device_get_devnode(dev, NULL, NULL, NULL, &tmp);
if (!req.name)
return -ENOMEM;
@@ -187,7 +192,8 @@ static int create_path(const char *nodepath)
return err;
}
-static int handle_create(const char *nodename, umode_t mode, struct device *dev)
+static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
+ kgid_t gid, struct device *dev)
{
struct dentry *dentry;
struct path path;
@@ -201,14 +207,14 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- err = vfs_mknod(path.dentry->d_inode,
- dentry, mode, dev->devt);
+ err = vfs_mknod(path.dentry->d_inode, dentry, mode, dev->devt);
if (!err) {
struct iattr newattrs;
- /* fixup possibly umasked mode */
newattrs.ia_mode = mode;
- newattrs.ia_valid = ATTR_MODE;
+ newattrs.ia_uid = uid;
+ newattrs.ia_gid = gid;
+ newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
mutex_lock(&dentry->d_inode->i_mutex);
notify_change(dentry, &newattrs);
mutex_unlock(&dentry->d_inode->i_mutex);
@@ -358,10 +364,11 @@ int devtmpfs_mount(const char *mntdir)
static DECLARE_COMPLETION(setup_done);
-static int handle(const char *name, umode_t mode, struct device *dev)
+static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid,
+ struct device *dev)
{
if (mode)
- return handle_create(name, mode, dev);
+ return handle_create(name, mode, uid, gid, dev);
else
return handle_remove(name, dev);
}
@@ -387,7 +394,8 @@ static int devtmpfsd(void *p)
spin_unlock(&req_lock);
while (req) {
struct req *next = req->next;
- req->err = handle(req->name, req->mode, req->dev);
+ req->err = handle(req->name, req->mode,
+ req->uid, req->gid, req->dev);
complete(&req->done);
req = next;
}
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 2a7cb0df176b..08fe897c0b4c 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -27,9 +27,18 @@
#include <linux/dma-buf.h>
#include <linux/anon_inodes.h>
#include <linux/export.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
static inline int is_dma_buf_file(struct file *);
+struct dma_buf_list {
+ struct list_head head;
+ struct mutex lock;
+};
+
+static struct dma_buf_list db_list;
+
static int dma_buf_release(struct inode *inode, struct file *file)
{
struct dma_buf *dmabuf;
@@ -42,6 +51,11 @@ static int dma_buf_release(struct inode *inode, struct file *file)
BUG_ON(dmabuf->vmapping_counter);
dmabuf->ops->release(dmabuf);
+
+ mutex_lock(&db_list.lock);
+ list_del(&dmabuf->list_node);
+ mutex_unlock(&db_list.lock);
+
kfree(dmabuf);
return 0;
}
@@ -77,22 +91,24 @@ static inline int is_dma_buf_file(struct file *file)
}
/**
- * dma_buf_export - Creates a new dma_buf, and associates an anon file
+ * dma_buf_export_named - Creates a new dma_buf, and associates an anon file
* with this buffer, so it can be exported.
* Also connect the allocator specific data and ops to the buffer.
+ * Additionally, provide a name string for exporter; useful in debugging.
*
* @priv: [in] Attach private data of allocator to this buffer
* @ops: [in] Attach allocator-defined dma buf ops to the new buffer.
* @size: [in] Size of the buffer
* @flags: [in] mode flags for the file.
+ * @exp_name: [in] name of the exporting module - useful for debugging.
*
* Returns, on success, a newly created dma_buf object, which wraps the
* supplied private data and operations for dma_buf_ops. On either missing
* ops, or error in allocating struct dma_buf, will return negative error.
*
*/
-struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
- size_t size, int flags)
+struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
+ size_t size, int flags, const char *exp_name)
{
struct dma_buf *dmabuf;
struct file *file;
@@ -114,6 +130,7 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
dmabuf->priv = priv;
dmabuf->ops = ops;
dmabuf->size = size;
+ dmabuf->exp_name = exp_name;
file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags);
@@ -122,9 +139,13 @@ struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
mutex_init(&dmabuf->lock);
INIT_LIST_HEAD(&dmabuf->attachments);
+ mutex_lock(&db_list.lock);
+ list_add(&dmabuf->list_node, &db_list.head);
+ mutex_unlock(&db_list.lock);
+
return dmabuf;
}
-EXPORT_SYMBOL_GPL(dma_buf_export);
+EXPORT_SYMBOL_GPL(dma_buf_export_named);
/**
@@ -548,3 +569,143 @@ void dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr)
mutex_unlock(&dmabuf->lock);
}
EXPORT_SYMBOL_GPL(dma_buf_vunmap);
+
+#ifdef CONFIG_DEBUG_FS
+static int dma_buf_describe(struct seq_file *s)
+{
+ int ret;
+ struct dma_buf *buf_obj;
+ struct dma_buf_attachment *attach_obj;
+ int count = 0, attach_count;
+ size_t size = 0;
+
+ ret = mutex_lock_interruptible(&db_list.lock);
+
+ if (ret)
+ return ret;
+
+ seq_printf(s, "\nDma-buf Objects:\n");
+ seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n");
+
+ list_for_each_entry(buf_obj, &db_list.head, list_node) {
+ ret = mutex_lock_interruptible(&buf_obj->lock);
+
+ if (ret) {
+ seq_printf(s,
+ "\tERROR locking buffer object: skipping\n");
+ continue;
+ }
+
+ seq_printf(s, "\t");
+
+ seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n",
+ buf_obj->exp_name, buf_obj->size,
+ buf_obj->file->f_flags, buf_obj->file->f_mode,
+ (long)(buf_obj->file->f_count.counter));
+
+ seq_printf(s, "\t\tAttached Devices:\n");
+ attach_count = 0;
+
+ list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
+ seq_printf(s, "\t\t");
+
+ seq_printf(s, "%s\n", attach_obj->dev->init_name);
+ attach_count++;
+ }
+
+ seq_printf(s, "\n\t\tTotal %d devices attached\n",
+ attach_count);
+
+ count++;
+ size += buf_obj->size;
+ mutex_unlock(&buf_obj->lock);
+ }
+
+ seq_printf(s, "\nTotal %d objects, %zu bytes\n", count, size);
+
+ mutex_unlock(&db_list.lock);
+ return 0;
+}
+
+static int dma_buf_show(struct seq_file *s, void *unused)
+{
+ void (*func)(struct seq_file *) = s->private;
+ func(s);
+ return 0;
+}
+
+static int dma_buf_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dma_buf_show, inode->i_private);
+}
+
+static const struct file_operations dma_buf_debug_fops = {
+ .open = dma_buf_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *dma_buf_debugfs_dir;
+
+static int dma_buf_init_debugfs(void)
+{
+ int err = 0;
+ dma_buf_debugfs_dir = debugfs_create_dir("dma_buf", NULL);
+ if (IS_ERR(dma_buf_debugfs_dir)) {
+ err = PTR_ERR(dma_buf_debugfs_dir);
+ dma_buf_debugfs_dir = NULL;
+ return err;
+ }
+
+ err = dma_buf_debugfs_create_file("bufinfo", dma_buf_describe);
+
+ if (err)
+ pr_debug("dma_buf: debugfs: failed to create node bufinfo\n");
+
+ return err;
+}
+
+static void dma_buf_uninit_debugfs(void)
+{
+ if (dma_buf_debugfs_dir)
+ debugfs_remove_recursive(dma_buf_debugfs_dir);
+}
+
+int dma_buf_debugfs_create_file(const char *name,
+ int (*write)(struct seq_file *))
+{
+ struct dentry *d;
+
+ d = debugfs_create_file(name, S_IRUGO, dma_buf_debugfs_dir,
+ write, &dma_buf_debug_fops);
+
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+
+ return 0;
+}
+#else
+static inline int dma_buf_init_debugfs(void)
+{
+ return 0;
+}
+static inline void dma_buf_uninit_debugfs(void)
+{
+}
+#endif
+
+static int __init dma_buf_init(void)
+{
+ mutex_init(&db_list.lock);
+ INIT_LIST_HEAD(&db_list.head);
+ dma_buf_init_debugfs();
+ return 0;
+}
+subsys_initcall(dma_buf_init);
+
+static void __exit dma_buf_deinit(void)
+{
+ dma_buf_uninit_debugfs();
+}
+__exitcall(dma_buf_deinit);
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index a51007b79032..14f8a6954da0 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -93,16 +93,6 @@ int register_memory(struct memory_block *memory)
return error;
}
-static void
-unregister_memory(struct memory_block *memory)
-{
- BUG_ON(memory->dev.bus != &memory_subsys);
-
- /* drop the ref. we got in remove_memory_block() */
- kobject_put(&memory->dev.kobj);
- device_unregister(&memory->dev);
-}
-
unsigned long __weak memory_block_size_bytes(void)
{
return MIN_MEMORY_BLOCK_SIZE;
@@ -217,8 +207,7 @@ int memory_isolate_notify(unsigned long val, void *v)
* The probe routines leave the pages reserved, just as the bootmem code does.
* Make sure they're still that way.
*/
-static bool pages_correctly_reserved(unsigned long start_pfn,
- unsigned long nr_pages)
+static bool pages_correctly_reserved(unsigned long start_pfn)
{
int i, j;
struct page *page;
@@ -266,7 +255,7 @@ memory_block_action(unsigned long phys_index, unsigned long action, int online_t
switch (action) {
case MEM_ONLINE:
- if (!pages_correctly_reserved(start_pfn, nr_pages))
+ if (!pages_correctly_reserved(start_pfn))
return -EBUSY;
ret = online_pages(start_pfn, nr_pages, online_type);
@@ -637,8 +626,28 @@ static int add_memory_section(int nid, struct mem_section *section,
return ret;
}
-int remove_memory_block(unsigned long node_id, struct mem_section *section,
- int phys_device)
+/*
+ * need an interface for the VM to add new memory regions,
+ * but without onlining it.
+ */
+int register_new_memory(int nid, struct mem_section *section)
+{
+ return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static void
+unregister_memory(struct memory_block *memory)
+{
+ BUG_ON(memory->dev.bus != &memory_subsys);
+
+ /* drop the ref. we got in remove_memory_block() */
+ kobject_put(&memory->dev.kobj);
+ device_unregister(&memory->dev);
+}
+
+static int remove_memory_block(unsigned long node_id,
+ struct mem_section *section, int phys_device)
{
struct memory_block *mem;
@@ -661,15 +670,6 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section,
return 0;
}
-/*
- * need an interface for the VM to add new memory regions,
- * but without onlining it.
- */
-int register_new_memory(int nid, struct mem_section *section)
-{
- return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG);
-}
-
int unregister_memory_section(struct mem_section *section)
{
if (!present_section(section))
@@ -677,6 +677,7 @@ int unregister_memory_section(struct mem_section *section)
return remove_memory_block(0, section, 0);
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
/*
* offline one memory block. If the memory block has been offlined, do nothing.
diff --git a/drivers/base/node.c b/drivers/base/node.c
index fac124a7e1c5..7616a77ca322 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -7,6 +7,7 @@
#include <linux/mm.h>
#include <linux/memory.h>
#include <linux/vmstat.h>
+#include <linux/notifier.h>
#include <linux/node.h>
#include <linux/hugetlb.h>
#include <linux/compaction.h>
@@ -683,8 +684,11 @@ static int __init register_node_type(void)
ret = subsys_system_register(&node_subsys, cpu_root_attr_groups);
if (!ret) {
- hotplug_memory_notifier(node_memory_callback,
- NODE_CALLBACK_PRI);
+ static struct notifier_block node_memory_callback_nb = {
+ .notifier_call = node_memory_callback,
+ .priority = NODE_CALLBACK_PRI,
+ };
+ register_hotmemory_notifier(&node_memory_callback_nb);
}
/*
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index c0b8df38402b..9eda84246ffd 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -46,8 +46,8 @@ EXPORT_SYMBOL_GPL(platform_bus);
* manipulate any relevant information in the pdev_archdata they can do:
*
* platform_device_alloc()
- * ... manipulate ...
- * platform_device_add()
+ * ... manipulate ...
+ * platform_device_add()
*
* And if they don't care they can just call platform_device_register() and
* everything will just work out.
@@ -326,9 +326,7 @@ int platform_device_add(struct platform_device *pdev)
}
if (p && insert_resource(p, r)) {
- printk(KERN_ERR
- "%s: failed to claim resource %d\n",
- dev_name(&pdev->dev), i);
+ dev_err(&pdev->dev, "failed to claim resource %d\n", i);
ret = -EBUSY;
goto failed;
}
@@ -555,7 +553,8 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister);
/**
* platform_driver_probe - register driver for non-hotpluggable device
* @drv: platform driver structure
- * @probe: the driver probe routine, probably from an __init section
+ * @probe: the driver probe routine, probably from an __init section,
+ * must not return -EPROBE_DEFER.
*
* Use this instead of platform_driver_register() when you know the device
* is not hotpluggable and has already been registered, and you want to
@@ -566,6 +565,9 @@ EXPORT_SYMBOL_GPL(platform_driver_unregister);
* into system-on-chip processors, where the controller devices have been
* configured as part of board setup.
*
+ * This is incompatible with deferred probing so probe() must not
+ * return -EPROBE_DEFER.
+ *
* Returns zero if the driver registered and bound to a device, else returns
* a negative error code and with the driver not registered.
*/
@@ -682,7 +684,7 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
int rc;
/* Some devices have extra OF data and an OF-style MODALIAS */
- rc = of_device_uevent_modalias(dev,env);
+ rc = of_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
@@ -1126,8 +1128,8 @@ static int __init early_platform_driver_probe_id(char *class_str,
switch (match_id) {
case EARLY_PLATFORM_ID_ERROR:
- pr_warning("%s: unable to parse %s parameter\n",
- class_str, epdrv->pdrv->driver.name);
+ pr_warn("%s: unable to parse %s parameter\n",
+ class_str, epdrv->pdrv->driver.name);
/* fall-through */
case EARLY_PLATFORM_ID_UNSET:
match = NULL;
@@ -1158,8 +1160,8 @@ static int __init early_platform_driver_probe_id(char *class_str,
}
if (epdrv->pdrv->probe(match))
- pr_warning("%s: unable to probe %s early.\n",
- class_str, match->name);
+ pr_warn("%s: unable to probe %s early.\n",
+ class_str, match->name);
else
n++;
}
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 9a6b05a35603..7072404c8b6d 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -920,7 +920,7 @@ static int pm_genpd_prepare(struct device *dev)
pm_wakeup_event(dev, 0);
if (pm_wakeup_pending()) {
- pm_runtime_put_sync(dev);
+ pm_runtime_put(dev);
return -EBUSY;
}
@@ -961,7 +961,7 @@ static int pm_genpd_prepare(struct device *dev)
pm_runtime_enable(dev);
}
- pm_runtime_put_sync(dev);
+ pm_runtime_put(dev);
return ret;
}
@@ -1327,7 +1327,7 @@ static void pm_genpd_complete(struct device *dev)
pm_generic_complete(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- pm_runtime_idle(dev);
+ pm_request_idle(dev);
}
}
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index d03d290f31c2..bfd898b8988e 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -324,6 +324,6 @@ void pm_generic_complete(struct device *dev)
* Let runtime PM try to suspend devices that haven't been in use before
* going into the system-wide sleep state we're resuming from.
*/
- pm_runtime_idle(dev);
+ pm_request_idle(dev);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 15beb500a4e4..5a9b6569dd74 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -756,7 +756,7 @@ static void device_complete(struct device *dev, pm_message_t state)
device_unlock(dev);
- pm_runtime_put_sync(dev);
+ pm_runtime_put(dev);
}
/**
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 32ee0fc7ea54..f0077cb8e249 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -55,6 +55,7 @@
* @rate: Frequency in hertz
* @u_volt: Nominal voltage in microvolts corresponding to this OPP
* @dev_opp: points back to the device_opp struct this opp belongs to
+ * @head: RCU callback head used for deferred freeing
*
* This structure stores the OPP information for a given device.
*/
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 5f74587ef258..71671c42ef45 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -46,6 +46,7 @@
#include "power.h"
static DEFINE_MUTEX(dev_pm_qos_mtx);
+static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
@@ -216,12 +217,17 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
struct pm_qos_constraints *c;
struct pm_qos_flags *f;
- mutex_lock(&dev_pm_qos_mtx);
+ mutex_lock(&dev_pm_qos_sysfs_mtx);
/*
* If the device's PM QoS resume latency limit or PM QoS flags have been
* exposed to user space, they have to be hidden at this point.
*/
+ pm_qos_sysfs_remove_latency(dev);
+ pm_qos_sysfs_remove_flags(dev);
+
+ mutex_lock(&dev_pm_qos_mtx);
+
__dev_pm_qos_hide_latency_limit(dev);
__dev_pm_qos_hide_flags(dev);
@@ -254,6 +260,8 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
out:
mutex_unlock(&dev_pm_qos_mtx);
+
+ mutex_unlock(&dev_pm_qos_sysfs_mtx);
}
/**
@@ -558,6 +566,14 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
kfree(req);
}
+static void dev_pm_qos_drop_user_request(struct device *dev,
+ enum dev_pm_qos_req_type type)
+{
+ mutex_lock(&dev_pm_qos_mtx);
+ __dev_pm_qos_drop_user_request(dev, type);
+ mutex_unlock(&dev_pm_qos_mtx);
+}
+
/**
* dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
* @dev: Device whose PM QoS latency limit is to be exposed to user space.
@@ -581,6 +597,8 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
return ret;
}
+ mutex_lock(&dev_pm_qos_sysfs_mtx);
+
mutex_lock(&dev_pm_qos_mtx);
if (IS_ERR_OR_NULL(dev->power.qos))
@@ -591,26 +609,27 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
if (ret < 0) {
__dev_pm_qos_remove_request(req);
kfree(req);
+ mutex_unlock(&dev_pm_qos_mtx);
goto out;
}
-
dev->power.qos->latency_req = req;
+
+ mutex_unlock(&dev_pm_qos_mtx);
+
ret = pm_qos_sysfs_add_latency(dev);
if (ret)
- __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+ dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
out:
- mutex_unlock(&dev_pm_qos_mtx);
+ mutex_unlock(&dev_pm_qos_sysfs_mtx);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
static void __dev_pm_qos_hide_latency_limit(struct device *dev)
{
- if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) {
- pm_qos_sysfs_remove_latency(dev);
+ if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
- }
}
/**
@@ -619,9 +638,15 @@ static void __dev_pm_qos_hide_latency_limit(struct device *dev)
*/
void dev_pm_qos_hide_latency_limit(struct device *dev)
{
+ mutex_lock(&dev_pm_qos_sysfs_mtx);
+
+ pm_qos_sysfs_remove_latency(dev);
+
mutex_lock(&dev_pm_qos_mtx);
__dev_pm_qos_hide_latency_limit(dev);
mutex_unlock(&dev_pm_qos_mtx);
+
+ mutex_unlock(&dev_pm_qos_sysfs_mtx);
}
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
@@ -649,6 +674,8 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
}
pm_runtime_get_sync(dev);
+ mutex_lock(&dev_pm_qos_sysfs_mtx);
+
mutex_lock(&dev_pm_qos_mtx);
if (IS_ERR_OR_NULL(dev->power.qos))
@@ -659,16 +686,19 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
if (ret < 0) {
__dev_pm_qos_remove_request(req);
kfree(req);
+ mutex_unlock(&dev_pm_qos_mtx);
goto out;
}
-
dev->power.qos->flags_req = req;
+
+ mutex_unlock(&dev_pm_qos_mtx);
+
ret = pm_qos_sysfs_add_flags(dev);
if (ret)
- __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
+ dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
out:
- mutex_unlock(&dev_pm_qos_mtx);
+ mutex_unlock(&dev_pm_qos_sysfs_mtx);
pm_runtime_put(dev);
return ret;
}
@@ -676,10 +706,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
static void __dev_pm_qos_hide_flags(struct device *dev)
{
- if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) {
- pm_qos_sysfs_remove_flags(dev);
+ if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
- }
}
/**
@@ -689,9 +717,15 @@ static void __dev_pm_qos_hide_flags(struct device *dev)
void dev_pm_qos_hide_flags(struct device *dev)
{
pm_runtime_get_sync(dev);
+ mutex_lock(&dev_pm_qos_sysfs_mtx);
+
+ pm_qos_sysfs_remove_flags(dev);
+
mutex_lock(&dev_pm_qos_mtx);
__dev_pm_qos_hide_flags(dev);
mutex_unlock(&dev_pm_qos_mtx);
+
+ mutex_unlock(&dev_pm_qos_sysfs_mtx);
pm_runtime_put(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 1244930e3d7a..ef13ad08afb2 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1400,5 +1400,5 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.runtime_status == RPM_ACTIVE)
pm_runtime_set_suspended(dev);
if (dev->power.irq_safe && dev->parent)
- pm_runtime_put_sync(dev->parent);
+ pm_runtime_put(dev->parent);
}
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd33ce3d..c130536e0ab0 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -38,7 +38,8 @@ struct regmap_format {
unsigned int reg, unsigned int val);
void (*format_reg)(void *buf, unsigned int reg, unsigned int shift);
void (*format_val)(void *buf, unsigned int val, unsigned int shift);
- unsigned int (*parse_val)(void *buf);
+ unsigned int (*parse_val)(const void *buf);
+ void (*parse_inplace)(void *buf);
};
struct regmap_async {
@@ -76,6 +77,7 @@ struct regmap {
unsigned int debugfs_tot_len;
struct list_head debugfs_off_cache;
+ struct mutex cache_lock;
#endif
unsigned int max_register;
@@ -125,6 +127,9 @@ struct regmap {
void *cache;
u32 cache_dirty;
+ unsigned long *cache_present;
+ unsigned int cache_present_nbits;
+
struct reg_default *patch;
int patch_regs;
@@ -187,12 +192,35 @@ int regcache_read(struct regmap *map,
int regcache_write(struct regmap *map,
unsigned int reg, unsigned int value);
int regcache_sync(struct regmap *map);
-
-unsigned int regcache_get_val(const void *base, unsigned int idx,
- unsigned int word_size);
-bool regcache_set_val(void *base, unsigned int idx,
- unsigned int val, unsigned int word_size);
+int regcache_sync_block(struct regmap *map, void *block,
+ unsigned int block_base, unsigned int start,
+ unsigned int end);
+
+static inline const void *regcache_get_val_addr(struct regmap *map,
+ const void *base,
+ unsigned int idx)
+{
+ return base + (map->cache_word_size * idx);
+}
+
+unsigned int regcache_get_val(struct regmap *map, const void *base,
+ unsigned int idx);
+bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
+ unsigned int val);
int regcache_lookup_reg(struct regmap *map, unsigned int reg);
+int regcache_set_reg_present(struct regmap *map, unsigned int reg);
+
+static inline bool regcache_reg_present(struct regmap *map, unsigned int reg)
+{
+ if (!map->cache_present)
+ return true;
+ if (reg > map->cache_present_nbits)
+ return false;
+ return map->cache_present[BIT_WORD(reg)] & BIT_MASK(reg);
+}
+
+int _regmap_raw_write(struct regmap *map, unsigned int reg,
+ const void *val, size_t val_len, bool async);
void regmap_async_complete_cb(struct regmap_async *async, int ret);
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index afd6aa91a0df..e210a6d1406a 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -260,8 +260,7 @@ static int regcache_lzo_read(struct regmap *map,
ret = regcache_lzo_decompress_cache_block(map, lzo_block);
if (ret >= 0)
/* fetch the value from the cache */
- *value = regcache_get_val(lzo_block->dst, blkpos,
- map->cache_word_size);
+ *value = regcache_get_val(map, lzo_block->dst, blkpos);
kfree(lzo_block->dst);
/* restore the pointer and length of the compressed block */
@@ -304,8 +303,7 @@ static int regcache_lzo_write(struct regmap *map,
}
/* write the new value to the cache */
- if (regcache_set_val(lzo_block->dst, blkpos, value,
- map->cache_word_size)) {
+ if (regcache_set_val(map, lzo_block->dst, blkpos, value)) {
kfree(lzo_block->dst);
goto out;
}
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index e6732cf7c06e..aa0875f6f1b7 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -47,22 +47,21 @@ static inline void regcache_rbtree_get_base_top_reg(
*top = rbnode->base_reg + ((rbnode->blklen - 1) * map->reg_stride);
}
-static unsigned int regcache_rbtree_get_register(
- struct regcache_rbtree_node *rbnode, unsigned int idx,
- unsigned int word_size)
+static unsigned int regcache_rbtree_get_register(struct regmap *map,
+ struct regcache_rbtree_node *rbnode, unsigned int idx)
{
- return regcache_get_val(rbnode->block, idx, word_size);
+ return regcache_get_val(map, rbnode->block, idx);
}
-static void regcache_rbtree_set_register(struct regcache_rbtree_node *rbnode,
- unsigned int idx, unsigned int val,
- unsigned int word_size)
+static void regcache_rbtree_set_register(struct regmap *map,
+ struct regcache_rbtree_node *rbnode,
+ unsigned int idx, unsigned int val)
{
- regcache_set_val(rbnode->block, idx, val, word_size);
+ regcache_set_val(map, rbnode->block, idx, val);
}
static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map,
- unsigned int reg)
+ unsigned int reg)
{
struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
struct rb_node *node;
@@ -139,15 +138,21 @@ static int rbtree_show(struct seq_file *s, void *ignored)
struct regcache_rbtree_node *n;
struct rb_node *node;
unsigned int base, top;
+ size_t mem_size;
int nodes = 0;
int registers = 0;
int this_registers, average;
map->lock(map);
+ mem_size = sizeof(*rbtree_ctx);
+ mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
+
for (node = rb_first(&rbtree_ctx->root); node != NULL;
node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
+ mem_size += sizeof(*n);
+ mem_size += (n->blklen * map->cache_word_size);
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
this_registers = ((top - base) / map->reg_stride) + 1;
@@ -162,8 +167,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
else
average = 0;
- seq_printf(s, "%d nodes, %d registers, average %d registers\n",
- nodes, registers, average);
+ seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n",
+ nodes, registers, average, mem_size);
map->unlock(map);
@@ -260,8 +265,9 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
- *value = regcache_rbtree_get_register(rbnode, reg_tmp,
- map->cache_word_size);
+ if (!regcache_reg_present(map, reg))
+ return -ENOENT;
+ *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
} else {
return -ENOENT;
}
@@ -270,21 +276,23 @@ static int regcache_rbtree_read(struct regmap *map,
}
-static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
+static int regcache_rbtree_insert_to_block(struct regmap *map,
+ struct regcache_rbtree_node *rbnode,
unsigned int pos, unsigned int reg,
- unsigned int value, unsigned int word_size)
+ unsigned int value)
{
u8 *blk;
blk = krealloc(rbnode->block,
- (rbnode->blklen + 1) * word_size, GFP_KERNEL);
+ (rbnode->blklen + 1) * map->cache_word_size,
+ GFP_KERNEL);
if (!blk)
return -ENOMEM;
/* insert the register value in the correct place in the rbnode block */
- memmove(blk + (pos + 1) * word_size,
- blk + pos * word_size,
- (rbnode->blklen - pos) * word_size);
+ memmove(blk + (pos + 1) * map->cache_word_size,
+ blk + pos * map->cache_word_size,
+ (rbnode->blklen - pos) * map->cache_word_size);
/* update the rbnode block, its size and the base register */
rbnode->block = blk;
@@ -292,7 +300,7 @@ static int regcache_rbtree_insert_to_block(struct regcache_rbtree_node *rbnode,
if (!pos)
rbnode->base_reg = reg;
- regcache_rbtree_set_register(rbnode, pos, value, word_size);
+ regcache_rbtree_set_register(map, rbnode, pos, value);
return 0;
}
@@ -302,25 +310,24 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
struct regcache_rbtree_ctx *rbtree_ctx;
struct regcache_rbtree_node *rbnode, *rbnode_tmp;
struct rb_node *node;
- unsigned int val;
unsigned int reg_tmp;
unsigned int pos;
int i;
int ret;
rbtree_ctx = map->cache;
+ /* update the reg_present bitmap, make space if necessary */
+ ret = regcache_set_reg_present(map, reg);
+ if (ret < 0)
+ return ret;
+
/* if we can't locate it in the cached rbnode we'll have
* to traverse the rbtree looking for it.
*/
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
- val = regcache_rbtree_get_register(rbnode, reg_tmp,
- map->cache_word_size);
- if (val == value)
- return 0;
- regcache_rbtree_set_register(rbnode, reg_tmp, value,
- map->cache_word_size);
+ regcache_rbtree_set_register(map, rbnode, reg_tmp, value);
} else {
/* look for an adjacent register to the one we are about to add */
for (node = rb_first(&rbtree_ctx->root); node;
@@ -337,9 +344,10 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
pos = i + 1;
else
pos = i;
- ret = regcache_rbtree_insert_to_block(rbnode_tmp, pos,
- reg, value,
- map->cache_word_size);
+ ret = regcache_rbtree_insert_to_block(map,
+ rbnode_tmp,
+ pos, reg,
+ value);
if (ret)
return ret;
rbtree_ctx->cached_rbnode = rbnode_tmp;
@@ -354,7 +362,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
if (!rbnode)
return -ENOMEM;
- rbnode->blklen = 1;
+ rbnode->blklen = sizeof(*rbnode);
rbnode->base_reg = reg;
rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
GFP_KERNEL);
@@ -362,7 +370,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
kfree(rbnode);
return -ENOMEM;
}
- regcache_rbtree_set_register(rbnode, 0, value, map->cache_word_size);
+ regcache_rbtree_set_register(map, rbnode, 0, value);
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
@@ -376,10 +384,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
struct regcache_rbtree_ctx *rbtree_ctx;
struct rb_node *node;
struct regcache_rbtree_node *rbnode;
- unsigned int regtmp;
- unsigned int val;
int ret;
- int i, base, end;
+ int base, end;
rbtree_ctx = map->cache;
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
@@ -398,31 +404,17 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
base = 0;
if (max < rbnode->base_reg + rbnode->blklen)
- end = rbnode->base_reg + rbnode->blklen - max;
+ end = max - rbnode->base_reg + 1;
else
end = rbnode->blklen;
- for (i = base; i < end; i++) {
- regtmp = rbnode->base_reg + (i * map->reg_stride);
- val = regcache_rbtree_get_register(rbnode, i,
- map->cache_word_size);
-
- /* Is this the hardware default? If so skip. */
- ret = regcache_lookup_reg(map, regtmp);
- if (ret >= 0 && val == map->reg_defaults[ret].def)
- continue;
-
- map->cache_bypass = 1;
- ret = _regmap_write(map, regtmp, val);
- map->cache_bypass = 0;
- if (ret)
- return ret;
- dev_dbg(map->dev, "Synced register %#x, value %#x\n",
- regtmp, val);
- }
+ ret = regcache_sync_block(map, rbnode->block, rbnode->base_reg,
+ base, end);
+ if (ret != 0)
+ return ret;
}
- return 0;
+ return regmap_async_complete(map);
}
struct regcache_ops regcache_rbtree_ops = {
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index e69ff3e4742c..75923f2396bd 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -45,8 +45,8 @@ static int regcache_hw_init(struct regmap *map)
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
if (!tmp_buf)
return -EINVAL;
- ret = regmap_bulk_read(map, 0, tmp_buf,
- map->num_reg_defaults_raw);
+ ret = regmap_raw_read(map, 0, tmp_buf,
+ map->num_reg_defaults_raw);
map->cache_bypass = cache_bypass;
if (ret < 0) {
kfree(tmp_buf);
@@ -58,8 +58,7 @@ static int regcache_hw_init(struct regmap *map)
/* calculate the size of reg_defaults */
for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
- val = regcache_get_val(map->reg_defaults_raw,
- i, map->cache_word_size);
+ val = regcache_get_val(map, map->reg_defaults_raw, i);
if (regmap_volatile(map, i * map->reg_stride))
continue;
count++;
@@ -75,8 +74,7 @@ static int regcache_hw_init(struct regmap *map)
/* fill the reg_defaults */
map->num_reg_defaults = count;
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
- val = regcache_get_val(map->reg_defaults_raw,
- i, map->cache_word_size);
+ val = regcache_get_val(map, map->reg_defaults_raw, i);
if (regmap_volatile(map, i * map->reg_stride))
continue;
map->reg_defaults[j].reg = i * map->reg_stride;
@@ -123,6 +121,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
map->reg_defaults_raw = config->reg_defaults_raw;
map->cache_word_size = DIV_ROUND_UP(config->val_bits, 8);
map->cache_size_raw = map->cache_word_size * config->num_reg_defaults_raw;
+ map->cache_present = NULL;
+ map->cache_present_nbits = 0;
map->cache = NULL;
map->cache_ops = cache_types[i];
@@ -181,6 +181,7 @@ void regcache_exit(struct regmap *map)
BUG_ON(!map->cache_ops);
+ kfree(map->cache_present);
kfree(map->reg_defaults);
if (map->cache_free)
kfree(map->reg_defaults_raw);
@@ -417,28 +418,68 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
-bool regcache_set_val(void *base, unsigned int idx,
- unsigned int val, unsigned int word_size)
+int regcache_set_reg_present(struct regmap *map, unsigned int reg)
{
- switch (word_size) {
+ unsigned long *cache_present;
+ unsigned int cache_present_size;
+ unsigned int nregs;
+ int i;
+
+ nregs = reg + 1;
+ cache_present_size = BITS_TO_LONGS(nregs);
+ cache_present_size *= sizeof(long);
+
+ if (!map->cache_present) {
+ cache_present = kmalloc(cache_present_size, GFP_KERNEL);
+ if (!cache_present)
+ return -ENOMEM;
+ bitmap_zero(cache_present, nregs);
+ map->cache_present = cache_present;
+ map->cache_present_nbits = nregs;
+ }
+
+ if (nregs > map->cache_present_nbits) {
+ cache_present = krealloc(map->cache_present,
+ cache_present_size, GFP_KERNEL);
+ if (!cache_present)
+ return -ENOMEM;
+ for (i = 0; i < nregs; i++)
+ if (i >= map->cache_present_nbits)
+ clear_bit(i, cache_present);
+ map->cache_present = cache_present;
+ map->cache_present_nbits = nregs;
+ }
+
+ set_bit(reg, map->cache_present);
+ return 0;
+}
+
+bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
+ unsigned int val)
+{
+ if (regcache_get_val(map, base, idx) == val)
+ return true;
+
+ /* Use device native format if possible */
+ if (map->format.format_val) {
+ map->format.format_val(base + (map->cache_word_size * idx),
+ val, 0);
+ return false;
+ }
+
+ switch (map->cache_word_size) {
case 1: {
u8 *cache = base;
- if (cache[idx] == val)
- return true;
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
- if (cache[idx] == val)
- return true;
cache[idx] = val;
break;
}
case 4: {
u32 *cache = base;
- if (cache[idx] == val)
- return true;
cache[idx] = val;
break;
}
@@ -448,13 +489,18 @@ bool regcache_set_val(void *base, unsigned int idx,
return false;
}
-unsigned int regcache_get_val(const void *base, unsigned int idx,
- unsigned int word_size)
+unsigned int regcache_get_val(struct regmap *map, const void *base,
+ unsigned int idx)
{
if (!base)
return -EINVAL;
- switch (word_size) {
+ /* Use device native format if possible */
+ if (map->format.parse_val)
+ return map->format.parse_val(regcache_get_val_addr(map, base,
+ idx));
+
+ switch (map->cache_word_size) {
case 1: {
const u8 *cache = base;
return cache[idx];
@@ -498,3 +544,117 @@ int regcache_lookup_reg(struct regmap *map, unsigned int reg)
else
return -ENOENT;
}
+
+static int regcache_sync_block_single(struct regmap *map, void *block,
+ unsigned int block_base,
+ unsigned int start, unsigned int end)
+{
+ unsigned int i, regtmp, val;
+ int ret;
+
+ for (i = start; i < end; i++) {
+ regtmp = block_base + (i * map->reg_stride);
+
+ if (!regcache_reg_present(map, regtmp))
+ continue;
+
+ val = regcache_get_val(map, block, i);
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, regtmp);
+ if (ret >= 0 && val == map->reg_defaults[ret].def)
+ continue;
+
+ map->cache_bypass = 1;
+
+ ret = _regmap_write(map, regtmp, val);
+
+ map->cache_bypass = 0;
+ if (ret != 0)
+ return ret;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n",
+ regtmp, val);
+ }
+
+ return 0;
+}
+
+static int regcache_sync_block_raw_flush(struct regmap *map, const void **data,
+ unsigned int base, unsigned int cur)
+{
+ size_t val_bytes = map->format.val_bytes;
+ int ret, count;
+
+ if (*data == NULL)
+ return 0;
+
+ count = cur - base;
+
+ dev_dbg(map->dev, "Writing %zu bytes for %d registers from 0x%x-0x%x\n",
+ count * val_bytes, count, base, cur - 1);
+
+ map->cache_bypass = 1;
+
+ ret = _regmap_raw_write(map, base, *data, count * val_bytes,
+ false);
+
+ map->cache_bypass = 0;
+
+ *data = NULL;
+
+ return ret;
+}
+
+static int regcache_sync_block_raw(struct regmap *map, void *block,
+ unsigned int block_base, unsigned int start,
+ unsigned int end)
+{
+ unsigned int i, val;
+ unsigned int regtmp = 0;
+ unsigned int base = 0;
+ const void *data = NULL;
+ int ret;
+
+ for (i = start; i < end; i++) {
+ regtmp = block_base + (i * map->reg_stride);
+
+ if (!regcache_reg_present(map, regtmp)) {
+ ret = regcache_sync_block_raw_flush(map, &data,
+ base, regtmp);
+ if (ret != 0)
+ return ret;
+ continue;
+ }
+
+ val = regcache_get_val(map, block, i);
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, regtmp);
+ if (ret >= 0 && val == map->reg_defaults[ret].def) {
+ ret = regcache_sync_block_raw_flush(map, &data,
+ base, regtmp);
+ if (ret != 0)
+ return ret;
+ continue;
+ }
+
+ if (!data) {
+ data = regcache_get_val_addr(map, block, i);
+ base = regtmp;
+ }
+ }
+
+ return regcache_sync_block_raw_flush(map, &data, base, regtmp);
+}
+
+int regcache_sync_block(struct regmap *map, void *block,
+ unsigned int block_base, unsigned int start,
+ unsigned int end)
+{
+ if (regmap_can_raw_write(map))
+ return regcache_sync_block_raw(map, block, block_base,
+ start, end);
+ else
+ return regcache_sync_block_single(map, block, block_base,
+ start, end);
+}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 81d6f605c92e..23b701f5fd2f 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,16 +88,16 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
* If we don't have a cache build one so we don't have to do a
* linear scan each time.
*/
+ mutex_lock(&map->cache_lock);
+ i = base;
if (list_empty(&map->debugfs_off_cache)) {
- for (i = base; i <= map->max_register; i += map->reg_stride) {
+ for (; i <= map->max_register; i += map->reg_stride) {
/* Skip unprinted registers, closing off cache entry */
if (!regmap_readable(map, i) ||
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
- fpos_offset = c->max - c->min;
- reg_offset = fpos_offset / map->debugfs_tot_len;
- c->max_reg = c->base_reg + reg_offset;
+ c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
&map->debugfs_off_cache);
c = NULL;
@@ -111,6 +111,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
regmap_debugfs_free_dump_cache(map);
+ mutex_unlock(&map->cache_lock);
return base;
}
c->min = p;
@@ -124,9 +125,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
- fpos_offset = c->max - c->min;
- reg_offset = fpos_offset / map->debugfs_tot_len;
- c->max_reg = c->base_reg + reg_offset;
+ c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
&map->debugfs_off_cache);
}
@@ -145,12 +144,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
fpos_offset = from - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len);
+ mutex_unlock(&map->cache_lock);
return c->base_reg + reg_offset;
}
*pos = c->max;
ret = c->max_reg;
}
+ mutex_unlock(&map->cache_lock);
return ret;
}
@@ -311,6 +312,79 @@ static const struct file_operations regmap_range_fops = {
.llseek = default_llseek,
};
+static ssize_t regmap_reg_ranges_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ struct regmap *map = file->private_data;
+ struct regmap_debugfs_off_cache *c;
+ loff_t p = 0;
+ size_t buf_pos = 0;
+ char *buf;
+ char *entry;
+ int ret;
+
+ if (*ppos < 0 || !count)
+ return -EINVAL;
+
+ buf = kmalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ entry = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!entry) {
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ /* While we are at it, build the register dump cache
+ * now so the read() operation on the `registers' file
+ * can benefit from using the cache. We do not care
+ * about the file position information that is contained
+ * in the cache, just about the actual register blocks */
+ regmap_calc_tot_len(map, buf, count);
+ regmap_debugfs_get_dump_start(map, 0, *ppos, &p);
+
+ /* Reset file pointer as the fixed-format of the `registers'
+ * file is not compatible with the `range' file */
+ p = 0;
+ mutex_lock(&map->cache_lock);
+ list_for_each_entry(c, &map->debugfs_off_cache, list) {
+ snprintf(entry, PAGE_SIZE, "%x-%x",
+ c->base_reg, c->max_reg);
+ if (p >= *ppos) {
+ if (buf_pos + 1 + strlen(entry) > count)
+ break;
+ snprintf(buf + buf_pos, count - buf_pos,
+ "%s", entry);
+ buf_pos += strlen(entry);
+ buf[buf_pos] = '\n';
+ buf_pos++;
+ }
+ p += strlen(entry) + 1;
+ }
+ mutex_unlock(&map->cache_lock);
+
+ kfree(entry);
+ ret = buf_pos;
+
+ if (copy_to_user(user_buf, buf, buf_pos)) {
+ ret = -EFAULT;
+ goto out_buf;
+ }
+
+ *ppos += buf_pos;
+out_buf:
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations regmap_reg_ranges_fops = {
+ .open = simple_open,
+ .read = regmap_reg_ranges_read_file,
+ .llseek = default_llseek,
+};
+
static ssize_t regmap_access_read_file(struct file *file,
char __user *user_buf, size_t count,
loff_t *ppos)
@@ -385,6 +459,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
struct regmap_range_node *range_node;
INIT_LIST_HEAD(&map->debugfs_off_cache);
+ mutex_init(&map->cache_lock);
if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
@@ -403,6 +478,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_file("name", 0400, map->debugfs,
map, &regmap_name_fops);
+ debugfs_create_file("range", 0400, map->debugfs,
+ map, &regmap_reg_ranges_fops);
+
if (map->max_register) {
debugfs_create_file("registers", 0400, map->debugfs,
map, &regmap_map_fops);
@@ -435,7 +513,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
void regmap_debugfs_exit(struct regmap *map)
{
debugfs_remove_recursive(map->debugfs);
+ mutex_lock(&map->cache_lock);
regmap_debugfs_free_dump_cache(map);
+ mutex_unlock(&map->cache_lock);
kfree(map->debugfs_name);
}
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 020ea2b9fd2f..1643e889bafc 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -460,7 +460,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
chip->name, d);
if (ret != 0) {
- dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
+ dev_err(map->dev, "Failed to request IRQ %d for %s: %d\n",
+ irq, chip->name, ret);
goto err_domain;
}
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 3d2367501fd0..a941dcfe7590 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -228,30 +228,39 @@ static void regmap_format_32_native(void *buf, unsigned int val,
*(u32 *)buf = val << shift;
}
-static unsigned int regmap_parse_8(void *buf)
+static void regmap_parse_inplace_noop(void *buf)
{
- u8 *b = buf;
+}
+
+static unsigned int regmap_parse_8(const void *buf)
+{
+ const u8 *b = buf;
return b[0];
}
-static unsigned int regmap_parse_16_be(void *buf)
+static unsigned int regmap_parse_16_be(const void *buf)
+{
+ const __be16 *b = buf;
+
+ return be16_to_cpu(b[0]);
+}
+
+static void regmap_parse_16_be_inplace(void *buf)
{
__be16 *b = buf;
b[0] = be16_to_cpu(b[0]);
-
- return b[0];
}
-static unsigned int regmap_parse_16_native(void *buf)
+static unsigned int regmap_parse_16_native(const void *buf)
{
return *(u16 *)buf;
}
-static unsigned int regmap_parse_24(void *buf)
+static unsigned int regmap_parse_24(const void *buf)
{
- u8 *b = buf;
+ const u8 *b = buf;
unsigned int ret = b[2];
ret |= ((unsigned int)b[1]) << 8;
ret |= ((unsigned int)b[0]) << 16;
@@ -259,16 +268,21 @@ static unsigned int regmap_parse_24(void *buf)
return ret;
}
-static unsigned int regmap_parse_32_be(void *buf)
+static unsigned int regmap_parse_32_be(const void *buf)
+{
+ const __be32 *b = buf;
+
+ return be32_to_cpu(b[0]);
+}
+
+static void regmap_parse_32_be_inplace(void *buf)
{
__be32 *b = buf;
b[0] = be32_to_cpu(b[0]);
-
- return b[0];
}
-static unsigned int regmap_parse_32_native(void *buf)
+static unsigned int regmap_parse_32_native(const void *buf)
{
return *(u32 *)buf;
}
@@ -555,16 +569,21 @@ struct regmap *regmap_init(struct device *dev,
goto err_map;
}
+ if (val_endian == REGMAP_ENDIAN_NATIVE)
+ map->format.parse_inplace = regmap_parse_inplace_noop;
+
switch (config->val_bits) {
case 8:
map->format.format_val = regmap_format_8;
map->format.parse_val = regmap_parse_8;
+ map->format.parse_inplace = regmap_parse_inplace_noop;
break;
case 16:
switch (val_endian) {
case REGMAP_ENDIAN_BIG:
map->format.format_val = regmap_format_16_be;
map->format.parse_val = regmap_parse_16_be;
+ map->format.parse_inplace = regmap_parse_16_be_inplace;
break;
case REGMAP_ENDIAN_NATIVE:
map->format.format_val = regmap_format_16_native;
@@ -585,6 +604,7 @@ struct regmap *regmap_init(struct device *dev,
case REGMAP_ENDIAN_BIG:
map->format.format_val = regmap_format_32_be;
map->format.parse_val = regmap_parse_32_be;
+ map->format.parse_inplace = regmap_parse_32_be_inplace;
break;
case REGMAP_ENDIAN_NATIVE:
map->format.format_val = regmap_format_32_native;
@@ -710,12 +730,12 @@ skip_format_initialization:
}
}
+ regmap_debugfs_init(map, config->name);
+
ret = regcache_init(map, config);
if (ret != 0)
goto err_range;
- regmap_debugfs_init(map, config->name);
-
/* Add a devres resource for dev_get_regmap() */
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
if (!m) {
@@ -917,8 +937,8 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
return 0;
}
-static int _regmap_raw_write(struct regmap *map, unsigned int reg,
- const void *val, size_t val_len, bool async)
+int _regmap_raw_write(struct regmap *map, unsigned int reg,
+ const void *val, size_t val_len, bool async)
{
struct regmap_range_node *range;
unsigned long flags;
@@ -930,7 +950,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
size_t len;
int i;
- BUG_ON(!map->bus);
+ WARN_ON(!map->bus);
/* Check for unwritable registers before we start */
if (map->writeable_reg)
@@ -943,8 +963,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
unsigned int ival;
int val_bytes = map->format.val_bytes;
for (i = 0; i < val_len / val_bytes; i++) {
- memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
- ival = map->format.parse_val(map->work_buf);
+ ival = map->format.parse_val(val + (i * val_bytes));
ret = regcache_write(map, reg + (i * map->reg_stride),
ival);
if (ret) {
@@ -999,6 +1018,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
if (!async)
return -ENOMEM;
+ trace_regmap_async_write_start(map->dev, reg, val_len);
+
async->work_buf = kzalloc(map->format.buf_size,
GFP_KERNEL | GFP_DMA);
if (!async->work_buf) {
@@ -1036,6 +1057,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
kfree(async->work_buf);
kfree(async);
}
+
+ return ret;
}
trace_regmap_hw_write_start(map->dev, reg,
@@ -1077,6 +1100,17 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
return ret;
}
+/**
+ * regmap_can_raw_write - Test if regmap_raw_write() is supported
+ *
+ * @map: Map to check.
+ */
+bool regmap_can_raw_write(struct regmap *map)
+{
+ return map->bus && map->format.format_val && map->format.format_reg;
+}
+EXPORT_SYMBOL_GPL(regmap_can_raw_write);
+
static int _regmap_bus_formatted_write(void *context, unsigned int reg,
unsigned int val)
{
@@ -1084,7 +1118,7 @@ static int _regmap_bus_formatted_write(void *context, unsigned int reg,
struct regmap_range_node *range;
struct regmap *map = context;
- BUG_ON(!map->bus || !map->format.format_write);
+ WARN_ON(!map->bus || !map->format.format_write);
range = _regmap_range_lookup(map, reg);
if (range) {
@@ -1110,7 +1144,7 @@ static int _regmap_bus_raw_write(void *context, unsigned int reg,
{
struct regmap *map = context;
- BUG_ON(!map->bus || !map->format.format_val);
+ WARN_ON(!map->bus || !map->format.format_val);
map->format.format_val(map->work_buf + map->format.reg_bytes
+ map->format.pad_bytes, val, 0);
@@ -1200,12 +1234,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
{
int ret;
- if (!map->bus)
+ if (!regmap_can_raw_write(map))
return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
- if (reg % map->reg_stride)
- return -EINVAL;
map->lock(map->lock_arg);
@@ -1240,7 +1272,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (!map->bus)
return -EINVAL;
- if (!map->format.parse_val)
+ if (!map->format.parse_inplace)
return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
@@ -1258,7 +1290,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
goto out;
}
for (i = 0; i < val_count * val_bytes; i += val_bytes)
- map->format.parse_val(wval + i);
+ map->format.parse_inplace(wval + i);
}
/*
* Some devices does not support bulk write, for
@@ -1336,7 +1368,7 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
u8 *u8 = map->work_buf;
int ret;
- BUG_ON(!map->bus);
+ WARN_ON(!map->bus);
range = _regmap_range_lookup(map, reg);
if (range) {
@@ -1391,7 +1423,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
int ret;
void *context = _regmap_map_get_context(map);
- BUG_ON(!map->reg_read);
+ WARN_ON(!map->reg_read);
if (!map->cache_bypass) {
ret = regcache_read(map, reg, val);
@@ -1519,7 +1551,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
if (!map->bus)
return -EINVAL;
- if (!map->format.parse_val)
+ if (!map->format.parse_inplace)
return -EINVAL;
if (reg % map->reg_stride)
return -EINVAL;
@@ -1546,7 +1578,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
}
for (i = 0; i < val_count * val_bytes; i += val_bytes)
- map->format.parse_val(val + i);
+ map->format.parse_inplace(val + i);
} else {
for (i = 0; i < val_count; i++) {
unsigned int ival;
@@ -1640,6 +1672,8 @@ void regmap_async_complete_cb(struct regmap_async *async, int ret)
struct regmap *map = async->map;
bool wake;
+ trace_regmap_async_io_complete(map->dev);
+
spin_lock(&map->async_lock);
list_del(&async->list);
@@ -1686,6 +1720,8 @@ int regmap_async_complete(struct regmap *map)
if (!map->bus->async_write)
return 0;
+ trace_regmap_async_complete_start(map->dev);
+
wait_event(map->async_waitq, regmap_async_is_done(map));
spin_lock_irqsave(&map->async_lock, flags);
@@ -1693,6 +1729,8 @@ int regmap_async_complete(struct regmap *map)
map->async_ret = 0;
spin_unlock_irqrestore(&map->async_lock, flags);
+ trace_regmap_async_complete_done(map->dev);
+
return ret;
}
EXPORT_SYMBOL_GPL(regmap_async_complete);
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
index 03bbe104338f..17b26ce7e051 100644
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -104,7 +104,13 @@ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
if (i)
bcma_err(core->bus, "PLL enable timeout\n");
} else {
- bcma_warn(core->bus, "Disabling PLL not supported yet!\n");
+ /*
+ * Mask the PLL but don't wait for it to be disabled. PLL may be
+ * shared between cores and will be still up if there is another
+ * core using it.
+ */
+ bcma_mask32(core, BCMA_CLKCTLST, ~req);
+ bcma_read32(core, BCMA_CLKCTLST);
}
}
EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 28fa50ad87be..036c6744b39b 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -25,13 +25,14 @@ static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
return value;
}
-static u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
+u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
{
if (cc->capabilities & BCMA_CC_CAP_PMU)
return bcma_pmu_get_alp_clock(cc);
return 20000000;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_get_alp_clock);
static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
{
@@ -213,6 +214,7 @@ u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
return res;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
{
@@ -225,6 +227,7 @@ u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
return res;
}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
/*
* If the bit is set to 0, chipcommon controlls this GPIO,
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index 932b101dee36..edca73af3cc0 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -174,19 +174,35 @@ u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc)
struct bcma_bus *bus = cc->core->bus;
switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM4313:
+ case BCMA_CHIP_ID_BCM43224:
+ case BCMA_CHIP_ID_BCM43225:
+ case BCMA_CHIP_ID_BCM43227:
+ case BCMA_CHIP_ID_BCM43228:
+ case BCMA_CHIP_ID_BCM4331:
+ case BCMA_CHIP_ID_BCM43421:
+ case BCMA_CHIP_ID_BCM43428:
+ case BCMA_CHIP_ID_BCM43431:
case BCMA_CHIP_ID_BCM4716:
- case BCMA_CHIP_ID_BCM4748:
case BCMA_CHIP_ID_BCM47162:
- case BCMA_CHIP_ID_BCM4313:
- case BCMA_CHIP_ID_BCM5357:
+ case BCMA_CHIP_ID_BCM4748:
case BCMA_CHIP_ID_BCM4749:
+ case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
+ case BCMA_CHIP_ID_BCM6362:
/* always 20Mhz */
return 20000 * 1000;
- case BCMA_CHIP_ID_BCM5356:
case BCMA_CHIP_ID_BCM4706:
+ case BCMA_CHIP_ID_BCM5356:
/* always 25Mhz */
return 25000 * 1000;
+ case BCMA_CHIP_ID_BCM43460:
+ case BCMA_CHIP_ID_BCM4352:
+ case BCMA_CHIP_ID_BCM4360:
+ if (cc->status & BCMA_CC_CHIPST_4360_XTAL_40MZ)
+ return 40000 * 1000;
+ else
+ return 20000 * 1000;
default:
bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
@@ -373,7 +389,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM4331:
@@ -394,7 +410,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
0x03000a08);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM43224:
@@ -427,7 +443,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
0x88888815);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
case BCMA_CHIP_ID_BCM4716:
@@ -461,7 +477,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
0x88888815);
}
- tmp = 3 << 9;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW;
break;
case BCMA_CHIP_ID_BCM43227:
@@ -497,7 +513,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
0x88888815);
}
- tmp = 1 << 10;
+ tmp = BCMA_CC_PMU_CTL_PLL_UPD;
break;
default:
bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 9a6188add590..f72f52b4b1dd 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -120,6 +120,11 @@ static int bcma_register_cores(struct bcma_bus *bus)
continue;
}
+ /* Only first GMAC core on BCM4706 is connected and working */
+ if (core->id.id == BCMA_CORE_4706_MAC_GBIT &&
+ core->core_unit > 0)
+ continue;
+
core->dev.release = bcma_release_core_dev;
core->dev.bus = &bcma_bus_type;
dev_set_name(&core->dev, "bcma%d:%d", bus->num, dev_id);
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 8d0b57164018..bca9c80056fe 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -137,19 +137,19 @@ static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
addr);
}
-static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
+static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = readl(*eromptr);
(*eromptr)++;
return ent;
}
-static void bcma_erom_push_ent(u32 **eromptr)
+static void bcma_erom_push_ent(u32 __iomem **eromptr)
{
(*eromptr)--;
}
-static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
+static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
if (!(ent & SCAN_ER_VALID))
@@ -159,14 +159,14 @@ static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
return ent;
}
-static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
+static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
bcma_erom_push_ent(eromptr);
return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
}
-static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
+static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
bcma_erom_push_ent(eromptr);
@@ -175,7 +175,7 @@ static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
}
-static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
+static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent;
while (1) {
@@ -189,7 +189,7 @@ static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
bcma_erom_push_ent(eromptr);
}
-static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
+static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
{
u32 ent = bcma_erom_get_ent(bus, eromptr);
if (!(ent & SCAN_ER_VALID))
@@ -199,7 +199,7 @@ static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
return ent;
}
-static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
+static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
u32 type, u8 port)
{
u32 addrl, addrh, sizel, sizeh = 0;
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 4adf9ef9a113..8934298a638d 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -217,6 +217,7 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
}
SPEX(board_rev, SSB_SPROM8_BOARDREV, ~0, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, ~0, 0);
SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01, SSB_SPROM4_TXPID2G0,
SSB_SPROM4_TXPID2G0_SHIFT);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 5dc0daed8fac..b81ddfea1da0 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -532,11 +532,11 @@ config BLK_DEV_RBD
If unsure, say N.
config BLK_DEV_RSXX
- tristate "RamSam PCIe Flash SSD Device Driver"
+ tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver"
depends on PCI
help
Device driver for IBM's high speed PCIe SSD
- storage devices: RamSan-70 and RamSan-80.
+ storage devices: FlashSystem-70 and FlashSystem-80.
To compile this driver as a module, choose M here: the
module will be called rsxx.
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 42e67ad6bd20..ab41be625a53 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -139,13 +139,12 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags);
return;
}
- mp = kmalloc(n, GFP_ATOMIC);
+ mp = kmemdup(msg, n, GFP_ATOMIC);
if (mp == NULL) {
printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n);
goto bail;
}
- memcpy(mp, msg, n);
em->msg = mp;
em->flags |= EMFL_VALID;
em->len = n;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 25ef5c014fca..92b6d7c51e39 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -51,8 +51,9 @@ new_skb(ulong len)
{
struct sk_buff *skb;
- skb = alloc_skb(len, GFP_ATOMIC);
+ skb = alloc_skb(len + MAX_HEADER, GFP_ATOMIC);
if (skb) {
+ skb_reserve(skb, MAX_HEADER);
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb->protocol = __constant_htons(ETH_P_AOE);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index d150fe1248bf..e18c99140c0a 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -4206,7 +4206,7 @@ static int cciss_find_cfgtables(ctlr_info_t *h)
if (rc)
return rc;
h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
- cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable));
+ cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
if (!h->cfgtable)
return -ENOMEM;
rc = write_driver_ver_to_cfgtable(h->cfgtable);
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index a9eccfc6079b..83c5ae0ed56b 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -757,7 +757,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_tconn *tconn, struct acc
rcu_read_unlock();
timeo = connect_int * HZ;
- timeo += (random32() & 1) ? timeo / 7 : -timeo / 7; /* 28.5% random jitter */
+ /* 28.5% random jitter */
+ timeo += (prandom_u32() & 1) ? timeo / 7 : -timeo / 7;
err = wait_for_completion_interruptible_timeout(&ad->door_bell, timeo);
if (err <= 0)
@@ -953,7 +954,7 @@ retry:
conn_warn(tconn, "Error receiving initial packet\n");
sock_release(s);
randomize:
- if (random32() & 1)
+ if (prandom_u32() & 1)
goto retry;
}
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index cd1e17460f03..b2955b3f2cbc 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -924,6 +924,11 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
lo->lo_flags |= LO_FLAGS_PARTSCAN;
if (lo->lo_flags & LO_FLAGS_PARTSCAN)
ioctl_by_bdev(bdev, BLKRRPART, 0);
+
+ /* Grab the block_device to prevent its destruction after we
+ * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev).
+ */
+ bdgrab(bdev);
return 0;
out_clr:
@@ -1033,8 +1038,10 @@ static int loop_clr_fd(struct loop_device *lo)
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
- if (bdev)
+ if (bdev) {
+ bdput(bdev);
invalidate_bdev(bdev);
+ }
set_capacity(lo->lo_disk, 0);
loop_sysfs_exit(lo);
if (bdev) {
@@ -1625,6 +1632,7 @@ static int loop_add(struct loop_device **l, int i)
goto out_free_dev;
i = err;
+ err = -ENOMEM;
lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
if (!lo->lo_queue)
goto out_free_dev;
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c
index 1788f491e0fb..076ae7f1b781 100644
--- a/drivers/block/mg_disk.c
+++ b/drivers/block/mg_disk.c
@@ -890,8 +890,10 @@ static int mg_probe(struct platform_device *plat_dev)
gpio_direction_output(host->rst, 1);
/* reset out pin */
- if (!(prv_data->dev_attr & MG_DEV_MASK))
+ if (!(prv_data->dev_attr & MG_DEV_MASK)) {
+ err = -EINVAL;
goto probe_err_3a;
+ }
if (prv_data->dev_attr != MG_BOOT_DEV) {
rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO,
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 11cc9522cdd4..32c678028e53 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -81,12 +81,17 @@
/* Device instance number, incremented each time a device is probed. */
static int instance;
+struct list_head online_list;
+struct list_head removing_list;
+spinlock_t dev_lock;
+
/*
* Global variable used to hold the major block device number
* allocated in mtip_init().
*/
static int mtip_major;
static struct dentry *dfs_parent;
+static struct dentry *dfs_device_status;
static u32 cpu_use[NR_CPUS];
@@ -243,40 +248,31 @@ static inline void release_slot(struct mtip_port *port, int tag)
/*
* Reset the HBA (without sleeping)
*
- * Just like hba_reset, except does not call sleep, so can be
- * run from interrupt/tasklet context.
- *
* @dd Pointer to the driver data structure.
*
* return value
* 0 The reset was successful.
* -1 The HBA Reset bit did not clear.
*/
-static int hba_reset_nosleep(struct driver_data *dd)
+static int mtip_hba_reset(struct driver_data *dd)
{
unsigned long timeout;
- /* Chip quirk: quiesce any chip function */
- mdelay(10);
-
/* Set the reset bit */
writel(HOST_RESET, dd->mmio + HOST_CTL);
/* Flush */
readl(dd->mmio + HOST_CTL);
- /*
- * Wait 10ms then spin for up to 1 second
- * waiting for reset acknowledgement
- */
- timeout = jiffies + msecs_to_jiffies(1000);
- mdelay(10);
- while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
- && time_before(jiffies, timeout))
- mdelay(1);
+ /* Spin for up to 2 seconds, waiting for reset acknowledgement */
+ timeout = jiffies + msecs_to_jiffies(2000);
+ do {
+ mdelay(10);
+ if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
+ return -1;
- if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))
- return -1;
+ } while ((readl(dd->mmio + HOST_CTL) & HOST_RESET)
+ && time_before(jiffies, timeout));
if (readl(dd->mmio + HOST_CTL) & HOST_RESET)
return -1;
@@ -481,7 +477,7 @@ static void mtip_restart_port(struct mtip_port *port)
dev_warn(&port->dd->pdev->dev,
"PxCMD.CR not clear, escalating reset\n");
- if (hba_reset_nosleep(port->dd))
+ if (mtip_hba_reset(port->dd))
dev_err(&port->dd->pdev->dev,
"HBA reset escalation failed.\n");
@@ -527,6 +523,26 @@ static void mtip_restart_port(struct mtip_port *port)
}
+static int mtip_device_reset(struct driver_data *dd)
+{
+ int rv = 0;
+
+ if (mtip_check_surprise_removal(dd->pdev))
+ return 0;
+
+ if (mtip_hba_reset(dd) < 0)
+ rv = -EFAULT;
+
+ mdelay(1);
+ mtip_init_port(dd->port);
+ mtip_start_port(dd->port);
+
+ /* Enable interrupts on the HBA. */
+ writel(readl(dd->mmio + HOST_CTL) | HOST_IRQ_EN,
+ dd->mmio + HOST_CTL);
+ return rv;
+}
+
/*
* Helper function for tag logging
*/
@@ -632,7 +648,7 @@ static void mtip_timeout_function(unsigned long int data)
if (cmdto_cnt) {
print_tags(port->dd, "timed out", tagaccum, cmdto_cnt);
if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) {
- mtip_restart_port(port);
+ mtip_device_reset(port->dd);
wake_up_interruptible(&port->svc_wait);
}
clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags);
@@ -1283,11 +1299,11 @@ static int mtip_exec_internal_command(struct mtip_port *port,
int rv = 0, ready2go = 1;
struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL];
unsigned long to;
+ struct driver_data *dd = port->dd;
/* Make sure the buffer is 8 byte aligned. This is asic specific. */
if (buffer & 0x00000007) {
- dev_err(&port->dd->pdev->dev,
- "SG buffer is not 8 byte aligned\n");
+ dev_err(&dd->pdev->dev, "SG buffer is not 8 byte aligned\n");
return -EFAULT;
}
@@ -1300,23 +1316,21 @@ static int mtip_exec_internal_command(struct mtip_port *port,
mdelay(100);
} while (time_before(jiffies, to));
if (!ready2go) {
- dev_warn(&port->dd->pdev->dev,
+ dev_warn(&dd->pdev->dev,
"Internal cmd active. new cmd [%02X]\n", fis->command);
return -EBUSY;
}
set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
port->ic_pause_timer = 0;
- if (fis->command == ATA_CMD_SEC_ERASE_UNIT)
- clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
- else if (fis->command == ATA_CMD_DOWNLOAD_MICRO)
- clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
+ clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags);
+ clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags);
if (atomic == GFP_KERNEL) {
if (fis->command != ATA_CMD_STANDBYNOW1) {
/* wait for io to complete if non atomic */
if (mtip_quiesce_io(port, 5000) < 0) {
- dev_warn(&port->dd->pdev->dev,
+ dev_warn(&dd->pdev->dev,
"Failed to quiesce IO\n");
release_slot(port, MTIP_TAG_INTERNAL);
clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags);
@@ -1361,58 +1375,84 @@ static int mtip_exec_internal_command(struct mtip_port *port,
/* Issue the command to the hardware */
mtip_issue_non_ncq_command(port, MTIP_TAG_INTERNAL);
- /* Poll if atomic, wait_for_completion otherwise */
if (atomic == GFP_KERNEL) {
/* Wait for the command to complete or timeout. */
- if (wait_for_completion_timeout(
+ if (wait_for_completion_interruptible_timeout(
&wait,
- msecs_to_jiffies(timeout)) == 0) {
- dev_err(&port->dd->pdev->dev,
- "Internal command did not complete [%d] "
- "within timeout of %lu ms\n",
- atomic, timeout);
- if (mtip_check_surprise_removal(port->dd->pdev) ||
+ msecs_to_jiffies(timeout)) <= 0) {
+ if (rv == -ERESTARTSYS) { /* interrupted */
+ dev_err(&dd->pdev->dev,
+ "Internal command [%02X] was interrupted after %lu ms\n",
+ fis->command, timeout);
+ rv = -EINTR;
+ goto exec_ic_exit;
+ } else if (rv == 0) /* timeout */
+ dev_err(&dd->pdev->dev,
+ "Internal command did not complete [%02X] within timeout of %lu ms\n",
+ fis->command, timeout);
+ else
+ dev_err(&dd->pdev->dev,
+ "Internal command [%02X] wait returned code [%d] after %lu ms - unhandled\n",
+ fis->command, rv, timeout);
+
+ if (mtip_check_surprise_removal(dd->pdev) ||
test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
- &port->dd->dd_flag)) {
+ &dd->dd_flag)) {
+ dev_err(&dd->pdev->dev,
+ "Internal command [%02X] wait returned due to SR\n",
+ fis->command);
rv = -ENXIO;
goto exec_ic_exit;
}
+ mtip_device_reset(dd); /* recover from timeout issue */
rv = -EAGAIN;
+ goto exec_ic_exit;
}
} else {
+ u32 hba_stat, port_stat;
+
/* Spin for <timeout> checking if command still outstanding */
timeout = jiffies + msecs_to_jiffies(timeout);
while ((readl(port->cmd_issue[MTIP_TAG_INTERNAL])
& (1 << MTIP_TAG_INTERNAL))
&& time_before(jiffies, timeout)) {
- if (mtip_check_surprise_removal(port->dd->pdev)) {
+ if (mtip_check_surprise_removal(dd->pdev)) {
rv = -ENXIO;
goto exec_ic_exit;
}
if ((fis->command != ATA_CMD_STANDBYNOW1) &&
test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
- &port->dd->dd_flag)) {
+ &dd->dd_flag)) {
rv = -ENXIO;
goto exec_ic_exit;
}
- if (readl(port->mmio + PORT_IRQ_STAT) & PORT_IRQ_ERR) {
- atomic_inc(&int_cmd->active); /* error */
- break;
+ port_stat = readl(port->mmio + PORT_IRQ_STAT);
+ if (!port_stat)
+ continue;
+
+ if (port_stat & PORT_IRQ_ERR) {
+ dev_err(&dd->pdev->dev,
+ "Internal command [%02X] failed\n",
+ fis->command);
+ mtip_device_reset(dd);
+ rv = -EIO;
+ goto exec_ic_exit;
+ } else {
+ writel(port_stat, port->mmio + PORT_IRQ_STAT);
+ hba_stat = readl(dd->mmio + HOST_IRQ_STAT);
+ if (hba_stat)
+ writel(hba_stat,
+ dd->mmio + HOST_IRQ_STAT);
}
+ break;
}
}
- if (atomic_read(&int_cmd->active) > 1) {
- dev_err(&port->dd->pdev->dev,
- "Internal command [%02X] failed\n", fis->command);
- rv = -EIO;
- }
if (readl(port->cmd_issue[MTIP_TAG_INTERNAL])
& (1 << MTIP_TAG_INTERNAL)) {
rv = -ENXIO;
- if (!test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
- &port->dd->dd_flag)) {
- mtip_restart_port(port);
+ if (!test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) {
+ mtip_device_reset(dd);
rv = -EAGAIN;
}
}
@@ -1724,7 +1764,8 @@ static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id,
* -EINVAL Invalid parameters passed in, trim not supported
* -EIO Error submitting trim request to hw
*/
-static int mtip_send_trim(struct driver_data *dd, unsigned int lba, unsigned int len)
+static int mtip_send_trim(struct driver_data *dd, unsigned int lba,
+ unsigned int len)
{
int i, rv = 0;
u64 tlba, tlen, sect_left;
@@ -1811,45 +1852,6 @@ static bool mtip_hw_get_capacity(struct driver_data *dd, sector_t *sectors)
}
/*
- * Reset the HBA.
- *
- * Resets the HBA by setting the HBA Reset bit in the Global
- * HBA Control register. After setting the HBA Reset bit the
- * function waits for 1 second before reading the HBA Reset
- * bit to make sure it has cleared. If HBA Reset is not clear
- * an error is returned. Cannot be used in non-blockable
- * context.
- *
- * @dd Pointer to the driver data structure.
- *
- * return value
- * 0 The reset was successful.
- * -1 The HBA Reset bit did not clear.
- */
-static int mtip_hba_reset(struct driver_data *dd)
-{
- mtip_deinit_port(dd->port);
-
- /* Set the reset bit */
- writel(HOST_RESET, dd->mmio + HOST_CTL);
-
- /* Flush */
- readl(dd->mmio + HOST_CTL);
-
- /* Wait for reset to clear */
- ssleep(1);
-
- /* Check the bit has cleared */
- if (readl(dd->mmio + HOST_CTL) & HOST_RESET) {
- dev_err(&dd->pdev->dev,
- "Reset bit did not clear.\n");
- return -1;
- }
-
- return 0;
-}
-
-/*
* Display the identify command data.
*
* @port Pointer to the port data structure.
@@ -2710,6 +2712,100 @@ static ssize_t mtip_hw_show_status(struct device *dev,
static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL);
+/* debugsfs entries */
+
+static ssize_t show_device_status(struct device_driver *drv, char *buf)
+{
+ int size = 0;
+ struct driver_data *dd, *tmp;
+ unsigned long flags;
+ char id_buf[42];
+ u16 status = 0;
+
+ spin_lock_irqsave(&dev_lock, flags);
+ size += sprintf(&buf[size], "Devices Present:\n");
+ list_for_each_entry_safe(dd, tmp, &online_list, online_list) {
+ if (dd->pdev) {
+ if (dd->port &&
+ dd->port->identify &&
+ dd->port->identify_valid) {
+ strlcpy(id_buf,
+ (char *) (dd->port->identify + 10), 21);
+ status = *(dd->port->identify + 141);
+ } else {
+ memset(id_buf, 0, 42);
+ status = 0;
+ }
+
+ if (dd->port &&
+ test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
+ size += sprintf(&buf[size],
+ " device %s %s (ftl rebuild %d %%)\n",
+ dev_name(&dd->pdev->dev),
+ id_buf,
+ status);
+ } else {
+ size += sprintf(&buf[size],
+ " device %s %s\n",
+ dev_name(&dd->pdev->dev),
+ id_buf);
+ }
+ }
+ }
+
+ size += sprintf(&buf[size], "Devices Being Removed:\n");
+ list_for_each_entry_safe(dd, tmp, &removing_list, remove_list) {
+ if (dd->pdev) {
+ if (dd->port &&
+ dd->port->identify &&
+ dd->port->identify_valid) {
+ strlcpy(id_buf,
+ (char *) (dd->port->identify+10), 21);
+ status = *(dd->port->identify + 141);
+ } else {
+ memset(id_buf, 0, 42);
+ status = 0;
+ }
+
+ if (dd->port &&
+ test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) {
+ size += sprintf(&buf[size],
+ " device %s %s (ftl rebuild %d %%)\n",
+ dev_name(&dd->pdev->dev),
+ id_buf,
+ status);
+ } else {
+ size += sprintf(&buf[size],
+ " device %s %s\n",
+ dev_name(&dd->pdev->dev),
+ id_buf);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&dev_lock, flags);
+
+ return size;
+}
+
+static ssize_t mtip_hw_read_device_status(struct file *f, char __user *ubuf,
+ size_t len, loff_t *offset)
+{
+ int size = *offset;
+ char buf[MTIP_DFS_MAX_BUF_SIZE];
+
+ if (!len || *offset)
+ return 0;
+
+ size += show_device_status(NULL, buf);
+
+ *offset = size <= len ? size : len;
+ size = copy_to_user(ubuf, buf, *offset);
+ if (size)
+ return -EFAULT;
+
+ return *offset;
+}
+
static ssize_t mtip_hw_read_registers(struct file *f, char __user *ubuf,
size_t len, loff_t *offset)
{
@@ -2804,6 +2900,13 @@ static ssize_t mtip_hw_read_flags(struct file *f, char __user *ubuf,
return *offset;
}
+static const struct file_operations mtip_device_status_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = mtip_hw_read_device_status,
+ .llseek = no_llseek,
+};
+
static const struct file_operations mtip_regs_fops = {
.owner = THIS_MODULE,
.open = simple_open,
@@ -4161,6 +4264,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
const struct cpumask *node_mask;
int cpu, i = 0, j = 0;
int my_node = NUMA_NO_NODE;
+ unsigned long flags;
/* Allocate memory for this devices private data. */
my_node = pcibus_to_node(pdev->bus);
@@ -4218,12 +4322,16 @@ static int mtip_pci_probe(struct pci_dev *pdev,
dd->pdev = pdev;
dd->numa_node = my_node;
+ INIT_LIST_HEAD(&dd->online_list);
+ INIT_LIST_HEAD(&dd->remove_list);
+
memset(dd->workq_name, 0, 32);
snprintf(dd->workq_name, 31, "mtipq%d", dd->instance);
dd->isr_workq = create_workqueue(dd->workq_name);
if (!dd->isr_workq) {
dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance);
+ rv = -ENOMEM;
goto block_initialize_err;
}
@@ -4282,7 +4390,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
INIT_WORK(&dd->work[7].work, mtip_workq_sdbf7);
pci_set_master(pdev);
- if (pci_enable_msi(pdev)) {
+ rv = pci_enable_msi(pdev);
+ if (rv) {
dev_warn(&pdev->dev,
"Unable to enable MSI interrupt.\n");
goto block_initialize_err;
@@ -4303,6 +4412,14 @@ static int mtip_pci_probe(struct pci_dev *pdev,
instance++;
if (rv != MTIP_FTL_REBUILD_MAGIC)
set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag);
+ else
+ rv = 0; /* device in rebuild state, return 0 from probe */
+
+ /* Add to online list even if in ftl rebuild */
+ spin_lock_irqsave(&dev_lock, flags);
+ list_add(&dd->online_list, &online_list);
+ spin_unlock_irqrestore(&dev_lock, flags);
+
goto done;
block_initialize_err:
@@ -4336,9 +4453,15 @@ static void mtip_pci_remove(struct pci_dev *pdev)
{
struct driver_data *dd = pci_get_drvdata(pdev);
int counter = 0;
+ unsigned long flags;
set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag);
+ spin_lock_irqsave(&dev_lock, flags);
+ list_del_init(&dd->online_list);
+ list_add(&dd->remove_list, &removing_list);
+ spin_unlock_irqrestore(&dev_lock, flags);
+
if (mtip_check_surprise_removal(pdev)) {
while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) {
counter++;
@@ -4364,6 +4487,10 @@ static void mtip_pci_remove(struct pci_dev *pdev)
pci_disable_msi(pdev);
+ spin_lock_irqsave(&dev_lock, flags);
+ list_del_init(&dd->remove_list);
+ spin_unlock_irqrestore(&dev_lock, flags);
+
kfree(dd);
pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
}
@@ -4511,6 +4638,11 @@ static int __init mtip_init(void)
pr_info(MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n");
+ spin_lock_init(&dev_lock);
+
+ INIT_LIST_HEAD(&online_list);
+ INIT_LIST_HEAD(&removing_list);
+
/* Allocate a major block device number to use with this driver. */
error = register_blkdev(0, MTIP_DRV_NAME);
if (error <= 0) {
@@ -4520,11 +4652,18 @@ static int __init mtip_init(void)
}
mtip_major = error;
- if (!dfs_parent) {
- dfs_parent = debugfs_create_dir("rssd", NULL);
- if (IS_ERR_OR_NULL(dfs_parent)) {
- pr_warn("Error creating debugfs parent\n");
- dfs_parent = NULL;
+ dfs_parent = debugfs_create_dir("rssd", NULL);
+ if (IS_ERR_OR_NULL(dfs_parent)) {
+ pr_warn("Error creating debugfs parent\n");
+ dfs_parent = NULL;
+ }
+ if (dfs_parent) {
+ dfs_device_status = debugfs_create_file("device_status",
+ S_IRUGO, dfs_parent, NULL,
+ &mtip_device_status_fops);
+ if (IS_ERR_OR_NULL(dfs_device_status)) {
+ pr_err("Error creating device_status node\n");
+ dfs_device_status = NULL;
}
}
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index 3bffff5f670c..8e8334c9dd0f 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -129,9 +129,9 @@ enum {
MTIP_PF_EH_ACTIVE_BIT = 1, /* error handling */
MTIP_PF_SE_ACTIVE_BIT = 2, /* secure erase */
MTIP_PF_DM_ACTIVE_BIT = 3, /* download microcde */
- MTIP_PF_PAUSE_IO = ((1 << MTIP_PF_IC_ACTIVE_BIT) | \
- (1 << MTIP_PF_EH_ACTIVE_BIT) | \
- (1 << MTIP_PF_SE_ACTIVE_BIT) | \
+ MTIP_PF_PAUSE_IO = ((1 << MTIP_PF_IC_ACTIVE_BIT) |
+ (1 << MTIP_PF_EH_ACTIVE_BIT) |
+ (1 << MTIP_PF_SE_ACTIVE_BIT) |
(1 << MTIP_PF_DM_ACTIVE_BIT)),
MTIP_PF_SVC_THD_ACTIVE_BIT = 4,
@@ -144,9 +144,9 @@ enum {
MTIP_DDF_REMOVE_PENDING_BIT = 1,
MTIP_DDF_OVER_TEMP_BIT = 2,
MTIP_DDF_WRITE_PROTECT_BIT = 3,
- MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \
- (1 << MTIP_DDF_SEC_LOCK_BIT) | \
- (1 << MTIP_DDF_OVER_TEMP_BIT) | \
+ MTIP_DDF_STOP_IO = ((1 << MTIP_DDF_REMOVE_PENDING_BIT) |
+ (1 << MTIP_DDF_SEC_LOCK_BIT) |
+ (1 << MTIP_DDF_OVER_TEMP_BIT) |
(1 << MTIP_DDF_WRITE_PROTECT_BIT)),
MTIP_DDF_CLEANUP_BIT = 5,
@@ -180,7 +180,7 @@ struct mtip_work {
#define MTIP_TRIM_TIMEOUT_MS 240000
#define MTIP_MAX_TRIM_ENTRIES 8
-#define MTIP_MAX_TRIM_ENTRY_LEN 0xfff8
+#define MTIP_MAX_TRIM_ENTRY_LEN 0xfff8
struct mtip_trim_entry {
u32 lba; /* starting lba of region */
@@ -501,6 +501,10 @@ struct driver_data {
atomic_t irq_workers_active;
int isr_binding;
+
+ struct list_head online_list; /* linkage for online list */
+
+ struct list_head remove_list; /* linkage for removing list */
};
#endif
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 7fecc784be01..037288e7874d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -856,6 +856,8 @@ static int __init nbd_init(void)
disk->queue->limits.discard_granularity = 512;
disk->queue->limits.max_discard_sectors = UINT_MAX;
disk->queue->limits.discard_zeroes_data = 0;
+ blk_queue_max_hw_sectors(disk->queue, 65536);
+ disk->queue->limits.max_sectors = 256;
}
if (register_blkdev(NBD_MAJOR, "nbd")) {
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 6c81a4c040b9..b7b7a88d9f68 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1264,6 +1264,32 @@ static bool obj_request_done_test(struct rbd_obj_request *obj_request)
return atomic_read(&obj_request->done) != 0;
}
+static void
+rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
+{
+ dout("%s: obj %p img %p result %d %llu/%llu\n", __func__,
+ obj_request, obj_request->img_request, obj_request->result,
+ obj_request->xferred, obj_request->length);
+ /*
+ * ENOENT means a hole in the image. We zero-fill the
+ * entire length of the request. A short read also implies
+ * zero-fill to the end of the request. Either way we
+ * update the xferred count to indicate the whole request
+ * was satisfied.
+ */
+ BUG_ON(obj_request->type != OBJ_REQUEST_BIO);
+ if (obj_request->result == -ENOENT) {
+ zero_bio_chain(obj_request->bio_list, 0);
+ obj_request->result = 0;
+ obj_request->xferred = obj_request->length;
+ } else if (obj_request->xferred < obj_request->length &&
+ !obj_request->result) {
+ zero_bio_chain(obj_request->bio_list, obj_request->xferred);
+ obj_request->xferred = obj_request->length;
+ }
+ obj_request_done_set(obj_request);
+}
+
static void rbd_obj_request_complete(struct rbd_obj_request *obj_request)
{
dout("%s: obj %p cb %p\n", __func__, obj_request,
@@ -1284,23 +1310,10 @@ static void rbd_osd_read_callback(struct rbd_obj_request *obj_request)
{
dout("%s: obj %p result %d %llu/%llu\n", __func__, obj_request,
obj_request->result, obj_request->xferred, obj_request->length);
- /*
- * ENOENT means a hole in the object. We zero-fill the
- * entire length of the request. A short read also implies
- * zero-fill to the end of the request. Either way we
- * update the xferred count to indicate the whole request
- * was satisfied.
- */
- if (obj_request->result == -ENOENT) {
- zero_bio_chain(obj_request->bio_list, 0);
- obj_request->result = 0;
- obj_request->xferred = obj_request->length;
- } else if (obj_request->xferred < obj_request->length &&
- !obj_request->result) {
- zero_bio_chain(obj_request->bio_list, obj_request->xferred);
- obj_request->xferred = obj_request->length;
- }
- obj_request_done_set(obj_request);
+ if (obj_request->img_request)
+ rbd_img_obj_request_read_callback(obj_request);
+ else
+ obj_request_done_set(obj_request);
}
static void rbd_osd_write_callback(struct rbd_obj_request *obj_request)
@@ -1729,9 +1742,10 @@ static int rbd_img_request_submit(struct rbd_img_request *img_request)
struct rbd_device *rbd_dev = img_request->rbd_dev;
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct rbd_obj_request *obj_request;
+ struct rbd_obj_request *next_obj_request;
dout("%s: img %p\n", __func__, img_request);
- for_each_obj_request(img_request, obj_request) {
+ for_each_obj_request_safe(img_request, obj_request, next_obj_request) {
int ret;
obj_request->callback = rbd_img_obj_callback;
diff --git a/drivers/block/rsxx/Makefile b/drivers/block/rsxx/Makefile
index f35cd0b71f7b..b1c53c0aa450 100644
--- a/drivers/block/rsxx/Makefile
+++ b/drivers/block/rsxx/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_BLK_DEV_RSXX) += rsxx.o
-rsxx-y := config.o core.o cregs.o dev.o dma.o
+rsxx-objs := config.o core.o cregs.o dev.o dma.o
diff --git a/drivers/block/rsxx/config.c b/drivers/block/rsxx/config.c
index a295e7e9ee41..10cd530d3e10 100644
--- a/drivers/block/rsxx/config.c
+++ b/drivers/block/rsxx/config.c
@@ -29,15 +29,13 @@
#include "rsxx_priv.h"
#include "rsxx_cfg.h"
-static void initialize_config(void *config)
+static void initialize_config(struct rsxx_card_cfg *cfg)
{
- struct rsxx_card_cfg *cfg = config;
-
cfg->hdr.version = RSXX_CFG_VERSION;
cfg->data.block_size = RSXX_HW_BLK_SIZE;
cfg->data.stripe_size = RSXX_HW_BLK_SIZE;
- cfg->data.vendor_id = RSXX_VENDOR_ID_TMS_IBM;
+ cfg->data.vendor_id = RSXX_VENDOR_ID_IBM;
cfg->data.cache_order = (-1);
cfg->data.intr_coal.mode = RSXX_INTR_COAL_DISABLED;
cfg->data.intr_coal.count = 0;
@@ -181,7 +179,7 @@ int rsxx_load_config(struct rsxx_cardinfo *card)
} else {
dev_info(CARD_TO_DEV(card),
"Initializing card configuration.\n");
- initialize_config(card);
+ initialize_config(&card->config);
st = rsxx_save_config(card);
if (st)
return st;
diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
index e5162487686a..5af21f2db29c 100644
--- a/drivers/block/rsxx/core.c
+++ b/drivers/block/rsxx/core.c
@@ -30,6 +30,7 @@
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/genhd.h>
#include <linux/idr.h>
@@ -39,8 +40,8 @@
#define NO_LEGACY 0
-MODULE_DESCRIPTION("IBM RamSan PCIe Flash SSD Device Driver");
-MODULE_AUTHOR("IBM <support@ramsan.com>");
+MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver");
+MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
@@ -52,6 +53,13 @@ static DEFINE_IDA(rsxx_disk_ida);
static DEFINE_SPINLOCK(rsxx_ida_lock);
/*----------------- Interrupt Control & Handling -------------------*/
+
+static void rsxx_mask_interrupts(struct rsxx_cardinfo *card)
+{
+ card->isr_mask = 0;
+ card->ier_mask = 0;
+}
+
static void __enable_intr(unsigned int *mask, unsigned int intr)
{
*mask |= intr;
@@ -71,7 +79,8 @@ static void __disable_intr(unsigned int *mask, unsigned int intr)
*/
void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr)
{
- if (unlikely(card->halt))
+ if (unlikely(card->halt) ||
+ unlikely(card->eeh_state))
return;
__enable_intr(&card->ier_mask, intr);
@@ -80,6 +89,9 @@ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr)
void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr)
{
+ if (unlikely(card->eeh_state))
+ return;
+
__disable_intr(&card->ier_mask, intr);
iowrite32(card->ier_mask, card->regmap + IER);
}
@@ -87,7 +99,8 @@ void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr)
void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card,
unsigned int intr)
{
- if (unlikely(card->halt))
+ if (unlikely(card->halt) ||
+ unlikely(card->eeh_state))
return;
__enable_intr(&card->isr_mask, intr);
@@ -97,6 +110,9 @@ void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card,
void rsxx_disable_ier_and_isr(struct rsxx_cardinfo *card,
unsigned int intr)
{
+ if (unlikely(card->eeh_state))
+ return;
+
__disable_intr(&card->isr_mask, intr);
__disable_intr(&card->ier_mask, intr);
iowrite32(card->ier_mask, card->regmap + IER);
@@ -115,6 +131,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
do {
reread_isr = 0;
+ if (unlikely(card->eeh_state))
+ break;
+
isr = ioread32(card->regmap + ISR);
if (isr == 0xffffffff) {
/*
@@ -161,9 +180,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
}
/*----------------- Card Event Handler -------------------*/
-static char *rsxx_card_state_to_str(unsigned int state)
+static const char * const rsxx_card_state_to_str(unsigned int state)
{
- static char *state_strings[] = {
+ static const char * const state_strings[] = {
"Unknown", "Shutdown", "Starting", "Formatting",
"Uninitialized", "Good", "Shutting Down",
"Fault", "Read Only Fault", "dStroying"
@@ -304,6 +323,192 @@ static int card_shutdown(struct rsxx_cardinfo *card)
return 0;
}
+static int rsxx_eeh_frozen(struct pci_dev *dev)
+{
+ struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+ int i;
+ int st;
+
+ dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n");
+
+ card->eeh_state = 1;
+ rsxx_mask_interrupts(card);
+
+ /*
+ * We need to guarantee that the write for eeh_state and masking
+ * interrupts does not become reordered. This will prevent a possible
+ * race condition with the EEH code.
+ */
+ wmb();
+
+ pci_disable_device(dev);
+
+ st = rsxx_eeh_save_issued_dmas(card);
+ if (st)
+ return st;
+
+ rsxx_eeh_save_issued_creg(card);
+
+ for (i = 0; i < card->n_targets; i++) {
+ if (card->ctrl[i].status.buf)
+ pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8,
+ card->ctrl[i].status.buf,
+ card->ctrl[i].status.dma_addr);
+ if (card->ctrl[i].cmd.buf)
+ pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8,
+ card->ctrl[i].cmd.buf,
+ card->ctrl[i].cmd.dma_addr);
+ }
+
+ return 0;
+}
+
+static void rsxx_eeh_failure(struct pci_dev *dev)
+{
+ struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+ int i;
+
+ dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n");
+
+ card->eeh_state = 1;
+
+ for (i = 0; i < card->n_targets; i++)
+ del_timer_sync(&card->ctrl[i].activity_timer);
+
+ rsxx_eeh_cancel_dmas(card);
+}
+
+static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card)
+{
+ unsigned int status;
+ int iter = 0;
+
+ /* We need to wait for the hardware to reset */
+ while (iter++ < 10) {
+ status = ioread32(card->regmap + PCI_RECONFIG);
+
+ if (status & RSXX_FLUSH_BUSY) {
+ ssleep(1);
+ continue;
+ }
+
+ if (status & RSXX_FLUSH_TIMEOUT)
+ dev_warn(CARD_TO_DEV(card), "HW: flash controller timeout\n");
+ return 0;
+ }
+
+ /* Hardware failed resetting itself. */
+ return -1;
+}
+
+static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error)
+{
+ int st;
+
+ if (dev->revision < RSXX_EEH_SUPPORT)
+ return PCI_ERS_RESULT_NONE;
+
+ if (error == pci_channel_io_perm_failure) {
+ rsxx_eeh_failure(dev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ st = rsxx_eeh_frozen(dev);
+ if (st) {
+ dev_err(&dev->dev, "Slot reset setup failed\n");
+ rsxx_eeh_failure(dev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
+{
+ struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+ unsigned long flags;
+ int i;
+ int st;
+
+ dev_warn(&dev->dev,
+ "IBM FlashSystem PCI: recovering from slot reset.\n");
+
+ st = pci_enable_device(dev);
+ if (st)
+ goto failed_hw_setup;
+
+ pci_set_master(dev);
+
+ st = rsxx_eeh_fifo_flush_poll(card);
+ if (st)
+ goto failed_hw_setup;
+
+ rsxx_dma_queue_reset(card);
+
+ for (i = 0; i < card->n_targets; i++) {
+ st = rsxx_hw_buffers_init(dev, &card->ctrl[i]);
+ if (st)
+ goto failed_hw_buffers_init;
+ }
+
+ if (card->config_valid)
+ rsxx_dma_configure(card);
+
+ /* Clears the ISR register from spurious interrupts */
+ st = ioread32(card->regmap + ISR);
+
+ card->eeh_state = 0;
+
+ st = rsxx_eeh_remap_dmas(card);
+ if (st)
+ goto failed_remap_dmas;
+
+ spin_lock_irqsave(&card->irq_lock, flags);
+ if (card->n_targets & RSXX_MAX_TARGETS)
+ rsxx_enable_ier_and_isr(card, CR_INTR_ALL_G);
+ else
+ rsxx_enable_ier_and_isr(card, CR_INTR_ALL_C);
+ spin_unlock_irqrestore(&card->irq_lock, flags);
+
+ rsxx_kick_creg_queue(card);
+
+ for (i = 0; i < card->n_targets; i++) {
+ spin_lock(&card->ctrl[i].queue_lock);
+ if (list_empty(&card->ctrl[i].queue)) {
+ spin_unlock(&card->ctrl[i].queue_lock);
+ continue;
+ }
+ spin_unlock(&card->ctrl[i].queue_lock);
+
+ queue_work(card->ctrl[i].issue_wq,
+ &card->ctrl[i].issue_dma_work);
+ }
+
+ dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n");
+
+ return PCI_ERS_RESULT_RECOVERED;
+
+failed_hw_buffers_init:
+failed_remap_dmas:
+ for (i = 0; i < card->n_targets; i++) {
+ if (card->ctrl[i].status.buf)
+ pci_free_consistent(card->dev,
+ STATUS_BUFFER_SIZE8,
+ card->ctrl[i].status.buf,
+ card->ctrl[i].status.dma_addr);
+ if (card->ctrl[i].cmd.buf)
+ pci_free_consistent(card->dev,
+ COMMAND_BUFFER_SIZE8,
+ card->ctrl[i].cmd.buf,
+ card->ctrl[i].cmd.dma_addr);
+ }
+failed_hw_setup:
+ rsxx_eeh_failure(dev);
+ return PCI_ERS_RESULT_DISCONNECT;
+
+}
+
/*----------------- Driver Initialization & Setup -------------------*/
/* Returns: 0 if the driver is compatible with the device
-1 if the driver is NOT compatible with the device */
@@ -383,6 +588,7 @@ static int rsxx_pci_probe(struct pci_dev *dev,
spin_lock_init(&card->irq_lock);
card->halt = 0;
+ card->eeh_state = 0;
spin_lock_irq(&card->irq_lock);
rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
@@ -538,9 +744,6 @@ static void rsxx_pci_remove(struct pci_dev *dev)
rsxx_disable_ier_and_isr(card, CR_INTR_EVENT);
spin_unlock_irqrestore(&card->irq_lock, flags);
- /* Prevent work_structs from re-queuing themselves. */
- card->halt = 1;
-
cancel_work_sync(&card->event_work);
rsxx_destroy_dev(card);
@@ -549,6 +752,10 @@ static void rsxx_pci_remove(struct pci_dev *dev)
spin_lock_irqsave(&card->irq_lock, flags);
rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
spin_unlock_irqrestore(&card->irq_lock, flags);
+
+ /* Prevent work_structs from re-queuing themselves. */
+ card->halt = 1;
+
free_irq(dev->irq, card);
if (!force_legacy)
@@ -592,11 +799,14 @@ static void rsxx_pci_shutdown(struct pci_dev *dev)
card_shutdown(card);
}
+static const struct pci_error_handlers rsxx_err_handler = {
+ .error_detected = rsxx_error_detected,
+ .slot_reset = rsxx_slot_reset,
+};
+
static DEFINE_PCI_DEVICE_TABLE(rsxx_pci_ids) = {
- {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70_FLASH)},
- {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70D_FLASH)},
- {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS80_FLASH)},
- {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS81_FLASH)},
+ {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS70_FLASH)},
+ {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS80_FLASH)},
{0,},
};
@@ -609,6 +819,7 @@ static struct pci_driver rsxx_pci_driver = {
.remove = rsxx_pci_remove,
.suspend = rsxx_pci_suspend,
.shutdown = rsxx_pci_shutdown,
+ .err_handler = &rsxx_err_handler,
};
static int __init rsxx_core_init(void)
diff --git a/drivers/block/rsxx/cregs.c b/drivers/block/rsxx/cregs.c
index 80bbe639fccd..4b5c020a0a65 100644
--- a/drivers/block/rsxx/cregs.c
+++ b/drivers/block/rsxx/cregs.c
@@ -58,7 +58,7 @@ static struct kmem_cache *creg_cmd_pool;
#error Unknown endianess!!! Aborting...
#endif
-static void copy_to_creg_data(struct rsxx_cardinfo *card,
+static int copy_to_creg_data(struct rsxx_cardinfo *card,
int cnt8,
void *buf,
unsigned int stream)
@@ -66,6 +66,9 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card,
int i = 0;
u32 *data = buf;
+ if (unlikely(card->eeh_state))
+ return -EIO;
+
for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
/*
* Firmware implementation makes it necessary to byte swap on
@@ -76,10 +79,12 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card,
else
iowrite32(data[i], card->regmap + CREG_DATA(i));
}
+
+ return 0;
}
-static void copy_from_creg_data(struct rsxx_cardinfo *card,
+static int copy_from_creg_data(struct rsxx_cardinfo *card,
int cnt8,
void *buf,
unsigned int stream)
@@ -87,6 +92,9 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card,
int i = 0;
u32 *data = buf;
+ if (unlikely(card->eeh_state))
+ return -EIO;
+
for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
/*
* Firmware implementation makes it necessary to byte swap on
@@ -97,41 +105,31 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card,
else
data[i] = ioread32(card->regmap + CREG_DATA(i));
}
-}
-
-static struct creg_cmd *pop_active_cmd(struct rsxx_cardinfo *card)
-{
- struct creg_cmd *cmd;
- /*
- * Spin lock is needed because this can be called in atomic/interrupt
- * context.
- */
- spin_lock_bh(&card->creg_ctrl.lock);
- cmd = card->creg_ctrl.active_cmd;
- card->creg_ctrl.active_cmd = NULL;
- spin_unlock_bh(&card->creg_ctrl.lock);
-
- return cmd;
+ return 0;
}
static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd)
{
+ int st;
+
+ if (unlikely(card->eeh_state))
+ return;
+
iowrite32(cmd->addr, card->regmap + CREG_ADD);
iowrite32(cmd->cnt8, card->regmap + CREG_CNT);
if (cmd->op == CREG_OP_WRITE) {
- if (cmd->buf)
- copy_to_creg_data(card, cmd->cnt8,
- cmd->buf, cmd->stream);
+ if (cmd->buf) {
+ st = copy_to_creg_data(card, cmd->cnt8,
+ cmd->buf, cmd->stream);
+ if (st)
+ return;
+ }
}
- /*
- * Data copy must complete before initiating the command. This is
- * needed for weakly ordered processors (i.e. PowerPC), so that all
- * neccessary registers are written before we kick the hardware.
- */
- wmb();
+ if (unlikely(card->eeh_state))
+ return;
/* Setting the valid bit will kick off the command. */
iowrite32(cmd->op, card->regmap + CREG_CMD);
@@ -196,11 +194,11 @@ static int creg_queue_cmd(struct rsxx_cardinfo *card,
cmd->cb_private = cb_private;
cmd->status = 0;
- spin_lock(&card->creg_ctrl.lock);
+ spin_lock_bh(&card->creg_ctrl.lock);
list_add_tail(&cmd->list, &card->creg_ctrl.queue);
card->creg_ctrl.q_depth++;
creg_kick_queue(card);
- spin_unlock(&card->creg_ctrl.lock);
+ spin_unlock_bh(&card->creg_ctrl.lock);
return 0;
}
@@ -210,7 +208,11 @@ static void creg_cmd_timed_out(unsigned long data)
struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data;
struct creg_cmd *cmd;
- cmd = pop_active_cmd(card);
+ spin_lock(&card->creg_ctrl.lock);
+ cmd = card->creg_ctrl.active_cmd;
+ card->creg_ctrl.active_cmd = NULL;
+ spin_unlock(&card->creg_ctrl.lock);
+
if (cmd == NULL) {
card->creg_ctrl.creg_stats.creg_timeout++;
dev_warn(CARD_TO_DEV(card),
@@ -247,7 +249,11 @@ static void creg_cmd_done(struct work_struct *work)
if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0)
card->creg_ctrl.creg_stats.failed_cancel_timer++;
- cmd = pop_active_cmd(card);
+ spin_lock_bh(&card->creg_ctrl.lock);
+ cmd = card->creg_ctrl.active_cmd;
+ card->creg_ctrl.active_cmd = NULL;
+ spin_unlock_bh(&card->creg_ctrl.lock);
+
if (cmd == NULL) {
dev_err(CARD_TO_DEV(card),
"Spurious creg interrupt!\n");
@@ -287,7 +293,7 @@ static void creg_cmd_done(struct work_struct *work)
goto creg_done;
}
- copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream);
+ st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream);
}
creg_done:
@@ -296,10 +302,10 @@ creg_done:
kmem_cache_free(creg_cmd_pool, cmd);
- spin_lock(&card->creg_ctrl.lock);
+ spin_lock_bh(&card->creg_ctrl.lock);
card->creg_ctrl.active = 0;
creg_kick_queue(card);
- spin_unlock(&card->creg_ctrl.lock);
+ spin_unlock_bh(&card->creg_ctrl.lock);
}
static void creg_reset(struct rsxx_cardinfo *card)
@@ -324,7 +330,7 @@ static void creg_reset(struct rsxx_cardinfo *card)
"Resetting creg interface for recovery\n");
/* Cancel outstanding commands */
- spin_lock(&card->creg_ctrl.lock);
+ spin_lock_bh(&card->creg_ctrl.lock);
list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
list_del(&cmd->list);
card->creg_ctrl.q_depth--;
@@ -345,7 +351,7 @@ static void creg_reset(struct rsxx_cardinfo *card)
card->creg_ctrl.active = 0;
}
- spin_unlock(&card->creg_ctrl.lock);
+ spin_unlock_bh(&card->creg_ctrl.lock);
card->creg_ctrl.reset = 0;
spin_lock_irqsave(&card->irq_lock, flags);
@@ -399,12 +405,12 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card,
return st;
/*
- * This timeout is neccessary for unresponsive hardware. The additional
+ * This timeout is necessary for unresponsive hardware. The additional
* 20 seconds to used to guarantee that each cregs requests has time to
* complete.
*/
- timeout = msecs_to_jiffies((CREG_TIMEOUT_MSEC *
- card->creg_ctrl.q_depth) + 20000);
+ timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC *
+ card->creg_ctrl.q_depth + 20000);
/*
* The creg interface is guaranteed to complete. It has a timeout
@@ -690,6 +696,32 @@ int rsxx_reg_access(struct rsxx_cardinfo *card,
return 0;
}
+void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card)
+{
+ struct creg_cmd *cmd = NULL;
+
+ cmd = card->creg_ctrl.active_cmd;
+ card->creg_ctrl.active_cmd = NULL;
+
+ if (cmd) {
+ del_timer_sync(&card->creg_ctrl.cmd_timer);
+
+ spin_lock_bh(&card->creg_ctrl.lock);
+ list_add(&cmd->list, &card->creg_ctrl.queue);
+ card->creg_ctrl.q_depth++;
+ card->creg_ctrl.active = 0;
+ spin_unlock_bh(&card->creg_ctrl.lock);
+ }
+}
+
+void rsxx_kick_creg_queue(struct rsxx_cardinfo *card)
+{
+ spin_lock_bh(&card->creg_ctrl.lock);
+ if (!list_empty(&card->creg_ctrl.queue))
+ creg_kick_queue(card);
+ spin_unlock_bh(&card->creg_ctrl.lock);
+}
+
/*------------ Initialization & Setup --------------*/
int rsxx_creg_setup(struct rsxx_cardinfo *card)
{
@@ -712,7 +744,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card)
int cnt = 0;
/* Cancel outstanding commands */
- spin_lock(&card->creg_ctrl.lock);
+ spin_lock_bh(&card->creg_ctrl.lock);
list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
list_del(&cmd->list);
if (cmd->cb)
@@ -737,7 +769,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card)
"Canceled active creg command\n");
kmem_cache_free(creg_cmd_pool, cmd);
}
- spin_unlock(&card->creg_ctrl.lock);
+ spin_unlock_bh(&card->creg_ctrl.lock);
cancel_work_sync(&card->creg_ctrl.done_work);
}
diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c
index 63176e67662f..0607513cfb41 100644
--- a/drivers/block/rsxx/dma.c
+++ b/drivers/block/rsxx/dma.c
@@ -28,7 +28,7 @@
struct rsxx_dma {
struct list_head list;
u8 cmd;
- unsigned int laddr; /* Logical address on the ramsan */
+ unsigned int laddr; /* Logical address */
struct {
u32 off;
u32 cnt;
@@ -81,9 +81,6 @@ enum rsxx_hw_status {
HW_STATUS_FAULT = 0x08,
};
-#define STATUS_BUFFER_SIZE8 4096
-#define COMMAND_BUFFER_SIZE8 4096
-
static struct kmem_cache *rsxx_dma_pool;
struct dma_tracker {
@@ -122,7 +119,7 @@ static unsigned int rsxx_get_dma_tgt(struct rsxx_cardinfo *card, u64 addr8)
return tgt;
}
-static void rsxx_dma_queue_reset(struct rsxx_cardinfo *card)
+void rsxx_dma_queue_reset(struct rsxx_cardinfo *card)
{
/* Reset all DMA Command/Status Queues */
iowrite32(DMA_QUEUE_RESET, card->regmap + RESET);
@@ -210,7 +207,8 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card)
u32 q_depth = 0;
u32 intr_coal;
- if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE)
+ if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE ||
+ unlikely(card->eeh_state))
return;
for (i = 0; i < card->n_targets; i++)
@@ -223,31 +221,26 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card)
}
/*----------------- RSXX DMA Handling -------------------*/
-static void rsxx_complete_dma(struct rsxx_cardinfo *card,
+static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl,
struct rsxx_dma *dma,
unsigned int status)
{
if (status & DMA_SW_ERR)
- printk_ratelimited(KERN_ERR
- "SW Error in DMA(cmd x%02x, laddr x%08x)\n",
- dma->cmd, dma->laddr);
+ ctrl->stats.dma_sw_err++;
if (status & DMA_HW_FAULT)
- printk_ratelimited(KERN_ERR
- "HW Fault in DMA(cmd x%02x, laddr x%08x)\n",
- dma->cmd, dma->laddr);
+ ctrl->stats.dma_hw_fault++;
if (status & DMA_CANCELLED)
- printk_ratelimited(KERN_ERR
- "DMA Cancelled(cmd x%02x, laddr x%08x)\n",
- dma->cmd, dma->laddr);
+ ctrl->stats.dma_cancelled++;
if (dma->dma_addr)
- pci_unmap_page(card->dev, dma->dma_addr, get_dma_size(dma),
+ pci_unmap_page(ctrl->card->dev, dma->dma_addr,
+ get_dma_size(dma),
dma->cmd == HW_CMD_BLK_WRITE ?
PCI_DMA_TODEVICE :
PCI_DMA_FROMDEVICE);
if (dma->cb)
- dma->cb(card, dma->cb_data, status ? 1 : 0);
+ dma->cb(ctrl->card, dma->cb_data, status ? 1 : 0);
kmem_cache_free(rsxx_dma_pool, dma);
}
@@ -330,14 +323,15 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
if (requeue_cmd)
rsxx_requeue_dma(ctrl, dma);
else
- rsxx_complete_dma(ctrl->card, dma, status);
+ rsxx_complete_dma(ctrl, dma, status);
}
static void dma_engine_stalled(unsigned long data)
{
struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data;
- if (atomic_read(&ctrl->stats.hw_q_depth) == 0)
+ if (atomic_read(&ctrl->stats.hw_q_depth) == 0 ||
+ unlikely(ctrl->card->eeh_state))
return;
if (ctrl->cmd.idx != ioread32(ctrl->regmap + SW_CMD_IDX)) {
@@ -369,7 +363,8 @@ static void rsxx_issue_dmas(struct work_struct *work)
ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
hw_cmd_buf = ctrl->cmd.buf;
- if (unlikely(ctrl->card->halt))
+ if (unlikely(ctrl->card->halt) ||
+ unlikely(ctrl->card->eeh_state))
return;
while (1) {
@@ -397,7 +392,7 @@ static void rsxx_issue_dmas(struct work_struct *work)
*/
if (unlikely(ctrl->card->dma_fault)) {
push_tracker(ctrl->trackers, tag);
- rsxx_complete_dma(ctrl->card, dma, DMA_CANCELLED);
+ rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
continue;
}
@@ -432,19 +427,15 @@ static void rsxx_issue_dmas(struct work_struct *work)
/* Let HW know we've queued commands. */
if (cmds_pending) {
- /*
- * We must guarantee that the CPU writes to 'ctrl->cmd.buf'
- * (which is in PCI-consistent system-memory) from the loop
- * above make it into the coherency domain before the
- * following PIO "trigger" updating the cmd.idx. A WMB is
- * sufficient. We need not explicitly CPU cache-flush since
- * the memory is a PCI-consistent (ie; coherent) mapping.
- */
- wmb();
-
atomic_add(cmds_pending, &ctrl->stats.hw_q_depth);
mod_timer(&ctrl->activity_timer,
jiffies + DMA_ACTIVITY_TIMEOUT);
+
+ if (unlikely(ctrl->card->eeh_state)) {
+ del_timer_sync(&ctrl->activity_timer);
+ return;
+ }
+
iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
}
}
@@ -463,7 +454,8 @@ static void rsxx_dma_done(struct work_struct *work)
hw_st_buf = ctrl->status.buf;
if (unlikely(ctrl->card->halt) ||
- unlikely(ctrl->card->dma_fault))
+ unlikely(ctrl->card->dma_fault) ||
+ unlikely(ctrl->card->eeh_state))
return;
count = le16_to_cpu(hw_st_buf[ctrl->status.idx].count);
@@ -508,7 +500,7 @@ static void rsxx_dma_done(struct work_struct *work)
if (status)
rsxx_handle_dma_error(ctrl, dma, status);
else
- rsxx_complete_dma(ctrl->card, dma, 0);
+ rsxx_complete_dma(ctrl, dma, 0);
push_tracker(ctrl->trackers, tag);
@@ -727,20 +719,54 @@ bvec_err:
/*----------------- DMA Engine Initialization & Setup -------------------*/
+int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl)
+{
+ ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8,
+ &ctrl->status.dma_addr);
+ ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8,
+ &ctrl->cmd.dma_addr);
+ if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL)
+ return -ENOMEM;
+
+ memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8);
+ iowrite32(lower_32_bits(ctrl->status.dma_addr),
+ ctrl->regmap + SB_ADD_LO);
+ iowrite32(upper_32_bits(ctrl->status.dma_addr),
+ ctrl->regmap + SB_ADD_HI);
+
+ memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8);
+ iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO);
+ iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI);
+
+ ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT);
+ if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) {
+ dev_crit(&dev->dev, "Failed reading status cnt x%x\n",
+ ctrl->status.idx);
+ return -EINVAL;
+ }
+ iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT);
+ iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT);
+
+ ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX);
+ if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) {
+ dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n",
+ ctrl->status.idx);
+ return -EINVAL;
+ }
+ iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX);
+ iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
+
+ return 0;
+}
+
static int rsxx_dma_ctrl_init(struct pci_dev *dev,
struct rsxx_dma_ctrl *ctrl)
{
int i;
+ int st;
memset(&ctrl->stats, 0, sizeof(ctrl->stats));
- ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8,
- &ctrl->status.dma_addr);
- ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8,
- &ctrl->cmd.dma_addr);
- if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL)
- return -ENOMEM;
-
ctrl->trackers = vmalloc(DMA_TRACKER_LIST_SIZE8);
if (!ctrl->trackers)
return -ENOMEM;
@@ -770,35 +796,9 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas);
INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done);
- memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8);
- iowrite32(lower_32_bits(ctrl->status.dma_addr),
- ctrl->regmap + SB_ADD_LO);
- iowrite32(upper_32_bits(ctrl->status.dma_addr),
- ctrl->regmap + SB_ADD_HI);
-
- memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8);
- iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO);
- iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI);
-
- ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT);
- if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) {
- dev_crit(&dev->dev, "Failed reading status cnt x%x\n",
- ctrl->status.idx);
- return -EINVAL;
- }
- iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT);
- iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT);
-
- ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX);
- if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) {
- dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n",
- ctrl->status.idx);
- return -EINVAL;
- }
- iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX);
- iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
-
- wmb();
+ st = rsxx_hw_buffers_init(dev, ctrl);
+ if (st)
+ return st;
return 0;
}
@@ -834,7 +834,7 @@ static int rsxx_dma_stripe_setup(struct rsxx_cardinfo *card,
return 0;
}
-static int rsxx_dma_configure(struct rsxx_cardinfo *card)
+int rsxx_dma_configure(struct rsxx_cardinfo *card)
{
u32 intr_coal;
@@ -980,6 +980,103 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card)
}
}
+int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
+{
+ int i;
+ int j;
+ int cnt;
+ struct rsxx_dma *dma;
+ struct list_head *issued_dmas;
+
+ issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets,
+ GFP_KERNEL);
+ if (!issued_dmas)
+ return -ENOMEM;
+
+ for (i = 0; i < card->n_targets; i++) {
+ INIT_LIST_HEAD(&issued_dmas[i]);
+ cnt = 0;
+ for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) {
+ dma = get_tracker_dma(card->ctrl[i].trackers, j);
+ if (dma == NULL)
+ continue;
+
+ if (dma->cmd == HW_CMD_BLK_WRITE)
+ card->ctrl[i].stats.writes_issued--;
+ else if (dma->cmd == HW_CMD_BLK_DISCARD)
+ card->ctrl[i].stats.discards_issued--;
+ else
+ card->ctrl[i].stats.reads_issued--;
+
+ list_add_tail(&dma->list, &issued_dmas[i]);
+ push_tracker(card->ctrl[i].trackers, j);
+ cnt++;
+ }
+
+ spin_lock(&card->ctrl[i].queue_lock);
+ list_splice(&issued_dmas[i], &card->ctrl[i].queue);
+
+ atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth);
+ card->ctrl[i].stats.sw_q_depth += cnt;
+ card->ctrl[i].e_cnt = 0;
+
+ list_for_each_entry(dma, &card->ctrl[i].queue, list) {
+ if (dma->dma_addr)
+ pci_unmap_page(card->dev, dma->dma_addr,
+ get_dma_size(dma),
+ dma->cmd == HW_CMD_BLK_WRITE ?
+ PCI_DMA_TODEVICE :
+ PCI_DMA_FROMDEVICE);
+ }
+ spin_unlock(&card->ctrl[i].queue_lock);
+ }
+
+ kfree(issued_dmas);
+
+ return 0;
+}
+
+void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card)
+{
+ struct rsxx_dma *dma;
+ struct rsxx_dma *tmp;
+ int i;
+
+ for (i = 0; i < card->n_targets; i++) {
+ spin_lock(&card->ctrl[i].queue_lock);
+ list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) {
+ list_del(&dma->list);
+
+ rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED);
+ }
+ spin_unlock(&card->ctrl[i].queue_lock);
+ }
+}
+
+int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
+{
+ struct rsxx_dma *dma;
+ int i;
+
+ for (i = 0; i < card->n_targets; i++) {
+ spin_lock(&card->ctrl[i].queue_lock);
+ list_for_each_entry(dma, &card->ctrl[i].queue, list) {
+ dma->dma_addr = pci_map_page(card->dev, dma->page,
+ dma->pg_off, get_dma_size(dma),
+ dma->cmd == HW_CMD_BLK_WRITE ?
+ PCI_DMA_TODEVICE :
+ PCI_DMA_FROMDEVICE);
+ if (!dma->dma_addr) {
+ spin_unlock(&card->ctrl[i].queue_lock);
+ kmem_cache_free(rsxx_dma_pool, dma);
+ return -ENOMEM;
+ }
+ }
+ spin_unlock(&card->ctrl[i].queue_lock);
+ }
+
+ return 0;
+}
int rsxx_dma_init(void)
{
diff --git a/drivers/block/rsxx/rsxx.h b/drivers/block/rsxx/rsxx.h
index 2e50b65902b7..24ba3642bd89 100644
--- a/drivers/block/rsxx/rsxx.h
+++ b/drivers/block/rsxx/rsxx.h
@@ -27,15 +27,17 @@
/*----------------- IOCTL Definitions -------------------*/
+#define RSXX_MAX_DATA 8
+
struct rsxx_reg_access {
__u32 addr;
__u32 cnt;
__u32 stat;
__u32 stream;
- __u32 data[8];
+ __u32 data[RSXX_MAX_DATA];
};
-#define RSXX_MAX_REG_CNT (8 * (sizeof(__u32)))
+#define RSXX_MAX_REG_CNT (RSXX_MAX_DATA * (sizeof(__u32)))
#define RSXX_IOC_MAGIC 'r'
diff --git a/drivers/block/rsxx/rsxx_cfg.h b/drivers/block/rsxx/rsxx_cfg.h
index c025fe5fdb70..f384c943846d 100644
--- a/drivers/block/rsxx/rsxx_cfg.h
+++ b/drivers/block/rsxx/rsxx_cfg.h
@@ -58,7 +58,7 @@ struct rsxx_card_cfg {
};
/* Vendor ID Values */
-#define RSXX_VENDOR_ID_TMS_IBM 0
+#define RSXX_VENDOR_ID_IBM 0
#define RSXX_VENDOR_ID_DSI 1
#define RSXX_VENDOR_COUNT 2
diff --git a/drivers/block/rsxx/rsxx_priv.h b/drivers/block/rsxx/rsxx_priv.h
index a1ac907d8f4c..382e8bf5c03b 100644
--- a/drivers/block/rsxx/rsxx_priv.h
+++ b/drivers/block/rsxx/rsxx_priv.h
@@ -45,16 +45,13 @@
struct proc_cmd;
-#define PCI_VENDOR_ID_TMS_IBM 0x15B6
-#define PCI_DEVICE_ID_RS70_FLASH 0x0019
-#define PCI_DEVICE_ID_RS70D_FLASH 0x001A
-#define PCI_DEVICE_ID_RS80_FLASH 0x001C
-#define PCI_DEVICE_ID_RS81_FLASH 0x001E
+#define PCI_DEVICE_ID_FS70_FLASH 0x04A9
+#define PCI_DEVICE_ID_FS80_FLASH 0x04AA
#define RS70_PCI_REV_SUPPORTED 4
#define DRIVER_NAME "rsxx"
-#define DRIVER_VERSION "3.7"
+#define DRIVER_VERSION "4.0"
/* Block size is 4096 */
#define RSXX_HW_BLK_SHIFT 12
@@ -67,6 +64,9 @@ struct proc_cmd;
#define RSXX_MAX_OUTSTANDING_CMDS 255
#define RSXX_CS_IDX_MASK 0xff
+#define STATUS_BUFFER_SIZE8 4096
+#define COMMAND_BUFFER_SIZE8 4096
+
#define RSXX_MAX_TARGETS 8
struct dma_tracker_list;
@@ -91,6 +91,9 @@ struct rsxx_dma_stats {
u32 discards_failed;
u32 done_rescheduled;
u32 issue_rescheduled;
+ u32 dma_sw_err;
+ u32 dma_hw_fault;
+ u32 dma_cancelled;
u32 sw_q_depth; /* Number of DMAs on the SW queue. */
atomic_t hw_q_depth; /* Number of DMAs queued to HW. */
};
@@ -116,6 +119,7 @@ struct rsxx_dma_ctrl {
struct rsxx_cardinfo {
struct pci_dev *dev;
unsigned int halt;
+ unsigned int eeh_state;
void __iomem *regmap;
spinlock_t irq_lock;
@@ -224,6 +228,7 @@ enum rsxx_pci_regmap {
PERF_RD512_HI = 0xac,
PERF_WR512_LO = 0xb0,
PERF_WR512_HI = 0xb4,
+ PCI_RECONFIG = 0xb8,
};
enum rsxx_intr {
@@ -237,6 +242,8 @@ enum rsxx_intr {
CR_INTR_DMA5 = 0x00000080,
CR_INTR_DMA6 = 0x00000100,
CR_INTR_DMA7 = 0x00000200,
+ CR_INTR_ALL_C = 0x0000003f,
+ CR_INTR_ALL_G = 0x000003ff,
CR_INTR_DMA_ALL = 0x000003f5,
CR_INTR_ALL = 0xffffffff,
};
@@ -253,8 +260,14 @@ enum rsxx_pci_reset {
DMA_QUEUE_RESET = 0x00000001,
};
+enum rsxx_hw_fifo_flush {
+ RSXX_FLUSH_BUSY = 0x00000002,
+ RSXX_FLUSH_TIMEOUT = 0x00000004,
+};
+
enum rsxx_pci_revision {
RSXX_DISCARD_SUPPORT = 2,
+ RSXX_EEH_SUPPORT = 3,
};
enum rsxx_creg_cmd {
@@ -360,11 +373,17 @@ int rsxx_dma_setup(struct rsxx_cardinfo *card);
void rsxx_dma_destroy(struct rsxx_cardinfo *card);
int rsxx_dma_init(void);
void rsxx_dma_cleanup(void);
+void rsxx_dma_queue_reset(struct rsxx_cardinfo *card);
+int rsxx_dma_configure(struct rsxx_cardinfo *card);
int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
struct bio *bio,
atomic_t *n_dmas,
rsxx_dma_cb cb,
void *cb_data);
+int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl);
+int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card);
+void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card);
+int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card);
/***** cregs.c *****/
int rsxx_creg_write(struct rsxx_cardinfo *card, u32 addr,
@@ -389,10 +408,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card);
void rsxx_creg_destroy(struct rsxx_cardinfo *card);
int rsxx_creg_init(void);
void rsxx_creg_cleanup(void);
-
int rsxx_reg_access(struct rsxx_cardinfo *card,
struct rsxx_reg_access __user *ucmd,
int read);
+void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card);
+void rsxx_kick_creg_queue(struct rsxx_cardinfo *card);
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index de1f319f7bd7..dd5b2fed97e9 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -164,7 +164,7 @@ static void make_response(struct xen_blkif *blkif, u64 id,
#define foreach_grant_safe(pos, n, rbtree, node) \
for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \
- (n) = rb_next(&(pos)->node); \
+ (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL; \
&(pos)->node != NULL; \
(pos) = container_of(n, typeof(*(pos)), node), \
(n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
@@ -381,8 +381,8 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
static void print_stats(struct xen_blkif *blkif)
{
- pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d"
- " | ds %4d\n",
+ pr_info("xen-blkback (%s): oo %3llu | rd %4llu | wr %4llu | f %4llu"
+ " | ds %4llu\n",
current->comm, blkif->st_oo_req,
blkif->st_rd_req, blkif->st_wr_req,
blkif->st_f_req, blkif->st_ds_req);
@@ -442,7 +442,7 @@ int xen_blkif_schedule(void *arg)
}
struct seg_buf {
- unsigned long buf;
+ unsigned int offset;
unsigned int nsec;
};
/*
@@ -621,30 +621,21 @@ static int xen_blkbk_map(struct blkif_request *req,
* If this is a new persistent grant
* save the handler
*/
- persistent_gnts[i]->handle = map[j].handle;
- persistent_gnts[i]->dev_bus_addr =
- map[j++].dev_bus_addr;
+ persistent_gnts[i]->handle = map[j++].handle;
}
pending_handle(pending_req, i) =
persistent_gnts[i]->handle;
if (ret)
continue;
-
- seg[i].buf = persistent_gnts[i]->dev_bus_addr |
- (req->u.rw.seg[i].first_sect << 9);
} else {
- pending_handle(pending_req, i) = map[j].handle;
+ pending_handle(pending_req, i) = map[j++].handle;
bitmap_set(pending_req->unmap_seg, i, 1);
- if (ret) {
- j++;
+ if (ret)
continue;
- }
-
- seg[i].buf = map[j++].dev_bus_addr |
- (req->u.rw.seg[i].first_sect << 9);
}
+ seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
}
return ret;
}
@@ -679,6 +670,16 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
return err;
}
+static int dispatch_other_io(struct xen_blkif *blkif,
+ struct blkif_request *req,
+ struct pending_req *pending_req)
+{
+ free_req(pending_req);
+ make_response(blkif, req->u.other.id, req->operation,
+ BLKIF_RSP_EOPNOTSUPP);
+ return -EIO;
+}
+
static void xen_blk_drain_io(struct xen_blkif *blkif)
{
atomic_set(&blkif->drain, 1);
@@ -800,17 +801,30 @@ __do_block_io_op(struct xen_blkif *blkif)
/* Apply all sanity checks to /private copy/ of request. */
barrier();
- if (unlikely(req.operation == BLKIF_OP_DISCARD)) {
+
+ switch (req.operation) {
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_WRITE_BARRIER:
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ if (dispatch_rw_block_io(blkif, &req, pending_req))
+ goto done;
+ break;
+ case BLKIF_OP_DISCARD:
free_req(pending_req);
if (dispatch_discard_io(blkif, &req))
- break;
- } else if (dispatch_rw_block_io(blkif, &req, pending_req))
+ goto done;
break;
+ default:
+ if (dispatch_other_io(blkif, &req, pending_req))
+ goto done;
+ break;
+ }
/* Yield point for this unbounded loop. */
cond_resched();
}
-
+done:
return more_to_do;
}
@@ -904,7 +918,8 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n",
operation == READ ? "read" : "write",
preq.sector_number,
- preq.sector_number + preq.nr_sects, preq.dev);
+ preq.sector_number + preq.nr_sects,
+ blkif->vbd.pdevice);
goto fail_response;
}
@@ -947,7 +962,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
(bio_add_page(bio,
pages[i],
seg[i].nsec << 9,
- seg[i].buf & ~PAGE_MASK) == 0)) {
+ seg[i].offset) == 0)) {
bio = bio_alloc(GFP_KERNEL, nseg-i);
if (unlikely(bio == NULL))
@@ -977,13 +992,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
bio->bi_end_io = end_block_io_op;
}
- /*
- * We set it one so that the last submit_bio does not have to call
- * atomic_inc.
- */
atomic_set(&pending_req->pendcnt, nbio);
-
- /* Get a reference count for the disk queue and start sending I/O */
blk_start_plug(&plug);
for (i = 0; i < nbio; i++)
@@ -1011,6 +1020,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
fail_put_bio:
for (i = 0; i < nbio; i++)
bio_put(biolist[i]);
+ atomic_set(&pending_req->pendcnt, 1);
__end_block_io_op(pending_req, -EINVAL);
msleep(1); /* back off a bit */
return -EIO;
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 6072390c7f57..60103e2517ba 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -77,11 +77,18 @@ struct blkif_x86_32_request_discard {
uint64_t nr_sectors;
} __attribute__((__packed__));
+struct blkif_x86_32_request_other {
+ uint8_t _pad1;
+ blkif_vdev_t _pad2;
+ uint64_t id; /* private guest value, echoed in resp */
+} __attribute__((__packed__));
+
struct blkif_x86_32_request {
uint8_t operation; /* BLKIF_OP_??? */
union {
struct blkif_x86_32_request_rw rw;
struct blkif_x86_32_request_discard discard;
+ struct blkif_x86_32_request_other other;
} u;
} __attribute__((__packed__));
@@ -113,11 +120,19 @@ struct blkif_x86_64_request_discard {
uint64_t nr_sectors;
} __attribute__((__packed__));
+struct blkif_x86_64_request_other {
+ uint8_t _pad1;
+ blkif_vdev_t _pad2;
+ uint32_t _pad3; /* offsetof(blkif_..,u.discard.id)==8 */
+ uint64_t id; /* private guest value, echoed in resp */
+} __attribute__((__packed__));
+
struct blkif_x86_64_request {
uint8_t operation; /* BLKIF_OP_??? */
union {
struct blkif_x86_64_request_rw rw;
struct blkif_x86_64_request_discard discard;
+ struct blkif_x86_64_request_other other;
} u;
} __attribute__((__packed__));
@@ -172,7 +187,6 @@ struct persistent_gnt {
struct page *page;
grant_ref_t gnt;
grant_handle_t handle;
- uint64_t dev_bus_addr;
struct rb_node node;
};
@@ -208,13 +222,13 @@ struct xen_blkif {
/* statistics */
unsigned long st_print;
- int st_rd_req;
- int st_wr_req;
- int st_oo_req;
- int st_f_req;
- int st_ds_req;
- int st_rd_sect;
- int st_wr_sect;
+ unsigned long long st_rd_req;
+ unsigned long long st_wr_req;
+ unsigned long long st_oo_req;
+ unsigned long long st_f_req;
+ unsigned long long st_ds_req;
+ unsigned long long st_rd_sect;
+ unsigned long long st_wr_sect;
wait_queue_head_t waiting_to_free;
};
@@ -278,6 +292,11 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
default:
+ /*
+ * Don't know how to translate this op. Only get the
+ * ID so failure can be reported to the frontend.
+ */
+ dst->u.other.id = src->u.other.id;
break;
}
}
@@ -309,6 +328,11 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
break;
default:
+ /*
+ * Don't know how to translate this op. Only get the
+ * ID so failure can be reported to the frontend.
+ */
+ dst->u.other.id = src->u.other.id;
break;
}
}
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 5e237f630c47..8bfd1bcf95ec 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -230,13 +230,13 @@ int __init xen_blkif_interface_init(void)
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
-VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
-VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
-VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
-VBD_SHOW(f_req, "%d\n", be->blkif->st_f_req);
-VBD_SHOW(ds_req, "%d\n", be->blkif->st_ds_req);
-VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
-VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
+VBD_SHOW(oo_req, "%llu\n", be->blkif->st_oo_req);
+VBD_SHOW(rd_req, "%llu\n", be->blkif->st_rd_req);
+VBD_SHOW(wr_req, "%llu\n", be->blkif->st_wr_req);
+VBD_SHOW(f_req, "%llu\n", be->blkif->st_f_req);
+VBD_SHOW(ds_req, "%llu\n", be->blkif->st_ds_req);
+VBD_SHOW(rd_sect, "%llu\n", be->blkif->st_rd_sect);
+VBD_SHOW(wr_sect, "%llu\n", be->blkif->st_wr_sect);
static struct attribute *xen_vbdstat_attrs[] = {
&dev_attr_oo_req.attr,
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index c3dae2e0f290..a894f88762d8 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -44,7 +44,7 @@
#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
-#include <linux/llist.h>
+#include <linux/list.h>
#include <xen/xen.h>
#include <xen/xenbus.h>
@@ -68,13 +68,12 @@ enum blkif_state {
struct grant {
grant_ref_t gref;
unsigned long pfn;
- struct llist_node node;
+ struct list_head node;
};
struct blk_shadow {
struct blkif_request req;
struct request *request;
- unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST];
};
@@ -105,7 +104,7 @@ struct blkfront_info
struct work_struct work;
struct gnttab_free_callback callback;
struct blk_shadow shadow[BLK_RING_SIZE];
- struct llist_head persistent_gnts;
+ struct list_head persistent_gnts;
unsigned int persistent_gnts_c;
unsigned long shadow_free;
unsigned int feature_flush;
@@ -165,6 +164,69 @@ static int add_id_to_freelist(struct blkfront_info *info,
return 0;
}
+static int fill_grant_buffer(struct blkfront_info *info, int num)
+{
+ struct page *granted_page;
+ struct grant *gnt_list_entry, *n;
+ int i = 0;
+
+ while(i < num) {
+ gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO);
+ if (!gnt_list_entry)
+ goto out_of_memory;
+
+ granted_page = alloc_page(GFP_NOIO);
+ if (!granted_page) {
+ kfree(gnt_list_entry);
+ goto out_of_memory;
+ }
+
+ gnt_list_entry->pfn = page_to_pfn(granted_page);
+ gnt_list_entry->gref = GRANT_INVALID_REF;
+ list_add(&gnt_list_entry->node, &info->persistent_gnts);
+ i++;
+ }
+
+ return 0;
+
+out_of_memory:
+ list_for_each_entry_safe(gnt_list_entry, n,
+ &info->persistent_gnts, node) {
+ list_del(&gnt_list_entry->node);
+ __free_page(pfn_to_page(gnt_list_entry->pfn));
+ kfree(gnt_list_entry);
+ i--;
+ }
+ BUG_ON(i != 0);
+ return -ENOMEM;
+}
+
+static struct grant *get_grant(grant_ref_t *gref_head,
+ struct blkfront_info *info)
+{
+ struct grant *gnt_list_entry;
+ unsigned long buffer_mfn;
+
+ BUG_ON(list_empty(&info->persistent_gnts));
+ gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant,
+ node);
+ list_del(&gnt_list_entry->node);
+
+ if (gnt_list_entry->gref != GRANT_INVALID_REF) {
+ info->persistent_gnts_c--;
+ return gnt_list_entry;
+ }
+
+ /* Assign a gref to this page */
+ gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
+ BUG_ON(gnt_list_entry->gref == -ENOSPC);
+ buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
+ gnttab_grant_foreign_access_ref(gnt_list_entry->gref,
+ info->xbdev->otherend_id,
+ buffer_mfn, 0);
+ return gnt_list_entry;
+}
+
static const char *op_name(int op)
{
static const char *const names[] = {
@@ -293,7 +355,6 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
static int blkif_queue_request(struct request *req)
{
struct blkfront_info *info = req->rq_disk->private_data;
- unsigned long buffer_mfn;
struct blkif_request *ring_req;
unsigned long id;
unsigned int fsect, lsect;
@@ -306,7 +367,6 @@ static int blkif_queue_request(struct request *req)
*/
bool new_persistent_gnts;
grant_ref_t gref_head;
- struct page *granted_page;
struct grant *gnt_list_entry = NULL;
struct scatterlist *sg;
@@ -370,41 +430,8 @@ static int blkif_queue_request(struct request *req)
fsect = sg->offset >> 9;
lsect = fsect + (sg->length >> 9) - 1;
- if (info->persistent_gnts_c) {
- BUG_ON(llist_empty(&info->persistent_gnts));
- gnt_list_entry = llist_entry(
- llist_del_first(&info->persistent_gnts),
- struct grant, node);
-
- ref = gnt_list_entry->gref;
- buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
- info->persistent_gnts_c--;
- } else {
- ref = gnttab_claim_grant_reference(&gref_head);
- BUG_ON(ref == -ENOSPC);
-
- gnt_list_entry =
- kmalloc(sizeof(struct grant),
- GFP_ATOMIC);
- if (!gnt_list_entry)
- return -ENOMEM;
-
- granted_page = alloc_page(GFP_ATOMIC);
- if (!granted_page) {
- kfree(gnt_list_entry);
- return -ENOMEM;
- }
-
- gnt_list_entry->pfn =
- page_to_pfn(granted_page);
- gnt_list_entry->gref = ref;
-
- buffer_mfn = pfn_to_mfn(page_to_pfn(
- granted_page));
- gnttab_grant_foreign_access_ref(ref,
- info->xbdev->otherend_id,
- buffer_mfn, 0);
- }
+ gnt_list_entry = get_grant(&gref_head, info);
+ ref = gnt_list_entry->gref;
info->shadow[id].grants_used[i] = gnt_list_entry;
@@ -435,7 +462,6 @@ static int blkif_queue_request(struct request *req)
kunmap_atomic(shared_data);
}
- info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
ring_req->u.rw.seg[i] =
(struct blkif_request_segment) {
.gref = ref,
@@ -790,9 +816,8 @@ static void blkif_restart_queue(struct work_struct *work)
static void blkif_free(struct blkfront_info *info, int suspend)
{
- struct llist_node *all_gnts;
- struct grant *persistent_gnt, *tmp;
- struct llist_node *n;
+ struct grant *persistent_gnt;
+ struct grant *n;
/* Prevent new requests being issued until we fix things up. */
spin_lock_irq(&info->io_lock);
@@ -803,22 +828,20 @@ static void blkif_free(struct blkfront_info *info, int suspend)
blk_stop_queue(info->rq);
/* Remove all persistent grants */
- if (info->persistent_gnts_c) {
- all_gnts = llist_del_all(&info->persistent_gnts);
- persistent_gnt = llist_entry(all_gnts, typeof(*(persistent_gnt)), node);
- while (persistent_gnt) {
- gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+ if (!list_empty(&info->persistent_gnts)) {
+ list_for_each_entry_safe(persistent_gnt, n,
+ &info->persistent_gnts, node) {
+ list_del(&persistent_gnt->node);
+ if (persistent_gnt->gref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(persistent_gnt->gref,
+ 0, 0UL);
+ info->persistent_gnts_c--;
+ }
__free_page(pfn_to_page(persistent_gnt->pfn));
- tmp = persistent_gnt;
- n = persistent_gnt->node.next;
- if (n)
- persistent_gnt = llist_entry(n, typeof(*(persistent_gnt)), node);
- else
- persistent_gnt = NULL;
- kfree(tmp);
+ kfree(persistent_gnt);
}
- info->persistent_gnts_c = 0;
}
+ BUG_ON(info->persistent_gnts_c != 0);
/* No more gnttab callback work. */
gnttab_cancel_free_callback(&info->callback);
@@ -875,7 +898,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
}
/* Add the persistent grant into the list of free grants */
for (i = 0; i < s->req.u.rw.nr_segments; i++) {
- llist_add(&s->grants_used[i]->node, &info->persistent_gnts);
+ list_add(&s->grants_used[i]->node, &info->persistent_gnts);
info->persistent_gnts_c++;
}
}
@@ -1013,6 +1036,12 @@ static int setup_blkring(struct xenbus_device *dev,
sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ /* Allocate memory for grants */
+ err = fill_grant_buffer(info, BLK_RING_SIZE *
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ if (err)
+ goto fail;
+
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
if (err < 0) {
free_page((unsigned long)sring);
@@ -1171,7 +1200,7 @@ static int blkfront_probe(struct xenbus_device *dev,
spin_lock_init(&info->io_lock);
info->xbdev = dev;
info->vdevice = vdevice;
- init_llist_head(&info->persistent_gnts);
+ INIT_LIST_HEAD(&info->persistent_gnts);
info->persistent_gnts_c = 0;
info->connected = BLKIF_STATE_DISCONNECTED;
INIT_WORK(&info->work, blkif_restart_queue);
@@ -1203,11 +1232,10 @@ static int blkif_recover(struct blkfront_info *info)
int j;
/* Stage 1: Make a safe copy of the shadow state. */
- copy = kmalloc(sizeof(info->shadow),
+ copy = kmemdup(info->shadow, sizeof(info->shadow),
GFP_NOIO | __GFP_REPEAT | __GFP_HIGH);
if (!copy)
return -ENOMEM;
- memcpy(copy, info->shadow, sizeof(info->shadow));
/* Stage 2: Set up free list. */
memset(&info->shadow, 0, sizeof(info->shadow));
@@ -1236,7 +1264,7 @@ static int blkif_recover(struct blkfront_info *info)
gnttab_grant_foreign_access_ref(
req->u.rw.seg[j].gref,
info->xbdev->otherend_id,
- pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]),
+ pfn_to_mfn(copy[i].grants_used[j]->pfn),
0);
}
info->shadow[req->u.rw.id].req = *req;
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 6aab00ef4379..11f467c00d0a 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -90,6 +90,7 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x0489, 0xe04e) },
{ USB_DEVICE(0x0489, 0xe056) },
+ { USB_DEVICE(0x0489, 0xe04d) },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
@@ -126,6 +127,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 0d26851d6e49..6c3e3d43c718 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -934,17 +934,4 @@ static struct pcmcia_driver bluecard_driver = {
.remove = bluecard_detach,
.id_table = bluecard_ids,
};
-
-static int __init init_bluecard_cs(void)
-{
- return pcmcia_register_driver(&bluecard_driver);
-}
-
-
-static void __exit exit_bluecard_cs(void)
-{
- pcmcia_unregister_driver(&bluecard_driver);
-}
-
-module_init(init_bluecard_cs);
-module_exit(exit_bluecard_cs);
+module_pcmcia_driver(bluecard_driver);
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 7ffd3f407144..a1aaa3ba2a4b 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -760,17 +760,4 @@ static struct pcmcia_driver bt3c_driver = {
.remove = bt3c_detach,
.id_table = bt3c_ids,
};
-
-static int __init init_bt3c_cs(void)
-{
- return pcmcia_register_driver(&bt3c_driver);
-}
-
-
-static void __exit exit_bt3c_cs(void)
-{
- pcmcia_unregister_driver(&bt3c_driver);
-}
-
-module_init(init_bt3c_cs);
-module_exit(exit_bt3c_cs);
+module_pcmcia_driver(bt3c_driver);
diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c
index 428dbb7574bd..db2c3c305df8 100644
--- a/drivers/bluetooth/btmrvl_debugfs.c
+++ b/drivers/bluetooth/btmrvl_debugfs.c
@@ -29,20 +29,6 @@
struct btmrvl_debugfs_data {
struct dentry *config_dir;
struct dentry *status_dir;
-
- /* config */
- struct dentry *psmode;
- struct dentry *pscmd;
- struct dentry *hsmode;
- struct dentry *hscmd;
- struct dentry *gpiogap;
- struct dentry *hscfgcmd;
-
- /* status */
- struct dentry *curpsmode;
- struct dentry *hsstate;
- struct dentry *psstate;
- struct dentry *txdnldready;
};
static ssize_t btmrvl_hscfgcmd_write(struct file *file,
@@ -91,47 +77,6 @@ static const struct file_operations btmrvl_hscfgcmd_fops = {
.llseek = default_llseek,
};
-static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- long result, ret;
-
- memset(buf, 0, sizeof(buf));
-
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- ret = strict_strtol(buf, 10, &result);
- if (ret)
- return ret;
-
- priv->btmrvl_dev.psmode = result;
-
- return count;
-}
-
-static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
- priv->btmrvl_dev.psmode);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_psmode_fops = {
- .read = btmrvl_psmode_read,
- .write = btmrvl_psmode_write,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
@@ -178,47 +123,6 @@ static const struct file_operations btmrvl_pscmd_fops = {
.llseek = default_llseek,
};
-static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- long result, ret;
-
- memset(buf, 0, sizeof(buf));
-
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- ret = strict_strtol(buf, 16, &result);
- if (ret)
- return ret;
-
- priv->btmrvl_dev.gpio_gap = result;
-
- return count;
-}
-
-static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
- priv->btmrvl_dev.gpio_gap);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_gpiogap_fops = {
- .read = btmrvl_gpiogap_read,
- .write = btmrvl_gpiogap_write,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
@@ -263,119 +167,6 @@ static const struct file_operations btmrvl_hscmd_fops = {
.llseek = default_llseek,
};
-static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- long result, ret;
-
- memset(buf, 0, sizeof(buf));
-
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
- return -EFAULT;
-
- ret = strict_strtol(buf, 10, &result);
- if (ret)
- return ret;
-
- priv->btmrvl_dev.hsmode = result;
-
- return count;
-}
-
-static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_hsmode_fops = {
- .read = btmrvl_hsmode_read,
- .write = btmrvl_hsmode_write,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
-static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_curpsmode_fops = {
- .read = btmrvl_curpsmode_read,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
-static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_psstate_fops = {
- .read = btmrvl_psstate_read,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
-static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_hsstate_fops = {
- .read = btmrvl_hsstate_read,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
-static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct btmrvl_private *priv = file->private_data;
- char buf[16];
- int ret;
-
- ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
- priv->btmrvl_dev.tx_dnld_rdy);
-
- return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-}
-
-static const struct file_operations btmrvl_txdnldready_fops = {
- .read = btmrvl_txdnldready_read,
- .open = simple_open,
- .llseek = default_llseek,
-};
-
void btmrvl_debugfs_init(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
@@ -394,30 +185,28 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)
dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);
- dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
- priv, &btmrvl_psmode_fops);
- dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
- priv, &btmrvl_pscmd_fops);
- dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
- priv, &btmrvl_gpiogap_fops);
- dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir,
- priv, &btmrvl_hsmode_fops);
- dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
- priv, &btmrvl_hscmd_fops);
- dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
- priv, &btmrvl_hscfgcmd_fops);
+ debugfs_create_u8("psmode", 0644, dbg->config_dir,
+ &priv->btmrvl_dev.psmode);
+ debugfs_create_file("pscmd", 0644, dbg->config_dir,
+ priv, &btmrvl_pscmd_fops);
+ debugfs_create_x16("gpiogap", 0644, dbg->config_dir,
+ &priv->btmrvl_dev.gpio_gap);
+ debugfs_create_u8("hsmode", 0644, dbg->config_dir,
+ &priv->btmrvl_dev.hsmode);
+ debugfs_create_file("hscmd", 0644, dbg->config_dir,
+ priv, &btmrvl_hscmd_fops);
+ debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
+ priv, &btmrvl_hscfgcmd_fops);
dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
- dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
- dbg->status_dir, priv,
- &btmrvl_curpsmode_fops);
- dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
- priv, &btmrvl_psstate_fops);
- dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
- priv, &btmrvl_hsstate_fops);
- dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
- dbg->status_dir, priv,
- &btmrvl_txdnldready_fops);
+ debugfs_create_u8("curpsmode", 0444, dbg->status_dir,
+ &priv->adapter->psmode);
+ debugfs_create_u8("psstate", 0444, dbg->status_dir,
+ &priv->adapter->ps_state);
+ debugfs_create_u8("hsstate", 0444, dbg->status_dir,
+ &priv->adapter->hs_state);
+ debugfs_create_u8("txdnldready", 0444, dbg->status_dir,
+ &priv->btmrvl_dev.tx_dnld_rdy);
}
void btmrvl_debugfs_remove(struct hci_dev *hdev)
@@ -428,19 +217,8 @@ void btmrvl_debugfs_remove(struct hci_dev *hdev)
if (!dbg)
return;
- debugfs_remove(dbg->psmode);
- debugfs_remove(dbg->pscmd);
- debugfs_remove(dbg->gpiogap);
- debugfs_remove(dbg->hsmode);
- debugfs_remove(dbg->hscmd);
- debugfs_remove(dbg->hscfgcmd);
- debugfs_remove(dbg->config_dir);
-
- debugfs_remove(dbg->curpsmode);
- debugfs_remove(dbg->psstate);
- debugfs_remove(dbg->hsstate);
- debugfs_remove(dbg->txdnldready);
- debugfs_remove(dbg->status_dir);
+ debugfs_remove_recursive(dbg->config_dir);
+ debugfs_remove_recursive(dbg->status_dir);
kfree(dbg);
}
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 9959d4cb23dc..c63488c54f4a 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
- .helper = "sd8688_helper.bin",
- .firmware = "sd8688.bin",
+ .helper = "mrvl/sd8688_helper.bin",
+ .firmware = "mrvl/sd8688.bin",
.reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64,
};
@@ -228,24 +228,24 @@ failed:
static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,
int pollnum)
{
- int ret = -ETIMEDOUT;
u16 firmwarestat;
- unsigned int tries;
+ int tries, ret;
/* Wait for firmware to become ready */
for (tries = 0; tries < pollnum; tries++) {
- if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0)
+ sdio_claim_host(card->func);
+ ret = btmrvl_sdio_read_fw_status(card, &firmwarestat);
+ sdio_release_host(card->func);
+ if (ret < 0)
continue;
- if (firmwarestat == FIRMWARE_READY) {
- ret = 0;
- break;
- } else {
- msleep(10);
- }
+ if (firmwarestat == FIRMWARE_READY)
+ return 0;
+
+ msleep(10);
}
- return ret;
+ return -ETIMEDOUT;
}
static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
@@ -874,7 +874,7 @@ exit:
static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
{
- int ret = 0;
+ int ret;
u8 fws0;
int pollnum = MAX_POLL_TRIES;
@@ -882,13 +882,14 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
BT_ERR("card or function is NULL!");
return -EINVAL;
}
- sdio_claim_host(card->func);
if (!btmrvl_sdio_verify_fw_download(card, 1)) {
BT_DBG("Firmware already downloaded!");
- goto done;
+ return 0;
}
+ sdio_claim_host(card->func);
+
/* Check if other function driver is downloading the firmware */
fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret) {
@@ -918,15 +919,21 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
}
}
+ sdio_release_host(card->func);
+
+ /*
+ * winner or not, with this test the FW synchronizes when the
+ * module can continue its initialization
+ */
if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
BT_ERR("FW failed to be active in time!");
- ret = -ETIMEDOUT;
- goto done;
+ return -ETIMEDOUT;
}
+ return 0;
+
done:
sdio_release_host(card->func);
-
return ret;
}
@@ -989,8 +996,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
goto unreg_dev;
}
- msleep(100);
-
btmrvl_sdio_enable_host_int(card);
priv = btmrvl_add_card(card);
@@ -1185,7 +1190,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("sd8688_helper.bin");
-MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
+MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 35a553a90616..beb262f2dc4d 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -688,17 +688,4 @@ static struct pcmcia_driver btuart_driver = {
.remove = btuart_detach,
.id_table = btuart_ids,
};
-
-static int __init init_btuart_cs(void)
-{
- return pcmcia_register_driver(&btuart_driver);
-}
-
-
-static void __exit exit_btuart_cs(void)
-{
- pcmcia_unregister_driver(&btuart_driver);
-}
-
-module_init(init_btuart_cs);
-module_exit(exit_btuart_cs);
+module_pcmcia_driver(btuart_driver);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 2cc5f774a29c..7a7e5f8ecadc 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -47,6 +48,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BROKEN_ISOC 0x20
#define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
+#define BTUSB_INTEL 0x100
static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -148,6 +150,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -206,6 +209,9 @@ static struct usb_device_id blacklist_table[] = {
/* Frontline ComProbe Bluetooth Sniffer */
{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },
+ /* Intel Bluetooth device */
+ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
+
{ } /* Terminating entry */
};
@@ -926,6 +932,391 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
+static int btusb_setup_bcm92035(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ u8 val = 0x00;
+
+ BT_DBG("%s", hdev->name);
+
+ skb = __hci_cmd_sync(hdev, 0xfc3b, 1, &val, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb))
+ BT_ERR("BCM92035 command failed (%ld)", -PTR_ERR(skb));
+ else
+ kfree_skb(skb);
+
+ return 0;
+}
+
+struct intel_version {
+ u8 status;
+ u8 hw_platform;
+ u8 hw_variant;
+ u8 hw_revision;
+ u8 fw_variant;
+ u8 fw_revision;
+ u8 fw_build_num;
+ u8 fw_build_ww;
+ u8 fw_build_yy;
+ u8 fw_patch_num;
+} __packed;
+
+static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
+ struct intel_version *ver)
+{
+ const struct firmware *fw;
+ char fwname[64];
+ int ret;
+
+ snprintf(fwname, sizeof(fwname),
+ "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq",
+ ver->hw_platform, ver->hw_variant, ver->hw_revision,
+ ver->fw_variant, ver->fw_revision, ver->fw_build_num,
+ ver->fw_build_ww, ver->fw_build_yy);
+
+ ret = request_firmware(&fw, fwname, &hdev->dev);
+ if (ret < 0) {
+ if (ret == -EINVAL) {
+ BT_ERR("%s Intel firmware file request failed (%d)",
+ hdev->name, ret);
+ return NULL;
+ }
+
+ BT_ERR("%s failed to open Intel firmware file: %s(%d)",
+ hdev->name, fwname, ret);
+
+ /* If the correct firmware patch file is not found, use the
+ * default firmware patch file instead
+ */
+ snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq",
+ ver->hw_platform, ver->hw_variant);
+ if (request_firmware(&fw, fwname, &hdev->dev) < 0) {
+ BT_ERR("%s failed to open default Intel fw file: %s",
+ hdev->name, fwname);
+ return NULL;
+ }
+ }
+
+ BT_INFO("%s: Intel Bluetooth firmware file: %s", hdev->name, fwname);
+
+ return fw;
+}
+
+static int btusb_setup_intel_patching(struct hci_dev *hdev,
+ const struct firmware *fw,
+ const u8 **fw_ptr, int *disable_patch)
+{
+ struct sk_buff *skb;
+ struct hci_command_hdr *cmd;
+ const u8 *cmd_param;
+ struct hci_event_hdr *evt = NULL;
+ const u8 *evt_param = NULL;
+ int remain = fw->size - (*fw_ptr - fw->data);
+
+ /* The first byte indicates the types of the patch command or event.
+ * 0x01 means HCI command and 0x02 is HCI event. If the first bytes
+ * in the current firmware buffer doesn't start with 0x01 or
+ * the size of remain buffer is smaller than HCI command header,
+ * the firmware file is corrupted and it should stop the patching
+ * process.
+ */
+ if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) {
+ BT_ERR("%s Intel fw corrupted: invalid cmd read", hdev->name);
+ return -EINVAL;
+ }
+ (*fw_ptr)++;
+ remain--;
+
+ cmd = (struct hci_command_hdr *)(*fw_ptr);
+ *fw_ptr += sizeof(*cmd);
+ remain -= sizeof(*cmd);
+
+ /* Ensure that the remain firmware data is long enough than the length
+ * of command parameter. If not, the firmware file is corrupted.
+ */
+ if (remain < cmd->plen) {
+ BT_ERR("%s Intel fw corrupted: invalid cmd len", hdev->name);
+ return -EFAULT;
+ }
+
+ /* If there is a command that loads a patch in the firmware
+ * file, then enable the patch upon success, otherwise just
+ * disable the manufacturer mode, for example patch activation
+ * is not required when the default firmware patch file is used
+ * because there are no patch data to load.
+ */
+ if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e)
+ *disable_patch = 0;
+
+ cmd_param = *fw_ptr;
+ *fw_ptr += cmd->plen;
+ remain -= cmd->plen;
+
+ /* This reads the expected events when the above command is sent to the
+ * device. Some vendor commands expects more than one events, for
+ * example command status event followed by vendor specific event.
+ * For this case, it only keeps the last expected event. so the command
+ * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of
+ * last expected event.
+ */
+ while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) {
+ (*fw_ptr)++;
+ remain--;
+
+ evt = (struct hci_event_hdr *)(*fw_ptr);
+ *fw_ptr += sizeof(*evt);
+ remain -= sizeof(*evt);
+
+ if (remain < evt->plen) {
+ BT_ERR("%s Intel fw corrupted: invalid evt len",
+ hdev->name);
+ return -EFAULT;
+ }
+
+ evt_param = *fw_ptr;
+ *fw_ptr += evt->plen;
+ remain -= evt->plen;
+ }
+
+ /* Every HCI commands in the firmware file has its correspond event.
+ * If event is not found or remain is smaller than zero, the firmware
+ * file is corrupted.
+ */
+ if (!evt || !evt_param || remain < 0) {
+ BT_ERR("%s Intel fw corrupted: invalid evt read", hdev->name);
+ return -EFAULT;
+ }
+
+ skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen,
+ cmd_param, evt->evt, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
+ hdev->name, cmd->opcode, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+
+ /* It ensures that the returned event matches the event data read from
+ * the firmware file. At fist, it checks the length and then
+ * the contents of the event.
+ */
+ if (skb->len != evt->plen) {
+ BT_ERR("%s mismatch event length (opcode 0x%4.4x)", hdev->name,
+ le16_to_cpu(cmd->opcode));
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+
+ if (memcmp(skb->data, evt_param, evt->plen)) {
+ BT_ERR("%s mismatch event parameter (opcode 0x%4.4x)",
+ hdev->name, le16_to_cpu(cmd->opcode));
+ kfree_skb(skb);
+ return -EFAULT;
+ }
+ kfree_skb(skb);
+
+ return 0;
+}
+
+static int btusb_setup_intel(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ const struct firmware *fw;
+ const u8 *fw_ptr;
+ int disable_patch;
+ struct intel_version *ver;
+
+ const u8 mfg_enable[] = { 0x01, 0x00 };
+ const u8 mfg_disable[] = { 0x00, 0x00 };
+ const u8 mfg_reset_deactivate[] = { 0x00, 0x01 };
+ const u8 mfg_reset_activate[] = { 0x00, 0x02 };
+
+ BT_DBG("%s", hdev->name);
+
+ /* The controller has a bug with the first HCI command sent to it
+ * returning number of completed commands as zero. This would stall the
+ * command processing in the Bluetooth core.
+ *
+ * As a workaround, send HCI Reset command first which will reset the
+ * number of completed commands and allow normal command processing
+ * from now on.
+ */
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s sending initial HCI reset command failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ /* Read Intel specific controller version first to allow selection of
+ * which firmware file to load.
+ *
+ * The returned information are hardware variant and revision plus
+ * firmware variant, revision and build number.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s reading Intel fw version command failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(*ver)) {
+ BT_ERR("%s Intel version event length mismatch", hdev->name);
+ kfree_skb(skb);
+ return -EIO;
+ }
+
+ ver = (struct intel_version *)skb->data;
+ if (ver->status) {
+ BT_ERR("%s Intel fw version event failed (%02x)", hdev->name,
+ ver->status);
+ kfree_skb(skb);
+ return -bt_to_errno(ver->status);
+ }
+
+ BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ hdev->name, ver->hw_platform, ver->hw_variant,
+ ver->hw_revision, ver->fw_variant, ver->fw_revision,
+ ver->fw_build_num, ver->fw_build_ww, ver->fw_build_yy,
+ ver->fw_patch_num);
+
+ /* fw_patch_num indicates the version of patch the device currently
+ * have. If there is no patch data in the device, it is always 0x00.
+ * So, if it is other than 0x00, no need to patch the deivce again.
+ */
+ if (ver->fw_patch_num) {
+ BT_INFO("%s: Intel device is already patched. patch num: %02x",
+ hdev->name, ver->fw_patch_num);
+ kfree_skb(skb);
+ return 0;
+ }
+
+ /* Opens the firmware patch file based on the firmware version read
+ * from the controller. If it fails to open the matching firmware
+ * patch file, it tries to open the default firmware patch file.
+ * If no patch file is found, allow the device to operate without
+ * a patch.
+ */
+ fw = btusb_setup_intel_get_fw(hdev, ver);
+ if (!fw) {
+ kfree_skb(skb);
+ return 0;
+ }
+ fw_ptr = fw->data;
+
+ /* This Intel specific command enables the manufacturer mode of the
+ * controller.
+ *
+ * Only while this mode is enabled, the driver can download the
+ * firmware patch data and configuration parameters.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc11, 2, mfg_enable, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ release_firmware(fw);
+ return -PTR_ERR(skb);
+ }
+
+ if (skb->data[0]) {
+ u8 evt_status = skb->data[0];
+ BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
+ hdev->name, evt_status);
+ kfree_skb(skb);
+ release_firmware(fw);
+ return -bt_to_errno(evt_status);
+ }
+ kfree_skb(skb);
+
+ disable_patch = 1;
+
+ /* The firmware data file consists of list of Intel specific HCI
+ * commands and its expected events. The first byte indicates the
+ * type of the message, either HCI command or HCI event.
+ *
+ * It reads the command and its expected event from the firmware file,
+ * and send to the controller. Once __hci_cmd_sync_ev() returns,
+ * the returned event is compared with the event read from the firmware
+ * file and it will continue until all the messages are downloaded to
+ * the controller.
+ *
+ * Once the firmware patching is completed successfully,
+ * the manufacturer mode is disabled with reset and activating the
+ * downloaded patch.
+ *
+ * If the firmware patching fails, the manufacturer mode is
+ * disabled with reset and deactivating the patch.
+ *
+ * If the default patch file is used, no reset is done when disabling
+ * the manufacturer.
+ */
+ while (fw->size > fw_ptr - fw->data) {
+ int ret;
+
+ ret = btusb_setup_intel_patching(hdev, fw, &fw_ptr,
+ &disable_patch);
+ if (ret < 0)
+ goto exit_mfg_deactivate;
+ }
+
+ release_firmware(fw);
+
+ if (disable_patch)
+ goto exit_mfg_disable;
+
+ /* Patching completed successfully and disable the manufacturer mode
+ * with reset and activate the downloaded firmware patches.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_activate),
+ mfg_reset_activate, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
+ hdev->name);
+
+ return 0;
+
+exit_mfg_disable:
+ /* Disable the manufacturer mode without reset */
+ skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_disable), mfg_disable,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);
+ return 0;
+
+exit_mfg_deactivate:
+ release_firmware(fw);
+
+ /* Patching failed. Disable the manufacturer mode with reset and
+ * deactivate the downloaded firmware patches.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_deactivate),
+ mfg_reset_deactivate, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return -PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
+ hdev->name);
+
+ return 0;
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -1022,11 +1413,17 @@ static int btusb_probe(struct usb_interface *intf,
SET_HCIDEV_DEV(hdev, &intf->dev);
- hdev->open = btusb_open;
- hdev->close = btusb_close;
- hdev->flush = btusb_flush;
- hdev->send = btusb_send_frame;
- hdev->notify = btusb_notify;
+ hdev->open = btusb_open;
+ hdev->close = btusb_close;
+ hdev->flush = btusb_flush;
+ hdev->send = btusb_send_frame;
+ hdev->notify = btusb_notify;
+
+ if (id->driver_info & BTUSB_BCM92035)
+ hdev->setup = btusb_setup_bcm92035;
+
+ if (id->driver_info & BTUSB_INTEL)
+ hdev->setup = btusb_setup_intel;
/* Interface numbers are hardcoded in the specification */
data->isoc = usb_ifnum_to_if(data->udev, 1);
@@ -1065,17 +1462,6 @@ static int btusb_probe(struct usb_interface *intf,
data->isoc = NULL;
}
- if (id->driver_info & BTUSB_BCM92035) {
- unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 };
- struct sk_buff *skb;
-
- skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
- if (skb) {
- memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
- skb_queue_tail(&hdev->driver_init, skb);
- }
- }
-
if (data->isoc) {
err = usb_driver_claim_interface(&btusb_driver,
data->isoc, data);
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 036cb366fe6e..33f3a6950c0e 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -628,17 +628,4 @@ static struct pcmcia_driver dtl1_driver = {
.remove = dtl1_detach,
.id_table = dtl1_ids,
};
-
-static int __init init_dtl1_cs(void)
-{
- return pcmcia_register_driver(&dtl1_driver);
-}
-
-
-static void __exit exit_dtl1_cs(void)
-{
- pcmcia_unregister_driver(&dtl1_driver);
-}
-
-module_init(init_dtl1_cs);
-module_exit(exit_dtl1_cs);
+module_pcmcia_driver(dtl1_driver);
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index c60623f206d4..8ae9f1ea2bb5 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -153,6 +153,9 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
{
int ret;
+ if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+ return -EUNATCH;
+
ret = hci_recv_stream_fragment(hu->hdev, data, count);
if (ret < 0) {
BT_ERR("Frame Reassembly Failed");
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index ed0fade46aed..bc68a440d432 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -260,12 +260,12 @@ static int hci_uart_send_frame(struct sk_buff *skb)
/* ------ LDISC part ------ */
/* hci_uart_tty_open
- *
+ *
* Called when line discipline changed to HCI_UART.
*
* Arguments:
* tty pointer to tty info structure
- * Return Value:
+ * Return Value:
* 0 if success, otherwise error code
*/
static int hci_uart_tty_open(struct tty_struct *tty)
@@ -365,15 +365,15 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
}
/* hci_uart_tty_receive()
- *
+ *
* Called by tty low level driver when receive data is
* available.
- *
+ *
* Arguments: tty pointer to tty isntance data
* data pointer to received data
* flags pointer to flags for data
* count count of received data in bytes
- *
+ *
* Return Value: None
*/
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
@@ -388,7 +388,10 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
spin_lock(&hu->rx_lock);
hu->proto->recv(hu, (void *) data, count);
- hu->hdev->stat.byte_rx += count;
+
+ if (hu->hdev)
+ hu->hdev->stat.byte_rx += count;
+
spin_unlock(&hu->rx_lock);
tty_unthrottle(tty);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 25373df1dcf8..974321a2508d 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -804,8 +804,8 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
printk(KERN_INFO "Prom version board %d ....... V%d.%d %s",
i+1,
- (int)(readb(apbs[IndexCard].RamIO + VERS) >> 4),
- (int)(readb(apbs[IndexCard].RamIO + VERS) & 0xF),
+ (int)(readb(apbs[i].RamIO + VERS) >> 4),
+ (int)(readb(apbs[i].RamIO + VERS) & 0xF),
boardname);
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index e3f9a99b8522..d784650d14f0 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -373,26 +373,14 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
struct hpet_dev *devp;
unsigned long addr;
- if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
- return -EINVAL;
-
devp = file->private_data;
addr = devp->hd_hpets->hp_hpet_phys;
if (addr & (PAGE_SIZE - 1))
return -ENOSYS;
- vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
- PAGE_SIZE, vma->vm_page_prot)) {
- printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
- __func__);
- return -EAGAIN;
- }
-
- return 0;
+ return vm_iomap_memory(vma, addr, PAGE_SIZE);
#else
return -ENOSYS;
#endif
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 69ae5972713c..a0f7724852eb 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -380,6 +380,15 @@ void hwrng_unregister(struct hwrng *rng)
}
EXPORT_SYMBOL_GPL(hwrng_unregister);
+static void __exit hwrng_exit(void)
+{
+ mutex_lock(&rng_mutex);
+ BUG_ON(current_rng);
+ kfree(rng_buffer);
+ mutex_unlock(&rng_mutex);
+}
+
+module_exit(hwrng_exit);
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c
index f05d85713fd3..895d0b8fb9ab 100644
--- a/drivers/char/hw_random/mxc-rnga.c
+++ b/drivers/char/hw_random/mxc-rnga.c
@@ -228,18 +228,7 @@ static struct platform_driver mxc_rnga_driver = {
.remove = __exit_p(mxc_rnga_remove),
};
-static int __init mod_init(void)
-{
- return platform_driver_probe(&mxc_rnga_driver, mxc_rnga_probe);
-}
-
-static void __exit mod_exit(void)
-{
- platform_driver_unregister(&mxc_rnga_driver);
-}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("H/W RNGA driver for i.MX");
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
index 30991989d65b..d34a24a0d484 100644
--- a/drivers/char/hw_random/tx4939-rng.c
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -166,18 +166,7 @@ static struct platform_driver tx4939_rng_driver = {
.remove = tx4939_rng_remove,
};
-static int __init tx4939rng_init(void)
-{
- return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe);
-}
-
-static void __exit tx4939rng_exit(void)
-{
- platform_driver_unregister(&tx4939_rng_driver);
-}
-
-module_init(tx4939rng_init);
-module_exit(tx4939rng_exit);
+module_platform_driver_probe(tx4939_rng_driver, tx4939_rng_probe);
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 32a6c5764950..cd9a6211dcad 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1485,6 +1485,7 @@ unsigned int get_random_int(void)
return ret;
}
+EXPORT_SYMBOL(get_random_int);
/*
* randomize_range() returns a start address such that
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 3b22a606f79d..2e2036e940fc 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -371,7 +371,7 @@ static int srom_setup_minor(struct srom_dev *srom, int index)
dev = device_create(srom_class, &platform_bus,
MKDEV(srom_major, index), srom, "%d", index);
- return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+ return PTR_RET(dev);
}
/** srom_init() - Initialize the driver's module. */
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 0d2e82f95577..7c3b3dcbfbc8 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1337,7 +1337,7 @@ int tpm_pm_suspend(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_cmd_t cmd;
- int rc;
+ int rc, try;
u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
@@ -1355,9 +1355,32 @@ int tpm_pm_suspend(struct device *dev)
}
/* now do the actual savestate */
- cmd.header.in = savestate_header;
- rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE,
- "sending savestate before suspend");
+ for (try = 0; try < TPM_RETRY; try++) {
+ cmd.header.in = savestate_header;
+ rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+
+ /*
+ * If the TPM indicates that it is too busy to respond to
+ * this command then retry before giving up. It can take
+ * several seconds for this TPM to be ready.
+ *
+ * This can happen if the TPM has already been sent the
+ * SaveState command before the driver has loaded. TCG 1.2
+ * specification states that any communication after SaveState
+ * may cause the TPM to invalidate previously saved state.
+ */
+ if (rc != TPM_WARN_RETRY)
+ break;
+ msleep(TPM_TIMEOUT_RETRY);
+ }
+
+ if (rc)
+ dev_err(chip->dev,
+ "Error (%d) sending savestate before suspend\n", rc);
+ else if (try > 0)
+ dev_warn(chip->dev, "TPM savestate took %dms\n",
+ try * TPM_TIMEOUT_RETRY);
+
return rc;
}
EXPORT_SYMBOL_GPL(tpm_pm_suspend);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 81b52015f669..0770d1d79366 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -32,10 +32,12 @@ enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
TPM_NUM_DEVICES = 256,
+ TPM_RETRY = 50, /* 5 seconds */
};
enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */
+ TPM_TIMEOUT_RETRY = 100 /* msecs */
};
/* TPM addresses */
@@ -44,6 +46,7 @@ enum tpm_addr {
TPM_ADDR = 0x4E,
};
+#define TPM_WARN_RETRY 0x800
#define TPM_WARN_DOING_SELFTEST 0x802
#define TPM_ERR_DEACTIVATED 0x6
#define TPM_ERR_DISABLED 0x7
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 8fe7ac3d095b..37d5dcc10ea7 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Infineon Technologies
+ * Copyright (C) 2012,2013 Infineon Technologies
*
* Authors:
* Peter Huewe <peter.huewe@infineon.com>
@@ -56,13 +56,21 @@
#define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000)
/* expected value for DIDVID register */
-#define TPM_TIS_I2C_DID_VID 0x000b15d1L
+#define TPM_TIS_I2C_DID_VID_9635 0xd1150b00L
+#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
+
+enum i2c_chip_type {
+ SLB9635,
+ SLB9645,
+ UNKNOWN,
+};
/* Structure to store I2C TPM specific stuff */
struct tpm_inf_dev {
struct i2c_client *client;
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */
struct tpm_chip *chip;
+ enum i2c_chip_type chip_type;
};
static struct tpm_inf_dev tpm_dev;
@@ -90,10 +98,20 @@ static struct i2c_driver tpm_tis_i2c_driver;
static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
{
- struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr };
- struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer };
+ struct i2c_msg msg1 = {
+ .addr = tpm_dev.client->addr,
+ .len = 1,
+ .buf = &addr
+ };
+ struct i2c_msg msg2 = {
+ .addr = tpm_dev.client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = buffer
+ };
+ struct i2c_msg msgs[] = {msg1, msg2};
- int rc;
+ int rc = 0;
int count;
/* Lock the adapter for the duration of the whole sequence. */
@@ -101,30 +119,53 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
return -EOPNOTSUPP;
i2c_lock_adapter(tpm_dev.client->adapter);
- for (count = 0; count < MAX_COUNT; count++) {
- rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
- if (rc > 0)
- break; /* break here to skip sleep */
-
- usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
- }
-
- if (rc <= 0)
- goto out;
-
- /* After the TPM has successfully received the register address it needs
- * some time, thus we're sleeping here again, before retrieving the data
- */
- for (count = 0; count < MAX_COUNT; count++) {
- usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
- rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
- if (rc > 0)
- break;
+ if (tpm_dev.chip_type == SLB9645) {
+ /* use a combined read for newer chips
+ * unfortunately the smbus functions are not suitable due to
+ * the 32 byte limit of the smbus.
+ * retries should usually not be needed, but are kept just to
+ * be on the safe side.
+ */
+ for (count = 0; count < MAX_COUNT; count++) {
+ rc = __i2c_transfer(tpm_dev.client->adapter, msgs, 2);
+ if (rc > 0)
+ break; /* break here to skip sleep */
+ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
+ }
+ } else {
+ /* slb9635 protocol should work in all cases */
+ for (count = 0; count < MAX_COUNT; count++) {
+ rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
+ if (rc > 0)
+ break; /* break here to skip sleep */
+
+ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
+ }
+ if (rc <= 0)
+ goto out;
+
+ /* After the TPM has successfully received the register address
+ * it needs some time, thus we're sleeping here again, before
+ * retrieving the data
+ */
+ for (count = 0; count < MAX_COUNT; count++) {
+ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
+ rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
+ if (rc > 0)
+ break;
+ }
}
out:
i2c_unlock_adapter(tpm_dev.client->adapter);
+ /* take care of 'guard time' */
+ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
+
+ /* __i2c_transfer returns the number of successfully transferred
+ * messages.
+ * So rc should be greater than 0 here otherwise we have an error.
+ */
if (rc <= 0)
return -EIO;
@@ -138,7 +179,11 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
int rc = -EIO;
int count;
- struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf };
+ struct i2c_msg msg1 = {
+ .addr = tpm_dev.client->addr,
+ .len = len + 1,
+ .buf = tpm_dev.buf
+ };
if (len > TPM_BUFSIZE)
return -EINVAL;
@@ -154,16 +199,24 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
/*
* NOTE: We have to use these special mechanisms here and unfortunately
* cannot rely on the standard behavior of i2c_transfer.
+ * Even for newer chips the smbus functions are not
+ * suitable due to the 32 byte limit of the smbus.
*/
for (count = 0; count < max_count; count++) {
rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
if (rc > 0)
break;
-
usleep_range(sleep_low, sleep_hi);
}
i2c_unlock_adapter(tpm_dev.client->adapter);
+ /* take care of 'guard time' */
+ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
+
+ /* __i2c_transfer returns the number of successfully transferred
+ * messages.
+ * So rc should be greater than 0 here otherwise we have an error.
+ */
if (rc <= 0)
return -EIO;
@@ -283,11 +336,18 @@ static int request_locality(struct tpm_chip *chip, int loc)
static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
{
/* NOTE: since I2C read may fail, return 0 in this case --> time-out */
- u8 buf;
- if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
- return 0;
- else
- return buf;
+ u8 buf = 0xFF;
+ u8 i = 0;
+
+ do {
+ if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
+ return 0;
+
+ i++;
+ /* if locallity is set STS should not be 0xFF */
+ } while ((buf == 0xFF) && i < 10);
+
+ return buf;
}
static void tpm_tis_i2c_ready(struct tpm_chip *chip)
@@ -328,7 +388,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
/* check current status */
*status = tpm_tis_i2c_status(chip);
- if ((*status & mask) == mask)
+ if ((*status != 0xFF) && (*status & mask) == mask)
return 0;
stop = jiffies + timeout;
@@ -372,7 +432,6 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
/* avoid endless loop in case of broken HW */
if (retries > MAX_COUNT_LONG)
return -EIO;
-
}
return size;
}
@@ -480,7 +539,6 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
rc = -EIO;
goto out_err;
}
-
}
/* write last byte */
@@ -568,6 +626,7 @@ static int tpm_tis_i2c_init(struct device *dev)
chip = tpm_register_hardware(dev, &tpm_tis_i2c);
if (!chip) {
+ dev_err(dev, "could not register hardware\n");
rc = -ENODEV;
goto out_err;
}
@@ -582,20 +641,24 @@ static int tpm_tis_i2c_init(struct device *dev)
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
if (request_locality(chip, 0) != 0) {
+ dev_err(dev, "could not request locality\n");
rc = -ENODEV;
goto out_vendor;
}
/* read four bytes from DID_VID register */
if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) {
+ dev_err(dev, "could not read vendor id\n");
rc = -EIO;
goto out_release;
}
- /* create DID_VID register value, after swapping to little-endian */
- vendor = be32_to_cpu((__be32) vendor);
-
- if (vendor != TPM_TIS_I2C_DID_VID) {
+ if (vendor == TPM_TIS_I2C_DID_VID_9645) {
+ tpm_dev.chip_type = SLB9645;
+ } else if (vendor == TPM_TIS_I2C_DID_VID_9635) {
+ tpm_dev.chip_type = SLB9635;
+ } else {
+ dev_err(dev, "vendor id did not match! ID was %08x\n", vendor);
rc = -ENODEV;
goto out_release;
}
@@ -631,22 +694,53 @@ out_err:
static const struct i2c_device_id tpm_tis_i2c_table[] = {
{"tpm_i2c_infineon", 0},
+ {"slb9635tt", 0},
+ {"slb9645tt", 1},
{},
};
MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tpm_tis_i2c_of_match[] = {
+ {
+ .name = "tpm_i2c_infineon",
+ .type = "tpm",
+ .compatible = "infineon,tpm_i2c_infineon",
+ .data = (void *)0
+ },
+ {
+ .name = "slb9635tt",
+ .type = "tpm",
+ .compatible = "infineon,slb9635tt",
+ .data = (void *)0
+ },
+ {
+ .name = "slb9645tt",
+ .type = "tpm",
+ .compatible = "infineon,slb9645tt",
+ .data = (void *)1
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
+#endif
+
static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume);
static int tpm_tis_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
- if (tpm_dev.client != NULL)
+ struct device *dev = &(client->dev);
+
+ if (tpm_dev.client != NULL) {
+ dev_err(dev, "This driver only supports one client at a time\n");
return -EBUSY; /* We only support one client */
+ }
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev,
- "no algorithms associated to the i2c bus\n");
+ dev_err(dev, "no algorithms associated to the i2c bus\n");
return -ENODEV;
}
@@ -682,7 +776,6 @@ static int tpm_tis_i2c_remove(struct i2c_client *client)
}
static struct i2c_driver tpm_tis_i2c_driver = {
-
.id_table = tpm_tis_i2c_table,
.probe = tpm_tis_i2c_probe,
.remove = tpm_tis_i2c_remove,
@@ -690,11 +783,12 @@ static struct i2c_driver tpm_tis_i2c_driver = {
.name = "tpm_i2c_infineon",
.owner = THIS_MODULE,
.pm = &tpm_tis_i2c_ops,
+ .of_match_table = of_match_ptr(tpm_tis_i2c_of_match),
},
};
module_i2c_driver(tpm_tis_i2c_driver);
MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>");
MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver");
-MODULE_VERSION("2.1.5");
+MODULE_VERSION("2.2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 1f5f71e14abe..5bb8e2ddd3b3 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -36,7 +36,6 @@
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -50,7 +49,6 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <linux/sched.h>
#include "tpm.h"
#include "tpm_i2c_stm_st33.h"
@@ -178,7 +176,7 @@ static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
struct i2c_client *client;
struct st33zp24_platform_data *pin_infos;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
pin_infos = client->dev.platform_data;
status = wait_for_completion_interruptible_timeout(
@@ -197,12 +195,12 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
int status = 2;
struct i2c_client *client;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
status = _wait_for_interrupt_serirq_timeout(chip, timeout);
if (!status) {
status = -EBUSY;
- } else{
+ } else {
clear_interruption(client);
if (condition)
status = 1;
@@ -219,7 +217,7 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
struct i2c_client *client;
u8 data;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
data = TPM_STS_COMMAND_READY;
I2C_WRITE_DATA(client, TPM_STS, &data, 1);
@@ -236,7 +234,7 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
{
struct i2c_client *client;
u8 data;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
I2C_READ_DATA(client, TPM_STS, &data, 1);
return data;
@@ -254,7 +252,7 @@ static int check_locality(struct tpm_chip *chip)
u8 data;
u8 status;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1);
if (status && (data &
@@ -278,7 +276,7 @@ static int request_locality(struct tpm_chip *chip)
struct i2c_client *client;
u8 data;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
if (check_locality(chip) == chip->vendor.locality)
return chip->vendor.locality;
@@ -294,7 +292,7 @@ static int request_locality(struct tpm_chip *chip)
chip->vendor.timeout_a);
if (rc > 0)
return chip->vendor.locality;
- } else{
+ } else {
stop = jiffies + chip->vendor.timeout_a;
do {
if (check_locality(chip) >= 0)
@@ -316,7 +314,7 @@ static void release_locality(struct tpm_chip *chip)
struct i2c_client *client;
u8 data;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
data = TPM_ACCESS_ACTIVE_LOCALITY;
I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
@@ -333,7 +331,7 @@ static int get_burstcount(struct tpm_chip *chip)
int burstcnt, status;
u8 tpm_reg, temp;
- struct i2c_client *client = (struct i2c_client *) TPM_VPRIV(chip);
+ struct i2c_client *client = (struct i2c_client *)TPM_VPRIV(chip);
stop = jiffies + chip->vendor.timeout_d;
do {
@@ -379,7 +377,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
mask), timeout);
if (rc > 0)
return 0;
- } else{
+ } else {
stop = jiffies + timeout;
do {
msleep(TPM_TIMEOUT);
@@ -403,7 +401,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
int size = 0, burstcnt, len;
struct i2c_client *client;
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
while (size < count &&
wait_for_stat(chip,
@@ -433,7 +431,7 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
disable_irq_nosync(irq);
- client = (struct i2c_client *) TPM_VPRIV(chip);
+ client = (struct i2c_client *)TPM_VPRIV(chip);
pin_infos = client->dev.platform_data;
complete(&pin_infos->irq_detection);
@@ -453,8 +451,7 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
size_t len)
{
- u32 status,
- burstcnt = 0, i, size;
+ u32 status, burstcnt = 0, i, size;
int ret;
u8 data;
struct i2c_client *client;
@@ -483,7 +480,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
}
}
- for (i = 0 ; i < len - 1 ;) {
+ for (i = 0; i < len - 1;) {
burstcnt = get_burstcount(chip);
size = min_t(int, len - i - 1, burstcnt);
ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
@@ -547,7 +544,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
goto out;
}
- expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ expected = be32_to_cpu(*(__be32 *)(buf + 2));
if (expected > count) {
size = -EIO;
goto out;
@@ -569,7 +566,7 @@ out:
static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
{
- return (status == TPM_STS_COMMAND_READY);
+ return (status == TPM_STS_COMMAND_READY);
}
static const struct file_operations tpm_st33_i2c_fops = {
@@ -617,7 +614,7 @@ static struct tpm_vendor_specific st_i2c_tpm = {
.miscdev = {.fops = &tpm_st33_i2c_fops,},
};
-static int interrupts ;
+static int interrupts;
module_param(interrupts, int, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
@@ -714,7 +711,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
"TPM SERIRQ management", chip);
if (err < 0) {
dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
- gpio_to_irq(platform_data->io_serirq));
+ gpio_to_irq(platform_data->io_serirq));
goto _irq_set;
}
@@ -754,7 +751,7 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_info(chip->dev, "TPM I2C Initialized\n");
return 0;
_irq_set:
- free_irq(gpio_to_irq(platform_data->io_serirq), (void *) chip);
+ free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
_gpio_init2:
if (interrupts)
gpio_free(platform_data->io_serirq);
@@ -784,7 +781,7 @@ static int tpm_st33_i2c_remove(struct i2c_client *client)
{
struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
struct st33zp24_platform_data *pin_infos =
- ((struct i2c_client *) TPM_VPRIV(chip))->dev.platform_data;
+ ((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
if (pin_infos != NULL) {
free_irq(pin_infos->io_serirq, chip);
@@ -823,9 +820,9 @@ static int tpm_st33_i2c_pm_suspend(struct device *dev)
struct st33zp24_platform_data *pin_infos = dev->platform_data;
int ret = 0;
- if (power_mgt)
+ if (power_mgt) {
gpio_set_value(pin_infos->io_lpcpd, 0);
- else{
+ } else {
if (chip->data_buffer == NULL)
chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
ret = tpm_pm_suspend(dev);
@@ -851,12 +848,12 @@ static int tpm_st33_i2c_pm_resume(struct device *dev)
(chip->vendor.status(chip) &
TPM_STS_VALID) == TPM_STS_VALID,
chip->vendor.timeout_b);
- } else{
- if (chip->data_buffer == NULL)
- chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
- ret = tpm_pm_resume(dev);
- if (!ret)
- tpm_do_selftest(chip);
+ } else {
+ if (chip->data_buffer == NULL)
+ chip->data_buffer = pin_infos->tpm_i2c_buffer[0];
+ ret = tpm_pm_resume(dev);
+ if (!ret)
+ tpm_do_selftest(chip);
}
return ret;
} /* tpm_st33_i2c_pm_resume() */
@@ -867,7 +864,8 @@ static const struct i2c_device_id tpm_st33_i2c_id[] = {
{}
};
MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
-static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend, tpm_st33_i2c_pm_resume);
+static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend,
+ tpm_st33_i2c_pm_resume);
static struct i2c_driver tpm_st33_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 720ebcf29fdf..2168d15bc728 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -158,9 +158,9 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
ACPI_TYPE_STRING);
if (ACPI_FAILURE(status))
return -ENOMEM;
- strncpy(version,
+ strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
- PPI_VERSION_LEN);
+ PPI_VERSION_LEN + 1);
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
@@ -237,9 +237,9 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
ACPI_TYPE_STRING);
if (ACPI_FAILURE(status))
return -ENOMEM;
- strncpy(version,
+ strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
- PPI_VERSION_LEN);
+ PPI_VERSION_LEN + 1);
/*
* PPI spec defines params[3].type as empty package, but some platforms
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
@@ -351,7 +351,7 @@ cleanup:
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
{
char *str = buf;
- char version[PPI_VERSION_LEN];
+ char version[PPI_VERSION_LEN + 1];
acpi_handle handle;
acpi_status status;
struct acpi_object_list input;
@@ -381,9 +381,9 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
if (ACPI_FAILURE(status))
return -ENOMEM;
- strncpy(version,
+ strlcpy(version,
((union acpi_object *)output.pointer)->string.pointer,
- PPI_VERSION_LEN);
+ PPI_VERSION_LEN + 1);
kfree(output.pointer);
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL;
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index e905d5f53051..ce5f3fc25d6d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -149,7 +149,8 @@ struct ports_device {
spinlock_t ports_lock;
/* To protect the vq operations for the control channel */
- spinlock_t cvq_lock;
+ spinlock_t c_ivq_lock;
+ spinlock_t c_ovq_lock;
/* The current config space is stored here */
struct virtio_console_config config;
@@ -569,11 +570,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
vq = portdev->c_ovq;
sg_init_one(sg, &cpkt, sizeof(cpkt));
+
+ spin_lock(&portdev->c_ovq_lock);
if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) {
virtqueue_kick(vq);
while (!virtqueue_get_buf(vq, &len))
cpu_relax();
}
+ spin_unlock(&portdev->c_ovq_lock);
return 0;
}
@@ -1436,7 +1440,7 @@ static int add_port(struct ports_device *portdev, u32 id)
* rproc_serial does not want the console port, only
* the generic port implementation.
*/
- port->host_connected = port->guest_connected = true;
+ port->host_connected = true;
else if (!use_multiport(port->portdev)) {
/*
* If we're not using multiport support,
@@ -1709,23 +1713,23 @@ static void control_work_handler(struct work_struct *work)
portdev = container_of(work, struct ports_device, control_work);
vq = portdev->c_ivq;
- spin_lock(&portdev->cvq_lock);
+ spin_lock(&portdev->c_ivq_lock);
while ((buf = virtqueue_get_buf(vq, &len))) {
- spin_unlock(&portdev->cvq_lock);
+ spin_unlock(&portdev->c_ivq_lock);
buf->len = len;
buf->offset = 0;
handle_control_message(portdev, buf);
- spin_lock(&portdev->cvq_lock);
+ spin_lock(&portdev->c_ivq_lock);
if (add_inbuf(portdev->c_ivq, buf) < 0) {
dev_warn(&portdev->vdev->dev,
"Error adding buffer to queue\n");
free_buf(buf, false);
}
}
- spin_unlock(&portdev->cvq_lock);
+ spin_unlock(&portdev->c_ivq_lock);
}
static void out_intr(struct virtqueue *vq)
@@ -1752,13 +1756,23 @@ static void in_intr(struct virtqueue *vq)
port->inbuf = get_inbuf(port);
/*
- * Don't queue up data when port is closed. This condition
+ * Normally the port should not accept data when the port is
+ * closed. For generic serial ports, the host won't (shouldn't)
+ * send data till the guest is connected. But this condition
* can be reached when a console port is not yet connected (no
- * tty is spawned) and the host sends out data to console
- * ports. For generic serial ports, the host won't
- * (shouldn't) send data till the guest is connected.
+ * tty is spawned) and the other side sends out data over the
+ * vring, or when a remote devices start sending data before
+ * the ports are opened.
+ *
+ * A generic serial port will discard data if not connected,
+ * while console ports and rproc-serial ports accepts data at
+ * any time. rproc-serial is initiated with guest_connected to
+ * false because port_fops_open expects this. Console ports are
+ * hooked up with an HVC console and is initialized with
+ * guest_connected to true.
*/
- if (!port->guest_connected)
+
+ if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
discard_port_data(port);
spin_unlock_irqrestore(&port->inbuf_lock, flags);
@@ -1986,10 +2000,12 @@ static int virtcons_probe(struct virtio_device *vdev)
if (multiport) {
unsigned int nr_added_bufs;
- spin_lock_init(&portdev->cvq_lock);
+ spin_lock_init(&portdev->c_ivq_lock);
+ spin_lock_init(&portdev->c_ovq_lock);
INIT_WORK(&portdev->control_work, &control_work_handler);
- nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+ nr_added_bufs = fill_queue(portdev->c_ivq,
+ &portdev->c_ivq_lock);
if (!nr_added_bufs) {
dev_err(&vdev->dev,
"Error allocating buffers for control queue\n");
@@ -2140,7 +2156,7 @@ static int virtcons_restore(struct virtio_device *vdev)
return ret;
if (use_multiport(portdev))
- fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+ fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
list_for_each_entry(port, &portdev->ports, list) {
port->in_vq = portdev->in_vqs[port->id];
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index a47e6ee98b8c..0357ac44638b 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -55,6 +55,16 @@ config COMMON_CLK_MAX77686
---help---
This driver supports Maxim 77686 crystal oscillator clock.
+config COMMON_CLK_SI5351
+ tristate "Clock driver for SiLabs 5351A/B/C"
+ depends on I2C
+ depends on OF
+ select REGMAP_I2C
+ select RATIONAL
+ ---help---
+ This driver supports Silicon Labs 5351A/B/C programmable clock
+ generators.
+
config CLK_TWL6040
tristate "External McPDM functional clock from twl6040"
depends on TWL6040_CORE
@@ -63,6 +73,14 @@ config CLK_TWL6040
McPDM. McPDM module is using the external bit clock on the McPDM bus
as functional clock.
+config COMMON_CLK_AXI_CLKGEN
+ tristate "AXI clkgen driver"
+ depends on ARCH_ZYNQ || MICROBLAZE
+ help
+ ---help---
+ Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
+ FPGAs. It is commonly used in Analog Devices' reference designs.
+
endmenu
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 300d4775d926..e7f7fe9b2f09 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
+obj-$(CONFIG_COMMON_CLK) += clk-composite.o
# SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
@@ -23,6 +24,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
@@ -31,6 +33,8 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_X86) += x86/
# Chip specific
+obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c
new file mode 100644
index 000000000000..8137327847c3
--- /dev/null
+++ b/drivers/clk/clk-axi-clkgen.c
@@ -0,0 +1,331 @@
+/*
+ * AXI clkgen driver
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#define AXI_CLKGEN_REG_UPDATE_ENABLE 0x04
+#define AXI_CLKGEN_REG_CLK_OUT1 0x08
+#define AXI_CLKGEN_REG_CLK_OUT2 0x0c
+#define AXI_CLKGEN_REG_CLK_DIV 0x10
+#define AXI_CLKGEN_REG_CLK_FB1 0x14
+#define AXI_CLKGEN_REG_CLK_FB2 0x18
+#define AXI_CLKGEN_REG_LOCK1 0x1c
+#define AXI_CLKGEN_REG_LOCK2 0x20
+#define AXI_CLKGEN_REG_LOCK3 0x24
+#define AXI_CLKGEN_REG_FILTER1 0x28
+#define AXI_CLKGEN_REG_FILTER2 0x2c
+
+struct axi_clkgen {
+ void __iomem *base;
+ struct clk_hw clk_hw;
+};
+
+static uint32_t axi_clkgen_lookup_filter(unsigned int m)
+{
+ switch (m) {
+ case 0:
+ return 0x01001990;
+ case 1:
+ return 0x01001190;
+ case 2:
+ return 0x01009890;
+ case 3:
+ return 0x01001890;
+ case 4:
+ return 0x01008890;
+ case 5 ... 8:
+ return 0x01009090;
+ case 9 ... 11:
+ return 0x01000890;
+ case 12:
+ return 0x08009090;
+ case 13 ... 22:
+ return 0x01001090;
+ case 23 ... 36:
+ return 0x01008090;
+ case 37 ... 46:
+ return 0x08001090;
+ default:
+ return 0x08008090;
+ }
+}
+
+static const uint32_t axi_clkgen_lock_table[] = {
+ 0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
+ 0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
+ 0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
+ 0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
+ 0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
+ 0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
+ 0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
+ 0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
+ 0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
+};
+
+static uint32_t axi_clkgen_lookup_lock(unsigned int m)
+{
+ if (m < ARRAY_SIZE(axi_clkgen_lock_table))
+ return axi_clkgen_lock_table[m];
+ return 0x1f1f00fa;
+}
+
+static const unsigned int fpfd_min = 10000;
+static const unsigned int fpfd_max = 300000;
+static const unsigned int fvco_min = 600000;
+static const unsigned int fvco_max = 1200000;
+
+static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
+ unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
+{
+ unsigned long d, d_min, d_max, _d_min, _d_max;
+ unsigned long m, m_min, m_max;
+ unsigned long f, dout, best_f, fvco;
+
+ fin /= 1000;
+ fout /= 1000;
+
+ best_f = ULONG_MAX;
+ *best_d = 0;
+ *best_m = 0;
+ *best_dout = 0;
+
+ d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
+ d_max = min_t(unsigned long, fin / fpfd_min, 80);
+
+ m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
+ m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
+
+ for (m = m_min; m <= m_max; m++) {
+ _d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
+ _d_max = min(d_max, fin * m / fvco_min);
+
+ for (d = _d_min; d <= _d_max; d++) {
+ fvco = fin * m / d;
+
+ dout = DIV_ROUND_CLOSEST(fvco, fout);
+ dout = clamp_t(unsigned long, dout, 1, 128);
+ f = fvco / dout;
+ if (abs(f - fout) < abs(best_f - fout)) {
+ best_f = f;
+ *best_d = d;
+ *best_m = m;
+ *best_dout = dout;
+ if (best_f == fout)
+ return;
+ }
+ }
+ }
+}
+
+static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
+ unsigned int *high, unsigned int *edge, unsigned int *nocount)
+{
+ if (divider == 1)
+ *nocount = 1;
+ else
+ *nocount = 0;
+
+ *high = divider / 2;
+ *edge = divider % 2;
+ *low = divider - *high;
+}
+
+static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
+ unsigned int reg, unsigned int val)
+{
+ writel(val, axi_clkgen->base + reg);
+}
+
+static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
+ unsigned int reg, unsigned int *val)
+{
+ *val = readl(axi_clkgen->base + reg);
+}
+
+static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
+{
+ return container_of(clk_hw, struct axi_clkgen, clk_hw);
+}
+
+static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+ unsigned int d, m, dout;
+ unsigned int nocount;
+ unsigned int high;
+ unsigned int edge;
+ unsigned int low;
+ uint32_t filter;
+ uint32_t lock;
+
+ if (parent_rate == 0 || rate == 0)
+ return -EINVAL;
+
+ axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
+
+ if (d == 0 || dout == 0 || m == 0)
+ return -EINVAL;
+
+ filter = axi_clkgen_lookup_filter(m - 1);
+ lock = axi_clkgen_lookup_lock(m - 1);
+
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0);
+
+ axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1,
+ (high << 6) | low);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2,
+ (edge << 7) | (nocount << 6));
+
+ axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV,
+ (edge << 13) | (nocount << 12) | (high << 6) | low);
+
+ axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1,
+ (high << 6) | low);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2,
+ (edge << 7) | (nocount << 6));
+
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2,
+ (((lock >> 16) & 0x1f) << 10) | 0x1);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3,
+ (((lock >> 24) & 0x1f) << 10) | 0x3e9);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16);
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter);
+
+ axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1);
+
+ return 0;
+}
+
+static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ unsigned int d, m, dout;
+
+ axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
+
+ if (d == 0 || dout == 0 || m == 0)
+ return -EINVAL;
+
+ return *parent_rate / d * m / dout;
+}
+
+static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
+ unsigned long parent_rate)
+{
+ struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
+ unsigned int d, m, dout;
+ unsigned int reg;
+ unsigned long long tmp;
+
+ axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, &reg);
+ dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
+ axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, &reg);
+ d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
+ axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, &reg);
+ m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
+
+ if (d == 0 || dout == 0)
+ return 0;
+
+ tmp = (unsigned long long)(parent_rate / d) * m;
+ do_div(tmp, dout);
+
+ if (tmp > ULONG_MAX)
+ return ULONG_MAX;
+
+ return tmp;
+}
+
+static const struct clk_ops axi_clkgen_ops = {
+ .recalc_rate = axi_clkgen_recalc_rate,
+ .round_rate = axi_clkgen_round_rate,
+ .set_rate = axi_clkgen_set_rate,
+};
+
+static int axi_clkgen_probe(struct platform_device *pdev)
+{
+ struct axi_clkgen *axi_clkgen;
+ struct clk_init_data init;
+ const char *parent_name;
+ const char *clk_name;
+ struct resource *mem;
+ struct clk *clk;
+
+ axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
+ if (!axi_clkgen)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(axi_clkgen->base))
+ return PTR_ERR(axi_clkgen->base);
+
+ parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
+ if (!parent_name)
+ return -EINVAL;
+
+ clk_name = pdev->dev.of_node->name;
+ of_property_read_string(pdev->dev.of_node, "clock-output-names",
+ &clk_name);
+
+ init.name = clk_name;
+ init.ops = &axi_clkgen_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ axi_clkgen->clk_hw.init = &init;
+ clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
+ clk);
+}
+
+static int axi_clkgen_remove(struct platform_device *pdev)
+{
+ of_clk_del_provider(pdev->dev.of_node);
+
+ return 0;
+}
+
+static const struct of_device_id axi_clkgen_ids[] = {
+ { .compatible = "adi,axi-clkgen-1.00.a" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
+
+static struct platform_driver axi_clkgen_driver = {
+ .driver = {
+ .name = "adi-axi-clkgen",
+ .owner = THIS_MODULE,
+ .of_match_table = axi_clkgen_ids,
+ },
+ .probe = axi_clkgen_probe,
+ .remove = axi_clkgen_remove,
+};
+module_platform_driver(axi_clkgen_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
new file mode 100644
index 000000000000..a33f46f20a41
--- /dev/null
+++ b/drivers/clk/clk-composite.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013 NVIDIA CORPORATION. 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/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
+
+static u8 clk_composite_get_parent(struct clk_hw *hw)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mux_ops = composite->mux_ops;
+ struct clk_hw *mux_hw = composite->mux_hw;
+
+ mux_hw->clk = hw->clk;
+
+ return mux_ops->get_parent(mux_hw);
+}
+
+static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *mux_ops = composite->mux_ops;
+ struct clk_hw *mux_hw = composite->mux_hw;
+
+ mux_hw->clk = hw->clk;
+
+ return mux_ops->set_parent(mux_hw, index);
+}
+
+static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *rate_ops = composite->rate_ops;
+ struct clk_hw *rate_hw = composite->rate_hw;
+
+ rate_hw->clk = hw->clk;
+
+ return rate_ops->recalc_rate(rate_hw, parent_rate);
+}
+
+static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *rate_ops = composite->rate_ops;
+ struct clk_hw *rate_hw = composite->rate_hw;
+
+ rate_hw->clk = hw->clk;
+
+ return rate_ops->round_rate(rate_hw, rate, prate);
+}
+
+static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *rate_ops = composite->rate_ops;
+ struct clk_hw *rate_hw = composite->rate_hw;
+
+ rate_hw->clk = hw->clk;
+
+ return rate_ops->set_rate(rate_hw, rate, parent_rate);
+}
+
+static int clk_composite_is_enabled(struct clk_hw *hw)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->is_enabled(gate_hw);
+}
+
+static int clk_composite_enable(struct clk_hw *hw)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ return gate_ops->enable(gate_hw);
+}
+
+static void clk_composite_disable(struct clk_hw *hw)
+{
+ struct clk_composite *composite = to_clk_composite(hw);
+ const struct clk_ops *gate_ops = composite->gate_ops;
+ struct clk_hw *gate_hw = composite->gate_hw;
+
+ gate_hw->clk = hw->clk;
+
+ gate_ops->disable(gate_hw);
+}
+
+struct clk *clk_register_composite(struct device *dev, const char *name,
+ const char **parent_names, int num_parents,
+ struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+ struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+ unsigned long flags)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct clk_composite *composite;
+ struct clk_ops *clk_composite_ops;
+
+ composite = kzalloc(sizeof(*composite), GFP_KERNEL);
+ if (!composite) {
+ pr_err("%s: could not allocate composite clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+
+ clk_composite_ops = &composite->ops;
+
+ if (mux_hw && mux_ops) {
+ if (!mux_ops->get_parent || !mux_ops->set_parent) {
+ clk = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ composite->mux_hw = mux_hw;
+ composite->mux_ops = mux_ops;
+ clk_composite_ops->get_parent = clk_composite_get_parent;
+ clk_composite_ops->set_parent = clk_composite_set_parent;
+ }
+
+ if (rate_hw && rate_ops) {
+ if (!rate_ops->recalc_rate) {
+ clk = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ /* .round_rate is a prerequisite for .set_rate */
+ if (rate_ops->round_rate) {
+ clk_composite_ops->round_rate = clk_composite_round_rate;
+ if (rate_ops->set_rate) {
+ clk_composite_ops->set_rate = clk_composite_set_rate;
+ }
+ } else {
+ WARN(rate_ops->set_rate,
+ "%s: missing round_rate op is required\n",
+ __func__);
+ }
+
+ composite->rate_hw = rate_hw;
+ composite->rate_ops = rate_ops;
+ clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
+ }
+
+ if (gate_hw && gate_ops) {
+ if (!gate_ops->is_enabled || !gate_ops->enable ||
+ !gate_ops->disable) {
+ clk = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ composite->gate_hw = gate_hw;
+ composite->gate_ops = gate_ops;
+ clk_composite_ops->is_enabled = clk_composite_is_enabled;
+ clk_composite_ops->enable = clk_composite_enable;
+ clk_composite_ops->disable = clk_composite_disable;
+ }
+
+ init.ops = clk_composite_ops;
+ composite->hw.init = &init;
+
+ clk = clk_register(dev, &composite->hw);
+ if (IS_ERR(clk))
+ goto err;
+
+ if (composite->mux_hw)
+ composite->mux_hw->clk = clk;
+
+ if (composite->rate_hw)
+ composite->rate_hw->clk = clk;
+
+ if (composite->gate_hw)
+ composite->gate_hw->clk = clk;
+
+ return clk;
+
+err:
+ kfree(composite);
+ return clk;
+}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 68b402101170..6d9674160430 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -109,8 +109,9 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
div = _get_div(divider, val);
if (!div) {
- WARN(1, "%s: Invalid divisor for clock %s\n", __func__,
- __clk_get_name(hw->clk));
+ WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+ "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+ __clk_get_name(hw->clk));
return parent_rate;
}
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 1ef271e47594..9ff7d510faa3 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -11,6 +11,7 @@
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
/*
* DOC: basic fixed multiplier and divider clock that cannot gate
@@ -96,3 +97,38 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
return clk;
}
+#ifdef CONFIG_OF
+/**
+ * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
+ */
+void __init of_fixed_factor_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ u32 div, mult;
+
+ if (of_property_read_u32(node, "clock-div", &div)) {
+ pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
+ __func__, node->name);
+ return;
+ }
+
+ if (of_property_read_u32(node, "clock-mult", &mult)) {
+ pr_err("%s Fixed factor clock <%s> must have a clokc-mult property\n",
+ __func__, node->name);
+ return;
+ }
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent_name = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
+ mult, div);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
+CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
+ of_fixed_factor_clk_setup);
+#endif
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 508c032edce4..25b1734560d0 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -32,6 +32,7 @@
static u8 clk_mux_get_parent(struct clk_hw *hw)
{
struct clk_mux *mux = to_clk_mux(hw);
+ int num_parents = __clk_get_num_parents(hw->clk);
u32 val;
/*
@@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
* val = 0x4 really means "bit 2, index starts at bit 0"
*/
val = readl(mux->reg) >> mux->shift;
- val &= (1 << mux->width) - 1;
+ val &= mux->mask;
+
+ if (mux->table) {
+ int i;
+
+ for (i = 0; i < num_parents; i++)
+ if (mux->table[i] == val)
+ return i;
+ return -EINVAL;
+ }
if (val && (mux->flags & CLK_MUX_INDEX_BIT))
val = ffs(val) - 1;
@@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
if (val && (mux->flags & CLK_MUX_INDEX_ONE))
val--;
- if (val >= __clk_get_num_parents(hw->clk))
+ if (val >= num_parents)
return -EINVAL;
return val;
@@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
u32 val;
unsigned long flags = 0;
- if (mux->flags & CLK_MUX_INDEX_BIT)
- index = (1 << ffs(index));
+ if (mux->table)
+ index = mux->table[index];
- if (mux->flags & CLK_MUX_INDEX_ONE)
- index++;
+ else {
+ if (mux->flags & CLK_MUX_INDEX_BIT)
+ index = (1 << ffs(index));
+
+ if (mux->flags & CLK_MUX_INDEX_ONE)
+ index++;
+ }
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
val = readl(mux->reg);
- val &= ~(((1 << mux->width) - 1) << mux->shift);
+ val &= ~(mux->mask << mux->shift);
val |= index << mux->shift;
writel(val, mux->reg);
@@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
};
EXPORT_SYMBOL_GPL(clk_mux_ops);
-struct clk *clk_register_mux(struct device *dev, const char *name,
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
- u8 clk_mux_flags, spinlock_t *lock)
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{
struct clk_mux *mux;
struct clk *clk;
@@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
/* struct clk_mux assignments */
mux->reg = reg;
mux->shift = shift;
- mux->width = width;
+ mux->mask = mask;
mux->flags = clk_mux_flags;
mux->lock = lock;
+ mux->table = table;
mux->hw.init = &init;
clk = clk_register(dev, &mux->hw);
@@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
return clk;
}
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u8 width,
+ u8 clk_mux_flags, spinlock_t *lock)
+{
+ u32 mask = BIT(width) - 1;
+
+ return clk_register_mux_table(dev, name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags,
+ NULL, lock);
+}
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index f8e9d0c27be2..643ca653fef0 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1113,7 +1113,7 @@ void __init sirfsoc_of_clk_init(void)
for (i = pll1; i < maxclk; i++) {
prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
- BUG_ON(!prima2_clks[i]);
+ BUG_ON(IS_ERR(prima2_clks[i]));
}
clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
clk_register_clkdev(prima2_clks[io], NULL, "io");
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
new file mode 100644
index 000000000000..892728412e9d
--- /dev/null
+++ b/drivers/clk/clk-si5351.c
@@ -0,0 +1,1510 @@
+/*
+ * clk-si5351.c: Silicon Laboratories Si5351A/B/C I2C Clock Generator
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Rabeeh Khoury <rabeeh@solid-run.com>
+ *
+ * References:
+ * [1] "Si5351A/B/C Data Sheet"
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
+ * [2] "Manually Generating an Si5351 Register Map"
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
+ *
+ * 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/kernel.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/rational.h>
+#include <linux/i2c.h>
+#include <linux/of_platform.h>
+#include <linux/platform_data/si5351.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <asm/div64.h>
+
+#include "clk-si5351.h"
+
+struct si5351_driver_data;
+
+struct si5351_parameters {
+ unsigned long p1;
+ unsigned long p2;
+ unsigned long p3;
+ int valid;
+};
+
+struct si5351_hw_data {
+ struct clk_hw hw;
+ struct si5351_driver_data *drvdata;
+ struct si5351_parameters params;
+ unsigned char num;
+};
+
+struct si5351_driver_data {
+ enum si5351_variant variant;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct clk_onecell_data onecell;
+
+ struct clk *pxtal;
+ const char *pxtal_name;
+ struct clk_hw xtal;
+ struct clk *pclkin;
+ const char *pclkin_name;
+ struct clk_hw clkin;
+
+ struct si5351_hw_data pll[2];
+ struct si5351_hw_data *msynth;
+ struct si5351_hw_data *clkout;
+};
+
+static const char const *si5351_input_names[] = {
+ "xtal", "clkin"
+};
+static const char const *si5351_pll_names[] = {
+ "plla", "pllb", "vxco"
+};
+static const char const *si5351_msynth_names[] = {
+ "ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7"
+};
+static const char const *si5351_clkout_names[] = {
+ "clk0", "clk1", "clk2", "clk3", "clk4", "clk5", "clk6", "clk7"
+};
+
+/*
+ * Si5351 i2c regmap
+ */
+static inline u8 si5351_reg_read(struct si5351_driver_data *drvdata, u8 reg)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(drvdata->regmap, reg, &val);
+ if (ret) {
+ dev_err(&drvdata->client->dev,
+ "unable to read from reg%02x\n", reg);
+ return 0;
+ }
+
+ return (u8)val;
+}
+
+static inline int si5351_bulk_read(struct si5351_driver_data *drvdata,
+ u8 reg, u8 count, u8 *buf)
+{
+ return regmap_bulk_read(drvdata->regmap, reg, buf, count);
+}
+
+static inline int si5351_reg_write(struct si5351_driver_data *drvdata,
+ u8 reg, u8 val)
+{
+ return regmap_write(drvdata->regmap, reg, val);
+}
+
+static inline int si5351_bulk_write(struct si5351_driver_data *drvdata,
+ u8 reg, u8 count, const u8 *buf)
+{
+ return regmap_raw_write(drvdata->regmap, reg, buf, count);
+}
+
+static inline int si5351_set_bits(struct si5351_driver_data *drvdata,
+ u8 reg, u8 mask, u8 val)
+{
+ return regmap_update_bits(drvdata->regmap, reg, mask, val);
+}
+
+static inline u8 si5351_msynth_params_address(int num)
+{
+ if (num > 5)
+ return SI5351_CLK6_PARAMETERS + (num - 6);
+ return SI5351_CLK0_PARAMETERS + (SI5351_PARAMETERS_LENGTH * num);
+}
+
+static void si5351_read_parameters(struct si5351_driver_data *drvdata,
+ u8 reg, struct si5351_parameters *params)
+{
+ u8 buf[SI5351_PARAMETERS_LENGTH];
+
+ switch (reg) {
+ case SI5351_CLK6_PARAMETERS:
+ case SI5351_CLK7_PARAMETERS:
+ buf[0] = si5351_reg_read(drvdata, reg);
+ params->p1 = buf[0];
+ params->p2 = 0;
+ params->p3 = 1;
+ break;
+ default:
+ si5351_bulk_read(drvdata, reg, SI5351_PARAMETERS_LENGTH, buf);
+ params->p1 = ((buf[2] & 0x03) << 16) | (buf[3] << 8) | buf[4];
+ params->p2 = ((buf[5] & 0x0f) << 16) | (buf[6] << 8) | buf[7];
+ params->p3 = ((buf[5] & 0xf0) << 12) | (buf[0] << 8) | buf[1];
+ }
+ params->valid = 1;
+}
+
+static void si5351_write_parameters(struct si5351_driver_data *drvdata,
+ u8 reg, struct si5351_parameters *params)
+{
+ u8 buf[SI5351_PARAMETERS_LENGTH];
+
+ switch (reg) {
+ case SI5351_CLK6_PARAMETERS:
+ case SI5351_CLK7_PARAMETERS:
+ buf[0] = params->p1 & 0xff;
+ si5351_reg_write(drvdata, reg, buf[0]);
+ break;
+ default:
+ buf[0] = ((params->p3 & 0x0ff00) >> 8) & 0xff;
+ buf[1] = params->p3 & 0xff;
+ /* save rdiv and divby4 */
+ buf[2] = si5351_reg_read(drvdata, reg + 2) & ~0x03;
+ buf[2] |= ((params->p1 & 0x30000) >> 16) & 0x03;
+ buf[3] = ((params->p1 & 0x0ff00) >> 8) & 0xff;
+ buf[4] = params->p1 & 0xff;
+ buf[5] = ((params->p3 & 0xf0000) >> 12) |
+ ((params->p2 & 0xf0000) >> 16);
+ buf[6] = ((params->p2 & 0x0ff00) >> 8) & 0xff;
+ buf[7] = params->p2 & 0xff;
+ si5351_bulk_write(drvdata, reg, SI5351_PARAMETERS_LENGTH, buf);
+ }
+}
+
+static bool si5351_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SI5351_DEVICE_STATUS:
+ case SI5351_INTERRUPT_STATUS:
+ case SI5351_PLL_RESET:
+ return true;
+ }
+ return false;
+}
+
+static bool si5351_regmap_is_writeable(struct device *dev, unsigned int reg)
+{
+ /* reserved registers */
+ if (reg >= 4 && reg <= 8)
+ return false;
+ if (reg >= 10 && reg <= 14)
+ return false;
+ if (reg >= 173 && reg <= 176)
+ return false;
+ if (reg >= 178 && reg <= 182)
+ return false;
+ /* read-only */
+ if (reg == SI5351_DEVICE_STATUS)
+ return false;
+ return true;
+}
+
+static struct regmap_config si5351_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .max_register = 187,
+ .writeable_reg = si5351_regmap_is_writeable,
+ .volatile_reg = si5351_regmap_is_volatile,
+};
+
+/*
+ * Si5351 xtal clock input
+ */
+static int si5351_xtal_prepare(struct clk_hw *hw)
+{
+ struct si5351_driver_data *drvdata =
+ container_of(hw, struct si5351_driver_data, xtal);
+ si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
+ SI5351_XTAL_ENABLE, SI5351_XTAL_ENABLE);
+ return 0;
+}
+
+static void si5351_xtal_unprepare(struct clk_hw *hw)
+{
+ struct si5351_driver_data *drvdata =
+ container_of(hw, struct si5351_driver_data, xtal);
+ si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
+ SI5351_XTAL_ENABLE, 0);
+}
+
+static const struct clk_ops si5351_xtal_ops = {
+ .prepare = si5351_xtal_prepare,
+ .unprepare = si5351_xtal_unprepare,
+};
+
+/*
+ * Si5351 clkin clock input (Si5351C only)
+ */
+static int si5351_clkin_prepare(struct clk_hw *hw)
+{
+ struct si5351_driver_data *drvdata =
+ container_of(hw, struct si5351_driver_data, clkin);
+ si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
+ SI5351_CLKIN_ENABLE, SI5351_CLKIN_ENABLE);
+ return 0;
+}
+
+static void si5351_clkin_unprepare(struct clk_hw *hw)
+{
+ struct si5351_driver_data *drvdata =
+ container_of(hw, struct si5351_driver_data, clkin);
+ si5351_set_bits(drvdata, SI5351_FANOUT_ENABLE,
+ SI5351_CLKIN_ENABLE, 0);
+}
+
+/*
+ * CMOS clock source constraints:
+ * The input frequency range of the PLL is 10Mhz to 40MHz.
+ * If CLKIN is >40MHz, the input divider must be used.
+ */
+static unsigned long si5351_clkin_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct si5351_driver_data *drvdata =
+ container_of(hw, struct si5351_driver_data, clkin);
+ unsigned long rate;
+ unsigned char idiv;
+
+ rate = parent_rate;
+ if (parent_rate > 160000000) {
+ idiv = SI5351_CLKIN_DIV_8;
+ rate /= 8;
+ } else if (parent_rate > 80000000) {
+ idiv = SI5351_CLKIN_DIV_4;
+ rate /= 4;
+ } else if (parent_rate > 40000000) {
+ idiv = SI5351_CLKIN_DIV_2;
+ rate /= 2;
+ } else {
+ idiv = SI5351_CLKIN_DIV_1;
+ }
+
+ si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
+ SI5351_CLKIN_DIV_MASK, idiv);
+
+ dev_dbg(&drvdata->client->dev, "%s - clkin div = %d, rate = %lu\n",
+ __func__, (1 << (idiv >> 6)), rate);
+
+ return rate;
+}
+
+static const struct clk_ops si5351_clkin_ops = {
+ .prepare = si5351_clkin_prepare,
+ .unprepare = si5351_clkin_unprepare,
+ .recalc_rate = si5351_clkin_recalc_rate,
+};
+
+/*
+ * Si5351 vxco clock input (Si5351B only)
+ */
+
+static int si5351_vxco_prepare(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+
+ dev_warn(&hwdata->drvdata->client->dev, "VXCO currently unsupported\n");
+
+ return 0;
+}
+
+static void si5351_vxco_unprepare(struct clk_hw *hw)
+{
+}
+
+static unsigned long si5351_vxco_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+static int si5351_vxco_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent)
+{
+ return 0;
+}
+
+static const struct clk_ops si5351_vxco_ops = {
+ .prepare = si5351_vxco_prepare,
+ .unprepare = si5351_vxco_unprepare,
+ .recalc_rate = si5351_vxco_recalc_rate,
+ .set_rate = si5351_vxco_set_rate,
+};
+
+/*
+ * Si5351 pll a/b
+ *
+ * Feedback Multisynth Divider Equations [2]
+ *
+ * fVCO = fIN * (a + b/c)
+ *
+ * with 15 + 0/1048575 <= (a + b/c) <= 90 + 0/1048575 and
+ * fIN = fXTAL or fIN = fCLKIN/CLKIN_DIV
+ *
+ * Feedback Multisynth Register Equations
+ *
+ * (1) MSNx_P1[17:0] = 128 * a + floor(128 * b/c) - 512
+ * (2) MSNx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
+ * (3) MSNx_P3[19:0] = c
+ *
+ * Transposing (2) yields: (4) floor(128 * b/c) = (128 * b / MSNx_P2)/c
+ *
+ * Using (4) on (1) yields:
+ * MSNx_P1 = 128 * a + (128 * b/MSNx_P2)/c - 512
+ * MSNx_P1 + 512 + MSNx_P2/c = 128 * a + 128 * b/c
+ *
+ * a + b/c = (MSNx_P1 + MSNx_P2/MSNx_P3 + 512)/128
+ * = (MSNx_P1*MSNx_P3 + MSNx_P2 + 512*MSNx_P3)/(128*MSNx_P3)
+ *
+ */
+static int _si5351_pll_reparent(struct si5351_driver_data *drvdata,
+ int num, enum si5351_pll_src parent)
+{
+ u8 mask = (num == 0) ? SI5351_PLLA_SOURCE : SI5351_PLLB_SOURCE;
+
+ if (parent == SI5351_PLL_SRC_DEFAULT)
+ return 0;
+
+ if (num > 2)
+ return -EINVAL;
+
+ if (drvdata->variant != SI5351_VARIANT_C &&
+ parent != SI5351_PLL_SRC_XTAL)
+ return -EINVAL;
+
+ si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE, mask,
+ (parent == SI5351_PLL_SRC_XTAL) ? 0 : mask);
+ return 0;
+}
+
+static unsigned char si5351_pll_get_parent(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 mask = (hwdata->num == 0) ? SI5351_PLLA_SOURCE : SI5351_PLLB_SOURCE;
+ u8 val;
+
+ val = si5351_reg_read(hwdata->drvdata, SI5351_PLL_INPUT_SOURCE);
+
+ return (val & mask) ? 1 : 0;
+}
+
+static int si5351_pll_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+
+ if (hwdata->drvdata->variant != SI5351_VARIANT_C &&
+ index > 0)
+ return -EPERM;
+
+ if (index > 1)
+ return -EINVAL;
+
+ return _si5351_pll_reparent(hwdata->drvdata, hwdata->num,
+ (index == 0) ? SI5351_PLL_SRC_XTAL :
+ SI5351_PLL_SRC_CLKIN);
+}
+
+static unsigned long si5351_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 reg = (hwdata->num == 0) ? SI5351_PLLA_PARAMETERS :
+ SI5351_PLLB_PARAMETERS;
+ unsigned long long rate;
+
+ if (!hwdata->params.valid)
+ si5351_read_parameters(hwdata->drvdata, reg, &hwdata->params);
+
+ if (hwdata->params.p3 == 0)
+ return parent_rate;
+
+ /* fVCO = fIN * (P1*P3 + 512*P3 + P2)/(128*P3) */
+ rate = hwdata->params.p1 * hwdata->params.p3;
+ rate += 512 * hwdata->params.p3;
+ rate += hwdata->params.p2;
+ rate *= parent_rate;
+ do_div(rate, 128 * hwdata->params.p3);
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk),
+ hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
+ parent_rate, (unsigned long)rate);
+
+ return (unsigned long)rate;
+}
+
+static long si5351_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ unsigned long rfrac, denom, a, b, c;
+ unsigned long long lltmp;
+
+ if (rate < SI5351_PLL_VCO_MIN)
+ rate = SI5351_PLL_VCO_MIN;
+ if (rate > SI5351_PLL_VCO_MAX)
+ rate = SI5351_PLL_VCO_MAX;
+
+ /* determine integer part of feedback equation */
+ a = rate / *parent_rate;
+
+ if (a < SI5351_PLL_A_MIN)
+ rate = *parent_rate * SI5351_PLL_A_MIN;
+ if (a > SI5351_PLL_A_MAX)
+ rate = *parent_rate * SI5351_PLL_A_MAX;
+
+ /* find best approximation for b/c = fVCO mod fIN */
+ denom = 1000 * 1000;
+ lltmp = rate % (*parent_rate);
+ lltmp *= denom;
+ do_div(lltmp, *parent_rate);
+ rfrac = (unsigned long)lltmp;
+
+ b = 0;
+ c = 1;
+ if (rfrac)
+ rational_best_approximation(rfrac, denom,
+ SI5351_PLL_B_MAX, SI5351_PLL_C_MAX, &b, &c);
+
+ /* calculate parameters */
+ hwdata->params.p3 = c;
+ hwdata->params.p2 = (128 * b) % c;
+ hwdata->params.p1 = 128 * a;
+ hwdata->params.p1 += (128 * b / c);
+ hwdata->params.p1 -= 512;
+
+ /* recalculate rate by fIN * (a + b/c) */
+ lltmp = *parent_rate;
+ lltmp *= b;
+ do_div(lltmp, c);
+
+ rate = (unsigned long)lltmp;
+ rate += *parent_rate * a;
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: a = %lu, b = %lu, c = %lu, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk), a, b, c,
+ *parent_rate, rate);
+
+ return rate;
+}
+
+static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 reg = (hwdata->num == 0) ? SI5351_PLLA_PARAMETERS :
+ SI5351_PLLB_PARAMETERS;
+
+ /* write multisynth parameters */
+ si5351_write_parameters(hwdata->drvdata, reg, &hwdata->params);
+
+ /* plla/pllb ctrl is in clk6/clk7 ctrl registers */
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK6_CTRL + hwdata->num,
+ SI5351_CLK_INTEGER_MODE,
+ (hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk),
+ hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
+ parent_rate, rate);
+
+ return 0;
+}
+
+static const struct clk_ops si5351_pll_ops = {
+ .set_parent = si5351_pll_set_parent,
+ .get_parent = si5351_pll_get_parent,
+ .recalc_rate = si5351_pll_recalc_rate,
+ .round_rate = si5351_pll_round_rate,
+ .set_rate = si5351_pll_set_rate,
+};
+
+/*
+ * Si5351 multisync divider
+ *
+ * for fOUT <= 150 MHz:
+ *
+ * fOUT = (fIN * (a + b/c)) / CLKOUTDIV
+ *
+ * with 6 + 0/1048575 <= (a + b/c) <= 1800 + 0/1048575 and
+ * fIN = fVCO0, fVCO1
+ *
+ * Output Clock Multisynth Register Equations
+ *
+ * MSx_P1[17:0] = 128 * a + floor(128 * b/c) - 512
+ * MSx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
+ * MSx_P3[19:0] = c
+ *
+ * MS[6,7] are integer (P1) divide only, P2 = 0, P3 = 0
+ *
+ * for 150MHz < fOUT <= 160MHz:
+ *
+ * MSx_P1 = 0, MSx_P2 = 0, MSx_P3 = 1, MSx_INT = 1, MSx_DIVBY4 = 11b
+ */
+static int _si5351_msynth_reparent(struct si5351_driver_data *drvdata,
+ int num, enum si5351_multisynth_src parent)
+{
+ if (parent == SI5351_MULTISYNTH_SRC_DEFAULT)
+ return 0;
+
+ if (num > 8)
+ return -EINVAL;
+
+ si5351_set_bits(drvdata, SI5351_CLK0_CTRL + num, SI5351_CLK_PLL_SELECT,
+ (parent == SI5351_MULTISYNTH_SRC_VCO0) ? 0 :
+ SI5351_CLK_PLL_SELECT);
+ return 0;
+}
+
+static unsigned char si5351_msynth_get_parent(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 val;
+
+ val = si5351_reg_read(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num);
+
+ return (val & SI5351_CLK_PLL_SELECT) ? 1 : 0;
+}
+
+static int si5351_msynth_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+
+ return _si5351_msynth_reparent(hwdata->drvdata, hwdata->num,
+ (index == 0) ? SI5351_MULTISYNTH_SRC_VCO0 :
+ SI5351_MULTISYNTH_SRC_VCO1);
+}
+
+static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 reg = si5351_msynth_params_address(hwdata->num);
+ unsigned long long rate;
+ unsigned long m;
+
+ if (!hwdata->params.valid)
+ si5351_read_parameters(hwdata->drvdata, reg, &hwdata->params);
+
+ if (hwdata->params.p3 == 0)
+ return parent_rate;
+
+ /*
+ * multisync0-5: fOUT = (128 * P3 * fIN) / (P1*P3 + P2 + 512*P3)
+ * multisync6-7: fOUT = fIN / P1
+ */
+ rate = parent_rate;
+ if (hwdata->num > 5) {
+ m = hwdata->params.p1;
+ } else if ((si5351_reg_read(hwdata->drvdata, reg + 2) &
+ SI5351_OUTPUT_CLK_DIVBY4) == SI5351_OUTPUT_CLK_DIVBY4) {
+ m = 4;
+ } else {
+ rate *= 128 * hwdata->params.p3;
+ m = hwdata->params.p1 * hwdata->params.p3;
+ m += hwdata->params.p2;
+ m += 512 * hwdata->params.p3;
+ }
+
+ if (m == 0)
+ return 0;
+ do_div(rate, m);
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, m = %lu, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk),
+ hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
+ m, parent_rate, (unsigned long)rate);
+
+ return (unsigned long)rate;
+}
+
+static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ unsigned long long lltmp;
+ unsigned long a, b, c;
+ int divby4;
+
+ /* multisync6-7 can only handle freqencies < 150MHz */
+ if (hwdata->num >= 6 && rate > SI5351_MULTISYNTH67_MAX_FREQ)
+ rate = SI5351_MULTISYNTH67_MAX_FREQ;
+
+ /* multisync frequency is 1MHz .. 160MHz */
+ if (rate > SI5351_MULTISYNTH_MAX_FREQ)
+ rate = SI5351_MULTISYNTH_MAX_FREQ;
+ if (rate < SI5351_MULTISYNTH_MIN_FREQ)
+ rate = SI5351_MULTISYNTH_MIN_FREQ;
+
+ divby4 = 0;
+ if (rate > SI5351_MULTISYNTH_DIVBY4_FREQ)
+ divby4 = 1;
+
+ /* multisync can set pll */
+ if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
+ /*
+ * find largest integer divider for max
+ * vco frequency and given target rate
+ */
+ if (divby4 == 0) {
+ lltmp = SI5351_PLL_VCO_MAX;
+ do_div(lltmp, rate);
+ a = (unsigned long)lltmp;
+ } else
+ a = 4;
+
+ b = 0;
+ c = 1;
+
+ *parent_rate = a * rate;
+ } else {
+ unsigned long rfrac, denom;
+
+ /* disable divby4 */
+ if (divby4) {
+ rate = SI5351_MULTISYNTH_DIVBY4_FREQ;
+ divby4 = 0;
+ }
+
+ /* determine integer part of divider equation */
+ a = *parent_rate / rate;
+ if (a < SI5351_MULTISYNTH_A_MIN)
+ a = SI5351_MULTISYNTH_A_MIN;
+ if (hwdata->num >= 6 && a > SI5351_MULTISYNTH67_A_MAX)
+ a = SI5351_MULTISYNTH67_A_MAX;
+ else if (a > SI5351_MULTISYNTH_A_MAX)
+ a = SI5351_MULTISYNTH_A_MAX;
+
+ /* find best approximation for b/c = fVCO mod fOUT */
+ denom = 1000 * 1000;
+ lltmp = (*parent_rate) % rate;
+ lltmp *= denom;
+ do_div(lltmp, rate);
+ rfrac = (unsigned long)lltmp;
+
+ b = 0;
+ c = 1;
+ if (rfrac)
+ rational_best_approximation(rfrac, denom,
+ SI5351_MULTISYNTH_B_MAX, SI5351_MULTISYNTH_C_MAX,
+ &b, &c);
+ }
+
+ /* recalculate rate by fOUT = fIN / (a + b/c) */
+ lltmp = *parent_rate;
+ lltmp *= c;
+ do_div(lltmp, a * c + b);
+ rate = (unsigned long)lltmp;
+
+ /* calculate parameters */
+ if (divby4) {
+ hwdata->params.p3 = 1;
+ hwdata->params.p2 = 0;
+ hwdata->params.p1 = 0;
+ } else {
+ hwdata->params.p3 = c;
+ hwdata->params.p2 = (128 * b) % c;
+ hwdata->params.p1 = 128 * a;
+ hwdata->params.p1 += (128 * b / c);
+ hwdata->params.p1 -= 512;
+ }
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: a = %lu, b = %lu, c = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk), a, b, c, divby4,
+ *parent_rate, rate);
+
+ return rate;
+}
+
+static int si5351_msynth_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ u8 reg = si5351_msynth_params_address(hwdata->num);
+ int divby4 = 0;
+
+ /* write multisynth parameters */
+ si5351_write_parameters(hwdata->drvdata, reg, &hwdata->params);
+
+ if (rate > SI5351_MULTISYNTH_DIVBY4_FREQ)
+ divby4 = 1;
+
+ /* enable/disable integer mode and divby4 on multisynth0-5 */
+ if (hwdata->num < 6) {
+ si5351_set_bits(hwdata->drvdata, reg + 2,
+ SI5351_OUTPUT_CLK_DIVBY4,
+ (divby4) ? SI5351_OUTPUT_CLK_DIVBY4 : 0);
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
+ SI5351_CLK_INTEGER_MODE,
+ (hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
+ }
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk),
+ hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
+ divby4, parent_rate, rate);
+
+ return 0;
+}
+
+static const struct clk_ops si5351_msynth_ops = {
+ .set_parent = si5351_msynth_set_parent,
+ .get_parent = si5351_msynth_get_parent,
+ .recalc_rate = si5351_msynth_recalc_rate,
+ .round_rate = si5351_msynth_round_rate,
+ .set_rate = si5351_msynth_set_rate,
+};
+
+/*
+ * Si5351 clkout divider
+ */
+static int _si5351_clkout_reparent(struct si5351_driver_data *drvdata,
+ int num, enum si5351_clkout_src parent)
+{
+ u8 val;
+
+ if (num > 8)
+ return -EINVAL;
+
+ switch (parent) {
+ case SI5351_CLKOUT_SRC_MSYNTH_N:
+ val = SI5351_CLK_INPUT_MULTISYNTH_N;
+ break;
+ case SI5351_CLKOUT_SRC_MSYNTH_0_4:
+ /* clk0/clk4 can only connect to its own multisync */
+ if (num == 0 || num == 4)
+ val = SI5351_CLK_INPUT_MULTISYNTH_N;
+ else
+ val = SI5351_CLK_INPUT_MULTISYNTH_0_4;
+ break;
+ case SI5351_CLKOUT_SRC_XTAL:
+ val = SI5351_CLK_INPUT_XTAL;
+ break;
+ case SI5351_CLKOUT_SRC_CLKIN:
+ if (drvdata->variant != SI5351_VARIANT_C)
+ return -EINVAL;
+
+ val = SI5351_CLK_INPUT_CLKIN;
+ break;
+ default:
+ return 0;
+ }
+
+ si5351_set_bits(drvdata, SI5351_CLK0_CTRL + num,
+ SI5351_CLK_INPUT_MASK, val);
+ return 0;
+}
+
+static int _si5351_clkout_set_drive_strength(
+ struct si5351_driver_data *drvdata, int num,
+ enum si5351_drive_strength drive)
+{
+ u8 mask;
+
+ if (num > 8)
+ return -EINVAL;
+
+ switch (drive) {
+ case SI5351_DRIVE_2MA:
+ mask = SI5351_CLK_DRIVE_STRENGTH_2MA;
+ break;
+ case SI5351_DRIVE_4MA:
+ mask = SI5351_CLK_DRIVE_STRENGTH_4MA;
+ break;
+ case SI5351_DRIVE_6MA:
+ mask = SI5351_CLK_DRIVE_STRENGTH_6MA;
+ break;
+ case SI5351_DRIVE_8MA:
+ mask = SI5351_CLK_DRIVE_STRENGTH_8MA;
+ break;
+ default:
+ return 0;
+ }
+
+ si5351_set_bits(drvdata, SI5351_CLK0_CTRL + num,
+ SI5351_CLK_DRIVE_STRENGTH_MASK, mask);
+ return 0;
+}
+
+static int si5351_clkout_prepare(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
+ SI5351_CLK_POWERDOWN, 0);
+ si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
+ (1 << hwdata->num), 0);
+ return 0;
+}
+
+static void si5351_clkout_unprepare(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
+ SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN);
+ si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL,
+ (1 << hwdata->num), (1 << hwdata->num));
+}
+
+static u8 si5351_clkout_get_parent(struct clk_hw *hw)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ int index = 0;
+ unsigned char val;
+
+ val = si5351_reg_read(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num);
+ switch (val & SI5351_CLK_INPUT_MASK) {
+ case SI5351_CLK_INPUT_MULTISYNTH_N:
+ index = 0;
+ break;
+ case SI5351_CLK_INPUT_MULTISYNTH_0_4:
+ index = 1;
+ break;
+ case SI5351_CLK_INPUT_XTAL:
+ index = 2;
+ break;
+ case SI5351_CLK_INPUT_CLKIN:
+ index = 3;
+ break;
+ }
+
+ return index;
+}
+
+static int si5351_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ enum si5351_clkout_src parent = SI5351_CLKOUT_SRC_DEFAULT;
+
+ switch (index) {
+ case 0:
+ parent = SI5351_CLKOUT_SRC_MSYNTH_N;
+ break;
+ case 1:
+ parent = SI5351_CLKOUT_SRC_MSYNTH_0_4;
+ break;
+ case 2:
+ parent = SI5351_CLKOUT_SRC_XTAL;
+ break;
+ case 3:
+ parent = SI5351_CLKOUT_SRC_CLKIN;
+ break;
+ }
+
+ return _si5351_clkout_reparent(hwdata->drvdata, hwdata->num, parent);
+}
+
+static unsigned long si5351_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ unsigned char reg;
+ unsigned char rdiv;
+
+ if (hwdata->num > 5)
+ reg = si5351_msynth_params_address(hwdata->num) + 2;
+ else
+ reg = SI5351_CLK6_7_OUTPUT_DIVIDER;
+
+ rdiv = si5351_reg_read(hwdata->drvdata, reg);
+ if (hwdata->num == 6) {
+ rdiv &= SI5351_OUTPUT_CLK6_DIV_MASK;
+ } else {
+ rdiv &= SI5351_OUTPUT_CLK_DIV_MASK;
+ rdiv >>= SI5351_OUTPUT_CLK_DIV_SHIFT;
+ }
+
+ return parent_rate >> rdiv;
+}
+
+static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ unsigned char rdiv;
+
+ /* clkout6/7 can only handle output freqencies < 150MHz */
+ if (hwdata->num >= 6 && rate > SI5351_CLKOUT67_MAX_FREQ)
+ rate = SI5351_CLKOUT67_MAX_FREQ;
+
+ /* clkout freqency is 8kHz - 160MHz */
+ if (rate > SI5351_CLKOUT_MAX_FREQ)
+ rate = SI5351_CLKOUT_MAX_FREQ;
+ if (rate < SI5351_CLKOUT_MIN_FREQ)
+ rate = SI5351_CLKOUT_MIN_FREQ;
+
+ /* request frequency if multisync master */
+ if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
+ /* use r divider for frequencies below 1MHz */
+ rdiv = SI5351_OUTPUT_CLK_DIV_1;
+ while (rate < SI5351_MULTISYNTH_MIN_FREQ &&
+ rdiv < SI5351_OUTPUT_CLK_DIV_128) {
+ rdiv += 1;
+ rate *= 2;
+ }
+ *parent_rate = rate;
+ } else {
+ unsigned long new_rate, new_err, err;
+
+ /* round to closed rdiv */
+ rdiv = SI5351_OUTPUT_CLK_DIV_1;
+ new_rate = *parent_rate;
+ err = abs(new_rate - rate);
+ do {
+ new_rate >>= 1;
+ new_err = abs(new_rate - rate);
+ if (new_err > err || rdiv == SI5351_OUTPUT_CLK_DIV_128)
+ break;
+ rdiv++;
+ err = new_err;
+ } while (1);
+ }
+ rate = *parent_rate >> rdiv;
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
+ *parent_rate, rate);
+
+ return rate;
+}
+
+static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct si5351_hw_data *hwdata =
+ container_of(hw, struct si5351_hw_data, hw);
+ unsigned long new_rate, new_err, err;
+ unsigned char rdiv;
+
+ /* round to closed rdiv */
+ rdiv = SI5351_OUTPUT_CLK_DIV_1;
+ new_rate = parent_rate;
+ err = abs(new_rate - rate);
+ do {
+ new_rate >>= 1;
+ new_err = abs(new_rate - rate);
+ if (new_err > err || rdiv == SI5351_OUTPUT_CLK_DIV_128)
+ break;
+ rdiv++;
+ err = new_err;
+ } while (1);
+
+ /* write output divider */
+ switch (hwdata->num) {
+ case 6:
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK6_7_OUTPUT_DIVIDER,
+ SI5351_OUTPUT_CLK6_DIV_MASK, rdiv);
+ break;
+ case 7:
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK6_7_OUTPUT_DIVIDER,
+ SI5351_OUTPUT_CLK_DIV_MASK,
+ rdiv << SI5351_OUTPUT_CLK_DIV_SHIFT);
+ break;
+ default:
+ si5351_set_bits(hwdata->drvdata,
+ si5351_msynth_params_address(hwdata->num) + 2,
+ SI5351_OUTPUT_CLK_DIV_MASK,
+ rdiv << SI5351_OUTPUT_CLK_DIV_SHIFT);
+ }
+
+ /* powerup clkout */
+ si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
+ SI5351_CLK_POWERDOWN, 0);
+
+ dev_dbg(&hwdata->drvdata->client->dev,
+ "%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
+ __func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
+ parent_rate, rate);
+
+ return 0;
+}
+
+static const struct clk_ops si5351_clkout_ops = {
+ .prepare = si5351_clkout_prepare,
+ .unprepare = si5351_clkout_unprepare,
+ .set_parent = si5351_clkout_set_parent,
+ .get_parent = si5351_clkout_get_parent,
+ .recalc_rate = si5351_clkout_recalc_rate,
+ .round_rate = si5351_clkout_round_rate,
+ .set_rate = si5351_clkout_set_rate,
+};
+
+/*
+ * Si5351 i2c probe and DT
+ */
+#ifdef CONFIG_OF
+static const struct of_device_id si5351_dt_ids[] = {
+ { .compatible = "silabs,si5351a", .data = (void *)SI5351_VARIANT_A, },
+ { .compatible = "silabs,si5351a-msop",
+ .data = (void *)SI5351_VARIANT_A3, },
+ { .compatible = "silabs,si5351b", .data = (void *)SI5351_VARIANT_B, },
+ { .compatible = "silabs,si5351c", .data = (void *)SI5351_VARIANT_C, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, si5351_dt_ids);
+
+static int si5351_dt_parse(struct i2c_client *client)
+{
+ struct device_node *child, *np = client->dev.of_node;
+ struct si5351_platform_data *pdata;
+ const struct of_device_id *match;
+ struct property *prop;
+ const __be32 *p;
+ int num = 0;
+ u32 val;
+
+ if (np == NULL)
+ return 0;
+
+ match = of_match_node(si5351_dt_ids, np);
+ if (match == NULL)
+ return -EINVAL;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->variant = (enum si5351_variant)match->data;
+ pdata->clk_xtal = of_clk_get(np, 0);
+ if (!IS_ERR(pdata->clk_xtal))
+ clk_put(pdata->clk_xtal);
+ pdata->clk_clkin = of_clk_get(np, 1);
+ if (!IS_ERR(pdata->clk_clkin))
+ clk_put(pdata->clk_clkin);
+
+ /*
+ * property silabs,pll-source : <num src>, [<..>]
+ * allow to selectively set pll source
+ */
+ of_property_for_each_u32(np, "silabs,pll-source", prop, p, num) {
+ if (num >= 2) {
+ dev_err(&client->dev,
+ "invalid pll %d on pll-source prop\n", num);
+ return -EINVAL;
+ }
+
+ p = of_prop_next_u32(prop, p, &val);
+ if (!p) {
+ dev_err(&client->dev,
+ "missing pll-source for pll %d\n", num);
+ return -EINVAL;
+ }
+
+ switch (val) {
+ case 0:
+ pdata->pll_src[num] = SI5351_PLL_SRC_XTAL;
+ break;
+ case 1:
+ if (pdata->variant != SI5351_VARIANT_C) {
+ dev_err(&client->dev,
+ "invalid parent %d for pll %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ pdata->pll_src[num] = SI5351_PLL_SRC_CLKIN;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid parent %d for pll %d\n", val, num);
+ return -EINVAL;
+ }
+ }
+
+ /* per clkout properties */
+ for_each_child_of_node(np, child) {
+ if (of_property_read_u32(child, "reg", &num)) {
+ dev_err(&client->dev, "missing reg property of %s\n",
+ child->name);
+ return -EINVAL;
+ }
+
+ if (num >= 8 ||
+ (pdata->variant == SI5351_VARIANT_A3 && num >= 3)) {
+ dev_err(&client->dev, "invalid clkout %d\n", num);
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(child, "silabs,multisynth-source",
+ &val)) {
+ switch (val) {
+ case 0:
+ pdata->clkout[num].multisynth_src =
+ SI5351_MULTISYNTH_SRC_VCO0;
+ break;
+ case 1:
+ pdata->clkout[num].multisynth_src =
+ SI5351_MULTISYNTH_SRC_VCO1;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid parent %d for multisynth %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "silabs,clock-source", &val)) {
+ switch (val) {
+ case 0:
+ pdata->clkout[num].clkout_src =
+ SI5351_CLKOUT_SRC_MSYNTH_N;
+ break;
+ case 1:
+ pdata->clkout[num].clkout_src =
+ SI5351_CLKOUT_SRC_MSYNTH_0_4;
+ break;
+ case 2:
+ pdata->clkout[num].clkout_src =
+ SI5351_CLKOUT_SRC_XTAL;
+ break;
+ case 3:
+ if (pdata->variant != SI5351_VARIANT_C) {
+ dev_err(&client->dev,
+ "invalid parent %d for clkout %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ pdata->clkout[num].clkout_src =
+ SI5351_CLKOUT_SRC_CLKIN;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid parent %d for clkout %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "silabs,drive-strength",
+ &val)) {
+ switch (val) {
+ case SI5351_DRIVE_2MA:
+ case SI5351_DRIVE_4MA:
+ case SI5351_DRIVE_6MA:
+ case SI5351_DRIVE_8MA:
+ pdata->clkout[num].drive = val;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid drive strength %d for clkout %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "clock-frequency", &val))
+ pdata->clkout[num].rate = val;
+
+ pdata->clkout[num].pll_master =
+ of_property_read_bool(child, "silabs,pll-master");
+ }
+ client->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static int si5351_dt_parse(struct i2c_client *client)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static int si5351_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct si5351_platform_data *pdata;
+ struct si5351_driver_data *drvdata;
+ struct clk_init_data init;
+ struct clk *clk;
+ const char *parent_names[4];
+ u8 num_parents, num_clocks;
+ int ret, n;
+
+ ret = si5351_dt_parse(client);
+ if (ret)
+ return ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata)
+ return -EINVAL;
+
+ drvdata = devm_kzalloc(&client->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (drvdata == NULL) {
+ dev_err(&client->dev, "unable to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, drvdata);
+ drvdata->client = client;
+ drvdata->variant = pdata->variant;
+ drvdata->pxtal = pdata->clk_xtal;
+ drvdata->pclkin = pdata->clk_clkin;
+
+ drvdata->regmap = devm_regmap_init_i2c(client, &si5351_regmap_config);
+ if (IS_ERR(drvdata->regmap)) {
+ dev_err(&client->dev, "failed to allocate register map\n");
+ return PTR_ERR(drvdata->regmap);
+ }
+
+ /* Disable interrupts */
+ si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
+ /* Set disabled output drivers to drive low */
+ si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00);
+ si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);
+ /* Ensure pll select is on XTAL for Si5351A/B */
+ if (drvdata->variant != SI5351_VARIANT_C)
+ si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
+ SI5351_PLLA_SOURCE | SI5351_PLLB_SOURCE, 0);
+
+ /* setup clock configuration */
+ for (n = 0; n < 2; n++) {
+ ret = _si5351_pll_reparent(drvdata, n, pdata->pll_src[n]);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to reparent pll %d to %d\n",
+ n, pdata->pll_src[n]);
+ return ret;
+ }
+ }
+
+ for (n = 0; n < 8; n++) {
+ ret = _si5351_msynth_reparent(drvdata, n,
+ pdata->clkout[n].multisynth_src);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to reparent multisynth %d to %d\n",
+ n, pdata->clkout[n].multisynth_src);
+ return ret;
+ }
+
+ ret = _si5351_clkout_reparent(drvdata, n,
+ pdata->clkout[n].clkout_src);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to reparent clkout %d to %d\n",
+ n, pdata->clkout[n].clkout_src);
+ return ret;
+ }
+
+ ret = _si5351_clkout_set_drive_strength(drvdata, n,
+ pdata->clkout[n].drive);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed set drive strength of clkout%d to %d\n",
+ n, pdata->clkout[n].drive);
+ return ret;
+ }
+ }
+
+ /* register xtal input clock gate */
+ memset(&init, 0, sizeof(init));
+ init.name = si5351_input_names[0];
+ init.ops = &si5351_xtal_ops;
+ init.flags = 0;
+ if (!IS_ERR(drvdata->pxtal)) {
+ drvdata->pxtal_name = __clk_get_name(drvdata->pxtal);
+ init.parent_names = &drvdata->pxtal_name;
+ init.num_parents = 1;
+ }
+ drvdata->xtal.init = &init;
+ clk = devm_clk_register(&client->dev, &drvdata->xtal);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n", init.name);
+ return PTR_ERR(clk);
+ }
+
+ /* register clkin input clock gate */
+ if (drvdata->variant == SI5351_VARIANT_C) {
+ memset(&init, 0, sizeof(init));
+ init.name = si5351_input_names[1];
+ init.ops = &si5351_clkin_ops;
+ if (!IS_ERR(drvdata->pclkin)) {
+ drvdata->pclkin_name = __clk_get_name(drvdata->pclkin);
+ init.parent_names = &drvdata->pclkin_name;
+ init.num_parents = 1;
+ }
+ drvdata->clkin.init = &init;
+ clk = devm_clk_register(&client->dev, &drvdata->clkin);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n",
+ init.name);
+ return PTR_ERR(clk);
+ }
+ }
+
+ /* Si5351C allows to mux either xtal or clkin to PLL input */
+ num_parents = (drvdata->variant == SI5351_VARIANT_C) ? 2 : 1;
+ parent_names[0] = si5351_input_names[0];
+ parent_names[1] = si5351_input_names[1];
+
+ /* register PLLA */
+ drvdata->pll[0].num = 0;
+ drvdata->pll[0].drvdata = drvdata;
+ drvdata->pll[0].hw.init = &init;
+ memset(&init, 0, sizeof(init));
+ init.name = si5351_pll_names[0];
+ init.ops = &si5351_pll_ops;
+ init.flags = 0;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ clk = devm_clk_register(&client->dev, &drvdata->pll[0].hw);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n", init.name);
+ return -EINVAL;
+ }
+
+ /* register PLLB or VXCO (Si5351B) */
+ drvdata->pll[1].num = 1;
+ drvdata->pll[1].drvdata = drvdata;
+ drvdata->pll[1].hw.init = &init;
+ memset(&init, 0, sizeof(init));
+ if (drvdata->variant == SI5351_VARIANT_B) {
+ init.name = si5351_pll_names[2];
+ init.ops = &si5351_vxco_ops;
+ init.flags = CLK_IS_ROOT;
+ init.parent_names = NULL;
+ init.num_parents = 0;
+ } else {
+ init.name = si5351_pll_names[1];
+ init.ops = &si5351_pll_ops;
+ init.flags = 0;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ }
+ clk = devm_clk_register(&client->dev, &drvdata->pll[1].hw);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n", init.name);
+ return -EINVAL;
+ }
+
+ /* register clk multisync and clk out divider */
+ num_clocks = (drvdata->variant == SI5351_VARIANT_A3) ? 3 : 8;
+ parent_names[0] = si5351_pll_names[0];
+ if (drvdata->variant == SI5351_VARIANT_B)
+ parent_names[1] = si5351_pll_names[2];
+ else
+ parent_names[1] = si5351_pll_names[1];
+
+ drvdata->msynth = devm_kzalloc(&client->dev, num_clocks *
+ sizeof(*drvdata->msynth), GFP_KERNEL);
+ drvdata->clkout = devm_kzalloc(&client->dev, num_clocks *
+ sizeof(*drvdata->clkout), GFP_KERNEL);
+
+ drvdata->onecell.clk_num = num_clocks;
+ drvdata->onecell.clks = devm_kzalloc(&client->dev,
+ num_clocks * sizeof(*drvdata->onecell.clks), GFP_KERNEL);
+
+ if (WARN_ON(!drvdata->msynth || !drvdata->clkout ||
+ !drvdata->onecell.clks))
+ return -ENOMEM;
+
+ for (n = 0; n < num_clocks; n++) {
+ drvdata->msynth[n].num = n;
+ drvdata->msynth[n].drvdata = drvdata;
+ drvdata->msynth[n].hw.init = &init;
+ memset(&init, 0, sizeof(init));
+ init.name = si5351_msynth_names[n];
+ init.ops = &si5351_msynth_ops;
+ init.flags = 0;
+ if (pdata->clkout[n].pll_master)
+ init.flags |= CLK_SET_RATE_PARENT;
+ init.parent_names = parent_names;
+ init.num_parents = 2;
+ clk = devm_clk_register(&client->dev, &drvdata->msynth[n].hw);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n",
+ init.name);
+ return -EINVAL;
+ }
+ }
+
+ num_parents = (drvdata->variant == SI5351_VARIANT_C) ? 4 : 3;
+ parent_names[2] = si5351_input_names[0];
+ parent_names[3] = si5351_input_names[1];
+ for (n = 0; n < num_clocks; n++) {
+ parent_names[0] = si5351_msynth_names[n];
+ parent_names[1] = (n < 4) ? si5351_msynth_names[0] :
+ si5351_msynth_names[4];
+
+ drvdata->clkout[n].num = n;
+ drvdata->clkout[n].drvdata = drvdata;
+ drvdata->clkout[n].hw.init = &init;
+ memset(&init, 0, sizeof(init));
+ init.name = si5351_clkout_names[n];
+ init.ops = &si5351_clkout_ops;
+ init.flags = 0;
+ if (pdata->clkout[n].clkout_src == SI5351_CLKOUT_SRC_MSYNTH_N)
+ init.flags |= CLK_SET_RATE_PARENT;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ clk = devm_clk_register(&client->dev, &drvdata->clkout[n].hw);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "unable to register %s\n",
+ init.name);
+ return -EINVAL;
+ }
+ drvdata->onecell.clks[n] = clk;
+ }
+
+ ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+ &drvdata->onecell);
+ if (ret) {
+ dev_err(&client->dev, "unable to add clk provider\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id si5351_i2c_ids[] = {
+ { "silabs,si5351", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
+
+static struct i2c_driver si5351_driver = {
+ .driver = {
+ .name = "si5351",
+ .of_match_table = of_match_ptr(si5351_dt_ids),
+ },
+ .probe = si5351_i2c_probe,
+ .id_table = si5351_i2c_ids,
+};
+module_i2c_driver(si5351_driver);
+
+MODULE_AUTHOR("Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com");
+MODULE_DESCRIPTION("Silicon Labs Si5351A/B/C clock generator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
new file mode 100644
index 000000000000..af41b5080f43
--- /dev/null
+++ b/drivers/clk/clk-si5351.h
@@ -0,0 +1,155 @@
+/*
+ * clk-si5351.h: Silicon Laboratories Si5351A/B/C I2C Clock Generator
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Rabeeh Khoury <rabeeh@solid-run.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 _CLK_SI5351_H_
+#define _CLK_SI5351_H_
+
+#define SI5351_BUS_BASE_ADDR 0x60
+
+#define SI5351_PLL_VCO_MIN 600000000
+#define SI5351_PLL_VCO_MAX 900000000
+#define SI5351_MULTISYNTH_MIN_FREQ 1000000
+#define SI5351_MULTISYNTH_DIVBY4_FREQ 150000000
+#define SI5351_MULTISYNTH_MAX_FREQ 160000000
+#define SI5351_MULTISYNTH67_MAX_FREQ SI5351_MULTISYNTH_DIVBY4_FREQ
+#define SI5351_CLKOUT_MIN_FREQ 8000
+#define SI5351_CLKOUT_MAX_FREQ SI5351_MULTISYNTH_MAX_FREQ
+#define SI5351_CLKOUT67_MAX_FREQ SI5351_MULTISYNTH67_MAX_FREQ
+
+#define SI5351_PLL_A_MIN 15
+#define SI5351_PLL_A_MAX 90
+#define SI5351_PLL_B_MAX (SI5351_PLL_C_MAX-1)
+#define SI5351_PLL_C_MAX 1048575
+#define SI5351_MULTISYNTH_A_MIN 6
+#define SI5351_MULTISYNTH_A_MAX 1800
+#define SI5351_MULTISYNTH67_A_MAX 254
+#define SI5351_MULTISYNTH_B_MAX (SI5351_MULTISYNTH_C_MAX-1)
+#define SI5351_MULTISYNTH_C_MAX 1048575
+#define SI5351_MULTISYNTH_P1_MAX ((1<<18)-1)
+#define SI5351_MULTISYNTH_P2_MAX ((1<<20)-1)
+#define SI5351_MULTISYNTH_P3_MAX ((1<<20)-1)
+
+#define SI5351_DEVICE_STATUS 0
+#define SI5351_INTERRUPT_STATUS 1
+#define SI5351_INTERRUPT_MASK 2
+#define SI5351_STATUS_SYS_INIT (1<<7)
+#define SI5351_STATUS_LOL_B (1<<6)
+#define SI5351_STATUS_LOL_A (1<<5)
+#define SI5351_STATUS_LOS (1<<4)
+#define SI5351_OUTPUT_ENABLE_CTRL 3
+#define SI5351_OEB_PIN_ENABLE_CTRL 9
+#define SI5351_PLL_INPUT_SOURCE 15
+#define SI5351_CLKIN_DIV_MASK (3<<6)
+#define SI5351_CLKIN_DIV_1 (0<<6)
+#define SI5351_CLKIN_DIV_2 (1<<6)
+#define SI5351_CLKIN_DIV_4 (2<<6)
+#define SI5351_CLKIN_DIV_8 (3<<6)
+#define SI5351_PLLB_SOURCE (1<<3)
+#define SI5351_PLLA_SOURCE (1<<2)
+
+#define SI5351_CLK0_CTRL 16
+#define SI5351_CLK1_CTRL 17
+#define SI5351_CLK2_CTRL 18
+#define SI5351_CLK3_CTRL 19
+#define SI5351_CLK4_CTRL 20
+#define SI5351_CLK5_CTRL 21
+#define SI5351_CLK6_CTRL 22
+#define SI5351_CLK7_CTRL 23
+#define SI5351_CLK_POWERDOWN (1<<7)
+#define SI5351_CLK_INTEGER_MODE (1<<6)
+#define SI5351_CLK_PLL_SELECT (1<<5)
+#define SI5351_CLK_INVERT (1<<4)
+#define SI5351_CLK_INPUT_MASK (3<<2)
+#define SI5351_CLK_INPUT_XTAL (0<<2)
+#define SI5351_CLK_INPUT_CLKIN (1<<2)
+#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2)
+#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2)
+#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0)
+#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0)
+
+#define SI5351_CLK3_0_DISABLE_STATE 24
+#define SI5351_CLK7_4_DISABLE_STATE 25
+#define SI5351_CLK_DISABLE_STATE_LOW 0
+#define SI5351_CLK_DISABLE_STATE_HIGH 1
+#define SI5351_CLK_DISABLE_STATE_FLOAT 2
+#define SI5351_CLK_DISABLE_STATE_NEVER 3
+
+#define SI5351_PARAMETERS_LENGTH 8
+#define SI5351_PLLA_PARAMETERS 26
+#define SI5351_PLLB_PARAMETERS 34
+#define SI5351_CLK0_PARAMETERS 42
+#define SI5351_CLK1_PARAMETERS 50
+#define SI5351_CLK2_PARAMETERS 58
+#define SI5351_CLK3_PARAMETERS 66
+#define SI5351_CLK4_PARAMETERS 74
+#define SI5351_CLK5_PARAMETERS 82
+#define SI5351_CLK6_PARAMETERS 90
+#define SI5351_CLK7_PARAMETERS 91
+#define SI5351_CLK6_7_OUTPUT_DIVIDER 92
+#define SI5351_OUTPUT_CLK_DIV_MASK (7 << 4)
+#define SI5351_OUTPUT_CLK6_DIV_MASK (7 << 0)
+#define SI5351_OUTPUT_CLK_DIV_SHIFT 4
+#define SI5351_OUTPUT_CLK_DIV6_SHIFT 0
+#define SI5351_OUTPUT_CLK_DIV_1 0
+#define SI5351_OUTPUT_CLK_DIV_2 1
+#define SI5351_OUTPUT_CLK_DIV_4 2
+#define SI5351_OUTPUT_CLK_DIV_8 3
+#define SI5351_OUTPUT_CLK_DIV_16 4
+#define SI5351_OUTPUT_CLK_DIV_32 5
+#define SI5351_OUTPUT_CLK_DIV_64 6
+#define SI5351_OUTPUT_CLK_DIV_128 7
+#define SI5351_OUTPUT_CLK_DIVBY4 (3<<2)
+
+#define SI5351_SSC_PARAM0 149
+#define SI5351_SSC_PARAM1 150
+#define SI5351_SSC_PARAM2 151
+#define SI5351_SSC_PARAM3 152
+#define SI5351_SSC_PARAM4 153
+#define SI5351_SSC_PARAM5 154
+#define SI5351_SSC_PARAM6 155
+#define SI5351_SSC_PARAM7 156
+#define SI5351_SSC_PARAM8 157
+#define SI5351_SSC_PARAM9 158
+#define SI5351_SSC_PARAM10 159
+#define SI5351_SSC_PARAM11 160
+#define SI5351_SSC_PARAM12 161
+
+#define SI5351_VXCO_PARAMETERS_LOW 162
+#define SI5351_VXCO_PARAMETERS_MID 163
+#define SI5351_VXCO_PARAMETERS_HIGH 164
+
+#define SI5351_CLK0_PHASE_OFFSET 165
+#define SI5351_CLK1_PHASE_OFFSET 166
+#define SI5351_CLK2_PHASE_OFFSET 167
+#define SI5351_CLK3_PHASE_OFFSET 168
+#define SI5351_CLK4_PHASE_OFFSET 169
+#define SI5351_CLK5_PHASE_OFFSET 170
+
+#define SI5351_PLL_RESET 177
+#define SI5351_PLL_RESET_B (1<<7)
+#define SI5351_PLL_RESET_A (1<<5)
+
+#define SI5351_CRYSTAL_LOAD 183
+#define SI5351_CRYSTAL_LOAD_MASK (3<<6)
+#define SI5351_CRYSTAL_LOAD_6PF (1<<6)
+#define SI5351_CRYSTAL_LOAD_8PF (2<<6)
+#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
+
+#define SI5351_FANOUT_ENABLE 187
+#define SI5351_CLKIN_ENABLE (1<<7)
+#define SI5351_XTAL_ENABLE (1<<6)
+#define SI5351_MULTISYNTH_ENABLE (1<<4)
+
+#endif
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index 09c63315e579..debf688afa8e 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -488,6 +488,7 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
case PLL_TYPE_WM8750:
wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
+ break;
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@@ -523,6 +524,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
case PLL_TYPE_WM8750:
wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
+ break;
default:
round_rate = 0;
}
diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c
index b14a25f39255..32062977f453 100644
--- a/drivers/clk/clk-zynq.c
+++ b/drivers/clk/clk-zynq.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/clk-provider.h>
+#include <linux/clk/zynq.h>
static void __iomem *slcr_base;
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index ed87b2405806..934cfd18f72d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -19,14 +19,77 @@
#include <linux/of.h>
#include <linux/device.h>
#include <linux/init.h>
+#include <linux/sched.h>
static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);
+static struct task_struct *prepare_owner;
+static struct task_struct *enable_owner;
+
+static int prepare_refcnt;
+static int enable_refcnt;
+
static HLIST_HEAD(clk_root_list);
static HLIST_HEAD(clk_orphan_list);
static LIST_HEAD(clk_notifier_list);
+/*** locking ***/
+static void clk_prepare_lock(void)
+{
+ if (!mutex_trylock(&prepare_lock)) {
+ if (prepare_owner == current) {
+ prepare_refcnt++;
+ return;
+ }
+ mutex_lock(&prepare_lock);
+ }
+ WARN_ON_ONCE(prepare_owner != NULL);
+ WARN_ON_ONCE(prepare_refcnt != 0);
+ prepare_owner = current;
+ prepare_refcnt = 1;
+}
+
+static void clk_prepare_unlock(void)
+{
+ WARN_ON_ONCE(prepare_owner != current);
+ WARN_ON_ONCE(prepare_refcnt == 0);
+
+ if (--prepare_refcnt)
+ return;
+ prepare_owner = NULL;
+ mutex_unlock(&prepare_lock);
+}
+
+static unsigned long clk_enable_lock(void)
+{
+ unsigned long flags;
+
+ if (!spin_trylock_irqsave(&enable_lock, flags)) {
+ if (enable_owner == current) {
+ enable_refcnt++;
+ return flags;
+ }
+ spin_lock_irqsave(&enable_lock, flags);
+ }
+ WARN_ON_ONCE(enable_owner != NULL);
+ WARN_ON_ONCE(enable_refcnt != 0);
+ enable_owner = current;
+ enable_refcnt = 1;
+ return flags;
+}
+
+static void clk_enable_unlock(unsigned long flags)
+{
+ WARN_ON_ONCE(enable_owner != current);
+ WARN_ON_ONCE(enable_refcnt == 0);
+
+ if (--enable_refcnt)
+ return;
+ enable_owner = NULL;
+ spin_unlock_irqrestore(&enable_lock, flags);
+}
+
/*** debugfs support ***/
#ifdef CONFIG_COMMON_CLK_DEBUG
@@ -69,7 +132,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
seq_printf(s, " clock enable_cnt prepare_cnt rate\n");
seq_printf(s, "---------------------------------------------------------------------\n");
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
hlist_for_each_entry(c, &clk_root_list, child_node)
clk_summary_show_subtree(s, c, 0);
@@ -77,7 +140,7 @@ static int clk_summary_show(struct seq_file *s, void *data)
hlist_for_each_entry(c, &clk_orphan_list, child_node)
clk_summary_show_subtree(s, c, 0);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return 0;
}
@@ -130,7 +193,7 @@ static int clk_dump(struct seq_file *s, void *data)
seq_printf(s, "{");
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
hlist_for_each_entry(c, &clk_root_list, child_node) {
if (!first_node)
@@ -144,7 +207,7 @@ static int clk_dump(struct seq_file *s, void *data)
clk_dump_subtree(s, c, 0);
}
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
seq_printf(s, "}");
return 0;
@@ -280,6 +343,39 @@ out:
}
/**
+ * clk_debug_reparent - reparent clk node in the debugfs clk tree
+ * @clk: the clk being reparented
+ * @new_parent: the new clk parent, may be NULL
+ *
+ * Rename clk entry in the debugfs clk tree if debugfs has been
+ * initialized. Otherwise it bails out early since the debugfs clk tree
+ * will be created lazily by clk_debug_init as part of a late_initcall.
+ *
+ * Caller must hold prepare_lock.
+ */
+static void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+{
+ struct dentry *d;
+ struct dentry *new_parent_d;
+
+ if (!inited)
+ return;
+
+ if (new_parent)
+ new_parent_d = new_parent->dentry;
+ else
+ new_parent_d = orphandir;
+
+ d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
+ new_parent_d, clk->name);
+ if (d)
+ clk->dentry = d;
+ else
+ pr_debug("%s: failed to rename debugfs entry for %s\n",
+ __func__, clk->name);
+}
+
+/**
* clk_debug_init - lazily create the debugfs clk tree visualization
*
* clks are often initialized very early during boot before memory can
@@ -316,7 +412,7 @@ static int __init clk_debug_init(void)
if (!orphandir)
return -ENOMEM;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
hlist_for_each_entry(clk, &clk_root_list, child_node)
clk_debug_create_subtree(clk, rootdir);
@@ -326,16 +422,45 @@ static int __init clk_debug_init(void)
inited = 1;
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return 0;
}
late_initcall(clk_debug_init);
#else
static inline int clk_debug_register(struct clk *clk) { return 0; }
+static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+{
+}
#endif
/* caller must hold prepare_lock */
+static void clk_unprepare_unused_subtree(struct clk *clk)
+{
+ struct clk *child;
+
+ if (!clk)
+ return;
+
+ hlist_for_each_entry(child, &clk->children, child_node)
+ clk_unprepare_unused_subtree(child);
+
+ if (clk->prepare_count)
+ return;
+
+ if (clk->flags & CLK_IGNORE_UNUSED)
+ return;
+
+ if (__clk_is_prepared(clk)) {
+ if (clk->ops->unprepare_unused)
+ clk->ops->unprepare_unused(clk->hw);
+ else if (clk->ops->unprepare)
+ clk->ops->unprepare(clk->hw);
+ }
+}
+EXPORT_SYMBOL_GPL(__clk_get_flags);
+
+/* caller must hold prepare_lock */
static void clk_disable_unused_subtree(struct clk *clk)
{
struct clk *child;
@@ -347,7 +472,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
hlist_for_each_entry(child, &clk->children, child_node)
clk_disable_unused_subtree(child);
- spin_lock_irqsave(&enable_lock, flags);
+ flags = clk_enable_lock();
if (clk->enable_count)
goto unlock_out;
@@ -368,17 +493,30 @@ static void clk_disable_unused_subtree(struct clk *clk)
}
unlock_out:
- spin_unlock_irqrestore(&enable_lock, flags);
+ clk_enable_unlock(flags);
out:
return;
}
+static bool clk_ignore_unused;
+static int __init clk_ignore_unused_setup(char *__unused)
+{
+ clk_ignore_unused = true;
+ return 1;
+}
+__setup("clk_ignore_unused", clk_ignore_unused_setup);
+
static int clk_disable_unused(void)
{
struct clk *clk;
- mutex_lock(&prepare_lock);
+ if (clk_ignore_unused) {
+ pr_warn("clk: Not disabling unused clocks\n");
+ return 0;
+ }
+
+ clk_prepare_lock();
hlist_for_each_entry(clk, &clk_root_list, child_node)
clk_disable_unused_subtree(clk);
@@ -386,7 +524,13 @@ static int clk_disable_unused(void)
hlist_for_each_entry(clk, &clk_orphan_list, child_node)
clk_disable_unused_subtree(clk);
- mutex_unlock(&prepare_lock);
+ hlist_for_each_entry(clk, &clk_root_list, child_node)
+ clk_unprepare_unused_subtree(clk);
+
+ hlist_for_each_entry(clk, &clk_orphan_list, child_node)
+ clk_unprepare_unused_subtree(clk);
+
+ clk_prepare_unlock();
return 0;
}
@@ -451,6 +595,27 @@ unsigned long __clk_get_flags(struct clk *clk)
return !clk ? 0 : clk->flags;
}
+bool __clk_is_prepared(struct clk *clk)
+{
+ int ret;
+
+ if (!clk)
+ return false;
+
+ /*
+ * .is_prepared is optional for clocks that can prepare
+ * fall back to software usage counter if it is missing
+ */
+ if (!clk->ops->is_prepared) {
+ ret = clk->prepare_count ? 1 : 0;
+ goto out;
+ }
+
+ ret = clk->ops->is_prepared(clk->hw);
+out:
+ return !!ret;
+}
+
bool __clk_is_enabled(struct clk *clk)
{
int ret;
@@ -548,9 +713,9 @@ void __clk_unprepare(struct clk *clk)
*/
void clk_unprepare(struct clk *clk)
{
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
__clk_unprepare(clk);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unprepare);
@@ -596,9 +761,9 @@ int clk_prepare(struct clk *clk)
{
int ret;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
ret = __clk_prepare(clk);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -640,9 +805,9 @@ void clk_disable(struct clk *clk)
{
unsigned long flags;
- spin_lock_irqsave(&enable_lock, flags);
+ flags = clk_enable_lock();
__clk_disable(clk);
- spin_unlock_irqrestore(&enable_lock, flags);
+ clk_enable_unlock(flags);
}
EXPORT_SYMBOL_GPL(clk_disable);
@@ -693,9 +858,9 @@ int clk_enable(struct clk *clk)
unsigned long flags;
int ret;
- spin_lock_irqsave(&enable_lock, flags);
+ flags = clk_enable_lock();
ret = __clk_enable(clk);
- spin_unlock_irqrestore(&enable_lock, flags);
+ clk_enable_unlock(flags);
return ret;
}
@@ -740,9 +905,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long ret;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
ret = __clk_round_rate(clk, rate);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -837,13 +1002,13 @@ unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
__clk_recalc_rates(clk, 0);
rate = __clk_get_rate(clk);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return rate;
}
@@ -876,16 +1041,16 @@ static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
else
new_rate = parent_rate;
- /* abort the rate change if a driver returns NOTIFY_BAD */
+ /* abort rate change if a driver returns NOTIFY_BAD or NOTIFY_STOP */
if (clk->notifier_count)
ret = __clk_notify(clk, PRE_RATE_CHANGE, clk->rate, new_rate);
- if (ret == NOTIFY_BAD)
+ if (ret & NOTIFY_STOP_MASK)
goto out;
hlist_for_each_entry(child, &clk->children, child_node) {
ret = __clk_speculate_rates(child, new_rate);
- if (ret == NOTIFY_BAD)
+ if (ret & NOTIFY_STOP_MASK)
break;
}
@@ -974,11 +1139,11 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
- return 0;
+ return NULL;
if (clk->notifier_count) {
ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
- if (ret == NOTIFY_BAD)
+ if (ret & NOTIFY_STOP_MASK)
fail_clk = clk;
}
@@ -1048,7 +1213,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
int ret = 0;
/* prevent racing with updates to the clock topology */
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
/* bail early if nothing to do */
if (rate == clk->rate)
@@ -1080,7 +1245,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
clk_change_rate(top);
out:
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -1096,9 +1261,9 @@ struct clk *clk_get_parent(struct clk *clk)
{
struct clk *parent;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
parent = __clk_get_parent(clk);
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return parent;
}
@@ -1162,16 +1327,8 @@ out:
return ret;
}
-void __clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_reparent(struct clk *clk, struct clk *new_parent)
{
-#ifdef CONFIG_COMMON_CLK_DEBUG
- struct dentry *d;
- struct dentry *new_parent_d;
-#endif
-
- if (!clk || !new_parent)
- return;
-
hlist_del(&clk->child_node);
if (new_parent)
@@ -1179,39 +1336,20 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
else
hlist_add_head(&clk->child_node, &clk_orphan_list);
-#ifdef CONFIG_COMMON_CLK_DEBUG
- if (!inited)
- goto out;
-
- if (new_parent)
- new_parent_d = new_parent->dentry;
- else
- new_parent_d = orphandir;
-
- d = debugfs_rename(clk->dentry->d_parent, clk->dentry,
- new_parent_d, clk->name);
- if (d)
- clk->dentry = d;
- else
- pr_debug("%s: failed to rename debugfs entry for %s\n",
- __func__, clk->name);
-out:
-#endif
-
clk->parent = new_parent;
+}
+void __clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+ clk_reparent(clk, new_parent);
+ clk_debug_reparent(clk, new_parent);
__clk_recalc_rates(clk, POST_RATE_CHANGE);
}
-static int __clk_set_parent(struct clk *clk, struct clk *parent)
+static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
{
- struct clk *old_parent;
- unsigned long flags;
- int ret = -EINVAL;
u8 i;
- old_parent = clk->parent;
-
if (!clk->parents)
clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
@@ -1231,36 +1369,79 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent)
}
}
- if (i == clk->num_parents) {
- pr_debug("%s: clock %s is not a possible parent of clock %s\n",
- __func__, parent->name, clk->name);
- goto out;
- }
+ return i;
+}
- /* migrate prepare and enable */
+static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct clk *old_parent = clk->parent;
+ bool migrated_enable = false;
+
+ /* migrate prepare */
if (clk->prepare_count)
__clk_prepare(parent);
- /* FIXME replace with clk_is_enabled(clk) someday */
- spin_lock_irqsave(&enable_lock, flags);
- if (clk->enable_count)
+ flags = clk_enable_lock();
+
+ /* migrate enable */
+ if (clk->enable_count) {
__clk_enable(parent);
- spin_unlock_irqrestore(&enable_lock, flags);
+ migrated_enable = true;
+ }
+
+ /* update the clk tree topology */
+ clk_reparent(clk, parent);
+
+ clk_enable_unlock(flags);
/* change clock input source */
- ret = clk->ops->set_parent(clk->hw, i);
+ if (parent && clk->ops->set_parent)
+ ret = clk->ops->set_parent(clk->hw, p_index);
- /* clean up old prepare and enable */
- spin_lock_irqsave(&enable_lock, flags);
- if (clk->enable_count)
+ if (ret) {
+ /*
+ * The error handling is tricky due to that we need to release
+ * the spinlock while issuing the .set_parent callback. This
+ * means the new parent might have been enabled/disabled in
+ * between, which must be considered when doing rollback.
+ */
+ flags = clk_enable_lock();
+
+ clk_reparent(clk, old_parent);
+
+ if (migrated_enable && clk->enable_count) {
+ __clk_disable(parent);
+ } else if (migrated_enable && (clk->enable_count == 0)) {
+ __clk_disable(old_parent);
+ } else if (!migrated_enable && clk->enable_count) {
+ __clk_disable(parent);
+ __clk_enable(old_parent);
+ }
+
+ clk_enable_unlock(flags);
+
+ if (clk->prepare_count)
+ __clk_unprepare(parent);
+
+ return ret;
+ }
+
+ /* clean up enable for old parent if migration was done */
+ if (migrated_enable) {
+ flags = clk_enable_lock();
__clk_disable(old_parent);
- spin_unlock_irqrestore(&enable_lock, flags);
+ clk_enable_unlock(flags);
+ }
+ /* clean up prepare for old parent if migration was done */
if (clk->prepare_count)
__clk_unprepare(old_parent);
-out:
- return ret;
+ /* update debugfs with new clk tree topology */
+ clk_debug_reparent(clk, parent);
+ return 0;
}
/**
@@ -1278,44 +1459,59 @@ out:
int clk_set_parent(struct clk *clk, struct clk *parent)
{
int ret = 0;
+ u8 p_index = 0;
+ unsigned long p_rate = 0;
if (!clk || !clk->ops)
return -EINVAL;
- if (!clk->ops->set_parent)
+ /* verify ops for for multi-parent clks */
+ if ((clk->num_parents > 1) && (!clk->ops->set_parent))
return -ENOSYS;
/* prevent racing with updates to the clock topology */
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
if (clk->parent == parent)
goto out;
+ /* check that we are allowed to re-parent if the clock is in use */
+ if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* try finding the new parent index */
+ if (parent) {
+ p_index = clk_fetch_parent_index(clk, parent);
+ p_rate = parent->rate;
+ if (p_index == clk->num_parents) {
+ pr_debug("%s: clk %s can not be parent of clk %s\n",
+ __func__, parent->name, clk->name);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
/* propagate PRE_RATE_CHANGE notifications */
if (clk->notifier_count)
- ret = __clk_speculate_rates(clk, parent->rate);
+ ret = __clk_speculate_rates(clk, p_rate);
/* abort if a driver objects */
- if (ret == NOTIFY_STOP)
+ if (ret & NOTIFY_STOP_MASK)
goto out;
- /* only re-parent if the clock is not in use */
- if ((clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count)
- ret = -EBUSY;
- else
- ret = __clk_set_parent(clk, parent);
+ /* do the re-parent */
+ ret = __clk_set_parent(clk, parent, p_index);
- /* propagate ABORT_RATE_CHANGE if .set_parent failed */
- if (ret) {
+ /* propagate rate recalculation accordingly */
+ if (ret)
__clk_recalc_rates(clk, ABORT_RATE_CHANGE);
- goto out;
- }
-
- /* propagate rate recalculation downstream */
- __clk_reparent(clk, parent);
+ else
+ __clk_recalc_rates(clk, POST_RATE_CHANGE);
out:
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -1338,7 +1534,7 @@ int __clk_init(struct device *dev, struct clk *clk)
if (!clk)
return -EINVAL;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
/* check to see if a clock with this name is already registered */
if (__clk_lookup(clk->name)) {
@@ -1462,7 +1658,7 @@ int __clk_init(struct device *dev, struct clk *clk)
clk_debug_register(clk);
out:
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -1696,7 +1892,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
if (!clk || !nb)
return -EINVAL;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
/* search the list of notifiers for this clk */
list_for_each_entry(cn, &clk_notifier_list, node)
@@ -1720,7 +1916,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
clk->notifier_count++;
out:
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
@@ -1745,7 +1941,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
if (!clk || !nb)
return -EINVAL;
- mutex_lock(&prepare_lock);
+ clk_prepare_lock();
list_for_each_entry(cn, &clk_notifier_list, node)
if (cn->clk == clk)
@@ -1766,7 +1962,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
ret = -ENOENT;
}
- mutex_unlock(&prepare_lock);
+ clk_prepare_unlock();
return ret;
}
diff --git a/drivers/clk/mvebu/clk-core.c b/drivers/clk/mvebu/clk-core.c
index 69056a7479e8..0a53edbae8b8 100644
--- a/drivers/clk/mvebu/clk-core.c
+++ b/drivers/clk/mvebu/clk-core.c
@@ -156,8 +156,8 @@ static u32 __init armada_370_get_cpu_freq(void __iomem *sar)
cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
SARL_A370_PCLK_FREQ_OPT_MASK);
- if (cpu_freq_select > ARRAY_SIZE(armada_370_cpu_frequencies)) {
- pr_err("CPU freq select unsuported %d\n", cpu_freq_select);
+ if (cpu_freq_select >= ARRAY_SIZE(armada_370_cpu_frequencies)) {
+ pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
cpu_freq = 0;
} else
cpu_freq = armada_370_cpu_frequencies[cpu_freq_select];
@@ -278,8 +278,8 @@ static u32 __init armada_xp_get_cpu_freq(void __iomem *sar)
cpu_freq_select |= (((readl(sar+4) >> SARH_AXP_PCLK_FREQ_OPT) &
SARH_AXP_PCLK_FREQ_OPT_MASK)
<< SARH_AXP_PCLK_FREQ_OPT_SHIFT);
- if (cpu_freq_select > ARRAY_SIZE(armada_xp_cpu_frequencies)) {
- pr_err("CPU freq select unsuported: %d\n", cpu_freq_select);
+ if (cpu_freq_select >= ARRAY_SIZE(armada_xp_cpu_frequencies)) {
+ pr_err("CPU freq select unsupported: %d\n", cpu_freq_select);
cpu_freq = 0;
} else
cpu_freq = armada_xp_cpu_frequencies[cpu_freq_select];
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
index 9dd2551a0a41..b0fbc0715491 100644
--- a/drivers/clk/mvebu/clk-cpu.c
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -16,7 +16,6 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/delay.h>
-#include "clk-cpu.h"
#define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET 0x0
#define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET 0xC
@@ -173,17 +172,5 @@ clks_out:
kfree(cpuclk);
}
-static const __initconst struct of_device_id clk_cpu_match[] = {
- {
- .compatible = "marvell,armada-xp-cpu-clock",
- .data = of_cpu_clk_setup,
- },
- {
- /* sentinel */
- },
-};
-
-void __init mvebu_cpu_clk_init(void)
-{
- of_clk_init(clk_cpu_match);
-}
+CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock",
+ of_cpu_clk_setup);
diff --git a/drivers/clk/mvebu/clk-cpu.h b/drivers/clk/mvebu/clk-cpu.h
deleted file mode 100644
index 08e2affba4e6..000000000000
--- a/drivers/clk/mvebu/clk-cpu.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Marvell MVEBU CPU clock handling.
- *
- * Copyright (C) 2012 Marvell
- *
- * Gregory CLEMENT <gregory.clement@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MVEBU_CLK_CPU_H
-#define __MVEBU_CLK_CPU_H
-
-#ifdef CONFIG_MVEBU_CLK_CPU
-void __init mvebu_cpu_clk_init(void);
-#else
-static inline void mvebu_cpu_clk_init(void) {}
-#endif
-
-#endif
diff --git a/drivers/clk/mvebu/clk.c b/drivers/clk/mvebu/clk.c
index 855681b8a9dc..29f10fb3006c 100644
--- a/drivers/clk/mvebu/clk.c
+++ b/drivers/clk/mvebu/clk.c
@@ -10,18 +10,14 @@
* warranty of any kind, whether express or implied.
*/
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/clk-provider.h>
-#include <linux/of_address.h>
-#include <linux/clk/mvebu.h>
#include <linux/of.h>
#include "clk-core.h"
-#include "clk-cpu.h"
#include "clk-gating-ctrl.h"
void __init mvebu_clocks_init(void)
{
mvebu_core_clk_init();
mvebu_gating_clk_init();
- mvebu_cpu_clk_init();
+ of_clk_init(NULL);
}
diff --git a/drivers/clk/mxs/clk.c b/drivers/clk/mxs/clk.c
index b24d56067c80..5301bce8957b 100644
--- a/drivers/clk/mxs/clk.c
+++ b/drivers/clk/mxs/clk.c
@@ -13,6 +13,7 @@
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
+#include "clk.h"
DEFINE_SPINLOCK(mxs_lock);
diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c
index 82abea366b78..35e7e2698e10 100644
--- a/drivers/clk/spear/spear1340_clock.c
+++ b/drivers/clk/spear/spear1340_clock.c
@@ -960,47 +960,47 @@ void __init spear1340_clk_init(void)
SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "d0100000.spdif-in");
- clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0,
+ clk = clk_register_gate(NULL, "acp_clk", "ahb_clk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "acp_clk");
- clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
+ clk = clk_register_gate(NULL, "plgpio_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "e2800000.gpio");
- clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
+ clk = clk_register_gate(NULL, "video_dec_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "video_dec");
- clk = clk_register_gate(NULL, "video_enc_clk", "video_enc_mclk", 0,
+ clk = clk_register_gate(NULL, "video_enc_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_ENC_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "video_enc");
- clk = clk_register_gate(NULL, "video_in_clk", "video_in_mclk", 0,
+ clk = clk_register_gate(NULL, "video_in_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_IN_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "spear_vip");
- clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
+ clk = clk_register_gate(NULL, "cam0_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "d0200000.cam0");
- clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
+ clk = clk_register_gate(NULL, "cam1_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "d0300000.cam1");
- clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
+ clk = clk_register_gate(NULL, "cam2_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "d0400000.cam2");
- clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
+ clk = clk_register_gate(NULL, "cam3_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
&_lock);
clk_register_clkdev(clk, NULL, "d0500000.cam3");
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
new file mode 100644
index 000000000000..b5bac917612c
--- /dev/null
+++ b/drivers/clk/sunxi/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sunxi specific clk
+#
+
+obj-y += clk-sunxi.o clk-factors.o
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
new file mode 100644
index 000000000000..88523f91d9b7
--- /dev/null
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2013 Emilio López <emilio@elopez.com.ar>
+ *
+ * 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.
+ *
+ * Adjustable factor-based clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+
+#include <linux/delay.h>
+
+#include "clk-factors.h"
+
+/*
+ * DOC: basic adjustable factor-based clock that cannot gate
+ *
+ * Traits of this clock:
+ * prepare - clk_prepare only ensures that parents are prepared
+ * enable - clk_enable only ensures that parents are enabled
+ * rate - rate is adjustable.
+ * clk->rate = (parent->rate * N * (K + 1) >> P) / (M + 1)
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+struct clk_factors {
+ struct clk_hw hw;
+ void __iomem *reg;
+ struct clk_factors_config *config;
+ void (*get_factors) (u32 *rate, u32 parent, u8 *n, u8 *k, u8 *m, u8 *p);
+ spinlock_t *lock;
+};
+
+#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
+
+#define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos))
+#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
+#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
+
+#define FACTOR_SET(bit, len, reg, val) \
+ (((reg) & CLRMASK(len, bit)) | (val << (bit)))
+
+static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ u8 n = 1, k = 0, p = 0, m = 0;
+ u32 reg;
+ unsigned long rate;
+ struct clk_factors *factors = to_clk_factors(hw);
+ struct clk_factors_config *config = factors->config;
+
+ /* Fetch the register value */
+ reg = readl(factors->reg);
+
+ /* Get each individual factor if applicable */
+ if (config->nwidth != SUNXI_FACTORS_NOT_APPLICABLE)
+ n = FACTOR_GET(config->nshift, config->nwidth, reg);
+ if (config->kwidth != SUNXI_FACTORS_NOT_APPLICABLE)
+ k = FACTOR_GET(config->kshift, config->kwidth, reg);
+ if (config->mwidth != SUNXI_FACTORS_NOT_APPLICABLE)
+ m = FACTOR_GET(config->mshift, config->mwidth, reg);
+ if (config->pwidth != SUNXI_FACTORS_NOT_APPLICABLE)
+ p = FACTOR_GET(config->pshift, config->pwidth, reg);
+
+ /* Calculate the rate */
+ rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
+
+ return rate;
+}
+
+static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct clk_factors *factors = to_clk_factors(hw);
+ factors->get_factors((u32 *)&rate, (u32)*parent_rate,
+ NULL, NULL, NULL, NULL);
+
+ return rate;
+}
+
+static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ u8 n, k, m, p;
+ u32 reg;
+ struct clk_factors *factors = to_clk_factors(hw);
+ struct clk_factors_config *config = factors->config;
+ unsigned long flags = 0;
+
+ factors->get_factors((u32 *)&rate, (u32)parent_rate, &n, &k, &m, &p);
+
+ if (factors->lock)
+ spin_lock_irqsave(factors->lock, flags);
+
+ /* Fetch the register value */
+ reg = readl(factors->reg);
+
+ /* Set up the new factors - macros do not do anything if width is 0 */
+ reg = FACTOR_SET(config->nshift, config->nwidth, reg, n);
+ reg = FACTOR_SET(config->kshift, config->kwidth, reg, k);
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, m);
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, p);
+
+ /* Apply them now */
+ writel(reg, factors->reg);
+
+ /* delay 500us so pll stabilizes */
+ __delay((rate >> 20) * 500 / 2);
+
+ if (factors->lock)
+ spin_unlock_irqrestore(factors->lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops clk_factors_ops = {
+ .recalc_rate = clk_factors_recalc_rate,
+ .round_rate = clk_factors_round_rate,
+ .set_rate = clk_factors_set_rate,
+};
+
+/**
+ * clk_register_factors - register a factors clock with
+ * the clock framework
+ * @dev: device registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust factors
+ * @config: shift and width of factors n, k, m and p
+ * @get_factors: function to calculate the factors for a given frequency
+ * @lock: shared register lock for this clock
+ */
+struct clk *clk_register_factors(struct device *dev, const char *name,
+ const char *parent_name,
+ unsigned long flags, void __iomem *reg,
+ struct clk_factors_config *config,
+ void (*get_factors)(u32 *rate, u32 parent,
+ u8 *n, u8 *k, u8 *m, u8 *p),
+ spinlock_t *lock)
+{
+ struct clk_factors *factors;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the factors */
+ factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
+ if (!factors) {
+ pr_err("%s: could not allocate factors clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &clk_factors_ops;
+ init.flags = flags;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct clk_factors assignments */
+ factors->reg = reg;
+ factors->config = config;
+ factors->lock = lock;
+ factors->hw.init = &init;
+ factors->get_factors = get_factors;
+
+ /* register the clock */
+ clk = clk_register(dev, &factors->hw);
+
+ if (IS_ERR(clk))
+ kfree(factors);
+
+ return clk;
+}
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
new file mode 100644
index 000000000000..f49851cc4380
--- /dev/null
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -0,0 +1,27 @@
+#ifndef __MACH_SUNXI_CLK_FACTORS_H
+#define __MACH_SUNXI_CLK_FACTORS_H
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#define SUNXI_FACTORS_NOT_APPLICABLE (0)
+
+struct clk_factors_config {
+ u8 nshift;
+ u8 nwidth;
+ u8 kshift;
+ u8 kwidth;
+ u8 mshift;
+ u8 mwidth;
+ u8 pshift;
+ u8 pwidth;
+};
+
+struct clk *clk_register_factors(struct device *dev, const char *name,
+ const char *parent_name,
+ unsigned long flags, void __iomem *reg,
+ struct clk_factors_config *config,
+ void (*get_factors) (u32 *rate, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p),
+ spinlock_t *lock);
+#endif
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
new file mode 100644
index 000000000000..8492ad1d5360
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * 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/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/sunxi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include "clk-factors.h"
+
+static DEFINE_SPINLOCK(clk_lock);
+
+/**
+ * sunxi_osc_clk_setup() - Setup function for gatable oscillator
+ */
+
+#define SUNXI_OSC24M_GATE 0
+
+static void __init sunxi_osc_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_fixed_rate *fixed;
+ struct clk_gate *gate;
+ const char *clk_name = node->name;
+ u32 rate;
+
+ /* allocate fixed-rate and gate clock structs */
+ fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
+ if (!fixed)
+ return;
+ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(fixed);
+ return;
+ }
+
+ if (of_property_read_u32(node, "clock-frequency", &rate))
+ return;
+
+ /* set up gate and fixed rate properties */
+ gate->reg = of_iomap(node, 0);
+ gate->bit_idx = SUNXI_OSC24M_GATE;
+ gate->lock = &clk_lock;
+ fixed->fixed_rate = rate;
+
+ clk = clk_register_composite(NULL, clk_name,
+ NULL, 0,
+ NULL, NULL,
+ &fixed->hw, &clk_fixed_rate_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_IS_ROOT);
+
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+
+
+
+/**
+ * sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1
+ * PLL1 rate is calculated as follows
+ * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
+ * parent_rate is always 24Mhz
+ */
+
+static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p)
+{
+ u8 div;
+
+ /* Normalize value to a 6M multiple */
+ div = *freq / 6000000;
+ *freq = 6000000 * div;
+
+ /* we were called to round the frequency, we can now return */
+ if (n == NULL)
+ return;
+
+ /* m is always zero for pll1 */
+ *m = 0;
+
+ /* k is 1 only on these cases */
+ if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
+ *k = 1;
+ else
+ *k = 0;
+
+ /* p will be 3 for divs under 10 */
+ if (div < 10)
+ *p = 3;
+
+ /* p will be 2 for divs between 10 - 20 and odd divs under 32 */
+ else if (div < 20 || (div < 32 && (div & 1)))
+ *p = 2;
+
+ /* p will be 1 for even divs under 32, divs under 40 and odd pairs
+ * of divs between 40-62 */
+ else if (div < 40 || (div < 64 && (div & 2)))
+ *p = 1;
+
+ /* any other entries have p = 0 */
+ else
+ *p = 0;
+
+ /* calculate a suitable n based on k and p */
+ div <<= *p;
+ div /= (*k + 1);
+ *n = div / 4;
+}
+
+
+
+/**
+ * sunxi_get_apb1_factors() - calculates m, p factors for APB1
+ * APB1 rate is calculated as follows
+ * rate = (parent_rate >> p) / (m + 1);
+ */
+
+static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate,
+ u8 *n, u8 *k, u8 *m, u8 *p)
+{
+ u8 calcm, calcp;
+
+ if (parent_rate < *freq)
+ *freq = parent_rate;
+
+ parent_rate = (parent_rate + (*freq - 1)) / *freq;
+
+ /* Invalid rate! */
+ if (parent_rate > 32)
+ return;
+
+ if (parent_rate <= 4)
+ calcp = 0;
+ else if (parent_rate <= 8)
+ calcp = 1;
+ else if (parent_rate <= 16)
+ calcp = 2;
+ else
+ calcp = 3;
+
+ calcm = (parent_rate >> calcp) - 1;
+
+ *freq = (parent_rate >> calcp) / (calcm + 1);
+
+ /* we were called to round the frequency, we can now return */
+ if (n == NULL)
+ return;
+
+ *m = calcm;
+ *p = calcp;
+}
+
+
+
+/**
+ * sunxi_factors_clk_setup() - Setup function for factor clocks
+ */
+
+struct factors_data {
+ struct clk_factors_config *table;
+ void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
+};
+
+static struct clk_factors_config pll1_config = {
+ .nshift = 8,
+ .nwidth = 5,
+ .kshift = 4,
+ .kwidth = 2,
+ .mshift = 0,
+ .mwidth = 2,
+ .pshift = 16,
+ .pwidth = 2,
+};
+
+static struct clk_factors_config apb1_config = {
+ .mshift = 0,
+ .mwidth = 5,
+ .pshift = 16,
+ .pwidth = 2,
+};
+
+static const __initconst struct factors_data pll1_data = {
+ .table = &pll1_config,
+ .getter = sunxi_get_pll1_factors,
+};
+
+static const __initconst struct factors_data apb1_data = {
+ .table = &apb1_config,
+ .getter = sunxi_get_apb1_factors,
+};
+
+static void __init sunxi_factors_clk_setup(struct device_node *node,
+ struct factors_data *data)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent;
+ void *reg;
+
+ reg = of_iomap(node, 0);
+
+ parent = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_factors(NULL, clk_name, parent, 0, reg,
+ data->table, data->getter, &clk_lock);
+
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+
+
+
+/**
+ * sunxi_mux_clk_setup() - Setup function for muxes
+ */
+
+#define SUNXI_MUX_GATE_WIDTH 2
+
+struct mux_data {
+ u8 shift;
+};
+
+static const __initconst struct mux_data cpu_data = {
+ .shift = 16,
+};
+
+static const __initconst struct mux_data apb1_mux_data = {
+ .shift = 24,
+};
+
+static void __init sunxi_mux_clk_setup(struct device_node *node,
+ struct mux_data *data)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parents[5];
+ void *reg;
+ int i = 0;
+
+ reg = of_iomap(node, 0);
+
+ while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ clk = clk_register_mux(NULL, clk_name, parents, i, 0, reg,
+ data->shift, SUNXI_MUX_GATE_WIDTH,
+ 0, &clk_lock);
+
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+
+
+
+/**
+ * sunxi_divider_clk_setup() - Setup function for simple divider clocks
+ */
+
+#define SUNXI_DIVISOR_WIDTH 2
+
+struct div_data {
+ u8 shift;
+ u8 pow;
+};
+
+static const __initconst struct div_data axi_data = {
+ .shift = 0,
+ .pow = 0,
+};
+
+static const __initconst struct div_data ahb_data = {
+ .shift = 4,
+ .pow = 1,
+};
+
+static const __initconst struct div_data apb0_data = {
+ .shift = 8,
+ .pow = 1,
+};
+
+static void __init sunxi_divider_clk_setup(struct device_node *node,
+ struct div_data *data)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *clk_parent;
+ void *reg;
+
+ reg = of_iomap(node, 0);
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
+ reg, data->shift, SUNXI_DIVISOR_WIDTH,
+ data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
+ &clk_lock);
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+
+
+
+/**
+ * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
+ */
+
+#define SUNXI_GATES_MAX_SIZE 64
+
+struct gates_data {
+ DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
+};
+
+static const __initconst struct gates_data axi_gates_data = {
+ .mask = {1},
+};
+
+static const __initconst struct gates_data ahb_gates_data = {
+ .mask = {0x7F77FFF, 0x14FB3F},
+};
+
+static const __initconst struct gates_data apb0_gates_data = {
+ .mask = {0x4EF},
+};
+
+static const __initconst struct gates_data apb1_gates_data = {
+ .mask = {0xFF00F7},
+};
+
+static void __init sunxi_gates_clk_setup(struct device_node *node,
+ struct gates_data *data)
+{
+ struct clk_onecell_data *clk_data;
+ const char *clk_parent;
+ const char *clk_name;
+ void *reg;
+ int qty;
+ int i = 0;
+ int j = 0;
+ int ignore;
+
+ reg = of_iomap(node, 0);
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+
+ /* Worst-case size approximation and memory allocation */
+ qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE);
+ clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+ clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
+ if (!clk_data->clks) {
+ kfree(clk_data);
+ return;
+ }
+
+ for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) {
+ of_property_read_string_index(node, "clock-output-names",
+ j, &clk_name);
+
+ /* No driver claims this clock, but it should remain gated */
+ ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0;
+
+ clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+ clk_parent, ignore,
+ reg + 4 * (i/32), i % 32,
+ 0, &clk_lock);
+ WARN_ON(IS_ERR(clk_data->clks[i]));
+
+ j++;
+ }
+
+ /* Adjust to the real max */
+ clk_data->clk_num = i;
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+
+/* Matches for of_clk_init */
+static const __initconst struct of_device_id clk_match[] = {
+ {.compatible = "allwinner,sun4i-osc-clk", .data = sunxi_osc_clk_setup,},
+ {}
+};
+
+/* Matches for factors clocks */
+static const __initconst struct of_device_id clk_factors_match[] = {
+ {.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,},
+ {.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,},
+ {}
+};
+
+/* Matches for divider clocks */
+static const __initconst struct of_device_id clk_div_match[] = {
+ {.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,},
+ {.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,},
+ {.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,},
+ {}
+};
+
+/* Matches for mux clocks */
+static const __initconst struct of_device_id clk_mux_match[] = {
+ {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
+ {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
+ {}
+};
+
+/* Matches for gate clocks */
+static const __initconst struct of_device_id clk_gates_match[] = {
+ {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,},
+ {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,},
+ {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,},
+ {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,},
+ {}
+};
+
+static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match,
+ void *function)
+{
+ struct device_node *np;
+ const struct div_data *data;
+ const struct of_device_id *match;
+ void (*setup_function)(struct device_node *, const void *) = function;
+
+ for_each_matching_node(np, clk_match) {
+ match = of_match_node(clk_match, np);
+ data = match->data;
+ setup_function(np, data);
+ }
+}
+
+void __init sunxi_init_clocks(void)
+{
+ /* Register all the simple sunxi clocks on DT */
+ of_clk_init(clk_match);
+
+ /* Register factor clocks */
+ of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
+
+ /* Register divider clocks */
+ of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
+
+ /* Register mux clocks */
+ of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
+
+ /* Register gate clocks */
+ of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup);
+}
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 1e2de7305362..f873dcefe0de 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -703,7 +703,7 @@ static void tegra20_pll_init(void)
clks[pll_a_out0] = clk;
/* PLLE */
- clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL,
+ clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, pmc_base,
0, 100000000, &pll_e_params,
0, pll_e_freq_table, NULL);
clk_register_clkdev(clk, "pll_e", NULL);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 0744731c6229..a09d7dcaf183 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -355,15 +355,16 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name,
struct tegra_clk_periph *periph, void __iomem *clk_base,
u32 offset);
-#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags, \
+#define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \
_div_shift, _div_width, _div_frac_width, \
_div_flags, _clk_num, _enb_refcnt, _regs, \
- _gate_flags) \
+ _gate_flags, _table) \
{ \
.mux = { \
.flags = _mux_flags, \
.shift = _mux_shift, \
- .width = _mux_width, \
+ .mask = _mux_mask, \
+ .table = _table, \
}, \
.divider = { \
.flags = _div_flags, \
@@ -393,26 +394,36 @@ struct tegra_periph_init_data {
const char *dev_id;
};
-#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \
- _mux_shift, _mux_width, _mux_flags, _div_shift, \
+#define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
+ _mux_shift, _mux_mask, _mux_flags, _div_shift, \
_div_width, _div_frac_width, _div_flags, _regs, \
- _clk_num, _enb_refcnt, _gate_flags, _clk_id) \
+ _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table) \
{ \
.name = _name, \
.clk_id = _clk_id, \
.parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \
- .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width, \
+ .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \
_mux_flags, _div_shift, \
_div_width, _div_frac_width, \
_div_flags, _clk_num, \
_enb_refcnt, _regs, \
- _gate_flags), \
+ _gate_flags, _table), \
.offset = _offset, \
.con_id = _con_id, \
.dev_id = _dev_id, \
}
+#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\
+ _mux_shift, _mux_width, _mux_flags, _div_shift, \
+ _div_width, _div_frac_width, _div_flags, _regs, \
+ _clk_num, _enb_refcnt, _gate_flags, _clk_id) \
+ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\
+ _mux_shift, BIT(_mux_width) - 1, _mux_flags, \
+ _div_shift, _div_width, _div_frac_width, _div_flags, \
+ _regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\
+ NULL)
+
/**
* struct clk_super_mux - super clock
*
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
index bcc0c11a507c..c6a806ed0e8c 100644
--- a/drivers/clk/ux500/Makefile
+++ b/drivers/clk/ux500/Makefile
@@ -5,6 +5,7 @@
# Clock types
obj-y += clk-prcc.o
obj-y += clk-prcmu.o
+obj-y += clk-sysctrl.o
# Clock definitions
obj-y += u8500_clk.o
diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c
index 9f7400d74fa7..a0fca004abc1 100644
--- a/drivers/clk/ux500/abx500-clk.c
+++ b/drivers/clk/ux500/abx500-clk.c
@@ -12,13 +12,78 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
-
-/* TODO: Add clock implementations here */
-
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include "clk.h"
/* Clock definitions for ab8500 */
static int ab8500_reg_clks(struct device *dev)
{
+ int ret;
+ struct clk *clk;
+
+ const char *intclk_parents[] = {"ab8500_sysclk", "ulpclk"};
+ u16 intclk_reg_sel[] = {0 , AB8500_SYSULPCLKCTRL1};
+ u8 intclk_reg_mask[] = {0 , AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_MASK};
+ u8 intclk_reg_bits[] = {
+ 0 ,
+ (1 << AB8500_SYSULPCLKCTRL1_SYSULPCLKINTSEL_SHIFT)
+ };
+
+ dev_info(dev, "register clocks for ab850x\n");
+
+ /* Enable SWAT */
+ ret = ab8500_sysctrl_set(AB8500_SWATCTRL, AB8500_SWATCTRL_SWATENABLE);
+ if (ret)
+ return ret;
+
+ /* ab8500_sysclk */
+ clk = clk_reg_prcmu_gate("ab8500_sysclk", NULL, PRCMU_SYSCLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");
+ clk_register_clkdev(clk, "sysclk", "ab-iddet.0");
+ clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, "sysclk", "shrm_bus");
+
+ /* ab8500_sysclk2 */
+ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk2", "ab8500_sysclk",
+ AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ,
+ AB8500_SYSULPCLKCTRL1_SYSCLKBUF2REQ, 0, 0);
+ clk_register_clkdev(clk, "sysclk", "0-0070");
+
+ /* ab8500_sysclk3 */
+ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk3", "ab8500_sysclk",
+ AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ,
+ AB8500_SYSULPCLKCTRL1_SYSCLKBUF3REQ, 0, 0);
+ clk_register_clkdev(clk, "sysclk", "cg1960_core.0");
+
+ /* ab8500_sysclk4 */
+ clk = clk_reg_sysctrl_gate(dev , "ab8500_sysclk4", "ab8500_sysclk",
+ AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ,
+ AB8500_SYSULPCLKCTRL1_SYSCLKBUF4REQ, 0, 0);
+
+ /* ab_ulpclk */
+ clk = clk_reg_sysctrl_gate_fixed_rate(dev, "ulpclk", NULL,
+ AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
+ AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
+ 38400000, 9000, CLK_IS_ROOT);
+ clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0");
+
+ /* ab8500_intclk */
+ clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
+ intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
+ clk_register_clkdev(clk, "intclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, NULL, "ab8500-pwm.1");
+
+ /* ab8500_audioclk */
+ clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
+ AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
+ AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
+ clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0");
+
return 0;
}
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index 74faa7e3cf59..293a28854417 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -20,15 +20,23 @@
struct clk_prcmu {
struct clk_hw hw;
u8 cg_sel;
+ int is_prepared;
int is_enabled;
+ int opp_requested;
};
/* PRCMU clock operations. */
static int clk_prcmu_prepare(struct clk_hw *hw)
{
+ int ret;
struct clk_prcmu *clk = to_clk_prcmu(hw);
- return prcmu_request_clock(clk->cg_sel, true);
+
+ ret = prcmu_request_clock(clk->cg_sel, true);
+ if (!ret)
+ clk->is_prepared = 1;
+
+ return ret;;
}
static void clk_prcmu_unprepare(struct clk_hw *hw)
@@ -36,7 +44,15 @@ static void clk_prcmu_unprepare(struct clk_hw *hw)
struct clk_prcmu *clk = to_clk_prcmu(hw);
if (prcmu_request_clock(clk->cg_sel, false))
pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- hw->init->name);
+ __clk_get_name(hw->clk));
+ else
+ clk->is_prepared = 0;
+}
+
+static int clk_prcmu_is_prepared(struct clk_hw *hw)
+{
+ struct clk_prcmu *clk = to_clk_prcmu(hw);
+ return clk->is_prepared;
}
static int clk_prcmu_enable(struct clk_hw *hw)
@@ -79,58 +95,52 @@ static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
return prcmu_set_clock_rate(clk->cg_sel, rate);
}
-static int request_ape_opp100(bool enable)
-{
- static int reqs;
- int err = 0;
-
- if (enable) {
- if (!reqs)
- err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
- "clock", 100);
- if (!err)
- reqs++;
- } else {
- reqs--;
- if (!reqs)
- prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
- "clock");
- }
- return err;
-}
-
static int clk_prcmu_opp_prepare(struct clk_hw *hw)
{
int err;
struct clk_prcmu *clk = to_clk_prcmu(hw);
- err = request_ape_opp100(true);
- if (err) {
- pr_err("clk_prcmu: %s failed to request APE OPP100 for %s.\n",
- __func__, hw->init->name);
- return err;
+ if (!clk->opp_requested) {
+ err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
+ (char *)__clk_get_name(hw->clk),
+ 100);
+ if (err) {
+ pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
+ __func__, __clk_get_name(hw->clk));
+ return err;
+ }
+ clk->opp_requested = 1;
}
err = prcmu_request_clock(clk->cg_sel, true);
- if (err)
- request_ape_opp100(false);
+ if (err) {
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
+ (char *)__clk_get_name(hw->clk));
+ clk->opp_requested = 0;
+ return err;
+ }
- return err;
+ clk->is_prepared = 1;
+ return 0;
}
static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- if (prcmu_request_clock(clk->cg_sel, false))
- goto out_error;
- if (request_ape_opp100(false))
- goto out_error;
- return;
-
-out_error:
- pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- hw->init->name);
+ if (prcmu_request_clock(clk->cg_sel, false)) {
+ pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+ __clk_get_name(hw->clk));
+ return;
+ }
+
+ if (clk->opp_requested) {
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
+ (char *)__clk_get_name(hw->clk));
+ clk->opp_requested = 0;
+ }
+
+ clk->is_prepared = 0;
}
static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
@@ -138,38 +148,49 @@ static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
int err;
struct clk_prcmu *clk = to_clk_prcmu(hw);
- err = prcmu_request_ape_opp_100_voltage(true);
- if (err) {
- pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n",
- __func__, hw->init->name);
- return err;
+ if (!clk->opp_requested) {
+ err = prcmu_request_ape_opp_100_voltage(true);
+ if (err) {
+ pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
+ __func__, __clk_get_name(hw->clk));
+ return err;
+ }
+ clk->opp_requested = 1;
}
err = prcmu_request_clock(clk->cg_sel, true);
- if (err)
+ if (err) {
prcmu_request_ape_opp_100_voltage(false);
+ clk->opp_requested = 0;
+ return err;
+ }
- return err;
+ clk->is_prepared = 1;
+ return 0;
}
static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
{
struct clk_prcmu *clk = to_clk_prcmu(hw);
- if (prcmu_request_clock(clk->cg_sel, false))
- goto out_error;
- if (prcmu_request_ape_opp_100_voltage(false))
- goto out_error;
- return;
-
-out_error:
- pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
- hw->init->name);
+ if (prcmu_request_clock(clk->cg_sel, false)) {
+ pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+ __clk_get_name(hw->clk));
+ return;
+ }
+
+ if (clk->opp_requested) {
+ prcmu_request_ape_opp_100_voltage(false);
+ clk->opp_requested = 0;
+ }
+
+ clk->is_prepared = 0;
}
static struct clk_ops clk_prcmu_scalable_ops = {
.prepare = clk_prcmu_prepare,
.unprepare = clk_prcmu_unprepare,
+ .is_prepared = clk_prcmu_is_prepared,
.enable = clk_prcmu_enable,
.disable = clk_prcmu_disable,
.is_enabled = clk_prcmu_is_enabled,
@@ -181,6 +202,7 @@ static struct clk_ops clk_prcmu_scalable_ops = {
static struct clk_ops clk_prcmu_gate_ops = {
.prepare = clk_prcmu_prepare,
.unprepare = clk_prcmu_unprepare,
+ .is_prepared = clk_prcmu_is_prepared,
.enable = clk_prcmu_enable,
.disable = clk_prcmu_disable,
.is_enabled = clk_prcmu_is_enabled,
@@ -202,6 +224,7 @@ static struct clk_ops clk_prcmu_rate_ops = {
static struct clk_ops clk_prcmu_opp_gate_ops = {
.prepare = clk_prcmu_opp_prepare,
.unprepare = clk_prcmu_opp_unprepare,
+ .is_prepared = clk_prcmu_is_prepared,
.enable = clk_prcmu_enable,
.disable = clk_prcmu_disable,
.is_enabled = clk_prcmu_is_enabled,
@@ -211,6 +234,7 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
.prepare = clk_prcmu_opp_volt_prepare,
.unprepare = clk_prcmu_opp_volt_unprepare,
+ .is_prepared = clk_prcmu_is_prepared,
.enable = clk_prcmu_enable,
.disable = clk_prcmu_disable,
.is_enabled = clk_prcmu_is_enabled,
@@ -242,7 +266,9 @@ static struct clk *clk_reg_prcmu(const char *name,
}
clk->cg_sel = cg_sel;
+ clk->is_prepared = 1;
clk->is_enabled = 1;
+ clk->opp_requested = 0;
/* "rate" can be used for changing the initial frequency */
if (rate)
prcmu_set_clock_rate(cg_sel, rate);
diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c
new file mode 100644
index 000000000000..bc7e9bde792b
--- /dev/null
+++ b/drivers/clk/ux500/clk-sysctrl.c
@@ -0,0 +1,221 @@
+/*
+ * Sysctrl clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2013 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include "clk.h"
+
+#define SYSCTRL_MAX_NUM_PARENTS 4
+
+#define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw)
+
+struct clk_sysctrl {
+ struct clk_hw hw;
+ struct device *dev;
+ u8 parent_index;
+ u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS];
+ u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS];
+ u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS];
+ unsigned long rate;
+ unsigned long enable_delay_us;
+};
+
+/* Sysctrl clock operations. */
+
+static int clk_sysctrl_prepare(struct clk_hw *hw)
+{
+ int ret;
+ struct clk_sysctrl *clk = to_clk_sysctrl(hw);
+
+ ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0],
+ clk->reg_bits[0]);
+
+ if (!ret && clk->enable_delay_us)
+ usleep_range(clk->enable_delay_us, clk->enable_delay_us);
+
+ return ret;
+}
+
+static void clk_sysctrl_unprepare(struct clk_hw *hw)
+{
+ struct clk_sysctrl *clk = to_clk_sysctrl(hw);
+ if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0]))
+ dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n",
+ __func__, __clk_get_name(hw->clk));
+}
+
+static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_sysctrl *clk = to_clk_sysctrl(hw);
+ return clk->rate;
+}
+
+static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_sysctrl *clk = to_clk_sysctrl(hw);
+ u8 old_index = clk->parent_index;
+ int ret = 0;
+
+ if (clk->reg_sel[old_index]) {
+ ret = ab8500_sysctrl_clear(clk->reg_sel[old_index],
+ clk->reg_mask[old_index]);
+ if (ret)
+ return ret;
+ }
+
+ if (clk->reg_sel[index]) {
+ ret = ab8500_sysctrl_write(clk->reg_sel[index],
+ clk->reg_mask[index],
+ clk->reg_bits[index]);
+ if (ret) {
+ if (clk->reg_sel[old_index])
+ ab8500_sysctrl_write(clk->reg_sel[old_index],
+ clk->reg_mask[old_index],
+ clk->reg_bits[old_index]);
+ return ret;
+ }
+ }
+ clk->parent_index = index;
+
+ return ret;
+}
+
+static u8 clk_sysctrl_get_parent(struct clk_hw *hw)
+{
+ struct clk_sysctrl *clk = to_clk_sysctrl(hw);
+ return clk->parent_index;
+}
+
+static struct clk_ops clk_sysctrl_gate_ops = {
+ .prepare = clk_sysctrl_prepare,
+ .unprepare = clk_sysctrl_unprepare,
+};
+
+static struct clk_ops clk_sysctrl_gate_fixed_rate_ops = {
+ .prepare = clk_sysctrl_prepare,
+ .unprepare = clk_sysctrl_unprepare,
+ .recalc_rate = clk_sysctrl_recalc_rate,
+};
+
+static struct clk_ops clk_sysctrl_set_parent_ops = {
+ .set_parent = clk_sysctrl_set_parent,
+ .get_parent = clk_sysctrl_get_parent,
+};
+
+static struct clk *clk_reg_sysctrl(struct device *dev,
+ const char *name,
+ const char **parent_names,
+ u8 num_parents,
+ u16 *reg_sel,
+ u8 *reg_mask,
+ u8 *reg_bits,
+ unsigned long rate,
+ unsigned long enable_delay_us,
+ unsigned long flags,
+ struct clk_ops *clk_sysctrl_ops)
+{
+ struct clk_sysctrl *clk;
+ struct clk_init_data clk_sysctrl_init;
+ struct clk *clk_reg;
+ int i;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) {
+ dev_err(dev, "clk_sysctrl: invalid arguments passed\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ clk = devm_kzalloc(dev, sizeof(struct clk_sysctrl), GFP_KERNEL);
+ if (!clk) {
+ dev_err(dev, "clk_sysctrl: could not allocate clk\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < num_parents; i++) {
+ clk->reg_sel[i] = reg_sel[i];
+ clk->reg_bits[i] = reg_bits[i];
+ clk->reg_mask[i] = reg_mask[i];
+ }
+
+ clk->parent_index = 0;
+ clk->rate = rate;
+ clk->enable_delay_us = enable_delay_us;
+ clk->dev = dev;
+
+ clk_sysctrl_init.name = name;
+ clk_sysctrl_init.ops = clk_sysctrl_ops;
+ clk_sysctrl_init.flags = flags;
+ clk_sysctrl_init.parent_names = parent_names;
+ clk_sysctrl_init.num_parents = num_parents;
+ clk->hw.init = &clk_sysctrl_init;
+
+ clk_reg = devm_clk_register(clk->dev, &clk->hw);
+ if (IS_ERR(clk_reg))
+ dev_err(dev, "clk_sysctrl: clk_register failed\n");
+
+ return clk_reg;
+}
+
+struct clk *clk_reg_sysctrl_gate(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ u16 reg_sel,
+ u8 reg_mask,
+ u8 reg_bits,
+ unsigned long enable_delay_us,
+ unsigned long flags)
+{
+ const char **parent_names = (parent_name ? &parent_name : NULL);
+ u8 num_parents = (parent_name ? 1 : 0);
+
+ return clk_reg_sysctrl(dev, name, parent_names, num_parents,
+ &reg_sel, &reg_mask, &reg_bits, 0, enable_delay_us,
+ flags, &clk_sysctrl_gate_ops);
+}
+
+struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ u16 reg_sel,
+ u8 reg_mask,
+ u8 reg_bits,
+ unsigned long rate,
+ unsigned long enable_delay_us,
+ unsigned long flags)
+{
+ const char **parent_names = (parent_name ? &parent_name : NULL);
+ u8 num_parents = (parent_name ? 1 : 0);
+
+ return clk_reg_sysctrl(dev, name, parent_names, num_parents,
+ &reg_sel, &reg_mask, &reg_bits,
+ rate, enable_delay_us, flags,
+ &clk_sysctrl_gate_fixed_rate_ops);
+}
+
+struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
+ const char *name,
+ const char **parent_names,
+ u8 num_parents,
+ u16 *reg_sel,
+ u8 *reg_mask,
+ u8 *reg_bits,
+ unsigned long flags)
+{
+ return clk_reg_sysctrl(dev, name, parent_names, num_parents,
+ reg_sel, reg_mask, reg_bits, 0, 0, flags,
+ &clk_sysctrl_set_parent_ops);
+}
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
index c3e449169a83..a2bb92d85ee0 100644
--- a/drivers/clk/ux500/clk.h
+++ b/drivers/clk/ux500/clk.h
@@ -11,16 +11,18 @@
#define __UX500_CLK_H
#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/types.h>
struct clk *clk_reg_prcc_pclk(const char *name,
const char *parent_name,
- unsigned int phy_base,
+ resource_size_t phy_base,
u32 cg_sel,
unsigned long flags);
struct clk *clk_reg_prcc_kclk(const char *name,
const char *parent_name,
- unsigned int phy_base,
+ resource_size_t phy_base,
u32 cg_sel,
unsigned long flags);
@@ -57,4 +59,32 @@ struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
unsigned long rate,
unsigned long flags);
+struct clk *clk_reg_sysctrl_gate(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ u16 reg_sel,
+ u8 reg_mask,
+ u8 reg_bits,
+ unsigned long enable_delay_us,
+ unsigned long flags);
+
+struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ u16 reg_sel,
+ u8 reg_mask,
+ u8 reg_bits,
+ unsigned long rate,
+ unsigned long enable_delay_us,
+ unsigned long flags);
+
+struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
+ const char *name,
+ const char **parent_names,
+ u8 num_parents,
+ u16 *reg_sel,
+ u8 *reg_mask,
+ u8 *reg_bits,
+ unsigned long flags);
+
#endif /* __UX500_CLK_H */
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index ec3b88fe3e6d..c16ca787170a 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -3,5 +3,5 @@ obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
-obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
+obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o clk-sp810.o
obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c
new file mode 100644
index 000000000000..bf9b15a585e1
--- /dev/null
+++ b/drivers/clk/versatile/clk-sp810.c
@@ -0,0 +1,188 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2013 ARM Limited
+ */
+
+#include <linux/amba/sp810.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define to_clk_sp810_timerclken(_hw) \
+ container_of(_hw, struct clk_sp810_timerclken, hw)
+
+struct clk_sp810;
+
+struct clk_sp810_timerclken {
+ struct clk_hw hw;
+ struct clk *clk;
+ struct clk_sp810 *sp810;
+ int channel;
+};
+
+struct clk_sp810 {
+ struct device_node *node;
+ int refclk_index, timclk_index;
+ void __iomem *base;
+ spinlock_t lock;
+ struct clk_sp810_timerclken timerclken[4];
+ struct clk *refclk;
+ struct clk *timclk;
+};
+
+static u8 clk_sp810_timerclken_get_parent(struct clk_hw *hw)
+{
+ struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
+ u32 val = readl(timerclken->sp810->base + SCCTRL);
+
+ return !!(val & (1 << SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel)));
+}
+
+static int clk_sp810_timerclken_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
+ struct clk_sp810 *sp810 = timerclken->sp810;
+ u32 val, shift = SCCTRL_TIMERENnSEL_SHIFT(timerclken->channel);
+ unsigned long flags = 0;
+
+ if (WARN_ON(index > 1))
+ return -EINVAL;
+
+ spin_lock_irqsave(&sp810->lock, flags);
+
+ val = readl(sp810->base + SCCTRL);
+ val &= ~(1 << shift);
+ val |= index << shift;
+ writel(val, sp810->base + SCCTRL);
+
+ spin_unlock_irqrestore(&sp810->lock, flags);
+
+ return 0;
+}
+
+/*
+ * FIXME - setting the parent every time .prepare is invoked is inefficient.
+ * This is better handled by a dedicated clock tree configuration mechanism at
+ * init-time. Revisit this later when such a mechanism exists
+ */
+static int clk_sp810_timerclken_prepare(struct clk_hw *hw)
+{
+ struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
+ struct clk_sp810 *sp810 = timerclken->sp810;
+ struct clk *old_parent = __clk_get_parent(hw->clk);
+ struct clk *new_parent;
+
+ if (!sp810->refclk)
+ sp810->refclk = of_clk_get(sp810->node, sp810->refclk_index);
+
+ if (!sp810->timclk)
+ sp810->timclk = of_clk_get(sp810->node, sp810->timclk_index);
+
+ if (WARN_ON(IS_ERR(sp810->refclk) || IS_ERR(sp810->timclk)))
+ return -ENOENT;
+
+ /* Select fastest parent */
+ if (clk_get_rate(sp810->refclk) > clk_get_rate(sp810->timclk))
+ new_parent = sp810->refclk;
+ else
+ new_parent = sp810->timclk;
+
+ /* Switch the parent if necessary */
+ if (old_parent != new_parent) {
+ clk_prepare(new_parent);
+ clk_set_parent(hw->clk, new_parent);
+ clk_unprepare(old_parent);
+ }
+
+ return 0;
+}
+
+static void clk_sp810_timerclken_unprepare(struct clk_hw *hw)
+{
+ struct clk_sp810_timerclken *timerclken = to_clk_sp810_timerclken(hw);
+ struct clk_sp810 *sp810 = timerclken->sp810;
+
+ clk_put(sp810->timclk);
+ clk_put(sp810->refclk);
+}
+
+static const struct clk_ops clk_sp810_timerclken_ops = {
+ .prepare = clk_sp810_timerclken_prepare,
+ .unprepare = clk_sp810_timerclken_unprepare,
+ .get_parent = clk_sp810_timerclken_get_parent,
+ .set_parent = clk_sp810_timerclken_set_parent,
+};
+
+struct clk *clk_sp810_timerclken_of_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct clk_sp810 *sp810 = data;
+
+ if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
+ ARRAY_SIZE(sp810->timerclken)))
+ return NULL;
+
+ return sp810->timerclken[clkspec->args[0]].clk;
+}
+
+void __init clk_sp810_of_setup(struct device_node *node)
+{
+ struct clk_sp810 *sp810 = kzalloc(sizeof(*sp810), GFP_KERNEL);
+ const char *parent_names[2];
+ char name[12];
+ struct clk_init_data init;
+ int i;
+
+ if (!sp810) {
+ pr_err("Failed to allocate memory for SP810!\n");
+ return;
+ }
+
+ sp810->refclk_index = of_property_match_string(node, "clock-names",
+ "refclk");
+ parent_names[0] = of_clk_get_parent_name(node, sp810->refclk_index);
+
+ sp810->timclk_index = of_property_match_string(node, "clock-names",
+ "timclk");
+ parent_names[1] = of_clk_get_parent_name(node, sp810->timclk_index);
+
+ if (parent_names[0] <= 0 || parent_names[1] <= 0) {
+ pr_warn("Failed to obtain parent clocks for SP810!\n");
+ return;
+ }
+
+ sp810->node = node;
+ sp810->base = of_iomap(node, 0);
+ spin_lock_init(&sp810->lock);
+
+ init.name = name;
+ init.ops = &clk_sp810_timerclken_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = ARRAY_SIZE(parent_names);
+
+ for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) {
+ snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+
+ sp810->timerclken[i].sp810 = sp810;
+ sp810->timerclken[i].channel = i;
+ sp810->timerclken[i].hw.init = &init;
+
+ sp810->timerclken[i].clk = clk_register(NULL,
+ &sp810->timerclken[i].hw);
+ WARN_ON(IS_ERR(sp810->timerclken[i].clk));
+ }
+
+ of_clk_add_provider(node, clk_sp810_timerclken_of_get, sp810);
+}
+CLK_OF_DECLARE(sp810, "arm,sp810", clk_sp810_of_setup);
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
index 82b45aad8ccf..a4a728d05092 100644
--- a/drivers/clk/versatile/clk-vexpress.c
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -15,8 +15,6 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
#include <linux/vexpress.h>
static struct clk *vexpress_sp810_timerclken[4];
@@ -86,50 +84,3 @@ void __init vexpress_clk_init(void __iomem *sp810_base)
WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
"v2m-timer1", "sp804"));
}
-
-#if defined(CONFIG_OF)
-
-struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
-{
- if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
- ARRAY_SIZE(vexpress_sp810_timerclken)))
- return NULL;
-
- return vexpress_sp810_timerclken[clkspec->args[0]];
-}
-
-void __init vexpress_clk_of_init(void)
-{
- struct device_node *node;
- struct clk *clk;
- struct clk *refclk, *timclk;
-
- of_clk_init(NULL);
-
- node = of_find_compatible_node(NULL, NULL, "arm,sp810");
- vexpress_sp810_init(of_iomap(node, 0));
- of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
-
- /* Select "better" (faster) parent for SP804 timers */
- refclk = of_clk_get_by_name(node, "refclk");
- timclk = of_clk_get_by_name(node, "timclk");
- if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
- int i = 0;
-
- if (clk_get_rate(refclk) > clk_get_rate(timclk))
- clk = refclk;
- else
- clk = timclk;
-
- for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
- WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
- clk));
- }
-
- WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
- "v2m-timer0", "sp804"));
- WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
- "v2m-timer1", "sp804"));
-}
-
-#endif
diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile
index f9ba4fab0ddc..04781389d0fb 100644
--- a/drivers/clk/x86/Makefile
+++ b/drivers/clk/x86/Makefile
@@ -1,2 +1,2 @@
-clk-x86-lpss-objs := clk-lpss.o clk-lpt.o
+clk-x86-lpss-objs := clk-lpt.o
obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o
diff --git a/drivers/clk/x86/clk-lpss.c b/drivers/clk/x86/clk-lpss.c
deleted file mode 100644
index b5e229f3c3d9..000000000000
--- a/drivers/clk/x86/clk-lpss.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Intel Low Power Subsystem clocks.
- *
- * Copyright (C) 2013, Intel Corporation
- * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
- * Heikki Krogerus <heikki.krogerus@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/acpi.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/module.h>
-
-static int clk_lpss_is_mmio_resource(struct acpi_resource *res, void *data)
-{
- struct resource r;
- return !acpi_dev_resource_memory(res, &r);
-}
-
-static acpi_status clk_lpss_find_mmio(acpi_handle handle, u32 level,
- void *data, void **retval)
-{
- struct resource_list_entry *rentry;
- struct list_head resource_list;
- struct acpi_device *adev;
- const char *uid = data;
- int ret;
-
- if (acpi_bus_get_device(handle, &adev))
- return AE_OK;
-
- if (uid) {
- if (!adev->pnp.unique_id)
- return AE_OK;
- if (strcmp(uid, adev->pnp.unique_id))
- return AE_OK;
- }
-
- INIT_LIST_HEAD(&resource_list);
- ret = acpi_dev_get_resources(adev, &resource_list,
- clk_lpss_is_mmio_resource, NULL);
- if (ret < 0)
- return AE_NO_MEMORY;
-
- list_for_each_entry(rentry, &resource_list, node)
- if (resource_type(&rentry->res) == IORESOURCE_MEM) {
- *(struct resource *)retval = rentry->res;
- break;
- }
-
- acpi_dev_free_resource_list(&resource_list);
- return AE_OK;
-}
-
-/**
- * clk_register_lpss_gate - register LPSS clock gate
- * @name: name of this clock gate
- * @parent_name: parent clock name
- * @hid: ACPI _HID of the device
- * @uid: ACPI _UID of the device (optional)
- * @offset: LPSS PRV_CLOCK_PARAMS offset
- *
- * Creates and registers LPSS clock gate.
- */
-struct clk *clk_register_lpss_gate(const char *name, const char *parent_name,
- const char *hid, const char *uid,
- unsigned offset)
-{
- struct resource res = { };
- void __iomem *mmio_base;
- acpi_status status;
- struct clk *clk;
-
- /*
- * First try to look the device and its mmio resource from the
- * ACPI namespace.
- */
- status = acpi_get_devices(hid, clk_lpss_find_mmio, (void *)uid,
- (void **)&res);
- if (ACPI_FAILURE(status) || !res.start)
- return ERR_PTR(-ENODEV);
-
- mmio_base = ioremap(res.start, resource_size(&res));
- if (!mmio_base)
- return ERR_PTR(-ENOMEM);
-
- clk = clk_register_gate(NULL, name, parent_name, 0, mmio_base + offset,
- 0, 0, NULL);
- if (IS_ERR(clk))
- iounmap(mmio_base);
-
- return clk;
-}
diff --git a/drivers/clk/x86/clk-lpss.h b/drivers/clk/x86/clk-lpss.h
deleted file mode 100644
index e9460f442297..000000000000
--- a/drivers/clk/x86/clk-lpss.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Intel Low Power Subsystem clock.
- *
- * Copyright (C) 2013, Intel Corporation
- * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
- * Heikki Krogerus <heikki.krogerus@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __CLK_LPSS_H
-#define __CLK_LPSS_H
-
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-
-#ifdef CONFIG_ACPI
-extern struct clk *clk_register_lpss_gate(const char *name,
- const char *parent_name,
- const char *hid, const char *uid,
- unsigned offset);
-#else
-static inline struct clk *clk_register_lpss_gate(const char *name,
- const char *parent_name,
- const char *hid,
- const char *uid,
- unsigned offset)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif
-
-#endif /* __CLK_LPSS_H */
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
index 81298aeef7e3..5cf4f4686406 100644
--- a/drivers/clk/x86/clk-lpt.c
+++ b/drivers/clk/x86/clk-lpt.c
@@ -10,7 +10,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -18,8 +17,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include "clk-lpss.h"
-
#define PRV_CLOCK_PARAMS 0x800
static int lpt_clk_probe(struct platform_device *pdev)
@@ -34,40 +31,6 @@ static int lpt_clk_probe(struct platform_device *pdev)
/* Shared DMA clock */
clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto");
-
- /* SPI clocks */
- clk = clk_register_lpss_gate("spi0_clk", "lpss_clk", "INT33C0", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C0:00");
-
- clk = clk_register_lpss_gate("spi1_clk", "lpss_clk", "INT33C1", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C1:00");
-
- /* I2C clocks */
- clk = clk_register_lpss_gate("i2c0_clk", "lpss_clk", "INT33C2", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C2:00");
-
- clk = clk_register_lpss_gate("i2c1_clk", "lpss_clk", "INT33C3", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C3:00");
-
- /* UART clocks */
- clk = clk_register_lpss_gate("uart0_clk", "lpss_clk", "INT33C4", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C4:00");
-
- clk = clk_register_lpss_gate("uart1_clk", "lpss_clk", "INT33C5", NULL,
- PRV_CLOCK_PARAMS);
- if (!IS_ERR(clk))
- clk_register_clkdev(clk, NULL, "INT33C5:00");
-
return 0;
}
@@ -79,8 +42,7 @@ static struct platform_driver lpt_clk_driver = {
.probe = lpt_clk_probe,
};
-static int __init lpt_clk_init(void)
+int __init lpt_clk_init(void)
{
return platform_driver_register(&lpt_clk_driver);
}
-arch_initcall(lpt_clk_init);
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4d8283aec5b5..96e25319659b 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
+obj-$(CONFIG_ARCH_BCM) += bcm_kona_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c
new file mode 100644
index 000000000000..350f49356458
--- /dev/null
+++ b/drivers/clocksource/bcm_kona_timer.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2012 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
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/types.h>
+
+#include <linux/io.h>
+#include <asm/mach/time.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+
+#define KONA_GPTIMER_STCS_OFFSET 0x00000000
+#define KONA_GPTIMER_STCLO_OFFSET 0x00000004
+#define KONA_GPTIMER_STCHI_OFFSET 0x00000008
+#define KONA_GPTIMER_STCM0_OFFSET 0x0000000C
+
+#define KONA_GPTIMER_STCS_TIMER_MATCH_SHIFT 0
+#define KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT 4
+
+struct kona_bcm_timers {
+ int tmr_irq;
+ void __iomem *tmr_regs;
+};
+
+static struct kona_bcm_timers timers;
+
+static u32 arch_timer_rate;
+
+/*
+ * We use the peripheral timers for system tick, the cpu global timer for
+ * profile tick
+ */
+static void kona_timer_disable_and_clear(void __iomem *base)
+{
+ uint32_t reg;
+
+ /*
+ * clear and disable interrupts
+ * We are using compare/match register 0 for our system interrupts
+ */
+ reg = readl(base + KONA_GPTIMER_STCS_OFFSET);
+
+ /* Clear compare (0) interrupt */
+ reg |= 1 << KONA_GPTIMER_STCS_TIMER_MATCH_SHIFT;
+ /* disable compare */
+ reg &= ~(1 << KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT);
+
+ writel(reg, base + KONA_GPTIMER_STCS_OFFSET);
+
+}
+
+static void
+kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
+{
+ void __iomem *base = IOMEM(timer_base);
+ int loop_limit = 4;
+
+ /*
+ * Read 64-bit free running counter
+ * 1. Read hi-word
+ * 2. Read low-word
+ * 3. Read hi-word again
+ * 4.1
+ * if new hi-word is not equal to previously read hi-word, then
+ * start from #1
+ * 4.2
+ * if new hi-word is equal to previously read hi-word then stop.
+ */
+
+ while (--loop_limit) {
+ *msw = readl(base + KONA_GPTIMER_STCHI_OFFSET);
+ *lsw = readl(base + KONA_GPTIMER_STCLO_OFFSET);
+ if (*msw == readl(base + KONA_GPTIMER_STCHI_OFFSET))
+ break;
+ }
+ if (!loop_limit) {
+ pr_err("bcm_kona_timer: getting counter failed.\n");
+ pr_err(" Timer will be impacted\n");
+ }
+
+ return;
+}
+
+static const struct of_device_id bcm_timer_ids[] __initconst = {
+ {.compatible = "bcm,kona-timer"},
+ {},
+};
+
+static void __init kona_timers_init(void)
+{
+ struct device_node *node;
+ u32 freq;
+
+ node = of_find_matching_node(NULL, bcm_timer_ids);
+
+ if (!node)
+ panic("No timer");
+
+ if (!of_property_read_u32(node, "clock-frequency", &freq))
+ arch_timer_rate = freq;
+ else
+ panic("clock-frequency not set in the .dts file");
+
+ /* Setup IRQ numbers */
+ timers.tmr_irq = irq_of_parse_and_map(node, 0);
+
+ /* Setup IO addresses */
+ timers.tmr_regs = of_iomap(node, 0);
+
+ kona_timer_disable_and_clear(timers.tmr_regs);
+}
+
+static int kona_timer_set_next_event(unsigned long clc,
+ struct clock_event_device *unused)
+{
+ /*
+ * timer (0) is disabled by the timer interrupt already
+ * so, here we reload the next event value and re-enable
+ * the timer.
+ *
+ * This way, we are potentially losing the time between
+ * timer-interrupt->set_next_event. CPU local timers, when
+ * they come in should get rid of skew.
+ */
+
+ uint32_t lsw, msw;
+ uint32_t reg;
+
+ kona_timer_get_counter(timers.tmr_regs, &msw, &lsw);
+
+ /* Load the "next" event tick value */
+ writel(lsw + clc, timers.tmr_regs + KONA_GPTIMER_STCM0_OFFSET);
+
+ /* Enable compare */
+ reg = readl(timers.tmr_regs + KONA_GPTIMER_STCS_OFFSET);
+ reg |= (1 << KONA_GPTIMER_STCS_COMPARE_ENABLE_SHIFT);
+ writel(reg, timers.tmr_regs + KONA_GPTIMER_STCS_OFFSET);
+
+ return 0;
+}
+
+static void kona_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *unused)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* by default mode is one shot don't do any thing */
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ kona_timer_disable_and_clear(timers.tmr_regs);
+ }
+}
+
+static struct clock_event_device kona_clockevent_timer = {
+ .name = "timer 1",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = kona_timer_set_next_event,
+ .set_mode = kona_timer_set_mode
+};
+
+static void __init kona_timer_clockevents_init(void)
+{
+ kona_clockevent_timer.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&kona_clockevent_timer,
+ arch_timer_rate, 6, 0xffffffff);
+}
+
+static irqreturn_t kona_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &kona_clockevent_timer;
+
+ kona_timer_disable_and_clear(timers.tmr_regs);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction kona_timer_irq = {
+ .name = "Kona Timer Tick",
+ .flags = IRQF_TIMER,
+ .handler = kona_timer_interrupt,
+};
+
+static void __init kona_timer_init(void)
+{
+ kona_timers_init();
+ kona_timer_clockevents_init();
+ setup_irq(timers.tmr_irq, &kona_timer_irq);
+ kona_timer_set_next_event((arch_timer_rate / HZ), NULL);
+}
+
+CLOCKSOURCE_OF_DECLARE(bcm_kona, "bcm,kona-timer",
+ kona_timer_init);
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
index 4086b9167159..0ce85e29769b 100644
--- a/drivers/clocksource/sunxi_timer.c
+++ b/drivers/clocksource/sunxi_timer.c
@@ -23,7 +23,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sunxi_timer.h>
-#include <linux/clk-provider.h>
+#include <linux/clk/sunxi.h>
#define TIMER_CTL_REG 0x00
#define TIMER_CTL_ENABLE (1 << 0)
@@ -123,7 +123,7 @@ void __init sunxi_timer_init(void)
if (irq <= 0)
panic("Can't parse IRQ");
- of_clk_init(NULL);
+ sunxi_init_clocks();
clk = of_clk_get(node, 0);
if (IS_ERR(clk))
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 1110478dd0fd..08ae128cce9b 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -232,6 +232,31 @@ void proc_comm_connector(struct task_struct *task)
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
}
+void proc_coredump_connector(struct task_struct *task)
+{
+ struct cn_msg *msg;
+ struct proc_event *ev;
+ __u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
+
+ if (atomic_read(&proc_event_num_listeners) < 1)
+ return;
+
+ msg = (struct cn_msg *)buffer;
+ ev = (struct proc_event *)msg->data;
+ get_seq(&msg->seq, &ev->cpu);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+ ev->what = PROC_EVENT_COREDUMP;
+ ev->event_data.coredump.process_pid = task->pid;
+ ev->event_data.coredump.process_tgid = task->tgid;
+
+ memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
+ msg->ack = 0; /* not used */
+ msg->len = sizeof(*ev);
+ cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
+}
+
void proc_exit_connector(struct task_struct *task)
{
struct cn_msg *msg;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index f1b7e244bfc1..6ecfa758942c 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <linux/list.h>
#include <linux/skbuff.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/moduleparam.h>
#include <linux/connector.h>
#include <linux/slab.h>
@@ -95,13 +95,13 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask)
if (!netlink_has_listeners(dev->nls, group))
return -ESRCH;
- size = NLMSG_SPACE(sizeof(*msg) + msg->len);
+ size = sizeof(*msg) + msg->len;
- skb = alloc_skb(size, gfp_mask);
+ skb = nlmsg_new(size, gfp_mask);
if (!skb)
return -ENOMEM;
- nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size, 0);
if (!nlh) {
kfree_skb(skb);
return -EMSGSIZE;
@@ -124,7 +124,7 @@ static int cn_call_callback(struct sk_buff *skb)
{
struct cn_callback_entry *i, *cbq = NULL;
struct cn_dev *dev = &cdev;
- struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb));
+ struct cn_msg *msg = nlmsg_data(nlmsg_hdr(skb));
struct netlink_skb_parms *nsp = &NETLINK_CB(skb);
int err = -ENODEV;
@@ -162,7 +162,7 @@ static void cn_rx_skb(struct sk_buff *__skb)
skb = skb_get(__skb);
- if (skb->len >= NLMSG_SPACE(0)) {
+ if (skb->len >= NLMSG_HDRLEN) {
nlh = nlmsg_hdr(skb);
if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index cbcb21e32771..a1488f58f6ca 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -205,10 +205,99 @@ depends on ARM
source "drivers/cpufreq/Kconfig.arm"
endmenu
+menu "AVR32 CPU frequency scaling drivers"
+depends on AVR32
+
+config AVR32_AT32AP_CPUFREQ
+ bool "CPU frequency driver for AT32AP"
+ depends on PLATFORM_AT32AP
+ default n
+ help
+ This enables the CPU frequency driver for AT32AP processors.
+ If in doubt, say N.
+
+endmenu
+
+menu "CPUFreq processor drivers"
+depends on IA64
+
+config IA64_ACPI_CPUFREQ
+ tristate "ACPI Processor P-States driver"
+ select CPU_FREQ_TABLE
+ depends on ACPI_PROCESSOR
+ help
+ This driver adds a CPUFreq driver which utilizes the ACPI
+ Processor Performance States.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+endmenu
+
+menu "MIPS CPUFreq processor drivers"
+depends on MIPS
+
+config LOONGSON2_CPUFREQ
+ tristate "Loongson2 CPUFreq Driver"
+ select CPU_FREQ_TABLE
+ help
+ This option adds a CPUFreq driver for loongson processors which
+ support software configurable cpu frequency.
+
+ Loongson2F and it's successors support this feature.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+endmenu
+
menu "PowerPC CPU frequency scaling drivers"
depends on PPC32 || PPC64
source "drivers/cpufreq/Kconfig.powerpc"
endmenu
+menu "SPARC CPU frequency scaling drivers"
+depends on SPARC64
+config SPARC_US3_CPUFREQ
+ tristate "UltraSPARC-III CPU Frequency driver"
+ select CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for UltraSPARC-III processors.
+
+ For details, take a look at <file:Documentation/cpu-freq>.
+
+ If in doubt, say N.
+
+config SPARC_US2E_CPUFREQ
+ tristate "UltraSPARC-IIe CPU Frequency driver"
+ select CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for UltraSPARC-IIe processors.
+
+ For details, take a look at <file:Documentation/cpu-freq>.
+
+ If in doubt, say N.
+endmenu
+
+menu "SH CPU Frequency scaling"
+depends on SUPERH
+config SH_CPU_FREQ
+ tristate "SuperH CPU Frequency driver"
+ select CPU_FREQ_TABLE
+ help
+ This adds the cpufreq driver for SuperH. Any CPU that supports
+ clock rate rounding through the clock framework can use this
+ driver. While it will make the kernel slightly larger, this is
+ harmless for CPUs that don't support rate rounding. The driver
+ will also generate a notice in the boot log before disabling
+ itself if the CPU in question is not capable of rate rounding.
+
+ For details, take a look at <file:Documentation/cpu-freq>.
+
+ If unsure, say N.
+endmenu
+
endif
endmenu
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 030ddf6dd3f1..f3af18b9acc5 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -2,6 +2,93 @@
# ARM CPU Frequency scaling drivers
#
+config ARM_BIG_LITTLE_CPUFREQ
+ tristate
+ depends on ARM_CPU_TOPOLOGY
+
+config ARM_DT_BL_CPUFREQ
+ tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
+ select ARM_BIG_LITTLE_CPUFREQ
+ depends on OF && HAVE_CLK
+ help
+ This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
+ This gets frequency tables from DT.
+
+config ARM_EXYNOS_CPUFREQ
+ bool "SAMSUNG EXYNOS SoCs"
+ depends on ARCH_EXYNOS
+ default y
+ help
+ This adds the CPUFreq driver common part for Samsung
+ EXYNOS SoCs.
+
+ If in doubt, say N.
+
+config ARM_EXYNOS4210_CPUFREQ
+ def_bool CPU_EXYNOS4210
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS4210
+ SoC (S5PV310 or S5PC210).
+
+config ARM_EXYNOS4X12_CPUFREQ
+ def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS4X12
+ SoC (EXYNOS4212 or EXYNOS4412).
+
+config ARM_EXYNOS5250_CPUFREQ
+ def_bool SOC_EXYNOS5250
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS5250
+ SoC.
+
+config ARM_EXYNOS5440_CPUFREQ
+ def_bool SOC_EXYNOS5440
+ depends on HAVE_CLK && PM_OPP && OF
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS5440
+ SoC. The nature of exynos5440 clock controller is
+ different than previous exynos controllers so not using
+ the common exynos framework.
+
+config ARM_HIGHBANK_CPUFREQ
+ tristate "Calxeda Highbank-based"
+ depends on ARCH_HIGHBANK
+ select CPU_FREQ_TABLE
+ select GENERIC_CPUFREQ_CPU0
+ select PM_OPP
+ select REGULATOR
+
+ default m
+ help
+ This adds the CPUFreq driver for Calxeda Highbank SoC
+ based boards.
+
+ If in doubt, say N.
+
+config ARM_IMX6Q_CPUFREQ
+ tristate "Freescale i.MX6Q cpufreq support"
+ depends on SOC_IMX6Q
+ depends on REGULATOR_ANATOP
+ help
+ This adds cpufreq driver support for Freescale i.MX6Q SOC.
+
+ If in doubt, say N.
+
+config ARM_INTEGRATOR
+ tristate "CPUfreq driver for ARM Integrator CPUs"
+ depends on ARCH_INTEGRATOR
+ default y
+ help
+ This enables the CPUfreq driver for ARM Integrator CPUs.
+ If in doubt, say Y.
+
+config ARM_KIRKWOOD_CPUFREQ
+ def_bool ARCH_KIRKWOOD && OF
+ help
+ This adds the CPUFreq driver for Marvell Kirkwood
+ SoCs.
+
config ARM_OMAP2PLUS_CPUFREQ
bool "TI OMAP2+"
depends on ARCH_OMAP2PLUS
@@ -42,6 +129,7 @@ config ARM_S3C64XX_CPUFREQ
config ARM_S5PV210_CPUFREQ
bool "Samsung S5PV210 and S5PC110"
depends on CPU_S5PV210
+ select CPU_FREQ_TABLE
default y
help
This adds the CPUFreq driver for Samsung S5PV210 and
@@ -49,48 +137,11 @@ config ARM_S5PV210_CPUFREQ
If in doubt, say N.
-config ARM_EXYNOS_CPUFREQ
- bool "SAMSUNG EXYNOS SoCs"
- depends on ARCH_EXYNOS
- default y
- help
- This adds the CPUFreq driver common part for Samsung
- EXYNOS SoCs.
-
- If in doubt, say N.
+config ARM_SA1100_CPUFREQ
+ bool
-config ARM_EXYNOS4210_CPUFREQ
- def_bool CPU_EXYNOS4210
- help
- This adds the CPUFreq driver for Samsung EXYNOS4210
- SoC (S5PV310 or S5PC210).
-
-config ARM_EXYNOS4X12_CPUFREQ
- def_bool (SOC_EXYNOS4212 || SOC_EXYNOS4412)
- help
- This adds the CPUFreq driver for Samsung EXYNOS4X12
- SoC (EXYNOS4212 or EXYNOS4412).
-
-config ARM_EXYNOS5250_CPUFREQ
- def_bool SOC_EXYNOS5250
- help
- This adds the CPUFreq driver for Samsung EXYNOS5250
- SoC.
-
-config ARM_KIRKWOOD_CPUFREQ
- def_bool ARCH_KIRKWOOD && OF
- help
- This adds the CPUFreq driver for Marvell Kirkwood
- SoCs.
-
-config ARM_IMX6Q_CPUFREQ
- tristate "Freescale i.MX6Q cpufreq support"
- depends on SOC_IMX6Q
- depends on REGULATOR_ANATOP
- help
- This adds cpufreq driver support for Freescale i.MX6Q SOC.
-
- If in doubt, say N.
+config ARM_SA1110_CPUFREQ
+ bool
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
@@ -98,18 +149,3 @@ config ARM_SPEAR_CPUFREQ
default y
help
This adds the CPUFreq driver support for SPEAr SOCs.
-
-config ARM_HIGHBANK_CPUFREQ
- tristate "Calxeda Highbank-based"
- depends on ARCH_HIGHBANK
- select CPU_FREQ_TABLE
- select GENERIC_CPUFREQ_CPU0
- select PM_OPP
- select REGULATOR
-
- default m
- help
- This adds the CPUFreq driver for Calxeda Highbank SoC
- based boards.
-
- If in doubt, say N.
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index e76992f79683..9c926ca0d718 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -1,3 +1,21 @@
+config CPU_FREQ_CBE
+ tristate "CBE frequency scaling"
+ depends on CBE_RAS && PPC_CELL
+ default m
+ help
+ This adds the cpufreq driver for Cell BE processors.
+ For details, take a look at <file:Documentation/cpu-freq/>.
+ If you don't have such processor, say N
+
+config CPU_FREQ_CBE_PMI
+ bool "CBE frequency scaling using PMI interface"
+ depends on CPU_FREQ_CBE
+ default n
+ help
+ Select this, if you want to use the PMI interface to switch
+ frequencies. Using PMI, the processor will not only be able to run at
+ lower speed, but also at lower core voltage.
+
config CPU_FREQ_MAPLE
bool "Support for Maple 970FX Evaluation Board"
depends on PPC_MAPLE
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index d7dc0ed6adb0..2b8a8c374548 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -129,6 +129,23 @@ config X86_POWERNOW_K8
For details, take a look at <file:Documentation/cpu-freq/>.
+config X86_AMD_FREQ_SENSITIVITY
+ tristate "AMD frequency sensitivity feedback powersave bias"
+ depends on CPU_FREQ_GOV_ONDEMAND && X86_ACPI_CPUFREQ && CPU_SUP_AMD
+ help
+ This adds AMD-specific powersave bias function to the ondemand
+ governor, which allows it to make more power-conscious frequency
+ change decisions based on feedback from hardware (availble on AMD
+ Family 16h and above).
+
+ Hardware feedback tells software how "sensitive" to frequency changes
+ the CPUs' workloads are. CPU-bound workloads will be more sensitive
+ -- they will perform better as frequency increases. Memory/IO-bound
+ workloads will be less sensitive -- they will not necessarily perform
+ better as frequency increases.
+
+ If in doubt, say N.
+
config X86_GX_SUSPMOD
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
depends on X86_32 && PCI
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd1865d45..315b9231feb1 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -41,23 +41,54 @@ obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
+obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
##################################################################################
# ARM SoC drivers
+obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
+# big LITTLE per platform glues. Keep DT_BL_CPUFREQ as the last entry in all big
+# LITTLE drivers, so that it is probed last.
+obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
+
+obj-$(CONFIG_ARCH_DAVINCI_DA850) += davinci-cpufreq.o
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
-obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
-obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
-obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
+obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
+obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
+obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
+obj-$(CONFIG_PXA25x) += pxa2xx-cpufreq.o
+obj-$(CONFIG_PXA27x) += pxa2xx-cpufreq.o
+obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
+obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
+obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
+obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
+obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
+obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
-obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
-obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
+obj-$(CONFIG_ARCH_TEGRA) += tegra-cpufreq.o
##################################################################################
# PowerPC platform drivers
+obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o
+ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
+obj-$(CONFIG_CPU_FREQ_CBE_PMI) += ppc_cbe_cpufreq_pmi.o
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
+
+##################################################################################
+# Other platform drivers
+obj-$(CONFIG_AVR32_AT32AP_CPUFREQ) += at32ap-cpufreq.o
+obj-$(CONFIG_BLACKFIN) += blackfin-cpufreq.o
+obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o
+obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o
+obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o
+obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
+obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o
+obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o
+obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o
+obj-$(CONFIG_UNICORE32) += unicore2-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 937bc286591f..11b8b4b54ceb 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -423,7 +423,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
struct drv_cmd cmd;
unsigned int next_state = 0; /* Index into freq_table */
unsigned int next_perf_state = 0; /* Index into perf table */
- unsigned int i;
int result = 0;
pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
@@ -486,10 +485,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = perf->states[perf->state].core_frequency * 1000;
freqs.new = data->freq_table[next_state].frequency;
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
drv_write(&cmd);
@@ -502,10 +498,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
}
}
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
perf->state = next_perf_state;
out:
@@ -730,7 +723,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
cpumask_copy(policy->cpus, perf->shared_cpu_map);
}
- cpumask_copy(policy->related_cpus, perf->shared_cpu_map);
#ifdef CONFIG_SMP
dmi_check_system(sw_any_bug_dmi_table);
@@ -742,7 +734,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) {
cpumask_clear(policy->cpus);
cpumask_set_cpu(cpu, policy->cpus);
- cpumask_copy(policy->related_cpus, cpu_sibling_mask(cpu));
policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
pr_info_once(PFX "overriding BIOS provided _PSD data\n");
}
diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c
new file mode 100644
index 000000000000..f6b79ab0070b
--- /dev/null
+++ b/drivers/cpufreq/amd_freq_sensitivity.c
@@ -0,0 +1,148 @@
+/*
+ * amd_freq_sensitivity.c: AMD frequency sensitivity feedback powersave bias
+ * for the ondemand governor.
+ *
+ * Copyright (C) 2013 Advanced Micro Devices, Inc.
+ *
+ * Author: Jacob Shin <jacob.shin@amd.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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/percpu-defs.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+
+#include "cpufreq_governor.h"
+
+#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
+#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
+#define CLASS_CODE_SHIFT 56
+#define POWERSAVE_BIAS_MAX 1000
+#define POWERSAVE_BIAS_DEF 400
+
+struct cpu_data_t {
+ u64 actual;
+ u64 reference;
+ unsigned int freq_prev;
+};
+
+static DEFINE_PER_CPU(struct cpu_data_t, cpu_data);
+
+static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
+ unsigned int freq_next,
+ unsigned int relation)
+{
+ int sensitivity;
+ long d_actual, d_reference;
+ struct msr actual, reference;
+ struct cpu_data_t *data = &per_cpu(cpu_data, policy->cpu);
+ struct dbs_data *od_data = policy->governor_data;
+ struct od_dbs_tuners *od_tuners = od_data->tuners;
+ struct od_cpu_dbs_info_s *od_info =
+ od_data->cdata->get_cpu_dbs_info_s(policy->cpu);
+
+ if (!od_info->freq_table)
+ return freq_next;
+
+ rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_ACTUAL,
+ &actual.l, &actual.h);
+ rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_REFERENCE,
+ &reference.l, &reference.h);
+ actual.h &= 0x00ffffff;
+ reference.h &= 0x00ffffff;
+
+ /* counter wrapped around, so stay on current frequency */
+ if (actual.q < data->actual || reference.q < data->reference) {
+ freq_next = policy->cur;
+ goto out;
+ }
+
+ d_actual = actual.q - data->actual;
+ d_reference = reference.q - data->reference;
+
+ /* divide by 0, so stay on current frequency as well */
+ if (d_reference == 0) {
+ freq_next = policy->cur;
+ goto out;
+ }
+
+ sensitivity = POWERSAVE_BIAS_MAX -
+ (POWERSAVE_BIAS_MAX * (d_reference - d_actual) / d_reference);
+
+ clamp(sensitivity, 0, POWERSAVE_BIAS_MAX);
+
+ /* this workload is not CPU bound, so choose a lower freq */
+ if (sensitivity < od_tuners->powersave_bias) {
+ if (data->freq_prev == policy->cur)
+ freq_next = policy->cur;
+
+ if (freq_next > policy->cur)
+ freq_next = policy->cur;
+ else if (freq_next < policy->cur)
+ freq_next = policy->min;
+ else {
+ unsigned int index;
+
+ cpufreq_frequency_table_target(policy,
+ od_info->freq_table, policy->cur - 1,
+ CPUFREQ_RELATION_H, &index);
+ freq_next = od_info->freq_table[index].frequency;
+ }
+
+ data->freq_prev = freq_next;
+ } else
+ data->freq_prev = 0;
+
+out:
+ data->actual = actual.q;
+ data->reference = reference.q;
+ return freq_next;
+}
+
+static int __init amd_freq_sensitivity_init(void)
+{
+ u64 val;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ return -ENODEV;
+
+ if (!static_cpu_has(X86_FEATURE_PROC_FEEDBACK))
+ return -ENODEV;
+
+ if (rdmsrl_safe(MSR_AMD64_FREQ_SENSITIVITY_ACTUAL, &val))
+ return -ENODEV;
+
+ if (!(val >> CLASS_CODE_SHIFT))
+ return -ENODEV;
+
+ od_register_powersave_bias_handler(amd_powersave_bias_target,
+ POWERSAVE_BIAS_DEF);
+ return 0;
+}
+late_initcall(amd_freq_sensitivity_init);
+
+static void __exit amd_freq_sensitivity_exit(void)
+{
+ od_unregister_powersave_bias_handler();
+}
+module_exit(amd_freq_sensitivity_exit);
+
+static const struct x86_cpu_id amd_freq_sensitivity_ids[] = {
+ X86_FEATURE_MATCH(X86_FEATURE_PROC_FEEDBACK),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, amd_freq_sensitivity_ids);
+
+MODULE_AUTHOR("Jacob Shin <jacob.shin@amd.com>");
+MODULE_DESCRIPTION("AMD frequency sensitivity feedback powersave bias for "
+ "the ondemand governor.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
new file mode 100644
index 000000000000..dbdf677d2f36
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.c
@@ -0,0 +1,278 @@
+/*
+ * ARM big.LITTLE Platforms CPUFreq support
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/export.h>
+#include <linux/of_platform.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/topology.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+/* Currently we support only two clusters */
+#define MAX_CLUSTERS 2
+
+static struct cpufreq_arm_bL_ops *arm_bL_ops;
+static struct clk *clk[MAX_CLUSTERS];
+static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
+static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
+
+static int cpu_to_cluster(int cpu)
+{
+ return topology_physical_package_id(cpu);
+}
+
+static unsigned int bL_cpufreq_get(unsigned int cpu)
+{
+ u32 cur_cluster = cpu_to_cluster(cpu);
+
+ return clk_get_rate(clk[cur_cluster]) / 1000;
+}
+
+/* Validate policy frequency range */
+static int bL_cpufreq_verify_policy(struct cpufreq_policy *policy)
+{
+ u32 cur_cluster = cpu_to_cluster(policy->cpu);
+
+ return cpufreq_frequency_table_verify(policy, freq_table[cur_cluster]);
+}
+
+/* Set clock frequency */
+static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ u32 cpu = policy->cpu, freq_tab_idx, cur_cluster;
+ int ret = 0;
+
+ cur_cluster = cpu_to_cluster(policy->cpu);
+
+ freqs.old = bL_cpufreq_get(policy->cpu);
+
+ /* Determine valid target frequency using freq_table */
+ cpufreq_frequency_table_target(policy, freq_table[cur_cluster],
+ target_freq, relation, &freq_tab_idx);
+ freqs.new = freq_table[cur_cluster][freq_tab_idx].frequency;
+
+ pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
+ __func__, cpu, cur_cluster, freqs.old, target_freq,
+ freqs.new);
+
+ if (freqs.old == freqs.new)
+ return 0;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+ ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
+ if (ret) {
+ pr_err("clk_set_rate failed: %d\n", ret);
+ return ret;
+ }
+
+ policy->cur = freqs.new;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ return ret;
+}
+
+static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+ u32 cluster = cpu_to_cluster(cpu_dev->id);
+
+ if (!atomic_dec_return(&cluster_usage[cluster])) {
+ clk_put(clk[cluster]);
+ opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+ dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
+ }
+}
+
+static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
+{
+ u32 cluster = cpu_to_cluster(cpu_dev->id);
+ char name[14] = "cpu-cluster.";
+ int ret;
+
+ if (atomic_inc_return(&cluster_usage[cluster]) != 1)
+ return 0;
+
+ ret = arm_bL_ops->init_opp_table(cpu_dev);
+ if (ret) {
+ dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
+ __func__, cpu_dev->id, ret);
+ goto atomic_dec;
+ }
+
+ ret = opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
+ if (ret) {
+ dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
+ __func__, cpu_dev->id, ret);
+ goto atomic_dec;
+ }
+
+ name[12] = cluster + '0';
+ clk[cluster] = clk_get_sys(name, NULL);
+ if (!IS_ERR(clk[cluster])) {
+ dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
+ __func__, clk[cluster], freq_table[cluster],
+ cluster);
+ return 0;
+ }
+
+ dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
+ __func__, cpu_dev->id, cluster);
+ ret = PTR_ERR(clk[cluster]);
+ opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+
+atomic_dec:
+ atomic_dec(&cluster_usage[cluster]);
+ dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
+ cluster);
+ return ret;
+}
+
+/* Per-CPU initialization */
+static int bL_cpufreq_init(struct cpufreq_policy *policy)
+{
+ u32 cur_cluster = cpu_to_cluster(policy->cpu);
+ struct device *cpu_dev;
+ int ret;
+
+ cpu_dev = get_cpu_device(policy->cpu);
+ if (!cpu_dev) {
+ pr_err("%s: failed to get cpu%d device\n", __func__,
+ policy->cpu);
+ return -ENODEV;
+ }
+
+ ret = get_cluster_clk_and_freq_table(cpu_dev);
+ if (ret)
+ return ret;
+
+ ret = cpufreq_frequency_table_cpuinfo(policy, freq_table[cur_cluster]);
+ if (ret) {
+ dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
+ policy->cpu, cur_cluster);
+ put_cluster_clk_and_freq_table(cpu_dev);
+ return ret;
+ }
+
+ cpufreq_frequency_table_get_attr(freq_table[cur_cluster], policy->cpu);
+
+ if (arm_bL_ops->get_transition_latency)
+ policy->cpuinfo.transition_latency =
+ arm_bL_ops->get_transition_latency(cpu_dev);
+ else
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+ policy->cur = bL_cpufreq_get(policy->cpu);
+
+ cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
+
+ dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
+ return 0;
+}
+
+static int bL_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ struct device *cpu_dev;
+
+ cpu_dev = get_cpu_device(policy->cpu);
+ if (!cpu_dev) {
+ pr_err("%s: failed to get cpu%d device\n", __func__,
+ policy->cpu);
+ return -ENODEV;
+ }
+
+ put_cluster_clk_and_freq_table(cpu_dev);
+ dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
+
+ return 0;
+}
+
+/* Export freq_table to sysfs */
+static struct freq_attr *bL_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver bL_cpufreq_driver = {
+ .name = "arm-big-little",
+ .flags = CPUFREQ_STICKY,
+ .verify = bL_cpufreq_verify_policy,
+ .target = bL_cpufreq_set_target,
+ .get = bL_cpufreq_get,
+ .init = bL_cpufreq_init,
+ .exit = bL_cpufreq_exit,
+ .have_governor_per_policy = true,
+ .attr = bL_cpufreq_attr,
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
+{
+ int ret;
+
+ if (arm_bL_ops) {
+ pr_debug("%s: Already registered: %s, exiting\n", __func__,
+ arm_bL_ops->name);
+ return -EBUSY;
+ }
+
+ if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
+ pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
+ return -ENODEV;
+ }
+
+ arm_bL_ops = ops;
+
+ ret = cpufreq_register_driver(&bL_cpufreq_driver);
+ if (ret) {
+ pr_info("%s: Failed registering platform driver: %s, err: %d\n",
+ __func__, ops->name, ret);
+ arm_bL_ops = NULL;
+ } else {
+ pr_info("%s: Registered platform driver: %s\n", __func__,
+ ops->name);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_register);
+
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
+{
+ if (arm_bL_ops != ops) {
+ pr_err("%s: Registered with: %s, can't unregister, exiting\n",
+ __func__, arm_bL_ops->name);
+ return;
+ }
+
+ cpufreq_unregister_driver(&bL_cpufreq_driver);
+ pr_info("%s: Un-registered platform driver: %s\n", __func__,
+ arm_bL_ops->name);
+ arm_bL_ops = NULL;
+}
+EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
new file mode 100644
index 000000000000..70f18fc12d4a
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little.h
@@ -0,0 +1,40 @@
+/*
+ * ARM big.LITTLE platform's CPUFreq header file
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef CPUFREQ_ARM_BIG_LITTLE_H
+#define CPUFREQ_ARM_BIG_LITTLE_H
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/types.h>
+
+struct cpufreq_arm_bL_ops {
+ char name[CPUFREQ_NAME_LEN];
+ int (*get_transition_latency)(struct device *cpu_dev);
+
+ /*
+ * This must set opp table for cpu_dev in a similar way as done by
+ * of_init_opp_table().
+ */
+ int (*init_opp_table)(struct device *cpu_dev);
+};
+
+int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
+void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
+
+#endif /* CPUFREQ_ARM_BIG_LITTLE_H */
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
new file mode 100644
index 000000000000..44be3115375c
--- /dev/null
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -0,0 +1,107 @@
+/*
+ * Generic big.LITTLE CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver and gets
+ * Frequency information from Device Tree. Freq table in DT must be in KHz.
+ *
+ * Copyright (C) 2013 Linaro.
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include "arm_big_little.h"
+
+static int dt_init_opp_table(struct device *cpu_dev)
+{
+ struct device_node *np, *parent;
+ int count = 0, ret;
+
+ parent = of_find_node_by_path("/cpus");
+ if (!parent) {
+ pr_err("failed to find OF /cpus\n");
+ return -ENOENT;
+ }
+
+ for_each_child_of_node(parent, np) {
+ if (count++ != cpu_dev->id)
+ continue;
+ if (!of_get_property(np, "operating-points", NULL)) {
+ ret = -ENODATA;
+ } else {
+ cpu_dev->of_node = np;
+ ret = of_init_opp_table(cpu_dev);
+ }
+ of_node_put(np);
+ of_node_put(parent);
+
+ return ret;
+ }
+
+ return -ENODEV;
+}
+
+static int dt_get_transition_latency(struct device *cpu_dev)
+{
+ struct device_node *np, *parent;
+ u32 transition_latency = CPUFREQ_ETERNAL;
+ int count = 0;
+
+ parent = of_find_node_by_path("/cpus");
+ if (!parent) {
+ pr_err("failed to find OF /cpus\n");
+ return -ENOENT;
+ }
+
+ for_each_child_of_node(parent, np) {
+ if (count++ != cpu_dev->id)
+ continue;
+
+ of_property_read_u32(np, "clock-latency", &transition_latency);
+ of_node_put(np);
+ of_node_put(parent);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static struct cpufreq_arm_bL_ops dt_bL_ops = {
+ .name = "dt-bl",
+ .get_transition_latency = dt_get_transition_latency,
+ .init_opp_table = dt_init_opp_table,
+};
+
+static int generic_bL_init(void)
+{
+ return bL_cpufreq_register(&dt_bL_ops);
+}
+module_init(generic_bL_init);
+
+static void generic_bL_exit(void)
+{
+ return bL_cpufreq_unregister(&dt_bL_ops);
+}
+module_exit(generic_bL_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
+MODULE_LICENSE("GPL");
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c
index 18b765629a0c..654488723cb5 100644
--- a/arch/avr32/mach-at32ap/cpufreq.c
+++ b/drivers/cpufreq/at32ap-cpufreq.c
@@ -61,7 +61,6 @@ static int at32_set_target(struct cpufreq_policy *policy,
freqs.old = at32_get_speed(0);
freqs.new = (freq + 500) / 1000;
- freqs.cpu = 0;
freqs.flags = 0;
if (!ref_freq) {
@@ -69,7 +68,7 @@ static int at32_set_target(struct cpufreq_policy *policy,
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (freqs.old < freqs.new)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new);
@@ -77,7 +76,7 @@ static int at32_set_target(struct cpufreq_policy *policy,
if (freqs.new < freqs.old)
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: set frequency %lu Hz\n", freq);
diff --git a/arch/blackfin/mach-common/cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index d88bd31319e6..995511e80bef 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -127,13 +127,13 @@ unsigned long cpu_set_cclk(int cpu, unsigned long new)
}
#endif
-static int bfin_target(struct cpufreq_policy *poli,
+static int bfin_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
#ifndef CONFIG_BF60x
unsigned int plldiv;
#endif
- unsigned int index, cpu;
+ unsigned int index;
unsigned long cclk_hz;
struct cpufreq_freqs freqs;
static unsigned long lpj_ref;
@@ -144,59 +144,48 @@ static int bfin_target(struct cpufreq_policy *poli,
cycles_t cycles;
#endif
- for_each_online_cpu(cpu) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (cpufreq_frequency_table_target(policy, bfin_freq_table, target_freq,
+ relation, &index))
+ return -EINVAL;
- if (!policy)
- continue;
+ cclk_hz = bfin_freq_table[index].frequency;
- if (cpufreq_frequency_table_target(policy, bfin_freq_table,
- target_freq, relation, &index))
- return -EINVAL;
+ freqs.old = bfin_getfreq_khz(0);
+ freqs.new = cclk_hz;
- cclk_hz = bfin_freq_table[index].frequency;
+ pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
+ cclk_hz, target_freq, freqs.old);
- freqs.old = bfin_getfreq_khz(0);
- freqs.new = cclk_hz;
- freqs.cpu = cpu;
-
- pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
- cclk_hz, target_freq, freqs.old);
-
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- if (cpu == CPUFREQ_CPU) {
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifndef CONFIG_BF60x
- plldiv = (bfin_read_PLL_DIV() & SSEL) |
- dpm_state_table[index].csel;
- bfin_write_PLL_DIV(plldiv);
+ plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
+ bfin_write_PLL_DIV(plldiv);
#else
- ret = cpu_set_cclk(cpu, freqs.new * 1000);
- if (ret != 0) {
- WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
- break;
- }
+ ret = cpu_set_cclk(policy->cpu, freqs.new * 1000);
+ if (ret != 0) {
+ WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
+ return ret;
+ }
#endif
- on_each_cpu(bfin_adjust_core_timer, &index, 1);
+ on_each_cpu(bfin_adjust_core_timer, &index, 1);
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
- cycles = get_cycles();
- SSYNC();
- cycles += 10; /* ~10 cycles we lose after get_cycles() */
- __bfin_cycles_off +=
- (cycles << __bfin_cycles_mod) - (cycles << index);
- __bfin_cycles_mod = index;
+ cycles = get_cycles();
+ SSYNC();
+ cycles += 10; /* ~10 cycles we lose after get_cycles() */
+ __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index);
+ __bfin_cycles_mod = index;
#endif
- if (!lpj_ref_freq) {
- lpj_ref = loops_per_jiffy;
- lpj_ref_freq = freqs.old;
- }
- if (freqs.new != freqs.old) {
- loops_per_jiffy = cpufreq_scale(lpj_ref,
- lpj_ref_freq, freqs.new);
- }
- }
- /* TODO: just test case for cycles clock source, remove later */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ if (!lpj_ref_freq) {
+ lpj_ref = loops_per_jiffy;
+ lpj_ref_freq = freqs.old;
}
+ if (freqs.new != freqs.old) {
+ loops_per_jiffy = cpufreq_scale(lpj_ref,
+ lpj_ref_freq, freqs.new);
+ }
+
+ /* TODO: just test case for cycles clock source, remove later */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: done\n");
return ret;
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 4e5b7fb8927c..3ab8294eab04 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -44,8 +44,9 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
{
struct cpufreq_freqs freqs;
struct opp *opp;
- unsigned long freq_Hz, volt = 0, volt_old = 0, tol = 0;
- unsigned int index, cpu;
+ unsigned long volt = 0, volt_old = 0, tol = 0;
+ long freq_Hz;
+ unsigned int index;
int ret;
ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
@@ -65,10 +66,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return 0;
- for_each_online_cpu(cpu) {
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (cpu_reg) {
rcu_read_lock();
@@ -76,7 +74,9 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
if (IS_ERR(opp)) {
rcu_read_unlock();
pr_err("failed to find OPP for %ld\n", freq_Hz);
- return PTR_ERR(opp);
+ freqs.new = freqs.old;
+ ret = PTR_ERR(opp);
+ goto post_notify;
}
volt = opp_get_voltage(opp);
rcu_read_unlock();
@@ -94,7 +94,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
if (ret) {
pr_err("failed to scale voltage up: %d\n", ret);
freqs.new = freqs.old;
- return ret;
+ goto post_notify;
}
}
@@ -103,7 +103,8 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
pr_err("failed to set clock rate: %d\n", ret);
if (cpu_reg)
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/* scaling down? scale voltage after frequency */
@@ -113,25 +114,19 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
pr_err("failed to scale voltage down: %d\n", ret);
clk_set_rate(cpu_clk, freqs.old * 1000);
freqs.new = freqs.old;
- return ret;
}
}
- for_each_online_cpu(cpu) {
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+post_notify:
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- return 0;
+ return ret;
}
static int cpu0_cpufreq_init(struct cpufreq_policy *policy)
{
int ret;
- if (policy->cpu != 0)
- return -EINVAL;
-
ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (ret) {
pr_err("invalid frequency table: %d\n", ret);
@@ -178,10 +173,16 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
static int cpu0_cpufreq_probe(struct platform_device *pdev)
{
- struct device_node *np;
+ struct device_node *np, *parent;
int ret;
- for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+ parent = of_find_node_by_path("/cpus");
+ if (!parent) {
+ pr_err("failed to find OF /cpus\n");
+ return -ENOENT;
+ }
+
+ for_each_child_of_node(parent, np) {
if (of_get_property(np, "operating-points", NULL))
break;
}
@@ -256,6 +257,7 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
}
of_node_put(np);
+ of_node_put(parent);
return 0;
out_free_table:
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index 13d311ee08b3..af1542d41440 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -263,7 +263,6 @@ static int nforce2_target(struct cpufreq_policy *policy,
freqs.old = nforce2_get(policy->cpu);
freqs.new = target_fsb * fid * 100;
- freqs.cpu = 0; /* Only one CPU on nForce2 platforms */
if (freqs.old == freqs.new)
return 0;
@@ -271,7 +270,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
freqs.old, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Disable IRQs */
/* local_irq_save(flags); */
@@ -286,7 +285,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
/* Enable IRQs */
/* local_irq_restore(flags); */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
@@ -360,12 +359,10 @@ static int nforce2_cpu_init(struct cpufreq_policy *policy)
min_fsb = NFORCE2_MIN_FSB;
/* cpuinfo and default policy values */
- policy->cpuinfo.min_freq = min_fsb * fid * 100;
- policy->cpuinfo.max_freq = max_fsb * fid * 100;
+ policy->min = policy->cpuinfo.min_freq = min_fsb * fid * 100;
+ policy->max = policy->cpuinfo.max_freq = max_fsb * fid * 100;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = nforce2_get(policy->cpu);
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
return 0;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index b02824d092e7..1b8a48eaf90f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -45,7 +45,7 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
-static DEFINE_SPINLOCK(cpufreq_driver_lock);
+static DEFINE_RWLOCK(cpufreq_driver_lock);
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -128,6 +128,11 @@ void disable_cpufreq(void)
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);
+bool have_governor_per_policy(void)
+{
+ return cpufreq_driver->have_governor_per_policy;
+}
+
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
{
struct cpufreq_policy *data;
@@ -137,7 +142,7 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
goto err_out;
/* get the cpufreq driver */
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ read_lock_irqsave(&cpufreq_driver_lock, flags);
if (!cpufreq_driver)
goto err_out_unlock;
@@ -155,13 +160,13 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
if (!sysfs && !kobject_get(&data->kobj))
goto err_out_put_module;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
return data;
err_out_put_module:
module_put(cpufreq_driver->owner);
err_out_unlock:
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
err_out:
return NULL;
}
@@ -244,19 +249,9 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
#endif
-/**
- * cpufreq_notify_transition - call notifier chain and adjust_jiffies
- * on frequency transition.
- *
- * This function calls the transition notifiers and the "adjust_jiffies"
- * function. It is called twice on all CPU frequency changes that have
- * external effects.
- */
-void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
+void __cpufreq_notify_transition(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs, unsigned int state)
{
- struct cpufreq_policy *policy;
- unsigned long flags;
-
BUG_ON(irqs_disabled());
if (cpufreq_disabled())
@@ -266,10 +261,6 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
pr_debug("notification %u of frequency transition to %u kHz\n",
state, freqs->new);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
- policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
switch (state) {
case CPUFREQ_PRECHANGE:
@@ -303,6 +294,20 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
break;
}
}
+/**
+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies
+ * on frequency transition.
+ *
+ * This function calls the transition notifiers and the "adjust_jiffies"
+ * function. It is called twice on all CPU frequency changes that have
+ * external effects.
+ */
+void cpufreq_notify_transition(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs, unsigned int state)
+{
+ for_each_cpu(freqs->cpu, policy->cpus)
+ __cpufreq_notify_transition(policy, freqs, state);
+}
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
@@ -765,12 +770,12 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
goto err_out_kobj_put;
}
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus) {
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(cpufreq_policy_cpu, j) = policy->cpu;
}
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = cpufreq_add_dev_symlink(cpu, policy);
if (ret)
@@ -803,27 +808,30 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling,
struct device *dev)
{
struct cpufreq_policy *policy;
- int ret = 0;
+ int ret = 0, has_target = !!cpufreq_driver->target;
unsigned long flags;
policy = cpufreq_cpu_get(sibling);
WARN_ON(!policy);
- __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
+ if (has_target)
+ __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
lock_policy_rwsem_write(sibling);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
cpumask_set_cpu(cpu, policy->cpus);
per_cpu(cpufreq_policy_cpu, cpu) = policy->cpu;
per_cpu(cpufreq_cpu_data, cpu) = policy;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
unlock_policy_rwsem_write(sibling);
- __cpufreq_governor(policy, CPUFREQ_GOV_START);
- __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ if (has_target) {
+ __cpufreq_governor(policy, CPUFREQ_GOV_START);
+ __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
+ }
ret = sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
if (ret) {
@@ -871,15 +879,15 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ read_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_online_cpu(sibling) {
struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
return cpufreq_add_policy_cpu(cpu, sibling, dev);
}
}
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
#endif
@@ -952,10 +960,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return 0;
err_out_unregister:
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_put(&policy->kobj);
wait_for_completion(&policy->kobj_unregister);
@@ -1008,12 +1016,12 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
data = per_cpu(cpufreq_cpu_data, cpu);
per_cpu(cpufreq_cpu_data, cpu) = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!data) {
pr_debug("%s: No cpu_data found\n", __func__);
@@ -1031,7 +1039,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
WARN_ON(lock_policy_rwsem_write(cpu));
cpus = cpumask_weight(data->cpus);
- cpumask_clear_cpu(cpu, data->cpus);
+
+ if (cpus > 1)
+ cpumask_clear_cpu(cpu, data->cpus);
unlock_policy_rwsem_write(cpu);
if (cpu != data->cpu) {
@@ -1047,9 +1057,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
WARN_ON(lock_policy_rwsem_write(cpu));
cpumask_set_cpu(cpu, data->cpus);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
per_cpu(cpufreq_cpu_data, cpu) = data;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
unlock_policy_rwsem_write(cpu);
@@ -1070,6 +1080,9 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
/* If cpu is last user of policy, free policy */
if (cpus == 1) {
+ if (cpufreq_driver->target)
+ __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
lock_policy_rwsem_read(cpu);
kobj = &data->kobj;
cmp = &data->kobj_unregister;
@@ -1134,16 +1147,23 @@ static void handle_update(struct work_struct *work)
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
unsigned int new_freq)
{
+ struct cpufreq_policy *policy;
struct cpufreq_freqs freqs;
+ unsigned long flags;
+
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
- freqs.cpu = cpu;
freqs.old = old_freq;
freqs.new = new_freq;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ read_lock_irqsave(&cpufreq_driver_lock, flags);
+ policy = per_cpu(cpufreq_cpu_data, cpu);
+ read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
}
@@ -1544,10 +1564,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy->cpu, event);
ret = policy->governor->governor(policy, event);
- if (event == CPUFREQ_GOV_START)
- policy->governor->initialized++;
- else if (event == CPUFREQ_GOV_STOP)
- policy->governor->initialized--;
+ if (!ret) {
+ if (event == CPUFREQ_GOV_POLICY_INIT)
+ policy->governor->initialized++;
+ else if (event == CPUFREQ_GOV_POLICY_EXIT)
+ policy->governor->initialized--;
+ }
/* we keep one module reference alive for
each CPU governed by this CPU */
@@ -1651,7 +1673,7 @@ EXPORT_SYMBOL(cpufreq_get_policy);
static int __cpufreq_set_policy(struct cpufreq_policy *data,
struct cpufreq_policy *policy)
{
- int ret = 0;
+ int ret = 0, failed = 1;
pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
policy->min, policy->max);
@@ -1705,18 +1727,31 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
pr_debug("governor switch\n");
/* end old governor */
- if (data->governor)
+ if (data->governor) {
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ __cpufreq_governor(data,
+ CPUFREQ_GOV_POLICY_EXIT);
+ }
/* start new governor */
data->governor = policy->governor;
- if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
+ if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
+ if (!__cpufreq_governor(data, CPUFREQ_GOV_START))
+ failed = 0;
+ else
+ __cpufreq_governor(data,
+ CPUFREQ_GOV_POLICY_EXIT);
+ }
+
+ if (failed) {
/* new governor failed, so re-start old one */
pr_debug("starting governor %s failed\n",
data->governor->name);
if (old_gov) {
data->governor = old_gov;
__cpufreq_governor(data,
+ CPUFREQ_GOV_POLICY_INIT);
+ __cpufreq_governor(data,
CPUFREQ_GOV_START);
}
ret = -EINVAL;
@@ -1848,13 +1883,13 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) {
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EBUSY;
}
cpufreq_driver = driver_data;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = subsys_interface_register(&cpufreq_interface);
if (ret)
@@ -1886,9 +1921,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
err_null_driver:
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
@@ -1914,9 +1949,9 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
subsys_interface_unregister(&cpufreq_interface);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
- spin_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
- spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 4fd0006b1291..0ceb2eff5a7e 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -20,6 +20,7 @@
#include <linux/mutex.h>
#include <linux/notifier.h>
#include <linux/percpu-defs.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@@ -28,25 +29,29 @@
/* Conservative governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
+#define DEF_FREQUENCY_STEP (5)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-static struct dbs_data cs_dbs_data;
static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info);
-static struct cs_dbs_tuners cs_tuners = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .ignore_nice = 0,
- .freq_step = 5,
-};
+static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
+ struct cpufreq_policy *policy)
+{
+ unsigned int freq_target = (cs_tuners->freq_step * policy->max) / 100;
+
+ /* max freq cannot be less than 100. But who knows... */
+ if (unlikely(freq_target == 0))
+ freq_target = DEF_FREQUENCY_STEP;
+
+ return freq_target;
+}
/*
* Every sampling_rate, we check, if current idle time is less than 20%
- * (default), then we try to increase frequency Every sampling_rate *
- * sampling_down_factor, we check, if current idle time is more than 80%, then
- * we try to decrease frequency
+ * (default), then we try to increase frequency. Every sampling_rate *
+ * sampling_down_factor, we check, if current idle time is more than 80%
+ * (default), then we try to decrease frequency
*
* Any frequency increase takes it to the maximum frequency. Frequency reduction
* happens at minimum steps of 5% (default) of maximum frequency
@@ -55,30 +60,25 @@ static void cs_check_cpu(int cpu, unsigned int load)
{
struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu);
struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
- unsigned int freq_target;
+ struct dbs_data *dbs_data = policy->governor_data;
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
/*
* break out if we 'cannot' reduce the speed as the user might
* want freq_step to be zero
*/
- if (cs_tuners.freq_step == 0)
+ if (cs_tuners->freq_step == 0)
return;
/* Check for frequency increase */
- if (load > cs_tuners.up_threshold) {
+ if (load > cs_tuners->up_threshold) {
dbs_info->down_skip = 0;
/* if we are already at full speed then break out early */
if (dbs_info->requested_freq == policy->max)
return;
- freq_target = (cs_tuners.freq_step * policy->max) / 100;
-
- /* max freq cannot be less than 100. But who knows.... */
- if (unlikely(freq_target == 0))
- freq_target = 5;
-
- dbs_info->requested_freq += freq_target;
+ dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
if (dbs_info->requested_freq > policy->max)
dbs_info->requested_freq = policy->max;
@@ -87,45 +87,48 @@ static void cs_check_cpu(int cpu, unsigned int load)
return;
}
- /*
- * The optimal frequency is the frequency that is the lowest that can
- * support the current CPU usage without triggering the up policy. To be
- * safe, we focus 10 points under the threshold.
- */
- if (load < (cs_tuners.down_threshold - 10)) {
- freq_target = (cs_tuners.freq_step * policy->max) / 100;
-
- dbs_info->requested_freq -= freq_target;
- if (dbs_info->requested_freq < policy->min)
- dbs_info->requested_freq = policy->min;
+ /* if sampling_down_factor is active break out early */
+ if (++dbs_info->down_skip < cs_tuners->sampling_down_factor)
+ return;
+ dbs_info->down_skip = 0;
+ /* Check for frequency decrease */
+ if (load < cs_tuners->down_threshold) {
/*
* if we cannot reduce the frequency anymore, break out early
*/
if (policy->cur == policy->min)
return;
+ dbs_info->requested_freq -= get_freq_target(cs_tuners, policy);
+ if (dbs_info->requested_freq < policy->min)
+ dbs_info->requested_freq = policy->min;
+
__cpufreq_driver_target(policy, dbs_info->requested_freq,
- CPUFREQ_RELATION_H);
+ CPUFREQ_RELATION_L);
return;
}
}
static void cs_dbs_timer(struct work_struct *work)
{
- struct delayed_work *dw = to_delayed_work(work);
struct cs_cpu_dbs_info_s *dbs_info = container_of(work,
struct cs_cpu_dbs_info_s, cdbs.work.work);
unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info,
cpu);
- int delay = delay_for_sampling_rate(cs_tuners.sampling_rate);
+ struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
+ int delay = delay_for_sampling_rate(cs_tuners->sampling_rate);
+ bool modify_all = true;
mutex_lock(&core_dbs_info->cdbs.timer_mutex);
- if (need_load_eval(&core_dbs_info->cdbs, cs_tuners.sampling_rate))
- dbs_check_cpu(&cs_dbs_data, cpu);
+ if (!need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate))
+ modify_all = false;
+ else
+ dbs_check_cpu(dbs_data, cpu);
- schedule_delayed_work_on(smp_processor_id(), dw, delay);
+ gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
}
@@ -154,16 +157,12 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
}
/************************** sysfs interface ************************/
-static ssize_t show_sampling_rate_min(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", cs_dbs_data.min_sampling_rate);
-}
+static struct common_dbs_data cs_dbs_cdata;
-static ssize_t store_sampling_down_factor(struct kobject *a,
- struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
+ const char *buf, size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -171,13 +170,14 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- cs_tuners.sampling_down_factor = input;
+ cs_tuners->sampling_down_factor = input;
return count;
}
-static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -185,43 +185,46 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
if (ret != 1)
return -EINVAL;
- cs_tuners.sampling_rate = max(input, cs_dbs_data.min_sampling_rate);
+ cs_tuners->sampling_rate = max(input, dbs_data->min_sampling_rate);
return count;
}
-static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
- if (ret != 1 || input > 100 || input <= cs_tuners.down_threshold)
+ if (ret != 1 || input > 100 || input <= cs_tuners->down_threshold)
return -EINVAL;
- cs_tuners.up_threshold = input;
+ cs_tuners->up_threshold = input;
return count;
}
-static ssize_t store_down_threshold(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
/* cannot be lower than 11 otherwise freq will not fall */
if (ret != 1 || input < 11 || input > 100 ||
- input >= cs_tuners.up_threshold)
+ input >= cs_tuners->up_threshold)
return -EINVAL;
- cs_tuners.down_threshold = input;
+ cs_tuners->down_threshold = input;
return count;
}
-static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input, j;
int ret;
@@ -232,27 +235,28 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
if (input > 1)
input = 1;
- if (input == cs_tuners.ignore_nice) /* nothing to do */
+ if (input == cs_tuners->ignore_nice) /* nothing to do */
return count;
- cs_tuners.ignore_nice = input;
+ cs_tuners->ignore_nice = input;
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct cs_cpu_dbs_info_s *dbs_info;
dbs_info = &per_cpu(cs_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
- &dbs_info->cdbs.prev_cpu_wall);
- if (cs_tuners.ignore_nice)
+ &dbs_info->cdbs.prev_cpu_wall, 0);
+ if (cs_tuners->ignore_nice)
dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
}
return count;
}
-static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -267,43 +271,88 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
* no need to test here if freq_step is zero as the user might actually
* want this, they would be crazy though :)
*/
- cs_tuners.freq_step = input;
+ cs_tuners->freq_step = input;
return count;
}
-show_one(cs, sampling_rate, sampling_rate);
-show_one(cs, sampling_down_factor, sampling_down_factor);
-show_one(cs, up_threshold, up_threshold);
-show_one(cs, down_threshold, down_threshold);
-show_one(cs, ignore_nice_load, ignore_nice);
-show_one(cs, freq_step, freq_step);
-
-define_one_global_rw(sampling_rate);
-define_one_global_rw(sampling_down_factor);
-define_one_global_rw(up_threshold);
-define_one_global_rw(down_threshold);
-define_one_global_rw(ignore_nice_load);
-define_one_global_rw(freq_step);
-define_one_global_ro(sampling_rate_min);
-
-static struct attribute *dbs_attributes[] = {
- &sampling_rate_min.attr,
- &sampling_rate.attr,
- &sampling_down_factor.attr,
- &up_threshold.attr,
- &down_threshold.attr,
- &ignore_nice_load.attr,
- &freq_step.attr,
+show_store_one(cs, sampling_rate);
+show_store_one(cs, sampling_down_factor);
+show_store_one(cs, up_threshold);
+show_store_one(cs, down_threshold);
+show_store_one(cs, ignore_nice);
+show_store_one(cs, freq_step);
+declare_show_sampling_rate_min(cs);
+
+gov_sys_pol_attr_rw(sampling_rate);
+gov_sys_pol_attr_rw(sampling_down_factor);
+gov_sys_pol_attr_rw(up_threshold);
+gov_sys_pol_attr_rw(down_threshold);
+gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(freq_step);
+gov_sys_pol_attr_ro(sampling_rate_min);
+
+static struct attribute *dbs_attributes_gov_sys[] = {
+ &sampling_rate_min_gov_sys.attr,
+ &sampling_rate_gov_sys.attr,
+ &sampling_down_factor_gov_sys.attr,
+ &up_threshold_gov_sys.attr,
+ &down_threshold_gov_sys.attr,
+ &ignore_nice_gov_sys.attr,
+ &freq_step_gov_sys.attr,
NULL
};
-static struct attribute_group cs_attr_group = {
- .attrs = dbs_attributes,
+static struct attribute_group cs_attr_group_gov_sys = {
+ .attrs = dbs_attributes_gov_sys,
+ .name = "conservative",
+};
+
+static struct attribute *dbs_attributes_gov_pol[] = {
+ &sampling_rate_min_gov_pol.attr,
+ &sampling_rate_gov_pol.attr,
+ &sampling_down_factor_gov_pol.attr,
+ &up_threshold_gov_pol.attr,
+ &down_threshold_gov_pol.attr,
+ &ignore_nice_gov_pol.attr,
+ &freq_step_gov_pol.attr,
+ NULL
+};
+
+static struct attribute_group cs_attr_group_gov_pol = {
+ .attrs = dbs_attributes_gov_pol,
.name = "conservative",
};
/************************** sysfs end ************************/
+static int cs_init(struct dbs_data *dbs_data)
+{
+ struct cs_dbs_tuners *tuners;
+
+ tuners = kzalloc(sizeof(struct cs_dbs_tuners), GFP_KERNEL);
+ if (!tuners) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
+ tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
+ tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
+ tuners->ignore_nice = 0;
+ tuners->freq_step = DEF_FREQUENCY_STEP;
+
+ dbs_data->tuners = tuners;
+ dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
+ jiffies_to_usecs(10);
+ mutex_init(&dbs_data->mutex);
+ return 0;
+}
+
+static void cs_exit(struct dbs_data *dbs_data)
+{
+ kfree(dbs_data->tuners);
+}
+
define_get_cpu_dbs_routines(cs_cpu_dbs_info);
static struct notifier_block cs_cpufreq_notifier_block = {
@@ -314,21 +363,23 @@ static struct cs_ops cs_ops = {
.notifier_block = &cs_cpufreq_notifier_block,
};
-static struct dbs_data cs_dbs_data = {
+static struct common_dbs_data cs_dbs_cdata = {
.governor = GOV_CONSERVATIVE,
- .attr_group = &cs_attr_group,
- .tuners = &cs_tuners,
+ .attr_group_gov_sys = &cs_attr_group_gov_sys,
+ .attr_group_gov_pol = &cs_attr_group_gov_pol,
.get_cpu_cdbs = get_cpu_cdbs,
.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
.gov_dbs_timer = cs_dbs_timer,
.gov_check_cpu = cs_check_cpu,
.gov_ops = &cs_ops,
+ .init = cs_init,
+ .exit = cs_exit,
};
static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int event)
{
- return cpufreq_governor_dbs(&cs_dbs_data, policy, event);
+ return cpufreq_governor_dbs(policy, &cs_dbs_cdata, event);
}
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
@@ -343,7 +394,6 @@ struct cpufreq_governor cpufreq_gov_conservative = {
static int __init cpufreq_gov_dbs_init(void)
{
- mutex_init(&cs_dbs_data.mutex);
return cpufreq_register_governor(&cpufreq_gov_conservative);
}
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 5a76086ff09b..443442df113b 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -22,12 +22,29 @@
#include <linux/export.h>
#include <linux/kernel_stat.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
#include <linux/tick.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include "cpufreq_governor.h"
+static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
+{
+ if (have_governor_per_policy())
+ return &policy->kobj;
+ else
+ return cpufreq_global_kobject;
+}
+
+static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
+{
+ if (have_governor_per_policy())
+ return dbs_data->cdata->attr_group_gov_pol;
+ else
+ return dbs_data->cdata->attr_group_gov_sys;
+}
+
static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
{
u64 idle_time;
@@ -50,13 +67,13 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
return cputime_to_usecs(idle_time);
}
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall)
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
{
- u64 idle_time = get_cpu_idle_time_us(cpu, NULL);
+ u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall);
- else
+ else if (!io_busy)
idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time;
@@ -65,7 +82,7 @@ EXPORT_SYMBOL_GPL(get_cpu_idle_time);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
{
- struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
+ struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
struct od_dbs_tuners *od_tuners = dbs_data->tuners;
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
struct cpufreq_policy *policy;
@@ -73,7 +90,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
unsigned int ignore_nice;
unsigned int j;
- if (dbs_data->governor == GOV_ONDEMAND)
+ if (dbs_data->cdata->governor == GOV_ONDEMAND)
ignore_nice = od_tuners->ignore_nice;
else
ignore_nice = cs_tuners->ignore_nice;
@@ -83,13 +100,22 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
/* Get Absolute Load (in terms of freq for ondemand gov) */
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs;
- u64 cur_wall_time, cur_idle_time, cur_iowait_time;
- unsigned int idle_time, wall_time, iowait_time;
+ u64 cur_wall_time, cur_idle_time;
+ unsigned int idle_time, wall_time;
unsigned int load;
+ int io_busy = 0;
- j_cdbs = dbs_data->get_cpu_cdbs(j);
+ j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);
- cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+ /*
+ * For the purpose of ondemand, waiting for disk IO is
+ * an indication that you're performance critical, and
+ * not that the system is actually idle. So do not add
+ * the iowait time to the cpu idle time.
+ */
+ if (dbs_data->cdata->governor == GOV_ONDEMAND)
+ io_busy = od_tuners->io_is_busy;
+ cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy);
wall_time = (unsigned int)
(cur_wall_time - j_cdbs->prev_cpu_wall);
@@ -117,35 +143,12 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
idle_time += jiffies_to_usecs(cur_nice_jiffies);
}
- if (dbs_data->governor == GOV_ONDEMAND) {
- struct od_cpu_dbs_info_s *od_j_dbs_info =
- dbs_data->get_cpu_dbs_info_s(cpu);
-
- cur_iowait_time = get_cpu_iowait_time_us(j,
- &cur_wall_time);
- if (cur_iowait_time == -1ULL)
- cur_iowait_time = 0;
-
- iowait_time = (unsigned int) (cur_iowait_time -
- od_j_dbs_info->prev_cpu_iowait);
- od_j_dbs_info->prev_cpu_iowait = cur_iowait_time;
-
- /*
- * For the purpose of ondemand, waiting for disk IO is
- * an indication that you're performance critical, and
- * not that the system is actually idle. So subtract the
- * iowait time from the cpu idle time.
- */
- if (od_tuners->io_is_busy && idle_time >= iowait_time)
- idle_time -= iowait_time;
- }
-
if (unlikely(!wall_time || wall_time < idle_time))
continue;
load = 100 * (wall_time - idle_time) / wall_time;
- if (dbs_data->governor == GOV_ONDEMAND) {
+ if (dbs_data->cdata->governor == GOV_ONDEMAND) {
int freq_avg = __cpufreq_driver_getavg(policy, j);
if (freq_avg <= 0)
freq_avg = policy->cur;
@@ -157,24 +160,42 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
max_load = load;
}
- dbs_data->gov_check_cpu(cpu, max_load);
+ dbs_data->cdata->gov_check_cpu(cpu, max_load);
}
EXPORT_SYMBOL_GPL(dbs_check_cpu);
-static inline void dbs_timer_init(struct dbs_data *dbs_data, int cpu,
- unsigned int sampling_rate)
+static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data,
+ unsigned int delay)
{
- int delay = delay_for_sampling_rate(sampling_rate);
- struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
+ struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
- schedule_delayed_work_on(cpu, &cdbs->work, delay);
+ mod_delayed_work_on(cpu, system_wq, &cdbs->work, delay);
}
-static inline void dbs_timer_exit(struct dbs_data *dbs_data, int cpu)
+void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
+ unsigned int delay, bool all_cpus)
{
- struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu);
+ int i;
- cancel_delayed_work_sync(&cdbs->work);
+ if (!all_cpus) {
+ __gov_queue_work(smp_processor_id(), dbs_data, delay);
+ } else {
+ for_each_cpu(i, policy->cpus)
+ __gov_queue_work(i, dbs_data, delay);
+ }
+}
+EXPORT_SYMBOL_GPL(gov_queue_work);
+
+static inline void gov_cancel_work(struct dbs_data *dbs_data,
+ struct cpufreq_policy *policy)
+{
+ struct cpu_dbs_common_info *cdbs;
+ int i;
+
+ for_each_cpu(i, policy->cpus) {
+ cdbs = dbs_data->cdata->get_cpu_cdbs(i);
+ cancel_delayed_work_sync(&cdbs->work);
+ }
}
/* Will return if we need to evaluate cpu load again or not */
@@ -196,31 +217,130 @@ bool need_load_eval(struct cpu_dbs_common_info *cdbs,
}
EXPORT_SYMBOL_GPL(need_load_eval);
-int cpufreq_governor_dbs(struct dbs_data *dbs_data,
- struct cpufreq_policy *policy, unsigned int event)
+static void set_sampling_rate(struct dbs_data *dbs_data,
+ unsigned int sampling_rate)
{
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
+ cs_tuners->sampling_rate = sampling_rate;
+ } else {
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+ od_tuners->sampling_rate = sampling_rate;
+ }
+}
+
+int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ struct common_dbs_data *cdata, unsigned int event)
+{
+ struct dbs_data *dbs_data;
struct od_cpu_dbs_info_s *od_dbs_info = NULL;
struct cs_cpu_dbs_info_s *cs_dbs_info = NULL;
- struct cs_ops *cs_ops = NULL;
struct od_ops *od_ops = NULL;
- struct od_dbs_tuners *od_tuners = dbs_data->tuners;
- struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
+ struct od_dbs_tuners *od_tuners = NULL;
+ struct cs_dbs_tuners *cs_tuners = NULL;
struct cpu_dbs_common_info *cpu_cdbs;
- unsigned int *sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
+ unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
+ int io_busy = 0;
int rc;
- cpu_cdbs = dbs_data->get_cpu_cdbs(cpu);
+ if (have_governor_per_policy())
+ dbs_data = policy->governor_data;
+ else
+ dbs_data = cdata->gdbs_data;
+
+ WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT));
+
+ switch (event) {
+ case CPUFREQ_GOV_POLICY_INIT:
+ if (have_governor_per_policy()) {
+ WARN_ON(dbs_data);
+ } else if (dbs_data) {
+ policy->governor_data = dbs_data;
+ return 0;
+ }
+
+ dbs_data = kzalloc(sizeof(*dbs_data), GFP_KERNEL);
+ if (!dbs_data) {
+ pr_err("%s: POLICY_INIT: kzalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ dbs_data->cdata = cdata;
+ rc = cdata->init(dbs_data);
+ if (rc) {
+ pr_err("%s: POLICY_INIT: init() failed\n", __func__);
+ kfree(dbs_data);
+ return rc;
+ }
+
+ rc = sysfs_create_group(get_governor_parent_kobj(policy),
+ get_sysfs_attr(dbs_data));
+ if (rc) {
+ cdata->exit(dbs_data);
+ kfree(dbs_data);
+ return rc;
+ }
+
+ policy->governor_data = dbs_data;
- if (dbs_data->governor == GOV_CONSERVATIVE) {
- cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
- sampling_rate = &cs_tuners->sampling_rate;
+ /* policy latency is in nS. Convert it to uS first */
+ latency = policy->cpuinfo.transition_latency / 1000;
+ if (latency == 0)
+ latency = 1;
+
+ /* Bring kernel and HW constraints together */
+ dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
+ MIN_LATENCY_MULTIPLIER * latency);
+ set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
+ latency * LATENCY_MULTIPLIER));
+
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
+
+ cpufreq_register_notifier(cs_ops->notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
+ if (!have_governor_per_policy())
+ cdata->gdbs_data = dbs_data;
+
+ return 0;
+ case CPUFREQ_GOV_POLICY_EXIT:
+ if ((policy->governor->initialized == 1) ||
+ have_governor_per_policy()) {
+ sysfs_remove_group(get_governor_parent_kobj(policy),
+ get_sysfs_attr(dbs_data));
+
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
+
+ cpufreq_unregister_notifier(cs_ops->notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
+ cdata->exit(dbs_data);
+ kfree(dbs_data);
+ cdata->gdbs_data = NULL;
+ }
+
+ policy->governor_data = NULL;
+ return 0;
+ }
+
+ cpu_cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
+
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ cs_tuners = dbs_data->tuners;
+ cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
+ sampling_rate = cs_tuners->sampling_rate;
ignore_nice = cs_tuners->ignore_nice;
- cs_ops = dbs_data->gov_ops;
} else {
- od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu);
- sampling_rate = &od_tuners->sampling_rate;
+ od_tuners = dbs_data->tuners;
+ od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
+ sampling_rate = od_tuners->sampling_rate;
ignore_nice = od_tuners->ignore_nice;
- od_ops = dbs_data->gov_ops;
+ od_ops = dbs_data->cdata->gov_ops;
+ io_busy = od_tuners->io_is_busy;
}
switch (event) {
@@ -232,96 +352,53 @@ int cpufreq_governor_dbs(struct dbs_data *dbs_data,
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs =
- dbs_data->get_cpu_cdbs(j);
+ dbs_data->cdata->get_cpu_cdbs(j);
j_cdbs->cpu = j;
j_cdbs->cur_policy = policy;
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
- &j_cdbs->prev_cpu_wall);
+ &j_cdbs->prev_cpu_wall, io_busy);
if (ignore_nice)
j_cdbs->prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
mutex_init(&j_cdbs->timer_mutex);
INIT_DEFERRABLE_WORK(&j_cdbs->work,
- dbs_data->gov_dbs_timer);
- }
-
- if (!policy->governor->initialized) {
- rc = sysfs_create_group(cpufreq_global_kobject,
- dbs_data->attr_group);
- if (rc) {
- mutex_unlock(&dbs_data->mutex);
- return rc;
- }
+ dbs_data->cdata->gov_dbs_timer);
}
/*
* conservative does not implement micro like ondemand
* governor, thus we are bound to jiffes/HZ
*/
- if (dbs_data->governor == GOV_CONSERVATIVE) {
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
cs_dbs_info->down_skip = 0;
cs_dbs_info->enable = 1;
cs_dbs_info->requested_freq = policy->cur;
-
- if (!policy->governor->initialized) {
- cpufreq_register_notifier(cs_ops->notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
-
- dbs_data->min_sampling_rate =
- MIN_SAMPLING_RATE_RATIO *
- jiffies_to_usecs(10);
- }
} else {
od_dbs_info->rate_mult = 1;
od_dbs_info->sample_type = OD_NORMAL_SAMPLE;
od_ops->powersave_bias_init_cpu(cpu);
-
- if (!policy->governor->initialized)
- od_tuners->io_is_busy = od_ops->io_busy();
}
- if (policy->governor->initialized)
- goto unlock;
-
- /* policy latency is in nS. Convert it to uS first */
- latency = policy->cpuinfo.transition_latency / 1000;
- if (latency == 0)
- latency = 1;
-
- /* Bring kernel and HW constraints together */
- dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate,
- MIN_LATENCY_MULTIPLIER * latency);
- *sampling_rate = max(dbs_data->min_sampling_rate, latency *
- LATENCY_MULTIPLIER);
-unlock:
mutex_unlock(&dbs_data->mutex);
/* Initiate timer time stamp */
cpu_cdbs->time_stamp = ktime_get();
- for_each_cpu(j, policy->cpus)
- dbs_timer_init(dbs_data, j, *sampling_rate);
+ gov_queue_work(dbs_data, policy,
+ delay_for_sampling_rate(sampling_rate), true);
break;
case CPUFREQ_GOV_STOP:
- if (dbs_data->governor == GOV_CONSERVATIVE)
+ if (dbs_data->cdata->governor == GOV_CONSERVATIVE)
cs_dbs_info->enable = 0;
- for_each_cpu(j, policy->cpus)
- dbs_timer_exit(dbs_data, j);
+ gov_cancel_work(dbs_data, policy);
mutex_lock(&dbs_data->mutex);
mutex_destroy(&cpu_cdbs->timer_mutex);
- if (policy->governor->initialized == 1) {
- sysfs_remove_group(cpufreq_global_kobject,
- dbs_data->attr_group);
- if (dbs_data->governor == GOV_CONSERVATIVE)
- cpufreq_unregister_notifier(cs_ops->notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- }
mutex_unlock(&dbs_data->mutex);
break;
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 46bde01eee62..8ac33538d0bd 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -14,8 +14,8 @@
* published by the Free Software Foundation.
*/
-#ifndef _CPUFREQ_GOVERNER_H
-#define _CPUFREQ_GOVERNER_H
+#ifndef _CPUFREQ_GOVERNOR_H
+#define _CPUFREQ_GOVERNOR_H
#include <linux/cpufreq.h>
#include <linux/kobject.h>
@@ -34,20 +34,81 @@
*/
#define MIN_SAMPLING_RATE_RATIO (2)
#define LATENCY_MULTIPLIER (1000)
-#define MIN_LATENCY_MULTIPLIER (100)
+#define MIN_LATENCY_MULTIPLIER (20)
#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
/* Ondemand Sampling types */
enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE};
-/* Macro creating sysfs show routines */
-#define show_one(_gov, file_name, object) \
-static ssize_t show_##file_name \
+/*
+ * Macro for creating governors sysfs routines
+ *
+ * - gov_sys: One governor instance per whole system
+ * - gov_pol: One governor instance per policy
+ */
+
+/* Create attributes */
+#define gov_sys_attr_ro(_name) \
+static struct global_attr _name##_gov_sys = \
+__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
+
+#define gov_sys_attr_rw(_name) \
+static struct global_attr _name##_gov_sys = \
+__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
+
+#define gov_pol_attr_ro(_name) \
+static struct freq_attr _name##_gov_pol = \
+__ATTR(_name, 0444, show_##_name##_gov_pol, NULL)
+
+#define gov_pol_attr_rw(_name) \
+static struct freq_attr _name##_gov_pol = \
+__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
+
+#define gov_sys_pol_attr_rw(_name) \
+ gov_sys_attr_rw(_name); \
+ gov_pol_attr_rw(_name)
+
+#define gov_sys_pol_attr_ro(_name) \
+ gov_sys_attr_ro(_name); \
+ gov_pol_attr_ro(_name)
+
+/* Create show/store routines */
+#define show_one(_gov, file_name) \
+static ssize_t show_##file_name##_gov_sys \
(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
- return sprintf(buf, "%u\n", _gov##_tuners.object); \
+ struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
+ return sprintf(buf, "%u\n", tuners->file_name); \
+} \
+ \
+static ssize_t show_##file_name##_gov_pol \
+(struct cpufreq_policy *policy, char *buf) \
+{ \
+ struct dbs_data *dbs_data = policy->governor_data; \
+ struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
+ return sprintf(buf, "%u\n", tuners->file_name); \
+}
+
+#define store_one(_gov, file_name) \
+static ssize_t store_##file_name##_gov_sys \
+(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
+{ \
+ struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
+ return store_##file_name(dbs_data, buf, count); \
+} \
+ \
+static ssize_t store_##file_name##_gov_pol \
+(struct cpufreq_policy *policy, const char *buf, size_t count) \
+{ \
+ struct dbs_data *dbs_data = policy->governor_data; \
+ return store_##file_name(dbs_data, buf, count); \
}
+#define show_store_one(_gov, file_name) \
+show_one(_gov, file_name); \
+store_one(_gov, file_name)
+
+/* create helper routines */
#define define_get_cpu_dbs_routines(_dbs_info) \
static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \
{ \
@@ -87,7 +148,6 @@ struct cpu_dbs_common_info {
struct od_cpu_dbs_info_s {
struct cpu_dbs_common_info cdbs;
- u64 prev_cpu_iowait;
struct cpufreq_frequency_table *freq_table;
unsigned int freq_lo;
unsigned int freq_lo_jiffies;
@@ -103,7 +163,7 @@ struct cs_cpu_dbs_info_s {
unsigned int enable:1;
};
-/* Governers sysfs tunables */
+/* Per policy Governers sysfs tunables */
struct od_dbs_tuners {
unsigned int ignore_nice;
unsigned int sampling_rate;
@@ -123,31 +183,42 @@ struct cs_dbs_tuners {
unsigned int freq_step;
};
-/* Per Governer data */
-struct dbs_data {
+/* Common Governer data across policies */
+struct dbs_data;
+struct common_dbs_data {
/* Common across governors */
#define GOV_ONDEMAND 0
#define GOV_CONSERVATIVE 1
int governor;
- unsigned int min_sampling_rate;
- struct attribute_group *attr_group;
- void *tuners;
+ struct attribute_group *attr_group_gov_sys; /* one governor - system */
+ struct attribute_group *attr_group_gov_pol; /* one governor - policy */
- /* dbs_mutex protects dbs_enable in governor start/stop */
- struct mutex mutex;
+ /* Common data for platforms that don't set have_governor_per_policy */
+ struct dbs_data *gdbs_data;
struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu);
void *(*get_cpu_dbs_info_s)(int cpu);
void (*gov_dbs_timer)(struct work_struct *work);
void (*gov_check_cpu)(int cpu, unsigned int load);
+ int (*init)(struct dbs_data *dbs_data);
+ void (*exit)(struct dbs_data *dbs_data);
/* Governor specific ops, see below */
void *gov_ops;
};
+/* Governer Per policy data */
+struct dbs_data {
+ struct common_dbs_data *cdata;
+ unsigned int min_sampling_rate;
+ void *tuners;
+
+ /* dbs_mutex protects dbs_enable in governor start/stop */
+ struct mutex mutex;
+};
+
/* Governor specific ops, will be passed to dbs_data->gov_ops */
struct od_ops {
- int (*io_busy)(void);
void (*powersave_bias_init_cpu)(int cpu);
unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation);
@@ -169,10 +240,31 @@ static inline int delay_for_sampling_rate(unsigned int sampling_rate)
return delay;
}
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall);
+#define declare_show_sampling_rate_min(_gov) \
+static ssize_t show_sampling_rate_min_gov_sys \
+(struct kobject *kobj, struct attribute *attr, char *buf) \
+{ \
+ struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
+ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
+} \
+ \
+static ssize_t show_sampling_rate_min_gov_pol \
+(struct cpufreq_policy *policy, char *buf) \
+{ \
+ struct dbs_data *dbs_data = policy->governor_data; \
+ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
+}
+
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate);
-int cpufreq_governor_dbs(struct dbs_data *dbs_data,
- struct cpufreq_policy *policy, unsigned int event);
-#endif /* _CPUFREQ_GOVERNER_H */
+int cpufreq_governor_dbs(struct cpufreq_policy *policy,
+ struct common_dbs_data *cdata, unsigned int event);
+void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
+ unsigned int delay, bool all_cpus);
+void od_register_powersave_bias_handler(unsigned int (*f)
+ (struct cpufreq_policy *, unsigned int, unsigned int),
+ unsigned int powersave_bias);
+void od_unregister_powersave_bias_handler(void);
+#endif /* _CPUFREQ_GOVERNOR_H */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index f3eb26cd848f..b0ffef96bf77 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -20,9 +20,11 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/percpu-defs.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/tick.h>
#include <linux/types.h>
+#include <linux/cpu.h>
#include "cpufreq_governor.h"
@@ -37,22 +39,14 @@
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
-static struct dbs_data od_dbs_data;
static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
+static struct od_ops od_ops;
+
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
static struct cpufreq_governor cpufreq_gov_ondemand;
#endif
-static struct od_dbs_tuners od_tuners = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
- DEF_FREQUENCY_DOWN_DIFFERENTIAL,
- .ignore_nice = 0,
- .powersave_bias = 0,
-};
-
static void ondemand_powersave_bias_init_cpu(int cpu)
{
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
@@ -89,7 +83,7 @@ static int should_io_be_busy(void)
* Returns the freq_hi to be used right now and will set freq_hi_jiffies,
* freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
*/
-static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
+static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
unsigned int freq_next, unsigned int relation)
{
unsigned int freq_req, freq_reduc, freq_avg;
@@ -98,6 +92,8 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
unsigned int jiffies_total, jiffies_hi, jiffies_lo;
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
policy->cpu);
+ struct dbs_data *dbs_data = policy->governor_data;
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
if (!dbs_info->freq_table) {
dbs_info->freq_lo = 0;
@@ -108,7 +104,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
relation, &index);
freq_req = dbs_info->freq_table[index].frequency;
- freq_reduc = freq_req * od_tuners.powersave_bias / 1000;
+ freq_reduc = freq_req * od_tuners->powersave_bias / 1000;
freq_avg = freq_req - freq_reduc;
/* Find freq bounds for freq_avg in freq_table */
@@ -127,7 +123,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
dbs_info->freq_lo_jiffies = 0;
return freq_lo;
}
- jiffies_total = usecs_to_jiffies(od_tuners.sampling_rate);
+ jiffies_total = usecs_to_jiffies(od_tuners->sampling_rate);
jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
jiffies_hi += ((freq_hi - freq_lo) / 2);
jiffies_hi /= (freq_hi - freq_lo);
@@ -148,12 +144,16 @@ static void ondemand_powersave_bias_init(void)
static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
{
- if (od_tuners.powersave_bias)
- freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
+ struct dbs_data *dbs_data = p->governor_data;
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+
+ if (od_tuners->powersave_bias)
+ freq = od_ops.powersave_bias_target(p, freq,
+ CPUFREQ_RELATION_H);
else if (p->cur == p->max)
return;
- __cpufreq_driver_target(p, freq, od_tuners.powersave_bias ?
+ __cpufreq_driver_target(p, freq, od_tuners->powersave_bias ?
CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
}
@@ -170,15 +170,17 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
{
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
+ struct dbs_data *dbs_data = policy->governor_data;
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
dbs_info->freq_lo = 0;
/* Check for frequency increase */
- if (load_freq > od_tuners.up_threshold * policy->cur) {
+ if (load_freq > od_tuners->up_threshold * policy->cur) {
/* If switching to max speed, apply sampling_down_factor */
if (policy->cur < policy->max)
dbs_info->rate_mult =
- od_tuners.sampling_down_factor;
+ od_tuners->sampling_down_factor;
dbs_freq_increase(policy, policy->max);
return;
}
@@ -193,9 +195,10 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
* support the current CPU usage without triggering the up policy. To be
* safe, we focus 10 points under the threshold.
*/
- if (load_freq < od_tuners.adj_up_threshold * policy->cur) {
+ if (load_freq < od_tuners->adj_up_threshold
+ * policy->cur) {
unsigned int freq_next;
- freq_next = load_freq / od_tuners.adj_up_threshold;
+ freq_next = load_freq / od_tuners->adj_up_threshold;
/* No longer fully busy, reset rate_mult */
dbs_info->rate_mult = 1;
@@ -203,65 +206,62 @@ static void od_check_cpu(int cpu, unsigned int load_freq)
if (freq_next < policy->min)
freq_next = policy->min;
- if (!od_tuners.powersave_bias) {
+ if (!od_tuners->powersave_bias) {
__cpufreq_driver_target(policy, freq_next,
CPUFREQ_RELATION_L);
- } else {
- int freq = powersave_bias_target(policy, freq_next,
- CPUFREQ_RELATION_L);
- __cpufreq_driver_target(policy, freq,
- CPUFREQ_RELATION_L);
+ return;
}
+
+ freq_next = od_ops.powersave_bias_target(policy, freq_next,
+ CPUFREQ_RELATION_L);
+ __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
}
}
static void od_dbs_timer(struct work_struct *work)
{
- struct delayed_work *dw = to_delayed_work(work);
struct od_cpu_dbs_info_s *dbs_info =
container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work);
unsigned int cpu = dbs_info->cdbs.cur_policy->cpu;
struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info,
cpu);
- int delay, sample_type = core_dbs_info->sample_type;
- bool eval_load;
+ struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data;
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
+ int delay = 0, sample_type = core_dbs_info->sample_type;
+ bool modify_all = true;
mutex_lock(&core_dbs_info->cdbs.timer_mutex);
- eval_load = need_load_eval(&core_dbs_info->cdbs,
- od_tuners.sampling_rate);
+ if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) {
+ modify_all = false;
+ goto max_delay;
+ }
/* Common NORMAL_SAMPLE setup */
core_dbs_info->sample_type = OD_NORMAL_SAMPLE;
if (sample_type == OD_SUB_SAMPLE) {
delay = core_dbs_info->freq_lo_jiffies;
- if (eval_load)
- __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
- core_dbs_info->freq_lo,
- CPUFREQ_RELATION_H);
+ __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy,
+ core_dbs_info->freq_lo, CPUFREQ_RELATION_H);
} else {
- if (eval_load)
- dbs_check_cpu(&od_dbs_data, cpu);
+ dbs_check_cpu(dbs_data, cpu);
if (core_dbs_info->freq_lo) {
/* Setup timer for SUB_SAMPLE */
core_dbs_info->sample_type = OD_SUB_SAMPLE;
delay = core_dbs_info->freq_hi_jiffies;
- } else {
- delay = delay_for_sampling_rate(od_tuners.sampling_rate
- * core_dbs_info->rate_mult);
}
}
- schedule_delayed_work_on(smp_processor_id(), dw, delay);
+max_delay:
+ if (!delay)
+ delay = delay_for_sampling_rate(od_tuners->sampling_rate
+ * core_dbs_info->rate_mult);
+
+ gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all);
mutex_unlock(&core_dbs_info->cdbs.timer_mutex);
}
/************************** sysfs interface ************************/
-
-static ssize_t show_sampling_rate_min(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%u\n", od_dbs_data.min_sampling_rate);
-}
+static struct common_dbs_data od_dbs_cdata;
/**
* update_sampling_rate - update sampling rate effective immediately if needed.
@@ -276,12 +276,14 @@ static ssize_t show_sampling_rate_min(struct kobject *kobj,
* reducing the sampling rate, we need to make the new value effective
* immediately.
*/
-static void update_sampling_rate(unsigned int new_rate)
+static void update_sampling_rate(struct dbs_data *dbs_data,
+ unsigned int new_rate)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
int cpu;
- od_tuners.sampling_rate = new_rate = max(new_rate,
- od_dbs_data.min_sampling_rate);
+ od_tuners->sampling_rate = new_rate = max(new_rate,
+ dbs_data->min_sampling_rate);
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
@@ -314,42 +316,54 @@ static void update_sampling_rate(unsigned int new_rate)
cancel_delayed_work_sync(&dbs_info->cdbs.work);
mutex_lock(&dbs_info->cdbs.timer_mutex);
- schedule_delayed_work_on(cpu, &dbs_info->cdbs.work,
- usecs_to_jiffies(new_rate));
+ gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy,
+ usecs_to_jiffies(new_rate), true);
}
mutex_unlock(&dbs_info->cdbs.timer_mutex);
}
}
-static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_sampling_rate(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
- update_sampling_rate(input);
+
+ update_sampling_rate(dbs_data, input);
return count;
}
-static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
+ unsigned int j;
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
- od_tuners.io_is_busy = !!input;
+ od_tuners->io_is_busy = !!input;
+
+ /* we need to re-evaluate prev_cpu_idle */
+ for_each_online_cpu(j) {
+ struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
+ j);
+ dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
+ &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
+ }
return count;
}
-static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -359,23 +373,24 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
return -EINVAL;
}
/* Calculate the new adj_up_threshold */
- od_tuners.adj_up_threshold += input;
- od_tuners.adj_up_threshold -= od_tuners.up_threshold;
+ od_tuners->adj_up_threshold += input;
+ od_tuners->adj_up_threshold -= od_tuners->up_threshold;
- od_tuners.up_threshold = input;
+ od_tuners->up_threshold = input;
return count;
}
-static ssize_t store_sampling_down_factor(struct kobject *a,
- struct attribute *b, const char *buf, size_t count)
+static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
+ const char *buf, size_t count)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input, j;
int ret;
ret = sscanf(buf, "%u", &input);
if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
return -EINVAL;
- od_tuners.sampling_down_factor = input;
+ od_tuners->sampling_down_factor = input;
/* Reset down sampling multiplier in case it was active */
for_each_online_cpu(j) {
@@ -386,9 +401,10 @@ static ssize_t store_sampling_down_factor(struct kobject *a,
return count;
}
-static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
@@ -401,18 +417,18 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
if (input > 1)
input = 1;
- if (input == od_tuners.ignore_nice) { /* nothing to do */
+ if (input == od_tuners->ignore_nice) { /* nothing to do */
return count;
}
- od_tuners.ignore_nice = input;
+ od_tuners->ignore_nice = input;
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct od_cpu_dbs_info_s *dbs_info;
dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
- &dbs_info->cdbs.prev_cpu_wall);
- if (od_tuners.ignore_nice)
+ &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
+ if (od_tuners->ignore_nice)
dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE];
@@ -420,9 +436,10 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b,
return count;
}
-static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
+static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
+ size_t count)
{
+ struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input;
int ret;
ret = sscanf(buf, "%u", &input);
@@ -433,68 +450,179 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
if (input > 1000)
input = 1000;
- od_tuners.powersave_bias = input;
+ od_tuners->powersave_bias = input;
ondemand_powersave_bias_init();
return count;
}
-show_one(od, sampling_rate, sampling_rate);
-show_one(od, io_is_busy, io_is_busy);
-show_one(od, up_threshold, up_threshold);
-show_one(od, sampling_down_factor, sampling_down_factor);
-show_one(od, ignore_nice_load, ignore_nice);
-show_one(od, powersave_bias, powersave_bias);
-
-define_one_global_rw(sampling_rate);
-define_one_global_rw(io_is_busy);
-define_one_global_rw(up_threshold);
-define_one_global_rw(sampling_down_factor);
-define_one_global_rw(ignore_nice_load);
-define_one_global_rw(powersave_bias);
-define_one_global_ro(sampling_rate_min);
-
-static struct attribute *dbs_attributes[] = {
- &sampling_rate_min.attr,
- &sampling_rate.attr,
- &up_threshold.attr,
- &sampling_down_factor.attr,
- &ignore_nice_load.attr,
- &powersave_bias.attr,
- &io_is_busy.attr,
+show_store_one(od, sampling_rate);
+show_store_one(od, io_is_busy);
+show_store_one(od, up_threshold);
+show_store_one(od, sampling_down_factor);
+show_store_one(od, ignore_nice);
+show_store_one(od, powersave_bias);
+declare_show_sampling_rate_min(od);
+
+gov_sys_pol_attr_rw(sampling_rate);
+gov_sys_pol_attr_rw(io_is_busy);
+gov_sys_pol_attr_rw(up_threshold);
+gov_sys_pol_attr_rw(sampling_down_factor);
+gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(powersave_bias);
+gov_sys_pol_attr_ro(sampling_rate_min);
+
+static struct attribute *dbs_attributes_gov_sys[] = {
+ &sampling_rate_min_gov_sys.attr,
+ &sampling_rate_gov_sys.attr,
+ &up_threshold_gov_sys.attr,
+ &sampling_down_factor_gov_sys.attr,
+ &ignore_nice_gov_sys.attr,
+ &powersave_bias_gov_sys.attr,
+ &io_is_busy_gov_sys.attr,
+ NULL
+};
+
+static struct attribute_group od_attr_group_gov_sys = {
+ .attrs = dbs_attributes_gov_sys,
+ .name = "ondemand",
+};
+
+static struct attribute *dbs_attributes_gov_pol[] = {
+ &sampling_rate_min_gov_pol.attr,
+ &sampling_rate_gov_pol.attr,
+ &up_threshold_gov_pol.attr,
+ &sampling_down_factor_gov_pol.attr,
+ &ignore_nice_gov_pol.attr,
+ &powersave_bias_gov_pol.attr,
+ &io_is_busy_gov_pol.attr,
NULL
};
-static struct attribute_group od_attr_group = {
- .attrs = dbs_attributes,
+static struct attribute_group od_attr_group_gov_pol = {
+ .attrs = dbs_attributes_gov_pol,
.name = "ondemand",
};
/************************** sysfs end ************************/
+static int od_init(struct dbs_data *dbs_data)
+{
+ struct od_dbs_tuners *tuners;
+ u64 idle_time;
+ int cpu;
+
+ tuners = kzalloc(sizeof(struct od_dbs_tuners), GFP_KERNEL);
+ if (!tuners) {
+ pr_err("%s: kzalloc failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ cpu = get_cpu();
+ idle_time = get_cpu_idle_time_us(cpu, NULL);
+ put_cpu();
+ if (idle_time != -1ULL) {
+ /* Idle micro accounting is supported. Use finer thresholds */
+ tuners->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
+ tuners->adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
+ MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
+ /*
+ * In nohz/micro accounting case we set the minimum frequency
+ * not depending on HZ, but fixed (very low). The deferred
+ * timer might skip some samples if idle/sleeping as needed.
+ */
+ dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
+ } else {
+ tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
+ tuners->adj_up_threshold = DEF_FREQUENCY_UP_THRESHOLD -
+ DEF_FREQUENCY_DOWN_DIFFERENTIAL;
+
+ /* For correct statistics, we need 10 ticks for each measure */
+ dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
+ jiffies_to_usecs(10);
+ }
+
+ tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
+ tuners->ignore_nice = 0;
+ tuners->powersave_bias = 0;
+ tuners->io_is_busy = should_io_be_busy();
+
+ dbs_data->tuners = tuners;
+ pr_info("%s: tuners %p\n", __func__, tuners);
+ mutex_init(&dbs_data->mutex);
+ return 0;
+}
+
+static void od_exit(struct dbs_data *dbs_data)
+{
+ kfree(dbs_data->tuners);
+}
+
define_get_cpu_dbs_routines(od_cpu_dbs_info);
static struct od_ops od_ops = {
- .io_busy = should_io_be_busy,
.powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu,
- .powersave_bias_target = powersave_bias_target,
+ .powersave_bias_target = generic_powersave_bias_target,
.freq_increase = dbs_freq_increase,
};
-static struct dbs_data od_dbs_data = {
+static struct common_dbs_data od_dbs_cdata = {
.governor = GOV_ONDEMAND,
- .attr_group = &od_attr_group,
- .tuners = &od_tuners,
+ .attr_group_gov_sys = &od_attr_group_gov_sys,
+ .attr_group_gov_pol = &od_attr_group_gov_pol,
.get_cpu_cdbs = get_cpu_cdbs,
.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
.gov_dbs_timer = od_dbs_timer,
.gov_check_cpu = od_check_cpu,
.gov_ops = &od_ops,
+ .init = od_init,
+ .exit = od_exit,
};
+static void od_set_powersave_bias(unsigned int powersave_bias)
+{
+ struct cpufreq_policy *policy;
+ struct dbs_data *dbs_data;
+ struct od_dbs_tuners *od_tuners;
+ unsigned int cpu;
+ cpumask_t done;
+
+ cpumask_clear(&done);
+
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpumask_test_cpu(cpu, &done))
+ continue;
+
+ policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.cur_policy;
+ dbs_data = policy->governor_data;
+ od_tuners = dbs_data->tuners;
+ od_tuners->powersave_bias = powersave_bias;
+
+ cpumask_or(&done, &done, policy->cpus);
+ }
+ put_online_cpus();
+}
+
+void od_register_powersave_bias_handler(unsigned int (*f)
+ (struct cpufreq_policy *, unsigned int, unsigned int),
+ unsigned int powersave_bias)
+{
+ od_ops.powersave_bias_target = f;
+ od_set_powersave_bias(powersave_bias);
+}
+EXPORT_SYMBOL_GPL(od_register_powersave_bias_handler);
+
+void od_unregister_powersave_bias_handler(void)
+{
+ od_ops.powersave_bias_target = generic_powersave_bias_target;
+ od_set_powersave_bias(0);
+}
+EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
+
static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int event)
{
- return cpufreq_governor_dbs(&od_dbs_data, policy, event);
+ return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
}
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
@@ -509,29 +637,6 @@ struct cpufreq_governor cpufreq_gov_ondemand = {
static int __init cpufreq_gov_dbs_init(void)
{
- u64 idle_time;
- int cpu = get_cpu();
-
- mutex_init(&od_dbs_data.mutex);
- idle_time = get_cpu_idle_time_us(cpu, NULL);
- put_cpu();
- if (idle_time != -1ULL) {
- /* Idle micro accounting is supported. Use finer thresholds */
- od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
- od_tuners.adj_up_threshold = MICRO_FREQUENCY_UP_THRESHOLD -
- MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
- /*
- * In nohz/micro accounting case we set the minimum frequency
- * not depending on HZ, but fixed (very low). The deferred
- * timer might skip some samples if idle/sleeping as needed.
- */
- od_dbs_data.min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
- } else {
- /* For correct statistics, we need 10 ticks for each measure */
- od_dbs_data.min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
- jiffies_to_usecs(10);
- }
-
return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 2fd779eb1ed1..bfd6273fd873 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -180,15 +180,19 @@ static void cpufreq_stats_free_sysfs(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!cpufreq_frequency_get_table(cpu))
+ if (!policy)
return;
- if (policy && !policy_is_shared(policy)) {
+ if (!cpufreq_frequency_get_table(cpu))
+ goto put_ref;
+
+ if (!policy_is_shared(policy)) {
pr_debug("%s: Free sysfs stat\n", __func__);
sysfs_remove_group(&policy->kobj, &stats_attr_group);
}
- if (policy)
- cpufreq_cpu_put(policy);
+
+put_ref:
+ cpufreq_cpu_put(policy);
}
static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
diff --git a/arch/cris/arch-v32/mach-a3/cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c
index ee391ecb5bc9..ee142c490575 100644
--- a/arch/cris/arch-v32/mach-a3/cpufreq.c
+++ b/drivers/cpufreq/cris-artpec3-cpufreq.c
@@ -27,23 +27,17 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
return clk_ctrl.pll ? 200000 : 6000;
}
-static void cris_freq_set_cpu_state(unsigned int state)
+static void cris_freq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int state)
{
- int i = 0;
struct cpufreq_freqs freqs;
reg_clkgen_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
-#ifdef CONFIG_SMP
- for_each_present_cpu(i)
-#endif
- {
- freqs.old = cris_freq_get_cpu_frequency(i);
- freqs.new = cris_freq_table[state].frequency;
- freqs.cpu = i;
- }
+ freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
+ freqs.new = cris_freq_table[state].frequency;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_disable();
@@ -57,7 +51,7 @@ static void cris_freq_set_cpu_state(unsigned int state)
local_irq_enable();
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
};
static int cris_freq_verify(struct cpufreq_policy *policy)
@@ -75,7 +69,7 @@ static int cris_freq_target(struct cpufreq_policy *policy,
target_freq, relation, &newstate))
return -EINVAL;
- cris_freq_set_cpu_state(newstate);
+ cris_freq_set_cpu_state(policy, newstate);
return 0;
}
diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c
index d92cf70d1cbe..12952235d5db 100644
--- a/arch/cris/arch-v32/mach-fs/cpufreq.c
+++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c
@@ -27,20 +27,17 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
return clk_ctrl.pll ? 200000 : 6000;
}
-static void cris_freq_set_cpu_state(unsigned int state)
+static void cris_freq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int state)
{
- int i;
struct cpufreq_freqs freqs;
reg_config_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
- for_each_possible_cpu(i) {
- freqs.old = cris_freq_get_cpu_frequency(i);
- freqs.new = cris_freq_table[state].frequency;
- freqs.cpu = i;
- }
+ freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
+ freqs.new = cris_freq_table[state].frequency;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_disable();
@@ -54,7 +51,7 @@ static void cris_freq_set_cpu_state(unsigned int state)
local_irq_enable();
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
};
static int cris_freq_verify(struct cpufreq_policy *policy)
@@ -71,7 +68,7 @@ static int cris_freq_target(struct cpufreq_policy *policy,
(policy, cris_freq_table, target_freq, relation, &newstate))
return -EINVAL;
- cris_freq_set_cpu_state(newstate);
+ cris_freq_set_cpu_state(policy, newstate);
return 0;
}
diff --git a/arch/arm/mach-davinci/cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index 4729eaab0f40..c33c76c360fa 100644
--- a/arch/arm/mach-davinci/cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -30,8 +30,6 @@
#include <mach/cpufreq.h>
#include <mach/common.h>
-#include "clock.h"
-
struct davinci_cpufreq {
struct device *dev;
struct clk *armclk;
@@ -79,18 +77,8 @@ static int davinci_target(struct cpufreq_policy *policy,
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
struct clk *armclk = cpufreq.armclk;
- /*
- * Ensure desired rate is within allowed range. Some govenors
- * (ondemand) will just pass target_freq=0 to get the minimum.
- */
- if (target_freq < policy->cpuinfo.min_freq)
- target_freq = policy->cpuinfo.min_freq;
- if (target_freq > policy->cpuinfo.max_freq)
- target_freq = policy->cpuinfo.max_freq;
-
freqs.old = davinci_getspeed(0);
freqs.new = clk_round_rate(armclk, target_freq * 1000) / 1000;
- freqs.cpu = 0;
if (freqs.old == freqs.new)
return ret;
@@ -102,7 +90,7 @@ static int davinci_target(struct cpufreq_policy *policy,
if (ret)
return -EINVAL;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* if moving to higher frequency, up the voltage beforehand */
if (pdata->set_voltage && freqs.new > freqs.old) {
@@ -126,7 +114,7 @@ static int davinci_target(struct cpufreq_policy *policy,
pdata->set_voltage(idx);
out:
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
}
@@ -147,21 +135,16 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
return result;
}
- policy->cur = policy->min = policy->max = davinci_getspeed(0);
+ policy->cur = davinci_getspeed(0);
- if (freq_table) {
- result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
- if (!result)
- cpufreq_frequency_table_get_attr(freq_table,
- policy->cpu);
- } else {
- policy->cpuinfo.min_freq = policy->min;
- policy->cpuinfo.max_freq = policy->max;
+ result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (result) {
+ pr_err("%s: cpufreq_frequency_table_cpuinfo() failed",
+ __func__);
+ return result;
}
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
- policy->cur = davinci_getspeed(0);
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
/*
* Time measurement across the target() function yields ~1500-1800us
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
index 72f0c3efa76e..6ec6539ae041 100644
--- a/drivers/cpufreq/dbx500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -37,12 +37,6 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int idx;
int ret;
- /* scale the target frequency to one of the extremes supported */
- if (target_freq < policy->cpuinfo.min_freq)
- target_freq = policy->cpuinfo.min_freq;
- if (target_freq > policy->cpuinfo.max_freq)
- target_freq = policy->cpuinfo.max_freq;
-
/* Lookup the next frequency */
if (cpufreq_frequency_table_target(policy, freq_table, target_freq,
relation, &idx))
@@ -55,8 +49,7 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
return 0;
/* pre-change notification */
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* update armss clk frequency */
ret = clk_set_rate(armss_clk, freqs.new * 1000);
@@ -68,8 +61,7 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
}
/* post change notification */
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
@@ -79,15 +71,15 @@ static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
int i = 0;
unsigned long freq = clk_get_rate(armss_clk) / 1000;
- while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
- if (freq <= freq_table[i].frequency)
+ /* The value is rounded to closest frequency in the defined table. */
+ while (freq_table[i + 1].frequency != CPUFREQ_TABLE_END) {
+ if (freq < freq_table[i].frequency +
+ (freq_table[i + 1].frequency - freq_table[i].frequency) / 2)
return freq_table[i].frequency;
i++;
}
- /* We could not find a corresponding frequency. */
- pr_err("dbx500-cpufreq: Failed to find cpufreq speed\n");
- return 0;
+ return freq_table[i].frequency;
}
static int __cpuinit dbx500_cpufreq_init(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 3fffbe6025cd..37380fb92621 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -104,7 +104,7 @@ static unsigned int eps_get(unsigned int cpu)
}
static int eps_set_state(struct eps_cpu_data *centaur,
- unsigned int cpu,
+ struct cpufreq_policy *policy,
u32 dest_state)
{
struct cpufreq_freqs freqs;
@@ -112,10 +112,9 @@ static int eps_set_state(struct eps_cpu_data *centaur,
int err = 0;
int i;
- freqs.old = eps_get(cpu);
+ freqs.old = eps_get(policy->cpu);
freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff);
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Wait while CPU is busy */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
@@ -162,7 +161,7 @@ postchange:
current_multiplier);
}
#endif
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return err;
}
@@ -190,7 +189,7 @@ static int eps_target(struct cpufreq_policy *policy,
/* Make frequency transition */
dest_state = centaur->freq_table[newstate].index & 0xffff;
- ret = eps_set_state(centaur, cpu, dest_state);
+ ret = eps_set_state(centaur, policy, dest_state);
if (ret)
printk(KERN_ERR "eps: Timeout!\n");
return ret;
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index 960671fd3d7e..658d860344b0 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -117,15 +117,15 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
* There is no return value.
*/
-static void elanfreq_set_cpu_state(unsigned int state)
+static void elanfreq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int state)
{
struct cpufreq_freqs freqs;
freqs.old = elanfreq_get_cpu_frequency(0);
freqs.new = elan_multiplier[state].clock;
- freqs.cpu = 0; /* elanfreq.c is UP only driver */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",
elan_multiplier[state].clock);
@@ -161,7 +161,7 @@ static void elanfreq_set_cpu_state(unsigned int state)
udelay(10000);
local_irq_enable();
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
};
@@ -188,7 +188,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
target_freq, relation, &newstate))
return -EINVAL;
- elanfreq_set_cpu_state(newstate);
+ elanfreq_set_cpu_state(policy, newstate);
return 0;
}
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 78057a357ddb..475b4f607f0d 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -70,7 +70,6 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
freqs.old = policy->cur;
freqs.new = target_freq;
- freqs.cpu = policy->cpu;
if (freqs.new == freqs.old)
goto out;
@@ -105,8 +104,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
}
arm_volt = volt_table[index];
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* When the new frequency is higher than current frequency */
if ((freqs.new > freqs.old) && !safe_arm_volt) {
@@ -131,8 +129,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
exynos_info->set_freq(old_index, index);
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
/* When the new frequency is lower than current frequency */
if ((freqs.new < freqs.old) ||
@@ -297,7 +294,7 @@ static int __init exynos_cpufreq_init(void)
else if (soc_is_exynos5250())
ret = exynos5250_cpufreq_init(exynos_info);
else
- pr_err("%s: CPU type not found\n", __func__);
+ return 0;
if (ret)
goto err_vdd_arm;
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
new file mode 100644
index 000000000000..0c74018eda47
--- /dev/null
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Amit Daniel Kachhap <amit.daniel@samsung.com>
+ *
+ * EXYNOS5440 - CPU frequency scaling support
+ *
+ * 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/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Register definitions */
+#define XMU_DVFS_CTRL 0x0060
+#define XMU_PMU_P0_7 0x0064
+#define XMU_C0_3_PSTATE 0x0090
+#define XMU_P_LIMIT 0x00a0
+#define XMU_P_STATUS 0x00a4
+#define XMU_PMUEVTEN 0x00d0
+#define XMU_PMUIRQEN 0x00d4
+#define XMU_PMUIRQ 0x00d8
+
+/* PMU mask and shift definations */
+#define P_VALUE_MASK 0x7
+
+#define XMU_DVFS_CTRL_EN_SHIFT 0
+
+#define P0_7_CPUCLKDEV_SHIFT 21
+#define P0_7_CPUCLKDEV_MASK 0x7
+#define P0_7_ATBCLKDEV_SHIFT 18
+#define P0_7_ATBCLKDEV_MASK 0x7
+#define P0_7_CSCLKDEV_SHIFT 15
+#define P0_7_CSCLKDEV_MASK 0x7
+#define P0_7_CPUEMA_SHIFT 28
+#define P0_7_CPUEMA_MASK 0xf
+#define P0_7_L2EMA_SHIFT 24
+#define P0_7_L2EMA_MASK 0xf
+#define P0_7_VDD_SHIFT 8
+#define P0_7_VDD_MASK 0x7f
+#define P0_7_FREQ_SHIFT 0
+#define P0_7_FREQ_MASK 0xff
+
+#define C0_3_PSTATE_VALID_SHIFT 8
+#define C0_3_PSTATE_CURR_SHIFT 4
+#define C0_3_PSTATE_NEW_SHIFT 0
+
+#define PSTATE_CHANGED_EVTEN_SHIFT 0
+
+#define PSTATE_CHANGED_IRQEN_SHIFT 0
+
+#define PSTATE_CHANGED_SHIFT 0
+
+/* some constant values for clock divider calculation */
+#define CPU_DIV_FREQ_MAX 500
+#define CPU_DBG_FREQ_MAX 375
+#define CPU_ATB_FREQ_MAX 500
+
+#define PMIC_LOW_VOLT 0x30
+#define PMIC_HIGH_VOLT 0x28
+
+#define CPUEMA_HIGH 0x2
+#define CPUEMA_MID 0x4
+#define CPUEMA_LOW 0x7
+
+#define L2EMA_HIGH 0x1
+#define L2EMA_MID 0x3
+#define L2EMA_LOW 0x4
+
+#define DIV_TAB_MAX 2
+/* frequency unit is 20MHZ */
+#define FREQ_UNIT 20
+#define MAX_VOLTAGE 1550000 /* In microvolt */
+#define VOLTAGE_STEP 12500 /* In microvolt */
+
+#define CPUFREQ_NAME "exynos5440_dvfs"
+#define DEF_TRANS_LATENCY 100000
+
+enum cpufreq_level_index {
+ L0, L1, L2, L3, L4,
+ L5, L6, L7, L8, L9,
+};
+#define CPUFREQ_LEVEL_END (L7 + 1)
+
+struct exynos_dvfs_data {
+ void __iomem *base;
+ struct resource *mem;
+ int irq;
+ struct clk *cpu_clk;
+ unsigned int cur_frequency;
+ unsigned int latency;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int freq_count;
+ struct device *dev;
+ bool dvfs_enabled;
+ struct work_struct irq_work;
+};
+
+static struct exynos_dvfs_data *dvfs_info;
+static DEFINE_MUTEX(cpufreq_lock);
+static struct cpufreq_freqs freqs;
+
+static int init_div_table(void)
+{
+ struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
+ unsigned int tmp, clk_div, ema_div, freq, volt_id;
+ int i = 0;
+ struct opp *opp;
+
+ rcu_read_lock();
+ for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
+
+ opp = opp_find_freq_exact(dvfs_info->dev,
+ freq_tbl[i].frequency * 1000, true);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dvfs_info->dev,
+ "failed to find valid OPP for %u KHZ\n",
+ freq_tbl[i].frequency);
+ return PTR_ERR(opp);
+ }
+
+ freq = freq_tbl[i].frequency / 1000; /* In MHZ */
+ clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
+ << P0_7_CPUCLKDEV_SHIFT;
+ clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
+ << P0_7_ATBCLKDEV_SHIFT;
+ clk_div |= ((freq / CPU_DBG_FREQ_MAX) & P0_7_CSCLKDEV_MASK)
+ << P0_7_CSCLKDEV_SHIFT;
+
+ /* Calculate EMA */
+ volt_id = opp_get_voltage(opp);
+ volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
+ if (volt_id < PMIC_HIGH_VOLT) {
+ ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
+ (L2EMA_HIGH << P0_7_L2EMA_SHIFT);
+ } else if (volt_id > PMIC_LOW_VOLT) {
+ ema_div = (CPUEMA_LOW << P0_7_CPUEMA_SHIFT) |
+ (L2EMA_LOW << P0_7_L2EMA_SHIFT);
+ } else {
+ ema_div = (CPUEMA_MID << P0_7_CPUEMA_SHIFT) |
+ (L2EMA_MID << P0_7_L2EMA_SHIFT);
+ }
+
+ tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
+ | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
+
+ __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
+ }
+
+ rcu_read_unlock();
+ return 0;
+}
+
+static void exynos_enable_dvfs(void)
+{
+ unsigned int tmp, i, cpu;
+ struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
+ /* Disable DVFS */
+ __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
+
+ /* Enable PSTATE Change Event */
+ tmp = __raw_readl(dvfs_info->base + XMU_PMUEVTEN);
+ tmp |= (1 << PSTATE_CHANGED_EVTEN_SHIFT);
+ __raw_writel(tmp, dvfs_info->base + XMU_PMUEVTEN);
+
+ /* Enable PSTATE Change IRQ */
+ tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQEN);
+ tmp |= (1 << PSTATE_CHANGED_IRQEN_SHIFT);
+ __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
+
+ /* Set initial performance index */
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+ if (freq_table[i].frequency == dvfs_info->cur_frequency)
+ break;
+
+ if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
+ dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
+ /* Assign the highest frequency */
+ i = 0;
+ dvfs_info->cur_frequency = freq_table[i].frequency;
+ }
+
+ dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
+ dvfs_info->cur_frequency);
+
+ for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
+ tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
+ tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
+ tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
+ __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
+ }
+
+ /* Enable DVFS */
+ __raw_writel(1 << XMU_DVFS_CTRL_EN_SHIFT,
+ dvfs_info->base + XMU_DVFS_CTRL);
+}
+
+static int exynos_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ dvfs_info->freq_table);
+}
+
+static unsigned int exynos_getspeed(unsigned int cpu)
+{
+ return dvfs_info->cur_frequency;
+}
+
+static int exynos_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int index, tmp;
+ int ret = 0, i;
+ struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
+
+ mutex_lock(&cpufreq_lock);
+
+ ret = cpufreq_frequency_table_target(policy, freq_table,
+ target_freq, relation, &index);
+ if (ret)
+ goto out;
+
+ freqs.old = dvfs_info->cur_frequency;
+ freqs.new = freq_table[index].frequency;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+ /* Set the target frequency in all C0_3_PSTATE register */
+ for_each_cpu(i, policy->cpus) {
+ tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
+ tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
+ tmp |= (index << C0_3_PSTATE_NEW_SHIFT);
+
+ __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4);
+ }
+out:
+ mutex_unlock(&cpufreq_lock);
+ return ret;
+}
+
+static void exynos_cpufreq_work(struct work_struct *work)
+{
+ unsigned int cur_pstate, index;
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */
+ struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
+
+ /* Ensure we can access cpufreq structures */
+ if (unlikely(dvfs_info->dvfs_enabled == false))
+ goto skip_work;
+
+ mutex_lock(&cpufreq_lock);
+ freqs.old = dvfs_info->cur_frequency;
+
+ cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS);
+ if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1)
+ index = (cur_pstate >> C0_3_PSTATE_CURR_SHIFT) & P_VALUE_MASK;
+ else
+ index = (cur_pstate >> C0_3_PSTATE_NEW_SHIFT) & P_VALUE_MASK;
+
+ if (likely(index < dvfs_info->freq_count)) {
+ freqs.new = freq_table[index].frequency;
+ dvfs_info->cur_frequency = freqs.new;
+ } else {
+ dev_crit(dvfs_info->dev, "New frequency out of range\n");
+ freqs.new = dvfs_info->cur_frequency;
+ }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+
+ cpufreq_cpu_put(policy);
+ mutex_unlock(&cpufreq_lock);
+skip_work:
+ enable_irq(dvfs_info->irq);
+}
+
+static irqreturn_t exynos_cpufreq_irq(int irq, void *id)
+{
+ unsigned int tmp;
+
+ tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQ);
+ if (tmp >> PSTATE_CHANGED_SHIFT & 0x1) {
+ __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQ);
+ disable_irq_nosync(irq);
+ schedule_work(&dvfs_info->irq_work);
+ }
+ return IRQ_HANDLED;
+}
+
+static void exynos_sort_descend_freq_table(void)
+{
+ struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
+ int i = 0, index;
+ unsigned int tmp_freq;
+ /*
+ * Exynos5440 clock controller state logic expects the cpufreq table to
+ * be in descending order. But the OPP library constructs the table in
+ * ascending order. So to make the table descending we just need to
+ * swap the i element with the N - i element.
+ */
+ for (i = 0; i < dvfs_info->freq_count / 2; i++) {
+ index = dvfs_info->freq_count - i - 1;
+ tmp_freq = freq_tbl[i].frequency;
+ freq_tbl[i].frequency = freq_tbl[index].frequency;
+ freq_tbl[index].frequency = tmp_freq;
+ }
+}
+
+static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int ret;
+
+ ret = cpufreq_frequency_table_cpuinfo(policy, dvfs_info->freq_table);
+ if (ret) {
+ dev_err(dvfs_info->dev, "Invalid frequency table: %d\n", ret);
+ return ret;
+ }
+
+ policy->cur = dvfs_info->cur_frequency;
+ policy->cpuinfo.transition_latency = dvfs_info->latency;
+ cpumask_setall(policy->cpus);
+
+ cpufreq_frequency_table_get_attr(dvfs_info->freq_table, policy->cpu);
+
+ return 0;
+}
+
+static struct cpufreq_driver exynos_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = exynos_verify_speed,
+ .target = exynos_target,
+ .get = exynos_getspeed,
+ .init = exynos_cpufreq_cpu_init,
+ .name = CPUFREQ_NAME,
+};
+
+static const struct of_device_id exynos_cpufreq_match[] = {
+ {
+ .compatible = "samsung,exynos5440-cpufreq",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_cpufreq_match);
+
+static int exynos_cpufreq_probe(struct platform_device *pdev)
+{
+ int ret = -EINVAL;
+ struct device_node *np;
+ struct resource res;
+
+ np = pdev->dev.of_node;
+ if (!np)
+ return -ENODEV;
+
+ dvfs_info = devm_kzalloc(&pdev->dev, sizeof(*dvfs_info), GFP_KERNEL);
+ if (!dvfs_info) {
+ ret = -ENOMEM;
+ goto err_put_node;
+ }
+
+ dvfs_info->dev = &pdev->dev;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ goto err_put_node;
+
+ dvfs_info->base = devm_ioremap_resource(dvfs_info->dev, &res);
+ if (IS_ERR(dvfs_info->base)) {
+ ret = PTR_ERR(dvfs_info->base);
+ goto err_put_node;
+ }
+
+ dvfs_info->irq = irq_of_parse_and_map(np, 0);
+ if (!dvfs_info->irq) {
+ dev_err(dvfs_info->dev, "No cpufreq irq found\n");
+ ret = -ENODEV;
+ goto err_put_node;
+ }
+
+ ret = of_init_opp_table(dvfs_info->dev);
+ if (ret) {
+ dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret);
+ goto err_put_node;
+ }
+
+ ret = opp_init_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+ if (ret) {
+ dev_err(dvfs_info->dev,
+ "failed to init cpufreq table: %d\n", ret);
+ goto err_put_node;
+ }
+ dvfs_info->freq_count = opp_get_opp_count(dvfs_info->dev);
+ exynos_sort_descend_freq_table();
+
+ if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency))
+ dvfs_info->latency = DEF_TRANS_LATENCY;
+
+ dvfs_info->cpu_clk = devm_clk_get(dvfs_info->dev, "armclk");
+ if (IS_ERR(dvfs_info->cpu_clk)) {
+ dev_err(dvfs_info->dev, "Failed to get cpu clock\n");
+ ret = PTR_ERR(dvfs_info->cpu_clk);
+ goto err_free_table;
+ }
+
+ dvfs_info->cur_frequency = clk_get_rate(dvfs_info->cpu_clk);
+ if (!dvfs_info->cur_frequency) {
+ dev_err(dvfs_info->dev, "Failed to get clock rate\n");
+ ret = -EINVAL;
+ goto err_free_table;
+ }
+ dvfs_info->cur_frequency /= 1000;
+
+ INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work);
+ ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq,
+ exynos_cpufreq_irq, IRQF_TRIGGER_NONE,
+ CPUFREQ_NAME, dvfs_info);
+ if (ret) {
+ dev_err(dvfs_info->dev, "Failed to register IRQ\n");
+ goto err_free_table;
+ }
+
+ ret = init_div_table();
+ if (ret) {
+ dev_err(dvfs_info->dev, "Failed to initialise div table\n");
+ goto err_free_table;
+ }
+
+ exynos_enable_dvfs();
+ ret = cpufreq_register_driver(&exynos_driver);
+ if (ret) {
+ dev_err(dvfs_info->dev,
+ "%s: failed to register cpufreq driver\n", __func__);
+ goto err_free_table;
+ }
+
+ of_node_put(np);
+ dvfs_info->dvfs_enabled = true;
+ return 0;
+
+err_free_table:
+ opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+err_put_node:
+ of_node_put(np);
+ dev_err(dvfs_info->dev, "%s: failed initialization\n", __func__);
+ return ret;
+}
+
+static int exynos_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_driver(&exynos_driver);
+ opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+ return 0;
+}
+
+static struct platform_driver exynos_cpufreq_platdrv = {
+ .driver = {
+ .name = "exynos5440-cpufreq",
+ .owner = THIS_MODULE,
+ .of_match_table = exynos_cpufreq_match,
+ },
+ .probe = exynos_cpufreq_probe,
+ .remove = exynos_cpufreq_remove,
+};
+module_platform_driver(exynos_cpufreq_platdrv);
+
+MODULE_AUTHOR("Amit Daniel Kachhap <amit.daniel@samsung.com>");
+MODULE_DESCRIPTION("Exynos5440 cpufreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 456bee058fe6..3dfc99b9ca86 100644
--- a/drivers/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -251,14 +251,13 @@ static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration,
* set cpu speed in khz.
**/
-static void gx_set_cpuspeed(unsigned int khz)
+static void gx_set_cpuspeed(struct cpufreq_policy *policy, unsigned int khz)
{
u8 suscfg, pmer1;
unsigned int new_khz;
unsigned long flags;
struct cpufreq_freqs freqs;
- freqs.cpu = 0;
freqs.old = gx_get_cpuspeed(0);
new_khz = gx_validate_speed(khz, &gx_params->on_duration,
@@ -266,11 +265,9 @@ static void gx_set_cpuspeed(unsigned int khz)
freqs.new = new_khz;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_save(flags);
-
-
if (new_khz != stock_freq) {
/* if new khz == 100% of CPU speed, it is special case */
switch (gx_params->cs55x0->device) {
@@ -317,7 +314,7 @@ static void gx_set_cpuspeed(unsigned int khz)
gx_params->pci_suscfg = suscfg;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
gx_params->on_duration * 32, gx_params->off_duration * 32);
@@ -397,7 +394,7 @@ static int cpufreq_gx_target(struct cpufreq_policy *policy,
tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2);
}
- gx_set_cpuspeed(tmp_freq);
+ gx_set_cpuspeed(policy, tmp_freq);
return 0;
}
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index f09b174244d5..c0075dbaa633 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -1,5 +1,4 @@
/*
- * arch/ia64/kernel/cpufreq/acpi-cpufreq.c
* This file provides the ACPI based P-state support. This
* module works with generic cpufreq infrastructure. Most of
* the code is based on i386 version
@@ -137,7 +136,7 @@ migrate_end:
static int
processor_set_freq (
struct cpufreq_acpi_io *data,
- unsigned int cpu,
+ struct cpufreq_policy *policy,
int state)
{
int ret = 0;
@@ -149,8 +148,8 @@ processor_set_freq (
pr_debug("processor_set_freq\n");
saved_mask = current->cpus_allowed;
- set_cpus_allowed_ptr(current, cpumask_of(cpu));
- if (smp_processor_id() != cpu) {
+ set_cpus_allowed_ptr(current, cpumask_of(policy->cpu));
+ if (smp_processor_id() != policy->cpu) {
retval = -EAGAIN;
goto migrate_end;
}
@@ -170,12 +169,11 @@ processor_set_freq (
data->acpi_data.state, state);
/* cpufreq frequency struct */
- cpufreq_freqs.cpu = cpu;
cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
cpufreq_freqs.new = data->freq_table[state].frequency;
/* notify cpufreq */
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_PRECHANGE);
/*
* First we write the target state's 'control' value to the
@@ -189,17 +187,20 @@ processor_set_freq (
ret = processor_set_pstate(value);
if (ret) {
unsigned int tmp = cpufreq_freqs.new;
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &cpufreq_freqs,
+ CPUFREQ_POSTCHANGE);
cpufreq_freqs.new = cpufreq_freqs.old;
cpufreq_freqs.old = tmp;
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &cpufreq_freqs,
+ CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &cpufreq_freqs,
+ CPUFREQ_POSTCHANGE);
printk(KERN_WARNING "Transition failed with error %d\n", ret);
retval = -ENODEV;
goto migrate_end;
}
- cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE);
data->acpi_data.state = state;
@@ -240,7 +241,7 @@ acpi_cpufreq_target (
if (result)
return (result);
- result = processor_set_freq(data, policy->cpu, next_state);
+ result = processor_set_freq(data, policy, next_state);
return (result);
}
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index 54e336de373b..b78bc35973ba 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -50,7 +50,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs;
struct opp *opp;
unsigned long freq_hz, volt, volt_old;
- unsigned int index, cpu;
+ unsigned int index;
int ret;
ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
@@ -68,10 +68,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return 0;
- for_each_online_cpu(cpu) {
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
rcu_read_lock();
opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
@@ -166,10 +163,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
}
}
- for_each_online_cpu(cpu) {
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/arch/arm/mach-integrator/cpu.c b/drivers/cpufreq/integrator-cpufreq.c
index 590c192cdf4d..f7c99df0880b 100644
--- a/arch/arm/mach-integrator/cpu.c
+++ b/drivers/cpufreq/integrator-cpufreq.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-integrator/cpu.c
- *
* Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
*
* This program is free software; you can redistribute it and/or modify
@@ -123,14 +121,12 @@ static int integrator_set_target(struct cpufreq_policy *policy,
vco = icst_hz_to_vco(&cclk_params, target_freq * 1000);
freqs.new = icst_hz(&cclk_params, vco) / 1000;
- freqs.cpu = policy->cpu;
-
if (freqs.old == freqs.new) {
set_cpus_allowed(current, cpus_allowed);
return 0;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
cm_osc = __raw_readl(CM_OSC);
@@ -151,7 +147,7 @@ static int integrator_set_target(struct cpufreq_policy *policy,
*/
set_cpus_allowed(current, cpus_allowed);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index f6dd1e761129..cc3a8e6c92be 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -1,5 +1,5 @@
/*
- * cpufreq_snb.c: Native P state management for Intel processors
+ * intel_pstate.c: Native P state management for Intel processors
*
* (C) Copyright 2012 Intel Corporation
* Author: Dirk Brandewie <dirk.j.brandewie@intel.com>
@@ -358,14 +358,14 @@ static void intel_pstate_sysfs_expose_params(void)
static int intel_pstate_min_pstate(void)
{
u64 value;
- rdmsrl(0xCE, value);
+ rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 40) & 0xFF;
}
static int intel_pstate_max_pstate(void)
{
u64 value;
- rdmsrl(0xCE, value);
+ rdmsrl(MSR_PLATFORM_INFO, value);
return (value >> 8) & 0xFF;
}
@@ -373,7 +373,7 @@ static int intel_pstate_turbo_pstate(void)
{
u64 value;
int nont, ret;
- rdmsrl(0x1AD, value);
+ rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
nont = intel_pstate_max_pstate();
ret = ((value) & 255);
if (ret <= nont)
@@ -454,7 +454,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
sample->idletime_us * 100,
sample->duration_us);
core_pct = div64_u64(sample->aperf * 100, sample->mperf);
- sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000;
+ sample->freq = cpu->pstate.max_pstate * core_pct * 1000;
sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct),
100);
@@ -502,7 +502,6 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
sample_time = cpu->pstate_policy->sample_rate_ms;
delay = msecs_to_jiffies(sample_time);
- delay -= jiffies % delay;
mod_timer_pinned(&cpu->timer, jiffies + delay);
}
@@ -658,30 +657,27 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{
struct cpudata *cpu;
- int min, max;
cpu = all_cpu_data[policy->cpu];
if (!policy->cpuinfo.max_freq)
return -ENODEV;
- intel_pstate_get_min_max(cpu, &min, &max);
-
- limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
- limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
- limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
-
- limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
- limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
- limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
-
if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
limits.min_perf_pct = 100;
limits.min_perf = int_tofp(1);
limits.max_perf_pct = 100;
limits.max_perf = int_tofp(1);
limits.no_turbo = 0;
+ return 0;
}
+ limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
+ limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
+ limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+
+ limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
+ limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
+ limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
return 0;
}
@@ -752,6 +748,29 @@ static struct cpufreq_driver intel_pstate_driver = {
static int __initdata no_load;
+static int intel_pstate_msrs_not_valid(void)
+{
+ /* Check that all the msr's we are using are valid. */
+ u64 aperf, mperf, tmp;
+
+ rdmsrl(MSR_IA32_APERF, aperf);
+ rdmsrl(MSR_IA32_MPERF, mperf);
+
+ if (!intel_pstate_min_pstate() ||
+ !intel_pstate_max_pstate() ||
+ !intel_pstate_turbo_pstate())
+ return -ENODEV;
+
+ rdmsrl(MSR_IA32_APERF, tmp);
+ if (!(tmp - aperf))
+ return -ENODEV;
+
+ rdmsrl(MSR_IA32_MPERF, tmp);
+ if (!(tmp - mperf))
+ return -ENODEV;
+
+ return 0;
+}
static int __init intel_pstate_init(void)
{
int cpu, rc = 0;
@@ -764,6 +783,9 @@ static int __init intel_pstate_init(void)
if (!id)
return -ENODEV;
+ if (intel_pstate_msrs_not_valid())
+ return -ENODEV;
+
pr_info("Intel P-state driver initializing.\n");
all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus());
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index 0e83e3c24f5b..d36ea8dc96eb 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -55,7 +55,8 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
return kirkwood_freq_table[0].frequency;
}
-static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
+static void kirkwood_cpufreq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int index)
{
struct cpufreq_freqs freqs;
unsigned int state = kirkwood_freq_table[index].index;
@@ -63,9 +64,8 @@ static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
freqs.new = kirkwood_freq_table[index].frequency;
- freqs.cpu = 0; /* Kirkwood is UP */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n",
kirkwood_freq_table[index].frequency);
@@ -99,7 +99,7 @@ static void kirkwood_cpufreq_set_cpu_state(unsigned int index)
local_irq_enable();
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
};
static int kirkwood_cpufreq_verify(struct cpufreq_policy *policy)
@@ -117,7 +117,7 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
target_freq, relation, &index))
return -EINVAL;
- kirkwood_cpufreq_set_cpu_state(index);
+ kirkwood_cpufreq_set_cpu_state(policy, index);
return 0;
}
@@ -175,11 +175,9 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Cannot get memory resource\n");
return -ENODEV;
}
- priv.base = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv.base) {
- dev_err(&pdev->dev, "Cannot ioremap\n");
- return -EADDRNOTAVAIL;
- }
+ priv.base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv.base))
+ return PTR_ERR(priv.base);
np = of_find_node_by_path("/cpus/cpu@0");
if (!np)
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 1180d536d1eb..b448638e34de 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -242,7 +242,8 @@ static void do_powersaver(int cx_address, unsigned int mults_index,
* Sets a new clock ratio.
*/
-static void longhaul_setstate(unsigned int table_index)
+static void longhaul_setstate(struct cpufreq_policy *policy,
+ unsigned int table_index)
{
unsigned int mults_index;
int speed, mult;
@@ -267,9 +268,8 @@ static void longhaul_setstate(unsigned int table_index)
freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
- freqs.cpu = 0; /* longhaul.c is UP only driver */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
@@ -386,7 +386,7 @@ retry_loop:
}
}
/* Report true CPU frequency */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (!bm_timeout)
printk(KERN_INFO PFX "Warning: Timeout while waiting for "
@@ -648,7 +648,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
return 0;
if (!can_scale_voltage)
- longhaul_setstate(table_index);
+ longhaul_setstate(policy, table_index);
else {
/* On test system voltage transitions exceeding single
* step up or down were turning motherboard off. Both
@@ -663,7 +663,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
while (i != table_index) {
vid = (longhaul_table[i].index >> 8) & 0x1f;
if (vid != current_vid) {
- longhaul_setstate(i);
+ longhaul_setstate(policy, i);
current_vid = vid;
msleep(200);
}
@@ -672,7 +672,7 @@ static int longhaul_target(struct cpufreq_policy *policy,
else
i--;
}
- longhaul_setstate(table_index);
+ longhaul_setstate(policy, table_index);
}
longhaul_index = table_index;
return 0;
@@ -998,15 +998,17 @@ static int __init longhaul_init(void)
static void __exit longhaul_exit(void)
{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
int i;
for (i = 0; i < numscales; i++) {
if (mults[i] == maxmult) {
- longhaul_setstate(i);
+ longhaul_setstate(policy, i);
break;
}
}
+ cpufreq_cpu_put(policy);
cpufreq_unregister_driver(&longhaul_driver);
kfree(longhaul_table);
}
diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index 3237c5235f9c..84889573b566 100644
--- a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -61,9 +61,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs;
unsigned int freq;
- if (!cpu_online(cpu))
- return -ENODEV;
-
cpus_allowed = current->cpus_allowed;
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -80,7 +77,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
- freqs.cpu = cpu;
freqs.old = loongson2_cpufreq_get(cpu);
freqs.new = freq;
freqs.flags = 0;
@@ -89,7 +85,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
return 0;
/* notifiers */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed);
@@ -97,7 +93,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
clk_set_rate(cpuclk, freq);
/* notifiers */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: set frequency %u kHz\n", freq);
@@ -110,9 +106,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
unsigned long rate;
int ret;
- if (!cpu_online(policy->cpu))
- return -ENODEV;
-
cpuclk = clk_get(NULL, "cpu_clk");
if (IS_ERR(cpuclk)) {
printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c
index d4c4989823dc..cdd62915efaf 100644
--- a/drivers/cpufreq/maple-cpufreq.c
+++ b/drivers/cpufreq/maple-cpufreq.c
@@ -158,11 +158,10 @@ static int maple_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = maple_cpu_freqs[maple_pmode_cur].frequency;
freqs.new = maple_cpu_freqs[newstate].frequency;
- freqs.cpu = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
rc = maple_scom_switch_freq(newstate);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&maple_switch_mutex);
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 9128c07bafba..0279d18a57f9 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -25,6 +25,7 @@
#include <linux/opp.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <asm/smp_plat.h>
@@ -88,16 +89,12 @@ static int omap_target(struct cpufreq_policy *policy,
}
freqs.old = omap_getspeed(policy->cpu);
- freqs.cpu = policy->cpu;
if (freqs.old == freqs.new && policy->cur == freqs.new)
return ret;
/* notifiers */
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
freq = freqs.new * 1000;
ret = clk_round_rate(mpu_clk, freq);
@@ -157,10 +154,7 @@ static int omap_target(struct cpufreq_policy *policy,
done:
/* notifiers */
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
}
@@ -184,7 +178,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
goto fail_ck;
}
- policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
+ policy->cur = omap_getspeed(policy->cpu);
if (!freq_table)
result = opp_init_cpufreq_table(mpu_dev, &freq_table);
@@ -203,8 +197,6 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
policy->cur = omap_getspeed(policy->cpu);
/*
@@ -252,7 +244,7 @@ static struct cpufreq_driver omap_driver = {
.attr = omap_cpufreq_attr,
};
-static int __init omap_cpufreq_init(void)
+static int omap_cpufreq_probe(struct platform_device *pdev)
{
mpu_dev = get_cpu_device(0);
if (!mpu_dev) {
@@ -280,12 +272,20 @@ static int __init omap_cpufreq_init(void)
return cpufreq_register_driver(&omap_driver);
}
-static void __exit omap_cpufreq_exit(void)
+static int omap_cpufreq_remove(struct platform_device *pdev)
{
- cpufreq_unregister_driver(&omap_driver);
+ return cpufreq_unregister_driver(&omap_driver);
}
+static struct platform_driver omap_cpufreq_platdrv = {
+ .driver = {
+ .name = "omap-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_cpufreq_probe,
+ .remove = omap_cpufreq_remove,
+};
+module_platform_driver(omap_cpufreq_platdrv);
+
MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
MODULE_LICENSE("GPL");
-module_init(omap_cpufreq_init);
-module_exit(omap_cpufreq_exit);
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 827629c9aad7..421ef37d0bb3 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -58,8 +58,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
{
u32 l, h;
- if (!cpu_online(cpu) ||
- (newstate > DC_DISABLE) || (newstate == DC_RESV))
+ if ((newstate > DC_DISABLE) || (newstate == DC_RESV))
return -EINVAL;
rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
@@ -125,10 +124,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
return 0;
/* notifiers */
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* run on each logical CPU,
* see section 13.15.3 of IA32 Intel Architecture Software
@@ -138,10 +134,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
/* notifiers */
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 503996a94a6a..0de00081a81e 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -215,8 +215,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
(pcch_virt_addr + pcc_cpu_data->input_offset));
freqs.new = target_freq;
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
input_buffer = 0x1 | (((target_freq * 100)
/ (ioread32(&pcch_hdr->nominal) * 1000)) << 8);
@@ -237,7 +236,7 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
}
iowrite16(0, &pcch_hdr->status);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
spin_unlock(&pcc_lock);
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index af23e0b9ec92..ea0222a45b7b 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -68,7 +68,8 @@ static int powernow_k6_get_cpu_multiplier(void)
*
* Tries to change the PowerNow! multiplier
*/
-static void powernow_k6_set_state(unsigned int best_i)
+static void powernow_k6_set_state(struct cpufreq_policy *policy,
+ unsigned int best_i)
{
unsigned long outvalue = 0, invalue = 0;
unsigned long msrval;
@@ -81,9 +82,8 @@ static void powernow_k6_set_state(unsigned int best_i)
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
freqs.new = busfreq * clock_ratio[best_i].index;
- freqs.cpu = 0; /* powernow-k6.c is UP only driver */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* we now need to transform best_i to the BVC format, see AMD#23446 */
@@ -98,7 +98,7 @@ static void powernow_k6_set_state(unsigned int best_i)
msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return;
}
@@ -136,7 +136,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
target_freq, relation, &newstate))
return -EINVAL;
- powernow_k6_set_state(newstate);
+ powernow_k6_set_state(policy, newstate);
return 0;
}
@@ -182,7 +182,7 @@ static int powernow_k6_cpu_exit(struct cpufreq_policy *policy)
unsigned int i;
for (i = 0; i < 8; i++) {
if (i == max_multiplier)
- powernow_k6_set_state(i);
+ powernow_k6_set_state(policy, i);
}
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 334cc2f1e9f1..53888dacbe58 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -248,7 +248,7 @@ static void change_VID(int vid)
}
-static void change_speed(unsigned int index)
+static void change_speed(struct cpufreq_policy *policy, unsigned int index)
{
u8 fid, vid;
struct cpufreq_freqs freqs;
@@ -263,15 +263,13 @@ static void change_speed(unsigned int index)
fid = powernow_table[index].index & 0xFF;
vid = (powernow_table[index].index & 0xFF00) >> 8;
- freqs.cpu = 0;
-
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID;
freqs.old = fsb * fid_codes[cfid] / 10;
freqs.new = powernow_table[index].frequency;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Now do the magic poking into the MSRs. */
@@ -292,7 +290,7 @@ static void change_speed(unsigned int index)
if (have_a0 == 1)
local_irq_enable();
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
}
@@ -546,7 +544,7 @@ static int powernow_target(struct cpufreq_policy *policy,
relation, &newstate))
return -EINVAL;
- change_speed(newstate);
+ change_speed(policy, newstate);
return 0;
}
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index d13a13678b5f..b828efe4b2f8 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -928,9 +928,10 @@ static int get_transition_latency(struct powernow_k8_data *data)
static int transition_frequency_fidvid(struct powernow_k8_data *data,
unsigned int index)
{
+ struct cpufreq_policy *policy;
u32 fid = 0;
u32 vid = 0;
- int res, i;
+ int res;
struct cpufreq_freqs freqs;
pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
@@ -959,10 +960,10 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
freqs.old = find_khz_freq_from_fid(data->currfid);
freqs.new = find_khz_freq_from_fid(fid);
- for_each_cpu(i, data->available_cores) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ policy = cpufreq_cpu_get(smp_processor_id());
+ cpufreq_cpu_put(policy);
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
res = transition_fid_vid(data, fid, vid);
if (res)
@@ -970,10 +971,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
freqs.new = find_khz_freq_from_fid(data->currfid);
- for_each_cpu(i, data->available_cores) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return res;
}
@@ -1104,9 +1102,6 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
struct init_on_cpu init_on_cpu;
int rc;
- if (!cpu_online(pol->cpu))
- return -ENODEV;
-
smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
if (rc)
return -ENODEV;
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index d4c39e32f147..e577a1dbbfcd 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -27,7 +27,8 @@
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/cell-regs.h>
-#include "cbe_cpufreq.h"
+
+#include "ppc_cbe_cpufreq.h"
static DEFINE_MUTEX(cbe_switch_mutex);
@@ -156,10 +157,9 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = cbe_freqs[cbe_pmode_new].frequency;
- freqs.cpu = policy->cpu;
mutex_lock(&cbe_switch_mutex);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, " \
"1/%d of max frequency\n",
@@ -169,7 +169,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy,
rc = set_pmode(policy->cpu, cbe_pmode_new);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&cbe_switch_mutex);
return rc;
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/drivers/cpufreq/ppc_cbe_cpufreq.h
index c1d86bfa92ff..b4c00a5a6a59 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.h
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.h
@@ -1,5 +1,5 @@
/*
- * cbe_cpufreq.h
+ * ppc_cbe_cpufreq.h
*
* This file contains the definitions used by the cbe_cpufreq driver.
*
@@ -17,7 +17,7 @@ int cbe_cpufreq_get_pmode(int cpu);
int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
-#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE)
+#if defined(CONFIG_CPU_FREQ_CBE_PMI) || defined(CONFIG_CPU_FREQ_CBE_PMI_MODULE)
extern bool cbe_cpufreq_has_pmi;
#else
#define cbe_cpufreq_has_pmi (0)
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/drivers/cpufreq/ppc_cbe_cpufreq_pervasive.c
index 20472e487b6f..84d2f2cf5ba7 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq_pervasive.c
@@ -30,7 +30,7 @@
#include <asm/hw_irq.h>
#include <asm/cell-regs.h>
-#include "cbe_cpufreq.h"
+#include "ppc_cbe_cpufreq.h"
/* to write to MIC register */
static u64 MIC_Slow_Fast_Timer_table[] = {
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
index 60a07a4f9326..d29e8da396a0 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c
@@ -35,7 +35,7 @@
#include <asm/time.h>
#endif
-#include "cbe_cpufreq.h"
+#include "ppc_cbe_cpufreq.h"
static u8 pmi_slow_mode_limit[MAX_CBE];
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index 6a7aeab42f6c..9e5bc8e388a0 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-pxa/cpufreq-pxa2xx.c
- *
* Copyright (C) 2002,2003 Intrinsyc Software
*
* This program is free software; you can redistribute it and/or modify
@@ -223,10 +221,11 @@ static void find_freq_tables(struct cpufreq_frequency_table **freq_table,
*pxa_freqs = pxa255_turbo_freqs;
*freq_table = pxa255_turbo_freq_table;
}
- }
- if (cpu_is_pxa27x()) {
+ } else if (cpu_is_pxa27x()) {
*pxa_freqs = pxa27x_freqs;
*freq_table = pxa27x_freq_table;
+ } else {
+ BUG();
}
}
@@ -311,7 +310,6 @@ static int pxa_set_target(struct cpufreq_policy *policy,
new_freq_mem = pxa_freq_settings[idx].membus;
freqs.old = policy->cur;
freqs.new = new_freq_cpu;
- freqs.cpu = policy->cpu;
if (freq_debug)
pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n",
@@ -327,7 +325,7 @@ static int pxa_set_target(struct cpufreq_policy *policy,
* you should add a notify client with any platform specific
* Vcc changing capability
*/
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Calculate the next MDREFR. If we're slowing down the SDRAM clock
* we need to preset the smaller DRI before the change. If we're
@@ -382,7 +380,7 @@ static int pxa_set_target(struct cpufreq_policy *policy,
* you should add a notify client with any platform specific
* SDRAM refresh timer adjustments
*/
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
/*
* Even if voltage setting fails, we don't report it, as the frequency
diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index b85b4ab7aac6..15d60f857ad5 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa3xx.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/arm/mach-pxa/cpufreq-pxa3xx.c
- *
* Copyright (C) 2008 Marvell International Ltd.
*
* This program is free software; you can redistribute it and/or modify
@@ -17,10 +15,9 @@
#include <linux/slab.h>
#include <linux/io.h>
+#include <mach/generic.h>
#include <mach/pxa3xx-regs.h>
-#include "generic.h"
-
#define HSS_104M (0)
#define HSS_156M (1)
#define HSS_208M (2)
@@ -184,7 +181,6 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
freqs.old = policy->cur;
freqs.new = next->cpufreq_mhz * 1000;
- freqs.cpu = policy->cpu;
pr_debug("CPU frequency from %d MHz to %d MHz%s\n",
freqs.old / 1000, freqs.new / 1000,
@@ -193,14 +189,14 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
if (freqs.old == target_freq)
return 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_save(flags);
__update_core_freq(next);
__update_bus_freq(next);
local_irq_restore(flags);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index bcc053bc02c4..4f1881eee3f1 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -256,7 +256,6 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
goto out;
}
- freqs.cpu = 0;
freqs.flags = 0;
freqs.old = s3c_freq->is_dvs ? FREQ_DVS
: clk_get_rate(s3c_freq->armclk) / 1000;
@@ -274,7 +273,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
if (!to_dvs && freqs.old == freqs.new)
goto out;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (to_dvs) {
pr_debug("cpufreq: enter dvs\n");
@@ -287,7 +286,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
out:
mutex_unlock(&cpufreq_lock);
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 6f9490b3c356..27cacb524796 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -84,7 +84,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret != 0)
return ret;
- freqs.cpu = 0;
freqs.old = clk_get_rate(armclk) / 1000;
freqs.new = s3c64xx_freq_table[i].frequency;
freqs.flags = 0;
@@ -95,7 +94,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifdef CONFIG_REGULATOR
if (vddarm && freqs.new > freqs.old) {
@@ -117,7 +116,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
goto err;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
#ifdef CONFIG_REGULATOR
if (vddarm && freqs.new < freqs.old) {
@@ -141,7 +140,7 @@ err_clk:
if (clk_set_rate(armclk, freqs.old * 1000) < 0)
pr_err("Failed to restore original clock rate\n");
err:
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
}
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index a484aaea9809..5c7757073793 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -229,7 +229,6 @@ static int s5pv210_target(struct cpufreq_policy *policy,
}
freqs.new = s5pv210_freq_table[index].frequency;
- freqs.cpu = 0;
if (freqs.new == freqs.old)
goto exit;
@@ -256,7 +255,7 @@ static int s5pv210_target(struct cpufreq_policy *policy,
goto exit;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Check if there need to change PLL */
if ((index == L0) || (priv_index == L0))
@@ -468,7 +467,7 @@ static int s5pv210_target(struct cpufreq_policy *policy,
}
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (freqs.new < freqs.old) {
regulator_set_voltage(int_regulator,
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/drivers/cpufreq/sa1100-cpufreq.c
index e8f4d1e19233..cff18e87ca58 100644
--- a/arch/arm/mach-sa1100/cpu-sa1100.c
+++ b/drivers/cpufreq/sa1100-cpufreq.c
@@ -91,10 +91,9 @@
#include <asm/cputype.h>
+#include <mach/generic.h>
#include <mach/hardware.h>
-#include "generic.h"
-
struct sa1100_dram_regs {
int speed;
u32 mdcnfg;
@@ -201,9 +200,8 @@ static int sa1100_target(struct cpufreq_policy *policy,
freqs.old = cur;
freqs.new = sa11x0_ppcr_to_freq(new_ppcr);
- freqs.cpu = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (freqs.new > cur)
sa1100_update_dram_timings(cur, freqs.new);
@@ -213,7 +211,7 @@ static int sa1100_target(struct cpufreq_policy *policy,
if (freqs.new < cur)
sa1100_update_dram_timings(cur, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/drivers/cpufreq/sa1110-cpufreq.c
index 48c45b0c92bb..39c90b6f4286 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/drivers/cpufreq/sa1110-cpufreq.c
@@ -27,10 +27,9 @@
#include <asm/cputype.h>
#include <asm/mach-types.h>
+#include <mach/generic.h>
#include <mach/hardware.h>
-#include "generic.h"
-
#undef DEBUG
struct sdram_params {
@@ -258,7 +257,6 @@ static int sa1110_target(struct cpufreq_policy *policy,
freqs.old = sa11x0_getspeed(0);
freqs.new = sa11x0_ppcr_to_freq(ppcr);
- freqs.cpu = 0;
sdram_calculate_timing(&sd, freqs.new, sdram);
@@ -279,7 +277,7 @@ static int sa1110_target(struct cpufreq_policy *policy,
sd.mdcas[2] = 0xaaaaaaaa;
#endif
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/*
* The clock could be going away for some time. Set the SDRAMs
@@ -327,7 +325,7 @@ static int sa1110_target(struct cpufreq_policy *policy,
*/
sdram_update_refresh(freqs.new, sdram);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index e42e073cd9b8..f740b134d27b 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -53,7 +53,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
}
}
-static void sc520_freq_set_cpu_state(unsigned int state)
+static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy,
+ unsigned int state)
{
struct cpufreq_freqs freqs;
@@ -61,9 +62,8 @@ static void sc520_freq_set_cpu_state(unsigned int state)
freqs.old = sc520_freq_get_cpu_frequency(0);
freqs.new = sc520_freq_table[state].frequency;
- freqs.cpu = 0; /* AMD Elan is UP */
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("attempting to set frequency to %i kHz\n",
sc520_freq_table[state].frequency);
@@ -75,7 +75,7 @@ static void sc520_freq_set_cpu_state(unsigned int state)
local_irq_enable();
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
};
static int sc520_freq_verify(struct cpufreq_policy *policy)
@@ -93,7 +93,7 @@ static int sc520_freq_target(struct cpufreq_policy *policy,
target_freq, relation, &newstate))
return -EINVAL;
- sc520_freq_set_cpu_state(newstate);
+ sc520_freq_set_cpu_state(policy, newstate);
return 0;
}
diff --git a/arch/sh/kernel/cpufreq.c b/drivers/cpufreq/sh-cpufreq.c
index e68b45b6f3f9..73adb64651e8 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/drivers/cpufreq/sh-cpufreq.c
@@ -1,6 +1,4 @@
/*
- * arch/sh/kernel/cpufreq.c
- *
* cpufreq driver for the SuperH processors.
*
* Copyright (C) 2002 - 2012 Paul Mundt
@@ -51,9 +49,6 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
struct device *dev;
long freq;
- if (!cpu_online(cpu))
- return -ENODEV;
-
cpus_allowed = current->cpus_allowed;
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -69,15 +64,14 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy,
dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000);
- freqs.cpu = cpu;
freqs.old = sh_cpufreq_get(cpu);
freqs.new = (freq + 500) / 1000;
freqs.flags = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed);
clk_set_rate(cpuclk, freq);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
dev_dbg(dev, "set frequency %lu Hz\n", freq);
@@ -112,9 +106,6 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
struct cpufreq_frequency_table *freq_table;
struct device *dev;
- if (!cpu_online(cpu))
- return -ENODEV;
-
dev = get_cpu_device(cpu);
cpuclk = clk_get(dev, "cpu_clk");
@@ -123,7 +114,7 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
return PTR_ERR(cpuclk);
}
- policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu);
+ policy->cur = sh_cpufreq_get(cpu);
freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
if (freq_table) {
@@ -136,15 +127,12 @@ static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
dev_notice(dev, "no frequency table found, falling back "
"to rate rounding.\n");
- policy->cpuinfo.min_freq =
+ policy->min = policy->cpuinfo.min_freq =
(clk_round_rate(cpuclk, 1) + 500) / 1000;
- policy->cpuinfo.max_freq =
+ policy->max = policy->cpuinfo.max_freq =
(clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
}
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
-
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, "
diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 489fc15f3194..306ae462bba6 100644
--- a/arch/sparc/kernel/us2e_cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -234,9 +234,6 @@ static unsigned int us2e_freq_get(unsigned int cpu)
cpumask_t cpus_allowed;
unsigned long clock_tick, estar;
- if (!cpu_online(cpu))
- return 0;
-
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -248,16 +245,15 @@ static unsigned int us2e_freq_get(unsigned int cpu)
return clock_tick / estar_to_divisor(estar);
}
-static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+static void us2e_set_cpu_divider_index(struct cpufreq_policy *policy,
+ unsigned int index)
{
+ unsigned int cpu = policy->cpu;
unsigned long new_bits, new_freq;
unsigned long clock_tick, divisor, old_divisor, estar;
cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
- if (!cpu_online(cpu))
- return;
-
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -272,14 +268,13 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index)
freqs.old = clock_tick / old_divisor;
freqs.new = new_freq;
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor)
us2e_transition(estar, new_bits, clock_tick * 1000,
old_divisor, divisor);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed);
}
@@ -295,7 +290,7 @@ static int us2e_freq_target(struct cpufreq_policy *policy,
target_freq, relation, &new_index))
return -EINVAL;
- us2e_set_cpu_divider_index(policy->cpu, new_index);
+ us2e_set_cpu_divider_index(policy, new_index);
return 0;
}
@@ -335,7 +330,7 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
static int us2e_freq_cpu_exit(struct cpufreq_policy *policy)
{
if (cpufreq_us2e_driver)
- us2e_set_cpu_divider_index(policy->cpu, 0);
+ us2e_set_cpu_divider_index(policy, 0);
return 0;
}
diff --git a/arch/sparc/kernel/us3_cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index eb1624b931d9..c71ee142347a 100644
--- a/arch/sparc/kernel/us3_cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -82,9 +82,6 @@ static unsigned int us3_freq_get(unsigned int cpu)
unsigned long reg;
unsigned int ret;
- if (!cpu_online(cpu))
- return 0;
-
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -96,15 +93,14 @@ static unsigned int us3_freq_get(unsigned int cpu)
return ret;
}
-static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
+static void us3_set_cpu_divider_index(struct cpufreq_policy *policy,
+ unsigned int index)
{
+ unsigned int cpu = policy->cpu;
unsigned long new_bits, new_freq, reg;
cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
- if (!cpu_online(cpu))
- return;
-
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -131,14 +127,13 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
freqs.old = get_current_freq(cpu, reg);
freqs.new = new_freq;
- freqs.cpu = cpu;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
reg &= ~SAFARI_CFG_DIV_MASK;
reg |= new_bits;
write_safari_cfg(reg);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed);
}
@@ -156,7 +151,7 @@ static int us3_freq_target(struct cpufreq_policy *policy,
&new_index))
return -EINVAL;
- us3_set_cpu_divider_index(policy->cpu, new_index);
+ us3_set_cpu_divider_index(policy, new_index);
return 0;
}
@@ -192,7 +187,7 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
{
if (cpufreq_us3_driver)
- us3_set_cpu_divider_index(policy->cpu, 0);
+ us3_set_cpu_divider_index(policy, 0);
return 0;
}
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 7e4d77327957..156829f4576d 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -121,7 +121,6 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
target_freq, relation, &index))
return -EINVAL;
- freqs.cpu = policy->cpu;
freqs.old = spear_cpufreq_get(0);
newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000;
@@ -158,8 +157,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = newfreq / 1000;
freqs.new /= mult;
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (mult == 2)
ret = spear1340_set_cpu_rate(srcclk, newfreq);
@@ -172,8 +170,7 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
}
- for_each_cpu(freqs.cpu, policy->cpus)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
}
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 3a953d519f46..618e6f417b1c 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -457,7 +457,7 @@ static int centrino_target (struct cpufreq_policy *policy,
unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu;
struct cpufreq_freqs freqs;
int retval = 0;
- unsigned int j, k, first_cpu, tmp;
+ unsigned int j, first_cpu, tmp;
cpumask_var_t covered_cpus;
if (unlikely(!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)))
@@ -481,10 +481,6 @@ static int centrino_target (struct cpufreq_policy *policy,
for_each_cpu(j, policy->cpus) {
int good_cpu;
- /* cpufreq holds the hotplug lock, so we are safe here */
- if (!cpu_online(j))
- continue;
-
/*
* Support for SMP systems.
* Make sure we are running on CPU that wants to change freq
@@ -522,13 +518,8 @@ static int centrino_target (struct cpufreq_policy *policy,
pr_debug("target=%dkHz old=%d new=%d msr=%04x\n",
target_freq, freqs.old, freqs.new, msr);
- for_each_cpu(k, policy->cpus) {
- if (!cpu_online(k))
- continue;
- freqs.cpu = k;
- cpufreq_notify_transition(&freqs,
+ cpufreq_notify_transition(policy, &freqs,
CPUFREQ_PRECHANGE);
- }
first_cpu = 0;
/* all but 16 LSB are reserved, treat them with care */
@@ -544,12 +535,7 @@ static int centrino_target (struct cpufreq_policy *policy,
cpumask_set_cpu(j, covered_cpus);
}
- for_each_cpu(k, policy->cpus) {
- if (!cpu_online(k))
- continue;
- freqs.cpu = k;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (unlikely(retval)) {
/*
@@ -565,12 +551,8 @@ static int centrino_target (struct cpufreq_policy *policy,
tmp = freqs.new;
freqs.new = freqs.old;
freqs.old = tmp;
- for_each_cpu(j, policy->cpus) {
- if (!cpu_online(j))
- continue;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
}
retval = 0;
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index e29b59aa68a8..e2e5aa971452 100644
--- a/drivers/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -263,7 +263,6 @@ static int speedstep_target(struct cpufreq_policy *policy,
{
unsigned int newstate = 0, policy_cpu;
struct cpufreq_freqs freqs;
- int i;
if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0],
target_freq, relation, &newstate))
@@ -272,7 +271,6 @@ static int speedstep_target(struct cpufreq_policy *policy,
policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask);
freqs.old = speedstep_get(policy_cpu);
freqs.new = speedstep_freqs[newstate].frequency;
- freqs.cpu = policy->cpu;
pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new);
@@ -280,18 +278,12 @@ static int speedstep_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return 0;
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
smp_call_function_single(policy_cpu, _speedstep_set_state, &newstate,
true);
- for_each_cpu(i, policy->cpus) {
- freqs.cpu = i;
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- }
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index 6a457fcaaad5..f5a6b70ee6c0 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -252,14 +252,13 @@ static int speedstep_target(struct cpufreq_policy *policy,
freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
freqs.new = speedstep_freqs[newstate].frequency;
- freqs.cpu = 0; /* speedstep.c is UP only driver */
if (freqs.old == freqs.new)
return 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
speedstep_set_state(newstate);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/drivers/cpufreq/tegra-cpufreq.c
index e3d6e15ff188..c74c0e130ef4 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-tegra/cpu-tegra.c
- *
* Copyright (C) 2010 Google, Inc.
*
* Author:
@@ -106,7 +104,8 @@ out:
return ret;
}
-static int tegra_update_cpu_speed(unsigned long rate)
+static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
+ unsigned long rate)
{
int ret = 0;
struct cpufreq_freqs freqs;
@@ -128,8 +127,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
else
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifdef CONFIG_CPU_FREQ_DEBUG
printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
@@ -143,8 +141,7 @@ static int tegra_update_cpu_speed(unsigned long rate)
return ret;
}
- for_each_online_cpu(freqs.cpu)
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
@@ -181,7 +178,7 @@ static int tegra_target(struct cpufreq_policy *policy,
target_cpu_speed[policy->cpu] = freq;
- ret = tegra_update_cpu_speed(tegra_cpu_highest_speed());
+ ret = tegra_update_cpu_speed(policy, tegra_cpu_highest_speed());
out:
mutex_unlock(&tegra_cpu_lock);
@@ -193,10 +190,12 @@ static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
{
mutex_lock(&tegra_cpu_lock);
if (event == PM_SUSPEND_PREPARE) {
+ struct cpufreq_policy *policy = cpufreq_cpu_get(0);
is_suspended = true;
pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
freq_table[0].frequency);
- tegra_update_cpu_speed(freq_table[0].frequency);
+ tegra_update_cpu_speed(policy, freq_table[0].frequency);
+ cpufreq_cpu_put(policy);
} else if (event == PM_POST_SUSPEND) {
is_suspended = false;
}
diff --git a/arch/unicore32/kernel/cpu-ucv2.c b/drivers/cpufreq/unicore2-cpufreq.c
index 4a99f62584c7..12fc904d7dab 100644
--- a/arch/unicore32/kernel/cpu-ucv2.c
+++ b/drivers/cpufreq/unicore2-cpufreq.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/unicore32/kernel/cpu-ucv2.c: clock scaling for the UniCore-II
+ * clock scaling for the UniCore-II
*
* Code specific to PKUnity SoC and UniCore ISA
*
@@ -52,15 +52,14 @@ static int ucv2_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs;
struct clk *mclk = clk_get(NULL, "MAIN_CLK");
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (!clk_set_rate(mclk, target_freq * 1000)) {
freqs.old = cur;
freqs.new = target_freq;
- freqs.cpu = 0;
}
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0;
}
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 071e2c3eec4f..c4cc27e5c8a5 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -39,10 +39,4 @@ config CPU_IDLE_CALXEDA
help
Select this to enable cpuidle on Calxeda processors.
-config CPU_IDLE_KIRKWOOD
- bool "CPU Idle Driver for Kirkwood processors"
- depends on ARCH_KIRKWOOD
- help
- Select this to enable cpuidle on Kirkwood processors.
-
endif
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 24c6e7d945ed..0d8bd55e776f 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -6,4 +6,4 @@ obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
-obj-$(CONFIG_CPU_IDLE_KIRKWOOD) += cpuidle-kirkwood.o
+obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
index e1aab38c5a8d..223379169cb0 100644
--- a/drivers/cpuidle/cpuidle-calxeda.c
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -1,7 +1,7 @@
/*
* Copyright 2012 Calxeda, Inc.
*
- * Based on arch/arm/plat-mxc/cpuidle.c:
+ * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7
* Copyright 2012 Freescale Semiconductor, Inc.
* Copyright 2012 Linaro Ltd.
*
@@ -16,6 +16,8 @@
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Maintainer: Rob Herring <rob.herring@calxeda.com>
*/
#include <linux/cpuidle.h>
@@ -35,8 +37,6 @@
extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
extern void *scu_base_addr;
-static struct cpuidle_device __percpu *calxeda_idle_cpuidle_devices;
-
static inline unsigned int get_auxcr(void)
{
unsigned int val;
@@ -85,22 +85,8 @@ static int calxeda_pwrdown_idle(struct cpuidle_device *dev,
return index;
}
-static void calxeda_idle_cpuidle_devices_uninit(void)
-{
- int i;
- struct cpuidle_device *dev;
-
- for_each_possible_cpu(i) {
- dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, i);
- cpuidle_unregister_device(dev);
- }
-
- free_percpu(calxeda_idle_cpuidle_devices);
-}
-
static struct cpuidle_driver calxeda_idle_driver = {
.name = "calxeda_idle",
- .en_core_tk_irqen = 1,
.states = {
ARM_CPUIDLE_WFI_STATE,
{
@@ -118,44 +104,9 @@ static struct cpuidle_driver calxeda_idle_driver = {
static int __init calxeda_cpuidle_init(void)
{
- int cpu_id;
- int ret;
- struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &calxeda_idle_driver;
-
if (!of_machine_is_compatible("calxeda,highbank"))
return -ENODEV;
- ret = cpuidle_register_driver(drv);
- if (ret)
- return ret;
-
- calxeda_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device);
- if (calxeda_idle_cpuidle_devices == NULL) {
- ret = -ENOMEM;
- goto unregister_drv;
- }
-
- /* initialize state data for each cpuidle_device */
- for_each_possible_cpu(cpu_id) {
- dev = per_cpu_ptr(calxeda_idle_cpuidle_devices, cpu_id);
- dev->cpu = cpu_id;
- dev->state_count = drv->state_count;
-
- ret = cpuidle_register_device(dev);
- if (ret) {
- pr_err("Failed to register cpu %u, error: %d\n",
- cpu_id, ret);
- goto uninit;
- }
- }
-
- return 0;
-
-uninit:
- calxeda_idle_cpuidle_devices_uninit();
-unregister_drv:
- cpuidle_unregister_driver(drv);
- return ret;
+ return cpuidle_register(&calxeda_idle_driver, NULL);
}
module_init(calxeda_cpuidle_init);
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c
index 670aa1e55cd6..521b0a7fdd89 100644
--- a/drivers/cpuidle/cpuidle-kirkwood.c
+++ b/drivers/cpuidle/cpuidle-kirkwood.c
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-kirkwood/cpuidle.c
- *
* CPU idle Marvell Kirkwood SoCs
*
* This file is licensed under the terms of the GNU General Public
@@ -11,6 +9,9 @@
* to implement two idle states -
* #1 wait-for-interrupt
* #2 wait-for-interrupt and DDR self refresh
+ *
+ * Maintainer: Jason Cooper <jason@lakedaemon.net>
+ * Maintainer: Andrew Lunn <andrew@lunn.ch>
*/
#include <linux/kernel.h>
@@ -41,7 +42,6 @@ static int kirkwood_enter_idle(struct cpuidle_device *dev,
static struct cpuidle_driver kirkwood_idle_driver = {
.name = "kirkwood_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
.states[0] = ARM_CPUIDLE_WFI_STATE,
.states[1] = {
.enter = kirkwood_enter_idle,
@@ -53,9 +53,6 @@ static struct cpuidle_driver kirkwood_idle_driver = {
},
.state_count = KIRKWOOD_MAX_STATES,
};
-static struct cpuidle_device *device;
-
-static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
/* Initialize CPU idle by registering the idle states */
static int kirkwood_cpuidle_probe(struct platform_device *pdev)
@@ -66,26 +63,16 @@ static int kirkwood_cpuidle_probe(struct platform_device *pdev)
if (res == NULL)
return -EINVAL;
- ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!ddr_operation_base)
- return -EADDRNOTAVAIL;
+ ddr_operation_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ddr_operation_base))
+ return PTR_ERR(ddr_operation_base);
- device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
- device->state_count = KIRKWOOD_MAX_STATES;
-
- cpuidle_register_driver(&kirkwood_idle_driver);
- if (cpuidle_register_device(device)) {
- pr_err("kirkwood_init_cpuidle: Failed registering\n");
- return -EIO;
- }
- return 0;
+ return cpuidle_register(&kirkwood_idle_driver, NULL);
}
int kirkwood_cpuidle_remove(struct platform_device *pdev)
{
- cpuidle_unregister_device(device);
- cpuidle_unregister_driver(&kirkwood_idle_driver);
-
+ cpuidle_unregister(&kirkwood_idle_driver);
return 0;
}
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index eba69290e074..c3a93fece819 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -8,6 +8,7 @@
* This code is licenced under the GPL.
*/
+#include <linux/clockchips.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/sched.h>
@@ -23,6 +24,7 @@
#include "cpuidle.h"
DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device, cpuidle_dev);
DEFINE_MUTEX(cpuidle_lock);
LIST_HEAD(cpuidle_detected_devices);
@@ -42,24 +44,6 @@ void disable_cpuidle(void)
static int __cpuidle_register_device(struct cpuidle_device *dev);
-static inline int cpuidle_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
-{
- struct cpuidle_state *target_state = &drv->states[index];
- return target_state->enter(dev, drv, index);
-}
-
-static inline int cpuidle_enter_tk(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
-{
- return cpuidle_wrap_enter(dev, drv, index, cpuidle_enter);
-}
-
-typedef int (*cpuidle_enter_t)(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index);
-
-static cpuidle_enter_t cpuidle_enter_ops;
-
/**
* cpuidle_play_dead - cpu off-lining
*
@@ -89,11 +73,27 @@ int cpuidle_play_dead(void)
* @next_state: index into drv->states of the state to enter
*/
int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
- int next_state)
+ int index)
{
int entered_state;
- entered_state = cpuidle_enter_ops(dev, drv, next_state);
+ struct cpuidle_state *target_state = &drv->states[index];
+ ktime_t time_start, time_end;
+ s64 diff;
+
+ time_start = ktime_get();
+
+ entered_state = target_state->enter(dev, drv, index);
+
+ time_end = ktime_get();
+
+ local_irq_enable();
+
+ diff = ktime_to_us(ktime_sub(time_end, time_start));
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ dev->last_residency = (int) diff;
if (entered_state >= 0) {
/* Update cpuidle counters */
@@ -146,12 +146,20 @@ int cpuidle_idle_call(void)
trace_cpu_idle_rcuidle(next_state, dev->cpu);
+ if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP)
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ &dev->cpu);
+
if (cpuidle_state_is_coupled(dev, drv, next_state))
entered_state = cpuidle_enter_state_coupled(dev, drv,
next_state);
else
entered_state = cpuidle_enter_state(dev, drv, next_state);
+ if (drv->states[next_state].flags & CPUIDLE_FLAG_TIMER_STOP)
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ &dev->cpu);
+
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, dev->cpu);
/* give the governor an opportunity to reflect on the outcome */
@@ -222,37 +230,6 @@ void cpuidle_resume(void)
mutex_unlock(&cpuidle_lock);
}
-/**
- * cpuidle_wrap_enter - performs timekeeping and irqen around enter function
- * @dev: pointer to a valid cpuidle_device object
- * @drv: pointer to a valid cpuidle_driver object
- * @index: index of the target cpuidle state.
- */
-int cpuidle_wrap_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index,
- int (*enter)(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index))
-{
- ktime_t time_start, time_end;
- s64 diff;
-
- time_start = ktime_get();
-
- index = enter(dev, drv, index);
-
- time_end = ktime_get();
-
- local_irq_enable();
-
- diff = ktime_to_us(ktime_sub(time_end, time_start));
- if (diff > INT_MAX)
- diff = INT_MAX;
-
- dev->last_residency = (int) diff;
-
- return index;
-}
-
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
static int poll_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
@@ -324,9 +301,6 @@ int cpuidle_enable_device(struct cpuidle_device *dev)
return ret;
}
- cpuidle_enter_ops = drv->en_core_tk_irqen ?
- cpuidle_enter_tk : cpuidle_enter;
-
poll_idle_init(drv);
ret = cpuidle_add_device_sysfs(dev);
@@ -480,6 +454,77 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
+/**
+ * cpuidle_unregister: unregister a driver and the devices. This function
+ * can be used only if the driver has been previously registered through
+ * the cpuidle_register function.
+ *
+ * @drv: a valid pointer to a struct cpuidle_driver
+ */
+void cpuidle_unregister(struct cpuidle_driver *drv)
+{
+ int cpu;
+ struct cpuidle_device *device;
+
+ for_each_possible_cpu(cpu) {
+ device = &per_cpu(cpuidle_dev, cpu);
+ cpuidle_unregister_device(device);
+ }
+
+ cpuidle_unregister_driver(drv);
+}
+EXPORT_SYMBOL_GPL(cpuidle_unregister);
+
+/**
+ * cpuidle_register: registers the driver and the cpu devices with the
+ * coupled_cpus passed as parameter. This function is used for all common
+ * initialization pattern there are in the arch specific drivers. The
+ * devices is globally defined in this file.
+ *
+ * @drv : a valid pointer to a struct cpuidle_driver
+ * @coupled_cpus: a cpumask for the coupled states
+ *
+ * Returns 0 on success, < 0 otherwise
+ */
+int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus)
+{
+ int ret, cpu;
+ struct cpuidle_device *device;
+
+ ret = cpuidle_register_driver(drv);
+ if (ret) {
+ pr_err("failed to register cpuidle driver\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ device = &per_cpu(cpuidle_dev, cpu);
+ device->cpu = cpu;
+
+#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
+ /*
+ * On multiplatform for ARM, the coupled idle states could
+ * enabled in the kernel even if the cpuidle driver does not
+ * use it. Note, coupled_cpus is a struct copy.
+ */
+ if (coupled_cpus)
+ device->coupled_cpus = *coupled_cpus;
+#endif
+ ret = cpuidle_register_device(device);
+ if (!ret)
+ continue;
+
+ pr_err("Failed to register cpuidle device for cpu%d\n", cpu);
+
+ cpuidle_unregister(drv);
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpuidle_register);
+
#ifdef CONFIG_SMP
static void smp_callback(void *v)
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 422c7b69ba7c..8dfaaae94444 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -11,6 +11,8 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/clockchips.h>
#include "cpuidle.h"
@@ -19,9 +21,28 @@ DEFINE_SPINLOCK(cpuidle_driver_lock);
static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
-static void __cpuidle_driver_init(struct cpuidle_driver *drv)
+static void cpuidle_setup_broadcast_timer(void *arg)
{
+ int cpu = smp_processor_id();
+ clockevents_notify((long)(arg), &cpu);
+}
+
+static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu)
+{
+ int i;
+
drv->refcnt = 0;
+
+ for (i = drv->state_count - 1; i >= 0 ; i--) {
+
+ if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
+ continue;
+
+ drv->bctimer = 1;
+ on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
+ (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
+ break;
+ }
}
static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
@@ -35,7 +56,7 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
if (__cpuidle_get_cpu_driver(cpu))
return -EBUSY;
- __cpuidle_driver_init(drv);
+ __cpuidle_driver_init(drv, cpu);
__cpuidle_set_cpu_driver(drv, cpu);
@@ -49,6 +70,12 @@ static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
if (!WARN_ON(drv->refcnt > 0))
__cpuidle_set_cpu_driver(NULL, cpu);
+
+ if (drv->bctimer) {
+ drv->bctimer = 0;
+ on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
+ (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
+ }
}
#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index b2a0a0726a54..cf268b14ae9a 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1650,11 +1650,7 @@ struct caam_alg_template {
};
static struct caam_alg_template driver_algs[] = {
- /*
- * single-pass ipsec_esp descriptor
- * authencesn(*,*) is also registered, although not present
- * explicitly here.
- */
+ /* single-pass ipsec_esp descriptor */
{
.name = "authenc(hmac(md5),cbc(aes))",
.driver_name = "authenc-hmac-md5-cbc-aes-caam",
@@ -2217,9 +2213,7 @@ static int __init caam_algapi_init(void)
for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
/* TODO: check if h/w supports alg */
struct caam_crypto_alg *t_alg;
- bool done = false;
-authencesn:
t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]);
if (IS_ERR(t_alg)) {
err = PTR_ERR(t_alg);
@@ -2233,25 +2227,8 @@ authencesn:
dev_warn(ctrldev, "%s alg registration failed\n",
t_alg->crypto_alg.cra_driver_name);
kfree(t_alg);
- } else {
+ } else
list_add_tail(&t_alg->entry, &priv->alg_list);
- if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD &&
- !memcmp(driver_algs[i].name, "authenc", 7) &&
- !done) {
- char *name;
-
- name = driver_algs[i].name;
- memmove(name + 10, name + 7, strlen(name) - 7);
- memcpy(name + 7, "esn", 3);
-
- name = driver_algs[i].driver_name;
- memmove(name + 10, name + 7, strlen(name) - 7);
- memcpy(name + 7, "esn", 3);
-
- done = true;
- goto authencesn;
- }
- }
}
if (!list_empty(&priv->alg_list))
dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n",
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
index cf15e7813801..762aeff626ac 100644
--- a/drivers/crypto/caam/compat.h
+++ b/drivers/crypto/caam/compat.h
@@ -23,7 +23,6 @@
#include <linux/types.h>
#include <linux/debugfs.h>
#include <linux/circ_buf.h>
-#include <linux/string.h>
#include <net/xfrm.h>
#include <crypto/algapi.h>
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 1c56f63524f2..8acf00490fd5 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -66,7 +66,7 @@ static void build_instantiation_desc(u32 *desc)
/*
* load 1 to clear written reg:
- * resets the done interrrupt and returns the RNG to idle.
+ * resets the done interrupt and returns the RNG to idle.
*/
append_load_imm_u32(desc, 1, LDST_SRCDST_WORD_CLRW);
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 09b184adf31b..5b2b5e61e4f9 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -38,7 +38,6 @@
#include <linux/spinlock.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
-#include <linux/string.h>
#include <crypto/algapi.h>
#include <crypto/aes.h>
@@ -1974,11 +1973,7 @@ struct talitos_alg_template {
};
static struct talitos_alg_template driver_algs[] = {
- /*
- * AEAD algorithms. These use a single-pass ipsec_esp descriptor.
- * authencesn(*,*) is also registered, although not present
- * explicitly here.
- */
+ /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */
{ .type = CRYPTO_ALG_TYPE_AEAD,
.alg.crypto = {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
@@ -2820,9 +2815,7 @@ static int talitos_probe(struct platform_device *ofdev)
if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
struct talitos_crypto_alg *t_alg;
char *name = NULL;
- bool authenc = false;
-authencesn:
t_alg = talitos_alg_alloc(dev, &driver_algs[i]);
if (IS_ERR(t_alg)) {
err = PTR_ERR(t_alg);
@@ -2837,8 +2830,6 @@ authencesn:
err = crypto_register_alg(
&t_alg->algt.alg.crypto);
name = t_alg->algt.alg.crypto.cra_driver_name;
- authenc = authenc ? !authenc :
- !(bool)memcmp(name, "authenc", 7);
break;
case CRYPTO_ALG_TYPE_AHASH:
err = crypto_register_ahash(
@@ -2851,25 +2842,8 @@ authencesn:
dev_err(dev, "%s alg registration failed\n",
name);
kfree(t_alg);
- } else {
+ } else
list_add_tail(&t_alg->entry, &priv->alg_list);
- if (authenc) {
- struct crypto_alg *alg =
- &driver_algs[i].alg.crypto;
-
- name = alg->cra_name;
- memmove(name + 10, name + 7,
- strlen(name) - 7);
- memcpy(name + 7, "esn", 3);
-
- name = alg->cra_driver_name;
- memmove(name + 10, name + 7,
- strlen(name) - 7);
- memcpy(name + 7, "esn", 3);
-
- goto authencesn;
- }
- }
}
}
if (!list_empty(&priv->alg_list))
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index 8bc5fef07e7a..22c9063e0120 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -1750,7 +1750,7 @@ static struct platform_driver cryp_driver = {
.shutdown = ux500_cryp_shutdown,
.driver = {
.owner = THIS_MODULE,
- .name = "cryp1"
+ .name = "cryp1",
.pm = &ux500_cryp_pm,
}
};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 80b69971cf28..aeaea32bcfda 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -83,6 +83,7 @@ config INTEL_IOP_ADMA
config DW_DMAC
tristate "Synopsys DesignWare AHB DMA support"
+ depends on GENERIC_HARDIRQS
select DMA_ENGINE
default y if CPU_AT32AP7000
help
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 6e13f262139a..88cfc61329d2 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -310,8 +310,6 @@ static void atc_complete_all(struct at_dma_chan *atchan)
dev_vdbg(chan2dev(&atchan->chan_common), "complete all\n");
- BUG_ON(atc_chan_is_enabled(atchan));
-
/*
* Submit queued descriptors ASAP, i.e. before we go through
* the completed ones.
@@ -368,6 +366,9 @@ static void atc_advance_work(struct at_dma_chan *atchan)
{
dev_vdbg(chan2dev(&atchan->chan_common), "advance_work\n");
+ if (atc_chan_is_enabled(atchan))
+ return;
+
if (list_empty(&atchan->active_list) ||
list_is_singular(&atchan->active_list)) {
atc_complete_all(atchan);
@@ -1078,9 +1079,7 @@ static void atc_issue_pending(struct dma_chan *chan)
return;
spin_lock_irqsave(&atchan->lock, flags);
- if (!atc_chan_is_enabled(atchan)) {
- atc_advance_work(atchan);
- }
+ atc_advance_work(atchan);
spin_unlock_irqrestore(&atchan->lock, flags);
}
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index c599558faeda..43a5329d4483 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1001,6 +1001,13 @@ static inline void convert_burst(u32 *maxburst)
*maxburst = 0;
}
+static inline void convert_slave_id(struct dw_dma_chan *dwc)
+{
+ struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+
+ dwc->dma_sconfig.slave_id -= dw->request_line_base;
+}
+
static int
set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
{
@@ -1015,6 +1022,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
convert_burst(&dwc->dma_sconfig.src_maxburst);
convert_burst(&dwc->dma_sconfig.dst_maxburst);
+ convert_slave_id(dwc);
return 0;
}
@@ -1276,9 +1284,9 @@ static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec,
if (dma_spec->args_count != 3)
return NULL;
- fargs.req = be32_to_cpup(dma_spec->args+0);
- fargs.src = be32_to_cpup(dma_spec->args+1);
- fargs.dst = be32_to_cpup(dma_spec->args+2);
+ fargs.req = dma_spec->args[0];
+ fargs.src = dma_spec->args[1];
+ fargs.dst = dma_spec->args[2];
if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
fargs.src >= dw->nr_masters ||
@@ -1628,6 +1636,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
static int dw_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *match;
struct dw_dma_platform_data *pdata;
struct resource *io;
struct dw_dma *dw;
@@ -1711,6 +1720,11 @@ static int dw_probe(struct platform_device *pdev)
memcpy(dw->data_width, pdata->data_width, 4);
}
+ /* Get the base request line if set */
+ match = platform_get_device_id(pdev);
+ if (match)
+ dw->request_line_base = (unsigned int)match->driver_data;
+
/* Calculate all channel mask before DMA setup */
dw->all_chan_mask = (1 << nr_channels) - 1;
@@ -1906,7 +1920,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table);
#endif
static const struct platform_device_id dw_dma_ids[] = {
- { "INTL9C60", 0 },
+ /* Name, Request Line Base */
+ { "INTL9C60", (kernel_ulong_t)16 },
{ }
};
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h
index cf0ce5c77d60..4d02c3669b75 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw_dmac_regs.h
@@ -247,6 +247,7 @@ struct dw_dma {
/* hardware configuration */
unsigned char nr_masters;
unsigned char data_width[4];
+ unsigned int request_line_base;
struct dw_dma_chan chan[0];
};
diff --git a/drivers/dma/ioat/dca.c b/drivers/dma/ioat/dca.c
index 9b041858d10d..9e84d5bc9307 100644
--- a/drivers/dma/ioat/dca.c
+++ b/drivers/dma/ioat/dca.c
@@ -470,8 +470,10 @@ struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
}
if (!dca2_tag_map_valid(ioatdca->tag_map)) {
- dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, "
- "disabling DCA\n");
+ WARN_TAINT_ONCE(1, TAINT_FIRMWARE_WORKAROUND,
+ "%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
+ dev_driver_string(&pdev->dev),
+ dev_name(&pdev->dev));
free_dca_provider(dca);
return NULL;
}
@@ -689,7 +691,10 @@ struct dca_provider *ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase)
}
if (dca3_tag_map_invalid(ioatdca->tag_map)) {
- dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n");
+ WARN_TAINT_ONCE(1, TAINT_FIRMWARE_WORKAROUND,
+ "%s %s: APICID_TAG_MAP set incorrectly by BIOS, disabling DCA\n",
+ dev_driver_string(&pdev->dev),
+ dev_name(&pdev->dev));
free_dca_provider(dca);
return NULL;
}
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index c4b4fd2acc42..08b43bf37158 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -276,12 +276,20 @@ static void omap_dma_issue_pending(struct dma_chan *chan)
spin_lock_irqsave(&c->vc.lock, flags);
if (vchan_issue_pending(&c->vc) && !c->desc) {
- struct omap_dmadev *d = to_omap_dma_dev(chan->device);
- spin_lock(&d->lock);
- if (list_empty(&c->node))
- list_add_tail(&c->node, &d->pending);
- spin_unlock(&d->lock);
- tasklet_schedule(&d->task);
+ /*
+ * c->cyclic is used only by audio and in this case the DMA need
+ * to be started without delay.
+ */
+ if (!c->cyclic) {
+ struct omap_dmadev *d = to_omap_dma_dev(chan->device);
+ spin_lock(&d->lock);
+ if (list_empty(&c->node))
+ list_add_tail(&c->node, &d->pending);
+ spin_unlock(&d->lock);
+ tasklet_schedule(&d->task);
+ } else {
+ omap_dma_start_desc(c);
+ }
}
spin_unlock_irqrestore(&c->vc.lock, flags);
}
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 718153122759..5dbc5946c4c3 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2882,7 +2882,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
{
struct dma_pl330_platdata *pdat;
struct dma_pl330_dmac *pdmac;
- struct dma_pl330_chan *pch;
+ struct dma_pl330_chan *pch, *_p;
struct pl330_info *pi;
struct dma_device *pd;
struct resource *res;
@@ -2984,7 +2984,16 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
ret = dma_async_device_register(pd);
if (ret) {
dev_err(&adev->dev, "unable to register DMAC\n");
- goto probe_err2;
+ goto probe_err3;
+ }
+
+ if (adev->dev.of_node) {
+ ret = of_dma_controller_register(adev->dev.of_node,
+ of_dma_pl330_xlate, pdmac);
+ if (ret) {
+ dev_err(&adev->dev,
+ "unable to register DMA to the generic DT DMA helpers\n");
+ }
}
dev_info(&adev->dev,
@@ -2995,16 +3004,21 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pi->pcfg.data_bus_width / 8, pi->pcfg.num_chan,
pi->pcfg.num_peri, pi->pcfg.num_events);
- ret = of_dma_controller_register(adev->dev.of_node,
- of_dma_pl330_xlate, pdmac);
- if (ret) {
- dev_err(&adev->dev,
- "unable to register DMA to the generic DT DMA helpers\n");
- goto probe_err2;
- }
-
return 0;
+probe_err3:
+ amba_set_drvdata(adev, NULL);
+ /* Idle the DMAC */
+ list_for_each_entry_safe(pch, _p, &pdmac->ddma.channels,
+ chan.device_node) {
+
+ /* Remove the channel */
+ list_del(&pch->chan.device_node);
+
+ /* Flush the channel */
+ pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+ pl330_free_chan_resources(&pch->chan);
+ }
probe_err2:
pl330_del(pi);
probe_err1:
@@ -3023,8 +3037,10 @@ static int pl330_remove(struct amba_device *adev)
if (!pdmac)
return 0;
- of_dma_controller_free(adev->dev.of_node);
+ if (adev->dev.of_node)
+ of_dma_controller_free(adev->dev.of_node);
+ dma_async_device_unregister(&pdmac->ddma);
amba_set_drvdata(adev, NULL);
/* Idle the DMAC */
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index e1d13c463c90..8b6a0343c220 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -98,6 +98,7 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
*
* F15h: we select which DCT we access using F1x10C[DctCfgSel]
*
+ * F16h: has only 1 DCT
*/
static int k8_read_dct_pci_cfg(struct amd64_pvt *pvt, int addr, u32 *val,
const char *func)
@@ -340,6 +341,27 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
base_bits = GENMASK(21, 31) | GENMASK(9, 15);
mask_bits = GENMASK(21, 29) | GENMASK(9, 15);
addr_shift = 4;
+
+ /*
+ * F16h needs two addr_shift values: 8 for high and 6 for low
+ * (cf. F16h BKDG).
+ */
+ } else if (boot_cpu_data.x86 == 0x16) {
+ csbase = pvt->csels[dct].csbases[csrow];
+ csmask = pvt->csels[dct].csmasks[csrow >> 1];
+
+ *base = (csbase & GENMASK(5, 15)) << 6;
+ *base |= (csbase & GENMASK(19, 30)) << 8;
+
+ *mask = ~0ULL;
+ /* poke holes for the csmask */
+ *mask &= ~((GENMASK(5, 15) << 6) |
+ (GENMASK(19, 30) << 8));
+
+ *mask |= (csmask & GENMASK(5, 15)) << 6;
+ *mask |= (csmask & GENMASK(19, 30)) << 8;
+
+ return;
} else {
csbase = pvt->csels[dct].csbases[csrow];
csmask = pvt->csels[dct].csmasks[csrow >> 1];
@@ -1150,6 +1172,21 @@ static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
return ddr3_cs_size(cs_mode, false);
}
+/*
+ * F16h has only limited cs_modes
+ */
+static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode)
+{
+ WARN_ON(cs_mode > 12);
+
+ if (cs_mode == 6 || cs_mode == 8 ||
+ cs_mode == 9 || cs_mode == 12)
+ return -1;
+ else
+ return ddr3_cs_size(cs_mode, false);
+}
+
static void read_dram_ctl_register(struct amd64_pvt *pvt)
{
@@ -1587,6 +1624,17 @@ static struct amd64_family_type amd64_family_types[] = {
.read_dct_pci_cfg = f15_read_dct_pci_cfg,
}
},
+ [F16_CPUS] = {
+ .ctl_name = "F16h",
+ .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
+ .f3_id = PCI_DEVICE_ID_AMD_16H_NB_F3,
+ .ops = {
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
+ .dbam_to_cs = f16_dbam_to_chip_select,
+ .read_dct_pci_cfg = f10_read_dct_pci_cfg,
+ }
+ },
};
/*
@@ -1939,7 +1987,9 @@ static void read_mc_regs(struct amd64_pvt *pvt)
if (c->x86 >= 0x10) {
amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
- amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
+ if (c->x86 != 0x16)
+ /* F16h has only DCT0 */
+ amd64_read_dct_pci_cfg(pvt, DBAM1, &pvt->dbam1);
/* F10h, revD and later can do x8 ECC too */
if ((c->x86 > 0x10 || c->x86_model > 7) && tmp & BIT(25))
@@ -2356,6 +2406,11 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
pvt->ops = &amd64_family_types[F15_CPUS].ops;
break;
+ case 0x16:
+ fam_type = &amd64_family_types[F16_CPUS];
+ pvt->ops = &amd64_family_types[F16_CPUS].ops;
+ break;
+
default:
amd64_err("Unsupported family!\n");
return NULL;
@@ -2581,6 +2636,14 @@ static DEFINE_PCI_DEVICE_TABLE(amd64_pci_table) = {
.class = 0,
.class_mask = 0,
},
+ {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_DEVICE_ID_AMD_16H_NB_F2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = 0,
+ .class_mask = 0,
+ },
{0, }
};
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 35637d83f235..2c6f113bae2b 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -172,7 +172,8 @@
*/
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
-
+#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
+#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532
/*
* Function 1 - Address Map
@@ -296,6 +297,7 @@ enum amd_families {
K8_CPUS = 0,
F10_CPUS,
F15_CPUS,
+ F16_CPUS,
NUM_FAMILIES,
};
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 087c27bc5d42..9004c64b169e 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -750,15 +750,23 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
struct i7300_dimm_info *dinfo;
int rc = -ENODEV;
int mtr;
- int ch, branch, slot, channel;
+ int ch, branch, slot, channel, max_channel, max_branch;
struct dimm_info *dimm;
pvt = mci->pvt_info;
edac_dbg(2, "Memory Technology Registers:\n");
+ if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
+ max_branch = 1;
+ max_channel = 1;
+ } else {
+ max_branch = MAX_BRANCHES;
+ max_channel = MAX_CH_PER_BRANCH;
+ }
+
/* Get the AMB present registers for the four channels */
- for (branch = 0; branch < MAX_BRANCHES; branch++) {
+ for (branch = 0; branch < max_branch; branch++) {
/* Read and dump branch 0's MTRs */
channel = to_channel(0, branch);
pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
@@ -767,6 +775,9 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n",
channel, pvt->ambpresent[channel]);
+ if (max_channel == 1)
+ continue;
+
channel = to_channel(1, branch);
pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
AMBPRESENT_1,
@@ -778,11 +789,11 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
/* Get the set of MTR[0-7] regs by each branch */
for (slot = 0; slot < MAX_SLOTS; slot++) {
int where = mtr_regs[slot];
- for (branch = 0; branch < MAX_BRANCHES; branch++) {
+ for (branch = 0; branch < max_branch; branch++) {
pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
where,
&pvt->mtr[slot][branch]);
- for (ch = 0; ch < MAX_CH_PER_BRANCH; ch++) {
+ for (ch = 0; ch < max_channel; ch++) {
int channel = to_channel(ch, branch);
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 57244f995614..e04462b60756 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -331,30 +331,31 @@ struct sbridge_pvt {
u64 tolm, tohm;
};
-#define PCI_DESCR(device, function, device_id) \
- .dev = (device), \
- .func = (function), \
- .dev_id = (device_id)
+#define PCI_DESCR(device, function, device_id, opt) \
+ .dev = (device), \
+ .func = (function), \
+ .dev_id = (device_id), \
+ .optional = opt
static const struct pci_id_descr pci_dev_descr_sbridge[] = {
/* Processor Home Agent */
- { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0) },
+ { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0) },
/* Memory controller */
- { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA) },
- { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS) },
- { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0) },
- { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1) },
- { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2) },
- { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3) },
- { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO) },
+ { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0) },
+ { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0) },
+ { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0) },
+ { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0) },
+ { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0) },
+ { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0) },
+ { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1) },
/* System Address Decoder */
- { PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0) },
- { PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1) },
+ { PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0) },
+ { PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0) },
/* Broadcast Registers */
- { PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR) },
+ { PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0) },
};
#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
@@ -556,14 +557,19 @@ static int get_dimm_config(struct mem_ctl_info *mci)
pvt->is_close_pg = false;
}
- pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, &reg);
- if (IS_RDIMM_ENABLED(reg)) {
- /* FIXME: Can also be LRDIMM */
- edac_dbg(0, "Memory is registered\n");
- mtype = MEM_RDDR3;
+ if (pvt->pci_ddrio) {
+ pci_read_config_dword(pvt->pci_ddrio, RANK_CFG_A, &reg);
+ if (IS_RDIMM_ENABLED(reg)) {
+ /* FIXME: Can also be LRDIMM */
+ edac_dbg(0, "Memory is registered\n");
+ mtype = MEM_RDDR3;
+ } else {
+ edac_dbg(0, "Memory is unregistered\n");
+ mtype = MEM_DDR3;
+ }
} else {
- edac_dbg(0, "Memory is unregistered\n");
- mtype = MEM_DDR3;
+ edac_dbg(0, "Cannot determine memory type\n");
+ mtype = MEM_UNKNOWN;
}
/* On all supported DDR3 DIMM types, there are 8 banks available */
@@ -1303,8 +1309,7 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
/* Check if everything were registered */
if (!pvt->pci_sad0 || !pvt->pci_sad1 || !pvt->pci_ha0 ||
- !pvt-> pci_tad || !pvt->pci_ras || !pvt->pci_ta ||
- !pvt->pci_ddrio)
+ !pvt-> pci_tad || !pvt->pci_ras || !pvt->pci_ta)
goto enodev;
for (i = 0; i < NUM_CHANNELS; i++) {
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 806c77bfd434..272a3ec35957 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -275,19 +275,18 @@ static int __init eisa_request_resources(struct eisa_root_device *root,
}
if (slot) {
- edev->res[i].name = NULL;
edev->res[i].start = SLOT_ADDRESS(root, slot)
+ (i * 0x400);
edev->res[i].end = edev->res[i].start + 0xff;
edev->res[i].flags = IORESOURCE_IO;
} else {
- edev->res[i].name = NULL;
edev->res[i].start = SLOT_ADDRESS(root, slot)
+ EISA_VENDOR_ID_OFFSET;
edev->res[i].end = edev->res[i].start + 3;
- edev->res[i].flags = IORESOURCE_BUSY;
+ edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY;
}
+ dev_printk(KERN_DEBUG, &edev->dev, "%pR\n", &edev->res[i]);
if (request_resource(root->res, &edev->res[i]))
goto failed;
}
@@ -314,41 +313,40 @@ static int __init eisa_probe(struct eisa_root_device *root)
{
int i, c;
struct eisa_device *edev;
+ char *enabled_str;
- printk(KERN_INFO "EISA: Probing bus %d at %s\n",
- root->bus_nr, dev_name(root->dev));
+ dev_info(root->dev, "Probing EISA bus %d\n", root->bus_nr);
/* First try to get hold of slot 0. If there is no device
* here, simply fail, unless root->force_probe is set. */
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
if (!edev) {
- printk(KERN_ERR "EISA: Couldn't allocate mainboard slot\n");
+ dev_err(root->dev, "EISA: Couldn't allocate mainboard slot\n");
return -ENOMEM;
}
- if (eisa_request_resources(root, edev, 0)) {
- printk(KERN_WARNING \
- "EISA: Cannot allocate resource for mainboard\n");
+ if (eisa_init_device(root, edev, 0)) {
kfree(edev);
if (!root->force_probe)
- return -EBUSY;
+ return -ENODEV;
goto force_probe;
}
- if (eisa_init_device(root, edev, 0)) {
- eisa_release_resources(edev);
+ if (eisa_request_resources(root, edev, 0)) {
+ dev_warn(root->dev,
+ "EISA: Cannot allocate resource for mainboard\n");
kfree(edev);
if (!root->force_probe)
- return -ENODEV;
+ return -EBUSY;
goto force_probe;
}
- printk(KERN_INFO "EISA: Mainboard %s detected.\n", edev->id.sig);
+ dev_info(&edev->dev, "EISA: Mainboard %s detected\n", edev->id.sig);
if (eisa_register_device(edev)) {
- printk(KERN_ERR "EISA: Failed to register %s\n",
- edev->id.sig);
+ dev_err(&edev->dev, "EISA: Failed to register %s\n",
+ edev->id.sig);
eisa_release_resources(edev);
kfree(edev);
}
@@ -358,55 +356,47 @@ static int __init eisa_probe(struct eisa_root_device *root)
for (c = 0, i = 1; i <= root->slots; i++) {
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
if (!edev) {
- printk(KERN_ERR "EISA: Out of memory for slot %d\n", i);
+ dev_err(root->dev, "EISA: Out of memory for slot %d\n",
+ i);
continue;
}
- if (eisa_request_resources(root, edev, i)) {
- printk(KERN_WARNING \
- "Cannot allocate resource for EISA slot %d\n",
- i);
+ if (eisa_init_device(root, edev, i)) {
kfree(edev);
continue;
}
- if (eisa_init_device(root, edev, i)) {
- eisa_release_resources(edev);
+ if (eisa_request_resources(root, edev, i)) {
+ dev_warn(root->dev,
+ "Cannot allocate resource for EISA slot %d\n",
+ i);
kfree(edev);
continue;
}
-
- printk(KERN_INFO "EISA: slot %d : %s detected",
- i, edev->id.sig);
-
- switch (edev->state) {
- case EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED:
- printk(" (forced enabled)");
- break;
-
- case EISA_CONFIG_FORCED:
- printk(" (forced disabled)");
- break;
-
- case 0:
- printk(" (disabled)");
- break;
- }
-
- printk (".\n");
+
+ if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED))
+ enabled_str = " (forced enabled)";
+ else if (edev->state == EISA_CONFIG_FORCED)
+ enabled_str = " (forced disabled)";
+ else if (edev->state == 0)
+ enabled_str = " (disabled)";
+ else
+ enabled_str = "";
+
+ dev_info(&edev->dev, "EISA: slot %d: %s detected%s\n", i,
+ edev->id.sig, enabled_str);
c++;
if (eisa_register_device(edev)) {
- printk(KERN_ERR "EISA: Failed to register %s\n",
- edev->id.sig);
+ dev_err(&edev->dev, "EISA: Failed to register %s\n",
+ edev->id.sig);
eisa_release_resources(edev);
kfree(edev);
}
}
- printk(KERN_INFO "EISA: Detected %d card%s.\n", c, c == 1 ? "" : "s");
-
+ dev_info(root->dev, "EISA: Detected %d card%s\n", c, c == 1 ? "" : "s");
return 0;
}
diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c
index cdae207028a7..a333bf3517de 100644
--- a/drivers/eisa/pci_eisa.c
+++ b/drivers/eisa/pci_eisa.c
@@ -19,48 +19,72 @@
/* There is only *one* pci_eisa device per machine, right ? */
static struct eisa_root_device pci_eisa_root;
-static int __init pci_eisa_init(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __init pci_eisa_init(struct pci_dev *pdev)
{
- int rc;
+ int rc, i;
+ struct resource *res, *bus_res = NULL;
if ((rc = pci_enable_device (pdev))) {
- printk (KERN_ERR "pci_eisa : Could not enable device %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Could not enable device\n");
return rc;
}
+ /*
+ * The Intel 82375 PCI-EISA bridge is a subtractive-decode PCI
+ * device, so the resources available on EISA are the same as those
+ * available on the 82375 bus. This works the same as a PCI-PCI
+ * bridge in subtractive-decode mode (see pci_read_bridge_bases()).
+ * We assume other PCI-EISA bridges are similar.
+ *
+ * eisa_root_register() can only deal with a single io port resource,
+ * so we use the first valid io port resource.
+ */
+ pci_bus_for_each_resource(pdev->bus, res, i)
+ if (res && (res->flags & IORESOURCE_IO)) {
+ bus_res = res;
+ break;
+ }
+
+ if (!bus_res) {
+ dev_err(&pdev->dev, "No resources available\n");
+ return -1;
+ }
+
pci_eisa_root.dev = &pdev->dev;
- pci_eisa_root.res = pdev->bus->resource[0];
- pci_eisa_root.bus_base_addr = pdev->bus->resource[0]->start;
+ pci_eisa_root.res = bus_res;
+ pci_eisa_root.bus_base_addr = bus_res->start;
pci_eisa_root.slots = EISA_MAX_SLOTS;
pci_eisa_root.dma_mask = pdev->dma_mask;
dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root);
if (eisa_root_register (&pci_eisa_root)) {
- printk (KERN_ERR "pci_eisa : Could not register EISA root\n");
+ dev_err(&pdev->dev, "Could not register EISA root\n");
return -1;
}
return 0;
}
-static struct pci_device_id pci_eisa_pci_tbl[] = {
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 },
- { 0, }
-};
+/*
+ * We have to call pci_eisa_init_early() before pnpacpi_init()/isapnp_init().
+ * Otherwise pnp resource will get enabled early and could prevent eisa
+ * to be initialized.
+ * Also need to make sure pci_eisa_init_early() is called after
+ * x86/pci_subsys_init().
+ * So need to use subsys_initcall_sync with it.
+ */
+static int __init pci_eisa_init_early(void)
+{
+ struct pci_dev *dev = NULL;
+ int ret;
-static struct pci_driver __refdata pci_eisa_driver = {
- .name = "pci_eisa",
- .id_table = pci_eisa_pci_tbl,
- .probe = pci_eisa_init,
-};
+ for_each_pci_dev(dev)
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) {
+ ret = pci_eisa_init(dev);
+ if (ret)
+ return ret;
+ }
-static int __init pci_eisa_init_module (void)
-{
- return pci_register_driver (&pci_eisa_driver);
+ return 0;
}
-
-device_initcall(pci_eisa_init_module);
-MODULE_DEVICE_TABLE(pci, pci_eisa_pci_tbl);
+subsys_initcall_sync(pci_eisa_init_early);
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index dc357a4051f6..7a1b4a7791ba 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -33,12 +33,17 @@
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
-#define ARIZONA_NUM_BUTTONS 6
+#define ARIZONA_MAX_MICD_RANGE 8
#define ARIZONA_ACCDET_MODE_MIC 0
#define ARIZONA_ACCDET_MODE_HPL 1
#define ARIZONA_ACCDET_MODE_HPR 2
+#define ARIZONA_HPDET_MAX 10000
+
+#define HPDET_DEBOUNCE 500
+#define DEFAULT_MICD_TIMEOUT 2000
+
struct arizona_extcon_info {
struct device *dev;
struct arizona *arizona;
@@ -46,17 +51,27 @@ struct arizona_extcon_info {
struct regulator *micvdd;
struct input_dev *input;
+ u16 last_jackdet;
+
int micd_mode;
const struct arizona_micd_config *micd_modes;
int micd_num_modes;
+ const struct arizona_micd_range *micd_ranges;
+ int num_micd_ranges;
+
+ int micd_timeout;
+
bool micd_reva;
bool micd_clamp;
struct delayed_work hpdet_work;
+ struct delayed_work micd_detect_work;
+ struct delayed_work micd_timeout_work;
bool hpdet_active;
bool hpdet_done;
+ bool hpdet_retried;
int num_hpdet_res;
unsigned int hpdet_res[3];
@@ -71,20 +86,25 @@ struct arizona_extcon_info {
};
static const struct arizona_micd_config micd_default_modes[] = {
- { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
{ ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 },
+ { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 },
};
-static struct {
- u16 status;
- int report;
-} arizona_lvl_to_key[ARIZONA_NUM_BUTTONS] = {
- { 0x1, BTN_0 },
- { 0x2, BTN_1 },
- { 0x4, BTN_2 },
- { 0x8, BTN_3 },
- { 0x10, BTN_4 },
- { 0x20, BTN_5 },
+static const struct arizona_micd_range micd_default_ranges[] = {
+ { .max = 11, .key = BTN_0 },
+ { .max = 28, .key = BTN_1 },
+ { .max = 54, .key = BTN_2 },
+ { .max = 100, .key = BTN_3 },
+ { .max = 186, .key = BTN_4 },
+ { .max = 430, .key = BTN_5 },
+};
+
+static const int arizona_micd_levels[] = {
+ 3, 6, 8, 11, 13, 16, 18, 21, 23, 26, 28, 31, 34, 36, 39, 41, 44, 46,
+ 49, 52, 54, 57, 60, 62, 65, 67, 70, 73, 75, 78, 81, 83, 89, 94, 100,
+ 105, 111, 116, 122, 127, 139, 150, 161, 173, 186, 196, 209, 220, 245,
+ 270, 295, 321, 348, 375, 402, 430, 489, 550, 614, 681, 752, 903, 1071,
+ 1257,
};
#define ARIZONA_CABLE_MECHANICAL 0
@@ -100,10 +120,63 @@ static const char *arizona_cable[] = {
NULL,
};
+static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
+
+static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
+ unsigned int magic)
+{
+ struct arizona *arizona = info->arizona;
+ int ret;
+
+ mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+ arizona->hpdet_magic = magic;
+
+ /* Keep the HP output stages disabled while doing the magic */
+ if (magic) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ ARIZONA_OUT1L_ENA |
+ ARIZONA_OUT1R_ENA, 0);
+ if (ret != 0)
+ dev_warn(arizona->dev,
+ "Failed to disable headphone outputs: %d\n",
+ ret);
+ }
+
+ ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
+ magic);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n",
+ ret);
+
+ ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
+ magic);
+ if (ret != 0)
+ dev_warn(arizona->dev, "Failed to do magic: %d\n",
+ ret);
+
+ /* Restore the desired state while not doing the magic */
+ if (!magic) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ ARIZONA_OUT1L_ENA |
+ ARIZONA_OUT1R_ENA, arizona->hp_ena);
+ if (ret != 0)
+ dev_warn(arizona->dev,
+ "Failed to restore headphone outputs: %d\n",
+ ret);
+ }
+
+ mutex_unlock(&arizona->dapm->card->dapm_mutex);
+}
+
static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
{
struct arizona *arizona = info->arizona;
+ mode %= info->micd_num_modes;
+
if (arizona->pdata.micd_pol_gpio > 0)
gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio,
info->micd_modes[mode].gpio);
@@ -330,7 +403,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
/* If we go out of range report top of range */
if (val < 100 || val > 0x3fb) {
dev_dbg(arizona->dev, "Measurement out of range\n");
- return 10000;
+ return ARIZONA_HPDET_MAX;
}
dev_dbg(arizona->dev, "HPDET read %d in range %d\n",
@@ -391,7 +464,8 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
return val;
}
-static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
+static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading,
+ bool *mic)
{
struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio;
@@ -403,32 +477,8 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
if (arizona->pdata.hpdet_acc_id) {
info->hpdet_res[info->num_hpdet_res++] = *reading;
- /*
- * If the impedence is too high don't measure the
- * second ground.
- */
- if (info->num_hpdet_res == 1 && *reading >= 45) {
- dev_dbg(arizona->dev, "Skipping ground flip\n");
- info->hpdet_res[info->num_hpdet_res++] = *reading;
- }
-
- if (info->num_hpdet_res == 1) {
- dev_dbg(arizona->dev, "Flipping ground\n");
-
- regmap_update_bits(arizona->regmap,
- ARIZONA_ACCESSORY_DETECT_MODE_1,
- ARIZONA_ACCDET_SRC,
- ~info->micd_modes[0].src);
-
- regmap_update_bits(arizona->regmap,
- ARIZONA_HEADPHONE_DETECT_1,
- ARIZONA_HP_POLL, ARIZONA_HP_POLL);
- return -EAGAIN;
- }
-
/* Only check the mic directly if we didn't already ID it */
- if (id_gpio && info->num_hpdet_res == 2 &&
- !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) {
+ if (id_gpio && info->num_hpdet_res == 1) {
dev_dbg(arizona->dev, "Measuring mic\n");
regmap_update_bits(arizona->regmap,
@@ -447,22 +497,28 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading)
}
/* OK, got both. Now, compare... */
- dev_dbg(arizona->dev, "HPDET measured %d %d %d\n",
- info->hpdet_res[0], info->hpdet_res[1],
- info->hpdet_res[2]);
-
+ dev_dbg(arizona->dev, "HPDET measured %d %d\n",
+ info->hpdet_res[0], info->hpdet_res[1]);
/* Take the headphone impedance for the main report */
*reading = info->hpdet_res[0];
+ /* Sometimes we get false readings due to slow insert */
+ if (*reading >= ARIZONA_HPDET_MAX && !info->hpdet_retried) {
+ dev_dbg(arizona->dev, "Retrying high impedance\n");
+ info->num_hpdet_res = 0;
+ info->hpdet_retried = true;
+ arizona_start_hpdet_acc_id(info);
+ pm_runtime_put(info->dev);
+ return -EAGAIN;
+ }
+
/*
- * Either the two grounds measure differently or we
- * measure the mic as high impedance.
+ * If we measure the mic as
*/
- if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) ||
- (id_gpio && info->hpdet_res[2] > 10)) {
+ if (!id_gpio || info->hpdet_res[1] > 50) {
dev_dbg(arizona->dev, "Detected mic\n");
- info->mic = true;
+ *mic = true;
info->detecting = true;
} else {
dev_dbg(arizona->dev, "Detected headphone\n");
@@ -484,8 +540,8 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio;
int report = ARIZONA_CABLE_HEADPHONE;
- unsigned int val;
int ret, reading;
+ bool mic = false;
mutex_lock(&info->lock);
@@ -521,7 +577,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
0);
- ret = arizona_hpdet_do_id(info, &reading);
+ ret = arizona_hpdet_do_id(info, &reading, &mic);
if (ret == -EAGAIN) {
goto out;
} else if (ret < 0) {
@@ -539,28 +595,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
dev_err(arizona->dev, "Failed to report HP/line: %d\n",
ret);
- mutex_lock(&arizona->dapm->card->dapm_mutex);
-
- ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to read output enables: %d\n",
- ret);
- val = 0;
- }
-
- if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
- ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to undo magic: %d\n",
- ret);
-
- ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to undo magic: %d\n",
- ret);
- }
-
- mutex_unlock(&arizona->dapm->card->dapm_mutex);
+ arizona_extcon_do_magic(info, 0);
done:
if (id_gpio)
@@ -572,7 +607,7 @@ done:
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
/* If we have a mic then reenable MICDET */
- if (info->mic)
+ if (mic || info->mic)
arizona_start_mic(info);
if (info->hpdet_active) {
@@ -606,13 +641,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
if (info->mic)
arizona_stop_mic(info);
- ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
-
- ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+ arizona_extcon_do_magic(info, 0x4000);
ret = regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -653,7 +682,8 @@ err:
static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
{
struct arizona *arizona = info->arizona;
- unsigned int val;
+ int hp_reading = 32;
+ bool mic;
int ret;
dev_dbg(arizona->dev, "Starting identification via HPDET\n");
@@ -663,32 +693,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
info->hpdet_active = true;
- arizona_extcon_pulse_micbias(info);
-
- mutex_lock(&arizona->dapm->card->dapm_mutex);
-
- ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to read output enables: %d\n",
- ret);
- val = 0;
- }
-
- if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
- ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
- 0x4000);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to do magic: %d\n",
- ret);
-
- ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
- 0x4000);
- if (ret != 0)
- dev_warn(arizona->dev, "Failed to do magic: %d\n",
- ret);
- }
-
- mutex_unlock(&arizona->dapm->card->dapm_mutex);
+ arizona_extcon_do_magic(info, 0x4000);
ret = regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -700,12 +705,18 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
goto err;
}
- ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
- ARIZONA_HP_POLL, ARIZONA_HP_POLL);
- if (ret != 0) {
- dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n",
- ret);
- goto err;
+ if (arizona->pdata.hpdet_acc_id_line) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_HEADPHONE_DETECT_1,
+ ARIZONA_HP_POLL, ARIZONA_HP_POLL);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Can't start HPDETL measurement: %d\n",
+ ret);
+ goto err;
+ }
+ } else {
+ arizona_hpdet_do_id(info, &hp_reading, &mic);
}
return;
@@ -724,28 +735,58 @@ err:
info->hpdet_active = false;
}
-static irqreturn_t arizona_micdet(int irq, void *data)
+static void arizona_micd_timeout_work(struct work_struct *work)
{
- struct arizona_extcon_info *info = data;
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ micd_timeout_work.work);
+
+ mutex_lock(&info->lock);
+
+ dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
+ arizona_identify_headphone(info);
+
+ info->detecting = false;
+
+ arizona_stop_mic(info);
+
+ mutex_unlock(&info->lock);
+}
+
+static void arizona_micd_detect(struct work_struct *work)
+{
+ struct arizona_extcon_info *info = container_of(work,
+ struct arizona_extcon_info,
+ micd_detect_work.work);
struct arizona *arizona = info->arizona;
- unsigned int val, lvl;
- int ret, i;
+ unsigned int val = 0, lvl;
+ int ret, i, key;
+
+ cancel_delayed_work_sync(&info->micd_timeout_work);
mutex_lock(&info->lock);
- ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
- if (ret != 0) {
- dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
- mutex_unlock(&info->lock);
- return IRQ_NONE;
- }
+ for (i = 0; i < 10 && !(val & 0x7fc); i++) {
+ ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret);
+ mutex_unlock(&info->lock);
+ return;
+ }
- dev_dbg(arizona->dev, "MICDET: %x\n", val);
+ dev_dbg(arizona->dev, "MICDET: %x\n", val);
+
+ if (!(val & ARIZONA_MICD_VALID)) {
+ dev_warn(arizona->dev, "Microphone detection state invalid\n");
+ mutex_unlock(&info->lock);
+ return;
+ }
+ }
- if (!(val & ARIZONA_MICD_VALID)) {
- dev_warn(arizona->dev, "Microphone detection state invalid\n");
+ if (i == 10 && !(val & 0x7fc)) {
+ dev_err(arizona->dev, "Failed to get valid MICDET value\n");
mutex_unlock(&info->lock);
- return IRQ_NONE;
+ return;
}
/* Due to jack detect this should never happen */
@@ -786,7 +827,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
* impedence then give up and report headphones.
*/
if (info->detecting && (val & 0x3f8)) {
- if (info->jack_flips >= info->micd_num_modes) {
+ if (info->jack_flips >= info->micd_num_modes * 10) {
dev_dbg(arizona->dev, "Detected HP/line\n");
arizona_identify_headphone(info);
@@ -816,12 +857,17 @@ static irqreturn_t arizona_micdet(int irq, void *data)
lvl = val & ARIZONA_MICD_LVL_MASK;
lvl >>= ARIZONA_MICD_LVL_SHIFT;
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
- if (lvl & arizona_lvl_to_key[i].status)
- input_report_key(info->input,
- arizona_lvl_to_key[i].report,
- 1);
- input_sync(info->input);
+ for (i = 0; i < info->num_micd_ranges; i++)
+ input_report_key(info->input,
+ info->micd_ranges[i].key, 0);
+
+ WARN_ON(!lvl);
+ WARN_ON(ffs(lvl) - 1 >= info->num_micd_ranges);
+ if (lvl && ffs(lvl) - 1 < info->num_micd_ranges) {
+ key = info->micd_ranges[ffs(lvl) - 1].key;
+ input_report_key(info->input, key, 1);
+ input_sync(info->input);
+ }
} else if (info->detecting) {
dev_dbg(arizona->dev, "Headphone detected\n");
@@ -835,16 +881,41 @@ static irqreturn_t arizona_micdet(int irq, void *data)
}
} else {
dev_dbg(arizona->dev, "Mic button released\n");
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+ for (i = 0; i < info->num_micd_ranges; i++)
input_report_key(info->input,
- arizona_lvl_to_key[i].report, 0);
+ info->micd_ranges[i].key, 0);
input_sync(info->input);
arizona_extcon_pulse_micbias(info);
}
handled:
+ if (info->detecting)
+ schedule_delayed_work(&info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
+
pm_runtime_mark_last_busy(info->dev);
mutex_unlock(&info->lock);
+}
+
+static irqreturn_t arizona_micdet(int irq, void *data)
+{
+ struct arizona_extcon_info *info = data;
+ struct arizona *arizona = info->arizona;
+ int debounce = arizona->pdata.micd_detect_debounce;
+
+ cancel_delayed_work_sync(&info->micd_detect_work);
+ cancel_delayed_work_sync(&info->micd_timeout_work);
+
+ mutex_lock(&info->lock);
+ if (!info->detecting)
+ debounce = 0;
+ mutex_unlock(&info->lock);
+
+ if (debounce)
+ schedule_delayed_work(&info->micd_detect_work,
+ msecs_to_jiffies(debounce));
+ else
+ arizona_micd_detect(&info->micd_detect_work.work);
return IRQ_HANDLED;
}
@@ -865,11 +936,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona;
unsigned int val, present, mask;
+ bool cancelled_hp, cancelled_mic;
int ret, i;
- pm_runtime_get_sync(info->dev);
+ cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
+ cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
- cancel_delayed_work_sync(&info->hpdet_work);
+ pm_runtime_get_sync(info->dev);
mutex_lock(&info->lock);
@@ -890,7 +963,22 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
return IRQ_NONE;
}
- if ((val & mask) == present) {
+ val &= mask;
+ if (val == info->last_jackdet) {
+ dev_dbg(arizona->dev, "Suppressing duplicate JACKDET\n");
+ if (cancelled_hp)
+ schedule_delayed_work(&info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+
+ if (cancelled_mic)
+ schedule_delayed_work(&info->micd_timeout_work,
+ msecs_to_jiffies(info->micd_timeout));
+
+ goto out;
+ }
+ info->last_jackdet = val;
+
+ if (info->last_jackdet == present) {
dev_dbg(arizona->dev, "Detected jack\n");
ret = extcon_set_cable_state_(&info->edev,
ARIZONA_CABLE_MECHANICAL, true);
@@ -907,7 +995,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
arizona_start_mic(info);
} else {
schedule_delayed_work(&info->hpdet_work,
- msecs_to_jiffies(250));
+ msecs_to_jiffies(HPDET_DEBOUNCE));
}
regmap_update_bits(arizona->regmap,
@@ -923,10 +1011,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
info->hpdet_res[i] = 0;
info->mic = false;
info->hpdet_done = false;
+ info->hpdet_retried = false;
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
+ for (i = 0; i < info->num_micd_ranges; i++)
input_report_key(info->input,
- arizona_lvl_to_key[i].report, 0);
+ info->micd_ranges[i].key, 0);
input_sync(info->input);
ret = extcon_update_state(&info->edev, 0xffffffff, 0);
@@ -940,6 +1029,11 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
}
+ if (arizona->pdata.micd_timeout)
+ info->micd_timeout = arizona->pdata.micd_timeout;
+ else
+ info->micd_timeout = DEFAULT_MICD_TIMEOUT;
+
/* Clear trig_sts to make sure DCVDD is not forced up */
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
@@ -947,6 +1041,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ARIZONA_JD1_FALL_TRIG_STS |
ARIZONA_JD1_RISE_TRIG_STS);
+out:
mutex_unlock(&info->lock);
pm_runtime_mark_last_busy(info->dev);
@@ -955,13 +1050,34 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
return IRQ_HANDLED;
}
+/* Map a level onto a slot in the register bank */
+static void arizona_micd_set_level(struct arizona *arizona, int index,
+ unsigned int level)
+{
+ int reg;
+ unsigned int mask;
+
+ reg = ARIZONA_MIC_DETECT_LEVEL_4 - (index / 2);
+
+ if (!(index % 2)) {
+ mask = 0x3f00;
+ level <<= 8;
+ } else {
+ mask = 0x3f;
+ }
+
+ /* Program the level itself */
+ regmap_update_bits(arizona->regmap, reg, mask, level);
+}
+
static int arizona_extcon_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct arizona_pdata *pdata;
struct arizona_extcon_info *info;
+ unsigned int val;
int jack_irq_fall, jack_irq_rise;
- int ret, mode, i;
+ int ret, mode, i, j;
if (!arizona->dapm || !arizona->dapm->card)
return -EPROBE_DEFER;
@@ -985,7 +1101,10 @@ static int arizona_extcon_probe(struct platform_device *pdev)
mutex_init(&info->lock);
info->arizona = arizona;
info->dev = &pdev->dev;
+ info->last_jackdet = ~(ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS);
INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work);
+ INIT_DELAYED_WORK(&info->micd_detect_work, arizona_micd_detect);
+ INIT_DELAYED_WORK(&info->micd_timeout_work, arizona_micd_timeout_work);
platform_set_drvdata(pdev, info);
switch (arizona->type) {
@@ -1014,6 +1133,17 @@ static int arizona_extcon_probe(struct platform_device *pdev)
goto err;
}
+ info->input = devm_input_allocate_device(&pdev->dev);
+ if (!info->input) {
+ dev_err(arizona->dev, "Can't allocate input dev\n");
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ info->input->name = "Headset";
+ info->input->phys = "arizona/extcon";
+ info->input->dev.parent = &pdev->dev;
+
if (pdata->num_micd_configs) {
info->micd_modes = pdata->micd_configs;
info->micd_num_modes = pdata->num_micd_configs;
@@ -1069,15 +1199,79 @@ static int arizona_extcon_probe(struct platform_device *pdev)
arizona->pdata.micd_dbtime
<< ARIZONA_MICD_DBTIME_SHIFT);
+ BUILD_BUG_ON(ARRAY_SIZE(arizona_micd_levels) != 0x40);
+
+ if (arizona->pdata.num_micd_ranges) {
+ info->micd_ranges = pdata->micd_ranges;
+ info->num_micd_ranges = pdata->num_micd_ranges;
+ } else {
+ info->micd_ranges = micd_default_ranges;
+ info->num_micd_ranges = ARRAY_SIZE(micd_default_ranges);
+ }
+
+ if (arizona->pdata.num_micd_ranges > ARIZONA_MAX_MICD_RANGE) {
+ dev_err(arizona->dev, "Too many MICD ranges: %d\n",
+ arizona->pdata.num_micd_ranges);
+ }
+
+ if (info->num_micd_ranges > 1) {
+ for (i = 1; i < info->num_micd_ranges; i++) {
+ if (info->micd_ranges[i - 1].max >
+ info->micd_ranges[i].max) {
+ dev_err(arizona->dev,
+ "MICD ranges must be sorted\n");
+ ret = -EINVAL;
+ goto err_input;
+ }
+ }
+ }
+
+ /* Disable all buttons by default */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ ARIZONA_MICD_LVL_SEL_MASK, 0x81);
+
+ /* Set up all the buttons the user specified */
+ for (i = 0; i < info->num_micd_ranges; i++) {
+ for (j = 0; j < ARRAY_SIZE(arizona_micd_levels); j++)
+ if (arizona_micd_levels[j] >= info->micd_ranges[i].max)
+ break;
+
+ if (j == ARRAY_SIZE(arizona_micd_levels)) {
+ dev_err(arizona->dev, "Unsupported MICD level %d\n",
+ info->micd_ranges[i].max);
+ ret = -EINVAL;
+ goto err_input;
+ }
+
+ dev_dbg(arizona->dev, "%d ohms for MICD threshold %d\n",
+ arizona_micd_levels[j], i);
+
+ arizona_micd_set_level(arizona, i, j);
+ input_set_capability(info->input, EV_KEY,
+ info->micd_ranges[i].key);
+
+ /* Enable reporting of that range */
+ regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_2,
+ 1 << i, 1 << i);
+ }
+
+ /* Set all the remaining keys to a maximum */
+ for (; i < ARIZONA_MAX_MICD_RANGE; i++)
+ arizona_micd_set_level(arizona, i, 0x3f);
+
/*
* If we have a clamp use it, activating in conjunction with
* GPIO5 if that is connected for jack detect operation.
*/
if (info->micd_clamp) {
if (arizona->pdata.jd_gpio5) {
- /* Put the GPIO into input mode */
+ /* Put the GPIO into input mode with optional pull */
+ val = 0xc101;
+ if (arizona->pdata.jd_gpio5_nopull)
+ val &= ~ARIZONA_GPN_PU;
+
regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL,
- 0xc101);
+ val);
regmap_update_bits(arizona->regmap,
ARIZONA_MICD_CLAMP_CONTROL,
@@ -1096,20 +1290,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
arizona_extcon_set_mode(info, 0);
- info->input = devm_input_allocate_device(&pdev->dev);
- if (!info->input) {
- dev_err(arizona->dev, "Can't allocate input dev\n");
- ret = -ENOMEM;
- goto err_register;
- }
-
- for (i = 0; i < ARIZONA_NUM_BUTTONS; i++)
- input_set_capability(info->input, EV_KEY,
- arizona_lvl_to_key[i].report);
- info->input->name = "Headset";
- info->input->phys = "arizona/extcon";
- info->input->dev.parent = &pdev->dev;
-
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index b70e3815c459..b56bdaa27d4b 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -32,6 +32,38 @@
#define DEV_NAME "max77693-muic"
#define DELAY_MS_DEFAULT 20000 /* unit: millisecond */
+/*
+ * Default value of MAX77693 register to bring up MUIC device.
+ * If user don't set some initial value for MUIC device through platform data,
+ * extcon-max77693 driver use 'default_init_data' to bring up base operation
+ * of MAX77693 MUIC device.
+ */
+static struct max77693_reg_data default_init_data[] = {
+ {
+ /* STATUS2 - [3]ChgDetRun */
+ .addr = MAX77693_MUIC_REG_STATUS2,
+ .data = STATUS2_CHGDETRUN_MASK,
+ }, {
+ /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */
+ .addr = MAX77693_MUIC_REG_INTMASK1,
+ .data = INTMASK1_ADC1K_MASK
+ | INTMASK1_ADC_MASK,
+ }, {
+ /* INTMASK2 - Unmask [0]ChgTypM */
+ .addr = MAX77693_MUIC_REG_INTMASK2,
+ .data = INTMASK2_CHGTYP_MASK,
+ }, {
+ /* INTMASK3 - Mask all of interrupts */
+ .addr = MAX77693_MUIC_REG_INTMASK3,
+ .data = 0x0,
+ }, {
+ /* CDETCTRL2 */
+ .addr = MAX77693_MUIC_REG_CDETCTRL2,
+ .data = CDETCTRL2_VIDRMEN_MASK
+ | CDETCTRL2_DXOVPEN_MASK,
+ },
+};
+
enum max77693_muic_adc_debounce_time {
ADC_DEBOUNCE_TIME_5MS = 0,
ADC_DEBOUNCE_TIME_10MS,
@@ -226,7 +258,7 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info,
CONTROL3_ADCDBSET_MASK);
if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
- return -EAGAIN;
+ return ret;
}
break;
default:
@@ -262,7 +294,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- return -EAGAIN;
+ return ret;
}
if (attached)
@@ -275,7 +307,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info,
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- return -EAGAIN;
+ return ret;
}
dev_info(info->dev,
@@ -1003,7 +1035,7 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info)
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
mutex_unlock(&info->mutex);
- return -EINVAL;
+ return ret;
}
adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC,
@@ -1045,8 +1077,9 @@ static int max77693_muic_probe(struct platform_device *pdev)
{
struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
- struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
struct max77693_muic_info *info;
+ struct max77693_reg_data *init_data;
+ int num_init_data;
int delay_jiffies;
int ret;
int i;
@@ -1145,15 +1178,25 @@ static int max77693_muic_probe(struct platform_device *pdev)
goto err_irq;
}
- /* Initialize MUIC register by using platform data */
- for (i = 0 ; i < muic_pdata->num_init_data ; i++) {
- enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR;
+
+ /* Initialize MUIC register by using platform data or default data */
+ if (pdata->muic_data) {
+ init_data = pdata->muic_data->init_data;
+ num_init_data = pdata->muic_data->num_init_data;
+ } else {
+ init_data = default_init_data;
+ num_init_data = ARRAY_SIZE(default_init_data);
+ }
+
+ for (i = 0 ; i < num_init_data ; i++) {
+ enum max77693_irq_source irq_src
+ = MAX77693_IRQ_GROUP_NR;
max77693_write_reg(info->max77693->regmap_muic,
- muic_pdata->init_data[i].addr,
- muic_pdata->init_data[i].data);
+ init_data[i].addr,
+ init_data[i].data);
- switch (muic_pdata->init_data[i].addr) {
+ switch (init_data[i].addr) {
case MAX77693_MUIC_REG_INTMASK1:
irq_src = MUIC_INT1;
break;
@@ -1167,22 +1210,40 @@ static int max77693_muic_probe(struct platform_device *pdev)
if (irq_src < MAX77693_IRQ_GROUP_NR)
info->max77693->irq_masks_cur[irq_src]
- = muic_pdata->init_data[i].data;
+ = init_data[i].data;
}
- /*
- * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
- * h/w path of COMP2/COMN1 on CONTROL1 register.
- */
- if (muic_pdata->path_uart)
- info->path_uart = muic_pdata->path_uart;
- else
- info->path_uart = CONTROL1_SW_UART;
+ if (pdata->muic_data) {
+ struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
- if (muic_pdata->path_usb)
- info->path_usb = muic_pdata->path_usb;
- else
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ if (muic_pdata->path_uart)
+ info->path_uart = muic_pdata->path_uart;
+ else
+ info->path_uart = CONTROL1_SW_UART;
+
+ if (muic_pdata->path_usb)
+ info->path_usb = muic_pdata->path_usb;
+ else
+ info->path_usb = CONTROL1_SW_USB;
+
+ /*
+ * Default delay time for detecting cable state
+ * after certain time.
+ */
+ if (muic_pdata->detcable_delay_ms)
+ delay_jiffies =
+ msecs_to_jiffies(muic_pdata->detcable_delay_ms);
+ else
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ } else {
info->path_usb = CONTROL1_SW_USB;
+ info->path_uart = CONTROL1_SW_UART;
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ }
/* Set initial path for UART */
max77693_muic_set_path(info, info->path_uart, true);
@@ -1208,10 +1269,6 @@ static int max77693_muic_probe(struct platform_device *pdev)
* driver should notify cable state to upper layer.
*/
INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
- if (muic_pdata->detcable_delay_ms)
- delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms);
- else
- delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
schedule_delayed_work(&info->wq_detcable, delay_jiffies);
return ret;
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c
index e636d950ad6c..67d6738d85a0 100644
--- a/drivers/extcon/extcon-max8997.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -196,7 +196,7 @@ static int max8997_muic_set_debounce_time(struct max8997_muic_info *info,
CONTROL3_ADCDBSET_MASK);
if (ret) {
dev_err(info->dev, "failed to set ADC debounce time\n");
- return -EAGAIN;
+ return ret;
}
break;
default:
@@ -232,7 +232,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- return -EAGAIN;
+ return ret;
}
if (attached)
@@ -245,7 +245,7 @@ static int max8997_muic_set_path(struct max8997_muic_info *info,
CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK);
if (ret < 0) {
dev_err(info->dev, "failed to update MUIC register\n");
- return -EAGAIN;
+ return ret;
}
dev_info(info->dev,
@@ -397,7 +397,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
ret = max8997_muic_set_path(info, info->path_uart, attached);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
- return -EINVAL;
+ return ret;
}
extcon_set_cable_state(info->edev, "JIG", attached);
@@ -608,7 +608,7 @@ static int max8997_muic_detect_dev(struct max8997_muic_info *info)
if (ret) {
dev_err(info->dev, "failed to read MUIC register\n");
mutex_unlock(&info->mutex);
- return -EINVAL;
+ return ret;
}
adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC,
@@ -646,7 +646,7 @@ static void max8997_muic_detect_cable_wq(struct work_struct *work)
ret = max8997_muic_detect_dev(info);
if (ret < 0)
- pr_err("failed to detect cable type\n");
+ dev_err(info->dev, "failed to detect cable type\n");
}
static int max8997_muic_probe(struct platform_device *pdev)
@@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev)
goto err_irq;
}
- /* Initialize registers according to platform data */
if (pdata->muic_pdata) {
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
-
- for (i = 0; i < mdata->num_init_data; i++) {
- max8997_write_reg(info->muic, mdata->init_data[i].addr,
- mdata->init_data[i].data);
+ struct max8997_muic_platform_data *muic_pdata
+ = pdata->muic_pdata;
+
+ /* Initialize registers according to platform data */
+ for (i = 0; i < muic_pdata->num_init_data; i++) {
+ max8997_write_reg(info->muic,
+ muic_pdata->init_data[i].addr,
+ muic_pdata->init_data[i].data);
}
- }
- /*
- * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
- * h/w path of COMP2/COMN1 on CONTROL1 register.
- */
- if (pdata->muic_pdata->path_uart)
- info->path_uart = pdata->muic_pdata->path_uart;
- else
- info->path_uart = CONTROL1_SW_UART;
+ /*
+ * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+ * h/w path of COMP2/COMN1 on CONTROL1 register.
+ */
+ if (muic_pdata->path_uart)
+ info->path_uart = muic_pdata->path_uart;
+ else
+ info->path_uart = CONTROL1_SW_UART;
- if (pdata->muic_pdata->path_usb)
- info->path_usb = pdata->muic_pdata->path_usb;
- else
+ if (muic_pdata->path_usb)
+ info->path_usb = muic_pdata->path_usb;
+ else
+ info->path_usb = CONTROL1_SW_USB;
+
+ /*
+ * Default delay time for detecting cable state
+ * after certain time.
+ */
+ if (muic_pdata->detcable_delay_ms)
+ delay_jiffies =
+ msecs_to_jiffies(muic_pdata->detcable_delay_ms);
+ else
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ } else {
+ info->path_uart = CONTROL1_SW_UART;
info->path_usb = CONTROL1_SW_USB;
+ delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+ }
/* Set initial path for UART */
max8997_muic_set_path(info, info->path_uart, true);
@@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
* driver should notify cable state to upper layer.
*/
INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
- if (pdata->muic_pdata->detcable_delay_ms)
- delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms);
- else
- delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
schedule_delayed_work(&info->wq_detcable, delay_jiffies);
return 0;
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 7224533e8ca6..7a701a58bbf0 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -47,9 +47,9 @@ config FIREWIRE_NET
tristate "IP networking over 1394"
depends on FIREWIRE && INET
help
- This enables IPv4 over IEEE 1394, providing IP connectivity with
- other implementations of RFC 2734 as found on several operating
- systems. Multicast support is currently limited.
+ This enables IPv4/IPv6 over IEEE 1394, providing IP connectivity
+ with other implementations of RFC 2734/3146 as found on several
+ operating systems. Multicast support is currently limited.
To compile this driver as a module, say M here: The module will be
called firewire-net.
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 2b27bff2591a..4d565365e476 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -1,5 +1,6 @@
/*
* IPv4 over IEEE 1394, per RFC 2734
+ * IPv6 over IEEE 1394, per RFC 3146
*
* Copyright (C) 2009 Jay Fenlason <fenlason@redhat.com>
*
@@ -28,6 +29,7 @@
#include <asm/unaligned.h>
#include <net/arp.h>
+#include <net/firewire.h>
/* rx limits */
#define FWNET_MAX_FRAGMENTS 30 /* arbitrary, > TX queue depth */
@@ -45,6 +47,7 @@
#define IANA_SPECIFIER_ID 0x00005eU
#define RFC2734_SW_VERSION 0x000001U
+#define RFC3146_SW_VERSION 0x000002U
#define IEEE1394_GASP_HDR_SIZE 8
@@ -57,32 +60,10 @@
#define RFC2374_HDR_LASTFRAG 2 /* last fragment */
#define RFC2374_HDR_INTFRAG 3 /* interior fragment */
-#define RFC2734_HW_ADDR_LEN 16
-
-struct rfc2734_arp {
- __be16 hw_type; /* 0x0018 */
- __be16 proto_type; /* 0x0806 */
- u8 hw_addr_len; /* 16 */
- u8 ip_addr_len; /* 4 */
- __be16 opcode; /* ARP Opcode */
- /* Above is exactly the same format as struct arphdr */
-
- __be64 s_uniq_id; /* Sender's 64bit EUI */
- u8 max_rec; /* Sender's max packet size */
- u8 sspd; /* Sender's max speed */
- __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
- __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
- __be32 sip; /* Sender's IP Address */
- __be32 tip; /* IP Address of requested hw addr */
-} __packed;
-
-/* This header format is specific to this driver implementation. */
-#define FWNET_ALEN 8
-#define FWNET_HLEN 10
-struct fwnet_header {
- u8 h_dest[FWNET_ALEN]; /* destination address */
- __be16 h_proto; /* packet type ID field */
-} __packed;
+static bool fwnet_hwaddr_is_multicast(u8 *ha)
+{
+ return !!(*ha & 1);
+}
/* IPv4 and IPv6 encapsulation header */
struct rfc2734_header {
@@ -191,8 +172,6 @@ struct fwnet_peer {
struct list_head peer_link;
struct fwnet_device *dev;
u64 guid;
- u64 fifo;
- __be32 ip;
/* guarded by dev->lock */
struct list_head pd_list; /* received partial datagrams */
@@ -222,6 +201,15 @@ struct fwnet_packet_task {
};
/*
+ * Get fifo address embedded in hwaddr
+ */
+static __u64 fwnet_hwaddr_fifo(union fwnet_hwaddr *ha)
+{
+ return (u64)get_unaligned_be16(&ha->uc.fifo_hi) << 32
+ | get_unaligned_be32(&ha->uc.fifo_lo);
+}
+
+/*
* saddr == NULL means use device source address.
* daddr == NULL means leave destination address (eg unresolved arp).
*/
@@ -513,10 +501,20 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
bool is_broadcast, u16 ether_type)
{
struct fwnet_device *dev;
- static const __be64 broadcast_hw = cpu_to_be64(~0ULL);
int status;
__be64 guid;
+ switch (ether_type) {
+ case ETH_P_ARP:
+ case ETH_P_IP:
+#if IS_ENABLED(CONFIG_IPV6)
+ case ETH_P_IPV6:
+#endif
+ break;
+ default:
+ goto err;
+ }
+
dev = netdev_priv(net);
/* Write metadata, and then pass to the receive level */
skb->dev = net;
@@ -524,92 +522,11 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
/*
* Parse the encapsulation header. This actually does the job of
- * converting to an ethernet frame header, as well as arp
- * conversion if needed. ARP conversion is easier in this
- * direction, since we are using ethernet as our backend.
+ * converting to an ethernet-like pseudo frame header.
*/
- /*
- * If this is an ARP packet, convert it. First, we want to make
- * use of some of the fields, since they tell us a little bit
- * about the sending machine.
- */
- if (ether_type == ETH_P_ARP) {
- struct rfc2734_arp *arp1394;
- struct arphdr *arp;
- unsigned char *arp_ptr;
- u64 fifo_addr;
- u64 peer_guid;
- unsigned sspd;
- u16 max_payload;
- struct fwnet_peer *peer;
- unsigned long flags;
-
- arp1394 = (struct rfc2734_arp *)skb->data;
- arp = (struct arphdr *)skb->data;
- arp_ptr = (unsigned char *)(arp + 1);
- peer_guid = get_unaligned_be64(&arp1394->s_uniq_id);
- fifo_addr = (u64)get_unaligned_be16(&arp1394->fifo_hi) << 32
- | get_unaligned_be32(&arp1394->fifo_lo);
-
- sspd = arp1394->sspd;
- /* Sanity check. OS X 10.3 PPC reportedly sends 131. */
- if (sspd > SCODE_3200) {
- dev_notice(&net->dev, "sspd %x out of range\n", sspd);
- sspd = SCODE_3200;
- }
- max_payload = fwnet_max_payload(arp1394->max_rec, sspd);
-
- spin_lock_irqsave(&dev->lock, flags);
- peer = fwnet_peer_find_by_guid(dev, peer_guid);
- if (peer) {
- peer->fifo = fifo_addr;
-
- if (peer->speed > sspd)
- peer->speed = sspd;
- if (peer->max_payload > max_payload)
- peer->max_payload = max_payload;
-
- peer->ip = arp1394->sip;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- if (!peer) {
- dev_notice(&net->dev,
- "no peer for ARP packet from %016llx\n",
- (unsigned long long)peer_guid);
- goto no_peer;
- }
-
- /*
- * Now that we're done with the 1394 specific stuff, we'll
- * need to alter some of the data. Believe it or not, all
- * that needs to be done is sender_IP_address needs to be
- * moved, the destination hardware address get stuffed
- * in and the hardware address length set to 8.
- *
- * IMPORTANT: The code below overwrites 1394 specific data
- * needed above so keep the munging of the data for the
- * higher level IP stack last.
- */
-
- arp->ar_hln = 8;
- /* skip over sender unique id */
- arp_ptr += arp->ar_hln;
- /* move sender IP addr */
- put_unaligned(arp1394->sip, (u32 *)arp_ptr);
- /* skip over sender IP addr */
- arp_ptr += arp->ar_pln;
-
- if (arp->ar_op == htons(ARPOP_REQUEST))
- memset(arp_ptr, 0, sizeof(u64));
- else
- memcpy(arp_ptr, net->dev_addr, sizeof(u64));
- }
-
- /* Now add the ethernet header. */
guid = cpu_to_be64(dev->card->guid);
if (dev_hard_header(skb, net, ether_type,
- is_broadcast ? &broadcast_hw : &guid,
+ is_broadcast ? net->broadcast : net->dev_addr,
NULL, skb->len) >= 0) {
struct fwnet_header *eth;
u16 *rawp;
@@ -618,7 +535,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
skb_reset_mac_header(skb);
skb_pull(skb, sizeof(*eth));
eth = (struct fwnet_header *)skb_mac_header(skb);
- if (*eth->h_dest & 1) {
+ if (fwnet_hwaddr_is_multicast(eth->h_dest)) {
if (memcmp(eth->h_dest, net->broadcast,
net->addr_len) == 0)
skb->pkt_type = PACKET_BROADCAST;
@@ -630,7 +547,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
if (memcmp(eth->h_dest, net->dev_addr, net->addr_len))
skb->pkt_type = PACKET_OTHERHOST;
}
- if (ntohs(eth->h_proto) >= 1536) {
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) {
protocol = eth->h_proto;
} else {
rawp = (u16 *)skb->data;
@@ -652,7 +569,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
return 0;
- no_peer:
+ err:
net->stats.rx_errors++;
net->stats.rx_dropped++;
@@ -856,7 +773,12 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
- if (specifier_id == IANA_SPECIFIER_ID && ver == RFC2734_SW_VERSION) {
+ if (specifier_id == IANA_SPECIFIER_ID &&
+ (ver == RFC2734_SW_VERSION
+#if IS_ENABLED(CONFIG_IPV6)
+ || ver == RFC3146_SW_VERSION
+#endif
+ )) {
buf_ptr += 2;
length -= IEEE1394_GASP_HDR_SIZE;
fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
@@ -1059,16 +981,27 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
u8 *p;
int generation;
int node_id;
+ unsigned int sw_version;
/* ptask->generation may not have been set yet */
generation = dev->card->generation;
smp_rmb();
node_id = dev->card->node_id;
+ switch (ptask->skb->protocol) {
+ default:
+ sw_version = RFC2734_SW_VERSION;
+ break;
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6):
+ sw_version = RFC3146_SW_VERSION;
+#endif
+ }
+
p = skb_push(ptask->skb, IEEE1394_GASP_HDR_SIZE);
put_unaligned_be32(node_id << 16 | IANA_SPECIFIER_ID >> 8, p);
put_unaligned_be32((IANA_SPECIFIER_ID & 0xff) << 24
- | RFC2734_SW_VERSION, &p[4]);
+ | sw_version, &p[4]);
/* We should not transmit if broadcast_channel.valid == 0. */
fw_send_request(dev->card, &ptask->transaction,
@@ -1116,6 +1049,62 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
return 0;
}
+static void fwnet_fifo_stop(struct fwnet_device *dev)
+{
+ if (dev->local_fifo == FWNET_NO_FIFO_ADDR)
+ return;
+
+ fw_core_remove_address_handler(&dev->handler);
+ dev->local_fifo = FWNET_NO_FIFO_ADDR;
+}
+
+static int fwnet_fifo_start(struct fwnet_device *dev)
+{
+ int retval;
+
+ if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
+ return 0;
+
+ dev->handler.length = 4096;
+ dev->handler.address_callback = fwnet_receive_packet;
+ dev->handler.callback_data = dev;
+
+ retval = fw_core_add_address_handler(&dev->handler,
+ &fw_high_memory_region);
+ if (retval < 0)
+ return retval;
+
+ dev->local_fifo = dev->handler.offset;
+
+ return 0;
+}
+
+static void __fwnet_broadcast_stop(struct fwnet_device *dev)
+{
+ unsigned u;
+
+ if (dev->broadcast_state != FWNET_BROADCAST_ERROR) {
+ for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++)
+ kunmap(dev->broadcast_rcv_buffer.pages[u]);
+ fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card);
+ }
+ if (dev->broadcast_rcv_context) {
+ fw_iso_context_destroy(dev->broadcast_rcv_context);
+ dev->broadcast_rcv_context = NULL;
+ }
+ kfree(dev->broadcast_rcv_buffer_ptrs);
+ dev->broadcast_rcv_buffer_ptrs = NULL;
+ dev->broadcast_state = FWNET_BROADCAST_ERROR;
+}
+
+static void fwnet_broadcast_stop(struct fwnet_device *dev)
+{
+ if (dev->broadcast_state == FWNET_BROADCAST_ERROR)
+ return;
+ fw_iso_context_stop(dev->broadcast_rcv_context);
+ __fwnet_broadcast_stop(dev);
+}
+
static int fwnet_broadcast_start(struct fwnet_device *dev)
{
struct fw_iso_context *context;
@@ -1124,60 +1113,47 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
unsigned max_receive;
struct fw_iso_packet packet;
unsigned long offset;
+ void **ptrptr;
unsigned u;
- if (dev->local_fifo == FWNET_NO_FIFO_ADDR) {
- dev->handler.length = 4096;
- dev->handler.address_callback = fwnet_receive_packet;
- dev->handler.callback_data = dev;
-
- retval = fw_core_add_address_handler(&dev->handler,
- &fw_high_memory_region);
- if (retval < 0)
- goto failed_initial;
-
- dev->local_fifo = dev->handler.offset;
- }
+ if (dev->broadcast_state != FWNET_BROADCAST_ERROR)
+ return 0;
max_receive = 1U << (dev->card->max_receive + 1);
num_packets = (FWNET_ISO_PAGE_COUNT * PAGE_SIZE) / max_receive;
- if (!dev->broadcast_rcv_context) {
- void **ptrptr;
-
- context = fw_iso_context_create(dev->card,
- FW_ISO_CONTEXT_RECEIVE, IEEE1394_BROADCAST_CHANNEL,
- dev->card->link_speed, 8, fwnet_receive_broadcast, dev);
- if (IS_ERR(context)) {
- retval = PTR_ERR(context);
- goto failed_context_create;
- }
+ ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL);
+ if (!ptrptr) {
+ retval = -ENOMEM;
+ goto failed;
+ }
+ dev->broadcast_rcv_buffer_ptrs = ptrptr;
+
+ context = fw_iso_context_create(dev->card, FW_ISO_CONTEXT_RECEIVE,
+ IEEE1394_BROADCAST_CHANNEL,
+ dev->card->link_speed, 8,
+ fwnet_receive_broadcast, dev);
+ if (IS_ERR(context)) {
+ retval = PTR_ERR(context);
+ goto failed;
+ }
- retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer,
- dev->card, FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE);
- if (retval < 0)
- goto failed_buffer_init;
+ retval = fw_iso_buffer_init(&dev->broadcast_rcv_buffer, dev->card,
+ FWNET_ISO_PAGE_COUNT, DMA_FROM_DEVICE);
+ if (retval < 0)
+ goto failed;
- ptrptr = kmalloc(sizeof(void *) * num_packets, GFP_KERNEL);
- if (!ptrptr) {
- retval = -ENOMEM;
- goto failed_ptrs_alloc;
- }
+ dev->broadcast_state = FWNET_BROADCAST_STOPPED;
- dev->broadcast_rcv_buffer_ptrs = ptrptr;
- for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) {
- void *ptr;
- unsigned v;
+ for (u = 0; u < FWNET_ISO_PAGE_COUNT; u++) {
+ void *ptr;
+ unsigned v;
- ptr = kmap(dev->broadcast_rcv_buffer.pages[u]);
- for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++)
- *ptrptr++ = (void *)
- ((char *)ptr + v * max_receive);
- }
- dev->broadcast_rcv_context = context;
- } else {
- context = dev->broadcast_rcv_context;
+ ptr = kmap(dev->broadcast_rcv_buffer.pages[u]);
+ for (v = 0; v < num_packets / FWNET_ISO_PAGE_COUNT; v++)
+ *ptrptr++ = (void *) ((char *)ptr + v * max_receive);
}
+ dev->broadcast_rcv_context = context;
packet.payload_length = max_receive;
packet.interrupt = 1;
@@ -1191,7 +1167,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
retval = fw_iso_context_queue(context, &packet,
&dev->broadcast_rcv_buffer, offset);
if (retval < 0)
- goto failed_rcv_queue;
+ goto failed;
offset += max_receive;
}
@@ -1201,7 +1177,7 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
retval = fw_iso_context_start(context, -1, 0,
FW_ISO_CONTEXT_MATCH_ALL_TAGS); /* ??? sync */
if (retval < 0)
- goto failed_rcv_queue;
+ goto failed;
/* FIXME: adjust it according to the min. speed of all known peers? */
dev->broadcast_xmt_max_payload = IEEE1394_MAX_PAYLOAD_S100
@@ -1210,19 +1186,8 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
return 0;
- failed_rcv_queue:
- kfree(dev->broadcast_rcv_buffer_ptrs);
- dev->broadcast_rcv_buffer_ptrs = NULL;
- failed_ptrs_alloc:
- fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer, dev->card);
- failed_buffer_init:
- fw_iso_context_destroy(context);
- dev->broadcast_rcv_context = NULL;
- failed_context_create:
- fw_core_remove_address_handler(&dev->handler);
- failed_initial:
- dev->local_fifo = FWNET_NO_FIFO_ADDR;
-
+ failed:
+ __fwnet_broadcast_stop(dev);
return retval;
}
@@ -1240,11 +1205,10 @@ static int fwnet_open(struct net_device *net)
struct fwnet_device *dev = netdev_priv(net);
int ret;
- if (dev->broadcast_state == FWNET_BROADCAST_ERROR) {
- ret = fwnet_broadcast_start(dev);
- if (ret)
- return ret;
- }
+ ret = fwnet_broadcast_start(dev);
+ if (ret)
+ return ret;
+
netif_start_queue(net);
spin_lock_irq(&dev->lock);
@@ -1257,9 +1221,10 @@ static int fwnet_open(struct net_device *net)
/* ifdown */
static int fwnet_stop(struct net_device *net)
{
- netif_stop_queue(net);
+ struct fwnet_device *dev = netdev_priv(net);
- /* Deallocate iso context for use by other applications? */
+ netif_stop_queue(net);
+ fwnet_broadcast_stop(dev);
return 0;
}
@@ -1299,19 +1264,27 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
* We might need to rebuild the header on tx failure.
*/
memcpy(&hdr_buf, skb->data, sizeof(hdr_buf));
- skb_pull(skb, sizeof(hdr_buf));
-
proto = hdr_buf.h_proto;
+
+ switch (proto) {
+ case htons(ETH_P_ARP):
+ case htons(ETH_P_IP):
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6):
+#endif
+ break;
+ default:
+ goto fail;
+ }
+
+ skb_pull(skb, sizeof(hdr_buf));
dg_size = skb->len;
/*
* Set the transmission type for the packet. ARP packets and IP
* broadcast packets are sent via GASP.
*/
- if (memcmp(hdr_buf.h_dest, net->broadcast, FWNET_ALEN) == 0
- || proto == htons(ETH_P_ARP)
- || (proto == htons(ETH_P_IP)
- && IN_MULTICAST(ntohl(ip_hdr(skb)->daddr)))) {
+ if (fwnet_hwaddr_is_multicast(hdr_buf.h_dest)) {
max_payload = dev->broadcast_xmt_max_payload;
datagram_label_ptr = &dev->broadcast_xmt_datagramlabel;
@@ -1320,11 +1293,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
ptask->dest_node = IEEE1394_ALL_NODES;
ptask->speed = SCODE_100;
} else {
- __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
+ union fwnet_hwaddr *ha = (union fwnet_hwaddr *)hdr_buf.h_dest;
+ __be64 guid = get_unaligned(&ha->uc.uniq_id);
u8 generation;
peer = fwnet_peer_find_by_guid(dev, be64_to_cpu(guid));
- if (!peer || peer->fifo == FWNET_NO_FIFO_ADDR)
+ if (!peer)
goto fail;
generation = peer->generation;
@@ -1332,32 +1306,12 @@ static netdev_tx_t fwnet_tx(struct sk_buff *skb, struct net_device *net)
max_payload = peer->max_payload;
datagram_label_ptr = &peer->datagram_label;
- ptask->fifo_addr = peer->fifo;
+ ptask->fifo_addr = fwnet_hwaddr_fifo(ha);
ptask->generation = generation;
ptask->dest_node = dest_node;
ptask->speed = peer->speed;
}
- /* If this is an ARP packet, convert it */
- if (proto == htons(ETH_P_ARP)) {
- struct arphdr *arp = (struct arphdr *)skb->data;
- unsigned char *arp_ptr = (unsigned char *)(arp + 1);
- struct rfc2734_arp *arp1394 = (struct rfc2734_arp *)skb->data;
- __be32 ipaddr;
-
- ipaddr = get_unaligned((__be32 *)(arp_ptr + FWNET_ALEN));
-
- arp1394->hw_addr_len = RFC2734_HW_ADDR_LEN;
- arp1394->max_rec = dev->card->max_receive;
- arp1394->sspd = dev->card->link_speed;
-
- put_unaligned_be16(dev->local_fifo >> 32,
- &arp1394->fifo_hi);
- put_unaligned_be32(dev->local_fifo & 0xffffffff,
- &arp1394->fifo_lo);
- put_unaligned(ipaddr, &arp1394->sip);
- }
-
ptask->hdr.w0 = 0;
ptask->hdr.w1 = 0;
ptask->skb = skb;
@@ -1472,8 +1426,6 @@ static int fwnet_add_peer(struct fwnet_device *dev,
peer->dev = dev;
peer->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4];
- peer->fifo = FWNET_NO_FIFO_ADDR;
- peer->ip = 0;
INIT_LIST_HEAD(&peer->pd_list);
peer->pdg_size = 0;
peer->datagram_label = 0;
@@ -1503,6 +1455,7 @@ static int fwnet_probe(struct device *_dev)
struct fwnet_device *dev;
unsigned max_mtu;
int ret;
+ union fwnet_hwaddr *ha;
mutex_lock(&fwnet_device_mutex);
@@ -1533,6 +1486,11 @@ static int fwnet_probe(struct device *_dev)
dev->card = card;
dev->netdev = net;
+ ret = fwnet_fifo_start(dev);
+ if (ret < 0)
+ goto out;
+ dev->local_fifo = dev->handler.offset;
+
/*
* Use the RFC 2734 default 1500 octets or the maximum payload
* as initial MTU
@@ -1542,24 +1500,31 @@ static int fwnet_probe(struct device *_dev)
net->mtu = min(1500U, max_mtu);
/* Set our hardware address while we're at it */
- put_unaligned_be64(card->guid, net->dev_addr);
- put_unaligned_be64(~0ULL, net->broadcast);
+ ha = (union fwnet_hwaddr *)net->dev_addr;
+ put_unaligned_be64(card->guid, &ha->uc.uniq_id);
+ ha->uc.max_rec = dev->card->max_receive;
+ ha->uc.sspd = dev->card->link_speed;
+ put_unaligned_be16(dev->local_fifo >> 32, &ha->uc.fifo_hi);
+ put_unaligned_be32(dev->local_fifo & 0xffffffff, &ha->uc.fifo_lo);
+
+ memset(net->broadcast, -1, net->addr_len);
+
ret = register_netdev(net);
if (ret)
goto out;
list_add_tail(&dev->dev_link, &fwnet_device_list);
- dev_notice(&net->dev, "IPv4 over IEEE 1394 on card %s\n",
+ dev_notice(&net->dev, "IP over IEEE 1394 on card %s\n",
dev_name(card->device));
have_dev:
ret = fwnet_add_peer(dev, unit, device);
if (ret && allocated_netdev) {
unregister_netdev(net);
list_del(&dev->dev_link);
- }
out:
- if (ret && allocated_netdev)
+ fwnet_fifo_stop(dev);
free_netdev(net);
+ }
mutex_unlock(&fwnet_device_mutex);
@@ -1592,22 +1557,14 @@ static int fwnet_remove(struct device *_dev)
mutex_lock(&fwnet_device_mutex);
net = dev->netdev;
- if (net && peer->ip)
- arp_invalidate(net, peer->ip);
fwnet_remove_peer(peer, dev);
if (list_empty(&dev->peer_list)) {
unregister_netdev(net);
- if (dev->local_fifo != FWNET_NO_FIFO_ADDR)
- fw_core_remove_address_handler(&dev->handler);
- if (dev->broadcast_rcv_context) {
- fw_iso_context_stop(dev->broadcast_rcv_context);
- fw_iso_buffer_destroy(&dev->broadcast_rcv_buffer,
- dev->card);
- fw_iso_context_destroy(dev->broadcast_rcv_context);
- }
+ fwnet_fifo_stop(dev);
+
for (i = 0; dev->queued_datagrams && i < 5; i++)
ssleep(1);
WARN_ON(dev->queued_datagrams);
@@ -1646,6 +1603,14 @@ static const struct ieee1394_device_id fwnet_id_table[] = {
.specifier_id = IANA_SPECIFIER_ID,
.version = RFC2734_SW_VERSION,
},
+#if IS_ENABLED(CONFIG_IPV6)
+ {
+ .match_flags = IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .specifier_id = IANA_SPECIFIER_ID,
+ .version = RFC3146_SW_VERSION,
+ },
+#endif
{ }
};
@@ -1683,6 +1648,30 @@ static struct fw_descriptor rfc2374_unit_directory = {
.data = rfc2374_unit_directory_data
};
+#if IS_ENABLED(CONFIG_IPV6)
+static const u32 rfc3146_unit_directory_data[] = {
+ 0x00040000, /* directory_length */
+ 0x1200005e, /* unit_specifier_id: IANA */
+ 0x81000003, /* textual descriptor offset */
+ 0x13000002, /* unit_sw_version: RFC 3146 */
+ 0x81000005, /* textual descriptor offset */
+ 0x00030000, /* descriptor_length */
+ 0x00000000, /* text */
+ 0x00000000, /* minimal ASCII, en */
+ 0x49414e41, /* I A N A */
+ 0x00030000, /* descriptor_length */
+ 0x00000000, /* text */
+ 0x00000000, /* minimal ASCII, en */
+ 0x49507636, /* I P v 6 */
+};
+
+static struct fw_descriptor rfc3146_unit_directory = {
+ .length = ARRAY_SIZE(rfc3146_unit_directory_data),
+ .key = (CSR_DIRECTORY | CSR_UNIT) << 24,
+ .data = rfc3146_unit_directory_data
+};
+#endif
+
static int __init fwnet_init(void)
{
int err;
@@ -1691,11 +1680,17 @@ static int __init fwnet_init(void)
if (err)
return err;
+#if IS_ENABLED(CONFIG_IPV6)
+ err = fw_core_add_descriptor(&rfc3146_unit_directory);
+ if (err)
+ goto out;
+#endif
+
fwnet_packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct fwnet_packet_task), 0, 0, NULL);
if (!fwnet_packet_task_cache) {
err = -ENOMEM;
- goto out;
+ goto out2;
}
err = driver_register(&fwnet_driver.driver);
@@ -1703,7 +1698,11 @@ static int __init fwnet_init(void)
return 0;
kmem_cache_destroy(fwnet_packet_task_cache);
+out2:
+#if IS_ENABLED(CONFIG_IPV6)
+ fw_core_remove_descriptor(&rfc3146_unit_directory);
out:
+#endif
fw_core_remove_descriptor(&rfc2374_unit_directory);
return err;
@@ -1714,11 +1713,14 @@ static void __exit fwnet_cleanup(void)
{
driver_unregister(&fwnet_driver.driver);
kmem_cache_destroy(fwnet_packet_task_cache);
+#if IS_ENABLED(CONFIG_IPV6)
+ fw_core_remove_descriptor(&rfc3146_unit_directory);
+#endif
fw_core_remove_descriptor(&rfc2374_unit_directory);
}
module_exit(fwnet_cleanup);
MODULE_AUTHOR("Jay Fenlason <fenlason@redhat.com>");
-MODULE_DESCRIPTION("IPv4 over IEEE1394 as per RFC 2734");
+MODULE_DESCRIPTION("IP over IEEE1394 as per RFC 2734/3146");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(ieee1394, fwnet_id_table);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 42c759a4d047..93876302fb2e 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -36,41 +36,6 @@ config FIRMWARE_MEMMAP
See also Documentation/ABI/testing/sysfs-firmware-memmap.
-config EFI_VARS
- tristate "EFI Variable Support via sysfs"
- depends on EFI
- default n
- help
- If you say Y here, you are able to get EFI (Extensible Firmware
- Interface) variable information via sysfs. You may read,
- write, create, and destroy EFI variables through this interface.
-
- Note that using this driver in concert with efibootmgr requires
- at least test release version 0.5.0-test3 or later, which is
- available from Matt Domsch's website located at:
- <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz>
-
- Subsequent efibootmgr releases may be found at:
- <http://linux.dell.com/efibootmgr>
-
-config EFI_VARS_PSTORE
- bool "Register efivars backend for pstore"
- depends on EFI_VARS && PSTORE
- default y
- help
- Say Y here to enable use efivars as a backend to pstore. This
- will allow writing console messages, crash dumps, or anything
- else supported by pstore to EFI variables.
-
-config EFI_VARS_PSTORE_DEFAULT_DISABLE
- bool "Disable using efivars as a pstore backend by default"
- depends on EFI_VARS_PSTORE
- default n
- help
- Saying Y here will disable the use of efivars as a storage
- backend for pstore by default. This setting can be overridden
- using the efivars module's pstore_disable parameter.
-
config EFI_PCDP
bool "Console device selection via EFI PCDP or HCDP table"
depends on ACPI && EFI && IA64
@@ -164,5 +129,6 @@ config ISCSI_IBFT
Otherwise, say N.
source "drivers/firmware/google/Kconfig"
+source "drivers/firmware/efi/Kconfig"
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 5a7e27399729..299fad6b5867 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,7 +4,6 @@
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
-obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_DCDBAS) += dcdbas.o
@@ -14,3 +13,4 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
+obj-$(CONFIG_EFI) += efi/
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 4cd392dbf115..b95159b33c39 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -22,6 +22,9 @@ static u16 __initdata dmi_ver;
*/
static int dmi_initialized;
+/* DMI system identification string used during boot */
+static char dmi_ids_string[128] __initdata;
+
static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
{
const u8 *bp = ((u8 *) dm) + dm->length;
@@ -376,99 +379,103 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
}
}
-static void __init print_filtered(const char *info)
+static int __init print_filtered(char *buf, size_t len, const char *info)
{
+ int c = 0;
const char *p;
if (!info)
- return;
+ return c;
for (p = info; *p; p++)
if (isprint(*p))
- printk(KERN_CONT "%c", *p);
+ c += scnprintf(buf + c, len - c, "%c", *p);
else
- printk(KERN_CONT "\\x%02x", *p & 0xff);
+ c += scnprintf(buf + c, len - c, "\\x%02x", *p & 0xff);
+ return c;
}
-static void __init dmi_dump_ids(void)
+static void __init dmi_format_ids(char *buf, size_t len)
{
+ int c = 0;
const char *board; /* Board Name is optional */
- printk(KERN_DEBUG "DMI: ");
- print_filtered(dmi_get_system_info(DMI_SYS_VENDOR));
- printk(KERN_CONT " ");
- print_filtered(dmi_get_system_info(DMI_PRODUCT_NAME));
+ c += print_filtered(buf + c, len - c,
+ dmi_get_system_info(DMI_SYS_VENDOR));
+ c += scnprintf(buf + c, len - c, " ");
+ c += print_filtered(buf + c, len - c,
+ dmi_get_system_info(DMI_PRODUCT_NAME));
+
board = dmi_get_system_info(DMI_BOARD_NAME);
if (board) {
- printk(KERN_CONT "/");
- print_filtered(board);
+ c += scnprintf(buf + c, len - c, "/");
+ c += print_filtered(buf + c, len - c, board);
}
- printk(KERN_CONT ", BIOS ");
- print_filtered(dmi_get_system_info(DMI_BIOS_VERSION));
- printk(KERN_CONT " ");
- print_filtered(dmi_get_system_info(DMI_BIOS_DATE));
- printk(KERN_CONT "\n");
+ c += scnprintf(buf + c, len - c, ", BIOS ");
+ c += print_filtered(buf + c, len - c,
+ dmi_get_system_info(DMI_BIOS_VERSION));
+ c += scnprintf(buf + c, len - c, " ");
+ c += print_filtered(buf + c, len - c,
+ dmi_get_system_info(DMI_BIOS_DATE));
}
-static int __init dmi_present(const char __iomem *p)
+static int __init dmi_present(const u8 *buf)
{
- u8 buf[15];
+ int smbios_ver;
+
+ if (memcmp(buf, "_SM_", 4) == 0 &&
+ buf[5] < 32 && dmi_checksum(buf, buf[5])) {
+ smbios_ver = (buf[6] << 8) + buf[7];
+
+ /* Some BIOS report weird SMBIOS version, fix that up */
+ switch (smbios_ver) {
+ case 0x021F:
+ case 0x0221:
+ pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
+ smbios_ver & 0xFF, 3);
+ smbios_ver = 0x0203;
+ break;
+ case 0x0233:
+ pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
+ smbios_ver = 0x0206;
+ break;
+ }
+ } else {
+ smbios_ver = 0;
+ }
- memcpy_fromio(buf, p, 15);
- if (dmi_checksum(buf, 15)) {
+ buf += 16;
+
+ if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
dmi_num = (buf[13] << 8) | buf[12];
dmi_len = (buf[7] << 8) | buf[6];
dmi_base = (buf[11] << 24) | (buf[10] << 16) |
(buf[9] << 8) | buf[8];
if (dmi_walk_early(dmi_decode) == 0) {
- if (dmi_ver)
+ if (smbios_ver) {
+ dmi_ver = smbios_ver;
pr_info("SMBIOS %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
- else {
+ } else {
dmi_ver = (buf[14] & 0xF0) << 4 |
(buf[14] & 0x0F);
pr_info("Legacy DMI %d.%d present.\n",
dmi_ver >> 8, dmi_ver & 0xFF);
}
- dmi_dump_ids();
+ dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
+ printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
return 0;
}
}
- dmi_ver = 0;
- return 1;
-}
-
-static int __init smbios_present(const char __iomem *p)
-{
- u8 buf[32];
- memcpy_fromio(buf, p, 32);
- if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) {
- dmi_ver = (buf[6] << 8) + buf[7];
-
- /* Some BIOS report weird SMBIOS version, fix that up */
- switch (dmi_ver) {
- case 0x021F:
- case 0x0221:
- pr_debug("SMBIOS version fixup(2.%d->2.%d)\n",
- dmi_ver & 0xFF, 3);
- dmi_ver = 0x0203;
- break;
- case 0x0233:
- pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6);
- dmi_ver = 0x0206;
- break;
- }
- return memcmp(p + 16, "_DMI_", 5) || dmi_present(p + 16);
- }
return 1;
}
void __init dmi_scan_machine(void)
{
char __iomem *p, *q;
- int rc;
+ char buf[32];
if (efi_enabled(EFI_CONFIG_TABLES)) {
if (efi.smbios == EFI_INVALID_TABLE_ADDR)
@@ -481,10 +488,10 @@ void __init dmi_scan_machine(void)
p = dmi_ioremap(efi.smbios, 32);
if (p == NULL)
goto error;
-
- rc = smbios_present(p);
+ memcpy_fromio(buf, p, 32);
dmi_iounmap(p, 32);
- if (!rc) {
+
+ if (!dmi_present(buf)) {
dmi_available = 1;
goto out;
}
@@ -499,18 +506,15 @@ void __init dmi_scan_machine(void)
if (p == NULL)
goto error;
+ memset(buf, 0, 16);
for (q = p; q < p + 0x10000; q += 16) {
- if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0)
- rc = smbios_present(q);
- else if (memcmp(q, "_DMI_", 5) == 0)
- rc = dmi_present(q);
- else
- continue;
- if (!rc) {
+ memcpy_fromio(buf + 16, q, 16);
+ if (!dmi_present(buf)) {
dmi_available = 1;
dmi_iounmap(p, 0x10000);
goto out;
}
+ memcpy(buf, buf + 16, 16);
}
dmi_iounmap(p, 0x10000);
}
@@ -521,6 +525,19 @@ void __init dmi_scan_machine(void)
}
/**
+ * dmi_set_dump_stack_arch_desc - set arch description for dump_stack()
+ *
+ * Invoke dump_stack_set_arch_desc() with DMI system information so that
+ * DMI identifiers are printed out on task dumps. Arch boot code should
+ * call this function after dmi_scan_machine() if it wants to print out DMI
+ * identifiers on task dumps.
+ */
+void __init dmi_set_dump_stack_arch_desc(void)
+{
+ dump_stack_set_arch_desc("%s", dmi_ids_string);
+}
+
+/**
* dmi_matches - check if dmi_system_id structure matches system DMI data
* @dmi: pointer to the dmi_system_id structure to check
*/
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
new file mode 100644
index 000000000000..b0fc7c79dfbb
--- /dev/null
+++ b/drivers/firmware/efi/Kconfig
@@ -0,0 +1,39 @@
+menu "EFI (Extensible Firmware Interface) Support"
+ depends on EFI
+
+config EFI_VARS
+ tristate "EFI Variable Support via sysfs"
+ depends on EFI
+ default n
+ help
+ If you say Y here, you are able to get EFI (Extensible Firmware
+ Interface) variable information via sysfs. You may read,
+ write, create, and destroy EFI variables through this interface.
+
+ Note that using this driver in concert with efibootmgr requires
+ at least test release version 0.5.0-test3 or later, which is
+ available from Matt Domsch's website located at:
+ <http://linux.dell.com/efibootmgr/testing/efibootmgr-0.5.0-test3.tar.gz>
+
+ Subsequent efibootmgr releases may be found at:
+ <http://linux.dell.com/efibootmgr>
+
+config EFI_VARS_PSTORE
+ tristate "Register efivars backend for pstore"
+ depends on EFI_VARS && PSTORE
+ default y
+ help
+ Say Y here to enable use efivars as a backend to pstore. This
+ will allow writing console messages, crash dumps, or anything
+ else supported by pstore to EFI variables.
+
+config EFI_VARS_PSTORE_DEFAULT_DISABLE
+ bool "Disable using efivars as a pstore backend by default"
+ depends on EFI_VARS_PSTORE
+ default n
+ help
+ Saying Y here will disable the use of efivars as a storage
+ backend for pstore by default. This setting can be overridden
+ using the efivars module's pstore_disable parameter.
+
+endmenu
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
new file mode 100644
index 000000000000..99245ab5a79c
--- /dev/null
+++ b/drivers/firmware/efi/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for linux kernel
+#
+obj-y += efi.o vars.o
+obj-$(CONFIG_EFI_VARS) += efivars.o
+obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
new file mode 100644
index 000000000000..202d2c85ba2e
--- /dev/null
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -0,0 +1,252 @@
+#include <linux/efi.h>
+#include <linux/module.h>
+#include <linux/pstore.h>
+#include <linux/slab.h>
+#include <linux/ucs2_string.h>
+
+#define DUMP_NAME_LEN 52
+
+static bool efivars_pstore_disable =
+ IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
+
+module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
+
+#define PSTORE_EFI_ATTRIBUTES \
+ (EFI_VARIABLE_NON_VOLATILE | \
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS)
+
+static int efi_pstore_open(struct pstore_info *psi)
+{
+ efivar_entry_iter_begin();
+ psi->data = NULL;
+ return 0;
+}
+
+static int efi_pstore_close(struct pstore_info *psi)
+{
+ efivar_entry_iter_end();
+ psi->data = NULL;
+ return 0;
+}
+
+struct pstore_read_data {
+ u64 *id;
+ enum pstore_type_id *type;
+ int *count;
+ struct timespec *timespec;
+ char **buf;
+};
+
+static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
+{
+ efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+ struct pstore_read_data *cb_data = data;
+ char name[DUMP_NAME_LEN];
+ int i;
+ int cnt;
+ unsigned int part;
+ unsigned long time, size;
+
+ if (efi_guidcmp(entry->var.VendorGuid, vendor))
+ return 0;
+
+ for (i = 0; i < DUMP_NAME_LEN; i++)
+ name[i] = entry->var.VariableName[i];
+
+ if (sscanf(name, "dump-type%u-%u-%d-%lu",
+ cb_data->type, &part, &cnt, &time) == 4) {
+ *cb_data->id = part;
+ *cb_data->count = cnt;
+ cb_data->timespec->tv_sec = time;
+ cb_data->timespec->tv_nsec = 0;
+ } else if (sscanf(name, "dump-type%u-%u-%lu",
+ cb_data->type, &part, &time) == 3) {
+ /*
+ * Check if an old format,
+ * which doesn't support holding
+ * multiple logs, remains.
+ */
+ *cb_data->id = part;
+ *cb_data->count = 0;
+ cb_data->timespec->tv_sec = time;
+ cb_data->timespec->tv_nsec = 0;
+ } else
+ return 0;
+
+ entry->var.DataSize = 1024;
+ __efivar_entry_get(entry, &entry->var.Attributes,
+ &entry->var.DataSize, entry->var.Data);
+ size = entry->var.DataSize;
+
+ *cb_data->buf = kmalloc(size, GFP_KERNEL);
+ if (*cb_data->buf == NULL)
+ return -ENOMEM;
+ memcpy(*cb_data->buf, entry->var.Data, size);
+ return size;
+}
+
+static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *timespec,
+ char **buf, struct pstore_info *psi)
+{
+ struct pstore_read_data data;
+
+ data.id = id;
+ data.type = type;
+ data.count = count;
+ data.timespec = timespec;
+ data.buf = buf;
+
+ return __efivar_entry_iter(efi_pstore_read_func, &efivar_sysfs_list, &data,
+ (struct efivar_entry **)&psi->data);
+}
+
+static int efi_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason, u64 *id,
+ unsigned int part, int count, size_t size,
+ struct pstore_info *psi)
+{
+ char name[DUMP_NAME_LEN];
+ efi_char16_t efi_name[DUMP_NAME_LEN];
+ efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+ int i, ret = 0;
+
+ sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
+ get_seconds());
+
+ for (i = 0; i < DUMP_NAME_LEN; i++)
+ efi_name[i] = name[i];
+
+ efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
+ !pstore_cannot_block_path(reason),
+ size, psi->buf);
+
+ if (reason == KMSG_DUMP_OOPS)
+ efivar_run_worker();
+
+ *id = part;
+ return ret;
+};
+
+struct pstore_erase_data {
+ u64 id;
+ enum pstore_type_id type;
+ int count;
+ struct timespec time;
+ efi_char16_t *name;
+};
+
+/*
+ * Clean up an entry with the same name
+ */
+static int efi_pstore_erase_func(struct efivar_entry *entry, void *data)
+{
+ struct pstore_erase_data *ed = data;
+ efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
+ efi_char16_t efi_name_old[DUMP_NAME_LEN];
+ efi_char16_t *efi_name = ed->name;
+ unsigned long ucs2_len = ucs2_strlen(ed->name);
+ char name_old[DUMP_NAME_LEN];
+ int i;
+
+ if (efi_guidcmp(entry->var.VendorGuid, vendor))
+ return 0;
+
+ if (ucs2_strncmp(entry->var.VariableName,
+ efi_name, (size_t)ucs2_len)) {
+ /*
+ * Check if an old format, which doesn't support
+ * holding multiple logs, remains.
+ */
+ sprintf(name_old, "dump-type%u-%u-%lu", ed->type,
+ (unsigned int)ed->id, ed->time.tv_sec);
+
+ for (i = 0; i < DUMP_NAME_LEN; i++)
+ efi_name_old[i] = name_old[i];
+
+ if (ucs2_strncmp(entry->var.VariableName, efi_name_old,
+ ucs2_strlen(efi_name_old)))
+ return 0;
+ }
+
+ /* found */
+ __efivar_entry_delete(entry);
+ list_del(&entry->list);
+
+ return 1;
+}
+
+static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
+ struct timespec time, struct pstore_info *psi)
+{
+ struct pstore_erase_data edata;
+ struct efivar_entry *entry = NULL;
+ char name[DUMP_NAME_LEN];
+ efi_char16_t efi_name[DUMP_NAME_LEN];
+ int found, i;
+
+ sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
+ time.tv_sec);
+
+ for (i = 0; i < DUMP_NAME_LEN; i++)
+ efi_name[i] = name[i];
+
+ edata.id = id;
+ edata.type = type;
+ edata.count = count;
+ edata.time = time;
+ edata.name = efi_name;
+
+ efivar_entry_iter_begin();
+ found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry);
+ efivar_entry_iter_end();
+
+ if (found)
+ efivar_unregister(entry);
+
+ return 0;
+}
+
+static struct pstore_info efi_pstore_info = {
+ .owner = THIS_MODULE,
+ .name = "efi",
+ .open = efi_pstore_open,
+ .close = efi_pstore_close,
+ .read = efi_pstore_read,
+ .write = efi_pstore_write,
+ .erase = efi_pstore_erase,
+};
+
+static __init int efivars_pstore_init(void)
+{
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ return 0;
+
+ if (!efivars_kobject())
+ return 0;
+
+ if (efivars_pstore_disable)
+ return 0;
+
+ efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
+ if (!efi_pstore_info.buf)
+ return -ENOMEM;
+
+ efi_pstore_info.bufsize = 1024;
+ spin_lock_init(&efi_pstore_info.buf_lock);
+
+ pstore_register(&efi_pstore_info);
+
+ return 0;
+}
+
+static __exit void efivars_pstore_exit(void)
+{
+}
+
+module_init(efivars_pstore_init);
+module_exit(efivars_pstore_exit);
+
+MODULE_DESCRIPTION("EFI variable backend for pstore");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
new file mode 100644
index 000000000000..5145fa344ad5
--- /dev/null
+++ b/drivers/firmware/efi/efi.c
@@ -0,0 +1,134 @@
+/*
+ * efi.c - EFI subsystem
+ *
+ * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
+ * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
+ * Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
+ *
+ * This code registers /sys/firmware/efi{,/efivars} when EFI is supported,
+ * allowing the efivarfs to be mounted or the efivars module to be loaded.
+ * The existance of /sys/firmware/efi may also be used by userspace to
+ * determine that the system supports EFI.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/efi.h>
+
+static struct kobject *efi_kobj;
+static struct kobject *efivars_kobj;
+
+/*
+ * Let's not leave out systab information that snuck into
+ * the efivars driver
+ */
+static ssize_t systab_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char *str = buf;
+
+ if (!kobj || !buf)
+ return -EINVAL;
+
+ if (efi.mps != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "MPS=0x%lx\n", efi.mps);
+ if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
+ if (efi.acpi != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
+ if (efi.smbios != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
+ if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
+ if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
+ if (efi.uga != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "UGA=0x%lx\n", efi.uga);
+
+ return str - buf;
+}
+
+static struct kobj_attribute efi_attr_systab =
+ __ATTR(systab, 0400, systab_show, NULL);
+
+static struct attribute *efi_subsys_attrs[] = {
+ &efi_attr_systab.attr,
+ NULL, /* maybe more in the future? */
+};
+
+static struct attribute_group efi_subsys_attr_group = {
+ .attrs = efi_subsys_attrs,
+};
+
+static struct efivars generic_efivars;
+static struct efivar_operations generic_ops;
+
+static int generic_ops_register(void)
+{
+ generic_ops.get_variable = efi.get_variable;
+ generic_ops.set_variable = efi.set_variable;
+ generic_ops.get_next_variable = efi.get_next_variable;
+ generic_ops.query_variable_store = efi_query_variable_store;
+
+ return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
+}
+
+static void generic_ops_unregister(void)
+{
+ efivars_unregister(&generic_efivars);
+}
+
+/*
+ * We register the efi subsystem with the firmware subsystem and the
+ * efivars subsystem with the efi subsystem, if the system was booted with
+ * EFI.
+ */
+static int __init efisubsys_init(void)
+{
+ int error;
+
+ if (!efi_enabled(EFI_BOOT))
+ return 0;
+
+ /* We register the efi directory at /sys/firmware/efi */
+ efi_kobj = kobject_create_and_add("efi", firmware_kobj);
+ if (!efi_kobj) {
+ pr_err("efi: Firmware registration failed.\n");
+ return -ENOMEM;
+ }
+
+ error = generic_ops_register();
+ if (error)
+ goto err_put;
+
+ error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
+ if (error) {
+ pr_err("efi: Sysfs attribute export failed with error %d.\n",
+ error);
+ goto err_unregister;
+ }
+
+ /* and the standard mountpoint for efivarfs */
+ efivars_kobj = kobject_create_and_add("efivars", efi_kobj);
+ if (!efivars_kobj) {
+ pr_err("efivars: Subsystem registration failed.\n");
+ error = -ENOMEM;
+ goto err_remove_group;
+ }
+
+ return 0;
+
+err_remove_group:
+ sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
+err_unregister:
+ generic_ops_unregister();
+err_put:
+ kobject_put(efi_kobj);
+ return error;
+}
+
+subsys_initcall(efisubsys_init);
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
new file mode 100644
index 000000000000..b623c599e572
--- /dev/null
+++ b/drivers/firmware/efi/efivars.c
@@ -0,0 +1,617 @@
+/*
+ * Originally from efivars.c,
+ *
+ * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
+ * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
+ *
+ * This code takes all variables accessible from EFI runtime and
+ * exports them via sysfs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Changelog:
+ *
+ * 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
+ * remove check for efi_enabled in exit
+ * add MODULE_VERSION
+ *
+ * 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
+ * minor bug fixes
+ *
+ * 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
+ * converted driver to export variable information via sysfs
+ * and moved to drivers/firmware directory
+ * bumped revision number to v0.07 to reflect conversion & move
+ *
+ * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
+ * fix locking per Peter Chubb's findings
+ *
+ * 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
+ * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
+ *
+ * 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
+ * use list_for_each_safe when deleting vars.
+ * remove ifdef CONFIG_SMP around include <linux/smp.h>
+ * v0.04 release to linux-ia64@linuxia64.org
+ *
+ * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ * Moved vars from /proc/efi to /proc/efi/vars, and made
+ * efi.c own the /proc/efi directory.
+ * v0.03 release to linux-ia64@linuxia64.org
+ *
+ * 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ * At the request of Stephane, moved ownership of /proc/efi
+ * to efi.c, and now efivars lives under /proc/efi/vars.
+ *
+ * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ * Feedback received from Stephane Eranian incorporated.
+ * efivar_write() checks copy_from_user() return value.
+ * efivar_read/write() returns proper errno.
+ * v0.02 release to linux-ia64@linuxia64.org
+ *
+ * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ * v0.01 release to linux-ia64@linuxia64.org
+ */
+
+#include <linux/efi.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/ucs2_string.h>
+
+#define EFIVARS_VERSION "0.08"
+#define EFIVARS_DATE "2004-May-17"
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
+MODULE_DESCRIPTION("sysfs interface to EFI Variables");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EFIVARS_VERSION);
+
+LIST_HEAD(efivar_sysfs_list);
+EXPORT_SYMBOL_GPL(efivar_sysfs_list);
+
+static struct kset *efivars_kset;
+
+static struct bin_attribute *efivars_new_var;
+static struct bin_attribute *efivars_del_var;
+
+struct efivar_attribute {
+ struct attribute attr;
+ ssize_t (*show) (struct efivar_entry *entry, char *buf);
+ ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
+};
+
+#define EFIVAR_ATTR(_name, _mode, _show, _store) \
+struct efivar_attribute efivar_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
+#define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj)
+
+/*
+ * Prototype for sysfs creation function
+ */
+static int
+efivar_create_sysfs_entry(struct efivar_entry *new_var);
+
+static ssize_t
+efivar_guid_read(struct efivar_entry *entry, char *buf)
+{
+ struct efi_variable *var = &entry->var;
+ char *str = buf;
+
+ if (!entry || !buf)
+ return 0;
+
+ efi_guid_unparse(&var->VendorGuid, str);
+ str += strlen(str);
+ str += sprintf(str, "\n");
+
+ return str - buf;
+}
+
+static ssize_t
+efivar_attr_read(struct efivar_entry *entry, char *buf)
+{
+ struct efi_variable *var = &entry->var;
+ char *str = buf;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ var->DataSize = 1024;
+ if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ return -EIO;
+
+ if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
+ str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
+ if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
+ str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
+ if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
+ str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
+ if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
+ str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
+ if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
+ str += sprintf(str,
+ "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
+ if (var->Attributes &
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+ str += sprintf(str,
+ "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
+ if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
+ str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
+ return str - buf;
+}
+
+static ssize_t
+efivar_size_read(struct efivar_entry *entry, char *buf)
+{
+ struct efi_variable *var = &entry->var;
+ char *str = buf;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ var->DataSize = 1024;
+ if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ return -EIO;
+
+ str += sprintf(str, "0x%lx\n", var->DataSize);
+ return str - buf;
+}
+
+static ssize_t
+efivar_data_read(struct efivar_entry *entry, char *buf)
+{
+ struct efi_variable *var = &entry->var;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ var->DataSize = 1024;
+ if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+ return -EIO;
+
+ memcpy(buf, var->Data, var->DataSize);
+ return var->DataSize;
+}
+/*
+ * We allow each variable to be edited via rewriting the
+ * entire efi variable structure.
+ */
+static ssize_t
+efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
+{
+ struct efi_variable *new_var, *var = &entry->var;
+ int err;
+
+ if (count != sizeof(struct efi_variable))
+ return -EINVAL;
+
+ new_var = (struct efi_variable *)buf;
+ /*
+ * If only updating the variable data, then the name
+ * and guid should remain the same
+ */
+ if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
+ efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
+ printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
+ return -EINVAL;
+ }
+
+ if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
+ printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
+ return -EINVAL;
+ }
+
+ if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
+ efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
+ printk(KERN_ERR "efivars: Malformed variable content\n");
+ return -EINVAL;
+ }
+
+ memcpy(&entry->var, new_var, count);
+
+ err = efivar_entry_set(entry, new_var->Attributes,
+ new_var->DataSize, new_var->Data, false);
+ if (err) {
+ printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
+ return -EIO;
+ }
+
+ return count;
+}
+
+static ssize_t
+efivar_show_raw(struct efivar_entry *entry, char *buf)
+{
+ struct efi_variable *var = &entry->var;
+
+ if (!entry || !buf)
+ return 0;
+
+ var->DataSize = 1024;
+ if (efivar_entry_get(entry, &entry->var.Attributes,
+ &entry->var.DataSize, entry->var.Data))
+ return -EIO;
+
+ memcpy(buf, var, sizeof(*var));
+
+ return sizeof(*var);
+}
+
+/*
+ * Generic read/write functions that call the specific functions of
+ * the attributes...
+ */
+static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct efivar_entry *var = to_efivar_entry(kobj);
+ struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
+ ssize_t ret = -EIO;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (efivar_attr->show) {
+ ret = efivar_attr->show(var, buf);
+ }
+ return ret;
+}
+
+static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct efivar_entry *var = to_efivar_entry(kobj);
+ struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
+ ssize_t ret = -EIO;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (efivar_attr->store)
+ ret = efivar_attr->store(var, buf, count);
+
+ return ret;
+}
+
+static const struct sysfs_ops efivar_attr_ops = {
+ .show = efivar_attr_show,
+ .store = efivar_attr_store,
+};
+
+static void efivar_release(struct kobject *kobj)
+{
+ struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
+ kfree(var);
+}
+
+static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
+static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
+static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
+static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
+static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
+
+static struct attribute *def_attrs[] = {
+ &efivar_attr_guid.attr,
+ &efivar_attr_size.attr,
+ &efivar_attr_attributes.attr,
+ &efivar_attr_data.attr,
+ &efivar_attr_raw_var.attr,
+ NULL,
+};
+
+static struct kobj_type efivar_ktype = {
+ .release = efivar_release,
+ .sysfs_ops = &efivar_attr_ops,
+ .default_attrs = def_attrs,
+};
+
+static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct efi_variable *new_var = (struct efi_variable *)buf;
+ struct efivar_entry *new_entry;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
+ efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
+ printk(KERN_ERR "efivars: Malformed variable content\n");
+ return -EINVAL;
+ }
+
+ new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
+ if (!new_entry)
+ return -ENOMEM;
+
+ memcpy(&new_entry->var, new_var, sizeof(*new_var));
+
+ err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize,
+ new_var->Data, &efivar_sysfs_list);
+ if (err) {
+ if (err == -EEXIST)
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (efivar_create_sysfs_entry(new_entry)) {
+ printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
+ kfree(new_entry);
+ }
+ return count;
+
+out:
+ kfree(new_entry);
+ return err;
+}
+
+static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct efi_variable *del_var = (struct efi_variable *)buf;
+ struct efivar_entry *entry;
+ int err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ efivar_entry_iter_begin();
+ entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid,
+ &efivar_sysfs_list, true);
+ if (!entry)
+ err = -EINVAL;
+ else if (__efivar_entry_delete(entry))
+ err = -EIO;
+
+ efivar_entry_iter_end();
+
+ if (err)
+ return err;
+
+ efivar_unregister(entry);
+
+ /* It's dead Jim.... */
+ return count;
+}
+
+/**
+ * efivar_create_sysfs_entry - create a new entry in sysfs
+ * @new_var: efivar entry to create
+ *
+ * Returns 1 on failure, 0 on success
+ */
+static int
+efivar_create_sysfs_entry(struct efivar_entry *new_var)
+{
+ int i, short_name_size;
+ char *short_name;
+ unsigned long variable_name_size;
+ efi_char16_t *variable_name;
+
+ variable_name = new_var->var.VariableName;
+ variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t);
+
+ /*
+ * Length of the variable bytes in ASCII, plus the '-' separator,
+ * plus the GUID, plus trailing NUL
+ */
+ short_name_size = variable_name_size / sizeof(efi_char16_t)
+ + 1 + EFI_VARIABLE_GUID_LEN + 1;
+
+ short_name = kzalloc(short_name_size, GFP_KERNEL);
+
+ if (!short_name)
+ return 1;
+
+ /* Convert Unicode to normal chars (assume top bits are 0),
+ ala UTF-8 */
+ for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
+ short_name[i] = variable_name[i] & 0xFF;
+ }
+ /* This is ugly, but necessary to separate one vendor's
+ private variables from another's. */
+
+ *(short_name + strlen(short_name)) = '-';
+ efi_guid_unparse(&new_var->var.VendorGuid,
+ short_name + strlen(short_name));
+
+ new_var->kobj.kset = efivars_kset;
+
+ i = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
+ NULL, "%s", short_name);
+ kfree(short_name);
+ if (i)
+ return 1;
+
+ kobject_uevent(&new_var->kobj, KOBJ_ADD);
+ efivar_entry_add(new_var, &efivar_sysfs_list);
+
+ return 0;
+}
+
+static int
+create_efivars_bin_attributes(void)
+{
+ struct bin_attribute *attr;
+ int error;
+
+ /* new_var */
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ attr->attr.name = "new_var";
+ attr->attr.mode = 0200;
+ attr->write = efivar_create;
+ efivars_new_var = attr;
+
+ /* del_var */
+ attr = kzalloc(sizeof(*attr), GFP_KERNEL);
+ if (!attr) {
+ error = -ENOMEM;
+ goto out_free;
+ }
+ attr->attr.name = "del_var";
+ attr->attr.mode = 0200;
+ attr->write = efivar_delete;
+ efivars_del_var = attr;
+
+ sysfs_bin_attr_init(efivars_new_var);
+ sysfs_bin_attr_init(efivars_del_var);
+
+ /* Register */
+ error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
+ if (error) {
+ printk(KERN_ERR "efivars: unable to create new_var sysfs file"
+ " due to error %d\n", error);
+ goto out_free;
+ }
+
+ error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
+ if (error) {
+ printk(KERN_ERR "efivars: unable to create del_var sysfs file"
+ " due to error %d\n", error);
+ sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
+ goto out_free;
+ }
+
+ return 0;
+out_free:
+ kfree(efivars_del_var);
+ efivars_del_var = NULL;
+ kfree(efivars_new_var);
+ efivars_new_var = NULL;
+ return error;
+}
+
+static int efivar_update_sysfs_entry(efi_char16_t *name, efi_guid_t vendor,
+ unsigned long name_size, void *data)
+{
+ struct efivar_entry *entry = data;
+
+ if (efivar_entry_find(name, vendor, &efivar_sysfs_list, false))
+ return 0;
+
+ memcpy(entry->var.VariableName, name, name_size);
+ memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
+
+ return 1;
+}
+
+static void efivar_update_sysfs_entries(struct work_struct *work)
+{
+ struct efivar_entry *entry;
+ int err;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return;
+
+ /* Add new sysfs entries */
+ while (1) {
+ memset(entry, 0, sizeof(*entry));
+
+ err = efivar_init(efivar_update_sysfs_entry, entry,
+ true, false, &efivar_sysfs_list);
+ if (!err)
+ break;
+
+ efivar_create_sysfs_entry(entry);
+ }
+
+ kfree(entry);
+}
+
+static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
+ unsigned long name_size, void *data)
+{
+ struct efivar_entry *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ memcpy(entry->var.VariableName, name, name_size);
+ memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
+
+ efivar_create_sysfs_entry(entry);
+
+ return 0;
+}
+
+static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
+{
+ efivar_entry_remove(entry);
+ efivar_unregister(entry);
+ return 0;
+}
+
+void efivars_sysfs_exit(void)
+{
+ /* Remove all entries and destroy */
+ __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL);
+
+ if (efivars_new_var)
+ sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
+ if (efivars_del_var)
+ sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
+ kfree(efivars_new_var);
+ kfree(efivars_del_var);
+ kset_unregister(efivars_kset);
+}
+
+int efivars_sysfs_init(void)
+{
+ struct kobject *parent_kobj = efivars_kobject();
+ int error = 0;
+
+ /* No efivars has been registered yet */
+ if (!parent_kobj)
+ return 0;
+
+ printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
+ EFIVARS_DATE);
+
+ efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
+ if (!efivars_kset) {
+ printk(KERN_ERR "efivars: Subsystem registration failed.\n");
+ return -ENOMEM;
+ }
+
+ efivar_init(efivars_sysfs_callback, NULL, false,
+ true, &efivar_sysfs_list);
+
+ error = create_efivars_bin_attributes();
+ if (error) {
+ efivars_sysfs_exit();
+ return error;
+ }
+
+ INIT_WORK(&efivar_work, efivar_update_sysfs_entries);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(efivars_sysfs_init);
+
+module_init(efivars_sysfs_init);
+module_exit(efivars_sysfs_exit);
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
new file mode 100644
index 000000000000..391c67b182d9
--- /dev/null
+++ b/drivers/firmware/efi/vars.c
@@ -0,0 +1,1041 @@
+/*
+ * Originally from efivars.c
+ *
+ * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
+ * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/capability.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/efi.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/ucs2_string.h>
+
+/* Private pointer to registered efivars */
+static struct efivars *__efivars;
+
+static bool efivar_wq_enabled = true;
+DECLARE_WORK(efivar_work, NULL);
+EXPORT_SYMBOL_GPL(efivar_work);
+
+static bool
+validate_device_path(struct efi_variable *var, int match, u8 *buffer,
+ unsigned long len)
+{
+ struct efi_generic_dev_path *node;
+ int offset = 0;
+
+ node = (struct efi_generic_dev_path *)buffer;
+
+ if (len < sizeof(*node))
+ return false;
+
+ while (offset <= len - sizeof(*node) &&
+ node->length >= sizeof(*node) &&
+ node->length <= len - offset) {
+ offset += node->length;
+
+ if ((node->type == EFI_DEV_END_PATH ||
+ node->type == EFI_DEV_END_PATH2) &&
+ node->sub_type == EFI_DEV_END_ENTIRE)
+ return true;
+
+ node = (struct efi_generic_dev_path *)(buffer + offset);
+ }
+
+ /*
+ * If we're here then either node->length pointed past the end
+ * of the buffer or we reached the end of the buffer without
+ * finding a device path end node.
+ */
+ return false;
+}
+
+static bool
+validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
+ unsigned long len)
+{
+ /* An array of 16-bit integers */
+ if ((len % 2) != 0)
+ return false;
+
+ return true;
+}
+
+static bool
+validate_load_option(struct efi_variable *var, int match, u8 *buffer,
+ unsigned long len)
+{
+ u16 filepathlength;
+ int i, desclength = 0, namelen;
+
+ namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));
+
+ /* Either "Boot" or "Driver" followed by four digits of hex */
+ for (i = match; i < match+4; i++) {
+ if (var->VariableName[i] > 127 ||
+ hex_to_bin(var->VariableName[i] & 0xff) < 0)
+ return true;
+ }
+
+ /* Reject it if there's 4 digits of hex and then further content */
+ if (namelen > match + 4)
+ return false;
+
+ /* A valid entry must be at least 8 bytes */
+ if (len < 8)
+ return false;
+
+ filepathlength = buffer[4] | buffer[5] << 8;
+
+ /*
+ * There's no stored length for the description, so it has to be
+ * found by hand
+ */
+ desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
+
+ /* Each boot entry must have a descriptor */
+ if (!desclength)
+ return false;
+
+ /*
+ * If the sum of the length of the description, the claimed filepath
+ * length and the original header are greater than the length of the
+ * variable, it's malformed
+ */
+ if ((desclength + filepathlength + 6) > len)
+ return false;
+
+ /*
+ * And, finally, check the filepath
+ */
+ return validate_device_path(var, match, buffer + desclength + 6,
+ filepathlength);
+}
+
+static bool
+validate_uint16(struct efi_variable *var, int match, u8 *buffer,
+ unsigned long len)
+{
+ /* A single 16-bit integer */
+ if (len != 2)
+ return false;
+
+ return true;
+}
+
+static bool
+validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
+ unsigned long len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] > 127)
+ return false;
+
+ if (buffer[i] == 0)
+ return true;
+ }
+
+ return false;
+}
+
+struct variable_validate {
+ char *name;
+ bool (*validate)(struct efi_variable *var, int match, u8 *data,
+ unsigned long len);
+};
+
+static const struct variable_validate variable_validate[] = {
+ { "BootNext", validate_uint16 },
+ { "BootOrder", validate_boot_order },
+ { "DriverOrder", validate_boot_order },
+ { "Boot*", validate_load_option },
+ { "Driver*", validate_load_option },
+ { "ConIn", validate_device_path },
+ { "ConInDev", validate_device_path },
+ { "ConOut", validate_device_path },
+ { "ConOutDev", validate_device_path },
+ { "ErrOut", validate_device_path },
+ { "ErrOutDev", validate_device_path },
+ { "Timeout", validate_uint16 },
+ { "Lang", validate_ascii_string },
+ { "PlatformLang", validate_ascii_string },
+ { "", NULL },
+};
+
+bool
+efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
+{
+ int i;
+ u16 *unicode_name = var->VariableName;
+
+ for (i = 0; variable_validate[i].validate != NULL; i++) {
+ const char *name = variable_validate[i].name;
+ int match;
+
+ for (match = 0; ; match++) {
+ char c = name[match];
+ u16 u = unicode_name[match];
+
+ /* All special variables are plain ascii */
+ if (u > 127)
+ return true;
+
+ /* Wildcard in the matching name means we've matched */
+ if (c == '*')
+ return variable_validate[i].validate(var,
+ match, data, len);
+
+ /* Case sensitive match */
+ if (c != u)
+ break;
+
+ /* Reached the end of the string while matching */
+ if (!c)
+ return variable_validate[i].validate(var,
+ match, data, len);
+ }
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(efivar_validate);
+
+static efi_status_t
+check_var_size(u32 attributes, unsigned long size)
+{
+ const struct efivar_operations *fops = __efivars->ops;
+
+ if (!fops->query_variable_store)
+ return EFI_UNSUPPORTED;
+
+ return fops->query_variable_store(attributes, size);
+}
+
+static int efi_status_to_err(efi_status_t status)
+{
+ int err;
+
+ switch (status) {
+ case EFI_SUCCESS:
+ err = 0;
+ break;
+ case EFI_INVALID_PARAMETER:
+ err = -EINVAL;
+ break;
+ case EFI_OUT_OF_RESOURCES:
+ err = -ENOSPC;
+ break;
+ case EFI_DEVICE_ERROR:
+ err = -EIO;
+ break;
+ case EFI_WRITE_PROTECTED:
+ err = -EROFS;
+ break;
+ case EFI_SECURITY_VIOLATION:
+ err = -EACCES;
+ break;
+ case EFI_NOT_FOUND:
+ err = -ENOENT;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor,
+ struct list_head *head)
+{
+ struct efivar_entry *entry, *n;
+ unsigned long strsize1, strsize2;
+ bool found = false;
+
+ strsize1 = ucs2_strsize(variable_name, 1024);
+ list_for_each_entry_safe(entry, n, head, list) {
+ strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
+ if (strsize1 == strsize2 &&
+ !memcmp(variable_name, &(entry->var.VariableName),
+ strsize2) &&
+ !efi_guidcmp(entry->var.VendorGuid,
+ *vendor)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+/*
+ * Returns the size of variable_name, in bytes, including the
+ * terminating NULL character, or variable_name_size if no NULL
+ * character is found among the first variable_name_size bytes.
+ */
+static unsigned long var_name_strnsize(efi_char16_t *variable_name,
+ unsigned long variable_name_size)
+{
+ unsigned long len;
+ efi_char16_t c;
+
+ /*
+ * The variable name is, by definition, a NULL-terminated
+ * string, so make absolutely sure that variable_name_size is
+ * the value we expect it to be. If not, return the real size.
+ */
+ for (len = 2; len <= variable_name_size; len += sizeof(c)) {
+ c = variable_name[(len / sizeof(c)) - 1];
+ if (!c)
+ break;
+ }
+
+ return min(len, variable_name_size);
+}
+
+/*
+ * Print a warning when duplicate EFI variables are encountered and
+ * disable the sysfs workqueue since the firmware is buggy.
+ */
+static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
+ unsigned long len16)
+{
+ size_t i, len8 = len16 / sizeof(efi_char16_t);
+ char *s8;
+
+ /*
+ * Disable the workqueue since the algorithm it uses for
+ * detecting new variables won't work with this buggy
+ * implementation of GetNextVariableName().
+ */
+ efivar_wq_enabled = false;
+
+ s8 = kzalloc(len8, GFP_KERNEL);
+ if (!s8)
+ return;
+
+ for (i = 0; i < len8; i++)
+ s8[i] = s16[i];
+
+ printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
+ s8, vendor_guid);
+ kfree(s8);
+}
+
+/**
+ * efivar_init - build the initial list of EFI variables
+ * @func: callback function to invoke for every variable
+ * @data: function-specific data to pass to @func
+ * @atomic: do we need to execute the @func-loop atomically?
+ * @duplicates: error if we encounter duplicates on @head?
+ * @head: initialised head of variable list
+ *
+ * Get every EFI variable from the firmware and invoke @func. @func
+ * should call efivar_entry_add() to build the list of variables.
+ *
+ * Returns 0 on success, or a kernel error code on failure.
+ */
+int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
+ void *data, bool atomic, bool duplicates,
+ struct list_head *head)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ unsigned long variable_name_size = 1024;
+ efi_char16_t *variable_name;
+ efi_status_t status;
+ efi_guid_t vendor_guid;
+ int err = 0;
+
+ variable_name = kzalloc(variable_name_size, GFP_KERNEL);
+ if (!variable_name) {
+ printk(KERN_ERR "efivars: Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_irq(&__efivars->lock);
+
+ /*
+ * Per EFI spec, the maximum storage allocated for both
+ * the variable name and variable data is 1024 bytes.
+ */
+
+ do {
+ variable_name_size = 1024;
+
+ status = ops->get_next_variable(&variable_name_size,
+ variable_name,
+ &vendor_guid);
+ switch (status) {
+ case EFI_SUCCESS:
+ if (!atomic)
+ spin_unlock_irq(&__efivars->lock);
+
+ variable_name_size = var_name_strnsize(variable_name,
+ variable_name_size);
+
+ /*
+ * Some firmware implementations return the
+ * same variable name on multiple calls to
+ * get_next_variable(). Terminate the loop
+ * immediately as there is no guarantee that
+ * we'll ever see a different variable name,
+ * and may end up looping here forever.
+ */
+ if (duplicates &&
+ variable_is_present(variable_name, &vendor_guid, head)) {
+ dup_variable_bug(variable_name, &vendor_guid,
+ variable_name_size);
+ if (!atomic)
+ spin_lock_irq(&__efivars->lock);
+
+ status = EFI_NOT_FOUND;
+ break;
+ }
+
+ err = func(variable_name, vendor_guid, variable_name_size, data);
+ if (err)
+ status = EFI_NOT_FOUND;
+
+ if (!atomic)
+ spin_lock_irq(&__efivars->lock);
+
+ break;
+ case EFI_NOT_FOUND:
+ break;
+ default:
+ printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
+ status);
+ status = EFI_NOT_FOUND;
+ break;
+ }
+
+ } while (status != EFI_NOT_FOUND);
+
+ spin_unlock_irq(&__efivars->lock);
+
+ kfree(variable_name);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(efivar_init);
+
+/**
+ * efivar_entry_add - add entry to variable list
+ * @entry: entry to add to list
+ * @head: list head
+ */
+void efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
+{
+ spin_lock_irq(&__efivars->lock);
+ list_add(&entry->list, head);
+ spin_unlock_irq(&__efivars->lock);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_add);
+
+/**
+ * efivar_entry_remove - remove entry from variable list
+ * @entry: entry to remove from list
+ */
+void efivar_entry_remove(struct efivar_entry *entry)
+{
+ spin_lock_irq(&__efivars->lock);
+ list_del(&entry->list);
+ spin_unlock_irq(&__efivars->lock);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_remove);
+
+/*
+ * efivar_entry_list_del_unlock - remove entry from variable list
+ * @entry: entry to remove
+ *
+ * Remove @entry from the variable list and release the list lock.
+ *
+ * NOTE: slightly weird locking semantics here - we expect to be
+ * called with the efivars lock already held, and we release it before
+ * returning. This is because this function is usually called after
+ * set_variable() while the lock is still held.
+ */
+static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
+{
+ WARN_ON(!spin_is_locked(&__efivars->lock));
+
+ list_del(&entry->list);
+ spin_unlock_irq(&__efivars->lock);
+}
+
+/**
+ * __efivar_entry_delete - delete an EFI variable
+ * @entry: entry containing EFI variable to delete
+ *
+ * Delete the variable from the firmware but leave @entry on the
+ * variable list.
+ *
+ * This function differs from efivar_entry_delete() because it does
+ * not remove @entry from the variable list. Also, it is safe to be
+ * called from within a efivar_entry_iter_begin() and
+ * efivar_entry_iter_end() region, unlike efivar_entry_delete().
+ *
+ * Returns 0 on success, or a converted EFI status code if
+ * set_variable() fails.
+ */
+int __efivar_entry_delete(struct efivar_entry *entry)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+
+ WARN_ON(!spin_is_locked(&__efivars->lock));
+
+ status = ops->set_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ 0, 0, NULL);
+
+ return efi_status_to_err(status);
+}
+EXPORT_SYMBOL_GPL(__efivar_entry_delete);
+
+/**
+ * efivar_entry_delete - delete variable and remove entry from list
+ * @entry: entry containing variable to delete
+ *
+ * Delete the variable from the firmware and remove @entry from the
+ * variable list. It is the caller's responsibility to free @entry
+ * once we return.
+ *
+ * Returns 0 on success, or a converted EFI status code if
+ * set_variable() fails.
+ */
+int efivar_entry_delete(struct efivar_entry *entry)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+
+ spin_lock_irq(&__efivars->lock);
+ status = ops->set_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ 0, 0, NULL);
+ if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
+ spin_unlock_irq(&__efivars->lock);
+ return efi_status_to_err(status);
+ }
+
+ efivar_entry_list_del_unlock(entry);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(efivar_entry_delete);
+
+/**
+ * efivar_entry_set - call set_variable()
+ * @entry: entry containing the EFI variable to write
+ * @attributes: variable attributes
+ * @size: size of @data buffer
+ * @data: buffer containing variable data
+ * @head: head of variable list
+ *
+ * Calls set_variable() for an EFI variable. If creating a new EFI
+ * variable, this function is usually followed by efivar_entry_add().
+ *
+ * Before writing the variable, the remaining EFI variable storage
+ * space is checked to ensure there is enough room available.
+ *
+ * If @head is not NULL a lookup is performed to determine whether
+ * the entry is already on the list.
+ *
+ * Returns 0 on success, -EEXIST if a lookup is performed and the entry
+ * already exists on the list, or a converted EFI status code if
+ * set_variable() fails.
+ */
+int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
+ unsigned long size, void *data, struct list_head *head)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+ efi_char16_t *name = entry->var.VariableName;
+ efi_guid_t vendor = entry->var.VendorGuid;
+
+ spin_lock_irq(&__efivars->lock);
+
+ if (head && efivar_entry_find(name, vendor, head, false)) {
+ spin_unlock_irq(&__efivars->lock);
+ return -EEXIST;
+ }
+
+ status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
+ if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
+ status = ops->set_variable(name, &vendor,
+ attributes, size, data);
+
+ spin_unlock_irq(&__efivars->lock);
+
+ return efi_status_to_err(status);
+
+}
+EXPORT_SYMBOL_GPL(efivar_entry_set);
+
+/**
+ * efivar_entry_set_safe - call set_variable() if enough space in firmware
+ * @name: buffer containing the variable name
+ * @vendor: variable vendor guid
+ * @attributes: variable attributes
+ * @block: can we block in this context?
+ * @size: size of @data buffer
+ * @data: buffer containing variable data
+ *
+ * Ensures there is enough free storage in the firmware for this variable, and
+ * if so, calls set_variable(). If creating a new EFI variable, this function
+ * is usually followed by efivar_entry_add().
+ *
+ * Returns 0 on success, -ENOSPC if the firmware does not have enough
+ * space for set_variable() to succeed, or a converted EFI status code
+ * if set_variable() fails.
+ */
+int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
+ bool block, unsigned long size, void *data)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ unsigned long flags;
+ efi_status_t status;
+
+ if (!ops->query_variable_store)
+ return -ENOSYS;
+
+ if (!block) {
+ if (!spin_trylock_irqsave(&__efivars->lock, flags))
+ return -EBUSY;
+ } else {
+ spin_lock_irqsave(&__efivars->lock, flags);
+ }
+
+ status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
+ if (status != EFI_SUCCESS) {
+ spin_unlock_irqrestore(&__efivars->lock, flags);
+ return -ENOSPC;
+ }
+
+ status = ops->set_variable(name, &vendor, attributes, size, data);
+
+ spin_unlock_irqrestore(&__efivars->lock, flags);
+
+ return efi_status_to_err(status);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_set_safe);
+
+/**
+ * efivar_entry_find - search for an entry
+ * @name: the EFI variable name
+ * @guid: the EFI variable vendor's guid
+ * @head: head of the variable list
+ * @remove: should we remove the entry from the list?
+ *
+ * Search for an entry on the variable list that has the EFI variable
+ * name @name and vendor guid @guid. If an entry is found on the list
+ * and @remove is true, the entry is removed from the list.
+ *
+ * The caller MUST call efivar_entry_iter_begin() and
+ * efivar_entry_iter_end() before and after the invocation of this
+ * function, respectively.
+ *
+ * Returns the entry if found on the list, %NULL otherwise.
+ */
+struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
+ struct list_head *head, bool remove)
+{
+ struct efivar_entry *entry, *n;
+ int strsize1, strsize2;
+ bool found = false;
+
+ WARN_ON(!spin_is_locked(&__efivars->lock));
+
+ list_for_each_entry_safe(entry, n, head, list) {
+ strsize1 = ucs2_strsize(name, 1024);
+ strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
+ if (strsize1 == strsize2 &&
+ !memcmp(name, &(entry->var.VariableName), strsize1) &&
+ !efi_guidcmp(guid, entry->var.VendorGuid)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return NULL;
+
+ if (remove)
+ list_del(&entry->list);
+
+ return entry;
+}
+EXPORT_SYMBOL_GPL(efivar_entry_find);
+
+/**
+ * efivar_entry_size - obtain the size of a variable
+ * @entry: entry for this variable
+ * @size: location to store the variable's size
+ */
+int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+
+ *size = 0;
+
+ spin_lock_irq(&__efivars->lock);
+ status = ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid, NULL, size, NULL);
+ spin_unlock_irq(&__efivars->lock);
+
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return efi_status_to_err(status);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(efivar_entry_size);
+
+/**
+ * __efivar_entry_get - call get_variable()
+ * @entry: read data for this variable
+ * @attributes: variable attributes
+ * @size: size of @data buffer
+ * @data: buffer to store variable data
+ *
+ * The caller MUST call efivar_entry_iter_begin() and
+ * efivar_entry_iter_end() before and after the invocation of this
+ * function, respectively.
+ */
+int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
+ unsigned long *size, void *data)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+
+ WARN_ON(!spin_is_locked(&__efivars->lock));
+
+ status = ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ attributes, size, data);
+
+ return efi_status_to_err(status);
+}
+EXPORT_SYMBOL_GPL(__efivar_entry_get);
+
+/**
+ * efivar_entry_get - call get_variable()
+ * @entry: read data for this variable
+ * @attributes: variable attributes
+ * @size: size of @data buffer
+ * @data: buffer to store variable data
+ */
+int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
+ unsigned long *size, void *data)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_status_t status;
+
+ spin_lock_irq(&__efivars->lock);
+ status = ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ attributes, size, data);
+ spin_unlock_irq(&__efivars->lock);
+
+ return efi_status_to_err(status);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_get);
+
+/**
+ * efivar_entry_set_get_size - call set_variable() and get new size (atomic)
+ * @entry: entry containing variable to set and get
+ * @attributes: attributes of variable to be written
+ * @size: size of data buffer
+ * @data: buffer containing data to write
+ * @set: did the set_variable() call succeed?
+ *
+ * This is a pretty special (complex) function. See efivarfs_file_write().
+ *
+ * Atomically call set_variable() for @entry and if the call is
+ * successful, return the new size of the variable from get_variable()
+ * in @size. The success of set_variable() is indicated by @set.
+ *
+ * Returns 0 on success, -EINVAL if the variable data is invalid,
+ * -ENOSPC if the firmware does not have enough available space, or a
+ * converted EFI status code if either of set_variable() or
+ * get_variable() fail.
+ *
+ * If the EFI variable does not exist when calling set_variable()
+ * (EFI_NOT_FOUND), @entry is removed from the variable list.
+ */
+int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
+ unsigned long *size, void *data, bool *set)
+{
+ const struct efivar_operations *ops = __efivars->ops;
+ efi_char16_t *name = entry->var.VariableName;
+ efi_guid_t *vendor = &entry->var.VendorGuid;
+ efi_status_t status;
+ int err;
+
+ *set = false;
+
+ if (efivar_validate(&entry->var, data, *size) == false)
+ return -EINVAL;
+
+ /*
+ * The lock here protects the get_variable call, the conditional
+ * set_variable call, and removal of the variable from the efivars
+ * list (in the case of an authenticated delete).
+ */
+ spin_lock_irq(&__efivars->lock);
+
+ /*
+ * Ensure that the available space hasn't shrunk below the safe level
+ */
+ status = check_var_size(attributes, *size + ucs2_strsize(name, 1024));
+ if (status != EFI_SUCCESS) {
+ if (status != EFI_UNSUPPORTED) {
+ err = efi_status_to_err(status);
+ goto out;
+ }
+
+ if (*size > 65536) {
+ err = -ENOSPC;
+ goto out;
+ }
+ }
+
+ status = ops->set_variable(name, vendor, attributes, *size, data);
+ if (status != EFI_SUCCESS) {
+ err = efi_status_to_err(status);
+ goto out;
+ }
+
+ *set = true;
+
+ /*
+ * Writing to the variable may have caused a change in size (which
+ * could either be an append or an overwrite), or the variable to be
+ * deleted. Perform a GetVariable() so we can tell what actually
+ * happened.
+ */
+ *size = 0;
+ status = ops->get_variable(entry->var.VariableName,
+ &entry->var.VendorGuid,
+ NULL, size, NULL);
+
+ if (status == EFI_NOT_FOUND)
+ efivar_entry_list_del_unlock(entry);
+ else
+ spin_unlock_irq(&__efivars->lock);
+
+ if (status && status != EFI_BUFFER_TOO_SMALL)
+ return efi_status_to_err(status);
+
+ return 0;
+
+out:
+ spin_unlock_irq(&__efivars->lock);
+ return err;
+
+}
+EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
+
+/**
+ * efivar_entry_iter_begin - begin iterating the variable list
+ *
+ * Lock the variable list to prevent entry insertion and removal until
+ * efivar_entry_iter_end() is called. This function is usually used in
+ * conjunction with __efivar_entry_iter() or efivar_entry_iter().
+ */
+void efivar_entry_iter_begin(void)
+{
+ spin_lock_irq(&__efivars->lock);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
+
+/**
+ * efivar_entry_iter_end - finish iterating the variable list
+ *
+ * Unlock the variable list and allow modifications to the list again.
+ */
+void efivar_entry_iter_end(void)
+{
+ spin_unlock_irq(&__efivars->lock);
+}
+EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
+
+/**
+ * __efivar_entry_iter - iterate over variable list
+ * @func: callback function
+ * @head: head of the variable list
+ * @data: function-specific data to pass to callback
+ * @prev: entry to begin iterating from
+ *
+ * Iterate over the list of EFI variables and call @func with every
+ * entry on the list. It is safe for @func to remove entries in the
+ * list via efivar_entry_delete().
+ *
+ * You MUST call efivar_enter_iter_begin() before this function, and
+ * efivar_entry_iter_end() afterwards.
+ *
+ * It is possible to begin iteration from an arbitrary entry within
+ * the list by passing @prev. @prev is updated on return to point to
+ * the last entry passed to @func. To begin iterating from the
+ * beginning of the list @prev must be %NULL.
+ *
+ * The restrictions for @func are the same as documented for
+ * efivar_entry_iter().
+ */
+int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
+ struct list_head *head, void *data,
+ struct efivar_entry **prev)
+{
+ struct efivar_entry *entry, *n;
+ int err = 0;
+
+ if (!prev || !*prev) {
+ list_for_each_entry_safe(entry, n, head, list) {
+ err = func(entry, data);
+ if (err)
+ break;
+ }
+
+ if (prev)
+ *prev = entry;
+
+ return err;
+ }
+
+
+ list_for_each_entry_safe_continue((*prev), n, head, list) {
+ err = func(*prev, data);
+ if (err)
+ break;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(__efivar_entry_iter);
+
+/**
+ * efivar_entry_iter - iterate over variable list
+ * @func: callback function
+ * @head: head of variable list
+ * @data: function-specific data to pass to callback
+ *
+ * Iterate over the list of EFI variables and call @func with every
+ * entry on the list. It is safe for @func to remove entries in the
+ * list via efivar_entry_delete() while iterating.
+ *
+ * Some notes for the callback function:
+ * - a non-zero return value indicates an error and terminates the loop
+ * - @func is called from atomic context
+ */
+int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
+ struct list_head *head, void *data)
+{
+ int err = 0;
+
+ efivar_entry_iter_begin();
+ err = __efivar_entry_iter(func, head, data, NULL);
+ efivar_entry_iter_end();
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(efivar_entry_iter);
+
+/**
+ * efivars_kobject - get the kobject for the registered efivars
+ *
+ * If efivars_register() has not been called we return NULL,
+ * otherwise return the kobject used at registration time.
+ */
+struct kobject *efivars_kobject(void)
+{
+ if (!__efivars)
+ return NULL;
+
+ return __efivars->kobject;
+}
+EXPORT_SYMBOL_GPL(efivars_kobject);
+
+/**
+ * efivar_run_worker - schedule the efivar worker thread
+ */
+void efivar_run_worker(void)
+{
+ if (efivar_wq_enabled)
+ schedule_work(&efivar_work);
+}
+EXPORT_SYMBOL_GPL(efivar_run_worker);
+
+/**
+ * efivars_register - register an efivars
+ * @efivars: efivars to register
+ * @ops: efivars operations
+ * @kobject: @efivars-specific kobject
+ *
+ * Only a single efivars can be registered at any time.
+ */
+int efivars_register(struct efivars *efivars,
+ const struct efivar_operations *ops,
+ struct kobject *kobject)
+{
+ spin_lock_init(&efivars->lock);
+ efivars->ops = ops;
+ efivars->kobject = kobject;
+
+ __efivars = efivars;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(efivars_register);
+
+/**
+ * efivars_unregister - unregister an efivars
+ * @efivars: efivars to unregister
+ *
+ * The caller must have already removed every entry from the list,
+ * failure to do so is an error.
+ */
+int efivars_unregister(struct efivars *efivars)
+{
+ int rv;
+
+ if (!__efivars) {
+ printk(KERN_ERR "efivars not registered\n");
+ rv = -EINVAL;
+ goto out;
+ }
+
+ if (__efivars != efivars) {
+ rv = -EINVAL;
+ goto out;
+ }
+
+ __efivars = NULL;
+
+ rv = 0;
+out:
+ return rv;
+}
+EXPORT_SYMBOL_GPL(efivars_unregister);
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
deleted file mode 100644
index 0f1026019c0f..000000000000
--- a/drivers/firmware/efivars.c
+++ /dev/null
@@ -1,2172 +0,0 @@
-/*
- * EFI Variables - efivars.c
- *
- * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
- * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
- *
- * This code takes all variables accessible from EFI runtime and
- * exports them via sysfs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Changelog:
- *
- * 17 May 2004 - Matt Domsch <Matt_Domsch@dell.com>
- * remove check for efi_enabled in exit
- * add MODULE_VERSION
- *
- * 26 Apr 2004 - Matt Domsch <Matt_Domsch@dell.com>
- * minor bug fixes
- *
- * 21 Apr 2004 - Matt Tolentino <matthew.e.tolentino@intel.com)
- * converted driver to export variable information via sysfs
- * and moved to drivers/firmware directory
- * bumped revision number to v0.07 to reflect conversion & move
- *
- * 10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
- * fix locking per Peter Chubb's findings
- *
- * 25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
- * move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
- *
- * 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
- * use list_for_each_safe when deleting vars.
- * remove ifdef CONFIG_SMP around include <linux/smp.h>
- * v0.04 release to linux-ia64@linuxia64.org
- *
- * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
- * Moved vars from /proc/efi to /proc/efi/vars, and made
- * efi.c own the /proc/efi directory.
- * v0.03 release to linux-ia64@linuxia64.org
- *
- * 26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
- * At the request of Stephane, moved ownership of /proc/efi
- * to efi.c, and now efivars lives under /proc/efi/vars.
- *
- * 12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
- * Feedback received from Stephane Eranian incorporated.
- * efivar_write() checks copy_from_user() return value.
- * efivar_read/write() returns proper errno.
- * v0.02 release to linux-ia64@linuxia64.org
- *
- * 26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
- * v0.01 release to linux-ia64@linuxia64.org
- */
-
-#include <linux/capability.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/efi.h>
-#include <linux/sysfs.h>
-#include <linux/kobject.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/pstore.h>
-#include <linux/ctype.h>
-#include <linux/magic.h>
-
-#include <linux/fs.h>
-#include <linux/ramfs.h>
-#include <linux/pagemap.h>
-
-#include <asm/uaccess.h>
-
-#define EFIVARS_VERSION "0.08"
-#define EFIVARS_DATE "2004-May-17"
-
-MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
-MODULE_DESCRIPTION("sysfs interface to EFI Variables");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(EFIVARS_VERSION);
-
-#define DUMP_NAME_LEN 52
-
-/*
- * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
- * not including trailing NUL
- */
-#define GUID_LEN 36
-
-static bool efivars_pstore_disable =
- IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
-
-module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
-
-/*
- * The maximum size of VariableName + Data = 1024
- * Therefore, it's reasonable to save that much
- * space in each part of the structure,
- * and we use a page for reading/writing.
- */
-
-struct efi_variable {
- efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
- efi_guid_t VendorGuid;
- unsigned long DataSize;
- __u8 Data[1024];
- efi_status_t Status;
- __u32 Attributes;
-} __attribute__((packed));
-
-struct efivar_entry {
- struct efivars *efivars;
- struct efi_variable var;
- struct list_head list;
- struct kobject kobj;
-};
-
-struct efivar_attribute {
- struct attribute attr;
- ssize_t (*show) (struct efivar_entry *entry, char *buf);
- ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
-};
-
-static struct efivars __efivars;
-static struct efivar_operations ops;
-
-#define PSTORE_EFI_ATTRIBUTES \
- (EFI_VARIABLE_NON_VOLATILE | \
- EFI_VARIABLE_BOOTSERVICE_ACCESS | \
- EFI_VARIABLE_RUNTIME_ACCESS)
-
-#define EFIVAR_ATTR(_name, _mode, _show, _store) \
-struct efivar_attribute efivar_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode}, \
- .show = _show, \
- .store = _store, \
-};
-
-#define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
-#define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj)
-
-/*
- * Prototype for sysfs creation function
- */
-static int
-efivar_create_sysfs_entry(struct efivars *efivars,
- unsigned long variable_name_size,
- efi_char16_t *variable_name,
- efi_guid_t *vendor_guid);
-
-/*
- * Prototype for workqueue functions updating sysfs entry
- */
-
-static void efivar_update_sysfs_entries(struct work_struct *);
-static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
-static bool efivar_wq_enabled = true;
-
-/* Return the number of unicode characters in data */
-static unsigned long
-utf16_strnlen(efi_char16_t *s, size_t maxlength)
-{
- unsigned long length = 0;
-
- while (*s++ != 0 && length < maxlength)
- length++;
- return length;
-}
-
-static inline unsigned long
-utf16_strlen(efi_char16_t *s)
-{
- return utf16_strnlen(s, ~0UL);
-}
-
-/*
- * Return the number of bytes is the length of this string
- * Note: this is NOT the same as the number of unicode characters
- */
-static inline unsigned long
-utf16_strsize(efi_char16_t *data, unsigned long maxlength)
-{
- return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
-}
-
-static inline int
-utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
-{
- while (1) {
- if (len == 0)
- return 0;
- if (*a < *b)
- return -1;
- if (*a > *b)
- return 1;
- if (*a == 0) /* implies *b == 0 */
- return 0;
- a++;
- b++;
- len--;
- }
-}
-
-static bool
-validate_device_path(struct efi_variable *var, int match, u8 *buffer,
- unsigned long len)
-{
- struct efi_generic_dev_path *node;
- int offset = 0;
-
- node = (struct efi_generic_dev_path *)buffer;
-
- if (len < sizeof(*node))
- return false;
-
- while (offset <= len - sizeof(*node) &&
- node->length >= sizeof(*node) &&
- node->length <= len - offset) {
- offset += node->length;
-
- if ((node->type == EFI_DEV_END_PATH ||
- node->type == EFI_DEV_END_PATH2) &&
- node->sub_type == EFI_DEV_END_ENTIRE)
- return true;
-
- node = (struct efi_generic_dev_path *)(buffer + offset);
- }
-
- /*
- * If we're here then either node->length pointed past the end
- * of the buffer or we reached the end of the buffer without
- * finding a device path end node.
- */
- return false;
-}
-
-static bool
-validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
- unsigned long len)
-{
- /* An array of 16-bit integers */
- if ((len % 2) != 0)
- return false;
-
- return true;
-}
-
-static bool
-validate_load_option(struct efi_variable *var, int match, u8 *buffer,
- unsigned long len)
-{
- u16 filepathlength;
- int i, desclength = 0, namelen;
-
- namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName));
-
- /* Either "Boot" or "Driver" followed by four digits of hex */
- for (i = match; i < match+4; i++) {
- if (var->VariableName[i] > 127 ||
- hex_to_bin(var->VariableName[i] & 0xff) < 0)
- return true;
- }
-
- /* Reject it if there's 4 digits of hex and then further content */
- if (namelen > match + 4)
- return false;
-
- /* A valid entry must be at least 8 bytes */
- if (len < 8)
- return false;
-
- filepathlength = buffer[4] | buffer[5] << 8;
-
- /*
- * There's no stored length for the description, so it has to be
- * found by hand
- */
- desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
-
- /* Each boot entry must have a descriptor */
- if (!desclength)
- return false;
-
- /*
- * If the sum of the length of the description, the claimed filepath
- * length and the original header are greater than the length of the
- * variable, it's malformed
- */
- if ((desclength + filepathlength + 6) > len)
- return false;
-
- /*
- * And, finally, check the filepath
- */
- return validate_device_path(var, match, buffer + desclength + 6,
- filepathlength);
-}
-
-static bool
-validate_uint16(struct efi_variable *var, int match, u8 *buffer,
- unsigned long len)
-{
- /* A single 16-bit integer */
- if (len != 2)
- return false;
-
- return true;
-}
-
-static bool
-validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
- unsigned long len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- if (buffer[i] > 127)
- return false;
-
- if (buffer[i] == 0)
- return true;
- }
-
- return false;
-}
-
-struct variable_validate {
- char *name;
- bool (*validate)(struct efi_variable *var, int match, u8 *data,
- unsigned long len);
-};
-
-static const struct variable_validate variable_validate[] = {
- { "BootNext", validate_uint16 },
- { "BootOrder", validate_boot_order },
- { "DriverOrder", validate_boot_order },
- { "Boot*", validate_load_option },
- { "Driver*", validate_load_option },
- { "ConIn", validate_device_path },
- { "ConInDev", validate_device_path },
- { "ConOut", validate_device_path },
- { "ConOutDev", validate_device_path },
- { "ErrOut", validate_device_path },
- { "ErrOutDev", validate_device_path },
- { "Timeout", validate_uint16 },
- { "Lang", validate_ascii_string },
- { "PlatformLang", validate_ascii_string },
- { "", NULL },
-};
-
-static bool
-validate_var(struct efi_variable *var, u8 *data, unsigned long len)
-{
- int i;
- u16 *unicode_name = var->VariableName;
-
- for (i = 0; variable_validate[i].validate != NULL; i++) {
- const char *name = variable_validate[i].name;
- int match;
-
- for (match = 0; ; match++) {
- char c = name[match];
- u16 u = unicode_name[match];
-
- /* All special variables are plain ascii */
- if (u > 127)
- return true;
-
- /* Wildcard in the matching name means we've matched */
- if (c == '*')
- return variable_validate[i].validate(var,
- match, data, len);
-
- /* Case sensitive match */
- if (c != u)
- break;
-
- /* Reached the end of the string while matching */
- if (!c)
- return variable_validate[i].validate(var,
- match, data, len);
- }
- }
-
- return true;
-}
-
-static efi_status_t
-get_var_data_locked(struct efivars *efivars, struct efi_variable *var)
-{
- efi_status_t status;
-
- var->DataSize = 1024;
- status = efivars->ops->get_variable(var->VariableName,
- &var->VendorGuid,
- &var->Attributes,
- &var->DataSize,
- var->Data);
- return status;
-}
-
-static efi_status_t
-get_var_data(struct efivars *efivars, struct efi_variable *var)
-{
- efi_status_t status;
- unsigned long flags;
-
- spin_lock_irqsave(&efivars->lock, flags);
- status = get_var_data_locked(efivars, var);
- spin_unlock_irqrestore(&efivars->lock, flags);
-
- if (status != EFI_SUCCESS) {
- printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n",
- status);
- }
- return status;
-}
-
-static efi_status_t
-check_var_size_locked(struct efivars *efivars, u32 attributes,
- unsigned long size)
-{
- u64 storage_size, remaining_size, max_size;
- efi_status_t status;
- const struct efivar_operations *fops = efivars->ops;
-
- if (!efivars->ops->query_variable_info)
- return EFI_UNSUPPORTED;
-
- status = fops->query_variable_info(attributes, &storage_size,
- &remaining_size, &max_size);
-
- if (status != EFI_SUCCESS)
- return status;
-
- if (!storage_size || size > remaining_size || size > max_size ||
- (remaining_size - size) < (storage_size / 2))
- return EFI_OUT_OF_RESOURCES;
-
- return status;
-}
-
-
-static efi_status_t
-check_var_size(struct efivars *efivars, u32 attributes, unsigned long size)
-{
- efi_status_t status;
- unsigned long flags;
-
- spin_lock_irqsave(&efivars->lock, flags);
- status = check_var_size_locked(efivars, attributes, size);
- spin_unlock_irqrestore(&efivars->lock, flags);
-
- return status;
-}
-
-static ssize_t
-efivar_guid_read(struct efivar_entry *entry, char *buf)
-{
- struct efi_variable *var = &entry->var;
- char *str = buf;
-
- if (!entry || !buf)
- return 0;
-
- efi_guid_unparse(&var->VendorGuid, str);
- str += strlen(str);
- str += sprintf(str, "\n");
-
- return str - buf;
-}
-
-static ssize_t
-efivar_attr_read(struct efivar_entry *entry, char *buf)
-{
- struct efi_variable *var = &entry->var;
- char *str = buf;
- efi_status_t status;
-
- if (!entry || !buf)
- return -EINVAL;
-
- status = get_var_data(entry->efivars, var);
- if (status != EFI_SUCCESS)
- return -EIO;
-
- if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
- str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
- if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
- str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
- if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
- str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
- if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
- str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
- if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
- str += sprintf(str,
- "EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
- if (var->Attributes &
- EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
- str += sprintf(str,
- "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
- if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
- str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
- return str - buf;
-}
-
-static ssize_t
-efivar_size_read(struct efivar_entry *entry, char *buf)
-{
- struct efi_variable *var = &entry->var;
- char *str = buf;
- efi_status_t status;
-
- if (!entry || !buf)
- return -EINVAL;
-
- status = get_var_data(entry->efivars, var);
- if (status != EFI_SUCCESS)
- return -EIO;
-
- str += sprintf(str, "0x%lx\n", var->DataSize);
- return str - buf;
-}
-
-static ssize_t
-efivar_data_read(struct efivar_entry *entry, char *buf)
-{
- struct efi_variable *var = &entry->var;
- efi_status_t status;
-
- if (!entry || !buf)
- return -EINVAL;
-
- status = get_var_data(entry->efivars, var);
- if (status != EFI_SUCCESS)
- return -EIO;
-
- memcpy(buf, var->Data, var->DataSize);
- return var->DataSize;
-}
-/*
- * We allow each variable to be edited via rewriting the
- * entire efi variable structure.
- */
-static ssize_t
-efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
-{
- struct efi_variable *new_var, *var = &entry->var;
- struct efivars *efivars = entry->efivars;
- efi_status_t status = EFI_NOT_FOUND;
-
- if (count != sizeof(struct efi_variable))
- return -EINVAL;
-
- new_var = (struct efi_variable *)buf;
- /*
- * If only updating the variable data, then the name
- * and guid should remain the same
- */
- if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
- efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
- printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
- return -EINVAL;
- }
-
- if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
- printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
- return -EINVAL;
- }
-
- if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
- validate_var(new_var, new_var->Data, new_var->DataSize) == false) {
- printk(KERN_ERR "efivars: Malformed variable content\n");
- return -EINVAL;
- }
-
- spin_lock_irq(&efivars->lock);
-
- status = check_var_size_locked(efivars, new_var->Attributes,
- new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
-
- if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
- status = efivars->ops->set_variable(new_var->VariableName,
- &new_var->VendorGuid,
- new_var->Attributes,
- new_var->DataSize,
- new_var->Data);
-
- spin_unlock_irq(&efivars->lock);
-
- if (status != EFI_SUCCESS) {
- printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
- status);
- return -EIO;
- }
-
- memcpy(&entry->var, new_var, count);
- return count;
-}
-
-static ssize_t
-efivar_show_raw(struct efivar_entry *entry, char *buf)
-{
- struct efi_variable *var = &entry->var;
- efi_status_t status;
-
- if (!entry || !buf)
- return 0;
-
- status = get_var_data(entry->efivars, var);
- if (status != EFI_SUCCESS)
- return -EIO;
-
- memcpy(buf, var, sizeof(*var));
- return sizeof(*var);
-}
-
-/*
- * Generic read/write functions that call the specific functions of
- * the attributes...
- */
-static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct efivar_entry *var = to_efivar_entry(kobj);
- struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
- ssize_t ret = -EIO;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (efivar_attr->show) {
- ret = efivar_attr->show(var, buf);
- }
- return ret;
-}
-
-static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct efivar_entry *var = to_efivar_entry(kobj);
- struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
- ssize_t ret = -EIO;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (efivar_attr->store)
- ret = efivar_attr->store(var, buf, count);
-
- return ret;
-}
-
-static const struct sysfs_ops efivar_attr_ops = {
- .show = efivar_attr_show,
- .store = efivar_attr_store,
-};
-
-static void efivar_release(struct kobject *kobj)
-{
- struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);
- kfree(var);
-}
-
-static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
-static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
-static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
-static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
-static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
-
-static struct attribute *def_attrs[] = {
- &efivar_attr_guid.attr,
- &efivar_attr_size.attr,
- &efivar_attr_attributes.attr,
- &efivar_attr_data.attr,
- &efivar_attr_raw_var.attr,
- NULL,
-};
-
-static struct kobj_type efivar_ktype = {
- .release = efivar_release,
- .sysfs_ops = &efivar_attr_ops,
- .default_attrs = def_attrs,
-};
-
-static inline void
-efivar_unregister(struct efivar_entry *var)
-{
- kobject_put(&var->kobj);
-}
-
-static int efivarfs_file_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-static int efi_status_to_err(efi_status_t status)
-{
- int err;
-
- switch (status) {
- case EFI_INVALID_PARAMETER:
- err = -EINVAL;
- break;
- case EFI_OUT_OF_RESOURCES:
- err = -ENOSPC;
- break;
- case EFI_DEVICE_ERROR:
- err = -EIO;
- break;
- case EFI_WRITE_PROTECTED:
- err = -EROFS;
- break;
- case EFI_SECURITY_VIOLATION:
- err = -EACCES;
- break;
- case EFI_NOT_FOUND:
- err = -EIO;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-static ssize_t efivarfs_file_write(struct file *file,
- const char __user *userbuf, size_t count, loff_t *ppos)
-{
- struct efivar_entry *var = file->private_data;
- struct efivars *efivars;
- efi_status_t status;
- void *data;
- u32 attributes;
- struct inode *inode = file->f_mapping->host;
- unsigned long datasize = count - sizeof(attributes);
- unsigned long newdatasize, varsize;
- ssize_t bytes = 0;
-
- if (count < sizeof(attributes))
- return -EINVAL;
-
- if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
- return -EFAULT;
-
- if (attributes & ~(EFI_VARIABLE_MASK))
- return -EINVAL;
-
- efivars = var->efivars;
-
- /*
- * Ensure that the user can't allocate arbitrarily large
- * amounts of memory. Pick a default size of 64K if
- * QueryVariableInfo() isn't supported by the firmware.
- */
-
- varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
- status = check_var_size(efivars, attributes, varsize);
-
- if (status != EFI_SUCCESS) {
- if (status != EFI_UNSUPPORTED)
- return efi_status_to_err(status);
-
- if (datasize > 65536)
- return -ENOSPC;
- }
-
- data = kmalloc(datasize, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
- bytes = -EFAULT;
- goto out;
- }
-
- if (validate_var(&var->var, data, datasize) == false) {
- bytes = -EINVAL;
- goto out;
- }
-
- /*
- * The lock here protects the get_variable call, the conditional
- * set_variable call, and removal of the variable from the efivars
- * list (in the case of an authenticated delete).
- */
- spin_lock_irq(&efivars->lock);
-
- /*
- * Ensure that the available space hasn't shrunk below the safe level
- */
-
- status = check_var_size_locked(efivars, attributes, varsize);
-
- if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED) {
- spin_unlock_irq(&efivars->lock);
- kfree(data);
-
- return efi_status_to_err(status);
- }
-
- status = efivars->ops->set_variable(var->var.VariableName,
- &var->var.VendorGuid,
- attributes, datasize,
- data);
-
- if (status != EFI_SUCCESS) {
- spin_unlock_irq(&efivars->lock);
- kfree(data);
-
- return efi_status_to_err(status);
- }
-
- bytes = count;
-
- /*
- * Writing to the variable may have caused a change in size (which
- * could either be an append or an overwrite), or the variable to be
- * deleted. Perform a GetVariable() so we can tell what actually
- * happened.
- */
- newdatasize = 0;
- status = efivars->ops->get_variable(var->var.VariableName,
- &var->var.VendorGuid,
- NULL, &newdatasize,
- NULL);
-
- if (status == EFI_BUFFER_TOO_SMALL) {
- spin_unlock_irq(&efivars->lock);
- mutex_lock(&inode->i_mutex);
- i_size_write(inode, newdatasize + sizeof(attributes));
- mutex_unlock(&inode->i_mutex);
-
- } else if (status == EFI_NOT_FOUND) {
- list_del(&var->list);
- spin_unlock_irq(&efivars->lock);
- efivar_unregister(var);
- drop_nlink(inode);
- d_delete(file->f_dentry);
- dput(file->f_dentry);
-
- } else {
- spin_unlock_irq(&efivars->lock);
- pr_warn("efivarfs: inconsistent EFI variable implementation? "
- "status = %lx\n", status);
- }
-
-out:
- kfree(data);
-
- return bytes;
-}
-
-static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
- size_t count, loff_t *ppos)
-{
- struct efivar_entry *var = file->private_data;
- struct efivars *efivars = var->efivars;
- efi_status_t status;
- unsigned long datasize = 0;
- u32 attributes;
- void *data;
- ssize_t size = 0;
-
- spin_lock_irq(&efivars->lock);
- status = efivars->ops->get_variable(var->var.VariableName,
- &var->var.VendorGuid,
- &attributes, &datasize, NULL);
- spin_unlock_irq(&efivars->lock);
-
- if (status != EFI_BUFFER_TOO_SMALL)
- return efi_status_to_err(status);
-
- data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
-
- if (!data)
- return -ENOMEM;
-
- spin_lock_irq(&efivars->lock);
- status = efivars->ops->get_variable(var->var.VariableName,
- &var->var.VendorGuid,
- &attributes, &datasize,
- (data + sizeof(attributes)));
- spin_unlock_irq(&efivars->lock);
-
- if (status != EFI_SUCCESS) {
- size = efi_status_to_err(status);
- goto out_free;
- }
-
- memcpy(data, &attributes, sizeof(attributes));
- size = simple_read_from_buffer(userbuf, count, ppos,
- data, datasize + sizeof(attributes));
-out_free:
- kfree(data);
-
- return size;
-}
-
-static void efivarfs_evict_inode(struct inode *inode)
-{
- clear_inode(inode);
-}
-
-static const struct super_operations efivarfs_ops = {
- .statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
- .evict_inode = efivarfs_evict_inode,
- .show_options = generic_show_options,
-};
-
-static struct super_block *efivarfs_sb;
-
-static const struct inode_operations efivarfs_dir_inode_operations;
-
-static const struct file_operations efivarfs_file_operations = {
- .open = efivarfs_file_open,
- .read = efivarfs_file_read,
- .write = efivarfs_file_write,
- .llseek = no_llseek,
-};
-
-static struct inode *efivarfs_get_inode(struct super_block *sb,
- const struct inode *dir, int mode, dev_t dev)
-{
- struct inode *inode = new_inode(sb);
-
- if (inode) {
- inode->i_ino = get_next_ino();
- inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- switch (mode & S_IFMT) {
- case S_IFREG:
- inode->i_fop = &efivarfs_file_operations;
- break;
- case S_IFDIR:
- inode->i_op = &efivarfs_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- inc_nlink(inode);
- break;
- }
- }
- return inode;
-}
-
-/*
- * Return true if 'str' is a valid efivarfs filename of the form,
- *
- * VariableName-12345678-1234-1234-1234-1234567891bc
- */
-static bool efivarfs_valid_name(const char *str, int len)
-{
- static const char dashes[GUID_LEN] = {
- [8] = 1, [13] = 1, [18] = 1, [23] = 1
- };
- const char *s = str + len - GUID_LEN;
- int i;
-
- /*
- * We need a GUID, plus at least one letter for the variable name,
- * plus the '-' separator
- */
- if (len < GUID_LEN + 2)
- return false;
-
- /* GUID must be preceded by a '-' */
- if (*(s - 1) != '-')
- return false;
-
- /*
- * Validate that 's' is of the correct format, e.g.
- *
- * 12345678-1234-1234-1234-123456789abc
- */
- for (i = 0; i < GUID_LEN; i++) {
- if (dashes[i]) {
- if (*s++ != '-')
- return false;
- } else {
- if (!isxdigit(*s++))
- return false;
- }
- }
-
- return true;
-}
-
-static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
-{
- guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
- guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]);
- guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]);
- guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]);
- guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]);
- guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]);
- guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]);
- guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]);
- guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]);
- guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]);
- guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]);
- guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]);
- guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]);
- guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]);
- guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]);
- guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]);
-}
-
-static int efivarfs_create(struct inode *dir, struct dentry *dentry,
- umode_t mode, bool excl)
-{
- struct inode *inode;
- struct efivars *efivars = &__efivars;
- struct efivar_entry *var;
- int namelen, i = 0, err = 0;
-
- if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
- return -EINVAL;
-
- inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
- if (!inode)
- return -ENOMEM;
-
- var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
- if (!var) {
- err = -ENOMEM;
- goto out;
- }
-
- /* length of the variable name itself: remove GUID and separator */
- namelen = dentry->d_name.len - GUID_LEN - 1;
-
- efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
- &var->var.VendorGuid);
-
- for (i = 0; i < namelen; i++)
- var->var.VariableName[i] = dentry->d_name.name[i];
-
- var->var.VariableName[i] = '\0';
-
- inode->i_private = var;
- var->efivars = efivars;
- var->kobj.kset = efivars->kset;
-
- err = kobject_init_and_add(&var->kobj, &efivar_ktype, NULL, "%s",
- dentry->d_name.name);
- if (err)
- goto out;
-
- kobject_uevent(&var->kobj, KOBJ_ADD);
- spin_lock_irq(&efivars->lock);
- list_add(&var->list, &efivars->list);
- spin_unlock_irq(&efivars->lock);
- d_instantiate(dentry, inode);
- dget(dentry);
-out:
- if (err) {
- kfree(var);
- iput(inode);
- }
- return err;
-}
-
-static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
-{
- struct efivar_entry *var = dentry->d_inode->i_private;
- struct efivars *efivars = var->efivars;
- efi_status_t status;
-
- spin_lock_irq(&efivars->lock);
-
- status = efivars->ops->set_variable(var->var.VariableName,
- &var->var.VendorGuid,
- 0, 0, NULL);
-
- if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) {
- list_del(&var->list);
- spin_unlock_irq(&efivars->lock);
- efivar_unregister(var);
- drop_nlink(dentry->d_inode);
- dput(dentry);
- return 0;
- }
-
- spin_unlock_irq(&efivars->lock);
- return -EINVAL;
-};
-
-/*
- * Compare two efivarfs file names.
- *
- * An efivarfs filename is composed of two parts,
- *
- * 1. A case-sensitive variable name
- * 2. A case-insensitive GUID
- *
- * So we need to perform a case-sensitive match on part 1 and a
- * case-insensitive match on part 2.
- */
-static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
- const struct dentry *dentry, const struct inode *inode,
- unsigned int len, const char *str,
- const struct qstr *name)
-{
- int guid = len - GUID_LEN;
-
- if (name->len != len)
- return 1;
-
- /* Case-sensitive compare for the variable name */
- if (memcmp(str, name->name, guid))
- return 1;
-
- /* Case-insensitive compare for the GUID */
- return strncasecmp(name->name + guid, str + guid, GUID_LEN);
-}
-
-static int efivarfs_d_hash(const struct dentry *dentry,
- const struct inode *inode, struct qstr *qstr)
-{
- unsigned long hash = init_name_hash();
- const unsigned char *s = qstr->name;
- unsigned int len = qstr->len;
-
- if (!efivarfs_valid_name(s, len))
- return -EINVAL;
-
- while (len-- > GUID_LEN)
- hash = partial_name_hash(*s++, hash);
-
- /* GUID is case-insensitive. */
- while (len--)
- hash = partial_name_hash(tolower(*s++), hash);
-
- qstr->hash = end_name_hash(hash);
- return 0;
-}
-
-/*
- * Retaining negative dentries for an in-memory filesystem just wastes
- * memory and lookup time: arrange for them to be deleted immediately.
- */
-static int efivarfs_delete_dentry(const struct dentry *dentry)
-{
- return 1;
-}
-
-static struct dentry_operations efivarfs_d_ops = {
- .d_compare = efivarfs_d_compare,
- .d_hash = efivarfs_d_hash,
- .d_delete = efivarfs_delete_dentry,
-};
-
-static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
-{
- struct dentry *d;
- struct qstr q;
- int err;
-
- q.name = name;
- q.len = strlen(name);
-
- err = efivarfs_d_hash(NULL, NULL, &q);
- if (err)
- return ERR_PTR(err);
-
- d = d_alloc(parent, &q);
- if (d)
- return d;
-
- return ERR_PTR(-ENOMEM);
-}
-
-static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct inode *inode = NULL;
- struct dentry *root;
- struct efivar_entry *entry, *n;
- struct efivars *efivars = &__efivars;
- char *name;
- int err = -ENOMEM;
-
- efivarfs_sb = sb;
-
- sb->s_maxbytes = MAX_LFS_FILESIZE;
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = EFIVARFS_MAGIC;
- sb->s_op = &efivarfs_ops;
- sb->s_d_op = &efivarfs_d_ops;
- sb->s_time_gran = 1;
-
- inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
- if (!inode)
- return -ENOMEM;
- inode->i_op = &efivarfs_dir_inode_operations;
-
- root = d_make_root(inode);
- sb->s_root = root;
- if (!root)
- return -ENOMEM;
-
- list_for_each_entry_safe(entry, n, &efivars->list, list) {
- struct dentry *dentry, *root = efivarfs_sb->s_root;
- unsigned long size = 0;
- int len, i;
-
- inode = NULL;
-
- len = utf16_strlen(entry->var.VariableName);
-
- /* name, plus '-', plus GUID, plus NUL*/
- name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
- if (!name)
- goto fail;
-
- for (i = 0; i < len; i++)
- name[i] = entry->var.VariableName[i] & 0xFF;
-
- name[len] = '-';
-
- efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);
-
- name[len+GUID_LEN+1] = '\0';
-
- inode = efivarfs_get_inode(efivarfs_sb, root->d_inode,
- S_IFREG | 0644, 0);
- if (!inode)
- goto fail_name;
-
- dentry = efivarfs_alloc_dentry(root, name);
- if (IS_ERR(dentry)) {
- err = PTR_ERR(dentry);
- goto fail_inode;
- }
-
- /* copied by the above to local storage in the dentry. */
- kfree(name);
-
- spin_lock_irq(&efivars->lock);
- efivars->ops->get_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- &entry->var.Attributes,
- &size,
- NULL);
- spin_unlock_irq(&efivars->lock);
-
- mutex_lock(&inode->i_mutex);
- inode->i_private = entry;
- i_size_write(inode, size + sizeof(entry->var.Attributes));
- mutex_unlock(&inode->i_mutex);
- d_add(dentry, inode);
- }
-
- return 0;
-
-fail_inode:
- iput(inode);
-fail_name:
- kfree(name);
-fail:
- return err;
-}
-
-static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_single(fs_type, flags, data, efivarfs_fill_super);
-}
-
-static void efivarfs_kill_sb(struct super_block *sb)
-{
- kill_litter_super(sb);
- efivarfs_sb = NULL;
-}
-
-static struct file_system_type efivarfs_type = {
- .name = "efivarfs",
- .mount = efivarfs_mount,
- .kill_sb = efivarfs_kill_sb,
-};
-MODULE_ALIAS_FS("efivarfs");
-
-/*
- * Handle negative dentry.
- */
-static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
- unsigned int flags)
-{
- if (dentry->d_name.len > NAME_MAX)
- return ERR_PTR(-ENAMETOOLONG);
- d_add(dentry, NULL);
- return NULL;
-}
-
-static const struct inode_operations efivarfs_dir_inode_operations = {
- .lookup = efivarfs_lookup,
- .unlink = efivarfs_unlink,
- .create = efivarfs_create,
-};
-
-#ifdef CONFIG_EFI_VARS_PSTORE
-
-static int efi_pstore_open(struct pstore_info *psi)
-{
- struct efivars *efivars = psi->data;
-
- spin_lock_irq(&efivars->lock);
- efivars->walk_entry = list_first_entry(&efivars->list,
- struct efivar_entry, list);
- return 0;
-}
-
-static int efi_pstore_close(struct pstore_info *psi)
-{
- struct efivars *efivars = psi->data;
-
- spin_unlock_irq(&efivars->lock);
- return 0;
-}
-
-static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
- int *count, struct timespec *timespec,
- char **buf, struct pstore_info *psi)
-{
- efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
- char name[DUMP_NAME_LEN];
- int i;
- int cnt;
- unsigned int part, size;
- unsigned long time;
-
- while (&efivars->walk_entry->list != &efivars->list) {
- if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid,
- vendor)) {
- for (i = 0; i < DUMP_NAME_LEN; i++) {
- name[i] = efivars->walk_entry->var.VariableName[i];
- }
- if (sscanf(name, "dump-type%u-%u-%d-%lu",
- type, &part, &cnt, &time) == 4) {
- *id = part;
- *count = cnt;
- timespec->tv_sec = time;
- timespec->tv_nsec = 0;
- } else if (sscanf(name, "dump-type%u-%u-%lu",
- type, &part, &time) == 3) {
- /*
- * Check if an old format,
- * which doesn't support holding
- * multiple logs, remains.
- */
- *id = part;
- *count = 0;
- timespec->tv_sec = time;
- timespec->tv_nsec = 0;
- } else {
- efivars->walk_entry = list_entry(
- efivars->walk_entry->list.next,
- struct efivar_entry, list);
- continue;
- }
-
- get_var_data_locked(efivars, &efivars->walk_entry->var);
- size = efivars->walk_entry->var.DataSize;
- *buf = kmalloc(size, GFP_KERNEL);
- if (*buf == NULL)
- return -ENOMEM;
- memcpy(*buf, efivars->walk_entry->var.Data,
- size);
- efivars->walk_entry = list_entry(
- efivars->walk_entry->list.next,
- struct efivar_entry, list);
- return size;
- }
- efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
- struct efivar_entry, list);
- }
- return 0;
-}
-
-static int efi_pstore_write(enum pstore_type_id type,
- enum kmsg_dump_reason reason, u64 *id,
- unsigned int part, int count, size_t size,
- struct pstore_info *psi)
-{
- char name[DUMP_NAME_LEN];
- efi_char16_t efi_name[DUMP_NAME_LEN];
- efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
- int i, ret = 0;
- efi_status_t status = EFI_NOT_FOUND;
- unsigned long flags;
-
- if (pstore_cannot_block_path(reason)) {
- /*
- * If the lock is taken by another cpu in non-blocking path,
- * this driver returns without entering firmware to avoid
- * hanging up.
- */
- if (!spin_trylock_irqsave(&efivars->lock, flags))
- return -EBUSY;
- } else
- spin_lock_irqsave(&efivars->lock, flags);
-
- /*
- * Check if there is a space enough to log.
- * size: a size of logging data
- * DUMP_NAME_LEN * 2: a maximum size of variable name
- */
-
- status = check_var_size_locked(efivars, PSTORE_EFI_ATTRIBUTES,
- size + DUMP_NAME_LEN * 2);
-
- if (status) {
- spin_unlock_irqrestore(&efivars->lock, flags);
- *id = part;
- return -ENOSPC;
- }
-
- sprintf(name, "dump-type%u-%u-%d-%lu", type, part, count,
- get_seconds());
-
- for (i = 0; i < DUMP_NAME_LEN; i++)
- efi_name[i] = name[i];
-
- efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES,
- size, psi->buf);
-
- spin_unlock_irqrestore(&efivars->lock, flags);
-
- if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled)
- schedule_work(&efivar_work);
-
- *id = part;
- return ret;
-};
-
-static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
- struct timespec time, struct pstore_info *psi)
-{
- char name[DUMP_NAME_LEN];
- efi_char16_t efi_name[DUMP_NAME_LEN];
- char name_old[DUMP_NAME_LEN];
- efi_char16_t efi_name_old[DUMP_NAME_LEN];
- efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
- struct efivars *efivars = psi->data;
- struct efivar_entry *entry, *found = NULL;
- int i;
-
- sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count,
- time.tv_sec);
-
- spin_lock_irq(&efivars->lock);
-
- for (i = 0; i < DUMP_NAME_LEN; i++)
- efi_name[i] = name[i];
-
- /*
- * Clean up an entry with the same name
- */
-
- list_for_each_entry(entry, &efivars->list, list) {
- get_var_data_locked(efivars, &entry->var);
-
- if (efi_guidcmp(entry->var.VendorGuid, vendor))
- continue;
- if (utf16_strncmp(entry->var.VariableName, efi_name,
- utf16_strlen(efi_name))) {
- /*
- * Check if an old format,
- * which doesn't support holding
- * multiple logs, remains.
- */
- sprintf(name_old, "dump-type%u-%u-%lu", type,
- (unsigned int)id, time.tv_sec);
-
- for (i = 0; i < DUMP_NAME_LEN; i++)
- efi_name_old[i] = name_old[i];
-
- if (utf16_strncmp(entry->var.VariableName, efi_name_old,
- utf16_strlen(efi_name_old)))
- continue;
- }
-
- /* found */
- found = entry;
- efivars->ops->set_variable(entry->var.VariableName,
- &entry->var.VendorGuid,
- PSTORE_EFI_ATTRIBUTES,
- 0, NULL);
- break;
- }
-
- if (found)
- list_del(&found->list);
-
- spin_unlock_irq(&efivars->lock);
-
- if (found)
- efivar_unregister(found);
-
- return 0;
-}
-
-static struct pstore_info efi_pstore_info = {
- .owner = THIS_MODULE,
- .name = "efi",
- .open = efi_pstore_open,
- .close = efi_pstore_close,
- .read = efi_pstore_read,
- .write = efi_pstore_write,
- .erase = efi_pstore_erase,
-};
-
-static void efivar_pstore_register(struct efivars *efivars)
-{
- efivars->efi_pstore_info = efi_pstore_info;
- efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
- if (efivars->efi_pstore_info.buf) {
- efivars->efi_pstore_info.bufsize = 1024;
- efivars->efi_pstore_info.data = efivars;
- spin_lock_init(&efivars->efi_pstore_info.buf_lock);
- pstore_register(&efivars->efi_pstore_info);
- }
-}
-#else
-static void efivar_pstore_register(struct efivars *efivars)
-{
- return;
-}
-#endif
-
-static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
-{
- struct efi_variable *new_var = (struct efi_variable *)buf;
- struct efivars *efivars = bin_attr->private;
- struct efivar_entry *search_efivar, *n;
- unsigned long strsize1, strsize2;
- efi_status_t status = EFI_NOT_FOUND;
- int found = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
- validate_var(new_var, new_var->Data, new_var->DataSize) == false) {
- printk(KERN_ERR "efivars: Malformed variable content\n");
- return -EINVAL;
- }
-
- spin_lock_irq(&efivars->lock);
-
- /*
- * Does this variable already exist?
- */
- list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
- strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
- strsize2 = utf16_strsize(new_var->VariableName, 1024);
- if (strsize1 == strsize2 &&
- !memcmp(&(search_efivar->var.VariableName),
- new_var->VariableName, strsize1) &&
- !efi_guidcmp(search_efivar->var.VendorGuid,
- new_var->VendorGuid)) {
- found = 1;
- break;
- }
- }
- if (found) {
- spin_unlock_irq(&efivars->lock);
- return -EINVAL;
- }
-
- status = check_var_size_locked(efivars, new_var->Attributes,
- new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
-
- if (status && status != EFI_UNSUPPORTED) {
- spin_unlock_irq(&efivars->lock);
- return efi_status_to_err(status);
- }
-
- /* now *really* create the variable via EFI */
- status = efivars->ops->set_variable(new_var->VariableName,
- &new_var->VendorGuid,
- new_var->Attributes,
- new_var->DataSize,
- new_var->Data);
-
- if (status != EFI_SUCCESS) {
- printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
- status);
- spin_unlock_irq(&efivars->lock);
- return -EIO;
- }
- spin_unlock_irq(&efivars->lock);
-
- /* Create the entry in sysfs. Locking is not required here */
- status = efivar_create_sysfs_entry(efivars,
- utf16_strsize(new_var->VariableName,
- 1024),
- new_var->VariableName,
- &new_var->VendorGuid);
- if (status) {
- printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n");
- }
- return count;
-}
-
-static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t pos, size_t count)
-{
- struct efi_variable *del_var = (struct efi_variable *)buf;
- struct efivars *efivars = bin_attr->private;
- struct efivar_entry *search_efivar, *n;
- unsigned long strsize1, strsize2;
- efi_status_t status = EFI_NOT_FOUND;
- int found = 0;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- spin_lock_irq(&efivars->lock);
-
- /*
- * Does this variable already exist?
- */
- list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
- strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
- strsize2 = utf16_strsize(del_var->VariableName, 1024);
- if (strsize1 == strsize2 &&
- !memcmp(&(search_efivar->var.VariableName),
- del_var->VariableName, strsize1) &&
- !efi_guidcmp(search_efivar->var.VendorGuid,
- del_var->VendorGuid)) {
- found = 1;
- break;
- }
- }
- if (!found) {
- spin_unlock_irq(&efivars->lock);
- return -EINVAL;
- }
- /* force the Attributes/DataSize to 0 to ensure deletion */
- del_var->Attributes = 0;
- del_var->DataSize = 0;
-
- status = efivars->ops->set_variable(del_var->VariableName,
- &del_var->VendorGuid,
- del_var->Attributes,
- del_var->DataSize,
- del_var->Data);
-
- if (status != EFI_SUCCESS) {
- printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",
- status);
- spin_unlock_irq(&efivars->lock);
- return -EIO;
- }
- list_del(&search_efivar->list);
- /* We need to release this lock before unregistering. */
- spin_unlock_irq(&efivars->lock);
- efivar_unregister(search_efivar);
-
- /* It's dead Jim.... */
- return count;
-}
-
-static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
-{
- struct efivar_entry *entry, *n;
- struct efivars *efivars = &__efivars;
- unsigned long strsize1, strsize2;
- bool found = false;
-
- strsize1 = utf16_strsize(variable_name, 1024);
- list_for_each_entry_safe(entry, n, &efivars->list, list) {
- strsize2 = utf16_strsize(entry->var.VariableName, 1024);
- if (strsize1 == strsize2 &&
- !memcmp(variable_name, &(entry->var.VariableName),
- strsize2) &&
- !efi_guidcmp(entry->var.VendorGuid,
- *vendor)) {
- found = true;
- break;
- }
- }
- return found;
-}
-
-/*
- * Returns the size of variable_name, in bytes, including the
- * terminating NULL character, or variable_name_size if no NULL
- * character is found among the first variable_name_size bytes.
- */
-static unsigned long var_name_strnsize(efi_char16_t *variable_name,
- unsigned long variable_name_size)
-{
- unsigned long len;
- efi_char16_t c;
-
- /*
- * The variable name is, by definition, a NULL-terminated
- * string, so make absolutely sure that variable_name_size is
- * the value we expect it to be. If not, return the real size.
- */
- for (len = 2; len <= variable_name_size; len += sizeof(c)) {
- c = variable_name[(len / sizeof(c)) - 1];
- if (!c)
- break;
- }
-
- return min(len, variable_name_size);
-}
-
-static void efivar_update_sysfs_entries(struct work_struct *work)
-{
- struct efivars *efivars = &__efivars;
- efi_guid_t vendor;
- efi_char16_t *variable_name;
- unsigned long variable_name_size = 1024;
- efi_status_t status = EFI_NOT_FOUND;
- bool found;
-
- /* Add new sysfs entries */
- while (1) {
- variable_name = kzalloc(variable_name_size, GFP_KERNEL);
- if (!variable_name) {
- pr_err("efivars: Memory allocation failed.\n");
- return;
- }
-
- spin_lock_irq(&efivars->lock);
- found = false;
- while (1) {
- variable_name_size = 1024;
- status = efivars->ops->get_next_variable(
- &variable_name_size,
- variable_name,
- &vendor);
- if (status != EFI_SUCCESS) {
- break;
- } else {
- if (!variable_is_present(variable_name,
- &vendor)) {
- found = true;
- break;
- }
- }
- }
- spin_unlock_irq(&efivars->lock);
-
- if (!found) {
- kfree(variable_name);
- break;
- } else {
- variable_name_size = var_name_strnsize(variable_name,
- variable_name_size);
- efivar_create_sysfs_entry(efivars,
- variable_name_size,
- variable_name, &vendor);
- }
- }
-}
-
-/*
- * Let's not leave out systab information that snuck into
- * the efivars driver
- */
-static ssize_t systab_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- char *str = buf;
-
- if (!kobj || !buf)
- return -EINVAL;
-
- if (efi.mps != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "MPS=0x%lx\n", efi.mps);
- if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
- if (efi.acpi != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
- if (efi.smbios != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
- if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
- if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
- if (efi.uga != EFI_INVALID_TABLE_ADDR)
- str += sprintf(str, "UGA=0x%lx\n", efi.uga);
-
- return str - buf;
-}
-
-static struct kobj_attribute efi_attr_systab =
- __ATTR(systab, 0400, systab_show, NULL);
-
-static struct attribute *efi_subsys_attrs[] = {
- &efi_attr_systab.attr,
- NULL, /* maybe more in the future? */
-};
-
-static struct attribute_group efi_subsys_attr_group = {
- .attrs = efi_subsys_attrs,
-};
-
-static struct kobject *efi_kobj;
-
-/*
- * efivar_create_sysfs_entry()
- * Requires:
- * variable_name_size = number of bytes required to hold
- * variable_name (not counting the NULL
- * character at the end.
- * efivars->lock is not held on entry or exit.
- * Returns 1 on failure, 0 on success
- */
-static int
-efivar_create_sysfs_entry(struct efivars *efivars,
- unsigned long variable_name_size,
- efi_char16_t *variable_name,
- efi_guid_t *vendor_guid)
-{
- int i, short_name_size;
- char *short_name;
- struct efivar_entry *new_efivar;
-
- /*
- * Length of the variable bytes in ASCII, plus the '-' separator,
- * plus the GUID, plus trailing NUL
- */
- short_name_size = variable_name_size / sizeof(efi_char16_t)
- + 1 + GUID_LEN + 1;
-
- short_name = kzalloc(short_name_size, GFP_KERNEL);
- new_efivar = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
-
- if (!short_name || !new_efivar) {
- kfree(short_name);
- kfree(new_efivar);
- return 1;
- }
-
- new_efivar->efivars = efivars;
- memcpy(new_efivar->var.VariableName, variable_name,
- variable_name_size);
- memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
-
- /* Convert Unicode to normal chars (assume top bits are 0),
- ala UTF-8 */
- for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
- short_name[i] = variable_name[i] & 0xFF;
- }
- /* This is ugly, but necessary to separate one vendor's
- private variables from another's. */
-
- *(short_name + strlen(short_name)) = '-';
- efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
-
- new_efivar->kobj.kset = efivars->kset;
- i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL,
- "%s", short_name);
- if (i) {
- kfree(short_name);
- kfree(new_efivar);
- return 1;
- }
-
- kobject_uevent(&new_efivar->kobj, KOBJ_ADD);
- kfree(short_name);
- short_name = NULL;
-
- spin_lock_irq(&efivars->lock);
- list_add(&new_efivar->list, &efivars->list);
- spin_unlock_irq(&efivars->lock);
-
- return 0;
-}
-
-static int
-create_efivars_bin_attributes(struct efivars *efivars)
-{
- struct bin_attribute *attr;
- int error;
-
- /* new_var */
- attr = kzalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr)
- return -ENOMEM;
-
- attr->attr.name = "new_var";
- attr->attr.mode = 0200;
- attr->write = efivar_create;
- attr->private = efivars;
- efivars->new_var = attr;
-
- /* del_var */
- attr = kzalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr) {
- error = -ENOMEM;
- goto out_free;
- }
- attr->attr.name = "del_var";
- attr->attr.mode = 0200;
- attr->write = efivar_delete;
- attr->private = efivars;
- efivars->del_var = attr;
-
- sysfs_bin_attr_init(efivars->new_var);
- sysfs_bin_attr_init(efivars->del_var);
-
- /* Register */
- error = sysfs_create_bin_file(&efivars->kset->kobj,
- efivars->new_var);
- if (error) {
- printk(KERN_ERR "efivars: unable to create new_var sysfs file"
- " due to error %d\n", error);
- goto out_free;
- }
- error = sysfs_create_bin_file(&efivars->kset->kobj,
- efivars->del_var);
- if (error) {
- printk(KERN_ERR "efivars: unable to create del_var sysfs file"
- " due to error %d\n", error);
- sysfs_remove_bin_file(&efivars->kset->kobj,
- efivars->new_var);
- goto out_free;
- }
-
- return 0;
-out_free:
- kfree(efivars->del_var);
- efivars->del_var = NULL;
- kfree(efivars->new_var);
- efivars->new_var = NULL;
- return error;
-}
-
-void unregister_efivars(struct efivars *efivars)
-{
- struct efivar_entry *entry, *n;
-
- list_for_each_entry_safe(entry, n, &efivars->list, list) {
- spin_lock_irq(&efivars->lock);
- list_del(&entry->list);
- spin_unlock_irq(&efivars->lock);
- efivar_unregister(entry);
- }
- if (efivars->new_var)
- sysfs_remove_bin_file(&efivars->kset->kobj, efivars->new_var);
- if (efivars->del_var)
- sysfs_remove_bin_file(&efivars->kset->kobj, efivars->del_var);
- kfree(efivars->new_var);
- kfree(efivars->del_var);
- kobject_put(efivars->kobject);
- kset_unregister(efivars->kset);
-}
-EXPORT_SYMBOL_GPL(unregister_efivars);
-
-/*
- * Print a warning when duplicate EFI variables are encountered and
- * disable the sysfs workqueue since the firmware is buggy.
- */
-static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
- unsigned long len16)
-{
- size_t i, len8 = len16 / sizeof(efi_char16_t);
- char *s8;
-
- /*
- * Disable the workqueue since the algorithm it uses for
- * detecting new variables won't work with this buggy
- * implementation of GetNextVariableName().
- */
- efivar_wq_enabled = false;
-
- s8 = kzalloc(len8, GFP_KERNEL);
- if (!s8)
- return;
-
- for (i = 0; i < len8; i++)
- s8[i] = s16[i];
-
- printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
- s8, vendor_guid);
- kfree(s8);
-}
-
-int register_efivars(struct efivars *efivars,
- const struct efivar_operations *ops,
- struct kobject *parent_kobj)
-{
- efi_status_t status = EFI_NOT_FOUND;
- efi_guid_t vendor_guid;
- efi_char16_t *variable_name;
- unsigned long variable_name_size = 1024;
- int error = 0;
-
- variable_name = kzalloc(variable_name_size, GFP_KERNEL);
- if (!variable_name) {
- printk(KERN_ERR "efivars: Memory allocation failed.\n");
- return -ENOMEM;
- }
-
- spin_lock_init(&efivars->lock);
- INIT_LIST_HEAD(&efivars->list);
- efivars->ops = ops;
-
- efivars->kset = kset_create_and_add("vars", NULL, parent_kobj);
- if (!efivars->kset) {
- printk(KERN_ERR "efivars: Subsystem registration failed.\n");
- error = -ENOMEM;
- goto out;
- }
-
- efivars->kobject = kobject_create_and_add("efivars", parent_kobj);
- if (!efivars->kobject) {
- pr_err("efivars: Subsystem registration failed.\n");
- error = -ENOMEM;
- kset_unregister(efivars->kset);
- goto out;
- }
-
- /*
- * Per EFI spec, the maximum storage allocated for both
- * the variable name and variable data is 1024 bytes.
- */
-
- do {
- variable_name_size = 1024;
-
- status = ops->get_next_variable(&variable_name_size,
- variable_name,
- &vendor_guid);
- switch (status) {
- case EFI_SUCCESS:
- variable_name_size = var_name_strnsize(variable_name,
- variable_name_size);
-
- /*
- * Some firmware implementations return the
- * same variable name on multiple calls to
- * get_next_variable(). Terminate the loop
- * immediately as there is no guarantee that
- * we'll ever see a different variable name,
- * and may end up looping here forever.
- */
- if (variable_is_present(variable_name, &vendor_guid)) {
- dup_variable_bug(variable_name, &vendor_guid,
- variable_name_size);
- status = EFI_NOT_FOUND;
- break;
- }
-
- efivar_create_sysfs_entry(efivars,
- variable_name_size,
- variable_name,
- &vendor_guid);
- break;
- case EFI_NOT_FOUND:
- break;
- default:
- printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",
- status);
- status = EFI_NOT_FOUND;
- break;
- }
- } while (status != EFI_NOT_FOUND);
-
- error = create_efivars_bin_attributes(efivars);
- if (error)
- unregister_efivars(efivars);
-
- if (!efivars_pstore_disable)
- efivar_pstore_register(efivars);
-
- register_filesystem(&efivarfs_type);
-
-out:
- kfree(variable_name);
-
- return error;
-}
-EXPORT_SYMBOL_GPL(register_efivars);
-
-/*
- * For now we register the efi subsystem with the firmware subsystem
- * and the vars subsystem with the efi subsystem. In the future, it
- * might make sense to split off the efi subsystem into its own
- * driver, but for now only efivars will register with it, so just
- * include it here.
- */
-
-static int __init
-efivars_init(void)
-{
- int error = 0;
-
- printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
- EFIVARS_DATE);
-
- if (!efi_enabled(EFI_RUNTIME_SERVICES))
- return 0;
-
- /* For now we'll register the efi directory at /sys/firmware/efi */
- efi_kobj = kobject_create_and_add("efi", firmware_kobj);
- if (!efi_kobj) {
- printk(KERN_ERR "efivars: Firmware registration failed.\n");
- return -ENOMEM;
- }
-
- ops.get_variable = efi.get_variable;
- ops.set_variable = efi.set_variable;
- ops.get_next_variable = efi.get_next_variable;
- ops.query_variable_info = efi.query_variable_info;
-
- error = register_efivars(&__efivars, &ops, efi_kobj);
- if (error)
- goto err_put;
-
- /* Don't forget the systab entry */
- error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
- if (error) {
- printk(KERN_ERR
- "efivars: Sysfs attribute export failed with error %d.\n",
- error);
- goto err_unregister;
- }
-
- return 0;
-
-err_unregister:
- unregister_efivars(&__efivars);
-err_put:
- kobject_put(efi_kobj);
- return error;
-}
-
-static void __exit
-efivars_exit(void)
-{
- cancel_work_sync(&efivar_work);
-
- if (efi_enabled(EFI_RUNTIME_SERVICES)) {
- unregister_efivars(&__efivars);
- kobject_put(efi_kobj);
- }
-}
-
-module_init(efivars_init);
-module_exit(efivars_exit);
-
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index 91ddf0f7a1b9..acba0b9f4406 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -28,6 +28,7 @@
#include <linux/reboot.h>
#include <linux/efi.h>
#include <linux/module.h>
+#include <linux/ucs2_string.h>
#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */
/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
@@ -288,17 +289,6 @@ static int gsmi_exec(u8 func, u8 sub)
return rc;
}
-/* Return the number of unicode characters in data */
-static size_t
-utf16_strlen(efi_char16_t *data, unsigned long maxlength)
-{
- unsigned long length = 0;
-
- while (*data++ != 0 && length < maxlength)
- length++;
- return length;
-}
-
static efi_status_t gsmi_get_variable(efi_char16_t *name,
efi_guid_t *vendor, u32 *attr,
unsigned long *data_size,
@@ -311,7 +301,7 @@ static efi_status_t gsmi_get_variable(efi_char16_t *name,
};
efi_status_t ret = EFI_SUCCESS;
unsigned long flags;
- size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+ size_t name_len = ucs2_strnlen(name, GSMI_BUF_SIZE / 2);
int rc;
if (name_len >= GSMI_BUF_SIZE / 2)
@@ -380,7 +370,7 @@ static efi_status_t gsmi_get_next_variable(unsigned long *name_size,
return EFI_BAD_BUFFER_SIZE;
/* Let's make sure the thing is at least null-terminated */
- if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2)
+ if (ucs2_strnlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2)
return EFI_INVALID_PARAMETER;
spin_lock_irqsave(&gsmi_dev.lock, flags);
@@ -408,7 +398,7 @@ static efi_status_t gsmi_get_next_variable(unsigned long *name_size,
/* Copy the name back */
memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE);
- *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2;
+ *name_size = ucs2_strnlen(name, GSMI_BUF_SIZE / 2) * 2;
/* copy guid to return buffer */
memcpy(vendor, &param.guid, sizeof(param.guid));
@@ -434,7 +424,7 @@ static efi_status_t gsmi_set_variable(efi_char16_t *name,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
};
- size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+ size_t name_len = ucs2_strnlen(name, GSMI_BUF_SIZE / 2);
efi_status_t ret = EFI_SUCCESS;
int rc;
unsigned long flags;
@@ -893,12 +883,19 @@ static __init int gsmi_init(void)
goto out_remove_bin_file;
}
- ret = register_efivars(&efivars, &efivar_ops, gsmi_kobj);
+ ret = efivars_register(&efivars, &efivar_ops, gsmi_kobj);
if (ret) {
printk(KERN_INFO "gsmi: Failed to register efivars\n");
goto out_remove_sysfs_files;
}
+ ret = efivars_sysfs_init();
+ if (ret) {
+ printk(KERN_INFO "gsmi: Failed to create efivars files\n");
+ efivars_unregister(&efivars);
+ goto out_remove_sysfs_files;
+ }
+
register_reboot_notifier(&gsmi_reboot_notifier);
register_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_register(&panic_notifier_list,
@@ -930,7 +927,7 @@ static void __exit gsmi_exit(void)
unregister_die_notifier(&gsmi_die_notifier);
atomic_notifier_chain_unregister(&panic_notifier_list,
&gsmi_panic_notifier);
- unregister_efivars(&efivars);
+ efivars_unregister(&efivars);
sysfs_remove_files(gsmi_kobj, gsmi_attrs);
sysfs_remove_bin_file(gsmi_kobj, &eventlog_bin_attr);
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 0b5b5f619c75..e2e04b007e15 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -114,12 +114,9 @@ static void __meminit release_firmware_map_entry(struct kobject *kobj)
* map_entries_bootmem here, and deleted from &map_entries in
* firmware_map_remove_entry().
*/
- if (firmware_map_find_entry(entry->start, entry->end,
- entry->type)) {
- spin_lock(&map_entries_bootmem_lock);
- list_add(&entry->list, &map_entries_bootmem);
- spin_unlock(&map_entries_bootmem_lock);
- }
+ spin_lock(&map_entries_bootmem_lock);
+ list_add(&entry->list, &map_entries_bootmem);
+ spin_unlock(&map_entries_bootmem_lock);
return;
}
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index f9dbd503fc40..de3c317bd3e2 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -214,7 +214,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
* If it can't be trusted, assume that the pin can be used as a GPIO.
*/
if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
- return 1;
+ return 0;
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
}
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 24059462c87f..9391cf16e990 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -575,7 +575,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
chip->gpio_chip.ngpio,
irq_base,
&pca953x_irq_simple_ops,
- NULL);
+ chip);
if (!chip->domain)
return -ENODEV;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b820869ca93c..d7008dfdd6f0 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
@@ -22,6 +23,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
#include <asm/mach/irq.h>
@@ -51,8 +53,7 @@ struct pl061_gpio {
spinlock_t lock;
void __iomem *base;
- int irq_base;
- struct irq_chip_generic *irq_gc;
+ struct irq_domain *domain;
struct gpio_chip gc;
#ifdef CONFIG_PM
@@ -60,6 +61,24 @@ struct pl061_gpio {
#endif
};
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void pl061_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -122,24 +141,20 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- if (chip->irq_base <= 0)
- return -EINVAL;
-
- return chip->irq_base + offset;
+ return irq_create_mapping(chip->domain, offset);
}
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = gc->private;
- int offset = d->irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
- raw_spin_lock_irqsave(&gc->lock, flags);
+ spin_lock_irqsave(&chip->lock, flags);
gpioiev = readb(chip->base + GPIOIEV);
@@ -168,7 +183,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
writeb(gpioiev, chip->base + GPIOIEV);
- raw_spin_unlock_irqrestore(&gc->lock, flags);
+ spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -192,31 +207,61 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
-static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+static void pl061_irq_mask(struct irq_data *d)
+{
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) & ~mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static void pl061_irq_unmask(struct irq_data *d)
{
- struct irq_chip_type *ct;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) | mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static struct irq_chip pl061_irqchip = {
+ .name = "pl061 gpio",
+ .irq_mask = pl061_irq_mask,
+ .irq_unmask = pl061_irq_unmask,
+ .irq_set_type = pl061_irq_type,
+};
- chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
- chip->base, handle_simple_irq);
- chip->irq_gc->private = chip;
+static int pl061_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct pl061_gpio *chip = d->host_data;
- ct = chip->irq_gc->chip_types;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->chip.irq_set_type = pl061_irq_type;
- ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->regs.mask = GPIOIE;
+ irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq,
+ "pl061");
+ irq_set_chip_data(virq, chip);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
- irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
- IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+ return 0;
}
+static const struct irq_domain_ops pl061_domain_ops = {
+ .map = pl061_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev->platform_data;
struct pl061_gpio *chip;
- int ret, irq, i;
+ int ret, irq, i, irq_base;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -224,24 +269,32 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
if (pdata) {
chip->gc.base = pdata->gpio_base;
- chip->irq_base = pdata->irq_base;
- } else if (adev->dev.of_node) {
+ irq_base = pdata->irq_base;
+ if (irq_base <= 0)
+ return -ENODEV;
+ } else {
chip->gc.base = -1;
- chip->irq_base = 0;
- } else
- return -ENODEV;
+ irq_base = 0;
+ }
if (!devm_request_mem_region(dev, adev->res.start,
- resource_size(&adev->res), "pl061"))
+ resource_size(&adev->res), "pl061"))
return -EBUSY;
chip->base = devm_ioremap(dev, adev->res.start,
- resource_size(&adev->res));
- if (chip->base == NULL)
+ resource_size(&adev->res));
+ if (!chip->base)
return -ENOMEM;
+ chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
+ irq_base, &pl061_domain_ops, chip);
+ if (!chip->domain)
+ return -ENODEV;
+
spin_lock_init(&chip->lock);
+ chip->gc.request = pl061_gpio_request;
+ chip->gc.free = pl061_gpio_free;
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
@@ -259,12 +312,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
-
- if (chip->irq_base <= 0)
- return 0;
-
- pl061_init_gc(chip, chip->irq_base);
-
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (irq < 0)
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 9cc108d2b770..8325f580c0f1 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -642,7 +642,12 @@ static struct platform_driver pxa_gpio_driver = {
.of_match_table = of_match_ptr(pxa_gpio_dt_ids),
},
};
-module_platform_driver(pxa_gpio_driver);
+
+static int __init pxa_gpio_init(void)
+{
+ return platform_driver_register(&pxa_gpio_driver);
+}
+postcore_initcall(pxa_gpio_init);
#ifdef CONFIG_PM
static int pxa_gpio_suspend(void)
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 770476a9da87..3ce5bc38ac31 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -307,11 +307,15 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
+ struct device_node *np)
{
- int base = stmpe_gpio->irq_base;
+ int base = 0;
- stmpe_gpio->domain = irq_domain_add_simple(NULL,
+ if (!np)
+ base = stmpe_gpio->irq_base;
+
+ stmpe_gpio->domain = irq_domain_add_simple(np,
stmpe_gpio->chip.ngpio, base,
&stmpe_gpio_irq_simple_ops, stmpe_gpio);
if (!stmpe_gpio->domain) {
@@ -346,6 +350,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
stmpe_gpio->chip.dev = &pdev->dev;
+#ifdef CONFIG_OF
+ stmpe_gpio->chip.of_node = np;
+#endif
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
if (pdata)
@@ -366,7 +373,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
goto out_free;
if (irq >= 0) {
- ret = stmpe_gpio_irq_init(stmpe_gpio);
+ ret = stmpe_gpio_irq_init(stmpe_gpio, np);
if (ret)
goto out_disable;
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 5150df6cba08..465f4ca57e80 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -203,22 +203,11 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!pctldev)
break;
- /*
- * This assumes that the n GPIO pins are consecutive in the
- * GPIO number space, and that the pins are also consecutive
- * in their local number space. Currently it is not possible
- * to add different ranges for one and the same GPIO chip,
- * as the code assumes that we have one consecutive range
- * on both, mapping 1-to-1.
- *
- * TODO: make the OF bindings handle multiple sparse ranges
- * on the same GPIO chip.
- */
ret = gpiochip_add_pin_range(chip,
pinctrl_dev_get_devname(pctldev),
- 0, /* offset in gpiochip */
pinspec.args[0],
- pinspec.args[1]);
+ pinspec.args[1],
+ pinspec.args[2]);
if (ret)
break;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 792c3e3795ca..dd64a06dc5b4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2326,7 +2326,6 @@ int drm_mode_addfb(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n");
- drm_modeset_unlock_all(dev);
return PTR_ERR(fb);
}
@@ -2506,7 +2505,6 @@ int drm_mode_addfb2(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n");
- drm_modeset_unlock_all(dev);
return PTR_ERR(fb);
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 59d6b9bf204b..892ff9f95975 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1544,10 +1544,10 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
if (!fb_helper->fb)
return 0;
- drm_modeset_lock_all(dev);
+ mutex_lock(&fb_helper->dev->mode_config.mutex);
if (!drm_fb_helper_is_bound(fb_helper)) {
fb_helper->delayed_hotplug = true;
- drm_modeset_unlock_all(dev);
+ mutex_unlock(&fb_helper->dev->mode_config.mutex);
return 0;
}
DRM_DEBUG_KMS("\n");
@@ -1558,9 +1558,11 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
max_height);
+ mutex_unlock(&fb_helper->dev->mode_config.mutex);
+
+ drm_modeset_lock_all(dev);
drm_setup_crtcs(fb_helper);
drm_modeset_unlock_all(dev);
-
drm_fb_helper_set_par(fb_helper->fbdev);
return 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 13fdcd10a605..429e07d0b0f1 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -123,6 +123,7 @@ int drm_open(struct inode *inode, struct file *filp)
int retcode = 0;
int need_setup = 0;
struct address_space *old_mapping;
+ struct address_space *old_imapping;
minor = idr_find(&drm_minors_idr, minor_id);
if (!minor)
@@ -137,6 +138,7 @@ int drm_open(struct inode *inode, struct file *filp)
if (!dev->open_count++)
need_setup = 1;
mutex_lock(&dev->struct_mutex);
+ old_imapping = inode->i_mapping;
old_mapping = dev->dev_mapping;
if (old_mapping == NULL)
dev->dev_mapping = &inode->i_data;
@@ -159,8 +161,8 @@ int drm_open(struct inode *inode, struct file *filp)
err_undo:
mutex_lock(&dev->struct_mutex);
- filp->f_mapping = old_mapping;
- inode->i_mapping = old_mapping;
+ filp->f_mapping = old_imapping;
+ inode->i_mapping = old_imapping;
iput(container_of(dev->dev_mapping, struct inode, i_data));
dev->dev_mapping = old_mapping;
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 04fa6f1808d1..f83f0719922e 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -506,7 +506,7 @@ drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
}
EXPORT_SYMBOL(drm_gtf_mode);
-#if IS_ENABLED(CONFIG_VIDEOMODE)
+#ifdef CONFIG_VIDEOMODE_HELPERS
int drm_display_mode_from_videomode(const struct videomode *vm,
struct drm_display_mode *dmode)
{
@@ -523,26 +523,25 @@ int drm_display_mode_from_videomode(const struct videomode *vm,
dmode->clock = vm->pixelclock / 1000;
dmode->flags = 0;
- if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+ if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PHSYNC;
- else if (vm->dmt_flags & VESA_DMT_HSYNC_LOW)
+ else if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NHSYNC;
- if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH)
+ if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
dmode->flags |= DRM_MODE_FLAG_PVSYNC;
- else if (vm->dmt_flags & VESA_DMT_VSYNC_LOW)
+ else if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
dmode->flags |= DRM_MODE_FLAG_NVSYNC;
- if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED)
dmode->flags |= DRM_MODE_FLAG_INTERLACE;
- if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
+ if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
drm_mode_set_name(dmode);
return 0;
}
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
-#endif
-#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+#ifdef CONFIG_OF
/**
* of_get_drm_display_mode - get a drm_display_mode from devicetree
* @np: device_node with the timing specification
@@ -572,7 +571,8 @@ int of_get_drm_display_mode(struct device_node *np,
return 0;
}
EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
-#endif
+#endif /* CONFIG_OF */
+#endif /* CONFIG_VIDEOMODE_HELPERS */
/**
* drm_mode_set_name - set the name on a mode
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 3b11ab0fbc96..9a48e1a2d417 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -57,7 +57,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args)
if (eb == NULL) {
int size = args->buffer_count;
int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
- BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
+ BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head));
while (count > 2*size)
count >>= 1;
eb = kzalloc(count*sizeof(struct hlist_head) +
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 32a3693905ec..1ce45a0a2d3e 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -45,6 +45,9 @@
struct intel_crt {
struct intel_encoder base;
+ /* DPMS state is stored in the connector, which we need in the
+ * encoder's enable/disable callbacks */
+ struct intel_connector *connector;
bool force_hotplug_required;
u32 adpa_reg;
};
@@ -81,29 +84,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
return true;
}
-static void intel_disable_crt(struct intel_encoder *encoder)
-{
- struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_crt *crt = intel_encoder_to_crt(encoder);
- u32 temp;
-
- temp = I915_READ(crt->adpa_reg);
- temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
- temp &= ~ADPA_DAC_ENABLE;
- I915_WRITE(crt->adpa_reg, temp);
-}
-
-static void intel_enable_crt(struct intel_encoder *encoder)
-{
- struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_crt *crt = intel_encoder_to_crt(encoder);
- u32 temp;
-
- temp = I915_READ(crt->adpa_reg);
- temp |= ADPA_DAC_ENABLE;
- I915_WRITE(crt->adpa_reg, temp);
-}
-
/* Note: The caller is required to filter out dpms modes not supported by the
* platform. */
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -135,6 +115,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
I915_WRITE(crt->adpa_reg, temp);
}
+static void intel_disable_crt(struct intel_encoder *encoder)
+{
+ intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void intel_enable_crt(struct intel_encoder *encoder)
+{
+ struct intel_crt *crt = intel_encoder_to_crt(encoder);
+
+ intel_crt_set_dpms(encoder, crt->connector->base.dpms);
+}
+
+
static void intel_crt_dpms(struct drm_connector *connector, int mode)
{
struct drm_device *dev = connector->dev;
@@ -746,6 +739,7 @@ void intel_crt_init(struct drm_device *dev)
}
connector = &intel_connector->base;
+ crt->connector = intel_connector;
drm_connector_init(dev, &intel_connector->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index d7d4afe01341..c3f5bd8a5077 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2028,7 +2028,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
}
if (channel_eq)
- DRM_DEBUG_KMS("Channel EQ done. DP Training successfull\n");
+ DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE);
}
@@ -2559,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
{
struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
struct intel_dp *intel_dp = &intel_dig_port->dp;
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
i2c_del_adapter(&intel_dp->adapter);
drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+ mutex_lock(&dev->mode_config.mutex);
ironlake_panel_vdd_off_sync(intel_dp);
+ mutex_unlock(&dev->mode_config.mutex);
}
kfree(intel_dig_port);
}
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 4d338740f2cb..a8117e614009 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -350,11 +350,11 @@ static void intel_didl_outputs(struct drm_device *dev)
if (!handle || acpi_bus_get_device(handle, &acpi_dev))
return;
- if (acpi_is_video_device(acpi_dev))
+ if (acpi_is_video_device(handle))
acpi_video_bus = acpi_dev;
else {
list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
- if (acpi_is_video_device(acpi_cdev)) {
+ if (acpi_is_video_device(acpi_cdev->handle)) {
acpi_video_bus = acpi_cdev;
break;
}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d07a8cdf998e..78413ec623c9 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -451,7 +451,7 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
int i, ret = true;
/* Would be simpler to allocate both in one go ? */
- buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL);
+ buf = kzalloc(args_len * 2 + 2, GFP_KERNEL);
if (!buf)
return false;
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index fe22bb780e1d..78d8e919509f 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -751,8 +751,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
int i;
unsigned char misc = 0;
unsigned char ext_vga[6];
- unsigned char ext_vga_index24;
- unsigned char dac_index90 = 0;
u8 bppshift;
static unsigned char dacvalue[] = {
@@ -803,7 +801,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
option2 = 0x0000b000;
break;
case G200_ER:
- dac_index90 = 0;
break;
}
@@ -852,10 +849,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG_DAC(i, dacvalue[i]);
}
- if (mdev->type == G200_ER) {
- WREG_DAC(0x90, dac_index90);
- }
-
+ if (mdev->type == G200_ER)
+ WREG_DAC(0x90, 0);
if (option)
pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
@@ -952,8 +947,6 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (mdev->type == G200_WB)
ext_vga[1] |= 0x88;
- ext_vga_index24 = 0x05;
-
/* Set pixel clocks */
misc = 0x2d;
WREG8(MGA_MISC_OUT, misc);
@@ -965,7 +958,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
}
if (mdev->type == G200_ER)
- WREG_ECRT(24, ext_vga_index24);
+ WREG_ECRT(0x24, 0x5);
if (mdev->type == G200_EV) {
WREG_ECRT(6, 0);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index e816f06637a7..0e2c1a4f1659 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -248,6 +248,22 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios)
}
}
+static void
+nouveau_bios_shadow_platform(struct nouveau_bios *bios)
+{
+ struct pci_dev *pdev = nv_device(bios)->pdev;
+ size_t size;
+
+ void __iomem *rom = pci_platform_rom(pdev, &size);
+ if (rom && size) {
+ bios->data = kmalloc(size, GFP_KERNEL);
+ if (bios->data) {
+ memcpy_fromio(bios->data, rom, size);
+ bios->size = size;
+ }
+ }
+}
+
static int
nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)
{
@@ -288,6 +304,7 @@ nouveau_bios_shadow(struct nouveau_bios *bios)
{ "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL },
{ "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL },
{ "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL },
+ { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL },
{}
};
struct methods *mthd, *best;
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 3b6dc883e150..5eb3e0da7c6e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -391,7 +391,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
- struct nouveau_abi16_chan *chan, *temp;
+ struct nouveau_abi16_chan *chan = NULL, *temp;
struct nouveau_abi16_ntfy *ntfy;
struct nouveau_object *object;
struct nv_dma_class args = {};
@@ -404,10 +404,11 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
if (unlikely(nv_device(abi16->device)->card_type >= NV_C0))
return nouveau_abi16_put(abi16, -EINVAL);
- list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
- if (chan->chan->handle == (NVDRM_CHAN | info->channel))
+ list_for_each_entry(temp, &abi16->channels, head) {
+ if (temp->chan->handle == (NVDRM_CHAN | info->channel)) {
+ chan = temp;
break;
- chan = NULL;
+ }
}
if (!chan)
@@ -459,17 +460,18 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
{
struct drm_nouveau_gpuobj_free *fini = data;
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
- struct nouveau_abi16_chan *chan, *temp;
+ struct nouveau_abi16_chan *chan = NULL, *temp;
struct nouveau_abi16_ntfy *ntfy;
int ret;
if (unlikely(!abi16))
return -ENOMEM;
- list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
- if (chan->chan->handle == (NVDRM_CHAN | fini->channel))
+ list_for_each_entry(temp, &abi16->channels, head) {
+ if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) {
+ chan = temp;
break;
- chan = NULL;
+ }
}
if (!chan)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index d1099365bfc1..c95decf543e9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -72,11 +72,25 @@ module_param_named(modeset, nouveau_modeset, int, 0400);
static struct drm_driver driver;
static int
+nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
+{
+ struct nouveau_drm *drm =
+ container_of(event, struct nouveau_drm, vblank[head]);
+ drm_handle_vblank(drm->dev, head);
+ return NVKM_EVENT_KEEP;
+}
+
+static int
nouveau_drm_vblank_enable(struct drm_device *dev, int head)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
- nouveau_event_get(pdisp->vblank, head, &drm->vblank);
+
+ if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank)))
+ return -EIO;
+ WARN_ON_ONCE(drm->vblank[head].func);
+ drm->vblank[head].func = nouveau_drm_vblank_handler;
+ nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]);
return 0;
}
@@ -85,16 +99,11 @@ nouveau_drm_vblank_disable(struct drm_device *dev, int head)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
- nouveau_event_put(pdisp->vblank, head, &drm->vblank);
-}
-
-static int
-nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
-{
- struct nouveau_drm *drm =
- container_of(event, struct nouveau_drm, vblank);
- drm_handle_vblank(drm->dev, head);
- return NVKM_EVENT_KEEP;
+ if (drm->vblank[head].func)
+ nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]);
+ else
+ WARN_ON_ONCE(1);
+ drm->vblank[head].func = NULL;
}
static u64
@@ -292,7 +301,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = drm;
drm->dev = dev;
- drm->vblank.func = nouveau_drm_vblank_handler;
INIT_LIST_HEAD(&drm->clients);
spin_lock_init(&drm->tile.lock);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index b25df374c901..9c39bafbef2c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -113,7 +113,7 @@ struct nouveau_drm {
struct nvbios vbios;
struct nouveau_display *display;
struct backlight_device *backlight;
- struct nouveau_eventh vblank;
+ struct nouveau_eventh vblank[4];
/* power management */
struct nouveau_pm *pm;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 7f0e6c3f37d1..1ddc03e51bf4 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -479,7 +479,7 @@ nv50_display_flip_wait(void *data)
{
struct nv50_display_flip *flip = data;
if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) ==
- flip->chan->data);
+ flip->chan->data)
return true;
usleep_range(1, 2);
return false;
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index b8015913d382..fa3c56fba294 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -99,6 +99,29 @@ static bool radeon_read_bios(struct radeon_device *rdev)
return true;
}
+static bool radeon_read_platform_bios(struct radeon_device *rdev)
+{
+ uint8_t __iomem *bios;
+ size_t size;
+
+ rdev->bios = NULL;
+
+ bios = pci_platform_rom(rdev->pdev, &size);
+ if (!bios) {
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ return false;
+ }
+ rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+ if (rdev->bios == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
#ifdef CONFIG_ACPI
/* ATRM is used to get the BIOS on the discrete cards in
* dual-gpu systems.
@@ -620,6 +643,9 @@ bool radeon_get_bios(struct radeon_device *rdev)
if (r == false) {
r = radeon_read_disabled_bios(rdev);
}
+ if (r == false) {
+ r = radeon_read_platform_bios(rdev);
+ }
if (r == false || rdev->bios == NULL) {
DRM_ERROR("Unable to locate a BIOS ROM\n");
rdev->bios = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 48f80cd42d8f..5a99d433fc35 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -270,7 +270,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
}
/**
- * radeon_irq_kms_fini - tear down driver interrrupt info
+ * radeon_irq_kms_fini - tear down driver interrupt info
*
* @rdev: radeon device pointer
*
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index d24d04013476..e461e9972455 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -4,8 +4,7 @@ config DRM_TILCDC
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
- select OF_VIDEOMODE
- select OF_DISPLAY_TIMING
+ select VIDEOMODE_HELPERS
select BACKLIGHT_CLASS_DEVICE
help
Choose this option if you have an TI SoC with LCDC display
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 580b74e2022b..90ee49786372 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -173,7 +173,7 @@ static int panel_connector_get_modes(struct drm_connector *connector)
struct drm_display_mode *mode = drm_mode_create(dev);
struct videomode vm;
- if (videomode_from_timing(timings, &vm, i))
+ if (videomode_from_timings(timings, &vm, i))
break;
drm_display_mode_from_videomode(&vm, mode);
diff --git a/drivers/gpu/drm/udl/udl_connector.c b/drivers/gpu/drm/udl/udl_connector.c
index fe5cdbcf2636..b44d548c56f8 100644
--- a/drivers/gpu/drm/udl/udl_connector.c
+++ b/drivers/gpu/drm/udl/udl_connector.c
@@ -61,6 +61,10 @@ static int udl_get_modes(struct drm_connector *connector)
int ret;
edid = (struct edid *)udl_get_edid(udl);
+ if (!edid) {
+ drm_mode_connector_update_edid_property(connector, NULL);
+ return 0;
+ }
/*
* We only read the main block, but if the monitor reports extension
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 5f07d85c4189..fb52f3f6de80 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -92,14 +92,14 @@ menu "Special HID drivers"
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACRUX
tristate "ACRUX game controller support"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you want to enable support for ACRUX game controllers.
@@ -113,7 +113,7 @@ config HID_ACRUX_FF
config HID_APPLE
tristate "Apple {i,Power,Mac}Books" if EXPERT
- depends on (USB_HID || BT_HIDP)
+ depends on HID
default !EXPERT
---help---
Support for some Apple devices which less or more break
@@ -122,36 +122,47 @@ config HID_APPLE
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
MacBooks, MacBook Pros and Apple Aluminum.
+config HID_APPLEIR
+ tristate "Apple infrared receiver"
+ depends on (USB_HID)
+ ---help---
+ Support for Apple infrared remote control. All the Apple computers from
+ 2005 onwards include such a port, except the unibody Macbook (2009),
+ and Mac Pros. This receiver is also used in the Apple TV set-top box
+ prior to the 2010 model.
+
+ Say Y here if you want support for Apple infrared remote control.
+
config HID_AUREAL
tristate "Aureal"
- depends on USB_HID
+ depends on HID
---help---
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Belkin Flip KVM and Wireless keyboard.
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
tristate "Chicony Tactical pad" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Chicony Tactical pad.
config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support"
- depends on USB_HID && SND
+ depends on HID && SND
select SND_RAWMIDI
---help---
Support for Prodikeys PC-MIDI Keyboard device support.
@@ -166,14 +177,14 @@ config HID_PRODIKEYS
config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for cypress mouse and barcode readers.
config HID_DRAGONRISE
tristate "DragonRise Inc. game controller"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you have DragonRise Inc. game controllers.
These might be branded as:
@@ -192,7 +203,7 @@ config DRAGONRISE_FF
config HID_EMS_FF
tristate "EMS Production Inc. force feedback support"
- depends on USB_HID
+ depends on HID
select INPUT_FF_MEMLESS
---help---
Say Y here if you want to enable force feedback support for devices by
@@ -202,13 +213,13 @@ config HID_EMS_FF
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
- depends on BT_HIDP
+ depends on HID
---help---
Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Ezkey BTC 8193 keyboard.
@@ -231,7 +242,7 @@ config HOLTEK_FF
config HID_KEYTOUCH
tristate "Keytouch HID devices"
- depends on USB_HID
+ depends on HID
---help---
Support for Keytouch HID devices not fully compliant with
the specification. Currently supported:
@@ -239,7 +250,7 @@ config HID_KEYTOUCH
config HID_KYE
tristate "KYE/Genius devices"
- depends on USB_HID
+ depends on HID
---help---
Support for KYE/Genius devices not fully compliant with HID standard:
- Ergo Mouse
@@ -249,25 +260,25 @@ config HID_KYE
config HID_UCLOGIC
tristate "UC-Logic"
- depends on USB_HID
+ depends on HID
---help---
Support for UC-Logic tablets.
config HID_WALTOP
tristate "Waltop"
- depends on USB_HID
+ depends on HID
---help---
Support for Waltop tablets.
config HID_GYRATION
tristate "Gyration remote control"
- depends on USB_HID
+ depends on HID
---help---
Support for Gyration remote control.
config HID_ICADE
tristate "ION iCade arcade controller"
- depends on BT_HIDP
+ depends on HID
---help---
Support for the ION iCade arcade controller to work as a joystick.
@@ -276,20 +287,20 @@ config HID_ICADE
config HID_TWINHAN
tristate "Twinhan IR remote control"
- depends on USB_HID
+ depends on HID
---help---
Support for Twinhan IR remote control.
config HID_KENSINGTON
tristate "Kensington Slimblade Trackball" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Kensington Slimblade Trackball.
config HID_LCPOWER
tristate "LC-Power"
- depends on USB_HID
+ depends on HID
---help---
Support for LC-Power RC1000MCE RF remote control.
@@ -308,7 +319,7 @@ config HID_LENOVO_TPKBD
config HID_LOGITECH
tristate "Logitech devices" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Logitech devices that are not fully compliant with HID standard.
@@ -373,31 +384,31 @@ config LOGIWHEELS_FF
- Logitech Formula Force EX
config HID_MAGICMOUSE
- tristate "Apple MagicMouse multi-touch support"
- depends on BT_HIDP
+ tristate "Apple Magic Mouse/Trackpad multi-touch support"
+ depends on HID
---help---
- Support for the Apple Magic Mouse multi-touch.
+ Support for the Apple Magic Mouse/Trackpad multi-touch.
Say Y here if you want support for the multi-touch features of the
- Apple Wireless "Magic" Mouse.
+ Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT
- depends on USB_HID
+ depends on HID
default !EXPERT
---help---
Support for Monterey Genius KB29E.
config HID_MULTITOUCH
tristate "HID Multitouch panels"
- depends on USB_HID
+ depends on HID
---help---
Generic support for HID multitouch panels.
@@ -445,7 +456,7 @@ config HID_NTRIG
config HID_ORTEK
tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"
- depends on USB_HID
+ depends on HID
---help---
There are certain devices which have LogicalMaximum wrong in the keyboard
usage page of their report descriptor. The most prevailing ones so far
@@ -458,7 +469,7 @@ config HID_ORTEK
config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you have a PantherLord/GreenAsia based game controller
or adapter.
@@ -473,13 +484,13 @@ config PANTHERLORD_FF
config HID_PETALYNX
tristate "Petalynx Maxter remote control"
- depends on USB_HID
+ depends on HID
---help---
Support for Petalynx Maxter remote control.
config HID_PICOLCD
tristate "PicoLCD (graphic version)"
- depends on USB_HID
+ depends on HID
---help---
This provides support for Minibox PicoLCD devices, currently
only the graphical ones are supported.
@@ -545,14 +556,14 @@ config HID_PICOLCD_CIR
config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices"
- depends on USB_HID
+ depends on HID
---help---
Support for Primax devices that are not fully compliant with the
HID standard.
config HID_PS3REMOTE
tristate "Sony PS3 BD Remote Control"
- depends on BT_HIDP
+ depends on HID
---help---
Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
Harmony Adapter for PS3, which connect over Bluetooth.
@@ -569,7 +580,7 @@ config HID_ROCCAT
config HID_SAITEK
tristate "Saitek non-fully HID-compliant devices"
- depends on USB_HID
+ depends on HID
---help---
Support for Saitek devices that are not fully compliant with the
HID standard.
@@ -578,7 +589,7 @@ config HID_SAITEK
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
- depends on USB_HID
+ depends on HID
---help---
Support for Samsung InfraRed remote control or keyboards.
@@ -592,25 +603,25 @@ config HID_SONY
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
- depends on USB_HID
+ depends on HID
---help---
Support for Speedlink Vicious and Divine Cezanne mouse.
config HID_STEELSERIES
tristate "Steelseries SRW-S1 steering wheel support"
- depends on USB_HID
+ depends on HID
---help---
Support for Steelseries SRW-S1 steering wheel
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
- depends on USB_HID
+ depends on HID
---help---
Support for Sunplus wireless desktop.
config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game
controller or adapter.
@@ -632,7 +643,7 @@ config HID_HYPERV_MOUSE
config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support"
- depends on USB_HID
+ depends on HID
---help---
Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
@@ -650,20 +661,20 @@ config SMARTJOYPLUS_FF
config HID_TIVO
tristate "TiVo Slide Bluetooth remote control support"
- depends on (USB_HID || BT_HIDP)
+ depends on HID
---help---
Say Y if you have a TiVo Slide Bluetooth remote control.
config HID_TOPSEED
tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
- depends on USB_HID
+ depends on HID
---help---
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
CLLRCMCE remote control.
config HID_THINGM
tristate "ThingM blink(1) USB RGB LED"
- depends on USB_HID
+ depends on HID
depends on LEDS_CLASS
---help---
Support for the ThingM blink(1) USB RGB LED. This driver registers a
@@ -673,7 +684,7 @@ config HID_THINGM
config HID_THRUSTMASTER
tristate "ThrustMaster devices support"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Wheel.
@@ -689,7 +700,7 @@ config THRUSTMASTER_FF
config HID_WACOM
tristate "Wacom Bluetooth devices support"
- depends on BT_HIDP
+ depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
---help---
@@ -697,7 +708,7 @@ config HID_WACOM
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
- depends on BT_HIDP
+ depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
select INPUT_FF_MEMLESS
@@ -715,7 +726,7 @@ config HID_WIIMOTE_EXT
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
- depends on USB_HID
+ depends on HID
---help---
Say Y here if you have a Zeroplus based game controller.
@@ -729,16 +740,16 @@ config ZEROPLUS_FF
config HID_ZYDACRON
tristate "Zydacron remote control support"
- depends on USB_HID
+ depends on HID
---help---
Support for Zydacron remote control.
config HID_SENSOR_HUB
tristate "HID Sensors framework support"
- depends on USB_HID && GENERIC_HARDIRQS
+ depends on HID && GENERIC_HARDIRQS
select MFD_CORE
default n
- -- help---
+ ---help---
Support for HID Sensor framework. This creates a MFD instance
for a sensor hub and identifies all the sensors connected to it.
Each sensor is registered as a MFD cell, so that sensor specific
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 72d1b0bc0a97..2065694f57ab 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -39,6 +39,7 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
+obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
@@ -94,8 +95,8 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
- hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-lua.o \
- hid-roccat-pyra.o hid-roccat-savu.o
+ hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
+ hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-savu.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 320a958d4139..feae88b53fcd 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -21,7 +21,6 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include "hid-ids.h"
@@ -390,10 +389,6 @@ static void apple_remove(struct hid_device *hdev)
}
static const struct hid_device_id apple_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
- .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
diff --git a/drivers/hid/hid-appleir.c b/drivers/hid/hid-appleir.c
new file mode 100644
index 000000000000..a42e6a394c5e
--- /dev/null
+++ b/drivers/hid/hid-appleir.c
@@ -0,0 +1,352 @@
+/*
+ * HID driver for the apple ir device
+ *
+ * Original driver written by James McKenzie
+ * Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
+ * Updated to support newer remotes by Bastien Nocera <hadess@hadess.net>
+ * Ported to HID subsystem by Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ *
+ * Copyright (C) 2006 James McKenzie
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2008 Novell Inc.
+ * Copyright (C) 2010, 2012 Bastien Nocera <hadess@hadess.net>
+ * Copyright (C) 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ * Copyright (C) 2013 Red Hat Inc. All Rights Reserved
+ *
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include "hid-ids.h"
+
+MODULE_AUTHOR("James McKenzie");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("HID Apple IR remote controls");
+MODULE_LICENSE("GPL");
+
+#define KEY_MASK 0x0F
+#define TWO_PACKETS_MASK 0x40
+
+/*
+ * James McKenzie has two devices both of which report the following
+ * 25 87 ee 83 0a +
+ * 25 87 ee 83 0c -
+ * 25 87 ee 83 09 <<
+ * 25 87 ee 83 06 >>
+ * 25 87 ee 83 05 >"
+ * 25 87 ee 83 03 menu
+ * 26 00 00 00 00 for key repeat
+ */
+
+/*
+ * Thomas Glanzmann reports the following responses
+ * 25 87 ee ca 0b +
+ * 25 87 ee ca 0d -
+ * 25 87 ee ca 08 <<
+ * 25 87 ee ca 07 >>
+ * 25 87 ee ca 04 >"
+ * 25 87 ee ca 02 menu
+ * 26 00 00 00 00 for key repeat
+ *
+ * He also observes the following event sometimes
+ * sent after a key is release, which I interpret
+ * as a flat battery message
+ * 25 87 e0 ca 06 flat battery
+ */
+
+/*
+ * Alexandre Karpenko reports the following responses for Device ID 0x8242
+ * 25 87 ee 47 0b +
+ * 25 87 ee 47 0d -
+ * 25 87 ee 47 08 <<
+ * 25 87 ee 47 07 >>
+ * 25 87 ee 47 04 >"
+ * 25 87 ee 47 02 menu
+ * 26 87 ee 47 ** for key repeat (** is the code of the key being held)
+ */
+
+/*
+ * Bastien Nocera's remote
+ * 25 87 ee 91 5f followed by
+ * 25 87 ee 91 05 gives you >"
+ *
+ * 25 87 ee 91 5c followed by
+ * 25 87 ee 91 05 gives you the middle button
+ */
+
+/*
+ * Fabien Andre's remote
+ * 25 87 ee a3 5e followed by
+ * 25 87 ee a3 04 gives you >"
+ *
+ * 25 87 ee a3 5d followed by
+ * 25 87 ee a3 04 gives you the middle button
+ */
+
+static const unsigned short appleir_key_table[] = {
+ KEY_RESERVED,
+ KEY_MENU,
+ KEY_PLAYPAUSE,
+ KEY_FORWARD,
+ KEY_BACK,
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_ENTER,
+ KEY_PLAYPAUSE,
+ KEY_RESERVED,
+};
+
+struct appleir {
+ struct input_dev *input_dev;
+ struct hid_device *hid;
+ unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
+ struct timer_list key_up_timer; /* timer for key up */
+ spinlock_t lock; /* protects .current_key */
+ int current_key; /* the currently pressed key */
+ int prev_key_idx; /* key index in a 2 packets message */
+};
+
+static int get_key(int data)
+{
+ /*
+ * The key is coded accross bits 2..9:
+ *
+ * 0x00 or 0x01 ( ) key: 0 -> KEY_RESERVED
+ * 0x02 or 0x03 ( menu ) key: 1 -> KEY_MENU
+ * 0x04 or 0x05 ( >" ) key: 2 -> KEY_PLAYPAUSE
+ * 0x06 or 0x07 ( >> ) key: 3 -> KEY_FORWARD
+ * 0x08 or 0x09 ( << ) key: 4 -> KEY_BACK
+ * 0x0a or 0x0b ( + ) key: 5 -> KEY_VOLUMEUP
+ * 0x0c or 0x0d ( - ) key: 6 -> KEY_VOLUMEDOWN
+ * 0x0e or 0x0f ( ) key: 7 -> KEY_RESERVED
+ * 0x50 or 0x51 ( ) key: 8 -> KEY_RESERVED
+ * 0x52 or 0x53 ( ) key: 9 -> KEY_RESERVED
+ * 0x54 or 0x55 ( ) key: 10 -> KEY_RESERVED
+ * 0x56 or 0x57 ( ) key: 11 -> KEY_RESERVED
+ * 0x58 or 0x59 ( ) key: 12 -> KEY_RESERVED
+ * 0x5a or 0x5b ( ) key: 13 -> KEY_RESERVED
+ * 0x5c or 0x5d ( middle ) key: 14 -> KEY_ENTER
+ * 0x5e or 0x5f ( >" ) key: 15 -> KEY_PLAYPAUSE
+ *
+ * Packets starting with 0x5 are part of a two-packets message,
+ * we notify the caller by sending a negative value.
+ */
+ int key = (data >> 1) & KEY_MASK;
+
+ if ((data & TWO_PACKETS_MASK))
+ /* Part of a 2 packets-command */
+ key = -key;
+
+ return key;
+}
+
+static void key_up(struct hid_device *hid, struct appleir *appleir, int key)
+{
+ input_report_key(appleir->input_dev, key, 0);
+ input_sync(appleir->input_dev);
+}
+
+static void key_down(struct hid_device *hid, struct appleir *appleir, int key)
+{
+ input_report_key(appleir->input_dev, key, 1);
+ input_sync(appleir->input_dev);
+}
+
+static void battery_flat(struct appleir *appleir)
+{
+ dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
+}
+
+static void key_up_tick(unsigned long data)
+{
+ struct appleir *appleir = (struct appleir *)data;
+ struct hid_device *hid = appleir->hid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&appleir->lock, flags);
+ if (appleir->current_key) {
+ key_up(hid, appleir, appleir->current_key);
+ appleir->current_key = 0;
+ }
+ spin_unlock_irqrestore(&appleir->lock, flags);
+}
+
+static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
+ u8 *data, int len)
+{
+ struct appleir *appleir = hid_get_drvdata(hid);
+ static const u8 keydown[] = { 0x25, 0x87, 0xee };
+ static const u8 keyrepeat[] = { 0x26, };
+ static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
+ unsigned long flags;
+
+ if (len != 5)
+ goto out;
+
+ if (!memcmp(data, keydown, sizeof(keydown))) {
+ int index;
+
+ spin_lock_irqsave(&appleir->lock, flags);
+ /*
+ * If we already have a key down, take it up before marking
+ * this one down
+ */
+ if (appleir->current_key)
+ key_up(hid, appleir, appleir->current_key);
+
+ /* Handle dual packet commands */
+ if (appleir->prev_key_idx > 0)
+ index = appleir->prev_key_idx;
+ else
+ index = get_key(data[4]);
+
+ if (index >= 0) {
+ appleir->current_key = appleir->keymap[index];
+
+ key_down(hid, appleir, appleir->current_key);
+ /*
+ * Remote doesn't do key up, either pull them up, in
+ * the test above, or here set a timer which pulls
+ * them up after 1/8 s
+ */
+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+ appleir->prev_key_idx = 0;
+ } else
+ /* Remember key for next packet */
+ appleir->prev_key_idx = -index;
+ spin_unlock_irqrestore(&appleir->lock, flags);
+ goto out;
+ }
+
+ appleir->prev_key_idx = 0;
+
+ if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
+ key_down(hid, appleir, appleir->current_key);
+ /*
+ * Remote doesn't do key up, either pull them up, in the test
+ * above, or here set a timer which pulls them up after 1/8 s
+ */
+ mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
+ goto out;
+ }
+
+ if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
+ battery_flat(appleir);
+ /* Fall through */
+ }
+
+out:
+ /* let hidraw and hiddev handle the report */
+ return 0;
+}
+
+static void appleir_input_configured(struct hid_device *hid,
+ struct hid_input *hidinput)
+{
+ struct input_dev *input_dev = hidinput->input;
+ struct appleir *appleir = hid_get_drvdata(hid);
+ int i;
+
+ appleir->input_dev = input_dev;
+
+ input_dev->keycode = appleir->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+ memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
+ 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);
+}
+
+static int appleir_input_mapping(struct hid_device *hid,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ return -1;
+}
+
+static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
+{
+ int ret;
+ struct appleir *appleir;
+
+ appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
+ if (!appleir) {
+ ret = -ENOMEM;
+ goto allocfail;
+ }
+
+ appleir->hid = hid;
+
+ spin_lock_init(&appleir->lock);
+ setup_timer(&appleir->key_up_timer,
+ key_up_tick, (unsigned long) appleir);
+
+ hid_set_drvdata(hid, appleir);
+
+ ret = hid_parse(hid);
+ if (ret) {
+ hid_err(hid, "parse failed\n");
+ goto fail;
+ }
+
+ ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
+ if (ret) {
+ hid_err(hid, "hw start failed\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ kfree(appleir);
+allocfail:
+ return ret;
+}
+
+static void appleir_remove(struct hid_device *hid)
+{
+ struct appleir *appleir = hid_get_drvdata(hid);
+ hid_hw_stop(hid);
+ del_timer_sync(&appleir->key_up_timer);
+ kfree(appleir);
+}
+
+static const struct hid_device_id appleir_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, appleir_devices);
+
+static struct hid_driver appleir_driver = {
+ .name = "appleir",
+ .id_table = appleir_devices,
+ .raw_event = appleir_raw_event,
+ .input_configured = appleir_input_configured,
+ .probe = appleir_probe,
+ .remove = appleir_remove,
+ .input_mapping = appleir_input_mapping,
+};
+module_hid_driver(appleir_driver);
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index 62f0cee032ba..64ab94a55aa7 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -29,14 +29,12 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_HID_ACRUX_FF
-#include "usbhid/usbhid.h"
struct axff_device {
struct hid_report *report;
@@ -68,7 +66,7 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
}
dbg_hid("running with 0x%02x 0x%02x", left, right);
- usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+ hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -114,7 +112,7 @@ static int axff_init(struct hid_device *hid)
goto err_free_mem;
axff->report = report;
- usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
+ hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 512b01c04ea7..6961bbeab3ed 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -728,8 +728,7 @@ static int hid_scan_report(struct hid_device *hid)
} else if (page == HID_UP_SENSOR &&
item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
- (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL &&
- (hid->bus == BUS_USB || hid->bus == BUS_I2C))
+ (item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
}
@@ -1260,14 +1259,12 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
struct hid_report *report;
- char *buf;
- unsigned int i;
int ret = 0;
if (!hid)
return -ENODEV;
- if (down_trylock(&hid->driver_lock))
+ if (down_trylock(&hid->driver_input_lock))
return -EBUSY;
if (!hid->driver) {
@@ -1284,28 +1281,9 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
}
/* Avoid unnecessary overhead if debugfs is disabled */
- if (list_empty(&hid->debug_list))
- goto nomem;
-
- buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
-
- if (!buf)
- goto nomem;
-
- /* dump the report */
- snprintf(buf, HID_DEBUG_BUFSIZE - 1,
- "\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un");
- hid_debug_event(hid, buf);
-
- for (i = 0; i < size; i++) {
- snprintf(buf, HID_DEBUG_BUFSIZE - 1,
- " %02x", data[i]);
- hid_debug_event(hid, buf);
- }
- hid_debug_event(hid, "\n");
- kfree(buf);
+ if (!list_empty(&hid->debug_list))
+ hid_dump_report(hid, type, data, size);
-nomem:
report = hid_get_report(report_enum, data);
if (!report) {
@@ -1324,7 +1302,7 @@ nomem:
ret = hid_report_raw_event(hid, type, data, size, interrupt);
unlock:
- up(&hid->driver_lock);
+ up(&hid->driver_input_lock);
return ret;
}
EXPORT_SYMBOL_GPL(hid_input_report);
@@ -1502,8 +1480,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
- { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@@ -1527,6 +1503,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
@@ -1654,6 +1635,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
@@ -1687,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
@@ -1747,6 +1730,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
};
@@ -1845,6 +1829,11 @@ static int hid_device_probe(struct device *dev)
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
+ if (down_interruptible(&hdev->driver_input_lock)) {
+ ret = -EINTR;
+ goto unlock_driver_lock;
+ }
+ hdev->io_started = false;
if (!hdev->driver) {
id = hid_match_device(hdev, hdrv);
@@ -1867,6 +1856,9 @@ static int hid_device_probe(struct device *dev)
}
}
unlock:
+ if (!hdev->io_started)
+ up(&hdev->driver_input_lock);
+unlock_driver_lock:
up(&hdev->driver_lock);
return ret;
}
@@ -1875,9 +1867,15 @@ static int hid_device_remove(struct device *dev)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct hid_driver *hdrv;
+ int ret = 0;
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
+ if (down_interruptible(&hdev->driver_input_lock)) {
+ ret = -EINTR;
+ goto unlock_driver_lock;
+ }
+ hdev->io_started = false;
hdrv = hdev->driver;
if (hdrv) {
@@ -1889,8 +1887,11 @@ static int hid_device_remove(struct device *dev)
hdev->driver = NULL;
}
+ if (!hdev->io_started)
+ up(&hdev->driver_input_lock);
+unlock_driver_lock:
up(&hdev->driver_lock);
- return 0;
+ return ret;
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
@@ -2077,7 +2078,6 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
- { HID_USB_DEVICE(USB_VENDOR_ID_MASTERKIT, USB_DEVICE_ID_MASTERKIT_MA901RADIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
@@ -2244,6 +2244,18 @@ bool hid_ignore(struct hid_device *hdev)
hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST))
return true;
break;
+ case USB_VENDOR_ID_ATMEL_V_USB:
+ /* Masterkit MA901 usb radio based on Atmel tiny85 chip and
+ * it has the same USB ID as many Atmel V-USB devices. This
+ * usb radio is handled by radio-ma901.c driver so we want
+ * ignore the hid. Check the name, bus, product and ignore
+ * if we have MA901 usb radio.
+ */
+ if (hdev->product == USB_DEVICE_ID_ATMEL_V_USB &&
+ hdev->bus == BUS_USB &&
+ strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
+ return true;
+ break;
}
if (hdev->type == HID_TYPE_USBMOUSE &&
@@ -2329,7 +2341,9 @@ struct hid_device *hid_allocate_device(void)
init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list);
+ mutex_init(&hdev->debug_list_lock);
sema_init(&hdev->driver_lock, 1);
+ sema_init(&hdev->driver_input_lock, 1);
return hdev;
}
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 933fff0fff1f..7e56cb3855e3 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -580,17 +580,49 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
int i;
struct hid_debug_list *list;
+ mutex_lock(&hdev->debug_list_lock);
list_for_each_entry(list, &hdev->debug_list, node) {
for (i = 0; i < strlen(buf); i++)
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
}
+ mutex_unlock(&hdev->debug_list_lock);
wake_up_interruptible(&hdev->debug_wait);
}
EXPORT_SYMBOL_GPL(hid_debug_event);
+void hid_dump_report(struct hid_device *hid, int type, u8 *data,
+ int size)
+{
+ struct hid_report_enum *report_enum;
+ char *buf;
+ unsigned int i;
+
+ buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
+
+ if (!buf)
+ return;
+
+ report_enum = hid->report_enum + type;
+
+ /* dump the report */
+ snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+ "\nreport (size %u) (%snumbered) = ", size,
+ report_enum->numbered ? "" : "un");
+ hid_debug_event(hid, buf);
+
+ for (i = 0; i < size; i++) {
+ snprintf(buf, HID_DEBUG_BUFSIZE - 1,
+ " %02x", data[i]);
+ hid_debug_event(hid, buf);
+ }
+ hid_debug_event(hid, "\n");
+ kfree(buf);
+}
+EXPORT_SYMBOL_GPL(hid_dump_report);
+
void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value)
{
char *buf;
@@ -960,7 +992,9 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
file->private_data = list;
mutex_init(&list->read_mutex);
+ mutex_lock(&list->hdev->debug_list_lock);
list_add_tail(&list->node, &list->hdev->debug_list);
+ mutex_unlock(&list->hdev->debug_list_lock);
out:
return err;
@@ -1055,7 +1089,9 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
{
struct hid_debug_list *list = file->private_data;
+ mutex_lock(&list->hdev->debug_list_lock);
list_del(&list->node);
+ mutex_unlock(&list->hdev->debug_list_lock);
kfree(list->hid_debug_buf);
kfree(list);
diff --git a/drivers/hid/hid-dr.c b/drivers/hid/hid-dr.c
index 0fe8f65ef01a..ce0644424f58 100644
--- a/drivers/hid/hid-dr.c
+++ b/drivers/hid/hid-dr.c
@@ -29,14 +29,12 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_DRAGONRISE_FF
-#include "usbhid/usbhid.h"
struct drff_device {
struct hid_report *report;
@@ -68,7 +66,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[1] = 0x00;
drff->report->field[0]->value[2] = weak;
drff->report->field[0]->value[4] = strong;
- usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+ hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
drff->report->field[0]->value[0] = 0xfa;
drff->report->field[0]->value[1] = 0xfe;
@@ -80,7 +78,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[2] = 0x00;
drff->report->field[0]->value[4] = 0x00;
dbg_hid("running with 0x%02x 0x%02x", strong, weak);
- usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+ hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -132,7 +130,7 @@ static int drff_init(struct hid_device *hid)
drff->report->field[0]->value[4] = 0x00;
drff->report->field[0]->value[5] = 0x00;
drff->report->field[0]->value[6] = 0x00;
- usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
+ hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for DragonRise Inc. "
"game controllers by Richard Walmsley <richwalm@gmail.com>\n");
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
index 2e093ab99b43..d82d75bb11f7 100644
--- a/drivers/hid/hid-emsff.c
+++ b/drivers/hid/hid-emsff.c
@@ -23,11 +23,9 @@
#include <linux/hid.h>
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
-#include "usbhid/usbhid.h"
struct emsff_device {
struct hid_report *report;
@@ -52,7 +50,7 @@ static int emsff_play(struct input_dev *dev, void *data,
emsff->report->field[0]->value[2] = strong;
dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
- usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+ hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -104,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
emsff->report->field[0]->value[4] = 0x00;
emsff->report->field[0]->value[5] = 0x00;
emsff->report->field[0]->value[6] = 0x00;
- usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+ hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 04d2e6aca778..2d8cead3adca 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -29,13 +29,11 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_GREENASIA_FF
-#include "usbhid/usbhid.h"
struct gaff_device {
struct hid_report *report;
@@ -63,14 +61,14 @@ static int hid_gaff_play(struct input_dev *dev, void *data,
gaff->report->field[0]->value[4] = left;
gaff->report->field[0]->value[5] = 0;
dbg_hid("running with 0x%02x 0x%02x", left, right);
- usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+ hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe;
gaff->report->field[0]->value[2] = 0x0;
gaff->report->field[0]->value[4] = 0x0;
- usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+ hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -122,12 +120,12 @@ static int gaff_init(struct hid_device *hid)
gaff->report->field[0]->value[1] = 0x00;
gaff->report->field[0]->value[2] = 0x00;
gaff->report->field[0]->value[3] = 0x00;
- usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+ hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe;
- usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+ hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c
index f34d1186a3e1..9a8f05124525 100644
--- a/drivers/hid/hid-holtekff.c
+++ b/drivers/hid/hid-holtekff.c
@@ -27,12 +27,10 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include "hid-ids.h"
#ifdef CONFIG_HOLTEK_FF
-#include "usbhid/usbhid.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
@@ -102,7 +100,7 @@ static void holtekff_send(struct holtekff_device *holtekff,
dbg_hid("sending %*ph\n", 7, data);
- usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT);
+ hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
}
static int holtekff_play(struct input_dev *dev, void *data,
diff --git a/drivers/hid/hid-icade.c b/drivers/hid/hid-icade.c
index 09dcc04595f3..76b5a7570780 100644
--- a/drivers/hid/hid-icade.c
+++ b/drivers/hid/hid-icade.c
@@ -159,7 +159,7 @@ static const struct icade_key icade_usage_table[30] = {
static const struct icade_key *icade_find_translation(u16 from)
{
- if (from < 0 || from > ICADE_MAX_USAGE)
+ if (from > ICADE_MAX_USAGE)
return NULL;
return &icade_usage_table[from];
}
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 92e47e5c9564..38535c9243d5 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -137,8 +137,11 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
-#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
+#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
+#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
+#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
#define USB_VENDOR_ID_ASUS 0x0486
#define USB_DEVICE_ID_ASUS_T91MT 0x0185
@@ -158,6 +161,8 @@
#define USB_VENDOR_ID_ATMEL 0x03eb
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
+#define USB_VENDOR_ID_ATMEL_V_USB 0x16c0
+#define USB_DEVICE_ID_ATMEL_V_USB 0x05df
#define USB_VENDOR_ID_AUREAL 0x0755
#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
@@ -557,9 +562,6 @@
#define USB_VENDOR_ID_MADCATZ 0x0738
#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540
-#define USB_VENDOR_ID_MASTERKIT 0x16c0
-#define USB_DEVICE_ID_MASTERKIT_MA901RADIO 0x05df
-
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
@@ -578,6 +580,7 @@
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
#define USB_DEVICE_ID_MS_NE4K 0x00db
+#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
#define USB_DEVICE_ID_MS_LK6K 0x00f9
#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
@@ -590,6 +593,9 @@
#define USB_VENDOR_ID_MONTEREY 0x0566
#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
+#define USB_VENDOR_ID_MSI 0x1770
+#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00
+
#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
#define USB_DEVICE_ID_N_S_HARMONY 0xc359
@@ -611,6 +617,7 @@
#define USB_VENDOR_ID_NINTENDO 0x057e
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
+#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330
#define USB_VENDOR_ID_NOVATEK 0x0603
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
@@ -684,11 +691,16 @@
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
+#define USB_VENDOR_ID_REALTEK 0x0bda
+#define USB_DEVICE_ID_REALTEK_READER 0x0152
+
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
+#define USB_DEVICE_ID_ROCCAT_ISKUFX 0x3264
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
+#define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe
#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 21b196c394b1..945b8158ec4c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1198,6 +1198,67 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
return hidinput;
}
+static bool hidinput_has_been_populated(struct hid_input *hidinput)
+{
+ int i;
+ unsigned long r = 0;
+
+ for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++)
+ r |= hidinput->input->evbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++)
+ r |= hidinput->input->keybit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
+ r |= hidinput->input->relbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
+ r |= hidinput->input->absbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
+ r |= hidinput->input->mscbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++)
+ r |= hidinput->input->ledbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++)
+ r |= hidinput->input->sndbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++)
+ r |= hidinput->input->ffbit[i];
+
+ for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++)
+ r |= hidinput->input->swbit[i];
+
+ return !!r;
+}
+
+static void hidinput_cleanup_hidinput(struct hid_device *hid,
+ struct hid_input *hidinput)
+{
+ struct hid_report *report;
+ int i, k;
+
+ list_del(&hidinput->list);
+ input_free_device(hidinput->input);
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+ if (k == HID_OUTPUT_REPORT &&
+ hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ continue;
+
+ list_for_each_entry(report, &hid->report_enum[k].report_list,
+ list) {
+
+ for (i = 0; i < report->maxfield; i++)
+ if (report->field[i]->hidinput == hidinput)
+ report->field[i]->hidinput = NULL;
+ }
+ }
+
+ kfree(hidinput);
+}
+
/*
* Register the input device; print a message.
* Configure the input layer interface
@@ -1249,6 +1310,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
+ if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
+ !hidinput_has_been_populated(hidinput))
+ continue;
+
if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
@@ -1265,6 +1330,18 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
+ if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
+ !hidinput_has_been_populated(hidinput)) {
+ /* no need to register an input device not populated */
+ hidinput_cleanup_hidinput(hid, hidinput);
+ hidinput = NULL;
+ }
+
+ if (list_empty(&hid->inputs)) {
+ hid_err(hid, "No inputs registered, leaving\n");
+ goto out_unwind;
+ }
+
if (hidinput) {
if (drv->input_configured)
drv->input_configured(hid, hidinput);
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index ef72daecfa16..6af90dbdc3d4 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -16,8 +16,6 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
#include "hid-ids.h"
@@ -361,7 +359,7 @@ static int kye_tablet_enable(struct hid_device *hdev)
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}
diff --git a/drivers/hid/hid-lenovo-tpkbd.c b/drivers/hid/hid-lenovo-tpkbd.c
index 956c3b135f64..07837f5a4eb8 100644
--- a/drivers/hid/hid-lenovo-tpkbd.c
+++ b/drivers/hid/hid-lenovo-tpkbd.c
@@ -68,7 +68,7 @@ static int tpkbd_features_set(struct hid_device *hdev)
report->field[2]->value[0] = data_pointer->sensitivity;
report->field[3]->value[0] = data_pointer->press_speed;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}
@@ -228,8 +228,6 @@ static ssize_t pointer_press_speed_show(struct device *dev,
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
- data_pointer = hid_get_drvdata(hdev);
-
return snprintf(buf, PAGE_SIZE, "%u\n",
data_pointer->press_speed);
}
@@ -332,7 +330,7 @@ static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
static int tpkbd_probe_tp(struct hid_device *hdev)
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index 3c31bc650e5d..b3cd1507dda2 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -23,10 +23,8 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid/usbhid.h"
#include "hid-lg.h"
struct lg2ff_device {
@@ -56,7 +54,7 @@ static int play_effect(struct input_dev *dev, void *data,
lg2ff->report->field[0]->value[4] = 0x00;
}
- usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
+ hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -108,7 +106,7 @@ int lg2ff_init(struct hid_device *hid)
report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index f98644c26c1d..e52f181f6aa1 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -22,10 +22,8 @@
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid/usbhid.h"
#include "hid-lg.h"
/*
@@ -92,7 +90,7 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
report->field[0]->value[1] = (unsigned char)(-x);
report->field[0]->value[31] = (unsigned char)(-y);
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@@ -118,7 +116,7 @@ static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
report->field[0]->value[33] = 0x7F;
report->field[0]->value[34] = 0x7F;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 65a6ec8d3742..0ddae2a00d59 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -34,6 +34,7 @@
#define DFGT_REV_MAJ 0x13
#define DFGT_REV_MIN 0x22
+#define DFGT2_REV_MIN 0x26
#define DFP_REV_MAJ 0x11
#define DFP_REV_MIN 0x06
#define FFEX_REV_MAJ 0x21
@@ -125,6 +126,7 @@ static const struct lg4ff_native_cmd native_g27 = {
static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
+ {DFGT_REV_MAJ, DFGT2_REV_MIN, &native_dfgt}, /* Driving Force GT v2 */
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
@@ -202,7 +204,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@@ -225,7 +227,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends autocentering command compatible with Formula Force EX */
@@ -245,7 +247,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends command to set range compatible with G25/G27/Driving Force GT */
@@ -265,7 +267,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends commands to set range compatible with Driving Force Pro wheel */
@@ -294,7 +296,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
report->field[0]->value[1] = 0x02;
full_range = 200;
}
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
/* Prepare "fine" limit command */
value[0] = 0x81;
@@ -306,7 +308,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[6] = 0x00;
if (range == 200 || range == 900) { /* Do not apply any fine limit */
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return;
}
@@ -320,7 +322,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
value[6] = 0xff;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
@@ -334,7 +336,7 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
for (i = 0; i < 7; i++)
report->field[0]->value[i] = cmd->cmd[j++];
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
}
@@ -410,7 +412,7 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 27bc54f92f44..d7ea8c845b40 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -30,10 +30,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid/usbhid.h"
#include "hid-lg.h"
struct dev_type {
@@ -89,7 +87,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = x;
report->field[0]->value[3] = y;
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
case FF_RUMBLE:
@@ -104,7 +102,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = left;
report->field[0]->value[3] = right;
dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@@ -124,7 +122,7 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
*value++ = 0x80;
*value++ = 0x00;
*value = 0x00;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
int lgff_init(struct hid_device* hid)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 8758f38c948c..5207591a598c 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
-#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include "hid-logitech-dj.h"
@@ -193,7 +192,6 @@ static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type);
-static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report)
@@ -234,7 +232,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__);
- djrcv_dev->querying_devices = false;
return;
}
@@ -245,12 +242,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return;
}
- if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
- /* The device is already known. No need to reallocate it. */
- dbg_hid("%s: device is already known\n", __func__);
- return;
- }
-
dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@ -314,7 +305,6 @@ static void delayedwork_callback(struct work_struct *work)
struct dj_report dj_report;
unsigned long flags;
int count;
- int retval;
dbg_hid("%s\n", __func__);
@@ -347,25 +337,6 @@ static void delayedwork_callback(struct work_struct *work)
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break;
default:
- /* A normal report (i. e. not belonging to a pair/unpair notification)
- * arriving here, means that the report arrived but we did not have a
- * paired dj_device associated to the report's device_index, this
- * means that the original "device paired" notification corresponding
- * to this dj_device never arrived to this driver. The reason is that
- * hid-core discards all packets coming from a device while probe() is
- * executing. */
- if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
- /* ok, we don't know the device, just re-ask the
- * receiver for the list of connected devices. */
- retval = logi_dj_recv_query_paired_devices(djrcv_dev);
- if (!retval) {
- /* everything went fine, so just leave */
- break;
- }
- dev_err(&djrcv_dev->hdev->dev,
- "%s:logi_dj_recv_query_paired_devices "
- "error:%d\n", __func__, retval);
- }
dbg_hid("%s: unexpected report type\n", __func__);
}
}
@@ -396,12 +367,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
- kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
-
- if (schedule_work(&djrcv_dev->work) == 0) {
- dbg_hid("%s: did not schedule the work item, was already "
- "queued\n", __func__);
- }
return;
}
@@ -432,12 +397,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
- kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
-
- if (schedule_work(&djrcv_dev->work) == 0) {
- dbg_hid("%s: did not schedule the work item, was already "
- "queued\n", __func__);
- }
return;
}
@@ -475,7 +434,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
for (i = 0; i < report->field[0]->report_count; i++)
report->field[0]->value[i] = data[i];
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}
@@ -485,10 +444,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
struct dj_report *dj_report;
int retval;
- /* no need to protect djrcv_dev->querying_devices */
- if (djrcv_dev->querying_devices)
- return 0;
-
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report)
return -ENOMEM;
@@ -500,7 +455,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
return retval;
}
-
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout)
{
@@ -644,7 +598,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
hid_set_field(report->field[0], 2, data[1]);
- usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT);
+ hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
return 0;
@@ -809,6 +763,9 @@ static int logi_dj_probe(struct hid_device *hdev,
goto llopen_failed;
}
+ /* Allow incoming packets to arrive: */
+ hid_device_io_start(hdev);
+
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
if (retval < 0) {
dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "
diff --git a/drivers/hid/hid-logitech-dj.h b/drivers/hid/hid-logitech-dj.h
index 4a4000340ce1..fd28a5e0ca3b 100644
--- a/drivers/hid/hid-logitech-dj.h
+++ b/drivers/hid/hid-logitech-dj.h
@@ -101,7 +101,6 @@ struct dj_receiver_dev {
struct work_struct work;
struct kfifo notif_fifo;
spinlock_t lock;
- bool querying_devices;
};
struct dj_device {
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index f7f113ba083e..5bc37343eb22 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -19,7 +19,6 @@
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include "hid-ids.h"
@@ -462,6 +461,21 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
return 0;
}
+static void magicmouse_input_configured(struct hid_device *hdev,
+ struct hid_input *hi)
+
+{
+ struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+ int 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;
+ }
+}
+
+
static int magicmouse_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -493,15 +507,10 @@ static int magicmouse_probe(struct hid_device *hdev,
goto err_free;
}
- /* We do this after hid-input is done parsing reports so that
- * hid-input uses the most natural button and axis IDs.
- */
- if (msc->input) {
- ret = magicmouse_setup_input(msc->input, hdev);
- if (ret) {
- hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
- goto err_stop_hw;
- }
+ if (!msc->input) {
+ hid_err(hdev, "magicmouse input not registered\n");
+ ret = -ENOMEM;
+ goto err_stop_hw;
}
if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
@@ -568,6 +577,7 @@ static struct hid_driver magicmouse_driver = {
.remove = magicmouse_remove,
.raw_event = magicmouse_raw_event,
.input_mapping = magicmouse_input_mapping,
+ .input_configured = magicmouse_input_configured,
};
module_hid_driver(magicmouse_driver);
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 29d27f65a118..551795b7da1d 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -195,6 +195,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
.driver_data = MS_ERGONOMY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
+ .driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
.driver_data = MS_ERGONOMY | MS_RDESC },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 7a1ebb867cf4..dc3ae5c56f56 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -2,8 +2,9 @@
* HID driver for multitouch panels
*
* Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
- * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ * Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
+ * Copyright (c) 2012-2013 Red Hat, Inc
*
* This code is partly based on hid-egalax.c:
*
@@ -26,13 +27,24 @@
* any later version.
*/
+/*
+ * This driver is regularly tested thanks to the tool hid-test[1].
+ * This tool relies on hid-replay[2] and a database of hid devices[3].
+ * Please run these regression tests before patching this module so that
+ * your patch won't break existing known devices.
+ *
+ * [1] https://github.com/bentiss/hid-test
+ * [2] https://github.com/bentiss/hid-replay
+ * [3] https://github.com/bentiss/hid-devices
+ */
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/input/mt.h>
-#include "usbhid/usbhid.h"
+#include <linux/string.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
@@ -86,9 +98,9 @@ struct mt_device {
multitouch fields */
int cc_index; /* contact count field index in the report */
int cc_value_index; /* contact count value index in the field */
- unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
+ unsigned pen_report_id; /* the report ID of the pen device */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
__s8 inputmode_index; /* InputMode HID feature index in the report */
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
@@ -104,6 +116,9 @@ struct mt_device {
unsigned mt_flags; /* flags to pass to input-mt */
};
+static void mt_post_parse_default_settings(struct mt_device *td);
+static void mt_post_parse(struct mt_device *td);
+
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
@@ -246,6 +261,14 @@ static struct mt_class mt_classes[] = {
{ }
};
+static void mt_free_input_name(struct hid_input *hi)
+{
+ struct hid_device *hdev = hi->report->device;
+
+ if (hi->input->name != hdev->name)
+ kfree(hi->input->name);
+}
+
static ssize_t mt_show_quirks(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -354,7 +377,53 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
f->usages[f->length++] = usage->hid;
}
-static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+
+ td->pen_report_id = field->report->id;
+
+ return 0;
+}
+
+static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ return 0;
+}
+
+static int mt_pen_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ /* let hid-input handle it */
+ return 0;
+}
+
+static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
+{
+ struct hid_field *field = report->field[0];
+
+ input_sync(field->hidinput->input);
+}
+
+static void mt_pen_input_configured(struct hid_device *hdev,
+ struct hid_input *hi)
+{
+ char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
+ if (name) {
+ sprintf(name, "%s Pen", hi->input->name);
+ mt_free_input_name(hi);
+ hi->input->name = name;
+ }
+
+ /* force BTN_STYLUS to allow tablet matching in udev */
+ __set_bit(BTN_STYLUS, hi->input->keybit);
+}
+
+static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
@@ -363,13 +432,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
int code;
struct hid_usage *prev_usage = NULL;
- /* Only map fields from TouchScreen or TouchPad collections.
- * We need to ignore fields that belong to other collections
- * such as Mouse that might have the same GenericDesktop usages. */
if (field->application == HID_DG_TOUCHSCREEN)
td->mt_flags |= INPUT_MT_DIRECT;
- else if (field->application != HID_DG_TOUCHPAD)
- return 0;
/*
* Model touchscreens providing buttons as touchpads.
@@ -378,12 +442,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
td->mt_flags |= INPUT_MT_POINTER;
- /* eGalax devices provide a Digitizer.Stylus input which overrides
- * the correct Digitizers.Finger X/Y ranges.
- * Let's just ignore this input. */
- if (field->physical == HID_DG_STYLUS)
- return -1;
-
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
@@ -405,7 +463,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) {
@@ -421,7 +478,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
}
return 0;
@@ -436,21 +492,17 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ABS_MT_DISTANCE, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_CONFIDENCE:
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTID:
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
td->touches_by_report++;
td->mt_report_id = field->report->id;
return 1;
@@ -461,7 +513,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
@@ -473,7 +524,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
@@ -481,17 +531,14 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure);
mt_store_field(usage, td, hi);
- td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
td->cc_index = field->index;
td->cc_value_index = usage->usage_index;
- td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */
- td->last_field_index = field->index;
return -1;
case HID_DG_TOUCH:
/* Legacy devices use TIPSWITCH and not TOUCH.
@@ -515,7 +562,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
-static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
@@ -606,7 +653,7 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
td->num_received = 0;
}
-static int mt_event(struct hid_device *hid, struct hid_field *field,
+static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
/* we will handle the hidinput part later, now remains hiddev */
@@ -621,6 +668,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
{
struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass.quirks;
+ struct input_dev *input = field->hidinput->input;
if (hid->claimed & HID_CLAIMED_INPUT) {
switch (usage->hid) {
@@ -670,6 +718,9 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
break;
default:
+ if (usage->type)
+ input_event(input, usage->type, usage->code,
+ value);
return;
}
@@ -677,28 +728,18 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
/* we only take into account the last report. */
if (usage->hid == td->last_slot_field)
mt_complete_slot(td, field->hidinput->input);
-
- if (field->index == td->last_field_index
- && td->num_received >= td->num_expected)
- mt_sync_frame(td, field->hidinput->input);
}
}
}
-static void mt_report(struct hid_device *hid, struct hid_report *report)
+static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
struct hid_field *field;
unsigned count;
int r, n;
- if (report->id != td->mt_report_id)
- return;
-
- if (!(hid->claimed & HID_CLAIMED_INPUT))
- return;
-
/*
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
@@ -721,6 +762,91 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
mt_process_mt_event(hid, field, &field->usage[n],
field->value[n]);
}
+
+ if (td->num_received >= td->num_expected)
+ mt_sync_frame(td, report->field[0]->hidinput->input);
+}
+
+static void 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;
+
+ if (!td->maxcontacts)
+ td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+ mt_post_parse(td);
+ if (td->serial_maybe)
+ mt_post_parse_default_settings(td);
+
+ if (cls->is_indirect)
+ td->mt_flags |= INPUT_MT_POINTER;
+
+ if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ td->mt_flags |= INPUT_MT_DROP_UNUSED;
+
+ input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+
+ td->mt_flags = 0;
+}
+
+static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ /* Only map fields from TouchScreen or TouchPad collections.
+ * We need to ignore fields that belong to other collections
+ * such as Mouse that might have the same GenericDesktop usages. */
+ if (field->application != HID_DG_TOUCHSCREEN &&
+ field->application != HID_DG_PEN &&
+ field->application != HID_DG_TOUCHPAD)
+ return -1;
+
+ if (field->physical == HID_DG_STYLUS)
+ return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
+
+ return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+}
+
+static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (field->physical == HID_DG_STYLUS)
+ return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
+
+ return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
+}
+
+static int mt_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mt_device *td = hid_get_drvdata(hid);
+
+ if (field->report->id == td->mt_report_id)
+ return mt_touch_event(hid, field, usage, value);
+
+ if (field->report->id == td->pen_report_id)
+ return mt_pen_event(hid, field, usage, value);
+
+ /* ignore other reports */
+ return 1;
+}
+
+static void mt_report(struct hid_device *hid, struct hid_report *report)
+{
+ struct mt_device *td = hid_get_drvdata(hid);
+
+ if (!(hid->claimed & HID_CLAIMED_INPUT))
+ return;
+
+ if (report->id == td->mt_report_id)
+ mt_touch_report(hid, report);
+
+ if (report->id == td->pen_report_id)
+ mt_pen_report(hid, report);
}
static void mt_set_input_mode(struct hid_device *hdev)
@@ -736,7 +862,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
r = re->report_id_hash[td->inputmode];
if (r) {
r->field[0]->value[td->inputmode_index] = 0x02;
- usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
}
}
@@ -761,7 +887,7 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
max = min(fieldmax, max);
if (r->field[0]->value[0] != max) {
r->field[0]->value[0] = max;
- usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
}
}
}
@@ -797,32 +923,18 @@ static void mt_post_parse(struct mt_device *td)
}
static void mt_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;
+ char *name = kstrdup(hdev->name, GFP_KERNEL);
- /* Only initialize slots for MT input devices */
- if (!test_bit(ABS_MT_POSITION_X, input->absbit))
- return;
+ if (name)
+ hi->input->name = name;
- if (!td->maxcontacts)
- td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+ if (hi->report->id == td->mt_report_id)
+ mt_touch_input_configured(hdev, hi);
- mt_post_parse(td);
- if (td->serial_maybe)
- mt_post_parse_default_settings(td);
-
- if (cls->is_indirect)
- td->mt_flags |= INPUT_MT_POINTER;
-
- if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
- td->mt_flags |= INPUT_MT_DROP_UNUSED;
-
- input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
-
- td->mt_flags = 0;
+ if (hi->report->id == td->pen_report_id)
+ mt_pen_input_configured(hdev, hi);
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -830,6 +942,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
int ret, i;
struct mt_device *td;
struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+ struct hid_input *hi;
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
@@ -843,6 +956,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+ /*
+ * This allows the driver to handle different input sensors
+ * that emits events through different reports on the same HID
+ * device.
+ */
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+ hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
+
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
@@ -852,6 +973,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->inputmode = -1;
td->maxcontact_report_id = -1;
td->cc_index = -1;
+ td->mt_report_id = -1;
+ td->pen_report_id = -1;
hid_set_drvdata(hdev, td);
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
@@ -870,7 +993,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
- goto fail;
+ goto hid_fail;
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
@@ -882,6 +1005,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
+hid_fail:
+ list_for_each_entry(hi, &hdev->inputs, list)
+ mt_free_input_name(hi);
fail:
kfree(td->fields);
kfree(td);
@@ -898,26 +1024,11 @@ static int mt_reset_resume(struct hid_device *hdev)
static int mt_resume(struct hid_device *hdev)
{
- struct usb_interface *intf;
- struct usb_host_interface *interface;
- struct usb_device *dev;
-
- if (hdev->bus != BUS_USB)
- return 0;
-
- intf = to_usb_interface(hdev->dev.parent);
- interface = intf->cur_altsetting;
- dev = hid_to_usb_dev(hdev);
-
/* Some Elan legacy devices require SET_IDLE to be set on resume.
* It should be safe to send it to other devices too.
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
- usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- HID_REQ_SET_IDLE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, interface->desc.bInterfaceNumber,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
+ hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
return 0;
}
@@ -926,8 +1037,14 @@ static int mt_resume(struct hid_device *hdev)
static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
+ struct hid_input *hi;
+
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
hid_hw_stop(hdev);
+
+ list_for_each_entry(hi, &hdev->inputs, list)
+ mt_free_input_name(hi);
+
kfree(td);
hid_set_drvdata(hdev, NULL);
}
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 7757e82416e7..ef95102515e4 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -118,8 +118,8 @@ static inline int ntrig_get_mode(struct hid_device *hdev)
if (!report)
return -EINVAL;
- usbhid_submit_report(hdev, report, USB_DIR_IN);
- usbhid_wait_io(hdev);
+ hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
+ hid_hw_wait(hdev);
return (int)report->field[0]->value[0];
}
@@ -137,7 +137,7 @@ static inline void ntrig_set_mode(struct hid_device *hdev, const int mode)
if (!report)
return;
- usbhid_submit_report(hdev, report, USB_DIR_IN);
+ hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
}
static void ntrig_report_version(struct hid_device *hdev)
@@ -937,8 +937,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (report) {
/* Let the device settle to ensure the wakeup message gets
* through */
- usbhid_wait_io(hdev);
- usbhid_submit_report(hdev, report, USB_DIR_IN);
+ hid_hw_wait(hdev);
+ hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
/*
* Sanity check: if the current mode is invalid reset it to
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h
index 020cef69f6a1..e56d847b2ef1 100644
--- a/drivers/hid/hid-picolcd.h
+++ b/drivers/hid/hid-picolcd.h
@@ -142,10 +142,10 @@ struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
#ifdef CONFIG_DEBUG_FS
void picolcd_debug_out_report(struct picolcd_data *data,
struct hid_device *hdev, struct hid_report *report);
-#define usbhid_submit_report(a, b, c) \
+#define hid_hw_request(a, b, c) \
do { \
picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
- usbhid_submit_report(a, b, c); \
+ hid_hw_request(a, b, c); \
} while (0)
void picolcd_debug_raw_event(struct picolcd_data *data,
@@ -302,7 +302,7 @@ static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report
static inline void picolcd_exit_cir(struct picolcd_data *data)
{
}
-#endif /* CONFIG_HID_PICOLCD_LIRC */
+#endif /* CONFIG_HID_PICOLCD_CIR */
int picolcd_reset(struct hid_device *hdev);
struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c
index b91f30945f9c..a32c5f86b0b3 100644
--- a/drivers/hid/hid-picolcd_backlight.c
+++ b/drivers/hid/hid-picolcd_backlight.c
@@ -18,8 +18,6 @@
***************************************************************************/
#include <linux/hid.h>
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/backlight.h>
@@ -46,7 +44,7 @@ static int picolcd_set_brightness(struct backlight_device *bdev)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
if (!(data->status & PICOLCD_FAILED))
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index a79e95bb9fb6..e346038f0f11 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
index 31cd93fc3d4b..b48092d0e139 100644
--- a/drivers/hid/hid-picolcd_core.c
+++ b/drivers/hid/hid-picolcd_core.c
@@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
@@ -110,7 +108,7 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
work = NULL;
} else {
data->pending = work;
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
spin_lock_irqsave(&data->lock, flags);
@@ -244,7 +242,7 @@ int picolcd_reset(struct hid_device *hdev)
spin_unlock_irqrestore(&data->lock, flags);
return -ENODEV;
}
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
error = picolcd_check_version(hdev);
@@ -303,7 +301,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, timeout & 0xff);
hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return count;
}
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c
index 4809aa1bdb9c..59ab8e157e6b 100644
--- a/drivers/hid/hid-picolcd_debugfs.c
+++ b/drivers/hid/hid-picolcd_debugfs.c
@@ -19,8 +19,6 @@
#include <linux/hid.h>
#include <linux/hid-debug.h>
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/seq_file.h>
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c
index eb003574b634..591f6b22aa94 100644
--- a/drivers/hid/hid-picolcd_fb.c
+++ b/drivers/hid/hid-picolcd_fb.c
@@ -19,8 +19,6 @@
#include <linux/hid.h>
#include <linux/vmalloc.h>
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/module.h>
@@ -143,8 +141,8 @@ static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
else
hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
- usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
- usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report1, HID_REQ_SET_REPORT);
+ hid_hw_request(data->hdev, report2, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
@@ -214,7 +212,7 @@ int picolcd_fb_reset(struct picolcd_data *data, int clear)
hid_set_field(report->field[0], j, mapcmd[j]);
else
hid_set_field(report->field[0], j, 0);
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
}
spin_unlock_irqrestore(&data->lock, flags);
@@ -270,7 +268,7 @@ static void picolcd_fb_update(struct fb_info *info)
mutex_unlock(&info->lock);
if (!data)
return;
- usbhid_wait_io(data->hdev);
+ hid_hw_wait(data->hdev);
mutex_lock(&info->lock);
n = 0;
}
@@ -288,7 +286,7 @@ static void picolcd_fb_update(struct fb_info *info)
spin_unlock_irqrestore(&fbdata->lock, flags);
mutex_unlock(&info->lock);
if (data)
- usbhid_wait_io(data->hdev);
+ hid_hw_wait(data->hdev);
return;
}
out:
diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c
index 2d0ddc5ac65f..89821c2da6d7 100644
--- a/drivers/hid/hid-picolcd_lcd.c
+++ b/drivers/hid/hid-picolcd_lcd.c
@@ -18,8 +18,6 @@
***************************************************************************/
#include <linux/hid.h>
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/lcd.h>
@@ -48,7 +46,7 @@ static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_contrast);
if (!(data->status & PICOLCD_FAILED))
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
index 28cb6a4f9634..e994f9c29012 100644
--- a/drivers/hid/hid-picolcd_leds.c
+++ b/drivers/hid/hid-picolcd_leds.c
@@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
@@ -55,7 +53,7 @@ void picolcd_leds_set(struct picolcd_data *data)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->led_state);
if (!(data->status & PICOLCD_FAILED))
- usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+ hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
}
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index b0199d27787b..d29112fa5cd5 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -43,13 +43,11 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include "hid-ids.h"
#ifdef CONFIG_PANTHERLORD_FF
-#include "usbhid/usbhid.h"
struct plff_device {
struct hid_report *report;
@@ -75,7 +73,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
*plff->strong = left;
*plff->weak = right;
debug("running with 0x%02x 0x%02x", left, right);
- usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+ hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -169,7 +167,7 @@ static int plff_init(struct hid_device *hid)
*strong = 0x00;
*weak = 0x00;
- usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+ hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
}
hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 4e1c4bcbdc03..7ed828056414 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -26,7 +26,6 @@
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
-#include "usbhid/usbhid.h"
#include "hid-ids.h"
@@ -306,7 +305,7 @@ static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state)
report->field[0]->value[0] = 0x01;
report->field[0]->value[1] = state;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data)
diff --git a/drivers/hid/hid-roccat-isku.c b/drivers/hid/hid-roccat-isku.c
index 1219998a02d6..8023751d5257 100644
--- a/drivers/hid/hid-roccat-isku.c
+++ b/drivers/hid/hid-roccat-isku.c
@@ -130,14 +130,14 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
if (off >= real_size)
return 0;
- if (off != 0 || count != real_size)
+ if (off != 0 || count > real_size)
return -EINVAL;
mutex_lock(&isku->isku_lock);
- retval = isku_receive(usb_dev, command, buf, real_size);
+ retval = isku_receive(usb_dev, command, buf, count);
mutex_unlock(&isku->isku_lock);
- return retval ? retval : real_size;
+ return retval ? retval : count;
}
static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
@@ -150,15 +150,15 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
- if (off != 0 || count != real_size)
+ if (off != 0 || count > real_size)
return -EINVAL;
mutex_lock(&isku->isku_lock);
retval = roccat_common2_send_with_status(usb_dev, command,
- (void *)buf, real_size);
+ (void *)buf, count);
mutex_unlock(&isku->isku_lock);
- return retval ? retval : real_size;
+ return retval ? retval : count;
}
#define ISKU_SYSFS_W(thingy, THINGY) \
@@ -216,6 +216,7 @@ ISKU_SYSFS_RW(light, LIGHT)
ISKU_SYSFS_RW(key_mask, KEY_MASK)
ISKU_SYSFS_RW(last_set, LAST_SET)
ISKU_SYSFS_W(talk, TALK)
+ISKU_SYSFS_W(talkfx, TALKFX)
ISKU_SYSFS_R(info, INFO)
ISKU_SYSFS_W(control, CONTROL)
ISKU_SYSFS_W(reset, RESET)
@@ -232,6 +233,7 @@ static struct bin_attribute isku_bin_attributes[] = {
ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
ISKU_BIN_ATTR_RW(last_set, LAST_SET),
ISKU_BIN_ATTR_W(talk, TALK),
+ ISKU_BIN_ATTR_W(talkfx, TALKFX),
ISKU_BIN_ATTR_R(info, INFO),
ISKU_BIN_ATTR_W(control, CONTROL),
ISKU_BIN_ATTR_W(reset, RESET),
@@ -405,6 +407,7 @@ static int isku_raw_event(struct hid_device *hdev,
static const struct hid_device_id isku_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) },
{ }
};
@@ -443,5 +446,5 @@ module_init(isku_init);
module_exit(isku_exit);
MODULE_AUTHOR("Stefan Achatz");
-MODULE_DESCRIPTION("USB Roccat Isku driver");
+MODULE_DESCRIPTION("USB Roccat Isku/FX driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-isku.h b/drivers/hid/hid-roccat-isku.h
index cf6896c83867..53056860d4d8 100644
--- a/drivers/hid/hid-roccat-isku.h
+++ b/drivers/hid/hid-roccat-isku.h
@@ -25,10 +25,11 @@ enum {
ISKU_SIZE_KEYS_MACRO = 0x23,
ISKU_SIZE_KEYS_CAPSLOCK = 0x06,
ISKU_SIZE_LAST_SET = 0x14,
- ISKU_SIZE_LIGHT = 0x0a,
+ ISKU_SIZE_LIGHT = 0x10,
ISKU_SIZE_MACRO = 0x823,
ISKU_SIZE_RESET = 0x03,
ISKU_SIZE_TALK = 0x10,
+ ISKU_SIZE_TALKFX = 0x10,
};
enum {
@@ -59,6 +60,7 @@ enum isku_commands {
ISKU_COMMAND_LAST_SET = 0x14,
ISKU_COMMAND_15 = 0x15,
ISKU_COMMAND_TALK = 0x16,
+ ISKU_COMMAND_TALKFX = 0x17,
ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
};
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 9ce2d0b615a4..7fae070788fa 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -818,8 +818,9 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
(uint8_t *)&roccat_report);
break;
case kone_mouse_event_call_overlong_macro:
+ case kone_mouse_event_multimedia:
if (event->value == kone_keystroke_action_press) {
- roccat_report.event = kone_mouse_event_call_overlong_macro;
+ roccat_report.event = event->event;
roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor,
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 64abb5b8a59a..52c6167d023e 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -169,6 +169,7 @@ enum kone_mouse_events {
/* TODO clarify meaning and occurence of kone_mouse_event_calibration */
kone_mouse_event_calibration = 0xc0,
kone_mouse_event_call_overlong_macro = 0xe0,
+ kone_mouse_event_multimedia = 0xe1,
/* switch events notify if user changed values with mousebutton click */
kone_mouse_event_switch_dpi = 0xf0,
kone_mouse_event_switch_profile = 0xf1
diff --git a/drivers/hid/hid-roccat-konepure.c b/drivers/hid/hid-roccat-konepure.c
new file mode 100644
index 000000000000..c79d0b06c143
--- /dev/null
+++ b/drivers/hid/hid-roccat-konepure.c
@@ -0,0 +1,304 @@
+/*
+ * Roccat KonePure driver for Linux
+ *
+ * Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Roccat KonePure is a smaller version of KoneXTD with less buttons and lights.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-konepure.h"
+
+static struct class *konepure_class;
+
+static ssize_t konepure_sysfs_read(struct file *fp, struct kobject *kobj,
+ char *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off >= real_size)
+ return 0;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&konepure->konepure_lock);
+ retval = roccat_common2_receive(usb_dev, command, buf, real_size);
+ mutex_unlock(&konepure->konepure_lock);
+
+ return retval ? retval : real_size;
+}
+
+static ssize_t konepure_sysfs_write(struct file *fp, struct kobject *kobj,
+ void const *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct konepure_device *konepure = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&konepure->konepure_lock);
+ retval = roccat_common2_send_with_status(usb_dev, command,
+ (void *)buf, real_size);
+ mutex_unlock(&konepure->konepure_lock);
+
+ return retval ? retval : real_size;
+}
+
+#define KONEPURE_SYSFS_W(thingy, THINGY) \
+static ssize_t konepure_sysfs_write_ ## thingy(struct file *fp, \
+ struct kobject *kobj, struct bin_attribute *attr, char *buf, \
+ loff_t off, size_t count) \
+{ \
+ return konepure_sysfs_write(fp, kobj, buf, off, count, \
+ KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
+}
+
+#define KONEPURE_SYSFS_R(thingy, THINGY) \
+static ssize_t konepure_sysfs_read_ ## thingy(struct file *fp, \
+ struct kobject *kobj, struct bin_attribute *attr, char *buf, \
+ loff_t off, size_t count) \
+{ \
+ return konepure_sysfs_read(fp, kobj, buf, off, count, \
+ KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
+}
+
+#define KONEPURE_SYSFS_RW(thingy, THINGY) \
+KONEPURE_SYSFS_W(thingy, THINGY) \
+KONEPURE_SYSFS_R(thingy, THINGY)
+
+#define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \
+{ \
+ .attr = { .name = #thingy, .mode = 0660 }, \
+ .size = KONEPURE_SIZE_ ## THINGY, \
+ .read = konepure_sysfs_read_ ## thingy, \
+ .write = konepure_sysfs_write_ ## thingy \
+}
+
+#define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \
+{ \
+ .attr = { .name = #thingy, .mode = 0440 }, \
+ .size = KONEPURE_SIZE_ ## THINGY, \
+ .read = konepure_sysfs_read_ ## thingy, \
+}
+
+#define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
+{ \
+ .attr = { .name = #thingy, .mode = 0220 }, \
+ .size = KONEPURE_SIZE_ ## THINGY, \
+ .write = konepure_sysfs_write_ ## thingy \
+}
+
+KONEPURE_SYSFS_RW(actual_profile, ACTUAL_PROFILE)
+KONEPURE_SYSFS_W(control, CONTROL)
+KONEPURE_SYSFS_RW(info, INFO)
+KONEPURE_SYSFS_W(talk, TALK)
+KONEPURE_SYSFS_W(macro, MACRO)
+KONEPURE_SYSFS_RW(sensor, SENSOR)
+KONEPURE_SYSFS_RW(tcu, TCU)
+KONEPURE_SYSFS_R(tcu_image, TCU_IMAGE)
+KONEPURE_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
+KONEPURE_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
+
+static struct bin_attribute konepure_bin_attributes[] = {
+ KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE),
+ KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL),
+ KONEPURE_BIN_ATTRIBUTE_RW(info, INFO),
+ KONEPURE_BIN_ATTRIBUTE_W(talk, TALK),
+ KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO),
+ KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR),
+ KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU),
+ KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
+ KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
+ KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
+ __ATTR_NULL
+};
+
+static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
+ struct konepure_device *konepure)
+{
+ mutex_init(&konepure->konepure_lock);
+
+ return 0;
+}
+
+static int konepure_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct konepure_device *konepure;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE) {
+ hid_set_drvdata(hdev, NULL);
+ return 0;
+ }
+
+ konepure = kzalloc(sizeof(*konepure), GFP_KERNEL);
+ if (!konepure) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, konepure);
+
+ retval = konepure_init_konepure_device_struct(usb_dev, konepure);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct konepure_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(konepure_class, hdev,
+ sizeof(struct konepure_mouse_report_button));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ konepure->chrdev_minor = retval;
+ konepure->roccat_claimed = 1;
+ }
+
+ return 0;
+exit_free:
+ kfree(konepure);
+ return retval;
+}
+
+static void konepure_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct konepure_device *konepure;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return;
+
+ konepure = hid_get_drvdata(hdev);
+ if (konepure->roccat_claimed)
+ roccat_disconnect(konepure->chrdev_minor);
+ kfree(konepure);
+}
+
+static int konepure_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = konepure_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void konepure_remove(struct hid_device *hdev)
+{
+ konepure_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static int konepure_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct konepure_device *konepure = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ if (data[0] != KONEPURE_MOUSE_REPORT_NUMBER_BUTTON)
+ return 0;
+
+ if (konepure != NULL && konepure->roccat_claimed)
+ roccat_report_event(konepure->chrdev_minor, data);
+
+ return 0;
+}
+
+static const struct hid_device_id konepure_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, konepure_devices);
+
+static struct hid_driver konepure_driver = {
+ .name = "konepure",
+ .id_table = konepure_devices,
+ .probe = konepure_probe,
+ .remove = konepure_remove,
+ .raw_event = konepure_raw_event
+};
+
+static int __init konepure_init(void)
+{
+ int retval;
+
+ konepure_class = class_create(THIS_MODULE, "konepure");
+ if (IS_ERR(konepure_class))
+ return PTR_ERR(konepure_class);
+ konepure_class->dev_bin_attrs = konepure_bin_attributes;
+
+ retval = hid_register_driver(&konepure_driver);
+ if (retval)
+ class_destroy(konepure_class);
+ return retval;
+}
+
+static void __exit konepure_exit(void)
+{
+ hid_unregister_driver(&konepure_driver);
+ class_destroy(konepure_class);
+}
+
+module_init(konepure_init);
+module_exit(konepure_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat KonePure driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-konepure.h b/drivers/hid/hid-roccat-konepure.h
new file mode 100644
index 000000000000..2cd24e93dfd6
--- /dev/null
+++ b/drivers/hid/hid-roccat-konepure.h
@@ -0,0 +1,72 @@
+#ifndef __HID_ROCCAT_KONEPURE_H
+#define __HID_ROCCAT_KONEPURE_H
+
+/*
+ * Copyright (c) 2012 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/types.h>
+
+enum {
+ KONEPURE_SIZE_ACTUAL_PROFILE = 0x03,
+ KONEPURE_SIZE_CONTROL = 0x03,
+ KONEPURE_SIZE_FIRMWARE_WRITE = 0x0402,
+ KONEPURE_SIZE_INFO = 0x06,
+ KONEPURE_SIZE_MACRO = 0x0822,
+ KONEPURE_SIZE_PROFILE_SETTINGS = 0x1f,
+ KONEPURE_SIZE_PROFILE_BUTTONS = 0x3b,
+ KONEPURE_SIZE_SENSOR = 0x06,
+ KONEPURE_SIZE_TALK = 0x10,
+ KONEPURE_SIZE_TCU = 0x04,
+ KONEPURE_SIZE_TCU_IMAGE = 0x0404,
+};
+
+enum konepure_control_requests {
+ KONEPURE_CONTROL_REQUEST_GENERAL = 0x80,
+ KONEPURE_CONTROL_REQUEST_BUTTONS = 0x90,
+};
+
+enum konepure_commands {
+ KONEPURE_COMMAND_CONTROL = 0x04,
+ KONEPURE_COMMAND_ACTUAL_PROFILE = 0x05,
+ KONEPURE_COMMAND_PROFILE_SETTINGS = 0x06,
+ KONEPURE_COMMAND_PROFILE_BUTTONS = 0x07,
+ KONEPURE_COMMAND_MACRO = 0x08,
+ KONEPURE_COMMAND_INFO = 0x09,
+ KONEPURE_COMMAND_TCU = 0x0c,
+ KONEPURE_COMMAND_TCU_IMAGE = 0x0c,
+ KONEPURE_COMMAND_E = 0x0e,
+ KONEPURE_COMMAND_SENSOR = 0x0f,
+ KONEPURE_COMMAND_TALK = 0x10,
+ KONEPURE_COMMAND_FIRMWARE_WRITE = 0x1b,
+ KONEPURE_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
+};
+
+enum {
+ KONEPURE_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct konepure_mouse_report_button {
+ uint8_t report_number; /* always KONEPURE_MOUSE_REPORT_NUMBER_BUTTON */
+ uint8_t zero;
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+ uint8_t zero2;
+ uint8_t unknown[2];
+} __packed;
+
+struct konepure_device {
+ int roccat_claimed;
+ int chrdev_minor;
+ struct mutex konepure_lock;
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index d7437ef5c695..b59b3df9ca95 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -242,7 +242,6 @@ static int roccat_release(struct inode *inode, struct file *file)
* roccat_report_event() - output data to readers
* @minor: minor device number returned by roccat_connect()
* @data: pointer to data
- * @len: size of data
*
* Return value is zero on success, a negative error code on failure.
*
@@ -290,6 +289,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* @class: the class thats used to create the device. Meant to hold device
* specific sysfs attributes.
* @hid: the hid device the char device should be connected to.
+ * @report_size: size of reports
*
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 6679788bf75a..ca7498107327 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -18,8 +18,6 @@
*/
#include <linux/device.h>
#include <linux/hid.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
@@ -204,8 +202,8 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
goto done_proc;
}
hid_set_field(report->field[field_index], 0, value);
- usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
- usbhid_wait_io(hsdev->hdev);
+ hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
+ hid_hw_wait(hsdev->hdev);
done_proc:
mutex_unlock(&data->mutex);
@@ -227,8 +225,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
ret = -EINVAL;
goto done_proc;
}
- usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
- usbhid_wait_io(hsdev->hdev);
+ hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
+ hid_hw_wait(hsdev->hdev);
*value = report->field[field_index]->value[0];
done_proc:
@@ -262,7 +260,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
spin_unlock_irqrestore(&data->lock, flags);
goto err_free;
}
- usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
+ hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) {
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index 28f774003f03..37845eccddb5 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -28,13 +28,11 @@
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_SMARTJOYPLUS_FF
-#include "usbhid/usbhid.h"
struct sjoyff_device {
struct hid_report *report;
@@ -57,7 +55,7 @@ static int hid_sjoyff_play(struct input_dev *dev, void *data,
sjoyff->report->field[0]->value[1] = right;
sjoyff->report->field[0]->value[2] = left;
dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
- usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+ hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -115,7 +113,7 @@ static int sjoyff_init(struct hid_device *hid)
sjoyff->report->field[0]->value[0] = 0x01;
sjoyff->report->field[0]->value[1] = 0x00;
sjoyff->report->field[0]->value[2] = 0x00;
- usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
+ hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
}
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c
index e94371a059cb..a2f587d004e1 100644
--- a/drivers/hid/hid-speedlink.c
+++ b/drivers/hid/hid-speedlink.c
@@ -16,10 +16,8 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
-#include <linux/usb.h>
#include "hid-ids.h"
-#include "usbhid/usbhid.h"
static const struct hid_device_id speedlink_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)},
diff --git a/drivers/hid/hid-steelseries.c b/drivers/hid/hid-steelseries.c
index 2ed995cda44a..9b0efb0083fe 100644
--- a/drivers/hid/hid-steelseries.c
+++ b/drivers/hid/hid-steelseries.c
@@ -16,7 +16,6 @@
#include <linux/hid.h>
#include <linux/module.h>
-#include "usbhid/usbhid.h"
#include "hid-ids.h"
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
@@ -132,7 +131,7 @@ static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
value[14] = 0x00;
value[15] = 0x00;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
/* Note: LED change does not show on device until the device is read/polled */
}
@@ -378,16 +377,5 @@ static struct hid_driver steelseries_srws1_driver = {
.report_fixup = steelseries_srws1_report_fixup
};
-static int __init steelseries_srws1_init(void)
-{
- return hid_register_driver(&steelseries_srws1_driver);
-}
-
-static void __exit steelseries_srws1_exit(void)
-{
- hid_unregister_driver(&steelseries_srws1_driver);
-}
-
-module_init(steelseries_srws1_init);
-module_exit(steelseries_srws1_exit);
+module_hid_driver(steelseries_srws1_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index 2055a52e9a20..99342cfa0ea2 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -12,7 +12,6 @@
#include <linux/hid.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/usb.h>
#include "hid-ids.h"
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index e4fcf3f702a5..b83376077d72 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -30,7 +30,6 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
@@ -46,7 +45,6 @@ static const signed short ff_joystick[] = {
};
#ifdef CONFIG_THRUSTMASTER_FF
-#include "usbhid/usbhid.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
@@ -103,7 +101,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
ff_field->value[0] = x;
ff_field->value[1] = y;
- usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break;
case FF_RUMBLE:
@@ -117,7 +115,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
ff_field->value[0] = left;
ff_field->value[1] = right;
- usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break;
}
return 0;
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 0fb8ab93db68..e5ee1f20bbd9 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -789,12 +789,20 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
input_report_abs(wdata->ir, yid, y);
}
-static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+/* reduced status report with "BB BB" key data only */
+static void handler_status_K(struct wiimote_data *wdata,
+ const __u8 *payload)
{
handler_keys(wdata, payload);
/* on status reports the drm is reset so we need to resend the drm */
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
+/* extended status report with "BB BB LF 00 00 VV" data */
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_status_K(wdata, payload);
wiiext_event(wdata, payload[2] & 0x02);
@@ -804,6 +812,12 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
}
}
+/* reduced generic report with "BB BB" key data only */
+static void handler_generic_K(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+}
+
static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
{
__u16 offset = payload[3] << 8 | payload[4];
@@ -947,16 +961,26 @@ struct wiiproto_handler {
static struct wiiproto_handler handlers[] = {
{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+ { .id = WIIPROTO_REQ_STATUS, .size = 2, .func = handler_status_K },
{ .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
+ { .id = WIIPROTO_REQ_DATA, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
+ { .id = WIIPROTO_REQ_RETURN, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
+ { .id = WIIPROTO_REQ_DRM_KA, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
+ { .id = WIIPROTO_REQ_DRM_KE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
+ { .id = WIIPROTO_REQ_DRM_KAI, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
+ { .id = WIIPROTO_REQ_DRM_KEE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
+ { .id = WIIPROTO_REQ_DRM_KAE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
+ { .id = WIIPROTO_REQ_DRM_KIE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
+ { .id = WIIPROTO_REQ_DRM_KAIE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
@@ -970,7 +994,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
struct wiiproto_handler *h;
int i;
unsigned long flags;
- bool handled = false;
if (size < 1)
return -EINVAL;
@@ -981,11 +1004,11 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
h = &handlers[i];
if (h->id == raw_data[0] && h->size < size) {
h->func(wdata, &raw_data[1]);
- handled = true;
+ break;
}
}
- if (!handled)
+ if (!handlers[i].id)
hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
size);
@@ -1160,6 +1183,7 @@ static void wiimote_destroy(struct wiimote_data *wdata)
wiimote_leds_destroy(wdata);
power_supply_unregister(&wdata->battery);
+ kfree(wdata->battery.name);
input_unregister_device(wdata->accel);
input_unregister_device(wdata->ir);
input_unregister_device(wdata->input);
@@ -1216,9 +1240,14 @@ static int wiimote_hid_probe(struct hid_device *hdev,
wdata->battery.properties = wiimote_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
wdata->battery.get_property = wiimote_battery_get_property;
- wdata->battery.name = "wiimote_battery";
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
wdata->battery.use_for_apm = 0;
+ wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s",
+ wdata->hdev->uniq);
+ if (!wdata->battery.name) {
+ ret = -ENOMEM;
+ goto err_battery_name;
+ }
ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
if (ret) {
@@ -1254,6 +1283,8 @@ err_free:
return ret;
err_battery:
+ kfree(wdata->battery.name);
+err_battery_name:
input_unregister_device(wdata->input);
wdata->input = NULL;
err_input:
@@ -1283,6 +1314,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
static const struct hid_device_id wiimote_hid_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_WIIMOTE) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
};
MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index af66452592e9..6ec28a37c146 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -24,13 +24,11 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_ZEROPLUS_FF
-#include "usbhid/usbhid.h"
struct zpff_device {
struct hid_report *report;
@@ -59,7 +57,7 @@ static int zpff_play(struct input_dev *dev, void *data,
zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right;
dbg_hid("running with 0x%02x 0x%02x\n", left, right);
- usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+ hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
return 0;
}
@@ -104,7 +102,7 @@ static int zpff_init(struct hid_device *hid)
zpff->report->field[1]->value[0] = 0x02;
zpff->report->field[2]->value[0] = 0x00;
zpff->report->field[3]->value[0] = 0x00;
- usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
+ hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index ec7930217a6d..2b1799a3b212 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -563,6 +563,36 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret;
}
+static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
+ int reqtype)
+{
+ struct i2c_client *client = hid->driver_data;
+ char *buf;
+ int ret;
+ int len = i2c_hid_get_report_length(rep) - 2;
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return;
+
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
+ if (ret < 0)
+ dev_err(&client->dev, "%s: unable to get report: %d\n",
+ __func__, ret);
+ else
+ hid_input_report(hid, rep->type, buf, ret, 0);
+ break;
+ case HID_REQ_SET_REPORT:
+ hid_output_report(rep, buf);
+ i2c_hid_output_raw_report(hid, buf, len, rep->type);
+ break;
+ }
+
+ kfree(buf);
+}
+
static int i2c_hid_parse(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
@@ -742,6 +772,7 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open,
.close = i2c_hid_close,
.power = i2c_hid_power,
+ .request = i2c_hid_request,
.hidinput_input_event = i2c_hid_hidinput_input_event,
};
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 8e0c4bf94ebc..99418285222c 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -639,7 +639,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
}
}
-void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
+static void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
@@ -648,7 +648,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
__usbhid_submit_report(hid, report, dir);
spin_unlock_irqrestore(&usbhid->lock, flags);
}
-EXPORT_SYMBOL_GPL(usbhid_submit_report);
/* Workqueue routine to send requests to change LEDs */
static void hid_led(struct work_struct *work)
@@ -706,7 +705,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return 0;
}
-int usbhid_wait_io(struct hid_device *hid)
+static int usbhid_wait_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -720,7 +719,6 @@ int usbhid_wait_io(struct hid_device *hid)
return 0;
}
-EXPORT_SYMBOL_GPL(usbhid_wait_io);
static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
{
@@ -1243,6 +1241,32 @@ static int usbhid_power(struct hid_device *hid, int lvl)
return r;
}
+static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
+{
+ switch (reqtype) {
+ case HID_REQ_GET_REPORT:
+ usbhid_submit_report(hid, rep, USB_DIR_IN);
+ break;
+ case HID_REQ_SET_REPORT:
+ usbhid_submit_report(hid, rep, USB_DIR_OUT);
+ break;
+ }
+}
+
+static int usbhid_idle(struct hid_device *hid, int report, int idle,
+ int reqtype)
+{
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int ifnum = interface->desc.bInterfaceNumber;
+
+ if (reqtype != HID_REQ_SET_IDLE)
+ return -EINVAL;
+
+ return hid_set_idle(dev, ifnum, report, idle);
+}
+
static struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse,
.start = usbhid_start,
@@ -1251,6 +1275,9 @@ static struct hid_ll_driver usb_hid_driver = {
.close = usbhid_close,
.power = usbhid_power,
.hidinput_input_event = usb_hidinput_input_event,
+ .request = usbhid_request,
+ .wait = usbhid_wait_io,
+ .idle = usbhid_idle,
};
static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -1493,7 +1520,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
{
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
- int status;
+ int status = 0;
bool driver_suspended = false;
if (PMSG_IS_AUTO(message)) {
@@ -1520,19 +1547,15 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
}
} else {
- if (hid->driver && hid->driver->suspend) {
+ /* TODO: resume() might need to handle suspend failure */
+ if (hid->driver && hid->driver->suspend)
status = hid->driver->suspend(hid, message);
- if (status < 0)
- return status;
- }
driver_suspended = true;
spin_lock_irq(&usbhid->lock);
set_bit(HID_SUSPENDED, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
- if (usbhid_wait_io(hid) < 0) {
+ if (usbhid_wait_io(hid) < 0)
status = -EIO;
- goto failed;
- }
}
hid_cancel_delayed_stuff(usbhid);
@@ -1544,7 +1567,7 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
goto failed;
}
dev_dbg(&intf->dev, "suspend\n");
- return 0;
+ return status;
failed:
hid_resume_common(hid, driver_suspended);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index f91c136821f7..10b616702780 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -263,8 +263,8 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
envelope->attack_level,
pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
+ HID_REQ_SET_REPORT);
}
/*
@@ -290,8 +290,8 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff,
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -325,8 +325,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -357,8 +357,8 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
+ HID_REQ_SET_REPORT);
}
@@ -399,8 +399,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
+ HID_REQ_SET_REPORT);
}
}
@@ -440,8 +440,8 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
effect->u.ramp.start_level);
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
effect->u.ramp.end_level);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
+ HID_REQ_SET_REPORT);
}
/*
@@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
int j;
pidff->create_new_effect_type->value[0] = efnum;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
+ HID_REQ_SET_REPORT);
hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0;
- usbhid_wait_io(pidff->hid);
+ hid_hw_wait(pidff->hid);
for (j = 0; j < 60; j++) {
hid_dbg(pidff->hid, "pid_block_load requested\n");
- usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
- USB_DIR_IN);
- usbhid_wait_io(pidff->hid);
+ hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+ HID_REQ_GET_REPORT);
+ hid_hw_wait(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
@@ -513,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
- usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+ HID_REQ_SET_REPORT);
}
/**
@@ -535,8 +535,8 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value)
static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
{
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
+ HID_REQ_SET_REPORT);
}
/*
@@ -551,7 +551,7 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
effect_id, pidff->pid_id[effect_id]);
/* Wait for the queue to clear. We do not want a full fifo to
prevent the effect removal. */
- usbhid_wait_io(pidff->hid);
+ hid_hw_wait(pidff->hid);
pidff_playback_pid(pidff, pid_id, 0);
pidff_erase_pid(pidff, pid_id);
@@ -718,8 +718,8 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain)
struct pidff_device *pidff = dev->ff->private;
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ HID_REQ_SET_REPORT);
}
static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
@@ -744,8 +744,8 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
pidff->set_effect[PID_START_DELAY].value[0] = 0;
- usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
- USB_DIR_OUT);
+ hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ HID_REQ_SET_REPORT);
}
/*
@@ -1158,19 +1158,19 @@ static void pidff_reset(struct pidff_device *pidff)
pidff->device_control->value[0] = pidff->control_id[PID_RESET];
/* We reset twice as sometimes hid_wait_io isn't waiting long enough */
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
pidff->device_control->value[0] =
pidff->control_id[PID_ENABLE_ACTUATORS];
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
/* pool report is sometimes messed up, refetch it */
- usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
@@ -1181,9 +1181,9 @@ static void pidff_reset(struct pidff_device *pidff)
break;
}
hid_dbg(pidff->hid, "pid_pool requested again\n");
- usbhid_submit_report(hid, pidff->reports[PID_POOL],
- USB_DIR_IN);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, pidff->reports[PID_POOL],
+ HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
}
}
}
@@ -1269,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
- usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
+ HID_REQ_SET_REPORT);
}
error = pidff_check_autocenter(pidff, dev);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index e0e6abf1cd3b..19b8360f2330 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -73,6 +73,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
@@ -80,6 +81,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 87bd64959a91..2f1ddca6f2e0 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -705,8 +705,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL)
break;
- usbhid_submit_report(hid, report, USB_DIR_IN);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, report, HID_REQ_GET_REPORT);
+ hid_hw_wait(hid);
r = 0;
break;
@@ -724,8 +724,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL)
break;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
- usbhid_wait_io(hid);
+ hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+ hid_hw_wait(hid);
r = 0;
break;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index bd87a61e5303..dbb6af699135 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -34,12 +34,9 @@
#include <linux/input.h>
/* API provided by hid-core.c for USB HID drivers */
-int usbhid_wait_io(struct hid_device* hid);
void usbhid_close(struct hid_device *hid);
int usbhid_open(struct hid_device *hid);
void usbhid_init_reports(struct hid_device *hid);
-void usbhid_submit_report
-(struct hid_device *hid, struct hid_report *report, unsigned char dir);
int usbhid_get_power(struct hid_device *hid);
void usbhid_put_power(struct hid_device *hid);
struct usb_interface *usbhid_find_interface(int minor);
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index 64630f15f181..0403b51d20ba 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -2,7 +2,7 @@ menu "Microsoft Hyper-V guest support"
config HYPERV
tristate "Microsoft Hyper-V client drivers"
- depends on X86 && ACPI && PCI && X86_LOCAL_APIC
+ depends on X86 && ACPI && PCI && X86_LOCAL_APIC && HYPERVISOR_GUEST
help
Select this option to run Linux as a Hyper-V client operating
system.
diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
index e6abfa02d8b7..0a74b5661186 100644
--- a/drivers/hv/Makefile
+++ b/drivers/hv/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o
-hv_utils-y := hv_util.o hv_kvp.o
+hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index ff1be167eb04..bad8128b283a 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -165,8 +165,19 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
struct vmbus_channel *channel = container_of(work,
struct vmbus_channel,
work);
+ unsigned long flags;
+ struct vmbus_channel_relid_released msg;
vmbus_device_unregister(channel->device_obj);
+ memset(&msg, 0, sizeof(struct vmbus_channel_relid_released));
+ msg.child_relid = channel->offermsg.child_relid;
+ msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
+ vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+
+ spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
+ list_del(&channel->listentry);
+ spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ free_channel(channel);
}
void vmbus_free_channels(void)
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 731158910c1e..ae4923756d98 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -289,9 +289,8 @@ void hv_synic_init(void *arg)
/* Check the version */
rdmsrl(HV_X64_MSR_SVERSION, version);
- hv_context.event_dpc[cpu] = (struct tasklet_struct *)
- kmalloc(sizeof(struct tasklet_struct),
- GFP_ATOMIC);
+ hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
+ GFP_ATOMIC);
if (hv_context.event_dpc[cpu] == NULL) {
pr_err("Unable to allocate event dpc\n");
goto cleanup;
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index 37873213e24f..4c605c70ebf9 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -117,7 +117,14 @@ union dm_caps {
struct {
__u64 balloon:1;
__u64 hot_add:1;
- __u64 reservedz:62;
+ /*
+ * To support guests that may have alignment
+ * limitations on hot-add, the guest can specify
+ * its alignment requirements; a value of n
+ * represents an alignment of 2^n in mega bytes.
+ */
+ __u64 hot_add_alignment:4;
+ __u64 reservedz:58;
} cap_bits;
__u64 caps;
} __packed;
@@ -412,13 +419,45 @@ struct dm_info_msg {
* End protocol definitions.
*/
-static bool hot_add;
+/*
+ * State to manage hot adding memory into the guest.
+ * The range start_pfn : end_pfn specifies the range
+ * that the host has asked us to hot add. The range
+ * start_pfn : ha_end_pfn specifies the range that we have
+ * currently hot added. We hot add in multiples of 128M
+ * chunks; it is possible that we may not be able to bring
+ * online all the pages in the region. The range
+ * covered_start_pfn : covered_end_pfn defines the pages that can
+ * be brough online.
+ */
+
+struct hv_hotadd_state {
+ struct list_head list;
+ unsigned long start_pfn;
+ unsigned long covered_start_pfn;
+ unsigned long covered_end_pfn;
+ unsigned long ha_end_pfn;
+ unsigned long end_pfn;
+};
+
+struct balloon_state {
+ __u32 num_pages;
+ struct work_struct wrk;
+};
+
+struct hot_add_wrk {
+ union dm_mem_page_range ha_page_range;
+ union dm_mem_page_range ha_region_range;
+ struct work_struct wrk;
+};
+
+static bool hot_add = true;
static bool do_hot_add;
/*
* Delay reporting memory pressure by
* the specified number of seconds.
*/
-static uint pressure_report_delay = 30;
+static uint pressure_report_delay = 45;
module_param(hot_add, bool, (S_IRUGO | S_IWUSR));
MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add");
@@ -446,6 +485,7 @@ enum hv_dm_state {
static __u8 recv_buffer[PAGE_SIZE];
static __u8 *send_buffer;
#define PAGES_IN_2M 512
+#define HA_CHUNK (32 * 1024)
struct hv_dynmem_device {
struct hv_device *dev;
@@ -459,7 +499,28 @@ struct hv_dynmem_device {
unsigned int num_pages_ballooned;
/*
- * This thread handles both balloon/hot-add
+ * State to manage the ballooning (up) operation.
+ */
+ struct balloon_state balloon_wrk;
+
+ /*
+ * State to execute the "hot-add" operation.
+ */
+ struct hot_add_wrk ha_wrk;
+
+ /*
+ * This state tracks if the host has specified a hot-add
+ * region.
+ */
+ bool host_specified_ha_region;
+
+ /*
+ * State to synchronize hot-add.
+ */
+ struct completion ol_waitevent;
+ bool ha_waiting;
+ /*
+ * This thread handles hot-add
* requests from the host as well as notifying
* the host with regards to memory pressure in
* the guest.
@@ -467,6 +528,11 @@ struct hv_dynmem_device {
struct task_struct *thread;
/*
+ * A list of hot-add regions.
+ */
+ struct list_head ha_region_list;
+
+ /*
* We start with the highest version we can support
* and downgrade based on the host; we save here the
* next version to try.
@@ -476,35 +542,358 @@ struct hv_dynmem_device {
static struct hv_dynmem_device dm_device;
-static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg)
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
{
+ int i;
- struct dm_hot_add_response resp;
+ for (i = 0; i < size; i++) {
+ struct page *pg;
+ pg = pfn_to_page(start_pfn + i);
+ __online_page_set_limits(pg);
+ __online_page_increment_counters(pg);
+ __online_page_free(pg);
+ }
+}
- if (do_hot_add) {
+static void hv_mem_hot_add(unsigned long start, unsigned long size,
+ unsigned long pfn_count,
+ struct hv_hotadd_state *has)
+{
+ int ret = 0;
+ int i, nid, t;
+ unsigned long start_pfn;
+ unsigned long processed_pfn;
+ unsigned long total_pfn = pfn_count;
+
+ for (i = 0; i < (size/HA_CHUNK); i++) {
+ start_pfn = start + (i * HA_CHUNK);
+ has->ha_end_pfn += HA_CHUNK;
+
+ if (total_pfn > HA_CHUNK) {
+ processed_pfn = HA_CHUNK;
+ total_pfn -= HA_CHUNK;
+ } else {
+ processed_pfn = total_pfn;
+ total_pfn = 0;
+ }
+
+ has->covered_end_pfn += processed_pfn;
+
+ init_completion(&dm_device.ol_waitevent);
+ dm_device.ha_waiting = true;
+
+ nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
+ ret = add_memory(nid, PFN_PHYS((start_pfn)),
+ (HA_CHUNK << PAGE_SHIFT));
- pr_info("Memory hot add not supported\n");
+ if (ret) {
+ pr_info("hot_add memory failed error is %d\n", ret);
+ if (ret == -EEXIST) {
+ /*
+ * This error indicates that the error
+ * is not a transient failure. This is the
+ * case where the guest's physical address map
+ * precludes hot adding memory. Stop all further
+ * memory hot-add.
+ */
+ do_hot_add = false;
+ }
+ has->ha_end_pfn -= HA_CHUNK;
+ has->covered_end_pfn -= processed_pfn;
+ break;
+ }
/*
- * Currently we do not support hot add.
- * Just fail the request.
+ * Wait for the memory block to be onlined.
*/
+ t = wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
+ if (t == 0) {
+ pr_info("hot_add memory timedout\n");
+ has->ha_end_pfn -= HA_CHUNK;
+ has->covered_end_pfn -= processed_pfn;
+ break;
+ }
+
+ }
+
+ return;
+}
+
+static void hv_online_page(struct page *pg)
+{
+ struct list_head *cur;
+ struct hv_hotadd_state *has;
+ unsigned long cur_start_pgp;
+ unsigned long cur_end_pgp;
+
+ if (dm_device.ha_waiting) {
+ dm_device.ha_waiting = false;
+ complete(&dm_device.ol_waitevent);
+ }
+
+ list_for_each(cur, &dm_device.ha_region_list) {
+ has = list_entry(cur, struct hv_hotadd_state, list);
+ cur_start_pgp = (unsigned long)
+ pfn_to_page(has->covered_start_pfn);
+ cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+ if (((unsigned long)pg >= cur_start_pgp) &&
+ ((unsigned long)pg < cur_end_pgp)) {
+ /*
+ * This frame is currently backed; online the
+ * page.
+ */
+ __online_page_set_limits(pg);
+ __online_page_increment_counters(pg);
+ __online_page_free(pg);
+ has->covered_start_pfn++;
+ }
+ }
+}
+
+static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+{
+ struct list_head *cur;
+ struct hv_hotadd_state *has;
+ unsigned long residual, new_inc;
+
+ if (list_empty(&dm_device.ha_region_list))
+ return false;
+
+ list_for_each(cur, &dm_device.ha_region_list) {
+ has = list_entry(cur, struct hv_hotadd_state, list);
+
+ /*
+ * If the pfn range we are dealing with is not in the current
+ * "hot add block", move on.
+ */
+ if ((start_pfn >= has->end_pfn))
+ continue;
+ /*
+ * If the current hot add-request extends beyond
+ * our current limit; extend it.
+ */
+ if ((start_pfn + pfn_cnt) > has->end_pfn) {
+ residual = (start_pfn + pfn_cnt - has->end_pfn);
+ /*
+ * Extend the region by multiples of HA_CHUNK.
+ */
+ new_inc = (residual / HA_CHUNK) * HA_CHUNK;
+ if (residual % HA_CHUNK)
+ new_inc += HA_CHUNK;
+
+ has->end_pfn += new_inc;
+ }
+
+ /*
+ * If the current start pfn is not where the covered_end
+ * is, update it.
+ */
+
+ if (has->covered_end_pfn != start_pfn) {
+ has->covered_end_pfn = start_pfn;
+ has->covered_start_pfn = start_pfn;
+ }
+ return true;
+
}
+ return false;
+}
+
+static unsigned long handle_pg_range(unsigned long pg_start,
+ unsigned long pg_count)
+{
+ unsigned long start_pfn = pg_start;
+ unsigned long pfn_cnt = pg_count;
+ unsigned long size;
+ struct list_head *cur;
+ struct hv_hotadd_state *has;
+ unsigned long pgs_ol = 0;
+ unsigned long old_covered_state;
+
+ if (list_empty(&dm_device.ha_region_list))
+ return 0;
+
+ list_for_each(cur, &dm_device.ha_region_list) {
+ has = list_entry(cur, struct hv_hotadd_state, list);
+
+ /*
+ * If the pfn range we are dealing with is not in the current
+ * "hot add block", move on.
+ */
+ if ((start_pfn >= has->end_pfn))
+ continue;
+
+ old_covered_state = has->covered_end_pfn;
+
+ if (start_pfn < has->ha_end_pfn) {
+ /*
+ * This is the case where we are backing pages
+ * in an already hot added region. Bring
+ * these pages online first.
+ */
+ pgs_ol = has->ha_end_pfn - start_pfn;
+ if (pgs_ol > pfn_cnt)
+ pgs_ol = pfn_cnt;
+ hv_bring_pgs_online(start_pfn, pgs_ol);
+ has->covered_end_pfn += pgs_ol;
+ has->covered_start_pfn += pgs_ol;
+ pfn_cnt -= pgs_ol;
+ }
+
+ if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
+ /*
+ * We have some residual hot add range
+ * that needs to be hot added; hot add
+ * it now. Hot add a multiple of
+ * of HA_CHUNK that fully covers the pages
+ * we have.
+ */
+ size = (has->end_pfn - has->ha_end_pfn);
+ if (pfn_cnt <= size) {
+ size = ((pfn_cnt / HA_CHUNK) * HA_CHUNK);
+ if (pfn_cnt % HA_CHUNK)
+ size += HA_CHUNK;
+ } else {
+ pfn_cnt = size;
+ }
+ hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has);
+ }
+ /*
+ * If we managed to online any pages that were given to us,
+ * we declare success.
+ */
+ return has->covered_end_pfn - old_covered_state;
+
+ }
+
+ return 0;
+}
+
+static unsigned long process_hot_add(unsigned long pg_start,
+ unsigned long pfn_cnt,
+ unsigned long rg_start,
+ unsigned long rg_size)
+{
+ struct hv_hotadd_state *ha_region = NULL;
+
+ if (pfn_cnt == 0)
+ return 0;
+
+ if (!dm_device.host_specified_ha_region)
+ if (pfn_covered(pg_start, pfn_cnt))
+ goto do_pg_range;
+
+ /*
+ * If the host has specified a hot-add range; deal with it first.
+ */
+
+ if (rg_size != 0) {
+ ha_region = kzalloc(sizeof(struct hv_hotadd_state), GFP_KERNEL);
+ if (!ha_region)
+ return 0;
+
+ INIT_LIST_HEAD(&ha_region->list);
+
+ list_add_tail(&ha_region->list, &dm_device.ha_region_list);
+ ha_region->start_pfn = rg_start;
+ ha_region->ha_end_pfn = rg_start;
+ ha_region->covered_start_pfn = pg_start;
+ ha_region->covered_end_pfn = pg_start;
+ ha_region->end_pfn = rg_start + rg_size;
+ }
+
+do_pg_range:
+ /*
+ * Process the page range specified; bringing them
+ * online if possible.
+ */
+ return handle_pg_range(pg_start, pfn_cnt);
+}
+
+#endif
+
+static void hot_add_req(struct work_struct *dummy)
+{
+ struct dm_hot_add_response resp;
+#ifdef CONFIG_MEMORY_HOTPLUG
+ unsigned long pg_start, pfn_cnt;
+ unsigned long rg_start, rg_sz;
+#endif
+ struct hv_dynmem_device *dm = &dm_device;
+
memset(&resp, 0, sizeof(struct dm_hot_add_response));
resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE;
resp.hdr.size = sizeof(struct dm_hot_add_response);
resp.hdr.trans_id = atomic_inc_return(&trans_id);
- resp.page_count = 0;
- resp.result = 0;
+#ifdef CONFIG_MEMORY_HOTPLUG
+ pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
+ pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
+
+ rg_start = dm->ha_wrk.ha_region_range.finfo.start_page;
+ rg_sz = dm->ha_wrk.ha_region_range.finfo.page_cnt;
+
+ if ((rg_start == 0) && (!dm->host_specified_ha_region)) {
+ unsigned long region_size;
+ unsigned long region_start;
+
+ /*
+ * The host has not specified the hot-add region.
+ * Based on the hot-add page range being specified,
+ * compute a hot-add region that can cover the pages
+ * that need to be hot-added while ensuring the alignment
+ * and size requirements of Linux as it relates to hot-add.
+ */
+ region_start = pg_start;
+ region_size = (pfn_cnt / HA_CHUNK) * HA_CHUNK;
+ if (pfn_cnt % HA_CHUNK)
+ region_size += HA_CHUNK;
+
+ region_start = (pg_start / HA_CHUNK) * HA_CHUNK;
+
+ rg_start = region_start;
+ rg_sz = region_size;
+ }
+
+ if (do_hot_add)
+ resp.page_count = process_hot_add(pg_start, pfn_cnt,
+ rg_start, rg_sz);
+#endif
+ /*
+ * The result field of the response structure has the
+ * following semantics:
+ *
+ * 1. If all or some pages hot-added: Guest should return success.
+ *
+ * 2. If no pages could be hot-added:
+ *
+ * If the guest returns success, then the host
+ * will not attempt any further hot-add operations. This
+ * signifies a permanent failure.
+ *
+ * If the guest returns failure, then this failure will be
+ * treated as a transient failure and the host may retry the
+ * hot-add operation after some delay.
+ */
+ if (resp.page_count > 0)
+ resp.result = 1;
+ else if (!do_hot_add)
+ resp.result = 1;
+ else
+ resp.result = 0;
+
+ if (!do_hot_add || (resp.page_count == 0))
+ pr_info("Memory hot add failed\n");
dm->state = DM_INITIALIZED;
vmbus_sendpacket(dm->dev->channel, &resp,
sizeof(struct dm_hot_add_response),
(unsigned long)NULL,
VM_PKT_DATA_INBAND, 0);
-
}
static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
@@ -523,7 +912,7 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
}
}
-unsigned long compute_balloon_floor(void)
+static unsigned long compute_balloon_floor(void)
{
unsigned long min_pages;
#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
@@ -644,6 +1033,14 @@ static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
dm->num_pages_ballooned += alloc_unit;
+ /*
+ * If we allocatted 2M pages; split them so we
+ * can free them in any order we get.
+ */
+
+ if (alloc_unit != 1)
+ split_page(pg, get_order(alloc_unit << PAGE_SHIFT));
+
bl_resp->range_count++;
bl_resp->range_array[i].finfo.start_page =
page_to_pfn(pg);
@@ -657,9 +1054,9 @@ static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages,
-static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
+static void balloon_up(struct work_struct *dummy)
{
- int num_pages = req->num_pages;
+ int num_pages = dm_device.balloon_wrk.num_pages;
int num_ballooned = 0;
struct dm_balloon_response *bl_resp;
int alloc_unit;
@@ -670,9 +1067,10 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
/*
- * Currently, we only support 4k allocations.
+ * We will attempt 2M allocations. However, if we fail to
+ * allocate 2M chunks, we will go back to 4k allocations.
*/
- alloc_unit = 1;
+ alloc_unit = 512;
while (!done) {
bl_resp = (struct dm_balloon_response *)send_buffer;
@@ -684,14 +1082,19 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
num_pages -= num_ballooned;
- num_ballooned = alloc_balloon_pages(dm, num_pages,
+ num_ballooned = alloc_balloon_pages(&dm_device, num_pages,
bl_resp, alloc_unit,
&alloc_error);
+ if ((alloc_error) && (alloc_unit != 1)) {
+ alloc_unit = 1;
+ continue;
+ }
+
if ((alloc_error) || (num_ballooned == num_pages)) {
bl_resp->more_pages = 0;
done = true;
- dm->state = DM_INITIALIZED;
+ dm_device.state = DM_INITIALIZED;
}
/*
@@ -719,7 +1122,7 @@ static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req)
pr_info("Balloon response failed\n");
for (i = 0; i < bl_resp->range_count; i++)
- free_balloon_pages(dm,
+ free_balloon_pages(&dm_device,
&bl_resp->range_array[i]);
done = true;
@@ -761,7 +1164,6 @@ static int dm_thread_func(void *dm_dev)
{
struct hv_dynmem_device *dm = dm_dev;
int t;
- unsigned long scan_start;
while (!kthread_should_stop()) {
t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ);
@@ -773,22 +1175,6 @@ static int dm_thread_func(void *dm_dev)
if (t == 0)
post_status(dm);
- scan_start = jiffies;
- switch (dm->state) {
- case DM_BALLOON_UP:
- balloon_up(dm, (struct dm_balloon *)recv_buffer);
- break;
-
- case DM_HOT_ADD:
- hot_add_req(dm, (struct dm_hot_add *)recv_buffer);
- break;
- default:
- break;
- }
-
- if (!time_in_range(jiffies, scan_start, scan_start + HZ))
- post_status(dm);
-
}
return 0;
@@ -861,6 +1247,10 @@ static void balloon_onchannelcallback(void *context)
struct dm_message *dm_msg;
struct dm_header *dm_hdr;
struct hv_dynmem_device *dm = hv_get_drvdata(dev);
+ struct dm_balloon *bal_msg;
+ struct dm_hot_add *ha_msg;
+ union dm_mem_page_range *ha_pg_range;
+ union dm_mem_page_range *ha_region;
memset(recv_buffer, 0, sizeof(recv_buffer));
vmbus_recvpacket(dev->channel, recv_buffer,
@@ -882,8 +1272,12 @@ static void balloon_onchannelcallback(void *context)
break;
case DM_BALLOON_REQUEST:
+ if (dm->state == DM_BALLOON_UP)
+ pr_warn("Currently ballooning\n");
+ bal_msg = (struct dm_balloon *)recv_buffer;
dm->state = DM_BALLOON_UP;
- complete(&dm->config_event);
+ dm_device.balloon_wrk.num_pages = bal_msg->num_pages;
+ schedule_work(&dm_device.balloon_wrk.wrk);
break;
case DM_UNBALLOON_REQUEST:
@@ -893,8 +1287,31 @@ static void balloon_onchannelcallback(void *context)
break;
case DM_MEM_HOT_ADD_REQUEST:
+ if (dm->state == DM_HOT_ADD)
+ pr_warn("Currently hot-adding\n");
dm->state = DM_HOT_ADD;
- complete(&dm->config_event);
+ ha_msg = (struct dm_hot_add *)recv_buffer;
+ if (ha_msg->hdr.size == sizeof(struct dm_hot_add)) {
+ /*
+ * This is a normal hot-add request specifying
+ * hot-add memory.
+ */
+ ha_pg_range = &ha_msg->range;
+ dm->ha_wrk.ha_page_range = *ha_pg_range;
+ dm->ha_wrk.ha_region_range.page_range = 0;
+ } else {
+ /*
+ * Host is specifying that we first hot-add
+ * a region and then partially populate this
+ * region.
+ */
+ dm->host_specified_ha_region = true;
+ ha_pg_range = &ha_msg->range;
+ ha_region = &ha_pg_range[1];
+ dm->ha_wrk.ha_page_range = *ha_pg_range;
+ dm->ha_wrk.ha_region_range = *ha_region;
+ }
+ schedule_work(&dm_device.ha_wrk.wrk);
break;
case DM_INFO_MESSAGE:
@@ -937,6 +1354,10 @@ static int balloon_probe(struct hv_device *dev,
dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7;
init_completion(&dm_device.host_event);
init_completion(&dm_device.config_event);
+ INIT_LIST_HEAD(&dm_device.ha_region_list);
+ INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
+ INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
+ dm_device.host_specified_ha_region = false;
dm_device.thread =
kthread_run(dm_thread_func, &dm_device, "hv_balloon");
@@ -945,6 +1366,10 @@ static int balloon_probe(struct hv_device *dev,
goto probe_error1;
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+ set_online_page_callback(&hv_online_page);
+#endif
+
hv_set_drvdata(dev, &dm_device);
/*
* Initiate the hand shake with the host and negotiate
@@ -962,8 +1387,7 @@ static int balloon_probe(struct hv_device *dev,
ret = vmbus_sendpacket(dev->channel, &version_req,
sizeof(struct dm_version_request),
(unsigned long)NULL,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ VM_PKT_DATA_INBAND, 0);
if (ret)
goto probe_error2;
@@ -990,13 +1414,13 @@ static int balloon_probe(struct hv_device *dev,
cap_msg.hdr.trans_id = atomic_inc_return(&trans_id);
cap_msg.caps.cap_bits.balloon = 1;
+ cap_msg.caps.cap_bits.hot_add = 1;
+
/*
- * While we currently don't support hot-add,
- * we still advertise this capability since the
- * host requires that guests partcipating in the
- * dynamic memory protocol support hot add.
+ * Specify our alignment requirements as it relates
+ * memory hot-add. Specify 128MB alignment.
*/
- cap_msg.caps.cap_bits.hot_add = 1;
+ cap_msg.caps.cap_bits.hot_add_alignment = 7;
/*
* Currently the host does not use these
@@ -1009,8 +1433,7 @@ static int balloon_probe(struct hv_device *dev,
ret = vmbus_sendpacket(dev->channel, &cap_msg,
sizeof(struct dm_capabilities),
(unsigned long)NULL,
- VM_PKT_DATA_INBAND,
- VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+ VM_PKT_DATA_INBAND, 0);
if (ret)
goto probe_error2;
@@ -1034,6 +1457,9 @@ static int balloon_probe(struct hv_device *dev,
return 0;
probe_error2:
+#ifdef CONFIG_MEMORY_HOTPLUG
+ restore_online_page_callback(&hv_online_page);
+#endif
kthread_stop(dm_device.thread);
probe_error1:
@@ -1046,13 +1472,26 @@ probe_error0:
static int balloon_remove(struct hv_device *dev)
{
struct hv_dynmem_device *dm = hv_get_drvdata(dev);
+ struct list_head *cur, *tmp;
+ struct hv_hotadd_state *has;
if (dm->num_pages_ballooned != 0)
pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
+ cancel_work_sync(&dm->balloon_wrk.wrk);
+ cancel_work_sync(&dm->ha_wrk.wrk);
+
vmbus_close(dev->channel);
kthread_stop(dm->thread);
kfree(send_buffer);
+#ifdef CONFIG_MEMORY_HOTPLUG
+ restore_online_page_callback(&hv_online_page);
+#endif
+ list_for_each_safe(cur, tmp, &dm->ha_region_list) {
+ has = list_entry(cur, struct hv_hotadd_state, list);
+ list_del(&has->list);
+ kfree(has);
+ }
return 0;
}
@@ -1079,14 +1518,7 @@ static int __init init_balloon_drv(void)
return vmbus_driver_register(&balloon_drv);
}
-static void exit_balloon_drv(void)
-{
-
- vmbus_driver_unregister(&balloon_drv);
-}
-
module_init(init_balloon_drv);
-module_exit(exit_balloon_drv);
MODULE_DESCRIPTION("Hyper-V Balloon");
MODULE_VERSION(HV_DRV_VERSION);
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
new file mode 100644
index 000000000000..8ad5653ce447
--- /dev/null
+++ b/drivers/hv/hv_snapshot.c
@@ -0,0 +1,287 @@
+/*
+ * An implementation of host initiated guest snapshot.
+ *
+ *
+ * Copyright (C) 2013, Microsoft, Inc.
+ * Author : K. Y. Srinivasan <kys@microsoft.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/net.h>
+#include <linux/nls.h>
+#include <linux/connector.h>
+#include <linux/workqueue.h>
+#include <linux/hyperv.h>
+
+
+
+/*
+ * Global state maintained for transaction that is being processed.
+ * Note that only one transaction can be active at any point in time.
+ *
+ * This state is set when we receive a request from the host; we
+ * cleanup this state when the transaction is completed - when we respond
+ * to the host with the key value.
+ */
+
+static struct {
+ bool active; /* transaction status - active or not */
+ int recv_len; /* number of bytes received. */
+ struct vmbus_channel *recv_channel; /* chn we got the request */
+ u64 recv_req_id; /* request ID. */
+ struct hv_vss_msg *msg; /* current message */
+} vss_transaction;
+
+
+static void vss_respond_to_host(int error);
+
+static struct cb_id vss_id = { CN_VSS_IDX, CN_VSS_VAL };
+static const char vss_name[] = "vss_kernel_module";
+static __u8 *recv_buffer;
+
+static void vss_send_op(struct work_struct *dummy);
+static DECLARE_WORK(vss_send_op_work, vss_send_op);
+
+/*
+ * Callback when data is received from user mode.
+ */
+
+static void
+vss_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
+{
+ struct hv_vss_msg *vss_msg;
+
+ vss_msg = (struct hv_vss_msg *)msg->data;
+
+ if (vss_msg->vss_hdr.operation == VSS_OP_REGISTER) {
+ pr_info("VSS daemon registered\n");
+ vss_transaction.active = false;
+ if (vss_transaction.recv_channel != NULL)
+ hv_vss_onchannelcallback(vss_transaction.recv_channel);
+ return;
+
+ }
+ vss_respond_to_host(vss_msg->error);
+}
+
+
+static void vss_send_op(struct work_struct *dummy)
+{
+ int op = vss_transaction.msg->vss_hdr.operation;
+ struct cn_msg *msg;
+ struct hv_vss_msg *vss_msg;
+
+ msg = kzalloc(sizeof(*msg) + sizeof(*vss_msg), GFP_ATOMIC);
+ if (!msg)
+ return;
+
+ vss_msg = (struct hv_vss_msg *)msg->data;
+
+ msg->id.idx = CN_VSS_IDX;
+ msg->id.val = CN_VSS_VAL;
+
+ vss_msg->vss_hdr.operation = op;
+ msg->len = sizeof(struct hv_vss_msg);
+
+ cn_netlink_send(msg, 0, GFP_ATOMIC);
+ kfree(msg);
+
+ return;
+}
+
+/*
+ * Send a response back to the host.
+ */
+
+static void
+vss_respond_to_host(int error)
+{
+ struct icmsg_hdr *icmsghdrp;
+ u32 buf_len;
+ struct vmbus_channel *channel;
+ u64 req_id;
+
+ /*
+ * If a transaction is not active; log and return.
+ */
+
+ if (!vss_transaction.active) {
+ /*
+ * This is a spurious call!
+ */
+ pr_warn("VSS: Transaction not active\n");
+ return;
+ }
+ /*
+ * Copy the global state for completing the transaction. Note that
+ * only one transaction can be active at a time.
+ */
+
+ buf_len = vss_transaction.recv_len;
+ channel = vss_transaction.recv_channel;
+ req_id = vss_transaction.recv_req_id;
+ vss_transaction.active = false;
+
+ icmsghdrp = (struct icmsg_hdr *)
+ &recv_buffer[sizeof(struct vmbuspipe_hdr)];
+
+ if (channel->onchannel_callback == NULL)
+ /*
+ * We have raced with util driver being unloaded;
+ * silently return.
+ */
+ return;
+
+ icmsghdrp->status = error;
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
+ VM_PKT_DATA_INBAND, 0);
+
+}
+
+/*
+ * This callback is invoked when we get a VSS message from the host.
+ * The host ensures that only one VSS transaction can be active at a time.
+ */
+
+void hv_vss_onchannelcallback(void *context)
+{
+ struct vmbus_channel *channel = context;
+ u32 recvlen;
+ u64 requestid;
+ struct hv_vss_msg *vss_msg;
+
+
+ struct icmsg_hdr *icmsghdrp;
+ struct icmsg_negotiate *negop = NULL;
+
+ if (vss_transaction.active) {
+ /*
+ * We will defer processing this callback once
+ * the current transaction is complete.
+ */
+ vss_transaction.recv_channel = channel;
+ return;
+ }
+
+ vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
+ &requestid);
+
+ if (recvlen > 0) {
+ icmsghdrp = (struct icmsg_hdr *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr)];
+
+ if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
+ /*
+ * We currently negotiate the highest number the
+ * host has presented. If this version is not
+ * atleast 5.0, reject.
+ */
+ negop = (struct icmsg_negotiate *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ if (negop->icversion_data[1].major < 5)
+ negop->icframe_vercnt = 0;
+ } else {
+ vss_msg = (struct hv_vss_msg *)&recv_buffer[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ /*
+ * Stash away this global state for completing the
+ * transaction; note transactions are serialized.
+ */
+
+ vss_transaction.recv_len = recvlen;
+ vss_transaction.recv_channel = channel;
+ vss_transaction.recv_req_id = requestid;
+ vss_transaction.active = true;
+ vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
+
+ switch (vss_msg->vss_hdr.operation) {
+ /*
+ * Initiate a "freeze/thaw"
+ * operation in the guest.
+ * We respond to the host once
+ * the operation is complete.
+ *
+ * We send the message to the
+ * user space daemon and the
+ * operation is performed in
+ * the daemon.
+ */
+ case VSS_OP_FREEZE:
+ case VSS_OP_THAW:
+ schedule_work(&vss_send_op_work);
+ return;
+
+ case VSS_OP_HOT_BACKUP:
+ vss_msg->vss_cf.flags =
+ VSS_HBU_NO_AUTO_RECOVERY;
+ vss_respond_to_host(0);
+ return;
+
+ case VSS_OP_GET_DM_INFO:
+ vss_msg->dm_info.flags = 0;
+ vss_respond_to_host(0);
+ return;
+
+ default:
+ vss_respond_to_host(0);
+ return;
+
+ }
+
+ }
+
+ icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
+ | ICMSGHDRFLAG_RESPONSE;
+
+ vmbus_sendpacket(channel, recv_buffer,
+ recvlen, requestid,
+ VM_PKT_DATA_INBAND, 0);
+ }
+
+}
+
+int
+hv_vss_init(struct hv_util_service *srv)
+{
+ int err;
+
+ err = cn_add_callback(&vss_id, vss_name, vss_cn_callback);
+ if (err)
+ return err;
+ recv_buffer = srv->recv_buffer;
+
+ /*
+ * When this driver loads, the user level daemon that
+ * processes the host requests may not yet be running.
+ * Defer processing channel callbacks until the daemon
+ * has registered.
+ */
+ vss_transaction.active = true;
+ return 0;
+}
+
+void hv_vss_deinit(void)
+{
+ cn_del_callback(&vss_id);
+ cancel_work_sync(&vss_send_op_work);
+}
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index 1d4cbd8e8261..2f561c5dfe24 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -49,6 +49,12 @@ static struct hv_util_service util_kvp = {
.util_deinit = hv_kvp_deinit,
};
+static struct hv_util_service util_vss = {
+ .util_cb = hv_vss_onchannelcallback,
+ .util_init = hv_vss_init,
+ .util_deinit = hv_vss_deinit,
+};
+
static void perform_shutdown(struct work_struct *dummy)
{
orderly_poweroff(true);
@@ -339,6 +345,10 @@ static const struct hv_vmbus_device_id id_table[] = {
{ HV_KVP_GUID,
.driver_data = (unsigned long)&util_kvp
},
+ /* VSS GUID */
+ { HV_VSS_GUID,
+ .driver_data = (unsigned long)&util_vss
+ },
{ },
};
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index cafa72ffdc30..d6fbb5772b8d 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -71,6 +71,7 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
{
+ smp_mb();
if (rbi->ring_buffer->interrupt_mask)
return false;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 89ac1cb26f24..9c333d471433 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -39,6 +39,19 @@ config HWMON_DEBUG_CHIP
comment "Native drivers"
+config SENSORS_AB8500
+ tristate "AB8500 thermal monitoring"
+ depends on AB8500_GPADC && AB8500_BM
+ default n
+ help
+ If you say yes here you get support for the thermal sensor part
+ of the AB8500 chip. The driver includes thermal management for
+ AB8500 die and two GPADC channels. The GPADC channel are preferably
+ used to access sensors outside the AB8500 chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called abx500-temp.
+
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
depends on X86 && DMI
@@ -179,9 +192,29 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_ADT7X10
+ tristate
+ help
+ This module contains common code shared by the ADT7310/ADT7320 and
+ ADT7410/ADT7420 temperature monitoring chip drivers.
+
+ If build as a module, the module will be called adt7x10.
+
+config SENSORS_ADT7310
+ tristate "Analog Devices ADT7310/ADT7320"
+ depends on SPI_MASTER
+ select SENSORS_ADT7X10
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7310 and ADT7320 temperature monitoring chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7310.
+
config SENSORS_ADT7410
tristate "Analog Devices ADT7410/ADT7420"
depends on I2C
+ select SENSORS_ADT7X10
help
If you say yes here you get support for the Analog Devices
ADT7410 and ADT7420 temperature monitoring chips.
@@ -499,6 +532,15 @@ config SENSORS_IBMPEX
This driver can also be built as a module. If so, the module
will be called ibmpex.
+config SENSORS_IIO_HWMON
+ tristate "Hwmon driver that uses channels specified via iio maps"
+ depends on IIO
+ help
+ This is a platform driver that in combination with a suitable
+ map allows IIO devices to provide basic hwmon functionality
+ for those channels specified in the map. This map can be provided
+ either via platform data or the device tree bindings.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on !PPC
@@ -751,6 +793,16 @@ config SENSORS_LTC4261
This driver can also be built as a module. If so, the module will
be called ltc4261.
+config SENSORS_LM95234
+ tristate "National Semiconductor LM95234"
+ depends on I2C
+ help
+ If you say yes here you get support for the LM95234 temperature
+ sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm95234.
+
config SENSORS_LM95241
tristate "National Semiconductor LM95241 and compatibles"
depends on I2C
@@ -877,8 +929,22 @@ config SENSORS_MCP3021
This driver can also be built as a module. If so, the module
will be called mcp3021.
+config SENSORS_NCT6775
+ tristate "Nuvoton NCT6775F and compatibles"
+ depends on !PPC
+ select HWMON_VID
+ help
+ If you say yes here you get support for the hardware monitoring
+ functionality of the Nuvoton NCT6775F, NCT6776F, NCT6779D
+ and compatible Super-I/O chips. This driver replaces the
+ w83627ehf driver for NCT6775F and NCT6776F.
+
+ This driver can also be built as a module. If so, the module
+ will be called nct6775.
+
config SENSORS_NTC_THERMISTOR
tristate "NTC thermistor support"
+ depends on (!OF && !IIO) || (OF && IIO)
help
This driver supports NTC thermistors sensor reading and its
interpretation. The driver can also monitor the temperature and
@@ -1204,8 +1270,8 @@ config SENSORS_TMP401
tristate "Texas Instruments TMP401 and compatibles"
depends on I2C
help
- If you say yes here you get support for Texas Instruments TMP401 and
- TMP411 temperature sensor chips.
+ If you say yes here you get support for Texas Instruments TMP401,
+ TMP411, TMP431, and TMP432 temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp401.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8d6d97ea7c1e..d17d3e64f9f4 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_W83795) += w83795.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
+obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o
@@ -34,6 +35,8 @@ obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
+obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o
+obj-$(CONFIG_SENSORS_ADT7310) += adt7310.o
obj-$(CONFIG_SENSORS_ADT7410) += adt7410.o
obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
@@ -65,6 +68,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
obj-$(CONFIG_SENSORS_INA209) += ina209.o
obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
@@ -86,6 +90,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
+obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
@@ -103,6 +108,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
+obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c
new file mode 100644
index 000000000000..d844dc806853
--- /dev/null
+++ b/drivers/hwmon/ab8500.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Hongbo Zhang <hongbo.zhang@linaro.org>
+ * License Terms: GNU General Public License v2
+ *
+ * When the AB8500 thermal warning temperature is reached (threshold cannot
+ * be changed by SW), an interrupt is set, and if no further action is taken
+ * within a certain time frame, pm_power off will be called.
+ *
+ * When AB8500 thermal shutdown temperature is reached a hardware shutdown of
+ * the AB8500 will occur.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/ab8500.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include "abx500.h"
+
+#define DEFAULT_POWER_OFF_DELAY (HZ * 10)
+#define THERMAL_VCC 1800
+#define PULL_UP_RESISTOR 47000
+/* Number of monitored sensors should not greater than NUM_SENSORS */
+#define NUM_MONITORED_SENSORS 4
+
+struct ab8500_gpadc_cfg {
+ const struct abx500_res_to_temp *temp_tbl;
+ int tbl_sz;
+ int vcc;
+ int r_up;
+};
+
+struct ab8500_temp {
+ struct ab8500_gpadc *gpadc;
+ struct ab8500_btemp *btemp;
+ struct delayed_work power_off_work;
+ struct ab8500_gpadc_cfg cfg;
+ struct abx500_temp *abx500_data;
+};
+
+/*
+ * The hardware connection is like this:
+ * VCC----[ R_up ]-----[ NTC ]----GND
+ * where R_up is pull-up resistance, and GPADC measures voltage on NTC.
+ * and res_to_temp table is strictly sorted by falling resistance values.
+ */
+static int ab8500_voltage_to_temp(struct ab8500_gpadc_cfg *cfg,
+ int v_ntc, int *temp)
+{
+ int r_ntc, i = 0, tbl_sz = cfg->tbl_sz;
+ const struct abx500_res_to_temp *tbl = cfg->temp_tbl;
+
+ if (cfg->vcc < 0 || v_ntc >= cfg->vcc)
+ return -EINVAL;
+
+ r_ntc = v_ntc * cfg->r_up / (cfg->vcc - v_ntc);
+ if (r_ntc > tbl[0].resist || r_ntc < tbl[tbl_sz - 1].resist)
+ return -EINVAL;
+
+ while (!(r_ntc <= tbl[i].resist && r_ntc > tbl[i + 1].resist) &&
+ i < tbl_sz - 2)
+ i++;
+
+ /* return milli-Celsius */
+ *temp = tbl[i].temp * 1000 + ((tbl[i + 1].temp - tbl[i].temp) * 1000 *
+ (r_ntc - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
+
+ return 0;
+}
+
+static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp)
+{
+ int voltage, ret;
+ struct ab8500_temp *ab8500_data = data->plat_data;
+
+ if (sensor == BAT_CTRL) {
+ *temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
+ } else if (sensor == BTEMP_BALL) {
+ *temp = ab8500_btemp_get_temp(ab8500_data->btemp);
+ } else {
+ voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor);
+ if (voltage < 0)
+ return voltage;
+
+ ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ab8500_thermal_power_off(struct work_struct *work)
+{
+ struct ab8500_temp *ab8500_data = container_of(work,
+ struct ab8500_temp, power_off_work.work);
+ struct abx500_temp *abx500_data = ab8500_data->abx500_data;
+
+ dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n");
+
+ pm_power_off();
+}
+
+static ssize_t ab8500_show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "ab8500\n");
+}
+
+static ssize_t ab8500_show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ char *label;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int index = attr->index;
+
+ switch (index) {
+ case 1:
+ label = "ext_adc1";
+ break;
+ case 2:
+ label = "ext_adc2";
+ break;
+ case 3:
+ label = "bat_temp";
+ break;
+ case 4:
+ label = "bat_ctrl";
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return sprintf(buf, "%s\n", label);
+}
+
+static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data)
+{
+ struct ab8500_temp *ab8500_data = data->plat_data;
+
+ dev_warn(&data->pdev->dev, "Power off in %d s\n",
+ DEFAULT_POWER_OFF_DELAY / HZ);
+
+ schedule_delayed_work(&ab8500_data->power_off_work,
+ DEFAULT_POWER_OFF_DELAY);
+ return 0;
+}
+
+int abx500_hwmon_init(struct abx500_temp *data)
+{
+ struct ab8500_temp *ab8500_data;
+
+ ab8500_data = devm_kzalloc(&data->pdev->dev, sizeof(*ab8500_data),
+ GFP_KERNEL);
+ if (!ab8500_data)
+ return -ENOMEM;
+
+ ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ if (IS_ERR(ab8500_data->gpadc))
+ return PTR_ERR(ab8500_data->gpadc);
+
+ ab8500_data->btemp = ab8500_btemp_get();
+ if (IS_ERR(ab8500_data->btemp))
+ return PTR_ERR(ab8500_data->btemp);
+
+ INIT_DELAYED_WORK(&ab8500_data->power_off_work,
+ ab8500_thermal_power_off);
+
+ ab8500_data->cfg.vcc = THERMAL_VCC;
+ ab8500_data->cfg.r_up = PULL_UP_RESISTOR;
+ ab8500_data->cfg.temp_tbl = ab8500_temp_tbl_a_thermistor;
+ ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size;
+
+ data->plat_data = ab8500_data;
+
+ /*
+ * ADC_AUX1 and ADC_AUX2, connected to external NTC
+ * BTEMP_BALL and BAT_CTRL, fixed usage
+ */
+ data->gpadc_addr[0] = ADC_AUX1;
+ data->gpadc_addr[1] = ADC_AUX2;
+ data->gpadc_addr[2] = BTEMP_BALL;
+ data->gpadc_addr[3] = BAT_CTRL;
+ data->monitored_sensors = NUM_MONITORED_SENSORS;
+
+ data->ops.read_sensor = ab8500_read_sensor;
+ data->ops.irq_handler = ab8500_temp_irq_handler;
+ data->ops.show_name = ab8500_show_name;
+ data->ops.show_label = ab8500_show_label;
+ data->ops.is_visible = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(abx500_hwmon_init);
+
+MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@linaro.org>");
+MODULE_DESCRIPTION("AB8500 temperature driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 6119ff8e8c87..df0b69987914 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -96,9 +96,12 @@
#define ABIT_UGURU_MAX_TIMEOUTS 2
/* utility macros */
#define ABIT_UGURU_NAME "abituguru"
-#define ABIT_UGURU_DEBUG(level, format, arg...) \
- if (level <= verbose) \
- printk(KERN_DEBUG ABIT_UGURU_NAME ": " format , ## arg)
+#define ABIT_UGURU_DEBUG(level, format, arg...) \
+ do { \
+ if (level <= verbose) \
+ pr_debug(format , ## arg); \
+ } while (0)
+
/* Macros to help calculate the sysfs_names array length */
/*
* sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
@@ -1533,7 +1536,7 @@ static int abituguru_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume);
-#define ABIT_UGURU_PM &abituguru_pm
+#define ABIT_UGURU_PM (&abituguru_pm)
#else
#define ABIT_UGURU_PM NULL
#endif /* CONFIG_PM */
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 205327d33c4d..1d2da31c27c6 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -76,9 +76,11 @@
#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
/* utility macros */
#define ABIT_UGURU3_NAME "abituguru3"
-#define ABIT_UGURU3_DEBUG(format, arg...) \
- if (verbose) \
- printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
+#define ABIT_UGURU3_DEBUG(format, arg...) \
+ do { \
+ if (verbose) \
+ pr_debug(format , ## arg); \
+ } while (0)
/* Macros to help calculate the sysfs_names array length */
#define ABIT_UGURU3_MAX_NO_SENSORS 26
@@ -1159,7 +1161,7 @@ static int abituguru3_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(abituguru3_pm, abituguru3_suspend, abituguru3_resume);
-#define ABIT_UGURU3_PM &abituguru3_pm
+#define ABIT_UGURU3_PM (&abituguru3_pm)
#else
#define ABIT_UGURU3_PM NULL
#endif /* CONFIG_PM */
diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c
new file mode 100644
index 000000000000..b4ad87b31a37
--- /dev/null
+++ b/drivers/hwmon/abx500.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Hongbo Zhang <hongbo.zhang@linaro.org>
+ * License Terms: GNU General Public License v2
+ *
+ * ABX500 does not provide auto ADC, so to monitor the required temperatures,
+ * a periodic work is used. It is more important to not wake up the CPU than
+ * to perform this job, hence the use of a deferred delay.
+ *
+ * A deferred delay for thermal monitor is considered safe because:
+ * If the chip gets too hot during a sleep state it's most likely due to
+ * external factors, such as the surrounding temperature. I.e. no SW decisions
+ * will make any difference.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include "abx500.h"
+
+#define DEFAULT_MONITOR_DELAY HZ
+#define DEFAULT_MAX_TEMP 130
+
+static inline void schedule_monitor(struct abx500_temp *data)
+{
+ data->work_active = true;
+ schedule_delayed_work(&data->work, DEFAULT_MONITOR_DELAY);
+}
+
+static void threshold_updated(struct abx500_temp *data)
+{
+ int i;
+ for (i = 0; i < data->monitored_sensors; i++)
+ if (data->max[i] != 0 || data->min[i] != 0) {
+ schedule_monitor(data);
+ return;
+ }
+
+ dev_dbg(&data->pdev->dev, "No active thresholds.\n");
+ cancel_delayed_work_sync(&data->work);
+ data->work_active = false;
+}
+
+static void gpadc_monitor(struct work_struct *work)
+{
+ int temp, i, ret;
+ char alarm_node[30];
+ bool updated_min_alarm, updated_max_alarm;
+ struct abx500_temp *data;
+
+ data = container_of(work, struct abx500_temp, work.work);
+ mutex_lock(&data->lock);
+
+ for (i = 0; i < data->monitored_sensors; i++) {
+ /* Thresholds are considered inactive if set to 0 */
+ if (data->max[i] == 0 && data->min[i] == 0)
+ continue;
+
+ if (data->max[i] < data->min[i])
+ continue;
+
+ ret = data->ops.read_sensor(data, data->gpadc_addr[i], &temp);
+ if (ret < 0) {
+ dev_err(&data->pdev->dev, "GPADC read failed\n");
+ continue;
+ }
+
+ updated_min_alarm = false;
+ updated_max_alarm = false;
+
+ if (data->min[i] != 0) {
+ if (temp < data->min[i]) {
+ if (data->min_alarm[i] == false) {
+ data->min_alarm[i] = true;
+ updated_min_alarm = true;
+ }
+ } else {
+ if (data->min_alarm[i] == true) {
+ data->min_alarm[i] = false;
+ updated_min_alarm = true;
+ }
+ }
+ }
+ if (data->max[i] != 0) {
+ if (temp > data->max[i]) {
+ if (data->max_alarm[i] == false) {
+ data->max_alarm[i] = true;
+ updated_max_alarm = true;
+ }
+ } else if (temp < data->max[i] - data->max_hyst[i]) {
+ if (data->max_alarm[i] == true) {
+ data->max_alarm[i] = false;
+ updated_max_alarm = true;
+ }
+ }
+ }
+
+ if (updated_min_alarm) {
+ ret = sprintf(alarm_node, "temp%d_min_alarm", i + 1);
+ sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
+ }
+ if (updated_max_alarm) {
+ ret = sprintf(alarm_node, "temp%d_max_alarm", i + 1);
+ sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
+ }
+ }
+
+ schedule_monitor(data);
+ mutex_unlock(&data->lock);
+}
+
+/* HWMON sysfs interfaces */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ /* Show chip name */
+ return data->ops.show_name(dev, devattr, buf);
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ /* Show each sensor label */
+ return data->ops.show_label(dev, devattr, buf);
+}
+
+static ssize_t show_input(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int ret, temp;
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ u8 gpadc_addr = data->gpadc_addr[attr->index];
+
+ ret = data->ops.read_sensor(data, gpadc_addr, &temp);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+/* Set functions (RW nodes) */
+static ssize_t set_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = kstrtol(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+ mutex_lock(&data->lock);
+ data->min[attr->index] = val;
+ threshold_updated(data);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = kstrtol(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+ mutex_lock(&data->lock);
+ data->max[attr->index] = val;
+ threshold_updated(data);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t set_max_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int res = kstrtoul(buf, 10, &val);
+ if (res < 0)
+ return res;
+
+ val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
+
+ mutex_lock(&data->lock);
+ data->max_hyst[attr->index] = val;
+ threshold_updated(data);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+/* Show functions (RO nodes) */
+static ssize_t show_min(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%ld\n", data->min[attr->index]);
+}
+
+static ssize_t show_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%ld\n", data->max[attr->index]);
+}
+
+static ssize_t show_max_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%ld\n", data->max_hyst[attr->index]);
+}
+
+static ssize_t show_min_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%d\n", data->min_alarm[attr->index]);
+}
+
+static ssize_t show_max_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct abx500_temp *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ return sprintf(buf, "%d\n", data->max_alarm[attr->index]);
+}
+
+static mode_t abx500_attrs_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct abx500_temp *data = dev_get_drvdata(dev);
+
+ if (data->ops.is_visible)
+ return data->ops.is_visible(attr, n);
+
+ return attr->mode;
+}
+
+/* Chip name, required by hwmon */
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+/* GPADC - SENSOR1 */
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_min, set_min, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_min_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_max_alarm, NULL, 0);
+
+/* GPADC - SENSOR2 */
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_min_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_max_alarm, NULL, 1);
+
+/* GPADC - SENSOR3 */
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_min_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_max_alarm, NULL, 2);
+
+/* GPADC - SENSOR4 */
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_label, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_min, set_min, 3);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_max, set_max, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IWUSR | S_IRUGO,
+ show_max_hyst, set_max_hyst, 3);
+static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_min_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_max_alarm, NULL, 3);
+
+struct attribute *abx500_temp_attributes[] = {
+ &sensor_dev_attr_name.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_label.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp3_label.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp4_label.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group abx500_temp_group = {
+ .attrs = abx500_temp_attributes,
+ .is_visible = abx500_attrs_visible,
+};
+
+static irqreturn_t abx500_temp_irq_handler(int irq, void *irq_data)
+{
+ struct platform_device *pdev = irq_data;
+ struct abx500_temp *data = platform_get_drvdata(pdev);
+
+ data->ops.irq_handler(irq, data);
+ return IRQ_HANDLED;
+}
+
+static int setup_irqs(struct platform_device *pdev)
+{
+ int ret;
+ int irq = platform_get_irq_byname(pdev, "ABX500_TEMP_WARM");
+
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Get irq by name failed\n");
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ abx500_temp_irq_handler, IRQF_NO_SUSPEND, "abx500-temp", pdev);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int abx500_temp_probe(struct platform_device *pdev)
+{
+ struct abx500_temp *data;
+ int err;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->pdev = pdev;
+ mutex_init(&data->lock);
+
+ /* Chip specific initialization */
+ err = abx500_hwmon_init(data);
+ if (err < 0 || !data->ops.read_sensor || !data->ops.show_name ||
+ !data->ops.show_label)
+ return err;
+
+ INIT_DEFERRABLE_WORK(&data->work, gpadc_monitor);
+
+ platform_set_drvdata(pdev, data);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &abx500_temp_group);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err);
+ return err;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+ goto exit_sysfs_group;
+ }
+
+ if (data->ops.irq_handler) {
+ err = setup_irqs(pdev);
+ if (err < 0)
+ goto exit_hwmon_reg;
+ }
+ return 0;
+
+exit_hwmon_reg:
+ hwmon_device_unregister(data->hwmon_dev);
+exit_sysfs_group:
+ sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
+ return err;
+}
+
+static int abx500_temp_remove(struct platform_device *pdev)
+{
+ struct abx500_temp *data = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&data->work);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
+
+ return 0;
+}
+
+static int abx500_temp_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct abx500_temp *data = platform_get_drvdata(pdev);
+
+ if (data->work_active)
+ cancel_delayed_work_sync(&data->work);
+
+ return 0;
+}
+
+static int abx500_temp_resume(struct platform_device *pdev)
+{
+ struct abx500_temp *data = platform_get_drvdata(pdev);
+
+ if (data->work_active)
+ schedule_monitor(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id abx500_temp_match[] = {
+ { .compatible = "stericsson,abx500-temp" },
+ {},
+};
+#endif
+
+static struct platform_driver abx500_temp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "abx500-temp",
+ .of_match_table = of_match_ptr(abx500_temp_match),
+ },
+ .suspend = abx500_temp_suspend,
+ .resume = abx500_temp_resume,
+ .probe = abx500_temp_probe,
+ .remove = abx500_temp_remove,
+};
+
+module_platform_driver(abx500_temp_driver);
+
+MODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>");
+MODULE_DESCRIPTION("ABX500 temperature driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/abx500.h b/drivers/hwmon/abx500.h
new file mode 100644
index 000000000000..9b295e684d0e
--- /dev/null
+++ b/drivers/hwmon/abx500.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) ST-Ericsson 2010 - 2013
+ * License terms: GNU General Public License v2
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Hongbo Zhang <hongbo.zhang@linaro.com>
+ */
+
+#ifndef _ABX500_H
+#define _ABX500_H
+
+#define NUM_SENSORS 5
+
+struct abx500_temp;
+
+/*
+ * struct abx500_temp_ops - abx500 chip specific ops
+ * @read_sensor: reads gpadc output
+ * @irq_handler: irq handler
+ * @show_name: hwmon device name
+ * @show_label: hwmon attribute label
+ * @is_visible: is attribute visible
+ */
+struct abx500_temp_ops {
+ int (*read_sensor)(struct abx500_temp *, u8, int *);
+ int (*irq_handler)(int, struct abx500_temp *);
+ ssize_t (*show_name)(struct device *,
+ struct device_attribute *, char *);
+ ssize_t (*show_label) (struct device *,
+ struct device_attribute *, char *);
+ int (*is_visible)(struct attribute *, int);
+};
+
+/*
+ * struct abx500_temp - representation of temp mon device
+ * @pdev: platform device
+ * @hwmon_dev: hwmon device
+ * @ops: abx500 chip specific ops
+ * @gpadc_addr: gpadc channel address
+ * @min: sensor temperature min value
+ * @max: sensor temperature max value
+ * @max_hyst: sensor temperature hysteresis value for max limit
+ * @min_alarm: sensor temperature min alarm
+ * @max_alarm: sensor temperature max alarm
+ * @work: delayed work scheduled to monitor temperature periodically
+ * @work_active: True if work is active
+ * @lock: mutex
+ * @monitored_sensors: number of monitored sensors
+ * @plat_data: private usage, usually points to platform specific data
+ */
+struct abx500_temp {
+ struct platform_device *pdev;
+ struct device *hwmon_dev;
+ struct abx500_temp_ops ops;
+ u8 gpadc_addr[NUM_SENSORS];
+ unsigned long min[NUM_SENSORS];
+ unsigned long max[NUM_SENSORS];
+ unsigned long max_hyst[NUM_SENSORS];
+ bool min_alarm[NUM_SENSORS];
+ bool max_alarm[NUM_SENSORS];
+ struct delayed_work work;
+ bool work_active;
+ struct mutex lock;
+ int monitored_sensors;
+ void *plat_data;
+};
+
+int abx500_hwmon_init(struct abx500_temp *data);
+
+#endif /* _ABX500_H */
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index a57584d28a40..f4f9b219bf16 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -116,7 +116,7 @@ static int ad7314_probe(struct spi_device *spi_dev)
if (chip == NULL)
return -ENOMEM;
- dev_set_drvdata(&spi_dev->dev, chip);
+ spi_set_drvdata(spi_dev, chip);
ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
if (ret < 0)
@@ -137,7 +137,7 @@ error_remove_group:
static int ad7314_remove(struct spi_device *spi_dev)
{
- struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev);
+ struct ad7314_data *chip = spi_get_drvdata(spi_dev);
hwmon_device_unregister(chip->hwmon_dev);
sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
@@ -166,6 +166,5 @@ static struct spi_driver ad7314_driver = {
module_spi_driver(ad7314_driver);
MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
- " temperature sensor driver");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index 71bcba8abfc0..7e76922a4ba9 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -312,8 +312,7 @@ static int adm1021_detect(struct i2c_client *client,
int conv_rate, status, config, man_id, dev_id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_debug("adm1021: detect failed, "
- "smbus byte data not supported!\n");
+ pr_debug("detect failed, smbus byte data not supported!\n");
return -ENODEV;
}
@@ -324,7 +323,7 @@ static int adm1021_detect(struct i2c_client *client,
/* Check unused bits */
if ((status & 0x03) || (config & 0x3F) || (conv_rate & 0xF8)) {
- pr_debug("adm1021: detect failed, chip not detected!\n");
+ pr_debug("detect failed, chip not detected!\n");
return -ENODEV;
}
@@ -353,7 +352,7 @@ static int adm1021_detect(struct i2c_client *client,
else
type_name = "max1617";
- pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
+ pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
type_name, i2c_adapter_id(adapter), client->addr);
strlcpy(info->type, type_name, I2C_NAME_SIZE);
@@ -368,10 +367,8 @@ static int adm1021_probe(struct i2c_client *client,
data = devm_kzalloc(&client->dev, sizeof(struct adm1021_data),
GFP_KERNEL);
- if (!data) {
- pr_debug("adm1021: detect failed, devm_kzalloc failed!\n");
+ if (!data)
return -ENOMEM;
- }
i2c_set_clientdata(client, data);
data->type = id->driver_data;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index ea09046e651d..3a6d9ef1c16c 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -49,14 +49,14 @@ static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };
module_param_array(gpio_input, int, NULL, 0);
MODULE_PARM_DESC(gpio_input, "List of GPIO pins (0-16) to program as inputs");
module_param_array(gpio_output, int, NULL, 0);
-MODULE_PARM_DESC(gpio_output, "List of GPIO pins (0-16) to program as "
- "outputs");
+MODULE_PARM_DESC(gpio_output,
+ "List of GPIO pins (0-16) to program as outputs");
module_param_array(gpio_inverted, int, NULL, 0);
-MODULE_PARM_DESC(gpio_inverted, "List of GPIO pins (0-16) to program as "
- "inverted");
+MODULE_PARM_DESC(gpio_inverted,
+ "List of GPIO pins (0-16) to program as inverted");
module_param_array(gpio_normal, int, NULL, 0);
-MODULE_PARM_DESC(gpio_normal, "List of GPIO pins (0-16) to program as "
- "normal/non-inverted");
+MODULE_PARM_DESC(gpio_normal,
+ "List of GPIO pins (0-16) to program as normal/non-inverted");
module_param_array(gpio_fan, int, NULL, 0);
MODULE_PARM_DESC(gpio_fan, "List of GPIO pins (0-7) to program as fan tachs");
@@ -372,31 +372,31 @@ static void adm1026_init_client(struct i2c_client *client)
dev_dbg(&client->dev, "ADM1026_REG_CONFIG1 is: 0x%02x\n",
data->config1);
if ((data->config1 & CFG1_MONITOR) == 0) {
- dev_dbg(&client->dev, "Monitoring not currently "
- "enabled.\n");
+ dev_dbg(&client->dev,
+ "Monitoring not currently enabled.\n");
}
if (data->config1 & CFG1_INT_ENABLE) {
- dev_dbg(&client->dev, "SMBALERT interrupts are "
- "enabled.\n");
+ dev_dbg(&client->dev,
+ "SMBALERT interrupts are enabled.\n");
}
if (data->config1 & CFG1_AIN8_9) {
- dev_dbg(&client->dev, "in8 and in9 enabled. "
- "temp3 disabled.\n");
+ dev_dbg(&client->dev,
+ "in8 and in9 enabled. temp3 disabled.\n");
} else {
- dev_dbg(&client->dev, "temp3 enabled. in8 and "
- "in9 disabled.\n");
+ dev_dbg(&client->dev,
+ "temp3 enabled. in8 and in9 disabled.\n");
}
if (data->config1 & CFG1_THERM_HOT) {
- dev_dbg(&client->dev, "Automatic THERM, PWM, "
- "and temp limits enabled.\n");
+ dev_dbg(&client->dev,
+ "Automatic THERM, PWM, and temp limits enabled.\n");
}
if (data->config3 & CFG3_GPIO16_ENABLE) {
- dev_dbg(&client->dev, "GPIO16 enabled. THERM "
- "pin disabled.\n");
+ dev_dbg(&client->dev,
+ "GPIO16 enabled. THERM pin disabled.\n");
} else {
- dev_dbg(&client->dev, "THERM pin enabled. "
- "GPIO16 disabled.\n");
+ dev_dbg(&client->dev,
+ "THERM pin enabled. GPIO16 disabled.\n");
}
if (data->config3 & CFG3_VREF_250)
dev_dbg(&client->dev, "Vref is 2.50 Volts.\n");
@@ -1798,8 +1798,8 @@ static int adm1026_detect(struct i2c_client *client,
company = adm1026_read_value(client, ADM1026_REG_COMPANY);
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
- dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
- " COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+ dev_dbg(&adapter->dev,
+ "Detecting device at %d,0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
i2c_adapter_id(client->adapter), client->addr,
company, verstep);
@@ -1811,11 +1811,12 @@ static int adm1026_detect(struct i2c_client *client,
/* Analog Devices ADM1026 */
} else if (company == ADM1026_COMPANY_ANALOG_DEV
&& (verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
- dev_err(&adapter->dev, "Unrecognized stepping "
- "0x%02x. Defaulting to ADM1026.\n", verstep);
+ dev_err(&adapter->dev,
+ "Unrecognized stepping 0x%02x. Defaulting to ADM1026.\n",
+ verstep);
} else if ((verstep & 0xf0) == ADM1026_VERSTEP_GENERIC) {
- dev_err(&adapter->dev, "Found version/stepping "
- "0x%02x. Assuming generic ADM1026.\n",
+ dev_err(&adapter->dev,
+ "Found version/stepping 0x%02x. Assuming generic ADM1026.\n",
verstep);
} else {
dev_dbg(&adapter->dev, "Autodetection failed\n");
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 97f4718382f6..9ee5e066423b 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -224,8 +224,9 @@ static ssize_t set_fan_div(struct device *dev,
break;
default:
mutex_unlock(&data->update_lock);
- dev_err(&client->dev, "fan_div value %ld not "
- "supported. Choose one of 1, 2 or 4!\n", val);
+ dev_err(&client->dev,
+ "fan_div value %ld not supported. Choose one of 1, 2 or 4!\n",
+ val);
return -EINVAL;
}
/* Update the value */
@@ -326,8 +327,8 @@ static int adm1029_detect(struct i2c_client *client,
* There are no "official" CHIP ID, so actually
* we use Major/Minor revision for that
*/
- pr_info("adm1029: Unknown major revision %x, "
- "please let us know\n", chip_id);
+ pr_info("Unknown major revision %x, please let us know\n",
+ chip_id);
return -ENODEV;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 2416628e0ab1..086d02a9ecdc 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -351,8 +351,9 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr,
reg &= ~(3 << shift);
reg |= (fan_div << shift);
i2c_smbus_write_byte_data(client, ADM9240_REG_VID_FAN_DIV, reg);
- dev_dbg(&client->dev, "fan%d clock divider changed from %u "
- "to %u\n", nr + 1, 1 << old, 1 << fan_div);
+ dev_dbg(&client->dev,
+ "fan%d clock divider changed from %u to %u\n",
+ nr + 1, 1 << old, 1 << fan_div);
}
/*
@@ -699,8 +700,8 @@ static void adm9240_init_client(struct i2c_client *client)
/* start measurement cycle */
i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
- dev_info(&client->dev, "cold start: config was 0x%02x "
- "mode %u\n", conf, mode);
+ dev_info(&client->dev,
+ "cold start: config was 0x%02x mode %u\n", conf, mode);
}
}
diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c
index a79875986f91..3eff73b6220d 100644
--- a/drivers/hwmon/ads7871.c
+++ b/drivers/hwmon/ads7871.c
@@ -40,25 +40,25 @@
* the instruction byte
*/
/*Instruction Bit masks*/
-#define INST_MODE_bm (1<<7)
-#define INST_READ_bm (1<<6)
-#define INST_16BIT_bm (1<<5)
+#define INST_MODE_BM (1 << 7)
+#define INST_READ_BM (1 << 6)
+#define INST_16BIT_BM (1 << 5)
/*From figure 18 in the datasheet*/
/*bit masks for Rev/Oscillator Control Register*/
-#define MUX_CNV_bv 7
-#define MUX_CNV_bm (1<<MUX_CNV_bv)
-#define MUX_M3_bm (1<<3) /*M3 selects single ended*/
-#define MUX_G_bv 4 /*allows for reg = (gain << MUX_G_bv) | ...*/
+#define MUX_CNV_BV 7
+#define MUX_CNV_BM (1 << MUX_CNV_BV)
+#define MUX_M3_BM (1 << 3) /*M3 selects single ended*/
+#define MUX_G_BV 4 /*allows for reg = (gain << MUX_G_BV) | ...*/
/*From figure 18 in the datasheet*/
/*bit masks for Rev/Oscillator Control Register*/
-#define OSC_OSCR_bm (1<<5)
-#define OSC_OSCE_bm (1<<4)
-#define OSC_REFE_bm (1<<3)
-#define OSC_BUFE_bm (1<<2)
-#define OSC_R2V_bm (1<<1)
-#define OSC_RBG_bm (1<<0)
+#define OSC_OSCR_BM (1 << 5)
+#define OSC_OSCE_BM (1 << 4)
+#define OSC_REFE_BM (1 << 3)
+#define OSC_BUFE_BM (1 << 2)
+#define OSC_R2V_BM (1 << 1)
+#define OSC_RBG_BM (1 << 0)
#include <linux/module.h>
#include <linux/init.h>
@@ -79,7 +79,7 @@ struct ads7871_data {
static int ads7871_read_reg8(struct spi_device *spi, int reg)
{
int ret;
- reg = reg | INST_READ_bm;
+ reg = reg | INST_READ_BM;
ret = spi_w8r8(spi, reg);
return ret;
}
@@ -87,7 +87,7 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
static int ads7871_read_reg16(struct spi_device *spi, int reg)
{
int ret;
- reg = reg | INST_READ_bm | INST_16BIT_bm;
+ reg = reg | INST_READ_BM | INST_16BIT_BM;
ret = spi_w8r16(spi, reg);
return ret;
}
@@ -111,13 +111,13 @@ static ssize_t show_voltage(struct device *dev,
* TODO: add support for conversions
* other than single ended with a gain of 1
*/
- /*MUX_M3_bm forces single ended*/
+ /*MUX_M3_BM forces single ended*/
/*This is also where the gain of the PGA would be set*/
ads7871_write_reg8(spi, REG_GAIN_MUX,
- (MUX_CNV_bm | MUX_M3_bm | channel));
+ (MUX_CNV_BM | MUX_M3_BM | channel));
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
- mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+ mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
/*
* on 400MHz arm9 platform the conversion
* is already done when we do this test
@@ -125,14 +125,14 @@ static ssize_t show_voltage(struct device *dev,
while ((i < 2) && mux_cnv) {
i++;
ret = ads7871_read_reg8(spi, REG_GAIN_MUX);
- mux_cnv = ((ret & MUX_CNV_bm)>>MUX_CNV_bv);
+ mux_cnv = ((ret & MUX_CNV_BM) >> MUX_CNV_BV);
msleep_interruptible(1);
}
if (mux_cnv == 0) {
val = ads7871_read_reg16(spi, REG_LS_BYTE);
/*result in volts*10000 = (val/8192)*2.5*10000*/
- val = ((val>>2) * 25000) / 8192;
+ val = ((val >> 2) * 25000) / 8192;
return sprintf(buf, "%d\n", val);
} else {
return -1;
@@ -189,7 +189,7 @@ static int ads7871_probe(struct spi_device *spi)
ads7871_write_reg8(spi, REG_SER_CONTROL, 0);
ads7871_write_reg8(spi, REG_AD_CONTROL, 0);
- val = (OSC_OSCR_bm | OSC_OSCE_bm | OSC_REFE_bm | OSC_BUFE_bm);
+ val = (OSC_OSCR_BM | OSC_OSCE_BM | OSC_REFE_BM | OSC_BUFE_BM);
ads7871_write_reg8(spi, REG_OSC_CONTROL, val);
ret = ads7871_read_reg8(spi, REG_OSC_CONTROL);
diff --git a/drivers/hwmon/adt7310.c b/drivers/hwmon/adt7310.c
new file mode 100644
index 000000000000..da5f0789fb97
--- /dev/null
+++ b/drivers/hwmon/adt7310.c
@@ -0,0 +1,123 @@
+/*
+ * ADT7310/ADT7310 digital temperature sensor driver
+ *
+ * Copyright 2012-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <asm/unaligned.h>
+
+#include "adt7x10.h"
+
+#define ADT7310_STATUS 0
+#define ADT7310_CONFIG 1
+#define ADT7310_TEMPERATURE 2
+#define ADT7310_ID 3
+#define ADT7310_T_CRIT 4
+#define ADT7310_T_HYST 5
+#define ADT7310_T_ALARM_HIGH 6
+#define ADT7310_T_ALARM_LOW 7
+
+static const u8 adt7310_reg_table[] = {
+ [ADT7X10_TEMPERATURE] = ADT7310_TEMPERATURE,
+ [ADT7X10_STATUS] = ADT7310_STATUS,
+ [ADT7X10_CONFIG] = ADT7310_CONFIG,
+ [ADT7X10_T_ALARM_HIGH] = ADT7310_T_ALARM_HIGH,
+ [ADT7X10_T_ALARM_LOW] = ADT7310_T_ALARM_LOW,
+ [ADT7X10_T_CRIT] = ADT7310_T_CRIT,
+ [ADT7X10_T_HYST] = ADT7310_T_HYST,
+ [ADT7X10_ID] = ADT7310_ID,
+};
+
+#define ADT7310_CMD_REG_OFFSET 3
+#define ADT7310_CMD_READ 0x40
+
+#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
+
+static int adt7310_spi_read_word(struct device *dev, u8 reg)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int ret;
+
+ ret = spi_w8r16(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+ if (ret < 0)
+ return ret;
+
+ return be16_to_cpu((__force __be16)ret);
+}
+
+static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u8 buf[3];
+
+ buf[0] = AD7310_COMMAND(reg);
+ put_unaligned_be16(data, &buf[1]);
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adt7310_spi_read_byte(struct device *dev, u8 reg)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
+}
+
+static int adt7310_spi_write_byte(struct device *dev, u8 reg,
+ u8 data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u8 buf[2];
+
+ buf[0] = AD7310_COMMAND(reg);
+ buf[1] = data;
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+static const struct adt7x10_ops adt7310_spi_ops = {
+ .read_word = adt7310_spi_read_word,
+ .write_word = adt7310_spi_write_word,
+ .read_byte = adt7310_spi_read_byte,
+ .write_byte = adt7310_spi_write_byte,
+};
+
+static int adt7310_spi_probe(struct spi_device *spi)
+{
+ return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
+ &adt7310_spi_ops);
+}
+
+static int adt7310_spi_remove(struct spi_device *spi)
+{
+ return adt7x10_remove(&spi->dev, spi->irq);
+}
+
+static const struct spi_device_id adt7310_id[] = {
+ { "adt7310", 0 },
+ { "adt7320", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+ .driver = {
+ .name = "adt7310",
+ .owner = THIS_MODULE,
+ .pm = ADT7X10_DEV_PM_OPS,
+ },
+ .probe = adt7310_spi_probe,
+ .remove = adt7310_spi_remove,
+ .id_table = adt7310_id,
+};
+module_spi_driver(adt7310_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
index 99a7290da0a3..0dc066a939b4 100644
--- a/drivers/hwmon/adt7410.c
+++ b/drivers/hwmon/adt7410.c
@@ -1,460 +1,80 @@
/*
- * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
- * monitoring
- * This driver handles the ADT7410 and compatible digital temperature sensors.
- * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
- * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
- * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ * ADT7410/ADT7420 digital temperature sensor driver
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * Copyright 2012-2013 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-
-/*
- * ADT7410 registers definition
- */
-
-#define ADT7410_TEMPERATURE 0
-#define ADT7410_STATUS 2
-#define ADT7410_CONFIG 3
-#define ADT7410_T_ALARM_HIGH 4
-#define ADT7410_T_ALARM_LOW 6
-#define ADT7410_T_CRIT 8
-#define ADT7410_T_HYST 0xA
-
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW (1 << 4)
-#define ADT7410_STAT_T_HIGH (1 << 5)
-#define ADT7410_STAT_T_CRIT (1 << 6)
-#define ADT7410_STAT_NOT_RDY (1 << 7)
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
-#define ADT7410_CT_POLARITY (1 << 2)
-#define ADT7410_INT_POLARITY (1 << 3)
-#define ADT7410_EVENT_MODE (1 << 4)
-#define ADT7410_MODE_MASK (1 << 5 | 1 << 6)
-#define ADT7410_FULL (0 << 5 | 0 << 6)
-#define ADT7410_PD (1 << 5 | 1 << 6)
-#define ADT7410_RESOLUTION (1 << 7)
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T13_VALUE_MASK 0xFFF8
-#define ADT7410_T_HYST_MASK 0xF
-
-/* straight from the datasheet */
-#define ADT7410_TEMP_MIN (-55000)
-#define ADT7410_TEMP_MAX 150000
-
-enum adt7410_type { /* keep sorted in alphabetical order */
- adt7410,
-};
-
-static const u8 ADT7410_REG_TEMP[4] = {
- ADT7410_TEMPERATURE, /* input */
- ADT7410_T_ALARM_HIGH, /* high */
- ADT7410_T_ALARM_LOW, /* low */
- ADT7410_T_CRIT, /* critical */
-};
-
-/* Each client has this additional data */
-struct adt7410_data {
- struct device *hwmon_dev;
- struct mutex update_lock;
- u8 config;
- u8 oldconfig;
- bool valid; /* true if registers valid */
- unsigned long last_updated; /* In jiffies */
- s16 temp[4]; /* Register values,
- 0 = input
- 1 = high
- 2 = low
- 3 = critical */
- u8 hyst; /* hysteresis offset */
-};
-
-/*
- * adt7410 register access by I2C
- */
-static int adt7410_temp_ready(struct i2c_client *client)
-{
- int i, status;
-
- for (i = 0; i < 6; i++) {
- status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
- if (status < 0)
- return status;
- if (!(status & ADT7410_STAT_NOT_RDY))
- return 0;
- msleep(60);
- }
- return -ETIMEDOUT;
-}
-
-static struct adt7410_data *adt7410_update_device(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7410_data *data = i2c_get_clientdata(client);
- struct adt7410_data *ret = data;
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
- int i, status;
- dev_dbg(&client->dev, "Starting update\n");
+#include "adt7x10.h"
- status = adt7410_temp_ready(client); /* check for new value */
- if (unlikely(status)) {
- ret = ERR_PTR(status);
- goto abort;
- }
- for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
- status = i2c_smbus_read_word_swapped(client,
- ADT7410_REG_TEMP[i]);
- if (unlikely(status < 0)) {
- dev_dbg(dev,
- "Failed to read value: reg %d, error %d\n",
- ADT7410_REG_TEMP[i], status);
- ret = ERR_PTR(status);
- goto abort;
- }
- data->temp[i] = status;
- }
- status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
- if (unlikely(status < 0)) {
- dev_dbg(dev,
- "Failed to read value: reg %d, error %d\n",
- ADT7410_T_HYST, status);
- ret = ERR_PTR(status);
- goto abort;
- }
- data->hyst = status;
- data->last_updated = jiffies;
- data->valid = true;
- }
-
-abort:
- mutex_unlock(&data->update_lock);
- return ret;
-}
-
-static s16 ADT7410_TEMP_TO_REG(long temp)
+static int adt7410_i2c_read_word(struct device *dev, u8 reg)
{
- return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7410_TEMP_MIN,
- ADT7410_TEMP_MAX) * 128, 1000);
+ return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
}
-static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
{
- /* in 13 bit mode, bits 0-2 are status flags - mask them out */
- if (!(data->config & ADT7410_RESOLUTION))
- reg &= ADT7410_T13_VALUE_MASK;
- /*
- * temperature is stored in twos complement format, in steps of
- * 1/128°C
- */
- return DIV_ROUND_CLOSEST(reg * 1000, 128);
+ return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
}
-/*-----------------------------------------------------------------------*/
-
-/* sysfs attributes for hwmon */
-
-static ssize_t adt7410_show_temp(struct device *dev,
- struct device_attribute *da, char *buf)
+static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct adt7410_data *data = adt7410_update_device(dev);
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
- data->temp[attr->index]));
+ return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
}
-static ssize_t adt7410_set_temp(struct device *dev,
- struct device_attribute *da,
- const char *buf, size_t count)
+static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7410_data *data = i2c_get_clientdata(client);
- int nr = attr->index;
- long temp;
- int ret;
-
- ret = kstrtol(buf, 10, &temp);
- if (ret)
- return ret;
-
- mutex_lock(&data->update_lock);
- data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
- ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
- data->temp[nr]);
- if (ret)
- count = ret;
- mutex_unlock(&data->update_lock);
- return count;
+ return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
}
-static ssize_t adt7410_show_t_hyst(struct device *dev,
- struct device_attribute *da,
- char *buf)
-{
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct adt7410_data *data;
- int nr = attr->index;
- int hyst;
-
- data = adt7410_update_device(dev);
- if (IS_ERR(data))
- return PTR_ERR(data);
- hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
-
- /*
- * hysteresis is stored as a 4 bit offset in the device, convert it
- * to an absolute value
- */
- if (nr == 2) /* min has positive offset, others have negative */
- hyst = -hyst;
- return sprintf(buf, "%d\n",
- ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
-}
-
-static ssize_t adt7410_set_t_hyst(struct device *dev,
- struct device_attribute *da,
- const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7410_data *data = i2c_get_clientdata(client);
- int limit, ret;
- long hyst;
-
- ret = kstrtol(buf, 10, &hyst);
- if (ret)
- return ret;
- /* convert absolute hysteresis value to a 4 bit delta value */
- limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
- hyst = clamp_val(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
- data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
- ADT7410_T_HYST_MASK);
- ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
- if (ret)
- return ret;
-
- return count;
-}
-
-static ssize_t adt7410_show_alarm(struct device *dev,
- struct device_attribute *da,
- char *buf)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- int ret;
-
- ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
- if (ret < 0)
- return ret;
-
- return sprintf(buf, "%d\n", !!(ret & attr->index));
-}
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
- adt7410_show_temp, adt7410_set_temp, 1);
-static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
- adt7410_show_temp, adt7410_set_temp, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
- adt7410_show_temp, adt7410_set_temp, 3);
-static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
- adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
-static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
- adt7410_show_t_hyst, NULL, 2);
-static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
- adt7410_show_t_hyst, NULL, 3);
-static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
- NULL, ADT7410_STAT_T_LOW);
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
- NULL, ADT7410_STAT_T_HIGH);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
- NULL, ADT7410_STAT_T_CRIT);
-
-static struct attribute *adt7410_attributes[] = {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
- &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- NULL
+static const struct adt7x10_ops adt7410_i2c_ops = {
+ .read_word = adt7410_i2c_read_word,
+ .write_word = adt7410_i2c_write_word,
+ .read_byte = adt7410_i2c_read_byte,
+ .write_byte = adt7410_i2c_write_byte,
};
-static const struct attribute_group adt7410_group = {
- .attrs = adt7410_attributes,
-};
-
-/*-----------------------------------------------------------------------*/
-
-/* device probe and removal */
-
-static int adt7410_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adt7410_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct adt7410_data *data;
- int ret;
-
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- i2c_set_clientdata(client, data);
- mutex_init(&data->update_lock);
-
- /* configure as specified */
- ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
- if (ret < 0) {
- dev_dbg(&client->dev, "Can't read config? %d\n", ret);
- return ret;
- }
- data->oldconfig = ret;
- /*
- * Set to 16 bit resolution, continous conversion and comparator mode.
- */
- ret &= ~ADT7410_MODE_MASK;
- data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
- ADT7410_EVENT_MODE;
- if (data->config != data->oldconfig) {
- ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
- data->config);
- if (ret)
- return ret;
- }
- dev_dbg(&client->dev, "Config %02x\n", data->config);
-
- /* Register sysfs hooks */
- ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
- if (ret)
- goto exit_restore;
-
- data->hwmon_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->hwmon_dev)) {
- ret = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
- }
-
- dev_info(&client->dev, "sensor '%s'\n", client->name);
-
- return 0;
-
-exit_remove:
- sysfs_remove_group(&client->dev.kobj, &adt7410_group);
-exit_restore:
- i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
- return ret;
+ return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
}
-static int adt7410_remove(struct i2c_client *client)
+static int adt7410_i2c_remove(struct i2c_client *client)
{
- struct adt7410_data *data = i2c_get_clientdata(client);
-
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &adt7410_group);
- if (data->oldconfig != data->config)
- i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
- data->oldconfig);
- return 0;
+ return adt7x10_remove(&client->dev, client->irq);
}
static const struct i2c_device_id adt7410_ids[] = {
- { "adt7410", adt7410, },
- { "adt7420", adt7410, },
- { /* LIST END */ }
+ { "adt7410", 0 },
+ { "adt7420", 0 },
+ {}
};
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
-#ifdef CONFIG_PM_SLEEP
-static int adt7410_suspend(struct device *dev)
-{
- int ret;
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7410_data *data = i2c_get_clientdata(client);
-
- ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
- data->config | ADT7410_PD);
- return ret;
-}
-
-static int adt7410_resume(struct device *dev)
-{
- int ret;
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7410_data *data = i2c_get_clientdata(client);
-
- ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
- return ret;
-}
-
-static SIMPLE_DEV_PM_OPS(adt7410_dev_pm_ops, adt7410_suspend, adt7410_resume);
-
-#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
-#else
-#define ADT7410_DEV_PM_OPS NULL
-#endif /* CONFIG_PM */
-
static struct i2c_driver adt7410_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adt7410",
- .pm = ADT7410_DEV_PM_OPS,
+ .pm = ADT7X10_DEV_PM_OPS,
},
- .probe = adt7410_probe,
- .remove = adt7410_remove,
+ .probe = adt7410_i2c_probe,
+ .remove = adt7410_i2c_remove,
.id_table = adt7410_ids,
.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
};
-
module_i2c_driver(adt7410_driver);
-MODULE_AUTHOR("Hartmut Knaack");
-MODULE_DESCRIPTION("ADT7410/ADT7420 driver");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("ADT7410/AD7420 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index 34ff03abb50b..d9299dee37d1 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -259,15 +259,17 @@ static int adt7411_detect(struct i2c_client *client,
val = i2c_smbus_read_byte_data(client, ADT7411_REG_MANUFACTURER_ID);
if (val < 0 || val != ADT7411_MANUFACTURER_ID) {
- dev_dbg(&client->dev, "Wrong manufacturer ID. Got %d, "
- "expected %d\n", val, ADT7411_MANUFACTURER_ID);
+ dev_dbg(&client->dev,
+ "Wrong manufacturer ID. Got %d, expected %d\n",
+ val, ADT7411_MANUFACTURER_ID);
return -ENODEV;
}
val = i2c_smbus_read_byte_data(client, ADT7411_REG_DEVICE_ID);
if (val < 0 || val != ADT7411_DEVICE_ID) {
- dev_dbg(&client->dev, "Wrong device ID. Got %d, "
- "expected %d\n", val, ADT7411_DEVICE_ID);
+ dev_dbg(&client->dev,
+ "Wrong device ID. Got %d, expected %d\n",
+ val, ADT7411_DEVICE_ID);
return -ENODEV;
}
diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c
new file mode 100644
index 000000000000..98141f483165
--- /dev/null
+++ b/drivers/hwmon/adt7x10.c
@@ -0,0 +1,511 @@
+/*
+ * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "adt7x10.h"
+
+/*
+ * ADT7X10 status
+ */
+#define ADT7X10_STAT_T_LOW (1 << 4)
+#define ADT7X10_STAT_T_HIGH (1 << 5)
+#define ADT7X10_STAT_T_CRIT (1 << 6)
+#define ADT7X10_STAT_NOT_RDY (1 << 7)
+
+/*
+ * ADT7X10 config
+ */
+#define ADT7X10_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
+#define ADT7X10_CT_POLARITY (1 << 2)
+#define ADT7X10_INT_POLARITY (1 << 3)
+#define ADT7X10_EVENT_MODE (1 << 4)
+#define ADT7X10_MODE_MASK (1 << 5 | 1 << 6)
+#define ADT7X10_FULL (0 << 5 | 0 << 6)
+#define ADT7X10_PD (1 << 5 | 1 << 6)
+#define ADT7X10_RESOLUTION (1 << 7)
+
+/*
+ * ADT7X10 masks
+ */
+#define ADT7X10_T13_VALUE_MASK 0xFFF8
+#define ADT7X10_T_HYST_MASK 0xF
+
+/* straight from the datasheet */
+#define ADT7X10_TEMP_MIN (-55000)
+#define ADT7X10_TEMP_MAX 150000
+
+/* Each client has this additional data */
+struct adt7x10_data {
+ const struct adt7x10_ops *ops;
+ const char *name;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ u8 config;
+ u8 oldconfig;
+ bool valid; /* true if registers valid */
+ unsigned long last_updated; /* In jiffies */
+ s16 temp[4]; /* Register values,
+ 0 = input
+ 1 = high
+ 2 = low
+ 3 = critical */
+ u8 hyst; /* hysteresis offset */
+};
+
+static int adt7x10_read_byte(struct device *dev, u8 reg)
+{
+ struct adt7x10_data *d = dev_get_drvdata(dev);
+ return d->ops->read_byte(dev, reg);
+}
+
+static int adt7x10_write_byte(struct device *dev, u8 reg, u8 data)
+{
+ struct adt7x10_data *d = dev_get_drvdata(dev);
+ return d->ops->write_byte(dev, reg, data);
+}
+
+static int adt7x10_read_word(struct device *dev, u8 reg)
+{
+ struct adt7x10_data *d = dev_get_drvdata(dev);
+ return d->ops->read_word(dev, reg);
+}
+
+static int adt7x10_write_word(struct device *dev, u8 reg, u16 data)
+{
+ struct adt7x10_data *d = dev_get_drvdata(dev);
+ return d->ops->write_word(dev, reg, data);
+}
+
+static const u8 ADT7X10_REG_TEMP[4] = {
+ ADT7X10_TEMPERATURE, /* input */
+ ADT7X10_T_ALARM_HIGH, /* high */
+ ADT7X10_T_ALARM_LOW, /* low */
+ ADT7X10_T_CRIT, /* critical */
+};
+
+static irqreturn_t adt7x10_irq_handler(int irq, void *private)
+{
+ struct device *dev = private;
+ int status;
+
+ status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+ if (status < 0)
+ return IRQ_HANDLED;
+
+ if (status & ADT7X10_STAT_T_HIGH)
+ sysfs_notify(&dev->kobj, NULL, "temp1_max_alarm");
+ if (status & ADT7X10_STAT_T_LOW)
+ sysfs_notify(&dev->kobj, NULL, "temp1_min_alarm");
+ if (status & ADT7X10_STAT_T_CRIT)
+ sysfs_notify(&dev->kobj, NULL, "temp1_crit_alarm");
+
+ return IRQ_HANDLED;
+}
+
+static int adt7x10_temp_ready(struct device *dev)
+{
+ int i, status;
+
+ for (i = 0; i < 6; i++) {
+ status = adt7x10_read_byte(dev, ADT7X10_STATUS);
+ if (status < 0)
+ return status;
+ if (!(status & ADT7X10_STAT_NOT_RDY))
+ return 0;
+ msleep(60);
+ }
+ return -ETIMEDOUT;
+}
+
+static int adt7x10_update_temp(struct device *dev)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ int temp;
+
+ dev_dbg(dev, "Starting update\n");
+
+ ret = adt7x10_temp_ready(dev); /* check for new value */
+ if (ret)
+ goto abort;
+
+ temp = adt7x10_read_word(dev, ADT7X10_REG_TEMP[0]);
+ if (temp < 0) {
+ ret = temp;
+ dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+ ADT7X10_REG_TEMP[0], ret);
+ goto abort;
+ }
+ data->temp[0] = temp;
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static int adt7x10_fill_cache(struct device *dev)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+ int ret;
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(data->temp); i++) {
+ ret = adt7x10_read_word(dev, ADT7X10_REG_TEMP[i]);
+ if (ret < 0) {
+ dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+ ADT7X10_REG_TEMP[i], ret);
+ return ret;
+ }
+ data->temp[i] = ret;
+ }
+
+ ret = adt7x10_read_byte(dev, ADT7X10_T_HYST);
+ if (ret < 0) {
+ dev_dbg(dev, "Failed to read value: reg %d, error %d\n",
+ ADT7X10_T_HYST, ret);
+ return ret;
+ }
+ data->hyst = ret;
+
+ return 0;
+}
+
+static s16 ADT7X10_TEMP_TO_REG(long temp)
+{
+ return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
+ ADT7X10_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
+{
+ /* in 13 bit mode, bits 0-2 are status flags - mask them out */
+ if (!(data->config & ADT7X10_RESOLUTION))
+ reg &= ADT7X10_T13_VALUE_MASK;
+ /*
+ * temperature is stored in twos complement format, in steps of
+ * 1/128°C
+ */
+ return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7x10_show_temp(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+
+
+ if (attr->index == 0) {
+ int ret;
+
+ ret = adt7x10_update_temp(dev);
+ if (ret)
+ return ret;
+ }
+
+ return sprintf(buf, "%d\n", ADT7X10_REG_TO_TEMP(data,
+ data->temp[attr->index]));
+}
+
+static ssize_t adt7x10_set_temp(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
+ long temp;
+ int ret;
+
+ ret = kstrtol(buf, 10, &temp);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = ADT7X10_TEMP_TO_REG(temp);
+ ret = adt7x10_write_word(dev, ADT7X10_REG_TEMP[nr], data->temp[nr]);
+ if (ret)
+ count = ret;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t adt7x10_show_t_hyst(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
+ int hyst;
+
+ hyst = (data->hyst & ADT7X10_T_HYST_MASK) * 1000;
+
+ /*
+ * hysteresis is stored as a 4 bit offset in the device, convert it
+ * to an absolute value
+ */
+ if (nr == 2) /* min has positive offset, others have negative */
+ hyst = -hyst;
+ return sprintf(buf, "%d\n",
+ ADT7X10_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7x10_set_t_hyst(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+ int limit, ret;
+ long hyst;
+
+ ret = kstrtol(buf, 10, &hyst);
+ if (ret)
+ return ret;
+ /* convert absolute hysteresis value to a 4 bit delta value */
+ limit = ADT7X10_REG_TO_TEMP(data, data->temp[1]);
+ hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
+ data->hyst = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+ 0, ADT7X10_T_HYST_MASK);
+ ret = adt7x10_write_byte(dev, ADT7X10_T_HYST, data->hyst);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t adt7x10_show_alarm(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int ret;
+
+ ret = adt7x10_read_byte(dev, ADT7X10_STATUS);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static ssize_t adt7x10_show_name(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7x10_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ adt7x10_show_temp, adt7x10_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+ adt7x10_show_temp, adt7x10_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+ adt7x10_show_temp, adt7x10_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ adt7x10_show_t_hyst, adt7x10_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+ adt7x10_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+ adt7x10_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7x10_show_alarm,
+ NULL, ADT7X10_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm,
+ NULL, ADT7X10_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm,
+ NULL, ADT7X10_STAT_T_CRIT);
+static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL);
+
+static struct attribute *adt7x10_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adt7x10_group = {
+ .attrs = adt7x10_attributes,
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+ const struct adt7x10_ops *ops)
+{
+ struct adt7x10_data *data;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->ops = ops;
+ data->name = name;
+
+ dev_set_drvdata(dev, data);
+ mutex_init(&data->update_lock);
+
+ /* configure as specified */
+ ret = adt7x10_read_byte(dev, ADT7X10_CONFIG);
+ if (ret < 0) {
+ dev_dbg(dev, "Can't read config? %d\n", ret);
+ return ret;
+ }
+ data->oldconfig = ret;
+
+ /*
+ * Set to 16 bit resolution, continous conversion and comparator mode.
+ */
+ data->config = data->oldconfig;
+ data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
+ ADT7X10_INT_POLARITY);
+ data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
+
+ if (data->config != data->oldconfig) {
+ ret = adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+ if (ret)
+ return ret;
+ }
+ dev_dbg(dev, "Config %02x\n", data->config);
+
+ ret = adt7x10_fill_cache(dev);
+ if (ret)
+ goto exit_restore;
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&dev->kobj, &adt7x10_group);
+ if (ret)
+ goto exit_restore;
+
+ /*
+ * The I2C device will already have it's own 'name' attribute, but for
+ * the SPI device we need to register it. name will only be non NULL if
+ * the device doesn't register the 'name' attribute on its own.
+ */
+ if (name) {
+ ret = device_create_file(dev, &dev_attr_name);
+ if (ret)
+ goto exit_remove;
+ }
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_name;
+ }
+
+ if (irq > 0) {
+ ret = request_threaded_irq(irq, NULL, adt7x10_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), dev);
+ if (ret)
+ goto exit_hwmon_device_unregister;
+ }
+
+ return 0;
+
+exit_hwmon_device_unregister:
+ hwmon_device_unregister(data->hwmon_dev);
+exit_remove_name:
+ if (name)
+ device_remove_file(dev, &dev_attr_name);
+exit_remove:
+ sysfs_remove_group(&dev->kobj, &adt7x10_group);
+exit_restore:
+ adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(adt7x10_probe);
+
+int adt7x10_remove(struct device *dev, int irq)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+
+ if (irq > 0)
+ free_irq(irq, dev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ if (data->name)
+ device_remove_file(dev, &dev_attr_name);
+ sysfs_remove_group(&dev->kobj, &adt7x10_group);
+ if (data->oldconfig != data->config)
+ adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adt7x10_remove);
+
+#ifdef CONFIG_PM_SLEEP
+
+static int adt7x10_suspend(struct device *dev)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+
+ return adt7x10_write_byte(dev, ADT7X10_CONFIG,
+ data->config | ADT7X10_PD);
+}
+
+static int adt7x10_resume(struct device *dev)
+{
+ struct adt7x10_data *data = dev_get_drvdata(dev);
+
+ return adt7x10_write_byte(dev, ADT7X10_CONFIG, data->config);
+}
+
+SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
+EXPORT_SYMBOL_GPL(adt7x10_dev_pm_ops);
+
+#endif /* CONFIG_PM_SLEEP */
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/adt7x10.h b/drivers/hwmon/adt7x10.h
new file mode 100644
index 000000000000..d491c698529e
--- /dev/null
+++ b/drivers/hwmon/adt7x10.h
@@ -0,0 +1,37 @@
+#ifndef __HWMON_ADT7X10_H__
+#define __HWMON_ADT7X10_H__
+
+#include <linux/types.h>
+#include <linux/pm.h>
+
+/* ADT7410 registers definition */
+#define ADT7X10_TEMPERATURE 0
+#define ADT7X10_STATUS 2
+#define ADT7X10_CONFIG 3
+#define ADT7X10_T_ALARM_HIGH 4
+#define ADT7X10_T_ALARM_LOW 6
+#define ADT7X10_T_CRIT 8
+#define ADT7X10_T_HYST 0xA
+#define ADT7X10_ID 0xB
+
+struct device;
+
+struct adt7x10_ops {
+ int (*read_byte)(struct device *, u8 reg);
+ int (*write_byte)(struct device *, u8 reg, u8 data);
+ int (*read_word)(struct device *, u8 reg);
+ int (*write_word)(struct device *, u8 reg, u16 data);
+};
+
+int adt7x10_probe(struct device *dev, const char *name, int irq,
+ const struct adt7x10_ops *ops);
+int adt7x10_remove(struct device *dev, int irq);
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops adt7x10_dev_pm_ops;
+#define ADT7X10_DEV_PM_OPS (&adt7x10_dev_pm_ops)
+#else
+#define ADT7X10_DEV_PM_OPS NULL
+#endif
+
+#endif
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index b41baffa20f0..62c2e32e25ef 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -922,7 +922,7 @@ static void applesmc_brightness_set(struct led_classdev *led_cdev,
ret = queue_work(applesmc_led_wq, &backlight_work);
if (debug && (!ret))
- printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
+ dev_dbg(led_cdev->dev, "work was already on the queue.\n");
}
static ssize_t applesmc_key_count_show(struct device *dev,
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 6ac612cabda1..f96063680e58 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -55,8 +55,8 @@ static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
static unsigned short force_subclients[4];
module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
- "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+ "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
/* Voltage IN registers 0-6 */
#define ASB100_REG_IN(nr) (0x20 + (nr))
@@ -689,8 +689,8 @@ static int asb100_detect_subclients(struct i2c_client *client)
for (i = 2; i <= 3; i++) {
if (force_subclients[i] < 0x48 ||
force_subclients[i] > 0x4f) {
- dev_err(&client->dev, "invalid subclient "
- "address %d; must be 0x48-0x4f\n",
+ dev_err(&client->dev,
+ "invalid subclient address %d; must be 0x48-0x4f\n",
force_subclients[i]);
err = -ENODEV;
goto ERROR_SC_2;
@@ -708,24 +708,27 @@ static int asb100_detect_subclients(struct i2c_client *client)
}
if (sc_addr[0] == sc_addr[1]) {
- dev_err(&client->dev, "duplicate addresses 0x%x "
- "for subclients\n", sc_addr[0]);
+ dev_err(&client->dev,
+ "duplicate addresses 0x%x for subclients\n",
+ sc_addr[0]);
err = -ENODEV;
goto ERROR_SC_2;
}
data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
if (!data->lm75[0]) {
- dev_err(&client->dev, "subclient %d registration "
- "at address 0x%x failed.\n", 1, sc_addr[0]);
+ dev_err(&client->dev,
+ "subclient %d registration at address 0x%x failed.\n",
+ 1, sc_addr[0]);
err = -ENOMEM;
goto ERROR_SC_2;
}
data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
if (!data->lm75[1]) {
- dev_err(&client->dev, "subclient %d registration "
- "at address 0x%x failed.\n", 2, sc_addr[1]);
+ dev_err(&client->dev,
+ "subclient %d registration at address 0x%x failed.\n",
+ 2, sc_addr[1]);
err = -ENOMEM;
goto ERROR_SC_3;
}
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index da7f5b5d5db5..3ad9d849add2 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -159,12 +159,12 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
* and retrieval of like parameters.
*/
-#define SETUP_SHOW_data_param(d, a) \
+#define SETUP_SHOW_DATA_PARAM(d, a) \
struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
struct asc7621_data *data = asc7621_update_device(d); \
struct asc7621_param *param = to_asc7621_param(sda)
-#define SETUP_STORE_data_param(d, a) \
+#define SETUP_STORE_DATA_PARAM(d, a) \
struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \
struct i2c_client *client = to_i2c_client(d); \
struct asc7621_data *data = i2c_get_clientdata(client); \
@@ -177,7 +177,7 @@ static inline int write_byte(struct i2c_client *client, u8 reg, u8 data)
static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
return sprintf(buf, "%u\n", data->reg[param->msb[0]]);
}
@@ -185,7 +185,7 @@ static ssize_t show_u8(struct device *dev, struct device_attribute *attr,
static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
if (kstrtol(buf, 10, &reqval))
@@ -206,7 +206,7 @@ static ssize_t store_u8(struct device *dev, struct device_attribute *attr,
static ssize_t show_bitmask(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
return sprintf(buf, "%u\n",
(data->reg[param->msb[0]] >> param->
@@ -217,7 +217,7 @@ static ssize_t store_bitmask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
u8 currval;
@@ -246,7 +246,7 @@ static ssize_t store_bitmask(struct device *dev,
static ssize_t show_fan16(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u16 regval;
mutex_lock(&data->update_lock);
@@ -262,7 +262,7 @@ static ssize_t store_fan16(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
if (kstrtol(buf, 10, &reqval))
@@ -307,7 +307,7 @@ static int asc7621_in_scaling[] = {
static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u16 regval;
u8 nr = sda->index;
@@ -325,7 +325,7 @@ static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 nr = sda->index;
return sprintf(buf, "%u\n",
@@ -336,7 +336,7 @@ static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
u8 nr = sda->index;
@@ -360,7 +360,7 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
static ssize_t show_temp8(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000);
}
@@ -369,7 +369,7 @@ static ssize_t store_temp8(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
s8 temp;
@@ -397,7 +397,7 @@ static ssize_t store_temp8(struct device *dev,
static ssize_t show_temp10(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 msb, lsb;
int temp;
@@ -414,7 +414,7 @@ static ssize_t show_temp10(struct device *dev,
static ssize_t show_temp62(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 regval = data->reg[param->msb[0]];
int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250);
@@ -425,7 +425,7 @@ static ssize_t store_temp62(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval, i, f;
s8 temp;
@@ -459,7 +459,7 @@ static u32 asc7621_range_map[] = {
static ssize_t show_ap2_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
long auto_point1;
u8 regval;
int temp;
@@ -479,7 +479,7 @@ static ssize_t store_ap2_temp(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval, auto_point1;
int i;
u8 currval, newval = 0;
@@ -510,7 +510,7 @@ static ssize_t store_ap2_temp(struct device *dev,
static ssize_t show_pwm_ac(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 config, altbit, regval;
u8 map[] = {
0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10,
@@ -530,7 +530,7 @@ static ssize_t store_pwm_ac(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
unsigned long reqval;
u8 currval, config, altbit, newval;
u16 map[] = {
@@ -569,7 +569,7 @@ static ssize_t store_pwm_ac(struct device *dev,
static ssize_t show_pwm_enable(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 config, altbit, minoff, val, newval;
mutex_lock(&data->update_lock);
@@ -599,7 +599,7 @@ static ssize_t store_pwm_enable(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
u8 currval, config, altbit, newval, minoff = 255;
@@ -659,7 +659,7 @@ static u32 asc7621_pwm_freq_map[] = {
static ssize_t show_pwm_freq(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
@@ -672,7 +672,7 @@ static ssize_t store_pwm_freq(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
unsigned long reqval;
u8 currval, newval = 255;
int i;
@@ -707,7 +707,7 @@ static u32 asc7621_pwm_auto_spinup_map[] = {
static ssize_t show_pwm_ast(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
@@ -721,7 +721,7 @@ static ssize_t store_pwm_ast(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
u8 currval, newval = 255;
u32 i;
@@ -756,7 +756,7 @@ static u32 asc7621_temp_smoothing_time_map[] = {
static ssize_t show_temp_st(struct device *dev,
struct device_attribute *attr, char *buf)
{
- SETUP_SHOW_data_param(dev, attr);
+ SETUP_SHOW_DATA_PARAM(dev, attr);
u8 regval =
(data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0];
regval = clamp_val(regval, 0, 7);
@@ -768,7 +768,7 @@ static ssize_t store_temp_st(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- SETUP_STORE_data_param(dev, attr);
+ SETUP_STORE_DATA_PARAM(dev, attr);
long reqval;
u8 currval, newval = 255;
u32 i;
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 3f1e297663ad..658ce3a8717f 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -411,8 +411,7 @@ static int __cpuinit chk_ucode_version(unsigned int cpu)
* fixed for stepping D0 (6EC).
*/
if (c->x86_model == 0xe && c->x86_mask < 0xc && c->microcode < 0x39) {
- pr_err("Errata AE18 not fixed, update BIOS or "
- "microcode of the CPU!\n");
+ pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n");
return -ENODEV;
}
return 0;
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
index ab4452c5a98c..960fac3fb166 100644
--- a/drivers/hwmon/da9052-hwmon.c
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -43,19 +43,19 @@ static const char * const input_names[] = {
};
/* Conversion function for VDDOUT and VBAT */
-static inline int volt_reg_to_mV(int value)
+static inline int volt_reg_to_mv(int value)
{
return DIV_ROUND_CLOSEST(value * 1000, 512) + 2500;
}
/* Conversion function for ADC channels 4, 5 and 6 */
-static inline int input_reg_to_mV(int value)
+static inline int input_reg_to_mv(int value)
{
return DIV_ROUND_CLOSEST(value * 2500, 1023);
}
/* Conversion function for VBBAT */
-static inline int vbbat_reg_to_mV(int value)
+static inline int vbbat_reg_to_mv(int value)
{
return DIV_ROUND_CLOSEST(value * 2500, 512);
}
@@ -96,7 +96,7 @@ static ssize_t da9052_read_vddout(struct device *dev,
goto hwmon_err;
mutex_unlock(&hwmon->hwmon_lock);
- return sprintf(buf, "%d\n", volt_reg_to_mV(vdd));
+ return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
hwmon_err_release:
da9052_disable_vddout_channel(hwmon->da9052);
@@ -137,7 +137,7 @@ static ssize_t da9052_read_vbat(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", volt_reg_to_mV(ret));
+ return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
}
static ssize_t da9052_read_misc_channel(struct device *dev,
@@ -152,7 +152,7 @@ static ssize_t da9052_read_misc_channel(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", input_reg_to_mV(ret));
+ return sprintf(buf, "%d\n", input_reg_to_mv(ret));
}
static ssize_t da9052_read_tjunc(struct device *dev,
@@ -187,7 +187,7 @@ static ssize_t da9052_read_vbbat(struct device *dev,
if (ret < 0)
return ret;
- return sprintf(buf, "%d\n", vbbat_reg_to_mV(ret));
+ return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
}
static ssize_t da9052_hwmon_show_name(struct device *dev,
diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c
index 9465c050c326..029ecabc4380 100644
--- a/drivers/hwmon/da9055-hwmon.c
+++ b/drivers/hwmon/da9055-hwmon.c
@@ -119,7 +119,7 @@ static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
}
/* Conversion function for VSYS and ADCINx */
-static inline int volt_reg_to_mV(int value, int channel)
+static inline int volt_reg_to_mv(int value, int channel)
{
if (channel == DA9055_ADC_VSYS)
return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
@@ -168,7 +168,7 @@ static ssize_t da9055_read_auto_ch(struct device *dev,
mutex_unlock(&hwmon->hwmon_lock);
- return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
+ return sprintf(buf, "%d\n", volt_reg_to_mv(adc, channel));
hwmon_err_release:
da9055_disable_auto_mode(hwmon->da9055, channel);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index c347c94f2f73..4ae3fff13f44 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -55,14 +55,16 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
static bool probe_all_addr;
module_param(probe_all_addr, bool, 0);
-MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
- "addresses");
+MODULE_PARM_DESC(probe_all_addr,
+ "Include probing of non-standard LPC addresses");
/* Addresses to scan */
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
enum chips { dme1737, sch5027, sch311x, sch5127 };
+#define DO_REPORT "Please report to the driver maintainer."
+
/* ---------------------------------------------------------------------
* Registers
*
@@ -566,9 +568,9 @@ static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
val = i2c_smbus_read_byte_data(client, reg);
if (val < 0) {
- dev_warn(&client->dev, "Read from register "
- "0x%02x failed! Please report to the driver "
- "maintainer.\n", reg);
+ dev_warn(&client->dev,
+ "Read from register 0x%02x failed! %s\n",
+ reg, DO_REPORT);
}
} else { /* ISA device */
outb(reg, data->addr);
@@ -587,9 +589,9 @@ static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
res = i2c_smbus_write_byte_data(client, reg, val);
if (res < 0) {
- dev_warn(&client->dev, "Write to register "
- "0x%02x failed! Please report to the driver "
- "maintainer.\n", reg);
+ dev_warn(&client->dev,
+ "Write to register 0x%02x failed! %s\n",
+ reg, DO_REPORT);
}
} else { /* ISA device */
outb(reg, data->addr);
@@ -1167,8 +1169,8 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
/* Only valid for fan[1-4] */
if (!(val == 1 || val == 2 || val == 4)) {
count = -EINVAL;
- dev_warn(dev, "Fan type value %ld not "
- "supported. Choose one of 1, 2, or 4.\n",
+ dev_warn(dev,
+ "Fan type value %ld not supported. Choose one of 1, 2, or 4.\n",
val);
goto exit;
}
@@ -1294,8 +1296,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
/* Only valid for pwm[1-3] */
if (val < 0 || val > 2) {
count = -EINVAL;
- dev_warn(dev, "PWM enable %ld not "
- "supported. Choose one of 0, 1, or 2.\n",
+ dev_warn(dev,
+ "PWM enable %ld not supported. Choose one of 0, 1, or 2.\n",
val);
goto exit;
}
@@ -1399,8 +1401,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
if (!(val == 1 || val == 2 || val == 4 ||
val == 6 || val == 7)) {
count = -EINVAL;
- dev_warn(dev, "PWM auto channels zone %ld "
- "not supported. Choose one of 1, 2, 4, 6, "
+ dev_warn(dev,
+ "PWM auto channels zone %ld not supported. Choose one of 1, 2, 4, 6, "
"or 7.\n", val);
goto exit;
}
@@ -2178,8 +2180,8 @@ static int dme1737_create_files(struct device *dev)
* selected attributes from read-only to read-writeable.
*/
if (data->config & 0x02) {
- dev_info(dev, "Device is locked. Some attributes "
- "will be read-only.\n");
+ dev_info(dev,
+ "Device is locked. Some attributes will be read-only.\n");
} else {
/* Change permissions of zone sysfs attributes */
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
@@ -2247,9 +2249,8 @@ static int dme1737_init_device(struct device *dev)
/* Inform if part is not monitoring/started */
if (!(data->config & 0x01)) {
if (!force_start) {
- dev_err(dev, "Device is not monitoring. "
- "Use the force_start load parameter to "
- "override.\n");
+ dev_err(dev,
+ "Device is not monitoring. Use the force_start load parameter to override.\n");
return -EFAULT;
}
@@ -2289,8 +2290,8 @@ static int dme1737_init_device(struct device *dev)
*/
if (dme1737_i2c_get_features(0x2e, data) &&
dme1737_i2c_get_features(0x4e, data)) {
- dev_warn(dev, "Failed to query Super-IO for optional "
- "features.\n");
+ dev_warn(dev,
+ "Failed to query Super-IO for optional features.\n");
}
}
@@ -2317,8 +2318,8 @@ static int dme1737_init_device(struct device *dev)
break;
}
- dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
- "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+ dev_info(dev,
+ "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
(data->has_features & HAS_PWM(2)) ? "yes" : "no",
(data->has_features & HAS_PWM(4)) ? "yes" : "no",
(data->has_features & HAS_PWM(5)) ? "yes" : "no",
@@ -2330,18 +2331,16 @@ static int dme1737_init_device(struct device *dev)
reg = dme1737_read(data, DME1737_REG_TACH_PWM);
/* Inform if fan-to-pwm mapping differs from the default */
if (client && reg != 0xa4) { /* I2C chip */
- dev_warn(dev, "Non-standard fan to pwm mapping: "
- "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
- "fan4->pwm%d. Please report to the driver "
- "maintainer.\n",
+ dev_warn(dev,
+ "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, fan4->pwm%d. %s\n",
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
- ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+ ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1,
+ DO_REPORT);
} else if (!client && reg != 0x24) { /* ISA chip */
- dev_warn(dev, "Non-standard fan to pwm mapping: "
- "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
- "Please report to the driver maintainer.\n",
+ dev_warn(dev,
+ "Non-standard fan to pwm mapping: fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. %s\n",
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
- ((reg >> 4) & 0x03) + 1);
+ ((reg >> 4) & 0x03) + 1, DO_REPORT);
}
/*
@@ -2355,8 +2354,9 @@ static int dme1737_init_device(struct device *dev)
DME1737_REG_PWM_CONFIG(ix));
if ((data->has_features & HAS_PWM(ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
- dev_info(dev, "Switching pwm%d to "
- "manual mode.\n", ix + 1);
+ dev_info(dev,
+ "Switching pwm%d to manual mode.\n",
+ ix + 1);
data->pwm_config[ix] = PWM_EN_TO_REG(1,
data->pwm_config[ix]);
dme1737_write(data, DME1737_REG_PWM(ix), 0);
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index a9816979c5de..0c9f3da242bf 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1350,8 +1350,7 @@ static void f71805f_init_device(struct f71805f_data *data)
reg = f71805f_read8(data, F71805F_REG_START);
if ((reg & 0x41) != 0x01) {
- printk(KERN_DEBUG DRVNAME ": Starting monitoring "
- "operations\n");
+ pr_debug("Starting monitoring operations\n");
f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40);
}
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index b757088aeddb..dff841085baf 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -189,8 +189,8 @@ static void fam15h_power_init_data(struct pci_dev *f4,
/* result not allowed to be >= 256W */
if ((tmp >> 16) >= 256)
- dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
- "(processor_pwr_watts>=%u)\n",
+ dev_warn(&f4->dev,
+ "Bogus value for ProcessorPwrWatts (processor_pwr_watts>=%u)\n",
(unsigned int) (tmp >> 16));
/* convert to microWatt */
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 8af2755cdb87..d58abdc5a4cf 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -463,8 +463,9 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
v = 3;
break;
default:
- dev_err(dev, "fan_div value %lu not supported. "
- "Choose one of 2, 4 or 8!\n", v);
+ dev_err(dev,
+ "fan_div value %lu not supported. Choose one of 2, 4 or 8!\n",
+ v);
return -EINVAL;
}
@@ -1249,8 +1250,8 @@ static int fschmd_probe(struct i2c_client *client,
}
if (i == ARRAY_SIZE(watchdog_minors)) {
data->watchdog_miscdev.minor = 0;
- dev_warn(&client->dev, "Couldn't register watchdog chardev "
- "(due to no free minor)\n");
+ dev_warn(&client->dev,
+ "Couldn't register watchdog chardev (due to no free minor)\n");
}
mutex_unlock(&watchdog_data_mutex);
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index e2e5909a34df..95257a5621d8 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -344,8 +344,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
val = 3;
break;
default:
- dev_err(dev, "Invalid fan clock divider %lu, choose one "
- "of 1, 2, 4 or 8\n", val);
+ dev_err(dev,
+ "Invalid fan clock divider %lu, choose one of 1, 2, 4 or 8\n",
+ val);
return -EINVAL;
}
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 39781945a5d2..3104149795c5 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -105,10 +105,6 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
if (err)
return err;
- err = device_create_file(&pdev->dev, &dev_attr_fan1_alarm);
- if (err)
- return err;
-
/*
* If the alarm GPIO don't support interrupts, just leave
* without initializing the fail notification support.
@@ -121,23 +117,9 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data,
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
IRQF_SHARED, "GPIO fan alarm", fan_data);
- if (err)
- goto err_free_sysfs;
-
- return 0;
-
-err_free_sysfs:
- device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
return err;
}
-static void fan_alarm_free(struct gpio_fan_data *fan_data)
-{
- struct platform_device *pdev = fan_data->pdev;
-
- device_remove_file(&pdev->dev, &dev_attr_fan1_alarm);
-}
-
/*
* Control GPIOs.
*/
@@ -327,6 +309,12 @@ exit_unlock:
return ret;
}
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "gpio-fan\n");
+}
+
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm);
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable, set_pwm_enable);
@@ -336,8 +324,26 @@ static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL);
static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL);
static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm);
-static struct attribute *gpio_fan_ctrl_attributes[] = {
- &dev_attr_pwm1.attr,
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static umode_t gpio_fan_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct gpio_fan_data *data = dev_get_drvdata(dev);
+
+ if (index == 1 && !data->alarm)
+ return 0;
+ if (index > 1 && !data->ctrl)
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute *gpio_fan_attributes[] = {
+ &dev_attr_name.attr,
+ &dev_attr_fan1_alarm.attr, /* 1 */
+ &dev_attr_pwm1.attr, /* 2 */
&dev_attr_pwm1_enable.attr,
&dev_attr_pwm1_mode.attr,
&dev_attr_fan1_input.attr,
@@ -347,8 +353,9 @@ static struct attribute *gpio_fan_ctrl_attributes[] = {
NULL
};
-static const struct attribute_group gpio_fan_ctrl_group = {
- .attrs = gpio_fan_ctrl_attributes,
+static const struct attribute_group gpio_fan_group = {
+ .attrs = gpio_fan_attributes,
+ .is_visible = gpio_fan_is_visible,
};
static int fan_ctrl_init(struct gpio_fan_data *fan_data,
@@ -379,30 +386,9 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
if (fan_data->speed_index < 0)
return -ENODEV;
- err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
- return err;
-}
-
-static void fan_ctrl_free(struct gpio_fan_data *fan_data)
-{
- struct platform_device *pdev = fan_data->pdev;
-
- sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_ctrl_group);
-}
-
-/*
- * Platform driver.
- */
-
-static ssize_t show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "gpio-fan\n");
+ return 0;
}
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
-
#ifdef CONFIG_OF_GPIO
/*
* Translate OpenFirmware node properties into platform_data
@@ -546,38 +532,30 @@ static int gpio_fan_probe(struct platform_device *pdev)
/* Configure control GPIOs if available. */
if (pdata->ctrl && pdata->num_ctrl > 0) {
- if (!pdata->speed || pdata->num_speed <= 1) {
- err = -EINVAL;
- goto err_free_alarm;
- }
+ if (!pdata->speed || pdata->num_speed <= 1)
+ return -EINVAL;
err = fan_ctrl_init(fan_data, pdata);
if (err)
- goto err_free_alarm;
+ return err;
}
- err = device_create_file(&pdev->dev, &dev_attr_name);
+ err = sysfs_create_group(&pdev->dev.kobj, &gpio_fan_group);
if (err)
- goto err_free_ctrl;
+ return err;
/* Make this driver part of hwmon class. */
fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(fan_data->hwmon_dev)) {
err = PTR_ERR(fan_data->hwmon_dev);
- goto err_remove_name;
+ goto err_remove;
}
dev_info(&pdev->dev, "GPIO fan initialized\n");
return 0;
-err_remove_name:
- device_remove_file(&pdev->dev, &dev_attr_name);
-err_free_ctrl:
- if (fan_data->ctrl)
- fan_ctrl_free(fan_data);
-err_free_alarm:
- if (fan_data->alarm)
- fan_alarm_free(fan_data);
+err_remove:
+ sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
return err;
}
@@ -586,11 +564,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
hwmon_device_unregister(fan_data->hwmon_dev);
- device_remove_file(&pdev->dev, &dev_attr_name);
- if (fan_data->alarm)
- fan_alarm_free(fan_data);
- if (fan_data->ctrl)
- fan_ctrl_free(fan_data);
+ sysfs_remove_group(&pdev->dev.kobj, &gpio_fan_group);
return 0;
}
@@ -619,7 +593,7 @@ static int gpio_fan_resume(struct device *dev)
}
static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
-#define GPIO_FAN_PM &gpio_fan_pm
+#define GPIO_FAN_PM (&gpio_fan_pm)
#else
#define GPIO_FAN_PM NULL
#endif
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index a14f634248e7..1429f6e177f4 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -289,8 +289,9 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
data, &data->user);
if (err < 0) {
- dev_err(bmc, "Unable to register user with IPMI "
- "interface %d\n", data->interface);
+ dev_err(bmc,
+ "Unable to register user with IPMI interface %d\n",
+ data->interface);
return -EACCES;
}
@@ -328,8 +329,8 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
struct aem_ipmi_data *data = user_msg_data;
if (msg->msgid != data->tx_msgid) {
- dev_err(data->bmc_device, "Mismatch between received msgid "
- "(%02x) and transmitted msgid (%02x)!\n",
+ dev_err(data->bmc_device,
+ "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
(int)msg->msgid,
(int)data->tx_msgid);
ipmi_free_recv_msg(msg);
@@ -575,8 +576,8 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
/* Register with hwmon */
data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
- dev_err(&data->pdev->dev, "Unable to register hwmon "
- "device for IPMI interface %d\n",
+ dev_err(&data->pdev->dev,
+ "Unable to register hwmon device for IPMI interface %d\n",
probe->interface);
res = PTR_ERR(data->hwmon_dev);
goto hwmon_reg_err;
@@ -715,8 +716,8 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
/* Register with hwmon */
data->hwmon_dev = hwmon_device_register(&data->pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
- dev_err(&data->pdev->dev, "Unable to register hwmon "
- "device for IPMI interface %d\n",
+ dev_err(&data->pdev->dev,
+ "Unable to register hwmon device for IPMI interface %d\n",
probe->interface);
res = PTR_ERR(data->hwmon_dev);
goto hwmon_reg_err;
@@ -768,8 +769,8 @@ static void aem_init_aem2(struct aem_ipmi_data *probe)
while (!aem_find_aem2(probe, &fi_resp, i)) {
if (fi_resp.major != 2) {
- dev_err(probe->bmc_device, "Unknown AEM v%d; please "
- "report this to the maintainer.\n",
+ dev_err(probe->bmc_device,
+ "Unknown AEM v%d; please report this to the maintainer.\n",
fi_resp.major);
i++;
continue;
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
index b622a93ec32c..74b365ea01c7 100644
--- a/drivers/hwmon/ibmpex.c
+++ b/drivers/hwmon/ibmpex.c
@@ -163,8 +163,8 @@ static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
data->sensor_major = data->rx_msg_data[0];
data->sensor_minor = data->rx_msg_data[1];
- dev_info(data->bmc_device, "Found BMC with sensor interface "
- "v%d.%d %d-%02d-%02d on interface %d\n",
+ dev_info(data->bmc_device,
+ "Found BMC with sensor interface v%d.%d %d-%02d-%02d on interface %d\n",
data->sensor_major,
data->sensor_minor,
extract_value(data->rx_msg_data, 2),
@@ -478,8 +478,9 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
data, &data->user);
if (err < 0) {
- dev_err(dev, "Unable to register user with IPMI "
- "interface %d\n", data->interface);
+ dev_err(dev,
+ "Unable to register user with IPMI interface %d\n",
+ data->interface);
goto out;
}
@@ -501,8 +502,8 @@ static void ibmpex_register_bmc(int iface, struct device *dev)
data->hwmon_dev = hwmon_device_register(data->bmc_device);
if (IS_ERR(data->hwmon_dev)) {
- dev_err(data->bmc_device, "Unable to register hwmon "
- "device for IPMI interface %d\n",
+ dev_err(data->bmc_device,
+ "Unable to register hwmon device for IPMI interface %d\n",
data->interface);
goto out_user;
}
@@ -567,8 +568,8 @@ static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
if (msg->msgid != data->tx_msgid) {
- dev_err(data->bmc_device, "Mismatch between received msgid "
- "(%02x) and transmitted msgid (%02x)!\n",
+ dev_err(data->bmc_device,
+ "Mismatch between received msgid (%02x) and transmitted msgid (%02x)!\n",
(int)msg->msgid,
(int)data->tx_msgid);
ipmi_free_recv_msg(msg);
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 93af756ba48c..aafa4531b961 100644
--- a/drivers/staging/iio/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/of.h>
#include <linux/hwmon-sysfs.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
@@ -58,7 +59,12 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "iio_hwmon\n");
+ const char *name = "iio_hwmon";
+
+ if (dev->of_node && dev->of_node->name)
+ name = dev->of_node->name;
+
+ return sprintf(buf, "%s\n", name);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 8e7158c3ad2f..4958b2f89dce 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -186,20 +186,20 @@ static ssize_t ina2xx_show_value(struct device *dev,
}
/* shunt voltage */
-static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
- ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
+ INA2XX_SHUNT_VOLTAGE);
/* bus voltage */
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
- ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina2xx_show_value, NULL,
+ INA2XX_BUS_VOLTAGE);
/* calculated current */
-static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
- ina2xx_show_value, NULL, INA2XX_CURRENT);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
+ INA2XX_CURRENT);
/* calculated power */
-static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
- ina2xx_show_value, NULL, INA2XX_POWER);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
+ INA2XX_POWER);
/* pointers to created device attributes */
static struct attribute *ina2xx_attributes[] = {
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 37fc980fde24..72b21d5b1c62 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1778,7 +1778,7 @@ static int __init it87_find(unsigned short *address,
superio_select(5);
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8783) {
- int reg25, reg27, reg2A, reg2C, regEF;
+ int reg25, reg27, reg2a, reg2c, regef;
sio_data->skip_vid = 1; /* No VID */
@@ -1786,15 +1786,15 @@ static int __init it87_find(unsigned short *address,
reg25 = superio_inb(IT87_SIO_GPIO1_REG);
reg27 = superio_inb(IT87_SIO_GPIO3_REG);
- reg2A = superio_inb(IT87_SIO_PINX1_REG);
- reg2C = superio_inb(IT87_SIO_PINX2_REG);
- regEF = superio_inb(IT87_SIO_SPI_REG);
+ reg2a = superio_inb(IT87_SIO_PINX1_REG);
+ reg2c = superio_inb(IT87_SIO_PINX2_REG);
+ regef = superio_inb(IT87_SIO_SPI_REG);
/* Check if fan3 is there or not */
- if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+ if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2)))
sio_data->skip_fan |= (1 << 2);
if ((reg25 & (1 << 4))
- || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+ || (!(reg2a & (1 << 1)) && (regef & (1 << 0))))
sio_data->skip_pwm |= (1 << 2);
/* Check if fan2 is there or not */
@@ -1804,7 +1804,7 @@ static int __init it87_find(unsigned short *address,
sio_data->skip_pwm |= (1 << 1);
/* VIN5 */
- if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+ if ((reg27 & (1 << 0)) || (reg2c & (1 << 2)))
sio_data->skip_in |= (1 << 5); /* No VIN5 */
/* VIN6 */
@@ -1829,18 +1829,18 @@ static int __init it87_find(unsigned short *address,
* not the case, and ask the user to report if the
* resulting voltage is sane.
*/
- if (!(reg2C & (1 << 1))) {
- reg2C |= (1 << 1);
- superio_outb(IT87_SIO_PINX2_REG, reg2C);
+ if (!(reg2c & (1 << 1))) {
+ reg2c |= (1 << 1);
+ superio_outb(IT87_SIO_PINX2_REG, reg2c);
pr_notice("Routing internal VCCH5V to in7.\n");
}
pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
pr_notice("Please report if it displays a reasonable voltage.\n");
}
- if (reg2C & (1 << 0))
+ if (reg2c & (1 << 0))
sio_data->internal |= (1 << 0);
- if (reg2C & (1 << 1))
+ if (reg2c & (1 << 1))
sio_data->internal |= (1 << 1);
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 9f3c0aeacdb9..5b50e9e4f96b 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -200,8 +200,8 @@ static int k8temp_probe(struct pci_dev *pdev,
*/
if (model >= 0x40) {
data->swap_core_select = 1;
- dev_warn(&pdev->dev, "Temperature readouts might be wrong - "
- "check erratum #141\n");
+ dev_warn(&pdev->dev,
+ "Temperature readouts might be wrong - check erratum #141\n");
}
/*
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 483538fa1bd5..6cf6bff79003 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -386,8 +386,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
data->fan_div[nr] = 3;
break;
default:
- dev_err(dev, "fan_div value %ld not "
- "supported. Choose one of 1, 2, 4 or 8!\n", val);
+ dev_err(dev,
+ "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+ val);
mutex_unlock(&data->update_lock);
return -EINVAL;
}
@@ -636,8 +637,9 @@ static int lm78_i2c_detect(struct i2c_client *client,
goto err_nodev;
if (lm78_alias_detect(client, i)) {
- dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
- "be the same as ISA device\n", address);
+ dev_dbg(&adapter->dev,
+ "Device at 0x%02x appears to be the same as ISA device\n",
+ address);
goto err_nodev;
}
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 357fbb998728..eba89aac3ece 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -286,8 +286,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
data->fan_div[nr] = 3;
break;
default:
- dev_err(&client->dev, "fan_div value %ld not "
- "supported. Choose one of 1, 2, 4 or 8!\n", val);
+ dev_err(&client->dev,
+ "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+ val);
mutex_unlock(&data->update_lock);
return -EINVAL;
}
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 47ade8ba152d..3894c408fda3 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -1293,8 +1293,8 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
company = lm85_read_value(client, LM85_REG_COMPANY);
verstep = lm85_read_value(client, LM85_REG_VERSTEP);
- dev_dbg(&adapter->dev, "Detecting device at 0x%02x with "
- "COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
+ dev_dbg(&adapter->dev,
+ "Detecting device at 0x%02x with COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
address, company, verstep);
/* All supported chips have the version in common */
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index b40f34cdb3ca..a6f46058b1be 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -354,12 +354,12 @@ static const unsigned long lm93_vin_val_max[16] = {
static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
{
- const long uV_max = lm93_vin_val_max[nr] * 1000;
- const long uV_min = lm93_vin_val_min[nr] * 1000;
+ const long uv_max = lm93_vin_val_max[nr] * 1000;
+ const long uv_min = lm93_vin_val_min[nr] * 1000;
- const long slope = (uV_max - uV_min) /
+ const long slope = (uv_max - uv_min) /
(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
- const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+ const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
return (slope * reg + intercept + 500) / 1000;
}
@@ -371,20 +371,20 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
static u8 LM93_IN_TO_REG(int nr, unsigned val)
{
/* range limit */
- const long mV = clamp_val(val,
+ const long mv = clamp_val(val,
lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
/* try not to lose too much precision here */
- const long uV = mV * 1000;
- const long uV_max = lm93_vin_val_max[nr] * 1000;
- const long uV_min = lm93_vin_val_min[nr] * 1000;
+ const long uv = mv * 1000;
+ const long uv_max = lm93_vin_val_max[nr] * 1000;
+ const long uv_min = lm93_vin_val_min[nr] * 1000;
/* convert */
- const long slope = (uV_max - uV_min) /
+ const long slope = (uv_max - uv_min) /
(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
- const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+ const long intercept = uv_min - slope * lm93_vin_reg_min[nr];
- u8 result = ((uV - intercept + (slope/2)) / slope);
+ u8 result = ((uv - intercept + (slope/2)) / slope);
result = clamp_val(result,
lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
return result;
@@ -393,10 +393,10 @@ static u8 LM93_IN_TO_REG(int nr, unsigned val)
/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
{
- const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+ const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
(((reg >> 0 & 0x0f) + 1) * -25000);
- const long uV_vid = vid * 1000;
- return (uV_vid + uV_offset + 5000) / 10000;
+ const long uv_vid = vid * 1000;
+ return (uv_vid + uv_offset + 5000) / 10000;
}
#define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid))
@@ -409,13 +409,13 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
*/
static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
{
- long uV_offset = vid * 1000 - val * 10000;
+ long uv_offset = vid * 1000 - val * 10000;
if (upper) {
- uV_offset = clamp_val(uV_offset, 12500, 200000);
- return (u8)((uV_offset / 12500 - 1) << 4);
+ uv_offset = clamp_val(uv_offset, 12500, 200000);
+ return (u8)((uv_offset / 12500 - 1) << 4);
} else {
- uV_offset = clamp_val(uV_offset, -400000, -25000);
- return (u8)((uV_offset / -25000 - 1) << 0);
+ uv_offset = clamp_val(uv_offset, -400000, -25000);
+ return (u8)((uv_offset / -25000 - 1) << 0);
}
}
@@ -818,8 +818,9 @@ static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
if (value >= 0) {
return value;
} else {
- dev_warn(&client->dev, "lm93: read byte data failed, "
- "address 0x%02x.\n", reg);
+ dev_warn(&client->dev,
+ "lm93: read byte data failed, address 0x%02x.\n",
+ reg);
mdelay(i + 3);
}
@@ -838,8 +839,9 @@ static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
result = i2c_smbus_write_byte_data(client, reg, value);
if (result < 0)
- dev_warn(&client->dev, "lm93: write byte data failed, "
- "0x%02x at address 0x%02x.\n", value, reg);
+ dev_warn(&client->dev,
+ "lm93: write byte data failed, 0x%02x at address 0x%02x.\n",
+ value, reg);
return result;
}
@@ -854,8 +856,9 @@ static u16 lm93_read_word(struct i2c_client *client, u8 reg)
if (value >= 0) {
return value;
} else {
- dev_warn(&client->dev, "lm93: read word data failed, "
- "address 0x%02x.\n", reg);
+ dev_warn(&client->dev,
+ "lm93: read word data failed, address 0x%02x.\n",
+ reg);
mdelay(i + 3);
}
@@ -874,8 +877,9 @@ static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
result = i2c_smbus_write_word_data(client, reg, value);
if (result < 0)
- dev_warn(&client->dev, "lm93: write word data failed, "
- "0x%04x at address 0x%02x.\n", value, reg);
+ dev_warn(&client->dev,
+ "lm93: write word data failed, 0x%04x at address 0x%02x.\n",
+ value, reg);
return result;
}
@@ -898,8 +902,8 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
if (result == lm93_block_read_cmds[fbn].len) {
break;
} else {
- dev_warn(&client->dev, "lm93: block read data failed, "
- "command 0x%02x.\n",
+ dev_warn(&client->dev,
+ "lm93: block read data failed, command 0x%02x.\n",
lm93_block_read_cmds[fbn].cmd);
mdelay(i + 3);
}
@@ -2672,8 +2676,8 @@ static void lm93_init_client(struct i2c_client *client)
return;
}
- dev_warn(&client->dev, "timed out waiting for sensor "
- "chip to signal ready!\n");
+ dev_warn(&client->dev,
+ "timed out waiting for sensor chip to signal ready!\n");
}
/* Return 0 if detection is successful, -ENODEV otherwise */
@@ -2733,12 +2737,12 @@ static int lm93_probe(struct i2c_client *client,
dev_dbg(&client->dev, "using SMBus block data transactions\n");
update = lm93_update_client_full;
} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
- dev_dbg(&client->dev, "disabled SMBus block data "
- "transactions\n");
+ dev_dbg(&client->dev,
+ "disabled SMBus block data transactions\n");
update = lm93_update_client_min;
} else {
- dev_dbg(&client->dev, "detect failed, "
- "smbus byte and/or word data not supported!\n");
+ dev_dbg(&client->dev,
+ "detect failed, smbus byte and/or word data not supported!\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c
new file mode 100644
index 000000000000..307c9eaeeb9f
--- /dev/null
+++ b/drivers/hwmon/lm95234.c
@@ -0,0 +1,769 @@
+/*
+ * Driver for Texas Instruments / National Semiconductor LM95234
+ *
+ * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from lm95241.c
+ * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+#define DRVNAME "lm95234"
+
+static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
+
+/* LM95234 registers */
+#define LM95234_REG_MAN_ID 0xFE
+#define LM95234_REG_CHIP_ID 0xFF
+#define LM95234_REG_STATUS 0x02
+#define LM95234_REG_CONFIG 0x03
+#define LM95234_REG_CONVRATE 0x04
+#define LM95234_REG_STS_FAULT 0x07
+#define LM95234_REG_STS_TCRIT1 0x08
+#define LM95234_REG_STS_TCRIT2 0x09
+#define LM95234_REG_TEMPH(x) ((x) + 0x10)
+#define LM95234_REG_TEMPL(x) ((x) + 0x20)
+#define LM95234_REG_UTEMPH(x) ((x) + 0x19) /* Remote only */
+#define LM95234_REG_UTEMPL(x) ((x) + 0x29)
+#define LM95234_REG_REM_MODEL 0x30
+#define LM95234_REG_REM_MODEL_STS 0x38
+#define LM95234_REG_OFFSET(x) ((x) + 0x31) /* Remote only */
+#define LM95234_REG_TCRIT1(x) ((x) + 0x40)
+#define LM95234_REG_TCRIT2(x) ((x) + 0x49) /* Remote channel 1,2 */
+#define LM95234_REG_TCRIT_HYST 0x5a
+
+#define NATSEMI_MAN_ID 0x01
+#define LM95234_CHIP_ID 0x79
+
+/* Client data (each client gets its own) */
+struct lm95234_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ unsigned long last_updated, interval; /* in jiffies */
+ bool valid; /* false until following fields are valid */
+ /* registers values */
+ int temp[5]; /* temperature (signed) */
+ u32 status; /* fault/alarm status */
+ u8 tcrit1[5]; /* critical temperature limit */
+ u8 tcrit2[2]; /* high temperature limit */
+ s8 toffset[4]; /* remote temperature offset */
+ u8 thyst; /* common hysteresis */
+
+ u8 sensor_type; /* temperature sensor type */
+};
+
+static int lm95234_read_temp(struct i2c_client *client, int index, int *t)
+{
+ int val;
+ u16 temp = 0;
+
+ if (index) {
+ val = i2c_smbus_read_byte_data(client,
+ LM95234_REG_UTEMPH(index - 1));
+ if (val < 0)
+ return val;
+ temp = val << 8;
+ val = i2c_smbus_read_byte_data(client,
+ LM95234_REG_UTEMPL(index - 1));
+ if (val < 0)
+ return val;
+ temp |= val;
+ *t = temp;
+ }
+ /*
+ * Read signed temperature if unsigned temperature is 0,
+ * or if this is the local sensor.
+ */
+ if (!temp) {
+ val = i2c_smbus_read_byte_data(client,
+ LM95234_REG_TEMPH(index));
+ if (val < 0)
+ return val;
+ temp = val << 8;
+ val = i2c_smbus_read_byte_data(client,
+ LM95234_REG_TEMPL(index));
+ if (val < 0)
+ return val;
+ temp |= val;
+ *t = (s16)temp;
+ }
+ return 0;
+}
+
+static u16 update_intervals[] = { 143, 364, 1000, 2500 };
+
+/* Fill value cache. Must be called with update lock held. */
+
+static int lm95234_fill_cache(struct i2c_client *client)
+{
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int i, ret;
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+ if (ret < 0)
+ return ret;
+
+ data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]);
+
+ for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) {
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i));
+ if (ret < 0)
+ return ret;
+ data->tcrit1[i] = ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) {
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i));
+ if (ret < 0)
+ return ret;
+ data->tcrit2[i] = ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(data->toffset); i++) {
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i));
+ if (ret < 0)
+ return ret;
+ data->toffset[i] = ret;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST);
+ if (ret < 0)
+ return ret;
+ data->thyst = ret;
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+ if (ret < 0)
+ return ret;
+ data->sensor_type = ret;
+
+ return 0;
+}
+
+static int lm95234_update_device(struct i2c_client *client,
+ struct lm95234_data *data)
+{
+ int ret;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + data->interval) ||
+ !data->valid) {
+ int i;
+
+ if (!data->valid) {
+ ret = lm95234_fill_cache(client);
+ if (ret < 0)
+ goto abort;
+ }
+
+ data->valid = false;
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ ret = lm95234_read_temp(client, i, &data->temp[i]);
+ if (ret < 0)
+ goto abort;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT);
+ if (ret < 0)
+ goto abort;
+ data->status = ret;
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1);
+ if (ret < 0)
+ goto abort;
+ data->status |= ret << 8;
+
+ ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2);
+ if (ret < 0)
+ goto abort;
+ data->status |= ret << 16;
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+ ret = 0;
+abort:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n",
+ DIV_ROUND_CLOSEST(data->temp[index] * 125, 32));
+}
+
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ u32 mask = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u", !!(data->status & mask));
+}
+
+static ssize_t show_type(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ u8 mask = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n");
+}
+
+static ssize_t set_type(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ u8 mask = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != 1 && val != 2)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (val == 1)
+ data->sensor_type |= mask;
+ else
+ data->sensor_type &= ~mask;
+ data->valid = false;
+ i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
+ data->sensor_type);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u", data->tcrit2[index] * 1000);
+}
+
+static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127);
+
+ mutex_lock(&data->update_lock);
+ data->tcrit2[index] = val;
+ i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_tcrit2_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ /* Result can be negative, so be careful with unsigned operands */
+ return sprintf(buf, "%d",
+ ((int)data->tcrit2[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+
+ return sprintf(buf, "%u", data->tcrit1[index] * 1000);
+}
+
+static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->tcrit1[index] = val;
+ i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_tcrit1_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ /* Result can be negative, so be careful with unsigned operands */
+ return sprintf(buf, "%d",
+ ((int)data->tcrit1[index] - (int)data->thyst) * 1000);
+}
+
+static ssize_t set_tcrit1_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ val = DIV_ROUND_CLOSEST(val, 1000);
+ val = clamp_val((int)data->tcrit1[index] - val, 0, 31);
+
+ mutex_lock(&data->update_lock);
+ data->thyst = val;
+ i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_offset(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d", data->toffset[index] * 500);
+}
+
+static ssize_t set_offset(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int index = to_sensor_dev_attr(attr)->index;
+ long val;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ /* Accuracy is 1/2 degrees C */
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127);
+
+ mutex_lock(&data->update_lock);
+ data->toffset[index] = val;
+ i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%lu\n",
+ DIV_ROUND_CLOSEST(data->interval * 1000, HZ));
+}
+
+static ssize_t set_interval(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm95234_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ u8 regval;
+ int ret = lm95234_update_device(client, data);
+
+ if (ret)
+ return ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ for (regval = 0; regval < 3; regval++) {
+ if (val <= update_intervals[regval])
+ break;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->interval = msecs_to_jiffies(update_intervals[regval]);
+ i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL,
+ BIT(0) | BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL,
+ BIT(2) | BIT(3));
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL,
+ BIT(4) | BIT(5));
+static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL,
+ BIT(6) | BIT(7));
+
+static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ BIT(1));
+static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ BIT(2));
+static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ BIT(3));
+static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type,
+ BIT(4));
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1,
+ set_tcrit1, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2,
+ set_tcrit2, 0);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2,
+ set_tcrit2, 1);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1,
+ set_tcrit1, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1,
+ set_tcrit1, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst,
+ set_tcrit1_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4);
+
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(0 + 8));
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(1 + 16));
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(2 + 16));
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(3 + 8));
+static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(4 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+ set_tcrit1, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1,
+ set_tcrit1, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(1 + 8));
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
+ BIT(2 + 8));
+
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset,
+ set_offset, 0);
+static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset,
+ set_offset, 1);
+static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset,
+ set_offset, 2);
+static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
+ set_offset, 3);
+
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
+ set_interval);
+
+static struct attribute *lm95234_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
+ &sensor_dev_attr_temp5_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+ &sensor_dev_attr_temp4_type.dev_attr.attr,
+ &sensor_dev_attr_temp5_type.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp4_offset.dev_attr.attr,
+ &sensor_dev_attr_temp5_offset.dev_attr.attr,
+ &dev_attr_update_interval.attr,
+ NULL
+};
+
+static const struct attribute_group lm95234_group = {
+ .attrs = lm95234_attributes,
+};
+
+static int lm95234_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int mfg_id, chip_id, val;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID);
+ if (mfg_id != NATSEMI_MAN_ID)
+ return -ENODEV;
+
+ chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
+ if (chip_id != LM95234_CHIP_ID)
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
+ if (val & 0x30)
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+ if (val & 0xbc)
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
+ if (val & 0xfc)
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+ if (val & 0xe1)
+ return -ENODEV;
+
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+ if (val & 0xe1)
+ return -ENODEV;
+
+ strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
+ return 0;
+}
+
+static int lm95234_init_client(struct i2c_client *client)
+{
+ int val, model;
+
+ /* start conversion if necessary */
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
+ if (val < 0)
+ return val;
+ if (val & 0x40)
+ i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG,
+ val & ~0x40);
+
+ /* If diode type status reports an error, try to fix it */
+ val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
+ if (val < 0)
+ return val;
+ model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
+ if (model < 0)
+ return model;
+ if (model & val) {
+ dev_notice(&client->dev,
+ "Fixing remote diode type misconfiguration (0x%x)\n",
+ val);
+ i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL,
+ model & ~val);
+ }
+ return 0;
+}
+
+static int lm95234_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct lm95234_data *data;
+ int err;
+
+ data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the LM95234 chip */
+ err = lm95234_init_client(client);
+ if (err < 0)
+ return err;
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&dev->kobj, &lm95234_group);
+ if (err)
+ return err;
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+exit_remove_files:
+ sysfs_remove_group(&dev->kobj, &lm95234_group);
+ return err;
+}
+
+static int lm95234_remove(struct i2c_client *client)
+{
+ struct lm95234_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm95234_group);
+
+ return 0;
+}
+
+/* Driver data (common to all clients) */
+static const struct i2c_device_id lm95234_id[] = {
+ { "lm95234", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm95234_id);
+
+static struct i2c_driver lm95234_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = DRVNAME,
+ },
+ .probe = lm95234_probe,
+ .remove = lm95234_remove,
+ .id_table = lm95234_id,
+ .detect = lm95234_detect,
+ .address_list = normal_i2c,
+};
+
+module_i2c_driver(lm95234_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("LM95234 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c
index 4319a94f549d..af81be1237c9 100644
--- a/drivers/hwmon/ltc4151.c
+++ b/drivers/hwmon/ltc4151.c
@@ -146,14 +146,14 @@ static ssize_t ltc4151_show_value(struct device *dev,
/*
* Input voltages.
*/
-static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
- ltc4151_show_value, NULL, LTC4151_VIN_H);
-static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, \
- ltc4151_show_value, NULL, LTC4151_ADIN_H);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4151_show_value, NULL,
+ LTC4151_VIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4151_show_value, NULL,
+ LTC4151_ADIN_H);
/* Currents (via sense resistor) */
-static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
- ltc4151_show_value, NULL, LTC4151_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4151_show_value, NULL,
+ LTC4151_SENSE_H);
/*
* Finally, construct an array of pointers to members of the above objects,
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c
index e8876108a6b3..8a142960d69e 100644
--- a/drivers/hwmon/ltc4215.c
+++ b/drivers/hwmon/ltc4215.c
@@ -172,12 +172,12 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
struct device_attribute *da,
char *buf)
{
- struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ltc4215_data *data = ltc4215_update_device(dev);
- const u8 reg = data->regs[attr->index];
- const u32 mask = attr->nr;
+ const u8 reg = data->regs[LTC4215_STATUS];
+ const u32 mask = attr->index;
- return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+ return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
}
/*
@@ -186,39 +186,29 @@ static ssize_t ltc4215_show_alarm(struct device *dev,
* for each register.
*/
-#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4215_show_voltage, NULL, ltc4215_cmd_idx)
-
-#define LTC4215_CURRENT(name) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4215_show_current, NULL, 0);
-
-#define LTC4215_POWER(name) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4215_show_power, NULL, 0);
-
-#define LTC4215_ALARM(name, mask, reg) \
- static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
- ltc4215_show_alarm, NULL, (mask), reg)
-
/* Construct a sensor_device_attribute structure for each register */
/* Current */
-LTC4215_CURRENT(curr1_input);
-LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4215_show_current, NULL, 0);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+ 1 << 2);
/* Power (virtual) */
-LTC4215_POWER(power1_input);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4215_show_power, NULL, 0);
/* Input Voltage */
-LTC4215_VOLTAGE(in1_input, LTC4215_ADIN);
-LTC4215_ALARM(in1_max_alarm, (1 << 0), LTC4215_STATUS);
-LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4215_show_voltage, NULL,
+ LTC4215_ADIN);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+ 1 << 0);
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+ 1 << 1);
/* Output Voltage */
-LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE);
-LTC4215_ALARM(in2_min_alarm, (1 << 3), LTC4215_STATUS);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4215_show_voltage, NULL,
+ LTC4215_SOURCE);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4215_show_alarm, NULL,
+ 1 << 3);
/*
* Finally, construct an array of pointers to members of the above objects,
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index 3653f79dc2de..cdc1ecc6734d 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -319,80 +319,82 @@ static ssize_t ltc4245_show_gpio(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
}
-/*
- * These macros are used below in constructing device attribute objects
- * for use with sysfs_create_group() to make a sysfs device file
- * for each register.
- */
-
-#define LTC4245_VOLTAGE(name, ltc4245_cmd_idx) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4245_show_voltage, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_CURRENT(name, ltc4245_cmd_idx) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4245_show_current, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_POWER(name, ltc4245_cmd_idx) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4245_show_power, NULL, ltc4245_cmd_idx)
-
-#define LTC4245_ALARM(name, mask, reg) \
- static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
- ltc4245_show_alarm, NULL, (mask), reg)
-
-#define LTC4245_GPIO_VOLTAGE(name, gpio_num) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4245_show_gpio, NULL, gpio_num)
-
/* Construct a sensor_device_attribute structure for each register */
/* Input voltages */
-LTC4245_VOLTAGE(in1_input, LTC4245_12VIN);
-LTC4245_VOLTAGE(in2_input, LTC4245_5VIN);
-LTC4245_VOLTAGE(in3_input, LTC4245_3VIN);
-LTC4245_VOLTAGE(in4_input, LTC4245_VEEIN);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_12VIN);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_5VIN);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_3VIN);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_VEEIN);
/* Input undervoltage alarms */
-LTC4245_ALARM(in1_min_alarm, (1 << 0), LTC4245_FAULT1);
-LTC4245_ALARM(in2_min_alarm, (1 << 1), LTC4245_FAULT1);
-LTC4245_ALARM(in3_min_alarm, (1 << 2), LTC4245_FAULT1);
-LTC4245_ALARM(in4_min_alarm, (1 << 3), LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 0, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 1, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 2, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 3, LTC4245_FAULT1);
/* Currents (via sense resistor) */
-LTC4245_CURRENT(curr1_input, LTC4245_12VSENSE);
-LTC4245_CURRENT(curr2_input, LTC4245_5VSENSE);
-LTC4245_CURRENT(curr3_input, LTC4245_3VSENSE);
-LTC4245_CURRENT(curr4_input, LTC4245_VEESENSE);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
+ LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
+ LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
+ LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
+ LTC4245_VEESENSE);
/* Overcurrent alarms */
-LTC4245_ALARM(curr1_max_alarm, (1 << 4), LTC4245_FAULT1);
-LTC4245_ALARM(curr2_max_alarm, (1 << 5), LTC4245_FAULT1);
-LTC4245_ALARM(curr3_max_alarm, (1 << 6), LTC4245_FAULT1);
-LTC4245_ALARM(curr4_max_alarm, (1 << 7), LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 4, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 5, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 6, LTC4245_FAULT1);
+static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 7, LTC4245_FAULT1);
/* Output voltages */
-LTC4245_VOLTAGE(in5_input, LTC4245_12VOUT);
-LTC4245_VOLTAGE(in6_input, LTC4245_5VOUT);
-LTC4245_VOLTAGE(in7_input, LTC4245_3VOUT);
-LTC4245_VOLTAGE(in8_input, LTC4245_VEEOUT);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_12VOUT);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_5VOUT);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_3VOUT);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
+ LTC4245_VEEOUT);
/* Power Bad alarms */
-LTC4245_ALARM(in5_min_alarm, (1 << 0), LTC4245_FAULT2);
-LTC4245_ALARM(in6_min_alarm, (1 << 1), LTC4245_FAULT2);
-LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
-LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 0, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 1, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 2, LTC4245_FAULT2);
+static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
+ 1 << 3, LTC4245_FAULT2);
/* GPIO voltages */
-LTC4245_GPIO_VOLTAGE(in9_input, 0);
-LTC4245_GPIO_VOLTAGE(in10_input, 1);
-LTC4245_GPIO_VOLTAGE(in11_input, 2);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
/* Power Consumption (virtual) */
-LTC4245_POWER(power1_input, LTC4245_12VSENSE);
-LTC4245_POWER(power2_input, LTC4245_5VSENSE);
-LTC4245_POWER(power3_input, LTC4245_3VSENSE);
-LTC4245_POWER(power4_input, LTC4245_VEESENSE);
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
+ LTC4245_12VSENSE);
+static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
+ LTC4245_5VSENSE);
+static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
+ LTC4245_3VSENSE);
+static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
+ LTC4245_VEESENSE);
/*
* Finally, construct an array of pointers to members of the above objects,
diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c
index 84a2d2872b20..487da58ec86c 100644
--- a/drivers/hwmon/ltc4261.c
+++ b/drivers/hwmon/ltc4261.c
@@ -165,24 +165,12 @@ static ssize_t ltc4261_show_bool(struct device *dev,
}
/*
- * These macros are used below in constructing device attribute objects
- * for use with sysfs_create_group() to make a sysfs device file
- * for each register.
- */
-
-#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4261_show_value, NULL, ltc4261_cmd_idx)
-
-#define LTC4261_BOOL(name, mask) \
- static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
- ltc4261_show_bool, NULL, (mask))
-
-/*
* Input voltages.
*/
-LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
-LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4261_show_value, NULL,
+ LTC4261_ADIN_H);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4261_show_value, NULL,
+ LTC4261_ADIN2_H);
/*
* Voltage alarms. The chip has only one set of voltage alarm status bits,
@@ -192,16 +180,22 @@ LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
* To ensure that the alarm condition is reported to the user, report it
* with both voltage sensors.
*/
-LTC4261_BOOL(in1_min_alarm, FAULT_UV);
-LTC4261_BOOL(in1_max_alarm, FAULT_OV);
-LTC4261_BOOL(in2_min_alarm, FAULT_UV);
-LTC4261_BOOL(in2_max_alarm, FAULT_OV);
+static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+ FAULT_UV);
+static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+ FAULT_OV);
+static SENSOR_DEVICE_ATTR(in2_min_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+ FAULT_UV);
+static SENSOR_DEVICE_ATTR(in2_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+ FAULT_OV);
/* Currents (via sense resistor) */
-LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4261_show_value, NULL,
+ LTC4261_SENSE_H);
/* Overcurrent alarm */
-LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
+static SENSOR_DEVICE_ATTR(curr1_max_alarm, S_IRUGO, ltc4261_show_bool, NULL,
+ FAULT_OC);
static struct attribute *ltc4261_attributes[] = {
&sensor_dev_attr_in1_input.dev_attr.attr,
diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c
index bf4aa3777fc1..328fb0353c17 100644
--- a/drivers/hwmon/max6697.c
+++ b/drivers/hwmon/max6697.c
@@ -399,82 +399,95 @@ static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_alarm, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_alarm, NULL, 7);
-static struct attribute *max6697_attributes[8][7] = {
- {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_crit.dev_attr.attr,
- &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_crit.dev_attr.attr,
- &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_crit.dev_attr.attr,
- &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp4_input.dev_attr.attr,
- &sensor_dev_attr_temp4_max.dev_attr.attr,
- &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_crit.dev_attr.attr,
- &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp5_input.dev_attr.attr,
- &sensor_dev_attr_temp5_max.dev_attr.attr,
- &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp5_crit.dev_attr.attr,
- &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp5_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp6_input.dev_attr.attr,
- &sensor_dev_attr_temp6_max.dev_attr.attr,
- &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp6_crit.dev_attr.attr,
- &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp6_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp7_input.dev_attr.attr,
- &sensor_dev_attr_temp7_max.dev_attr.attr,
- &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp7_crit.dev_attr.attr,
- &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp7_fault.dev_attr.attr,
- NULL
- }, {
- &sensor_dev_attr_temp8_input.dev_attr.attr,
- &sensor_dev_attr_temp8_max.dev_attr.attr,
- &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp8_crit.dev_attr.attr,
- &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp8_fault.dev_attr.attr,
- NULL
- }
+static DEVICE_ATTR(dummy, 0, NULL, NULL);
+
+static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
+ int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6697_data *data = i2c_get_clientdata(client);
+ const struct max6697_chip_data *chip = data->chip;
+ int channel = index / 6; /* channel number */
+ int nr = index % 6; /* attribute index within channel */
+
+ if (channel >= chip->channels)
+ return 0;
+
+ if ((nr == 3 || nr == 4) && !(chip->have_crit & (1 << channel)))
+ return 0;
+ if (nr == 5 && !(chip->have_fault & (1 << channel)))
+ return 0;
+
+ return attr->mode;
+}
+
+/*
+ * max6697_is_visible uses the index into the following array to determine
+ * if attributes should be created or not. Any change in order or content
+ * must be matched in max6697_is_visible.
+ */
+static struct attribute *max6697_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &dev_attr_dummy.attr,
+
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_crit.dev_attr.attr,
+ &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp7_input.dev_attr.attr,
+ &sensor_dev_attr_temp7_max.dev_attr.attr,
+ &sensor_dev_attr_temp7_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp7_crit.dev_attr.attr,
+ &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp7_fault.dev_attr.attr,
+
+ &sensor_dev_attr_temp8_input.dev_attr.attr,
+ &sensor_dev_attr_temp8_max.dev_attr.attr,
+ &sensor_dev_attr_temp8_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp8_crit.dev_attr.attr,
+ &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp8_fault.dev_attr.attr,
+ NULL
};
-static const struct attribute_group max6697_group[8] = {
- { .attrs = max6697_attributes[0] },
- { .attrs = max6697_attributes[1] },
- { .attrs = max6697_attributes[2] },
- { .attrs = max6697_attributes[3] },
- { .attrs = max6697_attributes[4] },
- { .attrs = max6697_attributes[5] },
- { .attrs = max6697_attributes[6] },
- { .attrs = max6697_attributes[7] },
+static const struct attribute_group max6697_group = {
+ .attrs = max6697_attributes, .is_visible = max6697_is_visible,
};
static void max6697_get_config_of(struct device_node *node,
@@ -606,21 +619,13 @@ done:
return 0;
}
-static void max6697_remove_files(struct i2c_client *client)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(max6697_group); i++)
- sysfs_remove_group(&client->dev.kobj, &max6697_group[i]);
-}
-
static int max6697_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct device *dev = &client->dev;
struct max6697_data *data;
- int i, err;
+ int err;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
@@ -639,37 +644,9 @@ static int max6697_probe(struct i2c_client *client,
if (err)
return err;
- for (i = 0; i < data->chip->channels; i++) {
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][0]);
- if (err)
- goto error;
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][1]);
- if (err)
- goto error;
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][2]);
- if (err)
- goto error;
-
- if (data->chip->have_crit & (1 << i)) {
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][3]);
- if (err)
- goto error;
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][4]);
- if (err)
- goto error;
- }
- if (data->chip->have_fault & (1 << i)) {
- err = sysfs_create_file(&dev->kobj,
- max6697_attributes[i][5]);
- if (err)
- goto error;
- }
- }
+ err = sysfs_create_group(&client->dev.kobj, &max6697_group);
+ if (err)
+ return err;
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -680,7 +657,7 @@ static int max6697_probe(struct i2c_client *client,
return 0;
error:
- max6697_remove_files(client);
+ sysfs_remove_group(&client->dev.kobj, &max6697_group);
return err;
}
@@ -689,7 +666,7 @@ static int max6697_remove(struct i2c_client *client)
struct max6697_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
- max6697_remove_files(client);
+ sysfs_remove_group(&client->dev.kobj, &max6697_group);
return 0;
}
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index 2a7f331cd3c0..982d8622c09b 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -273,18 +273,7 @@ static struct platform_driver mc13783_adc_driver = {
.id_table = mc13783_adc_idtable,
};
-static int __init mc13783_adc_init(void)
-{
- return platform_driver_probe(&mc13783_adc_driver, mc13783_adc_probe);
-}
-
-static void __exit mc13783_adc_exit(void)
-{
- platform_driver_unregister(&mc13783_adc_driver);
-}
-
-module_init(mc13783_adc_init);
-module_exit(mc13783_adc_exit);
+module_platform_driver_probe(mc13783_adc_driver, mc13783_adc_probe);
MODULE_DESCRIPTION("MC13783 ADC driver");
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
new file mode 100644
index 000000000000..f43f5e571db9
--- /dev/null
+++ b/drivers/hwmon/nct6775.c
@@ -0,0 +1,4191 @@
+/*
+ * nct6775 - Driver for the hardware monitoring functionality of
+ * Nuvoton NCT677x Super-I/O chips
+ *
+ * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net>
+ *
+ * Derived from w83627ehf driver
+ * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2006 Yuan Mu (Winbond),
+ * Rudolf Marek <r.marek@assembler.cz>
+ * David Hubbard <david.c.hubbard@gmail.com>
+ * Daniel J Blueman <daniel.blueman@gmail.com>
+ * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00)
+ *
+ * Shamelessly ripped from the w83627hf driver
+ * Copyright (C) 2003 Mark Studebaker
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Supports the following chips:
+ *
+ * Chip #vin #fan #pwm #temp chip IDs man ID
+ * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
+ * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
+ * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
+ *
+ * #temp lists the number of monitored temperature sources (first value) plus
+ * the number of directly connectable temperature sensors (second value).
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include "lm75.h"
+
+#define USE_ALTERNATE
+
+enum kinds { nct6775, nct6776, nct6779 };
+
+/* used to set data->name = nct6775_device_names[data->sio_kind] */
+static const char * const nct6775_device_names[] = {
+ "nct6775",
+ "nct6776",
+ "nct6779",
+};
+
+static unsigned short force_id;
+module_param(force_id, ushort, 0);
+MODULE_PARM_DESC(force_id, "Override the detected device ID");
+
+static unsigned short fan_debounce;
+module_param(fan_debounce, ushort, 0);
+MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
+
+#define DRVNAME "nct6775"
+
+/*
+ * Super-I/O constants and functions
+ */
+
+#define NCT6775_LD_ACPI 0x0a
+#define NCT6775_LD_HWM 0x0b
+#define NCT6775_LD_VID 0x0d
+
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_ENABLE 0x30 /* Logical device enable */
+#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+#define SIO_NCT6775_ID 0xb470
+#define SIO_NCT6776_ID 0xc330
+#define SIO_NCT6779_ID 0xc560
+#define SIO_ID_MASK 0xFFF0
+
+enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
+
+static inline void
+superio_outb(int ioreg, int reg, int val)
+{
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
+}
+
+static inline int
+superio_inb(int ioreg, int reg)
+{
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
+}
+
+static inline void
+superio_select(int ioreg, int ld)
+{
+ outb(SIO_REG_LDSEL, ioreg);
+ outb(ld, ioreg + 1);
+}
+
+static inline int
+superio_enter(int ioreg)
+{
+ /*
+ * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+ */
+ if (!request_muxed_region(ioreg, 2, DRVNAME))
+ return -EBUSY;
+
+ outb(0x87, ioreg);
+ outb(0x87, ioreg);
+
+ return 0;
+}
+
+static inline void
+superio_exit(int ioreg)
+{
+ outb(0xaa, ioreg);
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
+ release_region(ioreg, 2);
+}
+
+/*
+ * ISA constants
+ */
+
+#define IOREGION_ALIGNMENT (~7)
+#define IOREGION_OFFSET 5
+#define IOREGION_LENGTH 2
+#define ADDR_REG_OFFSET 0
+#define DATA_REG_OFFSET 1
+
+#define NCT6775_REG_BANK 0x4E
+#define NCT6775_REG_CONFIG 0x40
+
+/*
+ * Not currently used:
+ * REG_MAN_ID has the value 0x5ca3 for all supported chips.
+ * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
+ * REG_MAN_ID is at port 0x4f
+ * REG_CHIP_ID is at port 0x58
+ */
+
+#define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/
+#define NUM_TEMP_FIXED 6 /* Max number of fixed temp attribute sets */
+
+#define NUM_REG_ALARM 4 /* Max number of alarm registers */
+
+/* Common and NCT6775 specific data */
+
+/* Voltage min/max registers for nr=7..14 are in bank 5 */
+
+static const u16 NCT6775_REG_IN_MAX[] = {
+ 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a,
+ 0x55c, 0x55e, 0x560, 0x562 };
+static const u16 NCT6775_REG_IN_MIN[] = {
+ 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b,
+ 0x55d, 0x55f, 0x561, 0x563 };
+static const u16 NCT6775_REG_IN[] = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552
+};
+
+#define NCT6775_REG_VBAT 0x5D
+#define NCT6775_REG_DIODE 0x5E
+
+#define NCT6775_REG_FANDIV1 0x506
+#define NCT6775_REG_FANDIV2 0x507
+
+#define NCT6775_REG_CR_FAN_DEBOUNCE 0xf0
+
+static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };
+
+/* 0..15 voltages, 16..23 fans, 24..31 temperatures */
+
+static const s8 NCT6775_ALARM_BITS[] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, -1 }; /* intrusion0, intrusion1 */
+
+#define FAN_ALARM_BASE 16
+#define TEMP_ALARM_BASE 24
+#define INTRUSION_ALARM_BASE 30
+
+static const u8 NCT6775_REG_CR_CASEOPEN_CLR[] = { 0xe6, 0xee };
+static const u8 NCT6775_CR_CASEOPEN_CLR_MASK[] = { 0x20, 0x01 };
+
+/* DC or PWM output fan configuration */
+static const u8 NCT6775_REG_PWM_MODE[] = { 0x04, 0x04, 0x12 };
+static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
+
+/* Advanced Fan control, some values are common for all fans */
+
+static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301, 0x801, 0x901 };
+static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302, 0x802, 0x902 };
+static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
+ 0x103, 0x203, 0x303, 0x803, 0x903 };
+static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
+ 0x104, 0x204, 0x304, 0x804, 0x904 };
+static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
+ 0x105, 0x205, 0x305, 0x805, 0x905 };
+static const u16 NCT6775_REG_FAN_START_OUTPUT[]
+ = { 0x106, 0x206, 0x306, 0x806, 0x906 };
+static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
+static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
+
+static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
+ 0x107, 0x207, 0x307, 0x807, 0x907 };
+static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309, 0x809, 0x909 };
+static const u16 NCT6775_REG_PWM_READ[] = { 0x01, 0x03, 0x11, 0x13, 0x15 };
+
+static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
+static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
+static const u16 NCT6775_REG_FAN_PULSES[] = { 0x641, 0x642, 0x643, 0x644, 0 };
+
+static const u16 NCT6775_REG_TEMP[] = {
+ 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d };
+
+static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+ 0, 0x152, 0x252, 0x628, 0x629, 0x62A };
+static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+ 0x3a, 0x153, 0x253, 0x673, 0x678, 0x67D };
+static const u16 NCT6775_REG_TEMP_OVER[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+ 0x39, 0x155, 0x255, 0x672, 0x677, 0x67C };
+
+static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+ 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
+
+static const u16 NCT6775_REG_TEMP_SEL[] = {
+ 0x100, 0x200, 0x300, 0x800, 0x900 };
+
+static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
+ 0x139, 0x239, 0x339, 0x839, 0x939 };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP[] = {
+ 0x13a, 0x23a, 0x33a, 0x83a, 0x93a };
+static const u16 NCT6775_REG_WEIGHT_TEMP_STEP_TOL[] = {
+ 0x13b, 0x23b, 0x33b, 0x83b, 0x93b };
+static const u16 NCT6775_REG_WEIGHT_DUTY_STEP[] = {
+ 0x13c, 0x23c, 0x33c, 0x83c, 0x93c };
+static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
+ 0x13d, 0x23d, 0x33d, 0x83d, 0x93d };
+
+static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
+
+static const u16 NCT6775_REG_AUTO_TEMP[] = {
+ 0x121, 0x221, 0x321, 0x821, 0x921 };
+static const u16 NCT6775_REG_AUTO_PWM[] = {
+ 0x127, 0x227, 0x327, 0x827, 0x927 };
+
+#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
+#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
+
+static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
+
+static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
+ 0x135, 0x235, 0x335, 0x835, 0x935 };
+static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
+ 0x138, 0x238, 0x338, 0x838, 0x938 };
+
+static const char *const nct6775_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN",
+ "AMD SB-TSI",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PECI Agent 2",
+ "PECI Agent 3",
+ "PECI Agent 4",
+ "PECI Agent 5",
+ "PECI Agent 6",
+ "PECI Agent 7",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "PCH_DIM0_TEMP",
+ "PCH_DIM1_TEMP",
+ "PCH_DIM2_TEMP",
+ "PCH_DIM3_TEMP"
+};
+
+static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
+
+static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1]
+ = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06,
+ 0xa07 };
+
+/* NCT6776 specific data */
+
+static const s8 NCT6776_ALARM_BITS[] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, 9 }; /* intrusion0, intrusion1 */
+
+static const u16 NCT6776_REG_TOLERANCE_H[] = {
+ 0x10c, 0x20c, 0x30c, 0x80c, 0x90c };
+
+static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0 };
+static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0 };
+
+static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 };
+static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
+
+static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
+ 0x13e, 0x23e, 0x33e, 0x83e, 0x93e };
+
+static const u16 NCT6776_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
+ 0x18, 0x152, 0x252, 0x628, 0x629, 0x62A };
+
+static const char *const nct6776_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN",
+ "SMBUSMASTER 0",
+ "SMBUSMASTER 1",
+ "SMBUSMASTER 2",
+ "SMBUSMASTER 3",
+ "SMBUSMASTER 4",
+ "SMBUSMASTER 5",
+ "SMBUSMASTER 6",
+ "SMBUSMASTER 7",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "PCH_DIM0_TEMP",
+ "PCH_DIM1_TEMP",
+ "PCH_DIM2_TEMP",
+ "PCH_DIM3_TEMP",
+ "BYTE_TEMP"
+};
+
+static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
+
+static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+/* NCT6779 specific data */
+
+static const u16 NCT6779_REG_IN[] = {
+ 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487,
+ 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e };
+
+static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = {
+ 0x459, 0x45A, 0x45B, 0x568 };
+
+static const s8 NCT6779_ALARM_BITS[] = {
+ 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
+ 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */
+ -1, /* unused */
+ 6, 7, 11, 10, 23, /* fan1..fan5 */
+ -1, -1, -1, /* unused */
+ 4, 5, 13, -1, -1, -1, /* temp1..temp6 */
+ 12, 9 }; /* intrusion0, intrusion1 */
+
+static const u16 NCT6779_REG_FAN[] = { 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8 };
+static const u16 NCT6779_REG_FAN_PULSES[] = {
+ 0x644, 0x645, 0x646, 0x647, 0x648 };
+
+static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
+ 0x136, 0x236, 0x336, 0x836, 0x936 };
+static const u16 NCT6779_REG_CRITICAL_PWM[] = {
+ 0x137, 0x237, 0x337, 0x837, 0x937 };
+
+static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
+static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+ 0x18, 0x152 };
+static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+ 0x3a, 0x153 };
+static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
+ 0x39, 0x155 };
+
+static const u16 NCT6779_REG_TEMP_OFFSET[] = {
+ 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+
+static const char *const nct6779_temp_label[] = {
+ "",
+ "SYSTIN",
+ "CPUTIN",
+ "AUXTIN0",
+ "AUXTIN1",
+ "AUXTIN2",
+ "AUXTIN3",
+ "",
+ "SMBUSMASTER 0",
+ "SMBUSMASTER 1",
+ "SMBUSMASTER 2",
+ "SMBUSMASTER 3",
+ "SMBUSMASTER 4",
+ "SMBUSMASTER 5",
+ "SMBUSMASTER 6",
+ "SMBUSMASTER 7",
+ "PECI Agent 0",
+ "PECI Agent 1",
+ "PCH_CHIP_CPU_MAX_TEMP",
+ "PCH_CHIP_TEMP",
+ "PCH_CPU_TEMP",
+ "PCH_MCH_TEMP",
+ "PCH_DIM0_TEMP",
+ "PCH_DIM1_TEMP",
+ "PCH_DIM2_TEMP",
+ "PCH_DIM3_TEMP",
+ "BYTE_TEMP"
+};
+
+static const u16 NCT6779_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6779_temp_label) - 1]
+ = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
+ 0x408, 0 };
+
+static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1]
+ = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a };
+
+static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
+{
+ if (mode == 0 && pwm == 255)
+ return off;
+ return mode + 1;
+}
+
+static int pwm_enable_to_reg(enum pwm_enable mode)
+{
+ if (mode == off)
+ return 0;
+ return mode - 1;
+}
+
+/*
+ * Conversions
+ */
+
+/* 1 is DC mode, output in ms */
+static unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+ return mode ? 400 * reg : 100 * reg;
+}
+
+static u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+ return clamp_val((mode ? (msec + 200) / 400 :
+ (msec + 50) / 100), 1, 255);
+}
+
+static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
+{
+ if (reg == 0 || reg == 255)
+ return 0;
+ return 1350000U / (reg << divreg);
+}
+
+static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
+{
+ if ((reg & 0xff1f) == 0xff1f)
+ return 0;
+
+ reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
+
+ if (reg == 0)
+ return 0;
+
+ return 1350000U / reg;
+}
+
+static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
+{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
+
+ /*
+ * Even though the registers are 16 bit wide, the fan divisor
+ * still applies.
+ */
+ return 1350000U / (reg << divreg);
+}
+
+static u16 fan_to_reg(u32 fan, unsigned int divreg)
+{
+ if (!fan)
+ return 0;
+
+ return (1350000U / fan) >> divreg;
+}
+
+static inline unsigned int
+div_from_reg(u8 reg)
+{
+ return 1 << reg;
+}
+
+/*
+ * Some of the voltage inputs have internal scaling, the tables below
+ * contain 8 (the ADC LSB in mV) * scaling factor * 100
+ */
+static const u16 scale_in[15] = {
+ 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800,
+ 800, 800
+};
+
+static inline long in_from_reg(u8 reg, u8 nr)
+{
+ return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
+}
+
+static inline u8 in_to_reg(u32 val, u8 nr)
+{
+ return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
+}
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct nct6775_data {
+ int addr; /* IO base of hw monitor block */
+ enum kinds kind;
+ const char *name;
+
+ struct device *hwmon_dev;
+
+ u16 reg_temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+ * 3=temp_crit
+ */
+ u8 temp_src[NUM_TEMP];
+ u16 reg_temp_config[NUM_TEMP];
+ const char * const *temp_label;
+ int temp_label_num;
+
+ u16 REG_CONFIG;
+ u16 REG_VBAT;
+ u16 REG_DIODE;
+
+ const s8 *ALARM_BITS;
+
+ const u16 *REG_VIN;
+ const u16 *REG_IN_MINMAX[2];
+
+ const u16 *REG_TARGET;
+ const u16 *REG_FAN;
+ const u16 *REG_FAN_MODE;
+ const u16 *REG_FAN_MIN;
+ const u16 *REG_FAN_PULSES;
+ const u16 *REG_FAN_TIME[3];
+
+ const u16 *REG_TOLERANCE_H;
+
+ const u8 *REG_PWM_MODE;
+ const u8 *PWM_MODE_MASK;
+
+ const u16 *REG_PWM[7]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+ * [3]=pwm_max, [4]=pwm_step,
+ * [5]=weight_duty_step, [6]=weight_duty_base
+ */
+ const u16 *REG_PWM_READ;
+
+ const u16 *REG_AUTO_TEMP;
+ const u16 *REG_AUTO_PWM;
+
+ const u16 *REG_CRITICAL_TEMP;
+ const u16 *REG_CRITICAL_TEMP_TOLERANCE;
+
+ const u16 *REG_TEMP_SOURCE; /* temp register sources */
+ const u16 *REG_TEMP_SEL;
+ const u16 *REG_WEIGHT_TEMP_SEL;
+ const u16 *REG_WEIGHT_TEMP[3]; /* 0=base, 1=tolerance, 2=step */
+
+ const u16 *REG_TEMP_OFFSET;
+
+ const u16 *REG_ALARM;
+
+ unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
+ unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
+
+ struct mutex update_lock;
+ bool valid; /* true if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values */
+ u8 bank; /* current register bank */
+ u8 in_num; /* number of in inputs we have */
+ u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */
+ unsigned int rpm[5];
+ u16 fan_min[5];
+ u8 fan_pulses[5];
+ u8 fan_div[5];
+ u8 has_pwm;
+ u8 has_fan; /* some fan inputs can be disabled */
+ u8 has_fan_min; /* some fans don't have min register */
+ bool has_fan_div;
+
+ u8 temp_fixed_num; /* 3 or 6 */
+ u8 temp_type[NUM_TEMP_FIXED];
+ s8 temp_offset[NUM_TEMP_FIXED];
+ s16 temp[4][NUM_TEMP]; /* 0=temp, 1=temp_over, 2=temp_hyst,
+ * 3=temp_crit */
+ u64 alarms;
+
+ u8 pwm_num; /* number of pwm */
+ u8 pwm_mode[5]; /* 1->DC variable voltage, 0->PWM variable duty cycle */
+ enum pwm_enable pwm_enable[5];
+ /* 0->off
+ * 1->manual
+ * 2->thermal cruise mode (also called SmartFan I)
+ * 3->fan speed cruise mode
+ * 4->SmartFan III
+ * 5->enhanced variable thermal cruise (SmartFan IV)
+ */
+ u8 pwm[7][5]; /* [0]=pwm, [1]=pwm_start, [2]=pwm_floor,
+ * [3]=pwm_max, [4]=pwm_step,
+ * [5]=weight_duty_step, [6]=weight_duty_base
+ */
+
+ u8 target_temp[5];
+ u8 target_temp_mask;
+ u32 target_speed[5];
+ u32 target_speed_tolerance[5];
+ u8 speed_tolerance_limit;
+
+ u8 temp_tolerance[2][5];
+ u8 tolerance_mask;
+
+ u8 fan_time[3][5]; /* 0 = stop_time, 1 = step_up, 2 = step_down */
+
+ /* Automatic fan speed control registers */
+ int auto_pwm_num;
+ u8 auto_pwm[5][7];
+ u8 auto_temp[5][7];
+ u8 pwm_temp_sel[5];
+ u8 pwm_weight_temp_sel[5];
+ u8 weight_temp[3][5]; /* 0->temp_step, 1->temp_step_tol,
+ * 2->temp_base
+ */
+
+ u8 vid;
+ u8 vrm;
+
+ u16 have_temp;
+ u16 have_temp_fixed;
+ u16 have_in;
+#ifdef CONFIG_PM
+ /* Remember extra register values over suspend/resume */
+ u8 vbat;
+ u8 fandiv1;
+ u8 fandiv2;
+#endif
+};
+
+struct nct6775_sio_data {
+ int sioreg;
+ enum kinds kind;
+};
+
+static bool is_word_sized(struct nct6775_data *data, u16 reg)
+{
+ switch (data->kind) {
+ case nct6775:
+ return (((reg & 0xff00) == 0x100 ||
+ (reg & 0xff00) == 0x200) &&
+ ((reg & 0x00ff) == 0x50 ||
+ (reg & 0x00ff) == 0x53 ||
+ (reg & 0x00ff) == 0x55)) ||
+ (reg & 0xfff0) == 0x630 ||
+ reg == 0x640 || reg == 0x642 ||
+ reg == 0x662 ||
+ ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+ reg == 0x73 || reg == 0x75 || reg == 0x77;
+ case nct6776:
+ return (((reg & 0xff00) == 0x100 ||
+ (reg & 0xff00) == 0x200) &&
+ ((reg & 0x00ff) == 0x50 ||
+ (reg & 0x00ff) == 0x53 ||
+ (reg & 0x00ff) == 0x55)) ||
+ (reg & 0xfff0) == 0x630 ||
+ reg == 0x402 ||
+ reg == 0x640 || reg == 0x642 ||
+ ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) ||
+ reg == 0x73 || reg == 0x75 || reg == 0x77;
+ case nct6779:
+ return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
+ ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) ||
+ reg == 0x402 ||
+ reg == 0x63a || reg == 0x63c || reg == 0x63e ||
+ reg == 0x640 || reg == 0x642 ||
+ reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
+ reg == 0x7b;
+ }
+ return false;
+}
+
+/*
+ * On older chips, only registers 0x50-0x5f are banked.
+ * On more recent chips, all registers are banked.
+ * Assume that is the case and set the bank number for each access.
+ * Cache the bank number so it only needs to be set if it changes.
+ */
+static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
+{
+ u8 bank = reg >> 8;
+ if (data->bank != bank) {
+ outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
+ outb_p(bank, data->addr + DATA_REG_OFFSET);
+ data->bank = bank;
+ }
+}
+
+static u16 nct6775_read_value(struct nct6775_data *data, u16 reg)
+{
+ int res, word_sized = is_word_sized(data, reg);
+
+ nct6775_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+ res = inb_p(data->addr + DATA_REG_OFFSET);
+ if (word_sized) {
+ outb_p((reg & 0xff) + 1,
+ data->addr + ADDR_REG_OFFSET);
+ res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
+ }
+ return res;
+}
+
+static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value)
+{
+ int word_sized = is_word_sized(data, reg);
+
+ nct6775_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+ if (word_sized) {
+ outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
+ outb_p((reg & 0xff) + 1,
+ data->addr + ADDR_REG_OFFSET);
+ }
+ outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+ return 0;
+}
+
+/* We left-align 8-bit temperature values to make the code simpler */
+static u16 nct6775_read_temp(struct nct6775_data *data, u16 reg)
+{
+ u16 res;
+
+ res = nct6775_read_value(data, reg);
+ if (!is_word_sized(data, reg))
+ res <<= 8;
+
+ return res;
+}
+
+static int nct6775_write_temp(struct nct6775_data *data, u16 reg, u16 value)
+{
+ if (!is_word_sized(data, reg))
+ value >>= 8;
+ return nct6775_write_value(data, reg, value);
+}
+
+/* This function assumes that the caller holds data->update_lock */
+static void nct6775_write_fan_div(struct nct6775_data *data, int nr)
+{
+ u8 reg;
+
+ switch (nr) {
+ case 0:
+ reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
+ | (data->fan_div[0] & 0x7);
+ nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+ break;
+ case 1:
+ reg = (nct6775_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
+ | ((data->fan_div[1] << 4) & 0x70);
+ nct6775_write_value(data, NCT6775_REG_FANDIV1, reg);
+ break;
+ case 2:
+ reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
+ | (data->fan_div[2] & 0x7);
+ nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+ break;
+ case 3:
+ reg = (nct6775_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
+ | ((data->fan_div[3] << 4) & 0x70);
+ nct6775_write_value(data, NCT6775_REG_FANDIV2, reg);
+ break;
+ }
+}
+
+static void nct6775_write_fan_div_common(struct nct6775_data *data, int nr)
+{
+ if (data->kind == nct6775)
+ nct6775_write_fan_div(data, nr);
+}
+
+static void nct6775_update_fan_div(struct nct6775_data *data)
+{
+ u8 i;
+
+ i = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+ data->fan_div[0] = i & 0x7;
+ data->fan_div[1] = (i & 0x70) >> 4;
+ i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+ data->fan_div[2] = i & 0x7;
+ if (data->has_fan & (1 << 3))
+ data->fan_div[3] = (i & 0x70) >> 4;
+}
+
+static void nct6775_update_fan_div_common(struct nct6775_data *data)
+{
+ if (data->kind == nct6775)
+ nct6775_update_fan_div(data);
+}
+
+static void nct6775_init_fan_div(struct nct6775_data *data)
+{
+ int i;
+
+ nct6775_update_fan_div_common(data);
+ /*
+ * For all fans, start with highest divider value if the divider
+ * register is not initialized. This ensures that we get a
+ * reading from the fan count register, even if it is not optimal.
+ * We'll compute a better divider later on.
+ */
+ for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
+ if (!(data->has_fan & (1 << i)))
+ continue;
+ if (data->fan_div[i] == 0) {
+ data->fan_div[i] = 7;
+ nct6775_write_fan_div_common(data, i);
+ }
+ }
+}
+
+static void nct6775_init_fan_common(struct device *dev,
+ struct nct6775_data *data)
+{
+ int i;
+ u8 reg;
+
+ if (data->has_fan_div)
+ nct6775_init_fan_div(data);
+
+ /*
+ * If fan_min is not set (0), set it to 0xff to disable it. This
+ * prevents the unnecessary warning when fanX_min is reported as 0.
+ */
+ for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+ if (data->has_fan_min & (1 << i)) {
+ reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
+ if (!reg)
+ nct6775_write_value(data, data->REG_FAN_MIN[i],
+ data->has_fan_div ? 0xff
+ : 0xff1f);
+ }
+ }
+}
+
+static void nct6775_select_fan_div(struct device *dev,
+ struct nct6775_data *data, int nr, u16 reg)
+{
+ u8 fan_div = data->fan_div[nr];
+ u16 fan_min;
+
+ if (!data->has_fan_div)
+ return;
+
+ /*
+ * If we failed to measure the fan speed, or the reported value is not
+ * in the optimal range, and the clock divider can be modified,
+ * let's try that for next time.
+ */
+ if (reg == 0x00 && fan_div < 0x07)
+ fan_div++;
+ else if (reg != 0x00 && reg < 0x30 && fan_div > 0)
+ fan_div--;
+
+ if (fan_div != data->fan_div[nr]) {
+ dev_dbg(dev, "Modifying fan%d clock divider from %u to %u\n",
+ nr + 1, div_from_reg(data->fan_div[nr]),
+ div_from_reg(fan_div));
+
+ /* Preserve min limit if possible */
+ if (data->has_fan_min & (1 << nr)) {
+ fan_min = data->fan_min[nr];
+ if (fan_div > data->fan_div[nr]) {
+ if (fan_min != 255 && fan_min > 1)
+ fan_min >>= 1;
+ } else {
+ if (fan_min != 255) {
+ fan_min <<= 1;
+ if (fan_min > 254)
+ fan_min = 254;
+ }
+ }
+ if (fan_min != data->fan_min[nr]) {
+ data->fan_min[nr] = fan_min;
+ nct6775_write_value(data, data->REG_FAN_MIN[nr],
+ fan_min);
+ }
+ }
+ data->fan_div[nr] = fan_div;
+ nct6775_write_fan_div_common(data, nr);
+ }
+}
+
+static void nct6775_update_pwm(struct device *dev)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int i, j;
+ int fanmodecfg, reg;
+ bool duty_is_dc;
+
+ for (i = 0; i < data->pwm_num; i++) {
+ if (!(data->has_pwm & (1 << i)))
+ continue;
+
+ duty_is_dc = data->REG_PWM_MODE[i] &&
+ (nct6775_read_value(data, data->REG_PWM_MODE[i])
+ & data->PWM_MODE_MASK[i]);
+ data->pwm_mode[i] = duty_is_dc;
+
+ fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
+ for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
+ if (data->REG_PWM[j] && data->REG_PWM[j][i]) {
+ data->pwm[j][i]
+ = nct6775_read_value(data,
+ data->REG_PWM[j][i]);
+ }
+ }
+
+ data->pwm_enable[i] = reg_to_pwm_enable(data->pwm[0][i],
+ (fanmodecfg >> 4) & 7);
+
+ if (!data->temp_tolerance[0][i] ||
+ data->pwm_enable[i] != speed_cruise)
+ data->temp_tolerance[0][i] = fanmodecfg & 0x0f;
+ if (!data->target_speed_tolerance[i] ||
+ data->pwm_enable[i] == speed_cruise) {
+ u8 t = fanmodecfg & 0x0f;
+ if (data->REG_TOLERANCE_H) {
+ t |= (nct6775_read_value(data,
+ data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
+ }
+ data->target_speed_tolerance[i] = t;
+ }
+
+ data->temp_tolerance[1][i] =
+ nct6775_read_value(data,
+ data->REG_CRITICAL_TEMP_TOLERANCE[i]);
+
+ reg = nct6775_read_value(data, data->REG_TEMP_SEL[i]);
+ data->pwm_temp_sel[i] = reg & 0x1f;
+ /* If fan can stop, report floor as 0 */
+ if (reg & 0x80)
+ data->pwm[2][i] = 0;
+
+ reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]);
+ data->pwm_weight_temp_sel[i] = reg & 0x1f;
+ /* If weight is disabled, report weight source as 0 */
+ if (j == 1 && !(reg & 0x80))
+ data->pwm_weight_temp_sel[i] = 0;
+
+ /* Weight temp data */
+ for (j = 0; j < ARRAY_SIZE(data->weight_temp); j++) {
+ data->weight_temp[j][i]
+ = nct6775_read_value(data,
+ data->REG_WEIGHT_TEMP[j][i]);
+ }
+ }
+}
+
+static void nct6775_update_pwm_limits(struct device *dev)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int i, j;
+ u8 reg;
+ u16 reg_t;
+
+ for (i = 0; i < data->pwm_num; i++) {
+ if (!(data->has_pwm & (1 << i)))
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
+ data->fan_time[j][i] =
+ nct6775_read_value(data, data->REG_FAN_TIME[j][i]);
+ }
+
+ reg_t = nct6775_read_value(data, data->REG_TARGET[i]);
+ /* Update only in matching mode or if never updated */
+ if (!data->target_temp[i] ||
+ data->pwm_enable[i] == thermal_cruise)
+ data->target_temp[i] = reg_t & data->target_temp_mask;
+ if (!data->target_speed[i] ||
+ data->pwm_enable[i] == speed_cruise) {
+ if (data->REG_TOLERANCE_H) {
+ reg_t |= (nct6775_read_value(data,
+ data->REG_TOLERANCE_H[i]) & 0x0f) << 8;
+ }
+ data->target_speed[i] = reg_t;
+ }
+
+ for (j = 0; j < data->auto_pwm_num; j++) {
+ data->auto_pwm[i][j] =
+ nct6775_read_value(data,
+ NCT6775_AUTO_PWM(data, i, j));
+ data->auto_temp[i][j] =
+ nct6775_read_value(data,
+ NCT6775_AUTO_TEMP(data, i, j));
+ }
+
+ /* critical auto_pwm temperature data */
+ data->auto_temp[i][data->auto_pwm_num] =
+ nct6775_read_value(data, data->REG_CRITICAL_TEMP[i]);
+
+ switch (data->kind) {
+ case nct6775:
+ reg = nct6775_read_value(data,
+ NCT6775_REG_CRITICAL_ENAB[i]);
+ data->auto_pwm[i][data->auto_pwm_num] =
+ (reg & 0x02) ? 0xff : 0x00;
+ break;
+ case nct6776:
+ data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+ break;
+ case nct6779:
+ reg = nct6775_read_value(data,
+ NCT6779_REG_CRITICAL_PWM_ENABLE[i]);
+ if (reg & 1)
+ data->auto_pwm[i][data->auto_pwm_num] =
+ nct6775_read_value(data,
+ NCT6779_REG_CRITICAL_PWM[i]);
+ else
+ data->auto_pwm[i][data->auto_pwm_num] = 0xff;
+ break;
+ }
+ }
+}
+
+static struct nct6775_data *nct6775_update_device(struct device *dev)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ int i, j;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ /* Fan clock dividers */
+ nct6775_update_fan_div_common(data);
+
+ /* Measured voltages and limits */
+ for (i = 0; i < data->in_num; i++) {
+ if (!(data->have_in & (1 << i)))
+ continue;
+
+ data->in[i][0] = nct6775_read_value(data,
+ data->REG_VIN[i]);
+ data->in[i][1] = nct6775_read_value(data,
+ data->REG_IN_MINMAX[0][i]);
+ data->in[i][2] = nct6775_read_value(data,
+ data->REG_IN_MINMAX[1][i]);
+ }
+
+ /* Measured fan speeds and limits */
+ for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
+ u16 reg;
+
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
+ reg = nct6775_read_value(data, data->REG_FAN[i]);
+ data->rpm[i] = data->fan_from_reg(reg,
+ data->fan_div[i]);
+
+ if (data->has_fan_min & (1 << i))
+ data->fan_min[i] = nct6775_read_value(data,
+ data->REG_FAN_MIN[i]);
+ data->fan_pulses[i] =
+ nct6775_read_value(data, data->REG_FAN_PULSES[i]);
+
+ nct6775_select_fan_div(dev, data, i, reg);
+ }
+
+ nct6775_update_pwm(dev);
+ nct6775_update_pwm_limits(dev);
+
+ /* Measured temperatures and limits */
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
+ if (data->reg_temp[j][i])
+ data->temp[j][i]
+ = nct6775_read_temp(data,
+ data->reg_temp[j][i]);
+ }
+ if (!(data->have_temp_fixed & (1 << i)))
+ continue;
+ data->temp_offset[i]
+ = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
+ }
+
+ data->alarms = 0;
+ for (i = 0; i < NUM_REG_ALARM; i++) {
+ u8 alarm;
+ if (!data->REG_ALARM[i])
+ continue;
+ alarm = nct6775_read_value(data, data->REG_ALARM[i]);
+ data->alarms |= ((u64)alarm) << (i << 3);
+ }
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+static ssize_t
+show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
+}
+
+static ssize_t
+store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ unsigned long val;
+ int err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ mutex_lock(&data->update_lock);
+ data->in[nr][index] = in_to_reg(val, nr);
+ nct6775_write_value(data, data->REG_IN_MINMAX[index - 1][nr],
+ data->in[nr][index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = data->ALARM_BITS[sattr->index];
+ return sprintf(buf, "%u\n",
+ (unsigned int)((data->alarms >> nr) & 0x01));
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0);
+static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0);
+static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0);
+static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0);
+static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0);
+static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0);
+static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0);
+static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0);
+static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14);
+
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 3, 1);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 4, 1);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 5, 1);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 6, 1);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 7, 1);
+static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 8, 1);
+static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 9, 1);
+static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 10, 1);
+static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 11, 1);
+static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 12, 1);
+static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 13, 1);
+static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 14, 1);
+
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 1, 2);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 2, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 3, 2);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 4, 2);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 5, 2);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 6, 2);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 7, 2);
+static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 8, 2);
+static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 9, 2);
+static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 10, 2);
+static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 11, 2);
+static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 12, 2);
+static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 13, 2);
+static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg,
+ store_in_reg, 14, 2);
+
+static struct attribute *nct6775_attributes_in[15][5] = {
+ {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in9_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in10_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ &sensor_dev_attr_in11_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in12_max.dev_attr.attr,
+ &sensor_dev_attr_in12_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in13_max.dev_attr.attr,
+ &sensor_dev_attr_in13_alarm.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in14_max.dev_attr.attr,
+ &sensor_dev_attr_in14_alarm.dev_attr.attr,
+ NULL
+ },
+};
+
+static const struct attribute_group nct6775_group_in[15] = {
+ { .attrs = nct6775_attributes_in[0] },
+ { .attrs = nct6775_attributes_in[1] },
+ { .attrs = nct6775_attributes_in[2] },
+ { .attrs = nct6775_attributes_in[3] },
+ { .attrs = nct6775_attributes_in[4] },
+ { .attrs = nct6775_attributes_in[5] },
+ { .attrs = nct6775_attributes_in[6] },
+ { .attrs = nct6775_attributes_in[7] },
+ { .attrs = nct6775_attributes_in[8] },
+ { .attrs = nct6775_attributes_in[9] },
+ { .attrs = nct6775_attributes_in[10] },
+ { .attrs = nct6775_attributes_in[11] },
+ { .attrs = nct6775_attributes_in[12] },
+ { .attrs = nct6775_attributes_in[13] },
+ { .attrs = nct6775_attributes_in[14] },
+};
+
+static ssize_t
+show_fan(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%d\n", data->rpm[nr]);
+}
+
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%d\n",
+ data->fan_from_reg_min(data->fan_min[nr],
+ data->fan_div[nr]));
+}
+
+static ssize_t
+show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
+}
+
+static ssize_t
+store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ unsigned int reg;
+ u8 new_div;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ if (!data->has_fan_div) {
+ /* NCT6776F or NCT6779D; we know this is a 13 bit register */
+ if (!val) {
+ val = 0xff1f;
+ } else {
+ if (val > 1350000U)
+ val = 135000U;
+ val = 1350000U / val;
+ val = (val & 0x1f) | ((val << 3) & 0xff00);
+ }
+ data->fan_min[nr] = val;
+ goto write_min; /* Leave fan divider alone */
+ }
+ if (!val) {
+ /* No min limit, alarm disabled */
+ data->fan_min[nr] = 255;
+ new_div = data->fan_div[nr]; /* No change */
+ dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
+ goto write_div;
+ }
+ reg = 1350000U / val;
+ if (reg >= 128 * 255) {
+ /*
+ * Speed below this value cannot possibly be represented,
+ * even with the highest divider (128)
+ */
+ data->fan_min[nr] = 254;
+ new_div = 7; /* 128 == (1 << 7) */
+ dev_warn(dev,
+ "fan%u low limit %lu below minimum %u, set to minimum\n",
+ nr + 1, val, data->fan_from_reg_min(254, 7));
+ } else if (!reg) {
+ /*
+ * Speed above this value cannot possibly be represented,
+ * even with the lowest divider (1)
+ */
+ data->fan_min[nr] = 1;
+ new_div = 0; /* 1 == (1 << 0) */
+ dev_warn(dev,
+ "fan%u low limit %lu above maximum %u, set to maximum\n",
+ nr + 1, val, data->fan_from_reg_min(1, 0));
+ } else {
+ /*
+ * Automatically pick the best divider, i.e. the one such
+ * that the min limit will correspond to a register value
+ * in the 96..192 range
+ */
+ new_div = 0;
+ while (reg > 192 && new_div < 7) {
+ reg >>= 1;
+ new_div++;
+ }
+ data->fan_min[nr] = reg;
+ }
+
+write_div:
+ /*
+ * Write both the fan clock divider (if it changed) and the new
+ * fan min (unconditionally)
+ */
+ if (new_div != data->fan_div[nr]) {
+ dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
+ nr + 1, div_from_reg(data->fan_div[nr]),
+ div_from_reg(new_div));
+ data->fan_div[nr] = new_div;
+ nct6775_write_fan_div_common(data, nr);
+ /* Give the chip time to sample a new speed value */
+ data->last_updated = jiffies;
+ }
+
+write_min:
+ nct6775_write_value(data, data->REG_FAN_MIN[nr], data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int p = data->fan_pulses[sattr->index];
+
+ return sprintf(buf, "%d\n", p ? : 4);
+}
+
+static ssize_t
+store_fan_pulses(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (val > 4)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->fan_pulses[nr] = val & 3;
+ nct6775_write_value(data, data->REG_FAN_PULSES[nr], val & 3);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute sda_fan_input[] = {
+ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+ SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 1),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 2),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 3),
+ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, FAN_ALARM_BASE + 4),
+};
+
+static struct sensor_device_attribute sda_fan_min[] = {
+ SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 0),
+ SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 1),
+ SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 2),
+ SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 3),
+ SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
+ store_fan_min, 4),
+};
+
+static struct sensor_device_attribute sda_fan_pulses[] = {
+ SENSOR_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 0),
+ SENSOR_ATTR(fan2_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 1),
+ SENSOR_ATTR(fan3_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 2),
+ SENSOR_ATTR(fan4_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 3),
+ SENSOR_ATTR(fan5_pulses, S_IWUSR | S_IRUGO, show_fan_pulses,
+ store_fan_pulses, 4),
+};
+
+static struct sensor_device_attribute sda_fan_div[] = {
+ SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
+ SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
+ SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
+ SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
+ SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
+};
+
+static ssize_t
+show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
+}
+
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->temp[index][nr]));
+}
+
+static ssize_t
+store_temp(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ int err;
+ long val;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ data->temp[index][nr] = LM75_TEMP_TO_REG(val);
+ nct6775_write_temp(data, data->reg_temp[index][nr],
+ data->temp[index][nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_temp_offset(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+ return sprintf(buf, "%d\n", data->temp_offset[sattr->index] * 1000);
+}
+
+static ssize_t
+store_temp_offset(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+ mutex_lock(&data->update_lock);
+ data->temp_offset[nr] = val;
+ nct6775_write_value(data, data->REG_TEMP_OFFSET[nr], val);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
+static ssize_t
+store_temp_type(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ u8 vbat, diode, bit;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (val != 1 && val != 3 && val != 4)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ data->temp_type[nr] = val;
+ vbat = nct6775_read_value(data, data->REG_VBAT) & ~(0x02 << nr);
+ diode = nct6775_read_value(data, data->REG_DIODE) & ~(0x02 << nr);
+ bit = 0x02 << nr;
+ switch (val) {
+ case 1: /* CPU diode (diode, current mode) */
+ vbat |= bit;
+ diode |= bit;
+ break;
+ case 3: /* diode, voltage mode */
+ vbat |= bit;
+ break;
+ case 4: /* thermistor */
+ break;
+ }
+ nct6775_write_value(data, data->REG_VBAT, vbat);
+ nct6775_write_value(data, data->REG_DIODE, diode);
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute_2 sda_temp_input[] = {
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0),
+ SENSOR_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0),
+ SENSOR_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0),
+ SENSOR_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0),
+ SENSOR_ATTR_2(temp7_input, S_IRUGO, show_temp, NULL, 6, 0),
+ SENSOR_ATTR_2(temp8_input, S_IRUGO, show_temp, NULL, 7, 0),
+ SENSOR_ATTR_2(temp9_input, S_IRUGO, show_temp, NULL, 8, 0),
+ SENSOR_ATTR_2(temp10_input, S_IRUGO, show_temp, NULL, 9, 0),
+};
+
+static struct sensor_device_attribute sda_temp_label[] = {
+ SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
+ SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
+ SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
+ SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
+ SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
+ SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
+ SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
+ SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
+ SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
+ SENSOR_ATTR(temp10_label, S_IRUGO, show_temp_label, NULL, 9),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max[] = {
+ SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 0, 1),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 1, 1),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 2, 1),
+ SENSOR_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 3, 1),
+ SENSOR_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 4, 1),
+ SENSOR_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 5, 1),
+ SENSOR_ATTR_2(temp7_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 6, 1),
+ SENSOR_ATTR_2(temp8_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 7, 1),
+ SENSOR_ATTR_2(temp9_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 8, 1),
+ SENSOR_ATTR_2(temp10_max, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 9, 1),
+};
+
+static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
+ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 0, 2),
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 1, 2),
+ SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 2, 2),
+ SENSOR_ATTR_2(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 3, 2),
+ SENSOR_ATTR_2(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 4, 2),
+ SENSOR_ATTR_2(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 5, 2),
+ SENSOR_ATTR_2(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 6, 2),
+ SENSOR_ATTR_2(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 7, 2),
+ SENSOR_ATTR_2(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 8, 2),
+ SENSOR_ATTR_2(temp10_max_hyst, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 9, 2),
+};
+
+static struct sensor_device_attribute_2 sda_temp_crit[] = {
+ SENSOR_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 0, 3),
+ SENSOR_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 1, 3),
+ SENSOR_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 2, 3),
+ SENSOR_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 3, 3),
+ SENSOR_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 4, 3),
+ SENSOR_ATTR_2(temp6_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 5, 3),
+ SENSOR_ATTR_2(temp7_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 6, 3),
+ SENSOR_ATTR_2(temp8_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 7, 3),
+ SENSOR_ATTR_2(temp9_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 8, 3),
+ SENSOR_ATTR_2(temp10_crit, S_IRUGO | S_IWUSR, show_temp, store_temp,
+ 9, 3),
+};
+
+static struct sensor_device_attribute sda_temp_offset[] = {
+ SENSOR_ATTR(temp1_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 0),
+ SENSOR_ATTR(temp2_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 1),
+ SENSOR_ATTR(temp3_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 2),
+ SENSOR_ATTR(temp4_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 3),
+ SENSOR_ATTR(temp5_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 4),
+ SENSOR_ATTR(temp6_offset, S_IRUGO | S_IWUSR, show_temp_offset,
+ store_temp_offset, 5),
+};
+
+static struct sensor_device_attribute sda_temp_type[] = {
+ SENSOR_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 0),
+ SENSOR_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 1),
+ SENSOR_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 2),
+ SENSOR_ATTR(temp4_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 3),
+ SENSOR_ATTR(temp5_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 4),
+ SENSOR_ATTR(temp6_type, S_IRUGO | S_IWUSR, show_temp_type,
+ store_temp_type, 5),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 1),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 2),
+ SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 3),
+ SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 4),
+ SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
+ TEMP_ALARM_BASE + 5),
+};
+
+#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
+
+static ssize_t
+show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+ return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]);
+}
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ u8 reg;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (val > 1)
+ return -EINVAL;
+
+ /* Setting DC mode is not supported for all chips/channels */
+ if (data->REG_PWM_MODE[nr] == 0) {
+ if (val)
+ return -EINVAL;
+ return count;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->pwm_mode[nr] = val;
+ reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
+ reg &= ~data->PWM_MODE_MASK[nr];
+ if (val)
+ reg |= data->PWM_MODE_MASK[nr];
+ nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ int pwm;
+
+ /*
+ * For automatic fan control modes, show current pwm readings.
+ * Otherwise, show the configured value.
+ */
+ if (index == 0 && data->pwm_enable[nr] > manual)
+ pwm = nct6775_read_value(data, data->REG_PWM_READ[nr]);
+ else
+ pwm = data->pwm[index][nr];
+
+ return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ unsigned long val;
+ int minval[7] = { 0, 1, 1, data->pwm[2][nr], 0, 0, 0 };
+ int maxval[7]
+ = { 255, 255, data->pwm[3][nr] ? : 255, 255, 255, 255, 255 };
+ int err;
+ u8 reg;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ val = clamp_val(val, minval[index], maxval[index]);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[index][nr] = val;
+ nct6775_write_value(data, data->REG_PWM[index][nr], val);
+ if (index == 2) { /* floor: disable if val == 0 */
+ reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+ reg &= 0x7f;
+ if (val)
+ reg |= 0x80;
+ nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* Returns 0 if OK, -EINVAL otherwise */
+static int check_trip_points(struct nct6775_data *data, int nr)
+{
+ int i;
+
+ for (i = 0; i < data->auto_pwm_num - 1; i++) {
+ if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
+ return -EINVAL;
+ }
+ for (i = 0; i < data->auto_pwm_num - 1; i++) {
+ if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
+ return -EINVAL;
+ }
+ /* validate critical temperature and pwm if enabled (pwm > 0) */
+ if (data->auto_pwm[nr][data->auto_pwm_num]) {
+ if (data->auto_temp[nr][data->auto_pwm_num - 1] >
+ data->auto_temp[nr][data->auto_pwm_num] ||
+ data->auto_pwm[nr][data->auto_pwm_num - 1] >
+ data->auto_pwm[nr][data->auto_pwm_num])
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void pwm_update_registers(struct nct6775_data *data, int nr)
+{
+ u8 reg;
+
+ switch (data->pwm_enable[nr]) {
+ case off:
+ case manual:
+ break;
+ case speed_cruise:
+ reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+ reg = (reg & ~data->tolerance_mask) |
+ (data->target_speed_tolerance[nr] & data->tolerance_mask);
+ nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+ nct6775_write_value(data, data->REG_TARGET[nr],
+ data->target_speed[nr] & 0xff);
+ if (data->REG_TOLERANCE_H) {
+ reg = (data->target_speed[nr] >> 8) & 0x0f;
+ reg |= (data->target_speed_tolerance[nr] & 0x38) << 1;
+ nct6775_write_value(data,
+ data->REG_TOLERANCE_H[nr],
+ reg);
+ }
+ break;
+ case thermal_cruise:
+ nct6775_write_value(data, data->REG_TARGET[nr],
+ data->target_temp[nr]);
+ /* intentional */
+ default:
+ reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+ reg = (reg & ~data->tolerance_mask) |
+ data->temp_tolerance[0][nr];
+ nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+ break;
+ }
+}
+
+static ssize_t
+show_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+ return sprintf(buf, "%d\n", data->pwm_enable[sattr->index]);
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ u16 reg;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (val > sf4)
+ return -EINVAL;
+
+ if (val == sf3 && data->kind != nct6775)
+ return -EINVAL;
+
+ if (val == sf4 && check_trip_points(data, nr)) {
+ dev_err(dev, "Inconsistent trip points, not switching to SmartFan IV mode\n");
+ dev_err(dev, "Adjust trip points and try again\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->pwm_enable[nr] = val;
+ if (val == off) {
+ /*
+ * turn off pwm control: select manual mode, set pwm to maximum
+ */
+ data->pwm[0][nr] = 255;
+ nct6775_write_value(data, data->REG_PWM[0][nr], 255);
+ }
+ pwm_update_registers(data, nr);
+ reg = nct6775_read_value(data, data->REG_FAN_MODE[nr]);
+ reg &= 0x0f;
+ reg |= pwm_enable_to_reg(val) << 4;
+ nct6775_write_value(data, data->REG_FAN_MODE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
+{
+ int i, sel = 0;
+
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ if (src == data->temp_src[i]) {
+ sel = i + 1;
+ break;
+ }
+ }
+
+ return sprintf(buf, "%d\n", sel);
+}
+
+static ssize_t
+show_pwm_temp_sel(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int index = sattr->index;
+
+ return show_pwm_temp_sel_common(data, buf, data->pwm_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err, reg, src;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val == 0 || val > NUM_TEMP)
+ return -EINVAL;
+ if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1])
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ src = data->temp_src[val - 1];
+ data->pwm_temp_sel[nr] = src;
+ reg = nct6775_read_value(data, data->REG_TEMP_SEL[nr]);
+ reg &= 0xe0;
+ reg |= src;
+ nct6775_write_value(data, data->REG_TEMP_SEL[nr], reg);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int index = sattr->index;
+
+ return show_pwm_temp_sel_common(data, buf,
+ data->pwm_weight_temp_sel[index]);
+}
+
+static ssize_t
+store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err, reg, src;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val > NUM_TEMP)
+ return -EINVAL;
+ if (val && (!(data->have_temp & (1 << (val - 1))) ||
+ !data->temp_src[val - 1]))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (val) {
+ src = data->temp_src[val - 1];
+ data->pwm_weight_temp_sel[nr] = src;
+ reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+ reg &= 0xe0;
+ reg |= (src | 0x80);
+ nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+ } else {
+ data->pwm_weight_temp_sel[nr] = 0;
+ reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[nr]);
+ reg &= 0x7f;
+ nct6775_write_value(data, data->REG_WEIGHT_TEMP_SEL[nr], reg);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t
+show_target_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+
+ return sprintf(buf, "%d\n", data->target_temp[sattr->index] * 1000);
+}
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0,
+ data->target_temp_mask);
+
+ mutex_lock(&data->update_lock);
+ data->target_temp[nr] = val;
+ pwm_update_registers(data, nr);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_target_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+
+ return sprintf(buf, "%d\n",
+ fan_from_reg16(data->target_speed[nr],
+ data->fan_div[nr]));
+}
+
+static ssize_t
+store_target_speed(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ u16 speed;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp_val(val, 0, 1350000U);
+ speed = fan_to_reg(val, data->fan_div[nr]);
+
+ mutex_lock(&data->update_lock);
+ data->target_speed[nr] = speed;
+ pwm_update_registers(data, nr);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_temp_tolerance(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n", data->temp_tolerance[index][nr] * 1000);
+}
+
+static ssize_t
+store_temp_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ /* Limit tolerance as needed */
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, data->tolerance_mask);
+
+ mutex_lock(&data->update_lock);
+ data->temp_tolerance[index][nr] = val;
+ if (index)
+ pwm_update_registers(data, nr);
+ else
+ nct6775_write_value(data,
+ data->REG_CRITICAL_TEMP_TOLERANCE[nr],
+ val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * Fan speed tolerance is a tricky beast, since the associated register is
+ * a tick counter, but the value is reported and configured as rpm.
+ * Compute resulting low and high rpm values and report the difference.
+ */
+static ssize_t
+show_speed_tolerance(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ int low = data->target_speed[nr] - data->target_speed_tolerance[nr];
+ int high = data->target_speed[nr] + data->target_speed_tolerance[nr];
+ int tolerance;
+
+ if (low <= 0)
+ low = 1;
+ if (high > 0xffff)
+ high = 0xffff;
+ if (high < low)
+ high = low;
+
+ tolerance = (fan_from_reg16(low, data->fan_div[nr])
+ - fan_from_reg16(high, data->fan_div[nr])) / 2;
+
+ return sprintf(buf, "%d\n", tolerance);
+}
+
+static ssize_t
+store_speed_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ int nr = sattr->index;
+ unsigned long val;
+ int err;
+ int low, high;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ high = fan_from_reg16(data->target_speed[nr],
+ data->fan_div[nr]) + val;
+ low = fan_from_reg16(data->target_speed[nr],
+ data->fan_div[nr]) - val;
+ if (low <= 0)
+ low = 1;
+ if (high < low)
+ high = low;
+
+ val = (fan_to_reg(low, data->fan_div[nr]) -
+ fan_to_reg(high, data->fan_div[nr])) / 2;
+
+ /* Limit tolerance as needed */
+ val = clamp_val(val, 0, data->speed_tolerance_limit);
+
+ mutex_lock(&data->update_lock);
+ data->target_speed_tolerance[nr] = val;
+ pwm_update_registers(data, nr);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 2);
+static SENSOR_DEVICE_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 3);
+static SENSOR_DEVICE_ATTR(pwm5_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 3);
+static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 0);
+static SENSOR_DEVICE_ATTR(pwm2_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 1);
+static SENSOR_DEVICE_ATTR(pwm3_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 2);
+static SENSOR_DEVICE_ATTR(pwm4_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 3);
+static SENSOR_DEVICE_ATTR(pwm5_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_temp_sel, store_pwm_temp_sel, 4);
+
+static SENSOR_DEVICE_ATTR(pwm1_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 3);
+static SENSOR_DEVICE_ATTR(pwm5_target_temp, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 4);
+
+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, show_target_speed,
+ store_target_speed, 0);
+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, show_target_speed,
+ store_target_speed, 1);
+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, show_target_speed,
+ store_target_speed, 2);
+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, show_target_speed,
+ store_target_speed, 3);
+static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, show_target_speed,
+ store_target_speed, 4);
+
+static SENSOR_DEVICE_ATTR(fan1_tolerance, S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 0);
+static SENSOR_DEVICE_ATTR(fan2_tolerance, S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 1);
+static SENSOR_DEVICE_ATTR(fan3_tolerance, S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 2);
+static SENSOR_DEVICE_ATTR(fan4_tolerance, S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 3);
+static SENSOR_DEVICE_ATTR(fan5_tolerance, S_IWUSR | S_IRUGO,
+ show_speed_tolerance, store_speed_tolerance, 4);
+
+/* Smart Fan registers */
+
+static ssize_t
+show_weight_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n", data->weight_temp[index][nr] * 1000);
+}
+
+static ssize_t
+store_weight_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->weight_temp[index][nr] = val;
+ nct6775_write_value(data, data->REG_WEIGHT_TEMP[index][nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_weight_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+ 0);
+static SENSOR_DEVICE_ATTR(pwm2_weight_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+ 1);
+static SENSOR_DEVICE_ATTR(pwm3_weight_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+ 2);
+static SENSOR_DEVICE_ATTR(pwm4_weight_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+ 3);
+static SENSOR_DEVICE_ATTR(pwm5_weight_temp_sel, S_IWUSR | S_IRUGO,
+ show_pwm_weight_temp_sel, store_pwm_weight_temp_sel,
+ 4);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_tol, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_temp_step_base, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_temp_step_base, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_temp_step_base, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_temp_step_base, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_temp_step_base, S_IWUSR | S_IRUGO,
+ show_weight_temp, store_weight_temp, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_weight_duty_step, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 0, 5);
+static SENSOR_DEVICE_ATTR_2(pwm2_weight_duty_step, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 1, 5);
+static SENSOR_DEVICE_ATTR_2(pwm3_weight_duty_step, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 2, 5);
+static SENSOR_DEVICE_ATTR_2(pwm4_weight_duty_step, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 3, 5);
+static SENSOR_DEVICE_ATTR_2(pwm5_weight_duty_step, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 4, 5);
+
+/* duty_base is not supported on all chips */
+static struct sensor_device_attribute_2 sda_weight_duty_base[] = {
+ SENSOR_ATTR_2(pwm1_weight_duty_base, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 0, 6),
+ SENSOR_ATTR_2(pwm2_weight_duty_base, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 1, 6),
+ SENSOR_ATTR_2(pwm3_weight_duty_base, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 2, 6),
+ SENSOR_ATTR_2(pwm4_weight_duty_base, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 3, 6),
+ SENSOR_ATTR_2(pwm5_weight_duty_base, S_IWUSR | S_IRUGO,
+ show_pwm, store_pwm, 4, 6),
+};
+
+static ssize_t
+show_fan_time(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+
+ return sprintf(buf, "%d\n",
+ step_time_from_reg(data->fan_time[index][nr],
+ data->pwm_mode[nr]));
+}
+
+static ssize_t
+store_fan_time(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int index = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = step_time_to_reg(val, data->pwm_mode[nr]);
+ mutex_lock(&data->update_lock);
+ data->fan_time[index][nr] = val;
+ nct6775_write_value(data, data->REG_FAN_TIME[index][nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_stop_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_up_time, S_IWUSR | S_IRUGO, show_fan_time,
+ store_fan_time, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_step_down_time, S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_step_down_time, S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_step_down_time, S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_step_down_time, S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_step_down_time, S_IWUSR | S_IRUGO,
+ show_fan_time, store_fan_time, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_start, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_start, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_start, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_start, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_start, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 4, 1);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_floor, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_floor, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_floor, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm4_floor, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 3, 2);
+static SENSOR_DEVICE_ATTR_2(pwm5_floor, S_IWUSR | S_IRUGO, show_pwm,
+ store_pwm, 4, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm4_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 3, 0);
+static SENSOR_DEVICE_ATTR_2(pwm5_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 4, 0);
+
+static SENSOR_DEVICE_ATTR_2(pwm1_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm4_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 3, 1);
+static SENSOR_DEVICE_ATTR_2(pwm5_crit_temp_tolerance, S_IWUSR | S_IRUGO,
+ show_temp_tolerance, store_temp_tolerance, 4, 1);
+
+/* pwm_max is not supported on all chips */
+static struct sensor_device_attribute_2 sda_pwm_max[] = {
+ SENSOR_ATTR_2(pwm1_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 0, 3),
+ SENSOR_ATTR_2(pwm2_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 1, 3),
+ SENSOR_ATTR_2(pwm3_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 2, 3),
+ SENSOR_ATTR_2(pwm4_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 3, 3),
+ SENSOR_ATTR_2(pwm5_max, S_IWUSR | S_IRUGO, show_pwm, store_pwm,
+ 4, 3),
+};
+
+/* pwm_step is not supported on all chips */
+static struct sensor_device_attribute_2 sda_pwm_step[] = {
+ SENSOR_ATTR_2(pwm1_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0, 4),
+ SENSOR_ATTR_2(pwm2_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1, 4),
+ SENSOR_ATTR_2(pwm3_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2, 4),
+ SENSOR_ATTR_2(pwm4_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3, 4),
+ SENSOR_ATTR_2(pwm5_step, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 4, 4),
+};
+
+static struct attribute *nct6775_attributes_pwm[5][20] = {
+ {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm1_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm1_crit_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm1_target_temp.dev_attr.attr,
+ &sensor_dev_attr_fan1_target.dev_attr.attr,
+ &sensor_dev_attr_fan1_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
+ &sensor_dev_attr_pwm1_step_up_time.dev_attr.attr,
+ &sensor_dev_attr_pwm1_step_down_time.dev_attr.attr,
+ &sensor_dev_attr_pwm1_start.dev_attr.attr,
+ &sensor_dev_attr_pwm1_floor.dev_attr.attr,
+ &sensor_dev_attr_pwm1_weight_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm1_weight_temp_step.dev_attr.attr,
+ &sensor_dev_attr_pwm1_weight_temp_step_tol.dev_attr.attr,
+ &sensor_dev_attr_pwm1_weight_temp_step_base.dev_attr.attr,
+ &sensor_dev_attr_pwm1_weight_duty_step.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm2_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm2_crit_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm2_target_temp.dev_attr.attr,
+ &sensor_dev_attr_fan2_target.dev_attr.attr,
+ &sensor_dev_attr_fan2_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
+ &sensor_dev_attr_pwm2_step_up_time.dev_attr.attr,
+ &sensor_dev_attr_pwm2_step_down_time.dev_attr.attr,
+ &sensor_dev_attr_pwm2_start.dev_attr.attr,
+ &sensor_dev_attr_pwm2_floor.dev_attr.attr,
+ &sensor_dev_attr_pwm2_weight_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm2_weight_temp_step.dev_attr.attr,
+ &sensor_dev_attr_pwm2_weight_temp_step_tol.dev_attr.attr,
+ &sensor_dev_attr_pwm2_weight_temp_step_base.dev_attr.attr,
+ &sensor_dev_attr_pwm2_weight_duty_step.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm3_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm3_crit_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm3_target_temp.dev_attr.attr,
+ &sensor_dev_attr_fan3_target.dev_attr.attr,
+ &sensor_dev_attr_fan3_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
+ &sensor_dev_attr_pwm3_step_up_time.dev_attr.attr,
+ &sensor_dev_attr_pwm3_step_down_time.dev_attr.attr,
+ &sensor_dev_attr_pwm3_start.dev_attr.attr,
+ &sensor_dev_attr_pwm3_floor.dev_attr.attr,
+ &sensor_dev_attr_pwm3_weight_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm3_weight_temp_step.dev_attr.attr,
+ &sensor_dev_attr_pwm3_weight_temp_step_tol.dev_attr.attr,
+ &sensor_dev_attr_pwm3_weight_temp_step_base.dev_attr.attr,
+ &sensor_dev_attr_pwm3_weight_duty_step.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm4_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm4_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm4_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm4_crit_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm4_target_temp.dev_attr.attr,
+ &sensor_dev_attr_fan4_target.dev_attr.attr,
+ &sensor_dev_attr_fan4_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
+ &sensor_dev_attr_pwm4_step_up_time.dev_attr.attr,
+ &sensor_dev_attr_pwm4_step_down_time.dev_attr.attr,
+ &sensor_dev_attr_pwm4_start.dev_attr.attr,
+ &sensor_dev_attr_pwm4_floor.dev_attr.attr,
+ &sensor_dev_attr_pwm4_weight_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm4_weight_temp_step.dev_attr.attr,
+ &sensor_dev_attr_pwm4_weight_temp_step_tol.dev_attr.attr,
+ &sensor_dev_attr_pwm4_weight_temp_step_base.dev_attr.attr,
+ &sensor_dev_attr_pwm4_weight_duty_step.dev_attr.attr,
+ NULL
+ },
+ {
+ &sensor_dev_attr_pwm5.dev_attr.attr,
+ &sensor_dev_attr_pwm5_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm5_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm5_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm5_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm5_crit_temp_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm5_target_temp.dev_attr.attr,
+ &sensor_dev_attr_fan5_target.dev_attr.attr,
+ &sensor_dev_attr_fan5_tolerance.dev_attr.attr,
+ &sensor_dev_attr_pwm5_stop_time.dev_attr.attr,
+ &sensor_dev_attr_pwm5_step_up_time.dev_attr.attr,
+ &sensor_dev_attr_pwm5_step_down_time.dev_attr.attr,
+ &sensor_dev_attr_pwm5_start.dev_attr.attr,
+ &sensor_dev_attr_pwm5_floor.dev_attr.attr,
+ &sensor_dev_attr_pwm5_weight_temp_sel.dev_attr.attr,
+ &sensor_dev_attr_pwm5_weight_temp_step.dev_attr.attr,
+ &sensor_dev_attr_pwm5_weight_temp_step_tol.dev_attr.attr,
+ &sensor_dev_attr_pwm5_weight_temp_step_base.dev_attr.attr,
+ &sensor_dev_attr_pwm5_weight_duty_step.dev_attr.attr,
+ NULL
+ },
+};
+
+static const struct attribute_group nct6775_group_pwm[5] = {
+ { .attrs = nct6775_attributes_pwm[0] },
+ { .attrs = nct6775_attributes_pwm[1] },
+ { .attrs = nct6775_attributes_pwm[2] },
+ { .attrs = nct6775_attributes_pwm[3] },
+ { .attrs = nct6775_attributes_pwm[4] },
+};
+
+static ssize_t
+show_auto_pwm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n", data->auto_pwm[sattr->nr][sattr->index]);
+}
+
+static ssize_t
+store_auto_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int point = sattr->index;
+ unsigned long val;
+ int err;
+ u8 reg;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val > 255)
+ return -EINVAL;
+
+ if (point == data->auto_pwm_num) {
+ if (data->kind != nct6775 && !val)
+ return -EINVAL;
+ if (data->kind != nct6779 && val)
+ val = 0xff;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->auto_pwm[nr][point] = val;
+ if (point < data->auto_pwm_num) {
+ nct6775_write_value(data,
+ NCT6775_AUTO_PWM(data, nr, point),
+ data->auto_pwm[nr][point]);
+ } else {
+ switch (data->kind) {
+ case nct6775:
+ /* disable if needed (pwm == 0) */
+ reg = nct6775_read_value(data,
+ NCT6775_REG_CRITICAL_ENAB[nr]);
+ if (val)
+ reg |= 0x02;
+ else
+ reg &= ~0x02;
+ nct6775_write_value(data, NCT6775_REG_CRITICAL_ENAB[nr],
+ reg);
+ break;
+ case nct6776:
+ break; /* always enabled, nothing to do */
+ case nct6779:
+ nct6775_write_value(data, NCT6779_REG_CRITICAL_PWM[nr],
+ val);
+ reg = nct6775_read_value(data,
+ NCT6779_REG_CRITICAL_PWM_ENABLE[nr]);
+ if (val == 255)
+ reg &= ~0x01;
+ else
+ reg |= 0x01;
+ nct6775_write_value(data,
+ NCT6779_REG_CRITICAL_PWM_ENABLE[nr],
+ reg);
+ break;
+ }
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+show_auto_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int point = sattr->index;
+
+ /*
+ * We don't know for sure if the temperature is signed or unsigned.
+ * Assume it is unsigned.
+ */
+ return sprintf(buf, "%d\n", data->auto_temp[nr][point] * 1000);
+}
+
+static ssize_t
+store_auto_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int nr = sattr->nr;
+ int point = sattr->index;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
+ if (val > 255000)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->auto_temp[nr][point] = DIV_ROUND_CLOSEST(val, 1000);
+ if (point < data->auto_pwm_num) {
+ nct6775_write_value(data,
+ NCT6775_AUTO_TEMP(data, nr, point),
+ data->auto_temp[nr][point]);
+ } else {
+ nct6775_write_value(data, data->REG_CRITICAL_TEMP[nr],
+ data->auto_temp[nr][point]);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/*
+ * The number of auto-point trip points is chip dependent.
+ * Need to check support while generating/removing attribute files.
+ */
+static struct sensor_device_attribute_2 sda_auto_pwm_arrays[] = {
+ SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 1),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 1),
+ SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 2),
+ SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 2),
+ SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 3),
+ SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 3),
+ SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 4),
+ SENSOR_ATTR_2(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 4),
+ SENSOR_ATTR_2(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 5),
+ SENSOR_ATTR_2(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 5),
+ SENSOR_ATTR_2(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 0, 6),
+ SENSOR_ATTR_2(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 0, 6),
+
+ SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 0),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 0),
+ SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 2),
+ SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 2),
+ SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 3),
+ SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 3),
+ SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 4),
+ SENSOR_ATTR_2(pwm2_auto_point5_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 4),
+ SENSOR_ATTR_2(pwm2_auto_point6_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 5),
+ SENSOR_ATTR_2(pwm2_auto_point6_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 5),
+ SENSOR_ATTR_2(pwm2_auto_point7_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 1, 6),
+ SENSOR_ATTR_2(pwm2_auto_point7_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 1, 6),
+
+ SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 0),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 0),
+ SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 1),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 1),
+ SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 2),
+ SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 2),
+ SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 3),
+ SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 3),
+ SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 4),
+ SENSOR_ATTR_2(pwm3_auto_point5_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 4),
+ SENSOR_ATTR_2(pwm3_auto_point6_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 5),
+ SENSOR_ATTR_2(pwm3_auto_point6_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 5),
+ SENSOR_ATTR_2(pwm3_auto_point7_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 2, 6),
+ SENSOR_ATTR_2(pwm3_auto_point7_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 2, 6),
+
+ SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 0),
+ SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 0),
+ SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 1),
+ SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 1),
+ SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 2),
+ SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 2),
+ SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 3),
+ SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 3),
+ SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 4),
+ SENSOR_ATTR_2(pwm4_auto_point5_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 4),
+ SENSOR_ATTR_2(pwm4_auto_point6_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 5),
+ SENSOR_ATTR_2(pwm4_auto_point6_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 5),
+ SENSOR_ATTR_2(pwm4_auto_point7_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 3, 6),
+ SENSOR_ATTR_2(pwm4_auto_point7_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 3, 6),
+
+ SENSOR_ATTR_2(pwm5_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 0),
+ SENSOR_ATTR_2(pwm5_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 0),
+ SENSOR_ATTR_2(pwm5_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 1),
+ SENSOR_ATTR_2(pwm5_auto_point2_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 1),
+ SENSOR_ATTR_2(pwm5_auto_point3_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 2),
+ SENSOR_ATTR_2(pwm5_auto_point3_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 2),
+ SENSOR_ATTR_2(pwm5_auto_point4_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 3),
+ SENSOR_ATTR_2(pwm5_auto_point4_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 3),
+ SENSOR_ATTR_2(pwm5_auto_point5_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 4),
+ SENSOR_ATTR_2(pwm5_auto_point5_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 4),
+ SENSOR_ATTR_2(pwm5_auto_point6_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 5),
+ SENSOR_ATTR_2(pwm5_auto_point6_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 5),
+ SENSOR_ATTR_2(pwm5_auto_point7_pwm, S_IWUSR | S_IRUGO,
+ show_auto_pwm, store_auto_pwm, 4, 6),
+ SENSOR_ATTR_2(pwm5_auto_point7_temp, S_IWUSR | S_IRUGO,
+ show_auto_temp, store_auto_temp, 4, 6),
+};
+
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+/* Case open detection */
+
+static ssize_t
+clear_caseopen(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct nct6775_sio_data *sio_data = dev->platform_data;
+ int nr = to_sensor_dev_attr(attr)->index - INTRUSION_ALARM_BASE;
+ unsigned long val;
+ u8 reg;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val) || val != 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+
+ /*
+ * Use CR registers to clear caseopen status.
+ * The CR registers are the same for all chips, and not all chips
+ * support clearing the caseopen status through "regular" registers.
+ */
+ ret = superio_enter(sio_data->sioreg);
+ if (ret) {
+ count = ret;
+ goto error;
+ }
+
+ superio_select(sio_data->sioreg, NCT6775_LD_ACPI);
+ reg = superio_inb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr]);
+ reg |= NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+ superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+ reg &= ~NCT6775_CR_CASEOPEN_CLR_MASK[nr];
+ superio_outb(sio_data->sioreg, NCT6775_REG_CR_CASEOPEN_CLR[nr], reg);
+ superio_exit(sio_data->sioreg);
+
+ data->valid = false; /* Force cache refresh */
+error:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute sda_caseopen[] = {
+ SENSOR_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE),
+ SENSOR_ATTR(intrusion1_alarm, S_IWUSR | S_IRUGO, show_alarm,
+ clear_caseopen, INTRUSION_ALARM_BASE + 1),
+};
+
+/*
+ * Driver and device management
+ */
+
+static void nct6775_device_remove_files(struct device *dev)
+{
+ /*
+ * some entries in the following arrays may not have been used in
+ * device_create_file(), but device_remove_file() will ignore them
+ */
+ int i;
+ struct nct6775_data *data = dev_get_drvdata(dev);
+
+ for (i = 0; i < data->pwm_num; i++)
+ sysfs_remove_group(&dev->kobj, &nct6775_group_pwm[i]);
+
+ for (i = 0; i < ARRAY_SIZE(sda_pwm_max); i++)
+ device_remove_file(dev, &sda_pwm_max[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(sda_pwm_step); i++)
+ device_remove_file(dev, &sda_pwm_step[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(sda_weight_duty_base); i++)
+ device_remove_file(dev, &sda_weight_duty_base[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++)
+ device_remove_file(dev, &sda_auto_pwm_arrays[i].dev_attr);
+
+ for (i = 0; i < data->in_num; i++)
+ sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]);
+
+ for (i = 0; i < 5; i++) {
+ device_remove_file(dev, &sda_fan_input[i].dev_attr);
+ device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
+ device_remove_file(dev, &sda_fan_div[i].dev_attr);
+ device_remove_file(dev, &sda_fan_min[i].dev_attr);
+ device_remove_file(dev, &sda_fan_pulses[i].dev_attr);
+ }
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ device_remove_file(dev, &sda_temp_input[i].dev_attr);
+ device_remove_file(dev, &sda_temp_label[i].dev_attr);
+ device_remove_file(dev, &sda_temp_max[i].dev_attr);
+ device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
+ device_remove_file(dev, &sda_temp_crit[i].dev_attr);
+ if (!(data->have_temp_fixed & (1 << i)))
+ continue;
+ device_remove_file(dev, &sda_temp_type[i].dev_attr);
+ device_remove_file(dev, &sda_temp_offset[i].dev_attr);
+ if (i >= NUM_TEMP_ALARM)
+ continue;
+ device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
+ }
+
+ device_remove_file(dev, &sda_caseopen[0].dev_attr);
+ device_remove_file(dev, &sda_caseopen[1].dev_attr);
+
+ device_remove_file(dev, &dev_attr_name);
+ device_remove_file(dev, &dev_attr_cpu0_vid);
+}
+
+/* Get the monitoring functions started */
+static inline void nct6775_init_device(struct nct6775_data *data)
+{
+ int i;
+ u8 tmp, diode;
+
+ /* Start monitoring if needed */
+ if (data->REG_CONFIG) {
+ tmp = nct6775_read_value(data, data->REG_CONFIG);
+ if (!(tmp & 0x01))
+ nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01);
+ }
+
+ /* Enable temperature sensors if needed */
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ if (!data->reg_temp_config[i])
+ continue;
+ tmp = nct6775_read_value(data, data->reg_temp_config[i]);
+ if (tmp & 0x01)
+ nct6775_write_value(data, data->reg_temp_config[i],
+ tmp & 0xfe);
+ }
+
+ /* Enable VBAT monitoring if needed */
+ tmp = nct6775_read_value(data, data->REG_VBAT);
+ if (!(tmp & 0x01))
+ nct6775_write_value(data, data->REG_VBAT, tmp | 0x01);
+
+ diode = nct6775_read_value(data, data->REG_DIODE);
+
+ for (i = 0; i < data->temp_fixed_num; i++) {
+ if (!(data->have_temp_fixed & (1 << i)))
+ continue;
+ if ((tmp & (0x02 << i))) /* diode */
+ data->temp_type[i] = 3 - ((diode >> i) & 0x02);
+ else /* thermistor */
+ data->temp_type[i] = 4;
+ }
+}
+
+static int
+nct6775_check_fan_inputs(const struct nct6775_sio_data *sio_data,
+ struct nct6775_data *data)
+{
+ int regval;
+ bool fan3pin, fan3min, fan4pin, fan4min, fan5pin;
+ bool pwm3pin, pwm4pin, pwm5pin;
+ int ret;
+
+ ret = superio_enter(sio_data->sioreg);
+ if (ret)
+ return ret;
+
+ /* fan4 and fan5 share some pins with the GPIO and serial flash */
+ if (data->kind == nct6775) {
+ regval = superio_inb(sio_data->sioreg, 0x2c);
+
+ fan3pin = regval & (1 << 6);
+ fan3min = fan3pin;
+ pwm3pin = regval & (1 << 7);
+
+ /* On NCT6775, fan4 shares pins with the fdc interface */
+ fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
+ fan4min = 0;
+ fan5pin = 0;
+ pwm4pin = 0;
+ pwm5pin = 0;
+ } else if (data->kind == nct6776) {
+ bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80;
+
+ superio_select(sio_data->sioreg, NCT6775_LD_HWM);
+ regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE);
+
+ if (regval & 0x80)
+ fan3pin = gpok;
+ else
+ fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
+
+ if (regval & 0x40)
+ fan4pin = gpok;
+ else
+ fan4pin = superio_inb(sio_data->sioreg, 0x1C) & 0x01;
+
+ if (regval & 0x20)
+ fan5pin = gpok;
+ else
+ fan5pin = superio_inb(sio_data->sioreg, 0x1C) & 0x02;
+
+ fan4min = fan4pin;
+ fan3min = fan3pin;
+ pwm3pin = fan3pin;
+ pwm4pin = 0;
+ pwm5pin = 0;
+ } else { /* NCT6779D */
+ regval = superio_inb(sio_data->sioreg, 0x1c);
+
+ fan3pin = !(regval & (1 << 5));
+ fan4pin = !(regval & (1 << 6));
+ fan5pin = !(regval & (1 << 7));
+
+ pwm3pin = !(regval & (1 << 0));
+ pwm4pin = !(regval & (1 << 1));
+ pwm5pin = !(regval & (1 << 2));
+
+ fan3min = fan3pin;
+ fan4min = fan4pin;
+ }
+
+ superio_exit(sio_data->sioreg);
+
+ data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
+ data->has_fan |= fan3pin << 2;
+ data->has_fan_min |= fan3min << 2;
+
+ data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
+ data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
+
+ data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | (pwm5pin << 4);
+
+ return 0;
+}
+
+static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
+ int *available, int *mask)
+{
+ int i;
+ u8 src;
+
+ for (i = 0; i < data->pwm_num && *available; i++) {
+ int index;
+
+ if (!regp[i])
+ continue;
+ src = nct6775_read_value(data, regp[i]);
+ src &= 0x1f;
+ if (!src || (*mask & (1 << src)))
+ continue;
+ if (src >= data->temp_label_num ||
+ !strlen(data->temp_label[src]))
+ continue;
+
+ index = __ffs(*available);
+ nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
+ *available &= ~(1 << index);
+ *mask |= 1 << src;
+ }
+}
+
+static int nct6775_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct nct6775_sio_data *sio_data = dev->platform_data;
+ struct nct6775_data *data;
+ struct resource *res;
+ int i, s, err = 0;
+ int src, mask, available;
+ const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config;
+ const u16 *reg_temp_alternate, *reg_temp_crit;
+ int num_reg_temp;
+ bool have_vid = false;
+ u8 cr2a;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
+ DRVNAME))
+ return -EBUSY;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->kind = sio_data->kind;
+ data->addr = res->start;
+ mutex_init(&data->update_lock);
+ data->name = nct6775_device_names[data->kind];
+ data->bank = 0xff; /* Force initial bank selection */
+ platform_set_drvdata(pdev, data);
+
+ switch (data->kind) {
+ case nct6775:
+ data->in_num = 9;
+ data->pwm_num = 3;
+ data->auto_pwm_num = 6;
+ data->has_fan_div = true;
+ data->temp_fixed_num = 3;
+
+ data->ALARM_BITS = NCT6775_ALARM_BITS;
+
+ data->fan_from_reg = fan_from_reg16;
+ data->fan_from_reg_min = fan_from_reg8;
+ data->target_temp_mask = 0x7f;
+ data->tolerance_mask = 0x0f;
+ data->speed_tolerance_limit = 15;
+
+ data->temp_label = nct6775_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6775_temp_label);
+
+ data->REG_CONFIG = NCT6775_REG_CONFIG;
+ data->REG_VBAT = NCT6775_REG_VBAT;
+ data->REG_DIODE = NCT6775_REG_DIODE;
+ data->REG_VIN = NCT6775_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6775_REG_FAN;
+ data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6775_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6775_REG_FAN_PULSES;
+ data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+ data->REG_PWM[0] = NCT6775_REG_PWM;
+ data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[3] = NCT6775_REG_FAN_MAX_OUTPUT;
+ data->REG_PWM[4] = NCT6775_REG_FAN_STEP_OUTPUT;
+ data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6775_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6775_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE
+ = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6775_REG_ALARM;
+
+ reg_temp = NCT6775_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+ reg_temp_over = NCT6775_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+ reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6775_REG_TEMP_CRIT;
+
+ break;
+ case nct6776:
+ data->in_num = 9;
+ data->pwm_num = 3;
+ data->auto_pwm_num = 4;
+ data->has_fan_div = false;
+ data->temp_fixed_num = 3;
+
+ data->ALARM_BITS = NCT6776_ALARM_BITS;
+
+ data->fan_from_reg = fan_from_reg13;
+ data->fan_from_reg_min = fan_from_reg13;
+ data->target_temp_mask = 0xff;
+ data->tolerance_mask = 0x07;
+ data->speed_tolerance_limit = 63;
+
+ data->temp_label = nct6776_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6776_temp_label);
+
+ data->REG_CONFIG = NCT6775_REG_CONFIG;
+ data->REG_VBAT = NCT6775_REG_VBAT;
+ data->REG_DIODE = NCT6775_REG_DIODE;
+ data->REG_VIN = NCT6775_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6775_REG_FAN;
+ data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6776_REG_FAN_PULSES;
+ data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+ data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+ data->REG_PWM[0] = NCT6775_REG_PWM;
+ data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+ data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE
+ = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_TEMP_OFFSET = NCT6775_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6775_REG_ALARM;
+
+ reg_temp = NCT6775_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP);
+ reg_temp_over = NCT6775_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6775_REG_TEMP_HYST;
+ reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6776_REG_TEMP_CRIT;
+
+ break;
+ case nct6779:
+ data->in_num = 15;
+ data->pwm_num = 5;
+ data->auto_pwm_num = 4;
+ data->has_fan_div = false;
+ data->temp_fixed_num = 6;
+
+ data->ALARM_BITS = NCT6779_ALARM_BITS;
+
+ data->fan_from_reg = fan_from_reg13;
+ data->fan_from_reg_min = fan_from_reg13;
+ data->target_temp_mask = 0xff;
+ data->tolerance_mask = 0x07;
+ data->speed_tolerance_limit = 63;
+
+ data->temp_label = nct6779_temp_label;
+ data->temp_label_num = ARRAY_SIZE(nct6779_temp_label);
+
+ data->REG_CONFIG = NCT6775_REG_CONFIG;
+ data->REG_VBAT = NCT6775_REG_VBAT;
+ data->REG_DIODE = NCT6775_REG_DIODE;
+ data->REG_VIN = NCT6779_REG_IN;
+ data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN;
+ data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX;
+ data->REG_TARGET = NCT6775_REG_TARGET;
+ data->REG_FAN = NCT6779_REG_FAN;
+ data->REG_FAN_MODE = NCT6775_REG_FAN_MODE;
+ data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
+ data->REG_FAN_PULSES = NCT6779_REG_FAN_PULSES;
+ data->REG_FAN_TIME[0] = NCT6775_REG_FAN_STOP_TIME;
+ data->REG_FAN_TIME[1] = NCT6775_REG_FAN_STEP_UP_TIME;
+ data->REG_FAN_TIME[2] = NCT6775_REG_FAN_STEP_DOWN_TIME;
+ data->REG_TOLERANCE_H = NCT6776_REG_TOLERANCE_H;
+ data->REG_PWM[0] = NCT6775_REG_PWM;
+ data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT;
+ data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT;
+ data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP;
+ data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE;
+ data->REG_PWM_READ = NCT6775_REG_PWM_READ;
+ data->REG_PWM_MODE = NCT6776_REG_PWM_MODE;
+ data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK;
+ data->REG_AUTO_TEMP = NCT6775_REG_AUTO_TEMP;
+ data->REG_AUTO_PWM = NCT6775_REG_AUTO_PWM;
+ data->REG_CRITICAL_TEMP = NCT6775_REG_CRITICAL_TEMP;
+ data->REG_CRITICAL_TEMP_TOLERANCE
+ = NCT6775_REG_CRITICAL_TEMP_TOLERANCE;
+ data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET;
+ data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE;
+ data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL;
+ data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL;
+ data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP;
+ data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL;
+ data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE;
+ data->REG_ALARM = NCT6779_REG_ALARM;
+
+ reg_temp = NCT6779_REG_TEMP;
+ num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
+ reg_temp_over = NCT6779_REG_TEMP_OVER;
+ reg_temp_hyst = NCT6779_REG_TEMP_HYST;
+ reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
+ reg_temp_crit = NCT6779_REG_TEMP_CRIT;
+
+ break;
+ default:
+ return -ENODEV;
+ }
+ data->have_in = (1 << data->in_num) - 1;
+ data->have_temp = 0;
+
+ /*
+ * On some boards, not all available temperature sources are monitored,
+ * even though some of the monitoring registers are unused.
+ * Get list of unused monitoring registers, then detect if any fan
+ * controls are configured to use unmonitored temperature sources.
+ * If so, assign the unmonitored temperature sources to available
+ * monitoring registers.
+ */
+ mask = 0;
+ available = 0;
+ for (i = 0; i < num_reg_temp; i++) {
+ if (reg_temp[i] == 0)
+ continue;
+
+ src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+ if (!src || (mask & (1 << src)))
+ available |= 1 << i;
+
+ mask |= 1 << src;
+ }
+
+ /*
+ * Now find unmonitored temperature registers and enable monitoring
+ * if additional monitoring registers are available.
+ */
+ add_temp_sensors(data, data->REG_TEMP_SEL, &available, &mask);
+ add_temp_sensors(data, data->REG_WEIGHT_TEMP_SEL, &available, &mask);
+
+ mask = 0;
+ s = NUM_TEMP_FIXED; /* First dynamic temperature attribute */
+ for (i = 0; i < num_reg_temp; i++) {
+ if (reg_temp[i] == 0)
+ continue;
+
+ src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
+ if (!src || (mask & (1 << src)))
+ continue;
+
+ if (src >= data->temp_label_num ||
+ !strlen(data->temp_label[src])) {
+ dev_info(dev,
+ "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
+ src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
+ continue;
+ }
+
+ mask |= 1 << src;
+
+ /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
+ if (src <= data->temp_fixed_num) {
+ data->have_temp |= 1 << (src - 1);
+ data->have_temp_fixed |= 1 << (src - 1);
+ data->reg_temp[0][src - 1] = reg_temp[i];
+ data->reg_temp[1][src - 1] = reg_temp_over[i];
+ data->reg_temp[2][src - 1] = reg_temp_hyst[i];
+ data->reg_temp_config[src - 1] = reg_temp_config[i];
+ data->temp_src[src - 1] = src;
+ continue;
+ }
+
+ if (s >= NUM_TEMP)
+ continue;
+
+ /* Use dynamic index for other sources */
+ data->have_temp |= 1 << s;
+ data->reg_temp[0][s] = reg_temp[i];
+ data->reg_temp[1][s] = reg_temp_over[i];
+ data->reg_temp[2][s] = reg_temp_hyst[i];
+ data->reg_temp_config[s] = reg_temp_config[i];
+ if (reg_temp_crit[src - 1])
+ data->reg_temp[3][s] = reg_temp_crit[src - 1];
+
+ data->temp_src[s] = src;
+ s++;
+ }
+
+#ifdef USE_ALTERNATE
+ /*
+ * Go through the list of alternate temp registers and enable
+ * if possible.
+ * The temperature is already monitored if the respective bit in <mask>
+ * is set.
+ */
+ for (i = 0; i < data->temp_label_num - 1; i++) {
+ if (!reg_temp_alternate[i])
+ continue;
+ if (mask & (1 << (i + 1)))
+ continue;
+ if (i < data->temp_fixed_num) {
+ if (data->have_temp & (1 << i))
+ continue;
+ data->have_temp |= 1 << i;
+ data->have_temp_fixed |= 1 << i;
+ data->reg_temp[0][i] = reg_temp_alternate[i];
+ data->reg_temp[1][i] = reg_temp_over[i];
+ data->reg_temp[2][i] = reg_temp_hyst[i];
+ data->temp_src[i] = i + 1;
+ continue;
+ }
+
+ if (s >= NUM_TEMP) /* Abort if no more space */
+ break;
+
+ data->have_temp |= 1 << s;
+ data->reg_temp[0][s] = reg_temp_alternate[i];
+ data->temp_src[s] = i + 1;
+ s++;
+ }
+#endif /* USE_ALTERNATE */
+
+ /* Initialize the chip */
+ nct6775_init_device(data);
+
+ err = superio_enter(sio_data->sioreg);
+ if (err)
+ return err;
+
+ cr2a = superio_inb(sio_data->sioreg, 0x2a);
+ switch (data->kind) {
+ case nct6775:
+ have_vid = (cr2a & 0x40);
+ break;
+ case nct6776:
+ have_vid = (cr2a & 0x60) == 0x40;
+ break;
+ case nct6779:
+ break;
+ }
+
+ /*
+ * Read VID value
+ * We can get the VID input values directly at logical device D 0xe3.
+ */
+ if (have_vid) {
+ superio_select(sio_data->sioreg, NCT6775_LD_VID);
+ data->vid = superio_inb(sio_data->sioreg, 0xe3);
+ data->vrm = vid_which_vrm();
+ }
+
+ if (fan_debounce) {
+ u8 tmp;
+
+ superio_select(sio_data->sioreg, NCT6775_LD_HWM);
+ tmp = superio_inb(sio_data->sioreg,
+ NCT6775_REG_CR_FAN_DEBOUNCE);
+ switch (data->kind) {
+ case nct6775:
+ tmp |= 0x1e;
+ break;
+ case nct6776:
+ case nct6779:
+ tmp |= 0x3e;
+ break;
+ }
+ superio_outb(sio_data->sioreg, NCT6775_REG_CR_FAN_DEBOUNCE,
+ tmp);
+ dev_info(&pdev->dev, "Enabled fan debounce for chip %s\n",
+ data->name);
+ }
+
+ superio_exit(sio_data->sioreg);
+
+ if (have_vid) {
+ err = device_create_file(dev, &dev_attr_cpu0_vid);
+ if (err)
+ return err;
+ }
+
+ err = nct6775_check_fan_inputs(sio_data, data);
+ if (err)
+ goto exit_remove;
+
+ /* Read fan clock dividers immediately */
+ nct6775_init_fan_common(dev, data);
+
+ /* Register sysfs hooks */
+ for (i = 0; i < data->pwm_num; i++) {
+ if (!(data->has_pwm & (1 << i)))
+ continue;
+
+ err = sysfs_create_group(&dev->kobj, &nct6775_group_pwm[i]);
+ if (err)
+ goto exit_remove;
+
+ if (data->REG_PWM[3]) {
+ err = device_create_file(dev,
+ &sda_pwm_max[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->REG_PWM[4]) {
+ err = device_create_file(dev,
+ &sda_pwm_step[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->REG_PWM[6]) {
+ err = device_create_file(dev,
+ &sda_weight_duty_base[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(sda_auto_pwm_arrays); i++) {
+ struct sensor_device_attribute_2 *attr =
+ &sda_auto_pwm_arrays[i];
+
+ if (!(data->has_pwm & (1 << attr->nr)))
+ continue;
+ if (attr->index > data->auto_pwm_num)
+ continue;
+ err = device_create_file(dev, &attr->dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ for (i = 0; i < data->in_num; i++) {
+ if (!(data->have_in & (1 << i)))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]);
+ if (err)
+ goto exit_remove;
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (data->has_fan & (1 << i)) {
+ err = device_create_file(dev,
+ &sda_fan_input[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ err = device_create_file(dev,
+ &sda_fan_alarm[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ if (data->kind != nct6776 &&
+ data->kind != nct6779) {
+ err = device_create_file(dev,
+ &sda_fan_div[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->has_fan_min & (1 << i)) {
+ err = device_create_file(dev,
+ &sda_fan_min[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ err = device_create_file(dev,
+ &sda_fan_pulses[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ }
+
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+ err = device_create_file(dev, &sda_temp_input[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ if (data->temp_label) {
+ err = device_create_file(dev,
+ &sda_temp_label[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->reg_temp[1][i]) {
+ err = device_create_file(dev,
+ &sda_temp_max[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->reg_temp[2][i]) {
+ err = device_create_file(dev,
+ &sda_temp_max_hyst[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (data->reg_temp[3][i]) {
+ err = device_create_file(dev,
+ &sda_temp_crit[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+ if (!(data->have_temp_fixed & (1 << i)))
+ continue;
+ err = device_create_file(dev, &sda_temp_type[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ if (i >= NUM_TEMP_ALARM ||
+ data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0)
+ continue;
+ err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
+ if (data->ALARM_BITS[INTRUSION_ALARM_BASE + i] < 0)
+ continue;
+ err = device_create_file(dev, &sda_caseopen[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ err = device_create_file(dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ nct6775_device_remove_files(dev);
+ return err;
+}
+
+static int nct6775_remove(struct platform_device *pdev)
+{
+ struct nct6775_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ nct6775_device_remove_files(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int nct6775_suspend(struct device *dev)
+{
+ struct nct6775_data *data = nct6775_update_device(dev);
+ struct nct6775_sio_data *sio_data = dev->platform_data;
+
+ mutex_lock(&data->update_lock);
+ data->vbat = nct6775_read_value(data, data->REG_VBAT);
+ if (sio_data->kind == nct6775) {
+ data->fandiv1 = nct6775_read_value(data, NCT6775_REG_FANDIV1);
+ data->fandiv2 = nct6775_read_value(data, NCT6775_REG_FANDIV2);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return 0;
+}
+
+static int nct6775_resume(struct device *dev)
+{
+ struct nct6775_data *data = dev_get_drvdata(dev);
+ struct nct6775_sio_data *sio_data = dev->platform_data;
+ int i, j;
+
+ mutex_lock(&data->update_lock);
+ data->bank = 0xff; /* Force initial bank selection */
+
+ /* Restore limits */
+ for (i = 0; i < data->in_num; i++) {
+ if (!(data->have_in & (1 << i)))
+ continue;
+
+ nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
+ data->in[i][1]);
+ nct6775_write_value(data, data->REG_IN_MINMAX[1][i],
+ data->in[i][2]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
+ if (!(data->has_fan_min & (1 << i)))
+ continue;
+
+ nct6775_write_value(data, data->REG_FAN_MIN[i],
+ data->fan_min[i]);
+ }
+
+ for (i = 0; i < NUM_TEMP; i++) {
+ if (!(data->have_temp & (1 << i)))
+ continue;
+
+ for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
+ if (data->reg_temp[j][i])
+ nct6775_write_temp(data, data->reg_temp[j][i],
+ data->temp[j][i]);
+ }
+
+ /* Restore other settings */
+ nct6775_write_value(data, data->REG_VBAT, data->vbat);
+ if (sio_data->kind == nct6775) {
+ nct6775_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
+ nct6775_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
+ }
+
+ /* Force re-reading all values */
+ data->valid = false;
+ mutex_unlock(&data->update_lock);
+
+ return 0;
+}
+
+static const struct dev_pm_ops nct6775_dev_pm_ops = {
+ .suspend = nct6775_suspend,
+ .resume = nct6775_resume,
+};
+
+#define NCT6775_DEV_PM_OPS (&nct6775_dev_pm_ops)
+#else
+#define NCT6775_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver nct6775_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ .pm = NCT6775_DEV_PM_OPS,
+ },
+ .probe = nct6775_probe,
+ .remove = nct6775_remove,
+};
+
+static const char * const nct6775_sio_names[] __initconst = {
+ "NCT6775F",
+ "NCT6776D/F",
+ "NCT6779D",
+};
+
+/* nct6775_find() looks for a '627 in the Super-I/O config space */
+static int __init nct6775_find(int sioaddr, unsigned short *addr,
+ struct nct6775_sio_data *sio_data)
+{
+ u16 val;
+ int err;
+
+ err = superio_enter(sioaddr);
+ if (err)
+ return err;
+
+ if (force_id)
+ val = force_id;
+ else
+ val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+ | superio_inb(sioaddr, SIO_REG_DEVID + 1);
+ switch (val & SIO_ID_MASK) {
+ case SIO_NCT6775_ID:
+ sio_data->kind = nct6775;
+ break;
+ case SIO_NCT6776_ID:
+ sio_data->kind = nct6776;
+ break;
+ case SIO_NCT6779_ID:
+ sio_data->kind = nct6779;
+ break;
+ default:
+ if (val != 0xffff)
+ pr_debug("unsupported chip ID: 0x%04x\n", val);
+ superio_exit(sioaddr);
+ return -ENODEV;
+ }
+
+ /* We have a known chip, find the HWM I/O address */
+ superio_select(sioaddr, NCT6775_LD_HWM);
+ val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+ | superio_inb(sioaddr, SIO_REG_ADDR + 1);
+ *addr = val & IOREGION_ALIGNMENT;
+ if (*addr == 0) {
+ pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
+ superio_exit(sioaddr);
+ return -ENODEV;
+ }
+
+ /* Activate logical device if needed */
+ val = superio_inb(sioaddr, SIO_REG_ENABLE);
+ if (!(val & 0x01)) {
+ pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
+ superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+ }
+
+ superio_exit(sioaddr);
+ pr_info("Found %s or compatible chip at %#x\n",
+ nct6775_sio_names[sio_data->kind], *addr);
+ sio_data->sioreg = sioaddr;
+
+ return 0;
+}
+
+/*
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the nct6775 driver. But since we platform_device_alloc(), we
+ * must keep track of the device
+ */
+static struct platform_device *pdev;
+
+static int __init sensors_nct6775_init(void)
+{
+ int err;
+ unsigned short address;
+ struct resource res;
+ struct nct6775_sio_data sio_data;
+
+ /*
+ * initialize sio_data->kind and sio_data->sioreg.
+ *
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+ * nct6775 hardware monitor, and call probe()
+ */
+ if (nct6775_find(0x2e, &address, &sio_data) &&
+ nct6775_find(0x4e, &address, &sio_data))
+ return -ENODEV;
+
+ err = platform_driver_register(&nct6775_driver);
+ if (err)
+ goto exit;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ pr_err("Device allocation failed\n");
+ goto exit_unregister;
+ }
+
+ err = platform_device_add_data(pdev, &sio_data,
+ sizeof(struct nct6775_sio_data));
+ if (err) {
+ pr_err("Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
+ memset(&res, 0, sizeof(res));
+ res.name = DRVNAME;
+ res.start = address + IOREGION_OFFSET;
+ res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+ res.flags = IORESOURCE_IO;
+
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit_device_put;
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ pr_err("Device resource addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ /* platform_device_add calls probe() */
+ err = platform_device_add(pdev);
+ if (err) {
+ pr_err("Device addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit_unregister:
+ platform_driver_unregister(&nct6775_driver);
+exit:
+ return err;
+}
+
+static void __exit sensors_nct6775_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&nct6775_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_nct6775_init);
+module_exit(sensors_nct6775_exit);
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index b5f63f9c0ce1..d6d640a733d5 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -26,17 +26,33 @@
#include <linux/math64.h>
#include <linux/platform_device.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_data/ntc_thermistor.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
+
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
struct ntc_compensation {
- int temp_C;
+ int temp_c;
unsigned int ohm;
};
+static const struct platform_device_id ntc_thermistor_id[] = {
+ { "ncp15wb473", TYPE_NCPXXWB473 },
+ { "ncp18wb473", TYPE_NCPXXWB473 },
+ { "ncp21wb473", TYPE_NCPXXWB473 },
+ { "ncp03wb473", TYPE_NCPXXWB473 },
+ { "ncp15wl333", TYPE_NCPXXWL333 },
+ { },
+};
+
/*
* A compensation table should be sorted by the values of .ohm
* in descending order.
@@ -44,76 +60,76 @@ struct ntc_compensation {
* Thermistors Datasheet
*/
static const struct ntc_compensation ncpXXwb473[] = {
- { .temp_C = -40, .ohm = 1747920 },
- { .temp_C = -35, .ohm = 1245428 },
- { .temp_C = -30, .ohm = 898485 },
- { .temp_C = -25, .ohm = 655802 },
- { .temp_C = -20, .ohm = 483954 },
- { .temp_C = -15, .ohm = 360850 },
- { .temp_C = -10, .ohm = 271697 },
- { .temp_C = -5, .ohm = 206463 },
- { .temp_C = 0, .ohm = 158214 },
- { .temp_C = 5, .ohm = 122259 },
- { .temp_C = 10, .ohm = 95227 },
- { .temp_C = 15, .ohm = 74730 },
- { .temp_C = 20, .ohm = 59065 },
- { .temp_C = 25, .ohm = 47000 },
- { .temp_C = 30, .ohm = 37643 },
- { .temp_C = 35, .ohm = 30334 },
- { .temp_C = 40, .ohm = 24591 },
- { .temp_C = 45, .ohm = 20048 },
- { .temp_C = 50, .ohm = 16433 },
- { .temp_C = 55, .ohm = 13539 },
- { .temp_C = 60, .ohm = 11209 },
- { .temp_C = 65, .ohm = 9328 },
- { .temp_C = 70, .ohm = 7798 },
- { .temp_C = 75, .ohm = 6544 },
- { .temp_C = 80, .ohm = 5518 },
- { .temp_C = 85, .ohm = 4674 },
- { .temp_C = 90, .ohm = 3972 },
- { .temp_C = 95, .ohm = 3388 },
- { .temp_C = 100, .ohm = 2902 },
- { .temp_C = 105, .ohm = 2494 },
- { .temp_C = 110, .ohm = 2150 },
- { .temp_C = 115, .ohm = 1860 },
- { .temp_C = 120, .ohm = 1615 },
- { .temp_C = 125, .ohm = 1406 },
+ { .temp_c = -40, .ohm = 1747920 },
+ { .temp_c = -35, .ohm = 1245428 },
+ { .temp_c = -30, .ohm = 898485 },
+ { .temp_c = -25, .ohm = 655802 },
+ { .temp_c = -20, .ohm = 483954 },
+ { .temp_c = -15, .ohm = 360850 },
+ { .temp_c = -10, .ohm = 271697 },
+ { .temp_c = -5, .ohm = 206463 },
+ { .temp_c = 0, .ohm = 158214 },
+ { .temp_c = 5, .ohm = 122259 },
+ { .temp_c = 10, .ohm = 95227 },
+ { .temp_c = 15, .ohm = 74730 },
+ { .temp_c = 20, .ohm = 59065 },
+ { .temp_c = 25, .ohm = 47000 },
+ { .temp_c = 30, .ohm = 37643 },
+ { .temp_c = 35, .ohm = 30334 },
+ { .temp_c = 40, .ohm = 24591 },
+ { .temp_c = 45, .ohm = 20048 },
+ { .temp_c = 50, .ohm = 16433 },
+ { .temp_c = 55, .ohm = 13539 },
+ { .temp_c = 60, .ohm = 11209 },
+ { .temp_c = 65, .ohm = 9328 },
+ { .temp_c = 70, .ohm = 7798 },
+ { .temp_c = 75, .ohm = 6544 },
+ { .temp_c = 80, .ohm = 5518 },
+ { .temp_c = 85, .ohm = 4674 },
+ { .temp_c = 90, .ohm = 3972 },
+ { .temp_c = 95, .ohm = 3388 },
+ { .temp_c = 100, .ohm = 2902 },
+ { .temp_c = 105, .ohm = 2494 },
+ { .temp_c = 110, .ohm = 2150 },
+ { .temp_c = 115, .ohm = 1860 },
+ { .temp_c = 120, .ohm = 1615 },
+ { .temp_c = 125, .ohm = 1406 },
};
static const struct ntc_compensation ncpXXwl333[] = {
- { .temp_C = -40, .ohm = 1610154 },
- { .temp_C = -35, .ohm = 1130850 },
- { .temp_C = -30, .ohm = 802609 },
- { .temp_C = -25, .ohm = 575385 },
- { .temp_C = -20, .ohm = 416464 },
- { .temp_C = -15, .ohm = 304219 },
- { .temp_C = -10, .ohm = 224193 },
- { .temp_C = -5, .ohm = 166623 },
- { .temp_C = 0, .ohm = 124850 },
- { .temp_C = 5, .ohm = 94287 },
- { .temp_C = 10, .ohm = 71747 },
- { .temp_C = 15, .ohm = 54996 },
- { .temp_C = 20, .ohm = 42455 },
- { .temp_C = 25, .ohm = 33000 },
- { .temp_C = 30, .ohm = 25822 },
- { .temp_C = 35, .ohm = 20335 },
- { .temp_C = 40, .ohm = 16115 },
- { .temp_C = 45, .ohm = 12849 },
- { .temp_C = 50, .ohm = 10306 },
- { .temp_C = 55, .ohm = 8314 },
- { .temp_C = 60, .ohm = 6746 },
- { .temp_C = 65, .ohm = 5503 },
- { .temp_C = 70, .ohm = 4513 },
- { .temp_C = 75, .ohm = 3721 },
- { .temp_C = 80, .ohm = 3084 },
- { .temp_C = 85, .ohm = 2569 },
- { .temp_C = 90, .ohm = 2151 },
- { .temp_C = 95, .ohm = 1809 },
- { .temp_C = 100, .ohm = 1529 },
- { .temp_C = 105, .ohm = 1299 },
- { .temp_C = 110, .ohm = 1108 },
- { .temp_C = 115, .ohm = 949 },
- { .temp_C = 120, .ohm = 817 },
- { .temp_C = 125, .ohm = 707 },
+ { .temp_c = -40, .ohm = 1610154 },
+ { .temp_c = -35, .ohm = 1130850 },
+ { .temp_c = -30, .ohm = 802609 },
+ { .temp_c = -25, .ohm = 575385 },
+ { .temp_c = -20, .ohm = 416464 },
+ { .temp_c = -15, .ohm = 304219 },
+ { .temp_c = -10, .ohm = 224193 },
+ { .temp_c = -5, .ohm = 166623 },
+ { .temp_c = 0, .ohm = 124850 },
+ { .temp_c = 5, .ohm = 94287 },
+ { .temp_c = 10, .ohm = 71747 },
+ { .temp_c = 15, .ohm = 54996 },
+ { .temp_c = 20, .ohm = 42455 },
+ { .temp_c = 25, .ohm = 33000 },
+ { .temp_c = 30, .ohm = 25822 },
+ { .temp_c = 35, .ohm = 20335 },
+ { .temp_c = 40, .ohm = 16115 },
+ { .temp_c = 45, .ohm = 12849 },
+ { .temp_c = 50, .ohm = 10306 },
+ { .temp_c = 55, .ohm = 8314 },
+ { .temp_c = 60, .ohm = 6746 },
+ { .temp_c = 65, .ohm = 5503 },
+ { .temp_c = 70, .ohm = 4513 },
+ { .temp_c = 75, .ohm = 3721 },
+ { .temp_c = 80, .ohm = 3084 },
+ { .temp_c = 85, .ohm = 2569 },
+ { .temp_c = 90, .ohm = 2151 },
+ { .temp_c = 95, .ohm = 1809 },
+ { .temp_c = 100, .ohm = 1529 },
+ { .temp_c = 105, .ohm = 1299 },
+ { .temp_c = 110, .ohm = 1108 },
+ { .temp_c = 115, .ohm = 949 },
+ { .temp_c = 120, .ohm = 817 },
+ { .temp_c = 125, .ohm = 707 },
};
struct ntc_data {
@@ -125,6 +141,92 @@ struct ntc_data {
char name[PLATFORM_NAME_SIZE];
};
+#ifdef CONFIG_OF
+static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
+{
+ struct iio_channel *channel = pdata->chan;
+ unsigned int result;
+ int val, ret;
+
+ ret = iio_read_channel_raw(channel, &val);
+ if (ret < 0) {
+ pr_err("read channel() error: %d\n", ret);
+ return ret;
+ }
+
+ /* unit: mV */
+ result = pdata->pullup_uv * val;
+ result >>= 12;
+
+ return result;
+}
+
+static const struct of_device_id ntc_match[] = {
+ { .compatible = "ntc,ncp15wb473",
+ .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+ { .compatible = "ntc,ncp18wb473",
+ .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+ { .compatible = "ntc,ncp21wb473",
+ .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+ { .compatible = "ntc,ncp03wb473",
+ .data = &ntc_thermistor_id[TYPE_NCPXXWB473] },
+ { .compatible = "ntc,ncp15wl333",
+ .data = &ntc_thermistor_id[TYPE_NCPXXWL333] },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ntc_match);
+
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+ struct iio_channel *chan;
+ struct device_node *np = pdev->dev.of_node;
+ struct ntc_thermistor_platform_data *pdata;
+
+ if (!np)
+ return NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ chan = iio_channel_get(&pdev->dev, NULL);
+ if (IS_ERR(chan))
+ return ERR_CAST(chan);
+
+ if (of_property_read_u32(np, "pullup-uv", &pdata->pullup_uv))
+ return ERR_PTR(-ENODEV);
+ if (of_property_read_u32(np, "pullup-ohm", &pdata->pullup_ohm))
+ return ERR_PTR(-ENODEV);
+ if (of_property_read_u32(np, "pulldown-ohm", &pdata->pulldown_ohm))
+ return ERR_PTR(-ENODEV);
+
+ if (of_find_property(np, "connected-positive", NULL))
+ pdata->connect = NTC_CONNECTED_POSITIVE;
+ else /* status change should be possible if not always on. */
+ pdata->connect = NTC_CONNECTED_GROUND;
+
+ pdata->chan = chan;
+ pdata->read_uv = ntc_adc_iio_read;
+
+ return pdata;
+}
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{
+ if (pdata->chan)
+ iio_channel_release(pdata->chan);
+}
+#else
+static struct ntc_thermistor_platform_data *
+ntc_thermistor_parse_dt(struct platform_device *pdev)
+{
+ return NULL;
+}
+
+static void ntc_iio_channel_release(struct ntc_thermistor_platform_data *pdata)
+{ }
+#endif
+
static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
{
if (divisor == 0 && dividend == 0)
@@ -134,37 +236,37 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
return div64_u64(dividend, divisor);
}
-static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uv)
{
struct ntc_thermistor_platform_data *pdata = data->pdata;
- u64 mV = uV / 1000;
- u64 pmV = pdata->pullup_uV / 1000;
- u64 N, puO, pdO;
- puO = pdata->pullup_ohm;
- pdO = pdata->pulldown_ohm;
+ u64 mv = uv / 1000;
+ u64 pmv = pdata->pullup_uv / 1000;
+ u64 n, puo, pdo;
+ puo = pdata->pullup_ohm;
+ pdo = pdata->pulldown_ohm;
- if (mV == 0) {
+ if (mv == 0) {
if (pdata->connect == NTC_CONNECTED_POSITIVE)
return INT_MAX;
return 0;
}
- if (mV >= pmV)
+ if (mv >= pmv)
return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
0 : INT_MAX;
- if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
- N = div64_u64_safe(pdO * (pmV - mV), mV);
- else if (pdata->connect == NTC_CONNECTED_GROUND && pdO == 0)
- N = div64_u64_safe(puO * mV, pmV - mV);
+ if (pdata->connect == NTC_CONNECTED_POSITIVE && puo == 0)
+ n = div64_u64_safe(pdo * (pmv - mv), mv);
+ else if (pdata->connect == NTC_CONNECTED_GROUND && pdo == 0)
+ n = div64_u64_safe(puo * mv, pmv - mv);
else if (pdata->connect == NTC_CONNECTED_POSITIVE)
- N = div64_u64_safe(pdO * puO * (pmV - mV),
- puO * mV - pdO * (pmV - mV));
+ n = div64_u64_safe(pdo * puo * (pmv - mv),
+ puo * mv - pdo * (pmv - mv));
else
- N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
+ n = div64_u64_safe(pdo * puo * mv, pdo * (pmv - mv) - puo * mv);
- if (N > INT_MAX)
- N = INT_MAX;
- return N;
+ if (n > INT_MAX)
+ n = INT_MAX;
+ return n;
}
static void lookup_comp(struct ntc_data *data, unsigned int ohm,
@@ -233,7 +335,7 @@ static void lookup_comp(struct ntc_data *data, unsigned int ohm,
*i_high = end - 1;
}
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
+static int get_temp_mc(struct ntc_data *data, unsigned int ohm)
{
int low, high;
int temp;
@@ -241,10 +343,10 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
lookup_comp(data, ohm, &low, &high);
if (low == high) {
/* Unable to use linear approximation */
- temp = data->comp[low].temp_C * 1000;
+ temp = data->comp[low].temp_c * 1000;
} else {
- temp = data->comp[low].temp_C * 1000 +
- ((data->comp[high].temp_C - data->comp[low].temp_C) *
+ temp = data->comp[low].temp_c * 1000 +
+ ((data->comp[high].temp_c - data->comp[low].temp_c) *
1000 * ((int)ohm - (int)data->comp[low].ohm)) /
((int)data->comp[high].ohm - (int)data->comp[low].ohm);
}
@@ -253,16 +355,16 @@ static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
static int ntc_thermistor_get_ohm(struct ntc_data *data)
{
- int read_uV;
+ int read_uv;
if (data->pdata->read_ohm)
return data->pdata->read_ohm();
- if (data->pdata->read_uV) {
- read_uV = data->pdata->read_uV();
- if (read_uV < 0)
- return read_uV;
- return get_ohm_of_thermistor(data, read_uV);
+ if (data->pdata->read_uv) {
+ read_uv = data->pdata->read_uv(data->pdata);
+ if (read_uv < 0)
+ return read_uv;
+ return get_ohm_of_thermistor(data, read_uv);
}
return -EINVAL;
}
@@ -291,7 +393,7 @@ static ssize_t ntc_show_temp(struct device *dev,
if (ohm < 0)
return ohm;
- return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
+ return sprintf(buf, "%d\n", get_temp_mc(data, ohm));
}
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -311,9 +413,18 @@ static const struct attribute_group ntc_attr_group = {
static int ntc_thermistor_probe(struct platform_device *pdev)
{
+ const struct of_device_id *of_id =
+ of_match_device(of_match_ptr(ntc_match), &pdev->dev);
+ const struct platform_device_id *pdev_id;
+ struct ntc_thermistor_platform_data *pdata;
struct ntc_data *data;
- struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data;
- int ret = 0;
+ int ret;
+
+ pdata = ntc_thermistor_parse_dt(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ else if (pdata == NULL)
+ pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform init data supplied.\n");
@@ -321,19 +432,19 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
}
/* Either one of the two is required. */
- if (!pdata->read_uV && !pdata->read_ohm) {
+ if (!pdata->read_uv && !pdata->read_ohm) {
dev_err(&pdev->dev,
- "Both read_uV and read_ohm missing. Need either one of the two.\n");
+ "Both read_uv and read_ohm missing. Need either one of the two.\n");
return -EINVAL;
}
- if (pdata->read_uV && pdata->read_ohm) {
+ if (pdata->read_uv && pdata->read_ohm) {
dev_warn(&pdev->dev,
- "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
- pdata->read_uV = NULL;
+ "Only one of read_uv and read_ohm is needed; ignoring read_uv.\n");
+ pdata->read_uv = NULL;
}
- if (pdata->read_uV && (pdata->pullup_uV == 0 ||
+ if (pdata->read_uv && (pdata->pullup_uv == 0 ||
(pdata->pullup_ohm == 0 && pdata->connect ==
NTC_CONNECTED_GROUND) ||
(pdata->pulldown_ohm == 0 && pdata->connect ==
@@ -341,7 +452,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
(pdata->connect != NTC_CONNECTED_POSITIVE &&
pdata->connect != NTC_CONNECTED_GROUND))) {
dev_err(&pdev->dev,
- "Required data to use read_uV not supplied.\n");
+ "Required data to use read_uv not supplied.\n");
return -EINVAL;
}
@@ -349,11 +460,13 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
+ pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
data->dev = &pdev->dev;
data->pdata = pdata;
- strlcpy(data->name, pdev->id_entry->name, sizeof(data->name));
+ strlcpy(data->name, pdev_id->name, sizeof(data->name));
- switch (pdev->id_entry->driver_data) {
+ switch (pdev_id->driver_data) {
case TYPE_NCPXXWB473:
data->comp = ncpXXwb473;
data->n_comp = ARRAY_SIZE(ncpXXwb473);
@@ -364,8 +477,7 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
break;
default:
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
- pdev->id_entry->driver_data,
- pdev->id_entry->name);
+ pdev_id->driver_data, pdev_id->name);
return -EINVAL;
}
@@ -384,39 +496,34 @@ static int ntc_thermistor_probe(struct platform_device *pdev)
goto err_after_sysfs;
}
- dev_info(&pdev->dev, "Thermistor %s:%d (type: %s/%lu) successfully probed.\n",
- pdev->name, pdev->id, pdev->id_entry->name,
- pdev->id_entry->driver_data);
+ dev_info(&pdev->dev, "Thermistor type: %s successfully probed.\n",
+ pdev->name);
+
return 0;
err_after_sysfs:
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+ ntc_iio_channel_release(pdata);
return ret;
}
static int ntc_thermistor_remove(struct platform_device *pdev)
{
struct ntc_data *data = platform_get_drvdata(pdev);
+ struct ntc_thermistor_platform_data *pdata = data->pdata;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
+ ntc_iio_channel_release(pdata);
platform_set_drvdata(pdev, NULL);
return 0;
}
-static const struct platform_device_id ntc_thermistor_id[] = {
- { "ncp15wb473", TYPE_NCPXXWB473 },
- { "ncp18wb473", TYPE_NCPXXWB473 },
- { "ncp21wb473", TYPE_NCPXXWB473 },
- { "ncp03wb473", TYPE_NCPXXWB473 },
- { "ncp15wl333", TYPE_NCPXXWL333 },
- { },
-};
-
static struct platform_driver ntc_thermistor_driver = {
.driver = {
.name = "ntc-thermistor",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ntc_match),
},
.probe = ntc_thermistor_probe,
.remove = ntc_thermistor_remove,
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index e35856bb79b4..aa615ba73d4b 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1190,8 +1190,7 @@ static int __init pc87360_find(int sioaddr, u8 *devid,
confreg[3] = superio_inb(sioaddr, 0x25);
if (confreg[2] & 0x40) {
- pr_info("Using thermistors for "
- "temperature monitoring\n");
+ pr_info("Using thermistors for temperature monitoring\n");
}
if (confreg[3] & 0xE0) {
pr_info("VID inputs routed (mode %u)\n",
@@ -1271,9 +1270,9 @@ static int pc87360_probe(struct platform_device *pdev)
if (data->address[i]
&& !devm_request_region(dev, extra_isa[i], PC87360_EXTENT,
pc87360_driver.driver.name)) {
- dev_err(dev, "Region 0x%x-0x%x already "
- "in use!\n", extra_isa[i],
- extra_isa[i]+PC87360_EXTENT-1);
+ dev_err(dev,
+ "Region 0x%x-0x%x already in use!\n",
+ extra_isa[i], extra_isa[i]+PC87360_EXTENT-1);
return -EBUSY;
}
}
@@ -1435,8 +1434,8 @@ static void pc87360_init_device(struct platform_device *pdev,
if (init >= 2 && data->innr) {
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE);
- dev_info(&pdev->dev, "VLM conversion set to "
- "1s period, 160us delay\n");
+ dev_info(&pdev->dev,
+ "VLM conversion set to 1s period, 160us delay\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE,
(reg & 0xC0) | 0x11);
@@ -1450,8 +1449,8 @@ static void pc87360_init_device(struct platform_device *pdev,
if (init >= init_in[i]) {
/* Forcibly enable voltage channel */
if (!(reg & CHAN_ENA)) {
- dev_dbg(&pdev->dev, "Forcibly "
- "enabling in%d\n", i);
+ dev_dbg(&pdev->dev, "Forcibly enabling in%d\n",
+ i);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_IN_STATUS,
(reg & 0x68) | 0x87);
@@ -1575,8 +1574,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
data->fan_status[nr] += 0x20;
data->fan_min[nr] >>= 1;
data->fan[nr] >>= 1;
- dev_dbg(dev, "Increasing "
- "clock divider to %d for fan %d\n",
+ dev_dbg(dev,
+ "Increasing clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1);
}
} else {
@@ -1587,8 +1586,8 @@ static void pc87360_autodiv(struct device *dev, int nr)
data->fan_status[nr] -= 0x20;
data->fan_min[nr] <<= 1;
data->fan[nr] <<= 1;
- dev_dbg(dev, "Decreasing "
- "clock divider to %d for fan %d\n",
+ dev_dbg(dev,
+ "Decreasing clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]),
nr + 1);
}
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 6086ad039d7d..ea606860d2b2 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -627,8 +627,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute
pc87427_readall_pwm(data, nr);
mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK;
if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) {
- dev_notice(dev, "Can't set PWM%d duty cycle while not in "
- "manual mode\n", nr + 1);
+ dev_notice(dev,
+ "Can't set PWM%d duty cycle while not in manual mode\n",
+ nr + 1);
mutex_unlock(&data->lock);
return -EPERM;
}
@@ -1245,16 +1246,16 @@ static int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data)
val = superio_inb(sioaddr, SIOREG_MAP);
if (val & 0x01) {
- pr_warn("Logical device 0x%02x is memory-mapped, "
- "can't use\n", logdev[i]);
+ pr_warn("Logical device 0x%02x is memory-mapped, can't use\n",
+ logdev[i]);
continue;
}
val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8)
| superio_inb(sioaddr, SIOREG_IOBASE + 1);
if (!val) {
- pr_info("I/O base address not set for logical device "
- "0x%02x\n", logdev[i]);
+ pr_info("I/O base address not set for logical device 0x%02x\n",
+ logdev[i]);
continue;
}
sio_data->address[i] = val;
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 4f9eb0af5229..39cc63edfbb0 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -42,17 +42,17 @@ config SENSORS_LM25066
default n
help
If you say yes here you get hardware monitoring support for National
- Semiconductor LM25066, LM5064, and LM5066.
+ Semiconductor LM25056, LM25066, LM5064, and LM5066.
This driver can also be built as a module. If so, the module will
be called lm25066.
config SENSORS_LTC2978
- tristate "Linear Technologies LTC2978 and LTC3880"
+ tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
default n
help
If you say yes here you get hardware monitoring support for Linear
- Technology LTC2978 and LTC3880.
+ Technology LTC2974, LTC2978, LTC3880, and LTC3883.
This driver can also be built as a module. If so, the module will
be called ltc2978.
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c
index c299392716af..6a9d6edaacb3 100644
--- a/drivers/hwmon/pmbus/lm25066.c
+++ b/drivers/hwmon/pmbus/lm25066.c
@@ -1,7 +1,8 @@
/*
- * Hardware monitoring driver for LM25066 / LM5064 / LM5066
+ * Hardware monitoring driver for LM25056 / LM25066 / LM5064 / LM5066
*
* Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013 Guenter Roeck
*
* 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
@@ -26,7 +27,7 @@
#include <linux/i2c.h>
#include "pmbus.h"
-enum chips { lm25066, lm5064, lm5066 };
+enum chips { lm25056, lm25066, lm5064, lm5066 };
#define LM25066_READ_VAUX 0xd0
#define LM25066_MFR_READ_IIN 0xd1
@@ -43,6 +44,138 @@ enum chips { lm25066, lm5064, lm5066 };
#define LM25066_DEV_SETUP_CL (1 << 4) /* Current limit */
+/* LM25056 only */
+
+#define LM25056_VAUX_OV_WARN_LIMIT 0xe3
+#define LM25056_VAUX_UV_WARN_LIMIT 0xe4
+
+#define LM25056_MFR_STS_VAUX_OV_WARN (1 << 1)
+#define LM25056_MFR_STS_VAUX_UV_WARN (1 << 0)
+
+struct __coeff {
+ short m, b, R;
+};
+
+#define PSC_CURRENT_IN_L (PSC_NUM_CLASSES)
+#define PSC_POWER_L (PSC_NUM_CLASSES + 1)
+
+static struct __coeff lm25066_coeff[4][PSC_NUM_CLASSES + 2] = {
+ [lm25056] = {
+ [PSC_VOLTAGE_IN] = {
+ .m = 16296,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN] = {
+ .m = 13797,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN_L] = {
+ .m = 6726,
+ .R = -2,
+ },
+ [PSC_POWER] = {
+ .m = 5501,
+ .R = -3,
+ },
+ [PSC_POWER_L] = {
+ .m = 26882,
+ .R = -4,
+ },
+ [PSC_TEMPERATURE] = {
+ .m = 1580,
+ .b = -14500,
+ .R = -2,
+ },
+ },
+ [lm25066] = {
+ [PSC_VOLTAGE_IN] = {
+ .m = 22070,
+ .R = -2,
+ },
+ [PSC_VOLTAGE_OUT] = {
+ .m = 22070,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN] = {
+ .m = 13661,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN_L] = {
+ .m = 6852,
+ .R = -2,
+ },
+ [PSC_POWER] = {
+ .m = 736,
+ .R = -2,
+ },
+ [PSC_POWER_L] = {
+ .m = 369,
+ .R = -2,
+ },
+ [PSC_TEMPERATURE] = {
+ .m = 16,
+ },
+ },
+ [lm5064] = {
+ [PSC_VOLTAGE_IN] = {
+ .m = 4611,
+ .R = -2,
+ },
+ [PSC_VOLTAGE_OUT] = {
+ .m = 4621,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN] = {
+ .m = 10742,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN_L] = {
+ .m = 5456,
+ .R = -2,
+ },
+ [PSC_POWER] = {
+ .m = 1204,
+ .R = -3,
+ },
+ [PSC_POWER_L] = {
+ .m = 612,
+ .R = -3,
+ },
+ [PSC_TEMPERATURE] = {
+ .m = 16,
+ },
+ },
+ [lm5066] = {
+ [PSC_VOLTAGE_IN] = {
+ .m = 4587,
+ .R = -2,
+ },
+ [PSC_VOLTAGE_OUT] = {
+ .m = 4587,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN] = {
+ .m = 10753,
+ .R = -2,
+ },
+ [PSC_CURRENT_IN_L] = {
+ .m = 5405,
+ .R = -2,
+ },
+ [PSC_POWER] = {
+ .m = 1204,
+ .R = -3,
+ },
+ [PSC_POWER_L] = {
+ .m = 605,
+ .R = -3,
+ },
+ [PSC_TEMPERATURE] = {
+ .m = 16,
+ },
+ },
+};
+
struct lm25066_data {
int id;
struct pmbus_driver_info info;
@@ -56,42 +189,31 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
const struct lm25066_data *data = to_lm25066_data(info);
int ret;
- if (page > 1)
- return -ENXIO;
-
- /* Map READ_VAUX into READ_VOUT register on page 1 */
- if (page == 1) {
- switch (reg) {
- case PMBUS_READ_VOUT:
- ret = pmbus_read_word_data(client, 0,
- LM25066_READ_VAUX);
- if (ret < 0)
- break;
- /* Adjust returned value to match VOUT coefficients */
- switch (data->id) {
- case lm25066:
- /* VOUT: 4.54 mV VAUX: 283.2 uV LSB */
- ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
- break;
- case lm5064:
- /* VOUT: 4.53 mV VAUX: 700 uV LSB */
- ret = DIV_ROUND_CLOSEST(ret * 70, 453);
- break;
- case lm5066:
- /* VOUT: 2.18 mV VAUX: 725 uV LSB */
- ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
- break;
- }
+ switch (reg) {
+ case PMBUS_VIRT_READ_VMON:
+ ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
+ if (ret < 0)
+ break;
+ /* Adjust returned value to match VIN coefficients */
+ switch (data->id) {
+ case lm25056:
+ /* VIN: 6.14 mV VAUX: 293 uV LSB */
+ ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
break;
- default:
- /* No other valid registers on page 1 */
- ret = -ENXIO;
+ case lm25066:
+ /* VIN: 4.54 mV VAUX: 283.2 uV LSB */
+ ret = DIV_ROUND_CLOSEST(ret * 2832, 45400);
+ break;
+ case lm5064:
+ /* VIN: 4.53 mV VAUX: 700 uV LSB */
+ ret = DIV_ROUND_CLOSEST(ret * 70, 453);
+ break;
+ case lm5066:
+ /* VIN: 2.18 mV VAUX: 725 uV LSB */
+ ret = DIV_ROUND_CLOSEST(ret * 725, 2180);
break;
}
- goto done;
- }
-
- switch (reg) {
+ break;
case PMBUS_READ_IIN:
ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
break;
@@ -128,7 +250,58 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
ret = -ENODATA;
break;
}
-done:
+ return ret;
+}
+
+static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0,
+ LM25056_VAUX_UV_WARN_LIMIT);
+ if (ret < 0)
+ break;
+ /* Adjust returned value to match VIN coefficients */
+ ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+ break;
+ case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+ ret = pmbus_read_word_data(client, 0,
+ LM25056_VAUX_OV_WARN_LIMIT);
+ if (ret < 0)
+ break;
+ /* Adjust returned value to match VIN coefficients */
+ ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
+ break;
+ default:
+ ret = lm25066_read_word_data(client, page, reg);
+ break;
+ }
+ return ret;
+}
+
+static int lm25056_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret, s;
+
+ switch (reg) {
+ case PMBUS_VIRT_STATUS_VMON:
+ ret = pmbus_read_byte_data(client, 0,
+ PMBUS_STATUS_MFR_SPECIFIC);
+ if (ret < 0)
+ break;
+ s = 0;
+ if (ret & LM25056_MFR_STS_VAUX_UV_WARN)
+ s |= PB_VOLTAGE_UV_WARNING;
+ if (ret & LM25056_MFR_STS_VAUX_OV_WARN)
+ s |= PB_VOLTAGE_OV_WARNING;
+ ret = s;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
return ret;
}
@@ -137,19 +310,45 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
{
int ret;
- if (page > 1)
- return -ENXIO;
-
switch (reg) {
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_OT_WARN_LIMIT:
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+ ret = pmbus_write_word_data(client, 0, reg, word);
+ pmbus_clear_cache(client);
+ break;
case PMBUS_IIN_OC_WARN_LIMIT:
+ word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
ret = pmbus_write_word_data(client, 0,
LM25066_MFR_IIN_OC_WARN_LIMIT,
word);
+ pmbus_clear_cache(client);
break;
case PMBUS_PIN_OP_WARN_LIMIT:
+ word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
ret = pmbus_write_word_data(client, 0,
LM25066_MFR_PIN_OP_WARN_LIMIT,
word);
+ pmbus_clear_cache(client);
+ break;
+ case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
+ /* Adjust from VIN coefficients (for LM25056) */
+ word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+ word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+ ret = pmbus_write_word_data(client, 0,
+ LM25056_VAUX_UV_WARN_LIMIT, word);
+ pmbus_clear_cache(client);
+ break;
+ case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
+ /* Adjust from VIN coefficients (for LM25056) */
+ word = DIV_ROUND_CLOSEST((int)word * 6140, 293);
+ word = ((s16)word < 0) ? 0 : clamp_val(word, 0, 0x0fff);
+ ret = pmbus_write_word_data(client, 0,
+ LM25056_VAUX_OV_WARN_LIMIT, word);
+ pmbus_clear_cache(client);
break;
case PMBUS_VIRT_RESET_PIN_HISTORY:
ret = pmbus_write_byte(client, 0, LM25066_CLEAR_PIN_PEAK);
@@ -161,23 +360,13 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
return ret;
}
-static int lm25066_write_byte(struct i2c_client *client, int page, u8 value)
-{
- if (page > 1)
- return -ENXIO;
-
- if (page <= 0)
- return pmbus_write_byte(client, page, value);
-
- return 0;
-}
-
static int lm25066_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int config;
struct lm25066_data *data;
struct pmbus_driver_info *info;
+ struct __coeff *coeff;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA))
@@ -195,107 +384,54 @@ static int lm25066_probe(struct i2c_client *client,
data->id = id->driver_data;
info = &data->info;
- info->pages = 2;
+ info->pages = 1;
info->format[PSC_VOLTAGE_IN] = direct;
info->format[PSC_VOLTAGE_OUT] = direct;
info->format[PSC_CURRENT_IN] = direct;
info->format[PSC_TEMPERATURE] = direct;
info->format[PSC_POWER] = direct;
- info->m[PSC_TEMPERATURE] = 16;
- info->b[PSC_TEMPERATURE] = 0;
- info->R[PSC_TEMPERATURE] = 0;
-
- info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
- | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN
- | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
- info->func[1] = PMBUS_HAVE_VOUT;
-
- info->read_word_data = lm25066_read_word_data;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VMON
+ | PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
+
+ if (data->id == lm25056) {
+ info->func[0] |= PMBUS_HAVE_STATUS_VMON;
+ info->read_word_data = lm25056_read_word_data;
+ info->read_byte_data = lm25056_read_byte_data;
+ } else {
+ info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ info->read_word_data = lm25066_read_word_data;
+ }
info->write_word_data = lm25066_write_word_data;
- info->write_byte = lm25066_write_byte;
-
- switch (id->driver_data) {
- case lm25066:
- info->m[PSC_VOLTAGE_IN] = 22070;
- info->b[PSC_VOLTAGE_IN] = 0;
- info->R[PSC_VOLTAGE_IN] = -2;
- info->m[PSC_VOLTAGE_OUT] = 22070;
- info->b[PSC_VOLTAGE_OUT] = 0;
- info->R[PSC_VOLTAGE_OUT] = -2;
-
- if (config & LM25066_DEV_SETUP_CL) {
- info->m[PSC_CURRENT_IN] = 6852;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 369;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -2;
- } else {
- info->m[PSC_CURRENT_IN] = 13661;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 736;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -2;
- }
- break;
- case lm5064:
- info->m[PSC_VOLTAGE_IN] = 22075;
- info->b[PSC_VOLTAGE_IN] = 0;
- info->R[PSC_VOLTAGE_IN] = -2;
- info->m[PSC_VOLTAGE_OUT] = 22075;
- info->b[PSC_VOLTAGE_OUT] = 0;
- info->R[PSC_VOLTAGE_OUT] = -2;
-
- if (config & LM25066_DEV_SETUP_CL) {
- info->m[PSC_CURRENT_IN] = 6713;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 3619;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -3;
- } else {
- info->m[PSC_CURRENT_IN] = 13426;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 7238;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -3;
- }
- break;
- case lm5066:
- info->m[PSC_VOLTAGE_IN] = 4587;
- info->b[PSC_VOLTAGE_IN] = 0;
- info->R[PSC_VOLTAGE_IN] = -2;
- info->m[PSC_VOLTAGE_OUT] = 4587;
- info->b[PSC_VOLTAGE_OUT] = 0;
- info->R[PSC_VOLTAGE_OUT] = -2;
-
- if (config & LM25066_DEV_SETUP_CL) {
- info->m[PSC_CURRENT_IN] = 10753;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 1204;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -3;
- } else {
- info->m[PSC_CURRENT_IN] = 5405;
- info->b[PSC_CURRENT_IN] = 0;
- info->R[PSC_CURRENT_IN] = -2;
- info->m[PSC_POWER] = 605;
- info->b[PSC_POWER] = 0;
- info->R[PSC_POWER] = -3;
- }
- break;
- default:
- return -ENODEV;
+
+ coeff = &lm25066_coeff[data->id][0];
+ info->m[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].m;
+ info->b[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].b;
+ info->R[PSC_TEMPERATURE] = coeff[PSC_TEMPERATURE].R;
+ info->m[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].m;
+ info->b[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].b;
+ info->R[PSC_VOLTAGE_IN] = coeff[PSC_VOLTAGE_IN].R;
+ info->m[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].m;
+ info->b[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].b;
+ info->R[PSC_VOLTAGE_OUT] = coeff[PSC_VOLTAGE_OUT].R;
+ info->b[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].b;
+ info->R[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].R;
+ info->b[PSC_POWER] = coeff[PSC_POWER].b;
+ info->R[PSC_POWER] = coeff[PSC_POWER].R;
+ if (config & LM25066_DEV_SETUP_CL) {
+ info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN_L].m;
+ info->m[PSC_POWER] = coeff[PSC_POWER_L].m;
+ } else {
+ info->m[PSC_CURRENT_IN] = coeff[PSC_CURRENT_IN].m;
+ info->m[PSC_POWER] = coeff[PSC_POWER].m;
}
return pmbus_do_probe(client, id, info);
}
static const struct i2c_device_id lm25066_id[] = {
+ {"lm25056", lm25056},
{"lm25066", lm25066},
{"lm5064", lm5064},
{"lm5066", lm5066},
@@ -317,5 +453,5 @@ static struct i2c_driver lm25066_driver = {
module_i2c_driver(lm25066_driver);
MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LM25066/LM5064/LM5066");
+MODULE_DESCRIPTION("PMBus driver for LM25056/LM25066/LM5064/LM5066");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index 6d6130752f94..586a89ef9e0f 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -1,7 +1,8 @@
/*
- * Hardware monitoring driver for LTC2978 and LTC3880
+ * Hardware monitoring driver for LTC2974, LTC2978, LTC3880, and LTC3883
*
* Copyright (c) 2011 Ericsson AB.
+ * Copyright (c) 2013 Guenter Roeck
*
* 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
@@ -26,28 +27,43 @@
#include <linux/i2c.h>
#include "pmbus.h"
-enum chips { ltc2978, ltc3880 };
+enum chips { ltc2974, ltc2978, ltc3880, ltc3883 };
-/* LTC2978 and LTC3880 */
+/* Common for all chips */
#define LTC2978_MFR_VOUT_PEAK 0xdd
#define LTC2978_MFR_VIN_PEAK 0xde
#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
#define LTC2978_MFR_SPECIAL_ID 0xe7
-/* LTC2978 only */
+/* LTC2974 and LTC2978 */
#define LTC2978_MFR_VOUT_MIN 0xfb
#define LTC2978_MFR_VIN_MIN 0xfc
#define LTC2978_MFR_TEMPERATURE_MIN 0xfd
-/* LTC3880 only */
+/* LTC2974 only */
+#define LTC2974_MFR_IOUT_PEAK 0xd7
+#define LTC2974_MFR_IOUT_MIN 0xd8
+
+/* LTC3880 and LTC3883 */
#define LTC3880_MFR_IOUT_PEAK 0xd7
#define LTC3880_MFR_CLEAR_PEAKS 0xe3
#define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4
+/* LTC3883 only */
+#define LTC3883_MFR_IIN_PEAK 0xe1
+
+#define LTC2974_ID 0x0212
#define LTC2978_ID_REV1 0x0121
#define LTC2978_ID_REV2 0x0122
#define LTC3880_ID 0x4000
#define LTC3880_ID_MASK 0xff00
+#define LTC3883_ID 0x4300
+#define LTC3883_ID_MASK 0xff00
+
+#define LTC2974_NUM_PAGES 4
+#define LTC2978_NUM_PAGES 8
+#define LTC3880_NUM_PAGES 2
+#define LTC3883_NUM_PAGES 1
/*
* LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
@@ -56,13 +72,15 @@ enum chips { ltc2978, ltc3880 };
* internal cache of measured peak data, which is only cleared if an explicit
* "clear peak" command is executed for the sensor in question.
*/
+
struct ltc2978_data {
enum chips id;
- int vin_min, vin_max;
- int temp_min, temp_max[2];
- int vout_min[8], vout_max[8];
- int iout_max[2];
- int temp2_max;
+ u16 vin_min, vin_max;
+ u16 temp_min[LTC2974_NUM_PAGES], temp_max[LTC2974_NUM_PAGES];
+ u16 vout_min[LTC2978_NUM_PAGES], vout_max[LTC2978_NUM_PAGES];
+ u16 iout_min[LTC2974_NUM_PAGES], iout_max[LTC2974_NUM_PAGES];
+ u16 iin_max;
+ u16 temp2_max;
struct pmbus_driver_info info;
};
@@ -167,9 +185,9 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
LTC2978_MFR_TEMPERATURE_MIN);
if (ret >= 0) {
if (lin11_to_val(ret)
- < lin11_to_val(data->temp_min))
- data->temp_min = ret;
- ret = data->temp_min;
+ < lin11_to_val(data->temp_min[page]))
+ data->temp_min[page] = ret;
+ ret = data->temp_min[page];
}
break;
case PMBUS_VIRT_READ_IOUT_MAX:
@@ -185,6 +203,41 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
return ret;
}
+static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_IOUT_MAX:
+ ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ > lin11_to_val(data->iout_max[page]))
+ data->iout_max[page] = ret;
+ ret = data->iout_max[page];
+ }
+ break;
+ case PMBUS_VIRT_READ_IOUT_MIN:
+ ret = pmbus_read_word_data(client, page, LTC2974_MFR_IOUT_MIN);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ < lin11_to_val(data->iout_min[page]))
+ data->iout_min[page] = ret;
+ ret = data->iout_min[page];
+ }
+ break;
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ ret = 0;
+ break;
+ default:
+ ret = ltc2978_read_word_data(client, page, reg);
+ break;
+ }
+ return ret;
+}
+
static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -226,15 +279,41 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
return ret;
}
+static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct ltc2978_data *data = to_ltc2978_data(info);
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_IIN_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3883_MFR_IIN_PEAK);
+ if (ret >= 0) {
+ if (lin11_to_val(ret)
+ > lin11_to_val(data->iin_max))
+ data->iin_max = ret;
+ ret = data->iin_max;
+ }
+ break;
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ ret = 0;
+ break;
+ default:
+ ret = ltc3880_read_word_data(client, page, reg);
+ break;
+ }
+ return ret;
+}
+
static int ltc2978_clear_peaks(struct i2c_client *client, int page,
enum chips id)
{
int ret;
- if (id == ltc2978)
- ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
- else
+ if (id == ltc3880 || id == ltc3883)
ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
+ else
+ ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS);
return ret;
}
@@ -247,8 +326,13 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
int ret;
switch (reg) {
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ data->iin_max = 0x7c00;
+ ret = ltc2978_clear_peaks(client, page, data->id);
+ break;
case PMBUS_VIRT_RESET_IOUT_HISTORY:
data->iout_max[page] = 0x7c00;
+ data->iout_min[page] = 0xfbff;
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_TEMP2_HISTORY:
@@ -266,7 +350,7 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
ret = ltc2978_clear_peaks(client, page, data->id);
break;
case PMBUS_VIRT_RESET_TEMP_HISTORY:
- data->temp_min = 0x7bff;
+ data->temp_min[page] = 0x7bff;
data->temp_max[page] = 0x7c00;
ret = ltc2978_clear_peaks(client, page, data->id);
break;
@@ -278,8 +362,10 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
}
static const struct i2c_device_id ltc2978_id[] = {
+ {"ltc2974", ltc2974},
{"ltc2978", ltc2978},
{"ltc3880", ltc3880},
+ {"ltc3883", ltc3883},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -304,10 +390,14 @@ static int ltc2978_probe(struct i2c_client *client,
if (chip_id < 0)
return chip_id;
- if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
+ if (chip_id == LTC2974_ID) {
+ data->id = ltc2974;
+ } else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) {
data->id = ltc2978;
} else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) {
data->id = ltc3880;
+ } else if ((chip_id & LTC3883_ID_MASK) == LTC3883_ID) {
+ data->id = ltc3883;
} else {
dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
return -ENODEV;
@@ -323,26 +413,45 @@ static int ltc2978_probe(struct i2c_client *client,
data->vin_min = 0x7bff;
data->vin_max = 0x7c00;
- data->temp_min = 0x7bff;
+ for (i = 0; i < ARRAY_SIZE(data->vout_min); i++)
+ data->vout_min[i] = 0xffff;
+ for (i = 0; i < ARRAY_SIZE(data->iout_min); i++)
+ data->iout_min[i] = 0xfbff;
+ for (i = 0; i < ARRAY_SIZE(data->iout_max); i++)
+ data->iout_max[i] = 0x7c00;
+ for (i = 0; i < ARRAY_SIZE(data->temp_min); i++)
+ data->temp_min[i] = 0x7bff;
for (i = 0; i < ARRAY_SIZE(data->temp_max); i++)
data->temp_max[i] = 0x7c00;
data->temp2_max = 0x7c00;
switch (data->id) {
+ case ltc2974:
+ info->read_word_data = ltc2974_read_word_data;
+ info->pages = LTC2974_NUM_PAGES;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_TEMP2;
+ for (i = 0; i < info->pages; i++) {
+ info->func[i] |= PMBUS_HAVE_VOUT
+ | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
+ | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+ }
+ break;
case ltc2978:
info->read_word_data = ltc2978_read_word_data;
- info->pages = 8;
+ info->pages = LTC2978_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
- for (i = 1; i < 8; i++) {
+ for (i = 1; i < LTC2978_NUM_PAGES; i++) {
info->func[i] = PMBUS_HAVE_VOUT
| PMBUS_HAVE_STATUS_VOUT;
}
break;
case ltc3880:
info->read_word_data = ltc3880_read_word_data;
- info->pages = 2;
+ info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
| PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
@@ -353,15 +462,20 @@ static int ltc2978_probe(struct i2c_client *client,
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
- data->iout_max[0] = 0x7c00;
- data->iout_max[1] = 0x7c00;
+ break;
+ case ltc3883:
+ info->read_word_data = ltc3883_read_word_data;
+ info->pages = LTC3883_NUM_PAGES;
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
+ | PMBUS_HAVE_STATUS_INPUT
+ | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+ | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+ | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
+ | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
break;
default:
return -ENODEV;
}
- for (i = 0; i < info->pages; i++)
- data->vout_min[i] = 0xffff;
-
return pmbus_do_probe(client, id, info);
}
@@ -378,5 +492,5 @@ static struct i2c_driver ltc2978_driver = {
module_i2c_driver(ltc2978_driver);
MODULE_AUTHOR("Guenter Roeck");
-MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880");
+MODULE_DESCRIPTION("PMBus driver for LTC2974, LTC2978, LTC3880, and LTC3883");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c
index ff2ae0252a48..a9f7e804f1e4 100644
--- a/drivers/hwmon/s3c-hwmon.c
+++ b/drivers/hwmon/s3c-hwmon.c
@@ -107,17 +107,14 @@ static ssize_t s3c_hwmon_show_raw(struct device *dev,
return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret);
}
-#define DEF_ADC_ATTR(x) \
- static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x)
-
-DEF_ADC_ATTR(0);
-DEF_ADC_ATTR(1);
-DEF_ADC_ATTR(2);
-DEF_ADC_ATTR(3);
-DEF_ADC_ATTR(4);
-DEF_ADC_ATTR(5);
-DEF_ADC_ATTR(6);
-DEF_ADC_ATTR(7);
+static SENSOR_DEVICE_ATTR(adc0_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 0);
+static SENSOR_DEVICE_ATTR(adc1_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 1);
+static SENSOR_DEVICE_ATTR(adc2_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 2);
+static SENSOR_DEVICE_ATTR(adc3_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 3);
+static SENSOR_DEVICE_ATTR(adc4_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 4);
+static SENSOR_DEVICE_ATTR(adc5_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 5);
+static SENSOR_DEVICE_ATTR(adc6_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 6);
+static SENSOR_DEVICE_ATTR(adc7_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, 7);
static struct attribute *s3c_hwmon_attrs[9] = {
&sensor_dev_attr_adc0_raw.dev_attr.attr,
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index d00b30adc34b..738681983284 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -161,8 +161,8 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
break;
}
if (i == max_busy_polls + max_lazy_polls) {
- pr_err("Max retries exceeded reading virtual "
- "register 0x%04hx (%d)\n", reg, 1);
+ pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+ reg, 1);
return -EIO;
}
@@ -178,12 +178,12 @@ static int sch56xx_send_cmd(u16 addr, u8 cmd, u16 reg, u8 v)
break;
if (i == 0)
- pr_warn("EC reports: 0x%02x reading virtual register "
- "0x%04hx\n", (unsigned int)val, reg);
+ pr_warn("EC reports: 0x%02x reading virtual register 0x%04hx\n",
+ (unsigned int)val, reg);
}
if (i == max_busy_polls) {
- pr_err("Max retries exceeded reading virtual "
- "register 0x%04hx (%d)\n", reg, 2);
+ pr_err("Max retries exceeded reading virtual register 0x%04hx (%d)\n",
+ reg, 2);
return -EIO;
}
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index c35847a1a0a3..1404e6319deb 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -456,8 +456,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
data->fan_div[nr] = 3;
break;
default:
- dev_err(dev, "fan_div value %ld not "
- "supported. Choose one of 1, 2, 4 or 8!\n", val);
+ dev_err(dev,
+ "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+ val);
mutex_unlock(&data->update_lock);
return -EINVAL;
}
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 4b59eb53b18a..db288db7d3e9 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -41,8 +41,8 @@ enum chips { thmc50, adm1022 };
static unsigned short adm1022_temp3[16];
static unsigned int adm1022_temp3_num;
module_param_array(adm1022_temp3, ushort, &adm1022_temp3_num, 0);
-MODULE_PARM_DESC(adm1022_temp3, "List of adapter,address pairs "
- "to enable 3rd temperature (ADM1022 only)");
+MODULE_PARM_DESC(adm1022_temp3,
+ "List of adapter,address pairs to enable 3rd temperature (ADM1022 only)");
/* Many THMC50 constants specified below */
@@ -312,8 +312,7 @@ static int thmc50_detect(struct i2c_client *client,
const char *type_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_debug("thmc50: detect failed, "
- "smbus byte data not supported!\n");
+ pr_debug("thmc50: detect failed, smbus byte data not supported!\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 523dd89ba498..d7b47abf37fe 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -155,8 +155,8 @@ static int tmp102_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_err(&client->dev, "adapter doesn't support SMBus word "
- "transactions\n");
+ dev_err(&client->dev,
+ "adapter doesn't support SMBus word transactions\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index c85f6967ccc3..a478454f690f 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -5,6 +5,9 @@
* Gabriel Konat, Sander Leget, Wouter Willems
* Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
*
+ * Cleanup and support for TMP431 and TMP432 by Guenter Roeck
+ * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ *
* 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
@@ -30,6 +33,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
@@ -40,9 +44,9 @@
#include <linux/sysfs.h>
/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
-enum chips { tmp401, tmp411 };
+enum chips { tmp401, tmp411, tmp431, tmp432 };
/*
* The TMP401 registers, note some registers have different addresses for
@@ -54,42 +58,84 @@ enum chips { tmp401, tmp411 };
#define TMP401_CONVERSION_RATE_READ 0x04
#define TMP401_CONVERSION_RATE_WRITE 0x0A
#define TMP401_TEMP_CRIT_HYST 0x21
-#define TMP401_CONSECUTIVE_ALERT 0x22
#define TMP401_MANUFACTURER_ID_REG 0xFE
#define TMP401_DEVICE_ID_REG 0xFF
-#define TMP411_N_FACTOR_REG 0x18
-
-static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 };
-static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 };
-static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E };
-static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 };
-static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D };
-static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 };
-/* These are called the THERM limit / hysteresis / mask in the datasheet */
-static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 };
-
-static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 };
-static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 };
-static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 };
-static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 };
+
+static const u8 TMP401_TEMP_MSB_READ[6][2] = {
+ { 0x00, 0x01 }, /* temp */
+ { 0x06, 0x08 }, /* low limit */
+ { 0x05, 0x07 }, /* high limit */
+ { 0x20, 0x19 }, /* therm (crit) limit */
+ { 0x30, 0x34 }, /* lowest */
+ { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_MSB_WRITE[6][2] = {
+ { 0, 0 }, /* temp (unused) */
+ { 0x0C, 0x0E }, /* low limit */
+ { 0x0B, 0x0D }, /* high limit */
+ { 0x20, 0x19 }, /* therm (crit) limit */
+ { 0x30, 0x34 }, /* lowest */
+ { 0x32, 0x36 }, /* highest */
+};
+
+static const u8 TMP401_TEMP_LSB[6][2] = {
+ { 0x15, 0x10 }, /* temp */
+ { 0x17, 0x14 }, /* low limit */
+ { 0x16, 0x13 }, /* high limit */
+ { 0, 0 }, /* therm (crit) limit (unused) */
+ { 0x31, 0x35 }, /* lowest */
+ { 0x33, 0x37 }, /* highest */
+};
+
+static const u8 TMP432_TEMP_MSB_READ[4][3] = {
+ { 0x00, 0x01, 0x23 }, /* temp */
+ { 0x06, 0x08, 0x16 }, /* low limit */
+ { 0x05, 0x07, 0x15 }, /* high limit */
+ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_MSB_WRITE[4][3] = {
+ { 0, 0, 0 }, /* temp - unused */
+ { 0x0C, 0x0E, 0x16 }, /* low limit */
+ { 0x0B, 0x0D, 0x15 }, /* high limit */
+ { 0x20, 0x19, 0x1A }, /* therm (crit) limit */
+};
+
+static const u8 TMP432_TEMP_LSB[3][3] = {
+ { 0x29, 0x10, 0x24 }, /* temp */
+ { 0x3E, 0x14, 0x18 }, /* low limit */
+ { 0x3D, 0x13, 0x17 }, /* high limit */
+};
+
+/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
+static const u8 TMP432_STATUS_REG[] = {
+ 0x1b, 0x36, 0x35, 0x37 };
/* Flags */
-#define TMP401_CONFIG_RANGE 0x04
-#define TMP401_CONFIG_SHUTDOWN 0x40
-#define TMP401_STATUS_LOCAL_CRIT 0x01
-#define TMP401_STATUS_REMOTE_CRIT 0x02
-#define TMP401_STATUS_REMOTE_OPEN 0x04
-#define TMP401_STATUS_REMOTE_LOW 0x08
-#define TMP401_STATUS_REMOTE_HIGH 0x10
-#define TMP401_STATUS_LOCAL_LOW 0x20
-#define TMP401_STATUS_LOCAL_HIGH 0x40
+#define TMP401_CONFIG_RANGE BIT(2)
+#define TMP401_CONFIG_SHUTDOWN BIT(6)
+#define TMP401_STATUS_LOCAL_CRIT BIT(0)
+#define TMP401_STATUS_REMOTE_CRIT BIT(1)
+#define TMP401_STATUS_REMOTE_OPEN BIT(2)
+#define TMP401_STATUS_REMOTE_LOW BIT(3)
+#define TMP401_STATUS_REMOTE_HIGH BIT(4)
+#define TMP401_STATUS_LOCAL_LOW BIT(5)
+#define TMP401_STATUS_LOCAL_HIGH BIT(6)
+
+/* On TMP432, each status has its own register */
+#define TMP432_STATUS_LOCAL BIT(0)
+#define TMP432_STATUS_REMOTE1 BIT(1)
+#define TMP432_STATUS_REMOTE2 BIT(2)
/* Manufacturer / Device ID's */
#define TMP401_MANUFACTURER_ID 0x55
#define TMP401_DEVICE_ID 0x11
-#define TMP411_DEVICE_ID 0x12
+#define TMP411A_DEVICE_ID 0x12
+#define TMP411B_DEVICE_ID 0x13
+#define TMP411C_DEVICE_ID 0x10
+#define TMP431_DEVICE_ID 0x31
+#define TMP432_DEVICE_ID 0x32
/*
* Driver data (common to all clients)
@@ -98,6 +144,8 @@ static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 };
static const struct i2c_device_id tmp401_id[] = {
{ "tmp401", tmp401 },
{ "tmp411", tmp411 },
+ { "tmp431", tmp431 },
+ { "tmp432", tmp432 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp401_id);
@@ -113,16 +161,13 @@ struct tmp401_data {
unsigned long last_updated; /* in jiffies */
enum chips kind;
+ unsigned int update_interval; /* in milliseconds */
+
/* register values */
- u8 status;
+ u8 status[4];
u8 config;
- u16 temp[2];
- u16 temp_low[2];
- u16 temp_high[2];
- u8 temp_crit[2];
+ u16 temp[6][3];
u8 temp_crit_hyst;
- u16 temp_lowest[2];
- u16 temp_highest[2];
};
/*
@@ -136,31 +181,10 @@ static int tmp401_register_to_temp(u16 reg, u8 config)
if (config & TMP401_CONFIG_RANGE)
temp -= 64 * 256;
- return (temp * 625 + 80) / 160;
-}
-
-static u16 tmp401_temp_to_register(long temp, u8 config)
-{
- if (config & TMP401_CONFIG_RANGE) {
- temp = clamp_val(temp, -64000, 191000);
- temp += 64000;
- } else
- temp = clamp_val(temp, 0, 127000);
-
- return (temp * 160 + 312) / 625;
-}
-
-static int tmp401_crit_register_to_temp(u8 reg, u8 config)
-{
- int temp = reg;
-
- if (config & TMP401_CONFIG_RANGE)
- temp -= 64;
-
- return temp * 1000;
+ return DIV_ROUND_CLOSEST(temp * 125, 32);
}
-static u8 tmp401_crit_temp_to_register(long temp, u8 config)
+static u16 tmp401_temp_to_register(long temp, u8 config, int zbits)
{
if (config & TMP401_CONFIG_RANGE) {
temp = clamp_val(temp, -64000, 191000);
@@ -168,113 +192,127 @@ static u8 tmp401_crit_temp_to_register(long temp, u8 config)
} else
temp = clamp_val(temp, 0, 127000);
- return (temp + 500) / 1000;
+ return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
}
-static struct tmp401_data *tmp401_update_device_reg16(
- struct i2c_client *client, struct tmp401_data *data)
+static int tmp401_update_device_reg16(struct i2c_client *client,
+ struct tmp401_data *data)
{
- int i;
-
- for (i = 0; i < 2; i++) {
- /*
- * High byte must be read first immediately followed
- * by the low byte
- */
- data->temp[i] = i2c_smbus_read_byte_data(client,
- TMP401_TEMP_MSB[i]) << 8;
- data->temp[i] |= i2c_smbus_read_byte_data(client,
- TMP401_TEMP_LSB[i]);
- data->temp_low[i] = i2c_smbus_read_byte_data(client,
- TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
- data->temp_low[i] |= i2c_smbus_read_byte_data(client,
- TMP401_TEMP_LOW_LIMIT_LSB[i]);
- data->temp_high[i] = i2c_smbus_read_byte_data(client,
- TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
- data->temp_high[i] |= i2c_smbus_read_byte_data(client,
- TMP401_TEMP_HIGH_LIMIT_LSB[i]);
- data->temp_crit[i] = i2c_smbus_read_byte_data(client,
- TMP401_TEMP_CRIT_LIMIT[i]);
-
- if (data->kind == tmp411) {
- data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
- TMP411_TEMP_LOWEST_MSB[i]) << 8;
- data->temp_lowest[i] |= i2c_smbus_read_byte_data(
- client, TMP411_TEMP_LOWEST_LSB[i]);
-
- data->temp_highest[i] = i2c_smbus_read_byte_data(
- client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
- data->temp_highest[i] |= i2c_smbus_read_byte_data(
- client, TMP411_TEMP_HIGHEST_LSB[i]);
+ int i, j, val;
+ int num_regs = data->kind == tmp411 ? 6 : 4;
+ int num_sensors = data->kind == tmp432 ? 3 : 2;
+
+ for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */
+ for (j = 0; j < num_regs; j++) { /* temp / low / ... */
+ u8 regaddr;
+ /*
+ * High byte must be read first immediately followed
+ * by the low byte
+ */
+ regaddr = data->kind == tmp432 ?
+ TMP432_TEMP_MSB_READ[j][i] :
+ TMP401_TEMP_MSB_READ[j][i];
+ val = i2c_smbus_read_byte_data(client, regaddr);
+ if (val < 0)
+ return val;
+ data->temp[j][i] = val << 8;
+ if (j == 3) /* crit is msb only */
+ continue;
+ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i]
+ : TMP401_TEMP_LSB[j][i];
+ val = i2c_smbus_read_byte_data(client, regaddr);
+ if (val < 0)
+ return val;
+ data->temp[j][i] |= val;
}
}
- return data;
+ return 0;
}
static struct tmp401_data *tmp401_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct tmp401_data *data = i2c_get_clientdata(client);
+ struct tmp401_data *ret = data;
+ int i, val;
+ unsigned long next_update;
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
- data->config = i2c_smbus_read_byte_data(client,
- TMP401_CONFIG_READ);
- tmp401_update_device_reg16(client, data);
+ next_update = data->last_updated +
+ msecs_to_jiffies(data->update_interval) + 1;
+ if (time_after(jiffies, next_update) || !data->valid) {
+ if (data->kind != tmp432) {
+ /*
+ * The driver uses the TMP432 status format internally.
+ * Convert status to TMP432 format for other chips.
+ */
+ val = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->status[0] =
+ (val & TMP401_STATUS_REMOTE_OPEN) >> 1;
+ data->status[1] =
+ ((val & TMP401_STATUS_REMOTE_LOW) >> 2) |
+ ((val & TMP401_STATUS_LOCAL_LOW) >> 5);
+ data->status[2] =
+ ((val & TMP401_STATUS_REMOTE_HIGH) >> 3) |
+ ((val & TMP401_STATUS_LOCAL_HIGH) >> 6);
+ data->status[3] = val & (TMP401_STATUS_LOCAL_CRIT
+ | TMP401_STATUS_REMOTE_CRIT);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(data->status); i++) {
+ val = i2c_smbus_read_byte_data(client,
+ TMP432_STATUS_REG[i]);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->status[i] = val;
+ }
+ }
- data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
- TMP401_TEMP_CRIT_HYST);
+ val = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->config = val;
+ val = tmp401_update_device_reg16(client, data);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ val = i2c_smbus_read_byte_data(client, TMP401_TEMP_CRIT_HYST);
+ if (val < 0) {
+ ret = ERR_PTR(val);
+ goto abort;
+ }
+ data->temp_crit_hyst = val;
data->last_updated = jiffies;
data->valid = 1;
}
+abort:
mutex_unlock(&data->update_lock);
-
- return data;
-}
-
-static ssize_t show_temp_value(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
-
- return sprintf(buf, "%d\n",
- tmp401_register_to_temp(data->temp[index], data->config));
-}
-
-static ssize_t show_temp_min(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
-
- return sprintf(buf, "%d\n",
- tmp401_register_to_temp(data->temp_low[index], data->config));
+ return ret;
}
-static ssize_t show_temp_max(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
- int index = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int index = to_sensor_dev_attr_2(devattr)->index;
struct tmp401_data *data = tmp401_update_device(dev);
- return sprintf(buf, "%d\n",
- tmp401_register_to_temp(data->temp_high[index], data->config));
-}
-
-static ssize_t show_temp_crit(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
return sprintf(buf, "%d\n",
- tmp401_crit_register_to_temp(data->temp_crit[index],
- data->config));
+ tmp401_register_to_temp(data->temp[nr][index], data->config));
}
static ssize_t show_temp_crit_hyst(struct device *dev,
@@ -283,122 +321,60 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
int temp, index = to_sensor_dev_attr(devattr)->index;
struct tmp401_data *data = tmp401_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
mutex_lock(&data->update_lock);
- temp = tmp401_crit_register_to_temp(data->temp_crit[index],
- data->config);
+ temp = tmp401_register_to_temp(data->temp[3][index], data->config);
temp -= data->temp_crit_hyst * 1000;
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", temp);
}
-static ssize_t show_temp_lowest(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
-
- return sprintf(buf, "%d\n",
- tmp401_register_to_temp(data->temp_lowest[index],
- data->config));
-}
-
-static ssize_t show_temp_highest(struct device *dev,
- struct device_attribute *devattr, char *buf)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
-
- return sprintf(buf, "%d\n",
- tmp401_register_to_temp(data->temp_highest[index],
- data->config));
-}
-
static ssize_t show_status(struct device *dev,
struct device_attribute *devattr, char *buf)
{
- int mask = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
-
- if (data->status & mask)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t store_temp_min(struct device *dev, struct device_attribute
- *devattr, const char *buf, size_t count)
-{
- int index = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int mask = to_sensor_dev_attr_2(devattr)->index;
struct tmp401_data *data = tmp401_update_device(dev);
- long val;
- u16 reg;
-
- if (kstrtol(buf, 10, &val))
- return -EINVAL;
-
- reg = tmp401_temp_to_register(val, data->config);
-
- mutex_lock(&data->update_lock);
-
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
-
- data->temp_low[index] = reg;
- mutex_unlock(&data->update_lock);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
- return count;
+ return sprintf(buf, "%d\n", !!(data->status[nr] & mask));
}
-static ssize_t store_temp_max(struct device *dev, struct device_attribute
- *devattr, const char *buf, size_t count)
+static ssize_t store_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
- int index = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int index = to_sensor_dev_attr_2(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
struct tmp401_data *data = tmp401_update_device(dev);
long val;
u16 reg;
+ u8 regaddr;
- if (kstrtol(buf, 10, &val))
- return -EINVAL;
-
- reg = tmp401_temp_to_register(val, data->config);
-
- mutex_lock(&data->update_lock);
-
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
-
- data->temp_high[index] = reg;
-
- mutex_unlock(&data->update_lock);
-
- return count;
-}
-
-static ssize_t store_temp_crit(struct device *dev, struct device_attribute
- *devattr, const char *buf, size_t count)
-{
- int index = to_sensor_dev_attr(devattr)->index;
- struct tmp401_data *data = tmp401_update_device(dev);
- long val;
- u8 reg;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
if (kstrtol(buf, 10, &val))
return -EINVAL;
- reg = tmp401_crit_temp_to_register(val, data->config);
+ reg = tmp401_temp_to_register(val, data->config, nr == 3 ? 8 : 4);
mutex_lock(&data->update_lock);
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_CRIT_LIMIT[index], reg);
-
- data->temp_crit[index] = reg;
+ regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index]
+ : TMP401_TEMP_MSB_WRITE[nr][index];
+ i2c_smbus_write_byte_data(client, regaddr, reg >> 8);
+ if (nr != 3) {
+ regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index]
+ : TMP401_TEMP_LSB[nr][index];
+ i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF);
+ }
+ data->temp[nr][index] = reg;
mutex_unlock(&data->update_lock);
@@ -413,6 +389,9 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
long val;
u8 reg;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
if (kstrtol(buf, 10, &val))
return -EINVAL;
@@ -422,13 +401,12 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
val = clamp_val(val, 0, 127000);
mutex_lock(&data->update_lock);
- temp = tmp401_crit_register_to_temp(data->temp_crit[index],
- data->config);
+ temp = tmp401_register_to_temp(data->temp[3][index], data->config);
val = clamp_val(val, temp - 255000, temp);
reg = ((temp - val) + 500) / 1000;
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP401_TEMP_CRIT_HYST, reg);
+ i2c_smbus_write_byte_data(to_i2c_client(dev), TMP401_TEMP_CRIT_HYST,
+ reg);
data->temp_crit_hyst = reg;
@@ -445,54 +423,130 @@ static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
static ssize_t reset_temp_history(struct device *dev,
struct device_attribute *devattr, const char *buf, size_t count)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tmp401_data *data = i2c_get_clientdata(client);
long val;
if (kstrtol(buf, 10, &val))
return -EINVAL;
if (val != 1) {
- dev_err(dev, "temp_reset_history value %ld not"
- " supported. Use 1 to reset the history!\n", val);
+ dev_err(dev,
+ "temp_reset_history value %ld not supported. Use 1 to reset the history!\n",
+ val);
return -EINVAL;
}
- i2c_smbus_write_byte_data(to_i2c_client(dev),
- TMP411_TEMP_LOWEST_MSB[0], val);
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(client, TMP401_TEMP_MSB_WRITE[5][0], val);
+ data->valid = 0;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_update_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tmp401_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%u\n", data->update_interval);
+}
+
+static ssize_t set_update_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tmp401_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ int err, rate;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err)
+ return err;
+
+ /*
+ * For valid rates, interval can be calculated as
+ * interval = (1 << (7 - rate)) * 125;
+ * Rounded rate is therefore
+ * rate = 7 - __fls(interval * 4 / (125 * 3));
+ * Use clamp_val() to avoid overflows, and to ensure valid input
+ * for __fls.
+ */
+ val = clamp_val(val, 125, 16000);
+ rate = 7 - __fls(val * 4 / (125 * 3));
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate);
+ data->update_interval = (1 << (7 - rate)) * 125;
+ mutex_unlock(&data->update_lock);
return count;
}
-static struct sensor_device_attribute tmp401_attr[] = {
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
- SENSOR_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
- store_temp_min, 0),
- SENSOR_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
- store_temp_max, 0),
- SENSOR_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_crit,
- store_temp_crit, 0),
- SENSOR_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_crit_hyst,
- store_temp_crit_hyst, 0),
- SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_LOCAL_LOW),
- SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_LOCAL_HIGH),
- SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_LOCAL_CRIT),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
- SENSOR_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
- store_temp_min, 1),
- SENSOR_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
- store_temp_max, 1),
- SENSOR_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp_crit,
- store_temp_crit, 1),
- SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
- SENSOR_ATTR(temp2_fault, S_IRUGO, show_status, NULL,
- TMP401_STATUS_REMOTE_OPEN),
- SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_REMOTE_LOW),
- SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_REMOTE_HIGH),
- SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_status, NULL,
- TMP401_STATUS_REMOTE_CRIT),
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 3, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO,
+ show_temp_crit_hyst, store_temp_crit_hyst, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_status, NULL,
+ 1, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_status, NULL,
+ 2, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_status, NULL,
+ 3, TMP432_STATUS_LOCAL);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 3, 1);
+static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+ NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_status, NULL,
+ 0, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_status, NULL,
+ 1, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL,
+ 2, TMP432_STATUS_REMOTE1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL,
+ 3, TMP432_STATUS_REMOTE1);
+
+static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
+ set_update_interval);
+
+static struct attribute *tmp401_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+
+ &dev_attr_update_interval.attr,
+
+ NULL
+};
+
+static const struct attribute_group tmp401_group = {
+ .attrs = tmp401_attributes,
};
/*
@@ -502,12 +556,60 @@ static struct sensor_device_attribute tmp401_attr[] = {
* minimum and maximum register reset for both the local
* and remote channels.
*/
-static struct sensor_device_attribute tmp411_attr[] = {
- SENSOR_ATTR(temp1_highest, S_IRUGO, show_temp_highest, NULL, 0),
- SENSOR_ATTR(temp1_lowest, S_IRUGO, show_temp_lowest, NULL, 0),
- SENSOR_ATTR(temp2_highest, S_IRUGO, show_temp_highest, NULL, 1),
- SENSOR_ATTR(temp2_lowest, S_IRUGO, show_temp_lowest, NULL, 1),
- SENSOR_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history, 0),
+static SENSOR_DEVICE_ATTR_2(temp1_lowest, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_highest, S_IRUGO, show_temp, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_lowest, S_IRUGO, show_temp, NULL, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_highest, S_IRUGO, show_temp, NULL, 5, 1);
+static SENSOR_DEVICE_ATTR(temp_reset_history, S_IWUSR, NULL, reset_temp_history,
+ 0);
+
+static struct attribute *tmp411_attributes[] = {
+ &sensor_dev_attr_temp1_highest.dev_attr.attr,
+ &sensor_dev_attr_temp1_lowest.dev_attr.attr,
+ &sensor_dev_attr_temp2_highest.dev_attr.attr,
+ &sensor_dev_attr_temp2_lowest.dev_attr.attr,
+ &sensor_dev_attr_temp_reset_history.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group tmp411_group = {
+ .attrs = tmp411_attributes,
+};
+
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
+ store_temp, 3, 2);
+static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst,
+ NULL, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_status, NULL,
+ 0, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_status, NULL,
+ 1, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_status, NULL,
+ 2, TMP432_STATUS_REMOTE2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_status, NULL,
+ 3, TMP432_STATUS_REMOTE2);
+
+static struct attribute *tmp432_attributes[] = {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+
+ NULL
+};
+
+static const struct attribute_group tmp432_group = {
+ .attrs = tmp432_attributes,
};
/*
@@ -517,9 +619,11 @@ static struct sensor_device_attribute tmp411_attr[] = {
static void tmp401_init_client(struct i2c_client *client)
{
int config, config_orig;
+ struct tmp401_data *data = i2c_get_clientdata(client);
/* Set the conversion rate to 2 Hz */
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+ data->update_interval = 500;
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
@@ -554,11 +658,35 @@ static int tmp401_detect(struct i2c_client *client,
switch (reg) {
case TMP401_DEVICE_ID:
+ if (client->addr != 0x4c)
+ return -ENODEV;
kind = tmp401;
break;
- case TMP411_DEVICE_ID:
+ case TMP411A_DEVICE_ID:
+ if (client->addr != 0x4c)
+ return -ENODEV;
+ kind = tmp411;
+ break;
+ case TMP411B_DEVICE_ID:
+ if (client->addr != 0x4d)
+ return -ENODEV;
kind = tmp411;
break;
+ case TMP411C_DEVICE_ID:
+ if (client->addr != 0x4e)
+ return -ENODEV;
+ kind = tmp411;
+ break;
+ case TMP431_DEVICE_ID:
+ if (client->addr == 0x4e)
+ return -ENODEV;
+ kind = tmp431;
+ break;
+ case TMP432_DEVICE_ID:
+ if (client->addr == 0x4e)
+ return -ENODEV;
+ kind = tmp432;
+ break;
default:
return -ENODEV;
}
@@ -579,20 +707,19 @@ static int tmp401_detect(struct i2c_client *client,
static int tmp401_remove(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct tmp401_data *data = i2c_get_clientdata(client);
- int i;
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
- for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
- device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+ sysfs_remove_group(&dev->kobj, &tmp401_group);
- if (data->kind == tmp411) {
- for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
- device_remove_file(&client->dev,
- &tmp411_attr[i].dev_attr);
- }
+ if (data->kind == tmp411)
+ sysfs_remove_group(&dev->kobj, &tmp411_group);
+
+ if (data->kind == tmp432)
+ sysfs_remove_group(&dev->kobj, &tmp432_group);
return 0;
}
@@ -600,12 +727,12 @@ static int tmp401_remove(struct i2c_client *client)
static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int i, err = 0;
+ struct device *dev = &client->dev;
+ int err;
struct tmp401_data *data;
- const char *names[] = { "TMP401", "TMP411" };
+ const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
- data = devm_kzalloc(&client->dev, sizeof(struct tmp401_data),
- GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -617,31 +744,32 @@ static int tmp401_probe(struct i2c_client *client,
tmp401_init_client(client);
/* Register sysfs hooks */
- for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
- err = device_create_file(&client->dev,
- &tmp401_attr[i].dev_attr);
+ err = sysfs_create_group(&dev->kobj, &tmp401_group);
+ if (err)
+ return err;
+
+ /* Register additional tmp411 sysfs hooks */
+ if (data->kind == tmp411) {
+ err = sysfs_create_group(&dev->kobj, &tmp411_group);
if (err)
goto exit_remove;
}
- /* Register additional tmp411 sysfs hooks */
- if (data->kind == tmp411) {
- for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
- err = device_create_file(&client->dev,
- &tmp411_attr[i].dev_attr);
- if (err)
- goto exit_remove;
- }
+ /* Register additional tmp432 sysfs hooks */
+ if (data->kind == tmp432) {
+ err = sysfs_create_group(&dev->kobj, &tmp432_group);
+ if (err)
+ goto exit_remove;
}
- data->hwmon_dev = hwmon_device_register(&client->dev);
+ data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
data->hwmon_dev = NULL;
goto exit_remove;
}
- dev_info(&client->dev, "Detected TI %s chip\n", names[data->kind]);
+ dev_info(dev, "Detected TI %s chip\n", names[data->kind]);
return 0;
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 6a8ded29f1ed..964c1d688274 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -208,8 +208,8 @@ static int tmp421_init_client(struct i2c_client *client)
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1);
if (config < 0) {
- dev_err(&client->dev, "Could not read configuration"
- " register (%d)\n", config);
+ dev_err(&client->dev,
+ "Could not read configuration register (%d)\n", config);
return -ENODEV;
}
@@ -322,6 +322,5 @@ static struct i2c_driver tmp421_driver = {
module_i2c_driver(tmp421_driver);
MODULE_AUTHOR("Andre Prendel <andre.prendel@gmx.de>");
-MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor"
- " driver");
+MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 3123b30208c5..c9dcce8c3dc3 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -125,7 +125,7 @@ static const u8 VIA686A_REG_TEMP_HYST[] = { 0x3a, 0x3e, 0x1e };
* (These conversions were contributed by Jonathan Teh Soon Yew
* <j.teh@iname.com>)
*/
-static inline u8 IN_TO_REG(long val, int inNum)
+static inline u8 IN_TO_REG(long val, int in_num)
{
/*
* To avoid floating point, we multiply constants by 10 (100 for +12V).
@@ -134,29 +134,29 @@ static inline u8 IN_TO_REG(long val, int inNum)
* by an additional 10000 (100000 for +12V): 1000 for val and 10 (100)
* for the constants.
*/
- if (inNum <= 1)
+ if (in_num <= 1)
return (u8) clamp_val((val * 21024 - 1205000) / 250000, 0, 255);
- else if (inNum == 2)
+ else if (in_num == 2)
return (u8) clamp_val((val * 15737 - 1205000) / 250000, 0, 255);
- else if (inNum == 3)
+ else if (in_num == 3)
return (u8) clamp_val((val * 10108 - 1205000) / 250000, 0, 255);
else
return (u8) clamp_val((val * 41714 - 12050000) / 2500000, 0,
255);
}
-static inline long IN_FROM_REG(u8 val, int inNum)
+static inline long IN_FROM_REG(u8 val, int in_num)
{
/*
* To avoid floating point, we multiply constants by 10 (100 for +12V).
* We also multiply them by 1000 because we want 0.001V/bit for the
* output value. Rounding is done.
*/
- if (inNum <= 1)
+ if (in_num <= 1)
return (long) ((250000 * val + 1330000 + 21024 / 2) / 21024);
- else if (inNum == 2)
+ else if (in_num == 2)
return (long) ((250000 * val + 1330000 + 15737 / 2) / 15737);
- else if (inNum == 3)
+ else if (in_num == 3)
return (long) ((250000 * val + 1330000 + 10108 / 2) / 10108);
else
return (long) ((2500000 * val + 13300000 + 41714 / 2) / 41714);
@@ -210,10 +210,10 @@ static inline u8 FAN_TO_REG(long rpm, int div)
* VIA register values 0-255. I *10 before rounding, so we get tenth-degree
* precision. (I could have done all 1024 values for our 10-bit readings,
* but the function is very linear in the useful range (0-80 deg C), so
- * we'll just use linear interpolation for 10-bit readings.) So, tempLUT
+ * we'll just use linear interpolation for 10-bit readings.) So, temp_lut
* is the temp at via register values 0-255:
*/
-static const s16 tempLUT[] = {
+static const s16 temp_lut[] = {
-709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519,
-503, -487, -471, -456, -442, -428, -414, -400, -387, -375,
-362, -350, -339, -327, -316, -305, -295, -285, -275, -265,
@@ -261,7 +261,7 @@ static const s16 tempLUT[] = {
* - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01)
* Note that n=161:
*/
-static const u8 viaLUT[] = {
+static const u8 via_lut[] = {
12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40,
41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66,
@@ -284,26 +284,26 @@ static const u8 viaLUT[] = {
*/
static inline u8 TEMP_TO_REG(long val)
{
- return viaLUT[val <= -50000 ? 0 : val >= 110000 ? 160 :
+ return via_lut[val <= -50000 ? 0 : val >= 110000 ? 160 :
(val < 0 ? val - 500 : val + 500) / 1000 + 50];
}
/* for 8-bit temperature hyst and over registers */
-#define TEMP_FROM_REG(val) ((long)tempLUT[val] * 100)
+#define TEMP_FROM_REG(val) ((long)temp_lut[val] * 100)
/* for 10-bit temperature readings */
static inline long TEMP_FROM_REG10(u16 val)
{
- u16 eightBits = val >> 2;
- u16 twoBits = val & 3;
+ u16 eight_bits = val >> 2;
+ u16 two_bits = val & 3;
/* no interpolation for these */
- if (twoBits == 0 || eightBits == 255)
- return TEMP_FROM_REG(eightBits);
+ if (two_bits == 0 || eight_bits == 255)
+ return TEMP_FROM_REG(eight_bits);
/* do some linear interpolation */
- return (tempLUT[eightBits] * (4 - twoBits) +
- tempLUT[eightBits + 1] * twoBits) * 25;
+ return (temp_lut[eight_bits] * (4 - two_bits) +
+ temp_lut[eight_bits + 1] * two_bits) * 25;
}
#define DIV_FROM_REG(val) (1 << (val))
@@ -889,8 +889,8 @@ static int via686a_pci_probe(struct pci_dev *dev,
address = val & ~(VIA686A_EXTENT - 1);
if (address == 0) {
- dev_err(&dev->dev, "base address not set - upgrade BIOS "
- "or use force_addr=0xaddr\n");
+ dev_err(&dev->dev,
+ "base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
@@ -899,8 +899,9 @@ static int via686a_pci_probe(struct pci_dev *dev,
return -ENODEV;
if (!(val & 0x0001)) {
if (!force_addr) {
- dev_warn(&dev->dev, "Sensors disabled, enable "
- "with force_addr=0x%x\n", address);
+ dev_warn(&dev->dev,
+ "Sensors disabled, enable with force_addr=0x%x\n",
+ address);
return -ENODEV;
}
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index dcc62f80f67b..6b2f1a42b3ff 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -571,8 +571,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
break;
default:
count = -EINVAL;
- dev_warn(dev, "fan div value %ld not supported. "
- "Choose one of 1, 2, 4, or 8.\n", val);
+ dev_warn(dev,
+ "fan div value %ld not supported. Choose one of 1, 2, 4, or 8.\n",
+ val);
goto EXIT;
}
vt1211_write8(data, VT1211_REG_FAN_DIV,
@@ -674,8 +675,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
break;
default:
count = -EINVAL;
- dev_warn(dev, "pwm mode %ld not supported. "
- "Choose one of 0 or 2.\n", val);
+ dev_warn(dev,
+ "pwm mode %ld not supported. Choose one of 0 or 2.\n",
+ val);
goto EXIT;
}
vt1211_write8(data, VT1211_REG_PWM_CTL,
@@ -700,8 +702,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
if (val < 1 || val > 7) {
count = -EINVAL;
- dev_warn(dev, "temp channel %ld not supported. "
- "Choose a value between 1 and 7.\n", val);
+ dev_warn(dev,
+ "temp channel %ld not supported. Choose a value between 1 and 7.\n",
+ val);
goto EXIT;
}
if (!ISTEMP(val - 1, data->uch_config)) {
@@ -1325,15 +1328,15 @@ static int __init vt1211_init(void)
if ((uch_config < -1) || (uch_config > 31)) {
err = -EINVAL;
- pr_warn("Invalid UCH configuration %d. "
- "Choose a value between 0 and 31.\n", uch_config);
+ pr_warn("Invalid UCH configuration %d. Choose a value between 0 and 31.\n",
+ uch_config);
goto EXIT;
}
if ((int_mode < -1) || (int_mode > 0)) {
err = -EINVAL;
- pr_warn("Invalid interrupt mode %d. "
- "Only mode 0 is supported.\n", int_mode);
+ pr_warn("Invalid interrupt mode %d. Only mode 0 is supported.\n",
+ int_mode);
goto EXIT;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 988a2a796764..0e7017841f7d 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -573,8 +573,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
data->fan_div[nr] = 3;
break;
default:
- dev_err(dev, "fan_div value %ld not supported. "
- "Choose one of 1, 2, 4 or 8!\n", val);
+ dev_err(dev,
+ "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n",
+ val);
mutex_unlock(&data->update_lock);
return -EINVAL;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 0a89211c25f6..016027229e81 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -840,8 +840,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
&& (reg >= 0xff || (sio_data->kind == nct6775
&& reg == 0x00))
&& data->fan_div[i] < 0x07) {
- dev_dbg(dev, "Increasing fan%d "
- "clock divider from %u to %u\n",
+ dev_dbg(dev,
+ "Increasing fan%d clock divider from %u to %u\n",
i + 1, div_from_reg(data->fan_div[i]),
div_from_reg(data->fan_div[i] + 1));
data->fan_div[i]++;
@@ -1110,9 +1110,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
*/
data->fan_min[nr] = 254;
new_div = 7; /* 128 == (1 << 7) */
- dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
- "minimum\n", nr + 1, val,
- data->fan_from_reg_min(254, 7));
+ dev_warn(dev,
+ "fan%u low limit %lu below minimum %u, set to minimum\n",
+ nr + 1, val, data->fan_from_reg_min(254, 7));
} else if (!reg) {
/*
* Speed above this value cannot possibly be represented,
@@ -1120,9 +1120,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
*/
data->fan_min[nr] = 1;
new_div = 0; /* 1 == (1 << 0) */
- dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
- "maximum\n", nr + 1, val,
- data->fan_from_reg_min(1, 0));
+ dev_warn(dev,
+ "fan%u low limit %lu above maximum %u, set to maximum\n",
+ nr + 1, val, data->fan_from_reg_min(1, 0));
} else {
/*
* Automatically pick the best divider, i.e. the one such
@@ -2396,15 +2396,15 @@ static int w83627ehf_probe(struct platform_device *pdev)
en_vrm10 = superio_inb(sio_data->sioreg,
SIO_REG_EN_VRM10);
if ((en_vrm10 & 0x08) && data->vrm == 90) {
- dev_warn(dev, "Setting VID input "
- "voltage to TTL\n");
+ dev_warn(dev,
+ "Setting VID input voltage to TTL\n");
superio_outb(sio_data->sioreg,
SIO_REG_EN_VRM10,
en_vrm10 & ~0x08);
} else if (!(en_vrm10 & 0x08)
&& data->vrm == 100) {
- dev_warn(dev, "Setting VID input "
- "voltage to VRM10\n");
+ dev_warn(dev,
+ "Setting VID input voltage to VRM10\n");
superio_outb(sio_data->sioreg,
SIO_REG_EN_VRM10,
en_vrm10 | 0x08);
@@ -2420,8 +2420,8 @@ static int w83627ehf_probe(struct platform_device *pdev)
if (err)
goto exit_release;
} else {
- dev_info(dev, "VID pins in output mode, CPU VID not "
- "available\n");
+ dev_info(dev,
+ "VID pins in output mode, CPU VID not available\n");
}
}
@@ -2795,8 +2795,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
/* Activate logical device if needed */
val = superio_inb(sioaddr, SIO_REG_ENABLE);
if (!(val & 0x01)) {
- pr_warn("Forcibly enabling Super-I/O. "
- "Sensor is probably unusable.\n");
+ pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
}
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index aeec5b1d81c9..f9d513949a38 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -64,8 +64,8 @@ enum chips { w83781d, w83782d, w83783s, as99127f };
/* Insmod parameters */
static unsigned short force_subclients[4];
module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
- "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+ "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
static bool reset;
module_param(reset, bool, 0);
@@ -826,8 +826,9 @@ store_sensor(struct device *dev, struct device_attribute *da,
data->sens[nr] = val;
break;
case W83781D_DEFAULT_BETA:
- dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
- "instead\n", W83781D_DEFAULT_BETA);
+ dev_warn(dev,
+ "Sensor type %d is deprecated, please use 4 instead\n",
+ W83781D_DEFAULT_BETA);
/* fall through */
case 4: /* thermistor */
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
@@ -874,8 +875,8 @@ w83781d_detect_subclients(struct i2c_client *new_client)
for (i = 2; i <= 3; i++) {
if (force_subclients[i] < 0x48 ||
force_subclients[i] > 0x4f) {
- dev_err(&new_client->dev, "Invalid subclient "
- "address %d; must be 0x48-0x4f\n",
+ dev_err(&new_client->dev,
+ "Invalid subclient address %d; must be 0x48-0x4f\n",
force_subclients[i]);
err = -EINVAL;
goto ERROR_SC_1;
@@ -910,9 +911,9 @@ w83781d_detect_subclients(struct i2c_client *new_client)
for (i = 0; i < num_sc; i++) {
data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
if (!data->lm75[i]) {
- dev_err(&new_client->dev, "Subclient %d "
- "registration at address 0x%x "
- "failed.\n", i, sc_addr[i]);
+ dev_err(&new_client->dev,
+ "Subclient %d registration at address 0x%x failed.\n",
+ i, sc_addr[i]);
err = -ENOMEM;
if (i == 1)
goto ERROR_SC_3;
@@ -1176,8 +1177,9 @@ w83781d_detect(struct i2c_client *client, struct i2c_board_info *info)
goto err_nodev;
if (val1 <= 0x30 && w83781d_alias_detect(client, val1)) {
- dev_dbg(&adapter->dev, "Device at 0x%02x appears to "
- "be the same as ISA device\n", address);
+ dev_dbg(&adapter->dev,
+ "Device at 0x%02x appears to be the same as ISA device\n",
+ address);
goto err_nodev;
}
@@ -1367,8 +1369,8 @@ w83781d_init_device(struct device *dev)
* as I see very little reason why this would be needed at
* all.
*/
- dev_info(dev, "If reset=1 solved a problem you were "
- "having, please report!\n");
+ dev_info(dev,
+ "If reset=1 solved a problem you were having, please report!\n");
/* save these registers */
i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
@@ -1425,8 +1427,8 @@ w83781d_init_device(struct device *dev)
/* Enable temp2 */
tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
if (tmp & 0x01) {
- dev_warn(dev, "Enabling temp2, readings "
- "might not make sense\n");
+ dev_warn(dev,
+ "Enabling temp2, readings might not make sense\n");
w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
tmp & 0xfe);
}
@@ -1436,8 +1438,8 @@ w83781d_init_device(struct device *dev)
tmp = w83781d_read_value(data,
W83781D_REG_TEMP3_CONFIG);
if (tmp & 0x01) {
- dev_warn(dev, "Enabling temp3, "
- "readings might not make sense\n");
+ dev_warn(dev,
+ "Enabling temp3, readings might not make sense\n");
w83781d_write_value(data,
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
}
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 38dddddf8875..a3feee332e20 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -56,8 +56,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
static unsigned short force_subclients[4];
module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
- "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+ "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
static bool reset;
module_param(reset, bool, 0);
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 5cb83ddf2cc6..0b804895be43 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -54,8 +54,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
static unsigned short force_subclients[4];
module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
- "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+ "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
static bool init;
module_param(init, bool, 0);
@@ -951,8 +951,8 @@ w83792d_detect_subclients(struct i2c_client *new_client)
for (i = 2; i <= 3; i++) {
if (force_subclients[i] < 0x48 ||
force_subclients[i] > 0x4f) {
- dev_err(&new_client->dev, "invalid subclient "
- "address %d; must be 0x48-0x4f\n",
+ dev_err(&new_client->dev,
+ "invalid subclient address %d; must be 0x48-0x4f\n",
force_subclients[i]);
err = -ENODEV;
goto ERROR_SC_0;
@@ -969,8 +969,9 @@ w83792d_detect_subclients(struct i2c_client *new_client)
if (!(val & 0x80)) {
if ((data->lm75[0] != NULL) &&
((val & 0x7) == ((val >> 4) & 0x7))) {
- dev_err(&new_client->dev, "duplicate addresses 0x%x, "
- "use force_subclient\n", data->lm75[0]->addr);
+ dev_err(&new_client->dev,
+ "duplicate addresses 0x%x, use force_subclient\n",
+ data->lm75[0]->addr);
err = -ENODEV;
goto ERROR_SC_1;
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 660427520c53..b0c30a546ff2 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -59,8 +59,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
static unsigned short force_subclients[4];
module_param_array(force_subclients, short, NULL, 0);
-MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
- "{bus, clientaddr, subclientaddr1, subclientaddr2}");
+MODULE_PARM_DESC(force_subclients,
+ "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}");
static bool reset;
module_param(reset, bool, 0);
@@ -1921,8 +1921,8 @@ static int w83793_probe(struct i2c_client *client,
}
if (i == ARRAY_SIZE(watchdog_minors)) {
data->watchdog_miscdev.minor = 0;
- dev_warn(&client->dev, "Couldn't register watchdog chardev "
- "(due to no free minor)\n");
+ dev_warn(&client->dev,
+ "Couldn't register watchdog chardev (due to no free minor)\n");
}
mutex_unlock(&watchdog_data_mutex);
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index e226096148eb..908209d24664 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -2120,11 +2120,12 @@ static void w83795_check_dynamic_in_limits(struct i2c_client *client)
&w83795_in[i][3].dev_attr.attr,
S_IRUGO);
if (err_max || err_min)
- dev_warn(&client->dev, "Failed to set in%d limits "
- "read-only (%d, %d)\n", i, err_max, err_min);
+ dev_warn(&client->dev,
+ "Failed to set in%d limits read-only (%d, %d)\n",
+ i, err_max, err_min);
else
- dev_info(&client->dev, "in%d limits set dynamically "
- "from VID\n", i);
+ dev_info(&client->dev,
+ "in%d limits set dynamically from VID\n", i);
}
}
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index db713c0dfba4..461a0d739d75 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -416,6 +416,8 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock)
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "%s: can't power on device\n", __func__);
+ pm_runtime_put_noidle(dev);
+ module_put(dev->driver->owner);
return ret;
}
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0ceb6e1b0f65..e3085c487ace 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -182,7 +182,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
adap->algo = &i2c_dw_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
- ACPI_HANDLE_SET(&adap->dev, ACPI_HANDLE(&pdev->dev));
r = i2c_add_numbered_adapter(adap);
if (r) {
diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c
index 261d7db437e2..8acef657abf3 100644
--- a/drivers/i2c/busses/i2c-puv3.c
+++ b/drivers/i2c/busses/i2c-puv3.c
@@ -199,7 +199,7 @@ static int puv3_i2c_probe(struct platform_device *pdev)
adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
if (adapter == NULL) {
- dev_err(&pdev->dev, "can't allocate inteface!\n");
+ dev_err(&pdev->dev, "can't allocate interface!\n");
rc = -ENOMEM;
goto fail_nomem;
}
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 5d6675013864..0e8fab1913df 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -71,7 +71,6 @@
static struct cpuidle_driver intel_idle_driver = {
.name = "intel_idle",
.owner = THIS_MODULE,
- .en_core_tk_irqen = 1,
};
/* intel_idle.max_cstate=0 disables driver */
static int max_cstate = CPUIDLE_STATE_MAX - 1;
@@ -339,7 +338,6 @@ static int intel_idle(struct cpuidle_device *dev,
if (!(lapic_timer_reliable_states & (1 << (cstate))))
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
- stop_critical_timings();
if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -348,8 +346,6 @@ static int intel_idle(struct cpuidle_device *dev,
__mwait(eax, ecx);
}
- start_critical_timings();
-
if (!(lapic_timer_reliable_states & (1 << (cstate))))
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
@@ -465,6 +461,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
ICPU(0x3c, idle_cpu_hsw),
ICPU(0x3f, idle_cpu_hsw),
ICPU(0x45, idle_cpu_hsw),
+ ICPU(0x46, idle_cpu_hsw),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index dd8ea4284934..bbcbd7101f33 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -60,28 +60,28 @@ static const struct iio_chan_spec accel_3d_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index c2229a521ab9..7229645bf1d7 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -177,8 +177,8 @@ error_ret:
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = KXSD9_REG_##axis, \
}
@@ -186,7 +186,7 @@ static const struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
{
.type = IIO_VOLTAGE,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.indexed = 1,
.address = KXSD9_REG_AUX,
}
diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c
index 6bd82c7f769c..d9b350756f90 100644
--- a/drivers/iio/accel/st_accel_buffer.c
+++ b/drivers/iio/accel/st_accel_buffer.c
@@ -25,7 +25,7 @@
int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state);
}
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index e372257a8494..ab0767e6727e 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -30,6 +30,18 @@ config AD7298
To compile this driver as a module, choose M here: the
module will be called ad7298.
+config AD7923
+ tristate "Analog Devices AD7923 and similar ADCs driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices
+ AD7904, AD7914, AD7923, AD7924 4 Channel ADCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad7923.
+
config AD7791
tristate "Analog Devices AD7791 ADC driver"
depends on SPI
@@ -91,6 +103,14 @@ config AT91_ADC
help
Say yes here to build support for Atmel AT91 ADC.
+config EXYNOS_ADC
+ bool "Exynos ADC driver support"
+ depends on OF
+ help
+ Core support for the ADC block found in the Samsung EXYNOS series
+ of SoCs for drivers such as the touchscreen and hwmon to use to share
+ this resource.
+
config LP8788_ADC
bool "LP8788 ADC driver"
depends on MFD_LP8788
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 2d5f10080d8d..0a825bed43f6 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -5,11 +5,13 @@
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7298) += ad7298.o
+obj-$(CONFIG_AD7923) += ad7923.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index bbad9b94cd75..c2744a75c3b0 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -201,9 +201,9 @@ static int ad7266_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \
.channel = (_chan), \
.address = (_chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \
- | IIO_CHAN_INFO_SCALE_SHARED_BIT \
- | IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = (_sign), \
@@ -249,9 +249,9 @@ static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's');
.channel = (_chan) * 2, \
.channel2 = (_chan) * 2 + 1, \
.address = (_chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \
- | IIO_CHAN_INFO_SCALE_SHARED_BIT \
- | IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
+ | BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = (_chan), \
.scan_type = { \
.sign = _sign, \
diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
index b34d754994d5..03b77189dbfe 100644
--- a/drivers/iio/adc/ad7298.c
+++ b/drivers/iio/adc/ad7298.c
@@ -63,8 +63,8 @@ struct ad7298_state {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = index, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
@@ -80,9 +80,9 @@ static const struct iio_chan_spec ad7298_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
.address = AD7298_CH_TEMP,
.scan_index = -1,
.scan_type = {
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 1491fa6debb2..2e98bef4af67 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -140,12 +140,12 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
-#define _AD7476_CHAN(bits, _shift, _info_mask) \
+#define _AD7476_CHAN(bits, _shift, _info_mask_sep) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
- .info_mask = _info_mask | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = _info_mask_sep, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = { \
.sign = 'u', \
.realbits = (bits), \
@@ -156,9 +156,9 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
}
#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \
- IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+ BIT(IIO_CHAN_INFO_RAW))
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
- IIO_CHAN_INFO_RAW_SEPARATE_BIT)
+ BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c
index a33d5cd1a536..dd15a5b0f701 100644
--- a/drivers/iio/adc/ad7887.c
+++ b/drivers/iio/adc/ad7887.c
@@ -207,8 +207,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
@@ -217,8 +217,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
diff --git a/drivers/iio/adc/ad7923.c b/drivers/iio/adc/ad7923.c
new file mode 100644
index 000000000000..97fa0d3dc4aa
--- /dev/null
+++ b/drivers/iio/adc/ad7923.c
@@ -0,0 +1,383 @@
+/*
+ * AD7904/AD7914/AD7923/AD7924 SPI ADC driver
+ *
+ * Copyright 2011 Analog Devices Inc (from AD7923 Driver)
+ * Copyright 2012 CS Systemes d'Information
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define AD7923_WRITE_CR (1 << 11) /* write control register */
+#define AD7923_RANGE (1 << 1) /* range to REFin */
+#define AD7923_CODING (1 << 0) /* coding is straight binary */
+#define AD7923_PM_MODE_AS (1) /* auto shutdown */
+#define AD7923_PM_MODE_FS (2) /* full shutdown */
+#define AD7923_PM_MODE_OPS (3) /* normal operation */
+#define AD7923_CHANNEL_0 (0) /* analog input 0 */
+#define AD7923_CHANNEL_1 (1) /* analog input 1 */
+#define AD7923_CHANNEL_2 (2) /* analog input 2 */
+#define AD7923_CHANNEL_3 (3) /* analog input 3 */
+#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
+#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
+#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
+
+#define AD7923_MAX_CHAN 4
+
+#define AD7923_PM_MODE_WRITE(mode) (mode << 4) /* write mode */
+#define AD7923_CHANNEL_WRITE(channel) (channel << 6) /* write channel */
+#define AD7923_SEQUENCE_WRITE(sequence) (((sequence & 1) << 3) \
+ + ((sequence & 2) << 9))
+ /* write sequence fonction */
+/* left shift for CR : bit 11 transmit in first */
+#define AD7923_SHIFT_REGISTER 4
+
+/* val = value, dec = left shift, bits = number of bits of the mask */
+#define EXTRACT(val, dec, bits) ((val >> dec) & ((1 << bits) - 1))
+
+struct ad7923_state {
+ struct spi_device *spi;
+ struct spi_transfer ring_xfer[5];
+ struct spi_transfer scan_single_xfer[2];
+ struct spi_message ring_msg;
+ struct spi_message scan_single_msg;
+
+ struct regulator *reg;
+
+ unsigned int settings;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ __be16 rx_buf[4] ____cacheline_aligned;
+ __be16 tx_buf[4];
+};
+
+struct ad7923_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+enum ad7923_id {
+ AD7904,
+ AD7914,
+ AD7924,
+};
+
+#define AD7923_V_CHAN(index, bits) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define DECLARE_AD7923_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ AD7923_V_CHAN(0, bits), \
+ AD7923_V_CHAN(1, bits), \
+ AD7923_V_CHAN(2, bits), \
+ AD7923_V_CHAN(3, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
+static DECLARE_AD7923_CHANNELS(ad7904, 8);
+static DECLARE_AD7923_CHANNELS(ad7914, 10);
+static DECLARE_AD7923_CHANNELS(ad7924, 12);
+
+static const struct ad7923_chip_info ad7923_chip_info[] = {
+ [AD7904] = {
+ .channels = ad7904_channels,
+ .num_channels = ARRAY_SIZE(ad7904_channels),
+ },
+ [AD7914] = {
+ .channels = ad7914_channels,
+ .num_channels = ARRAY_SIZE(ad7914_channels),
+ },
+ [AD7924] = {
+ .channels = ad7924_channels,
+ .num_channels = ARRAY_SIZE(ad7924_channels),
+ },
+};
+
+/**
+ * ad7923_update_scan_mode() setup the spi transfer buffer for the new scan mask
+ **/
+static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct ad7923_state *st = iio_priv(indio_dev);
+ int i, cmd, len;
+
+ len = 0;
+ for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
+ cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
+ AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
+ st->settings;
+ cmd <<= AD7923_SHIFT_REGISTER;
+ st->tx_buf[len++] = cpu_to_be16(cmd);
+ }
+ /* build spi ring message */
+ st->ring_xfer[0].tx_buf = &st->tx_buf[0];
+ st->ring_xfer[0].len = len;
+ st->ring_xfer[0].cs_change = 1;
+
+ spi_message_init(&st->ring_msg);
+ spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg);
+
+ for (i = 0; i < len; i++) {
+ st->ring_xfer[i + 1].rx_buf = &st->rx_buf[i];
+ st->ring_xfer[i + 1].len = 2;
+ st->ring_xfer[i + 1].cs_change = 1;
+ spi_message_add_tail(&st->ring_xfer[i + 1], &st->ring_msg);
+ }
+ /* make sure last transfer cs_change is not set */
+ st->ring_xfer[i + 1].cs_change = 0;
+
+ return 0;
+}
+
+/**
+ * ad7923_trigger_handler() bh of trigger launched polling to ring buffer
+ *
+ * Currently there is no option in this driver to disable the saving of
+ * timestamps within the ring.
+ **/
+static irqreturn_t ad7923_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad7923_state *st = iio_priv(indio_dev);
+ s64 time_ns = 0;
+ int b_sent;
+
+ b_sent = spi_sync(st->spi, &st->ring_msg);
+ if (b_sent)
+ goto done;
+
+ if (indio_dev->scan_timestamp) {
+ time_ns = iio_get_time_ns();
+ memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
+ &time_ns, sizeof(time_ns));
+ }
+
+ iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf);
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
+{
+ int ret, cmd;
+
+ cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(ch) |
+ AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
+ st->settings;
+ cmd <<= AD7923_SHIFT_REGISTER;
+ st->tx_buf[0] = cpu_to_be16(cmd);
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret)
+ return ret;
+
+ return be16_to_cpu(st->rx_buf[0]);
+}
+
+static int ad7923_get_range(struct ad7923_state *st)
+{
+ int vref;
+
+ vref = regulator_get_voltage(st->reg);
+ if (vref < 0)
+ return vref;
+
+ vref /= 1000;
+
+ if (!(st->settings & AD7923_RANGE))
+ vref *= 2;
+
+ return vref;
+}
+
+static int ad7923_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ int ret;
+ struct ad7923_state *st = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+ if (iio_buffer_enabled(indio_dev))
+ ret = -EBUSY;
+ else
+ ret = ad7923_scan_direct(st, chan->address);
+ mutex_unlock(&indio_dev->mlock);
+
+ if (ret < 0)
+ return ret;
+
+ if (chan->address == EXTRACT(ret, 12, 4))
+ *val = EXTRACT(ret, 0, 12);
+ else
+ return -EIO;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = ad7923_get_range(st);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info ad7923_info = {
+ .read_raw = &ad7923_read_raw,
+ .update_scan_mode = ad7923_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static int ad7923_probe(struct spi_device *spi)
+{
+ struct ad7923_state *st;
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
+ const struct ad7923_chip_info *info;
+ int ret;
+
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+ st->settings = AD7923_CODING | AD7923_RANGE |
+ AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS);
+
+ info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data];
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+ indio_dev->info = &ad7923_info;
+
+ /* Setup default message */
+
+ st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
+ st->scan_single_xfer[0].len = 2;
+ st->scan_single_xfer[0].cs_change = 1;
+ st->scan_single_xfer[1].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[1].len = 2;
+
+ spi_message_init(&st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg);
+ spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg);
+
+ st->reg = regulator_get(&spi->dev, "refin");
+ if (IS_ERR(st->reg)) {
+ ret = PTR_ERR(st->reg);
+ goto error_free;
+ }
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &ad7923_trigger_handler, NULL);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_ring;
+
+ return 0;
+
+error_cleanup_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ regulator_disable(st->reg);
+error_put_reg:
+ regulator_put(st->reg);
+error_free:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int ad7923_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad7923_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad7923_id[] = {
+ {"ad7904", AD7904},
+ {"ad7914", AD7914},
+ {"ad7923", AD7924},
+ {"ad7924", AD7924},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, ad7923_id);
+
+static struct spi_driver ad7923_driver = {
+ .driver = {
+ .name = "ad7923",
+ .owner = THIS_MODULE,
+ },
+ .probe = ad7923_probe,
+ .remove = ad7923_remove,
+ .id_table = ad7923_id,
+};
+module_spi_driver(ad7923_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
+MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index afe6d78c8ff0..f0d6335ae087 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -470,7 +470,7 @@ static int ad_sd_probe_trigger(struct iio_dev *indio_dev)
disable_irq_nosync(sigma_delta->spi->irq);
}
sigma_delta->trig->dev.parent = &sigma_delta->spi->dev;
- sigma_delta->trig->private_data = sigma_delta;
+ iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
ret = iio_trigger_register(sigma_delta->trig);
if (ret)
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 83c836ba600f..e5b88d5d3b59 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -52,11 +52,15 @@ struct at91_adc_state {
void __iomem *reg_base;
struct at91_adc_reg_desc *registers;
u8 startup_time;
+ u8 sample_hold_time;
+ bool sleep_mode;
struct iio_trigger **trig;
struct at91_adc_trigger *trigger_list;
u32 trigger_number;
bool use_external;
u32 vref_mv;
+ u32 res; /* resolution used for convertions */
+ bool low_res; /* the resolution corresponds to the lowest one */
wait_queue_head_t wq_data_avail;
};
@@ -138,10 +142,10 @@ static int at91_adc_channel_init(struct iio_dev *idev)
chan->channel = bit;
chan->scan_index = idx;
chan->scan_type.sign = 'u';
- chan->scan_type.realbits = 10;
+ chan->scan_type.realbits = st->res;
chan->scan_type.storagebits = 16;
- chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+ chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
idx++;
}
timestamp = chan_array + idx;
@@ -188,7 +192,7 @@ static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{
- struct iio_dev *idev = trig->private_data;
+ struct iio_dev *idev = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(idev);
struct iio_buffer *buffer = idev->buffer;
struct at91_adc_reg_desc *reg = st->registers;
@@ -254,7 +258,7 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
return NULL;
trig->dev.parent = idev->dev.parent;
- trig->private_data = idev;
+ iio_trigger_set_drvdata(trig, idev);
trig->ops = &at91_adc_trigger_ops;
ret = iio_trigger_register(trig);
@@ -372,6 +376,59 @@ static int at91_adc_read_raw(struct iio_dev *idev,
return -EINVAL;
}
+static int at91_adc_of_get_resolution(struct at91_adc_state *st,
+ struct platform_device *pdev)
+{
+ struct iio_dev *idev = iio_priv_to_dev(st);
+ struct device_node *np = pdev->dev.of_node;
+ int count, i, ret = 0;
+ char *res_name, *s;
+ u32 *resolutions;
+
+ count = of_property_count_strings(np, "atmel,adc-res-names");
+ if (count < 2) {
+ dev_err(&idev->dev, "You must specified at least two resolution names for "
+ "adc-res-names property in the DT\n");
+ return count;
+ }
+
+ resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
+ if (!resolutions)
+ return -ENOMEM;
+
+ if (of_property_read_u32_array(np, "atmel,adc-res", resolutions, count)) {
+ dev_err(&idev->dev, "Missing adc-res property in the DT.\n");
+ ret = -ENODEV;
+ goto ret;
+ }
+
+ if (of_property_read_string(np, "atmel,adc-use-res", (const char **)&res_name))
+ res_name = "highres";
+
+ for (i = 0; i < count; i++) {
+ if (of_property_read_string_index(np, "atmel,adc-res-names", i, (const char **)&s))
+ continue;
+
+ if (strcmp(res_name, s))
+ continue;
+
+ st->res = resolutions[i];
+ if (!strcmp(res_name, "lowres"))
+ st->low_res = true;
+ else
+ st->low_res = false;
+
+ dev_info(&idev->dev, "Resolution used: %u bits\n", st->res);
+ goto ret;
+ }
+
+ dev_err(&idev->dev, "There is no resolution for %s\n", res_name);
+
+ret:
+ kfree(resolutions);
+ return ret;
+}
+
static int at91_adc_probe_dt(struct at91_adc_state *st,
struct platform_device *pdev)
{
@@ -400,6 +457,8 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
}
st->num_channels = prop;
+ st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
+
if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
ret = -EINVAL;
@@ -407,6 +466,9 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
}
st->startup_time = prop;
+ prop = 0;
+ of_property_read_u32(node, "atmel,adc-sample-hold-time", &prop);
+ st->sample_hold_time = prop;
if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
@@ -415,6 +477,10 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
}
st->vref_mv = prop;
+ ret = at91_adc_of_get_resolution(st, pdev);
+ if (ret)
+ goto error_ret;
+
st->registers = devm_kzalloc(&idev->dev,
sizeof(struct at91_adc_reg_desc),
GFP_KERNEL);
@@ -516,11 +582,12 @@ static const struct iio_info at91_adc_info = {
static int at91_adc_probe(struct platform_device *pdev)
{
- unsigned int prsc, mstrclk, ticks, adc_clk;
+ unsigned int prsc, mstrclk, ticks, adc_clk, shtim;
int ret;
struct iio_dev *idev;
struct at91_adc_state *st;
struct resource *res;
+ u32 reg;
idev = iio_device_alloc(sizeof(struct at91_adc_state));
if (idev == NULL) {
@@ -628,9 +695,22 @@ static int at91_adc_probe(struct platform_device *pdev)
*/
ticks = round_up((st->startup_time * adc_clk /
1000000) - 1, 8) / 8;
- at91_adc_writel(st, AT91_ADC_MR,
- (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
- (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+ /*
+ * a minimal Sample and Hold Time is necessary for the ADC to guarantee
+ * the best converted final value between two channels selection
+ * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock
+ */
+ shtim = round_up((st->sample_hold_time * adc_clk /
+ 1000000) - 1, 1);
+
+ reg = AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL;
+ reg |= AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP;
+ if (st->low_res)
+ reg |= AT91_ADC_LOWRES;
+ if (st->sleep_mode)
+ reg |= AT91_ADC_SLEEP;
+ reg |= AT91_ADC_SHTIM_(shtim) & AT91_ADC_SHTIM;
+ at91_adc_writel(st, AT91_ADC_MR, reg);
/* Setup the ADC channels available on the board */
ret = at91_adc_channel_init(idev);
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
new file mode 100644
index 000000000000..9f3a8ef1fb3e
--- /dev/null
+++ b/drivers/iio/adc/exynos_adc.c
@@ -0,0 +1,452 @@
+/*
+ * exynos_adc.c - Support for ADC in EXYNOS SoCs
+ *
+ * 8 ~ 10 channel, 10/12-bit ADC
+ *
+ * Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+enum adc_version {
+ ADC_V1,
+ ADC_V2
+};
+
+/* EXYNOS4412/5250 ADC_V1 registers definitions */
+#define ADC_V1_CON(x) ((x) + 0x00)
+#define ADC_V1_DLY(x) ((x) + 0x08)
+#define ADC_V1_DATX(x) ((x) + 0x0C)
+#define ADC_V1_INTCLR(x) ((x) + 0x18)
+#define ADC_V1_MUX(x) ((x) + 0x1c)
+
+/* Future ADC_V2 registers definitions */
+#define ADC_V2_CON1(x) ((x) + 0x00)
+#define ADC_V2_CON2(x) ((x) + 0x04)
+#define ADC_V2_STAT(x) ((x) + 0x08)
+#define ADC_V2_INT_EN(x) ((x) + 0x10)
+#define ADC_V2_INT_ST(x) ((x) + 0x14)
+#define ADC_V2_VER(x) ((x) + 0x20)
+
+/* Bit definitions for ADC_V1 */
+#define ADC_V1_CON_RES (1u << 16)
+#define ADC_V1_CON_PRSCEN (1u << 14)
+#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
+#define ADC_V1_CON_STANDBY (1u << 2)
+
+/* Bit definitions for ADC_V2 */
+#define ADC_V2_CON1_SOFT_RESET (1u << 2)
+
+#define ADC_V2_CON2_OSEL (1u << 10)
+#define ADC_V2_CON2_ESEL (1u << 9)
+#define ADC_V2_CON2_HIGHF (1u << 8)
+#define ADC_V2_CON2_C_TIME(x) (((x) & 7) << 4)
+#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
+#define ADC_V2_CON2_ACH_MASK 0xF
+
+#define MAX_ADC_V2_CHANNELS 10
+#define MAX_ADC_V1_CHANNELS 8
+
+/* Bit definitions common for ADC_V1 and ADC_V2 */
+#define ADC_CON_EN_START (1u << 0)
+#define ADC_DATX_MASK 0xFFF
+
+#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(1000))
+
+struct exynos_adc {
+ void __iomem *regs;
+ void __iomem *enable_reg;
+ struct clk *clk;
+ unsigned int irq;
+ struct regulator *vdd;
+
+ struct completion completion;
+
+ u32 value;
+ unsigned int version;
+};
+
+static const struct of_device_id exynos_adc_match[] = {
+ { .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 },
+ { .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_adc_match);
+
+static inline unsigned int exynos_adc_get_version(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_node(exynos_adc_match, pdev->dev.of_node);
+ return (unsigned int)match->data;
+}
+
+static int exynos_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct exynos_adc *info = iio_priv(indio_dev);
+ unsigned long timeout;
+ u32 con1, con2;
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Select the channel to be used and Trigger conversion */
+ if (info->version == ADC_V2) {
+ con2 = readl(ADC_V2_CON2(info->regs));
+ con2 &= ~ADC_V2_CON2_ACH_MASK;
+ con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
+ writel(con2, ADC_V2_CON2(info->regs));
+
+ con1 = readl(ADC_V2_CON1(info->regs));
+ writel(con1 | ADC_CON_EN_START,
+ ADC_V2_CON1(info->regs));
+ } else {
+ writel(chan->address, ADC_V1_MUX(info->regs));
+
+ con1 = readl(ADC_V1_CON(info->regs));
+ writel(con1 | ADC_CON_EN_START,
+ ADC_V1_CON(info->regs));
+ }
+
+ timeout = wait_for_completion_interruptible_timeout
+ (&info->completion, EXYNOS_ADC_TIMEOUT);
+ *val = info->value;
+
+ mutex_unlock(&indio_dev->mlock);
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return IIO_VAL_INT;
+}
+
+static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
+{
+ struct exynos_adc *info = (struct exynos_adc *)dev_id;
+
+ /* Read value */
+ info->value = readl(ADC_V1_DATX(info->regs)) &
+ ADC_DATX_MASK;
+ /* clear irq */
+ if (info->version == ADC_V2)
+ writel(1, ADC_V2_INT_ST(info->regs));
+ else
+ writel(1, ADC_V1_INTCLR(info->regs));
+
+ complete(&info->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int exynos_adc_reg_access(struct iio_dev *indio_dev,
+ unsigned reg, unsigned writeval,
+ unsigned *readval)
+{
+ struct exynos_adc *info = iio_priv(indio_dev);
+
+ if (readval == NULL)
+ return -EINVAL;
+
+ *readval = readl(info->regs + reg);
+
+ return 0;
+}
+
+static const struct iio_info exynos_adc_iio_info = {
+ .read_raw = &exynos_read_raw,
+ .debugfs_reg_access = &exynos_adc_reg_access,
+ .driver_module = THIS_MODULE,
+};
+
+#define ADC_CHANNEL(_index, _id) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _index, \
+ .address = _index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .datasheet_name = _id, \
+}
+
+static const struct iio_chan_spec exynos_adc_iio_channels[] = {
+ ADC_CHANNEL(0, "adc0"),
+ ADC_CHANNEL(1, "adc1"),
+ ADC_CHANNEL(2, "adc2"),
+ ADC_CHANNEL(3, "adc3"),
+ ADC_CHANNEL(4, "adc4"),
+ ADC_CHANNEL(5, "adc5"),
+ ADC_CHANNEL(6, "adc6"),
+ ADC_CHANNEL(7, "adc7"),
+ ADC_CHANNEL(8, "adc8"),
+ ADC_CHANNEL(9, "adc9"),
+};
+
+static int exynos_adc_remove_devices(struct device *dev, void *c)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
+static void exynos_adc_hw_init(struct exynos_adc *info)
+{
+ u32 con1, con2;
+
+ if (info->version == ADC_V2) {
+ con1 = ADC_V2_CON1_SOFT_RESET;
+ writel(con1, ADC_V2_CON1(info->regs));
+
+ con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
+ ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
+ writel(con2, ADC_V2_CON2(info->regs));
+
+ /* Enable interrupts */
+ writel(1, ADC_V2_INT_EN(info->regs));
+ } else {
+ /* set default prescaler values and Enable prescaler */
+ con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
+
+ /* Enable 12-bit ADC resolution */
+ con1 |= ADC_V1_CON_RES;
+ writel(con1, ADC_V1_CON(info->regs));
+ }
+}
+
+static int exynos_adc_probe(struct platform_device *pdev)
+{
+ struct exynos_adc *info = NULL;
+ struct device_node *np = pdev->dev.of_node;
+ struct iio_dev *indio_dev = NULL;
+ struct resource *mem;
+ int ret = -ENODEV;
+ int irq;
+
+ if (!np)
+ return ret;
+
+ indio_dev = iio_device_alloc(sizeof(struct exynos_adc));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ info = iio_priv(indio_dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ info->regs = devm_request_and_ioremap(&pdev->dev, mem);
+ if (!info->regs) {
+ ret = -ENOMEM;
+ goto err_iio;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ info->enable_reg = devm_request_and_ioremap(&pdev->dev, mem);
+ if (!info->enable_reg) {
+ ret = -ENOMEM;
+ goto err_iio;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ ret = irq;
+ goto err_iio;
+ }
+
+ info->irq = irq;
+
+ init_completion(&info->completion);
+
+ ret = request_irq(info->irq, exynos_adc_isr,
+ 0, dev_name(&pdev->dev), info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
+ info->irq);
+ goto err_iio;
+ }
+
+ writel(1, info->enable_reg);
+
+ info->clk = devm_clk_get(&pdev->dev, "adc");
+ if (IS_ERR(info->clk)) {
+ dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
+ PTR_ERR(info->clk));
+ ret = PTR_ERR(info->clk);
+ goto err_irq;
+ }
+
+ info->vdd = devm_regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(info->vdd)) {
+ dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
+ PTR_ERR(info->vdd));
+ ret = PTR_ERR(info->vdd);
+ goto err_irq;
+ }
+
+ info->version = exynos_adc_get_version(pdev);
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->info = &exynos_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = exynos_adc_iio_channels;
+
+ if (info->version == ADC_V1)
+ indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
+ else
+ indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_irq;
+
+ ret = regulator_enable(info->vdd);
+ if (ret)
+ goto err_iio_dev;
+
+ clk_prepare_enable(info->clk);
+
+ exynos_adc_hw_init(info);
+
+ ret = of_platform_populate(np, exynos_adc_match, NULL, &pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed adding child nodes\n");
+ goto err_of_populate;
+ }
+
+ return 0;
+
+err_of_populate:
+ device_for_each_child(&pdev->dev, NULL,
+ exynos_adc_remove_devices);
+ regulator_disable(info->vdd);
+ clk_disable_unprepare(info->clk);
+err_iio_dev:
+ iio_device_unregister(indio_dev);
+err_irq:
+ free_irq(info->irq, info);
+err_iio:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int exynos_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct exynos_adc *info = iio_priv(indio_dev);
+
+ device_for_each_child(&pdev->dev, NULL,
+ exynos_adc_remove_devices);
+ regulator_disable(info->vdd);
+ clk_disable_unprepare(info->clk);
+ writel(0, info->enable_reg);
+ iio_device_unregister(indio_dev);
+ free_irq(info->irq, info);
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_adc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct exynos_adc *info = platform_get_drvdata(pdev);
+ u32 con;
+
+ if (info->version == ADC_V2) {
+ con = readl(ADC_V2_CON1(info->regs));
+ con &= ~ADC_CON_EN_START;
+ writel(con, ADC_V2_CON1(info->regs));
+ } else {
+ con = readl(ADC_V1_CON(info->regs));
+ con |= ADC_V1_CON_STANDBY;
+ writel(con, ADC_V1_CON(info->regs));
+ }
+
+ clk_disable_unprepare(info->clk);
+ writel(0, info->enable_reg);
+ regulator_disable(info->vdd);
+
+ return 0;
+}
+
+static int exynos_adc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct exynos_adc *info = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = regulator_enable(info->vdd);
+ if (ret)
+ return ret;
+
+ writel(1, info->enable_reg);
+ clk_prepare_enable(info->clk);
+
+ exynos_adc_hw_init(info);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(exynos_adc_pm_ops,
+ exynos_adc_suspend,
+ exynos_adc_resume);
+
+static struct platform_driver exynos_adc_driver = {
+ .probe = exynos_adc_probe,
+ .remove = exynos_adc_remove,
+ .driver = {
+ .name = "exynos-adc",
+ .owner = THIS_MODULE,
+ .of_match_table = exynos_adc_match,
+ .pm = &exynos_adc_pm_ops,
+ },
+};
+
+module_platform_driver(exynos_adc_driver);
+
+MODULE_AUTHOR("Naveen Krishna Chatradhi <ch.naveen@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS5 ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c
index 763f57565ee4..62bc39e9c94f 100644
--- a/drivers/iio/adc/lp8788_adc.c
+++ b/drivers/iio/adc/lp8788_adc.c
@@ -132,8 +132,8 @@ static const struct iio_info lp8788_adc_info = {
.type = _type, \
.indexed = 1, \
.channel = LPADC_##_id, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = #_id, \
}
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 6c1cfb74bdfc..9e6da72ad823 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -427,15 +427,15 @@ static const enum max1363_modes max1363_mode_list[] = {
#define MAX1363_EV_M \
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
| IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
-#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT)
+
#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = num, \
.address = addr, \
- .info_mask = MAX1363_INFO_MASK, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "AIN"#num, \
.scan_type = { \
.sign = 'u', \
@@ -456,7 +456,8 @@ static const enum max1363_modes max1363_mode_list[] = {
.channel = num, \
.channel2 = num2, \
.address = addr, \
- .info_mask = MAX1363_INFO_MASK, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = "AIN"#num"-AIN"#num2, \
.scan_type = { \
.sign = 's', \
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index f4a46dd8f43b..2826faae706c 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -55,8 +55,8 @@ static int adc081c_read_raw(struct iio_dev *iio,
static const struct iio_chan_spec adc081c_channel = {
.type = IIO_VOLTAGE,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
};
static const struct iio_info adc081c_info = {
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index cd030e100c39..5f9a7e7d3135 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -89,7 +89,7 @@ static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->channel = i;
- chan->info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
}
indio_dev->channels = chan_array;
diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c
index ad0261533dee..56ac481c73c0 100644
--- a/drivers/iio/adc/viperboard_adc.c
+++ b/drivers/iio/adc/viperboard_adc.c
@@ -41,7 +41,7 @@ struct vprbrd_adc {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \
.scan_type = { \
.sign = 'u', \
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index d6c0af23a2a7..d354554b51b3 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -125,7 +125,7 @@ static const struct iio_info ad8366_info = {
.output = 1, \
.indexed = 1, \
.channel = _channel, \
- .info_mask = IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT,\
+ .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),\
}
static const struct iio_chan_spec ad8366_channels[] = {
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 7a525a91105d..87419c41b991 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -31,7 +31,7 @@
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct hid_sensor_common *st = trig->private_data;
+ struct hid_sensor_common *st = iio_trigger_get_drvdata(trig);
int state_val;
state_val = state ? 1 : 0;
@@ -76,7 +76,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
}
trig->dev.parent = indio_dev->dev.parent;
- trig->private_data = attrb;
+ iio_trigger_set_drvdata(trig, attrb);
trig->ops = &hid_sensor_trigger_ops;
ret = iio_trigger_register(trig);
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
index f0aa2f105222..251baf6abc25 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -29,7 +29,6 @@ static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
- struct spi_message msg;
int err;
struct spi_transfer xfers[] = {
@@ -51,10 +50,7 @@ static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
else
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
- err = spi_sync(to_spi_device(dev), &msg);
+ err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers));
if (err)
goto acc_spi_read_error;
@@ -83,7 +79,6 @@ static int st_sensors_spi_read_multiple_byte(
static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
- struct spi_message msg;
int err;
struct spi_transfer xfers = {
@@ -96,9 +91,7 @@ static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
tb->tx_buf[0] = reg_addr;
tb->tx_buf[1] = data;
- spi_message_init(&msg);
- spi_message_add_tail(&xfers, &msg);
- err = spi_sync(to_spi_device(dev), &msg);
+ err = spi_sync_transfer(to_spi_device(dev), &xfers, 1);
mutex_unlock(&tb->buf_lock);
return err;
diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
index 139ed030abb0..8fc3a97eb266 100644
--- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
@@ -40,7 +40,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
if (err)
goto request_irq_error;
- sdata->trig->private_data = indio_dev;
+ iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index 74f2d52795f6..aa26d50ab638 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -296,8 +296,8 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = (chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = addr, \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \
.ext_info = ad5064_ext_info, \
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
index 92771217f665..80923af424f2 100644
--- a/drivers/iio/dac/ad5360.c
+++ b/drivers/iio/dac/ad5360.c
@@ -102,11 +102,11 @@ enum ad5360_type {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \
}
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
index 483fc379a2da..bf2db02215c2 100644
--- a/drivers/iio/dac/ad5380.c
+++ b/drivers/iio/dac/ad5380.c
@@ -257,10 +257,10 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)), \
.ext_info = ad5380_ext_info, \
}
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
index 6b86a638dad0..98f24407c3ce 100644
--- a/drivers/iio/dac/ad5421.c
+++ b/drivers/iio/dac/ad5421.c
@@ -86,11 +86,11 @@ static const struct iio_chan_spec ad5421_channels[] = {
.indexed = 1,
.output = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
.scan_type = IIO_ST('u', 16, 16, 0),
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
index f5583aedfb59..cae8f6056ac3 100644
--- a/drivers/iio/dac/ad5446.c
+++ b/drivers/iio/dac/ad5446.c
@@ -143,8 +143,8 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = {
.indexed = 1, \
.output = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
.ext_info = (ext), \
}
diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c
index c4731b7b577b..ba1c914b0399 100644
--- a/drivers/iio/dac/ad5449.c
+++ b/drivers/iio/dac/ad5449.c
@@ -206,8 +206,8 @@ static const struct iio_info ad5449_info = {
.indexed = 1, \
.output = 1, \
.channel = (chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = (chan), \
.scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \
}
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index e5e59749f109..139206e84cb7 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -259,8 +259,8 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = AD5504_ADDR_DAC(_chan), \
.scan_type = IIO_ST('u', 12, 16, 0), \
.ext_info = ad5504_ext_info, \
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
index f6e116627b71..bb298aaff321 100644
--- a/drivers/iio/dac/ad5624r_spi.c
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -174,8 +174,8 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (_chan), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
.ext_info = ad5624r_ext_info, \
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 5e554af21703..06439b1af9b6 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -276,9 +276,9 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = chan, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
- .address = AD5686_ADDR_DAC(chan), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
+ .address = AD5686_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', bits, 16, shift), \
.ext_info = ad5686_ext_info, \
}
diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c
index 71faabc6b14e..12bb315e55f8 100644
--- a/drivers/iio/dac/ad5755.c
+++ b/drivers/iio/dac/ad5755.c
@@ -393,11 +393,11 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = {
#define AD5755_CHANNEL(_bits) { \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
.ext_info = ad5755_ext_info, \
}
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
index 5b7acd3a2c77..7a53f7d70dac 100644
--- a/drivers/iio/dac/ad5764.c
+++ b/drivers/iio/dac/ad5764.c
@@ -78,11 +78,11 @@ enum ad5764_type {
.output = 1, \
.channel = (_chan), \
.address = (_chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)) \
}
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index 8dfd3da8a07b..97c1e5d780df 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -302,9 +302,9 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
.scan_type = IIO_ST('u', bits, 24, shift), \
.ext_info = ad5791_ext_info, \
}
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
index 352abe2004a4..ebfaa4156246 100644
--- a/drivers/iio/dac/max517.c
+++ b/drivers/iio/dac/max517.c
@@ -146,8 +146,8 @@ static const struct iio_info max517_info = {
.indexed = 1, \
.output = 1, \
.channel = (chan), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.scan_type = IIO_ST('u', 8, 8, 0), \
}
diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c
index 8f88cc4059a2..a612ec766d96 100644
--- a/drivers/iio/dac/mcp4725.c
+++ b/drivers/iio/dac/mcp4725.c
@@ -69,8 +69,8 @@ static const struct iio_chan_spec mcp4725_channel = {
.indexed = 1,
.output = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_type = IIO_ST('u', 12, 16, 0),
};
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 1ea132e239ea..92276deeb026 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -920,10 +920,10 @@ static int ad9523_setup(struct iio_dev *indio_dev)
st->ad9523_channels[i].channel = chan->channel_num;
st->ad9523_channels[i].extend_name =
chan->extended_name;
- st->ad9523_channels[i].info_mask =
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_PHASE_SEPARATE_BIT |
- IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT;
+ st->ad9523_channels[i].info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_PHASE) |
+ BIT(IIO_CHAN_INFO_FREQUENCY);
}
}
diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c
index 1861287911f1..e1bb5f994a54 100644
--- a/drivers/iio/gyro/adis16080.c
+++ b/drivers/iio/gyro/adis16080.c
@@ -136,32 +136,32 @@ static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
.address = ADIS16080_DIN_TEMP,
}
};
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c
index 8cb0bcbfd609..058e6d5c955f 100644
--- a/drivers/iio/gyro/adis16136.c
+++ b/drivers/iio/gyro/adis16136.c
@@ -357,10 +357,11 @@ static const struct iio_chan_spec adis16136_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+
.address = ADIS16136_REG_GYRO_OUT2,
.scan_index = ADIS16136_SCAN_GYRO,
.scan_type = {
@@ -373,8 +374,8 @@ static const struct iio_chan_spec adis16136_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16136_REG_TEMP_OUT,
.scan_index = ADIS16136_SCAN_TEMP,
.scan_type = {
diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c
index 5b79953f7011..8bd72b490b7f 100644
--- a/drivers/iio/gyro/adxrs450.c
+++ b/drivers/iio/gyro/adxrs450.c
@@ -383,16 +383,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
}
},
[ID_ADXRS453] = {
@@ -400,15 +400,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW),
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
}
},
};
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index fcfc83a9f861..bc943dd47da5 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -60,28 +60,28 @@ static const struct iio_chan_spec gyro_3d_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
diff --git a/drivers/iio/gyro/itg3200_buffer.c b/drivers/iio/gyro/itg3200_buffer.c
index f667d2c8c00f..6c43af9bb0a4 100644
--- a/drivers/iio/gyro/itg3200_buffer.c
+++ b/drivers/iio/gyro/itg3200_buffer.c
@@ -81,7 +81,7 @@ void itg3200_buffer_unconfigure(struct iio_dev *indio_dev)
static int itg3200_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
int ret;
u8 msc;
@@ -129,7 +129,7 @@ int itg3200_probe_trigger(struct iio_dev *indio_dev)
st->trig->dev.parent = &st->i2c->dev;
st->trig->ops = &itg3200_trigger_ops;
- st->trig->private_data = indio_dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
if (ret)
goto error_free_irq;
diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c
index df2e6aa5d73b..d66605d2629d 100644
--- a/drivers/iio/gyro/itg3200_core.c
+++ b/drivers/iio/gyro/itg3200_core.c
@@ -248,12 +248,6 @@ err_ret:
return ret;
}
-#define ITG3200_TEMP_INFO_MASK (IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_RAW_SEPARATE_BIT)
-#define ITG3200_GYRO_INFO_MASK (IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_RAW_SEPARATE_BIT)
-
#define ITG3200_ST \
{ .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE }
@@ -261,7 +255,8 @@ err_ret:
.type = IIO_ANGL_VEL, \
.modified = 1, \
.channel2 = IIO_MOD_ ## _mod, \
- .info_mask = ITG3200_GYRO_INFO_MASK, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = ITG3200_REG_GYRO_ ## _mod ## OUT_H, \
.scan_index = ITG3200_SCAN_GYRO_ ## _mod, \
.scan_type = ITG3200_ST, \
@@ -271,7 +266,9 @@ static const struct iio_chan_spec itg3200_channels[] = {
{
.type = IIO_TEMP,
.channel2 = IIO_NO_MOD,
- .info_mask = ITG3200_TEMP_INFO_MASK,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = ITG3200_REG_TEMP_OUT_H,
.scan_index = ITG3200_SCAN_TEMP,
.scan_type = ITG3200_ST,
diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c
index da4d122ec7dc..69017c7ec302 100644
--- a/drivers/iio/gyro/st_gyro_buffer.c
+++ b/drivers/iio/gyro/st_gyro_buffer.c
@@ -25,7 +25,7 @@
int st_gyro_trig_set_state(struct iio_trigger *trig, bool state)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
return st_sensors_set_dataready_irq(indio_dev, state);
}
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index f652e6ae5a35..05c1b74502a3 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -18,6 +18,7 @@
struct iio_chan_spec;
struct iio_dev;
+extern struct device_type iio_device_type;
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c
index b7f215eab5de..f60591f0b925 100644
--- a/drivers/iio/imu/adis16400_core.c
+++ b/drivers/iio/imu/adis16400_core.c
@@ -484,8 +484,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \
.channel = 0, \
.extend_name = name, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
@@ -507,10 +507,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_ANGL_VEL, \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = addr, \
.scan_index = ADIS16400_SCAN_GYRO_ ## mod, \
.scan_type = { \
@@ -526,10 +526,10 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \
.scan_index = ADIS16400_SCAN_ACC_ ## mod, \
.scan_type = { \
@@ -545,9 +545,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \
.scan_index = ADIS16400_SCAN_MAGN_ ## mod, \
.scan_type = { \
@@ -568,10 +568,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.indexed = 1, \
.channel = 0, \
.extend_name = ADIS16400_MOD_TEMP_NAME_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.address = (addr), \
.scan_index = ADIS16350_SCAN_TEMP_ ## mod, \
.scan_type = { \
@@ -587,9 +588,9 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \
.scan_index = ADIS16350_SCAN_TEMP_X, \
.scan_type = { \
@@ -605,8 +606,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
.type = IIO_INCLI, \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \
.scan_index = ADIS16300_SCAN_INCLI_ ## mod, \
.scan_type = { \
@@ -646,8 +647,8 @@ static const struct iio_chan_spec adis16448_channels[] = {
ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 16),
{
.type = IIO_PRESSURE,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16448_BARO_OUT,
.scan_index = ADIS16400_SCAN_BARO,
.scan_type = IIO_ST('s', 16, 16, 0),
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
index 8c26a5f7cd5d..b7db38376295 100644
--- a/drivers/iio/imu/adis16480.c
+++ b/drivers/iio/imu/adis16480.c
@@ -591,15 +591,15 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
}
}
-#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info, _bits) \
+#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info_sep, _bits) \
{ \
.type = (_type), \
.modified = 1, \
.channel2 = (_mod), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- _info, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ _info_sep, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (_address), \
.scan_index = (_si), \
.scan_type = { \
@@ -613,21 +613,21 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
#define ADIS16480_GYRO_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), \
32)
#define ADIS16480_ACCEL_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), \
32)
#define ADIS16480_MAGN_CHANNEL(_mod) \
ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, \
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
16)
#define ADIS16480_PRESSURE_CHANNEL() \
@@ -635,9 +635,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
.type = IIO_PRESSURE, \
.indexed = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = ADIS16480_REG_BAROM_OUT, \
.scan_index = ADIS16480_SCAN_BARO, \
.scan_type = { \
@@ -652,9 +652,9 @@ static int adis16480_write_raw(struct iio_dev *indio_dev,
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
.address = ADIS16480_REG_TEMP_OUT, \
.scan_index = ADIS16480_SCAN_TEMP, \
.scan_type = { \
diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c
index 5a24c9cac343..e0017c22bb9c 100644
--- a/drivers/iio/imu/adis_trigger.c
+++ b/drivers/iio/imu/adis_trigger.c
@@ -19,7 +19,7 @@
static int adis_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct adis *adis = trig->private_data;
+ struct adis *adis = iio_trigger_get_drvdata(trig);
return adis_enable_irq(adis, state);
}
@@ -57,7 +57,7 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
adis->trig->dev.parent = &adis->spi->dev;
adis->trig->ops = &adis_trigger_ops;
- adis->trig->private_data = adis;
+ iio_trigger_set_drvdata(adis->trig, adis);
ret = iio_trigger_register(adis->trig);
indio_dev->trig = adis->trig;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 37ca05b47e4b..fe4c61e219f3 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -544,8 +544,8 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
.type = _type, \
.modified = 1, \
.channel2 = _channel2, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \
- | IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
@@ -564,9 +564,9 @@ static const struct iio_chan_spec inv_mpu_channels[] = {
*/
{
.type = IIO_TEMP,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT
- | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT
- | IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_OFFSET)
+ | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index 331781ffbb15..7da0832f187b 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -105,9 +105,8 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
s64 timestamp;
timestamp = iio_get_time_ns();
- spin_lock(&st->time_stamp_lock);
- kfifo_in(&st->timestamps, &timestamp, 1);
- spin_unlock(&st->time_stamp_lock);
+ kfifo_in_spinlocked(&st->timestamps, &timestamp, 1,
+ &st->time_stamp_lock);
return IRQ_WAKE_THREAD;
}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index e1d0869e0ad1..03b9372c1212 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -103,7 +103,7 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- return inv_mpu6050_set_enable(trig->private_data, state);
+ return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state);
}
static const struct iio_trigger_ops inv_mpu_trigger_ops = {
@@ -130,8 +130,8 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
if (ret)
goto error_free_trig;
st->trig->dev.parent = &st->client->dev;
- st->trig->private_data = indio_dev;
st->trig->ops = &inv_mpu_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
if (ret)
goto error_free_irq;
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 8848f16c547b..e145931ef1b8 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -691,21 +691,34 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
if (chan->channel < 0)
return 0;
- for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
- ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
+ for_each_set_bit(i, &chan->info_mask_separate, sizeof(long)*8) {
+ ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
chan,
&iio_read_channel_info,
&iio_write_channel_info,
- i/2,
- !(i%2),
+ i,
+ 0,
&indio_dev->dev,
&indio_dev->channel_attr_list);
- if (ret == -EBUSY && (i%2 == 0)) {
+ if (ret < 0)
+ goto error_ret;
+ attrcount++;
+ }
+ for_each_set_bit(i, &chan->info_mask_shared_by_type, sizeof(long)*8) {
+ ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
+ chan,
+ &iio_read_channel_info,
+ &iio_write_channel_info,
+ i,
+ 1,
+ &indio_dev->dev,
+ &indio_dev->channel_attr_list);
+ if (ret == -EBUSY) {
ret = 0;
continue;
- }
- if (ret < 0)
+ } else if (ret < 0) {
goto error_ret;
+ }
attrcount++;
}
@@ -847,7 +860,7 @@ static void iio_dev_release(struct device *device)
kfree(indio_dev);
}
-static struct device_type iio_dev_type = {
+struct device_type iio_device_type = {
.name = "iio_device",
.release = iio_dev_release,
};
@@ -869,7 +882,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
if (dev) {
dev->dev.groups = dev->groups;
- dev->dev.type = &iio_dev_type;
+ dev->dev.type = &iio_device_type;
dev->dev.bus = &iio_bus_type;
device_initialize(&dev->dev);
dev_set_drvdata(&dev->dev, (void *)dev);
@@ -960,6 +973,10 @@ int iio_device_register(struct iio_dev *indio_dev)
{
int ret;
+ /* If the calling driver did not initialize of_node, do it here */
+ if (!indio_dev->dev.of_node && indio_dev->dev.parent)
+ indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
+
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 261cae00557e..10aa9ef86cec 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -46,10 +46,11 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
{
struct iio_event_interface *ev_int = indio_dev->event_interface;
struct iio_event_data ev;
+ unsigned long flags;
int copied;
/* Does anyone care? */
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irqsave(&ev_int->wait.lock, flags);
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
ev.id = ev_code;
@@ -59,7 +60,7 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
if (copied != 0)
wake_up_locked_poll(&ev_int->wait, POLLIN);
}
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irqrestore(&ev_int->wait.lock, flags);
return 0;
}
@@ -76,10 +77,10 @@ static unsigned int iio_event_poll(struct file *filep,
poll_wait(filep, &ev_int->wait, wait);
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irq(&ev_int->wait.lock);
if (!kfifo_is_empty(&ev_int->det_events))
events = POLLIN | POLLRDNORM;
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
return events;
}
@@ -96,14 +97,14 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
if (count < sizeof(struct iio_event_data))
return -EINVAL;
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irq(&ev_int->wait.lock);
if (kfifo_is_empty(&ev_int->det_events)) {
if (filep->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
goto error_unlock;
}
/* Blocking on device; waiting for something to be there */
- ret = wait_event_interruptible_locked(ev_int->wait,
+ ret = wait_event_interruptible_locked_irq(ev_int->wait,
!kfifo_is_empty(&ev_int->det_events));
if (ret)
goto error_unlock;
@@ -113,7 +114,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
error_unlock:
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
return ret ? ret : copied;
}
@@ -122,7 +123,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
{
struct iio_event_interface *ev_int = filep->private_data;
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irq(&ev_int->wait.lock);
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
/*
* In order to maintain a clean state for reopening,
@@ -130,7 +131,7 @@ static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
* any new __iio_push_event calls running.
*/
kfifo_reset_out(&ev_int->det_events);
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
return 0;
}
@@ -151,18 +152,18 @@ int iio_event_getfd(struct iio_dev *indio_dev)
if (ev_int == NULL)
return -ENODEV;
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irq(&ev_int->wait.lock);
if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
return -EBUSY;
}
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
fd = anon_inode_getfd("iio:event",
&iio_event_chrdev_fileops, ev_int, O_RDONLY);
if (fd < 0) {
- spin_lock(&ev_int->wait.lock);
+ spin_lock_irq(&ev_int->wait.lock);
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
- spin_unlock(&ev_int->wait.lock);
+ spin_unlock_irq(&ev_int->wait.lock);
}
return fd;
}
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index b289915b8469..795d100b4c36 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -10,6 +10,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/iio/iio.h>
#include "iio_core.h"
@@ -92,6 +93,164 @@ static const struct iio_chan_spec
return chan;
}
+#ifdef CONFIG_OF
+
+static int iio_dev_node_match(struct device *dev, void *data)
+{
+ return dev->of_node == data && dev->type == &iio_device_type;
+}
+
+static int __of_iio_channel_get(struct iio_channel *channel,
+ struct device_node *np, int index)
+{
+ struct device *idev;
+ struct iio_dev *indio_dev;
+ int err;
+ struct of_phandle_args iiospec;
+
+ err = of_parse_phandle_with_args(np, "io-channels",
+ "#io-channel-cells",
+ index, &iiospec);
+ if (err)
+ return err;
+
+ idev = bus_find_device(&iio_bus_type, NULL, iiospec.np,
+ iio_dev_node_match);
+ of_node_put(iiospec.np);
+ if (idev == NULL)
+ return -EPROBE_DEFER;
+
+ indio_dev = dev_to_iio_dev(idev);
+ channel->indio_dev = indio_dev;
+ index = iiospec.args_count ? iiospec.args[0] : 0;
+ if (index >= indio_dev->num_channels) {
+ return -EINVAL;
+ goto err_put;
+ }
+ channel->channel = &indio_dev->channels[index];
+
+ return 0;
+
+err_put:
+ iio_device_put(indio_dev);
+ return err;
+}
+
+static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
+{
+ struct iio_channel *channel;
+ int err;
+
+ if (index < 0)
+ return ERR_PTR(-EINVAL);
+
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+ if (channel == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ err = __of_iio_channel_get(channel, np, index);
+ if (err)
+ goto err_free_channel;
+
+ return channel;
+
+err_free_channel:
+ kfree(channel);
+ return ERR_PTR(err);
+}
+
+static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
+ const char *name)
+{
+ struct iio_channel *chan = NULL;
+
+ /* Walk up the tree of devices looking for a matching iio channel */
+ while (np) {
+ int index = 0;
+
+ /*
+ * For named iio channels, first look up the name in the
+ * "io-channel-names" property. If it cannot be found, the
+ * index will be an error code, and of_iio_channel_get()
+ * will fail.
+ */
+ if (name)
+ index = of_property_match_string(np, "io-channel-names",
+ name);
+ chan = of_iio_channel_get(np, index);
+ if (!IS_ERR(chan))
+ break;
+ else if (name && index >= 0) {
+ pr_err("ERROR: could not get IIO channel %s:%s(%i)\n",
+ np->full_name, name ? name : "", index);
+ return chan;
+ }
+
+ /*
+ * No matching IIO channel found on this node.
+ * If the parent node has a "io-channel-ranges" property,
+ * then we can try one of its channels.
+ */
+ np = np->parent;
+ if (np && !of_get_property(np, "io-channel-ranges", NULL))
+ break;
+ }
+ return chan;
+}
+
+static struct iio_channel *of_iio_channel_get_all(struct device *dev)
+{
+ struct iio_channel *chans;
+ int i, mapind, nummaps = 0;
+ int ret;
+
+ do {
+ ret = of_parse_phandle_with_args(dev->of_node,
+ "io-channels",
+ "#io-channel-cells",
+ nummaps, NULL);
+ if (ret < 0)
+ break;
+ } while (++nummaps);
+
+ if (nummaps == 0) /* no error, return NULL to search map table */
+ return NULL;
+
+ /* NULL terminated array to save passing size */
+ chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
+ if (chans == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ /* Search for OF matches */
+ for (mapind = 0; mapind < nummaps; mapind++) {
+ ret = __of_iio_channel_get(&chans[mapind], dev->of_node,
+ mapind);
+ if (ret)
+ goto error_free_chans;
+ }
+ return chans;
+
+error_free_chans:
+ for (i = 0; i < mapind; i++)
+ iio_device_put(chans[i].indio_dev);
+ kfree(chans);
+ return ERR_PTR(ret);
+}
+
+#else /* CONFIG_OF */
+
+static inline struct iio_channel *
+of_iio_channel_get_by_name(struct device_node *np, const char *name)
+{
+ return NULL;
+}
+
+static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_OF */
static struct iio_channel *iio_channel_get_sys(const char *name,
const char *channel_name)
@@ -150,7 +309,14 @@ struct iio_channel *iio_channel_get(struct device *dev,
const char *channel_name)
{
const char *name = dev ? dev_name(dev) : NULL;
+ struct iio_channel *channel;
+ if (dev) {
+ channel = of_iio_channel_get_by_name(dev->of_node,
+ channel_name);
+ if (channel != NULL)
+ return channel;
+ }
return iio_channel_get_sys(name, channel_name);
}
EXPORT_SYMBOL_GPL(iio_channel_get);
@@ -173,6 +339,11 @@ struct iio_channel *iio_channel_get_all(struct device *dev)
if (dev == NULL)
return ERR_PTR(-EINVAL);
+
+ chans = of_iio_channel_get_all(dev);
+ if (chans)
+ return chans;
+
name = dev_name(dev);
mutex_lock(&iio_map_list_lock);
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index d5b9d39d95b2..5f4749e60b04 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -207,8 +207,8 @@ static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = {
.type = IIO_INTENSITY, \
.modified = 1, \
.address = (IDX_##_color), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.channel2 = (IIO_MOD_LIGHT_##_color), \
.scan_index = (_scan_idx), \
.scan_type = IIO_ST('u', 10, 16, 0), \
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 3d7e8c9b4beb..80d68ff02d29 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -49,10 +49,10 @@ static const struct iio_chan_spec als_channels[] = {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
}
};
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index 7503012ce933..5fa31a4ef82a 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -231,7 +231,7 @@ static int lm3533_als_read_raw(struct iio_dev *indio_dev,
.channel = _channel, \
.indexed = true, \
.output = true, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static const struct iio_chan_spec lm3533_als_channels[] = {
@@ -239,8 +239,8 @@ static const struct iio_chan_spec lm3533_als_channels[] = {
.type = IIO_LIGHT,
.channel = 0,
.indexed = true,
- .info_mask = (IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_RAW_SEPARATE_BIT),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
+ BIT(IIO_CHAN_INFO_RAW),
},
CHANNEL_CURRENT(0),
CHANNEL_CURRENT(1),
diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c
index fd8be69b7d05..1f529f36f138 100644
--- a/drivers/iio/light/tsl2563.c
+++ b/drivers/iio/light/tsl2563.c
@@ -530,14 +530,14 @@ static const struct iio_chan_spec tsl2563_channels[] = {
{
.type = IIO_LIGHT,
.indexed = 1,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.channel = 0,
}, {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
@@ -546,8 +546,8 @@ static const struct iio_chan_spec tsl2563_channels[] = {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_IR,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
}
};
diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c
index 2aa748fbdc0e..1014943d949a 100644
--- a/drivers/iio/light/vcnl4000.c
+++ b/drivers/iio/light/vcnl4000.c
@@ -93,11 +93,11 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_PROXIMITY,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index cd29be54f643..bd1cfb666695 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -3,6 +3,17 @@
#
menu "Magnetometer sensors"
+config AK8975
+ tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+ depends on I2C
+ depends on GPIOLIB
+ help
+ Say yes here to build support for Asahi Kasei AK8975 3-Axis
+ Magnetometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ak8975.
+
config HID_SENSOR_MAGNETOMETER_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index e78672876dc2..7f328e37fbab 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -2,6 +2,7 @@
# Makefile for industrial I/O Magnetometer sensor drivers
#
+obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index 28f080e9eeee..af6c320a534e 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -94,7 +94,6 @@ struct ak8975_data {
long raw_to_gauss[3];
u8 reg_cache[AK8975_MAX_REGS];
int eoc_gpio;
- int eoc_irq;
};
static const int ak8975_index_to_reg[] = {
@@ -124,36 +123,6 @@ static int ak8975_write_data(struct i2c_client *client,
}
/*
- * Helper function to read a contiguous set of the I2C device's registers.
- */
-static int ak8975_read_data(struct i2c_client *client,
- u8 reg, u8 length, u8 *buffer)
-{
- int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
- .flags = I2C_M_NOSTART,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = buffer,
- }
- };
-
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0) {
- dev_err(&client->dev, "Read from device fails\n");
- return ret;
- }
-
- return 0;
-}
-
-/*
* Perform some start-of-day setup, including reading the asa calibration
* values and caching them.
*/
@@ -165,11 +134,12 @@ static int ak8975_setup(struct i2c_client *client)
int ret;
/* Confirm that the device we're talking to is really an AK8975. */
- ret = ak8975_read_data(client, AK8975_REG_WIA, 1, &device_id);
+ ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n");
return ret;
}
+ device_id = ret;
if (device_id != AK8975_DEVICE_ID) {
dev_err(&client->dev, "Device ak8975 not found\n");
return -ENODEV;
@@ -187,7 +157,8 @@ static int ak8975_setup(struct i2c_client *client)
}
/* Get asa data and store in the device data. */
- ret = ak8975_read_data(client, AK8975_REG_ASAX, 3, data->asa);
+ ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
+ 3, data->asa);
if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n");
return ret;
@@ -249,7 +220,6 @@ static int ak8975_setup(struct i2c_client *client)
static int wait_conversion_complete_gpio(struct ak8975_data *data)
{
struct i2c_client *client = data->client;
- u8 read_status;
u32 timeout_ms = AK8975_MAX_CONVERSION_TIMEOUT;
int ret;
@@ -265,12 +235,11 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
return -EINVAL;
}
- ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status);
- if (ret < 0) {
+ ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+ if (ret < 0)
dev_err(&client->dev, "Error in reading ST1\n");
- return ret;
- }
- return read_status;
+
+ return ret;
}
static int wait_conversion_complete_polled(struct ak8975_data *data)
@@ -283,11 +252,12 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
/* Wait for the conversion to complete. */
while (timeout_ms) {
msleep(AK8975_CONVERSION_DONE_POLL_TIME);
- ret = ak8975_read_data(client, AK8975_REG_ST1, 1, &read_status);
+ ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST1\n");
return ret;
}
+ read_status = ret;
if (read_status)
break;
timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
@@ -308,7 +278,6 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
struct i2c_client *client = data->client;
u16 meas_reg;
s16 raw;
- u8 read_status;
int ret;
mutex_lock(&data->lock);
@@ -332,18 +301,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
if (ret < 0)
goto exit;
- read_status = ret;
-
- if (read_status & AK8975_REG_ST1_DRDY_MASK) {
- ret = ak8975_read_data(client, AK8975_REG_ST2, 1, &read_status);
+ if (ret & AK8975_REG_ST1_DRDY_MASK) {
+ ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST2\n");
goto exit;
}
- if (read_status & (AK8975_REG_ST2_DERR_MASK |
- AK8975_REG_ST2_HOFL_MASK)) {
- dev_err(&client->dev, "ST2 status error 0x%x\n",
- read_status);
+ if (ret & (AK8975_REG_ST2_DERR_MASK |
+ AK8975_REG_ST2_HOFL_MASK)) {
+ dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
ret = -EINVAL;
goto exit;
}
@@ -351,12 +317,12 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
/* Read the flux value from the appropriate register
(the register is specified in the iio device attributes). */
- ret = ak8975_read_data(client, ak8975_index_to_reg[index],
- 2, (u8 *)&meas_reg);
+ ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
if (ret < 0) {
dev_err(&client->dev, "Read axis data fails\n");
goto exit;
}
+ meas_reg = ret;
mutex_unlock(&data->lock);
@@ -395,8 +361,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
}
@@ -452,7 +418,6 @@ static int ak8975_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->lock);
- data->eoc_irq = client->irq;
data->eoc_gpio = eoc_gpio;
indio_dev->dev.parent = &client->dev;
indio_dev->channels = ak8975_channels;
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index d8d01265220b..99f4e494513b 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -60,28 +60,28 @@ static const struct iio_chan_spec magn_3d_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT |
- IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index a0f29c1d03bc..c85b56c28099 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -59,5 +59,6 @@ source "drivers/infiniband/ulp/srp/Kconfig"
source "drivers/infiniband/ulp/srpt/Kconfig"
source "drivers/infiniband/ulp/iser/Kconfig"
+source "drivers/infiniband/ulp/isert/Kconfig"
endif # INFINIBAND
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index bf846a14b9d3..b126fefe0b1c 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
obj-$(CONFIG_INFINIBAND_SRPT) += ulp/srpt/
obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
+obj-$(CONFIG_INFINIBAND_ISERT) += ulp/isert/
diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h
index ba7a1208ff9e..d619d735838b 100644
--- a/drivers/infiniband/hw/amso1100/c2.h
+++ b/drivers/infiniband/hw/amso1100/c2.h
@@ -265,7 +265,6 @@ struct c2_pd_table {
struct c2_qp_table {
struct idr idr;
spinlock_t lock;
- int last;
};
struct c2_element {
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
index 0ab826b280b2..86708dee58b1 100644
--- a/drivers/infiniband/hw/amso1100/c2_qp.c
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -385,8 +385,7 @@ static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp)
idr_preload(GFP_KERNEL);
spin_lock_irq(&c2dev->qp_table.lock);
- ret = idr_alloc(&c2dev->qp_table.idr, qp, c2dev->qp_table.last++, 0,
- GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&c2dev->qp_table.idr, qp, 0, 0, GFP_NOWAIT);
if (ret >= 0)
qp->qpn = ret;
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index a3fde52840ca..65c30ea8c1a1 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -511,12 +511,16 @@ static unsigned int select_ntuple(struct c4iw_dev *dev, struct dst_entry *dst,
static int send_connect(struct c4iw_ep *ep)
{
struct cpl_act_open_req *req;
+ struct cpl_t5_act_open_req *t5_req;
struct sk_buff *skb;
u64 opt0;
u32 opt2;
unsigned int mtu_idx;
int wscale;
- int wrlen = roundup(sizeof *req, 16);
+ int size = is_t4(ep->com.dev->rdev.lldi.adapter_type) ?
+ sizeof(struct cpl_act_open_req) :
+ sizeof(struct cpl_t5_act_open_req);
+ int wrlen = roundup(size, 16);
PDBG("%s ep %p atid %u\n", __func__, ep, ep->atid);
@@ -552,17 +556,36 @@ static int send_connect(struct c4iw_ep *ep)
opt2 |= WND_SCALE_EN(1);
t4_set_arp_err_handler(skb, NULL, act_open_req_arp_failure);
- 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 = ep->com.local_addr.sin_port;
- req->peer_port = ep->com.remote_addr.sin_port;
- req->local_ip = ep->com.local_addr.sin_addr.s_addr;
- req->peer_ip = ep->com.remote_addr.sin_addr.s_addr;
- req->opt0 = cpu_to_be64(opt0);
- req->params = cpu_to_be32(select_ntuple(ep->com.dev, ep->dst, ep->l2t));
- req->opt2 = cpu_to_be32(opt2);
+ if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) {
+ 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 = ep->com.local_addr.sin_port;
+ req->peer_port = ep->com.remote_addr.sin_port;
+ req->local_ip = ep->com.local_addr.sin_addr.s_addr;
+ req->peer_ip = ep->com.remote_addr.sin_addr.s_addr;
+ req->opt0 = cpu_to_be64(opt0);
+ req->params = cpu_to_be32(select_ntuple(ep->com.dev,
+ ep->dst, ep->l2t));
+ req->opt2 = cpu_to_be32(opt2);
+ } else {
+ 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 = ep->com.local_addr.sin_port;
+ t5_req->peer_port = ep->com.remote_addr.sin_port;
+ t5_req->local_ip = ep->com.local_addr.sin_addr.s_addr;
+ t5_req->peer_ip = ep->com.remote_addr.sin_addr.s_addr;
+ t5_req->opt0 = cpu_to_be64(opt0);
+ t5_req->params = cpu_to_be64(V_FILTER_TUPLE(
+ select_ntuple(ep->com.dev, ep->dst, ep->l2t)));
+ t5_req->opt2 = cpu_to_be32(opt2);
+ }
+
set_bit(ACT_OPEN_REQ, &ep->com.history);
return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
}
@@ -1676,9 +1699,9 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
case CPL_ERR_CONN_TIMEDOUT:
break;
case CPL_ERR_TCAM_FULL:
+ dev->rdev.stats.tcam_full++;
if (dev->rdev.lldi.enable_fw_ofld_conn) {
mutex_lock(&dev->rdev.stats.lock);
- dev->rdev.stats.tcam_full++;
mutex_unlock(&dev->rdev.stats.lock);
send_fw_act_open_req(ep,
GET_TID_TID(GET_AOPEN_ATID(
@@ -2875,12 +2898,14 @@ 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;
+ u16 vlantag, len, hdr_len, eth_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;
+ 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;
@@ -2896,7 +2921,7 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
*/
memset(&tmp_opt, 0, sizeof(tmp_opt));
tcp_clear_options(&tmp_opt);
- tcp_parse_options(skb, &tmp_opt, NULL, 0, NULL);
+ tcp_parse_options(skb, &tmp_opt, 0, NULL);
req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
@@ -2904,14 +2929,16 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
V_SYN_MAC_IDX(G_RX_MACIDX(
(__force int) htonl(l2info))) |
F_SYN_XACT_MATCH);
+ eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
+ G_RX_ETHHDR_LEN((__force int) htonl(l2info)) :
+ G_RX_T5_ETHHDR_LEN((__force int) htonl(l2info));
req->hdr_len = cpu_to_be32(V_SYN_RX_CHAN(G_RX_CHAN(
(__force int) htonl(l2info))) |
V_TCP_HDR_LEN(G_RX_TCPHDR_LEN(
(__force int) htons(hdr_len))) |
V_IP_HDR_LEN(G_RX_IPHDR_LEN(
(__force int) htons(hdr_len))) |
- V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(
- (__force int) htonl(l2info))));
+ V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(eth_hdr_len)));
req->vlan = (__force __be16) vlantag;
req->len = (__force __be16) len;
req->tos_stid = cpu_to_be32(PASS_OPEN_TID(stid) |
@@ -2999,7 +3026,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
u16 window;
struct port_info *pi;
struct net_device *pdev;
- u16 rss_qid;
+ u16 rss_qid, eth_hdr_len;
int step;
u32 tx_chan;
struct neighbour *neigh;
@@ -3028,7 +3055,10 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
goto reject;
}
- if (G_RX_ETHHDR_LEN(ntohl(cpl->l2info)) == ETH_HLEN) {
+ eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
+ G_RX_ETHHDR_LEN(htonl(cpl->l2info)) :
+ G_RX_T5_ETHHDR_LEN(htonl(cpl->l2info));
+ if (eth_hdr_len == ETH_HLEN) {
eh = (struct ethhdr *)(req + 1);
iph = (struct iphdr *)(eh + 1);
} else {
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 80069ad595c1..ae656016e1ae 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -41,10 +41,20 @@
#define DRV_VERSION "0.1"
MODULE_AUTHOR("Steve Wise");
-MODULE_DESCRIPTION("Chelsio T4 RDMA Driver");
+MODULE_DESCRIPTION("Chelsio T4/T5 RDMA Driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
+static int allow_db_fc_on_t5;
+module_param(allow_db_fc_on_t5, int, 0644);
+MODULE_PARM_DESC(allow_db_fc_on_t5,
+ "Allow DB Flow Control on T5 (default = 0)");
+
+static int allow_db_coalescing_on_t5;
+module_param(allow_db_coalescing_on_t5, int, 0644);
+MODULE_PARM_DESC(allow_db_coalescing_on_t5,
+ "Allow DB Coalescing on T5 (default = 0)");
+
struct uld_ctx {
struct list_head entry;
struct cxgb4_lld_info lldi;
@@ -614,7 +624,7 @@ static int rdma_supported(const struct cxgb4_lld_info *infop)
{
return infop->vr->stag.size > 0 && infop->vr->pbl.size > 0 &&
infop->vr->rq.size > 0 && infop->vr->qp.size > 0 &&
- infop->vr->cq.size > 0 && infop->vr->ocq.size > 0;
+ infop->vr->cq.size > 0;
}
static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
@@ -627,6 +637,22 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
pci_name(infop->pdev));
return ERR_PTR(-ENOSYS);
}
+ if (!ocqp_supported(infop))
+ pr_info("%s: On-Chip Queues not supported on this device.\n",
+ pci_name(infop->pdev));
+
+ if (!is_t4(infop->adapter_type)) {
+ if (!allow_db_fc_on_t5) {
+ db_fc_threshold = 100000;
+ pr_info("DB Flow Control Disabled.\n");
+ }
+
+ if (!allow_db_coalescing_on_t5) {
+ db_coalescing_threshold = -1;
+ pr_info("DB Coalescing Disabled.\n");
+ }
+ }
+
devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
if (!devp) {
printk(KERN_ERR MOD "Cannot allocate ib device\n");
@@ -678,8 +704,8 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
int i;
if (!vers_printed++)
- printk(KERN_INFO MOD "Chelsio T4 RDMA Driver - version %s\n",
- DRV_VERSION);
+ pr_info("Chelsio T4/T5 RDMA Driver - version %s\n",
+ DRV_VERSION);
ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
if (!ctx) {
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 7eec5e13fa8c..485183ad34cd 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -162,7 +162,7 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
return min((int)T4_MAX_NUM_STAG, (int)(rdev->lldi.vr->stag.size >> 5));
}
-#define C4IW_WR_TO (10*HZ)
+#define C4IW_WR_TO (30*HZ)
struct c4iw_wr_wait {
struct completion completion;
@@ -369,7 +369,6 @@ struct c4iw_fr_page_list {
DEFINE_DMA_UNMAP_ADDR(mapping);
dma_addr_t dma_addr;
struct c4iw_dev *dev;
- int size;
};
static inline struct c4iw_fr_page_list *to_c4iw_fr_page_list(
@@ -817,6 +816,15 @@ static inline int compute_wscale(int win)
return wscale;
}
+static inline int ocqp_supported(const struct cxgb4_lld_info *infop)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
+ return infop->vr->ocq.size > 0;
+#else
+ return 0;
+#endif
+}
+
u32 c4iw_id_alloc(struct c4iw_id_table *alloc);
void c4iw_id_free(struct c4iw_id_table *alloc, u32 obj);
int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,
@@ -930,6 +938,8 @@ extern struct cxgb4_client t4c_client;
extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS];
extern int c4iw_max_read_depth;
extern int db_fc_threshold;
+extern int db_coalescing_threshold;
+extern int use_dsgl;
#endif
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 903a92d6f91d..4cb8eb24497c 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -30,16 +30,76 @@
* SOFTWARE.
*/
+#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <rdma/ib_umem.h>
#include <linux/atomic.h>
#include "iw_cxgb4.h"
+int use_dsgl = 1;
+module_param(use_dsgl, int, 0644);
+MODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=1)");
+
#define T4_ULPTX_MIN_IO 32
#define C4IW_MAX_INLINE_SIZE 96
+#define T4_ULPTX_MAX_DMA 1024
+#define C4IW_INLINE_THRESHOLD 128
-static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
- void *data)
+static int inline_threshold = C4IW_INLINE_THRESHOLD;
+module_param(inline_threshold, int, 0644);
+MODULE_PARM_DESC(inline_threshold, "inline vs dsgl threshold (default=128)");
+
+static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
+ u32 len, dma_addr_t data, int wait)
+{
+ struct sk_buff *skb;
+ struct ulp_mem_io *req;
+ struct ulptx_sgl *sgl;
+ u8 wr_len;
+ int ret = 0;
+ struct c4iw_wr_wait wr_wait;
+
+ addr &= 0x7FFFFFF;
+
+ if (wait)
+ c4iw_init_wr_wait(&wr_wait);
+ wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
+
+ skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
+ if (!skb)
+ return -ENOMEM;
+ set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
+
+ req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
+ memset(req, 0, wr_len);
+ INIT_ULPTX_WR(req, wr_len, 0, 0);
+ req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
+ (wait ? FW_WR_COMPL(1) : 0));
+ req->wr.wr_lo = wait ? (__force __be64)&wr_wait : 0;
+ req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
+ req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
+ req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1));
+ req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(len>>5));
+ req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
+ req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR(addr));
+
+ sgl = (struct ulptx_sgl *)(req + 1);
+ sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD(ULP_TX_SC_DSGL) |
+ ULPTX_NSGE(1));
+ sgl->len0 = cpu_to_be32(len);
+ sgl->addr0 = cpu_to_be64(data);
+
+ ret = c4iw_ofld_send(rdev, skb);
+ if (ret)
+ return ret;
+ if (wait)
+ ret = c4iw_wait_for_reply(rdev, &wr_wait, 0, 0, __func__);
+ return ret;
+}
+
+static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
+ void *data)
{
struct sk_buff *skb;
struct ulp_mem_io *req;
@@ -47,6 +107,12 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
u8 wr_len, *to_dp, *from_dp;
int copy_len, num_wqe, i, ret = 0;
struct c4iw_wr_wait wr_wait;
+ __be32 cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
+
+ if (is_t4(rdev->lldi.adapter_type))
+ cmd |= cpu_to_be32(ULP_MEMIO_ORDER(1));
+ else
+ cmd |= cpu_to_be32(V_T5_ULP_MEMIO_IMM(1));
addr &= 0x7FFFFFF;
PDBG("%s addr 0x%x len %u\n", __func__, addr, len);
@@ -77,7 +143,7 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
req->wr.wr_mid = cpu_to_be32(
FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
- req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE) | (1<<23));
+ req->cmd = cmd;
req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(
DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr),
@@ -107,6 +173,67 @@ static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
return ret;
}
+int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len, void *data)
+{
+ u32 remain = len;
+ u32 dmalen;
+ int ret = 0;
+ dma_addr_t daddr;
+ dma_addr_t save;
+
+ daddr = dma_map_single(&rdev->lldi.pdev->dev, data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&rdev->lldi.pdev->dev, daddr))
+ return -1;
+ save = daddr;
+
+ while (remain > inline_threshold) {
+ if (remain < T4_ULPTX_MAX_DMA) {
+ if (remain & ~T4_ULPTX_MIN_IO)
+ dmalen = remain & ~(T4_ULPTX_MIN_IO-1);
+ else
+ dmalen = remain;
+ } else
+ dmalen = T4_ULPTX_MAX_DMA;
+ remain -= dmalen;
+ ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr,
+ !remain);
+ if (ret)
+ goto out;
+ addr += dmalen >> 5;
+ data += dmalen;
+ daddr += dmalen;
+ }
+ if (remain)
+ ret = _c4iw_write_mem_inline(rdev, addr, remain, data);
+out:
+ dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE);
+ return ret;
+}
+
+/*
+ * write len bytes of data into addr (32B aligned address)
+ * If data is NULL, clear len byte of memory to zero.
+ */
+static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
+ void *data)
+{
+ if (is_t5(rdev->lldi.adapter_type) && use_dsgl) {
+ if (len > inline_threshold) {
+ if (_c4iw_write_mem_dma(rdev, addr, len, data)) {
+ printk_ratelimited(KERN_WARNING
+ "%s: dma map"
+ " failure (non fatal)\n",
+ pci_name(rdev->lldi.pdev));
+ return _c4iw_write_mem_inline(rdev, addr, len,
+ data);
+ } else
+ return 0;
+ } else
+ return _c4iw_write_mem_inline(rdev, addr, len, data);
+ } else
+ return _c4iw_write_mem_inline(rdev, addr, len, data);
+}
+
/*
* Build and write a TPT entry.
* IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size,
@@ -760,19 +887,23 @@ struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl(struct ib_device *device,
struct c4iw_fr_page_list *c4pl;
struct c4iw_dev *dev = to_c4iw_dev(device);
dma_addr_t dma_addr;
- int size = sizeof *c4pl + page_list_len * sizeof(u64);
+ int pll_len = roundup(page_list_len * sizeof(u64), 32);
- c4pl = dma_alloc_coherent(&dev->rdev.lldi.pdev->dev, size,
- &dma_addr, GFP_KERNEL);
+ c4pl = kmalloc(sizeof(*c4pl), GFP_KERNEL);
if (!c4pl)
return ERR_PTR(-ENOMEM);
+ 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->size = size;
- c4pl->ibpl.page_list = (u64 *)(c4pl + 1);
- c4pl->ibpl.max_page_list_len = page_list_len;
+ c4pl->ibpl.max_page_list_len = pll_len;
return &c4pl->ibpl;
}
@@ -781,8 +912,10 @@ void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *ibpl)
{
struct c4iw_fr_page_list *c4pl = to_c4iw_fr_page_list(ibpl);
- dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev, c4pl->size,
- c4pl, dma_unmap_addr(c4pl, mapping));
+ dma_free_coherent(&c4pl->dev->rdev.lldi.pdev->dev,
+ c4pl->ibpl.max_page_list_len,
+ c4pl->ibpl.page_list, dma_unmap_addr(c4pl, mapping));
+ kfree(c4pl);
}
int c4iw_dereg_mr(struct ib_mr *ib_mr)
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index e084fdc6da7f..7e94c9a656a1 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -162,8 +162,14 @@ 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
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ else {
+ if (is_t5(rdev->lldi.adapter_type))
+ vma->vm_page_prot =
+ t4_pgprot_wc(vma->vm_page_prot);
+ else
+ vma->vm_page_prot =
+ pgprot_noncached(vma->vm_page_prot);
+ }
ret = io_remap_pfn_range(vma, vma->vm_start,
addr >> PAGE_SHIFT,
len, vma->vm_page_prot);
@@ -263,7 +269,7 @@ static int c4iw_query_device(struct ib_device *ibdev,
dev = to_c4iw_dev(ibdev);
memset(props, 0, sizeof *props);
memcpy(&props->sys_image_guid, dev->rdev.lldi.ports[0]->dev_addr, 6);
- props->hw_ver = dev->rdev.lldi.adapter_type;
+ props->hw_ver = CHELSIO_CHIP_RELEASE(dev->rdev.lldi.adapter_type);
props->fw_ver = dev->rdev.lldi.fw_vers;
props->device_cap_flags = dev->device_cap_flags;
props->page_size_cap = T4_PAGESIZE_MASK;
@@ -346,7 +352,8 @@ static ssize_t show_rev(struct device *dev, struct device_attribute *attr,
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev.dev);
PDBG("%s dev 0x%p\n", __func__, dev);
- return sprintf(buf, "%d\n", c4iw_dev->rdev.lldi.adapter_type);
+ return sprintf(buf, "%d\n",
+ CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type));
}
static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 70b1808a08f4..5b059e2d80cc 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -42,10 +42,21 @@ static int ocqp_support = 1;
module_param(ocqp_support, int, 0644);
MODULE_PARM_DESC(ocqp_support, "Support on-chip SQs (default=1)");
-int db_fc_threshold = 2000;
+int db_fc_threshold = 1000;
module_param(db_fc_threshold, int, 0644);
-MODULE_PARM_DESC(db_fc_threshold, "QP count/threshold that triggers automatic "
- "db flow control mode (default = 2000)");
+MODULE_PARM_DESC(db_fc_threshold,
+ "QP count/threshold that triggers"
+ " automatic db flow control mode (default = 1000)");
+
+int db_coalescing_threshold;
+module_param(db_coalescing_threshold, int, 0644);
+MODULE_PARM_DESC(db_coalescing_threshold,
+ "QP count/threshold that triggers"
+ " disabling db coalescing (default = 0)");
+
+static int max_fr_immd = T4_MAX_FR_IMMD;
+module_param(max_fr_immd, int, 0644);
+MODULE_PARM_DESC(max_fr_immd, "fastreg threshold for using DSGL instead of immedate");
static void set_state(struct c4iw_qp *qhp, enum c4iw_qp_state state)
{
@@ -76,7 +87,7 @@ static void dealloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
static int alloc_oc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq)
{
- if (!ocqp_support || !t4_ocqp_supported())
+ if (!ocqp_support || !ocqp_supported(&rdev->lldi))
return -ENOSYS;
sq->dma_addr = c4iw_ocqp_pool_alloc(rdev, sq->memsize);
if (!sq->dma_addr)
@@ -129,7 +140,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
int wr_len;
struct c4iw_wr_wait wr_wait;
struct sk_buff *skb;
- int ret;
+ int ret = 0;
int eqsize;
wq->sq.qid = c4iw_get_qpid(rdev, uctx);
@@ -169,17 +180,14 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
}
if (user) {
- ret = alloc_oc_sq(rdev, &wq->sq);
- if (ret)
+ if (alloc_oc_sq(rdev, &wq->sq) && alloc_host_sq(rdev, &wq->sq))
goto free_hwaddr;
-
- ret = alloc_host_sq(rdev, &wq->sq);
- if (ret)
- goto free_sq;
- } else
+ } else {
ret = alloc_host_sq(rdev, &wq->sq);
if (ret)
goto free_hwaddr;
+ }
+
memset(wq->sq.queue, 0, wq->sq.memsize);
dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
@@ -534,7 +542,7 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
}
static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
- struct ib_send_wr *wr, u8 *len16)
+ struct ib_send_wr *wr, u8 *len16, u8 t5dev)
{
struct fw_ri_immd *imdp;
@@ -556,28 +564,51 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe,
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 &
0xffffffff);
- WARN_ON(pbllen > T4_MAX_FR_IMMD);
- imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
- imdp->op = FW_RI_DATA_IMMD;
- imdp->r1 = 0;
- imdp->r2 = 0;
- 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]);
- rem -= sizeof *p;
- if (++p == (__be64 *)&sq->queue[sq->size])
- p = (__be64 *)sq->queue;
- }
- BUG_ON(rem < 0);
- while (rem) {
- *p = 0;
- rem -= sizeof *p;
- if (++p == (__be64 *)&sq->queue[sq->size])
- p = (__be64 *)sq->queue;
+
+ 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]);
+ }
+
+ 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->len0 = cpu_to_be32(pbllen);
+
+ *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*sglp), 16);
+ } else {
+ imdp = (struct fw_ri_immd *)(&wqe->fr + 1);
+ imdp->op = FW_RI_DATA_IMMD;
+ imdp->r1 = 0;
+ imdp->r2 = 0;
+ 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]);
+ rem -= sizeof(*p);
+ if (++p == (__be64 *)&sq->queue[sq->size])
+ p = (__be64 *)sq->queue;
+ }
+ BUG_ON(rem < 0);
+ while (rem) {
+ *p = 0;
+ rem -= sizeof(*p);
+ if (++p == (__be64 *)&sq->queue[sq->size])
+ p = (__be64 *)sq->queue;
+ }
+ *len16 = DIV_ROUND_UP(sizeof(wqe->fr) + sizeof(*imdp)
+ + pbllen, 16);
}
- *len16 = DIV_ROUND_UP(sizeof wqe->fr + sizeof *imdp + pbllen, 16);
return 0;
}
@@ -678,7 +709,10 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_FAST_REG_MR:
fw_opcode = FW_RI_FR_NSMR_WR;
swsqe->opcode = FW_RI_FAST_REGISTER;
- err = build_fastreg(&qhp->wq.sq, wqe, wr, &len16);
+ err = build_fastreg(&qhp->wq.sq, wqe, 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)
@@ -1450,6 +1484,9 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
rhp->db_state = NORMAL;
idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
}
+ if (db_coalescing_threshold >= 0)
+ if (rhp->qpcnt <= db_coalescing_threshold)
+ cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]);
spin_unlock_irq(&rhp->lock);
atomic_dec(&qhp->refcnt);
wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
@@ -1561,11 +1598,15 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
spin_lock_irq(&rhp->lock);
if (rhp->db_state != NORMAL)
t4_disable_wq_db(&qhp->wq);
- if (++rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
+ rhp->qpcnt++;
+ if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
rhp->rdev.stats.db_state_transitions++;
rhp->db_state = FLOW_CONTROL;
idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
}
+ if (db_coalescing_threshold >= 0)
+ if (rhp->qpcnt > db_coalescing_threshold)
+ cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]);
ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
spin_unlock_irq(&rhp->lock);
if (ret)
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 16f26ab29302..ebcb03bd1b72 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -84,7 +84,7 @@ struct t4_status_page {
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
sizeof(struct fw_ri_immd)) & ~31UL)
-#define T4_MAX_FR_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
+#define T4_MAX_FR_DEPTH (1024 / sizeof(u64))
#define T4_RQ_NUM_SLOTS 2
#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS)
@@ -280,15 +280,6 @@ static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
#endif
}
-static inline int t4_ocqp_supported(void)
-{
-#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
- return 1;
-#else
- return 0;
-#endif
-}
-
enum {
T4_SQ_ONCHIP = (1<<0),
};
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index add98d01476c..d1f5f1dd77b0 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -204,7 +204,6 @@ static struct id_map_entry *
id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
{
int ret;
- static int next_id;
struct id_map_entry *ent;
struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov;
@@ -223,9 +222,8 @@ id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id)
idr_preload(GFP_KERNEL);
spin_lock(&to_mdev(ibdev)->sriov.id_map_lock);
- ret = idr_alloc(&sriov->pv_id_table, ent, next_id, 0, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(&sriov->pv_id_table, ent, 0, 0, GFP_NOWAIT);
if (ret >= 0) {
- next_id = max(ret + 1, 0);
ent->pv_cm_id = (u32)ret;
sl_id_map_add(ibdev, ent);
list_add_tail(&ent->list, &sriov->cm_list);
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index ae67df35dd4d..73b3a7132587 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -228,7 +228,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
vector = dev->eq_table[vector % ibdev->num_comp_vectors];
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
- cq->db.dma, &cq->mcq, vector, 0);
+ cq->db.dma, &cq->mcq, vector, 0, 0);
if (err)
goto err_dbmap;
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 67647e264611..418004c93feb 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2948,7 +2948,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
nesvnic->netdev->name, vlan_tag);
- __vlan_hwaccel_put_tag(rx_skb, vlan_tag);
+ __vlan_hwaccel_put_tag(rx_skb, htons(ETH_P_8021Q), vlan_tag);
}
if (nes_use_lro)
lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 85cf4d1ac442..49eb5111d2cd 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1599,7 +1599,7 @@ static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev,
/* Enable/Disable VLAN Stripping */
u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
u32temp &= 0xfdffffff;
else
u32temp |= 0x02000000;
@@ -1614,10 +1614,10 @@ static netdev_features_t nes_fix_features(struct net_device *netdev, netdev_feat
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -1628,7 +1628,7 @@ static int nes_set_features(struct net_device *netdev, netdev_features_t feature
struct nes_device *nesdev = nesvnic->nesdev;
u32 changed = netdev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
nes_vlan_mode(netdev, nesdev, features);
return 0;
@@ -1706,11 +1706,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
netdev->dev_addr[4] = (u8)(u64temp>>8);
netdev->dev_addr[5] = (u8)u64temp;
- netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX;
if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
netdev->hw_features |= NETIF_F_TSO;
- netdev->features = netdev->hw_features | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX;
+ netdev->features = netdev->hw_features | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX;
netdev->hw_features |= NETIF_F_LRO;
nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c
index 08a6c6d39e56..911205d3d5a0 100644
--- a/drivers/infiniband/hw/qib/qib_sd7220.c
+++ b/drivers/infiniband/hw/qib/qib_sd7220.c
@@ -44,7 +44,7 @@
#include "qib.h"
#include "qib_7220.h"
-#define SD7220_FW_NAME "intel/sd7220.fw"
+#define SD7220_FW_NAME "qlogic/sd7220.fw"
MODULE_FIRMWARE(SD7220_FW_NAME);
/*
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 8534afd04e7c..554b9063da54 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -730,7 +730,8 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ((header->proto != htons(ETH_P_IP)) &&
(header->proto != htons(ETH_P_IPV6)) &&
(header->proto != htons(ETH_P_ARP)) &&
- (header->proto != htons(ETH_P_RARP))) {
+ (header->proto != htons(ETH_P_RARP)) &&
+ (header->proto != htons(ETH_P_TIPC))) {
/* ethertype not supported by IPoIB */
++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
@@ -751,6 +752,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
switch (header->proto) {
case htons(ETH_P_IP):
case htons(ETH_P_IPV6):
+ case htons(ETH_P_TIPC):
neigh = ipoib_neigh_get(dev, cb->hwaddr);
if (unlikely(!neigh)) {
neigh_add_path(skb, cb->hwaddr, dev);
diff --git a/drivers/infiniband/ulp/isert/Kconfig b/drivers/infiniband/ulp/isert/Kconfig
new file mode 100644
index 000000000000..ce3fd32167dc
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/Kconfig
@@ -0,0 +1,5 @@
+config INFINIBAND_ISERT
+ tristate "iSCSI Extentions for RDMA (iSER) target support"
+ depends on INET && INFINIBAND_ADDR_TRANS && TARGET_CORE && ISCSI_TARGET
+ ---help---
+ Support for iSCSI Extentions for RDMA (iSER) Target on Infiniband fabrics.
diff --git a/drivers/infiniband/ulp/isert/Makefile b/drivers/infiniband/ulp/isert/Makefile
new file mode 100644
index 000000000000..c8bf2421f5bc
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/Makefile
@@ -0,0 +1,2 @@
+ccflags-y := -Idrivers/target -Idrivers/target/iscsi
+obj-$(CONFIG_INFINIBAND_ISERT) += ib_isert.o
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
new file mode 100644
index 000000000000..41712f096515
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -0,0 +1,2281 @@
+/*******************************************************************************
+ * This file contains iSCSI extentions for RDMA (iSER) Verbs
+ *
+ * (c) Copyright 2013 RisingTide Systems LLC.
+ *
+ * Nicholas A. Bellinger <nab@linux-iscsi.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ ****************************************************************************/
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
+
+#include "isert_proto.h"
+#include "ib_isert.h"
+
+#define ISERT_MAX_CONN 8
+#define ISER_MAX_RX_CQ_LEN (ISERT_QP_MAX_RECV_DTOS * ISERT_MAX_CONN)
+#define ISER_MAX_TX_CQ_LEN (ISERT_QP_MAX_REQ_DTOS * ISERT_MAX_CONN)
+
+static DEFINE_MUTEX(device_list_mutex);
+static LIST_HEAD(device_list);
+static struct workqueue_struct *isert_rx_wq;
+static struct workqueue_struct *isert_comp_wq;
+static struct kmem_cache *isert_cmd_cache;
+
+static void
+isert_qp_event_callback(struct ib_event *e, void *context)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)context;
+
+ pr_err("isert_qp_event_callback event: %d\n", e->event);
+ switch (e->event) {
+ case IB_EVENT_COMM_EST:
+ rdma_notify(isert_conn->conn_cm_id, IB_EVENT_COMM_EST);
+ break;
+ case IB_EVENT_QP_LAST_WQE_REACHED:
+ pr_warn("Reached TX IB_EVENT_QP_LAST_WQE_REACHED:\n");
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+isert_query_device(struct ib_device *ib_dev, struct ib_device_attr *devattr)
+{
+ int ret;
+
+ ret = ib_query_device(ib_dev, devattr);
+ if (ret) {
+ pr_err("ib_query_device() failed: %d\n", ret);
+ return ret;
+ }
+ pr_debug("devattr->max_sge: %d\n", devattr->max_sge);
+ pr_debug("devattr->max_sge_rd: %d\n", devattr->max_sge_rd);
+
+ return 0;
+}
+
+static int
+isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id)
+{
+ struct isert_device *device = isert_conn->conn_device;
+ struct ib_qp_init_attr attr;
+ struct ib_device_attr devattr;
+ int ret, index, min_index = 0;
+
+ memset(&devattr, 0, sizeof(struct ib_device_attr));
+ ret = isert_query_device(cma_id->device, &devattr);
+ if (ret)
+ return ret;
+
+ mutex_lock(&device_list_mutex);
+ for (index = 0; index < device->cqs_used; index++)
+ if (device->cq_active_qps[index] <
+ device->cq_active_qps[min_index])
+ min_index = index;
+ device->cq_active_qps[min_index]++;
+ pr_debug("isert_conn_setup_qp: Using min_index: %d\n", min_index);
+ mutex_unlock(&device_list_mutex);
+
+ memset(&attr, 0, sizeof(struct ib_qp_init_attr));
+ attr.event_handler = isert_qp_event_callback;
+ attr.qp_context = isert_conn;
+ attr.send_cq = device->dev_tx_cq[min_index];
+ attr.recv_cq = device->dev_rx_cq[min_index];
+ attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS;
+ attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS;
+ /*
+ * FIXME: Use devattr.max_sge - 2 for max_send_sge as
+ * work-around for RDMA_READ..
+ */
+ attr.cap.max_send_sge = devattr.max_sge - 2;
+ isert_conn->max_sge = attr.cap.max_send_sge;
+
+ attr.cap.max_recv_sge = 1;
+ attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+ attr.qp_type = IB_QPT_RC;
+
+ pr_debug("isert_conn_setup_qp cma_id->device: %p\n",
+ cma_id->device);
+ pr_debug("isert_conn_setup_qp conn_pd->device: %p\n",
+ isert_conn->conn_pd->device);
+
+ ret = rdma_create_qp(cma_id, isert_conn->conn_pd, &attr);
+ if (ret) {
+ pr_err("rdma_create_qp failed for cma_id %d\n", ret);
+ return ret;
+ }
+ isert_conn->conn_qp = cma_id->qp;
+ pr_debug("rdma_create_qp() returned success >>>>>>>>>>>>>>>>>>>>>>>>>.\n");
+
+ return 0;
+}
+
+static void
+isert_cq_event_callback(struct ib_event *e, void *context)
+{
+ pr_debug("isert_cq_event_callback event: %d\n", e->event);
+}
+
+static int
+isert_alloc_rx_descriptors(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iser_rx_desc *rx_desc;
+ struct ib_sge *rx_sg;
+ u64 dma_addr;
+ int i, j;
+
+ isert_conn->conn_rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS *
+ sizeof(struct iser_rx_desc), GFP_KERNEL);
+ if (!isert_conn->conn_rx_descs)
+ goto fail;
+
+ rx_desc = isert_conn->conn_rx_descs;
+
+ for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) {
+ dma_addr = ib_dma_map_single(ib_dev, (void *)rx_desc,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(ib_dev, dma_addr))
+ goto dma_map_fail;
+
+ rx_desc->dma_addr = dma_addr;
+
+ rx_sg = &rx_desc->rx_sg;
+ rx_sg->addr = rx_desc->dma_addr;
+ rx_sg->length = ISER_RX_PAYLOAD_SIZE;
+ rx_sg->lkey = isert_conn->conn_mr->lkey;
+ }
+
+ isert_conn->conn_rx_desc_head = 0;
+ return 0;
+
+dma_map_fail:
+ rx_desc = isert_conn->conn_rx_descs;
+ for (j = 0; j < i; j++, rx_desc++) {
+ ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ }
+ kfree(isert_conn->conn_rx_descs);
+ isert_conn->conn_rx_descs = NULL;
+fail:
+ return -ENOMEM;
+}
+
+static void
+isert_free_rx_descriptors(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iser_rx_desc *rx_desc;
+ int i;
+
+ if (!isert_conn->conn_rx_descs)
+ return;
+
+ rx_desc = isert_conn->conn_rx_descs;
+ for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) {
+ ib_dma_unmap_single(ib_dev, rx_desc->dma_addr,
+ ISER_RX_PAYLOAD_SIZE, DMA_FROM_DEVICE);
+ }
+
+ kfree(isert_conn->conn_rx_descs);
+ isert_conn->conn_rx_descs = NULL;
+}
+
+static void isert_cq_tx_callback(struct ib_cq *, void *);
+static void isert_cq_rx_callback(struct ib_cq *, void *);
+
+static int
+isert_create_device_ib_res(struct isert_device *device)
+{
+ struct ib_device *ib_dev = device->ib_device;
+ struct isert_cq_desc *cq_desc;
+ int ret = 0, i, j;
+
+ device->cqs_used = min_t(int, num_online_cpus(),
+ device->ib_device->num_comp_vectors);
+ device->cqs_used = min(ISERT_MAX_CQ, device->cqs_used);
+ pr_debug("Using %d CQs, device %s supports %d vectors\n",
+ device->cqs_used, device->ib_device->name,
+ device->ib_device->num_comp_vectors);
+ device->cq_desc = kzalloc(sizeof(struct isert_cq_desc) *
+ device->cqs_used, GFP_KERNEL);
+ if (!device->cq_desc) {
+ pr_err("Unable to allocate device->cq_desc\n");
+ return -ENOMEM;
+ }
+ cq_desc = device->cq_desc;
+
+ device->dev_pd = ib_alloc_pd(ib_dev);
+ if (IS_ERR(device->dev_pd)) {
+ ret = PTR_ERR(device->dev_pd);
+ pr_err("ib_alloc_pd failed for dev_pd: %d\n", ret);
+ goto out_cq_desc;
+ }
+
+ for (i = 0; i < device->cqs_used; i++) {
+ cq_desc[i].device = device;
+ cq_desc[i].cq_index = i;
+
+ device->dev_rx_cq[i] = ib_create_cq(device->ib_device,
+ isert_cq_rx_callback,
+ isert_cq_event_callback,
+ (void *)&cq_desc[i],
+ ISER_MAX_RX_CQ_LEN, i);
+ if (IS_ERR(device->dev_rx_cq[i]))
+ goto out_cq;
+
+ device->dev_tx_cq[i] = ib_create_cq(device->ib_device,
+ isert_cq_tx_callback,
+ isert_cq_event_callback,
+ (void *)&cq_desc[i],
+ ISER_MAX_TX_CQ_LEN, i);
+ if (IS_ERR(device->dev_tx_cq[i]))
+ goto out_cq;
+
+ if (ib_req_notify_cq(device->dev_rx_cq[i], IB_CQ_NEXT_COMP))
+ goto out_cq;
+
+ if (ib_req_notify_cq(device->dev_tx_cq[i], IB_CQ_NEXT_COMP))
+ goto out_cq;
+ }
+
+ device->dev_mr = ib_get_dma_mr(device->dev_pd, IB_ACCESS_LOCAL_WRITE);
+ if (IS_ERR(device->dev_mr)) {
+ ret = PTR_ERR(device->dev_mr);
+ pr_err("ib_get_dma_mr failed for dev_mr: %d\n", ret);
+ goto out_cq;
+ }
+
+ return 0;
+
+out_cq:
+ for (j = 0; j < i; j++) {
+ cq_desc = &device->cq_desc[j];
+
+ if (device->dev_rx_cq[j]) {
+ cancel_work_sync(&cq_desc->cq_rx_work);
+ ib_destroy_cq(device->dev_rx_cq[j]);
+ }
+ if (device->dev_tx_cq[j]) {
+ cancel_work_sync(&cq_desc->cq_tx_work);
+ ib_destroy_cq(device->dev_tx_cq[j]);
+ }
+ }
+ ib_dealloc_pd(device->dev_pd);
+
+out_cq_desc:
+ kfree(device->cq_desc);
+
+ return ret;
+}
+
+static void
+isert_free_device_ib_res(struct isert_device *device)
+{
+ struct isert_cq_desc *cq_desc;
+ int i;
+
+ for (i = 0; i < device->cqs_used; i++) {
+ cq_desc = &device->cq_desc[i];
+
+ cancel_work_sync(&cq_desc->cq_rx_work);
+ cancel_work_sync(&cq_desc->cq_tx_work);
+ ib_destroy_cq(device->dev_rx_cq[i]);
+ ib_destroy_cq(device->dev_tx_cq[i]);
+ device->dev_rx_cq[i] = NULL;
+ device->dev_tx_cq[i] = NULL;
+ }
+
+ ib_dereg_mr(device->dev_mr);
+ ib_dealloc_pd(device->dev_pd);
+ kfree(device->cq_desc);
+}
+
+static void
+isert_device_try_release(struct isert_device *device)
+{
+ mutex_lock(&device_list_mutex);
+ device->refcount--;
+ if (!device->refcount) {
+ isert_free_device_ib_res(device);
+ list_del(&device->dev_node);
+ kfree(device);
+ }
+ mutex_unlock(&device_list_mutex);
+}
+
+static struct isert_device *
+isert_device_find_by_ib_dev(struct rdma_cm_id *cma_id)
+{
+ struct isert_device *device;
+ int ret;
+
+ mutex_lock(&device_list_mutex);
+ list_for_each_entry(device, &device_list, dev_node) {
+ if (device->ib_device->node_guid == cma_id->device->node_guid) {
+ device->refcount++;
+ mutex_unlock(&device_list_mutex);
+ return device;
+ }
+ }
+
+ device = kzalloc(sizeof(struct isert_device), GFP_KERNEL);
+ if (!device) {
+ mutex_unlock(&device_list_mutex);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ INIT_LIST_HEAD(&device->dev_node);
+
+ device->ib_device = cma_id->device;
+ ret = isert_create_device_ib_res(device);
+ if (ret) {
+ kfree(device);
+ mutex_unlock(&device_list_mutex);
+ return ERR_PTR(ret);
+ }
+
+ device->refcount++;
+ list_add_tail(&device->dev_node, &device_list);
+ mutex_unlock(&device_list_mutex);
+
+ return device;
+}
+
+static int
+isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+ struct iscsi_np *np = cma_id->context;
+ struct isert_np *isert_np = np->np_context;
+ struct isert_conn *isert_conn;
+ struct isert_device *device;
+ struct ib_device *ib_dev = cma_id->device;
+ int ret = 0;
+
+ pr_debug("Entering isert_connect_request cma_id: %p, context: %p\n",
+ cma_id, cma_id->context);
+
+ isert_conn = kzalloc(sizeof(struct isert_conn), GFP_KERNEL);
+ if (!isert_conn) {
+ pr_err("Unable to allocate isert_conn\n");
+ return -ENOMEM;
+ }
+ isert_conn->state = ISER_CONN_INIT;
+ INIT_LIST_HEAD(&isert_conn->conn_accept_node);
+ init_completion(&isert_conn->conn_login_comp);
+ init_waitqueue_head(&isert_conn->conn_wait);
+ init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+ kref_init(&isert_conn->conn_kref);
+ kref_get(&isert_conn->conn_kref);
+
+ cma_id->context = isert_conn;
+ isert_conn->conn_cm_id = cma_id;
+ isert_conn->responder_resources = event->param.conn.responder_resources;
+ isert_conn->initiator_depth = event->param.conn.initiator_depth;
+ pr_debug("Using responder_resources: %u initiator_depth: %u\n",
+ isert_conn->responder_resources, isert_conn->initiator_depth);
+
+ isert_conn->login_buf = kzalloc(ISCSI_DEF_MAX_RECV_SEG_LEN +
+ ISER_RX_LOGIN_SIZE, GFP_KERNEL);
+ if (!isert_conn->login_buf) {
+ pr_err("Unable to allocate isert_conn->login_buf\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ isert_conn->login_req_buf = isert_conn->login_buf;
+ isert_conn->login_rsp_buf = isert_conn->login_buf +
+ ISCSI_DEF_MAX_RECV_SEG_LEN;
+ pr_debug("Set login_buf: %p login_req_buf: %p login_rsp_buf: %p\n",
+ isert_conn->login_buf, isert_conn->login_req_buf,
+ isert_conn->login_rsp_buf);
+
+ isert_conn->login_req_dma = ib_dma_map_single(ib_dev,
+ (void *)isert_conn->login_req_buf,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE);
+
+ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_req_dma);
+ if (ret) {
+ pr_err("ib_dma_mapping_error failed for login_req_dma: %d\n",
+ ret);
+ isert_conn->login_req_dma = 0;
+ goto out_login_buf;
+ }
+
+ isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev,
+ (void *)isert_conn->login_rsp_buf,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+
+ ret = ib_dma_mapping_error(ib_dev, isert_conn->login_rsp_dma);
+ if (ret) {
+ pr_err("ib_dma_mapping_error failed for login_rsp_dma: %d\n",
+ ret);
+ isert_conn->login_rsp_dma = 0;
+ goto out_req_dma_map;
+ }
+
+ device = isert_device_find_by_ib_dev(cma_id);
+ if (IS_ERR(device)) {
+ ret = PTR_ERR(device);
+ goto out_rsp_dma_map;
+ }
+
+ isert_conn->conn_device = device;
+ isert_conn->conn_pd = device->dev_pd;
+ isert_conn->conn_mr = device->dev_mr;
+
+ ret = isert_conn_setup_qp(isert_conn, cma_id);
+ if (ret)
+ goto out_conn_dev;
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ list_add_tail(&isert_np->np_accept_list, &isert_conn->conn_accept_node);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ pr_debug("isert_connect_request() waking up np_accept_wq: %p\n", np);
+ wake_up(&isert_np->np_accept_wq);
+ return 0;
+
+out_conn_dev:
+ isert_device_try_release(device);
+out_rsp_dma_map:
+ ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+out_req_dma_map:
+ ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+ ISCSI_DEF_MAX_RECV_SEG_LEN, DMA_FROM_DEVICE);
+out_login_buf:
+ kfree(isert_conn->login_buf);
+out:
+ kfree(isert_conn);
+ return ret;
+}
+
+static void
+isert_connect_release(struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_device *device = isert_conn->conn_device;
+ int cq_index;
+
+ pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ if (isert_conn->conn_qp) {
+ cq_index = ((struct isert_cq_desc *)
+ isert_conn->conn_qp->recv_cq->cq_context)->cq_index;
+ pr_debug("isert_connect_release: cq_index: %d\n", cq_index);
+ isert_conn->conn_device->cq_active_qps[cq_index]--;
+
+ rdma_destroy_qp(isert_conn->conn_cm_id);
+ }
+
+ isert_free_rx_descriptors(isert_conn);
+ rdma_destroy_id(isert_conn->conn_cm_id);
+
+ if (isert_conn->login_buf) {
+ ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
+ ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
+ ib_dma_unmap_single(ib_dev, isert_conn->login_req_dma,
+ ISCSI_DEF_MAX_RECV_SEG_LEN,
+ DMA_FROM_DEVICE);
+ kfree(isert_conn->login_buf);
+ }
+ kfree(isert_conn);
+
+ if (device)
+ isert_device_try_release(device);
+
+ pr_debug("Leaving isert_connect_release >>>>>>>>>>>>\n");
+}
+
+static void
+isert_connected_handler(struct rdma_cm_id *cma_id)
+{
+ return;
+}
+
+static void
+isert_release_conn_kref(struct kref *kref)
+{
+ struct isert_conn *isert_conn = container_of(kref,
+ struct isert_conn, conn_kref);
+
+ pr_debug("Calling isert_connect_release for final kref %s/%d\n",
+ current->comm, current->pid);
+
+ isert_connect_release(isert_conn);
+}
+
+static void
+isert_put_conn(struct isert_conn *isert_conn)
+{
+ kref_put(&isert_conn->conn_kref, isert_release_conn_kref);
+}
+
+static void
+isert_disconnect_work(struct work_struct *work)
+{
+ struct isert_conn *isert_conn = container_of(work,
+ struct isert_conn, conn_logout_work);
+
+ pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ isert_conn->state = ISER_CONN_DOWN;
+
+ if (isert_conn->post_recv_buf_count == 0 &&
+ atomic_read(&isert_conn->post_send_buf_count) == 0) {
+ pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
+ wake_up(&isert_conn->conn_wait);
+ }
+
+ isert_put_conn(isert_conn);
+}
+
+static void
+isert_disconnected_handler(struct rdma_cm_id *cma_id)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)cma_id->context;
+
+ INIT_WORK(&isert_conn->conn_logout_work, isert_disconnect_work);
+ schedule_work(&isert_conn->conn_logout_work);
+}
+
+static int
+isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+ int ret = 0;
+
+ pr_debug("isert_cma_handler: event %d status %d conn %p id %p\n",
+ event->event, event->status, cma_id->context, cma_id);
+
+ switch (event->event) {
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ pr_debug("RDMA_CM_EVENT_CONNECT_REQUEST: >>>>>>>>>>>>>>>\n");
+ ret = isert_connect_request(cma_id, event);
+ break;
+ case RDMA_CM_EVENT_ESTABLISHED:
+ pr_debug("RDMA_CM_EVENT_ESTABLISHED >>>>>>>>>>>>>>\n");
+ isert_connected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ pr_debug("RDMA_CM_EVENT_DISCONNECTED: >>>>>>>>>>>>>>\n");
+ isert_disconnected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ case RDMA_CM_EVENT_ADDR_CHANGE:
+ break;
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ default:
+ pr_err("Unknown RDMA CMA event: %d\n", event->event);
+ break;
+ }
+
+ if (ret != 0) {
+ pr_err("isert_cma_handler failed RDMA_CM_EVENT: 0x%08x %d\n",
+ event->event, ret);
+ dump_stack();
+ }
+
+ return ret;
+}
+
+static int
+isert_post_recv(struct isert_conn *isert_conn, u32 count)
+{
+ struct ib_recv_wr *rx_wr, *rx_wr_failed;
+ int i, ret;
+ unsigned int rx_head = isert_conn->conn_rx_desc_head;
+ struct iser_rx_desc *rx_desc;
+
+ for (rx_wr = isert_conn->conn_rx_wr, i = 0; i < count; i++, rx_wr++) {
+ rx_desc = &isert_conn->conn_rx_descs[rx_head];
+ rx_wr->wr_id = (unsigned long)rx_desc;
+ rx_wr->sg_list = &rx_desc->rx_sg;
+ rx_wr->num_sge = 1;
+ rx_wr->next = rx_wr + 1;
+ rx_head = (rx_head + 1) & (ISERT_QP_MAX_RECV_DTOS - 1);
+ }
+
+ rx_wr--;
+ rx_wr->next = NULL; /* mark end of work requests list */
+
+ isert_conn->post_recv_buf_count += count;
+ ret = ib_post_recv(isert_conn->conn_qp, isert_conn->conn_rx_wr,
+ &rx_wr_failed);
+ if (ret) {
+ pr_err("ib_post_recv() failed with ret: %d\n", ret);
+ isert_conn->post_recv_buf_count -= count;
+ } else {
+ pr_debug("isert_post_recv(): Posted %d RX buffers\n", count);
+ isert_conn->conn_rx_desc_head = rx_head;
+ }
+ return ret;
+}
+
+static int
+isert_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_send_wr send_wr, *send_wr_failed;
+ int ret;
+
+ ib_dma_sync_single_for_device(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+
+ send_wr.next = NULL;
+ send_wr.wr_id = (unsigned long)tx_desc;
+ send_wr.sg_list = tx_desc->tx_sg;
+ send_wr.num_sge = tx_desc->num_sge;
+ send_wr.opcode = IB_WR_SEND;
+ send_wr.send_flags = IB_SEND_SIGNALED;
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &send_wr, &send_wr_failed);
+ if (ret) {
+ pr_err("ib_post_send() failed, ret: %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+
+ return ret;
+}
+
+static void
+isert_create_send_desc(struct isert_conn *isert_conn,
+ struct isert_cmd *isert_cmd,
+ struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+
+ memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
+ tx_desc->iser_header.flags = ISER_VER;
+
+ tx_desc->num_sge = 1;
+ tx_desc->isert_cmd = isert_cmd;
+
+ if (tx_desc->tx_sg[0].lkey != isert_conn->conn_mr->lkey) {
+ tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey;
+ pr_debug("tx_desc %p lkey mismatch, fixing\n", tx_desc);
+ }
+}
+
+static int
+isert_init_tx_hdrs(struct isert_conn *isert_conn,
+ struct iser_tx_desc *tx_desc)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ u64 dma_addr;
+
+ dma_addr = ib_dma_map_single(ib_dev, (void *)tx_desc,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(ib_dev, dma_addr)) {
+ pr_err("ib_dma_mapping_error() failed\n");
+ return -ENOMEM;
+ }
+
+ tx_desc->dma_addr = dma_addr;
+ tx_desc->tx_sg[0].addr = tx_desc->dma_addr;
+ tx_desc->tx_sg[0].length = ISER_HEADERS_LEN;
+ tx_desc->tx_sg[0].lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("isert_init_tx_hdrs: Setup tx_sg[0].addr: 0x%llx length: %u"
+ " lkey: 0x%08x\n", tx_desc->tx_sg[0].addr,
+ tx_desc->tx_sg[0].length, tx_desc->tx_sg[0].lkey);
+
+ return 0;
+}
+
+static void
+isert_init_send_wr(struct isert_cmd *isert_cmd, struct ib_send_wr *send_wr)
+{
+ isert_cmd->rdma_wr.iser_ib_op = ISER_IB_SEND;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ send_wr->opcode = IB_WR_SEND;
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ send_wr->sg_list = &isert_cmd->tx_desc.tx_sg[0];
+ send_wr->num_sge = isert_cmd->tx_desc.num_sge;
+}
+
+static int
+isert_rdma_post_recvl(struct isert_conn *isert_conn)
+{
+ struct ib_recv_wr rx_wr, *rx_wr_fail;
+ struct ib_sge sge;
+ int ret;
+
+ memset(&sge, 0, sizeof(struct ib_sge));
+ sge.addr = isert_conn->login_req_dma;
+ sge.length = ISER_RX_LOGIN_SIZE;
+ sge.lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("Setup sge: addr: %llx length: %d 0x%08x\n",
+ sge.addr, sge.length, sge.lkey);
+
+ memset(&rx_wr, 0, sizeof(struct ib_recv_wr));
+ rx_wr.wr_id = (unsigned long)isert_conn->login_req_buf;
+ rx_wr.sg_list = &sge;
+ rx_wr.num_sge = 1;
+
+ isert_conn->post_recv_buf_count++;
+ ret = ib_post_recv(isert_conn->conn_qp, &rx_wr, &rx_wr_fail);
+ if (ret) {
+ pr_err("ib_post_recv() failed: %d\n", ret);
+ isert_conn->post_recv_buf_count--;
+ }
+
+ pr_debug("ib_post_recv(): returned success >>>>>>>>>>>>>>>>>>>>>>>>\n");
+ return ret;
+}
+
+static int
+isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
+ u32 length)
+{
+ struct isert_conn *isert_conn = conn->context;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iser_tx_desc *tx_desc = &isert_conn->conn_login_tx_desc;
+ int ret;
+
+ isert_create_send_desc(isert_conn, NULL, tx_desc);
+
+ memcpy(&tx_desc->iscsi_header, &login->rsp[0],
+ sizeof(struct iscsi_hdr));
+
+ isert_init_tx_hdrs(isert_conn, tx_desc);
+
+ if (length > 0) {
+ struct ib_sge *tx_dsg = &tx_desc->tx_sg[1];
+
+ ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_rsp_dma,
+ length, DMA_TO_DEVICE);
+
+ memcpy(isert_conn->login_rsp_buf, login->rsp_buf, length);
+
+ ib_dma_sync_single_for_device(ib_dev, isert_conn->login_rsp_dma,
+ length, DMA_TO_DEVICE);
+
+ tx_dsg->addr = isert_conn->login_rsp_dma;
+ tx_dsg->length = length;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ tx_desc->num_sge = 2;
+ }
+ if (!login->login_failed) {
+ if (login->login_complete) {
+ ret = isert_alloc_rx_descriptors(isert_conn);
+ if (ret)
+ return ret;
+
+ ret = isert_post_recv(isert_conn, ISERT_MIN_POSTED_RX);
+ if (ret)
+ return ret;
+
+ isert_conn->state = ISER_CONN_UP;
+ goto post_send;
+ }
+
+ ret = isert_rdma_post_recvl(isert_conn);
+ if (ret)
+ return ret;
+ }
+post_send:
+ ret = isert_post_send(isert_conn, tx_desc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+isert_rx_login_req(struct iser_rx_desc *rx_desc, int rx_buflen,
+ struct isert_conn *isert_conn)
+{
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_login *login = conn->conn_login;
+ int size;
+
+ if (!login) {
+ pr_err("conn->conn_login is NULL\n");
+ dump_stack();
+ return;
+ }
+
+ if (login->first_request) {
+ struct iscsi_login_req *login_req =
+ (struct iscsi_login_req *)&rx_desc->iscsi_header;
+ /*
+ * Setup the initial iscsi_login values from the leading
+ * login request PDU.
+ */
+ login->leading_connection = (!login_req->tsih) ? 1 : 0;
+ login->current_stage =
+ (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK)
+ >> 2;
+ login->version_min = login_req->min_version;
+ login->version_max = login_req->max_version;
+ memcpy(login->isid, login_req->isid, 6);
+ login->cmd_sn = be32_to_cpu(login_req->cmdsn);
+ login->init_task_tag = login_req->itt;
+ login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+ login->cid = be16_to_cpu(login_req->cid);
+ login->tsih = be16_to_cpu(login_req->tsih);
+ }
+
+ memcpy(&login->req[0], (void *)&rx_desc->iscsi_header, ISCSI_HDR_LEN);
+
+ size = min(rx_buflen, MAX_KEY_VALUE_PAIRS);
+ pr_debug("Using login payload size: %d, rx_buflen: %d MAX_KEY_VALUE_PAIRS: %d\n",
+ size, rx_buflen, MAX_KEY_VALUE_PAIRS);
+ memcpy(login->req_buf, &rx_desc->data[0], size);
+
+ complete(&isert_conn->conn_login_comp);
+}
+
+static void
+isert_release_cmd(struct iscsi_cmd *cmd)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd, struct isert_cmd,
+ iscsi_cmd);
+
+ pr_debug("Entering isert_release_cmd %p >>>>>>>>>>>>>>>.\n", isert_cmd);
+
+ kfree(cmd->buf_ptr);
+ kfree(cmd->tmr_req);
+
+ kmem_cache_free(isert_cmd_cache, isert_cmd);
+}
+
+static struct iscsi_cmd
+*isert_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct isert_cmd *isert_cmd;
+
+ isert_cmd = kmem_cache_zalloc(isert_cmd_cache, gfp);
+ if (!isert_cmd) {
+ pr_err("Unable to allocate isert_cmd\n");
+ return NULL;
+ }
+ isert_cmd->conn = isert_conn;
+ isert_cmd->iscsi_cmd.release_cmd = &isert_release_cmd;
+
+ return &isert_cmd->iscsi_cmd;
+}
+
+static int
+isert_handle_scsi_cmd(struct isert_conn *isert_conn,
+ struct isert_cmd *isert_cmd, struct iser_rx_desc *rx_desc,
+ unsigned char *buf)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
+ struct scatterlist *sg;
+ int imm_data, imm_data_len, unsol_data, sg_nents, rc;
+ bool dump_payload = false;
+
+ rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
+ if (rc < 0)
+ return rc;
+
+ imm_data = cmd->immediate_data;
+ imm_data_len = cmd->first_burst_len;
+ unsol_data = cmd->unsolicited_data;
+
+ rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
+ if (rc < 0) {
+ return 0;
+ } else if (rc > 0) {
+ dump_payload = true;
+ goto sequence_cmd;
+ }
+
+ if (!imm_data)
+ return 0;
+
+ sg = &cmd->se_cmd.t_data_sg[0];
+ sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE));
+
+ pr_debug("Copying Immediate SG: %p sg_nents: %u from %p imm_data_len: %d\n",
+ sg, sg_nents, &rx_desc->data[0], imm_data_len);
+
+ sg_copy_from_buffer(sg, sg_nents, &rx_desc->data[0], imm_data_len);
+
+ cmd->write_data_done += imm_data_len;
+
+ if (cmd->write_data_done == cmd->se_cmd.data_length) {
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+ cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+ spin_unlock_bh(&cmd->istate_lock);
+ }
+
+sequence_cmd:
+ rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+
+ if (!rc && dump_payload == false && unsol_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+
+ if (rc == CMDSN_ERROR_CANNOT_RECOVER)
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 0, (unsigned char *)hdr, cmd);
+
+ return 0;
+}
+
+static int
+isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
+ struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+ struct scatterlist *sg_start;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_cmd *cmd = NULL;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
+ u32 unsol_data_len = ntoh24(hdr->dlength);
+ int rc, sg_nents, sg_off, page_off;
+
+ rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
+ if (rc < 0)
+ return rc;
+ else if (!cmd)
+ return 0;
+ /*
+ * FIXME: Unexpected unsolicited_data out
+ */
+ if (!cmd->unsolicited_data) {
+ pr_err("Received unexpected solicited data payload\n");
+ dump_stack();
+ return -1;
+ }
+
+ pr_debug("Unsolicited DataOut unsol_data_len: %u, write_data_done: %u, data_length: %u\n",
+ unsol_data_len, cmd->write_data_done, cmd->se_cmd.data_length);
+
+ sg_off = cmd->write_data_done / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ sg_nents = max(1UL, DIV_ROUND_UP(unsol_data_len, PAGE_SIZE));
+ page_off = cmd->write_data_done % PAGE_SIZE;
+ /*
+ * FIXME: Non page-aligned unsolicited_data out
+ */
+ if (page_off) {
+ pr_err("Received unexpected non-page aligned data payload\n");
+ dump_stack();
+ return -1;
+ }
+ pr_debug("Copying DataOut: sg_start: %p, sg_off: %u sg_nents: %u from %p %u\n",
+ sg_start, sg_off, sg_nents, &rx_desc->data[0], unsol_data_len);
+
+ sg_copy_from_buffer(sg_start, sg_nents, &rx_desc->data[0],
+ unsol_data_len);
+
+ rc = iscsit_check_dataout_payload(cmd, hdr, false);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int
+isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
+ uint32_t read_stag, uint64_t read_va,
+ uint32_t write_stag, uint64_t write_va)
+{
+ struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_cmd *cmd;
+ struct isert_cmd *isert_cmd;
+ int ret = -EINVAL;
+ u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
+
+ switch (opcode) {
+ case ISCSI_OP_SCSI_CMD:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ isert_cmd->read_stag = read_stag;
+ isert_cmd->read_va = read_va;
+ isert_cmd->write_stag = write_stag;
+ isert_cmd->write_va = write_va;
+
+ ret = isert_handle_scsi_cmd(isert_conn, isert_cmd,
+ rx_desc, (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_SCSI_DATA_OUT:
+ ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
+ (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_task_mgt_cmd(conn, cmd,
+ (unsigned char *)hdr);
+ break;
+ case ISCSI_OP_LOGOUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
+ if (ret > 0)
+ wait_for_completion_timeout(&conn->conn_logout_comp,
+ SECONDS_FOR_LOGOUT_COMP *
+ HZ);
+ break;
+ default:
+ pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
+ dump_stack();
+ break;
+ }
+
+ return ret;
+}
+
+static void
+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:
+ if (iser_hdr->flags & ISER_RSV) {
+ read_stag = be32_to_cpu(iser_hdr->read_stag);
+ read_va = be64_to_cpu(iser_hdr->read_va);
+ pr_debug("ISER_RSV: read_stag: 0x%08x read_va: 0x%16llx\n",
+ read_stag, (unsigned long long)read_va);
+ }
+ if (iser_hdr->flags & ISER_WSV) {
+ write_stag = be32_to_cpu(iser_hdr->write_stag);
+ write_va = be64_to_cpu(iser_hdr->write_va);
+ pr_debug("ISER_WSV: write__stag: 0x%08x write_va: 0x%16llx\n",
+ write_stag, (unsigned long long)write_va);
+ }
+
+ pr_debug("ISER ISCSI_CTRL PDU\n");
+ break;
+ case ISER_HELLO:
+ pr_err("iSER Hello message\n");
+ break;
+ default:
+ pr_warn("Unknown iSER hdr flags: 0x%02x\n", iser_hdr->flags);
+ break;
+ }
+
+ rc = isert_rx_opcode(isert_conn, rx_desc,
+ read_stag, read_va, write_stag, write_va);
+}
+
+static void
+isert_rx_completion(struct iser_rx_desc *desc, struct isert_conn *isert_conn,
+ unsigned long xfer_len)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iscsi_hdr *hdr;
+ u64 rx_dma;
+ int rx_buflen, outstanding;
+
+ if ((char *)desc == isert_conn->login_req_buf) {
+ rx_dma = isert_conn->login_req_dma;
+ rx_buflen = ISER_RX_LOGIN_SIZE;
+ pr_debug("ISER login_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n",
+ rx_dma, rx_buflen);
+ } else {
+ rx_dma = desc->dma_addr;
+ rx_buflen = ISER_RX_PAYLOAD_SIZE;
+ pr_debug("ISER req_buf: Using rx_dma: 0x%llx, rx_buflen: %d\n",
+ rx_dma, rx_buflen);
+ }
+
+ ib_dma_sync_single_for_cpu(ib_dev, rx_dma, rx_buflen, DMA_FROM_DEVICE);
+
+ hdr = &desc->iscsi_header;
+ pr_debug("iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n",
+ hdr->opcode, hdr->itt, hdr->flags,
+ (int)(xfer_len - ISER_HEADERS_LEN));
+
+ if ((char *)desc == isert_conn->login_req_buf)
+ isert_rx_login_req(desc, xfer_len - ISER_HEADERS_LEN,
+ isert_conn);
+ else
+ isert_rx_do_work(desc, isert_conn);
+
+ ib_dma_sync_single_for_device(ib_dev, rx_dma, rx_buflen,
+ DMA_FROM_DEVICE);
+
+ isert_conn->post_recv_buf_count--;
+ pr_debug("iSERT: Decremented post_recv_buf_count: %d\n",
+ isert_conn->post_recv_buf_count);
+
+ if ((char *)desc == isert_conn->login_req_buf)
+ return;
+
+ outstanding = isert_conn->post_recv_buf_count;
+ if (outstanding + ISERT_MIN_POSTED_RX <= ISERT_QP_MAX_RECV_DTOS) {
+ int err, count = min(ISERT_QP_MAX_RECV_DTOS - outstanding,
+ ISERT_MIN_POSTED_RX);
+ err = isert_post_recv(isert_conn, count);
+ if (err) {
+ pr_err("isert_post_recv() count: %d failed, %d\n",
+ count, err);
+ }
+ }
+}
+
+static void
+isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
+{
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ pr_debug("isert_unmap_cmd >>>>>>>>>>>>>>>>>>>>>>>\n");
+
+ if (wr->sge) {
+ ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
+ wr->sge = NULL;
+ }
+
+ kfree(wr->send_wr);
+ wr->send_wr = NULL;
+
+ kfree(isert_cmd->ib_sge);
+ isert_cmd->ib_sge = NULL;
+}
+
+static void
+isert_put_cmd(struct isert_cmd *isert_cmd)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct isert_conn *isert_conn = isert_cmd->conn;
+ struct iscsi_conn *conn;
+
+ pr_debug("Entering isert_put_cmd: %p\n", isert_cmd);
+
+ switch (cmd->iscsi_opcode) {
+ case ISCSI_OP_SCSI_CMD:
+ conn = isert_conn->conn;
+
+ spin_lock_bh(&conn->cmd_lock);
+ if (!list_empty(&cmd->i_conn_node))
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ if (cmd->data_direction == DMA_TO_DEVICE)
+ iscsit_stop_dataout_timer(cmd);
+
+ isert_unmap_cmd(isert_cmd, isert_conn);
+ /*
+ * Fall-through
+ */
+ case ISCSI_OP_SCSI_TMFUNC:
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+ break;
+ case ISCSI_OP_REJECT:
+ case ISCSI_OP_NOOP_OUT:
+ conn = isert_conn->conn;
+
+ spin_lock_bh(&conn->cmd_lock);
+ if (!list_empty(&cmd->i_conn_node))
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
+ /*
+ * Handle special case for REJECT when iscsi_add_reject*() has
+ * overwritten the original iscsi_opcode assignment, and the
+ * associated cmd->se_cmd needs to be released.
+ */
+ if (cmd->se_cmd.se_tfo != NULL) {
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+ break;
+ }
+ /*
+ * Fall-through
+ */
+ default:
+ isert_release_cmd(cmd);
+ break;
+ }
+}
+
+static void
+isert_unmap_tx_desc(struct iser_tx_desc *tx_desc, struct ib_device *ib_dev)
+{
+ if (tx_desc->dma_addr != 0) {
+ pr_debug("Calling ib_dma_unmap_single for tx_desc->dma_addr\n");
+ ib_dma_unmap_single(ib_dev, tx_desc->dma_addr,
+ ISER_HEADERS_LEN, DMA_TO_DEVICE);
+ tx_desc->dma_addr = 0;
+ }
+}
+
+static void
+isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd,
+ struct ib_device *ib_dev)
+{
+ if (isert_cmd->sense_buf_dma != 0) {
+ pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n");
+ ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma,
+ isert_cmd->sense_buf_len, DMA_TO_DEVICE);
+ isert_cmd->sense_buf_dma = 0;
+ }
+
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ isert_put_cmd(isert_cmd);
+}
+
+static void
+isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
+ struct isert_cmd *isert_cmd)
+{
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct ib_device *ib_dev = isert_cmd->conn->conn_cm_id->device;
+
+ iscsit_stop_dataout_timer(cmd);
+
+ if (wr->sge) {
+ pr_debug("isert_do_rdma_read_comp: Unmapping wr->sge from t_data_sg\n");
+ ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
+ wr->sge = NULL;
+ }
+
+ if (isert_cmd->ib_sge) {
+ pr_debug("isert_do_rdma_read_comp: Freeing isert_cmd->ib_sge\n");
+ kfree(isert_cmd->ib_sge);
+ isert_cmd->ib_sge = NULL;
+ }
+
+ cmd->write_data_done = se_cmd->data_length;
+
+ pr_debug("isert_do_rdma_read_comp, calling target_execute_cmd\n");
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
+ cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
+ spin_unlock_bh(&cmd->istate_lock);
+
+ target_execute_cmd(se_cmd);
+}
+
+static void
+isert_do_control_comp(struct work_struct *work)
+{
+ struct isert_cmd *isert_cmd = container_of(work,
+ struct isert_cmd, comp_work);
+ struct isert_conn *isert_conn = isert_cmd->conn;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+
+ switch (cmd->i_state) {
+ case ISTATE_SEND_TASKMGTRSP:
+ pr_debug("Calling iscsit_tmr_post_handler >>>>>>>>>>>>>>>>>\n");
+
+ atomic_dec(&isert_conn->post_send_buf_count);
+ iscsit_tmr_post_handler(cmd, cmd->conn);
+
+ cmd->i_state = ISTATE_SENT_STATUS;
+ isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ break;
+ case ISTATE_SEND_REJECT:
+ pr_debug("Got isert_do_control_comp ISTATE_SEND_REJECT: >>>\n");
+ atomic_dec(&isert_conn->post_send_buf_count);
+
+ cmd->i_state = ISTATE_SENT_STATUS;
+ complete(&cmd->reject_comp);
+ isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ case ISTATE_SEND_LOGOUTRSP:
+ pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
+ /*
+ * Call atomic_dec(&isert_conn->post_send_buf_count)
+ * from isert_free_conn()
+ */
+ isert_conn->logout_posted = true;
+ iscsit_logout_post_handler(cmd, cmd->conn);
+ break;
+ default:
+ pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state);
+ dump_stack();
+ break;
+ }
+}
+
+static void
+isert_response_completion(struct iser_tx_desc *tx_desc,
+ struct isert_cmd *isert_cmd,
+ struct isert_conn *isert_conn,
+ struct ib_device *ib_dev)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+
+ if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
+ cmd->i_state == ISTATE_SEND_LOGOUTRSP) {
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+
+ INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
+ queue_work(isert_comp_wq, &isert_cmd->comp_work);
+ return;
+ }
+ atomic_dec(&isert_conn->post_send_buf_count);
+
+ cmd->i_state = ISTATE_SENT_STATUS;
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
+
+static void
+isert_send_completion(struct iser_tx_desc *tx_desc,
+ struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+ struct isert_rdma_wr *wr;
+
+ if (!isert_cmd) {
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ return;
+ }
+ wr = &isert_cmd->rdma_wr;
+
+ switch (wr->iser_ib_op) {
+ case ISER_IB_RECV:
+ pr_err("isert_send_completion: Got ISER_IB_RECV\n");
+ dump_stack();
+ break;
+ case ISER_IB_SEND:
+ pr_debug("isert_send_completion: Got ISER_IB_SEND\n");
+ isert_response_completion(tx_desc, isert_cmd,
+ isert_conn, ib_dev);
+ break;
+ case ISER_IB_RDMA_WRITE:
+ pr_err("isert_send_completion: Got ISER_IB_RDMA_WRITE\n");
+ dump_stack();
+ break;
+ case ISER_IB_RDMA_READ:
+ pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
+
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_completion_rdma_read(tx_desc, isert_cmd);
+ break;
+ default:
+ pr_err("Unknown wr->iser_ib_op: 0x%02x\n", wr->iser_ib_op);
+ dump_stack();
+ break;
+ }
+}
+
+static void
+isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+{
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+
+ if (tx_desc) {
+ struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+
+ if (!isert_cmd)
+ isert_unmap_tx_desc(tx_desc, ib_dev);
+ else
+ isert_completion_put(tx_desc, isert_cmd, ib_dev);
+ }
+
+ if (isert_conn->post_recv_buf_count == 0 &&
+ atomic_read(&isert_conn->post_send_buf_count) == 0) {
+ pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
+ pr_debug("Calling wake_up from isert_cq_comp_err\n");
+
+ isert_conn->state = ISER_CONN_TERMINATING;
+ wake_up(&isert_conn->conn_wait_comp_err);
+ }
+}
+
+static void
+isert_cq_tx_work(struct work_struct *work)
+{
+ struct isert_cq_desc *cq_desc = container_of(work,
+ struct isert_cq_desc, cq_tx_work);
+ struct isert_device *device = cq_desc->device;
+ int cq_index = cq_desc->cq_index;
+ struct ib_cq *tx_cq = device->dev_tx_cq[cq_index];
+ struct isert_conn *isert_conn;
+ struct iser_tx_desc *tx_desc;
+ struct ib_wc wc;
+
+ while (ib_poll_cq(tx_cq, 1, &wc) == 1) {
+ tx_desc = (struct iser_tx_desc *)(unsigned long)wc.wr_id;
+ isert_conn = wc.qp->qp_context;
+
+ if (wc.status == IB_WC_SUCCESS) {
+ isert_send_completion(tx_desc, isert_conn);
+ } else {
+ pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
+ pr_debug("TX wc.status: 0x%08x\n", wc.status);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ isert_cq_comp_err(tx_desc, isert_conn);
+ }
+ }
+
+ ib_req_notify_cq(tx_cq, IB_CQ_NEXT_COMP);
+}
+
+static void
+isert_cq_tx_callback(struct ib_cq *cq, void *context)
+{
+ struct isert_cq_desc *cq_desc = (struct isert_cq_desc *)context;
+
+ INIT_WORK(&cq_desc->cq_tx_work, isert_cq_tx_work);
+ queue_work(isert_comp_wq, &cq_desc->cq_tx_work);
+}
+
+static void
+isert_cq_rx_work(struct work_struct *work)
+{
+ struct isert_cq_desc *cq_desc = container_of(work,
+ struct isert_cq_desc, cq_rx_work);
+ struct isert_device *device = cq_desc->device;
+ int cq_index = cq_desc->cq_index;
+ struct ib_cq *rx_cq = device->dev_rx_cq[cq_index];
+ struct isert_conn *isert_conn;
+ struct iser_rx_desc *rx_desc;
+ struct ib_wc wc;
+ unsigned long xfer_len;
+
+ while (ib_poll_cq(rx_cq, 1, &wc) == 1) {
+ rx_desc = (struct iser_rx_desc *)(unsigned long)wc.wr_id;
+ isert_conn = wc.qp->qp_context;
+
+ if (wc.status == IB_WC_SUCCESS) {
+ xfer_len = (unsigned long)wc.byte_len;
+ isert_rx_completion(rx_desc, isert_conn, xfer_len);
+ } else {
+ pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
+ if (wc.status != IB_WC_WR_FLUSH_ERR)
+ pr_debug("RX wc.status: 0x%08x\n", wc.status);
+
+ isert_conn->post_recv_buf_count--;
+ isert_cq_comp_err(NULL, isert_conn);
+ }
+ }
+
+ ib_req_notify_cq(rx_cq, IB_CQ_NEXT_COMP);
+}
+
+static void
+isert_cq_rx_callback(struct ib_cq *cq, void *context)
+{
+ struct isert_cq_desc *cq_desc = (struct isert_cq_desc *)context;
+
+ INIT_WORK(&cq_desc->cq_rx_work, isert_cq_rx_work);
+ queue_work(isert_rx_wq, &cq_desc->cq_rx_work);
+}
+
+static int
+isert_post_response(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd)
+{
+ struct ib_send_wr *wr_failed;
+ int ret;
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ ret = ib_post_send(isert_conn->conn_qp, &isert_cmd->tx_desc.send_wr,
+ &wr_failed);
+ if (ret) {
+ pr_err("ib_post_send failed with %d\n", ret);
+ atomic_dec(&isert_conn->post_send_buf_count);
+ return ret;
+ }
+ return ret;
+}
+
+static int
+isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+ struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)
+ &isert_cmd->tx_desc.iscsi_header;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_rsp_pdu(cmd, conn, true, hdr);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ /*
+ * Attach SENSE DATA payload to iSCSI Response PDU
+ */
+ if (cmd->se_cmd.sense_buffer &&
+ ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ||
+ (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ u32 padding, sense_len;
+
+ put_unaligned_be16(cmd->se_cmd.scsi_sense_length,
+ cmd->sense_buffer);
+ cmd->se_cmd.scsi_sense_length += sizeof(__be16);
+
+ padding = -(cmd->se_cmd.scsi_sense_length) & 3;
+ hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
+ sense_len = cmd->se_cmd.scsi_sense_length + padding;
+
+ isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->sense_buffer, sense_len,
+ DMA_TO_DEVICE);
+
+ isert_cmd->sense_buf_len = sense_len;
+ tx_dsg->addr = isert_cmd->sense_buf_dma;
+ tx_dsg->length = sense_len;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+ }
+
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting SCSI Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
+isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ bool nopout_response)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_nopin_rsp(cmd, conn, (struct iscsi_nopin *)
+ &isert_cmd->tx_desc.iscsi_header,
+ nopout_response);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting NOPIN Reponse IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
+isert_put_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_logout_rsp(cmd, conn, (struct iscsi_logout_rsp *)
+ &isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting Logout Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
+isert_put_tm_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_task_mgt_rsp(cmd, conn, (struct iscsi_tm_rsp *)
+ &isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting Task Management Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
+isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_reject(cmd, conn, (struct iscsi_reject *)
+ &isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+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,
+ u32 data_left, u32 offset)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct scatterlist *sg_start, *tmp_sg;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ u32 sg_off, page_off;
+ int i = 0, sg_nents;
+
+ sg_off = offset / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ 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->num_sge = sg_nents;
+ send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+ /*
+ * Perform mapping of TCM scatterlist memory ib_sge dma_addr.
+ */
+ for_each_sg(sg_start, tmp_sg, sg_nents, i) {
+ pr_debug("ISER RDMA from SGL dma_addr: 0x%16llx dma_len: %u, page_off: %u\n",
+ (unsigned long long)tmp_sg->dma_address,
+ tmp_sg->length, page_off);
+
+ ib_sge->addr = ib_sg_dma_address(ib_dev, tmp_sg) + page_off;
+ ib_sge->length = min_t(u32, data_left,
+ ib_sg_dma_len(ib_dev, tmp_sg) - page_off);
+ ib_sge->lkey = isert_conn->conn_mr->lkey;
+
+ pr_debug("RDMA ib_sge: addr: 0x%16llx length: %u\n",
+ ib_sge->addr, ib_sge->length);
+ page_off = 0;
+ data_left -= ib_sge->length;
+ ib_sge++;
+ pr_debug("Incrementing ib_sge pointer to %p\n", ib_sge);
+ }
+
+ pr_debug("Set outgoing sg_list: %p num_sg: %u from TCM SGLs\n",
+ send_wr->sg_list, send_wr->num_sge);
+
+ return sg_nents;
+}
+
+static int
+isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *wr_failed, *send_wr;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *ib_sge;
+ struct scatterlist *sg;
+ u32 offset = 0, data_len, data_left, rdma_write_max;
+ int rc, ret = 0, count, sg_nents, i, ib_sge_cnt;
+
+ pr_debug("RDMA_WRITE: data_length: %u\n", se_cmd->data_length);
+
+ sg = &se_cmd->t_data_sg[0];
+ sg_nents = se_cmd->t_data_nents;
+
+ count = ib_dma_map_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+ if (unlikely(!count)) {
+ pr_err("Unable to map put_datain SGs\n");
+ return -EINVAL;
+ }
+ wr->sge = sg;
+ wr->num_sge = sg_nents;
+ pr_debug("Mapped IB count: %u sg: %p sg_nents: %u for RDMA_WRITE\n",
+ count, sg, sg_nents);
+
+ ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
+ if (!ib_sge) {
+ pr_warn("Unable to allocate datain ib_sge\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ isert_cmd->ib_sge = ib_sge;
+
+ pr_debug("Allocated ib_sge: %p from t_data_ents: %d for RDMA_WRITE\n",
+ ib_sge, se_cmd->t_data_nents);
+
+ wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
+ wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
+ GFP_KERNEL);
+ if (!wr->send_wr) {
+ pr_err("Unable to allocate wr->send_wr\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
+ wr->send_wr, wr->send_wr_num);
+
+ iscsit_increment_maxcmdsn(cmd, conn->sess);
+ cmd->stat_sn = conn->stat_sn++;
+
+ wr->isert_cmd = isert_cmd;
+ rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
+ data_left = se_cmd->data_length;
+
+ for (i = 0; i < wr->send_wr_num; i++) {
+ send_wr = &isert_cmd->rdma_wr.send_wr[i];
+ data_len = min(data_left, rdma_write_max);
+
+ send_wr->opcode = IB_WR_RDMA_WRITE;
+ send_wr->send_flags = 0;
+ send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset;
+ send_wr->wr.rdma.rkey = isert_cmd->read_stag;
+
+ ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
+ send_wr, data_len, offset);
+ ib_sge += ib_sge_cnt;
+
+ if (i + 1 == wr->send_wr_num)
+ send_wr->next = &isert_cmd->tx_desc.send_wr;
+ else
+ send_wr->next = &wr->send_wr[i + 1];
+
+ offset += data_len;
+ data_left -= data_len;
+ }
+ /*
+ * Build isert_conn->tx_desc for iSCSI response PDU and attach
+ */
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ iscsit_build_rsp_pdu(cmd, conn, false, (struct iscsi_scsi_rsp *)
+ &isert_cmd->tx_desc.iscsi_header);
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+ isert_init_send_wr(isert_cmd, &isert_cmd->tx_desc.send_wr);
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+ if (rc) {
+ pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+ pr_debug("Posted RDMA_WRITE + Response for iSER Data READ\n");
+ return 1;
+
+unmap_sg:
+ ib_dma_unmap_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+ return ret;
+}
+
+static int
+isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
+{
+ struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *wr_failed, *send_wr;
+ struct ib_sge *ib_sge;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct scatterlist *sg_start;
+ u32 sg_off, sg_nents, page_off, va_offset = 0;
+ u32 offset = 0, data_len, data_left, rdma_write_max;
+ int rc, ret = 0, count, i, ib_sge_cnt;
+
+ pr_debug("RDMA_READ: data_length: %u write_data_done: %u\n",
+ se_cmd->data_length, cmd->write_data_done);
+
+ sg_off = cmd->write_data_done / PAGE_SIZE;
+ sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+ page_off = cmd->write_data_done % PAGE_SIZE;
+
+ pr_debug("RDMA_READ: sg_off: %d, sg_start: %p page_off: %d\n",
+ sg_off, sg_start, page_off);
+
+ data_left = se_cmd->data_length - cmd->write_data_done;
+ sg_nents = se_cmd->t_data_nents - sg_off;
+
+ pr_debug("RDMA_READ: data_left: %d, sg_nents: %d\n",
+ data_left, sg_nents);
+
+ count = ib_dma_map_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
+ if (unlikely(!count)) {
+ pr_err("Unable to map get_dataout SGs\n");
+ return -EINVAL;
+ }
+ wr->sge = sg_start;
+ wr->num_sge = sg_nents;
+ pr_debug("Mapped IB count: %u sg_start: %p sg_nents: %u for RDMA_READ\n",
+ count, sg_start, sg_nents);
+
+ ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
+ if (!ib_sge) {
+ pr_warn("Unable to allocate dataout ib_sge\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ isert_cmd->ib_sge = ib_sge;
+
+ pr_debug("Using ib_sge: %p from sg_ents: %d for RDMA_READ\n",
+ ib_sge, sg_nents);
+
+ wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
+ wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
+ GFP_KERNEL);
+ if (!wr->send_wr) {
+ pr_debug("Unable to allocate wr->send_wr\n");
+ ret = -ENOMEM;
+ goto unmap_sg;
+ }
+ pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
+ wr->send_wr, wr->send_wr_num);
+
+ isert_cmd->tx_desc.isert_cmd = isert_cmd;
+
+ wr->iser_ib_op = ISER_IB_RDMA_READ;
+ wr->isert_cmd = isert_cmd;
+ rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
+ offset = cmd->write_data_done;
+
+ for (i = 0; i < wr->send_wr_num; i++) {
+ send_wr = &isert_cmd->rdma_wr.send_wr[i];
+ data_len = min(data_left, rdma_write_max);
+
+ 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;
+
+ ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
+ send_wr, data_len, offset);
+ ib_sge += ib_sge_cnt;
+
+ if (i + 1 == wr->send_wr_num)
+ send_wr->send_flags = IB_SEND_SIGNALED;
+ else
+ send_wr->next = &wr->send_wr[i + 1];
+
+ offset += data_len;
+ va_offset += data_len;
+ data_left -= data_len;
+ }
+
+ atomic_inc(&isert_conn->post_send_buf_count);
+
+ rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+ if (rc) {
+ pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
+ atomic_dec(&isert_conn->post_send_buf_count);
+ }
+ pr_debug("Posted RDMA_READ memory for ISER Data WRITE\n");
+ return 0;
+
+unmap_sg:
+ ib_dma_unmap_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
+ return ret;
+}
+
+static int
+isert_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+ switch (state) {
+ case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+ ret = isert_put_nopin(cmd, conn, false);
+ break;
+ default:
+ pr_err("Unknown immediate state: 0x%02x\n", state);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+ switch (state) {
+ case ISTATE_SEND_LOGOUTRSP:
+ ret = isert_put_logout_rsp(cmd, conn);
+ if (!ret) {
+ pr_debug("Returning iSER Logout -EAGAIN\n");
+ ret = -EAGAIN;
+ }
+ break;
+ case ISTATE_SEND_NOPIN:
+ ret = isert_put_nopin(cmd, conn, true);
+ break;
+ case ISTATE_SEND_TASKMGTRSP:
+ ret = isert_put_tm_rsp(cmd, conn);
+ break;
+ case ISTATE_SEND_REJECT:
+ ret = isert_put_reject(cmd, conn);
+ break;
+ case ISTATE_SEND_STATUS:
+ /*
+ * Special case for sending non GOOD SCSI status from TX thread
+ * context during pre se_cmd excecution failure.
+ */
+ ret = isert_put_response(conn, cmd);
+ break;
+ default:
+ pr_err("Unknown response state: 0x%02x\n", state);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+isert_setup_np(struct iscsi_np *np,
+ struct __kernel_sockaddr_storage *ksockaddr)
+{
+ struct isert_np *isert_np;
+ struct rdma_cm_id *isert_lid;
+ struct sockaddr *sa;
+ int ret;
+
+ isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL);
+ if (!isert_np) {
+ pr_err("Unable to allocate struct isert_np\n");
+ return -ENOMEM;
+ }
+ init_waitqueue_head(&isert_np->np_accept_wq);
+ mutex_init(&isert_np->np_accept_mutex);
+ INIT_LIST_HEAD(&isert_np->np_accept_list);
+ init_completion(&isert_np->np_login_comp);
+
+ sa = (struct sockaddr *)ksockaddr;
+ pr_debug("ksockaddr: %p, sa: %p\n", ksockaddr, sa);
+ /*
+ * Setup the np->np_sockaddr from the passed sockaddr setup
+ * in iscsi_target_configfs.c code..
+ */
+ memcpy(&np->np_sockaddr, ksockaddr,
+ sizeof(struct __kernel_sockaddr_storage));
+
+ isert_lid = rdma_create_id(isert_cma_handler, np, RDMA_PS_TCP,
+ IB_QPT_RC);
+ if (IS_ERR(isert_lid)) {
+ pr_err("rdma_create_id() for isert_listen_handler failed: %ld\n",
+ PTR_ERR(isert_lid));
+ ret = PTR_ERR(isert_lid);
+ goto out;
+ }
+
+ ret = rdma_bind_addr(isert_lid, sa);
+ if (ret) {
+ pr_err("rdma_bind_addr() for isert_lid failed: %d\n", ret);
+ goto out_lid;
+ }
+
+ ret = rdma_listen(isert_lid, ISERT_RDMA_LISTEN_BACKLOG);
+ if (ret) {
+ pr_err("rdma_listen() for isert_lid failed: %d\n", ret);
+ goto out_lid;
+ }
+
+ isert_np->np_cm_id = isert_lid;
+ np->np_context = isert_np;
+ pr_debug("Setup isert_lid->context: %p\n", isert_lid->context);
+
+ return 0;
+
+out_lid:
+ rdma_destroy_id(isert_lid);
+out:
+ kfree(isert_np);
+ return ret;
+}
+
+static int
+isert_check_accept_queue(struct isert_np *isert_np)
+{
+ int empty;
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ empty = list_empty(&isert_np->np_accept_list);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ return empty;
+}
+
+static int
+isert_rdma_accept(struct isert_conn *isert_conn)
+{
+ struct rdma_cm_id *cm_id = isert_conn->conn_cm_id;
+ struct rdma_conn_param cp;
+ int ret;
+
+ memset(&cp, 0, sizeof(struct rdma_conn_param));
+ cp.responder_resources = isert_conn->responder_resources;
+ cp.initiator_depth = isert_conn->initiator_depth;
+ cp.retry_count = 7;
+ cp.rnr_retry_count = 7;
+
+ pr_debug("Before rdma_accept >>>>>>>>>>>>>>>>>>>>.\n");
+
+ ret = rdma_accept(cm_id, &cp);
+ if (ret) {
+ pr_err("rdma_accept() failed with: %d\n", ret);
+ return ret;
+ }
+
+ pr_debug("After rdma_accept >>>>>>>>>>>>>>>>>>>>>.\n");
+
+ return 0;
+}
+
+static int
+isert_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ int ret;
+
+ pr_debug("isert_get_login_rx before conn_login_comp conn: %p\n", conn);
+
+ ret = wait_for_completion_interruptible(&isert_conn->conn_login_comp);
+ if (ret)
+ return ret;
+
+ pr_debug("isert_get_login_rx processing login->req: %p\n", login->req);
+ return 0;
+}
+
+static void
+isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn,
+ struct isert_conn *isert_conn)
+{
+ struct rdma_cm_id *cm_id = isert_conn->conn_cm_id;
+ struct rdma_route *cm_route = &cm_id->route;
+ struct sockaddr_in *sock_in;
+ struct sockaddr_in6 *sock_in6;
+
+ conn->login_family = np->np_sockaddr.ss_family;
+
+ if (np->np_sockaddr.ss_family == AF_INET6) {
+ sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.dst_addr;
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6->sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6->sin6_port);
+
+ sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr;
+ snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
+ &sock_in6->sin6_addr.in6_u);
+ conn->local_port = ntohs(sock_in6->sin6_port);
+ } else {
+ sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr;
+ sprintf(conn->login_ip, "%pI4",
+ &sock_in->sin_addr.s_addr);
+ conn->login_port = ntohs(sock_in->sin_port);
+
+ sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr;
+ sprintf(conn->local_ip, "%pI4",
+ &sock_in->sin_addr.s_addr);
+ conn->local_port = ntohs(sock_in->sin_port);
+ }
+}
+
+static int
+isert_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
+{
+ struct isert_np *isert_np = (struct isert_np *)np->np_context;
+ struct isert_conn *isert_conn;
+ int max_accept = 0, ret;
+
+accept_wait:
+ ret = wait_event_interruptible(isert_np->np_accept_wq,
+ !isert_check_accept_queue(isert_np) ||
+ np->np_thread_state == ISCSI_NP_THREAD_RESET);
+ if (max_accept > 5)
+ return -ENODEV;
+
+ spin_lock_bh(&np->np_thread_lock);
+ if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ spin_unlock_bh(&np->np_thread_lock);
+ pr_err("ISCSI_NP_THREAD_RESET for isert_accept_np\n");
+ return -ENODEV;
+ }
+ spin_unlock_bh(&np->np_thread_lock);
+
+ mutex_lock(&isert_np->np_accept_mutex);
+ if (list_empty(&isert_np->np_accept_list)) {
+ mutex_unlock(&isert_np->np_accept_mutex);
+ max_accept++;
+ goto accept_wait;
+ }
+ isert_conn = list_first_entry(&isert_np->np_accept_list,
+ struct isert_conn, conn_accept_node);
+ list_del_init(&isert_conn->conn_accept_node);
+ mutex_unlock(&isert_np->np_accept_mutex);
+
+ conn->context = isert_conn;
+ isert_conn->conn = conn;
+ max_accept = 0;
+
+ ret = isert_rdma_post_recvl(isert_conn);
+ if (ret)
+ return ret;
+
+ ret = isert_rdma_accept(isert_conn);
+ if (ret)
+ return ret;
+
+ isert_set_conn_info(np, conn, isert_conn);
+
+ pr_debug("Processing isert_accept_np: isert_conn: %p\n", isert_conn);
+ return 0;
+}
+
+static void
+isert_free_np(struct iscsi_np *np)
+{
+ struct isert_np *isert_np = (struct isert_np *)np->np_context;
+
+ rdma_destroy_id(isert_np->np_cm_id);
+
+ np->np_context = NULL;
+ kfree(isert_np);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+ struct isert_conn *isert_conn = conn->context;
+
+ pr_debug("isert_free_conn: Starting \n");
+ /*
+ * Decrement post_send_buf_count for special case when called
+ * from isert_do_control_comp() -> iscsit_logout_post_handler()
+ */
+ if (isert_conn->logout_posted)
+ atomic_dec(&isert_conn->post_send_buf_count);
+
+ if (isert_conn->conn_cm_id)
+ rdma_disconnect(isert_conn->conn_cm_id);
+ /*
+ * Only wait for conn_wait_comp_err if the isert_conn made it
+ * into full feature phase..
+ */
+ if (isert_conn->state > ISER_CONN_INIT) {
+ pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
+ isert_conn->state);
+ wait_event(isert_conn->conn_wait_comp_err,
+ isert_conn->state == ISER_CONN_TERMINATING);
+ pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n");
+ }
+
+ pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state);
+ wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN);
+ pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n");
+
+ isert_put_conn(isert_conn);
+}
+
+static struct iscsit_transport iser_target_transport = {
+ .name = "IB/iSER",
+ .transport_type = ISCSI_INFINIBAND,
+ .owner = THIS_MODULE,
+ .iscsit_setup_np = isert_setup_np,
+ .iscsit_accept_np = isert_accept_np,
+ .iscsit_free_np = isert_free_np,
+ .iscsit_free_conn = isert_free_conn,
+ .iscsit_alloc_cmd = isert_alloc_cmd,
+ .iscsit_get_login_rx = isert_get_login_rx,
+ .iscsit_put_login_tx = isert_put_login_tx,
+ .iscsit_immediate_queue = isert_immediate_queue,
+ .iscsit_response_queue = isert_response_queue,
+ .iscsit_get_dataout = isert_get_dataout,
+ .iscsit_queue_data_in = isert_put_datain,
+ .iscsit_queue_status = isert_put_response,
+};
+
+static int __init isert_init(void)
+{
+ int ret;
+
+ isert_rx_wq = alloc_workqueue("isert_rx_wq", 0, 0);
+ if (!isert_rx_wq) {
+ pr_err("Unable to allocate isert_rx_wq\n");
+ return -ENOMEM;
+ }
+
+ isert_comp_wq = alloc_workqueue("isert_comp_wq", 0, 0);
+ if (!isert_comp_wq) {
+ pr_err("Unable to allocate isert_comp_wq\n");
+ ret = -ENOMEM;
+ goto destroy_rx_wq;
+ }
+
+ isert_cmd_cache = kmem_cache_create("isert_cmd_cache",
+ sizeof(struct isert_cmd), __alignof__(struct isert_cmd),
+ 0, NULL);
+ if (!isert_cmd_cache) {
+ pr_err("Unable to create isert_cmd_cache\n");
+ ret = -ENOMEM;
+ goto destroy_tx_cq;
+ }
+
+ iscsit_register_transport(&iser_target_transport);
+ pr_debug("iSER_TARGET[0] - Loaded iser_target_transport\n");
+ return 0;
+
+destroy_tx_cq:
+ destroy_workqueue(isert_comp_wq);
+destroy_rx_wq:
+ destroy_workqueue(isert_rx_wq);
+ return ret;
+}
+
+static void __exit isert_exit(void)
+{
+ kmem_cache_destroy(isert_cmd_cache);
+ destroy_workqueue(isert_comp_wq);
+ destroy_workqueue(isert_rx_wq);
+ iscsit_unregister_transport(&iser_target_transport);
+ pr_debug("iSER_TARGET[0] - Released iser_target_transport\n");
+}
+
+MODULE_DESCRIPTION("iSER-Target for mainline target infrastructure");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("nab@Linux-iSCSI.org");
+MODULE_LICENSE("GPL");
+
+module_init(isert_init);
+module_exit(isert_exit);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
new file mode 100644
index 000000000000..b104f4c2cd38
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -0,0 +1,138 @@
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+
+#define ISERT_RDMA_LISTEN_BACKLOG 10
+
+enum isert_desc_type {
+ ISCSI_TX_CONTROL,
+ ISCSI_TX_DATAIN
+};
+
+enum iser_ib_op_code {
+ ISER_IB_RECV,
+ ISER_IB_SEND,
+ ISER_IB_RDMA_WRITE,
+ ISER_IB_RDMA_READ,
+};
+
+enum iser_conn_state {
+ ISER_CONN_INIT,
+ ISER_CONN_UP,
+ ISER_CONN_TERMINATING,
+ ISER_CONN_DOWN,
+};
+
+struct iser_rx_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ char data[ISER_RECV_DATA_SEG_LEN];
+ u64 dma_addr;
+ struct ib_sge rx_sg;
+ char pad[ISER_RX_PAD_SIZE];
+} __packed;
+
+struct iser_tx_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ enum isert_desc_type type;
+ u64 dma_addr;
+ struct ib_sge tx_sg[2];
+ int num_sge;
+ struct isert_cmd *isert_cmd;
+ struct ib_send_wr send_wr;
+} __packed;
+
+struct isert_rdma_wr {
+ struct list_head wr_list;
+ struct isert_cmd *isert_cmd;
+ enum iser_ib_op_code iser_ib_op;
+ struct ib_sge *ib_sge;
+ int num_sge;
+ struct scatterlist *sge;
+ int send_wr_num;
+ struct ib_send_wr *send_wr;
+};
+
+struct isert_cmd {
+ uint32_t read_stag;
+ uint32_t write_stag;
+ uint64_t read_va;
+ uint64_t write_va;
+ u64 sense_buf_dma;
+ u32 sense_buf_len;
+ u32 read_va_off;
+ u32 write_va_off;
+ u32 rdma_wr_num;
+ struct isert_conn *conn;
+ struct iscsi_cmd iscsi_cmd;
+ struct ib_sge *ib_sge;
+ struct iser_tx_desc tx_desc;
+ struct isert_rdma_wr rdma_wr;
+ struct work_struct comp_work;
+};
+
+struct isert_device;
+
+struct isert_conn {
+ enum iser_conn_state state;
+ bool logout_posted;
+ int post_recv_buf_count;
+ atomic_t post_send_buf_count;
+ u32 responder_resources;
+ u32 initiator_depth;
+ u32 max_sge;
+ char *login_buf;
+ char *login_req_buf;
+ char *login_rsp_buf;
+ u64 login_req_dma;
+ u64 login_rsp_dma;
+ unsigned int conn_rx_desc_head;
+ struct iser_rx_desc *conn_rx_descs;
+ struct ib_recv_wr conn_rx_wr[ISERT_MIN_POSTED_RX];
+ struct iscsi_conn *conn;
+ struct list_head conn_accept_node;
+ struct completion conn_login_comp;
+ struct iser_tx_desc conn_login_tx_desc;
+ struct rdma_cm_id *conn_cm_id;
+ struct ib_pd *conn_pd;
+ struct ib_mr *conn_mr;
+ struct ib_qp *conn_qp;
+ struct isert_device *conn_device;
+ struct work_struct conn_logout_work;
+ wait_queue_head_t conn_wait;
+ wait_queue_head_t conn_wait_comp_err;
+ struct kref conn_kref;
+};
+
+#define ISERT_MAX_CQ 64
+
+struct isert_cq_desc {
+ struct isert_device *device;
+ int cq_index;
+ struct work_struct cq_rx_work;
+ struct work_struct cq_tx_work;
+};
+
+struct isert_device {
+ int cqs_used;
+ int refcount;
+ int cq_active_qps[ISERT_MAX_CQ];
+ struct ib_device *ib_device;
+ struct ib_pd *dev_pd;
+ struct ib_mr *dev_mr;
+ struct ib_cq *dev_rx_cq[ISERT_MAX_CQ];
+ struct ib_cq *dev_tx_cq[ISERT_MAX_CQ];
+ struct isert_cq_desc *cq_desc;
+ struct list_head dev_node;
+};
+
+struct isert_np {
+ wait_queue_head_t np_accept_wq;
+ struct rdma_cm_id *np_cm_id;
+ struct mutex np_accept_mutex;
+ struct list_head np_accept_list;
+ struct completion np_login_comp;
+};
diff --git a/drivers/infiniband/ulp/isert/isert_proto.h b/drivers/infiniband/ulp/isert/isert_proto.h
new file mode 100644
index 000000000000..4dccd313b777
--- /dev/null
+++ b/drivers/infiniband/ulp/isert/isert_proto.h
@@ -0,0 +1,47 @@
+/* From iscsi_iser.h */
+
+struct iser_hdr {
+ u8 flags;
+ u8 rsvd[3];
+ __be32 write_stag; /* write rkey */
+ __be64 write_va;
+ __be32 read_stag; /* read rkey */
+ __be64 read_va;
+} __packed;
+
+/*Constant PDU lengths calculations */
+#define ISER_HEADERS_LEN (sizeof(struct iser_hdr) + sizeof(struct iscsi_hdr))
+
+#define ISER_RECV_DATA_SEG_LEN 8192
+#define ISER_RX_PAYLOAD_SIZE (ISER_HEADERS_LEN + ISER_RECV_DATA_SEG_LEN)
+#define ISER_RX_LOGIN_SIZE (ISER_HEADERS_LEN + ISCSI_DEF_MAX_RECV_SEG_LEN)
+
+/* QP settings */
+/* Maximal bounds on received asynchronous PDUs */
+#define ISERT_MAX_TX_MISC_PDUS 4 /* NOOP_IN(2) , ASYNC_EVENT(2) */
+
+#define ISERT_MAX_RX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
+ * SCSI_TMFUNC(2), LOGOUT(1) */
+
+#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* from libiscsi.h, must be power of 2 */
+
+#define ISERT_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX)
+
+#define ISERT_MIN_POSTED_RX (ISCSI_DEF_XMIT_CMDS_MAX >> 2)
+
+#define ISERT_INFLIGHT_DATAOUTS 8
+
+#define ISERT_QP_MAX_REQ_DTOS (ISCSI_DEF_XMIT_CMDS_MAX * \
+ (1 + ISERT_INFLIGHT_DATAOUTS) + \
+ ISERT_MAX_TX_MISC_PDUS + \
+ ISERT_MAX_RX_MISC_PDUS)
+
+#define ISER_RX_PAD_SIZE (ISER_RECV_DATA_SEG_LEN + 4096 - \
+ (ISER_RX_PAYLOAD_SIZE + sizeof(u64) + sizeof(struct ib_sge)))
+
+#define ISER_VER 0x10
+#define ISER_WSV 0x08
+#define ISER_RSV 0x04
+#define ISCSI_CTRL 0x10
+#define ISER_HELLO 0x20
+#define ISER_HELLORPLY 0x30
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 71db1930573f..d398f1321f14 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -79,6 +79,8 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
}
if (flags & INPUT_MT_DIRECT)
__set_bit(INPUT_PROP_DIRECT, dev->propbit);
+ if (flags & INPUT_MT_SEMI_MT)
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
if (flags & INPUT_MT_TRACK) {
unsigned int n2 = num_slots * num_slots;
mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
@@ -246,6 +248,7 @@ void input_mt_sync_frame(struct input_dev *dev)
{
struct input_mt *mt = dev->mt;
struct input_mt_slot *s;
+ bool use_count = false;
if (!mt)
return;
@@ -259,7 +262,10 @@ void input_mt_sync_frame(struct input_dev *dev)
}
}
- input_mt_report_pointer_emulation(dev, (mt->flags & INPUT_MT_POINTER));
+ if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
+ use_count = true;
+
+ input_mt_report_pointer_emulation(dev, use_count);
mt->frame++;
}
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index 79172af164f2..ba0b36f7daea 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -260,18 +260,6 @@ static struct platform_driver amikbd_driver = {
},
};
-static int __init amikbd_init(void)
-{
- return platform_driver_probe(&amikbd_driver, amikbd_probe);
-}
-
-module_init(amikbd_init);
-
-static void __exit amikbd_exit(void)
-{
- platform_driver_unregister(&amikbd_driver);
-}
-
-module_exit(amikbd_exit);
+module_platform_driver_probe(amikbd_driver, amikbd_probe);
MODULE_ALIAS("platform:amiga-keyboard");
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index 4e4e453ea15e..829753702b62 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -329,17 +329,7 @@ static struct platform_driver davinci_ks_driver = {
.remove = davinci_ks_remove,
};
-static int __init davinci_ks_init(void)
-{
- return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe);
-}
-module_init(davinci_ks_init);
-
-static void __exit davinci_ks_exit(void)
-{
- platform_driver_unregister(&davinci_ks_driver);
-}
-module_exit(davinci_ks_exit);
+module_platform_driver_probe(davinci_ks_driver, davinci_ks_probe);
MODULE_AUTHOR("Miguel Aguilar");
MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 98f9113251d2..03c8cc5cb6c1 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -448,24 +448,17 @@ static int imx_keypad_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to request I/O memory\n");
- return -EBUSY;
- }
-
- input_dev = input_allocate_device();
+ input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate the input device\n");
- error = -ENOMEM;
- goto failed_rel_mem;
+ return -ENOMEM;
}
- keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL);
+ keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
+ GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
- error = -ENOMEM;
- goto failed_free_input;
+ return -ENOMEM;
}
keypad->input_dev = input_dev;
@@ -475,18 +468,14 @@ static int imx_keypad_probe(struct platform_device *pdev)
setup_timer(&keypad->check_matrix_timer,
imx_keypad_check_for_events, (unsigned long) keypad);
- keypad->mmio_base = ioremap(res->start, resource_size(res));
- if (keypad->mmio_base == NULL) {
- dev_err(&pdev->dev, "failed to remap I/O memory\n");
- error = -ENOMEM;
- goto failed_free_priv;
- }
+ keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(keypad->mmio_base))
+ return PTR_ERR(keypad->mmio_base);
- keypad->clk = clk_get(&pdev->dev, NULL);
+ keypad->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk)) {
dev_err(&pdev->dev, "failed to get keypad clock\n");
- error = PTR_ERR(keypad->clk);
- goto failed_unmap;
+ return PTR_ERR(keypad->clk);
}
/* Init the Input device */
@@ -502,7 +491,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
keypad->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
- goto failed_clock_put;
+ return error;
}
/* Search for rows and cols enabled */
@@ -527,61 +516,24 @@ static int imx_keypad_probe(struct platform_device *pdev)
imx_keypad_inhibit(keypad);
clk_disable_unprepare(keypad->clk);
- error = request_irq(irq, imx_keypad_irq_handler, 0,
+ error = devm_request_irq(&pdev->dev, irq, imx_keypad_irq_handler, 0,
pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
- goto failed_clock_put;
+ return error;
}
/* Register the input device */
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
- goto failed_free_irq;
+ return error;
}
platform_set_drvdata(pdev, keypad);
device_init_wakeup(&pdev->dev, 1);
return 0;
-
-failed_free_irq:
- free_irq(irq, pdev);
-failed_clock_put:
- clk_put(keypad->clk);
-failed_unmap:
- iounmap(keypad->mmio_base);
-failed_free_priv:
- kfree(keypad);
-failed_free_input:
- input_free_device(input_dev);
-failed_rel_mem:
- release_mem_region(res->start, resource_size(res));
- return error;
-}
-
-static int imx_keypad_remove(struct platform_device *pdev)
-{
- struct imx_keypad *keypad = platform_get_drvdata(pdev);
- struct resource *res;
-
- dev_dbg(&pdev->dev, ">%s\n", __func__);
-
- platform_set_drvdata(pdev, NULL);
-
- input_unregister_device(keypad->input_dev);
-
- free_irq(keypad->irq, keypad);
- clk_put(keypad->clk);
-
- iounmap(keypad->mmio_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(keypad);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -640,7 +592,6 @@ static struct platform_driver imx_keypad_driver = {
.of_match_table = of_match_ptr(imx_keypad_of_match),
},
.probe = imx_keypad_probe,
- .remove = imx_keypad_remove,
};
module_platform_driver(imx_keypad_driver);
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 0e6a8151fee3..c7d505cce72f 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -430,17 +430,7 @@ static struct platform_driver ske_keypad_driver = {
.remove = ske_keypad_remove,
};
-static int __init ske_keypad_init(void)
-{
- return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe);
-}
-module_init(ske_keypad_init);
-
-static void __exit ske_keypad_exit(void)
-{
- platform_driver_unregister(&ske_keypad_driver);
-}
-module_exit(ske_keypad_exit);
+module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 0e138ebcc768..b46142f78ef2 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -27,17 +27,19 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
#include <linux/clk/tegra.h>
+#include <linux/err.h>
-#define KBC_MAX_GPIO 24
#define KBC_MAX_KPENT 8
-#define KBC_MAX_ROW 16
-#define KBC_MAX_COL 8
-#define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL)
+/* Maximum row/column supported by Tegra KBC yet is 16x8 */
+#define KBC_MAX_GPIO 24
+/* Maximum keys supported by Tegra KBC yet is 16 x 8*/
+#define KBC_MAX_KEY (16 * 8)
#define KBC_MAX_DEBOUNCE_CNT 0x3ffu
@@ -80,6 +82,12 @@ enum tegra_pin_type {
PIN_CFG_ROW,
};
+/* Tegra KBC hw support */
+struct tegra_kbc_hw_support {
+ int max_rows;
+ int max_columns;
+};
+
struct tegra_kbc_pin_cfg {
enum tegra_pin_type type;
unsigned char num;
@@ -108,6 +116,9 @@ struct tegra_kbc {
u32 wakeup_key;
struct timer_list timer;
struct clk *clk;
+ const struct tegra_kbc_hw_support *hw_support;
+ int max_keys;
+ int num_rows_and_columns;
};
static void tegra_kbc_report_released_keys(struct input_dev *input,
@@ -204,11 +215,11 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
/*
* If the platform uses Fn keymaps, translate keys on a Fn keypress.
- * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
+ * Function keycodes are max_keys apart from the plain keycodes.
*/
if (fn_keypress) {
for (i = 0; i < num_down; i++) {
- scancodes[i] += KBC_MAX_KEY;
+ scancodes[i] += kbc->max_keys;
keycodes[i] = kbc->keycode[scancodes[i]];
}
}
@@ -315,7 +326,7 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
/* Either mask all keys or none. */
rst_val = (filter && !kbc->wakeup) ? ~0 : 0;
- for (i = 0; i < KBC_MAX_ROW; i++)
+ for (i = 0; i < kbc->hw_support->max_rows; i++)
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
}
@@ -452,7 +463,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
switch (pin_cfg->type) {
case PIN_CFG_ROW:
- if (pin_cfg->num >= KBC_MAX_ROW) {
+ if (pin_cfg->num >= kbc->hw_support->max_rows) {
dev_err(kbc->dev,
"pin_cfg[%d]: invalid row number %d\n",
i, pin_cfg->num);
@@ -462,7 +473,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
break;
case PIN_CFG_COL:
- if (pin_cfg->num >= KBC_MAX_COL) {
+ if (pin_cfg->num >= kbc->hw_support->max_columns) {
dev_err(kbc->dev,
"pin_cfg[%d]: invalid column number %d\n",
i, pin_cfg->num);
@@ -520,6 +531,18 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
}
num_cols = proplen / sizeof(u32);
+ if (num_rows > kbc->hw_support->max_rows) {
+ dev_err(kbc->dev,
+ "Number of rows is more than supported by hardware\n");
+ return -EINVAL;
+ }
+
+ if (num_cols > kbc->hw_support->max_columns) {
+ dev_err(kbc->dev,
+ "Number of cols is more than supported by hardware\n");
+ return -EINVAL;
+ }
+
if (!of_get_property(np, "linux,keymap", &proplen)) {
dev_err(kbc->dev, "property linux,keymap not found\n");
return -ENOENT;
@@ -532,7 +555,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
}
/* Set all pins as non-configured */
- for (i = 0; i < KBC_MAX_GPIO; i++)
+ for (i = 0; i < kbc->num_rows_and_columns; i++)
kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
@@ -562,6 +585,24 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
return 0;
}
+static const struct tegra_kbc_hw_support tegra20_kbc_hw_support = {
+ .max_rows = 16,
+ .max_columns = 8,
+};
+
+static const struct tegra_kbc_hw_support tegra11_kbc_hw_support = {
+ .max_rows = 11,
+ .max_columns = 8,
+};
+
+static const struct of_device_id tegra_kbc_of_match[] = {
+ { .compatible = "nvidia,tegra114-kbc", .data = &tegra11_kbc_hw_support},
+ { .compatible = "nvidia,tegra30-kbc", .data = &tegra20_kbc_hw_support},
+ { .compatible = "nvidia,tegra20-kbc", .data = &tegra20_kbc_hw_support},
+ { },
+};
+MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
+
static int tegra_kbc_probe(struct platform_device *pdev)
{
struct tegra_kbc *kbc;
@@ -570,7 +611,10 @@ static int tegra_kbc_probe(struct platform_device *pdev)
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
- unsigned int keymap_rows = KBC_MAX_KEY;
+ unsigned int keymap_rows;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(tegra_kbc_of_match), &pdev->dev);
kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);
if (!kbc) {
@@ -579,6 +623,12 @@ static int tegra_kbc_probe(struct platform_device *pdev)
}
kbc->dev = &pdev->dev;
+ kbc->hw_support = match->data;
+ kbc->max_keys = kbc->hw_support->max_rows *
+ kbc->hw_support->max_columns;
+ kbc->num_rows_and_columns = kbc->hw_support->max_rows +
+ kbc->hw_support->max_columns;
+ keymap_rows = kbc->max_keys;
spin_lock_init(&kbc->lock);
err = tegra_kbc_parse_dt(kbc);
@@ -608,11 +658,9 @@ static int tegra_kbc_probe(struct platform_device *pdev)
setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
- kbc->mmio = devm_request_and_ioremap(&pdev->dev, res);
- if (!kbc->mmio) {
- dev_err(&pdev->dev, "Cannot request memregion/iomap address\n");
- return -EBUSY;
- }
+ kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(kbc->mmio))
+ return PTR_ERR(kbc->mmio);
kbc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(kbc->clk)) {
@@ -641,7 +689,8 @@ static int tegra_kbc_probe(struct platform_device *pdev)
keymap_rows *= 2;
err = matrix_keypad_build_keymap(kbc->keymap_data, NULL,
- keymap_rows, KBC_MAX_COL,
+ keymap_rows,
+ kbc->hw_support->max_columns,
kbc->keycode, kbc->idev);
if (err) {
dev_err(&pdev->dev, "failed to setup keymap\n");
@@ -767,12 +816,6 @@ static int tegra_kbc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);
-static const struct of_device_id tegra_kbc_of_match[] = {
- { .compatible = "nvidia,tegra20-kbc", },
- { },
-};
-MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
-
static struct platform_driver tegra_kbc_driver = {
.probe = tegra_kbc_probe,
.driver = {
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 259ef31abb18..af80928a46b4 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -590,6 +590,16 @@ config INPUT_ADXL34X_SPI
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
+config INPUT_IMS_PCU
+ tristate "IMS Passenger Control Unit driver"
+ depends on USB
+ depends on LEDS_CLASS
+ help
+ Say Y here if you have system with IMS Rave Passenger Control Unit.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ims_pcu.
+
config INPUT_CMA3000
tristate "VTI CMA3000 Tri-axis accelerometer"
help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 1f1e1b109d9d..d7fc17f11d77 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
+obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index 29d2064c26f2..e0f522516ef5 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -13,7 +13,7 @@
#include <linux/pm.h>
#include "ad714x.h"
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ad714x_i2c_suspend(struct device *dev)
{
return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index bdccca42d138..61891486067c 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -16,7 +16,7 @@
#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */
#define AD714x_SPI_READ BIT(10)
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ad714x_spi_suspend(struct device *dev)
{
return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index 535dda48cace..416f47ddcc90 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -105,7 +105,7 @@ static int adxl34x_i2c_remove(struct i2c_client *client)
return adxl34x_remove(ac);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int adxl34x_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
index ad5f40d37e48..76dc0679d3b1 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -89,16 +89,16 @@ static int adxl34x_spi_probe(struct spi_device *spi)
static int adxl34x_spi_remove(struct spi_device *spi)
{
- struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+ struct adxl34x *ac = spi_get_drvdata(spi);
return adxl34x_remove(ac);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int adxl34x_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+ struct adxl34x *ac = spi_get_drvdata(spi);
adxl34x_suspend(ac);
@@ -108,7 +108,7 @@ static int adxl34x_spi_suspend(struct device *dev)
static int adxl34x_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+ struct adxl34x *ac = spi_get_drvdata(spi);
adxl34x_resume(ac);
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
new file mode 100644
index 000000000000..e204f26b0011
--- /dev/null
+++ b/drivers/input/misc/ims-pcu.c
@@ -0,0 +1,1901 @@
+/*
+ * Driver for IMS Passenger Control Unit Devices
+ *
+ * Copyright (C) 2013 The IMS Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/ihex.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/usb/input.h>
+#include <linux/usb/cdc.h>
+#include <asm/unaligned.h>
+
+#define IMS_PCU_KEYMAP_LEN 32
+
+struct ims_pcu_buttons {
+ struct input_dev *input;
+ char name[32];
+ char phys[32];
+ unsigned short keymap[IMS_PCU_KEYMAP_LEN];
+};
+
+struct ims_pcu_gamepad {
+ struct input_dev *input;
+ char name[32];
+ char phys[32];
+};
+
+struct ims_pcu_backlight {
+ struct led_classdev cdev;
+ struct work_struct work;
+ enum led_brightness desired_brightness;
+ char name[32];
+};
+
+#define IMS_PCU_PART_NUMBER_LEN 15
+#define IMS_PCU_SERIAL_NUMBER_LEN 8
+#define IMS_PCU_DOM_LEN 8
+#define IMS_PCU_FW_VERSION_LEN (9 + 1)
+#define IMS_PCU_BL_VERSION_LEN (9 + 1)
+#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
+
+#define IMS_PCU_BUF_SIZE 128
+
+struct ims_pcu {
+ struct usb_device *udev;
+ struct device *dev; /* control interface's device, used for logging */
+
+ unsigned int device_no;
+
+ bool bootloader_mode;
+
+ char part_number[IMS_PCU_PART_NUMBER_LEN];
+ char serial_number[IMS_PCU_SERIAL_NUMBER_LEN];
+ char date_of_manufacturing[IMS_PCU_DOM_LEN];
+ char fw_version[IMS_PCU_FW_VERSION_LEN];
+ char bl_version[IMS_PCU_BL_VERSION_LEN];
+ char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
+ int update_firmware_status;
+
+ struct usb_interface *ctrl_intf;
+
+ struct usb_endpoint_descriptor *ep_ctrl;
+ struct urb *urb_ctrl;
+ u8 *urb_ctrl_buf;
+ dma_addr_t ctrl_dma;
+ size_t max_ctrl_size;
+
+ struct usb_interface *data_intf;
+
+ struct usb_endpoint_descriptor *ep_in;
+ struct urb *urb_in;
+ u8 *urb_in_buf;
+ dma_addr_t read_dma;
+ size_t max_in_size;
+
+ struct usb_endpoint_descriptor *ep_out;
+ u8 *urb_out_buf;
+ size_t max_out_size;
+
+ u8 read_buf[IMS_PCU_BUF_SIZE];
+ u8 read_pos;
+ u8 check_sum;
+ bool have_stx;
+ bool have_dle;
+
+ u8 cmd_buf[IMS_PCU_BUF_SIZE];
+ u8 ack_id;
+ u8 expected_response;
+ u8 cmd_buf_len;
+ struct completion cmd_done;
+ struct mutex cmd_mutex;
+
+ u32 fw_start_addr;
+ u32 fw_end_addr;
+ struct completion async_firmware_done;
+
+ struct ims_pcu_buttons buttons;
+ struct ims_pcu_gamepad *gamepad;
+ struct ims_pcu_backlight backlight;
+
+ bool setup_complete; /* Input and LED devices have been created */
+};
+
+
+/*********************************************************************
+ * Buttons Input device support *
+ *********************************************************************/
+
+static const unsigned short ims_pcu_keymap_1[] = {
+ [1] = KEY_ATTENDANT_OFF,
+ [2] = KEY_ATTENDANT_ON,
+ [3] = KEY_LIGHTS_TOGGLE,
+ [4] = KEY_VOLUMEUP,
+ [5] = KEY_VOLUMEDOWN,
+ [6] = KEY_INFO,
+};
+
+static const unsigned short ims_pcu_keymap_2[] = {
+ [4] = KEY_VOLUMEUP,
+ [5] = KEY_VOLUMEDOWN,
+ [6] = KEY_INFO,
+};
+
+static const unsigned short ims_pcu_keymap_3[] = {
+ [1] = KEY_HOMEPAGE,
+ [2] = KEY_ATTENDANT_TOGGLE,
+ [3] = KEY_LIGHTS_TOGGLE,
+ [4] = KEY_VOLUMEUP,
+ [5] = KEY_VOLUMEDOWN,
+ [6] = KEY_DISPLAYTOGGLE,
+ [18] = KEY_PLAYPAUSE,
+};
+
+static const unsigned short ims_pcu_keymap_4[] = {
+ [1] = KEY_ATTENDANT_OFF,
+ [2] = KEY_ATTENDANT_ON,
+ [3] = KEY_LIGHTS_TOGGLE,
+ [4] = KEY_VOLUMEUP,
+ [5] = KEY_VOLUMEDOWN,
+ [6] = KEY_INFO,
+ [18] = KEY_PLAYPAUSE,
+};
+
+static const unsigned short ims_pcu_keymap_5[] = {
+ [1] = KEY_ATTENDANT_OFF,
+ [2] = KEY_ATTENDANT_ON,
+ [3] = KEY_LIGHTS_TOGGLE,
+};
+
+struct ims_pcu_device_info {
+ const unsigned short *keymap;
+ size_t keymap_len;
+ bool has_gamepad;
+};
+
+#define IMS_PCU_DEVINFO(_n, _gamepad) \
+ [_n] = { \
+ .keymap = ims_pcu_keymap_##_n, \
+ .keymap_len = ARRAY_SIZE(ims_pcu_keymap_##_n), \
+ .has_gamepad = _gamepad, \
+ }
+
+static const struct ims_pcu_device_info ims_pcu_device_info[] = {
+ IMS_PCU_DEVINFO(1, true),
+ IMS_PCU_DEVINFO(2, true),
+ IMS_PCU_DEVINFO(3, true),
+ IMS_PCU_DEVINFO(4, true),
+ IMS_PCU_DEVINFO(5, false),
+};
+
+static void ims_pcu_buttons_report(struct ims_pcu *pcu, u32 data)
+{
+ struct ims_pcu_buttons *buttons = &pcu->buttons;
+ struct input_dev *input = buttons->input;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ unsigned short keycode = buttons->keymap[i];
+
+ if (keycode != KEY_RESERVED)
+ input_report_key(input, keycode, data & (1UL << i));
+ }
+
+ input_sync(input);
+}
+
+static int ims_pcu_setup_buttons(struct ims_pcu *pcu,
+ const unsigned short *keymap,
+ size_t keymap_len)
+{
+ struct ims_pcu_buttons *buttons = &pcu->buttons;
+ struct input_dev *input;
+ int i;
+ int error;
+
+ input = input_allocate_device();
+ if (!input) {
+ dev_err(pcu->dev,
+ "Not enough memory for input input device\n");
+ return -ENOMEM;
+ }
+
+ snprintf(buttons->name, sizeof(buttons->name),
+ "IMS PCU#%d Button Interface", pcu->device_no);
+
+ usb_make_path(pcu->udev, buttons->phys, sizeof(buttons->phys));
+ strlcat(buttons->phys, "/input0", sizeof(buttons->phys));
+
+ memcpy(buttons->keymap, keymap, sizeof(*keymap) * keymap_len);
+
+ input->name = buttons->name;
+ input->phys = buttons->phys;
+ usb_to_input_id(pcu->udev, &input->id);
+ input->dev.parent = &pcu->ctrl_intf->dev;
+
+ input->keycode = buttons->keymap;
+ input->keycodemax = ARRAY_SIZE(buttons->keymap);
+ input->keycodesize = sizeof(buttons->keymap[0]);
+
+ __set_bit(EV_KEY, input->evbit);
+ for (i = 0; i < IMS_PCU_KEYMAP_LEN; i++)
+ __set_bit(buttons->keymap[i], input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to register buttons input device: %d\n",
+ error);
+ input_free_device(input);
+ return error;
+ }
+
+ buttons->input = input;
+ return 0;
+}
+
+static void ims_pcu_destroy_buttons(struct ims_pcu *pcu)
+{
+ struct ims_pcu_buttons *buttons = &pcu->buttons;
+
+ input_unregister_device(buttons->input);
+}
+
+
+/*********************************************************************
+ * Gamepad Input device support *
+ *********************************************************************/
+
+static void ims_pcu_gamepad_report(struct ims_pcu *pcu, u32 data)
+{
+ struct ims_pcu_gamepad *gamepad = pcu->gamepad;
+ struct input_dev *input = gamepad->input;
+ int x, y;
+
+ x = !!(data & (1 << 14)) - !!(data & (1 << 13));
+ y = !!(data & (1 << 12)) - !!(data & (1 << 11));
+
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+
+ input_report_key(input, BTN_A, data & (1 << 7));
+ input_report_key(input, BTN_B, data & (1 << 8));
+ input_report_key(input, BTN_X, data & (1 << 9));
+ input_report_key(input, BTN_Y, data & (1 << 10));
+ input_report_key(input, BTN_START, data & (1 << 15));
+ input_report_key(input, BTN_SELECT, data & (1 << 16));
+
+ input_sync(input);
+}
+
+static int ims_pcu_setup_gamepad(struct ims_pcu *pcu)
+{
+ struct ims_pcu_gamepad *gamepad;
+ struct input_dev *input;
+ int error;
+
+ gamepad = kzalloc(sizeof(struct ims_pcu_gamepad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!gamepad || !input) {
+ dev_err(pcu->dev,
+ "Not enough memory for gamepad device\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ gamepad->input = input;
+
+ snprintf(gamepad->name, sizeof(gamepad->name),
+ "IMS PCU#%d Gamepad Interface", pcu->device_no);
+
+ usb_make_path(pcu->udev, gamepad->phys, sizeof(gamepad->phys));
+ strlcat(gamepad->phys, "/input1", sizeof(gamepad->phys));
+
+ input->name = gamepad->name;
+ input->phys = gamepad->phys;
+ usb_to_input_id(pcu->udev, &input->id);
+ input->dev.parent = &pcu->ctrl_intf->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_A, input->keybit);
+ __set_bit(BTN_B, input->keybit);
+ __set_bit(BTN_X, input->keybit);
+ __set_bit(BTN_Y, input->keybit);
+ __set_bit(BTN_START, input->keybit);
+ __set_bit(BTN_SELECT, input->keybit);
+
+ __set_bit(EV_ABS, input->evbit);
+ input_set_abs_params(input, ABS_X, -1, 1, 0, 0);
+ input_set_abs_params(input, ABS_Y, -1, 1, 0, 0);
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to register gamepad input device: %d\n",
+ error);
+ goto err_free_mem;
+ }
+
+ pcu->gamepad = gamepad;
+ return 0;
+
+err_free_mem:
+ input_free_device(input);
+ kfree(gamepad);
+ return -ENOMEM;
+}
+
+static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
+{
+ struct ims_pcu_gamepad *gamepad = pcu->gamepad;
+
+ input_unregister_device(gamepad->input);
+ kfree(gamepad);
+}
+
+
+/*********************************************************************
+ * PCU Communication protocol handling *
+ *********************************************************************/
+
+#define IMS_PCU_PROTOCOL_STX 0x02
+#define IMS_PCU_PROTOCOL_ETX 0x03
+#define IMS_PCU_PROTOCOL_DLE 0x10
+
+/* PCU commands */
+#define IMS_PCU_CMD_STATUS 0xa0
+#define IMS_PCU_CMD_PCU_RESET 0xa1
+#define IMS_PCU_CMD_RESET_REASON 0xa2
+#define IMS_PCU_CMD_SEND_BUTTONS 0xa3
+#define IMS_PCU_CMD_JUMP_TO_BTLDR 0xa4
+#define IMS_PCU_CMD_GET_INFO 0xa5
+#define IMS_PCU_CMD_SET_BRIGHTNESS 0xa6
+#define IMS_PCU_CMD_EEPROM 0xa7
+#define IMS_PCU_CMD_GET_FW_VERSION 0xa8
+#define IMS_PCU_CMD_GET_BL_VERSION 0xa9
+#define IMS_PCU_CMD_SET_INFO 0xab
+#define IMS_PCU_CMD_GET_BRIGHTNESS 0xac
+#define IMS_PCU_CMD_GET_DEVICE_ID 0xae
+#define IMS_PCU_CMD_SPECIAL_INFO 0xb0
+#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
+
+/* PCU responses */
+#define IMS_PCU_RSP_STATUS 0xc0
+#define IMS_PCU_RSP_PCU_RESET 0 /* Originally 0xc1 */
+#define IMS_PCU_RSP_RESET_REASON 0xc2
+#define IMS_PCU_RSP_SEND_BUTTONS 0xc3
+#define IMS_PCU_RSP_JUMP_TO_BTLDR 0 /* Originally 0xc4 */
+#define IMS_PCU_RSP_GET_INFO 0xc5
+#define IMS_PCU_RSP_SET_BRIGHTNESS 0xc6
+#define IMS_PCU_RSP_EEPROM 0xc7
+#define IMS_PCU_RSP_GET_FW_VERSION 0xc8
+#define IMS_PCU_RSP_GET_BL_VERSION 0xc9
+#define IMS_PCU_RSP_SET_INFO 0xcb
+#define IMS_PCU_RSP_GET_BRIGHTNESS 0xcc
+#define IMS_PCU_RSP_CMD_INVALID 0xcd
+#define IMS_PCU_RSP_GET_DEVICE_ID 0xce
+#define IMS_PCU_RSP_SPECIAL_INFO 0xd0
+#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
+
+#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
+#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
+
+
+#define IMS_PCU_MIN_PACKET_LEN 3
+#define IMS_PCU_DATA_OFFSET 2
+
+#define IMS_PCU_CMD_WRITE_TIMEOUT 100 /* msec */
+#define IMS_PCU_CMD_RESPONSE_TIMEOUT 500 /* msec */
+
+static void ims_pcu_report_events(struct ims_pcu *pcu)
+{
+ u32 data = get_unaligned_be32(&pcu->read_buf[3]);
+
+ ims_pcu_buttons_report(pcu, data & ~IMS_PCU_GAMEPAD_MASK);
+ if (pcu->gamepad)
+ ims_pcu_gamepad_report(pcu, data);
+}
+
+static void ims_pcu_handle_response(struct ims_pcu *pcu)
+{
+ switch (pcu->read_buf[0]) {
+ case IMS_PCU_RSP_EVNT_BUTTONS:
+ if (likely(pcu->setup_complete))
+ ims_pcu_report_events(pcu);
+ break;
+
+ default:
+ /*
+ * See if we got command completion.
+ * If both the sequence and response code match save
+ * the data and signal completion.
+ */
+ if (pcu->read_buf[0] == pcu->expected_response &&
+ pcu->read_buf[1] == pcu->ack_id - 1) {
+
+ memcpy(pcu->cmd_buf, pcu->read_buf, pcu->read_pos);
+ pcu->cmd_buf_len = pcu->read_pos;
+ complete(&pcu->cmd_done);
+ }
+ break;
+ }
+}
+
+static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
+{
+ int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ u8 data = pcu->urb_in_buf[i];
+
+ /* Skip everything until we get Start Xmit */
+ if (!pcu->have_stx && data != IMS_PCU_PROTOCOL_STX)
+ continue;
+
+ if (pcu->have_dle) {
+ pcu->have_dle = false;
+ pcu->read_buf[pcu->read_pos++] = data;
+ pcu->check_sum += data;
+ continue;
+ }
+
+ switch (data) {
+ case IMS_PCU_PROTOCOL_STX:
+ if (pcu->have_stx)
+ dev_warn(pcu->dev,
+ "Unexpected STX at byte %d, discarding old data\n",
+ pcu->read_pos);
+ pcu->have_stx = true;
+ pcu->have_dle = false;
+ pcu->read_pos = 0;
+ pcu->check_sum = 0;
+ break;
+
+ case IMS_PCU_PROTOCOL_DLE:
+ pcu->have_dle = true;
+ break;
+
+ case IMS_PCU_PROTOCOL_ETX:
+ if (pcu->read_pos < IMS_PCU_MIN_PACKET_LEN) {
+ dev_warn(pcu->dev,
+ "Short packet received (%d bytes), ignoring\n",
+ pcu->read_pos);
+ } else if (pcu->check_sum != 0) {
+ dev_warn(pcu->dev,
+ "Invalid checksum in packet (%d bytes), ignoring\n",
+ pcu->read_pos);
+ } else {
+ ims_pcu_handle_response(pcu);
+ }
+
+ pcu->have_stx = false;
+ pcu->have_dle = false;
+ pcu->read_pos = 0;
+ break;
+
+ default:
+ pcu->read_buf[pcu->read_pos++] = data;
+ pcu->check_sum += data;
+ break;
+ }
+ }
+}
+
+static bool ims_pcu_byte_needs_escape(u8 byte)
+{
+ return byte == IMS_PCU_PROTOCOL_STX ||
+ byte == IMS_PCU_PROTOCOL_ETX ||
+ byte == IMS_PCU_PROTOCOL_DLE;
+}
+
+static int ims_pcu_send_cmd_chunk(struct ims_pcu *pcu,
+ u8 command, int chunk, int len)
+{
+ int error;
+
+ error = usb_bulk_msg(pcu->udev,
+ usb_sndbulkpipe(pcu->udev,
+ pcu->ep_out->bEndpointAddress),
+ pcu->urb_out_buf, len,
+ NULL, IMS_PCU_CMD_WRITE_TIMEOUT);
+ if (error < 0) {
+ dev_dbg(pcu->dev,
+ "Sending 0x%02x command failed at chunk %d: %d\n",
+ command, chunk, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int ims_pcu_send_command(struct ims_pcu *pcu,
+ u8 command, const u8 *data, int len)
+{
+ int count = 0;
+ int chunk = 0;
+ int delta;
+ int i;
+ int error;
+ u8 csum = 0;
+ u8 ack_id;
+
+ pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_STX;
+
+ /* We know the command need not be escaped */
+ pcu->urb_out_buf[count++] = command;
+ csum += command;
+
+ ack_id = pcu->ack_id++;
+ if (ack_id == 0xff)
+ ack_id = pcu->ack_id++;
+
+ if (ims_pcu_byte_needs_escape(ack_id))
+ pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
+
+ pcu->urb_out_buf[count++] = ack_id;
+ csum += ack_id;
+
+ for (i = 0; i < len; i++) {
+
+ delta = ims_pcu_byte_needs_escape(data[i]) ? 2 : 1;
+ if (count + delta >= pcu->max_out_size) {
+ error = ims_pcu_send_cmd_chunk(pcu, command,
+ ++chunk, count);
+ if (error)
+ return error;
+
+ count = 0;
+ }
+
+ if (delta == 2)
+ pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
+
+ pcu->urb_out_buf[count++] = data[i];
+ csum += data[i];
+ }
+
+ csum = 1 + ~csum;
+
+ delta = ims_pcu_byte_needs_escape(csum) ? 3 : 2;
+ if (count + delta >= pcu->max_out_size) {
+ error = ims_pcu_send_cmd_chunk(pcu, command, ++chunk, count);
+ if (error)
+ return error;
+
+ count = 0;
+ }
+
+ if (delta == 3)
+ pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_DLE;
+
+ pcu->urb_out_buf[count++] = csum;
+ pcu->urb_out_buf[count++] = IMS_PCU_PROTOCOL_ETX;
+
+ return ims_pcu_send_cmd_chunk(pcu, command, ++chunk, count);
+}
+
+static int __ims_pcu_execute_command(struct ims_pcu *pcu,
+ u8 command, const void *data, size_t len,
+ u8 expected_response, int response_time)
+{
+ int error;
+
+ pcu->expected_response = expected_response;
+ init_completion(&pcu->cmd_done);
+
+ error = ims_pcu_send_command(pcu, command, data, len);
+ if (error)
+ return error;
+
+ if (expected_response &&
+ !wait_for_completion_timeout(&pcu->cmd_done,
+ msecs_to_jiffies(response_time))) {
+ dev_dbg(pcu->dev, "Command 0x%02x timed out\n", command);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+#define ims_pcu_execute_command(pcu, code, data, len) \
+ __ims_pcu_execute_command(pcu, \
+ IMS_PCU_CMD_##code, data, len, \
+ IMS_PCU_RSP_##code, \
+ IMS_PCU_CMD_RESPONSE_TIMEOUT)
+
+#define ims_pcu_execute_query(pcu, code) \
+ ims_pcu_execute_command(pcu, code, NULL, 0)
+
+/* Bootloader commands */
+#define IMS_PCU_BL_CMD_QUERY_DEVICE 0xa1
+#define IMS_PCU_BL_CMD_UNLOCK_CONFIG 0xa2
+#define IMS_PCU_BL_CMD_ERASE_APP 0xa3
+#define IMS_PCU_BL_CMD_PROGRAM_DEVICE 0xa4
+#define IMS_PCU_BL_CMD_PROGRAM_COMPLETE 0xa5
+#define IMS_PCU_BL_CMD_READ_APP 0xa6
+#define IMS_PCU_BL_CMD_RESET_DEVICE 0xa7
+#define IMS_PCU_BL_CMD_LAUNCH_APP 0xa8
+
+/* Bootloader commands */
+#define IMS_PCU_BL_RSP_QUERY_DEVICE 0xc1
+#define IMS_PCU_BL_RSP_UNLOCK_CONFIG 0xc2
+#define IMS_PCU_BL_RSP_ERASE_APP 0xc3
+#define IMS_PCU_BL_RSP_PROGRAM_DEVICE 0xc4
+#define IMS_PCU_BL_RSP_PROGRAM_COMPLETE 0xc5
+#define IMS_PCU_BL_RSP_READ_APP 0xc6
+#define IMS_PCU_BL_RSP_RESET_DEVICE 0 /* originally 0xa7 */
+#define IMS_PCU_BL_RSP_LAUNCH_APP 0 /* originally 0xa8 */
+
+#define IMS_PCU_BL_DATA_OFFSET 3
+
+static int __ims_pcu_execute_bl_command(struct ims_pcu *pcu,
+ u8 command, const void *data, size_t len,
+ u8 expected_response, int response_time)
+{
+ int error;
+
+ pcu->cmd_buf[0] = command;
+ if (data)
+ memcpy(&pcu->cmd_buf[1], data, len);
+
+ error = __ims_pcu_execute_command(pcu,
+ IMS_PCU_CMD_BOOTLOADER, pcu->cmd_buf, len + 1,
+ expected_response ? IMS_PCU_RSP_BOOTLOADER : 0,
+ response_time);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failure when sending 0x%02x command to bootloader, error: %d\n",
+ pcu->cmd_buf[0], error);
+ return error;
+ }
+
+ if (expected_response && pcu->cmd_buf[2] != expected_response) {
+ dev_err(pcu->dev,
+ "Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n",
+ pcu->cmd_buf[2], expected_response);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#define ims_pcu_execute_bl_command(pcu, code, data, len, timeout) \
+ __ims_pcu_execute_bl_command(pcu, \
+ IMS_PCU_BL_CMD_##code, data, len, \
+ IMS_PCU_BL_RSP_##code, timeout) \
+
+#define IMS_PCU_INFO_PART_OFFSET 2
+#define IMS_PCU_INFO_DOM_OFFSET 17
+#define IMS_PCU_INFO_SERIAL_OFFSET 25
+
+#define IMS_PCU_SET_INFO_SIZE 31
+
+static int ims_pcu_get_info(struct ims_pcu *pcu)
+{
+ int error;
+
+ error = ims_pcu_execute_query(pcu, GET_INFO);
+ if (error) {
+ dev_err(pcu->dev,
+ "GET_INFO command failed, error: %d\n", error);
+ return error;
+ }
+
+ memcpy(pcu->part_number,
+ &pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET],
+ sizeof(pcu->part_number));
+ memcpy(pcu->date_of_manufacturing,
+ &pcu->cmd_buf[IMS_PCU_INFO_DOM_OFFSET],
+ sizeof(pcu->date_of_manufacturing));
+ memcpy(pcu->serial_number,
+ &pcu->cmd_buf[IMS_PCU_INFO_SERIAL_OFFSET],
+ sizeof(pcu->serial_number));
+
+ return 0;
+}
+
+static int ims_pcu_set_info(struct ims_pcu *pcu)
+{
+ int error;
+
+ memcpy(&pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET],
+ pcu->part_number, sizeof(pcu->part_number));
+ memcpy(&pcu->cmd_buf[IMS_PCU_INFO_DOM_OFFSET],
+ pcu->date_of_manufacturing, sizeof(pcu->date_of_manufacturing));
+ memcpy(&pcu->cmd_buf[IMS_PCU_INFO_SERIAL_OFFSET],
+ pcu->serial_number, sizeof(pcu->serial_number));
+
+ error = ims_pcu_execute_command(pcu, SET_INFO,
+ &pcu->cmd_buf[IMS_PCU_DATA_OFFSET],
+ IMS_PCU_SET_INFO_SIZE);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to update device information, error: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int ims_pcu_switch_to_bootloader(struct ims_pcu *pcu)
+{
+ int error;
+
+ /* Execute jump to the bootoloader */
+ error = ims_pcu_execute_command(pcu, JUMP_TO_BTLDR, NULL, 0);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failure when sending JUMP TO BOOLTLOADER command, error: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ * Firmware Update handling *
+ *********************************************************************/
+
+#define IMS_PCU_FIRMWARE_NAME "imspcu.fw"
+
+struct ims_pcu_flash_fmt {
+ __le32 addr;
+ u8 len;
+ u8 data[];
+};
+
+static unsigned int ims_pcu_count_fw_records(const struct firmware *fw)
+{
+ const struct ihex_binrec *rec = (const struct ihex_binrec *)fw->data;
+ unsigned int count = 0;
+
+ while (rec) {
+ count++;
+ rec = ihex_next_binrec(rec);
+ }
+
+ return count;
+}
+
+static int ims_pcu_verify_block(struct ims_pcu *pcu,
+ u32 addr, u8 len, const u8 *data)
+{
+ struct ims_pcu_flash_fmt *fragment;
+ int error;
+
+ fragment = (void *)&pcu->cmd_buf[1];
+ put_unaligned_le32(addr, &fragment->addr);
+ fragment->len = len;
+
+ error = ims_pcu_execute_bl_command(pcu, READ_APP, NULL, 5,
+ IMS_PCU_CMD_RESPONSE_TIMEOUT);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to retrieve block at 0x%08x, len %d, error: %d\n",
+ addr, len, error);
+ return error;
+ }
+
+ fragment = (void *)&pcu->cmd_buf[IMS_PCU_BL_DATA_OFFSET];
+ if (get_unaligned_le32(&fragment->addr) != addr ||
+ fragment->len != len) {
+ dev_err(pcu->dev,
+ "Wrong block when retrieving 0x%08x (0x%08x), len %d (%d)\n",
+ addr, get_unaligned_le32(&fragment->addr),
+ len, fragment->len);
+ return -EINVAL;
+ }
+
+ if (memcmp(fragment->data, data, len)) {
+ dev_err(pcu->dev,
+ "Mismatch in block at 0x%08x, len %d\n",
+ addr, len);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ims_pcu_flash_firmware(struct ims_pcu *pcu,
+ const struct firmware *fw,
+ unsigned int n_fw_records)
+{
+ const struct ihex_binrec *rec = (const struct ihex_binrec *)fw->data;
+ struct ims_pcu_flash_fmt *fragment;
+ unsigned int count = 0;
+ u32 addr;
+ u8 len;
+ int error;
+
+ error = ims_pcu_execute_bl_command(pcu, ERASE_APP, NULL, 0, 2000);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to erase application image, error: %d\n",
+ error);
+ return error;
+ }
+
+ while (rec) {
+ /*
+ * The firmware format is messed up for some reason.
+ * The address twice that of what is needed for some
+ * reason and we end up overwriting half of the data
+ * with the next record.
+ */
+ addr = be32_to_cpu(rec->addr) / 2;
+ len = be16_to_cpu(rec->len);
+
+ fragment = (void *)&pcu->cmd_buf[1];
+ put_unaligned_le32(addr, &fragment->addr);
+ fragment->len = len;
+ memcpy(fragment->data, rec->data, len);
+
+ error = ims_pcu_execute_bl_command(pcu, PROGRAM_DEVICE,
+ NULL, len + 5,
+ IMS_PCU_CMD_RESPONSE_TIMEOUT);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to write block at 0x%08x, len %d, error: %d\n",
+ addr, len, error);
+ return error;
+ }
+
+ if (addr >= pcu->fw_start_addr && addr < pcu->fw_end_addr) {
+ error = ims_pcu_verify_block(pcu, addr, len, rec->data);
+ if (error)
+ return error;
+ }
+
+ count++;
+ pcu->update_firmware_status = (count * 100) / n_fw_records;
+
+ rec = ihex_next_binrec(rec);
+ }
+
+ error = ims_pcu_execute_bl_command(pcu, PROGRAM_COMPLETE,
+ NULL, 0, 2000);
+ if (error)
+ dev_err(pcu->dev,
+ "Failed to send PROGRAM_COMPLETE, error: %d\n",
+ error);
+
+ return 0;
+}
+
+static int ims_pcu_handle_firmware_update(struct ims_pcu *pcu,
+ const struct firmware *fw)
+{
+ unsigned int n_fw_records;
+ int retval;
+
+ dev_info(pcu->dev, "Updating firmware %s, size: %zu\n",
+ IMS_PCU_FIRMWARE_NAME, fw->size);
+
+ n_fw_records = ims_pcu_count_fw_records(fw);
+
+ retval = ims_pcu_flash_firmware(pcu, fw, n_fw_records);
+ if (retval)
+ goto out;
+
+ retval = ims_pcu_execute_bl_command(pcu, LAUNCH_APP, NULL, 0, 0);
+ if (retval)
+ dev_err(pcu->dev,
+ "Failed to start application image, error: %d\n",
+ retval);
+
+out:
+ pcu->update_firmware_status = retval;
+ sysfs_notify(&pcu->dev->kobj, NULL, "update_firmware_status");
+ return retval;
+}
+
+static void ims_pcu_process_async_firmware(const struct firmware *fw,
+ void *context)
+{
+ struct ims_pcu *pcu = context;
+ int error;
+
+ if (!fw) {
+ dev_err(pcu->dev, "Failed to get firmware %s\n",
+ IMS_PCU_FIRMWARE_NAME);
+ goto out;
+ }
+
+ error = ihex_validate_fw(fw);
+ if (error) {
+ dev_err(pcu->dev, "Firmware %s is invalid\n",
+ IMS_PCU_FIRMWARE_NAME);
+ goto out;
+ }
+
+ mutex_lock(&pcu->cmd_mutex);
+ ims_pcu_handle_firmware_update(pcu, fw);
+ mutex_unlock(&pcu->cmd_mutex);
+
+ release_firmware(fw);
+
+out:
+ complete(&pcu->async_firmware_done);
+}
+
+/*********************************************************************
+ * Backlight LED device support *
+ *********************************************************************/
+
+#define IMS_PCU_MAX_BRIGHTNESS 31998
+
+static void ims_pcu_backlight_work(struct work_struct *work)
+{
+ struct ims_pcu_backlight *backlight =
+ container_of(work, struct ims_pcu_backlight, work);
+ struct ims_pcu *pcu =
+ container_of(backlight, struct ims_pcu, backlight);
+ int desired_brightness = backlight->desired_brightness;
+ __le16 br_val = cpu_to_le16(desired_brightness);
+ int error;
+
+ mutex_lock(&pcu->cmd_mutex);
+
+ error = ims_pcu_execute_command(pcu, SET_BRIGHTNESS,
+ &br_val, sizeof(br_val));
+ if (error && error != -ENODEV)
+ dev_warn(pcu->dev,
+ "Failed to set desired brightness %u, error: %d\n",
+ desired_brightness, error);
+
+ mutex_unlock(&pcu->cmd_mutex);
+}
+
+static void ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct ims_pcu_backlight *backlight =
+ container_of(cdev, struct ims_pcu_backlight, cdev);
+
+ backlight->desired_brightness = value;
+ schedule_work(&backlight->work);
+}
+
+static enum led_brightness
+ims_pcu_backlight_get_brightness(struct led_classdev *cdev)
+{
+ struct ims_pcu_backlight *backlight =
+ container_of(cdev, struct ims_pcu_backlight, cdev);
+ struct ims_pcu *pcu =
+ container_of(backlight, struct ims_pcu, backlight);
+ int brightness;
+ int error;
+
+ mutex_lock(&pcu->cmd_mutex);
+
+ error = ims_pcu_execute_query(pcu, GET_BRIGHTNESS);
+ if (error) {
+ dev_warn(pcu->dev,
+ "Failed to get current brightness, error: %d\n",
+ error);
+ /* Assume the LED is OFF */
+ brightness = LED_OFF;
+ } else {
+ brightness =
+ get_unaligned_le16(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
+ }
+
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return brightness;
+}
+
+static int ims_pcu_setup_backlight(struct ims_pcu *pcu)
+{
+ struct ims_pcu_backlight *backlight = &pcu->backlight;
+ int error;
+
+ INIT_WORK(&backlight->work, ims_pcu_backlight_work);
+ snprintf(backlight->name, sizeof(backlight->name),
+ "pcu%d::kbd_backlight", pcu->device_no);
+
+ backlight->cdev.name = backlight->name;
+ backlight->cdev.max_brightness = IMS_PCU_MAX_BRIGHTNESS;
+ backlight->cdev.brightness_get = ims_pcu_backlight_get_brightness;
+ backlight->cdev.brightness_set = ims_pcu_backlight_set_brightness;
+
+ error = led_classdev_register(pcu->dev, &backlight->cdev);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to register backlight LED device, error: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void ims_pcu_destroy_backlight(struct ims_pcu *pcu)
+{
+ struct ims_pcu_backlight *backlight = &pcu->backlight;
+
+ led_classdev_unregister(&backlight->cdev);
+ cancel_work_sync(&backlight->work);
+}
+
+
+/*********************************************************************
+ * Sysfs attributes handling *
+ *********************************************************************/
+
+struct ims_pcu_attribute {
+ struct device_attribute dattr;
+ size_t field_offset;
+ int field_length;
+};
+
+static ssize_t ims_pcu_attribute_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct ims_pcu_attribute *attr =
+ container_of(dattr, struct ims_pcu_attribute, dattr);
+ char *field = (char *)pcu + attr->field_offset;
+
+ return scnprintf(buf, PAGE_SIZE, "%.*s\n", attr->field_length, field);
+}
+
+static ssize_t ims_pcu_attribute_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct ims_pcu_attribute *attr =
+ container_of(dattr, struct ims_pcu_attribute, dattr);
+ char *field = (char *)pcu + attr->field_offset;
+ size_t data_len;
+ int error;
+
+ if (count > attr->field_length)
+ return -EINVAL;
+
+ data_len = strnlen(buf, attr->field_length);
+ if (data_len > attr->field_length)
+ return -EINVAL;
+
+ error = mutex_lock_interruptible(&pcu->cmd_mutex);
+ if (error)
+ return error;
+
+ memset(field, 0, attr->field_length);
+ memcpy(field, buf, data_len);
+
+ error = ims_pcu_set_info(pcu);
+
+ /*
+ * Even if update failed, let's fetch the info again as we just
+ * clobbered one of the fields.
+ */
+ ims_pcu_get_info(pcu);
+
+ mutex_unlock(&pcu->cmd_mutex);
+
+ return error < 0 ? error : count;
+}
+
+#define IMS_PCU_ATTR(_field, _mode) \
+struct ims_pcu_attribute ims_pcu_attr_##_field = { \
+ .dattr = __ATTR(_field, _mode, \
+ ims_pcu_attribute_show, \
+ ims_pcu_attribute_store), \
+ .field_offset = offsetof(struct ims_pcu, _field), \
+ .field_length = sizeof(((struct ims_pcu *)NULL)->_field), \
+}
+
+#define IMS_PCU_RO_ATTR(_field) \
+ IMS_PCU_ATTR(_field, S_IRUGO)
+#define IMS_PCU_RW_ATTR(_field) \
+ IMS_PCU_ATTR(_field, S_IRUGO | S_IWUSR)
+
+static IMS_PCU_RW_ATTR(part_number);
+static IMS_PCU_RW_ATTR(serial_number);
+static IMS_PCU_RW_ATTR(date_of_manufacturing);
+
+static IMS_PCU_RO_ATTR(fw_version);
+static IMS_PCU_RO_ATTR(bl_version);
+static IMS_PCU_RO_ATTR(reset_reason);
+
+static ssize_t ims_pcu_reset_device(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ static const u8 reset_byte = 1;
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ int value;
+ int error;
+
+ error = kstrtoint(buf, 0, &value);
+ if (error)
+ return error;
+
+ if (value != 1)
+ return -EINVAL;
+
+ dev_info(pcu->dev, "Attempting to reset device\n");
+
+ error = ims_pcu_execute_command(pcu, PCU_RESET, &reset_byte, 1);
+ if (error) {
+ dev_info(pcu->dev,
+ "Failed to reset device, error: %d\n",
+ error);
+ return error;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(reset_device, S_IWUSR, NULL, ims_pcu_reset_device);
+
+static ssize_t ims_pcu_update_firmware_store(struct device *dev,
+ struct device_attribute *dattr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ const struct firmware *fw = NULL;
+ int value;
+ int error;
+
+ error = kstrtoint(buf, 0, &value);
+ if (error)
+ return error;
+
+ if (value != 1)
+ return -EINVAL;
+
+ error = mutex_lock_interruptible(&pcu->cmd_mutex);
+ if (error)
+ return error;
+
+ error = request_ihex_firmware(&fw, IMS_PCU_FIRMWARE_NAME, pcu->dev);
+ if (error) {
+ dev_err(pcu->dev, "Failed to request firmware %s, error: %d\n",
+ IMS_PCU_FIRMWARE_NAME, error);
+ goto out;
+ }
+
+ /*
+ * If we are already in bootloader mode we can proceed with
+ * flashing the firmware.
+ *
+ * If we are in application mode, then we need to switch into
+ * bootloader mode, which will cause the device to disconnect
+ * and reconnect as different device.
+ */
+ if (pcu->bootloader_mode)
+ error = ims_pcu_handle_firmware_update(pcu, fw);
+ else
+ error = ims_pcu_switch_to_bootloader(pcu);
+
+ release_firmware(fw);
+
+out:
+ mutex_unlock(&pcu->cmd_mutex);
+ return error ?: count;
+}
+
+static DEVICE_ATTR(update_firmware, S_IWUSR,
+ NULL, ims_pcu_update_firmware_store);
+
+static ssize_t
+ims_pcu_update_firmware_status_show(struct device *dev,
+ struct device_attribute *dattr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", pcu->update_firmware_status);
+}
+
+static DEVICE_ATTR(update_firmware_status, S_IRUGO,
+ ims_pcu_update_firmware_status_show, NULL);
+
+static struct attribute *ims_pcu_attrs[] = {
+ &ims_pcu_attr_part_number.dattr.attr,
+ &ims_pcu_attr_serial_number.dattr.attr,
+ &ims_pcu_attr_date_of_manufacturing.dattr.attr,
+ &ims_pcu_attr_fw_version.dattr.attr,
+ &ims_pcu_attr_bl_version.dattr.attr,
+ &ims_pcu_attr_reset_reason.dattr.attr,
+ &dev_attr_reset_device.attr,
+ &dev_attr_update_firmware.attr,
+ &dev_attr_update_firmware_status.attr,
+ NULL
+};
+
+static umode_t ims_pcu_is_attr_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ umode_t mode = attr->mode;
+
+ if (pcu->bootloader_mode) {
+ if (attr != &dev_attr_update_firmware_status.attr &&
+ attr != &dev_attr_update_firmware.attr &&
+ attr != &dev_attr_reset_device.attr) {
+ mode = 0;
+ }
+ } else {
+ if (attr == &dev_attr_update_firmware_status.attr)
+ mode = 0;
+ }
+
+ return mode;
+}
+
+static struct attribute_group ims_pcu_attr_group = {
+ .is_visible = ims_pcu_is_attr_visible,
+ .attrs = ims_pcu_attrs,
+};
+
+static void ims_pcu_irq(struct urb *urb)
+{
+ struct ims_pcu *pcu = urb->context;
+ int retval, status;
+
+ status = urb->status;
+
+ switch (status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dev_dbg(pcu->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
+ return;
+ default:
+ dev_dbg(pcu->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
+ goto exit;
+ }
+
+ dev_dbg(pcu->dev, "%s: received %d: %*ph\n", __func__,
+ urb->actual_length, urb->actual_length, pcu->urb_in_buf);
+
+ if (urb == pcu->urb_in)
+ ims_pcu_process_data(pcu, urb);
+
+exit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval && retval != -ENODEV)
+ dev_err(pcu->dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
+}
+
+static int ims_pcu_buffers_alloc(struct ims_pcu *pcu)
+{
+ int error;
+
+ pcu->urb_in_buf = usb_alloc_coherent(pcu->udev, pcu->max_in_size,
+ GFP_KERNEL, &pcu->read_dma);
+ if (!pcu->urb_in_buf) {
+ dev_err(pcu->dev,
+ "Failed to allocate memory for read buffer\n");
+ return -ENOMEM;
+ }
+
+ pcu->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pcu->urb_in) {
+ dev_err(pcu->dev, "Failed to allocate input URB\n");
+ error = -ENOMEM;
+ goto err_free_urb_in_buf;
+ }
+
+ pcu->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ pcu->urb_in->transfer_dma = pcu->read_dma;
+
+ usb_fill_bulk_urb(pcu->urb_in, pcu->udev,
+ usb_rcvbulkpipe(pcu->udev,
+ pcu->ep_in->bEndpointAddress),
+ pcu->urb_in_buf, pcu->max_in_size,
+ ims_pcu_irq, pcu);
+
+ /*
+ * We are using usb_bulk_msg() for sending so there is no point
+ * in allocating memory with usb_alloc_coherent().
+ */
+ pcu->urb_out_buf = kmalloc(pcu->max_out_size, GFP_KERNEL);
+ if (!pcu->urb_out_buf) {
+ dev_err(pcu->dev, "Failed to allocate memory for write buffer\n");
+ error = -ENOMEM;
+ goto err_free_in_urb;
+ }
+
+ pcu->urb_ctrl_buf = usb_alloc_coherent(pcu->udev, pcu->max_ctrl_size,
+ GFP_KERNEL, &pcu->ctrl_dma);
+ if (!pcu->urb_ctrl_buf) {
+ dev_err(pcu->dev,
+ "Failed to allocate memory for read buffer\n");
+ goto err_free_urb_out_buf;
+ }
+
+ pcu->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pcu->urb_ctrl) {
+ dev_err(pcu->dev, "Failed to allocate input URB\n");
+ error = -ENOMEM;
+ goto err_free_urb_ctrl_buf;
+ }
+
+ pcu->urb_ctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ pcu->urb_ctrl->transfer_dma = pcu->ctrl_dma;
+
+ usb_fill_int_urb(pcu->urb_ctrl, pcu->udev,
+ usb_rcvintpipe(pcu->udev,
+ pcu->ep_ctrl->bEndpointAddress),
+ pcu->urb_ctrl_buf, pcu->max_ctrl_size,
+ ims_pcu_irq, pcu, pcu->ep_ctrl->bInterval);
+
+ return 0;
+
+err_free_urb_ctrl_buf:
+ usb_free_coherent(pcu->udev, pcu->max_ctrl_size,
+ pcu->urb_ctrl_buf, pcu->ctrl_dma);
+err_free_urb_out_buf:
+ kfree(pcu->urb_out_buf);
+err_free_in_urb:
+ usb_free_urb(pcu->urb_in);
+err_free_urb_in_buf:
+ usb_free_coherent(pcu->udev, pcu->max_in_size,
+ pcu->urb_in_buf, pcu->read_dma);
+ return error;
+}
+
+static void ims_pcu_buffers_free(struct ims_pcu *pcu)
+{
+ usb_kill_urb(pcu->urb_in);
+ usb_free_urb(pcu->urb_in);
+
+ usb_free_coherent(pcu->udev, pcu->max_out_size,
+ pcu->urb_in_buf, pcu->read_dma);
+
+ kfree(pcu->urb_out_buf);
+
+ usb_kill_urb(pcu->urb_ctrl);
+ usb_free_urb(pcu->urb_ctrl);
+
+ usb_free_coherent(pcu->udev, pcu->max_ctrl_size,
+ pcu->urb_ctrl_buf, pcu->ctrl_dma);
+}
+
+static const struct usb_cdc_union_desc *
+ims_pcu_get_cdc_union_desc(struct usb_interface *intf)
+{
+ const void *buf = intf->altsetting->extra;
+ size_t buflen = intf->altsetting->extralen;
+ struct usb_cdc_union_desc *union_desc;
+
+ if (!buf) {
+ dev_err(&intf->dev, "Missing descriptor data\n");
+ return NULL;
+ }
+
+ if (!buflen) {
+ dev_err(&intf->dev, "Zero length descriptor\n");
+ return NULL;
+ }
+
+ while (buflen > 0) {
+ union_desc = (struct usb_cdc_union_desc *)buf;
+
+ if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE &&
+ union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) {
+ dev_dbg(&intf->dev, "Found union header\n");
+ return union_desc;
+ }
+
+ buflen -= union_desc->bLength;
+ buf += union_desc->bLength;
+ }
+
+ dev_err(&intf->dev, "Missing CDC union descriptor\n");
+ return NULL;
+}
+
+static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pcu)
+{
+ const struct usb_cdc_union_desc *union_desc;
+ struct usb_host_interface *alt;
+
+ union_desc = ims_pcu_get_cdc_union_desc(intf);
+ if (!union_desc)
+ return -EINVAL;
+
+ pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
+ union_desc->bMasterInterface0);
+
+ alt = pcu->ctrl_intf->cur_altsetting;
+ pcu->ep_ctrl = &alt->endpoint[0].desc;
+ pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
+
+ pcu->data_intf = usb_ifnum_to_if(pcu->udev,
+ union_desc->bSlaveInterface0);
+
+ alt = pcu->data_intf->cur_altsetting;
+ if (alt->desc.bNumEndpoints != 2) {
+ dev_err(pcu->dev,
+ "Incorrect number of endpoints on data interface (%d)\n",
+ alt->desc.bNumEndpoints);
+ return -EINVAL;
+ }
+
+ pcu->ep_out = &alt->endpoint[0].desc;
+ if (!usb_endpoint_is_bulk_out(pcu->ep_out)) {
+ dev_err(pcu->dev,
+ "First endpoint on data interface is not BULK OUT\n");
+ return -EINVAL;
+ }
+
+ pcu->max_out_size = usb_endpoint_maxp(pcu->ep_out);
+ if (pcu->max_out_size < 8) {
+ dev_err(pcu->dev,
+ "Max OUT packet size is too small (%zd)\n",
+ pcu->max_out_size);
+ return -EINVAL;
+ }
+
+ pcu->ep_in = &alt->endpoint[1].desc;
+ if (!usb_endpoint_is_bulk_in(pcu->ep_in)) {
+ dev_err(pcu->dev,
+ "Second endpoint on data interface is not BULK IN\n");
+ return -EINVAL;
+ }
+
+ pcu->max_in_size = usb_endpoint_maxp(pcu->ep_in);
+ if (pcu->max_in_size < 8) {
+ dev_err(pcu->dev,
+ "Max IN packet size is too small (%zd)\n",
+ pcu->max_in_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ims_pcu_start_io(struct ims_pcu *pcu)
+{
+ int error;
+
+ error = usb_submit_urb(pcu->urb_ctrl, GFP_KERNEL);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to start control IO - usb_submit_urb failed with result: %d\n",
+ error);
+ return -EIO;
+ }
+
+ error = usb_submit_urb(pcu->urb_in, GFP_KERNEL);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to start IO - usb_submit_urb failed with result: %d\n",
+ error);
+ usb_kill_urb(pcu->urb_ctrl);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void ims_pcu_stop_io(struct ims_pcu *pcu)
+{
+ usb_kill_urb(pcu->urb_in);
+ usb_kill_urb(pcu->urb_ctrl);
+}
+
+static int ims_pcu_line_setup(struct ims_pcu *pcu)
+{
+ struct usb_host_interface *interface = pcu->ctrl_intf->cur_altsetting;
+ struct usb_cdc_line_coding *line = (void *)pcu->cmd_buf;
+ int error;
+
+ memset(line, 0, sizeof(*line));
+ line->dwDTERate = cpu_to_le32(57600);
+ line->bDataBits = 8;
+
+ error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0),
+ USB_CDC_REQ_SET_LINE_CODING,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, interface->desc.bInterfaceNumber,
+ line, sizeof(struct usb_cdc_line_coding),
+ 5000);
+ if (error < 0) {
+ dev_err(pcu->dev, "Failed to set line coding, error: %d\n",
+ error);
+ return error;
+ }
+
+ error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0),
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0x03, interface->desc.bInterfaceNumber,
+ NULL, 0, 5000);
+ if (error < 0) {
+ dev_err(pcu->dev, "Failed to set line state, error: %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int ims_pcu_get_device_info(struct ims_pcu *pcu)
+{
+ int error;
+
+ error = ims_pcu_get_info(pcu);
+ if (error)
+ return error;
+
+ error = ims_pcu_execute_query(pcu, GET_FW_VERSION);
+ if (error) {
+ dev_err(pcu->dev,
+ "GET_FW_VERSION command failed, error: %d\n", error);
+ return error;
+ }
+
+ snprintf(pcu->fw_version, sizeof(pcu->fw_version),
+ "%02d%02d%02d%02d.%c%c",
+ pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
+ pcu->cmd_buf[6], pcu->cmd_buf[7]);
+
+ error = ims_pcu_execute_query(pcu, GET_BL_VERSION);
+ if (error) {
+ dev_err(pcu->dev,
+ "GET_BL_VERSION command failed, error: %d\n", error);
+ return error;
+ }
+
+ snprintf(pcu->bl_version, sizeof(pcu->bl_version),
+ "%02d%02d%02d%02d.%c%c",
+ pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
+ pcu->cmd_buf[6], pcu->cmd_buf[7]);
+
+ error = ims_pcu_execute_query(pcu, RESET_REASON);
+ if (error) {
+ dev_err(pcu->dev,
+ "RESET_REASON command failed, error: %d\n", error);
+ return error;
+ }
+
+ snprintf(pcu->reset_reason, sizeof(pcu->reset_reason),
+ "%02x", pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
+
+ dev_dbg(pcu->dev,
+ "P/N: %s, MD: %s, S/N: %s, FW: %s, BL: %s, RR: %s\n",
+ pcu->part_number,
+ pcu->date_of_manufacturing,
+ pcu->serial_number,
+ pcu->fw_version,
+ pcu->bl_version,
+ pcu->reset_reason);
+
+ return 0;
+}
+
+static int ims_pcu_identify_type(struct ims_pcu *pcu, u8 *device_id)
+{
+ int error;
+
+ error = ims_pcu_execute_query(pcu, GET_DEVICE_ID);
+ if (error) {
+ dev_err(pcu->dev,
+ "GET_DEVICE_ID command failed, error: %d\n", error);
+ return error;
+ }
+
+ *device_id = pcu->cmd_buf[IMS_PCU_DATA_OFFSET];
+ dev_dbg(pcu->dev, "Detected device ID: %d\n", *device_id);
+
+ return 0;
+}
+
+static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
+{
+ static atomic_t device_no = ATOMIC_INIT(0);
+
+ const struct ims_pcu_device_info *info;
+ u8 device_id;
+ int error;
+
+ error = ims_pcu_get_device_info(pcu);
+ if (error) {
+ /* Device does not respond to basic queries, hopeless */
+ return error;
+ }
+
+ error = ims_pcu_identify_type(pcu, &device_id);
+ if (error) {
+ dev_err(pcu->dev,
+ "Failed to identify device, error: %d\n", error);
+ /*
+ * Do not signal error, but do not create input nor
+ * backlight devices either, let userspace figure this
+ * out (flash a new firmware?).
+ */
+ return 0;
+ }
+
+ if (device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
+ !ims_pcu_device_info[device_id].keymap) {
+ dev_err(pcu->dev, "Device ID %d is not valid\n", device_id);
+ /* Same as above, punt to userspace */
+ return 0;
+ }
+
+ /* Device appears to be operable, complete initialization */
+ pcu->device_no = atomic_inc_return(&device_no) - 1;
+
+ error = ims_pcu_setup_backlight(pcu);
+ if (error)
+ return error;
+
+ info = &ims_pcu_device_info[device_id];
+ error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
+ if (error)
+ goto err_destroy_backlight;
+
+ if (info->has_gamepad) {
+ error = ims_pcu_setup_gamepad(pcu);
+ if (error)
+ goto err_destroy_buttons;
+ }
+
+ pcu->setup_complete = true;
+
+ return 0;
+
+err_destroy_backlight:
+ ims_pcu_destroy_backlight(pcu);
+err_destroy_buttons:
+ ims_pcu_destroy_buttons(pcu);
+ return error;
+}
+
+static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
+{
+ if (pcu->setup_complete) {
+ pcu->setup_complete = false;
+ mb(); /* make sure flag setting is not reordered */
+
+ if (pcu->gamepad)
+ ims_pcu_destroy_gamepad(pcu);
+ ims_pcu_destroy_buttons(pcu);
+ ims_pcu_destroy_backlight(pcu);
+ }
+}
+
+static int ims_pcu_init_bootloader_mode(struct ims_pcu *pcu)
+{
+ int error;
+
+ error = ims_pcu_execute_bl_command(pcu, QUERY_DEVICE, NULL, 0,
+ IMS_PCU_CMD_RESPONSE_TIMEOUT);
+ if (error) {
+ dev_err(pcu->dev, "Bootloader does not respond, aborting\n");
+ return error;
+ }
+
+ pcu->fw_start_addr =
+ get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 11]);
+ pcu->fw_end_addr =
+ get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 15]);
+
+ dev_info(pcu->dev,
+ "Device is in bootloader mode (addr 0x%08x-0x%08x), requesting firmware\n",
+ pcu->fw_start_addr, pcu->fw_end_addr);
+
+ error = request_firmware_nowait(THIS_MODULE, true,
+ IMS_PCU_FIRMWARE_NAME,
+ pcu->dev, GFP_KERNEL, pcu,
+ ims_pcu_process_async_firmware);
+ if (error) {
+ /* This error is not fatal, let userspace have another chance */
+ complete(&pcu->async_firmware_done);
+ }
+
+ return 0;
+}
+
+static void ims_pcu_destroy_bootloader_mode(struct ims_pcu *pcu)
+{
+ /* Make sure our initial firmware request has completed */
+ wait_for_completion(&pcu->async_firmware_done);
+}
+
+#define IMS_PCU_APPLICATION_MODE 0
+#define IMS_PCU_BOOTLOADER_MODE 1
+
+static struct usb_driver ims_pcu_driver;
+
+static int ims_pcu_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ims_pcu *pcu;
+ int error;
+
+ pcu = kzalloc(sizeof(struct ims_pcu), GFP_KERNEL);
+ if (!pcu)
+ return -ENOMEM;
+
+ pcu->dev = &intf->dev;
+ pcu->udev = udev;
+ pcu->bootloader_mode = id->driver_info == IMS_PCU_BOOTLOADER_MODE;
+ mutex_init(&pcu->cmd_mutex);
+ init_completion(&pcu->cmd_done);
+ init_completion(&pcu->async_firmware_done);
+
+ error = ims_pcu_parse_cdc_data(intf, pcu);
+ if (error)
+ goto err_free_mem;
+
+ error = usb_driver_claim_interface(&ims_pcu_driver,
+ pcu->data_intf, pcu);
+ if (error) {
+ dev_err(&intf->dev,
+ "Unable to claim corresponding data interface: %d\n",
+ error);
+ goto err_free_mem;
+ }
+
+ usb_set_intfdata(pcu->ctrl_intf, pcu);
+ usb_set_intfdata(pcu->data_intf, pcu);
+
+ error = ims_pcu_buffers_alloc(pcu);
+ if (error)
+ goto err_unclaim_intf;
+
+ error = ims_pcu_start_io(pcu);
+ if (error)
+ goto err_free_buffers;
+
+ error = ims_pcu_line_setup(pcu);
+ if (error)
+ goto err_stop_io;
+
+ error = sysfs_create_group(&intf->dev.kobj, &ims_pcu_attr_group);
+ if (error)
+ goto err_stop_io;
+
+ error = pcu->bootloader_mode ?
+ ims_pcu_init_bootloader_mode(pcu) :
+ ims_pcu_init_application_mode(pcu);
+ if (error)
+ goto err_remove_sysfs;
+
+ return 0;
+
+err_remove_sysfs:
+ sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
+err_stop_io:
+ ims_pcu_stop_io(pcu);
+err_free_buffers:
+ ims_pcu_buffers_free(pcu);
+err_unclaim_intf:
+ usb_driver_release_interface(&ims_pcu_driver, pcu->data_intf);
+err_free_mem:
+ kfree(pcu);
+ return error;
+}
+
+static void ims_pcu_disconnect(struct usb_interface *intf)
+{
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+
+ usb_set_intfdata(intf, NULL);
+
+ /*
+ * See if we are dealing with control or data interface. The cleanup
+ * happens when we unbind primary (control) interface.
+ */
+ if (alt->desc.bInterfaceClass != USB_CLASS_COMM)
+ return;
+
+ sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
+
+ ims_pcu_stop_io(pcu);
+
+ if (pcu->bootloader_mode)
+ ims_pcu_destroy_bootloader_mode(pcu);
+ else
+ ims_pcu_destroy_application_mode(pcu);
+
+ ims_pcu_buffers_free(pcu);
+ kfree(pcu);
+}
+
+#ifdef CONFIG_PM
+static int ims_pcu_suspend(struct usb_interface *intf,
+ pm_message_t message)
+{
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+
+ if (alt->desc.bInterfaceClass == USB_CLASS_COMM)
+ ims_pcu_stop_io(pcu);
+
+ return 0;
+}
+
+static int ims_pcu_resume(struct usb_interface *intf)
+{
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int retval = 0;
+
+ if (alt->desc.bInterfaceClass == USB_CLASS_COMM) {
+ retval = ims_pcu_start_io(pcu);
+ if (retval == 0)
+ retval = ims_pcu_line_setup(pcu);
+ }
+
+ return retval;
+}
+#endif
+
+static const struct usb_device_id ims_pcu_id_table[] = {
+ {
+ USB_DEVICE_AND_INTERFACE_INFO(0x04d8, 0x0082,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_V25TER),
+ .driver_info = IMS_PCU_APPLICATION_MODE,
+ },
+ {
+ USB_DEVICE_AND_INTERFACE_INFO(0x04d8, 0x0083,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ACM,
+ USB_CDC_ACM_PROTO_AT_V25TER),
+ .driver_info = IMS_PCU_BOOTLOADER_MODE,
+ },
+ { }
+};
+
+static struct usb_driver ims_pcu_driver = {
+ .name = "ims_pcu",
+ .id_table = ims_pcu_id_table,
+ .probe = ims_pcu_probe,
+ .disconnect = ims_pcu_disconnect,
+#ifdef CONFIG_PM
+ .suspend = ims_pcu_suspend,
+ .resume = ims_pcu_resume,
+ .reset_resume = ims_pcu_resume,
+#endif
+};
+
+module_usb_driver(ims_pcu_driver);
+
+MODULE_DESCRIPTION("IMS Passenger Control Unit driver");
+MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 480557f14f23..f3309696d053 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -123,9 +123,9 @@ static void mma8450_poll(struct input_polled_dev *dev)
if (ret < 0)
return;
- x = ((buf[1] << 4) & 0xff0) | (buf[0] & 0xf);
- y = ((buf[3] << 4) & 0xff0) | (buf[2] & 0xf);
- z = ((buf[5] << 4) & 0xff0) | (buf[4] & 0xf);
+ x = ((int)(s8)buf[1] << 4) | (buf[0] & 0xf);
+ y = ((int)(s8)buf[3] << 4) | (buf[2] & 0xf);
+ z = ((int)(s8)buf[5] << 4) | (buf[4] & 0xf);
input_report_abs(dev->input, ABS_X, x);
input_report_abs(dev->input, ABS_Y, y);
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index 27c2bc8aa890..b9a05fda03e4 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -114,18 +114,8 @@ static struct platform_driver twl4030_pwrbutton_driver = {
},
};
-static int __init twl4030_pwrbutton_init(void)
-{
- return platform_driver_probe(&twl4030_pwrbutton_driver,
+module_platform_driver_probe(twl4030_pwrbutton_driver,
twl4030_pwrbutton_probe);
-}
-module_init(twl4030_pwrbutton_init);
-
-static void __exit twl4030_pwrbutton_exit(void)
-{
- platform_driver_unregister(&twl4030_pwrbutton_driver);
-}
-module_exit(twl4030_pwrbutton_exit);
MODULE_ALIAS("platform:twl4030_pwrbutton");
MODULE_DESCRIPTION("Triton2 Power Button");
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0238e0e14335..7c5d72a6a26a 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1013,8 +1013,8 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -EIO;
- psmouse_dbg(psmouse, "%2.2X report: %2.2x %2.2x %2.2x\n",
- repeated_command, param[0], param[1], param[2]);
+ psmouse_dbg(psmouse, "%2.2X report: %3ph\n",
+ repeated_command, param);
return 0;
}
@@ -1274,9 +1274,7 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
psmouse_warn(psmouse, "trackstick E7 report failed\n");
ret = -ENODEV;
} else {
- psmouse_dbg(psmouse,
- "trackstick E7 report: %2.2x %2.2x %2.2x\n",
- param[0], param[1], param[2]);
+ psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param);
/*
* Not sure what this does, but it is absolutely
@@ -1323,6 +1321,7 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
if (reg_val == -EIO)
goto error;
+
if (reg_val == 0 &&
alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
goto error;
@@ -1676,8 +1675,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
}
psmouse_info(psmouse,
- "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n",
- e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]);
+ "Unknown ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
return -EINVAL;
}
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 5fa99341a39d..b55d5af217a7 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -146,18 +146,6 @@ static struct platform_driver amimouse_driver = {
},
};
-static int __init amimouse_init(void)
-{
- return platform_driver_probe(&amimouse_driver, amimouse_probe);
-}
-
-module_init(amimouse_init);
-
-static void __exit amimouse_exit(void)
-{
- platform_driver_unregister(&amimouse_driver);
-}
-
-module_exit(amimouse_exit);
+module_platform_driver_probe(amimouse_driver, amimouse_probe);
MODULE_ALIAS("platform:amiga-mouse");
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index f3102494237d..ca843b6cf6bd 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -20,9 +20,34 @@
#include "trackpoint.h"
/*
+ * Power-on Reset: Resets all trackpoint parameters, including RAM values,
+ * to defaults.
+ * Returns zero on success, non-zero on failure.
+ */
+static int trackpoint_power_on_reset(struct ps2dev *ps2dev)
+{
+ unsigned char results[2];
+ int tries = 0;
+
+ /* Issue POR command, and repeat up to once if 0xFC00 received */
+ do {
+ if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
+ ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR)))
+ return -1;
+ } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2);
+
+ /* Check for success response -- 0xAA00 */
+ if (results[0] != 0xAA || results[1] != 0x00)
+ return -1;
+
+ return 0;
+}
+
+/*
* Device IO: read, write and toggle bit
*/
-static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned char *results)
+static int trackpoint_read(struct ps2dev *ps2dev,
+ unsigned char loc, unsigned char *results)
{
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) {
@@ -32,7 +57,8 @@ static int trackpoint_read(struct ps2dev *ps2dev, unsigned char loc, unsigned ch
return 0;
}
-static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned char val)
+static int trackpoint_write(struct ps2dev *ps2dev,
+ unsigned char loc, unsigned char val)
{
if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) ||
ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) ||
@@ -44,7 +70,8 @@ static int trackpoint_write(struct ps2dev *ps2dev, unsigned char loc, unsigned c
return 0;
}
-static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsigned char mask)
+static int trackpoint_toggle_bit(struct ps2dev *ps2dev,
+ unsigned char loc, unsigned char mask)
{
/* Bad things will happen if the loc param isn't in this range */
if (loc < 0x20 || loc >= 0x2F)
@@ -60,6 +87,18 @@ static int trackpoint_toggle_bit(struct ps2dev *ps2dev, unsigned char loc, unsig
return 0;
}
+static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc,
+ unsigned char mask, unsigned char value)
+{
+ int retval = 0;
+ unsigned char data;
+
+ trackpoint_read(ps2dev, loc, &data);
+ if (((data & mask) == mask) != !!value)
+ retval = trackpoint_toggle_bit(ps2dev, loc, mask);
+
+ return retval;
+}
/*
* Trackpoint-specific attributes
@@ -69,6 +108,7 @@ struct trackpoint_attr_data {
unsigned char command;
unsigned char mask;
unsigned char inverted;
+ unsigned char power_on_default;
};
static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf)
@@ -102,10 +142,11 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
return count;
}
-#define TRACKPOINT_INT_ATTR(_name, _command) \
+#define TRACKPOINT_INT_ATTR(_name, _command, _default) \
static struct trackpoint_attr_data trackpoint_attr_##_name = { \
.field_offset = offsetof(struct trackpoint_data, _name), \
.command = _command, \
+ .power_on_default = _default, \
}; \
PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
&trackpoint_attr_##_name, \
@@ -139,31 +180,60 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
}
-#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv) \
- static struct trackpoint_attr_data trackpoint_attr_##_name = { \
- .field_offset = offsetof(struct trackpoint_data, _name), \
- .command = _command, \
- .mask = _mask, \
- .inverted = _inv, \
- }; \
- PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
- &trackpoint_attr_##_name, \
- trackpoint_show_int_attr, trackpoint_set_bit_attr)
-
-TRACKPOINT_INT_ATTR(sensitivity, TP_SENS);
-TRACKPOINT_INT_ATTR(speed, TP_SPEED);
-TRACKPOINT_INT_ATTR(inertia, TP_INERTIA);
-TRACKPOINT_INT_ATTR(reach, TP_REACH);
-TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS);
-TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG);
-TRACKPOINT_INT_ATTR(thresh, TP_THRESH);
-TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH);
-TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME);
-TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV);
-
-TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0);
-TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0);
-TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1);
+#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \
+static struct trackpoint_attr_data trackpoint_attr_##_name = { \
+ .field_offset = offsetof(struct trackpoint_data, \
+ _name), \
+ .command = _command, \
+ .mask = _mask, \
+ .inverted = _inv, \
+ .power_on_default = _default, \
+ }; \
+PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \
+ &trackpoint_attr_##_name, \
+ trackpoint_show_int_attr, trackpoint_set_bit_attr)
+
+#define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name) \
+do { \
+ struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \
+ \
+ trackpoint_update_bit(&_psmouse->ps2dev, \
+ _attr->command, _attr->mask, _tp->_name); \
+} while (0)
+
+#define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \
+do { \
+ if (!_power_on || \
+ _tp->_name != trackpoint_attr_##_name.power_on_default) { \
+ if (!trackpoint_attr_##_name.mask) \
+ trackpoint_write(&_psmouse->ps2dev, \
+ trackpoint_attr_##_name.command, \
+ _tp->_name); \
+ else \
+ TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name); \
+ } \
+} while (0)
+
+#define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \
+ (_tp->_name = trackpoint_attr_##_name.power_on_default)
+
+TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS);
+TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED);
+TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA);
+TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH);
+TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS);
+TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG);
+TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH);
+TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH);
+TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME);
+TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV);
+
+TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0,
+ TP_DEF_PTSON);
+TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0,
+ TP_DEF_SKIPBACK);
+TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1,
+ TP_DEF_EXT_DEV);
static struct attribute *trackpoint_attrs[] = {
&psmouse_attr_sensitivity.dattr.attr,
@@ -202,73 +272,72 @@ static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *fir
return 0;
}
-static int trackpoint_sync(struct psmouse *psmouse)
+/*
+ * Write parameters to trackpad.
+ * in_power_on_state: Set to true if TP is in default / power-on state (ex. if
+ * power-on reset was run). If so, values will only be
+ * written to TP if they differ from power-on default.
+ */
+static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state)
{
struct trackpoint_data *tp = psmouse->private;
- unsigned char toggle;
-
- /* Disable features that may make device unusable with this driver */
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
- if (toggle & TP_MASK_TWOHAND)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, TP_MASK_TWOHAND);
-
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, &toggle);
- if (toggle & TP_MASK_SOURCE_TAG)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, TP_MASK_SOURCE_TAG);
-
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_MB, &toggle);
- if (toggle & TP_MASK_MB)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_MB, TP_MASK_MB);
-
- /* Push the config to the device */
- trackpoint_write(&psmouse->ps2dev, TP_SENS, tp->sensitivity);
- trackpoint_write(&psmouse->ps2dev, TP_INERTIA, tp->inertia);
- trackpoint_write(&psmouse->ps2dev, TP_SPEED, tp->speed);
-
- trackpoint_write(&psmouse->ps2dev, TP_REACH, tp->reach);
- trackpoint_write(&psmouse->ps2dev, TP_DRAGHYS, tp->draghys);
- trackpoint_write(&psmouse->ps2dev, TP_MINDRAG, tp->mindrag);
-
- trackpoint_write(&psmouse->ps2dev, TP_THRESH, tp->thresh);
- trackpoint_write(&psmouse->ps2dev, TP_UP_THRESH, tp->upthresh);
- trackpoint_write(&psmouse->ps2dev, TP_Z_TIME, tp->ztime);
- trackpoint_write(&psmouse->ps2dev, TP_JENKS_CURV, tp->jenks);
+ if (!in_power_on_state) {
+ /*
+ * Disable features that may make device unusable
+ * with this driver.
+ */
+ trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND,
+ TP_MASK_TWOHAND, TP_DEF_TWOHAND);
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_PTSON, &toggle);
- if (((toggle & TP_MASK_PTSON) == TP_MASK_PTSON) != tp->press_to_select)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_PTSON, TP_MASK_PTSON);
+ trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG,
+ TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG);
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, &toggle);
- if (((toggle & TP_MASK_SKIPBACK) == TP_MASK_SKIPBACK) != tp->skipback)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK);
+ trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB,
+ TP_MASK_MB, TP_DEF_MB);
+ }
- trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, &toggle);
- if (((toggle & TP_MASK_EXT_DEV) == TP_MASK_EXT_DEV) != tp->ext_dev)
- trackpoint_toggle_bit(&psmouse->ps2dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV);
+ /*
+ * These properties can be changed in this driver. Only
+ * configure them if the values are non-default or if the TP is in
+ * an unknown state.
+ */
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks);
+
+ /* toggles */
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback);
+ TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev);
return 0;
}
static void trackpoint_defaults(struct trackpoint_data *tp)
{
- tp->press_to_select = TP_DEF_PTSON;
- tp->sensitivity = TP_DEF_SENS;
- tp->speed = TP_DEF_SPEED;
- tp->reach = TP_DEF_REACH;
-
- tp->draghys = TP_DEF_DRAGHYS;
- tp->mindrag = TP_DEF_MINDRAG;
-
- tp->thresh = TP_DEF_THRESH;
- tp->upthresh = TP_DEF_UP_THRESH;
-
- tp->ztime = TP_DEF_Z_TIME;
- tp->jenks = TP_DEF_JENKS_CURV;
-
- tp->inertia = TP_DEF_INERTIA;
- tp->skipback = TP_DEF_SKIPBACK;
- tp->ext_dev = TP_DEF_EXT_DEV;
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia);
+
+ /* toggles */
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback);
+ TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev);
}
static void trackpoint_disconnect(struct psmouse *psmouse)
@@ -281,10 +350,13 @@ static void trackpoint_disconnect(struct psmouse *psmouse)
static int trackpoint_reconnect(struct psmouse *psmouse)
{
+ int reset_fail;
+
if (trackpoint_start_protocol(psmouse, NULL))
return -1;
- if (trackpoint_sync(psmouse))
+ reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev);
+ if (trackpoint_sync(psmouse, !reset_fail))
return -1;
return 0;
@@ -322,7 +394,12 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties)
__set_bit(BTN_MIDDLE, psmouse->dev->keybit);
trackpoint_defaults(psmouse->private);
- trackpoint_sync(psmouse);
+
+ error = trackpoint_power_on_reset(&psmouse->ps2dev);
+
+ /* Write defaults to TP only if reset fails. */
+ if (error)
+ trackpoint_sync(psmouse, false);
error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group);
if (error) {
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index e558a7096618..ecd0547964a5 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -126,6 +126,8 @@
#define TP_DEF_PTSON 0x00
#define TP_DEF_SKIPBACK 0x00
#define TP_DEF_EXT_DEV 0x00 /* 0 means enabled */
+#define TP_DEF_TWOHAND 0x00
+#define TP_DEF_SOURCE_TAG 0x00
#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd))
@@ -136,9 +138,9 @@ struct trackpoint_data
unsigned char thresh, upthresh;
unsigned char ztime, jenks;
+ /* toggles */
unsigned char press_to_select;
unsigned char skipback;
-
unsigned char ext_dev;
};
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 3ec5ef2dd443..aebfe3ecb945 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -245,4 +245,14 @@ config SERIO_ARC_PS2
To compile this driver as a module, choose M here; the module
will be called arc_ps2.
+config SERIO_APBPS2
+ tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller"
+ depends on OF
+ help
+ Say Y here if you want support for GRLIB APBPS2 peripherals used
+ to connect to PS/2 keyboard and/or mouse.
+
+ To compile this driver as a module, choose M here: the module will
+ be called apbps2.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 4b0c8f84f1c1..8edb36c2cdb4 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o
obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
+obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c
new file mode 100644
index 000000000000..17e01a807ddc
--- /dev/null
+++ b/drivers/input/serio/apbps2.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2013 Aeroflex Gaisler
+ *
+ * This driver supports the APBPS2 PS/2 core available in the GRLIB
+ * VHDL IP core library.
+ *
+ * Full documentation of the APBPS2 core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * See "Documentation/devicetree/bindings/input/ps2keyb-mouse-apbps2.txt" for
+ * information on open firmware properties.
+ *
+ * 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.
+ *
+ * Contributors: Daniel Hellstrom <daniel@gaisler.com>
+ */
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+struct apbps2_regs {
+ u32 __iomem data; /* 0x00 */
+ u32 __iomem status; /* 0x04 */
+ u32 __iomem ctrl; /* 0x08 */
+ u32 __iomem reload; /* 0x0c */
+};
+
+#define APBPS2_STATUS_DR (1<<0)
+#define APBPS2_STATUS_PE (1<<1)
+#define APBPS2_STATUS_FE (1<<2)
+#define APBPS2_STATUS_KI (1<<3)
+#define APBPS2_STATUS_RF (1<<4)
+#define APBPS2_STATUS_TF (1<<5)
+#define APBPS2_STATUS_TCNT (0x1f<<22)
+#define APBPS2_STATUS_RCNT (0x1f<<27)
+
+#define APBPS2_CTRL_RE (1<<0)
+#define APBPS2_CTRL_TE (1<<1)
+#define APBPS2_CTRL_RI (1<<2)
+#define APBPS2_CTRL_TI (1<<3)
+
+struct apbps2_priv {
+ struct serio *io;
+ struct apbps2_regs *regs;
+};
+
+static int apbps2_idx;
+
+static irqreturn_t apbps2_isr(int irq, void *dev_id)
+{
+ struct apbps2_priv *priv = dev_id;
+ unsigned long status, data, rxflags;
+ irqreturn_t ret = IRQ_NONE;
+
+ while ((status = ioread32be(&priv->regs->status)) & APBPS2_STATUS_DR) {
+ data = ioread32be(&priv->regs->data);
+ rxflags = (status & APBPS2_STATUS_PE) ? SERIO_PARITY : 0;
+ rxflags |= (status & APBPS2_STATUS_FE) ? SERIO_FRAME : 0;
+
+ /* clear error bits? */
+ if (rxflags)
+ iowrite32be(0, &priv->regs->status);
+
+ serio_interrupt(priv->io, data, rxflags);
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int apbps2_write(struct serio *io, unsigned char val)
+{
+ struct apbps2_priv *priv = io->port_data;
+ unsigned int tleft = 10000; /* timeout in 100ms */
+
+ /* delay until PS/2 controller has room for more chars */
+ while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) && tleft--)
+ udelay(10);
+
+ if ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) == 0) {
+ iowrite32be(val, &priv->regs->data);
+
+ iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI | APBPS2_CTRL_TE,
+ &priv->regs->ctrl);
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int apbps2_open(struct serio *io)
+{
+ struct apbps2_priv *priv = io->port_data;
+ int limit;
+ unsigned long tmp;
+
+ /* clear error flags */
+ iowrite32be(0, &priv->regs->status);
+
+ /* Clear old data if available (unlikely) */
+ limit = 1024;
+ while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_DR) && --limit)
+ tmp = ioread32be(&priv->regs->data);
+
+ /* Enable reciever and it's interrupt */
+ iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI, &priv->regs->ctrl);
+
+ return 0;
+}
+
+static void apbps2_close(struct serio *io)
+{
+ struct apbps2_priv *priv = io->port_data;
+
+ /* stop interrupts at PS/2 HW level */
+ iowrite32be(0, &priv->regs->ctrl);
+}
+
+/* Initialize one APBPS2 PS/2 core */
+static int apbps2_of_probe(struct platform_device *ofdev)
+{
+ struct apbps2_priv *priv;
+ int irq, err;
+ u32 freq_hz;
+ struct resource *res;
+
+ priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&ofdev->dev, "memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Find Device Address */
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ priv->regs = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ /* Reset hardware, disable interrupt */
+ iowrite32be(0, &priv->regs->ctrl);
+
+ /* IRQ */
+ irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ err = devm_request_irq(&ofdev->dev, irq, apbps2_isr,
+ IRQF_SHARED, "apbps2", priv);
+ if (err) {
+ dev_err(&ofdev->dev, "request IRQ%d failed\n", irq);
+ return err;
+ }
+
+ /* Get core frequency */
+ if (of_property_read_u32(ofdev->dev.of_node, "freq", &freq_hz)) {
+ dev_err(&ofdev->dev, "unable to get core frequency\n");
+ return -EINVAL;
+ }
+
+ /* Set reload register to core freq in kHz/10 */
+ iowrite32be(freq_hz / 10000, &priv->regs->reload);
+
+ priv->io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!priv->io)
+ return -ENOMEM;
+
+ priv->io->id.type = SERIO_8042;
+ priv->io->open = apbps2_open;
+ priv->io->close = apbps2_close;
+ priv->io->write = apbps2_write;
+ priv->io->port_data = priv;
+ strlcpy(priv->io->name, "APBPS2 PS/2", sizeof(priv->io->name));
+ snprintf(priv->io->phys, sizeof(priv->io->phys),
+ "apbps2_%d", apbps2_idx++);
+
+ dev_info(&ofdev->dev, "irq = %d, base = 0x%p\n", irq, priv->regs);
+
+ serio_register_port(priv->io);
+
+ platform_set_drvdata(ofdev, priv);
+
+ return 0;
+}
+
+static int apbps2_of_remove(struct platform_device *of_dev)
+{
+ struct apbps2_priv *priv = platform_get_drvdata(of_dev);
+
+ serio_unregister_port(priv->io);
+
+ return 0;
+}
+
+static struct of_device_id apbps2_of_match[] = {
+ { .name = "GAISLER_APBPS2", },
+ { .name = "01_060", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, apbps2_of_match);
+
+static struct platform_driver apbps2_of_driver = {
+ .driver = {
+ .name = "grlib-apbps2",
+ .owner = THIS_MODULE,
+ .of_match_table = apbps2_of_match,
+ },
+ .probe = apbps2_of_probe,
+ .remove = apbps2_of_remove,
+};
+
+module_platform_driver(apbps2_of_driver);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("GRLIB APBPS2 PS/2 serial I/O");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index c52e3e589f72..3fb7727c8ea5 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -259,10 +260,19 @@ static int arc_ps2_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id arc_ps2_match[] = {
+ { .compatible = "snps,arc_ps2" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, arc_ps2_match);
+#endif
+
static struct platform_driver arc_ps2_driver = {
.driver = {
- .name = "arc_ps2",
- .owner = THIS_MODULE,
+ .name = "arc_ps2",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(arc_ps2_match),
},
.probe = arc_ps2_probe,
.remove = arc_ps2_remove,
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
index 36e799c31f5e..190ce35af7df 100644
--- a/drivers/input/serio/at32psif.c
+++ b/drivers/input/serio/at32psif.c
@@ -359,18 +359,7 @@ static struct platform_driver psif_driver = {
},
};
-static int __init psif_init(void)
-{
- return platform_driver_probe(&psif_driver, psif_probe);
-}
-
-static void __exit psif_exit(void)
-{
- platform_driver_unregister(&psif_driver);
-}
-
-module_init(psif_init);
-module_exit(psif_exit);
+module_platform_driver_probe(psif_driver, psif_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver");
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 70fe542839fb..436a3433f8e5 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -193,15 +193,4 @@ static struct platform_driver q40kbd_driver = {
.remove = q40kbd_remove,
};
-static int __init q40kbd_init(void)
-{
- return platform_driver_probe(&q40kbd_driver, q40kbd_probe);
-}
-
-static void __exit q40kbd_exit(void)
-{
- platform_driver_unregister(&q40kbd_driver);
-}
-
-module_init(q40kbd_init);
-module_exit(q40kbd_exit);
+module_platform_driver_probe(q40kbd_driver, q40kbd_probe);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 1daa97913b7d..0bfd8cf25200 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -359,7 +359,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x802: /* Intuos4 General Pen */
case 0x804: /* Intuos4 Marker Pen */
case 0x40802: /* Intuos4 Classic Pen */
- case 0x18803: /* DTH2242 Grip Pen */
+ case 0x18802: /* DTH2242 Grip Pen */
case 0x022:
wacom->tool[idx] = BTN_TOOL_PEN;
break;
@@ -1912,7 +1912,7 @@ static const struct wacom_features wacom_features_0xBB =
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047,
63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xBC =
- { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047,
+ { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40640, 25400, 2047,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x26 =
{ "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047,
@@ -2144,7 +2144,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x44) },
{ USB_DEVICE_WACOM(0x45) },
{ USB_DEVICE_WACOM(0x59) },
- { USB_DEVICE_WACOM(0x5D) },
+ { USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0xB0) },
{ USB_DEVICE_WACOM(0xB1) },
{ USB_DEVICE_WACOM(0xB2) },
@@ -2209,7 +2209,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
{ USB_DEVICE_WACOM(0xF8) },
- { USB_DEVICE_WACOM(0xF6) },
+ { USB_DEVICE_DETAILED(0xF6, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0xFA) },
{ USB_DEVICE_LENOVO(0x6004) },
{ }
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 23fa829b869d..f3a174a83c82 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -273,7 +273,7 @@ static int ad7877_write(struct spi_device *spi, u16 reg, u16 val)
static int ad7877_read_adc(struct spi_device *spi, unsigned command)
{
- struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+ struct ad7877 *ts = spi_get_drvdata(spi);
struct ser_req *req;
int status;
int sample;
@@ -720,7 +720,7 @@ static int ad7877_probe(struct spi_device *spi)
goto err_free_mem;
}
- dev_set_drvdata(&spi->dev, ts);
+ spi_set_drvdata(spi, ts);
ts->spi = spi;
ts->input = input_dev;
@@ -806,13 +806,13 @@ err_free_irq:
err_free_mem:
input_free_device(input_dev);
kfree(ts);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
return err;
}
static int ad7877_remove(struct spi_device *spi)
{
- struct ad7877 *ts = dev_get_drvdata(&spi->dev);
+ struct ad7877 *ts = spi_get_drvdata(spi);
sysfs_remove_group(&spi->dev.kobj, &ad7877_attr_group);
@@ -823,7 +823,7 @@ static int ad7877_remove(struct spi_device *spi)
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
return 0;
}
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 434c3df250ca..84ccf140c1bb 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1245,7 +1245,7 @@ static int ads7846_probe(struct spi_device *spi)
goto err_free_mem;
}
- dev_set_drvdata(&spi->dev, ts);
+ spi_set_drvdata(spi, ts);
ts->packet = packet;
ts->spi = spi;
@@ -1397,7 +1397,7 @@ static int ads7846_probe(struct spi_device *spi)
static int ads7846_remove(struct spi_device *spi)
{
- struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+ struct ads7846 *ts = spi_get_drvdata(spi);
device_init_wakeup(&spi->dev, false);
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
index c5c2dbb93869..2c1e46b7e45b 100644
--- a/drivers/input/touchscreen/atmel-wm97xx.c
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -432,17 +432,7 @@ static struct platform_driver atmel_wm97xx_driver = {
},
};
-static int __init atmel_wm97xx_init(void)
-{
- return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
-}
-module_init(atmel_wm97xx_init);
-
-static void __exit atmel_wm97xx_exit(void)
-{
- platform_driver_unregister(&atmel_wm97xx_driver);
-}
-module_exit(atmel_wm97xx_exit);
+module_platform_driver_probe(atmel_wm97xx_driver, atmel_wm97xx_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index c6e19a96348e..d3f9f6b0f9b7 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -31,6 +31,8 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/input/auo-pixcir-ts.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
/*
* Coordinate calculation:
@@ -111,6 +113,7 @@
struct auo_pixcir_ts {
struct i2c_client *client;
struct input_dev *input;
+ const struct auo_pixcir_ts_platdata *pdata;
char phys[32];
/* special handling for touch_indicate interupt mode */
@@ -132,7 +135,7 @@ static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
struct auo_point_t *point)
{
struct i2c_client *client = ts->client;
- const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+ const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
uint8_t raw_coord[8];
uint8_t raw_area[4];
int i, ret;
@@ -178,8 +181,7 @@ static int auo_pixcir_collect_data(struct auo_pixcir_ts *ts,
static irqreturn_t auo_pixcir_interrupt(int irq, void *dev_id)
{
struct auo_pixcir_ts *ts = dev_id;
- struct i2c_client *client = ts->client;
- const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+ const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
struct auo_point_t point[AUO_PIXCIR_REPORT_POINTS];
int i;
int ret;
@@ -290,7 +292,7 @@ static int auo_pixcir_int_config(struct auo_pixcir_ts *ts,
int int_setting)
{
struct i2c_client *client = ts->client;
- struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+ const struct auo_pixcir_ts_platdata *pdata = ts->pdata;
int ret;
ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_INT_SETTING);
@@ -479,53 +481,105 @@ unlock:
}
#endif
-static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, auo_pixcir_suspend,
- auo_pixcir_resume);
+static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
+ auo_pixcir_suspend, auo_pixcir_resume);
+
+#ifdef CONFIG_OF
+static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev)
+{
+ struct auo_pixcir_ts_platdata *pdata;
+ struct device_node *np = dev->of_node;
+
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "failed to allocate platform data\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pdata->gpio_int = of_get_gpio(np, 0);
+ if (!gpio_is_valid(pdata->gpio_int)) {
+ dev_err(dev, "failed to get interrupt gpio\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata->gpio_rst = of_get_gpio(np, 1);
+ if (!gpio_is_valid(pdata->gpio_rst)) {
+ dev_err(dev, "failed to get reset gpio\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
+ dev_err(dev, "failed to get x-size property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
+ dev_err(dev, "failed to get y-size property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* default to asserting the interrupt when the screen is touched */
+ pdata->int_setting = AUO_PIXCIR_INT_TOUCH_IND;
+
+ return pdata;
+}
+#else
+static struct auo_pixcir_ts_platdata *auo_pixcir_parse_dt(struct device *dev)
+{
+ return ERR_PTR(-EINVAL);
+}
+#endif
+
+static void auo_pixcir_reset(void *data)
+{
+ struct auo_pixcir_ts *ts = data;
+
+ gpio_set_value(ts->pdata->gpio_rst, 0);
+}
static int auo_pixcir_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
- const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+ const struct auo_pixcir_ts_platdata *pdata;
struct auo_pixcir_ts *ts;
struct input_dev *input_dev;
- int ret;
-
- if (!pdata)
- return -EINVAL;
+ int version;
+ int error;
+
+ pdata = dev_get_platdata(&client->dev);
+ if (!pdata) {
+ pdata = auo_pixcir_parse_dt(&client->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ }
- ts = kzalloc(sizeof(struct auo_pixcir_ts), GFP_KERNEL);
+ ts = devm_kzalloc(&client->dev,
+ sizeof(struct auo_pixcir_ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
- ret = gpio_request(pdata->gpio_int, "auo_pixcir_ts_int");
- if (ret) {
- dev_err(&client->dev, "request of gpio %d failed, %d\n",
- pdata->gpio_int, ret);
- goto err_gpio_int;
+ input_dev = devm_input_allocate_device(&client->dev);
+ if (!input_dev) {
+ dev_err(&client->dev, "could not allocate input device\n");
+ return -ENOMEM;
}
- if (pdata->init_hw)
- pdata->init_hw(client);
-
+ ts->pdata = pdata;
ts->client = client;
+ ts->input = input_dev;
ts->touch_ind_mode = 0;
+ ts->stopped = true;
init_waitqueue_head(&ts->wait);
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
- input_dev = input_allocate_device();
- if (!input_dev) {
- dev_err(&client->dev, "could not allocate input device\n");
- goto err_input_alloc;
- }
-
- ts->input = input_dev;
-
input_dev->name = "AUO-Pixcir touchscreen";
input_dev->phys = ts->phys;
input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
input_dev->open = auo_pixcir_input_open;
input_dev->close = auo_pixcir_input_close;
@@ -550,70 +604,70 @@ static int auo_pixcir_probe(struct i2c_client *client,
AUO_PIXCIR_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
- ret = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
- if (ret < 0)
- goto err_fw_vers;
- dev_info(&client->dev, "firmware version 0x%X\n", ret);
-
- ret = auo_pixcir_int_config(ts, pdata->int_setting);
- if (ret)
- goto err_fw_vers;
-
input_set_drvdata(ts->input, ts);
- ts->stopped = true;
- ret = request_threaded_irq(client->irq, NULL, auo_pixcir_interrupt,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- input_dev->name, ts);
- if (ret) {
- dev_err(&client->dev, "irq %d requested failed\n", client->irq);
- goto err_fw_vers;
+ error = devm_gpio_request_one(&client->dev, pdata->gpio_int,
+ GPIOF_DIR_IN, "auo_pixcir_ts_int");
+ if (error) {
+ dev_err(&client->dev, "request of gpio %d failed, %d\n",
+ pdata->gpio_int, error);
+ return error;
}
- /* stop device and put it into deep sleep until it is opened */
- ret = auo_pixcir_stop(ts);
- if (ret < 0)
- goto err_input_register;
-
- ret = input_register_device(input_dev);
- if (ret) {
- dev_err(&client->dev, "could not register input device\n");
- goto err_input_register;
+ error = devm_gpio_request_one(&client->dev, pdata->gpio_rst,
+ GPIOF_DIR_OUT | GPIOF_INIT_HIGH,
+ "auo_pixcir_ts_rst");
+ if (error) {
+ dev_err(&client->dev, "request of gpio %d failed, %d\n",
+ pdata->gpio_rst, error);
+ return error;
}
- i2c_set_clientdata(client, ts);
-
- return 0;
+ error = devm_add_action(&client->dev, auo_pixcir_reset, ts);
+ if (error) {
+ auo_pixcir_reset(ts);
+ dev_err(&client->dev, "failed to register reset action, %d\n",
+ error);
+ return error;
+ }
-err_input_register:
- free_irq(client->irq, ts);
-err_fw_vers:
- input_free_device(input_dev);
-err_input_alloc:
- if (pdata->exit_hw)
- pdata->exit_hw(client);
- gpio_free(pdata->gpio_int);
-err_gpio_int:
- kfree(ts);
+ msleep(200);
- return ret;
-}
-
-static int auo_pixcir_remove(struct i2c_client *client)
-{
- struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
- const struct auo_pixcir_ts_platdata *pdata = client->dev.platform_data;
+ version = i2c_smbus_read_byte_data(client, AUO_PIXCIR_REG_VERSION);
+ if (version < 0) {
+ error = version;
+ return error;
+ }
- free_irq(client->irq, ts);
+ dev_info(&client->dev, "firmware version 0x%X\n", version);
- input_unregister_device(ts->input);
+ error = auo_pixcir_int_config(ts, pdata->int_setting);
+ if (error)
+ return error;
- if (pdata->exit_hw)
- pdata->exit_hw(client);
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, auo_pixcir_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ input_dev->name, ts);
+ if (error) {
+ dev_err(&client->dev, "irq %d requested failed, %d\n",
+ client->irq, error);
+ return error;
+ }
- gpio_free(pdata->gpio_int);
+ /* stop device and put it into deep sleep until it is opened */
+ error = auo_pixcir_stop(ts);
+ if (error)
+ return error;
+
+ error = input_register_device(input_dev);
+ if (error) {
+ dev_err(&client->dev, "could not register input device, %d\n",
+ error);
+ return error;
+ }
- kfree(ts);
+ i2c_set_clientdata(client, ts);
return 0;
}
@@ -624,14 +678,22 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
+#ifdef CONFIG_OF
+static struct of_device_id auo_pixcir_ts_dt_idtable[] = {
+ { .compatible = "auo,auo_pixcir_ts" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable);
+#endif
+
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "auo_pixcir_ts",
.pm = &auo_pixcir_pm_ops,
+ .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable),
},
.probe = auo_pixcir_probe,
- .remove = auo_pixcir_remove,
.id_table = auo_pixcir_idtable,
};
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index a9170157b442..83fa1b15a97f 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -440,8 +440,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
return -EIO;
}
- if (tsdata->raw_buffer)
- kfree(tsdata->raw_buffer);
+ kfree(tsdata->raw_buffer);
tsdata->raw_buffer = NULL;
/* restore parameters */
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 55255a940072..8fe5086c8d2e 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -206,8 +206,7 @@ static int eeti_ts_probe(struct i2c_client *client,
if (err < 0)
goto err1;
- if (pdata)
- priv->irq_active_high = pdata->irq_active_high;
+ priv->irq_active_high = pdata->irq_active_high;
irq_flags = priv->irq_active_high ?
IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index 02103b6abb39..89308fe38752 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -250,17 +250,7 @@ static struct platform_driver mc13783_ts_driver = {
},
};
-static int __init mc13783_ts_init(void)
-{
- return platform_driver_probe(&mc13783_ts_driver, &mc13783_ts_probe);
-}
-module_init(mc13783_ts_init);
-
-static void __exit mc13783_ts_exit(void)
-{
- platform_driver_unregister(&mc13783_ts_driver);
-}
-module_exit(mc13783_ts_exit);
+module_platform_driver_probe(mc13783_ts_driver, mc13783_ts_probe);
MODULE_DESCRIPTION("MC13783 input touchscreen driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index d9d05e222428..1740a2496371 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -19,13 +19,16 @@
*/
#include <linux/delay.h>
+#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/of_gpio.h>
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/platform_data/st1232_pdata.h>
#define ST1232_TS_NAME "st1232-ts"
@@ -48,6 +51,7 @@ struct st1232_ts_data {
struct input_dev *input_dev;
struct st1232_ts_finger finger[MAX_FINGERS];
struct dev_pm_qos_request low_latency_req;
+ int reset_gpio;
};
static int st1232_ts_read_data(struct st1232_ts_data *ts)
@@ -139,10 +143,17 @@ end:
return IRQ_HANDLED;
}
+static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron)
+{
+ if (gpio_is_valid(ts->reset_gpio))
+ gpio_direction_output(ts->reset_gpio, poweron);
+}
+
static int st1232_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct st1232_ts_data *ts;
+ struct st1232_pdata *pdata = client->dev.platform_data;
struct input_dev *input_dev;
int error;
@@ -156,17 +167,36 @@ static int st1232_ts_probe(struct i2c_client *client,
return -EINVAL;
}
+ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
- ts = kzalloc(sizeof(struct st1232_ts_data), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ts || !input_dev) {
- error = -ENOMEM;
- goto err_free_mem;
- }
+ input_dev = devm_input_allocate_device(&client->dev);
+ if (!input_dev)
+ return -ENOMEM;
ts->client = client;
ts->input_dev = input_dev;
+ if (pdata)
+ ts->reset_gpio = pdata->reset_gpio;
+ else if (client->dev.of_node)
+ ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
+ else
+ ts->reset_gpio = -ENODEV;
+
+ if (gpio_is_valid(ts->reset_gpio)) {
+ error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
+ if (error) {
+ dev_err(&client->dev,
+ "Unable to request GPIO pin %d.\n",
+ ts->reset_gpio);
+ return error;
+ }
+ }
+
+ st1232_ts_power(ts, true);
+
input_dev->name = "st1232-touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
@@ -179,31 +209,26 @@ static int st1232_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev, ABS_MT_POSITION_X, MIN_X, MAX_X, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, MIN_Y, MAX_Y, 0, 0);
- error = request_threaded_irq(client->irq, NULL, st1232_ts_irq_handler,
- IRQF_ONESHOT, client->name, ts);
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, st1232_ts_irq_handler,
+ IRQF_ONESHOT,
+ client->name, ts);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
- goto err_free_mem;
+ return error;
}
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&client->dev, "Unable to register %s input device\n",
input_dev->name);
- goto err_free_irq;
+ return error;
}
i2c_set_clientdata(client, ts);
device_init_wakeup(&client->dev, 1);
return 0;
-
-err_free_irq:
- free_irq(client->irq, ts);
-err_free_mem:
- input_free_device(input_dev);
- kfree(ts);
- return error;
}
static int st1232_ts_remove(struct i2c_client *client)
@@ -211,9 +236,7 @@ static int st1232_ts_remove(struct i2c_client *client)
struct st1232_ts_data *ts = i2c_get_clientdata(client);
device_init_wakeup(&client->dev, 0);
- free_irq(client->irq, ts);
- input_unregister_device(ts->input_dev);
- kfree(ts);
+ st1232_ts_power(ts, false);
return 0;
}
@@ -222,11 +245,14 @@ static int st1232_ts_remove(struct i2c_client *client)
static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct st1232_ts_data *ts = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev))
+ if (device_may_wakeup(&client->dev)) {
enable_irq_wake(client->irq);
- else
+ } else {
disable_irq(client->irq);
+ st1232_ts_power(ts, false);
+ }
return 0;
}
@@ -234,11 +260,14 @@ static int st1232_ts_suspend(struct device *dev)
static int st1232_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct st1232_ts_data *ts = i2c_get_clientdata(client);
- if (device_may_wakeup(&client->dev))
+ if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
- else
+ } else {
+ st1232_ts_power(ts, true);
enable_irq(client->irq);
+ }
return 0;
}
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index 6e743e3dfda4..16b52115c27f 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -162,14 +162,14 @@ static void wm9712_phy_init(struct wm97xx *wm)
if (rpu) {
dig2 &= 0xffc0;
dig2 |= WM9712_RPU(rpu);
- dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
+ dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms\n",
64000 / rpu);
}
/* WM9712 five wire */
if (five_wire) {
dig2 |= WM9712_45W;
- dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
+ dev_dbg(wm->dev, "setting 5-wire touchscreen mode.\n");
if (pil) {
dev_warn(wm->dev, "pressure measurement is not "
@@ -182,21 +182,21 @@ static void wm9712_phy_init(struct wm97xx *wm)
if (pil == 2) {
dig2 |= WM9712_PIL;
dev_dbg(wm->dev,
- "setting pressure measurement current to 400uA.");
+ "setting pressure measurement current to 400uA.\n");
} else if (pil)
dev_dbg(wm->dev,
- "setting pressure measurement current to 200uA.");
+ "setting pressure measurement current to 200uA.\n");
if (!pil)
pressure = 0;
/* polling mode sample settling delay */
if (delay < 0 || delay > 15) {
- dev_dbg(wm->dev, "supplied delay out of range.");
+ dev_dbg(wm->dev, "supplied delay out of range.\n");
delay = 4;
}
dig1 &= 0xff0f;
dig1 |= WM97XX_DELAY(delay);
- dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
+ dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.\n",
delay_table[delay]);
/* mask */
@@ -285,7 +285,7 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
if (is_pden(wm))
wm->pen_probably_down = 0;
else
- dev_dbg(wm->dev, "adc sample timeout");
+ dev_dbg(wm->dev, "adc sample timeout\n");
return RC_PENUP;
}
@@ -295,15 +295,19 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
/* check we have correct sample */
if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
- dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
+ dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x\n",
adcsel & WM97XX_ADCSEL_MASK,
*sample & WM97XX_ADCSEL_MASK);
- return RC_PENUP;
+ return RC_AGAIN;
}
if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
- wm->pen_probably_down = 0;
- return RC_PENUP;
+ /* Sometimes it reads a wrong value the first time. */
+ *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
+ if (!(*sample & WM97XX_PEN_DOWN)) {
+ wm->pen_probably_down = 0;
+ return RC_PENUP;
+ }
}
return RC_VALID;
@@ -345,7 +349,7 @@ static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
if (is_pden(wm))
wm->pen_probably_down = 0;
else
- dev_dbg(wm->dev, "adc sample timeout");
+ dev_dbg(wm->dev, "adc sample timeout\n");
return RC_PENUP;
}
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 5dbe73af2f8f..7e45c9f6e6b7 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -442,6 +442,16 @@ static int wm97xx_read_samples(struct wm97xx *wm)
"pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
data.x >> 12, data.x & 0xfff, data.y >> 12,
data.y & 0xfff, data.p >> 12, data.p & 0xfff);
+
+ if (abs_x[0] > (data.x & 0xfff) ||
+ abs_x[1] < (data.x & 0xfff) ||
+ abs_y[0] > (data.y & 0xfff) ||
+ abs_y[1] < (data.y & 0xfff)) {
+ dev_dbg(wm->dev, "Measurement out of range, dropping it\n");
+ rc = RC_AGAIN;
+ goto out;
+ }
+
input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
@@ -455,6 +465,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
wm->ts_reader_interval = wm->ts_reader_min_interval;
}
+out:
mutex_unlock(&wm->codec_mutex);
return rc;
}
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 5c514d0711d1..c332fb98480d 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -130,7 +130,7 @@ config IRQ_REMAP
# OMAP IOMMU support
config OMAP_IOMMU
bool "OMAP IOMMU Support"
- depends on ARCH_OMAP
+ depends on ARCH_OMAP2PLUS
select IOMMU_API
config OMAP_IOVMM
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 98f555dafb55..830183737b0f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -173,7 +173,7 @@ static inline u16 get_device_id(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- return calc_devid(pdev->bus->number, pdev->devfn);
+ return PCI_DEVID(pdev->bus->number, pdev->devfn);
}
static struct iommu_dev_data *get_dev_data(struct device *dev)
@@ -649,26 +649,26 @@ retry:
case EVENT_TYPE_ILL_DEV:
printk("ILLEGAL_DEV_TABLE_ENTRY device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags);
dump_dte_entry(devid);
break;
case EVENT_TYPE_IO_FAULT:
printk("IO_PAGE_FAULT device=%02x:%02x.%x "
"domain=0x%04x address=0x%016llx flags=0x%04x]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
domid, address, flags);
break;
case EVENT_TYPE_DEV_TAB_ERR:
printk("DEV_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags);
break;
case EVENT_TYPE_PAGE_TAB_ERR:
printk("PAGE_TAB_HARDWARE_ERROR device=%02x:%02x.%x "
"domain=0x%04x address=0x%016llx flags=0x%04x]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
domid, address, flags);
break;
case EVENT_TYPE_ILL_CMD:
@@ -682,13 +682,13 @@ retry:
case EVENT_TYPE_IOTLB_INV_TO:
printk("IOTLB_INV_TIMEOUT device=%02x:%02x.%x "
"address=0x%016llx]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address);
break;
case EVENT_TYPE_INV_DEV_REQ:
printk("INVALID_DEVICE_REQUEST device=%02x:%02x.%x "
"address=0x%016llx flags=0x%04x]\n",
- PCI_BUS(devid), PCI_SLOT(devid), PCI_FUNC(devid),
+ PCI_BUS_NUM(devid), PCI_SLOT(devid), PCI_FUNC(devid),
address, flags);
break;
default:
@@ -2466,18 +2466,16 @@ static int device_change_notifier(struct notifier_block *nb,
/* allocate a protection domain if a device is added */
dma_domain = find_protection_domain(devid);
- if (dma_domain)
- goto out;
- dma_domain = dma_ops_domain_alloc();
- if (!dma_domain)
- goto out;
- dma_domain->target_dev = devid;
-
- spin_lock_irqsave(&iommu_pd_list_lock, flags);
- list_add_tail(&dma_domain->list, &iommu_pd_list);
- spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
-
- dev_data = get_dev_data(dev);
+ if (!dma_domain) {
+ dma_domain = dma_ops_domain_alloc();
+ if (!dma_domain)
+ goto out;
+ dma_domain->target_dev = devid;
+
+ spin_lock_irqsave(&iommu_pd_list_lock, flags);
+ list_add_tail(&dma_domain->list, &iommu_pd_list);
+ spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
+ }
dev->archdata.dma_ops = &amd_iommu_dma_ops;
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index b6ecddb63cd0..2f46881256a2 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -406,7 +406,7 @@ static int __init find_last_devid_on_pci(int bus, int dev, int fn, int cap_ptr)
u32 cap;
cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
- update_last_devid(calc_devid(MMIO_GET_BUS(cap), MMIO_GET_LD(cap)));
+ update_last_devid(PCI_DEVID(MMIO_GET_BUS(cap), MMIO_GET_LD(cap)));
return 0;
}
@@ -423,7 +423,7 @@ static int __init find_last_devid_from_ivhd(struct ivhd_header *h)
p += sizeof(*h);
end += h->length;
- find_last_devid_on_pci(PCI_BUS(h->devid),
+ find_last_devid_on_pci(PCI_BUS_NUM(h->devid),
PCI_SLOT(h->devid),
PCI_FUNC(h->devid),
h->cap_ptr);
@@ -784,10 +784,10 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_ALL\t\t\t first devid: %02x:%02x.%x"
" last device %02x:%02x.%x flags: %02x\n",
- PCI_BUS(iommu->first_device),
+ PCI_BUS_NUM(iommu->first_device),
PCI_SLOT(iommu->first_device),
PCI_FUNC(iommu->first_device),
- PCI_BUS(iommu->last_device),
+ PCI_BUS_NUM(iommu->last_device),
PCI_SLOT(iommu->last_device),
PCI_FUNC(iommu->last_device),
e->flags);
@@ -801,7 +801,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_SELECT\t\t\t devid: %02x:%02x.%x "
"flags: %02x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -813,7 +813,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_SELECT_RANGE_START\t "
"devid: %02x:%02x.%x flags: %02x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags);
@@ -827,11 +827,11 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_ALIAS\t\t\t devid: %02x:%02x.%x "
"flags: %02x devid_to: %02x:%02x.%x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags,
- PCI_BUS(e->ext >> 8),
+ PCI_BUS_NUM(e->ext >> 8),
PCI_SLOT(e->ext >> 8),
PCI_FUNC(e->ext >> 8));
@@ -846,11 +846,11 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_ALIAS_RANGE\t\t "
"devid: %02x:%02x.%x flags: %02x "
"devid_to: %02x:%02x.%x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags,
- PCI_BUS(e->ext >> 8),
+ PCI_BUS_NUM(e->ext >> 8),
PCI_SLOT(e->ext >> 8),
PCI_FUNC(e->ext >> 8));
@@ -864,7 +864,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_EXT_SELECT\t\t devid: %02x:%02x.%x "
"flags: %02x ext: %08x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags, e->ext);
@@ -877,7 +877,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_EXT_SELECT_RANGE\t devid: "
"%02x:%02x.%x flags: %02x ext: %08x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid),
e->flags, e->ext);
@@ -890,7 +890,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
case IVHD_DEV_RANGE_END:
DUMP_printk(" DEV_RANGE_END\t\t devid: %02x:%02x.%x\n",
- PCI_BUS(e->devid),
+ PCI_BUS_NUM(e->devid),
PCI_SLOT(e->devid),
PCI_FUNC(e->devid));
@@ -924,7 +924,7 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
DUMP_printk(" DEV_SPECIAL(%s[%d])\t\tdevid: %02x:%02x.%x\n",
var, (int)handle,
- PCI_BUS(devid),
+ PCI_BUS_NUM(devid),
PCI_SLOT(devid),
PCI_FUNC(devid));
@@ -980,7 +980,7 @@ static void __init free_iommu_all(void)
* BIOS should disable L2B micellaneous clock gating by setting
* L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b
*/
-static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
+static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
{
u32 value;
@@ -1086,7 +1086,7 @@ static int __init init_iommu_all(struct acpi_table_header *table)
DUMP_printk("device: %02x:%02x.%01x cap: %04x "
"seg: %d flags: %01x info %04x\n",
- PCI_BUS(h->devid), PCI_SLOT(h->devid),
+ PCI_BUS_NUM(h->devid), PCI_SLOT(h->devid),
PCI_FUNC(h->devid), h->cap_ptr,
h->pci_seg, h->flags, h->info);
DUMP_printk(" mmio-addr: %016llx\n",
@@ -1116,7 +1116,7 @@ static int iommu_init_pci(struct amd_iommu *iommu)
int cap_ptr = iommu->cap_ptr;
u32 range, misc, low, high;
- iommu->dev = pci_get_bus_and_slot(PCI_BUS(iommu->devid),
+ iommu->dev = pci_get_bus_and_slot(PCI_BUS_NUM(iommu->devid),
iommu->devid & 0xff);
if (!iommu->dev)
return -ENODEV;
@@ -1128,9 +1128,9 @@ static int iommu_init_pci(struct amd_iommu *iommu)
pci_read_config_dword(iommu->dev, cap_ptr + MMIO_MISC_OFFSET,
&misc);
- iommu->first_device = calc_devid(MMIO_GET_BUS(range),
+ iommu->first_device = PCI_DEVID(MMIO_GET_BUS(range),
MMIO_GET_FD(range));
- iommu->last_device = calc_devid(MMIO_GET_BUS(range),
+ iommu->last_device = PCI_DEVID(MMIO_GET_BUS(range),
MMIO_GET_LD(range));
if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
@@ -1388,8 +1388,8 @@ static int __init init_unity_map_range(struct ivmd_header *m)
DUMP_printk("%s devid_start: %02x:%02x.%x devid_end: %02x:%02x.%x"
" range_start: %016llx range_end: %016llx flags: %x\n", s,
- PCI_BUS(e->devid_start), PCI_SLOT(e->devid_start),
- PCI_FUNC(e->devid_start), PCI_BUS(e->devid_end),
+ PCI_BUS_NUM(e->devid_start), PCI_SLOT(e->devid_start),
+ PCI_FUNC(e->devid_start), PCI_BUS_NUM(e->devid_end),
PCI_SLOT(e->devid_end), PCI_FUNC(e->devid_end),
e->address_start, e->address_end, m->flags);
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index e38ab438bb34..ec36cf63e0ca 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <linux/pci.h>
/*
* Maximum number of IOMMUs supported
@@ -315,9 +316,6 @@
#define MAX_DOMAIN_ID 65536
-/* FIXME: move this macro to <linux/pci.h> */
-#define PCI_BUS(x) (((x) >> 8) & 0xff)
-
/* Protection domain flags */
#define PD_DMA_OPS_MASK (1UL << 0) /* domain used for dma_ops */
#define PD_DEFAULT_MASK (1UL << 1) /* domain is a default dma_ops
@@ -703,13 +701,6 @@ extern int amd_iommu_max_glx_val;
*/
extern void iommu_flush_all_caches(struct amd_iommu *iommu);
-/* takes bus and device/function and returns the device id
- * FIXME: should that be in generic PCI code? */
-static inline u16 calc_devid(u8 bus, u8 devfn)
-{
- return (((u16)bus) << 8) | devfn;
-}
-
static inline int get_ioapic_devid(int id)
{
struct devid_map *entry;
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index e5cdaf87822c..b8008f679bc7 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -129,7 +129,8 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
(*cnt)++;
- else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC) {
+ else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC &&
+ scope->entry_type != ACPI_DMAR_SCOPE_TYPE_HPET) {
pr_warn("Unsupported device scope\n");
}
start += scope->length;
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index d56f8c17c5fe..7c11ff368d07 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -2,7 +2,6 @@
#include <linux/cpumask.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/cpumask.h>
#include <linux/errno.h>
#include <linux/msi.h>
#include <linux/irq.h>
diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c
index 0246b1fddffe..c276fde318e5 100644
--- a/drivers/ipack/carriers/tpci200.c
+++ b/drivers/ipack/carriers/tpci200.c
@@ -480,6 +480,7 @@ static void tpci200_release_device(struct ipack_device *dev)
static int tpci200_create_device(struct tpci200_board *tpci200, int i)
{
+ int ret;
enum ipack_space space;
struct ipack_device *dev =
kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
@@ -495,7 +496,18 @@ static int tpci200_create_device(struct tpci200_board *tpci200, int i)
+ tpci200_space_interval[space] * i;
dev->region[space].size = tpci200_space_size[space];
}
- return ipack_device_register(dev);
+
+ ret = ipack_device_init(dev);
+ if (ret < 0) {
+ ipack_put_device(dev);
+ return ret;
+ }
+
+ ret = ipack_device_add(dev);
+ if (ret < 0)
+ ipack_put_device(dev);
+
+ return ret;
}
static int tpci200_pci_probe(struct pci_dev *pdev,
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c
index 7ec6b208b1cb..6e066c53acce 100644
--- a/drivers/ipack/ipack.c
+++ b/drivers/ipack/ipack.c
@@ -227,7 +227,7 @@ static int ipack_unregister_bus_member(struct device *dev, void *data)
struct ipack_bus_device *bus = data;
if (idev->bus == bus)
- ipack_device_unregister(idev);
+ ipack_device_del(idev);
return 1;
}
@@ -419,7 +419,7 @@ out:
return ret;
}
-int ipack_device_register(struct ipack_device *dev)
+int ipack_device_init(struct ipack_device *dev)
{
int ret;
@@ -428,6 +428,7 @@ int ipack_device_register(struct ipack_device *dev)
dev->dev.parent = dev->bus->parent;
dev_set_name(&dev->dev,
"ipack-dev.%u.%u", dev->bus->bus_nr, dev->slot);
+ device_initialize(&dev->dev);
if (dev->bus->ops->set_clockrate(dev, 8))
dev_warn(&dev->dev, "failed to switch to 8 MHz operation for reading of device ID.\n");
@@ -447,19 +448,34 @@ int ipack_device_register(struct ipack_device *dev)
dev_err(&dev->dev, "failed to switch to 32 MHz operation.\n");
}
- ret = device_register(&dev->dev);
- if (ret < 0)
- kfree(dev->id);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipack_device_init);
- return ret;
+int ipack_device_add(struct ipack_device *dev)
+{
+ return device_add(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_add);
+
+void ipack_device_del(struct ipack_device *dev)
+{
+ device_del(&dev->dev);
+ ipack_put_device(dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_del);
+
+void ipack_get_device(struct ipack_device *dev)
+{
+ get_device(&dev->dev);
}
-EXPORT_SYMBOL_GPL(ipack_device_register);
+EXPORT_SYMBOL_GPL(ipack_get_device);
-void ipack_device_unregister(struct ipack_device *dev)
+void ipack_put_device(struct ipack_device *dev)
{
- device_unregister(&dev->dev);
+ put_device(&dev->dev);
}
-EXPORT_SYMBOL_GPL(ipack_device_unregister);
+EXPORT_SYMBOL_GPL(ipack_put_device);
static int __init ipack_init(void)
{
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index a32e0d5aa45f..fc6aebf1e4b2 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -236,7 +236,8 @@ static int gic_retrigger(struct irq_data *d)
if (gic_arch_extn.irq_retrigger)
return gic_arch_extn.irq_retrigger(d);
- return -ENXIO;
+ /* the genirq layer expects 0 if we can't retrigger in hardware */
+ return 0;
}
#ifdef CONFIG_SMP
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index 9dbd82b716d3..065b7a31a478 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -139,7 +139,7 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
int i;
if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) {
- pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__);
+ pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_VERSATILE_FPGA_IRQ_NR\n", __func__);
return;
}
f = &fpga_irq_devices[fpga_irq_id];
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 89562a845f6a..ac6f72b455d1 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -569,7 +569,6 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
{
struct capidev *cdev = ap->private;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
- struct tty_struct *tty;
struct capiminor *mp;
u16 datahandle;
struct capincci *np;
@@ -627,11 +626,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
CAPIMSG_U16(skb->data, CAPIMSG_BASELEN + 4 + 2));
kfree_skb(skb);
capiminor_del_ack(mp, datahandle);
- tty = tty_port_tty_get(&mp->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&mp->port);
handle_minor_send(mp);
} else {
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 832bc807ed20..cc9f1927a322 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -469,8 +469,7 @@ static int capidrv_add_ack(struct capidrv_ncci *nccip,
{
struct ncci_datahandle_queue *n, **pp;
- n = (struct ncci_datahandle_queue *)
- kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
+ n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
if (!n) {
printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
return -1;
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index db432e635496..50749a70c5ca 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -441,8 +441,7 @@ static int isdn_divert_icall(isdn_ctrl *ic)
switch (dv->rule.action) {
case DEFLECT_IGNORE:
- return (0);
- break;
+ return 0;
case DEFLECT_ALERT:
case DEFLECT_PROCEED:
@@ -510,10 +509,9 @@ static int isdn_divert_icall(isdn_ctrl *ic)
break;
default:
- return (0); /* ignore call */
- break;
+ return 0; /* ignore call */
} /* switch action */
- break;
+ break; /* will break the 'for' looping */
} /* scan_table */
if (cs) {
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index e2b539675b66..600c79b030cd 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -487,12 +487,8 @@ static const struct tty_operations if_ops = {
static void if_wake(unsigned long data)
{
struct cardstate *cs = (struct cardstate *)data;
- struct tty_struct *tty = tty_port_tty_get(&cs->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&cs->port);
}
/*** interface to common ***/
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index c21353d8e915..62b8030ee331 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -163,16 +163,4 @@ static struct pcmcia_driver avmcs_driver = {
.remove = avmcs_detach,
.id_table = avmcs_ids,
};
-
-static int __init avmcs_init(void)
-{
- return pcmcia_register_driver(&avmcs_driver);
-}
-
-static void __exit avmcs_exit(void)
-{
- pcmcia_unregister_driver(&avmcs_driver);
-}
-
-module_init(avmcs_init);
-module_exit(avmcs_exit);
+module_pcmcia_driver(avmcs_driver);
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 4e676bcf8506..baad94ec1f4a 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -159,16 +159,4 @@ static struct pcmcia_driver avma1cs_driver = {
.remove = avma1cs_detach,
.id_table = avma1cs_ids,
};
-
-static int __init init_avma1_cs(void)
-{
- return pcmcia_register_driver(&avma1cs_driver);
-}
-
-static void __exit exit_avma1_cs(void)
-{
- pcmcia_unregister_driver(&avma1cs_driver);
-}
-
-module_init(init_avma1_cs);
-module_exit(exit_avma1_cs);
+module_pcmcia_driver(avma1cs_driver);
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index ebe56918f6fc..40f6fad79de3 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -215,16 +215,4 @@ static struct pcmcia_driver elsa_cs_driver = {
.suspend = elsa_suspend,
.resume = elsa_resume,
};
-
-static int __init init_elsa_cs(void)
-{
- return pcmcia_register_driver(&elsa_cs_driver);
-}
-
-static void __exit exit_elsa_cs(void)
-{
- pcmcia_unregister_driver(&elsa_cs_driver);
-}
-
-module_init(init_elsa_cs);
-module_exit(exit_elsa_cs);
+module_pcmcia_driver(elsa_cs_driver);
diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
index 1bb291021fdb..c7a94713e9ec 100644
--- a/drivers/isdn/hisax/fsm.c
+++ b/drivers/isdn/hisax/fsm.c
@@ -26,7 +26,7 @@ FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
{
int i;
- fsm->jumpmatrix = (FSMFNPTR *)
+ fsm->jumpmatrix =
kzalloc(sizeof(FSMFNPTR) * fsm->state_count * fsm->event_count, GFP_KERNEL);
if (!fsm->jumpmatrix)
return -ENOMEM;
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 90f34ae2b80f..dc4574f735ef 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1479,7 +1479,7 @@ int setup_hfcsx(struct IsdnCard *card)
release_region(cs->hw.hfcsx.base, 2);
return (0);
}
- if (!(cs->hw.hfcsx.extra = (void *)
+ if (!(cs->hw.hfcsx.extra =
kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) {
release_region(cs->hw.hfcsx.base, 2);
printk(KERN_WARNING "HFC-SX: unable to allocate memory\n");
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 90f81291641b..92ef62d4caf4 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -206,16 +206,4 @@ static struct pcmcia_driver sedlbauer_driver = {
.suspend = sedlbauer_suspend,
.resume = sedlbauer_resume,
};
-
-static int __init init_sedlbauer_cs(void)
-{
- return pcmcia_register_driver(&sedlbauer_driver);
-}
-
-static void __exit exit_sedlbauer_cs(void)
-{
- pcmcia_unregister_driver(&sedlbauer_driver);
-}
-
-module_init(init_sedlbauer_cs);
-module_exit(exit_sedlbauer_cs);
+module_pcmcia_driver(sedlbauer_driver);
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index f2476ffb04fd..b8dd14958757 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -197,16 +197,4 @@ static struct pcmcia_driver teles_cs_driver = {
.suspend = teles_suspend,
.resume = teles_resume,
};
-
-static int __init init_teles_cs(void)
-{
- return pcmcia_register_driver(&teles_cs_driver);
-}
-
-static void __exit exit_teles_cs(void)
-{
- pcmcia_unregister_driver(&teles_cs_driver);
-}
-
-module_init(init_teles_cs);
-module_exit(exit_teles_cs);
+module_pcmcia_driver(teles_cs_driver);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index babc621a07fb..88d657dff474 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1385,7 +1385,7 @@ isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
return eth->h_proto;
rawp = skb->data;
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index ebaebdf30f98..3c5f2491a16f 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1472,9 +1472,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
tty->termios.c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS))
- tty->hw_stopped = 0;
}
}
@@ -3427,7 +3424,6 @@ isdn_tty_parse_at(modem_info *info)
p++;
isdn_tty_cmd_ATA(info);
return;
- break;
case 'D':
/* D - Dial */
if (info->msr & UART_MSR_DCD)
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 8b07f83d48ad..e47dcb9d1e91 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -578,6 +578,7 @@ data_sock_getname(struct socket *sock, struct sockaddr *addr,
lock_sock(sk);
*addr_len = sizeof(*maddr);
+ maddr->family = AF_ISDN;
maddr->dev = _pms(sk)->dev->id;
maddr->channel = _pms(sk)->ch.nr;
maddr->sapi = _pms(sk)->ch.addr & 0xff;
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 6b580b2c717f..ca997bd4e818 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -33,8 +33,8 @@ static unsigned long ram[] = {0, 0, 0, 0};
static bool do_reset = 0;
module_param_array(io, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-module_param_array(ram, int, NULL, 0);
+module_param_array(irq, byte, NULL, 0);
+module_param_array(ram, long, NULL, 0);
module_param(do_reset, bool, 0);
static int identify_board(unsigned long, unsigned int);
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 3b62be160a6e..864baabaee25 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -686,7 +686,7 @@ static unsigned int new_pgdir(struct lg_cpu *cpu,
* We pick one entry at random to throw out. Choosing the Least
* Recently Used might be better, but this is easy.
*/
- next = random32() % ARRAY_SIZE(cpu->lg->pgdirs);
+ next = prandom_u32() % ARRAY_SIZE(cpu->lg->pgdirs);
/* If it's never been allocated at all before, try now. */
if (!cpu->lg->pgdirs[next].pgdir) {
cpu->lg->pgdirs[next].pgdir =
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 4fd9d6aeff6a..5a2c75499824 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -846,7 +846,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
set_bit(bit, kaddr);
else
- test_and_set_bit_le(bit, kaddr);
+ set_bit_le(bit, kaddr);
kunmap_atomic(kaddr);
pr_debug("set file bit %lu page %lu\n", bit, page->index);
/* record page number so it gets flushed to disk when unplug occurs */
@@ -868,7 +868,7 @@ static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
clear_bit(bit, paddr);
else
- test_and_clear_bit_le(bit, paddr);
+ clear_bit_le(bit, paddr);
kunmap_atomic(paddr);
if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) {
set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 66120bd46d15..10744091e6ca 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -6,6 +6,7 @@
#include "dm.h"
#include "dm-bio-prison.h"
+#include "dm-bio-record.h"
#include "dm-cache-metadata.h"
#include <linux/dm-io.h>
@@ -201,10 +202,15 @@ struct per_bio_data {
unsigned req_nr:2;
struct dm_deferred_entry *all_io_entry;
- /* writethrough fields */
+ /*
+ * writethrough fields. These MUST remain at the end of this
+ * structure and the 'cache' member must be the first as it
+ * is used to determine the offsetof the writethrough fields.
+ */
struct cache *cache;
dm_cblock_t cblock;
bio_end_io_t *saved_bi_end_io;
+ struct dm_bio_details bio_details;
};
struct dm_cache_migration {
@@ -513,16 +519,28 @@ static void save_stats(struct cache *cache)
/*----------------------------------------------------------------
* Per bio data
*--------------------------------------------------------------*/
-static struct per_bio_data *get_per_bio_data(struct bio *bio)
+
+/*
+ * If using writeback, leave out struct per_bio_data's writethrough fields.
+ */
+#define PB_DATA_SIZE_WB (offsetof(struct per_bio_data, cache))
+#define PB_DATA_SIZE_WT (sizeof(struct per_bio_data))
+
+static size_t get_per_bio_data_size(struct cache *cache)
+{
+ return cache->features.write_through ? PB_DATA_SIZE_WT : PB_DATA_SIZE_WB;
+}
+
+static struct per_bio_data *get_per_bio_data(struct bio *bio, size_t data_size)
{
- struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+ struct per_bio_data *pb = dm_per_bio_data(bio, data_size);
BUG_ON(!pb);
return pb;
}
-static struct per_bio_data *init_per_bio_data(struct bio *bio)
+static struct per_bio_data *init_per_bio_data(struct bio *bio, size_t data_size)
{
- struct per_bio_data *pb = get_per_bio_data(bio);
+ struct per_bio_data *pb = get_per_bio_data(bio, data_size);
pb->tick = false;
pb->req_nr = dm_bio_get_target_bio_nr(bio);
@@ -556,7 +574,8 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio)
{
unsigned long flags;
- struct per_bio_data *pb = get_per_bio_data(bio);
+ size_t pb_data_size = get_per_bio_data_size(cache);
+ struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
spin_lock_irqsave(&cache->lock, flags);
if (cache->need_tick_bio &&
@@ -635,7 +654,7 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio)
static void writethrough_endio(struct bio *bio, int err)
{
- struct per_bio_data *pb = get_per_bio_data(bio);
+ struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
bio->bi_end_io = pb->saved_bi_end_io;
if (err) {
@@ -643,6 +662,7 @@ static void writethrough_endio(struct bio *bio, int err)
return;
}
+ dm_bio_restore(&pb->bio_details, bio);
remap_to_cache(pb->cache, bio, pb->cblock);
/*
@@ -662,11 +682,12 @@ static void writethrough_endio(struct bio *bio, int err)
static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio,
dm_oblock_t oblock, dm_cblock_t cblock)
{
- struct per_bio_data *pb = get_per_bio_data(bio);
+ struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
pb->cache = cache;
pb->cblock = cblock;
pb->saved_bi_end_io = bio->bi_end_io;
+ dm_bio_record(&pb->bio_details, bio);
bio->bi_end_io = writethrough_endio;
remap_to_origin_clear_discard(pb->cache, bio, oblock);
@@ -1035,7 +1056,8 @@ static void defer_bio(struct cache *cache, struct bio *bio)
static void process_flush_bio(struct cache *cache, struct bio *bio)
{
- struct per_bio_data *pb = get_per_bio_data(bio);
+ size_t pb_data_size = get_per_bio_data_size(cache);
+ struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
BUG_ON(bio->bi_size);
if (!pb->req_nr)
@@ -1107,7 +1129,8 @@ static void process_bio(struct cache *cache, struct prealloc *structs,
dm_oblock_t block = get_bio_block(cache, bio);
struct dm_bio_prison_cell *cell_prealloc, *old_ocell, *new_ocell;
struct policy_result lookup_result;
- struct per_bio_data *pb = get_per_bio_data(bio);
+ size_t pb_data_size = get_per_bio_data_size(cache);
+ struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
bool discarded_block = is_discarded_oblock(cache, block);
bool can_migrate = discarded_block || spare_migration_bandwidth(cache);
@@ -1881,7 +1904,6 @@ static int cache_create(struct cache_args *ca, struct cache **result)
cache->ti = ca->ti;
ti->private = cache;
- ti->per_bio_data_size = sizeof(struct per_bio_data);
ti->num_flush_bios = 2;
ti->flush_supported = true;
@@ -1890,6 +1912,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
ti->discard_zeroes_data_unsupported = true;
memcpy(&cache->features, &ca->features, sizeof(cache->features));
+ ti->per_bio_data_size = get_per_bio_data_size(cache);
cache->callbacks.congested_fn = cache_is_congested;
dm_table_add_target_callbacks(ti->table, &cache->callbacks);
@@ -2092,6 +2115,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
int r;
dm_oblock_t block = get_bio_block(cache, bio);
+ size_t pb_data_size = get_per_bio_data_size(cache);
bool can_migrate = false;
bool discarded_block;
struct dm_bio_prison_cell *cell;
@@ -2108,7 +2132,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_REMAPPED;
}
- pb = init_per_bio_data(bio);
+ pb = init_per_bio_data(bio, pb_data_size);
if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
defer_bio(cache, bio);
@@ -2193,7 +2217,8 @@ static int cache_end_io(struct dm_target *ti, struct bio *bio, int error)
{
struct cache *cache = ti->private;
unsigned long flags;
- struct per_bio_data *pb = get_per_bio_data(bio);
+ size_t pb_data_size = get_per_bio_data_size(cache);
+ struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
if (pb->tick) {
policy_tick(cache->policy);
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 311e3d35b272..1d3fe1a40a9b 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -1279,6 +1279,31 @@ static int raid_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_SUBMITTED;
}
+static const char *decipher_sync_action(struct mddev *mddev)
+{
+ if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
+ return "frozen";
+
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+ (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) {
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ return "reshape";
+
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ return "resync";
+ else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ return "check";
+ return "repair";
+ }
+
+ if (test_bit(MD_RECOVERY_RECOVER, &mddev->recovery))
+ return "recover";
+ }
+
+ return "idle";
+}
+
static void raid_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
@@ -1298,8 +1323,18 @@ static void raid_status(struct dm_target *ti, status_type_t type,
sync = rs->md.recovery_cp;
if (sync >= rs->md.resync_max_sectors) {
+ /*
+ * Sync complete.
+ */
array_in_sync = 1;
sync = rs->md.resync_max_sectors;
+ } else if (test_bit(MD_RECOVERY_REQUESTED, &rs->md.recovery)) {
+ /*
+ * If "check" or "repair" is occurring, the array has
+ * undergone and initial sync and the health characters
+ * should not be 'a' anymore.
+ */
+ array_in_sync = 1;
} else {
/*
* The array may be doing an initial sync, or it may
@@ -1311,6 +1346,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
if (!test_bit(In_sync, &rs->dev[i].rdev.flags))
array_in_sync = 1;
}
+
/*
* Status characters:
* 'D' = Dead/Failed device
@@ -1339,6 +1375,21 @@ static void raid_status(struct dm_target *ti, status_type_t type,
(unsigned long long) sync,
(unsigned long long) rs->md.resync_max_sectors);
+ /*
+ * Sync action:
+ * See Documentation/device-mapper/dm-raid.c for
+ * information on each of these states.
+ */
+ DMEMIT(" %s", decipher_sync_action(&rs->md));
+
+ /*
+ * resync_mismatches/mismatch_cnt
+ * This field shows the number of discrepancies found when
+ * performing a "check" of the array.
+ */
+ DMEMIT(" %llu",
+ (unsigned long long)
+ atomic64_read(&rs->md.resync_mismatches));
break;
case STATUSTYPE_TABLE:
/* The string you would use to construct this array */
@@ -1425,7 +1476,62 @@ static void raid_status(struct dm_target *ti, status_type_t type,
}
}
-static int raid_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
+static int raid_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ struct raid_set *rs = ti->private;
+ struct mddev *mddev = &rs->md;
+
+ if (!strcasecmp(argv[0], "reshape")) {
+ DMERR("Reshape not supported.");
+ return -EINVAL;
+ }
+
+ if (!mddev->pers || !mddev->pers->sync_request)
+ return -EINVAL;
+
+ if (!strcasecmp(argv[0], "frozen"))
+ set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+ else
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+
+ if (!strcasecmp(argv[0], "idle") || !strcasecmp(argv[0], "frozen")) {
+ if (mddev->sync_thread) {
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ md_reap_sync_thread(mddev);
+ }
+ } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+ return -EBUSY;
+ else if (!strcasecmp(argv[0], "resync"))
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ else if (!strcasecmp(argv[0], "recover")) {
+ set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ } else {
+ if (!strcasecmp(argv[0], "check"))
+ set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ else if (!!strcasecmp(argv[0], "repair"))
+ return -EINVAL;
+ set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ }
+ if (mddev->ro == 2) {
+ /* A write to sync_action is enough to justify
+ * canceling read-auto mode
+ */
+ mddev->ro = 0;
+ if (!mddev->suspended)
+ md_wakeup_thread(mddev->sync_thread);
+ }
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ if (!mddev->suspended)
+ md_wakeup_thread(mddev->thread);
+
+ return 0;
+}
+
+static int raid_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
{
struct raid_set *rs = ti->private;
unsigned i;
@@ -1482,12 +1588,13 @@ static void raid_resume(struct dm_target *ti)
static struct target_type raid_target = {
.name = "raid",
- .version = {1, 4, 2},
+ .version = {1, 5, 0},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,
.map = raid_map,
.status = raid_status,
+ .message = raid_message,
.iterate_devices = raid_iterate_devices,
.io_hints = raid_io_hints,
.presuspend = raid_presuspend,
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 7e469260fe5e..9a0bdad9ad8f 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -611,6 +611,7 @@ static void dec_pending(struct dm_io *io, int error)
queue_io(md, bio);
} else {
/* done with normal IO or empty flush */
+ trace_block_bio_complete(md->queue, bio, io_error);
bio_endio(bio, io_error);
}
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index aeceedfc530b..4c74424c78b0 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -72,6 +72,9 @@ static DECLARE_WAIT_QUEUE_HEAD(resync_wait);
static struct workqueue_struct *md_wq;
static struct workqueue_struct *md_misc_wq;
+static int remove_and_add_spares(struct mddev *mddev,
+ struct md_rdev *this);
+
#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
/*
@@ -1564,8 +1567,8 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
sector, count, 1) == 0)
return -EINVAL;
}
- } else if (sb->bblog_offset == 0)
- rdev->badblocks.shift = -1;
+ } else if (sb->bblog_offset != 0)
+ rdev->badblocks.shift = 0;
if (!refdev) {
ret = 1;
@@ -2411,6 +2414,11 @@ static void md_update_sb(struct mddev * mddev, int force_change)
int nospares = 0;
int any_badblocks_changed = 0;
+ if (mddev->ro) {
+ if (force_change)
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ return;
+ }
repeat:
/* First make sure individual recovery_offsets are correct */
rdev_for_each(rdev, mddev) {
@@ -2800,12 +2808,10 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
/* personality does all needed checks */
if (rdev->mddev->pers->hot_remove_disk == NULL)
return -EINVAL;
- err = rdev->mddev->pers->
- hot_remove_disk(rdev->mddev, rdev);
- if (err)
- return err;
- sysfs_unlink_rdev(rdev->mddev, rdev);
- rdev->raid_disk = -1;
+ clear_bit(Blocked, &rdev->flags);
+ remove_and_add_spares(rdev->mddev, rdev);
+ if (rdev->raid_disk >= 0)
+ return -EBUSY;
set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
md_wakeup_thread(rdev->mddev->thread);
} else if (rdev->mddev->pers) {
@@ -3221,7 +3227,7 @@ int md_rdev_init(struct md_rdev *rdev)
* be used - I wonder if that matters
*/
rdev->badblocks.count = 0;
- rdev->badblocks.shift = 0;
+ rdev->badblocks.shift = -1; /* disabled until explicitly enabled */
rdev->badblocks.page = kmalloc(PAGE_SIZE, GFP_KERNEL);
seqlock_init(&rdev->badblocks.lock);
if (rdev->badblocks.page == NULL)
@@ -3293,9 +3299,6 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
goto abort_free;
}
}
- if (super_format == -1)
- /* hot-add for 0.90, or non-persistent: so no badblocks */
- rdev->badblocks.shift = -1;
return rdev;
@@ -4225,8 +4228,6 @@ action_show(struct mddev *mddev, char *page)
return sprintf(page, "%s\n", type);
}
-static void reap_sync_thread(struct mddev *mddev);
-
static ssize_t
action_store(struct mddev *mddev, const char *page, size_t len)
{
@@ -4241,7 +4242,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
if (cmd_match(page, "idle") || cmd_match(page, "frozen")) {
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- reap_sync_thread(mddev);
+ md_reap_sync_thread(mddev);
}
} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
@@ -5279,7 +5280,7 @@ static void __md_stop_writes(struct mddev *mddev)
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- reap_sync_thread(mddev);
+ md_reap_sync_thread(mddev);
}
del_timer_sync(&mddev->safemode_timer);
@@ -5287,7 +5288,8 @@ static void __md_stop_writes(struct mddev *mddev)
bitmap_flush(mddev);
md_super_wait(mddev);
- if (!mddev->in_sync || mddev->flags) {
+ if (mddev->ro == 0 &&
+ (!mddev->in_sync || mddev->flags)) {
/* mark array as shutdown cleanly */
mddev->in_sync = 1;
md_update_sb(mddev, 1);
@@ -5810,7 +5812,7 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
else
sysfs_notify_dirent_safe(rdev->sysfs_state);
- md_update_sb(mddev, 1);
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
if (mddev->degraded)
set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -5877,6 +5879,9 @@ static int hot_remove_disk(struct mddev * mddev, dev_t dev)
if (!rdev)
return -ENXIO;
+ clear_bit(Blocked, &rdev->flags);
+ remove_and_add_spares(mddev, rdev);
+
if (rdev->raid_disk >= 0)
goto busy;
@@ -6490,6 +6495,28 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
err = md_set_readonly(mddev, bdev);
goto done_unlock;
+ case HOT_REMOVE_DISK:
+ err = hot_remove_disk(mddev, new_decode_dev(arg));
+ goto done_unlock;
+
+ case ADD_NEW_DISK:
+ /* We can support ADD_NEW_DISK on read-only arrays
+ * on if we are re-adding a preexisting device.
+ * So require mddev->pers and MD_DISK_SYNC.
+ */
+ if (mddev->pers) {
+ mdu_disk_info_t info;
+ if (copy_from_user(&info, argp, sizeof(info)))
+ err = -EFAULT;
+ else if (!(info.state & (1<<MD_DISK_SYNC)))
+ /* Need to clear read-only for this */
+ break;
+ else
+ err = add_new_disk(mddev, &info);
+ goto done_unlock;
+ }
+ break;
+
case BLKROSET:
if (get_user(ro, (int __user *)(arg))) {
err = -EFAULT;
@@ -6560,10 +6587,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
goto done_unlock;
}
- case HOT_REMOVE_DISK:
- err = hot_remove_disk(mddev, new_decode_dev(arg));
- goto done_unlock;
-
case HOT_ADD_DISK:
err = hot_add_disk(mddev, new_decode_dev(arg));
goto done_unlock;
@@ -7644,14 +7667,16 @@ void md_do_sync(struct md_thread *thread)
}
EXPORT_SYMBOL_GPL(md_do_sync);
-static int remove_and_add_spares(struct mddev *mddev)
+static int remove_and_add_spares(struct mddev *mddev,
+ struct md_rdev *this)
{
struct md_rdev *rdev;
int spares = 0;
int removed = 0;
rdev_for_each(rdev, mddev)
- if (rdev->raid_disk >= 0 &&
+ if ((this == NULL || rdev == this) &&
+ rdev->raid_disk >= 0 &&
!test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
@@ -7666,74 +7691,52 @@ static int remove_and_add_spares(struct mddev *mddev)
if (removed && mddev->kobj.sd)
sysfs_notify(&mddev->kobj, NULL, "degraded");
+ if (this)
+ goto no_add;
+
rdev_for_each(rdev, mddev) {
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
!test_bit(Faulty, &rdev->flags))
spares++;
- if (rdev->raid_disk < 0
- && !test_bit(Faulty, &rdev->flags)) {
- rdev->recovery_offset = 0;
- if (mddev->pers->
- hot_add_disk(mddev, rdev) == 0) {
- if (sysfs_link_rdev(mddev, rdev))
- /* failure here is OK */;
- spares++;
- md_new_event(mddev);
- set_bit(MD_CHANGE_DEVS, &mddev->flags);
- }
+ if (rdev->raid_disk >= 0)
+ continue;
+ if (test_bit(Faulty, &rdev->flags))
+ continue;
+ if (mddev->ro &&
+ rdev->saved_raid_disk < 0)
+ continue;
+
+ rdev->recovery_offset = 0;
+ if (rdev->saved_raid_disk >= 0 && mddev->in_sync) {
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->in_sync)
+ /* OK, this device, which is in_sync,
+ * will definitely be noticed before
+ * the next write, so recovery isn't
+ * needed.
+ */
+ rdev->recovery_offset = mddev->recovery_cp;
+ spin_unlock_irq(&mddev->write_lock);
+ }
+ if (mddev->ro && rdev->recovery_offset != MaxSector)
+ /* not safe to add this disk now */
+ continue;
+ if (mddev->pers->
+ hot_add_disk(mddev, rdev) == 0) {
+ if (sysfs_link_rdev(mddev, rdev))
+ /* failure here is OK */;
+ spares++;
+ md_new_event(mddev);
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
}
}
+no_add:
if (removed)
set_bit(MD_CHANGE_DEVS, &mddev->flags);
return spares;
}
-static void reap_sync_thread(struct mddev *mddev)
-{
- struct md_rdev *rdev;
-
- /* resync has finished, collect result */
- md_unregister_thread(&mddev->sync_thread);
- if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
- !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
- /* success...*/
- /* activate any spares */
- if (mddev->pers->spare_active(mddev)) {
- sysfs_notify(&mddev->kobj, NULL,
- "degraded");
- set_bit(MD_CHANGE_DEVS, &mddev->flags);
- }
- }
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- mddev->pers->finish_reshape)
- mddev->pers->finish_reshape(mddev);
-
- /* If array is no-longer degraded, then any saved_raid_disk
- * information must be scrapped. Also if any device is now
- * In_sync we must scrape the saved_raid_disk for that device
- * do the superblock for an incrementally recovered device
- * written out.
- */
- rdev_for_each(rdev, mddev)
- if (!mddev->degraded ||
- test_bit(In_sync, &rdev->flags))
- rdev->saved_raid_disk = -1;
-
- md_update_sb(mddev, 1);
- clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
- clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
- clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
- clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
- clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
- /* flag recovery needed just to double check */
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- sysfs_notify_dirent_safe(mddev->sysfs_action);
- md_new_event(mddev);
- if (mddev->event_work.func)
- queue_work(md_misc_wq, &mddev->event_work);
-}
-
/*
* This routine is regularly called by all per-raid-array threads to
* deal with generic issues like resync and super-block update.
@@ -7789,22 +7792,16 @@ void md_check_recovery(struct mddev *mddev)
int spares = 0;
if (mddev->ro) {
- /* Only thing we do on a ro array is remove
- * failed devices.
+ /* On a read-only array we can:
+ * - remove failed devices
+ * - add already-in_sync devices if the array itself
+ * is in-sync.
+ * As we only add devices that are already in-sync,
+ * we can activate the spares immediately.
*/
- struct md_rdev *rdev;
- rdev_for_each(rdev, mddev)
- if (rdev->raid_disk >= 0 &&
- !test_bit(Blocked, &rdev->flags) &&
- test_bit(Faulty, &rdev->flags) &&
- atomic_read(&rdev->nr_pending)==0) {
- if (mddev->pers->hot_remove_disk(
- mddev, rdev) == 0) {
- sysfs_unlink_rdev(mddev, rdev);
- rdev->raid_disk = -1;
- }
- }
clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ remove_and_add_spares(mddev, NULL);
+ mddev->pers->spare_active(mddev);
goto unlock;
}
@@ -7836,7 +7833,7 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
}
if (mddev->sync_thread) {
- reap_sync_thread(mddev);
+ md_reap_sync_thread(mddev);
goto unlock;
}
/* Set RUNNING before clearing NEEDED to avoid
@@ -7867,7 +7864,7 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
- } else if ((spares = remove_and_add_spares(mddev))) {
+ } else if ((spares = remove_and_add_spares(mddev, NULL))) {
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
@@ -7917,6 +7914,51 @@ void md_check_recovery(struct mddev *mddev)
}
}
+void md_reap_sync_thread(struct mddev *mddev)
+{
+ struct md_rdev *rdev;
+
+ /* resync has finished, collect result */
+ md_unregister_thread(&mddev->sync_thread);
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+ /* success...*/
+ /* activate any spares */
+ if (mddev->pers->spare_active(mddev)) {
+ sysfs_notify(&mddev->kobj, NULL,
+ "degraded");
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ }
+ }
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ mddev->pers->finish_reshape)
+ mddev->pers->finish_reshape(mddev);
+
+ /* If array is no-longer degraded, then any saved_raid_disk
+ * information must be scrapped. Also if any device is now
+ * In_sync we must scrape the saved_raid_disk for that device
+ * do the superblock for an incrementally recovered device
+ * written out.
+ */
+ rdev_for_each(rdev, mddev)
+ if (!mddev->degraded ||
+ test_bit(In_sync, &rdev->flags))
+ rdev->saved_raid_disk = -1;
+
+ md_update_sb(mddev, 1);
+ clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ /* flag recovery needed just to double check */
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ sysfs_notify_dirent_safe(mddev->sysfs_action);
+ md_new_event(mddev);
+ if (mddev->event_work.func)
+ queue_work(md_misc_wq, &mddev->event_work);
+}
+
void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev)
{
sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8642,6 +8684,7 @@ EXPORT_SYMBOL(md_register_thread);
EXPORT_SYMBOL(md_unregister_thread);
EXPORT_SYMBOL(md_wakeup_thread);
EXPORT_SYMBOL(md_check_recovery);
+EXPORT_SYMBOL(md_reap_sync_thread);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MD RAID framework");
MODULE_ALIAS("md");
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d90fb1a879e1..653f992b687a 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -567,6 +567,7 @@ extern struct md_thread *md_register_thread(
extern void md_unregister_thread(struct md_thread **threadp);
extern void md_wakeup_thread(struct md_thread *thread);
extern void md_check_recovery(struct mddev *mddev);
+extern void md_reap_sync_thread(struct mddev *mddev);
extern void md_write_start(struct mddev *mddev, struct bio *bi);
extern void md_write_end(struct mddev *mddev);
extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index fd86b372692d..851023e2ba5d 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -981,7 +981,12 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
while (bio) { /* submit pending writes */
struct bio *next = bio->bi_next;
bio->bi_next = NULL;
- generic_make_request(bio);
+ if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+ !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+ /* Just ignore it */
+ bio_endio(bio, 0);
+ else
+ generic_make_request(bio);
bio = next;
}
kfree(plug);
@@ -2901,6 +2906,7 @@ static int stop(struct mddev *mddev)
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
+ safe_put_page(conf->tmppage);
kfree(conf->poolinfo);
kfree(conf);
mddev->private = NULL;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 77b562d18a90..018741ba9310 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1133,7 +1133,12 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
while (bio) { /* submit pending writes */
struct bio *next = bio->bi_next;
bio->bi_next = NULL;
- generic_make_request(bio);
+ if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+ !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+ /* Just ignore it */
+ bio_endio(bio, 0);
+ else
+ generic_make_request(bio);
bio = next;
}
kfree(plug);
@@ -2913,6 +2918,22 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
if (init_resync(conf))
return 0;
+ /*
+ * Allow skipping a full rebuild for incremental assembly
+ * of a clean array, like RAID1 does.
+ */
+ if (mddev->bitmap == NULL &&
+ mddev->recovery_cp == MaxSector &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+ conf->fullsync == 0) {
+ *skipped = 1;
+ max_sector = mddev->dev_sectors;
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ max_sector = mddev->resync_max_sectors;
+ return max_sector - sector_nr;
+ }
+
skipped:
max_sector = mddev->dev_sectors;
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
@@ -3810,6 +3831,7 @@ static int stop(struct mddev *mddev)
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
+ safe_put_page(conf->tmppage);
kfree(conf->mirrors);
kfree(conf);
mddev->private = NULL;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 24909eb13fec..4a7be455d6d8 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -184,6 +184,8 @@ static void return_io(struct bio *return_bi)
return_bi = bi->bi_next;
bi->bi_next = NULL;
bi->bi_size = 0;
+ trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+ bi, 0);
bio_endio(bi, 0);
bi = return_bi;
}
@@ -1885,8 +1887,15 @@ static void raid5_end_write_request(struct bio *bi, int error)
&rdev->mddev->recovery);
} else if (is_badblock(rdev, sh->sector,
STRIPE_SECTORS,
- &first_bad, &bad_sectors))
+ &first_bad, &bad_sectors)) {
set_bit(R5_MadeGood, &sh->dev[i].flags);
+ if (test_bit(R5_ReadError, &sh->dev[i].flags))
+ /* That was a successful write so make
+ * sure it looks like we already did
+ * a re-write.
+ */
+ set_bit(R5_ReWrite, &sh->dev[i].flags);
+ }
}
rdev_dec_pending(rdev, conf->mddev);
@@ -3914,6 +3923,8 @@ static void raid5_align_endio(struct bio *bi, int error)
rdev_dec_pending(rdev, conf->mddev);
if (!error && uptodate) {
+ trace_block_bio_complete(bdev_get_queue(raid_bi->bi_bdev),
+ raid_bi, 0);
bio_endio(raid_bi, 0);
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_stripe);
@@ -4382,6 +4393,8 @@ static void make_request(struct mddev *mddev, struct bio * bi)
if ( rw == WRITE )
md_write_end(mddev);
+ trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
+ bi, 0);
bio_endio(bi, 0);
}
}
@@ -4666,9 +4679,10 @@ static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int
*skipped = 1;
return rv;
}
- if (!bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
- !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
- !conf->fullsync && sync_blocks >= STRIPE_SECTORS) {
+ if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+ !conf->fullsync &&
+ !bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 1) &&
+ sync_blocks >= STRIPE_SECTORS) {
/* we can skip this block, and probably more */
sync_blocks /= STRIPE_SECTORS;
*skipped = 1;
@@ -4758,8 +4772,11 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
handled++;
}
remaining = raid5_dec_bi_active_stripes(raid_bio);
- if (remaining == 0)
+ if (remaining == 0) {
+ trace_block_bio_complete(bdev_get_queue(raid_bio->bi_bdev),
+ raid_bio, 0);
bio_endio(raid_bio, 0);
+ }
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_stripe);
return handled;
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 56c25e6299e9..b85f88c8ddbd 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -16,6 +16,10 @@ config VIDEO_TVEEPROM
tristate
depends on I2C
+config CYPRESS_FIRMWARE
+ tristate "Cypress firmware helper routines"
+ depends on USB
+
source "drivers/media/common/b2c2/Kconfig"
source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 8f8d18755d15..d208de3b7cc0 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -2,3 +2,4 @@ obj-y += b2c2/ saa7146/ siano/
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
+obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c
index 850a6c606750..7e14e90d2922 100644
--- a/drivers/media/common/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c
@@ -325,7 +325,7 @@ static int skystar2_rev27_attach(struct flexcop_device *fc,
/* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
- 0x08, 1, 1)) {
+ 0x08, 1, 1, false)) {
err("ISL6421 could NOT be attached");
goto fail_isl;
}
@@ -391,7 +391,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc,
fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
- 0x08, 0, 0)) {
+ 0x08, 0, 0, false)) {
err("ISL6421 could NOT be attached");
fc->fc_i2c_adap[2].no_base_addr = 0;
return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/common/cypress_firmware.c
index 211df549f26a..577e82058fdc 100644
--- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c
+++ b/drivers/media/common/cypress_firmware.c
@@ -8,7 +8,10 @@
*
*/
-#include "dvb_usb.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
#include "cypress_firmware.h"
struct usb_cypress_controller {
@@ -30,14 +33,42 @@ static const struct usb_cypress_controller cypress[] = {
static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
u8 len)
{
- dvb_usb_dbg_usb_control_msg(udev,
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len);
-
return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
}
-int usbv2_cypress_load_firmware(struct usb_device *udev,
+static int cypress_get_hexline(const struct firmware *fw,
+ struct hexline *hx, int *pos)
+{
+ u8 *b = (u8 *) &fw->data[*pos];
+ int data_offs = 4;
+
+ if (*pos >= fw->size)
+ return 0;
+
+ memset(hx, 0, sizeof(struct hexline));
+ hx->len = b[0];
+
+ if ((*pos + hx->len + 4) >= fw->size)
+ return -EINVAL;
+
+ hx->addr = b[1] | (b[2] << 8);
+ hx->type = b[3];
+
+ if (hx->type == 0x04) {
+ /* b[4] and b[5] are the Extended linear address record data
+ * field */
+ hx->addr |= (b[4] << 24) | (b[5] << 16);
+ }
+
+ memcpy(hx->data, &b[data_offs], hx->len);
+ hx->chk = b[hx->len + data_offs];
+ *pos += hx->len + 5;
+
+ return *pos;
+}
+
+int cypress_load_firmware(struct usb_device *udev,
const struct firmware *fw, int type)
{
struct hexline *hx;
@@ -61,7 +92,7 @@ int usbv2_cypress_load_firmware(struct usb_device *udev,
/* write firmware to memory */
for (;;) {
- ret = dvb_usbv2_get_hexline(fw, hx, &pos);
+ ret = cypress_get_hexline(fw, hx, &pos);
if (ret < 0)
goto err_kfree;
else if (ret == 0)
@@ -71,9 +102,8 @@ int usbv2_cypress_load_firmware(struct usb_device *udev,
if (ret < 0) {
goto err_kfree;
} else if (ret != hx->len) {
- dev_err(&udev->dev, "%s: error while transferring " \
- "firmware (transferred size=%d, " \
- "block size=%d)\n",
+ dev_err(&udev->dev,
+ "%s: error while transferring firmware (transferred size=%d, block size=%d)\n",
KBUILD_MODNAME, ret, hx->len);
ret = -EIO;
goto err_kfree;
@@ -95,39 +125,7 @@ err_kfree:
kfree(hx);
return ret;
}
-EXPORT_SYMBOL(usbv2_cypress_load_firmware);
-
-int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
- int *pos)
-{
- u8 *b = (u8 *) &fw->data[*pos];
- int data_offs = 4;
-
- if (*pos >= fw->size)
- return 0;
-
- memset(hx, 0, sizeof(struct hexline));
- hx->len = b[0];
-
- if ((*pos + hx->len + 4) >= fw->size)
- return -EINVAL;
-
- hx->addr = b[1] | (b[2] << 8);
- hx->type = b[3];
-
- if (hx->type == 0x04) {
- /* b[4] and b[5] are the Extended linear address record data
- * field */
- hx->addr |= (b[4] << 24) | (b[5] << 16);
- }
-
- memcpy(hx->data, &b[data_offs], hx->len);
- hx->chk = b[hx->len + data_offs];
- *pos += hx->len + 5;
-
- return *pos;
-}
-EXPORT_SYMBOL(dvb_usbv2_get_hexline);
+EXPORT_SYMBOL(cypress_load_firmware);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Cypress firmware download");
diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/common/cypress_firmware.h
index 80085fd4132c..e493cbc7a528 100644
--- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h
+++ b/drivers/media/common/cypress_firmware.h
@@ -1,5 +1,4 @@
-/* cypress_firmware.h is part of the DVB USB library.
- *
+/*
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
@@ -23,9 +22,7 @@ struct hexline {
u8 data[255];
u8 chk;
};
-extern int usbv2_cypress_load_firmware(struct usb_device *,
- const struct firmware *, int);
-extern int dvb_usbv2_get_hexline(const struct firmware *,
- struct hexline *, int *);
+
+int cypress_load_firmware(struct usb_device *, const struct firmware *, int);
#endif
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 4143d61f79b1..fe907f2e8f59 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -832,7 +832,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
}
*/
-static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
@@ -856,7 +856,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
}
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
- if (*id & dev->ext_vv_data->stds[i].id)
+ if (id & dev->ext_vv_data->stds[i].id)
break;
if (i != dev->ext_vv_data->num_stds) {
vv->standard = &dev->ext_vv_data->stds[i];
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
index 68f0f604678e..f3f5ec44e685 100644
--- a/drivers/media/common/siano/Kconfig
+++ b/drivers/media/common/siano/Kconfig
@@ -17,3 +17,15 @@ config SMS_SIANO_RC
default y
---help---
Choose Y to select Remote Controller support for Siano driver.
+
+config SMS_SIANO_DEBUGFS
+ bool "Enable debugfs for smsdvb"
+ depends on SMS_SIANO_MDTV
+ depends on DEBUG_FS
+ depends on SMS_USB_DRV
+ ---help---
+ Choose Y to enable visualizing a dump of the frontend
+ statistics response packets via debugfs. Currently, works
+ only with Siano USB devices.
+
+ Useful only for developers. In doubt, say N.
diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile
index 81b1e985bea5..4c0567f106b2 100644
--- a/drivers/media/common/siano/Makefile
+++ b/drivers/media/common/siano/Makefile
@@ -1,4 +1,5 @@
smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o
+smsdvb-objs := smsdvb-main.o
obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
@@ -6,6 +7,10 @@ ifeq ($(CONFIG_SMS_SIANO_RC),y)
smsmdtv-objs += smsir.o
endif
+ifeq ($(CONFIG_SMS_SIANO_DEBUGFS),y)
+ smsdvb-objs += smsdvb-debugfs.o
+endif
+
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index 680c781c8dd6..82769993eeb7 100644
--- a/drivers/media/common/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
@@ -28,43 +28,53 @@ MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
static struct sms_board sms_boards[] = {
[SMS_BOARD_UNKNOWN] = {
.name = "Unknown board",
+ .type = SMS_UNKNOWN_TYPE,
+ .default_mode = DEVICE_MODE_NONE,
},
[SMS1XXX_BOARD_SIANO_STELLAR] = {
.name = "Siano Stellar Digital Receiver",
.type = SMS_STELLAR,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_SIANO_NOVA_A] = {
.name = "Siano Nova A Digital Receiver",
.type = SMS_NOVA_A0,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_SIANO_NOVA_B] = {
.name = "Siano Nova B Digital Receiver",
.type = SMS_NOVA_B0,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_SIANO_VEGA] = {
.name = "Siano Vega Digital Receiver",
.type = SMS_VEGA,
+ .default_mode = DEVICE_MODE_CMMB,
},
[SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
.name = "Hauppauge Catamount",
.type = SMS_STELLAR,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_STELLAR,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
.name = "Hauppauge Okemo-A",
.type = SMS_NOVA_A0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_A,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
.name = "Hauppauge Okemo-B",
.type = SMS_NOVA_B0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_B,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
- .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .fw[DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_HCW_55XXX,
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
.rc_codes = RC_MAP_HAUPPAUGE,
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
@@ -77,7 +87,8 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
.name = "Hauppauge WinTV MiniCard",
.type = SMS_NOVA_B0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
.lna_ctrl = 29,
.board_cfg.foreign_lna0_ctrl = 29,
.rf_switch = 17,
@@ -86,18 +97,65 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
.name = "Hauppauge WinTV MiniCard",
.type = SMS_NOVA_B0,
- .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
.lna_ctrl = -1,
},
[SMS1XXX_BOARD_SIANO_NICE] = {
- /* 11 */
.name = "Siano Nice Digital Receiver",
.type = SMS_NOVA_B0,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
},
[SMS1XXX_BOARD_SIANO_VENICE] = {
- /* 12 */
.name = "Siano Venice Digital Receiver",
.type = SMS_VEGA,
+ .default_mode = DEVICE_MODE_CMMB,
+ },
+ [SMS1XXX_BOARD_SIANO_STELLAR_ROM] = {
+ .name = "Siano Stellar Digital Receiver ROM",
+ .type = SMS_STELLAR,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
+ .intf_num = 1,
+ },
+ [SMS1XXX_BOARD_ZTE_DVB_DATA_CARD] = {
+ .name = "ZTE Data Card Digital Receiver",
+ .type = SMS_NOVA_B0,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
+ .intf_num = 5,
+ .mtu = 15792,
+ },
+ [SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD] = {
+ .name = "ONDA Data Card Digital Receiver",
+ .type = SMS_NOVA_B0,
+ .default_mode = DEVICE_MODE_DVBT_BDA,
+ .intf_num = 6,
+ .mtu = 15792,
+ },
+ [SMS1XXX_BOARD_SIANO_MING] = {
+ .name = "Siano Ming Digital Receiver",
+ .type = SMS_MING,
+ .default_mode = DEVICE_MODE_CMMB,
+ },
+ [SMS1XXX_BOARD_SIANO_PELE] = {
+ .name = "Siano Pele Digital Receiver",
+ .type = SMS_PELE,
+ .default_mode = DEVICE_MODE_ISDBT_BDA,
+ },
+ [SMS1XXX_BOARD_SIANO_RIO] = {
+ .name = "Siano Rio Digital Receiver",
+ .type = SMS_RIO,
+ .default_mode = DEVICE_MODE_ISDBT_BDA,
+ },
+ [SMS1XXX_BOARD_SIANO_DENVER_1530] = {
+ .name = "Siano Denver (ATSC-M/H) Digital Receiver",
+ .type = SMS_DENVER_1530,
+ .default_mode = DEVICE_MODE_ATSC,
+ .crystal = 2400,
+ },
+ [SMS1XXX_BOARD_SIANO_DENVER_2160] = {
+ .name = "Siano Denver (TDMB) Digital Receiver",
+ .type = SMS_DENVER_2160,
+ .default_mode = DEVICE_MODE_DAB_TDMB,
},
};
@@ -109,20 +167,21 @@ struct sms_board *sms_get_board(unsigned id)
}
EXPORT_SYMBOL_GPL(sms_get_board);
static inline void sms_gpio_assign_11xx_default_led_config(
- struct smscore_gpio_config *pGpioConfig) {
- pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
- pGpioConfig->InputCharacteristics =
- SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
- pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
- pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
- pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+ struct smscore_config_gpio *p_gpio_config) {
+ p_gpio_config->direction = SMS_GPIO_DIRECTION_OUTPUT;
+ p_gpio_config->inputcharacteristics =
+ SMS_GPIO_INPUTCHARACTERISTICS_NORMAL;
+ p_gpio_config->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA;
+ p_gpio_config->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+ p_gpio_config->pullupdown = SMS_GPIO_PULLUPDOWN_NONE;
}
int sms_board_event(struct smscore_device_t *coredev,
- enum SMS_BOARD_EVENTS gevent) {
- struct smscore_gpio_config MyGpioConfig;
+ enum SMS_BOARD_EVENTS gevent)
+{
+ struct smscore_config_gpio my_gpio_config;
- sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+ sms_gpio_assign_11xx_default_led_config(&my_gpio_config);
switch (gevent) {
case BOARD_EVENT_POWER_INIT: /* including hotplug */
@@ -182,8 +241,8 @@ static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
.direction = SMS_GPIO_DIRECTION_OUTPUT,
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
- .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
- .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
+ .outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_FAST,
+ .outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA,
};
if (pin == 0)
@@ -293,19 +352,7 @@ EXPORT_SYMBOL_GPL(sms_board_lna_control);
int sms_board_load_modules(int id)
{
- switch (id) {
- case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
- case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
- case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
- case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
- case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
- case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
- request_module("smsdvb");
- break;
- default:
- /* do nothing */
- break;
- }
+ request_module("smsdvb");
return 0;
}
EXPORT_SYMBOL_GPL(sms_board_load_modules);
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
index d8cdf756f7cf..c63b544c49c5 100644
--- a/drivers/media/common/siano/sms-cards.h
+++ b/drivers/media/common/siano/sms-cards.h
@@ -37,6 +37,14 @@
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
#define SMS1XXX_BOARD_SIANO_NICE 11
#define SMS1XXX_BOARD_SIANO_VENICE 12
+#define SMS1XXX_BOARD_SIANO_STELLAR_ROM 13
+#define SMS1XXX_BOARD_ZTE_DVB_DATA_CARD 14
+#define SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD 15
+#define SMS1XXX_BOARD_SIANO_MING 16
+#define SMS1XXX_BOARD_SIANO_PELE 17
+#define SMS1XXX_BOARD_SIANO_RIO 18
+#define SMS1XXX_BOARD_SIANO_DENVER_1530 19
+#define SMS1XXX_BOARD_SIANO_DENVER_2160 20
struct sms_board_gpio_cfg {
int lna_vhf_exist;
@@ -79,6 +87,12 @@ struct sms_board {
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
+
+ char intf_num;
+ int default_mode;
+ unsigned int mtu;
+ unsigned int crystal;
+ struct sms_antenna_config_ST *antenna_config;
};
struct sms_board *sms_get_board(unsigned id);
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 1842e64e6338..45ac9eea4882 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -37,7 +37,6 @@
#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsir.h"
-#include "smsendian.h"
static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
@@ -58,11 +57,350 @@ struct smscore_client_t {
struct list_head entry;
struct smscore_device_t *coredev;
void *context;
- struct list_head idlist;
- onresponse_t onresponse_handler;
+ struct list_head idlist;
+ onresponse_t onresponse_handler;
onremove_t onremove_handler;
};
+static char *siano_msgs[] = {
+ [MSG_TYPE_BASE_VAL - MSG_TYPE_BASE_VAL] = "MSG_TYPE_BASE_VAL",
+ [MSG_SMS_GET_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_REQ",
+ [MSG_SMS_GET_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_RES",
+ [MSG_SMS_MULTI_BRIDGE_CFG - MSG_TYPE_BASE_VAL] = "MSG_SMS_MULTI_BRIDGE_CFG",
+ [MSG_SMS_GPIO_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_REQ",
+ [MSG_SMS_GPIO_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_RES",
+ [MSG_SMS_GPIO_SET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_REQ",
+ [MSG_SMS_GPIO_SET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_RES",
+ [MSG_SMS_GPIO_GET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_REQ",
+ [MSG_SMS_GPIO_GET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_RES",
+ [MSG_SMS_EEPROM_BURN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_BURN_IND",
+ [MSG_SMS_LOG_ENABLE_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_REQ",
+ [MSG_SMS_LOG_ENABLE_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_RES",
+ [MSG_SMS_SET_MAX_TX_MSG_LEN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_REQ",
+ [MSG_SMS_SET_MAX_TX_MSG_LEN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_RES",
+ [MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE",
+ [MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST",
+ [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ",
+ [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES",
+ [MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND",
+ [MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND",
+ [MSG_SMS_CONFIGURE_RF_SWITCH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_REQ",
+ [MSG_SMS_CONFIGURE_RF_SWITCH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_RES",
+ [MSG_SMS_MRC_PATH_DISCONNECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_REQ",
+ [MSG_SMS_MRC_PATH_DISCONNECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_RES",
+ [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ",
+ [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES",
+ [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ",
+ [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES",
+ [MSG_WR_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_REQ",
+ [MSG_WR_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_RES",
+ [MSG_RD_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_REQ",
+ [MSG_RD_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_RES",
+ [MSG_RD_REG_ALL_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_REQ",
+ [MSG_RD_REG_ALL_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_RES",
+ [MSG_HELP_INT - MSG_TYPE_BASE_VAL] = "MSG_HELP_INT",
+ [MSG_RUN_SCRIPT_INT - MSG_TYPE_BASE_VAL] = "MSG_RUN_SCRIPT_INT",
+ [MSG_SMS_EWS_INBAND_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_REQ",
+ [MSG_SMS_EWS_INBAND_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_RES",
+ [MSG_SMS_RFS_SELECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_REQ",
+ [MSG_SMS_RFS_SELECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_RES",
+ [MSG_SMS_MB_GET_VER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_REQ",
+ [MSG_SMS_MB_GET_VER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_RES",
+ [MSG_SMS_MB_WRITE_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_REQ",
+ [MSG_SMS_MB_WRITE_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_RES",
+ [MSG_SMS_MB_READ_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_REQ",
+ [MSG_SMS_MB_READ_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_RES",
+ [MSG_SMS_RD_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_REQ",
+ [MSG_SMS_RD_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_RES",
+ [MSG_SMS_WR_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_REQ",
+ [MSG_SMS_WR_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_RES",
+ [MSG_SMS_UPDATE_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_REQ",
+ [MSG_SMS_UPDATE_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_RES",
+ [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ",
+ [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES",
+ [MSG_SMS_RF_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_REQ",
+ [MSG_SMS_RF_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_RES",
+ [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ",
+ [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES",
+ [MSG_SMS_ISDBT_SB_RECEPTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_REQ",
+ [MSG_SMS_ISDBT_SB_RECEPTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_RES",
+ [MSG_SMS_GENERIC_EPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_REQ",
+ [MSG_SMS_GENERIC_EPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_RES",
+ [MSG_SMS_GENERIC_EPROM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_REQ",
+ [MSG_SMS_GENERIC_EPROM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_RES",
+ [MSG_SMS_EEPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_REQ",
+ [MSG_SMS_EEPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_RES",
+ [MSG_SMS_CUSTOM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_REQ",
+ [MSG_SMS_CUSTOM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_RES",
+ [MSG_SMS_CUSTOM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_REQ",
+ [MSG_SMS_CUSTOM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_RES",
+ [MSG_SMS_INIT_DEVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_REQ",
+ [MSG_SMS_INIT_DEVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_RES",
+ [MSG_SMS_ATSC_SET_ALL_IP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_REQ",
+ [MSG_SMS_ATSC_SET_ALL_IP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_RES",
+ [MSG_SMS_ATSC_START_ENSEMBLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_REQ",
+ [MSG_SMS_ATSC_START_ENSEMBLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_RES",
+ [MSG_SMS_SET_OUTPUT_MODE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_REQ",
+ [MSG_SMS_SET_OUTPUT_MODE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_RES",
+ [MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES",
+ [MSG_SMS_SUB_CHANNEL_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_REQ",
+ [MSG_SMS_SUB_CHANNEL_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_RES",
+ [MSG_SMS_SUB_CHANNEL_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_REQ",
+ [MSG_SMS_SUB_CHANNEL_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_RES",
+ [MSG_SMS_ATSC_IP_FILTER_ADD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_ADD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_RES",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_RES",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ",
+ [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES",
+ [MSG_SMS_WAIT_CMD - MSG_TYPE_BASE_VAL] = "MSG_SMS_WAIT_CMD",
+ [MSG_SMS_ADD_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_REQ",
+ [MSG_SMS_ADD_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_RES",
+ [MSG_SMS_REMOVE_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_REQ",
+ [MSG_SMS_REMOVE_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_RES",
+ [MSG_SMS_FAST_INFORMATION_CHANNEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_REQ",
+ [MSG_SMS_FAST_INFORMATION_CHANNEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_RES",
+ [MSG_SMS_DAB_CHANNEL - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_CHANNEL",
+ [MSG_SMS_GET_PID_FILTER_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_REQ",
+ [MSG_SMS_GET_PID_FILTER_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_RES",
+ [MSG_SMS_POWER_DOWN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_REQ",
+ [MSG_SMS_POWER_DOWN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_RES",
+ [MSG_SMS_ATSC_SLT_EXIST_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SLT_EXIST_IND",
+ [MSG_SMS_ATSC_NO_SLT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_NO_SLT_IND",
+ [MSG_SMS_GET_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_REQ",
+ [MSG_SMS_GET_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_RES",
+ [MSG_SMS_SEND_DUMP - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_DUMP",
+ [MSG_SMS_SCAN_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_REQ",
+ [MSG_SMS_SCAN_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_RES",
+ [MSG_SMS_SCAN_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_REQ",
+ [MSG_SMS_SCAN_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_RES",
+ [MSG_SMS_SCAN_PROGRESS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_PROGRESS_IND",
+ [MSG_SMS_SCAN_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_COMPLETE_IND",
+ [MSG_SMS_LOG_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ITEM",
+ [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ",
+ [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES",
+ [MSG_SMS_HO_PER_SLICES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PER_SLICES_IND",
+ [MSG_SMS_HO_INBAND_POWER_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_INBAND_POWER_IND",
+ [MSG_SMS_MANUAL_DEMOD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MANUAL_DEMOD_REQ",
+ [MSG_SMS_HO_TUNE_ON_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_REQ",
+ [MSG_SMS_HO_TUNE_ON_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_RES",
+ [MSG_SMS_HO_TUNE_OFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_REQ",
+ [MSG_SMS_HO_TUNE_OFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_RES",
+ [MSG_SMS_HO_PEEK_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_REQ",
+ [MSG_SMS_HO_PEEK_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_RES",
+ [MSG_SMS_HO_PEEK_FREQ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_IND",
+ [MSG_SMS_MB_ATTEN_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_REQ",
+ [MSG_SMS_MB_ATTEN_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_RES",
+ [MSG_SMS_ENABLE_STAT_IN_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_REQ",
+ [MSG_SMS_ENABLE_STAT_IN_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_RES",
+ [MSG_SMS_SET_ANTENNA_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_REQ",
+ [MSG_SMS_SET_ANTENNA_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_RES",
+ [MSG_SMS_GET_STATISTICS_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_REQ",
+ [MSG_SMS_GET_STATISTICS_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_RES",
+ [MSG_SMS_SLEEP_RESUME_COMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLEEP_RESUME_COMP_IND",
+ [MSG_SMS_SWITCH_HOST_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_REQ",
+ [MSG_SMS_SWITCH_HOST_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_RES",
+ [MSG_SMS_DATA_DOWNLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_REQ",
+ [MSG_SMS_DATA_DOWNLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_RES",
+ [MSG_SMS_DATA_VALIDITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_REQ",
+ [MSG_SMS_DATA_VALIDITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_RES",
+ [MSG_SMS_SWDOWNLOAD_TRIGGER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_REQ",
+ [MSG_SMS_SWDOWNLOAD_TRIGGER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_RES",
+ [MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ",
+ [MSG_SMS_SWDOWNLOAD_BACKDOOR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_RES",
+ [MSG_SMS_GET_VERSION_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_REQ",
+ [MSG_SMS_GET_VERSION_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_RES",
+ [MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ",
+ [MSG_SMS_CLOCK_OUTPUT_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_RES",
+ [MSG_SMS_I2C_SET_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_REQ",
+ [MSG_SMS_I2C_SET_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_RES",
+ [MSG_SMS_GENERIC_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_REQ",
+ [MSG_SMS_GENERIC_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_RES",
+ [MSG_SMS_DVBT_BDA_DATA - MSG_TYPE_BASE_VAL] = "MSG_SMS_DVBT_BDA_DATA",
+ [MSG_SW_RELOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_REQ",
+ [MSG_SMS_DATA_MSG - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_MSG",
+ [MSG_TABLE_UPLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_REQ",
+ [MSG_TABLE_UPLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_RES",
+ [MSG_SW_RELOAD_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_REQ",
+ [MSG_SW_RELOAD_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_RES",
+ [MSG_SW_RELOAD_EXEC_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_REQ",
+ [MSG_SW_RELOAD_EXEC_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_RES",
+ [MSG_SMS_SPI_INT_LINE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_REQ",
+ [MSG_SMS_SPI_INT_LINE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_RES",
+ [MSG_SMS_GPIO_CONFIG_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_REQ",
+ [MSG_SMS_GPIO_CONFIG_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_RES",
+ [MSG_SMS_WATCHDOG_ACT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_REQ",
+ [MSG_SMS_WATCHDOG_ACT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_RES",
+ [MSG_SMS_LOOPBACK_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_REQ",
+ [MSG_SMS_LOOPBACK_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_RES",
+ [MSG_SMS_RAW_CAPTURE_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_REQ",
+ [MSG_SMS_RAW_CAPTURE_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_RES",
+ [MSG_SMS_RAW_CAPTURE_ABORT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_REQ",
+ [MSG_SMS_RAW_CAPTURE_ABORT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_RES",
+ [MSG_SMS_RAW_CAPTURE_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_COMPLETE_IND",
+ [MSG_SMS_DATA_PUMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_IND",
+ [MSG_SMS_DATA_PUMP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_REQ",
+ [MSG_SMS_DATA_PUMP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_RES",
+ [MSG_SMS_FLASH_DL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FLASH_DL_REQ",
+ [MSG_SMS_EXEC_TEST_1_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_REQ",
+ [MSG_SMS_EXEC_TEST_1_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_RES",
+ [MSG_SMS_ENBALE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_REQ",
+ [MSG_SMS_ENBALE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_RES",
+ [MSG_SMS_SPI_SET_BUS_WIDTH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_REQ",
+ [MSG_SMS_SPI_SET_BUS_WIDTH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_RES",
+ [MSG_SMS_SEND_EMM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_REQ",
+ [MSG_SMS_SEND_EMM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_RES",
+ [MSG_SMS_DISABLE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_REQ",
+ [MSG_SMS_DISABLE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_RES",
+ [MSG_SMS_IS_BUF_FREE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_REQ",
+ [MSG_SMS_IS_BUF_FREE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_RES",
+ [MSG_SMS_EXT_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_REQ",
+ [MSG_SMS_EXT_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_RES",
+ [MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE",
+ [MSG_SMS_BATTERY_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_REQ",
+ [MSG_SMS_BATTERY_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_RES",
+ [MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE",
+ [MSG_SMS_FM_RADIO_BLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_FM_RADIO_BLOCK_IND",
+ [MSG_SMS_HOST_NOTIFICATION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HOST_NOTIFICATION_IND",
+ [MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE",
+ [MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE",
+ [MSG_SMS_CMMB_GET_NETWORKS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_REQ",
+ [MSG_SMS_CMMB_GET_NETWORKS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_RES",
+ [MSG_SMS_CMMB_START_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_REQ",
+ [MSG_SMS_CMMB_START_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_RES",
+ [MSG_SMS_CMMB_STOP_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_REQ",
+ [MSG_SMS_CMMB_STOP_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_RES",
+ [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ",
+ [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES",
+ [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ",
+ [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES",
+ [MSG_SMS_CMMB_START_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_REQ",
+ [MSG_SMS_CMMB_START_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_RES",
+ [MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ",
+ [MSG_SMS_CMMB_STOP_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_RES",
+ [MSG_SMS_ISDBT_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_REQ",
+ [MSG_SMS_ISDBT_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_RES",
+ [MSG_SMS_TRANSMISSION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_TRANSMISSION_IND",
+ [MSG_SMS_PID_STATISTICS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_PID_STATISTICS_IND",
+ [MSG_SMS_POWER_DOWN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_IND",
+ [MSG_SMS_POWER_DOWN_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_CONF",
+ [MSG_SMS_POWER_UP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_IND",
+ [MSG_SMS_POWER_UP_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_CONF",
+ [MSG_SMS_POWER_MODE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_REQ",
+ [MSG_SMS_POWER_MODE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_RES",
+ [MSG_SMS_DEBUG_HOST_EVENT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_REQ",
+ [MSG_SMS_DEBUG_HOST_EVENT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_RES",
+ [MSG_SMS_NEW_CRYSTAL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_REQ",
+ [MSG_SMS_NEW_CRYSTAL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_RES",
+ [MSG_SMS_CONFIG_SPI_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_REQ",
+ [MSG_SMS_CONFIG_SPI_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_RES",
+ [MSG_SMS_I2C_SHORT_STAT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SHORT_STAT_IND",
+ [MSG_SMS_START_IR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_REQ",
+ [MSG_SMS_START_IR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_RES",
+ [MSG_SMS_IR_SAMPLES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_IR_SAMPLES_IND",
+ [MSG_SMS_CMMB_CA_SERVICE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_CA_SERVICE_IND",
+ [MSG_SMS_SLAVE_DEVICE_DETECTED - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLAVE_DEVICE_DETECTED",
+ [MSG_SMS_INTERFACE_LOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_LOCK_IND",
+ [MSG_SMS_INTERFACE_UNLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_UNLOCK_IND",
+ [MSG_SMS_SEND_ROSUM_BUFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_REQ",
+ [MSG_SMS_SEND_ROSUM_BUFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_RES",
+ [MSG_SMS_ROSUM_BUFF - MSG_TYPE_BASE_VAL] = "MSG_SMS_ROSUM_BUFF",
+ [MSG_SMS_SET_AES128_KEY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_REQ",
+ [MSG_SMS_SET_AES128_KEY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_RES",
+ [MSG_SMS_MBBMS_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_REQ",
+ [MSG_SMS_MBBMS_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_RES",
+ [MSG_SMS_MBBMS_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_READ_IND",
+ [MSG_SMS_IQ_STREAM_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_REQ",
+ [MSG_SMS_IQ_STREAM_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_RES",
+ [MSG_SMS_IQ_STREAM_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_REQ",
+ [MSG_SMS_IQ_STREAM_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_RES",
+ [MSG_SMS_IQ_STREAM_DATA_BLOCK - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_DATA_BLOCK",
+ [MSG_SMS_GET_EEPROM_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_REQ",
+ [MSG_SMS_GET_EEPROM_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_RES",
+ [MSG_SMS_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SIGNAL_DETECTED_IND",
+ [MSG_SMS_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_NO_SIGNAL_IND",
+ [MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ",
+ [MSG_SMS_MRC_SHUTDOWN_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_RES",
+ [MSG_SMS_MRC_BRINGUP_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_REQ",
+ [MSG_SMS_MRC_BRINGUP_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_RES",
+ [MSG_SMS_EXTERNAL_LNA_CTRL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_REQ",
+ [MSG_SMS_EXTERNAL_LNA_CTRL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_RES",
+ [MSG_SMS_SET_PERIODIC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_REQ",
+ [MSG_SMS_SET_PERIODIC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_RES",
+ [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ",
+ [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES",
+ [LOCAL_TUNE - MSG_TYPE_BASE_VAL] = "LOCAL_TUNE",
+ [LOCAL_IFFT_H_ICI - MSG_TYPE_BASE_VAL] = "LOCAL_IFFT_H_ICI",
+ [MSG_RESYNC_REQ - MSG_TYPE_BASE_VAL] = "MSG_RESYNC_REQ",
+ [MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ",
+ [MSG_SMS_CMMB_GET_MRC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_RES",
+ [MSG_SMS_LOG_EX_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_EX_ITEM",
+ [MSG_SMS_DEVICE_DATA_LOSS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEVICE_DATA_LOSS_IND",
+ [MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND",
+ [MSG_SMS_USER_MSG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_REQ",
+ [MSG_SMS_USER_MSG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_RES",
+ [MSG_SMS_SMART_CARD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_REQ",
+ [MSG_SMS_SMART_CARD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_RES",
+ [MSG_SMS_SMART_CARD_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_REQ",
+ [MSG_SMS_SMART_CARD_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_RES",
+ [MSG_SMS_SMART_CARD_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_READ_IND",
+ [MSG_SMS_TSE_ENABLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_REQ",
+ [MSG_SMS_TSE_ENABLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_RES",
+ [MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ",
+ [MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES",
+ [MSG_SMS_LED_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_REQ",
+ [MSG_SMS_LED_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_RES",
+ [MSG_PWM_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_REQ",
+ [MSG_PWM_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_RES",
+ [MSG_SMS_CMMB_SMD_SN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_REQ",
+ [MSG_SMS_CMMB_SMD_SN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_RES",
+ [MSG_SMS_CMMB_SET_CA_CW_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_REQ",
+ [MSG_SMS_CMMB_SET_CA_CW_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_RES",
+ [MSG_SMS_CMMB_SET_CA_SALT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_REQ",
+ [MSG_SMS_CMMB_SET_CA_SALT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_RES",
+ [MSG_SMS_NSCD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_REQ",
+ [MSG_SMS_NSCD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_RES",
+ [MSG_SMS_NSCD_PROCESS_SECTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_REQ",
+ [MSG_SMS_NSCD_PROCESS_SECTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_RES",
+ [MSG_SMS_DBD_CREATE_OBJECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_REQ",
+ [MSG_SMS_DBD_CREATE_OBJECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_RES",
+ [MSG_SMS_DBD_CONFIGURE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_REQ",
+ [MSG_SMS_DBD_CONFIGURE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_RES",
+ [MSG_SMS_DBD_SET_KEYS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_REQ",
+ [MSG_SMS_DBD_SET_KEYS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_RES",
+ [MSG_SMS_DBD_PROCESS_HEADER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_REQ",
+ [MSG_SMS_DBD_PROCESS_HEADER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_RES",
+ [MSG_SMS_DBD_PROCESS_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_REQ",
+ [MSG_SMS_DBD_PROCESS_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_RES",
+ [MSG_SMS_DBD_PROCESS_GET_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_REQ",
+ [MSG_SMS_DBD_PROCESS_GET_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_RES",
+ [MSG_SMS_NSCD_OPEN_SESSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_REQ",
+ [MSG_SMS_NSCD_OPEN_SESSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_RES",
+ [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ",
+ [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES",
+ [MSG_LAST_MSG_TYPE - MSG_TYPE_BASE_VAL] = "MSG_LAST_MSG_TYPE",
+};
+
+char *smscore_translate_msg(enum msg_types msgtype)
+{
+ int i = msgtype - MSG_TYPE_BASE_VAL;
+ char *msg;
+
+ if (i < 0 || i >= ARRAY_SIZE(siano_msgs))
+ return "Unknown msg type";
+
+ msg = siano_msgs[i];
+
+ if (!*msg)
+ return "Unknown msg type";
+
+ return msg;
+}
+EXPORT_SYMBOL_GPL(smscore_translate_msg);
+
void smscore_set_board_id(struct smscore_device_t *core, int id)
{
core->board_id = id;
@@ -96,7 +434,7 @@ static struct mutex g_smscore_deviceslock;
static struct list_head g_smscore_registry;
static struct mutex g_smscore_registrylock;
-static int default_mode = 4;
+static int default_mode = DEVICE_MODE_NONE;
module_param(default_mode, int, 0644);
MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
@@ -151,10 +489,10 @@ static enum sms_device_type_st smscore_registry_gettype(char *devpath)
else
sms_err("No registry found.");
- return -1;
+ return -EINVAL;
}
-void smscore_registry_setmode(char *devpath, int mode)
+static void smscore_registry_setmode(char *devpath, int mode)
{
struct smscore_registry_entry_t *entry;
@@ -294,10 +632,11 @@ static struct
smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
dma_addr_t common_buffer_phys)
{
- struct smscore_buffer_t *cb =
- kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
+ struct smscore_buffer_t *cb;
+
+ cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
if (!cb) {
- sms_info("kmalloc(...) failed");
+ sms_info("kzalloc(...) failed");
return NULL;
}
@@ -344,6 +683,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
/* init completion events */
init_completion(&dev->version_ex_done);
init_completion(&dev->data_download_done);
+ init_completion(&dev->data_validity_done);
init_completion(&dev->trigger_done);
init_completion(&dev->init_device_done);
init_completion(&dev->reload_start_done);
@@ -370,9 +710,10 @@ int smscore_register_device(struct smsdevice_params_t *params,
for (buffer = dev->common_buffer;
dev->num_buffers < params->num_buffers;
dev->num_buffers++, buffer += params->buffer_size) {
- struct smscore_buffer_t *cb =
- smscore_createbuffer(buffer, dev->common_buffer,
- dev->common_buffer_phys);
+ struct smscore_buffer_t *cb;
+
+ cb = smscore_createbuffer(buffer, dev->common_buffer,
+ dev->common_buffer_phys);
if (!cb) {
smscore_unregister_device(dev);
return -ENOMEM;
@@ -384,6 +725,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
sms_info("allocated %d buffers", dev->num_buffers);
dev->mode = DEVICE_MODE_NONE;
+ dev->board_id = SMS_BOARD_UNKNOWN;
dev->context = params->context;
dev->device = params->device;
dev->setmode_handler = params->setmode_handler;
@@ -413,7 +755,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device);
static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
void *buffer, size_t size, struct completion *completion) {
- int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+ int rc;
+
+ if (completion == NULL)
+ return -EINVAL;
+ init_completion(completion);
+
+ rc = coredev->sendrequest_handler(coredev->context, buffer, size);
if (rc < 0) {
sms_info("sendrequest returned error %d", rc);
return rc;
@@ -444,24 +792,22 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
if (rc != 0)
sms_err("Error initialization DTV IR sub-module");
else {
- buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+ buffer = kmalloc(sizeof(struct sms_msg_data2) +
SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (buffer) {
- struct SmsMsgData_ST2 *msg =
- (struct SmsMsgData_ST2 *)
+ struct sms_msg_data2 *msg =
+ (struct sms_msg_data2 *)
SMS_ALIGN_ADDRESS(buffer);
- SMS_INIT_MSG(&msg->xMsgHeader,
+ SMS_INIT_MSG(&msg->x_msg_header,
MSG_SMS_START_IR_REQ,
- sizeof(struct SmsMsgData_ST2));
- msg->msgData[0] = coredev->ir.controller;
- msg->msgData[1] = coredev->ir.timeout;
+ sizeof(struct sms_msg_data2));
+ msg->msg_data[0] = coredev->ir.controller;
+ msg->msg_data[1] = coredev->ir.timeout;
- smsendian_handle_tx_message(
- (struct SmsMsgHdr_ST2 *)msg);
rc = smscore_sendrequest_and_wait(coredev, msg,
- msg->xMsgHeader. msgLength,
+ msg->x_msg_header. msg_length,
&coredev->ir_init_done);
kfree(buffer);
@@ -476,21 +822,82 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
}
/**
+ * configures device features according to board configuration structure.
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_configure_board(struct smscore_device_t *coredev)
+{
+ struct sms_board *board;
+
+ board = sms_get_board(coredev->board_id);
+ if (!board) {
+ sms_err("no board configuration exist.");
+ return -EINVAL;
+ }
+
+ if (board->mtu) {
+ struct sms_msg_data mtu_msg;
+ sms_debug("set max transmit unit %d", board->mtu);
+
+ mtu_msg.x_msg_header.msg_src_id = 0;
+ mtu_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ mtu_msg.x_msg_header.msg_flags = 0;
+ mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
+ mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg);
+ mtu_msg.msg_data[0] = board->mtu;
+
+ coredev->sendrequest_handler(coredev->context, &mtu_msg,
+ sizeof(mtu_msg));
+ }
+
+ if (board->crystal) {
+ struct sms_msg_data crys_msg;
+ sms_debug("set crystal value %d", board->crystal);
+
+ SMS_INIT_MSG(&crys_msg.x_msg_header,
+ MSG_SMS_NEW_CRYSTAL_REQ,
+ sizeof(crys_msg));
+ crys_msg.msg_data[0] = board->crystal;
+
+ coredev->sendrequest_handler(coredev->context, &crys_msg,
+ sizeof(crys_msg));
+ }
+
+ return 0;
+}
+
+/**
* sets initial device mode and notifies client hotplugs that device is ready
*
* @param coredev pointer to a coredev object returned by
- * smscore_register_device
+ * smscore_register_device
*
* @return 0 on success, <0 on error.
*/
int smscore_start_device(struct smscore_device_t *coredev)
{
- int rc = smscore_set_device_mode(
- coredev, smscore_registry_getmode(coredev->devpath));
+ int rc;
+ int board_id = smscore_get_board_id(coredev);
+ int mode = smscore_registry_getmode(coredev->devpath);
+
+ /* Device is initialized as DEVICE_MODE_NONE */
+ if (board_id != SMS_BOARD_UNKNOWN && mode == DEVICE_MODE_NONE)
+ mode = sms_get_board(board_id)->default_mode;
+
+ rc = smscore_set_device_mode(coredev, mode);
if (rc < 0) {
sms_info("set device mode faile , rc %d", rc);
return rc;
}
+ rc = smscore_configure_board(coredev);
+ if (rc < 0) {
+ sms_info("configure board failed , rc %d", rc);
+ return rc;
+ }
kmutex_lock(&g_smscore_deviceslock);
@@ -509,18 +916,19 @@ EXPORT_SYMBOL_GPL(smscore_start_device);
static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
void *buffer, size_t size)
{
- struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
- struct SmsMsgHdr_ST *msg;
- u32 mem_address;
- u8 *payload = firmware->Payload;
+ struct sms_firmware *firmware = (struct sms_firmware *) buffer;
+ struct sms_msg_data4 *msg;
+ u32 mem_address, calc_checksum = 0;
+ u32 i, *ptr;
+ u8 *payload = firmware->payload;
int rc = 0;
- firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
- firmware->Length = le32_to_cpu(firmware->Length);
+ firmware->start_address = le32_to_cpu(firmware->start_address);
+ firmware->length = le32_to_cpu(firmware->length);
- mem_address = firmware->StartAddress;
+ mem_address = firmware->start_address;
sms_info("loading FW to addr 0x%x size %d",
- mem_address, firmware->Length);
+ mem_address, firmware->length);
if (coredev->preload_handler) {
rc = coredev->preload_handler(coredev->context);
if (rc < 0)
@@ -534,35 +942,36 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
if (coredev->mode != DEVICE_MODE_NONE) {
sms_debug("sending reload command.");
- SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
- sizeof(struct SmsMsgHdr_ST));
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ,
+ sizeof(struct sms_msg_hdr));
rc = smscore_sendrequest_and_wait(coredev, msg,
- msg->msgLength,
+ msg->x_msg_header.msg_length,
&coredev->reload_start_done);
+ if (rc < 0) {
+ sms_err("device reload failed, rc %d", rc);
+ goto exit_fw_download;
+ }
mem_address = *(u32 *) &payload[20];
}
+ for (i = 0, ptr = (u32 *)firmware->payload; i < firmware->length/4 ;
+ i++, ptr++)
+ calc_checksum += *ptr;
+
while (size && rc >= 0) {
- struct SmsDataDownload_ST *DataMsg =
- (struct SmsDataDownload_ST *) msg;
- int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
+ struct sms_data_download *data_msg =
+ (struct sms_data_download *) msg;
+ int payload_size = min_t(int, size, SMS_MAX_PAYLOAD_SIZE);
- SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
- (u16)(sizeof(struct SmsMsgHdr_ST) +
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_DOWNLOAD_REQ,
+ (u16)(sizeof(struct sms_msg_hdr) +
sizeof(u32) + payload_size));
- DataMsg->MemAddr = mem_address;
- memcpy(DataMsg->Payload, payload, payload_size);
+ data_msg->mem_addr = mem_address;
+ memcpy(data_msg->payload, payload, payload_size);
- if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
- (coredev->mode == DEVICE_MODE_NONE))
- rc = coredev->sendrequest_handler(
- coredev->context, DataMsg,
- DataMsg->xMsgHeader.msgLength);
- else
- rc = smscore_sendrequest_and_wait(
- coredev, DataMsg,
- DataMsg->xMsgHeader.msgLength,
+ rc = smscore_sendrequest_and_wait(coredev, data_msg,
+ data_msg->x_msg_header.msg_length,
&coredev->data_download_done);
payload += payload_size;
@@ -570,50 +979,158 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
mem_address += payload_size;
}
- if (rc >= 0) {
- if (coredev->mode == DEVICE_MODE_NONE) {
- struct SmsMsgData_ST *TriggerMsg =
- (struct SmsMsgData_ST *) msg;
-
- SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
- sizeof(struct SmsMsgHdr_ST) +
- sizeof(u32) * 5);
-
- TriggerMsg->msgData[0] = firmware->StartAddress;
- /* Entry point */
- TriggerMsg->msgData[1] = 5; /* Priority */
- TriggerMsg->msgData[2] = 0x200; /* Stack size */
- TriggerMsg->msgData[3] = 0; /* Parameter */
- TriggerMsg->msgData[4] = 4; /* Task ID */
-
- if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
- rc = coredev->sendrequest_handler(
- coredev->context, TriggerMsg,
- TriggerMsg->xMsgHeader.msgLength);
- msleep(100);
- } else
- rc = smscore_sendrequest_and_wait(
- coredev, TriggerMsg,
- TriggerMsg->xMsgHeader.msgLength,
+ if (rc < 0)
+ goto exit_fw_download;
+
+ sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x",
+ calc_checksum);
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ,
+ sizeof(msg->x_msg_header) +
+ sizeof(u32) * 3);
+ msg->msg_data[0] = firmware->start_address;
+ /* Entry point */
+ msg->msg_data[1] = firmware->length;
+ msg->msg_data[2] = 0; /* Regular checksum*/
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header.msg_length,
+ &coredev->data_validity_done);
+ if (rc < 0)
+ goto exit_fw_download;
+
+ if (coredev->mode == DEVICE_MODE_NONE) {
+ struct sms_msg_data *trigger_msg =
+ (struct sms_msg_data *) msg;
+
+ sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ");
+ SMS_INIT_MSG(&msg->x_msg_header,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
+ sizeof(struct sms_msg_hdr) +
+ sizeof(u32) * 5);
+
+ trigger_msg->msg_data[0] = firmware->start_address;
+ /* Entry point */
+ trigger_msg->msg_data[1] = 6; /* Priority */
+ trigger_msg->msg_data[2] = 0x200; /* Stack size */
+ trigger_msg->msg_data[3] = 0; /* Parameter */
+ trigger_msg->msg_data[4] = 4; /* Task ID */
+
+ rc = smscore_sendrequest_and_wait(coredev, trigger_msg,
+ trigger_msg->x_msg_header.msg_length,
&coredev->trigger_done);
- } else {
- SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
- sizeof(struct SmsMsgHdr_ST));
-
- rc = coredev->sendrequest_handler(coredev->context,
- msg, msg->msgLength);
- }
- msleep(500);
+ } else {
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ,
+ sizeof(struct sms_msg_hdr));
+ rc = coredev->sendrequest_handler(coredev->context, msg,
+ msg->x_msg_header.msg_length);
}
- sms_debug("rc=%d, postload=%p ", rc,
- coredev->postload_handler);
+ if (rc < 0)
+ goto exit_fw_download;
+
+ /*
+ * backward compatibility - wait to device_ready_done for
+ * not more than 400 ms
+ */
+ msleep(400);
+exit_fw_download:
kfree(msg);
- return ((rc >= 0) && coredev->postload_handler) ?
- coredev->postload_handler(coredev->context) :
- rc;
+ if (coredev->postload_handler) {
+ sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler);
+ if (rc >= 0)
+ return coredev->postload_handler(coredev->context);
+ }
+
+ sms_debug("rc=%d", rc);
+ return rc;
+}
+
+static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = {
+ [SMS_NOVA_A0] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ,
+ },
+ [SMS_NOVA_B0] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ_B0,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ_B0,
+ [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO,
+ [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO,
+ },
+ [SMS_VEGA] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VEGA_12MHZ,
+ },
+ [SMS_VENICE] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VENICE_12MHZ,
+ },
+ [SMS_MING] = {
+ [DEVICE_MODE_CMMB] = SMS_FW_CMMB_MING_APP,
+ },
+ [SMS_PELE] = {
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_PELE,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_PELE,
+ },
+ [SMS_RIO] = {
+ [DEVICE_MODE_DVBT] = SMS_FW_DVB_RIO,
+ [DEVICE_MODE_DVBH] = SMS_FW_DVBH_RIO,
+ [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_RIO,
+ [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_RIO,
+ [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_RIO,
+ [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO_RIO,
+ [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO_RIO,
+ },
+ [SMS_DENVER_1530] = {
+ [DEVICE_MODE_ATSC] = SMS_FW_ATSC_DENVER,
+ },
+ [SMS_DENVER_2160] = {
+ [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_DENVER,
+ },
+};
+
+/**
+ * get firmware file name from one of the two mechanisms : sms_boards or
+ * smscore_fw_lkup.
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ * @param lookup if 1, always get the fw filename from smscore_fw_lkup
+ * table. if 0, try first to get from sms_boards
+ *
+ * @return 0 on success, <0 on error.
+ */
+static char *smscore_get_fw_filename(struct smscore_device_t *coredev,
+ int mode)
+{
+ char **fw;
+ int board_id = smscore_get_board_id(coredev);
+ enum sms_device_type_st type;
+
+ type = smscore_registry_gettype(coredev->devpath);
+
+ /* Prevent looking outside the smscore_fw_lkup table */
+ if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES)
+ return NULL;
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX)
+ return NULL;
+
+ sms_debug("trying to get fw name from sms_boards board_id %d mode %d",
+ board_id, mode);
+ fw = sms_get_board(board_id)->fw;
+ if (!fw || !fw[mode]) {
+ sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d",
+ mode, type);
+ return smscore_fw_lkup[type][mode];
+ }
+
+ return fw[mode];
}
/**
@@ -627,41 +1144,46 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
* @return 0 on success, <0 on error.
*/
static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
- char *filename,
+ int mode,
loadfirmware_t loadfirmware_handler)
{
int rc = -ENOENT;
+ u8 *fw_buf;
+ u32 fw_buf_size;
const struct firmware *fw;
- u8 *fw_buffer;
- if (loadfirmware_handler == NULL && !(coredev->device_flags &
- SMS_DEVICE_FAMILY2))
+ char *fw_filename = smscore_get_fw_filename(coredev, mode);
+ if (!fw_filename) {
+ sms_info("mode %d not supported on this device", mode);
+ return -ENOENT;
+ }
+ sms_debug("Firmware name: %s", fw_filename);
+
+ if (loadfirmware_handler == NULL && !(coredev->device_flags
+ & SMS_DEVICE_FAMILY2))
return -EINVAL;
- rc = request_firmware(&fw, filename, coredev->device);
+ rc = request_firmware(&fw, fw_filename, coredev->device);
if (rc < 0) {
- sms_info("failed to open \"%s\"", filename);
+ sms_info("failed to open \"%s\"", fw_filename);
return rc;
}
- sms_info("read FW %s, size=%zd", filename, fw->size);
- fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
- GFP_KERNEL | GFP_DMA);
- if (fw_buffer) {
- memcpy(fw_buffer, fw->data, fw->size);
-
- rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
- smscore_load_firmware_family2(coredev,
- fw_buffer,
- fw->size) :
- loadfirmware_handler(coredev->context,
- fw_buffer, fw->size);
-
- kfree(fw_buffer);
- } else {
+ sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size);
+ fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
+ GFP_KERNEL | GFP_DMA);
+ if (!fw_buf) {
sms_info("failed to allocate firmware buffer");
- rc = -ENOMEM;
+ return -ENOMEM;
}
+ memcpy(fw_buf, fw->data, fw->size);
+ fw_buf_size = fw->size;
+
+ rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
+ smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size)
+ : loadfirmware_handler(coredev->context, fw_buf,
+ fw_buf_size);
+ kfree(fw_buf);
release_firmware(fw);
return rc;
@@ -703,14 +1225,15 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
if (num_buffers == coredev->num_buffers)
break;
if (++retry > 10) {
- sms_info("exiting although "
- "not all buffers released.");
+ sms_info("exiting although not all buffers released.");
break;
}
sms_info("waiting for %d buffer(s)",
coredev->num_buffers - num_buffers);
+ kmutex_unlock(&g_smscore_deviceslock);
msleep(100);
+ kmutex_lock(&g_smscore_deviceslock);
}
sms_info("freed %d buffers", num_buffers);
@@ -719,8 +1242,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
dma_free_coherent(NULL, coredev->common_buffer_size,
coredev->common_buffer, coredev->common_buffer_phys);
- if (coredev->fw_buf != NULL)
- kfree(coredev->fw_buf);
+ kfree(coredev->fw_buf);
list_del(&coredev->entry);
kfree(coredev);
@@ -733,19 +1255,19 @@ EXPORT_SYMBOL_GPL(smscore_unregister_device);
static int smscore_detect_mode(struct smscore_device_t *coredev)
{
- void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
+ void *buffer = kmalloc(sizeof(struct sms_msg_hdr) + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
- struct SmsMsgHdr_ST *msg =
- (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
+ struct sms_msg_hdr *msg =
+ (struct sms_msg_hdr *) SMS_ALIGN_ADDRESS(buffer);
int rc;
if (!buffer)
return -ENOMEM;
SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
- sizeof(struct SmsMsgHdr_ST));
+ sizeof(struct sms_msg_hdr));
- rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
+ rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length,
&coredev->version_ex_done);
if (rc == -ETIME) {
sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
@@ -753,11 +1275,11 @@ static int smscore_detect_mode(struct smscore_device_t *coredev)
if (wait_for_completion_timeout(&coredev->resume_done,
msecs_to_jiffies(5000))) {
rc = smscore_sendrequest_and_wait(
- coredev, msg, msg->msgLength,
+ coredev, msg, msg->msg_length,
&coredev->version_ex_done);
if (rc < 0)
- sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
- "second try, rc %d", rc);
+ sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d",
+ rc);
} else
rc = -ETIME;
}
@@ -767,31 +1289,39 @@ static int smscore_detect_mode(struct smscore_device_t *coredev)
return rc;
}
-static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
- /*Stellar NOVA A0 Nova B0 VEGA*/
- /*DVBT*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
- /*DVBH*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
- /*TDMB*/
- {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
- /*DABIP*/
- {"none", "none", "none", "none"},
- /*BDA*/
- {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
- /*ISDBT*/
- {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
- /*ISDBTBDA*/
- {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
- /*CMMB*/
- {"none", "none", "none", "cmmb_vega_12mhz.inp"}
-};
-
-static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
- int mode, enum sms_device_type_st type)
+/**
+ * send init device request and wait for response
+ *
+ * @param coredev pointer to a coredev object returned by
+ * smscore_register_device
+ * @param mode requested mode of operation
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int smscore_init_device(struct smscore_device_t *coredev, int mode)
{
- char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
- return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
+ void *buffer;
+ struct sms_msg_data *msg;
+ int rc = 0;
+
+ buffer = kmalloc(sizeof(struct sms_msg_data) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ sms_err("Could not allocate buffer for init device message.");
+ return -ENOMEM;
+ }
+
+ msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer);
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct sms_msg_data));
+ msg->msg_data[0] = mode;
+
+ rc = smscore_sendrequest_and_wait(coredev, msg,
+ msg->x_msg_header. msg_length,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ return rc;
}
/**
@@ -806,13 +1336,11 @@ static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
*/
int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
{
- void *buffer;
int rc = 0;
- enum sms_device_type_st type;
sms_debug("set device mode to %d", mode);
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
- if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
sms_err("invalid mode specified %d", mode);
return -EINVAL;
}
@@ -833,58 +1361,21 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
}
if (!(coredev->modes_supported & (1 << mode))) {
- char *fw_filename;
-
- type = smscore_registry_gettype(coredev->devpath);
- fw_filename = sms_get_fw_name(coredev, mode, type);
-
rc = smscore_load_firmware_from_file(coredev,
- fw_filename, NULL);
- if (rc < 0) {
- sms_warn("error %d loading firmware: %s, "
- "trying again with default firmware",
- rc, fw_filename);
-
- /* try again with the default firmware */
- fw_filename = smscore_fw_lkup[mode][type];
- rc = smscore_load_firmware_from_file(coredev,
- fw_filename, NULL);
-
- if (rc < 0) {
- sms_warn("error %d loading "
- "firmware: %s", rc,
- fw_filename);
- return rc;
- }
- }
- sms_log("firmware download success: %s", fw_filename);
- } else
- sms_info("mode %d supported by running "
- "firmware", mode);
-
- buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
- SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
- if (buffer) {
- struct SmsMsgData_ST *msg =
- (struct SmsMsgData_ST *)
- SMS_ALIGN_ADDRESS(buffer);
-
- SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
- sizeof(struct SmsMsgData_ST));
- msg->msgData[0] = mode;
-
- rc = smscore_sendrequest_and_wait(
- coredev, msg, msg->xMsgHeader.msgLength,
- &coredev->init_device_done);
-
- kfree(buffer);
+ mode, NULL);
+ if (rc >= 0)
+ sms_info("firmware download success");
} else {
- sms_err("Could not allocate buffer for "
- "init device message.");
- rc = -ENOMEM;
+ sms_info("mode %d is already supported by running firmware",
+ mode);
+ }
+ if (coredev->fw_version >= 0x800) {
+ rc = smscore_init_device(coredev, mode);
+ if (rc < 0)
+ sms_err("device init failed, rc %d.", rc);
}
} else {
- if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
+ if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) {
sms_err("invalid mode specified %d", mode);
return -EINVAL;
}
@@ -900,12 +1391,32 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
}
if (rc >= 0) {
+ char *buffer;
coredev->mode = mode;
coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
+
+ buffer = kmalloc(sizeof(struct sms_msg_data) +
+ SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
+ if (buffer) {
+ struct sms_msg_data *msg = (struct sms_msg_data *) SMS_ALIGN_ADDRESS(buffer);
+
+ SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
+ sizeof(struct sms_msg_data));
+ msg->msg_data[0] = mode;
+
+ rc = smscore_sendrequest_and_wait(
+ coredev, msg, msg->x_msg_header.msg_length,
+ &coredev->init_device_done);
+
+ kfree(buffer);
+ }
}
if (rc < 0)
sms_err("return error code %d.", rc);
+ else
+ sms_debug("Success setting device mode.");
+
return rc;
}
@@ -971,7 +1482,7 @@ found:
*/
void smscore_onresponse(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb) {
- struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) ((u8 *) cb->p
+ cb->offset);
struct smscore_client_t *client;
int rc = -EBUSY;
@@ -983,7 +1494,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
last_sample_time = time_now;
if (time_now - last_sample_time > 10000) {
- sms_debug("\ndata rate %d bytes/secs",
+ sms_debug("data rate %d bytes/secs",
(int)((data_total * 1000) /
(time_now - last_sample_time)));
@@ -993,14 +1504,14 @@ void smscore_onresponse(struct smscore_device_t *coredev,
data_total += cb->size;
/* Do we need to re-route? */
- if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
- (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
+ if ((phdr->msg_type == MSG_SMS_HO_PER_SLICES_IND) ||
+ (phdr->msg_type == MSG_SMS_TRANSMISSION_IND)) {
if (coredev->mode == DEVICE_MODE_DVBT_BDA)
- phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
+ phdr->msg_dst_id = DVBT_BDA_CONTROL_MSG_ID;
}
- client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+ client = smscore_find_client(coredev, phdr->msg_type, phdr->msg_dst_id);
/* If no client registered for type & id,
* check for control client where type is not registered */
@@ -1008,57 +1519,75 @@ void smscore_onresponse(struct smscore_device_t *coredev,
rc = client->onresponse_handler(client->context, cb);
if (rc < 0) {
- switch (phdr->msgType) {
+ switch (phdr->msg_type) {
+ case MSG_SMS_ISDBT_TUNE_RES:
+ break;
+ case MSG_SMS_RF_TUNE_RES:
+ break;
+ case MSG_SMS_SIGNAL_DETECTED_IND:
+ break;
+ case MSG_SMS_NO_SIGNAL_IND:
+ break;
+ case MSG_SMS_SPI_INT_LINE_SET_RES:
+ break;
+ case MSG_SMS_INTERFACE_LOCK_IND:
+ break;
+ case MSG_SMS_INTERFACE_UNLOCK_IND:
+ break;
case MSG_SMS_GET_VERSION_EX_RES:
{
- struct SmsVersionRes_ST *ver =
- (struct SmsVersionRes_ST *) phdr;
- sms_debug("MSG_SMS_GET_VERSION_EX_RES "
- "id %d prots 0x%x ver %d.%d",
- ver->FirmwareId, ver->SupportedProtocols,
- ver->RomVersionMajor, ver->RomVersionMinor);
-
- coredev->mode = ver->FirmwareId == 255 ?
- DEVICE_MODE_NONE : ver->FirmwareId;
- coredev->modes_supported = ver->SupportedProtocols;
+ struct sms_version_res *ver =
+ (struct sms_version_res *) phdr;
+ sms_debug("Firmware id %d prots 0x%x ver %d.%d",
+ ver->firmware_id, ver->supported_protocols,
+ ver->rom_ver_major, ver->rom_ver_minor);
+
+ coredev->mode = ver->firmware_id == 255 ?
+ DEVICE_MODE_NONE : ver->firmware_id;
+ coredev->modes_supported = ver->supported_protocols;
+ coredev->fw_version = ver->rom_ver_major << 8 |
+ ver->rom_ver_minor;
complete(&coredev->version_ex_done);
break;
}
case MSG_SMS_INIT_DEVICE_RES:
- sms_debug("MSG_SMS_INIT_DEVICE_RES");
complete(&coredev->init_device_done);
break;
case MSG_SW_RELOAD_START_RES:
- sms_debug("MSG_SW_RELOAD_START_RES");
complete(&coredev->reload_start_done);
break;
+ case MSG_SMS_DATA_VALIDITY_RES:
+ {
+ struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
+
+ sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x",
+ validity->msg_data[0]);
+ complete(&coredev->data_validity_done);
+ break;
+ }
case MSG_SMS_DATA_DOWNLOAD_RES:
complete(&coredev->data_download_done);
break;
case MSG_SW_RELOAD_EXEC_RES:
- sms_debug("MSG_SW_RELOAD_EXEC_RES");
break;
case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
- sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
complete(&coredev->trigger_done);
break;
case MSG_SMS_SLEEP_RESUME_COMP_IND:
complete(&coredev->resume_done);
break;
case MSG_SMS_GPIO_CONFIG_EX_RES:
- sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
complete(&coredev->gpio_configuration_done);
break;
case MSG_SMS_GPIO_SET_LEVEL_RES:
- sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
complete(&coredev->gpio_set_level_done);
break;
case MSG_SMS_GPIO_GET_LEVEL_RES:
{
u32 *msgdata = (u32 *) phdr;
coredev->gpio_get_res = msgdata[1];
- sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+ sms_debug("gpio level %d",
coredev->gpio_get_res);
complete(&coredev->gpio_get_level_done);
break;
@@ -1070,12 +1599,24 @@ void smscore_onresponse(struct smscore_device_t *coredev,
sms_ir_event(coredev,
(const char *)
((char *)phdr
- + sizeof(struct SmsMsgHdr_ST)),
- (int)phdr->msgLength
- - sizeof(struct SmsMsgHdr_ST));
+ + sizeof(struct sms_msg_hdr)),
+ (int)phdr->msg_length
+ - sizeof(struct sms_msg_hdr));
+ break;
+
+ case MSG_SMS_DVBT_BDA_DATA:
+ /*
+ * It can be received here, if the frontend is
+ * tuned into a valid channel and the proper firmware
+ * is loaded. That happens when the module got removed
+ * and re-inserted, without powering the device off
+ */
break;
default:
+ sms_debug("message %s(%d) not handled.",
+ smscore_translate_msg(phdr->msg_type),
+ phdr->msg_type);
break;
}
smscore_putbuffer(coredev, cb);
@@ -1257,7 +1798,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
void *buffer, size_t size)
{
struct smscore_device_t *coredev;
- struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
int rc;
if (client == NULL) {
@@ -1274,7 +1815,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
}
rc = smscore_validate_client(client->coredev, client, 0,
- phdr->msgSrcId);
+ phdr->msg_src_id);
if (rc < 0)
return rc;
@@ -1288,16 +1829,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_config_gpio *pinconfig)
{
struct {
- struct SmsMsgHdr_ST hdr;
+ struct sms_msg_hdr hdr;
u32 data[6];
} msg;
if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
- msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- msg.hdr.msgDstId = HIF_TASK;
- msg.hdr.msgFlags = 0;
- msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
- msg.hdr.msgLength = sizeof(msg);
+ msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msg_dst_id = HIF_TASK;
+ msg.hdr.msg_flags = 0;
+ msg.hdr.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ msg.hdr.msg_length = sizeof(msg);
msg.data[0] = pin;
msg.data[1] = pinconfig->pullupdown;
@@ -1306,16 +1847,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
switch (pinconfig->outputdriving) {
- case SMS_GPIO_OUTPUTDRIVING_16mA:
+ case SMS_GPIO_OUTPUTDRIVING_S_16mA:
msg.data[3] = 7; /* Nova - 16mA */
break;
- case SMS_GPIO_OUTPUTDRIVING_12mA:
+ case SMS_GPIO_OUTPUTDRIVING_S_12mA:
msg.data[3] = 5; /* Nova - 11mA */
break;
- case SMS_GPIO_OUTPUTDRIVING_8mA:
+ case SMS_GPIO_OUTPUTDRIVING_S_8mA:
msg.data[3] = 3; /* Nova - 7mA */
break;
- case SMS_GPIO_OUTPUTDRIVING_4mA:
+ case SMS_GPIO_OUTPUTDRIVING_S_4mA:
default:
msg.data[3] = 2; /* Nova - 4mA */
break;
@@ -1333,18 +1874,18 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
{
struct {
- struct SmsMsgHdr_ST hdr;
+ struct sms_msg_hdr hdr;
u32 data[3];
} msg;
if (pin > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
- msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- msg.hdr.msgDstId = HIF_TASK;
- msg.hdr.msgFlags = 0;
- msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
- msg.hdr.msgLength = sizeof(msg);
+ msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.hdr.msg_dst_id = HIF_TASK;
+ msg.hdr.msg_flags = 0;
+ msg.hdr.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ msg.hdr.msg_length = sizeof(msg);
msg.data[0] = pin;
msg.data[1] = level ? 1 : 0;
@@ -1355,122 +1896,121 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
}
/* new GPIO management implementation */
-static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
- u32 *pGroupNum, u32 *pGroupCfg) {
-
- *pGroupCfg = 1;
-
- if (PinNum <= 1) {
- *pTranslatedPinNum = 0;
- *pGroupNum = 9;
- *pGroupCfg = 2;
- } else if (PinNum >= 2 && PinNum <= 6) {
- *pTranslatedPinNum = 2;
- *pGroupNum = 0;
- *pGroupCfg = 2;
- } else if (PinNum >= 7 && PinNum <= 11) {
- *pTranslatedPinNum = 7;
- *pGroupNum = 1;
- } else if (PinNum >= 12 && PinNum <= 15) {
- *pTranslatedPinNum = 12;
- *pGroupNum = 2;
- *pGroupCfg = 3;
- } else if (PinNum == 16) {
- *pTranslatedPinNum = 16;
- *pGroupNum = 23;
- } else if (PinNum >= 17 && PinNum <= 24) {
- *pTranslatedPinNum = 17;
- *pGroupNum = 3;
- } else if (PinNum == 25) {
- *pTranslatedPinNum = 25;
- *pGroupNum = 6;
- } else if (PinNum >= 26 && PinNum <= 28) {
- *pTranslatedPinNum = 26;
- *pGroupNum = 4;
- } else if (PinNum == 29) {
- *pTranslatedPinNum = 29;
- *pGroupNum = 5;
- *pGroupCfg = 2;
- } else if (PinNum == 30) {
- *pTranslatedPinNum = 30;
- *pGroupNum = 8;
- } else if (PinNum == 31) {
- *pTranslatedPinNum = 31;
- *pGroupNum = 17;
+static int get_gpio_pin_params(u32 pin_num, u32 *p_translatedpin_num,
+ u32 *p_group_num, u32 *p_group_cfg) {
+
+ *p_group_cfg = 1;
+
+ if (pin_num <= 1) {
+ *p_translatedpin_num = 0;
+ *p_group_num = 9;
+ *p_group_cfg = 2;
+ } else if (pin_num >= 2 && pin_num <= 6) {
+ *p_translatedpin_num = 2;
+ *p_group_num = 0;
+ *p_group_cfg = 2;
+ } else if (pin_num >= 7 && pin_num <= 11) {
+ *p_translatedpin_num = 7;
+ *p_group_num = 1;
+ } else if (pin_num >= 12 && pin_num <= 15) {
+ *p_translatedpin_num = 12;
+ *p_group_num = 2;
+ *p_group_cfg = 3;
+ } else if (pin_num == 16) {
+ *p_translatedpin_num = 16;
+ *p_group_num = 23;
+ } else if (pin_num >= 17 && pin_num <= 24) {
+ *p_translatedpin_num = 17;
+ *p_group_num = 3;
+ } else if (pin_num == 25) {
+ *p_translatedpin_num = 25;
+ *p_group_num = 6;
+ } else if (pin_num >= 26 && pin_num <= 28) {
+ *p_translatedpin_num = 26;
+ *p_group_num = 4;
+ } else if (pin_num == 29) {
+ *p_translatedpin_num = 29;
+ *p_group_num = 5;
+ *p_group_cfg = 2;
+ } else if (pin_num == 30) {
+ *p_translatedpin_num = 30;
+ *p_group_num = 8;
+ } else if (pin_num == 31) {
+ *p_translatedpin_num = 31;
+ *p_group_num = 17;
} else
return -1;
- *pGroupCfg <<= 24;
+ *p_group_cfg <<= 24;
return 0;
}
-int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
- struct smscore_gpio_config *pGpioConfig) {
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
+ struct smscore_config_gpio *p_gpio_config) {
- u32 totalLen;
- u32 TranslatedPinNum = 0;
- u32 GroupNum = 0;
- u32 ElectricChar;
- u32 groupCfg;
+ u32 total_len;
+ u32 translatedpin_num = 0;
+ u32 group_num = 0;
+ u32 electric_char;
+ u32 group_cfg;
void *buffer;
int rc;
- struct SetGpioMsg {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 msgData[6];
- } *pMsg;
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[6];
+ } *p_msg;
- if (PinNum > MAX_GPIO_PIN_NUMBER)
+ if (pin_num > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
- if (pGpioConfig == NULL)
+ if (p_gpio_config == NULL)
return -EINVAL;
- totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+ total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6);
- buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
- pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
- pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- pMsg->xMsgHeader.msgDstId = HIF_TASK;
- pMsg->xMsgHeader.msgFlags = 0;
- pMsg->xMsgHeader.msgLength = (u16) totalLen;
- pMsg->msgData[0] = PinNum;
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
- pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
- if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
- &groupCfg) != 0) {
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ;
+ if (get_gpio_pin_params(pin_num, &translatedpin_num, &group_num,
+ &group_cfg) != 0) {
rc = -EINVAL;
goto free;
}
- pMsg->msgData[1] = TranslatedPinNum;
- pMsg->msgData[2] = GroupNum;
- ElectricChar = (pGpioConfig->PullUpDown)
- | (pGpioConfig->InputCharacteristics << 2)
- | (pGpioConfig->OutputSlewRate << 3)
- | (pGpioConfig->OutputDriving << 4);
- pMsg->msgData[3] = ElectricChar;
- pMsg->msgData[4] = pGpioConfig->Direction;
- pMsg->msgData[5] = groupCfg;
+ p_msg->msg_data[1] = translatedpin_num;
+ p_msg->msg_data[2] = group_num;
+ electric_char = (p_gpio_config->pullupdown)
+ | (p_gpio_config->inputcharacteristics << 2)
+ | (p_gpio_config->outputslewrate << 3)
+ | (p_gpio_config->outputdriving << 4);
+ p_msg->msg_data[3] = electric_char;
+ p_msg->msg_data[4] = p_gpio_config->direction;
+ p_msg->msg_data[5] = group_cfg;
} else {
- pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
- pMsg->msgData[1] = pGpioConfig->PullUpDown;
- pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
- pMsg->msgData[3] = pGpioConfig->OutputDriving;
- pMsg->msgData[4] = pGpioConfig->Direction;
- pMsg->msgData[5] = 0;
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ;
+ p_msg->msg_data[1] = p_gpio_config->pullupdown;
+ p_msg->msg_data[2] = p_gpio_config->outputslewrate;
+ p_msg->msg_data[3] = p_gpio_config->outputdriving;
+ p_msg->msg_data[4] = p_gpio_config->direction;
+ p_msg->msg_data[5] = 0;
}
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
- rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
&coredev->gpio_configuration_done);
if (rc != 0) {
@@ -1485,42 +2025,41 @@ free:
return rc;
}
-int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
- u8 NewLevel) {
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 new_level) {
- u32 totalLen;
+ u32 total_len;
int rc;
void *buffer;
- struct SetGpioMsg {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 msgData[3]; /* keep it 3 ! */
- } *pMsg;
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[3]; /* keep it 3 ! */
+ } *p_msg;
- if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
+ if ((new_level > 1) || (pin_num > MAX_GPIO_PIN_NUMBER))
return -EINVAL;
- totalLen = sizeof(struct SmsMsgHdr_ST) +
+ total_len = sizeof(struct sms_msg_hdr) +
(3 * sizeof(u32)); /* keep it 3 ! */
- buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
- pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
- pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- pMsg->xMsgHeader.msgDstId = HIF_TASK;
- pMsg->xMsgHeader.msgFlags = 0;
- pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
- pMsg->xMsgHeader.msgLength = (u16) totalLen;
- pMsg->msgData[0] = PinNum;
- pMsg->msgData[1] = NewLevel;
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
+ p_msg->msg_data[1] = new_level;
/* Send message to SMS */
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
- rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
&coredev->gpio_set_level_done);
if (rc != 0) {
@@ -1534,42 +2073,41 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
return rc;
}
-int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
u8 *level) {
- u32 totalLen;
+ u32 total_len;
int rc;
void *buffer;
- struct SetGpioMsg {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 msgData[2];
- } *pMsg;
+ struct set_gpio_msg {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[2];
+ } *p_msg;
- if (PinNum > MAX_GPIO_PIN_NUMBER)
+ if (pin_num > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
- totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+ total_len = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32));
- buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+ buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
- pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+ p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer);
- pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- pMsg->xMsgHeader.msgDstId = HIF_TASK;
- pMsg->xMsgHeader.msgFlags = 0;
- pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
- pMsg->xMsgHeader.msgLength = (u16) totalLen;
- pMsg->msgData[0] = PinNum;
- pMsg->msgData[1] = 0;
+ p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ p_msg->x_msg_header.msg_dst_id = HIF_TASK;
+ p_msg->x_msg_header.msg_flags = 0;
+ p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ;
+ p_msg->x_msg_header.msg_length = (u16) total_len;
+ p_msg->msg_data[0] = pin_num;
+ p_msg->msg_data[1] = 0;
/* Send message to SMS */
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
- rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+ rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len,
&coredev->gpio_get_level_done);
if (rc != 0) {
@@ -1635,3 +2173,27 @@ module_exit(smscore_module_exit);
MODULE_DESCRIPTION("Siano MDTV Core module");
MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
MODULE_LICENSE("GPL");
+
+/* This should match what's defined at smscoreapi.h */
+MODULE_FIRMWARE(SMS_FW_ATSC_DENVER);
+MODULE_FIRMWARE(SMS_FW_CMMB_MING_APP);
+MODULE_FIRMWARE(SMS_FW_CMMB_VEGA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_CMMB_VENICE_12MHZ);
+MODULE_FIRMWARE(SMS_FW_DVBH_RIO);
+MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_DVB_RIO);
+MODULE_FIRMWARE(SMS_FW_FM_RADIO);
+MODULE_FIRMWARE(SMS_FW_FM_RADIO_RIO);
+MODULE_FIRMWARE(SMS_FW_DVBT_HCW_55XXX);
+MODULE_FIRMWARE(SMS_FW_ISDBT_HCW_55XXX);
+MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ);
+MODULE_FIRMWARE(SMS_FW_ISDBT_PELE);
+MODULE_FIRMWARE(SMS_FW_ISDBT_RIO);
+MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_A);
+MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_B);
+MODULE_FIRMWARE(SMS_FW_DVBT_STELLAR);
+MODULE_FIRMWARE(SMS_FW_TDMB_DENVER);
+MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ_B0);
+MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ);
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index c592ae090397..d0799e323364 100644
--- a/drivers/media/common/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -40,9 +40,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define kmutex_trylock(_p_) mutex_trylock(_p_)
#define kmutex_unlock(_p_) mutex_unlock(_p_)
-#ifndef min
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#endif
+/*
+ * Define the firmware names used by the driver.
+ * Those should match what's used at smscoreapi.c and sms-cards.c
+ * including the MODULE_FIRMWARE() macros at the end of smscoreapi.c
+ */
+#define SMS_FW_ATSC_DENVER "atsc_denver.inp"
+#define SMS_FW_CMMB_MING_APP "cmmb_ming_app.inp"
+#define SMS_FW_CMMB_VEGA_12MHZ "cmmb_vega_12mhz.inp"
+#define SMS_FW_CMMB_VENICE_12MHZ "cmmb_venice_12mhz.inp"
+#define SMS_FW_DVBH_RIO "dvbh_rio.inp"
+#define SMS_FW_DVB_NOVA_12MHZ_B0 "dvb_nova_12mhz_b0.inp"
+#define SMS_FW_DVB_NOVA_12MHZ "dvb_nova_12mhz.inp"
+#define SMS_FW_DVB_RIO "dvb_rio.inp"
+#define SMS_FW_FM_RADIO "fm_radio.inp"
+#define SMS_FW_FM_RADIO_RIO "fm_radio_rio.inp"
+#define SMS_FW_DVBT_HCW_55XXX "sms1xxx-hcw-55xxx-dvbt-02.fw"
+#define SMS_FW_ISDBT_HCW_55XXX "sms1xxx-hcw-55xxx-isdbt-02.fw"
+#define SMS_FW_ISDBT_NOVA_12MHZ_B0 "isdbt_nova_12mhz_b0.inp"
+#define SMS_FW_ISDBT_NOVA_12MHZ "isdbt_nova_12mhz.inp"
+#define SMS_FW_ISDBT_PELE "isdbt_pele.inp"
+#define SMS_FW_ISDBT_RIO "isdbt_rio.inp"
+#define SMS_FW_DVBT_NOVA_A "sms1xxx-nova-a-dvbt-01.fw"
+#define SMS_FW_DVBT_NOVA_B "sms1xxx-nova-b-dvbt-01.fw"
+#define SMS_FW_DVBT_STELLAR "sms1xxx-stellar-dvbt-01.fw"
+#define SMS_FW_TDMB_DENVER "tdmb_denver.inp"
+#define SMS_FW_TDMB_NOVA_12MHZ_B0 "tdmb_nova_12mhz_b0.inp"
+#define SMS_FW_TDMB_NOVA_12MHZ "tdmb_nova_12mhz.inp"
#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000)
#define SMS_ALLOC_ALIGNMENT 128
@@ -50,18 +74,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define SMS_ALIGN_ADDRESS(addr) \
((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
+#define SMS_DEVICE_FAMILY1 0
#define SMS_DEVICE_FAMILY2 1
#define SMS_ROM_NO_RESPONSE 2
#define SMS_DEVICE_NOT_READY 0x8000000
enum sms_device_type_st {
+ SMS_UNKNOWN_TYPE = -1,
SMS_STELLAR = 0,
SMS_NOVA_A0,
SMS_NOVA_B0,
SMS_VEGA,
+ SMS_VENICE,
+ SMS_MING,
+ SMS_PELE,
+ SMS_RIO,
+ SMS_DENVER_1530,
+ SMS_DENVER_2160,
SMS_NUM_OF_DEVICE_TYPES
};
+enum sms_power_mode_st {
+ SMS_POWER_MODE_ACTIVE,
+ SMS_POWER_MODE_SUSPENDED
+};
+
struct smscore_device_t;
struct smscore_client_t;
struct smscore_buffer_t;
@@ -149,6 +186,7 @@ struct smscore_device_t {
/* host <--> device messages */
struct completion version_ex_done, data_download_done, trigger_done;
+ struct completion data_validity_done, device_ready_done;
struct completion init_device_done, reload_start_done, resume_done;
struct completion gpio_configuration_done, gpio_set_level_done;
struct completion gpio_get_level_done, ir_init_done;
@@ -165,10 +203,17 @@ struct smscore_device_t {
/* Firmware */
u8 *fw_buf;
u32 fw_buf_size;
+ u16 fw_version;
/* Infrared (IR) */
struct ir_t ir;
+ /*
+ * Identify if device is USB or not.
+ * Used by smsdvb-sysfs to know the root node for debugfs
+ */
+ bool is_usb_device;
+
int led_state;
};
@@ -176,81 +221,363 @@ struct smscore_device_t {
#define SMS_ANTENNA_GPIO_0 1
#define SMS_ANTENNA_GPIO_1 0
-#define BW_8_MHZ 0
-#define BW_7_MHZ 1
-#define BW_6_MHZ 2
-#define BW_5_MHZ 3
-#define BW_ISDBT_1SEG 4
-#define BW_ISDBT_3SEG 5
+enum sms_bandwidth_mode {
+ BW_8_MHZ = 0,
+ BW_7_MHZ = 1,
+ BW_6_MHZ = 2,
+ BW_5_MHZ = 3,
+ BW_ISDBT_1SEG = 4,
+ BW_ISDBT_3SEG = 5,
+ BW_2_MHZ = 6,
+ BW_FM_RADIO = 7,
+ BW_ISDBT_13SEG = 8,
+ BW_1_5_MHZ = 15,
+ BW_UNKNOWN = 0xffff
+};
+
#define MSG_HDR_FLAG_SPLIT_MSG 4
#define MAX_GPIO_PIN_NUMBER 31
#define HIF_TASK 11
+#define HIF_TASK_SLAVE 22
+#define HIF_TASK_SLAVE2 33
+#define HIF_TASK_SLAVE3 44
#define SMS_HOST_LIB 150
#define DVBT_BDA_CONTROL_MSG_ID 201
#define SMS_MAX_PAYLOAD_SIZE 240
#define SMS_TUNE_TIMEOUT 500
-#define MSG_SMS_GPIO_CONFIG_REQ 507
-#define MSG_SMS_GPIO_CONFIG_RES 508
-#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
-#define MSG_SMS_GPIO_SET_LEVEL_RES 510
-#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
-#define MSG_SMS_GPIO_GET_LEVEL_RES 512
-#define MSG_SMS_RF_TUNE_REQ 561
-#define MSG_SMS_RF_TUNE_RES 562
-#define MSG_SMS_INIT_DEVICE_REQ 578
-#define MSG_SMS_INIT_DEVICE_RES 579
-#define MSG_SMS_ADD_PID_FILTER_REQ 601
-#define MSG_SMS_ADD_PID_FILTER_RES 602
-#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
-#define MSG_SMS_REMOVE_PID_FILTER_RES 604
-#define MSG_SMS_DAB_CHANNEL 607
-#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
-#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
-#define MSG_SMS_GET_STATISTICS_RES 616
-#define MSG_SMS_GET_STATISTICS_REQ 615
-#define MSG_SMS_HO_PER_SLICES_IND 630
-#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
-#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
-#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
-#define MSG_SMS_DATA_DOWNLOAD_REQ 660
-#define MSG_SMS_DATA_DOWNLOAD_RES 661
-#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
-#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
-#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
-#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
-#define MSG_SMS_GET_VERSION_EX_REQ 668
-#define MSG_SMS_GET_VERSION_EX_RES 669
-#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
-#define MSG_SMS_I2C_SET_FREQ_REQ 685
-#define MSG_SMS_GENERIC_I2C_REQ 687
-#define MSG_SMS_GENERIC_I2C_RES 688
-#define MSG_SMS_DVBT_BDA_DATA 693
-#define MSG_SW_RELOAD_REQ 697
-#define MSG_SMS_DATA_MSG 699
-#define MSG_SW_RELOAD_START_REQ 702
-#define MSG_SW_RELOAD_START_RES 703
-#define MSG_SW_RELOAD_EXEC_REQ 704
-#define MSG_SW_RELOAD_EXEC_RES 705
-#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
-#define MSG_SMS_GPIO_CONFIG_EX_REQ 712
-#define MSG_SMS_GPIO_CONFIG_EX_RES 713
-#define MSG_SMS_ISDBT_TUNE_REQ 776
-#define MSG_SMS_ISDBT_TUNE_RES 777
-#define MSG_SMS_TRANSMISSION_IND 782
-#define MSG_SMS_START_IR_REQ 800
-#define MSG_SMS_START_IR_RES 801
-#define MSG_SMS_IR_SAMPLES_IND 802
-#define MSG_SMS_SIGNAL_DETECTED_IND 827
-#define MSG_SMS_NO_SIGNAL_IND 828
+enum msg_types {
+ MSG_TYPE_BASE_VAL = 500,
+ MSG_SMS_GET_VERSION_REQ = 503,
+ MSG_SMS_GET_VERSION_RES = 504,
+ MSG_SMS_MULTI_BRIDGE_CFG = 505,
+ MSG_SMS_GPIO_CONFIG_REQ = 507,
+ MSG_SMS_GPIO_CONFIG_RES = 508,
+ MSG_SMS_GPIO_SET_LEVEL_REQ = 509,
+ MSG_SMS_GPIO_SET_LEVEL_RES = 510,
+ MSG_SMS_GPIO_GET_LEVEL_REQ = 511,
+ MSG_SMS_GPIO_GET_LEVEL_RES = 512,
+ MSG_SMS_EEPROM_BURN_IND = 513,
+ MSG_SMS_LOG_ENABLE_CHANGE_REQ = 514,
+ MSG_SMS_LOG_ENABLE_CHANGE_RES = 515,
+ MSG_SMS_SET_MAX_TX_MSG_LEN_REQ = 516,
+ MSG_SMS_SET_MAX_TX_MSG_LEN_RES = 517,
+ MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE = 518,
+ MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST = 519,
+ MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ = 520,
+ MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES = 521,
+ MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND = 522,
+ MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND = 523,
+ MSG_SMS_CONFIGURE_RF_SWITCH_REQ = 524,
+ MSG_SMS_CONFIGURE_RF_SWITCH_RES = 525,
+ MSG_SMS_MRC_PATH_DISCONNECT_REQ = 526,
+ MSG_SMS_MRC_PATH_DISCONNECT_RES = 527,
+ MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ = 528,
+ MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES = 529,
+ MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ = 530,
+ MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES = 531,
+ MSG_WR_REG_RFT_REQ = 533,
+ MSG_WR_REG_RFT_RES = 534,
+ MSG_RD_REG_RFT_REQ = 535,
+ MSG_RD_REG_RFT_RES = 536,
+ MSG_RD_REG_ALL_RFT_REQ = 537,
+ MSG_RD_REG_ALL_RFT_RES = 538,
+ MSG_HELP_INT = 539,
+ MSG_RUN_SCRIPT_INT = 540,
+ MSG_SMS_EWS_INBAND_REQ = 541,
+ MSG_SMS_EWS_INBAND_RES = 542,
+ MSG_SMS_RFS_SELECT_REQ = 543,
+ MSG_SMS_RFS_SELECT_RES = 544,
+ MSG_SMS_MB_GET_VER_REQ = 545,
+ MSG_SMS_MB_GET_VER_RES = 546,
+ MSG_SMS_MB_WRITE_CFGFILE_REQ = 547,
+ MSG_SMS_MB_WRITE_CFGFILE_RES = 548,
+ MSG_SMS_MB_READ_CFGFILE_REQ = 549,
+ MSG_SMS_MB_READ_CFGFILE_RES = 550,
+ MSG_SMS_RD_MEM_REQ = 552,
+ MSG_SMS_RD_MEM_RES = 553,
+ MSG_SMS_WR_MEM_REQ = 554,
+ MSG_SMS_WR_MEM_RES = 555,
+ MSG_SMS_UPDATE_MEM_REQ = 556,
+ MSG_SMS_UPDATE_MEM_RES = 557,
+ MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ = 558,
+ MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES = 559,
+ MSG_SMS_RF_TUNE_REQ = 561,
+ MSG_SMS_RF_TUNE_RES = 562,
+ MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ = 563,
+ MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES = 564,
+ MSG_SMS_ISDBT_SB_RECEPTION_REQ = 565,
+ MSG_SMS_ISDBT_SB_RECEPTION_RES = 566,
+ MSG_SMS_GENERIC_EPROM_WRITE_REQ = 567,
+ MSG_SMS_GENERIC_EPROM_WRITE_RES = 568,
+ MSG_SMS_GENERIC_EPROM_READ_REQ = 569,
+ MSG_SMS_GENERIC_EPROM_READ_RES = 570,
+ MSG_SMS_EEPROM_WRITE_REQ = 571,
+ MSG_SMS_EEPROM_WRITE_RES = 572,
+ MSG_SMS_CUSTOM_READ_REQ = 574,
+ MSG_SMS_CUSTOM_READ_RES = 575,
+ MSG_SMS_CUSTOM_WRITE_REQ = 576,
+ MSG_SMS_CUSTOM_WRITE_RES = 577,
+ MSG_SMS_INIT_DEVICE_REQ = 578,
+ MSG_SMS_INIT_DEVICE_RES = 579,
+ MSG_SMS_ATSC_SET_ALL_IP_REQ = 580,
+ MSG_SMS_ATSC_SET_ALL_IP_RES = 581,
+ MSG_SMS_ATSC_START_ENSEMBLE_REQ = 582,
+ MSG_SMS_ATSC_START_ENSEMBLE_RES = 583,
+ MSG_SMS_SET_OUTPUT_MODE_REQ = 584,
+ MSG_SMS_SET_OUTPUT_MODE_RES = 585,
+ MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ = 586,
+ MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES = 587,
+ MSG_SMS_SUB_CHANNEL_START_REQ = 589,
+ MSG_SMS_SUB_CHANNEL_START_RES = 590,
+ MSG_SMS_SUB_CHANNEL_STOP_REQ = 591,
+ MSG_SMS_SUB_CHANNEL_STOP_RES = 592,
+ MSG_SMS_ATSC_IP_FILTER_ADD_REQ = 593,
+ MSG_SMS_ATSC_IP_FILTER_ADD_RES = 594,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ = 595,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_RES = 596,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ = 597,
+ MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES = 598,
+ MSG_SMS_WAIT_CMD = 599,
+ MSG_SMS_ADD_PID_FILTER_REQ = 601,
+ MSG_SMS_ADD_PID_FILTER_RES = 602,
+ MSG_SMS_REMOVE_PID_FILTER_REQ = 603,
+ MSG_SMS_REMOVE_PID_FILTER_RES = 604,
+ MSG_SMS_FAST_INFORMATION_CHANNEL_REQ = 605,
+ MSG_SMS_FAST_INFORMATION_CHANNEL_RES = 606,
+ MSG_SMS_DAB_CHANNEL = 607,
+ MSG_SMS_GET_PID_FILTER_LIST_REQ = 608,
+ MSG_SMS_GET_PID_FILTER_LIST_RES = 609,
+ MSG_SMS_POWER_DOWN_REQ = 610,
+ MSG_SMS_POWER_DOWN_RES = 611,
+ MSG_SMS_ATSC_SLT_EXIST_IND = 612,
+ MSG_SMS_ATSC_NO_SLT_IND = 613,
+ MSG_SMS_GET_STATISTICS_REQ = 615,
+ MSG_SMS_GET_STATISTICS_RES = 616,
+ MSG_SMS_SEND_DUMP = 617,
+ MSG_SMS_SCAN_START_REQ = 618,
+ MSG_SMS_SCAN_START_RES = 619,
+ MSG_SMS_SCAN_STOP_REQ = 620,
+ MSG_SMS_SCAN_STOP_RES = 621,
+ MSG_SMS_SCAN_PROGRESS_IND = 622,
+ MSG_SMS_SCAN_COMPLETE_IND = 623,
+ MSG_SMS_LOG_ITEM = 624,
+ MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ = 628,
+ MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES = 629,
+ MSG_SMS_HO_PER_SLICES_IND = 630,
+ MSG_SMS_HO_INBAND_POWER_IND = 631,
+ MSG_SMS_MANUAL_DEMOD_REQ = 632,
+ MSG_SMS_HO_TUNE_ON_REQ = 636,
+ MSG_SMS_HO_TUNE_ON_RES = 637,
+ MSG_SMS_HO_TUNE_OFF_REQ = 638,
+ MSG_SMS_HO_TUNE_OFF_RES = 639,
+ MSG_SMS_HO_PEEK_FREQ_REQ = 640,
+ MSG_SMS_HO_PEEK_FREQ_RES = 641,
+ MSG_SMS_HO_PEEK_FREQ_IND = 642,
+ MSG_SMS_MB_ATTEN_SET_REQ = 643,
+ MSG_SMS_MB_ATTEN_SET_RES = 644,
+ MSG_SMS_ENABLE_STAT_IN_I2C_REQ = 649,
+ MSG_SMS_ENABLE_STAT_IN_I2C_RES = 650,
+ MSG_SMS_SET_ANTENNA_CONFIG_REQ = 651,
+ MSG_SMS_SET_ANTENNA_CONFIG_RES = 652,
+ MSG_SMS_GET_STATISTICS_EX_REQ = 653,
+ MSG_SMS_GET_STATISTICS_EX_RES = 654,
+ MSG_SMS_SLEEP_RESUME_COMP_IND = 655,
+ MSG_SMS_SWITCH_HOST_INTERFACE_REQ = 656,
+ MSG_SMS_SWITCH_HOST_INTERFACE_RES = 657,
+ MSG_SMS_DATA_DOWNLOAD_REQ = 660,
+ MSG_SMS_DATA_DOWNLOAD_RES = 661,
+ MSG_SMS_DATA_VALIDITY_REQ = 662,
+ MSG_SMS_DATA_VALIDITY_RES = 663,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_REQ = 664,
+ MSG_SMS_SWDOWNLOAD_TRIGGER_RES = 665,
+ MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ = 666,
+ MSG_SMS_SWDOWNLOAD_BACKDOOR_RES = 667,
+ MSG_SMS_GET_VERSION_EX_REQ = 668,
+ MSG_SMS_GET_VERSION_EX_RES = 669,
+ MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ = 670,
+ MSG_SMS_CLOCK_OUTPUT_CONFIG_RES = 671,
+ MSG_SMS_I2C_SET_FREQ_REQ = 685,
+ MSG_SMS_I2C_SET_FREQ_RES = 686,
+ MSG_SMS_GENERIC_I2C_REQ = 687,
+ MSG_SMS_GENERIC_I2C_RES = 688,
+ MSG_SMS_DVBT_BDA_DATA = 693,
+ MSG_SW_RELOAD_REQ = 697,
+ MSG_SMS_DATA_MSG = 699,
+ MSG_TABLE_UPLOAD_REQ = 700,
+ MSG_TABLE_UPLOAD_RES = 701,
+ MSG_SW_RELOAD_START_REQ = 702,
+ MSG_SW_RELOAD_START_RES = 703,
+ MSG_SW_RELOAD_EXEC_REQ = 704,
+ MSG_SW_RELOAD_EXEC_RES = 705,
+ MSG_SMS_SPI_INT_LINE_SET_REQ = 710,
+ MSG_SMS_SPI_INT_LINE_SET_RES = 711,
+ MSG_SMS_GPIO_CONFIG_EX_REQ = 712,
+ MSG_SMS_GPIO_CONFIG_EX_RES = 713,
+ MSG_SMS_WATCHDOG_ACT_REQ = 716,
+ MSG_SMS_WATCHDOG_ACT_RES = 717,
+ MSG_SMS_LOOPBACK_REQ = 718,
+ MSG_SMS_LOOPBACK_RES = 719,
+ MSG_SMS_RAW_CAPTURE_START_REQ = 720,
+ MSG_SMS_RAW_CAPTURE_START_RES = 721,
+ MSG_SMS_RAW_CAPTURE_ABORT_REQ = 722,
+ MSG_SMS_RAW_CAPTURE_ABORT_RES = 723,
+ MSG_SMS_RAW_CAPTURE_COMPLETE_IND = 728,
+ MSG_SMS_DATA_PUMP_IND = 729,
+ MSG_SMS_DATA_PUMP_REQ = 730,
+ MSG_SMS_DATA_PUMP_RES = 731,
+ MSG_SMS_FLASH_DL_REQ = 732,
+ MSG_SMS_EXEC_TEST_1_REQ = 734,
+ MSG_SMS_EXEC_TEST_1_RES = 735,
+ MSG_SMS_ENBALE_TS_INTERFACE_REQ = 736,
+ MSG_SMS_ENBALE_TS_INTERFACE_RES = 737,
+ MSG_SMS_SPI_SET_BUS_WIDTH_REQ = 738,
+ MSG_SMS_SPI_SET_BUS_WIDTH_RES = 739,
+ MSG_SMS_SEND_EMM_REQ = 740,
+ MSG_SMS_SEND_EMM_RES = 741,
+ MSG_SMS_DISABLE_TS_INTERFACE_REQ = 742,
+ MSG_SMS_DISABLE_TS_INTERFACE_RES = 743,
+ MSG_SMS_IS_BUF_FREE_REQ = 744,
+ MSG_SMS_IS_BUF_FREE_RES = 745,
+ MSG_SMS_EXT_ANTENNA_REQ = 746,
+ MSG_SMS_EXT_ANTENNA_RES = 747,
+ MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE = 748,
+ MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE = 749,
+ MSG_SMS_BATTERY_LEVEL_REQ = 750,
+ MSG_SMS_BATTERY_LEVEL_RES = 751,
+ MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE = 752,
+ MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE = 753,
+ MSG_SMS_FM_RADIO_BLOCK_IND = 754,
+ MSG_SMS_HOST_NOTIFICATION_IND = 755,
+ MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE = 756,
+ MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE = 757,
+ MSG_SMS_CMMB_GET_NETWORKS_REQ = 760,
+ MSG_SMS_CMMB_GET_NETWORKS_RES = 761,
+ MSG_SMS_CMMB_START_SERVICE_REQ = 762,
+ MSG_SMS_CMMB_START_SERVICE_RES = 763,
+ MSG_SMS_CMMB_STOP_SERVICE_REQ = 764,
+ MSG_SMS_CMMB_STOP_SERVICE_RES = 765,
+ MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ = 768,
+ MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES = 769,
+ MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ = 770,
+ MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES = 771,
+ MSG_SMS_CMMB_START_CONTROL_INFO_REQ = 772,
+ MSG_SMS_CMMB_START_CONTROL_INFO_RES = 773,
+ MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ = 774,
+ MSG_SMS_CMMB_STOP_CONTROL_INFO_RES = 775,
+ MSG_SMS_ISDBT_TUNE_REQ = 776,
+ MSG_SMS_ISDBT_TUNE_RES = 777,
+ MSG_SMS_TRANSMISSION_IND = 782,
+ MSG_SMS_PID_STATISTICS_IND = 783,
+ MSG_SMS_POWER_DOWN_IND = 784,
+ MSG_SMS_POWER_DOWN_CONF = 785,
+ MSG_SMS_POWER_UP_IND = 786,
+ MSG_SMS_POWER_UP_CONF = 787,
+ MSG_SMS_POWER_MODE_SET_REQ = 790,
+ MSG_SMS_POWER_MODE_SET_RES = 791,
+ MSG_SMS_DEBUG_HOST_EVENT_REQ = 792,
+ MSG_SMS_DEBUG_HOST_EVENT_RES = 793,
+ MSG_SMS_NEW_CRYSTAL_REQ = 794,
+ MSG_SMS_NEW_CRYSTAL_RES = 795,
+ MSG_SMS_CONFIG_SPI_REQ = 796,
+ MSG_SMS_CONFIG_SPI_RES = 797,
+ MSG_SMS_I2C_SHORT_STAT_IND = 798,
+ MSG_SMS_START_IR_REQ = 800,
+ MSG_SMS_START_IR_RES = 801,
+ MSG_SMS_IR_SAMPLES_IND = 802,
+ MSG_SMS_CMMB_CA_SERVICE_IND = 803,
+ MSG_SMS_SLAVE_DEVICE_DETECTED = 804,
+ MSG_SMS_INTERFACE_LOCK_IND = 805,
+ MSG_SMS_INTERFACE_UNLOCK_IND = 806,
+ MSG_SMS_SEND_ROSUM_BUFF_REQ = 810,
+ MSG_SMS_SEND_ROSUM_BUFF_RES = 811,
+ MSG_SMS_ROSUM_BUFF = 812,
+ MSG_SMS_SET_AES128_KEY_REQ = 815,
+ MSG_SMS_SET_AES128_KEY_RES = 816,
+ MSG_SMS_MBBMS_WRITE_REQ = 817,
+ MSG_SMS_MBBMS_WRITE_RES = 818,
+ MSG_SMS_MBBMS_READ_IND = 819,
+ MSG_SMS_IQ_STREAM_START_REQ = 820,
+ MSG_SMS_IQ_STREAM_START_RES = 821,
+ MSG_SMS_IQ_STREAM_STOP_REQ = 822,
+ MSG_SMS_IQ_STREAM_STOP_RES = 823,
+ MSG_SMS_IQ_STREAM_DATA_BLOCK = 824,
+ MSG_SMS_GET_EEPROM_VERSION_REQ = 825,
+ MSG_SMS_GET_EEPROM_VERSION_RES = 826,
+ MSG_SMS_SIGNAL_DETECTED_IND = 827,
+ MSG_SMS_NO_SIGNAL_IND = 828,
+ MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ = 830,
+ MSG_SMS_MRC_SHUTDOWN_SLAVE_RES = 831,
+ MSG_SMS_MRC_BRINGUP_SLAVE_REQ = 832,
+ MSG_SMS_MRC_BRINGUP_SLAVE_RES = 833,
+ MSG_SMS_EXTERNAL_LNA_CTRL_REQ = 834,
+ MSG_SMS_EXTERNAL_LNA_CTRL_RES = 835,
+ MSG_SMS_SET_PERIODIC_STATISTICS_REQ = 836,
+ MSG_SMS_SET_PERIODIC_STATISTICS_RES = 837,
+ MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ = 838,
+ MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES = 839,
+ LOCAL_TUNE = 850,
+ LOCAL_IFFT_H_ICI = 851,
+ MSG_RESYNC_REQ = 852,
+ MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ = 853,
+ MSG_SMS_CMMB_GET_MRC_STATISTICS_RES = 854,
+ MSG_SMS_LOG_EX_ITEM = 855,
+ MSG_SMS_DEVICE_DATA_LOSS_IND = 856,
+ MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND = 857,
+ MSG_SMS_USER_MSG_REQ = 858,
+ MSG_SMS_USER_MSG_RES = 859,
+ MSG_SMS_SMART_CARD_INIT_REQ = 860,
+ MSG_SMS_SMART_CARD_INIT_RES = 861,
+ MSG_SMS_SMART_CARD_WRITE_REQ = 862,
+ MSG_SMS_SMART_CARD_WRITE_RES = 863,
+ MSG_SMS_SMART_CARD_READ_IND = 864,
+ MSG_SMS_TSE_ENABLE_REQ = 866,
+ MSG_SMS_TSE_ENABLE_RES = 867,
+ MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ = 868,
+ MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES = 869,
+ MSG_SMS_LED_CONFIG_REQ = 870,
+ MSG_SMS_LED_CONFIG_RES = 871,
+ MSG_PWM_ANTENNA_REQ = 872,
+ MSG_PWM_ANTENNA_RES = 873,
+ MSG_SMS_CMMB_SMD_SN_REQ = 874,
+ MSG_SMS_CMMB_SMD_SN_RES = 875,
+ MSG_SMS_CMMB_SET_CA_CW_REQ = 876,
+ MSG_SMS_CMMB_SET_CA_CW_RES = 877,
+ MSG_SMS_CMMB_SET_CA_SALT_REQ = 878,
+ MSG_SMS_CMMB_SET_CA_SALT_RES = 879,
+ MSG_SMS_NSCD_INIT_REQ = 880,
+ MSG_SMS_NSCD_INIT_RES = 881,
+ MSG_SMS_NSCD_PROCESS_SECTION_REQ = 882,
+ MSG_SMS_NSCD_PROCESS_SECTION_RES = 883,
+ MSG_SMS_DBD_CREATE_OBJECT_REQ = 884,
+ MSG_SMS_DBD_CREATE_OBJECT_RES = 885,
+ MSG_SMS_DBD_CONFIGURE_REQ = 886,
+ MSG_SMS_DBD_CONFIGURE_RES = 887,
+ MSG_SMS_DBD_SET_KEYS_REQ = 888,
+ MSG_SMS_DBD_SET_KEYS_RES = 889,
+ MSG_SMS_DBD_PROCESS_HEADER_REQ = 890,
+ MSG_SMS_DBD_PROCESS_HEADER_RES = 891,
+ MSG_SMS_DBD_PROCESS_DATA_REQ = 892,
+ MSG_SMS_DBD_PROCESS_DATA_RES = 893,
+ MSG_SMS_DBD_PROCESS_GET_DATA_REQ = 894,
+ MSG_SMS_DBD_PROCESS_GET_DATA_RES = 895,
+ MSG_SMS_NSCD_OPEN_SESSION_REQ = 896,
+ MSG_SMS_NSCD_OPEN_SESSION_RES = 897,
+ MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ = 898,
+ MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES = 899,
+ MSG_LAST_MSG_TYPE = 900,
+};
#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
- (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
- (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
+ (ptr)->msg_type = type; \
+ (ptr)->msg_src_id = src; \
+ (ptr)->msg_dst_id = dst; \
+ (ptr)->msg_length = len; \
+ (ptr)->msg_flags = 0; \
} while (0)
#define SMS_INIT_MSG(ptr, type, len) \
@@ -277,228 +604,296 @@ enum SMS_DEVICE_MODE {
DEVICE_MODE_ISDBT_BDA,
DEVICE_MODE_CMMB,
DEVICE_MODE_RAW_TUNER,
+ DEVICE_MODE_FM_RADIO,
+ DEVICE_MODE_FM_RADIO_BDA,
+ DEVICE_MODE_ATSC,
DEVICE_MODE_MAX,
};
-struct SmsMsgHdr_ST {
- u16 msgType;
- u8 msgSrcId;
- u8 msgDstId;
- u16 msgLength; /* Length of entire message, including header */
- u16 msgFlags;
+struct sms_msg_hdr {
+ u16 msg_type;
+ u8 msg_src_id;
+ u8 msg_dst_id;
+ u16 msg_length; /* length of entire message, including header */
+ u16 msg_flags;
+};
+
+struct sms_msg_data {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[1];
};
-struct SmsMsgData_ST {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 msgData[1];
+struct sms_msg_data2 {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[2];
};
-struct SmsMsgData_ST2 {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 msgData[2];
+struct sms_msg_data4 {
+ struct sms_msg_hdr x_msg_header;
+ u32 msg_data[4];
};
-struct SmsDataDownload_ST {
- struct SmsMsgHdr_ST xMsgHeader;
- u32 MemAddr;
- u8 Payload[SMS_MAX_PAYLOAD_SIZE];
+struct sms_data_download {
+ struct sms_msg_hdr x_msg_header;
+ u32 mem_addr;
+ u8 payload[SMS_MAX_PAYLOAD_SIZE];
};
-struct SmsVersionRes_ST {
- struct SmsMsgHdr_ST xMsgHeader;
+struct sms_version_res {
+ struct sms_msg_hdr x_msg_header;
- u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
- u8 Step; /* 0 - Step A */
- u8 MetalFix; /* 0 - Metal 0 */
+ u16 chip_model; /* e.g. 0x1102 for SMS-1102 "Nova" */
+ u8 step; /* 0 - step A */
+ u8 metal_fix; /* 0 - Metal 0 */
- /* FirmwareId 0xFF if ROM, otherwise the
+ /* firmware_id 0xFF if ROM, otherwise the
* value indicated by SMSHOSTLIB_DEVICE_MODES_E */
- u8 FirmwareId;
- /* SupportedProtocols Bitwise OR combination of
+ u8 firmware_id;
+ /* supported_protocols Bitwise OR combination of
* supported protocols */
- u8 SupportedProtocols;
+ u8 supported_protocols;
- u8 VersionMajor;
- u8 VersionMinor;
- u8 VersionPatch;
- u8 VersionFieldPatch;
+ u8 version_major;
+ u8 version_minor;
+ u8 version_patch;
+ u8 version_field_patch;
- u8 RomVersionMajor;
- u8 RomVersionMinor;
- u8 RomVersionPatch;
- u8 RomVersionFieldPatch;
+ u8 rom_ver_major;
+ u8 rom_ver_minor;
+ u8 rom_ver_patch;
+ u8 rom_ver_field_patch;
u8 TextLabel[34];
};
-struct SmsFirmware_ST {
- u32 CheckSum;
- u32 Length;
- u32 StartAddress;
- u8 Payload[1];
+struct sms_firmware {
+ u32 check_sum;
+ u32 length;
+ u32 start_address;
+ u8 payload[1];
};
-/* Statistics information returned as response for
- * SmsHostApiGetStatistics_Req */
-struct SMSHOSTLIB_STATISTICS_ST {
- u32 Reserved; /* Reserved */
+/* statistics information returned as response for
+ * SmsHostApiGetstatistics_Req */
+struct sms_stats {
+ u32 reserved; /* reserved */
/* Common parameters */
- u32 IsRfLocked; /* 0 - not locked, 1 - locked */
- u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
- u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
/* Reception quality */
s32 SNR; /* dB */
- u32 BER; /* Post Viterbi BER [1E-5] */
+ u32 ber; /* Post Viterbi ber [1E-5] */
u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
- u32 TS_PER; /* Transport stream PER,
+ u32 ts_per; /* Transport stream PER,
0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
u32 MFER; /* DVB-H frame error rate in percentage,
0xFFFFFFFF indicate N/A, valid only for DVB-H */
s32 RSSI; /* dBm */
- s32 InBandPwr; /* In band power in dBM */
- s32 CarrierOffset; /* Carrier Offset in bin/1024 */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
/* Transmission parameters */
- u32 Frequency; /* Frequency in Hz */
- u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */
- u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz, valid only for DVB-T/H */
+ u32 transmission_mode; /* Transmission Mode, for DAB modes 1-4,
for DVB-T/H FFT mode carriers in Kilos */
- u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
valid only for DVB-T/H */
- u32 GuardInterval; /* Guard Interval from
- SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */
- u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ u32 guard_interval; /* Guard Interval from
+ SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
valid only for DVB-T/H */
- u32 LPCodeRate; /* Low Priority Code Rate from
+ u32 lp_code_rate; /* Low Priority Code Rate from
SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
- u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+ u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET,
valid only for DVB-T/H */
- u32 Constellation; /* Constellation from
+ u32 constellation; /* constellation from
SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
/* Burst parameters, valid only for DVB-H */
- u32 BurstSize; /* Current burst size in bytes,
+ u32 burst_size; /* Current burst size in bytes,
valid only for DVB-H */
- u32 BurstDuration; /* Current burst duration in mSec,
+ u32 burst_duration; /* Current burst duration in mSec,
valid only for DVB-H */
- u32 BurstCycleTime; /* Current burst cycle time in mSec,
+ u32 burst_cycle_time; /* Current burst cycle time in mSec,
valid only for DVB-H */
- u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
+ u32 calc_burst_cycle_time;/* Current burst cycle time in mSec,
as calculated by demodulator, valid only for DVB-H */
- u32 NumOfRows; /* Number of rows in MPE table,
+ u32 num_of_rows; /* Number of rows in MPE table,
valid only for DVB-H */
- u32 NumOfPaddCols; /* Number of padding columns in MPE table,
+ u32 num_of_padd_cols; /* Number of padding columns in MPE table,
valid only for DVB-H */
- u32 NumOfPunctCols; /* Number of puncturing columns in MPE table,
+ u32 num_of_punct_cols; /* Number of puncturing columns in MPE table,
valid only for DVB-H */
- u32 ErrorTSPackets; /* Number of erroneous
+ u32 error_ts_packets; /* Number of erroneous
transport-stream packets */
- u32 TotalTSPackets; /* Total number of transport-stream packets */
- u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+ u32 num_of_valid_mpe_tlbs; /* Number of MPE tables which do not include
errors after MPE RS decoding */
- u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+ u32 num_of_invalid_mpe_tlbs;/* Number of MPE tables which include errors
after MPE RS decoding */
- u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
+ u32 num_of_corrected_mpe_tlbs;/* Number of MPE tables which were
corrected by MPE RS decoding */
/* Common params */
- u32 BERErrorCount; /* Number of errornous SYNC bits. */
- u32 BERBitCount; /* Total number of SYNC bits. */
+ u32 ber_error_count; /* Number of errornous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
/* Interface information */
- u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+ u32 sms_to_host_tx_errors; /* Total number of transmission errors. */
/* DAB/T-DMB */
- u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+ u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi ber [1E-5] */
/* DVB-H TPS parameters */
- u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
if set to 0xFFFFFFFF cell_id not yet recovered */
- u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
+ u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
- u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
+ u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
- u32 NumMPEReceived; /* DVB-H, Num MPE section received */
+ u32 num_mpe_received; /* DVB-H, Num MPE section received */
- u32 ReservedFields[10]; /* Reserved */
+ u32 reservedFields[10]; /* reserved */
};
-struct SmsMsgStatisticsInfo_ST {
- u32 RequestResult;
+struct sms_msg_statistics_info {
+ u32 request_result;
- struct SMSHOSTLIB_STATISTICS_ST Stat;
+ struct sms_stats stat;
/* Split the calc of the SNR in DAB */
- u32 Signal; /* dB */
- u32 Noise; /* dB */
+ u32 signal; /* dB */
+ u32 noise; /* dB */
};
-struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
+struct sms_isdbt_layer_stats {
/* Per-layer information */
- u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
* 255 means layer does not exist */
- u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
+ u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET,
* 255 means layer does not exist */
- u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
- u32 BERErrorCount; /* Post Viterbi Error Bits Count */
- u32 BERBitCount; /* Post Viterbi Total Bits Count */
- u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
- u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
- u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
- u32 TotalTSPackets; /* Total number of transport-stream packets */
- u32 TILdepthI; /* Time interleaver depth I parameter,
+ u32 ber; /* Post Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 ber_error_count; /* Post Viterbi Error Bits Count */
+ u32 ber_bit_count; /* Post Viterbi Total Bits Count */
+ u32 pre_ber; /* Pre Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */
+ u32 ts_per; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
+ u32 error_ts_packets; /* Number of erroneous transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+ u32 ti_ldepth_i; /* Time interleaver depth I parameter,
* 255 means layer does not exist */
- u32 NumberOfSegments; /* Number of segments in layer A,
+ u32 number_of_segments; /* Number of segments in layer A,
* 255 means layer does not exist */
- u32 TMCCErrors; /* TMCC errors */
+ u32 tmcc_errors; /* TMCC errors */
};
-struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
- u32 StatisticsType; /* Enumerator identifying the type of the
+struct sms_isdbt_stats {
+ u32 statistics_type; /* Enumerator identifying the type of the
* structure. Values are the same as
* SMSHOSTLIB_DEVICE_MODES_E
*
* This field MUST always be first in any
* statistics structure */
- u32 FullSize; /* Total size of the structure returned by the modem.
+ u32 full_size; /* Total size of the structure returned by the modem.
* If the size requested by the host is smaller than
- * FullSize, the struct will be truncated */
+ * full_size, the struct will be truncated */
/* Common parameters */
- u32 IsRfLocked; /* 0 - not locked, 1 - locked */
- u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
- u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
/* Reception quality */
s32 SNR; /* dB */
s32 RSSI; /* dBm */
- s32 InBandPwr; /* In band power in dBM */
- s32 CarrierOffset; /* Carrier Offset in Hz */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in Hz */
/* Transmission parameters */
- u32 Frequency; /* Frequency in Hz */
- u32 Bandwidth; /* Bandwidth in MHz */
- u32 TransmissionMode; /* ISDB-T transmission mode */
- u32 ModemState; /* 0 - Acquisition, 1 - Locked */
- u32 GuardInterval; /* Guard Interval, 1 divided by value */
- u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
- u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
- u32 NumOfLayers; /* Number of ISDB-T layers in the network */
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* ISDB-T transmission mode */
+ u32 modem_state; /* 0 - Acquisition, 1 - Locked */
+ u32 guard_interval; /* Guard Interval, 1 divided by value */
+ u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */
+ u32 num_of_layers; /* Number of ISDB-T layers in the network */
/* Per-layer information */
/* Layers A, B and C */
- struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3];
- /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
+ struct sms_isdbt_layer_stats layer_info[3];
+ /* Per-layer statistics, see sms_isdbt_layer_stats */
/* Interface information */
- u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+ u32 sms_to_host_tx_errors; /* Total number of transmission errors. */
};
-struct PID_STATISTICS_DATA_S {
+struct sms_isdbt_stats_ex {
+ u32 statistics_type; /* Enumerator identifying the type of the
+ * structure. Values are the same as
+ * SMSHOSTLIB_DEVICE_MODES_E
+ *
+ * This field MUST always be first in any
+ * statistics structure */
+
+ u32 full_size; /* Total size of the structure returned by the modem.
+ * If the size requested by the host is smaller than
+ * full_size, the struct will be truncated */
+
+ /* Common parameters */
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ /* Reception quality */
+ s32 SNR; /* dB */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in Hz */
+
+ /* Transmission parameters */
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* ISDB-T transmission mode */
+ u32 modem_state; /* 0 - Acquisition, 1 - Locked */
+ u32 guard_interval; /* Guard Interval, 1 divided by value */
+ u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
+ u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */
+ u32 num_of_layers; /* Number of ISDB-T layers in the network */
+
+ u32 segment_number; /* Segment number for ISDB-Tsb */
+ u32 tune_bw; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */
+
+ /* Per-layer information */
+ /* Layers A, B and C */
+ struct sms_isdbt_layer_stats layer_info[3];
+ /* Per-layer statistics, see sms_isdbt_layer_stats */
+
+ /* Interface information */
+ u32 reserved1; /* Was sms_to_host_tx_errors - obsolete . */
+ /* Proprietary information */
+ u32 ext_antenna; /* Obsolete field. */
+ u32 reception_quality;
+ u32 ews_alert_active; /* signals if EWS alert is currently on */
+ u32 lna_on_off; /* Internal LNA state: 0: OFF, 1: ON */
+
+ u32 rf_agc_level; /* RF AGC Level [linear units], full gain = 65535 (20dB) */
+ u32 bb_agc_level; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */
+ u32 fw_errors_counter; /* Application errors - should be always zero */
+ u8 FwErrorsHistoryArr[8]; /* Last FW errors IDs - first is most recent, last is oldest */
+
+ s32 MRC_SNR; /* dB */
+ u32 snr_full_res; /* dB x 65536 */
+ u32 reserved4[4];
+};
+
+
+struct sms_pid_stats_data {
struct PID_BURST_S {
u32 size;
u32 padding_cols;
@@ -513,112 +908,155 @@ struct PID_STATISTICS_DATA_S {
u32 tot_cor_tbl;
};
-struct PID_DATA_S {
+struct sms_pid_data {
u32 pid;
u32 num_rows;
- struct PID_STATISTICS_DATA_S pid_statistics;
+ struct sms_pid_stats_data pid_statistics;
};
#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
-#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.bandwidth = 8 - _stat.bandwidth)
#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
- if (_stat.TransmissionMode == 0) \
- _stat.TransmissionMode = 2; \
- else if (_stat.TransmissionMode == 1) \
- _stat.TransmissionMode = 8; \
+ if (_stat.transmission_mode == 0) \
+ _stat.transmission_mode = 2; \
+ else if (_stat.transmission_mode == 1) \
+ _stat.transmission_mode = 8; \
else \
- _stat.TransmissionMode = 4;
+ _stat.transmission_mode = 4;
-struct TRANSMISSION_STATISTICS_S {
- u32 Frequency; /* Frequency in Hz */
- u32 Bandwidth; /* Bandwidth in MHz */
- u32 TransmissionMode; /* FFT mode carriers in Kilos */
- u32 GuardInterval; /* Guard Interval from
+struct sms_tx_stats {
+ u32 frequency; /* frequency in Hz */
+ u32 bandwidth; /* bandwidth in MHz */
+ u32 transmission_mode; /* FFT mode carriers in Kilos */
+ u32 guard_interval; /* Guard Interval from
SMSHOSTLIB_GUARD_INTERVALS_ET */
- u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
- u32 LPCodeRate; /* Low Priority Code Rate from
+ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+ u32 lp_code_rate; /* Low Priority Code Rate from
SMSHOSTLIB_CODE_RATE_ET */
- u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
- u32 Constellation; /* Constellation from
+ u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+ u32 constellation; /* constellation from
SMSHOSTLIB_CONSTELLATION_ET */
/* DVB-H TPS parameters */
- u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
if set to 0xFFFFFFFF cell_id not yet recovered */
- u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
+ u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
- u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
+ u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
- u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+};
+
+struct sms_rx_stats {
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
+
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+ s32 SNR; /* dB */
+ u32 ber; /* Post Viterbi ber [1E-5] */
+ u32 ber_error_count; /* Number of erronous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+ u32 ts_per; /* Transport stream PER,
+ 0xFFFFFFFF indicate N/A */
+ u32 MFER; /* DVB-H frame error rate in percentage,
+ 0xFFFFFFFF indicate N/A, valid only for DVB-H */
+ s32 RSSI; /* dBm */
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+ u32 error_ts_packets; /* Number of erroneous
+ transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+
+ s32 MRC_SNR; /* dB */
+ s32 MRC_RSSI; /* dBm */
+ s32 mrc_in_band_pwr; /* In band power in dBM */
};
-struct RECEPTION_STATISTICS_S {
- u32 IsRfLocked; /* 0 - not locked, 1 - locked */
- u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
- u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+struct sms_rx_stats_ex {
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */
- u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
s32 SNR; /* dB */
- u32 BER; /* Post Viterbi BER [1E-5] */
- u32 BERErrorCount; /* Number of erronous SYNC bits. */
- u32 BERBitCount; /* Total number of SYNC bits. */
- u32 TS_PER; /* Transport stream PER,
+ u32 ber; /* Post Viterbi ber [1E-5] */
+ u32 ber_error_count; /* Number of erronous SYNC bits. */
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+ u32 ts_per; /* Transport stream PER,
0xFFFFFFFF indicate N/A */
u32 MFER; /* DVB-H frame error rate in percentage,
0xFFFFFFFF indicate N/A, valid only for DVB-H */
s32 RSSI; /* dBm */
- s32 InBandPwr; /* In band power in dBM */
- s32 CarrierOffset; /* Carrier Offset in bin/1024 */
- u32 ErrorTSPackets; /* Number of erroneous
+ s32 in_band_pwr; /* In band power in dBM */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+ u32 error_ts_packets; /* Number of erroneous
transport-stream packets */
- u32 TotalTSPackets; /* Total number of transport-stream packets */
+ u32 total_ts_packets; /* Total number of transport-stream packets */
+
+ s32 ref_dev_ppm;
+ s32 freq_dev_hz;
s32 MRC_SNR; /* dB */
s32 MRC_RSSI; /* dBm */
- s32 MRC_InBandPwr; /* In band power in dBM */
+ s32 mrc_in_band_pwr; /* In band power in dBM */
};
-/* Statistics information returned as response for
- * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
-struct SMSHOSTLIB_STATISTICS_DVB_S {
+/* statistics information returned as response for
+ * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */
+struct sms_stats_dvb {
/* Reception */
- struct RECEPTION_STATISTICS_S ReceptionData;
+ struct sms_rx_stats reception_data;
/* Transmission parameters */
- struct TRANSMISSION_STATISTICS_S TransmissionData;
+ struct sms_tx_stats transmission_data;
/* Burst parameters, valid only for DVB-H */
#define SRVM_MAX_PID_FILTERS 8
- struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
+ struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS];
};
-struct SRVM_SIGNAL_STATUS_S {
+/* statistics information returned as response for
+ * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */
+struct sms_stats_dvb_ex {
+ /* Reception */
+ struct sms_rx_stats_ex reception_data;
+
+ /* Transmission parameters */
+ struct sms_tx_stats transmission_data;
+
+ /* Burst parameters, valid only for DVB-H */
+#define SRVM_MAX_PID_FILTERS 8
+ struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS];
+};
+
+struct sms_srvm_signal_status {
u32 result;
u32 snr;
- u32 tsPackets;
- u32 etsPackets;
+ u32 ts_packets;
+ u32 ets_packets;
u32 constellation;
- u32 hpCode;
- u32 tpsSrvIndLP;
- u32 tpsSrvIndHP;
- u32 cellId;
+ u32 hp_code;
+ u32 tps_srv_ind_lp;
+ u32 tps_srv_ind_hp;
+ u32 cell_id;
u32 reason;
- s32 inBandPower;
- u32 requestId;
+ s32 in_band_power;
+ u32 request_id;
};
-struct SMSHOSTLIB_I2C_REQ_ST {
- u32 DeviceAddress; /* I2c device address */
- u32 WriteCount; /* number of bytes to write */
- u32 ReadCount; /* number of bytes to read */
+struct sms_i2c_req {
+ u32 device_address; /* I2c device address */
+ u32 write_count; /* number of bytes to write */
+ u32 read_count; /* number of bytes to read */
u8 Data[1];
};
-struct SMSHOSTLIB_I2C_RES_ST {
- u32 Status; /* non-zero value in case of failure */
- u32 ReadCount; /* number of bytes read */
+struct sms_i2c_res {
+ u32 status; /* non-zero value in case of failure */
+ u32 read_count; /* number of bytes read */
u8 Data[1];
};
@@ -638,59 +1076,39 @@ struct smscore_config_gpio {
#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
u8 inputcharacteristics;
-#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
-#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
- u8 outputslewrate;
-
-#define SMS_GPIO_OUTPUTDRIVING_4mA 0
-#define SMS_GPIO_OUTPUTDRIVING_8mA 1
-#define SMS_GPIO_OUTPUTDRIVING_12mA 2
-#define SMS_GPIO_OUTPUTDRIVING_16mA 3
- u8 outputdriving;
-};
-
-struct smscore_gpio_config {
-#define SMS_GPIO_DIRECTION_INPUT 0
-#define SMS_GPIO_DIRECTION_OUTPUT 1
- u8 Direction;
-
-#define SMS_GPIO_PULL_UP_DOWN_NONE 0
-#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
-#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2
-#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3
- u8 PullUpDown;
-
-#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0
-#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
- u8 InputCharacteristics;
-
-#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */
+ /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0
+#define SMS_GPIO_OUTPUT_SLEW_WRATE_SLOW 1
+ /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3
-#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */
-#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */
- u8 OutputSlewRate;
+ u8 outputslewrate;
-#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */
-#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */
+ /* 10xx */
+#define SMS_GPIO_OUTPUTDRIVING_S_4mA 0
+#define SMS_GPIO_OUTPUTDRIVING_S_8mA 1
+#define SMS_GPIO_OUTPUTDRIVING_S_12mA 2
+#define SMS_GPIO_OUTPUTDRIVING_S_16mA 3
+
+ /* 11xx*/
+#define SMS_GPIO_OUTPUTDRIVING_1_5mA 0
+#define SMS_GPIO_OUTPUTDRIVING_2_8mA 1
+#define SMS_GPIO_OUTPUTDRIVING_4mA 2
+#define SMS_GPIO_OUTPUTDRIVING_7mA 3
+#define SMS_GPIO_OUTPUTDRIVING_10mA 4
+#define SMS_GPIO_OUTPUTDRIVING_11mA 5
+#define SMS_GPIO_OUTPUTDRIVING_14mA 6
+#define SMS_GPIO_OUTPUTDRIVING_16mA 7
-#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */
-#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */
- u8 OutputDriving;
+ u8 outputdriving;
};
-extern void smscore_registry_setmode(char *devpath, int mode);
+char *smscore_translate_msg(enum msg_types msgtype);
+
extern int smscore_registry_getmode(char *devpath);
extern int smscore_register_hotplug(hotplug_t hotplug);
@@ -721,8 +1139,6 @@ extern void smscore_onresponse(struct smscore_device_t *coredev,
extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
struct vm_area_struct *vma);
-extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
- int mode, char *filename);
extern int smscore_send_fw_file(struct smscore_device_t *coredev,
u8 *ufwbuf, int size);
@@ -737,11 +1153,11 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
/* new GPIO management */
-extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
- struct smscore_gpio_config *pGpioConfig);
-extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
- u8 NewLevel);
-extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
+ struct smscore_config_gpio *p_gpio_config);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num,
+ u8 new_level);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num,
u8 *level);
void smscore_set_board_id(struct smscore_device_t *core, int id);
@@ -760,7 +1176,8 @@ int smscore_led_state(struct smscore_device_t *core, int led);
#define dprintk(kern, lvl, fmt, arg...) do {\
if (sms_dbg & lvl) \
- sms_printk(kern, fmt, ##arg); } while (0)
+ sms_printk(kern, fmt, ##arg); \
+} while (0)
#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
#define sms_err(fmt, arg...) \
diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c
new file mode 100644
index 000000000000..0bb4430535f9
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb-debugfs.c
@@ -0,0 +1,551 @@
+/***********************************************************************
+ *
+ * Copyright(c) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ***********************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "smscoreapi.h"
+
+#include "smsdvb.h"
+
+static struct dentry *smsdvb_debugfs_usb_root;
+
+struct smsdvb_debugfs {
+ struct kref refcount;
+ spinlock_t lock;
+
+ char stats_data[PAGE_SIZE];
+ unsigned stats_count;
+ bool stats_was_read;
+
+ wait_queue_head_t stats_queue;
+};
+
+static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
+ struct sms_stats *p)
+{
+ int n = 0;
+ char *buf;
+
+ spin_lock(&debug_data->lock);
+ if (debug_data->stats_count) {
+ spin_unlock(&debug_data->lock);
+ return;
+ }
+
+ buf = debug_data->stats_data;
+
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_rf_locked = %d\n", p->is_rf_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_demod_locked = %d\n", p->is_demod_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_external_lna_on = %d\n", p->is_external_lna_on);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "SNR = %d\n", p->SNR);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "ber = %d\n", p->ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "FIB_CRC = %d\n", p->FIB_CRC);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "ts_per = %d\n", p->ts_per);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "MFER = %d\n", p->MFER);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "RSSI = %d\n", p->RSSI);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "in_band_pwr = %d\n", p->in_band_pwr);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "carrier_offset = %d\n", p->carrier_offset);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "modem_state = %d\n", p->modem_state);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "frequency = %d\n", p->frequency);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "bandwidth = %d\n", p->bandwidth);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "transmission_mode = %d\n", p->transmission_mode);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "modem_state = %d\n", p->modem_state);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "guard_interval = %d\n", p->guard_interval);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "code_rate = %d\n", p->code_rate);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "lp_code_rate = %d\n", p->lp_code_rate);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "hierarchy = %d\n", p->hierarchy);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "constellation = %d\n", p->constellation);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "burst_size = %d\n", p->burst_size);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "burst_duration = %d\n", p->burst_duration);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "burst_cycle_time = %d\n", p->burst_cycle_time);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "calc_burst_cycle_time = %d\n",
+ p->calc_burst_cycle_time);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_rows = %d\n", p->num_of_rows);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_padd_cols = %d\n", p->num_of_padd_cols);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_punct_cols = %d\n", p->num_of_punct_cols);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "error_ts_packets = %d\n", p->error_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "total_ts_packets = %d\n", p->total_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "ber_error_count = %d\n", p->ber_error_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "ber_bit_count = %d\n", p->ber_bit_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "pre_ber = %d\n", p->pre_ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "cell_id = %d\n", p->cell_id);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_mpe_received = %d\n", p->num_mpe_received);
+
+ debug_data->stats_count = n;
+ spin_unlock(&debug_data->lock);
+ wake_up(&debug_data->stats_queue);
+}
+
+static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
+ struct sms_isdbt_stats *p)
+{
+ int i, n = 0;
+ char *buf;
+
+ spin_lock(&debug_data->lock);
+ if (debug_data->stats_count) {
+ spin_unlock(&debug_data->lock);
+ return;
+ }
+
+ buf = debug_data->stats_data;
+
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "statistics_type = %d\t", p->statistics_type);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "full_size = %d\n", p->full_size);
+
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_rf_locked = %d\t\t", p->is_rf_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_demod_locked = %d\t", p->is_demod_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_external_lna_on = %d\n", p->is_external_lna_on);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "SNR = %d dB\t\t", p->SNR);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "RSSI = %d dBm\t\t", p->RSSI);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "in_band_pwr = %d dBm\n", p->in_band_pwr);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "carrier_offset = %d\t", p->carrier_offset);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "bandwidth = %d\t\t", p->bandwidth);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "frequency = %d Hz\n", p->frequency);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "transmission_mode = %d\t", p->transmission_mode);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "modem_state = %d\t\t", p->modem_state);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "guard_interval = %d\n", p->guard_interval);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "system_type = %d\t\t", p->system_type);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "partial_reception = %d\t", p->partial_reception);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_layers = %d\n", p->num_of_layers);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
+
+ for (i = 0; i < 3; i++) {
+ if (p->layer_info[i].number_of_segments < 1 ||
+ p->layer_info[i].number_of_segments > 13)
+ continue;
+
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
+ p->layer_info[i].code_rate);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
+ p->layer_info[i].constellation);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
+ p->layer_info[i].ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
+ p->layer_info[i].ber_error_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
+ p->layer_info[i].ber_bit_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
+ p->layer_info[i].pre_ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
+ p->layer_info[i].ts_per);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
+ p->layer_info[i].error_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
+ p->layer_info[i].total_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
+ p->layer_info[i].ti_ldepth_i);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "\tnumber_of_segments = %d\t",
+ p->layer_info[i].number_of_segments);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
+ p->layer_info[i].tmcc_errors);
+ }
+
+ debug_data->stats_count = n;
+ spin_unlock(&debug_data->lock);
+ wake_up(&debug_data->stats_queue);
+}
+
+static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
+ struct sms_isdbt_stats_ex *p)
+{
+ int i, n = 0;
+ char *buf;
+
+ spin_lock(&debug_data->lock);
+ if (debug_data->stats_count) {
+ spin_unlock(&debug_data->lock);
+ return;
+ }
+
+ buf = debug_data->stats_data;
+
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "statistics_type = %d\t", p->statistics_type);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "full_size = %d\n", p->full_size);
+
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_rf_locked = %d\t\t", p->is_rf_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_demod_locked = %d\t", p->is_demod_locked);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "is_external_lna_on = %d\n", p->is_external_lna_on);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "SNR = %d dB\t\t", p->SNR);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "RSSI = %d dBm\t\t", p->RSSI);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "in_band_pwr = %d dBm\n", p->in_band_pwr);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "carrier_offset = %d\t", p->carrier_offset);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "bandwidth = %d\t\t", p->bandwidth);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "frequency = %d Hz\n", p->frequency);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "transmission_mode = %d\t", p->transmission_mode);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "modem_state = %d\t\t", p->modem_state);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "guard_interval = %d\n", p->guard_interval);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "system_type = %d\t\t", p->system_type);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "partial_reception = %d\t", p->partial_reception);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "num_of_layers = %d\n", p->num_of_layers);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
+ p->segment_number);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
+ p->tune_bw);
+
+ for (i = 0; i < 3; i++) {
+ if (p->layer_info[i].number_of_segments < 1 ||
+ p->layer_info[i].number_of_segments > 13)
+ continue;
+
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
+ p->layer_info[i].code_rate);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
+ p->layer_info[i].constellation);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
+ p->layer_info[i].ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
+ p->layer_info[i].ber_error_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
+ p->layer_info[i].ber_bit_count);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
+ p->layer_info[i].pre_ber);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
+ p->layer_info[i].ts_per);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
+ p->layer_info[i].error_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
+ p->layer_info[i].total_ts_packets);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
+ p->layer_info[i].ti_ldepth_i);
+ n += snprintf(&buf[n], PAGE_SIZE - n,
+ "\tnumber_of_segments = %d\t",
+ p->layer_info[i].number_of_segments);
+ n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
+ p->layer_info[i].tmcc_errors);
+ }
+
+
+ debug_data->stats_count = n;
+ spin_unlock(&debug_data->lock);
+
+ wake_up(&debug_data->stats_queue);
+}
+
+static int smsdvb_stats_open(struct inode *inode, struct file *file)
+{
+ struct smsdvb_client_t *client = inode->i_private;
+ struct smsdvb_debugfs *debug_data = client->debug_data;
+
+ kref_get(&debug_data->refcount);
+
+ spin_lock(&debug_data->lock);
+ debug_data->stats_count = 0;
+ debug_data->stats_was_read = false;
+ spin_unlock(&debug_data->lock);
+
+ file->private_data = debug_data;
+
+ return 0;
+}
+
+static void smsdvb_debugfs_data_release(struct kref *ref)
+{
+ struct smsdvb_debugfs *debug_data;
+
+ debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
+ kfree(debug_data);
+}
+
+static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
+{
+ int rc = 1;
+
+ spin_lock(&debug_data->lock);
+
+ if (debug_data->stats_was_read)
+ goto exit;
+
+ rc = debug_data->stats_count;
+
+exit:
+ spin_unlock(&debug_data->lock);
+ return rc;
+}
+
+static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait)
+{
+ struct smsdvb_debugfs *debug_data = file->private_data;
+ int rc;
+
+ kref_get(&debug_data->refcount);
+
+ poll_wait(file, &debug_data->stats_queue, wait);
+
+ rc = smsdvb_stats_wait_read(debug_data);
+ if (rc > 0)
+ rc = POLLIN | POLLRDNORM;
+
+ kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
+
+ return rc;
+}
+
+static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
+ size_t nbytes, loff_t *ppos)
+{
+ int rc = 0, len;
+ struct smsdvb_debugfs *debug_data = file->private_data;
+
+ kref_get(&debug_data->refcount);
+
+ if (file->f_flags & O_NONBLOCK) {
+ rc = smsdvb_stats_wait_read(debug_data);
+ if (!rc) {
+ rc = -EWOULDBLOCK;
+ goto ret;
+ }
+ } else {
+ rc = wait_event_interruptible(debug_data->stats_queue,
+ smsdvb_stats_wait_read(debug_data));
+ if (rc < 0)
+ goto ret;
+ }
+
+ if (debug_data->stats_was_read) {
+ rc = 0; /* EOF */
+ goto ret;
+ }
+
+ len = debug_data->stats_count - *ppos;
+ if (len >= 0)
+ rc = simple_read_from_buffer(user_buf, nbytes, ppos,
+ debug_data->stats_data, len);
+ else
+ rc = 0;
+
+ if (*ppos >= debug_data->stats_count) {
+ spin_lock(&debug_data->lock);
+ debug_data->stats_was_read = true;
+ spin_unlock(&debug_data->lock);
+ }
+ret:
+ kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
+ return rc;
+}
+
+static int smsdvb_stats_release(struct inode *inode, struct file *file)
+{
+ struct smsdvb_debugfs *debug_data = file->private_data;
+
+ spin_lock(&debug_data->lock);
+ debug_data->stats_was_read = true; /* return EOF to read() */
+ spin_unlock(&debug_data->lock);
+ wake_up_interruptible_sync(&debug_data->stats_queue);
+
+ kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations debugfs_stats_ops = {
+ .open = smsdvb_stats_open,
+ .poll = smsdvb_stats_poll,
+ .read = smsdvb_stats_read,
+ .release = smsdvb_stats_release,
+ .llseek = generic_file_llseek,
+};
+
+/*
+ * Functions used by smsdvb, in order to create the interfaces
+ */
+
+int smsdvb_debugfs_create(struct smsdvb_client_t *client)
+{
+ struct smscore_device_t *coredev = client->coredev;
+ struct dentry *d;
+ struct smsdvb_debugfs *debug_data;
+
+ if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device)
+ return -ENODEV;
+
+ client->debugfs = debugfs_create_dir(coredev->devpath,
+ smsdvb_debugfs_usb_root);
+ if (IS_ERR_OR_NULL(client->debugfs)) {
+ pr_info("Unable to create debugfs %s directory.\n",
+ coredev->devpath);
+ return -ENODEV;
+ }
+
+ d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs,
+ client, &debugfs_stats_ops);
+ if (!d) {
+ debugfs_remove(client->debugfs);
+ return -ENOMEM;
+ }
+
+ debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL);
+ if (!debug_data)
+ return -ENOMEM;
+
+ client->debug_data = debug_data;
+ client->prt_dvb_stats = smsdvb_print_dvb_stats;
+ client->prt_isdb_stats = smsdvb_print_isdb_stats;
+ client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex;
+
+ init_waitqueue_head(&debug_data->stats_queue);
+ spin_lock_init(&debug_data->lock);
+ kref_init(&debug_data->refcount);
+
+ return 0;
+}
+
+void smsdvb_debugfs_release(struct smsdvb_client_t *client)
+{
+ if (!client->debugfs)
+ return;
+
+ client->prt_dvb_stats = NULL;
+ client->prt_isdb_stats = NULL;
+ client->prt_isdb_stats_ex = NULL;
+
+ debugfs_remove_recursive(client->debugfs);
+ kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release);
+
+ client->debug_data = NULL;
+ client->debugfs = NULL;
+}
+
+int smsdvb_debugfs_register(void)
+{
+ struct dentry *d;
+
+ /*
+ * FIXME: This was written to debug Siano USB devices. So, it creates
+ * the debugfs node under <debugfs>/usb.
+ * A similar logic would be needed for Siano sdio devices, but, in that
+ * case, usb_debug_root is not a good choice.
+ *
+ * Perhaps the right fix here would be to create another sysfs root
+ * node for sdio-based boards, but this may need some logic at sdio
+ * subsystem.
+ */
+ d = debugfs_create_dir("smsdvb", usb_debug_root);
+ if (IS_ERR_OR_NULL(d)) {
+ sms_err("Couldn't create sysfs node for smsdvb");
+ return PTR_ERR(d);
+ } else {
+ smsdvb_debugfs_usb_root = d;
+ }
+ return 0;
+}
+
+void smsdvb_debugfs_unregister(void)
+{
+ debugfs_remove_recursive(smsdvb_debugfs_usb_root);
+ smsdvb_debugfs_usb_root = NULL;
+}
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
new file mode 100644
index 000000000000..297f1b2f9a32
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -0,0 +1,1230 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/div64.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+#include "smsdvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct list_head g_smsdvb_clients;
+static struct mutex g_smsdvb_clientslock;
+
+static int sms_dbg;
+module_param_named(debug, sms_dbg, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
+
+
+u32 sms_to_guard_interval_table[] = {
+ [0] = GUARD_INTERVAL_1_32,
+ [1] = GUARD_INTERVAL_1_16,
+ [2] = GUARD_INTERVAL_1_8,
+ [3] = GUARD_INTERVAL_1_4,
+};
+
+u32 sms_to_code_rate_table[] = {
+ [0] = FEC_1_2,
+ [1] = FEC_2_3,
+ [2] = FEC_3_4,
+ [3] = FEC_5_6,
+ [4] = FEC_7_8,
+};
+
+
+u32 sms_to_hierarchy_table[] = {
+ [0] = HIERARCHY_NONE,
+ [1] = HIERARCHY_1,
+ [2] = HIERARCHY_2,
+ [3] = HIERARCHY_4,
+};
+
+u32 sms_to_modulation_table[] = {
+ [0] = QPSK,
+ [1] = QAM_16,
+ [2] = QAM_64,
+ [3] = DQPSK,
+};
+
+
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+ enum SMS_DVB3_EVENTS event) {
+
+ struct smscore_device_t *coredev = client->coredev;
+ switch (event) {
+ case DVB3_EVENT_INIT:
+ sms_debug("DVB3_EVENT_INIT");
+ sms_board_event(coredev, BOARD_EVENT_BIND);
+ break;
+ case DVB3_EVENT_SLEEP:
+ sms_debug("DVB3_EVENT_SLEEP");
+ sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+ break;
+ case DVB3_EVENT_HOTPLUG:
+ sms_debug("DVB3_EVENT_HOTPLUG");
+ sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+ break;
+ case DVB3_EVENT_FE_LOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_LOCK;
+ sms_debug("DVB3_EVENT_FE_LOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+ }
+ break;
+ case DVB3_EVENT_FE_UNLOCK:
+ if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+ client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+ sms_debug("DVB3_EVENT_FE_UNLOCK");
+ sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+ }
+ break;
+ case DVB3_EVENT_UNC_OK:
+ if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+ client->event_unc_state = DVB3_EVENT_UNC_OK;
+ sms_debug("DVB3_EVENT_UNC_OK");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+ }
+ break;
+ case DVB3_EVENT_UNC_ERR:
+ if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+ client->event_unc_state = DVB3_EVENT_UNC_ERR;
+ sms_debug("DVB3_EVENT_UNC_ERR");
+ sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+ }
+ break;
+
+ default:
+ sms_err("Unknown dvb3 api event");
+ break;
+ }
+}
+
+static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int i, n_layers;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ n_layers = 4;
+ default:
+ n_layers = 1;
+ }
+
+ /* Global stats */
+ c->strength.len = 1;
+ c->cnr.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+ /* Per-layer stats */
+ c->post_bit_error.len = n_layers;
+ c->post_bit_count.len = n_layers;
+ c->block_error.len = n_layers;
+ c->block_count.len = n_layers;
+
+ /*
+ * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically
+ * changed when the stats become available.
+ */
+ for (i = 0; i < n_layers; i++) {
+ c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+}
+
+static inline int sms_to_mode(u32 mode)
+{
+ switch (mode) {
+ case 2:
+ return TRANSMISSION_MODE_2K;
+ case 4:
+ return TRANSMISSION_MODE_4K;
+ case 8:
+ return TRANSMISSION_MODE_8K;
+ }
+ return TRANSMISSION_MODE_AUTO;
+}
+
+static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
+{
+ if (is_demod_locked)
+ return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+
+ if (is_rf_locked)
+ return FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+ return 0;
+}
+
+static inline u32 sms_to_bw(u32 value)
+{
+ return value * 1000000;
+}
+
+#define convert_from_table(value, table, defval) ({ \
+ u32 __ret; \
+ if (value < ARRAY_SIZE(table)) \
+ __ret = table[value]; \
+ else \
+ __ret = defval; \
+ __ret; \
+})
+
+#define sms_to_guard_interval(value) \
+ convert_from_table(value, sms_to_guard_interval_table, \
+ GUARD_INTERVAL_AUTO);
+
+#define sms_to_code_rate(value) \
+ convert_from_table(value, sms_to_code_rate_table, \
+ FEC_NONE);
+
+#define sms_to_hierarchy(value) \
+ convert_from_table(value, sms_to_hierarchy_table, \
+ FEC_NONE);
+
+#define sms_to_modulation(value) \
+ convert_from_table(value, sms_to_modulation_table, \
+ FEC_NONE);
+
+static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
+ struct sms_tx_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->code_rate_HP = sms_to_code_rate(p->code_rate);
+ c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
+ c->hierarchy = sms_to_hierarchy(p->hierarchy);
+ c->modulation = sms_to_modulation(p->constellation);
+}
+
+static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
+ struct RECEPTION_STATISTICS_PER_SLICES_S *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u64 tmp;
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+ c->modulation = sms_to_modulation(p->constellation);
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_power * 1000;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->snr * 1000;
+
+ /* PER/BER requires demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ /* TS PER */
+ client->last_per = c->block_error.stat[0].uvalue;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += p->ets_packets;
+ c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += p->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
+
+ /* Legacy PER/BER */
+ tmp = p->ets_packets * 65535;
+ do_div(tmp, p->ts_packets + p->ets_packets);
+ client->legacy_per = tmp;
+}
+
+static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
+ struct sms_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ if (client->prt_dvb_stats)
+ client->prt_dvb_stats(client->debug_data, p);
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+
+ /* Update DVB modulation parameters */
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->code_rate_HP = sms_to_code_rate(p->code_rate);
+ c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
+ c->hierarchy = sms_to_hierarchy(p->hierarchy);
+ c->modulation = sms_to_modulation(p->constellation);
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER requires demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ /* TS PER */
+ client->last_per = c->block_error.stat[0].uvalue;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += p->error_ts_packets;
+ c->block_count.stat[0].uvalue += p->total_ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += p->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
+
+ /* Legacy PER/BER */
+ client->legacy_ber = p->ber;
+};
+
+static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
+ struct sms_isdbt_stats *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct sms_isdbt_layer_stats *lr;
+ int i, n_layers;
+
+ if (client->prt_isdb_stats)
+ client->prt_isdb_stats(client->debug_data, p);
+
+ client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
+
+ /*
+ * Firmware 2.1 seems to report only lock status and
+ * signal strength. The signal strength indicator is at the
+ * wrong field.
+ */
+ if (p->statistics_type == 0) {
+ c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return;
+ }
+
+ /* Update ISDB-T transmission parameters */
+ c->frequency = p->frequency;
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
+ n_layers = p->num_of_layers;
+ if (n_layers < 1)
+ n_layers = 1;
+ if (n_layers > 3)
+ n_layers = 3;
+ c->isdbt_layer_enabled = 0;
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER and per-layer stats require demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ client->last_per = c->block_error.stat[0].uvalue;
+
+ /* Clears global counters, as the code below will sum it again */
+ c->block_error.stat[0].uvalue = 0;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+
+ for (i = 0; i < n_layers; i++) {
+ lr = &p->layer_info[i];
+
+ /* Update per-layer transmission parameters */
+ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
+ c->isdbt_layer_enabled |= 1 << i;
+ c->layer[i].segment_count = lr->number_of_segments;
+ } else {
+ continue;
+ }
+ c->layer[i].modulation = sms_to_modulation(lr->constellation);
+
+ /* TS PER */
+ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
+ c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
+
+ /* Update global PER counter */
+ c->block_error.stat[0].uvalue += lr->error_ts_packets;
+ c->block_count.stat[0].uvalue += lr->total_ts_packets;
+
+ /* BER */
+ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
+
+ /* Update global BER counter */
+ c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
+ }
+}
+
+static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
+ struct sms_isdbt_stats_ex *p)
+{
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct sms_isdbt_layer_stats *lr;
+ int i, n_layers;
+
+ if (client->prt_isdb_stats_ex)
+ client->prt_isdb_stats_ex(client->debug_data, p);
+
+ /* Update ISDB-T transmission parameters */
+ c->frequency = p->frequency;
+ client->fe_status = sms_to_status(p->is_demod_locked, 0);
+ c->bandwidth_hz = sms_to_bw(p->bandwidth);
+ c->transmission_mode = sms_to_mode(p->transmission_mode);
+ c->guard_interval = sms_to_guard_interval(p->guard_interval);
+ c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
+ n_layers = p->num_of_layers;
+ if (n_layers < 1)
+ n_layers = 1;
+ if (n_layers > 3)
+ n_layers = 3;
+ c->isdbt_layer_enabled = 0;
+
+ /* update reception data */
+ c->lna = p->is_external_lna_on ? 1 : 0;
+
+ /* Carrier to noise ratio, in DB */
+ c->cnr.stat[0].svalue = p->SNR * 1000;
+
+ /* signal Strength, in DBm */
+ c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
+
+ /* PER/BER and per-layer stats require demod lock */
+ if (!p->is_demod_locked)
+ return;
+
+ client->last_per = c->block_error.stat[0].uvalue;
+
+ /* Clears global counters, as the code below will sum it again */
+ c->block_error.stat[0].uvalue = 0;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+
+ c->post_bit_error.len = n_layers + 1;
+ c->post_bit_count.len = n_layers + 1;
+ c->block_error.len = n_layers + 1;
+ c->block_count.len = n_layers + 1;
+ for (i = 0; i < n_layers; i++) {
+ lr = &p->layer_info[i];
+
+ /* Update per-layer transmission parameters */
+ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
+ c->isdbt_layer_enabled |= 1 << i;
+ c->layer[i].segment_count = lr->number_of_segments;
+ } else {
+ continue;
+ }
+ c->layer[i].modulation = sms_to_modulation(lr->constellation);
+
+ /* TS PER */
+ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
+ c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
+
+ /* Update global PER counter */
+ c->block_error.stat[0].uvalue += lr->error_ts_packets;
+ c->block_count.stat[0].uvalue += lr->total_ts_packets;
+
+ /* ber */
+ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
+
+ /* Update global ber counter */
+ c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
+ c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
+ }
+}
+
+static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
+{
+ struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p)
+ + cb->offset);
+ void *p = phdr + 1;
+ struct dvb_frontend *fe = &client->frontend;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ bool is_status_update = false;
+
+ switch (phdr->msg_type) {
+ case MSG_SMS_DVBT_BDA_DATA:
+ /*
+ * Only feed data to dvb demux if are there any feed listening
+ * to it and if the device has tuned
+ */
+ if (client->feed_users && client->has_tuned)
+ dvb_dmx_swfilter(&client->demux, p,
+ cb->size - sizeof(struct sms_msg_hdr));
+ break;
+
+ case MSG_SMS_RF_TUNE_RES:
+ case MSG_SMS_ISDBT_TUNE_RES:
+ complete(&client->tune_done);
+ break;
+
+ case MSG_SMS_SIGNAL_DETECTED_IND:
+ client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_NO_SIGNAL_IND:
+ client->fe_status = 0;
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_TRANSMISSION_IND:
+ smsdvb_update_tx_params(client, p);
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_HO_PER_SLICES_IND:
+ smsdvb_update_per_slices(client, p);
+
+ is_status_update = true;
+ break;
+
+ case MSG_SMS_GET_STATISTICS_RES:
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ smsdvb_update_isdbt_stats(client, p);
+ break;
+ default:
+ /* Skip sms_msg_statistics_info:request_result field */
+ smsdvb_update_dvb_stats(client, p + sizeof(u32));
+ }
+
+ is_status_update = true;
+ break;
+
+ /* Only for ISDB-T */
+ case MSG_SMS_GET_STATISTICS_EX_RES:
+ /* Skip sms_msg_statistics_info:request_result field? */
+ smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
+ is_status_update = true;
+ break;
+ default:
+ sms_info("message not handled");
+ }
+ smscore_putbuffer(client->coredev, cb);
+
+ if (is_status_update) {
+ if (client->fe_status & FE_HAS_LOCK) {
+ sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+ if (client->last_per == c->block_error.stat[0].uvalue)
+ sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+ else
+ sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
+ client->has_tuned = true;
+ } else {
+ smsdvb_stats_not_ready(fe);
+ client->has_tuned = false;
+ sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+ }
+ complete(&client->stats_done);
+ }
+
+ return 0;
+}
+
+static void smsdvb_unregister_client(struct smsdvb_client_t *client)
+{
+ /* must be called under clientslock */
+
+ list_del(&client->entry);
+
+ smsdvb_debugfs_release(client);
+ smscore_unregister_client(client->smsclient);
+ dvb_unregister_frontend(&client->frontend);
+ dvb_dmxdev_release(&client->dmxdev);
+ dvb_dmx_release(&client->demux);
+ dvb_unregister_adapter(&client->adapter);
+ kfree(client);
+}
+
+static void smsdvb_onremove(void *context)
+{
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ smsdvb_unregister_client((struct smsdvb_client_t *) context);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+static int smsdvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct sms_msg_data pid_msg;
+
+ sms_debug("add pid %d(%x)",
+ feed->pid, feed->pid);
+
+ client->feed_users++;
+
+ pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ pid_msg.x_msg_header.msg_flags = 0;
+ pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;
+ pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
+ pid_msg.msg_data[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &pid_msg, sizeof(pid_msg));
+}
+
+static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct smsdvb_client_t *client =
+ container_of(feed->demux, struct smsdvb_client_t, demux);
+ struct sms_msg_data pid_msg;
+
+ sms_debug("remove pid %d(%x)",
+ feed->pid, feed->pid);
+
+ client->feed_users--;
+
+ pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
+ pid_msg.x_msg_header.msg_flags = 0;
+ pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;
+ pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
+ pid_msg.msg_data[0] = feed->pid;
+
+ return smsclient_sendrequest(client->smsclient,
+ &pid_msg, sizeof(pid_msg));
+}
+
+static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
+ void *buffer, size_t size,
+ struct completion *completion)
+{
+ int rc;
+
+ rc = smsclient_sendrequest(client->smsclient, buffer, size);
+ if (rc < 0)
+ return rc;
+
+ return wait_for_completion_timeout(completion,
+ msecs_to_jiffies(2000)) ?
+ 0 : -ETIME;
+}
+
+static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
+{
+ int rc;
+ struct sms_msg_hdr msg;
+
+ /* Don't request stats too fast */
+ if (client->get_stats_jiffies &&
+ (!time_after(jiffies, client->get_stats_jiffies)))
+ return 0;
+ client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);
+
+ msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg_dst_id = HIF_TASK;
+ msg.msg_flags = 0;
+ msg.msg_length = sizeof(msg);
+
+ switch (smscore_get_device_mode(client->coredev)) {
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ /*
+ * Check for firmware version, to avoid breaking for old cards
+ */
+ if (client->coredev->fw_version >= 0x800)
+ msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ;
+ else
+ msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
+ break;
+ default:
+ msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
+ }
+
+ rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->stats_done);
+
+ return rc;
+}
+
+static inline int led_feedback(struct smsdvb_client_t *client)
+{
+ if (!(client->fe_status & FE_HAS_LOCK))
+ return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+
+ return sms_board_led_feedback(client->coredev,
+ (client->legacy_ber == 0) ?
+ SMS_LED_HI : SMS_LED_LO);
+}
+
+static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ int rc;
+ struct smsdvb_client_t *client;
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *stat = client->fe_status;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ int rc;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *ber = client->legacy_ber;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ s32 power = (s32) c->strength.stat[0].uvalue;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ if (power < -95)
+ *strength = 0;
+ else if (power > -29)
+ *strength = 65535;
+ else
+ *strength = (power + 95) * 65535 / 66;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ /* Preferred scale for SNR with legacy API: 0.1 dB */
+ *snr = ((u32)c->cnr.stat[0].svalue) / 100;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ int rc;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client;
+
+ client = container_of(fe, struct smsdvb_client_t, frontend);
+
+ rc = smsdvb_send_statistics_request(client);
+
+ *ucblocks = c->block_error.stat[0].uvalue;
+
+ led_feedback(client);
+
+ return rc;
+}
+
+static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ sms_debug("");
+
+ tune->min_delay_ms = 400;
+ tune->step_size = 250000;
+ tune->max_drift = 0;
+ return 0;
+}
+
+static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ struct {
+ struct sms_msg_hdr msg;
+ u32 Data[3];
+ } msg;
+
+ int ret;
+
+ client->fe_status = 0;
+ client->event_fe_state = -1;
+ client->event_unc_state = -1;
+ fe->dtv_property_cache.delivery_system = SYS_DVBT;
+
+ msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg.msg_dst_id = HIF_TASK;
+ msg.msg.msg_flags = 0;
+ msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ;
+ msg.msg.msg_length = sizeof(msg);
+ msg.Data[0] = c->frequency;
+ msg.Data[2] = 12000000;
+
+ sms_info("%s: freq %d band %d", __func__, c->frequency,
+ c->bandwidth_hz);
+
+ switch (c->bandwidth_hz / 1000000) {
+ case 8:
+ msg.Data[1] = BW_8_MHZ;
+ break;
+ case 7:
+ msg.Data[1] = BW_7_MHZ;
+ break;
+ case 6:
+ msg.Data[1] = BW_6_MHZ;
+ break;
+ case 0:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+ /* Disable LNA, if any. An error is returned if no LNA is present */
+ ret = sms_board_lna_control(client->coredev, 0);
+ if (ret == 0) {
+ fe_status_t status;
+
+ /* tune with LNA off at first */
+ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+
+ smsdvb_read_status(fe, &status);
+
+ if (status & FE_HAS_LOCK)
+ return ret;
+
+ /* previous tune didn't lock - enable LNA and tune again */
+ sms_board_lna_control(client->coredev, 1);
+ }
+
+ return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+}
+
+static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ int board_id = smscore_get_board_id(client->coredev);
+ struct sms_board *board = sms_get_board(board_id);
+ enum sms_device_type_st type = board->type;
+ int ret;
+
+ struct {
+ struct sms_msg_hdr msg;
+ u32 Data[4];
+ } msg;
+
+ fe->dtv_property_cache.delivery_system = SYS_ISDBT;
+
+ msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
+ msg.msg.msg_dst_id = HIF_TASK;
+ msg.msg.msg_flags = 0;
+ msg.msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ;
+ msg.msg.msg_length = sizeof(msg);
+
+ if (c->isdbt_sb_segment_idx == -1)
+ c->isdbt_sb_segment_idx = 0;
+
+ if (!c->isdbt_layer_enabled)
+ c->isdbt_layer_enabled = 7;
+
+ msg.Data[0] = c->frequency;
+ msg.Data[1] = BW_ISDBT_1SEG;
+ msg.Data[2] = 12000000;
+ msg.Data[3] = c->isdbt_sb_segment_idx;
+
+ if (c->isdbt_partial_reception) {
+ if ((type == SMS_PELE || type == SMS_RIO) &&
+ c->isdbt_sb_segment_count > 3)
+ msg.Data[1] = BW_ISDBT_13SEG;
+ else if (c->isdbt_sb_segment_count > 1)
+ msg.Data[1] = BW_ISDBT_3SEG;
+ } else if (type == SMS_PELE || type == SMS_RIO)
+ msg.Data[1] = BW_ISDBT_13SEG;
+
+ c->bandwidth_hz = 6000000;
+
+ sms_info("%s: freq %d segwidth %d segindex %d", __func__,
+ c->frequency, c->isdbt_sb_segment_count,
+ c->isdbt_sb_segment_idx);
+
+ /* Disable LNA, if any. An error is returned if no LNA is present */
+ ret = sms_board_lna_control(client->coredev, 0);
+ if (ret == 0) {
+ fe_status_t status;
+
+ /* tune with LNA off at first */
+ ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+
+ smsdvb_read_status(fe, &status);
+
+ if (status & FE_HAS_LOCK)
+ return ret;
+
+ /* previous tune didn't lock - enable LNA and tune again */
+ sms_board_lna_control(client->coredev, 1);
+ }
+ return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
+ &client->tune_done);
+}
+
+static int smsdvb_set_frontend(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+ struct smscore_device_t *coredev = client->coredev;
+
+ smsdvb_stats_not_ready(fe);
+ c->strength.stat[0].uvalue = 0;
+ c->cnr.stat[0].uvalue = 0;
+
+ client->has_tuned = false;
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ return smsdvb_dvbt_set_frontend(fe);
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ return smsdvb_isdbt_set_frontend(fe);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Nothing to do here, as stats are automatically updated */
+static int smsdvb_get_frontend(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int smsdvb_init(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_power(client->coredev, 1);
+
+ sms_board_dvb3_event(client, DVB3_EVENT_INIT);
+ return 0;
+}
+
+static int smsdvb_sleep(struct dvb_frontend *fe)
+{
+ struct smsdvb_client_t *client =
+ container_of(fe, struct smsdvb_client_t, frontend);
+
+ sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+ sms_board_power(client->coredev, 0);
+
+ sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
+
+ return 0;
+}
+
+static void smsdvb_release(struct dvb_frontend *fe)
+{
+ /* do nothing */
+}
+
+static struct dvb_frontend_ops smsdvb_fe_ops = {
+ .info = {
+ .name = "Siano Mobile Digital MDTV Receiver",
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = smsdvb_release,
+
+ .set_frontend = smsdvb_set_frontend,
+ .get_frontend = smsdvb_get_frontend,
+ .get_tune_settings = smsdvb_get_tune_settings,
+
+ .read_status = smsdvb_read_status,
+ .read_ber = smsdvb_read_ber,
+ .read_signal_strength = smsdvb_read_signal_strength,
+ .read_snr = smsdvb_read_snr,
+ .read_ucblocks = smsdvb_read_ucblocks,
+
+ .init = smsdvb_init,
+ .sleep = smsdvb_sleep,
+};
+
+static int smsdvb_hotplug(struct smscore_device_t *coredev,
+ struct device *device, int arrival)
+{
+ struct smsclient_params_t params;
+ struct smsdvb_client_t *client;
+ int rc;
+
+ /* device removal handled by onremove callback */
+ if (!arrival)
+ return 0;
+ client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
+ if (!client) {
+ sms_err("kmalloc() failed");
+ return -ENOMEM;
+ }
+
+ /* register dvb adapter */
+ rc = dvb_register_adapter(&client->adapter,
+ sms_get_board(
+ smscore_get_board_id(coredev))->name,
+ THIS_MODULE, device, adapter_nr);
+ if (rc < 0) {
+ sms_err("dvb_register_adapter() failed %d", rc);
+ goto adapter_error;
+ }
+
+ /* init dvb demux */
+ client->demux.dmx.capabilities = DMX_TS_FILTERING;
+ client->demux.filternum = 32; /* todo: nova ??? */
+ client->demux.feednum = 32;
+ client->demux.start_feed = smsdvb_start_feed;
+ client->demux.stop_feed = smsdvb_stop_feed;
+
+ rc = dvb_dmx_init(&client->demux);
+ if (rc < 0) {
+ sms_err("dvb_dmx_init failed %d", rc);
+ goto dvbdmx_error;
+ }
+
+ /* init dmxdev */
+ client->dmxdev.filternum = 32;
+ client->dmxdev.demux = &client->demux.dmx;
+ client->dmxdev.capabilities = 0;
+
+ rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
+ if (rc < 0) {
+ sms_err("dvb_dmxdev_init failed %d", rc);
+ goto dmxdev_error;
+ }
+
+ /* init and register frontend */
+ memcpy(&client->frontend.ops, &smsdvb_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ switch (smscore_get_device_mode(coredev)) {
+ case DEVICE_MODE_DVBT:
+ case DEVICE_MODE_DVBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_DVBT;
+ break;
+ case DEVICE_MODE_ISDBT:
+ case DEVICE_MODE_ISDBT_BDA:
+ client->frontend.ops.delsys[0] = SYS_ISDBT;
+ break;
+ }
+
+ rc = dvb_register_frontend(&client->adapter, &client->frontend);
+ if (rc < 0) {
+ sms_err("frontend registration failed %d", rc);
+ goto frontend_error;
+ }
+
+ params.initial_id = 1;
+ params.data_type = MSG_SMS_DVBT_BDA_DATA;
+ params.onresponse_handler = smsdvb_onresponse;
+ params.onremove_handler = smsdvb_onremove;
+ params.context = client;
+
+ rc = smscore_register_client(coredev, &params, &client->smsclient);
+ if (rc < 0) {
+ sms_err("smscore_register_client() failed %d", rc);
+ goto client_error;
+ }
+
+ client->coredev = coredev;
+
+ init_completion(&client->tune_done);
+ init_completion(&client->stats_done);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ list_add(&client->entry, &g_smsdvb_clients);
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+
+ client->event_fe_state = -1;
+ client->event_unc_state = -1;
+ sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
+
+ sms_info("success");
+ sms_board_setup(coredev);
+
+ if (smsdvb_debugfs_create(client) < 0)
+ sms_info("failed to create debugfs node");
+
+ return 0;
+
+client_error:
+ dvb_unregister_frontend(&client->frontend);
+
+frontend_error:
+ dvb_dmxdev_release(&client->dmxdev);
+
+dmxdev_error:
+ dvb_dmx_release(&client->demux);
+
+dvbdmx_error:
+ dvb_unregister_adapter(&client->adapter);
+
+adapter_error:
+ kfree(client);
+ return rc;
+}
+
+static int __init smsdvb_module_init(void)
+{
+ int rc;
+
+ INIT_LIST_HEAD(&g_smsdvb_clients);
+ kmutex_init(&g_smsdvb_clientslock);
+
+ smsdvb_debugfs_register();
+
+ rc = smscore_register_hotplug(smsdvb_hotplug);
+
+ sms_debug("");
+
+ return rc;
+}
+
+static void __exit smsdvb_module_exit(void)
+{
+ smscore_unregister_hotplug(smsdvb_hotplug);
+
+ kmutex_lock(&g_smsdvb_clientslock);
+
+ while (!list_empty(&g_smsdvb_clients))
+ smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
+
+ smsdvb_debugfs_unregister();
+
+ kmutex_unlock(&g_smsdvb_clientslock);
+}
+
+module_init(smsdvb_module_init);
+module_exit(smsdvb_module_exit);
+
+MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c
deleted file mode 100644
index aa77e54a8fae..000000000000
--- a/drivers/media/common/siano/smsdvb.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/****************************************************************
-
-Siano Mobile Silicon, Inc.
-MDTV receiver kernel modules.
-Copyright (C) 2006-2008, Uri Shkolnik
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 2 of the License, or
-(at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************/
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
-
-#include "smscoreapi.h"
-#include "smsendian.h"
-#include "sms-cards.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-struct smsdvb_client_t {
- struct list_head entry;
-
- struct smscore_device_t *coredev;
- struct smscore_client_t *smsclient;
-
- struct dvb_adapter adapter;
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dvb_frontend frontend;
-
- fe_status_t fe_status;
-
- struct completion tune_done;
-
- struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
- int event_fe_state;
- int event_unc_state;
-};
-
-static struct list_head g_smsdvb_clients;
-static struct mutex g_smsdvb_clientslock;
-
-static int sms_dbg;
-module_param_named(debug, sms_dbg, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
-
-/* Events that may come from DVB v3 adapter */
-static void sms_board_dvb3_event(struct smsdvb_client_t *client,
- enum SMS_DVB3_EVENTS event) {
-
- struct smscore_device_t *coredev = client->coredev;
- switch (event) {
- case DVB3_EVENT_INIT:
- sms_debug("DVB3_EVENT_INIT");
- sms_board_event(coredev, BOARD_EVENT_BIND);
- break;
- case DVB3_EVENT_SLEEP:
- sms_debug("DVB3_EVENT_SLEEP");
- sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
- break;
- case DVB3_EVENT_HOTPLUG:
- sms_debug("DVB3_EVENT_HOTPLUG");
- sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
- break;
- case DVB3_EVENT_FE_LOCK:
- if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
- client->event_fe_state = DVB3_EVENT_FE_LOCK;
- sms_debug("DVB3_EVENT_FE_LOCK");
- sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
- }
- break;
- case DVB3_EVENT_FE_UNLOCK:
- if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
- client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
- sms_debug("DVB3_EVENT_FE_UNLOCK");
- sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
- }
- break;
- case DVB3_EVENT_UNC_OK:
- if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
- client->event_unc_state = DVB3_EVENT_UNC_OK;
- sms_debug("DVB3_EVENT_UNC_OK");
- sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
- }
- break;
- case DVB3_EVENT_UNC_ERR:
- if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
- client->event_unc_state = DVB3_EVENT_UNC_ERR;
- sms_debug("DVB3_EVENT_UNC_ERR");
- sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
- }
- break;
-
- default:
- sms_err("Unknown dvb3 api event");
- break;
- }
-}
-
-
-static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
- struct SMSHOSTLIB_STATISTICS_ST *p)
-{
- if (sms_dbg & 2) {
- printk(KERN_DEBUG "Reserved = %d", p->Reserved);
- printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
- printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
- printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
- printk(KERN_DEBUG "SNR = %d", p->SNR);
- printk(KERN_DEBUG "BER = %d", p->BER);
- printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
- printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
- printk(KERN_DEBUG "MFER = %d", p->MFER);
- printk(KERN_DEBUG "RSSI = %d", p->RSSI);
- printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
- printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
- printk(KERN_DEBUG "Frequency = %d", p->Frequency);
- printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
- printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
- printk(KERN_DEBUG "ModemState = %d", p->ModemState);
- printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
- printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
- printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
- printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
- printk(KERN_DEBUG "Constellation = %d", p->Constellation);
- printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
- printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
- printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
- printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
- printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
- printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
- printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
- printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
- printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
- printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
- printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
- printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
- printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
- printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
- printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
- printk(KERN_DEBUG "PreBER = %d", p->PreBER);
- printk(KERN_DEBUG "CellId = %d", p->CellId);
- printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
- printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
- printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
- }
-
- pReceptionData->IsDemodLocked = p->IsDemodLocked;
-
- pReceptionData->SNR = p->SNR;
- pReceptionData->BER = p->BER;
- pReceptionData->BERErrorCount = p->BERErrorCount;
- pReceptionData->InBandPwr = p->InBandPwr;
- pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
-};
-
-
-static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
- struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
-{
- int i;
-
- if (sms_dbg & 2) {
- printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
- printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
- printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
- printk(KERN_DEBUG "SNR = %d", p->SNR);
- printk(KERN_DEBUG "RSSI = %d", p->RSSI);
- printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
- printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
- printk(KERN_DEBUG "Frequency = %d", p->Frequency);
- printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
- printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
- printk(KERN_DEBUG "ModemState = %d", p->ModemState);
- printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
- printk(KERN_DEBUG "SystemType = %d", p->SystemType);
- printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
- printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
- printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
-
- for (i = 0; i < 3; i++) {
- printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
- printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
- printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
- printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
- printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
- printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
- printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
- printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
- printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
- printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
- printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
- printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
- }
- }
-
- pReceptionData->IsDemodLocked = p->IsDemodLocked;
-
- pReceptionData->SNR = p->SNR;
- pReceptionData->InBandPwr = p->InBandPwr;
-
- pReceptionData->ErrorTSPackets = 0;
- pReceptionData->BER = 0;
- pReceptionData->BERErrorCount = 0;
- for (i = 0; i < 3; i++) {
- pReceptionData->BER += p->LayerInfo[i].BER;
- pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
- pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
- }
-}
-
-static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
-{
- struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
- struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
- + cb->offset);
- u32 *pMsgData = (u32 *) phdr + 1;
- /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
- bool is_status_update = false;
-
- smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
-
- switch (phdr->msgType) {
- case MSG_SMS_DVBT_BDA_DATA:
- dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
- cb->size - sizeof(struct SmsMsgHdr_ST));
- break;
-
- case MSG_SMS_RF_TUNE_RES:
- case MSG_SMS_ISDBT_TUNE_RES:
- complete(&client->tune_done);
- break;
-
- case MSG_SMS_SIGNAL_DETECTED_IND:
- sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
- client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
- is_status_update = true;
- break;
-
- case MSG_SMS_NO_SIGNAL_IND:
- sms_info("MSG_SMS_NO_SIGNAL_IND");
- client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
- is_status_update = true;
- break;
-
- case MSG_SMS_TRANSMISSION_IND: {
- sms_info("MSG_SMS_TRANSMISSION_IND");
-
- pMsgData++;
- memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
- sizeof(struct TRANSMISSION_STATISTICS_S));
-
- /* Mo need to correct guard interval
- * (as opposed to old statistics message).
- */
- CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
- CORRECT_STAT_TRANSMISSON_MODE(
- client->sms_stat_dvb.TransmissionData);
- is_status_update = true;
- break;
- }
- case MSG_SMS_HO_PER_SLICES_IND: {
- struct RECEPTION_STATISTICS_S *pReceptionData =
- &client->sms_stat_dvb.ReceptionData;
- struct SRVM_SIGNAL_STATUS_S SignalStatusData;
-
- /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
- pMsgData++;
- SignalStatusData.result = pMsgData[0];
- SignalStatusData.snr = pMsgData[1];
- SignalStatusData.inBandPower = (s32) pMsgData[2];
- SignalStatusData.tsPackets = pMsgData[3];
- SignalStatusData.etsPackets = pMsgData[4];
- SignalStatusData.constellation = pMsgData[5];
- SignalStatusData.hpCode = pMsgData[6];
- SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
- SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
- SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
- SignalStatusData.reason = pMsgData[10];
- SignalStatusData.requestId = pMsgData[11];
- pReceptionData->IsRfLocked = pMsgData[16];
- pReceptionData->IsDemodLocked = pMsgData[17];
- pReceptionData->ModemState = pMsgData[12];
- pReceptionData->SNR = pMsgData[1];
- pReceptionData->BER = pMsgData[13];
- pReceptionData->RSSI = pMsgData[14];
- CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
-
- pReceptionData->InBandPwr = (s32) pMsgData[2];
- pReceptionData->CarrierOffset = (s32) pMsgData[15];
- pReceptionData->TotalTSPackets = pMsgData[3];
- pReceptionData->ErrorTSPackets = pMsgData[4];
-
- /* TS PER */
- if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
- > 0) {
- pReceptionData->TS_PER = (SignalStatusData.etsPackets
- * 100) / (SignalStatusData.tsPackets
- + SignalStatusData.etsPackets);
- } else {
- pReceptionData->TS_PER = 0;
- }
-
- pReceptionData->BERBitCount = pMsgData[18];
- pReceptionData->BERErrorCount = pMsgData[19];
-
- pReceptionData->MRC_SNR = pMsgData[20];
- pReceptionData->MRC_InBandPwr = pMsgData[21];
- pReceptionData->MRC_RSSI = pMsgData[22];
-
- is_status_update = true;
- break;
- }
- case MSG_SMS_GET_STATISTICS_RES: {
- union {
- struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
- struct SmsMsgStatisticsInfo_ST dvb;
- } *p = (void *) (phdr + 1);
- struct RECEPTION_STATISTICS_S *pReceptionData =
- &client->sms_stat_dvb.ReceptionData;
-
- sms_info("MSG_SMS_GET_STATISTICS_RES");
-
- is_status_update = true;
-
- switch (smscore_get_device_mode(client->coredev)) {
- case DEVICE_MODE_ISDBT:
- case DEVICE_MODE_ISDBT_BDA:
- smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
- break;
- default:
- smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
- }
- if (!pReceptionData->IsDemodLocked) {
- pReceptionData->SNR = 0;
- pReceptionData->BER = 0;
- pReceptionData->BERErrorCount = 0;
- pReceptionData->InBandPwr = 0;
- pReceptionData->ErrorTSPackets = 0;
- }
-
- complete(&client->tune_done);
- break;
- }
- default:
- sms_info("Unhandled message %d", phdr->msgType);
-
- }
- smscore_putbuffer(client->coredev, cb);
-
- if (is_status_update) {
- if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
- client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
- | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
- if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
- == 0)
- sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
- else
- sms_board_dvb3_event(client,
- DVB3_EVENT_UNC_ERR);
-
- } else {
- if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
- client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
- else
- client->fe_status = 0;
- sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
- }
- }
-
- return 0;
-}
-
-static void smsdvb_unregister_client(struct smsdvb_client_t *client)
-{
- /* must be called under clientslock */
-
- list_del(&client->entry);
-
- smscore_unregister_client(client->smsclient);
- dvb_unregister_frontend(&client->frontend);
- dvb_dmxdev_release(&client->dmxdev);
- dvb_dmx_release(&client->demux);
- dvb_unregister_adapter(&client->adapter);
- kfree(client);
-}
-
-static void smsdvb_onremove(void *context)
-{
- kmutex_lock(&g_smsdvb_clientslock);
-
- smsdvb_unregister_client((struct smsdvb_client_t *) context);
-
- kmutex_unlock(&g_smsdvb_clientslock);
-}
-
-static int smsdvb_start_feed(struct dvb_demux_feed *feed)
-{
- struct smsdvb_client_t *client =
- container_of(feed->demux, struct smsdvb_client_t, demux);
- struct SmsMsgData_ST PidMsg;
-
- sms_debug("add pid %d(%x)",
- feed->pid, feed->pid);
-
- PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- PidMsg.xMsgHeader.msgDstId = HIF_TASK;
- PidMsg.xMsgHeader.msgFlags = 0;
- PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
- PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
- PidMsg.msgData[0] = feed->pid;
-
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
- return smsclient_sendrequest(client->smsclient,
- &PidMsg, sizeof(PidMsg));
-}
-
-static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
-{
- struct smsdvb_client_t *client =
- container_of(feed->demux, struct smsdvb_client_t, demux);
- struct SmsMsgData_ST PidMsg;
-
- sms_debug("remove pid %d(%x)",
- feed->pid, feed->pid);
-
- PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- PidMsg.xMsgHeader.msgDstId = HIF_TASK;
- PidMsg.xMsgHeader.msgFlags = 0;
- PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
- PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
- PidMsg.msgData[0] = feed->pid;
-
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
- return smsclient_sendrequest(client->smsclient,
- &PidMsg, sizeof(PidMsg));
-}
-
-static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
- void *buffer, size_t size,
- struct completion *completion)
-{
- int rc;
-
- smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
- rc = smsclient_sendrequest(client->smsclient, buffer, size);
- if (rc < 0)
- return rc;
-
- return wait_for_completion_timeout(completion,
- msecs_to_jiffies(2000)) ?
- 0 : -ETIME;
-}
-
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
- int rc;
- struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
- DVBT_BDA_CONTROL_MSG_ID,
- HIF_TASK,
- sizeof(struct SmsMsgHdr_ST), 0 };
-
- rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
- &client->tune_done);
-
- return rc;
-}
-
-static inline int led_feedback(struct smsdvb_client_t *client)
-{
- if (client->fe_status & FE_HAS_LOCK)
- return sms_board_led_feedback(client->coredev,
- (client->sms_stat_dvb.ReceptionData.BER
- == 0) ? SMS_LED_HI : SMS_LED_LO);
- else
- return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-}
-
-static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-{
- int rc;
- struct smsdvb_client_t *client;
- client = container_of(fe, struct smsdvb_client_t, frontend);
-
- rc = smsdvb_send_statistics_request(client);
-
- *stat = client->fe_status;
-
- led_feedback(client);
-
- return rc;
-}
-
-static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- int rc;
- struct smsdvb_client_t *client;
- client = container_of(fe, struct smsdvb_client_t, frontend);
-
- rc = smsdvb_send_statistics_request(client);
-
- *ber = client->sms_stat_dvb.ReceptionData.BER;
-
- led_feedback(client);
-
- return rc;
-}
-
-static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- int rc;
-
- struct smsdvb_client_t *client;
- client = container_of(fe, struct smsdvb_client_t, frontend);
-
- rc = smsdvb_send_statistics_request(client);
-
- if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
- *strength = 0;
- else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
- *strength = 100;
- else
- *strength =
- (client->sms_stat_dvb.ReceptionData.InBandPwr
- + 95) * 3 / 2;
-
- led_feedback(client);
-
- return rc;
-}
-
-static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- int rc;
- struct smsdvb_client_t *client;
- client = container_of(fe, struct smsdvb_client_t, frontend);
-
- rc = smsdvb_send_statistics_request(client);
-
- *snr = client->sms_stat_dvb.ReceptionData.SNR;
-
- led_feedback(client);
-
- return rc;
-}
-
-static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
-{
- int rc;
- struct smsdvb_client_t *client;
- client = container_of(fe, struct smsdvb_client_t, frontend);
-
- rc = smsdvb_send_statistics_request(client);
-
- *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
-
- led_feedback(client);
-
- return rc;
-}
-
-static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *tune)
-{
- sms_debug("");
-
- tune->min_delay_ms = 400;
- tune->step_size = 250000;
- tune->max_drift = 0;
- return 0;
-}
-
-static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
-
- struct {
- struct SmsMsgHdr_ST Msg;
- u32 Data[3];
- } Msg;
-
- int ret;
-
- client->fe_status = FE_HAS_SIGNAL;
- client->event_fe_state = -1;
- client->event_unc_state = -1;
- fe->dtv_property_cache.delivery_system = SYS_DVBT;
-
- Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- Msg.Msg.msgDstId = HIF_TASK;
- Msg.Msg.msgFlags = 0;
- Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
- Msg.Msg.msgLength = sizeof(Msg);
- Msg.Data[0] = c->frequency;
- Msg.Data[2] = 12000000;
-
- sms_info("%s: freq %d band %d", __func__, c->frequency,
- c->bandwidth_hz);
-
- switch (c->bandwidth_hz / 1000000) {
- case 8:
- Msg.Data[1] = BW_8_MHZ;
- break;
- case 7:
- Msg.Data[1] = BW_7_MHZ;
- break;
- case 6:
- Msg.Data[1] = BW_6_MHZ;
- break;
- case 0:
- return -EOPNOTSUPP;
- default:
- return -EINVAL;
- }
- /* Disable LNA, if any. An error is returned if no LNA is present */
- ret = sms_board_lna_control(client->coredev, 0);
- if (ret == 0) {
- fe_status_t status;
-
- /* tune with LNA off at first */
- ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
- &client->tune_done);
-
- smsdvb_read_status(fe, &status);
-
- if (status & FE_HAS_LOCK)
- return ret;
-
- /* previous tune didn't lock - enable LNA and tune again */
- sms_board_lna_control(client->coredev, 1);
- }
-
- return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
- &client->tune_done);
-}
-
-static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
-
- struct {
- struct SmsMsgHdr_ST Msg;
- u32 Data[4];
- } Msg;
-
- fe->dtv_property_cache.delivery_system = SYS_ISDBT;
-
- Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
- Msg.Msg.msgDstId = HIF_TASK;
- Msg.Msg.msgFlags = 0;
- Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
- Msg.Msg.msgLength = sizeof(Msg);
-
- if (c->isdbt_sb_segment_idx == -1)
- c->isdbt_sb_segment_idx = 0;
-
- switch (c->isdbt_sb_segment_count) {
- case 3:
- Msg.Data[1] = BW_ISDBT_3SEG;
- break;
- case 1:
- Msg.Data[1] = BW_ISDBT_1SEG;
- break;
- case 0: /* AUTO */
- switch (c->bandwidth_hz / 1000000) {
- case 8:
- case 7:
- c->isdbt_sb_segment_count = 3;
- Msg.Data[1] = BW_ISDBT_3SEG;
- break;
- case 6:
- c->isdbt_sb_segment_count = 1;
- Msg.Data[1] = BW_ISDBT_1SEG;
- break;
- default: /* Assumes 6 MHZ bw */
- c->isdbt_sb_segment_count = 1;
- c->bandwidth_hz = 6000;
- Msg.Data[1] = BW_ISDBT_1SEG;
- break;
- }
- break;
- default:
- sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
- return -EINVAL;
- }
-
- Msg.Data[0] = c->frequency;
- Msg.Data[2] = 12000000;
- Msg.Data[3] = c->isdbt_sb_segment_idx;
-
- sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
- c->frequency, c->isdbt_sb_segment_count,
- c->isdbt_sb_segment_idx);
-
- return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
- &client->tune_done);
-}
-
-static int smsdvb_set_frontend(struct dvb_frontend *fe)
-{
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
- struct smscore_device_t *coredev = client->coredev;
-
- switch (smscore_get_device_mode(coredev)) {
- case DEVICE_MODE_DVBT:
- case DEVICE_MODE_DVBT_BDA:
- return smsdvb_dvbt_set_frontend(fe);
- case DEVICE_MODE_ISDBT:
- case DEVICE_MODE_ISDBT_BDA:
- return smsdvb_isdbt_set_frontend(fe);
- default:
- return -EINVAL;
- }
-}
-
-static int smsdvb_get_frontend(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
- struct smscore_device_t *coredev = client->coredev;
- struct TRANSMISSION_STATISTICS_S *td =
- &client->sms_stat_dvb.TransmissionData;
-
- switch (smscore_get_device_mode(coredev)) {
- case DEVICE_MODE_DVBT:
- case DEVICE_MODE_DVBT_BDA:
- fep->frequency = td->Frequency;
-
- switch (td->Bandwidth) {
- case 6:
- fep->bandwidth_hz = 6000000;
- break;
- case 7:
- fep->bandwidth_hz = 7000000;
- break;
- case 8:
- fep->bandwidth_hz = 8000000;
- break;
- }
-
- switch (td->TransmissionMode) {
- case 2:
- fep->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case 8:
- fep->transmission_mode = TRANSMISSION_MODE_8K;
- }
-
- switch (td->GuardInterval) {
- case 0:
- fep->guard_interval = GUARD_INTERVAL_1_32;
- break;
- case 1:
- fep->guard_interval = GUARD_INTERVAL_1_16;
- break;
- case 2:
- fep->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case 3:
- fep->guard_interval = GUARD_INTERVAL_1_4;
- break;
- }
-
- switch (td->CodeRate) {
- case 0:
- fep->code_rate_HP = FEC_1_2;
- break;
- case 1:
- fep->code_rate_HP = FEC_2_3;
- break;
- case 2:
- fep->code_rate_HP = FEC_3_4;
- break;
- case 3:
- fep->code_rate_HP = FEC_5_6;
- break;
- case 4:
- fep->code_rate_HP = FEC_7_8;
- break;
- }
-
- switch (td->LPCodeRate) {
- case 0:
- fep->code_rate_LP = FEC_1_2;
- break;
- case 1:
- fep->code_rate_LP = FEC_2_3;
- break;
- case 2:
- fep->code_rate_LP = FEC_3_4;
- break;
- case 3:
- fep->code_rate_LP = FEC_5_6;
- break;
- case 4:
- fep->code_rate_LP = FEC_7_8;
- break;
- }
-
- switch (td->Constellation) {
- case 0:
- fep->modulation = QPSK;
- break;
- case 1:
- fep->modulation = QAM_16;
- break;
- case 2:
- fep->modulation = QAM_64;
- break;
- }
-
- switch (td->Hierarchy) {
- case 0:
- fep->hierarchy = HIERARCHY_NONE;
- break;
- case 1:
- fep->hierarchy = HIERARCHY_1;
- break;
- case 2:
- fep->hierarchy = HIERARCHY_2;
- break;
- case 3:
- fep->hierarchy = HIERARCHY_4;
- break;
- }
-
- fep->inversion = INVERSION_AUTO;
- break;
- case DEVICE_MODE_ISDBT:
- case DEVICE_MODE_ISDBT_BDA:
- fep->frequency = td->Frequency;
- fep->bandwidth_hz = 6000000;
- /* todo: retrive the other parameters */
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int smsdvb_init(struct dvb_frontend *fe)
-{
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
-
- sms_board_power(client->coredev, 1);
-
- sms_board_dvb3_event(client, DVB3_EVENT_INIT);
- return 0;
-}
-
-static int smsdvb_sleep(struct dvb_frontend *fe)
-{
- struct smsdvb_client_t *client =
- container_of(fe, struct smsdvb_client_t, frontend);
-
- sms_board_led_feedback(client->coredev, SMS_LED_OFF);
- sms_board_power(client->coredev, 0);
-
- sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
-
- return 0;
-}
-
-static void smsdvb_release(struct dvb_frontend *fe)
-{
- /* do nothing */
-}
-
-static struct dvb_frontend_ops smsdvb_fe_ops = {
- .info = {
- .name = "Siano Mobile Digital MDTV Receiver",
- .frequency_min = 44250000,
- .frequency_max = 867250000,
- .frequency_stepsize = 250000,
- .caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
- FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_RECOVER |
- FE_CAN_HIERARCHY_AUTO,
- },
-
- .release = smsdvb_release,
-
- .set_frontend = smsdvb_set_frontend,
- .get_frontend = smsdvb_get_frontend,
- .get_tune_settings = smsdvb_get_tune_settings,
-
- .read_status = smsdvb_read_status,
- .read_ber = smsdvb_read_ber,
- .read_signal_strength = smsdvb_read_signal_strength,
- .read_snr = smsdvb_read_snr,
- .read_ucblocks = smsdvb_read_ucblocks,
-
- .init = smsdvb_init,
- .sleep = smsdvb_sleep,
-};
-
-static int smsdvb_hotplug(struct smscore_device_t *coredev,
- struct device *device, int arrival)
-{
- struct smsclient_params_t params;
- struct smsdvb_client_t *client;
- int rc;
-
- /* device removal handled by onremove callback */
- if (!arrival)
- return 0;
- client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
- if (!client) {
- sms_err("kmalloc() failed");
- return -ENOMEM;
- }
-
- /* register dvb adapter */
- rc = dvb_register_adapter(&client->adapter,
- sms_get_board(
- smscore_get_board_id(coredev))->name,
- THIS_MODULE, device, adapter_nr);
- if (rc < 0) {
- sms_err("dvb_register_adapter() failed %d", rc);
- goto adapter_error;
- }
-
- /* init dvb demux */
- client->demux.dmx.capabilities = DMX_TS_FILTERING;
- client->demux.filternum = 32; /* todo: nova ??? */
- client->demux.feednum = 32;
- client->demux.start_feed = smsdvb_start_feed;
- client->demux.stop_feed = smsdvb_stop_feed;
-
- rc = dvb_dmx_init(&client->demux);
- if (rc < 0) {
- sms_err("dvb_dmx_init failed %d", rc);
- goto dvbdmx_error;
- }
-
- /* init dmxdev */
- client->dmxdev.filternum = 32;
- client->dmxdev.demux = &client->demux.dmx;
- client->dmxdev.capabilities = 0;
-
- rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
- if (rc < 0) {
- sms_err("dvb_dmxdev_init failed %d", rc);
- goto dmxdev_error;
- }
-
- /* init and register frontend */
- memcpy(&client->frontend.ops, &smsdvb_fe_ops,
- sizeof(struct dvb_frontend_ops));
-
- switch (smscore_get_device_mode(coredev)) {
- case DEVICE_MODE_DVBT:
- case DEVICE_MODE_DVBT_BDA:
- client->frontend.ops.delsys[0] = SYS_DVBT;
- break;
- case DEVICE_MODE_ISDBT:
- case DEVICE_MODE_ISDBT_BDA:
- client->frontend.ops.delsys[0] = SYS_ISDBT;
- break;
- }
-
- rc = dvb_register_frontend(&client->adapter, &client->frontend);
- if (rc < 0) {
- sms_err("frontend registration failed %d", rc);
- goto frontend_error;
- }
-
- params.initial_id = 1;
- params.data_type = MSG_SMS_DVBT_BDA_DATA;
- params.onresponse_handler = smsdvb_onresponse;
- params.onremove_handler = smsdvb_onremove;
- params.context = client;
-
- rc = smscore_register_client(coredev, &params, &client->smsclient);
- if (rc < 0) {
- sms_err("smscore_register_client() failed %d", rc);
- goto client_error;
- }
-
- client->coredev = coredev;
-
- init_completion(&client->tune_done);
-
- kmutex_lock(&g_smsdvb_clientslock);
-
- list_add(&client->entry, &g_smsdvb_clients);
-
- kmutex_unlock(&g_smsdvb_clientslock);
-
- client->event_fe_state = -1;
- client->event_unc_state = -1;
- sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
-
- sms_info("success");
- sms_board_setup(coredev);
-
- return 0;
-
-client_error:
- dvb_unregister_frontend(&client->frontend);
-
-frontend_error:
- dvb_dmxdev_release(&client->dmxdev);
-
-dmxdev_error:
- dvb_dmx_release(&client->demux);
-
-dvbdmx_error:
- dvb_unregister_adapter(&client->adapter);
-
-adapter_error:
- kfree(client);
- return rc;
-}
-
-static int __init smsdvb_module_init(void)
-{
- int rc;
-
- INIT_LIST_HEAD(&g_smsdvb_clients);
- kmutex_init(&g_smsdvb_clientslock);
-
- rc = smscore_register_hotplug(smsdvb_hotplug);
-
- sms_debug("");
-
- return rc;
-}
-
-static void __exit smsdvb_module_exit(void)
-{
- smscore_unregister_hotplug(smsdvb_hotplug);
-
- kmutex_lock(&g_smsdvb_clientslock);
-
- while (!list_empty(&g_smsdvb_clients))
- smsdvb_unregister_client(
- (struct smsdvb_client_t *) g_smsdvb_clients.next);
-
- kmutex_unlock(&g_smsdvb_clientslock);
-}
-
-module_init(smsdvb_module_init);
-module_exit(smsdvb_module_exit);
-
-MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
-MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h
new file mode 100644
index 000000000000..92c413ba0c79
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb.h
@@ -0,0 +1,130 @@
+/***********************************************************************
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ ***********************************************************************/
+
+struct smsdvb_debugfs;
+struct smsdvb_client_t;
+
+typedef void (*sms_prt_dvb_stats_t)(struct smsdvb_debugfs *debug_data,
+ struct sms_stats *p);
+
+typedef void (*sms_prt_isdb_stats_t)(struct smsdvb_debugfs *debug_data,
+ struct sms_isdbt_stats *p);
+
+typedef void (*sms_prt_isdb_stats_ex_t)
+ (struct smsdvb_debugfs *debug_data,
+ struct sms_isdbt_stats_ex *p);
+
+
+struct smsdvb_client_t {
+ struct list_head entry;
+
+ struct smscore_device_t *coredev;
+ struct smscore_client_t *smsclient;
+
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dvb_frontend frontend;
+
+ fe_status_t fe_status;
+
+ struct completion tune_done;
+ struct completion stats_done;
+
+ int last_per;
+
+ int legacy_ber, legacy_per;
+
+ int event_fe_state;
+ int event_unc_state;
+
+ unsigned long get_stats_jiffies;
+
+ int feed_users;
+ bool has_tuned;
+
+ /* stats debugfs data */
+ struct dentry *debugfs;
+
+ struct smsdvb_debugfs *debug_data;
+
+ sms_prt_dvb_stats_t prt_dvb_stats;
+ sms_prt_isdb_stats_t prt_isdb_stats;
+ sms_prt_isdb_stats_ex_t prt_isdb_stats_ex;
+};
+
+/*
+ * This struct is a mix of struct sms_rx_stats_ex and
+ * struct sms_srvm_signal_status.
+ * It was obtained by comparing the way it was filled by the original code
+ */
+struct RECEPTION_STATISTICS_PER_SLICES_S {
+ u32 result;
+ u32 snr;
+ s32 in_band_power;
+ u32 ts_packets;
+ u32 ets_packets;
+ u32 constellation;
+ u32 hp_code;
+ u32 tps_srv_ind_lp;
+ u32 tps_srv_ind_hp;
+ u32 cell_id;
+ u32 reason;
+ u32 request_id;
+ u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+
+ u32 ber; /* Post Viterbi BER [1E-5] */
+ s32 RSSI; /* dBm */
+ s32 carrier_offset; /* Carrier Offset in bin/1024 */
+
+ u32 is_rf_locked; /* 0 - not locked, 1 - locked */
+ u32 is_demod_locked; /* 0 - not locked, 1 - locked */
+
+ u32 ber_bit_count; /* Total number of SYNC bits. */
+ u32 ber_error_count; /* Number of erronous SYNC bits. */
+
+ s32 MRC_SNR; /* dB */
+ s32 mrc_in_band_pwr; /* In band power in dBM */
+ s32 MRC_RSSI; /* dBm */
+};
+
+/* From smsdvb-debugfs.c */
+#ifdef CONFIG_SMS_SIANO_DEBUGFS
+
+int smsdvb_debugfs_create(struct smsdvb_client_t *client);
+void smsdvb_debugfs_release(struct smsdvb_client_t *client);
+int smsdvb_debugfs_register(void);
+void smsdvb_debugfs_unregister(void);
+
+#else
+
+static inline int smsdvb_debugfs_create(struct smsdvb_client_t *client)
+{
+ return 0;
+}
+
+static inline void smsdvb_debugfs_release(struct smsdvb_client_t *client) {}
+
+static inline int smsdvb_debugfs_register(void)
+{
+ return 0;
+};
+
+static inline void smsdvb_debugfs_unregister(void) {};
+
+#endif
+
diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
index e2657c2f0109..bfe831c10b1c 100644
--- a/drivers/media/common/siano/smsendian.c
+++ b/drivers/media/common/siano/smsendian.c
@@ -28,23 +28,23 @@
void smsendian_handle_tx_message(void *buffer)
{
#ifdef __BIG_ENDIAN
- struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+ struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
int i;
- int msgWords;
+ int msg_words;
- switch (msg->xMsgHeader.msgType) {
+ switch (msg->x_msg_header.msg_type) {
case MSG_SMS_DATA_DOWNLOAD_REQ:
{
- msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+ msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]);
break;
}
default:
- msgWords = (msg->xMsgHeader.msgLength -
- sizeof(struct SmsMsgHdr_ST))/4;
+ msg_words = (msg->x_msg_header.msg_length -
+ sizeof(struct sms_msg_hdr))/4;
- for (i = 0; i < msgWords; i++)
- msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+ for (i = 0; i < msg_words; i++)
+ msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
break;
}
@@ -55,16 +55,16 @@ EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
void smsendian_handle_rx_message(void *buffer)
{
#ifdef __BIG_ENDIAN
- struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+ struct sms_msg_data *msg = (struct sms_msg_data *)buffer;
int i;
- int msgWords;
+ int msg_words;
- switch (msg->xMsgHeader.msgType) {
+ switch (msg->x_msg_header.msg_type) {
case MSG_SMS_GET_VERSION_EX_RES:
{
- struct SmsVersionRes_ST *ver =
- (struct SmsVersionRes_ST *) msg;
- ver->ChipModel = le16_to_cpu(ver->ChipModel);
+ struct sms_version_res *ver =
+ (struct sms_version_res *) msg;
+ ver->chip_model = le16_to_cpu(ver->chip_model);
break;
}
@@ -77,11 +77,11 @@ void smsendian_handle_rx_message(void *buffer)
default:
{
- msgWords = (msg->xMsgHeader.msgLength -
- sizeof(struct SmsMsgHdr_ST))/4;
+ msg_words = (msg->x_msg_header.msg_length -
+ sizeof(struct sms_msg_hdr))/4;
- for (i = 0; i < msgWords; i++)
- msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+ for (i = 0; i < msg_words; i++)
+ msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]);
break;
}
@@ -93,11 +93,11 @@ EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
void smsendian_handle_message_header(void *msg)
{
#ifdef __BIG_ENDIAN
- struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg;
- phdr->msgType = le16_to_cpu(phdr->msgType);
- phdr->msgLength = le16_to_cpu(phdr->msgLength);
- phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+ phdr->msg_type = le16_to_cpu(phdr->msg_type);
+ phdr->msg_length = le16_to_cpu(phdr->msg_length);
+ phdr->msg_flags = le16_to_cpu(phdr->msg_flags);
#endif /* __BIG_ENDIAN */
}
EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
index 69b59b9eee28..fc8b7925c532 100644
--- a/drivers/media/common/siano/smsir.h
+++ b/drivers/media/common/siano/smsir.h
@@ -40,7 +40,6 @@ struct ir_t {
char phys[32];
char *rc_codes;
- u64 protocol;
u32 timeout;
u32 controller;
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
index eb91fd808c16..833191bcd810 100644
--- a/drivers/media/dvb-core/demux.h
+++ b/drivers/media/dvb-core/demux.h
@@ -83,45 +83,6 @@ enum dmx_success {
#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to
the demux device, not to the dvr device */
-/* PES type for filters which write to built-in decoder */
-/* these should be kept identical to the types in dmx.h */
-
-enum dmx_ts_pes
-{ /* also send packets to decoder (if it exists) */
- DMX_TS_PES_AUDIO0,
- DMX_TS_PES_VIDEO0,
- DMX_TS_PES_TELETEXT0,
- DMX_TS_PES_SUBTITLE0,
- DMX_TS_PES_PCR0,
-
- DMX_TS_PES_AUDIO1,
- DMX_TS_PES_VIDEO1,
- DMX_TS_PES_TELETEXT1,
- DMX_TS_PES_SUBTITLE1,
- DMX_TS_PES_PCR1,
-
- DMX_TS_PES_AUDIO2,
- DMX_TS_PES_VIDEO2,
- DMX_TS_PES_TELETEXT2,
- DMX_TS_PES_SUBTITLE2,
- DMX_TS_PES_PCR2,
-
- DMX_TS_PES_AUDIO3,
- DMX_TS_PES_VIDEO3,
- DMX_TS_PES_TELETEXT3,
- DMX_TS_PES_SUBTITLE3,
- DMX_TS_PES_PCR3,
-
- DMX_TS_PES_OTHER
-};
-
-#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0
-#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0
-#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
-#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
-#define DMX_TS_PES_PCR DMX_TS_PES_PCR0
-
-
struct dmx_ts_feed {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux *parent; /* Back-pointer */
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
index d81dbb22aa81..a1a3a5159d71 100644
--- a/drivers/media/dvb-core/dmxdev.c
+++ b/drivers/media/dvb-core/dmxdev.c
@@ -569,7 +569,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
dmx_output_t otype;
int ret;
int ts_type;
- dmx_pes_type_t ts_pes;
+ enum dmx_ts_pes ts_pes;
struct dmx_ts_feed *tsfeed;
feed->ts = NULL;
@@ -852,7 +852,8 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params)
{
- dprintk("function : %s\n", __func__);
+ dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n",
+ __func__, params->pid, params->flags, params->timeout);
dvb_dmxdev_filter_stop(dmxdevfilter);
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 399e1042d351..335a8f4695b4 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -124,8 +124,7 @@
#define USB_PID_DIBCOM_STK7770P 0x1e80
#define USB_PID_DIBCOM_NIM7090 0x1bb2
#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4
-#define USB_PID_DIBCOM_TFE7090E 0x1bb7
-#define USB_PID_DIBCOM_TFE7790E 0x1e6e
+#define USB_PID_DIBCOM_TFE7790P 0x1e6e
#define USB_PID_DIBCOM_NIM9090M 0x2383
#define USB_PID_DIBCOM_NIM9090MD 0x2384
#define USB_PID_DPOSH_M9206_COLD 0x9206
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index d319717eb535..3485655fa082 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -440,20 +440,22 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
if (!dvb_demux_feed_err_pkts)
return;
} else /* if TEI bit is set, pid may be wrong- skip pkt counter */
- if (demux->cnt_storage && dvb_demux_tscheck) {
- /* check pkt counter */
- if (pid < MAX_PID) {
- if ((buf[3] & 0xf) != demux->cnt_storage[pid])
- dprintk_tscheck("TS packet counter mismatch. "
- "PID=0x%x expected 0x%x "
- "got 0x%x\n",
+ if (demux->cnt_storage && dvb_demux_tscheck) {
+ /* check pkt counter */
+ if (pid < MAX_PID) {
+ if (buf[3] & 0x10)
+ demux->cnt_storage[pid] =
+ (demux->cnt_storage[pid] + 1) & 0xf;
+
+ if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
+ dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
pid, demux->cnt_storage[pid],
buf[3] & 0xf);
-
- demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+ demux->cnt_storage[pid] = buf[3] & 0xf;
+ }
+ }
+ /* end check */
}
- /* end check */
- }
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
@@ -672,7 +674,7 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
return -ERESTARTSYS;
if (ts_type & TS_DECODER) {
- if (pes_type >= DMX_TS_PES_OTHER) {
+ if (pes_type >= DMX_PES_OTHER) {
mutex_unlock(&demux->mutex);
return -EINVAL;
}
@@ -844,7 +846,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
feed->pid = 0xffff;
- if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
+ if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_PES_OTHER)
demux->pesfilter[feed->pes_type] = NULL;
mutex_unlock(&demux->mutex);
@@ -1266,7 +1268,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
INIT_LIST_HEAD(&dvbdemux->frontend_list);
- for (i = 0; i < DMX_TS_PES_OTHER; i++) {
+ for (i = 0; i < DMX_PES_OTHER; i++) {
dvbdemux->pesfilter[i] = NULL;
dvbdemux->pids[i] = 0xffff;
}
diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
index fa7188a253aa..ae7fc33c3231 100644
--- a/drivers/media/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb-core/dvb_demux.h
@@ -119,8 +119,8 @@ struct dvb_demux {
struct list_head frontend_list;
- struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
- u16 pids[DMX_TS_PES_OTHER];
+ struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
+ u16 pids[DMX_PES_OTHER];
int playing;
int recording;
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 73fc7fe00751..1f925e856974 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -920,7 +920,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
u32 delsys;
delsys = c->delivery_system;
- memset(c, 0, sizeof(struct dtv_frontend_properties));
+ memset(c, 0, offsetof(struct dtv_frontend_properties, strength));
c->delivery_system = delsys;
c->state = DTV_CLEAR;
@@ -1509,9 +1509,74 @@ static bool is_dvbv3_delsys(u32 delsys)
return status;
}
-static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+/**
+ * emulate_delivery_system - emulate a DVBv5 delivery system with a DVBv3 type
+ * @fe: struct frontend;
+ * @delsys: DVBv5 type that will be used for emulation
+ *
+ * Provides emulation for delivery systems that are compatible with the old
+ * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows
+ * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent
+ * parameters are compatible with DVB-S spec.
+ */
+static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys)
{
- int ncaps, i;
+ int i;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ c->delivery_system = delsys;
+
+ /*
+ * If the call is for ISDB-T, put it into full-seg, auto mode, TV
+ */
+ if (c->delivery_system == SYS_ISDBT) {
+ dev_dbg(fe->dvb->device,
+ "%s: Using defaults for SYS_ISDBT\n",
+ __func__);
+
+ if (!c->bandwidth_hz)
+ c->bandwidth_hz = 6000000;
+
+ c->isdbt_partial_reception = 0;
+ c->isdbt_sb_mode = 0;
+ c->isdbt_sb_subchannel = 0;
+ c->isdbt_sb_segment_idx = 0;
+ c->isdbt_sb_segment_count = 0;
+ c->isdbt_layer_enabled = 7;
+ for (i = 0; i < 3; i++) {
+ c->layer[i].fec = FEC_AUTO;
+ c->layer[i].modulation = QAM_AUTO;
+ c->layer[i].interleaving = 0;
+ c->layer[i].segment_count = 0;
+ }
+ }
+ dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
+ __func__, c->delivery_system);
+
+ return 0;
+}
+
+/**
+ * dvbv5_set_delivery_system - Sets the delivery system for a DVBv5 API call
+ * @fe: frontend struct
+ * @desired_system: delivery system requested by the user
+ *
+ * A DVBv5 call know what's the desired system it wants. So, set it.
+ *
+ * There are, however, a few known issues with early DVBv5 applications that
+ * are also handled by this logic:
+ *
+ * 1) Some early apps use SYS_UNDEFINED as the desired delivery system.
+ * This is an API violation, but, as we don't want to break userspace,
+ * convert it to the first supported delivery system.
+ * 2) Some apps might be using a DVBv5 call in a wrong way, passing, for
+ * example, SYS_DVBT instead of SYS_ISDBT. This is because early usage of
+ * ISDB-T provided backward compat with DVB-T.
+ */
+static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
+ u32 desired_system)
+{
+ int ncaps;
u32 delsys = SYS_UNDEFINED;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
enum dvbv3_emulation_type type;
@@ -1522,166 +1587,136 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
* assume that the application wants to use the first supported
* delivery system.
*/
- if (c->delivery_system == SYS_UNDEFINED)
- c->delivery_system = fe->ops.delsys[0];
+ if (desired_system == SYS_UNDEFINED)
+ desired_system = fe->ops.delsys[0];
- if (desired_system == SYS_UNDEFINED) {
- /*
- * A DVBv3 call doesn't know what's the desired system.
- * Also, DVBv3 applications don't know that ops.info->type
- * could be changed, and they simply dies when it doesn't
- * match.
- * So, don't change the current delivery system, as it
- * may be trying to do the wrong thing, like setting an
- * ISDB-T frontend as DVB-T. Instead, find the closest
- * DVBv3 system that matches the delivery system.
- */
- if (is_dvbv3_delsys(c->delivery_system)) {
+ /*
+ * This is a DVBv5 call. So, it likely knows the supported
+ * delivery systems. So, check if the desired delivery system is
+ * supported
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (fe->ops.delsys[ncaps] == desired_system) {
+ c->delivery_system = desired_system;
dev_dbg(fe->dvb->device,
- "%s: Using delivery system to %d\n",
- __func__, c->delivery_system);
- return 0;
- }
- type = dvbv3_type(c->delivery_system);
- switch (type) {
- case DVBV3_QPSK:
- desired_system = SYS_DVBS;
- break;
- case DVBV3_QAM:
- desired_system = SYS_DVBC_ANNEX_A;
- break;
- case DVBV3_ATSC:
- desired_system = SYS_ATSC;
- break;
- case DVBV3_OFDM:
- desired_system = SYS_DVBT;
- break;
- default:
- dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n",
- __func__);
- return -EINVAL;
- }
- /*
- * Get a delivery system that is compatible with DVBv3
- * NOTE: in order for this to work with softwares like Kaffeine that
- * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
- * DVB-S, drivers that support both should put the SYS_DVBS entry
- * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
- * The real fix is that userspace applications should not use DVBv3
- * and not trust on calling FE_SET_FRONTEND to switch the delivery
- * system.
- */
- ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
- if (fe->ops.delsys[ncaps] == desired_system) {
- delsys = desired_system;
- break;
- }
- ncaps++;
- }
- if (delsys == SYS_UNDEFINED) {
- dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n",
+ "%s: Changing delivery system to %d\n",
__func__, desired_system);
+ return 0;
}
- } else {
- /*
- * This is a DVBv5 call. So, it likely knows the supported
- * delivery systems.
- */
+ ncaps++;
+ }
- /* Check if the desired delivery system is supported */
- ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
- if (fe->ops.delsys[ncaps] == desired_system) {
- c->delivery_system = desired_system;
- dev_dbg(fe->dvb->device,
- "%s: Changing delivery system to %d\n",
- __func__, desired_system);
- return 0;
- }
- ncaps++;
- }
- type = dvbv3_type(desired_system);
+ /*
+ * The requested delivery system isn't supported. Maybe userspace
+ * is requesting a DVBv3 compatible delivery system.
+ *
+ * The emulation only works if the desired system is one of the
+ * delivery systems supported by DVBv3 API
+ */
+ if (!is_dvbv3_delsys(desired_system)) {
+ dev_dbg(fe->dvb->device,
+ "%s: Delivery system %d not supported.\n",
+ __func__, desired_system);
+ return -EINVAL;
+ }
- /*
- * The delivery system is not supported. See if it can be
- * emulated.
- * The emulation only works if the desired system is one of the
- * DVBv3 delivery systems
- */
- if (!is_dvbv3_delsys(desired_system)) {
- dev_dbg(fe->dvb->device,
- "%s: can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
- __func__);
- return -EINVAL;
- }
+ type = dvbv3_type(desired_system);
- /*
- * Get the last non-DVBv3 delivery system that has the same type
- * of the desired system
- */
- ncaps = 0;
- while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
- if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
- !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
- delsys = fe->ops.delsys[ncaps];
- ncaps++;
- }
- /* There's nothing compatible with the desired delivery system */
- if (delsys == SYS_UNDEFINED) {
- dev_dbg(fe->dvb->device,
- "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
- __func__);
- return -EINVAL;
- }
+ /*
+ * Get the last non-DVBv3 delivery system that has the same type
+ * of the desired system
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
+ delsys = fe->ops.delsys[ncaps];
+ ncaps++;
}
- c->delivery_system = delsys;
+ /* There's nothing compatible with the desired delivery system */
+ if (delsys == SYS_UNDEFINED) {
+ dev_dbg(fe->dvb->device,
+ "%s: Delivery system %d not supported on emulation mode.\n",
+ __func__, desired_system);
+ return -EINVAL;
+ }
+
+ dev_dbg(fe->dvb->device,
+ "%s: Using delivery system %d emulated as if it were %d\n",
+ __func__, delsys, desired_system);
+
+ return emulate_delivery_system(fe, desired_system);
+}
+
+/**
+ * dvbv3_set_delivery_system - Sets the delivery system for a DVBv3 API call
+ * @fe: frontend struct
+ *
+ * A DVBv3 call doesn't know what's the desired system it wants. It also
+ * doesn't allow to switch between different types. Due to that, userspace
+ * should use DVBv5 instead.
+ * However, in order to avoid breaking userspace API, limited backward
+ * compatibility support is provided.
+ *
+ * There are some delivery systems that are incompatible with DVBv3 calls.
+ *
+ * This routine should work fine for frontends that support just one delivery
+ * system.
+ *
+ * For frontends that support multiple frontends:
+ * 1) It defaults to use the first supported delivery system. There's an
+ * userspace application that allows changing it at runtime;
+ *
+ * 2) If the current delivery system is not compatible with DVBv3, it gets
+ * the first one that it is compatible.
+ *
+ * NOTE: in order for this to work with applications like Kaffeine that
+ * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
+ * DVB-S, drivers that support both DVB-S and DVB-S2 should have the
+ * SYS_DVBS entry before the SYS_DVBS2, otherwise it won't switch back
+ * to DVB-S.
+ */
+static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
+{
+ int ncaps;
+ u32 delsys = SYS_UNDEFINED;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ /* If not set yet, defaults to the first supported delivery system */
+ if (c->delivery_system == SYS_UNDEFINED)
+ c->delivery_system = fe->ops.delsys[0];
/*
- * The DVBv3 or DVBv5 call is requesting a different system. So,
- * emulation is needed.
- *
- * Emulate newer delivery systems like ISDBT, DVBT and DTMB
- * for older DVBv5 applications. The emulation will try to use
- * the auto mode for most things, and will assume that the desired
- * delivery system is the last one at the ops.delsys[] array
+ * Trivial case: just use the current one, if it already a DVBv3
+ * delivery system
*/
- dev_dbg(fe->dvb->device,
- "%s: Using delivery system %d emulated as if it were a %d\n",
- __func__, delsys, desired_system);
+ if (is_dvbv3_delsys(c->delivery_system)) {
+ dev_dbg(fe->dvb->device,
+ "%s: Using delivery system to %d\n",
+ __func__, c->delivery_system);
+ return 0;
+ }
/*
- * For now, handles ISDB-T calls. More code may be needed here for the
- * other emulated stuff
+ * Seek for the first delivery system that it is compatible with a
+ * DVBv3 standard
*/
- if (type == DVBV3_OFDM) {
- if (c->delivery_system == SYS_ISDBT) {
- dev_dbg(fe->dvb->device,
- "%s: Using defaults for SYS_ISDBT\n",
- __func__);
-
- if (!c->bandwidth_hz)
- c->bandwidth_hz = 6000000;
-
- c->isdbt_partial_reception = 0;
- c->isdbt_sb_mode = 0;
- c->isdbt_sb_subchannel = 0;
- c->isdbt_sb_segment_idx = 0;
- c->isdbt_sb_segment_count = 0;
- c->isdbt_layer_enabled = 0;
- for (i = 0; i < 3; i++) {
- c->layer[i].fec = FEC_AUTO;
- c->layer[i].modulation = QAM_AUTO;
- c->layer[i].interleaving = 0;
- c->layer[i].segment_count = 0;
- }
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
+ delsys = fe->ops.delsys[ncaps];
+ break;
}
+ ncaps++;
}
- dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
- __func__, c->delivery_system);
-
- return 0;
+ if (delsys == SYS_UNDEFINED) {
+ dev_dbg(fe->dvb->device,
+ "%s: Couldn't find a delivery system that works with FE_SET_FRONTEND\n",
+ __func__);
+ return -EINVAL;
+ }
+ return emulate_delivery_system(fe, delsys);
}
static int dtv_property_process_set(struct dvb_frontend *fe,
@@ -1742,7 +1777,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
c->rolloff = tvp->u.data;
break;
case DTV_DELIVERY_SYSTEM:
- r = set_delivery_system(fe, tvp->u.data);
+ r = dvbv5_set_delivery_system(fe, tvp->u.data);
break;
case DTV_VOLTAGE:
c->voltage = tvp->u.data;
@@ -2335,7 +2370,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break;
case FE_SET_FRONTEND:
- err = set_delivery_system(fe, SYS_UNDEFINED);
+ err = dvbv3_set_delivery_system(fe);
if (err)
break;
@@ -2591,7 +2626,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
* first supported delivery system (ops->delsys[0])
*/
- fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
+ fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
dvb_frontend_clear_cache(fe);
mutex_unlock(&frontend_mutex);
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index b34922a08156..371b6caf486c 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -245,8 +245,8 @@ struct analog_demod_ops {
void (*set_params)(struct dvb_frontend *fe,
struct analog_parameters *params);
- int (*has_signal)(struct dvb_frontend *fe);
- int (*get_afc)(struct dvb_frontend *fe);
+ int (*has_signal)(struct dvb_frontend *fe, u16 *signal);
+ int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
void (*tuner_status)(struct dvb_frontend *fe);
void (*standby)(struct dvb_frontend *fe);
void (*release)(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 59ba60659a3e..f91c80c0e9ec 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -185,7 +185,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
skb->pkt_type=PACKET_MULTICAST;
}
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
return eth->h_proto;
rawp = skb->data;
@@ -228,9 +228,9 @@ static int ule_test_sndu( struct dvb_net_priv *p )
static int ule_bridged_sndu( struct dvb_net_priv *p )
{
struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
- if(ntohs(hdr->h_proto) < 1536) {
+ if(ntohs(hdr->h_proto) < ETH_P_802_3_MIN) {
int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
- /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+ /* A frame Type < ETH_P_802_3_MIN for a bridged frame, introduces a LLC Length field. */
if(framelen != ntohs(hdr->h_proto)) {
return -1;
}
@@ -320,7 +320,7 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
(int) p->ule_sndu_type, l, total_ext_len);
#endif
- } while (p->ule_sndu_type < 1536);
+ } while (p->ule_sndu_type < ETH_P_802_3_MIN);
return total_ext_len;
}
@@ -712,7 +712,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
/* Handle ULE Extension Headers. */
- if (priv->ule_sndu_type < 1536) {
+ if (priv->ule_sndu_type < ETH_P_802_3_MIN) {
/* There is an extension header. Handle it accordingly. */
int l = handle_ule_extensions(priv);
if (l < 0) {
@@ -1044,7 +1044,7 @@ static int dvb_net_feed_start(struct net_device *dev)
ret = priv->tsfeed->set(priv->tsfeed,
priv->pid, /* pid */
TS_PACKET, /* type */
- DMX_TS_PES_OTHER, /* pes type */
+ DMX_PES_OTHER, /* pes type */
32768, /* circular buffer size */
timeout /* timeout */
);
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 6f809a70c78e..0e2ec6f73b05 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -210,7 +210,7 @@ config DVB_SI21XX
config DVB_TS2020
tristate "Montage Tehnology TS2020 based tuners"
depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
+ default m if !MEDIA_SUBDRV_AUTOSELECT
help
A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner.
diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h
index ed29e5504f76..b6ef6427cfa5 100644
--- a/drivers/media/dvb-frontends/a8293.h
+++ b/drivers/media/dvb-frontends/a8293.h
@@ -21,12 +21,13 @@
#ifndef A8293_H
#define A8293_H
+#include <linux/kconfig.h>
+
struct a8293_config {
u8 i2c_addr;
};
-#if defined(CONFIG_DVB_A8293) || \
- (defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_A8293)
extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct a8293_config *cfg);
#else
diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h
index dc837d91327a..09273b2cd310 100644
--- a/drivers/media/dvb-frontends/af9013.h
+++ b/drivers/media/dvb-frontends/af9013.h
@@ -25,6 +25,7 @@
#ifndef AF9013_H
#define AF9013_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
/* AF9013/5 GPIOs (mostly guessed)
@@ -102,8 +103,7 @@ struct af9013_config {
u8 gpio[4];
};
-#if defined(CONFIG_DVB_AF9013) || \
- (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_AF9013)
extern struct dvb_frontend *af9013_attach(const struct af9013_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index c9cad989b8b9..a777b4b944eb 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -156,6 +156,37 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
return 0;
}
+/* write reg val table using reg addr auto increment */
+static int af9033_wr_reg_val_tab(struct af9033_state *state,
+ const struct reg_val *tab, int tab_len)
+{
+ int ret, i, j;
+ u8 buf[tab_len];
+
+ dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
+
+ for (i = 0, j = 0; i < tab_len; i++) {
+ buf[j] = tab[i].val;
+
+ if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) {
+ ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1);
+ if (ret < 0)
+ goto err;
+
+ j = 0;
+ } else {
+ j++;
+ }
+ }
+
+ return 0;
+
+err:
+ dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x)
{
u32 r = 0, c = 0, i;
@@ -223,6 +254,7 @@ static int af9033_init(struct dvb_frontend *fe)
{ 0x80f986, state->ts_mode_parallel, 0x01 },
{ 0x00d827, 0x00, 0xff },
{ 0x00d829, 0x00, 0xff },
+ { 0x800045, state->cfg.adc_multiplier, 0xff },
};
/* program clock control */
@@ -286,14 +318,29 @@ static int af9033_init(struct dvb_frontend *fe)
/* load OFSM settings */
dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__);
- len = ARRAY_SIZE(ofsm_init);
- init = ofsm_init;
- for (i = 0; i < len; i++) {
- ret = af9033_wr_reg(state, init[i].reg, init[i].val);
- if (ret < 0)
- goto err;
+ switch (state->cfg.tuner) {
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ len = ARRAY_SIZE(ofsm_init_it9135_v1);
+ init = ofsm_init_it9135_v1;
+ break;
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ len = ARRAY_SIZE(ofsm_init_it9135_v2);
+ init = ofsm_init_it9135_v2;
+ break;
+ default:
+ len = ARRAY_SIZE(ofsm_init);
+ init = ofsm_init;
+ break;
}
+ ret = af9033_wr_reg_val_tab(state, init, len);
+ if (ret < 0)
+ goto err;
+
/* load tuner specific settings */
dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n",
__func__);
@@ -322,6 +369,30 @@ static int af9033_init(struct dvb_frontend *fe)
len = ARRAY_SIZE(tuner_init_fc0012);
init = tuner_init_fc0012;
break;
+ case AF9033_TUNER_IT9135_38:
+ len = ARRAY_SIZE(tuner_init_it9135_38);
+ init = tuner_init_it9135_38;
+ break;
+ case AF9033_TUNER_IT9135_51:
+ len = ARRAY_SIZE(tuner_init_it9135_51);
+ init = tuner_init_it9135_51;
+ break;
+ case AF9033_TUNER_IT9135_52:
+ len = ARRAY_SIZE(tuner_init_it9135_52);
+ init = tuner_init_it9135_52;
+ break;
+ case AF9033_TUNER_IT9135_60:
+ len = ARRAY_SIZE(tuner_init_it9135_60);
+ init = tuner_init_it9135_60;
+ break;
+ case AF9033_TUNER_IT9135_61:
+ len = ARRAY_SIZE(tuner_init_it9135_61);
+ init = tuner_init_it9135_61;
+ break;
+ case AF9033_TUNER_IT9135_62:
+ len = ARRAY_SIZE(tuner_init_it9135_62);
+ init = tuner_init_it9135_62;
+ break;
default:
dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n",
__func__, state->cfg.tuner);
@@ -329,11 +400,9 @@ static int af9033_init(struct dvb_frontend *fe)
goto err;
}
- for (i = 0; i < len; i++) {
- ret = af9033_wr_reg(state, init[i].reg, init[i].val);
- if (ret < 0)
- goto err;
- }
+ ret = af9033_wr_reg_val_tab(state, init, len);
+ if (ret < 0)
+ goto err;
if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01);
@@ -349,6 +418,15 @@ static int af9033_init(struct dvb_frontend *fe)
goto err;
}
+ switch (state->cfg.tuner) {
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ ret = af9033_wr_reg(state, 0x800000, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
state->bandwidth_hz = 0; /* force to program all parameters */
return 0;
@@ -415,7 +493,8 @@ err:
static int af9033_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *fesettings)
{
- fesettings->min_delay_ms = 800;
+ /* 800 => 2000 because IT9135 v2 is slow to gain lock */
+ fesettings->min_delay_ms = 2000;
fesettings->step_size = 0;
fesettings->max_drift = 0;
@@ -498,17 +577,17 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
if (spec_inv == -1)
freq_cw = 0x800000 - freq_cw;
- /* get adc multiplies */
- ret = af9033_rd_reg(state, 0x800045, &tmp);
- if (ret < 0)
- goto err;
-
- if (tmp == 1)
+ if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X)
freq_cw /= 2;
buf[0] = (freq_cw >> 0) & 0xff;
buf[1] = (freq_cw >> 8) & 0xff;
buf[2] = (freq_cw >> 16) & 0x7f;
+
+ /* FIXME: there seems to be calculation error here... */
+ if (if_frequency == 0)
+ buf[2] = 0;
+
ret = af9033_wr_regs(state, 0x800029, buf, 3);
if (ret < 0)
goto err;
@@ -934,13 +1013,24 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config,
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
/* sleep */
- ret = af9033_wr_reg(state, 0x80004c, 1);
- if (ret < 0)
- goto err;
+ switch (state->cfg.tuner) {
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ /* IT9135 did not like to sleep at that early */
+ break;
+ default:
+ ret = af9033_wr_reg(state, 0x80004c, 1);
+ if (ret < 0)
+ goto err;
- ret = af9033_wr_reg(state, 0x800000, 0);
- if (ret < 0)
- goto err;
+ ret = af9033_wr_reg(state, 0x800000, 0);
+ if (ret < 0)
+ goto err;
+ }
/* configure internal TS mode */
switch (state->cfg.ts_mode) {
diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h
index 82bd8c1513b6..c286e8f1ec02 100644
--- a/drivers/media/dvb-frontends/af9033.h
+++ b/drivers/media/dvb-frontends/af9033.h
@@ -22,6 +22,8 @@
#ifndef AF9033_H
#define AF9033_H
+#include <linux/kconfig.h>
+
struct af9033_config {
/*
* I2C address
@@ -36,6 +38,13 @@ struct af9033_config {
u32 clock;
/*
+ * ADC multiplier
+ */
+#define AF9033_ADC_MULTIPLIER_1X 0
+#define AF9033_ADC_MULTIPLIER_2X 1
+ u8 adc_multiplier;
+
+ /*
* tuner
*/
#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */
@@ -44,6 +53,14 @@ struct af9033_config {
#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */
#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */
#define AF9033_TUNER_FC2580 0x32 /* FCI FC2580 */
+/* 50-5f Omega */
+#define AF9033_TUNER_IT9135_38 0x38 /* Omega */
+#define AF9033_TUNER_IT9135_51 0x51 /* Omega LNA config 1 */
+#define AF9033_TUNER_IT9135_52 0x52 /* Omega LNA config 2 */
+/* 60-6f Omega v2 */
+#define AF9033_TUNER_IT9135_60 0x60 /* Omega v2 */
+#define AF9033_TUNER_IT9135_61 0x61 /* Omega v2 LNA config 1 */
+#define AF9033_TUNER_IT9135_62 0x62 /* Omega v2 LNA config 2 */
u8 tuner;
/*
@@ -61,8 +78,7 @@ struct af9033_config {
};
-#if defined(CONFIG_DVB_AF9033) || \
- (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_AF9033)
extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index e9bd78265543..fc2ad581e302 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -547,5 +547,1509 @@ static const struct reg_val tuner_init_fc2580[] = {
{ 0x80f1e6, 0x01 },
};
-#endif /* AF9033_PRIV_H */
+static const struct reg_val ofsm_init_it9135_v1[] = {
+ { 0x800051, 0x01 },
+ { 0x800070, 0x0a },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800099, 0x01 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c6, 0x19 },
+ { 0x80f000, 0x0f },
+ { 0x80f016, 0x10 },
+ { 0x80f017, 0x04 },
+ { 0x80f018, 0x05 },
+ { 0x80f019, 0x04 },
+ { 0x80f01a, 0x05 },
+ { 0x80f021, 0x03 },
+ { 0x80f022, 0x0a },
+ { 0x80f023, 0x0a },
+ { 0x80f02b, 0x00 },
+ { 0x80f02c, 0x01 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5df, 0xfb },
+ { 0x80f5e0, 0x00 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f5f8, 0x01 },
+ { 0x80f5fd, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* ITE Tech IT9135 Omega tuner init
+ AF9033_TUNER_IT9135_38 = 0x38 */
+static const struct reg_val tuner_init_it9135_38[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x38 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x0a },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0xc8 },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x80007f, 0x00 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x12 },
+ { 0x800083, 0x02 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x03 },
+ { 0x800086, 0xc8 },
+ { 0x800087, 0xb8 },
+ { 0x800088, 0xd0 },
+ { 0x800089, 0xc3 },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5a },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x32 },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cc, 0x2e },
+ { 0x8000cd, 0x51 },
+ { 0x8000ce, 0x33 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0x8c },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x02 },
+ { 0x8000fd, 0x02 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x09 },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x7b },
+ { 0x800102, 0x77 },
+ { 0x800103, 0x00 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xc8 },
+ { 0x800106, 0x05 },
+ { 0x800107, 0x7b },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x800117, 0x02 },
+ { 0x800118, 0x80 },
+ { 0x80011a, 0xc8 },
+ { 0x80011b, 0x7b },
+ { 0x80011c, 0x8a },
+ { 0x80011d, 0xa0 },
+ { 0x800122, 0x02 },
+ { 0x800123, 0x18 },
+ { 0x800124, 0xc3 },
+ { 0x800127, 0x00 },
+ { 0x800128, 0x07 },
+ { 0x80012a, 0x53 },
+ { 0x80012b, 0x51 },
+ { 0x80012c, 0x4e },
+ { 0x80012d, 0x43 },
+ { 0x800137, 0x01 },
+ { 0x800138, 0x00 },
+ { 0x800139, 0x07 },
+ { 0x80013a, 0x00 },
+ { 0x80013b, 0x06 },
+ { 0x80013d, 0x00 },
+ { 0x80013e, 0x01 },
+ { 0x80013f, 0x5b },
+ { 0x800140, 0xc8 },
+ { 0x800141, 0x59 },
+ { 0x80f000, 0x0f },
+ { 0x80f016, 0x10 },
+ { 0x80f017, 0x04 },
+ { 0x80f018, 0x05 },
+ { 0x80f019, 0x04 },
+ { 0x80f01a, 0x05 },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f021, 0x03 },
+ { 0x80f022, 0x0a },
+ { 0x80f023, 0x0a },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f02c, 0x01 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f085, 0x00 },
+ { 0x80f086, 0x02 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5df, 0xfb },
+ { 0x80f5e0, 0x00 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f5f8, 0x01 },
+ { 0x80f5fd, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* ITE Tech IT9135 Omega LNA config 1 tuner init
+ AF9033_TUNER_IT9135_51 = 0x51 */
+static const struct reg_val tuner_init_it9135_51[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x51 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x0a },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x06 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0xc8 },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x80007f, 0x00 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x12 },
+ { 0x800083, 0x02 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x03 },
+ { 0x800086, 0xc0 },
+ { 0x800087, 0x96 },
+ { 0x800088, 0xcf },
+ { 0x800089, 0xc3 },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5a },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x3c },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cc, 0x2e },
+ { 0x8000cd, 0x51 },
+ { 0x8000ce, 0x33 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0x8c },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x03 },
+ { 0x8000fd, 0x02 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x09 },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x7a },
+ { 0x800102, 0x77 },
+ { 0x800103, 0x01 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xb0 },
+ { 0x800106, 0x02 },
+ { 0x800107, 0x7a },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x800117, 0x02 },
+ { 0x800118, 0x80 },
+ { 0x80011a, 0xc0 },
+ { 0x80011b, 0x7a },
+ { 0x80011c, 0xac },
+ { 0x80011d, 0x8c },
+ { 0x800122, 0x02 },
+ { 0x800123, 0x70 },
+ { 0x800124, 0xa4 },
+ { 0x800127, 0x00 },
+ { 0x800128, 0x07 },
+ { 0x80012a, 0x53 },
+ { 0x80012b, 0x51 },
+ { 0x80012c, 0x4e },
+ { 0x80012d, 0x43 },
+ { 0x800137, 0x01 },
+ { 0x800138, 0x00 },
+ { 0x800139, 0x07 },
+ { 0x80013a, 0x00 },
+ { 0x80013b, 0x06 },
+ { 0x80013d, 0x00 },
+ { 0x80013e, 0x01 },
+ { 0x80013f, 0x5b },
+ { 0x800140, 0xc0 },
+ { 0x800141, 0x59 },
+ { 0x80f000, 0x0f },
+ { 0x80f016, 0x10 },
+ { 0x80f017, 0x04 },
+ { 0x80f018, 0x05 },
+ { 0x80f019, 0x04 },
+ { 0x80f01a, 0x05 },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f021, 0x03 },
+ { 0x80f022, 0x0a },
+ { 0x80f023, 0x0a },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f02c, 0x01 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f085, 0xc0 },
+ { 0x80f086, 0x01 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5df, 0xfb },
+ { 0x80f5e0, 0x00 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f5f8, 0x01 },
+ { 0x80f5fd, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* ITE Tech IT9135 Omega LNA config 2 tuner init
+ AF9033_TUNER_IT9135_52 = 0x52 */
+static const struct reg_val tuner_init_it9135_52[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x52 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x10 },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0xa0 },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x80007f, 0x00 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x17 },
+ { 0x800083, 0x03 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x03 },
+ { 0x800086, 0xb3 },
+ { 0x800087, 0x97 },
+ { 0x800088, 0xc0 },
+ { 0x800089, 0x9e },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5c },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x3c },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cc, 0x2e },
+ { 0x8000cd, 0x51 },
+ { 0x8000ce, 0x33 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0x91 },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x03 },
+ { 0x8000fd, 0x02 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x09 },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x74 },
+ { 0x800102, 0x77 },
+ { 0x800103, 0x02 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xa4 },
+ { 0x800106, 0x02 },
+ { 0x800107, 0x6e },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x800117, 0x02 },
+ { 0x800118, 0x80 },
+ { 0x80011a, 0xcd },
+ { 0x80011b, 0x62 },
+ { 0x80011c, 0xa4 },
+ { 0x80011d, 0x8c },
+ { 0x800122, 0x03 },
+ { 0x800123, 0x18 },
+ { 0x800124, 0x9e },
+ { 0x800127, 0x00 },
+ { 0x800128, 0x07 },
+ { 0x80012a, 0x53 },
+ { 0x80012b, 0x51 },
+ { 0x80012c, 0x4e },
+ { 0x80012d, 0x43 },
+ { 0x800137, 0x00 },
+ { 0x800138, 0x00 },
+ { 0x800139, 0x07 },
+ { 0x80013a, 0x00 },
+ { 0x80013b, 0x06 },
+ { 0x80013d, 0x00 },
+ { 0x80013e, 0x01 },
+ { 0x80013f, 0x5b },
+ { 0x800140, 0xb6 },
+ { 0x800141, 0x59 },
+ { 0x80f000, 0x0f },
+ { 0x80f016, 0x10 },
+ { 0x80f017, 0x04 },
+ { 0x80f018, 0x05 },
+ { 0x80f019, 0x04 },
+ { 0x80f01a, 0x05 },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f021, 0x03 },
+ { 0x80f022, 0x0a },
+ { 0x80f023, 0x0a },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f02c, 0x01 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f085, 0xc0 },
+ { 0x80f086, 0x01 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5df, 0xfb },
+ { 0x80f5e0, 0x00 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f5f8, 0x01 },
+ { 0x80f5fd, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+static const struct reg_val ofsm_init_it9135_v2[] = {
+ { 0x800051, 0x01 },
+ { 0x800070, 0x0a },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800099, 0x01 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c6, 0x19 },
+ { 0x80f000, 0x0f },
+ { 0x80f02b, 0x00 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* ITE Tech IT9135 Omega v2 tuner init
+ AF9033_TUNER_IT9135_60 = 0x60 */
+static const struct reg_val tuner_init_it9135_60[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x60 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x0a },
+ { 0x80006a, 0x03 },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0x8c },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x18 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x33 },
+ { 0x800086, 0xbe },
+ { 0x800087, 0xa0 },
+ { 0x800088, 0xc6 },
+ { 0x800089, 0xb6 },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5a },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x3a },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c3, 0x01 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cb, 0x32 },
+ { 0x8000cc, 0x2c },
+ { 0x8000cd, 0x4f },
+ { 0x8000ce, 0x30 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0xa0 },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x03 },
+ { 0x8000fd, 0x03 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x0a },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x7b },
+ { 0x800102, 0x8c },
+ { 0x800103, 0x00 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xbe },
+ { 0x800106, 0x00 },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x80011a, 0xbe },
+ { 0x800124, 0xae },
+ { 0x800127, 0x00 },
+ { 0x80012a, 0x56 },
+ { 0x80012b, 0x50 },
+ { 0x80012c, 0x47 },
+ { 0x80012d, 0x42 },
+ { 0x800137, 0x00 },
+ { 0x80013b, 0x08 },
+ { 0x80013f, 0x5b },
+ { 0x800141, 0x59 },
+ { 0x800142, 0xf9 },
+ { 0x800143, 0x19 },
+ { 0x800144, 0x00 },
+ { 0x800145, 0x8c },
+ { 0x800146, 0x8c },
+ { 0x800147, 0x8c },
+ { 0x800148, 0x6e },
+ { 0x800149, 0x8c },
+ { 0x80014a, 0x50 },
+ { 0x80014b, 0x8c },
+ { 0x80014d, 0xac },
+ { 0x80014e, 0xc6 },
+ { 0x80014f, 0x03 },
+ { 0x800151, 0x1e },
+ { 0x800153, 0xbc },
+ { 0x800178, 0x09 },
+ { 0x800181, 0x94 },
+ { 0x800182, 0x6e },
+ { 0x800185, 0x24 },
+ { 0x800189, 0xbe },
+ { 0x80018c, 0x03 },
+ { 0x80018d, 0x5f },
+ { 0x80018f, 0xa0 },
+ { 0x800190, 0x5a },
+ { 0x80ed02, 0xff },
+ { 0x80ee42, 0xff },
+ { 0x80ee82, 0xff },
+ { 0x80f000, 0x0f },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+/* ITE Tech IT9135 Omega v2 LNA config 1 tuner init
+ AF9033_TUNER_IT9135_61 = 0x61 */
+static const struct reg_val tuner_init_it9135_61[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x61 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x06 },
+ { 0x80006a, 0x03 },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0x90 },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x12 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x33 },
+ { 0x800086, 0xbc },
+ { 0x800087, 0x9c },
+ { 0x800088, 0xcc },
+ { 0x800089, 0xa8 },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5c },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x3a },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c3, 0x01 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cb, 0x32 },
+ { 0x8000cc, 0x2c },
+ { 0x8000cd, 0x4f },
+ { 0x8000ce, 0x30 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0xa0 },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x03 },
+ { 0x8000fd, 0x03 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x08 },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x7b },
+ { 0x800102, 0x8c },
+ { 0x800103, 0x01 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xc8 },
+ { 0x800106, 0x00 },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x80011a, 0xc6 },
+ { 0x800124, 0xa8 },
+ { 0x800127, 0x00 },
+ { 0x80012a, 0x59 },
+ { 0x80012b, 0x50 },
+ { 0x80012c, 0x47 },
+ { 0x80012d, 0x42 },
+ { 0x800137, 0x00 },
+ { 0x80013b, 0x05 },
+ { 0x80013f, 0x5b },
+ { 0x800141, 0x59 },
+ { 0x800142, 0xf9 },
+ { 0x800143, 0x59 },
+ { 0x800144, 0x01 },
+ { 0x800145, 0x8c },
+ { 0x800146, 0x8c },
+ { 0x800147, 0x8c },
+ { 0x800148, 0x7b },
+ { 0x800149, 0x8c },
+ { 0x80014a, 0x50 },
+ { 0x80014b, 0x8c },
+ { 0x80014d, 0xa8 },
+ { 0x80014e, 0xc6 },
+ { 0x80014f, 0x03 },
+ { 0x800151, 0x28 },
+ { 0x800153, 0xcc },
+ { 0x800178, 0x09 },
+ { 0x800181, 0x9c },
+ { 0x800182, 0x76 },
+ { 0x800185, 0x28 },
+ { 0x800189, 0xaa },
+ { 0x80018c, 0x03 },
+ { 0x80018d, 0x5f },
+ { 0x80018f, 0xfb },
+ { 0x800190, 0x5c },
+ { 0x80ed02, 0xff },
+ { 0x80ee42, 0xff },
+ { 0x80ee82, 0xff },
+ { 0x80f000, 0x0f },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* ITE Tech IT9135 Omega v2 LNA config 2 tuner init
+ AF9033_TUNER_IT9135_62 = 0x62 */
+static const struct reg_val tuner_init_it9135_62[] = {
+ { 0x800043, 0x00 },
+ { 0x800046, 0x62 },
+ { 0x800051, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x0a },
+ { 0x80006a, 0x03 },
+ { 0x800070, 0x0a },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800075, 0x8c },
+ { 0x800076, 0x8c },
+ { 0x800077, 0x8c },
+ { 0x800078, 0x8c },
+ { 0x800079, 0x01 },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x800082, 0x12 },
+ { 0x800084, 0x0a },
+ { 0x800085, 0x33 },
+ { 0x800086, 0xb8 },
+ { 0x800087, 0x9c },
+ { 0x800088, 0xb2 },
+ { 0x800089, 0xa6 },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x800099, 0x01 },
+ { 0x80009b, 0x3c },
+ { 0x80009c, 0x28 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a4, 0x5a },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000b3, 0x02 },
+ { 0x8000b4, 0x3a },
+ { 0x8000b6, 0x14 },
+ { 0x8000c0, 0x11 },
+ { 0x8000c1, 0x00 },
+ { 0x8000c2, 0x05 },
+ { 0x8000c3, 0x01 },
+ { 0x8000c4, 0x00 },
+ { 0x8000c6, 0x19 },
+ { 0x8000c7, 0x00 },
+ { 0x8000cb, 0x32 },
+ { 0x8000cc, 0x2c },
+ { 0x8000cd, 0x4f },
+ { 0x8000ce, 0x30 },
+ { 0x8000f3, 0x05 },
+ { 0x8000f4, 0x8c },
+ { 0x8000f5, 0x8c },
+ { 0x8000f8, 0x03 },
+ { 0x8000f9, 0x06 },
+ { 0x8000fa, 0x06 },
+ { 0x8000fc, 0x02 },
+ { 0x8000fd, 0x03 },
+ { 0x8000fe, 0x02 },
+ { 0x8000ff, 0x09 },
+ { 0x800100, 0x50 },
+ { 0x800101, 0x6e },
+ { 0x800102, 0x8c },
+ { 0x800103, 0x02 },
+ { 0x800104, 0x02 },
+ { 0x800105, 0xc2 },
+ { 0x800106, 0x00 },
+ { 0x800109, 0x02 },
+ { 0x800115, 0x0a },
+ { 0x800116, 0x03 },
+ { 0x80011a, 0xb8 },
+ { 0x800124, 0xa8 },
+ { 0x800127, 0x00 },
+ { 0x80012a, 0x53 },
+ { 0x80012b, 0x51 },
+ { 0x80012c, 0x4e },
+ { 0x80012d, 0x43 },
+ { 0x800137, 0x00 },
+ { 0x80013b, 0x05 },
+ { 0x80013f, 0x5b },
+ { 0x800141, 0x59 },
+ { 0x800142, 0xf9 },
+ { 0x800143, 0x59 },
+ { 0x800144, 0x00 },
+ { 0x800145, 0x8c },
+ { 0x800146, 0x8c },
+ { 0x800147, 0x8c },
+ { 0x800148, 0x7b },
+ { 0x800149, 0x8c },
+ { 0x80014a, 0x50 },
+ { 0x80014b, 0x70 },
+ { 0x80014d, 0x96 },
+ { 0x80014e, 0xd0 },
+ { 0x80014f, 0x03 },
+ { 0x800151, 0x28 },
+ { 0x800153, 0xb2 },
+ { 0x800178, 0x09 },
+ { 0x800181, 0x9c },
+ { 0x800182, 0x6e },
+ { 0x800185, 0x24 },
+ { 0x800189, 0xb8 },
+ { 0x80018c, 0x03 },
+ { 0x80018d, 0x5f },
+ { 0x80018f, 0xfb },
+ { 0x800190, 0x5a },
+ { 0x80ed02, 0xff },
+ { 0x80ee42, 0xff },
+ { 0x80ee82, 0xff },
+ { 0x80f000, 0x0f },
+ { 0x80f01f, 0x8c },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x8c },
+ { 0x80f02a, 0x00 },
+ { 0x80f02b, 0x00 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f077, 0x01 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f24c, 0x88 },
+ { 0x80f24d, 0x95 },
+ { 0x80f24e, 0x9a },
+ { 0x80f24f, 0x90 },
+ { 0x80f25a, 0x07 },
+ { 0x80f25b, 0xe8 },
+ { 0x80f25c, 0x03 },
+ { 0x80f25d, 0xb0 },
+ { 0x80f25e, 0x04 },
+ { 0x80f270, 0x01 },
+ { 0x80f271, 0x02 },
+ { 0x80f272, 0x01 },
+ { 0x80f273, 0x02 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+#endif /* AF9033_PRIV_H */
diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h
index 024273374bd8..8e0ac98f8d08 100644
--- a/drivers/media/dvb-frontends/atbm8830.h
+++ b/drivers/media/dvb-frontends/atbm8830.h
@@ -22,6 +22,7 @@
#ifndef __ATBM8830_H__
#define __ATBM8830_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
@@ -60,8 +61,7 @@ struct atbm8830_config {
u8 agc_hold_loop;
};
-#if defined(CONFIG_DVB_ATBM8830) || \
- (defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ATBM8830)
extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
index 565dcf31af57..83fe9a615619 100644
--- a/drivers/media/dvb-frontends/au8522.h
+++ b/drivers/media/dvb-frontends/au8522.h
@@ -22,6 +22,7 @@
#ifndef __AU8522_H__
#define __AU8522_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
enum au8522_if_freq {
@@ -60,8 +61,7 @@ struct au8522_config {
enum au8522_if_freq qam_if;
};
-#if defined(CONFIG_DVB_AU8522) || \
- (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_AU8522_DTV)
extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index 5243ba6295cc..2099f21e374d 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -229,15 +229,11 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
/* Provide reasonable defaults for picture tuning values */
au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07);
au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed);
- state->brightness = 0xed - 128;
au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79);
- state->contrast = 0x79;
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
- state->saturation = 0x80;
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
- state->hue = 0x00;
/* Other decoder registers */
au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
@@ -489,75 +485,32 @@ static void set_audio_input(struct au8522_state *state, int aud_input)
/* ----------------------------------------------------------------------- */
-static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int au8522_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct au8522_state *state = to_state(sd);
+ struct au8522_state *state =
+ container_of(ctrl->handler, struct au8522_state, hdl);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- state->brightness = ctrl->value;
au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH,
- ctrl->value - 128);
+ ctrl->val - 128);
break;
case V4L2_CID_CONTRAST:
- state->contrast = ctrl->value;
au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH,
- ctrl->value);
+ ctrl->val);
break;
case V4L2_CID_SATURATION:
- state->saturation = ctrl->value;
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
- ctrl->value);
+ ctrl->val);
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
- ctrl->value);
+ ctrl->val);
break;
case V4L2_CID_HUE:
- state->hue = ctrl->value;
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
- ctrl->value >> 8);
+ ctrl->val >> 8);
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
- ctrl->value & 0xFF);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- /* Not yet implemented */
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct au8522_state *state = to_state(sd);
-
- /* Note that we are using values cached in the state structure instead
- of reading the registers due to issues with i2c reads not working
- properly/consistently yet on the HVR-950q */
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = state->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = state->contrast;
+ ctrl->val & 0xFF);
break;
- case V4L2_CID_SATURATION:
- ctrl->value = state->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = state->hue;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- /* Not yet supported */
default:
return -EINVAL;
}
@@ -583,7 +536,7 @@ static int au8522_g_register(struct v4l2_subdev *sd,
}
static int au8522_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct au8522_state *state = to_state(sd);
@@ -616,26 +569,6 @@ static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1,
- AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
- default:
- break;
- }
-
- qc->type = 0;
- return -EINVAL;
-}
-
static int au8522_reset(struct v4l2_subdev *sd, u32 val)
{
struct au8522_state *state = to_state(sd);
@@ -712,20 +645,11 @@ static int au8522_g_chip_ident(struct v4l2_subdev *sd,
return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev);
}
-static int au8522_log_status(struct v4l2_subdev *sd)
-{
- /* FIXME: Add some status info here */
- return 0;
-}
-
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops au8522_core_ops = {
- .log_status = au8522_log_status,
+ .log_status = v4l2_ctrl_subdev_log_status,
.g_chip_ident = au8522_g_chip_ident,
- .g_ctrl = au8522_g_ctrl,
- .s_ctrl = au8522_s_ctrl,
- .queryctrl = au8522_queryctrl,
.reset = au8522_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = au8522_g_register,
@@ -753,12 +677,17 @@ static const struct v4l2_subdev_ops au8522_ops = {
.video = &au8522_video_ops,
};
+static const struct v4l2_ctrl_ops au8522_ctrl_ops = {
+ .s_ctrl = au8522_s_ctrl,
+};
+
/* ----------------------------------------------------------------------- */
static int au8522_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct au8522_state *state;
+ struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
int instance;
struct au8522_config *demod_config;
@@ -799,6 +728,27 @@ static int au8522_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &au8522_ops);
+ hdl = &state->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 109);
+ v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1,
+ AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
+ v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops,
+ V4L2_CID_HUE, -32768, 32767, 1, 0);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(demod_config);
+ kfree(state);
+ return err;
+ }
+
state->c = client;
state->vid_input = AU8522_COMPOSITE_CH1;
state->aud_input = AU8522_AUDIO_NONE;
@@ -815,6 +765,7 @@ static int au8522_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
au8522_release_state(to_state(sd));
return 0;
}
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index 0529699a27bd..aa0f16d6b610 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
#include "au8522.h"
@@ -65,10 +66,7 @@ struct au8522_state {
int aud_input;
u32 id;
u32 rev;
- u8 brightness;
- u8 contrast;
- u8 saturation;
- s16 hue;
+ struct v4l2_ctrl_handler hdl;
};
/* These are routines shared by both the VSB/QAM demodulator and the analog
diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h
index f154e1f428eb..0b1a6c2f9d5f 100644
--- a/drivers/media/dvb-frontends/cx22702.h
+++ b/drivers/media/dvb-frontends/cx22702.h
@@ -28,6 +28,7 @@
#ifndef CX22702_H
#define CX22702_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct cx22702_config {
@@ -40,8 +41,7 @@ struct cx22702_config {
u8 output_mode;
};
-#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX22702)
extern struct dvb_frontend *cx22702_attach(
const struct cx22702_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h
index 01eb7b9c28f4..782711ba1a32 100644
--- a/drivers/media/dvb-frontends/cx24113.h
+++ b/drivers/media/dvb-frontends/cx24113.h
@@ -22,6 +22,8 @@
#ifndef CX24113_H
#define CX24113_H
+#include <linux/kconfig.h>
+
struct dvb_frontend;
struct cx24113_config {
@@ -30,8 +32,7 @@ struct cx24113_config {
u32 xtal_khz;
};
-#if defined(CONFIG_DVB_TUNER_CX24113) || \
- (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TUNER_CX24113)
extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *,
const struct cx24113_config *config, struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h
index 7d90ab949c03..2ec84fae3f9f 100644
--- a/drivers/media/dvb-frontends/cx24116.h
+++ b/drivers/media/dvb-frontends/cx24116.h
@@ -21,6 +21,7 @@
#ifndef CX24116_H
#define CX24116_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct cx24116_config {
@@ -40,8 +41,7 @@ struct cx24116_config {
u16 i2c_wr_max;
};
-#if defined(CONFIG_DVB_CX24116) || \
- (defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX24116)
extern struct dvb_frontend *cx24116_attach(
const struct cx24116_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c
index 68c88ab58e71..a771da3e9f99 100644
--- a/drivers/media/dvb-frontends/cx24123.c
+++ b/drivers/media/dvb-frontends/cx24123.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <asm/div64.h>
#include "dvb_frontend.h"
#include "cx24123.h"
@@ -452,7 +453,8 @@ static u32 cx24123_int_log2(u32 a, u32 b)
static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
{
- u32 tmp, sample_rate, ratio, sample_gain;
+ u64 tmp;
+ u32 sample_rate, ratio, sample_gain;
u8 pll_mult;
/* check if symbol rate is within limits */
@@ -482,27 +484,11 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate)
sample_rate = pll_mult * XTAL;
- /*
- SYSSymbolRate[21:0] = (srate << 23) / sample_rate
-
- We have to use 32 bit unsigned arithmetic without precision loss.
- The maximum srate is 45000000 or 0x02AEA540. This number has
- only 6 clear bits on top, hence we can shift it left only 6 bits
- at a time. Borrowed from cx24110.c
- */
-
- tmp = srate << 6;
- ratio = tmp / sample_rate;
-
- tmp = (tmp % sample_rate) << 6;
- ratio = (ratio << 6) + (tmp / sample_rate);
-
- tmp = (tmp % sample_rate) << 6;
- ratio = (ratio << 6) + (tmp / sample_rate);
-
- tmp = (tmp % sample_rate) << 5;
- ratio = (ratio << 5) + (tmp / sample_rate);
+ /* SYSSymbolRate[21:0] = (srate << 23) / sample_rate */
+ tmp = ((u64)srate) << 23;
+ do_div(tmp, sample_rate);
+ ratio = (u32) tmp;
cx24123_writereg(state, 0x01, pll_mult * 6);
diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h
index 51ae866e9fed..102e70d17c43 100644
--- a/drivers/media/dvb-frontends/cx24123.h
+++ b/drivers/media/dvb-frontends/cx24123.h
@@ -21,6 +21,7 @@
#ifndef CX24123_H
#define CX24123_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct cx24123_config {
@@ -38,8 +39,7 @@ struct cx24123_config {
void (*agc_callback) (struct dvb_frontend *);
};
-#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CX24123)
extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index 6acc21c581c5..82b3d93718f8 100644
--- a/drivers/media/dvb-frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -22,6 +22,7 @@
#ifndef CXD2820R_H
#define CXD2820R_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#define CXD2820R_GPIO_D (0 << 0) /* disable */
@@ -65,8 +66,7 @@ struct cxd2820r_config {
};
-#if defined(CONFIG_DVB_CXD2820R) || \
- (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_CXD2820R)
extern struct dvb_frontend *cxd2820r_attach(
const struct cxd2820r_config *config,
struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c
index 9b658c1cf39a..7ca5c69dd200 100644
--- a/drivers/media/dvb-frontends/cxd2820r_core.c
+++ b/drivers/media/dvb-frontends/cxd2820r_core.c
@@ -660,7 +660,8 @@ static const struct dvb_frontend_ops cxd2820r_ops = {
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_MUTE_TS |
- FE_CAN_2G_MODULATION
+ FE_CAN_2G_MODULATION |
+ FE_CAN_MULTISTREAM
},
.release = cxd2820r_release,
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
index e82d82a7a2eb..2ba130e245b6 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
@@ -124,6 +124,23 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
buf[1] = ((if_ctl >> 8) & 0xff);
buf[2] = ((if_ctl >> 0) & 0xff);
+ /* PLP filtering */
+ if (c->stream_id > 255) {
+ dev_dbg(&priv->i2c->dev, "%s: Disable PLP filtering\n", __func__);
+ ret = cxd2820r_wr_reg(priv, 0x023ad , 0);
+ if (ret)
+ goto error;
+ } else {
+ dev_dbg(&priv->i2c->dev, "%s: Enable PLP filtering = %d\n", __func__,
+ c->stream_id);
+ ret = cxd2820r_wr_reg(priv, 0x023af , c->stream_id & 0xFF);
+ if (ret)
+ goto error;
+ ret = cxd2820r_wr_reg(priv, 0x023ad , 1);
+ if (ret)
+ goto error;
+ }
+
ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
if (ret)
goto error;
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index d9fe60b4be48..3ee22ff76315 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -528,20 +528,19 @@ static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_
u16 PllCfg, i, v;
HARD_RESET(state);
-
dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL);
- dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
+ if (cfg->in_soc)
+ return;
- if (!cfg->in_soc) {
- /* adcClkOutRatio=8->7, release reset */
- dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
- if (cfg->clkoutdrive != 0)
- dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
- | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
- else
- dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
- | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
- }
+ dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */
+ /* adcClkOutRatio=8->7, release reset */
+ dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0);
+ if (cfg->clkoutdrive != 0)
+ dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+ | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
+ else
+ dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8)
+ | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0));
/* Read Pll current config * */
PllCfg = dib0090_read_reg(state, 0x21);
@@ -694,192 +693,174 @@ void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast)
EXPORT_SYMBOL(dib0090_dcc_freq);
static const u16 bb_ramp_pwm_normal_socs[] = {
- 550, /* max BB gain in 10th of dB */
- (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 550, /* max BB gain in 10th of dB */
+ (1<<9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
440,
- (4 << 9) | 0, /* BB_RAMP3 = 26dB */
- (0 << 9) | 208, /* BB_RAMP4 */
- (4 << 9) | 208, /* BB_RAMP5 = 29dB */
- (0 << 9) | 440, /* BB_RAMP6 */
+ (4 << 9) | 0, /* BB_RAMP3 = 26dB */
+ (0 << 9) | 208, /* BB_RAMP4 */
+ (4 << 9) | 208, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 440, /* BB_RAMP6 */
};
-static const u16 rf_ramp_pwm_cband_7090[] = {
- 280, /* max RF gain in 10th of dB */
- 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 504, /* ramp_max = maximum X used on the ramp */
- (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
- (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
- (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
- (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
- (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
- (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
- (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
- (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
+static const u16 rf_ramp_pwm_cband_7090p[] = {
+ 280, /* max RF gain in 10th of dB */
+ 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 504, /* ramp_max = maximum X used on the ramp */
+ (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */
+ (0 << 10) | 504, /* RF_RAMP6, LNA 1 */
+ (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */
+ (0 << 10) | 364, /* RF_RAMP8, LNA 2 */
+ (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */
+ (0 << 10) | 228, /* GAIN_4_2, LNA 3 */
+ (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */
+ (0 << 10) | 109, /* RF_RAMP4, LNA 4 */
};
-static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = {
- 186,
- 40,
- 746,
- (10 << 10) | 345,
- (0 << 10) | 746,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (28 << 10) | 200,
- (0 << 10) | 345,
- (20 << 10) | 0,
- (0 << 10) | 200,
+static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = {
+ 186, /* max RF gain in 10th of dB */
+ 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 746, /* ramp_max = maximum X used on the ramp */
+ (10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */
+ (0 << 10) | 746, /* RF_RAMP6, LNA 1 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
+ (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
+ (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
+ (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
+ (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
};
-static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = {
- 86,
- 40,
- 345,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (0 << 10) | 0,
- (28 << 10) | 200,
- (0 << 10) | 345,
- (20 << 10) | 0,
- (0 << 10) | 200,
+static const u16 rf_ramp_pwm_cband_7090e_aci[] = {
+ 86, /* max RF gain in 10th of dB */
+ 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 345, /* ramp_max = maximum X used on the ramp */
+ (0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */
+ (0 << 10) | 0, /* RF_RAMP6, LNA 1 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 2 */
+ (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */
+ (0 << 10) | 345, /* GAIN_4_2, LNA 3 */
+ (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */
+ (0 << 10) | 200, /* RF_RAMP4, LNA 4 */
};
static const u16 rf_ramp_pwm_cband_8090[] = {
- 345, /* max RF gain in 10th of dB */
- 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 1000, /* ramp_max = maximum X used on the ramp */
- (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
- (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
- (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
- (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
- (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
- (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
- (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
- (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
+ 345, /* max RF gain in 10th of dB */
+ 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1000, /* ramp_max = maximum X used on the ramp */
+ (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */
+ (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */
+ (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */
+ (0 << 10) | 772, /* RF_RAMP6, LNA 2 */
+ (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */
+ (0 << 10) | 496, /* RF_RAMP8, LNA 3 */
+ (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */
+ (0 << 10) | 200, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf_7090[] = {
- 407, /* max RF gain in 10th of dB */
- 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 529, /* ramp_max = maximum X used on the ramp */
- (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
- (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
- (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
- (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
- (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
- (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
- (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
- (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
+ 407, /* max RF gain in 10th of dB */
+ 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 529, /* ramp_max = maximum X used on the ramp */
+ (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
+ (0 << 10) | 176, /* RF_RAMP4, LNA 1 */
+ (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */
+ (0 << 10) | 529, /* RF_RAMP6, LNA 2 */
+ (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */
+ (0 << 10) | 400, /* RF_RAMP8, LNA 3 */
+ (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */
+ (0 << 10) | 316, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf_8090[] = {
- 388, /* max RF gain in 10th of dB */
- 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
- 1008, /* ramp_max = maximum X used on the ramp */
- (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
- (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
- (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
- (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
- (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
- (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
- (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
- (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
+ 388, /* max RF gain in 10th of dB */
+ 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1008, /* ramp_max = maximum X used on the ramp */
+ (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */
+ (0 << 10) | 369, /* RF_RAMP4, LNA 1 */
+ (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */
+ (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */
+ (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */
+ (0 << 10) | 809, /* RF_RAMP8, LNA 3 */
+ (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */
+ (0 << 10) | 659, /* GAIN_4_2, LNA 4 */
};
-static const u16 rf_ramp_pwm_cband[] = {
- 0, /* max RF gain in 10th of dB */
- 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 0, /* ramp_max = maximum X used on the ramp */
- (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */
- (0 << 10) | 0, /* 0x2d, LNA 1 */
- (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */
- (0 << 10) | 0, /* 0x2f, LNA 2 */
- (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */
- (0 << 10) | 0, /* 0x31, LNA 3 */
- (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
- (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
-};
-
-static const u16 rf_ramp_vhf[] = {
- 412, /* max RF gain in 10th of dB */
- 132, 307, 127, /* LNA1, 13.2dB */
- 105, 412, 255, /* LNA2, 10.5dB */
- 50, 50, 127, /* LNA3, 5dB */
- 125, 175, 127, /* LNA4, 12.5dB */
- 0, 0, 127, /* CBAND, 0dB */
-};
-
-static const u16 rf_ramp_uhf[] = {
- 412, /* max RF gain in 10th of dB */
- 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */
- 105, 412, 255, /* LNA2 : 10.5 dB */
- 50, 50, 127, /* LNA3 : 5.0 dB */
- 125, 175, 127, /* LNA4 : 12.5 dB */
- 0, 0, 127, /* CBAND : 0.0 dB */
+/* GENERAL PWM ramp definition for all other Krosus */
+static const u16 bb_ramp_pwm_normal[] = {
+ 500, /* max BB gain in 10th of dB */
+ 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 400,
+ (2 << 9) | 0, /* BB_RAMP3 = 21dB */
+ (0 << 9) | 168, /* BB_RAMP4 */
+ (2 << 9) | 168, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 400, /* BB_RAMP6 */
};
-static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */
-{
- 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */
- 84, 314, 127, /* LNA1 */
- 80, 230, 255, /* LNA2 */
- 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */
- 70, 70, 127, /* LNA4 */
- 0, 0, 127, /* CBAND */
+static const u16 bb_ramp_pwm_boost[] = {
+ 550, /* max BB gain in 10th of dB */
+ 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */
+ 440,
+ (2 << 9) | 0, /* BB_RAMP3 = 26dB */
+ (0 << 9) | 208, /* BB_RAMP4 */
+ (2 << 9) | 208, /* BB_RAMP5 = 29dB */
+ (0 << 9) | 440, /* BB_RAMP6 */
};
-static const u16 rf_ramp_cband[] = {
- 332, /* max RF gain in 10th of dB */
- 132, 252, 127, /* LNA1, dB */
- 80, 332, 255, /* LNA2, dB */
- 0, 0, 127, /* LNA3, dB */
- 0, 0, 127, /* LNA4, dB */
- 120, 120, 127, /* LT1 CBAND */
+static const u16 rf_ramp_pwm_cband[] = {
+ 314, /* max RF gain in 10th of dB */
+ 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 1023, /* ramp_max = maximum X used on the ramp */
+ (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */
+ (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */
+ (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */
+ (0 << 10) | 742, /* RF_RAMP6, LNA 2 */
+ (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */
+ (0 << 10) | 468, /* RF_RAMP8, LNA 3 */
+ (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
+ (0 << 10) | 233, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_vhf[] = {
- 404, /* max RF gain in 10th of dB */
- 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 1011, /* ramp_max = maximum X used on the ramp */
- (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
- (0 << 10) | 756, /* 0x2d, LNA 1 */
- (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
- (0 << 10) | 1011, /* 0x2f, LNA 2 */
- (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */
- (0 << 10) | 417, /* 0x31, LNA 3 */
- (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */
- (0 << 10) | 290, /* GAIN_4_2, LNA 4 */
+ 398, /* max RF gain in 10th of dB */
+ 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 954, /* ramp_max = maximum X used on the ramp */
+ (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
+ (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
+ (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
+ (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
+ (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
+ (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
+ (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
+ (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
};
static const u16 rf_ramp_pwm_uhf[] = {
- 404, /* max RF gain in 10th of dB */
- 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */
- 1011, /* ramp_max = maximum X used on the ramp */
- (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */
- (0 << 10) | 756, /* 0x2d, LNA 1 */
- (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */
- (0 << 10) | 1011, /* 0x2f, LNA 2 */
- (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */
- (0 << 10) | 127, /* 0x31, LNA 3 */
- (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */
- (0 << 10) | 417, /* GAIN_4_2, LNA 4 */
+ 398, /* max RF gain in 10th of dB */
+ 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 954, /* ramp_max = maximum X used on the ramp */
+ (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */
+ (0 << 10) | 290, /* RF_RAMP4, LNA 1 */
+ (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */
+ (0 << 10) | 954, /* RF_RAMP6, LNA 2 */
+ (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */
+ (0 << 10) | 699, /* RF_RAMP8, LNA 3 */
+ (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */
+ (0 << 10) | 580, /* GAIN_4_2, LNA 4 */
};
-static const u16 bb_ramp_boost[] = {
- 550, /* max BB gain in 10th of dB */
- 260, 260, 26, /* BB1, 26dB */
- 290, 550, 29, /* BB2, 29dB */
-};
-
-static const u16 bb_ramp_pwm_normal[] = {
- 500, /* max RF gain in 10th of dB */
- 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */
- 400,
- (2 << 9) | 0, /* 0x35 = 21dB */
- (0 << 9) | 168, /* 0x36 */
- (2 << 9) | 168, /* 0x37 = 29dB */
- (0 << 9) | 400, /* 0x38 */
+static const u16 rf_ramp_pwm_sband[] = {
+ 253, /* max RF gain in 10th of dB */
+ 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */
+ 961,
+ (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */
+ (0 << 10) | 508, /* RF_RAMP4, LNA 1 */
+ (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */
+ (0 << 10) | 961, /* RF_RAMP6, LNA 2 */
+ (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */
+ (0 << 10) | 0, /* RF_RAMP8, LNA 3 */
+ (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */
+ (0 << 10) | 0, /* GAIN_4_2, LNA 4 */
};
struct slope {
@@ -1089,70 +1070,69 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
{
struct dib0090_state *state = fe->tuner_priv;
- /* reset the AGC */
+ u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
+ u16 *rf_ramp = NULL;
+ u8 en_pwm_rf_mux = 1;
+ /* reset the AGC */
if (state->config->use_pwm_agc) {
-#ifdef CONFIG_BAND_SBAND
- if (state->current_band == BAND_SBAND) {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost);
- } else
-#endif
-#ifdef CONFIG_BAND_CBAND
if (state->current_band == BAND_CBAND) {
if (state->identity.in_soc) {
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090);
- else if (state->identity.version == SOC_7090_P1G_11R1
- || state->identity.version == SOC_7090_P1G_21R1) {
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
+ else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
if (state->config->is_dib7090e) {
if (state->rf_ramp == NULL)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity);
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
else
- dib0090_set_rframp_pwm(state, state->rf_ramp);
+ rf_ramp = (u16 *)state->rf_ramp;
} else
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090);
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
}
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
- }
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_cband;
} else
-#endif
-#ifdef CONFIG_BAND_VHF
- if (state->current_band == BAND_VHF) {
- if (state->identity.in_soc) {
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
+
+ if (state->current_band == BAND_VHF) {
+ if (state->identity.in_soc) {
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+ /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
+ } else if (state->current_band == BAND_UHF) {
+ if (state->identity.in_soc) {
+ bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
+ if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
+ else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
+ } else
+ rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
}
+ if (rf_ramp)
+ dib0090_set_rframp_pwm(state, rf_ramp);
+ dib0090_set_bbramp_pwm(state, bb_ramp);
+
+ /* activate the ramp generator using PWM control */
+ dprintk("ramp RF gain = %d BAND = %s version = %d", state->rf_ramp[0], (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", state->identity.version & 0x1f);
+
+ if ((state->rf_ramp[0] == 0) || (state->current_band == BAND_CBAND && (state->identity.version & 0x1f) <= P1D_E_F)) {
+ dprintk("DE-Engage mux for direct gain reg control");
+ en_pwm_rf_mux = 0;
} else
-#endif
- {
- if (state->identity.in_soc) {
- if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090);
- else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs);
- } else {
- dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf);
- dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal);
- }
- }
+ dprintk("Engage mux for PWM control");
- if (state->rf_ramp[0] != 0)
- dib0090_write_reg(state, 0x32, (3 << 11));
- else
- dib0090_write_reg(state, 0x32, (0 << 11));
+ dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11));
- dib0090_write_reg(state, 0x04, 0x03);
- dib0090_write_reg(state, 0x39, (1 << 10));
+ /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/
+ if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
+ dib0090_write_reg(state, 0x04, 3);
+ else
+ dib0090_write_reg(state, 0x04, 1);
+ dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */
}
}
-
EXPORT_SYMBOL(dib0090_pwm_gain_reset);
void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff)
@@ -1193,22 +1173,22 @@ int dib0090_gain_control(struct dvb_frontend *fe)
#endif
#ifdef CONFIG_BAND_VHF
if (state->current_band == BAND_VHF && !state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_vhf);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_vhf);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
} else
#endif
#ifdef CONFIG_BAND_CBAND
if (state->current_band == BAND_CBAND && !state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_cband);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_cband);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
} else
#endif
if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) {
- dib0090_set_rframp(state, rf_ramp_cband_broadmatching);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs);
} else {
- dib0090_set_rframp(state, rf_ramp_uhf);
- dib0090_set_bbramp(state, bb_ramp_boost);
+ dib0090_set_rframp(state, rf_ramp_pwm_uhf);
+ dib0090_set_bbramp(state, bb_ramp_pwm_normal);
}
dib0090_write_reg(state, 0x32, 0);
@@ -1553,14 +1533,16 @@ static void dib0090_set_EFUSE(struct dib0090_state *state)
if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN))
c = 32;
+ else
+ c += 14;
if ((h >= HR_MAX) || (h <= HR_MIN))
h = 34;
if ((n >= POLY_MAX) || (n <= POLY_MIN))
n = 3;
- dib0090_write_reg(state, 0x13, (h << 10)) ;
- e2 = (n<<11) | ((h>>2)<<6) | (c);
- dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */
+ dib0090_write_reg(state, 0x13, (h << 10));
+ e2 = (n << 11) | ((h >> 2)<<6) | c;
+ dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */
}
}
diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h
index d75ffad2d752..129d1425516a 100644
--- a/drivers/media/dvb-frontends/dib3000mc.h
+++ b/drivers/media/dvb-frontends/dib3000mc.h
@@ -13,6 +13,8 @@
#ifndef DIB3000MC_H
#define DIB3000MC_H
+#include <linux/kconfig.h>
+
#include "dibx000_common.h"
struct dib3000mc_config {
@@ -39,8 +41,7 @@ struct dib3000mc_config {
#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
#define DEFAULT_DIB3000P_I2C_ADDRESS 24
-#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap,
u8 i2c_addr,
struct dib3000mc_config *cfg);
diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h
index 81fcf2241c64..b585413f9a29 100644
--- a/drivers/media/dvb-frontends/dib7000m.h
+++ b/drivers/media/dvb-frontends/dib7000m.h
@@ -1,6 +1,8 @@
#ifndef DIB7000M_H
#define DIB7000M_H
+#include <linux/kconfig.h>
+
#include "dibx000_common.h"
struct dib7000m_config {
@@ -38,8 +40,7 @@ struct dib7000m_config {
#define DEFAULT_DIB7000M_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB7000M)
extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap,
u8 i2c_addr,
struct dib7000m_config *cfg);
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 3e1eefada0e8..effb87f773b0 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -429,6 +429,13 @@ int dib7000p_get_agc_values(struct dvb_frontend *fe,
}
EXPORT_SYMBOL(dib7000p_get_agc_values);
+int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+{
+ struct dib7000p_state *state = fe->demodulator_priv;
+ return dib7000p_write_word(state, 108, v);
+}
+EXPORT_SYMBOL(dib7000p_set_agc1_min);
+
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
@@ -821,6 +828,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod)
u8 agc_split;
u16 reg;
u32 upd_demod_gain_period = 0x1000;
+ s32 frequency_offset = 0;
switch (state->agc_state) {
case 0:
@@ -841,7 +849,14 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod)
if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0)
return -1;
- dib7000p_set_dds(state, 0);
+ if (demod->ops.tuner_ops.get_frequency) {
+ u32 frequency_tuner;
+
+ demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner);
+ frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000;
+ }
+
+ dib7000p_set_dds(state, frequency_offset);
ret = 7;
(*agc_state)++;
break;
diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
index b61b03a6e1ed..d08cdff59bdf 100644
--- a/drivers/media/dvb-frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -1,6 +1,8 @@
#ifndef DIB7000P_H
#define DIB7000P_H
+#include <linux/kconfig.h>
+
#include "dibx000_common.h"
struct dib7000p_config {
@@ -44,8 +46,7 @@ struct dib7000p_config {
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
-#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB7000P)
extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
@@ -62,6 +63,7 @@ extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
extern int dib7090_slave_reset(struct dvb_frontend *fe);
extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
+extern int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v);
#else
static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
{
@@ -153,6 +155,12 @@ static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
}
+
+static inline int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return -ENODEV;
+}
#endif
#endif
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 1f3bcb5a1de8..a54182dd0e91 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -23,8 +23,8 @@
#define LAYER_B 2
#define LAYER_C 3
-#define FE_CALLBACK_TIME_NEVER 0xffffffff
#define MAX_NUMBER_OF_FRONTENDS 6
+/* #define DIB8000_AGC_FREEZE */
static int debug;
module_param(debug, int, 0644);
@@ -32,8 +32,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0)
-#define FE_STATUS_TUNE_FAILED 0
-
struct i2c_device {
struct i2c_adapter *adap;
u8 addr;
@@ -42,6 +40,23 @@ struct i2c_device {
struct mutex *i2c_buffer_lock;
};
+enum param_loop_step {
+ LOOP_TUNE_1,
+ LOOP_TUNE_2
+};
+
+enum dib8000_autosearch_step {
+ AS_START = 0,
+ AS_SEARCHING_FFT,
+ AS_SEARCHING_GUARD,
+ AS_DONE = 100,
+};
+
+enum timeout_mode {
+ SYMBOL_DEPENDENT_OFF = 0,
+ SYMBOL_DEPENDENT_ON,
+};
+
struct dib8000_state {
struct dib8000_config cfg;
@@ -72,7 +87,7 @@ struct dib8000_state {
u16 revision;
u8 isdbt_cfg_loaded;
enum frontend_tune_state tune_state;
- u32 status;
+ s32 status;
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
@@ -85,6 +100,30 @@ struct dib8000_state {
u16 tuner_enable;
struct i2c_adapter dib8096p_tuner_adap;
+ u16 current_demod_bw;
+
+ u16 seg_mask;
+ u16 seg_diff_mask;
+ u16 mode;
+ u8 layer_b_nb_seg;
+ u8 layer_c_nb_seg;
+
+ u8 channel_parameters_set;
+ u16 autosearch_state;
+ u16 found_nfft;
+ u16 found_guard;
+ u8 subchannel;
+ u8 symbol_duration;
+ u32 timeout;
+ u8 longest_intlv_layer;
+ u16 output_mode;
+
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1_max;
+ u16 agc1_min;
+ u16 agc2_max;
+ u16 agc2_min;
+#endif
};
enum dib8000_power_mode {
@@ -338,9 +377,9 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state)
static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
{
struct dib8000_state *state = fe->demodulator_priv;
-
u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */
+ state->output_mode = mode;
outreg = 0;
fifo_threshold = 1792;
smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1);
@@ -399,8 +438,9 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode)
static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
{
struct dib8000_state *state = fe->demodulator_priv;
- u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0;
+ dprintk("set diversity input to %i", onoff);
if (!state->differential_constellation) {
dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1
dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2
@@ -424,6 +464,13 @@ static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff)
dib8000_write_word(state, 271, 1);
break;
}
+
+ if (state->revision == 0x8002) {
+ tmp = dib8000_read_word(state, 903);
+ dib8000_write_word(state, 903, tmp & ~(1 << 3));
+ msleep(30);
+ dib8000_write_word(state, 903, tmp | (1 << 3));
+ }
return 0;
}
@@ -468,27 +515,6 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow
dib8000_write_word(state, 1280, reg_1280);
}
-static int dib8000_init_sdram(struct dib8000_state *state)
-{
- u16 reg = 0;
- dprintk("Init sdram");
-
- reg = dib8000_read_word(state, 274)&0xfff0;
- /* P_dintlv_delay_ram = 7 because of MobileSdram */
- dib8000_write_word(state, 274, reg | 0x7);
-
- dib8000_write_word(state, 1803, (7<<2));
-
- reg = dib8000_read_word(state, 1280);
- /* force restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg | (1<<2));
-
- /* release restart P_restart_sdram */
- dib8000_write_word(state, 1280, reg);
-
- return 0;
-}
-
static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no)
{
int ret = 0;
@@ -584,18 +610,23 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw)
static int dib8000_sad_calib(struct dib8000_state *state)
{
+ u8 sad_sel = 3;
+
if (state->revision == 0x8090) {
- dprintk("%s: the sad calibration is not needed for the dib8096P",
- __func__);
- return 0;
- }
- /* internal */
- dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
- dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ dib8000_write_word(state, 923, 2048);
+
+ dib8000_write_word(state, 922, (sad_sel << 2) | 0x1);
+ dib8000_write_word(state, 922, (sad_sel << 2));
+ } else {
+ /* internal */
+ dib8000_write_word(state, 923, (0 << 1) | (0 << 0));
+ dib8000_write_word(state, 924, 776);
- /* do the calibration */
- dib8000_write_word(state, 923, (1 << 0));
- dib8000_write_word(state, 923, (0 << 0));
+ /* do the calibration */
+ dib8000_write_word(state, 923, (1 << 0));
+ dib8000_write_word(state, 923, (0 << 0));
+ }
msleep(1);
return 0;
@@ -609,8 +640,8 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
state->wbd_ref = value;
return dib8000_write_word(state, 106, value);
}
-
EXPORT_SYMBOL(dib8000_set_wbd_ref);
+
static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
{
dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25);
@@ -685,20 +716,23 @@ static void dib8000_reset_pll(struct dib8000_state *state)
}
int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll)
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856);
- u8 loopdiv, prediv;
+ u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ;
u32 internal, xtal;
/* get back old values */
prediv = reg_1856 & 0x3f;
loopdiv = (reg_1856 >> 6) & 0x3f;
- if ((pll != NULL) && (pll->pll_prediv != prediv ||
- pll->pll_ratio != loopdiv)) {
- dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if ((pll == NULL) || (pll->pll_prediv == prediv &&
+ pll->pll_ratio == loopdiv))
+ return -EINVAL;
+
+ dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio);
+ if (state->revision == 0x8090) {
reg_1856 &= 0xf000;
reg_1857 = dib8000_read_word(state, 1857);
/* disable PLL */
@@ -729,10 +763,33 @@ int dib8000_update_pll(struct dvb_frontend *fe,
reg_1856 = dib8000_read_word(state, 1856);
dprintk("PLL Updated with prediv = %d and loopdiv = %d",
reg_1856&0x3f, (reg_1856>>6)&0x3f);
+ } else {
+ if (bw != state->current_demod_bw) {
+ /** Bandwidth change => force PLL update **/
+ dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv);
+
+ if (state->cfg.pll->pll_prediv != oldprediv) {
+ /** Full PLL change only if prediv is changed **/
+
+ /** full update => bypass and reconfigure **/
+ dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio);
+ dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */
+ dib8000_reset_pll(state);
+ dib8000_write_word(state, 898, 0x0004); /* sad */
+ } else
+ ratio = state->cfg.pll->pll_ratio;
- return 0;
- }
- return -EINVAL;
+ state->current_demod_bw = bw;
+ }
+
+ if (ratio != 0) {
+ /** ratio update => only change ratio **/
+ dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
+ dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
+ }
+}
+
+ return 0;
}
EXPORT_SYMBOL(dib8000_update_pll);
@@ -928,7 +985,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_power_mode(state, DIB8000_POWER_ALL);
/* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */
- dib8000_set_adc_state(state, DIBX000_VBG_ENABLE);
+ dib8000_set_adc_state(state, DIBX000_ADC_OFF);
/* restart all parts */
dib8000_write_word(state, 770, 0xffff);
@@ -992,12 +1049,11 @@ static int dib8000_reset(struct dvb_frontend *fe)
l = *n++;
}
}
- if (state->revision != 0x8090)
- dib8000_write_word(state, 903, (0 << 4) | 2);
+
state->isdbt_cfg_loaded = 0;
//div_cfg override for special configs
- if (state->cfg.div_cfg != 0)
+ if ((state->revision != 8090) && (state->cfg.div_cfg != 0))
dib8000_write_word(state, 903, state->cfg.div_cfg);
/* unforce divstr regardless whether i2c enumeration was done or not */
@@ -1006,10 +1062,12 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_bandwidth(fe, 6000);
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON);
- if (state->revision != 0x8090) {
- dib8000_sad_calib(state);
+ dib8000_sad_calib(state);
+ if (state->revision != 0x8090)
dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
- }
+
+ /* ber_rs_len = 3 */
+ dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5));
dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
@@ -1441,6 +1499,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode)
u8 prefer_mpeg_mux_use = 1;
int ret = 0;
+ state->output_mode = mode;
dib8096p_host_bus_drive(state, 1);
fifo_threshold = 1792;
@@ -1879,782 +1938,643 @@ static const u16 adc_target_16dB[11] = {
};
static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
-static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
{
- u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
- u8 guard, crate, constellation, timeI;
- u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
- const s16 *ncoeff = NULL, *ana_fe;
- u16 tmcc_pow = 0;
- u16 coff_pow = 0x2800;
- u16 init_prbs = 0xfff;
- u16 ana_gain = 0;
-
- if (state->revision == 0x8090)
- dib8000_init_sdram(state);
+ u8 cr, constellation, time_intlv;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
- if (state->ber_monitored_layer != LAYER_ALL)
- dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
- else
- dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
-
- i = dib8000_read_word(state, 26) & 1; // P_dds_invspec
- dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- //compute new dds_freq for the seg and adjust prbs
- int seg_offset =
- state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) -
- (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2);
- int clk = state->cfg.pll->internal;
- u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26)
- int dds_offset = seg_offset * segtodds;
- int new_dds, sub_channel;
- if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- dds_offset -= (int)(segtodds / 2);
-
- if (state->cfg.pll->ifreq == 0) {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) {
- dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
- new_dds = dds_offset;
- } else
- new_dds = dds_offset;
-
- // We shift tuning frequency if the wanted segment is :
- // - the segment of center frequency with an odd total number of segments
- // - the segment to the left of center frequency with an even total number of segments
- // - the segment to the right of center frequency with an even total number of segments
- if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2)))
- || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0)
- && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx ==
- ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))
- )) {
- new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26)
- }
- } else {
- if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0)
- new_dds = state->cfg.pll->ifreq - dds_offset;
- else
- new_dds = state->cfg.pll->ifreq + dds_offset;
- }
- dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (new_dds & 0xffff));
- if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2)
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3;
- else
- sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3;
- sub_channel -= 6;
-
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K
- || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1
- } else {
- dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0
- dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0
- }
-
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_2K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x423;
- break; // 02~04
- case -4:
- init_prbs = 0x9;
- break; // 05~07
- case -3:
- init_prbs = 0x5C7;
- break; // 08~10
- case -2:
- init_prbs = 0x7A6;
- break; // 11~13
- case -1:
- init_prbs = 0x3D8;
- break; // 14~16
- case 0:
- init_prbs = 0x527;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x79B;
- break; // 23~25
- case 3:
- init_prbs = 0x3D6;
- break; // 26~28
- case 4:
- init_prbs = 0x3A2;
- break; // 29~31
- case 5:
- init_prbs = 0x53B;
- break; // 32~34
- case 6:
- init_prbs = 0x2F4;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x213;
- break; // 38~40
- }
- break;
-
- case TRANSMISSION_MODE_4K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x208;
- break; // 02~04
- case -4:
- init_prbs = 0xC3;
- break; // 05~07
- case -3:
- init_prbs = 0x7B9;
- break; // 08~10
- case -2:
- init_prbs = 0x423;
- break; // 11~13
- case -1:
- init_prbs = 0x5C7;
- break; // 14~16
- case 0:
- init_prbs = 0x3D8;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x3D6;
- break; // 23~25
- case 3:
- init_prbs = 0x53B;
- break; // 26~28
- case 4:
- init_prbs = 0x213;
- break; // 29~31
- case 5:
- init_prbs = 0x29;
- break; // 32~34
- case 6:
- init_prbs = 0xD0;
- break; // 35~37
- default:
- case 7:
- init_prbs = 0x48E;
- break; // 38~40
- }
- break;
-
- default:
- case TRANSMISSION_MODE_8K:
- switch (sub_channel) {
- case -6:
- init_prbs = 0x0;
- break; // 41, 0, 1
- case -5:
- init_prbs = 0x740;
- break; // 02~04
- case -4:
- init_prbs = 0x069;
- break; // 05~07
- case -3:
- init_prbs = 0x7DD;
- break; // 08~10
- case -2:
- init_prbs = 0x208;
- break; // 11~13
- case -1:
- init_prbs = 0x7B9;
- break; // 14~16
- case 0:
- init_prbs = 0x5C7;
- break; // 17~19
- case 1:
- init_prbs = 0x7FF;
- break; // 20~22
- case 2:
- init_prbs = 0x53B;
- break; // 23~25
- case 3:
- init_prbs = 0x29;
- break; // 26~28
- case 4:
- init_prbs = 0x48E;
- break; // 29~31
- case 5:
- init_prbs = 0x4C4;
- break; // 32~34
- case 6:
- init_prbs = 0x367;
- break; // 33~37
- default:
- case 7:
- init_prbs = 0x684;
- break; // 38~40
- }
- break;
- }
- } else {
- dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff));
- dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff));
- dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003));
- }
- /*P_mode == ?? */
- dib8000_write_word(state, 10, (seq << 4));
- // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000);
-
- switch (state->fe[0]->dtv_property_cache.guard_interval) {
- case GUARD_INTERVAL_1_32:
- guard = 0;
- break;
- case GUARD_INTERVAL_1_16:
- guard = 1;
- break;
- case GUARD_INTERVAL_1_8:
- guard = 2;
- break;
- case GUARD_INTERVAL_1_4:
- default:
- guard = 3;
- break;
- }
-
- dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1
-
- max_constellation = DQPSK;
- for (i = 0; i < 3; i++) {
- switch (state->fe[0]->dtv_property_cache.layer[i].modulation) {
- case DQPSK:
+ switch (c->layer[layer_index].modulation) {
+ case DQPSK:
constellation = 0;
break;
- case QPSK:
+ case QPSK:
constellation = 1;
break;
- case QAM_16:
+ case QAM_16:
constellation = 2;
break;
- case QAM_64:
- default:
+ case QAM_64:
+ default:
constellation = 3;
break;
- }
+ }
- switch (state->fe[0]->dtv_property_cache.layer[i].fec) {
- case FEC_1_2:
- crate = 1;
+ switch (c->layer[layer_index].fec) {
+ case FEC_1_2:
+ cr = 1;
break;
- case FEC_2_3:
- crate = 2;
+ case FEC_2_3:
+ cr = 2;
break;
- case FEC_3_4:
- crate = 3;
+ case FEC_3_4:
+ cr = 3;
break;
- case FEC_5_6:
- crate = 5;
+ case FEC_5_6:
+ cr = 5;
break;
- case FEC_7_8:
- default:
- crate = 7;
+ case FEC_7_8:
+ default:
+ cr = 7;
break;
- }
+ }
- if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) &&
- ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) ||
- (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))
- )
- timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving;
- else
- timeI = 0;
- dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) |
- (crate << 3) | timeI);
- if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) {
- switch (max_constellation) {
- case DQPSK:
- case QPSK:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 ||
- state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+ if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
+ time_intlv = c->layer[layer_index].interleaving;
+ else
+ time_intlv = 0;
+
+ dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
+ if (c->layer[layer_index].segment_count > 0) {
+ switch (max_constellation) {
+ case DQPSK:
+ case QPSK:
+ if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64)
+ max_constellation = c->layer[layer_index].modulation;
break;
- case QAM_16:
- if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64)
- max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation;
+ case QAM_16:
+ if (c->layer[layer_index].modulation == QAM_64)
+ max_constellation = c->layer[layer_index].modulation;
break;
- }
}
}
- mode = fft_to_mode(state);
+ return max_constellation;
+}
- //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/
+static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */
+static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */
+static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */
+static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation)
+{
+ u16 i, ana_gain = 0;
+ const u16 *adp;
- dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) |
- ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.
- isdbt_sb_mode & 1) << 4));
+ /* channel estimation fine configuration */
+ switch (max_constellation) {
+ case QAM_64:
+ ana_gain = 0x7;
+ adp = &adp_Q64[0];
+ break;
+ case QAM_16:
+ ana_gain = 0x7;
+ adp = &adp_Q16[0];
+ break;
+ default:
+ ana_gain = 0;
+ adp = &adp_Qdefault[0];
+ break;
+ }
- dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval);
+ for (i = 0; i < 4; i++)
+ dib8000_write_word(state, 215 + i, adp[i]);
- /* signal optimization parameter */
+ return ana_gain;
+}
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) {
- seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0];
- for (i = 1; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i + 1];
- } else {
- for (i = 0; i < 3; i++)
- nbseg_diff +=
- (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count;
- for (i = 0; i < nbseg_diff; i++)
- seg_diff_mask |= 1 << permu_seg[i];
+static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain)
+{
+ u16 i;
+
+ dib8000_write_word(state, 116, ana_gain);
+
+ /* update ADC target depending on ana_gain */
+ if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */
+ for (i = 0; i < 10; i++)
+ dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
+ } else { /* set -22dB ADC target for ana_gain=0 */
+ for (i = 0; i < 10; i++)
+ dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
}
- dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask);
+}
- state->differential_constellation = (seg_diff_mask != 0);
- if (state->revision != 0x8090)
- dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
- else
- dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff);
+static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe)
+{
+ u16 mode = 0;
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
- seg_mask13 = 0x00E0;
- else // 1-segment
- seg_mask13 = 0x0040;
- } else
- seg_mask13 = 0x1fff;
+ if (state->isdbt_cfg_loaded == 0)
+ for (mode = 0; mode < 24; mode++)
+ dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+}
- // WRITE: Mode & Diff mask
- dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask);
+static const u16 lut_prbs_2k[14] = {
+ 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213
+};
+static const u16 lut_prbs_4k[14] = {
+ 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E
+};
+static const u16 lut_prbs_8k[14] = {
+ 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684
+};
- if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode))
- dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
- else
- dib8000_write_word(state, 268, (2 << 9) | 39); //init value
+static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel)
+{
+ int sub_channel_prbs_group = 0;
- // ---- SMALL ----
- // P_small_seg_diff
- dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352
+ sub_channel_prbs_group = (subchannel / 3) + 1;
+ dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]);
- dib8000_write_word(state, 353, seg_mask13); // ADDR 353
+ switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ return lut_prbs_2k[sub_channel_prbs_group];
+ case TRANSMISSION_MODE_4K:
+ return lut_prbs_4k[sub_channel_prbs_group];
+ default:
+ case TRANSMISSION_MODE_8K:
+ return lut_prbs_8k[sub_channel_prbs_group];
+ }
+}
+
+static void dib8000_set_13seg_channel(struct dib8000_state *state)
+{
+ u16 i;
+ u16 coff_pow = 0x2800;
-/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */
+ state->seg_mask = 0x1fff; /* All 13 segments enabled */
- // ---- SMALL ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
+ /* ---- COFF ---- Carloff, the most robust --- */
+ if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */
+ dib8000_write_word(state, 180, (16 << 6) | 9);
+ dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
+ coff_pow = 0x2800;
+ for (i = 0; i < 6; i++)
+ dib8000_write_word(state, 181+i, coff_pow);
+
+ /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */
+ /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
+
+ /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */
+ dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
+ /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */
+ dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+
+ dib8000_write_word(state, 228, 0); /* default value */
+ dib8000_write_word(state, 265, 31); /* default value */
+ dib8000_write_word(state, 205, 0x200f); /* init value */
+ }
+
+ /*
+ * make the cpil_coff_lock more robust but slower p_coff_winlen
+ * 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
+ */
+
+ if (state->cfg.pll->ifreq == 0)
+ dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
+
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg);
+}
+
+static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs)
+{
+ u16 reg_1;
+
+ reg_1 = dib8000_read_word(state, 1);
+ dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */
+}
+
+static void dib8000_small_fine_tune(struct dib8000_state *state)
+{
+ u16 i;
+ const s16 *ncoeff;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+
+ dib8000_write_word(state, 352, state->seg_diff_mask);
+ dib8000_write_word(state, 353, state->seg_mask);
+
+ /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */
+ dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5);
+
+ if (c->isdbt_sb_mode) {
+ /* ---- SMALL ---- */
+ switch (c->transmission_mode) {
case TRANSMISSION_MODE_2K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_2k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_2k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg_0dqpsk;
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK)
- ncoeff = coeff_2k_sb_3seg_1dqpsk;
- else // QPSK or QAM on external segments
- ncoeff = coeff_2k_sb_3seg;
+ if (c->isdbt_partial_reception == 0) { /* 1-seg */
+ if (c->layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_2k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_2k_sb_1seg;
+ } else { /* 3-segments */
+ if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_2k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_2k_sb_3seg;
+ }
}
- }
- break;
-
+ break;
case TRANSMISSION_MODE_4K:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_4k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_4k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg_0dqpsk;
+ if (c->isdbt_partial_reception == 0) { /* 1-seg */
+ if (c->layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_4k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_4k_sb_1seg;
+ } else { /* 3-segments */
+ if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_4k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_4k_sb_3seg;
}
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_4k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_4k_sb_3seg;
}
- }
- break;
-
+ break;
case TRANSMISSION_MODE_AUTO:
case TRANSMISSION_MODE_8K:
default:
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK)
- ncoeff = coeff_8k_sb_1seg_dqpsk;
- else // QPSK or QAM
- ncoeff = coeff_8k_sb_1seg;
- } else { // 3-segments
- if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) {
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
- } else { // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg_0dqpsk;
+ if (c->isdbt_partial_reception == 0) { /* 1-seg */
+ if (c->layer[0].modulation == DQPSK) /* DQPSK */
+ ncoeff = coeff_8k_sb_1seg_dqpsk;
+ else /* QPSK or QAM */
+ ncoeff = coeff_8k_sb_1seg;
+ } else { /* 3-segments */
+ if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg_0dqpsk;
+ } else { /* QPSK or QAM on central segment */
+ if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */
+ ncoeff = coeff_8k_sb_3seg_1dqpsk;
+ else /* QPSK or QAM on external segments */
+ ncoeff = coeff_8k_sb_3seg;
}
- } else { // QPSK or QAM on central segment
- if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) {
- ncoeff = coeff_8k_sb_3seg_1dqpsk;
- } else // QPSK or QAM on external segments
- ncoeff = coeff_8k_sb_3seg;
}
- }
- break;
+ break;
}
+
for (i = 0; i < 8; i++)
dib8000_write_word(state, 343 + i, ncoeff[i]);
}
+}
- // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5
- dib8000_write_word(state, 351,
- (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5);
+static const u16 coff_thres_1seg[3] = {300, 150, 80};
+static const u16 coff_thres_3seg[3] = {350, 300, 250};
+static void dib8000_set_sb_channel(struct dib8000_state *state)
+{
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ const u16 *coff;
+ u16 i;
- // ---- COFF ----
- // Carloff, the most robust
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
+ if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) {
+ dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */
+ dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */
+ } else {
+ dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */
+ dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */
+ }
- // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64
- // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1
- dib8000_write_word(state, 187,
- (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2)
- | 0x3);
+ if (c->isdbt_partial_reception == 1) /* 3-segments */
+ state->seg_mask = 0x00E0;
+ else /* 1-segment */
+ state->seg_mask = 0x0040;
-/* // P_small_coef_ext_enable = 1 */
-/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+ /* ---- COFF ---- Carloff, the most robust --- */
+ /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */
+ dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3);
- // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1)
- if (mode == 3)
- dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14));
- else
- dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14));
- // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
- // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
- dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
- // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
- // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
- dib8000_write_word(state, 181, 300);
- dib8000_write_word(state, 182, 150);
- dib8000_write_word(state, 183, 80);
- dib8000_write_word(state, 184, 300);
- dib8000_write_word(state, 185, 150);
- dib8000_write_word(state, 186, 80);
- } else { // Sound Broadcasting mode 3 seg
- // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15
- /* if (mode == 3) */
- /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */
- /* else */
- /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */
- dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
-
- // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
- // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8
- dib8000_write_word(state, 340, (16 << 6) | (8 << 0));
- //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
-
- // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k
- dib8000_write_word(state, 181, 350);
- dib8000_write_word(state, 182, 300);
- dib8000_write_word(state, 183, 250);
- dib8000_write_word(state, 184, 350);
- dib8000_write_word(state, 185, 300);
- dib8000_write_word(state, 186, 250);
- }
+ dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */
+ dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */
- } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments
- dib8000_write_word(state, 180, (16 << 6) | 9);
- dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2);
- coff_pow = 0x2800;
- for (i = 0; i < 6; i++)
- dib8000_write_word(state, 181 + i, coff_pow);
+ /* Sound Broadcasting mode 1 seg */
+ if (c->isdbt_partial_reception == 0) {
+ /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */
+ if (state->mode == 3)
+ dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14));
+ else
+ dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14));
- // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1,
- // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1
- dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1);
+ /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4);
+ coff = &coff_thres_1seg[0];
+ } else { /* Sound Broadcasting mode 3 seg */
+ dib8000_write_word(state, 180, 0x1fcf | (1 << 14));
+ /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */
+ dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4);
+ coff = &coff_thres_3seg[0];
+ }
- // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6
- dib8000_write_word(state, 340, (8 << 6) | (6 << 0));
- // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1
- dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
+ dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */
+ dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */
+
+ if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K)
+ dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */
+
+ /* Write COFF thres */
+ for (i = 0 ; i < 3; i++) {
+ dib8000_write_word(state, 181+i, coff[i]);
+ dib8000_write_word(state, 184+i, coff[i]);
}
- // ---- FFT ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- dib8000_write_word(state, 178, 64); // P_fft_powrange=64
- else
- dib8000_write_word(state, 178, 32); // P_fft_powrange=32
- /* make the cpil_coff_lock more robust but slower p_coff_winlen
+ /*
+ * make the cpil_coff_lock more robust but slower p_coff_winlen
* 6bits; p_coff_thres_lock 6bits (for coff lock if needed)
*/
- /* if ( ( nbseg_diff>0)&&(nbseg_diff<13))
- dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */
-
- dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */
- dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */
- dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */
- if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0))
- dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */
- else
- dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */
- dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */
- //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */
- if (!autosearching)
- dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
+
+ dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */
+
+ if (c->isdbt_partial_reception == 0)
+ dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */
else
- dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels.
- dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000);
-
- dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */
-
- /* offset loop parameters */
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40);
-
- else // Sound Broadcasting mode 3 seg
- /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60);
- } else
- // TODO in 13 seg, timf_alpha can always be the same or not ?
- /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
- dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80);
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode));
-
- else // Sound Broadcasting mode 3 seg
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode));
- } else
- /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
- dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode));
+ dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
+}
- /* P_dvsy_sync_wait - reuse mode */
- switch (state->fe[0]->dtv_property_cache.transmission_mode) {
- case TRANSMISSION_MODE_8K:
- mode = 256;
- break;
- case TRANSMISSION_MODE_4K:
- mode = 128;
- break;
- default:
- case TRANSMISSION_MODE_2K:
- mode = 64;
- break;
+static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
+{
+ u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0;
+ u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ;
+ u16 max_constellation = DQPSK;
+ int init_prbs;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+
+ /* P_mode */
+ dib8000_write_word(state, 10, (seq << 4));
+
+ /* init mode */
+ state->mode = fft_to_mode(state);
+
+ /* set guard */
+ tmp = dib8000_read_word(state, 1);
+ dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3));
+
+ dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4));
+
+ /* signal optimization parameter */
+ if (c->isdbt_partial_reception) {
+ state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0];
+ for (i = 1; i < 3; i++)
+ nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
+ for (i = 0; i < nbseg_diff; i++)
+ state->seg_diff_mask |= 1 << permu_seg[i+1];
+ } else {
+ for (i = 0; i < 3; i++)
+ nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count;
+ for (i = 0; i < nbseg_diff; i++)
+ state->seg_diff_mask |= 1 << permu_seg[i];
}
- if (state->cfg.diversity_delay == 0)
- mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+
+ if (state->seg_diff_mask)
+ dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200);
else
- mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo
- mode <<= 4;
- dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode);
+ dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */
- /* channel estimation fine configuration */
- switch (max_constellation) {
- case QAM_64:
- ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
- coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
- coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
- coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
- coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
- //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1
- break;
- case QAM_16:
- ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB
- coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
- coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
- coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
- coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */
- //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16)))
- break;
- default:
- ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level
- coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */
- coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */
- coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */
- coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
- break;
+ for (i = 0; i < 3; i++)
+ max_constellation = dib8000_set_layer(state, i, max_constellation);
+ if (autosearching == 0) {
+ state->layer_b_nb_seg = c->layer[1].segment_count;
+ state->layer_c_nb_seg = c->layer[2].segment_count;
}
- for (mode = 0; mode < 4; mode++)
- dib8000_write_word(state, 215 + mode, coeff[mode]);
- // update ana_gain depending on max constellation
- dib8000_write_word(state, 116, ana_gain);
- // update ADC target depending on ana_gain
- if (ana_gain) { // set -16dB ADC target for ana_gain=-1
- for (i = 0; i < 10; i++)
- dib8000_write_word(state, 80 + i, adc_target_16dB[i]);
- } else { // set -22dB ADC target for ana_gain=0
- for (i = 0; i < 10; i++)
- dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355);
+ /* WRITE: Mode & Diff mask */
+ dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask);
+
+ state->differential_constellation = (state->seg_diff_mask != 0);
+
+ /* channel estimation fine configuration */
+ ana_gain = dib8000_adp_fine_tune(state, max_constellation);
+
+ /* update ana_gain depending on max constellation */
+ dib8000_update_ana_gain(state, ana_gain);
+
+ /* ---- ANA_FE ---- */
+ if (c->isdbt_partial_reception) /* 3-segments */
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg);
+ else
+ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */
+
+ /* TSB or ISDBT ? apply it now */
+ if (c->isdbt_sb_mode) {
+ dib8000_set_sb_channel(state);
+ if (c->isdbt_sb_subchannel < 14)
+ init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel);
+ else
+ init_prbs = 0;
+ } else {
+ dib8000_set_13seg_channel(state);
+ init_prbs = 0xfff;
}
- // ---- ANA_FE ----
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1)
- ana_fe = ana_fe_coeff_3seg;
- else // 1-segment
- ana_fe = ana_fe_coeff_1seg;
- } else
- ana_fe = ana_fe_coeff_13seg;
+ /* SMALL */
+ dib8000_small_fine_tune(state);
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0)
- for (mode = 0; mode < 24; mode++)
- dib8000_write_word(state, 117 + mode, ana_fe[mode]);
+ dib8000_set_subchannel_prbs(state, init_prbs);
- // ---- CHAN_BLK ----
+ /* ---- CHAN_BLK ---- */
for (i = 0; i < 13; i++) {
- if ((((~seg_diff_mask) >> i) & 1) == 1) {
- P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0));
- P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0));
+ if ((((~state->seg_diff_mask) >> i) & 1) == 1) {
+ p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0));
+ p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0));
}
}
- dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge
- dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge
- // "P_cspu_left_edge" not used => do not care
- // "P_cspu_right_edge" not used => do not care
-
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1
- dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0
- && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) {
- //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0
- dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15
- }
- } else if (state->isdbt_cfg_loaded == 0) {
- dib8000_write_word(state, 228, 0); // default value
- dib8000_write_word(state, 265, 31); // default value
- dib8000_write_word(state, 205, 0x200f); // init value
- }
- // ---- TMCC ----
+ dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */
+ dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */
+ /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */
+
+ dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */
+ dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */
+ dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */
+
+ if (!autosearching)
+ dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */
+ else
+ dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */
+
+ dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */
+ dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */
+
+ dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */
+
+ /* ---- TMCC ---- */
for (i = 0; i < 3; i++)
- tmcc_pow +=
- (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count);
- // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9);
- // Threshold is set at 1/4 of max power.
- tmcc_pow *= (1 << (9 - 2));
-
- dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k
- dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k
- dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k
- //dib8000_write_word(state, 287, (1 << 13) | 0x1000 );
- // ---- PHA3 ----
+ tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ;
+
+ /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */
+ /* Threshold is set at 1/4 of max power. */
+ tmcc_pow *= (1 << (9-2));
+ dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */
+ dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */
+ dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */
+ /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */
+ /* ---- PHA3 ---- */
if (state->isdbt_cfg_loaded == 0)
- dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */
+ dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)
- state->isdbt_cfg_loaded = 0;
- else
- state->isdbt_cfg_loaded = 1;
+ state->isdbt_cfg_loaded = 0;
+}
+static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal,
+ u32 wait0_ms, u32 wait1_ms, u32 wait2_ms)
+{
+ u32 value = 0; /* P_search_end0 wait time */
+ u16 reg = 11; /* P_search_end0 start addr */
+
+ for (reg = 11; reg < 16; reg += 2) {
+ if (reg == 11) {
+ if (state->revision == 0x8090)
+ value = internal * wait1_ms;
+ else
+ value = internal * wait0_ms;
+ } else if (reg == 13)
+ value = internal * wait1_ms;
+ else if (reg == 15)
+ value = internal * wait2_ms;
+ dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff));
+ dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff));
+ }
+ return value;
}
static int dib8000_autosearch_start(struct dvb_frontend *fe)
{
- u8 factor;
- u32 value;
struct dib8000_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ u8 slist = 0;
+ u32 value, internal = state->cfg.pll->internal;
- int slist = 0;
-
- state->fe[0]->dtv_property_cache.inversion = 0;
- if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode)
- state->fe[0]->dtv_property_cache.layer[0].segment_count = 13;
- state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64;
- state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3;
- state->fe[0]->dtv_property_cache.layer[0].interleaving = 0;
-
- //choose the right list, in sb, always do everything
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) {
- state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
- state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
- slist = 7;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
- } else {
- if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) {
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
- slist = 7;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2
- } else
- slist = 3;
- } else {
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) {
- slist = 2;
- dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
- } else
- slist = 0;
- }
+ if (state->revision == 0x8090)
+ internal = dib8000_read32(state, 23) / 1000;
+
+ if (state->autosearch_state == AS_SEARCHING_FFT) {
+ dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
+ dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
- if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO)
- state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
- if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO)
- state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */
+ dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */
+ dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */
+ dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */
+ dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */
+ dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */
- dprintk("using list for autosearch : %d", slist);
- dib8000_set_channel(state, (unsigned char)slist, 1);
- //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1
+ if (state->revision == 0x8090)
+ value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
- factor = 1;
+ dib8000_write_word(state, 17, 0);
+ dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */
+ dib8000_write_word(state, 19, 0);
+ dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */
+ dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */
+ dib8000_write_word(state, 22, value & 0xffff);
- //set lock_mask values
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */
+ else
+ dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */
+ dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */
+
+ /* P_search_param_select = (1 | 1<<4 | 1 << 8) */
+ dib8000_write_word(state, 356, 0);
+ dib8000_write_word(state, 357, 0x111);
+
+ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
+ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
+ } else if (state->autosearch_state == AS_SEARCHING_GUARD) {
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ c->inversion = 0;
+ c->layer[0].modulation = QAM_64;
+ c->layer[0].fec = FEC_2_3;
+ c->layer[0].interleaving = 0;
+ c->layer[0].segment_count = 13;
+
+ slist = 16;
+ c->transmission_mode = state->found_nfft;
+
+ dib8000_set_isdbt_common_channel(state, slist, 1);
+
+ /* set lock_mask values */
dib8000_write_word(state, 6, 0x4);
- dib8000_write_word(state, 7, 0x8);
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */
+ else
+ dib8000_write_word(state, 7, 0x8);
dib8000_write_word(state, 8, 0x1000);
- //set lock_mask wait time values
- value = 50 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
- dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
- dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time
- value = 1000 * state->cfg.pll->internal * factor;
- dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
- dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time
+ /* set lock_mask wait time values */
+ if (state->revision == 0x8090)
+ dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+
+ dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */
+
+ /* P_search_param_select = 0xf; look for the 4 different guard intervals */
+ dib8000_write_word(state, 356, 0);
+ dib8000_write_word(state, 357, 0xf);
value = dib8000_read_word(state, 0);
- dib8000_write_word(state, 0, (u16) ((1 << 15) | value));
- dib8000_read_word(state, 1284); // reset the INT. n_irq_pending
- dib8000_write_word(state, 0, (u16) value);
+ dib8000_write_word(state, 0, (u16)((1 << 15) | value));
+ dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
+ dib8000_write_word(state, 0, (u16)value);
+ } else {
+ c->inversion = 0;
+ c->layer[0].modulation = QAM_64;
+ c->layer[0].fec = FEC_2_3;
+ c->layer[0].interleaving = 0;
+ c->layer[0].segment_count = 13;
+ if (!c->isdbt_sb_mode)
+ c->layer[0].segment_count = 13;
+
+ /* choose the right list, in sb, always do everything */
+ if (c->isdbt_sb_mode) {
+ slist = 7;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13));
+ } else {
+ if (c->guard_interval == GUARD_INTERVAL_AUTO) {
+ if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ slist = 7;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */
+ } else {
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ slist = 3;
+ }
+ } else {
+ if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ slist = 2;
+ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */
+ } else
+ slist = 0;
+ }
+ }
+ dprintk("Using list for autosearch : %d", slist);
- }
+ dib8000_set_isdbt_common_channel(state, slist, 1);
+
+ /* set lock_mask values */
+ dib8000_write_word(state, 6, 0x4);
+ if (state->revision == 0x8090)
+ dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10));
+ else
+ dib8000_write_word(state, 7, 0x8);
+ dib8000_write_word(state, 8, 0x1000);
+ /* set lock_mask wait time values */
+ if (state->revision == 0x8090)
+ dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+ else
+ dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */
+
+ value = dib8000_read_word(state, 0);
+ dib8000_write_word(state, 0, (u16)((1 << 15) | value));
+ dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */
+ dib8000_write_word(state, 0, (u16)value);
+ }
return 0;
}
@@ -2663,96 +2583,635 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe)
struct dib8000_state *state = fe->demodulator_priv;
u16 irq_pending = dib8000_read_word(state, 1284);
- if (irq_pending & 0x1) { // failed
- dprintk("dib8000_autosearch_irq failed");
- return 1;
- }
+ if (state->autosearch_state == AS_SEARCHING_FFT) {
+ if (irq_pending & 0x1) {
+ dprintk("dib8000_autosearch_irq: max correlation result available");
+ return 3;
+ }
+ } else {
+ if (irq_pending & 0x1) { /* failed */
+ dprintk("dib8000_autosearch_irq failed");
+ return 1;
+ }
- if (irq_pending & 0x2) { // succeeded
- dprintk("dib8000_autosearch_irq succeeded");
- return 2;
+ if (irq_pending & 0x2) { /* succeeded */
+ dprintk("dib8000_autosearch_irq succeeded");
+ return 2;
+ }
}
return 0; // still pending
}
-static int dib8000_tune(struct dvb_frontend *fe)
+static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff)
{
- struct dib8000_state *state = fe->demodulator_priv;
- int ret = 0;
- u16 lock, value, mode;
+ u16 tmp;
- // we are already tuned - just resuming from suspend
- if (state == NULL)
- return -EINVAL;
+ tmp = dib8000_read_word(state, 771);
+ if (onoff) /* start P_restart_chd : channel_decoder */
+ dib8000_write_word(state, 771, tmp & 0xfffd);
+ else /* stop P_restart_chd : channel_decoder */
+ dib8000_write_word(state, 771, tmp | (1<<1));
+}
+
+static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz)
+{
+ s16 unit_khz_dds_val;
+ u32 abs_offset_khz = ABS(offset_khz);
+ u32 dds = state->cfg.pll->ifreq & 0x1ffffff;
+ u8 invert = !!(state->cfg.pll->ifreq & (1 << 25));
+ u8 ratio;
- mode = fft_to_mode(state);
+ if (state->revision == 0x8090) {
+ ratio = 4;
+ unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000);
+ if (offset_khz < 0)
+ dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val);
+ else
+ dds = (abs_offset_khz * unit_khz_dds_val);
- dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000);
- dib8000_set_channel(state, 0, 0);
+ if (invert)
+ dds = (1<<26) - dds;
+ } else {
+ ratio = 2;
+ unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal);
- // restart demod
- ret |= dib8000_write_word(state, 770, 0x4000);
- ret |= dib8000_write_word(state, 770, 0x0000);
- msleep(45);
+ if (offset_khz < 0)
+ unit_khz_dds_val *= -1;
- /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */
- /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */
+ /* IF tuner */
+ if (invert)
+ dds -= abs_offset_khz * unit_khz_dds_val;
+ else
+ dds += abs_offset_khz * unit_khz_dds_val;
+ }
- // never achieved a lock before - wait for timfreq to update
- if (state->timf == 0) {
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0)
- msleep(300);
- else // Sound Broadcasting mode 3 seg
- msleep(500);
- } else // 13 seg
- msleep(200);
+ dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val);
+
+ if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) {
+ /* Max dds offset is the half of the demod freq */
+ dib8000_write_word(state, 26, invert);
+ dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff);
+ dib8000_write_word(state, 28, (u16)(dds & 0xffff));
}
- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) {
- if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) {
+}
- /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */
- dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40);
- //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80);
+static void dib8000_set_frequency_offset(struct dib8000_state *state)
+{
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ int i;
+ u32 current_rf;
+ int total_dds_offset_khz;
- /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */
- ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5));
+ if (state->fe[0]->ops.tuner_ops.get_frequency)
+ state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], &current_rf);
+ else
+ current_rf = c->frequency;
+ current_rf /= 1000;
+ total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000;
- } else { // Sound Broadcasting mode 3 seg
+ if (c->isdbt_sb_mode) {
+ state->subchannel = c->isdbt_sb_subchannel;
- /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */
- dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60);
+ i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */
+ dib8000_write_word(state, 26, c->inversion ^ i);
- ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5));
+ if (state->cfg.pll->ifreq == 0) { /* low if tuner */
+ if ((c->inversion ^ i) == 0)
+ dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1);
+ } else {
+ if ((c->inversion ^ i) == 0)
+ total_dds_offset_khz *= -1;
}
+ }
- } else { // 13 seg
- /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */
- dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80);
+ dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz);
- ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5));
+ /* apply dds offset now */
+ dib8000_set_dds(state, total_dds_offset_khz);
+}
+
+static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 };
+
+static u32 dib8000_get_symbol_duration(struct dib8000_state *state)
+{
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ u16 i;
+ switch (c->transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ i = 0;
+ break;
+ case TRANSMISSION_MODE_4K:
+ i = 2;
+ break;
+ default:
+ case TRANSMISSION_MODE_AUTO:
+ case TRANSMISSION_MODE_8K:
+ i = 1;
+ break;
}
- // we achieved a coff_cpil_lock - it's time to update the timf
- if (state->revision != 0x8090)
- lock = dib8000_read_word(state, 568);
+ return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1;
+}
+
+static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step)
+{
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ u16 reg_32 = 0, reg_37 = 0;
+
+ switch (loop_step) {
+ case LOOP_TUNE_1:
+ if (c->isdbt_sb_mode) {
+ if (c->isdbt_partial_reception == 0) {
+ reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */
+ reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */
+ } else { /* Sound Broadcasting mode 3 seg */
+ reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */
+ reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */
+ }
+ } else { /* 13-seg start conf offset loop parameters */
+ reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */
+ reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */
+ }
+ break;
+ case LOOP_TUNE_2:
+ if (c->isdbt_sb_mode) {
+ if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */
+ reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/
+ reg_37 = (12-state->mode) | ((5 + state->mode) << 5);
+ } else { /* Sound Broadcasting mode 3 seg */
+ reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */
+ reg_37 = (11-state->mode) | ((5 + state->mode) << 5);
+ }
+ } else { /* 13 seg */
+ reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */
+ reg_37 = ((5+state->mode) << 5) | (10 - state->mode);
+ }
+ break;
+ }
+ dib8000_write_word(state, 32, reg_32);
+ dib8000_write_word(state, 37, reg_37);
+}
+
+static void dib8000_demod_restart(struct dib8000_state *state)
+{
+ dib8000_write_word(state, 770, 0x4000);
+ dib8000_write_word(state, 770, 0x0000);
+ return;
+}
+
+static void dib8000_set_sync_wait(struct dib8000_state *state)
+{
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ u16 sync_wait = 64;
+
+ /* P_dvsy_sync_wait - reuse mode */
+ switch (c->transmission_mode) {
+ case TRANSMISSION_MODE_8K:
+ sync_wait = 256;
+ break;
+ case TRANSMISSION_MODE_4K:
+ sync_wait = 128;
+ break;
+ default:
+ case TRANSMISSION_MODE_2K:
+ sync_wait = 64;
+ break;
+ }
+
+ if (state->cfg.diversity_delay == 0)
+ sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */
else
- lock = dib8000_read_word(state, 570);
- if ((lock >> 11) & 0x1)
- dib8000_update_timf(state);
+ sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */
- //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start
- dib8000_write_word(state, 6, 0x200);
+ dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
+}
- if (state->revision == 0x8002) {
- value = dib8000_read_word(state, 903);
- dib8000_write_word(state, 903, value & ~(1 << 3));
- msleep(1);
- dib8000_write_word(state, 903, value | (1 << 3));
+static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
+{
+ if (mode == SYMBOL_DEPENDENT_ON)
+ return systime() + (delay * state->symbol_duration);
+ else
+ return systime() + delay;
+}
+
+static s32 dib8000_get_status(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ return state->status;
+}
+
+enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ return state->tune_state;
+}
+EXPORT_SYMBOL(dib8000_get_tune_state);
+
+int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ state->tune_state = tune_state;
+ return 0;
+}
+EXPORT_SYMBOL(dib8000_set_tune_state);
+
+static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ state->status = FE_STATUS_TUNE_PENDING;
+ state->tune_state = CT_DEMOD_START;
+ return 0;
+}
+
+static u16 dib8000_read_lock(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+
+ if (state->revision == 0x8090)
+ return dib8000_read_word(state, 570);
+ return dib8000_read_word(state, 568);
+}
+
+static int dib8090p_init_sdram(struct dib8000_state *state)
+{
+ u16 reg = 0;
+ dprintk("init sdram");
+
+ reg = dib8000_read_word(state, 274) & 0xfff0;
+ dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */
+
+ dib8000_write_word(state, 1803, (7 << 2));
+
+ reg = dib8000_read_word(state, 1280);
+ dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */
+ dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */
+
+ return 0;
+}
+
+static int dib8000_tune(struct dvb_frontend *fe)
+{
+ struct dib8000_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ enum frontend_tune_state *tune_state = &state->tune_state;
+
+ u16 locks, deeper_interleaver = 0, i;
+ int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
+
+ u32 *timeout = &state->timeout;
+ u32 now = systime();
+#ifdef DIB8000_AGC_FREEZE
+ u16 agc1, agc2;
+#endif
+
+ u32 corm[4] = {0, 0, 0, 0};
+ u8 find_index, max_value;
+
+#if 0
+ if (*tune_state < CT_DEMOD_STOP)
+ dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
+#endif
+
+ switch (*tune_state) {
+ case CT_DEMOD_START: /* 30 */
+ if (state->revision == 0x8090)
+ dib8090p_init_sdram(state);
+ state->status = FE_STATUS_TUNE_PENDING;
+ if ((c->delivery_system != SYS_ISDBT) ||
+ (c->inversion == INVERSION_AUTO) ||
+ (c->transmission_mode == TRANSMISSION_MODE_AUTO) ||
+ (c->guard_interval == GUARD_INTERVAL_AUTO) ||
+ (((c->isdbt_layer_enabled & (1 << 0)) != 0) &&
+ (c->layer[0].segment_count != 0xff) &&
+ (c->layer[0].segment_count != 0) &&
+ ((c->layer[0].modulation == QAM_AUTO) ||
+ (c->layer[0].fec == FEC_AUTO))) ||
+ (((c->isdbt_layer_enabled & (1 << 1)) != 0) &&
+ (c->layer[1].segment_count != 0xff) &&
+ (c->layer[1].segment_count != 0) &&
+ ((c->layer[1].modulation == QAM_AUTO) ||
+ (c->layer[1].fec == FEC_AUTO))) ||
+ (((c->isdbt_layer_enabled & (1 << 2)) != 0) &&
+ (c->layer[2].segment_count != 0xff) &&
+ (c->layer[2].segment_count != 0) &&
+ ((c->layer[2].modulation == QAM_AUTO) ||
+ (c->layer[2].fec == FEC_AUTO))) ||
+ (((c->layer[0].segment_count == 0) ||
+ ((c->isdbt_layer_enabled & (1 << 0)) == 0)) &&
+ ((c->layer[1].segment_count == 0) ||
+ ((c->isdbt_layer_enabled & (2 << 0)) == 0)) &&
+ ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0))))
+ state->channel_parameters_set = 0; /* auto search */
+ else
+ state->channel_parameters_set = 1; /* channel parameters are known */
+
+ dib8000_viterbi_state(state, 0); /* force chan dec in restart */
+
+ /* Layer monit */
+ dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
+
+ dib8000_set_frequency_offset(state);
+ dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
+
+ if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
+#ifdef DIB8000_AGC_FREEZE
+ if (state->revision != 0x8090) {
+ state->agc1_max = dib8000_read_word(state, 108);
+ state->agc1_min = dib8000_read_word(state, 109);
+ state->agc2_max = dib8000_read_word(state, 110);
+ state->agc2_min = dib8000_read_word(state, 111);
+ agc1 = dib8000_read_word(state, 388);
+ agc2 = dib8000_read_word(state, 389);
+ dib8000_write_word(state, 108, agc1);
+ dib8000_write_word(state, 109, agc1);
+ dib8000_write_word(state, 110, agc2);
+ dib8000_write_word(state, 111, agc2);
+ }
+#endif
+ state->autosearch_state = AS_SEARCHING_FFT;
+ state->found_nfft = TRANSMISSION_MODE_AUTO;
+ state->found_guard = GUARD_INTERVAL_AUTO;
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ } else { /* we already know the channel struct so TUNE only ! */
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STEP_3;
+ }
+ state->symbol_duration = dib8000_get_symbol_duration(state);
+ break;
+
+ case CT_DEMOD_SEARCH_NEXT: /* 51 */
+ dib8000_autosearch_start(fe);
+ if (state->revision == 0x8090)
+ ret = 50;
+ else
+ ret = 15;
+ *tune_state = CT_DEMOD_STEP_1;
+ break;
+
+ case CT_DEMOD_STEP_1: /* 31 */
+ switch (dib8000_autosearch_irq(fe)) {
+ case 1: /* fail */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
+ break;
+ case 2: /* Succes */
+ state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ *tune_state = CT_DEMOD_STEP_3;
+ if (state->autosearch_state == AS_SEARCHING_GUARD)
+ *tune_state = CT_DEMOD_STEP_2;
+ else
+ state->autosearch_state = AS_DONE;
+ break;
+ case 3: /* Autosearch FFT max correlation endded */
+ *tune_state = CT_DEMOD_STEP_2;
+ break;
+ }
+ break;
+
+ case CT_DEMOD_STEP_2:
+ switch (state->autosearch_state) {
+ case AS_SEARCHING_FFT:
+ /* searching for the correct FFT */
+ if (state->revision == 0x8090) {
+ corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
+ } else {
+ corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
+ corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ }
+ /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
+
+ max_value = 0;
+ for (find_index = 1 ; find_index < 3 ; find_index++) {
+ if (corm[max_value] < corm[find_index])
+ max_value = find_index ;
+ }
+
+ switch (max_value) {
+ case 0:
+ state->found_nfft = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ state->found_nfft = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ default:
+ state->found_nfft = TRANSMISSION_MODE_8K;
+ break;
+ }
+ /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
+
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ state->autosearch_state = AS_SEARCHING_GUARD;
+ if (state->revision == 0x8090)
+ ret = 50;
+ else
+ ret = 10;
+ break;
+ case AS_SEARCHING_GUARD:
+ /* searching for the correct guard interval */
+ if (state->revision == 0x8090)
+ state->found_guard = dib8000_read_word(state, 572) & 0x3;
+ else
+ state->found_guard = dib8000_read_word(state, 570) & 0x3;
+ /* dprintk("guard interval found=%i", state->found_guard); */
+
+ *tune_state = CT_DEMOD_STEP_3;
+ break;
+ default:
+ /* the demod should never be in this state */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
+ break;
+ }
+ break;
+
+ case CT_DEMOD_STEP_3: /* 33 */
+ state->symbol_duration = dib8000_get_symbol_duration(state);
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
+ dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
+ *tune_state = CT_DEMOD_STEP_4;
+ break;
+
+ case CT_DEMOD_STEP_4: /* (34) */
+ dib8000_demod_restart(state);
+
+ dib8000_set_sync_wait(state);
+ dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+
+ locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
+ /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */
+ *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_5;
+ break;
+
+ case CT_DEMOD_STEP_5: /* (35) */
+ locks = dib8000_read_lock(fe);
+ if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
+ dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
+ if (!state->differential_constellation) {
+ /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
+ *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_7;
+ } else {
+ *tune_state = CT_DEMOD_STEP_8;
+ }
+ } else if (now > *timeout) {
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ }
+ break;
+
+ case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
+ if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
+ /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
+ if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
+ *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
+ else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ } else {
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
+
+ case CT_DEMOD_STEP_7: /* 37 */
+ locks = dib8000_read_lock(fe);
+ if (locks & (1<<10)) { /* lmod4_lock */
+ ret = 14; /* wait for 14 symbols */
+ *tune_state = CT_DEMOD_STEP_8;
+ } else if (now > *timeout)
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ break;
+
+ case CT_DEMOD_STEP_8: /* 38 */
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+
+ /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation) {
+ state->subchannel = 0;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else {
+ *tune_state = CT_DEMOD_STEP_9;
+ state->status = FE_STATUS_LOCKED;
+ }
+ break;
+
+ case CT_DEMOD_STEP_9: /* 39 */
+ if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
+ /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */
+ for (i = 0; i < 3; i++) {
+ if (c->layer[i].interleaving >= deeper_interleaver) {
+ dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
+ if (c->layer[i].segment_count > 0) { /* valid layer */
+ deeper_interleaver = c->layer[0].interleaving;
+ state->longest_intlv_layer = i;
+ }
+ }
+ }
+
+ if (deeper_interleaver == 0)
+ locks = 2; /* locks is the tmp local variable name */
+ else if (deeper_interleaver == 3)
+ locks = 8;
+ else
+ locks = 2 * deeper_interleaver;
+
+ if (state->diversity_onoff != 0) /* because of diversity sync */
+ locks *= 2;
+
+ *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
+ dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
+
+ *tune_state = CT_DEMOD_STEP_10;
+ } else
+ *tune_state = CT_DEMOD_STOP;
+ break;
+
+ case CT_DEMOD_STEP_10: /* 40 */
+ locks = dib8000_read_lock(fe);
+ if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
+ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation)
+ /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ state->status = FE_STATUS_DEMOD_SUCCESS;
+ else
+ state->status = FE_STATUS_DATA_LOCKED;
+ *tune_state = CT_DEMOD_STOP;
+ } else if (now > *timeout) {
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation) { /* continue to try init prbs autosearch */
+ state->subchannel += 3;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
+ if (locks & (0x7<<5)) {
+ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
+ state->status = FE_STATUS_DATA_LOCKED;
+ } else
+ state->status = FE_STATUS_TUNE_FAILED;
+ *tune_state = CT_DEMOD_STOP;
+ }
+ }
+ break;
+
+ case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
+ if (state->subchannel <= 41) {
+ dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
+ *tune_state = CT_DEMOD_STEP_9;
+ } else {
+ *tune_state = CT_DEMOD_STOP;
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* tuning is finished - cleanup the demod */
+ switch (*tune_state) {
+ case CT_DEMOD_STOP: /* (42) */
+#ifdef DIB8000_AGC_FREEZE
+ if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
+ dib8000_write_word(state, 108, state->agc1_max);
+ dib8000_write_word(state, 109, state->agc1_min);
+ dib8000_write_word(state, 110, state->agc2_max);
+ dib8000_write_word(state, 111, state->agc2_min);
+ state->agc1_max = 0;
+ state->agc1_min = 0;
+ state->agc2_max = 0;
+ state->agc2_min = 0;
+ }
+#endif
+ ret = FE_CALLBACK_TIME_NEVER;
+ break;
+ default:
+ break;
}
+ if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
+ return ret * state->symbol_duration;
+ if ((ret > 0) && (ret < state->symbol_duration))
+ return state->symbol_duration; /* at least one symbol */
return ret;
}
@@ -2767,7 +3226,7 @@ static int dib8000_wakeup(struct dvb_frontend *fe)
if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
dprintk("could not start Slow ADC");
- if (state->revision != 0x8090)
+ if (state->revision == 0x8090)
dib8000_sad_calib(state);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
@@ -2797,21 +3256,6 @@ static int dib8000_sleep(struct dvb_frontend *fe)
return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
}
-enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
- struct dib8000_state *state = fe->demodulator_priv;
- return state->tune_state;
-}
-EXPORT_SYMBOL(dib8000_get_tune_state);
-
-int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
- struct dib8000_state *state = fe->demodulator_priv;
- state->tune_state = tune_state;
- return 0;
-}
-EXPORT_SYMBOL(dib8000_set_tune_state);
-
static int dib8000_get_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
@@ -2961,19 +3405,19 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
static int dib8000_set_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
- u8 nbr_pending, exit_condition, index_frontend;
- s8 index_frontend_success = -1;
- int time, ret;
- int time_slave = FE_CALLBACK_TIME_NEVER;
+ struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER;
+ u8 exit_condition, index_frontend;
+ u32 delay, callback_time;
- if (state->fe[0]->dtv_property_cache.frequency == 0) {
+ if (c->frequency == 0) {
dprintk("dib8000: must at least specify frequency ");
return 0;
}
- if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) {
+ if (c->bandwidth_hz == 0) {
dprintk("dib8000: no bandwidth specified, set to default ");
- state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000;
+ c->bandwidth_hz = 6000000;
}
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
@@ -2981,18 +3425,36 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT;
memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties));
- if (state->revision != 0x8090)
- dib8000_set_output_mode(state->fe[index_frontend],
- OUTMODE_HIGH_Z);
- else
- dib8096p_set_output_mode(state->fe[index_frontend],
- OUTMODE_HIGH_Z);
+ /* set output mode and diversity input */
+ if (state->revision != 0x8090) {
+ dib8000_set_diversity_in(state->fe[index_frontend], 1);
+ if (index_frontend != 0)
+ dib8000_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ else
+ dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
+ } else {
+ dib8096p_set_diversity_in(state->fe[index_frontend], 1);
+ if (index_frontend != 0)
+ dib8096p_set_output_mode(state->fe[index_frontend],
+ OUTMODE_DIVERSITY);
+ else
+ dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z);
+ }
+
+ /* tune the tuner */
if (state->fe[index_frontend]->ops.tuner_ops.set_params)
state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]);
dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START);
}
+ /* turn off the diversity of the last chip */
+ if (state->revision != 0x8090)
+ dib8000_set_diversity_in(state->fe[index_frontend - 1], 0);
+ else
+ dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0);
+
/* start up the AGC */
do {
time = dib8000_agc_startup(state->fe[0]);
@@ -3019,139 +3481,88 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START);
- if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) ||
- (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) ||
- (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) ||
- (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) &&
- (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) &&
- (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) &&
- ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) ||
- (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) ||
- (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) ||
- ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) &&
- ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) ||
- ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) &&
- ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) {
- int i = 100;
- u8 found = 0;
- u8 tune_failed = 0;
-
+ active = 1;
+ do {
+ callback_time = FE_CALLBACK_TIME_NEVER;
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000);
- dib8000_autosearch_start(state->fe[index_frontend]);
- }
-
- do {
- msleep(20);
- nbr_pending = 0;
- exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */
- for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
- if (((tune_failed >> index_frontend) & 0x1) == 0) {
- found = dib8000_autosearch_irq(state->fe[index_frontend]);
- switch (found) {
- case 0: /* tune pending */
- nbr_pending++;
- break;
- case 2:
- dprintk("autosearch succeed on the frontend%i", index_frontend);
- exit_condition = 2;
- index_frontend_success = index_frontend;
- break;
- default:
- dprintk("unhandled autosearch result");
- case 1:
- tune_failed |= (1 << index_frontend);
- dprintk("autosearch failed for the frontend%i", index_frontend);
- break;
+ delay = dib8000_tune(state->fe[index_frontend]);
+ if (delay != FE_CALLBACK_TIME_NEVER)
+ delay += systime();
+
+ /* we are in autosearch */
+ if (state->channel_parameters_set == 0) { /* searching */
+ if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) {
+ dprintk("autosearch succeeded on fe%i", index_frontend);
+ dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */
+ state->channel_parameters_set = 1;
+
+ for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
+ if (l != index_frontend) { /* and for all frontend except the successful one */
+ dib8000_tune_restart_from_demod(state->fe[l]);
+
+ state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
+ state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion;
+ state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode;
+ state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval;
+ state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception;
+ for (i = 0; i < 3; i++) {
+ state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count;
+ state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving;
+ state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec;
+ state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation;
+ }
+
+ }
}
}
}
-
- /* if all tune are done and no success, exit: tune failed */
- if ((nbr_pending == 0) && (exit_condition == 0))
- exit_condition = 1;
- } while ((exit_condition == 0) && i--);
-
- if (exit_condition == 1) { /* tune failed */
- dprintk("tune failed");
- return 0;
+ if (delay < callback_time)
+ callback_time = delay;
+ }
+ /* tuning is done when the master frontend is done (failed or success) */
+ if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
+ dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED ||
+ dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) {
+ active = 0;
+ /* we need to wait for all frontends to be finished */
+ for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP)
+ active = 1;
+ }
+ if (active == 0)
+ dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
}
- dprintk("tune success on frontend%i", index_frontend_success);
-
- dib8000_get_frontend(fe);
- }
+ if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
+ dprintk("strange callback time something went wrong");
+ active = 0;
+ }
- for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
- ret = dib8000_tune(state->fe[index_frontend]);
+ while ((active == 1) && (systime() < callback_time))
+ msleep(100);
+ } while (active);
- /* set output mode and diversity input */
- if (state->revision != 0x8090) {
+ /* set output mode */
+ if (state->revision != 0x8090)
dib8000_set_output_mode(state->fe[0], state->cfg.output_mode);
- for (index_frontend = 1;
- (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
- (state->fe[index_frontend] != NULL);
- index_frontend++) {
- dib8000_set_output_mode(state->fe[index_frontend],
- OUTMODE_DIVERSITY);
- dib8000_set_diversity_in(state->fe[index_frontend-1], 1);
- }
-
- /* turn off the diversity of the last chip */
- dib8000_set_diversity_in(state->fe[index_frontend-1], 0);
- } else {
+ else {
dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode);
if (state->cfg.enMpegOutput == 0) {
dib8096p_setDibTxMux(state, MPEG_ON_DIBTX);
dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS);
}
- for (index_frontend = 1;
- (index_frontend < MAX_NUMBER_OF_FRONTENDS) &&
- (state->fe[index_frontend] != NULL);
- index_frontend++) {
- dib8096p_set_output_mode(state->fe[index_frontend],
- OUTMODE_DIVERSITY);
- dib8096p_set_diversity_in(state->fe[index_frontend-1], 1);
- }
-
- /* turn off the diversity of the last chip */
- dib8096p_set_diversity_in(state->fe[index_frontend-1], 0);
}
return ret;
}
-static u16 dib8000_read_lock(struct dvb_frontend *fe)
-{
- struct dib8000_state *state = fe->demodulator_priv;
-
- if (state->revision == 0x8090)
- return dib8000_read_word(state, 570);
- return dib8000_read_word(state, 568);
-}
-
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 lock_slave = 0, lock;
u8 index_frontend;
- if (state->revision == 0x8090)
- lock = dib8000_read_word(state, 570);
- else
- lock = dib8000_read_word(state, 568);
-
+ lock = dib8000_read_lock(fe);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
lock_slave |= dib8000_read_lock(state->fe[index_frontend]);
@@ -3545,10 +3956,11 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
dib8000_reset(fe);
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */
+ state->current_demod_bw = 6000;
return fe;
- error:
+error:
kfree(state);
return NULL;
}
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index 9e7a2b170d55..b8c11e52c512 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -33,6 +33,8 @@ struct dib8000_config {
u8 output_mode;
u8 refclksel;
u8 enMpegOutput:1;
+
+ struct dibx000_bandwidth_config *plltable;
};
#define DEFAULT_DIB8000_I2C_ADDRESS 18
@@ -58,7 +60,7 @@ extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
uint8_t op, uint32_t timf);
extern int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll);
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio);
extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
@@ -147,7 +149,7 @@ static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
return 0;
}
static inline int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll)
+ struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -ENODEV;
diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h
index 5f484881d7b1..b538e0555c95 100644
--- a/drivers/media/dvb-frontends/dibx000_common.h
+++ b/drivers/media/dvb-frontends/dibx000_common.h
@@ -193,7 +193,8 @@ enum frontend_tune_state {
CT_DEMOD_STEP_8,
CT_DEMOD_STEP_9,
CT_DEMOD_STEP_10,
- CT_DEMOD_SEARCH_NEXT = 41,
+ CT_DEMOD_STEP_11,
+ CT_DEMOD_SEARCH_NEXT = 51,
CT_DEMOD_STEP_LOCKED,
CT_DEMOD_STOP,
diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
index 216c8c3702f8..5f1d6b5f1685 100644
--- a/drivers/media/dvb-frontends/drxd.h
+++ b/drivers/media/dvb-frontends/drxd.h
@@ -24,6 +24,7 @@
#ifndef _DRXD_H_
#define _DRXD_H_
+#include <linux/kconfig.h>
#include <linux/types.h>
#include <linux/i2c.h>
@@ -51,8 +52,7 @@ struct drxd_config {
s16(*osc_deviation) (void *priv, s16 dev, int flag);
};
-#if defined(CONFIG_DVB_DRXD) || \
- (defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DRXD)
extern
struct dvb_frontend *drxd_attach(const struct drxd_config *config,
void *priv, struct i2c_adapter *i2c,
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
index 94fecfbf14c1..e6667189ddce 100644
--- a/drivers/media/dvb-frontends/drxk.h
+++ b/drivers/media/dvb-frontends/drxk.h
@@ -1,6 +1,7 @@
#ifndef _DRXK_H_
#define _DRXK_H_
+#include <linux/kconfig.h>
#include <linux/types.h>
#include <linux/i2c.h>
@@ -52,8 +53,7 @@ struct drxk_config {
int qam_demod_parameter_count;
};
-#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DRXK)
extern struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index c2fc7da0d6bf..ec24d71e153d 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -1947,8 +1947,7 @@ static int ShutDown(struct drxk_state *state)
return 0;
}
-static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus,
- u32 Time)
+static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus)
{
int status = -EINVAL;
@@ -2490,32 +2489,6 @@ error:
return status;
}
-static int ReadIFAgc(struct drxk_state *state, u32 *pValue)
-{
- u16 agcDacLvl;
- int status;
- u16 Level = 0;
-
- dprintk(1, "\n");
-
- status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl);
- if (status < 0) {
- printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__);
- return status;
- }
-
- *pValue = 0;
-
- if (agcDacLvl > DRXK_AGC_DAC_OFFSET)
- Level = agcDacLvl - DRXK_AGC_DAC_OFFSET;
- if (Level < 14000)
- *pValue = (14000 - Level) / 4;
- else
- *pValue = 0;
-
- return status;
-}
-
static int GetQAMSignalToNoise(struct drxk_state *state,
s32 *pSignalToNoise)
{
@@ -2654,12 +2627,7 @@ static int GetDVBTSignalToNoise(struct drxk_state *state,
/* log(x) x = (16bits + 16bits) << 15 ->32 bits */
c = Log10Times100(SqrErrIQ);
- iMER = a + b;
- /* No negative MER, clip to zero */
- if (iMER > c)
- iMER -= c;
- else
- iMER = 0;
+ iMER = a + b - c;
}
*pSignalToNoise = iMER;
@@ -6380,46 +6348,257 @@ static int drxk_set_parameters(struct dvb_frontend *fe)
fe->ops.tuner_ops.get_if_frequency(fe, &IF);
Start(state, 0, IF);
+ /* After set_frontend, stats aren't avaliable */
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
/* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */
return 0;
}
-static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
+static int get_strength(struct drxk_state *state, u64 *strength)
{
+ int status;
+ struct SCfgAgc rfAgc, ifAgc;
+ u32 totalGain = 0;
+ u32 atten = 0;
+ u32 agcRange = 0;
+ u16 scu_lvl = 0;
+ u16 scu_coc = 0;
+ /* FIXME: those are part of the tuner presets */
+ u16 tunerRfGain = 50; /* Default value on az6007 driver */
+ u16 tunerIfGain = 40; /* Default value on az6007 driver */
+
+ *strength = 0;
+
+ if (IsDVBT(state)) {
+ rfAgc = state->m_dvbtRfAgcCfg;
+ ifAgc = state->m_dvbtIfAgcCfg;
+ } else if (IsQAM(state)) {
+ rfAgc = state->m_qamRfAgcCfg;
+ ifAgc = state->m_qamIfAgcCfg;
+ } else {
+ rfAgc = state->m_atvRfAgcCfg;
+ ifAgc = state->m_atvIfAgcCfg;
+ }
+
+ if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+ /* SCU outputLevel */
+ status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl);
+ if (status < 0)
+ return status;
+
+ /* SCU c.o.c. */
+ read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc);
+ if (status < 0)
+ return status;
+
+ if (((u32) scu_lvl + (u32) scu_coc) < 0xffff)
+ rfAgc.outputLevel = scu_lvl + scu_coc;
+ else
+ rfAgc.outputLevel = 0xffff;
+
+ /* Take RF gain into account */
+ totalGain += tunerRfGain;
+
+ /* clip output value */
+ if (rfAgc.outputLevel < rfAgc.minOutputLevel)
+ rfAgc.outputLevel = rfAgc.minOutputLevel;
+ if (rfAgc.outputLevel > rfAgc.maxOutputLevel)
+ rfAgc.outputLevel = rfAgc.maxOutputLevel;
+
+ agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel);
+ if (agcRange > 0) {
+ atten += 100UL *
+ ((u32)(tunerRfGain)) *
+ ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel))
+ / agcRange;
+ }
+ }
+
+ if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) {
+ status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A,
+ &ifAgc.outputLevel);
+ if (status < 0)
+ return status;
+
+ status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A,
+ &ifAgc.top);
+ if (status < 0)
+ return status;
+
+ /* Take IF gain into account */
+ totalGain += (u32) tunerIfGain;
+
+ /* clip output value */
+ if (ifAgc.outputLevel < ifAgc.minOutputLevel)
+ ifAgc.outputLevel = ifAgc.minOutputLevel;
+ if (ifAgc.outputLevel > ifAgc.maxOutputLevel)
+ ifAgc.outputLevel = ifAgc.maxOutputLevel;
+
+ agcRange = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel);
+ if (agcRange > 0) {
+ atten += 100UL *
+ ((u32)(tunerIfGain)) *
+ ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel))
+ / agcRange;
+ }
+ }
+
+ /*
+ * Convert to 0..65535 scale.
+ * If it can't be measured (AGC is disabled), just show 100%.
+ */
+ if (totalGain > 0)
+ *strength = (65535UL * atten / totalGain / 100);
+ else
+ *strength = 65535;
+
+ return 0;
+}
+
+static int drxk_get_stats(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct drxk_state *state = fe->demodulator_priv;
+ int status;
u32 stat;
-
- dprintk(1, "\n");
+ u16 reg16;
+ u32 post_bit_count;
+ u32 post_bit_err_count;
+ u32 post_bit_error_scale;
+ u32 pre_bit_err_count;
+ u32 pre_bit_count;
+ u32 pkt_count;
+ u32 pkt_error_count;
+ s32 cnr;
if (state->m_DrxkState == DRXK_NO_DEV)
return -ENODEV;
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
- *status = 0;
- GetLockStatus(state, &stat, 0);
+ /* get status */
+ state->fe_status = 0;
+ GetLockStatus(state, &stat);
if (stat == MPEG_LOCK)
- *status |= 0x1f;
+ state->fe_status |= 0x1f;
if (stat == FEC_LOCK)
- *status |= 0x0f;
+ state->fe_status |= 0x0f;
if (stat == DEMOD_LOCK)
- *status |= 0x07;
- return 0;
+ state->fe_status |= 0x07;
+
+ /*
+ * Estimate signal strength from AGC
+ */
+ get_strength(state, &c->strength.stat[0].uvalue);
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+
+
+ if (stat >= DEMOD_LOCK) {
+ GetSignalToNoise(state, &cnr);
+ c->cnr.stat[0].svalue = cnr * 100;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ } else {
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ if (stat < FEC_LOCK) {
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return 0;
+ }
+
+ /* Get post BER */
+
+ /* BER measurement is valid if at least FEC lock is achieved */
+
+ /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written
+ to set nr of symbols or bits over which
+ to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */
+
+ /* Read registers for post/preViterbi BER calculation */
+ status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, &reg16);
+ if (status < 0)
+ goto error;
+ pre_bit_err_count = reg16;
+
+ status = read16(state, OFDM_EC_VD_IN_BIT_CNT__A , &reg16);
+ if (status < 0)
+ goto error;
+ pre_bit_count = reg16;
+
+ /* Number of bit-errors */
+ status = read16(state, FEC_RS_NR_BIT_ERRORS__A, &reg16);
+ if (status < 0)
+ goto error;
+ post_bit_err_count = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PRESCALE__A, &reg16);
+ if (status < 0)
+ goto error;
+ post_bit_error_scale = reg16;
+
+ status = read16(state, FEC_RS_MEASUREMENT_PERIOD__A, &reg16);
+ if (status < 0)
+ goto error;
+ pkt_count = reg16;
+
+ status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, &reg16);
+ if (status < 0)
+ goto error;
+ pkt_error_count = reg16;
+ write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0);
+
+ post_bit_err_count *= post_bit_error_scale;
+
+ post_bit_count = pkt_count * 204 * 8;
+
+ /* Store the results */
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += pkt_error_count;
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += pkt_count;
+
+ c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[0].uvalue += pre_bit_err_count;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[0].uvalue += pre_bit_count;
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += post_bit_err_count;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += post_bit_count;
+
+error:
+ return status;
}
-static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber)
+
+static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct drxk_state *state = fe->demodulator_priv;
+ int rc;
dprintk(1, "\n");
- if (state->m_DrxkState == DRXK_NO_DEV)
- return -ENODEV;
- if (state->m_DrxkState == DRXK_UNINITIALIZED)
- return -EAGAIN;
+ rc = drxk_get_stats(fe);
+ if (rc < 0)
+ return rc;
+
+ *status = state->fe_status;
- *ber = 0;
return 0;
}
@@ -6427,7 +6606,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
u16 *strength)
{
struct drxk_state *state = fe->demodulator_priv;
- u32 val = 0;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
dprintk(1, "\n");
@@ -6436,8 +6615,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe,
if (state->m_DrxkState == DRXK_UNINITIALIZED)
return -EAGAIN;
- ReadIFAgc(state, &val);
- *strength = val & 0xffff;
+ *strength = c->strength.stat[0].uvalue;
return 0;
}
@@ -6454,6 +6632,10 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr)
return -EAGAIN;
GetSignalToNoise(state, &snr2);
+
+ /* No negative SNR, clip to zero */
+ if (snr2 < 0)
+ snr2 = 0;
*snr = snr2 & 0xffff;
return 0;
}
@@ -6529,7 +6711,6 @@ static struct dvb_frontend_ops drxk_ops = {
.get_tune_settings = drxk_get_tune_settings,
.read_status = drxk_read_status,
- .read_ber = drxk_read_ber,
.read_signal_strength = drxk_read_signal_strength,
.read_snr = drxk_read_snr,
.read_ucblocks = drxk_read_ucblocks,
@@ -6538,6 +6719,7 @@ static struct dvb_frontend_ops drxk_ops = {
struct dvb_frontend *drxk_attach(const struct drxk_config *config,
struct i2c_adapter *i2c)
{
+ struct dtv_frontend_properties *p;
struct drxk_state *state = NULL;
u8 adr = config->adr;
int status;
@@ -6618,6 +6800,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
} else if (init_drxk(state) < 0)
goto error;
+
+ /* Initialize stats */
+ p = &state->frontend.dtv_property_cache;
+ p->strength.len = 1;
+ p->cnr.len = 1;
+ p->block_error.len = 1;
+ p->block_count.len = 1;
+ p->pre_bit_error.len = 1;
+ p->pre_bit_count.len = 1;
+ p->post_bit_error.len = 1;
+ p->post_bit_count.len = 1;
+
+ p->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
printk(KERN_INFO "drxk: frontend initialized.\n");
return &state->frontend;
diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h
index d18a896a9835..b8424f15f9a6 100644
--- a/drivers/media/dvb-frontends/drxk_hard.h
+++ b/drivers/media/dvb-frontends/drxk_hard.h
@@ -345,6 +345,8 @@ struct drxk_state {
bool antenna_dvbt;
u16 antenna_gpio;
+ fe_status_t fe_status;
+
/* Firmware */
const char *microcode_name;
struct completion fw_wait_load;
diff --git a/drivers/media/dvb-frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h
index 23e16c12f234..761613f9fd5a 100644
--- a/drivers/media/dvb-frontends/drxk_map.h
+++ b/drivers/media/dvb-frontends/drxk_map.h
@@ -10,6 +10,7 @@
#define FEC_RS_COMM_EXEC_STOP 0x0
#define FEC_RS_MEASUREMENT_PERIOD__A 0x1C30012
#define FEC_RS_MEASUREMENT_PRESCALE__A 0x1C30013
+#define FEC_RS_NR_BIT_ERRORS__A 0x1C30014
#define FEC_OC_MODE__A 0x1C40011
#define FEC_OC_MODE_PARITY__M 0x1
#define FEC_OC_DTO_MODE__A 0x1C40014
@@ -129,6 +130,8 @@
#define OFDM_EC_SB_PRIOR__A 0x3410013
#define OFDM_EC_SB_PRIOR_HI 0x0
#define OFDM_EC_SB_PRIOR_LO 0x1
+#define OFDM_EC_VD_ERR_BIT_CNT__A 0x3420017
+#define OFDM_EC_VD_IN_BIT_CNT__A 0x3420018
#define OFDM_EQ_TOP_TD_TPS_CONST__A 0x3010054
#define OFDM_EQ_TOP_TD_TPS_CONST__M 0x3
#define OFDM_EQ_TOP_TD_TPS_CONST_64QAM 0x2
diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h
index 478ad66c63d7..f9c21fb7af13 100644
--- a/drivers/media/dvb-frontends/ds3000.h
+++ b/drivers/media/dvb-frontends/ds3000.h
@@ -22,6 +22,7 @@
#ifndef DS3000_H
#define DS3000_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct ds3000_config {
@@ -34,8 +35,7 @@ struct ds3000_config {
void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
-#if defined(CONFIG_DVB_DS3000) || \
- (defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DS3000)
extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h
index 1fcb987d6386..0cbf96105631 100644
--- a/drivers/media/dvb-frontends/dvb_dummy_fe.h
+++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h
@@ -22,11 +22,11 @@
#ifndef DVB_DUMMY_FE_H
#define DVB_DUMMY_FE_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \
-defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DUMMY_FE)
extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void);
extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void);
extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void);
diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h
index b8479719d7f1..37558403068d 100644
--- a/drivers/media/dvb-frontends/ec100.h
+++ b/drivers/media/dvb-frontends/ec100.h
@@ -22,6 +22,7 @@
#ifndef EC100_H
#define EC100_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct ec100_config {
@@ -30,8 +31,7 @@ struct ec100_config {
};
-#if defined(CONFIG_DVB_EC100) || \
- (defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_EC100)
extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h
index 4ad00d79aa77..05cd13028a91 100644
--- a/drivers/media/dvb-frontends/hd29l2.h
+++ b/drivers/media/dvb-frontends/hd29l2.h
@@ -23,6 +23,7 @@
#ifndef HD29L2_H
#define HD29L2_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct hd29l2_config {
@@ -50,8 +51,7 @@ struct hd29l2_config {
};
-#if defined(CONFIG_DVB_HD29L2) || \
- (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_HD29L2)
extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c
index 0cb3f0f74c9c..c77002fcc8e2 100644
--- a/drivers/media/dvb-frontends/isl6421.c
+++ b/drivers/media/dvb-frontends/isl6421.c
@@ -89,6 +89,30 @@ static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
}
+static int isl6421_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ switch (tone) {
+ case SEC_TONE_ON:
+ isl6421->config |= ISL6421_ENT1;
+ break;
+ case SEC_TONE_OFF:
+ isl6421->config &= ~ISL6421_ENT1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
static void isl6421_release(struct dvb_frontend *fe)
{
/* power off */
@@ -100,7 +124,7 @@ static void isl6421_release(struct dvb_frontend *fe)
}
struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
- u8 override_set, u8 override_clear)
+ u8 override_set, u8 override_clear, bool override_tone)
{
struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
if (!isl6421)
@@ -131,6 +155,8 @@ struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter
/* override frontend ops */
fe->ops.set_voltage = isl6421_set_voltage;
fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+ if (override_tone)
+ fe->ops.set_tone = isl6421_set_tone;
return fe;
}
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index e7ca7d12b50a..630e7f8a150e 100644
--- a/drivers/media/dvb-frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -42,10 +42,10 @@
#if IS_ENABLED(CONFIG_DVB_ISL6421)
/* override_set and override_clear control which system register bits (above) to always set & clear */
extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
- u8 override_set, u8 override_clear);
+ u8 override_set, u8 override_clear, bool override_tone);
#else
static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
- u8 override_set, u8 override_clear)
+ u8 override_set, u8 override_clear, bool override_tone)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb-frontends/it913x-fe.h b/drivers/media/dvb-frontends/it913x-fe.h
index 07fa4594c12b..df0ad4207343 100644
--- a/drivers/media/dvb-frontends/it913x-fe.h
+++ b/drivers/media/dvb-frontends/it913x-fe.h
@@ -21,6 +21,7 @@
#ifndef IT913X_FE_H
#define IT913X_FE_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -38,8 +39,7 @@ struct ite_config {
u8 read_slevel;
};
-#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \
-defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_IT913X_FE)
extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap,
u8 i2c_addr, struct ite_config *config);
#else
diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h
index 67e89d616d50..1a735a75aa98 100644
--- a/drivers/media/dvb-frontends/ix2505v.h
+++ b/drivers/media/dvb-frontends/ix2505v.h
@@ -20,6 +20,7 @@
#ifndef DVB_IX2505V_H
#define DVB_IX2505V_H
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -48,8 +49,7 @@ struct ix2505v_config {
};
-#if defined(CONFIG_DVB_IX2505V) || \
- (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_IX2505V)
extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
const struct ix2505v_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h
index 9e2c0f41199a..194a07a78dc1 100644
--- a/drivers/media/dvb-frontends/lg2160.h
+++ b/drivers/media/dvb-frontends/lg2160.h
@@ -22,6 +22,7 @@
#ifndef _LG2160_H_
#define _LG2160_H_
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -56,18 +57,17 @@ struct lg2160_config {
u16 if_khz;
/* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
- int deny_i2c_rptr:1;
+ unsigned int deny_i2c_rptr:1;
/* spectral inversion - 0:disabled 1:enabled */
- int spectral_inversion:1;
+ unsigned int spectral_inversion:1;
unsigned int output_if;
enum lg2160_spi_clock spi_clock;
enum lg_chip_type lg_chip;
};
-#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LG2160)
extern
struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h
index 02172eca4d47..d9ab556c1b27 100644
--- a/drivers/media/dvb-frontends/lgdt3305.h
+++ b/drivers/media/dvb-frontends/lgdt3305.h
@@ -22,6 +22,7 @@
#ifndef _LGDT3305_H_
#define _LGDT3305_H_
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -73,8 +74,7 @@ struct lgdt3305_config {
enum lgdt_demod_chip_type demod_chip;
};
-#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LGDT3305)
extern
struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
struct i2c_adapter *i2c_adap);
diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h
index d14176787a7d..c2da59614727 100644
--- a/drivers/media/dvb-frontends/lgs8gl5.h
+++ b/drivers/media/dvb-frontends/lgs8gl5.h
@@ -23,6 +23,7 @@
#ifndef LGS8GL5_H
#define LGS8GL5_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct lgs8gl5_config {
@@ -30,8 +31,7 @@ struct lgs8gl5_config {
u8 demod_address;
};
-#if defined(CONFIG_DVB_LGS8GL5) || \
- (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LGS8GL5)
extern struct dvb_frontend *lgs8gl5_attach(
const struct lgs8gl5_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h
index 33c3c5e162fa..dadb78bf61a9 100644
--- a/drivers/media/dvb-frontends/lgs8gxx.h
+++ b/drivers/media/dvb-frontends/lgs8gxx.h
@@ -26,6 +26,7 @@
#ifndef __LGS8GXX_H__
#define __LGS8GXX_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
@@ -79,8 +80,7 @@ struct lgs8gxx_config {
u8 tuner_address;
};
-#if defined(CONFIG_DVB_LGS8GXX) || \
- (defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LGS8GXX)
extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h
index c059b165318f..b327a4f31d16 100644
--- a/drivers/media/dvb-frontends/lnbh24.h
+++ b/drivers/media/dvb-frontends/lnbh24.h
@@ -23,6 +23,8 @@
#ifndef _LNBH24_H
#define _LNBH24_H
+#include <linux/kconfig.h>
+
/* system register bits */
#define LNBH24_OLF 0x01
#define LNBH24_OTF 0x02
@@ -35,8 +37,7 @@
#include <linux/dvb/frontend.h>
-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LNBP21)
/* override_set and override_clear control which
system register bits (above) to always set & clear */
extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h
index fcdf1c650dde..dbcbcc2f20a3 100644
--- a/drivers/media/dvb-frontends/lnbp21.h
+++ b/drivers/media/dvb-frontends/lnbp21.h
@@ -27,6 +27,8 @@
#ifndef _LNBP21_H
#define _LNBP21_H
+#include <linux/kconfig.h>
+
/* system register bits */
/* [RO] 0=OK; 1=over current limit flag */
#define LNBP21_OLF 0x01
@@ -55,8 +57,7 @@
#include <linux/dvb/frontend.h>
-#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LNBP21)
/* override_set and override_clear control which
system register bits (above) to always set & clear */
extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h
index 63e2dec7e68a..63861b311dd8 100644
--- a/drivers/media/dvb-frontends/lnbp22.h
+++ b/drivers/media/dvb-frontends/lnbp22.h
@@ -28,6 +28,8 @@
#ifndef _LNBP22_H
#define _LNBP22_H
+#include <linux/kconfig.h>
+
/* Enable */
#define LNBP22_EN 0x10
/* Voltage selection */
@@ -37,8 +39,7 @@
#include <linux/dvb/frontend.h>
-#if defined(CONFIG_DVB_LNBP22) || \
- (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_LNBP22)
/*
* override_set and override_clear control which system register bits (above)
* to always set & clear
diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h
index 5a8023e5a4b8..14ce31e76ae6 100644
--- a/drivers/media/dvb-frontends/m88rs2000.h
+++ b/drivers/media/dvb-frontends/m88rs2000.h
@@ -20,6 +20,7 @@
#ifndef M88RS2000_H
#define M88RS2000_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -40,8 +41,7 @@ enum {
CALL_IS_READ,
};
-#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_M88RS2000)
extern struct dvb_frontend *m88rs2000_attach(
const struct m88rs2000_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index f19cd7367040..856374bd3676 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -20,10 +20,24 @@
#include "dvb_frontend.h"
#include "mb86a20s.h"
+#define NUM_LAYERS 3
+
static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+enum mb86a20s_bandwidth {
+ MB86A20S_13SEG = 0,
+ MB86A20S_13SEG_PARTIAL = 1,
+ MB86A20S_1SEG = 2,
+ MB86A20S_3SEG = 3,
+};
+
+u8 mb86a20s_subchannel[] = {
+ 0xb0, 0xc0, 0xd0, 0xe0,
+ 0xf0, 0x00, 0x10, 0x20,
+};
+
struct mb86a20s_state {
struct i2c_adapter *i2c;
const struct mb86a20s_config *config;
@@ -31,7 +45,13 @@ struct mb86a20s_state {
struct dvb_frontend frontend;
- u32 estimated_rate[3];
+ u32 if_freq;
+ enum mb86a20s_bandwidth bw;
+ bool inversion;
+ u32 subchannel;
+
+ u32 estimated_rate[NUM_LAYERS];
+ unsigned long get_strength_time;
bool need_init;
};
@@ -47,35 +67,33 @@ struct regdata {
* Initialization sequence: Use whatevere default values that PV SBTVD
* does on its initialisation, obtained via USB snoop
*/
-static struct regdata mb86a20s_init[] = {
+static struct regdata mb86a20s_init1[] = {
{ 0x70, 0x0f },
{ 0x70, 0xff },
{ 0x08, 0x01 },
- { 0x09, 0x3e },
- { 0x50, 0xd1 }, { 0x51, 0x22 },
- { 0x39, 0x01 },
- { 0x71, 0x00 },
- { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 },
- { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 },
+ { 0x50, 0xd1 }, { 0x51, 0x20 },
+};
+
+static struct regdata mb86a20s_init2[] = {
{ 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 },
{ 0x3b, 0x21 },
- { 0x3c, 0x3a },
+ { 0x3c, 0x38 },
{ 0x01, 0x0d },
- { 0x04, 0x08 }, { 0x05, 0x05 },
+ { 0x04, 0x08 }, { 0x05, 0x03 },
{ 0x04, 0x0e }, { 0x05, 0x00 },
- { 0x04, 0x0f }, { 0x05, 0x14 },
- { 0x04, 0x0b }, { 0x05, 0x8c },
+ { 0x04, 0x0f }, { 0x05, 0x37 },
+ { 0x04, 0x0b }, { 0x05, 0x78 },
{ 0x04, 0x00 }, { 0x05, 0x00 },
- { 0x04, 0x01 }, { 0x05, 0x07 },
- { 0x04, 0x02 }, { 0x05, 0x0f },
- { 0x04, 0x03 }, { 0x05, 0xa0 },
+ { 0x04, 0x01 }, { 0x05, 0x1e },
+ { 0x04, 0x02 }, { 0x05, 0x07 },
+ { 0x04, 0x03 }, { 0x05, 0xd0 },
{ 0x04, 0x09 }, { 0x05, 0x00 },
{ 0x04, 0x0a }, { 0x05, 0xff },
- { 0x04, 0x27 }, { 0x05, 0x64 },
+ { 0x04, 0x27 }, { 0x05, 0x00 },
{ 0x04, 0x28 }, { 0x05, 0x00 },
- { 0x04, 0x1e }, { 0x05, 0xff },
- { 0x04, 0x29 }, { 0x05, 0x0a },
- { 0x04, 0x32 }, { 0x05, 0x0a },
+ { 0x04, 0x1e }, { 0x05, 0x00 },
+ { 0x04, 0x29 }, { 0x05, 0x64 },
+ { 0x04, 0x32 }, { 0x05, 0x02 },
{ 0x04, 0x14 }, { 0x05, 0x02 },
{ 0x04, 0x04 }, { 0x05, 0x00 },
{ 0x04, 0x05 }, { 0x05, 0x22 },
@@ -142,39 +160,39 @@ static struct regdata mb86a20s_init[] = {
{ 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */
{ 0x50, 0xd6 }, { 0x51, 0x1f },
{ 0x50, 0xd2 }, { 0x51, 0x03 },
- { 0x50, 0xd7 }, { 0x51, 0x3f },
- { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 },
- { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c },
+ { 0x50, 0xd7 }, { 0x51, 0xbf },
+ { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xff },
+ { 0x28, 0x46 }, { 0x29, 0x00 }, { 0x2a, 0x1a }, { 0x2b, 0x0c },
{ 0x04, 0x40 }, { 0x05, 0x00 },
- { 0x28, 0x00 }, { 0x29, 0x10 },
- { 0x28, 0x05 }, { 0x29, 0x02 },
+ { 0x28, 0x00 }, { 0x2b, 0x08 },
+ { 0x28, 0x05 }, { 0x2b, 0x00 },
{ 0x1c, 0x01 },
- { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 },
- { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d },
- { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
- { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 },
- { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 },
- { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 },
- { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
- { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 },
- { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e },
- { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e },
- { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 },
- { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
- { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 },
- { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 },
- { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe },
- { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 },
- { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee },
- { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 },
- { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f },
- { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 },
- { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 },
- { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a },
- { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc },
- { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba },
- { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 },
+ { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x1f },
+ { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x18 },
+ { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x12 },
+ { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x30 },
+ { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x37 },
+ { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 },
+ { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x09 },
+ { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x06 },
+ { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7b },
+ { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x76 },
+ { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7d },
+ { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x08 },
+ { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0b },
+ { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
+ { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf2 },
+ { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf3 },
+ { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x05 },
+ { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 },
+ { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f },
+ { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xef },
+ { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xd8 },
+ { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xf1 },
+ { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x3d },
+ { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x94 },
+ { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xba },
{ 0x50, 0x1e }, { 0x51, 0x5d },
{ 0x50, 0x22 }, { 0x51, 0x00 },
{ 0x50, 0x23 }, { 0x51, 0xc8 },
@@ -183,6 +201,8 @@ static struct regdata mb86a20s_init[] = {
{ 0x50, 0x26 }, { 0x51, 0x00 },
{ 0x50, 0x27 }, { 0x51, 0xc3 },
{ 0x50, 0x39 }, { 0x51, 0x02 },
+ { 0xec, 0x0f },
+ { 0xeb, 0x1f },
{ 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 },
{ 0xd0, 0x00 },
};
@@ -308,15 +328,23 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n",
__func__, *status, val);
- return 0;
+ return val;
}
static int mb86a20s_read_signal_strength(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int rc;
unsigned rf_max, rf_min, rf;
+ if (state->get_strength_time &&
+ (!time_after(jiffies, state->get_strength_time)))
+ return c->strength.stat[0].uvalue;
+
+ /* Reset its value if an error happen */
+ c->strength.stat[0].uvalue = 0;
+
/* Does a binary search to get RF strength */
rf_max = 0xfff;
rf_min = 0;
@@ -331,7 +359,7 @@ static int mb86a20s_read_signal_strength(struct dvb_frontend *fe)
rc = mb86a20s_writereg(state, 0x04, 0x20);
if (rc < 0)
return rc;
- rc = mb86a20s_writereg(state, 0x04, rf);
+ rc = mb86a20s_writereg(state, 0x05, rf);
if (rc < 0)
return rc;
@@ -346,15 +374,19 @@ static int mb86a20s_read_signal_strength(struct dvb_frontend *fe)
rf = (rf_max + rf_min) / 2;
/* Rescale it from 2^12 (4096) to 2^16 */
- rf <<= (16 - 12);
+ rf = rf << (16 - 12);
+ if (rf)
+ rf |= (1 << 12) - 1;
+
dev_dbg(&state->i2c->dev,
"%s: signal strength = %d (%d < RF=%d < %d)\n",
__func__, rf, rf_min, rf >> 4, rf_max);
- return rf;
+ c->strength.stat[0].uvalue = rf;
+ state->get_strength_time = jiffies +
+ msecs_to_jiffies(1000);
+ return 0;
}
} while (1);
-
- return 0;
}
static int mb86a20s_get_modulation(struct mb86a20s_state *state,
@@ -534,12 +566,13 @@ static u32 isdbt_rate[3][5][4] = {
};
static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
- u32 modulation, u32 fec, u32 interleaving,
+ u32 modulation, u32 forward_error_correction,
+ u32 interleaving,
u32 segment)
{
struct mb86a20s_state *state = fe->demodulator_priv;
u32 rate;
- int m, f, i;
+ int mod, fec, guard;
/*
* If modulation/fec/interleaving is not detected, the default is
@@ -550,54 +583,54 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
case DQPSK:
case QPSK:
default:
- m = 0;
+ mod = 0;
break;
case QAM_16:
- m = 1;
+ mod = 1;
break;
case QAM_64:
- m = 2;
+ mod = 2;
break;
}
- switch (fec) {
+ switch (forward_error_correction) {
default:
case FEC_1_2:
case FEC_AUTO:
- f = 0;
+ fec = 0;
break;
case FEC_2_3:
- f = 1;
+ fec = 1;
break;
case FEC_3_4:
- f = 2;
+ fec = 2;
break;
case FEC_5_6:
- f = 3;
+ fec = 3;
break;
case FEC_7_8:
- f = 4;
+ fec = 4;
break;
}
switch (interleaving) {
default:
case GUARD_INTERVAL_1_4:
- i = 0;
+ guard = 0;
break;
case GUARD_INTERVAL_1_8:
- i = 1;
+ guard = 1;
break;
case GUARD_INTERVAL_1_16:
- i = 2;
+ guard = 2;
break;
case GUARD_INTERVAL_1_32:
- i = 3;
+ guard = 3;
break;
}
/* Samples BER at BER_SAMPLING_RATE seconds */
- rate = isdbt_rate[m][f][i] * segment * BER_SAMPLING_RATE;
+ rate = isdbt_rate[mod][fec][guard] * segment * BER_SAMPLING_RATE;
/* Avoids sampling too quickly or to overflow the register */
if (rate < 256)
@@ -607,18 +640,18 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
dev_dbg(&state->i2c->dev,
"%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n",
- __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000,
+ __func__, 'A' + layer,
+ segment * isdbt_rate[mod][fec][guard]/1000,
rate, rate);
- state->estimated_rate[i] = rate;
+ state->estimated_rate[layer] = rate;
}
-
static int mb86a20s_get_frontend(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int i, rc;
+ int layer, rc;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
@@ -636,43 +669,43 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
/* Get per-layer data */
- for (i = 0; i < 3; i++) {
+ for (layer = 0; layer < NUM_LAYERS; layer++) {
dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n",
- __func__, 'A' + i);
+ __func__, 'A' + layer);
- rc = mb86a20s_get_segment_count(state, i);
+ rc = mb86a20s_get_segment_count(state, layer);
if (rc < 0)
goto noperlayer_error;
if (rc >= 0 && rc < 14) {
- c->layer[i].segment_count = rc;
+ c->layer[layer].segment_count = rc;
} else {
- c->layer[i].segment_count = 0;
- state->estimated_rate[i] = 0;
+ c->layer[layer].segment_count = 0;
+ state->estimated_rate[layer] = 0;
continue;
}
- c->isdbt_layer_enabled |= 1 << i;
- rc = mb86a20s_get_modulation(state, i);
+ c->isdbt_layer_enabled |= 1 << layer;
+ rc = mb86a20s_get_modulation(state, layer);
if (rc < 0)
goto noperlayer_error;
dev_dbg(&state->i2c->dev, "%s: modulation %d.\n",
__func__, rc);
- c->layer[i].modulation = rc;
- rc = mb86a20s_get_fec(state, i);
+ c->layer[layer].modulation = rc;
+ rc = mb86a20s_get_fec(state, layer);
if (rc < 0)
goto noperlayer_error;
dev_dbg(&state->i2c->dev, "%s: FEC %d.\n",
__func__, rc);
- c->layer[i].fec = rc;
- rc = mb86a20s_get_interleaving(state, i);
+ c->layer[layer].fec = rc;
+ rc = mb86a20s_get_interleaving(state, layer);
if (rc < 0)
goto noperlayer_error;
dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n",
__func__, rc);
- c->layer[i].interleaving = rc;
- mb86a20s_layer_bitrate(fe, i, c->layer[i].modulation,
- c->layer[i].fec,
- c->layer[i].interleaving,
- c->layer[i].segment_count);
+ c->layer[layer].interleaving = rc;
+ mb86a20s_layer_bitrate(fe, layer, c->layer[layer].modulation,
+ c->layer[layer].fec,
+ c->layer[layer].interleaving,
+ c->layer[layer].segment_count);
}
rc = mb86a20s_writereg(state, 0x6d, 0x84);
@@ -735,7 +768,6 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe)
/* Reset the counters, if the channel changed */
if (state->last_frequency != c->frequency) {
- memset(&c->strength, 0, sizeof(c->strength));
memset(&c->cnr, 0, sizeof(c->cnr));
memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error));
memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count));
@@ -799,7 +831,7 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe,
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
- if (layer >= 3)
+ if (layer >= NUM_LAYERS)
return -EINVAL;
/* Check if the BER measures are already available */
@@ -933,7 +965,7 @@ static int mb86a20s_get_post_ber(struct dvb_frontend *fe,
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
- if (layer >= 3)
+ if (layer >= NUM_LAYERS)
return -EINVAL;
/* Check if the BER measures are already available */
@@ -1060,7 +1092,7 @@ static int mb86a20s_get_blk_error(struct dvb_frontend *fe,
u32 collect_rate;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
- if (layer >= 3)
+ if (layer >= NUM_LAYERS)
return -EINVAL;
/* Check if the PER measures are already available */
@@ -1095,7 +1127,7 @@ static int mb86a20s_get_blk_error(struct dvb_frontend *fe,
if (rc < 0)
return rc;
*error |= rc;
- dev_err(&state->i2c->dev, "%s: block error for layer %c: %d.\n",
+ dev_dbg(&state->i2c->dev, "%s: block error for layer %c: %d.\n",
__func__, 'A' + layer, *error);
/* Read Bit Count */
@@ -1386,7 +1418,7 @@ static int mb86a20s_get_main_CNR(struct dvb_frontend *fe)
return rc;
if (!(rc & 0x40)) {
- dev_info(&state->i2c->dev, "%s: CNR is not available yet.\n",
+ dev_dbg(&state->i2c->dev, "%s: CNR is not available yet.\n",
__func__);
return -EBUSY;
}
@@ -1425,7 +1457,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
struct mb86a20s_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
u32 mer, cnr;
- int rc, val, i;
+ int rc, val, layer;
struct linear_segments *segs;
unsigned segs_len;
@@ -1441,33 +1473,33 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
/* Check if data is available */
if (!(rc & 0x01)) {
- dev_info(&state->i2c->dev,
+ dev_dbg(&state->i2c->dev,
"%s: MER measures aren't available yet.\n", __func__);
return -EBUSY;
}
/* Read all layers */
- for (i = 0; i < 3; i++) {
- if (!(c->isdbt_layer_enabled & (1 << i))) {
- c->cnr.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ for (layer = 0; layer < NUM_LAYERS; layer++) {
+ if (!(c->isdbt_layer_enabled & (1 << layer))) {
+ c->cnr.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
continue;
}
- rc = mb86a20s_writereg(state, 0x50, 0x52 + i * 3);
+ rc = mb86a20s_writereg(state, 0x50, 0x52 + layer * 3);
if (rc < 0)
return rc;
rc = mb86a20s_readreg(state, 0x51);
if (rc < 0)
return rc;
mer = rc << 16;
- rc = mb86a20s_writereg(state, 0x50, 0x53 + i * 3);
+ rc = mb86a20s_writereg(state, 0x50, 0x53 + layer * 3);
if (rc < 0)
return rc;
rc = mb86a20s_readreg(state, 0x51);
if (rc < 0)
return rc;
mer |= rc << 8;
- rc = mb86a20s_writereg(state, 0x50, 0x54 + i * 3);
+ rc = mb86a20s_writereg(state, 0x50, 0x54 + layer * 3);
if (rc < 0)
return rc;
rc = mb86a20s_readreg(state, 0x51);
@@ -1475,7 +1507,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
return rc;
mer |= rc;
- switch (c->layer[i].modulation) {
+ switch (c->layer[layer].modulation) {
case DQPSK:
case QPSK:
segs = cnr_qpsk_table;
@@ -1493,12 +1525,12 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe)
}
cnr = interpolate_value(mer, segs, segs_len);
- c->cnr.stat[1 + i].scale = FE_SCALE_DECIBEL;
- c->cnr.stat[1 + i].svalue = cnr;
+ c->cnr.stat[1 + layer].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[1 + layer].svalue = cnr;
dev_dbg(&state->i2c->dev,
"%s: CNR for layer %c is %d.%03d dB (MER = %d).\n",
- __func__, 'A' + i, cnr / 1000, cnr % 1000, mer);
+ __func__, 'A' + layer, cnr / 1000, cnr % 1000, mer);
}
@@ -1526,7 +1558,7 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int i;
+ int layer;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
@@ -1536,35 +1568,35 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe)
c->strength.len = 1;
/* Per-layer stats - 3 layers + global */
- c->cnr.len = 4;
- c->pre_bit_error.len = 4;
- c->pre_bit_count.len = 4;
- c->post_bit_error.len = 4;
- c->post_bit_count.len = 4;
- c->block_error.len = 4;
- c->block_count.len = 4;
+ c->cnr.len = NUM_LAYERS + 1;
+ c->pre_bit_error.len = NUM_LAYERS + 1;
+ c->pre_bit_count.len = NUM_LAYERS + 1;
+ c->post_bit_error.len = NUM_LAYERS + 1;
+ c->post_bit_count.len = NUM_LAYERS + 1;
+ c->block_error.len = NUM_LAYERS + 1;
+ c->block_count.len = NUM_LAYERS + 1;
/* Signal is always available */
c->strength.stat[0].scale = FE_SCALE_RELATIVE;
c->strength.stat[0].uvalue = 0;
/* Put all of them at FE_SCALE_NOT_AVAILABLE */
- for (i = 0; i < 4; i++) {
- c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
- c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+ for (layer = 0; layer < NUM_LAYERS + 1; layer++) {
+ c->cnr.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE;
}
}
-static int mb86a20s_get_stats(struct dvb_frontend *fe)
+static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr)
{
struct mb86a20s_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int rc = 0, i;
+ int rc = 0, layer;
u32 bit_error = 0, bit_count = 0;
u32 t_pre_bit_error = 0, t_pre_bit_count = 0;
u32 t_post_bit_error = 0, t_post_bit_count = 0;
@@ -1580,90 +1612,98 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
/* Get per-layer stats */
mb86a20s_get_blk_error_layer_CNR(fe);
- for (i = 0; i < 3; i++) {
- if (c->isdbt_layer_enabled & (1 << i)) {
+ /*
+ * At state 7, only CNR is available
+ * For BER measures, state=9 is required
+ * FIXME: we may get MER measures with state=8
+ */
+ if (status_nr < 9)
+ return 0;
+
+ for (layer = 0; layer < NUM_LAYERS; layer++) {
+ if (c->isdbt_layer_enabled & (1 << layer)) {
/* Layer is active and has rc segments */
active_layers++;
/* Handle BER before vterbi */
- rc = mb86a20s_get_pre_ber(fe, i,
+ rc = mb86a20s_get_pre_ber(fe, layer,
&bit_error, &bit_count);
if (rc >= 0) {
- c->pre_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->pre_bit_error.stat[1 + i].uvalue += bit_error;
- c->pre_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->pre_bit_count.stat[1 + i].uvalue += bit_count;
+ c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->pre_bit_error.stat[1 + layer].uvalue += bit_error;
+ c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->pre_bit_count.stat[1 + layer].uvalue += bit_count;
} else if (rc != -EBUSY) {
/*
* If an I/O error happened,
* measures are now unavailable
*/
- c->pre_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
- c->pre_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
dev_err(&state->i2c->dev,
"%s: Can't get BER for layer %c (error %d).\n",
- __func__, 'A' + i, rc);
+ __func__, 'A' + layer, rc);
}
- if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE)
pre_ber_layers++;
/* Handle BER post vterbi */
- rc = mb86a20s_get_post_ber(fe, i,
+ rc = mb86a20s_get_post_ber(fe, layer,
&bit_error, &bit_count);
if (rc >= 0) {
- c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->post_bit_error.stat[1 + i].uvalue += bit_error;
- c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->post_bit_count.stat[1 + i].uvalue += bit_count;
+ c->post_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[1 + layer].uvalue += bit_error;
+ c->post_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[1 + layer].uvalue += bit_count;
} else if (rc != -EBUSY) {
/*
* If an I/O error happened,
* measures are now unavailable
*/
- c->post_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
dev_err(&state->i2c->dev,
"%s: Can't get BER for layer %c (error %d).\n",
- __func__, 'A' + i, rc);
+ __func__, 'A' + layer, rc);
}
- if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE)
post_ber_layers++;
/* Handle Block errors for PER/UCB reports */
- rc = mb86a20s_get_blk_error(fe, i,
+ rc = mb86a20s_get_blk_error(fe, layer,
&block_error,
&block_count);
if (rc >= 0) {
- c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->block_error.stat[1 + i].uvalue += block_error;
- c->block_count.stat[1 + i].scale = FE_SCALE_COUNTER;
- c->block_count.stat[1 + i].uvalue += block_count;
+ c->block_error.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[1 + layer].uvalue += block_error;
+ c->block_count.stat[1 + layer].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[1 + layer].uvalue += block_count;
} else if (rc != -EBUSY) {
/*
* If an I/O error happened,
* measures are now unavailable
*/
- c->block_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
- c->block_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE;
dev_err(&state->i2c->dev,
"%s: Can't get PER for layer %c (error %d).\n",
- __func__, 'A' + i, rc);
+ __func__, 'A' + layer, rc);
}
- if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE)
+ if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE)
per_layers++;
/* Update total preBER */
- t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue;
- t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue;
+ t_pre_bit_error += c->pre_bit_error.stat[1 + layer].uvalue;
+ t_pre_bit_count += c->pre_bit_count.stat[1 + layer].uvalue;
/* Update total postBER */
- t_post_bit_error += c->post_bit_error.stat[1 + i].uvalue;
- t_post_bit_count += c->post_bit_count.stat[1 + i].uvalue;
+ t_post_bit_error += c->post_bit_error.stat[1 + layer].uvalue;
+ t_post_bit_count += c->post_bit_count.stat[1 + layer].uvalue;
/* Update total PER */
- t_block_error += c->block_error.stat[1 + i].uvalue;
- t_block_count += c->block_count.stat[1 + i].uvalue;
+ t_block_error += c->block_error.stat[1 + layer].uvalue;
+ t_block_count += c->block_count.stat[1 + layer].uvalue;
}
}
@@ -1737,8 +1777,10 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe)
static int mb86a20s_initfe(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
+ u64 pll;
+ u32 fclk;
int rc;
- u8 regD5 = 1;
+ u8 regD5 = 1, reg71, reg09 = 0x3a;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
@@ -1746,10 +1788,78 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 0);
/* Initialize the frontend */
- rc = mb86a20s_writeregdata(state, mb86a20s_init);
+ rc = mb86a20s_writeregdata(state, mb86a20s_init1);
if (rc < 0)
goto err;
+ if (!state->inversion)
+ reg09 |= 0x04;
+ rc = mb86a20s_writereg(state, 0x09, reg09);
+ if (rc < 0)
+ goto err;
+ if (!state->bw)
+ reg71 = 1;
+ else
+ reg71 = 0;
+ rc = mb86a20s_writereg(state, 0x39, reg71);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x71, state->bw);
+ if (rc < 0)
+ goto err;
+ if (state->subchannel) {
+ rc = mb86a20s_writereg(state, 0x44, state->subchannel);
+ if (rc < 0)
+ goto err;
+ }
+
+ fclk = state->config->fclk;
+ if (!fclk)
+ fclk = 32571428;
+
+ /* Adjust IF frequency to match tuner */
+ if (fe->ops.tuner_ops.get_if_frequency)
+ fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq);
+
+ if (!state->if_freq)
+ state->if_freq = 3300000;
+
+ pll = (((u64)1) << 34) * state->if_freq;
+ do_div(pll, 63 * fclk);
+ pll = (1 << 25) - pll;
+ rc = mb86a20s_writereg(state, 0x28, 0x2a);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x2b, pll & 0xff);
+ if (rc < 0)
+ goto err;
+ dev_dbg(&state->i2c->dev, "%s: fclk=%d, IF=%d, clock reg=0x%06llx\n",
+ __func__, fclk, state->if_freq, (long long)pll);
+
+ /* pll = freq[Hz] * 2^24/10^6 / 16.285714286 */
+ pll = state->if_freq * 1677721600L;
+ do_div(pll, 1628571429L);
+ rc = mb86a20s_writereg(state, 0x28, 0x20);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x2b, pll & 0xff);
+ if (rc < 0)
+ goto err;
+ dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n",
+ __func__, state->if_freq, (long long)pll);
+
if (!state->config->is_serial) {
regD5 &= ~1;
@@ -1761,6 +1871,11 @@ static int mb86a20s_initfe(struct dvb_frontend *fe)
goto err;
}
+ rc = mb86a20s_writeregdata(state, mb86a20s_init2);
+ if (rc < 0)
+ goto err;
+
+
err:
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1779,15 +1894,34 @@ err:
static int mb86a20s_set_frontend(struct dvb_frontend *fe)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- int rc;
-#if 0
- /*
- * FIXME: Properly implement the set frontend properties
- */
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-#endif
+ int rc, if_freq;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
+ if (!c->isdbt_layer_enabled)
+ c->isdbt_layer_enabled = 7;
+
+ if (c->isdbt_layer_enabled == 1)
+ state->bw = MB86A20S_1SEG;
+ else if (c->isdbt_partial_reception)
+ state->bw = MB86A20S_13SEG_PARTIAL;
+ else
+ state->bw = MB86A20S_13SEG;
+
+ if (c->inversion == INVERSION_ON)
+ state->inversion = true;
+ else
+ state->inversion = false;
+
+ if (!c->isdbt_sb_mode) {
+ state->subchannel = 0;
+ } else {
+ if (c->isdbt_sb_subchannel >= ARRAY_SIZE(mb86a20s_subchannel))
+ c->isdbt_sb_subchannel = 0;
+
+ state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel];
+ }
+
/*
* Gate should already be opened, but it doesn't hurt to
* double-check
@@ -1796,6 +1930,9 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 1);
fe->ops.tuner_ops.set_params(fe);
+ if (fe->ops.tuner_ops.get_if_frequency)
+ fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+
/*
* Make it more reliable: if, for some reason, the initial
* device initialization doesn't happen, initialize it when
@@ -1805,15 +1942,22 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe)
* the agc callback logic is not called during DVB attach time,
* causing mb86a20s to not be initialized with Kworld SBTVD.
* So, this hack is needed, in order to make Kworld SBTVD to work.
+ *
+ * It is also needed to change the IF after the initial init.
+ *
+ * HACK: Always init the frontend when set_frontend is called:
+ * it was noticed that, on some devices, it fails to lock on a
+ * different channel. So, it is better to reset everything, even
+ * wasting some time, than to loose channel lock.
*/
- if (state->need_init)
- mb86a20s_initfe(fe);
+ mb86a20s_initfe(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
mb86a20s_reset_counters(fe);
+ mb86a20s_stats_not_ready(fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
@@ -1825,8 +1969,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
fe_status_t *status)
{
struct mb86a20s_state *state = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int rc;
+ int rc, status_nr;
dev_dbg(&state->i2c->dev, "%s called.\n", __func__);
@@ -1834,12 +1977,12 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 0);
/* Get lock */
- rc = mb86a20s_read_status(fe, status);
- if (!(*status & FE_HAS_LOCK)) {
+ status_nr = mb86a20s_read_status(fe, status);
+ if (status_nr < 7) {
mb86a20s_stats_not_ready(fe);
mb86a20s_reset_frontend_cache(fe);
}
- if (rc < 0) {
+ if (status_nr < 0) {
dev_err(&state->i2c->dev,
"%s: Can't read frontend lock status\n", __func__);
goto error;
@@ -1856,10 +1999,8 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
rc = 0; /* Status is OK */
goto error;
}
- /* Fill signal strength */
- c->strength.stat[0].uvalue = rc;
- if (*status & FE_HAS_LOCK) {
+ if (status_nr >= 7) {
/* Get TMCC info*/
rc = mb86a20s_get_frontend(fe);
if (rc < 0) {
@@ -1870,7 +2011,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe,
}
/* Get statistics */
- rc = mb86a20s_get_stats(fe);
+ rc = mb86a20s_get_stats(fe, status_nr);
if (rc < 0 && rc != -EBUSY) {
dev_err(&state->i2c->dev,
"%s: Can't get FE statistics.\n", __func__);
@@ -1994,7 +2135,7 @@ static struct dvb_frontend_ops mb86a20s_ops = {
/* Use dib8000 values per default */
.info = {
.name = "Fujitsu mb86A20s",
- .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
+ .caps = FE_CAN_RECOVER |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index bf22e77888b9..6627a3976087 100644
--- a/drivers/media/dvb-frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -16,21 +16,25 @@
#ifndef MB86A20S_H
#define MB86A20S_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
/**
* struct mb86a20s_config - Define the per-device attributes of the frontend
*
+ * @fclk: Clock frequency. If zero, assumes the default
+ * (32.57142 Mhz)
* @demod_address: the demodulator's i2c address
+ * @is_serial: if true, TS is serial. Otherwise, TS is parallel
*/
struct mb86a20s_config {
- u8 demod_address;
- bool is_serial;
+ u32 fclk;
+ u8 demod_address;
+ bool is_serial;
};
-#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_MB86A20S)
extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/rtl2830.h b/drivers/media/dvb-frontends/rtl2830.h
index f4349a1fc03e..3313847fb0be 100644
--- a/drivers/media/dvb-frontends/rtl2830.h
+++ b/drivers/media/dvb-frontends/rtl2830.h
@@ -21,6 +21,7 @@
#ifndef RTL2830_H
#define RTL2830_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct rtl2830_config {
@@ -59,8 +60,7 @@ struct rtl2830_config {
u8 agc_targ_val;
};
-#if defined(CONFIG_DVB_RTL2830) || \
- (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_RTL2830)
extern struct dvb_frontend *rtl2830_attach(
const struct rtl2830_config *config,
struct i2c_adapter *i2c
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 73887690b046..facb84841518 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -380,13 +380,41 @@ err:
return ret;
}
-static int rtl2832_init(struct dvb_frontend *fe)
+
+static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
- int i, ret, len;
- u8 en_bbin;
+ int ret;
u64 pset_iffreq;
+ u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0);
+
+ /*
+ * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
+ * / CrystalFreqHz)
+ */
+
+ pset_iffreq = if_freq % priv->cfg.xtal;
+ pset_iffreq *= 0x400000;
+ pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+ pset_iffreq = -pset_iffreq;
+ pset_iffreq = pset_iffreq & 0x3fffff;
+ dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n",
+ __func__, if_freq, (unsigned)pset_iffreq);
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+ if (ret)
+ return ret;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+
+ return (ret);
+}
+
+static int rtl2832_init(struct dvb_frontend *fe)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
const struct rtl2832_reg_value *init;
+ int i, ret, len;
/* initialization values for the demodulator registers */
struct rtl2832_reg_value rtl2832_initial_regs[] = {
@@ -432,22 +460,10 @@ static int rtl2832_init(struct dvb_frontend *fe)
{DVBT_TR_THD_SET2, 0x6},
{DVBT_TRK_KC_I2, 0x5},
{DVBT_CR_THD_SET2, 0x1},
- {DVBT_SPEC_INV, 0x0},
};
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
- en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
-
- /*
- * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
- * / CrystalFreqHz)
- */
- pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
- pset_iffreq *= 0x400000;
- pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
- pset_iffreq = pset_iffreq & 0x3fffff;
-
for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
rtl2832_initial_regs[i].value);
@@ -472,6 +488,10 @@ static int rtl2832_init(struct dvb_frontend *fe)
len = ARRAY_SIZE(rtl2832_tuner_init_e4000);
init = rtl2832_tuner_init_e4000;
break;
+ case RTL2832_TUNER_R820T:
+ len = ARRAY_SIZE(rtl2832_tuner_init_r820t);
+ init = rtl2832_tuner_init_r820t;
+ break;
default:
ret = -EINVAL;
goto err;
@@ -483,14 +503,26 @@ static int rtl2832_init(struct dvb_frontend *fe)
goto err;
}
- /* if frequency settings */
- ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+ if (!fe->ops.tuner_ops.get_if_frequency) {
+ ret = rtl2832_set_if(fe, priv->cfg.if_dvbt);
if (ret)
goto err;
+ }
- ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
- if (ret)
- goto err;
+ /*
+ * r820t NIM code does a software reset here at the demod -
+ * may not be needed, as there's already a software reset at set_params()
+ */
+#if 1
+ /* soft reset */
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+ if (ret)
+ goto err;
+#endif
priv->sleeping = false;
@@ -564,6 +596,19 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
+ /* If the frontend has get_if_frequency(), use it */
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ u32 if_freq;
+
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_set_if(fe, if_freq);
+ if (ret)
+ goto err;
+ }
+
switch (c->bandwidth_hz) {
case 6000000:
i = 0;
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index 785a466eb065..91b2dcf5a6ea 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -21,6 +21,7 @@
#ifndef RTL2832_H
#define RTL2832_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct rtl2832_config {
@@ -51,11 +52,11 @@ struct rtl2832_config {
#define RTL2832_TUNER_FC0012 0x26
#define RTL2832_TUNER_E4000 0x27
#define RTL2832_TUNER_FC0013 0x29
+#define RTL2832_TUNER_R820T 0x2a
u8 tuner;
};
-#if defined(CONFIG_DVB_RTL2832) || \
- (defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_RTL2832)
extern struct dvb_frontend *rtl2832_attach(
const struct rtl2832_config *cfg,
struct i2c_adapter *i2c
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index 7d97ce9d2193..b5f2b80092ee 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -267,6 +267,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = {
{DVBT_OPT_ADC_IQ, 0x1},
{DVBT_AD_AVI, 0x0},
{DVBT_AD_AVQ, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = {
@@ -300,6 +301,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = {
{DVBT_GI_PGA_STATE, 0x0},
{DVBT_EN_AGC_PGA, 0x1},
{DVBT_IF_AGC_MAN, 0x0},
+ {DVBT_SPEC_INV, 0x0},
};
static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = {
@@ -337,6 +339,32 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = {
{DVBT_REG_MONSEL, 0x1},
{DVBT_REG_MON, 0x1},
{DVBT_REG_4MSEL, 0x0},
+ {DVBT_SPEC_INV, 0x0},
+};
+
+static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = {
+ {DVBT_DAGC_TRG_VAL, 0x39},
+ {DVBT_AGC_TARG_VAL_0, 0x0},
+ {DVBT_AGC_TARG_VAL_8_1, 0x40},
+ {DVBT_AAGC_LOOP_GAIN, 0x16},
+ {DVBT_LOOP_GAIN2_3_0, 0x8},
+ {DVBT_LOOP_GAIN2_4, 0x1},
+ {DVBT_LOOP_GAIN3, 0x18},
+ {DVBT_VTOP1, 0x35},
+ {DVBT_VTOP2, 0x21},
+ {DVBT_VTOP3, 0x21},
+ {DVBT_KRF1, 0x0},
+ {DVBT_KRF2, 0x40},
+ {DVBT_KRF3, 0x10},
+ {DVBT_KRF4, 0x10},
+ {DVBT_IF_AGC_MIN, 0x80},
+ {DVBT_IF_AGC_MAX, 0x7f},
+ {DVBT_RF_AGC_MIN, 0x80},
+ {DVBT_RF_AGC_MAX, 0x7f},
+ {DVBT_POLAR_RF_AGC, 0x0},
+ {DVBT_POLAR_IF_AGC, 0x0},
+ {DVBT_AD7_SETTING, 0xe9f4},
+ {DVBT_SPEC_INV, 0x1},
};
#endif /* RTL2832_PRIV_H */
diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
index 91f2ebd1a534..63b1e0a34e4e 100644
--- a/drivers/media/dvb-frontends/s5h1409.h
+++ b/drivers/media/dvb-frontends/s5h1409.h
@@ -22,6 +22,7 @@
#ifndef __S5H1409_H__
#define __S5H1409_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct s5h1409_config {
@@ -66,8 +67,7 @@ struct s5h1409_config {
u8 hvr1600_opt;
};
-#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S5H1409)
extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
index 45ec0f82989c..e4f56871f982 100644
--- a/drivers/media/dvb-frontends/s5h1411.h
+++ b/drivers/media/dvb-frontends/s5h1411.h
@@ -22,6 +22,7 @@
#ifndef __S5H1411_H__
#define __S5H1411_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#define S5H1411_I2C_TOP_ADDR (0x32 >> 1)
@@ -68,8 +69,7 @@ struct s5h1411_config {
u8 status_mode;
};
-#if defined(CONFIG_DVB_S5H1411) || \
- (defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S5H1411)
extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h
index b57438c32546..70917dd2533a 100644
--- a/drivers/media/dvb-frontends/s5h1432.h
+++ b/drivers/media/dvb-frontends/s5h1432.h
@@ -22,6 +22,7 @@
#ifndef __S5H1432_H__
#define __S5H1432_H__
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
@@ -74,8 +75,7 @@ struct s5h1432_config {
u8 status_mode;
};
-#if defined(CONFIG_DVB_S5H1432) || \
- (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S5H1432)
extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h
index f220d8299c81..8d5e2a6e187c 100644
--- a/drivers/media/dvb-frontends/s921.h
+++ b/drivers/media/dvb-frontends/s921.h
@@ -17,6 +17,7 @@
#ifndef S921_H
#define S921_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct s921_config {
@@ -24,8 +25,7 @@ struct s921_config {
u8 demod_address;
};
-#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_S921)
extern struct dvb_frontend *s921_attach(const struct s921_config *config,
struct i2c_adapter *i2c);
extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h
index 141b5b8a5f63..1509fed44a3a 100644
--- a/drivers/media/dvb-frontends/si21xx.h
+++ b/drivers/media/dvb-frontends/si21xx.h
@@ -1,6 +1,7 @@
#ifndef SI21XX_H
#define SI21XX_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -12,8 +13,7 @@ struct si21xx_config {
int min_delay_ms;
};
-#if defined(CONFIG_DVB_SI21XX) || \
- (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_SI21XX)
extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h
index 7be479c22d5b..a768189bfaad 100644
--- a/drivers/media/dvb-frontends/stb6000.h
+++ b/drivers/media/dvb-frontends/stb6000.h
@@ -23,6 +23,7 @@
#ifndef __DVB_STB6000_H__
#define __DVB_STB6000_H__
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -34,8 +35,7 @@
* @param i2c i2c adapter to use.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STB6000)
extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h
index f2b53db0606d..a0bd93107154 100644
--- a/drivers/media/dvb-frontends/stv0288.h
+++ b/drivers/media/dvb-frontends/stv0288.h
@@ -27,6 +27,7 @@
#ifndef STV0288_H
#define STV0288_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -42,8 +43,7 @@ struct stv0288_config {
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
-#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \
- defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0288)
extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config,
struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h
index 93cc4a57eea0..ea80b341f094 100644
--- a/drivers/media/dvb-frontends/stv0367.h
+++ b/drivers/media/dvb-frontends/stv0367.h
@@ -26,6 +26,7 @@
#ifndef STV0367_H
#define STV0367_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -38,8 +39,7 @@ struct stv0367_config {
int clk_pol;
};
-#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0367)
extern struct
dvb_frontend *stv0367ter_attach(const struct stv0367_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h
index 91c7ee8b2313..e2a6dc69ecb4 100644
--- a/drivers/media/dvb-frontends/stv0900.h
+++ b/drivers/media/dvb-frontends/stv0900.h
@@ -26,6 +26,7 @@
#ifndef STV0900_H
#define STV0900_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include "dvb_frontend.h"
@@ -57,8 +58,7 @@ struct stv0900_config {
void (*set_lock_led)(struct dvb_frontend *fe, int offon);
};
-#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV0900)
extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
struct i2c_adapter *i2c, int demod);
#else
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index f36eeefb76a6..56d470ad5a82 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -3906,12 +3906,12 @@ static int stv090x_sleep(struct dvb_frontend *fe)
reg = stv090x_read_reg(state, STV090x_TSTTNR1);
STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
- goto err;
+ goto err_unlock;
/* power off DiSEqC 1 */
reg = stv090x_read_reg(state, STV090x_TSTTNR2);
STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0);
if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0)
- goto err;
+ goto err_unlock;
/* check whether path 2 is already sleeping, that is when
ADC2 is off */
@@ -3930,7 +3930,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
if (full_standby)
STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
- goto err;
+ goto err_unlock;
reg = stv090x_read_reg(state, STV090x_STOPCLK2);
/* sampling 1 clock */
STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1);
@@ -3941,7 +3941,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
if (full_standby)
STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
- goto err;
+ goto err_unlock;
break;
case STV090x_DEMODULATOR_1:
@@ -3949,12 +3949,12 @@ static int stv090x_sleep(struct dvb_frontend *fe)
reg = stv090x_read_reg(state, STV090x_TSTTNR3);
STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0);
if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0)
- goto err;
+ goto err_unlock;
/* power off DiSEqC 2 */
reg = stv090x_read_reg(state, STV090x_TSTTNR4);
STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0);
if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0)
- goto err;
+ goto err_unlock;
/* check whether path 1 is already sleeping, that is when
ADC1 is off */
@@ -3973,7 +3973,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
if (full_standby)
STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1);
if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0)
- goto err;
+ goto err_unlock;
reg = stv090x_read_reg(state, STV090x_STOPCLK2);
/* sampling 2 clock */
STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1);
@@ -3984,7 +3984,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
if (full_standby)
STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1);
if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
- goto err;
+ goto err_unlock;
break;
default:
@@ -3997,7 +3997,7 @@ static int stv090x_sleep(struct dvb_frontend *fe)
reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
- goto err;
+ goto err_unlock;
}
mutex_unlock(&state->internal->demod_lock);
@@ -4005,8 +4005,10 @@ static int stv090x_sleep(struct dvb_frontend *fe)
err_gateoff:
stv090x_i2c_gate_ctrl(state, 0);
-err:
+ goto err;
+err_unlock:
mutex_unlock(&state->internal->demod_lock);
+err:
dprintk(FE_ERROR, 1, "I/O error");
return -1;
}
diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h
index fe71bba6a26e..8fa07e6a6745 100644
--- a/drivers/media/dvb-frontends/stv6110.h
+++ b/drivers/media/dvb-frontends/stv6110.h
@@ -25,6 +25,7 @@
#ifndef __DVB_STV6110_H__
#define __DVB_STV6110_H__
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -45,8 +46,7 @@ struct stv6110_config {
u8 clk_div; /* divisor value for the output clock */
};
-#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_STV6110)
extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
const struct stv6110_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h
index fb2ef5ac9487..5e7bf4e47cb3 100644
--- a/drivers/media/dvb-frontends/tda10048.h
+++ b/drivers/media/dvb-frontends/tda10048.h
@@ -22,6 +22,7 @@
#ifndef TDA10048_H
#define TDA10048_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
#include <linux/firmware.h>
@@ -72,8 +73,7 @@ struct tda10048_config {
u8 pll_n;
};
-#if defined(CONFIG_DVB_TDA10048) || \
- (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10048)
extern struct dvb_frontend *tda10048_attach(
const struct tda10048_config *config,
struct i2c_adapter *i2c);
diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h
index bff1c38df802..f9542f68fe78 100644
--- a/drivers/media/dvb-frontends/tda10071.h
+++ b/drivers/media/dvb-frontends/tda10071.h
@@ -21,6 +21,7 @@
#ifndef TDA10071_H
#define TDA10071_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct tda10071_config {
@@ -71,8 +72,7 @@ struct tda10071_config {
};
-#if defined(CONFIG_DVB_TDA10071) || \
- (defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TDA10071)
extern struct dvb_frontend *tda10071_attach(
const struct tda10071_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h
index 1389c74e12ce..dd84f7b69bec 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd.h
@@ -1,7 +1,9 @@
#ifndef _TDA18271C2DD_H_
#define _TDA18271C2DD_H_
-#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \
- && defined(MODULE))
+
+#include <linux/kconfig.h>
+
+#if IS_ENABLED(CONFIG_DVB_TDA18271C2DD)
struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, u8 adr);
#else
diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h
index c7e64afa614a..5bcb9a71ca80 100644
--- a/drivers/media/dvb-frontends/ts2020.h
+++ b/drivers/media/dvb-frontends/ts2020.h
@@ -22,6 +22,7 @@
#ifndef TS2020_H
#define TS2020_H
+#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
struct ts2020_config {
@@ -29,8 +30,7 @@ struct ts2020_config {
u8 clk_out_div;
};
-#if defined(CONFIG_DVB_TS2020) || \
- (defined(CONFIG_DVB_TS2020_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_TS2020)
extern struct dvb_frontend *ts2020_attach(
struct dvb_frontend *fe,
diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h
index d84b8f8215e9..5f1e8217eeb6 100644
--- a/drivers/media/dvb-frontends/zl10036.h
+++ b/drivers/media/dvb-frontends/zl10036.h
@@ -21,6 +21,7 @@
#ifndef DVB_ZL10036_H
#define DVB_ZL10036_H
+#include <linux/kconfig.h>
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -37,8 +38,7 @@ struct zl10036_config {
int rf_loop_enable;
};
-#if defined(CONFIG_DVB_ZL10036) || \
- (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_ZL10036)
extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe,
const struct zl10036_config *config, struct i2c_adapter *i2c);
#else
diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h
index 5eee7ea162a1..750b9bca9d02 100644
--- a/drivers/media/dvb-frontends/zl10039.h
+++ b/drivers/media/dvb-frontends/zl10039.h
@@ -22,8 +22,9 @@
#ifndef ZL10039_H
#define ZL10039_H
-#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
- && defined(MODULE))
+#include <linux/kconfig.h>
+
+#if IS_ENABLED(CONFIG_DVB_ZL10039)
struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe,
u8 i2c_addr,
struct i2c_adapter *i2c);
diff --git a/drivers/media/firewire/firedtv-dvb.c b/drivers/media/firewire/firedtv-dvb.c
index eb7496eab130..f710e17953e3 100644
--- a/drivers/media/firewire/firedtv-dvb.c
+++ b/drivers/media/firewire/firedtv-dvb.c
@@ -71,11 +71,11 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (dvbdmxfeed->type == DMX_TYPE_TS) {
switch (dvbdmxfeed->pes_type) {
- case DMX_TS_PES_VIDEO:
- case DMX_TS_PES_AUDIO:
- case DMX_TS_PES_TELETEXT:
- case DMX_TS_PES_PCR:
- case DMX_TS_PES_OTHER:
+ case DMX_PES_VIDEO:
+ case DMX_PES_AUDIO:
+ case DMX_PES_TELETEXT:
+ case DMX_PES_PCR:
+ case DMX_PES_OTHER:
c = alloc_channel(fdtv);
break;
default:
@@ -132,7 +132,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
(demux->dmx.frontend->source != DMX_MEMORY_FE))) {
if (dvbdmxfeed->ts_type & TS_DECODER) {
- if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
+ if (dvbdmxfeed->pes_type >= DMX_PES_OTHER ||
!demux->pesfilter[dvbdmxfeed->pes_type])
return -EINVAL;
@@ -141,7 +141,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
}
if (!(dvbdmxfeed->ts_type & TS_DECODER &&
- dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
+ dvbdmxfeed->pes_type < DMX_PES_OTHER))
return 0;
}
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 7b771baa2212..f981d50a2a8c 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -112,6 +112,15 @@ config VIDEO_TLV320AIC23B
To compile this driver as a module, choose M here: the
module will be called tlv320aic23b.
+config VIDEO_UDA1342
+ tristate "Philips UDA1342 audio codec"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips UDA1342 audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called uda1342.
+
config VIDEO_WM8775
tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
depends on VIDEO_V4L2 && I2C
@@ -133,7 +142,7 @@ config VIDEO_WM8739
module will be called wm8739.
config VIDEO_VP27SMPX
- tristate "Panasonic VP27s internal MPX"
+ tristate "Panasonic VP27's internal MPX"
depends on VIDEO_V4L2 && I2C
---help---
Support for the internal MPX of the Panasonic VP27s tuner.
@@ -141,6 +150,15 @@ config VIDEO_VP27SMPX
To compile this driver as a module, choose M here: the
module will be called vp27smpx.
+config VIDEO_SONY_BTF_MPX
+ tristate "Sony BTF's internal MPX"
+ depends on VIDEO_V4L2 && I2C
+ help
+ Support for the internal MPX of the Sony BTF-PG472Z tuner.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sony-btf-mpx.
+
comment "RDS decoders"
config VIDEO_SAA6588
@@ -283,6 +301,35 @@ config VIDEO_TVP7002
To compile this driver as a module, choose M here: the
module will be called tvp7002.
+config VIDEO_TW2804
+ tristate "Techwell TW2804 multiple video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Techwell tw2804 multiple video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw2804.
+
+config VIDEO_TW9903
+ tristate "Techwell TW9903 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Techwell tw9903 multi-standard video decoder
+ with high quality down scaler.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw9903.
+
+config VIDEO_TW9906
+ tristate "Techwell TW9906 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Techwell tw9906 enhanced multi-standard comb filter
+ video decoder with YCbCr input support.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw9906.
+
config VIDEO_VPX3220
tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
depends on VIDEO_V4L2 && I2C
@@ -386,6 +433,17 @@ config VIDEO_APTINA_PLL
config VIDEO_SMIAPP_PLL
tristate
+config VIDEO_OV7640
+ tristate "OmniVision OV7640 sensor support"
+ depends on I2C && VIDEO_V4L2
+ depends on MEDIA_CAMERA_SUPPORT
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV7640 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov7640.
+
config VIDEO_OV7670
tristate "OmniVision OV7670 sensor support"
depends on I2C && VIDEO_V4L2
@@ -501,8 +559,8 @@ config VIDEO_S5C73M3
tristate "Samsung S5C73M3 sensor support"
depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---help---
- This is a V4L2 sensor-level driver for Samsung S5C73M3
- 8 Mpixel camera.
+ This is a V4L2 sensor-level driver for Samsung S5C73M3
+ 8 Mpixel camera.
comment "Flash devices"
@@ -550,10 +608,10 @@ config VIDEO_UPD64083
comment "Miscelaneous helper chips"
config VIDEO_THS7303
- tristate "THS7303 Video Amplifier"
- depends on I2C
+ tristate "THS7303/53 Video Amplifier"
+ depends on VIDEO_V4L2 && I2C
help
- Support for TI THS7303 video amplifier
+ Support for TI THS7303/53 video amplifier
To compile this driver as a module, choose M here: the
module will be called ths7303.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index cfefd30cc1bc..720f42d9d9f4 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -37,16 +37,22 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
+obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
+obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
+obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
-obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
+obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index c2886b6a727d..58344b6c3a55 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -354,7 +354,7 @@ static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int ad9389b_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index df163800c8e1..ef75abe5984c 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -447,7 +447,7 @@ free_and_quit:
return ret;
}
-static int __exit adp1653_remove(struct i2c_client *client)
+static int adp1653_remove(struct i2c_client *client)
{
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct adp1653_flash *flash = to_adp1653_flash(subdev);
@@ -476,7 +476,7 @@ static struct i2c_driver adp1653_i2c_driver = {
.pm = &adp1653_pm_ops,
},
.probe = adp1653_probe,
- .remove = __exit_p(adp1653_remove),
+ .remove = adp1653_remove,
.id_table = adp1653_id_table,
};
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 34f39d3b3e3e..afd561ab190d 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -135,6 +135,10 @@ struct adv7180_state {
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
{
+ /* in case V4L2_IN_ST_NO_SIGNAL */
+ if (!(status1 & ADV7180_STATUS1_IN_LOCK))
+ return V4L2_STD_UNKNOWN;
+
switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
case ADV7180_STATUS1_AUTOD_NTSM_M_J:
return V4L2_STD_NTSC;
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index 6fed5b74e743..56a1fa4af0fe 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -507,7 +507,7 @@ static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index f47555b1000a..31a63c9324fe 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -699,7 +699,7 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
}
static int adv7604_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index ba674656b10d..fd47465e4f6a 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -101,7 +101,7 @@ static int ak881x_g_register(struct v4l2_subdev *sd,
}
static int ak881x_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c
index c8581e26fa9c..1d2f7c8512b5 100644
--- a/drivers/media/i2c/cs5345.c
+++ b/drivers/media/i2c/cs5345.c
@@ -110,7 +110,7 @@ static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
return 0;
}
-static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int cs5345_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index f4149eb4d7b4..12fb9b2eb887 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -1671,7 +1671,7 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1835,7 +1835,7 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
return set_input(client, state->vid_input, input);
}
-static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1881,7 +1881,7 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 08ae067b2b6f..8e2f79cb045e 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -230,7 +230,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
return 0;
dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup);
- if (keygroup < 2 || keygroup > 3) {
+ if (keygroup < 2 || keygroup > 4) {
/* Only a warning */
dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n",
keygroup, key);
@@ -239,6 +239,10 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
*ir_key = key;
*ir_raw = key;
+ if (!strcmp(ir->ir_codes, RC_MAP_AVERMEDIA_M733A_RM_K6)) {
+ *ir_key |= keygroup << 8;
+ *ir_raw |= keygroup << 8;
+ }
return 1;
}
@@ -332,6 +336,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
rc_type = RC_BIT_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
+ case 0x41:
+ name = "AVerMedia EM78P153";
+ ir->get_key = get_key_avermedia_cardbus;
+ rc_type = RC_BIT_OTHER;
+ /* RM-KV remote, seems to be same as RM-K6 */
+ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
+ break;
case 0x71:
name = "Hauppauge/Zilog Z8";
ir->get_key = get_key_haup_xvr;
@@ -423,6 +434,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
rc->map_name = ir->ir_codes;
rc->allowed_protos = rc_type;
+ rc->enabled_protocols = rc_type;
if (!rc->driver_name)
rc->driver_name = MODULE_NAME;
diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c
index 0991576f4c82..39f50fd2b8d2 100644
--- a/drivers/media/i2c/m52790.c
+++ b/drivers/media/i2c/m52790.c
@@ -96,7 +96,7 @@ static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
return 0;
}
-static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct m52790_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index d4e7567b367c..0b899cb6cda1 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -724,7 +724,7 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
if (enable) {
if (is_code(code, M5MOLS_RESTYPE_MONITOR))
ret = m5mols_start_monitor(info);
- if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
+ else if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
ret = m5mols_start_capture(info);
else
ret = -EINVAL;
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 766305f69a28..54a9dd394f45 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -445,7 +445,7 @@ static int msp_s_radio(struct v4l2_subdev *sd)
return 0;
}
-static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+static int msp_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -535,7 +535,7 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int msp_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct msp_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index f80c1d7ec884..8edb3d8f7b90 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -87,9 +87,27 @@
#define MT9M032_RESTART 0x0b
#define MT9M032_RESET 0x0d
#define MT9M032_PLL_CONFIG1 0x11
-#define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f
+#define MT9M032_PLL_CONFIG1_PREDIV_MASK 0x3f
#define MT9M032_PLL_CONFIG1_MUL_SHIFT 8
#define MT9M032_READ_MODE1 0x1e
+#define MT9M032_READ_MODE1_OUTPUT_BAD_FRAMES (1 << 13)
+#define MT9M032_READ_MODE1_MAINTAIN_FRAME_RATE (1 << 12)
+#define MT9M032_READ_MODE1_XOR_LINE_VALID (1 << 11)
+#define MT9M032_READ_MODE1_CONT_LINE_VALID (1 << 10)
+#define MT9M032_READ_MODE1_INVERT_TRIGGER (1 << 9)
+#define MT9M032_READ_MODE1_SNAPSHOT (1 << 8)
+#define MT9M032_READ_MODE1_GLOBAL_RESET (1 << 7)
+#define MT9M032_READ_MODE1_BULB_EXPOSURE (1 << 6)
+#define MT9M032_READ_MODE1_INVERT_STROBE (1 << 5)
+#define MT9M032_READ_MODE1_STROBE_ENABLE (1 << 4)
+#define MT9M032_READ_MODE1_STROBE_START_TRIG1 (0 << 2)
+#define MT9M032_READ_MODE1_STROBE_START_EXP (1 << 2)
+#define MT9M032_READ_MODE1_STROBE_START_SHUTTER (2 << 2)
+#define MT9M032_READ_MODE1_STROBE_START_TRIG2 (3 << 2)
+#define MT9M032_READ_MODE1_STROBE_END_TRIG1 (0 << 0)
+#define MT9M032_READ_MODE1_STROBE_END_EXP (1 << 0)
+#define MT9M032_READ_MODE1_STROBE_END_SHUTTER (2 << 0)
+#define MT9M032_READ_MODE1_STROBE_END_TRIG2 (3 << 0)
#define MT9M032_READ_MODE2 0x20
#define MT9M032_READ_MODE2_VFLIP_SHIFT 15
#define MT9M032_READ_MODE2_HFLIP_SHIFT 14
@@ -106,6 +124,8 @@
#define MT9M032_GAIN_AMUL_SHIFT 6
#define MT9M032_GAIN_ANALOG_MASK 0x3f
#define MT9M032_FORMATTER1 0x9e
+#define MT9M032_FORMATTER1_PLL_P1_6 (1 << 8)
+#define MT9M032_FORMATTER1_PARALLEL (1 << 12)
#define MT9M032_FORMATTER2 0x9f
#define MT9M032_FORMATTER2_DOUT_EN 0x1000
#define MT9M032_FORMATTER2_PIXCLK_EN 0x2000
@@ -121,8 +141,6 @@
#define MT9P031_PLL_CONTROL_PWROFF 0x0050
#define MT9P031_PLL_CONTROL_PWRON 0x0051
#define MT9P031_PLL_CONTROL_USEPLL 0x0052
-#define MT9P031_PLL_CONFIG2 0x11
-#define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f
struct mt9m032 {
struct v4l2_subdev subdev;
@@ -255,13 +273,14 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
.n_max = 64,
.m_min = 16,
.m_max = 255,
- .p1_min = 1,
- .p1_max = 128,
+ .p1_min = 6,
+ .p1_max = 7,
};
struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
struct mt9m032_platform_data *pdata = sensor->pdata;
struct aptina_pll pll;
+ u16 reg_val;
int ret;
pll.ext_clock = pdata->ext_clock;
@@ -274,18 +293,21 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor)
sensor->pix_clock = pdata->pix_clock;
ret = mt9m032_write(client, MT9M032_PLL_CONFIG1,
- (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT)
- | (pll.p1 - 1));
- if (!ret)
- ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1);
+ (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) |
+ ((pll.n - 1) & MT9M032_PLL_CONFIG1_PREDIV_MASK));
if (!ret)
ret = mt9m032_write(client, MT9P031_PLL_CONTROL,
MT9P031_PLL_CONTROL_PWRON |
MT9P031_PLL_CONTROL_USEPLL);
if (!ret) /* more reserved, Continuous, Master Mode */
- ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006);
- if (!ret) /* Set 14-bit mode, select 7 divider */
- ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e);
+ ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8000 |
+ MT9M032_READ_MODE1_STROBE_START_EXP |
+ MT9M032_READ_MODE1_STROBE_END_SHUTTER);
+ if (!ret) {
+ reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0)
+ | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */
+ ret = mt9m032_write(client, MT9M032_FORMATTER1, reg_val);
+ }
return ret;
}
@@ -548,7 +570,7 @@ static int mt9m032_g_register(struct v4l2_subdev *sd,
}
static int mt9m032_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct mt9m032 *sensor = to_mt9m032(sd);
struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev);
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e32833262d32..28cf95b37285 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -12,6 +12,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
@@ -19,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/pm.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
@@ -121,6 +123,11 @@ struct mt9p031 {
struct mutex power_lock; /* lock to protect power_count */
int power_count;
+ struct clk *clk;
+ struct regulator *vaa;
+ struct regulator *vdd;
+ struct regulator *vdd_io;
+
enum mt9p031_model model;
struct aptina_pll pll;
int reset;
@@ -195,7 +202,7 @@ static int mt9p031_reset(struct mt9p031 *mt9p031)
0);
}
-static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
+static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
{
static const struct aptina_pll_limits limits = {
.ext_clock_min = 6000000,
@@ -216,6 +223,12 @@ static int mt9p031_pll_setup(struct mt9p031 *mt9p031)
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
struct mt9p031_platform_data *pdata = mt9p031->pdata;
+ mt9p031->clk = devm_clk_get(&client->dev, NULL);
+ if (IS_ERR(mt9p031->clk))
+ return PTR_ERR(mt9p031->clk);
+
+ clk_set_rate(mt9p031->clk, pdata->ext_freq);
+
mt9p031->pll.ext_clock = pdata->ext_freq;
mt9p031->pll.pix_clock = pdata->target_freq;
@@ -264,10 +277,14 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
usleep_range(1000, 2000);
}
+ /* Bring up the supplies */
+ regulator_enable(mt9p031->vdd);
+ regulator_enable(mt9p031->vdd_io);
+ regulator_enable(mt9p031->vaa);
+
/* Emable clock */
- if (mt9p031->pdata->set_xclk)
- mt9p031->pdata->set_xclk(&mt9p031->subdev,
- mt9p031->pdata->ext_freq);
+ if (mt9p031->clk)
+ clk_prepare_enable(mt9p031->clk);
/* Now RESET_BAR must be high */
if (mt9p031->reset != -1) {
@@ -285,8 +302,12 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031)
usleep_range(1000, 2000);
}
- if (mt9p031->pdata->set_xclk)
- mt9p031->pdata->set_xclk(&mt9p031->subdev, 0);
+ regulator_disable(mt9p031->vaa);
+ regulator_disable(mt9p031->vdd_io);
+ regulator_disable(mt9p031->vdd);
+
+ if (mt9p031->clk)
+ clk_disable_unprepare(mt9p031->clk);
}
static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
@@ -927,7 +948,7 @@ static int mt9p031_probe(struct i2c_client *client,
return -EIO;
}
- mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL);
+ mt9p031 = devm_kzalloc(&client->dev, sizeof(*mt9p031), GFP_KERNEL);
if (mt9p031 == NULL)
return -ENOMEM;
@@ -937,6 +958,16 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->model = did->driver_data;
mt9p031->reset = -1;
+ mt9p031->vaa = devm_regulator_get(&client->dev, "vaa");
+ mt9p031->vdd = devm_regulator_get(&client->dev, "vdd");
+ mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io");
+
+ if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) ||
+ IS_ERR(mt9p031->vdd_io)) {
+ dev_err(&client->dev, "Unable to get regulators\n");
+ return -ENODEV;
+ }
+
v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6);
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
@@ -1001,24 +1032,20 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
if (pdata->reset != -1) {
- ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
- "mt9p031_rst");
+ ret = devm_gpio_request_one(&client->dev, pdata->reset,
+ GPIOF_OUT_INIT_LOW, "mt9p031_rst");
if (ret < 0)
goto done;
mt9p031->reset = pdata->reset;
}
- ret = mt9p031_pll_setup(mt9p031);
+ ret = mt9p031_clk_setup(mt9p031);
done:
if (ret < 0) {
- if (mt9p031->reset != -1)
- gpio_free(mt9p031->reset);
-
v4l2_ctrl_handler_free(&mt9p031->ctrls);
media_entity_cleanup(&mt9p031->subdev.entity);
- kfree(mt9p031);
}
return ret;
@@ -1032,9 +1059,6 @@ static int mt9p031_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&mt9p031->ctrls);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
- if (mt9p031->reset != -1)
- gpio_free(mt9p031->reset);
- kfree(mt9p031);
return 0;
}
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 73b7688cbebd..3f415fd12de3 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -421,7 +421,7 @@ static int mt9v011_g_register(struct v4l2_subdev *sd,
}
static int mt9v011_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/staging/media/go7007/wis-ov7640.c b/drivers/media/i2c/ov7640.c
index 9f01657f884a..b0cc927e8b19 100644
--- a/drivers/staging/media/go7007/wis-ov7640.c
+++ b/drivers/media/i2c/ov7640.c
@@ -15,21 +15,18 @@
* Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
-#include <linux/module.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/slab.h>
-#include "wis-i2c.h"
-
-struct wis_ov7640 {
- int brightness;
- int contrast;
- int saturation;
- int hue;
-};
+MODULE_DESCRIPTION("OmniVision ov7640 sensor driver");
+MODULE_LICENSE("GPL v2");
-static u8 initial_registers[] = {
+static const u8 initial_registers[] = {
0x12, 0x80,
0x12, 0x54,
0x14, 0x24,
@@ -39,7 +36,7 @@ static u8 initial_registers[] = {
0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
};
-static int write_regs(struct i2c_client *client, u8 *regs)
+static int write_regs(struct i2c_client *client, const u8 *regs)
{
int i;
@@ -49,48 +46,61 @@ static int write_regs(struct i2c_client *client, u8 *regs)
return 0;
}
-static int wis_ov7640_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_ops ov7640_ops;
+
+static int ov7640_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct v4l2_subdev *sd;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+ v4l2_i2c_subdev_init(sd, client, &ov7640_ops);
+
client->flags = I2C_CLIENT_SCCB;
- dev_dbg(&client->dev,
- "wis-ov7640: initializing OV7640 at address %d on %s\n",
- client->addr, adapter->name);
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
if (write_regs(client, initial_registers) < 0) {
- dev_err(&client->dev, "wis-ov7640: error initializing OV7640\n");
+ v4l_err(client, "error initializing OV7640\n");
+ kfree(sd);
return -ENODEV;
}
return 0;
}
-static int wis_ov7640_remove(struct i2c_client *client)
+
+static int ov7640_remove(struct i2c_client *client)
{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
return 0;
}
-static const struct i2c_device_id wis_ov7640_id[] = {
- { "wis_ov7640", 0 },
+static const struct i2c_device_id ov7640_id[] = {
+ { "ov7640", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, wis_ov7640_id);
+MODULE_DEVICE_TABLE(i2c, ov7640_id);
-static struct i2c_driver wis_ov7640_driver = {
+static struct i2c_driver ov7640_driver = {
.driver = {
- .name = "WIS OV7640 I2C driver",
+ .owner = THIS_MODULE,
+ .name = "ov7640",
},
- .probe = wis_ov7640_probe,
- .remove = wis_ov7640_remove,
- .id_table = wis_ov7640_id,
+ .probe = ov7640_probe,
+ .remove = ov7640_remove,
+ .id_table = ov7640_id,
};
-
-module_i2c_driver(wis_ov7640_driver);
-
-MODULE_LICENSE("GPL v2");
+module_i2c_driver(ov7640_driver);
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 05ed5b8e7f88..617ad3fff4aa 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1487,7 +1487,7 @@ static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
return ret;
}
-static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 5dbb65e1f6b7..cb52438e53ac 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -357,7 +357,7 @@ static int s5c73m3_load_fw(struct v4l2_subdev *sd)
return -EINVAL;
}
- v4l2_info(sd, "Loading firmware (%s, %d B)\n", fw_name, fw->size);
+ v4l2_info(sd, "Loading firmware (%s, %zu B)\n", fw_name, fw->size);
ret = s5c73m3_spi_write(state, fw->data, fw->size, 64);
@@ -1457,6 +1457,12 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd)
return ret;
}
+static void s5c73m3_oif_unregistered(struct v4l2_subdev *sd)
+{
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ v4l2_device_unregister_subdev(&state->sensor_sd);
+}
+
static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = {
.open = s5c73m3_open,
};
@@ -1474,6 +1480,7 @@ static const struct v4l2_subdev_ops s5c73m3_subdev_ops = {
static const struct v4l2_subdev_internal_ops oif_internal_ops = {
.registered = s5c73m3_oif_registered,
+ .unregistered = s5c73m3_oif_unregistered,
.open = s5c73m3_oif_open,
};
@@ -1668,13 +1675,17 @@ out_err1:
static int s5c73m3_remove(struct i2c_client *client)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd);
+ struct v4l2_subdev *oif_sd = i2c_get_clientdata(client);
+ struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd);
+ struct v4l2_subdev *sensor_sd = &state->sensor_sd;
- v4l2_device_unregister_subdev(sd);
+ v4l2_device_unregister_subdev(oif_sd);
- v4l2_ctrl_handler_free(sd->ctrl_handler);
- media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(oif_sd->ctrl_handler);
+ media_entity_cleanup(&oif_sd->entity);
+
+ v4l2_device_unregister_subdev(sensor_sd);
+ media_entity_cleanup(&sensor_sd->entity);
s5c73m3_unregister_spi_driver(state);
s5c73m3_free_gpios(state);
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
index 0caac50d7cf4..b4e1ccbd87ec 100644
--- a/drivers/media/i2c/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
@@ -435,7 +435,7 @@ static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct saa6588 *s = to_saa6588(sd);
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 6b6788cd08f6..52c717d977c9 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -83,9 +83,10 @@ struct saa711x_state {
u32 ident;
u32 audclk_freq;
u32 crystal_freq;
- u8 ucgc;
+ bool ucgc;
u8 cgcdiv;
- u8 apll;
+ bool apll;
+ bool double_asclk;
};
static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
@@ -732,8 +733,12 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
if (state->apll)
acc |= 0x08;
+ if (state->double_asclk) {
+ acpf <<= 1;
+ acni <<= 1;
+ }
saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
- saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+ saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10 << state->double_asclk);
saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
@@ -1259,6 +1264,12 @@ static int saa711x_s_routing(struct v4l2_subdev *sd,
(saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) |
(state->output & 0x01));
}
+ if (state->ident > V4L2_IDENT_SAA7111A) {
+ if (config & SAA7115_IDQ_IS_DEFAULT)
+ saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20);
+ else
+ saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x21);
+ }
return 0;
}
@@ -1296,9 +1307,10 @@ static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags)
if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ)
return -EINVAL;
state->crystal_freq = freq;
+ state->double_asclk = flags & SAA7115_FREQ_FL_DOUBLE_ASCLK;
state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
- state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
- state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ state->ucgc = flags & SAA7115_FREQ_FL_UCGC;
+ state->apll = flags & SAA7115_FREQ_FL_APLL;
saa711x_s_clock_freq(sd, state->audclk_freq);
return 0;
}
@@ -1354,6 +1366,34 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
*/
reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+
+ if (state->ident == V4L2_IDENT_SAA7115) {
+ reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
+
+ v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
+
+ switch (reg1e & 0x03) {
+ case 1:
+ *std &= V4L2_STD_NTSC;
+ break;
+ case 2:
+ /*
+ * V4L2_STD_PAL just cover the european PAL standards.
+ * This is wrong, as the device could also be using an
+ * other PAL standard.
+ */
+ *std &= V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
+ V4L2_STD_PAL_M | V4L2_STD_PAL_60;
+ break;
+ case 3:
+ *std &= V4L2_STD_SECAM;
+ break;
+ default:
+ /* Can't detect anything */
+ break;
+ }
+ }
+
v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f);
/* horizontal/vertical not locked */
@@ -1365,34 +1405,6 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
else
*std &= V4L2_STD_625_50;
- if (state->ident != V4L2_IDENT_SAA7115)
- goto ret;
-
- reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
-
- switch (reg1e & 0x03) {
- case 1:
- *std &= V4L2_STD_NTSC;
- break;
- case 2:
- /*
- * V4L2_STD_PAL just cover the european PAL standards.
- * This is wrong, as the device could also be using an
- * other PAL standard.
- */
- *std &= V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
- V4L2_STD_PAL_M | V4L2_STD_PAL_60;
- break;
- case 3:
- *std &= V4L2_STD_SECAM;
- break;
- default:
- /* Can't detect anything */
- break;
- }
-
- v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e);
-
ret:
v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std);
@@ -1428,7 +1440,7 @@ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
index b745f68fbc92..8a47ac10927f 100644
--- a/drivers/media/i2c/saa7127.c
+++ b/drivers/media/i2c/saa7127.c
@@ -672,7 +672,7 @@ static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index 1e84466515aa..cf3a0aa7e45e 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -988,7 +988,7 @@ static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
u16 addr = reg->reg & 0xffff;
@@ -1113,7 +1113,7 @@ static int saa717x_s_stream(struct v4l2_subdev *sd, int enable)
}
/* change audio mode */
-static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct saa717x_state *decoder = to_state(sd);
int audio_mode;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 83c7ed7ffcc2..cae4f4683851 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -2833,7 +2833,7 @@ static int smiapp_probe(struct i2c_client *client,
sensor->src->pads, 0);
}
-static int __exit smiapp_remove(struct i2c_client *client)
+static int smiapp_remove(struct i2c_client *client)
{
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
@@ -2881,7 +2881,7 @@ static struct i2c_driver smiapp_i2c_driver = {
.pm = &smiapp_pm_ops,
},
.probe = smiapp_probe,
- .remove = __exit_p(smiapp_remove),
+ .remove = smiapp_remove,
.id_table = smiapp_id_table,
};
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig
index 6dff2b7ad520..23d352f0adf0 100644
--- a/drivers/media/i2c/soc_camera/Kconfig
+++ b/drivers/media/i2c/soc_camera/Kconfig
@@ -9,7 +9,6 @@ config SOC_CAMERA_IMX074
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
depends on SOC_CAMERA && I2C
- select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
help
This driver supports MT9M001 cameras from Micron, monochrome
and colour models.
@@ -36,7 +35,6 @@ config SOC_CAMERA_MT9T112
config SOC_CAMERA_MT9V022
tristate "mt9v022 and mt9v024 support"
depends on SOC_CAMERA && I2C
- select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
help
This driver supports MT9V022 cameras from Micron
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index bcdc86175549..dd9089805757 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -360,7 +360,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd,
}
static int mt9m001_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index bbc4ff99603c..8bd4e0d2ea03 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -641,7 +641,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
}
static int mt9m111_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -701,11 +701,11 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain)
return reg_write(GLOBAL_GAIN, val);
}
-static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on)
+static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int val)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
- if (on)
+ if (val == V4L2_EXPOSURE_AUTO)
return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN);
}
@@ -785,8 +785,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111)
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
- /* Default HIGHPOWER context */
- mt9m111->ctx = &context_b;
ret = mt9m111_enable(mt9m111);
if (!ret)
ret = mt9m111_reset(mt9m111);
@@ -975,6 +973,9 @@ static int mt9m111_probe(struct i2c_client *client,
if (!mt9m111)
return -ENOMEM;
+ /* Default HIGHPOWER context */
+ mt9m111->ctx = &context_b;
+
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index d80d044ebf15..26a15b87a9a2 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -430,7 +430,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd,
}
static int mt9t031_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 188e29b03273..a7256b732804 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -766,7 +766,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd,
}
static int mt9t112_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index a5e65d6a0781..a295e598486f 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -275,6 +275,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_rect rect = a->c;
+ int min_row, min_blank;
int ret;
/* Bayer format - even size lengths */
@@ -310,13 +311,21 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
if (!ret)
ret = reg_write(client, MT9V022_ROW_START, rect.top);
+ /*
+ * mt9v022: min total row time is 660 columns, min blanking is 43
+ * mt9v024: min total row time is 690 columns, min blanking is 61
+ */
+ if (is_mt9v024(mt9v022->chip_version)) {
+ min_row = 690;
+ min_blank = 61;
+ } else {
+ min_row = 660;
+ min_blank = 43;
+ }
if (!ret)
- /*
- * Default 94, Phytec driver says:
- * "width + horizontal blank >= 660"
- */
ret = v4l2_ctrl_s_ctrl(mt9v022->hblank,
- rect.width > 660 - 43 ? 43 : 660 - rect.width);
+ rect.width > min_row - min_blank ?
+ min_blank : min_row - rect.width);
if (!ret)
ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45);
if (!ret)
@@ -488,7 +497,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd,
}
static int mt9v022_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index 0f520f693b6e..e3168424f9ba 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -756,7 +756,7 @@ static int ov2640_g_register(struct v4l2_subdev *sd,
}
static int ov2640_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
index 9d53309619d2..9aa56de69eed 100644
--- a/drivers/media/i2c/soc_camera/ov5642.c
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -708,7 +708,7 @@ static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
return ret;
}
-static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
index dbe4f564e6b2..991202d4bbae 100644
--- a/drivers/media/i2c/soc_camera/ov6650.c
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -421,7 +421,7 @@ static int ov6650_get_register(struct v4l2_subdev *sd,
}
static int ov6650_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index fbeb5b2f3ae5..713d62e349f6 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -652,7 +652,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
}
static int ov772x_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
index 05993041be31..20ca62d371c1 100644
--- a/drivers/media/i2c/soc_camera/ov9640.c
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -322,7 +322,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd,
}
static int ov9640_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index 2f236da80165..012bd6271124 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -835,7 +835,7 @@ static int ov9740_get_register(struct v4l2_subdev *sd,
}
static int ov9740_set_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
index 5c92679bfefb..1f9ec3b06b4e 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -1161,7 +1161,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd,
}
static int rj54n1_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index 7d2074601881..bad90b16a6dd 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -554,7 +554,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
}
static int tw9910_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c
new file mode 100644
index 000000000000..38cbea98764c
--- /dev/null
+++ b/drivers/media/i2c/sony-btf-mpx.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <linux/slab.h>
+
+MODULE_DESCRIPTION("sony-btf-mpx driver");
+MODULE_LICENSE("GPL v2");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n");
+
+/* #define MPX_DEBUG */
+
+/*
+ * Note:
+ *
+ * AS(IF/MPX) pin: LOW HIGH/OPEN
+ * IF/MPX address: 0x42/0x40 0x43/0x44
+ */
+
+
+static int force_mpx_mode = -1;
+module_param(force_mpx_mode, int, 0644);
+
+struct sony_btf_mpx {
+ struct v4l2_subdev sd;
+ int mpxmode;
+ u32 audmode;
+};
+
+static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sony_btf_mpx, sd);
+}
+
+static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
+{
+ u8 buffer[5];
+ struct i2c_msg msg;
+
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 5;
+ msg.buf = buffer;
+ i2c_transfer(client->adapter, &msg, 1);
+ return 0;
+}
+
+/*
+ * MPX register values for the BTF-PG472Z:
+ *
+ * FM_ NICAM_ SCART_
+ * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
+ * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
+ * ---------------------------------------------------------------
+ * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
+ *
+ * B/G
+ * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
+ * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
+ * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
+ *
+ * I
+ * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
+ * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
+ *
+ * D/K
+ * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
+ * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
+ * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
+ * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
+ * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
+ *
+ * L/L'
+ * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
+ * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
+ *
+ * M
+ * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
+ *
+ * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
+ *
+ * Bilingual selection in A2/NICAM:
+ *
+ * High byte of SOURCE Left chan Right chan
+ * 0x01 MAIN SUB
+ * 0x03 MAIN MAIN
+ * 0x04 SUB SUB
+ *
+ * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
+ * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
+ *
+ * FMONO_A2
+ * 10/0022
+ * --------
+ * Forced mono ON 07F0
+ * Forced mono OFF 0190
+ */
+
+static const struct {
+ enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
+ u16 modus;
+ u16 source;
+ u16 acb;
+ u16 fm_prescale;
+ u16 nicam_prescale;
+ u16 scart_prescale;
+ u16 system;
+ u16 volume;
+} mpx_audio_modes[] = {
+ /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0001, 0x7500 },
+ /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0003, 0x7500 },
+ /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0003, 0x7500 },
+ /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0008, 0x7500 },
+ /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x7900, 0x0000, 0x000A, 0x7500 },
+ /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x7900, 0x0000, 0x000A, 0x7500 },
+ /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0004, 0x7500 },
+ /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0004, 0x7500 },
+ /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0005, 0x7500 },
+ /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0007, 0x7500 },
+ /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x000B, 0x7500 },
+ /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
+ 0x5000, 0x2200, 0x0009, 0x7500 },
+ /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
+ 0x5000, 0x0000, 0x0009, 0x7500 },
+};
+
+#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
+
+static int mpx_setup(struct sony_btf_mpx *t)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
+ u16 source = 0;
+ u8 buffer[3];
+ struct i2c_msg msg;
+ int mode = t->mpxmode;
+
+ /* reset MPX */
+ buffer[0] = 0x00;
+ buffer[1] = 0x80;
+ buffer[2] = 0x00;
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = buffer;
+ i2c_transfer(client->adapter, &msg, 1);
+ buffer[1] = 0x00;
+ i2c_transfer(client->adapter, &msg, 1);
+
+ if (t->audmode != V4L2_TUNER_MODE_MONO)
+ mode++;
+
+ if (mpx_audio_modes[mode].audio_mode != AUD_MONO) {
+ switch (t->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ switch (mpx_audio_modes[mode].audio_mode) {
+ case AUD_A2:
+ source = mpx_audio_modes[mode].source;
+ break;
+ case AUD_NICAM:
+ source = 0x0000;
+ break;
+ case AUD_NICAM_L:
+ source = 0x0200;
+ break;
+ default:
+ break;
+ }
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ source = mpx_audio_modes[mode].source;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ source = 0x0300;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ source = 0x0400;
+ break;
+ }
+ source |= mpx_audio_modes[mode].source & 0x00ff;
+ } else
+ source = mpx_audio_modes[mode].source;
+
+ mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus);
+ mpx_write(client, 0x12, 0x0008, source);
+ mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb);
+ mpx_write(client, 0x12, 0x000e,
+ mpx_audio_modes[mode].fm_prescale);
+ mpx_write(client, 0x12, 0x0010,
+ mpx_audio_modes[mode].nicam_prescale);
+ mpx_write(client, 0x12, 0x000d,
+ mpx_audio_modes[mode].scart_prescale);
+ mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system);
+ mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume);
+ if (mpx_audio_modes[mode].audio_mode == AUD_A2)
+ mpx_write(client, 0x10, 0x0022,
+ t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
+
+#ifdef MPX_DEBUG
+ {
+ u8 buf1[3], buf2[2];
+ struct i2c_msg msgs[2];
+
+ v4l2_info(client,
+ "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
+ mpx_audio_modes[mode].modus,
+ source,
+ mpx_audio_modes[mode].acb,
+ mpx_audio_modes[mode].fm_prescale,
+ mpx_audio_modes[mode].nicam_prescale,
+ mpx_audio_modes[mode].scart_prescale,
+ mpx_audio_modes[mode].system,
+ mpx_audio_modes[mode].volume);
+ buf1[0] = 0x11;
+ buf1[1] = 0x00;
+ buf1[2] = 0x7e;
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 3;
+ msgs[0].buf = buf1;
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 2;
+ msgs[1].buf = buf2;
+ i2c_transfer(client->adapter, msgs, 2);
+ v4l2_info(client, "MPX system: %02x%02x\n",
+ buf2[0], buf2[1]);
+ buf1[0] = 0x11;
+ buf1[1] = 0x02;
+ buf1[2] = 0x00;
+ i2c_transfer(client->adapter, msgs, 2);
+ v4l2_info(client, "MPX status: %02x%02x\n",
+ buf2[0], buf2[1]);
+ }
+#endif
+ return 0;
+}
+
+
+static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct sony_btf_mpx *t = to_state(sd);
+ int default_mpx_mode = 0;
+
+ if (std & V4L2_STD_PAL_BG)
+ default_mpx_mode = 1;
+ else if (std & V4L2_STD_PAL_I)
+ default_mpx_mode = 4;
+ else if (std & V4L2_STD_PAL_DK)
+ default_mpx_mode = 6;
+ else if (std & V4L2_STD_SECAM_L)
+ default_mpx_mode = 11;
+
+ if (default_mpx_mode != t->mpxmode) {
+ t->mpxmode = default_mpx_mode;
+ mpx_setup(t);
+ }
+ return 0;
+}
+
+static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct sony_btf_mpx *t = to_state(sd);
+
+ vt->capability = V4L2_TUNER_CAP_NORM |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2;
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO |
+ V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2;
+ vt->audmode = t->audmode;
+ return 0;
+}
+
+static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
+{
+ struct sony_btf_mpx *t = to_state(sd);
+
+ if (vt->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+
+ if (vt->audmode != t->audmode) {
+ t->audmode = vt->audmode;
+ mpx_setup(t);
+ }
+ return 0;
+}
+
+/* --------------------------------------------------------------------------*/
+
+static const struct v4l2_subdev_core_ops sony_btf_mpx_core_ops = {
+ .s_std = sony_btf_mpx_s_std,
+};
+
+static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
+ .s_tuner = sony_btf_mpx_s_tuner,
+ .g_tuner = sony_btf_mpx_g_tuner,
+};
+
+static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
+ .core = &sony_btf_mpx_core_ops,
+ .tuner = &sony_btf_mpx_tuner_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+static int sony_btf_mpx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct sony_btf_mpx *t;
+ struct v4l2_subdev *sd;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENODEV;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ t = kzalloc(sizeof(struct sony_btf_mpx), GFP_KERNEL);
+ if (t == NULL)
+ return -ENOMEM;
+
+ sd = &t->sd;
+ v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops);
+
+ /* Initialize sony_btf_mpx */
+ t->mpxmode = 0;
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+
+ return 0;
+}
+
+static int sony_btf_mpx_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(to_state(sd));
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id sony_btf_mpx_id[] = {
+ { "sony-btf-mpx", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id);
+
+static struct i2c_driver sony_btf_mpx_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sony-btf-mpx",
+ },
+ .probe = sony_btf_mpx_probe,
+ .remove = sony_btf_mpx_remove,
+ .id_table = sony_btf_mpx_id,
+};
+module_i2c_driver(sony_btf_mpx_driver);
diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c
index f7707e65761e..28b5121881f5 100644
--- a/drivers/media/i2c/tda7432.c
+++ b/drivers/media/i2c/tda7432.c
@@ -35,6 +35,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/i2c-addr.h>
#ifndef VIDEO_AUDIO_BALANCE
@@ -60,13 +61,17 @@ MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default
struct tda7432 {
struct v4l2_subdev sd;
- int addr;
- int input;
- int volume;
- int muted;
- int bass, treble;
- int lf, lr, rf, rr;
- int loud;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* bass/treble cluster */
+ struct v4l2_ctrl *bass;
+ struct v4l2_ctrl *treble;
+ };
+ struct {
+ /* mute/balance cluster */
+ struct v4l2_ctrl *mute;
+ struct v4l2_ctrl *balance;
+ };
};
static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
@@ -74,6 +79,11 @@ static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct tda7432, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct tda7432, hdl)->sd;
+}
+
/* The TDA7432 is made by STS-Thompson
* http://www.st.com
* http://us.st.com/stonline/books/pdf/docs/4056.pdf
@@ -227,24 +237,22 @@ static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val)
static int tda7432_set(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct tda7432 *t = to_state(sd);
unsigned char buf[16];
- v4l2_dbg(1, debug, sd,
- "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
- t->input, t->volume, t->bass, t->treble, t->lf, t->lr,
- t->rf, t->rr, t->loud);
buf[0] = TDA7432_IN;
- buf[1] = t->input;
- buf[2] = t->volume;
- buf[3] = t->bass;
- buf[4] = t->treble;
- buf[5] = t->lf;
- buf[6] = t->lr;
- buf[7] = t->rf;
- buf[8] = t->rr;
- buf[9] = t->loud;
- if (10 != i2c_master_send(client, buf, 10)) {
+ buf[1] = TDA7432_STEREO_IN | /* Main (stereo) input */
+ TDA7432_BASS_SYM | /* Symmetric bass cut */
+ TDA7432_BASS_NORM; /* Normal bass range */
+ buf[2] = 0x3b;
+ if (loudness) /* Turn loudness on? */
+ buf[2] |= TDA7432_LD_ON;
+ buf[3] = TDA7432_TREBLE_0DB | (TDA7432_BASS_0DB << 4);
+ buf[4] = TDA7432_ATTEN_0DB;
+ buf[5] = TDA7432_ATTEN_0DB;
+ buf[6] = TDA7432_ATTEN_0DB;
+ buf[7] = TDA7432_ATTEN_0DB;
+ buf[8] = loudness;
+ if (9 != i2c_master_send(client, buf, 9)) {
v4l2_err(sd, "I/O error, trying tda7432_set\n");
return -1;
}
@@ -252,174 +260,86 @@ static int tda7432_set(struct v4l2_subdev *sd)
return 0;
}
-static void do_tda7432_init(struct v4l2_subdev *sd)
-{
- struct tda7432 *t = to_state(sd);
-
- v4l2_dbg(2, debug, sd, "In tda7432_init\n");
-
- t->input = TDA7432_STEREO_IN | /* Main (stereo) input */
- TDA7432_BASS_SYM | /* Symmetric bass cut */
- TDA7432_BASS_NORM; /* Normal bass range */
- t->volume = 0x3b ; /* -27dB Volume */
- if (loudness) /* Turn loudness on? */
- t->volume |= TDA7432_LD_ON;
- t->muted = 1;
- t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */
- t->bass = TDA7432_BASS_0DB; /* 0dB Bass */
- t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */
- t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */
- t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */
- t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */
- t->loud = loudness; /* insmod parameter */
-
- tda7432_set(sd);
-}
-
-static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tda7432_log_status(struct v4l2_subdev *sd)
{
- struct tda7432 *t = to_state(sd);
+ struct tda7432 *state = to_state(sd);
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value=t->muted;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (!maxvol){ /* max +20db */
- ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
- } else { /* max 0db */
- ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
- }
- return 0;
- case V4L2_CID_AUDIO_BALANCE:
- {
- if ( (t->lf) < (t->rf) )
- /* right is attenuated, balance shifted left */
- ctrl->value = (32768 - 1057*(t->rf));
- else
- /* left is attenuated, balance shifted right */
- ctrl->value = (32768 + 1057*(t->lf));
- return 0;
- }
- case V4L2_CID_AUDIO_BASS:
- {
- /* Bass/treble 4 bits each */
- int bass=t->bass;
- if(bass >= 0x8)
- bass = ~(bass - 0x8) & 0xf;
- ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
- return 0;
- }
- case V4L2_CID_AUDIO_TREBLE:
- {
- int treble=t->treble;
- if(treble >= 0x8)
- treble = ~(treble - 0x8) & 0xf;
- ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
- return 0;
- }
- }
- return -EINVAL;
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+ return 0;
}
-static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct tda7432 *t = to_state(sd);
+ u8 bass, treble, volume;
+ u8 lf, lr, rf, rr;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- t->muted=ctrl->value;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- if(!maxvol){ /* max +20db */
- t->volume = 0x6f - ((ctrl->value)/630);
- } else { /* max 0db */
- t->volume = 0x6f - ((ctrl->value)/829);
- }
- if (loudness) /* Turn on the loudness bit */
- t->volume |= TDA7432_LD_ON;
-
- tda7432_write(sd, TDA7432_VL, t->volume);
- return 0;
- case V4L2_CID_AUDIO_BALANCE:
- if (ctrl->value < 32768) {
+ if (t->balance->val < 0) {
/* shifted to left, attenuate right */
- t->rr = (32768 - ctrl->value)/1057;
- t->rf = t->rr;
- t->lr = TDA7432_ATTEN_0DB;
- t->lf = TDA7432_ATTEN_0DB;
- } else if(ctrl->value > 32769) {
+ rr = rf = -t->balance->val;
+ lr = lf = TDA7432_ATTEN_0DB;
+ } else if (t->balance->val > 0) {
/* shifted to right, attenuate left */
- t->lf = (ctrl->value - 32768)/1057;
- t->lr = t->lf;
- t->rr = TDA7432_ATTEN_0DB;
- t->rf = TDA7432_ATTEN_0DB;
+ rr = rf = TDA7432_ATTEN_0DB;
+ lr = lf = t->balance->val;
} else {
/* centered */
- t->rr = TDA7432_ATTEN_0DB;
- t->rf = TDA7432_ATTEN_0DB;
- t->lf = TDA7432_ATTEN_0DB;
- t->lr = TDA7432_ATTEN_0DB;
+ rr = rf = TDA7432_ATTEN_0DB;
+ lr = lf = TDA7432_ATTEN_0DB;
}
- break;
- case V4L2_CID_AUDIO_BASS:
- t->bass = ctrl->value >> 12;
- if(t->bass>= 0x8)
- t->bass = (~t->bass & 0xf) + 0x8 ;
-
- tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+ if (t->mute->val) {
+ lf |= TDA7432_MUTE;
+ lr |= TDA7432_MUTE;
+ lf |= TDA7432_MUTE;
+ rr |= TDA7432_MUTE;
+ }
+ /* Mute & update balance*/
+ tda7432_write(sd, TDA7432_LF, lf);
+ tda7432_write(sd, TDA7432_LR, lr);
+ tda7432_write(sd, TDA7432_RF, rf);
+ tda7432_write(sd, TDA7432_RR, rr);
return 0;
- case V4L2_CID_AUDIO_TREBLE:
- t->treble= ctrl->value >> 12;
- if(t->treble>= 0x8)
- t->treble = (~t->treble & 0xf) + 0x8 ;
+ case V4L2_CID_AUDIO_VOLUME:
+ volume = 0x6f - ctrl->val;
+ if (loudness) /* Turn on the loudness bit */
+ volume |= TDA7432_LD_ON;
- tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+ tda7432_write(sd, TDA7432_VL, volume);
return 0;
- default:
- return -EINVAL;
- }
-
- /* Used for both mute and balance changes */
- if (t->muted)
- {
- /* Mute & update balance*/
- tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE);
- tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE);
- tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE);
- tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE);
- } else {
- tda7432_write(sd, TDA7432_LF, t->lf);
- tda7432_write(sd, TDA7432_LR, t->lr);
- tda7432_write(sd, TDA7432_RF, t->rf);
- tda7432_write(sd, TDA7432_RR, t->rr);
- }
- return 0;
-}
-
-static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ bass = t->bass->val;
+ treble = t->treble->val;
+ if (bass >= 0x8)
+ bass = 14 - (bass - 8);
+ if (treble >= 0x8)
+ treble = 14 - (treble - 8);
+
+ tda7432_write(sd, TDA7432_TN, 0x10 | (bass << 4) | treble);
+ return 0;
}
return -EINVAL;
}
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops tda7432_core_ops = {
- .queryctrl = tda7432_queryctrl,
- .g_ctrl = tda7432_g_ctrl,
+static const struct v4l2_ctrl_ops tda7432_ctrl_ops = {
.s_ctrl = tda7432_s_ctrl,
};
+static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+ .log_status = tda7432_log_status,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+};
+
static const struct v4l2_subdev_ops tda7432_ops = {
.core = &tda7432_core_ops,
};
@@ -444,6 +364,28 @@ static int tda7432_probe(struct i2c_client *client,
return -ENOMEM;
sd = &t->sd;
v4l2_i2c_subdev_init(sd, client, &tda7432_ops);
+ v4l2_ctrl_handler_init(&t->hdl, 5);
+ v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, maxvol ? 0x68 : 0x4f, 1, maxvol ? 0x5d : 0x47);
+ t->mute = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ t->balance = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+ V4L2_CID_AUDIO_BALANCE, -31, 31, 1, 0);
+ t->bass = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+ V4L2_CID_AUDIO_BASS, 0, 14, 1, 7);
+ t->treble = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+ V4L2_CID_AUDIO_TREBLE, 0, 14, 1, 7);
+ sd->ctrl_handler = &t->hdl;
+ if (t->hdl.error) {
+ int err = t->hdl.error;
+
+ v4l2_ctrl_handler_free(&t->hdl);
+ kfree(t);
+ return err;
+ }
+ v4l2_ctrl_cluster(2, &t->bass);
+ v4l2_ctrl_cluster(2, &t->mute);
+ v4l2_ctrl_handler_setup(&t->hdl);
if (loudness < 0 || loudness > 15) {
v4l2_warn(sd, "loudness parameter must be between 0 and 15\n");
if (loudness < 0)
@@ -452,17 +394,19 @@ static int tda7432_probe(struct i2c_client *client,
loudness = 15;
}
- do_tda7432_init(sd);
+ tda7432_set(sd);
return 0;
}
static int tda7432_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tda7432 *t = to_state(sd);
- do_tda7432_init(sd);
+ tda7432_set(sd);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
+ v4l2_ctrl_handler_free(&t->hdl);
+ kfree(t);
return 0;
}
diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c
index 3d7ddd93282d..01441e35d88b 100644
--- a/drivers/media/i2c/tda9840.c
+++ b/drivers/media/i2c/tda9840.c
@@ -87,7 +87,7 @@ static int tda9840_status(struct v4l2_subdev *sd)
return byte & 0x60;
}
-static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
+static int tda9840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *t)
{
int stat = tda9840_status(sd);
int byte;
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index e747524ba6ed..c4339556a2ea 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -1,7 +1,15 @@
/*
- * ths7303- THS7303 Video Amplifier driver
+ * ths7303/53- THS7303/53 Video Amplifier driver
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * Author: Chaithrika U S <chaithrika@ti.com>
+ *
+ * Contributors:
+ * Hans Verkuil <hans.verkuil@cisco.com>
+ * Lad, Prabhakar <prabhakar.lad@ti.com>
+ * Martin Bugge <marbugge@cisco.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -13,25 +21,27 @@
* GNU General Public License for more details.
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/uaccess.h>
-#include <linux/videodev2.h>
+#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-subdev.h>
+#include <media/ths7303.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
#define THS7303_CHANNEL_1 1
#define THS7303_CHANNEL_2 2
#define THS7303_CHANNEL_3 3
+struct ths7303_state {
+ struct v4l2_subdev sd;
+ struct ths7303_platform_data pdata;
+ struct v4l2_bt_timings bt;
+ int std_id;
+ int stream_on;
+ int driver_data;
+};
+
enum ths7303_filter_mode {
THS7303_FILTER_MODE_480I_576I,
THS7303_FILTER_MODE_480P_576P,
@@ -48,64 +58,84 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level 0-1");
+static inline struct ths7303_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ths7303_state, sd);
+}
+
+static int ths7303_read(struct v4l2_subdev *sd, u8 reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret == 0)
+ return 0;
+ }
+ return ret;
+}
+
/* following function is used to set ths7303 */
int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode)
{
- u8 input_bias_chroma = 3;
- u8 input_bias_luma = 3;
- int disable = 0;
- int err = 0;
- u8 val = 0;
- u8 temp;
-
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ths7303_state *state = to_state(sd);
+ struct ths7303_platform_data *pdata = &state->pdata;
+ u8 val, sel = 0;
+ int err, disable = 0;
if (!client)
return -EINVAL;
switch (mode) {
case THS7303_FILTER_MODE_1080P:
- val = (3 << 6);
- val |= (3 << 3);
+ sel = 0x3; /*1080p and SXGA/UXGA */
break;
case THS7303_FILTER_MODE_720P_1080I:
- val = (2 << 6);
- val |= (2 << 3);
+ sel = 0x2; /*720p, 1080i and SVGA/XGA */
break;
case THS7303_FILTER_MODE_480P_576P:
- val = (1 << 6);
- val |= (1 << 3);
+ sel = 0x1; /* EDTV 480p/576p and VGA */
break;
case THS7303_FILTER_MODE_480I_576I:
+ sel = 0x0; /* SDTV, S-Video, 480i/576i */
break;
- case THS7303_FILTER_MODE_DISABLE:
- pr_info("mode disabled\n");
- /* disable all channels */
- disable = 1;
default:
/* disable all channels */
disable = 1;
}
- /* Setup channel 2 - Luma - Green */
- temp = val;
+
+ val = (sel << 6) | (sel << 3);
if (!disable)
- val |= input_bias_luma;
- err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val);
+ val |= (pdata->ch_1 & 0x27);
+ err = ths7303_write(sd, THS7303_CHANNEL_1, val);
if (err)
goto out;
- /* setup two chroma channels */
+ val = (sel << 6) | (sel << 3);
if (!disable)
- temp |= input_bias_chroma;
-
- err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp);
+ val |= (pdata->ch_2 & 0x27);
+ err = ths7303_write(sd, THS7303_CHANNEL_2, val);
if (err)
goto out;
- err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp);
+ val = (sel << 6) | (sel << 3);
+ if (!disable)
+ val |= (pdata->ch_3 & 0x27);
+ err = ths7303_write(sd, THS7303_CHANNEL_3, val);
if (err)
goto out;
- return err;
+
+ return 0;
out:
pr_info("write byte data failed\n");
return err;
@@ -113,49 +143,209 @@ out:
static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
{
- if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM))
+ struct ths7303_state *state = to_state(sd);
+
+ if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
+ state->std_id = 1;
+ state->bt.pixelclock = 0;
return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
- else
- return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
+ }
+
+ return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
}
-/* for setting filter for HD output */
-static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
- struct v4l2_dv_timings *dv_timings)
+static int ths7303_config(struct v4l2_subdev *sd)
{
- u32 height = dv_timings->bt.height;
- int interlaced = dv_timings->bt.interlaced;
- int res = 0;
+ struct ths7303_state *state = to_state(sd);
+ int res;
+
+ if (!state->stream_on) {
+ ths7303_write(sd, THS7303_CHANNEL_1,
+ (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) |
+ 0x00);
+ ths7303_write(sd, THS7303_CHANNEL_2,
+ (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) |
+ 0x00);
+ ths7303_write(sd, THS7303_CHANNEL_3,
+ (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) |
+ 0x00);
+ return 0;
+ }
- if (height == 1080 && !interlaced)
+ if (state->bt.pixelclock > 120000000)
res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P);
- else if ((height == 720 && !interlaced) ||
- (height == 1080 && interlaced))
+ else if (state->bt.pixelclock > 70000000)
res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I);
- else if ((height == 480 || height == 576) && !interlaced)
+ else if (state->bt.pixelclock > 20000000)
res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P);
+ else if (state->std_id)
+ res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I);
else
/* disable all channels */
res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE);
return res;
+
+}
+
+static int ths7303_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ths7303_state *state = to_state(sd);
+
+ state->stream_on = enable;
+
+ return ths7303_config(sd);
+}
+
+/* for setting filter for HD output */
+static int ths7303_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *dv_timings)
+{
+ struct ths7303_state *state = to_state(sd);
+
+ if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120)
+ return -EINVAL;
+
+ state->bt = dv_timings->bt;
+ state->std_id = 0;
+
+ return ths7303_config(sd);
}
static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ths7303_state *state = to_state(sd);
- return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0);
+ return v4l2_chip_ident_i2c_client(client, chip, state->driver_data, 0);
}
static const struct v4l2_subdev_video_ops ths7303_video_ops = {
+ .s_stream = ths7303_s_stream,
.s_std_output = ths7303_s_std_output,
- .s_dv_timings = ths7303_s_dv_timings,
+ .s_dv_timings = ths7303_s_dv_timings,
};
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+static int ths7303_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ reg->size = 1;
+ reg->val = ths7303_read(sd, reg->reg);
+ return 0;
+}
+
+static int ths7303_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!v4l2_chip_match_i2c_client(client, &reg->match))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ths7303_write(sd, reg->reg, reg->val);
+ return 0;
+}
+#endif
+
+static const char * const stc_lpf_sel_txt[4] = {
+ "500-kHz Filter",
+ "2.5-MHz Filter",
+ "5-MHz Filter",
+ "5-MHz Filter",
+};
+
+static const char * const in_mux_sel_txt[2] = {
+ "Input A Select",
+ "Input B Select",
+};
+
+static const char * const lpf_freq_sel_txt[4] = {
+ "9-MHz LPF",
+ "16-MHz LPF",
+ "35-MHz LPF",
+ "Bypass LPF",
+};
+
+static const char * const in_bias_sel_dis_cont_txt[8] = {
+ "Disable Channel",
+ "Mute Function - No Output",
+ "DC Bias Select",
+ "DC Bias + 250 mV Offset Select",
+ "AC Bias Select",
+ "Sync Tip Clamp with low bias",
+ "Sync Tip Clamp with mid bias",
+ "Sync Tip Clamp with high bias",
+};
+
+static void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg)
+{
+ u8 val = ths7303_read(sd, reg);
+
+ if ((val & 0x7) == 0) {
+ v4l2_info(sd, "Channel %d Off\n", reg);
+ return;
+ }
+
+ v4l2_info(sd, "Channel %d On\n", reg);
+ v4l2_info(sd, " value 0x%x\n", val);
+ v4l2_info(sd, " %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]);
+ v4l2_info(sd, " %s\n", in_mux_sel_txt[(val >> 5) & 0x1]);
+ v4l2_info(sd, " %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]);
+ v4l2_info(sd, " %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]);
+}
+
+static int ths7303_log_status(struct v4l2_subdev *sd)
+{
+ struct ths7303_state *state = to_state(sd);
+
+ v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
+
+ if (state->bt.pixelclock) {
+ struct v4l2_bt_timings *bt = bt = &state->bt;
+ u32 frame_width, frame_height;
+
+ frame_width = bt->width + bt->hfrontporch +
+ bt->hsync + bt->hbackporch;
+ frame_height = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ v4l2_info(sd,
+ "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n",
+ bt->width, bt->height, bt->interlaced ? "i" : "p",
+ (frame_height * frame_width) > 0 ?
+ (int)bt->pixelclock /
+ (frame_height * frame_width) : 0,
+ frame_width, frame_height,
+ (int)bt->pixelclock, bt->polarities);
+ } else {
+ v4l2_info(sd, "no timings set\n");
+ }
+
+ ths7303_log_channel_status(sd, THS7303_CHANNEL_1);
+ ths7303_log_channel_status(sd, THS7303_CHANNEL_2);
+ ths7303_log_channel_status(sd, THS7303_CHANNEL_3);
+
+ return 0;
+}
+
static const struct v4l2_subdev_core_ops ths7303_core_ops = {
.g_chip_ident = ths7303_g_chip_ident,
+ .log_status = ths7303_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ths7303_g_register,
+ .s_register = ths7303_s_register,
+#endif
};
static const struct v4l2_subdev_ops ths7303_ops = {
@@ -163,11 +353,38 @@ static const struct v4l2_subdev_ops ths7303_ops = {
.video = &ths7303_video_ops,
};
+static int ths7303_setup(struct v4l2_subdev *sd)
+{
+ struct ths7303_state *state = to_state(sd);
+ struct ths7303_platform_data *pdata = &state->pdata;
+ int ret;
+ u8 mask;
+
+ state->stream_on = pdata->init_enable;
+
+ mask = state->stream_on ? 0xff : 0xf8;
+
+ ret = ths7303_write(sd, THS7303_CHANNEL_1, pdata->ch_1 & mask);
+ if (ret)
+ return ret;
+
+ ret = ths7303_write(sd, THS7303_CHANNEL_2, pdata->ch_2 & mask);
+ if (ret)
+ return ret;
+
+ ret = ths7303_write(sd, THS7303_CHANNEL_3, pdata->ch_3 & mask);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int ths7303_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct ths7303_platform_data *pdata = client->dev.platform_data;
+ struct ths7303_state *state;
struct v4l2_subdev *sd;
- v4l2_std_id std_id = V4L2_STD_NTSC;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
@@ -175,13 +392,28 @@ static int ths7303_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- sd = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev), GFP_KERNEL);
- if (sd == NULL)
+ state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state),
+ GFP_KERNEL);
+ if (!state)
return -ENOMEM;
+ if (!pdata)
+ v4l_warn(client, "No platform data, using default data!\n");
+ else
+ state->pdata = *pdata;
+
+ sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
- return ths7303_s_std_output(sd, std_id);
+ /* store the driver data to differntiate the chip */
+ state->driver_data = (int)id->driver_data;
+
+ if (ths7303_setup(sd) < 0) {
+ v4l_err(client, "init failed\n");
+ return -EIO;
+ }
+
+ return 0;
}
static int ths7303_remove(struct i2c_client *client)
@@ -194,7 +426,8 @@ static int ths7303_remove(struct i2c_client *client)
}
static const struct i2c_device_id ths7303_id[] = {
- {"ths7303", 0},
+ {"ths7303", V4L2_IDENT_THS7303},
+ {"ths7353", V4L2_IDENT_THS7353},
{},
};
@@ -203,7 +436,7 @@ MODULE_DEVICE_TABLE(i2c, ths7303_id);
static struct i2c_driver ths7303_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "ths7303",
+ .name = "ths73x3",
},
.probe = ths7303_probe,
.remove = ths7303_remove,
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index e3b33b78dd21..b72a59d3216a 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -1761,7 +1761,7 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int tvaudio_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
@@ -1803,7 +1803,7 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
vt->audmode = chip->audmode;
vt->rxsubchans = desc->getrxsubchans(chip);
- vt->capability = V4L2_TUNER_CAP_STEREO |
+ vt->capability |= V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
return 0;
@@ -1817,7 +1817,7 @@ static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
-static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
{
struct CHIPSTATE *chip = to_state(sd);
struct CHIPDESC *desc = chip->desc;
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index aa94ebc2d755..ab8f3fee7e94 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -12,6 +12,7 @@
* Hardik Shah <hardik.shah@ti.com>
* Manjunath Hadli <mrh@ti.com>
* Karicheri Muralidharan <m-karicheri2@ti.com>
+ * Prabhakar Lad <prabhakar.lad@ti.com>
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -33,6 +34,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/module.h>
+#include <linux/v4l2-mediabus.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
@@ -40,12 +42,10 @@
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ctrls.h>
#include <media/tvp514x.h>
+#include <media/media-entity.h>
#include "tvp514x_regs.h"
-/* Module Name */
-#define TVP514X_MODULE_NAME "tvp514x"
-
/* Private macros for TVP */
#define I2C_RETRY_COUNT (5)
#define LOCK_RETRY_COUNT (5)
@@ -91,6 +91,9 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
* @pdata: Board specific
* @ver: Chip version
* @streaming: TVP5146/47 decoder streaming - enabled or disabled.
+ * @pix: Current pixel format
+ * @num_fmts: Number of formats
+ * @fmt_list: Format list
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
@@ -106,12 +109,20 @@ struct tvp514x_decoder {
int ver;
int streaming;
+ struct v4l2_pix_format pix;
+ int num_fmts;
+ const struct v4l2_fmtdesc *fmt_list;
+
enum tvp514x_std current_std;
int num_stds;
const struct tvp514x_std_info *std_list;
/* Input and Output Routing parameters */
u32 input;
u32 output;
+
+ /* mc related members */
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
};
/* TVP514x default register values */
@@ -200,6 +211,21 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
};
/**
+ * List of image formats supported by TVP5146/47 decoder
+ * Currently we are using 8 bit mode only, but can be
+ * extended to 10/20 bit mode.
+ */
+static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = 0,
+ .description = "8-bit UYVY 4:2:2 Format",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ },
+};
+
+/**
* Supported standards -
*
* Currently supports two standards only, need to add support for rest of the
@@ -733,7 +759,7 @@ tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
}
/**
- * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
+ * tvp514x_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt
* @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to the mediabus format structure
*
@@ -751,12 +777,11 @@ tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
/* Calculate height and width based on current standard */
current_std = decoder->current_std;
- f->code = V4L2_MBUS_FMT_YUYV10_2X10;
+ f->code = V4L2_MBUS_FMT_YUYV8_2X8;
f->width = decoder->std_list[current_std].width;
f->height = decoder->std_list[current_std].height;
f->field = V4L2_FIELD_INTERLACED;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
f->width, f->height);
return 0;
@@ -892,6 +917,88 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
.s_ctrl = tvp514x_s_ctrl,
};
+/**
+ * tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle
+ * @code: pointer to v4l2_subdev_mbus_code_enum structure
+ *
+ * Enumertaes mbus codes supported
+ */
+static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ u32 pad = code->pad;
+ u32 index = code->index;
+
+ memset(code, 0, sizeof(*code));
+ code->index = index;
+ code->pad = pad;
+
+ if (index != 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ return 0;
+}
+
+/**
+ * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle
+ * @format: pointer to v4l2_subdev_format structure
+ *
+ * Retrieves pad format which is active or tried based on requirement
+ */
+static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+ __u32 which = format->which;
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ format->format = decoder->format;
+ return 0;
+ }
+
+ format->format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ format->format.width = tvp514x_std_list[decoder->current_std].width;
+ format->format.height = tvp514x_std_list[decoder->current_std].height;
+ format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ format->format.field = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+/**
+ * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format
+ * @sd: pointer to standard V4L2 sub-device structure
+ * @fh: file handle
+ * @format: pointer to v4l2_subdev_format structure
+ *
+ * Set pad format for the output pad
+ */
+static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tvp514x_decoder *decoder = to_decoder(sd);
+
+ if (fmt->format.field != V4L2_FIELD_INTERLACED ||
+ fmt->format.code != V4L2_MBUS_FMT_YUYV8_2X8 ||
+ fmt->format.colorspace != V4L2_COLORSPACE_SMPTE170M ||
+ fmt->format.width != tvp514x_std_list[decoder->current_std].width ||
+ fmt->format.height != tvp514x_std_list[decoder->current_std].height)
+ return -EINVAL;
+
+ decoder->format = fmt->format;
+
+ return 0;
+}
+
static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
@@ -915,13 +1022,33 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_stream = tvp514x_s_stream,
};
+static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
+ .enum_mbus_code = tvp514x_enum_mbus_code,
+ .get_fmt = tvp514x_get_pad_format,
+ .set_fmt = tvp514x_set_pad_format,
+};
+
static const struct v4l2_subdev_ops tvp514x_ops = {
.core = &tvp514x_core_ops,
.video = &tvp514x_video_ops,
+ .pad = &tvp514x_pad_ops,
};
static struct tvp514x_decoder tvp514x_dev = {
.streaming = 0,
+ .fmt_list = tvp514x_fmt_list,
+ .num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
+ .pix = {
+ /* Default to NTSC 8-bit YUV 422 */
+ .width = NTSC_NUM_ACTIVE_PIXELS,
+ .height = NTSC_NUM_ACTIVE_LINES,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2,
+ .sizeimage = NTSC_NUM_ACTIVE_PIXELS * 2 *
+ NTSC_NUM_ACTIVE_LINES,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ },
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
@@ -941,6 +1068,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp514x_decoder *decoder;
struct v4l2_subdev *sd;
+ int ret;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -981,7 +1109,21 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Register with V4L2 layer as slave device */
sd = &decoder->sd;
v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
-
+ strlcpy(sd->name, TVP514X_MODULE_NAME, sizeof(sd->name));
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ decoder->pad.flags = MEDIA_PAD_FL_SOURCE;
+ decoder->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ decoder->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+
+ ret = media_entity_init(&decoder->sd.entity, 1, &decoder->pad, 0);
+ if (ret < 0) {
+ v4l2_err(sd, "%s decoder driver failed to register !!\n",
+ sd->name);
+ kfree(decoder);
+ return ret;
+ }
+#endif
v4l2_ctrl_handler_init(&decoder->hdl, 5);
v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
@@ -995,10 +1137,10 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
sd->ctrl_handler = &decoder->hdl;
if (decoder->hdl.error) {
- int err = decoder->hdl.error;
+ ret = decoder->hdl.error;
v4l2_ctrl_handler_free(&decoder->hdl);
- return err;
+ return ret;
}
v4l2_ctrl_handler_setup(&decoder->hdl);
@@ -1021,6 +1163,9 @@ static int tvp514x_remove(struct i2c_client *client)
struct tvp514x_decoder *decoder = to_decoder(sd);
v4l2_device_unregister_subdev(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ media_entity_cleanup(&decoder->sd.entity);
+#endif
v4l2_ctrl_handler_free(&decoder->hdl);
return 0;
}
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 5967e1a0c809..485159a3c0b7 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1067,7 +1067,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
return 0;
}
-static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 537f6b4d4918..027809cca5f5 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -326,9 +326,8 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = {
{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
};
-/* Preset definition for handling device operation */
-struct tvp7002_preset_definition {
- u32 preset;
+/* Timings definition for handling device operation */
+struct tvp7002_timings_definition {
struct v4l2_dv_timings timings;
const struct i2c_reg_value *p_settings;
enum v4l2_colorspace color_space;
@@ -339,10 +338,9 @@ struct tvp7002_preset_definition {
u16 cpl_max;
};
-/* Struct list for digital video presets */
-static const struct tvp7002_preset_definition tvp7002_presets[] = {
+/* Struct list for digital video timings */
+static const struct tvp7002_timings_definition tvp7002_timings[] = {
{
- V4L2_DV_720P60,
V4L2_DV_BT_CEA_1280X720P60,
tvp7002_parms_720P60,
V4L2_COLORSPACE_REC709,
@@ -353,7 +351,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
153
},
{
- V4L2_DV_1080I60,
V4L2_DV_BT_CEA_1920X1080I60,
tvp7002_parms_1080I60,
V4L2_COLORSPACE_REC709,
@@ -364,7 +361,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
205
},
{
- V4L2_DV_1080I50,
V4L2_DV_BT_CEA_1920X1080I50,
tvp7002_parms_1080I50,
V4L2_COLORSPACE_REC709,
@@ -375,7 +371,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
245
},
{
- V4L2_DV_720P50,
V4L2_DV_BT_CEA_1280X720P50,
tvp7002_parms_720P50,
V4L2_COLORSPACE_REC709,
@@ -386,7 +381,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
183
},
{
- V4L2_DV_1080P60,
V4L2_DV_BT_CEA_1920X1080P60,
tvp7002_parms_1080P60,
V4L2_COLORSPACE_REC709,
@@ -397,7 +391,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
102
},
{
- V4L2_DV_480P59_94,
V4L2_DV_BT_CEA_720X480P59_94,
tvp7002_parms_480P,
V4L2_COLORSPACE_SMPTE170M,
@@ -408,7 +401,6 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
0xffff
},
{
- V4L2_DV_576P50,
V4L2_DV_BT_CEA_720X576P50,
tvp7002_parms_576P,
V4L2_COLORSPACE_SMPTE170M,
@@ -420,7 +412,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
}
};
-#define NUM_PRESETS ARRAY_SIZE(tvp7002_presets)
+#define NUM_TIMINGS ARRAY_SIZE(tvp7002_timings)
/* Device definition */
struct tvp7002 {
@@ -431,7 +423,7 @@ struct tvp7002 {
int ver;
int streaming;
- const struct tvp7002_preset_definition *current_preset;
+ const struct tvp7002_timings_definition *current_timings;
};
/*
@@ -588,32 +580,6 @@ static int tvp7002_write_inittab(struct v4l2_subdev *sd,
return error;
}
-/*
- * tvp7002_s_dv_preset() - Set digital video preset
- * @sd: ptr to v4l2_subdev struct
- * @dv_preset: ptr to v4l2_dv_preset struct
- *
- * Set the digital video preset for a TVP7002 decoder device.
- * Returns zero when successful or -EINVAL if register access fails.
- */
-static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *dv_preset)
-{
- struct tvp7002 *device = to_tvp7002(sd);
- u32 preset;
- int i;
-
- for (i = 0; i < NUM_PRESETS; i++) {
- preset = tvp7002_presets[i].preset;
- if (preset == dv_preset->preset) {
- device->current_preset = &tvp7002_presets[i];
- return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
- }
- }
-
- return -EINVAL;
-}
-
static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *dv_timings)
{
@@ -623,12 +589,12 @@ static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,
if (dv_timings->type != V4L2_DV_BT_656_1120)
return -EINVAL;
- for (i = 0; i < NUM_PRESETS; i++) {
- const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt;
+ for (i = 0; i < NUM_TIMINGS; i++) {
+ const struct v4l2_bt_timings *t = &tvp7002_timings[i].timings.bt;
if (!memcmp(bt, t, &bt->standards - &bt->width)) {
- device->current_preset = &tvp7002_presets[i];
- return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+ device->current_timings = &tvp7002_timings[i];
+ return tvp7002_write_inittab(sd, tvp7002_timings[i].p_settings);
}
}
return -EINVAL;
@@ -639,7 +605,7 @@ static int tvp7002_g_dv_timings(struct v4l2_subdev *sd,
{
struct tvp7002 *device = to_tvp7002(sd);
- *dv_timings = device->current_preset->timings;
+ *dv_timings = device->current_timings->timings;
return 0;
}
@@ -677,19 +643,13 @@ static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl)
static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct tvp7002 *device = to_tvp7002(sd);
- struct v4l2_dv_enum_preset e_preset;
- int error;
+ const struct v4l2_bt_timings *bt = &device->current_timings->timings.bt;
- /* Calculate height and width based on current standard */
- error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
- if (error)
- return error;
-
- f->width = e_preset.width;
- f->height = e_preset.height;
+ f->width = bt->width;
+ f->height = bt->height;
f->code = V4L2_MBUS_FMT_YUYV10_1X20;
- f->field = device->current_preset->scanmode;
- f->colorspace = device->current_preset->color_space;
+ f->field = device->current_timings->scanmode;
+ f->colorspace = device->current_timings->color_space;
v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d",
f->width, f->height);
@@ -697,16 +657,16 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f
}
/*
- * tvp7002_query_dv_preset() - query DV preset
+ * tvp7002_query_dv() - query DV timings
* @sd: pointer to standard V4L2 sub-device structure
- * @qpreset: standard V4L2 v4l2_dv_preset structure
+ * @index: index into the tvp7002_timings array
*
- * Returns the current DV preset by TVP7002. If no active input is
+ * Returns the current DV timings detected by TVP7002. If no active input is
* detected, returns -EINVAL
*/
static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
{
- const struct tvp7002_preset_definition *presets = tvp7002_presets;
+ const struct tvp7002_timings_definition *timings = tvp7002_timings;
u8 progressive;
u32 lpfr;
u32 cpln;
@@ -717,7 +677,7 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
u8 cpl_msb;
/* Return invalid index if no active input is detected */
- *index = NUM_PRESETS;
+ *index = NUM_TIMINGS;
/* Read standards from device registers */
tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error);
@@ -738,39 +698,23 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT;
/* Do checking of video modes */
- for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++)
- if (lpfr == presets->lines_per_frame &&
- progressive == presets->progressive) {
- if (presets->cpl_min == 0xffff)
+ for (*index = 0; *index < NUM_TIMINGS; (*index)++, timings++)
+ if (lpfr == timings->lines_per_frame &&
+ progressive == timings->progressive) {
+ if (timings->cpl_min == 0xffff)
break;
- if (cpln >= presets->cpl_min && cpln <= presets->cpl_max)
+ if (cpln >= timings->cpl_min && cpln <= timings->cpl_max)
break;
}
- if (*index == NUM_PRESETS) {
+ if (*index == NUM_TIMINGS) {
v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
lpfr, cpln);
return -ENOLINK;
}
/* Update lines per frame and clocks per line info */
- v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index);
- return 0;
-}
-
-static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *qpreset)
-{
- int index;
- int err = tvp7002_query_dv(sd, &index);
-
- if (err || index == NUM_PRESETS) {
- qpreset->preset = V4L2_DV_INVALID;
- if (err == -ENOLINK)
- err = 0;
- return err;
- }
- qpreset->preset = tvp7002_presets[index].preset;
+ v4l2_dbg(1, debug, sd, "detected timings: %d\n", *index);
return 0;
}
@@ -782,7 +726,7 @@ static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
if (err)
return err;
- *timings = tvp7002_presets[index].timings;
+ *timings = tvp7002_timings[index].timings;
return 0;
}
@@ -824,7 +768,7 @@ static int tvp7002_g_register(struct v4l2_subdev *sd,
* -EPERM if call not allowed.
*/
static int tvp7002_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -896,35 +840,21 @@ static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable)
*/
static int tvp7002_log_status(struct v4l2_subdev *sd)
{
- const struct tvp7002_preset_definition *presets = tvp7002_presets;
struct tvp7002 *device = to_tvp7002(sd);
- struct v4l2_dv_enum_preset e_preset;
- struct v4l2_dv_preset detected;
- int i;
-
- detected.preset = V4L2_DV_INVALID;
- /* Find my current standard*/
- tvp7002_query_dv_preset(sd, &detected);
+ const struct v4l2_bt_timings *bt;
+ int detected;
- /* Print standard related code values */
- for (i = 0; i < NUM_PRESETS; i++, presets++)
- if (presets->preset == detected.preset)
- break;
+ /* Find my current timings */
+ tvp7002_query_dv(sd, &detected);
- if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset))
- return -EINVAL;
-
- v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name);
- v4l2_info(sd, " Pixels per line: %u\n", e_preset.width);
- v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height);
- if (i == NUM_PRESETS) {
- v4l2_info(sd, "Detected DV Preset: None\n");
+ bt = &device->current_timings->timings.bt;
+ v4l2_info(sd, "Selected DV Timings: %ux%u\n", bt->width, bt->height);
+ if (detected == NUM_TIMINGS) {
+ v4l2_info(sd, "Detected DV Timings: None\n");
} else {
- if (v4l_fill_dv_preset_info(presets->preset, &e_preset))
- return -EINVAL;
- v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name);
- v4l2_info(sd, " Pixels per line: %u\n", e_preset.width);
- v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height);
+ bt = &tvp7002_timings[detected].timings.bt;
+ v4l2_info(sd, "Detected DV Timings: %ux%u\n",
+ bt->width, bt->height);
}
v4l2_info(sd, "Streaming enabled: %s\n",
device->streaming ? "yes" : "no");
@@ -935,31 +865,14 @@ static int tvp7002_log_status(struct v4l2_subdev *sd)
return 0;
}
-/*
- * tvp7002_enum_dv_presets() - Enum supported digital video formats
- * @sd: pointer to standard V4L2 sub-device structure
- * @preset: pointer to format struct
- *
- * Enumerate supported digital video formats.
- */
-static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
- struct v4l2_dv_enum_preset *preset)
-{
- /* Check requested format index is within range */
- if (preset->index >= NUM_PRESETS)
- return -EINVAL;
-
- return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
-}
-
static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
/* Check requested format index is within range */
- if (timings->index >= NUM_PRESETS)
+ if (timings->index >= NUM_TIMINGS)
return -EINVAL;
- timings->timings = tvp7002_presets[timings->index].timings;
+ timings->timings = tvp7002_timings[timings->index].timings;
return 0;
}
@@ -986,9 +899,6 @@ static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
/* Specific video subsystem operation handlers */
static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
- .enum_dv_presets = tvp7002_enum_dv_presets,
- .s_dv_preset = tvp7002_s_dv_preset,
- .query_dv_preset = tvp7002_query_dv_preset,
.g_dv_timings = tvp7002_g_dv_timings,
.s_dv_timings = tvp7002_s_dv_timings,
.enum_dv_timings = tvp7002_enum_dv_timings,
@@ -1019,7 +929,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
{
struct v4l2_subdev *sd;
struct tvp7002 *device;
- struct v4l2_dv_preset preset;
+ struct v4l2_dv_timings timings;
int polarity_a;
int polarity_b;
u8 revision;
@@ -1043,7 +953,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
sd = &device->sd;
device->pdata = c->dev.platform_data;
- device->current_preset = tvp7002_presets;
+ device->current_timings = tvp7002_timings;
/* Tell v4l2 the device is ready */
v4l2_i2c_subdev_init(sd, c, &tvp7002_ops);
@@ -1080,8 +990,8 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
return error;
/* Set registers according to default video mode */
- preset.preset = device->current_preset->preset;
- error = tvp7002_s_dv_preset(sd, &preset);
+ timings = device->current_timings->timings;
+ error = tvp7002_s_dv_timings(sd, &timings);
v4l2_ctrl_handler_init(&device->hdl, 1);
v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c
new file mode 100644
index 000000000000..c5dc2c3bf2d7
--- /dev/null
+++ b/drivers/media/i2c/tw2804.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
+
+#define TW2804_REG_AUTOGAIN 0x02
+#define TW2804_REG_HUE 0x0f
+#define TW2804_REG_SATURATION 0x10
+#define TW2804_REG_CONTRAST 0x11
+#define TW2804_REG_BRIGHTNESS 0x12
+#define TW2804_REG_COLOR_KILLER 0x14
+#define TW2804_REG_GAIN 0x3c
+#define TW2804_REG_CHROMA_GAIN 0x3d
+#define TW2804_REG_BLUE_BALANCE 0x3e
+#define TW2804_REG_RED_BALANCE 0x3f
+
+struct tw2804 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ u8 channel:2;
+ u8 input:1;
+ int norm;
+};
+
+static const u8 global_registers[] = {
+ 0x39, 0x00,
+ 0x3a, 0xff,
+ 0x3b, 0x84,
+ 0x3c, 0x80,
+ 0x3d, 0x80,
+ 0x3e, 0x82,
+ 0x3f, 0x82,
+ 0x78, 0x00,
+ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static const u8 channel_registers[] = {
+ 0x01, 0xc4,
+ 0x02, 0xa5,
+ 0x03, 0x20,
+ 0x04, 0xd0,
+ 0x05, 0x20,
+ 0x06, 0xd0,
+ 0x07, 0x88,
+ 0x08, 0x20,
+ 0x09, 0x07,
+ 0x0a, 0xf0,
+ 0x0b, 0x07,
+ 0x0c, 0xf0,
+ 0x0d, 0x40,
+ 0x0e, 0xd2,
+ 0x0f, 0x80,
+ 0x10, 0x80,
+ 0x11, 0x80,
+ 0x12, 0x80,
+ 0x13, 0x1f,
+ 0x14, 0x00,
+ 0x15, 0x00,
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0xff,
+ 0x19, 0xff,
+ 0x1a, 0xff,
+ 0x1b, 0xff,
+ 0x1c, 0xff,
+ 0x1d, 0xff,
+ 0x1e, 0xff,
+ 0x1f, 0xff,
+ 0x20, 0x07,
+ 0x21, 0x07,
+ 0x22, 0x00,
+ 0x23, 0x91,
+ 0x24, 0x51,
+ 0x25, 0x03,
+ 0x26, 0x00,
+ 0x27, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x00,
+ 0x2a, 0x00,
+ 0x2b, 0x00,
+ 0x2c, 0x00,
+ 0x2d, 0x00,
+ 0x2e, 0x00,
+ 0x2f, 0x00,
+ 0x30, 0x00,
+ 0x31, 0x00,
+ 0x32, 0x00,
+ 0x33, 0x00,
+ 0x34, 0x00,
+ 0x35, 0x00,
+ 0x36, 0x00,
+ 0x37, 0x00,
+ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel)
+{
+ return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
+}
+
+static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel)
+{
+ int ret;
+ int i;
+
+ for (i = 0; regs[i] != 0xff; i += 2) {
+ ret = i2c_smbus_write_byte_data(client,
+ regs[i] | (channel << 6), regs[i + 1]);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int read_reg(struct i2c_client *client, u8 reg, u8 channel)
+{
+ return i2c_smbus_read_byte_data(client, (reg) | (channel << 6));
+}
+
+static inline struct tw2804 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tw2804, sd);
+}
+
+static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct tw2804, hdl);
+}
+
+static int tw2804_log_status(struct v4l2_subdev *sd)
+{
+ struct tw2804 *state = to_state(sd);
+
+ v4l2_info(sd, "Standard: %s\n",
+ state->norm & V4L2_STD_525_60 ? "60 Hz" : "50 Hz");
+ v4l2_info(sd, "Channel: %d\n", state->channel);
+ v4l2_info(sd, "Input: %d\n", state->input);
+ return v4l2_ctrl_subdev_log_status(sd);
+}
+
+/*
+ * These volatile controls are needed because all four channels share
+ * these controls. So a change made to them through one channel would
+ * require another channel to be updated.
+ *
+ * Normally this would have been done in a different way, but since the one
+ * board that uses this driver sees this single chip as if it was on four
+ * different i2c adapters (each adapter belonging to a separate instance of
+ * the same USB driver) there is no reliable method that I have found to let
+ * the instances know about each other.
+ *
+ * So implementing these global registers as volatile is the best we can do.
+ */
+static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw2804 *state = to_state_from_ctrl(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->val = read_reg(client, TW2804_REG_GAIN, 0);
+ return 0;
+
+ case V4L2_CID_CHROMA_GAIN:
+ ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0);
+ return 0;
+
+ case V4L2_CID_BLUE_BALANCE:
+ ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0);
+ return 0;
+
+ case V4L2_CID_RED_BALANCE:
+ ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0);
+ return 0;
+ }
+ return 0;
+}
+
+static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw2804 *state = to_state_from_ctrl(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+ int addr;
+ int reg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ addr = TW2804_REG_AUTOGAIN;
+ reg = read_reg(client, addr, state->channel);
+ if (reg < 0)
+ return reg;
+ if (ctrl->val == 0)
+ reg &= ~(1 << 7);
+ else
+ reg |= 1 << 7;
+ return write_reg(client, addr, reg, state->channel);
+
+ case V4L2_CID_COLOR_KILLER:
+ addr = TW2804_REG_COLOR_KILLER;
+ reg = read_reg(client, addr, state->channel);
+ if (reg < 0)
+ return reg;
+ reg = (reg & ~(0x03)) | (ctrl->val == 0 ? 0x02 : 0x03);
+ return write_reg(client, addr, reg, state->channel);
+
+ case V4L2_CID_GAIN:
+ return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0);
+
+ case V4L2_CID_CHROMA_GAIN:
+ return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0);
+
+ case V4L2_CID_BLUE_BALANCE:
+ return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0);
+
+ case V4L2_CID_RED_BALANCE:
+ return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0);
+
+ case V4L2_CID_BRIGHTNESS:
+ return write_reg(client, TW2804_REG_BRIGHTNESS,
+ ctrl->val, state->channel);
+
+ case V4L2_CID_CONTRAST:
+ return write_reg(client, TW2804_REG_CONTRAST,
+ ctrl->val, state->channel);
+
+ case V4L2_CID_SATURATION:
+ return write_reg(client, TW2804_REG_SATURATION,
+ ctrl->val, state->channel);
+
+ case V4L2_CID_HUE:
+ return write_reg(client, TW2804_REG_HUE,
+ ctrl->val, state->channel);
+
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct tw2804 *dec = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ bool is_60hz = norm & V4L2_STD_525_60;
+ u8 regs[] = {
+ 0x01, is_60hz ? 0xc4 : 0x84,
+ 0x09, is_60hz ? 0x07 : 0x04,
+ 0x0a, is_60hz ? 0xf0 : 0x20,
+ 0x0b, is_60hz ? 0x07 : 0x04,
+ 0x0c, is_60hz ? 0xf0 : 0x20,
+ 0x0d, is_60hz ? 0x40 : 0x4a,
+ 0x16, is_60hz ? 0x00 : 0x40,
+ 0x17, is_60hz ? 0x00 : 0x40,
+ 0x20, is_60hz ? 0x07 : 0x0f,
+ 0x21, is_60hz ? 0x07 : 0x0f,
+ 0xff, 0xff,
+ };
+
+ write_regs(client, regs, dec->channel);
+ dec->norm = norm;
+ return 0;
+}
+
+static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+ u32 config)
+{
+ struct tw2804 *dec = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int reg;
+
+ if (config && config - 1 != dec->channel) {
+ if (config > 4) {
+ dev_err(&client->dev,
+ "channel %d is not between 1 and 4!\n", config);
+ return -EINVAL;
+ }
+ dec->channel = config - 1;
+ dev_dbg(&client->dev, "initializing TW2804 channel %d\n",
+ dec->channel);
+ if (dec->channel == 0 &&
+ write_regs(client, global_registers, 0) < 0) {
+ dev_err(&client->dev,
+ "error initializing TW2804 global registers\n");
+ return -EIO;
+ }
+ if (write_regs(client, channel_registers, dec->channel) < 0) {
+ dev_err(&client->dev,
+ "error initializing TW2804 channel %d\n",
+ dec->channel);
+ return -EIO;
+ }
+ }
+
+ if (input > 1)
+ return -EINVAL;
+
+ if (input == dec->input)
+ return 0;
+
+ reg = read_reg(client, 0x22, dec->channel);
+
+ if (reg >= 0) {
+ if (input == 0)
+ reg &= ~(1 << 2);
+ else
+ reg |= 1 << 2;
+ reg = write_reg(client, 0x22, reg, dec->channel);
+ }
+
+ if (reg >= 0)
+ dec->input = input;
+ else
+ return reg;
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
+ .g_volatile_ctrl = tw2804_g_volatile_ctrl,
+ .s_ctrl = tw2804_s_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops tw2804_video_ops = {
+ .s_routing = tw2804_s_video_routing,
+};
+
+static const struct v4l2_subdev_core_ops tw2804_core_ops = {
+ .log_status = tw2804_log_status,
+ .s_std = tw2804_s_std,
+};
+
+static const struct v4l2_subdev_ops tw2804_ops = {
+ .core = &tw2804_core_ops,
+ .video = &tw2804_video_ops,
+};
+
+static int tw2804_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct tw2804 *state;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl *ctrl;
+ int err;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ state = kzalloc(sizeof(struct tw2804), GFP_KERNEL);
+
+ if (state == NULL)
+ return -ENOMEM;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &tw2804_ops);
+ state->channel = -1;
+ state->norm = V4L2_STD_NTSC;
+
+ v4l2_ctrl_handler_init(&state->hdl, 10);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_HUE, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 0);
+ ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_GAIN, 0, 255, 1, 128);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_CHROMA_GAIN, 0, 255, 1, 128);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 255, 1, 122);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 255, 1, 122);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ sd->ctrl_handler = &state->hdl;
+ err = state->hdl.error;
+ if (err) {
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ return 0;
+}
+
+static int tw2804_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tw2804 *state = to_state(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return 0;
+}
+
+static const struct i2c_device_id tw2804_id[] = {
+ { "tw2804", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw2804_id);
+
+static struct i2c_driver tw2804_driver = {
+ .driver = {
+ .name = "tw2804",
+ },
+ .probe = tw2804_probe,
+ .remove = tw2804_remove,
+ .id_table = tw2804_id,
+};
+
+module_i2c_driver(tw2804_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver");
+MODULE_AUTHOR("Micronas USA Inc");
diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c
new file mode 100644
index 000000000000..87880b19d8c3
--- /dev/null
+++ b/drivers/media/i2c/tw9903.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/slab.h>
+
+MODULE_DESCRIPTION("TW9903 I2C subdev driver");
+MODULE_LICENSE("GPL v2");
+
+/*
+ * This driver is based on the wis-tw9903.c source that was in
+ * drivers/staging/media/go7007. That source had commented out code for
+ * saturation and scaling (neither seemed to work). If anyone ever gets
+ * hardware to test this driver, then that code might be useful to look at.
+ * You need to get the kernel sources of, say, kernel 3.8 where that
+ * wis-tw9903 driver is still present.
+ */
+
+struct tw9903 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ v4l2_std_id norm;
+};
+
+static inline struct tw9903 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tw9903, sd);
+}
+
+static const u8 initial_registers[] = {
+ 0x02, 0x44, /* input 1, composite */
+ 0x03, 0x92, /* correct digital format */
+ 0x04, 0x00,
+ 0x05, 0x80, /* or 0x00 for PAL */
+ 0x06, 0x40, /* second internal current reference */
+ 0x07, 0x02, /* window */
+ 0x08, 0x14, /* window */
+ 0x09, 0xf0, /* window */
+ 0x0a, 0x81, /* window */
+ 0x0b, 0xd0, /* window */
+ 0x0c, 0x8c,
+ 0x0d, 0x00, /* scaling */
+ 0x0e, 0x11, /* scaling */
+ 0x0f, 0x00, /* scaling */
+ 0x10, 0x00, /* brightness */
+ 0x11, 0x60, /* contrast */
+ 0x12, 0x01, /* sharpness */
+ 0x13, 0x7f, /* U gain */
+ 0x14, 0x5a, /* V gain */
+ 0x15, 0x00, /* hue */
+ 0x16, 0xc3, /* sharpness */
+ 0x18, 0x00,
+ 0x19, 0x58, /* vbi */
+ 0x1a, 0x80,
+ 0x1c, 0x0f, /* video norm */
+ 0x1d, 0x7f, /* video norm */
+ 0x20, 0xa0, /* clamping gain (working 0x50) */
+ 0x21, 0x22,
+ 0x22, 0xf0,
+ 0x23, 0xfe,
+ 0x24, 0x3c,
+ 0x25, 0x38,
+ 0x26, 0x44,
+ 0x27, 0x20,
+ 0x28, 0x00,
+ 0x29, 0x15,
+ 0x2a, 0xa0,
+ 0x2b, 0x44,
+ 0x2c, 0x37,
+ 0x2d, 0x00,
+ 0x2e, 0xa5, /* burst PLL control (working: a9) */
+ 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */
+ 0x31, 0x00,
+ 0x33, 0x22,
+ 0x34, 0x11,
+ 0x35, 0x35,
+ 0x3b, 0x05,
+ 0x06, 0xc0, /* reset device */
+ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct v4l2_subdev *sd, const u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0x00; i += 2)
+ if (write_reg(sd, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int tw9903_s_video_routing(struct v4l2_subdev *sd, u32 input,
+ u32 output, u32 config)
+{
+ write_reg(sd, 0x02, 0x40 | (input << 1));
+ return 0;
+}
+
+static int tw9903_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct tw9903 *dec = to_state(sd);
+ bool is_60hz = norm & V4L2_STD_525_60;
+ static const u8 config_60hz[] = {
+ 0x05, 0x80,
+ 0x07, 0x02,
+ 0x08, 0x14,
+ 0x09, 0xf0,
+ 0, 0,
+ };
+ static const u8 config_50hz[] = {
+ 0x05, 0x00,
+ 0x07, 0x12,
+ 0x08, 0x18,
+ 0x09, 0x20,
+ 0, 0,
+ };
+
+ write_regs(sd, is_60hz ? config_60hz : config_50hz);
+ dec->norm = norm;
+ return 0;
+}
+
+
+static int tw9903_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw9903 *dec = container_of(ctrl->handler, struct tw9903, hdl);
+ struct v4l2_subdev *sd = &dec->sd;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ write_reg(sd, 0x10, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ write_reg(sd, 0x11, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ write_reg(sd, 0x15, ctrl->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int tw9903_log_status(struct v4l2_subdev *sd)
+{
+ struct tw9903 *dec = to_state(sd);
+ bool is_60hz = dec->norm & V4L2_STD_525_60;
+
+ v4l2_info(sd, "Standard: %d Hz\n", is_60hz ? 60 : 50);
+ v4l2_ctrl_subdev_log_status(sd);
+ return 0;
+}
+
+/* --------------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops tw9903_ctrl_ops = {
+ .s_ctrl = tw9903_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tw9903_core_ops = {
+ .log_status = tw9903_log_status,
+ .s_std = tw9903_s_std,
+};
+
+static const struct v4l2_subdev_video_ops tw9903_video_ops = {
+ .s_routing = tw9903_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops tw9903_ops = {
+ .core = &tw9903_core_ops,
+ .video = &tw9903_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+static int tw9903_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tw9903 *dec;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ dec = kzalloc(sizeof(struct tw9903), GFP_KERNEL);
+ if (dec == NULL)
+ return -ENOMEM;
+ sd = &dec->sd;
+ v4l2_i2c_subdev_init(sd, client, &tw9903_ops);
+ hdl = &dec->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 0x60);
+ v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(dec);
+ return err;
+ }
+
+ /* Initialize tw9903 */
+ dec->norm = V4L2_STD_NTSC;
+
+ if (write_regs(sd, initial_registers) < 0) {
+ v4l2_err(client, "error initializing TW9903\n");
+ kfree(dec);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tw9903_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&to_state(sd)->hdl);
+ kfree(to_state(sd));
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id tw9903_id[] = {
+ { "tw9903", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9903_id);
+
+static struct i2c_driver tw9903_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tw9903",
+ },
+ .probe = tw9903_probe,
+ .remove = tw9903_remove,
+ .id_table = tw9903_id,
+};
+module_i2c_driver(tw9903_driver);
diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c
new file mode 100644
index 000000000000..accd79e5a7fd
--- /dev/null
+++ b/drivers/media/i2c/tw9906.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+MODULE_DESCRIPTION("TW9906 I2C subdev driver");
+MODULE_LICENSE("GPL v2");
+
+struct tw9906 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ v4l2_std_id norm;
+};
+
+static inline struct tw9906 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct tw9906, sd);
+}
+
+static const u8 initial_registers[] = {
+ 0x02, 0x40, /* input 0, composite */
+ 0x03, 0xa2, /* correct digital format */
+ 0x05, 0x81, /* or 0x01 for PAL */
+ 0x07, 0x02, /* window */
+ 0x08, 0x14, /* window */
+ 0x09, 0xf0, /* window */
+ 0x0a, 0x10, /* window */
+ 0x0b, 0xd0, /* window */
+ 0x0d, 0x00, /* scaling */
+ 0x0e, 0x11, /* scaling */
+ 0x0f, 0x00, /* scaling */
+ 0x10, 0x00, /* brightness */
+ 0x11, 0x60, /* contrast */
+ 0x12, 0x11, /* sharpness */
+ 0x13, 0x7e, /* U gain */
+ 0x14, 0x7e, /* V gain */
+ 0x15, 0x00, /* hue */
+ 0x19, 0x57, /* vbi */
+ 0x1a, 0x0f,
+ 0x1b, 0x40,
+ 0x29, 0x03,
+ 0x55, 0x00,
+ 0x6b, 0x26,
+ 0x6c, 0x36,
+ 0x6d, 0xf0,
+ 0x6e, 0x41,
+ 0x6f, 0x13,
+ 0xad, 0x70,
+ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct v4l2_subdev *sd, const u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0x00; i += 2)
+ if (write_reg(sd, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int tw9906_s_video_routing(struct v4l2_subdev *sd, u32 input,
+ u32 output, u32 config)
+{
+ write_reg(sd, 0x02, 0x40 | (input << 1));
+ return 0;
+}
+
+static int tw9906_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct tw9906 *dec = to_state(sd);
+ bool is_60hz = norm & V4L2_STD_525_60;
+ static const u8 config_60hz[] = {
+ 0x05, 0x81,
+ 0x07, 0x02,
+ 0x08, 0x14,
+ 0x09, 0xf0,
+ 0, 0,
+ };
+ static const u8 config_50hz[] = {
+ 0x05, 0x01,
+ 0x07, 0x12,
+ 0x08, 0x18,
+ 0x09, 0x20,
+ 0, 0,
+ };
+
+ write_regs(sd, is_60hz ? config_60hz : config_50hz);
+ dec->norm = norm;
+ return 0;
+}
+
+static int tw9906_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw9906 *dec = container_of(ctrl->handler, struct tw9906, hdl);
+ struct v4l2_subdev *sd = &dec->sd;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ write_reg(sd, 0x10, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ write_reg(sd, 0x11, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ write_reg(sd, 0x15, ctrl->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int tw9906_log_status(struct v4l2_subdev *sd)
+{
+ struct tw9906 *dec = to_state(sd);
+ bool is_60hz = dec->norm & V4L2_STD_525_60;
+
+ v4l2_info(sd, "Standard: %d Hz\n", is_60hz ? 60 : 50);
+ v4l2_ctrl_subdev_log_status(sd);
+ return 0;
+}
+
+/* --------------------------------------------------------------------------*/
+
+static const struct v4l2_ctrl_ops tw9906_ctrl_ops = {
+ .s_ctrl = tw9906_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tw9906_core_ops = {
+ .log_status = tw9906_log_status,
+ .s_std = tw9906_s_std,
+};
+
+static const struct v4l2_subdev_video_ops tw9906_video_ops = {
+ .s_routing = tw9906_s_video_routing,
+};
+
+static const struct v4l2_subdev_ops tw9906_ops = {
+ .core = &tw9906_core_ops,
+ .video = &tw9906_video_ops,
+};
+
+static int tw9906_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tw9906 *dec;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ dec = kzalloc(sizeof(struct tw9906), GFP_KERNEL);
+ if (dec == NULL)
+ return -ENOMEM;
+ sd = &dec->sd;
+ v4l2_i2c_subdev_init(sd, client, &tw9906_ops);
+ hdl = &dec->hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 0x60);
+ v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(dec);
+ return err;
+ }
+
+ /* Initialize tw9906 */
+ dec->norm = V4L2_STD_NTSC;
+
+ if (write_regs(sd, initial_registers) < 0) {
+ v4l2_err(client, "error initializing TW9906\n");
+ kfree(dec);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tw9906_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&to_state(sd)->hdl);
+ kfree(to_state(sd));
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id tw9906_id[] = {
+ { "tw9906", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9906_id);
+
+static struct i2c_driver tw9906_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tw9906",
+ },
+ .probe = tw9906_probe,
+ .remove = tw9906_remove,
+ .id_table = tw9906_id,
+};
+module_i2c_driver(tw9906_driver);
diff --git a/drivers/staging/media/go7007/wis-uda1342.c b/drivers/media/i2c/uda1342.c
index 582ea120a531..3af408556d27 100644
--- a/drivers/staging/media/go7007/wis-uda1342.c
+++ b/drivers/media/i2c/uda1342.c
@@ -19,10 +19,9 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/tvaudio.h>
-#include <media/v4l2-common.h>
-
-#include "wis-i2c.h"
+#include <media/v4l2-device.h>
+#include <media/uda1342.h>
+#include <linux/slab.h>
static int write_reg(struct i2c_client *client, int reg, int value)
{
@@ -31,38 +30,38 @@ static int write_reg(struct i2c_client *client, int reg, int value)
return 0;
}
-static int wis_uda1342_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
+static int uda1342_s_routing(struct v4l2_subdev *sd,
+ u32 input, u32 output, u32 config)
{
- switch (cmd) {
- case VIDIOC_S_AUDIO:
- {
- int *inp = arg;
-
- switch (*inp) {
- case TVAUDIO_INPUT_TUNER:
- write_reg(client, 0x00, 0x1441); /* select input 2 */
- break;
- case TVAUDIO_INPUT_EXTERN:
- write_reg(client, 0x00, 0x1241); /* select input 1 */
- break;
- default:
- dev_err(&client->dev, "input %d not supported\n",
- *inp);
- break;
- }
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ switch (input) {
+ case UDA1342_IN1:
+ write_reg(client, 0x00, 0x1241); /* select input 1 */
+ break;
+ case UDA1342_IN2:
+ write_reg(client, 0x00, 0x1441); /* select input 2 */
break;
- }
default:
+ v4l2_err(sd, "input %d not supported\n", input);
break;
}
return 0;
}
-static int wis_uda1342_probe(struct i2c_client *client,
+static const struct v4l2_subdev_audio_ops uda1342_audio_ops = {
+ .s_routing = uda1342_s_routing,
+};
+
+static const struct v4l2_subdev_ops uda1342_ops = {
+ .audio = &uda1342_audio_ops,
+};
+
+static int uda1342_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
+ struct v4l2_subdev *sd;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -70,33 +69,45 @@ static int wis_uda1342_probe(struct i2c_client *client,
dev_dbg(&client->dev, "initializing UDA1342 at address %d on %s\n",
client->addr, adapter->name);
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(sd, client, &uda1342_ops);
+
write_reg(client, 0x00, 0x8000); /* reset registers */
write_reg(client, 0x00, 0x1241); /* select input 1 */
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
return 0;
}
-static int wis_uda1342_remove(struct i2c_client *client)
+static int uda1342_remove(struct i2c_client *client)
{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
return 0;
}
-static const struct i2c_device_id wis_uda1342_id[] = {
- { "wis_uda1342", 0 },
+static const struct i2c_device_id uda1342_id[] = {
+ { "uda1342", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, wis_uda1342_id);
+MODULE_DEVICE_TABLE(i2c, uda1342_id);
-static struct i2c_driver wis_uda1342_driver = {
+static struct i2c_driver uda1342_driver = {
.driver = {
- .name = "WIS UDA1342 I2C driver",
+ .name = "uda1342",
},
- .probe = wis_uda1342_probe,
- .remove = wis_uda1342_remove,
- .command = wis_uda1342_command,
- .id_table = wis_uda1342_id,
+ .probe = uda1342_probe,
+ .remove = uda1342_remove,
+ .id_table = uda1342_id,
};
-module_i2c_driver(wis_uda1342_driver);
+module_i2c_driver(uda1342_driver);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c
index 1e7446542091..f0a09214c519 100644
--- a/drivers/media/i2c/upd64031a.c
+++ b/drivers/media/i2c/upd64031a.c
@@ -111,7 +111,7 @@ static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val)
/* ------------------------------------------------------------------------ */
/* The input changed due to new input or channel changed */
-static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+static int upd64031a_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
{
struct upd64031a_state *state = to_state(sd);
u8 reg = state->regs[R00];
@@ -175,7 +175,7 @@ static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
return 0;
}
-static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c
index 75d6acc62018..343e0215f74c 100644
--- a/drivers/media/i2c/upd64083.c
+++ b/drivers/media/i2c/upd64083.c
@@ -133,7 +133,7 @@ static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register
return 0;
}
-static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
index 7cfbc9d94a48..e71f139695af 100644
--- a/drivers/media/i2c/vp27smpx.c
+++ b/drivers/media/i2c/vp27smpx.c
@@ -90,7 +90,7 @@ static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
return 0;
}
-static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int vp27smpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct vp27smpx_state *state = to_state(sd);
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index 9ac1b8c3a837..f366fad6269e 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -748,7 +748,7 @@ static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
return 0;
}
-static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c
index bee77ea9f49e..27c27b4ae238 100644
--- a/drivers/media/i2c/wm8775.c
+++ b/drivers/media/i2c/wm8775.c
@@ -174,7 +174,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
return 0;
}
-static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
+static int wm8775_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq)
{
wm8775_set_audio(sd, 0);
return 0;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index d01fcb7e87c2..1957c0df08fd 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -20,10 +20,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/types.h>
+#include <linux/compat.h>
+#include <linux/export.h>
#include <linux/ioctl.h>
#include <linux/media.h>
-#include <linux/export.h>
+#include <linux/types.h>
#include <media/media-device.h>
#include <media/media-devnode.h>
@@ -101,9 +102,12 @@ static long media_device_enum_entities(struct media_device *mdev,
return -EINVAL;
u_ent.id = ent->id;
- u_ent.name[0] = '\0';
- if (ent->name)
- strlcpy(u_ent.name, ent->name, sizeof(u_ent.name));
+ if (ent->name) {
+ strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
+ u_ent.name[sizeof(u_ent.name) - 1] = '\0';
+ } else {
+ memset(u_ent.name, 0, sizeof(u_ent.name));
+ }
u_ent.type = ent->type;
u_ent.revision = ent->revision;
u_ent.flags = ent->flags;
@@ -124,35 +128,31 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad,
upad->flags = kpad->flags;
}
-static long media_device_enum_links(struct media_device *mdev,
- struct media_links_enum __user *ulinks)
+static long __media_device_enum_links(struct media_device *mdev,
+ struct media_links_enum *links)
{
struct media_entity *entity;
- struct media_links_enum links;
- if (copy_from_user(&links, ulinks, sizeof(links)))
- return -EFAULT;
-
- entity = find_entity(mdev, links.entity);
+ entity = find_entity(mdev, links->entity);
if (entity == NULL)
return -EINVAL;
- if (links.pads) {
+ if (links->pads) {
unsigned int p;
for (p = 0; p < entity->num_pads; p++) {
struct media_pad_desc pad;
media_device_kpad_to_upad(&entity->pads[p], &pad);
- if (copy_to_user(&links.pads[p], &pad, sizeof(pad)))
+ if (copy_to_user(&links->pads[p], &pad, sizeof(pad)))
return -EFAULT;
}
}
- if (links.links) {
+ if (links->links) {
struct media_link_desc __user *ulink;
unsigned int l;
- for (l = 0, ulink = links.links; l < entity->num_links; l++) {
+ for (l = 0, ulink = links->links; l < entity->num_links; l++) {
struct media_link_desc link;
/* Ignore backlinks. */
@@ -169,8 +169,26 @@ static long media_device_enum_links(struct media_device *mdev,
ulink++;
}
}
+
+ return 0;
+}
+
+static long media_device_enum_links(struct media_device *mdev,
+ struct media_links_enum __user *ulinks)
+{
+ struct media_links_enum links;
+ int rval;
+
+ if (copy_from_user(&links, ulinks, sizeof(links)))
+ return -EFAULT;
+
+ rval = __media_device_enum_links(mdev, &links);
+ if (rval < 0)
+ return rval;
+
if (copy_to_user(ulinks, &links, sizeof(*ulinks)))
return -EFAULT;
+
return 0;
}
@@ -251,10 +269,71 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
return ret;
}
+#ifdef CONFIG_COMPAT
+
+struct media_links_enum32 {
+ __u32 entity;
+ compat_uptr_t pads; /* struct media_pad_desc * */
+ compat_uptr_t links; /* struct media_link_desc * */
+ __u32 reserved[4];
+};
+
+static long media_device_enum_links32(struct media_device *mdev,
+ struct media_links_enum32 __user *ulinks)
+{
+ struct media_links_enum links;
+ compat_uptr_t pads_ptr, links_ptr;
+
+ memset(&links, 0, sizeof(links));
+
+ if (get_user(links.entity, &ulinks->entity)
+ || get_user(pads_ptr, &ulinks->pads)
+ || get_user(links_ptr, &ulinks->links))
+ return -EFAULT;
+
+ links.pads = compat_ptr(pads_ptr);
+ links.links = compat_ptr(links_ptr);
+
+ return __media_device_enum_links(mdev, &links);
+}
+
+#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
+
+static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct media_devnode *devnode = media_devnode_data(filp);
+ struct media_device *dev = to_media_device(devnode);
+ long ret;
+
+ switch (cmd) {
+ case MEDIA_IOC_DEVICE_INFO:
+ case MEDIA_IOC_ENUM_ENTITIES:
+ case MEDIA_IOC_SETUP_LINK:
+ return media_device_ioctl(filp, cmd, arg);
+
+ case MEDIA_IOC_ENUM_LINKS32:
+ mutex_lock(&dev->graph_mutex);
+ ret = media_device_enum_links32(dev,
+ (struct media_links_enum32 __user *)arg);
+ mutex_unlock(&dev->graph_mutex);
+ break;
+
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_COMPAT */
+
static const struct media_file_operations media_device_fops = {
.owner = THIS_MODULE,
.open = media_device_open,
.ioctl = media_device_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = media_device_compat_ioctl,
+#endif /* CONFIG_COMPAT */
.release = media_device_close,
};
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index 023b2a1cbb9b..fb0f0469fad7 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -116,19 +116,41 @@ static unsigned int media_poll(struct file *filp,
return mdev->fops->poll(filp, poll);
}
-static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static long
+__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
+ long (*ioctl_func)(struct file *filp, unsigned int cmd,
+ unsigned long arg))
{
struct media_devnode *mdev = media_devnode_data(filp);
- if (!mdev->fops->ioctl)
+ if (!ioctl_func)
return -ENOTTY;
if (!media_devnode_is_registered(mdev))
return -EIO;
- return mdev->fops->ioctl(filp, cmd, arg);
+ return ioctl_func(filp, cmd, arg);
+}
+
+static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl);
}
+#ifdef CONFIG_COMPAT
+
+static long media_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct media_devnode *mdev = media_devnode_data(filp);
+
+ return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl);
+}
+
+#endif /* CONFIG_COMPAT */
+
/* Override for the open function */
static int media_open(struct inode *inode, struct file *filp)
{
@@ -188,6 +210,9 @@ static const struct file_operations media_devnode_fops = {
.write = media_write,
.open = media_open,
.unlocked_ioctl = media_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = media_compat_ioctl,
+#endif /* CONFIG_COMPAT */
.release = media_release,
.poll = media_poll,
.llseek = no_llseek,
diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c
index 15d34935e00b..912c2814c6cf 100644
--- a/drivers/media/mmc/siano/smssdio.c
+++ b/drivers/media/mmc/siano/smssdio.c
@@ -43,6 +43,7 @@
#include "smscoreapi.h"
#include "sms-cards.h"
+#include "smsendian.h"
/* Registers */
@@ -61,6 +62,16 @@ static const struct sdio_device_id smssdio_ids[] = {
.driver_data = SMS1XXX_BOARD_SIANO_VEGA},
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
.driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x302),
+ .driver_data = SMS1XXX_BOARD_SIANO_MING},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x500),
+ .driver_data = SMS1XXX_BOARD_SIANO_PELE},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x600),
+ .driver_data = SMS1XXX_BOARD_SIANO_RIO},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x700),
+ .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x800),
+ .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530},
{ /* end: all zeroes */ },
};
@@ -87,6 +98,7 @@ static int smssdio_sendrequest(void *context, void *buffer, size_t size)
sdio_claim_host(smsdev->func);
+ smsendian_handle_tx_message((struct sms_msg_data *) buffer);
while (size >= smsdev->func->cur_blksize) {
ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
buffer, smsdev->func->cur_blksize);
@@ -118,7 +130,7 @@ static void smssdio_interrupt(struct sdio_func *func)
struct smssdio_device *smsdev;
struct smscore_buffer_t *cb;
- struct SmsMsgHdr_ST *hdr;
+ struct sms_msg_hdr *hdr;
size_t size;
smsdev = sdio_get_drvdata(func);
@@ -151,20 +163,20 @@ static void smssdio_interrupt(struct sdio_func *func)
hdr = cb->p;
- if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
+ if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
smsdev->split_cb = cb;
return;
}
- if (hdr->msgLength > smsdev->func->cur_blksize)
- size = hdr->msgLength - smsdev->func->cur_blksize;
+ if (hdr->msg_length > smsdev->func->cur_blksize)
+ size = hdr->msg_length - smsdev->func->cur_blksize;
else
size = 0;
} else {
cb = smsdev->split_cb;
hdr = cb->p;
- size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
+ size = hdr->msg_length - sizeof(struct sms_msg_hdr);
smsdev->split_cb = NULL;
}
@@ -172,7 +184,7 @@ static void smssdio_interrupt(struct sdio_func *func)
if (size) {
void *buffer;
- buffer = cb->p + (hdr->msgLength - size);
+ buffer = cb->p + (hdr->msg_length - size);
size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
@@ -218,9 +230,10 @@ static void smssdio_interrupt(struct sdio_func *func)
}
}
- cb->size = hdr->msgLength;
+ cb->size = hdr->msg_length;
cb->offset = 0;
+ smsendian_handle_rx_message((struct sms_msg_data *) cb->p);
smscore_onresponse(smsdev->coredev, cb);
}
diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c
index 77f9c92186f4..66c957a02ba7 100644
--- a/drivers/media/parport/pms.c
+++ b/drivers/media/parport/pms.c
@@ -735,12 +735,12 @@ static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
-static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
+static int pms_s_std(struct file *file, void *fh, v4l2_std_id std)
{
struct pms *dev = video_drvdata(file);
int ret = 0;
- dev->std = *std;
+ dev->std = std;
if (dev->std & V4L2_STD_NTSC) {
pms_framerate(dev, 30);
pms_secamcross(dev, 0);
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index c4c59175e52c..b7dc921e1b91 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -3547,6 +3547,16 @@ void bttv_init_card2(struct bttv *btv)
if (btv->sd_msp34xx)
return;
+ /* Now see if we can find one of the tvaudio devices. */
+ btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
+ if (btv->sd_tvaudio) {
+ /* There may be two tvaudio chips on the card, so try to
+ find another. */
+ v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
+ }
+
/* it might also be a tda7432. */
if (!bttv_tvcards[btv->c.type].no_tda7432) {
static const unsigned short addrs[] = {
@@ -3554,14 +3564,11 @@ void bttv_init_card2(struct bttv *btv)
I2C_CLIENT_END
};
- if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", 0, addrs))
+ btv->sd_tda7432 = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
+ &btv->c.i2c_adap, "tda7432", 0, addrs);
+ if (btv->sd_tda7432)
return;
}
-
- /* Now see if we can find one of the tvaudio devices. */
- btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
@@ -3940,7 +3947,7 @@ static void avermedia_eeprom(struct bttv *btv)
u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits)
{
- if (btv->audio == TVAUDIO_INPUT_TUNER) {
+ if (btv->audio_input == TVAUDIO_INPUT_TUNER) {
if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN)
gpiobits |= 0x10000;
else
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index ccd18e4ee789..e7d088413411 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -49,6 +49,8 @@
#include "bttvp.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-chip-ident.h>
#include <media/tvaudio.h>
#include <media/msp3400.h>
@@ -93,7 +95,7 @@ static unsigned int combfilter;
static unsigned int lumafilter;
static unsigned int automute = 1;
static unsigned int chroma_agc;
-static unsigned int adc_crush = 1;
+static unsigned int agc_crush = 1;
static unsigned int whitecrush_upper = 0xCF;
static unsigned int whitecrush_lower = 0x7F;
static unsigned int vcr_hack;
@@ -125,7 +127,7 @@ module_param(combfilter, int, 0444);
module_param(lumafilter, int, 0444);
module_param(automute, int, 0444);
module_param(chroma_agc, int, 0444);
-module_param(adc_crush, int, 0444);
+module_param(agc_crush, int, 0444);
module_param(whitecrush_upper, int, 0444);
module_param(whitecrush_lower, int, 0444);
module_param(vcr_hack, int, 0444);
@@ -138,27 +140,27 @@ module_param_array(video_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
-MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
-MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
-MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
-MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
-MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
-MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
+MODULE_PARM_DESC(radio, "The TV card supports radio, default is 0 (no)");
+MODULE_PARM_DESC(bigendian, "byte order of the framebuffer, default is native endian");
+MODULE_PARM_DESC(bttv_verbose, "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(bttv_gpio, "log gpio changes, default is 0 (no)");
+MODULE_PARM_DESC(bttv_debug, "debug messages, default is 0 (no)");
+MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)");
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
-MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
-MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
-MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
+MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8");
+MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default "
"is 1 (yes) for compatibility with older applications");
-MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
-MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
-MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
-MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
-MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
-MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
-MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
-MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
-MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
-MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
+MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)");
+MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)");
+MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)");
+MODULE_PARM_DESC(whitecrush_upper, "sets the white crush upper value, default is 207");
+MODULE_PARM_DESC(whitecrush_lower, "sets the white crush lower value, default is 127");
+MODULE_PARM_DESC(vcr_hack, "enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
+MODULE_PARM_DESC(irq_iswitch, "switch inputs in irq handler");
+MODULE_PARM_DESC(uv_ratio, "ratio between u and v gains, default is 50");
+MODULE_PARM_DESC(full_luma_range, "use the full luma range, default is 0 (no)");
+MODULE_PARM_DESC(coring, "set the luma coring level, default is 0 (no)");
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
@@ -168,6 +170,17 @@ MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
MODULE_LICENSE("GPL");
MODULE_VERSION(BTTV_VERSION);
+#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_USER_BTTV_BASE + 0)
+#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_BTTV_BASE + 1)
+#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_USER_BTTV_BASE + 2)
+#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_USER_BTTV_BASE + 3)
+#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_USER_BTTV_BASE + 4)
+#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_USER_BTTV_BASE + 5)
+#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_USER_BTTV_BASE + 6)
+#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_USER_BTTV_BASE + 7)
+#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_USER_BTTV_BASE + 8)
+#define V4L2_CID_PRIVATE_CORING (V4L2_CID_USER_BTTV_BASE + 9)
+
/* ----------------------------------------------------------------------- */
/* sysfs */
@@ -250,17 +263,19 @@ static u8 SRAM_Table[][60] =
vdelay start of active video in 2 * field lines relative to
trailing edge of /VRESET pulse (VDELAY register).
sheight height of active video in 2 * field lines.
+ extraheight Added to sheight for cropcap.bounds.height only
videostart0 ITU-R frame line number of the line corresponding
to vdelay in the first field. */
#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
- vdelay, sheight, videostart0) \
+ vdelay, sheight, extraheight, videostart0) \
.cropcap.bounds.left = minhdelayx1, \
/* * 2 because vertically we count field lines times two, */ \
/* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
.cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
/* 4 is a safety margin at the end of the line. */ \
.cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
- .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
+ .cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) - \
+ MIN_VDELAY, \
.cropcap.defrect.left = hdelayx1, \
.cropcap.defrect.top = (videostart0) * 2, \
.cropcap.defrect.width = swidth, \
@@ -301,9 +316,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* totalwidth */ 1135,
/* sqwidth */ 944,
/* vdelay */ 0x20,
- /* bt878 (and bt848?) can capture another
- line below active video. */
- /* sheight */ (576 + 2) + 0x20 - 2,
+ /* sheight */ 576,
+ /* bt878 (and bt848?) can capture another
+ line below active video. */
+ /* extraheight */ 2,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
@@ -330,6 +346,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 780,
/* vdelay */ 0x1a,
/* sheight */ 480,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_SECAM,
@@ -355,6 +372,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 944,
/* vdelay */ 0x20,
/* sheight */ 576,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_Nc,
@@ -380,6 +398,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 780,
/* vdelay */ 0x1a,
/* sheight */ 576,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_M,
@@ -405,6 +424,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 780,
/* vdelay */ 0x1a,
/* sheight */ 480,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_N,
@@ -430,6 +450,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 944,
/* vdelay */ 0x20,
/* sheight */ 576,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
@@ -455,6 +476,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 780,
/* vdelay */ 0x16,
/* sheight */ 480,
+ /* extraheight */ 0,
/* videostart0 */ 23)
},{
/* that one hopefully works with the strange timing
@@ -484,6 +506,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
/* sqwidth */ 944,
/* vdelay */ 0x1a,
/* sheight */ 480,
+ /* extraheight */ 0,
/* videostart0 */ 23)
}
};
@@ -622,198 +645,6 @@ static const struct bttv_format formats[] = {
static const unsigned int FORMATS = ARRAY_SIZE(formats);
/* ----------------------------------------------------------------------- */
-
-#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
-#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
-#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
-#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
-#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
-#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
-
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-static const struct v4l2_queryctrl bttv_ctls[] = {
- /* --- video --- */
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 65535,
- .step = 256,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 65535,
- .step = 128,
- .default_value = 27648,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 65535,
- .step = 128,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_COLOR_KILLER,
- .name = "Color killer",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- }, {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 65535,
- .step = 256,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- /* --- audio --- */
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 65535,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BASS,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_TREBLE,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- /* --- private --- */
- {
- .id = V4L2_CID_PRIVATE_CHROMA_AGC,
- .name = "chroma agc",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_COMBFILTER,
- .name = "combfilter",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_AUTOMUTE,
- .name = "automute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_LUMAFILTER,
- .name = "luma decimation filter",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_AGC_CRUSH,
- .name = "agc crush",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_VCR_HACK,
- .name = "vcr hack",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
- .name = "whitecrush upper",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0xCF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
- .name = "whitecrush lower",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0x7F,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_UV_RATIO,
- .name = "uv ratio",
- .minimum = 0,
- .maximum = 100,
- .step = 1,
- .default_value = 50,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
- .name = "full luma range",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_CORING,
- .name = "coring",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-
-
-
-};
-
-static const struct v4l2_queryctrl *ctrl_by_id(int id)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
- if (bttv_ctls[i].id == id)
- return bttv_ctls+i;
-
- return NULL;
-}
-
-/* ----------------------------------------------------------------------- */
/* resource management */
/*
@@ -1168,23 +999,20 @@ static char *audio_modes[] = {
"audio: intern", "audio: mute"
};
-static int
-audio_mux(struct bttv *btv, int input, int mute)
+static void
+audio_mux_gpio(struct bttv *btv, int input, int mute)
{
- int gpio_val, signal;
- struct v4l2_control ctrl;
+ int gpio_val, signal, mute_gpio;
gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
bttv_tvcards[btv->c.type].gpiomask);
signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
- btv->mute = mute;
- btv->audio = input;
-
/* automute */
- mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
+ mute_gpio = mute || (btv->opt_automute && (!signal || !btv->users)
+ && !btv->has_radio_tuner);
- if (mute)
+ if (mute_gpio)
gpio_val = bttv_tvcards[btv->c.type].gpiomute;
else
gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
@@ -1200,13 +1028,39 @@ audio_mux(struct bttv *btv, int input, int mute)
}
if (bttv_gpio)
- bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
- if (in_interrupt())
- return 0;
+ bttv_gpio_tracking(btv, audio_modes[mute_gpio ? 4 : input]);
+}
+
+static int
+audio_mute(struct bttv *btv, int mute)
+{
+ struct v4l2_ctrl *ctrl;
+
+ audio_mux_gpio(btv, btv->audio_input, mute);
+
+ if (btv->sd_msp34xx) {
+ ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, mute);
+ }
+ if (btv->sd_tvaudio) {
+ ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, mute);
+ }
+ if (btv->sd_tda7432) {
+ ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, mute);
+ }
+ return 0;
+}
+
+static int
+audio_input(struct bttv *btv, int input)
+{
+ audio_mux_gpio(btv, input, btv->mute);
- ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = btv->mute;
- bttv_call_all(btv, core, s_ctrl, &ctrl);
if (btv->sd_msp34xx) {
u32 in;
@@ -1255,23 +1109,11 @@ audio_mux(struct bttv *btv, int input, int mute)
}
if (btv->sd_tvaudio) {
v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
- input, 0, 0);
+ input, 0, 0);
}
return 0;
}
-static inline int
-audio_mute(struct bttv *btv, int mute)
-{
- return audio_mux(btv, btv->audio, mute);
-}
-
-static inline int
-audio_input(struct bttv *btv, int input)
-{
- return audio_mux(btv, input, btv->mute);
-}
-
static void
bttv_crop_calc_limits(struct bttv_crop *c)
{
@@ -1365,8 +1207,9 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm)
} else {
video_mux(btv,input);
}
- audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?
- TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);
+ btv->audio_input = (btv->tuner_type != TUNER_ABSENT && input == 0) ?
+ TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN;
+ audio_input(btv, btv->audio_input);
set_tvnorm(btv, norm);
}
@@ -1394,8 +1237,6 @@ static void init_irqreg(struct bttv *btv)
static void init_bt848(struct bttv *btv)
{
- int val;
-
if (bttv_tvcards[btv->c.type].no_video) {
/* very basic init only */
init_irqreg(btv);
@@ -1415,30 +1256,10 @@ static void init_bt848(struct bttv *btv)
BT848_GPIO_DMA_CTL_GPINTI,
BT848_GPIO_DMA_CTL);
- val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
- btwrite(val, BT848_E_SCLOOP);
- btwrite(val, BT848_O_SCLOOP);
-
btwrite(0x20, BT848_E_VSCALE_HI);
btwrite(0x20, BT848_O_VSCALE_HI);
- btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
- BT848_ADC);
-
- btwrite(whitecrush_upper, BT848_WC_UP);
- btwrite(whitecrush_lower, BT848_WC_DOWN);
-
- if (btv->opt_lumafilter) {
- btwrite(0, BT848_E_CONTROL);
- btwrite(0, BT848_O_CONTROL);
- } else {
- btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
- btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
- }
- bt848_bright(btv, btv->bright);
- bt848_hue(btv, btv->hue);
- bt848_contrast(btv, btv->contrast);
- bt848_sat(btv, btv->saturation);
+ v4l2_ctrl_handler_setup(&btv->ctrl_handler);
/* interrupt */
init_irqreg(btv);
@@ -1460,103 +1281,26 @@ static void bttv_reinit_bt848(struct bttv *btv)
set_input(btv, btv->input, btv->tvnorm);
}
-static int bttv_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *c)
-{
- struct bttv_fh *fh = priv;
- struct bttv *btv = fh->btv;
-
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = btv->bright;
- break;
- case V4L2_CID_HUE:
- c->value = btv->hue;
- break;
- case V4L2_CID_CONTRAST:
- c->value = btv->contrast;
- break;
- case V4L2_CID_SATURATION:
- c->value = btv->saturation;
- break;
- case V4L2_CID_COLOR_KILLER:
- c->value = btv->opt_color_killer;
- break;
-
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- bttv_call_all(btv, core, g_ctrl, c);
- break;
-
- case V4L2_CID_PRIVATE_CHROMA_AGC:
- c->value = btv->opt_chroma_agc;
- break;
- case V4L2_CID_PRIVATE_COMBFILTER:
- c->value = btv->opt_combfilter;
- break;
- case V4L2_CID_PRIVATE_LUMAFILTER:
- c->value = btv->opt_lumafilter;
- break;
- case V4L2_CID_PRIVATE_AUTOMUTE:
- c->value = btv->opt_automute;
- break;
- case V4L2_CID_PRIVATE_AGC_CRUSH:
- c->value = btv->opt_adc_crush;
- break;
- case V4L2_CID_PRIVATE_VCR_HACK:
- c->value = btv->opt_vcr_hack;
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
- c->value = btv->opt_whitecrush_upper;
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
- c->value = btv->opt_whitecrush_lower;
- break;
- case V4L2_CID_PRIVATE_UV_RATIO:
- c->value = btv->opt_uv_ratio;
- break;
- case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
- c->value = btv->opt_full_luma_range;
- break;
- case V4L2_CID_PRIVATE_CORING:
- c->value = btv->opt_coring;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int bttv_s_ctrl(struct file *file, void *f,
- struct v4l2_control *c)
+static int bttv_s_ctrl(struct v4l2_ctrl *c)
{
- int err;
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
-
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
+ struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler);
+ int val;
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- bt848_bright(btv, c->value);
+ bt848_bright(btv, c->val);
break;
case V4L2_CID_HUE:
- bt848_hue(btv, c->value);
+ bt848_hue(btv, c->val);
break;
case V4L2_CID_CONTRAST:
- bt848_contrast(btv, c->value);
+ bt848_contrast(btv, c->val);
break;
case V4L2_CID_SATURATION:
- bt848_sat(btv, c->value);
+ bt848_sat(btv, c->val);
break;
case V4L2_CID_COLOR_KILLER:
- btv->opt_color_killer = c->value;
- if (btv->opt_color_killer) {
+ if (c->val) {
btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP);
btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP);
} else {
@@ -1565,36 +1309,23 @@ static int bttv_s_ctrl(struct file *file, void *f,
}
break;
case V4L2_CID_AUDIO_MUTE:
- audio_mute(btv, c->value);
- /* fall through */
- case V4L2_CID_AUDIO_VOLUME:
- if (btv->volume_gpio)
- btv->volume_gpio(btv, c->value);
-
- bttv_call_all(btv, core, s_ctrl, c);
+ audio_mute(btv, c->val);
+ btv->mute = c->val;
break;
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- bttv_call_all(btv, core, s_ctrl, c);
+ case V4L2_CID_AUDIO_VOLUME:
+ btv->volume_gpio(btv, c->val);
break;
- case V4L2_CID_PRIVATE_CHROMA_AGC:
- btv->opt_chroma_agc = c->value;
- if (btv->opt_chroma_agc) {
- btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP);
- btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP);
- } else {
- btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP);
- btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP);
- }
+ case V4L2_CID_CHROMA_AGC:
+ val = c->val ? BT848_SCLOOP_CAGC : 0;
+ btwrite(val, BT848_E_SCLOOP);
+ btwrite(val, BT848_O_SCLOOP);
break;
case V4L2_CID_PRIVATE_COMBFILTER:
- btv->opt_combfilter = c->value;
+ btv->opt_combfilter = c->val;
break;
case V4L2_CID_PRIVATE_LUMAFILTER:
- btv->opt_lumafilter = c->value;
- if (btv->opt_lumafilter) {
+ if (c->val) {
btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
} else {
@@ -1603,36 +1334,31 @@ static int bttv_s_ctrl(struct file *file, void *f,
}
break;
case V4L2_CID_PRIVATE_AUTOMUTE:
- btv->opt_automute = c->value;
+ btv->opt_automute = c->val;
break;
case V4L2_CID_PRIVATE_AGC_CRUSH:
- btv->opt_adc_crush = c->value;
btwrite(BT848_ADC_RESERVED |
- (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
+ (c->val ? BT848_ADC_CRUSH : 0),
BT848_ADC);
break;
case V4L2_CID_PRIVATE_VCR_HACK:
- btv->opt_vcr_hack = c->value;
+ btv->opt_vcr_hack = c->val;
break;
case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
- btv->opt_whitecrush_upper = c->value;
- btwrite(c->value, BT848_WC_UP);
+ btwrite(c->val, BT848_WC_UP);
break;
case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
- btv->opt_whitecrush_lower = c->value;
- btwrite(c->value, BT848_WC_DOWN);
+ btwrite(c->val, BT848_WC_DOWN);
break;
case V4L2_CID_PRIVATE_UV_RATIO:
- btv->opt_uv_ratio = c->value;
+ btv->opt_uv_ratio = c->val;
bt848_sat(btv, btv->saturation);
break;
case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
- btv->opt_full_luma_range = c->value;
- btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
+ btaor((c->val << 7), ~BT848_OFORM_RANGE, BT848_OFORM);
break;
case V4L2_CID_PRIVATE_CORING:
- btv->opt_coring = c->value;
- btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
+ btaor((c->val << 5), ~BT848_OFORM_CORE32, BT848_OFORM);
break;
default:
return -EINVAL;
@@ -1642,6 +1368,121 @@ static int bttv_s_ctrl(struct file *file, void *f,
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops bttv_ctrl_ops = {
+ .s_ctrl = bttv_s_ctrl,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_combfilter = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_COMBFILTER,
+ .name = "Comb Filter",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_automute = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_AUTOMUTE,
+ .name = "Auto Mute",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_lumafilter = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_LUMAFILTER,
+ .name = "Luma Decimation Filter",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_agc_crush = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_AGC_CRUSH,
+ .name = "AGC Crush",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_vcr_hack = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_VCR_HACK,
+ .name = "VCR Hack",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_whitecrush_lower = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
+ .name = "Whitecrush Lower",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ .def = 0x7f,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_whitecrush_upper = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
+ .name = "Whitecrush Upper",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ .def = 0xcf,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_uv_ratio = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_UV_RATIO,
+ .name = "UV Ratio",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = 50,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_full_luma = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
+ .name = "Full Luma Range",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+};
+
+static struct v4l2_ctrl_config bttv_ctrl_coring = {
+ .ops = &bttv_ctrl_ops,
+ .id = V4L2_CID_PRIVATE_CORING,
+ .name = "Coring",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 3,
+ .step = 1,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
void bttv_gpio_tracking(struct bttv *btv, char *comment)
{
unsigned int outbits, data;
@@ -1871,25 +1712,33 @@ static struct videobuf_queue_ops bttv_video_qops = {
.buf_release = buffer_release,
};
-static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static void radio_enable(struct bttv *btv)
+{
+ /* Switch to the radio tuner */
+ if (!btv->has_radio_tuner) {
+ btv->has_radio_tuner = 1;
+ bttv_call_all(btv, tuner, s_radio);
+ btv->audio_input = TVAUDIO_INPUT_RADIO;
+ audio_input(btv, btv->audio_input);
+ }
+}
+
+static int bttv_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
unsigned int i;
- int err;
-
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (err)
- goto err;
+ int err = 0;
for (i = 0; i < BTTV_TVNORMS; i++)
- if (*id & bttv_tvnorms[i].v4l2_id)
+ if (id & bttv_tvnorms[i].v4l2_id)
break;
if (i == BTTV_TVNORMS) {
err = -EINVAL;
goto err;
}
+ btv->std = id;
set_tvnorm(btv, i);
err:
@@ -1897,6 +1746,15 @@ err:
return err;
}
+static int bttv_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+
+ *id = btv->std;
+ return 0;
+}
+
static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
{
struct bttv_fh *fh = f;
@@ -1922,7 +1780,7 @@ static int bttv_enum_input(struct file *file, void *priv,
}
i->type = V4L2_INPUT_TYPE_CAMERA;
- i->audioset = 1;
+ i->audioset = 0;
if (btv->tuner_type != TUNER_ABSENT && i->index == 0) {
sprintf(i->name, "Television");
@@ -1964,49 +1822,29 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int err;
-
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (unlikely(err))
- goto err;
-
- if (i > bttv_tvcards[btv->c.type].video_inputs) {
- err = -EINVAL;
- goto err;
- }
+ if (i >= bttv_tvcards[btv->c.type].video_inputs)
+ return -EINVAL;
set_input(btv, i, btv->tvnorm);
-
-err:
return 0;
}
static int bttv_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int err;
- if (unlikely(0 != t->index))
+ if (t->index)
return -EINVAL;
- if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
- err = -EINVAL;
- goto err;
- }
-
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (unlikely(err))
- goto err;
-
bttv_call_all(btv, tuner, s_tuner, t);
- if (btv->audio_mode_gpio)
- btv->audio_mode_gpio(btv, t, 1);
-
-err:
+ if (btv->audio_mode_gpio) {
+ struct v4l2_tuner copy = *t;
+ btv->audio_mode_gpio(btv, &copy, 1);
+ }
return 0;
}
@@ -2016,49 +1854,81 @@ static int bttv_g_frequency(struct file *file, void *priv,
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = btv->freq;
+ if (f->tuner)
+ return -EINVAL;
+
+ if (f->type == V4L2_TUNER_RADIO)
+ radio_enable(btv);
+ f->frequency = f->type == V4L2_TUNER_RADIO ?
+ btv->radio_freq : btv->tv_freq;
return 0;
}
+static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f)
+{
+ struct v4l2_frequency new_freq = *f;
+
+ bttv_call_all(btv, tuner, s_frequency, f);
+ /* s_frequency may clamp the frequency, so get the actual
+ frequency before assigning radio/tv_freq. */
+ bttv_call_all(btv, tuner, g_frequency, &new_freq);
+ if (new_freq.type == V4L2_TUNER_RADIO) {
+ radio_enable(btv);
+ btv->radio_freq = new_freq.frequency;
+ if (btv->has_matchbox)
+ tea5757_set_freq(btv, btv->radio_freq);
+ } else {
+ btv->tv_freq = new_freq.frequency;
+ }
+}
+
static int bttv_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int err;
- if (unlikely(f->tuner != 0))
+ if (f->tuner)
return -EINVAL;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (unlikely(err))
- goto err;
-
- if (unlikely(f->type != (btv->radio_user
- ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
- err = -EINVAL;
- goto err;
- }
- btv->freq = f->frequency;
- bttv_call_all(btv, tuner, s_frequency, f);
- if (btv->has_matchbox && btv->radio_user)
- tea5757_set_freq(btv, btv->freq);
-err:
-
+ bttv_set_frequency(btv, f);
return 0;
}
static int bttv_log_status(struct file *file, void *f)
{
+ struct video_device *vdev = video_devdata(file);
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ v4l2_ctrl_handler_log_status(vdev->ctrl_handler, btv->c.v4l2_dev.name);
bttv_call_all(btv, core, log_status);
return 0;
}
+static int bttv_g_chip_ident(struct file *file, void *f, struct v4l2_dbg_chip_ident *chip)
+{
+ struct bttv_fh *fh = f;
+ struct bttv *btv = fh->btv;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match)) {
+ chip->ident = btv->id;
+ if (chip->ident == PCI_DEVICE_ID_FUSION879)
+ chip->ident = V4L2_IDENT_BT879;
+ }
+ return 0;
+ }
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+ /* TODO: is this correct? */
+ return bttv_call_all_err(btv, core, g_chip_ident, chip);
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int bttv_g_register(struct file *file, void *f,
struct v4l2_dbg_register *reg)
@@ -2069,8 +1939,12 @@ static int bttv_g_register(struct file *file, void *f,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ if (!v4l2_chip_match_host(&reg->match)) {
+ /* TODO: subdev errors should not be ignored, this should become a
+ subdev helper function. */
+ bttv_call_all(btv, core, g_register, reg);
+ return 0;
+ }
/* bt848 has a 12-bit register space */
reg->reg &= 0xfff;
@@ -2081,7 +1955,7 @@ static int bttv_g_register(struct file *file, void *f,
}
static int bttv_s_register(struct file *file, void *f,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
@@ -2089,12 +1963,15 @@ static int bttv_s_register(struct file *file, void *f,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ if (!v4l2_chip_match_host(&reg->match)) {
+ /* TODO: subdev errors should not be ignored, this should become a
+ subdev helper function. */
+ bttv_call_all(btv, core, s_register, reg);
+ return 0;
+ }
/* bt848 has a 12-bit register space */
- reg->reg &= 0xfff;
- btwrite(reg->val, reg->reg);
+ btwrite(reg->val, reg->reg & 0xfff);
return 0;
}
@@ -2263,22 +2140,33 @@ limit_scaled_size_lock (struct bttv_fh * fh,
may also adjust the current cropping parameters to get closer
to the desired window size. */
static int
-verify_window_lock (struct bttv_fh * fh,
- struct v4l2_window * win,
- int adjust_size,
- int adjust_crop)
+verify_window_lock(struct bttv_fh *fh, struct v4l2_window *win,
+ int adjust_size, int adjust_crop)
{
enum v4l2_field field;
unsigned int width_mask;
int rc;
- if (win->w.width < 48 || win->w.height < 32)
- return -EINVAL;
+ if (win->w.width < 48)
+ win->w.width = 48;
+ if (win->w.height < 32)
+ win->w.height = 32;
if (win->clipcount > 2048)
- return -EINVAL;
+ win->clipcount = 2048;
+ win->chromakey = 0;
+ win->global_alpha = 0;
field = win->field;
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ field = V4L2_FIELD_ANY;
+ break;
+ }
if (V4L2_FIELD_ANY == field) {
__s32 height2;
@@ -2287,18 +2175,11 @@ verify_window_lock (struct bttv_fh * fh,
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
+ win->field = field;
- /* 4-byte alignment. */
if (NULL == fh->ovfmt)
return -EINVAL;
+ /* 4-byte alignment. */
width_mask = ~0;
switch (fh->ovfmt->depth) {
case 8:
@@ -2323,8 +2204,6 @@ verify_window_lock (struct bttv_fh * fh,
adjust_size, adjust_crop);
if (0 != rc)
return rc;
-
- win->field = field;
return 0;
}
@@ -2481,6 +2360,7 @@ static int bttv_g_fmt_vid_cap(struct file *file, void *priv,
fh->width, fh->height);
f->fmt.pix.field = fh->cap.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -2504,6 +2384,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
struct bttv *btv = fh->btv;
enum v4l2_field field;
__s32 width, height;
+ __s32 height2;
int rc;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2512,30 +2393,25 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
field = f->fmt.pix.field;
- if (V4L2_FIELD_ANY == field) {
- __s32 height2;
-
- height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
- field = (f->fmt.pix.height > height2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
-
- if (V4L2_FIELD_SEQ_BT == field)
- field = V4L2_FIELD_SEQ_TB;
-
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
case V4L2_FIELD_INTERLACED:
break;
+ case V4L2_FIELD_SEQ_BT:
case V4L2_FIELD_SEQ_TB:
- if (fmt->flags & FORMAT_FLAGS_PLANAR)
- return -EINVAL;
+ if (!(fmt->flags & FORMAT_FLAGS_PLANAR)) {
+ field = V4L2_FIELD_SEQ_TB;
+ break;
+ }
+ /* fall through */
+ default: /* FIELD_ANY case */
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (f->fmt.pix.height > height2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
break;
- default:
- return -EINVAL;
}
width = f->fmt.pix.width;
@@ -2552,6 +2428,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
/* update data for the application */
f->fmt.pix.field = field;
pix_format_set_size(&f->fmt.pix, fmt, width, height);
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -2561,9 +2438,10 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
- return verify_window_lock(fh, &f->fmt.win,
+ verify_window_lock(fh, &f->fmt.win,
/* adjust_size */ 1,
/* adjust_crop */ 0);
+ return 0;
}
static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
@@ -2630,6 +2508,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
static int bttv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct video_device *vdev = video_devdata(file);
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
@@ -2642,11 +2521,15 @@ static int bttv_querycap(struct file *file, void *priv,
"PCI:%s", pci_name(btv->c.pci));
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+ if (btv->vbi_dev)
+ cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+ if (btv->radio_dev)
+ cap->capabilities |= V4L2_CAP_RADIO;
/*
* No need to lock here: those vars are initialized during board
@@ -2656,6 +2539,25 @@ static int bttv_querycap(struct file *file, void *priv,
cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (btv->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps = cap->capabilities &
+ (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_TUNER);
+ else if (vdev->vfl_type == VFL_TYPE_VBI)
+ cap->device_caps = cap->capabilities &
+ (V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_TUNER);
+ else {
+ cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ if (btv->has_saa6588)
+ cap->device_caps |= V4L2_CAP_READWRITE |
+ V4L2_CAP_RDS_CAPTURE;
+ }
return 0;
}
@@ -2718,6 +2620,7 @@ static int bttv_g_fbuf(struct file *file, void *f,
*fb = btv->fbuf;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ fb->flags = V4L2_FBUF_FLAG_PRIMARY;
if (fh->ovfmt)
fb->fmt.pixelformat = fh->ovfmt->fourcc;
return 0;
@@ -2891,36 +2794,15 @@ static int bttv_streamoff(struct file *file, void *priv,
return 0;
}
-static int bttv_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct bttv_fh *fh = priv;
- struct bttv *btv = fh->btv;
- const struct v4l2_queryctrl *ctrl;
-
- if ((c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1) &&
- (c->id < V4L2_CID_PRIVATE_BASE ||
- c->id >= V4L2_CID_PRIVATE_LASTP1))
- return -EINVAL;
-
- if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
- *c = no_ctl;
- else {
- ctrl = ctrl_by_id(c->id);
-
- *c = (NULL != ctrl) ? *ctrl : no_ctl;
- }
-
- return 0;
-}
-
static int bttv_g_parm(struct file *file, void *f,
struct v4l2_streamparm *parm)
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ parm->parm.capture.readbuffers = gbuffers;
v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
&parm->parm.capture.timeperframe);
@@ -2933,15 +2815,13 @@ static int bttv_g_tuner(struct file *file, void *priv,
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- if (btv->tuner_type == TUNER_ABSENT)
- return -EINVAL;
if (0 != t->index)
return -EINVAL;
t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ t->capability = V4L2_TUNER_CAP_NORM;
bttv_call_all(btv, tuner, g_tuner, t);
strcpy(t->name, "Television");
- t->capability = V4L2_TUNER_CAP_NORM;
t->type = V4L2_TUNER_ANALOG_TV;
if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
t->signal = 0xffff;
@@ -2952,28 +2832,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
return 0;
}
-static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
-
- *p = v4l2_prio_max(&btv->prio);
-
- return 0;
-}
-
-static int bttv_s_priority(struct file *file, void *f,
- enum v4l2_priority prio)
-{
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
- int rc;
-
- rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
-
- return rc;
-}
-
static int bttv_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cap)
{
@@ -3026,11 +2884,6 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop)
/* Make sure tvnorm, vbi_end and the current cropping
parameters remain consistent until we're done. Note
read() may change vbi_end in check_alloc_btres_lock(). */
- retval = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != retval) {
- return retval;
- }
-
retval = -EBUSY;
if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
@@ -3088,23 +2941,6 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop)
return 0;
}
-static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "audio");
- return 0;
-}
-
-static int bttv_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- return 0;
-}
-
static ssize_t bttv_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@@ -3144,34 +2980,43 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
- unsigned int rc = POLLERR;
+ unsigned int rc = 0;
+ unsigned long req_events = poll_requested_events(wait);
+
+ if (v4l2_event_pending(&fh->fh))
+ rc = POLLPRI;
+ else if (req_events & POLLPRI)
+ poll_wait(file, &fh->fh.wait, wait);
+
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return rc;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
- return POLLERR;
- return videobuf_poll_stream(file, &fh->vbi, wait);
+ return rc | POLLERR;
+ return rc | videobuf_poll_stream(file, &fh->vbi, wait);
}
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
- goto err;
+ return rc | POLLERR;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
- goto err;
+ return rc | POLLERR;
fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf)
- goto err;
+ return rc | POLLERR;
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
field = videobuf_next_field(&fh->cap);
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
kfree (fh->cap.read_buf);
fh->cap.read_buf = NULL;
- goto err;
+ return rc | POLLERR;
}
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
@@ -3182,10 +3027,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
- rc = POLLIN|POLLRDNORM;
- else
- rc = 0;
-err:
+ rc = rc | POLLIN|POLLRDNORM;
return rc;
}
@@ -3214,15 +3056,15 @@ static int bttv_open(struct file *file)
fh = kmalloc(sizeof(*fh), GFP_KERNEL);
if (unlikely(!fh))
return -ENOMEM;
+ btv->users++;
file->private_data = fh;
*fh = btv->init;
+ v4l2_fh_init(&fh->fh, vdev);
fh->type = type;
fh->ov.setup_ok = 0;
- v4l2_prio_open(&btv->prio, &fh->prio);
-
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -3237,8 +3079,7 @@ static int bttv_open(struct file *file)
fh, &btv->lock);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
-
- btv->users++;
+ audio_mute(btv, btv->mute);
/* The V4L2 spec requires one global set of cropping parameters
which only change on request. These are stored in btv->crop[1].
@@ -3257,6 +3098,7 @@ static int bttv_open(struct file *file)
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
+ v4l2_fh_add(&fh->fh);
return 0;
}
@@ -3292,16 +3134,17 @@ static int bttv_release(struct file *file)
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
- v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
- kfree(fh);
btv->users--;
bttv_field_count(btv);
if (!btv->users)
- audio_mute(btv, 1);
+ audio_mute(btv, btv->mute);
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
+ kfree(fh);
return 0;
}
@@ -3340,20 +3183,16 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
- .vidioc_g_audio = bttv_g_audio,
- .vidioc_s_audio = bttv_s_audio,
.vidioc_cropcap = bttv_cropcap,
.vidioc_reqbufs = bttv_reqbufs,
.vidioc_querybuf = bttv_querybuf,
.vidioc_qbuf = bttv_qbuf,
.vidioc_dqbuf = bttv_dqbuf,
.vidioc_s_std = bttv_s_std,
+ .vidioc_g_std = bttv_g_std,
.vidioc_enum_input = bttv_enum_input,
.vidioc_g_input = bttv_g_input,
.vidioc_s_input = bttv_s_input,
- .vidioc_queryctrl = bttv_queryctrl,
- .vidioc_g_ctrl = bttv_g_ctrl,
- .vidioc_s_ctrl = bttv_s_ctrl,
.vidioc_streamon = bttv_streamon,
.vidioc_streamoff = bttv_streamoff,
.vidioc_g_tuner = bttv_g_tuner,
@@ -3363,13 +3202,14 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_g_fbuf = bttv_g_fbuf,
.vidioc_s_fbuf = bttv_s_fbuf,
.vidioc_overlay = bttv_overlay,
- .vidioc_g_priority = bttv_g_priority,
- .vidioc_s_priority = bttv_s_priority,
.vidioc_g_parm = bttv_g_parm,
.vidioc_g_frequency = bttv_g_frequency,
.vidioc_s_frequency = bttv_s_frequency,
.vidioc_log_status = bttv_log_status,
.vidioc_querystd = bttv_querystd,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = bttv_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = bttv_g_register,
.vidioc_s_register = bttv_s_register,
@@ -3380,7 +3220,6 @@ static struct video_device bttv_video_template = {
.fops = &bttv_fops,
.ioctl_ops = &bttv_ioctl_ops,
.tvnorms = BTTV_NORMS,
- .current_norm = V4L2_STD_PAL,
};
/* ----------------------------------------------------------------------- */
@@ -3402,13 +3241,12 @@ static int radio_open(struct file *file)
return -ENOMEM;
file->private_data = fh;
*fh = btv->init;
-
- v4l2_prio_open(&btv->prio, &fh->prio);
+ v4l2_fh_init(&fh->fh, vdev);
btv->radio_user++;
+ audio_mute(btv, btv->mute);
- bttv_call_all(btv, tuner, s_radio);
- audio_input(btv,TVAUDIO_INPUT_RADIO);
+ v4l2_fh_add(&fh->fh);
return 0;
}
@@ -3419,28 +3257,17 @@ static int radio_release(struct file *file)
struct bttv *btv = fh->btv;
struct saa6588_command cmd;
- v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
btv->radio_user--;
bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
- return 0;
-}
-
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct bttv_fh *fh = priv;
- struct bttv *btv = fh->btv;
-
- strcpy(cap->driver, "bttv");
- strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
- sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
- cap->capabilities = V4L2_CAP_TUNER;
-
+ if (btv->radio_user == 0)
+ btv->has_radio_tuner = 0;
return 0;
}
@@ -3449,12 +3276,11 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- if (btv->tuner_type == TUNER_ABSENT)
- return -EINVAL;
if (0 != t->index)
return -EINVAL;
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
+ radio_enable(btv);
bttv_call_all(btv, tuner, g_tuner, t);
@@ -3464,31 +3290,8 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return 0;
}
-static int radio_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
-
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
-
- return 0;
-}
-
-static int radio_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
-
- return 0;
-}
-
static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
@@ -3496,56 +3299,11 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
+ radio_enable(btv);
bttv_call_all(btv, tuner, s_tuner, t);
return 0;
}
-static int radio_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- return 0;
-}
-
-static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-{
- if (unlikely(i))
- return -EINVAL;
-
- return 0;
-}
-
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- const struct v4l2_queryctrl *ctrl;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- ctrl = ctrl_by_id(c->id);
- *c = *ctrl;
- } else
- *c = no_ctl;
-
- return 0;
-}
-
-static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
static ssize_t radio_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@@ -3556,6 +3314,7 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;
+ radio_enable(btv);
bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
@@ -3566,10 +3325,18 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
+ unsigned long req_events = poll_requested_events(wait);
struct saa6588_command cmd;
+ unsigned int res = 0;
+
+ if (v4l2_event_pending(&fh->fh))
+ res = POLLPRI;
+ else if (req_events & POLLPRI)
+ poll_wait(file, &fh->fh.wait, wait);
+ radio_enable(btv);
cmd.instance = file;
cmd.event_list = wait;
- cmd.result = -ENODEV;
+ cmd.result = res;
bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
return cmd.result;
@@ -3586,20 +3353,14 @@ static const struct v4l2_file_operations radio_fops =
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = bttv_querycap,
+ .vidioc_log_status = bttv_log_status,
.vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_s_std = radio_s_std,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_input = radio_g_input,
- .vidioc_g_ctrl = bttv_g_ctrl,
- .vidioc_s_ctrl = bttv_s_ctrl,
.vidioc_g_frequency = bttv_g_frequency,
.vidioc_s_frequency = bttv_s_frequency,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device radio_template = {
@@ -4102,7 +3863,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
bttv_irq_switch_video(btv);
if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
- audio_mute(btv, btv->mute); /* trigger automute */
+ /* trigger automute */
+ audio_mux_gpio(btv, btv->audio_input, btv->mute);
if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
pr_info("%d: %s%s @ %08x,",
@@ -4151,7 +3913,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
/* ----------------------------------------------------------------------- */
-/* initialitation */
+/* initialization */
static struct video_device *vdev_init(struct bttv *btv,
const struct video_device *template,
@@ -4166,10 +3928,17 @@ static struct video_device *vdev_init(struct bttv *btv,
vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
vfd->debug = bttv_debug;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
video_set_drvdata(vfd, btv);
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
type_name, bttv_tvcards[btv->c.type].name);
+ if (btv->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ }
return vfd;
}
@@ -4237,6 +4006,7 @@ static int bttv_register_video(struct bttv *btv)
btv->radio_dev = vdev_init(btv, &radio_template, "radio");
if (NULL == btv->radio_dev)
goto err;
+ btv->radio_dev->ctrl_handler = &btv->radio_ctrl_handler;
if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,
radio_nr[btv->c.nr]) < 0)
goto err;
@@ -4267,9 +4037,15 @@ static void pci_set_command(struct pci_dev *dev)
static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
{
+ struct v4l2_frequency init_freq = {
+ .tuner = 0,
+ .type = V4L2_TUNER_ANALOG_TV,
+ .frequency = 980,
+ };
int result;
unsigned char lat;
struct bttv *btv;
+ struct v4l2_ctrl_handler *hdl;
if (bttv_num == BTTV_MAX)
return -ENOMEM;
@@ -4291,7 +4067,6 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
INIT_LIST_HEAD(&btv->c.subs);
INIT_LIST_HEAD(&btv->capture);
INIT_LIST_HEAD(&btv->vcapture);
- v4l2_prio_init(&btv->prio);
init_timer(&btv->timeout);
btv->timeout.function = bttv_irq_timeout;
@@ -4329,6 +4104,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr);
goto fail0;
}
+ hdl = &btv->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 20);
+ btv->c.v4l2_dev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(&btv->radio_ctrl_handler, 6);
btv->revision = dev->revision;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
@@ -4365,16 +4144,19 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
/* init options from insmod args */
btv->opt_combfilter = combfilter;
- btv->opt_lumafilter = lumafilter;
+ bttv_ctrl_combfilter.def = combfilter;
+ bttv_ctrl_lumafilter.def = lumafilter;
btv->opt_automute = automute;
- btv->opt_chroma_agc = chroma_agc;
- btv->opt_adc_crush = adc_crush;
+ bttv_ctrl_automute.def = automute;
+ bttv_ctrl_agc_crush.def = agc_crush;
btv->opt_vcr_hack = vcr_hack;
- btv->opt_whitecrush_upper = whitecrush_upper;
- btv->opt_whitecrush_lower = whitecrush_lower;
+ bttv_ctrl_vcr_hack.def = vcr_hack;
+ bttv_ctrl_whitecrush_upper.def = whitecrush_upper;
+ bttv_ctrl_whitecrush_lower.def = whitecrush_lower;
btv->opt_uv_ratio = uv_ratio;
- btv->opt_full_luma_range = full_luma_range;
- btv->opt_coring = coring;
+ bttv_ctrl_uv_ratio.def = uv_ratio;
+ bttv_ctrl_full_luma.def = full_luma_range;
+ bttv_ctrl_coring.def = coring;
/* fill struct bttv with some useful defaults */
btv->init.btv = btv;
@@ -4383,8 +4165,39 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
btv->init.width = 320;
btv->init.height = 240;
+ btv->init.ov.w.width = 320;
+ btv->init.ov.w.height = 240;
+ btv->init.ov.field = V4L2_FIELD_INTERLACED;
btv->input = 0;
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 0xff00, 0x100, 32768);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 0xff80, 0x80, 0x6c00);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 0xff80, 0x80, 32768);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_HUE, 0, 0xff00, 0x100, 32768);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_CHROMA_AGC, 0, 1, 1, !!chroma_agc);
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ if (btv->volume_gpio)
+ v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 0xff00, 0x100, 0xff00);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_combfilter, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_automute, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_lumafilter, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_agc_crush, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_vcr_hack, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_lower, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_upper, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_uv_ratio, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_full_luma, NULL);
+ v4l2_ctrl_new_custom(hdl, &bttv_ctrl_coring, NULL);
+
/* initialize hardware */
if (bttv_gpio)
bttv_gpio_tracking(btv,"pre-init");
@@ -4407,21 +4220,34 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
/* some card-specific stuff (needs working i2c) */
bttv_init_card2(btv);
bttv_init_tuner(btv);
+ if (btv->tuner_type != TUNER_ABSENT) {
+ bttv_set_frequency(btv, &init_freq);
+ btv->radio_freq = 90500 * 16; /* 90.5Mhz default */
+ }
+ btv->std = V4L2_STD_PAL;
init_irqreg(btv);
+ v4l2_ctrl_handler_setup(hdl);
+ if (hdl->error) {
+ result = hdl->error;
+ goto fail2;
+ }
+ /* mute device */
+ audio_mute(btv, 1);
/* register video4linux + input */
if (!bttv_tvcards[btv->c.type].no_video) {
- bttv_register_video(btv);
- bt848_bright(btv,32768);
- bt848_contrast(btv, 27648);
- bt848_hue(btv,32768);
- bt848_sat(btv,32768);
- audio_mute(btv, 1);
+ v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl,
+ v4l2_ctrl_radio_filter);
+ if (btv->radio_ctrl_handler.error) {
+ result = btv->radio_ctrl_handler.error;
+ goto fail2;
+ }
set_input(btv, 0, btv->tvnorm);
bttv_crop_reset(&btv->crop[0], btv->tvnorm);
btv->crop[1] = btv->crop[0]; /* current = default */
disclaim_vbi_lines(btv);
disclaim_video_lines(btv);
+ bttv_register_video(btv);
}
/* add subdevices and autoload dvb-bt8xx if needed */
@@ -4443,6 +4269,8 @@ fail2:
free_irq(btv->c.pci->irq,btv);
fail1:
+ v4l2_ctrl_handler_free(&btv->ctrl_handler);
+ v4l2_ctrl_handler_free(&btv->radio_ctrl_handler);
v4l2_device_unregister(&btv->c.v4l2_dev);
fail0:
@@ -4484,9 +4312,11 @@ static void bttv_remove(struct pci_dev *pci_dev)
bttv_unregister_video(btv);
/* free allocated memory */
+ v4l2_ctrl_handler_free(&btv->ctrl_handler);
+ v4l2_ctrl_handler_free(&btv->radio_ctrl_handler);
btcx_riscmem_free(btv->c.pci,&btv->main);
- /* free ressources */
+ /* free resources */
free_irq(btv->c.pci->irq,btv);
iounmap(btv->bt848_mmio);
release_mem_region(pci_resource_start(btv->c.pci,0),
diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c
index c63c643ed1f8..b7c52dc8999c 100644
--- a/drivers/media/pci/bt8xx/bttv-i2c.c
+++ b/drivers/media/pci/bt8xx/bttv-i2c.c
@@ -394,3 +394,11 @@ int init_bttv_i2c(struct bttv *btv)
return btv->i2c_rc;
}
+
+int fini_bttv_i2c(struct bttv *btv)
+{
+ if (0 != btv->i2c_rc)
+ return 0;
+
+ return i2c_del_adapter(&btv->c.i2c_adap);
+}
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index 04207a799055..f36821367d8d 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -375,6 +375,7 @@ void init_bttv_i2c_ir(struct bttv *btv)
I2C_CLIENT_END
};
struct i2c_board_info info;
+ struct i2c_client *i2c_dev;
if (0 != btv->i2c_rc)
return;
@@ -390,7 +391,12 @@ void init_bttv_i2c_ir(struct bttv *btv)
btv->init_data.ir_codes = RC_MAP_PV951;
info.addr = 0x4b;
break;
- default:
+ }
+
+ if (btv->init_data.name) {
+ info.platform_data = &btv->init_data;
+ i2c_dev = i2c_new_device(&btv->c.i2c_adap, &info);
+ } else {
/*
* The external IR receiver is at i2c address 0x34 (0x35 for
* reads). Future Hauppauge cards will have an internal
@@ -399,24 +405,14 @@ void init_bttv_i2c_ir(struct bttv *btv)
* internal.
* That's why we probe 0x1a (~0x34) first. CB
*/
-
- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
- return;
+ i2c_dev = i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
}
+ if (NULL == i2c_dev)
+ return;
- if (btv->init_data.name)
- info.platform_data = &btv->init_data;
- i2c_new_device(&btv->c.i2c_adap, &info);
-
- return;
-}
-
-int fini_bttv_i2c(struct bttv *btv)
-{
- if (0 != btv->i2c_rc)
- return 0;
-
- return i2c_del_adapter(&btv->c.i2c_adap);
+#if defined(CONFIG_MODULES) && defined(MODULE)
+ request_module("ir-kbd-i2c");
+#endif
}
int bttv_input_init(struct bttv *btv)
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index 79a11240a590..6139ce26dc2c 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -359,6 +359,9 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits);
#define bttv_call_all(btv, o, f, args...) \
v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args)
+#define bttv_call_all_err(btv, o, f, args...) \
+ v4l2_device_call_until_err(&btv->c.v4l2_dev, 0, o, f, ##args)
+
extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both);
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 9ec0adba236c..9c1cc2c50ee2 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -33,9 +33,11 @@
#include <linux/input.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/device.h>
#include <asm/io.h>
#include <media/v4l2-common.h>
-#include <linux/device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
#include <media/videobuf-dma-sg.h>
#include <media/tveeprom.h>
#include <media/rc-core.h>
@@ -214,11 +216,11 @@ struct bttv_crop {
};
struct bttv_fh {
+ /* This must be the first field in this struct */
+ struct v4l2_fh fh;
+
struct bttv *btv;
int resources;
-#ifdef VIDIOC_G_PRIORITY
- enum v4l2_priority prio;
-#endif
enum v4l2_buf_type type;
/* video capture */
@@ -298,6 +300,10 @@ extern int no_overlay;
/* bttv-input.c */
extern void init_bttv_i2c_ir(struct bttv *btv);
+
+/* ---------------------------------------------------------- */
+/* bttv-i2c.c */
+extern int init_bttv_i2c(struct bttv *btv);
extern int fini_bttv_i2c(struct bttv *btv);
/* ---------------------------------------------------------- */
@@ -308,7 +314,6 @@ extern unsigned int bttv_verbose;
extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
-extern int init_bttv_i2c(struct bttv *btv);
#define dprintk(fmt, ...) \
do { \
@@ -393,12 +398,17 @@ struct bttv {
wait_queue_head_t i2c_queue;
struct v4l2_subdev *sd_msp34xx;
struct v4l2_subdev *sd_tvaudio;
+ struct v4l2_subdev *sd_tda7432;
/* video4linux (1) */
struct video_device *video_dev;
struct video_device *radio_dev;
struct video_device *vbi_dev;
+ /* controls */
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl_handler radio_ctrl_handler;
+
/* infrared remote */
int has_remote;
struct bttv_ir *remote;
@@ -410,38 +420,30 @@ struct bttv {
spinlock_t s_lock;
struct mutex lock;
int resources;
-#ifdef VIDIOC_G_PRIORITY
- struct v4l2_prio_state prio;
-#endif
/* video state */
unsigned int input;
- unsigned int audio;
+ unsigned int audio_input;
unsigned int mute;
- unsigned long freq;
+ unsigned long tv_freq;
unsigned int tvnorm;
+ v4l2_std_id std;
int hue, contrast, bright, saturation;
struct v4l2_framebuffer fbuf;
unsigned int field_count;
/* various options */
int opt_combfilter;
- int opt_lumafilter;
int opt_automute;
- int opt_chroma_agc;
- int opt_color_killer;
- int opt_adc_crush;
int opt_vcr_hack;
- int opt_whitecrush_upper;
- int opt_whitecrush_lower;
int opt_uv_ratio;
- int opt_full_luma_range;
- int opt_coring;
/* radio data/state */
int has_radio;
+ int has_radio_tuner;
int radio_user;
int radio_uses_msp_demodulator;
+ unsigned long radio_freq;
/* miro/pinnacle + Aimslab VHX
philips matchbox (tea5757 radio tuner) support */
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index f164b7f610a5..38b1d64ffc27 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -576,7 +576,7 @@ static void input_change(struct cx18 *cx)
}
static int cx18_av_s_frequency(struct v4l2_subdev *sd,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
input_change(cx);
@@ -809,7 +809,7 @@ static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int cx18_av_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
@@ -1266,7 +1266,7 @@ static int cx18_av_g_register(struct v4l2_subdev *sd,
}
static int cx18_av_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 613e5ae7d5ca..67b61cf3e03a 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -1243,7 +1243,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
in one place. */
cx->std++; /* Force full standard initialization */
std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
- cx18_s_std(NULL, &fh, &std);
+ cx18_s_std(NULL, &fh, std);
cx18_s_frequency(NULL, &fh, &vf);
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index cd8d2c2b1624..aee7b6dacbfe 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -415,42 +415,34 @@ static int cx18_g_chip_ident(struct file *file, void *fh,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
-{
- struct v4l2_dbg_register *regs = arg;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
- return -EINVAL;
-
- regs->size = 4;
- if (cmd == VIDIOC_DBG_S_REGISTER)
- cx18_write_enc(cx, regs->val, regs->reg);
- else
- regs->val = cx18_read_enc(cx, regs->reg);
- return 0;
-}
-
static int cx18_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
struct cx18 *cx = fh2id(fh)->cx;
- if (v4l2_chip_match_host(&reg->match))
- return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg);
+ if (v4l2_chip_match_host(&reg->match)) {
+ if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+ reg->size = 4;
+ reg->val = cx18_read_enc(cx, reg->reg);
+ return 0;
+ }
/* FIXME - errors shouldn't be ignored */
cx18_call_all(cx, core, g_register, reg);
return 0;
}
static int cx18_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct cx18 *cx = fh2id(fh)->cx;
- if (v4l2_chip_match_host(&reg->match))
- return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg);
+ if (v4l2_chip_match_host(&reg->match)) {
+ if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+ cx18_write_enc(cx, reg->val, reg->reg);
+ return 0;
+ }
/* FIXME - errors shouldn't be ignored */
cx18_call_all(cx, core, s_register, reg);
return 0;
@@ -614,7 +606,7 @@ static int cx18_g_frequency(struct file *file, void *fh,
return 0;
}
-int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
@@ -637,15 +629,15 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
-int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id std)
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
- if ((*std & V4L2_STD_ALL) == 0)
+ if ((std & V4L2_STD_ALL) == 0)
return -EINVAL;
- if (*std == cx->std)
+ if (std == cx->std)
return 0;
if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
@@ -656,8 +648,8 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
return -EBUSY;
}
- cx->std = *std;
- cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ cx->std = std;
+ cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
cx->is_50hz = !cx->is_60hz;
cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
cx->cxhdl.width = 720;
@@ -673,7 +665,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
-static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
@@ -1118,7 +1110,7 @@ static int cx18_log_status(struct file *file, void *fh)
}
static long cx18_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
struct cx18 *cx = fh2id(fh)->cx;
diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h
index 2f9dd591ee0f..43433969d633 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.h
+++ b/drivers/media/pci/cx18/cx18-ioctl.h
@@ -26,6 +26,6 @@ u16 cx18_service2vbi(int type);
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
void cx18_set_funcs(struct video_device *vdev);
-int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std);
-int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int cx18_s_std(struct file *file, void *fh, v4l2_std_id std);
+int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
int cx18_s_input(struct file *file, void *fh, unsigned int inp);
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 70e4fd69ad9e..4998c96caebe 100644
--- a/drivers/media/pci/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -24,6 +24,8 @@
#ifndef __ALTERA_CI_H
#define __ALTERA_CI_H
+#include <linux/kconfig.h>
+
#define ALT_DATA 0x000000ff
#define ALT_TDI 0x00008000
#define ALT_TDO 0x00004000
@@ -41,8 +43,7 @@ struct altera_ci_config {
int (*fpga_rw) (void *dev, int ad_rg, int val, int rw);
};
-#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \
- && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_ALTERA_CI)
extern int altera_ci_init(struct altera_ci_config *config, int ci_nr);
extern void altera_ci_release(void *dev, int ci_nr);
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 5d5052d0253f..6dea11a7a858 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1222,14 +1222,14 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
- if (*id & cx23885_tvnorms[i].id)
+ if (id & cx23885_tvnorms[i].id)
break;
if (i == ARRAY_SIZE(cx23885_tvnorms))
return -EINVAL;
@@ -1237,7 +1237,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
/* Have the drier core notify the subdevices */
mutex_lock(&dev->lock);
- cx23885_set_tvnorm(dev, *id);
+ cx23885_set_tvnorm(dev, id);
mutex_unlock(&dev->lock);
return 0;
@@ -1280,7 +1280,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
@@ -1311,7 +1311,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
return cx23885_set_frequency(file, priv, f);
}
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index ea9a614f3bbf..acdb6d58db58 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -158,18 +158,17 @@ int cx23885_g_register(struct file *file, void *fh,
}
static int cx23885_s_host_register(struct cx23885_dev *dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0))
return -EINVAL;
- reg->size = 4;
cx_write(reg->reg, reg->val);
return 0;
}
static int cx23417_s_register(struct cx23885_dev *dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
if (dev->v4l_device == NULL)
return -EINVAL;
@@ -179,13 +178,11 @@ static int cx23417_s_register(struct cx23885_dev *dev,
if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val))
return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */
-
- reg->size = 4;
return 0;
}
int cx23885_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index 315be0ca5a04..a6080964a9ee 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -33,7 +33,7 @@ int cx23885_g_register(struct file *file, void *fh,
int cx23885_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg);
+ const struct v4l2_dbg_register *reg);
#endif
#endif
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 5991bc8dc158..ed08c89adde0 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -1259,13 +1259,13 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
dprintk(1, "%s()\n", __func__);
mutex_lock(&dev->lock);
- cx23885_set_tvnorm(dev, *tvnorms);
+ cx23885_set_tvnorm(dev, tvnorms);
mutex_unlock(&dev->lock);
return 0;
@@ -1486,7 +1486,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
@@ -1518,7 +1518,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
-static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
+static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f)
{
struct v4l2_control ctrl;
@@ -1550,7 +1550,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f)
}
static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct v4l2_control ctrl;
struct videobuf_dvb_frontend *vfe;
@@ -1608,7 +1608,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
}
int cx23885_set_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
@@ -1628,7 +1628,7 @@ int cx23885_set_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
return cx23885_set_frequency(file, priv, f);
}
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 59c322d870f2..5687d3f678db 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -587,7 +587,7 @@ extern void cx23885_video_wakeup(struct cx23885_dev *dev,
int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
int cx23885_set_input(struct file *file, void *priv, unsigned int i);
int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
-int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f);
+int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f);
int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index d51eed051d59..fa672fe41079 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -1124,7 +1124,7 @@ static int cx23888_ir_g_register(struct v4l2_subdev *sd,
}
static int cx23888_ir_s_register(struct v4l2_subdev *sd,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct cx23888_ir_state *state = to_state(sd);
u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg;
diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig
index 4017c9420348..6439a847680c 100644
--- a/drivers/media/pci/cx25821/Kconfig
+++ b/drivers/media/pci/cx25821/Kconfig
@@ -1,14 +1,9 @@
config VIDEO_CX25821
tristate "Conexant cx25821 support"
- depends on DVB_CORE && VIDEO_DEV && PCI && I2C
+ depends on VIDEO_DEV && PCI && I2C
select I2C_ALGOBIT
select VIDEO_BTCX
- select VIDEO_TVEEPROM
- depends on RC_CORE
- select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
- select VIDEO_CX25840
- select VIDEO_CX2341X
---help---
This is a video4linux driver for Conexant 25821 based
TV cards.
diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile
index caa32b7b51f8..fb76c3d3713a 100644
--- a/drivers/media/pci/cx25821/Makefile
+++ b/drivers/media/pci/cx25821/Makefile
@@ -1,14 +1,9 @@
cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
cx25821-gpio.o cx25821-medusa-video.o \
- cx25821-video.o cx25821-video-upstream.o \
- cx25821-video-upstream-ch2.o \
- cx25821-audio-upstream.o
+ cx25821-video.o cx25821-video-upstream.o
obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
ccflags-y += -Idrivers/media/i2c
ccflags-y += -Idrivers/media/common
-ccflags-y += -Idrivers/media/tuners
-ccflags-y += -Idrivers/media/dvb-core
-ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index 1858a45dd081..6e91e84d6bf9 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -59,7 +59,6 @@ do { \
Data type declarations - Can be moded to a header file later
****************************************************************************/
-static struct snd_card *snd_cx25821_cards[SNDRV_CARDS];
static int devno;
struct cx25821_audio_buffer {
@@ -151,7 +150,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip)
{
struct cx25821_audio_buffer *buf = chip->buf;
struct cx25821_dev *dev = chip->dev;
- struct sram_channel *audio_ch =
+ const struct sram_channel *audio_ch =
&cx25821_sram_channels[AUDIO_SRAM_CHANNEL];
u32 tmp = 0;
@@ -627,34 +626,6 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = {
MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl);
/*
- * Not used in the function snd_cx25821_dev_free so removing
- * from the file.
- */
-/*
-static int snd_cx25821_free(struct cx25821_audio_dev *chip)
-{
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
-
- cx25821_dev_unregister(chip->dev);
- pci_disable_device(chip->pci);
-
- return 0;
-}
-*/
-
-/*
- * Component Destructor
- */
-static void snd_cx25821_dev_free(struct snd_card *card)
-{
- struct cx25821_audio_dev *chip = card->private_data;
-
- /* snd_cx25821_free(chip); */
- snd_card_free(chip->card);
-}
-
-/*
* Alsa Constructor - Component probe
*/
static int cx25821_audio_initdev(struct cx25821_dev *dev)
@@ -685,7 +656,6 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
strcpy(card->driver, "cx25821");
/* Card "creation" */
- card->private_free = snd_cx25821_dev_free;
chip = card->private_data;
spin_lock_init(&chip->reg_lock);
@@ -729,8 +699,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
goto error;
}
- snd_cx25821_cards[devno] = card;
-
+ dev->card = card;
devno++;
return 0;
@@ -742,9 +711,33 @@ error:
/****************************************************************************
LINUX MODULE INIT
****************************************************************************/
+
+static int cx25821_alsa_exit_callback(struct device *dev, void *data)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+ struct cx25821_dev *cxdev = get_cx25821(v4l2_dev);
+
+ snd_card_free(cxdev->card);
+ return 0;
+}
+
static void cx25821_audio_fini(void)
{
- snd_card_free(snd_cx25821_cards[0]);
+ struct device_driver *drv = driver_find("cx25821", &pci_bus_type);
+ int ret;
+
+ ret = driver_for_each_device(drv, NULL, NULL, cx25821_alsa_exit_callback);
+ if (ret)
+ pr_err("%s failed to find a cx25821 driver.\n", __func__);
+}
+
+static int cx25821_alsa_init_callback(struct device *dev, void *data)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
+ struct cx25821_dev *cxdev = get_cx25821(v4l2_dev);
+
+ cx25821_audio_initdev(cxdev);
+ return 0;
}
/*
@@ -756,29 +749,11 @@ static void cx25821_audio_fini(void)
*/
static int cx25821_alsa_init(void)
{
- struct cx25821_dev *dev = NULL;
- struct list_head *list;
+ struct device_driver *drv = driver_find("cx25821", &pci_bus_type);
- mutex_lock(&cx25821_devlist_mutex);
- list_for_each(list, &cx25821_devlist) {
- dev = list_entry(list, struct cx25821_dev, devlist);
- cx25821_audio_initdev(dev);
- }
- mutex_unlock(&cx25821_devlist_mutex);
-
- if (dev == NULL)
- pr_info("ERROR ALSA: no cx25821 cards found\n");
-
- return 0;
+ return driver_for_each_device(drv, NULL, NULL, cx25821_alsa_init_callback);
}
late_initcall(cx25821_alsa_init);
module_exit(cx25821_audio_fini);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
index d6dfb5765d0b..68dbc2dbc982 100644
--- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c
@@ -45,7 +45,7 @@ static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF |
FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR;
static int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i, lines;
@@ -106,7 +106,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev,
int fifo_enable)
{
unsigned int line;
- struct sram_channel *sram_ch =
+ const struct sram_channel *sram_ch =
dev->channels[dev->_audio_upstream_channel].sram_channels;
int offset = 0;
@@ -215,7 +215,7 @@ static void cx25821_free_memory_audio(struct cx25821_dev *dev)
void cx25821_stop_upstream_audio(struct cx25821_dev *dev)
{
- struct sram_channel *sram_ch =
+ const struct sram_channel *sram_ch =
dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels;
u32 tmp = 0;
@@ -257,7 +257,7 @@ void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev)
}
static int cx25821_get_audio_data(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+ const struct sram_channel *sram_ch)
{
struct file *file;
int frame_index_temp = dev->_audioframe_index;
@@ -319,7 +319,7 @@ static void cx25821_audioups_handler(struct work_struct *work)
}
static int cx25821_openfile_audio(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+ const struct sram_channel *sram_ch)
{
char *p = (void *)dev->_audiodata_buf_virt_addr;
struct file *file;
@@ -360,7 +360,7 @@ static int cx25821_openfile_audio(struct cx25821_dev *dev,
}
static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev,
- struct sram_channel *sram_ch,
+ const struct sram_channel *sram_ch,
int bpl)
{
int ret = 0;
@@ -422,7 +422,7 @@ static int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
{
int i = 0;
u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
dma_addr_t risc_phys_jump_addr;
__le32 *rp;
@@ -514,7 +514,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
struct cx25821_dev *dev = dev_id;
u32 audio_status;
int handled = 0;
- struct sram_channel *sram_ch;
+ const struct sram_channel *sram_ch;
if (!dev)
return -1;
@@ -538,7 +538,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
}
static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+ const struct sram_channel *sram_ch)
{
int count = 0;
u32 tmp;
@@ -562,7 +562,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev,
}
static int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+ const struct sram_channel *sram_ch)
{
u32 tmp = 0;
int err = 0;
@@ -626,7 +626,7 @@ fail_irq:
int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
{
- struct sram_channel *sram_ch;
+ const struct sram_channel *sram_ch;
int err = 0;
if (dev->_audio_is_running) {
@@ -655,26 +655,17 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select)
dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER;
_line_size = AUDIO_LINE_SIZE;
- if (dev->input_audiofilename) {
+ if ((dev->input_audiofilename) &&
+ (strcmp(dev->input_audiofilename, "") != 0))
dev->_audiofilename = kstrdup(dev->input_audiofilename,
GFP_KERNEL);
-
- if (!dev->_audiofilename) {
- err = -ENOMEM;
- goto error;
- }
-
- /* Default if filename is empty string */
- if (strcmp(dev->input_audiofilename, "") == 0)
- dev->_audiofilename = "/root/audioGOOD.wav";
- } else {
+ else
dev->_audiofilename = kstrdup(_defaultAudioName,
GFP_KERNEL);
- if (!dev->_audiofilename) {
- err = -ENOMEM;
- goto error;
- }
+ if (!dev->_audiofilename) {
+ err = -ENOMEM;
+ goto error;
}
cx25821_sram_channel_setup_upstream_audio(dev, sram_ch,
diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c
index 99988c988095..3b409feb03d8 100644
--- a/drivers/media/pci/cx25821/cx25821-cards.c
+++ b/drivers/media/pci/cx25821/cx25821-cards.c
@@ -26,11 +26,8 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/delay.h>
-#include <media/cx25840.h>
#include "cx25821.h"
-#include "tuner-xc2028.h"
/* board config info */
@@ -45,28 +42,8 @@ struct cx25821_board cx25821_boards[] = {
.name = "CX25821",
.portb = CX25821_RAW,
.portc = CX25821_264,
- .input[0].type = CX25821_VMUX_COMPOSITE,
},
};
const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards);
-
-struct cx25821_subid cx25821_subids[] = {
- {
- .subvendor = 0x14f1,
- .subdevice = 0x0920,
- .card = CX25821_BOARD,
- },
-};
-
-void cx25821_card_setup(struct cx25821_dev *dev)
-{
- static u8 eeprom[256];
-
- if (dev->i2c_bus[0].i2c_rc == 0) {
- dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
- sizeof(eeprom));
- }
-}
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index 1884e2cc35e9..b762c5b2ca10 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -41,14 +41,7 @@ static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
-static unsigned int cx25821_devcount;
-
-DEFINE_MUTEX(cx25821_devlist_mutex);
-EXPORT_SYMBOL(cx25821_devlist_mutex);
-LIST_HEAD(cx25821_devlist);
-EXPORT_SYMBOL(cx25821_devlist);
-
-struct sram_channel cx25821_sram_channels[] = {
+const struct sram_channel cx25821_sram_channels[] = {
[SRAM_CH00] = {
.i = SRAM_CH00,
.name = "VID A",
@@ -317,20 +310,6 @@ struct sram_channel cx25821_sram_channels[] = {
};
EXPORT_SYMBOL(cx25821_sram_channels);
-struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00];
-struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01];
-struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02];
-struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03];
-struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04];
-struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05];
-struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06];
-struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07];
-struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09];
-struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10];
-struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11];
-
-struct cx25821_dmaqueue mpegq;
-
static int cx25821_risc_decode(u32 risc)
{
static const char * const instr[16] = {
@@ -457,7 +436,7 @@ static void cx25821_registers_init(struct cx25821_dev *dev)
}
int cx25821_sram_channel_setup(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i, lines;
@@ -523,10 +502,9 @@ int cx25821_sram_channel_setup(struct cx25821_dev *dev,
return 0;
}
-EXPORT_SYMBOL(cx25821_sram_channel_setup);
int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i, lines;
@@ -592,7 +570,7 @@ int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
}
EXPORT_SYMBOL(cx25821_sram_channel_setup_audio);
-void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
+void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch)
{
static char *name[] = {
"init risc lo",
@@ -652,10 +630,9 @@ void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch)
pr_warn(" : cnt2_reg: 0x%08x\n",
cx_read(ch->cnt2_reg));
}
-EXPORT_SYMBOL(cx25821_sram_channel_dump);
void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
- struct sram_channel *ch)
+ const struct sram_channel *ch)
{
static const char * const name[] = {
"init risc lo",
@@ -798,12 +775,12 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select,
if (channel_select <= 7 && channel_select >= 0) {
cx_write(dev->channels[channel_select].sram_channels->pix_frmt,
format);
- dev->channels[channel_select].pixel_formats = format;
}
+ dev->channels[channel_select].pixel_formats = format;
}
static void cx25821_set_vip_mode(struct cx25821_dev *dev,
- struct sram_channel *ch)
+ const struct sram_channel *ch)
{
cx_write(ch->pix_frmt, PIXEL_FRMT_422);
cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1);
@@ -837,12 +814,13 @@ static void cx25821_initialize(struct cx25821_dev *dev)
cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels,
1440, 0);
dev->channels[i].pixel_formats = PIXEL_FRMT_422;
- dev->channels[i].use_cif_resolution = FALSE;
+ dev->channels[i].use_cif_resolution = 0;
}
/* Probably only affect Downstream */
for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) {
+ dev->channels[i].pixel_formats = PIXEL_FRMT_422;
cx25821_set_vip_mode(dev, dev->channels[i].sram_channels);
}
@@ -868,8 +846,7 @@ static void cx25821_dev_checkrevision(struct cx25821_dev *dev)
{
dev->hwrevision = cx_read(RDR_CFG2) & 0xff;
- pr_info("%s(): Hardware revision = 0x%02x\n",
- __func__, dev->hwrevision);
+ pr_info("Hardware revision = 0x%02x\n", dev->hwrevision);
}
static void cx25821_iounmap(struct cx25821_dev *dev)
@@ -879,7 +856,6 @@ static void cx25821_iounmap(struct cx25821_dev *dev)
/* Releasing IO memory */
if (dev->lmmio != NULL) {
- CX25821_INFO("Releasing lmmio.\n");
iounmap(dev->lmmio);
dev->lmmio = NULL;
}
@@ -887,23 +863,14 @@ static void cx25821_iounmap(struct cx25821_dev *dev)
static int cx25821_dev_setup(struct cx25821_dev *dev)
{
+ static unsigned int cx25821_devcount;
int i;
- pr_info("\n***********************************\n");
- pr_info("cx25821 set up\n");
- pr_info("***********************************\n\n");
-
mutex_init(&dev->lock);
- atomic_inc(&dev->refcount);
-
dev->nr = ++cx25821_devcount;
sprintf(dev->name, "cx25821[%d]", dev->nr);
- mutex_lock(&cx25821_devlist_mutex);
- list_add_tail(&dev->devlist, &cx25821_devlist);
- mutex_unlock(&cx25821_devlist_mutex);
-
if (dev->pci->device != 0x8210) {
pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
__func__, dev->pci->device);
@@ -914,8 +881,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
- for (i = 0; i < MAX_VID_CHANNEL_NUM; i++)
+ for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
+ dev->channels[i].dev = dev;
+ dev->channels[i].id = i;
dev->channels[i].sram_channels = &cx25821_sram_channels[i];
+ }
if (dev->nr > 1)
CX25821_INFO("dev->nr > 1!");
@@ -978,63 +948,15 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
/* cx25821_i2c_register(&dev->i2c_bus[1]);
* cx25821_i2c_register(&dev->i2c_bus[2]); */
- CX25821_INFO("i2c register! bus->i2c_rc = %d\n",
- dev->i2c_bus[0].i2c_rc);
-
- cx25821_card_setup(dev);
-
if (medusa_video_init(dev) < 0)
CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__);
cx25821_video_register(dev);
- /* register IOCTL device */
- dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci,
- &cx25821_videoioctl_template, "video");
-
- if (video_register_device
- (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) {
- cx25821_videoioctl_unregister(dev);
- pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n",
- __func__);
- }
-
cx25821_dev_checkrevision(dev);
- CX25821_INFO("setup done!\n");
-
return 0;
}
-void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev,
- struct upstream_user_struct *up_data)
-{
- dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0;
-
- dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
- medusa_set_videostandard(dev);
-
- cx25821_vidupstream_init_ch1(dev, dev->channel_select,
- dev->pixel_format);
-}
-
-void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev,
- struct upstream_user_struct *up_data)
-{
- dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0;
-
- dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M;
- medusa_set_videostandard(dev);
-
- cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2,
- dev->pixel_format_ch2);
-}
-
-void cx25821_start_upstream_audio(struct cx25821_dev *dev,
- struct upstream_user_struct *up_data)
-{
- cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B);
-}
-
void cx25821_dev_unregister(struct cx25821_dev *dev)
{
int i;
@@ -1042,25 +964,16 @@ void cx25821_dev_unregister(struct cx25821_dev *dev)
if (!dev->base_io_addr)
return;
- cx25821_free_mem_upstream_ch1(dev);
- cx25821_free_mem_upstream_ch2(dev);
- cx25821_free_mem_upstream_audio(dev);
-
release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
- if (!atomic_dec_and_test(&dev->refcount))
- return;
-
- for (i = 0; i < VID_CHANNEL_NUM; i++)
- cx25821_video_unregister(dev, i);
-
- for (i = VID_UPSTREAM_SRAM_CHANNEL_I;
- i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) {
+ for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) {
+ if (i == SRAM_CH08) /* audio channel */
+ continue;
+ if (i == SRAM_CH09 || i == SRAM_CH10)
+ cx25821_free_mem_upstream(&dev->channels[i]);
cx25821_video_unregister(dev, i);
}
- cx25821_videoioctl_unregister(dev);
-
cx25821_i2c_unregister(&dev->i2c_bus[0]);
cx25821_iounmap(dev);
}
@@ -1385,8 +1298,6 @@ static int cx25821_initdev(struct pci_dev *pci_dev,
goto fail_unregister_device;
}
- pr_info("Athena pci enable !\n");
-
err = cx25821_dev_setup(dev);
if (err) {
if (err == -EBUSY)
@@ -1445,10 +1356,6 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
if (pci_dev->irq)
free_irq(pci_dev->irq, dev);
- mutex_lock(&cx25821_devlist_mutex);
- list_del(&dev->devlist);
- mutex_unlock(&cx25821_devlist_mutex);
-
cx25821_dev_unregister(dev);
v4l2_device_unregister(v4l2_dev);
kfree(dev);
diff --git a/drivers/media/pci/cx25821/cx25821-gpio.c b/drivers/media/pci/cx25821/cx25821-gpio.c
index 29e43b03c85e..95e8ddf62947 100644
--- a/drivers/media/pci/cx25821/cx25821-gpio.c
+++ b/drivers/media/pci/cx25821/cx25821-gpio.c
@@ -20,6 +20,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/module.h>
#include "cx25821.h"
/********************* GPIO stuffs *********************/
diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c
index a8dc945bbe17..dca37c7dba73 100644
--- a/drivers/media/pci/cx25821/cx25821-i2c.c
+++ b/drivers/media/pci/cx25821/cx25821-i2c.c
@@ -23,8 +23,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include "cx25821.h"
+#include <linux/module.h>
#include <linux/i2c.h>
+#include "cx25821.h"
static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c
index 6a92e5c70c2a..22fa04415ccc 100644
--- a/drivers/media/pci/cx25821/cx25821-medusa-video.c
+++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c
@@ -94,8 +94,6 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
u32 value = 0;
u32 tmp = 0;
- mutex_lock(&dev->lock);
-
for (i = 0; i < MAX_DECODERS; i++) {
/* set video format NTSC-M */
value = cx25821_i2c_read(&dev->i2c_bus[0],
@@ -222,8 +220,6 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev)
value |= 0x00080200;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
- mutex_unlock(&dev->lock);
-
return ret_val;
}
@@ -265,8 +261,6 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
u32 value = 0;
u32 tmp = 0;
- mutex_lock(&dev->lock);
-
for (i = 0; i < MAX_DECODERS; i++) {
/* set video format PAL-BDGHI */
value = cx25821_i2c_read(&dev->i2c_bus[0],
@@ -397,14 +391,12 @@ static int medusa_initialize_pal(struct cx25821_dev *dev)
value &= 0xFFF7FDFF;
ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value);
- mutex_unlock(&dev->lock);
-
return ret_val;
}
int medusa_set_videostandard(struct cx25821_dev *dev)
{
- int status = STATUS_SUCCESS;
+ int status = 0;
u32 value = 0, tmp = 0;
if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
@@ -434,8 +426,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
u32 vscale = 0x0;
const int MAX_WIDTH = 720;
- mutex_lock(&dev->lock);
-
/* validate the width */
if (width > MAX_WIDTH) {
pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n",
@@ -485,8 +475,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
cx25821_i2c_write(&dev->i2c_bus[0],
VSCALE_CTRL + (0x200 * decoder), vscale);
}
-
- mutex_unlock(&dev->lock);
}
static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
@@ -496,11 +484,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
u32 tmp = 0;
u32 disp_cnt_reg = DISP_AB_CNT;
- mutex_lock(&dev->lock);
-
/* no support */
if (decoder < VDEC_A || decoder > VDEC_H) {
- mutex_unlock(&dev->lock);
return;
}
@@ -535,8 +520,6 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
}
cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
-
- mutex_unlock(&dev->lock);
}
/* Map to Medusa register setting */
@@ -587,10 +570,8 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
int value = 0;
u32 val = 0, tmp = 0;
- mutex_lock(&dev->lock);
if ((brightness > VIDEO_PROCAMP_MAX) ||
(brightness < VIDEO_PROCAMP_MIN)) {
- mutex_unlock(&dev->lock);
return -1;
}
ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness,
@@ -601,7 +582,6 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder)
val &= 0xFFFFFF00;
ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value);
- mutex_unlock(&dev->lock);
return ret_val;
}
@@ -611,10 +591,7 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
int value = 0;
u32 val = 0, tmp = 0;
- mutex_lock(&dev->lock);
-
if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) {
- mutex_unlock(&dev->lock);
return -1;
}
@@ -626,7 +603,6 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder)
ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value);
- mutex_unlock(&dev->lock);
return ret_val;
}
@@ -636,10 +612,7 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
int value = 0;
u32 val = 0, tmp = 0;
- mutex_lock(&dev->lock);
-
if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) {
- mutex_unlock(&dev->lock);
return -1;
}
@@ -654,7 +627,6 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder)
ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
VDEC_A_HUE_CTRL + (0x200 * decoder), val | value);
- mutex_unlock(&dev->lock);
return ret_val;
}
@@ -664,11 +636,8 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
int value = 0;
u32 val = 0, tmp = 0;
- mutex_lock(&dev->lock);
-
if ((saturation > VIDEO_PROCAMP_MAX) ||
(saturation < VIDEO_PROCAMP_MIN)) {
- mutex_unlock(&dev->lock);
return -1;
}
@@ -687,7 +656,6 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder)
ret_val |= cx25821_i2c_write(&dev->i2c_bus[0],
VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value);
- mutex_unlock(&dev->lock);
return ret_val;
}
@@ -699,8 +667,6 @@ int medusa_video_init(struct cx25821_dev *dev)
int ret_val = 0;
int i = 0;
- mutex_lock(&dev->lock);
-
_num_decoders = dev->_max_num_decoders;
/* disable Auto source selection on all video decoders */
@@ -719,13 +685,9 @@ int medusa_video_init(struct cx25821_dev *dev)
if (ret_val < 0)
goto error;
- mutex_unlock(&dev->lock);
-
for (i = 0; i < _num_decoders; i++)
medusa_set_decoderduration(dev, i, _display_field_cnt[i]);
- mutex_lock(&dev->lock);
-
/* Select monitor as DENC A input, power up the DAC */
value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp);
value &= 0xFF70FF70;
@@ -774,14 +736,8 @@ int medusa_video_init(struct cx25821_dev *dev)
if (ret_val < 0)
goto error;
-
- mutex_unlock(&dev->lock);
-
ret_val = medusa_set_videostandard(dev);
- return ret_val;
-
error:
- mutex_unlock(&dev->lock);
return ret_val;
}
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
deleted file mode 100644
index cf2723c7197f..000000000000
--- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "cx25821-video.h"
-#include "cx25821-video-upstream-ch2.h"
-
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/syscalls.h>
-#include <linux/file.h>
-#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-
-MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
-MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
-MODULE_LICENSE("GPL");
-
-static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC |
- FLD_VID_SRC_OPC_ERR;
-
-static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev,
- __le32 *rp, unsigned int offset,
- unsigned int bpl, u32 sync_line,
- unsigned int lines,
- int fifo_enable, int field_type)
-{
- unsigned int line, i;
- int dist_betwn_starts = bpl * 2;
-
- *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-
- if (USE_RISC_NOOP_VIDEO) {
- for (i = 0; i < NUM_NO_OPS; i++)
- *(rp++) = cpu_to_le32(RISC_NOOP);
- }
-
- /* scan lines */
- for (line = 0; line < lines; line++) {
- *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
- *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset);
- *(rp++) = cpu_to_le32(0); /* bits 63-32 */
-
- if ((lines <= NTSC_FIELD_HEIGHT) ||
- (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
- offset += dist_betwn_starts;
- }
- }
-
- return rp;
-}
-
-static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev,
- __le32 *rp,
- dma_addr_t databuf_phys_addr,
- unsigned int offset,
- u32 sync_line, unsigned int bpl,
- unsigned int lines,
- int fifo_enable, int field_type)
-{
- unsigned int line, i;
- struct sram_channel *sram_ch =
- dev->channels[dev->_channel2_upstream_select].sram_channels;
- int dist_betwn_starts = bpl * 2;
-
- /* sync instruction */
- if (sync_line != NO_SYNC_LINE)
- *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-
- if (USE_RISC_NOOP_VIDEO) {
- for (i = 0; i < NUM_NO_OPS; i++)
- *(rp++) = cpu_to_le32(RISC_NOOP);
- }
-
- /* scan lines */
- for (line = 0; line < lines; line++) {
- *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
- *(rp++) = cpu_to_le32(databuf_phys_addr + offset);
- *(rp++) = cpu_to_le32(0); /* bits 63-32 */
-
- if ((lines <= NTSC_FIELD_HEIGHT) ||
- (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) {
- offset += dist_betwn_starts;
- }
-
- /*
- check if we need to enable the FIFO after the first 4 lines
- For the upstream video channel, the risc engine will enable
- the FIFO.
- */
- if (fifo_enable && line == 3) {
- *(rp++) = RISC_WRITECR;
- *(rp++) = sram_ch->dma_ctl;
- *(rp++) = FLD_VID_FIFO_EN;
- *(rp++) = 0x00000001;
- }
- }
-
- return rp;
-}
-
-static int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev,
- struct pci_dev *pci,
- unsigned int top_offset,
- unsigned int bpl,
- unsigned int lines)
-{
- __le32 *rp;
- int fifo_enable = 0;
- int singlefield_lines = lines >> 1; /*get line count for single field */
- int odd_num_lines = singlefield_lines;
- int frame = 0;
- int frame_size = 0;
- int databuf_offset = 0;
- int risc_program_size = 0;
- int risc_flag = RISC_CNT_RESET;
- unsigned int bottom_offset = bpl;
- dma_addr_t risc_phys_jump_addr;
-
- if (dev->_isNTSC_ch2) {
- odd_num_lines = singlefield_lines + 1;
- risc_program_size = FRAME1_VID_PROG_SIZE;
- if (bpl == Y411_LINE_SZ)
- frame_size = FRAME_SIZE_NTSC_Y411;
- else
- frame_size = FRAME_SIZE_NTSC_Y422;
- } else {
- risc_program_size = PAL_VID_PROG_SIZE;
- if (bpl == Y411_LINE_SZ)
- frame_size = FRAME_SIZE_PAL_Y411;
- else
- frame_size = FRAME_SIZE_PAL_Y422;
- }
-
- /* Virtual address of Risc buffer program */
- rp = dev->_dma_virt_addr_ch2;
-
- for (frame = 0; frame < NUM_FRAMES; frame++) {
- databuf_offset = frame_size * frame;
-
- if (UNSET != top_offset) {
- fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
- rp = cx25821_risc_field_upstream_ch2(dev, rp,
- dev->_data_buf_phys_addr_ch2 + databuf_offset,
- top_offset, 0, bpl, odd_num_lines, fifo_enable,
- ODD_FIELD);
- }
-
- fifo_enable = FIFO_DISABLE;
-
- /* Even field */
- rp = cx25821_risc_field_upstream_ch2(dev, rp,
- dev->_data_buf_phys_addr_ch2 + databuf_offset,
- bottom_offset, 0x200, bpl, singlefield_lines,
- fifo_enable, EVEN_FIELD);
-
- if (frame == 0) {
- risc_flag = RISC_CNT_RESET;
- risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 +
- risc_program_size;
- } else {
- risc_flag = RISC_CNT_INC;
- risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2;
- }
-
- /*
- * Loop to 2ndFrameRISC or to Start of
- * Risc program & generate IRQ
- */
- *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag);
- *(rp++) = cpu_to_le32(risc_phys_jump_addr);
- *(rp++) = cpu_to_le32(0);
- }
-
- return 0;
-}
-
-void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev)
-{
- struct sram_channel *sram_ch =
- dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels;
- u32 tmp = 0;
-
- if (!dev->_is_running_ch2) {
- pr_info("No video file is currently running so return!\n");
- return;
- }
- /* Disable RISC interrupts */
- tmp = cx_read(sram_ch->int_msk);
- cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
-
- /* Turn OFF risc and fifo */
- tmp = cx_read(sram_ch->dma_ctl);
- cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
-
- /* Clear data buffer memory */
- if (dev->_data_buf_virt_addr_ch2)
- memset(dev->_data_buf_virt_addr_ch2, 0,
- dev->_data_buf_size_ch2);
-
- dev->_is_running_ch2 = 0;
- dev->_is_first_frame_ch2 = 0;
- dev->_frame_count_ch2 = 0;
- dev->_file_status_ch2 = END_OF_FILE;
-
- kfree(dev->_irq_queues_ch2);
- dev->_irq_queues_ch2 = NULL;
-
- kfree(dev->_filename_ch2);
-
- tmp = cx_read(VID_CH_MODE_SEL);
- cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
-}
-
-void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev)
-{
- if (dev->_is_running_ch2)
- cx25821_stop_upstream_video_ch2(dev);
-
- if (dev->_dma_virt_addr_ch2) {
- pci_free_consistent(dev->pci, dev->_risc_size_ch2,
- dev->_dma_virt_addr_ch2,
- dev->_dma_phys_addr_ch2);
- dev->_dma_virt_addr_ch2 = NULL;
- }
-
- if (dev->_data_buf_virt_addr_ch2) {
- pci_free_consistent(dev->pci, dev->_data_buf_size_ch2,
- dev->_data_buf_virt_addr_ch2,
- dev->_data_buf_phys_addr_ch2);
- dev->_data_buf_virt_addr_ch2 = NULL;
- }
-}
-
-static int cx25821_get_frame_ch2(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
-{
- struct file *myfile;
- int frame_index_temp = dev->_frame_index_ch2;
- int i = 0;
- int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
- Y411_LINE_SZ : Y422_LINE_SZ;
- int frame_size = 0;
- int frame_offset = 0;
- ssize_t vfs_read_retval = 0;
- char mybuf[line_size];
- loff_t file_offset;
- loff_t pos;
- mm_segment_t old_fs;
-
- if (dev->_file_status_ch2 == END_OF_FILE)
- return 0;
-
- if (dev->_isNTSC_ch2) {
- frame_size = (line_size == Y411_LINE_SZ) ?
- FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
- } else {
- frame_size = (line_size == Y411_LINE_SZ) ?
- FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
- }
-
- frame_offset = (frame_index_temp > 0) ? frame_size : 0;
- file_offset = dev->_frame_count_ch2 * frame_size;
-
- myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
- if (IS_ERR(myfile)) {
- const int open_errno = -PTR_ERR(myfile);
- pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename_ch2, open_errno);
- return PTR_ERR(myfile);
- } else {
- if (!(myfile->f_op)) {
- pr_err("%s(): File has no file operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- if (!myfile->f_op->read) {
- pr_err("%s(): File has no READ operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- pos = myfile->f_pos;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- for (i = 0; i < dev->_lines_count_ch2; i++) {
- pos = file_offset;
-
- vfs_read_retval = vfs_read(myfile, mybuf, line_size,
- &pos);
-
- if (vfs_read_retval > 0 && vfs_read_retval == line_size
- && dev->_data_buf_virt_addr_ch2 != NULL) {
- memcpy((void *)(dev->_data_buf_virt_addr_ch2 +
- frame_offset / 4), mybuf,
- vfs_read_retval);
- }
-
- file_offset += vfs_read_retval;
- frame_offset += vfs_read_retval;
-
- if (vfs_read_retval < line_size) {
- pr_info("Done: exit %s() since no more bytes to read from Video file\n",
- __func__);
- break;
- }
- }
-
- if (i > 0)
- dev->_frame_count_ch2++;
-
- dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
- IN_PROGRESS : END_OF_FILE;
-
- set_fs(old_fs);
- filp_close(myfile, NULL);
- }
-
- return 0;
-}
-
-static void cx25821_vidups_handler_ch2(struct work_struct *work)
-{
- struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
- _irq_work_entry_ch2);
-
- if (!dev) {
- pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
- return;
- }
-
- cx25821_get_frame_ch2(dev, dev->channels[dev->
- _channel2_upstream_select].sram_channels);
-}
-
-static int cx25821_openfile_ch2(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
-{
- struct file *myfile;
- int i = 0, j = 0;
- int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ?
- Y411_LINE_SZ : Y422_LINE_SZ;
- ssize_t vfs_read_retval = 0;
- char mybuf[line_size];
- loff_t pos;
- loff_t offset = (unsigned long)0;
- mm_segment_t old_fs;
-
- myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0);
-
- if (IS_ERR(myfile)) {
- const int open_errno = -PTR_ERR(myfile);
- pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename_ch2, open_errno);
- return PTR_ERR(myfile);
- } else {
- if (!(myfile->f_op)) {
- pr_err("%s(): File has no file operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- if (!myfile->f_op->read) {
- pr_err("%s(): File has no READ operations registered! Returning\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- pos = myfile->f_pos;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- for (j = 0; j < NUM_FRAMES; j++) {
- for (i = 0; i < dev->_lines_count_ch2; i++) {
- pos = offset;
-
- vfs_read_retval = vfs_read(myfile, mybuf,
- line_size, &pos);
-
- if (vfs_read_retval > 0 &&
- vfs_read_retval == line_size &&
- dev->_data_buf_virt_addr_ch2 != NULL) {
- memcpy((void *)(dev->
- _data_buf_virt_addr_ch2
- + offset / 4), mybuf,
- vfs_read_retval);
- }
-
- offset += vfs_read_retval;
-
- if (vfs_read_retval < line_size) {
- pr_info("Done: exit %s() since no more bytes to read from Video file\n",
- __func__);
- break;
- }
- }
-
- if (i > 0)
- dev->_frame_count_ch2++;
-
- if (vfs_read_retval < line_size)
- break;
- }
-
- dev->_file_status_ch2 = (vfs_read_retval == line_size) ?
- IN_PROGRESS : END_OF_FILE;
-
- set_fs(old_fs);
- myfile->f_pos = 0;
- filp_close(myfile, NULL);
- }
-
- return 0;
-}
-
-static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev,
- struct sram_channel *sram_ch,
- int bpl)
-{
- int ret = 0;
- dma_addr_t dma_addr;
- dma_addr_t data_dma_addr;
-
- if (dev->_dma_virt_addr_ch2 != NULL) {
- pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2,
- dev->_dma_virt_addr_ch2,
- dev->_dma_phys_addr_ch2);
- }
-
- dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
- dev->upstream_riscbuf_size_ch2, &dma_addr);
- dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2;
- dev->_dma_phys_start_addr_ch2 = dma_addr;
- dev->_dma_phys_addr_ch2 = dma_addr;
- dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2;
-
- if (!dev->_dma_virt_addr_ch2) {
- pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
- return -ENOMEM;
- }
-
- /* Iniitize at this address until n bytes to 0 */
- memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2);
-
- if (dev->_data_buf_virt_addr_ch2 != NULL) {
- pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2,
- dev->_data_buf_virt_addr_ch2,
- dev->_data_buf_phys_addr_ch2);
- }
- /* For Video Data buffer allocation */
- dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci,
- dev->upstream_databuf_size_ch2, &data_dma_addr);
- dev->_data_buf_phys_addr_ch2 = data_dma_addr;
- dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2;
-
- if (!dev->_data_buf_virt_addr_ch2) {
- pr_err("FAILED to allocate memory for data buffer! Returning\n");
- return -ENOMEM;
- }
-
- /* Initialize at this address until n bytes to 0 */
- memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2);
-
- ret = cx25821_openfile_ch2(dev, sram_ch);
- if (ret < 0)
- return ret;
-
- /* Creating RISC programs */
- ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl,
- dev->_lines_count_ch2);
- if (ret < 0) {
- pr_info("Failed creating Video Upstream Risc programs!\n");
- goto error;
- }
-
- return 0;
-
-error:
- return ret;
-}
-
-static int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev,
- int chan_num,
- u32 status)
-{
- u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
- int singlefield_lines = NTSC_FIELD_HEIGHT;
- int line_size_in_bytes = Y422_LINE_SZ;
- int odd_risc_prog_size = 0;
- dma_addr_t risc_phys_jump_addr;
- __le32 *rp;
-
- if (status & FLD_VID_SRC_RISC1) {
- /* We should only process one program per call */
- u32 prog_cnt = cx_read(channel->gpcnt);
-
- /*
- * Since we've identified our IRQ, clear our bits from the
- * interrupt mask and interrupt status registers
- */
- int_msk_tmp = cx_read(channel->int_msk);
- cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
- cx_write(channel->int_stat, _intr_msk);
-
- spin_lock(&dev->slock);
-
- dev->_frame_index_ch2 = prog_cnt;
-
- queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2);
-
- if (dev->_is_first_frame_ch2) {
- dev->_is_first_frame_ch2 = 0;
-
- if (dev->_isNTSC_ch2) {
- singlefield_lines += 1;
- odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE;
- } else {
- singlefield_lines = PAL_FIELD_HEIGHT;
- odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE;
- }
-
- if (dev->_dma_virt_start_addr_ch2 != NULL) {
- if (dev->_pixel_format_ch2 == PIXEL_FRMT_411)
- line_size_in_bytes = Y411_LINE_SZ;
- else
- line_size_in_bytes = Y422_LINE_SZ;
- risc_phys_jump_addr =
- dev->_dma_phys_start_addr_ch2 +
- odd_risc_prog_size;
-
- rp = cx25821_update_riscprogram_ch2(dev,
- dev->_dma_virt_start_addr_ch2,
- TOP_OFFSET, line_size_in_bytes,
- 0x0, singlefield_lines,
- FIFO_DISABLE, ODD_FIELD);
-
- /* Jump to Even Risc program of 1st Frame */
- *(rp++) = cpu_to_le32(RISC_JUMP);
- *(rp++) = cpu_to_le32(risc_phys_jump_addr);
- *(rp++) = cpu_to_le32(0);
- }
- }
-
- spin_unlock(&dev->slock);
- }
-
- if (dev->_file_status_ch2 == END_OF_FILE) {
- pr_info("EOF Channel 2 Framecount = %d\n",
- dev->_frame_count_ch2);
- return -1;
- }
- /* ElSE, set the interrupt mask register, re-enable irq. */
- int_msk_tmp = cx_read(channel->int_msk);
- cx_write(channel->int_msk, int_msk_tmp |= _intr_msk);
-
- return 0;
-}
-
-static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
-{
- struct cx25821_dev *dev = dev_id;
- u32 vid_status;
- int handled = 0;
- int channel_num = 0;
- struct sram_channel *sram_ch;
-
- if (!dev)
- return -1;
-
- channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
- sram_ch = dev->channels[channel_num].sram_channels;
-
- vid_status = cx_read(sram_ch->int_stat);
-
- /* Only deal with our interrupt */
- if (vid_status)
- handled = cx25821_video_upstream_irq_ch2(dev, channel_num,
- vid_status);
-
- if (handled < 0)
- cx25821_stop_upstream_video_ch2(dev);
- else
- handled += handled;
-
- return IRQ_RETVAL(handled);
-}
-
-static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev,
- struct sram_channel *ch, int pix_format)
-{
- int width = WIDTH_D1;
- int height = dev->_lines_count_ch2;
- int num_lines, odd_num_lines;
- u32 value;
- int vip_mode = PIXEL_ENGINE_VIP1;
-
- value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7);
- value &= 0xFFFFFFEF;
- value |= dev->_isNTSC_ch2 ? 0 : 0x10;
- cx_write(ch->vid_fmt_ctl, value);
-
- /*
- * set number of active pixels in each line. Default is 720
- * pixels in both NTSC and PAL format
- */
- cx_write(ch->vid_active_ctl1, width);
-
- num_lines = (height / 2) & 0x3FF;
- odd_num_lines = num_lines;
-
- if (dev->_isNTSC_ch2)
- odd_num_lines += 1;
-
- value = (num_lines << 16) | odd_num_lines;
-
- /* set number of active lines in field 0 (top) and field 1 (bottom) */
- cx_write(ch->vid_active_ctl2, value);
-
- cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
-}
-
-static int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
-{
- u32 tmp = 0;
- int err = 0;
-
- /*
- * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface
- * for channel A-C
- */
- tmp = cx_read(VID_CH_MODE_SEL);
- cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
-
- /*
- * Set the physical start address of the RISC program in the initial
- * program counter(IPC) member of the cmds.
- */
- cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2);
- cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */
-
- /* reset counter */
- cx_write(sram_ch->gpcnt_ctl, 3);
-
- /* Clear our bits from the interrupt status register. */
- cx_write(sram_ch->int_stat, _intr_msk);
-
- /* Set the interrupt mask register, enable irq. */
- cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit));
- tmp = cx_read(sram_ch->int_msk);
- cx_write(sram_ch->int_msk, tmp |= _intr_msk);
-
- err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2,
- IRQF_SHARED, dev->name, dev);
- if (err < 0) {
- pr_err("%s: can't get upstream IRQ %d\n",
- dev->name, dev->pci->irq);
- goto fail_irq;
- }
- /* Start the DMA engine */
- tmp = cx_read(sram_ch->dma_ctl);
- cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
-
- dev->_is_running_ch2 = 1;
- dev->_is_first_frame_ch2 = 1;
-
- return 0;
-
-fail_irq:
- cx25821_dev_unregister(dev);
- return err;
-}
-
-int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select,
- int pixel_format)
-{
- struct sram_channel *sram_ch;
- u32 tmp;
- int err = 0;
- int data_frame_size = 0;
- int risc_buffer_size = 0;
-
- if (dev->_is_running_ch2) {
- pr_info("Video Channel is still running so return!\n");
- return 0;
- }
-
- dev->_channel2_upstream_select = channel_select;
- sram_ch = dev->channels[channel_select].sram_channels;
-
- INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2);
- dev->_irq_queues_ch2 =
- create_singlethread_workqueue("cx25821_workqueue2");
-
- if (!dev->_irq_queues_ch2) {
- pr_err("create_singlethread_workqueue() for Video FAILED!\n");
- return -ENOMEM;
- }
- /*
- * 656/VIP SRC Upstream Channel I & J and 7 -
- * Host Bus Interface for channel A-C
- */
- tmp = cx_read(VID_CH_MODE_SEL);
- cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
-
- dev->_is_running_ch2 = 0;
- dev->_frame_count_ch2 = 0;
- dev->_file_status_ch2 = RESET_STATUS;
- dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576;
- dev->_pixel_format_ch2 = pixel_format;
- dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ?
- (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
- data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
- risc_buffer_size = dev->_isNTSC_ch2 ?
- NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
-
- if (dev->input_filename_ch2)
- dev->_filename_ch2 = kstrdup(dev->input_filename_ch2,
- GFP_KERNEL);
- else
- dev->_filename_ch2 = kstrdup(dev->_defaultname_ch2,
- GFP_KERNEL);
-
- if (!dev->_filename_ch2) {
- err = -ENOENT;
- goto error;
- }
-
- /* Default if filename is empty string */
- if (strcmp(dev->_filename_ch2, "") == 0) {
- if (dev->_isNTSC_ch2) {
- dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? "/root/vid411.yuv" :
- "/root/vidtest.yuv";
- } else {
- dev->_filename_ch2 = (dev->_pixel_format_ch2 ==
- PIXEL_FRMT_411) ? "/root/pal411.yuv" :
- "/root/pal422.yuv";
- }
- }
-
- err = cx25821_sram_channel_setup_upstream(dev, sram_ch,
- dev->_line_size_ch2, 0);
-
- /* setup fifo + format */
- cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2);
-
- dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2;
- dev->upstream_databuf_size_ch2 = data_frame_size * 2;
-
- /* Allocating buffers and prepare RISC program */
- err = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch,
- dev->_line_size_ch2);
- if (err < 0) {
- pr_err("%s: Failed to set up Video upstream buffers!\n",
- dev->name);
- goto error;
- }
-
- cx25821_start_video_dma_upstream_ch2(dev, sram_ch);
-
- return 0;
-
-error:
- cx25821_dev_unregister(dev);
-
- return err;
-}
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
deleted file mode 100644
index d42dab59b663..000000000000
--- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Driver for the Conexant CX25821 PCIe bridge
- *
- * Copyright (C) 2009 Conexant Systems Inc.
- * Authors <hiep.huynh@conexant.com>, <shu.lin@conexant.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/mutex.h>
-#include <linux/workqueue.h>
-
-#define OPEN_FILE_1 0
-#define NUM_PROGS 8
-#define NUM_FRAMES 2
-#define ODD_FIELD 0
-#define EVEN_FIELD 1
-#define TOP_OFFSET 0
-#define FIFO_DISABLE 0
-#define FIFO_ENABLE 1
-#define TEST_FRAMES 5
-#define END_OF_FILE 0
-#define IN_PROGRESS 1
-#define RESET_STATUS -1
-#define NUM_NO_OPS 5
-
-/* PAL and NTSC line sizes and number of lines. */
-#define WIDTH_D1 720
-#define NTSC_LINES_PER_FRAME 480
-#define PAL_LINES_PER_FRAME 576
-#define PAL_LINE_SZ 1440
-#define Y422_LINE_SZ 1440
-#define Y411_LINE_SZ 1080
-#define NTSC_FIELD_HEIGHT 240
-#define NTSC_ODD_FLD_LINES 241
-#define PAL_FIELD_HEIGHT 288
-
-#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ)
-#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ)
-#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ)
-#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ)
-
-#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME)
-#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME)
-
-#define RISC_WRITECR_INSTRUCTION_SIZE 16
-#define RISC_SYNC_INSTRUCTION_SIZE 4
-#define JUMP_INSTRUCTION_SIZE 12
-#define MAXSIZE_NO_OPS 36
-#define DWORD_SIZE 4
-
-#define USE_RISC_NOOP_VIDEO 1
-
-#ifdef USE_RISC_NOOP_VIDEO
-#define PAL_US_VID_PROG_SIZE \
- (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \
- NUM_NO_OPS * DWORD_SIZE)
-
-#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE)
-
-#define PAL_VID_PROG_SIZE \
- ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \
- 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
- JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE)
-
-#define ODD_FLD_PAL_PROG_SIZE \
- (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \
- RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
- NUM_NO_OPS * DWORD_SIZE)
-
-#define NTSC_US_VID_PROG_SIZE \
- ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \
- NUM_NO_OPS * DWORD_SIZE)
-
-#define NTSC_RISC_BUF_SIZE \
- (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
-
-#define FRAME1_VID_PROG_SIZE \
- ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \
- 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \
- 2 * NUM_NO_OPS * DWORD_SIZE)
-
-#define ODD_FLD_NTSC_PROG_SIZE \
- (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \
- RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
- NUM_NO_OPS * DWORD_SIZE)
-#endif
-
-#ifndef USE_RISC_NOOP_VIDEO
-#define PAL_US_VID_PROG_SIZE \
- ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE)
-
-#define PAL_RISC_BUF_SIZE \
- (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE))
-
-#define PAL_VID_PROG_SIZE \
- ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \
- 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \
- JUMP_INSTRUCTION_SIZE)
-
-#define ODD_FLD_PAL_PROG_SIZE \
- (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \
- RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
-
-#define ODD_FLD_NTSC_PROG_SIZE \
- (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \
- RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE)
-
-#define NTSC_US_VID_PROG_SIZE \
- ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-
-#define NTSC_RISC_BUF_SIZE \
- (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE))
-
-#define FRAME1_VID_PROG_SIZE \
- ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \
- 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \
- RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE)
-
-#endif
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
index 7fc97110d973..88ffef410c50 100644
--- a/drivers/media/pci/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
@@ -25,16 +25,11 @@
#include "cx25821-video.h"
#include "cx25821-video-upstream.h"
-#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/syscalls.h>
-#include <linux/file.h>
-#include <linux/fcntl.h>
#include <linux/slab.h>
-#include <linux/uaccess.h>
MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards");
MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
@@ -44,7 +39,7 @@ static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC |
FLD_VID_SRC_OPC_ERR;
int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i, lines;
@@ -97,12 +92,13 @@ int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
return 0;
}
-static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev,
+static __le32 *cx25821_update_riscprogram(struct cx25821_channel *chan,
__le32 *rp, unsigned int offset,
unsigned int bpl, u32 sync_line,
unsigned int lines, int fifo_enable,
int field_type)
{
+ struct cx25821_video_out_data *out = chan->out;
unsigned int line, i;
int dist_betwn_starts = bpl * 2;
@@ -116,11 +112,11 @@ static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev,
/* scan lines */
for (line = 0; line < lines; line++) {
*(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl);
- *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset);
+ *(rp++) = cpu_to_le32(out->_data_buf_phys_addr + offset);
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
if ((lines <= NTSC_FIELD_HEIGHT)
- || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) {
+ || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz)) {
offset += dist_betwn_starts;
}
}
@@ -128,15 +124,15 @@ static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev,
return rp;
}
-static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
+static __le32 *cx25821_risc_field_upstream(struct cx25821_channel *chan, __le32 *rp,
dma_addr_t databuf_phys_addr,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int lines,
int fifo_enable, int field_type)
{
+ struct cx25821_video_out_data *out = chan->out;
unsigned int line, i;
- struct sram_channel *sram_ch =
- dev->channels[dev->_channel_upstream_select].sram_channels;
+ const struct sram_channel *sram_ch = chan->sram_channels;
int dist_betwn_starts = bpl * 2;
/* sync instruction */
@@ -155,7 +151,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
if ((lines <= NTSC_FIELD_HEIGHT)
- || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC))
+ || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz))
/* to skip the other field line */
offset += dist_betwn_starts;
@@ -173,11 +169,12 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp,
return rp;
}
-static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
+static int cx25821_risc_buffer_upstream(struct cx25821_channel *chan,
struct pci_dev *pci,
unsigned int top_offset,
unsigned int bpl, unsigned int lines)
{
+ struct cx25821_video_out_data *out = chan->out;
__le32 *rp;
int fifo_enable = 0;
/* get line count for single field */
@@ -191,7 +188,7 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
unsigned int bottom_offset = bpl;
dma_addr_t risc_phys_jump_addr;
- if (dev->_isNTSC) {
+ if (out->is_60hz) {
odd_num_lines = singlefield_lines + 1;
risc_program_size = FRAME1_VID_PROG_SIZE;
frame_size = (bpl == Y411_LINE_SZ) ?
@@ -203,15 +200,15 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
}
/* Virtual address of Risc buffer program */
- rp = dev->_dma_virt_addr;
+ rp = out->_dma_virt_addr;
for (frame = 0; frame < NUM_FRAMES; frame++) {
databuf_offset = frame_size * frame;
if (UNSET != top_offset) {
fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE;
- rp = cx25821_risc_field_upstream(dev, rp,
- dev->_data_buf_phys_addr +
+ rp = cx25821_risc_field_upstream(chan, rp,
+ out->_data_buf_phys_addr +
databuf_offset, top_offset, 0, bpl,
odd_num_lines, fifo_enable, ODD_FIELD);
}
@@ -219,18 +216,18 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
fifo_enable = FIFO_DISABLE;
/* Even Field */
- rp = cx25821_risc_field_upstream(dev, rp,
- dev->_data_buf_phys_addr +
+ rp = cx25821_risc_field_upstream(chan, rp,
+ out->_data_buf_phys_addr +
databuf_offset, bottom_offset,
0x200, bpl, singlefield_lines,
fifo_enable, EVEN_FIELD);
if (frame == 0) {
risc_flag = RISC_CNT_RESET;
- risc_phys_jump_addr = dev->_dma_phys_start_addr +
+ risc_phys_jump_addr = out->_dma_phys_start_addr +
risc_program_size;
} else {
- risc_phys_jump_addr = dev->_dma_phys_start_addr;
+ risc_phys_jump_addr = out->_dma_phys_start_addr;
risc_flag = RISC_CNT_INC;
}
@@ -245,16 +242,21 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev,
return 0;
}
-void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
+void cx25821_stop_upstream_video(struct cx25821_channel *chan)
{
- struct sram_channel *sram_ch =
- dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels;
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
+ const struct sram_channel *sram_ch = chan->sram_channels;
u32 tmp = 0;
- if (!dev->_is_running) {
+ if (!out->_is_running) {
pr_info("No video file is currently running so return!\n");
return;
}
+
+ /* Set the interrupt mask register, disable irq. */
+ cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) & ~(1 << sram_ch->irq_bit));
+
/* Disable RISC interrupts */
tmp = cx_read(sram_ch->int_msk);
cx_write(sram_ch->int_msk, tmp & ~_intr_msk);
@@ -263,283 +265,133 @@ void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev)
tmp = cx_read(sram_ch->dma_ctl);
cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN));
- /* Clear data buffer memory */
- if (dev->_data_buf_virt_addr)
- memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
+ free_irq(dev->pci->irq, chan);
- dev->_is_running = 0;
- dev->_is_first_frame = 0;
- dev->_frame_count = 0;
- dev->_file_status = END_OF_FILE;
-
- kfree(dev->_irq_queues);
- dev->_irq_queues = NULL;
+ /* Clear data buffer memory */
+ if (out->_data_buf_virt_addr)
+ memset(out->_data_buf_virt_addr, 0, out->_data_buf_size);
- kfree(dev->_filename);
+ out->_is_running = 0;
+ out->_is_first_frame = 0;
+ out->_frame_count = 0;
+ out->_file_status = END_OF_FILE;
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00);
}
-void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev)
+void cx25821_free_mem_upstream(struct cx25821_channel *chan)
{
- if (dev->_is_running)
- cx25821_stop_upstream_video_ch1(dev);
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
- if (dev->_dma_virt_addr) {
- pci_free_consistent(dev->pci, dev->_risc_size,
- dev->_dma_virt_addr, dev->_dma_phys_addr);
- dev->_dma_virt_addr = NULL;
+ if (out->_is_running)
+ cx25821_stop_upstream_video(chan);
+
+ if (out->_dma_virt_addr) {
+ pci_free_consistent(dev->pci, out->_risc_size,
+ out->_dma_virt_addr, out->_dma_phys_addr);
+ out->_dma_virt_addr = NULL;
}
- if (dev->_data_buf_virt_addr) {
- pci_free_consistent(dev->pci, dev->_data_buf_size,
- dev->_data_buf_virt_addr,
- dev->_data_buf_phys_addr);
- dev->_data_buf_virt_addr = NULL;
+ if (out->_data_buf_virt_addr) {
+ pci_free_consistent(dev->pci, out->_data_buf_size,
+ out->_data_buf_virt_addr,
+ out->_data_buf_phys_addr);
+ out->_data_buf_virt_addr = NULL;
}
}
-static int cx25821_get_frame(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+int cx25821_write_frame(struct cx25821_channel *chan,
+ const char __user *data, size_t count)
{
- struct file *myfile;
- int frame_index_temp = dev->_frame_index;
- int i = 0;
- int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
+ struct cx25821_video_out_data *out = chan->out;
+ int line_size = (out->_pixel_format == PIXEL_FRMT_411) ?
Y411_LINE_SZ : Y422_LINE_SZ;
int frame_size = 0;
int frame_offset = 0;
- ssize_t vfs_read_retval = 0;
- char mybuf[line_size];
- loff_t file_offset;
- loff_t pos;
- mm_segment_t old_fs;
-
- if (dev->_file_status == END_OF_FILE)
- return 0;
+ int curpos = out->curpos;
- if (dev->_isNTSC)
+ if (out->is_60hz)
frame_size = (line_size == Y411_LINE_SZ) ?
FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422;
else
frame_size = (line_size == Y411_LINE_SZ) ?
FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422;
- frame_offset = (frame_index_temp > 0) ? frame_size : 0;
- file_offset = dev->_frame_count * frame_size;
-
- myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0);
-
- if (IS_ERR(myfile)) {
- const int open_errno = -PTR_ERR(myfile);
- pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename, open_errno);
- return PTR_ERR(myfile);
- } else {
- if (!(myfile->f_op)) {
- pr_err("%s(): File has no file operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- if (!myfile->f_op->read) {
- pr_err("%s(): File has no READ operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- pos = myfile->f_pos;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- for (i = 0; i < dev->_lines_count; i++) {
- pos = file_offset;
-
- vfs_read_retval = vfs_read(myfile, mybuf, line_size,
- &pos);
-
- if (vfs_read_retval > 0 && vfs_read_retval == line_size
- && dev->_data_buf_virt_addr != NULL) {
- memcpy((void *)(dev->_data_buf_virt_addr +
- frame_offset / 4), mybuf,
- vfs_read_retval);
- }
-
- file_offset += vfs_read_retval;
- frame_offset += vfs_read_retval;
-
- if (vfs_read_retval < line_size) {
- pr_info("Done: exit %s() since no more bytes to read from Video file\n",
- __func__);
- break;
- }
- }
-
- if (i > 0)
- dev->_frame_count++;
-
- dev->_file_status = (vfs_read_retval == line_size) ?
- IN_PROGRESS : END_OF_FILE;
-
- set_fs(old_fs);
- filp_close(myfile, NULL);
- }
-
- return 0;
-}
-
-static void cx25821_vidups_handler(struct work_struct *work)
-{
- struct cx25821_dev *dev = container_of(work, struct cx25821_dev,
- _irq_work_entry);
-
- if (!dev) {
- pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n",
- __func__);
- return;
+ if (curpos == 0) {
+ out->cur_frame_index = out->_frame_index;
+ if (wait_event_interruptible(out->waitq, out->cur_frame_index != out->_frame_index))
+ return -EINTR;
+ out->cur_frame_index = out->_frame_index;
}
- cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select].
- sram_channels);
-}
-
-static int cx25821_openfile(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
-{
- struct file *myfile;
- int i = 0, j = 0;
- int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ?
- Y411_LINE_SZ : Y422_LINE_SZ;
- ssize_t vfs_read_retval = 0;
- char mybuf[line_size];
- loff_t pos;
- loff_t offset = (unsigned long)0;
- mm_segment_t old_fs;
-
- myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0);
-
- if (IS_ERR(myfile)) {
- const int open_errno = -PTR_ERR(myfile);
- pr_err("%s(): ERROR opening file(%s) with errno = %d!\n",
- __func__, dev->_filename, open_errno);
- return PTR_ERR(myfile);
- } else {
- if (!(myfile->f_op)) {
- pr_err("%s(): File has no file operations registered!\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- if (!myfile->f_op->read) {
- pr_err("%s(): File has no READ operations registered! Returning\n",
- __func__);
- filp_close(myfile, NULL);
- return -EIO;
- }
-
- pos = myfile->f_pos;
- old_fs = get_fs();
- set_fs(KERNEL_DS);
-
- for (j = 0; j < NUM_FRAMES; j++) {
- for (i = 0; i < dev->_lines_count; i++) {
- pos = offset;
-
- vfs_read_retval = vfs_read(myfile, mybuf,
- line_size, &pos);
-
- if (vfs_read_retval > 0
- && vfs_read_retval == line_size
- && dev->_data_buf_virt_addr != NULL) {
- memcpy((void *)(dev->
- _data_buf_virt_addr +
- offset / 4), mybuf,
- vfs_read_retval);
- }
-
- offset += vfs_read_retval;
-
- if (vfs_read_retval < line_size) {
- pr_info("Done: exit %s() since no more bytes to read from Video file\n",
- __func__);
- break;
- }
- }
+ frame_offset = out->cur_frame_index ? frame_size : 0;
- if (i > 0)
- dev->_frame_count++;
-
- if (vfs_read_retval < line_size)
- break;
- }
-
- dev->_file_status = (vfs_read_retval == line_size) ?
- IN_PROGRESS : END_OF_FILE;
-
- set_fs(old_fs);
- myfile->f_pos = 0;
- filp_close(myfile, NULL);
+ if (frame_size - curpos < count)
+ count = frame_size - curpos;
+ memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos,
+ data, count);
+ curpos += count;
+ if (curpos == frame_size) {
+ out->_frame_count++;
+ curpos = 0;
}
+ out->curpos = curpos;
- return 0;
+ return count;
}
-static int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev,
- struct sram_channel *sram_ch,
+static int cx25821_upstream_buffer_prepare(struct cx25821_channel *chan,
+ const struct sram_channel *sram_ch,
int bpl)
{
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
int ret = 0;
dma_addr_t dma_addr;
dma_addr_t data_dma_addr;
- if (dev->_dma_virt_addr != NULL)
- pci_free_consistent(dev->pci, dev->upstream_riscbuf_size,
- dev->_dma_virt_addr, dev->_dma_phys_addr);
+ if (out->_dma_virt_addr != NULL)
+ pci_free_consistent(dev->pci, out->upstream_riscbuf_size,
+ out->_dma_virt_addr, out->_dma_phys_addr);
- dev->_dma_virt_addr = pci_alloc_consistent(dev->pci,
- dev->upstream_riscbuf_size, &dma_addr);
- dev->_dma_virt_start_addr = dev->_dma_virt_addr;
- dev->_dma_phys_start_addr = dma_addr;
- dev->_dma_phys_addr = dma_addr;
- dev->_risc_size = dev->upstream_riscbuf_size;
+ out->_dma_virt_addr = pci_alloc_consistent(dev->pci,
+ out->upstream_riscbuf_size, &dma_addr);
+ out->_dma_virt_start_addr = out->_dma_virt_addr;
+ out->_dma_phys_start_addr = dma_addr;
+ out->_dma_phys_addr = dma_addr;
+ out->_risc_size = out->upstream_riscbuf_size;
- if (!dev->_dma_virt_addr) {
+ if (!out->_dma_virt_addr) {
pr_err("FAILED to allocate memory for Risc buffer! Returning\n");
return -ENOMEM;
}
/* Clear memory at address */
- memset(dev->_dma_virt_addr, 0, dev->_risc_size);
+ memset(out->_dma_virt_addr, 0, out->_risc_size);
- if (dev->_data_buf_virt_addr != NULL)
- pci_free_consistent(dev->pci, dev->upstream_databuf_size,
- dev->_data_buf_virt_addr,
- dev->_data_buf_phys_addr);
+ if (out->_data_buf_virt_addr != NULL)
+ pci_free_consistent(dev->pci, out->upstream_databuf_size,
+ out->_data_buf_virt_addr,
+ out->_data_buf_phys_addr);
/* For Video Data buffer allocation */
- dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci,
- dev->upstream_databuf_size, &data_dma_addr);
- dev->_data_buf_phys_addr = data_dma_addr;
- dev->_data_buf_size = dev->upstream_databuf_size;
+ out->_data_buf_virt_addr = pci_alloc_consistent(dev->pci,
+ out->upstream_databuf_size, &data_dma_addr);
+ out->_data_buf_phys_addr = data_dma_addr;
+ out->_data_buf_size = out->upstream_databuf_size;
- if (!dev->_data_buf_virt_addr) {
+ if (!out->_data_buf_virt_addr) {
pr_err("FAILED to allocate memory for data buffer! Returning\n");
return -ENOMEM;
}
/* Clear memory at address */
- memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size);
-
- ret = cx25821_openfile(dev, sram_ch);
- if (ret < 0)
- return ret;
+ memset(out->_data_buf_virt_addr, 0, out->_data_buf_size);
/* Create RISC programs */
- ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl,
- dev->_lines_count);
+ ret = cx25821_risc_buffer_upstream(chan, dev->pci, 0, bpl,
+ out->_lines_count);
if (ret < 0) {
pr_info("Failed creating Video Upstream Risc programs!\n");
goto error;
@@ -551,11 +403,12 @@ error:
return ret;
}
-static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
- u32 status)
+static int cx25821_video_upstream_irq(struct cx25821_channel *chan, u32 status)
{
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
u32 int_msk_tmp;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ const struct sram_channel *channel = chan->sram_channels;
int singlefield_lines = NTSC_FIELD_HEIGHT;
int line_size_in_bytes = Y422_LINE_SZ;
int odd_risc_prog_size = 0;
@@ -572,16 +425,16 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk);
cx_write(channel->int_stat, _intr_msk);
- spin_lock(&dev->slock);
+ wake_up(&out->waitq);
- dev->_frame_index = prog_cnt;
+ spin_lock(&dev->slock);
- queue_work(dev->_irq_queues, &dev->_irq_work_entry);
+ out->_frame_index = prog_cnt;
- if (dev->_is_first_frame) {
- dev->_is_first_frame = 0;
+ if (out->_is_first_frame) {
+ out->_is_first_frame = 0;
- if (dev->_isNTSC) {
+ if (out->is_60hz) {
singlefield_lines += 1;
odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE;
} else {
@@ -589,17 +442,17 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE;
}
- if (dev->_dma_virt_start_addr != NULL) {
+ if (out->_dma_virt_start_addr != NULL) {
line_size_in_bytes =
- (dev->_pixel_format ==
+ (out->_pixel_format ==
PIXEL_FRMT_411) ? Y411_LINE_SZ :
Y422_LINE_SZ;
risc_phys_jump_addr =
- dev->_dma_phys_start_addr +
+ out->_dma_phys_start_addr +
odd_risc_prog_size;
- rp = cx25821_update_riscprogram(dev,
- dev->_dma_virt_start_addr, TOP_OFFSET,
+ rp = cx25821_update_riscprogram(chan,
+ out->_dma_virt_start_addr, TOP_OFFSET,
line_size_in_bytes, 0x0,
singlefield_lines, FIFO_DISABLE,
ODD_FIELD);
@@ -626,8 +479,8 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
__func__);
}
- if (dev->_file_status == END_OF_FILE) {
- pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count);
+ if (out->_file_status == END_OF_FILE) {
+ pr_err("EOF Channel 1 Framecount = %d\n", out->_frame_count);
return -1;
}
/* ElSE, set the interrupt mask register, re-enable irq. */
@@ -639,47 +492,41 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
{
- struct cx25821_dev *dev = dev_id;
+ struct cx25821_channel *chan = dev_id;
+ struct cx25821_dev *dev = chan->dev;
u32 vid_status;
int handled = 0;
- int channel_num = 0;
- struct sram_channel *sram_ch;
+ const struct sram_channel *sram_ch;
if (!dev)
return -1;
- channel_num = VID_UPSTREAM_SRAM_CHANNEL_I;
-
- sram_ch = dev->channels[channel_num].sram_channels;
+ sram_ch = chan->sram_channels;
vid_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
if (vid_status)
- handled = cx25821_video_upstream_irq(dev, channel_num,
- vid_status);
-
- if (handled < 0)
- cx25821_stop_upstream_video_ch1(dev);
- else
- handled += handled;
+ handled = cx25821_video_upstream_irq(chan, vid_status);
return IRQ_RETVAL(handled);
}
-static void cx25821_set_pixelengine(struct cx25821_dev *dev,
- struct sram_channel *ch,
+static void cx25821_set_pixelengine(struct cx25821_channel *chan,
+ const struct sram_channel *ch,
int pix_format)
{
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
int width = WIDTH_D1;
- int height = dev->_lines_count;
+ int height = out->_lines_count;
int num_lines, odd_num_lines;
u32 value;
int vip_mode = OUTPUT_FRMT_656;
value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7);
value &= 0xFFFFFFEF;
- value |= dev->_isNTSC ? 0 : 0x10;
+ value |= out->is_60hz ? 0 : 0x10;
cx_write(ch->vid_fmt_ctl, value);
/* set number of active pixels in each line.
@@ -689,7 +536,7 @@ static void cx25821_set_pixelengine(struct cx25821_dev *dev,
num_lines = (height / 2) & 0x3FF;
odd_num_lines = num_lines;
- if (dev->_isNTSC)
+ if (out->is_60hz)
odd_num_lines += 1;
value = (num_lines << 16) | odd_num_lines;
@@ -700,9 +547,11 @@ static void cx25821_set_pixelengine(struct cx25821_dev *dev,
cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3);
}
-static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
- struct sram_channel *sram_ch)
+static int cx25821_start_video_dma_upstream(struct cx25821_channel *chan,
+ const struct sram_channel *sram_ch)
{
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
u32 tmp = 0;
int err = 0;
@@ -715,7 +564,7 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
/* Set the physical start address of the RISC program in the initial
* program counter(IPC) member of the cmds.
*/
- cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr);
+ cx_write(sram_ch->cmds_start + 0, out->_dma_phys_addr);
/* Risc IPC High 64 bits 63-32 */
cx_write(sram_ch->cmds_start + 4, 0);
@@ -731,7 +580,7 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
cx_write(sram_ch->int_msk, tmp |= _intr_msk);
err = request_irq(dev->pci->irq, cx25821_upstream_irq,
- IRQF_SHARED, dev->name, dev);
+ IRQF_SHARED, dev->name, chan);
if (err < 0) {
pr_err("%s: can't get upstream IRQ %d\n",
dev->name, dev->pci->irq);
@@ -742,8 +591,8 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev,
tmp = cx_read(sram_ch->dma_ctl);
cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN);
- dev->_is_running = 1;
- dev->_is_first_frame = 1;
+ out->_is_running = 1;
+ out->_is_first_frame = 1;
return 0;
@@ -752,107 +601,71 @@ fail_irq:
return err;
}
-int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select,
+int cx25821_vidupstream_init(struct cx25821_channel *chan,
int pixel_format)
{
- struct sram_channel *sram_ch;
+ struct cx25821_video_out_data *out = chan->out;
+ struct cx25821_dev *dev = chan->dev;
+ const struct sram_channel *sram_ch;
u32 tmp;
int err = 0;
int data_frame_size = 0;
int risc_buffer_size = 0;
- int str_length = 0;
- if (dev->_is_running) {
+ if (out->_is_running) {
pr_info("Video Channel is still running so return!\n");
return 0;
}
- dev->_channel_upstream_select = channel_select;
- sram_ch = dev->channels[channel_select].sram_channels;
+ sram_ch = chan->sram_channels;
- INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler);
- dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue");
+ out->is_60hz = dev->tvnorm & V4L2_STD_525_60;
- if (!dev->_irq_queues) {
- pr_err("create_singlethread_workqueue() for Video FAILED!\n");
- return -ENOMEM;
- }
/* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for
* channel A-C
*/
tmp = cx_read(VID_CH_MODE_SEL);
cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF);
- dev->_is_running = 0;
- dev->_frame_count = 0;
- dev->_file_status = RESET_STATUS;
- dev->_lines_count = dev->_isNTSC ? 480 : 576;
- dev->_pixel_format = pixel_format;
- dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+ out->_is_running = 0;
+ out->_frame_count = 0;
+ out->_file_status = RESET_STATUS;
+ out->_lines_count = out->is_60hz ? 480 : 576;
+ out->_pixel_format = pixel_format;
+ out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ?
(WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
- data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
- risc_buffer_size = dev->_isNTSC ?
+ data_frame_size = out->is_60hz ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ;
+ risc_buffer_size = out->is_60hz ?
NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE;
- if (dev->input_filename) {
- str_length = strlen(dev->input_filename);
- dev->_filename = kmemdup(dev->input_filename, str_length + 1,
- GFP_KERNEL);
-
- if (!dev->_filename) {
- err = -ENOENT;
- goto error;
- }
- } else {
- str_length = strlen(dev->_defaultname);
- dev->_filename = kmemdup(dev->_defaultname, str_length + 1,
- GFP_KERNEL);
-
- if (!dev->_filename) {
- err = -ENOENT;
- goto error;
- }
- }
-
- /* Default if filename is empty string */
- if (strcmp(dev->_filename, "") == 0) {
- if (dev->_isNTSC) {
- dev->_filename =
- (dev->_pixel_format == PIXEL_FRMT_411) ?
- "/root/vid411.yuv" : "/root/vidtest.yuv";
- } else {
- dev->_filename =
- (dev->_pixel_format == PIXEL_FRMT_411) ?
- "/root/pal411.yuv" : "/root/pal422.yuv";
- }
- }
-
- dev->_is_running = 0;
- dev->_frame_count = 0;
- dev->_file_status = RESET_STATUS;
- dev->_lines_count = dev->_isNTSC ? 480 : 576;
- dev->_pixel_format = pixel_format;
- dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ?
+ out->_is_running = 0;
+ out->_frame_count = 0;
+ out->_file_status = RESET_STATUS;
+ out->_lines_count = out->is_60hz ? 480 : 576;
+ out->_pixel_format = pixel_format;
+ out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ?
(WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2;
+ out->curpos = 0;
+ init_waitqueue_head(&out->waitq);
err = cx25821_sram_channel_setup_upstream(dev, sram_ch,
- dev->_line_size, 0);
+ out->_line_size, 0);
/* setup fifo + format */
- cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format);
+ cx25821_set_pixelengine(chan, sram_ch, out->_pixel_format);
- dev->upstream_riscbuf_size = risc_buffer_size * 2;
- dev->upstream_databuf_size = data_frame_size * 2;
+ out->upstream_riscbuf_size = risc_buffer_size * 2;
+ out->upstream_databuf_size = data_frame_size * 2;
/* Allocating buffers and prepare RISC program */
- err = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size);
+ err = cx25821_upstream_buffer_prepare(chan, sram_ch, out->_line_size);
if (err < 0) {
pr_err("%s: Failed to set up Video upstream buffers!\n",
dev->name);
goto error;
}
- cx25821_start_video_dma_upstream(dev, sram_ch);
+ cx25821_start_video_dma_upstream(chan, sram_ch);
return 0;
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index d4de021dc844..d270819fd875 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -33,13 +33,10 @@ MODULE_AUTHOR("Hiep Huynh <hiep.huynh@conexant.com>");
MODULE_LICENSE("GPL");
static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
static unsigned int video_debug = VIDEO_DEBUG;
module_param(video_debug, int, 0644);
@@ -49,24 +46,14 @@ static unsigned int irq_debug;
module_param(irq_debug, int, 0644);
MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]");
-unsigned int vid_limit = 16;
+static unsigned int vid_limit = 16;
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
-static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num);
-
-static const struct v4l2_file_operations video_fops;
-static const struct v4l2_ioctl_ops video_ioctl_ops;
-
#define FORMAT_FLAGS_PACKED 0x01
-struct cx25821_fmt formats[] = {
+static const struct cx25821_fmt formats[] = {
{
- .name = "8 bpp, gray",
- .fourcc = V4L2_PIX_FMT_GREY,
- .depth = 8,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
.name = "4:1:1, packed, Y41P",
.fourcc = V4L2_PIX_FMT_Y41P,
.depth = 12,
@@ -76,36 +63,16 @@ struct cx25821_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "4:2:0, YUV",
- .fourcc = V4L2_PIX_FMT_YUV420,
- .depth = 12,
- .flags = FORMAT_FLAGS_PACKED,
},
};
-int cx25821_get_format_size(void)
-{
- return ARRAY_SIZE(formats);
-}
-
-struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
+static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
- if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P)
- return formats + 1;
-
for (i = 0; i < ARRAY_SIZE(formats); i++)
if (formats[i].fourcc == fourcc)
return formats + i;
-
- pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc);
return NULL;
}
@@ -144,129 +111,10 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
}
-#ifdef TUNER_FLAG
-int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm)
-{
- dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
- __func__, (unsigned int)norm, v4l2_norm_to_name(norm));
-
- dev->tvnorm = norm;
-
- /* Tell the internal A/V decoder */
- cx25821_call_all(dev, core, s_std, norm);
-
- return 0;
-}
-#endif
-
-struct video_device *cx25821_vdev_init(struct cx25821_dev *dev,
- struct pci_dev *pci,
- struct video_device *template,
- char *type)
-{
- struct video_device *vfd;
- dprintk(1, "%s()\n", __func__);
-
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type,
- cx25821_boards[dev->board].name);
- video_set_drvdata(vfd, dev);
- return vfd;
-}
-
-/*
-static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
- int i;
-
- if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- for (i = 0; i < CX25821_CTLS; i++)
- if (cx25821_ctls[i].v.id == qctrl->id)
- break;
- if (i == CX25821_CTLS) {
- *qctrl = no_ctl;
- return 0;
- }
- *qctrl = cx25821_ctls[i].v;
- return 0;
-}
-*/
-
-/* resource management */
-int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
- unsigned int bit)
-{
- dprintk(1, "%s()\n", __func__);
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->channels[fh->channel_id].resources & bit) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->channels[fh->channel_id].resources |= bit;
- dprintk(1, "res: get %d\n", bit);
- mutex_unlock(&dev->lock);
- return 1;
-}
-
-int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit)
-{
- return fh->resources & bit;
-}
-
-int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit)
-{
- return fh->dev->channels[fh->channel_id].resources & bit;
-}
-
-void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
- unsigned int bits)
-{
- BUG_ON((fh->resources & bits) != bits);
- dprintk(1, "%s()\n", __func__);
-
- mutex_lock(&dev->lock);
- fh->resources &= ~bits;
- dev->channels[fh->channel_id].resources &= ~bits;
- dprintk(1, "res: put %d\n", bits);
- mutex_unlock(&dev->lock);
-}
-
-int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input)
-{
- struct v4l2_routing route;
- memset(&route, 0, sizeof(route));
-
- dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
- __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0,
- INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3);
- dev->input = input;
-
- route.input = INPUT(input)->vmux;
-
- /* Tell the internal A/V decoder */
- cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0);
-
- return 0;
-}
-
int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
- struct sram_channel *channel)
+ const struct sram_channel *channel)
{
int tmp = 0;
@@ -293,7 +141,7 @@ int cx25821_start_video_dma(struct cx25821_dev *dev,
static int cx25821_restart_video_queue(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
- struct sram_channel *channel)
+ const struct sram_channel *channel)
{
struct cx25821_buffer *buf, *prev;
struct list_head *item;
@@ -346,8 +194,8 @@ static void cx25821_vid_timeout(unsigned long data)
{
struct cx25821_data *timeout_data = (struct cx25821_data *)data;
struct cx25821_dev *dev = timeout_data->dev;
- struct sram_channel *channel = timeout_data->channel;
- struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq;
+ const struct sram_channel *channel = timeout_data->channel;
+ struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq;
struct cx25821_buffer *buf;
unsigned long flags;
@@ -373,7 +221,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
u32 count = 0;
int handled = 0;
u32 mask;
- struct sram_channel *channel = dev->channels[chan_num].sram_channels;
+ const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
mask = cx_read(channel->int_msk);
if (0 == (status & mask))
@@ -393,7 +241,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
if (status & FLD_VID_DST_RISC1) {
spin_lock(&dev->slock);
count = cx_read(channel->gpcnt);
- cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq,
+ cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq,
count);
spin_unlock(&dev->slock);
handled++;
@@ -404,122 +252,19 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
dprintk(2, "stopper video\n");
spin_lock(&dev->slock);
cx25821_restart_video_queue(dev,
- &dev->channels[channel->i].vidq, channel);
+ &dev->channels[channel->i].dma_vidq, channel);
spin_unlock(&dev->slock);
handled++;
}
return handled;
}
-void cx25821_videoioctl_unregister(struct cx25821_dev *dev)
-{
- if (dev->ioctl_dev) {
- if (video_is_registered(dev->ioctl_dev))
- video_unregister_device(dev->ioctl_dev);
- else
- video_device_release(dev->ioctl_dev);
-
- dev->ioctl_dev = NULL;
- }
-}
-
-void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
-{
- cx_clear(PCI_INT_MSK, 1);
-
- if (dev->channels[chan_num].video_dev) {
- if (video_is_registered(dev->channels[chan_num].video_dev))
- video_unregister_device(
- dev->channels[chan_num].video_dev);
- else
- video_device_release(
- dev->channels[chan_num].video_dev);
-
- dev->channels[chan_num].video_dev = NULL;
-
- btcx_riscmem_free(dev->pci,
- &dev->channels[chan_num].vidq.stopper);
-
- pr_warn("device %d released!\n", chan_num);
- }
-
-}
-
-int cx25821_video_register(struct cx25821_dev *dev)
-{
- int err;
- int i;
-
- struct video_device cx25821_video_device = {
- .name = "cx25821-video",
- .fops = &video_fops,
- .minor = -1,
- .ioctl_ops = &video_ioctl_ops,
- .tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
- };
-
- spin_lock_init(&dev->slock);
-
- for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
- cx25821_init_controls(dev, i);
-
- cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper,
- dev->channels[i].sram_channels->dma_ctl, 0x11, 0);
-
- dev->channels[i].sram_channels = &cx25821_sram_channels[i];
- dev->channels[i].video_dev = NULL;
- dev->channels[i].resources = 0;
-
- cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff);
-
- INIT_LIST_HEAD(&dev->channels[i].vidq.active);
- INIT_LIST_HEAD(&dev->channels[i].vidq.queued);
-
- dev->channels[i].timeout_data.dev = dev;
- dev->channels[i].timeout_data.channel =
- &cx25821_sram_channels[i];
- dev->channels[i].vidq.timeout.function = cx25821_vid_timeout;
- dev->channels[i].vidq.timeout.data =
- (unsigned long)&dev->channels[i].timeout_data;
- init_timer(&dev->channels[i].vidq.timeout);
-
- /* register v4l devices */
- dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci,
- &cx25821_video_device, "video");
-
- err = video_register_device(dev->channels[i].video_dev,
- VFL_TYPE_GRABBER, video_nr[dev->nr]);
-
- if (err < 0)
- goto fail_unreg;
-
- }
-
- /* set PCI interrupt */
- cx_set(PCI_INT_MSK, 0xff);
-
- /* initial device configuration */
- mutex_lock(&dev->lock);
-#ifdef TUNER_FLAG
- dev->tvnorm = cx25821_video_device.current_norm;
- cx25821_set_tvnorm(dev, dev->tvnorm);
-#endif
- mutex_unlock(&dev->lock);
-
- return 0;
-
-fail_unreg:
- cx25821_video_unregister(dev, i);
- return err;
-}
-
-int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
unsigned int *size)
{
- struct cx25821_fh *fh = q->priv_data;
+ struct cx25821_channel *chan = q->priv_data;
- *size = fh->fmt->depth * fh->width * fh->height >> 3;
+ *size = chan->fmt->depth * chan->width * chan->height >> 3;
if (0 == *count)
*count = 32;
@@ -530,35 +275,34 @@ int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
return 0;
}
-int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
- struct cx25821_fh *fh = q->priv_data;
- struct cx25821_dev *dev = fh->dev;
+ struct cx25821_channel *chan = q->priv_data;
+ struct cx25821_dev *dev = chan->dev;
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
int rc, init_buffer = 0;
u32 line0_offset;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int bpl_local = LINE_SIZE_D1;
- int channel_opened = fh->channel_id;
- BUG_ON(NULL == fh->fmt);
- if (fh->width < 48 || fh->width > 720 ||
- fh->height < 32 || fh->height > 576)
+ BUG_ON(NULL == chan->fmt);
+ if (chan->width < 48 || chan->width > 720 ||
+ chan->height < 32 || chan->height > 576)
return -EINVAL;
- buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+ buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height || buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
+ if (buf->fmt != chan->fmt ||
+ buf->vb.width != chan->width ||
+ buf->vb.height != chan->height || buf->vb.field != field) {
+ buf->fmt = chan->fmt;
+ buf->vb.width = chan->width;
+ buf->vb.height = chan->height;
buf->vb.field = field;
init_buffer = 1;
}
@@ -575,34 +319,21 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
dprintk(1, "init_buffer=%d\n", init_buffer);
if (init_buffer) {
-
- channel_opened = dev->channel_opened;
- if (channel_opened < 0 || channel_opened > 7)
- channel_opened = 7;
-
- if (dev->channels[channel_opened].pixel_formats ==
- PIXEL_FRMT_411)
+ if (chan->pixel_formats == PIXEL_FRMT_411)
buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
else
buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
- if (dev->channels[channel_opened].pixel_formats ==
- PIXEL_FRMT_411) {
+ if (chan->pixel_formats == PIXEL_FRMT_411) {
bpl_local = buf->bpl;
} else {
bpl_local = buf->bpl; /* Default */
- if (channel_opened >= 0 && channel_opened <= 7) {
- if (dev->channels[channel_opened]
- .use_cif_resolution) {
- if (dev->tvnorm & V4L2_STD_PAL_BG ||
- dev->tvnorm & V4L2_STD_PAL_DK)
- bpl_local = 352 << 1;
- else
- bpl_local = dev->channels[
- channel_opened].
- cif_width << 1;
- }
+ if (chan->use_cif_resolution) {
+ if (dev->tvnorm & V4L2_STD_625_50)
+ bpl_local = 352 << 1;
+ else
+ bpl_local = chan->cif_width << 1;
}
}
@@ -645,8 +376,8 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
}
dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
- buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth,
- fh->fmt->name, (unsigned long)buf->risc.dma);
+ buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth,
+ chan->fmt->name, (unsigned long)buf->risc.dma);
buf->vb.state = VIDEOBUF_PREPARED;
@@ -657,7 +388,7 @@ fail:
return rc;
}
-void cx25821_buffer_release(struct videobuf_queue *q,
+static void cx25821_buffer_release(struct videobuf_queue *q,
struct videobuf_buffer *vb)
{
struct cx25821_buffer *buf =
@@ -666,33 +397,11 @@ void cx25821_buffer_release(struct videobuf_queue *q,
cx25821_free_buffer(q, buf);
}
-struct videobuf_queue *get_queue(struct cx25821_fh *fh)
+static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return &fh->vidq;
- default:
- BUG();
- return NULL;
- }
-}
+ struct cx25821_channel *chan = video_drvdata(file);
-int cx25821_get_resource(struct cx25821_fh *fh, int resource)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return resource;
- default:
- BUG();
- return 0;
- }
-}
-
-int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx25821_fh *fh = file->private_data;
-
- return videobuf_mmap_mapper(get_queue(fh), vma);
+ return videobuf_mmap_mapper(&chan->vidq, vma);
}
@@ -701,9 +410,9 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
struct cx25821_buffer *prev;
- struct cx25821_fh *fh = vq->priv_data;
- struct cx25821_dev *dev = fh->dev;
- struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq;
+ struct cx25821_channel *chan = vq->priv_data;
+ struct cx25821_dev *dev = chan->dev;
+ struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq;
/* add jump to stopper */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
@@ -720,8 +429,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
} else if (list_empty(&q->active)) {
list_add_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf,
- dev->channels[fh->channel_id].sram_channels);
+ cx25821_start_video_dma(dev, q, buf, chan->sram_channels);
buf->vb.state = VIDEOBUF_ACTIVE;
buf->count = q->count++;
mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
@@ -762,1183 +470,487 @@ static struct videobuf_queue_ops cx25821_video_qops = {
.buf_release = cx25821_buffer_release,
};
-static int video_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx25821_dev *h, *dev = video_drvdata(file);
- struct cx25821_fh *fh;
- struct list_head *list;
- int minor = video_devdata(file)->minor;
- enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- u32 pix_format;
- int ch_id = 0;
- int i;
-
- dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev),
- v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- mutex_lock(&cx25821_devlist_mutex);
-
- list_for_each(list, &cx25821_devlist)
- {
- h = list_entry(list, struct cx25821_dev, devlist);
-
- for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) {
- if (h->channels[i].video_dev &&
- h->channels[i].video_dev->minor == minor) {
- dev = h;
- ch_id = i;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
- }
- }
-
- if (NULL == dev) {
- mutex_unlock(&cx25821_devlist_mutex);
- kfree(fh);
- return -ENODEV;
- }
-
- file->private_data = fh;
- fh->dev = dev;
- fh->type = type;
- fh->width = 720;
- fh->channel_id = ch_id;
-
- if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK)
- fh->height = 576;
- else
- fh->height = 480;
-
- dev->channel_opened = fh->channel_id;
- if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411)
- pix_format = V4L2_PIX_FMT_Y41P;
- else
- pix_format = V4L2_PIX_FMT_YUYV;
- fh->fmt = cx25821_format_by_fourcc(pix_format);
-
- v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio);
-
- videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev,
- &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
- fh, NULL);
-
- dprintk(1, "post videobuf_queue_init()\n");
- mutex_unlock(&cx25821_devlist_mutex);
-
- return 0;
-}
-
static ssize_t video_read(struct file *file, char __user * data, size_t count,
loff_t *ppos)
{
- struct cx25821_fh *fh = file->private_data;
+ struct v4l2_fh *fh = file->private_data;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ int err = 0;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (cx25821_res_locked(fh, RESOURCE_VIDEO0))
- return -EBUSY;
-
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-
- default:
- BUG();
- return 0;
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ if (chan->streaming_fh && chan->streaming_fh != fh) {
+ err = -EBUSY;
+ goto unlock;
}
+ chan->streaming_fh = fh;
+
+ err = videobuf_read_one(&chan->vidq, data, count, ppos,
+ file->f_flags & O_NONBLOCK);
+unlock:
+ mutex_unlock(&dev->lock);
+ return err;
}
static unsigned int video_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_buffer *buf;
-
- if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vidq.stream.next,
- struct cx25821_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx25821_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
-
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) {
- if (buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = fh->dev;
-
- if (dev && dev->channels[fh->channel_id]
- .use_cif_resolution) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (fh->width * 2),
- (fh->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
+ struct cx25821_channel *chan = video_drvdata(file);
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int res = v4l2_ctrl_poll(file, wait);
+
+ if (req_events & (POLLIN | POLLRDNORM))
+ res |= videobuf_poll_stream(file, &chan->vidq, wait);
+ return res;
+
+ /* This doesn't belong in poll(). This can be done
+ * much better with vb2. We keep this code here as a
+ * reminder.
+ if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) {
+ struct cx25821_dev *dev = chan->dev;
+
+ if (dev && chan->use_cif_resolution) {
+ u8 cam_id = *((char *)buf->vb.baddr + 3);
+ memcpy((char *)buf->vb.baddr,
+ (char *)buf->vb.baddr + (chan->width * 2),
+ (chan->width * 2));
+ *((char *)buf->vb.baddr + 3) = cam_id;
}
-
- return POLLIN | POLLRDNORM;
}
-
- return 0;
+ */
}
static int video_release(struct file *file)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct v4l2_fh *fh = file->private_data;
+ struct cx25821_dev *dev = chan->dev;
+ const struct sram_channel *sram_ch =
+ dev->channels[0].sram_channels;
+ mutex_lock(&dev->lock);
/* stop the risc engine and fifo */
- cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */
+ cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
/* stop video capture */
- if (cx25821_res_check(fh, RESOURCE_VIDEO0)) {
- videobuf_queue_cancel(&fh->vidq);
- cx25821_res_free(dev, fh, RESOURCE_VIDEO0);
+ if (chan->streaming_fh == fh) {
+ videobuf_queue_cancel(&chan->vidq);
+ chan->streaming_fh = NULL;
}
- if (fh->vidq.read_buf) {
- cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
+ if (chan->vidq.read_buf) {
+ cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf);
+ kfree(chan->vidq.read_buf);
}
- videobuf_mmap_free(&fh->vidq);
-
- v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
+ videobuf_mmap_free(&chan->vidq);
+ mutex_unlock(&dev->lock);
- return 0;
+ return v4l2_fh_release(file);
}
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
+/* VIDEO IOCTLS */
- if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(formats)))
return -EINVAL;
- if (unlikely(i != fh->type))
- return -EINVAL;
+ strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ f->pixelformat = formats[f->index].fourcc;
- if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh,
- RESOURCE_VIDEO0))))
- return -EBUSY;
+ return 0;
+}
+
+static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx25821_channel *chan = video_drvdata(file);
- return videobuf_streamon(get_queue(fh));
+ f->fmt.pix.width = chan->width;
+ f->fmt.pix.height = chan->height;
+ f->fmt.pix.field = chan->vidq.field;
+ f->fmt.pix.pixelformat = chan->fmt->fourcc;
+ f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+
+ return 0;
}
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
- int err, res;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ const struct cx25821_fmt *fmt;
+ enum v4l2_field field = f->fmt.pix.field;
+ unsigned int maxh;
+ unsigned w;
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (i != fh->type)
+ fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
return -EINVAL;
+ maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
+
+ w = f->fmt.pix.width;
+ if (field != V4L2_FIELD_BOTTOM)
+ field = V4L2_FIELD_TOP;
+ if (w < 352) {
+ w = 176;
+ f->fmt.pix.height = maxh / 4;
+ } else if (w < 720) {
+ w = 352;
+ f->fmt.pix.height = maxh / 2;
+ } else {
+ w = 720;
+ f->fmt.pix.height = maxh;
+ field = V4L2_FIELD_INTERLACED;
+ }
+ f->fmt.pix.field = field;
+ f->fmt.pix.width = w;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
- res = cx25821_get_resource(fh, RESOURCE_VIDEO0);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- cx25821_res_free(dev, fh, res);
return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct v4l2_mbus_framefmt mbus_fmt;
- int err;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
int pix_format = PIXEL_FRMT_422;
+ int err;
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- }
-
- dprintk(2, "%s()\n", __func__);
err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f);
if (0 != err)
return err;
- fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
- fh->vidq.field = f->fmt.pix.field;
-
- /* check if width and height is valid based on set standard */
- if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm))
- fh->width = f->fmt.pix.width;
-
- if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm))
- fh->height = f->fmt.pix.height;
+ chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+ chan->vidq.field = f->fmt.pix.field;
+ chan->width = f->fmt.pix.width;
+ chan->height = f->fmt.pix.height;
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
pix_format = PIXEL_FRMT_411;
- else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
- pix_format = PIXEL_FRMT_422;
else
- return -EINVAL;
+ pix_format = PIXEL_FRMT_422;
cx25821_set_pixel_format(dev, SRAM_CH00, pix_format);
/* check if cif resolution */
- if (fh->width == 320 || fh->width == 352)
- dev->channels[fh->channel_id].use_cif_resolution = 1;
+ if (chan->width == 320 || chan->width == 352)
+ chan->use_cif_resolution = 1;
else
- dev->channels[fh->channel_id].use_cif_resolution = 0;
-
- dev->channels[fh->channel_id].cif_width = fh->width;
- medusa_set_resolution(dev, fh->width, SRAM_CH00);
-
- dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width,
- fh->height, fh->vidq.field);
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
- cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ chan->use_cif_resolution = 0;
+ chan->cif_width = chan->width;
+ medusa_set_resolution(dev, chan->width, SRAM_CH00);
return 0;
}
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
- int ret_val = 0;
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ struct cx25821_channel *chan = video_drvdata(file);
- ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK);
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
- p->sequence = dev->channels[fh->channel_id].vidq.count;
+ if (chan->streaming_fh && chan->streaming_fh != priv)
+ return -EBUSY;
+ chan->streaming_fh = priv;
- return ret_val;
+ return videobuf_streamon(&chan->vidq);
}
-static int vidioc_log_status(struct file *file, void *priv)
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct cx25821_fh *fh = priv;
- char name[32 + 2];
+ struct cx25821_channel *chan = video_drvdata(file);
- struct sram_channel *sram_ch = dev->channels[fh->channel_id]
- .sram_channels;
- u32 tmp = 0;
-
- snprintf(name, sizeof(name), "%s/2", dev->name);
- pr_info("%s/2: ============ START LOG STATUS ============\n",
- dev->name);
- cx25821_call_all(dev, core, log_status);
- tmp = cx_read(sram_ch->dma_ctl);
- pr_info("Video input 0 is %s\n",
- (tmp & 0x11) ? "streaming" : "stopped");
- pr_info("%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- }
+ if (chan->streaming_fh && chan->streaming_fh != priv)
+ return -EBUSY;
+ if (chan->streaming_fh == NULL)
+ return 0;
- return cx25821_set_control(dev, ctl, fh->channel_id);
+ chan->streaming_fh = NULL;
+ return videobuf_streamoff(&chan->vidq);
}
-/* VIDEO IOCTLS */
-int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct cx25821_fh *fh = priv;
+ int ret_val = 0;
+ struct cx25821_channel *chan = video_drvdata(file);
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK);
+ p->sequence = chan->dma_vidq.count;
- return 0;
+ return ret_val;
}
-int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int vidioc_log_status(struct file *file, void *priv)
{
- struct cx25821_fmt *fmt;
- enum v4l2_field field;
- unsigned int maxw, maxh;
-
- fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- field = f->fmt.pix.field;
- maxw = 720;
- maxh = 576;
-
- if (V4L2_FIELD_ANY == field) {
- if (f->fmt.pix.height > maxh / 2)
- field = V4L2_FIELD_INTERLACED;
- else
- field = V4L2_FIELD_TOP;
- }
-
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
-
- f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ const struct sram_channel *sram_ch = chan->sram_channels;
+ u32 tmp = 0;
+ tmp = cx_read(sram_ch->dma_ctl);
+ pr_info("Video input 0 is %s\n",
+ (tmp & 0x11) ? "streaming" : "stopped");
return 0;
}
-int cx25821_vidioc_querycap(struct file *file, void *priv,
+
+static int cx25821_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE;
strcpy(cap->driver, "cx25821");
strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
- cap->version = CX25821_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- if (UNSET != dev->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
- return 0;
-}
-
-int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (unlikely(f->index >= ARRAY_SIZE(formats)))
- return -EINVAL;
-
- strlcpy(f->description, formats[f->index].name, sizeof(f->description));
- f->pixelformat = formats[f->index].fourcc;
-
+ if (chan->id >= VID_CHANNEL_NUM)
+ cap->device_caps = cap_output;
+ else
+ cap->device_caps = cap_input;
+ cap->capabilities = cap_input | cap_output | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-int cx25821_vidioc_reqbufs(struct file *file, void *priv,
+static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
- struct cx25821_fh *fh = priv;
- return videobuf_reqbufs(get_queue(fh), p);
+ struct cx25821_channel *chan = video_drvdata(file);
+
+ return videobuf_reqbufs(&chan->vidq, p);
}
-int cx25821_vidioc_querybuf(struct file *file, void *priv,
+static int cx25821_vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct cx25821_fh *fh = priv;
- return videobuf_querybuf(get_queue(fh), p);
-}
+ struct cx25821_channel *chan = video_drvdata(file);
-int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_fh *fh = priv;
- return videobuf_qbuf(get_queue(fh), p);
+ return videobuf_querybuf(&chan->vidq, p);
}
-int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p)
+static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
- struct cx25821_fh *fh = f;
+ struct cx25821_channel *chan = video_drvdata(file);
- *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio);
-
- return 0;
+ return videobuf_qbuf(&chan->vidq, p);
}
-int cx25821_vidioc_s_priority(struct file *file, void *f,
- enum v4l2_priority prio)
+static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
- struct cx25821_fh *fh = f;
- struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev;
+ struct cx25821_channel *chan = video_drvdata(file);
- return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio,
- prio);
+ *tvnorms = chan->dev->tvnorm;
+ return 0;
}
-#ifdef TUNER_FLAG
-int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms)
+static int cx25821_vidioc_s_std(struct file *file, void *priv,
+ v4l2_std_id tvnorms)
{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- dprintk(1, "%s()\n", __func__);
-
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- }
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
- if (dev->tvnorm == *tvnorms)
+ if (dev->tvnorm == tvnorms)
return 0;
- mutex_lock(&dev->lock);
- cx25821_set_tvnorm(dev, *tvnorms);
- mutex_unlock(&dev->lock);
+ dev->tvnorm = tvnorms;
+ chan->width = 720;
+ chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
medusa_set_videostandard(dev);
return 0;
}
-#endif
-int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i)
+static int cx25821_vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
{
- static const char * const iname[] = {
- [CX25821_VMUX_COMPOSITE] = "Composite",
- [CX25821_VMUX_SVIDEO] = "S-Video",
- [CX25821_VMUX_DEBUG] = "for debug only",
- };
- unsigned int n;
- dprintk(1, "%s()\n", __func__);
-
- n = i->index;
- if (n >= 2)
- return -EINVAL;
-
- if (0 == INPUT(n)->type)
+ if (i->index)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name, iname[INPUT(n)->type]);
-
i->std = CX25821_NORMS;
+ strcpy(i->name, "Composite");
return 0;
}
-int cx25821_vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- dprintk(1, "%s()\n", __func__);
- return cx25821_enum_input(dev, i);
-}
-
-int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- *i = dev->input;
- dprintk(1, "%s(): returns %d\n", __func__, *i);
- return 0;
-}
-
-int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- int err;
-
- dprintk(1, "%s(%d)\n", __func__, i);
-
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- }
-
- if (i >= CX25821_NR_INPUT) {
- dprintk(1, "%s(): -EINVAL\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
- cx25821_video_mux(dev, i);
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-#ifdef TUNER_FLAG
-int cx25821_vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev = fh->dev;
-
- f->frequency = dev->freq;
-
- cx25821_call_all(dev, tuner, g_frequency, f);
-
- return 0;
-}
-
-int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f)
-{
- mutex_lock(&dev->lock);
- dev->freq = f->frequency;
-
- cx25821_call_all(dev, tuner, s_frequency, f);
-
- /* When changing channels it is required to reset TVAUDIO */
- msleep(10);
-
- mutex_unlock(&dev->lock);
-
- return 0;
-}
-
-int cx25821_vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct cx25821_fh *fh = priv;
- struct cx25821_dev *dev;
- int err;
-
- if (fh) {
- dev = fh->dev;
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- } else {
- pr_err("Invalid fh pointer!\n");
- return -EINVAL;
- }
-
- return cx25821_set_freq(dev, f);
-}
-#endif
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-int cx25821_vidioc_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
-
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
-
- cx25821_call_all(dev, core, g_register, reg);
-
- return 0;
-}
-
-int cx25821_vidioc_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev;
-
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
-
- cx25821_call_all(dev, core, s_register, reg);
-
+ *i = 0;
return 0;
}
-#endif
-
-#ifdef TUNER_FLAG
-int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- if (unlikely(UNSET == dev->tuner_type))
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
-
- t->signal = 0xffff; /* LOCKED */
- return 0;
+ return i ? -EINVAL : 0;
}
-int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct cx25821_fh *fh = priv;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
- }
+ struct cx25821_channel *chan =
+ container_of(ctrl->handler, struct cx25821_channel, hdl);
+ struct cx25821_dev *dev = chan->dev;
- dprintk(1, "%s()\n", __func__);
- if (UNSET == dev->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- return 0;
-}
-
-#endif
-/*****************************************************************************/
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct v4l2_queryctrl cx25821_ctls[] = {
- /* --- video --- */
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 6200,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 10000,
- .step = 1,
- .default_value = 5000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
-static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls);
-
-static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
- int i;
-
- if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- for (i = 0; i < CX25821_CTLS; i++)
- if (cx25821_ctls[i].id == qctrl->id)
- break;
- if (i == CX25821_CTLS) {
- *qctrl = no_ctl;
- return 0;
- }
- *qctrl = cx25821_ctls[i];
- return 0;
-}
-
-int cx25821_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl)
-{
- return cx25821_ctrl_query(qctrl);
-}
-
-/* ------------------------------------------------------------------ */
-/* VIDEO CTRL IOCTLS */
-
-static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id)
-{
- unsigned int i;
-
- for (i = 0; i < CX25821_CTLS; i++)
- if (cx25821_ctls[i].id == id)
- return cx25821_ctls + i;
- return NULL;
-}
-
-int cx25821_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct cx25821_fh *fh = priv;
-
- const struct v4l2_queryctrl *ctrl;
-
- ctrl = ctrl_by_id(ctl->id);
-
- if (NULL == ctrl)
- return -EINVAL;
- switch (ctl->id) {
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctl->value = dev->channels[fh->channel_id].ctl_bright;
+ medusa_set_brightness(dev, ctrl->val, chan->id);
break;
case V4L2_CID_HUE:
- ctl->value = dev->channels[fh->channel_id].ctl_hue;
+ medusa_set_hue(dev, ctrl->val, chan->id);
break;
case V4L2_CID_CONTRAST:
- ctl->value = dev->channels[fh->channel_id].ctl_contrast;
+ medusa_set_contrast(dev, ctrl->val, chan->id);
break;
case V4L2_CID_SATURATION:
- ctl->value = dev->channels[fh->channel_id].ctl_saturation;
- break;
- }
- return 0;
-}
-
-int cx25821_set_control(struct cx25821_dev *dev,
- struct v4l2_control *ctl, int chan_num)
-{
- int err;
- const struct v4l2_queryctrl *ctrl;
-
- err = -EINVAL;
-
- ctrl = ctrl_by_id(ctl->id);
-
- if (NULL == ctrl)
- return err;
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER:
- if (ctl->value < ctrl->minimum)
- ctl->value = ctrl->minimum;
- if (ctl->value > ctrl->maximum)
- ctl->value = ctrl->maximum;
+ medusa_set_saturation(dev, ctrl->val, chan->id);
break;
default:
- /* nothing */ ;
- }
-
- switch (ctl->id) {
- case V4L2_CID_BRIGHTNESS:
- dev->channels[chan_num].ctl_bright = ctl->value;
- medusa_set_brightness(dev, ctl->value, chan_num);
- break;
- case V4L2_CID_HUE:
- dev->channels[chan_num].ctl_hue = ctl->value;
- medusa_set_hue(dev, ctl->value, chan_num);
- break;
- case V4L2_CID_CONTRAST:
- dev->channels[chan_num].ctl_contrast = ctl->value;
- medusa_set_contrast(dev, ctl->value, chan_num);
- break;
- case V4L2_CID_SATURATION:
- dev->channels[chan_num].ctl_saturation = ctl->value;
- medusa_set_saturation(dev, ctl->value, chan_num);
- break;
- }
-
- err = 0;
-
- return err;
-}
-
-static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num)
-{
- struct v4l2_control ctrl;
- int i;
- for (i = 0; i < CX25821_CTLS; i++) {
- ctrl.id = cx25821_ctls[i].id;
- ctrl.value = cx25821_ctls[i].default_value;
-
- cx25821_set_control(dev, &ctrl, chan_num);
- }
-}
-
-int cx25821_vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cropcap)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
-
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cropcap->bounds.top = 0;
- cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480;
- cropcap->pixelaspect.numerator =
- dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10;
- cropcap->pixelaspect.denominator =
- dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11;
- cropcap->defrect = cropcap->bounds;
- return 0;
-}
-
-int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop)
-{
- struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev;
- struct cx25821_fh *fh = priv;
- int err;
-
- if (fh) {
- err = v4l2_prio_check(&dev->channels[fh->channel_id].prio,
- fh->prio);
- if (0 != err)
- return err;
}
- /* cx25821_vidioc_s_crop not supported */
- return -EINVAL;
-}
-
-int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
-{
- /* cx25821_vidioc_g_crop not supported */
- return -EINVAL;
+ return 0;
}
-int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm)
+static int cx25821_vidioc_enum_output(struct file *file, void *priv,
+ struct v4l2_output *o)
{
- /* medusa does not support video standard sensing of current input */
- *norm = CX25821_NORMS;
+ if (o->index)
+ return -EINVAL;
+ o->type = V4L2_INPUT_TYPE_CAMERA;
+ o->std = CX25821_NORMS;
+ strcpy(o->name, "Composite");
return 0;
}
-int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm)
+static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o)
{
- if (tvnorm == V4L2_STD_PAL_BG) {
- if (width == 352 || width == 720)
- return 1;
- else
- return 0;
- }
-
- if (tvnorm == V4L2_STD_NTSC_M) {
- if (width == 320 || width == 352 || width == 720)
- return 1;
- else
- return 0;
- }
+ *o = 0;
return 0;
}
-int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm)
+static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o)
{
- if (tvnorm == V4L2_STD_PAL_BG) {
- if (height == 576 || height == 288)
- return 1;
- else
- return 0;
- }
-
- if (tvnorm == V4L2_STD_NTSC_M) {
- if (height == 480 || height == 240)
- return 1;
- else
- return 0;
- }
-
- return 0;
+ return o ? -EINVAL : 0;
}
-static long video_ioctl_upstream9(struct file *file, unsigned int cmd,
- unsigned long arg)
+static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
-
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
- return 0;
-
- dev->input_filename = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname = data_from_user->vid_stdname;
- dev->pixel_format = data_from_user->pixel_format;
- dev->channel_select = data_from_user->channel_select;
- dev->command = data_from_user->command;
-
- switch (command) {
- case UPSTREAM_START_VIDEO:
- cx25821_start_upstream_video_ch1(dev, data_from_user);
- break;
-
- case UPSTREAM_STOP_VIDEO:
- cx25821_stop_upstream_video_ch1(dev);
- break;
- }
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ const struct cx25821_fmt *fmt;
+ fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+ f->fmt.pix.width = 720;
+ f->fmt.pix.height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
return 0;
}
-static long video_ioctl_upstream10(struct file *file, unsigned int cmd,
- unsigned long arg)
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
-
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO)
- return 0;
-
- dev->input_filename_ch2 = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname_ch2 = data_from_user->vid_stdname;
- dev->pixel_format_ch2 = data_from_user->pixel_format;
- dev->channel_select_ch2 = data_from_user->channel_select;
- dev->command_ch2 = data_from_user->command;
+ struct cx25821_channel *chan = video_drvdata(file);
+ int err;
- switch (command) {
- case UPSTREAM_START_VIDEO:
- cx25821_start_upstream_video_ch2(dev, data_from_user);
- break;
+ err = cx25821_vidioc_try_fmt_vid_out(file, priv, f);
- case UPSTREAM_STOP_VIDEO:
- cx25821_stop_upstream_video_ch2(dev);
- break;
- }
+ if (0 != err)
+ return err;
+ chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
+ chan->vidq.field = f->fmt.pix.field;
+ chan->width = f->fmt.pix.width;
+ chan->height = f->fmt.pix.height;
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
+ chan->pixel_formats = PIXEL_FRMT_411;
+ else
+ chan->pixel_formats = PIXEL_FRMT_422;
return 0;
}
-static long video_ioctl_upstream11(struct file *file, unsigned int cmd,
- unsigned long arg)
+static ssize_t video_write(struct file *file, const char __user *data, size_t count,
+ loff_t *ppos)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- int command = 0;
- struct upstream_user_struct *data_from_user;
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ struct v4l2_fh *fh = file->private_data;
+ int err = 0;
- data_from_user = (struct upstream_user_struct *)arg;
-
- if (!data_from_user) {
- pr_err("%s(): Upstream data is INVALID. Returning\n", __func__);
- return 0;
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ if (chan->streaming_fh && chan->streaming_fh != fh) {
+ err = -EBUSY;
+ goto unlock;
}
-
- command = data_from_user->command;
-
- if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO)
- return 0;
-
- dev->input_filename = data_from_user->input_filename;
- dev->input_audiofilename = data_from_user->input_filename;
- dev->vid_stdname = data_from_user->vid_stdname;
- dev->pixel_format = data_from_user->pixel_format;
- dev->channel_select = data_from_user->channel_select;
- dev->command = data_from_user->command;
-
- switch (command) {
- case UPSTREAM_START_AUDIO:
- cx25821_start_upstream_audio(dev, data_from_user);
- break;
-
- case UPSTREAM_STOP_AUDIO:
- cx25821_stop_upstream_audio(dev);
- break;
+ if (!chan->streaming_fh) {
+ err = cx25821_vidupstream_init(chan, chan->pixel_formats);
+ if (err)
+ goto unlock;
+ chan->streaming_fh = fh;
}
- return 0;
+ err = cx25821_write_frame(chan, data, count);
+ count -= err;
+ *ppos += err;
+
+unlock:
+ mutex_unlock(&dev->lock);
+ return err;
}
-static long video_ioctl_set(struct file *file, unsigned int cmd,
- unsigned long arg)
+static int video_out_release(struct file *file)
{
- struct cx25821_fh *fh = file->private_data;
- struct cx25821_dev *dev = fh->dev;
- struct downstream_user_struct *data_from_user;
- int command;
- int width = 720;
- int selected_channel = 0;
- int pix_format = 0;
- int i = 0;
- int cif_enable = 0;
- int cif_width = 0;
-
- data_from_user = (struct downstream_user_struct *)arg;
-
- if (!data_from_user) {
- pr_err("%s(): User data is INVALID. Returning\n", __func__);
- return 0;
- }
-
- command = data_from_user->command;
-
- if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT
- && command != ENABLE_CIF_RESOLUTION && command != REG_READ
- && command != REG_WRITE && command != MEDUSA_READ
- && command != MEDUSA_WRITE) {
- return 0;
- }
-
- switch (command) {
- case SET_VIDEO_STD:
- if (!strcmp(data_from_user->vid_stdname, "PAL"))
- dev->tvnorm = V4L2_STD_PAL_BG;
- else
- dev->tvnorm = V4L2_STD_NTSC_M;
- medusa_set_videostandard(dev);
- break;
-
- case SET_PIXEL_FORMAT:
- selected_channel = data_from_user->decoder_select;
- pix_format = data_from_user->pixel_format;
-
- if (!(selected_channel <= 7 && selected_channel >= 0)) {
- selected_channel -= 4;
- selected_channel = selected_channel % 8;
- }
-
- if (selected_channel >= 0)
- cx25821_set_pixel_format(dev, selected_channel,
- pix_format);
-
- break;
-
- case ENABLE_CIF_RESOLUTION:
- selected_channel = data_from_user->decoder_select;
- cif_enable = data_from_user->cif_resolution_enable;
- cif_width = data_from_user->cif_width;
-
- if (cif_enable) {
- if (dev->tvnorm & V4L2_STD_PAL_BG
- || dev->tvnorm & V4L2_STD_PAL_DK) {
- width = 352;
- } else {
- width = cif_width;
- if (cif_width != 320 && cif_width != 352)
- width = 320;
- }
- }
-
- if (!(selected_channel <= 7 && selected_channel >= 0)) {
- selected_channel -= 4;
- selected_channel = selected_channel % 8;
- }
+ struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_dev *dev = chan->dev;
+ struct v4l2_fh *fh = file->private_data;
- if (selected_channel <= 7 && selected_channel >= 0) {
- dev->channels[selected_channel].use_cif_resolution =
- cif_enable;
- dev->channels[selected_channel].cif_width = width;
- } else {
- for (i = 0; i < VID_CHANNEL_NUM; i++) {
- dev->channels[i].use_cif_resolution =
- cif_enable;
- dev->channels[i].cif_width = width;
- }
- }
-
- medusa_set_resolution(dev, width, selected_channel);
- break;
- case REG_READ:
- data_from_user->reg_data = cx_read(data_from_user->reg_address);
- break;
- case REG_WRITE:
- cx_write(data_from_user->reg_address, data_from_user->reg_data);
- break;
- case MEDUSA_READ:
- cx25821_i2c_read(&dev->i2c_bus[0],
- (u16) data_from_user->reg_address,
- &data_from_user->reg_data);
- break;
- case MEDUSA_WRITE:
- cx25821_i2c_write(&dev->i2c_bus[0],
- (u16) data_from_user->reg_address,
- data_from_user->reg_data);
- break;
+ mutex_lock(&dev->lock);
+ if (chan->streaming_fh == fh) {
+ cx25821_stop_upstream_video(chan);
+ chan->streaming_fh = NULL;
}
+ mutex_unlock(&dev->lock);
- return 0;
+ return v4l2_fh_release(file);
}
-static long cx25821_video_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
-
- struct cx25821_fh *fh = file->private_data;
-
- /* check to see if it's the video upstream */
- if (fh->channel_id == SRAM_CH09) {
- ret = video_ioctl_upstream9(file, cmd, arg);
- return ret;
- } else if (fh->channel_id == SRAM_CH10) {
- ret = video_ioctl_upstream10(file, cmd, arg);
- return ret;
- } else if (fh->channel_id == SRAM_CH11) {
- ret = video_ioctl_upstream11(file, cmd, arg);
- ret = video_ioctl_set(file, cmd, arg);
- return ret;
- }
-
- return video_ioctl2(file, cmd, arg);
-}
+static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
+ .s_ctrl = cx25821_s_ctrl,
+};
-/* exported stuff */
static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
- .open = video_open,
+ .open = v4l2_fh_open,
.release = video_release,
.read = video_read,
.poll = video_poll,
.mmap = cx25821_video_mmap,
- .ioctl = cx25821_video_ioctl,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1951,40 +963,170 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_querybuf = cx25821_vidioc_querybuf,
.vidioc_qbuf = cx25821_vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
-#ifdef TUNER_FLAG
+ .vidioc_g_std = cx25821_vidioc_g_std,
.vidioc_s_std = cx25821_vidioc_s_std,
- .vidioc_querystd = cx25821_vidioc_querystd,
-#endif
- .vidioc_cropcap = cx25821_vidioc_cropcap,
- .vidioc_s_crop = cx25821_vidioc_s_crop,
- .vidioc_g_crop = cx25821_vidioc_g_crop,
.vidioc_enum_input = cx25821_vidioc_enum_input,
.vidioc_g_input = cx25821_vidioc_g_input,
.vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_g_ctrl = cx25821_vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_queryctrl = cx25821_vidioc_queryctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_log_status = vidioc_log_status,
- .vidioc_g_priority = cx25821_vidioc_g_priority,
- .vidioc_s_priority = cx25821_vidioc_s_priority,
-#ifdef TUNER_FLAG
- .vidioc_g_tuner = cx25821_vidioc_g_tuner,
- .vidioc_s_tuner = cx25821_vidioc_s_tuner,
- .vidioc_g_frequency = cx25821_vidioc_g_frequency,
- .vidioc_s_frequency = cx25821_vidioc_s_frequency,
-#endif
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = cx25821_vidioc_g_register,
- .vidioc_s_register = cx25821_vidioc_s_register,
-#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-struct video_device cx25821_videoioctl_template = {
- .name = "cx25821-videoioctl",
+static const struct video_device cx25821_video_device = {
+ .name = "cx25821-video",
.fops = &video_fops,
+ .release = video_device_release_empty,
+ .minor = -1,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = CX25821_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
};
+
+static const struct v4l2_file_operations video_out_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .write = video_write,
+ .release = video_out_release,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
+ .vidioc_querycap = cx25821_vidioc_querycap,
+ .vidioc_enum_fmt_vid_out = cx25821_vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out = cx25821_vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out = cx25821_vidioc_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
+ .vidioc_g_std = cx25821_vidioc_g_std,
+ .vidioc_s_std = cx25821_vidioc_s_std,
+ .vidioc_enum_output = cx25821_vidioc_enum_output,
+ .vidioc_g_output = cx25821_vidioc_g_output,
+ .vidioc_s_output = cx25821_vidioc_s_output,
+ .vidioc_log_status = vidioc_log_status,
+};
+
+static const struct video_device cx25821_video_out_device = {
+ .name = "cx25821-video",
+ .fops = &video_out_fops,
+ .release = video_device_release_empty,
+ .minor = -1,
+ .ioctl_ops = &video_out_ioctl_ops,
+ .tvnorms = CX25821_NORMS,
+};
+
+void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
+{
+ cx_clear(PCI_INT_MSK, 1);
+
+ if (video_is_registered(&dev->channels[chan_num].vdev)) {
+ video_unregister_device(&dev->channels[chan_num].vdev);
+ v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
+
+ btcx_riscmem_free(dev->pci,
+ &dev->channels[chan_num].dma_vidq.stopper);
+ }
+}
+
+int cx25821_video_register(struct cx25821_dev *dev)
+{
+ int err;
+ int i;
+
+ /* initial device configuration */
+ dev->tvnorm = V4L2_STD_NTSC_M;
+
+ spin_lock_init(&dev->slock);
+
+ for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+ struct cx25821_channel *chan = &dev->channels[i];
+ struct video_device *vdev = &chan->vdev;
+ struct v4l2_ctrl_handler *hdl = &chan->hdl;
+ bool is_output = i > SRAM_CH08;
+
+ if (i == SRAM_CH08) /* audio channel */
+ continue;
+
+ if (!is_output) {
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200);
+ v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 10000, 1, 5000);
+ v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 10000, 1, 5000);
+ v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops,
+ V4L2_CID_HUE, 0, 10000, 1, 5000);
+ if (hdl->error) {
+ err = hdl->error;
+ goto fail_unreg;
+ }
+ err = v4l2_ctrl_handler_setup(hdl);
+ if (err)
+ goto fail_unreg;
+ } else {
+ chan->out = &dev->vid_out_data[i - SRAM_CH09];
+ chan->out->chan = chan;
+ }
+
+ cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
+ chan->sram_channels->dma_ctl, 0x11, 0);
+
+ chan->sram_channels = &cx25821_sram_channels[i];
+ chan->width = 720;
+ if (dev->tvnorm & V4L2_STD_625_50)
+ chan->height = 576;
+ else
+ chan->height = 480;
+
+ if (chan->pixel_formats == PIXEL_FRMT_411)
+ chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P);
+ else
+ chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV);
+
+ cx_write(chan->sram_channels->int_stat, 0xffffffff);
+
+ INIT_LIST_HEAD(&chan->dma_vidq.active);
+ INIT_LIST_HEAD(&chan->dma_vidq.queued);
+
+ chan->timeout_data.dev = dev;
+ chan->timeout_data.channel = &cx25821_sram_channels[i];
+ chan->dma_vidq.timeout.function = cx25821_vid_timeout;
+ chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
+ init_timer(&chan->dma_vidq.timeout);
+
+ if (!is_output)
+ videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
+ &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
+ chan, &dev->lock);
+
+ /* register v4l devices */
+ *vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
+ vdev->v4l2_dev = &dev->v4l2_dev;
+ if (!is_output)
+ vdev->ctrl_handler = hdl;
+ else
+ vdev->vfl_dir = VFL_DIR_TX;
+ vdev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
+ snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
+ video_set_drvdata(vdev, chan);
+
+ err = video_register_device(vdev, VFL_TYPE_GRABBER,
+ video_nr[dev->nr]);
+
+ if (err < 0)
+ goto fail_unreg;
+ }
+
+ /* set PCI interrupt */
+ cx_set(PCI_INT_MSK, 0xff);
+
+ return 0;
+
+fail_unreg:
+ while (i >= 0)
+ cx25821_video_unregister(dev, i--);
+ return err;
+}
diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h
index c265e35b37c3..ab63b3858acf 100644
--- a/drivers/media/pci/cx25821/cx25821-video.h
+++ b/drivers/media/pci/cx25821/cx25821-video.h
@@ -39,8 +39,7 @@
#include "cx25821.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-
-#define TUNER_FLAG
+#include <media/v4l2-event.h>
#define VIDEO_DEBUG 0
@@ -50,137 +49,17 @@ do { \
printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \
} while (0)
-/* For IOCTL to identify running upstream */
-#define UPSTREAM_START_VIDEO 700
-#define UPSTREAM_STOP_VIDEO 701
-#define UPSTREAM_START_AUDIO 702
-#define UPSTREAM_STOP_AUDIO 703
-#define UPSTREAM_DUMP_REGISTERS 702
-#define SET_VIDEO_STD 800
-#define SET_PIXEL_FORMAT 1000
-#define ENABLE_CIF_RESOLUTION 1001
-
-#define REG_READ 900
-#define REG_WRITE 901
-#define MEDUSA_READ 910
-#define MEDUSA_WRITE 911
-
-extern struct sram_channel *channel0;
-extern struct sram_channel *channel1;
-extern struct sram_channel *channel2;
-extern struct sram_channel *channel3;
-extern struct sram_channel *channel4;
-extern struct sram_channel *channel5;
-extern struct sram_channel *channel6;
-extern struct sram_channel *channel7;
-extern struct sram_channel *channel9;
-extern struct sram_channel *channel10;
-extern struct sram_channel *channel11;
-extern struct video_device cx25821_videoioctl_template;
-/* extern const u32 *ctrl_classes[]; */
-
-extern unsigned int vid_limit;
-
#define FORMAT_FLAGS_PACKED 0x01
-extern struct cx25821_fmt formats[];
-extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
-extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
-
extern void cx25821_video_wakeup(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q, u32 count);
-#ifdef TUNER_FLAG
-extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm);
-#endif
-
-extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh,
- unsigned int bit);
-extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit);
-extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit);
-extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh,
- unsigned int bits);
-extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input);
extern int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
- struct sram_channel *channel);
+ const struct sram_channel *channel);
-extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width,
- unsigned int height, enum v4l2_field field);
extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status);
extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num);
extern int cx25821_video_register(struct cx25821_dev *dev);
-extern int cx25821_get_format_size(void);
-
-extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size);
-extern int cx25821_buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field);
-extern void cx25821_buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb);
-extern struct videobuf_queue *get_queue(struct cx25821_fh *fh);
-extern int cx25821_get_resource(struct cx25821_fh *fh, int resource);
-extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma);
-extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f);
-extern int cx25821_vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap);
-extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f);
-extern int cx25821_vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p);
-extern int cx25821_vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p);
-extern int cx25821_vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p);
-extern int cx25821_vidioc_s_std(struct file *file, void *priv,
- v4l2_std_id *tvnorms);
-extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i);
-extern int cx25821_vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i);
-extern int cx25821_vidioc_g_input(struct file *file, void *priv,
- unsigned int *i);
-extern int cx25821_vidioc_s_input(struct file *file, void *priv,
- unsigned int i);
-extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl);
-extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f);
-extern int cx25821_vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f);
-extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f);
-extern int cx25821_vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f);
-extern int cx25821_vidioc_g_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg);
-extern int cx25821_vidioc_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg);
-extern int cx25821_vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t);
-extern int cx25821_vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t);
-
-extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm);
-extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm);
-
-extern int cx25821_vidioc_g_priority(struct file *file, void *f,
- enum v4l2_priority *p);
-extern int cx25821_vidioc_s_priority(struct file *file, void *f,
- enum v4l2_priority prio);
-
-extern int cx25821_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl);
-extern int cx25821_set_control(struct cx25821_dev *dev,
- struct v4l2_control *ctrl, int chan_num);
-
-extern int cx25821_vidioc_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cropcap);
-extern int cx25821_vidioc_s_crop(struct file *file, void *priv,
- const struct v4l2_crop *crop);
-extern int cx25821_vidioc_g_crop(struct file *file, void *priv,
- struct v4l2_crop *crop);
-extern int cx25821_vidioc_querystd(struct file *file, void *priv,
- v4l2_std_id *norm);
#endif
diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h
index 8a9c0c869412..90bdc196929f 100644
--- a/drivers/media/pci/cx25821/cx25821.h
+++ b/drivers/media/pci/cx25821/cx25821.h
@@ -33,17 +33,14 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
-#include <media/tuner.h>
-#include <media/tveeprom.h>
+#include <media/v4l2-ctrls.h>
#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
#include "btcx-risc.h"
#include "cx25821-reg.h"
#include "cx25821-medusa-reg.h"
#include "cx25821-sram.h"
#include "cx25821-audio.h"
-#include "media/cx2341x.h"
#include <linux/version.h>
#include <linux/mutex.h>
@@ -55,8 +52,6 @@
#define CX25821_MAXBOARDS 2
-#define TRUE 1
-#define FALSE 0
#define LINE_SIZE_D1 1440
/* Number of decoders and encoders */
@@ -67,7 +62,6 @@
/* Max number of inputs by card */
#define MAX_CX25821_INPUT 8
-#define INPUT(nr) (&cx25821_boards[dev->board].input[nr])
#define RESOURCE_VIDEO0 1
#define RESOURCE_VIDEO1 2
#define RESOURCE_VIDEO2 4
@@ -80,7 +74,6 @@
#define RESOURCE_VIDEO9 512
#define RESOURCE_VIDEO10 1024
#define RESOURCE_VIDEO11 2048
-#define RESOURCE_VIDEO_IOCTL 4096
#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
@@ -97,7 +90,6 @@
#define CX25821_BOARD_CONEXANT_ATHENA10 1
#define MAX_VID_CHANNEL_NUM 12
#define VID_CHANNEL_NUM 8
-#define CX25821_NR_INPUT 2
struct cx25821_fmt {
char *name;
@@ -107,14 +99,6 @@ struct cx25821_fmt {
u32 cxformat;
};
-struct cx25821_ctrl {
- struct v4l2_queryctrl v;
- u32 off;
- u32 reg;
- u32 mask;
- u32 shift;
-};
-
struct cx25821_tvnorm {
char *name;
v4l2_std_id id;
@@ -122,40 +106,6 @@ struct cx25821_tvnorm {
u32 cxoformat;
};
-struct cx25821_fh {
- struct cx25821_dev *dev;
- enum v4l2_buf_type type;
- int radio;
- u32 resources;
-
- enum v4l2_priority prio;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip *clips;
- unsigned int nclips;
-
- /* video capture */
- struct cx25821_fmt *fmt;
- unsigned int width, height;
- int channel_id;
-
- /* vbi capture */
- struct videobuf_queue vidq;
- struct videobuf_queue vbiq;
-
- /* H264 Encoder specifics ONLY */
- struct videobuf_queue mpegq;
- atomic_t v4l_reading;
-};
-
-enum cx25821_itype {
- CX25821_VMUX_COMPOSITE = 1,
- CX25821_VMUX_SVIDEO,
- CX25821_VMUX_DEBUG,
- CX25821_RADIO,
-};
-
enum cx25821_src_sel_type {
CX25821_SRC_SEL_EXT_656_VIDEO = 0,
CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO
@@ -169,16 +119,10 @@ struct cx25821_buffer {
/* cx25821 specific */
unsigned int bpl;
struct btcx_riscmem risc;
- struct cx25821_fmt *fmt;
+ const struct cx25821_fmt *fmt;
u32 count;
};
-struct cx25821_input {
- enum cx25821_itype type;
- unsigned int vmux;
- u32 gpio0, gpio1, gpio2, gpio3;
-};
-
enum port {
CX25821_UNDEFINED = 0,
CX25821_RAW,
@@ -190,19 +134,8 @@ struct cx25821_board {
enum port porta;
enum port portb;
enum port portc;
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
u32 clk_freq;
- struct cx25821_input input[CX25821_NR_INPUT];
-};
-
-struct cx25821_subid {
- u16 subvendor;
- u16 subdevice;
- u32 card;
};
struct cx25821_i2c {
@@ -234,34 +167,70 @@ struct cx25821_dmaqueue {
struct cx25821_data {
struct cx25821_dev *dev;
- struct sram_channel *channel;
+ const struct sram_channel *channel;
+};
+
+struct cx25821_dev;
+
+struct cx25821_channel;
+
+struct cx25821_video_out_data {
+ struct cx25821_channel *chan;
+ int _line_size;
+ int _prog_cnt;
+ int _pixel_format;
+ int _is_first_frame;
+ int _is_running;
+ int _file_status;
+ int _lines_count;
+ int _frame_count;
+ unsigned int _risc_size;
+
+ __le32 *_dma_virt_start_addr;
+ __le32 *_dma_virt_addr;
+ dma_addr_t _dma_phys_addr;
+ dma_addr_t _dma_phys_start_addr;
+
+ unsigned int _data_buf_size;
+ __le32 *_data_buf_virt_addr;
+ dma_addr_t _data_buf_phys_addr;
+
+ u32 upstream_riscbuf_size;
+ u32 upstream_databuf_size;
+ int is_60hz;
+ int _frame_index;
+ int cur_frame_index;
+ int curpos;
+ wait_queue_head_t waitq;
};
struct cx25821_channel {
- struct v4l2_prio_state prio;
+ unsigned id;
+ struct cx25821_dev *dev;
+ struct v4l2_fh *streaming_fh;
- int ctl_bright;
- int ctl_contrast;
- int ctl_hue;
- int ctl_saturation;
+ struct v4l2_ctrl_handler hdl;
struct cx25821_data timeout_data;
- struct video_device *video_dev;
- struct cx25821_dmaqueue vidq;
-
- struct sram_channel *sram_channels;
+ struct video_device vdev;
+ struct cx25821_dmaqueue dma_vidq;
+ struct videobuf_queue vidq;
- struct mutex lock;
- int resources;
+ const struct sram_channel *sram_channels;
+ const struct cx25821_fmt *fmt;
+ unsigned int width, height;
int pixel_formats;
int use_cif_resolution;
int cif_width;
+
+ /* video output data for the video output channel */
+ struct cx25821_video_out_data *out;
};
+struct snd_card;
+
struct cx25821_dev {
- struct list_head devlist;
- atomic_t refcount;
struct v4l2_device v4l2_dev;
/* pci stuff */
@@ -273,6 +242,8 @@ struct cx25821_dev {
u8 __iomem *bmmio;
int pci_irqmask;
int hwrevision;
+ /* used by cx25821-alsa */
+ struct snd_card *card;
u32 clk_freq;
@@ -289,17 +260,8 @@ struct cx25821_dev {
char name[32];
/* Analog video */
- u32 resources;
unsigned int input;
- u32 tvaudio;
v4l2_std_id tvnorm;
- unsigned int tuner_type;
- unsigned char tuner_addr;
- unsigned int radio_type;
- unsigned char radio_addr;
- unsigned int has_radio;
- unsigned int videc_type;
- unsigned char videc_addr;
unsigned short _max_num_decoders;
/* Analog Audio Upstream */
@@ -323,132 +285,26 @@ struct cx25821_dev {
__le32 *_audiodata_buf_virt_addr;
dma_addr_t _audiodata_buf_phys_addr;
char *_audiofilename;
-
- /* V4l */
- u32 freq;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
- struct video_device *ioctl_dev;
-
- spinlock_t slock;
-
- /* Video Upstream */
- int _line_size;
- int _prog_cnt;
- int _pixel_format;
- int _is_first_frame;
- int _is_running;
- int _file_status;
- int _lines_count;
- int _frame_count;
- int _channel_upstream_select;
- unsigned int _risc_size;
-
- __le32 *_dma_virt_start_addr;
- __le32 *_dma_virt_addr;
- dma_addr_t _dma_phys_addr;
- dma_addr_t _dma_phys_start_addr;
-
- unsigned int _data_buf_size;
- __le32 *_data_buf_virt_addr;
- dma_addr_t _data_buf_phys_addr;
- char *_filename;
- char *_defaultname;
-
- int _line_size_ch2;
- int _prog_cnt_ch2;
- int _pixel_format_ch2;
- int _is_first_frame_ch2;
- int _is_running_ch2;
- int _file_status_ch2;
- int _lines_count_ch2;
- int _frame_count_ch2;
- int _channel2_upstream_select;
- unsigned int _risc_size_ch2;
-
- __le32 *_dma_virt_start_addr_ch2;
- __le32 *_dma_virt_addr_ch2;
- dma_addr_t _dma_phys_addr_ch2;
- dma_addr_t _dma_phys_start_addr_ch2;
-
- unsigned int _data_buf_size_ch2;
- __le32 *_data_buf_virt_addr_ch2;
- dma_addr_t _data_buf_phys_addr_ch2;
- char *_filename_ch2;
- char *_defaultname_ch2;
-
- /* MPEG Encoder ONLY settings */
- u32 cx23417_mailbox;
- struct cx2341x_mpeg_params mpeg_params;
- struct video_device *v4l_device;
- atomic_t v4l_reader_count;
- struct cx25821_tvnorm encodernorm;
-
- u32 upstream_riscbuf_size;
- u32 upstream_databuf_size;
- u32 upstream_riscbuf_size_ch2;
- u32 upstream_databuf_size_ch2;
u32 audio_upstream_riscbuf_size;
u32 audio_upstream_databuf_size;
- int _isNTSC;
- int _frame_index;
int _audioframe_index;
- struct workqueue_struct *_irq_queues;
- struct work_struct _irq_work_entry;
- struct workqueue_struct *_irq_queues_ch2;
- struct work_struct _irq_work_entry_ch2;
struct workqueue_struct *_irq_audio_queues;
struct work_struct _audio_work_entry;
- char *input_filename;
- char *input_filename_ch2;
- int _frame_index_ch2;
- int _isNTSC_ch2;
- char *vid_stdname_ch2;
- int pixel_format_ch2;
- int channel_select_ch2;
- int command_ch2;
char *input_audiofilename;
- char *vid_stdname;
- int pixel_format;
- int channel_select;
- int command;
- int channel_opened;
-};
-struct upstream_user_struct {
- char *input_filename;
- char *vid_stdname;
- int pixel_format;
- int channel_select;
- int command;
-};
+ /* V4l */
+ spinlock_t slock;
-struct downstream_user_struct {
- char *vid_stdname;
- int pixel_format;
- int cif_resolution_enable;
- int cif_width;
- int decoder_select;
- int command;
- int reg_address;
- int reg_data;
+ /* Video Upstream */
+ struct cx25821_video_out_data vid_out_data[2];
};
-extern struct upstream_user_struct *up_data;
-
static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev)
{
return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev);
}
-#define cx25821_call_all(dev, o, f, args...) \
- v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
-
-extern struct list_head cx25821_devlist;
-extern struct mutex cx25821_devlist_mutex;
-
extern struct cx25821_board cx25821_boards[];
-extern struct cx25821_subid cx25821_subids[];
#define SRAM_CH00 0 /* Video A */
#define SRAM_CH01 1 /* Video B */
@@ -467,7 +323,6 @@ extern struct cx25821_subid cx25821_subids[];
#define VID_UPSTREAM_SRAM_CHANNEL_I SRAM_CH09
#define VID_UPSTREAM_SRAM_CHANNEL_J SRAM_CH10
#define AUDIO_UPSTREAM_SRAM_CHANNEL_B SRAM_CH11
-#define VIDEO_IOCTL_CH 11
struct sram_channel {
char *name;
@@ -503,10 +358,8 @@ struct sram_channel {
u32 jumponly;
u32 irq_bit;
};
-extern struct sram_channel cx25821_sram_channels[];
-#define STATUS_SUCCESS 0
-#define STATUS_UNSUCCESSFUL -1
+extern const struct sram_channel cx25821_sram_channels[];
#define cx_read(reg) readl(dev->lmmio + ((reg)>>2))
#define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2))
@@ -529,8 +382,6 @@ extern struct sram_channel cx25821_sram_channels[];
pr_info("(%d): " fmt, dev->board, ##args)
extern int cx25821_i2c_register(struct cx25821_i2c *bus);
-extern void cx25821_card_setup(struct cx25821_dev *dev);
-extern int cx25821_ir_init(struct cx25821_dev *dev);
extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value);
extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value);
extern int cx25821_i2c_unregister(struct cx25821_i2c *bus);
@@ -551,7 +402,7 @@ extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation,
int decoder);
extern int cx25821_sram_channel_setup(struct cx25821_dev *dev,
- struct sram_channel *ch, unsigned int bpl,
+ const struct sram_channel *ch, unsigned int bpl,
u32 risc);
extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
@@ -570,46 +421,31 @@ extern void cx25821_free_buffer(struct videobuf_queue *q,
extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value);
extern void cx25821_sram_channel_dump(struct cx25821_dev *dev,
- struct sram_channel *ch);
+ const struct sram_channel *ch);
extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
- struct sram_channel *ch);
+ const struct sram_channel *ch);
extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci);
extern void cx25821_print_irqbits(char *name, char *tag, char **strings,
int len, u32 bits, u32 mask);
extern void cx25821_dev_unregister(struct cx25821_dev *dev);
extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc);
-extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev,
- int channel_select, int pixel_format);
-extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev,
- int channel_select, int pixel_format);
+extern int cx25821_vidupstream_init(struct cx25821_channel *chan, int pixel_format);
extern int cx25821_audio_upstream_init(struct cx25821_dev *dev,
int channel_select);
-extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev);
-extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev);
+extern int cx25821_write_frame(struct cx25821_channel *chan,
+ const char __user *data, size_t count);
+extern void cx25821_free_mem_upstream(struct cx25821_channel *chan);
extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev);
-extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev,
- struct upstream_user_struct
- *up_data);
-extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev,
- struct upstream_user_struct
- *up_data);
-extern void cx25821_start_upstream_audio(struct cx25821_dev *dev,
- struct upstream_user_struct *up_data);
-extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev);
-extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev);
+extern void cx25821_stop_upstream_video(struct cx25821_channel *chan);
extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev);
extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc);
extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel,
u32 format);
-extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev);
-extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev,
- struct pci_dev *pci,
- struct video_device *template,
- char *type);
+
#endif
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index a6ff8a6f4fc0..150bb76e7839 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -815,7 +815,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
}
static int vidioc_s_frequency (struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct cx8802_fh *fh = priv;
struct cx8802_dev *dev = fh->dev;
@@ -918,7 +918,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
}
static int vidioc_s_tuner (struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
@@ -939,12 +939,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
return 0;
}
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
mutex_lock(&core->lock);
- cx88_set_tvnorm(core,*id);
+ cx88_set_tvnorm(core, id);
mutex_unlock(&core->lock);
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index e2e0b8faf7a4..a87a0e19593e 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -59,6 +59,11 @@ MODULE_PARM_DESC(disable_ir, "Disable IR support");
#define err_printk(core, fmt, arg...) \
printk(KERN_ERR "%s: " fmt, core->name , ## arg)
+#define dprintk(level,fmt, arg...) do { \
+ if (cx88_core_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \
+ } while(0)
+
/* ------------------------------------------------------------------ */
/* board config info */
@@ -2855,6 +2860,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
core->board.tuner_type = tv.tuner_type;
core->tuner_formats = tv.tuner_formats;
core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
+ core->model = tv.model;
/* Make sure we support the board model */
switch (tv.model)
@@ -3133,7 +3139,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
case XC2028_TUNER_RESET:
switch (INPUT(core->input).type) {
case CX88_RADIO:
- info_printk(core, "setting GPIO to radio!\n");
+ dprintk(1, "setting GPIO to radio!\n");
cx_write(MO_GP0_IO, 0x4ff);
mdelay(250);
cx_write(MO_GP2_IO, 0xff);
@@ -3141,7 +3147,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
break;
case CX88_VMUX_DVB: /* Digital TV*/
default: /* Analog TV */
- info_printk(core, "setting GPIO to TV!\n");
+ dprintk(1, "setting GPIO to TV!\n");
break;
}
cx_write(MO_GP1_IO, 0x101010);
@@ -3199,8 +3205,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
not having any tuning at all. */
return 0;
} else {
- err_printk(core, "xc5000: unknown tuner "
- "callback command.\n");
+ dprintk(1, "xc5000: unknown tuner callback command.\n");
return -EINVAL;
}
break;
@@ -3211,8 +3216,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
cx_set(MO_GP0_IO, 0x00000010);
return 0;
} else {
- printk(KERN_ERR
- "xc5000: unknown tuner callback command.\n");
+ dprintk(1, "xc5000: unknown tuner callback command.\n");
return -EINVAL;
}
break;
@@ -3242,13 +3246,13 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg)
switch (core->board.tuner_type) {
case TUNER_XC2028:
- info_printk(core, "Calling XC2028/3028 callback\n");
+ dprintk(1, "Calling XC2028/3028 callback\n");
return cx88_xc2028_tuner_callback(core, command, arg);
case TUNER_XC4000:
- info_printk(core, "Calling XC4000 callback\n");
+ dprintk(1, "Calling XC4000 callback\n");
return cx88_xc4000_tuner_callback(core, command, arg);
case TUNER_XC5000:
- info_printk(core, "Calling XC5000 callback\n");
+ dprintk(1, "Calling XC5000 callback\n");
return cx88_xc5000_tuner_callback(core, command, arg);
}
err_printk(core, "Error: Calling callback for tuner %d\n",
@@ -3589,8 +3593,8 @@ static void cx88_card_setup(struct cx88_core *core)
memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
- info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
- ctl.fname);
+ dprintk(1, "Asking xc2028/3028 to load firmware %s\n",
+ ctl.fname);
call_all(core, tuner, s_config, &xc2028_cfg);
}
call_all(core, core, s_power, 0);
@@ -3759,8 +3763,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
if (radio[core->nr] != UNSET)
core->board.radio_type = radio[core->nr];
- info_printk(core, "TV tuner type %d, Radio tuner type %d\n",
- core->board.tuner_type, core->board.radio_type);
+ dprintk(1, "TV tuner type %d, Radio tuner type %d\n",
+ core->board.tuner_type, core->board.radio_type);
/* init hardware */
cx88_reset(core);
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 39f095c37ffd..c8f3dcc579d4 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -48,9 +48,9 @@ MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
-static unsigned int core_debug;
-module_param(core_debug,int,0644);
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+unsigned int cx88_core_debug;
+module_param_named(core_debug, cx88_core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
static unsigned int nicam;
module_param(nicam,int,0644);
@@ -60,8 +60,10 @@ static unsigned int nocomb;
module_param(nocomb,int,0644);
MODULE_PARM_DESC(nocomb,"disable comb filter");
-#define dprintk(level,fmt, arg...) if (core_debug >= level) \
- printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
+#define dprintk(level,fmt, arg...) do { \
+ if (cx88_core_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \
+ } while(0)
static unsigned int cx88_devcount;
static LIST_HEAD(cx88_devlist);
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 672b267a2d3e..053ed1ba1d85 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -1042,7 +1042,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (!dvb_attach(isl6421_attach,
fe0->dvb.frontend,
&dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
+ 0x08, ISL6421_DCL, 0x00, false))
goto frontend_detach;
}
/* MFE frontend 2 */
@@ -1279,8 +1279,16 @@ static int dvb_register(struct cx8802_dev *dev)
&hauppauge_novas_config,
&core->i2c_adap);
if (fe0->dvb.frontend) {
+ bool override_tone;
+
+ if (core->model == 92001)
+ override_tone = true;
+ else
+ override_tone = false;
+
if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
- &core->i2c_adap, 0x08, ISL6421_DCL, 0x00))
+ &core->i2c_adap, 0x08, ISL6421_DCL, 0x00,
+ override_tone))
goto frontend_detach;
}
break;
@@ -1403,7 +1411,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (!dvb_attach(isl6421_attach,
fe0->dvb.frontend,
&dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
+ 0x08, ISL6421_DCL, 0x00, false))
goto frontend_detach;
}
/* MFE frontend 2 */
@@ -1431,7 +1439,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (!dvb_attach(isl6421_attach,
fe0->dvb.frontend,
&dev->core->i2c_adap,
- 0x08, ISL6421_DCL, 0x00))
+ 0x08, ISL6421_DCL, 0x00, false))
goto frontend_detach;
}
break;
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index c9d3182f79d5..2d3507eb4897 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
{
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
/* stop mpeg dma */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) {
dprintk( 2, "suspend\n" );
printk("%s: suspend mpeg\n", core->name);
cx8802_stop_dma(dev);
del_timer(&dev->mpegq.timeout);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* FIXME -- shutdown device */
cx88_shutdown(dev->core);
@@ -558,6 +559,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
{
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
int err;
if (dev->state.disabled) {
@@ -584,12 +586,12 @@ static int cx8802_resume_common(struct pci_dev *pci_dev)
cx88_reset(dev->core);
/* restart video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->mpegq.active)) {
printk("%s: resume mpeg\n", core->name);
cx8802_restart_queue(dev,&dev->mpegq);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index bc78354262ac..1b00615fd395 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1193,12 +1193,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
return 0;
}
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
mutex_lock(&core->lock);
- cx88_set_tvnorm(core,*tvnorms);
+ cx88_set_tvnorm(core, tvnorms);
mutex_unlock(&core->lock);
return 0;
@@ -1289,7 +1289,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
}
static int vidioc_s_tuner (struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
@@ -1321,8 +1321,10 @@ static int vidioc_g_frequency (struct file *file, void *priv,
}
int cx88_set_freq (struct cx88_core *core,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
+ struct v4l2_frequency new_freq = *f;
+
if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (unlikely(f->tuner != 0))
@@ -1331,8 +1333,8 @@ int cx88_set_freq (struct cx88_core *core,
mutex_lock(&core->lock);
cx88_newstation(core);
call_all(core, tuner, s_frequency, f);
- call_all(core, tuner, g_frequency, f);
- core->freq = f->frequency;
+ call_all(core, tuner, g_frequency, &new_freq);
+ core->freq = new_freq.frequency;
/* When changing channels it is required to reset TVAUDIO */
msleep (10);
@@ -1345,7 +1347,7 @@ int cx88_set_freq (struct cx88_core *core,
EXPORT_SYMBOL(cx88_set_freq);
static int vidioc_s_frequency (struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct cx8800_fh *fh = priv;
struct cx88_core *core = fh->dev->core;
@@ -1378,7 +1380,7 @@ static int vidioc_g_register (struct file *file, void *fh,
}
static int vidioc_s_register (struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
@@ -1407,20 +1409,15 @@ static int radio_g_tuner (struct file *file, void *priv,
return 0;
}
-/* FIXME: Should add a standard for radio */
-
static int radio_s_tuner (struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
if (0 != t->index)
return -EINVAL;
- if (t->audmode > V4L2_TUNER_MODE_STEREO)
- t->audmode = V4L2_TUNER_MODE_STEREO;
call_all(core, tuner, s_tuner, t);
-
return 0;
}
@@ -1957,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
/* stop video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) {
printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev);
@@ -1970,7 +1968,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
cx8800_stop_vbi_dma(dev);
del_timer(&dev->vbiq.timeout);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
if (core->ir)
cx88_ir_stop(core);
@@ -1989,6 +1987,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
+ unsigned long flags;
int err;
if (dev->state.disabled) {
@@ -2019,7 +2018,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* restart video+vbi capture */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
if (!list_empty(&dev->vidq.active)) {
printk("%s/0: resume video\n", core->name);
restart_video_queue(dev,&dev->vidq);
@@ -2028,7 +2027,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
printk("%s/0: resume vbi\n", core->name);
cx8800_restart_vbi_queue(dev,&dev->vbiq);
}
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index feff53c0a251..51ce2c0e8bc1 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -334,6 +334,7 @@ struct cx88_core {
/* board name */
int nr;
char name[32];
+ u32 model;
/* pci stuff */
int pci_bus;
@@ -617,6 +618,8 @@ struct cx8802_dev {
/* ----------------------------------------------------------- */
/* cx88-core.c */
+extern unsigned int cx88_core_debug;
+
extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
int len, u32 bits, u32 mask);
@@ -740,7 +743,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev);
/* ----------------------------------------------------------- */
/* cx88-video.c*/
int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
-int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
+int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f);
int cx88_video_mux(struct cx88_core *core, unsigned int input);
void cx88_querycap(struct file *file, struct cx88_core *core,
struct v4l2_capability *cap);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index 2928e7287da8..07b8460953b6 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -1387,7 +1387,7 @@ int ivtv_init_on_first_open(struct ivtv *itv)
if (!itv->has_cx23415)
write_reg_sync(0x03, IVTV_REG_DMACONTROL);
- ivtv_s_std_enc(itv, &itv->tuner_std);
+ ivtv_s_std_enc(itv, itv->tuner_std);
/* Default interrupts enabled. For the PVR350 this includes the
decoder VSYNC interrupt, which is always on. It is not only used
@@ -1397,7 +1397,7 @@ int ivtv_init_on_first_open(struct ivtv *itv)
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
ivtv_set_osd_alpha(itv);
- ivtv_s_std_dec(itv, &itv->tuner_std);
+ ivtv_s_std_dec(itv, itv->tuner_std);
} else {
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
}
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
index 68387d4369d6..ed73edd2bcd3 100644
--- a/drivers/media/pci/ivtv/ivtv-firmware.c
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -302,7 +302,7 @@ static int ivtv_firmware_restart(struct ivtv *itv)
/* Restore encoder video standard */
std = itv->std;
itv->std = 0;
- ivtv_s_std_enc(itv, &std);
+ ivtv_s_std_enc(itv, std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_init_mpeg_decoder(itv);
@@ -310,7 +310,7 @@ static int ivtv_firmware_restart(struct ivtv *itv)
/* Restore decoder video standard */
std = itv->std_out;
itv->std_out = 0;
- ivtv_s_std_dec(itv, &std);
+ ivtv_s_std_dec(itv, std);
/* Restore framebuffer if active */
if (itv->ivtvfb_restore)
diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c
index 8f0d07789053..af52def700cc 100644
--- a/drivers/media/pci/ivtv/ivtv-gpio.c
+++ b/drivers/media/pci/ivtv/ivtv-gpio.c
@@ -192,7 +192,7 @@ static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int subdev_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct ivtv *itv = sd_to_ivtv(sd);
u16 mask, data;
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 7a8b0d0b6127..9cbbce0eaedc 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -711,28 +711,26 @@ static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_i
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
+static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val)
{
- struct v4l2_dbg_register *regs = arg;
volatile u8 __iomem *reg_start;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
+ if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE)
reg_start = itv->reg_mem - IVTV_REG_OFFSET;
- else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
- regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
+ else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET &&
+ reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
- else if (regs->reg < IVTV_ENCODER_SIZE)
+ else if (reg < IVTV_ENCODER_SIZE)
reg_start = itv->enc_mem;
else
return -EINVAL;
- regs->size = 4;
- if (cmd == VIDIOC_DBG_G_REGISTER)
- regs->val = readl(regs->reg + reg_start);
+ if (get)
+ *val = readl(reg + reg_start);
else
- writel(regs->val, regs->reg + reg_start);
+ writel(*val, reg + reg_start);
return 0;
}
@@ -740,20 +738,25 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register
{
struct ivtv *itv = fh2id(fh)->itv;
- if (v4l2_chip_match_host(&reg->match))
- return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
+ if (v4l2_chip_match_host(&reg->match)) {
+ reg->size = 4;
+ return ivtv_itvc(itv, true, reg->reg, &reg->val);
+ }
/* TODO: subdev errors should not be ignored, this should become a
subdev helper function. */
ivtv_call_all(itv, core, g_register, reg);
return 0;
}
-static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
{
struct ivtv *itv = fh2id(fh)->itv;
- if (v4l2_chip_match_host(&reg->match))
- return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
+ if (v4l2_chip_match_host(&reg->match)) {
+ u64 val = reg->val;
+
+ return ivtv_itvc(itv, false, reg->reg, &val);
+ }
/* TODO: subdev errors should not be ignored, this should become a
subdev helper function. */
ivtv_call_all(itv, core, s_register, reg);
@@ -1078,7 +1081,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *
return 0;
}
-int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
+int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf)
{
struct ivtv *itv = fh2id(fh)->itv;
struct ivtv_stream *s = &itv->streams[fh2id(fh)->type];
@@ -1103,10 +1106,10 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
-void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std)
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std)
{
- itv->std = *std;
- itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ itv->std = std;
+ itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
itv->is_50hz = !itv->is_60hz;
cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
itv->cxhdl.width = 720;
@@ -1122,15 +1125,15 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std)
ivtv_call_all(itv, core, s_std, itv->std);
}
-void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std)
{
struct yuv_playback_info *yi = &itv->yuv_info;
DEFINE_WAIT(wait);
int f;
/* set display standard */
- itv->std_out = *std;
- itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
+ itv->std_out = std;
+ itv->is_out_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
itv->is_out_50hz = !itv->is_out_60hz;
ivtv_call_all(itv, video, s_std_output, itv->std_out);
@@ -1168,14 +1171,14 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std)
}
}
-static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
+static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std)
{
struct ivtv *itv = fh2id(fh)->itv;
- if ((*std & V4L2_STD_ALL) == 0)
+ if ((std & V4L2_STD_ALL) == 0)
return -EINVAL;
- if (*std == itv->std)
+ if (std == itv->std)
return 0;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
@@ -1196,7 +1199,7 @@ static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
return 0;
}
-static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
+static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
{
struct ivtv_open_id *id = fh2id(fh);
struct ivtv *itv = id->itv;
@@ -1804,7 +1807,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
}
static long ivtv_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
struct ivtv *itv = fh2id(fh)->itv;
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h
index 7c553d16579b..75c397756116 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.h
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.h
@@ -27,9 +27,9 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
void ivtv_set_funcs(struct video_device *vdev);
-void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std);
-void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std);
-int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std);
+void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std);
+int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
#endif
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 05b94aa8ba32..9ff1230192e8 100644
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -1171,8 +1171,7 @@ static void ivtvfb_release_buffers (struct ivtv *itv)
fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
/* Release pseudo palette */
- if (oi->ivtvfb_info.pseudo_palette)
- kfree(oi->ivtvfb_info.pseudo_palette);
+ kfree(oi->ivtvfb_info.pseudo_palette);
#ifdef CONFIG_MTRR
if (oi->fb_end_aligned_physaddr) {
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 7859c43479d7..2381b05432e6 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1410,7 +1410,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
}
static long vidioc_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
switch (cmd) {
case MEYEIOC_G_PARAMS:
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index dc68cf1070f7..d45e7f6ff332 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -50,6 +50,11 @@ static char name_svideo[] = "S-Video";
/* ------------------------------------------------------------------ */
/* board config info */
+static struct tda18271_std_map aver_a706_std_map = {
+ .fm_radio = { .if_freq = 5500, .fm_rfn = 0, .agc_mode = 3, .std = 0,
+ .if_lvl = 0, .rfagc_top = 0x2c, },
+};
+
/* If radio_type !=UNSET, radio_addr should be specified
*/
@@ -2760,7 +2765,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
@@ -3291,7 +3296,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 1,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x000200000,
.inputs = {{
@@ -3395,7 +3400,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 1,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200100,
.inputs = {{
@@ -3426,7 +3431,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 3,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_SERIAL,
.ts_force_val = 1,
@@ -3459,7 +3464,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 3,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_SERIAL,
.gpiomask = 0x0800100, /* GPIO 21 is an INPUT */
@@ -3683,7 +3688,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
@@ -3736,7 +3741,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
@@ -3754,7 +3759,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -3887,7 +3892,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
.name = name_tv, /* FIXME: analog tv untested */
@@ -3903,7 +3908,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.gpiomask = 0x020200000,
.inputs = {{
.name = name_tv,
@@ -3937,7 +3942,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.gpiomask = 0x020200000,
.inputs = {{
.name = name_tv,
@@ -4737,7 +4742,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = {{
@@ -4823,7 +4828,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
.name = name_tv,
@@ -4847,7 +4852,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = { {
@@ -5057,7 +5062,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -5087,7 +5092,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 2,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF },
.gpiomask = 1 << 21,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -5176,7 +5181,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.gpiomask = 0x0200000,
.inputs = { {
@@ -5406,7 +5411,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .tuner_config = 0,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF },
.mpeg = SAA7134_MPEG_DVB,
.ts_type = SAA7134_MPEG_TS_PARALLEL,
.inputs = {{
@@ -5629,7 +5634,7 @@ struct saa7134_board saa7134_boards[] = {
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
- .tuner_config = 3,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE },
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask = 0x02050000,
@@ -5790,6 +5795,38 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x6010000,
} },
},
+ [SAA7134_BOARD_AVERMEDIA_A706] = {
+ .name = "AverMedia AverTV Satellite Hybrid+FM A706",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF,
+ .no_i2c_gate = 1,
+ .tda18271_std_map = &aver_a706_std_map },
+ .gpiomask = 1 << 11,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp,
+ .vmux = 4,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0000800,
+ },
+ },
};
@@ -7037,6 +7074,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x0911,
.driver_data = SAA7134_BOARD_SENSORAY811_911,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A706,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -7585,6 +7628,17 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ /* radio antenna select: tristate both as in Windows driver */
+ saa7134_set_gpio(dev, 12, 3); /* TV antenna */
+ saa7134_set_gpio(dev, 13, 3); /* FM antenna */
+ dev->has_remote = SAA7134_REMOTE_I2C;
+ /*
+ * Disable CE5039 DVB-S tuner now (SLEEP pin high) to prevent
+ * it from interfering with analog tuner detection
+ */
+ saa7134_set_gpio(dev, 23, 1);
+ break;
case SAA7134_BOARD_VIDEOMATE_S350:
dev->has_remote = SAA7134_REMOTE_GPIO;
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000);
@@ -7633,7 +7687,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev)
if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
tun_setup.type = dev->tuner_type;
tun_setup.addr = dev->tuner_addr;
- tun_setup.config = saa7134_boards[dev->board].tuner_config;
+ tun_setup.config = &saa7134_boards[dev->board].tda829x_conf;
tun_setup.tuner_callback = saa7134_tuner_callback;
tun_setup.mode_mask = mode_mask;
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 8fd24e7c9403..45f0aca597ae 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -805,6 +805,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
dev->name, type, saa7134_boards[dev->board].name);
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
video_set_drvdata(vfd, dev);
return vfd;
}
@@ -1028,8 +1029,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
}
}
- v4l2_prio_init(&dev->prio);
-
mutex_lock(&saa7134_devlist_lock);
list_for_each_entry(mops, &mops_list, next)
mpeg_ops_attach(mops, dev);
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index 27915e501db9..4a08ae31df2e 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -1073,6 +1073,10 @@ static struct mt312_config zl10313_compro_s350_config = {
.demod_address = 0x0e,
};
+static struct mt312_config zl10313_avermedia_a706_config = {
+ .demod_address = 0x0e,
+};
+
static struct lgdt3305_config hcw_lgdt3305_config = {
.i2c_addr = 0x0e,
.mpeg_mode = LGDT3305_MPEG_SERIAL,
@@ -1391,8 +1395,9 @@ static int dvb_init(struct saa7134_dev *dev)
wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
goto detach_frontend;
}
- if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap,
- 0x08, 0, 0) == NULL) {
+ if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
+ &dev->i2c_adap,
+ 0x08, 0, 0, false) == NULL) {
wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
goto detach_frontend;
}
@@ -1509,7 +1514,8 @@ static int dvb_init(struct saa7134_dev *dev)
goto detach_frontend;
}
if (dvb_attach(isl6421_attach, fe0->dvb.frontend,
- &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ &dev->i2c_adap,
+ 0x08, 0, 0, false) == NULL) {
wprintk("%s: No ISL6421 found!\n", __func__);
goto detach_frontend;
}
@@ -1820,6 +1826,25 @@ static int dvb_init(struct saa7134_dev *dev)
&prohdtv_pro2_tda18271_config);
}
break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ /* Enable all DVB-S devices now */
+ /* CE5039 DVB-S tuner SLEEP pin low */
+ saa7134_set_gpio(dev, 23, 0);
+ /* CE6313 DVB-S demod SLEEP pin low */
+ saa7134_set_gpio(dev, 9, 0);
+ /* CE6313 DVB-S demod RESET# pin high */
+ saa7134_set_gpio(dev, 25, 1);
+ msleep(1);
+ fe0->dvb.frontend = dvb_attach(mt312_attach,
+ &zl10313_avermedia_a706_config, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (dvb_attach(zl10039_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap) == NULL)
+ wprintk("%s: No zl10039 found!\n",
+ __func__);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 4df79c656909..66a70814004c 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -428,7 +428,7 @@ static int empress_g_chip_ident(struct file *file, void *fh,
return -EINVAL;
}
-static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int empress_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = file->private_data;
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index a176ec3285e0..c68169d75804 100644
--- a/drivers/media/pci/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -256,6 +256,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
addr |= 1;
if (i > 0 && msgs[i].flags &
I2C_M_RD && msgs[i].addr != 0x40 &&
+ msgs[i].addr != 0x41 &&
msgs[i].addr != 0x19) {
/* workaround for a saa7134 i2c bug
* needed to talk to the mt352 demux
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index e761262f7475..6f4312663bdf 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -997,6 +997,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
info.addr = 0x40;
break;
+ case SAA7134_BOARD_AVERMEDIA_A706:
+ info.addr = 0x41;
+ break;
case SAA7134_BOARD_FLYDVB_TRIO:
dev->init_data.name = "FlyDVB Trio";
dev->init_data.get_key = get_key_flydvb_trio;
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index b7a99bee2f98..0f34e09d98dc 100644
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -796,6 +796,7 @@ static int tvaudio_thread_ddep(void *data)
dprintk("FM Radio\n");
if (dev->tuner_type == TUNER_PHILIPS_TDA8290) {
norms = (0x11 << 2) | 0x01;
+ /* set IF frequency to 5.5 MHz */
saa_dsp_writel(dev, 0x42c >> 2, 0x729555);
} else {
norms = (0x0f << 2) | 0x01;
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 7c503fb68526..cc409380ee16 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1176,14 +1176,6 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str
int restart_overlay = 0;
int err;
- /* When called from the empress code fh == NULL.
- That needs to be fixed somehow, but for now this is
- good enough. */
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- }
err = -EINVAL;
mutex_lock(&dev->lock);
@@ -1352,6 +1344,7 @@ static int video_open(struct file *file)
if (NULL == fh)
return -ENOMEM;
+ v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -1359,7 +1352,6 @@ static int video_open(struct file *file)
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
fh->width = 720;
fh->height = 576;
- v4l2_prio_open(&dev->prio, &fh->prio);
videobuf_queue_sg_init(&fh->cap, &video_qops,
&dev->pci->dev, &dev->slock,
@@ -1384,6 +1376,8 @@ static int video_open(struct file *file)
/* switch to video/vbi mode */
video_mux(dev,dev->ctl_input);
}
+ v4l2_fh_add(&fh->fh);
+
return 0;
}
@@ -1504,7 +1498,8 @@ static int video_release(struct file *file)
saa7134_pgtable_free(dev->pci,&fh->pt_cap);
saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
- v4l2_prio_close(&dev->prio, fh->prio);
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
file->private_data = NULL;
kfree(fh);
return 0;
@@ -1557,6 +1552,7 @@ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
struct saa7134_dev *dev = fh->dev;
struct saa7134_tvnorm *norm = dev->tvnorm;
+ memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1755,7 +1751,6 @@ static int saa7134_enum_input(struct file *file, void *priv,
strcpy(i->name, card_in(dev, n).name);
if (card_in(dev, n).tv)
i->type = V4L2_INPUT_TYPE_TUNER;
- i->audioset = 1;
if (n == dev->ctl_input) {
int v1 = saa_readb(SAA7134_STATUS_VIDEO1);
int v2 = saa_readb(SAA7134_STATUS_VIDEO2);
@@ -1784,11 +1779,6 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- int err;
-
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
if (i >= SAA7134_INPUT_MAX)
return -EINVAL;
@@ -1805,6 +1795,8 @@ static int saa7134_querycap(struct file *file, void *priv,
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
+ struct video_device *vdev = video_devdata(file);
+ u32 radio_caps, video_caps, vbi_caps;
unsigned int tuner_type = dev->tuner_type;
@@ -1812,54 +1804,67 @@ static int saa7134_querycap(struct file *file, void *priv,
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_TUNER;
+
+ cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if ((tuner_type != TUNER_ABSENT) && (tuner_type != UNSET))
+ cap->device_caps |= V4L2_CAP_TUNER;
+
+ radio_caps = V4L2_CAP_RADIO;
if (dev->has_rds)
- cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
+ radio_caps |= V4L2_CAP_RDS_CAPTURE;
+
+ video_caps = V4L2_CAP_VIDEO_CAPTURE;
if (saa7134_no_overlay <= 0)
- cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+ video_caps |= V4L2_CAP_VIDEO_OVERLAY;
+
+ vbi_caps = V4L2_CAP_VBI_CAPTURE;
+
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_RADIO:
+ cap->device_caps |= radio_caps;
+ break;
+ case VFL_TYPE_GRABBER:
+ cap->device_caps |= video_caps;
+ break;
+ case VFL_TYPE_VBI:
+ cap->device_caps |= vbi_caps;
+ break;
+ }
+ cap->capabilities = radio_caps | video_caps | vbi_caps |
+ cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ if (vdev->vfl_type == VFL_TYPE_RADIO) {
+ cap->device_caps &= ~V4L2_CAP_STREAMING;
+ if (!dev->has_rds)
+ cap->device_caps &= ~V4L2_CAP_READWRITE;
+ }
- if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
- cap->capabilities &= ~V4L2_CAP_TUNER;
return 0;
}
-int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id)
{
unsigned long flags;
unsigned int i;
v4l2_std_id fixup;
- int err;
- /* When called from the empress code fh == NULL.
- That needs to be fixed somehow, but for now this is
- good enough. */
- if (fh) {
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
- } else if (res_locked(dev, RESOURCE_OVERLAY)) {
+ if (!fh && res_locked(dev, RESOURCE_OVERLAY)) {
/* Don't change the std from the mpeg device
if overlay is active. */
return -EBUSY;
}
for (i = 0; i < TVNORMS; i++)
- if (*id == tvnorms[i].id)
+ if (id == tvnorms[i].id)
break;
if (i == TVNORMS)
for (i = 0; i < TVNORMS; i++)
- if (*id & tvnorms[i].id)
+ if (id & tvnorms[i].id)
break;
if (i == TVNORMS)
return -EINVAL;
- if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+ if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) {
if (secam[0] == 'L' || secam[0] == 'l') {
if (secam[1] == 'C' || secam[1] == 'c')
fixup = V4L2_STD_SECAM_LC;
@@ -1879,7 +1884,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
return -EINVAL;
}
- *id = tvnorms[i].id;
+ id = tvnorms[i].id;
mutex_lock(&dev->lock);
if (fh && res_check(fh, RESOURCE_OVERLAY)) {
@@ -1901,7 +1906,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
}
EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
-static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_fh *fh = priv;
@@ -2009,11 +2014,11 @@ static int saa7134_g_tuner(struct file *file, void *priv,
if (NULL != card_in(dev, n).name) {
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
+ saa_call_all(dev, tuner, g_tuner, t);
t->capability = V4L2_TUNER_CAP_NORM |
V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2;
- t->rangehigh = 0xffffffffUL;
t->rxsubchans = saa7134_tvaudio_getstereo(dev);
t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
}
@@ -2023,15 +2028,14 @@ static int saa7134_g_tuner(struct file *file, void *priv,
}
static int saa7134_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- int rx, mode, err;
+ int rx, mode;
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
+ if (0 != t->index)
+ return -EINVAL;
mode = dev->thread.mode;
if (UNSET == mode) {
@@ -2050,22 +2054,20 @@ static int saa7134_g_frequency(struct file *file, void *priv,
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
+ if (0 != f->tuner)
+ return -EINVAL;
+
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
+ saa_call_all(dev, tuner, g_frequency, f);
return 0;
}
static int saa7134_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
- int err;
-
- err = v4l2_prio_check(&dev->prio, fh->prio);
- if (0 != err)
- return err;
if (0 != f->tuner)
return -EINVAL;
@@ -2074,7 +2076,6 @@ static int saa7134_s_frequency(struct file *file, void *priv,
if (1 == fh->radio && V4L2_TUNER_RADIO != f->type)
return -EINVAL;
mutex_lock(&dev->lock);
- dev->ctl_freq = f->frequency;
saa_call_all(dev, tuner, s_frequency, f);
@@ -2083,35 +2084,6 @@ static int saa7134_s_frequency(struct file *file, void *priv,
return 0;
}
-static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- strcpy(a->name, "audio");
- return 0;
-}
-
-static int saa7134_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p)
-{
- struct saa7134_fh *fh = f;
- struct saa7134_dev *dev = fh->dev;
-
- *p = v4l2_prio_max(&dev->prio);
- return 0;
-}
-
-static int saa7134_s_priority(struct file *file, void *f,
- enum v4l2_priority prio)
-{
- struct saa7134_fh *fh = f;
- struct saa7134_dev *dev = fh->dev;
-
- return v4l2_prio_change(&dev->prio, &fh->prio, prio);
-}
-
static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
@@ -2279,12 +2251,6 @@ static int saa7134_streamoff(struct file *file, void *priv,
return 0;
}
-static int saa7134_g_parm(struct file *file, void *fh,
- struct v4l2_streamparm *parm)
-{
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -2300,7 +2266,7 @@ static int vidioc_g_register (struct file *file, void *priv,
}
static int vidioc_s_register (struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
@@ -2312,19 +2278,6 @@ static int vidioc_s_register (struct file *file, void *priv,
}
#endif
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct saa7134_fh *fh = file->private_data;
- struct saa7134_dev *dev = fh->dev;
-
- strcpy(cap->driver, "saa7134");
- strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card));
- sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
@@ -2339,6 +2292,7 @@ static int radio_g_tuner(struct file *file, void *priv,
t->type = V4L2_TUNER_RADIO;
saa_call_all(dev, tuner, g_tuner, t);
+ t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO;
if (dev->input->amux == TV) {
t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
t->rxsubchans = (saa_readb(0x529) & 0x08) ?
@@ -2347,7 +2301,7 @@ static int radio_g_tuner(struct file *file, void *priv,
return 0;
}
static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
@@ -2377,26 +2331,12 @@ static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
return 0;
}
-static int radio_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- memset(a, 0, sizeof(*a));
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_audio(struct file *file, void *priv,
- const struct v4l2_audio *a)
-{
- return 0;
-}
-
static int radio_s_input(struct file *filp, void *priv, unsigned int i)
{
return 0;
}
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+static int radio_s_std(struct file *file, void *fh, v4l2_std_id norm)
{
return 0;
}
@@ -2441,8 +2381,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
- .vidioc_g_audio = saa7134_g_audio,
- .vidioc_s_audio = saa7134_s_audio,
.vidioc_cropcap = saa7134_cropcap,
.vidioc_reqbufs = saa7134_reqbufs,
.vidioc_querybuf = saa7134_querybuf,
@@ -2465,9 +2403,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fbuf = saa7134_g_fbuf,
.vidioc_s_fbuf = saa7134_s_fbuf,
.vidioc_overlay = saa7134_overlay,
- .vidioc_g_priority = saa7134_g_priority,
- .vidioc_s_priority = saa7134_s_priority,
- .vidioc_g_parm = saa7134_g_parm,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2486,12 +2421,10 @@ static const struct v4l2_file_operations radio_fops = {
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = saa7134_querycap,
.vidioc_g_tuner = radio_g_tuner,
.vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
.vidioc_s_input = radio_s_input,
.vidioc_s_std = radio_s_std,
.vidioc_queryctrl = radio_queryctrl,
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 71eefef5e324..d2ad16c1569a 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -36,6 +36,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
#include <media/tuner.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
@@ -45,6 +46,7 @@
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
#include <media/videobuf-dvb.h>
#endif
+#include "tda8290.h"
#define UNSET (-1U)
@@ -334,6 +336,7 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_KWORLD_PC150U 189
#define SAA7134_BOARD_ASUSTeK_PS3_100 190
#define SAA7134_BOARD_HAWELL_HW_9004V1 191
+#define SAA7134_BOARD_AVERMEDIA_A706 192
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -390,7 +393,7 @@ struct saa7134_board {
unsigned char rds_addr;
unsigned int tda9887_conf;
- unsigned int tuner_config;
+ struct tda829x_config tda829x_conf;
/* peripheral I/O */
enum saa7134_video_out video_out;
@@ -466,11 +469,11 @@ struct saa7134_dmaqueue {
/* video filehandle status */
struct saa7134_fh {
+ struct v4l2_fh fh;
struct saa7134_dev *dev;
unsigned int radio;
enum v4l2_buf_type type;
unsigned int resources;
- enum v4l2_priority prio;
struct pm_qos_request qos_request;
/* video overlay */
@@ -542,7 +545,6 @@ struct saa7134_dev {
struct list_head devlist;
struct mutex lock;
spinlock_t slock;
- struct v4l2_prio_state prio;
struct v4l2_device v4l2_dev;
/* workstruct for loading modules */
struct work_struct request_module_wk;
@@ -605,7 +607,6 @@ struct saa7134_dev {
int ctl_contrast;
int ctl_hue;
int ctl_saturation;
- int ctl_freq;
int ctl_mute; /* audio */
int ctl_volume;
int ctl_invert; /* private */
@@ -766,7 +767,7 @@ extern struct video_device saa7134_radio_template;
int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
-int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id);
+int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id);
int saa7134_videoport_init(struct saa7134_dev *dev);
void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 91369daad722..71e8bead321b 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -560,7 +560,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
return call_all(dev, tuner, g_tuner, t);
}
-static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
@@ -595,7 +595,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
@@ -612,8 +612,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
/* tune in desired frequency */
tuner_call(mxb, tuner, s_frequency, f);
/* let the tuner subdev clamp the frequency to the tuner range */
- tuner_call(mxb, tuner, g_frequency, f);
mxb->cur_freq = *f;
+ tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq);
if (mxb->cur_audinput == 0)
mxb_update_audmode(mxb);
@@ -680,7 +680,7 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
return 0;
}
-static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
+static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
@@ -688,7 +688,6 @@ static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_regist
return -EPERM;
if (v4l2_chip_match_host(&reg->match)) {
saa7146_write(dev, reg->reg, reg->val);
- reg->size = 4;
return 0;
}
return call_all(dev, core, s_register, reg);
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 63502e7a2a76..7618fdae811e 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug, "enable debug messages");
unsigned int fw_debug;
module_param(fw_debug, int, 0644);
-MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
+MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2");
unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
module_param(encoder_buffers, int, 0644);
diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c
index 9bb0903ee5f1..0b74fb2300dd 100644
--- a/drivers/media/pci/saa7164/saa7164-encoder.c
+++ b/drivers/media/pci/saa7164/saa7164-encoder.c
@@ -211,17 +211,17 @@ static int saa7164_encoder_initialize(struct saa7164_port *port)
}
/* -- V4L2 --------------------------------------------------------- */
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7164_encoder_fh *fh = file->private_data;
struct saa7164_port *port = fh->port;
struct saa7164_dev *dev = port->dev;
unsigned int i;
- dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id);
+ dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)id);
for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
- if (*id & saa7164_tvnorms[i].id)
+ if (id & saa7164_tvnorms[i].id)
break;
}
if (i == ARRAY_SIZE(saa7164_tvnorms))
@@ -234,7 +234,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
*/
saa7164_api_set_audio_std(port);
- dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+ dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)id);
return 0;
}
@@ -318,7 +318,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
/* Update the A/V core */
return 0;
@@ -337,7 +337,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct saa7164_encoder_fh *fh = file->private_data;
struct saa7164_port *port = fh->port;
@@ -1313,7 +1313,7 @@ static int saa7164_g_register(struct file *file, void *fh,
}
static int saa7164_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
struct saa7164_dev *dev = port->dev;
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index b4532299c0ed..da224eb39b95 100644
--- a/drivers/media/pci/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -183,17 +183,17 @@ static int saa7164_vbi_initialize(struct saa7164_port *port)
}
/* -- V4L2 --------------------------------------------------------- */
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7164_vbi_fh *fh = file->private_data;
struct saa7164_port *port = fh->port;
struct saa7164_dev *dev = port->dev;
unsigned int i;
- dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id);
+ dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)id);
for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
- if (*id & saa7164_tvnorms[i].id)
+ if (id & saa7164_tvnorms[i].id)
break;
}
if (i == ARRAY_SIZE(saa7164_tvnorms))
@@ -206,7 +206,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
*/
saa7164_api_set_audio_std(port);
- dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+ dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)id);
return 0;
}
@@ -290,7 +290,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
/* Update the A/V core */
return 0;
@@ -309,7 +309,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct saa7164_vbi_fh *fh = file->private_data;
struct saa7164_port *port = fh->port;
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index a94ccad02066..03130157db83 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -4,6 +4,7 @@ config STA2X11_VIP
select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
select VIDEOBUF2_DMA_CONTIG
depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+ depends on I2C
help
Say Y for support for STA2X11 VIP (Video Input Port) capture
device.
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 4b703fe8c953..7005695aa4bd 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -439,22 +439,22 @@ static int vidioc_querycap(struct file *file, void *priv,
*
* other, returned from video DAC.
*/
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
{
struct sta2x11_vip *vip = video_drvdata(file);
v4l2_std_id oldstd = vip->std, newstd;
int status;
- if (V4L2_STD_ALL == *std) {
- v4l2_subdev_call(vip->decoder, core, s_std, *std);
+ if (V4L2_STD_ALL == std) {
+ v4l2_subdev_call(vip->decoder, core, s_std, std);
ssleep(2);
v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
if (status & V4L2_IN_ST_NO_SIGNAL)
return -EIO;
- *std = vip->std = newstd;
- if (oldstd != *std) {
- if (V4L2_STD_525_60 & (*std))
+ std = vip->std = newstd;
+ if (oldstd != std) {
+ if (V4L2_STD_525_60 & std)
vip->format = formats_60[0];
else
vip->format = formats_50[0];
@@ -462,14 +462,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
return 0;
}
- if (oldstd != *std) {
- if (V4L2_STD_525_60 & (*std))
+ if (oldstd != std) {
+ if (V4L2_STD_525_60 & std)
vip->format = formats_60[0];
else
vip->format = formats_50[0];
}
- return v4l2_subdev_call(vip->decoder, core, s_std, *std);
+ return v4l2_subdev_call(vip->decoder, core, s_std, std);
}
/**
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 3dc7aa9b6f40..f38329d29daa 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -990,7 +990,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
if (feed->type == DMX_TYPE_TS) {
if ((feed->ts_type & TS_DECODER) &&
- (feed->pes_type <= DMX_TS_PES_PCR)) {
+ (feed->pes_type <= DMX_PES_PCR)) {
switch (demux->dmx.frontend->source) {
case DMX_MEMORY_FE:
if (feed->ts_type & TS_DECODER)
@@ -1051,14 +1051,14 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
if (feed->type == DMX_TYPE_TS) {
if (feed->ts_type & TS_DECODER) {
- if (feed->pes_type >= DMX_TS_PES_OTHER ||
+ if (feed->pes_type >= DMX_PES_OTHER ||
!demux->pesfilter[feed->pes_type])
return -EINVAL;
demux->pids[feed->pes_type] |= 0x8000;
demux->pesfilter[feed->pes_type] = NULL;
}
if (feed->ts_type & TS_DECODER &&
- feed->pes_type < DMX_TS_PES_OTHER) {
+ feed->pes_type < DMX_PES_OTHER) {
ret = dvb_feed_stop_pid(feed);
} else
if ((feed->ts_type & TS_PACKET) &&
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
index 730e906ea912..6c4076acb131 100644
--- a/drivers/media/pci/ttpci/av7110_v4l.c
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
@@ -366,7 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
@@ -426,7 +426,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
+static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
index 7e6e43ae5c51..6ccc48833fd8 100644
--- a/drivers/media/pci/ttpci/budget.c
+++ b/drivers/media/pci/ttpci/budget.c
@@ -537,6 +537,16 @@ static void frontend_init(struct budget *budget)
}
break;
+ case 0x4f52: /* Cards based on Philips Semi Sylt PCI ref. design */
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ printk(KERN_INFO "budget: tuner ALPS BSRU6 in Philips Semi. Sylt detected\n");
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ break;
+ }
+ break;
+
case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */
{
int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);
@@ -818,6 +828,7 @@ MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps front
MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(sylt, "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
@@ -832,6 +843,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020),
+ MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52),
{
.vendor = 0,
}
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index 2e8f518f298f..1168a84a737d 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -2435,14 +2435,14 @@ static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
return 0;
}
-static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std)
+static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res = 0;
mutex_lock(&zr->resource_lock);
- res = zoran_set_norm(zr, *std);
+ res = zoran_set_norm(zr, std);
if (res)
goto sstd_unlock_and_return;
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 05d7b6333461..0494d2769fd7 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -122,7 +122,7 @@ config VIDEO_S3C_CAMIF
will be called s3c-camif.
source "drivers/media/platform/soc_camera/Kconfig"
-source "drivers/media/platform/s5p-fimc/Kconfig"
+source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/s5p-tv/Kconfig"
endif # V4L_PLATFORM_DRIVERS
@@ -145,7 +145,6 @@ config VIDEO_CODA
depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- select IRAM_ALLOC if SOC_IMX53
---help---
Coda is a range of video codec IPs that supports
H.264, MPEG-4, and other video formats.
@@ -204,7 +203,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
config VIDEO_SH_VEU
tristate "SuperH VEU mem2mem video processing driver"
- depends on VIDEO_DEV && VIDEO_V4L2
+ depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 42089ba3600f..eee28dd78d7d 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o
obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o
obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
+obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 5f209d5810dc..0e55b087076f 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -384,7 +384,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
params.ppi_control = bcap_dev->cfg->ppi_control;
params.int_mask = bcap_dev->cfg->int_mask;
if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities
- & V4L2_IN_CAP_CUSTOM_TIMINGS) {
+ & V4L2_IN_CAP_DV_TIMINGS) {
struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt;
params.hdelay = bt->hsync + bt->hbackporch;
@@ -633,7 +633,7 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std)
return 0;
}
-static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
+static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std)
{
struct bcap_device *bcap_dev = video_drvdata(file);
int ret;
@@ -641,11 +641,11 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std)
if (vb2_is_busy(&bcap_dev->buffer_queue))
return -EBUSY;
- ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std);
+ ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, std);
if (ret < 0)
return ret;
- bcap_dev->std = *std;
+ bcap_dev->std = std;
return 0;
}
@@ -890,7 +890,7 @@ static int bcap_dbg_g_register(struct file *file, void *priv,
}
static int bcap_dbg_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct bcap_device *bcap_dev = video_drvdata(file);
@@ -1029,6 +1029,7 @@ static int bcap_probe(struct platform_device *pdev)
q->buf_struct_size = sizeof(struct bcap_buffer);
q->ops = &bcap_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
vb2_queue_init(q);
@@ -1110,7 +1111,7 @@ static int bcap_probe(struct platform_device *pdev)
}
bcap_dev->std = std;
}
- if (config->inputs[0].capabilities & V4L2_IN_CAP_CUSTOM_TIMINGS) {
+ if (config->inputs[0].capabilities & V4L2_IN_CAP_DV_TIMINGS) {
struct v4l2_dv_timings dv_timings;
ret = v4l2_subdev_call(bcap_dev->sd, video,
g_dv_timings, &dv_timings);
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 20827ba168fc..48b8d7af386d 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -14,6 +14,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
+#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -23,7 +24,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/of.h>
-#include <linux/platform_data/imx-iram.h>
+#include <linux/platform_data/coda.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -43,6 +44,7 @@
#define CODA7_WORK_BUF_SIZE (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA_ISRAM_SIZE (2048 * 2)
+#define CODADX6_IRAM_SIZE 0xb000
#define CODA7_IRAM_SIZE 0x14000 /* 81920 bytes */
#define CODA_MAX_FRAMEBUFFERS 2
@@ -128,7 +130,10 @@ struct coda_dev {
struct coda_aux_buf codebuf;
struct coda_aux_buf workbuf;
+ struct gen_pool *iram_pool;
+ long unsigned int iram_vaddr;
long unsigned int iram_paddr;
+ unsigned long iram_size;
spinlock_t irqlock;
struct mutex dev_mutex;
@@ -1422,6 +1427,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1433,6 +1439,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -1628,6 +1635,9 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
}
+ dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+ dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
@@ -1926,6 +1936,9 @@ static int coda_probe(struct platform_device *pdev)
const struct of_device_id *of_id =
of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
const struct platform_device_id *pdev_id;
+ struct coda_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *np = pdev->dev.of_node;
+ struct gen_pool *pool;
struct coda_dev *dev;
struct resource *res;
int ret, irq;
@@ -1988,6 +2001,16 @@ static int coda_probe(struct platform_device *pdev)
return -ENOENT;
}
+ /* Get IRAM pool from device tree or platform data */
+ pool = of_get_named_gen_pool(np, "iram", 0);
+ if (!pool && pdata)
+ pool = dev_get_gen_pool(pdata->iram_dev);
+ if (!pool) {
+ dev_err(&pdev->dev, "iram pool not available\n");
+ return -ENOMEM;
+ }
+ dev->iram_pool = pool;
+
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
return ret;
@@ -2022,18 +2045,17 @@ static int coda_probe(struct platform_device *pdev)
return -ENOMEM;
}
- if (dev->devtype->product == CODA_DX6) {
- dev->iram_paddr = 0xffff4c00;
- } else {
- void __iomem *iram_vaddr;
-
- iram_vaddr = iram_alloc(CODA7_IRAM_SIZE,
- &dev->iram_paddr);
- if (!iram_vaddr) {
- dev_err(&pdev->dev, "unable to alloc iram\n");
- return -ENOMEM;
- }
+ if (dev->devtype->product == CODA_DX6)
+ dev->iram_size = CODADX6_IRAM_SIZE;
+ else
+ dev->iram_size = CODA7_IRAM_SIZE;
+ dev->iram_vaddr = gen_pool_alloc(dev->iram_pool, dev->iram_size);
+ if (!dev->iram_vaddr) {
+ dev_err(&pdev->dev, "unable to alloc iram\n");
+ return -ENOMEM;
}
+ dev->iram_paddr = gen_pool_virt_to_phys(dev->iram_pool,
+ dev->iram_vaddr);
platform_set_drvdata(pdev, dev);
@@ -2050,8 +2072,8 @@ static int coda_remove(struct platform_device *pdev)
if (dev->alloc_ctx)
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
v4l2_device_unregister(&dev->v4l2_dev);
- if (dev->iram_paddr)
- iram_free(dev->iram_paddr, CODA7_IRAM_SIZE);
+ if (dev->iram_vaddr)
+ gen_pool_free(dev->iram_pool, dev->iram_vaddr, dev->iram_size);
if (dev->codebuf.vaddr)
dma_free_coherent(&pdev->dev, dev->codebuf.size,
&dev->codebuf.vaddr, dev->codebuf.paddr);
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index ccfde4eb626a..afb3aec1320e 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -1,79 +1,47 @@
config VIDEO_DAVINCI_VPIF_DISPLAY
- tristate "DM646x/DA850/OMAPL138 EVM Video Display"
- depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+ tristate "TI DaVinci VPIF V4L2-Display driver"
+ depends on VIDEO_DEV && ARCH_DAVINCI
select VIDEOBUF2_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
help
Enables Davinci VPIF module used for display devices.
- This module is common for following DM6467/DA850/OMAPL138
- based display devices.
+ This module is used for display on TI DM6467/DA850/OMAPL138
+ SoCs.
- To compile this driver as a module, choose M here: the
- module will be called vpif_display.
+ To compile this driver as a module, choose M here. There will
+ be two modules called vpif.ko and vpif_display.ko
config VIDEO_DAVINCI_VPIF_CAPTURE
- tristate "DM646x/DA850/OMAPL138 EVM Video Capture"
- depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM)
+ tristate "TI DaVinci VPIF video capture driver"
+ depends on VIDEO_DEV && ARCH_DAVINCI
select VIDEOBUF2_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
help
- Enables Davinci VPIF module used for captur devices.
- This module is common for following DM6467/DA850/OMAPL138
- based capture devices.
+ Enables Davinci VPIF module used for capture devices.
+ This module is used for capture on TI DM6467/DA850/OMAPL138
+ SoCs.
- To compile this driver as a module, choose M here: the
- module will be called vpif_capture.
+ To compile this driver as a module, choose M here. There will
+ be two modules called vpif.ko and vpif_capture.ko
-config VIDEO_DAVINCI_VPIF
- tristate "DaVinci VPIF Driver"
- depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE
- help
- Support for DaVinci VPIF Driver.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif.
-
-config VIDEO_VPSS_SYSTEM
- tristate "VPSS System module driver"
- depends on ARCH_DAVINCI
- help
- Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
- tristate "VPFE Video Capture Driver"
+config VIDEO_DM6446_CCDC
+ tristate "TI DM6446 CCDC video capture driver"
depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
- depends on I2C
select VIDEOBUF_DMA_CONTIG
help
- Support for DMx/AMx VPFE based frame grabber. This is the
- common V4L2 module for following DMx/AMx SoCs from Texas
- Instruments:- DM6446, DM365, DM355 & AM3517/05.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
- tristate "DM6446 CCDC HW module"
- depends on VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
with decoder modules such as TVP5146 over BT656 or
sensor module such as MT9T001 over a raw interface. This
module configures the interface and CCDC/ISIF to do
video frame capture from slave decoders.
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
+ To compile this driver as a module, choose M here. There will
+ be three modules called vpfe_capture.ko, vpss.ko and dm644x_ccdc.ko
config VIDEO_DM355_CCDC
- tristate "DM355 CCDC HW module"
- depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
+ tristate "TI DM355 CCDC video capture driver"
+ depends on VIDEO_V4L2 && ARCH_DAVINCI
+ select VIDEOBUF_DMA_CONTIG
help
Enables DM355 CCD hw module. DM355 CCDC hw interfaces
with decoder modules such as TVP5146 over BT656 or
@@ -81,31 +49,30 @@ config VIDEO_DM355_CCDC
module configures the interface and CCDC/ISIF to do
video frame capture from a slave decoders
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
+ To compile this driver as a module, choose M here. There will
+ be three modules called vpfe_capture.ko, vpss.ko and dm355_ccdc.ko
-config VIDEO_ISIF
- tristate "ISIF HW module"
- depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
+config VIDEO_DM365_ISIF
+ tristate "TI DM365 ISIF video capture driver"
+ depends on VIDEO_V4L2 && ARCH_DAVINCI
+ select VIDEOBUF_DMA_CONTIG
help
Enables ISIF hw module. This is the hardware module for
- configuring ISIF in VPFE to capture Raw Bayer RGB data from
+ configuring ISIF in VPFE to capture Raw Bayer RGB data from
a image sensor or YUV data from a YUV source.
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
+ To compile this driver as a module, choose M here. There will
+ be three modules called vpfe_capture.ko, vpss.ko and isif.ko
config VIDEO_DAVINCI_VPBE_DISPLAY
- tristate "DM644X/DM365/DM355 VPBE HW module"
- depends on ARCH_DAVINCI_DM644x || ARCH_DAVINCI_DM355 || ARCH_DAVINCI_DM365
- select VIDEO_VPSS_SYSTEM
+ tristate "TI DaVinci VPBE V4L2-Display driver"
+ depends on ARCH_DAVINCI
select VIDEOBUF2_DMA_CONTIG
help
Enables Davinci VPBE module used for display devices.
- This module is common for following DM644x/DM365/DM355
+ This module is used for display on TI DM644x/DM365/DM355
based display devices.
- To compile this driver as a module, choose M here: the
- module will be called vpbe.
+ To compile this driver as a module, choose M here. There will
+ be five modules created called vpss.ko, vpbe.ko, vpbe_osd.ko,
+ vpbe_venc.ko and vpbe_display.ko
diff --git a/drivers/media/platform/davinci/Makefile b/drivers/media/platform/davinci/Makefile
index f40f5219ca50..d74d9eeb0e9e 100644
--- a/drivers/media/platform/davinci/Makefile
+++ b/drivers/media/platform/davinci/Makefile
@@ -2,19 +2,14 @@
# Makefile for the davinci video device drivers.
#
-# VPIF
-obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o
-
#VPIF Display driver
-obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif_display.o
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif.o vpif_display.o
#VPIF Capture driver
-obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif_capture.o
+obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif.o vpif_capture.o
# Capture: DM6446 and DM355
-obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o
-obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o
-obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o
-obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o
-obj-$(CONFIG_VIDEO_ISIF) += isif.o
-obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpbe.o vpbe_osd.o \
+obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o vpss.o dm644x_ccdc.o
+obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o vpss.o dm355_ccdc.o
+obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o vpss.o isif.o
+obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpss.o vpbe.o vpbe_osd.o \
vpbe_venc.o vpbe_display.o
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
index 4277e4ad810c..05f8fb7f7b70 100644
--- a/drivers/media/platform/davinci/dm355_ccdc.c
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -37,7 +37,6 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/videodev2.h>
-#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -59,10 +58,6 @@ static struct ccdc_oper_config {
struct ccdc_params_raw bayer;
/* YCbCr configuration */
struct ccdc_params_ycbcr ycbcr;
- /* Master clock */
- struct clk *mclk;
- /* slave clock */
- struct clk *sclk;
/* ccdc base address */
void __iomem *base_addr;
} ccdc_cfg = {
@@ -85,7 +80,7 @@ static struct ccdc_oper_config {
.mfilt1 = CCDC_NO_MEDIAN_FILTER1,
.mfilt2 = CCDC_NO_MEDIAN_FILTER2,
.alaw = {
- .gama_wd = 2,
+ .gamma_wd = 2,
},
.blk_clamp = {
.sample_pixel = 1,
@@ -303,8 +298,8 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
}
if (ccdcparam->alaw.enable) {
- if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
- ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
+ if (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_13_4 ||
+ ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) {
dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
return -EINVAL;
}
@@ -680,8 +675,8 @@ static int ccdc_config_raw(void)
/* Enable and configure aLaw register if needed */
if (config_params->alaw.enable) {
val |= (CCDC_ALAW_ENABLE |
- ((config_params->alaw.gama_wd &
- CCDC_ALAW_GAMA_WD_MASK) <<
+ ((config_params->alaw.gamma_wd &
+ CCDC_ALAW_GAMMA_WD_MASK) <<
CCDC_GAMMAWD_INPUT_SHIFT));
}
@@ -997,32 +992,10 @@ static int dm355_ccdc_probe(struct platform_device *pdev)
goto fail_nomem;
}
- /* Get and enable Master clock */
- ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(ccdc_cfg.mclk)) {
- status = PTR_ERR(ccdc_cfg.mclk);
- goto fail_nomap;
- }
- if (clk_prepare_enable(ccdc_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Get and enable Slave clock */
- ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
- if (IS_ERR(ccdc_cfg.sclk)) {
- status = PTR_ERR(ccdc_cfg.sclk);
- goto fail_mclk;
- }
- if (clk_prepare_enable(ccdc_cfg.sclk)) {
- status = -ENODEV;
- goto fail_sclk;
- }
-
/* Platform data holds setup_pinmux function ptr */
if (NULL == pdev->dev.platform_data) {
status = -ENODEV;
- goto fail_sclk;
+ goto fail_nomap;
}
setup_pinmux = pdev->dev.platform_data;
/*
@@ -1033,12 +1006,6 @@ static int dm355_ccdc_probe(struct platform_device *pdev)
ccdc_cfg.dev = &pdev->dev;
printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
return 0;
-fail_sclk:
- clk_disable_unprepare(ccdc_cfg.sclk);
- clk_put(ccdc_cfg.sclk);
-fail_mclk:
- clk_disable_unprepare(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.mclk);
fail_nomap:
iounmap(ccdc_cfg.base_addr);
fail_nomem:
@@ -1052,10 +1019,6 @@ static int dm355_ccdc_remove(struct platform_device *pdev)
{
struct resource *res;
- clk_disable_unprepare(ccdc_cfg.sclk);
- clk_disable_unprepare(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.sclk);
iounmap(ccdc_cfg.base_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
diff --git a/drivers/media/platform/davinci/dm355_ccdc_regs.h b/drivers/media/platform/davinci/dm355_ccdc_regs.h
index d6d2ef0533b5..2e1946e0b99f 100644
--- a/drivers/media/platform/davinci/dm355_ccdc_regs.h
+++ b/drivers/media/platform/davinci/dm355_ccdc_regs.h
@@ -153,7 +153,7 @@
#define CCDC_VDHDEN_ENABLE (1 << 16)
#define CCDC_LPF_ENABLE (1 << 14)
#define CCDC_ALAW_ENABLE 1
-#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_ALAW_GAMMA_WD_MASK 7
#define CCDC_REC656IF_BT656_EN 3
#define CCDC_FMTCFG_FMTMODE_MASK 3
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index 318e80512998..30fa08405d61 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -38,7 +38,6 @@
#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <linux/gfp.h>
-#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -60,10 +59,6 @@ static struct ccdc_oper_config {
struct ccdc_params_raw bayer;
/* YCbCr configuration */
struct ccdc_params_ycbcr ycbcr;
- /* Master clock */
- struct clk *mclk;
- /* slave clock */
- struct clk *sclk;
/* ccdc base address */
void __iomem *base_addr;
} ccdc_cfg = {
@@ -228,9 +223,12 @@ static void ccdc_readregs(void)
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
{
if (ccdcparam->alaw.enable) {
- if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) ||
- (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) ||
- (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) {
+ u8 max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd);
+ u8 max_data = ccdc_data_size_max_bit(ccdcparam->data_sz);
+
+ if ((ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) ||
+ (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_15_6) ||
+ (max_gamma > max_data)) {
dev_dbg(ccdc_cfg.dev, "\nInvalid data line select");
return -1;
}
@@ -560,8 +558,8 @@ void ccdc_config_raw(void)
/* Enable and configure aLaw register if needed */
if (config_params->alaw.enable) {
- val = ((config_params->alaw.gama_wd &
- CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE);
+ val = ((config_params->alaw.gamma_wd &
+ CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE);
regw(val, CCDC_ALAW);
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val);
}
@@ -988,38 +986,9 @@ static int dm644x_ccdc_probe(struct platform_device *pdev)
goto fail_nomem;
}
- /* Get and enable Master clock */
- ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(ccdc_cfg.mclk)) {
- status = PTR_ERR(ccdc_cfg.mclk);
- goto fail_nomap;
- }
- if (clk_prepare_enable(ccdc_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Get and enable Slave clock */
- ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
- if (IS_ERR(ccdc_cfg.sclk)) {
- status = PTR_ERR(ccdc_cfg.sclk);
- goto fail_mclk;
- }
- if (clk_prepare_enable(ccdc_cfg.sclk)) {
- status = -ENODEV;
- goto fail_sclk;
- }
ccdc_cfg.dev = &pdev->dev;
printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
return 0;
-fail_sclk:
- clk_disable_unprepare(ccdc_cfg.sclk);
- clk_put(ccdc_cfg.sclk);
-fail_mclk:
- clk_disable_unprepare(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.mclk);
-fail_nomap:
- iounmap(ccdc_cfg.base_addr);
fail_nomem:
release_mem_region(res->start, resource_size(res));
fail_nores:
@@ -1031,10 +1000,6 @@ static int dm644x_ccdc_remove(struct platform_device *pdev)
{
struct resource *res;
- clk_disable_unprepare(ccdc_cfg.mclk);
- clk_disable_unprepare(ccdc_cfg.sclk);
- clk_put(ccdc_cfg.mclk);
- clk_put(ccdc_cfg.sclk);
iounmap(ccdc_cfg.base_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
@@ -1049,18 +1014,12 @@ static int dm644x_ccdc_suspend(struct device *dev)
ccdc_save_context();
/* Disable CCDC */
ccdc_enable(0);
- /* Disable both master and slave clock */
- clk_disable_unprepare(ccdc_cfg.mclk);
- clk_disable_unprepare(ccdc_cfg.sclk);
return 0;
}
static int dm644x_ccdc_resume(struct device *dev)
{
- /* Enable both master and slave clock */
- clk_prepare_enable(ccdc_cfg.mclk);
- clk_prepare_enable(ccdc_cfg.sclk);
/* Restore CCDC context */
ccdc_restore_context();
diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
index 90370e414e2c..2b0aca5383f0 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h
+++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
@@ -84,7 +84,7 @@
#define CCDC_VDHDEN_ENABLE (1 << 16)
#define CCDC_LPF_ENABLE (1 << 14)
#define CCDC_ALAW_ENABLE (1 << 3)
-#define CCDC_ALAW_GAMA_WD_MASK 7
+#define CCDC_ALAW_GAMMA_WD_MASK 7
#define CCDC_BLK_CLAMP_ENABLE (1 << 31)
#define CCDC_BLK_SGAIN_MASK 0x1F
#define CCDC_BLK_ST_PXL_MASK 0x7FFF
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
index 5050f9265f48..3332cca632e5 100644
--- a/drivers/media/platform/davinci/isif.c
+++ b/drivers/media/platform/davinci/isif.c
@@ -32,7 +32,6 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/videodev2.h>
-#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
@@ -88,8 +87,6 @@ static struct isif_oper_config {
struct isif_ycbcr_config ycbcr;
struct isif_params_raw bayer;
enum isif_data_pack data_pack;
- /* Master clock */
- struct clk *mclk;
/* ISIF base address */
void __iomem *base_addr;
/* ISIF Linear Table 0 */
@@ -604,7 +601,7 @@ static int isif_config_raw(void)
if (module_params->compress.alg == ISIF_ALAW)
val |= ISIF_ALAW_ENABLE;
- val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
+ val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT);
regw(val, CGAMMAWD);
/* Configure DPCM compression settings */
@@ -1039,6 +1036,10 @@ static int isif_probe(struct platform_device *pdev)
void *__iomem addr;
int status = 0, i;
+ /* Platform data holds setup_pinmux function ptr */
+ if (!pdev->dev.platform_data)
+ return -ENODEV;
+
/*
* first try to register with vpfe. If not correct platform, then we
* don't have to iomap
@@ -1047,22 +1048,6 @@ static int isif_probe(struct platform_device *pdev)
if (status < 0)
return status;
- /* Get and enable Master clock */
- isif_cfg.mclk = clk_get(&pdev->dev, "master");
- if (IS_ERR(isif_cfg.mclk)) {
- status = PTR_ERR(isif_cfg.mclk);
- goto fail_mclk;
- }
- if (clk_prepare_enable(isif_cfg.mclk)) {
- status = -ENODEV;
- goto fail_mclk;
- }
-
- /* Platform data holds setup_pinmux function ptr */
- if (NULL == pdev->dev.platform_data) {
- status = -ENODEV;
- goto fail_mclk;
- }
setup_pinmux = pdev->dev.platform_data;
/*
* setup Mux configuration for ccdc which may be different for
@@ -1124,9 +1109,6 @@ fail_nobase_res:
release_mem_region(res->start, resource_size(res));
i--;
}
-fail_mclk:
- clk_disable_unprepare(isif_cfg.mclk);
- clk_put(isif_cfg.mclk);
vpfe_unregister_ccdc_device(&isif_hw_dev);
return status;
}
@@ -1146,8 +1128,6 @@ static int isif_remove(struct platform_device *pdev)
i++;
}
vpfe_unregister_ccdc_device(&isif_hw_dev);
- clk_disable_unprepare(isif_cfg.mclk);
- clk_put(isif_cfg.mclk);
return 0;
}
diff --git a/drivers/media/platform/davinci/isif_regs.h b/drivers/media/platform/davinci/isif_regs.h
index aa69a463c122..3993aece821b 100644
--- a/drivers/media/platform/davinci/isif_regs.h
+++ b/drivers/media/platform/davinci/isif_regs.h
@@ -203,8 +203,8 @@
#define ISIF_LPF_MASK 1
/* GAMMAWD registers */
-#define ISIF_ALAW_GAMA_WD_MASK 0xF
-#define ISIF_ALAW_GAMA_WD_SHIFT 1
+#define ISIF_ALAW_GAMMA_WD_MASK 0xF
+#define ISIF_ALAW_GAMMA_WD_SHIFT 1
#define ISIF_ALAW_ENABLE 1
#define ISIF_GAMMAWD_CFA_SHIFT 5
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index 4ca0f9a2ad8a..33b9660b7f77 100644
--- a/drivers/media/platform/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -344,7 +344,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev,
return -EINVAL;
for (i = 0; i < output->num_modes; i++) {
- if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS &&
+ if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS &&
!memcmp(&output->modes[i].dv_timings,
dv_timings, sizeof(*dv_timings)))
break;
@@ -385,7 +385,7 @@ static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev,
struct v4l2_dv_timings *dv_timings)
{
if (vpbe_dev->current_timings.timings_type &
- VPBE_ENC_CUSTOM_TIMINGS) {
+ VPBE_ENC_DV_TIMINGS) {
*dv_timings = vpbe_dev->current_timings.dv_timings;
return 0;
}
@@ -412,7 +412,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev,
return -EINVAL;
for (i = 0; i < output->num_modes; i++) {
- if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) {
+ if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) {
if (j == timings->index)
break;
j++;
@@ -431,7 +431,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev,
* Sets the standard if supported by the current encoder. Return the status.
* 0 - success & -EINVAL on error
*/
-static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
+static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id)
{
struct vpbe_config *cfg = vpbe_dev->cfg;
int out_index = vpbe_dev->current_out_index;
@@ -442,14 +442,14 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
V4L2_OUT_CAP_STD))
return -EINVAL;
- ret = vpbe_get_std_info(vpbe_dev, *std_id);
+ ret = vpbe_get_std_info(vpbe_dev, std_id);
if (ret)
return ret;
mutex_lock(&vpbe_dev->lock);
ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video,
- s_std_output, *std_id);
+ s_std_output, std_id);
/* set the lcd controller output for the given mode */
if (!ret) {
struct osd_state *osd_device = vpbe_dev->osd_device;
@@ -513,9 +513,9 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev,
*/
if (preset_mode->timings_type & VPBE_ENC_STD)
return vpbe_s_std(vpbe_dev,
- &preset_mode->std_id);
+ preset_mode->std_id);
if (preset_mode->timings_type &
- VPBE_ENC_CUSTOM_TIMINGS) {
+ VPBE_ENC_DV_TIMINGS) {
dv_timings =
preset_mode->dv_timings;
return vpbe_s_dv_timings(vpbe_dev, &dv_timings);
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 5e6b0cab514b..1802f11e939f 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -983,7 +983,7 @@ static int vpbe_display_try_fmt(struct file *file, void *priv,
* 0 - success & -EINVAL on error
*/
static int vpbe_display_s_std(struct file *file, void *priv,
- v4l2_std_id *std_id)
+ v4l2_std_id std_id)
{
struct vpbe_fh *fh = priv;
struct vpbe_layer *layer = fh->layer;
@@ -1176,10 +1176,6 @@ vpbe_display_s_dv_timings(struct file *file, void *priv,
"Failed to set the dv timings info\n");
return -EINVAL;
}
- /* set the current norm to zero to be consistent. If STD is used
- * v4l2 layer will set the norm properly on successful s_std call
- */
- layer->video_dev.current_norm = 0;
return 0;
}
@@ -1202,7 +1198,7 @@ vpbe_display_g_dv_timings(struct file *file, void *priv,
/* Get the given standard in the encoder */
if (vpbe_dev->current_timings.timings_type &
- VPBE_ENC_CUSTOM_TIMINGS) {
+ VPBE_ENC_DV_TIMINGS) {
*dv_timings = vpbe_dev->current_timings.dv_timings;
} else {
return -EINVAL;
@@ -1404,6 +1400,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpbe_disp_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret) {
@@ -1600,7 +1597,7 @@ static int vpbe_display_g_register(struct file *file, void *priv,
}
static int vpbe_display_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
return 0;
}
@@ -1693,12 +1690,8 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
vbd->vfl_dir = VFL_DIR_TX;
if (disp_dev->vpbe_dev->current_timings.timings_type &
- VPBE_ENC_STD) {
+ VPBE_ENC_STD)
vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50);
- vbd->current_norm =
- disp_dev->vpbe_dev->current_timings.std_id;
- } else
- vbd->current_norm = 0;
snprintf(vbd->name, sizeof(vbd->name),
"DaVinci_VPBE Display_DRIVER_V%d.%d.%d",
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 12ad17c52ef3..396a51cbede7 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -52,6 +52,9 @@ static struct platform_device_id vpbe_osd_devtype[] = {
.name = DM355_VPBE_OSD_SUBDEV_NAME,
.driver_data = VPBE_VERSION_3,
},
+ {
+ /* sentinel */
+ }
};
MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype);
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index bdbebd59df98..87eef9be08ed 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -51,6 +51,9 @@ static struct platform_device_id vpbe_venc_devtype[] = {
.name = DM355_VPBE_VENC_SUBDEV_NAME,
.driver_data = VPBE_VERSION_3,
},
+ {
+ /* sentinel */
+ }
};
MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype);
@@ -199,6 +202,25 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable)
}
}
+static void
+venc_enable_vpss_clock(int venc_type,
+ enum vpbe_enc_timings_type type,
+ unsigned int pclock)
+{
+ if (venc_type == VPBE_VERSION_1)
+ return;
+
+ if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type ==
+ VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) {
+ vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1);
+ vpss_enable_clock(VPSS_VPBE_CLOCK, 1);
+ return;
+ }
+
+ if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD)
+ vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0);
+}
+
#define VDAC_CONFIG_SD_V3 0x0E21A6B6
#define VDAC_CONFIG_SD_V2 0x081141CF
/*
@@ -217,6 +239,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd)
if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60);
venc_enabledigitaloutput(sd, 0);
if (venc->venc_type == VPBE_VERSION_3) {
@@ -262,6 +285,7 @@ static int venc_set_pal(struct v4l2_subdev *sd)
if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50);
venc_enabledigitaloutput(sd, 0);
if (venc->venc_type == VPBE_VERSION_3) {
@@ -313,9 +337,10 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd)
return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
- if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0)
+ if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000);
venc_enabledigitaloutput(sd, 0);
if (venc->venc_type == VPBE_VERSION_2)
@@ -360,9 +385,10 @@ static int venc_set_576p50(struct v4l2_subdev *sd)
venc->venc_type != VPBE_VERSION_2)
return -EINVAL;
/* Setup clock at VPSS & VENC for SD */
- if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0)
+ if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000);
venc_enabledigitaloutput(sd, 0);
if (venc->venc_type == VPBE_VERSION_2)
@@ -400,9 +426,10 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd)
struct venc_state *venc = to_state(sd);
struct venc_platform_data *pdata = venc->pdata;
- if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0)
+ if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000);
venc_enabledigitaloutput(sd, 0);
venc_write(sd, VENC_OSDCLK0, 0);
@@ -428,9 +455,10 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd)
struct venc_state *venc = to_state(sd);
struct venc_platform_data *pdata = venc->pdata;
- if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0)
+ if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0)
return -EINVAL;
+ venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000);
venc_enabledigitaloutput(sd, 0);
venc_write(sd, VENC_OSDCLK0, 0);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 28d019da4c01..8c50d3074866 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -376,7 +376,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
* values in ccdc
*/
static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
- const v4l2_std_id *std_id)
+ v4l2_std_id std_id)
{
struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
struct v4l2_mbus_framefmt mbus_fmt;
@@ -384,7 +384,7 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
- if (vpfe_standards[i].std_id & *std_id) {
+ if (vpfe_standards[i].std_id & std_id) {
vpfe_dev->std_info.active_pixels =
vpfe_standards[i].width;
vpfe_dev->std_info.active_lines =
@@ -461,7 +461,7 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev)
/* Configure the default format information */
ret = vpfe_config_image_format(vpfe_dev,
- &vpfe_standards[vpfe_dev->std_index].std_id);
+ vpfe_standards[vpfe_dev->std_index].std_id);
if (ret)
return ret;
@@ -1107,6 +1107,7 @@ static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
{
struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct v4l2_subdev *sd;
struct vpfe_subdev_info *sdinfo;
int subdev_index, inp_index;
struct vpfe_route *route;
@@ -1138,14 +1139,15 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
}
sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index];
+ sd = vpfe_dev->sd[subdev_index];
route = &sdinfo->routes[inp_index];
if (route && sdinfo->can_route) {
input = route->input;
output = route->output;
}
- ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- video, s_routing, input, output, 0);
+ if (sd)
+ ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0);
if (ret) {
v4l2_err(&vpfe_dev->v4l2_dev,
@@ -1154,6 +1156,8 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
goto unlock_out;
}
vpfe_dev->current_subdev = sdinfo;
+ if (sd)
+ vpfe_dev->v4l2_dev.ctrl_handler = sd->ctrl_handler;
vpfe_dev->current_input = index;
vpfe_dev->std_index = 0;
@@ -1164,7 +1168,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
/* set the default image parameters in the device */
ret = vpfe_config_image_format(vpfe_dev,
- &vpfe_standards[vpfe_dev->std_index].std_id);
+ vpfe_standards[vpfe_dev->std_index].std_id);
unlock_out:
mutex_unlock(&vpfe_dev->lock);
return ret;
@@ -1189,7 +1193,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
return ret;
}
-static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
struct vpfe_device *vpfe_dev = video_drvdata(file);
struct vpfe_subdev_info *sdinfo;
@@ -1211,7 +1215,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
}
ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_std, *std_id);
+ core, s_std, std_id);
if (ret < 0) {
v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
goto unlock_out;
@@ -1439,41 +1443,6 @@ static int vpfe_dqbuf(struct file *file, void *priv,
buf, file->f_flags & O_NONBLOCK);
}
-static int vpfe_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, queryctrl, qctrl);
-
-}
-
-static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, g_ctrl, ctrl);
-}
-
-static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl)
-{
- struct vpfe_device *vpfe_dev = video_drvdata(file);
- struct vpfe_subdev_info *sdinfo;
-
- sdinfo = vpfe_dev->current_subdev;
-
- return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_ctrl, ctrl);
-}
-
/*
* vpfe_calculate_offsets : This function calculates buffers offset
* for top and bottom field
@@ -1717,7 +1686,7 @@ unlock_out:
static long vpfe_param_handler(struct file *file, void *priv,
- bool valid_prio, int cmd, void *param)
+ bool valid_prio, unsigned int cmd, void *param)
{
struct vpfe_device *vpfe_dev = video_drvdata(file);
int ret = 0;
@@ -1781,9 +1750,6 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
.vidioc_querystd = vpfe_querystd,
.vidioc_s_std = vpfe_s_std,
.vidioc_g_std = vpfe_g_std,
- .vidioc_queryctrl = vpfe_queryctrl,
- .vidioc_g_ctrl = vpfe_g_ctrl,
- .vidioc_s_ctrl = vpfe_s_ctrl,
.vidioc_reqbufs = vpfe_reqbufs,
.vidioc_querybuf = vpfe_querybuf,
.vidioc_qbuf = vpfe_qbuf,
@@ -1918,7 +1884,6 @@ static int vpfe_probe(struct platform_device *pdev)
vfd->fops = &vpfe_fops;
vfd->ioctl_ops = &vpfe_ioctl_ops;
vfd->tvnorms = 0;
- vfd->current_norm = V4L2_STD_PAL;
vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
snprintf(vfd->name, sizeof(vfd->name),
"%s_V%d.%d.%d",
@@ -2007,6 +1972,7 @@ static int vpfe_probe(struct platform_device *pdev)
/* set first sub device as current one */
vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0];
+ vpfe_dev->v4l2_dev.ctrl_handler = vpfe_dev->sd[0]->ctrl_handler;
/* We have at least one sub device to work with */
mutex_unlock(&ccdc_lock);
diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c
index 28638a86f129..ea82a8bd2803 100644
--- a/drivers/media/platform/davinci/vpif.c
+++ b/drivers/media/platform/davinci/vpif.c
@@ -23,8 +23,8 @@
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/io.h>
-#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/pm_runtime.h>
#include <linux/v4l2-dv-timings.h>
#include <mach/hardware.h>
@@ -44,13 +44,13 @@ static struct resource *res;
spinlock_t vpif_lock;
void __iomem *vpif_base;
-struct clk *vpif_clk;
+EXPORT_SYMBOL_GPL(vpif_base);
/**
- * ch_params: video standard configuration parameters for vpif
+ * vpif_ch_params: video standard configuration parameters for vpif
* The table must include all presets from supported subdevices.
*/
-const struct vpif_channel_config_params ch_params[] = {
+const struct vpif_channel_config_params vpif_ch_params[] = {
/* HDTV formats */
{
.name = "480p59_94",
@@ -220,8 +220,10 @@ const struct vpif_channel_config_params ch_params[] = {
.stdid = V4L2_STD_625_50,
},
};
+EXPORT_SYMBOL_GPL(vpif_ch_params);
-const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(vpif_ch_params);
+EXPORT_SYMBOL_GPL(vpif_ch_params_count);
static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
{
@@ -439,19 +441,13 @@ static int vpif_probe(struct platform_device *pdev)
goto fail;
}
- vpif_clk = clk_get(&pdev->dev, "vpif");
- if (IS_ERR(vpif_clk)) {
- status = PTR_ERR(vpif_clk);
- goto clk_fail;
- }
- clk_prepare_enable(vpif_clk);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get(&pdev->dev);
spin_lock_init(&vpif_lock);
dev_info(&pdev->dev, "vpif probe success\n");
return 0;
-clk_fail:
- iounmap(vpif_base);
fail:
release_mem_region(res->start, res_len);
return status;
@@ -459,11 +455,7 @@ fail:
static int vpif_remove(struct platform_device *pdev)
{
- if (vpif_clk) {
- clk_disable_unprepare(vpif_clk);
- clk_put(vpif_clk);
- }
-
+ pm_runtime_disable(&pdev->dev);
iounmap(vpif_base);
release_mem_region(res->start, res_len);
return 0;
@@ -472,13 +464,13 @@ static int vpif_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int vpif_suspend(struct device *dev)
{
- clk_disable_unprepare(vpif_clk);
+ pm_runtime_put(dev);
return 0;
}
static int vpif_resume(struct device *dev)
{
- clk_prepare_enable(vpif_clk);
+ pm_runtime_get(dev);
return 0;
}
diff --git a/drivers/media/platform/davinci/vpif.h b/drivers/media/platform/davinci/vpif.h
index a1ab6a0f4e9e..9956e6788693 100644
--- a/drivers/media/platform/davinci/vpif.h
+++ b/drivers/media/platform/davinci/vpif.h
@@ -638,7 +638,7 @@ struct vpif_channel_config_params {
};
extern const unsigned int vpif_ch_params_count;
-extern const struct vpif_channel_config_params ch_params[];
+extern const struct vpif_channel_config_params vpif_ch_params[];
struct vpif_video_params;
struct vpif_params;
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 5892d2bc8eee..5f98df1fc8a0 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -563,7 +563,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
vpif_dbg(2, debug, "vpif_update_std_info\n");
for (index = 0; index < vpif_ch_params_count; index++) {
- config = &ch_params[index];
+ config = &vpif_ch_params[index];
if (config->hd_sd == 0) {
vpif_dbg(2, debug, "SD format\n");
if (config->stdid & vid_ch->stdid) {
@@ -1035,6 +1035,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_cap_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret) {
@@ -1394,7 +1395,7 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
* @priv: file handle
* @std_id: ptr to std id
*/
-static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
@@ -1423,7 +1424,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
fh->initialized = 1;
/* Call encoder subdevice function to set the standard */
- ch->video.stdid = *std_id;
+ ch->video.stdid = std_id;
memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));
/* Get the information about the standard */
@@ -1436,7 +1437,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
vpif_config_format(ch);
/* set standard in the sub device */
- ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id);
+ ret = v4l2_subdev_call(ch->sd, core, s_std, std_id);
if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
return ret;
@@ -1923,7 +1924,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv,
* Returns zero or -EINVAL if write operations fails.
*/
static int vpif_dbg_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
+ const struct v4l2_dbg_register *reg)
+{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index dd249c96126d..1b3fb5ca2ad4 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -511,7 +511,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
int i;
for (i = 0; i < vpif_ch_params_count; i++) {
- config = &ch_params[i];
+ config = &vpif_ch_params[i];
if (config->hd_sd == 0) {
vpif_dbg(2, debug, "SD format\n");
if (config->stdid & vid_ch->stdid) {
@@ -1001,6 +1001,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_disp_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret) {
@@ -1058,14 +1059,14 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
return vb2_qbuf(&common->buffer_queue, buf);
}
-static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
int ret = 0;
- if (!(*std_id & VPIF_V4L2_STD))
+ if (!(std_id & VPIF_V4L2_STD))
return -EINVAL;
if (common->started) {
@@ -1074,7 +1075,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
}
/* Call encoder subdevice function to set the standard */
- ch->video.stdid = *std_id;
+ ch->video.stdid = std_id;
memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));
/* Get the information about the standard */
if (vpif_update_resolution(ch))
@@ -1092,14 +1093,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
vpif_config_format(ch);
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
- s_std_output, *std_id);
+ s_std_output, std_id);
if (ret < 0) {
vpif_err("Failed to set output standard\n");
return ret;
}
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
- s_std, *std_id);
+ s_std, std_id);
if (ret < 0)
vpif_err("Failed to set standard for sub devices\n");
return ret;
@@ -1567,7 +1568,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv,
* Returns zero or -EINVAL if write operations fails.
*/
static int vpif_dbg_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg){
+ const struct v4l2_dbg_register *reg)
+{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index a19c552232d1..8a2f01e344ee 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -17,14 +17,11 @@
*
* common vpss system module platform driver for all video drivers.
*/
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/compiler.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
+
#include <media/davinci/vpss.h>
MODULE_LICENSE("GPL");
@@ -99,7 +96,7 @@ enum vpss_platform_type {
/*
* vpss operations. Depends on platform. Not all functions are available
- * on all platforms. The api, first check if a functio is available before
+ * on all platforms. The api, first check if a function is available before
* invoking it. In the probe, the function ptrs are initialized based on
* vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
*/
@@ -114,7 +111,7 @@ struct vpss_hw_ops {
void (*set_sync_pol)(struct vpss_sync_pol);
/* set the PG_FRAME_SIZE register*/
void (*set_pg_frame_size)(struct vpss_pg_frame_size);
- /* check and clear interrupt if occured */
+ /* check and clear interrupt if occurred */
int (*dma_complete_interrupt)(void);
};
@@ -233,7 +230,7 @@ EXPORT_SYMBOL(vpss_clear_wbl_overflow);
/*
* dm355_enable_clock - Enable VPSS Clock
- * @clock_sel: CLock to be enabled/disabled
+ * @clock_sel: Clock to be enabled/disabled
* @en: enable/disable flag
*
* This is called to enable or disable a vpss clock
@@ -490,6 +487,10 @@ static int vpss_probe(struct platform_device *pdev)
} else
oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow;
+ pm_runtime_enable(&pdev->dev);
+
+ pm_runtime_get(&pdev->dev);
+
spin_lock_init(&oper_cfg.vpss_lock);
dev_info(&pdev->dev, "%s vpss probe success\n", platform_name);
return 0;
@@ -507,6 +508,7 @@ static int vpss_remove(struct platform_device *pdev)
{
struct resource *res;
+ pm_runtime_disable(&pdev->dev);
iounmap(oper_cfg.vpss_regs_base0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
@@ -518,10 +520,28 @@ static int vpss_remove(struct platform_device *pdev)
return 0;
}
+static int vpss_suspend(struct device *dev)
+{
+ pm_runtime_put(dev);
+ return 0;
+}
+
+static int vpss_resume(struct device *dev)
+{
+ pm_runtime_get(dev);
+ return 0;
+}
+
+static const struct dev_pm_ops vpss_pm_ops = {
+ .suspend = vpss_suspend,
+ .resume = vpss_resume,
+};
+
static struct platform_driver vpss_driver = {
.driver = {
.name = "vpss",
.owner = THIS_MODULE,
+ .pm = &vpss_pm_ops,
},
.remove = vpss_remove,
.probe = vpss_probe,
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 82d9f6ac12f3..33b5ffc8d66d 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -1054,16 +1054,18 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc)
static int gsc_m2m_resume(struct gsc_dev *gsc)
{
+ struct gsc_ctx *ctx;
unsigned long flags;
spin_lock_irqsave(&gsc->slock, flags);
/* Clear for full H/W setup in first run after resume */
+ ctx = gsc->m2m.ctx;
gsc->m2m.ctx = NULL;
spin_unlock_irqrestore(&gsc->slock, flags);
if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
- gsc_m2m_job_finish(gsc->m2m.ctx,
- VB2_BUF_STATE_ERROR);
+ gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
return 0;
}
@@ -1204,7 +1206,7 @@ static int gsc_resume(struct device *dev)
/* Do not resume if the device was idle before system suspend */
spin_lock_irqsave(&gsc->slock, flags);
if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
- !gsc_m2m_active(gsc)) {
+ !gsc_m2m_opened(gsc)) {
spin_unlock_irqrestore(&gsc->slock, flags);
return 0;
}
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 386c0a7a3a52..40a73f7d20da 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -80,6 +80,9 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_vb && dst_vb) {
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_vb, vb_state);
v4l2_m2m_buf_done(dst_vb, vb_state);
@@ -584,6 +587,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &gsc_m2m_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -596,6 +600,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &gsc_m2m_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c
index 6f5b5a486cf3..e22d147a6940 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.c
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.c
@@ -12,7 +12,6 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include <mach/map.h>
#include "gsc-core.h"
diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/exynos4-is/Kconfig
index f997a5203b7c..6ff99b5849f9 100644
--- a/drivers/media/platform/s5p-fimc/Kconfig
+++ b/drivers/media/platform/exynos4-is/Kconfig
@@ -1,21 +1,22 @@
-config VIDEO_SAMSUNG_S5P_FIMC
- bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
+config VIDEO_SAMSUNG_EXYNOS4_IS
+ bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
help
Say Y here to enable camera host interface devices for
Samsung S5P and EXYNOS SoC series.
-if VIDEO_SAMSUNG_S5P_FIMC
+if VIDEO_SAMSUNG_EXYNOS4_IS
config VIDEO_S5P_FIMC
tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
depends on I2C
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
+ select MFD_SYSCON if OF
help
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
- interface and video postprocessor (FIMC and FIMC-LITE) devices.
+ interface and video postprocessor (FIMC) devices.
To compile this driver as a module, choose M here: the
module will be called s5p-fimc.
@@ -45,4 +46,16 @@ config VIDEO_EXYNOS_FIMC_LITE
module will be called exynos-fimc-lite.
endif
+config VIDEO_EXYNOS4_FIMC_IS
+ tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
+ select VIDEOBUF2_DMA_CONTIG
+ depends on OF
+ select FW_LOADER
+ help
+ This is a V4L2 driver for Samsung EXYNOS4x12 SoC series
+ FIMC-IS (Imaging Subsystem).
+
+ To compile this driver as a module, choose M here: the
+ module will be called exynos4-fimc-is.
+
endif # VIDEO_SAMSUNG_S5P_FIMC
diff --git a/drivers/media/platform/s5p-fimc/Makefile b/drivers/media/platform/exynos4-is/Makefile
index 46485143e1ca..f25f46377399 100644
--- a/drivers/media/platform/s5p-fimc/Makefile
+++ b/drivers/media/platform/exynos4-is/Makefile
@@ -1,7 +1,10 @@
-s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o media-dev.o
exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
+exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
+exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
s5p-csis-objs := mipi-csis.o
obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o
+obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o
obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index f553cc2a8ee8..528f41369364 100644
--- a/drivers/media/platform/s5p-fimc/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -27,32 +27,33 @@
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
-#include "fimc-mdevice.h"
+#include "media-dev.h"
#include "fimc-core.h"
#include "fimc-reg.h"
static int fimc_capture_hw_init(struct fimc_dev *fimc)
{
+ struct fimc_source_info *si = &fimc->vid_cap.source_config;
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- struct fimc_pipeline *p = &fimc->pipeline;
- struct fimc_sensor_info *sensor;
+ int ret;
unsigned long flags;
- int ret = 0;
- if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
- return -ENXIO;
- if (ctx->s_frame.fmt == NULL)
+ if (ctx == NULL || ctx->s_frame.fmt == NULL)
return -EINVAL;
- sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
+ if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) {
+ ret = fimc_hw_camblk_cfg_writeback(fimc);
+ if (ret < 0)
+ return ret;
+ }
spin_lock_irqsave(&fimc->slock, flags);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
fimc_set_yuv_order(ctx);
- fimc_hw_set_camera_polarity(fimc, &sensor->pdata);
- fimc_hw_set_camera_type(fimc, &sensor->pdata);
- fimc_hw_set_camera_source(fimc, &sensor->pdata);
+ fimc_hw_set_camera_polarity(fimc, si);
+ fimc_hw_set_camera_type(fimc, si);
+ fimc_hw_set_camera_source(fimc, si);
fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
ret = fimc_set_scaler_info(ctx);
@@ -65,7 +66,7 @@ static int fimc_capture_hw_init(struct fimc_dev *fimc)
fimc_hw_set_effect(ctx);
fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx);
- if (fimc->variant->has_alpha)
+ if (fimc->drv_data->alpha_color)
fimc_hw_set_rgb_alpha(ctx);
clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
}
@@ -168,7 +169,7 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx)
fimc_hw_set_effect(ctx);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
fimc_hw_set_out_dma(ctx);
- if (fimc->variant->has_alpha)
+ if (fimc->drv_data->alpha_color)
fimc_hw_set_rgb_alpha(ctx);
clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
@@ -286,8 +287,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
fimc_activate_capture(ctx);
if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
- fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 1);
+ return fimc_pipeline_call(fimc, set_stream,
+ &fimc->pipeline, 1);
}
return 0;
@@ -443,35 +444,28 @@ static void buffer_queue(struct vb2_buffer *vb)
if (vb2_is_streaming(&vid_cap->vbq) &&
vid_cap->active_buf_cnt >= min_bufs &&
!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) {
+ int ret;
+
fimc_activate_capture(ctx);
spin_unlock_irqrestore(&fimc->slock, flags);
- if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
- fimc_pipeline_call(fimc, set_stream,
- &fimc->pipeline, 1);
+ if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
+ return;
+
+ ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1);
+ if (ret < 0)
+ v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret);
return;
}
spin_unlock_irqrestore(&fimc->slock, flags);
}
-static void fimc_lock(struct vb2_queue *vq)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_lock(&ctx->fimc_dev->lock);
-}
-
-static void fimc_unlock(struct vb2_queue *vq)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_unlock(&ctx->fimc_dev->lock);
-}
-
static struct vb2_ops fimc_capture_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = fimc_unlock,
- .wait_finish = fimc_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
@@ -530,7 +524,7 @@ static int fimc_capture_open(struct file *file)
goto unlock;
}
- if (++fimc->vid_cap.refcnt == 1) {
+ if (v4l2_fh_is_singular_file(file)) {
ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
&fimc->vid_cap.vfd.entity, true);
@@ -543,8 +537,9 @@ static int fimc_capture_open(struct file *file)
if (ret < 0) {
clear_bit(ST_CAPT_BUSY, &fimc->state);
pm_runtime_put_sync(&fimc->pdev->dev);
- fimc->vid_cap.refcnt--;
v4l2_fh_release(file);
+ } else {
+ fimc->vid_cap.refcnt++;
}
}
unlock:
@@ -553,59 +548,34 @@ unlock:
return ret;
}
-static int fimc_capture_close(struct file *file)
+static int fimc_capture_release(struct file *file)
{
struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
int ret;
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
mutex_lock(&fimc->lock);
- if (--fimc->vid_cap.refcnt == 0) {
+ if (v4l2_fh_is_singular_file(file)) {
+ if (vc->streaming) {
+ media_entity_pipeline_stop(&vc->vfd.entity);
+ vc->streaming = false;
+ }
clear_bit(ST_CAPT_BUSY, &fimc->state);
fimc_stop_capture(fimc, false);
fimc_pipeline_call(fimc, close, &fimc->pipeline);
clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
+ fimc->vid_cap.refcnt--;
}
pm_runtime_put(&fimc->pdev->dev);
- if (fimc->vid_cap.refcnt == 0) {
- vb2_queue_release(&fimc->vid_cap.vbq);
+ if (v4l2_fh_is_singular_file(file))
fimc_ctrls_delete(fimc->vid_cap.ctx);
- }
-
- ret = v4l2_fh_release(file);
-
- mutex_unlock(&fimc->lock);
- return ret;
-}
-
-static unsigned int fimc_capture_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct fimc_dev *fimc = video_drvdata(file);
- int ret;
-
- if (mutex_lock_interruptible(&fimc->lock))
- return POLL_ERR;
- ret = vb2_poll(&fimc->vid_cap.vbq, file, wait);
- mutex_unlock(&fimc->lock);
-
- return ret;
-}
-
-static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct fimc_dev *fimc = video_drvdata(file);
- int ret;
-
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
-
- ret = vb2_mmap(&fimc->vid_cap.vbq, vma);
+ ret = vb2_fop_release(file);
mutex_unlock(&fimc->lock);
return ret;
@@ -614,10 +584,10 @@ static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
static const struct v4l2_file_operations fimc_capture_fops = {
.owner = THIS_MODULE,
.open = fimc_capture_open,
- .release = fimc_capture_close,
- .poll = fimc_capture_poll,
+ .release = fimc_capture_release,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = fimc_capture_mmap,
+ .mmap = vb2_fop_mmap,
};
/*
@@ -642,18 +612,22 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
fimc_fmt_is_user_defined(ctx->s_frame.fmt->color))
*code = ctx->s_frame.fmt->mbus_code;
- if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK)
+ if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE)
mask |= FMT_FLAGS_M2M;
+ if (pad == FIMC_SD_PAD_SINK_FIFO)
+ mask = FMT_FLAGS_WRITEBACK;
+
ffmt = fimc_find_format(fourcc, code, mask, 0);
if (WARN_ON(!ffmt))
return NULL;
+
if (code)
*code = ffmt->mbus_code;
if (fourcc)
*fourcc = ffmt->fourcc;
- if (pad == FIMC_SD_PAD_SINK) {
+ if (pad != FIMC_SD_PAD_SOURCE) {
max_w = fimc_fmt_is_user_defined(ffmt->color) ?
pl->scaler_dis_w : pl->scaler_en_w;
/* Apply the camera input interface pixel constraints */
@@ -768,16 +742,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx,
/*
* The video node ioctl operations
*/
-static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+static int fimc_cap_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct fimc_dev *fimc = video_drvdata(file);
- strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
-
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE);
return 0;
}
@@ -887,7 +858,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
tfmt->width = mf->width;
tfmt->height = mf->height;
ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
- NULL, &fcc, FIMC_SD_PAD_SINK);
+ NULL, &fcc, FIMC_SD_PAD_SINK_CAM);
ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height,
NULL, &fcc, FIMC_SD_PAD_SOURCE);
if (ffmt && ffmt->mbus_code)
@@ -974,7 +945,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh,
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
- FIMC_SD_PAD_SINK);
+ FIMC_SD_PAD_SINK_CAM);
ctx->s_frame.f_width = pix->width;
ctx->s_frame.f_height = pix->height;
}
@@ -1028,7 +999,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
{
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf;
+ struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt;
struct fimc_frame *ff = &ctx->d_frame;
struct fimc_fmt *s_fmt = NULL;
int ret, i;
@@ -1040,7 +1011,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc,
if (fimc_jpeg_fourcc(pix->pixelformat)) {
fimc_capture_try_format(ctx, &pix->width, &pix->height,
NULL, &pix->pixelformat,
- FIMC_SD_PAD_SINK);
+ FIMC_SD_PAD_SINK_CAM);
ctx->s_frame.f_width = pix->width;
ctx->s_frame.f_height = pix->height;
}
@@ -1157,44 +1128,51 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i)
static int fimc_pipeline_validate(struct fimc_dev *fimc)
{
struct v4l2_subdev_format sink_fmt, src_fmt;
- struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
- struct v4l2_subdev *sd;
- struct media_pad *pad;
- int ret;
-
- /* Start with the video capture node pad */
- pad = media_entity_remote_source(&vid_cap->vd_pad);
- if (pad == NULL)
- return -EPIPE;
- /* FIMC.{N} subdevice */
- sd = media_entity_to_v4l2_subdev(pad->entity);
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct v4l2_subdev *sd = &vc->subdev;
+ struct media_pad *sink_pad, *src_pad;
+ int i, ret;
while (1) {
- /* Retrieve format at the sink pad */
- pad = &sd->entity.pads[0];
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ /*
+ * Find current entity sink pad and any remote sink pad linked
+ * to it. We stop if there is no sink pad in current entity or
+ * it is not linked to any other remote entity.
+ */
+ src_pad = NULL;
+
+ for (i = 0; i < sd->entity.num_pads; i++) {
+ struct media_pad *p = &sd->entity.pads[i];
+
+ if (p->flags & MEDIA_PAD_FL_SINK) {
+ sink_pad = p;
+ src_pad = media_entity_remote_source(sink_pad);
+ if (src_pad)
+ break;
+ }
+ }
+
+ if (src_pad == NULL ||
+ media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
+
/* Don't call FIMC subdev operation to avoid nested locking */
- if (sd == &fimc->vid_cap.subdev) {
- struct fimc_frame *ff = &vid_cap->ctx->s_frame;
+ if (sd == &vc->subdev) {
+ struct fimc_frame *ff = &vc->ctx->s_frame;
sink_fmt.format.width = ff->f_width;
sink_fmt.format.height = ff->f_height;
sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0;
} else {
- sink_fmt.pad = pad->index;
+ sink_fmt.pad = sink_pad->index;
sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
return -EPIPE;
}
- /* Retrieve format at the source pad */
- pad = media_entity_remote_source(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
- sd = media_entity_to_v4l2_subdev(pad->entity);
- src_fmt.pad = pad->index;
+ /* Retrieve format at the source pad */
+ sd = media_entity_to_v4l2_subdev(src_pad->entity);
+ src_fmt.pad = src_pad->index;
src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
if (ret < 0 && ret != -ENOIOCTLCMD)
@@ -1208,7 +1186,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
if (sd == fimc->pipeline.subdevs[IDX_SENSOR] &&
fimc_user_defined_mbus_fmt(src_fmt.format.code)) {
struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES];
- struct fimc_frame *frame = &vid_cap->ctx->d_frame;
+ struct fimc_frame *frame = &vc->ctx->d_frame;
unsigned int i;
ret = fimc_get_sensor_frame_desc(sd, plane_fmt,
@@ -1230,96 +1208,80 @@ static int fimc_cap_streamon(struct file *file, void *priv,
{
struct fimc_dev *fimc = video_drvdata(file);
struct fimc_pipeline *p = &fimc->pipeline;
- struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR];
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct media_entity *entity = &vc->vfd.entity;
+ struct fimc_source_info *si = NULL;
+ struct v4l2_subdev *sd;
int ret;
if (fimc_capture_active(fimc))
return -EBUSY;
- ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline);
+ ret = media_entity_pipeline_start(entity, p->m_pipeline);
if (ret < 0)
return ret;
- if (fimc->vid_cap.user_subdev_api) {
+ sd = p->subdevs[IDX_SENSOR];
+ if (sd)
+ si = v4l2_get_subdev_hostdata(sd);
+
+ if (si == NULL) {
+ ret = -EPIPE;
+ goto err_p_stop;
+ }
+ /*
+ * Save configuration data related to currently attached image
+ * sensor or other data source, e.g. FIMC-IS.
+ */
+ vc->source_config = *si;
+
+ if (vc->input == GRP_ID_FIMC_IS)
+ vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
+
+ if (vc->user_subdev_api) {
ret = fimc_pipeline_validate(fimc);
- if (ret < 0) {
- media_entity_pipeline_stop(&sd->entity);
- return ret;
- }
+ if (ret < 0)
+ goto err_p_stop;
}
- return vb2_streamon(&fimc->vid_cap.vbq, type);
+
+ ret = vb2_ioctl_streamon(file, priv, type);
+ if (!ret) {
+ vc->streaming = true;
+ return ret;
+ }
+
+err_p_stop:
+ media_entity_pipeline_stop(entity);
+ return ret;
}
static int fimc_cap_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
int ret;
- ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
- if (ret == 0)
- media_entity_pipeline_stop(&sd->entity);
- return ret;
+ ret = vb2_ioctl_streamoff(file, priv, type);
+ if (ret < 0)
+ return ret;
+
+ media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity);
+ fimc->vid_cap.streaming = false;
+ return 0;
}
static int fimc_cap_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct fimc_dev *fimc = video_drvdata(file);
- int ret = vb2_reqbufs(&fimc->vid_cap.vbq, reqbufs);
+ int ret;
+
+ ret = vb2_ioctl_reqbufs(file, priv, reqbufs);
if (!ret)
fimc->vid_cap.reqbufs_count = reqbufs->count;
- return ret;
-}
-
-static int fimc_cap_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_dev *fimc = video_drvdata(file);
-
- return vb2_querybuf(&fimc->vid_cap.vbq, buf);
-}
-
-static int fimc_cap_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_dev *fimc = video_drvdata(file);
-
- return vb2_qbuf(&fimc->vid_cap.vbq, buf);
-}
-
-static int fimc_cap_expbuf(struct file *file, void *priv,
- struct v4l2_exportbuffer *eb)
-{
- struct fimc_dev *fimc = video_drvdata(file);
-
- return vb2_expbuf(&fimc->vid_cap.vbq, eb);
-}
-
-static int fimc_cap_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_dev *fimc = video_drvdata(file);
-
- return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int fimc_cap_create_bufs(struct file *file, void *priv,
- struct v4l2_create_buffers *create)
-{
- struct fimc_dev *fimc = video_drvdata(file);
- return vb2_create_bufs(&fimc->vid_cap.vbq, create);
-}
-
-static int fimc_cap_prepare_buf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct fimc_dev *fimc = video_drvdata(file);
-
- return vb2_prepare_buf(&fimc->vid_cap.vbq, b);
+ return ret;
}
static int fimc_cap_g_selection(struct file *file, void *fh,
@@ -1410,7 +1372,7 @@ static int fimc_cap_s_selection(struct file *file, void *fh,
}
static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
- .vidioc_querycap = fimc_vidioc_querycap_capture,
+ .vidioc_querycap = fimc_cap_querycap,
.vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane,
@@ -1418,14 +1380,12 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
.vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane,
.vidioc_reqbufs = fimc_cap_reqbufs,
- .vidioc_querybuf = fimc_cap_querybuf,
-
- .vidioc_qbuf = fimc_cap_qbuf,
- .vidioc_dqbuf = fimc_cap_dqbuf,
- .vidioc_expbuf = fimc_cap_expbuf,
-
- .vidioc_prepare_buf = fimc_cap_prepare_buf,
- .vidioc_create_bufs = fimc_cap_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_streamon = fimc_cap_streamon,
.vidioc_streamoff = fimc_cap_streamoff,
@@ -1487,7 +1447,7 @@ static const struct media_entity_operations fimc_sd_media_ops = {
void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
void *arg)
{
- struct fimc_sensor_info *sensor;
+ struct fimc_source_info *si;
struct fimc_vid_buffer *buf;
struct fimc_md *fmd;
struct fimc_dev *fimc;
@@ -1496,11 +1456,12 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
if (sd == NULL)
return;
- sensor = v4l2_get_subdev_hostdata(sd);
+ si = v4l2_get_subdev_hostdata(sd);
fmd = entity_to_fimc_mdev(&sd->entity);
spin_lock_irqsave(&fmd->slock, flags);
- fimc = sensor ? sensor->host : NULL;
+
+ fimc = si ? source_to_sensor_info(si)->host : NULL;
if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY &&
test_bit(ST_CAPT_PEND, &fimc->state)) {
@@ -1537,25 +1498,37 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_frame *ff = &ctx->s_frame;
struct v4l2_mbus_framefmt *mf;
- struct fimc_frame *ff;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
mf = v4l2_subdev_get_try_format(fh, fmt->pad);
fmt->format = *mf;
return 0;
}
- mf = &fmt->format;
- mf->colorspace = V4L2_COLORSPACE_JPEG;
- ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame;
+ mf = &fmt->format;
mutex_lock(&fimc->lock);
- /* The pixel code is same on both input and output pad */
- if (!WARN_ON(ctx->s_frame.fmt == NULL))
- mf->code = ctx->s_frame.fmt->mbus_code;
- mf->width = ff->f_width;
- mf->height = ff->f_height;
+
+ switch (fmt->pad) {
+ case FIMC_SD_PAD_SOURCE:
+ if (!WARN_ON(ff->fmt == NULL))
+ mf->code = ff->fmt->mbus_code;
+ /* Sink pads crop rectangle size */
+ mf->width = ff->width;
+ mf->height = ff->height;
+ break;
+ case FIMC_SD_PAD_SINK_FIFO:
+ *mf = fimc->vid_cap.wb_fmt;
+ break;
+ case FIMC_SD_PAD_SINK_CAM:
+ default:
+ *mf = fimc->vid_cap.ci_fmt;
+ break;
+ }
+
mutex_unlock(&fimc->lock);
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
return 0;
}
@@ -1566,15 +1539,15 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
- struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct fimc_ctx *ctx = vc->ctx;
struct fimc_frame *ff;
struct fimc_fmt *ffmt;
dbg("pad%d: code: 0x%x, %dx%d",
fmt->pad, mf->code, mf->width, mf->height);
- if (fmt->pad == FIMC_SD_PAD_SOURCE &&
- vb2_is_busy(&fimc->vid_cap.vbq))
+ if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq))
return -EBUSY;
mutex_lock(&fimc->lock);
@@ -1596,21 +1569,32 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
fimc_alpha_ctrl_update(ctx);
fimc_capture_mark_jpeg_xfer(ctx, ffmt->color);
-
- ff = fmt->pad == FIMC_SD_PAD_SINK ?
- &ctx->s_frame : &ctx->d_frame;
+ if (fmt->pad == FIMC_SD_PAD_SOURCE) {
+ ff = &ctx->d_frame;
+ /* Sink pads crop rectangle size */
+ mf->width = ctx->s_frame.width;
+ mf->height = ctx->s_frame.height;
+ } else {
+ ff = &ctx->s_frame;
+ }
mutex_lock(&fimc->lock);
set_frame_bounds(ff, mf->width, mf->height);
- fimc->vid_cap.mf = *mf;
+
+ if (fmt->pad == FIMC_SD_PAD_SINK_FIFO)
+ vc->wb_fmt = *mf;
+ else if (fmt->pad == FIMC_SD_PAD_SINK_CAM)
+ vc->ci_fmt = *mf;
+
ff->fmt = ffmt;
/* Reset the crop rectangle if required. */
if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))
set_frame_crop(ff, 0, 0, mf->width, mf->height);
- if (fmt->pad == FIMC_SD_PAD_SINK)
+ if (fmt->pad != FIMC_SD_PAD_SOURCE)
ctx->state &= ~FIMC_COMPOSE;
+
mutex_unlock(&fimc->lock);
return 0;
}
@@ -1625,7 +1609,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
struct v4l2_rect *r = &sel->r;
struct v4l2_rect *try_sel;
- if (sel->pad != FIMC_SD_PAD_SINK)
+ if (sel->pad == FIMC_SD_PAD_SOURCE)
return -EINVAL;
mutex_lock(&fimc->lock);
@@ -1681,7 +1665,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_rect *try_sel;
unsigned long flags;
- if (sel->pad != FIMC_SD_PAD_SINK)
+ if (sel->pad == FIMC_SD_PAD_SOURCE)
return -EINVAL;
mutex_lock(&fimc->lock);
@@ -1752,9 +1736,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
struct v4l2_device *v4l2_dev)
{
struct video_device *vfd = &fimc->vid_cap.vfd;
- struct fimc_vid_cap *vid_cap;
+ struct vb2_queue *q = &fimc->vid_cap.vbq;
struct fimc_ctx *ctx;
- struct vb2_queue *q;
+ struct fimc_vid_cap *vid_cap;
int ret = -ENOMEM;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -1776,27 +1760,27 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
vfd->v4l2_dev = v4l2_dev;
vfd->minor = -1;
vfd->release = video_device_release_empty;
+ vfd->queue = q;
vfd->lock = &fimc->lock;
video_set_drvdata(vfd, fimc);
-
vid_cap = &fimc->vid_cap;
vid_cap->active_buf_cnt = 0;
- vid_cap->reqbufs_count = 0;
- vid_cap->refcnt = 0;
+ vid_cap->reqbufs_count = 0;
+ vid_cap->ctx = ctx;
INIT_LIST_HEAD(&vid_cap->pending_buf_q);
INIT_LIST_HEAD(&vid_cap->active_buf_q);
- vid_cap->ctx = ctx;
- q = &fimc->vid_cap.vbq;
memset(q, 0, sizeof(*q));
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
- q->drv_priv = fimc->vid_cap.ctx;
+ q->drv_priv = ctx;
q->ops = &fimc_capture_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct fimc_vid_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &fimc->lock;
ret = vb2_queue_init(q);
if (ret)
@@ -1882,10 +1866,11 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
int ret;
v4l2_subdev_init(sd, &fimc_subdev_ops);
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
- snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id);
- fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK;
+ fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK;
fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
fimc->vid_cap.sd_pads, 0);
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index e3916bde45cf..379a5e9d52a7 100644
--- a/drivers/media/platform/s5p-fimc/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -20,7 +20,10 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/list.h>
+#include <linux/mfd/syscon.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <media/v4l2-ioctl.h>
@@ -29,7 +32,7 @@
#include "fimc-core.h"
#include "fimc-reg.h"
-#include "fimc-mdevice.h"
+#include "media-dev.h"
static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
"sclk_fimc", "fimc"
@@ -77,6 +80,10 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
+ .name = "YUV 4:4:4",
+ .mbus_code = V4L2_MBUS_FMT_YUV10_1X30,
+ .flags = FMT_FLAGS_WRITEBACK,
+ }, {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = { 16 },
@@ -206,6 +213,17 @@ struct fimc_fmt *fimc_get_format(unsigned int index)
return &fimc_formats[index];
}
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps)
+{
+ strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ strlcpy(cap->card, dev->driver->name, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", dev_name(dev));
+ cap->device_caps = caps;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+}
+
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
int dw, int dh, int rotation)
{
@@ -405,34 +423,34 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx)
/* Set order for 1 plane input formats. */
switch (ctx->s_frame.fmt->color) {
case FIMC_FMT_YCRYCB422:
- ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
break;
case FIMC_FMT_CBYCRY422:
- ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
break;
case FIMC_FMT_CRYCBY422:
- ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
break;
case FIMC_FMT_YCBYCR422:
default:
- ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
break;
}
dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
switch (ctx->d_frame.fmt->color) {
case FIMC_FMT_YCRYCB422:
- ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
break;
case FIMC_FMT_CBYCRY422:
- ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
break;
case FIMC_FMT_CRYCBY422:
- ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
break;
case FIMC_FMT_YCBYCR422:
default:
- ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
break;
}
dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
@@ -440,14 +458,14 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx)
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
{
- const struct fimc_variant *variant = ctx->fimc_dev->variant;
+ bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff;
u32 i, depth = 0;
for (i = 0; i < f->fmt->colplanes; i++)
depth += f->fmt->depth[i];
f->dma_offset.y_h = f->offs_h;
- if (!variant->pix_hoff)
+ if (!pix_hoff)
f->dma_offset.y_h *= (depth >> 3);
f->dma_offset.y_v = f->offs_v;
@@ -458,7 +476,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
f->dma_offset.cr_h = f->offs_h;
f->dma_offset.cr_v = f->offs_v;
- if (!variant->pix_hoff) {
+ if (!pix_hoff) {
if (f->fmt->colplanes == 3) {
f->dma_offset.cb_h >>= 1;
f->dma_offset.cr_h >>= 1;
@@ -589,7 +607,6 @@ static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
int fimc_ctrls_create(struct fimc_ctx *ctx)
{
- const struct fimc_variant *variant = ctx->fimc_dev->variant;
unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
struct fimc_ctrls *ctrls = &ctx->ctrls;
struct v4l2_ctrl_handler *handler = &ctrls->handler;
@@ -606,7 +623,7 @@ int fimc_ctrls_create(struct fimc_ctx *ctx)
ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- if (variant->has_alpha)
+ if (ctx->fimc_dev->drv_data->alpha_color)
ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_ALPHA_COMPONENT,
0, max_alpha, 1, 0);
@@ -677,7 +694,7 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
struct fimc_dev *fimc = ctx->fimc_dev;
struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
- if (ctrl == NULL || !fimc->variant->has_alpha)
+ if (ctrl == NULL || !fimc->drv_data->alpha_color)
return;
v4l2_ctrl_lock(ctrl);
@@ -850,56 +867,128 @@ static int fimc_m2m_suspend(struct fimc_dev *fimc)
static int fimc_m2m_resume(struct fimc_dev *fimc)
{
+ struct fimc_ctx *ctx;
unsigned long flags;
spin_lock_irqsave(&fimc->slock, flags);
/* Clear for full H/W setup in first run after resume */
+ ctx = fimc->m2m.ctx;
fimc->m2m.ctx = NULL;
spin_unlock_irqrestore(&fimc->slock, flags);
if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
- fimc_m2m_job_finish(fimc->m2m.ctx,
- VB2_BUF_STATE_ERROR);
+ fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
+ return 0;
+}
+
+static const struct of_device_id fimc_of_match[];
+
+static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq)
+{
+ struct device *dev = &fimc->pdev->dev;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *of_id;
+ struct fimc_variant *v;
+ struct fimc_pix_limit *lim;
+ u32 args[FIMC_PIX_LIMITS_MAX];
+ int ret;
+
+ if (of_property_read_bool(node, "samsung,lcd-wb"))
+ return -ENODEV;
+
+ v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL);
+ if (!v)
+ return -ENOMEM;
+
+ of_id = of_match_node(fimc_of_match, node);
+ if (!of_id)
+ return -EINVAL;
+ fimc->drv_data = of_id->data;
+ ret = of_property_read_u32_array(node, "samsung,pix-limits",
+ args, FIMC_PIX_LIMITS_MAX);
+ if (ret < 0)
+ return ret;
+
+ lim = (struct fimc_pix_limit *)&v[1];
+
+ lim->scaler_en_w = args[0];
+ lim->scaler_dis_w = args[1];
+ lim->out_rot_en_w = args[2];
+ lim->out_rot_dis_w = args[3];
+ v->pix_limit = lim;
+
+ ret = of_property_read_u32_array(node, "samsung,min-pix-sizes",
+ args, 2);
+ v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0];
+ v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1];
+ ret = of_property_read_u32_array(node, "samsung,min-pix-alignment",
+ args, 2);
+ v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0];
+ v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1];
+
+ ret = of_property_read_u32(node, "samsung,rotators", &args[1]);
+ v->has_inp_rot = ret ? 1 : args[1] & 0x01;
+ v->has_out_rot = ret ? 1 : args[1] & 0x10;
+ v->has_mainscaler_ext = of_property_read_bool(node,
+ "samsung,mainscaler-ext");
+
+ v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb");
+ v->has_cam_if = of_property_read_bool(node, "samsung,cam-if");
+ of_property_read_u32(node, "clock-frequency", clk_freq);
+ fimc->id = of_alias_get_id(node, "fimc");
+
+ fimc->variant = v;
return 0;
}
static int fimc_probe(struct platform_device *pdev)
{
- const struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
- struct s5p_platform_fimc *pdata;
+ struct device *dev = &pdev->dev;
+ u32 lclk_freq = 0;
struct fimc_dev *fimc;
struct resource *res;
int ret = 0;
- if (pdev->id >= drv_data->num_entities) {
- dev_err(&pdev->dev, "Invalid platform device id: %d\n",
- pdev->id);
- return -EINVAL;
- }
-
- fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+ fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL);
if (!fimc)
return -ENOMEM;
- fimc->id = pdev->id;
-
- fimc->variant = drv_data->variant[fimc->id];
fimc->pdev = pdev;
- pdata = pdev->dev.platform_data;
- fimc->pdata = pdata;
+
+ if (dev->of_node) {
+ ret = fimc_parse_dt(fimc, &lclk_freq);
+ if (ret < 0)
+ return ret;
+ } else {
+ fimc->drv_data = fimc_get_drvdata(pdev);
+ fimc->id = pdev->id;
+ }
+ if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities ||
+ fimc->id < 0) {
+ dev_err(dev, "Invalid driver data or device id (%d)\n",
+ fimc->id);
+ return -EINVAL;
+ }
+ if (!dev->of_node)
+ fimc->variant = fimc->drv_data->variant[fimc->id];
init_waitqueue_head(&fimc->irq_queue);
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
+ fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node);
+ if (IS_ERR(fimc->sysreg))
+ return PTR_ERR(fimc->sysreg);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fimc->regs = devm_ioremap_resource(&pdev->dev, res);
+ fimc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(fimc->regs))
return PTR_ERR(fimc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
- dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+ dev_err(dev, "Failed to get IRQ resource\n");
return -ENXIO;
}
@@ -907,7 +996,10 @@ static int fimc_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
+ if (lclk_freq == 0)
+ lclk_freq = fimc->drv_data->lclk_frequency;
+
+ ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq);
if (ret < 0)
return ret;
@@ -915,10 +1007,10 @@ static int fimc_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
- 0, dev_name(&pdev->dev), fimc);
+ ret = devm_request_irq(dev, res->start, fimc_irq_handler,
+ 0, dev_name(dev), fimc);
if (ret) {
- dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+ dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_clk;
}
@@ -927,23 +1019,23 @@ static int fimc_probe(struct platform_device *pdev)
goto err_clk;
platform_set_drvdata(pdev, fimc);
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_sd;
/* Initialize contiguous memory allocator */
- fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
goto err_pm;
}
- dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id);
+ dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id);
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put(dev);
return 0;
err_pm:
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put(dev);
err_sd:
fimc_unregister_capture_subdev(fimc);
err_clk:
@@ -1046,35 +1138,21 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = {
[0] = {
.scaler_en_w = 3264,
.scaler_dis_w = 8192,
- .in_rot_en_h = 1920,
- .in_rot_dis_w = 8192,
.out_rot_en_w = 1920,
.out_rot_dis_w = 4224,
},
[1] = {
.scaler_en_w = 4224,
.scaler_dis_w = 8192,
- .in_rot_en_h = 1920,
- .in_rot_dis_w = 8192,
.out_rot_en_w = 1920,
.out_rot_dis_w = 4224,
},
[2] = {
.scaler_en_w = 1920,
.scaler_dis_w = 8192,
- .in_rot_en_h = 1280,
- .in_rot_dis_w = 8192,
.out_rot_en_w = 1280,
.out_rot_dis_w = 1920,
},
- [3] = {
- .scaler_en_w = 1920,
- .scaler_dis_w = 8192,
- .in_rot_en_h = 1366,
- .in_rot_dis_w = 8192,
- .out_rot_en_w = 1366,
- .out_rot_dis_w = 1920,
- },
};
static const struct fimc_variant fimc0_variant_s5p = {
@@ -1085,7 +1163,6 @@ static const struct fimc_variant fimc0_variant_s5p = {
.min_out_pixsize = 16,
.hor_offs_align = 8,
.min_vsize_align = 16,
- .out_buf_count = 4,
.pix_limit = &s5p_pix_limit[0],
};
@@ -1095,12 +1172,10 @@ static const struct fimc_variant fimc2_variant_s5p = {
.min_out_pixsize = 16,
.hor_offs_align = 8,
.min_vsize_align = 16,
- .out_buf_count = 4,
.pix_limit = &s5p_pix_limit[1],
};
static const struct fimc_variant fimc0_variant_s5pv210 = {
- .pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
.has_cam_if = 1,
@@ -1108,12 +1183,10 @@ static const struct fimc_variant fimc0_variant_s5pv210 = {
.min_out_pixsize = 16,
.hor_offs_align = 8,
.min_vsize_align = 16,
- .out_buf_count = 4,
.pix_limit = &s5p_pix_limit[1],
};
static const struct fimc_variant fimc1_variant_s5pv210 = {
- .pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
.has_cam_if = 1,
@@ -1122,80 +1195,18 @@ static const struct fimc_variant fimc1_variant_s5pv210 = {
.min_out_pixsize = 16,
.hor_offs_align = 1,
.min_vsize_align = 1,
- .out_buf_count = 4,
.pix_limit = &s5p_pix_limit[2],
};
static const struct fimc_variant fimc2_variant_s5pv210 = {
.has_cam_if = 1,
- .pix_hoff = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 8,
.min_vsize_align = 16,
- .out_buf_count = 4,
.pix_limit = &s5p_pix_limit[2],
};
-static const struct fimc_variant fimc0_variant_exynos4210 = {
- .pix_hoff = 1,
- .has_inp_rot = 1,
- .has_out_rot = 1,
- .has_cam_if = 1,
- .has_cistatus2 = 1,
- .has_mainscaler_ext = 1,
- .has_alpha = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 2,
- .min_vsize_align = 1,
- .out_buf_count = 32,
- .pix_limit = &s5p_pix_limit[1],
-};
-
-static const struct fimc_variant fimc3_variant_exynos4210 = {
- .pix_hoff = 1,
- .has_cistatus2 = 1,
- .has_mainscaler_ext = 1,
- .has_alpha = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 2,
- .min_vsize_align = 1,
- .out_buf_count = 32,
- .pix_limit = &s5p_pix_limit[3],
-};
-
-static const struct fimc_variant fimc0_variant_exynos4x12 = {
- .pix_hoff = 1,
- .has_inp_rot = 1,
- .has_out_rot = 1,
- .has_cam_if = 1,
- .has_isp_wb = 1,
- .has_cistatus2 = 1,
- .has_mainscaler_ext = 1,
- .has_alpha = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 2,
- .min_vsize_align = 1,
- .out_buf_count = 32,
- .pix_limit = &s5p_pix_limit[1],
-};
-
-static const struct fimc_variant fimc3_variant_exynos4x12 = {
- .pix_hoff = 1,
- .has_cistatus2 = 1,
- .has_mainscaler_ext = 1,
- .has_alpha = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 2,
- .min_vsize_align = 1,
- .out_buf_count = 32,
- .pix_limit = &s5p_pix_limit[3],
-};
-
/* S5PC100 */
static const struct fimc_drvdata fimc_drvdata_s5p = {
.variant = {
@@ -1203,8 +1214,9 @@ static const struct fimc_drvdata fimc_drvdata_s5p = {
[1] = &fimc0_variant_s5p,
[2] = &fimc2_variant_s5p,
},
- .num_entities = 3,
+ .num_entities = 3,
.lclk_frequency = 133000000UL,
+ .out_buf_count = 4,
};
/* S5PV210, S5PC110 */
@@ -1214,32 +1226,30 @@ static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
[1] = &fimc1_variant_s5pv210,
[2] = &fimc2_variant_s5pv210,
},
- .num_entities = 3,
- .lclk_frequency = 166000000UL,
+ .num_entities = 3,
+ .lclk_frequency = 166000000UL,
+ .out_buf_count = 4,
+ .dma_pix_hoff = 1,
};
/* EXYNOS4210, S5PV310, S5PC210 */
static const struct fimc_drvdata fimc_drvdata_exynos4210 = {
- .variant = {
- [0] = &fimc0_variant_exynos4210,
- [1] = &fimc0_variant_exynos4210,
- [2] = &fimc0_variant_exynos4210,
- [3] = &fimc3_variant_exynos4210,
- },
- .num_entities = 4,
+ .num_entities = 4,
.lclk_frequency = 166000000UL,
+ .dma_pix_hoff = 1,
+ .cistatus2 = 1,
+ .alpha_color = 1,
+ .out_buf_count = 32,
};
/* EXYNOS4212, EXYNOS4412 */
static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
- .variant = {
- [0] = &fimc0_variant_exynos4x12,
- [1] = &fimc0_variant_exynos4x12,
- [2] = &fimc0_variant_exynos4x12,
- [3] = &fimc3_variant_exynos4x12,
- },
- .num_entities = 4,
- .lclk_frequency = 166000000UL,
+ .num_entities = 4,
+ .lclk_frequency = 166000000UL,
+ .dma_pix_hoff = 1,
+ .cistatus2 = 1,
+ .alpha_color = 1,
+ .out_buf_count = 32,
};
static const struct platform_device_id fimc_driver_ids[] = {
@@ -1256,9 +1266,22 @@ static const struct platform_device_id fimc_driver_ids[] = {
.name = "exynos4x12-fimc",
.driver_data = (unsigned long)&fimc_drvdata_exynos4x12,
},
- {},
+ { },
+};
+
+static const struct of_device_id fimc_of_match[] = {
+ {
+ .compatible = "samsung,s5pv210-fimc",
+ .data = &fimc_drvdata_s5pv210,
+ }, {
+ .compatible = "samsung,exynos4210-fimc",
+ .data = &fimc_drvdata_exynos4210,
+ }, {
+ .compatible = "samsung,exynos4212-fimc",
+ .data = &fimc_drvdata_exynos4x12,
+ },
+ { /* sentinel */ },
};
-MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
static const struct dev_pm_ops fimc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume)
@@ -1270,9 +1293,10 @@ static struct platform_driver fimc_driver = {
.remove = fimc_remove,
.id_table = fimc_driver_ids,
.driver = {
- .name = FIMC_MODULE_NAME,
- .owner = THIS_MODULE,
- .pm = &fimc_pm_ops,
+ .of_match_table = fimc_of_match,
+ .name = FIMC_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_pm_ops,
}
};
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index 412d50708f75..539a3f71c16a 100644
--- a/drivers/media/platform/s5p-fimc/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -12,8 +12,10 @@
/*#define DEBUG*/
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/io.h>
@@ -33,7 +35,7 @@
/* Time to wait for next frame VSYNC interrupt while stopping operation. */
#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
#define MAX_FIMC_CLOCKS 2
-#define FIMC_MODULE_NAME "s5p-fimc"
+#define FIMC_DRIVER_NAME "exynos4-fimc"
#define FIMC_MAX_DEVS 4
#define FIMC_MAX_OUT_BUFS 4
#define SCALER_MAX_HRATIO 64
@@ -42,6 +44,10 @@
#define FIMC_CAMIF_MAX_HEIGHT 0x2000
#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M)
#define FIMC_MAX_PLANES 3
+#define FIMC_PIX_LIMITS_MAX 4
+#define FIMC_DEF_MIN_SIZE 16
+#define FIMC_DEF_HEIGHT_ALIGN 2
+#define FIMC_DEF_HOR_OFFS_ALIGN 1
/* indices to the clocks array */
enum {
@@ -132,36 +138,6 @@ enum fimc_color_fmt {
#define FIMC_COLOR_RANGE_NARROW (1 << 3)
/**
- * struct fimc_fmt - the driver's internal color format data
- * @mbus_code: Media Bus pixel code, -1 if not applicable
- * @name: format description
- * @fourcc: the fourcc code for this format, 0 if not applicable
- * @color: the corresponding fimc_color_fmt
- * @memplanes: number of physically non-contiguous data planes
- * @colplanes: number of physically contiguous data planes
- * @depth: per plane driver's private 'number of bits per pixel'
- * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no)
- * @flags: flags indicating which operation mode format applies to
- */
-struct fimc_fmt {
- enum v4l2_mbus_pixelcode mbus_code;
- char *name;
- u32 fourcc;
- u32 color;
- u16 memplanes;
- u16 colplanes;
- u8 depth[VIDEO_MAX_PLANES];
- u16 mdataplanes;
- u16 flags;
-#define FMT_FLAGS_CAM (1 << 0)
-#define FMT_FLAGS_M2M_IN (1 << 1)
-#define FMT_FLAGS_M2M_OUT (1 << 2)
-#define FMT_FLAGS_M2M (1 << 1 | 1 << 2)
-#define FMT_HAS_ALPHA (1 << 3)
-#define FMT_FLAGS_COMPRESSED (1 << 4)
-};
-
-/**
* struct fimc_dma_offset - pixel offset information for DMA
* @y_h: y value horizontal offset
* @y_v: y value vertical offset
@@ -299,9 +275,10 @@ struct fimc_m2m_device {
int refcnt;
};
-#define FIMC_SD_PAD_SINK 0
-#define FIMC_SD_PAD_SOURCE 1
-#define FIMC_SD_PADS_NUM 2
+#define FIMC_SD_PAD_SINK_CAM 0
+#define FIMC_SD_PAD_SINK_FIFO 1
+#define FIMC_SD_PAD_SOURCE 2
+#define FIMC_SD_PADS_NUM 3
/**
* struct fimc_vid_cap - camera capture device information
@@ -310,7 +287,9 @@ struct fimc_m2m_device {
* @subdev: subdev exposing the FIMC processing block
* @vd_pad: fimc video capture node pad
* @sd_pads: fimc video processing block pads
- * @mf: media bus format at the FIMC camera input (and the scaler output) pad
+ * @ci_fmt: image format at the FIMC camera input (and the scaler output)
+ * @wb_fmt: image format at the FIMC ISP Writeback input
+ * @source_config: external image source related configuration structure
* @pending_buf_q: the pending buffer queue head
* @active_buf_q: the queue head of buffers scheduled in hardware
* @vbq: the capture am video buffer queue
@@ -329,8 +308,10 @@ struct fimc_vid_cap {
struct video_device vfd;
struct v4l2_subdev subdev;
struct media_pad vd_pad;
- struct v4l2_mbus_framefmt mf;
struct media_pad sd_pads[FIMC_SD_PADS_NUM];
+ struct v4l2_mbus_framefmt ci_fmt;
+ struct v4l2_mbus_framefmt wb_fmt;
+ struct fimc_source_info source_config;
struct list_head pending_buf_q;
struct list_head active_buf_q;
struct vb2_queue vbq;
@@ -338,6 +319,7 @@ struct fimc_vid_cap {
int buf_index;
unsigned int frame_count;
unsigned int reqbufs_count;
+ bool streaming;
int input_index;
int refcnt;
u32 input;
@@ -365,10 +347,8 @@ struct fimc_pix_limit {
/**
* struct fimc_variant - FIMC device variant information
- * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
* @has_inp_rot: set if has input rotator
* @has_out_rot: set if has output rotator
- * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
* @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register
* are present in this IP revision
* @has_cam_if: set if this instance has a camera input interface
@@ -378,23 +358,18 @@ struct fimc_pix_limit {
* @min_out_pixsize: minimum output pixel size
* @hor_offs_align: horizontal pixel offset aligment
* @min_vsize_align: minimum vertical pixel size alignment
- * @out_buf_count: the number of buffers in output DMA sequence
*/
struct fimc_variant {
- unsigned int pix_hoff:1;
unsigned int has_inp_rot:1;
unsigned int has_out_rot:1;
- unsigned int has_cistatus2:1;
unsigned int has_mainscaler_ext:1;
unsigned int has_cam_if:1;
unsigned int has_isp_wb:1;
- unsigned int has_alpha:1;
const struct fimc_pix_limit *pix_limit;
u16 min_inp_pixsize;
u16 min_out_pixsize;
u16 hor_offs_align;
u16 min_vsize_align;
- u16 out_buf_count;
};
/**
@@ -402,11 +377,20 @@ struct fimc_variant {
* @variant: variant information for this device
* @num_entities: number of fimc instances available in a SoC
* @lclk_frequency: local bus clock frequency
+ * @cistatus2: 1 if the FIMC IPs have CISTATUS2 register
+ * @dma_pix_hoff: the horizontal DMA offset unit: 1 - pixels, 0 - bytes
+ * @alpha_color: 1 if alpha color component is supported
+ * @out_buf_count: maximum number of output DMA buffers supported
*/
struct fimc_drvdata {
const struct fimc_variant *variant[FIMC_MAX_DEVS];
int num_entities;
unsigned long lclk_frequency;
+ /* Fields common to all FIMC IP instances */
+ u8 cistatus2;
+ u8 dma_pix_hoff;
+ u8 alpha_color;
+ u8 out_buf_count;
};
#define fimc_get_drvdata(_pdev) \
@@ -420,6 +404,7 @@ struct fimc_ctx;
* @lock: the mutex protecting this data structure
* @pdev: pointer to the FIMC platform device
* @pdata: pointer to the device platform data
+ * @sysreg: pointer to the SYSREG regmap
* @variant: the IP variant information
* @id: FIMC device index (0..FIMC_MAX_DEVS)
* @clock: clocks required for FIMC operation
@@ -437,8 +422,10 @@ struct fimc_dev {
struct mutex lock;
struct platform_device *pdev;
struct s5p_platform_fimc *pdata;
+ struct regmap *sysreg;
const struct fimc_variant *variant;
- u16 id;
+ const struct fimc_drvdata *drv_data;
+ int id;
struct clk *clock[MAX_FIMC_CLOCKS];
void __iomem *regs;
wait_queue_head_t irq_queue;
@@ -633,6 +620,8 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
/* fimc-core.c */
int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
struct v4l2_fmtdesc *f);
+void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap,
+ unsigned int caps);
int fimc_ctrls_create(struct fimc_ctx *ctx);
void fimc_ctrls_delete(struct fimc_ctx *ctx);
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active);
@@ -660,6 +649,15 @@ void fimc_unregister_m2m_device(struct fimc_dev *fimc);
int fimc_register_driver(void);
void fimc_unregister_driver(void);
+#ifdef CONFIG_MFD_SYSCON
+static inline struct regmap * fimc_get_sysreg_regmap(struct device_node *node)
+{
+ return syscon_regmap_lookup_by_phandle(node, "samsung,sysreg");
+}
+#else
+#define fimc_get_sysreg_regmap(node) (NULL)
+#endif
+
/* -----------------------------------------------------*/
/* fimc-m2m.c */
void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-command.h b/drivers/media/platform/exynos4-is/fimc-is-command.h
new file mode 100644
index 000000000000..0d1f52e394b1
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-command.h
@@ -0,0 +1,137 @@
+/*
+ * Samsung Exynos4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * FIMC-IS command set definitions
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_IS_CMD_H_
+#define FIMC_IS_CMD_H_
+
+#define FIMC_IS_COMMAND_VER 110 /* FIMC-IS command set version 1.10 */
+
+/* Enumeration of commands beetween the FIMC-IS and the host processor. */
+
+/* HOST to FIMC-IS */
+#define HIC_PREVIEW_STILL 0x0001
+#define HIC_PREVIEW_VIDEO 0x0002
+#define HIC_CAPTURE_STILL 0x0003
+#define HIC_CAPTURE_VIDEO 0x0004
+#define HIC_STREAM_ON 0x0005
+#define HIC_STREAM_OFF 0x0006
+#define HIC_SET_PARAMETER 0x0007
+#define HIC_GET_PARAMETER 0x0008
+#define HIC_SET_TUNE 0x0009
+#define HIC_GET_STATUS 0x000b
+/* Sensor part */
+#define HIC_OPEN_SENSOR 0x000c
+#define HIC_CLOSE_SENSOR 0x000d
+#define HIC_SIMMIAN_INIT 0x000e
+#define HIC_SIMMIAN_WRITE 0x000f
+#define HIC_SIMMIAN_READ 0x0010
+#define HIC_POWER_DOWN 0x0011
+#define HIC_GET_SET_FILE_ADDR 0x0012
+#define HIC_LOAD_SET_FILE 0x0013
+#define HIC_MSG_CONFIG 0x0014
+#define HIC_MSG_TEST 0x0015
+/* FIMC-IS to HOST */
+#define IHC_GET_SENSOR_NUM 0x1000
+#define IHC_SET_SHOT_MARK 0x1001
+/* parameter1: frame number */
+/* parameter2: confidence level (smile 0~100) */
+/* parameter3: confidence level (blink 0~100) */
+#define IHC_SET_FACE_MARK 0x1002
+/* parameter1: coordinate count */
+/* parameter2: coordinate buffer address */
+#define IHC_FRAME_DONE 0x1003
+/* parameter1: frame start number */
+/* parameter2: frame count */
+#define IHC_AA_DONE 0x1004
+#define IHC_NOT_READY 0x1005
+
+#define IH_REPLY_DONE 0x2000
+#define IH_REPLY_NOT_DONE 0x2001
+
+enum fimc_is_scenario {
+ IS_SC_PREVIEW_STILL,
+ IS_SC_PREVIEW_VIDEO,
+ IS_SC_CAPTURE_STILL,
+ IS_SC_CAPTURE_VIDEO,
+ IS_SC_MAX
+};
+
+enum fimc_is_sub_scenario {
+ IS_SC_SUB_DEFAULT,
+ IS_SC_SUB_PS_VTCALL,
+ IS_SC_SUB_CS_VTCALL,
+ IS_SC_SUB_PV_VTCALL,
+ IS_SC_SUB_CV_VTCALL,
+};
+
+struct is_common_regs {
+ u32 hicmd;
+ u32 hic_sensorid;
+ u32 hic_param[4];
+ u32 reserved1[4];
+
+ u32 ihcmd;
+ u32 ihc_sensorid;
+ u32 ihc_param[4];
+ u32 reserved2[4];
+
+ u32 isp_sensor_id;
+ u32 isp_param[2];
+ u32 reserved3[1];
+
+ u32 scc_sensor_id;
+ u32 scc_param[2];
+ u32 reserved4[1];
+
+ u32 dnr_sensor_id;
+ u32 dnr_param[2];
+ u32 reserved5[1];
+
+ u32 scp_sensor_id;
+ u32 scp_param[2];
+ u32 reserved6[29];
+} __packed;
+
+struct is_mcuctl_reg {
+ u32 mcuctl;
+ u32 bboar;
+
+ u32 intgr0;
+ u32 intcr0;
+ u32 intmr0;
+ u32 intsr0;
+ u32 intmsr0;
+
+ u32 intgr1;
+ u32 intcr1;
+ u32 intmr1;
+ u32 intsr1;
+ u32 intmsr1;
+
+ u32 intcr2;
+ u32 intmr2;
+ u32 intsr2;
+ u32 intmsr2;
+
+ u32 gpoctrl;
+ u32 cpoenctlr;
+ u32 gpictlr;
+
+ u32 reserved[0xd];
+
+ struct is_common_regs common;
+} __packed;
+
+#endif /* FIMC_IS_CMD_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c
new file mode 100644
index 000000000000..e8519e151c1a
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c
@@ -0,0 +1,272 @@
+/*
+ * Samsung Exynos4 SoC series FIMC-IS slave interface driver
+ *
+ * Error log interface functions
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "fimc-is-errno.h"
+
+const char * const fimc_is_param_strerr(unsigned int error)
+{
+ switch (error) {
+ case ERROR_COMMON_CMD:
+ return "ERROR_COMMON_CMD: Invalid Command";
+ case ERROR_COMMON_PARAMETER:
+ return "ERROR_COMMON_PARAMETER: Invalid Parameter";
+ case ERROR_COMMON_SETFILE_LOAD:
+ return "ERROR_COMMON_SETFILE_LOAD: Illegal Setfile Loading";
+ case ERROR_COMMON_SETFILE_ADJUST:
+ return "ERROR_COMMON_SETFILE_ADJUST: Setfile isn't adjusted";
+ case ERROR_COMMON_SETFILE_INDEX:
+ return "ERROR_COMMON_SETFILE_INDEX: Invalid setfile index";
+ case ERROR_COMMON_INPUT_PATH:
+ return "ERROR_COMMON_INPUT_PATH: Input path can be changed in ready state";
+ case ERROR_COMMON_INPUT_INIT:
+ return "ERROR_COMMON_INPUT_INIT: IP can not start if input path is not set";
+ case ERROR_COMMON_OUTPUT_PATH:
+ return "ERROR_COMMON_OUTPUT_PATH: Output path can be changed in ready state (stop)";
+ case ERROR_COMMON_OUTPUT_INIT:
+ return "ERROR_COMMON_OUTPUT_INIT: IP can not start if output path is not set";
+ case ERROR_CONTROL_BYPASS:
+ return "ERROR_CONTROL_BYPASS";
+ case ERROR_OTF_INPUT_FORMAT:
+ return "ERROR_OTF_INPUT_FORMAT: Invalid format (DRC: YUV444, FD: YUV444, 422, 420)";
+ case ERROR_OTF_INPUT_WIDTH:
+ return "ERROR_OTF_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)";
+ case ERROR_OTF_INPUT_HEIGHT:
+ return "ERROR_OTF_INPUT_HEIGHT: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+ case ERROR_OTF_INPUT_BIT_WIDTH:
+ return "ERROR_OTF_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+ case ERROR_DMA_INPUT_WIDTH:
+ return "ERROR_DMA_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)";
+ case ERROR_DMA_INPUT_HEIGHT:
+ return "ERROR_DMA_INPUT_HEIGHT: Invalid height (DRC: 64~8192, FD: 16~8190)";
+ case ERROR_DMA_INPUT_FORMAT:
+ return "ERROR_DMA_INPUT_FORMAT: Invalid format (DRC: YUV444 or YUV422, FD: YUV444,422,420)";
+ case ERROR_DMA_INPUT_BIT_WIDTH:
+ return "ERROR_DMA_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+ case ERROR_DMA_INPUT_ORDER:
+ return "ERROR_DMA_INPUT_ORDER: Invalid order(DRC: YYCbCr,YCbYCr,FD:NO,YYCbCr,YCbYCr,CbCr,CrCb)";
+ case ERROR_DMA_INPUT_PLANE:
+ return "ERROR_DMA_INPUT_PLANE: Invalid palne (DRC: 3, FD: 1, 2, 3)";
+ case ERROR_OTF_OUTPUT_WIDTH:
+ return "ERROR_OTF_OUTPUT_WIDTH: Invalid width (DRC: 128~8192)";
+ case ERROR_OTF_OUTPUT_HEIGHT:
+ return "ERROR_OTF_OUTPUT_HEIGHT: Invalid height (DRC: 64~8192)";
+ case ERROR_OTF_OUTPUT_FORMAT:
+ return "ERROR_OTF_OUTPUT_FORMAT: Invalid format (DRC: YUV444)";
+ case ERROR_OTF_OUTPUT_BIT_WIDTH:
+ return "ERROR_OTF_OUTPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+ case ERROR_DMA_OUTPUT_WIDTH:
+ return "ERROR_DMA_OUTPUT_WIDTH";
+ case ERROR_DMA_OUTPUT_HEIGHT:
+ return "ERROR_DMA_OUTPUT_HEIGHT";
+ case ERROR_DMA_OUTPUT_FORMAT:
+ return "ERROR_DMA_OUTPUT_FORMAT";
+ case ERROR_DMA_OUTPUT_BIT_WIDTH:
+ return "ERROR_DMA_OUTPUT_BIT_WIDTH";
+ case ERROR_DMA_OUTPUT_PLANE:
+ return "ERROR_DMA_OUTPUT_PLANE";
+ case ERROR_DMA_OUTPUT_ORDER:
+ return "ERROR_DMA_OUTPUT_ORDER";
+
+ /* Sensor Error(100~199) */
+ case ERROR_SENSOR_I2C_FAIL:
+ return "ERROR_SENSOR_I2C_FAIL";
+ case ERROR_SENSOR_INVALID_FRAMERATE:
+ return "ERROR_SENSOR_INVALID_FRAMERATE";
+ case ERROR_SENSOR_INVALID_EXPOSURETIME:
+ return "ERROR_SENSOR_INVALID_EXPOSURETIME";
+ case ERROR_SENSOR_INVALID_SIZE:
+ return "ERROR_SENSOR_INVALID_SIZE";
+ case ERROR_SENSOR_INVALID_SETTING:
+ return "ERROR_SENSOR_INVALID_SETTING";
+ case ERROR_SENSOR_ACTURATOR_INIT_FAIL:
+ return "ERROR_SENSOR_ACTURATOR_INIT_FAIL";
+ case ERROR_SENSOR_INVALID_AF_POS:
+ return "ERROR_SENSOR_INVALID_AF_POS";
+ case ERROR_SENSOR_UNSUPPORT_FUNC:
+ return "ERROR_SENSOR_UNSUPPORT_FUNC";
+ case ERROR_SENSOR_UNSUPPORT_PERI:
+ return "ERROR_SENSOR_UNSUPPORT_PERI";
+ case ERROR_SENSOR_UNSUPPORT_AF:
+ return "ERROR_SENSOR_UNSUPPORT_AF";
+
+ /* ISP Error (200~299) */
+ case ERROR_ISP_AF_BUSY:
+ return "ERROR_ISP_AF_BUSY";
+ case ERROR_ISP_AF_INVALID_COMMAND:
+ return "ERROR_ISP_AF_INVALID_COMMAND";
+ case ERROR_ISP_AF_INVALID_MODE:
+ return "ERROR_ISP_AF_INVALID_MODE";
+
+ /* DRC Error (300~399) */
+ /* FD Error (400~499) */
+ case ERROR_FD_CONFIG_MAX_NUMBER_STATE:
+ return "ERROR_FD_CONFIG_MAX_NUMBER_STATE";
+ case ERROR_FD_CONFIG_MAX_NUMBER_INVALID:
+ return "ERROR_FD_CONFIG_MAX_NUMBER_INVALID";
+ case ERROR_FD_CONFIG_YAW_ANGLE_STATE:
+ return "ERROR_FD_CONFIG_YAW_ANGLE_STATE";
+ case ERROR_FD_CONFIG_YAW_ANGLE_INVALID:
+ return "ERROR_FD_CONFIG_YAW_ANGLE_INVALID\n";
+ case ERROR_FD_CONFIG_ROLL_ANGLE_STATE:
+ return "ERROR_FD_CONFIG_ROLL_ANGLE_STATE";
+ case ERROR_FD_CONFIG_ROLL_ANGLE_INVALID:
+ return "ERROR_FD_CONFIG_ROLL_ANGLE_INVALID";
+ case ERROR_FD_CONFIG_SMILE_MODE_INVALID:
+ return "ERROR_FD_CONFIG_SMILE_MODE_INVALID";
+ case ERROR_FD_CONFIG_BLINK_MODE_INVALID:
+ return "ERROR_FD_CONFIG_BLINK_MODE_INVALID";
+ case ERROR_FD_CONFIG_EYES_DETECT_INVALID:
+ return "ERROR_FD_CONFIG_EYES_DETECT_INVALID";
+ case ERROR_FD_CONFIG_MOUTH_DETECT_INVALID:
+ return "ERROR_FD_CONFIG_MOUTH_DETECT_INVALID";
+ case ERROR_FD_CONFIG_ORIENTATION_STATE:
+ return "ERROR_FD_CONFIG_ORIENTATION_STATE";
+ case ERROR_FD_CONFIG_ORIENTATION_INVALID:
+ return "ERROR_FD_CONFIG_ORIENTATION_INVALID";
+ case ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID:
+ return "ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID";
+ case ERROR_FD_RESULT:
+ return "ERROR_FD_RESULT";
+ case ERROR_FD_MODE:
+ return "ERROR_FD_MODE";
+ default:
+ return "Unknown";
+ }
+}
+
+const char * const fimc_is_strerr(unsigned int error)
+{
+ error &= ~IS_ERROR_TIME_OUT_FLAG;
+
+ switch (error) {
+ /* General */
+ case IS_ERROR_INVALID_COMMAND:
+ return "IS_ERROR_INVALID_COMMAND";
+ case IS_ERROR_REQUEST_FAIL:
+ return "IS_ERROR_REQUEST_FAIL";
+ case IS_ERROR_INVALID_SCENARIO:
+ return "IS_ERROR_INVALID_SCENARIO";
+ case IS_ERROR_INVALID_SENSORID:
+ return "IS_ERROR_INVALID_SENSORID";
+ case IS_ERROR_INVALID_MODE_CHANGE:
+ return "IS_ERROR_INVALID_MODE_CHANGE";
+ case IS_ERROR_INVALID_MAGIC_NUMBER:
+ return "IS_ERROR_INVALID_MAGIC_NUMBER";
+ case IS_ERROR_INVALID_SETFILE_HDR:
+ return "IS_ERROR_INVALID_SETFILE_HDR";
+ case IS_ERROR_BUSY:
+ return "IS_ERROR_BUSY";
+ case IS_ERROR_SET_PARAMETER:
+ return "IS_ERROR_SET_PARAMETER";
+ case IS_ERROR_INVALID_PATH:
+ return "IS_ERROR_INVALID_PATH";
+ case IS_ERROR_OPEN_SENSOR_FAIL:
+ return "IS_ERROR_OPEN_SENSOR_FAIL";
+ case IS_ERROR_ENTRY_MSG_THREAD_DOWN:
+ return "IS_ERROR_ENTRY_MSG_THREAD_DOWN";
+ case IS_ERROR_ISP_FRAME_END_NOT_DONE:
+ return "IS_ERROR_ISP_FRAME_END_NOT_DONE";
+ case IS_ERROR_DRC_FRAME_END_NOT_DONE:
+ return "IS_ERROR_DRC_FRAME_END_NOT_DONE";
+ case IS_ERROR_SCALERC_FRAME_END_NOT_DONE:
+ return "IS_ERROR_SCALERC_FRAME_END_NOT_DONE";
+ case IS_ERROR_ODC_FRAME_END_NOT_DONE:
+ return "IS_ERROR_ODC_FRAME_END_NOT_DONE";
+ case IS_ERROR_DIS_FRAME_END_NOT_DONE:
+ return "IS_ERROR_DIS_FRAME_END_NOT_DONE";
+ case IS_ERROR_TDNR_FRAME_END_NOT_DONE:
+ return "IS_ERROR_TDNR_FRAME_END_NOT_DONE";
+ case IS_ERROR_SCALERP_FRAME_END_NOT_DONE:
+ return "IS_ERROR_SCALERP_FRAME_END_NOT_DONE";
+ case IS_ERROR_WAIT_STREAM_OFF_NOT_DONE:
+ return "IS_ERROR_WAIT_STREAM_OFF_NOT_DONE";
+ case IS_ERROR_NO_MSG_IS_RECEIVED:
+ return "IS_ERROR_NO_MSG_IS_RECEIVED";
+ case IS_ERROR_SENSOR_MSG_FAIL:
+ return "IS_ERROR_SENSOR_MSG_FAIL";
+ case IS_ERROR_ISP_MSG_FAIL:
+ return "IS_ERROR_ISP_MSG_FAIL";
+ case IS_ERROR_DRC_MSG_FAIL:
+ return "IS_ERROR_DRC_MSG_FAIL";
+ case IS_ERROR_LHFD_MSG_FAIL:
+ return "IS_ERROR_LHFD_MSG_FAIL";
+ case IS_ERROR_UNKNOWN:
+ return "IS_ERROR_UNKNOWN";
+
+ /* Sensor */
+ case IS_ERROR_SENSOR_PWRDN_FAIL:
+ return "IS_ERROR_SENSOR_PWRDN_FAIL";
+
+ /* ISP */
+ case IS_ERROR_ISP_PWRDN_FAIL:
+ return "IS_ERROR_ISP_PWRDN_FAIL";
+ case IS_ERROR_ISP_MULTIPLE_INPUT:
+ return "IS_ERROR_ISP_MULTIPLE_INPUT";
+ case IS_ERROR_ISP_ABSENT_INPUT:
+ return "IS_ERROR_ISP_ABSENT_INPUT";
+ case IS_ERROR_ISP_ABSENT_OUTPUT:
+ return "IS_ERROR_ISP_ABSENT_OUTPUT";
+ case IS_ERROR_ISP_NONADJACENT_OUTPUT:
+ return "IS_ERROR_ISP_NONADJACENT_OUTPUT";
+ case IS_ERROR_ISP_FORMAT_MISMATCH:
+ return "IS_ERROR_ISP_FORMAT_MISMATCH";
+ case IS_ERROR_ISP_WIDTH_MISMATCH:
+ return "IS_ERROR_ISP_WIDTH_MISMATCH";
+ case IS_ERROR_ISP_HEIGHT_MISMATCH:
+ return "IS_ERROR_ISP_HEIGHT_MISMATCH";
+ case IS_ERROR_ISP_BITWIDTH_MISMATCH:
+ return "IS_ERROR_ISP_BITWIDTH_MISMATCH";
+ case IS_ERROR_ISP_FRAME_END_TIME_OUT:
+ return "IS_ERROR_ISP_FRAME_END_TIME_OUT";
+
+ /* DRC */
+ case IS_ERROR_DRC_PWRDN_FAIL:
+ return "IS_ERROR_DRC_PWRDN_FAIL";
+ case IS_ERROR_DRC_MULTIPLE_INPUT:
+ return "IS_ERROR_DRC_MULTIPLE_INPUT";
+ case IS_ERROR_DRC_ABSENT_INPUT:
+ return "IS_ERROR_DRC_ABSENT_INPUT";
+ case IS_ERROR_DRC_NONADJACENT_INPUT:
+ return "IS_ERROR_DRC_NONADJACENT_INPUT";
+ case IS_ERROR_DRC_ABSENT_OUTPUT:
+ return "IS_ERROR_DRC_ABSENT_OUTPUT";
+ case IS_ERROR_DRC_NONADJACENT_OUTPUT:
+ return "IS_ERROR_DRC_NONADJACENT_OUTPUT";
+ case IS_ERROR_DRC_FORMAT_MISMATCH:
+ return "IS_ERROR_DRC_FORMAT_MISMATCH";
+ case IS_ERROR_DRC_WIDTH_MISMATCH:
+ return "IS_ERROR_DRC_WIDTH_MISMATCH";
+ case IS_ERROR_DRC_HEIGHT_MISMATCH:
+ return "IS_ERROR_DRC_HEIGHT_MISMATCH";
+ case IS_ERROR_DRC_BITWIDTH_MISMATCH:
+ return "IS_ERROR_DRC_BITWIDTH_MISMATCH";
+ case IS_ERROR_DRC_FRAME_END_TIME_OUT:
+ return "IS_ERROR_DRC_FRAME_END_TIME_OUT";
+
+ /* FD */
+ case IS_ERROR_FD_PWRDN_FAIL:
+ return "IS_ERROR_FD_PWRDN_FAIL";
+ case IS_ERROR_FD_MULTIPLE_INPUT:
+ return "IS_ERROR_FD_MULTIPLE_INPUT";
+ case IS_ERROR_FD_ABSENT_INPUT:
+ return "IS_ERROR_FD_ABSENT_INPUT";
+ case IS_ERROR_FD_NONADJACENT_INPUT:
+ return "IS_ERROR_FD_NONADJACENT_INPUT";
+ case IS_ERROR_LHFD_FRAME_END_TIME_OUT:
+ return "IS_ERROR_LHFD_FRAME_END_TIME_OUT";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h
new file mode 100644
index 000000000000..3de6f6da6f87
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h
@@ -0,0 +1,248 @@
+/*
+ * Samsung Exynos4 SoC series FIMC-IS slave interface driver
+ *
+ * FIMC-IS error code definition
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef FIMC_IS_ERR_H_
+#define FIMC_IS_ERR_H_
+
+#define IS_ERROR_VER 011 /* IS ERROR VERSION 0.11 */
+
+enum {
+ IS_ERROR_NONE,
+
+ /* General 1 ~ 99 */
+ IS_ERROR_INVALID_COMMAND,
+ IS_ERROR_REQUEST_FAIL,
+ IS_ERROR_INVALID_SCENARIO,
+ IS_ERROR_INVALID_SENSORID,
+ IS_ERROR_INVALID_MODE_CHANGE,
+ IS_ERROR_INVALID_MAGIC_NUMBER,
+ IS_ERROR_INVALID_SETFILE_HDR,
+ IS_ERROR_BUSY,
+ IS_ERROR_SET_PARAMETER,
+ IS_ERROR_INVALID_PATH,
+ IS_ERROR_OPEN_SENSOR_FAIL,
+ IS_ERROR_ENTRY_MSG_THREAD_DOWN,
+ IS_ERROR_ISP_FRAME_END_NOT_DONE,
+ IS_ERROR_DRC_FRAME_END_NOT_DONE,
+ IS_ERROR_SCALERC_FRAME_END_NOT_DONE,
+ IS_ERROR_ODC_FRAME_END_NOT_DONE,
+ IS_ERROR_DIS_FRAME_END_NOT_DONE,
+ IS_ERROR_TDNR_FRAME_END_NOT_DONE,
+ IS_ERROR_SCALERP_FRAME_END_NOT_DONE,
+ IS_ERROR_WAIT_STREAM_OFF_NOT_DONE,
+ IS_ERROR_NO_MSG_IS_RECEIVED,
+ IS_ERROR_SENSOR_MSG_FAIL,
+ IS_ERROR_ISP_MSG_FAIL,
+ IS_ERROR_DRC_MSG_FAIL,
+ IS_ERROR_SCALERC_MSG_FAIL,
+ IS_ERROR_ODC_MSG_FAIL,
+ IS_ERROR_DIS_MSG_FAIL,
+ IS_ERROR_TDNR_MSG_FAIL,
+ IS_ERROR_SCALERP_MSG_FAIL,
+ IS_ERROR_LHFD_MSG_FAIL,
+ IS_ERROR_LHFD_INTERNAL_STOP,
+
+ /* Sensor 100 ~ 199 */
+ IS_ERROR_SENSOR_PWRDN_FAIL = 100,
+ IS_ERROR_SENSOR_STREAM_ON_FAIL,
+ IS_ERROR_SENSOR_STREAM_OFF_FAIL,
+
+ /* ISP 200 ~ 299 */
+ IS_ERROR_ISP_PWRDN_FAIL = 200,
+ IS_ERROR_ISP_MULTIPLE_INPUT,
+ IS_ERROR_ISP_ABSENT_INPUT,
+ IS_ERROR_ISP_ABSENT_OUTPUT,
+ IS_ERROR_ISP_NONADJACENT_OUTPUT,
+ IS_ERROR_ISP_FORMAT_MISMATCH,
+ IS_ERROR_ISP_WIDTH_MISMATCH,
+ IS_ERROR_ISP_HEIGHT_MISMATCH,
+ IS_ERROR_ISP_BITWIDTH_MISMATCH,
+ IS_ERROR_ISP_FRAME_END_TIME_OUT,
+
+ /* DRC 300 ~ 399 */
+ IS_ERROR_DRC_PWRDN_FAIL = 300,
+ IS_ERROR_DRC_MULTIPLE_INPUT,
+ IS_ERROR_DRC_ABSENT_INPUT,
+ IS_ERROR_DRC_NONADJACENT_INPUT,
+ IS_ERROR_DRC_ABSENT_OUTPUT,
+ IS_ERROR_DRC_NONADJACENT_OUTPUT,
+ IS_ERROR_DRC_FORMAT_MISMATCH,
+ IS_ERROR_DRC_WIDTH_MISMATCH,
+ IS_ERROR_DRC_HEIGHT_MISMATCH,
+ IS_ERROR_DRC_BITWIDTH_MISMATCH,
+ IS_ERROR_DRC_FRAME_END_TIME_OUT,
+
+ /* SCALERC 400 ~ 499 */
+ IS_ERROR_SCALERC_PWRDN_FAIL = 400,
+
+ /* ODC 500 ~ 599 */
+ IS_ERROR_ODC_PWRDN_FAIL = 500,
+
+ /* DIS 600 ~ 699 */
+ IS_ERROR_DIS_PWRDN_FAIL = 600,
+
+ /* TDNR 700 ~ 799 */
+ IS_ERROR_TDNR_PWRDN_FAIL = 700,
+
+ /* SCALERC 800 ~ 899 */
+ IS_ERROR_SCALERP_PWRDN_FAIL = 800,
+
+ /* FD 900 ~ 999 */
+ IS_ERROR_FD_PWRDN_FAIL = 900,
+ IS_ERROR_FD_MULTIPLE_INPUT,
+ IS_ERROR_FD_ABSENT_INPUT,
+ IS_ERROR_FD_NONADJACENT_INPUT,
+ IS_ERROR_LHFD_FRAME_END_TIME_OUT,
+
+ IS_ERROR_UNKNOWN = 1000,
+};
+
+#define IS_ERROR_TIME_OUT_FLAG 0x80000000
+
+/* Set parameter error enum */
+enum fimc_is_error {
+ /* Common error (0~99) */
+ ERROR_COMMON_NONE = 0,
+ ERROR_COMMON_CMD = 1, /* Invalid command */
+ ERROR_COMMON_PARAMETER = 2, /* Invalid parameter */
+ /* setfile is not loaded before adjusting */
+ ERROR_COMMON_SETFILE_LOAD = 3,
+ /* setfile is not Adjusted before runnng. */
+ ERROR_COMMON_SETFILE_ADJUST = 4,
+ /* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */
+ ERROR_COMMON_SETFILE_INDEX = 5,
+ /* Input path can be changed in ready state(stop) */
+ ERROR_COMMON_INPUT_PATH = 6,
+ /* IP can not start if input path is not set */
+ ERROR_COMMON_INPUT_INIT = 7,
+ /* Output path can be changed in ready state (stop) */
+ ERROR_COMMON_OUTPUT_PATH = 8,
+ /* IP can not start if output path is not set */
+ ERROR_COMMON_OUTPUT_INIT = 9,
+
+ ERROR_CONTROL_NONE = ERROR_COMMON_NONE,
+ ERROR_CONTROL_BYPASS = 11, /* Enable or Disable */
+
+ ERROR_OTF_INPUT_NONE = ERROR_COMMON_NONE,
+ ERROR_OTF_INPUT_CMD = 21,
+ /* invalid format (DRC: YUV444, FD: YUV444, 422, 420) */
+ ERROR_OTF_INPUT_FORMAT = 22,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_OTF_INPUT_WIDTH = 23,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_OTF_INPUT_HEIGHT = 24,
+ /* invalid bit-width (DRC: 8~12bits, FD: 8bit) */
+ ERROR_OTF_INPUT_BIT_WIDTH = 25,
+ /* invalid FrameTime for ISP */
+ ERROR_OTF_INPUT_USER_FRAMETIIME = 26,
+
+ ERROR_DMA_INPUT_NONE = ERROR_COMMON_NONE,
+ /* invalid width (DRC: 128~8192, FD: 32~8190) */
+ ERROR_DMA_INPUT_WIDTH = 31,
+ /* invalid height (DRC: 64~8192, FD: 16~8190) */
+ ERROR_DMA_INPUT_HEIGHT = 32,
+ /* invalid format (DRC: YUV444 or YUV422, FD: YUV444, 422, 420) */
+ ERROR_DMA_INPUT_FORMAT = 33,
+ /* invalid bit-width (DRC: 8~12bit, FD: 8bit) */
+ ERROR_DMA_INPUT_BIT_WIDTH = 34,
+ /* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */
+ ERROR_DMA_INPUT_ORDER = 35,
+ /* invalid palne (DRC: 3, FD: 1, 2, 3) */
+ ERROR_DMA_INPUT_PLANE = 36,
+
+ ERROR_OTF_OUTPUT_NONE = ERROR_COMMON_NONE,
+ /* invalid width (DRC: 128~8192) */
+ ERROR_OTF_OUTPUT_WIDTH = 41,
+ /* invalid height (DRC: 64~8192) */
+ ERROR_OTF_OUTPUT_HEIGHT = 42,
+ /* invalid format (DRC: YUV444) */
+ ERROR_OTF_OUTPUT_FORMAT = 43,
+ /* invalid bit-width (DRC: 8~12bits) */
+ ERROR_OTF_OUTPUT_BIT_WIDTH = 44,
+
+ ERROR_DMA_OUTPUT_NONE = ERROR_COMMON_NONE,
+ ERROR_DMA_OUTPUT_WIDTH = 51, /* invalid width */
+ ERROR_DMA_OUTPUT_HEIGHT = 52, /* invalid height */
+ ERROR_DMA_OUTPUT_FORMAT = 53, /* invalid format */
+ ERROR_DMA_OUTPUT_BIT_WIDTH = 54, /* invalid bit-width */
+ ERROR_DMA_OUTPUT_PLANE = 55, /* invalid plane */
+ ERROR_DMA_OUTPUT_ORDER = 56, /* invalid order */
+
+ ERROR_GLOBAL_SHOTMODE_NONE = ERROR_COMMON_NONE,
+
+ /* SENSOR Error(100~199) */
+ ERROR_SENSOR_NONE = ERROR_COMMON_NONE,
+ ERROR_SENSOR_I2C_FAIL = 101,
+ ERROR_SENSOR_INVALID_FRAMERATE,
+ ERROR_SENSOR_INVALID_EXPOSURETIME,
+ ERROR_SENSOR_INVALID_SIZE,
+ ERROR_SENSOR_INVALID_SETTING,
+ ERROR_SENSOR_ACTURATOR_INIT_FAIL,
+ ERROR_SENSOR_INVALID_AF_POS,
+ ERROR_SENSOR_UNSUPPORT_FUNC,
+ ERROR_SENSOR_UNSUPPORT_PERI,
+ ERROR_SENSOR_UNSUPPORT_AF,
+
+ /* ISP Error (200~299) */
+ ERROR_ISP_AF_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_AF_BUSY = 201,
+ ERROR_ISP_AF_INVALID_COMMAND = 202,
+ ERROR_ISP_AF_INVALID_MODE = 203,
+ ERROR_ISP_FLASH_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_AWB_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_IMAGE_EFFECT_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_ISO_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_ADJUST_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_METERING_NONE = ERROR_COMMON_NONE,
+ ERROR_ISP_AFC_NONE = ERROR_COMMON_NONE,
+
+ /* DRC Error (300~399) */
+
+ /* FD Error (400~499) */
+ ERROR_FD_NONE = ERROR_COMMON_NONE,
+ /* Invalid max number (1~16) */
+ ERROR_FD_CONFIG_MAX_NUMBER_STATE = 401,
+ ERROR_FD_CONFIG_MAX_NUMBER_INVALID = 402,
+ ERROR_FD_CONFIG_YAW_ANGLE_STATE = 403,
+ ERROR_FD_CONFIG_YAW_ANGLE_INVALID = 404,
+ ERROR_FD_CONFIG_ROLL_ANGLE_STATE = 405,
+ ERROR_FD_CONFIG_ROLL_ANGLE_INVALID = 406,
+ ERROR_FD_CONFIG_SMILE_MODE_INVALID = 407,
+ ERROR_FD_CONFIG_BLINK_MODE_INVALID = 408,
+ ERROR_FD_CONFIG_EYES_DETECT_INVALID = 409,
+ ERROR_FD_CONFIG_MOUTH_DETECT_INVALID = 410,
+ ERROR_FD_CONFIG_ORIENTATION_STATE = 411,
+ ERROR_FD_CONFIG_ORIENTATION_INVALID = 412,
+ ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID = 413,
+ /* PARAM_FdResultStr can be only applied in ready-state or stream off */
+ ERROR_FD_RESULT = 414,
+ /* PARAM_FdModeStr can be only applied in ready-state or stream off */
+ ERROR_FD_MODE = 415,
+ /* Scaler Error (500 ~ 599) */
+ ERROR_SCALER_NO_NONE = ERROR_COMMON_NONE,
+ ERROR_SCALER_DMA_OUTSEL = 501,
+ ERROR_SCALER_H_RATIO = 502,
+ ERROR_SCALER_V_RATIO = 503,
+
+ ERROR_SCALER_IMAGE_EFFECT = 510,
+
+ ERROR_SCALER_ROTATE = 520,
+ ERROR_SCALER_FLIP = 521,
+};
+
+const char * const fimc_is_strerr(unsigned int error);
+const char * const fimc_is_param_strerr(unsigned int error);
+
+#endif /* FIMC_IS_ERR_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
new file mode 100644
index 000000000000..c397777d7cbb
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -0,0 +1,126 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include "fimc-is-i2c.h"
+
+struct fimc_is_i2c {
+ struct i2c_adapter adapter;
+ struct clk *clock;
+};
+
+/*
+ * An empty algorithm is used as the actual I2C bus controller driver
+ * is implemented in the FIMC-IS subsystem firmware and the host CPU
+ * doesn't access the I2C bus controller.
+ */
+static const struct i2c_algorithm fimc_is_i2c_algorithm;
+
+static int fimc_is_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct fimc_is_i2c *isp_i2c;
+ struct i2c_adapter *i2c_adap;
+ int ret;
+
+ isp_i2c = devm_kzalloc(&pdev->dev, sizeof(*isp_i2c), GFP_KERNEL);
+ if (!isp_i2c)
+ return -ENOMEM;
+
+ isp_i2c->clock = devm_clk_get(&pdev->dev, "i2c_isp");
+ if (IS_ERR(isp_i2c->clock)) {
+ dev_err(&pdev->dev, "failed to get the clock\n");
+ return PTR_ERR(isp_i2c->clock);
+ }
+
+ i2c_adap = &isp_i2c->adapter;
+ i2c_adap->dev.of_node = node;
+ i2c_adap->dev.parent = &pdev->dev;
+ strlcpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name));
+ i2c_adap->owner = THIS_MODULE;
+ i2c_adap->algo = &fimc_is_i2c_algorithm;
+ i2c_adap->class = I2C_CLASS_SPD;
+
+ ret = i2c_add_adapter(i2c_adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add I2C bus %s\n",
+ node->full_name);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, isp_i2c);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_enable(&i2c_adap->dev);
+
+ of_i2c_register_devices(i2c_adap);
+
+ return 0;
+}
+
+static int fimc_is_i2c_remove(struct platform_device *pdev)
+{
+ struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&isp_i2c->adapter.dev);
+ pm_runtime_disable(&pdev->dev);
+ i2c_del_adapter(&isp_i2c->adapter);
+
+ return 0;
+}
+
+static int fimc_is_i2c_suspend(struct device *dev)
+{
+ struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
+ clk_disable_unprepare(isp_i2c->clock);
+ return 0;
+}
+
+static int fimc_is_i2c_resume(struct device *dev)
+{
+ struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
+ return clk_prepare_enable(isp_i2c->clock);
+}
+
+UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend,
+ fimc_is_i2c_resume, NULL);
+
+static const struct of_device_id fimc_is_i2c_of_match[] = {
+ { .compatible = FIMC_IS_I2C_COMPATIBLE },
+ { },
+};
+
+static struct platform_driver fimc_is_i2c_driver = {
+ .probe = fimc_is_i2c_probe,
+ .remove = fimc_is_i2c_remove,
+ .driver = {
+ .of_match_table = fimc_is_i2c_of_match,
+ .name = "fimc-isp-i2c",
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_i2c_pm_ops,
+ }
+};
+
+int fimc_is_register_i2c_driver(void)
+{
+ return platform_driver_register(&fimc_is_i2c_driver);
+}
+
+void fimc_is_unregister_i2c_driver(void)
+{
+ platform_driver_unregister(&fimc_is_i2c_driver);
+}
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.h b/drivers/media/platform/exynos4-is/fimc-is-i2c.h
new file mode 100644
index 000000000000..0d38d6bb963b
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.h
@@ -0,0 +1,15 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp"
+
+int fimc_is_register_i2c_driver(void);
+void fimc_is_unregister_i2c_driver(void);
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c
new file mode 100644
index 000000000000..53fe2a2b4db3
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.c
@@ -0,0 +1,900 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-errno.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-sensor.h"
+
+static void __hw_param_copy(void *dst, void *src)
+{
+ memcpy(dst, src, FIMC_IS_PARAM_MAX_SIZE);
+}
+
+void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
+{
+ struct param_global_shotmode *dst, *src;
+
+ dst = &is->is_p_region->parameter.global.shotmode;
+ src = &is->config[is->config_index].global.shotmode;
+ __hw_param_copy(dst, src);
+}
+
+void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
+{
+ struct param_sensor_framerate *dst, *src;
+
+ dst = &is->is_p_region->parameter.sensor.frame_rate;
+ src = &is->config[is->config_index].sensor.frame_rate;
+ __hw_param_copy(dst, src);
+}
+
+int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset)
+{
+ struct is_param_region *par = &is->is_p_region->parameter;
+ struct chain_config *cfg = &is->config[is->config_index];
+
+ switch (offset) {
+ case PARAM_ISP_CONTROL:
+ __hw_param_copy(&par->isp.control, &cfg->isp.control);
+ break;
+
+ case PARAM_ISP_OTF_INPUT:
+ __hw_param_copy(&par->isp.otf_input, &cfg->isp.otf_input);
+ break;
+
+ case PARAM_ISP_DMA1_INPUT:
+ __hw_param_copy(&par->isp.dma1_input, &cfg->isp.dma1_input);
+ break;
+
+ case PARAM_ISP_DMA2_INPUT:
+ __hw_param_copy(&par->isp.dma2_input, &cfg->isp.dma2_input);
+ break;
+
+ case PARAM_ISP_AA:
+ __hw_param_copy(&par->isp.aa, &cfg->isp.aa);
+ break;
+
+ case PARAM_ISP_FLASH:
+ __hw_param_copy(&par->isp.flash, &cfg->isp.flash);
+ break;
+
+ case PARAM_ISP_AWB:
+ __hw_param_copy(&par->isp.awb, &cfg->isp.awb);
+ break;
+
+ case PARAM_ISP_IMAGE_EFFECT:
+ __hw_param_copy(&par->isp.effect, &cfg->isp.effect);
+ break;
+
+ case PARAM_ISP_ISO:
+ __hw_param_copy(&par->isp.iso, &cfg->isp.iso);
+ break;
+
+ case PARAM_ISP_ADJUST:
+ __hw_param_copy(&par->isp.adjust, &cfg->isp.adjust);
+ break;
+
+ case PARAM_ISP_METERING:
+ __hw_param_copy(&par->isp.metering, &cfg->isp.metering);
+ break;
+
+ case PARAM_ISP_AFC:
+ __hw_param_copy(&par->isp.afc, &cfg->isp.afc);
+ break;
+
+ case PARAM_ISP_OTF_OUTPUT:
+ __hw_param_copy(&par->isp.otf_output, &cfg->isp.otf_output);
+ break;
+
+ case PARAM_ISP_DMA1_OUTPUT:
+ __hw_param_copy(&par->isp.dma1_output, &cfg->isp.dma1_output);
+ break;
+
+ case PARAM_ISP_DMA2_OUTPUT:
+ __hw_param_copy(&par->isp.dma2_output, &cfg->isp.dma2_output);
+ break;
+
+ case PARAM_DRC_CONTROL:
+ __hw_param_copy(&par->drc.control, &cfg->drc.control);
+ break;
+
+ case PARAM_DRC_OTF_INPUT:
+ __hw_param_copy(&par->drc.otf_input, &cfg->drc.otf_input);
+ break;
+
+ case PARAM_DRC_DMA_INPUT:
+ __hw_param_copy(&par->drc.dma_input, &cfg->drc.dma_input);
+ break;
+
+ case PARAM_DRC_OTF_OUTPUT:
+ __hw_param_copy(&par->drc.otf_output, &cfg->drc.otf_output);
+ break;
+
+ case PARAM_FD_CONTROL:
+ __hw_param_copy(&par->fd.control, &cfg->fd.control);
+ break;
+
+ case PARAM_FD_OTF_INPUT:
+ __hw_param_copy(&par->fd.otf_input, &cfg->fd.otf_input);
+ break;
+
+ case PARAM_FD_DMA_INPUT:
+ __hw_param_copy(&par->fd.dma_input, &cfg->fd.dma_input);
+ break;
+
+ case PARAM_FD_CONFIG:
+ __hw_param_copy(&par->fd.config, &cfg->fd.config);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+unsigned int __get_pending_param_count(struct fimc_is *is)
+{
+ struct chain_config *config = &is->config[is->config_index];
+ unsigned long flags;
+ unsigned int count;
+
+ spin_lock_irqsave(&is->slock, flags);
+ count = hweight32(config->p_region_index1);
+ count += hweight32(config->p_region_index2);
+ spin_unlock_irqrestore(&is->slock, flags);
+
+ return count;
+}
+
+int __is_hw_update_params(struct fimc_is *is)
+{
+ unsigned long *p_index1, *p_index2;
+ int i, id, ret = 0;
+
+ id = is->config_index;
+ p_index1 = &is->config[id].p_region_index1;
+ p_index2 = &is->config[id].p_region_index2;
+
+ if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1))
+ __fimc_is_hw_update_param_global_shotmode(is);
+
+ if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index1))
+ __fimc_is_hw_update_param_sensor_framerate(is);
+
+ for (i = PARAM_ISP_CONTROL; i < PARAM_DRC_CONTROL; i++) {
+ if (test_bit(i, p_index1))
+ ret = __fimc_is_hw_update_param(is, i);
+ }
+
+ for (i = PARAM_DRC_CONTROL; i < PARAM_SCALERC_CONTROL; i++) {
+ if (test_bit(i, p_index1))
+ ret = __fimc_is_hw_update_param(is, i);
+ }
+
+ for (i = PARAM_FD_CONTROL; i <= PARAM_FD_CONFIG; i++) {
+ if (test_bit((i - 32), p_index2))
+ ret = __fimc_is_hw_update_param(is, i);
+ }
+
+ return ret;
+}
+
+void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
+{
+ struct isp_param *isp;
+
+ isp = &is->config[is->config_index].isp;
+ mf->width = isp->otf_input.width;
+ mf->height = isp->otf_input.height;
+}
+
+void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+ struct drc_param *drc;
+ struct fd_param *fd;
+
+ isp = &is->config[index].isp;
+ drc = &is->config[index].drc;
+ fd = &is->config[index].fd;
+
+ /* Update isp size info (OTF only) */
+ isp->otf_input.width = mf->width;
+ isp->otf_input.height = mf->height;
+ isp->otf_output.width = mf->width;
+ isp->otf_output.height = mf->height;
+ /* Update drc size info (OTF only) */
+ drc->otf_input.width = mf->width;
+ drc->otf_input.height = mf->height;
+ drc->otf_output.width = mf->width;
+ drc->otf_output.height = mf->height;
+ /* Update fd size info (OTF only) */
+ fd->otf_input.width = mf->width;
+ fd->otf_input.height = mf->height;
+
+ if (test_bit(PARAM_ISP_OTF_INPUT,
+ &is->config[index].p_region_index1))
+ return;
+
+ /* Update field */
+ fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+ fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
+ fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
+ fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
+ fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
+}
+
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is)
+{
+ switch (is->sensor->drvdata->id) {
+ case FIMC_IS_SENSOR_ID_S5K6A3:
+ return 30;
+ default:
+ return 15;
+ }
+}
+
+void __is_set_sensor(struct fimc_is *is, int fps)
+{
+ unsigned int index = is->config_index;
+ struct sensor_param *sensor;
+ struct isp_param *isp;
+
+ sensor = &is->config[index].sensor;
+ isp = &is->config[index].isp;
+
+ if (fps == 0) {
+ sensor->frame_rate.frame_rate =
+ fimc_is_hw_get_sensor_max_framerate(is);
+ isp->otf_input.frametime_min = 0;
+ isp->otf_input.frametime_max = 66666;
+ } else {
+ sensor->frame_rate.frame_rate = fps;
+ isp->otf_input.frametime_min = 0;
+ isp->otf_input.frametime_max = (u32)1000000 / fps;
+ }
+
+ fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE);
+ fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+}
+
+void __is_set_init_isp_aa(struct fimc_is *is)
+{
+ struct isp_param *isp;
+
+ isp = &is->config[is->config_index].isp;
+
+ isp->aa.cmd = ISP_AA_COMMAND_START;
+ isp->aa.target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE |
+ ISP_AA_TARGET_AWB;
+ isp->aa.mode = 0;
+ isp->aa.scene = 0;
+ isp->aa.sleep = 0;
+ isp->aa.face = 0;
+ isp->aa.touch_x = 0;
+ isp->aa.touch_y = 0;
+ isp->aa.manual_af_setting = 0;
+ isp->aa.err = ISP_AF_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_AA);
+}
+
+void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp = &is->config[index].isp;
+
+ isp->flash.cmd = cmd;
+ isp->flash.redeye = redeye;
+ isp->flash.err = ISP_FLASH_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_FLASH);
+}
+
+void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+
+ isp = &is->config[index].isp;
+
+ isp->awb.cmd = cmd;
+ isp->awb.illumination = val;
+ isp->awb.err = ISP_AWB_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_AWB);
+}
+
+void __is_set_isp_effect(struct fimc_is *is, u32 cmd)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+
+ isp = &is->config[index].isp;
+
+ isp->effect.cmd = cmd;
+ isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT);
+}
+
+void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+
+ isp = &is->config[index].isp;
+
+ isp->iso.cmd = cmd;
+ isp->iso.value = val;
+ isp->iso.err = ISP_ISO_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_ISO);
+}
+
+void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val)
+{
+ unsigned int index = is->config_index;
+ unsigned long *p_index;
+ struct isp_param *isp;
+
+ p_index = &is->config[index].p_region_index1;
+ isp = &is->config[index].isp;
+
+ switch (cmd) {
+ case ISP_ADJUST_COMMAND_MANUAL_CONTRAST:
+ isp->adjust.contrast = val;
+ break;
+ case ISP_ADJUST_COMMAND_MANUAL_SATURATION:
+ isp->adjust.saturation = val;
+ break;
+ case ISP_ADJUST_COMMAND_MANUAL_SHARPNESS:
+ isp->adjust.sharpness = val;
+ break;
+ case ISP_ADJUST_COMMAND_MANUAL_EXPOSURE:
+ isp->adjust.exposure = val;
+ break;
+ case ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS:
+ isp->adjust.brightness = val;
+ break;
+ case ISP_ADJUST_COMMAND_MANUAL_HUE:
+ isp->adjust.hue = val;
+ break;
+ case ISP_ADJUST_COMMAND_AUTO:
+ isp->adjust.contrast = 0;
+ isp->adjust.saturation = 0;
+ isp->adjust.sharpness = 0;
+ isp->adjust.exposure = 0;
+ isp->adjust.brightness = 0;
+ isp->adjust.hue = 0;
+ break;
+ }
+
+ if (!test_bit(PARAM_ISP_ADJUST, p_index)) {
+ isp->adjust.cmd = cmd;
+ isp->adjust.err = ISP_ADJUST_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_ADJUST);
+ } else {
+ isp->adjust.cmd |= cmd;
+ }
+}
+
+void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index1;
+ isp = &is->config[index].isp;
+
+ switch (id) {
+ case IS_METERING_CONFIG_CMD:
+ isp->metering.cmd = val;
+ break;
+ case IS_METERING_CONFIG_WIN_POS_X:
+ isp->metering.win_pos_x = val;
+ break;
+ case IS_METERING_CONFIG_WIN_POS_Y:
+ isp->metering.win_pos_y = val;
+ break;
+ case IS_METERING_CONFIG_WIN_WIDTH:
+ isp->metering.win_width = val;
+ break;
+ case IS_METERING_CONFIG_WIN_HEIGHT:
+ isp->metering.win_height = val;
+ break;
+ default:
+ return;
+ }
+
+ if (!test_bit(PARAM_ISP_METERING, p_index)) {
+ isp->metering.err = ISP_METERING_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_METERING);
+ }
+}
+
+void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct isp_param *isp;
+
+ isp = &is->config[index].isp;
+
+ isp->afc.cmd = cmd;
+ isp->afc.manual = val;
+ isp->afc.err = ISP_AFC_ERROR_NONE;
+
+ fimc_is_set_param_bit(is, PARAM_ISP_AFC);
+}
+
+void __is_set_drc_control(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct drc_param *drc;
+
+ drc = &is->config[index].drc;
+
+ drc->control.bypass = val;
+
+ fimc_is_set_param_bit(is, PARAM_DRC_CONTROL);
+}
+
+void __is_set_fd_control(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->control.cmd = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index))
+ fimc_is_set_param_bit(is, PARAM_FD_CONTROL);
+}
+
+void __is_set_fd_config_maxface(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.max_number = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_MAXIMUM_NUMBER;
+ }
+}
+
+void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.roll_angle = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_ROLL_ANGLE;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_ROLL_ANGLE;
+ }
+}
+
+void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.yaw_angle = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_YAW_ANGLE;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_YAW_ANGLE;
+ }
+}
+
+void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.smile_mode = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_SMILE_MODE;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_SMILE_MODE;
+ }
+}
+
+void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.blink_mode = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_BLINK_MODE;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_BLINK_MODE;
+ }
+}
+
+void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.eye_detect = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_EYES_DETECT;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_EYES_DETECT;
+ }
+}
+
+void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.mouth_detect = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_MOUTH_DETECT;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_MOUTH_DETECT;
+ }
+}
+
+void __is_set_fd_config_orientation(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.orientation = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION;
+ }
+}
+
+void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
+{
+ unsigned int index = is->config_index;
+ struct fd_param *fd;
+ unsigned long *p_index;
+
+ p_index = &is->config[index].p_region_index2;
+ fd = &is->config[index].fd;
+
+ fd->config.orientation_value = val;
+
+ if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+ fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION_VALUE;
+ fd->config.err = ERROR_FD_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+ } else {
+ fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION_VALUE;
+ }
+}
+
+void fimc_is_set_initial_params(struct fimc_is *is)
+{
+ struct global_param *global;
+ struct sensor_param *sensor;
+ struct isp_param *isp;
+ struct drc_param *drc;
+ struct fd_param *fd;
+ unsigned long *p_index1, *p_index2;
+ unsigned int index;
+
+ index = is->config_index;
+ global = &is->config[index].global;
+ sensor = &is->config[index].sensor;
+ isp = &is->config[index].isp;
+ drc = &is->config[index].drc;
+ fd = &is->config[index].fd;
+ p_index1 = &is->config[index].p_region_index1;
+ p_index2 = &is->config[index].p_region_index2;
+
+ /* Global */
+ global->shotmode.cmd = 1;
+ fimc_is_set_param_bit(is, PARAM_GLOBAL_SHOTMODE);
+
+ /* ISP */
+ isp->control.cmd = CONTROL_COMMAND_START;
+ isp->control.bypass = CONTROL_BYPASS_DISABLE;
+ isp->control.err = CONTROL_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
+
+ isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+ if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) {
+ isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+ }
+ if (is->sensor->test_pattern)
+ isp->otf_input.format = OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER;
+ else
+ isp->otf_input.format = OTF_INPUT_FORMAT_BAYER;
+ isp->otf_input.bitwidth = 10;
+ isp->otf_input.order = OTF_INPUT_ORDER_BAYER_GR_BG;
+ isp->otf_input.crop_offset_x = 0;
+ isp->otf_input.crop_offset_y = 0;
+ isp->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+ isp->dma1_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+ isp->dma1_input.width = 0;
+ isp->dma1_input.height = 0;
+ isp->dma1_input.format = 0;
+ isp->dma1_input.bitwidth = 0;
+ isp->dma1_input.plane = 0;
+ isp->dma1_input.order = 0;
+ isp->dma1_input.buffer_number = 0;
+ isp->dma1_input.width = 0;
+ isp->dma1_input.err = DMA_INPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_DMA1_INPUT);
+
+ isp->dma2_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+ isp->dma2_input.width = 0;
+ isp->dma2_input.height = 0;
+ isp->dma2_input.format = 0;
+ isp->dma2_input.bitwidth = 0;
+ isp->dma2_input.plane = 0;
+ isp->dma2_input.order = 0;
+ isp->dma2_input.buffer_number = 0;
+ isp->dma2_input.width = 0;
+ isp->dma2_input.err = DMA_INPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_DMA2_INPUT);
+
+ isp->aa.cmd = ISP_AA_COMMAND_START;
+ isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB;
+ fimc_is_set_param_bit(is, PARAM_ISP_AA);
+
+ if (!test_bit(PARAM_ISP_FLASH, p_index1))
+ __is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE,
+ ISP_FLASH_REDEYE_DISABLE);
+
+ if (!test_bit(PARAM_ISP_AWB, p_index1))
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
+
+ if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index1))
+ __is_set_isp_effect(is, ISP_IMAGE_EFFECT_DISABLE);
+
+ if (!test_bit(PARAM_ISP_ISO, p_index1))
+ __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
+
+ if (!test_bit(PARAM_ISP_ADJUST, p_index1)) {
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 0);
+ __is_set_isp_adjust(is,
+ ISP_ADJUST_COMMAND_MANUAL_SATURATION, 0);
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS, 0);
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE, 0);
+ __is_set_isp_adjust(is,
+ ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS, 0);
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 0);
+ }
+
+ if (!test_bit(PARAM_ISP_METERING, p_index1)) {
+ __is_set_isp_metering(is, 0, ISP_METERING_COMMAND_CENTER);
+ __is_set_isp_metering(is, 1, 0);
+ __is_set_isp_metering(is, 2, 0);
+ __is_set_isp_metering(is, 3, 0);
+ __is_set_isp_metering(is, 4, 0);
+ }
+
+ if (!test_bit(PARAM_ISP_AFC, p_index1))
+ __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
+
+ isp->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index1)) {
+ isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
+ }
+ isp->otf_output.format = OTF_OUTPUT_FORMAT_YUV444;
+ isp->otf_output.bitwidth = 12;
+ isp->otf_output.order = 0;
+ isp->otf_output.err = OTF_OUTPUT_ERROR_NONE;
+
+ if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index1)) {
+ isp->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ isp->dma1_output.width = 0;
+ isp->dma1_output.height = 0;
+ isp->dma1_output.format = 0;
+ isp->dma1_output.bitwidth = 0;
+ isp->dma1_output.plane = 0;
+ isp->dma1_output.order = 0;
+ isp->dma1_output.buffer_number = 0;
+ isp->dma1_output.buffer_address = 0;
+ isp->dma1_output.notify_dma_done = 0;
+ isp->dma1_output.dma_out_mask = 0;
+ isp->dma1_output.err = DMA_OUTPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT);
+ }
+
+ if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) {
+ isp->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+ isp->dma2_output.width = 0;
+ isp->dma2_output.height = 0;
+ isp->dma2_output.format = 0;
+ isp->dma2_output.bitwidth = 0;
+ isp->dma2_output.plane = 0;
+ isp->dma2_output.order = 0;
+ isp->dma2_output.buffer_number = 0;
+ isp->dma2_output.buffer_address = 0;
+ isp->dma2_output.notify_dma_done = 0;
+ isp->dma2_output.dma_out_mask = 0;
+ isp->dma2_output.err = DMA_OUTPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT);
+ }
+
+ /* Sensor */
+ if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) {
+ if (is->config_index == 0)
+ __is_set_sensor(is, 0);
+ }
+
+ /* DRC */
+ drc->control.cmd = CONTROL_COMMAND_START;
+ __is_set_drc_control(is, CONTROL_BYPASS_ENABLE);
+
+ drc->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+ if (!test_bit(PARAM_DRC_OTF_INPUT, p_index1)) {
+ drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
+ }
+ drc->otf_input.format = OTF_INPUT_FORMAT_YUV444;
+ drc->otf_input.bitwidth = 12;
+ drc->otf_input.order = 0;
+ drc->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+ drc->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+ drc->dma_input.width = 0;
+ drc->dma_input.height = 0;
+ drc->dma_input.format = 0;
+ drc->dma_input.bitwidth = 0;
+ drc->dma_input.plane = 0;
+ drc->dma_input.order = 0;
+ drc->dma_input.buffer_number = 0;
+ drc->dma_input.width = 0;
+ drc->dma_input.err = DMA_INPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT);
+
+ drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) {
+ drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
+ }
+ drc->otf_output.format = OTF_OUTPUT_FORMAT_YUV444;
+ drc->otf_output.bitwidth = 8;
+ drc->otf_output.order = 0;
+ drc->otf_output.err = OTF_OUTPUT_ERROR_NONE;
+
+ /* FD */
+ __is_set_fd_control(is, CONTROL_COMMAND_STOP);
+ fd->control.bypass = CONTROL_BYPASS_DISABLE;
+
+ fd->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+ if (!test_bit((PARAM_FD_OTF_INPUT - 32), p_index2)) {
+ fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
+ }
+
+ fd->otf_input.format = OTF_INPUT_FORMAT_YUV444;
+ fd->otf_input.bitwidth = 8;
+ fd->otf_input.order = 0;
+ fd->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+ fd->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+ fd->dma_input.width = 0;
+ fd->dma_input.height = 0;
+ fd->dma_input.format = 0;
+ fd->dma_input.bitwidth = 0;
+ fd->dma_input.plane = 0;
+ fd->dma_input.order = 0;
+ fd->dma_input.buffer_number = 0;
+ fd->dma_input.width = 0;
+ fd->dma_input.err = DMA_INPUT_ERROR_NONE;
+ fimc_is_set_param_bit(is, PARAM_FD_DMA_INPUT);
+
+ __is_set_fd_config_maxface(is, 5);
+ __is_set_fd_config_rollangle(is, FD_CONFIG_ROLL_ANGLE_FULL);
+ __is_set_fd_config_yawangle(is, FD_CONFIG_YAW_ANGLE_45_90);
+ __is_set_fd_config_smilemode(is, FD_CONFIG_SMILE_MODE_DISABLE);
+ __is_set_fd_config_blinkmode(is, FD_CONFIG_BLINK_MODE_DISABLE);
+ __is_set_fd_config_eyedetect(is, FD_CONFIG_EYES_DETECT_ENABLE);
+ __is_set_fd_config_mouthdetect(is, FD_CONFIG_MOUTH_DETECT_DISABLE);
+ __is_set_fd_config_orientation(is, FD_CONFIG_ORIENTATION_DISABLE);
+ __is_set_fd_config_orientation_val(is, 0);
+}
diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h
new file mode 100644
index 000000000000..f9358c27ae2d
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-param.h
@@ -0,0 +1,1020 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_PARAM_H_
+#define FIMC_IS_PARAM_H_
+
+#include <linux/compiler.h>
+
+#define FIMC_IS_CONFIG_TIMEOUT 3000 /* ms */
+#define IS_DEFAULT_WIDTH 1280
+#define IS_DEFAULT_HEIGHT 720
+
+#define DEFAULT_PREVIEW_STILL_WIDTH IS_DEFAULT_WIDTH
+#define DEFAULT_PREVIEW_STILL_HEIGHT IS_DEFAULT_HEIGHT
+#define DEFAULT_CAPTURE_STILL_WIDTH IS_DEFAULT_WIDTH
+#define DEFAULT_CAPTURE_STILL_HEIGHT IS_DEFAULT_HEIGHT
+#define DEFAULT_PREVIEW_VIDEO_WIDTH IS_DEFAULT_WIDTH
+#define DEFAULT_PREVIEW_VIDEO_HEIGHT IS_DEFAULT_HEIGHT
+#define DEFAULT_CAPTURE_VIDEO_WIDTH IS_DEFAULT_WIDTH
+#define DEFAULT_CAPTURE_VIDEO_HEIGHT IS_DEFAULT_HEIGHT
+
+#define DEFAULT_PREVIEW_STILL_FRAMERATE 30
+#define DEFAULT_CAPTURE_STILL_FRAMERATE 15
+#define DEFAULT_PREVIEW_VIDEO_FRAMERATE 30
+#define DEFAULT_CAPTURE_VIDEO_FRAMERATE 30
+
+#define FIMC_IS_REGION_VER 124 /* IS REGION VERSION 1.24 */
+#define FIMC_IS_PARAM_SIZE (FIMC_IS_REGION_SIZE + 1)
+#define FIMC_IS_MAGIC_NUMBER 0x01020304
+#define FIMC_IS_PARAM_MAX_SIZE 64 /* in bytes */
+#define FIMC_IS_PARAM_MAX_ENTRIES (FIMC_IS_PARAM_MAX_SIZE / 4)
+
+/* The parameter bitmask bit definitions. */
+enum is_param_bit {
+ PARAM_GLOBAL_SHOTMODE,
+ PARAM_SENSOR_CONTROL,
+ PARAM_SENSOR_OTF_OUTPUT,
+ PARAM_SENSOR_FRAME_RATE,
+ PARAM_BUFFER_CONTROL,
+ PARAM_BUFFER_OTF_INPUT,
+ PARAM_BUFFER_OTF_OUTPUT,
+ PARAM_ISP_CONTROL,
+ PARAM_ISP_OTF_INPUT,
+ PARAM_ISP_DMA1_INPUT,
+ /* 10 */
+ PARAM_ISP_DMA2_INPUT,
+ PARAM_ISP_AA,
+ PARAM_ISP_FLASH,
+ PARAM_ISP_AWB,
+ PARAM_ISP_IMAGE_EFFECT,
+ PARAM_ISP_ISO,
+ PARAM_ISP_ADJUST,
+ PARAM_ISP_METERING,
+ PARAM_ISP_AFC,
+ PARAM_ISP_OTF_OUTPUT,
+ /* 20 */
+ PARAM_ISP_DMA1_OUTPUT,
+ PARAM_ISP_DMA2_OUTPUT,
+ PARAM_DRC_CONTROL,
+ PARAM_DRC_OTF_INPUT,
+ PARAM_DRC_DMA_INPUT,
+ PARAM_DRC_OTF_OUTPUT,
+ PARAM_SCALERC_CONTROL,
+ PARAM_SCALERC_OTF_INPUT,
+ PARAM_SCALERC_IMAGE_EFFECT,
+ PARAM_SCALERC_INPUT_CROP,
+ /* 30 */
+ PARAM_SCALERC_OUTPUT_CROP,
+ PARAM_SCALERC_OTF_OUTPUT,
+ PARAM_SCALERC_DMA_OUTPUT,
+ PARAM_ODC_CONTROL,
+ PARAM_ODC_OTF_INPUT,
+ PARAM_ODC_OTF_OUTPUT,
+ PARAM_DIS_CONTROL,
+ PARAM_DIS_OTF_INPUT,
+ PARAM_DIS_OTF_OUTPUT,
+ PARAM_TDNR_CONTROL,
+ /* 40 */
+ PARAM_TDNR_OTF_INPUT,
+ PARAM_TDNR_1ST_FRAME,
+ PARAM_TDNR_OTF_OUTPUT,
+ PARAM_TDNR_DMA_OUTPUT,
+ PARAM_SCALERP_CONTROL,
+ PARAM_SCALERP_OTF_INPUT,
+ PARAM_SCALERP_IMAGE_EFFECT,
+ PARAM_SCALERP_INPUT_CROP,
+ PARAM_SCALERP_OUTPUT_CROP,
+ PARAM_SCALERP_ROTATION,
+ /* 50 */
+ PARAM_SCALERP_FLIP,
+ PARAM_SCALERP_OTF_OUTPUT,
+ PARAM_SCALERP_DMA_OUTPUT,
+ PARAM_FD_CONTROL,
+ PARAM_FD_OTF_INPUT,
+ PARAM_FD_DMA_INPUT,
+ PARAM_FD_CONFIG,
+};
+
+/* Interrupt map */
+#define FIMC_IS_INT_GENERAL 0
+#define FIMC_IS_INT_FRAME_DONE_ISP 1
+
+/* Input */
+
+#define CONTROL_COMMAND_STOP 0
+#define CONTROL_COMMAND_START 1
+
+#define CONTROL_BYPASS_DISABLE 0
+#define CONTROL_BYPASS_ENABLE 1
+
+#define CONTROL_ERROR_NONE 0
+
+/* OTF (On-The-Fly) input interface commands */
+#define OTF_INPUT_COMMAND_DISABLE 0
+#define OTF_INPUT_COMMAND_ENABLE 1
+
+/* OTF input interface color formats */
+enum oft_input_fmt {
+ OTF_INPUT_FORMAT_BAYER = 0, /* 1 channel */
+ OTF_INPUT_FORMAT_YUV444 = 1, /* 3 channels */
+ OTF_INPUT_FORMAT_YUV422 = 2, /* 3 channels */
+ OTF_INPUT_FORMAT_YUV420 = 3, /* 3 channels */
+ OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER = 10,
+ OTF_INPUT_FORMAT_BAYER_DMA = 11,
+};
+
+#define OTF_INPUT_ORDER_BAYER_GR_BG 0
+
+/* OTF input error codes */
+#define OTF_INPUT_ERROR_NONE 0 /* Input setting is done */
+
+/* DMA input commands */
+#define DMA_INPUT_COMMAND_DISABLE 0
+#define DMA_INPUT_COMMAND_ENABLE 1
+
+/* DMA input color formats */
+enum dma_input_fmt {
+ DMA_INPUT_FORMAT_BAYER = 0,
+ DMA_INPUT_FORMAT_YUV444 = 1,
+ DMA_INPUT_FORMAT_YUV422 = 2,
+ DMA_INPUT_FORMAT_YUV420 = 3,
+};
+
+enum dma_input_order {
+ /* (for DMA_INPUT_PLANE_3) */
+ DMA_INPUT_ORDER_NO = 0,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CBCR = 1,
+ /* (only valid at DMA_INPUT_PLANE_2) */
+ DMA_INPUT_ORDER_CRCB = 2,
+ /* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */
+ DMA_INPUT_ORDER_YCBCR = 3,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YYCBCR = 4,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCBYCR = 5,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_YCRYCB = 6,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CBYCRY = 7,
+ /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+ DMA_INPUT_ORDER_CRYCBY = 8,
+ /* (only valid at DMA_INPUT_FORMAT_BAYER) */
+ DMA_INPUT_ORDER_GR_BG = 9
+};
+
+#define DMA_INPUT_ERROR_NONE 0 /* DMA input setting
+ is done */
+/*
+ * Data output parameter definitions
+ */
+#define OTF_OUTPUT_CROP_DISABLE 0
+#define OTF_OUTPUT_CROP_ENABLE 1
+
+#define OTF_OUTPUT_COMMAND_DISABLE 0
+#define OTF_OUTPUT_COMMAND_ENABLE 1
+
+enum otf_output_fmt {
+ OTF_OUTPUT_FORMAT_YUV444 = 1,
+ OTF_OUTPUT_FORMAT_YUV422 = 2,
+ OTF_OUTPUT_FORMAT_YUV420 = 3,
+ OTF_OUTPUT_FORMAT_RGB = 4,
+};
+
+#define OTF_OUTPUT_ORDER_BAYER_GR_BG 0
+
+#define OTF_OUTPUT_ERROR_NONE 0 /* Output Setting is done */
+
+#define DMA_OUTPUT_COMMAND_DISABLE 0
+#define DMA_OUTPUT_COMMAND_ENABLE 1
+
+enum dma_output_fmt {
+ DMA_OUTPUT_FORMAT_BAYER = 0,
+ DMA_OUTPUT_FORMAT_YUV444 = 1,
+ DMA_OUTPUT_FORMAT_YUV422 = 2,
+ DMA_OUTPUT_FORMAT_YUV420 = 3,
+ DMA_OUTPUT_FORMAT_RGB = 4,
+};
+
+enum dma_output_order {
+ DMA_OUTPUT_ORDER_NO = 0,
+ /* for DMA_OUTPUT_PLANE_3 */
+ DMA_OUTPUT_ORDER_CBCR = 1,
+ /* only valid at DMA_INPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_CRCB = 2,
+ /* only valid at DMA_OUTPUT_PLANE_2) */
+ DMA_OUTPUT_ORDER_YYCBCR = 3,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_YCBYCR = 4,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_YCRYCB = 5,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CBYCRY = 6,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CRYCBY = 7,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_YCBCR = 8,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CRYCB = 9,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CRCBY = 10,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CBYCR = 11,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_YCRCB = 12,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_CBCRY = 13,
+ /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+ DMA_OUTPUT_ORDER_BGR = 14,
+ /* only valid at DMA_OUTPUT_FORMAT_RGB */
+ DMA_OUTPUT_ORDER_GB_BG = 15
+ /* only valid at DMA_OUTPUT_FORMAT_BAYER */
+};
+
+/* enum dma_output_notify_dma_done */
+#define DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE 0
+#define DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE 1
+
+/* DMA output error codes */
+#define DMA_OUTPUT_ERROR_NONE 0 /* DMA output setting
+ is done */
+
+/* ---------------------- Global ----------------------------------- */
+#define GLOBAL_SHOTMODE_ERROR_NONE 0 /* shot-mode setting
+ is done */
+/* 3A lock commands */
+#define ISP_AA_COMMAND_START 0
+#define ISP_AA_COMMAND_STOP 1
+
+/* 3A lock target */
+#define ISP_AA_TARGET_AF 1
+#define ISP_AA_TARGET_AE 2
+#define ISP_AA_TARGET_AWB 4
+
+enum isp_af_mode {
+ ISP_AF_MODE_MANUAL = 0,
+ ISP_AF_MODE_SINGLE = 1,
+ ISP_AF_MODE_CONTINUOUS = 2,
+ ISP_AF_MODE_TOUCH = 3,
+ ISP_AF_MODE_SLEEP = 4,
+ ISP_AF_MODE_INIT = 5,
+ ISP_AF_MODE_SET_CENTER_WINDOW = 6,
+ ISP_AF_MODE_SET_TOUCH_WINDOW = 7
+};
+
+/* Face AF commands */
+#define ISP_AF_FACE_DISABLE 0
+#define ISP_AF_FACE_ENABLE 1
+
+/* AF range */
+#define ISP_AF_RANGE_NORMAL 0
+#define ISP_AF_RANGE_MACRO 1
+
+/* AF sleep */
+#define ISP_AF_SLEEP_OFF 0
+#define ISP_AF_SLEEP_ON 1
+
+/* Continuous AF commands */
+#define ISP_AF_CONTINUOUS_DISABLE 0
+#define ISP_AF_CONTINUOUS_ENABLE 1
+
+/* ISP AF error codes */
+#define ISP_AF_ERROR_NONE 0 /* AF mode change is done */
+#define ISP_AF_ERROR_NONE_LOCK_DONE 1 /* AF lock is done */
+
+/* Flash commands */
+#define ISP_FLASH_COMMAND_DISABLE 0
+#define ISP_FLASH_COMMAND_MANUAL_ON 1 /* (forced flash) */
+#define ISP_FLASH_COMMAND_AUTO 2
+#define ISP_FLASH_COMMAND_TORCH 3 /* 3 sec */
+
+/* Flash red-eye commads */
+#define ISP_FLASH_REDEYE_DISABLE 0
+#define ISP_FLASH_REDEYE_ENABLE 1
+
+/* Flash error codes */
+#define ISP_FLASH_ERROR_NONE 0 /* Flash setting is done */
+
+/* -------------------------- AWB ------------------------------------ */
+enum isp_awb_command {
+ ISP_AWB_COMMAND_AUTO = 0,
+ ISP_AWB_COMMAND_ILLUMINATION = 1,
+ ISP_AWB_COMMAND_MANUAL = 2
+};
+
+enum isp_awb_illumination {
+ ISP_AWB_ILLUMINATION_DAYLIGHT = 0,
+ ISP_AWB_ILLUMINATION_CLOUDY = 1,
+ ISP_AWB_ILLUMINATION_TUNGSTEN = 2,
+ ISP_AWB_ILLUMINATION_FLUORESCENT = 3
+};
+
+/* ISP AWN error codes */
+#define ISP_AWB_ERROR_NONE 0 /* AWB setting is done */
+
+/* -------------------------- Effect ----------------------------------- */
+enum isp_imageeffect_command {
+ ISP_IMAGE_EFFECT_DISABLE = 0,
+ ISP_IMAGE_EFFECT_MONOCHROME = 1,
+ ISP_IMAGE_EFFECT_NEGATIVE_MONO = 2,
+ ISP_IMAGE_EFFECT_NEGATIVE_COLOR = 3,
+ ISP_IMAGE_EFFECT_SEPIA = 4
+};
+
+/* Image effect error codes */
+#define ISP_IMAGE_EFFECT_ERROR_NONE 0 /* Image effect setting
+ is done */
+/* ISO commands */
+#define ISP_ISO_COMMAND_AUTO 0
+#define ISP_ISO_COMMAND_MANUAL 1
+
+/* ISO error codes */
+#define ISP_ISO_ERROR_NONE 0 /* ISO setting is done */
+
+/* ISP adjust commands */
+#define ISP_ADJUST_COMMAND_AUTO (0 << 0)
+#define ISP_ADJUST_COMMAND_MANUAL_CONTRAST (1 << 0)
+#define ISP_ADJUST_COMMAND_MANUAL_SATURATION (1 << 1)
+#define ISP_ADJUST_COMMAND_MANUAL_SHARPNESS (1 << 2)
+#define ISP_ADJUST_COMMAND_MANUAL_EXPOSURE (1 << 3)
+#define ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS (1 << 4)
+#define ISP_ADJUST_COMMAND_MANUAL_HUE (1 << 5)
+#define ISP_ADJUST_COMMAND_MANUAL_ALL 0x7f
+
+/* ISP adjustment error codes */
+#define ISP_ADJUST_ERROR_NONE 0 /* Adjust setting is done */
+
+/*
+ * Exposure metering
+ */
+enum isp_metering_command {
+ ISP_METERING_COMMAND_AVERAGE = 0,
+ ISP_METERING_COMMAND_SPOT = 1,
+ ISP_METERING_COMMAND_MATRIX = 2,
+ ISP_METERING_COMMAND_CENTER = 3
+};
+
+/* ISP metering error codes */
+#define ISP_METERING_ERROR_NONE 0 /* Metering setting is done */
+
+/*
+ * AFC
+ */
+enum isp_afc_command {
+ ISP_AFC_COMMAND_DISABLE = 0,
+ ISP_AFC_COMMAND_AUTO = 1,
+ ISP_AFC_COMMAND_MANUAL = 2,
+};
+
+#define ISP_AFC_MANUAL_50HZ 50
+#define ISP_AFC_MANUAL_60HZ 60
+
+/* ------------------------ SCENE MODE--------------------------------- */
+enum isp_scene_mode {
+ ISP_SCENE_NONE = 0,
+ ISP_SCENE_PORTRAIT = 1,
+ ISP_SCENE_LANDSCAPE = 2,
+ ISP_SCENE_SPORTS = 3,
+ ISP_SCENE_PARTYINDOOR = 4,
+ ISP_SCENE_BEACHSNOW = 5,
+ ISP_SCENE_SUNSET = 6,
+ ISP_SCENE_DAWN = 7,
+ ISP_SCENE_FALL = 8,
+ ISP_SCENE_NIGHT = 9,
+ ISP_SCENE_AGAINSTLIGHTWLIGHT = 10,
+ ISP_SCENE_AGAINSTLIGHTWOLIGHT = 11,
+ ISP_SCENE_FIRE = 12,
+ ISP_SCENE_TEXT = 13,
+ ISP_SCENE_CANDLE = 14
+};
+
+/* AFC error codes */
+#define ISP_AFC_ERROR_NONE 0 /* AFC setting is done */
+
+/* ---------------------------- FD ------------------------------------- */
+enum fd_config_command {
+ FD_CONFIG_COMMAND_MAXIMUM_NUMBER = 0x1,
+ FD_CONFIG_COMMAND_ROLL_ANGLE = 0x2,
+ FD_CONFIG_COMMAND_YAW_ANGLE = 0x4,
+ FD_CONFIG_COMMAND_SMILE_MODE = 0x8,
+ FD_CONFIG_COMMAND_BLINK_MODE = 0x10,
+ FD_CONFIG_COMMAND_EYES_DETECT = 0x20,
+ FD_CONFIG_COMMAND_MOUTH_DETECT = 0x40,
+ FD_CONFIG_COMMAND_ORIENTATION = 0x80,
+ FD_CONFIG_COMMAND_ORIENTATION_VALUE = 0x100
+};
+
+enum fd_config_roll_angle {
+ FD_CONFIG_ROLL_ANGLE_BASIC = 0,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC = 1,
+ FD_CONFIG_ROLL_ANGLE_SIDES = 2,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES = 3,
+ FD_CONFIG_ROLL_ANGLE_FULL = 4,
+ FD_CONFIG_ROLL_ANGLE_PRECISE_FULL = 5,
+};
+
+enum fd_config_yaw_angle {
+ FD_CONFIG_YAW_ANGLE_0 = 0,
+ FD_CONFIG_YAW_ANGLE_45 = 1,
+ FD_CONFIG_YAW_ANGLE_90 = 2,
+ FD_CONFIG_YAW_ANGLE_45_90 = 3,
+};
+
+/* Smile mode configuration */
+#define FD_CONFIG_SMILE_MODE_DISABLE 0
+#define FD_CONFIG_SMILE_MODE_ENABLE 1
+
+/* Blink mode configuration */
+#define FD_CONFIG_BLINK_MODE_DISABLE 0
+#define FD_CONFIG_BLINK_MODE_ENABLE 1
+
+/* Eyes detection configuration */
+#define FD_CONFIG_EYES_DETECT_DISABLE 0
+#define FD_CONFIG_EYES_DETECT_ENABLE 1
+
+/* Mouth detection configuration */
+#define FD_CONFIG_MOUTH_DETECT_DISABLE 0
+#define FD_CONFIG_MOUTH_DETECT_ENABLE 1
+
+#define FD_CONFIG_ORIENTATION_DISABLE 0
+#define FD_CONFIG_ORIENTATION_ENABLE 1
+
+struct param_control {
+ u32 cmd;
+ u32 bypass;
+ u32 buffer_address;
+ u32 buffer_size;
+ u32 skip_frames; /* only valid at ISP */
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6];
+ u32 err;
+};
+
+struct param_otf_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 frametime_min;
+ u32 frametime_max;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 13];
+ u32 err;
+};
+
+struct param_dma_input {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+ u32 err;
+};
+
+struct param_otf_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 order;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7];
+ u32 err;
+};
+
+struct param_dma_output {
+ u32 cmd;
+ u32 width;
+ u32 height;
+ u32 format;
+ u32 bitwidth;
+ u32 plane;
+ u32 order;
+ u32 buffer_number;
+ u32 buffer_address;
+ u32 notify_dma_done;
+ u32 dma_out_mask;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 12];
+ u32 err;
+};
+
+struct param_global_shotmode {
+ u32 cmd;
+ u32 skip_frames;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+ u32 err;
+};
+
+struct param_sensor_framerate {
+ u32 frame_rate;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+ u32 err;
+};
+
+struct param_isp_aa {
+ u32 cmd;
+ u32 target;
+ u32 mode;
+ u32 scene;
+ u32 sleep;
+ u32 face;
+ u32 touch_x;
+ u32 touch_y;
+ u32 manual_af_setting;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+ u32 err;
+};
+
+struct param_isp_flash {
+ u32 cmd;
+ u32 redeye;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+ u32 err;
+};
+
+struct param_isp_awb {
+ u32 cmd;
+ u32 illumination;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+ u32 err;
+};
+
+struct param_isp_imageeffect {
+ u32 cmd;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+ u32 err;
+};
+
+struct param_isp_iso {
+ u32 cmd;
+ u32 value;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+ u32 err;
+};
+
+struct param_isp_adjust {
+ u32 cmd;
+ s32 contrast;
+ s32 saturation;
+ s32 sharpness;
+ s32 exposure;
+ s32 brightness;
+ s32 hue;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 8];
+ u32 err;
+};
+
+struct param_isp_metering {
+ u32 cmd;
+ u32 win_pos_x;
+ u32 win_pos_y;
+ u32 win_width;
+ u32 win_height;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6];
+ u32 err;
+};
+
+struct param_isp_afc {
+ u32 cmd;
+ u32 manual;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+ u32 err;
+};
+
+struct param_scaler_imageeffect {
+ u32 cmd;
+ u32 arbitrary_cb;
+ u32 arbitrary_cr;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 4];
+ u32 err;
+};
+
+struct param_scaler_input_crop {
+ u32 cmd;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 in_width;
+ u32 in_height;
+ u32 out_width;
+ u32 out_height;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+ u32 err;
+};
+
+struct param_scaler_output_crop {
+ u32 cmd;
+ u32 crop_offset_x;
+ u32 crop_offset_y;
+ u32 crop_width;
+ u32 crop_height;
+ u32 out_format;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7];
+ u32 err;
+};
+
+struct param_scaler_rotation {
+ u32 cmd;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+ u32 err;
+};
+
+struct param_scaler_flip {
+ u32 cmd;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+ u32 err;
+};
+
+struct param_3dnr_1stframe {
+ u32 cmd;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+ u32 err;
+};
+
+struct param_fd_config {
+ u32 cmd;
+ u32 max_number;
+ u32 roll_angle;
+ u32 yaw_angle;
+ u32 smile_mode;
+ u32 blink_mode;
+ u32 eye_detect;
+ u32 mouth_detect;
+ u32 orientation;
+ u32 orientation_value;
+ u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 11];
+ u32 err;
+};
+
+struct global_param {
+ struct param_global_shotmode shotmode;
+};
+
+struct sensor_param {
+ struct param_control control;
+ struct param_otf_output otf_output;
+ struct param_sensor_framerate frame_rate;
+} __packed;
+
+struct buffer_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+} __packed;
+
+struct isp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma1_input;
+ struct param_dma_input dma2_input;
+ struct param_isp_aa aa;
+ struct param_isp_flash flash;
+ struct param_isp_awb awb;
+ struct param_isp_imageeffect effect;
+ struct param_isp_iso iso;
+ struct param_isp_adjust adjust;
+ struct param_isp_metering metering;
+ struct param_isp_afc afc;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma1_output;
+ struct param_dma_output dma2_output;
+} __packed;
+
+struct drc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_otf_output otf_output;
+} __packed;
+
+struct scalerc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+} __packed;
+
+struct odc_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_otf_output otf_output;
+} __packed;
+
+struct dis_param {
+ struct param_control control;
+ struct param_otf_output otf_input;
+ struct param_otf_output otf_output;
+} __packed;
+
+struct tdnr_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_3dnr_1stframe frame;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+} __packed;
+
+struct scalerp_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_scaler_imageeffect effect;
+ struct param_scaler_input_crop input_crop;
+ struct param_scaler_output_crop output_crop;
+ struct param_scaler_rotation rotation;
+ struct param_scaler_flip flip;
+ struct param_otf_output otf_output;
+ struct param_dma_output dma_output;
+} __packed;
+
+struct fd_param {
+ struct param_control control;
+ struct param_otf_input otf_input;
+ struct param_dma_input dma_input;
+ struct param_fd_config config;
+} __packed;
+
+struct is_param_region {
+ struct global_param global;
+ struct sensor_param sensor;
+ struct buffer_param buf;
+ struct isp_param isp;
+ struct drc_param drc;
+ struct scalerc_param scalerc;
+ struct odc_param odc;
+ struct dis_param dis;
+ struct tdnr_param tdnr;
+ struct scalerp_param scalerp;
+ struct fd_param fd;
+} __packed;
+
+#define NUMBER_OF_GAMMA_CURVE_POINTS 32
+
+struct is_tune_sensor {
+ u32 exposure;
+ u32 analog_gain;
+ u32 frame_rate;
+ u32 actuator_position;
+};
+
+struct is_tune_gammacurve {
+ u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS];
+ u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS];
+};
+
+struct is_tune_isp {
+ /* Brightness level: range 0...100, default 7. */
+ u32 brightness_level;
+ /* Contrast level: range -127...127, default 0. */
+ s32 contrast_level;
+ /* Saturation level: range -127...127, default 0. */
+ s32 saturation_level;
+ s32 gamma_level;
+ struct is_tune_gammacurve gamma_curve[4];
+ /* Hue: range -127...127, default 0. */
+ s32 hue;
+ /* Sharpness blur: range -127...127, default 0. */
+ s32 sharpness_blur;
+ /* Despeckle : range -127~127, default : 0 */
+ s32 despeckle;
+ /* Edge color supression: range -127...127, default 0. */
+ s32 edge_color_supression;
+ /* Noise reduction: range -127...127, default 0. */
+ s32 noise_reduction;
+ /* (32 * 4 + 9) * 4 = 548 bytes */
+} __packed;
+
+struct is_tune_region {
+ struct is_tune_sensor sensor;
+ struct is_tune_isp isp;
+} __packed;
+
+struct rational {
+ u32 num;
+ u32 den;
+};
+
+struct srational {
+ s32 num;
+ s32 den;
+};
+
+#define FLASH_FIRED_SHIFT 0
+#define FLASH_NOT_FIRED 0
+#define FLASH_FIRED 1
+
+#define FLASH_STROBE_SHIFT 1
+#define FLASH_STROBE_NO_DETECTION 0
+#define FLASH_STROBE_RESERVED 1
+#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED 2
+#define FLASH_STROBE_RETURN_LIGHT_DETECTED 3
+
+#define FLASH_MODE_SHIFT 3
+#define FLASH_MODE_UNKNOWN 0
+#define FLASH_MODE_COMPULSORY_FLASH_FIRING 1
+#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION 2
+#define FLASH_MODE_AUTO_MODE 3
+
+#define FLASH_FUNCTION_SHIFT 5
+#define FLASH_FUNCTION_PRESENT 0
+#define FLASH_FUNCTION_NONE 1
+
+#define FLASH_RED_EYE_SHIFT 6
+#define FLASH_RED_EYE_DISABLED 0
+#define FLASH_RED_EYE_SUPPORTED 1
+
+enum apex_aperture_value {
+ F1_0 = 0,
+ F1_4 = 1,
+ F2_0 = 2,
+ F2_8 = 3,
+ F4_0 = 4,
+ F5_6 = 5,
+ F8_9 = 6,
+ F11_0 = 7,
+ F16_0 = 8,
+ F22_0 = 9,
+ F32_0 = 10,
+};
+
+struct exif_attribute {
+ struct rational exposure_time;
+ struct srational shutter_speed;
+ u32 iso_speed_rating;
+ u32 flash;
+ struct srational brightness;
+} __packed;
+
+struct is_frame_header {
+ u32 valid;
+ u32 bad_mark;
+ u32 captured;
+ u32 frame_number;
+ struct exif_attribute exif;
+} __packed;
+
+struct is_fd_rect {
+ u32 offset_x;
+ u32 offset_y;
+ u32 width;
+ u32 height;
+};
+
+struct is_face_marker {
+ u32 frame_number;
+ struct is_fd_rect face;
+ struct is_fd_rect left_eye;
+ struct is_fd_rect right_eye;
+ struct is_fd_rect mouth;
+ u32 roll_angle;
+ u32 yaw_angle;
+ u32 confidence;
+ s32 smile_level;
+ s32 blink_level;
+} __packed;
+
+#define MAX_FRAME_COUNT 8
+#define MAX_FRAME_COUNT_PREVIEW 4
+#define MAX_FRAME_COUNT_CAPTURE 1
+#define MAX_FACE_COUNT 16
+#define MAX_SHARED_COUNT 500
+
+struct is_region {
+ struct is_param_region parameter;
+ struct is_tune_region tune;
+ struct is_frame_header header[MAX_FRAME_COUNT];
+ struct is_face_marker face[MAX_FACE_COUNT];
+ u32 shared[MAX_SHARED_COUNT];
+} __packed;
+
+struct is_debug_frame_descriptor {
+ u32 sensor_frame_time;
+ u32 sensor_exposure_time;
+ s32 sensor_analog_gain;
+ /* monitor for AA */
+ u32 req_lei;
+
+ u32 next_next_lei_exp;
+ u32 next_next_lei_a_gain;
+ u32 next_next_lei_d_gain;
+ u32 next_next_lei_statlei;
+ u32 next_next_lei_lei;
+
+ u32 dummy0;
+};
+
+#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM (30*20) /* 600 frames */
+#define MAX_VERSION_DISPLAY_BUF 32
+
+struct is_share_region {
+ u32 frame_time;
+ u32 exposure_time;
+ s32 analog_gain;
+
+ u32 r_gain;
+ u32 g_gain;
+ u32 b_gain;
+
+ u32 af_position;
+ u32 af_status;
+ /* 0 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_NOMESSAGE */
+ /* 1 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_REACHED */
+ /* 2 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_UNABLETOREACH */
+ /* 3 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_LOST */
+ /* default : unknown */
+ u32 af_scene_type;
+
+ u32 frame_descp_onoff_control;
+ u32 frame_descp_update_done;
+ u32 frame_descp_idx;
+ u32 frame_descp_max_idx;
+ struct is_debug_frame_descriptor
+ dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM];
+
+ u32 chip_id;
+ u32 chip_rev_no;
+ u8 isp_fw_ver_no[MAX_VERSION_DISPLAY_BUF];
+ u8 isp_fw_ver_date[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_ver_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_rev_no[MAX_VERSION_DISPLAY_BUF];
+ u8 sirc_sdk_rev_date[MAX_VERSION_DISPLAY_BUF];
+} __packed;
+
+struct is_debug_control {
+ u32 write_point; /* 0~ 500KB boundary */
+ u32 assert_flag; /* 0: Not invoked, 1: Invoked */
+ u32 pabort_flag; /* 0: Not invoked, 1: Invoked */
+ u32 dabort_flag; /* 0: Not invoked, 1: Invoked */
+};
+
+struct sensor_open_extended {
+ u32 actuator_type;
+ u32 mclk;
+ u32 mipi_lane_num;
+ u32 mipi_speed;
+ /* Skip setfile loading when fast_open_sensor is not 0 */
+ u32 fast_open_sensor;
+ /* Activating sensor self calibration mode (6A3) */
+ u32 self_calibration_mode;
+ /* This field is to adjust I2c clock based on ACLK200 */
+ /* This value is varied in case of rev 0.2 */
+ u32 i2c_sclk;
+};
+
+struct fimc_is;
+
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is);
+void fimc_is_set_initial_params(struct fimc_is *is);
+unsigned int __get_pending_param_count(struct fimc_is *is);
+
+int __is_hw_update_params(struct fimc_is *is);
+void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf);
+void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf);
+void __is_set_sensor(struct fimc_is *is, int fps);
+void __is_set_isp_aa_ae(struct fimc_is *is);
+void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye);
+void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_effect(struct fimc_is *is, u32 cmd);
+void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val);
+void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_drc_control(struct fimc_is *is, u32 val);
+void __is_set_fd_control(struct fimc_is *is, u32 val);
+void __is_set_fd_config_maxface(struct fimc_is *is, u32 val);
+void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val);
+void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val);
+void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val);
+void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val);
+void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val);
+void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val);
+void __is_set_fd_config_orientation(struct fimc_is *is, u32 val);
+void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val);
+void __is_set_isp_aa_af_mode(struct fimc_is *is, int cmd);
+void __is_set_isp_aa_af_start_stop(struct fimc_is *is, int cmd);
+
+#endif
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c
new file mode 100644
index 000000000000..b0ff67bc1b05
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c
@@ -0,0 +1,243 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-sensor.h"
+
+void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int nr)
+{
+ mcuctl_write(1UL << nr, is, MCUCTL_REG_INTCR1);
+}
+
+void fimc_is_fw_clear_irq2(struct fimc_is *is)
+{
+ u32 cfg = mcuctl_read(is, MCUCTL_REG_INTSR2);
+ mcuctl_write(cfg, is, MCUCTL_REG_INTCR2);
+}
+
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is)
+{
+ mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0);
+}
+
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is)
+{
+ unsigned int timeout = 2000;
+ u32 cfg, status;
+
+ cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
+ status = INTSR0_GET_INTSD(0, cfg);
+
+ while (status) {
+ cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
+ status = INTSR0_GET_INTSD(0, cfg);
+ if (timeout == 0) {
+ dev_warn(&is->pdev->dev, "%s timeout\n",
+ __func__);
+ return -ETIME;
+ }
+ timeout--;
+ udelay(1);
+ }
+ return 0;
+}
+
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is)
+{
+ unsigned int timeout = 2000;
+ u32 cfg, status;
+
+ cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
+ status = INTMSR0_GET_INTMSD(0, cfg);
+
+ while (status) {
+ cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
+ status = INTMSR0_GET_INTMSD(0, cfg);
+ if (timeout == 0) {
+ dev_warn(&is->pdev->dev, "%s timeout\n",
+ __func__);
+ return -ETIME;
+ }
+ timeout--;
+ udelay(1);
+ }
+ return 0;
+}
+
+int fimc_is_hw_set_param(struct fimc_is *is)
+{
+ struct chain_config *config = &is->config[is->config_index];
+ unsigned int param_count = __get_pending_param_count(is);
+
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+ mcuctl_write(HIC_SET_PARAMETER, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(is->config_index, is, MCUCTL_REG_ISSR(2));
+
+ mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3));
+ mcuctl_write(config->p_region_index1, is, MCUCTL_REG_ISSR(4));
+ mcuctl_write(config->p_region_index2, is, MCUCTL_REG_ISSR(5));
+
+ fimc_is_hw_set_intgr0_gd0(is);
+ return 0;
+}
+
+int fimc_is_hw_set_tune(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+ mcuctl_write(HIC_SET_TUNE, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(is->h2i_cmd.entry_id, is, MCUCTL_REG_ISSR(2));
+
+ fimc_is_hw_set_intgr0_gd0(is);
+ return 0;
+}
+
+#define FIMC_IS_MAX_PARAMS 4
+
+int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args)
+{
+ int i;
+
+ if (num_args > FIMC_IS_MAX_PARAMS)
+ return -EINVAL;
+
+ is->i2h_cmd.num_args = num_args;
+
+ for (i = 0; i < FIMC_IS_MAX_PARAMS; i++) {
+ if (i < num_args)
+ is->i2h_cmd.args[i] = mcuctl_read(is,
+ MCUCTL_REG_ISSR(12 + i));
+ else
+ is->i2h_cmd.args[i] = 0;
+ }
+ return 0;
+}
+
+void fimc_is_hw_set_sensor_num(struct fimc_is *is)
+{
+ pr_debug("setting sensor index to: %d\n", is->sensor_index);
+
+ mcuctl_write(IH_REPLY_DONE, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(IHC_GET_SENSOR_NUM, is, MCUCTL_REG_ISSR(2));
+ mcuctl_write(FIMC_IS_SENSOR_NUM, is, MCUCTL_REG_ISSR(3));
+}
+
+void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index)
+{
+ if (is->sensor_index != index)
+ return;
+
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_CLOSE_SENSOR, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(2));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_get_setfile_addr(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_GET_SET_FILE_ADDR, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_load_setfile(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_LOAD_SET_FILE, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+int fimc_is_hw_change_mode(struct fimc_is *is)
+{
+ const u8 cmd[] = {
+ HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO,
+ HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO,
+ };
+
+ if (WARN_ON(is->config_index > ARRAY_SIZE(cmd)))
+ return -EINVAL;
+
+ mcuctl_write(cmd[is->config_index], is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2));
+ fimc_is_hw_set_intgr0_gd0(is);
+ return 0;
+}
+
+void fimc_is_hw_stream_on(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_STREAM_ON, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(0, is, MCUCTL_REG_ISSR(2));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_stream_off(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_STREAM_OFF, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_subip_power_off(struct fimc_is *is)
+{
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ mcuctl_write(HIC_POWER_DOWN, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ fimc_is_hw_set_intgr0_gd0(is);
+}
+
+int fimc_is_itf_s_param(struct fimc_is *is, bool update)
+{
+ int ret;
+
+ if (update)
+ __is_hw_update_params(is);
+
+ fimc_is_mem_barrier();
+
+ clear_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+ fimc_is_hw_set_param(is);
+ ret = fimc_is_wait_event(is, IS_ST_BLOCK_CMD_CLEARED, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0)
+ dev_err(&is->pdev->dev, "%s() timeout\n", __func__);
+
+ return ret;
+}
+
+int fimc_is_itf_mode_change(struct fimc_is *is)
+{
+ int ret;
+
+ clear_bit(IS_ST_CHANGE_MODE, &is->state);
+ fimc_is_hw_change_mode(is);
+ ret = fimc_is_wait_event(is, IS_ST_CHANGE_MODE, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (!ret < 0)
+ dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n",
+ __func__, is->config_index);
+ return ret;
+}
diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h
new file mode 100644
index 000000000000..5fa2fda46742
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h
@@ -0,0 +1,164 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_REG_H_
+#define FIMC_IS_REG_H_
+
+/* WDT_ISP register */
+#define REG_WDT_ISP 0x00170000
+
+/* MCUCTL registers base offset */
+#define MCUCTL_BASE 0x00180000
+
+/* MCU Controller Register */
+#define MCUCTL_REG_MCUCTRL (MCUCTL_BASE + 0x00)
+#define MCUCTRL_MSWRST (1 << 0)
+
+/* Boot Base Offset Address Register */
+#define MCUCTL_REG_BBOAR (MCUCTL_BASE + 0x04)
+
+/* Interrupt Generation Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTGR0 (MCUCTL_BASE + 0x08)
+/* __n = 0...9 */
+#define INTGR0_INTGC(__n) (1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTGR0_INTGD(__n) (1 << (__n))
+
+/* Interrupt Clear Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTCR0 (MCUCTL_BASE + 0x0c)
+/* __n = 0...9 */
+#define INTCR0_INTGC(__n) (1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTCR0_INTCD(__n) (1 << ((__n) + 16))
+
+/* Interrupt Mask Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTMR0 (MCUCTL_BASE + 0x10)
+/* __n = 0...9 */
+#define INTMR0_INTMC(__n) (1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTMR0_INTMD(__n) (1 << (__n))
+
+/* Interrupt Status Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTSR0 (MCUCTL_BASE + 0x14)
+/* __n (bit number) = 0...4 */
+#define INTSR0_GET_INTSD(x, __n) (((x) >> (__n)) & 0x1)
+/* __n (bit number) = 0...9 */
+#define INTSR0_GET_INTSC(x, __n) (((x) >> ((__n) + 16)) & 0x1)
+
+/* Interrupt Mask Status Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTMSR0 (MCUCTL_BASE + 0x18)
+/* __n (bit number) = 0...4 */
+#define INTMSR0_GET_INTMSD(x, __n) (((x) >> (__n)) & 0x1)
+/* __n (bit number) = 0...9 */
+#define INTMSR0_GET_INTMSC(x, __n) (((x) >> ((__n) + 16)) & 0x1)
+
+/* Interrupt Generation Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTGR1 (MCUCTL_BASE + 0x1c)
+/* __n = 0...9 */
+#define INTGR1_INTGC(__n) (1 << (__n))
+
+/* Interrupt Clear Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTCR1 (MCUCTL_BASE + 0x20)
+/* __n = 0...9 */
+#define INTCR1_INTCC(__n) (1 << (__n))
+
+/* Interrupt Mask Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTMR1 (MCUCTL_BASE + 0x24)
+/* __n = 0...9 */
+#define INTMR1_INTMC(__n) (1 << (__n))
+
+/* Interrupt Status Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTSR1 (MCUCTL_BASE + 0x28)
+/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTMSR1 (MCUCTL_BASE + 0x2c)
+
+/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTCR2 (MCUCTL_BASE + 0x30)
+/* __n = 0...5 */
+#define INTCR2_INTCC(__n) (1 << ((__n) + 16))
+
+/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTMR2 (MCUCTL_BASE + 0x34)
+/* __n = 0...25 */
+#define INTMR2_INTMCIS(__n) (1 << (__n))
+
+/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTSR2 (MCUCTL_BASE + 0x38)
+/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTMSR2 (MCUCTL_BASE + 0x3c)
+
+/* General Purpose Output Control Register (0~17) */
+#define MCUCTL_REG_GPOCTLR (MCUCTL_BASE + 0x40)
+/* __n = 0...17 */
+#define GPOCTLR_GPOG(__n) (1 << (__n))
+
+/* General Purpose Pad Output Enable Register (0~17) */
+#define MCUCTL_REG_GPOENCTLR (MCUCTL_BASE + 0x44)
+/* __n = 0...17 */
+#define GPOENCTLR_GPOEN(__n) (1 << (__n))
+
+/* General Purpose Input Control Register (0~17) */
+#define MCUCTL_REG_GPICTLR (MCUCTL_BASE + 0x48)
+
+/* Shared registers between ISP CPU and the host CPU - ISSRxx */
+
+/* ISSR(1): Command Host -> IS */
+/* ISSR(1): Sensor ID for Command, ISSR2...5 = Parameter 1...4 */
+
+/* ISSR(10): Reply IS -> Host */
+/* ISSR(11): Sensor ID for Reply, ISSR12...15 = Parameter 1...4 */
+
+/* ISSR(20): ISP_FRAME_DONE : SENSOR ID */
+/* ISSR(21): ISP_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(24): SCALERC_FRAME_DONE : SENSOR ID */
+/* ISSR(25): SCALERC_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(28): 3DNR_FRAME_DONE : SENSOR ID */
+/* ISSR(29): 3DNR_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(32): SCALERP_FRAME_DONE : SENSOR ID */
+/* ISSR(33): SCALERP_FRAME_DONE : PARAMETER 1 */
+
+/* __n = 0...63 */
+#define MCUCTL_REG_ISSR(__n) (MCUCTL_BASE + 0x80 + ((__n) * 4))
+
+/* PMU ISP register offsets */
+#define REG_CMU_RESET_ISP_SYS_PWR_REG 0x1174
+#define REG_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13b8
+#define REG_PMU_ISP_ARM_SYS 0x1050
+#define REG_PMU_ISP_ARM_CONFIGURATION 0x2280
+#define REG_PMU_ISP_ARM_STATUS 0x2284
+#define REG_PMU_ISP_ARM_OPTION 0x2288
+
+void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int bit);
+void fimc_is_fw_clear_irq2(struct fimc_is *is);
+int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num);
+
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is);
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is);
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is);
+void fimc_is_hw_set_sensor_num(struct fimc_is *is);
+void fimc_is_hw_stream_on(struct fimc_is *is);
+void fimc_is_hw_stream_off(struct fimc_is *is);
+int fimc_is_hw_set_param(struct fimc_is *is);
+int fimc_is_hw_change_mode(struct fimc_is *is);
+
+void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index);
+void fimc_is_hw_get_setfile_addr(struct fimc_is *is);
+void fimc_is_hw_load_setfile(struct fimc_is *is);
+void fimc_is_hw_subip_power_off(struct fimc_is *is);
+
+int fimc_is_itf_s_param(struct fimc_is *is, bool update);
+int fimc_is_itf_mode_change(struct fimc_is *is);
+
+#endif /* FIMC_IS_REG_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
new file mode 100644
index 000000000000..6647421e5d3a
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c
@@ -0,0 +1,305 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <media/v4l2-subdev.h>
+
+#include "fimc-is.h"
+#include "fimc-is-sensor.h"
+
+#define DRIVER_NAME "FIMC-IS-SENSOR"
+
+static const char * const sensor_supply_names[] = {
+ "svdda",
+ "svddio",
+};
+
+static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = {
+ {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ }
+};
+
+static const struct v4l2_mbus_framefmt *find_sensor_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_is_sensor_formats); i++)
+ if (mf->code == fimc_is_sensor_formats[i].code)
+ return &fimc_is_sensor_formats[i];
+
+ return &fimc_is_sensor_formats[0];
+}
+
+static int fimc_is_sensor_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(fimc_is_sensor_formats))
+ return -EINVAL;
+
+ code->code = fimc_is_sensor_formats[code->index].code;
+ return 0;
+}
+
+static void fimc_is_sensor_try_format(struct fimc_is_sensor *sensor,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct sensor_drv_data *dd = sensor->drvdata;
+ const struct v4l2_mbus_framefmt *fmt;
+
+ fmt = find_sensor_format(mf);
+ mf->code = fmt->code;
+ v4l_bound_align_image(&mf->width, 16 + 8, dd->width, 0,
+ &mf->height, 12 + 8, dd->height, 0, 0);
+}
+
+static struct v4l2_mbus_framefmt *__fimc_is_sensor_get_format(
+ struct fimc_is_sensor *sensor, struct v4l2_subdev_fh *fh,
+ u32 pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+ return &sensor->format;
+}
+
+static int fimc_is_sensor_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ fimc_is_sensor_try_format(sensor, &fmt->format);
+
+ mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
+ if (mf) {
+ mutex_lock(&sensor->lock);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ *mf = fmt->format;
+ mutex_unlock(&sensor->lock);
+ }
+ return 0;
+}
+
+static int fimc_is_sensor_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
+
+ mutex_lock(&sensor->lock);
+ fmt->format = *mf;
+ mutex_unlock(&sensor->lock);
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = {
+ .enum_mbus_code = fimc_is_sensor_enum_mbus_code,
+ .get_fmt = fimc_is_sensor_get_fmt,
+ .set_fmt = fimc_is_sensor_set_fmt,
+};
+
+static int fimc_is_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+ *format = fimc_is_sensor_formats[0];
+ format->width = FIMC_IS_SENSOR_DEF_PIX_WIDTH;
+ format->height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = {
+ .open = fimc_is_sensor_open,
+};
+
+static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
+ int gpio = sensor->gpio_reset;
+ int ret;
+
+ if (on) {
+ ret = pm_runtime_get(sensor->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_bulk_enable(SENSOR_NUM_SUPPLIES,
+ sensor->supplies);
+ if (ret < 0) {
+ pm_runtime_put(sensor->dev);
+ return ret;
+ }
+ if (gpio_is_valid(gpio)) {
+ gpio_set_value(gpio, 1);
+ usleep_range(600, 800);
+ gpio_set_value(gpio, 0);
+ usleep_range(10000, 11000);
+ gpio_set_value(gpio, 1);
+ }
+
+ /* A delay needed for the sensor initialization. */
+ msleep(20);
+ } else {
+ if (gpio_is_valid(gpio))
+ gpio_set_value(gpio, 0);
+
+ ret = regulator_bulk_disable(SENSOR_NUM_SUPPLIES,
+ sensor->supplies);
+ if (!ret)
+ pm_runtime_put(sensor->dev);
+ }
+
+ pr_info("%s:%d: on: %d, ret: %d\n", __func__, __LINE__, on, ret);
+
+ return ret;
+}
+
+static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = {
+ .s_power = fimc_is_sensor_s_power,
+};
+
+static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = {
+ .core = &fimc_is_sensor_core_ops,
+ .pad = &fimc_is_sensor_pad_ops,
+};
+
+static const struct of_device_id fimc_is_sensor_of_match[];
+
+static int fimc_is_sensor_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct fimc_is_sensor *sensor;
+ const struct of_device_id *of_id;
+ struct v4l2_subdev *sd;
+ int gpio, i, ret;
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ mutex_init(&sensor->lock);
+ sensor->gpio_reset = -EINVAL;
+
+ gpio = of_get_gpio_flags(dev->of_node, 0, NULL);
+ if (gpio_is_valid(gpio)) {
+ ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW,
+ DRIVER_NAME);
+ if (ret < 0)
+ return ret;
+ }
+ sensor->gpio_reset = gpio;
+
+ for (i = 0; i < SENSOR_NUM_SUPPLIES; i++)
+ sensor->supplies[i].supply = sensor_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES,
+ sensor->supplies);
+ if (ret < 0)
+ return ret;
+
+ of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node);
+ if (!of_id)
+ return -ENODEV;
+
+ sensor->drvdata = of_id->data;
+ sensor->dev = dev;
+
+ sd = &sensor->subdev;
+ v4l2_i2c_subdev_init(sd, client, &fimc_is_sensor_subdev_ops);
+ snprintf(sd->name, sizeof(sd->name), sensor->drvdata->subdev_name);
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ sensor->format.code = fimc_is_sensor_formats[0].code;
+ sensor->format.width = FIMC_IS_SENSOR_DEF_PIX_WIDTH;
+ sensor->format.height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
+
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0);
+ if (ret < 0)
+ return ret;
+
+ pm_runtime_no_callbacks(dev);
+ pm_runtime_enable(dev);
+
+ return ret;
+}
+
+static int fimc_is_sensor_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ media_entity_cleanup(&sd->entity);
+ return 0;
+}
+
+static const struct i2c_device_id fimc_is_sensor_ids[] = {
+ { }
+};
+
+static const struct sensor_drv_data s5k6a3_drvdata = {
+ .id = FIMC_IS_SENSOR_ID_S5K6A3,
+ .subdev_name = "S5K6A3",
+ .width = S5K6A3_SENSOR_WIDTH,
+ .height = S5K6A3_SENSOR_HEIGHT,
+};
+
+static const struct of_device_id fimc_is_sensor_of_match[] = {
+ {
+ .compatible = "samsung,s5k6a3",
+ .data = &s5k6a3_drvdata,
+ },
+ { }
+};
+
+static struct i2c_driver fimc_is_sensor_driver = {
+ .driver = {
+ .of_match_table = fimc_is_sensor_of_match,
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = fimc_is_sensor_probe,
+ .remove = fimc_is_sensor_remove,
+ .id_table = fimc_is_sensor_ids,
+};
+
+int fimc_is_register_sensor_driver(void)
+{
+ return i2c_add_driver(&fimc_is_sensor_driver);
+}
+
+void fimc_is_unregister_sensor_driver(void)
+{
+ i2c_del_driver(&fimc_is_sensor_driver);
+}
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("Exynos4x12 FIMC-IS image sensor subdev driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
new file mode 100644
index 000000000000..6036d49a6c68
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h
@@ -0,0 +1,89 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_SENSOR_H_
+#define FIMC_IS_SENSOR_H_
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+
+#define FIMC_IS_SENSOR_OPEN_TIMEOUT 2000 /* ms */
+
+#define FIMC_IS_SENSOR_DEF_PIX_WIDTH 1296
+#define FIMC_IS_SENSOR_DEF_PIX_HEIGHT 732
+
+#define S5K6A3_SENSOR_WIDTH 1392
+#define S5K6A3_SENSOR_HEIGHT 1392
+
+#define SENSOR_NUM_SUPPLIES 2
+
+enum fimc_is_sensor_id {
+ FIMC_IS_SENSOR_ID_S5K3H2 = 1,
+ FIMC_IS_SENSOR_ID_S5K6A3,
+ FIMC_IS_SENSOR_ID_S5K4E5,
+ FIMC_IS_SENSOR_ID_S5K3H7,
+ FIMC_IS_SENSOR_ID_CUSTOM,
+ FIMC_IS_SENSOR_ID_END
+};
+
+#define IS_SENSOR_CTRL_BUS_I2C0 0
+#define IS_SENSOR_CTRL_BUS_I2C1 1
+
+struct sensor_drv_data {
+ enum fimc_is_sensor_id id;
+ const char * const subdev_name;
+ unsigned int width;
+ unsigned int height;
+};
+
+/**
+ * struct fimc_is_sensor - fimc-is sensor data structure
+ * @dev: pointer to this I2C client device structure
+ * @subdev: the image sensor's v4l2 subdev
+ * @pad: subdev media source pad
+ * @supplies: image sensor's voltage regulator supplies
+ * @gpio_reset: GPIO connected to the sensor's reset pin
+ * @drvdata: a pointer to the sensor's parameters data structure
+ * @i2c_bus: ISP I2C bus index (0...1)
+ * @test_pattern: true to enable video test pattern
+ * @lock: mutex protecting the structure's members below
+ * @format: media bus format at the sensor's source pad
+ */
+struct fimc_is_sensor {
+ struct device *dev;
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct regulator_bulk_data supplies[SENSOR_NUM_SUPPLIES];
+ int gpio_reset;
+ const struct sensor_drv_data *drvdata;
+ unsigned int i2c_bus;
+ bool test_pattern;
+
+ struct mutex lock;
+ struct v4l2_mbus_framefmt format;
+};
+
+static inline
+struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct fimc_is_sensor, subdev);
+}
+
+int fimc_is_register_sensor_driver(void);
+void fimc_is_unregister_sensor_driver(void);
+
+#endif /* FIMC_IS_SENSOR_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
new file mode 100644
index 000000000000..47c6363d04e2
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -0,0 +1,1007 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/dma-contiguous.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "media-dev.h"
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-errno.h"
+#include "fimc-is-i2c.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+
+
+static char *fimc_is_clocks[ISS_CLKS_MAX] = {
+ [ISS_CLK_PPMUISPX] = "ppmuispx",
+ [ISS_CLK_PPMUISPMX] = "ppmuispmx",
+ [ISS_CLK_LITE0] = "lite0",
+ [ISS_CLK_LITE1] = "lite1",
+ [ISS_CLK_MPLL] = "mpll",
+ [ISS_CLK_SYSREG] = "sysreg",
+ [ISS_CLK_ISP] = "isp",
+ [ISS_CLK_DRC] = "drc",
+ [ISS_CLK_FD] = "fd",
+ [ISS_CLK_MCUISP] = "mcuisp",
+ [ISS_CLK_UART] = "uart",
+ [ISS_CLK_ISP_DIV0] = "ispdiv0",
+ [ISS_CLK_ISP_DIV1] = "ispdiv1",
+ [ISS_CLK_MCUISP_DIV0] = "mcuispdiv0",
+ [ISS_CLK_MCUISP_DIV1] = "mcuispdiv1",
+ [ISS_CLK_ACLK200] = "aclk200",
+ [ISS_CLK_ACLK200_DIV] = "div_aclk200",
+ [ISS_CLK_ACLK400MCUISP] = "aclk400mcuisp",
+ [ISS_CLK_ACLK400MCUISP_DIV] = "div_aclk400mcuisp",
+};
+
+static void fimc_is_put_clocks(struct fimc_is *is)
+{
+ int i;
+
+ for (i = 0; i < ISS_CLKS_MAX; i++) {
+ if (IS_ERR(is->clocks[i]))
+ continue;
+ clk_unprepare(is->clocks[i]);
+ clk_put(is->clocks[i]);
+ is->clocks[i] = ERR_PTR(-EINVAL);
+ }
+}
+
+static int fimc_is_get_clocks(struct fimc_is *is)
+{
+ int i, ret;
+
+ for (i = 0; i < ISS_CLKS_MAX; i++)
+ is->clocks[i] = ERR_PTR(-EINVAL);
+
+ for (i = 0; i < ISS_CLKS_MAX; i++) {
+ is->clocks[i] = clk_get(&is->pdev->dev, fimc_is_clocks[i]);
+ if (IS_ERR(is->clocks[i])) {
+ ret = PTR_ERR(is->clocks[i]);
+ goto err;
+ }
+ ret = clk_prepare(is->clocks[i]);
+ if (ret < 0) {
+ clk_put(is->clocks[i]);
+ is->clocks[i] = ERR_PTR(-EINVAL);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ fimc_is_put_clocks(is);
+ dev_err(&is->pdev->dev, "failed to get clock: %s\n",
+ fimc_is_clocks[i]);
+ return -ENXIO;
+}
+
+static int fimc_is_setup_clocks(struct fimc_is *is)
+{
+ int ret;
+
+ ret = clk_set_parent(is->clocks[ISS_CLK_ACLK200],
+ is->clocks[ISS_CLK_ACLK200_DIV]);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_set_parent(is->clocks[ISS_CLK_ACLK400MCUISP],
+ is->clocks[ISS_CLK_ACLK400MCUISP_DIV]);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV0], ACLK_AXI_FREQUENCY);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV1], ACLK_AXI_FREQUENCY);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV0],
+ ATCLK_MCUISP_FREQUENCY);
+ if (ret < 0)
+ return ret;
+
+ return clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV1],
+ ATCLK_MCUISP_FREQUENCY);
+}
+
+int fimc_is_enable_clocks(struct fimc_is *is)
+{
+ int i, ret;
+
+ for (i = 0; i < ISS_GATE_CLKS_MAX; i++) {
+ if (IS_ERR(is->clocks[i]))
+ continue;
+ ret = clk_enable(is->clocks[i]);
+ if (ret < 0) {
+ dev_err(&is->pdev->dev, "clock %s enable failed\n",
+ fimc_is_clocks[i]);
+ for (--i; i >= 0; i--)
+ clk_disable(is->clocks[i]);
+ return ret;
+ }
+ pr_debug("enabled clock: %s\n", fimc_is_clocks[i]);
+ }
+ return 0;
+}
+
+void fimc_is_disable_clocks(struct fimc_is *is)
+{
+ int i;
+
+ for (i = 0; i < ISS_GATE_CLKS_MAX; i++) {
+ if (!IS_ERR(is->clocks[i])) {
+ clk_disable(is->clocks[i]);
+ pr_debug("disabled clock: %s\n", fimc_is_clocks[i]);
+ }
+ }
+}
+
+static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor,
+ struct device_node *np)
+{
+ u32 tmp = 0;
+ int ret;
+
+ np = v4l2_of_get_next_endpoint(np, NULL);
+ if (!np)
+ return -ENXIO;
+ np = v4l2_of_get_remote_port(np);
+ if (!np)
+ return -ENXIO;
+
+ /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */
+ ret = of_property_read_u32(np, "reg", &tmp);
+ sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0;
+
+ return ret;
+}
+
+static int fimc_is_register_subdevs(struct fimc_is *is)
+{
+ struct device_node *adapter, *child;
+ int ret;
+
+ ret = fimc_isp_subdev_create(&is->isp);
+ if (ret < 0)
+ return ret;
+
+ for_each_compatible_node(adapter, NULL, FIMC_IS_I2C_COMPATIBLE) {
+ if (!of_find_device_by_node(adapter)) {
+ of_node_put(adapter);
+ return -EPROBE_DEFER;
+ }
+
+ for_each_available_child_of_node(adapter, child) {
+ struct i2c_client *client;
+ struct v4l2_subdev *sd;
+
+ client = of_find_i2c_device_by_node(child);
+ if (!client)
+ goto e_retry;
+
+ sd = i2c_get_clientdata(client);
+ if (!sd)
+ goto e_retry;
+
+ /* FIXME: Add support for multiple sensors. */
+ if (WARN_ON(is->sensor))
+ continue;
+
+ is->sensor = sd_to_fimc_is_sensor(sd);
+
+ if (fimc_is_parse_sensor_config(is->sensor, child)) {
+ dev_warn(&is->pdev->dev, "DT parse error: %s\n",
+ child->full_name);
+ }
+ pr_debug("%s(): registered subdev: %p\n",
+ __func__, sd->name);
+ }
+ }
+ return 0;
+
+e_retry:
+ of_node_put(child);
+ return -EPROBE_DEFER;
+}
+
+static int fimc_is_unregister_subdevs(struct fimc_is *is)
+{
+ fimc_isp_subdev_destroy(&is->isp);
+ is->sensor = NULL;
+ return 0;
+}
+
+static int fimc_is_load_setfile(struct fimc_is *is, char *file_name)
+{
+ const struct firmware *fw;
+ void *buf;
+ int ret;
+
+ ret = request_firmware(&fw, file_name, &is->pdev->dev);
+ if (ret < 0) {
+ dev_err(&is->pdev->dev, "firmware request failed (%d)\n", ret);
+ return ret;
+ }
+ buf = is->memory.vaddr + is->setfile.base;
+ memcpy(buf, fw->data, fw->size);
+ fimc_is_mem_barrier();
+ is->setfile.size = fw->size;
+
+ pr_debug("mem vaddr: %p, setfile buf: %p\n", is->memory.vaddr, buf);
+
+ memcpy(is->fw.setfile_info,
+ fw->data + fw->size - FIMC_IS_SETFILE_INFO_LEN,
+ FIMC_IS_SETFILE_INFO_LEN - 1);
+
+ is->fw.setfile_info[FIMC_IS_SETFILE_INFO_LEN - 1] = '\0';
+ is->setfile.state = 1;
+
+ pr_debug("FIMC-IS setfile loaded: base: %#x, size: %zu B\n",
+ is->setfile.base, fw->size);
+
+ release_firmware(fw);
+ return ret;
+}
+
+int fimc_is_cpu_set_power(struct fimc_is *is, int on)
+{
+ unsigned int timeout = FIMC_IS_POWER_ON_TIMEOUT;
+
+ if (on) {
+ /* Disable watchdog */
+ mcuctl_write(0, is, REG_WDT_ISP);
+
+ /* Cortex-A5 start address setting */
+ mcuctl_write(is->memory.paddr, is, MCUCTL_REG_BBOAR);
+
+ /* Enable and start Cortex-A5 */
+ pmuisp_write(0x18000, is, REG_PMU_ISP_ARM_OPTION);
+ pmuisp_write(0x1, is, REG_PMU_ISP_ARM_CONFIGURATION);
+ } else {
+ /* A5 power off */
+ pmuisp_write(0x10000, is, REG_PMU_ISP_ARM_OPTION);
+ pmuisp_write(0x0, is, REG_PMU_ISP_ARM_CONFIGURATION);
+
+ while (pmuisp_read(is, REG_PMU_ISP_ARM_STATUS) & 1) {
+ if (timeout == 0)
+ return -ETIME;
+ timeout--;
+ udelay(1);
+ }
+ }
+
+ return 0;
+}
+
+/* Wait until @bit of @is->state is set to @state in the interrupt handler. */
+int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
+ unsigned int state, unsigned int timeout)
+{
+
+ int ret = wait_event_timeout(is->irq_queue,
+ !state ^ test_bit(bit, &is->state),
+ timeout);
+ if (ret == 0) {
+ dev_WARN(&is->pdev->dev, "%s() timed out\n", __func__);
+ return -ETIME;
+ }
+ return 0;
+}
+
+int fimc_is_start_firmware(struct fimc_is *is)
+{
+ struct device *dev = &is->pdev->dev;
+ int ret;
+
+ memcpy(is->memory.vaddr, is->fw.f_w->data, is->fw.f_w->size);
+ wmb();
+
+ ret = fimc_is_cpu_set_power(is, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = fimc_is_wait_event(is, IS_ST_A5_PWR_ON, 1,
+ msecs_to_jiffies(FIMC_IS_FW_LOAD_TIMEOUT));
+ if (ret < 0)
+ dev_err(dev, "FIMC-IS CPU power on failed\n");
+
+ return ret;
+}
+
+/* Allocate working memory for the FIMC-IS CPU. */
+static int fimc_is_alloc_cpu_memory(struct fimc_is *is)
+{
+ struct device *dev = &is->pdev->dev;
+
+ is->memory.vaddr = dma_alloc_coherent(dev, FIMC_IS_CPU_MEM_SIZE,
+ &is->memory.paddr, GFP_KERNEL);
+ if (is->memory.vaddr == NULL)
+ return -ENOMEM;
+
+ is->memory.size = FIMC_IS_CPU_MEM_SIZE;
+ memset(is->memory.vaddr, 0, is->memory.size);
+
+ dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr);
+
+ if (((u32)is->memory.paddr) & FIMC_IS_FW_ADDR_MASK) {
+ dev_err(dev, "invalid firmware memory alignment: %#x\n",
+ (u32)is->memory.paddr);
+ dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
+ is->memory.paddr);
+ return -EIO;
+ }
+
+ is->is_p_region = (struct is_region *)(is->memory.vaddr +
+ FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE);
+
+ is->is_dma_p_region = is->memory.paddr +
+ FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE;
+
+ is->is_shared_region = (struct is_share_region *)(is->memory.vaddr +
+ FIMC_IS_SHARED_REGION_OFFSET);
+ return 0;
+}
+
+static void fimc_is_free_cpu_memory(struct fimc_is *is)
+{
+ struct device *dev = &is->pdev->dev;
+
+ dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
+ is->memory.paddr);
+}
+
+static void fimc_is_load_firmware(const struct firmware *fw, void *context)
+{
+ struct fimc_is *is = context;
+ struct device *dev = &is->pdev->dev;
+ void *buf;
+ int ret;
+
+ if (fw == NULL) {
+ dev_err(dev, "firmware request failed\n");
+ return;
+ }
+ mutex_lock(&is->lock);
+
+ if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
+ dev_err(dev, "wrong firmware size: %d\n", fw->size);
+ goto done;
+ }
+
+ is->fw.size = fw->size;
+
+ ret = fimc_is_alloc_cpu_memory(is);
+ if (ret < 0) {
+ dev_err(dev, "failed to allocate FIMC-IS CPU memory\n");
+ goto done;
+ }
+
+ memcpy(is->memory.vaddr, fw->data, fw->size);
+ wmb();
+
+ /* Read firmware description. */
+ buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_DESC_LEN);
+ memcpy(&is->fw.info, buf, FIMC_IS_FW_INFO_LEN);
+ is->fw.info[FIMC_IS_FW_INFO_LEN] = 0;
+
+ buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_VER_LEN);
+ memcpy(&is->fw.version, buf, FIMC_IS_FW_VER_LEN);
+ is->fw.version[FIMC_IS_FW_VER_LEN - 1] = 0;
+
+ is->fw.state = 1;
+
+ dev_info(dev, "loaded firmware: %s, rev. %s\n",
+ is->fw.info, is->fw.version);
+ dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr);
+
+ is->is_shared_region->chip_id = 0xe4412;
+ is->is_shared_region->chip_rev_no = 1;
+
+ fimc_is_mem_barrier();
+
+ /*
+ * FIXME: The firmware is not being released for now, as it is
+ * needed around for copying to the IS working memory every
+ * time before the Cortex-A5 is restarted.
+ */
+ if (is->fw.f_w)
+ release_firmware(is->fw.f_w);
+ is->fw.f_w = fw;
+done:
+ mutex_unlock(&is->lock);
+}
+
+static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
+{
+ return request_firmware_nowait(THIS_MODULE,
+ FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev,
+ GFP_KERNEL, is, fimc_is_load_firmware);
+}
+
+/* General IS interrupt handler */
+static void fimc_is_general_irq_handler(struct fimc_is *is)
+{
+ is->i2h_cmd.cmd = mcuctl_read(is, MCUCTL_REG_ISSR(10));
+
+ switch (is->i2h_cmd.cmd) {
+ case IHC_GET_SENSOR_NUM:
+ fimc_is_hw_get_params(is, 1);
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+ fimc_is_hw_set_sensor_num(is);
+ pr_debug("ISP FW version: %#x\n", is->i2h_cmd.args[0]);
+ break;
+ case IHC_SET_FACE_MARK:
+ case IHC_FRAME_DONE:
+ fimc_is_hw_get_params(is, 2);
+ break;
+ case IHC_SET_SHOT_MARK:
+ case IHC_AA_DONE:
+ case IH_REPLY_DONE:
+ fimc_is_hw_get_params(is, 3);
+ break;
+ case IH_REPLY_NOT_DONE:
+ fimc_is_hw_get_params(is, 4);
+ break;
+ case IHC_NOT_READY:
+ break;
+ default:
+ pr_info("unknown command: %#x\n", is->i2h_cmd.cmd);
+ }
+
+ fimc_is_fw_clear_irq1(is, FIMC_IS_INT_GENERAL);
+
+ switch (is->i2h_cmd.cmd) {
+ case IHC_GET_SENSOR_NUM:
+ fimc_is_hw_set_intgr0_gd0(is);
+ set_bit(IS_ST_A5_PWR_ON, &is->state);
+ break;
+
+ case IHC_SET_SHOT_MARK:
+ break;
+
+ case IHC_SET_FACE_MARK:
+ is->fd_header.count = is->i2h_cmd.args[0];
+ is->fd_header.index = is->i2h_cmd.args[1];
+ is->fd_header.offset = 0;
+ break;
+
+ case IHC_FRAME_DONE:
+ break;
+
+ case IHC_AA_DONE:
+ pr_debug("AA_DONE - %d, %d, %d\n", is->i2h_cmd.args[0],
+ is->i2h_cmd.args[1], is->i2h_cmd.args[2]);
+ break;
+
+ case IH_REPLY_DONE:
+ pr_debug("ISR_DONE: args[0]: %#x\n", is->i2h_cmd.args[0]);
+
+ switch (is->i2h_cmd.args[0]) {
+ case HIC_PREVIEW_STILL...HIC_CAPTURE_VIDEO:
+ /* Get CAC margin */
+ set_bit(IS_ST_CHANGE_MODE, &is->state);
+ is->isp.cac_margin_x = is->i2h_cmd.args[1];
+ is->isp.cac_margin_y = is->i2h_cmd.args[2];
+ pr_debug("CAC margin (x,y): (%d,%d)\n",
+ is->isp.cac_margin_x, is->isp.cac_margin_y);
+ break;
+
+ case HIC_STREAM_ON:
+ clear_bit(IS_ST_STREAM_OFF, &is->state);
+ set_bit(IS_ST_STREAM_ON, &is->state);
+ break;
+
+ case HIC_STREAM_OFF:
+ clear_bit(IS_ST_STREAM_ON, &is->state);
+ set_bit(IS_ST_STREAM_OFF, &is->state);
+ break;
+
+ case HIC_SET_PARAMETER:
+ is->config[is->config_index].p_region_index1 = 0;
+ is->config[is->config_index].p_region_index2 = 0;
+ set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+ pr_debug("HIC_SET_PARAMETER\n");
+ break;
+
+ case HIC_GET_PARAMETER:
+ break;
+
+ case HIC_SET_TUNE:
+ break;
+
+ case HIC_GET_STATUS:
+ break;
+
+ case HIC_OPEN_SENSOR:
+ set_bit(IS_ST_OPEN_SENSOR, &is->state);
+ pr_debug("data lanes: %d, settle line: %d\n",
+ is->i2h_cmd.args[2], is->i2h_cmd.args[1]);
+ break;
+
+ case HIC_CLOSE_SENSOR:
+ clear_bit(IS_ST_OPEN_SENSOR, &is->state);
+ is->sensor_index = 0;
+ break;
+
+ case HIC_MSG_TEST:
+ pr_debug("config MSG level completed\n");
+ break;
+
+ case HIC_POWER_DOWN:
+ clear_bit(IS_ST_PWR_SUBIP_ON, &is->state);
+ break;
+
+ case HIC_GET_SET_FILE_ADDR:
+ is->setfile.base = is->i2h_cmd.args[1];
+ set_bit(IS_ST_SETFILE_LOADED, &is->state);
+ break;
+
+ case HIC_LOAD_SET_FILE:
+ set_bit(IS_ST_SETFILE_LOADED, &is->state);
+ break;
+ }
+ break;
+
+ case IH_REPLY_NOT_DONE:
+ pr_err("ISR_NDONE: %d: %#x, %s\n", is->i2h_cmd.args[0],
+ is->i2h_cmd.args[1],
+ fimc_is_strerr(is->i2h_cmd.args[1]));
+
+ if (is->i2h_cmd.args[1] & IS_ERROR_TIME_OUT_FLAG)
+ pr_err("IS_ERROR_TIME_OUT\n");
+
+ switch (is->i2h_cmd.args[1]) {
+ case IS_ERROR_SET_PARAMETER:
+ fimc_is_mem_barrier();
+ }
+
+ switch (is->i2h_cmd.args[0]) {
+ case HIC_SET_PARAMETER:
+ is->config[is->config_index].p_region_index1 = 0;
+ is->config[is->config_index].p_region_index2 = 0;
+ set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+ break;
+ }
+ break;
+
+ case IHC_NOT_READY:
+ pr_err("IS control sequence error: Not Ready\n");
+ break;
+ }
+
+ wake_up(&is->irq_queue);
+}
+
+static irqreturn_t fimc_is_irq_handler(int irq, void *priv)
+{
+ struct fimc_is *is = priv;
+ unsigned long flags;
+ u32 status;
+
+ spin_lock_irqsave(&is->slock, flags);
+ status = mcuctl_read(is, MCUCTL_REG_INTSR1);
+
+ if (status & (1UL << FIMC_IS_INT_GENERAL))
+ fimc_is_general_irq_handler(is);
+
+ if (status & (1UL << FIMC_IS_INT_FRAME_DONE_ISP))
+ fimc_isp_irq_handler(is);
+
+ spin_unlock_irqrestore(&is->slock, flags);
+ return IRQ_HANDLED;
+}
+
+static int fimc_is_hw_open_sensor(struct fimc_is *is,
+ struct fimc_is_sensor *sensor)
+{
+ struct sensor_open_extended *soe = (void *)&is->is_p_region->shared;
+
+ fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+ soe->self_calibration_mode = 1;
+ soe->actuator_type = 0;
+ soe->mipi_lane_num = 0;
+ soe->mclk = 0;
+ soe->mipi_speed = 0;
+ soe->fast_open_sensor = 0;
+ soe->i2c_sclk = 88000000;
+
+ fimc_is_mem_barrier();
+
+ mcuctl_write(HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0));
+ mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+ mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2));
+ mcuctl_write(sensor->i2c_bus, is, MCUCTL_REG_ISSR(3));
+ mcuctl_write(is->is_dma_p_region, is, MCUCTL_REG_ISSR(4));
+
+ fimc_is_hw_set_intgr0_gd0(is);
+
+ return fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 1,
+ FIMC_IS_SENSOR_OPEN_TIMEOUT);
+}
+
+
+int fimc_is_hw_initialize(struct fimc_is *is)
+{
+ const int config_ids[] = {
+ IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO,
+ IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO
+ };
+ struct device *dev = &is->pdev->dev;
+ u32 prev_id;
+ int i, ret;
+
+ /* Sensor initialization. */
+ ret = fimc_is_hw_open_sensor(is, is->sensor);
+ if (ret < 0)
+ return ret;
+
+ /* Get the setfile address. */
+ fimc_is_hw_get_setfile_addr(is);
+
+ ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ dev_err(dev, "get setfile address timed out\n");
+ return ret;
+ }
+ pr_debug("setfile.base: %#x\n", is->setfile.base);
+
+ /* Load the setfile. */
+ fimc_is_load_setfile(is, FIMC_IS_SETFILE_6A3);
+ clear_bit(IS_ST_SETFILE_LOADED, &is->state);
+ fimc_is_hw_load_setfile(is);
+ ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ dev_err(dev, "loading setfile timed out\n");
+ return ret;
+ }
+
+ pr_debug("setfile: base: %#x, size: %d\n",
+ is->setfile.base, is->setfile.size);
+ pr_info("FIMC-IS Setfile info: %s\n", is->fw.setfile_info);
+
+ /* Check magic number. */
+ if (is->is_p_region->shared[MAX_SHARED_COUNT - 1] !=
+ FIMC_IS_MAGIC_NUMBER) {
+ dev_err(dev, "magic number error!\n");
+ return -EIO;
+ }
+
+ pr_debug("shared region: %#x, parameter region: %#x\n",
+ is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET,
+ is->is_dma_p_region);
+
+ is->setfile.sub_index = 0;
+
+ /* Stream off. */
+ fimc_is_hw_stream_off(is);
+ ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ dev_err(dev, "stream off timeout\n");
+ return ret;
+ }
+
+ /* Preserve previous mode. */
+ prev_id = is->config_index;
+
+ /* Set initial parameter values. */
+ for (i = 0; i < ARRAY_SIZE(config_ids); i++) {
+ is->config_index = config_ids[i];
+ fimc_is_set_initial_params(is);
+ ret = fimc_is_itf_s_param(is, true);
+ if (ret < 0) {
+ is->config_index = prev_id;
+ return ret;
+ }
+ }
+ is->config_index = prev_id;
+
+ set_bit(IS_ST_INIT_DONE, &is->state);
+ dev_info(dev, "initialization sequence completed (%d)\n",
+ is->config_index);
+ return 0;
+}
+
+static int fimc_is_log_show(struct seq_file *s, void *data)
+{
+ struct fimc_is *is = s->private;
+ const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET;
+
+ if (is->memory.vaddr == NULL) {
+ dev_err(&is->pdev->dev, "firmware memory is not initialized\n");
+ return -EIO;
+ }
+
+ seq_printf(s, "%s\n", buf);
+ return 0;
+}
+
+static int fimc_is_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, fimc_is_log_show, inode->i_private);
+}
+
+static const struct file_operations fimc_is_debugfs_fops = {
+ .open = fimc_is_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void fimc_is_debugfs_remove(struct fimc_is *is)
+{
+ debugfs_remove_recursive(is->debugfs_entry);
+ is->debugfs_entry = NULL;
+}
+
+static int fimc_is_debugfs_create(struct fimc_is *is)
+{
+ struct dentry *dentry;
+
+ is->debugfs_entry = debugfs_create_dir("fimc_is", NULL);
+
+ dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry,
+ is, &fimc_is_debugfs_fops);
+ if (!dentry)
+ fimc_is_debugfs_remove(is);
+
+ return is->debugfs_entry == NULL ? -EIO : 0;
+}
+
+static int fimc_is_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fimc_is *is;
+ struct resource res;
+ struct device_node *node;
+ int ret;
+
+ is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL);
+ if (!is)
+ return -ENOMEM;
+
+ is->pdev = pdev;
+ is->isp.pdev = pdev;
+
+ init_waitqueue_head(&is->irq_queue);
+ spin_lock_init(&is->slock);
+ mutex_init(&is->lock);
+
+ ret = of_address_to_resource(dev->of_node, 0, &res);
+ if (ret < 0)
+ return ret;
+
+ is->regs = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(is->regs))
+ return PTR_ERR(is->regs);
+
+ node = of_get_child_by_name(dev->of_node, "pmu");
+ if (!node)
+ return -ENODEV;
+
+ is->pmu_regs = of_iomap(node, 0);
+ if (!is->pmu_regs)
+ return -ENOMEM;
+
+ is->irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (is->irq < 0) {
+ dev_err(dev, "no irq found\n");
+ return is->irq;
+ }
+
+ ret = fimc_is_get_clocks(is);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, is);
+
+ ret = request_irq(is->irq, fimc_is_irq_handler, 0, dev_name(dev), is);
+ if (ret < 0) {
+ dev_err(dev, "irq request failed\n");
+ goto err_clk;
+ }
+ pm_runtime_enable(dev);
+ /*
+ * Enable only the ISP power domain, keep FIMC-IS clocks off until
+ * the whole clock tree is configured. The ISP power domain needs
+ * be active in order to acces any CMU_ISP clock registers.
+ */
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto err_irq;
+
+ ret = fimc_is_setup_clocks(is);
+ pm_runtime_put_sync(dev);
+
+ if (ret < 0)
+ goto err_irq;
+
+ is->clk_init = true;
+
+ is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
+ if (IS_ERR(is->alloc_ctx)) {
+ ret = PTR_ERR(is->alloc_ctx);
+ goto err_irq;
+ }
+ /*
+ * Register FIMC-IS V4L2 subdevs to this driver. The video nodes
+ * will be created within the subdev's registered() callback.
+ */
+ ret = fimc_is_register_subdevs(is);
+ if (ret < 0)
+ goto err_vb;
+
+ ret = fimc_is_debugfs_create(is);
+ if (ret < 0)
+ goto err_sd;
+
+ ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
+ if (ret < 0)
+ goto err_dfs;
+
+ dev_dbg(dev, "FIMC-IS registered successfully\n");
+ return 0;
+
+err_dfs:
+ fimc_is_debugfs_remove(is);
+err_vb:
+ vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+err_sd:
+ fimc_is_unregister_subdevs(is);
+err_irq:
+ free_irq(is->irq, is);
+err_clk:
+ fimc_is_put_clocks(is);
+ return ret;
+}
+
+static int fimc_is_runtime_resume(struct device *dev)
+{
+ struct fimc_is *is = dev_get_drvdata(dev);
+
+ if (!is->clk_init)
+ return 0;
+
+ return fimc_is_enable_clocks(is);
+}
+
+static int fimc_is_runtime_suspend(struct device *dev)
+{
+ struct fimc_is *is = dev_get_drvdata(dev);
+
+ if (is->clk_init)
+ fimc_is_disable_clocks(is);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_is_resume(struct device *dev)
+{
+ /* TODO: */
+ return 0;
+}
+
+static int fimc_is_suspend(struct device *dev)
+{
+ struct fimc_is *is = dev_get_drvdata(dev);
+
+ /* TODO: */
+ if (test_bit(IS_ST_A5_PWR_ON, &is->state))
+ return -EBUSY;
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int fimc_is_remove(struct platform_device *pdev)
+{
+ struct fimc_is *is = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ free_irq(is->irq, is);
+ fimc_is_unregister_subdevs(is);
+ vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+ fimc_is_put_clocks(is);
+ fimc_is_debugfs_remove(is);
+ release_firmware(is->fw.f_w);
+ fimc_is_free_cpu_memory(is);
+
+ return 0;
+}
+
+static const struct of_device_id fimc_is_of_match[] = {
+ { .compatible = "samsung,exynos4212-fimc-is" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, fimc_is_of_match);
+
+static const struct dev_pm_ops fimc_is_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fimc_is_suspend, fimc_is_resume)
+ SET_RUNTIME_PM_OPS(fimc_is_runtime_suspend, fimc_is_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver fimc_is_driver = {
+ .probe = fimc_is_probe,
+ .remove = fimc_is_remove,
+ .driver = {
+ .of_match_table = fimc_is_of_match,
+ .name = FIMC_IS_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_is_pm_ops,
+ }
+};
+
+static int fimc_is_module_init(void)
+{
+ int ret;
+
+ ret = fimc_is_register_sensor_driver();
+ if (ret < 0)
+ return ret;
+
+ ret = fimc_is_register_i2c_driver();
+ if (ret < 0)
+ goto err_sens;
+
+ ret = platform_driver_register(&fimc_is_driver);
+ if (!ret)
+ return ret;
+
+ fimc_is_unregister_i2c_driver();
+err_sens:
+ fimc_is_unregister_sensor_driver();
+ return ret;
+}
+
+static void fimc_is_module_exit(void)
+{
+ fimc_is_unregister_sensor_driver();
+ fimc_is_unregister_i2c_driver();
+ platform_driver_unregister(&fimc_is_driver);
+}
+
+module_init(fimc_is_module_init);
+module_exit(fimc_is_module_exit);
+
+MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME);
+MODULE_AUTHOR("Younghwan Joo <yhwan.joo@samsung.com>");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h
new file mode 100644
index 000000000000..f5275a5b0156
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-is.h
@@ -0,0 +1,345 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_H_
+#define FIMC_IS_H_
+
+#include <asm/barrier.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
+
+#include "fimc-isp.h"
+#include "fimc-is-command.h"
+#include "fimc-is-sensor.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+
+#define FIMC_IS_DRV_NAME "exynos4-fimc-is"
+
+#define FIMC_IS_FW_FILENAME "fimc_is_fw.bin"
+#define FIMC_IS_SETFILE_6A3 "setfile.bin"
+
+#define FIMC_IS_FW_LOAD_TIMEOUT 1000 /* ms */
+#define FIMC_IS_POWER_ON_TIMEOUT 1000 /* us */
+
+#define FIMC_IS_SENSOR_NUM 2
+
+/* Memory definitions */
+#define FIMC_IS_CPU_MEM_SIZE (0xa00000)
+#define FIMC_IS_CPU_BASE_MASK ((1 << 26) - 1)
+#define FIMC_IS_REGION_SIZE 0x5000
+
+#define FIMC_IS_DEBUG_REGION_OFFSET 0x0084b000
+#define FIMC_IS_SHARED_REGION_OFFSET 0x008c0000
+#define FIMC_IS_FW_INFO_LEN 31
+#define FIMC_IS_FW_VER_LEN 7
+#define FIMC_IS_FW_DESC_LEN (FIMC_IS_FW_INFO_LEN + \
+ FIMC_IS_FW_VER_LEN)
+#define FIMC_IS_SETFILE_INFO_LEN 39
+
+#define FIMC_IS_EXTRA_MEM_SIZE (FIMC_IS_EXTRA_FW_SIZE + \
+ FIMC_IS_EXTRA_SETFILE_SIZE + 0x1000)
+#define FIMC_IS_EXTRA_FW_SIZE 0x180000
+#define FIMC_IS_EXTRA_SETFILE_SIZE 0x4b000
+
+/* TODO: revisit */
+#define FIMC_IS_FW_ADDR_MASK ((1 << 26) - 1)
+#define FIMC_IS_FW_SIZE_MAX (SZ_4M)
+#define FIMC_IS_FW_SIZE_MIN (SZ_32K)
+
+#define ATCLK_MCUISP_FREQUENCY 100000000UL
+#define ACLK_AXI_FREQUENCY 100000000UL
+
+enum {
+ ISS_CLK_PPMUISPX,
+ ISS_CLK_PPMUISPMX,
+ ISS_CLK_LITE0,
+ ISS_CLK_LITE1,
+ ISS_CLK_MPLL,
+ ISS_CLK_SYSREG,
+ ISS_CLK_ISP,
+ ISS_CLK_DRC,
+ ISS_CLK_FD,
+ ISS_CLK_MCUISP,
+ ISS_CLK_UART,
+ ISS_GATE_CLKS_MAX,
+ ISS_CLK_ISP_DIV0 = ISS_GATE_CLKS_MAX,
+ ISS_CLK_ISP_DIV1,
+ ISS_CLK_MCUISP_DIV0,
+ ISS_CLK_MCUISP_DIV1,
+ ISS_CLK_ACLK200,
+ ISS_CLK_ACLK200_DIV,
+ ISS_CLK_ACLK400MCUISP,
+ ISS_CLK_ACLK400MCUISP_DIV,
+ ISS_CLKS_MAX
+};
+
+/* The driver's internal state flags */
+enum {
+ IS_ST_IDLE,
+ IS_ST_PWR_ON,
+ IS_ST_A5_PWR_ON,
+ IS_ST_FW_LOADED,
+ IS_ST_OPEN_SENSOR,
+ IS_ST_SETFILE_LOADED,
+ IS_ST_INIT_DONE,
+ IS_ST_STREAM_ON,
+ IS_ST_STREAM_OFF,
+ IS_ST_CHANGE_MODE,
+ IS_ST_BLOCK_CMD_CLEARED,
+ IS_ST_SET_ZOOM,
+ IS_ST_PWR_SUBIP_ON,
+ IS_ST_END,
+};
+
+enum af_state {
+ FIMC_IS_AF_IDLE = 0,
+ FIMC_IS_AF_SETCONFIG = 1,
+ FIMC_IS_AF_RUNNING = 2,
+ FIMC_IS_AF_LOCK = 3,
+ FIMC_IS_AF_ABORT = 4,
+ FIMC_IS_AF_FAILED = 5,
+};
+
+enum af_lock_state {
+ FIMC_IS_AF_UNLOCKED = 0,
+ FIMC_IS_AF_LOCKED = 2
+};
+
+enum ae_lock_state {
+ FIMC_IS_AE_UNLOCKED = 0,
+ FIMC_IS_AE_LOCKED = 1
+};
+
+enum awb_lock_state {
+ FIMC_IS_AWB_UNLOCKED = 0,
+ FIMC_IS_AWB_LOCKED = 1
+};
+
+enum {
+ IS_METERING_CONFIG_CMD,
+ IS_METERING_CONFIG_WIN_POS_X,
+ IS_METERING_CONFIG_WIN_POS_Y,
+ IS_METERING_CONFIG_WIN_WIDTH,
+ IS_METERING_CONFIG_WIN_HEIGHT,
+ IS_METERING_CONFIG_MAX
+};
+
+struct is_setfile {
+ const struct firmware *info;
+ int state;
+ u32 sub_index;
+ u32 base;
+ size_t size;
+};
+
+struct is_fd_result_header {
+ u32 offset;
+ u32 count;
+ u32 index;
+ u32 curr_index;
+ u32 width;
+ u32 height;
+};
+
+struct is_af_info {
+ u16 mode;
+ u32 af_state;
+ u32 af_lock_state;
+ u32 ae_lock_state;
+ u32 awb_lock_state;
+ u16 pos_x;
+ u16 pos_y;
+ u16 prev_pos_x;
+ u16 prev_pos_y;
+ u16 use_af;
+};
+
+struct fimc_is_firmware {
+ const struct firmware *f_w;
+
+ dma_addr_t paddr;
+ void *vaddr;
+ unsigned int size;
+
+ char info[FIMC_IS_FW_INFO_LEN + 1];
+ char version[FIMC_IS_FW_VER_LEN + 1];
+ char setfile_info[FIMC_IS_SETFILE_INFO_LEN + 1];
+ u8 state;
+};
+
+struct fimc_is_memory {
+ /* physical base address */
+ dma_addr_t paddr;
+ /* virtual base address */
+ void *vaddr;
+ /* total length */
+ unsigned int size;
+};
+
+#define FIMC_IS_I2H_MAX_ARGS 12
+
+struct i2h_cmd {
+ u32 cmd;
+ u32 sensor_id;
+ u16 num_args;
+ u32 args[FIMC_IS_I2H_MAX_ARGS];
+};
+
+struct h2i_cmd {
+ u16 cmd_type;
+ u32 entry_id;
+};
+
+#define FIMC_IS_DEBUG_MSG 0x3f
+#define FIMC_IS_DEBUG_LEVEL 3
+
+struct fimc_is_setfile {
+ const struct firmware *info;
+ unsigned int state;
+ unsigned int size;
+ u32 sub_index;
+ u32 base;
+};
+
+struct chain_config {
+ struct global_param global;
+ struct sensor_param sensor;
+ struct isp_param isp;
+ struct drc_param drc;
+ struct fd_param fd;
+
+ unsigned long p_region_index1;
+ unsigned long p_region_index2;
+};
+
+/**
+ * struct fimc_is - fimc-is data structure
+ * @pdev: pointer to FIMC-IS platform device
+ * @pctrl: pointer to pinctrl structure for this device
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @lock: mutex serializing video device and the subdev operations
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @clocks: FIMC-LITE gate clock
+ * @regs: MCUCTL mmapped registers region
+ * @pmu_regs: PMU ISP mmapped registers region
+ * @irq_queue: interrupt handling waitqueue
+ * @lpm: low power mode flag
+ * @state: internal driver's state flags
+ */
+struct fimc_is {
+ struct platform_device *pdev;
+ struct pinctrl *pctrl;
+ struct v4l2_device *v4l2_dev;
+
+ struct fimc_is_firmware fw;
+ struct fimc_is_memory memory;
+ struct firmware *f_w;
+
+ struct fimc_isp isp;
+ struct fimc_is_sensor *sensor;
+ struct fimc_is_setfile setfile;
+
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct mutex lock;
+ spinlock_t slock;
+
+ struct clk *clocks[ISS_CLKS_MAX];
+ bool clk_init;
+ void __iomem *regs;
+ void __iomem *pmu_regs;
+ int irq;
+ wait_queue_head_t irq_queue;
+ u8 lpm;
+
+ unsigned long state;
+ unsigned int sensor_index;
+
+ struct i2h_cmd i2h_cmd;
+ struct h2i_cmd h2i_cmd;
+ struct is_fd_result_header fd_header;
+
+ struct chain_config config[IS_SC_MAX];
+ unsigned config_index;
+
+ struct is_region *is_p_region;
+ dma_addr_t is_dma_p_region;
+ struct is_share_region *is_shared_region;
+ struct is_af_info af;
+
+ struct dentry *debugfs_entry;
+};
+
+static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp)
+{
+ return container_of(isp, struct fimc_is, isp);
+}
+
+static inline void fimc_is_mem_barrier(void)
+{
+ mb();
+}
+
+static inline void fimc_is_set_param_bit(struct fimc_is *is, int num)
+{
+ struct chain_config *cfg = &is->config[is->config_index];
+
+ if (num >= 32)
+ set_bit(num - 32, &cfg->p_region_index2);
+ else
+ set_bit(num, &cfg->p_region_index1);
+}
+
+static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd)
+{
+ is->is_p_region->parameter.isp.control.cmd = cmd;
+}
+
+static inline void mcuctl_write(u32 v, struct fimc_is *is, unsigned int offset)
+{
+ writel(v, is->regs + offset);
+}
+
+static inline u32 mcuctl_read(struct fimc_is *is, unsigned int offset)
+{
+ return readl(is->regs + offset);
+}
+
+static inline void pmuisp_write(u32 v, struct fimc_is *is, unsigned int offset)
+{
+ writel(v, is->pmu_regs + offset);
+}
+
+static inline u32 pmuisp_read(struct fimc_is *is, unsigned int offset)
+{
+ return readl(is->pmu_regs + offset);
+}
+
+int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
+ unsigned int state, unsigned int timeout);
+int fimc_is_cpu_set_power(struct fimc_is *is, int on);
+int fimc_is_start_firmware(struct fimc_is *is);
+int fimc_is_hw_initialize(struct fimc_is *is);
+void fimc_is_log_dump(const char *level, const void *buf, size_t len);
+
+#endif /* FIMC_IS_H_ */
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
new file mode 100644
index 000000000000..d63947f7b302
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -0,0 +1,703 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/v4l2-device.h>
+
+#include "media-dev.h"
+#include "fimc-is-command.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+#include "fimc-is.h"
+
+static int debug;
+module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR);
+
+static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
+ {
+ .name = "RAW8 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = { 8 },
+ .color = FIMC_FMT_RAW8,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ }, {
+ .name = "RAW10 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .depth = { 10 },
+ .color = FIMC_FMT_RAW10,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ }, {
+ .name = "RAW12 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .depth = { 12 },
+ .color = FIMC_FMT_RAW12,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ },
+};
+
+/**
+ * fimc_isp_find_format - lookup color format by fourcc or media bus code
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @index: index to the fimc_isp_formats array, ignored if negative
+ */
+const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
+ const u32 *mbus_code, int index)
+{
+ const struct fimc_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+ int id = 0;
+
+ if (index >= (int)ARRAY_SIZE(fimc_isp_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_isp_formats); ++i) {
+ fmt = &fimc_isp_formats[i];
+ if (pixelformat && fmt->fourcc == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == id)
+ def_fmt = fmt;
+ id++;
+ }
+ return def_fmt;
+}
+
+void fimc_isp_irq_handler(struct fimc_is *is)
+{
+ is->i2h_cmd.args[0] = mcuctl_read(is, MCUCTL_REG_ISSR(20));
+ is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21));
+
+ fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP);
+
+ /* TODO: Complete ISP DMA interrupt handler */
+ wake_up(&is->irq_queue);
+}
+
+/* Capture subdev media entity operations */
+static int fimc_is_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ return 0;
+}
+
+static const struct media_entity_operations fimc_is_subdev_media_ops = {
+ .link_setup = fimc_is_link_setup,
+};
+
+static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ const struct fimc_fmt *fmt;
+
+ fmt = fimc_isp_find_format(NULL, NULL, code->index);
+ if (!fmt)
+ return -EINVAL;
+ code->code = fmt->mbus_code;
+ return 0;
+}
+
+static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+ struct fimc_is *is = fimc_isp_to_is(isp);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct v4l2_mbus_framefmt cur_fmt;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ fmt->format = *mf;
+ return 0;
+ }
+
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ mutex_lock(&isp->subdev_lock);
+ __is_get_frame_size(is, &cur_fmt);
+
+ if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+ /* full camera input frame size */
+ mf->width = cur_fmt.width + FIMC_ISP_CAC_MARGIN_WIDTH;
+ mf->height = cur_fmt.height + FIMC_ISP_CAC_MARGIN_HEIGHT;
+ mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ } else {
+ /* crop size */
+ mf->width = cur_fmt.width;
+ mf->height = cur_fmt.height;
+ mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ }
+
+ mutex_unlock(&isp->subdev_lock);
+
+ v4l2_dbg(1, debug, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n",
+ __func__, fmt->pad, mf->code, mf->width, mf->height);
+
+ return 0;
+}
+
+static void __isp_subdev_try_format(struct fimc_isp *isp,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+
+ if (fmt->pad == FIMC_ISP_SD_PAD_SINK) {
+ v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN,
+ FIMC_ISP_SINK_WIDTH_MAX, 0,
+ &mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
+ FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
+ isp->subdev_fmt = *mf;
+ } else {
+ /* Allow changing format only on sink pad */
+ mf->width = isp->subdev_fmt.width - FIMC_ISP_CAC_MARGIN_WIDTH;
+ mf->height = isp->subdev_fmt.height - FIMC_ISP_CAC_MARGIN_HEIGHT;
+ mf->code = isp->subdev_fmt.code;
+ }
+}
+
+static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+ struct fimc_is *is = fimc_isp_to_is(isp);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
+ __func__, fmt->pad, mf->code, mf->width, mf->height);
+
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ mutex_lock(&isp->subdev_lock);
+ __isp_subdev_try_format(isp, fmt);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = fmt->format;
+ mutex_unlock(&isp->subdev_lock);
+ return 0;
+ }
+
+ if (sd->entity.stream_count == 0)
+ __is_set_frame_size(is, mf);
+ else
+ ret = -EBUSY;
+ mutex_unlock(&isp->subdev_lock);
+
+ return ret;
+}
+
+static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+ struct fimc_is *is = fimc_isp_to_is(isp);
+ int ret;
+
+ v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
+
+ if (!test_bit(IS_ST_INIT_DONE, &is->state))
+ return -EBUSY;
+
+ fimc_is_mem_barrier();
+
+ if (on) {
+ if (__get_pending_param_count(is)) {
+ ret = fimc_is_itf_s_param(is, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ v4l2_dbg(1, debug, sd, "changing mode to %d\n",
+ is->config_index);
+ ret = fimc_is_itf_mode_change(is);
+ if (ret)
+ return -EINVAL;
+
+ clear_bit(IS_ST_STREAM_ON, &is->state);
+ fimc_is_hw_stream_on(is);
+ ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ v4l2_err(sd, "stream on timeout\n");
+ return ret;
+ }
+ } else {
+ clear_bit(IS_ST_STREAM_OFF, &is->state);
+ fimc_is_hw_stream_off(is);
+ ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ v4l2_err(sd, "stream off timeout\n");
+ return ret;
+ }
+ is->setfile.sub_index = 0;
+ }
+
+ return 0;
+}
+
+static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+ struct fimc_is *is = fimc_isp_to_is(isp);
+ int ret = 0;
+
+ pr_debug("on: %d\n", on);
+
+ if (on) {
+ ret = pm_runtime_get_sync(&is->pdev->dev);
+ if (ret < 0)
+ return ret;
+ set_bit(IS_ST_PWR_ON, &is->state);
+
+ ret = fimc_is_start_firmware(is);
+ if (ret < 0) {
+ v4l2_err(sd, "firmware booting failed\n");
+ pm_runtime_put(&is->pdev->dev);
+ return ret;
+ }
+ set_bit(IS_ST_PWR_SUBIP_ON, &is->state);
+
+ ret = fimc_is_hw_initialize(is);
+ } else {
+ /* Close sensor */
+ if (!test_bit(IS_ST_PWR_ON, &is->state)) {
+ fimc_is_hw_close_sensor(is, 0);
+
+ ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ v4l2_err(sd, "sensor close timeout\n");
+ return ret;
+ }
+ }
+
+ /* SUB IP power off */
+ if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) {
+ fimc_is_hw_subip_power_off(is);
+ ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0,
+ FIMC_IS_CONFIG_TIMEOUT);
+ if (ret < 0) {
+ v4l2_err(sd, "sub-IP power off timeout\n");
+ return ret;
+ }
+ }
+
+ fimc_is_cpu_set_power(is, 0);
+ pm_runtime_put_sync(&is->pdev->dev);
+
+ clear_bit(IS_ST_PWR_ON, &is->state);
+ clear_bit(IS_ST_INIT_DONE, &is->state);
+ is->state = 0;
+ is->config[is->config_index].p_region_index1 = 0;
+ is->config[is->config_index].p_region_index2 = 0;
+ set_bit(IS_ST_IDLE, &is->state);
+ wmb();
+ }
+
+ return ret;
+}
+
+static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt fmt;
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK);
+
+ fmt.colorspace = V4L2_COLORSPACE_SRGB;
+ fmt.code = fimc_isp_formats[0].mbus_code;
+ fmt.width = DEFAULT_PREVIEW_STILL_WIDTH + FIMC_ISP_CAC_MARGIN_WIDTH;
+ fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT;
+ fmt.field = V4L2_FIELD_NONE;
+ *format = fmt;
+
+ format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO);
+ fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
+ fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+ *format = fmt;
+
+ format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA);
+ *format = fmt;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = {
+ .open = fimc_isp_subdev_open,
+};
+
+static const struct v4l2_subdev_pad_ops fimc_is_subdev_pad_ops = {
+ .enum_mbus_code = fimc_is_subdev_enum_mbus_code,
+ .get_fmt = fimc_isp_subdev_get_fmt,
+ .set_fmt = fimc_isp_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = {
+ .s_stream = fimc_isp_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops fimc_is_core_ops = {
+ .s_power = fimc_isp_subdev_s_power,
+};
+
+static struct v4l2_subdev_ops fimc_is_subdev_ops = {
+ .core = &fimc_is_core_ops,
+ .video = &fimc_is_subdev_video_ops,
+ .pad = &fimc_is_subdev_pad_ops,
+};
+
+static int __ctrl_set_white_balance(struct fimc_is *is, int value)
+{
+ switch (value) {
+ case V4L2_WHITE_BALANCE_AUTO:
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
+ break;
+ case V4L2_WHITE_BALANCE_DAYLIGHT:
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+ ISP_AWB_ILLUMINATION_DAYLIGHT);
+ break;
+ case V4L2_WHITE_BALANCE_CLOUDY:
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+ ISP_AWB_ILLUMINATION_CLOUDY);
+ break;
+ case V4L2_WHITE_BALANCE_INCANDESCENT:
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+ ISP_AWB_ILLUMINATION_TUNGSTEN);
+ break;
+ case V4L2_WHITE_BALANCE_FLUORESCENT:
+ __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+ ISP_AWB_ILLUMINATION_FLUORESCENT);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __ctrl_set_aewb_lock(struct fimc_is *is,
+ struct v4l2_ctrl *ctrl)
+{
+ bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
+ bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
+ struct isp_param *isp = &is->is_p_region->parameter.isp;
+ int cmd, ret;
+
+ cmd = ae_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
+ isp->aa.cmd = cmd;
+ isp->aa.target = ISP_AA_TARGET_AE;
+ fimc_is_set_param_bit(is, PARAM_ISP_AA);
+ is->af.ae_lock_state = ae_lock;
+ wmb();
+
+ ret = fimc_is_itf_s_param(is, false);
+ if (ret < 0)
+ return ret;
+
+ cmd = awb_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
+ isp->aa.cmd = cmd;
+ isp->aa.target = ISP_AA_TARGET_AE;
+ fimc_is_set_param_bit(is, PARAM_ISP_AA);
+ is->af.awb_lock_state = awb_lock;
+ wmb();
+
+ return fimc_is_itf_s_param(is, false);
+}
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+ 50, 100, 200, 400, 800,
+};
+
+static int __ctrl_set_iso(struct fimc_is *is, int value)
+{
+ unsigned int idx, iso;
+
+ if (value == V4L2_ISO_SENSITIVITY_AUTO) {
+ __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
+ return 0;
+ }
+ idx = is->isp.ctrls.iso->val;
+ if (idx >= ARRAY_SIZE(iso_qmenu))
+ return -EINVAL;
+
+ iso = iso_qmenu[idx];
+ __is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso);
+ return 0;
+}
+
+static int __ctrl_set_metering(struct fimc_is *is, unsigned int value)
+{
+ unsigned int val;
+
+ switch (value) {
+ case V4L2_EXPOSURE_METERING_AVERAGE:
+ val = ISP_METERING_COMMAND_AVERAGE;
+ break;
+ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+ val = ISP_METERING_COMMAND_CENTER;
+ break;
+ case V4L2_EXPOSURE_METERING_SPOT:
+ val = ISP_METERING_COMMAND_SPOT;
+ break;
+ case V4L2_EXPOSURE_METERING_MATRIX:
+ val = ISP_METERING_COMMAND_MATRIX;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ __is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val);
+ return 0;
+}
+
+static int __ctrl_set_afc(struct fimc_is *is, int value)
+{
+ switch (value) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+ __is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+ __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+ __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
+ __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __ctrl_set_image_effect(struct fimc_is *is, int value)
+{
+ static const u8 effects[][2] = {
+ { V4L2_COLORFX_NONE, ISP_IMAGE_EFFECT_DISABLE },
+ { V4L2_COLORFX_BW, ISP_IMAGE_EFFECT_MONOCHROME },
+ { V4L2_COLORFX_SEPIA, ISP_IMAGE_EFFECT_SEPIA },
+ { V4L2_COLORFX_NEGATIVE, ISP_IMAGE_EFFECT_NEGATIVE_MONO },
+ { 16 /* TODO */, ISP_IMAGE_EFFECT_NEGATIVE_COLOR },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(effects); i++) {
+ if (effects[i][0] != value)
+ continue;
+
+ __is_set_isp_effect(is, effects[i][1]);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl);
+ struct fimc_is *is = fimc_isp_to_is(isp);
+ bool set_param = true;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_SATURATION:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_SHARPNESS:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE_ABSOLUTE:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_HUE:
+ __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE_METERING:
+ ret = __ctrl_set_metering(is, ctrl->val);
+ break;
+
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ret = __ctrl_set_white_balance(is, ctrl->val);
+ break;
+
+ case V4L2_CID_3A_LOCK:
+ ret = __ctrl_set_aewb_lock(is, ctrl);
+ set_param = false;
+ break;
+
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ ret = __ctrl_set_iso(is, ctrl->val);
+ break;
+
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ ret = __ctrl_set_afc(is, ctrl->val);
+ break;
+
+ case V4L2_CID_COLORFX:
+ __ctrl_set_image_effect(is, ctrl->val);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret < 0) {
+ v4l2_err(&isp->subdev, "Failed to set control: %s (%d)\n",
+ ctrl->name, ctrl->val);
+ return ret;
+ }
+
+ if (set_param && test_bit(IS_ST_STREAM_ON, &is->state))
+ return fimc_is_itf_s_param(is, true);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
+ .s_ctrl = fimc_is_s_ctrl,
+};
+
+int fimc_isp_subdev_create(struct fimc_isp *isp)
+{
+ const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
+ struct v4l2_ctrl_handler *handler = &isp->ctrls.handler;
+ struct v4l2_subdev *sd = &isp->subdev;
+ struct fimc_isp_ctrls *ctrls = &isp->ctrls;
+ int ret;
+
+ mutex_init(&isp->subdev_lock);
+
+ v4l2_subdev_init(sd, &fimc_is_subdev_ops);
+ sd->grp_id = GRP_ID_FIMC_IS;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
+
+ isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
+ isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, FIMC_ISP_SD_PADS_NUM,
+ isp->subdev_pads, 0);
+ if (ret)
+ return ret;
+
+ v4l2_ctrl_handler_init(handler, 20);
+
+ ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION,
+ -2, 2, 1, 0);
+ ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS,
+ -4, 4, 1, 0);
+ ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST,
+ -2, 2, 1, 0);
+ ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS,
+ -2, 2, 1, 0);
+ ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE,
+ -2, 2, 1, 0);
+
+ ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ 8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
+
+ ctrls->exposure = v4l2_ctrl_new_std(handler, ops,
+ V4L2_CID_EXPOSURE_ABSOLUTE,
+ -4, 4, 1, 0);
+
+ ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops,
+ V4L2_CID_EXPOSURE_METERING, 3,
+ ~0xf, V4L2_EXPOSURE_METERING_AVERAGE);
+
+ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+ /* ISO sensitivity */
+ ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops,
+ V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
+ V4L2_ISO_SENSITIVITY_AUTO);
+
+ ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops,
+ V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+ ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+ ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops,
+ V4L2_CID_3A_LOCK, 0, 0x3, 0, 0);
+
+ /* TODO: Add support for NEGATIVE_COLOR option */
+ ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX,
+ V4L2_COLORFX_SET_CBCR + 1, ~0x1000f, V4L2_COLORFX_NONE);
+
+ if (handler->error) {
+ media_entity_cleanup(&sd->entity);
+ return handler->error;
+ }
+
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso,
+ V4L2_ISO_SENSITIVITY_MANUAL, false);
+
+ sd->ctrl_handler = handler;
+ sd->internal_ops = &fimc_is_subdev_internal_ops;
+ sd->entity.ops = &fimc_is_subdev_media_ops;
+ v4l2_set_subdevdata(sd, isp);
+
+ return 0;
+}
+
+void fimc_isp_subdev_destroy(struct fimc_isp *isp)
+{
+ struct v4l2_subdev *sd = &isp->subdev;
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&isp->ctrls.handler);
+ v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h
new file mode 100644
index 000000000000..800aba7ab4a7
--- /dev/null
+++ b/drivers/media/platform/exynos4-is/fimc-isp.h
@@ -0,0 +1,181 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ * Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_ISP_H_
+#define FIMC_ISP_H_
+
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+/* FIXME: revisit these constraints */
+#define FIMC_ISP_SINK_WIDTH_MIN (16 + 8)
+#define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8)
+#define FIMC_ISP_SOURCE_WIDTH_MIN 8
+#define FIMC_ISP_SOURC_HEIGHT_MIN 8
+#define FIMC_ISP_CAC_MARGIN_WIDTH 16
+#define FIMC_ISP_CAC_MARGIN_HEIGHT 12
+
+#define FIMC_ISP_SINK_WIDTH_MAX (4000 - 16)
+#define FIMC_ISP_SINK_HEIGHT_MAX (4000 + 12)
+#define FIMC_ISP_SOURCE_WIDTH_MAX 4000
+#define FIMC_ISP_SOURC_HEIGHT_MAX 4000
+
+#define FIMC_ISP_NUM_FORMATS 3
+#define FIMC_ISP_REQ_BUFS_MIN 2
+
+#define FIMC_ISP_SD_PAD_SINK 0
+#define FIMC_ISP_SD_PAD_SRC_FIFO 1
+#define FIMC_ISP_SD_PAD_SRC_DMA 2
+#define FIMC_ISP_SD_PADS_NUM 3
+#define FIMC_ISP_MAX_PLANES 1
+
+/**
+ * struct fimc_isp_frame - source/target frame properties
+ * @width: full image width
+ * @height: full image height
+ * @rect: crop/composition rectangle
+ */
+struct fimc_isp_frame {
+ u16 width;
+ u16 height;
+ struct v4l2_rect rect;
+};
+
+struct fimc_isp_ctrls {
+ struct v4l2_ctrl_handler handler;
+
+ /* Auto white balance */
+ struct v4l2_ctrl *auto_wb;
+ /* Auto ISO control cluster */
+ struct {
+ struct v4l2_ctrl *auto_iso;
+ struct v4l2_ctrl *iso;
+ };
+ /* Adjust - contrast */
+ struct v4l2_ctrl *contrast;
+ /* Adjust - saturation */
+ struct v4l2_ctrl *saturation;
+ /* Adjust - sharpness */
+ struct v4l2_ctrl *sharpness;
+ /* Adjust - brightness */
+ struct v4l2_ctrl *brightness;
+ /* Adjust - hue */
+ struct v4l2_ctrl *hue;
+
+ /* Auto/manual exposure */
+ struct v4l2_ctrl *auto_exp;
+ /* Manual exposure value */
+ struct v4l2_ctrl *exposure;
+ /* AE/AWB lock/unlock */
+ struct v4l2_ctrl *aewb_lock;
+ /* Exposure metering mode */
+ struct v4l2_ctrl *exp_metering;
+ /* AFC */
+ struct v4l2_ctrl *afc;
+ /* ISP image effect */
+ struct v4l2_ctrl *colorfx;
+};
+
+/**
+ * struct fimc_is_video - fimc-is video device structure
+ * @vdev: video_device structure
+ * @type: video device type (CAPTURE/OUTPUT)
+ * @pad: video device media (sink) pad
+ * @pending_buf_q: pending buffers queue head
+ * @active_buf_q: a queue head of buffers scheduled in hardware
+ * @vb_queue: vb2 buffer queue
+ * @active_buf_count: number of video buffers scheduled in hardware
+ * @frame_count: counter of frames dequeued to user space
+ * @reqbufs_count: number of buffers requested with REQBUFS ioctl
+ * @format: current pixel format
+ */
+struct fimc_is_video {
+ struct video_device vdev;
+ enum v4l2_buf_type type;
+ struct media_pad pad;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ struct vb2_queue vb_queue;
+ unsigned int frame_count;
+ unsigned int reqbufs_count;
+ int streaming;
+ unsigned long payload[FIMC_ISP_MAX_PLANES];
+ const struct fimc_fmt *format;
+};
+
+/**
+ * struct fimc_isp - FIMC-IS ISP data structure
+ * @pdev: pointer to FIMC-IS platform device
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @subdev: ISP v4l2_subdev
+ * @subdev_pads: the ISP subdev media pads
+ * @ctrl_handler: v4l2 controls handler
+ * @test_pattern: test pattern controls
+ * @pipeline: video capture pipeline data structure
+ * @video_lock: mutex serializing video device and the subdev operations
+ * @fmt: pointer to color format description structure
+ * @payload: image size in bytes (w x h x bpp)
+ * @inp_frame: camera input frame structure
+ * @out_frame: DMA output frame structure
+ * @source_subdev_grp_id: group id of remote source subdev
+ * @cac_margin_x: horizontal CAC margin in pixels
+ * @cac_margin_y: vertical CAC margin in pixels
+ * @state: driver state flags
+ * @video_capture: the ISP block video capture device
+ */
+struct fimc_isp {
+ struct platform_device *pdev;
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct v4l2_subdev subdev;
+ struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM];
+ struct v4l2_mbus_framefmt subdev_fmt;
+ struct v4l2_ctrl *test_pattern;
+ struct fimc_isp_ctrls ctrls;
+
+ struct mutex video_lock;
+ struct mutex subdev_lock;
+
+ struct fimc_isp_frame inp_frame;
+ struct fimc_isp_frame out_frame;
+ unsigned int source_subdev_grp_id;
+
+ unsigned int cac_margin_x;
+ unsigned int cac_margin_y;
+
+ unsigned long state;
+
+ struct fimc_is_video video_capture;
+};
+
+#define ctrl_to_fimc_isp(_ctrl) \
+ container_of(ctrl->handler, struct fimc_isp, ctrls.handler)
+
+struct fimc_is;
+
+int fimc_isp_subdev_create(struct fimc_isp *isp);
+void fimc_isp_subdev_destroy(struct fimc_isp *isp);
+void fimc_isp_irq_handler(struct fimc_is *is);
+int fimc_is_create_controls(struct fimc_isp *isp);
+int fimc_is_delete_controls(struct fimc_isp *isp);
+const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
+ const u32 *mbus_code, int index);
+#endif /* FIMC_ISP_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index f0af0754a7b4..8cc0d39a2fea 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -127,11 +127,11 @@ static const u32 src_pixfmt_map[8][3] = {
/* Set camera input pixel format and resolution */
void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
{
- enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
- unsigned int i = ARRAY_SIZE(src_pixfmt_map);
+ enum v4l2_mbus_pixelcode pixelcode = f->fmt->mbus_code;
+ int i = ARRAY_SIZE(src_pixfmt_map);
u32 cfg;
- while (i-- >= 0) {
+ while (--i >= 0) {
if (src_pixfmt_map[i][0] == pixelcode)
break;
}
@@ -224,10 +224,10 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
{ V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
};
u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
- unsigned int i = ARRAY_SIZE(pixcode);
+ int i = ARRAY_SIZE(pixcode);
- while (i-- >= 0)
- if (pixcode[i][0] == dev->fmt->mbus_code)
+ while (--i >= 0)
+ if (pixcode[i][0] == f->fmt->mbus_code)
break;
cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
index 0e345844c13a..390383941c19 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
@@ -72,10 +72,10 @@
#define FLITE_REG_CIODMAFMT 0x18
#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15)
#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
-#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
-#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
-#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
-#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4)
+#define FLITE_REG_CIODMAFMT_CRYCBY (3 << 4)
#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4)
/* Camera Output Canvas */
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index bfc4206935c8..14bb7bc8adbe 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -11,12 +11,14 @@
#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
#include <linux/bug.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -30,7 +32,6 @@
#include <media/videobuf2-dma-contig.h>
#include <media/s5p_fimc.h>
-#include "fimc-mdevice.h"
#include "fimc-core.h"
#include "fimc-lite.h"
#include "fimc-lite-reg.h"
@@ -46,6 +47,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
@@ -53,6 +55,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
@@ -60,6 +63,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
@@ -67,6 +71,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .flags = FMT_FLAGS_YUV,
}, {
.name = "RAW8 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG8,
@@ -74,6 +79,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_RAW8,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
@@ -81,6 +87,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_RAW10,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
@@ -88,6 +95,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.color = FIMC_FMT_RAW12,
.memplanes = 1,
.mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .flags = FMT_FLAGS_RAW_BAYER,
},
};
@@ -95,10 +103,11 @@ static const struct fimc_fmt fimc_lite_formats[] = {
* fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
* @pixelformat: fourcc to match, ignored if null
* @mbus_code: media bus code to match, ignored if null
+ * @mask: the color format flags to match
* @index: index to the fimc_lite_formats array, ignored if negative
*/
static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
- const u32 *mbus_code, int index)
+ const u32 *mbus_code, unsigned int mask, int index)
{
const struct fimc_fmt *fmt, *def_fmt = NULL;
unsigned int i;
@@ -109,6 +118,8 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
fmt = &fimc_lite_formats[i];
+ if (mask && !(fmt->flags & mask))
+ continue;
if (pixelformat && fmt->fourcc == *pixelformat)
return fmt;
if (mbus_code && fmt->mbus_code == *mbus_code)
@@ -120,26 +131,49 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
return def_fmt;
}
+/* Called with the media graph mutex held or @me stream_count > 0. */
+static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
+{
+ struct media_pad *pad = &me->pads[0];
+ struct v4l2_subdev *sd;
+
+ while (pad->flags & MEDIA_PAD_FL_SINK) {
+ /* source pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR ||
+ sd->grp_id == GRP_ID_SENSOR)
+ return sd;
+ /* sink pad */
+ pad = &sd->entity.pads[0];
+ }
+ return NULL;
+}
+
static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output)
{
- struct fimc_pipeline *pipeline = &fimc->pipeline;
- struct v4l2_subdev *sensor;
- struct fimc_sensor_info *si;
+ struct fimc_source_info *si;
unsigned long flags;
- sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR];
-
- if (sensor == NULL)
+ if (fimc->sensor == NULL)
return -ENXIO;
- if (fimc->fmt == NULL)
+ if (fimc->inp_frame.fmt == NULL || fimc->out_frame.fmt == NULL)
return -EINVAL;
/* Get sensor configuration data from the sensor subdev */
- si = v4l2_get_subdev_hostdata(sensor);
+ si = v4l2_get_subdev_hostdata(fimc->sensor);
+ if (!si)
+ return -EINVAL;
+
spin_lock_irqsave(&fimc->slock, flags);
- flite_hw_set_camera_bus(fimc, &si->pdata);
+ flite_hw_set_camera_bus(fimc, si);
flite_hw_set_source_format(fimc, &fimc->inp_frame);
flite_hw_set_window_offset(fimc, &fimc->inp_frame);
flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output);
@@ -339,13 +373,13 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
const struct v4l2_pix_format_mplane *pixm = NULL;
struct fimc_lite *fimc = vq->drv_priv;
struct flite_frame *frame = &fimc->out_frame;
- const struct fimc_fmt *fmt = fimc->fmt;
+ const struct fimc_fmt *fmt = frame->fmt;
unsigned long wh;
int i;
if (pfmt) {
pixm = &pfmt->fmt.pix_mp;
- fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1);
+ fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1);
wh = pixm->width * pixm->height;
} else {
wh = frame->f_width * frame->f_height;
@@ -374,10 +408,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
struct fimc_lite *fimc = vq->drv_priv;
int i;
- if (fimc->fmt == NULL)
+ if (fimc->out_frame.fmt == NULL)
return -EINVAL;
- for (i = 0; i < fimc->fmt->memplanes; i++) {
+ for (i = 0; i < fimc->out_frame.fmt->memplanes; i++) {
unsigned long size = fimc->payload[i];
if (vb2_plane_size(vb, i) < size) {
@@ -425,24 +459,12 @@ static void buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&fimc->slock, flags);
}
-static void fimc_lock(struct vb2_queue *vq)
-{
- struct fimc_lite *fimc = vb2_get_drv_priv(vq);
- mutex_lock(&fimc->lock);
-}
-
-static void fimc_unlock(struct vb2_queue *vq)
-{
- struct fimc_lite *fimc = vb2_get_drv_priv(vq);
- mutex_unlock(&fimc->lock);
-}
-
static const struct vb2_ops fimc_lite_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = fimc_unlock,
- .wait_finish = fimc_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
@@ -467,99 +489,73 @@ static int fimc_lite_open(struct file *file)
mutex_lock(&fimc->lock);
if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) {
ret = -EBUSY;
- goto done;
+ goto unlock;
}
set_bit(ST_FLITE_IN_USE, &fimc->state);
ret = pm_runtime_get_sync(&fimc->pdev->dev);
if (ret < 0)
- goto done;
+ goto unlock;
ret = v4l2_fh_open(file);
if (ret < 0)
- goto done;
+ goto err_pm;
- if (++fimc->ref_count == 1 &&
- atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
- ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
- &fimc->vfd.entity, true);
- if (ret < 0) {
- pm_runtime_put_sync(&fimc->pdev->dev);
- fimc->ref_count--;
- v4l2_fh_release(file);
- clear_bit(ST_FLITE_IN_USE, &fimc->state);
- }
+ if (!v4l2_fh_is_singular_file(file) ||
+ atomic_read(&fimc->out_path) != FIMC_IO_DMA)
+ goto unlock;
+ ret = fimc_pipeline_call(fimc, open, &fimc->pipeline,
+ me, true);
+ if (!ret) {
fimc_lite_clear_event_counters(fimc);
+ fimc->ref_count++;
+ goto unlock;
}
-done:
+
+ v4l2_fh_release(file);
+err_pm:
+ pm_runtime_put_sync(&fimc->pdev->dev);
+ clear_bit(ST_FLITE_IN_USE, &fimc->state);
+unlock:
mutex_unlock(&fimc->lock);
mutex_unlock(&me->parent->graph_mutex);
return ret;
}
-static int fimc_lite_close(struct file *file)
+static int fimc_lite_release(struct file *file)
{
struct fimc_lite *fimc = video_drvdata(file);
- int ret;
mutex_lock(&fimc->lock);
- if (--fimc->ref_count == 0 &&
+ if (v4l2_fh_is_singular_file(file) &&
atomic_read(&fimc->out_path) == FIMC_IO_DMA) {
+ if (fimc->streaming) {
+ media_entity_pipeline_stop(&fimc->vfd.entity);
+ fimc->streaming = false;
+ }
clear_bit(ST_FLITE_IN_USE, &fimc->state);
fimc_lite_stop_capture(fimc, false);
fimc_pipeline_call(fimc, close, &fimc->pipeline);
- clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+ fimc->ref_count--;
}
+ vb2_fop_release(file);
pm_runtime_put(&fimc->pdev->dev);
+ clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
- if (fimc->ref_count == 0)
- vb2_queue_release(&fimc->vb_queue);
-
- ret = v4l2_fh_release(file);
-
- mutex_unlock(&fimc->lock);
- return ret;
-}
-
-static unsigned int fimc_lite_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct fimc_lite *fimc = video_drvdata(file);
- int ret;
-
- if (mutex_lock_interruptible(&fimc->lock))
- return POLL_ERR;
-
- ret = vb2_poll(&fimc->vb_queue, file, wait);
- mutex_unlock(&fimc->lock);
-
- return ret;
-}
-
-static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct fimc_lite *fimc = video_drvdata(file);
- int ret;
-
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
-
- ret = vb2_mmap(&fimc->vb_queue, vma);
mutex_unlock(&fimc->lock);
-
- return ret;
+ return 0;
}
static const struct v4l2_file_operations fimc_lite_fops = {
.owner = THIS_MODULE,
.open = fimc_lite_open,
- .release = fimc_lite_close,
- .poll = fimc_lite_poll,
+ .release = fimc_lite_release,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = fimc_lite_mmap,
+ .mmap = vb2_fop_mmap,
};
/*
@@ -570,10 +566,23 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
u32 *width, u32 *height,
u32 *code, u32 *fourcc, int pad)
{
- struct flite_variant *variant = fimc->variant;
+ struct flite_drvdata *dd = fimc->dd;
const struct fimc_fmt *fmt;
+ unsigned int flags = 0;
- fmt = fimc_lite_find_format(fourcc, code, 0);
+ if (pad == FLITE_SD_PAD_SINK) {
+ v4l_bound_align_image(width, 8, dd->max_width,
+ ffs(dd->out_width_align) - 1,
+ height, 0, dd->max_height, 0, 0);
+ } else {
+ v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
+ ffs(dd->out_width_align) - 1,
+ height, 0, fimc->inp_frame.rect.height,
+ 0, 0);
+ flags = fimc->inp_frame.fmt->flags;
+ }
+
+ fmt = fimc_lite_find_format(fourcc, code, flags, 0);
if (WARN_ON(!fmt))
return NULL;
@@ -582,17 +591,6 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
if (fourcc)
*fourcc = fmt->fourcc;
- if (pad == FLITE_SD_PAD_SINK) {
- v4l_bound_align_image(width, 8, variant->max_width,
- ffs(variant->out_width_align) - 1,
- height, 0, variant->max_height, 0, 0);
- } else {
- v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
- ffs(variant->out_width_align) - 1,
- height, 0, fimc->inp_frame.rect.height,
- 0, 0);
- }
-
v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
code ? *code : 0, *width, *height);
@@ -608,7 +606,7 @@ static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
/* Adjust left/top if cropping rectangle got out of bounds */
r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
- r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
+ r->left = round_down(r->left, fimc->dd->win_hor_offs_align);
r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height);
v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n",
@@ -628,7 +626,7 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
/* Adjust left/top if the composing rectangle got out of bounds */
r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
- r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
+ r->left = round_down(r->left, fimc->dd->out_hor_offs_align);
r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n",
@@ -671,7 +669,7 @@ static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0];
struct flite_frame *frame = &fimc->out_frame;
- const struct fimc_fmt *fmt = fimc->fmt;
+ const struct fimc_fmt *fmt = frame->fmt;
plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8;
plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height;
@@ -689,18 +687,31 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc,
struct v4l2_pix_format_mplane *pixm,
const struct fimc_fmt **ffmt)
{
- struct flite_variant *variant = fimc->variant;
u32 bpl = pixm->plane_fmt[0].bytesperline;
+ struct flite_drvdata *dd = fimc->dd;
+ const struct fimc_fmt *inp_fmt = fimc->inp_frame.fmt;
const struct fimc_fmt *fmt;
- fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0);
+ if (WARN_ON(inp_fmt == NULL))
+ return -EINVAL;
+ /*
+ * We allow some flexibility only for YUV formats. In case of raw
+ * raw Bayer the FIMC-LITE's output format must match its camera
+ * interface input format.
+ */
+ if (inp_fmt->flags & FMT_FLAGS_YUV)
+ fmt = fimc_lite_find_format(&pixm->pixelformat, NULL,
+ inp_fmt->flags, 0);
+ else
+ fmt = inp_fmt;
+
if (WARN_ON(fmt == NULL))
return -EINVAL;
if (ffmt)
*ffmt = fmt;
- v4l_bound_align_image(&pixm->width, 8, variant->max_width,
- ffs(variant->out_width_align) - 1,
- &pixm->height, 0, variant->max_height, 0, 0);
+ v4l_bound_align_image(&pixm->width, 8, dd->max_width,
+ ffs(dd->out_width_align) - 1,
+ &pixm->height, 0, dd->max_height, 0, 0);
if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width))
pixm->plane_fmt[0].bytesperline = (pixm->width *
@@ -720,7 +731,6 @@ static int fimc_lite_try_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct fimc_lite *fimc = video_drvdata(file);
-
return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL);
}
@@ -740,7 +750,7 @@ static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
if (ret < 0)
return ret;
- fimc->fmt = fmt;
+ frame->fmt = fmt;
fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
pixm->plane_fmt[0].sizeimage);
frame->f_width = pixm->width;
@@ -766,7 +776,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
struct flite_frame *ff = &fimc->out_frame;
sink_fmt.format.width = ff->f_width;
sink_fmt.format.height = ff->f_height;
- sink_fmt.format.code = fimc->fmt->mbus_code;
+ sink_fmt.format.code = fimc->inp_frame.fmt->mbus_code;
} else {
sink_fmt.pad = pad->index;
sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -800,37 +810,47 @@ static int fimc_lite_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_lite *fimc = video_drvdata(file);
- struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
+ struct media_entity *entity = &fimc->vfd.entity;
struct fimc_pipeline *p = &fimc->pipeline;
int ret;
if (fimc_lite_active(fimc))
return -EBUSY;
- ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+ ret = media_entity_pipeline_start(entity, p->m_pipeline);
if (ret < 0)
return ret;
ret = fimc_pipeline_validate(fimc);
- if (ret) {
- media_entity_pipeline_stop(&sensor->entity);
+ if (ret < 0)
+ goto err_p_stop;
+
+ fimc->sensor = __find_remote_sensor(&fimc->subdev.entity);
+
+ ret = vb2_ioctl_streamon(file, priv, type);
+ if (!ret) {
+ fimc->streaming = true;
return ret;
}
- return vb2_streamon(&fimc->vb_queue, type);
+err_p_stop:
+ media_entity_pipeline_stop(entity);
+ return 0;
}
static int fimc_lite_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_lite *fimc = video_drvdata(file);
- struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
int ret;
- ret = vb2_streamoff(&fimc->vb_queue, type);
- if (ret == 0)
- media_entity_pipeline_stop(&sd->entity);
- return ret;
+ ret = vb2_ioctl_streamoff(file, priv, type);
+ if (ret < 0)
+ return ret;
+
+ media_entity_pipeline_stop(&fimc->vfd.entity);
+ fimc->streaming = false;
+ return 0;
}
static int fimc_lite_reqbufs(struct file *file, void *priv,
@@ -840,53 +860,13 @@ static int fimc_lite_reqbufs(struct file *file, void *priv,
int ret;
reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count);
- ret = vb2_reqbufs(&fimc->vb_queue, reqbufs);
+ ret = vb2_ioctl_reqbufs(file, priv, reqbufs);
if (!ret)
fimc->reqbufs_count = reqbufs->count;
return ret;
}
-static int fimc_lite_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_lite *fimc = video_drvdata(file);
-
- return vb2_querybuf(&fimc->vb_queue, buf);
-}
-
-static int fimc_lite_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_lite *fimc = video_drvdata(file);
-
- return vb2_qbuf(&fimc->vb_queue, buf);
-}
-
-static int fimc_lite_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct fimc_lite *fimc = video_drvdata(file);
-
- return vb2_dqbuf(&fimc->vb_queue, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int fimc_lite_create_bufs(struct file *file, void *priv,
- struct v4l2_create_buffers *create)
-{
- struct fimc_lite *fimc = video_drvdata(file);
-
- return vb2_create_bufs(&fimc->vb_queue, create);
-}
-
-static int fimc_lite_prepare_buf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct fimc_lite *fimc = video_drvdata(file);
-
- return vb2_prepare_buf(&fimc->vb_queue, b);
-}
-
/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
{
@@ -966,38 +946,15 @@ static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
.vidioc_g_selection = fimc_lite_g_selection,
.vidioc_s_selection = fimc_lite_s_selection,
.vidioc_reqbufs = fimc_lite_reqbufs,
- .vidioc_querybuf = fimc_lite_querybuf,
- .vidioc_prepare_buf = fimc_lite_prepare_buf,
- .vidioc_create_bufs = fimc_lite_create_bufs,
- .vidioc_qbuf = fimc_lite_qbuf,
- .vidioc_dqbuf = fimc_lite_dqbuf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = fimc_lite_streamon,
.vidioc_streamoff = fimc_lite_streamoff,
};
-/* Called with the media graph mutex held */
-static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me)
-{
- struct media_pad *pad = &me->pads[0];
- struct v4l2_subdev *sd;
-
- while (pad->flags & MEDIA_PAD_FL_SINK) {
- /* source pad */
- pad = media_entity_remote_source(pad);
- if (pad == NULL ||
- media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
- break;
-
- sd = media_entity_to_v4l2_subdev(pad->entity);
-
- if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR)
- return sd;
- /* sink pad */
- pad = &sd->entity.pads[0];
- }
- return NULL;
-}
-
/* Capture subdev media entity operations */
static int fimc_lite_link_setup(struct media_entity *entity,
const struct media_pad *local,
@@ -1072,7 +1029,7 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
{
const struct fimc_fmt *fmt;
- fmt = fimc_lite_find_format(NULL, NULL, code->index);
+ fmt = fimc_lite_find_format(NULL, NULL, 0, code->index);
if (!fmt)
return -EINVAL;
code->code = fmt->mbus_code;
@@ -1085,7 +1042,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
{
struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf = &fmt->format;
- struct flite_frame *f = &fimc->out_frame;
+ struct flite_frame *f = &fimc->inp_frame;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
mf = v4l2_subdev_get_try_format(fh, fmt->pad);
@@ -1095,7 +1052,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&fimc->lock);
- mf->code = fimc->fmt->mbus_code;
+ mf->code = f->fmt->mbus_code;
if (fmt->pad == FLITE_SD_PAD_SINK) {
/* full camera input frame size */
@@ -1147,7 +1104,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
if (fmt->pad == FLITE_SD_PAD_SINK) {
sink->f_width = mf->width;
sink->f_height = mf->height;
- fimc->fmt = ffmt;
+ sink->fmt = ffmt;
/* Set sink crop rectangle */
sink->rect.width = mf->width;
sink->rect.height = mf->height;
@@ -1159,7 +1116,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
source->f_height = mf->height;
} else {
/* Allow changing format only on sink pad */
- mf->code = fimc->fmt->mbus_code;
+ mf->code = sink->fmt->mbus_code;
mf->width = sink->rect.width;
mf->height = sink->rect.height;
}
@@ -1300,7 +1257,8 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
memset(vfd, 0, sizeof(*vfd));
- fimc->fmt = &fimc_lite_formats[0];
+ fimc->inp_frame.fmt = &fimc_lite_formats[0];
+ fimc->out_frame.fmt = &fimc_lite_formats[0];
atomic_set(&fimc->out_path, FIMC_IO_DMA);
snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
@@ -1311,8 +1269,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
vfd->v4l2_dev = sd->v4l2_dev;
vfd->minor = -1;
vfd->release = video_device_release_empty;
- vfd->lock = &fimc->lock;
- fimc->ref_count = 0;
+ vfd->queue = q;
fimc->reqbufs_count = 0;
INIT_LIST_HEAD(&fimc->pending_buf_q);
@@ -1325,6 +1282,8 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct flite_buffer);
q->drv_priv = fimc;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &fimc->lock;
ret = vb2_queue_init(q);
if (ret < 0)
@@ -1408,6 +1367,7 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = {
.id = V4L2_CTRL_CLASS_USER | 0x1001,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Test Pattern 640x480",
+ .step = 1,
};
static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
@@ -1417,7 +1377,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
int ret;
v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
@@ -1439,6 +1399,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
sd->ctrl_handler = handler;
sd->internal_ops = &fimc_lite_subdev_internal_ops;
sd->entity.ops = &fimc_lite_subdev_media_ops;
+ sd->owner = THIS_MODULE;
v4l2_set_subdevdata(sd, fimc);
return 0;
@@ -1480,19 +1441,35 @@ static int fimc_lite_clk_get(struct fimc_lite *fimc)
return ret;
}
+static const struct of_device_id flite_of_match[];
+
static int fimc_lite_probe(struct platform_device *pdev)
{
- struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
+ struct flite_drvdata *drv_data = NULL;
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id;
struct fimc_lite *fimc;
struct resource *res;
int ret;
- fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+ fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL);
if (!fimc)
return -ENOMEM;
- fimc->index = pdev->id;
- fimc->variant = drv_data->variant[fimc->index];
+ if (dev->of_node) {
+ of_id = of_match_node(flite_of_match, dev->of_node);
+ if (of_id)
+ drv_data = (struct flite_drvdata *)of_id->data;
+ fimc->index = of_alias_get_id(dev->of_node, "fimc-lite");
+ } else {
+ drv_data = fimc_lite_get_drvdata(pdev);
+ fimc->index = pdev->id;
+ }
+
+ if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS)
+ return -EINVAL;
+
+ fimc->dd = drv_data;
fimc->pdev = pdev;
init_waitqueue_head(&fimc->irq_queue);
@@ -1500,13 +1477,13 @@ static int fimc_lite_probe(struct platform_device *pdev)
mutex_init(&fimc->lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fimc->regs = devm_ioremap_resource(&pdev->dev, res);
+ fimc->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(fimc->regs))
return PTR_ERR(fimc->regs);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
- dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+ dev_err(dev, "Failed to get IRQ resource\n");
return -ENXIO;
}
@@ -1514,10 +1491,10 @@ static int fimc_lite_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler,
- 0, dev_name(&pdev->dev), fimc);
+ ret = devm_request_irq(dev, res->start, flite_irq_handler,
+ 0, dev_name(dev), fimc);
if (ret) {
- dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+ dev_err(dev, "Failed to install irq (%d)\n", ret);
goto err_clk;
}
@@ -1527,23 +1504,23 @@ static int fimc_lite_probe(struct platform_device *pdev)
goto err_clk;
platform_set_drvdata(pdev, fimc);
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_sd;
- fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
goto err_pm;
}
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put(dev);
- dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n",
+ dev_dbg(dev, "FIMC-LITE.%d registered successfully\n",
fimc->index);
return 0;
err_pm:
- pm_runtime_put(&pdev->dev);
+ pm_runtime_put(dev);
err_sd:
fimc_lite_unregister_capture_subdev(fimc);
err_clk:
@@ -1634,7 +1611,14 @@ static int fimc_lite_remove(struct platform_device *pdev)
return 0;
}
-static struct flite_variant fimc_lite0_variant_exynos4 = {
+static const struct dev_pm_ops fimc_lite_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
+ SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
+ NULL)
+};
+
+/* EXYNOS4212, EXYNOS4412 */
+static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
.max_width = 8192,
.max_height = 8192,
.out_width_align = 8,
@@ -1642,14 +1626,6 @@ static struct flite_variant fimc_lite0_variant_exynos4 = {
.out_hor_offs_align = 8,
};
-/* EXYNOS4212, EXYNOS4412 */
-static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
- .variant = {
- [0] = &fimc_lite0_variant_exynos4,
- [1] = &fimc_lite0_variant_exynos4,
- },
-};
-
static struct platform_device_id fimc_lite_driver_ids[] = {
{
.name = "exynos-fimc-lite",
@@ -1659,17 +1635,21 @@ static struct platform_device_id fimc_lite_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
-static const struct dev_pm_ops fimc_lite_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
- SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
- NULL)
+static const struct of_device_id flite_of_match[] = {
+ {
+ .compatible = "samsung,exynos4212-fimc-lite",
+ .data = &fimc_lite_drvdata_exynos4,
+ },
+ { /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, flite_of_match);
static struct platform_driver fimc_lite_driver = {
.probe = fimc_lite_probe,
.remove = fimc_lite_remove,
.id_table = fimc_lite_driver_ids,
.driver = {
+ .of_match_table = flite_of_match,
.name = FIMC_LITE_DRV_NAME,
.owner = THIS_MODULE,
.pm = &fimc_lite_pm_ops,
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index 7085761f8c4b..47da5e049247 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -20,12 +20,11 @@
#include <media/media-entity.h>
#include <media/videobuf2-core.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
#include <media/s5p_fimc.h>
-#include "fimc-core.h"
-
#define FIMC_LITE_DRV_NAME "exynos-fimc-lite"
#define FLITE_CLK_NAME "flite"
#define FIMC_LITE_MAX_DEVS 2
@@ -49,7 +48,7 @@ enum {
#define FLITE_SD_PAD_SOURCE_ISP 2
#define FLITE_SD_PADS_NUM 3
-struct flite_variant {
+struct flite_drvdata {
unsigned short max_width;
unsigned short max_height;
unsigned short out_width_align;
@@ -57,10 +56,6 @@ struct flite_variant {
unsigned short out_hor_offs_align;
};
-struct flite_drvdata {
- struct flite_variant *variant[FIMC_LITE_MAX_DEVS];
-};
-
#define fimc_lite_get_drvdata(_pdev) \
((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
@@ -75,11 +70,13 @@ struct fimc_lite_events {
* @f_width: full pixel width
* @f_height: full pixel height
* @rect: crop/composition rectangle
+ * @fmt: pointer to pixel format description data structure
*/
struct flite_frame {
u16 f_width;
u16 f_height;
struct v4l2_rect rect;
+ const struct fimc_fmt *fmt;
};
/**
@@ -97,7 +94,7 @@ struct flite_buffer {
/**
* struct fimc_lite - fimc lite structure
* @pdev: pointer to FIMC-LITE platform device
- * @variant: variant information for this IP
+ * @dd: SoC specific driver data structure
* @v4l2_dev: pointer to top the level v4l2_device
* @vfd: video device node
* @fh: v4l2 file handle
@@ -116,7 +113,6 @@ struct flite_buffer {
* @clock: FIMC-LITE gate clock
* @regs: memory mapped io registers
* @irq_queue: interrupt handler waitqueue
- * @fmt: pointer to color format description structure
* @payload: image size in bytes (w x h x bpp)
* @inp_frame: camera input frame structure
* @out_frame: DMA output frame structure
@@ -133,7 +129,7 @@ struct flite_buffer {
*/
struct fimc_lite {
struct platform_device *pdev;
- struct flite_variant *variant;
+ struct flite_drvdata *dd;
struct v4l2_device *v4l2_dev;
struct video_device vfd;
struct v4l2_fh fh;
@@ -144,7 +140,7 @@ struct fimc_lite {
struct v4l2_subdev *sensor;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *test_pattern;
- u32 index;
+ int index;
struct fimc_pipeline pipeline;
const struct fimc_pipeline_ops *pipeline_ops;
@@ -155,7 +151,6 @@ struct fimc_lite {
void __iomem *regs;
wait_queue_head_t irq_queue;
- const struct fimc_fmt *fmt;
unsigned long payload[FLITE_MAX_PLANES];
struct flite_frame inp_frame;
struct flite_frame out_frame;
@@ -171,6 +166,7 @@ struct fimc_lite {
int ref_count;
struct fimc_lite_events events;
+ bool streaming;
};
static inline bool fimc_lite_active(struct fimc_lite *fimc)
diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index f3d535cdd87f..bde1f47f7ed3 100644
--- a/drivers/media/platform/s5p-fimc/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -29,8 +29,7 @@
#include "fimc-core.h"
#include "fimc-reg.h"
-#include "fimc-mdevice.h"
-
+#include "media-dev.h"
static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
{
@@ -100,7 +99,7 @@ static int stop_streaming(struct vb2_queue *q)
static void fimc_device_run(void *priv)
{
- struct vb2_buffer *vb = NULL;
+ struct vb2_buffer *src_vb, *dst_vb;
struct fimc_ctx *ctx = priv;
struct fimc_frame *sf, *df;
struct fimc_dev *fimc;
@@ -123,16 +122,18 @@ static void fimc_device_run(void *priv)
fimc_prepare_dma_offset(ctx, df);
}
- vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr);
+ src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
if (ret)
goto dma_unlock;
- vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, df, &df->paddr);
+ dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
if (ret)
goto dma_unlock;
+ dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp;
+
/* Reconfigure hardware if the context has changed. */
if (fimc->m2m.ctx != ctx) {
ctx->state |= FIMC_PARAMS;
@@ -152,7 +153,7 @@ static void fimc_device_run(void *priv)
fimc_hw_set_rotation(ctx);
fimc_hw_set_effect(ctx);
fimc_hw_set_out_dma(ctx);
- if (fimc->variant->has_alpha)
+ if (fimc->drv_data->alpha_color)
fimc_hw_set_rgb_alpha(ctx);
fimc_hw_set_output_path(ctx);
}
@@ -250,22 +251,20 @@ static struct vb2_ops fimc_qops = {
* V4L2 ioctl handlers
*/
static int fimc_m2m_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
+ struct v4l2_capability *cap)
{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_dev *fimc = video_drvdata(file);
+ unsigned int caps;
- strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
* and are scheduled for removal.
*/
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
+ caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps);
return 0;
}
@@ -623,6 +622,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &fimc_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -634,6 +634,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &fimc_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -667,16 +668,15 @@ static int fimc_m2m_open(struct file *file)
struct fimc_ctx *ctx;
int ret = -EBUSY;
- dbg("pid: %d, state: 0x%lx, refcnt: %d",
- task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+ pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state);
if (mutex_lock_interruptible(&fimc->lock))
return -ERESTARTSYS;
/*
- * Return if the corresponding video capture node
- * is already opened.
+ * Don't allow simultaneous open() of the mem-to-mem and the
+ * capture video node that belong to same FIMC IP instance.
*/
- if (fimc->vid_cap.refcnt > 0)
+ if (test_bit(ST_CAPT_BUSY, &fimc->state))
goto unlock;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index 50b97c75b956..f079f36099de 100644
--- a/drivers/media/platform/s5p-fimc/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -1,22 +1,24 @@
/*
* Register interface file for Samsung Camera Interface (FIMC) driver
*
- * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
- * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+
#include <media/s5p_fimc.h>
+#include "media-dev.h"
#include "fimc-reg.h"
#include "fimc-core.h"
-
void fimc_hw_reset(struct fimc_dev *dev)
{
u32 cfg;
@@ -35,7 +37,7 @@ void fimc_hw_reset(struct fimc_dev *dev)
cfg &= ~FIMC_REG_CIGCTRL_SWRST;
writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
- if (dev->variant->out_buf_count > 4)
+ if (dev->drv_data->out_buf_count > 4)
fimc_hw_set_dma_seq(dev, 0xF);
}
@@ -447,7 +449,8 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
| FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK
| FIMC_REG_MSCTRL_INPUT_MASK
| FIMC_REG_MSCTRL_C_INT_IN_MASK
- | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK);
+ | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK
+ | FIMC_REG_MSCTRL_ORDER422_MASK);
cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)
| FIMC_REG_MSCTRL_INPUT_MEMORY
@@ -598,7 +601,8 @@ static const struct mbus_pixfmt_desc pix_desc[] = {
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
struct fimc_source_info *source)
{
- struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+ struct fimc_vid_cap *vc = &fimc->vid_cap;
+ struct fimc_frame *f = &vc->ctx->s_frame;
u32 bus_width, cfg = 0;
int i;
@@ -606,7 +610,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
case FIMC_BUS_TYPE_ITU_601:
case FIMC_BUS_TYPE_ITU_656:
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
- if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
+ if (vc->ci_fmt.code == pix_desc[i].pixelcode) {
cfg = pix_desc[i].cisrcfmt;
bus_width = pix_desc[i].bus_width;
break;
@@ -614,9 +618,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
}
if (i == ARRAY_SIZE(pix_desc)) {
- v4l2_err(&fimc->vid_cap.vfd,
+ v4l2_err(&vc->vfd,
"Camera color format not supported: %d\n",
- fimc->vid_cap.mf.code);
+ vc->ci_fmt.code);
return -EINVAL;
}
@@ -631,6 +635,10 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
if (fimc_fmt_is_user_defined(f->fmt->color))
cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
break;
+ default:
+ case FIMC_BUS_TYPE_ISP_WRITEBACK:
+ /* Anything to do here ? */
+ break;
}
cfg |= (f->o_width << 16) | f->o_height;
@@ -660,16 +668,17 @@ void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
struct fimc_source_info *source)
{
- u32 cfg, tmp;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
u32 csis_data_alignment = 32;
+ u32 cfg, tmp;
cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
/* Select ITU B interface, disable Writeback path and test pattern. */
cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
- FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
+ FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG |
+ FIMC_REG_CIGCTRL_SELWB_A);
switch (source->fimc_bus_type) {
case FIMC_BUS_TYPE_MIPI_CSI2:
@@ -679,7 +688,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
- switch (vid_cap->mf.code) {
+ switch (vid_cap->ci_fmt.code) {
case V4L2_MBUS_FMT_VYUY8_2X8:
tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
break;
@@ -691,7 +700,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
default:
v4l2_err(&vid_cap->vfd,
"Not supported camera pixel format: %#x\n",
- vid_cap->mf.code);
+ vid_cap->ci_fmt.code);
return -EINVAL;
}
tmp |= (csis_data_alignment == 32) << 8;
@@ -704,6 +713,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
break;
case FIMC_BUS_TYPE_LCD_WRITEBACK_A:
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
+ /* fall through */
+ case FIMC_BUS_TYPE_ISP_WRITEBACK:
+ if (fimc->variant->has_isp_wb)
+ cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
+ else
+ WARN_ONCE(1, "ISP Writeback input is not supported\n");
break;
default:
v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n",
@@ -747,7 +762,7 @@ s32 fimc_hw_get_frame_index(struct fimc_dev *dev)
{
s32 reg;
- if (dev->variant->has_cistatus2) {
+ if (dev->drv_data->cistatus2) {
reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f;
return reg - 1;
}
@@ -763,7 +778,7 @@ s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev)
{
s32 reg;
- if (!dev->variant->has_cistatus2)
+ if (!dev->drv_data->cistatus2)
return -1;
reg = readl(dev->regs + FIMC_REG_CISTATUS2);
@@ -784,3 +799,43 @@ void fimc_deactivate_capture(struct fimc_dev *fimc)
fimc_hw_enable_scaler(fimc, false);
fimc_hw_en_lastirq(fimc, false);
}
+
+int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc)
+{
+ struct regmap *map = fimc->sysreg;
+ unsigned int mask, val, camblk_cfg;
+ int ret;
+
+ if (map == NULL)
+ return 0;
+
+ ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg);
+ if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3))
+ return ret;
+
+ if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id))
+ val = 0x1 << (fimc->id + 20);
+ else
+ val = 0;
+
+ mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN;
+ ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ val |= SYSREG_CAMBLK_FIFORST_ISP;
+ ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val);
+ if (ret < 0)
+ return ret;
+
+ mask = SYSREG_ISPBLK_FIFORST_CAM_BLK;
+ ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask);
+ if (ret < 0)
+ return ret;
+
+ usleep_range(1000, 2000);
+
+ return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h
index 1a40df6d1a80..6c97798c75a5 100644
--- a/drivers/media/platform/s5p-fimc/fimc-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-reg.h
@@ -52,6 +52,8 @@
#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19)
#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16)
#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12)
+/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */
+#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10)
#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8)
#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7)
#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6)
@@ -93,10 +95,10 @@
/* Output DMA control */
#define FIMC_REG_CIOCTRL 0x4c
#define FIMC_REG_CIOCTRL_ORDER422_MASK (3 << 0)
-#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (0 << 0)
-#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (1 << 0)
-#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (2 << 0)
-#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (3 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (0 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (1 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (2 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (3 << 0)
#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
#define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3)
#define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3)
@@ -218,10 +220,10 @@
#define FIMC_REG_MSCTRL_FLIP_180 (3 << 13)
#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12)
#define FIMC_REG_MSCTRL_ORDER422_SHIFT 4
-#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (0 << 4)
-#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (1 << 4)
-#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (2 << 4)
-#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (3 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (0 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (1 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (2 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (3 << 4)
#define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4)
#define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3)
#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3)
@@ -276,6 +278,14 @@
/* Output frame buffer sequence mask */
#define FIMC_REG_CIFCNTSEQ 0x1fc
+/* SYSREG ISP Writeback register address offsets */
+#define SYSREG_ISPBLK 0x020c
+#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7)
+
+#define SYSREG_CAMBLK 0x0218
+#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15)
+#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20)
+
/*
* Function declarations
*/
@@ -309,6 +319,7 @@ void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
void fimc_hw_disable_capture(struct fimc_dev *dev);
s32 fimc_hw_get_frame_index(struct fimc_dev *dev);
s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev);
+int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc);
void fimc_activate_capture(struct fimc_ctx *ctx);
void fimc_deactivate_capture(struct fimc_dev *fimc);
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/exynos4-is/media-dev.c
index a17fcb2d5d41..15ef8f28239b 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -17,32 +17,37 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-of.h>
#include <media/media-device.h>
#include <media/s5p_fimc.h>
+#include "media-dev.h"
#include "fimc-core.h"
+#include "fimc-is.h"
#include "fimc-lite.h"
-#include "fimc-mdevice.h"
#include "mipi-csis.h"
static int __fimc_md_set_camclk(struct fimc_md *fmd,
- struct fimc_sensor_info *s_info,
+ struct fimc_source_info *si,
bool on);
/**
* fimc_pipeline_prepare - update pipeline information with subdevice pointers
- * @fimc: fimc device terminating the pipeline
+ * @me: media entity terminating the pipeline
*
* Caller holds the graph mutex.
*/
static void fimc_pipeline_prepare(struct fimc_pipeline *p,
struct media_entity *me)
{
- struct media_pad *pad = &me->pads[0];
struct v4l2_subdev *sd;
int i;
@@ -50,15 +55,21 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
p->subdevs[i] = NULL;
while (1) {
- if (!(pad->flags & MEDIA_PAD_FL_SINK))
- break;
+ struct media_pad *pad = NULL;
+
+ /* Find remote source pad */
+ for (i = 0; i < me->num_pads; i++) {
+ struct media_pad *spad = &me->pads[i];
+ if (!(spad->flags & MEDIA_PAD_FL_SINK))
+ continue;
+ pad = media_entity_remote_source(spad);
+ if (pad)
+ break;
+ }
- /* source pad */
- pad = media_entity_remote_source(pad);
if (pad == NULL ||
media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
-
sd = media_entity_to_v4l2_subdev(pad->entity);
switch (sd->grp_id) {
@@ -75,12 +86,15 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
case GRP_ID_FIMC:
/* No need to control FIMC subdev through subdev ops */
break;
+ case GRP_ID_FIMC_IS:
+ p->subdevs[IDX_IS_ISP] = sd;
+ break;
default:
- pr_warn("%s: Unknown subdev grp_id: %#x\n",
- __func__, sd->grp_id);
+ break;
}
- /* sink pad */
- pad = &sd->entity.pads[0];
+ me = &sd->entity;
+ if (me->num_pads == 1)
+ break;
}
}
@@ -117,49 +131,81 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on)
*
* Needs to be called with the graph mutex held.
*/
-static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
+static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool on)
{
- unsigned int i;
- int ret;
+ static const u8 seq[2][IDX_MAX - 1] = {
+ { IDX_IS_ISP, IDX_SENSOR, IDX_CSIS, IDX_FLITE },
+ { IDX_CSIS, IDX_FLITE, IDX_SENSOR, IDX_IS_ISP },
+ };
+ int i, ret = 0;
if (p->subdevs[IDX_SENSOR] == NULL)
return -ENXIO;
- for (i = 0; i < IDX_MAX; i++) {
- unsigned int idx = state ? (IDX_MAX - 1) - i : i;
+ for (i = 0; i < IDX_MAX - 1; i++) {
+ unsigned int idx = seq[on][i];
+
+ ret = __subdev_set_power(p->subdevs[idx], on);
+
- ret = __subdev_set_power(p->subdevs[idx], state);
if (ret < 0 && ret != -ENXIO)
- return ret;
+ goto error;
}
-
return 0;
+error:
+ for (; i >= 0; i--) {
+ unsigned int idx = seq[on][i];
+ __subdev_set_power(p->subdevs[idx], !on);
+ }
+ return ret;
}
/**
* __fimc_pipeline_open - update the pipeline information, enable power
* of all pipeline subdevs and the sensor clock
* @me: media entity to start graph walk with
- * @prep: true to acquire sensor (and csis) subdevs
+ * @prepare: true to walk the current pipeline and acquire all subdevs
*
* Called with the graph mutex held.
*/
static int __fimc_pipeline_open(struct fimc_pipeline *p,
- struct media_entity *me, bool prep)
+ struct media_entity *me, bool prepare)
{
+ struct fimc_md *fmd = entity_to_fimc_mdev(me);
+ struct v4l2_subdev *sd;
int ret;
- if (prep)
+ if (WARN_ON(p == NULL || me == NULL))
+ return -EINVAL;
+
+ if (prepare)
fimc_pipeline_prepare(p, me);
- if (p->subdevs[IDX_SENSOR] == NULL)
+ sd = p->subdevs[IDX_SENSOR];
+ if (sd == NULL)
return -EINVAL;
- ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
- if (ret)
- return ret;
+ /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
+ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) {
+ ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]);
+ if (ret < 0)
+ return ret;
+ }
+ ret = fimc_md_set_camclk(sd, true);
+ if (ret < 0)
+ goto err_wbclk;
+
+ ret = fimc_pipeline_s_power(p, 1);
+ if (!ret)
+ return 0;
- return fimc_pipeline_s_power(p, 1);
+ fimc_md_set_camclk(sd, false);
+
+err_wbclk:
+ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
+ clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
+
+ return ret;
}
/**
@@ -170,41 +216,58 @@ static int __fimc_pipeline_open(struct fimc_pipeline *p,
*/
static int __fimc_pipeline_close(struct fimc_pipeline *p)
{
+ struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL;
+ struct fimc_md *fmd;
int ret = 0;
- if (!p || !p->subdevs[IDX_SENSOR])
+ if (WARN_ON(sd == NULL))
return -EINVAL;
if (p->subdevs[IDX_SENSOR]) {
ret = fimc_pipeline_s_power(p, 0);
- fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
+ fimc_md_set_camclk(sd, false);
}
+
+ fmd = entity_to_fimc_mdev(&sd->entity);
+
+ /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */
+ if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
+ clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
+
return ret == -ENXIO ? 0 : ret;
}
/**
- * __fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
+ * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs
* @pipeline: video pipeline structure
- * @on: passed as the s_stream call argument
+ * @on: passed as the s_stream() callback argument
*/
static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
{
- int i, ret;
+ static const u8 seq[2][IDX_MAX] = {
+ { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE },
+ { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
+ };
+ int i, ret = 0;
if (p->subdevs[IDX_SENSOR] == NULL)
return -ENODEV;
for (i = 0; i < IDX_MAX; i++) {
- unsigned int idx = on ? (IDX_MAX - 1) - i : i;
+ unsigned int idx = seq[on][i];
ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
- return ret;
+ goto error;
}
-
return 0;
-
+error:
+ for (; i >= 0; i--) {
+ unsigned int idx = seq[on][i];
+ v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on);
+ }
+ return ret;
}
/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */
@@ -218,35 +281,40 @@ static const struct fimc_pipeline_ops fimc_pipeline_ops = {
* Sensor subdevice helper functions
*/
static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
- struct fimc_sensor_info *s_info)
+ struct fimc_source_info *si)
{
struct i2c_adapter *adapter;
struct v4l2_subdev *sd = NULL;
- if (!s_info || !fmd)
+ if (!si || !fmd)
return NULL;
+ /*
+ * If FIMC bus type is not Writeback FIFO assume it is same
+ * as sensor_bus_type.
+ */
+ si->fimc_bus_type = si->sensor_bus_type;
- adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num);
+ adapter = i2c_get_adapter(si->i2c_bus_num);
if (!adapter) {
v4l2_warn(&fmd->v4l2_dev,
"Failed to get I2C adapter %d, deferring probe\n",
- s_info->pdata.i2c_bus_num);
+ si->i2c_bus_num);
return ERR_PTR(-EPROBE_DEFER);
}
sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
- s_info->pdata.board_info, NULL);
+ si->board_info, NULL);
if (IS_ERR_OR_NULL(sd)) {
i2c_put_adapter(adapter);
v4l2_warn(&fmd->v4l2_dev,
"Failed to acquire subdev %s, deferring probe\n",
- s_info->pdata.board_info->type);
+ si->board_info->type);
return ERR_PTR(-EPROBE_DEFER);
}
- v4l2_set_subdev_hostdata(sd, s_info);
+ v4l2_set_subdev_hostdata(sd, si);
sd->grp_id = GRP_ID_SENSOR;
v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
- s_info->pdata.board_info->type);
+ sd->name);
return sd;
}
@@ -257,57 +325,262 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
if (!client)
return;
+
v4l2_device_unregister_subdev(sd);
- adapter = client->adapter;
- i2c_unregister_device(client);
- if (adapter)
- i2c_put_adapter(adapter);
+
+ if (!client->dev.of_node) {
+ adapter = client->adapter;
+ i2c_unregister_device(client);
+ if (adapter)
+ i2c_put_adapter(adapter);
+ }
}
+#ifdef CONFIG_OF
+/* Register I2C client subdev associated with @node. */
+static int fimc_md_of_add_sensor(struct fimc_md *fmd,
+ struct device_node *node, int index)
+{
+ struct fimc_sensor_info *si;
+ struct i2c_client *client;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
+ return -EINVAL;
+ si = &fmd->sensor[index];
+
+ client = of_find_i2c_device_by_node(node);
+ if (!client)
+ return -EPROBE_DEFER;
+
+ device_lock(&client->dev);
+
+ if (!client->driver ||
+ !try_module_get(client->driver->driver.owner)) {
+ ret = -EPROBE_DEFER;
+ v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n",
+ node->full_name);
+ goto dev_put;
+ }
+
+ /* Enable sensor's master clock */
+ ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
+ if (ret < 0)
+ goto mod_put;
+ sd = i2c_get_clientdata(client);
+
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ __fimc_md_set_camclk(fmd, &si->pdata, false);
+ if (ret < 0)
+ goto mod_put;
+
+ v4l2_set_subdev_hostdata(sd, &si->pdata);
+ if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
+ sd->grp_id = GRP_ID_FIMC_IS_SENSOR;
+ else
+ sd->grp_id = GRP_ID_SENSOR;
+
+ si->subdev = sd;
+ v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
+ sd->name, fmd->num_sensors);
+ fmd->num_sensors++;
+
+mod_put:
+ module_put(client->driver->driver.owner);
+dev_put:
+ device_unlock(&client->dev);
+ put_device(&client->dev);
+ return ret;
+}
+
+/* Parse port node and register as a sub-device any sensor specified there. */
+static int fimc_md_parse_port_node(struct fimc_md *fmd,
+ struct device_node *port,
+ unsigned int index)
+{
+ struct device_node *rem, *ep, *np;
+ struct fimc_source_info *pd;
+ struct v4l2_of_endpoint endpoint;
+ int ret;
+ u32 val;
+
+ pd = &fmd->sensor[index].pdata;
+
+ /* Assume here a port node can have only one endpoint node. */
+ ep = of_get_next_child(port, NULL);
+ if (!ep)
+ return 0;
+
+ v4l2_of_parse_endpoint(ep, &endpoint);
+ if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS)
+ return -EINVAL;
+
+ pd->mux_id = (endpoint.port - 1) & 0x1;
+
+ rem = v4l2_of_get_remote_port_parent(ep);
+ of_node_put(ep);
+ if (rem == NULL) {
+ v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n",
+ ep->full_name);
+ return 0;
+ }
+ if (!of_property_read_u32(rem, "samsung,camclk-out", &val))
+ pd->clk_id = val;
+
+ if (!of_property_read_u32(rem, "clock-frequency", &val))
+ pd->clk_frequency = val;
+
+ if (pd->clk_frequency == 0) {
+ v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n",
+ rem->full_name);
+ of_node_put(rem);
+ return -EINVAL;
+ }
+
+ if (fimc_input_is_parallel(endpoint.port)) {
+ if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
+ pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601;
+ else
+ pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656;
+ pd->flags = endpoint.bus.parallel.flags;
+ } else if (fimc_input_is_mipi_csi(endpoint.port)) {
+ /*
+ * MIPI CSI-2: only input mux selection and
+ * the sensor's clock frequency is needed.
+ */
+ pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2;
+ } else {
+ v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
+ endpoint.port, rem->full_name);
+ }
+ /*
+ * For FIMC-IS handled sensors, that are placed under i2c-isp device
+ * node, FIMC is connected to the FIMC-IS through its ISP Writeback
+ * input. Sensors are attached to the FIMC-LITE hostdata interface
+ * directly or through MIPI-CSIS, depending on the external media bus
+ * used. This needs to be handled in a more reliable way, not by just
+ * checking parent's node name.
+ */
+ np = of_get_parent(rem);
+
+ if (np && !of_node_cmp(np->name, "i2c-isp"))
+ pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
+ else
+ pd->fimc_bus_type = pd->sensor_bus_type;
+
+ ret = fimc_md_of_add_sensor(fmd, rem, index);
+ of_node_put(rem);
+
+ return ret;
+}
+
+/* Register all SoC external sub-devices */
+static int fimc_md_of_sensors_register(struct fimc_md *fmd,
+ struct device_node *np)
+{
+ struct device_node *parent = fmd->pdev->dev.of_node;
+ struct device_node *node, *ports;
+ int index = 0;
+ int ret;
+
+ /* Attach sensors linked to MIPI CSI-2 receivers */
+ for_each_available_child_of_node(parent, node) {
+ struct device_node *port;
+
+ if (of_node_cmp(node->name, "csis"))
+ continue;
+ /* The csis node can have only port subnode. */
+ port = of_get_next_child(node, NULL);
+ if (!port)
+ continue;
+
+ ret = fimc_md_parse_port_node(fmd, port, index);
+ if (ret < 0)
+ return ret;
+ index++;
+ }
+
+ /* Attach sensors listed in the parallel-ports node */
+ ports = of_get_child_by_name(parent, "parallel-ports");
+ if (!ports)
+ return 0;
+
+ for_each_child_of_node(ports, node) {
+ ret = fimc_md_parse_port_node(fmd, node, index);
+ if (ret < 0)
+ break;
+ index++;
+ }
+
+ return 0;
+}
+
+static int __of_get_csis_id(struct device_node *np)
+{
+ u32 reg = 0;
+
+ np = of_get_child_by_name(np, "port");
+ if (!np)
+ return -EINVAL;
+ of_property_read_u32(np, "reg", &reg);
+ return reg - FIMC_INPUT_MIPI_CSI2_0;
+}
+#else
+#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS)
+#define __of_get_csis_id(np) (-ENOSYS)
+#endif
+
static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
{
struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
- struct fimc_dev *fd = NULL;
- int num_clients, ret, i;
+ struct device_node *of_node = fmd->pdev->dev.of_node;
+ int num_clients = 0;
+ int ret, i;
/*
* Runtime resume one of the FIMC entities to make sure
* the sclk_cam clocks are not globally disabled.
*/
- for (i = 0; !fd && i < ARRAY_SIZE(fmd->fimc); i++)
- if (fmd->fimc[i])
- fd = fmd->fimc[i];
- if (!fd)
+ if (!fmd->pmf)
return -ENXIO;
- ret = pm_runtime_get_sync(&fd->pdev->dev);
+
+ ret = pm_runtime_get_sync(fmd->pmf);
if (ret < 0)
return ret;
- WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
- num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor));
-
- fmd->num_sensors = num_clients;
- for (i = 0; i < num_clients; i++) {
- struct v4l2_subdev *sd;
-
- fmd->sensor[i].pdata = pdata->source_info[i];
- ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
- if (ret)
- break;
- sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]);
- ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false);
-
- if (!IS_ERR(sd)) {
- fmd->sensor[i].subdev = sd;
- } else {
- fmd->sensor[i].subdev = NULL;
- ret = PTR_ERR(sd);
- break;
+ if (of_node) {
+ fmd->num_sensors = 0;
+ ret = fimc_md_of_sensors_register(fmd, of_node);
+ } else if (pdata) {
+ WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
+ num_clients = min_t(u32, pdata->num_clients,
+ ARRAY_SIZE(fmd->sensor));
+ fmd->num_sensors = num_clients;
+
+ for (i = 0; i < num_clients; i++) {
+ struct fimc_sensor_info *si = &fmd->sensor[i];
+ struct v4l2_subdev *sd;
+
+ si->pdata = pdata->source_info[i];
+ ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
+ if (ret)
+ break;
+ sd = fimc_md_register_sensor(fmd, &si->pdata);
+ ret = __fimc_md_set_camclk(fmd, &si->pdata, false);
+
+ if (IS_ERR(sd)) {
+ si->subdev = NULL;
+ ret = PTR_ERR(sd);
+ break;
+ }
+ si->subdev = sd;
+ if (ret)
+ break;
}
- if (ret)
- break;
}
- pm_runtime_put(&fd->pdev->dev);
+
+ pm_runtime_put(fmd->pmf);
return ret;
}
@@ -352,6 +625,8 @@ static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc)
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (!ret) {
+ if (!fmd->pmf && fimc->pdev)
+ fmd->pmf = &fimc->pdev->dev;
fmd->fimc[fimc->id] = fimc;
fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
} else {
@@ -368,13 +643,13 @@ static int register_csis_entity(struct fimc_md *fmd,
struct device_node *node = pdev->dev.of_node;
int id, ret;
- id = node ? of_alias_get_id(node, "csis") : max(0, pdev->id);
+ id = node ? __of_get_csis_id(node) : max(0, pdev->id);
- if (WARN_ON(id >= CSIS_MAX_ENTITIES || fmd->csis[id].sd))
- return -EBUSY;
+ if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES))
+ return -ENOENT;
- if (WARN_ON(id >= CSIS_MAX_ENTITIES))
- return 0;
+ if (WARN_ON(fmd->csis[id].sd))
+ return -EBUSY;
sd->grp_id = GRP_ID_CSIS;
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
@@ -386,6 +661,22 @@ static int register_csis_entity(struct fimc_md *fmd,
return ret;
}
+static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is)
+{
+ struct v4l2_subdev *sd = &is->isp.subdev;
+ int ret;
+
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ if (ret) {
+ v4l2_err(&fmd->v4l2_dev,
+ "Failed to register FIMC-ISP (%d)\n", ret);
+ return ret;
+ }
+
+ fmd->fimc_is = is;
+ return 0;
+}
+
static int fimc_md_register_platform_entity(struct fimc_md *fmd,
struct platform_device *pdev,
int plat_entity)
@@ -413,6 +704,9 @@ static int fimc_md_register_platform_entity(struct fimc_md *fmd,
case IDX_CSIS:
ret = register_csis_entity(fmd, pdev, drvdata);
break;
+ case IDX_IS_ISP:
+ ret = register_fimc_is_entity(fmd, drvdata);
+ break;
default:
ret = -ENODEV;
}
@@ -457,6 +751,47 @@ static int fimc_md_pdev_match(struct device *dev, void *data)
return 0;
}
+/* Register FIMC, FIMC-LITE and CSIS media entities */
+#ifdef CONFIG_OF
+static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
+ struct device_node *parent)
+{
+ struct device_node *node;
+ int ret = 0;
+
+ for_each_available_child_of_node(parent, node) {
+ struct platform_device *pdev;
+ int plat_entity = -1;
+
+ pdev = of_find_device_by_node(node);
+ if (!pdev)
+ continue;
+
+ /* If driver of any entity isn't ready try all again later. */
+ if (!strcmp(node->name, CSIS_OF_NODE_NAME))
+ plat_entity = IDX_CSIS;
+ else if (!strcmp(node->name, FIMC_IS_OF_NODE_NAME))
+ plat_entity = IDX_IS_ISP;
+ else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
+ plat_entity = IDX_FLITE;
+ else if (!strcmp(node->name, FIMC_OF_NODE_NAME) &&
+ !of_property_read_bool(node, "samsung,lcd-wb"))
+ plat_entity = IDX_FIMC;
+
+ if (plat_entity >= 0)
+ ret = fimc_md_register_platform_entity(fmd, pdev,
+ plat_entity);
+ put_device(&pdev->dev);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+#else
+#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS)
+#endif
+
static void fimc_md_unregister_entities(struct fimc_md *fmd)
{
int i;
@@ -479,7 +814,6 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
if (fmd->csis[i].sd == NULL)
continue;
v4l2_device_unregister_subdev(fmd->csis[i].sd);
- module_put(fmd->csis[i].sd->owner);
fmd->csis[i].sd = NULL;
}
for (i = 0; i < fmd->num_sensors; i++) {
@@ -488,6 +822,10 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
fimc_md_unregister_sensor(fmd->sensor[i].subdev);
fmd->sensor[i].subdev = NULL;
}
+
+ if (fmd->fimc_is)
+ v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev);
+
v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n");
}
@@ -504,12 +842,19 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
struct v4l2_subdev *sensor,
int pad, int link_mask)
{
- struct fimc_sensor_info *s_info = NULL;
+ struct fimc_source_info *si = NULL;
struct media_entity *sink;
unsigned int flags = 0;
- int ret, i;
+ int i, ret = 0;
- for (i = 0; i < FIMC_MAX_DEVS; i++) {
+ if (sensor) {
+ si = v4l2_get_subdev_hostdata(sensor);
+ /* Skip direct FIMC links in the logical FIMC-IS sensor path */
+ if (si && si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
+ ret = 1;
+ }
+
+ for (i = 0; !ret && i < FIMC_MAX_DEVS; i++) {
if (!fmd->fimc[i])
continue;
/*
@@ -523,7 +868,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
sink = &fmd->fimc[i]->vid_cap.subdev.entity;
ret = media_entity_create_link(source, pad, sink,
- FIMC_SD_PAD_SINK, flags);
+ FIMC_SD_PAD_SINK_CAM, flags);
if (ret)
return ret;
@@ -538,11 +883,13 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
if (flags == 0 || sensor == NULL)
continue;
- s_info = v4l2_get_subdev_hostdata(sensor);
- if (!WARN_ON(s_info == NULL)) {
+
+ if (!WARN_ON(si == NULL)) {
unsigned long irq_flags;
+ struct fimc_sensor_info *inf = source_to_sensor_info(si);
+
spin_lock_irqsave(&fmd->slock, irq_flags);
- s_info->host = fmd->fimc[i];
+ inf->host = fmd->fimc[i];
spin_unlock_irqrestore(&fmd->slock, irq_flags);
}
}
@@ -551,25 +898,20 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
if (!fmd->fimc_lite[i])
continue;
- if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
- flags = MEDIA_LNK_FL_ENABLED;
- else
- flags = 0;
-
sink = &fmd->fimc_lite[i]->subdev.entity;
ret = media_entity_create_link(source, pad, sink,
- FLITE_SD_PAD_SINK, flags);
+ FLITE_SD_PAD_SINK, 0);
if (ret)
return ret;
/* Notify FIMC-LITE subdev entity */
ret = media_entity_call(sink, link_setup, &sink->pads[0],
- &source->pads[pad], flags);
+ &source->pads[pad], 0);
if (ret)
break;
- v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
- source->name, flags ? '=' : '-', sink->name);
+ v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n",
+ source->name, sink->name);
}
return 0;
}
@@ -578,21 +920,50 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
{
struct media_entity *source, *sink;
- unsigned int flags = MEDIA_LNK_FL_ENABLED;
int i, ret = 0;
for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
struct fimc_lite *fimc = fmd->fimc_lite[i];
+
if (fimc == NULL)
continue;
+
source = &fimc->subdev.entity;
sink = &fimc->vfd.entity;
/* FIMC-LITE's subdev and video node */
ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
- sink, 0, flags);
+ sink, 0, 0);
+ if (ret)
+ break;
+ /* Link from FIMC-LITE to IS-ISP subdev */
+ sink = &fmd->fimc_is->isp.subdev.entity;
+ ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP,
+ sink, 0, 0);
if (ret)
break;
- /* TODO: create links to other entities */
+ }
+
+ return ret;
+}
+
+/* Create FIMC-IS links */
+static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
+{
+ struct media_entity *source, *sink;
+ int i, ret;
+
+ source = &fmd->fimc_is->isp.subdev.entity;
+
+ for (i = 0; i < FIMC_MAX_DEVS; i++) {
+ if (fmd->fimc[i] == NULL)
+ continue;
+
+ /* Link from IS-ISP subdev to FIMC */
+ sink = &fmd->fimc[i]->vid_cap.subdev.entity;
+ ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO,
+ sink, FIMC_SD_PAD_SINK_FIFO, 0);
+ if (ret)
+ return ret;
}
return ret;
@@ -615,7 +986,6 @@ static int fimc_md_create_links(struct fimc_md *fmd)
struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL };
struct v4l2_subdev *sensor, *csis;
struct fimc_source_info *pdata;
- struct fimc_sensor_info *s_info;
struct media_entity *source, *sink;
int i, pad, fimc_id = 0, ret = 0;
u32 flags, link_mask = 0;
@@ -625,12 +995,11 @@ static int fimc_md_create_links(struct fimc_md *fmd)
continue;
sensor = fmd->sensor[i].subdev;
- s_info = v4l2_get_subdev_hostdata(sensor);
- if (!s_info)
+ pdata = v4l2_get_subdev_hostdata(sensor);
+ if (!pdata)
continue;
source = NULL;
- pdata = &s_info->pdata;
switch (pdata->sensor_bus_type) {
case FIMC_BUS_TYPE_MIPI_CSI2:
@@ -680,6 +1049,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
if (fmd->csis[i].sd == NULL)
continue;
+
source = &fmd->csis[i].sd->entity;
pad = CSIS_PAD_SOURCE;
sensor = csi_sensors[i];
@@ -694,19 +1064,28 @@ static int fimc_md_create_links(struct fimc_md *fmd)
for (i = 0; i < FIMC_MAX_DEVS; i++) {
if (!fmd->fimc[i])
continue;
+
source = &fmd->fimc[i]->vid_cap.subdev.entity;
sink = &fmd->fimc[i]->vid_cap.vfd.entity;
+
ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
sink, 0, flags);
if (ret)
break;
}
- return __fimc_md_create_flite_source_links(fmd);
+ ret = __fimc_md_create_flite_source_links(fmd);
+ if (ret < 0)
+ return ret;
+
+ if (fmd->use_isp)
+ ret = __fimc_md_create_fimc_is_links(fmd);
+
+ return ret;
}
/*
- * The peripheral sensor clock management.
+ * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management.
*/
static void fimc_md_put_clocks(struct fimc_md *fmd)
{
@@ -719,6 +1098,14 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
clk_put(fmd->camclk[i].clock);
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
}
+
+ /* Writeback (PIXELASYNCMx) clocks */
+ for (i = 0; i < FIMC_MAX_WBCLKS; i++) {
+ if (IS_ERR(fmd->wbclk[i]))
+ continue;
+ clk_put(fmd->wbclk[i]);
+ fmd->wbclk[i] = ERR_PTR(-EINVAL);
+ }
}
static int fimc_md_get_clocks(struct fimc_md *fmd)
@@ -755,35 +1142,59 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
if (ret)
fimc_md_put_clocks(fmd);
+ if (!fmd->use_isp)
+ return 0;
+ /*
+ * For now get only PIXELASYNCM1 clock (Writeback B/ISP),
+ * leave PIXELASYNCM0 out for the LCD Writeback driver.
+ */
+ fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL);
+
+ for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) {
+ snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i);
+ clock = clk_get(dev, clk_name);
+ if (IS_ERR(clock)) {
+ v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n",
+ clk_name);
+ ret = PTR_ERR(clock);
+ break;
+ }
+ fmd->wbclk[i] = clock;
+ }
+ if (ret)
+ fimc_md_put_clocks(fmd);
+
return ret;
}
static int __fimc_md_set_camclk(struct fimc_md *fmd,
- struct fimc_sensor_info *s_info,
+ struct fimc_source_info *si,
bool on)
{
- struct fimc_source_info *pdata = &s_info->pdata;
struct fimc_camclk_info *camclk;
int ret = 0;
- if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL)
+ if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf)
return -EINVAL;
- camclk = &fmd->camclk[pdata->clk_id];
+ camclk = &fmd->camclk[si->clk_id];
dbg("camclk %d, f: %lu, use_count: %d, on: %d",
- pdata->clk_id, pdata->clk_frequency, camclk->use_count, on);
+ si->clk_id, si->clk_frequency, camclk->use_count, on);
if (on) {
if (camclk->use_count > 0 &&
- camclk->frequency != pdata->clk_frequency)
+ camclk->frequency != si->clk_frequency)
return -EINVAL;
if (camclk->use_count++ == 0) {
- clk_set_rate(camclk->clock, pdata->clk_frequency);
- camclk->frequency = pdata->clk_frequency;
+ clk_set_rate(camclk->clock, si->clk_frequency);
+ camclk->frequency = si->clk_frequency;
+ ret = pm_runtime_get_sync(fmd->pmf);
+ if (ret < 0)
+ return ret;
ret = clk_enable(camclk->clock);
- dbg("Enabled camclk %d: f: %lu", pdata->clk_id,
+ dbg("Enabled camclk %d: f: %lu", si->clk_id,
clk_get_rate(camclk->clock));
}
return ret;
@@ -794,7 +1205,8 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
if (--camclk->use_count == 0) {
clk_disable(camclk->clock);
- dbg("Disabled camclk %d", pdata->clk_id);
+ pm_runtime_put(fmd->pmf);
+ dbg("Disabled camclk %d", si->clk_id);
}
return ret;
}
@@ -813,10 +1225,10 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
*/
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
{
- struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd);
+ struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd);
struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
- return __fimc_md_set_camclk(fmd, s_info, on);
+ return __fimc_md_set_camclk(fmd, si, on);
}
static int fimc_md_link_notify(struct media_pad *source,
@@ -827,7 +1239,7 @@ static int fimc_md_link_notify(struct media_pad *source,
struct fimc_pipeline *pipeline;
struct v4l2_subdev *sd;
struct mutex *lock;
- int ret = 0;
+ int i, ret = 0;
int ref_count;
if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -854,29 +1266,28 @@ static int fimc_md_link_notify(struct media_pad *source,
return 0;
}
+ mutex_lock(lock);
+ ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
+
if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- int i;
- mutex_lock(lock);
- ret = __fimc_pipeline_close(pipeline);
+ if (ref_count > 0) {
+ ret = __fimc_pipeline_close(pipeline);
+ if (!ret && fimc)
+ fimc_ctrls_delete(fimc->vid_cap.ctx);
+ }
for (i = 0; i < IDX_MAX; i++)
pipeline->subdevs[i] = NULL;
- if (fimc)
- fimc_ctrls_delete(fimc->vid_cap.ctx);
- mutex_unlock(lock);
- return ret;
+ } else if (ref_count > 0) {
+ /*
+ * Link activation. Enable power of pipeline elements only if
+ * the pipeline is already in use, i.e. its video node is open.
+ * Recreate the controls destroyed during the link deactivation.
+ */
+ ret = __fimc_pipeline_open(pipeline,
+ source->entity, true);
+ if (!ret && fimc)
+ ret = fimc_capture_ctrls_create(fimc);
}
- /*
- * Link activation. Enable power of pipeline elements only if the
- * pipeline is already in use, i.e. its video node is opened.
- * Recreate the controls destroyed during the link deactivation.
- */
- mutex_lock(lock);
-
- ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
- if (ref_count > 0)
- ret = __fimc_pipeline_open(pipeline, source->entity, true);
- if (!ret && fimc)
- ret = fimc_capture_ctrls_create(fimc);
mutex_unlock(lock);
return ret ? -EPIPE : ret;
@@ -927,13 +1338,33 @@ static ssize_t fimc_md_sysfs_store(struct device *dev,
static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
fimc_md_sysfs_show, fimc_md_sysfs_store);
+static int fimc_md_get_pinctrl(struct fimc_md *fmd)
+{
+ struct device *dev = &fmd->pdev->dev;
+ struct fimc_pinctrl *pctl = &fmd->pinctl;
+
+ pctl->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pctl->pinctrl))
+ return PTR_ERR(pctl->pinctrl);
+
+ pctl->state_default = pinctrl_lookup_state(pctl->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(pctl->state_default))
+ return PTR_ERR(pctl->state_default);
+
+ pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl,
+ PINCTRL_STATE_IDLE);
+ return 0;
+}
+
static int fimc_md_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev;
struct fimc_md *fmd;
int ret;
- fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL);
+ fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL);
if (!fmd)
return -ENOMEM;
@@ -943,15 +1374,16 @@ static int fimc_md_probe(struct platform_device *pdev)
strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
sizeof(fmd->media_dev.model));
fmd->media_dev.link_notify = fimc_md_link_notify;
- fmd->media_dev.dev = &pdev->dev;
+ fmd->media_dev.dev = dev;
v4l2_dev = &fmd->v4l2_dev;
v4l2_dev->mdev = &fmd->media_dev;
v4l2_dev->notify = fimc_sensor_notify;
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s",
- dev_name(&pdev->dev));
+ strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
+
+ fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
- ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev);
+ ret = v4l2_device_register(dev, &fmd->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
return ret;
@@ -965,21 +1397,32 @@ static int fimc_md_probe(struct platform_device *pdev)
if (ret)
goto err_clk;
- fmd->user_subdev_api = false;
+ fmd->user_subdev_api = (dev->of_node != NULL);
/* Protect the media graph while we're registering entities */
mutex_lock(&fmd->media_dev.graph_mutex);
- ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
- fimc_md_pdev_match);
+ ret = fimc_md_get_pinctrl(fmd);
+ if (ret < 0) {
+ if (ret != EPROBE_DEFER)
+ dev_err(dev, "Failed to get pinctrl: %d\n", ret);
+ goto err_unlock;
+ }
+
+ if (dev->of_node)
+ ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
+ else
+ ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
+ fimc_md_pdev_match);
if (ret)
goto err_unlock;
- if (pdev->dev.platform_data) {
+ if (dev->platform_data || dev->of_node) {
ret = fimc_md_register_sensor_entities(fmd);
if (ret)
goto err_unlock;
}
+
ret = fimc_md_create_links(fmd);
if (ret)
goto err_unlock;
@@ -1019,12 +1462,25 @@ static int fimc_md_remove(struct platform_device *pdev)
return 0;
}
+static struct platform_device_id fimc_driver_ids[] __always_unused = {
+ { .name = "s5p-fimc-md" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
+
+static const struct of_device_id fimc_md_of_match[] = {
+ { .compatible = "samsung,fimc" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, fimc_md_of_match);
+
static struct platform_driver fimc_md_driver = {
.probe = fimc_md_probe,
.remove = fimc_md_remove,
.driver = {
- .name = "s5p-fimc-md",
- .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(fimc_md_of_match),
+ .name = "s5p-fimc-md",
+ .owner = THIS_MODULE,
}
};
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/exynos4-is/media-dev.h
index 06b0d8276fd2..44d86b61d660 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -12,6 +12,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
#include <media/media-device.h>
#include <media/media-entity.h>
#include <media/v4l2-device.h>
@@ -21,18 +23,23 @@
#include "fimc-lite.h"
#include "mipi-csis.h"
-/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
-#define GRP_ID_SENSOR (1 << 8)
-#define GRP_ID_FIMC_IS_SENSOR (1 << 9)
-#define GRP_ID_WRITEBACK (1 << 10)
-#define GRP_ID_CSIS (1 << 11)
-#define GRP_ID_FIMC (1 << 12)
-#define GRP_ID_FLITE (1 << 13)
-#define GRP_ID_FIMC_IS (1 << 14)
+#define FIMC_OF_NODE_NAME "fimc"
+#define FIMC_LITE_OF_NODE_NAME "fimc-lite"
+#define FIMC_IS_OF_NODE_NAME "fimc-is"
+#define CSIS_OF_NODE_NAME "csis"
+
+#define PINCTRL_STATE_IDLE "idle"
#define FIMC_MAX_SENSORS 8
#define FIMC_MAX_CAMCLKS 2
+/* LCD/ISP Writeback clocks (PIXELASYNCMx) */
+enum {
+ CLK_IDX_WB_A,
+ CLK_IDX_WB_B,
+ FIMC_MAX_WBCLKS
+};
+
struct fimc_csis_info {
struct v4l2_subdev *sd;
int id;
@@ -65,9 +72,15 @@ struct fimc_sensor_info {
* @num_sensors: actual number of registered sensors
* @camclk: external sensor clock information
* @fimc: array of registered fimc devices
+ * @fimc_is: fimc-is data structure
+ * @use_isp: set to true when FIMC-IS subsystem is used
+ * @pmf: handle to the CAMCLK clock control FIMC helper device
* @media_dev: top level media device
* @v4l2_dev: top level v4l2_device holding up the subdevs
* @pdev: platform device this media device is hooked up into
+ * @pinctrl: camera port pinctrl handle
+ * @state_default: pinctrl default state handle
+ * @state_idle: pinctrl idle state handle
* @user_subdev_api: true if subdevs are not configured by the host driver
* @slock: spinlock protecting @sensor array
*/
@@ -76,11 +89,20 @@ struct fimc_md {
struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
int num_sensors;
struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
+ struct clk *wbclk[FIMC_MAX_WBCLKS];
struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
struct fimc_dev *fimc[FIMC_MAX_DEVS];
+ struct fimc_is *fimc_is;
+ bool use_isp;
+ struct device *pmf;
struct media_device media_dev;
struct v4l2_device v4l2_dev;
struct platform_device *pdev;
+ struct fimc_pinctrl {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *state_default;
+ struct pinctrl_state *state_idle;
+ } pinctl;
bool user_subdev_api;
spinlock_t slock;
};
@@ -93,6 +115,12 @@ struct fimc_md {
#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)
+static inline
+struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si)
+{
+ return container_of(si, struct fimc_sensor_info, pdata);
+}
+
static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
{
return me->parent == NULL ? NULL :
@@ -111,4 +139,14 @@ static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
+#ifdef CONFIG_OF
+static inline bool fimc_md_is_isp_available(struct device_node *node)
+{
+ node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME);
+ return node ? of_device_is_available(node) : false;
+}
+#else
+#define fimc_md_is_isp_available(node) (false)
+#endif /* CONFIG_OF */
+
#endif
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 981863d05aaa..a2eda9d5ac87 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -19,14 +19,18 @@
#include <linux/kernel.h>
#include <linux/memory.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/mipi-csis.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/videodev2.h>
+#include <media/s5p_fimc.h>
+#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
-#include <linux/platform_data/mipi-csis.h>
+
#include "mipi-csis.h"
static int debug;
@@ -113,6 +117,7 @@ static char *csi_clock_name[] = {
[CSIS_CLK_GATE] = "csis",
};
#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
+#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
static const char * const csis_supply_name[] = {
"vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */
@@ -167,6 +172,11 @@ struct csis_pktbuf {
* @clock: CSIS clocks
* @irq: requested s5p-mipi-csis irq number
* @flags: the state variable for power and streaming control
+ * @clock_frequency: device bus clock frequency
+ * @hs_settle: HS-RX settle time
+ * @num_lanes: number of MIPI-CSI data lanes used
+ * @max_num_lanes: maximum number of MIPI-CSI data lanes supported
+ * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM
* @csis_fmt: current CSIS pixel format
* @format: common media bus format for the source and sink pad
* @slock: spinlock protecting structure members below
@@ -184,6 +194,13 @@ struct csis_state {
struct clk *clock[NUM_CSIS_CLOCKS];
int irq;
u32 flags;
+
+ u32 clk_frequency;
+ u32 hs_settle;
+ u32 num_lanes;
+ u32 max_num_lanes;
+ u8 wclk_ext;
+
const struct csis_pix_format *csis_fmt;
struct v4l2_mbus_framefmt format;
@@ -273,7 +290,6 @@ static void s5pcsis_reset(struct csis_state *state)
static void s5pcsis_system_enable(struct csis_state *state, int on)
{
- struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
u32 val, mask;
val = s5pcsis_read(state, S5PCSIS_CTRL);
@@ -286,7 +302,7 @@ static void s5pcsis_system_enable(struct csis_state *state, int on)
val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
val &= ~S5PCSIS_DPHYCTRL_ENABLE;
if (on) {
- mask = (1 << (pdata->lanes + 1)) - 1;
+ mask = (1 << (state->num_lanes + 1)) - 1;
val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
}
s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
@@ -321,15 +337,14 @@ static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
static void s5pcsis_set_params(struct csis_state *state)
{
- struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
u32 val;
val = s5pcsis_read(state, S5PCSIS_CONFIG);
- val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1);
s5pcsis_write(state, S5PCSIS_CONFIG, val);
__s5pcsis_set_format(state);
- s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+ s5pcsis_set_hsync_settle(state, state->hs_settle);
val = s5pcsis_read(state, S5PCSIS_CTRL);
if (state->csis_fmt->data_alignment == 32)
@@ -338,7 +353,7 @@ static void s5pcsis_set_params(struct csis_state *state)
val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
- if (pdata->wclk_source)
+ if (state->wclk_ext)
val |= S5PCSIS_CTRL_WCLK_EXTCLK;
s5pcsis_write(state, S5PCSIS_CTRL, val);
@@ -534,10 +549,10 @@ static struct csis_pix_format const *s5pcsis_try_format(
static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
struct csis_state *state, struct v4l2_subdev_fh *fh,
- u32 pad, enum v4l2_subdev_format_whence which)
+ enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+ return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
return &state->format;
}
@@ -549,10 +564,7 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct csis_pix_format const *csis_fmt;
struct v4l2_mbus_framefmt *mf;
- if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
- return -EINVAL;
-
- mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ mf = __s5pcsis_get_format(state, fh, fmt->which);
if (fmt->pad == CSIS_PAD_SOURCE) {
if (mf) {
@@ -579,10 +591,7 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct csis_state *state = sd_to_csis_state(sd);
struct v4l2_mbus_framefmt *mf;
- if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
- return -EINVAL;
-
- mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ mf = __s5pcsis_get_format(state, fh, fmt->which);
if (!mf)
return -EINVAL;
@@ -701,52 +710,111 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int s5pcsis_get_platform_data(struct platform_device *pdev,
+ struct csis_state *state)
+{
+ struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Platform data not specified\n");
+ return -EINVAL;
+ }
+
+ state->clk_frequency = pdata->clk_rate;
+ state->num_lanes = pdata->lanes;
+ state->hs_settle = pdata->hs_settle;
+ state->index = max(0, pdev->id);
+ state->max_num_lanes = state->index ? CSIS1_MAX_LANES :
+ CSIS0_MAX_LANES;
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static int s5pcsis_parse_dt(struct platform_device *pdev,
+ struct csis_state *state)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct v4l2_of_endpoint endpoint;
+
+ if (of_property_read_u32(node, "clock-frequency",
+ &state->clk_frequency))
+ state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
+ if (of_property_read_u32(node, "bus-width",
+ &state->max_num_lanes))
+ return -EINVAL;
+
+ node = v4l2_of_get_next_endpoint(node, NULL);
+ if (!node) {
+ dev_err(&pdev->dev, "No port node at %s\n",
+ node->full_name);
+ return -EINVAL;
+ }
+ /* Get port node and validate MIPI-CSI channel id. */
+ v4l2_of_parse_endpoint(node, &endpoint);
+
+ state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0;
+ if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES)
+ return -ENXIO;
+
+ /* Get MIPI CSI-2 bus configration from the endpoint node. */
+ of_property_read_u32(node, "samsung,csis-hs-settle",
+ &state->hs_settle);
+ state->wclk_ext = of_property_read_bool(node,
+ "samsung,csis-wclk");
+
+ state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes;
+
+ of_node_put(node);
+ return 0;
+}
+#else
+#define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
+#endif
+
static int s5pcsis_probe(struct platform_device *pdev)
{
- struct s5p_platform_mipi_csis *pdata;
+ struct device *dev = &pdev->dev;
struct resource *mem_res;
struct csis_state *state;
int ret = -ENOMEM;
int i;
- state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
mutex_init(&state->lock);
spin_lock_init(&state->slock);
-
state->pdev = pdev;
- state->index = max(0, pdev->id);
- pdata = pdev->dev.platform_data;
- if (pdata == NULL) {
- dev_err(&pdev->dev, "Platform data not fully specified\n");
- return -EINVAL;
- }
+ if (dev->of_node)
+ ret = s5pcsis_parse_dt(pdev, state);
+ else
+ ret = s5pcsis_get_platform_data(pdev, state);
+ if (ret < 0)
+ return ret;
- if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
- pdata->lanes > CSIS0_MAX_LANES) {
- dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
- pdata->lanes);
+ if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
+ dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n",
+ state->num_lanes, state->max_num_lanes);
return -EINVAL;
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- state->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ state->regs = devm_ioremap_resource(dev, mem_res);
if (IS_ERR(state->regs))
return PTR_ERR(state->regs);
state->irq = platform_get_irq(pdev, 0);
if (state->irq < 0) {
- dev_err(&pdev->dev, "Failed to get irq\n");
+ dev_err(dev, "Failed to get irq\n");
return state->irq;
}
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
state->supplies[i].supply = csis_supply_name[i];
- ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
+ ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES,
state->supplies);
if (ret)
return ret;
@@ -755,11 +823,11 @@ static int s5pcsis_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- if (pdata->clk_rate)
+ if (state->clk_frequency)
ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
- pdata->clk_rate);
+ state->clk_frequency);
else
- dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+ dev_WARN(dev, "No clock frequency specified!\n");
if (ret < 0)
goto e_clkput;
@@ -767,16 +835,17 @@ static int s5pcsis_probe(struct platform_device *pdev)
if (ret < 0)
goto e_clkput;
- ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
- 0, dev_name(&pdev->dev), state);
+ ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler,
+ 0, dev_name(dev), state);
if (ret) {
- dev_err(&pdev->dev, "Interrupt request failed\n");
+ dev_err(dev, "Interrupt request failed\n");
goto e_clkdis;
}
v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
state->sd.owner = THIS_MODULE;
- strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+ snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d",
+ CSIS_SUBDEV_NAME, state->index);
state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->csis_fmt = &s5pcsis_formats[0];
@@ -796,10 +865,12 @@ static int s5pcsis_probe(struct platform_device *pdev)
/* .. and a pointer to the subdev. */
platform_set_drvdata(pdev, &state->sd);
-
memcpy(state->events, s5pcsis_events, sizeof(state->events));
+ pm_runtime_enable(dev);
- pm_runtime_enable(&pdev->dev);
+ dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n",
+ state->num_lanes, state->hs_settle, state->wclk_ext,
+ state->clk_frequency);
return 0;
e_clkdis:
@@ -923,13 +994,21 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
};
+static const struct of_device_id s5pcsis_of_match[] = {
+ { .compatible = "samsung,s5pv210-csis" },
+ { .compatible = "samsung,exynos4210-csis" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
+
static struct platform_driver s5pcsis_driver = {
.probe = s5pcsis_probe,
.remove = s5pcsis_remove,
.driver = {
- .name = CSIS_DRIVER_NAME,
- .owner = THIS_MODULE,
- .pm = &s5pcsis_pm_ops,
+ .of_match_table = s5pcsis_of_match,
+ .name = CSIS_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5pcsis_pm_ops,
},
};
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/exynos4-is/mipi-csis.h
index 2709286396e1..28c11c4085d8 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.h
+++ b/drivers/media/platform/exynos4-is/mipi-csis.h
@@ -11,6 +11,7 @@
#define S5P_MIPI_CSIS_H_
#define CSIS_DRIVER_NAME "s5p-mipi-csis"
+#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME
#define CSIS_MAX_ENTITIES 2
#define CSIS0_MAX_LANES 4
#define CSIS1_MAX_LANES 2
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 5f7db3f1f6f5..3a6a0dcdc3e4 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -957,12 +957,12 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct viu_fh *fh = priv;
- fh->dev->std = *id;
- decoder_call(fh->dev, core, s_std, *id);
+ fh->dev->std = id;
+ decoder_call(fh->dev, core, s_std, id);
return 0;
}
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 6c4db9b98989..758564649589 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -207,6 +207,9 @@ static void dma_callback(void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -866,6 +869,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &deinterlace_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_SRC].fmt = &formats[0];
q_data[V4L2_M2M_SRC].width = 640;
q_data[V4L2_M2M_SRC].height = 480;
@@ -882,6 +886,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &deinterlace_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
q_data[V4L2_M2M_DST].fmt = &formats[0];
q_data[V4L2_M2M_DST].width = 640;
q_data[V4L2_M2M_DST].height = 480;
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 92a33f081852..64ab91edfb81 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1357,7 +1357,7 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
}
/* from vivi.c */
-static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a)
{
return 0;
}
@@ -1445,7 +1445,7 @@ static int mcam_vidioc_g_register(struct file *file, void *priv,
}
static int mcam_vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct mcam_camera *cam = priv;
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 7487d7208dea..4cc7f65d7d76 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -38,6 +38,10 @@ MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.1");
+static unsigned debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "activates debug info");
+
#define MIN_W 32
#define MIN_H 32
#define MAX_W 640
@@ -67,7 +71,7 @@ MODULE_VERSION("0.1.1");
#define MEM2MEM_VFLIP (1 << 1)
#define dprintk(dev, fmt, arg...) \
- v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+ v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
static void m2mtest_dev_release(struct device *dev)
@@ -234,6 +238,10 @@ static int device_process(struct m2mtest_ctx *ctx,
bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES;
w = 0;
+ memcpy(&out_vb->v4l2_buf.timestamp,
+ &in_vb->v4l2_buf.timestamp,
+ sizeof(struct timeval));
+
switch (ctx->mode) {
case MEM2MEM_HFLIP | MEM2MEM_VFLIP:
p_out += bytesperline * height - bytes_left;
@@ -844,6 +852,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &m2mtest_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -855,6 +864,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &m2mtest_qops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 4b9e0a28616a..f7440e585b6b 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -377,6 +377,9 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp;
+ src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode;
+
spin_lock_irqsave(&pcdev->irqlock, flags);
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
@@ -763,6 +766,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &emmaprp_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -774,6 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &emmaprp_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 96c4a17e4280..477268a2415f 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -648,9 +648,12 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
/* First save the configuration in ovelray structure */
ret = omapvid_init(vout, addr);
- if (ret)
+ if (ret) {
printk(KERN_ERR VOUT_NAME
"failed to set overlay info\n");
+ goto vout_isr_err;
+ }
+
/* Enable the pipeline and set the Go bit */
ret = omapvid_apply_changes(vout);
if (ret)
@@ -1660,13 +1663,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_VSYNC2;
- omap_dispc_register_isr(omap_vout_isr, vout, mask);
-
/* First save the configuration in ovelray structure */
ret = omapvid_init(vout, addr);
- if (ret)
+ if (ret) {
v4l2_err(&vout->vid_dev->v4l2_dev,
"failed to set overlay info\n");
+ goto streamon_err1;
+ }
+
+ omap_dispc_register_isr(omap_vout_isr, vout, mask);
+
/* Enable the pipeline and set the Go bit */
ret = omapvid_apply_changes(vout);
if (ret)
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 6e5ad8ec0a22..1d7dbd5c0fba 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -55,6 +55,7 @@
#include <asm/cacheflush.h>
#include <linux/clk.h>
+#include <linux/clkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
@@ -148,6 +149,201 @@ void omap3isp_flush(struct isp_device *isp)
isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
}
+/* -----------------------------------------------------------------------------
+ * XCLK
+ */
+
+#define to_isp_xclk(_hw) container_of(_hw, struct isp_xclk, hw)
+
+static void isp_xclk_update(struct isp_xclk *xclk, u32 divider)
+{
+ switch (xclk->id) {
+ case ISP_XCLK_A:
+ isp_reg_clr_set(xclk->isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ ISPTCTRL_CTRL_DIVA_MASK,
+ divider << ISPTCTRL_CTRL_DIVA_SHIFT);
+ break;
+ case ISP_XCLK_B:
+ isp_reg_clr_set(xclk->isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+ ISPTCTRL_CTRL_DIVB_MASK,
+ divider << ISPTCTRL_CTRL_DIVB_SHIFT);
+ break;
+ }
+}
+
+static int isp_xclk_prepare(struct clk_hw *hw)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+
+ omap3isp_get(xclk->isp);
+
+ return 0;
+}
+
+static void isp_xclk_unprepare(struct clk_hw *hw)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+
+ omap3isp_put(xclk->isp);
+}
+
+static int isp_xclk_enable(struct clk_hw *hw)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&xclk->lock, flags);
+ isp_xclk_update(xclk, xclk->divider);
+ xclk->enabled = true;
+ spin_unlock_irqrestore(&xclk->lock, flags);
+
+ return 0;
+}
+
+static void isp_xclk_disable(struct clk_hw *hw)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&xclk->lock, flags);
+ isp_xclk_update(xclk, 0);
+ xclk->enabled = false;
+ spin_unlock_irqrestore(&xclk->lock, flags);
+}
+
+static unsigned long isp_xclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+
+ return parent_rate / xclk->divider;
+}
+
+static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate)
+{
+ u32 divider;
+
+ if (*rate >= parent_rate) {
+ *rate = parent_rate;
+ return ISPTCTRL_CTRL_DIV_BYPASS;
+ }
+
+ divider = DIV_ROUND_CLOSEST(parent_rate, *rate);
+ if (divider >= ISPTCTRL_CTRL_DIV_BYPASS)
+ divider = ISPTCTRL_CTRL_DIV_BYPASS - 1;
+
+ *rate = parent_rate / divider;
+ return divider;
+}
+
+static long isp_xclk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ isp_xclk_calc_divider(&rate, *parent_rate);
+ return rate;
+}
+
+static int isp_xclk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct isp_xclk *xclk = to_isp_xclk(hw);
+ unsigned long flags;
+ u32 divider;
+
+ divider = isp_xclk_calc_divider(&rate, parent_rate);
+
+ spin_lock_irqsave(&xclk->lock, flags);
+
+ xclk->divider = divider;
+ if (xclk->enabled)
+ isp_xclk_update(xclk, divider);
+
+ spin_unlock_irqrestore(&xclk->lock, flags);
+
+ dev_dbg(xclk->isp->dev, "%s: cam_xclk%c set to %lu Hz (div %u)\n",
+ __func__, xclk->id == ISP_XCLK_A ? 'a' : 'b', rate, divider);
+ return 0;
+}
+
+static const struct clk_ops isp_xclk_ops = {
+ .prepare = isp_xclk_prepare,
+ .unprepare = isp_xclk_unprepare,
+ .enable = isp_xclk_enable,
+ .disable = isp_xclk_disable,
+ .recalc_rate = isp_xclk_recalc_rate,
+ .round_rate = isp_xclk_round_rate,
+ .set_rate = isp_xclk_set_rate,
+};
+
+static const char *isp_xclk_parent_name = "cam_mclk";
+
+static const struct clk_init_data isp_xclk_init_data = {
+ .name = "cam_xclk",
+ .ops = &isp_xclk_ops,
+ .parent_names = &isp_xclk_parent_name,
+ .num_parents = 1,
+};
+
+static int isp_xclk_init(struct isp_device *isp)
+{
+ struct isp_platform_data *pdata = isp->pdata;
+ struct clk_init_data init;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) {
+ struct isp_xclk *xclk = &isp->xclks[i];
+ struct clk *clk;
+
+ xclk->isp = isp;
+ xclk->id = i == 0 ? ISP_XCLK_A : ISP_XCLK_B;
+ xclk->divider = 1;
+ spin_lock_init(&xclk->lock);
+
+ init.name = i == 0 ? "cam_xclka" : "cam_xclkb";
+ init.ops = &isp_xclk_ops;
+ init.parent_names = &isp_xclk_parent_name;
+ init.num_parents = 1;
+
+ xclk->hw.init = &init;
+
+ clk = devm_clk_register(isp->dev, &xclk->hw);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (pdata->xclks[i].con_id == NULL &&
+ pdata->xclks[i].dev_id == NULL)
+ continue;
+
+ xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL);
+ if (xclk->lookup == NULL)
+ return -ENOMEM;
+
+ xclk->lookup->con_id = pdata->xclks[i].con_id;
+ xclk->lookup->dev_id = pdata->xclks[i].dev_id;
+ xclk->lookup->clk = clk;
+
+ clkdev_add(xclk->lookup);
+ }
+
+ return 0;
+}
+
+static void isp_xclk_cleanup(struct isp_device *isp)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) {
+ struct isp_xclk *xclk = &isp->xclks[i];
+
+ if (xclk->lookup)
+ clkdev_drop(xclk->lookup);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupts
+ */
+
/*
* isp_enable_interrupts - Enable ISP interrupts.
* @isp: OMAP3 ISP device
@@ -180,80 +376,6 @@ static void isp_disable_interrupts(struct isp_device *isp)
isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
}
-/**
- * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
- * @isp: OMAP3 ISP device
- * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high
- * @xclksel: XCLK to configure (0 = A, 1 = B).
- *
- * Configures the specified MCLK divisor in the ISP timing control register
- * (TCTRL_CTRL) to generate the desired xclk clock value.
- *
- * Divisor = cam_mclk_hz / xclk
- *
- * Returns the final frequency that is actually being generated
- **/
-static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
-{
- u32 divisor;
- u32 currentxclk;
- unsigned long mclk_hz;
-
- if (!omap3isp_get(isp))
- return 0;
-
- mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]);
-
- if (xclk >= mclk_hz) {
- divisor = ISPTCTRL_CTRL_DIV_BYPASS;
- currentxclk = mclk_hz;
- } else if (xclk >= 2) {
- divisor = mclk_hz / xclk;
- if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
- divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
- currentxclk = mclk_hz / divisor;
- } else {
- divisor = xclk;
- currentxclk = 0;
- }
-
- switch (xclksel) {
- case ISP_XCLK_A:
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
- ISPTCTRL_CTRL_DIVA_MASK,
- divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
- dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n",
- currentxclk);
- break;
- case ISP_XCLK_B:
- isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
- ISPTCTRL_CTRL_DIVB_MASK,
- divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
- dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n",
- currentxclk);
- break;
- case ISP_XCLK_NONE:
- default:
- omap3isp_put(isp);
- dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested "
- "xclk. Must be 0 (A) or 1 (B).\n");
- return -EINVAL;
- }
-
- /* Do we go from stable whatever to clock? */
- if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2)
- omap3isp_get(isp);
- /* Stopping the clock. */
- else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2)
- omap3isp_put(isp);
-
- isp->xclk_divisor[xclksel - 1] = divisor;
-
- omap3isp_put(isp);
-
- return currentxclk;
-}
-
/*
* isp_core_init - ISP core settings
* @isp: OMAP3 ISP device
@@ -1969,6 +2091,7 @@ static int isp_remove(struct platform_device *pdev)
isp_unregister_entities(isp);
isp_cleanup_modules(isp);
+ isp_xclk_cleanup(isp);
__omap3isp_get(isp, false);
iommu_detach_device(isp->domain, &pdev->dev);
@@ -2042,7 +2165,6 @@ static int isp_probe(struct platform_device *pdev)
}
isp->autoidle = autoidle;
- isp->platform_cb.set_xclk = isp_set_xclk;
mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock);
@@ -2093,6 +2215,10 @@ static int isp_probe(struct platform_device *pdev)
if (ret < 0)
goto error_isp;
+ ret = isp_xclk_init(isp);
+ if (ret < 0)
+ goto error_isp;
+
/* Memory resources */
for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++)
if (isp->revision == isp_res_maps[m].isp_rev)
@@ -2162,6 +2288,7 @@ detach_dev:
free_domain:
iommu_domain_free(isp->domain);
error_isp:
+ isp_xclk_cleanup(isp);
omap3isp_put(isp);
error:
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index c77e1f2ae5ca..cd3eff45ae7d 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -29,6 +29,7 @@
#include <media/omap3isp.h>
#include <media/v4l2-device.h>
+#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/iommu.h>
@@ -125,8 +126,20 @@ struct isp_reg {
u32 val;
};
-struct isp_platform_callback {
- u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel);
+enum isp_xclk_id {
+ ISP_XCLK_A,
+ ISP_XCLK_B,
+};
+
+struct isp_xclk {
+ struct isp_device *isp;
+ struct clk_hw hw;
+ struct clk_lookup *lookup;
+ enum isp_xclk_id id;
+
+ spinlock_t lock; /* Protects enabled and divider */
+ bool enabled;
+ unsigned int divider;
};
/*
@@ -149,6 +162,7 @@ struct isp_platform_callback {
* @cam_mclk: Pointer to camera functional clock structure.
* @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
* @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @xclks: External clocks provided by the ISP
* @irq: Currently attached ISP ISR callbacks information structure.
* @isp_af: Pointer to current settings for ISP AutoFocus SCM.
* @isp_hist: Pointer to current settings for ISP Histogram SCM.
@@ -185,12 +199,12 @@ struct isp_device {
int has_context;
int ref_count;
unsigned int autoidle;
- u32 xclk_divisor[2]; /* Two clocks, a and b. */
#define ISP_CLK_CAM_ICK 0
#define ISP_CLK_CAM_MCLK 1
#define ISP_CLK_CSI2_FCK 2
#define ISP_CLK_L3_ICK 3
struct clk *clock[4];
+ struct isp_xclk xclks[2];
/* ISP modules */
struct ispstat isp_af;
@@ -209,8 +223,6 @@ struct isp_device {
unsigned int subclk_resources;
struct iommu_domain *domain;
-
- struct isp_platform_callback platform_cb;
};
#define v4l2_dev_to_isp_device(dev) \
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index a55793c3d811..70438a0f62ae 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -934,12 +934,19 @@ static int s3c_camif_reqbufs(struct file *file, void *priv,
vp->owner = NULL;
ret = vb2_reqbufs(&vp->vb_queue, rb);
- if (!ret) {
- vp->reqbufs_count = rb->count;
- if (vp->owner == NULL && rb->count > 0)
- vp->owner = priv;
+ if (ret < 0)
+ return ret;
+
+ if (rb->count && rb->count < CAMIF_REQ_BUFS_MIN) {
+ rb->count = 0;
+ vb2_reqbufs(&vp->vb_queue, rb);
+ ret = -ENOMEM;
}
+ vp->reqbufs_count = rb->count;
+ if (vp->owner == NULL && rb->count > 0)
+ vp->owner = priv;
+
return ret;
}
@@ -1153,6 +1160,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct camif_buffer);
q->drv_priv = vp;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index aaaf276a5a6c..553d87e5ceab 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <media/v4l2-mem2mem.h>
@@ -157,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &g2d_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -168,6 +170,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &g2d_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -634,6 +637,9 @@ static irqreturn_t g2d_isr(int irq, void *prv)
BUG_ON(src == NULL);
BUG_ON(dst == NULL);
+ dst->v4l2_buf.timecode = src->v4l2_buf.timecode;
+ dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp;
+
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
@@ -695,11 +701,14 @@ static struct v4l2_m2m_ops g2d_m2m_ops = {
.unlock = g2d_unlock,
};
+static const struct of_device_id exynos_g2d_match[];
+
static int g2d_probe(struct platform_device *pdev)
{
struct g2d_dev *dev;
struct video_device *vfd;
struct resource *res;
+ const struct of_device_id *of_id;
int ret = 0;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -794,7 +803,17 @@ static int g2d_probe(struct platform_device *pdev)
}
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
- dev->variant = g2d_get_drv_data(pdev);
+
+ if (!pdev->dev.of_node) {
+ dev->variant = g2d_get_drv_data(pdev);
+ } else {
+ of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
+ if (!of_id) {
+ ret = -ENODEV;
+ goto unreg_video_dev;
+ }
+ dev->variant = (struct g2d_variant *)of_id->data;
+ }
return 0;
@@ -835,13 +854,25 @@ static int g2d_remove(struct platform_device *pdev)
}
static struct g2d_variant g2d_drvdata_v3x = {
- .hw_rev = TYPE_G2D_3X,
+ .hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */
};
static struct g2d_variant g2d_drvdata_v4x = {
.hw_rev = TYPE_G2D_4X, /* Revision 4.1 for Exynos4X12 and Exynos5 */
};
+static const struct of_device_id exynos_g2d_match[] = {
+ {
+ .compatible = "samsung,s5pv210-g2d",
+ .data = &g2d_drvdata_v3x,
+ }, {
+ .compatible = "samsung,exynos4212-g2d",
+ .data = &g2d_drvdata_v4x,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_g2d_match);
+
static struct platform_device_id g2d_driver_ids[] = {
{
.name = "s5p-g2d",
@@ -861,6 +892,7 @@ static struct platform_driver g2d_pdrv = {
.driver = {
.name = G2D_NAME,
.owner = THIS_MODULE,
+ .of_match_table = exynos_g2d_match,
},
};
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 3b023752bcb4..15d23968d1de 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1229,6 +1229,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &s5p_jpeg_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1240,6 +1241,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &s5p_jpeg_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_queue_init(dst_vq);
}
@@ -1287,6 +1289,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
payload_size = jpeg_compressed_size(jpeg->regs);
}
+ dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+ dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+
v4l2_m2m_buf_done(src_buf, state);
if (curr_ctx->mode == S5P_JPEG_ENCODE)
vb2_set_plane_payload(dst_buf, 0, payload_size);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index e84703c314ce..01f9ae0dadb0 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -243,12 +243,10 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
- memcpy(&dst_buf->b->v4l2_buf.timecode,
- &src_buf->b->v4l2_buf.timecode,
- sizeof(struct v4l2_timecode));
- memcpy(&dst_buf->b->v4l2_buf.timestamp,
- &src_buf->b->v4l2_buf.timestamp,
- sizeof(struct timeval));
+ dst_buf->b->v4l2_buf.timecode =
+ src_buf->b->v4l2_buf.timecode;
+ dst_buf->b->v4l2_buf.timestamp =
+ src_buf->b->v4l2_buf.timestamp;
switch (frame_type) {
case S5P_FIMV_DECODE_FRAME_I_FRAME:
dst_buf->b->v4l2_buf.flags |=
@@ -276,7 +274,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
unsigned int frame_type;
dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
- frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev);
+ frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx);
/* If frame is same as previous then skip and do not dequeue */
if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
@@ -386,6 +384,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
} else {
mfc_debug(2, "MFC needs next buffer\n");
ctx->consumed_stream = 0;
+ if (src_buf->flags & MFC_BUF_FLAG_EOS)
+ ctx->state = MFCINST_FINISHING;
list_del(&src_buf->list);
ctx->src_queue_cnt--;
if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0)
@@ -804,6 +804,7 @@ static int s5p_mfc_open(struct file *file)
goto err_queue_init;
}
q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
mfc_err("Failed to initialize videobuf2 queue(capture)\n");
@@ -825,6 +826,7 @@ static int s5p_mfc_open(struct file *file)
goto err_queue_init;
}
q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
mfc_err("Failed to initialize videobuf2 queue(output)\n");
@@ -1016,7 +1018,7 @@ static void *mfc_get_drv_data(struct platform_device *pdev);
static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev)
{
- unsigned int mem_info[2];
+ unsigned int mem_info[2] = { };
dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev,
sizeof(struct device), GFP_KERNEL);
@@ -1106,7 +1108,8 @@ static int s5p_mfc_probe(struct platform_device *pdev)
}
if (pdev->dev.of_node) {
- if (s5p_mfc_alloc_memdevs(dev) < 0)
+ ret = s5p_mfc_alloc_memdevs(dev);
+ if (ret < 0)
goto err_res;
} else {
dev->mem_dev_l = device_find_child(&dev->plat_dev->dev,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
index 138778083c63..ad4f1df0a18e 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
@@ -16,7 +16,7 @@
#include "s5p_mfc_debug.h"
/* This function is used to send a command to the MFC */
-int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
+static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
struct s5p_mfc_cmd_args *args)
{
int cur_cmd;
@@ -41,7 +41,7 @@ int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
}
/* Initialize the MFC */
-int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
@@ -52,7 +52,7 @@ int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev)
}
/* Suspend the MFC hardware */
-int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
@@ -61,7 +61,7 @@ int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev)
}
/* Wake up the MFC hardware */
-int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
@@ -71,7 +71,7 @@ int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev)
}
-int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_cmd_args h2r_args;
@@ -124,7 +124,7 @@ int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
return ret;
}
-int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_cmd_args h2r_args;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
index 754bfbcb1c43..5708fc3d9b4d 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
@@ -17,7 +17,7 @@
#include "s5p_mfc_intr.h"
#include "s5p_mfc_opr.h"
-int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
+static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
struct s5p_mfc_cmd_args *args)
{
mfc_debug(2, "Issue the command: %d\n", cmd);
@@ -32,7 +32,7 @@ int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd,
return 0;
}
-int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv;
@@ -44,7 +44,7 @@ int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev)
&h2r_args);
}
-int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
@@ -53,7 +53,7 @@ int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev)
&h2r_args);
}
-int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_cmd_args h2r_args;
@@ -63,7 +63,7 @@ int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev)
}
/* Open a new instance and get its number */
-int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_cmd_args h2r_args;
@@ -121,7 +121,7 @@ int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
}
/* Close instance */
-int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_cmd_args h2r_args;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 4582473978ca..4af53bd2f182 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -22,6 +22,7 @@
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/videobuf2-core.h>
#include "s5p_mfc_common.h"
#include "s5p_mfc_debug.h"
@@ -623,17 +624,27 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
/* Dequeue a buffer */
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
+ const struct v4l2_event ev = {
+ .type = V4L2_EVENT_EOS
+ };
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ int ret;
if (ctx->state == MFCINST_ERROR) {
mfc_err("Call on DQBUF after unrecoverable error\n");
return -EIO;
}
if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
- else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
- return -EINVAL;
+ ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
+ else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
+ if (ret == 0 && ctx->state == MFCINST_FINISHED &&
+ list_empty(&ctx->vq_dst.done_list))
+ v4l2_event_queue_fh(&ctx->fh, &ev);
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
}
/* Export DMA buffer */
@@ -809,6 +820,59 @@ static int vidioc_g_crop(struct file *file, void *priv,
return 0;
}
+int vidioc_decoder_cmd(struct file *file, void *priv,
+ struct v4l2_decoder_cmd *cmd)
+{
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ struct s5p_mfc_buf *buf;
+ unsigned long flags;
+
+ switch (cmd->cmd) {
+ case V4L2_ENC_CMD_STOP:
+ if (cmd->flags != 0)
+ return -EINVAL;
+
+ if (!ctx->vq_src.streaming)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->irqlock, flags);
+ if (list_empty(&ctx->src_queue)) {
+ mfc_err("EOS: empty src queue, entering finishing state");
+ ctx->state = MFCINST_FINISHING;
+ if (s5p_mfc_ctx_ready(ctx))
+ set_work_bit_irqsave(ctx);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ } else {
+ mfc_err("EOS: marking last buffer of stream");
+ buf = list_entry(ctx->src_queue.prev,
+ struct s5p_mfc_buf, list);
+ if (buf->flags & MFC_BUF_FLAG_USED)
+ ctx->state = MFCINST_FINISHING;
+ else
+ buf->flags |= MFC_BUF_FLAG_EOS;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 2, NULL);
+ default:
+ return -EINVAL;
+ }
+}
+
+
/* v4l2_ioctl_ops */
static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
@@ -830,6 +894,9 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_crop = vidioc_g_crop,
+ .vidioc_decoder_cmd = vidioc_decoder_cmd,
+ .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static int s5p_mfc_queue_setup(struct vb2_queue *vq,
@@ -1147,3 +1214,4 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
(unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
}
+
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 2356fd52a169..4f6b553c4b2d 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -232,6 +232,7 @@ static struct mfc_control controls[] = {
.minimum = 0,
.maximum = 1,
.default_value = 0,
+ .step = 1,
.menu_skip_mask = 0,
},
{
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index f61dba837899..0af05a2d1cd4 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -34,7 +34,7 @@
#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT)
/* Allocate temporary buffers for decoding */
-int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv;
@@ -55,13 +55,13 @@ int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx)
/* Release temporary buffers for decoding */
-void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx)
{
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->dsc);
}
/* Allocate codec buffers */
-int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int enc_ref_y_size = 0;
@@ -193,14 +193,14 @@ int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
}
/* Release buffers allocated for codec */
-void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx)
{
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1);
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_r, &ctx->bank2);
}
/* Allocate memory for instance data buffer */
-int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv;
@@ -241,20 +241,20 @@ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
}
/* Release instance buffer */
-void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx)
{
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx);
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->shm);
}
-int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
{
/* NOP */
return 0;
}
-void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
+static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev)
{
/* NOP */
}
@@ -273,7 +273,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx,
return readl(ctx->shm.virt + ofs);
}
-void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
{
unsigned int guard_width, guard_height;
@@ -315,7 +315,7 @@ void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx)
}
}
-void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx)
{
if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN);
@@ -361,8 +361,9 @@ static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
}
/* Set registers for decoding stream buffer */
-int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr,
- unsigned int start_num_byte, unsigned int buf_size)
+static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
+ int buf_addr, unsigned int start_num_byte,
+ unsigned int buf_size)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -374,7 +375,7 @@ int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr,
}
/* Set decoding frame buffer */
-int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
{
unsigned int frame_size, i;
unsigned int frame_size_ch, frame_size_mv;
@@ -506,7 +507,7 @@ int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx)
}
/* Set registers for encoding stream buffer */
-int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
+static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
unsigned long addr, unsigned int size)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -516,7 +517,7 @@ int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
return 0;
}
-void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
+static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
unsigned long y_addr, unsigned long c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -525,7 +526,7 @@ void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR);
}
-void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
+static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
unsigned long *y_addr, unsigned long *c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -537,7 +538,7 @@ void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
}
/* Set encoding ref & codec buffer */
-int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
size_t buf_addr1, buf_addr2;
@@ -1041,7 +1042,7 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
}
/* Initialize decoding */
-int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1077,7 +1078,7 @@ static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
}
/* Decode a single frame */
-int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx,
+static int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx,
enum s5p_mfc_decode_arg last_frame)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1106,7 +1107,7 @@ int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx,
return 0;
}
-int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1128,7 +1129,7 @@ int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx)
}
/* Encode a single frame */
-int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
int cmd;
@@ -1187,6 +1188,15 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
unsigned long flags;
unsigned int index;
+ if (ctx->state == MFCINST_FINISHING) {
+ last_frame = MFC_DEC_LAST_FRAME;
+ s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame_v5(ctx, last_frame);
+ return 0;
+ }
+
spin_lock_irqsave(&dev->irqlock, flags);
/* Frames are being decoded */
if (list_empty(&ctx->src_queue)) {
@@ -1353,7 +1363,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
}
/* Try running an operation on hardware */
-void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
+static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_ctx *ctx;
int new_ctx;
@@ -1469,7 +1479,7 @@ void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
}
-void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq)
+static void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq)
{
struct s5p_mfc_buf *b;
int i;
@@ -1483,52 +1493,52 @@ void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq)
}
}
-void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev)
+static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev)
{
mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID);
}
-int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT;
}
-int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT;
}
-int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS);
}
-int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS);
}
-int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) &
S5P_FIMV_DECODE_FRAME_MASK;
}
-int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx)
{
return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >>
S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) &
S5P_FIMV_DECODE_FRAME_MASK;
}
-int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES);
}
-int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev)
{
int reason;
reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) &
@@ -1576,98 +1586,98 @@ int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev)
return reason;
}
-int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2);
}
-int s5p_mfc_err_dec_v5(unsigned int err)
+static int s5p_mfc_err_dec_v5(unsigned int err)
{
return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT;
}
-int s5p_mfc_err_dspl_v5(unsigned int err)
+static int s5p_mfc_err_dspl_v5(unsigned int err)
{
return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT;
}
-int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_HRESOL);
}
-int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_VRESOL);
}
-int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER);
}
-int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev)
{
/* NOP */
return -1;
}
-int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1);
}
-int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE);
}
-int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE);
}
-int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev)
{
return -1;
}
-int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT);
}
-int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL);
}
-int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev)
{
return -1;
}
-int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev)
{
return -1;
}
-unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP);
}
-unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT);
}
-unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, CROP_INFO_H);
}
-unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, CROP_INFO_V);
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index beb6dbacebd9..7e76fce2e524 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -49,7 +49,7 @@
#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET)
/* Allocate temporary buffers for decoding */
-int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx)
{
/* NOP */
@@ -57,19 +57,19 @@ int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx)
}
/* Release temproary buffers for decoding */
-void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx)
{
/* NOP */
}
-int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
{
/* NOP */
return -1;
}
/* Allocate codec buffers */
-int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int mb_width, mb_height;
@@ -203,13 +203,13 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
}
/* Release buffers allocated for codec */
-void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1);
}
/* Allocate memory for instance data buffer */
-int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv;
@@ -258,13 +258,13 @@ int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
}
/* Release instance buffer */
-void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx)
{
s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx);
}
/* Allocate context buffers for SYS_INIT */
-int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv;
int ret;
@@ -287,7 +287,7 @@ int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
}
/* Release context buffers for SYS_INIT */
-void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
+static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev)
{
s5p_mfc_release_priv_buf(dev->mem_dev_l, &dev->ctx_buf);
}
@@ -306,7 +306,7 @@ static int calc_plane(int width, int height)
(mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6);
}
-void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
{
ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
@@ -326,7 +326,7 @@ void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
}
}
-void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
{
unsigned int mb_width, mb_height;
@@ -339,8 +339,9 @@ void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
}
/* Set registers for decoding stream buffer */
-int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr,
- unsigned int start_num_byte, unsigned int strm_size)
+static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
+ int buf_addr, unsigned int start_num_byte,
+ unsigned int strm_size)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
@@ -359,7 +360,7 @@ int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr,
}
/* Set decoding frame buffer */
-int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
{
unsigned int frame_size, i;
unsigned int frame_size_ch, frame_size_mv;
@@ -440,7 +441,7 @@ int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
}
/* Set registers for encoding stream buffer */
-int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
+static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long addr, unsigned int size)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -454,7 +455,7 @@ int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
return 0;
}
-void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
+static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long y_addr, unsigned long c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -466,7 +467,7 @@ void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr);
}
-void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
+static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long *y_addr, unsigned long *c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -483,7 +484,7 @@ void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
}
/* Set encoding ref & codec buffer */
-int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
size_t buf_addr1;
@@ -1147,7 +1148,7 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
}
/* Initialize decoding */
-int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int reg = 0;
@@ -1215,7 +1216,7 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
}
/* Decode a single frame */
-int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
+static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
enum s5p_mfc_decode_arg last_frame)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1244,7 +1245,7 @@ int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
return 0;
}
-int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1267,7 +1268,7 @@ int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
return 0;
}
-int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
@@ -1283,7 +1284,7 @@ int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
}
/* Encode a single frame */
-int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1312,7 +1313,7 @@ static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
int cnt;
spin_lock_irqsave(&dev->condlock, flags);
- mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx,
+ mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx,
dev->ctx_work_bits);
new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
cnt = 0;
@@ -1362,8 +1363,16 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
unsigned long flags;
int last_frame = 0;
- spin_lock_irqsave(&dev->irqlock, flags);
+ if (ctx->state == MFCINST_FINISHING) {
+ last_frame = MFC_DEC_LAST_FRAME;
+ s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0);
+ dev->curr_ctx = ctx->num;
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_decode_one_frame_v6(ctx, last_frame);
+ return 0;
+ }
+ spin_lock_irqsave(&dev->irqlock, flags);
/* Frames are being decoded */
if (list_empty(&ctx->src_queue)) {
mfc_debug(2, "No src buffers.\n");
@@ -1540,7 +1549,7 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx)
}
/* Try running an operation on hardware */
-void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
+static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_ctx *ctx;
int new_ctx;
@@ -1663,7 +1672,7 @@ void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
}
-void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
+static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
{
struct s5p_mfc_buf *b;
int i;
@@ -1677,13 +1686,13 @@ void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
}
}
-void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
+static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
{
mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6);
}
-void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
+static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
unsigned int ofs)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1693,7 +1702,8 @@ void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
s5p_mfc_clock_off();
}
-unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
+static unsigned int
+s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
{
struct s5p_mfc_dev *dev = ctx->dev;
int ret;
@@ -1705,140 +1715,140 @@ unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
return ret;
}
-int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6);
}
-int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6);
}
-int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6);
}
-int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6);
}
-int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) &
S5P_FIMV_DECODE_FRAME_MASK_V6;
}
-int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
{
return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) &
S5P_FIMV_DECODE_FRAME_MASK_V6;
}
-int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6);
}
-int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) &
S5P_FIMV_RISC2HOST_CMD_MASK;
}
-int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6);
}
-int s5p_mfc_err_dec_v6(unsigned int err)
+static int s5p_mfc_err_dec_v6(unsigned int err)
{
return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6;
}
-int s5p_mfc_err_dspl_v6(unsigned int err)
+static int s5p_mfc_err_dspl_v6(unsigned int err)
{
return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6;
}
-int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6);
}
-int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6);
}
-int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6);
}
-int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6);
}
-int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6);
}
-int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6);
}
-int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6);
}
-int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6);
}
-int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6);
}
-int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
+static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
{
return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6);
}
-int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6);
}
-int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
+static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6);
}
-unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6);
}
-unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6);
}
-unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6);
}
-unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
+static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6);
}
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 8de1b3dce459..4e86626dad4b 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -31,6 +31,7 @@
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
+#include <linux/v4l2-dv-timings.h>
#include <media/s5p_hdmi.h>
#include <media/v4l2-common.h>
@@ -43,9 +44,6 @@ MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
MODULE_DESCRIPTION("Samsung HDMI");
MODULE_LICENSE("GPL");
-/* default preset configured on probe */
-#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
-
struct hdmi_pulse {
u32 beg;
u32 end;
@@ -91,8 +89,8 @@ struct hdmi_device {
const struct hdmi_timings *cur_conf;
/** flag indicating that timings are dirty */
int cur_conf_dirty;
- /** current preset */
- u32 cur_preset;
+ /** current timings */
+ struct v4l2_dv_timings cur_timings;
/** other resources */
struct hdmi_resources res;
};
@@ -252,7 +250,6 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
{
struct device *dev = hdmi_dev->dev;
const struct hdmi_timings *conf = hdmi_dev->cur_conf;
- struct v4l2_dv_preset preset;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -267,11 +264,11 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT);
mdelay(10);
- /* configure presets */
- preset.preset = hdmi_dev->cur_preset;
- ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset);
+ /* configure timings */
+ ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_timings,
+ &hdmi_dev->cur_timings);
if (ret) {
- dev_err(dev, "failed to set preset (%u)\n", preset.preset);
+ dev_err(dev, "failed to set timings\n");
return ret;
}
@@ -475,33 +472,26 @@ static const struct hdmi_timings hdmi_timings_1080p50 = {
.vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
};
+/* default hdmi_timings index of the timings configured on probe */
+#define HDMI_DEFAULT_TIMINGS_IDX (0)
+
static const struct {
- u32 preset;
- const struct hdmi_timings *timings;
+ bool reduced_fps;
+ const struct v4l2_dv_timings dv_timings;
+ const struct hdmi_timings *hdmi_timings;
} hdmi_timings[] = {
- { V4L2_DV_480P59_94, &hdmi_timings_480p },
- { V4L2_DV_576P50, &hdmi_timings_576p50 },
- { V4L2_DV_720P50, &hdmi_timings_720p50 },
- { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
- { V4L2_DV_720P60, &hdmi_timings_720p60 },
- { V4L2_DV_1080P24, &hdmi_timings_1080p24 },
- { V4L2_DV_1080P30, &hdmi_timings_1080p60 },
- { V4L2_DV_1080P50, &hdmi_timings_1080p50 },
- { V4L2_DV_1080I50, &hdmi_timings_1080i50 },
- { V4L2_DV_1080I60, &hdmi_timings_1080i60 },
- { V4L2_DV_1080P60, &hdmi_timings_1080p60 },
+ { false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p },
+ { false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 },
+ { false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 },
+ { true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 },
+ { false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 },
+ { false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 },
+ { false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 },
+ { false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 },
};
-static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
- if (hdmi_timings[i].preset == preset)
- return hdmi_timings[i].timings;
- return NULL;
-}
-
static int hdmi_streamon(struct hdmi_device *hdev)
{
struct device *dev = hdev->dev;
@@ -621,29 +611,33 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on)
return IS_ERR_VALUE(ret) ? ret : 0;
}
-static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
struct device *dev = hdev->dev;
- const struct hdmi_timings *conf;
+ int i;
- conf = hdmi_preset2timings(preset->preset);
- if (conf == NULL) {
- dev_err(dev, "preset (%u) not supported\n", preset->preset);
+ for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
+ if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings,
+ timings, 0))
+ break;
+ if (i == ARRAY_SIZE(hdmi_timings)) {
+ dev_err(dev, "timings not supported\n");
return -EINVAL;
}
- hdev->cur_conf = conf;
+ hdev->cur_conf = hdmi_timings[i].hdmi_timings;
hdev->cur_conf_dirty = 1;
- hdev->cur_preset = preset->preset;
+ hdev->cur_timings = *timings;
+ if (!hdmi_timings[i].reduced_fps)
+ hdev->cur_timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
return 0;
}
-static int hdmi_g_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmi_g_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
- memset(preset, 0, sizeof(*preset));
- preset->preset = sd_to_hdmi_dev(sd)->cur_preset;
+ *timings = sd_to_hdmi_dev(sd)->cur_timings;
return 0;
}
@@ -670,13 +664,33 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
- struct v4l2_dv_enum_preset *preset)
+static int hdmi_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
{
- if (preset->index >= ARRAY_SIZE(hdmi_timings))
+ if (timings->index >= ARRAY_SIZE(hdmi_timings))
return -EINVAL;
- return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
- preset);
+ timings->timings = hdmi_timings[timings->index].dv_timings;
+ if (!hdmi_timings[timings->index].reduced_fps)
+ timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS;
+ return 0;
+}
+
+static int hdmi_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+
+ /* Let the phy fill in the pixelclock range */
+ v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap);
+ cap->type = V4L2_DV_BT_656_1120;
+ cap->bt.min_width = 720;
+ cap->bt.max_width = 1920;
+ cap->bt.min_height = 480;
+ cap->bt.max_height = 1080;
+ cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+ cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED |
+ V4L2_DV_BT_CAP_PROGRESSIVE;
+ return 0;
}
static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
@@ -684,9 +698,10 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
};
static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
- .s_dv_preset = hdmi_s_dv_preset,
- .g_dv_preset = hdmi_g_dv_preset,
- .enum_dv_presets = hdmi_enum_dv_presets,
+ .s_dv_timings = hdmi_s_dv_timings,
+ .g_dv_timings = hdmi_g_dv_timings,
+ .enum_dv_timings = hdmi_enum_dv_timings,
+ .dv_timings_cap = hdmi_dv_timings_cap,
.g_mbus_fmt = hdmi_g_mbus_fmt,
.s_stream = hdmi_s_stream,
};
@@ -956,9 +971,11 @@ static int hdmi_probe(struct platform_device *pdev)
sd->owner = THIS_MODULE;
strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name));
- hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
- /* FIXME: missing fail preset is not supported */
- hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+ hdmi_dev->cur_timings =
+ hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].dv_timings;
+ /* FIXME: missing fail timings is not supported */
+ hdmi_dev->cur_conf =
+ hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].hdmi_timings;
hdmi_dev->cur_conf_dirty = 1;
/* storing subdev for call that have only access to struct device */
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
index 80717cec76ae..e19a0af1ea4f 100644
--- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
@@ -176,35 +176,9 @@ static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd)
return container_of(sd, struct hdmiphy_ctx, sd);
}
-static unsigned long hdmiphy_preset_to_pixclk(u32 preset)
+static const u8 *hdmiphy_find_conf(unsigned long pixclk,
+ const struct hdmiphy_conf *conf)
{
- static const unsigned long pixclk[] = {
- [V4L2_DV_480P59_94] = 27000000,
- [V4L2_DV_576P50] = 27000000,
- [V4L2_DV_720P59_94] = 74176000,
- [V4L2_DV_720P50] = 74250000,
- [V4L2_DV_720P60] = 74250000,
- [V4L2_DV_1080P24] = 74250000,
- [V4L2_DV_1080P30] = 74250000,
- [V4L2_DV_1080I50] = 74250000,
- [V4L2_DV_1080I60] = 74250000,
- [V4L2_DV_1080P50] = 148500000,
- [V4L2_DV_1080P60] = 148500000,
- };
- if (preset < ARRAY_SIZE(pixclk))
- return pixclk[preset];
- else
- return 0;
-}
-
-static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf)
-{
- unsigned long pixclk;
-
- pixclk = hdmiphy_preset_to_pixclk(preset);
- if (!pixclk)
- return NULL;
-
for (; conf->pixclk; ++conf)
if (conf->pixclk == pixclk)
return conf->data;
@@ -217,8 +191,8 @@ static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
return 0;
}
-static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset)
+static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
const u8 *data;
u8 buffer[32];
@@ -226,9 +200,12 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
+ unsigned long pixclk = timings->bt.pixelclock;
- dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
- data = hdmiphy_find_conf(preset->preset, ctx->conf_tab);
+ dev_info(dev, "s_dv_timings\n");
+ if ((timings->bt.flags & V4L2_DV_FL_REDUCED_FPS) && pixclk == 74250000)
+ pixclk = 74176000;
+ data = hdmiphy_find_conf(pixclk, ctx->conf_tab);
if (!data) {
dev_err(dev, "format not supported\n");
return -EINVAL;
@@ -245,6 +222,17 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
return 0;
}
+static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap)
+{
+ cap->type = V4L2_DV_BT_656_1120;
+ /* The phy only determines the pixelclock, leave the other values
+ * at 0 to signify that we have no information for them. */
+ cap->bt.min_pixelclock = 27000000;
+ cap->bt.max_pixelclock = 148500000;
+ return 0;
+}
+
static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -270,7 +258,8 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
};
static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
- .s_dv_preset = hdmiphy_s_dv_preset,
+ .s_dv_timings = hdmiphy_s_dv_timings,
+ .dv_timings_cap = hdmiphy_dv_timings_cap,
.s_stream = hdmiphy_s_stream,
};
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index 82142a2d6d93..ef0efdf422fe 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -501,8 +501,8 @@ fail:
return -ERANGE;
}
-static int mxr_enum_dv_presets(struct file *file, void *fh,
- struct v4l2_dv_enum_preset *preset)
+static int mxr_enum_dv_timings(struct file *file, void *fh,
+ struct v4l2_enum_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -510,14 +510,14 @@ static int mxr_enum_dv_presets(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_timings, timings);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
}
-static int mxr_s_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
+static int mxr_s_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -526,7 +526,7 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- /* preset change cannot be done while there is an entity
+ /* timings change cannot be done while there is an entity
* dependant on output configuration
*/
if (mdev->n_output > 0) {
@@ -534,7 +534,7 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
return -EBUSY;
}
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_timings, timings);
mutex_unlock(&mdev->mutex);
@@ -544,8 +544,8 @@ static int mxr_s_dv_preset(struct file *file, void *fh,
return ret ? -EINVAL : 0;
}
-static int mxr_g_dv_preset(struct file *file, void *fh,
- struct v4l2_dv_preset *preset)
+static int mxr_g_dv_timings(struct file *file, void *fh,
+ struct v4l2_dv_timings *timings)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -553,13 +553,28 @@ static int mxr_g_dv_preset(struct file *file, void *fh,
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_timings, timings);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
}
-static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+static int mxr_dv_timings_cap(struct file *file, void *fh,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct mxr_layer *layer = video_drvdata(file);
+ struct mxr_device *mdev = layer->mdev;
+ int ret;
+
+ /* lock protects from changing sd_out */
+ mutex_lock(&mdev->mutex);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, dv_timings_cap, cap);
+ mutex_unlock(&mdev->mutex);
+
+ return ret ? -EINVAL : 0;
+}
+
+static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm)
{
struct mxr_layer *layer = video_drvdata(file);
struct mxr_device *mdev = layer->mdev;
@@ -576,7 +591,7 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm)
return -EBUSY;
}
- ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm);
+ ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, norm);
mutex_unlock(&mdev->mutex);
@@ -616,8 +631,8 @@ static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a)
/* try to obtain supported tv norms */
v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std);
a->capabilities = 0;
- if (sd->ops->video && sd->ops->video->s_dv_preset)
- a->capabilities |= V4L2_OUT_CAP_PRESETS;
+ if (sd->ops->video && sd->ops->video->s_dv_timings)
+ a->capabilities |= V4L2_OUT_CAP_DV_TIMINGS;
if (sd->ops->video && sd->ops->video->s_std_output)
a->capabilities |= V4L2_OUT_CAP_STD;
a->type = V4L2_OUTPUT_TYPE_ANALOG;
@@ -738,10 +753,11 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = {
/* Streaming control */
.vidioc_streamon = mxr_streamon,
.vidioc_streamoff = mxr_streamoff,
- /* Preset functions */
- .vidioc_enum_dv_presets = mxr_enum_dv_presets,
- .vidioc_s_dv_preset = mxr_s_dv_preset,
- .vidioc_g_dv_preset = mxr_g_dv_preset,
+ /* DV Timings functions */
+ .vidioc_enum_dv_timings = mxr_enum_dv_timings,
+ .vidioc_s_dv_timings = mxr_s_dv_timings,
+ .vidioc_g_dv_timings = mxr_g_dv_timings,
+ .vidioc_dv_timings_cap = mxr_dv_timings_cap,
/* analog TV standard functions */
.vidioc_s_std = mxr_s_std,
.vidioc_g_std = mxr_g_std,
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index d90d2286090b..39b77d24b9c2 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -23,9 +23,6 @@
#include <linux/regulator/machine.h>
#include <linux/slab.h>
-#include <mach/gpio.h>
-#include <plat/gpio-cfg.h>
-
#include <media/sii9234.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index cb54c69d5748..0b32cc3f6a47 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation
*/
+#include <linux/err.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -1164,9 +1165,9 @@ static int sh_veu_probe(struct platform_device *pdev)
veu->is_2h = resource_size(reg_res) == 0x22c;
- veu->base = devm_request_and_ioremap(&pdev->dev, reg_res);
- if (!veu->base)
- return -ENOMEM;
+ veu->base = devm_ioremap_resource(&pdev->dev, reg_res);
+ if (IS_ERR(veu->base))
+ return PTR_ERR(veu->base);
ret = devm_request_threaded_irq(&pdev->dev, irq, sh_veu_isr, sh_veu_bh,
0, "veu", veu);
@@ -1248,18 +1249,7 @@ static struct platform_driver __refdata sh_veu_pdrv = {
},
};
-static int __init sh_veu_init(void)
-{
- return platform_driver_probe(&sh_veu_pdrv, sh_veu_probe);
-}
-
-static void __exit sh_veu_exit(void)
-{
- platform_driver_unregister(&sh_veu_pdrv);
-}
-
-module_init(sh_veu_init);
-module_exit(sh_veu_exit);
+module_platform_driver_probe(sh_veu_pdrv, sh_veu_probe);
MODULE_DESCRIPTION("sh-mobile VEU mem2mem driver");
MODULE_AUTHOR("Guennadi Liakhovetski, <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 66c8da18df84..7d0235069c87 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -881,29 +881,29 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt)
}
}
-static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
struct sh_vou_device *vou_dev = video_drvdata(file);
int ret;
- dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id);
+ dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id);
- if (*std_id & ~vou_dev->vdev->tvnorms)
+ if (std_id & ~vou_dev->vdev->tvnorms)
return -EINVAL;
ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video,
- s_std_output, *std_id);
+ s_std_output, std_id);
/* Shall we continue, if the subdev doesn't support .s_std_output()? */
if (ret < 0 && ret != -ENOIOCTLCMD)
return ret;
- if (*std_id & V4L2_STD_525_60)
+ if (std_id & V4L2_STD_525_60)
sh_vou_reg_ab_set(vou_dev, VOUCR,
sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29);
else
sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29);
- vou_dev->std = *std_id;
+ vou_dev->std = std_id;
return 0;
}
@@ -1266,7 +1266,7 @@ static int sh_vou_g_register(struct file *file, void *fh,
}
static int sh_vou_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct sh_vou_device *vou_dev = video_drvdata(file);
@@ -1485,18 +1485,7 @@ static struct platform_driver __refdata sh_vou = {
},
};
-static int __init sh_vou_init(void)
-{
- return platform_driver_probe(&sh_vou, sh_vou_probe);
-}
-
-static void __exit sh_vou_exit(void)
-{
- platform_driver_unregister(&sh_vou);
-}
-
-module_init(sh_vou_init);
-module_exit(sh_vou_exit);
+module_platform_driver_probe(sh_vou, sh_vou_probe);
MODULE_DESCRIPTION("SuperH VOU driver");
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 82dbf99d347c..1abbb36d0755 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -514,6 +514,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q,
q->buf_struct_size = sizeof(struct frame_buffer);
q->ops = &isi_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
@@ -1020,7 +1021,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ if (IS_ERR_VALUE(irq)) {
ret = irq;
goto err_req_irq;
}
@@ -1073,7 +1074,6 @@ err_clk_prepare_pclk:
}
static struct platform_driver atmel_isi_driver = {
- .probe = atmel_isi_probe,
.remove = atmel_isi_remove,
.driver = {
.name = "atmel_isi",
@@ -1081,17 +1081,7 @@ static struct platform_driver atmel_isi_driver = {
},
};
-static int __init atmel_isi_init_module(void)
-{
- return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe);
-}
-
-static void __exit atmel_isi_exit(void)
-{
- platform_driver_unregister(&atmel_isi_driver);
-}
-module_init(atmel_isi_init_module);
-module_exit(atmel_isi_exit);
+module_platform_driver_probe(atmel_isi_driver, atmel_isi_probe);
MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index 25b2a285dc86..a3fd8d63546c 100644
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
@@ -776,7 +776,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
/* request irq */
err = claim_fiq(&fh);
if (err) {
- dev_err(&pdev->dev, "Camera interrupt register failed \n");
+ dev_err(&pdev->dev, "Camera interrupt register failed\n");
goto exit_free_dma;
}
@@ -853,24 +853,13 @@ static int __exit mx1_camera_remove(struct platform_device *pdev)
}
static struct platform_driver mx1_camera_driver = {
- .driver = {
+ .driver = {
.name = DRIVER_NAME,
},
.remove = __exit_p(mx1_camera_remove),
};
-static int __init mx1_camera_init(void)
-{
- return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe);
-}
-
-static void __exit mx1_camera_exit(void)
-{
- return platform_driver_unregister(&mx1_camera_driver);
-}
-
-module_init(mx1_camera_init);
-module_exit(mx1_camera_exit);
+module_platform_driver_probe(mx1_camera_driver, mx1_camera_probe);
MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver");
MODULE_AUTHOR("Paulius Zaleckas <paulius.zaleckas@teltonika.lt>");
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index ffba7d91f413..5bbeb43e4531 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -797,6 +797,7 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q,
q->ops = &mx2_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mx2_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
@@ -1453,7 +1454,7 @@ static int mx27_camera_emma_init(struct platform_device *pdev)
err = devm_request_irq(pcdev->dev, irq_emma, mx27_camera_emma_irq, 0,
MX2_CAM_DRV_NAME, pcdev);
if (err) {
- dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
+ dev_err(pcdev->dev, "Camera EMMA interrupt register failed\n");
goto out;
}
@@ -1614,15 +1615,14 @@ static int mx2_camera_remove(struct platform_device *pdev)
}
static struct platform_driver mx2_camera_driver = {
- .driver = {
+ .driver = {
.name = MX2_CAM_DRV_NAME,
},
.id_table = mx2_camera_devtype,
.remove = mx2_camera_remove,
- .probe = mx2_camera_probe,
};
-module_platform_driver(mx2_camera_driver);
+module_platform_driver_probe(mx2_camera_driver, mx2_camera_probe);
MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver");
MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index f5cbb92db545..5da337736cd8 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -455,6 +455,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q,
q->ops = &mx3_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mx3_camera_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
@@ -1275,7 +1276,7 @@ static int mx3_camera_remove(struct platform_device *pdev)
}
static struct platform_driver mx3_camera_driver = {
- .driver = {
+ .driver = {
.name = MX3_CAM_DRV_NAME,
},
.probe = mx3_camera_probe,
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index 2547bf88f79f..9689a6e89b7f 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -1546,7 +1546,7 @@ static struct soc_camera_host_ops omap1_host_ops = {
.poll = omap1_cam_poll,
};
-static int __init omap1_cam_probe(struct platform_device *pdev)
+static int omap1_cam_probe(struct platform_device *pdev)
{
struct omap1_cam_dev *pcdev;
struct resource *res;
@@ -1677,7 +1677,7 @@ exit:
return err;
}
-static int __exit omap1_cam_remove(struct platform_device *pdev)
+static int omap1_cam_remove(struct platform_device *pdev)
{
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct omap1_cam_dev *pcdev = container_of(soc_host,
@@ -1709,7 +1709,7 @@ static struct platform_driver omap1_cam_driver = {
.name = DRIVER_NAME,
},
.probe = omap1_cam_probe,
- .remove = __exit_p(omap1_cam_remove),
+ .remove = omap1_cam_remove,
};
module_platform_driver(omap1_cam_driver);
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 395e2e043615..d665242e8207 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
@@ -1710,9 +1711,10 @@ static int pxa_camera_probe(struct platform_device *pdev)
/*
* Request the regions.
*/
- base = devm_request_and_ioremap(&pdev->dev, res);
- if (!base)
- return -ENOMEM;
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
pcdev->irq = irq;
pcdev->base = base;
@@ -1794,13 +1796,13 @@ static int pxa_camera_remove(struct platform_device *pdev)
return 0;
}
-static struct dev_pm_ops pxa_camera_pm = {
+static const struct dev_pm_ops pxa_camera_pm = {
.suspend = pxa_camera_suspend,
.resume = pxa_camera_resume,
};
static struct platform_driver pxa_camera_driver = {
- .driver = {
+ .driver = {
.name = PXA_CAM_DRV_NAME,
.pm = &pxa_camera_pm,
},
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index bb08a46432f4..143d29fe0137 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -20,6 +20,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
@@ -2026,6 +2027,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
q->ops = &sh_mobile_ceu_videobuf_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
return vb2_queue_init(q);
}
@@ -2110,11 +2112,9 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
pcdev->max_width = pcdev->pdata->max_width ? : 2560;
pcdev->max_height = pcdev->pdata->max_height ? : 1920;
- base = devm_request_and_ioremap(&pdev->dev, res);
- if (!base) {
- dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
- return -ENXIO;
- }
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
pcdev->irq = irq;
pcdev->base = base;
@@ -2288,7 +2288,7 @@ static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = {
};
static struct platform_driver sh_mobile_ceu_driver = {
- .driver = {
+ .driver = {
.name = "sh_mobile_ceu",
.pm = &sh_mobile_ceu_dev_pm_ops,
},
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index 42c559eb4937..09cb4fc88f34 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -9,6 +9,7 @@
*/
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/platform_device.h>
@@ -324,11 +325,9 @@ static int sh_csi2_probe(struct platform_device *pdev)
priv->irq = irq;
- priv->base = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv->base) {
- dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
- return -ENXIO;
- }
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
priv->pdev = pdev;
platform_set_drvdata(pdev, priv);
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 8ec98051ea73..eea832c5fd01 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -256,12 +256,12 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
+static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a)
{
struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, core, s_std, *a);
+ return v4l2_subdev_call(sd, core, s_std, a);
}
static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
@@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
static int soc_camera_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
- struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+ struct soc_camera_device *icd;
struct soc_camera_host *ici;
int ret;
- if (!to_soc_camera_control(icd))
- /* No device driver attached */
- return -ENODEV;
-
/*
* Don't mess with the host during probe: wait until the loop in
- * scan_add_host() completes
+ * scan_add_host() completes. Also protect against a race with
+ * soc_camera_host_unregister().
*/
if (mutex_lock_interruptible(&list_lock))
return -ERESTARTSYS;
+
+ if (!vdev || !video_is_registered(vdev)) {
+ mutex_unlock(&list_lock);
+ return -ENODEV;
+ }
+
+ icd = dev_get_drvdata(vdev->parent);
ici = to_soc_camera_host(icd->parent);
+
+ ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
mutex_unlock(&list_lock);
- if (mutex_lock_interruptible(&ici->host_lock))
- return -ERESTARTSYS;
- if (!try_module_get(ici->ops->owner)) {
+ if (ret < 0) {
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
- ret = -EINVAL;
- goto emodule;
+ return ret;
}
+ if (!to_soc_camera_control(icd)) {
+ /* No device driver attached */
+ ret = -ENODEV;
+ goto econtrol;
+ }
+
+ if (mutex_lock_interruptible(&ici->host_lock)) {
+ ret = -ERESTARTSYS;
+ goto elockhost;
+ }
icd->use_count++;
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
/* Restore parameters before the last close() per V4L2 API */
struct v4l2_format f = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -609,9 +622,10 @@ epower:
ici->ops->remove(icd);
eiciadd:
icd->use_count--;
- module_put(ici->ops->owner);
-emodule:
mutex_unlock(&ici->host_lock);
+elockhost:
+econtrol:
+ module_put(ici->ops->owner);
return ret;
}
@@ -1042,7 +1056,7 @@ static int soc_camera_g_register(struct file *file, void *fh,
}
static int soc_camera_s_register(struct file *file, void *fh,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index ce3b1d6a4734..1b7a88ca195b 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -188,7 +188,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev)
}
static struct platform_driver soc_camera_platform_driver = {
- .driver = {
+ .driver = {
.name = "soc_camera_platform",
.owner = THIS_MODULE,
},
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index 89dce097a827..dc02deca7563 100644
--- a/drivers/media/platform/soc_camera/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
@@ -73,7 +73,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_LE,
+ .order = SOC_MBUS_ORDER_BE,
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
@@ -93,10 +93,46 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
- .order = SOC_MBUS_ORDER_LE,
+ .order = SOC_MBUS_ORDER_BE,
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
+ .code = V4L2_MBUS_FMT_RGB666_1X18,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "RGB666/32bpp",
+ .bits_per_sample = 18,
+ .packing = SOC_MBUS_PACKING_EXTEND32,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB888_1X24,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "RGB888/32bpp",
+ .bits_per_sample = 24,
+ .packing = SOC_MBUS_PACKING_EXTEND32,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB888_2X12_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "RGB888/32bpp",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND32,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB888_2X12_LE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "RGB888/32bpp",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND32,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
.code = V4L2_MBUS_FMT_SBGGR8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR8,
@@ -358,6 +394,10 @@ int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
*numerator = 1;
*denominator = 1;
return 0;
+ case SOC_MBUS_PACKING_EXTEND32:
+ *numerator = 1;
+ *denominator = 1;
+ return 0;
case SOC_MBUS_PACKING_2X8_PADHI:
case SOC_MBUS_PACKING_2X8_PADLO:
*numerator = 2;
@@ -392,6 +432,8 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
return width * 3 / 2;
case SOC_MBUS_PACKING_VARIABLE:
return 0;
+ case SOC_MBUS_PACKING_EXTEND32:
+ return width * 4;
}
return -EINVAL;
}
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index c3a2a4484401..a2f7bdd5104f 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -78,7 +78,7 @@ struct timblogiw_buffer {
struct timblogiw_fh *fh;
};
-const struct timblogiw_tvnorm timblogiw_tvnorms[] = {
+static const struct timblogiw_tvnorm timblogiw_tvnorms[] = {
{
.std = V4L2_STD_PAL,
.width = 720,
@@ -336,7 +336,7 @@ static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std)
return 0;
}
-static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std)
+static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std)
{
struct video_device *vdev = video_devdata(file);
struct timblogiw *lw = video_get_drvdata(vdev);
@@ -348,10 +348,10 @@ static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std)
mutex_lock(&lw->lock);
if (TIMBLOGIW_HAS_DECODER(lw))
- err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std);
+ err = v4l2_subdev_call(lw->sd_enc, core, s_std, std);
if (!err)
- fh->cur_norm = timblogiw_get_norm(*std);
+ fh->cur_norm = timblogiw_get_norm(std);
mutex_unlock(&lw->lock);
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index b051c4a28554..a794cd6c4441 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -847,7 +847,7 @@ static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
return 0;
}
-static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std)
{
return 0;
}
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
index eb5d6f955709..c6af974c5b45 100644
--- a/drivers/media/platform/vino.c
+++ b/drivers/media/platform/vino.c
@@ -3042,7 +3042,7 @@ static int vino_g_std(struct file *file, void *__fh,
}
static int vino_s_std(struct file *file, void *__fh,
- v4l2_std_id *std)
+ v4l2_std_id std)
{
struct vino_channel_settings *vcs = video_drvdata(file);
unsigned long flags;
@@ -3056,7 +3056,7 @@ static int vino_s_std(struct file *file, void *__fh,
}
/* check if the standard is valid for the current input */
- if ((*std) & vino_inputs[vcs->input].std) {
+ if (std & vino_inputs[vcs->input].std) {
dprintk("standard accepted\n");
/* change the video norm for SAA7191
@@ -3065,13 +3065,13 @@ static int vino_s_std(struct file *file, void *__fh,
if (vcs->input == VINO_INPUT_D1)
goto out;
- if ((*std) & V4L2_STD_PAL) {
+ if (std & V4L2_STD_PAL) {
ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
&flags);
- } else if ((*std) & V4L2_STD_NTSC) {
+ } else if (std & V4L2_STD_NTSC) {
ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC,
&flags);
- } else if ((*std) & V4L2_STD_SECAM) {
+ } else if (std & V4L2_STD_SECAM) {
ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM,
&flags);
} else {
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 8a33a712f480..85bc314382d3 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -1093,6 +1093,15 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
dev->input = i;
+ /*
+ * Modify the brightness range depending on the input.
+ * This makes it easy to use vivi to test if applications can
+ * handle control range modifications and is also how this is
+ * typically used in practice as different inputs may be hooked
+ * up to different receivers with different control ranges.
+ */
+ v4l2_ctrl_modify_range(dev->brightness,
+ 128 * i, 255 + 128 * i, 1, 127 + 128 * i);
precalculate_bars(dev);
precalculate_line(dev);
return 0;
@@ -1429,6 +1438,7 @@ static int __init vivi_create_instance(int inst)
q->buf_struct_size = sizeof(struct vivi_buffer);
q->ops = &vivi_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 24e64a09884c..c0beee2fa37c 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -18,6 +18,22 @@ config RADIO_SI470X
source "drivers/media/radio/si470x/Kconfig"
+config RADIO_SI476X
+ tristate "Silicon Laboratories Si476x I2C FM Radio"
+ depends on I2C && VIDEO_V4L2
+ depends on MFD_SI476X_CORE
+ select SND_SOC_SI476X
+ ---help---
+ Choose Y here if you have this FM radio chip.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l2" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-si476x.
+
config USB_MR800
tristate "AverMedia MR 800 USB FM radio support"
depends on USB && VIDEO_V4L2
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 303eaebdb85a..0dcdb320cfc7 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
+obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 63b112b555b2..142c2ee64d31 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -208,13 +208,13 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
return v->index ? -EINVAL : 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct dsbr100_device *radio = video_drvdata(file);
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 643d80ac28fb..545c04cf7226 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -90,6 +90,26 @@ static u16 sigtable[2][4] = {
{ 2185, 4369, 13107, 65535 },
};
+static const struct v4l2_frequency_band bands[] = {
+ {
+ .index = 0,
+ .type = V4L2_TUNER_RADIO,
+ .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 8320, /* 520 kHz */
+ .rangehigh = 26400, /* 1650 kHz */
+ .modulation = V4L2_BAND_MODULATION_AM,
+ }, {
+ .index = 1,
+ .type = V4L2_TUNER_RADIO,
+ .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW |
+ V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 1400000, /* 87.5 MHz */
+ .rangehigh = 1728000, /* 108.0 MHz */
+ .modulation = V4L2_BAND_MODULATION_FM,
+ },
+};
+
static int cadet_getstereo(struct cadet *dev)
{
@@ -196,6 +216,8 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
int i, j, test;
int curvol;
+ freq = clamp(freq, bands[dev->is_fm_band].rangelow,
+ bands[dev->is_fm_band].rangehigh);
dev->curfreq = freq;
/*
* Formulate a fifo command
@@ -337,26 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static const struct v4l2_frequency_band bands[] = {
- {
- .index = 0,
- .type = V4L2_TUNER_RADIO,
- .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 8320, /* 520 kHz */
- .rangehigh = 26400, /* 1650 kHz */
- .modulation = V4L2_BAND_MODULATION_AM,
- }, {
- .index = 1,
- .type = V4L2_TUNER_RADIO,
- .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
- V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW |
- V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 1400000, /* 87.5 MHz */
- .rangehigh = 1728000, /* 108.0 MHz */
- .modulation = V4L2_BAND_MODULATION_FM,
- },
-};
-
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
@@ -388,7 +390,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
return v->index ? -EINVAL : 0;
}
@@ -418,7 +420,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct cadet *dev = video_drvdata(file);
@@ -426,8 +428,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return -EINVAL;
dev->is_fm_band =
f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2;
- clamp(f->frequency, bands[dev->is_fm_band].rangelow,
- bands[dev->is_fm_band].rangehigh);
cadet_setfreq(dev, f->frequency);
return 0;
}
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 84b7b9f4385e..6ff350831d56 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -51,8 +51,8 @@ static int radio_isa_querycap(struct file *file, void *priv,
strlcpy(v->card, isa->drv->card, sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name);
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS;
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -87,7 +87,7 @@ static int radio_isa_g_tuner(struct file *file, void *priv,
}
static int radio_isa_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct radio_isa_card *isa = video_drvdata(file);
const struct radio_isa_ops *ops = isa->drv->ops;
@@ -102,17 +102,18 @@ static int radio_isa_s_tuner(struct file *file, void *priv,
}
static int radio_isa_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct radio_isa_card *isa = video_drvdata(file);
+ u32 freq = f->frequency;
int res;
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH);
- res = isa->drv->ops->s_frequency(isa, f->frequency);
+ freq = clamp(freq, FREQ_LOW, FREQ_HIGH);
+ res = isa->drv->ops->s_frequency(isa, freq);
if (res == 0)
- isa->freq = f->frequency;
+ isa->freq = freq;
return res;
}
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 296941a9ae25..4c9ae767fb31 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -215,15 +215,15 @@ static int vidioc_s_modulator(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct keene_device *radio = video_drvdata(file);
+ unsigned freq = f->frequency;
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- f->frequency = clamp(f->frequency,
- FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
- return keene_cmd_main(radio, f->frequency, true);
+ freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
+ return keene_cmd_main(radio, freq, true);
}
static int vidioc_g_frequency(struct file *file, void *priv,
diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c
index c61f590029ad..a85b064cb7be 100644
--- a/drivers/media/radio/radio-ma901.c
+++ b/drivers/media/radio/radio-ma901.c
@@ -239,7 +239,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
/* vidioc_s_tuner - set tuner attributes */
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct ma901radio_device *radio = video_drvdata(file);
@@ -257,7 +257,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
/* vidioc_s_frequency - set tuner radio frequency */
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct ma901radio_device *radio = video_drvdata(file);
@@ -347,9 +347,20 @@ static void usb_ma901radio_release(struct v4l2_device *v4l2_dev)
static int usb_ma901radio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_device *dev = interface_to_usbdev(intf);
struct ma901radio_device *radio;
int retval = 0;
+ /* Masterkit MA901 usb radio has the same USB ID as many others
+ * Atmel V-USB devices. Let's make additional checks to be sure
+ * that this is our device.
+ */
+
+ if (dev->product && dev->manufacturer &&
+ (strncmp(dev->product, "MA901", 5) != 0
+ || strncmp(dev->manufacturer, "www.masterkit.ru", 16) != 0))
+ return -ENODEV;
+
radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL);
if (!radio) {
dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n");
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 3d0ff4404d12..a7e93d7477dd 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -103,16 +103,18 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct pcm20 *dev = video_drvdata(file);
if (v->index)
return -EINVAL;
if (v->audmode > V4L2_TUNER_MODE_STEREO)
- v->audmode = V4L2_TUNER_MODE_STEREO;
+ dev->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ dev->audmode = v->audmode;
snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
- v->audmode == V4L2_TUNER_MODE_MONO, -1);
+ dev->audmode == V4L2_TUNER_MODE_MONO, -1);
return 0;
}
@@ -131,14 +133,14 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct pcm20 *dev = video_drvdata(file);
if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
- dev->freq = clamp(f->frequency, 87 * 16000U, 108 * 16000U);
+ dev->freq = clamp_t(u32, f->frequency, 87 * 16000U, 108 * 16000U);
pcm20_setfreq(dev, dev->freq);
return 0;
}
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 9c5a267b60b4..a360227ca3ab 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -203,10 +203,14 @@ static int amradio_set_mute(struct amradio_device *radio, bool mute)
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int amradio_set_freq(struct amradio_device *radio, int freq)
{
- unsigned short freq_send = 0x10 + (freq >> 3) / 25;
+ unsigned short freq_send;
u8 buf[3];
int retval;
+ /* we need to be sure that frequency isn't out of range */
+ freq = clamp_t(unsigned, freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
+ freq_send = 0x10 + (freq >> 3) / 25;
+
/* frequency is calculated from freq_send and placed in first 2 bytes */
buf[0] = (freq_send >> 8) & 0xff;
buf[1] = freq_send & 0xff;
@@ -305,7 +309,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
/* vidioc_s_tuner - set tuner attributes */
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct amradio_device *radio = video_drvdata(file);
@@ -323,14 +327,13 @@ static int vidioc_s_tuner(struct file *file, void *priv,
/* vidioc_s_frequency - set tuner radio frequency */
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct amradio_device *radio = video_drvdata(file);
if (f->tuner != 0)
return -EINVAL;
- return amradio_set_freq(radio, clamp_t(unsigned, f->frequency,
- FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
+ return amradio_set_freq(radio, f->frequency);
}
/* vidioc_g_frequency - get tuner radio frequency */
@@ -389,6 +392,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
continue;
amradio_send_cmd(radio, AMRADIO_GET_FREQ, 0, NULL, 0, true);
if (radio->buffer[1] || radio->buffer[2]) {
+ /* To check: sometimes radio->curfreq is set to out of range value */
radio->curfreq = (radio->buffer[1] << 8) | radio->buffer[2];
radio->curfreq = (radio->curfreq - 0x10) * 200;
amradio_send_cmd(radio, AMRADIO_STOP_SEARCH,
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b1f844c64fde..09cfbc373c92 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -8,6 +8,8 @@
*
* Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Fully tested with actual hardware and the v4l2-compliance tool.
*/
#include <linux/module.h> /* Modules */
@@ -81,8 +83,7 @@ static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq)
zero(isa);
outb_p(0xc8, isa->io);
- if (!v4l2_ctrl_g_ctrl(isa->mute))
- outb_p(0, isa->io);
+ outb_p(v4l2_ctrl_g_ctrl(isa->mute), isa->io);
return 0;
}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 637a55564958..adfcc61bdf0b 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -145,13 +145,13 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
return v->index ? -EINVAL : 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct fmi *fmi = video_drvdata(file);
diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c
index 8c309c7134d7..8fa18ab5b725 100644
--- a/drivers/media/radio/radio-shark.c
+++ b/drivers/media/radio/radio-shark.c
@@ -284,7 +284,7 @@ static void shark_resume_leds(struct shark_device *shark)
static int shark_register_leds(struct shark_device *shark, struct device *dev)
{
v4l2_warn(&shark->v4l2_dev,
- "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+ "CONFIG_LEDS_CLASS not enabled, LED support disabled\n");
return 0;
}
static inline void shark_unregister_leds(struct shark_device *shark) { }
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index ef65ebbd5364..9fb669721e66 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -250,7 +250,7 @@ static void shark_resume_leds(struct shark_device *shark)
static int shark_register_leds(struct shark_device *shark, struct device *dev)
{
v4l2_warn(&shark->v4l2_dev,
- "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+ "CONFIG_LEDS_CLASS not enabled, LED support disabled\n");
return 0;
}
static inline void shark_unregister_leds(struct shark_device *shark) { }
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 1507c9d508d7..ba4cfc946868 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -31,6 +31,9 @@
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/radio-si4713.h>
/* module parameters */
@@ -39,54 +42,30 @@ module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr,
"Minor number for radio device (-1 ==> auto assign)");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter");
MODULE_VERSION("0.0.1");
+MODULE_ALIAS("platform:radio-si4713");
/* Driver state struct */
struct radio_si4713_device {
struct v4l2_device v4l2_dev;
- struct video_device *radio_dev;
+ struct video_device radio_dev;
+ struct mutex lock;
};
/* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
/* Note: locking is done at the subdev level in the i2c driver. */
.unlocked_ioctl = video_ioctl2,
};
/* Video4Linux Interface */
-static int radio_si4713_fill_audout(struct v4l2_audioout *vao)
-{
- /* TODO: check presence of audio output */
- strlcpy(vao->name, "FM Modulator Audio Out", 32);
-
- return 0;
-}
-
-static int radio_si4713_enumaudout(struct file *file, void *priv,
- struct v4l2_audioout *vao)
-{
- return radio_si4713_fill_audout(vao);
-}
-
-static int radio_si4713_g_audout(struct file *file, void *priv,
- struct v4l2_audioout *vao)
-{
- int rval = radio_si4713_fill_audout(vao);
-
- vao->index = 0;
-
- return rval;
-}
-
-static int radio_si4713_s_audout(struct file *file, void *priv,
- const struct v4l2_audioout *vao)
-{
- return vao->index ? -EINVAL : 0;
-}
/* radio_si4713_querycap - query device capabilities */
static int radio_si4713_querycap(struct file *file, void *priv,
@@ -94,67 +73,15 @@ static int radio_si4713_querycap(struct file *file, void *priv,
{
strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver));
strlcpy(capability->card, "Silicon Labs Si4713 Modulator",
- sizeof(capability->card));
- capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
+ sizeof(capability->card));
+ strlcpy(capability->bus_info, "platform:radio-si4713",
+ sizeof(capability->bus_info));
+ capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
+ capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-/* radio_si4713_queryctrl - enumerate control items */
-static int radio_si4713_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- /* Must be sorted from low to high control ID! */
- static const u32 user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_AUDIO_MUTE,
- 0
- };
-
- /* Must be sorted from low to high control ID! */
- static const u32 fmtx_ctrls[] = {
- V4L2_CID_FM_TX_CLASS,
- V4L2_CID_RDS_TX_DEVIATION,
- V4L2_CID_RDS_TX_PI,
- V4L2_CID_RDS_TX_PTY,
- V4L2_CID_RDS_TX_PS_NAME,
- V4L2_CID_RDS_TX_RADIO_TEXT,
- V4L2_CID_AUDIO_LIMITER_ENABLED,
- V4L2_CID_AUDIO_LIMITER_RELEASE_TIME,
- V4L2_CID_AUDIO_LIMITER_DEVIATION,
- V4L2_CID_AUDIO_COMPRESSION_ENABLED,
- V4L2_CID_AUDIO_COMPRESSION_GAIN,
- V4L2_CID_AUDIO_COMPRESSION_THRESHOLD,
- V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME,
- V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME,
- V4L2_CID_PILOT_TONE_ENABLED,
- V4L2_CID_PILOT_TONE_DEVIATION,
- V4L2_CID_PILOT_TONE_FREQUENCY,
- V4L2_CID_TUNE_PREEMPHASIS,
- V4L2_CID_TUNE_POWER_LEVEL,
- V4L2_CID_TUNE_ANTENNA_CAPACITOR,
- 0
- };
- static const u32 *ctrl_classes[] = {
- user_ctrls,
- fmtx_ctrls,
- NULL
- };
- struct radio_si4713_device *rsdev;
-
- rsdev = video_get_drvdata(video_devdata(file));
-
- qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
- if (qc->id == 0)
- return -EINVAL;
-
- if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS)
- return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0);
-
- return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core,
- queryctrl, qc);
-}
-
/*
* v4l2 ioctl call backs.
* we are just a wrapper for v4l2_sub_devs.
@@ -164,83 +91,50 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file)
return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev;
}
-static int radio_si4713_g_ext_ctrls(struct file *file, void *p,
- struct v4l2_ext_controls *vecs)
-{
- return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
- g_ext_ctrls, vecs);
-}
-
-static int radio_si4713_s_ext_ctrls(struct file *file, void *p,
- struct v4l2_ext_controls *vecs)
-{
- return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
- s_ext_ctrls, vecs);
-}
-
-static int radio_si4713_g_ctrl(struct file *file, void *p,
- struct v4l2_control *vc)
-{
- return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
- g_ctrl, vc);
-}
-
-static int radio_si4713_s_ctrl(struct file *file, void *p,
- struct v4l2_control *vc)
-{
- return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
- s_ctrl, vc);
-}
-
static int radio_si4713_g_modulator(struct file *file, void *p,
- struct v4l2_modulator *vm)
+ struct v4l2_modulator *vm)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
- g_modulator, vm);
+ g_modulator, vm);
}
static int radio_si4713_s_modulator(struct file *file, void *p,
- const struct v4l2_modulator *vm)
+ const struct v4l2_modulator *vm)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
- s_modulator, vm);
+ s_modulator, vm);
}
static int radio_si4713_g_frequency(struct file *file, void *p,
- struct v4l2_frequency *vf)
+ struct v4l2_frequency *vf)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
- g_frequency, vf);
+ g_frequency, vf);
}
static int radio_si4713_s_frequency(struct file *file, void *p,
- struct v4l2_frequency *vf)
+ const struct v4l2_frequency *vf)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner,
- s_frequency, vf);
+ s_frequency, vf);
}
static long radio_si4713_default(struct file *file, void *p,
- bool valid_prio, int cmd, void *arg)
+ bool valid_prio, unsigned int cmd, void *arg)
{
return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core,
- ioctl, cmd, arg);
+ ioctl, cmd, arg);
}
static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
- .vidioc_enumaudout = radio_si4713_enumaudout,
- .vidioc_g_audout = radio_si4713_g_audout,
- .vidioc_s_audout = radio_si4713_s_audout,
.vidioc_querycap = radio_si4713_querycap,
- .vidioc_queryctrl = radio_si4713_queryctrl,
- .vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls,
- .vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls,
- .vidioc_g_ctrl = radio_si4713_g_ctrl,
- .vidioc_s_ctrl = radio_si4713_s_ctrl,
.vidioc_g_modulator = radio_si4713_g_modulator,
.vidioc_s_modulator = radio_si4713_s_modulator,
.vidioc_g_frequency = radio_si4713_g_frequency,
.vidioc_s_frequency = radio_si4713_s_frequency,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
.vidioc_default = radio_si4713_default,
};
@@ -248,7 +142,7 @@ static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = {
static struct video_device radio_si4713_vdev_template = {
.fops = &radio_si4713_fops,
.name = "radio-si4713",
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &radio_si4713_ioctl_ops,
.vfl_dir = VFL_DIR_TX,
};
@@ -275,6 +169,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
rval = -ENOMEM;
goto exit;
}
+ mutex_init(&rsdev->lock);
rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
if (rval) {
@@ -285,40 +180,35 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
adapter = i2c_get_adapter(pdata->i2c_bus);
if (!adapter) {
dev_err(&pdev->dev, "Cannot get i2c adapter %d\n",
- pdata->i2c_bus);
+ pdata->i2c_bus);
rval = -ENODEV;
goto unregister_v4l2_dev;
}
sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
- pdata->subdev_board_info, NULL);
+ pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
rval = -ENODEV;
goto put_adapter;
}
- rsdev->radio_dev = video_device_alloc();
- if (!rsdev->radio_dev) {
- dev_err(&pdev->dev, "Failed to alloc video device.\n");
- rval = -ENOMEM;
- goto put_adapter;
- }
-
- memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
- sizeof(radio_si4713_vdev_template));
- video_set_drvdata(rsdev->radio_dev, rsdev);
- if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
+ rsdev->radio_dev = radio_si4713_vdev_template;
+ rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev;
+ rsdev->radio_dev.ctrl_handler = sd->ctrl_handler;
+ set_bit(V4L2_FL_USE_FH_PRIO, &rsdev->radio_dev.flags);
+ /* Serialize all access to the si4713 */
+ rsdev->radio_dev.lock = &rsdev->lock;
+ video_set_drvdata(&rsdev->radio_dev, rsdev);
+ if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
dev_err(&pdev->dev, "Could not register video device.\n");
rval = -EIO;
- goto free_vdev;
+ goto put_adapter;
}
dev_info(&pdev->dev, "New device successfully probed\n");
goto exit;
-free_vdev:
- video_device_release(rsdev->radio_dev);
put_adapter:
i2c_put_adapter(adapter);
unregister_v4l2_dev:
@@ -328,17 +218,16 @@ exit:
}
/* radio_si4713_pdriver_remove - remove the device */
-static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
+static int radio_si4713_pdriver_remove(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
- struct radio_si4713_device *rsdev = container_of(v4l2_dev,
- struct radio_si4713_device,
- v4l2_dev);
struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
struct v4l2_subdev, list);
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct radio_si4713_device *rsdev;
- video_unregister_device(rsdev->radio_dev);
+ rsdev = container_of(v4l2_dev, struct radio_si4713_device, v4l2_dev);
+ video_unregister_device(&rsdev->radio_dev);
i2c_put_adapter(client->adapter);
v4l2_device_unregister(&rsdev->v4l2_dev);
@@ -348,9 +237,10 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
static struct platform_driver radio_si4713_pdriver = {
.driver = {
.name = "radio-si4713",
+ .owner = THIS_MODULE,
},
.probe = radio_si4713_pdriver_probe,
- .remove = __exit_p(radio_si4713_pdriver_remove),
+ .remove = radio_si4713_pdriver_remove,
};
module_platform_driver(radio_si4713_pdriver);
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
new file mode 100644
index 000000000000..9430c6a29937
--- /dev/null
+++ b/drivers/media/radio/radio-si476x.c
@@ -0,0 +1,1599 @@
+/*
+ * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-device.h>
+
+#include <media/si476x.h>
+#include <linux/mfd/si476x-core.h>
+
+#define FM_FREQ_RANGE_LOW 64000000
+#define FM_FREQ_RANGE_HIGH 108000000
+
+#define AM_FREQ_RANGE_LOW 520000
+#define AM_FREQ_RANGE_HIGH 30000000
+
+#define PWRLINEFLTR (1 << 8)
+
+#define FREQ_MUL (10000000 / 625)
+
+#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status))
+
+#define DRIVER_NAME "si476x-radio"
+#define DRIVER_CARD "SI476x AM/FM Receiver"
+
+enum si476x_freq_bands {
+ SI476X_BAND_FM,
+ SI476X_BAND_AM,
+};
+
+static const struct v4l2_frequency_band si476x_bands[] = {
+ [SI476X_BAND_FM] = {
+ .type = V4L2_TUNER_RADIO,
+ .index = SI476X_BAND_FM,
+ .capability = V4L2_TUNER_CAP_LOW
+ | V4L2_TUNER_CAP_STEREO
+ | V4L2_TUNER_CAP_RDS
+ | V4L2_TUNER_CAP_RDS_BLOCK_IO
+ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 64 * FREQ_MUL,
+ .rangehigh = 108 * FREQ_MUL,
+ .modulation = V4L2_BAND_MODULATION_FM,
+ },
+ [SI476X_BAND_AM] = {
+ .type = V4L2_TUNER_RADIO,
+ .index = SI476X_BAND_AM,
+ .capability = V4L2_TUNER_CAP_LOW
+ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 0.52 * FREQ_MUL,
+ .rangehigh = 30 * FREQ_MUL,
+ .modulation = V4L2_BAND_MODULATION_AM,
+ },
+};
+
+static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band)
+{
+ return freq >= si476x_bands[band].rangelow &&
+ freq <= si476x_bands[band].rangehigh;
+}
+
+static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high,
+ int band)
+{
+ return low >= si476x_bands[band].rangelow &&
+ high <= si476x_bands[band].rangehigh;
+}
+
+static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl);
+static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
+
+enum phase_diversity_modes_idx {
+ SI476X_IDX_PHDIV_DISABLED,
+ SI476X_IDX_PHDIV_PRIMARY_COMBINING,
+ SI476X_IDX_PHDIV_PRIMARY_ANTENNA,
+ SI476X_IDX_PHDIV_SECONDARY_ANTENNA,
+ SI476X_IDX_PHDIV_SECONDARY_COMBINING,
+};
+
+static const char * const phase_diversity_modes[] = {
+ [SI476X_IDX_PHDIV_DISABLED] = "Disabled",
+ [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary",
+ [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna",
+ [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna",
+ [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary",
+};
+
+static inline enum phase_diversity_modes_idx
+si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode)
+{
+ switch (mode) {
+ default: /* FALLTHROUGH */
+ case SI476X_PHDIV_DISABLED:
+ return SI476X_IDX_PHDIV_DISABLED;
+ case SI476X_PHDIV_PRIMARY_COMBINING:
+ return SI476X_IDX_PHDIV_PRIMARY_COMBINING;
+ case SI476X_PHDIV_PRIMARY_ANTENNA:
+ return SI476X_IDX_PHDIV_PRIMARY_ANTENNA;
+ case SI476X_PHDIV_SECONDARY_ANTENNA:
+ return SI476X_IDX_PHDIV_SECONDARY_ANTENNA;
+ case SI476X_PHDIV_SECONDARY_COMBINING:
+ return SI476X_IDX_PHDIV_SECONDARY_COMBINING;
+ }
+}
+
+static inline enum si476x_phase_diversity_mode
+si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx)
+{
+ static const int idx_to_value[] = {
+ [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED,
+ [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING,
+ [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA,
+ [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA,
+ [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING,
+ };
+
+ return idx_to_value[idx];
+}
+
+static const struct v4l2_ctrl_ops si476x_ctrl_ops = {
+ .g_volatile_ctrl = si476x_radio_g_volatile_ctrl,
+ .s_ctrl = si476x_radio_s_ctrl,
+};
+
+
+enum si476x_ctrl_idx {
+ SI476X_IDX_RSSI_THRESHOLD,
+ SI476X_IDX_SNR_THRESHOLD,
+ SI476X_IDX_MAX_TUNE_ERROR,
+ SI476X_IDX_HARMONICS_COUNT,
+ SI476X_IDX_DIVERSITY_MODE,
+ SI476X_IDX_INTERCHIP_LINK,
+};
+static struct v4l2_ctrl_config si476x_ctrls[] = {
+
+ /**
+ * SI476X during its station seeking(or tuning) process uses several
+ * parameters to detrmine if "the station" is valid:
+ *
+ * - Signal's SNR(in dBuV) must be lower than
+ * #V4L2_CID_SI476X_SNR_THRESHOLD
+ * - Signal's RSSI(in dBuV) must be greater than
+ * #V4L2_CID_SI476X_RSSI_THRESHOLD
+ * - Signal's frequency deviation(in units of 2ppm) must not be
+ * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR
+ */
+ [SI476X_IDX_RSSI_THRESHOLD] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_RSSI_THRESHOLD,
+ .name = "Valid RSSI Threshold",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = -128,
+ .max = 127,
+ .step = 1,
+ },
+ [SI476X_IDX_SNR_THRESHOLD] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_SNR_THRESHOLD,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Valid SNR Threshold",
+ .min = -128,
+ .max = 127,
+ .step = 1,
+ },
+ [SI476X_IDX_MAX_TUNE_ERROR] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_MAX_TUNE_ERROR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Max Tune Errors",
+ .min = 0,
+ .max = 126 * 2,
+ .step = 2,
+ },
+
+ /**
+ * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics
+ * built-in power-line noise supression filter is to reject
+ * during AM-mode operation.
+ */
+ [SI476X_IDX_HARMONICS_COUNT] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_HARMONICS_COUNT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+
+ .name = "Count of Harmonics to Reject",
+ .min = 0,
+ .max = 20,
+ .step = 1,
+ },
+
+ /**
+ * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which
+ * two tuners working in diversity mode are to work in.
+ *
+ * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled
+ * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is
+ * on, primary tuner's antenna is the main one.
+ * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is
+ * off, primary tuner's antenna is the main one.
+ * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is
+ * off, secondary tuner's antenna is the main one.
+ * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is
+ * on, secondary tuner's antenna is the main one.
+ */
+ [SI476X_IDX_DIVERSITY_MODE] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_DIVERSITY_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Phase Diversity Mode",
+ .qmenu = phase_diversity_modes,
+ .min = 0,
+ .max = ARRAY_SIZE(phase_diversity_modes) - 1,
+ },
+
+ /**
+ * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in
+ * diversity mode indicator. Allows user to determine if two
+ * chips working in diversity mode have established a link
+ * between each other and if the system as a whole uses
+ * signals from both antennas to receive FM radio.
+ */
+ [SI476X_IDX_INTERCHIP_LINK] = {
+ .ops = &si476x_ctrl_ops,
+ .id = V4L2_CID_SI476X_INTERCHIP_LINK,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
+ .name = "Inter-Chip Link",
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ },
+};
+
+struct si476x_radio;
+
+/**
+ * struct si476x_radio_ops - vtable of tuner functions
+ *
+ * This table holds pointers to functions implementing particular
+ * operations depending on the mode in which the tuner chip was
+ * configured to start in. If the function is not supported
+ * corresponding element is set to #NULL.
+ *
+ * @tune_freq: Tune chip to a specific frequency
+ * @seek_start: Star station seeking
+ * @rsq_status: Get Recieved Signal Quality(RSQ) status
+ * @rds_blckcnt: Get recived RDS blocks count
+ * @phase_diversity: Change phase diversity mode of the tuner
+ * @phase_div_status: Get phase diversity mode status
+ * @acf_status: Get the status of Automatically Controlled
+ * Features(ACF)
+ * @agc_status: Get Automatic Gain Control(AGC) status
+ */
+struct si476x_radio_ops {
+ int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *);
+ int (*seek_start)(struct si476x_core *, bool, bool);
+ int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *,
+ struct si476x_rsq_status_report *);
+ int (*rds_blckcnt)(struct si476x_core *, bool,
+ struct si476x_rds_blockcount_report *);
+
+ int (*phase_diversity)(struct si476x_core *,
+ enum si476x_phase_diversity_mode);
+ int (*phase_div_status)(struct si476x_core *);
+ int (*acf_status)(struct si476x_core *,
+ struct si476x_acf_status_report *);
+ int (*agc_status)(struct si476x_core *,
+ struct si476x_agc_status_report *);
+};
+
+/**
+ * struct si476x_radio - radio device
+ *
+ * @core: Pointer to underlying core device
+ * @videodev: Pointer to video device created by V4L2 subsystem
+ * @ops: Vtable of functions. See struct si476x_radio_ops for details
+ * @kref: Reference counter
+ * @core_lock: An r/w semaphore to brebvent the deletion of underlying
+ * core structure is the radio device is being used
+ */
+struct si476x_radio {
+ struct v4l2_device v4l2dev;
+ struct video_device videodev;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct si476x_core *core;
+ /* This field should not be accesses unless core lock is held */
+ const struct si476x_radio_ops *ops;
+
+ struct dentry *debugfs;
+ u32 audmode;
+};
+
+static inline struct si476x_radio *
+v4l2_dev_to_radio(struct v4l2_device *d)
+{
+ return container_of(d, struct si476x_radio, v4l2dev);
+}
+
+static inline struct si476x_radio *
+v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d)
+{
+ return container_of(d, struct si476x_radio, ctrl_handler);
+}
+
+/*
+ * si476x_vidioc_querycap - query device capabilities
+ */
+static int si476x_radio_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+{
+ struct si476x_radio *radio = video_drvdata(file);
+
+ strlcpy(capability->driver, radio->v4l2dev.name,
+ sizeof(capability->driver));
+ strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
+ snprintf(capability->bus_info, sizeof(capability->bus_info),
+ "platform:%s", radio->v4l2dev.name);
+
+ capability->device_caps = V4L2_CAP_TUNER
+ | V4L2_CAP_RADIO
+ | V4L2_CAP_HW_FREQ_SEEK;
+
+ si476x_core_lock(radio->core);
+ if (!si476x_core_is_a_secondary_tuner(radio->core))
+ capability->device_caps |= V4L2_CAP_RDS_CAPTURE
+ | V4L2_CAP_READWRITE;
+ si476x_core_unlock(radio->core);
+
+ capability->capabilities = capability->device_caps
+ | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int si476x_radio_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ int err;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ if (band->tuner != 0)
+ return -EINVAL;
+
+ switch (radio->core->chip_id) {
+ /* AM/FM tuners -- all bands are supported */
+ case SI476X_CHIP_SI4761:
+ case SI476X_CHIP_SI4764:
+ if (band->index < ARRAY_SIZE(si476x_bands)) {
+ *band = si476x_bands[band->index];
+ err = 0;
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ /* FM companion tuner chips -- only FM bands are
+ * supported */
+ case SI476X_CHIP_SI4768:
+ if (band->index == SI476X_BAND_FM) {
+ *band = si476x_bands[band->index];
+ err = 0;
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static int si476x_radio_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ int err;
+ struct si476x_rsq_status_report report;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ struct si476x_rsq_status_args args = {
+ .primary = false,
+ .rsqack = false,
+ .attune = false,
+ .cancel = false,
+ .stcack = false,
+ };
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ tuner->type = V4L2_TUNER_RADIO;
+ tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies
+ * in multiples of
+ * 62.5 Hz */
+ | V4L2_TUNER_CAP_STEREO
+ | V4L2_TUNER_CAP_HWSEEK_BOUNDED
+ | V4L2_TUNER_CAP_HWSEEK_WRAP
+ | V4L2_TUNER_CAP_HWSEEK_PROG_LIM;
+
+ si476x_core_lock(radio->core);
+
+ if (si476x_core_is_a_secondary_tuner(radio->core)) {
+ strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name));
+ tuner->rxsubchans = 0;
+ tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
+ } else if (si476x_core_has_am(radio->core)) {
+ if (si476x_core_is_a_primary_tuner(radio->core))
+ strlcpy(tuner->name, "AM/FM (primary)",
+ sizeof(tuner->name));
+ else
+ strlcpy(tuner->name, "AM/FM", sizeof(tuner->name));
+
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO
+ | V4L2_TUNER_SUB_RDS;
+ tuner->capability |= V4L2_TUNER_CAP_RDS
+ | V4L2_TUNER_CAP_RDS_BLOCK_IO
+ | V4L2_TUNER_CAP_FREQ_BANDS;
+
+ tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow;
+ } else {
+ strlcpy(tuner->name, "FM", sizeof(tuner->name));
+ tuner->rxsubchans = V4L2_TUNER_SUB_RDS;
+ tuner->capability |= V4L2_TUNER_CAP_RDS
+ | V4L2_TUNER_CAP_RDS_BLOCK_IO
+ | V4L2_TUNER_CAP_FREQ_BANDS;
+ tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow;
+ }
+
+ tuner->audmode = radio->audmode;
+
+ tuner->afc = 1;
+ tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh;
+
+ err = radio->ops->rsq_status(radio->core,
+ &args, &report);
+ if (err < 0) {
+ tuner->signal = 0;
+ } else {
+ /*
+ * tuner->signal value range: 0x0000 .. 0xFFFF,
+ * report.rssi: -128 .. 127
+ */
+ tuner->signal = (report.rssi + 128) * 257;
+ }
+ si476x_core_unlock(radio->core);
+
+ return err;
+}
+
+static int si476x_radio_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *tuner)
+{
+ struct si476x_radio *radio = video_drvdata(file);
+
+ if (tuner->index != 0)
+ return -EINVAL;
+
+ if (tuner->audmode == V4L2_TUNER_MODE_MONO ||
+ tuner->audmode == V4L2_TUNER_MODE_STEREO)
+ radio->audmode = tuner->audmode;
+ else
+ radio->audmode = V4L2_TUNER_MODE_STEREO;
+
+ return 0;
+}
+
+static int si476x_radio_init_vtable(struct si476x_radio *radio,
+ enum si476x_func func)
+{
+ static const struct si476x_radio_ops fm_ops = {
+ .tune_freq = si476x_core_cmd_fm_tune_freq,
+ .seek_start = si476x_core_cmd_fm_seek_start,
+ .rsq_status = si476x_core_cmd_fm_rsq_status,
+ .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount,
+ .phase_diversity = si476x_core_cmd_fm_phase_diversity,
+ .phase_div_status = si476x_core_cmd_fm_phase_div_status,
+ .acf_status = si476x_core_cmd_fm_acf_status,
+ .agc_status = si476x_core_cmd_agc_status,
+ };
+
+ static const struct si476x_radio_ops am_ops = {
+ .tune_freq = si476x_core_cmd_am_tune_freq,
+ .seek_start = si476x_core_cmd_am_seek_start,
+ .rsq_status = si476x_core_cmd_am_rsq_status,
+ .rds_blckcnt = NULL,
+ .phase_diversity = NULL,
+ .phase_div_status = NULL,
+ .acf_status = si476x_core_cmd_am_acf_status,
+ .agc_status = NULL,
+ };
+
+ switch (func) {
+ case SI476X_FUNC_FM_RECEIVER:
+ radio->ops = &fm_ops;
+ return 0;
+
+ case SI476X_FUNC_AM_RECEIVER:
+ radio->ops = &am_ops;
+ return 0;
+ default:
+ WARN(1, "Unexpected tuner function value\n");
+ return -EINVAL;
+ }
+}
+
+static int si476x_radio_pretune(struct si476x_radio *radio,
+ enum si476x_func func)
+{
+ int retval;
+
+ struct si476x_tune_freq_args args = {
+ .zifsr = false,
+ .hd = false,
+ .injside = SI476X_INJSIDE_AUTO,
+ .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE,
+ .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO,
+ .antcap = 0,
+ };
+
+ switch (func) {
+ case SI476X_FUNC_FM_RECEIVER:
+ args.freq = v4l2_to_si476x(radio->core,
+ 92 * FREQ_MUL);
+ retval = radio->ops->tune_freq(radio->core, &args);
+ break;
+ case SI476X_FUNC_AM_RECEIVER:
+ args.freq = v4l2_to_si476x(radio->core,
+ 0.6 * FREQ_MUL);
+ retval = radio->ops->tune_freq(radio->core, &args);
+ break;
+ default:
+ WARN(1, "Unexpected tuner function value\n");
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio,
+ enum si476x_func func)
+{
+ int err;
+
+ /* regcache_mark_dirty(radio->core->regmap); */
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE,
+ SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT);
+ if (err < 0)
+ return err;
+
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_AUDIO_DEEMPHASIS,
+ SI476X_PROP_AUDIO_PWR_LINE_FILTER);
+ if (err < 0)
+ return err;
+
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_INT_CTL_ENABLE,
+ SI476X_PROP_INT_CTL_ENABLE);
+ if (err < 0)
+ return err;
+
+ /*
+ * Is there any point in restoring SNR and the like
+ * when switching between AM/FM?
+ */
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_VALID_MAX_TUNE_ERROR,
+ SI476X_PROP_VALID_MAX_TUNE_ERROR);
+ if (err < 0)
+ return err;
+
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_VALID_SNR_THRESHOLD,
+ SI476X_PROP_VALID_RSSI_THRESHOLD);
+ if (err < 0)
+ return err;
+
+ if (func == SI476X_FUNC_FM_RECEIVER) {
+ if (si476x_core_has_diversity(radio->core)) {
+ err = si476x_core_cmd_fm_phase_diversity(radio->core,
+ radio->core->diversity_mode);
+ if (err < 0)
+ return err;
+ }
+
+ err = regcache_sync_region(radio->core->regmap,
+ SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
+ SI476X_PROP_FM_RDS_CONFIG);
+ if (err < 0)
+ return err;
+ }
+
+ return si476x_radio_init_vtable(radio, func);
+
+}
+
+static int si476x_radio_change_func(struct si476x_radio *radio,
+ enum si476x_func func)
+{
+ int err;
+ bool soft;
+ /*
+ * Since power/up down is a very time consuming operation,
+ * try to avoid doing it if the requested mode matches the one
+ * the tuner is in
+ */
+ if (func == radio->core->power_up_parameters.func)
+ return 0;
+
+ soft = true;
+ err = si476x_core_stop(radio->core, soft);
+ if (err < 0) {
+ /*
+ * OK, if the chip does not want to play nice let's
+ * try to reset it in more brutal way
+ */
+ soft = false;
+ err = si476x_core_stop(radio->core, soft);
+ if (err < 0)
+ return err;
+ }
+ /*
+ Set the desired radio tuner function
+ */
+ radio->core->power_up_parameters.func = func;
+
+ err = si476x_core_start(radio->core, soft);
+ if (err < 0)
+ return err;
+
+ /*
+ * No need to do the rest of manipulations for the bootlader
+ * mode
+ */
+ if (func != SI476X_FUNC_FM_RECEIVER &&
+ func != SI476X_FUNC_AM_RECEIVER)
+ return err;
+
+ return si476x_radio_do_post_powerup_init(radio, func);
+}
+
+static int si476x_radio_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ int err;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ if (f->tuner != 0 ||
+ f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+
+ si476x_core_lock(radio->core);
+
+ if (radio->ops->rsq_status) {
+ struct si476x_rsq_status_report report;
+ struct si476x_rsq_status_args args = {
+ .primary = false,
+ .rsqack = false,
+ .attune = true,
+ .cancel = false,
+ .stcack = false,
+ };
+
+ err = radio->ops->rsq_status(radio->core, &args, &report);
+ if (!err)
+ f->frequency = si476x_to_v4l2(radio->core,
+ report.readfreq);
+ } else {
+ err = -EINVAL;
+ }
+
+ si476x_core_unlock(radio->core);
+
+ return err;
+}
+
+static int si476x_radio_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
+{
+ int err;
+ u32 freq = f->frequency;
+ struct si476x_tune_freq_args args;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh +
+ si476x_bands[SI476X_BAND_FM].rangelow) / 2;
+ const int band = (freq > midrange) ?
+ SI476X_BAND_FM : SI476X_BAND_AM;
+ const enum si476x_func func = (band == SI476X_BAND_AM) ?
+ SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER;
+
+ if (f->tuner != 0 ||
+ f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+
+ si476x_core_lock(radio->core);
+
+ freq = clamp(freq,
+ si476x_bands[band].rangelow,
+ si476x_bands[band].rangehigh);
+
+ if (si476x_radio_freq_is_inside_of_the_band(freq,
+ SI476X_BAND_AM) &&
+ (!si476x_core_has_am(radio->core) ||
+ si476x_core_is_a_secondary_tuner(radio->core))) {
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ err = si476x_radio_change_func(radio, func);
+ if (err < 0)
+ goto unlock;
+
+ args.zifsr = false;
+ args.hd = false;
+ args.injside = SI476X_INJSIDE_AUTO;
+ args.freq = v4l2_to_si476x(radio->core, freq);
+ args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE;
+ args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO;
+ args.antcap = 0;
+
+ err = radio->ops->tune_freq(radio->core, &args);
+
+unlock:
+ si476x_core_unlock(radio->core);
+ return err;
+}
+
+static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv,
+ const struct v4l2_hw_freq_seek *seek)
+{
+ int err;
+ enum si476x_func func;
+ u32 rangelow, rangehigh;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (seek->tuner != 0 ||
+ seek->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+
+ si476x_core_lock(radio->core);
+
+ if (!seek->rangelow) {
+ err = regmap_read(radio->core->regmap,
+ SI476X_PROP_SEEK_BAND_BOTTOM,
+ &rangelow);
+ if (!err)
+ rangelow = si476x_to_v4l2(radio->core, rangelow);
+ else
+ goto unlock;
+ }
+ if (!seek->rangehigh) {
+ err = regmap_read(radio->core->regmap,
+ SI476X_PROP_SEEK_BAND_TOP,
+ &rangehigh);
+ if (!err)
+ rangehigh = si476x_to_v4l2(radio->core, rangehigh);
+ else
+ goto unlock;
+ }
+
+ if (rangelow > rangehigh) {
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
+ SI476X_BAND_FM)) {
+ func = SI476X_FUNC_FM_RECEIVER;
+
+ } else if (si476x_core_has_am(radio->core) &&
+ si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh,
+ SI476X_BAND_AM)) {
+ func = SI476X_FUNC_AM_RECEIVER;
+ } else {
+ err = -EINVAL;
+ goto unlock;
+ }
+
+ err = si476x_radio_change_func(radio, func);
+ if (err < 0)
+ goto unlock;
+
+ if (seek->rangehigh) {
+ err = regmap_write(radio->core->regmap,
+ SI476X_PROP_SEEK_BAND_TOP,
+ v4l2_to_si476x(radio->core,
+ seek->rangehigh));
+ if (err)
+ goto unlock;
+ }
+ if (seek->rangelow) {
+ err = regmap_write(radio->core->regmap,
+ SI476X_PROP_SEEK_BAND_BOTTOM,
+ v4l2_to_si476x(radio->core,
+ seek->rangelow));
+ if (err)
+ goto unlock;
+ }
+ if (seek->spacing) {
+ err = regmap_write(radio->core->regmap,
+ SI476X_PROP_SEEK_FREQUENCY_SPACING,
+ v4l2_to_si476x(radio->core,
+ seek->spacing));
+ if (err)
+ goto unlock;
+ }
+
+ err = radio->ops->seek_start(radio->core,
+ seek->seek_upward,
+ seek->wrap_around);
+unlock:
+ si476x_core_unlock(radio->core);
+
+
+
+ return err;
+}
+
+static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int retval;
+ struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
+
+ si476x_core_lock(radio->core);
+
+ switch (ctrl->id) {
+ case V4L2_CID_SI476X_INTERCHIP_LINK:
+ if (si476x_core_has_diversity(radio->core)) {
+ if (radio->ops->phase_diversity) {
+ retval = radio->ops->phase_div_status(radio->core);
+ if (retval < 0)
+ break;
+
+ ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval);
+ retval = 0;
+ break;
+ } else {
+ retval = -ENOTTY;
+ break;
+ }
+ }
+ retval = -EINVAL;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ si476x_core_unlock(radio->core);
+ return retval;
+
+}
+
+static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ int retval;
+ enum si476x_phase_diversity_mode mode;
+ struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler);
+
+ si476x_core_lock(radio->core);
+
+ switch (ctrl->id) {
+ case V4L2_CID_SI476X_HARMONICS_COUNT:
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_AUDIO_PWR_LINE_FILTER,
+ SI476X_PROP_PWR_HARMONICS_MASK,
+ ctrl->val);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (ctrl->val) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_AUDIO_PWR_LINE_FILTER,
+ SI476X_PROP_PWR_ENABLE_MASK,
+ 0);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_AUDIO_PWR_LINE_FILTER,
+ SI476X_PROP_PWR_GRID_MASK,
+ SI476X_PROP_PWR_GRID_50HZ);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_AUDIO_PWR_LINE_FILTER,
+ SI476X_PROP_PWR_GRID_MASK,
+ SI476X_PROP_PWR_GRID_60HZ);
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ break;
+ case V4L2_CID_SI476X_RSSI_THRESHOLD:
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_VALID_RSSI_THRESHOLD,
+ ctrl->val);
+ break;
+ case V4L2_CID_SI476X_SNR_THRESHOLD:
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_VALID_SNR_THRESHOLD,
+ ctrl->val);
+ break;
+ case V4L2_CID_SI476X_MAX_TUNE_ERROR:
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_VALID_MAX_TUNE_ERROR,
+ ctrl->val);
+ break;
+ case V4L2_CID_RDS_RECEPTION:
+ /*
+ * It looks like RDS related properties are
+ * inaccesable when tuner is in AM mode, so cache the
+ * changes
+ */
+ if (si476x_core_is_in_am_receiver_mode(radio->core))
+ regcache_cache_only(radio->core->regmap, true);
+
+ if (ctrl->val) {
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT,
+ radio->core->rds_fifo_depth);
+ if (retval < 0)
+ break;
+
+ if (radio->core->client->irq) {
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_FM_RDS_INTERRUPT_SOURCE,
+ SI476X_RDSRECV);
+ if (retval < 0)
+ break;
+ }
+
+ /* Drain RDS FIFO before enabling RDS processing */
+ retval = si476x_core_cmd_fm_rds_status(radio->core,
+ false,
+ true,
+ true,
+ NULL);
+ if (retval < 0)
+ break;
+
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_FM_RDS_CONFIG,
+ SI476X_PROP_RDSEN_MASK,
+ SI476X_PROP_RDSEN);
+ } else {
+ retval = regmap_update_bits(radio->core->regmap,
+ SI476X_PROP_FM_RDS_CONFIG,
+ SI476X_PROP_RDSEN_MASK,
+ !SI476X_PROP_RDSEN);
+ }
+
+ if (si476x_core_is_in_am_receiver_mode(radio->core))
+ regcache_cache_only(radio->core->regmap, false);
+ break;
+ case V4L2_CID_TUNE_DEEMPHASIS:
+ retval = regmap_write(radio->core->regmap,
+ SI476X_PROP_AUDIO_DEEMPHASIS,
+ ctrl->val);
+ break;
+
+ case V4L2_CID_SI476X_DIVERSITY_MODE:
+ mode = si476x_phase_diversity_idx_to_mode(ctrl->val);
+
+ if (mode == radio->core->diversity_mode) {
+ retval = 0;
+ break;
+ }
+
+ if (si476x_core_is_in_am_receiver_mode(radio->core)) {
+ /*
+ * Diversity cannot be configured while tuner
+ * is in AM mode so save the changes and carry on.
+ */
+ radio->core->diversity_mode = mode;
+ retval = 0;
+ } else {
+ retval = radio->ops->phase_diversity(radio->core, mode);
+ if (!retval)
+ radio->core->diversity_mode = mode;
+ }
+ break;
+
+ default:
+ retval = -EINVAL;
+ break;
+ }
+
+ si476x_core_unlock(radio->core);
+
+ return retval;
+}
+
+static int si476x_radio_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
+ v4l2_chip_match_host(&chip->match))
+ return 0;
+ return -EINVAL;
+}
+
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int si476x_radio_g_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ int err;
+ unsigned int value;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ si476x_core_lock(radio->core);
+ reg->size = 2;
+ err = regmap_read(radio->core->regmap,
+ (unsigned int)reg->reg, &value);
+ reg->val = value;
+ si476x_core_unlock(radio->core);
+
+ return err;
+}
+static int si476x_radio_s_register(struct file *file, void *fh,
+ const struct v4l2_dbg_register *reg)
+{
+
+ int err;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ si476x_core_lock(radio->core);
+ err = regmap_write(radio->core->regmap,
+ (unsigned int)reg->reg,
+ (unsigned int)reg->val);
+ si476x_core_unlock(radio->core);
+
+ return err;
+}
+#endif
+
+static int si476x_radio_fops_open(struct file *file)
+{
+ struct si476x_radio *radio = video_drvdata(file);
+ int err;
+
+ err = v4l2_fh_open(file);
+ if (err)
+ return err;
+
+ if (v4l2_fh_is_singular_file(file)) {
+ si476x_core_lock(radio->core);
+ err = si476x_core_set_power_state(radio->core,
+ SI476X_POWER_UP_FULL);
+ if (err < 0)
+ goto done;
+
+ err = si476x_radio_do_post_powerup_init(radio,
+ radio->core->power_up_parameters.func);
+ if (err < 0)
+ goto power_down;
+
+ err = si476x_radio_pretune(radio,
+ radio->core->power_up_parameters.func);
+ if (err < 0)
+ goto power_down;
+
+ si476x_core_unlock(radio->core);
+ /*Must be done after si476x_core_unlock to prevent a deadlock*/
+ v4l2_ctrl_handler_setup(&radio->ctrl_handler);
+ }
+
+ return err;
+
+power_down:
+ si476x_core_set_power_state(radio->core,
+ SI476X_POWER_DOWN);
+done:
+ si476x_core_unlock(radio->core);
+ v4l2_fh_release(file);
+
+ return err;
+}
+
+static int si476x_radio_fops_release(struct file *file)
+{
+ int err;
+ struct si476x_radio *radio = video_drvdata(file);
+
+ if (v4l2_fh_is_singular_file(file) &&
+ atomic_read(&radio->core->is_alive))
+ si476x_core_set_power_state(radio->core,
+ SI476X_POWER_DOWN);
+
+ err = v4l2_fh_release(file);
+
+ return err;
+}
+
+static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rval;
+ size_t fifo_len;
+ unsigned int copied;
+
+ struct si476x_radio *radio = video_drvdata(file);
+
+ /* block if no new data available */
+ if (kfifo_is_empty(&radio->core->rds_fifo)) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ rval = wait_event_interruptible(radio->core->rds_read_queue,
+ (!kfifo_is_empty(&radio->core->rds_fifo) ||
+ !atomic_read(&radio->core->is_alive)));
+ if (rval < 0)
+ return -EINTR;
+
+ if (!atomic_read(&radio->core->is_alive))
+ return -ENODEV;
+ }
+
+ fifo_len = kfifo_len(&radio->core->rds_fifo);
+
+ if (kfifo_to_user(&radio->core->rds_fifo, buf,
+ min(fifo_len, count),
+ &copied) != 0) {
+ dev_warn(&radio->videodev.dev,
+ "Error during FIFO to userspace copy\n");
+ rval = -EIO;
+ } else {
+ rval = (ssize_t)copied;
+ }
+
+ return rval;
+}
+
+static unsigned int si476x_radio_fops_poll(struct file *file,
+ struct poll_table_struct *pts)
+{
+ struct si476x_radio *radio = video_drvdata(file);
+ unsigned long req_events = poll_requested_events(pts);
+ unsigned int err = v4l2_ctrl_poll(file, pts);
+
+ if (req_events & (POLLIN | POLLRDNORM)) {
+ if (atomic_read(&radio->core->is_alive))
+ poll_wait(file, &radio->core->rds_read_queue, pts);
+
+ if (!atomic_read(&radio->core->is_alive))
+ err = POLLHUP;
+
+ if (!kfifo_is_empty(&radio->core->rds_fifo))
+ err = POLLIN | POLLRDNORM;
+ }
+
+ return err;
+}
+
+static const struct v4l2_file_operations si476x_fops = {
+ .owner = THIS_MODULE,
+ .read = si476x_radio_fops_read,
+ .poll = si476x_radio_fops_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .open = si476x_radio_fops_open,
+ .release = si476x_radio_fops_release,
+};
+
+
+static const struct v4l2_ioctl_ops si4761_ioctl_ops = {
+ .vidioc_querycap = si476x_radio_querycap,
+ .vidioc_g_tuner = si476x_radio_g_tuner,
+ .vidioc_s_tuner = si476x_radio_s_tuner,
+
+ .vidioc_g_frequency = si476x_radio_g_frequency,
+ .vidioc_s_frequency = si476x_radio_s_frequency,
+ .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek,
+ .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_g_chip_ident = si476x_radio_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = si476x_radio_g_register,
+ .vidioc_s_register = si476x_radio_s_register,
+#endif
+};
+
+
+static const struct video_device si476x_viddev_template = {
+ .fops = &si476x_fops,
+ .name = DRIVER_NAME,
+ .release = video_device_release_empty,
+};
+
+
+
+static ssize_t si476x_radio_read_acf_blob(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ struct si476x_radio *radio = file->private_data;
+ struct si476x_acf_status_report report;
+
+ si476x_core_lock(radio->core);
+ if (radio->ops->acf_status)
+ err = radio->ops->acf_status(radio->core, &report);
+ else
+ err = -ENOENT;
+ si476x_core_unlock(radio->core);
+
+ if (err < 0)
+ return err;
+
+ return simple_read_from_buffer(user_buf, count, ppos, &report,
+ sizeof(report));
+}
+
+static const struct file_operations radio_acf_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = si476x_radio_read_acf_blob,
+};
+
+static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ struct si476x_radio *radio = file->private_data;
+ struct si476x_rds_blockcount_report report;
+
+ si476x_core_lock(radio->core);
+ if (radio->ops->rds_blckcnt)
+ err = radio->ops->rds_blckcnt(radio->core, true,
+ &report);
+ else
+ err = -ENOENT;
+ si476x_core_unlock(radio->core);
+
+ if (err < 0)
+ return err;
+
+ return simple_read_from_buffer(user_buf, count, ppos, &report,
+ sizeof(report));
+}
+
+static const struct file_operations radio_rds_blckcnt_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = si476x_radio_read_rds_blckcnt_blob,
+};
+
+static ssize_t si476x_radio_read_agc_blob(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ struct si476x_radio *radio = file->private_data;
+ struct si476x_agc_status_report report;
+
+ si476x_core_lock(radio->core);
+ if (radio->ops->rds_blckcnt)
+ err = radio->ops->agc_status(radio->core, &report);
+ else
+ err = -ENOENT;
+ si476x_core_unlock(radio->core);
+
+ if (err < 0)
+ return err;
+
+ return simple_read_from_buffer(user_buf, count, ppos, &report,
+ sizeof(report));
+}
+
+static const struct file_operations radio_agc_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = si476x_radio_read_agc_blob,
+};
+
+static ssize_t si476x_radio_read_rsq_blob(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ struct si476x_radio *radio = file->private_data;
+ struct si476x_rsq_status_report report;
+ struct si476x_rsq_status_args args = {
+ .primary = false,
+ .rsqack = false,
+ .attune = false,
+ .cancel = false,
+ .stcack = false,
+ };
+
+ si476x_core_lock(radio->core);
+ if (radio->ops->rds_blckcnt)
+ err = radio->ops->rsq_status(radio->core, &args, &report);
+ else
+ err = -ENOENT;
+ si476x_core_unlock(radio->core);
+
+ if (err < 0)
+ return err;
+
+ return simple_read_from_buffer(user_buf, count, ppos, &report,
+ sizeof(report));
+}
+
+static const struct file_operations radio_rsq_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = si476x_radio_read_rsq_blob,
+};
+
+static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int err;
+ struct si476x_radio *radio = file->private_data;
+ struct si476x_rsq_status_report report;
+ struct si476x_rsq_status_args args = {
+ .primary = true,
+ .rsqack = false,
+ .attune = false,
+ .cancel = false,
+ .stcack = false,
+ };
+
+ si476x_core_lock(radio->core);
+ if (radio->ops->rds_blckcnt)
+ err = radio->ops->rsq_status(radio->core, &args, &report);
+ else
+ err = -ENOENT;
+ si476x_core_unlock(radio->core);
+
+ if (err < 0)
+ return err;
+
+ return simple_read_from_buffer(user_buf, count, ppos, &report,
+ sizeof(report));
+}
+
+static const struct file_operations radio_rsq_primary_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = si476x_radio_read_rsq_primary_blob,
+};
+
+
+static int si476x_radio_init_debugfs(struct si476x_radio *radio)
+{
+ struct dentry *dentry;
+ int ret;
+
+ dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto exit;
+ }
+ radio->debugfs = dentry;
+
+ dentry = debugfs_create_file("acf", S_IRUGO,
+ radio->debugfs, radio, &radio_acf_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto cleanup;
+ }
+
+ dentry = debugfs_create_file("rds_blckcnt", S_IRUGO,
+ radio->debugfs, radio,
+ &radio_rds_blckcnt_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto cleanup;
+ }
+
+ dentry = debugfs_create_file("agc", S_IRUGO,
+ radio->debugfs, radio, &radio_agc_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto cleanup;
+ }
+
+ dentry = debugfs_create_file("rsq", S_IRUGO,
+ radio->debugfs, radio, &radio_rsq_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto cleanup;
+ }
+
+ dentry = debugfs_create_file("rsq_primary", S_IRUGO,
+ radio->debugfs, radio,
+ &radio_rsq_primary_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto cleanup;
+ }
+
+ return 0;
+cleanup:
+ debugfs_remove_recursive(radio->debugfs);
+exit:
+ return ret;
+}
+
+
+static int si476x_radio_add_new_custom(struct si476x_radio *radio,
+ enum si476x_ctrl_idx idx)
+{
+ int rval;
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler,
+ &si476x_ctrls[idx],
+ NULL);
+ rval = radio->ctrl_handler.error;
+ if (ctrl == NULL && rval)
+ dev_err(radio->v4l2dev.dev,
+ "Could not initialize '%s' control %d\n",
+ si476x_ctrls[idx].name, rval);
+
+ return rval;
+}
+
+static int si476x_radio_probe(struct platform_device *pdev)
+{
+ int rval;
+ struct si476x_radio *radio;
+ struct v4l2_ctrl *ctrl;
+
+ static atomic_t instance = ATOMIC_INIT(0);
+
+ radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL);
+ if (!radio)
+ return -ENOMEM;
+
+ radio->core = i2c_mfd_cell_to_core(&pdev->dev);
+
+ v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance);
+
+ rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
+ if (rval) {
+ dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
+ return rval;
+ }
+
+ memcpy(&radio->videodev, &si476x_viddev_template,
+ sizeof(struct video_device));
+
+ radio->videodev.v4l2_dev = &radio->v4l2dev;
+ radio->videodev.ioctl_ops = &si4761_ioctl_ops;
+
+ video_set_drvdata(&radio->videodev, radio);
+ platform_set_drvdata(pdev, radio);
+
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
+
+ radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
+ v4l2_ctrl_handler_init(&radio->ctrl_handler,
+ 1 + ARRAY_SIZE(si476x_ctrls));
+
+ if (si476x_core_has_am(radio->core)) {
+ ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
+ &si476x_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ 0, 0);
+ rval = radio->ctrl_handler.error;
+ if (ctrl == NULL && rval) {
+ dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n",
+ rval);
+ goto exit;
+ }
+
+ rval = si476x_radio_add_new_custom(radio,
+ SI476X_IDX_HARMONICS_COUNT);
+ if (rval < 0)
+ goto exit;
+ }
+
+ rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD);
+ if (rval < 0)
+ goto exit;
+
+ rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD);
+ if (rval < 0)
+ goto exit;
+
+ rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR);
+ if (rval < 0)
+ goto exit;
+
+ ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler,
+ &si476x_ctrl_ops,
+ V4L2_CID_TUNE_DEEMPHASIS,
+ V4L2_DEEMPHASIS_75_uS, 0, 0);
+ rval = radio->ctrl_handler.error;
+ if (ctrl == NULL && rval) {
+ dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n",
+ rval);
+ goto exit;
+ }
+
+ ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops,
+ V4L2_CID_RDS_RECEPTION,
+ 0, 1, 1, 1);
+ rval = radio->ctrl_handler.error;
+ if (ctrl == NULL && rval) {
+ dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n",
+ rval);
+ goto exit;
+ }
+
+ if (si476x_core_has_diversity(radio->core)) {
+ si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def =
+ si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode);
+ si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE);
+ if (rval < 0)
+ goto exit;
+
+ si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK);
+ if (rval < 0)
+ goto exit;
+ }
+
+ /* register video device */
+ rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "Could not register video device\n");
+ goto exit;
+ }
+
+ rval = si476x_radio_init_debugfs(radio);
+ if (rval < 0) {
+ dev_err(&pdev->dev, "Could not creat debugfs interface\n");
+ goto exit;
+ }
+
+ return 0;
+exit:
+ v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
+ return rval;
+}
+
+static int si476x_radio_remove(struct platform_device *pdev)
+{
+ struct si476x_radio *radio = platform_get_drvdata(pdev);
+
+ v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
+ video_unregister_device(&radio->videodev);
+ v4l2_device_unregister(&radio->v4l2dev);
+ debugfs_remove_recursive(radio->debugfs);
+
+ return 0;
+}
+
+MODULE_ALIAS("platform:si476x-radio");
+
+static struct platform_driver si476x_radio_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = si476x_radio_probe,
+ .remove = si476x_radio_remove,
+};
+module_platform_driver(si476x_radio_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
+MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 1978516af67e..38d563d62595 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -339,7 +339,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct tea5764_device *radio = video_drvdata(file);
@@ -351,7 +351,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct tea5764_device *radio = video_drvdata(file);
diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c
index 4b5190d4fea5..e2455970725a 100644
--- a/drivers/media/radio/radio-tea5777.c
+++ b/drivers/media/radio/radio-tea5777.c
@@ -336,7 +336,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct radio_tea5777 *tea = video_drvdata(file);
u32 orig_audmode = tea->audmode;
@@ -344,10 +344,9 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (v->index)
return -EINVAL;
- if (v->audmode > V4L2_TUNER_MODE_STEREO)
- v->audmode = V4L2_TUNER_MODE_STEREO;
-
tea->audmode = v->audmode;
+ if (tea->audmode > V4L2_TUNER_MODE_STEREO)
+ tea->audmode = V4L2_TUNER_MODE_STEREO;
if (tea->audmode != orig_audmode && tea->band == BAND_FM)
return radio_tea5777_set_freq(tea);
@@ -368,7 +367,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct radio_tea5777 *tea = video_drvdata(file);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index b87effeb5dc6..bb7b143b65d1 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -56,7 +56,7 @@ static int timbradio_vidioc_g_tuner(struct file *file, void *priv,
}
static int timbradio_vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct timbradio *tr = video_drvdata(file);
return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v);
@@ -91,7 +91,7 @@ static int timbradio_vidioc_s_audio(struct file *file, void *priv,
}
static int timbradio_vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct timbradio *tr = video_drvdata(file);
return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f);
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 02151e0e6e63..97c2c18803ef 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1559,7 +1559,7 @@ out:
}
static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
+ const struct v4l2_tuner *tuner)
{
struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
struct wl1273_core *core = radio->core;
@@ -1640,7 +1640,7 @@ static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv,
}
static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
struct wl1273_core *core = radio->core;
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 18989388ddc1..5c57e5b0f949 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -636,7 +636,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
* si470x_vidioc_s_tuner - set tuner attributes
*/
static int si470x_vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
+ const struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
@@ -678,7 +678,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
* si470x_vidioc_s_frequency - set tuner or modulator radio frequency
*/
static int si470x_vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct si470x_device *radio = video_drvdata(file);
int retval;
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index bd61b3bd0ca3..fe160882ee10 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -21,7 +21,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -53,8 +52,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
#define DEFAULT_RDS_PI 0x00
#define DEFAULT_RDS_PTY 0x00
-#define DEFAULT_RDS_PS_NAME ""
-#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME
#define DEFAULT_RDS_DEVIATION 0x00C8
#define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003
#define DEFAULT_LIMITER_RTIME 0x1392
@@ -108,7 +105,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
(status & SI4713_ERR))
/* mute definition */
#define set_mute(p) ((p & 1) | ((p & 1) << 1));
-#define get_mute(p) (p & 0x01)
#ifdef DEBUG
#define DBG_BUFFER(device, message, buffer, size) \
@@ -190,21 +186,6 @@ static int usecs_to_dev(unsigned long usecs, unsigned long const array[],
return rval;
}
-static unsigned long dev_to_usecs(int value, unsigned long const array[],
- int size)
-{
- int i;
- int rval = -EINVAL;
-
- for (i = 0; i < size / 2; i++)
- if (array[i * 2] == value) {
- rval = array[(i * 2) + 1];
- break;
- }
-
- return rval;
-}
-
/* si4713_handler: IRQ handler, just complete work */
static irqreturn_t si4713_handler(int irq, void *dev)
{
@@ -458,15 +439,13 @@ static int si4713_checkrev(struct si4713_device *sdev)
int rval;
u8 resp[SI4713_GETREV_NRESP];
- mutex_lock(&sdev->mutex);
-
rval = si4713_send_command(sdev, SI4713_CMD_GET_REV,
NULL, 0,
resp, ARRAY_SIZE(resp),
DEFAULT_TIMEOUT);
if (rval < 0)
- goto unlock;
+ return rval;
if (resp[1] == SI4713_PRODUCT_NUMBER) {
v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n",
@@ -475,9 +454,6 @@ static int si4713_checkrev(struct si4713_device *sdev)
v4l2_err(&sdev->sd, "Invalid product number\n");
rval = -EINVAL;
}
-
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
@@ -778,17 +754,9 @@ static int si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid,
static int si4713_set_power_state(struct si4713_device *sdev, u8 value)
{
- int rval;
-
- mutex_lock(&sdev->mutex);
-
if (value)
- rval = si4713_powerup(sdev);
- else
- rval = si4713_powerdown(sdev);
-
- mutex_unlock(&sdev->mutex);
- return rval;
+ return si4713_powerup(sdev);
+ return si4713_powerdown(sdev);
}
static int si4713_set_mute(struct si4713_device *sdev, u16 mute)
@@ -797,17 +765,10 @@ static int si4713_set_mute(struct si4713_device *sdev, u16 mute)
mute = set_mute(mute);
- mutex_lock(&sdev->mutex);
-
if (sdev->power_state)
rval = si4713_write_property(sdev,
SI4713_TX_LINE_INPUT_MUTE, mute);
- if (rval >= 0)
- sdev->mute = get_mute(mute);
-
- mutex_unlock(&sdev->mutex);
-
return rval;
}
@@ -820,15 +781,13 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
if (!strlen(ps_name))
memset(ps_name, 0, MAX_RDS_PS_NAME + 1);
- mutex_lock(&sdev->mutex);
-
if (sdev->power_state) {
/* Write the new ps name and clear the padding */
for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) {
rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)),
ps_name + i);
if (rval < 0)
- goto unlock;
+ return rval;
}
/* Setup the size to be sent */
@@ -841,19 +800,15 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
SI4713_TX_RDS_PS_MESSAGE_COUNT,
rds_ps_nblocks(len));
if (rval < 0)
- goto unlock;
+ return rval;
rval = si4713_write_property(sdev,
SI4713_TX_RDS_PS_REPEAT_COUNT,
DEFAULT_RDS_PS_REPEAT_COUNT * 2);
if (rval < 0)
- goto unlock;
+ return rval;
}
- strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME);
-
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
@@ -864,27 +819,24 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
u8 b_index = 0, cr_inserted = 0;
s8 left;
- mutex_lock(&sdev->mutex);
-
if (!sdev->power_state)
- goto copy;
+ return rval;
rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left);
if (rval < 0)
- goto unlock;
+ return rval;
if (!strlen(rt))
- goto copy;
+ return rval;
do {
/* RDS spec says that if the last block isn't used,
* then apply a carriage return
*/
- if (t_index < (RDS_RADIOTEXT_INDEX_MAX *
- RDS_RADIOTEXT_BLK_SIZE)) {
+ if (t_index < (RDS_RADIOTEXT_INDEX_MAX * RDS_RADIOTEXT_BLK_SIZE)) {
for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) {
- if (!rt[t_index + i] || rt[t_index + i] ==
- RDS_CARRIAGE_RETURN) {
+ if (!rt[t_index + i] ||
+ rt[t_index + i] == RDS_CARRIAGE_RETURN) {
rt[t_index + i] = RDS_CARRIAGE_RETURN;
cr_inserted = 1;
break;
@@ -898,7 +850,7 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
compose_u16(rt[t_index + 2], rt[t_index + 3]),
&left);
if (rval < 0)
- goto unlock;
+ return rval;
t_index += RDS_RADIOTEXT_BLK_SIZE;
@@ -906,16 +858,38 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
break;
} while (left > 0);
-copy:
- strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT);
+ return rval;
+}
-unlock:
- mutex_unlock(&sdev->mutex);
+/*
+ * si4713_update_tune_status - update properties from tx_tune_status
+ * command. Must be called with sdev->mutex held.
+ * @sdev: si4713_device structure for the device we are communicating
+ */
+static int si4713_update_tune_status(struct si4713_device *sdev)
+{
+ int rval;
+ u16 f = 0;
+ u8 p = 0, a = 0, n = 0;
+
+ rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n);
+
+ if (rval < 0)
+ goto exit;
+
+/* TODO: check that power_level and antenna_capacitor really are not
+ changed by the hardware. If they are, then these controls should become
+ volatiles.
+ sdev->power_level = p;
+ sdev->antenna_capacitor = a;*/
+ sdev->tune_rnl = n;
+
+exit:
return rval;
}
static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
- u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul,
+ s32 *bit, s32 *mask, u16 *property, int *mul,
unsigned long **table, int *size)
{
s32 rval = 0;
@@ -925,157 +899,71 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
case V4L2_CID_RDS_TX_PI:
*property = SI4713_TX_RDS_PI;
*mul = 1;
- *shadow = &sdev->rds_info.pi;
break;
case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
*property = SI4713_TX_ACOMP_THRESHOLD;
*mul = 1;
- *shadow = &sdev->acomp_info.threshold;
break;
case V4L2_CID_AUDIO_COMPRESSION_GAIN:
*property = SI4713_TX_ACOMP_GAIN;
*mul = 1;
- *shadow = &sdev->acomp_info.gain;
break;
case V4L2_CID_PILOT_TONE_FREQUENCY:
*property = SI4713_TX_PILOT_FREQUENCY;
*mul = 1;
- *shadow = &sdev->pilot_info.frequency;
break;
case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
*property = SI4713_TX_ACOMP_ATTACK_TIME;
*mul = ATTACK_TIME_UNIT;
- *shadow = &sdev->acomp_info.attack_time;
break;
case V4L2_CID_PILOT_TONE_DEVIATION:
*property = SI4713_TX_PILOT_DEVIATION;
*mul = 10;
- *shadow = &sdev->pilot_info.deviation;
break;
case V4L2_CID_AUDIO_LIMITER_DEVIATION:
*property = SI4713_TX_AUDIO_DEVIATION;
*mul = 10;
- *shadow = &sdev->limiter_info.deviation;
break;
case V4L2_CID_RDS_TX_DEVIATION:
*property = SI4713_TX_RDS_DEVIATION;
*mul = 1;
- *shadow = &sdev->rds_info.deviation;
break;
case V4L2_CID_RDS_TX_PTY:
*property = SI4713_TX_RDS_PS_MISC;
*bit = 5;
*mask = 0x1F << 5;
- *shadow = &sdev->rds_info.pty;
break;
case V4L2_CID_AUDIO_LIMITER_ENABLED:
*property = SI4713_TX_ACOMP_ENABLE;
*bit = 1;
*mask = 1 << 1;
- *shadow = &sdev->limiter_info.enabled;
break;
case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
*property = SI4713_TX_ACOMP_ENABLE;
*bit = 0;
*mask = 1 << 0;
- *shadow = &sdev->acomp_info.enabled;
break;
case V4L2_CID_PILOT_TONE_ENABLED:
*property = SI4713_TX_COMPONENT_ENABLE;
*bit = 0;
*mask = 1 << 0;
- *shadow = &sdev->pilot_info.enabled;
break;
case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
*property = SI4713_TX_LIMITER_RELEASE_TIME;
*table = limiter_times;
*size = ARRAY_SIZE(limiter_times);
- *shadow = &sdev->limiter_info.release_time;
break;
case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
*property = SI4713_TX_ACOMP_RELEASE_TIME;
*table = acomp_rtimes;
*size = ARRAY_SIZE(acomp_rtimes);
- *shadow = &sdev->acomp_info.release_time;
break;
case V4L2_CID_TUNE_PREEMPHASIS:
*property = SI4713_TX_PREEMPHASIS;
*table = preemphasis_values;
*size = ARRAY_SIZE(preemphasis_values);
- *shadow = &sdev->preemphasis;
- break;
-
- default:
- rval = -EINVAL;
- }
-
- return rval;
-}
-
-static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc);
-
-/* write string property */
-static int si4713_write_econtrol_string(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
-{
- struct v4l2_queryctrl vqc;
- int len;
- s32 rval = 0;
-
- vqc.id = control->id;
- rval = si4713_queryctrl(&sdev->sd, &vqc);
- if (rval < 0)
- goto exit;
-
- switch (control->id) {
- case V4L2_CID_RDS_TX_PS_NAME: {
- char ps_name[MAX_RDS_PS_NAME + 1];
-
- len = control->size - 1;
- if (len < 0 || len > MAX_RDS_PS_NAME) {
- rval = -ERANGE;
- goto exit;
- }
- rval = copy_from_user(ps_name, control->string, len);
- if (rval) {
- rval = -EFAULT;
- goto exit;
- }
- ps_name[len] = '\0';
-
- if (strlen(ps_name) % vqc.step) {
- rval = -ERANGE;
- goto exit;
- }
-
- rval = si4713_set_rds_ps_name(sdev, ps_name);
- }
- break;
-
- case V4L2_CID_RDS_TX_RADIO_TEXT: {
- char radio_text[MAX_RDS_RADIO_TEXT + 1];
-
- len = control->size - 1;
- if (len < 0 || len > MAX_RDS_RADIO_TEXT) {
- rval = -ERANGE;
- goto exit;
- }
- rval = copy_from_user(radio_text, control->string, len);
- if (rval) {
- rval = -EFAULT;
- goto exit;
- }
- radio_text[len] = '\0';
-
- if (strlen(radio_text) % vqc.step) {
- rval = -ERANGE;
- goto exit;
- }
-
- rval = si4713_set_rds_radio_text(sdev, radio_text);
- }
break;
default:
@@ -1083,136 +971,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
break;
}
-exit:
- return rval;
-}
-
-static int validate_range(struct v4l2_subdev *sd,
- struct v4l2_ext_control *control)
-{
- struct v4l2_queryctrl vqc;
- int rval;
-
- vqc.id = control->id;
- rval = si4713_queryctrl(sd, &vqc);
- if (rval < 0)
- goto exit;
-
- if (control->value < vqc.minimum || control->value > vqc.maximum)
- rval = -ERANGE;
-
-exit:
- return rval;
-}
-
-/* properties which use tx_tune_power*/
-static int si4713_write_econtrol_tune(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
-{
- s32 rval = 0;
- u8 power, antcap;
-
- rval = validate_range(&sdev->sd, control);
- if (rval < 0)
- goto exit;
-
- mutex_lock(&sdev->mutex);
-
- switch (control->id) {
- case V4L2_CID_TUNE_POWER_LEVEL:
- power = control->value;
- antcap = sdev->antenna_capacitor;
- break;
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- power = sdev->power_level;
- antcap = control->value;
- break;
- default:
- rval = -EINVAL;
- goto unlock;
- }
-
- if (sdev->power_state)
- rval = si4713_tx_tune_power(sdev, power, antcap);
-
- if (rval == 0) {
- sdev->power_level = power;
- sdev->antenna_capacitor = antcap;
- }
-
-unlock:
- mutex_unlock(&sdev->mutex);
-exit:
- return rval;
-}
-
-static int si4713_write_econtrol_integers(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
-{
- s32 rval;
- u32 *shadow = NULL, val = 0;
- s32 bit = 0, mask = 0;
- u16 property = 0;
- int mul = 0;
- unsigned long *table = NULL;
- int size = 0;
-
- rval = validate_range(&sdev->sd, control);
- if (rval < 0)
- goto exit;
-
- rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
- &mask, &property, &mul, &table, &size);
- if (rval < 0)
- goto exit;
-
- val = control->value;
- if (mul) {
- val = control->value / mul;
- } else if (table) {
- rval = usecs_to_dev(control->value, table, size);
- if (rval < 0)
- goto exit;
- val = rval;
- rval = 0;
- }
-
- mutex_lock(&sdev->mutex);
-
- if (sdev->power_state) {
- if (mask) {
- rval = si4713_read_property(sdev, property, &val);
- if (rval < 0)
- goto unlock;
- val = set_bits(val, control->value, bit, mask);
- }
-
- rval = si4713_write_property(sdev, property, val);
- if (rval < 0)
- goto unlock;
- if (mask)
- val = control->value;
- }
-
- if (mul) {
- *shadow = val * mul;
- } else if (table) {
- rval = dev_to_usecs(val, table, size);
- if (rval < 0)
- goto unlock;
- *shadow = rval;
- rval = 0;
- } else {
- *shadow = val;
- }
-
-unlock:
- mutex_unlock(&sdev->mutex);
-exit:
return rval;
}
-static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f);
+static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f);
static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulator *);
/*
* si4713_setup - Sets the device up with current configuration.
@@ -1220,111 +982,25 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato
*/
static int si4713_setup(struct si4713_device *sdev)
{
- struct v4l2_ext_control ctrl;
struct v4l2_frequency f;
struct v4l2_modulator vm;
- struct si4713_device *tmp;
- int rval = 0;
-
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- /* Get a local copy to avoid race */
- mutex_lock(&sdev->mutex);
- memcpy(tmp, sdev, sizeof(*sdev));
- mutex_unlock(&sdev->mutex);
-
- ctrl.id = V4L2_CID_RDS_TX_PI;
- ctrl.value = tmp->rds_info.pi;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD;
- ctrl.value = tmp->acomp_info.threshold;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN;
- ctrl.value = tmp->acomp_info.gain;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY;
- ctrl.value = tmp->pilot_info.frequency;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME;
- ctrl.value = tmp->acomp_info.attack_time;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION;
- ctrl.value = tmp->pilot_info.deviation;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION;
- ctrl.value = tmp->limiter_info.deviation;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_RDS_TX_DEVIATION;
- ctrl.value = tmp->rds_info.deviation;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_RDS_TX_PTY;
- ctrl.value = tmp->rds_info.pty;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED;
- ctrl.value = tmp->limiter_info.enabled;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED;
- ctrl.value = tmp->acomp_info.enabled;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_PILOT_TONE_ENABLED;
- ctrl.value = tmp->pilot_info.enabled;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME;
- ctrl.value = tmp->limiter_info.release_time;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME;
- ctrl.value = tmp->acomp_info.release_time;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_TUNE_PREEMPHASIS;
- ctrl.value = tmp->preemphasis;
- rval |= si4713_write_econtrol_integers(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_RDS_TX_PS_NAME;
- rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name);
-
- ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT;
- rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text);
+ int rval;
/* Device procedure needs to set frequency first */
- f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY;
+ f.tuner = 0;
+ f.frequency = sdev->frequency ? sdev->frequency : DEFAULT_FREQUENCY;
f.frequency = si4713_to_v4l2(f.frequency);
- rval |= si4713_s_frequency(&sdev->sd, &f);
-
- ctrl.id = V4L2_CID_TUNE_POWER_LEVEL;
- ctrl.value = tmp->power_level;
- rval |= si4713_write_econtrol_tune(sdev, &ctrl);
-
- ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
- ctrl.value = tmp->antenna_capacitor;
- rval |= si4713_write_econtrol_tune(sdev, &ctrl);
+ rval = si4713_s_frequency(&sdev->sd, &f);
vm.index = 0;
- if (tmp->stereo)
+ if (sdev->stereo)
vm.txsubchans = V4L2_TUNER_SUB_STEREO;
else
vm.txsubchans = V4L2_TUNER_SUB_MONO;
- if (tmp->rds_info.enabled)
+ if (sdev->rds_enabled)
vm.txsubchans |= V4L2_TUNER_SUB_RDS;
si4713_s_modulator(&sdev->sd, &vm);
- kfree(tmp);
-
return rval;
}
@@ -1338,434 +1014,126 @@ static int si4713_initialize(struct si4713_device *sdev)
rval = si4713_set_power_state(sdev, POWER_ON);
if (rval < 0)
- goto exit;
+ return rval;
rval = si4713_checkrev(sdev);
if (rval < 0)
- goto exit;
+ return rval;
rval = si4713_set_power_state(sdev, POWER_OFF);
if (rval < 0)
- goto exit;
-
- mutex_lock(&sdev->mutex);
-
- sdev->rds_info.pi = DEFAULT_RDS_PI;
- sdev->rds_info.pty = DEFAULT_RDS_PTY;
- sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION;
- strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME);
- strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT,
- MAX_RDS_RADIO_TEXT);
- sdev->rds_info.enabled = 1;
-
- sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME;
- sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV;
- sdev->limiter_info.enabled = 1;
-
- sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION;
- sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY;
- sdev->pilot_info.enabled = 1;
+ return rval;
- sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME;
- sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME;
- sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD;
- sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN;
- sdev->acomp_info.enabled = 1;
sdev->frequency = DEFAULT_FREQUENCY;
- sdev->preemphasis = DEFAULT_PREEMPHASIS;
- sdev->mute = DEFAULT_MUTE;
- sdev->power_level = DEFAULT_POWER_LEVEL;
- sdev->antenna_capacitor = 0;
sdev->stereo = 1;
sdev->tune_rnl = DEFAULT_TUNE_RNL;
-
- mutex_unlock(&sdev->mutex);
-
-exit:
- return rval;
-}
-
-/* read string property */
-static int si4713_read_econtrol_string(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
-{
- s32 rval = 0;
-
- switch (control->id) {
- case V4L2_CID_RDS_TX_PS_NAME:
- if (strlen(sdev->rds_info.ps_name) + 1 > control->size) {
- control->size = MAX_RDS_PS_NAME + 1;
- rval = -ENOSPC;
- goto exit;
- }
- rval = copy_to_user(control->string, sdev->rds_info.ps_name,
- strlen(sdev->rds_info.ps_name) + 1);
- if (rval)
- rval = -EFAULT;
- break;
-
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- if (strlen(sdev->rds_info.radio_text) + 1 > control->size) {
- control->size = MAX_RDS_RADIO_TEXT + 1;
- rval = -ENOSPC;
- goto exit;
- }
- rval = copy_to_user(control->string, sdev->rds_info.radio_text,
- strlen(sdev->rds_info.radio_text) + 1);
- if (rval)
- rval = -EFAULT;
- break;
-
- default:
- rval = -EINVAL;
- break;
- }
-
-exit:
- return rval;
-}
-
-/*
- * si4713_update_tune_status - update properties from tx_tune_status
- * command. Must be called with sdev->mutex held.
- * @sdev: si4713_device structure for the device we are communicating
- */
-static int si4713_update_tune_status(struct si4713_device *sdev)
-{
- int rval;
- u16 f = 0;
- u8 p = 0, a = 0, n = 0;
-
- rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n);
-
- if (rval < 0)
- goto exit;
-
- sdev->power_level = p;
- sdev->antenna_capacitor = a;
- sdev->tune_rnl = n;
-
-exit:
- return rval;
-}
-
-/* properties which use tx_tune_status */
-static int si4713_read_econtrol_tune(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
-{
- s32 rval = 0;
-
- mutex_lock(&sdev->mutex);
-
- if (sdev->power_state) {
- rval = si4713_update_tune_status(sdev);
- if (rval < 0)
- goto unlock;
- }
-
- switch (control->id) {
- case V4L2_CID_TUNE_POWER_LEVEL:
- control->value = sdev->power_level;
- break;
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- control->value = sdev->antenna_capacitor;
- break;
- default:
- rval = -EINVAL;
- }
-
-unlock:
- mutex_unlock(&sdev->mutex);
- return rval;
+ return 0;
}
-static int si4713_read_econtrol_integers(struct si4713_device *sdev,
- struct v4l2_ext_control *control)
+/* si4713_s_ctrl - set the value of a control */
+static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
{
- s32 rval;
- u32 *shadow = NULL, val = 0;
+ struct si4713_device *sdev =
+ container_of(ctrl->handler, struct si4713_device, ctrl_handler);
+ u32 val = 0;
s32 bit = 0, mask = 0;
u16 property = 0;
int mul = 0;
unsigned long *table = NULL;
int size = 0;
+ bool force = false;
+ int c;
+ int ret = 0;
- rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
- &mask, &property, &mul, &table, &size);
- if (rval < 0)
- goto exit;
-
- mutex_lock(&sdev->mutex);
-
- if (sdev->power_state) {
- rval = si4713_read_property(sdev, property, &val);
- if (rval < 0)
- goto unlock;
-
- /* Keep negative values for threshold */
- if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD)
- *shadow = (s16)val;
- else if (mask)
- *shadow = get_status_bit(val, bit, mask);
- else if (mul)
- *shadow = val * mul;
- else
- *shadow = dev_to_usecs(val, table, size);
- }
-
- control->value = *shadow;
-
-unlock:
- mutex_unlock(&sdev->mutex);
-exit:
- return rval;
-}
-
-/*
- * Video4Linux Subdev Interface
- */
-/* si4713_s_ext_ctrls - set extended controls value */
-static int si4713_s_ext_ctrls(struct v4l2_subdev *sd,
- struct v4l2_ext_controls *ctrls)
-{
- struct si4713_device *sdev = to_si4713_device(sd);
- int i;
-
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
return -EINVAL;
-
- for (i = 0; i < ctrls->count; i++) {
- int err;
-
- switch ((ctrls->controls + i)->id) {
- case V4L2_CID_RDS_TX_PS_NAME:
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- err = si4713_write_econtrol_string(sdev,
- ctrls->controls + i);
- break;
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- case V4L2_CID_TUNE_POWER_LEVEL:
- err = si4713_write_econtrol_tune(sdev,
- ctrls->controls + i);
- break;
- default:
- err = si4713_write_econtrol_integers(sdev,
- ctrls->controls + i);
- }
-
- if (err < 0) {
- ctrls->error_idx = i;
- return err;
+ if (ctrl->is_new) {
+ if (ctrl->val) {
+ ret = si4713_set_mute(sdev, ctrl->val);
+ if (!ret)
+ ret = si4713_set_power_state(sdev, POWER_DOWN);
+ return ret;
}
+ ret = si4713_set_power_state(sdev, POWER_UP);
+ if (!ret)
+ ret = si4713_set_mute(sdev, ctrl->val);
+ if (!ret)
+ ret = si4713_setup(sdev);
+ if (ret)
+ return ret;
+ force = true;
}
- return 0;
-}
+ if (!sdev->power_state)
+ return 0;
-/* si4713_g_ext_ctrls - get extended controls value */
-static int si4713_g_ext_ctrls(struct v4l2_subdev *sd,
- struct v4l2_ext_controls *ctrls)
-{
- struct si4713_device *sdev = to_si4713_device(sd);
- int i;
+ for (c = 1; !ret && c < ctrl->ncontrols; c++) {
+ ctrl = ctrl->cluster[c];
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
- return -EINVAL;
+ if (!force && !ctrl->is_new)
+ continue;
- for (i = 0; i < ctrls->count; i++) {
- int err;
-
- switch ((ctrls->controls + i)->id) {
+ switch (ctrl->id) {
case V4L2_CID_RDS_TX_PS_NAME:
+ ret = si4713_set_rds_ps_name(sdev, ctrl->string);
+ break;
+
case V4L2_CID_RDS_TX_RADIO_TEXT:
- err = si4713_read_econtrol_string(sdev,
- ctrls->controls + i);
+ ret = si4713_set_rds_radio_text(sdev, ctrl->string);
break;
+
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ /* don't handle this control if we force setting all
+ * controls since in that case it will be handled by
+ * V4L2_CID_TUNE_POWER_LEVEL. */
+ if (force)
+ break;
+ /* fall through */
case V4L2_CID_TUNE_POWER_LEVEL:
- err = si4713_read_econtrol_tune(sdev,
- ctrls->controls + i);
+ ret = si4713_tx_tune_power(sdev,
+ sdev->tune_pwr_level->val, sdev->tune_ant_cap->val);
+ if (!ret) {
+ /* Make sure we don't set this twice */
+ sdev->tune_ant_cap->is_new = false;
+ sdev->tune_pwr_level->is_new = false;
+ }
break;
- default:
- err = si4713_read_econtrol_integers(sdev,
- ctrls->controls + i);
- }
-
- if (err < 0) {
- ctrls->error_idx = i;
- return err;
- }
- }
-
- return 0;
-}
-
-/* si4713_queryctrl - enumerate control items */
-static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- int rval = 0;
-
- switch (qc->id) {
- /* User class controls */
- case V4L2_CID_AUDIO_MUTE:
- rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE);
- break;
- /* FM_TX class controls */
- case V4L2_CID_RDS_TX_PI:
- rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI);
- break;
- case V4L2_CID_RDS_TX_PTY:
- rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY);
- break;
- case V4L2_CID_RDS_TX_DEVIATION:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION,
- 10, DEFAULT_RDS_DEVIATION);
- break;
- case V4L2_CID_RDS_TX_PS_NAME:
- /*
- * Report step as 8. From RDS spec, psname
- * should be 8. But there are receivers which scroll strings
- * sized as 8xN.
- */
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0);
- break;
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- /*
- * Report step as 32 (2A block). From RDS spec,
- * radio text should be 32 for 2A block. But there are receivers
- * which scroll strings sized as 32xN. Setting default to 32.
- */
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0);
- break;
-
- case V4L2_CID_AUDIO_LIMITER_ENABLED:
- rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- break;
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
- rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME,
- 50, DEFAULT_LIMITER_RTIME);
- break;
- case V4L2_CID_AUDIO_LIMITER_DEVIATION:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION,
- 10, DEFAULT_LIMITER_DEV);
- break;
-
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
- rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- break;
- case V4L2_CID_AUDIO_COMPRESSION_GAIN:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1,
- DEFAULT_ACOMP_GAIN);
- break;
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
- rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD,
- MAX_ACOMP_THRESHOLD, 1,
- DEFAULT_ACOMP_THRESHOLD);
- break;
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME,
- 500, DEFAULT_ACOMP_ATIME);
- break;
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
- rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME,
- 100000, DEFAULT_ACOMP_RTIME);
- break;
-
- case V4L2_CID_PILOT_TONE_ENABLED:
- rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- break;
- case V4L2_CID_PILOT_TONE_DEVIATION:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION,
- 10, DEFAULT_PILOT_DEVIATION);
- break;
- case V4L2_CID_PILOT_TONE_FREQUENCY:
- rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY,
- 1, DEFAULT_PILOT_FREQUENCY);
- break;
-
- case V4L2_CID_TUNE_PREEMPHASIS:
- rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED,
- V4L2_PREEMPHASIS_75_uS, 1,
- V4L2_PREEMPHASIS_50_uS);
- break;
- case V4L2_CID_TUNE_POWER_LEVEL:
- rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL);
- break;
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0);
- break;
- default:
- rval = -EINVAL;
- break;
- }
-
- return rval;
-}
-
-/* si4713_g_ctrl - get the value of a control */
-static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct si4713_device *sdev = to_si4713_device(sd);
- int rval = 0;
-
- if (!sdev)
- return -ENODEV;
-
- mutex_lock(&sdev->mutex);
-
- if (sdev->power_state) {
- rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE,
- &sdev->mute);
-
- if (rval < 0)
- goto unlock;
- }
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = get_mute(sdev->mute);
- break;
- }
-
-unlock:
- mutex_unlock(&sdev->mutex);
- return rval;
-}
-
-/* si4713_s_ctrl - set the value of a control */
-static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct si4713_device *sdev = to_si4713_device(sd);
- int rval = 0;
-
- if (!sdev)
- return -ENODEV;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value) {
- rval = si4713_set_mute(sdev, ctrl->value);
- if (rval < 0)
- goto exit;
- rval = si4713_set_power_state(sdev, POWER_DOWN);
- } else {
- rval = si4713_set_power_state(sdev, POWER_UP);
- if (rval < 0)
- goto exit;
+ default:
+ ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
+ &mask, &property, &mul, &table, &size);
+ if (ret < 0)
+ break;
+
+ val = ctrl->val;
+ if (mul) {
+ val = val / mul;
+ } else if (table) {
+ ret = usecs_to_dev(val, table, size);
+ if (ret < 0)
+ break;
+ val = ret;
+ ret = 0;
+ }
- rval = si4713_setup(sdev);
- if (rval < 0)
- goto exit;
+ if (mask) {
+ ret = si4713_read_property(sdev, property, &val);
+ if (ret < 0)
+ break;
+ val = set_bits(val, ctrl->val, bit, mask);
+ }
- rval = si4713_set_mute(sdev, ctrl->value);
+ ret = si4713_write_property(sdev, property, val);
+ if (ret < 0)
+ break;
+ if (mask)
+ val = ctrl->val;
+ break;
}
- break;
}
-exit:
- return rval;
+ return ret;
}
/* si4713_ioctl - deal with private ioctls (only rnl for now) */
@@ -1779,7 +1147,6 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
if (!arg)
return -EINVAL;
- mutex_lock(&sdev->mutex);
switch (cmd) {
case SI4713_IOC_MEASURE_RNL:
frequency = v4l2_to_si4713(rnl->frequency);
@@ -1788,11 +1155,11 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
/* Set desired measurement frequency */
rval = si4713_tx_tune_measure(sdev, frequency, 0);
if (rval < 0)
- goto unlock;
+ return rval;
/* get results from tune status */
rval = si4713_update_tune_status(sdev);
if (rval < 0)
- goto unlock;
+ return rval;
}
rnl->rnl = sdev->tune_rnl;
break;
@@ -1802,35 +1169,20 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
rval = -ENOIOCTLCMD;
}
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
-static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
- .queryctrl = si4713_queryctrl,
- .g_ext_ctrls = si4713_g_ext_ctrls,
- .s_ext_ctrls = si4713_s_ext_ctrls,
- .g_ctrl = si4713_g_ctrl,
- .s_ctrl = si4713_s_ctrl,
- .ioctl = si4713_ioctl,
-};
-
/* si4713_g_modulator - get modulator attributes */
static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
{
struct si4713_device *sdev = to_si4713_device(sd);
int rval = 0;
- if (!sdev) {
- rval = -ENODEV;
- goto exit;
- }
+ if (!sdev)
+ return -ENODEV;
- if (vm->index > 0) {
- rval = -EINVAL;
- goto exit;
- }
+ if (vm->index > 0)
+ return -EINVAL;
strncpy(vm->name, "FM Modulator", 32);
vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
@@ -1840,18 +1192,15 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH);
- mutex_lock(&sdev->mutex);
-
if (sdev->power_state) {
u32 comp_en = 0;
rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE,
&comp_en);
if (rval < 0)
- goto unlock;
+ return rval;
sdev->stereo = get_status_bit(comp_en, 1, 1 << 1);
- sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2);
}
/* Report current audio mode: mono or stereo */
@@ -1861,14 +1210,11 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
vm->txsubchans = V4L2_TUNER_SUB_MONO;
/* Report rds feature status */
- if (sdev->rds_info.enabled)
+ if (sdev->rds_enabled)
vm->txsubchans |= V4L2_TUNER_SUB_RDS;
else
vm->txsubchans &= ~V4L2_TUNER_SUB_RDS;
-unlock:
- mutex_unlock(&sdev->mutex);
-exit:
return rval;
}
@@ -1896,13 +1242,11 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato
rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS);
- mutex_lock(&sdev->mutex);
-
if (sdev->power_state) {
rval = si4713_read_property(sdev,
SI4713_TX_COMPONENT_ENABLE, &p);
if (rval < 0)
- goto unlock;
+ return rval;
p = set_bits(p, stereo, 1, 1 << 1);
p = set_bits(p, rds, 2, 1 << 2);
@@ -1910,14 +1254,12 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato
rval = si4713_write_property(sdev,
SI4713_TX_COMPONENT_ENABLE, p);
if (rval < 0)
- goto unlock;
+ return rval;
}
sdev->stereo = stereo;
- sdev->rds_info.enabled = rds;
+ sdev->rds_enabled = rds;
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
@@ -1927,9 +1269,8 @@ static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
struct si4713_device *sdev = to_si4713_device(sd);
int rval = 0;
- f->type = V4L2_TUNER_RADIO;
-
- mutex_lock(&sdev->mutex);
+ if (f->tuner)
+ return -EINVAL;
if (sdev->power_state) {
u16 freq;
@@ -1937,46 +1278,49 @@ static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
rval = si4713_tx_tune_status(sdev, 0x00, &freq, &p, &a, &n);
if (rval < 0)
- goto unlock;
+ return rval;
sdev->frequency = freq;
}
f->frequency = si4713_to_v4l2(sdev->frequency);
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
/* si4713_s_frequency - set tuner or modulator radio frequency */
-static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f)
{
struct si4713_device *sdev = to_si4713_device(sd);
int rval = 0;
u16 frequency = v4l2_to_si4713(f->frequency);
- /* Check frequency range */
- if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH)
- return -EDOM;
+ if (f->tuner)
+ return -EINVAL;
- mutex_lock(&sdev->mutex);
+ /* Check frequency range */
+ frequency = clamp_t(u16, frequency, FREQ_RANGE_LOW, FREQ_RANGE_HIGH);
if (sdev->power_state) {
rval = si4713_tx_tune_freq(sdev, frequency);
if (rval < 0)
- goto unlock;
+ return rval;
frequency = rval;
rval = 0;
}
sdev->frequency = frequency;
- f->frequency = si4713_to_v4l2(frequency);
-unlock:
- mutex_unlock(&sdev->mutex);
return rval;
}
+static const struct v4l2_ctrl_ops si4713_ctrl_ops = {
+ .s_ctrl = si4713_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = {
+ .ioctl = si4713_ioctl,
+};
+
static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = {
.g_frequency = si4713_g_frequency,
.s_frequency = si4713_s_frequency,
@@ -1998,6 +1342,7 @@ static int si4713_probe(struct i2c_client *client,
{
struct si4713_device *sdev;
struct si4713_platform_data *pdata = client->dev.platform_data;
+ struct v4l2_ctrl_handler *hdl;
int rval, i;
sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
@@ -2031,9 +1376,84 @@ static int si4713_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops);
- mutex_init(&sdev->mutex);
init_completion(&sdev->work);
+ hdl = &sdev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 20);
+ sdev->mute = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, DEFAULT_MUTE);
+
+ sdev->rds_pi = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, DEFAULT_RDS_PI);
+ sdev->rds_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_PTY, 0, 31, 1, DEFAULT_RDS_PTY);
+ sdev->rds_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_DEVIATION, 0, MAX_RDS_DEVIATION,
+ 10, DEFAULT_RDS_DEVIATION);
+ /*
+ * Report step as 8. From RDS spec, psname
+ * should be 8. But there are receivers which scroll strings
+ * sized as 8xN.
+ */
+ sdev->rds_ps_name = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_PS_NAME, 0, MAX_RDS_PS_NAME, 8, 0);
+ /*
+ * Report step as 32 (2A block). From RDS spec,
+ * radio text should be 32 for 2A block. But there are receivers
+ * which scroll strings sized as 32xN. Setting default to 32.
+ */
+ sdev->rds_radio_text = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_RADIO_TEXT, 0, MAX_RDS_RADIO_TEXT, 32, 0);
+
+ sdev->limiter_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_LIMITER_ENABLED, 0, 1, 1, 1);
+ sdev->limiter_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, 250,
+ MAX_LIMITER_RELEASE_TIME, 10, DEFAULT_LIMITER_RTIME);
+ sdev->limiter_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_LIMITER_DEVIATION, 0,
+ MAX_LIMITER_DEVIATION, 10, DEFAULT_LIMITER_DEV);
+
+ sdev->compression_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_COMPRESSION_ENABLED, 0, 1, 1, 1);
+ sdev->compression_gain = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1,
+ DEFAULT_ACOMP_GAIN);
+ sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, MIN_ACOMP_THRESHOLD,
+ MAX_ACOMP_THRESHOLD, 1,
+ DEFAULT_ACOMP_THRESHOLD);
+ sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0,
+ MAX_ACOMP_ATTACK_TIME, 500, DEFAULT_ACOMP_ATIME);
+ sdev->compression_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, 100000,
+ MAX_ACOMP_RELEASE_TIME, 100000, DEFAULT_ACOMP_RTIME);
+
+ sdev->pilot_tone_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_PILOT_TONE_ENABLED, 0, 1, 1, 1);
+ sdev->pilot_tone_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_PILOT_TONE_DEVIATION, 0, MAX_PILOT_DEVIATION,
+ 10, DEFAULT_PILOT_DEVIATION);
+ sdev->pilot_tone_freq = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_PILOT_TONE_FREQUENCY, 0, MAX_PILOT_FREQUENCY,
+ 1, DEFAULT_PILOT_FREQUENCY);
+
+ sdev->tune_preemphasis = v4l2_ctrl_new_std_menu(hdl, &si4713_ctrl_ops,
+ V4L2_CID_TUNE_PREEMPHASIS,
+ V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS);
+ sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_TUNE_POWER_LEVEL, 0, 120, 1, DEFAULT_POWER_LEVEL);
+ sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 191, 1, 0);
+
+ if (hdl->error) {
+ rval = hdl->error;
+ goto free_ctrls;
+ }
+ v4l2_ctrl_cluster(20, &sdev->mute);
+ sdev->sd.ctrl_handler = hdl;
+
if (client->irq) {
rval = request_irq(client->irq,
si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
@@ -2058,6 +1478,8 @@ static int si4713_probe(struct i2c_client *client,
free_irq:
if (client->irq)
free_irq(client->irq, sdev);
+free_ctrls:
+ v4l2_ctrl_handler_free(hdl);
put_reg:
regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
free_gpio:
@@ -2082,6 +1504,7 @@ static int si4713_remove(struct i2c_client *client)
free_irq(client->irq, sdev);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
if (gpio_is_valid(sdev->gpio_reset))
gpio_free(sdev->gpio_reset);
diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h
index c6dfa7fb101c..25cdea26343b 100644
--- a/drivers/media/radio/si4713-i2c.h
+++ b/drivers/media/radio/si4713-i2c.h
@@ -16,6 +16,7 @@
#define SI4713_I2C_H
#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
#include <media/si4713.h>
#define SI4713_PRODUCT_NUMBER 0x0D
@@ -160,56 +161,33 @@
#define POWER_UP 0x01
#define POWER_DOWN 0x00
-struct rds_info {
- u32 pi;
#define MAX_RDS_PTY 31
- u32 pty;
#define MAX_RDS_DEVIATION 90000
- u32 deviation;
+
/*
* PSNAME is known to be defined as 8 character sized (RDS Spec).
* However, there is receivers which scroll PSNAME 8xN sized.
*/
#define MAX_RDS_PS_NAME 96
- u8 ps_name[MAX_RDS_PS_NAME + 1];
+
/*
* MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group)
* character sized (RDS Spec).
* However, there is receivers which scroll them as well.
*/
#define MAX_RDS_RADIO_TEXT 384
- u8 radio_text[MAX_RDS_RADIO_TEXT + 1];
- u32 enabled;
-};
-struct limiter_info {
#define MAX_LIMITER_RELEASE_TIME 102390
- u32 release_time;
#define MAX_LIMITER_DEVIATION 90000
- u32 deviation;
- u32 enabled;
-};
-struct pilot_info {
#define MAX_PILOT_DEVIATION 90000
- u32 deviation;
#define MAX_PILOT_FREQUENCY 19000
- u32 frequency;
- u32 enabled;
-};
-struct acomp_info {
#define MAX_ACOMP_RELEASE_TIME 1000000
- u32 release_time;
#define MAX_ACOMP_ATTACK_TIME 5000
- u32 attack_time;
#define MAX_ACOMP_THRESHOLD 0
#define MIN_ACOMP_THRESHOLD (-40)
- s32 threshold;
#define MAX_ACOMP_GAIN 20
- u32 gain;
- u32 enabled;
-};
#define SI4713_NUM_SUPPLIES 2
@@ -219,21 +197,41 @@ struct acomp_info {
struct si4713_device {
/* v4l2_subdev and i2c reference (v4l2_subdev priv data) */
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler ctrl_handler;
/* private data structures */
- struct mutex mutex;
+ struct { /* si4713 control cluster */
+ /* This is one big cluster since the mute control
+ * powers off the device and after unmuting again all
+ * controls need to be set at once. The only way of doing
+ * that is by making it one big cluster. */
+ struct v4l2_ctrl *mute;
+ struct v4l2_ctrl *rds_ps_name;
+ struct v4l2_ctrl *rds_radio_text;
+ struct v4l2_ctrl *rds_pi;
+ struct v4l2_ctrl *rds_deviation;
+ struct v4l2_ctrl *rds_pty;
+ struct v4l2_ctrl *compression_enabled;
+ struct v4l2_ctrl *compression_threshold;
+ struct v4l2_ctrl *compression_gain;
+ struct v4l2_ctrl *compression_attack_time;
+ struct v4l2_ctrl *compression_release_time;
+ struct v4l2_ctrl *pilot_tone_enabled;
+ struct v4l2_ctrl *pilot_tone_freq;
+ struct v4l2_ctrl *pilot_tone_deviation;
+ struct v4l2_ctrl *limiter_enabled;
+ struct v4l2_ctrl *limiter_deviation;
+ struct v4l2_ctrl *limiter_release_time;
+ struct v4l2_ctrl *tune_preemphasis;
+ struct v4l2_ctrl *tune_pwr_level;
+ struct v4l2_ctrl *tune_ant_cap;
+ };
struct completion work;
- struct rds_info rds_info;
- struct limiter_info limiter_info;
- struct pilot_info pilot_info;
- struct acomp_info acomp_info;
struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES];
int gpio_reset;
+ u32 power_state;
+ u32 rds_enabled;
u32 frequency;
u32 preemphasis;
- u32 mute;
- u32 power_level;
- u32 power_state;
- u32 antenna_capacitor;
u32 stereo;
u32 tune_rnl;
};
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index b18c2dc268ba..82c6c9475d7c 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -96,12 +96,12 @@ static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
return 0;
}
-static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
+static int tef6862_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
{
return v->index ? -EINVAL : 0;
}
-static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f)
{
struct tef6862_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 0a8ee8fab924..5dec323f4247 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -331,7 +331,7 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
* Should we set other tuner attributes, too?
*/
static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *tuner)
+ const struct v4l2_tuner *tuner)
{
struct fmdev *fmdev = video_drvdata(file);
u16 aud_mode;
@@ -388,7 +388,7 @@ static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv,
/* Set tuner or modulator radio frequency */
static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct fmdev *fmdev = video_drvdata(file);
@@ -396,9 +396,7 @@ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv,
* As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency
* in units of 62.5 Hz.
*/
- freq->frequency = (u32)(freq->frequency / 16);
-
- return fmc_set_freq(fmdev, freq->frequency);
+ return fmc_set_freq(fmdev, freq->frequency / 16);
}
/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 19f3563c61da..5a79c333d45e 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -291,7 +291,7 @@ config IR_TTUSBIR
config IR_RX51
tristate "Nokia N900 IR transmitter diode"
- depends on OMAP_DM_TIMER && LIRC && !ARCH_MULTIPLATFORM
+ depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM
---help---
Say Y or M here if you want to enable support for the IR
transmitter diode built in the Nokia N900 (RX51) device.
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index ee6c984cade2..ed184f68c17c 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1098,6 +1098,7 @@ exit_release_hw_io:
release_region(dev->hw_io, ENE_IO_SIZE);
exit_unregister_device:
rc_unregister_device(rdev);
+ rdev = NULL;
exit_free_dev_rdev:
rc_free_device(rdev);
kfree(dev);
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index dec203bb06f6..72e3fa652481 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -112,6 +112,7 @@ struct imon_context {
bool tx_control;
unsigned char usb_rx_buf[8];
unsigned char usb_tx_buf[8];
+ unsigned int send_packet_delay;
struct tx_t {
unsigned char data_buf[35]; /* user data buffer */
@@ -185,6 +186,10 @@ enum {
IMON_KEY_PANEL = 2,
};
+enum {
+ IMON_NEED_20MS_PKT_DELAY = 1
+};
+
/*
* USB Device ID for iMON USB Control Boards
*
@@ -215,7 +220,7 @@ static struct usb_device_id imon_usb_id_table[] = {
/* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
{ USB_DEVICE(0x15c2, 0x0035) },
/* SoundGraph iMON OEM VFD (IR & VFD) */
- { USB_DEVICE(0x15c2, 0x0036) },
+ { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY },
/* device specifics unknown */
{ USB_DEVICE(0x15c2, 0x0037) },
/* SoundGraph iMON OEM LCD (IR & LCD) */
@@ -523,8 +528,10 @@ static int send_packet(struct imon_context *ictx)
mutex_unlock(&ictx->lock);
retval = wait_for_completion_interruptible(
&ictx->tx.finished);
- if (retval)
+ if (retval) {
+ usb_kill_urb(ictx->tx_urb);
pr_err_ratelimited("task interrupted\n");
+ }
mutex_lock(&ictx->lock);
retval = ictx->tx.status;
@@ -535,12 +542,12 @@ static int send_packet(struct imon_context *ictx)
kfree(control_req);
/*
- * Induce a mandatory 5ms delay before returning, as otherwise,
+ * Induce a mandatory delay before returning, as otherwise,
* send_packet can get called so rapidly as to overwhelm the device,
* particularly on faster systems and/or those with quirky usb.
*/
- timeout = msecs_to_jiffies(5);
- set_current_state(TASK_UNINTERRUPTIBLE);
+ timeout = msecs_to_jiffies(ictx->send_packet_delay);
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(timeout);
return retval;
@@ -1568,11 +1575,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type < 0)
goto not_input_data;
- spin_lock_irqsave(&ictx->kc_lock, flags);
- if (ictx->kc == KEY_UNKNOWN)
- goto unknown_key;
- spin_unlock_irqrestore(&ictx->kc_lock, flags);
-
if (ktype != IMON_KEY_PANEL) {
if (press_type == 0)
rc_keyup(ictx->rdev);
@@ -1615,12 +1617,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
return;
-unknown_key:
- spin_unlock_irqrestore(&ictx->kc_lock, flags);
- dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
- (long long)scancode);
- return;
-
not_input_data:
if (len != 8) {
dev_warn(dev, "imon %s: invalid incoming packet "
@@ -2099,7 +2095,8 @@ static bool imon_find_endpoints(struct imon_context *ictx,
}
-static struct imon_context *imon_init_intf0(struct usb_interface *intf)
+static struct imon_context *imon_init_intf0(struct usb_interface *intf,
+ const struct usb_device_id *id)
{
struct imon_context *ictx;
struct urb *rx_urb;
@@ -2139,6 +2136,10 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
+ /* default send_packet delay is 5ms but some devices need more */
+ ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ?
+ 20 : 5;
+
ret = -ENODEV;
iface_desc = intf->cur_altsetting;
if (!imon_find_endpoints(ictx, iface_desc)) {
@@ -2317,7 +2318,7 @@ static int imon_probe(struct usb_interface *interface,
first_if_ctx = usb_get_intfdata(first_if);
if (ifnum == 0) {
- ictx = imon_init_intf0(interface);
+ ictx = imon_init_intf0(interface, id);
if (!ictx) {
pr_err("failed to initialize context!\n");
ret = -ENODEV;
@@ -2325,7 +2326,14 @@ static int imon_probe(struct usb_interface *interface,
}
} else {
- /* this is the secondary interface on the device */
+ /* this is the secondary interface on the device */
+
+ /* fail early if first intf failed to register */
+ if (!first_if_ctx) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
ictx = imon_init_intf1(interface, first_if_ctx);
if (!ictx) {
pr_err("failed to attach to context!\n");
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 69edffb9fe9a..3948138ca870 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!(dev->raw->enabled_protocols & RC_BIT_JVC))
+ if (!(dev->enabled_protocols & RC_BIT_JVC))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index 8ee080ef2f2c..e4561264e124 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!(dev->raw->enabled_protocols & RC_BIT_LIRC))
+ if (!(dev->enabled_protocols & RC_BIT_LIRC))
return 0;
if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 33fafa4cf7cb..9f3c9b59f30c 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD))
+ if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index a47ee3634969..9a9009411439 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!(dev->raw->enabled_protocols & RC_BIT_NEC))
+ if (!(dev->enabled_protocols & RC_BIT_NEC))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 17c94be9f24c..5c42750c7b71 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -256,7 +256,7 @@ int ir_raw_event_register(struct rc_dev *dev)
return -ENOMEM;
dev->raw->dev = dev;
- dev->raw->enabled_protocols = ~0;
+ dev->enabled_protocols = ~0;
rc = kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL);
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 5b4d1ddeac4e..4e53a319c5d8 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -52,7 +52,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle;
u32 scancode;
- if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
+ if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
return 0;
if (!is_timing_event(ev)) {
@@ -128,7 +128,7 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) {
+ if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -145,7 +145,7 @@ again:
} else {
/* RC5 */
u8 command, system;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) {
+ if (!(dev->enabled_protocols & RC_BIT_RC5)) {
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
index fd807a8308d8..865fe84fd854 100644
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle, command, system;
u32 scancode;
- if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ))
+ if (!(dev->enabled_protocols & RC_BIT_RC5_SZ))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index e19072ffb36c..7cba7d33a3fa 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -89,7 +89,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 toggle;
- if (!(dev->raw->enabled_protocols &
+ if (!(dev->enabled_protocols &
(RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
return 0;
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
index 8ead492d03aa..31b955bf7664 100644
--- a/drivers/media/rc/ir-rx51.c
+++ b/drivers/media/rc/ir-rx51.c
@@ -464,14 +464,14 @@ static int lirc_rx51_probe(struct platform_device *dev)
return 0;
}
-static int __exit lirc_rx51_remove(struct platform_device *dev)
+static int lirc_rx51_remove(struct platform_device *dev)
{
return lirc_unregister_driver(lirc_rx51_driver.minor);
}
struct platform_driver lirc_rx51_platform_driver = {
.probe = lirc_rx51_probe,
- .remove = __exit_p(lirc_rx51_remove),
+ .remove = lirc_rx51_remove,
.suspend = lirc_rx51_suspend,
.resume = lirc_rx51_resume,
.driver = {
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index 7e69a3b65370..0a06205b5677 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!(dev->raw->enabled_protocols & RC_BIT_SANYO))
+ if (!(dev->enabled_protocols & RC_BIT_SANYO))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index fb914342cf4d..29ab9c2db060 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -45,7 +45,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 device, subdevice, function;
- if (!(dev->raw->enabled_protocols &
+ if (!(dev->enabled_protocols &
(RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
return 0;
@@ -124,7 +124,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY12)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -133,7 +133,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
function = bitrev8((data->bits >> 4) & 0xFE);
break;
case 15:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY15)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -142,7 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
function = bitrev8((data->bits >> 7) & 0xFE);
break;
case 20:
- if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY20)) {
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index dd8237324c09..63b42252166a 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1613,6 +1613,7 @@ exit_release_cir_addr:
release_region(itdev->cir_addr, itdev->params.io_region_size);
exit_unregister_device:
rc_unregister_device(rdev);
+ rdev = NULL;
exit_free_dev_rdev:
rc_free_device(rdev);
kfree(itdev);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 778661971aed..5ab94ea4bc28 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-hauppauge.o \
rc-rc6-mce.o \
rc-real-audio-220-32-keys.o \
+ rc-reddo.o \
rc-snapstream-firefly.o \
rc-streamzap.o \
rc-tbs-nec.o \
@@ -88,7 +89,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-tevii-nec.o \
rc-tivo.o \
rc-total-media-in-hand.o \
- rc-total-media-in-hand-02.o \
+ rc-total-media-in-hand-02.o \
rc-trekstor.o \
rc-tt-1500.o \
rc-twinhan1027.o \
diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c
new file mode 100644
index 000000000000..b80b336e9284
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-reddo.c
@@ -0,0 +1,86 @@
+/*
+ * MSI DIGIVOX mini III remote controller keytable
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/*
+ * Derived from MSI DIGIVOX mini III remote (rc-msi-digivox-iii.c)
+ *
+ * Differences between these remotes are:
+ *
+ * 1) scancode 0x61d601 is mapped to different button:
+ * MSI DIGIVOX mini III "Source" = KEY_VIDEO
+ * Reddo "EPG" = KEY_EPG
+ *
+ * 2) Reddo remote has less buttons. Missing buttons are: colored buttons,
+ * navigation buttons and main power button.
+ */
+
+static struct rc_map_table reddo[] = {
+ { 0x61d601, KEY_EPG }, /* EPG */
+ { 0x61d602, KEY_3 },
+ { 0x61d604, KEY_1 },
+ { 0x61d605, KEY_5 },
+ { 0x61d606, KEY_6 },
+ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */
+ { 0x61d608, KEY_2 },
+ { 0x61d609, KEY_CHANNELUP }, /* CH+ */
+ { 0x61d60a, KEY_9 },
+ { 0x61d60b, KEY_ZOOM }, /* Zoom */
+ { 0x61d60c, KEY_7 },
+ { 0x61d60d, KEY_8 },
+ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
+ { 0x61d60f, KEY_4 },
+ { 0x61d610, KEY_ESC }, /* [back up arrow] */
+ { 0x61d611, KEY_0 },
+ { 0x61d612, KEY_OK }, /* [enter arrow] */
+ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
+ { 0x61d614, KEY_RECORD }, /* Rec */
+ { 0x61d615, KEY_STOP }, /* Stop */
+ { 0x61d616, KEY_PLAY }, /* Play */
+ { 0x61d617, KEY_MUTE }, /* Mute */
+ { 0x61d643, KEY_POWER2 }, /* [red power button] */
+};
+
+static struct rc_map_list reddo_map = {
+ .map = {
+ .scan = reddo,
+ .size = ARRAY_SIZE(reddo),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_REDDO,
+ }
+};
+
+static int __init init_rc_map_reddo(void)
+{
+ return rc_map_register(&reddo_map);
+}
+
+static void __exit exit_rc_map_reddo(void)
+{
+ rc_map_unregister(&reddo_map);
+}
+
+module_init(init_rc_map_reddo)
+module_exit(exit_rc_map_reddo)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 5b5b6e6f79e8..3c761014d3ce 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -482,7 +482,7 @@ static char SET_RX_SENSOR[] = {MCE_CMD_PORT_IR,
MCE_RSP_EQIRRXPORTEN, 0x00};
*/
-static int mceusb_cmdsize(u8 cmd, u8 subcmd)
+static int mceusb_cmd_datasize(u8 cmd, u8 subcmd)
{
int datasize = 0;
@@ -493,6 +493,9 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
break;
case MCE_CMD_PORT_SYS:
switch (subcmd) {
+ case MCE_RSP_GETPORTSTATUS:
+ datasize = 5;
+ break;
case MCE_RSP_EQWAKEVERSION:
datasize = 4;
break;
@@ -500,6 +503,9 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
datasize = 2;
break;
case MCE_RSP_EQWAKESUPPORT:
+ case MCE_RSP_GETWAKESOURCE:
+ case MCE_RSP_EQDEVDETAILS:
+ case MCE_RSP_EQEMVER:
datasize = 1;
break;
}
@@ -509,6 +515,7 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd)
case MCE_RSP_EQIRCFS:
case MCE_RSP_EQIRTIMEOUT:
case MCE_RSP_EQIRRXCFCNT:
+ case MCE_RSP_EQIRNUMPORTS:
datasize = 2;
break;
case MCE_CMD_SIG_END:
@@ -968,7 +975,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
for (; i < buf_len; i++) {
switch (ir->parser_state) {
case SUBCMD:
- ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
+ ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]);
mceusb_dev_printdata(ir, ir->buf_in, i - 1,
ir->rem + 2, false);
mceusb_handle_command(ir, i);
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 40125d779049..21ee0dc1b7ec 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1107,6 +1107,7 @@ exit_release_cir_addr:
release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
exit_unregister_device:
rc_unregister_device(rdev);
+ rdev = NULL;
exit_free_dev_rdev:
rc_free_device(rdev);
kfree(nvt);
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 5d87287ed372..70a180bb0bd0 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -39,7 +39,6 @@ struct ir_raw_event_ctrl {
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
struct rc_dev *dev; /* pointer to the parent rc_dev */
- u64 enabled_protocols; /* enabled raw protocol decoders */
/* raw decoder state follows */
struct ir_raw_event prev_ev;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 759a40a42eaa..1cf382a0b277 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -715,14 +715,14 @@ static void ir_close(struct input_dev *idev)
}
/* class for /sys/class/rc */
-static char *ir_devnode(struct device *dev, umode_t *mode)
+static char *rc_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
}
-static struct class ir_input_class = {
+static struct class rc_class = {
.name = "rc",
- .devnode = ir_devnode,
+ .devnode = rc_devnode,
};
/*
@@ -783,13 +783,12 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
- if (dev->driver_type == RC_DRIVER_SCANCODE) {
- enabled = dev->rc_map.rc_type;
+ enabled = dev->enabled_protocols;
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
allowed = dev->allowed_protos;
- } else if (dev->raw) {
- enabled = dev->raw->enabled_protocols;
+ else if (dev->raw)
allowed = ir_raw_get_allowed_protocols();
- } else {
+ else {
mutex_unlock(&dev->lock);
return -ENODEV;
}
@@ -847,7 +846,6 @@ static ssize_t store_protocols(struct device *device,
u64 type;
u64 mask;
int rc, i, count = 0;
- unsigned long flags;
ssize_t ret;
/* Device is being removed */
@@ -856,15 +854,12 @@ static ssize_t store_protocols(struct device *device,
mutex_lock(&dev->lock);
- if (dev->driver_type == RC_DRIVER_SCANCODE)
- type = dev->rc_map.rc_type;
- else if (dev->raw)
- type = dev->raw->enabled_protocols;
- else {
+ if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
IR_dprintk(1, "Protocol switching not supported\n");
ret = -EINVAL;
goto out;
}
+ type = dev->enabled_protocols;
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
if (!*tmp)
@@ -922,14 +917,7 @@ static ssize_t store_protocols(struct device *device,
}
}
- if (dev->driver_type == RC_DRIVER_SCANCODE) {
- spin_lock_irqsave(&dev->rc_map.lock, flags);
- dev->rc_map.rc_type = type;
- spin_unlock_irqrestore(&dev->rc_map.lock, flags);
- } else {
- dev->raw->enabled_protocols = type;
- }
-
+ dev->enabled_protocols = type;
IR_dprintk(1, "Current protocol(s): 0x%llx\n",
(long long)type);
@@ -1016,7 +1004,7 @@ struct rc_dev *rc_allocate_device(void)
setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
dev->dev.type = &rc_dev_type;
- dev->dev.class = &ir_input_class;
+ dev->dev.class = &rc_class;
device_initialize(&dev->dev);
__module_get(THIS_MODULE);
@@ -1068,9 +1056,8 @@ int rc_register_device(struct rc_dev *dev)
/*
* Take the lock here, as the device sysfs node will appear
* when device_add() is called, which may trigger an ir-keytable udev
- * rule, which will in turn call show_protocols and access either
- * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has
- * been initialized.
+ * rule, which will in turn call show_protocols and access
+ * dev->enabled_protocols before it has been initialized.
*/
mutex_lock(&dev->lock);
@@ -1132,6 +1119,7 @@ int rc_register_device(struct rc_dev *dev)
rc = dev->change_protocol(dev, &rc_type);
if (rc < 0)
goto out_raw;
+ dev->enabled_protocols = rc_type;
}
mutex_unlock(&dev->lock);
@@ -1190,7 +1178,7 @@ EXPORT_SYMBOL_GPL(rc_unregister_device);
static int __init rc_core_init(void)
{
- int rc = class_register(&ir_input_class);
+ int rc = class_register(&rc_class);
if (rc) {
printk(KERN_ERR "rc_core: unable to register rc class\n");
return rc;
@@ -1203,11 +1191,11 @@ static int __init rc_core_init(void)
static void __exit rc_core_exit(void)
{
- class_unregister(&ir_input_class);
+ class_unregister(&rc_class);
rc_map_unregister(&empty_map);
}
-module_init(rc_core_init);
+subsys_initcall(rc_core_init);
module_exit(rc_core_exit);
int rc_core_debug; /* ir_debug level (0,1,2) */
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 1b37fe2779f8..12167a6b5472 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -45,6 +45,7 @@
*
*/
+#include <asm/unaligned.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -53,7 +54,6 @@
#include <media/rc-core.h>
/* Driver Information */
-#define DRIVER_VERSION "0.70"
#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
#define DRIVER_AUTHOR2 "The Dweller, Stephen Cox"
#define DRIVER_DESC "RedRat3 USB IR Transceiver Driver"
@@ -129,25 +129,11 @@ static int debug;
/* USB bulk-in IR data endpoint address */
#define RR3_BULK_IN_EP_ADDR 0x82
-/* Raw Modulated signal data value offsets */
-#define RR3_PAUSE_OFFSET 0
-#define RR3_FREQ_COUNT_OFFSET 4
-#define RR3_NUM_PERIOD_OFFSET 6
-#define RR3_MAX_LENGTHS_OFFSET 8
-#define RR3_NUM_LENGTHS_OFFSET 9
-#define RR3_MAX_SIGS_OFFSET 10
-#define RR3_NUM_SIGS_OFFSET 12
-#define RR3_REPEATS_OFFSET 14
-
/* Size of the fixed-length portion of the signal */
-#define RR3_HEADER_LENGTH 15
#define RR3_DRIVER_MAXLENS 128
#define RR3_MAX_SIG_SIZE 512
-#define RR3_MAX_BUF_SIZE \
- ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE)
#define RR3_TIME_UNIT 50
#define RR3_END_OF_SIGNAL 0x7f
-#define RR3_TX_HEADER_OFFSET 4
#define RR3_TX_TRAILER_LEN 2
#define RR3_RX_MIN_TIMEOUT 5
#define RR3_RX_MAX_TIMEOUT 2000
@@ -159,6 +145,32 @@ static int debug;
#define USB_RR3USB_PRODUCT_ID 0x0001
#define USB_RR3IIUSB_PRODUCT_ID 0x0005
+struct redrat3_header {
+ __be16 length;
+ __be16 transfer_type;
+} __packed;
+
+/* sending and receiving irdata */
+struct redrat3_irdata {
+ struct redrat3_header header;
+ __be32 pause;
+ __be16 mod_freq_count;
+ __be16 num_periods;
+ __u8 max_lengths;
+ __u8 no_lengths;
+ __be16 max_sig_size;
+ __be16 sig_size;
+ __u8 no_repeats;
+ __be16 lens[RR3_DRIVER_MAXLENS]; /* not aligned */
+ __u8 sigdata[RR3_MAX_SIG_SIZE];
+} __packed;
+
+/* firmware errors */
+struct redrat3_error {
+ struct redrat3_header header;
+ __be16 fw_error;
+} __packed;
+
/* table of devices that work with this driver */
static struct usb_device_id redrat3_dev_table[] = {
/* Original version of the RedRat3 */
@@ -180,20 +192,15 @@ struct redrat3_dev {
/* the receive endpoint */
struct usb_endpoint_descriptor *ep_in;
/* the buffer to receive data */
- unsigned char *bulk_in_buf;
+ void *bulk_in_buf;
/* urb used to read ir data */
struct urb *read_urb;
/* the send endpoint */
struct usb_endpoint_descriptor *ep_out;
- /* the buffer to send data */
- unsigned char *bulk_out_buf;
- /* the urb used to send data */
- struct urb *write_urb;
/* usb dma */
dma_addr_t dma_in;
- dma_addr_t dma_out;
/* rx signal timeout timer */
struct timer_list rx_timeout;
@@ -205,72 +212,15 @@ struct redrat3_dev {
bool transmitting;
/* store for current packet */
- char pbuf[RR3_MAX_BUF_SIZE];
- u16 pktlen;
- u16 pkttype;
+ struct redrat3_irdata irdata;
u16 bytes_read;
- /* indicate whether we are going to reprocess
- * the USB callback with a bigger buffer */
- int buftoosmall;
- char *datap;
u32 carrier;
- char name[128];
+ char name[64];
char phys[64];
};
-/* All incoming data buffers adhere to a very specific data format */
-struct redrat3_signal_header {
- u16 length; /* Length of data being transferred */
- u16 transfer_type; /* Type of data transferred */
- u32 pause; /* Pause between main and repeat signals */
- u16 mod_freq_count; /* Value of timer on mod. freq. measurement */
- u16 no_periods; /* No. of periods over which mod. freq. is measured */
- u8 max_lengths; /* Max no. of lengths (i.e. size of array) */
- u8 no_lengths; /* Actual no. of elements in lengths array */
- u16 max_sig_size; /* Max no. of values in signal data array */
- u16 sig_size; /* Acuto no. of values in signal data array */
- u8 no_repeats; /* No. of repeats of repeat signal section */
- /* Here forward is the lengths and signal data */
-};
-
-static void redrat3_dump_signal_header(struct redrat3_signal_header *header)
-{
- pr_info("%s:\n", __func__);
- pr_info(" * length: %u, transfer_type: 0x%02x\n",
- header->length, header->transfer_type);
- pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n",
- header->pause, header->mod_freq_count, header->no_periods);
- pr_info(" * lengths: %u (max: %u)\n",
- header->no_lengths, header->max_lengths);
- pr_info(" * sig_size: %u (max: %u)\n",
- header->sig_size, header->max_sig_size);
- pr_info(" * repeats: %u\n", header->no_repeats);
-}
-
-static void redrat3_dump_signal_data(char *buffer, u16 len)
-{
- int offset, i;
- char *data_vals;
-
- pr_info("%s:", __func__);
-
- offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH
- + (RR3_DRIVER_MAXLENS * sizeof(u16));
-
- /* read RR3_DRIVER_MAXLENS from ctrl msg */
- data_vals = buffer + offset;
-
- for (i = 0; i < len; i++) {
- if (i % 10 == 0)
- pr_cont("\n * ");
- pr_cont("%02x ", *data_vals++);
- }
-
- pr_cont("\n");
-}
-
/*
* redrat3_issue_async
*
@@ -283,7 +233,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3)
rr3_ftr(rr3->dev, "Entering %s\n", __func__);
- memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
if (res)
rr3_dbg(rr3->dev, "%s: receive request FAILED! "
@@ -352,13 +301,14 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
}
}
-static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph)
+static u32 redrat3_val_to_mod_freq(struct redrat3_irdata *irdata)
{
u32 mod_freq = 0;
+ u16 mod_freq_count = be16_to_cpu(irdata->mod_freq_count);
- if (ph->mod_freq_count != 0)
- mod_freq = (RR3_CLK * ph->no_periods) /
- (ph->mod_freq_count * RR3_CLK_PER_COUNT);
+ if (mod_freq_count != 0)
+ mod_freq = (RR3_CLK * be16_to_cpu(irdata->num_periods)) /
+ (mod_freq_count * RR3_CLK_PER_COUNT);
return mod_freq;
}
@@ -396,7 +346,6 @@ static u32 redrat3_us_to_len(u32 microsec)
/* don't allow zero lengths to go back, breaks lirc */
return result ? result : 1;
-
}
/* timer callback to send reset event */
@@ -411,16 +360,11 @@ static void redrat3_rx_timeout(unsigned long data)
static void redrat3_process_ir_data(struct redrat3_dev *rr3)
{
DEFINE_IR_RAW_EVENT(rawir);
- struct redrat3_signal_header header;
struct device *dev;
- int i, trailer = 0;
+ unsigned i, trailer = 0;
+ unsigned sig_size, single_len, offset, val;
unsigned long delay;
- u32 mod_freq, single_len;
- u16 *len_vals;
- u8 *data_vals;
- u32 tmp32;
- u16 tmp16;
- char *sig_data;
+ u32 mod_freq;
if (!rr3) {
pr_err("%s called with no context!\n", __func__);
@@ -430,57 +374,20 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
rr3_ftr(rr3->dev, "Entered %s\n", __func__);
dev = rr3->dev;
- sig_data = rr3->pbuf;
-
- header.length = rr3->pktlen;
- header.transfer_type = rr3->pkttype;
-
- /* Sanity check */
- if (!(header.length >= RR3_HEADER_LENGTH))
- dev_warn(dev, "read returned less than rr3 header len\n");
/* Make sure we reset the IR kfifo after a bit of inactivity */
delay = usecs_to_jiffies(rr3->hw_timeout);
mod_timer(&rr3->rx_timeout, jiffies + delay);
- memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32));
- header.pause = be32_to_cpu(tmp32);
-
- memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16));
- header.mod_freq_count = be16_to_cpu(tmp16);
-
- memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16));
- header.no_periods = be16_to_cpu(tmp16);
-
- header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET];
- header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET];
-
- memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16));
- header.max_sig_size = be16_to_cpu(tmp16);
-
- memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16));
- header.sig_size = be16_to_cpu(tmp16);
-
- header.no_repeats= sig_data[RR3_REPEATS_OFFSET];
-
- if (debug) {
- redrat3_dump_signal_header(&header);
- redrat3_dump_signal_data(sig_data, header.sig_size);
- }
-
- mod_freq = redrat3_val_to_mod_freq(&header);
+ mod_freq = redrat3_val_to_mod_freq(&rr3->irdata);
rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq);
- /* Here we pull out the 'length' values from the signal */
- len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH);
-
- data_vals = sig_data + RR3_HEADER_LENGTH +
- (header.max_lengths * sizeof(u16));
-
/* process each rr3 encoded byte into an int */
- for (i = 0; i < header.sig_size; i++) {
- u16 val = len_vals[data_vals[i]];
- single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
+ sig_size = be16_to_cpu(rr3->irdata.sig_size);
+ for (i = 0; i < sig_size; i++) {
+ offset = rr3->irdata.sigdata[i];
+ val = get_unaligned_be16(&rr3->irdata.lens[offset]);
+ single_len = redrat3_len_to_us(val);
/* we should always get pulse/space/pulse/space samples */
if (i % 2)
@@ -515,8 +422,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
rr3_dbg(dev, "calling ir_raw_event_handle\n");
ir_raw_event_handle(rr3->rc);
-
- return;
}
/* Util fn to send rr3 cmds */
@@ -540,7 +445,7 @@ static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3)
__func__, res, *data);
res = -EIO;
} else
- res = (u8)data[0];
+ res = data[0];
kfree(data);
@@ -598,22 +503,18 @@ static inline void redrat3_delete(struct redrat3_dev *rr3,
{
rr3_ftr(rr3->dev, "%s cleaning up\n", __func__);
usb_kill_urb(rr3->read_urb);
- usb_kill_urb(rr3->write_urb);
usb_free_urb(rr3->read_urb);
- usb_free_urb(rr3->write_urb);
- usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize,
+ usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize),
rr3->bulk_in_buf, rr3->dma_in);
- usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize,
- rr3->bulk_out_buf, rr3->dma_out);
kfree(rr3);
}
static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
{
- u32 *tmp;
+ __be32 *tmp;
u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */
int len, ret, pipe;
@@ -628,14 +529,16 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
- if (ret != len) {
+ if (ret != len)
dev_warn(rr3->dev, "Failed to read timeout from hardware\n");
- return timeout;
+ else {
+ timeout = redrat3_len_to_us(be32_to_cpup(tmp));
+
+ rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000);
}
- timeout = redrat3_len_to_us(be32_to_cpu(*tmp));
+ kfree(tmp);
- rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000);
return timeout;
}
@@ -652,7 +555,7 @@ static void redrat3_reset(struct redrat3_dev *rr3)
rxpipe = usb_rcvctrlpipe(udev, 0);
txpipe = usb_sndctrlpipe(udev, 0);
- val = kzalloc(len, GFP_KERNEL);
+ val = kmalloc(len, GFP_KERNEL);
if (!val) {
dev_err(dev, "Memory allocation failure\n");
return;
@@ -706,82 +609,74 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3)
rr3_ftr(rr3->dev, "Exiting %s\n", __func__);
}
-static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len)
+static void redrat3_read_packet_start(struct redrat3_dev *rr3, unsigned len)
{
- u16 tx_error;
- u16 hdrlen;
+ struct redrat3_header *header = rr3->bulk_in_buf;
+ unsigned pktlen, pkttype;
rr3_ftr(rr3->dev, "Entering %s\n", __func__);
/* grab the Length and type of transfer */
- memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf,
- sizeof(rr3->pktlen));
- memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf +
- sizeof(rr3->pktlen)),
- sizeof(rr3->pkttype));
+ pktlen = be16_to_cpu(header->length);
+ pkttype = be16_to_cpu(header->transfer_type);
- /*data needs conversion to know what its real values are*/
- rr3->pktlen = be16_to_cpu(rr3->pktlen);
- rr3->pkttype = be16_to_cpu(rr3->pkttype);
+ if (pktlen > sizeof(rr3->irdata)) {
+ dev_warn(rr3->dev, "packet length %u too large\n", pktlen);
+ return;
+ }
- switch (rr3->pkttype) {
+ switch (pkttype) {
case RR3_ERROR:
- memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf
- + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))),
- sizeof(tx_error));
- tx_error = be16_to_cpu(tx_error);
- redrat3_dump_fw_error(rr3, tx_error);
+ if (len >= sizeof(struct redrat3_error)) {
+ struct redrat3_error *error = rr3->bulk_in_buf;
+ unsigned fw_error = be16_to_cpu(error->fw_error);
+ redrat3_dump_fw_error(rr3, fw_error);
+ }
break;
case RR3_MOD_SIGNAL_IN:
- hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype);
+ memcpy(&rr3->irdata, rr3->bulk_in_buf, len);
rr3->bytes_read = len;
- rr3->bytes_read -= hdrlen;
- rr3->datap = &(rr3->pbuf[0]);
-
- memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen),
- rr3->bytes_read);
- rr3->datap += rr3->bytes_read;
rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
- rr3->bytes_read, rr3->pktlen);
+ rr3->bytes_read, pktlen);
break;
default:
- rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, "
- "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen);
+ rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, len of %d, 0x%02x\n",
+ pkttype, len, pktlen);
break;
}
}
-static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len)
+static void redrat3_read_packet_continue(struct redrat3_dev *rr3, unsigned len)
{
+ void *irdata = &rr3->irdata;
rr3_ftr(rr3->dev, "Entering %s\n", __func__);
- memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len);
- rr3->datap += len;
+ if (len + rr3->bytes_read > sizeof(rr3->irdata)) {
+ dev_warn(rr3->dev, "too much data for packet\n");
+ rr3->bytes_read = 0;
+ return;
+ }
+
+ memcpy(irdata + rr3->bytes_read, rr3->bulk_in_buf, len);
rr3->bytes_read += len;
- rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
- rr3->bytes_read, rr3->pktlen);
+ rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", rr3->bytes_read,
+ be16_to_cpu(rr3->irdata.header.length));
}
/* gather IR data from incoming urb, process it when we have enough */
-static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len)
+static int redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len)
{
struct device *dev = rr3->dev;
+ unsigned pkttype;
int ret = 0;
rr3_ftr(dev, "Entering %s\n", __func__);
- if (rr3->pktlen > RR3_MAX_BUF_SIZE) {
- dev_err(rr3->dev, "error: packet larger than buffer\n");
- ret = -EINVAL;
- goto out;
- }
-
- if ((rr3->bytes_read == 0) &&
- (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) {
+ if (rr3->bytes_read == 0 && len >= sizeof(struct redrat3_header)) {
redrat3_read_packet_start(rr3, len);
} else if (rr3->bytes_read != 0) {
redrat3_read_packet_continue(rr3, len);
@@ -791,31 +686,25 @@ static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len)
goto out;
}
- if (rr3->bytes_read > rr3->pktlen) {
- dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n",
- rr3->bytes_read, rr3->pktlen);
- ret = -EINVAL;
- goto out;
- } else if (rr3->bytes_read < rr3->pktlen)
+ if (rr3->bytes_read < be16_to_cpu(rr3->irdata.header.length))
/* we're still accumulating data */
return 0;
/* if we get here, we've got IR data to decode */
- if (rr3->pkttype == RR3_MOD_SIGNAL_IN)
+ pkttype = be16_to_cpu(rr3->irdata.header.transfer_type);
+ if (pkttype == RR3_MOD_SIGNAL_IN)
redrat3_process_ir_data(rr3);
else
- rr3_dbg(dev, "discarding non-signal data packet "
- "(type 0x%02x)\n", rr3->pkttype);
+ rr3_dbg(dev, "discarding non-signal data packet (type 0x%02x)\n",
+ pkttype);
out:
rr3->bytes_read = 0;
- rr3->pktlen = 0;
- rr3->pkttype = 0;
return ret;
}
/* callback function from USB when async USB request has completed */
-static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
+static void redrat3_handle_async(struct urb *urb)
{
struct redrat3_dev *rr3;
int ret;
@@ -851,34 +740,16 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
default:
dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status);
rr3->bytes_read = 0;
- rr3->pktlen = 0;
- rr3->pkttype = 0;
break;
}
}
-static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
-{
- struct redrat3_dev *rr3;
- int len;
-
- if (!urb)
- return;
-
- rr3 = urb->context;
- if (rr3) {
- len = urb->actual_length;
- rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n",
- __func__, urb->status, len);
- }
-}
-
static u16 mod_freq_to_val(unsigned int mod_freq)
{
int mult = 6000000;
/* Clk used in mod. freq. generation is CLK24/4. */
- return (u16)(65536 - (mult / mod_freq));
+ return 65536 - (mult / mod_freq);
}
static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier)
@@ -900,17 +771,12 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
{
struct redrat3_dev *rr3 = rcdev->priv;
struct device *dev = rr3->dev;
- struct redrat3_signal_header header;
- int i, j, ret, ret_len, offset;
+ struct redrat3_irdata *irdata = NULL;
+ int ret, ret_len;
int lencheck, cur_sample_len, pipe;
- char *buffer = NULL, *sigdata = NULL;
int *sample_lens = NULL;
- u32 tmpi;
- u16 tmps;
- u8 *datap;
u8 curlencheck = 0;
- u16 *lengths_ptr;
- int sendbuf_len;
+ unsigned i, sendbuf_len;
rr3_ftr(dev, "Entering %s\n", __func__);
@@ -931,8 +797,19 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
goto out;
}
+ irdata = kzalloc(sizeof(*irdata), GFP_KERNEL);
+ if (!irdata) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
for (i = 0; i < count; i++) {
cur_sample_len = redrat3_us_to_len(txbuf[i]);
+ if (cur_sample_len > 0xffff) {
+ dev_warn(dev, "transmit period of %uus truncated to %uus\n",
+ txbuf[i], redrat3_len_to_us(0xffff));
+ cur_sample_len = 0xffff;
+ }
for (lencheck = 0; lencheck < curlencheck; lencheck++) {
if (sample_lens[lencheck] == cur_sample_len)
break;
@@ -944,94 +821,41 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
/* now convert the value to a proper
* rr3 value.. */
sample_lens[curlencheck] = cur_sample_len;
+ put_unaligned_be16(cur_sample_len,
+ &irdata->lens[curlencheck]);
curlencheck++;
} else {
count = i - 1;
break;
}
}
+ irdata->sigdata[i] = lencheck;
}
- sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL);
- if (!sigdata) {
- ret = -ENOMEM;
- goto out;
- }
-
- sigdata[count] = RR3_END_OF_SIGNAL;
- sigdata[count + 1] = RR3_END_OF_SIGNAL;
- for (i = 0; i < count; i++) {
- for (j = 0; j < curlencheck; j++) {
- if (sample_lens[j] == redrat3_us_to_len(txbuf[i]))
- sigdata[i] = j;
- }
- }
-
- offset = RR3_TX_HEADER_OFFSET;
- sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS)
- + count + RR3_TX_TRAILER_LEN + offset;
-
- buffer = kzalloc(sendbuf_len, GFP_KERNEL);
- if (!buffer) {
- ret = -ENOMEM;
- goto out;
- }
+ irdata->sigdata[count] = RR3_END_OF_SIGNAL;
+ irdata->sigdata[count + 1] = RR3_END_OF_SIGNAL;
+ sendbuf_len = offsetof(struct redrat3_irdata,
+ sigdata[count + RR3_TX_TRAILER_LEN]);
/* fill in our packet header */
- header.length = sendbuf_len - offset;
- header.transfer_type = RR3_MOD_SIGNAL_OUT;
- header.pause = redrat3_len_to_us(100);
- header.mod_freq_count = mod_freq_to_val(rr3->carrier);
- header.no_periods = 0; /* n/a to transmit */
- header.max_lengths = RR3_DRIVER_MAXLENS;
- header.no_lengths = curlencheck;
- header.max_sig_size = RR3_MAX_SIG_SIZE;
- header.sig_size = count + RR3_TX_TRAILER_LEN;
- /* we currently rely on repeat handling in the IR encoding source */
- header.no_repeats = 0;
-
- tmps = cpu_to_be16(header.length);
- memcpy(buffer, &tmps, 2);
-
- tmps = cpu_to_be16(header.transfer_type);
- memcpy(buffer + 2, &tmps, 2);
-
- tmpi = cpu_to_be32(header.pause);
- memcpy(buffer + offset, &tmpi, sizeof(tmpi));
-
- tmps = cpu_to_be16(header.mod_freq_count);
- memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2);
-
- buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths;
-
- tmps = cpu_to_be16(header.sig_size);
- memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2);
-
- buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats;
-
- lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH);
- for (i = 0; i < curlencheck; ++i)
- lengths_ptr[i] = cpu_to_be16(sample_lens[i]);
-
- datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH +
- (sizeof(u16) * RR3_DRIVER_MAXLENS));
- memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN));
-
- if (debug) {
- redrat3_dump_signal_header(&header);
- redrat3_dump_signal_data(buffer, header.sig_size);
- }
+ irdata->header.length = cpu_to_be16(sendbuf_len -
+ sizeof(struct redrat3_header));
+ irdata->header.transfer_type = cpu_to_be16(RR3_MOD_SIGNAL_OUT);
+ irdata->pause = cpu_to_be32(redrat3_len_to_us(100));
+ irdata->mod_freq_count = cpu_to_be16(mod_freq_to_val(rr3->carrier));
+ irdata->no_lengths = curlencheck;
+ irdata->sig_size = cpu_to_be16(count + RR3_TX_TRAILER_LEN);
pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
- tmps = usb_bulk_msg(rr3->udev, pipe, buffer,
+ ret = usb_bulk_msg(rr3->udev, pipe, irdata,
sendbuf_len, &ret_len, 10 * HZ);
- rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps);
+ rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret);
/* now tell the hardware to transmit what we sent it */
pipe = usb_rcvctrlpipe(rr3->udev, 0);
ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, 0, buffer, 2, HZ * 10);
+ 0, 0, irdata, 2, HZ * 10);
if (ret < 0)
dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
@@ -1040,8 +864,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf,
out:
kfree(sample_lens);
- kfree(buffer);
- kfree(sigdata);
+ kfree(irdata);
rr3->transmitting = false;
/* rr3 re-enables rc detector because it was enabled before */
@@ -1165,38 +988,18 @@ static int redrat3_dev_probe(struct usb_interface *intf,
}
rr3->ep_in = ep_in;
- rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize,
- GFP_ATOMIC, &rr3->dma_in);
+ rr3->bulk_in_buf = usb_alloc_coherent(udev,
+ le16_to_cpu(ep_in->wMaxPacketSize), GFP_ATOMIC, &rr3->dma_in);
if (!rr3->bulk_in_buf) {
dev_err(dev, "Read buffer allocation failure\n");
goto error;
}
pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
- usb_fill_bulk_urb(rr3->read_urb, udev, pipe,
- rr3->bulk_in_buf, ep_in->wMaxPacketSize,
- (usb_complete_t)redrat3_handle_async, rr3);
-
- /* set up bulk-out endpoint*/
- rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!rr3->write_urb) {
- dev_err(dev, "Write urb allocation failure\n");
- goto error;
- }
+ usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
+ le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3);
rr3->ep_out = ep_out;
- rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize,
- GFP_ATOMIC, &rr3->dma_out);
- if (!rr3->bulk_out_buf) {
- dev_err(dev, "Write buffer allocation failure\n");
- goto error;
- }
-
- pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress);
- usb_fill_bulk_urb(rr3->write_urb, udev, pipe,
- rr3->bulk_out_buf, ep_out->wMaxPacketSize,
- (usb_complete_t)redrat3_write_bulk_callback, rr3);
-
rr3->udev = udev;
redrat3_reset(rr3);
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index cf0d47f57fb2..891762d167ed 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -347,6 +347,7 @@ static int ttusbir_probe(struct usb_interface *intf,
return 0;
out3:
rc_unregister_device(rc);
+ rc = NULL;
out2:
led_classdev_unregister(&tt->led);
out:
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 535a18dccbd0..87af2d3ba601 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1151,6 +1151,7 @@ exit_release_wbase:
release_region(data->wbase, WAKEUP_IOMEM_LEN);
exit_unregister_device:
rc_unregister_device(data->dev);
+ data->dev = NULL;
exit_free_rc:
rc_free_device(data->dev);
exit_unregister_led:
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index e8fdf713fce8..f6768cad001a 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -241,4 +241,18 @@ config MEDIA_TUNER_TUA9001
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Infineon TUA 9001 silicon tuner driver.
+
+config MEDIA_TUNER_IT913X
+ tristate "ITE Tech IT913x silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ ITE Tech IT913x silicon tuner driver.
+
+config MEDIA_TUNER_R820T
+ tristate "Rafael Micro R820T silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Rafael Micro R820T silicon tuner driver.
endmenu
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 5e569b1083cf..308f108eadba 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
+obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o
+obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h
index 71b1935eb3d2..3783a0bdf855 100644
--- a/drivers/media/tuners/e4000.h
+++ b/drivers/media/tuners/e4000.h
@@ -21,6 +21,7 @@
#ifndef E4000_H
#define E4000_H
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
struct e4000_config {
@@ -36,8 +37,7 @@ struct e4000_config {
u32 clock;
};
-#if defined(CONFIG_MEDIA_TUNER_E4000) || \
- (defined(CONFIG_MEDIA_TUNER_E4000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_E4000)
extern struct dvb_frontend *e4000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct e4000_config *cfg);
#else
diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h
index 0ee581f122d2..43ec893a6877 100644
--- a/drivers/media/tuners/fc0011.h
+++ b/drivers/media/tuners/fc0011.h
@@ -1,6 +1,7 @@
#ifndef LINUX_FC0011_H_
#define LINUX_FC0011_H_
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
@@ -22,8 +23,7 @@ enum fc0011_fe_callback_commands {
FC0011_FE_CALLBACK_RESET,
};
-#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\
- defined(CONFIG_MEDIA_TUNER_FC0011_MODULE)
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0011)
struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct fc0011_config *config);
diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h
index 54508fcc3469..1d08057e3275 100644
--- a/drivers/media/tuners/fc0012.h
+++ b/drivers/media/tuners/fc0012.h
@@ -21,6 +21,7 @@
#ifndef _FC0012_H_
#define _FC0012_H_
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
#include "fc001x-common.h"
@@ -48,8 +49,7 @@ struct fc0012_config {
bool clock_out;
};
-#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
- (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0012)
extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct fc0012_config *cfg);
diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h
index 594efd64aeec..d65d5b37f56e 100644
--- a/drivers/media/tuners/fc0013.h
+++ b/drivers/media/tuners/fc0013.h
@@ -22,11 +22,11 @@
#ifndef _FC0013_H_
#define _FC0013_H_
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
#include "fc001x-common.h"
-#if defined(CONFIG_MEDIA_TUNER_FC0013) || \
- (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0013)
extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
u8 i2c_address, int dual_master,
diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h
index 222601e5d23b..9c43c1cc82d9 100644
--- a/drivers/media/tuners/fc2580.h
+++ b/drivers/media/tuners/fc2580.h
@@ -21,6 +21,7 @@
#ifndef FC2580_H
#define FC2580_H
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
struct fc2580_config {
@@ -36,8 +37,7 @@ struct fc2580_config {
u32 clock;
};
-#if defined(CONFIG_MEDIA_TUNER_FC2580) || \
- (defined(CONFIG_MEDIA_TUNER_FC2580_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC2580)
extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, const struct fc2580_config *cfg);
#else
diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h
index c063c36a93d3..26e1dc64bb67 100644
--- a/drivers/media/tuners/max2165.h
+++ b/drivers/media/tuners/max2165.h
@@ -22,6 +22,8 @@
#ifndef __MAX2165_H__
#define __MAX2165_H__
+#include <linux/kconfig.h>
+
struct dvb_frontend;
struct i2c_adapter;
@@ -30,8 +32,7 @@ struct max2165_config {
u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
};
-#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \
- (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MAX2165)
extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct max2165_config *cfg);
diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h
index 34f3892d3f6d..9aae50aca2b7 100644
--- a/drivers/media/tuners/mc44s803.h
+++ b/drivers/media/tuners/mc44s803.h
@@ -22,6 +22,8 @@
#ifndef MC44S803_H
#define MC44S803_H
+#include <linux/kconfig.h>
+
struct dvb_frontend;
struct i2c_adapter;
@@ -30,8 +32,7 @@ struct mc44s803_config {
u8 dig_out;
};
-#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \
- (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MC44S803)
extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct mc44s803_config *cfg);
#else
diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h
index fc8a1ffc53b4..ae8db885ad87 100644
--- a/drivers/media/tuners/mxl5005s.h
+++ b/drivers/media/tuners/mxl5005s.h
@@ -23,6 +23,8 @@
#ifndef __MXL5005S_H
#define __MXL5005S_H
+#include <linux/kconfig.h>
+
#include <linux/i2c.h>
#include "dvb_frontend.h"
@@ -116,8 +118,7 @@ struct mxl5005s_config {
u8 AgcMasterByte;
};
-#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
- (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5005S)
extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mxl5005s_config *config);
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
new file mode 100644
index 000000000000..4835021aa3b6
--- /dev/null
+++ b/drivers/media/tuners/r820t.c
@@ -0,0 +1,2355 @@
+/*
+ * Rafael Micro R820T driver
+ *
+ * Copyright (C) 2013 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This driver was written from scratch, based on an existing driver
+ * that it is part of rtl-sdr git tree, released under GPLv2:
+ * https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug
+ * https://github.com/n1gp/gr-baz
+ *
+ * From what I understood from the threads, the original driver was converted
+ * to userspace from a Realtek tree. I couldn't find the original tree.
+ * However, the original driver look awkward on my eyes. So, I decided to
+ * write a new version from it from the scratch, while trying to reproduce
+ * everything found there.
+ *
+ * TODO:
+ * After locking, the original driver seems to have some routines to
+ * improve reception. This was not implemented here yet.
+ *
+ * RF Gain set/get is not implemented.
+ *
+ * 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/videodev2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/bitrev.h>
+
+#include "tuner-i2c.h"
+#include "r820t.h"
+
+/*
+ * FIXME: I think that there are only 32 registers, but better safe than
+ * sorry. After finishing the driver, we may review it.
+ */
+#define REG_SHADOW_START 5
+#define NUM_REGS 27
+#define NUM_IMR 5
+#define IMR_TRIAL 9
+
+#define VER_NUM 49
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static int no_imr_cal;
+module_param(no_imr_cal, int, 0444);
+MODULE_PARM_DESC(no_imr_cal, "Disable IMR calibration at module init");
+
+
+/*
+ * enums and structures
+ */
+
+enum xtal_cap_value {
+ XTAL_LOW_CAP_30P = 0,
+ XTAL_LOW_CAP_20P,
+ XTAL_LOW_CAP_10P,
+ XTAL_LOW_CAP_0P,
+ XTAL_HIGH_CAP_0P
+};
+
+struct r820t_sect_type {
+ u8 phase_y;
+ u8 gain_x;
+ u16 value;
+};
+
+struct r820t_priv {
+ struct list_head hybrid_tuner_instance_list;
+ const struct r820t_config *cfg;
+ struct tuner_i2c_props i2c_props;
+ struct mutex lock;
+
+ u8 regs[NUM_REGS];
+ u8 buf[NUM_REGS + 1];
+ enum xtal_cap_value xtal_cap_sel;
+ u16 pll; /* kHz */
+ u32 int_freq;
+ u8 fil_cal_code;
+ bool imr_done;
+ bool has_lock;
+ bool init_done;
+ struct r820t_sect_type imr_data[NUM_IMR];
+
+ /* Store current mode */
+ u32 delsys;
+ enum v4l2_tuner_type type;
+ v4l2_std_id std;
+ u32 bw; /* in MHz */
+};
+
+struct r820t_freq_range {
+ u32 freq;
+ u8 open_d;
+ u8 rf_mux_ploy;
+ u8 tf_c;
+ u8 xtal_cap20p;
+ u8 xtal_cap10p;
+ u8 xtal_cap0p;
+ u8 imr_mem; /* Not used, currently */
+};
+
+#define VCO_POWER_REF 0x02
+#define DIP_FREQ 32000000
+
+/*
+ * Static constants
+ */
+
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(r820t_list_mutex);
+
+/* Those initial values start from REG_SHADOW_START */
+static const u8 r820t_init_array[NUM_REGS] = {
+ 0x83, 0x32, 0x75, /* 05 to 07 */
+ 0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */
+ 0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */
+ 0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */
+ 0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */
+ 0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */
+ 0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */
+};
+
+/* Tuner frequency ranges */
+static const struct r820t_freq_range freq_ranges[] = {
+ {
+ .freq = 0,
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0xdf, /* R27[7:0] band2,band0 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 50, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0xbe, /* R27[7:0] band4,band1 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 55, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x8b, /* R27[7:0] band7,band4 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 60, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x7b, /* R27[7:0] band8,band4 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 65, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x69, /* R27[7:0] band9,band6 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 70, /* Start freq, in MHz */
+ .open_d = 0x08, /* low */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x58, /* R27[7:0] band10,band7 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 75, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x44, /* R27[7:0] band11,band11 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 80, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x44, /* R27[7:0] band11,band11 */
+ .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 90, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x34, /* R27[7:0] band12,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 100, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x34, /* R27[7:0] band12,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 0,
+ }, {
+ .freq = 110, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x24, /* R27[7:0] band13,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 120, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x24, /* R27[7:0] band13,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 140, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x14, /* R27[7:0] band14,band11 */
+ .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */
+ .xtal_cap10p = 0x01,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 180, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x13, /* R27[7:0] band14,band12 */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 1,
+ }, {
+ .freq = 220, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x13, /* R27[7:0] band14,band12 */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 250, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x11, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 280, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 310, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 2,
+ }, {
+ .freq = 450, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 3,
+ }, {
+ .freq = 588, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 3,
+ }, {
+ .freq = 650, /* Start freq, in MHz */
+ .open_d = 0x00, /* high */
+ .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */
+ .tf_c = 0x00, /* R27[7:0] highest,highest */
+ .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */
+ .xtal_cap10p = 0x00,
+ .xtal_cap0p = 0x00,
+ .imr_mem = 4,
+ }
+};
+
+static int r820t_xtal_capacitor[][2] = {
+ { 0x0b, XTAL_LOW_CAP_30P },
+ { 0x02, XTAL_LOW_CAP_20P },
+ { 0x01, XTAL_LOW_CAP_10P },
+ { 0x00, XTAL_LOW_CAP_0P },
+ { 0x10, XTAL_HIGH_CAP_0P },
+};
+
+/*
+ * measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm
+ * input power, for raw results see:
+ * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/
+ */
+
+static const int r820t_lna_gain_steps[] = {
+ 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13
+};
+
+static const int r820t_mixer_gain_steps[] = {
+ 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8
+};
+
+/*
+ * I2C read/write code and shadow registers logic
+ */
+static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val,
+ int len)
+{
+ int r = reg - REG_SHADOW_START;
+
+ if (r < 0) {
+ len += r;
+ r = 0;
+ }
+ if (len <= 0)
+ return;
+ if (len > NUM_REGS)
+ len = NUM_REGS;
+
+ tuner_dbg("%s: prev reg=%02x len=%d: %*ph\n",
+ __func__, r + REG_SHADOW_START, len, len, val);
+
+ memcpy(&priv->regs[r], val, len);
+}
+
+static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val,
+ int len)
+{
+ int rc, size, pos = 0;
+
+ /* Store the shadow registers */
+ shadow_store(priv, reg, val, len);
+
+ do {
+ if (len > priv->cfg->max_i2c_msg_len - 1)
+ size = priv->cfg->max_i2c_msg_len - 1;
+ else
+ size = len;
+
+ /* Fill I2C buffer */
+ priv->buf[0] = reg;
+ memcpy(&priv->buf[1], &val[pos], size);
+
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, priv->buf, size + 1);
+ if (rc != size + 1) {
+ tuner_info("%s: i2c wr failed=%d reg=%02x len=%d: %*ph\n",
+ __func__, rc, reg, size, size, &priv->buf[1]);
+ if (rc < 0)
+ return rc;
+ return -EREMOTEIO;
+ }
+ tuner_dbg("%s: i2c wr reg=%02x len=%d: %*ph\n",
+ __func__, reg, size, size, &priv->buf[1]);
+
+ reg += size;
+ len -= size;
+ pos += size;
+ } while (len > 0);
+
+ return 0;
+}
+
+static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val)
+{
+ return r820t_write(priv, reg, &val, 1);
+}
+
+static int r820t_read_cache_reg(struct r820t_priv *priv, int reg)
+{
+ reg -= REG_SHADOW_START;
+
+ if (reg >= 0 && reg < NUM_REGS)
+ return priv->regs[reg];
+ else
+ return -EINVAL;
+}
+
+static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val,
+ u8 bit_mask)
+{
+ int rc = r820t_read_cache_reg(priv, reg);
+
+ if (rc < 0)
+ return rc;
+
+ val = (rc & ~bit_mask) | (val & bit_mask);
+
+ return r820t_write(priv, reg, &val, 1);
+}
+
+static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len)
+{
+ int rc, i;
+ u8 *p = &priv->buf[1];
+
+ priv->buf[0] = reg;
+
+ rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, priv->buf, 1, p, len);
+ if (rc != len) {
+ tuner_info("%s: i2c rd failed=%d reg=%02x len=%d: %*ph\n",
+ __func__, rc, reg, len, len, p);
+ if (rc < 0)
+ return rc;
+ return -EREMOTEIO;
+ }
+
+ /* Copy data to the output buffer */
+ for (i = 0; i < len; i++)
+ val[i] = bitrev8(p[i]);
+
+ tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n",
+ __func__, reg, len, len, val);
+
+ return 0;
+}
+
+/*
+ * r820t tuning logic
+ */
+
+static int r820t_set_mux(struct r820t_priv *priv, u32 freq)
+{
+ const struct r820t_freq_range *range;
+ int i, rc;
+ u8 val, reg08, reg09;
+
+ /* Get the proper frequency range */
+ freq = freq / 1000000;
+ for (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) {
+ if (freq < freq_ranges[i + 1].freq)
+ break;
+ }
+ range = &freq_ranges[i];
+
+ tuner_dbg("set r820t range#%d for frequency %d MHz\n", i, freq);
+
+ /* Open Drain */
+ rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* RF_MUX,Polymux */
+ rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3);
+ if (rc < 0)
+ return rc;
+
+ /* TF BAND */
+ rc = r820t_write_reg(priv, 0x1b, range->tf_c);
+ if (rc < 0)
+ return rc;
+
+ /* XTAL CAP & Drive */
+ switch (priv->xtal_cap_sel) {
+ case XTAL_LOW_CAP_30P:
+ case XTAL_LOW_CAP_20P:
+ val = range->xtal_cap20p | 0x08;
+ break;
+ case XTAL_LOW_CAP_10P:
+ val = range->xtal_cap10p | 0x08;
+ break;
+ case XTAL_HIGH_CAP_0P:
+ val = range->xtal_cap0p | 0x00;
+ break;
+ default:
+ case XTAL_LOW_CAP_0P:
+ val = range->xtal_cap0p | 0x08;
+ break;
+ }
+ rc = r820t_write_reg_mask(priv, 0x10, val, 0x0b);
+ if (rc < 0)
+ return rc;
+
+ if (priv->imr_done) {
+ reg08 = priv->imr_data[range->imr_mem].gain_x;
+ reg09 = priv->imr_data[range->imr_mem].phase_y;
+ } else {
+ reg08 = 0;
+ reg09 = 0;
+ }
+ rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f);
+
+ return rc;
+}
+
+static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type,
+ u32 freq)
+{
+ u32 vco_freq;
+ int rc, i;
+ unsigned sleep_time = 10000;
+ u32 vco_fra; /* VCO contribution by SDM (kHz) */
+ u32 vco_min = 1770000;
+ u32 vco_max = vco_min * 2;
+ u32 pll_ref;
+ u16 n_sdm = 2;
+ u16 sdm = 0;
+ u8 mix_div = 2;
+ u8 div_buf = 0;
+ u8 div_num = 0;
+ u8 refdiv2 = 0;
+ u8 ni, si, nint, vco_fine_tune, val;
+ u8 data[5];
+
+ /* Frequency in kHz */
+ freq = freq / 1000;
+ pll_ref = priv->cfg->xtal / 1000;
+
+#if 0
+ /* Doesn't exist on rtl-sdk, and on field tests, caused troubles */
+ if ((priv->cfg->rafael_chip == CHIP_R620D) ||
+ (priv->cfg->rafael_chip == CHIP_R828D) ||
+ (priv->cfg->rafael_chip == CHIP_R828)) {
+ /* ref set refdiv2, reffreq = Xtal/2 on ATV application */
+ if (type != V4L2_TUNER_DIGITAL_TV) {
+ pll_ref /= 2;
+ refdiv2 = 0x10;
+ sleep_time = 20000;
+ }
+ } else {
+ if (priv->cfg->xtal > 24000000) {
+ pll_ref /= 2;
+ refdiv2 = 0x10;
+ }
+ }
+#endif
+
+ rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set pll autotune = 128kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
+ if (rc < 0)
+ return rc;
+
+ /* set VCO current = 100 */
+ rc = r820t_write_reg_mask(priv, 0x12, 0x80, 0xe0);
+ if (rc < 0)
+ return rc;
+
+ /* Calculate divider */
+ while (mix_div <= 64) {
+ if (((freq * mix_div) >= vco_min) &&
+ ((freq * mix_div) < vco_max)) {
+ div_buf = mix_div;
+ while (div_buf > 2) {
+ div_buf = div_buf >> 1;
+ div_num++;
+ }
+ break;
+ }
+ mix_div = mix_div << 1;
+ }
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ vco_fine_tune = (data[4] & 0x30) >> 4;
+
+ if (vco_fine_tune > VCO_POWER_REF)
+ div_num = div_num - 1;
+ else if (vco_fine_tune < VCO_POWER_REF)
+ div_num = div_num + 1;
+
+ rc = r820t_write_reg_mask(priv, 0x10, div_num << 5, 0xe0);
+ if (rc < 0)
+ return rc;
+
+ vco_freq = freq * mix_div;
+ nint = vco_freq / (2 * pll_ref);
+ vco_fra = vco_freq - 2 * pll_ref * nint;
+
+ /* boundary spur prevention */
+ if (vco_fra < pll_ref / 64) {
+ vco_fra = 0;
+ } else if (vco_fra > pll_ref * 127 / 64) {
+ vco_fra = 0;
+ nint++;
+ } else if ((vco_fra > pll_ref * 127 / 128) && (vco_fra < pll_ref)) {
+ vco_fra = pll_ref * 127 / 128;
+ } else if ((vco_fra > pll_ref) && (vco_fra < pll_ref * 129 / 128)) {
+ vco_fra = pll_ref * 129 / 128;
+ }
+
+ if (nint > 63) {
+ tuner_info("No valid PLL values for %u kHz!\n", freq);
+ return -EINVAL;
+ }
+
+ ni = (nint - 13) / 4;
+ si = nint - 4 * ni - 13;
+
+ rc = r820t_write_reg(priv, 0x14, ni + (si << 6));
+ if (rc < 0)
+ return rc;
+
+ /* pw_sdm */
+ if (!vco_fra)
+ val = 0x08;
+ else
+ val = 0x00;
+
+ rc = r820t_write_reg_mask(priv, 0x12, val, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* sdm calculator */
+ while (vco_fra > 1) {
+ if (vco_fra > (2 * pll_ref / n_sdm)) {
+ sdm = sdm + 32768 / (n_sdm / 2);
+ vco_fra = vco_fra - 2 * pll_ref / n_sdm;
+ if (n_sdm >= 0x8000)
+ break;
+ }
+ n_sdm = n_sdm << 1;
+ }
+
+ tuner_dbg("freq %d kHz, pll ref %d%s, sdm=0x%04x\n",
+ freq, pll_ref, refdiv2 ? " / 2" : "", sdm);
+
+ rc = r820t_write_reg(priv, 0x16, sdm >> 8);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x15, sdm & 0xff);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < 2; i++) {
+ usleep_range(sleep_time, sleep_time + 1000);
+
+ /* Check if PLL has locked */
+ rc = r820t_read(priv, 0x00, data, 3);
+ if (rc < 0)
+ return rc;
+ if (data[2] & 0x40)
+ break;
+
+ if (!i) {
+ /* Didn't lock. Increase VCO current */
+ rc = r820t_write_reg_mask(priv, 0x12, 0x60, 0xe0);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ if (!(data[2] & 0x40)) {
+ priv->has_lock = false;
+ return 0;
+ }
+
+ priv->has_lock = true;
+ tuner_dbg("tuner has lock at frequency %d kHz\n", freq);
+
+ /* set pll autotune = 8kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x08, 0x08);
+
+ return rc;
+}
+
+static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std,
+ u32 delsys)
+{
+ int rc;
+ u8 mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l;
+ u8 air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur;
+
+ tuner_dbg("adjusting tuner parameters for the standard\n");
+
+ switch (delsys) {
+ case SYS_DVBT:
+ if ((freq == 506000000) || (freq == 666000000) ||
+ (freq == 818000000)) {
+ mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ cp_cur = 0x28; /* 101, 0.2 */
+ div_buf_cur = 0x20; /* 10, 200u */
+ } else {
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ }
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ filter_cur = 0x40; /* 10, low */
+ break;
+ case SYS_DVBT2:
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ case SYS_ISDBT:
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ default: /* DVB-T 8M */
+ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */
+ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */
+ lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */
+ mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */
+ air_cable1_in = 0x00;
+ cable2_in = 0x00;
+ pre_dect = 0x40;
+ lna_discharge = 14;
+ cp_cur = 0x38; /* 111, auto */
+ div_buf_cur = 0x30; /* 11, 150u */
+ filter_cur = 0x40; /* 10, low */
+ break;
+ }
+
+ if (priv->cfg->use_diplexer &&
+ ((priv->cfg->rafael_chip == CHIP_R820T) ||
+ (priv->cfg->rafael_chip == CHIP_R828S) ||
+ (priv->cfg->rafael_chip == CHIP_R820C))) {
+ if (freq > DIP_FREQ)
+ air_cable1_in = 0x00;
+ else
+ air_cable1_in = 0x60;
+ cable2_in = 0x00;
+ }
+
+
+ if (priv->cfg->use_predetect) {
+ rc = r820t_write_reg_mask(priv, 0x06, pre_dect, 0x40);
+ if (rc < 0)
+ return rc;
+ }
+
+ rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0xf8);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0d, lna_vth_l);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0e, mixer_vth_l);
+ if (rc < 0)
+ return rc;
+
+ /* Air-IN only for Astrometa */
+ rc = r820t_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x06, cable2_in, 0x08);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x11, cp_cur, 0x38);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x17, div_buf_cur, 0x30);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg_mask(priv, 0x0a, filter_cur, 0x60);
+ if (rc < 0)
+ return rc;
+ /*
+ * Original driver initializes regs 0x05 and 0x06 with the
+ * same value again on this point. Probably, it is just an
+ * error there
+ */
+
+ /*
+ * Set LNA
+ */
+
+ tuner_dbg("adjusting LNA parameters\n");
+ if (type != V4L2_TUNER_ANALOG_TV) {
+ /* LNA TOP: lowest */
+ rc = r820t_write_reg_mask(priv, 0x1d, 0, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /* 0: normal mode */
+ rc = r820t_write_reg_mask(priv, 0x1c, 0, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* 0: PRE_DECT off */
+ rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 250hz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x30, 0x30);
+ if (rc < 0)
+ return rc;
+
+ msleep(250);
+
+ /* write LNA TOP = 3 */
+ rc = r820t_write_reg_mask(priv, 0x1d, 0x18, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * write discharge mode
+ * FIXME: IMHO, the mask here is wrong, but it matches
+ * what's there at the original driver
+ */
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* LNA discharge current */
+ rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 60hz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x20, 0x30);
+ if (rc < 0)
+ return rc;
+ } else {
+ /* PRE_DECT off */
+ rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* write LNA TOP */
+ rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0x38);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * write discharge mode
+ * FIXME: IMHO, the mask here is wrong, but it matches
+ * what's there at the original driver
+ */
+ rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* LNA discharge current */
+ rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* agc clk 1Khz, external det1 cap 1u */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x30);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x04);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int r820t_set_tv_standard(struct r820t_priv *priv,
+ unsigned bw,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std, u32 delsys)
+
+{
+ int rc, i;
+ u32 if_khz, filt_cal_lo;
+ u8 data[5], val;
+ u8 filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through;
+ u8 lt_att, flt_ext_widest, polyfil_cur;
+ bool need_calibration;
+
+ tuner_dbg("selecting the delivery system\n");
+
+ if (delsys == SYS_ISDBT) {
+ if_khz = 4063;
+ filt_cal_lo = 59000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
+ ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else {
+ if (bw <= 6) {
+ if_khz = 3570;
+ filt_cal_lo = 56000; /* 52000->56000 */
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else if (bw == 7) {
+#if 0
+ /*
+ * There are two 7 MHz tables defined on the original
+ * driver, but just the second one seems to be visible
+ * by rtl2832. Keep this one here commented, as it
+ * might be needed in the future
+ */
+
+ if_khz = 4070;
+ filt_cal_lo = 60000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+#endif
+ /* 7 MHz, second table */
+ if_khz = 4570;
+ filt_cal_lo = 63000;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else {
+ if_khz = 4570;
+ filt_cal_lo = 68500;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
+ }
+ }
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* Init Flag & Xtal_check Result */
+ if (priv->imr_done)
+ val = 1 | priv->xtal_cap_sel << 1;
+ else
+ val = 0;
+ rc = r820t_write_reg_mask(priv, 0x0c, val, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* version */
+ rc = r820t_write_reg_mask(priv, 0x13, VER_NUM, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ /* for LT Gain test */
+ if (type != V4L2_TUNER_ANALOG_TV) {
+ rc = r820t_write_reg_mask(priv, 0x1d, 0x00, 0x38);
+ if (rc < 0)
+ return rc;
+ usleep_range(1000, 2000);
+ }
+ priv->int_freq = if_khz * 1000;
+
+ /* Check if standard changed. If so, filter calibration is needed */
+ if (type != priv->type)
+ need_calibration = true;
+ else if ((type == V4L2_TUNER_ANALOG_TV) && (std != priv->std))
+ need_calibration = true;
+ else if ((type == V4L2_TUNER_DIGITAL_TV) &&
+ ((delsys != priv->delsys) || bw != priv->bw))
+ need_calibration = true;
+ else
+ need_calibration = false;
+
+ if (need_calibration) {
+ tuner_dbg("calibrating the tuner\n");
+ for (i = 0; i < 2; i++) {
+ /* Set filt_cap */
+ rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* set cali clk =on */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* X'tal cap 0pF for PLL */
+ rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_set_pll(priv, type, filt_cal_lo * 1000);
+ if (rc < 0 || !priv->has_lock)
+ return rc;
+
+ /* Start Trigger */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(1000, 2000);
+
+ /* Stop Trigger */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set cali clk =off */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04);
+ if (rc < 0)
+ return rc;
+
+ /* Check if calibration worked */
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ priv->fil_cal_code = data[4] & 0x0f;
+ if (priv->fil_cal_code && priv->fil_cal_code != 0x0f)
+ break;
+ }
+ /* narrowest */
+ if (priv->fil_cal_code == 0x0f)
+ priv->fil_cal_code = 0;
+ }
+
+ rc = r820t_write_reg_mask(priv, 0x0a,
+ filt_q | priv->fil_cal_code, 0x1f);
+ if (rc < 0)
+ return rc;
+
+ /* Set BW, Filter_gain, & HP corner */
+ rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0xef);
+ if (rc < 0)
+ return rc;
+
+
+ /* Set Img_R */
+ rc = r820t_write_reg_mask(priv, 0x07, img_r, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Set filt_3dB, V6MHz */
+ rc = r820t_write_reg_mask(priv, 0x06, filt_gain, 0x30);
+ if (rc < 0)
+ return rc;
+
+ /* channel filter extension */
+ rc = r820t_write_reg_mask(priv, 0x1e, ext_enable, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Loop through */
+ rc = r820t_write_reg_mask(priv, 0x05, loop_through, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Loop through attenuation */
+ rc = r820t_write_reg_mask(priv, 0x1f, lt_att, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* filter extension widest */
+ rc = r820t_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* RF poly filter current */
+ rc = r820t_write_reg_mask(priv, 0x19, polyfil_cur, 0x60);
+ if (rc < 0)
+ return rc;
+
+ /* Store current standard. If it changes, re-calibrate the tuner */
+ priv->delsys = delsys;
+ priv->type = type;
+ priv->std = std;
+ priv->bw = bw;
+
+ return 0;
+}
+
+static int r820t_read_gain(struct r820t_priv *priv)
+{
+ u8 data[4];
+ int rc;
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4);
+}
+
+#if 0
+/* FIXME: This routine requires more testing */
+static int r820t_set_gain_mode(struct r820t_priv *priv,
+ bool set_manual_gain,
+ int gain)
+{
+ int rc;
+
+ if (set_manual_gain) {
+ int i, total_gain = 0;
+ uint8_t mix_index = 0, lna_index = 0;
+ u8 data[4];
+
+ /* LNA auto off */
+ rc = r820t_write_reg_mask(priv, 0x05, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* Mixer auto off */
+ rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ /* set fixed VGA gain for now (16.3 dB) */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x08, 0x9f);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < 15; i++) {
+ if (total_gain >= gain)
+ break;
+
+ total_gain += r820t_lna_gain_steps[++lna_index];
+
+ if (total_gain >= gain)
+ break;
+
+ total_gain += r820t_mixer_gain_steps[++mix_index];
+ }
+
+ /* set LNA gain */
+ rc = r820t_write_reg_mask(priv, 0x05, lna_index, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* set Mixer gain */
+ rc = r820t_write_reg_mask(priv, 0x07, mix_index, 0x0f);
+ if (rc < 0)
+ return rc;
+ } else {
+ /* LNA */
+ rc = r820t_write_reg_mask(priv, 0x05, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* Mixer */
+ rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* set fixed VGA gain for now (26.5 dB) */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+#endif
+
+static int generic_set_freq(struct dvb_frontend *fe,
+ u32 freq /* in HZ */,
+ unsigned bw,
+ enum v4l2_tuner_type type,
+ v4l2_std_id std, u32 delsys)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc = -EINVAL;
+ u32 lo_freq;
+
+ tuner_dbg("should set frequency to %d kHz, bw %d MHz\n",
+ freq / 1000, bw);
+
+ rc = r820t_set_tv_standard(priv, bw, type, std, delsys);
+ if (rc < 0)
+ goto err;
+
+ if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC))
+ lo_freq = freq - priv->int_freq;
+ else
+ lo_freq = freq + priv->int_freq;
+
+ rc = r820t_set_mux(priv, lo_freq);
+ if (rc < 0)
+ goto err;
+
+ rc = r820t_set_pll(priv, type, lo_freq);
+ if (rc < 0 || !priv->has_lock)
+ goto err;
+
+ rc = r820t_sysfreq_sel(priv, freq, type, std, delsys);
+ if (rc < 0)
+ goto err;
+
+ tuner_dbg("%s: PLL locked on frequency %d Hz, gain=%d\n",
+ __func__, freq, r820t_read_gain(priv));
+
+err:
+
+ if (rc < 0)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+/*
+ * r820t standby logic
+ */
+
+static int r820t_standby(struct r820t_priv *priv)
+{
+ int rc;
+
+ /* If device was not initialized yet, don't need to standby */
+ if (!priv->init_done)
+ return 0;
+
+ rc = r820t_write_reg(priv, 0x06, 0xb1);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x05, 0x03);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x07, 0x3a);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x08, 0x40);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x09, 0xc0);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0a, 0x36);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0c, 0x35);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x0f, 0x68);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x11, 0x03);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x17, 0xf4);
+ if (rc < 0)
+ return rc;
+ rc = r820t_write_reg(priv, 0x19, 0x0c);
+
+ /* Force initial calibration */
+ priv->type = -1;
+
+ return rc;
+}
+
+/*
+ * r820t device init logic
+ */
+
+static int r820t_xtal_check(struct r820t_priv *priv)
+{
+ int rc, i;
+ u8 data[3], val;
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* cap 30pF & Drive Low */
+ rc = r820t_write_reg_mask(priv, 0x10, 0x0b, 0x0b);
+ if (rc < 0)
+ return rc;
+
+ /* set pll autotune = 128kHz */
+ rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c);
+ if (rc < 0)
+ return rc;
+
+ /* set manual initial reg = 111111; */
+ rc = r820t_write_reg_mask(priv, 0x13, 0x7f, 0x7f);
+ if (rc < 0)
+ return rc;
+
+ /* set auto */
+ rc = r820t_write_reg_mask(priv, 0x13, 0x00, 0x40);
+ if (rc < 0)
+ return rc;
+
+ /* Try several xtal capacitor alternatives */
+ for (i = 0; i < ARRAY_SIZE(r820t_xtal_capacitor); i++) {
+ rc = r820t_write_reg_mask(priv, 0x10,
+ r820t_xtal_capacitor[i][0], 0x1b);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(5000, 6000);
+
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+ if (!(data[2] & 0x40))
+ continue;
+
+ val = data[2] & 0x3f;
+
+ if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23))
+ break;
+
+ if (val != 0x3f)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(r820t_xtal_capacitor))
+ return -EINVAL;
+
+ return r820t_xtal_capacitor[i][1];
+}
+
+static int r820t_imr_prepare(struct r820t_priv *priv)
+{
+ int rc;
+
+ /* Initialize the shadow registers */
+ memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array));
+
+ /* lna off (air-in off) */
+ rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20);
+ if (rc < 0)
+ return rc;
+
+ /* mixer gain mode = manual */
+ rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* filter corner = lowest */
+ rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ /* filter bw=+2cap, hp=5M */
+ rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f);
+ if (rc < 0)
+ return rc;
+
+ /* adc=on, vga code mode, gain = 26.5dB */
+ rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f);
+ if (rc < 0)
+ return rc;
+
+ /* ring clk = on */
+ rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08);
+ if (rc < 0)
+ return rc;
+
+ /* ring power = on */
+ rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10);
+ if (rc < 0)
+ return rc;
+
+ /* from ring = ring pll in */
+ rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02);
+ if (rc < 0)
+ return rc;
+
+ /* sw_pdect = det3 */
+ rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80);
+ if (rc < 0)
+ return rc;
+
+ /* Set filt_3dB */
+ rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20);
+
+ return rc;
+}
+
+static int r820t_multi_read(struct r820t_priv *priv)
+{
+ int rc, i;
+ u8 data[2], min = 0, max = 255, sum = 0;
+
+ usleep_range(5000, 6000);
+
+ for (i = 0; i < 6; i++) {
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ return rc;
+
+ sum += data[1];
+
+ if (data[1] < min)
+ min = data[1];
+
+ if (data[1] > max)
+ max = data[1];
+ }
+ rc = sum - max - min;
+
+ return rc;
+}
+
+static int r820t_imr_cross(struct r820t_priv *priv,
+ struct r820t_sect_type iq_point[3],
+ u8 *x_direct)
+{
+ struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */
+ struct r820t_sect_type tmp;
+ int i, rc;
+ u8 reg08, reg09;
+
+ reg08 = r820t_read_cache_reg(priv, 8) & 0xc0;
+ reg09 = r820t_read_cache_reg(priv, 9) & 0xc0;
+
+ tmp.gain_x = 0;
+ tmp.phase_y = 0;
+ tmp.value = 255;
+
+ for (i = 0; i < 5; i++) {
+ switch (i) {
+ case 0:
+ cross[i].gain_x = reg08;
+ cross[i].phase_y = reg09;
+ break;
+ case 1:
+ cross[i].gain_x = reg08; /* 0 */
+ cross[i].phase_y = reg09 + 1; /* Q-1 */
+ break;
+ case 2:
+ cross[i].gain_x = reg08; /* 0 */
+ cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */
+ break;
+ case 3:
+ cross[i].gain_x = reg08 + 1; /* Q-1 */
+ cross[i].phase_y = reg09;
+ break;
+ default:
+ cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */
+ cross[i].phase_y = reg09;
+ }
+
+ rc = r820t_write_reg(priv, 0x08, cross[i].gain_x);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, 0x09, cross[i].phase_y);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+
+ cross[i].value = rc;
+
+ if (cross[i].value < tmp.value)
+ memcpy(&tmp, &cross[i], sizeof(tmp));
+ }
+
+ if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */
+ *x_direct = 0;
+
+ iq_point[0] = cross[0];
+ iq_point[1] = cross[1];
+ iq_point[2] = cross[2];
+ } else { /* (0,0) or x-direction */
+ *x_direct = 1;
+
+ iq_point[0] = cross[0];
+ iq_point[1] = cross[3];
+ iq_point[2] = cross[4];
+ }
+ return 0;
+}
+
+static void r820t_compre_cor(struct r820t_sect_type iq[3])
+{
+ int i;
+
+ for (i = 3; i > 0; i--) {
+ if (iq[0].value > iq[i - 1].value)
+ swap(iq[0], iq[i - 1]);
+ }
+}
+
+static int r820t_compre_step(struct r820t_priv *priv,
+ struct r820t_sect_type iq[3], u8 reg)
+{
+ int rc;
+ struct r820t_sect_type tmp;
+
+ /*
+ * Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare
+ * with min value:
+ * new < min => update to min and continue
+ * new > min => Exit
+ */
+
+ /* min value already saved in iq[0] */
+ tmp.phase_y = iq[0].phase_y;
+ tmp.gain_x = iq[0].gain_x;
+
+ while (((tmp.gain_x & 0x1f) < IMR_TRIAL) &&
+ ((tmp.phase_y & 0x1f) < IMR_TRIAL)) {
+ if (reg == 0x08)
+ tmp.gain_x++;
+ else
+ tmp.phase_y++;
+
+ rc = r820t_write_reg(priv, 0x08, tmp.gain_x);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, 0x09, tmp.phase_y);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+ tmp.value = rc;
+
+ if (tmp.value <= iq[0].value) {
+ iq[0].gain_x = tmp.gain_x;
+ iq[0].phase_y = tmp.phase_y;
+ iq[0].value = tmp.value;
+ } else {
+ return 0;
+ }
+
+ }
+
+ return 0;
+}
+
+static int r820t_iq_tree(struct r820t_priv *priv,
+ struct r820t_sect_type iq[3],
+ u8 fix_val, u8 var_val, u8 fix_reg)
+{
+ int rc, i;
+ u8 tmp, var_reg;
+
+ /*
+ * record IMC results by input gain/phase location then adjust
+ * gain or phase positive 1 step and negtive 1 step,
+ * both record results
+ */
+
+ if (fix_reg == 0x08)
+ var_reg = 0x09;
+ else
+ var_reg = 0x08;
+
+ for (i = 0; i < 3; i++) {
+ rc = r820t_write_reg(priv, fix_reg, fix_val);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg(priv, var_reg, var_val);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+ iq[i].value = rc;
+
+ if (fix_reg == 0x08) {
+ iq[i].gain_x = fix_val;
+ iq[i].phase_y = var_val;
+ } else {
+ iq[i].phase_y = fix_val;
+ iq[i].gain_x = var_val;
+ }
+
+ if (i == 0) { /* try right-side point */
+ var_val++;
+ } else if (i == 1) { /* try left-side point */
+ /* if absolute location is 1, change I/Q direction */
+ if ((var_val & 0x1f) < 0x02) {
+ tmp = 2 - (var_val & 0x1f);
+
+ /* b[5]:I/Q selection. 0:Q-path, 1:I-path */
+ if (var_val & 0x20) {
+ var_val &= 0xc0;
+ var_val |= tmp;
+ } else {
+ var_val |= 0x20 | tmp;
+ }
+ } else {
+ var_val -= 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int r820t_section(struct r820t_priv *priv,
+ struct r820t_sect_type *iq_point)
+{
+ int rc;
+ struct r820t_sect_type compare_iq[3], compare_bet[3];
+
+ /* Try X-1 column and save min result to compare_bet[0] */
+ if (!(iq_point->gain_x & 0x1f))
+ compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */
+ else
+ compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ /* y-direction */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[0] = compare_iq[0];
+
+ /* Try X column and save min result to compare_bet[1] */
+ compare_iq[0].gain_x = iq_point->gain_x;
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[1] = compare_iq[0];
+
+ /* Try X+1 column and save min result to compare_bet[2] */
+ if ((iq_point->gain_x & 0x1f) == 0x00)
+ compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */
+ else
+ compare_iq[0].gain_x = iq_point->gain_x + 1;
+ compare_iq[0].phase_y = iq_point->phase_y;
+
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, 0x08);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ compare_bet[2] = compare_iq[0];
+
+ r820t_compre_cor(compare_bet);
+
+ *iq_point = compare_bet[0];
+
+ return 0;
+}
+
+static int r820t_vga_adjust(struct r820t_priv *priv)
+{
+ int rc;
+ u8 vga_count;
+
+ /* increase vga power to let image significant */
+ for (vga_count = 12; vga_count < 16; vga_count++) {
+ rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f);
+ if (rc < 0)
+ return rc;
+
+ usleep_range(10000, 11000);
+
+ rc = r820t_multi_read(priv);
+ if (rc < 0)
+ return rc;
+
+ if (rc > 40 * 4)
+ break;
+ }
+
+ return 0;
+}
+
+static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
+{
+ struct r820t_sect_type compare_iq[3];
+ int rc;
+ u8 x_direction = 0; /* 1:x, 0:y */
+ u8 dir_reg, other_reg;
+
+ r820t_vga_adjust(priv);
+
+ rc = r820t_imr_cross(priv, compare_iq, &x_direction);
+ if (rc < 0)
+ return rc;
+
+ if (x_direction == 1) {
+ dir_reg = 0x08;
+ other_reg = 0x09;
+ } else {
+ dir_reg = 0x09;
+ other_reg = 0x08;
+ }
+
+ /* compare and find min of 3 points. determine i/q direction */
+ r820t_compre_cor(compare_iq);
+
+ /* increase step to find min value of this direction */
+ rc = r820t_compre_step(priv, compare_iq, dir_reg);
+ if (rc < 0)
+ return rc;
+
+ /* the other direction */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, dir_reg);
+ if (rc < 0)
+ return rc;
+
+ /* compare and find min of 3 points. determine i/q direction */
+ r820t_compre_cor(compare_iq);
+
+ /* increase step to find min value on this direction */
+ rc = r820t_compre_step(priv, compare_iq, other_reg);
+ if (rc < 0)
+ return rc;
+
+ /* check 3 points again */
+ rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x,
+ compare_iq[0].phase_y, other_reg);
+ if (rc < 0)
+ return rc;
+
+ r820t_compre_cor(compare_iq);
+
+ /* section-9 check */
+ rc = r820t_section(priv, compare_iq);
+
+ *iq_pont = compare_iq[0];
+
+ /* reset gain/phase control setting */
+ rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f);
+
+ return rc;
+}
+
+static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont)
+{
+ int rc;
+
+ r820t_vga_adjust(priv);
+
+ /*
+ * search surrounding points from previous point
+ * try (x-1), (x), (x+1) columns, and find min IMR result point
+ */
+ rc = r820t_section(priv, iq_pont);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag)
+{
+ struct r820t_sect_type imr_point;
+ int rc;
+ u32 ring_vco, ring_freq, ring_ref;
+ u8 n_ring, n;
+ int reg18, reg19, reg1f;
+
+ if (priv->cfg->xtal > 24000000)
+ ring_ref = priv->cfg->xtal / 2;
+ else
+ ring_ref = priv->cfg->xtal;
+
+ n_ring = 15;
+ for (n = 0; n < 16; n++) {
+ if ((16 + n) * 8 * ring_ref >= 3100000) {
+ n_ring = n;
+ break;
+ }
+ }
+
+ reg18 = r820t_read_cache_reg(priv, 0x18);
+ reg19 = r820t_read_cache_reg(priv, 0x19);
+ reg1f = r820t_read_cache_reg(priv, 0x1f);
+
+ reg18 &= 0xf0; /* set ring[3:0] */
+ reg18 |= n_ring;
+
+ ring_vco = (16 + n_ring) * 8 * ring_ref;
+
+ reg18 &= 0xdf; /* clear ring_se23 */
+ reg19 &= 0xfc; /* clear ring_seldiv */
+ reg1f &= 0xfc; /* clear ring_att */
+
+ switch (imr_mem) {
+ case 0:
+ ring_freq = ring_vco / 48;
+ reg18 |= 0x20; /* ring_se23 = 1 */
+ reg19 |= 0x03; /* ring_seldiv = 3 */
+ reg1f |= 0x02; /* ring_att 10 */
+ break;
+ case 1:
+ ring_freq = ring_vco / 16;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x02; /* ring_seldiv = 2 */
+ reg1f |= 0x00; /* pw_ring 00 */
+ break;
+ case 2:
+ ring_freq = ring_vco / 8;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x01; /* ring_seldiv = 1 */
+ reg1f |= 0x03; /* pw_ring 11 */
+ break;
+ case 3:
+ ring_freq = ring_vco / 6;
+ reg18 |= 0x20; /* ring_se23 = 1 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x03; /* pw_ring 11 */
+ break;
+ case 4:
+ ring_freq = ring_vco / 4;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x01; /* pw_ring 01 */
+ break;
+ default:
+ ring_freq = ring_vco / 4;
+ reg18 |= 0x00; /* ring_se23 = 0 */
+ reg19 |= 0x00; /* ring_seldiv = 0 */
+ reg1f |= 0x01; /* pw_ring 01 */
+ break;
+ }
+
+
+ /* write pw_ring, n_ring, ringdiv2 registers */
+
+ /* n_ring, ring_se23 */
+ rc = r820t_write_reg(priv, 0x18, reg18);
+ if (rc < 0)
+ return rc;
+
+ /* ring_sediv */
+ rc = r820t_write_reg(priv, 0x19, reg19);
+ if (rc < 0)
+ return rc;
+
+ /* pw_ring */
+ rc = r820t_write_reg(priv, 0x1f, reg1f);
+ if (rc < 0)
+ return rc;
+
+ /* mux input freq ~ rf_in freq */
+ rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV,
+ (ring_freq - 5300) * 1000);
+ if (!priv->has_lock)
+ rc = -EINVAL;
+ if (rc < 0)
+ return rc;
+
+ if (im_flag) {
+ rc = r820t_iq(priv, &imr_point);
+ } else {
+ imr_point.gain_x = priv->imr_data[3].gain_x;
+ imr_point.phase_y = priv->imr_data[3].phase_y;
+ imr_point.value = priv->imr_data[3].value;
+
+ rc = r820t_f_imr(priv, &imr_point);
+ }
+ if (rc < 0)
+ return rc;
+
+ /* save IMR value */
+ switch (imr_mem) {
+ case 0:
+ priv->imr_data[0].gain_x = imr_point.gain_x;
+ priv->imr_data[0].phase_y = imr_point.phase_y;
+ priv->imr_data[0].value = imr_point.value;
+ break;
+ case 1:
+ priv->imr_data[1].gain_x = imr_point.gain_x;
+ priv->imr_data[1].phase_y = imr_point.phase_y;
+ priv->imr_data[1].value = imr_point.value;
+ break;
+ case 2:
+ priv->imr_data[2].gain_x = imr_point.gain_x;
+ priv->imr_data[2].phase_y = imr_point.phase_y;
+ priv->imr_data[2].value = imr_point.value;
+ break;
+ case 3:
+ priv->imr_data[3].gain_x = imr_point.gain_x;
+ priv->imr_data[3].phase_y = imr_point.phase_y;
+ priv->imr_data[3].value = imr_point.value;
+ break;
+ case 4:
+ priv->imr_data[4].gain_x = imr_point.gain_x;
+ priv->imr_data[4].phase_y = imr_point.phase_y;
+ priv->imr_data[4].value = imr_point.value;
+ break;
+ default:
+ priv->imr_data[4].gain_x = imr_point.gain_x;
+ priv->imr_data[4].phase_y = imr_point.phase_y;
+ priv->imr_data[4].value = imr_point.value;
+ break;
+ }
+
+ return 0;
+}
+
+static int r820t_imr_callibrate(struct r820t_priv *priv)
+{
+ int rc, i;
+ int xtal_cap = 0;
+
+ if (priv->init_done)
+ return 0;
+
+ /* Detect Xtal capacitance */
+ if ((priv->cfg->rafael_chip == CHIP_R820T) ||
+ (priv->cfg->rafael_chip == CHIP_R828S) ||
+ (priv->cfg->rafael_chip == CHIP_R820C)) {
+ priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
+ } else {
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+ if (rc < 0)
+ return rc;
+ for (i = 0; i < 3; i++) {
+ rc = r820t_xtal_check(priv);
+ if (rc < 0)
+ return rc;
+ if (!i || rc > xtal_cap)
+ xtal_cap = rc;
+ }
+ priv->xtal_cap_sel = xtal_cap;
+ }
+
+ /*
+ * Disables IMR callibration. That emulates the same behaviour
+ * as what is done by rtl-sdr userspace library. Useful for testing
+ */
+ if (no_imr_cal) {
+ priv->init_done = true;
+
+ return 0;
+ }
+
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_imr_prepare(priv);
+ if (rc < 0)
+ return rc;
+
+ rc = r820t_imr(priv, 3, true);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 1, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 0, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 2, false);
+ if (rc < 0)
+ return rc;
+ rc = r820t_imr(priv, 4, false);
+ if (rc < 0)
+ return rc;
+
+ priv->init_done = true;
+ priv->imr_done = true;
+
+ return 0;
+}
+
+#if 0
+/* Not used, for now */
+static int r820t_gpio(struct r820t_priv *priv, bool enable)
+{
+ return r820t_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01);
+}
+#endif
+
+/*
+ * r820t frontend operations and tuner attach code
+ *
+ * All driver locks and i2c control are only in this part of the code
+ */
+
+static int r820t_init(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = r820t_imr_callibrate(priv);
+ if (rc < 0)
+ goto err;
+
+ /* Initialize registers */
+ rc = r820t_write(priv, 0x05,
+ r820t_init_array, sizeof(r820t_init_array));
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ if (rc < 0)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_sleep(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = r820t_standby(priv);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_set_analog_freq(struct dvb_frontend *fe,
+ struct analog_parameters *p)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ unsigned bw;
+ int rc;
+
+ tuner_dbg("%s called\n", __func__);
+
+ /* if std is not defined, choose one */
+ if (!p->std)
+ p->std = V4L2_STD_MN;
+
+ if ((p->std == V4L2_STD_PAL_M) || (p->std == V4L2_STD_NTSC))
+ bw = 6;
+ else
+ bw = 8;
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ rc = generic_set_freq(fe, 62500l * p->frequency, bw,
+ V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ return rc;
+}
+
+static int r820t_set_params(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int rc;
+ unsigned bw;
+
+ tuner_dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ __func__, c->delivery_system, c->frequency, c->bandwidth_hz);
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ bw = (c->bandwidth_hz + 500000) / 1000000;
+ if (!bw)
+ bw = 8;
+
+ rc = generic_set_freq(fe, c->frequency, bw,
+ V4L2_TUNER_DIGITAL_TV, 0, c->delivery_system);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ if (rc)
+ tuner_dbg("%s: failed=%d\n", __func__, rc);
+ return rc;
+}
+
+static int r820t_signal(struct dvb_frontend *fe, u16 *strength)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+ int rc = 0;
+
+ mutex_lock(&priv->lock);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (priv->has_lock) {
+ rc = r820t_read_gain(priv);
+ if (rc < 0)
+ goto err;
+
+ /* A higher gain at LNA means a lower signal strength */
+ *strength = (45 - rc) << 4 | 0xff;
+ if (*strength == 0xff)
+ *strength = 0;
+ } else {
+ *strength = 0;
+ }
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ mutex_unlock(&priv->lock);
+
+ tuner_dbg("%s: %s, gain=%d strength=%d\n",
+ __func__,
+ priv->has_lock ? "PLL locked" : "no signal",
+ rc, *strength);
+
+ return 0;
+}
+
+static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+
+ tuner_dbg("%s:\n", __func__);
+
+ *frequency = priv->int_freq;
+
+ return 0;
+}
+
+static int r820t_release(struct dvb_frontend *fe)
+{
+ struct r820t_priv *priv = fe->tuner_priv;
+
+ tuner_dbg("%s:\n", __func__);
+
+ mutex_lock(&r820t_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&r820t_list_mutex);
+
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops r820t_tuner_ops = {
+ .info = {
+ .name = "Rafael Micro R820T",
+ .frequency_min = 42000000,
+ .frequency_max = 1002000000,
+ },
+ .init = r820t_init,
+ .release = r820t_release,
+ .sleep = r820t_sleep,
+ .set_params = r820t_set_params,
+ .set_analog_params = r820t_set_analog_freq,
+ .get_if_frequency = r820t_get_if_frequency,
+ .get_rf_strength = r820t_signal,
+};
+
+struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg)
+{
+ struct r820t_priv *priv;
+ int rc = -ENODEV;
+ u8 data[5];
+ int instance;
+
+ mutex_lock(&r820t_list_mutex);
+
+ instance = hybrid_tuner_request_state(struct r820t_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, cfg->i2c_addr,
+ "r820t");
+ switch (instance) {
+ case 0:
+ /* memory allocation failure */
+ goto err_no_gate;
+ break;
+ case 1:
+ /* new tuner instance */
+ priv->cfg = cfg;
+
+ mutex_init(&priv->lock);
+
+ fe->tuner_priv = priv;
+ break;
+ case 2:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+ break;
+ }
+
+ memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ /* check if the tuner is there */
+ rc = r820t_read(priv, 0x00, data, sizeof(data));
+ if (rc < 0)
+ goto err;
+
+ rc = r820t_sleep(fe);
+ if (rc < 0)
+ goto err;
+
+ tuner_info("Rafael Micro r820t successfully identified\n");
+
+ fe->tuner_priv = priv;
+ memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ mutex_unlock(&r820t_list_mutex);
+
+ return fe;
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+err_no_gate:
+ mutex_unlock(&r820t_list_mutex);
+
+ tuner_info("%s: failed=%d\n", __func__, rc);
+ r820t_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(r820t_attach);
+
+MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h
new file mode 100644
index 000000000000..48af3548027d
--- /dev/null
+++ b/drivers/media/tuners/r820t.h
@@ -0,0 +1,59 @@
+/*
+ * Elonics R820T silicon tuner driver
+ *
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef R820T_H
+#define R820T_H
+
+#include <linux/kconfig.h>
+#include "dvb_frontend.h"
+
+enum r820t_chip {
+ CHIP_R820T,
+ CHIP_R620D,
+ CHIP_R828D,
+ CHIP_R828,
+ CHIP_R828S,
+ CHIP_R820C,
+};
+
+struct r820t_config {
+ u8 i2c_addr; /* 0x34 */
+ u32 xtal;
+ enum r820t_chip rafael_chip;
+ unsigned max_i2c_msg_len;
+ bool use_diplexer;
+ bool use_predetect;
+};
+
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T)
+struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg);
+#else
+static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct r820t_config *cfg)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h
index 9bd5da4aabb7..7e0d503baf05 100644
--- a/drivers/media/tuners/tda18212.h
+++ b/drivers/media/tuners/tda18212.h
@@ -21,6 +21,7 @@
#ifndef TDA18212_H
#define TDA18212_H
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
struct tda18212_config {
@@ -36,8 +37,7 @@ struct tda18212_config {
u16 if_dvbc;
};
-#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
- (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212)
extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18212_config *cfg);
#else
diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h
index b4180d180029..366410e0cc9a 100644
--- a/drivers/media/tuners/tda18218.h
+++ b/drivers/media/tuners/tda18218.h
@@ -21,6 +21,7 @@
#ifndef TDA18218_H
#define TDA18218_H
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
struct tda18218_config {
@@ -29,8 +30,7 @@ struct tda18218_config {
u8 loop_through:1;
};
-#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
- (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18218)
extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tda18218_config *cfg);
#else
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index e7786862dab2..4995b890c164 100644
--- a/drivers/media/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -21,6 +21,7 @@
#include <linux/delay.h>
#include <linux/videodev2.h>
#include "tda18271-priv.h"
+#include "tda8290.h"
int tda18271_debug;
module_param_named(debug, tda18271_debug, int, 0644);
@@ -867,12 +868,12 @@ static int tda18271_agc(struct dvb_frontend *fe)
int ret = 0;
switch (priv->config) {
- case 0:
+ case TDA8290_LNA_OFF:
/* no external agc configuration required */
if (tda18271_debug & DBG_ADV)
tda_dbg("no agc configuration provided\n");
break;
- case 3:
+ case TDA8290_LNA_ON_BRIDGE:
/* switch with GPIO of saa713x */
tda_dbg("invoking callback\n");
if (fe->callback)
@@ -881,8 +882,8 @@ static int tda18271_agc(struct dvb_frontend *fe)
TDA18271_CALLBACK_CMD_AGC_ENABLE,
priv->mode);
break;
- case 1:
- case 2:
+ case TDA8290_LNA_GP0_HIGH_ON:
+ case TDA8290_LNA_GP0_HIGH_OFF:
default:
/* n/a - currently not supported */
tda_err("unsupported configuration: %d\n", priv->config);
diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c
index a0d176267470..73453a255cdc 100644
--- a/drivers/media/tuners/tda827x.c
+++ b/drivers/media/tuners/tda827x.c
@@ -479,10 +479,10 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
dprintk("setting LNA to low gain\n");
}
switch (priv->cfg->config) {
- case 0: /* no LNA */
+ case TDA8290_LNA_OFF: /* no LNA */
break;
- case 1: /* switch is GPIO 0 of tda8290 */
- case 2:
+ case TDA8290_LNA_GP0_HIGH_ON: /* switch is GPIO 0 of tda8290 */
+ case TDA8290_LNA_GP0_HIGH_OFF:
if (params == NULL) {
gp_func = 0;
arg = 0;
@@ -499,11 +499,11 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
DVB_FRONTEND_COMPONENT_TUNER,
gp_func, arg);
buf[1] = high ? 0 : 1;
- if (priv->cfg->config == 2)
+ if (priv->cfg->config == TDA8290_LNA_GP0_HIGH_OFF)
buf[1] = high ? 1 : 0;
tuner_transfer(fe, &msg, 1);
break;
- case 3: /* switch with GPIO of saa713x */
+ case TDA8290_LNA_ON_BRIDGE: /* switch with GPIO of saa713x */
if (fe->callback)
fe->callback(priv->i2c_adap->algo_data,
DVB_FRONTEND_COMPONENT_TUNER, 0, high);
diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h
index 9432b5b6121b..b64292152baf 100644
--- a/drivers/media/tuners/tda827x.h
+++ b/drivers/media/tuners/tda827x.h
@@ -26,6 +26,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
+#include "tda8290.h"
struct tda827x_config
{
@@ -34,7 +35,7 @@ struct tda827x_config
int (*sleep) (struct dvb_frontend *fe);
/* interface to tda829x driver */
- unsigned int config;
+ enum tda8290_lna config;
int switch_addr;
void (*agcf)(struct dvb_frontend *fe);
diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c
index 8c4852114eeb..ab4106c17b4c 100644
--- a/drivers/media/tuners/tda8290.c
+++ b/drivers/media/tuners/tda8290.c
@@ -54,6 +54,7 @@ struct tda8290_priv {
#define TDA18271 16
struct tda827x_config cfg;
+ struct tda18271_std_map *tda18271_std_map;
};
/*---------------------------------------------------------------------*/
@@ -233,7 +234,8 @@ static void tda8290_set_params(struct dvb_frontend *fe,
}
- tda8290_i2c_bridge(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, params);
@@ -302,7 +304,8 @@ static void tda8290_set_params(struct dvb_frontend *fe,
}
}
- tda8290_i2c_bridge(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
}
@@ -388,7 +391,7 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2);
}
-static int tda8295_has_signal(struct dvb_frontend *fe)
+static int tda8295_has_signal(struct dvb_frontend *fe, u16 *signal)
{
struct tda8290_priv *priv = fe->analog_demod_priv;
@@ -396,7 +399,8 @@ static int tda8295_has_signal(struct dvb_frontend *fe)
unsigned char ret;
tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
- return (ret & 0x01) ? 65535 : 0;
+ *signal = (ret & 0x01) ? 65535 : 0;
+ return 0;
}
/*---------------------------------------------------------------------*/
@@ -405,7 +409,7 @@ static void tda8295_set_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
struct tda8290_priv *priv = fe->analog_demod_priv;
-
+ u16 signal = 0;
unsigned char blanking_mode[] = { 0x1d, 0x00 };
set_audio(fe, params);
@@ -424,7 +428,8 @@ static void tda8295_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2);
msleep(20);
- tda8295_i2c_bridge(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, params);
@@ -432,17 +437,19 @@ static void tda8295_set_params(struct dvb_frontend *fe,
if (priv->cfg.agcf)
priv->cfg.agcf(fe);
- if (tda8295_has_signal(fe))
+ tda8295_has_signal(fe, &signal);
+ if (signal)
tuner_dbg("tda8295 is locked\n");
else
tuner_dbg("tda8295 not locked, no signal?\n");
- tda8295_i2c_bridge(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
}
/*---------------------------------------------------------------------*/
-static int tda8290_has_signal(struct dvb_frontend *fe)
+static int tda8290_has_signal(struct dvb_frontend *fe, u16 *signal)
{
struct tda8290_priv *priv = fe->analog_demod_priv;
@@ -451,7 +458,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe)
tuner_i2c_xfer_send_recv(&priv->i2c_props,
i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
- return (afc & 0x80)? 65535:0;
+ *signal = (afc & 0x80) ? 65535 : 0;
+ return 0;
}
/*---------------------------------------------------------------------*/
@@ -465,11 +473,13 @@ static void tda8290_standby(struct dvb_frontend *fe)
unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
- tda8290_i2c_bridge(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
if (priv->ver & TDA8275A)
cb1[1] = 0x90;
i2c_transfer(priv->i2c_props.adap, &msg, 1);
- tda8290_i2c_bridge(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
}
@@ -489,7 +499,8 @@ static void tda8290_init_if(struct dvb_frontend *fe)
unsigned char set_GP00_CF[] = { 0x20, 0x01 };
unsigned char set_GP01_CF[] = { 0x20, 0x0B };
- if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
+ if ((priv->cfg.config == TDA8290_LNA_GP0_HIGH_ON) ||
+ (priv->cfg.config == TDA8290_LNA_GP0_HIGH_OFF))
tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
else
tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
@@ -537,9 +548,11 @@ static void tda8290_init_tuner(struct dvb_frontend *fe)
if (priv->ver & TDA8275A)
msg.buf = tda8275a_init;
- tda8290_i2c_bridge(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_props.adap, &msg, 1);
- tda8290_i2c_bridge(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
}
/*---------------------------------------------------------------------*/
@@ -565,19 +578,13 @@ static struct tda18271_config tda829x_tda18271_config = {
static int tda829x_find_tuner(struct dvb_frontend *fe)
{
struct tda8290_priv *priv = fe->analog_demod_priv;
- struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
int i, ret, tuners_found;
u32 tuner_addrs;
u8 data;
struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 };
- if (!analog_ops->i2c_gate_ctrl) {
- printk(KERN_ERR "tda8290: no gate control were provided!\n");
-
- return -EINVAL;
- }
-
- analog_ops->i2c_gate_ctrl(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
/* probe for tuner chip */
tuners_found = 0;
@@ -595,7 +602,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
give a response now
*/
- analog_ops->i2c_gate_ctrl(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
if (tuners_found > 1)
for (i = 0; i < tuners_found; i++) {
@@ -618,18 +626,21 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
priv->tda827x_addr = tuner_addrs;
msg.addr = tuner_addrs;
- analog_ops->i2c_gate_ctrl(fe, 1);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if (ret != 1) {
tuner_warn("tuner access failed!\n");
- analog_ops->i2c_gate_ctrl(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
return -EREMOTEIO;
}
if ((data == 0x83) || (data == 0x84)) {
priv->ver |= TDA18271;
tda829x_tda18271_config.config = priv->cfg.config;
+ tda829x_tda18271_config.std_map = priv->tda18271_std_map;
dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
priv->i2c_props.adap, &tda829x_tda18271_config);
} else {
@@ -648,7 +659,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
if (fe->ops.tuner_ops.sleep)
fe->ops.tuner_ops.sleep(fe);
- analog_ops->i2c_gate_ctrl(fe, 0);
+ if (fe->ops.analog_ops.i2c_gate_ctrl)
+ fe->ops.analog_ops.i2c_gate_ctrl(fe, 0);
return 0;
}
@@ -740,8 +752,10 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
priv->i2c_props.name = "tda829x";
- if (cfg)
- priv->cfg.config = cfg->lna_cfg;
+ if (cfg) {
+ priv->cfg.config = cfg->lna_cfg;
+ priv->tda18271_std_map = cfg->tda18271_std_map;
+ }
if (tda8290_probe(&priv->i2c_props) == 0) {
priv->ver = TDA8290;
@@ -755,6 +769,9 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
sizeof(struct analog_demod_ops));
}
+ if (cfg && cfg->no_i2c_gate)
+ fe->ops.analog_ops.i2c_gate_ctrl = NULL;
+
if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
tda8295_power(fe, 1);
if (tda829x_find_tuner(fe) < 0)
diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h
index e12ecbaa35a4..cf96e585785e 100644
--- a/drivers/media/tuners/tda8290.h
+++ b/drivers/media/tuners/tda8290.h
@@ -19,13 +19,23 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
+#include "tda18271.h"
+
+enum tda8290_lna {
+ TDA8290_LNA_OFF = 0,
+ TDA8290_LNA_GP0_HIGH_ON = 1,
+ TDA8290_LNA_GP0_HIGH_OFF = 2,
+ TDA8290_LNA_ON_BRIDGE = 3,
+};
struct tda829x_config {
- unsigned int lna_cfg;
+ enum tda8290_lna lna_cfg;
unsigned int probe_tuner:1;
#define TDA829X_PROBE_TUNER 0
#define TDA829X_DONT_PROBE 1
+ unsigned int no_i2c_gate:1;
+ struct tda18271_std_map *tda18271_std_map;
};
#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290)
diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c
index cdb645d57438..300005c535ba 100644
--- a/drivers/media/tuners/tda9887.c
+++ b/drivers/media/tuners/tda9887.c
@@ -596,22 +596,22 @@ static void tda9887_tuner_status(struct dvb_frontend *fe)
priv->data[1], priv->data[2], priv->data[3]);
}
-static int tda9887_get_afc(struct dvb_frontend *fe)
+static int tda9887_get_afc(struct dvb_frontend *fe, s32 *afc)
{
struct tda9887_priv *priv = fe->analog_demod_priv;
- static int AFC_BITS_2_kHz[] = {
+ static const int AFC_BITS_2_kHz[] = {
-12500, -37500, -62500, -97500,
-112500, -137500, -162500, -187500,
187500, 162500, 137500, 112500,
97500 , 62500, 37500 , 12500
};
- int afc=0;
__u8 reg = 0;
- if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
- afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
-
- return afc;
+ if (priv->mode != V4L2_TUNER_RADIO)
+ return 0;
+ if (1 == tuner_i2c_xfer_recv(&priv->i2c_props, &reg, 1))
+ *afc = AFC_BITS_2_kHz[(reg >> 1) & 0x0f];
+ return 0;
}
static void tda9887_standby(struct dvb_frontend *fe)
diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h
index cf5b815feff9..26358da1c100 100644
--- a/drivers/media/tuners/tua9001.h
+++ b/drivers/media/tuners/tua9001.h
@@ -21,6 +21,7 @@
#ifndef TUA9001_H
#define TUA9001_H
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
struct tua9001_config {
@@ -50,8 +51,7 @@ struct tua9001_config {
#define TUA9001_CMD_RESETN 1
#define TUA9001_CMD_RXEN 2
-#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \
- (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_TUA9001)
extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c, struct tua9001_config *cfg);
#else
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
index 39e7e583c8c0..ca274c2d8c70 100644
--- a/drivers/media/tuners/tuner-simple.c
+++ b/drivers/media/tuners/tuner-simple.c
@@ -115,6 +115,7 @@ struct tuner_simple_priv {
u32 frequency;
u32 bandwidth;
+ bool radio_mode;
};
/* ---------------------------------------------------------------------- */
@@ -189,7 +190,7 @@ static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
struct tuner_simple_priv *priv = fe->tuner_priv;
int signal;
- if (priv->i2c_props.adap == NULL)
+ if (priv->i2c_props.adap == NULL || !priv->radio_mode)
return -EINVAL;
signal = tuner_signal(tuner_read_status(fe));
@@ -776,11 +777,13 @@ static int simple_set_params(struct dvb_frontend *fe,
switch (params->mode) {
case V4L2_TUNER_RADIO:
+ priv->radio_mode = true;
ret = simple_set_radio_freq(fe, params);
priv->frequency = params->frequency * 125 / 2;
break;
case V4L2_TUNER_ANALOG_TV:
case V4L2_TUNER_DIGITAL_TV:
+ priv->radio_mode = false;
ret = simple_set_tv_freq(fe, params);
priv->frequency = params->frequency * 62500;
break;
diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c
index 2da4440c16ee..98bc15a388be 100644
--- a/drivers/media/tuners/tuner-types.c
+++ b/drivers/media/tuners/tuner-types.c
@@ -1381,6 +1381,58 @@ static struct tuner_params tuner_philips_fq1236_mk5_params[] = {
},
};
+/* --------- Sony BTF-PG472Z PAL/SECAM ------- */
+
+static struct tuner_range tuner_sony_btf_pg472z_ranges[] = {
+ { 16 * 144.25 /*MHz*/, 0xc6, 0x01, },
+ { 16 * 427.25 /*MHz*/, 0xc6, 0x02, },
+ { 16 * 999.99 , 0xc6, 0x04, },
+};
+
+static struct tuner_params tuner_sony_btf_pg472z_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_sony_btf_pg472z_ranges,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg472z_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_invert_for_secam_lc = 1,
+ },
+};
+
+/* 90-99 */
+/* --------- Sony BTF-PG467Z NTSC-M-JP ------- */
+
+static struct tuner_range tuner_sony_btf_pg467z_ranges[] = {
+ { 16 * 220.25 /*MHz*/, 0xc6, 0x01, },
+ { 16 * 467.25 /*MHz*/, 0xc6, 0x02, },
+ { 16 * 999.99 , 0xc6, 0x04, },
+};
+
+static struct tuner_params tuner_sony_btf_pg467z_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_sony_btf_pg467z_ranges,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg467z_ranges),
+ },
+};
+
+/* --------- Sony BTF-PG463Z NTSC-M ------- */
+
+static struct tuner_range tuner_sony_btf_pg463z_ranges[] = {
+ { 16 * 130.25 /*MHz*/, 0xc6, 0x01, },
+ { 16 * 364.25 /*MHz*/, 0xc6, 0x02, },
+ { 16 * 999.99 , 0xc6, 0x04, },
+};
+
+static struct tuner_params tuner_sony_btf_pg463z_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_sony_btf_pg463z_ranges,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg463z_ranges),
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1872,6 +1924,23 @@ struct tunertype tuners[] = {
.name = "Xceive 5000C tuner",
/* see xc5000.c for details */
},
+ [TUNER_SONY_BTF_PG472Z] = {
+ .name = "Sony BTF-PG472Z PAL/SECAM",
+ .params = tuner_sony_btf_pg472z_params,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg472z_params),
+ },
+
+ /* 90-99 */
+ [TUNER_SONY_BTF_PK467Z] = {
+ .name = "Sony BTF-PK467Z NTSC-M-JP",
+ .params = tuner_sony_btf_pg467z_params,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg467z_params),
+ },
+ [TUNER_SONY_BTF_PB463Z] = {
+ .name = "Sony BTF-PB463Z NTSC-M",
+ .params = tuner_sony_btf_pg463z_params,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg463z_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 09451737c77e..878d2c4d9e8e 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1378,8 +1378,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
* For the firmware name, keep a local copy of the string,
* in order to avoid troubles during device release.
*/
- if (priv->ctrl.fname)
- kfree(priv->ctrl.fname);
+ kfree(priv->ctrl.fname);
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c
new file mode 100644
index 000000000000..6f30d7e535b8
--- /dev/null
+++ b/drivers/media/tuners/tuner_it913x.c
@@ -0,0 +1,447 @@
+/*
+ * ITE Tech IT9137 silicon tuner driver
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9137 Copyright (C) ITE Tech Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include "tuner_it913x_priv.h"
+
+struct it913x_state {
+ struct i2c_adapter *i2c_adap;
+ u8 i2c_addr;
+ u8 chip_ver;
+ u8 tuner_type;
+ u8 firmware_ver;
+ u16 tun_xtal;
+ u8 tun_fdiv;
+ u8 tun_clk_mode;
+ u32 tun_fn_min;
+};
+
+/* read multiple registers */
+static int it913x_rd_regs(struct it913x_state *state,
+ u32 reg, u8 *data, u8 count)
+{
+ int ret;
+ u8 b[3];
+ struct i2c_msg msg[2] = {
+ { .addr = state->i2c_addr, .flags = 0,
+ .buf = b, .len = sizeof(b) },
+ { .addr = state->i2c_addr, .flags = I2C_M_RD,
+ .buf = data, .len = count }
+ };
+ b[0] = (u8)(reg >> 16) & 0xff;
+ b[1] = (u8)(reg >> 8) & 0xff;
+ b[2] = (u8) reg & 0xff;
+ b[0] |= 0x80; /* All reads from demodulator */
+
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+ return ret;
+}
+
+/* read single register */
+static int it913x_rd_reg(struct it913x_state *state, u32 reg)
+{
+ int ret;
+ u8 b[1];
+ ret = it913x_rd_regs(state, reg, &b[0], sizeof(b));
+ return (ret < 0) ? -ENODEV : b[0];
+}
+
+/* write multiple registers */
+static int it913x_wr_regs(struct it913x_state *state,
+ u8 pro, u32 reg, u8 buf[], u8 count)
+{
+ u8 b[256];
+ struct i2c_msg msg[1] = {
+ { .addr = state->i2c_addr, .flags = 0,
+ .buf = b, .len = 3 + count }
+ };
+ int ret;
+ b[0] = (u8)(reg >> 16) & 0xff;
+ b[1] = (u8)(reg >> 8) & 0xff;
+ b[2] = (u8) reg & 0xff;
+ memcpy(&b[3], buf, count);
+
+ if (pro == PRO_DMOD)
+ b[0] |= 0x80;
+
+ ret = i2c_transfer(state->i2c_adap, msg, 1);
+
+ if (ret < 0)
+ return -EIO;
+
+ return 0;
+}
+
+/* write single register */
+static int it913x_wr_reg(struct it913x_state *state,
+ u8 pro, u32 reg, u32 data)
+{
+ int ret;
+ u8 b[4];
+ u8 s;
+
+ b[0] = data >> 24;
+ b[1] = (data >> 16) & 0xff;
+ b[2] = (data >> 8) & 0xff;
+ b[3] = data & 0xff;
+ /* expand write as needed */
+ if (data < 0x100)
+ s = 3;
+ else if (data < 0x1000)
+ s = 2;
+ else if (data < 0x100000)
+ s = 1;
+ else
+ s = 0;
+
+ ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s);
+
+ return ret;
+}
+
+static int it913x_script_loader(struct it913x_state *state,
+ struct it913xset *loadscript)
+{
+ int ret, i;
+ if (loadscript == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < 1000; ++i) {
+ if (loadscript[i].pro == 0xff)
+ break;
+ ret = it913x_wr_regs(state, loadscript[i].pro,
+ loadscript[i].address,
+ loadscript[i].reg, loadscript[i].count);
+ if (ret < 0)
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int it913x_init(struct dvb_frontend *fe)
+{
+ struct it913x_state *state = fe->tuner_priv;
+ int ret, i, reg;
+ u8 val, nv_val;
+ u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
+ u8 b[2];
+
+ reg = it913x_rd_reg(state, 0xec86);
+ switch (reg) {
+ case 0:
+ state->tun_clk_mode = reg;
+ state->tun_xtal = 2000;
+ state->tun_fdiv = 3;
+ val = 16;
+ break;
+ case -ENODEV:
+ return -ENODEV;
+ case 1:
+ default:
+ state->tun_clk_mode = reg;
+ state->tun_xtal = 640;
+ state->tun_fdiv = 1;
+ val = 6;
+ break;
+ }
+
+ reg = it913x_rd_reg(state, 0xed03);
+
+ if (reg < 0)
+ return -ENODEV;
+ else if (reg < ARRAY_SIZE(nv))
+ nv_val = nv[reg];
+ else
+ nv_val = 2;
+
+ for (i = 0; i < 50; i++) {
+ ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b));
+ reg = (b[1] << 8) + b[0];
+ if (reg > 0)
+ break;
+ if (ret < 0)
+ return -ENODEV;
+ udelay(2000);
+ }
+ state->tun_fn_min = state->tun_xtal * reg;
+ state->tun_fn_min /= (state->tun_fdiv * nv_val);
+ dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__,
+ state->tun_fn_min);
+
+ if (state->chip_ver > 1)
+ msleep(50);
+ else {
+ for (i = 0; i < 50; i++) {
+ reg = it913x_rd_reg(state, 0xec82);
+ if (reg > 0)
+ break;
+ if (reg < 0)
+ return -ENODEV;
+ udelay(2000);
+ }
+ }
+
+ /* Power Up Tuner - common all versions */
+ ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1);
+ ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0);
+ ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0);
+ ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0);
+
+ return it913x_wr_reg(state, PRO_DMOD, 0xed81, val);
+}
+
+static int it9137_set_params(struct dvb_frontend *fe)
+{
+ struct it913x_state *state = fe->tuner_priv;
+ struct it913xset *set_tuner = set_it9137_template;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 bandwidth = p->bandwidth_hz;
+ u32 frequency_m = p->frequency;
+ int ret, reg;
+ u32 frequency = frequency_m / 1000;
+ u32 freq, temp_f, tmp;
+ u16 iqik_m_cal;
+ u16 n_div;
+ u8 n;
+ u8 l_band;
+ u8 lna_band;
+ u8 bw;
+
+ if (state->firmware_ver == 1)
+ set_tuner = set_it9135_template;
+ else
+ set_tuner = set_it9137_template;
+
+ dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n",
+ __func__, frequency, bandwidth);
+
+ if (frequency >= 51000 && frequency <= 440000) {
+ l_band = 0;
+ lna_band = 0;
+ } else if (frequency > 440000 && frequency <= 484000) {
+ l_band = 1;
+ lna_band = 1;
+ } else if (frequency > 484000 && frequency <= 533000) {
+ l_band = 1;
+ lna_band = 2;
+ } else if (frequency > 533000 && frequency <= 587000) {
+ l_band = 1;
+ lna_band = 3;
+ } else if (frequency > 587000 && frequency <= 645000) {
+ l_band = 1;
+ lna_band = 4;
+ } else if (frequency > 645000 && frequency <= 710000) {
+ l_band = 1;
+ lna_band = 5;
+ } else if (frequency > 710000 && frequency <= 782000) {
+ l_band = 1;
+ lna_band = 6;
+ } else if (frequency > 782000 && frequency <= 860000) {
+ l_band = 1;
+ lna_band = 7;
+ } else if (frequency > 1450000 && frequency <= 1492000) {
+ l_band = 1;
+ lna_band = 0;
+ } else if (frequency > 1660000 && frequency <= 1685000) {
+ l_band = 1;
+ lna_band = 1;
+ } else
+ return -EINVAL;
+ set_tuner[0].reg[0] = lna_band;
+
+ switch (bandwidth) {
+ case 5000000:
+ bw = 0;
+ break;
+ case 6000000:
+ bw = 2;
+ break;
+ case 7000000:
+ bw = 4;
+ break;
+ default:
+ case 8000000:
+ bw = 6;
+ break;
+ }
+
+ set_tuner[1].reg[0] = bw;
+ set_tuner[2].reg[0] = 0xa0 | (l_band << 3);
+
+ if (frequency > 53000 && frequency <= 74000) {
+ n_div = 48;
+ n = 0;
+ } else if (frequency > 74000 && frequency <= 111000) {
+ n_div = 32;
+ n = 1;
+ } else if (frequency > 111000 && frequency <= 148000) {
+ n_div = 24;
+ n = 2;
+ } else if (frequency > 148000 && frequency <= 222000) {
+ n_div = 16;
+ n = 3;
+ } else if (frequency > 222000 && frequency <= 296000) {
+ n_div = 12;
+ n = 4;
+ } else if (frequency > 296000 && frequency <= 445000) {
+ n_div = 8;
+ n = 5;
+ } else if (frequency > 445000 && frequency <= state->tun_fn_min) {
+ n_div = 6;
+ n = 6;
+ } else if (frequency > state->tun_fn_min && frequency <= 950000) {
+ n_div = 4;
+ n = 7;
+ } else if (frequency > 1450000 && frequency <= 1680000) {
+ n_div = 2;
+ n = 0;
+ } else
+ return -EINVAL;
+
+ reg = it913x_rd_reg(state, 0xed81);
+ iqik_m_cal = (u16)reg * n_div;
+
+ if (reg < 0x20) {
+ if (state->tun_clk_mode == 0)
+ iqik_m_cal = (iqik_m_cal * 9) >> 5;
+ else
+ iqik_m_cal >>= 1;
+ } else {
+ iqik_m_cal = 0x40 - iqik_m_cal;
+ if (state->tun_clk_mode == 0)
+ iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
+ else
+ iqik_m_cal = ~(iqik_m_cal >> 1);
+ }
+
+ temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv;
+ freq = temp_f / state->tun_xtal;
+ tmp = freq * state->tun_xtal;
+
+ if ((temp_f - tmp) >= (state->tun_xtal >> 1))
+ freq++;
+
+ freq += (u32) n << 13;
+ /* Frequency OMEGA_IQIK_M_CAL_MID*/
+ temp_f = freq + (u32)iqik_m_cal;
+
+ set_tuner[3].reg[0] = temp_f & 0xff;
+ set_tuner[4].reg[0] = (temp_f >> 8) & 0xff;
+
+ dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n",
+ __func__, temp_f);
+
+ /* Lower frequency */
+ set_tuner[5].reg[0] = freq & 0xff;
+ set_tuner[6].reg[0] = (freq >> 8) & 0xff;
+
+ dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n",
+ __func__, freq);
+
+ ret = it913x_script_loader(state, set_tuner);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Power sequence */
+/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */
+/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */
+
+static int it913x_sleep(struct dvb_frontend *fe)
+{
+ struct it913x_state *state = fe->tuner_priv;
+ return it913x_script_loader(state, it9137_tuner_off);
+}
+
+static int it913x_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ return 0;
+}
+
+static const struct dvb_tuner_ops it913x_tuner_ops = {
+ .info = {
+ .name = "ITE Tech IT913X",
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ },
+
+ .release = it913x_release,
+
+ .init = it913x_init,
+ .sleep = it913x_sleep,
+ .set_params = it9137_set_params,
+};
+
+struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config)
+{
+ struct it913x_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->i2c_adap = i2c_adap;
+ state->i2c_addr = i2c_addr;
+
+ switch (config) {
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ state->chip_ver = 0x01;
+ break;
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ state->chip_ver = 0x02;
+ break;
+ default:
+ dev_dbg(&i2c_adap->dev,
+ "%s: invalid config=%02x\n", __func__, config);
+ goto error;
+ }
+
+ state->tuner_type = config;
+ state->firmware_ver = 1;
+
+ fe->tuner_priv = state;
+ memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ dev_info(&i2c_adap->dev,
+ "%s: ITE Tech IT913X successfully attached\n",
+ KBUILD_MODNAME);
+ dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n",
+ __func__, config, state->chip_ver);
+
+ return fe;
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(it913x_attach);
+
+MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/tuner_it913x.h
new file mode 100644
index 000000000000..12dd36bd9e79
--- /dev/null
+++ b/drivers/media/tuners/tuner_it913x.h
@@ -0,0 +1,45 @@
+/*
+ * ITE Tech IT9137 silicon tuner driver
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9137 Copyright (C) ITE Tech Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef IT913X_H
+#define IT913X_H
+
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_MEDIA_TUNER_IT913X) || \
+ (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE))
+extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ u8 config);
+#else
+static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ u8 config)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h
new file mode 100644
index 000000000000..ce652108aa5d
--- /dev/null
+++ b/drivers/media/tuners/tuner_it913x_priv.h
@@ -0,0 +1,78 @@
+/*
+ * ITE Tech IT9137 silicon tuner driver
+ *
+ * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
+ * IT9137 Copyright (C) ITE Tech Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef IT913X_PRIV_H
+#define IT913X_PRIV_H
+
+#include "tuner_it913x.h"
+#include "af9033.h"
+
+#define PRO_LINK 0x0
+#define PRO_DMOD 0x1
+#define TRIGGER_OFSM 0x0000
+
+struct it913xset { u32 pro;
+ u32 address;
+ u8 reg[15];
+ u8 count;
+};
+
+/* Tuner setting scripts (still keeping it9137) */
+static struct it913xset it9137_tuner_off[] = {
+ {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */
+ {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */
+ {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04},
+ {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}, 0x0c},
+ {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04},
+ {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00}, 0x09},
+ {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00}, 0x0a},
+ {PRO_DMOD, 0xec20, {0x00}, 0x01},
+ {PRO_DMOD, 0xec3f, {0x01}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset set_it9135_template[] = {
+ {PRO_DMOD, 0xee06, {0x00}, 0x01},
+ {PRO_DMOD, 0xec56, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4c, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4d, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4e, {0x00}, 0x01},
+ {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */
+ {PRO_DMOD, 0x011f, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+static struct it913xset set_it9137_template[] = {
+ {PRO_DMOD, 0xee06, {0x00}, 0x01},
+ {PRO_DMOD, 0xec56, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4c, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4d, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4e, {0x00}, 0x01},
+ {PRO_DMOD, 0xec4f, {0x00}, 0x01},
+ {PRO_DMOD, 0xec50, {0x00}, 0x01},
+ {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */
+};
+
+#endif
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index d6be1b613c52..5cd09a681b6a 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -422,13 +422,19 @@ static int xc_initialize(struct xc5000_priv *priv)
}
static int xc_SetTVStandard(struct xc5000_priv *priv,
- u16 VideoMode, u16 AudioMode)
+ u16 VideoMode, u16 AudioMode, u8 RadioMode)
{
int ret;
dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
- dprintk(1, "%s() Standard = %s\n",
- __func__,
- XC5000_Standard[priv->video_standard].Name);
+ if (RadioMode) {
+ dprintk(1, "%s() Standard = %s\n",
+ __func__,
+ XC5000_Standard[RadioMode].Name);
+ } else {
+ dprintk(1, "%s() Standard = %s\n",
+ __func__,
+ XC5000_Standard[priv->video_standard].Name);
+ }
ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
if (ret == XC_RESULT_SUCCESS)
@@ -824,7 +830,7 @@ static int xc5000_set_params(struct dvb_frontend *fe)
ret = xc_SetTVStandard(priv,
XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode);
+ XC5000_Standard[priv->video_standard].AudioMode, 0);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
return -EREMOTEIO;
@@ -940,7 +946,7 @@ tune_channel:
ret = xc_SetTVStandard(priv,
XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode);
+ XC5000_Standard[priv->video_standard].AudioMode, 0);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
return -EREMOTEIO;
@@ -1003,7 +1009,7 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
priv->rf_mode = XC_RF_MODE_AIR;
ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
- XC5000_Standard[radio_input].AudioMode);
+ XC5000_Standard[radio_input].AudioMode, radio_input);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h
index b1a547494625..7245cae19f0c 100644
--- a/drivers/media/tuners/xc5000.h
+++ b/drivers/media/tuners/xc5000.h
@@ -22,6 +22,7 @@
#ifndef __XC5000_H__
#define __XC5000_H__
+#include <linux/kconfig.h>
#include <linux/firmware.h>
struct dvb_frontend;
@@ -56,8 +57,7 @@ struct xc5000_config {
* it's passed back to a bridge during tuner_callback().
*/
-#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
- (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC5000)
extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct xc5000_config *cfg);
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 1e6f40ef1c6b..bd9d19a73efd 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -125,6 +125,26 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
return status;
}
+static void au0828_usb_release(struct au0828_dev *dev)
+{
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ kfree(dev);
+}
+
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
+{
+ struct au0828_dev *dev =
+ container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ au0828_usb_release(dev);
+}
+#endif
+
static void au0828_usb_disconnect(struct usb_interface *interface)
{
struct au0828_dev *dev = usb_get_intfdata(interface);
@@ -134,26 +154,19 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
/* Digital TV */
au0828_dvb_unregister(dev);
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED)
- au0828_analog_unregister(dev);
-#endif
-
- /* I2C */
- au0828_i2c_unregister(dev);
-
-#ifdef CONFIG_VIDEO_AU0828_V4L2
- v4l2_device_unregister(&dev->v4l2_dev);
-#endif
-
usb_set_intfdata(interface, NULL);
-
mutex_lock(&dev->mutex);
dev->usbdev = NULL;
mutex_unlock(&dev->mutex);
-
- kfree(dev);
-
+#ifdef CONFIG_VIDEO_AU0828_V4L2
+ if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
+ au0828_analog_unregister(dev);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_put(&dev->v4l2_dev);
+ return;
+ }
+#endif
+ au0828_usb_release(dev);
}
static int au0828_usb_probe(struct usb_interface *interface,
@@ -202,15 +215,27 @@ static int au0828_usb_probe(struct usb_interface *interface,
dev->boardnr = id->driver_info;
#ifdef CONFIG_VIDEO_AU0828_V4L2
+ dev->v4l2_dev.release = au0828_usb_v4l2_release;
+
/* Create the v4l2_device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
- printk(KERN_ERR "%s() v4l2_device_register failed\n",
+ pr_err("%s() v4l2_device_register failed\n",
+ __func__);
+ mutex_unlock(&dev->lock);
+ kfree(dev);
+ return retval;
+ }
+ /* This control handler will inherit the controls from au8522 */
+ retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
+ if (retval) {
+ pr_err("%s() v4l2_ctrl_handler_init failed\n",
__func__);
mutex_unlock(&dev->lock);
kfree(dev);
- return -EIO;
+ return retval;
}
+ dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
#endif
/* Power Up the bridge */
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 8b9e8268e911..75ac9947cdac 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -35,6 +35,7 @@
#include <linux/suspend.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
#include <media/tuner.h>
#include "au0828.h"
@@ -58,6 +59,12 @@ do {\
} \
} while (0)
+static inline void i2c_gate_ctrl(struct au0828_dev *dev, int val)
+{
+ if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+ dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, val);
+}
+
static inline void print_err_status(struct au0828_dev *dev,
int packet, int status)
{
@@ -988,20 +995,22 @@ static int au0828_v4l2_open(struct file *filp)
fh->type = type;
fh->dev = dev;
+ v4l2_fh_init(&fh->fh, vdev);
filp->private_data = fh;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (mutex_lock_interruptible(&dev->lock)) {
+ kfree(fh);
+ return -ERESTARTSYS;
+ }
+ if (dev->users == 0) {
/* set au0828 interface0 to AS5 here again */
ret = usb_set_interface(dev->usbdev, 0, 5);
if (ret < 0) {
+ mutex_unlock(&dev->lock);
printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
+ kfree(fh);
return -EBUSY;
}
- dev->width = NTSC_STD_W;
- dev->height = NTSC_STD_H;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->width * dev->height;
- dev->bytesperline = dev->width * 2;
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
@@ -1014,6 +1023,7 @@ static int au0828_v4l2_open(struct file *filp)
}
dev->users++;
+ mutex_unlock(&dev->lock);
videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
NULL, &dev->slock,
@@ -1023,14 +1033,13 @@ static int au0828_v4l2_open(struct file *filp)
&dev->lock);
/* VBI Setup */
- dev->vbi_width = 720;
- dev->vbi_height = 1;
videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct au0828_buffer), fh,
&dev->lock);
+ v4l2_fh_add(&fh->fh);
return ret;
}
@@ -1040,6 +1049,9 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
+ mutex_lock(&dev->lock);
if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
/* Cancel timeout thread in case they didn't call streamoff */
dev->vid_timeout_running = 0;
@@ -1058,19 +1070,14 @@ static int au0828_v4l2_close(struct file *filp)
res_free(fh, AU0828_RESOURCE_VBI);
}
- if (dev->users == 1) {
- if (dev->dev_state & DEV_DISCONNECTED) {
- au0828_analog_unregister(dev);
- kfree(dev);
- return 0;
- }
-
+ if (dev->users == 1 && video_is_registered(video_devdata(filp))) {
au0828_analog_stream_disable(dev);
au0828_uninit_isoc(dev);
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ dev->std_set_in_tuner_core = 0;
/* When close the device, set the usb intf0 into alt0 to free
USB bandwidth */
@@ -1078,6 +1085,7 @@ static int au0828_v4l2_close(struct file *filp)
if (ret < 0)
printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
}
+ mutex_unlock(&dev->lock);
videobuf_mmap_free(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vbiq);
@@ -1087,6 +1095,26 @@ static int au0828_v4l2_close(struct file *filp)
return 0;
}
+/* Must be called with dev->lock held */
+static void au0828_init_tuner(struct au0828_dev *dev)
+{
+ struct v4l2_frequency f = {
+ .frequency = dev->ctrl_freq,
+ .type = V4L2_TUNER_ANALOG_TV,
+ };
+
+ if (dev->std_set_in_tuner_core)
+ return;
+ dev->std_set_in_tuner_core = 1;
+ i2c_gate_ctrl(dev, 1);
+ /* If we've never sent the standard in tuner core, do so now.
+ We don't do this at device probe because we don't want to
+ incur the cost of a firmware load */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ i2c_gate_ctrl(dev, 0);
+}
+
static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
@@ -1098,6 +1126,11 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
if (rc < 0)
return rc;
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
+
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(dev, AU0828_RESOURCE_VIDEO))
return -EBUSY;
@@ -1128,23 +1161,32 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
{
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
- int rc;
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int res;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
+ if (check_dev(dev) < 0)
+ return POLLERR;
+
+ res = v4l2_ctrl_poll(filp, wait);
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ au0828_init_tuner(dev);
+ mutex_unlock(&dev->lock);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VIDEO))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (!res_get(fh, AU0828_RESOURCE_VBI))
return POLLERR;
- return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- } else {
- return POLLERR;
+ return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
}
+ return POLLERR;
}
static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -1172,9 +1214,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
int width = format->fmt.pix.width;
int height = format->fmt.pix.height;
- if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
/* If they are demanding a format other than the one we support,
bail out (tvtime asks for UYVY and then retries with YUYV) */
if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
@@ -1193,6 +1232,7 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
format->fmt.pix.sizeimage = width * height * 2;
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
format->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ format->fmt.pix.priv = 0;
if (cmd == VIDIOC_TRY_FMT)
return 0;
@@ -1226,35 +1266,28 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct au0828_fh *fh = priv;
+ struct video_device *vdev = video_devdata(file);
+ struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
strlcpy(cap->card, dev->board.name, sizeof(cap->card));
- strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+ usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
- /*set the device capabilities */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO |
+ /* set the device capabilities */
+ cap->device_caps = V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
return 0;
}
@@ -1286,6 +1319,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = dev->frame_size;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1320,24 +1354,34 @@ out:
return rc;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+ dev->std = norm;
+
+ au0828_init_tuner(dev);
+
+ i2c_gate_ctrl(dev, 1);
/* FIXME: when we support something other than NTSC, we are going to
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
- dev->std_set_in_tuner_core = 1;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm);
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
+
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ *norm = dev->std;
return 0;
}
@@ -1368,10 +1412,13 @@ static int vidioc_enum_input(struct file *file, void *priv,
input->index = tmp;
strcpy(input->name, inames[AUVI_INPUT(tmp).type]);
if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
- (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE))
+ (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) {
input->type |= V4L2_INPUT_TYPE_TUNER;
- else
+ input->audioset = 1;
+ } else {
input->type |= V4L2_INPUT_TYPE_CAMERA;
+ input->audioset = 2;
+ }
input->std = dev->vdev->tvnorms;
@@ -1386,32 +1433,25 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+static void au0828_s_input(struct au0828_dev *dev, int index)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
int i;
- dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
- index);
- if (index >= AU0828_MAX_INPUT)
- return -EINVAL;
- if (AUVI_INPUT(index).type == 0)
- return -EINVAL;
- dev->ctrl_input = index;
-
switch (AUVI_INPUT(index).type) {
case AU0828_VMUX_SVIDEO:
dev->input_type = AU0828_VMUX_SVIDEO;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_COMPOSITE:
dev->input_type = AU0828_VMUX_COMPOSITE;
+ dev->ctrl_ainput = 1;
break;
case AU0828_VMUX_TELEVISION:
dev->input_type = AU0828_VMUX_TELEVISION;
+ dev->ctrl_ainput = 0;
break;
default:
- dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n",
+ dprintk(1, "unknown input type set [%d]\n",
AUVI_INPUT(index).type);
break;
}
@@ -1442,55 +1482,60 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
AUVI_INPUT(index).amux, 0, 0);
- return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- unsigned int index = a->index;
+ dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
+ index);
+ if (index >= AU0828_MAX_INPUT)
+ return -EINVAL;
+ if (AUVI_INPUT(index).type == 0)
+ return -EINVAL;
+ dev->ctrl_input = index;
+ au0828_s_input(dev, index);
+ return 0;
+}
+
+static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
+{
if (a->index > 1)
return -EINVAL;
- index = dev->ctrl_ainput;
- if (index == 0)
+ if (a->index == 0)
strcpy(a->name, "Television");
else
strcpy(a->name, "Line in");
a->capability = V4L2_AUDCAP_STEREO;
- a->index = index;
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- if (a->index != dev->ctrl_ainput)
- return -EINVAL;
- return 0;
-}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ a->index = dev->ctrl_ainput;
+ if (a->index == 0)
+ strcpy(a->name, "Television");
+ else
+ strcpy(a->name, "Line in");
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
+ a->capability = V4L2_AUDCAP_STEREO;
return 0;
-
}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+
+ if (a->index != dev->ctrl_ainput)
+ return -EINVAL;
return 0;
}
@@ -1503,12 +1548,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return -EINVAL;
strcpy(t->name, "Auvitek tuner");
+
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ i2c_gate_ctrl(dev, 0);
return 0;
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
@@ -1516,15 +1565,10 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (t->index != 0)
return -EINVAL;
- t->type = V4L2_TUNER_ANALOG_TV;
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
t->afc);
@@ -1539,40 +1583,31 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
- freq->type = V4L2_TUNER_ANALOG_TV;
+ if (freq->tuner != 0)
+ return -EINVAL;
freq->frequency = dev->ctrl_freq;
return 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
+ struct v4l2_frequency new_freq = *freq;
if (freq->tuner != 0)
return -EINVAL;
- if (freq->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
-
- dev->ctrl_freq = freq->frequency;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
-
- if (dev->std_set_in_tuner_core == 0) {
- /* If we've never sent the standard in tuner core, do so now. We
- don't do this at device probe because we don't want to incur
- the cost of a firmware load */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
- dev->vdev->tvnorms);
- dev->std_set_in_tuner_core = 1;
- }
+ au0828_init_tuner(dev);
+ i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
+ /* Get the actual set (and possibly clamped) frequency */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ dev->ctrl_freq = new_freq.frequency;
- if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
- dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+ i2c_gate_ctrl(dev, 0);
au0828_analog_stream_reset(dev);
@@ -1598,6 +1633,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
format->fmt.vbi.count[1] = dev->vbi_height;
format->fmt.vbi.start[0] = 21;
format->fmt.vbi.start[1] = 284;
+ memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
return 0;
}
@@ -1664,6 +1700,7 @@ static int vidioc_streamon(struct file *file, void *priv,
if (unlikely(!res_get(fh, get_ressource(fh))))
return -EBUSY;
+ au0828_init_tuner(dev);
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
au0828_analog_stream_enable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
@@ -1756,7 +1793,7 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct au0828_fh *fh = priv;
struct au0828_dev *dev = fh->dev;
@@ -1773,6 +1810,15 @@ static int vidioc_s_register(struct file *file, void *priv,
}
#endif
+static int vidioc_log_status(struct file *file, void *fh)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ v4l2_ctrl_log_status(file, fh);
+ v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status);
+ return 0;
+}
+
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
@@ -1872,7 +1918,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
@@ -1881,12 +1929,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -1898,6 +1944,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct video_device au0828_video_template = {
@@ -1905,7 +1954,6 @@ static const struct video_device au0828_video_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_NTSC_M,
- .current_norm = V4L2_STD_NTSC_M,
};
/**************************************************************************/
@@ -1972,7 +2020,12 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->field_size = dev->width * dev->height;
dev->frame_size = dev->field_size << 1;
dev->bytesperline = dev->width << 1;
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
dev->ctrl_ainput = 0;
+ dev->ctrl_freq = 960;
+ dev->std = V4L2_STD_NTSC_M;
+ au0828_s_input(dev, 0);
/* allocate and fill v4l2 video struct */
dev->vdev = video_device_alloc();
@@ -1991,14 +2044,16 @@ int au0828_analog_register(struct au0828_dev *dev,
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
- dev->vdev->parent = &dev->usbdev->dev;
+ dev->vdev->v4l2_dev = &dev->v4l2_dev;
dev->vdev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags);
strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
- dev->vbi_dev->parent = &dev->usbdev->dev;
+ dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
dev->vbi_dev->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags);
strcpy(dev->vbi_dev->name, "au0828a vbi");
/* Register the v4l2 device */
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index e579ff69ca4a..ef1f57f22be7 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -28,6 +28,8 @@
#include <linux/videodev2.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
/* DVB */
#include "demux.h"
@@ -118,6 +120,9 @@ enum au0828_dev_state {
};
struct au0828_fh {
+ /* must be the first field of this struct! */
+ struct v4l2_fh fh;
+
struct au0828_dev *dev;
unsigned int resources;
@@ -202,6 +207,7 @@ struct au0828_dev {
#ifdef CONFIG_VIDEO_AU0828_V4L2
/* Analog */
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
#endif
int users;
unsigned int resources; /* resources in use */
@@ -216,6 +222,7 @@ struct au0828_dev {
int vbi_width;
int vbi_height;
u32 vbi_read;
+ v4l2_std_id std;
u32 field_size;
u32 frame_size;
u32 bytesperline;
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 28688dbcb609..f548db8043d4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -34,11 +34,12 @@
#include <linux/vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/cx2341x.h>
+#include <media/tuner.h>
#include <linux/usb.h>
#include "cx231xx.h"
-/*#include "cx23885-ioctl.h"*/
#define CX231xx_FIRM_IMAGE_SIZE 376836
#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -75,9 +76,11 @@
static unsigned int mpegbufs = 8;
module_param(mpegbufs, int, 0644);
MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+
static unsigned int mpeglines = 128;
module_param(mpeglines, int, 0644);
MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+
static unsigned int mpeglinesize = 512;
module_param(mpeglinesize, int, 0644);
MODULE_PARM_DESC(mpeglinesize,
@@ -86,10 +89,10 @@ MODULE_PARM_DESC(mpeglinesize,
static unsigned int v4l_debug = 1;
module_param(v4l_debug, int, 0644);
MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
-struct cx231xx_dmaqueue *dma_qq;
+
#define dprintk(level, fmt, arg...)\
do { if (v4l_debug >= level) \
- printk(KERN_INFO "%s: " fmt, \
+ pr_info("%s: " fmt, \
(dev) ? dev->name : "cx231xx[?]", ## arg); \
} while (0)
@@ -131,11 +134,13 @@ static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
};
/* ------------------------------------------------------------------ */
+
enum cx231xx_capture_type {
CX231xx_MPEG_CAPTURE,
CX231xx_RAW_CAPTURE,
CX231xx_RAW_PASSTHRU_CAPTURE
};
+
enum cx231xx_capture_bits {
CX231xx_RAW_BITS_NONE = 0x00,
CX231xx_RAW_BITS_YUV_CAPTURE = 0x01,
@@ -144,33 +149,40 @@ enum cx231xx_capture_bits {
CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10
};
+
enum cx231xx_capture_end {
CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
CX231xx_END_NOW, /* stop immediately, no irq */
};
+
enum cx231xx_framerate {
CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */
};
+
enum cx231xx_stream_port {
CX231xx_OUTPUT_PORT_MEMORY,
CX231xx_OUTPUT_PORT_STREAMING,
CX231xx_OUTPUT_PORT_SERIAL
};
+
enum cx231xx_data_xfer_status {
CX231xx_MORE_BUFFERS_FOLLOW,
CX231xx_LAST_BUFFER,
};
+
enum cx231xx_picture_mask {
CX231xx_PICTURE_MASK_NONE,
CX231xx_PICTURE_MASK_I_FRAMES,
CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
};
+
enum cx231xx_vbi_mode_bits {
CX231xx_VBI_BITS_SLICED,
CX231xx_VBI_BITS_RAW,
};
+
enum cx231xx_vbi_insertion_bits {
CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
@@ -178,56 +190,69 @@ enum cx231xx_vbi_insertion_bits {
CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
};
+
enum cx231xx_dma_unit {
CX231xx_DMA_BYTES,
CX231xx_DMA_FRAMES,
};
+
enum cx231xx_dma_transfer_status_bits {
CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
};
+
enum cx231xx_pause {
CX231xx_PAUSE_ENCODING,
CX231xx_RESUME_ENCODING,
};
+
enum cx231xx_copyright {
CX231xx_COPYRIGHT_OFF,
CX231xx_COPYRIGHT_ON,
};
+
enum cx231xx_notification_type {
CX231xx_NOTIFICATION_REFRESH,
};
+
enum cx231xx_notification_status {
CX231xx_NOTIFICATION_OFF,
CX231xx_NOTIFICATION_ON,
};
+
enum cx231xx_notification_mailbox {
CX231xx_NOTIFICATION_NO_MAILBOX = -1,
};
+
enum cx231xx_field1_lines {
CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
};
+
enum cx231xx_field2_lines {
CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
};
+
enum cx231xx_custom_data_type {
CX231xx_CUSTOM_EXTENSION_USR_DATA,
CX231xx_CUSTOM_PRIVATE_PACKET,
};
+
enum cx231xx_mute {
CX231xx_UNMUTE,
CX231xx_MUTE,
};
+
enum cx231xx_mute_video_mask {
CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
};
+
enum cx231xx_mute_video_shift {
CX231xx_MUTE_VIDEO_V_SHIFT = 8,
CX231xx_MUTE_VIDEO_U_SHIFT = 16,
@@ -296,41 +321,43 @@ enum cx231xx_mute_video_shift {
#define CX23417_GPIO_MASK 0xFC0003FF
-static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+
+static int set_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 value)
{
int status = 0;
u32 _gpio_direction = 0;
_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
+ _gpio_direction = _gpio_direction | gpio_direction;
status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
(u8 *)&value, 4, 0, 0);
return status;
}
-static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+
+static int get_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 *val_ptr)
{
int status = 0;
u32 _gpio_direction = 0;
_gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
- _gpio_direction = _gpio_direction|gpio_direction;
+ _gpio_direction = _gpio_direction | gpio_direction;
status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
- (u8 *)pValue, 4, 0, 1);
+ (u8 *)val_ptr, 4, 0, 1);
return status;
}
-static int waitForMciComplete(struct cx231xx *dev)
+static int wait_for_mci_complete(struct cx231xx *dev)
{
u32 gpio;
- u32 gpio_driection = 0;
+ u32 gpio_direction = 0;
u8 count = 0;
- getITVCReg(dev, gpio_driection, &gpio);
+ get_itvc_reg(dev, gpio_direction, &gpio);
while (!(gpio&0x020000)) {
msleep(10);
- getITVCReg(dev, gpio_driection, &gpio);
+ get_itvc_reg(dev, gpio_direction, &gpio);
if (count++ > 100) {
dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
@@ -345,57 +372,57 @@ static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
u32 temp;
int status = 0;
- temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
- status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE0 | ((value & 0x000000FF) << 8);
+ temp = temp << 10;
+ status = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (status < 0)
return status;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 1;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 2;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 3;*/
- temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 0;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x000000FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1;*/
- temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0x0000FF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*Write that the mode is write.*/
temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
- return waitForMciComplete(dev);
+ return wait_for_mci_complete(dev);
}
static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
@@ -407,70 +434,68 @@ static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1;*/
temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write that the mode is read;*/
temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*wait for the MIRDY line to be asserted ,
signalling that the read is done;*/
- ret = waitForMciComplete(dev);
+ ret = wait_for_mci_complete(dev);
/*switch the DATA- GPIO to input mode;*/
/*Read data byte 0;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/* Read data byte 1;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 2;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) >> 2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 3;*/
temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
return_value |= ((temp & 0x03FC0000) << 6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
*value = return_value;
-
-
return ret;
}
@@ -481,59 +506,59 @@ static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
u32 temp;
int ret = 0;
- temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
temp = temp << 10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (ret < 0)
return ret;
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 1;*/
temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
temp = temp << 10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp | ((0x05) << 10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*wait for MIRDY line;*/
- waitForMciComplete(dev);
+ wait_for_mci_complete(dev);
return 0;
}
@@ -545,68 +570,68 @@ static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
int ret = 0;
/*write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
- ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
+ ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
if (ret < 0)
return ret;
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 1*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*write address byte 0*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
- temp = temp<<10;
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
- temp = temp|((0x05)<<10);
- setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | (0x05 << 10);
+ set_itvc_reg(dev, ITVC_WRITE_DIR, temp);
/*Wait for MIRDY line*/
- ret = waitForMciComplete(dev);
+ ret = wait_for_mci_complete(dev);
/*Read data byte 3;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)<<6);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE3) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE3) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) << 6);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 2;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>2);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE2) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE2) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 2);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/* Read data byte 1;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>10);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE1) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE1) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
/*Read data byte 0;*/
- temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
- setITVCReg(dev, ITVC_READ_DIR, temp);
- temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
- setITVCReg(dev, ITVC_READ_DIR, temp);
- getITVCReg(dev, ITVC_READ_DIR, &temp);
- return_value |= ((temp&0x03FC0000)>>18);
- setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+ temp = (0x82 | MCI_MEMORY_DATA_BYTE0) << 10;
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_MEMORY_DATA_BYTE0) << 10);
+ set_itvc_reg(dev, ITVC_READ_DIR, temp);
+ get_itvc_reg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 18);
+ set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10));
*value = return_value;
return ret;
@@ -619,94 +644,91 @@ static char *cmd_to_str(int cmd)
{
switch (cmd) {
case CX2341X_ENC_PING_FW:
- return "PING_FW";
+ return "PING_FW";
case CX2341X_ENC_START_CAPTURE:
- return "START_CAPTURE";
+ return "START_CAPTURE";
case CX2341X_ENC_STOP_CAPTURE:
- return "STOP_CAPTURE";
+ return "STOP_CAPTURE";
case CX2341X_ENC_SET_AUDIO_ID:
- return "SET_AUDIO_ID";
+ return "SET_AUDIO_ID";
case CX2341X_ENC_SET_VIDEO_ID:
- return "SET_VIDEO_ID";
+ return "SET_VIDEO_ID";
case CX2341X_ENC_SET_PCR_ID:
- return "SET_PCR_PID";
+ return "SET_PCR_PID";
case CX2341X_ENC_SET_FRAME_RATE:
- return "SET_FRAME_RATE";
+ return "SET_FRAME_RATE";
case CX2341X_ENC_SET_FRAME_SIZE:
- return "SET_FRAME_SIZE";
+ return "SET_FRAME_SIZE";
case CX2341X_ENC_SET_BIT_RATE:
- return "SET_BIT_RATE";
+ return "SET_BIT_RATE";
case CX2341X_ENC_SET_GOP_PROPERTIES:
- return "SET_GOP_PROPERTIES";
+ return "SET_GOP_PROPERTIES";
case CX2341X_ENC_SET_ASPECT_RATIO:
- return "SET_ASPECT_RATIO";
+ return "SET_ASPECT_RATIO";
case CX2341X_ENC_SET_DNR_FILTER_MODE:
- return "SET_DNR_FILTER_PROPS";
+ return "SET_DNR_FILTER_PROPS";
case CX2341X_ENC_SET_DNR_FILTER_PROPS:
- return "SET_DNR_FILTER_PROPS";
+ return "SET_DNR_FILTER_PROPS";
case CX2341X_ENC_SET_CORING_LEVELS:
- return "SET_CORING_LEVELS";
+ return "SET_CORING_LEVELS";
case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
- return "SET_SPATIAL_FILTER_TYPE";
+ return "SET_SPATIAL_FILTER_TYPE";
case CX2341X_ENC_SET_VBI_LINE:
- return "SET_VBI_LINE";
+ return "SET_VBI_LINE";
case CX2341X_ENC_SET_STREAM_TYPE:
- return "SET_STREAM_TYPE";
+ return "SET_STREAM_TYPE";
case CX2341X_ENC_SET_OUTPUT_PORT:
- return "SET_OUTPUT_PORT";
+ return "SET_OUTPUT_PORT";
case CX2341X_ENC_SET_AUDIO_PROPERTIES:
- return "SET_AUDIO_PROPERTIES";
+ return "SET_AUDIO_PROPERTIES";
case CX2341X_ENC_HALT_FW:
- return "HALT_FW";
+ return "HALT_FW";
case CX2341X_ENC_GET_VERSION:
- return "GET_VERSION";
+ return "GET_VERSION";
case CX2341X_ENC_SET_GOP_CLOSURE:
- return "SET_GOP_CLOSURE";
+ return "SET_GOP_CLOSURE";
case CX2341X_ENC_GET_SEQ_END:
- return "GET_SEQ_END";
+ return "GET_SEQ_END";
case CX2341X_ENC_SET_PGM_INDEX_INFO:
- return "SET_PGM_INDEX_INFO";
+ return "SET_PGM_INDEX_INFO";
case CX2341X_ENC_SET_VBI_CONFIG:
- return "SET_VBI_CONFIG";
+ return "SET_VBI_CONFIG";
case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
- return "SET_DMA_BLOCK_SIZE";
+ return "SET_DMA_BLOCK_SIZE";
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
- return "GET_PREV_DMA_INFO_MB_10";
+ return "GET_PREV_DMA_INFO_MB_10";
case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
- return "GET_PREV_DMA_INFO_MB_9";
+ return "GET_PREV_DMA_INFO_MB_9";
case CX2341X_ENC_SCHED_DMA_TO_HOST:
- return "SCHED_DMA_TO_HOST";
+ return "SCHED_DMA_TO_HOST";
case CX2341X_ENC_INITIALIZE_INPUT:
- return "INITIALIZE_INPUT";
+ return "INITIALIZE_INPUT";
case CX2341X_ENC_SET_FRAME_DROP_RATE:
- return "SET_FRAME_DROP_RATE";
+ return "SET_FRAME_DROP_RATE";
case CX2341X_ENC_PAUSE_ENCODER:
- return "PAUSE_ENCODER";
+ return "PAUSE_ENCODER";
case CX2341X_ENC_REFRESH_INPUT:
- return "REFRESH_INPUT";
+ return "REFRESH_INPUT";
case CX2341X_ENC_SET_COPYRIGHT:
- return "SET_COPYRIGHT";
+ return "SET_COPYRIGHT";
case CX2341X_ENC_SET_EVENT_NOTIFICATION:
- return "SET_EVENT_NOTIFICATION";
+ return "SET_EVENT_NOTIFICATION";
case CX2341X_ENC_SET_NUM_VSYNC_LINES:
- return "SET_NUM_VSYNC_LINES";
+ return "SET_NUM_VSYNC_LINES";
case CX2341X_ENC_SET_PLACEHOLDER:
- return "SET_PLACEHOLDER";
+ return "SET_PLACEHOLDER";
case CX2341X_ENC_MUTE_VIDEO:
- return "MUTE_VIDEO";
+ return "MUTE_VIDEO";
case CX2341X_ENC_MUTE_AUDIO:
- return "MUTE_AUDIO";
+ return "MUTE_AUDIO";
case CX2341X_ENC_MISC:
- return "MISC";
+ return "MISC";
default:
return "UNKNOWN";
}
}
-static int cx231xx_mbox_func(void *priv,
- u32 command,
- int in,
- int out,
+static int cx231xx_mbox_func(void *priv, u32 command, int in, int out,
u32 data[CX2341X_MBOX_MAX_DATA])
{
struct cx231xx *dev = priv;
@@ -721,11 +743,9 @@ static int cx231xx_mbox_func(void *priv,
without side effects */
mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
if (value != 0x12345678) {
- dprintk(3,
- "Firmware and/or mailbox pointer not initialized "
- "or corrupted, signature = 0x%x, cmd = %s\n", value,
- cmd_to_str(command));
- return -1;
+ dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n",
+ value, cmd_to_str(command));
+ return -EIO;
}
/* This read looks at 32 bits, but flag is only 8 bits.
@@ -733,9 +753,9 @@ static int cx231xx_mbox_func(void *priv,
*/
mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
if (flag) {
- dprintk(3, "ERROR: Mailbox appears to be in use "
- "(%x), cmd = %s\n", flag, cmd_to_str(command));
- return -1;
+ dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n",
+ flag, cmd_to_str(command));
+ return -EBUSY;
}
flag |= 1; /* tell 'em we're working on it */
@@ -764,7 +784,7 @@ static int cx231xx_mbox_func(void *priv,
break;
if (time_after(jiffies, timeout)) {
dprintk(3, "ERROR: API Mailbox timeout\n");
- return -1;
+ return -EIO;
}
udelay(10);
}
@@ -781,17 +801,14 @@ static int cx231xx_mbox_func(void *priv,
flag = 0;
mc417_memory_write(dev, dev->cx23417_mailbox, flag);
- return retval;
+ return 0;
}
/* We don't need to call the API often, so using just one
* mailbox will probably suffice
*/
-static int cx231xx_api_cmd(struct cx231xx *dev,
- u32 command,
- u32 inputcnt,
- u32 outputcnt,
- ...)
+static int cx231xx_api_cmd(struct cx231xx *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
{
u32 data[CX2341X_MBOX_MAX_DATA];
va_list vargs;
@@ -813,6 +830,7 @@ static int cx231xx_api_cmd(struct cx231xx *dev,
return err;
}
+
static int cx231xx_find_mailbox(struct cx231xx *dev)
{
u32 signature[4] = {
@@ -834,81 +852,80 @@ static int cx231xx_find_mailbox(struct cx231xx *dev)
else
signaturecnt = 0;
if (4 == signaturecnt) {
- dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
- return i+1;
+ dprintk(1, "Mailbox signature found at 0x%x\n", i + 1);
+ return i + 1;
}
}
dprintk(3, "Mailbox signature values not found!\n");
return -1;
}
-static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value,
u32 *p_fw_image)
{
-
u32 temp = 0;
int i = 0;
- temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 1;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 2;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/*write data byte 3;*/
- temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 2;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
- ((address & 0x003F0000)>>8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000) >> 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 1;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
/* write address byte 0;*/
- temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
- temp = temp<<10;
+ temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
*p_fw_image = temp;
p_fw_image++;
- temp = temp|((0x05)<<10);
+ temp = temp | (0x05 << 10);
*p_fw_image = temp;
p_fw_image++;
@@ -971,8 +988,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
IVTV_REG_APU, 0);
if (retval != 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
- __func__);
+ pr_err("%s: Error with mc417_register_write\n", __func__);
return -1;
}
@@ -980,25 +996,21 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
&dev->udev->dev);
if (retval != 0) {
- printk(KERN_ERR
- "ERROR: Hotplug firmware request failed (%s).\n",
+ pr_err("ERROR: Hotplug firmware request failed (%s).\n",
CX231xx_FIRM_IMAGE_NAME);
- printk(KERN_ERR "Please fix your hotplug setup, the board will "
- "not work without firmware loaded!\n");
+ pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
return -1;
}
if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
- printk(KERN_ERR "ERROR: Firmware size mismatch "
- "(have %zd, expected %d)\n",
+ pr_err("ERROR: Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, CX231xx_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
if (0 != memcmp(firmware->data, magic, 8)) {
- printk(KERN_ERR
- "ERROR: Firmware magic mismatch, wrong file?\n");
+ pr_err("ERROR: Firmware magic mismatch, wrong file?\n");
release_firmware(firmware);
return -1;
}
@@ -1013,7 +1025,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
transfer_size += 4) {
fw_data = *p_fw_data;
- mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+ mci_write_memory_to_gpio(dev, address, fw_data, p_current_fw);
address = address + 1;
p_current_fw += 20;
p_fw_data += 1;
@@ -1045,7 +1057,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
IVTV_CMD_HW_BLOCKS_RST);
if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ pr_err("%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1057,7 +1069,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
if (retval < 0) {
- printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ pr_err("%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1082,10 +1094,10 @@ static void cx231xx_codec_settings(struct cx231xx *dev)
cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
dev->ts1.height, dev->ts1.width);
- dev->mpeg_params.width = dev->ts1.width;
- dev->mpeg_params.height = dev->ts1.height;
+ dev->mpeg_ctrl_handler.width = dev->ts1.width;
+ dev->mpeg_ctrl_handler.height = dev->ts1.height;
- cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+ cx2341x_handler_setup(&dev->mpeg_ctrl_handler);
cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1105,27 +1117,25 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
dprintk(2, "%s() PING OK\n", __func__);
retval = cx231xx_load_firmware(dev);
if (retval < 0) {
- printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ pr_err("%s() f/w load failed\n", __func__);
return retval;
}
retval = cx231xx_find_mailbox(dev);
if (retval < 0) {
- printk(KERN_ERR "%s() mailbox < 0, error\n",
+ pr_err("%s() mailbox < 0, error\n",
__func__);
return -1;
}
dev->cx23417_mailbox = retval;
retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
if (retval < 0) {
- printk(KERN_ERR
- "ERROR: cx23417 firmware ping failed!\n");
+ pr_err("ERROR: cx23417 firmware ping failed!\n");
return -1;
}
retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
&version);
if (retval < 0) {
- printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
- "version failed!\n");
+ pr_err("ERROR: cx23417 firmware get encoder: version failed!\n");
return -1;
}
dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
@@ -1134,7 +1144,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
for (i = 0; i < 1; i++) {
retval = mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+ dprintk(3, "***before enable656() VIM Capture Lines = %d ***\n",
val);
if (retval < 0)
return retval;
@@ -1202,7 +1212,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
for (i = 0; i < 1; i++) {
mc417_register_read(dev, 0x20f8, &val);
- dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+ dprintk(3, "***VIM Capture Lines =%d ***\n", val);
}
return 0;
@@ -1223,6 +1233,7 @@ static int bb_buf_setup(struct videobuf_queue *q,
return 0;
}
+
static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
{
struct cx231xx_fh *fh = vq->priv_data;
@@ -1249,91 +1260,85 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
struct cx231xx_dmaqueue *dma_q)
{
- void *vbuf;
- struct cx231xx_buffer *buf;
- u32 tail_data = 0;
- char *p_data;
-
- if (dma_q->mpeg_buffer_done == 0) {
- if (list_empty(&dma_q->active))
- return;
-
- buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
- dev->video_mode.isoc_ctl.buf = buf;
- dma_q->mpeg_buffer_done = 1;
- }
- /* Fill buffer */
- buf = dev->video_mode.isoc_ctl.buf;
- vbuf = videobuf_to_vmalloc(&buf->vb);
-
- if ((dma_q->mpeg_buffer_completed+len) <
- mpeglines*mpeglinesize) {
- if (dma_q->add_ps_package_head ==
- CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- dma_q->ps_head, 3);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + 3;
- dma_q->add_ps_package_head =
- CX231XX_NONEED_PS_PACKAGE_HEAD;
- }
- memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
- dma_q->mpeg_buffer_completed =
- dma_q->mpeg_buffer_completed + len;
- } else {
- dma_q->mpeg_buffer_done = 0;
-
- tail_data =
- mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
- memcpy(vbuf+dma_q->mpeg_buffer_completed,
- data, tail_data);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- dma_q->mpeg_buffer_completed = 0;
-
- if (len - tail_data > 0) {
- p_data = data + tail_data;
- dma_q->left_data_count = len - tail_data;
- memcpy(dma_q->p_left_data,
- p_data, len - tail_data);
- }
-
- }
-
- return;
-}
-
-static void buffer_filled(char *data, int len, struct urb *urb,
- struct cx231xx_dmaqueue *dma_q)
-{
- void *vbuf;
- struct cx231xx_buffer *buf;
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+ u32 tail_data = 0;
+ char *p_data;
+ if (dma_q->mpeg_buffer_done == 0) {
if (list_empty(&dma_q->active))
return;
-
buf = list_entry(dma_q->active.next,
- struct cx231xx_buffer, vb.queue);
+ struct cx231xx_buffer, vb.queue);
+ dev->video_mode.isoc_ctl.buf = buf;
+ dma_q->mpeg_buffer_done = 1;
+ }
+ /* Fill buffer */
+ buf = dev->video_mode.isoc_ctl.buf;
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+
+ if ((dma_q->mpeg_buffer_completed+len) <
+ mpeglines*mpeglinesize) {
+ if (dma_q->add_ps_package_head ==
+ CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ dma_q->ps_head, 3);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + 3;
+ dma_q->add_ps_package_head =
+ CX231XX_NONEED_PS_PACKAGE_HEAD;
+ }
+ memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + len;
+ } else {
+ dma_q->mpeg_buffer_done = 0;
+ tail_data =
+ mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ data, tail_data);
- /* Fill buffer */
- vbuf = videobuf_to_vmalloc(&buf->vb);
- memcpy(vbuf, data, len);
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
v4l2_get_timestamp(&buf->vb.ts);
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
+ dma_q->mpeg_buffer_completed = 0;
- return;
+ if (len - tail_data > 0) {
+ p_data = data + tail_data;
+ dma_q->left_data_count = len - tail_data;
+ memcpy(dma_q->p_left_data,
+ p_data, len - tail_data);
+ }
+ }
}
-static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+
+ if (list_empty(&dma_q->active))
+ return;
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+
+ /* Fill buffer */
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+ memcpy(vbuf, data, len);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ v4l2_get_timestamp(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+static int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
unsigned char *p_buffer;
@@ -1358,11 +1363,9 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
-static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
-{
- /*char *outp;*/
- /*struct cx231xx_buffer *buf;*/
+static int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
struct cx231xx_dmaqueue *dma_q = urb->context;
unsigned char *p_buffer, *buffer;
u32 buffer_size = 0;
@@ -1393,8 +1396,6 @@ static int bb_buf_prepare(struct videobuf_queue *q,
int rc = 0, urb_init = 0;
int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
- dma_qq = &dev->video_mode.vidq;
-
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
buf->vb.width = fh->dev->ts1.ts_packet_size;
@@ -1482,36 +1483,6 @@ static struct videobuf_queue_ops cx231xx_qops = {
/* ------------------------------------------------------------------ */
-static const u32 *ctrl_classes[] = {
- cx2341x_mpeg_ctrls,
- NULL
-};
-
-static int cx231xx_queryctrl(struct cx231xx *dev,
- struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
-
- /* MPEG V4L2 controls */
- if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
-
- return 0;
-}
-
-static int cx231xx_querymenu(struct cx231xx *dev,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = qmenu->id;
- cx231xx_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
-
static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
{
struct cx231xx_fh *fh = file->private_data;
@@ -1520,14 +1491,15 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
*norm = dev->encodernorm.id;
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
- if (*id & cx231xx_tvnorms[i].id)
+ if (id & cx231xx_tvnorms[i].id)
break;
if (i == ARRAY_SIZE(cx231xx_tvnorms))
return -EINVAL;
@@ -1537,12 +1509,12 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
dprintk(3, "encodernorm set to NTSC\n");
dev->norm = V4L2_STD_NTSC;
dev->ts1.height = 480;
- dev->mpeg_params.is_50hz = 0;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
} else {
dprintk(3, "encodernorm set to PAL\n");
dev->norm = V4L2_STD_PAL_B;
dev->ts1.height = 576;
- dev->mpeg_params.is_50hz = 1;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
}
call_all(dev, core, s_std, dev->norm);
/* do mode control overrides */
@@ -1551,161 +1523,23 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
return 0;
}
-static int vidioc_g_audio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-return 0;
-}
-static int vidioc_enumaudio(struct file *file, void *fh,
- struct v4l2_audio *a)
-{
- struct v4l2_audio *vin = a;
-
- int ret = -EINVAL;
-
- if (vin->index > 0)
- return ret;
- strncpy(vin->name, "VideoGrabber Audio", 14);
- vin->capability = V4L2_AUDCAP_STEREO;
-
-
-return 0;
-}
-static const char *iname[] = {
- [CX231XX_VMUX_COMPOSITE1] = "Composite1",
- [CX231XX_VMUX_SVIDEO] = "S-Video",
- [CX231XX_VMUX_TELEVISION] = "Television",
- [CX231XX_VMUX_CABLE] = "Cable TV",
- [CX231XX_VMUX_DVB] = "DVB",
- [CX231XX_VMUX_DEBUG] = "for debug only",
-};
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
- struct cx231xx_input *input;
- int n;
- dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
-
- if (i->index >= 4)
- return -EINVAL;
-
-
- input = &cx231xx_boards[dev->model].input[i->index];
-
- if (input->type == 0)
- return -EINVAL;
-
- /* FIXME
- * strcpy(i->name, input->name); */
-
- n = i->index;
- strcpy(i->name, iname[INPUT(n)->type]);
-
- if (input->type == CX231XX_VMUX_TELEVISION ||
- input->type == CX231XX_VMUX_CABLE)
- i->type = V4L2_INPUT_TYPE_TUNER;
- else
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
-{
- struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
-
- dprintk(3, "enter vidioc_s_input() i=%d\n", i);
-
- mutex_lock(&dev->lock);
-
- video_mux(dev, i);
-
- mutex_unlock(&dev->lock);
-
- if (i >= 4)
- return -EINVAL;
- dev->input = i;
- dprintk(3, "exit vidioc_s_input()\n");
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
-{
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- return 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
-
-
- return 0;
-}
static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctl)
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_s_ctrl()\n");
/* Update the A/V core */
call_all(dev, core, s_ctrl, ctl);
dprintk(3, "exit vidioc_s_ctrl()\n");
return 0;
}
-static struct v4l2_capability pvr_capability = {
- .driver = "cx231xx",
- .card = "VideoGrabber",
- .bus_info = "usb",
- .version = 1,
- .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
-};
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
-
-
-
- memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
- return 0;
-}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
-
if (f->index != 0)
return -EINVAL;
@@ -1720,17 +1554,18 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->ts1.width;
- f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->vidq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
return 0;
}
@@ -1740,25 +1575,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage =
- dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
- f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
return 0;
}
-static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
-
- return 0;
-}
-
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -1795,22 +1625,22 @@ static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type i)
{
struct cx231xx_fh *fh = file->private_data;
-
struct cx231xx *dev = fh->dev;
+
dprintk(3, "enter vidioc_streamon()\n");
- cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
- if (dev->USE_ISO)
- cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
- CX231XX_NUM_BUFS,
- dev->video_mode.max_pkt_size,
- cx231xx_isoc_copy);
- else {
- cx231xx_init_bulk(dev, 320,
- 5,
- dev->ts1_mode.max_pkt_size,
- cx231xx_bulk_copy);
- }
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (dev->USE_ISO)
+ cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else {
+ cx231xx_init_bulk(dev, 320,
+ 5,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
dprintk(3, "exit vidioc_streamon()\n");
return videobuf_streamon(&fh->vidq);
}
@@ -1822,117 +1652,25 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return videobuf_streamoff(&fh->vidq);
}
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_g_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- dprintk(3, "exit vidioc_g_ext_ctrls()\n");
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_s_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- if (err == 0) {
- err = cx2341x_update(dev, cx231xx_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
-
- return err;
-
-
-return 0;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
- dprintk(3, "enter vidioc_try_ext_ctrls()\n");
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
- return err;
-}
-
static int vidioc_log_status(struct file *file, void *priv)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- char name[32 + 2];
- snprintf(name, sizeof(name), "%s/2", dev->name);
- dprintk(3,
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
call_all(dev, core, log_status);
- cx2341x_log_status(&dev->mpeg_params, name);
- dprintk(3,
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_querymenu()\n");
- dprintk(3, "exit vidioc_querymenu()\n");
- return cx231xx_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- dprintk(3, "enter vidioc_queryctrl()\n");
- dprintk(3, "exit vidioc_queryctrl()\n");
- return cx231xx_queryctrl(dev, c);
+ return v4l2_ctrl_log_status(file, priv);
}
static int mpeg_open(struct file *file)
{
- int minor = video_devdata(file)->minor;
- struct cx231xx *h, *dev = NULL;
- /*struct list_head *list;*/
+ struct video_device *vdev = video_devdata(file);
+ struct cx231xx *dev = video_drvdata(file);
struct cx231xx_fh *fh;
- /*u32 value = 0;*/
dprintk(2, "%s()\n", __func__);
- list_for_each_entry(h, &cx231xx_devlist, devlist) {
- if (h->v4l_device->minor == minor)
- dev = h;
- }
-
- if (dev == NULL)
- return -ENODEV;
-
- mutex_lock(&dev->lock);
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
@@ -1942,29 +1680,30 @@ static int mpeg_open(struct file *file)
}
file->private_data = fh;
- fh->dev = dev;
+ v4l2_fh_init(&fh->fh, vdev);
+ fh->dev = dev;
videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
NULL, &dev->video_mode.slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer), fh, NULL);
+ sizeof(struct cx231xx_buffer), fh, &dev->lock);
/*
videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
&dev->udev->dev, &dev->ts1.slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx231xx_buffer),
- fh, NULL);
+ fh, &dev->lock);
*/
-
cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
cx231xx_set_gpio_value(dev, 2, 0);
cx231xx_initialize_codec(dev);
mutex_unlock(&dev->lock);
+ v4l2_fh_add(&fh->fh);
cx231xx_start_TS1(dev);
return 0;
@@ -1977,25 +1716,20 @@ static int mpeg_release(struct file *file)
dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
- if (!dev) {
- dprintk(3, "abort!!!\n");
- return 0;
- }
-
mutex_lock(&dev->lock);
cx231xx_stop_TS1(dev);
- /* do this before setting alternate! */
- if (dev->USE_ISO)
- cx231xx_uninit_isoc(dev);
- else
- cx231xx_uninit_bulk(dev);
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
- cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
- CX231xx_RAW_BITS_NONE);
+ cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_BITS_NONE);
/* FIXME: Review this crap */
/* Shut device down on last close */
@@ -2015,7 +1749,8 @@ static int mpeg_release(struct file *file)
videobuf_read_stop(&fh->vidq);
videobuf_mmap_free(&fh->vidq);
- file->private_data = NULL;
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
mutex_unlock(&dev->lock);
return 0;
@@ -2027,7 +1762,6 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
-
/* Deal w/ A/V decoder * and mpeg encoder sync issues. */
/* Start mpeg encoder on first read. */
if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
@@ -2044,12 +1778,23 @@ static ssize_t mpeg_read(struct file *file, char __user *data,
static unsigned int mpeg_poll(struct file *file,
struct poll_table_struct *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct cx231xx_fh *fh = file->private_data;
- /*struct cx231xx *dev = fh->dev;*/
+ struct cx231xx *dev = fh->dev;
+ unsigned int res = 0;
+
+ if (v4l2_event_pending(&fh->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(file, &fh->fh.wait, wait);
- /*dprintk(2, "%s\n", __func__);*/
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
- return videobuf_poll_stream(file, &fh->vidq, wait);
+ mutex_lock(&dev->lock);
+ res |= videobuf_poll_stream(file, &fh->vidq, wait);
+ mutex_unlock(&dev->lock);
+ return res;
}
static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
@@ -2069,44 +1814,39 @@ static struct v4l2_file_operations mpeg_fops = {
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_enumaudio = vidioc_enumaudio,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = cx231xx_g_tuner,
+ .vidioc_s_tuner = cx231xx_s_tuner,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_enum_input = cx231xx_enum_input,
+ .vidioc_g_input = cx231xx_g_input,
+ .vidioc_s_input = cx231xx_s_input,
.vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_querycap = vidioc_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
.vidioc_log_status = vidioc_log_status,
- .vidioc_querymenu = vidioc_querymenu,
- .vidioc_queryctrl = vidioc_queryctrl,
-/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
-/* .vidioc_g_register = cx231xx_g_register,*/
-/* .vidioc_s_register = cx231xx_s_register,*/
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_mpeg_template = {
@@ -2114,8 +1854,7 @@ static struct video_device cx231xx_mpeg_template = {
.fops = &mpeg_fops,
.ioctl_ops = &mpeg_ioctl_ops,
.minor = -1,
- .tvnorms = CX231xx_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
+ .tvnorms = V4L2_STD_ALL,
};
void cx231xx_417_unregister(struct cx231xx *dev)
@@ -2128,10 +1867,44 @@ void cx231xx_417_unregister(struct cx231xx *dev)
video_unregister_device(dev->v4l_device);
else
video_device_release(dev->v4l_device);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
dev->v4l_device = NULL;
}
}
+static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
+{
+ struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
+ int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_mbus_framefmt fmt;
+
+ /* fix videodecoder resolution */
+ fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+ fmt.height = cxhdl->height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt);
+ return 0;
+}
+
+static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
+{
+ static const u32 freqs[3] = { 44100, 48000, 32000 };
+ struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler);
+
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < ARRAY_SIZE(freqs))
+ call_all(dev, audio, s_clock_freq, freqs[idx]);
+ return 0;
+}
+
+static struct cx2341x_handler_ops cx231xx_ops = {
+ /* needed for the video clock freq */
+ .s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
+ /* needed for setting up the video resolution */
+ .s_video_encoding = cx231xx_s_video_encoding,
+};
+
static struct video_device *cx231xx_video_dev_alloc(
struct cx231xx *dev,
struct usb_device *usbdev,
@@ -2145,12 +1918,21 @@ static struct video_device *cx231xx_video_dev_alloc(
if (NULL == vfd)
return NULL;
*vfd = *template;
- vfd->minor = -1;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
type, cx231xx_boards[dev->model].name);
vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->lock = &dev->lock;
vfd->release = video_device_release;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
+ video_set_drvdata(vfd, dev);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ }
return vfd;
@@ -2173,10 +1955,27 @@ int cx231xx_417_register(struct cx231xx *dev)
tsport->height = 576;
tsport->width = 720;
- cx2341x_fill_defaults(&dev->mpeg_params);
+ err = cx2341x_handler_init(&dev->mpeg_ctrl_handler, 50);
+ if (err) {
+ dprintk(3, "%s: can't init cx2341x controls\n", dev->name);
+ return err;
+ }
+ dev->mpeg_ctrl_handler.func = cx231xx_mbox_func;
+ dev->mpeg_ctrl_handler.priv = dev;
+ dev->mpeg_ctrl_handler.ops = &cx231xx_ops;
+ if (dev->sd_cx25840)
+ v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl,
+ dev->sd_cx25840->ctrl_handler, NULL);
+ if (dev->mpeg_ctrl_handler.hdl.error) {
+ err = dev->mpeg_ctrl_handler.hdl.error;
+ dprintk(3, "%s: can't add cx25840 controls\n", dev->name);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
+ return err;
+ }
dev->norm = V4L2_STD_NTSC;
- dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+ dev->mpeg_ctrl_handler.port = CX2341X_PORT_SERIAL;
+ cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false);
/* Allocate and initialize V4L video device */
dev->v4l_device = cx231xx_video_dev_alloc(dev,
@@ -2185,6 +1984,7 @@ int cx231xx_417_register(struct cx231xx *dev)
VFL_TYPE_GRABBER, -1);
if (err < 0) {
dprintk(3, "%s: can't register mpeg device\n", dev->name);
+ v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
return err;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index b4c99c7270cf..81a1d971d797 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -449,9 +449,6 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
return -ENODEV;
}
- /* Sets volume, mute, etc */
- dev->mute = 0;
-
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
mutex_lock(&dev->lock);
@@ -503,7 +500,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
return ret;
}
- dev->mute = 1;
dev->adev.users--;
mutex_unlock(&dev->lock);
@@ -708,8 +704,8 @@ static int cx231xx_audio_init(struct cx231xx *dev)
audio_index + 1];
adev->end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
adev->num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 722207913740..235ba657d52e 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -357,6 +357,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
+ case CX231XX_BOARD_OTG102:
if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
FLD_PWRDN_ENABLE_PLL)) {
@@ -1720,6 +1721,7 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
case CX231XX_BOARD_CNXT_RDU_250:
case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_OTG102:
func_mode = 0x03;
break;
case CX231XX_BOARD_CNXT_RDE_253S:
@@ -2133,7 +2135,7 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
- return status;
+ return status == sizeof(dwval) ? 0 : -EIO;
}
/******************************************************************************
@@ -2221,7 +2223,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
switch (mode) {
case POLARIS_AVMODE_ENXTERNAL_AV:
@@ -2442,7 +2444,7 @@ int cx231xx_power_suspend(struct cx231xx *dev)
if (status > 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp &= (~PWR_MODE_MASK);
value[0] = (u8) tmp;
@@ -2470,7 +2472,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp |= ep_mask;
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -2495,7 +2497,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp &= (~ep_mask);
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -2638,20 +2640,23 @@ EXPORT_SYMBOL_GPL(cx231xx_capture_start);
/*****************************************************************************
* G P I O B I T control functions *
******************************************************************************/
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val)
{
int status = 0;
- status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0);
+ gpio_val = cpu_to_le32(gpio_val);
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0);
return status;
}
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
+static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val)
{
+ u32 tmp;
int status = 0;
- status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1);
+ status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1);
+ *gpio_val = le32_to_cpu(tmp);
return status;
}
@@ -2683,7 +2688,7 @@ int cx231xx_set_gpio_direction(struct cx231xx *dev,
else
value = dev->gpio_dir | (1 << pin_number);
- status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, value, dev->gpio_val);
/* cache the value for future */
dev->gpio_dir = value;
@@ -2717,7 +2722,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
value = dev->gpio_dir | (1 << pin_number);
dev->gpio_dir = value;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *) &dev->gpio_val);
+ dev->gpio_val);
value = 0;
}
@@ -2730,7 +2735,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value)
dev->gpio_val = value;
/* toggle bit0 of GP_IO */
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2748,7 +2753,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2756,7 +2761,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2764,7 +2769,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2782,7 +2787,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2790,7 +2795,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2800,7 +2805,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev)
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
status =
- cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
if (status < 0)
return -EINVAL;
@@ -2822,33 +2827,33 @@ int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to output 0 */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 0; set SDA to output 0 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
} else {
/* set SCL to output 0; set SDA to output 1 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
dev->gpio_val |= 1 << dev->board.tuner_sda_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to output 1 */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 0; set SDA to output 1 */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
}
}
return status;
@@ -2867,17 +2872,17 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
/* set SCL to output 0; set SDA to input */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* set SCL to output 1; set SDA to input */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
status = cx231xx_set_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ dev->gpio_val);
/* get SDA data bit */
gpio_logic_value = dev->gpio_val;
status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ &dev->gpio_val);
if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0)
value |= (1 << (8 - i - 1));
@@ -2888,7 +2893,7 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
!!!set SDA to input, never to modify SDA direction at
the same times */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* store the value */
*buf = value & 0xff;
@@ -2909,12 +2914,12 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio);
gpio_logic_value = dev->gpio_val;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
do {
msleep(2);
status = cx231xx_get_gpio_bit(dev, dev->gpio_dir,
- (u8 *)&dev->gpio_val);
+ &dev->gpio_val);
nCnt--;
} while (((dev->gpio_val &
(1 << dev->board.tuner_scl_gpio)) == 0) &&
@@ -2929,7 +2934,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
* through clock stretch, slave has given a SCL signal,
* so the SDA data can be directly read.
*/
- status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, &dev->gpio_val);
if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) {
dev->gpio_val = gpio_logic_value;
@@ -2945,7 +2950,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
dev->gpio_val = gpio_logic_value;
dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2956,24 +2961,24 @@ int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev)
/* set SDA to ouput */
dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 0 (output); set SDA = 0 (output) */
dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio);
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 1 (output); set SDA = 0 (output) */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SCL = 0 (output); set SDA = 0 (output) */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set SDA to input,and then the slave will read data from SDA. */
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
@@ -2985,15 +2990,15 @@ int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
/* set scl to output ; set sda to input */
dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio;
dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set scl to output 0; set sda to input */
dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio);
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
/* set scl to output 1; set sda to input */
dev->gpio_val |= 1 << dev->board.tuner_scl_gpio;
- status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val);
+ status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val);
return status;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 8d529565f163..13249e5a7891 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -263,7 +263,11 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_PAL,
.no_alt_vanc = 1,
.external_av = 1,
- .has_417 = 1,
+ .dont_use_port_3 = 1,
+ /* Actually, it has a 417, but it isn't working correctly.
+ * So set to 0 for now until someone can manage to get this
+ * to work reliably. */
+ .has_417 = 0,
.input = {{
.type = CX231XX_VMUX_COMPOSITE1,
@@ -630,6 +634,39 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_OTG102] = {
+ .name = "Geniatech OTG102",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ /* According with PV CxPlrCAP.inf file */
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_NTSC,
+ .no_alt_vanc = 1,
+ .external_av = 1,
+ .dont_use_port_3 = 1,
+ /*.has_417 = 1, */
+ /* This board is believed to have a hardware encoding chip
+ * supporting mpeg1/2/4, but as the 417 is apparently not
+ * working for the reference board it is not here either. */
+
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -671,6 +708,8 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_ICONBIT_U100},
{USB_DEVICE(0x0fd9, 0x0037),
.driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2},
+ {USB_DEVICE(0x1f4d, 0x0102),
+ .driver_info = CX231XX_BOARD_OTG102},
{},
};
@@ -846,8 +885,6 @@ void cx231xx_card_setup(struct cx231xx *dev)
int cx231xx_config(struct cx231xx *dev)
{
/* TBD need to add cx231xx specific code */
- dev->mute = 1; /* maybe not the right place... */
- dev->volume = 0x1f;
return 0;
}
@@ -1187,8 +1224,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
uif = udev->actconfig->interface[dev->current_pcb_config.
hs_config_info[0].interface_info.video_index + 1];
- dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0].
- endpoint[isoc_pipe].desc.bEndpointAddress);
+ dev->video_mode.end_point_addr = uif->altsetting[0].
+ endpoint[isoc_pipe].desc.bEndpointAddress;
dev->video_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1221,8 +1258,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
vanc_index + 1];
dev->vbi_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
dev->vbi_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1256,8 +1293,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
hanc_index + 1];
dev->sliced_cc_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
dev->sliced_cc_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
@@ -1292,8 +1329,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
ts1_index + 1];
dev->ts1_mode.end_point_addr =
- le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].
- desc.bEndpointAddress);
+ uif->altsetting[0].endpoint[isoc_pipe].
+ desc.bEndpointAddress;
dev->ts1_mode.num_alt = uif->num_altsetting;
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 05358d486135..4ba3ce09b713 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1488,7 +1488,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
if (status < 0)
return status;
- tmp = *((u32 *) value);
+ tmp = le32_to_cpu(*((u32 *) value));
tmp |= mode;
value[0] = (u8) tmp;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 7c4e360ba9bc..14e26106fd72 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -89,8 +89,8 @@ static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
};
static struct tda18271_std_map mb86a20s_tda18271_config = {
- .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
- .if_lvl = 7, .rfagc_top = 0x37, },
+ .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+ .if_lvl = 0, .rfagc_top = 0x37, },
};
static struct tda18271_config cnxt_rde253s_tunerconfig = {
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index 7473c33e823e..d7308ab7a90f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev)
pcb config it is related to */
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
- config_info = *((u32 *) data);
+ config_info = le32_to_cpu(*((u32 *) data));
usb_speed = (u8) (config_info & 0x1);
/* Verify this device belongs to Bus power or Self power device */
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
index f5e46e89f3ab..b3c6190e0c69 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
@@ -68,11 +68,6 @@ enum USB_SPEED{
HIGH_SPEED = 0x1 /* 1: high speed */
};
-enum _true_false{
- FALSE = 0,
- TRUE = 1
-};
-
#define TS_MASK 0x6
enum TS_PORT{
NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid,
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index 46e3892557c2..1340ff268817 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -70,10 +70,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
break;
}
if (packet < 0) {
- cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status,
+ cx231xx_err("URB status %d [%s].\n", status,
errmsg);
} else {
- cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n",
+ cx231xx_err("URB packet %d, status %d [%s].\n",
packet, status, errmsg);
}
}
@@ -317,7 +317,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- cx231xx_err(DRIVER_NAME "urb completition error %d.\n",
+ cx231xx_err("urb completition error %d.\n",
urb->status);
break;
}
@@ -332,7 +332,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
- cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n",
+ cx231xx_err("urb resubmit failed (error=%i)\n",
urb->status);
}
}
@@ -345,7 +345,7 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
struct urb *urb;
int i;
- cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
+ cx231xx_info("called cx231xx_uninit_vbi_isoc\n");
dev->vbi_mode.bulk_ctl.nfields = -1;
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
@@ -394,7 +394,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
struct urb *urb;
int rc;
- cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n");
+ cx231xx_info("called cx231xx_vbi_isoc\n");
/* De-allocates all pending stuff */
cx231xx_uninit_vbi_isoc(dev);
@@ -442,8 +442,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- cx231xx_err(DRIVER_NAME
- ": cannot alloc bulk_ctl.urb %i\n", i);
+ cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -453,8 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
- cx231xx_err(DRIVER_NAME
- ": unable to allocate %i bytes for transfer"
+ cx231xx_err("unable to allocate %i bytes for transfer"
" buffer %i%s\n", sb_size, i,
in_interrupt() ? " while in int" : "");
cx231xx_uninit_vbi_isoc(dev);
@@ -473,8 +471,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
if (rc) {
- cx231xx_err(DRIVER_NAME
- ": submit of urb %i failed (error=%i)\n", i,
+ cx231xx_err("submit of urb %i failed (error=%i)\n", i,
rc);
cx231xx_uninit_vbi_isoc(dev);
return rc;
@@ -526,7 +523,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
struct cx231xx_buffer *buf)
{
/* Advice that buffer was filled */
- /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */
+ /* cx231xx_info("[%p/%d] wakeup\n", buf, buf->vb.i); */
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
@@ -618,7 +615,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
char *outp;
if (list_empty(&dma_q->active)) {
- cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
+ cx231xx_err("No active queue to serve\n");
dev->vbi_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 06376d904c9f..cd221474e1b9 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -35,6 +35,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -100,125 +101,6 @@ static struct cx231xx_fmt format[] = {
},
};
-/* supported controls */
-/* Common to all boards */
-
-/* ------------------------------------------------------------------- */
-
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx231xx_ctrl cx231xx_ctls[] = {
- /* --- video --- */
- {
- .v = {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = LUMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- .v = {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = LUMA_CTRL,
- .mask = 0xff00,
- .shift = 8,
- }, {
- .v = {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = CHROMA_CTRL,
- .mask = 0xff0000,
- .shift = 16,
- }, {
- /* strictly, this only describes only U saturation.
- * V saturation is handled specially through code.
- */
- .v = {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = CHROMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- /* --- audio --- */
- .v = {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
- .reg = PATH1_CTL1,
- .mask = (0x1f << 24),
- .shift = 24,
- }, {
- .v = {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .reg = PATH1_VOL_CTL,
- .mask = 0xff,
- .shift = 0,
- }
-};
-static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls);
-
-static const u32 cx231xx_user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_AUDIO_VOLUME,
-#if 0
- V4L2_CID_AUDIO_BALANCE,
-#endif
- V4L2_CID_AUDIO_MUTE,
- 0
-};
-
-static const u32 *ctrl_classes[] = {
- cx231xx_user_ctrls,
- NULL
-};
/* ------------------------------------------------------------------
Video buffer and parser functions
@@ -1005,6 +887,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1045,10 +928,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = width;
f->fmt.pix.height = height;
f->fmt.pix.pixelformat = fmt->fourcc;
- f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+ f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -1103,39 +987,39 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
struct v4l2_mbus_framefmt mbus_fmt;
- struct v4l2_format f;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
+ if (dev->norm == norm)
+ return 0;
- dev->norm = *norm;
+ if (videobuf_queue_is_busy(&fh->vb_vidq))
+ return -EBUSY;
+
+ dev->norm = norm;
/* Adjusts width/height, if needed */
- f.fmt.pix.width = dev->width;
- f.fmt.pix.height = dev->height;
- vidioc_try_fmt_vid_cap(file, priv, &f);
+ dev->width = 720;
+ dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
call_all(dev, core, s_std, dev->norm);
/* We need to reset basic properties in the decoder related to
resolution (since a standard change effects things like the number
of lines in VACT, etc) */
- v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+ memset(&mbus_fmt, 0, sizeof(mbus_fmt));
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.width = dev->width;
+ mbus_fmt.height = dev->height;
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
- v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
-
- /* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
@@ -1152,7 +1036,7 @@ static const char *iname[] = {
[CX231XX_VMUX_DEBUG] = "for debug only",
};
-static int vidioc_enum_input(struct file *file, void *priv,
+int cx231xx_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct cx231xx_fh *fh = priv;
@@ -1192,7 +1076,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+int cx231xx_g_input(struct file *file, void *priv, unsigned int *i)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1202,7 +1086,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1231,117 +1115,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
-
- switch (a->index) {
- case CX231XX_AMUX_VIDEO:
- strcpy(a->name, "Television");
- break;
- case CX231XX_AMUX_LINE_IN:
- strcpy(a->name, "Line In");
- break;
- default:
- return -EINVAL;
- }
-
- a->index = dev->ctl_ainput;
- a->capability = V4L2_AUDCAP_STEREO;
-
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int status = 0;
-
- /* Doesn't allow manual routing */
- if (a->index != dev->ctl_ainput)
- return -EINVAL;
-
- dev->ctl_ainput = INPUT(a->index)->amux;
- status = cx231xx_set_audio_input(dev, dev->ctl_ainput);
-
- return status;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int id = qc->id;
- int i;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- qc->id = v4l2_ctrl_next(ctrl_classes, qc->id);
- if (unlikely(qc->id == 0))
- return -EINVAL;
-
- memset(qc, 0, sizeof(*qc));
-
- qc->id = id;
-
- if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1)
- return -EINVAL;
-
- for (i = 0; i < CX231XX_CTLS; i++)
- if (cx231xx_ctls[i].v.id == qc->id)
- break;
-
- if (i == CX231XX_CTLS) {
- *qc = no_ctl;
- return 0;
- }
- *qc = cx231xx_ctls[i].v;
-
- call_all(dev, core, queryctrl, qc);
-
- if (qc->type)
- return 0;
- else
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, g_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, core, s_ctrl, ctrl);
- return rc;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1360,11 +1134,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
t->capability = V4L2_TUNER_CAP_NORM;
t->rangehigh = 0xffffffffUL;
t->signal = 0xffff; /* LOCKED */
+ call_all(dev, tuner, g_tuner, t);
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1382,25 +1157,26 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return 0;
}
-static int vidioc_g_frequency(struct file *file, void *priv,
+int cx231xx_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = dev->ctl_freq;
+ if (f->tuner)
+ return -EINVAL;
- call_all(dev, tuner, g_frequency, f);
+ f->frequency = dev->ctl_freq;
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+int cx231xx_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+ struct v4l2_frequency new_freq = *f;
int rc;
u32 if_frequency = 5400000;
@@ -1415,16 +1191,12 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
- return -EINVAL;
- if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
- return -EINVAL;
-
/* set pre channel change settings in DIF first */
rc = cx231xx_tuner_pre_channel_change(dev);
- dev->ctl_freq = f->frequency;
call_all(dev, tuner, s_frequency, f);
+ call_all(dev, tuner, g_frequency, &new_freq);
+ dev->ctl_freq = new_freq.frequency;
/* set post channel change settings in DIF first */
rc = cx231xx_tuner_post_channel_change(dev);
@@ -1456,6 +1228,19 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return rc;
}
+int cx231xx_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match))
+ chip->ident = V4L2_IDENT_CX23100;
+ return 0;
+ }
+ return -EINVAL;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
@@ -1471,7 +1256,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if type == i2caddr, then <chip> is the 7-bit I2C address
*/
-static int vidioc_g_register(struct file *file, void *priv,
+int cx231xx_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct cx231xx_fh *fh = priv;
@@ -1618,8 +1403,8 @@ static int vidioc_g_register(struct file *file, void *priv,
return ret;
}
-static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+int cx231xx_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1837,9 +1622,6 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
if (type != fh->type)
return -EINVAL;
@@ -1851,9 +1633,10 @@ static int vidioc_streamoff(struct file *file, void *priv,
return 0;
}
-static int vidioc_querycap(struct file *file, void *priv,
+int cx231xx_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct video_device *vdev = video_devdata(file);
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1861,17 +1644,22 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VBI_CAPTURE |
-#if 0
- V4L2_CAP_SLICED_VBI_CAPTURE |
-#endif
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
-
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ cap->device_caps = V4L2_CAP_RADIO;
+ else {
+ cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (vdev->vfl_type == VFL_TYPE_VBI)
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ }
if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
+ cap->device_caps |= V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE |
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
+ if (dev->radio_dev)
+ cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1888,47 +1676,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/* Sliced VBI ioctls */
-static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- f->fmt.sliced.service_set = 0;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- rc = -EINVAL;
-
- return rc;
-}
-
-static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct cx231xx_fh *fh = priv;
- struct cx231xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
-
- if (f->fmt.sliced.service_set == 0)
- return -EINVAL;
-
- return 0;
-}
-
/* RAW VBI ioctls */
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
@@ -1936,6 +1683,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1947,6 +1695,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
return 0;
@@ -1958,12 +1707,6 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- if (dev->vbi_stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
- return -EBUSY;
- }
-
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1976,11 +1719,25 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263;
f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+ memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
return 0;
}
+static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+
+ if (dev->vbi_stream_on && !fh->stream_on) {
+ cx231xx_errdev("%s device in use by another fh\n", __func__);
+ return -EBUSY;
+ }
+ return vidioc_try_fmt_vbi_cap(file, priv, f);
+}
+
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
@@ -2038,58 +1795,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
-
- strlcpy(cap->driver, "cx231xx", sizeof(cap->driver));
- strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
-}
-
static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
- if (unlikely(t->index > 0))
+ if (t->index)
return -EINVAL;
strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- call_all(dev, tuner, s_tuner, t);
-
- return 0;
-}
-static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i)
-{
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
+ call_all(dev, tuner, g_tuner, t);
return 0;
}
-
-static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- if (unlikely(a->index))
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
+static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t)
{
struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev;
- if (0 != t->index)
+ if (t->index)
return -EINVAL;
call_all(dev, tuner, s_tuner, t);
@@ -2097,36 +1820,6 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return 0;
}
-static int radio_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
-{
- return 0;
-}
-
-static int radio_s_input(struct file *file, void *fh, unsigned int i)
-{
- return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- int i;
-
- if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX231XX_CTLS; i++) {
- if (cx231xx_ctls[i].v.id == c->id)
- break;
- }
- if (i == CX231XX_CTLS)
- return -EINVAL;
- *c = cx231xx_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
-}
-
/*
* cx231xx_v4l2_open()
* inits the device and starts isoc transfer
@@ -2174,14 +1867,11 @@ static int cx231xx_v4l2_open(struct file *filp)
return -ERESTARTSYS;
}
fh->dev = dev;
- fh->radio = radio;
fh->type = fh_type;
filp->private_data = fh;
+ v4l2_fh_init(&fh->fh, vdev);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
- dev->width = norm_maxw(dev);
- dev->height = norm_maxh(dev);
-
/* Power up in Analog TV mode */
if (dev->board.external_av)
cx231xx_set_power_mode(dev,
@@ -2204,7 +1894,7 @@ static int cx231xx_v4l2_open(struct file *filp)
dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
}
- if (fh->radio) {
+ if (radio) {
cx231xx_videodbg("video_open: setting radio device\n");
/* cx231xx_start_radio(dev); */
@@ -2232,6 +1922,7 @@ static int cx231xx_v4l2_open(struct file *filp)
fh, &dev->lock);
}
mutex_unlock(&dev->lock);
+ v4l2_fh_add(&fh->fh);
return errCode;
}
@@ -2275,6 +1966,8 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
video_device_release(dev->vdev);
dev->vdev = NULL;
}
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
}
/*
@@ -2324,12 +2017,15 @@ static int cx231xx_close(struct file *filp)
else
cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
return 0;
}
+ v4l2_fh_del(&fh->fh);
dev->users--;
if (!dev->users) {
videobuf_stop(&fh->vb_vidq);
@@ -2356,6 +2052,7 @@ static int cx231xx_close(struct file *filp)
/* set alternate 0 */
cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0);
}
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
wake_up_interruptible_nr(&dev->open, 1);
return 0;
@@ -2412,29 +2109,37 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
*/
static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct cx231xx_fh *fh = filp->private_data;
struct cx231xx *dev = fh->dev;
+ unsigned res = 0;
int rc;
rc = check_dev(dev);
if (rc < 0)
- return rc;
+ return POLLERR;
rc = res_get(fh);
if (unlikely(rc < 0))
return POLLERR;
+ if (v4l2_event_pending(&fh->fh))
+ res |= POLLPRI;
+ else
+ poll_wait(filp, &fh->fh.wait, wait);
+
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return res;
+
if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
(V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
- unsigned int res;
-
mutex_lock(&dev->lock);
- res = videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ res |= videobuf_poll_stream(filp, &fh->vb_vidq, wait);
mutex_unlock(&dev->lock);
return res;
}
- return POLLERR;
+ return res | POLLERR;
}
/*
@@ -2479,41 +2184,37 @@ static const struct v4l2_file_operations cx231xx_v4l_fops = {
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
.vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_enum_input = cx231xx_enum_input,
+ .vidioc_g_input = cx231xx_g_input,
+ .vidioc_s_input = cx231xx_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = cx231xx_g_tuner,
+ .vidioc_s_tuner = cx231xx_s_tuner,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_vbi_template;
@@ -2523,33 +2224,29 @@ static const struct video_device cx231xx_video_template = {
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_PAL,
};
static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = cx231xx_v4l2_open,
.release = cx231xx_v4l2_close,
- .ioctl = video_ioctl2,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
- .vidioc_querycap = radio_querycap,
+ .vidioc_querycap = cx231xx_querycap,
.vidioc_g_tuner = radio_g_tuner,
- .vidioc_enum_input = radio_enum_input,
- .vidioc_g_audio = radio_g_audio,
.vidioc_s_tuner = radio_s_tuner,
- .vidioc_s_audio = radio_s_audio,
- .vidioc_s_input = radio_s_input,
- .vidioc_queryctrl = radio_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_frequency = cx231xx_g_frequency,
+ .vidioc_s_frequency = cx231xx_s_frequency,
+ .vidioc_g_chip_ident = cx231xx_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .vidioc_g_register = vidioc_g_register,
- .vidioc_s_register = vidioc_s_register,
+ .vidioc_g_register = cx231xx_g_register,
+ .vidioc_s_register = cx231xx_s_register,
#endif
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx231xx_radio_template = {
@@ -2575,10 +2272,17 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
video_set_drvdata(vfd, dev);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER);
+ }
return vfd;
}
@@ -2590,7 +2294,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev->name, CX231XX_VERSION);
/* set default norm */
- /*dev->norm = cx231xx_video_template.current_norm; */
+ dev->norm = V4L2_STD_PAL;
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
dev->interlaced = 0;
@@ -2601,9 +2305,23 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Set the initial input */
video_mux(dev, dev->video_input);
- /* Audio defaults */
- dev->mute = 1;
- dev->volume = 0x1f;
+ call_all(dev, core, s_std, dev->norm);
+
+ v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
+ v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
+
+ if (dev->sd_cx25840) {
+ v4l2_ctrl_add_handler(&dev->ctrl_handler,
+ dev->sd_cx25840->ctrl_handler, NULL);
+ v4l2_ctrl_add_handler(&dev->radio_ctrl_handler,
+ dev->sd_cx25840->ctrl_handler,
+ v4l2_ctrl_radio_filter);
+ }
+
+ if (dev->ctrl_handler.error)
+ return dev->ctrl_handler.error;
+ if (dev->radio_ctrl_handler.error)
+ return dev->radio_ctrl_handler.error;
/* enable vbi capturing */
/* write code here... */
@@ -2615,6 +2333,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
return -ENODEV;
}
+ dev->vdev->ctrl_handler = &dev->ctrl_handler;
/* register v4l2 video video_device */
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
@@ -2634,6 +2353,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Allocate and fill vbi video_device struct */
dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
+ if (!dev->vbi_dev) {
+ cx231xx_errdev("cannot allocate video_device.\n");
+ return -ENODEV;
+ }
+ dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
/* register v4l2 vbi video_device */
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
@@ -2652,6 +2376,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
cx231xx_errdev("cannot allocate video_device.\n");
return -ENODEV;
}
+ dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 3e11462be0d0..5ad9fd61d3c8 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -33,6 +33,8 @@
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dvb.h>
@@ -69,6 +71,7 @@
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14
#define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15
#define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16
+#define CX231XX_BOARD_OTG102 17
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -428,27 +431,12 @@ struct cx231xx_audio {
struct cx231xx;
struct cx231xx_fh {
+ struct v4l2_fh fh;
struct cx231xx *dev;
unsigned int stream_on:1; /* Locks streams */
- int radio;
-
- struct videobuf_queue vb_vidq;
-
enum v4l2_buf_type type;
-
-
-/*following is copyed from cx23885.h*/
- u32 resources;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip *clips;
- unsigned int nclips;
-
- /* video capture */
- struct cx23417_fmt *fmt;
- unsigned int width, height;
+ struct videobuf_queue vb_vidq;
/* vbi capture */
struct videobuf_queue vidq;
@@ -516,14 +504,6 @@ struct cx231xx_tvnorm {
u32 cxoformat;
};
-struct cx231xx_ctrl {
- struct v4l2_queryctrl v;
- u32 off;
- u32 reg;
- u32 mask;
- u32 shift;
-};
-
enum TRANSFER_TYPE {
Raw_Video = 0,
Audio,
@@ -631,6 +611,9 @@ struct cx231xx {
struct v4l2_device v4l2_dev;
struct v4l2_subdev *sd_cx25840;
struct v4l2_subdev *sd_tuner;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl_handler radio_ctrl_handler;
+ struct cx2341x_handler mpeg_ctrl_handler;
struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
atomic_t stream_started; /* stream should be running if true */
@@ -653,8 +636,6 @@ struct cx231xx {
v4l2_std_id norm; /* selected tv norm */
int ctl_freq; /* selected frequency */
unsigned int ctl_ainput; /* selected audio input */
- int mute;
- int volume;
/* frame properties */
int width; /* current frame width */
@@ -736,7 +717,6 @@ struct cx231xx {
u8 USE_ISO;
struct cx231xx_tvnorm encodernorm;
struct cx231xx_tsport ts1, ts2;
- struct cx2341x_mpeg_params mpeg_params;
struct video_device *v4l_device;
atomic_t v4l_reader_count;
u32 freq;
@@ -866,8 +846,6 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
/* Gpio related functions */
int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
u8 len, u8 request, u8 direction);
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val);
int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value);
int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number,
int pin_value);
@@ -955,6 +933,23 @@ int cx231xx_register_extension(struct cx231xx_ops *dev);
void cx231xx_unregister_extension(struct cx231xx_ops *dev);
void cx231xx_init_extension(struct cx231xx *dev);
void cx231xx_close_extension(struct cx231xx *dev);
+int cx231xx_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap);
+int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t);
+int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t);
+int cx231xx_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f);
+int cx231xx_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f);
+int cx231xx_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i);
+int cx231xx_g_input(struct file *file, void *priv, unsigned int *i);
+int cx231xx_s_input(struct file *file, void *priv, unsigned int i);
+int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
+int cx231xx_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg);
+int cx231xx_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg);
/* Provided by cx231xx-cards.c */
extern void cx231xx_pre_card_setup(struct cx231xx *dev);
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 692224d97d06..a3c8ecf22078 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -13,10 +13,6 @@ config DVB_USB_V2
Say Y if you own a USB DVB device.
-config DVB_USB_CYPRESS_FIRMWARE
- tristate "Cypress firmware helper routines"
- depends on DVB_USB_V2
-
config DVB_USB_AF9015
tristate "Afatech AF9015 DVB-T USB2.0 support"
depends on DVB_USB_V2
@@ -41,6 +37,7 @@ config DVB_USB_AF9035
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Afatech AF9035 based DVB USB receiver.
@@ -72,7 +69,7 @@ config DVB_USB_AU6610
config DVB_USB_AZ6007
tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
depends on DVB_USB_V2
- select DVB_USB_CYPRESS_FIRMWARE
+ select CYPRESS_FIRMWARE
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
help
@@ -146,6 +143,7 @@ config DVB_USB_RTL28XXU
select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile
index b76f58e6c64f..2c06714b9ef0 100644
--- a/drivers/media/usb/dvb-usb-v2/Makefile
+++ b/drivers/media/usb/dvb-usb-v2/Makefile
@@ -1,9 +1,6 @@
dvb_usb_v2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o
obj-$(CONFIG_DVB_USB_V2) += dvb_usb_v2.o
-dvb_usb_cypress_firmware-objs := cypress_firmware.o
-obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o
-
dvb-usb-af9015-objs := af9015.o
obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
@@ -46,4 +43,4 @@ obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
ccflags-y += -I$(srctree)/drivers/media/tuners
-
+ccflags-y += -I$(srctree)/drivers/media/common
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index b86d0f27a398..d556042cf312 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -30,22 +30,22 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
{
-#define BUF_LEN 63
#define REQ_HDR_LEN 8 /* send header size */
#define ACK_HDR_LEN 2 /* rece header size */
struct af9015_state *state = d_to_priv(d);
int ret, wlen, rlen;
- u8 buf[BUF_LEN];
u8 write = 1;
- buf[0] = req->cmd;
- buf[1] = state->seq++;
- buf[2] = req->i2c_addr;
- buf[3] = req->addr >> 8;
- buf[4] = req->addr & 0xff;
- buf[5] = req->mbox;
- buf[6] = req->addr_len;
- buf[7] = req->data_len;
+ mutex_lock(&d->usb_mutex);
+
+ state->buf[0] = req->cmd;
+ state->buf[1] = state->seq++;
+ state->buf[2] = req->i2c_addr;
+ state->buf[3] = req->addr >> 8;
+ state->buf[4] = req->addr & 0xff;
+ state->buf[5] = req->mbox;
+ state->buf[6] = req->addr_len;
+ state->buf[7] = req->data_len;
switch (req->cmd) {
case GET_CONFIG:
@@ -55,14 +55,14 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
break;
case READ_I2C:
write = 0;
- buf[2] |= 0x01; /* set I2C direction */
+ state->buf[2] |= 0x01; /* set I2C direction */
case WRITE_I2C:
- buf[0] = READ_WRITE_I2C;
+ state->buf[0] = READ_WRITE_I2C;
break;
case WRITE_MEMORY:
if (((req->addr & 0xff00) == 0xff00) ||
((req->addr & 0xff00) == 0xae00))
- buf[0] = WRITE_VIRTUAL_MEMORY;
+ state->buf[0] = WRITE_VIRTUAL_MEMORY;
case WRITE_VIRTUAL_MEMORY:
case COPY_FIRMWARE:
case DOWNLOAD_FIRMWARE:
@@ -90,7 +90,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
rlen = ACK_HDR_LEN;
if (write) {
wlen += req->data_len;
- memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
+ memcpy(&state->buf[REQ_HDR_LEN], req->data, req->data_len);
} else {
rlen += req->data_len;
}
@@ -99,22 +99,25 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
rlen = 0;
- ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ ret = dvb_usbv2_generic_rw_locked(d,
+ state->buf, wlen, state->buf, rlen);
if (ret)
goto error;
/* check status */
- if (rlen && buf[1]) {
+ if (rlen && state->buf[1]) {
dev_err(&d->udev->dev, "%s: command failed=%d\n",
- KBUILD_MODNAME, buf[1]);
+ KBUILD_MODNAME, state->buf[1]);
ret = -EIO;
goto error;
}
/* read request, copy returned data to return buf */
if (!write)
- memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
+ memcpy(req->data, &state->buf[ACK_HDR_LEN], req->data_len);
error:
+ mutex_unlock(&d->usb_mutex);
+
return ret;
}
@@ -1317,6 +1320,43 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
#define af9015_get_rc_config NULL
#endif
+static int af9015_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char manufacturer[sizeof("ITE Technologies, Inc.")];
+
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ /*
+ * There is two devices having same ID but different chipset. One uses
+ * AF9015 and the other IT9135 chipset. Only difference seen on lsusb
+ * is iManufacturer string.
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 Afatech
+ * iProduct 2 DVB-T 2
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 ITE Technologies, Inc.
+ * iProduct 2 DVB-T TV Stick
+ */
+ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) &&
+ (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
+ if (!strcmp("ITE Technologies, Inc.", manufacturer)) {
+ dev_dbg(&udev->dev, "%s: rejecting device\n", __func__);
+ return -ENODEV;
+ }
+ }
+
+ return dvb_usbv2_probe(intf, id);
+}
+
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
static struct dvb_usb_device_properties af9015_props = {
@@ -1425,6 +1465,7 @@ static const struct usb_device_id af9015_id_table[] = {
&af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC,
&af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) },
+ /* XXX: that same ID [0ccd:0099] is used by af9035 driver too */
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
&af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) },
{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T,
@@ -1441,7 +1482,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table);
static struct usb_driver af9015_usb_driver = {
.name = KBUILD_MODNAME,
.id_table = af9015_id_table,
- .probe = dvb_usbv2_probe,
+ .probe = af9015_probe,
.disconnect = dvb_usbv2_disconnect,
.suspend = dvb_usbv2_suspend,
.resume = dvb_usbv2_resume,
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h
index 533637dedd23..3a6f3ad1eadb 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.h
+++ b/drivers/media/usb/dvb-usb-v2/af9015.h
@@ -115,7 +115,9 @@ enum af9015_ir_mode {
AF9015_IR_MODE_POLLING, /* just guess */
};
+#define BUF_LEN 63
struct af9015_state {
+ u8 buf[BUF_LEN]; /* bulk USB control message */
u8 ir_mode;
u8 rc_repeat;
u32 rc_keycode;
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index f11cc42454f0..b638fc1cd574 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -41,79 +41,84 @@ static u16 af9035_checksum(const u8 *buf, size_t len)
static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
{
-#define BUF_LEN 64
#define REQ_HDR_LEN 4 /* send header size */
#define ACK_HDR_LEN 3 /* rece header size */
#define CHECKSUM_LEN 2
#define USB_TIMEOUT 2000
struct state *state = d_to_priv(d);
int ret, wlen, rlen;
- u8 buf[BUF_LEN];
u16 checksum, tmp_checksum;
+ mutex_lock(&d->usb_mutex);
+
/* buffer overflow check */
if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
__func__, req->wlen, req->rlen);
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
- buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
- buf[1] = req->mbox;
- buf[2] = req->cmd;
- buf[3] = state->seq++;
- memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+ state->buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+ state->buf[1] = req->mbox;
+ state->buf[2] = req->cmd;
+ state->buf[3] = state->seq++;
+ memcpy(&state->buf[REQ_HDR_LEN], req->wbuf, req->wlen);
wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
/* calc and add checksum */
- checksum = af9035_checksum(buf, buf[0] - 1);
- buf[buf[0] - 1] = (checksum >> 8);
- buf[buf[0] - 0] = (checksum & 0xff);
+ checksum = af9035_checksum(state->buf, state->buf[0] - 1);
+ state->buf[state->buf[0] - 1] = (checksum >> 8);
+ state->buf[state->buf[0] - 0] = (checksum & 0xff);
/* no ack for these packets */
if (req->cmd == CMD_FW_DL)
rlen = 0;
- ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+ ret = dvb_usbv2_generic_rw_locked(d,
+ state->buf, wlen, state->buf, rlen);
if (ret)
- goto err;
+ goto exit;
/* no ack for those packets */
if (req->cmd == CMD_FW_DL)
goto exit;
/* verify checksum */
- checksum = af9035_checksum(buf, rlen - 2);
- tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
+ checksum = af9035_checksum(state->buf, rlen - 2);
+ tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1];
if (tmp_checksum != checksum) {
dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
"(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
tmp_checksum, checksum);
ret = -EIO;
- goto err;
+ goto exit;
}
/* check status */
- if (buf[2]) {
+ if (state->buf[2]) {
+ /* fw returns status 1 when IR code was not received */
+ if (req->cmd == CMD_IR_GET || state->buf[2] == 1) {
+ ret = 1;
+ goto exit;
+ }
+
dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n",
- __func__, req->cmd, buf[2]);
+ __func__, req->cmd, state->buf[2]);
ret = -EIO;
- goto err;
+ goto exit;
}
/* read request, copy returned data to return buf */
if (req->rlen)
- memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
-
+ memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen);
exit:
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
-
+ mutex_unlock(&d->usb_mutex);
+ if (ret < 0)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -292,12 +297,40 @@ static struct i2c_algorithm af9035_i2c_algo = {
static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
{
+ struct state *state = d_to_priv(d);
int ret;
u8 wbuf[1] = { 1 };
u8 rbuf[4];
struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
sizeof(rbuf), rbuf };
+ ret = af9035_rd_regs(d, 0x1222, rbuf, 3);
+ if (ret < 0)
+ goto err;
+
+ state->chip_version = rbuf[0];
+ state->chip_type = rbuf[2] << 8 | rbuf[1] << 0;
+
+ ret = af9035_rd_reg(d, 0x384f, &state->prechip_version);
+ if (ret < 0)
+ goto err;
+
+ dev_info(&d->udev->dev,
+ "%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n",
+ __func__, state->prechip_version, state->chip_version,
+ state->chip_type);
+
+ if (state->chip_type == 0x9135) {
+ if (state->chip_version == 0x02)
+ *name = AF9035_FIRMWARE_IT9135_V2;
+ else
+ *name = AF9035_FIRMWARE_IT9135_V1;
+ state->eeprom_addr = EEPROM_BASE_IT9135;
+ } else {
+ *name = AF9035_FIRMWARE_AF9035;
+ state->eeprom_addr = EEPROM_BASE_AF9035;
+ }
+
ret = af9035_ctrl_msg(d, &req);
if (ret < 0)
goto err;
@@ -316,66 +349,19 @@ err:
return ret;
}
-static int af9035_download_firmware(struct dvb_usb_device *d,
+static int af9035_download_firmware_old(struct dvb_usb_device *d,
const struct firmware *fw)
{
int ret, i, j, len;
u8 wbuf[1];
- u8 rbuf[4];
struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
- u8 hdr_core, tmp;
+ u8 hdr_core;
u16 hdr_addr, hdr_data_len, hdr_checksum;
#define MAX_DATA 58
#define HDR_SIZE 7
/*
- * In case of dual tuner configuration we need to do some extra
- * initialization in order to download firmware to slave demod too,
- * which is done by master demod.
- * Master feeds also clock and controls power via GPIO.
- */
- ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
- if (ret < 0)
- goto err;
-
- if (tmp) {
- /* configure gpioh1, reset & power slave demod */
- ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01);
- if (ret < 0)
- goto err;
-
- usleep_range(10000, 50000);
-
- ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01);
- if (ret < 0)
- goto err;
-
- /* tell the slave I2C address */
- ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x00417f, tmp);
- if (ret < 0)
- goto err;
-
- /* enable clock out */
- ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01);
- if (ret < 0)
- goto err;
- }
-
- /*
* Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
*
* byte 0: MCS 51 core
@@ -441,28 +427,6 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
if (i)
dev_warn(&d->udev->dev, "%s: bad firmware\n", KBUILD_MODNAME);
- /* firmware loaded, request boot */
- req.cmd = CMD_FW_BOOT;
- ret = af9035_ctrl_msg(d, &req);
- if (ret < 0)
- goto err;
-
- /* ensure firmware starts */
- wbuf[0] = 1;
- ret = af9035_ctrl_msg(d, &req_fw_ver);
- if (ret < 0)
- goto err;
-
- if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
- dev_err(&d->udev->dev, "%s: firmware did not run\n",
- KBUILD_MODNAME);
- ret = -ENODEV;
- goto err;
- }
-
- dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d",
- KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
-
return 0;
err:
@@ -471,15 +435,11 @@ err:
return ret;
}
-static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
+static int af9035_download_firmware_new(struct dvb_usb_device *d,
const struct firmware *fw)
{
int ret, i, i_prev;
- u8 wbuf[1];
- u8 rbuf[4];
- struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
- struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
#define HDR_SIZE 7
/*
@@ -494,7 +454,6 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
* 5: addr LSB
* 6: count of data bytes ?
*/
-
for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
if (i == fw->size ||
(fw->data[i + 0] == 0x03 &&
@@ -513,6 +472,86 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
}
}
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware(struct dvb_usb_device *d,
+ const struct firmware *fw)
+{
+ struct state *state = d_to_priv(d);
+ int ret;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ u8 tmp;
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+ /*
+ * In case of dual tuner configuration we need to do some extra
+ * initialization in order to download firmware to slave demod too,
+ * which is done by master demod.
+ * Master feeds also clock and controls power via GPIO.
+ */
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp) {
+ /* configure gpioh1, reset & power slave demod */
+ ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 50000);
+
+ ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* tell the slave I2C address */
+ ret = af9035_rd_reg(d,
+ state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
+ &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (state->chip_type == 0x9135) {
+ ret = af9035_wr_reg(d, 0x004bfb, tmp);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = af9035_wr_reg(d, 0x00417f, tmp);
+ if (ret < 0)
+ goto err;
+
+ /* enable clock out */
+ ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+ }
+
+ if (fw->data[0] == 0x01)
+ ret = af9035_download_firmware_old(d, fw);
+ else
+ ret = af9035_download_firmware_new(d, fw);
+ if (ret < 0)
+ goto err;
+
/* firmware loaded, request boot */
req.cmd = CMD_FW_BOOT;
ret = af9035_ctrl_msg(d, &req);
@@ -546,15 +585,42 @@ err:
static int af9035_read_config(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
- int ret, i, eeprom_shift = 0;
+ int ret, i;
u8 tmp;
- u16 tmp16;
+ u16 tmp16, addr;
/* demod I2C "address" */
state->af9033_config[0].i2c_addr = 0x38;
+ state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
+ state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X;
+ state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+ state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+ /* eeprom memory mapped location */
+ if (state->chip_type == 0x9135) {
+ if (state->chip_version == 0x02) {
+ state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
+ state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60;
+ tmp16 = 0x00461d;
+ } else {
+ state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38;
+ state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38;
+ tmp16 = 0x00461b;
+ }
+
+ /* check if eeprom exists */
+ ret = af9035_rd_reg(d, tmp16, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp == 0x00) {
+ dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
+ goto skip_eeprom;
+ }
+ }
/* check if there is dual tuners */
- ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp);
if (ret < 0)
goto err;
@@ -564,7 +630,9 @@ static int af9035_read_config(struct dvb_usb_device *d)
if (state->dual_mode) {
/* read 2nd demodulator I2C address */
- ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp);
+ ret = af9035_rd_reg(d,
+ state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR,
+ &tmp);
if (ret < 0)
goto err;
@@ -573,17 +641,25 @@ static int af9035_read_config(struct dvb_usb_device *d)
__func__, tmp);
}
+ addr = state->eeprom_addr;
+
for (i = 0; i < state->dual_mode + 1; i++) {
/* tuner */
- ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_TUNER_ID, &tmp);
if (ret < 0)
goto err;
- state->af9033_config[i].tuner = tmp;
+ if (tmp == 0x00)
+ dev_dbg(&d->udev->dev,
+ "%s: [%d]tuner not set, using default\n",
+ __func__, i);
+ else
+ state->af9033_config[i].tuner = tmp;
+
dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n",
- __func__, i, tmp);
+ __func__, i, state->af9033_config[i].tuner);
- switch (tmp) {
+ switch (state->af9033_config[i].tuner) {
case AF9033_TUNER_TUA9001:
case AF9033_TUNER_FC0011:
case AF9033_TUNER_MXL5007T:
@@ -592,32 +668,46 @@ static int af9035_read_config(struct dvb_usb_device *d)
case AF9033_TUNER_FC0012:
state->af9033_config[i].spec_inv = 1;
break;
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ break;
default:
- dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \
- "supported, please report!",
+ dev_warn(&d->udev->dev,
+ "%s: tuner id=%02x not supported, please report!",
KBUILD_MODNAME, tmp);
}
/* disable dual mode if driver does not support it */
if (i == 1)
- switch (tmp) {
+ switch (state->af9033_config[i].tuner) {
case AF9033_TUNER_FC0012:
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ case AF9033_TUNER_MXL5007T:
break;
default:
state->dual_mode = false;
- dev_info(&d->udev->dev, "%s: driver does not " \
- "support 2nd tuner and will " \
- "disable it", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: driver does not support 2nd tuner and will disable it",
+ KBUILD_MODNAME);
}
/* tuner IF frequency */
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_IF_L, &tmp);
if (ret < 0)
goto err;
tmp16 = tmp;
- ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+ ret = af9035_rd_reg(d, addr + EEPROM_1_IF_H, &tmp);
if (ret < 0)
goto err;
@@ -625,9 +715,10 @@ static int af9035_read_config(struct dvb_usb_device *d)
dev_dbg(&d->udev->dev, "%s: [%d]IF=%d\n", __func__, i, tmp16);
- eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+ addr += 0x10; /* shift for the 2nd tuner params */
}
+skip_eeprom:
/* get demod clock */
ret = af9035_rd_reg(d, 0x00d800, &tmp);
if (ret < 0)
@@ -635,34 +726,12 @@ static int af9035_read_config(struct dvb_usb_device *d)
tmp = (tmp >> 0) & 0x0f;
- for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
- state->af9033_config[i].clock = clock_lut[tmp];
-
- return 0;
-
-err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
-
- return ret;
-}
-
-static int af9035_read_config_it9135(struct dvb_usb_device *d)
-{
- struct state *state = d_to_priv(d);
- int ret, i;
- u8 tmp;
-
- state->dual_mode = false;
-
- /* get demod clock */
- ret = af9035_rd_reg(d, 0x00d800, &tmp);
- if (ret < 0)
- goto err;
-
- tmp = (tmp >> 0) & 0x0f;
-
- for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
- state->af9033_config[i].clock = clock_lut_it9135[tmp];
+ for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) {
+ if (state->chip_type == 0x9135)
+ state->af9033_config[i].clock = clock_lut_it9135[tmp];
+ else
+ state->af9033_config[i].clock = clock_lut_af9035[tmp];
+ }
return 0;
@@ -821,7 +890,12 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
static int af9035_get_adapter_count(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
- return state->dual_mode + 1;
+
+ /* disable 2nd adapter as we don't have PID filters implemented */
+ if (d->udev->speed == USB_SPEED_FULL)
+ return 1;
+ else
+ return state->dual_mode + 1;
}
static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
@@ -829,6 +903,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
struct state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
int ret;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
if (!state->af9033_config[adap->id].tuner) {
/* unsupported tuner */
@@ -836,20 +911,6 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
goto err;
}
- if (adap->id == 0) {
- state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
- state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
-
- ret = af9035_wr_reg(d, 0x00417f,
- state->af9033_config[1].i2c_addr);
- if (ret < 0)
- goto err;
-
- ret = af9035_wr_reg(d, 0x00d81a, state->dual_mode);
- if (ret < 0)
- goto err;
- }
-
/* attach demodulator */
adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id],
&d->i2c_adap);
@@ -928,6 +989,8 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
struct dvb_frontend *fe;
struct i2c_msg msg[1];
u8 tuner_addr;
+ dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
/*
* XXX: Hack used in that function: we abuse unused I2C address bit [7]
* to carry info about used I2C bus for dual tuner configuration.
@@ -1082,6 +1145,17 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
fe = dvb_attach(fc0012_attach, adap->fe[0], &d->i2c_adap,
&af9035_fc0012_config[adap->id]);
break;
+ case AF9033_TUNER_IT9135_38:
+ case AF9033_TUNER_IT9135_51:
+ case AF9033_TUNER_IT9135_52:
+ case AF9033_TUNER_IT9135_60:
+ case AF9033_TUNER_IT9135_61:
+ case AF9033_TUNER_IT9135_62:
+ /* attach tuner */
+ fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap,
+ state->af9033_config[adap->id].i2c_addr,
+ state->af9033_config[0].tuner);
+ break;
default:
fe = NULL;
}
@@ -1103,8 +1177,8 @@ static int af9035_init(struct dvb_usb_device *d)
{
struct state *state = d_to_priv(d);
int ret, i;
- u16 frame_size = 87 * 188 / 4;
- u8 packet_size = 512 / 4;
+ u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4;
+ u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
struct reg_val_mask tab[] = {
{ 0x80f99d, 0x01, 0x01 },
{ 0x80f9a4, 0x01, 0x01 },
@@ -1149,40 +1223,49 @@ err:
#if IS_ENABLED(CONFIG_RC_CORE)
static int af9035_rc_query(struct dvb_usb_device *d)
{
- unsigned int key;
- unsigned char b[4];
int ret;
- struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+ u32 key;
+ u8 buf[4];
+ struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf };
ret = af9035_ctrl_msg(d, &req);
- if (ret < 0)
+ if (ret == 1)
+ return 0;
+ else if (ret < 0)
goto err;
- if ((b[2] + b[3]) == 0xff) {
- if ((b[0] + b[1]) == 0xff) {
- /* NEC */
- key = b[0] << 8 | b[2];
+ if ((buf[2] + buf[3]) == 0xff) {
+ if ((buf[0] + buf[1]) == 0xff) {
+ /* NEC standard 16bit */
+ key = buf[0] << 8 | buf[2];
} else {
- /* ext. NEC */
- key = b[0] << 16 | b[1] << 8 | b[2];
+ /* NEC extended 24bit */
+ key = buf[0] << 16 | buf[1] << 8 | buf[2];
}
} else {
- key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+ /* NEC full code 32bit */
+ key = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
+ dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf);
+
rc_keydown(d->rc_dev, key, 0);
-err:
- /* ignore errors */
return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
}
static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
{
+ struct state *state = d_to_priv(d);
int ret;
u8 tmp;
- ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_MODE, &tmp);
if (ret < 0)
goto err;
@@ -1190,7 +1273,8 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
/* don't activate rc if in HID mode or if not available */
if (tmp == 5) {
- ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+ ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_TYPE,
+ &tmp);
if (ret < 0)
goto err;
@@ -1225,6 +1309,109 @@ err:
#define af9035_get_rc_config NULL
#endif
+static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+ struct usb_data_stream_properties *stream)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+
+ if (d->udev->speed == USB_SPEED_FULL)
+ stream->u.bulk.buffersize = 5 * 188;
+
+ return 0;
+}
+
+/*
+ * FIXME: PID filter is property of demodulator and should be moved to the
+ * correct driver. Also we support only adapter #0 PID filter and will
+ * disable adapter #1 if USB1.1 is used.
+ */
+static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+
+ dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+
+ ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret;
+ u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff};
+
+ dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n",
+ __func__, index, pid, onoff);
+
+ ret = af9035_wr_regs(d, 0x80f996, wbuf, 2);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x80f994, onoff);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0x80f995, index);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char manufacturer[sizeof("Afatech")];
+
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ /*
+ * There is two devices having same ID but different chipset. One uses
+ * AF9015 and the other IT9135 chipset. Only difference seen on lsusb
+ * is iManufacturer string.
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 Afatech
+ * iProduct 2 DVB-T 2
+ *
+ * idVendor 0x0ccd TerraTec Electronic GmbH
+ * idProduct 0x0099
+ * bcdDevice 2.00
+ * iManufacturer 1 ITE Technologies, Inc.
+ * iProduct 2 DVB-T TV Stick
+ */
+ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) &&
+ (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) {
+ if (!strcmp("Afatech", manufacturer)) {
+ dev_dbg(&udev->dev, "%s: rejecting device\n", __func__);
+ return -ENODEV;
+ }
+ }
+
+ return dvb_usbv2_probe(intf, id);
+}
+
/* interface 0 is used by DVB-T receiver and
interface 1 is for remote controller (HID) */
static const struct dvb_usb_device_properties af9035_props = {
@@ -1237,7 +1424,6 @@ static const struct dvb_usb_device_properties af9035_props = {
.generic_bulk_ctrl_endpoint_response = 0x81,
.identify_state = af9035_identify_state,
- .firmware = AF9035_FIRMWARE_AF9035,
.download_firmware = af9035_download_firmware,
.i2c_algo = &af9035_i2c_algo,
@@ -1246,40 +1432,18 @@ static const struct dvb_usb_device_properties af9035_props = {
.tuner_attach = af9035_tuner_attach,
.init = af9035_init,
.get_rc_config = af9035_get_rc_config,
+ .get_stream_config = af9035_get_stream_config,
.get_adapter_count = af9035_get_adapter_count,
.adapter = {
{
- .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
- }, {
- .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
- },
- },
-};
-
-static const struct dvb_usb_device_properties it9135_props = {
- .driver_name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct state),
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .generic_bulk_ctrl_endpoint = 0x02,
- .generic_bulk_ctrl_endpoint_response = 0x81,
-
- .identify_state = af9035_identify_state,
- .firmware = AF9035_FIRMWARE_IT9135,
- .download_firmware = af9035_download_firmware_it9135,
+ .pid_filter_count = 32,
+ .pid_filter_ctrl = af9035_pid_filter_ctrl,
+ .pid_filter = af9035_pid_filter,
- .i2c_algo = &af9035_i2c_algo,
- .read_config = af9035_read_config_it9135,
- .frontend_attach = af9035_frontend_attach,
- .tuner_attach = af9035_tuner_attach,
- .init = af9035_init,
- .get_rc_config = af9035_get_rc_config,
-
- .num_adapters = 1,
- .adapter = {
- {
.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
}, {
.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
@@ -1288,6 +1452,7 @@ static const struct dvb_usb_device_properties it9135_props = {
};
static const struct usb_device_id af9035_id_table[] = {
+ /* AF9035 devices */
{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
&af9035_props, "Afatech AF9035 reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
@@ -1312,6 +1477,18 @@ static const struct usb_device_id af9035_id_table[] = {
&af9035_props, "AVerMedia Twinstar (A825)", NULL) },
{ DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS,
&af9035_props, "Asus U3100Mini Plus", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa,
+ &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) },
+ /* IT9135 devices */
+#if 0
+ { DVB_USB_DEVICE(0x048d, 0x9135,
+ &af9035_props, "IT9135 reference design", NULL) },
+ { DVB_USB_DEVICE(0x048d, 0x9006,
+ &af9035_props, "IT9135 reference design", NULL) },
+#endif
+ /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
+ &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, af9035_id_table);
@@ -1319,7 +1496,7 @@ MODULE_DEVICE_TABLE(usb, af9035_id_table);
static struct usb_driver af9035_usb_driver = {
.name = KBUILD_MODNAME,
.id_table = af9035_id_table,
- .probe = dvb_usbv2_probe,
+ .probe = af9035_probe,
.disconnect = dvb_usbv2_disconnect,
.suspend = dvb_usbv2_suspend,
.resume = dvb_usbv2_resume,
@@ -1334,4 +1511,5 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Afatech AF9035 driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
-MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index 29f3eec22c2c..b5827ca3a01e 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -30,6 +30,7 @@
#include "mxl5007t.h"
#include "tda18218.h"
#include "fc2580.h"
+#include "tuner_it913x.h"
struct reg_val {
u32 reg;
@@ -52,12 +53,18 @@ struct usb_req {
};
struct state {
+#define BUF_LEN 64
+ u8 buf[BUF_LEN];
u8 seq; /* packet sequence number */
- bool dual_mode;
+ u8 prechip_version;
+ u8 chip_version;
+ u16 chip_type;
+ u8 dual_mode:1;
+ u16 eeprom_addr;
struct af9033_config af9033_config[2];
};
-u32 clock_lut[] = {
+static const u32 clock_lut_af9035[] = {
20480000, /* FPGA */
16384000, /* 16.38 MHz */
20480000, /* 20.48 MHz */
@@ -72,7 +79,7 @@ u32 clock_lut[] = {
12000000, /* 12.00 MHz */
};
-u32 clock_lut_it9135[] = {
+static const u32 clock_lut_it9135[] = {
12000000, /* 12.00 MHz */
20480000, /* 20.48 MHz */
36000000, /* 36.00 MHz */
@@ -86,19 +93,31 @@ u32 clock_lut_it9135[] = {
};
#define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
-#define AF9035_FIRMWARE_IT9135 "dvb-usb-it9135-01.fw"
+#define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
+#define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
-/* EEPROM locations */
-#define EEPROM_IR_MODE 0x430d
-#define EEPROM_DUAL_MODE 0x4326
-#define EEPROM_2ND_DEMOD_ADDR 0x4327
-#define EEPROM_IR_TYPE 0x4329
-#define EEPROM_1_IFFREQ_L 0x432d
-#define EEPROM_1_IFFREQ_H 0x432e
-#define EEPROM_1_TUNER_ID 0x4331
-#define EEPROM_2_IFFREQ_L 0x433d
-#define EEPROM_2_IFFREQ_H 0x433e
-#define EEPROM_2_TUNER_ID 0x4341
+/*
+ * eeprom is memory mapped as read only. Writing that memory mapped address
+ * will not corrupt eeprom.
+ *
+ * eeprom has value 0x00 single mode and 0x03 for dual mode as far as I have
+ * seen to this day.
+ */
+
+#define EEPROM_BASE_AF9035 0x42fd
+#define EEPROM_BASE_IT9135 0x499c
+#define EEPROM_SHIFT 0x10
+
+#define EEPROM_IR_MODE 0x10
+#define EEPROM_DUAL_MODE 0x29
+#define EEPROM_2ND_DEMOD_ADDR 0x2a
+#define EEPROM_IR_TYPE 0x2c
+#define EEPROM_1_IF_L 0x30
+#define EEPROM_1_IF_H 0x31
+#define EEPROM_1_TUNER_ID 0x34
+#define EEPROM_2_IF_L 0x40
+#define EEPROM_2_IF_H 0x41
+#define EEPROM_2_TUNER_ID 0x44
/* USB commands */
#define CMD_MEM_RD 0x00
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index a20d691d0b63..90cfa35ef6e6 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -45,25 +45,24 @@
#include "cxd2820r.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static DEFINE_MUTEX(anysee_usb_mutex);
-static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
- u8 *rbuf, u8 rlen)
+static int anysee_ctrl_msg(struct dvb_usb_device *d,
+ u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen)
{
struct anysee_state *state = d_to_priv(d);
int act_len, ret, i;
- u8 buf[64];
- memcpy(&buf[0], sbuf, slen);
- buf[60] = state->seq++;
+ mutex_lock(&d->usb_mutex);
- mutex_lock(&anysee_usb_mutex);
+ memcpy(&state->buf[0], sbuf, slen);
+ state->buf[60] = state->seq++;
- dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, buf);
+ dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf);
/* We need receive one message more after dvb_usb_generic_rw due
to weird transaction flow, which is 1 x send + 2 x receive. */
- ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf));
+ ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf),
+ state->buf, sizeof(state->buf));
if (ret)
goto error_unlock;
@@ -82,20 +81,19 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
for (i = 0; i < 3; i++) {
/* receive 2nd answer */
ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
- d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf),
- &act_len, 2000);
-
+ d->props->generic_bulk_ctrl_endpoint),
+ state->buf, sizeof(state->buf), &act_len, 2000);
if (ret) {
- dev_dbg(&d->udev->dev, "%s: recv bulk message " \
- "failed=%d\n", __func__, ret);
+ dev_dbg(&d->udev->dev,
+ "%s: recv bulk message failed=%d\n",
+ __func__, ret);
} else {
dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
- rlen, buf);
-
- if (buf[63] != 0x4f)
- dev_dbg(&d->udev->dev, "%s: cmd failed\n",
- __func__);
+ rlen, state->buf);
+ if (state->buf[63] != 0x4f)
+ dev_dbg(&d->udev->dev,
+ "%s: cmd failed\n", __func__);
break;
}
}
@@ -109,11 +107,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
/* read request, copy returned data to return buf */
if (rbuf && rlen)
- memcpy(rbuf, buf, rlen);
+ memcpy(rbuf, state->buf, rlen);
error_unlock:
- mutex_unlock(&anysee_usb_mutex);
-
+ mutex_unlock(&d->usb_mutex);
return ret;
}
@@ -638,7 +635,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap_to_priv(adap);
struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
+ int ret = 0;
u8 tmp;
struct i2c_msg msg[2] = {
{
@@ -884,9 +881,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (!adap->fe[0]) {
/* we have no frontend :-( */
ret = -ENODEV;
- dev_err(&d->udev->dev, "%s: Unsupported Anysee version. " \
- "Please report the " \
- "<linux-media@vger.kernel.org>.\n",
+ dev_err(&d->udev->dev,
+ "%s: Unsupported Anysee version. Please report to <linux-media@vger.kernel.org>.\n",
KBUILD_MODNAME);
}
error:
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h
index c1a4273f14ff..8f426d9fc6e1 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.h
+++ b/drivers/media/usb/dvb-usb-v2/anysee.h
@@ -52,8 +52,9 @@ enum cmd {
};
struct anysee_state {
- u8 hw; /* PCB ID */
+ u8 buf[64];
u8 seq;
+ u8 hw; /* PCB ID */
u8 fe_id:1; /* frondend ID */
u8 has_ci:1;
u8 ci_attached:1;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index 70ec80d8be71..44c64ef361bf 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -842,7 +842,7 @@ static int az6007_download_firmware(struct dvb_usb_device *d,
{
pr_debug("Loading az6007 firmware\n");
- return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
+ return cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
}
/* DVB USB Driver stuff */
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 3cac8bd0b116..658c6d47fdff 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -329,13 +329,16 @@ struct dvb_usb_adapter {
u8 feed_count;
u8 max_feed_count;
s8 active_fe;
+#define ADAP_INIT 0
+#define ADAP_SLEEP 1
+#define ADAP_STREAMING 2
+ unsigned long state_bits;
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
struct dvb_demux demux;
struct dvb_net dvb_net;
- struct mutex sync_mutex;
struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
@@ -400,5 +403,9 @@ extern int dvb_usbv2_reset_resume(struct usb_interface *);
/* the generic read/write method for device control */
extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+/* caller must hold lock when locked versions are called */
+extern int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *,
+ u8 *, u16, u8 *, u16);
+extern int dvb_usbv2_generic_write_locked(struct dvb_usb_device *, u8 *, u16);
#endif
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 086792055912..19f6737d9817 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -28,10 +28,11 @@ MODULE_PARM_DESC(disable_rc_polling,
static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
int, 0444);
-MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \
- "PID filter, if any (default: 0)");
+MODULE_PARM_DESC(force_pid_filter_usage,
+ "force all DVB USB devices to use a PID filter, if any (default: 0)");
-static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name)
+static int dvb_usbv2_download_firmware(struct dvb_usb_device *d,
+ const char *name)
{
int ret;
const struct firmware *fw;
@@ -44,10 +45,9 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam
ret = request_firmware(&fw, name, &d->udev->dev);
if (ret < 0) {
- dev_err(&d->udev->dev, "%s: Did not find the firmware file "\
- "'%s'. Please see linux/Documentation/dvb/ " \
- "for more details on firmware-problems. " \
- "Status %d\n", KBUILD_MODNAME, name, ret);
+ dev_err(&d->udev->dev,
+ "%s: Did not find the firmware file '%s'. Please see linux/Documentation/dvb/ for more details on firmware-problems. Status %d\n",
+ KBUILD_MODNAME, name, ret);
goto err;
}
@@ -181,9 +181,9 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
/* initialize a work queue for handling polling */
INIT_DELAYED_WORK(&d->rc_query_work,
dvb_usb_read_remote_control);
- dev_info(&d->udev->dev, "%s: schedule remote query interval " \
- "to %d msecs\n", KBUILD_MODNAME,
- d->rc.interval);
+ dev_info(&d->udev->dev,
+ "%s: schedule remote query interval to %d msecs\n",
+ KBUILD_MODNAME, d->rc.interval);
schedule_delayed_work(&d->rc_query_work,
msecs_to_jiffies(d->rc.interval));
d->rc_polling_active = true;
@@ -253,128 +253,159 @@ static int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
return usb_urb_exitv2(&adap->stream);
}
-static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
- int count)
+static int wait_schedule(void *ptr)
+{
+ schedule();
+
+ return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
struct dvb_usb_device *d = adap_to_d(adap);
- int ret;
- dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \
- "setting pid [%s]: %04x (%04d) at index %d '%s'\n",
+ int ret = 0;
+ struct usb_data_stream_properties stream_props;
+ dev_dbg(&d->udev->dev,
+ "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
__func__, adap->id, adap->active_fe, dvbdmxfeed->type,
adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
- dvbdmxfeed->pid, dvbdmxfeed->index,
- (count == 1) ? "on" : "off");
+ dvbdmxfeed->pid, dvbdmxfeed->index);
+
+ /* wait init is done */
+ wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule,
+ TASK_UNINTERRUPTIBLE);
if (adap->active_fe == -1)
return -EINVAL;
- adap->feed_count += count;
-
- /* stop feeding if it is last pid */
- if (adap->feed_count == 0) {
- dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
-
- if (d->props->streaming_ctrl) {
- ret = d->props->streaming_ctrl(
- adap->fe[adap->active_fe], 0);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
- usb_urb_killv2(&adap->stream);
- goto err_mutex_unlock;
- }
- }
- usb_urb_killv2(&adap->stream);
- mutex_unlock(&adap->sync_mutex);
- }
+ /* skip feed setup if we are already feeding */
+ if (adap->feed_count++ > 0)
+ goto skip_feed_start;
- /* activate the pid on the device pid filter */
- if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->pid_filtering && adap->props->pid_filter) {
- ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
- dvbdmxfeed->pid, (count == 1) ? 1 : 0);
- if (ret < 0)
- dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ /* set 'streaming' status bit */
+ set_bit(ADAP_STREAMING, &adap->state_bits);
+
+ /* resolve input and output streaming parameters */
+ if (d->props->get_stream_config) {
+ memcpy(&stream_props, &adap->props->stream,
+ sizeof(struct usb_data_stream_properties));
+ ret = d->props->get_stream_config(adap->fe[adap->active_fe],
+ &adap->ts_type, &stream_props);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: get_stream_config() failed=%d\n",
KBUILD_MODNAME, ret);
+ } else {
+ stream_props = adap->props->stream;
}
- /* start feeding if it is first pid */
- if (adap->feed_count == 1 && count == 1) {
- struct usb_data_stream_properties stream_props;
- mutex_lock(&adap->sync_mutex);
- dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
+ switch (adap->ts_type) {
+ case DVB_USB_FE_TS_TYPE_204:
+ adap->stream.complete = dvb_usb_data_complete_204;
+ break;
+ case DVB_USB_FE_TS_TYPE_RAW:
+ adap->stream.complete = dvb_usb_data_complete_raw;
+ break;
+ case DVB_USB_FE_TS_TYPE_188:
+ default:
+ adap->stream.complete = dvb_usb_data_complete;
+ break;
+ }
- /* resolve input and output streaming paramters */
- if (d->props->get_stream_config) {
- memcpy(&stream_props, &adap->props->stream,
- sizeof(struct usb_data_stream_properties));
- ret = d->props->get_stream_config(
- adap->fe[adap->active_fe],
- &adap->ts_type, &stream_props);
- if (ret < 0)
- goto err_mutex_unlock;
- } else {
- stream_props = adap->props->stream;
- }
+ /* submit USB streaming packets */
+ usb_urb_submitv2(&adap->stream, &stream_props);
- switch (adap->ts_type) {
- case DVB_USB_FE_TS_TYPE_204:
- adap->stream.complete = dvb_usb_data_complete_204;
- break;
- case DVB_USB_FE_TS_TYPE_RAW:
- adap->stream.complete = dvb_usb_data_complete_raw;
- break;
- case DVB_USB_FE_TS_TYPE_188:
- default:
- adap->stream.complete = dvb_usb_data_complete;
- break;
- }
+ /* enable HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap, 1);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
- usb_urb_submitv2(&adap->stream, &stream_props);
-
- if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->props->caps &
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
- adap->props->pid_filter_ctrl) {
- ret = adap->props->pid_filter_ctrl(adap,
- adap->pid_filtering);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: " \
- "pid_filter_ctrl() failed=%d\n",
- KBUILD_MODNAME, ret);
- goto err_mutex_unlock;
- }
- }
+ /* ask device to start streaming */
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 1);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+skip_feed_start:
- if (d->props->streaming_ctrl) {
- ret = d->props->streaming_ctrl(
- adap->fe[adap->active_fe], 1);
- if (ret < 0) {
- dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
- goto err_mutex_unlock;
- }
- }
+ /* add PID to device HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter) {
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, 1);
+ if (ret)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
}
- return 0;
-err_mutex_unlock:
- mutex_unlock(&adap->sync_mutex);
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ if (ret)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
-static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
-}
-
static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+ dev_dbg(&d->udev->dev,
+ "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n",
+ __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
+ adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+ dvbdmxfeed->pid, dvbdmxfeed->index);
+
+ if (adap->active_fe == -1)
+ return -EINVAL;
+
+ /* remove PID from device HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter) {
+ ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+ dvbdmxfeed->pid, 0);
+ if (ret)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* we cannot stop streaming until last PID is removed */
+ if (--adap->feed_count > 0)
+ goto skip_feed_stop;
+
+ /* ask device to stop streaming */
+ if (d->props->streaming_ctrl) {
+ ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 0);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: streaming_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* disable HW PID filter */
+ if (adap->pid_filtering && adap->props->pid_filter_ctrl) {
+ ret = adap->props->pid_filter_ctrl(adap, 0);
+ if (ret)
+ dev_err(&d->udev->dev,
+ "%s: pid_filter_ctrl() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
+
+ /* kill USB streaming packets */
+ usb_urb_killv2(&adap->stream);
+
+ /* clear 'streaming' status bit */
+ clear_bit(ADAP_STREAMING, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_STREAMING);
+skip_feed_stop:
+
+ if (ret)
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
}
static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
@@ -435,8 +466,6 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
goto err_dvb_net_init;
}
- mutex_init(&adap->sync_mutex);
-
return 0;
err_dvb_net_init:
dvb_dmxdev_release(&adap->dmxdev);
@@ -500,7 +529,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe)
if (!adap->suspend_resume_active) {
adap->active_fe = fe->id;
- mutex_lock(&adap->sync_mutex);
+ set_bit(ADAP_INIT, &adap->state_bits);
}
ret = dvb_usbv2_device_power_ctrl(d, 1);
@@ -519,8 +548,11 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe)
goto err;
}
err:
- if (!adap->suspend_resume_active)
- mutex_unlock(&adap->sync_mutex);
+ if (!adap->suspend_resume_active) {
+ clear_bit(ADAP_INIT, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_INIT);
+ }
dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
return ret;
@@ -534,8 +566,11 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
fe->id);
- if (!adap->suspend_resume_active)
- mutex_lock(&adap->sync_mutex);
+ if (!adap->suspend_resume_active) {
+ set_bit(ADAP_SLEEP, &adap->state_bits);
+ wait_on_bit(&adap->state_bits, ADAP_STREAMING, wait_schedule,
+ TASK_UNINTERRUPTIBLE);
+ }
if (adap->fe_sleep[fe->id]) {
ret = adap->fe_sleep[fe->id](fe);
@@ -555,7 +590,9 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
err:
if (!adap->suspend_resume_active) {
adap->active_fe = -1;
- mutex_unlock(&adap->sync_mutex);
+ clear_bit(ADAP_SLEEP, &adap->state_bits);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&adap->state_bits, ADAP_SLEEP);
}
dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret);
@@ -574,8 +611,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
if (d->props->frontend_attach) {
ret = d->props->frontend_attach(adap);
if (ret < 0) {
- dev_dbg(&d->udev->dev, "%s: frontend_attach() " \
- "failed=%d\n", __func__, ret);
+ dev_dbg(&d->udev->dev,
+ "%s: frontend_attach() failed=%d\n",
+ __func__, ret);
goto err_dvb_frontend_detach;
}
} else {
@@ -595,8 +633,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
if (ret < 0) {
- dev_err(&d->udev->dev, "%s: frontend%d registration " \
- "failed\n", KBUILD_MODNAME, i);
+ dev_err(&d->udev->dev,
+ "%s: frontend%d registration failed\n",
+ KBUILD_MODNAME, i);
goto err_dvb_unregister_frontend;
}
@@ -670,33 +709,33 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d)
/* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL &&
!(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
- dev_err(&d->udev->dev, "%s: this USB2.0 device " \
- "cannot be run on a USB1.1 port (it " \
- "lacks a hardware PID filter)\n",
+ dev_err(&d->udev->dev,
+ "%s: this USB2.0 device cannot be run on a USB1.1 port (it lacks a hardware PID filter)\n",
KBUILD_MODNAME);
ret = -ENODEV;
goto err;
} else if ((d->udev->speed == USB_SPEED_FULL &&
adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
- dev_info(&d->udev->dev, "%s: will use the device's " \
- "hardware PID filter " \
- "(table count: %d)\n", KBUILD_MODNAME,
+ dev_info(&d->udev->dev,
+ "%s: will use the device's hardware PID filter (table count: %d)\n",
+ KBUILD_MODNAME,
adap->props->pid_filter_count);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props->pid_filter_count;
} else {
- dev_info(&d->udev->dev, "%s: will pass the complete " \
- "MPEG2 transport stream to the " \
- "software demuxer\n", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: will pass the complete MPEG2 transport stream to the software demuxer\n",
+ KBUILD_MODNAME);
adap->pid_filtering = 0;
adap->max_feed_count = 255;
}
if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage &&
adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
- dev_info(&d->udev->dev, "%s: PID filter enabled by " \
- "module option\n", KBUILD_MODNAME);
+ dev_info(&d->udev->dev,
+ "%s: PID filter enabled by module option\n",
+ KBUILD_MODNAME);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props->pid_filter_count;
}
@@ -825,8 +864,9 @@ static void dvb_usbv2_init_work(struct work_struct *work)
if (ret == 0) {
;
} else if (ret == COLD) {
- dev_info(&d->udev->dev, "%s: found a '%s' in cold " \
- "state\n", KBUILD_MODNAME, d->name);
+ dev_info(&d->udev->dev,
+ "%s: found a '%s' in cold state\n",
+ KBUILD_MODNAME, d->name);
if (!name)
name = d->props->firmware;
@@ -868,8 +908,9 @@ static void dvb_usbv2_init_work(struct work_struct *work)
if (ret < 0)
goto err_usb_driver_release_interface;
- dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \
- "connected\n", KBUILD_MODNAME, d->name);
+ dev_info(&d->udev->dev,
+ "%s: '%s' successfully initialized and connected\n",
+ KBUILD_MODNAME, d->name);
return;
err_usb_driver_release_interface:
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
index 5716662b4834..33ff97e708e3 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -21,8 +21,8 @@
#include "dvb_usb_common.h"
-int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
- u16 rlen)
+static int dvb_usb_v2_generic_io(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
{
int ret, actual_length;
@@ -32,8 +32,6 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
return -EINVAL;
}
- mutex_lock(&d->usb_mutex);
-
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
@@ -56,20 +54,51 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
d->props->generic_bulk_ctrl_endpoint_response),
rbuf, rlen, &actual_length, 2000);
if (ret)
- dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \
- "failed=%d\n", KBUILD_MODNAME, ret);
+ dev_err(&d->udev->dev,
+ "%s: 2nd usb_bulk_msg() failed=%d\n",
+ KBUILD_MODNAME, ret);
dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__,
actual_length, rbuf);
}
+ return ret;
+}
+
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
mutex_unlock(&d->usb_mutex);
+
return ret;
}
EXPORT_SYMBOL(dvb_usbv2_generic_rw);
int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
{
- return dvb_usbv2_generic_rw(d, buf, len, NULL, 0);
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
}
EXPORT_SYMBOL(dvb_usbv2_generic_write);
+
+int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *d,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ return dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw_locked);
+
+int dvb_usbv2_generic_write_locked(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+ return dvb_usb_v2_generic_io(d, buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write_locked);
diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c
index 833847995c65..e48cdeb9df41 100644
--- a/drivers/media/usb/dvb-usb-v2/it913x.c
+++ b/drivers/media/usb/dvb-usb-v2/it913x.c
@@ -218,6 +218,7 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
deb_info(1, "PID_C (%02x)", onoff);
+ st->pid_filter_onoff = adap->pid_filtering;
ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff);
mutex_unlock(&d->i2c_mutex);
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index f30c58cecbba..b3fd0ffa3c3f 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -1241,10 +1241,13 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
struct usb_data_stream_properties *stream)
{
struct dvb_usb_adapter *adap = fe_to_adap(fe);
- struct dvb_usb_device *d = adap_to_d(adap);
+ struct dvb_usb_device *d;
if (adap == NULL)
return 0;
+
+ d = adap_to_d(adap);
+
/* Turn PID filter on the fly by module option */
if (pid_filter == 2) {
adap->pid_filtering = 1;
@@ -1299,8 +1302,7 @@ static void lme2510_exit(struct dvb_usb_device *d)
if (d != NULL) {
usb_buffer = lme2510_exit_int(d);
- if (usb_buffer != NULL)
- kfree(usb_buffer);
+ kfree(usb_buffer);
}
}
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 432706ae5274..3f3f8bfd190b 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -21,6 +21,7 @@
#ifndef __MXL111SF_DEMOD_H__
#define __MXL111SF_DEMOD_H__
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
#include "mxl111sf.h"
@@ -31,8 +32,7 @@ struct mxl111sf_demod_config {
struct mxl111sf_reg_ctrl_info *ctrl_reg_info);
};
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
- (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
struct mxl111sf_demod_config *cfg);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index ff333960b184..90f583e5d6a6 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -21,8 +21,8 @@
#ifndef __MXL111SF_TUNER_H__
#define __MXL111SF_TUNER_H__
+#include <linux/kconfig.h>
#include "dvb_frontend.h"
-
#include "mxl111sf.h"
enum mxl_if_freq {
@@ -60,8 +60,7 @@ struct mxl111sf_tuner_config {
/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_DVB_USB_MXL111SF) || \
- (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
struct mxl111sf_state *mxl_state,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index d98387a3c95e..22015fe1a0f3 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -33,6 +33,7 @@
#include "e4000.h"
#include "fc2580.h"
#include "tua9001.h"
+#include "r820t.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -375,6 +376,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
+ struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf};
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -479,6 +481,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
goto found;
}
+ /* check R820T by reading tuner stats at I2C addr 0x1a */
+ ret = rtl28xxu_ctrl_msg(d, &req_r820t);
+ if (ret == 0) {
+ priv->tuner = TUNER_RTL2832_R820T;
+ priv->tuner_name = "R820T";
+ goto found;
+ }
+
found:
dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
@@ -589,6 +599,12 @@ static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
.tuner = TUNER_RTL2832_E4000,
};
+static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
+ .i2c_addr = 0x10,
+ .xtal = 28800000,
+ .tuner = TUNER_RTL2832_R820T,
+};
+
static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
int cmd, int arg)
{
@@ -728,6 +744,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
case TUNER_RTL2832_E4000:
rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
break;
+ case TUNER_RTL2832_R820T:
+ rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
+ break;
default:
dev_err(&d->udev->dev, "%s: unknown tuner=%s\n",
KBUILD_MODNAME, priv->tuner_name);
@@ -840,6 +859,13 @@ static const struct fc0012_config rtl2832u_fc0012_config = {
.xtal_freq = FC_XTAL_28_8_MHZ,
};
+static const struct r820t_config rtl2832u_r820t_config = {
+ .i2c_addr = 0x1a,
+ .xtal = 28800000,
+ .max_i2c_msg_len = 2,
+ .rafael_chip = CHIP_R820T,
+};
+
static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
@@ -889,6 +915,14 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap,
&rtl2832u_tua9001_config);
break;
+ case TUNER_RTL2832_R820T:
+ fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ &rtl2832u_r820t_config);
+
+ /* Use tuner to get the signal strength */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+ break;
default:
fe = NULL;
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
@@ -1372,6 +1406,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Digivox Micro Hd", NULL) },
{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
&rtl2832u_props, "Compro VideoMate U620F", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
+ &rtl2832u_props, "MaxMedia HU394-T", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 2f3af2d3b6ce..533a33127289 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -82,6 +82,7 @@ enum rtl28xxu_tuner {
TUNER_RTL2832_E4000,
TUNER_RTL2832_TDA18272,
TUNER_RTL2832_FC0013,
+ TUNER_RTL2832_R820T,
};
struct rtl28xxu_req {
diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c
index 7346f85f3f2f..ca8f3c2b1082 100644
--- a/drivers/media/usb/dvb-usb-v2/usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c
@@ -22,8 +22,8 @@ static void usb_urb_complete(struct urb *urb)
int i;
u8 *b;
- dev_dbg_ratelimited(&stream->udev->dev, "%s: %s urb completed " \
- "status=%d length=%d/%d pack_num=%d errors=%d\n",
+ dev_dbg_ratelimited(&stream->udev->dev,
+ "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n",
__func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
urb->status, urb->actual_length,
urb->transfer_buffer_length,
@@ -49,8 +49,8 @@ static void usb_urb_complete(struct urb *urb)
case PIPE_ISOCHRONOUS:
for (i = 0; i < urb->number_of_packets; i++) {
if (urb->iso_frame_desc[i].status != 0)
- dev_dbg(&stream->udev->dev, "%s: iso frame " \
- "descriptor has an error=%d\n",
+ dev_dbg(&stream->udev->dev,
+ "%s: iso frame descriptor has an error=%d\n",
__func__,
urb->iso_frame_desc[i].status);
else if (urb->iso_frame_desc[i].actual_length > 0)
@@ -67,8 +67,9 @@ static void usb_urb_complete(struct urb *urb)
stream->complete(stream, b, urb->actual_length);
break;
default:
- dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \
- "completition handler\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: unknown endpoint type in completition handler\n",
+ KBUILD_MODNAME);
return;
}
usb_submit_urb(urb, GFP_ATOMIC);
@@ -101,8 +102,8 @@ int usb_urb_submitv2(struct usb_data_stream *stream,
dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
if (ret) {
- dev_err(&stream->udev->dev, "%s: could not submit " \
- "urb no. %d - get them all back\n",
+ dev_err(&stream->udev->dev,
+ "%s: could not submit urb no. %d - get them all back\n",
KBUILD_MODNAME, i);
usb_urb_killv2(stream);
return ret;
@@ -229,8 +230,9 @@ static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
stream->buf_num = 0;
stream->buf_size = size;
- dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \
- "streaming\n", __func__, num * size);
+ dev_dbg(&stream->udev->dev,
+ "%s: all in all I will use %lu bytes for streaming\n",
+ __func__, num * size);
for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
stream->buf_list[stream->buf_num] = usb_alloc_coherent(
@@ -274,8 +276,8 @@ int usb_urb_reconfig(struct usb_data_stream *stream,
}
if (stream->buf_num < props->count || stream->buf_size < buf_size) {
- dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \
- "allocated buffers are too small\n",
+ dev_err(&stream->udev->dev,
+ "%s: cannot reconfigure as allocated buffers are too small\n",
KBUILD_MODNAME);
return -EINVAL;
}
@@ -321,8 +323,9 @@ int usb_urb_initv2(struct usb_data_stream *stream,
memcpy(&stream->props, props, sizeof(*props));
if (!stream->complete) {
- dev_err(&stream->udev->dev, "%s: there is no data callback - " \
- "this doesn't make sense\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: there is no data callback - this doesn't make sense\n",
+ KBUILD_MODNAME);
return -EINVAL;
}
@@ -343,8 +346,9 @@ int usb_urb_initv2(struct usb_data_stream *stream,
return usb_urb_alloc_isoc_urbs(stream);
default:
- dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \
- "transfer\n", KBUILD_MODNAME);
+ dev_err(&stream->udev->dev,
+ "%s: unknown urb-type for data transfer\n",
+ KBUILD_MODNAME);
return -EINVAL;
}
}
diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
index 1efc028a76c9..c890fe46acd3 100644
--- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c
+++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c
@@ -300,8 +300,7 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
static void cinergyt2_fe_release(struct dvb_frontend *fe)
{
struct cinergyt2_fe_state *state = fe->demodulator_priv;
- if (state != NULL)
- kfree(state);
+ kfree(state);
}
static struct dvb_frontend_ops cinergyt2_fe_ops;
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 11798426fa88..f08136052f9c 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1431,13 +1431,22 @@ static int dib8090_get_adc_power(struct dvb_frontend *fe)
return dib8000_get_adc_power(fe, 1);
}
+static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
+{
+ deb_info("AGC control callback: %i\n", restart);
+ dib0090_dcc_freq(fe, restart);
+
+ if (restart == 0) /* before AGC startup */
+ dib0090_set_dc_servo(fe, 1);
+}
+
static struct dib8000_config dib809x_dib8000_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1456,7 +1465,7 @@ static struct dib8000_config dib809x_dib8000_config[2] = {
.agc_config_count = 2,
.agc = dib8090_agc_config,
- .agc_control = dib0090_dcc_freq,
+ .agc_control = dib8090_agc_control,
.pll = &dib8090_pll_config_12mhz,
.tuner_is_baseband = 1,
@@ -1504,28 +1513,89 @@ static struct dib0090_config dib809x_dib0090_config = {
.fref_clock_ratio = 6,
};
+static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe)
+{
+ u8 optimal_pll_ratio = 20;
+ u32 freq_adc, ratio, rest, max = 0;
+ u8 pll_ratio;
+
+ for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) {
+ freq_adc = 12 * pll_ratio * (1 << 8) / 16;
+ ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc;
+ rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc;
+
+ if (rest > freq_adc / 2)
+ rest = freq_adc - rest;
+ deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest);
+ if ((rest > max) && (rest > 717)) {
+ optimal_pll_ratio = pll_ratio;
+ max = rest;
+ }
+ }
+ deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio);
+
+ return optimal_pll_ratio;
+}
+
static int dib8096_set_param_override(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
- u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
- u16 target;
+ u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000);
+ u16 target, ltgain, rf_gain_limit;
+ u32 timf;
int ret = 0;
enum frontend_tune_state tune_state = CT_SHUTDOWN;
- u16 ltgain, rf_gain_limit;
+
+ switch (band) {
+ default:
+ deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
+ case BAND_VHF:
+ dib8000_set_gpio(fe, 3, 0, 1);
+ break;
+ case BAND_UHF:
+ dib8000_set_gpio(fe, 3, 0, 0);
+ break;
+ }
ret = state->set_param_save(fe);
if (ret < 0)
return ret;
- target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
- dib8000_set_wbd_ref(fe, target);
+ if (fe->dtv_property_cache.bandwidth_hz != 6000000) {
+ deb_info("only 6MHz bandwidth is supported\n");
+ return -EINVAL;
+ }
+
+ /** Update PLL if needed ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+
+ /** Get optimize PLL ratio to remove spurious **/
+ pll_ratio = dib8090_compute_pll_parameters(fe);
+ if (pll_ratio == 17)
+ timf = 21387946;
+ else if (pll_ratio == 18)
+ timf = 20199727;
+ else if (pll_ratio == 19)
+ timf = 19136583;
+ else
+ timf = 18179756;
+
+ /** Update ratio **/
+ dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf);
+
+ if (band != BAND_CBAND) {
+ /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
+ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
+ dib8000_set_wbd_ref(fe, target);
+ }
if (band == BAND_CBAND) {
deb_info("tuning in CBAND - soft-AGC startup\n");
dib0090_set_tune_state(fe, CT_AGC_START);
+
do {
ret = dib0090_gain_control(fe);
msleep(ret);
@@ -1534,14 +1604,17 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
dib8000_set_gpio(fe, 6, 0, 1);
else if (tune_state == CT_AGC_STEP_1) {
dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
- if (rf_gain_limit == 0)
+ if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
dib8000_set_gpio(fe, 6, 0, 0);
}
} while (tune_state < CT_AGC_STOP);
+
+ deb_info("switching to PWM AGC\n");
dib0090_pwm_gain_reset(fe);
dib8000_pwm_agc_reset(fe);
dib8000_set_tune_state(fe, CT_DEMOD_START);
} else {
+ /* for everything else than CBAND we are using standard AGC */
deb_info("not tuning in CBAND - standard AGC startup\n");
dib0090_pwm_gain_reset(fe);
}
@@ -1814,21 +1887,92 @@ struct dibx090p_adc {
u32 pll_prediv; /* New loopdiv */
};
-struct dibx090p_adc dib8090p_adc_tab[] = {
- { 50000, 17043521, 16, 3}, /* 64 MHz */
- {878000, 20199729, 9, 1}, /* 60 MHz */
- {0xffffffff, 0, 0, 0}, /* 60 MHz */
+struct dibx090p_best_adc {
+ u32 timf;
+ u32 pll_loopdiv;
+ u32 pll_prediv;
};
+static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc)
+{
+ u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+ u16 xtal = 12000;
+ u16 fcp_min = 1900; /* PLL, Minimum Frequency of phase comparator (KHz) */
+ u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */
+ u32 fmem_max = 140000; /* 140MHz max SDRAM freq */
+ u32 fdem_min = 66000;
+ u32 fcp = 0, fs = 0, fdem = 0, fmem = 0;
+ u32 harmonic_id = 0;
+
+ adc->timf = 0;
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+
+ deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz);
+
+ /* Find Min and Max prediv */
+ while ((xtal / max_prediv) >= fcp_min)
+ max_prediv++;
+
+ max_prediv--;
+ min_prediv = max_prediv;
+ while ((xtal / min_prediv) <= fcp_max) {
+ min_prediv--;
+ if (min_prediv == 1)
+ break;
+ }
+ deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+ min_prediv = 1;
+
+ for (prediv = min_prediv; prediv < max_prediv; prediv++) {
+ fcp = xtal / prediv;
+ if (fcp > fcp_min && fcp < fcp_max) {
+ for (loopdiv = 1; loopdiv < 64; loopdiv++) {
+ fmem = ((xtal/prediv) * loopdiv);
+ fdem = fmem / 2;
+ fs = fdem / 4;
+
+ /* test min/max system restrictions */
+ if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) {
+ spur = 0;
+ /* test fs harmonics positions */
+ for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs)); harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) {
+ if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) && ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) {
+ spur = 1;
+ break;
+ }
+ }
+
+ if (!spur) {
+ adc->pll_loopdiv = loopdiv;
+ adc->pll_prediv = prediv;
+ adc->timf = (4260880253U / fdem) * (1 << 8);
+ adc->timf += ((4260880253U % fdem) << 8) / fdem;
+
+ deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf);
+ break;
+ }
+ }
+ }
+ }
+ if (!spur)
+ break;
+ }
+
+ if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0)
+ return -EINVAL;
+ return 0;
+}
+
static int dib8096p_agc_startup(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct dvb_usb_adapter *adap = fe->dvb->priv;
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
+ struct dibx090p_best_adc adc;
u16 target;
- int better_sampling_freq = 0, ret;
- struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0];
+ int ret;
ret = state->set_param_save(fe);
if (ret < 0)
@@ -1841,23 +1985,27 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe)
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
dib8000_set_wbd_ref(fe, target);
+ if (dib8096p_get_best_sampling(fe, &adc) == 0) {
+ pll.pll_ratio = adc.pll_loopdiv;
+ pll.pll_prediv = adc.pll_prediv;
- while (p->frequency / 1000 > adc_table->freq) {
- better_sampling_freq = 1;
- adc_table++;
- }
-
- if ((adc_table->freq != 0xffffffff) && better_sampling_freq) {
- pll.pll_ratio = adc_table->pll_loopdiv;
- pll.pll_prediv = adc_table->pll_prediv;
- dib8000_update_pll(fe, &pll);
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf);
+ dib0700_set_i2c_speed(adap->dev, 200);
+ dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+ dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+ dib0700_set_i2c_speed(adap->dev, 1000);
}
return 0;
}
static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_state *st = adap->dev->priv;
+ u32 fw_version;
+
+ dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+ if (fw_version >= 0x10200)
+ st->fw_use_new_i2c_api = 1;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(20);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -2242,13 +2390,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
}
/* NIM7090 */
-struct dib7090p_best_adc {
- u32 timf;
- u32 pll_loopdiv;
- u32 pll_prediv;
-};
-
-static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dibx090p_best_adc *adc)
{
u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
@@ -2327,7 +2469,7 @@ static int dib7090_agc_startup(struct dvb_frontend *fe)
struct dib0700_adapter_state *state = adap->priv;
struct dibx000_bandwidth_config pll;
u16 target;
- struct dib7090p_best_adc adc;
+ struct dibx090p_best_adc adc;
int ret;
ret = state->set_param_save(fe);
@@ -2357,36 +2499,16 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
return 0;
}
-static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global)
+static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global)
{
- u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1;
- s16 wbd_delta;
+ deb_info("update LNA: agc global=%i", agc_global);
- if ((fe->dtv_property_cache.frequency) < 400000000)
- threshold_agc1 = 25000;
- else
- threshold_agc1 = 30000;
-
- wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2;
- wbd_offset = dib0090_get_wbd_offset(fe);
- dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd);
- wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ;
-
- deb_info("update lna, agc_global=%d agc1=%d agc2=%d",
- agc_global, agc1, agc2);
- deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d",
- wbd, wbd_target, wbd_offset, wbd_delta);
-
- if ((agc1 < threshold_agc1) && (wbd_delta > 0)) {
- dib0090_set_switch(fe, 1, 1, 1);
- dib0090_set_vga(fe, 0);
- dib0090_update_rframp_7090(fe, 0);
- dib0090_update_tuning_table_7090(fe, 0);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 8, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
} else {
- dib0090_set_vga(fe, 1);
- dib0090_update_rframp_7090(fe, 1);
- dib0090_update_tuning_table_7090(fe, 1);
- dib0090_set_switch(fe, 0, 0, 0);
+ dib7000p_set_gpio(fe, 8, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
}
return 0;
@@ -2400,15 +2522,6 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = {
{ 0xFFFF, 0, 0, 0, 0, 0},
};
-static struct dib0090_wbd_slope dib7090e_wbd_table[] = {
- { 380, 81, 850, 64, 540, 4},
- { 700, 51, 866, 21, 320, 4},
- { 860, 48, 666, 18, 330, 6},
- {1700, 0, 250, 0, 100, 6},
- {2600, 0, 250, 0, 100, 6},
- { 0xFFFF, 0, 0, 0, 0, 0},
-};
-
static struct dibx000_agc_config dib7090_agc_config[2] = {
{
.band_caps = BAND_UHF,
@@ -2428,7 +2541,7 @@ static struct dibx000_agc_config dib7090_agc_config[2] = {
.wbd_alpha = 5,
.agc1_max = 65535,
- .agc1_min = 0,
+ .agc1_min = 32768,
.agc2_max = 65535,
.agc2_min = 0,
@@ -2505,7 +2618,7 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7790p_update_lna, /* GPIO used is the same as TFE7790 */
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2529,12 +2642,26 @@ static struct dib7000p_config nim7090_dib7000p_config = {
.enMpegOutput = 1,
};
+static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global)
+{
+ deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global);
+ if (agc_global < 25000) {
+ dib7000p_set_gpio(fe, 5, 0, 0);
+ dib7000p_set_agc1_min(fe, 0);
+ } else {
+ dib7000p_set_gpio(fe, 5, 0, 1);
+ dib7000p_set_agc1_min(fe, 32768);
+ }
+
+ return 0;
+}
+
static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
{
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2561,7 +2688,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = NULL,
+ .update_lna = tfe7090p_pvr_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2587,34 +2714,6 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
}
};
-static struct dib7000p_config tfe7090e_dib7000p_config = {
- .output_mpeg2_in_188_bytes = 1,
- .hostbus_diversity = 1,
- .tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
-
- .agc_config_count = 2,
- .agc = dib7090_agc_config,
-
- .bw = &dib7090_clock_config_12_mhz,
-
- .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
- .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
- .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
-
- .pwm_freq_div = 0,
-
- .agc_control = dib7090_agc_restart,
-
- .spur_protect = 0,
- .disable_sample_and_hold = 0,
- .enable_current_mirror = 0,
- .diversity_delay = 0,
-
- .output_mode = OUTMODE_MPEG2_FIFO,
- .enMpegOutput = 1,
-};
-
static const struct dib0090_config nim7090_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
@@ -2649,47 +2748,11 @@ static const struct dib0090_config nim7090_dib0090_config = {
.in_soc = 1,
};
-static const struct dib0090_config tfe7090e_dib0090_config = {
- .io.clock_khz = 12000,
- .io.pll_bypass = 0,
- .io.pll_range = 0,
- .io.pll_prediv = 3,
- .io.pll_loopdiv = 6,
- .io.adc_clock_ratio = 0,
- .io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
-
- .freq_offset_khz_uhf = 0,
- .freq_offset_khz_vhf = 0,
-
- .get_adc_power = dib7090_get_adc_power,
-
- .clkouttobamse = 1,
- .analog_output = 0,
-
- .wbd_vhf_offset = 0,
- .wbd_cband_offset = 0,
- .use_pwm_agc = 1,
- .clkoutdrive = 0,
-
- .fref_clock_ratio = 0,
-
- .wbd = dib7090e_wbd_table,
-
- .ls_cfg_pad_drv = 0,
- .data_tx_drv = 0,
- .low_if = NULL,
- .in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
-};
-
-static struct dib7000p_config tfe7790e_dib7000p_config = {
+static struct dib7000p_config tfe7790p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
.hostbus_diversity = 1,
.tuner_is_baseband = 1,
- .update_lna = dib7090e_update_lna,
+ .update_lna = tfe7790p_update_lna,
.agc_config_count = 2,
.agc = dib7090_agc_config,
@@ -2713,7 +2776,7 @@ static struct dib7000p_config tfe7790e_dib7000p_config = {
.enMpegOutput = 1,
};
-static const struct dib0090_config tfe7790e_dib0090_config = {
+static const struct dib0090_config tfe7790p_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -2739,14 +2802,14 @@ static const struct dib0090_config tfe7790e_dib0090_config = {
.fref_clock_ratio = 0,
- .wbd = dib7090e_wbd_table,
+ .wbd = dib7090_wbd_table,
.ls_cfg_pad_drv = 0,
.data_tx_drv = 0,
.low_if = NULL,
.in_soc = 1,
- .force_cband_input = 1,
- .is_dib7090e = 1,
+ .force_cband_input = 0,
+ .is_dib7090e = 0,
.force_crystal_mode = 1,
};
@@ -2942,37 +3005,11 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap)
-{
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
-
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
- msleep(20);
- dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
-
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7090e_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
- __func__);
- return -ENODEV;
- }
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7090e_dib7000p_config);
-
- return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
- /* The TFE7790E requires the dib0700 to not be in master mode */
+ /* The TFE7790P requires the dib0700 to not be in master mode */
st->disable_streaming_master_mode = 1;
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
@@ -2988,42 +3025,25 @@ static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
- 1, 0x10, &tfe7790e_dib7000p_config) != 0) {
+ 1, 0x10, &tfe7790p_dib7000p_config) != 0) {
err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
__func__);
return -ENODEV;
}
adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
- 0x80, &tfe7790e_dib7000p_config);
+ 0x80, &tfe7790p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
-static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap)
-{
- struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c =
- dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
-
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7790e_dib0090_config) == NULL)
- return -ENODEV;
-
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
-
- st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
- adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
- return 0;
-}
-
-static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap)
+static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c =
dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
- &tfe7090e_dib0090_config) == NULL)
+ &tfe7790p_dib0090_config) == NULL)
return -ENODEV;
dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
@@ -3566,10 +3586,9 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) },
-/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
- { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790P) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
+/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3880,7 +3899,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Elgato EyeTV DTT rev. 2",
- { &dib0700_usb_id_table[81], NULL },
+ { &dib0700_usb_id_table[80], NULL },
{ NULL },
},
},
@@ -4697,48 +4716,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7090e_frontend_attach,
- .tuner_attach = tfe7090e_tuner_attach,
-
- DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
- } },
-
- .size_of_priv =
- sizeof(struct dib0700_adapter_state),
- },
- },
-
- .num_device_descs = 1,
- .devices = {
- { "DiBcom TFE7090E reference design",
- { &dib0700_usb_id_table[78], NULL },
- { NULL },
- },
- },
-
- .rc.core = {
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .module_name = "dib0700",
- .rc_query = dib0700_rc_query_old_firmware,
- .allowed_protos = RC_BIT_RC5 |
- RC_BIT_RC6_MCE |
- RC_BIT_NEC,
- .change_protocol = dib0700_change_protocol,
- },
- }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
- .num_adapters = 1,
- .adapter = {
- {
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
- .pid_filter_count = 32,
- .pid_filter = stk70x0p_pid_filter,
- .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = tfe7790e_frontend_attach,
- .tuner_attach = tfe7790e_tuner_attach,
+ .frontend_attach = tfe7790p_frontend_attach,
+ .tuner_attach = tfe7790p_tuner_attach,
DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
} },
@@ -4750,8 +4729,8 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.num_device_descs = 1,
.devices = {
- { "DiBcom TFE7790E reference design",
- { &dib0700_usb_id_table[79], NULL },
+ { "DiBcom TFE7790P reference design",
+ { &dib0700_usb_id_table[78], NULL },
{ NULL },
},
},
@@ -4792,7 +4771,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.num_device_descs = 1,
.devices = {
{ "DiBcom TFE8096P reference design",
- { &dib0700_usb_id_table[80], NULL },
+ { &dib0700_usb_id_table[79], NULL },
{ NULL },
},
},
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index af0d4321845b..c2dded92f1d3 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -8,6 +8,8 @@
*
* see Documentation/dvb/README.dvb-usb for more information
*/
+
+#include <linux/kconfig.h>
#include "dibusb.h"
static int debug;
@@ -232,8 +234,7 @@ static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
.agc2_slope2 = 0x1e,
};
-#if defined(CONFIG_DVB_DIB3000MC) || \
- (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_DVB_DIB3000MC)
static struct dib3000mc_config mod3000p_dib3000p_config = {
&dib3000p_panasonic_agc_config,
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 9578a6761f1b..6e237b6dd0a8 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -29,7 +29,6 @@
#include "stb6100.h"
#include "stb6100_proc.h"
#include "m88rs2000.h"
-#include "ts2020.h"
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@@ -79,6 +78,10 @@
#define USB_PID_TEVII_S632 0xd632
#endif
+#ifndef USB_PID_GOTVIEW_SAT_HD
+#define USB_PID_GOTVIEW_SAT_HD 0x5456
+#endif
+
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@@ -1548,6 +1551,8 @@ enum dw2102_table_entry {
X3M_SPC1400HD,
TEVII_S421,
TEVII_S632,
+ TERRATEC_CINERGY_S2_R2,
+ GOTVIEW_SAT_HD,
};
static struct usb_device_id dw2102_table[] = {
@@ -1568,6 +1573,8 @@ static struct usb_device_id dw2102_table[] = {
[X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)},
[TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)},
[TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
+ [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
+ [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
{ }
};
@@ -1968,7 +1975,7 @@ static struct dvb_usb_device_properties su3000_properties = {
}},
}
},
- .num_device_descs = 3,
+ .num_device_descs = 5,
.devices = {
{ "SU3000HD DVB-S USB2.0",
{ &dw2102_table[GENIATECH_SU3000], NULL },
@@ -1982,6 +1989,14 @@ static struct dvb_usb_device_properties su3000_properties = {
{ &dw2102_table[X3M_SPC1400HD], NULL },
{ NULL },
},
+ { "Terratec Cinergy S2 USB HD Rev.2",
+ { &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL },
+ { NULL },
+ },
+ { "GOTVIEW Satellite HD",
+ { &dw2102_table[GOTVIEW_SAT_HD], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 92afeb20650f..c2b635d6a17a 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -68,20 +68,20 @@ static inline int m920x_write_seq(struct usb_device *udev, u8 request,
struct m920x_inits *seq)
{
int ret;
- while (seq->address) {
+ do {
ret = m920x_write(udev, request, seq->data, seq->address);
if (ret != 0)
return ret;
seq++;
- }
+ } while (seq->address);
- return ret;
+ return 0;
}
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
- int ret = 0, i, epi, flags = 0;
+ int ret, i, epi, flags = 0;
int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
@@ -124,7 +124,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
}
}
- return ret;
+ return 0;
}
static int m920x_init_ep(struct usb_interface *intf)
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index c8a95042dfbc..16ba90acf539 100644
--- a/drivers/media/usb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -151,7 +151,7 @@ static int opera1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
break;
}
if (dvb_usb_opera1_debug & 0x10)
- info("sending i2c mesage %d %d", tmp, msg[i].len);
+ info("sending i2c message %d %d", tmp, msg[i].len);
}
mutex_unlock(&d->i2c_mutex);
return num;
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index c754a80a8d8b..ca5ee6aceb62 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -46,6 +46,7 @@ config VIDEO_EM28XX_DVB
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
---help---
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index 634fb920dd39..ad6d48557940 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,5 +1,5 @@
em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y += em28xx-core.o em28xx-vbi.o
+em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o
em28xx-alsa-objs := em28xx-audio.o
em28xx-rc-objs := em28xx-input.o
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
new file mode 100644
index 000000000000..73cc50afa5e1
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -0,0 +1,434 @@
+/*
+ em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices
+
+ Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@infradead.org>
+ Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/i2c.h>
+#include <media/soc_camera.h>
+#include <media/mt9v011.h>
+#include <media/v4l2-common.h>
+
+#include "em28xx.h"
+
+
+/* Possible i2c addresses of Micron sensors */
+static unsigned short micron_sensor_addrs[] = {
+ 0xb8 >> 1, /* MT9V111, MT9V403 */
+ 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */
+ 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */
+ I2C_CLIENT_END
+};
+
+/* Possible i2c addresses of Omnivision sensors */
+static unsigned short omnivision_sensor_addrs[] = {
+ 0x42 >> 1, /* OV7725, OV7670/60/48 */
+ 0x60 >> 1, /* OV2640, OV9650/53/55 */
+ I2C_CLIENT_END
+};
+
+
+static struct soc_camera_link camlink = {
+ .bus_id = 0,
+ .flags = 0,
+ .module_name = "em28xx",
+};
+
+
+/* FIXME: Should be replaced by a proper mt9m111 driver */
+static int em28xx_initialize_mt9m111(struct em28xx *dev)
+{
+ int i;
+ unsigned char regs[][3] = {
+ { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
+ { 0x0d, 0x00, 0x00, },
+ { 0x0a, 0x00, 0x21, },
+ { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ &regs[i][0], 3);
+
+ return 0;
+}
+
+
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+ int i;
+ unsigned char regs[][3] = {
+ { 0x0d, 0x00, 0x01, },
+ { 0x0d, 0x00, 0x00, },
+ { 0x04, 0x05, 0x00, }, /* hres = 1280 */
+ { 0x03, 0x04, 0x00, }, /* vres = 1024 */
+ { 0x20, 0x11, 0x00, },
+ { 0x06, 0x00, 0x10, },
+ { 0x2b, 0x00, 0x24, },
+ { 0x2e, 0x00, 0x24, },
+ { 0x35, 0x00, 0x24, },
+ { 0x2d, 0x00, 0x20, },
+ { 0x2c, 0x00, 0x20, },
+ { 0x09, 0x0a, 0xd4, },
+ { 0x35, 0x00, 0x57, },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++)
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
+ &regs[i][0], 3);
+
+ return 0;
+}
+
+
+/*
+ * Probes Micron sensors with 8 bit address and 16 bit register width
+ */
+static int em28xx_probe_sensor_micron(struct em28xx *dev)
+{
+ int ret, i;
+ char *name;
+ u8 reg;
+ __be16 id_be;
+ u16 id;
+
+ struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+
+ dev->em28xx_sensor = EM28XX_NOSENSOR;
+ for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) {
+ client.addr = micron_sensor_addrs[i];
+ /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */
+ /* Read chip ID from register 0x00 */
+ reg = 0x00;
+ ret = i2c_master_send(&client, &reg, 1);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = be16_to_cpu(id_be);
+ /* Read chip ID from register 0xff */
+ reg = 0xff;
+ ret = i2c_master_send(&client, &reg, 1);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ ret = i2c_master_recv(&client, (u8 *)&id_be, 2);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ /* Validate chip ID to be sure we have a Micron device */
+ if (id != be16_to_cpu(id_be))
+ continue;
+ /* Check chip ID */
+ id = be16_to_cpu(id_be);
+ switch (id) {
+ case 0x1222:
+ name = "MT9V012"; /* MI370 */ /* 640x480 */
+ break;
+ case 0x1229:
+ name = "MT9V112"; /* 640x480 */
+ break;
+ case 0x1433:
+ name = "MT9M011"; /* 1280x1024 */
+ break;
+ case 0x143a: /* found in the ECS G200 */
+ name = "MT9M111"; /* MI1310 */ /* 1280x1024 */
+ dev->em28xx_sensor = EM28XX_MT9M111;
+ break;
+ case 0x148c:
+ name = "MT9M112"; /* MI1320 */ /* 1280x1024 */
+ break;
+ case 0x1511:
+ name = "MT9D011"; /* MI2010 */ /* 1600x1200 */
+ break;
+ case 0x8232:
+ case 0x8243: /* rev B */
+ name = "MT9V011"; /* MI360 */ /* 640x480 */
+ dev->em28xx_sensor = EM28XX_MT9V011;
+ break;
+ case 0x8431:
+ name = "MT9M001"; /* 1280x1024 */
+ dev->em28xx_sensor = EM28XX_MT9M001;
+ break;
+ default:
+ em28xx_info("unknown Micron sensor detected: 0x%04x\n",
+ id);
+ return 0;
+ }
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR)
+ em28xx_info("unsupported sensor detected: %s\n", name);
+ else
+ em28xx_info("sensor %s detected\n", name);
+
+ dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+/*
+ * Probes Omnivision sensors with 8 bit address and register width
+ */
+static int em28xx_probe_sensor_omnivision(struct em28xx *dev)
+{
+ int ret, i;
+ char *name;
+ u8 reg;
+ u16 id;
+ struct i2c_client client = dev->i2c_client[dev->def_i2c_bus];
+
+ dev->em28xx_sensor = EM28XX_NOSENSOR;
+ /* NOTE: these devices have the register auto incrementation disabled
+ * by default, so we have to use single byte reads ! */
+ for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) {
+ client.addr = omnivision_sensor_addrs[i];
+ /* Read manufacturer ID from registers 0x1c-0x1d (BE) */
+ reg = 0x1c;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = ret << 8;
+ reg = 0x1d;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id += ret;
+ /* Check manufacturer ID */
+ if (id != 0x7fa2)
+ continue;
+ /* Read product ID from registers 0x0a-0x0b (BE) */
+ reg = 0x0a;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id = ret << 8;
+ reg = 0x0b;
+ ret = i2c_smbus_read_byte_data(&client, reg);
+ if (ret < 0) {
+ em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",
+ client.addr << 1, ret);
+ continue;
+ }
+ id += ret;
+ /* Check product ID */
+ switch (id) {
+ case 0x2642:
+ name = "OV2640";
+ dev->em28xx_sensor = EM28XX_OV2640;
+ break;
+ case 0x7648:
+ name = "OV7648";
+ break;
+ case 0x7660:
+ name = "OV7660";
+ break;
+ case 0x7673:
+ name = "OV7670";
+ break;
+ case 0x7720:
+ name = "OV7720";
+ break;
+ case 0x7721:
+ name = "OV7725";
+ break;
+ case 0x9648: /* Rev 2 */
+ case 0x9649: /* Rev 3 */
+ name = "OV9640";
+ break;
+ case 0x9650:
+ case 0x9652: /* OV9653 */
+ name = "OV9650";
+ break;
+ case 0x9656: /* Rev 4 */
+ case 0x9657: /* Rev 5 */
+ name = "OV9655";
+ break;
+ default:
+ em28xx_info("unknown OmniVision sensor detected: 0x%04x\n",
+ id);
+ return 0;
+ }
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR)
+ em28xx_info("unsupported sensor detected: %s\n", name);
+ else
+ em28xx_info("sensor %s detected\n", name);
+
+ dev->i2c_client[dev->def_i2c_bus].addr = client.addr;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+int em28xx_detect_sensor(struct em28xx *dev)
+{
+ int ret;
+
+ ret = em28xx_probe_sensor_micron(dev);
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0)
+ ret = em28xx_probe_sensor_omnivision(dev);
+
+ /*
+ * NOTE: the Windows driver also probes i2c addresses
+ * 0x22 (Samsung ?) and 0x66 (Kodak ?)
+ */
+
+ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) {
+ em28xx_info("No sensor detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int em28xx_init_camera(struct em28xx *dev)
+{
+ switch (dev->em28xx_sensor) {
+ case EM28XX_MT9V011:
+ {
+ struct mt9v011_platform_data pdata;
+ struct i2c_board_info mt9v011_info = {
+ .type = "mt9v011",
+ .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .platform_data = &pdata,
+ };
+
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 480;
+
+ /*
+ * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
+ * the Silvercrest cam I have here for testing - for higher
+ * resolutions, a high clock cause horizontal artifacts, so we
+ * need to use a lower xclk frequency.
+ * Yet, it would be possible to adjust xclk depending on the
+ * desired resolution, since this affects directly the
+ * frame rate.
+ */
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ dev->sensor_xtal = 4300000;
+ pdata.xtal = dev->sensor_xtal;
+ if (NULL ==
+ v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &mt9v011_info, NULL))
+ return -ENODEV;
+ /* probably means GRGB 16 bit bayer */
+ dev->vinmode = 0x0d;
+ dev->vinctl = 0x00;
+
+ break;
+ }
+ case EM28XX_MT9M001:
+ dev->sensor_xres = 1280;
+ dev->sensor_yres = 1024;
+
+ em28xx_initialize_mt9m001(dev);
+
+ /* probably means BGGR 16 bit bayer */
+ dev->vinmode = 0x0c;
+ dev->vinctl = 0x00;
+
+ break;
+ case EM28XX_MT9M111:
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 512;
+
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ em28xx_initialize_mt9m111(dev);
+
+ dev->vinmode = 0x0a;
+ dev->vinctl = 0x00;
+
+ break;
+ case EM28XX_OV2640:
+ {
+ struct v4l2_subdev *subdev;
+ struct i2c_board_info ov2640_info = {
+ .type = "ov2640",
+ .flags = I2C_CLIENT_SCCB,
+ .addr = dev->i2c_client[dev->def_i2c_bus].addr,
+ .platform_data = &camlink,
+ };
+ struct v4l2_mbus_framefmt fmt;
+
+ /*
+ * FIXME: sensor supports resolutions up to 1600x1200, but
+ * resolution setting/switching needs to be modified to
+ * - switch sensor output resolution (including further
+ * configuration changes)
+ * - adjust bridge xclk
+ * - disable 16 bit (12 bit) output formats on high resolutions
+ */
+ dev->sensor_xres = 640;
+ dev->sensor_yres = 480;
+
+ subdev =
+ v4l2_i2c_new_subdev_board(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &ov2640_info, NULL);
+
+ fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt.width = 640;
+ fmt.height = 480;
+ v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt);
+
+ /* NOTE: for UXGA=1600x1200 switch to 12MHz */
+ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
+ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
+ dev->vinmode = 0x08;
+ dev->vinctl = 0x00;
+
+ break;
+ }
+ case EM28XX_NOSENSOR:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 54a03b20de6e..83bfbe4c980f 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -34,7 +34,6 @@
#include <media/saa7115.h>
#include <media/tvp5150.h>
#include <media/tvaudio.h>
-#include <media/mt9v011.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -345,6 +344,18 @@ static struct em28xx_reg_seq pctv_460e[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
+ {EM2874_R80_GPIO, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfd, 0xff, 10}, /* xc5000 reset */
+ {EM2874_R80_GPIO, 0xf9, 0xff, 35},
+ {EM2874_R80_GPIO, 0xfd, 0xff, 10},
+ {EM2874_R80_GPIO, 0xff, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfe, 0xff, 10},
+ {EM2874_R80_GPIO, 0xbe, 0xff, 10},
+ {EM2874_R80_GPIO, 0xfe, 0xff, 20},
+ { -1, -1, -1, -1},
+};
+
#if 0
static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{EM2874_R80_GPIO, 0x6f, 0xff, 10},
@@ -958,8 +969,8 @@ struct em28xx_board em28xx_boards[] = {
#else
.tuner_type = TUNER_ABSENT,
#endif
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
@@ -974,17 +985,27 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
#endif
.ir_codes = RC_MAP_HAUPPAUGE,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
+ [EM2884_BOARD_C3TECH_DIGITAL_DUO] = {
+ .name = "C3 Tech Digital Duo HDTV/SDTV USB",
+ .has_dvb = 1,
+ /* FIXME: Add analog support - need a saa7136 driver */
+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
+ .ir_codes = RC_MAP_EMPTY,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
+ .dvb_gpio = c3tech_digital_duo_digital,
+ },
[EM2884_BOARD_CINERGY_HTC_STICK] = {
.name = "Terratec Cinergy HTC Stick",
.has_dvb = 1,
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
.tuner_type = TUNER_ABSENT,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
@@ -1404,8 +1425,8 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2874_BOARD_LEADERSHIP_ISDBT] = {
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_100_KHZ,
.xclk = EM28XX_XCLK_FREQUENCY_10MHZ,
.name = "EM2874 Leadership ISDBT",
@@ -1917,8 +1938,8 @@ struct em28xx_board em28xx_boards[] = {
* Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
[EM28174_BOARD_PCTV_290E] = {
.name = "PCTV nanoStick T2 290e",
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_290e,
.has_dvb = 1,
@@ -1927,8 +1948,8 @@ struct em28xx_board em28xx_boards[] = {
/* 2013:024f PCTV DVB-S2 Stick 460e
* Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */
[EM28174_BOARD_PCTV_460E] = {
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
.name = "PCTV DVB-S2 Stick (460e)",
.tuner_type = TUNER_ABSENT,
.tuner_gpio = pctv_460e,
@@ -1958,8 +1979,9 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_gpio = maxmedia_ub425_tc,
.has_dvb = 1,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .ir_codes = RC_MAP_REDDO,
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
/* 2304:0242 PCTV QuatroStick (510e)
@@ -1970,8 +1992,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = pctv_510e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
/* 2013:0251 PCTV QuatroStick nano (520e)
@@ -1982,8 +2004,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = pctv_520e,
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
[EM2884_BOARD_TERRATEC_HTC_USB_XS] = {
@@ -1991,8 +2013,8 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
.tuner_type = TUNER_ABSENT,
- .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
- EM28XX_I2C_CLK_WAIT_ENABLE |
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_400_KHZ,
},
};
@@ -2144,6 +2166,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28174_BOARD_PCTV_460E },
{ USB_DEVICE(0x2040, 0x1605),
.driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+ { USB_DEVICE(0x1b80, 0xe755),
+ .driver_info = EM2884_BOARD_C3TECH_DIGITAL_DUO },
{ USB_DEVICE(0xeb1a, 0x5006),
.driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
{ USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
@@ -2183,6 +2207,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
};
+/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
static unsigned short saa711x_addrs[] = {
@@ -2204,8 +2229,9 @@ static unsigned short msp3400_addrs[] = {
int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
{
+ struct em28xx_i2c_bus *i2c_bus = ptr;
+ struct em28xx *dev = i2c_bus->dev;
int rc = 0;
- struct em28xx *dev = ptr;
if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
return 0;
@@ -2233,145 +2259,9 @@ static inline void em28xx_set_model(struct em28xx *dev)
if (!dev->board.i2c_speed)
dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
EM28XX_I2C_FREQ_100_KHZ;
-}
-
-
-/* FIXME: Should be replaced by a proper mt9m111 driver */
-static int em28xx_initialize_mt9m111(struct em28xx *dev)
-{
- int i;
- unsigned char regs[][3] = {
- { 0x0d, 0x00, 0x01, }, /* reset and use defaults */
- { 0x0d, 0x00, 0x00, },
- { 0x0a, 0x00, 0x21, },
- { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */
- };
-
- for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
-
- return 0;
-}
-
-
-/* FIXME: Should be replaced by a proper mt9m001 driver */
-static int em28xx_initialize_mt9m001(struct em28xx *dev)
-{
- int i;
- unsigned char regs[][3] = {
- { 0x0d, 0x00, 0x01, },
- { 0x0d, 0x00, 0x00, },
- { 0x04, 0x05, 0x00, }, /* hres = 1280 */
- { 0x03, 0x04, 0x00, }, /* vres = 1024 */
- { 0x20, 0x11, 0x00, },
- { 0x06, 0x00, 0x10, },
- { 0x2b, 0x00, 0x24, },
- { 0x2e, 0x00, 0x24, },
- { 0x35, 0x00, 0x24, },
- { 0x2d, 0x00, 0x20, },
- { 0x2c, 0x00, 0x20, },
- { 0x09, 0x0a, 0xd4, },
- { 0x35, 0x00, 0x57, },
- };
-
- for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
-
- return 0;
-}
-
-/* HINT method: webcam I2C chips
- *
- * This method works for webcams with Micron sensors
- */
-static int em28xx_hint_sensor(struct em28xx *dev)
-{
- int rc;
- char *sensor_name;
- unsigned char cmd;
- __be16 version_be;
- u16 version;
-
- /* Micron sensor detection */
- dev->i2c_client.addr = 0xba >> 1;
- cmd = 0;
- i2c_master_send(&dev->i2c_client, &cmd, 1);
- rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2);
- if (rc != 2)
- return -EINVAL;
-
- version = be16_to_cpu(version_be);
- switch (version) {
- case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */
- case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */
- dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
- em28xx_set_model(dev);
-
- sensor_name = "mt9v011";
- dev->em28xx_sensor = EM28XX_MT9V011;
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
- /*
- * FIXME: mt9v011 uses I2S speed as xtal clk - at least with
- * the Silvercrest cam I have here for testing - for higher
- * resolutions, a high clock cause horizontal artifacts, so we
- * need to use a lower xclk frequency.
- * Yet, it would be possible to adjust xclk depending on the
- * desired resolution, since this affects directly the
- * frame rate.
- */
- dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
- dev->sensor_xtal = 4300000;
-
- /* probably means GRGB 16 bit bayer */
- dev->vinmode = 0x0d;
- dev->vinctl = 0x00;
-
- break;
-
- case 0x143a: /* MT9M111 as found in the ECS G200 */
- dev->model = EM2750_BOARD_UNKNOWN;
- em28xx_set_model(dev);
-
- sensor_name = "mt9m111";
- dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
- dev->em28xx_sensor = EM28XX_MT9M111;
- em28xx_initialize_mt9m111(dev);
- dev->sensor_xres = 640;
- dev->sensor_yres = 512;
-
- dev->vinmode = 0x0a;
- dev->vinctl = 0x00;
-
- break;
-
- case 0x8431:
- dev->model = EM2750_BOARD_UNKNOWN;
- em28xx_set_model(dev);
-
- sensor_name = "mt9m001";
- dev->em28xx_sensor = EM28XX_MT9M001;
- em28xx_initialize_mt9m001(dev);
- dev->sensor_xres = 1280;
- dev->sensor_yres = 1024;
-
- /* probably means BGGR 16 bit bayer */
- dev->vinmode = 0x0c;
- dev->vinctl = 0x00;
-
- break;
- default:
- printk("Unknown Micron Sensor 0x%04x\n", version);
- return -EINVAL;
- }
-
- /* Setup webcam defaults */
- em28xx_pre_card_setup(dev);
- em28xx_errdev("Sensor is %s, using model %s entry.\n",
- sensor_name, em28xx_boards[dev->model].name);
-
- return 0;
+ /* Should be initialized early, for I2C to work */
+ dev->def_i2c_bus = dev->board.def_i2c_bus;
}
/* Since em28xx_pre_card_setup() requires a proper dev->model,
@@ -2599,6 +2489,18 @@ static int em28xx_hint_board(struct em28xx *dev)
{
int i;
+ if (dev->board.is_webcam) {
+ if (dev->em28xx_sensor == EM28XX_MT9V011) {
+ dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
+ } else if (dev->em28xx_sensor == EM28XX_MT9M001 ||
+ dev->em28xx_sensor == EM28XX_MT9M111) {
+ dev->model = EM2750_BOARD_UNKNOWN;
+ }
+ /* FIXME: IMPROVE ! */
+
+ return 0;
+ }
+
/* HINT method: EEPROM
*
* This method works only for boards with eeprom.
@@ -2638,7 +2540,7 @@ static int em28xx_hint_board(struct em28xx *dev)
/* user did not request i2c scanning => do it now */
if (!dev->i2c_hash)
- em28xx_do_i2c_scan(dev);
+ em28xx_do_i2c_scan(dev, dev->def_i2c_bus);
for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) {
if (dev->i2c_hash == em28xx_i2c_hash[i].hash) {
@@ -2684,16 +2586,16 @@ static void em28xx_card_setup(struct em28xx *dev)
* If sensor is not found, then it isn't a webcam.
*/
if (dev->board.is_webcam) {
- if (em28xx_hint_sensor(dev) < 0)
+ if (em28xx_detect_sensor(dev) < 0)
dev->board.is_webcam = 0;
else
dev->progressive = 1;
}
- if (!dev->board.is_webcam) {
- switch (dev->model) {
- case EM2820_BOARD_UNKNOWN:
- case EM2800_BOARD_UNKNOWN:
+ switch (dev->model) {
+ case EM2750_BOARD_UNKNOWN:
+ case EM2820_BOARD_UNKNOWN:
+ case EM2800_BOARD_UNKNOWN:
/*
* The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
*
@@ -2714,9 +2616,8 @@ static void em28xx_card_setup(struct em28xx *dev)
em28xx_pre_card_setup(dev);
}
break;
- default:
- em28xx_set_model(dev);
- }
+ default:
+ em28xx_set_model(dev);
}
em28xx_info("Identified as %s (card=%d)\n",
@@ -2736,15 +2637,19 @@ static void em28xx_card_setup(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
{
struct tveeprom tv;
+
+ if (dev->eedata == NULL)
+ break;
#if defined(CONFIG_MODULES) && defined(MODULE)
request_module("tveeprom");
#endif
/* Call first TVeeprom */
- dev->i2c_client.addr = 0xa0 >> 1;
- tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata);
+ dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1;
+ tveeprom_hauppauge_analog(&dev->i2c_client[dev->def_i2c_bus], &tv, dev->eedata);
dev->tuner_type = tv.tuner_type;
@@ -2791,7 +2696,7 @@ static void em28xx_card_setup(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break;
-/*
+ /*
* The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR.
*
* This occurs because they share identical USB vendor and
@@ -2826,51 +2731,41 @@ static void em28xx_card_setup(struct em28xx *dev)
"addresses)\n\n");
}
+ /* Free eeprom data memory */
+ kfree(dev->eedata);
+ dev->eedata = NULL;
+
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
/* request some modules */
if (dev->board.has_msp34xx)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tvp5150", 0, tvp5150_addrs);
- if (dev->em28xx_sensor == EM28XX_MT9V011) {
- struct mt9v011_platform_data pdata;
- struct i2c_board_info mt9v011_info = {
- .type = "mt9v011",
- .addr = 0xba >> 1,
- .platform_data = &pdata,
- };
-
- pdata.xtal = dev->sensor_xtal;
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
- &mt9v011_info, NULL);
- }
-
-
if (dev->board.adecoder == EM28XX_TVAUDIO)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tuner", dev->board.radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner",
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
@@ -2878,18 +2773,20 @@ static void em28xx_card_setup(struct em28xx *dev)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner",
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
"tuner", dev->tuner_addr, NULL);
}
}
em28xx_tuner_setup(dev);
+
+ em28xx_init_camera(dev);
}
@@ -2914,7 +2811,8 @@ static void request_module_async(struct work_struct *work)
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)
+ if (dev->board.has_snapshot_button ||
+ ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir))
request_module("em28xx-rc");
#endif /* CONFIG_MODULES */
}
@@ -2941,7 +2839,9 @@ void em28xx_release_resources(struct em28xx *dev)
em28xx_release_analog_resources(dev);
- em28xx_i2c_unregister(dev);
+ if (dev->def_i2c_bus)
+ em28xx_i2c_unregister(dev, 1);
+ em28xx_i2c_unregister(dev, 0);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
@@ -3002,8 +2902,23 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
case CHIP_ID_EM2750:
chip_name = "em2750";
break;
+ case CHIP_ID_EM2765:
+ chip_name = "em2765";
+ dev->wait_after_write = 0;
+ dev->is_em25xx = 1;
+ dev->eeprom_addrwidth_16bit = 1;
+ break;
case CHIP_ID_EM2820:
chip_name = "em2710/2820";
+ if (le16_to_cpu(dev->udev->descriptor.idVendor)
+ == 0xeb1a) {
+ __le16 idProd = dev->udev->descriptor.idProduct;
+ if (le16_to_cpu(idProd) == 0x2710)
+ chip_name = "em2710";
+ else if (le16_to_cpu(idProd) == 0x2820)
+ chip_name = "em2820";
+ }
+ /* NOTE: the em2820 is used in webcams, too ! */
break;
case CHIP_ID_EM2840:
chip_name = "em2840";
@@ -3019,11 +2934,13 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
chip_name = "em2874";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
case CHIP_ID_EM28174:
chip_name = "em28174";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
case CHIP_ID_EM2883:
chip_name = "em2882/3";
@@ -3033,6 +2950,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
chip_name = "em2884";
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
break;
default:
printk(KERN_INFO DRIVER_NAME
@@ -3066,14 +2984,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
em28xx_pre_card_setup(dev);
- if (dev->chip_id == CHIP_ID_EM2820) {
- if (dev->board.is_webcam)
- chip_name = "em2710";
- else
- chip_name = "em2820";
- snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno);
- }
-
if (!dev->board.is_em2800) {
/* Resets I2C speed */
retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
@@ -3091,17 +3001,37 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return retval;
}
- v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_handler_init(hdl, 8);
dev->v4l2_dev.ctrl_handler = hdl;
- /* register i2c bus */
- retval = em28xx_i2c_register(dev);
+ rt_mutex_init(&dev->i2c_bus_lock);
+
+ /* register i2c bus 0 */
+ if (dev->board.is_em2800)
+ retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM2800);
+ else
+ retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX);
if (retval < 0) {
- em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n",
+ em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
__func__, retval);
goto unregister_dev;
}
+ /* register i2c bus 1 */
+ if (dev->def_i2c_bus) {
+ if (dev->is_em25xx)
+ retval = em28xx_i2c_register(dev, 1,
+ EM28XX_I2C_ALGO_EM25XX_BUS_B);
+ else
+ retval = em28xx_i2c_register(dev, 1,
+ EM28XX_I2C_ALGO_EM28XX);
+ if (retval < 0) {
+ em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
+ __func__, retval);
+ goto unregister_dev;
+ }
+ }
+
/*
* Default format, used for tvp5150 or saa711x output formats
*/
@@ -3160,11 +3090,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
msleep(3);
}
- v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- retval = dev->ctrl_handler.error;
- if (retval)
- goto fail;
-
retval = em28xx_register_analog_devices(dev);
if (retval < 0) {
goto fail;
@@ -3176,7 +3101,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
return 0;
fail:
- em28xx_i2c_unregister(dev);
+ if (dev->def_i2c_bus)
+ em28xx_i2c_unregister(dev, 1);
+ em28xx_i2c_unregister(dev, 0);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
unregister_dev:
@@ -3292,14 +3219,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->analog_ep_bulk =
e->bEndpointAddress;
} else {
- has_dvb = true;
if (usb_endpoint_xfer_isoc(e)) {
- dev->dvb_ep_isoc = e->bEndpointAddress;
if (size > dev->dvb_max_pkt_size_isoc) {
+ has_dvb = true; /* see NOTE (~) */
+ dev->dvb_ep_isoc = e->bEndpointAddress;
dev->dvb_max_pkt_size_isoc = size;
dev->dvb_alt_isoc = i;
}
} else {
+ has_dvb = true;
dev->dvb_ep_bulk = e->bEndpointAddress;
}
}
@@ -3326,6 +3254,12 @@ static int em28xx_usb_probe(struct usb_interface *interface,
* so far. But there might be devices for which this
* logic is not sufficient...
*/
+ /*
+ * NOTE (~): some manufacturers (e.g. Terratec) disable
+ * endpoints by setting wMaxPacketSize to 0 bytes for
+ * all alt settings. So far, we've seen this for
+ * DVB isoc endpoints only.
+ */
}
}
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index aaedd11791f2..a802128ce9c5 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -607,12 +607,12 @@ EXPORT_SYMBOL_GPL(em28xx_audio_setup);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */
- em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */
- em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */
- em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00);
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
@@ -681,6 +681,11 @@ int em28xx_vbi_supported(struct em28xx *dev)
if (disable_vbi == 1)
return 0;
+ if (dev->board.is_webcam)
+ return 0;
+
+ /* FIXME: check subdevices for VBI support */
+
if (dev->chip_id == CHIP_ID_EM2860 ||
dev->chip_id == CHIP_ID_EM2883)
return 1;
@@ -692,12 +697,23 @@ int em28xx_vbi_supported(struct em28xx *dev)
int em28xx_set_outfmt(struct em28xx *dev)
{
int ret;
- u8 vinctrl;
-
- ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
- dev->format->reg | 0x20, 0xff);
+ u8 fmt, vinctrl;
+
+ fmt = dev->format->reg;
+ if (!dev->is_em25xx)
+ fmt |= 0x20;
+ /*
+ * NOTE: it's not clear if this is really needed !
+ * The datasheets say bit 5 is a reserved bit and devices seem to work
+ * fine without it. But the Windows driver sets it for em2710/50+em28xx
+ * devices and we've always been setting it, too.
+ *
+ * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+ * it's likely used for an additional (compressed ?) format there.
+ */
+ ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
if (ret < 0)
- return ret;
+ return ret;
ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
if (ret < 0)
@@ -751,6 +767,13 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+ /* FIXME: function/meaning of these registers ? */
+ /* FIXME: align width+height to multiples of 4 ?! */
+ if (dev->is_em25xx) {
+ em28xx_write_reg(dev, 0x34, width >> 4);
+ em28xx_write_reg(dev, 0x35, height >> 4);
+ }
}
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a81ec2e8cc9b..b22f8fed8127 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -50,6 +50,7 @@
#include "tda10071.h"
#include "a8293.h"
#include "qt1010.h"
+#include "mb86a20s.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -177,7 +178,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
static int em28xx_start_streaming(struct em28xx_dvb *dvb)
{
int rc;
- struct em28xx *dev = dvb->adapter.priv;
+ struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
+ struct em28xx *dev = i2c_bus->dev;
int dvb_max_packet_size, packet_multiplier, dvb_alt;
if (dev->dvb_xfer_bulk) {
@@ -216,12 +218,11 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
{
- struct em28xx *dev = dvb->adapter.priv;
+ struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
+ struct em28xx *dev = i2c_bus->dev;
em28xx_stop_urbs(dev);
- em28xx_set_mode(dev, EM28XX_SUSPEND);
-
return 0;
}
@@ -269,7 +270,8 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
/* ------------------------------------------------------------------ */
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
- struct em28xx *dev = fe->dvb->priv;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
if (acquire)
return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -465,10 +467,10 @@ static void hauppauge_hvr930c_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, hauppauge_hvr930c_end);
msleep(100);
@@ -522,10 +524,10 @@ static void terratec_h5_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_h5_end);
};
@@ -575,10 +577,10 @@ static void terratec_htc_stick_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_stick_end);
};
@@ -633,10 +635,10 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev)
em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
msleep(10);
- dev->i2c_client.addr = 0x82 >> 1;
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
em28xx_gpio_set(dev, terratec_htc_usb_xs_end);
};
@@ -662,10 +664,10 @@ static void pctv_520e_init(struct em28xx *dev)
{{ 0x01, 0x00, 0x73, 0xaf }, 4},
};
- dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */
+ dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */
for (i = 0; i < ARRAY_SIZE(regs); i++)
- i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len);
+ i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len);
};
static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
@@ -768,9 +770,25 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
};
static struct qt1010_config em28xx_qt1010_config = {
.i2c_address = 0x62
+};
+static const struct mb86a20s_config c3tech_duo_mb86a20s_config = {
+ .demod_address = 0x10,
+ .is_serial = true,
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_config = {
+ .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
};
+static struct tda18271_config c3tech_duo_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_config,
+ .gate = TDA18271_GATE_DIGITAL,
+ .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
+};
+
+
/* ------------------------------------------------------------------ */
static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
@@ -779,7 +797,7 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
struct xc2028_config cfg;
memset(&cfg, 0, sizeof(cfg));
- cfg.i2c_adap = &dev->i2c_adap;
+ cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus];
cfg.i2c_addr = addr;
if (!dev->dvb->fe[0]) {
@@ -824,7 +842,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
if (dvb->fe[1])
dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
- dvb->adapter.priv = dev;
+ dvb->adapter.priv = &dev->i2c_bus[dev->def_i2c_bus];
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
@@ -962,7 +980,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
switch (dev->model) {
case EM2874_BOARD_LEADERSHIP_ISDBT:
dvb->fe[0] = dvb_attach(s921_attach,
- &sharp_isdbt, &dev->i2c_adap);
+ &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
@@ -976,7 +994,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -985,7 +1003,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_KWORLD_DVB_310U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -996,7 +1014,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1009,13 +1027,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2882_BOARD_KWORLD_VS_DVBT:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
}
if (em28xx_attach_xc3028(0x61, dev) < 0) {
@@ -1026,16 +1044,16 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(qt1010_attach, dvb->fe[0],
- &dev->i2c_adap, &em28xx_qt1010_config);
+ &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config);
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1044,10 +1062,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2882_BOARD_KWORLD_ATSC_315U:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free;
}
@@ -1056,7 +1074,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
- &dev->i2c_adap, &dev->udev->dev);
+ &dev->i2c_adap[dev->def_i2c_bus], &dev->udev->dev);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
@@ -1066,10 +1084,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
dvb->fe[0] = dvb_attach(tda10023_attach,
&em28xx_tda10023_config,
- &dev->i2c_adap, 0x48);
+ &dev->i2c_adap[dev->def_i2c_bus], 0x48);
if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free;
}
@@ -1078,10 +1096,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2870_BOARD_KWORLD_A340:
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap, &kworld_a340_config);
+ &dev->i2c_adap[dev->def_i2c_bus], &kworld_a340_config);
break;
case EM28174_BOARD_PCTV_290E:
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
@@ -1089,14 +1107,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
CXD2820R_GPIO_L;
dvb->fe[0] = dvb_attach(cxd2820r_attach,
&em28xx_cxd2820r_config,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&dvb->lna_gpio);
if (dvb->fe[0]) {
/* FE 0 attach tuner */
if (!dvb_attach(tda18271_attach,
dvb->fe[0],
0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
@@ -1126,7 +1144,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
hauppauge_hvr930c_init(dev);
dvb->fe[0] = dvb_attach(drxk_attach,
- &hauppauge_930c_drxk, &dev->i2c_adap);
+ &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1144,7 +1162,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap,
+ if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&cfg)) {
result = -EINVAL;
goto out_free;
@@ -1157,7 +1175,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2884_BOARD_TERRATEC_H5:
terratec_h5_init(dev);
- dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap);
+ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1171,7 +1189,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach tda18271 to DVB-C frontend */
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
- if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) {
+ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
result = -EINVAL;
goto out_free;
}
@@ -1179,20 +1197,29 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
break;
+ case EM2884_BOARD_C3TECH_DIGITAL_DUO:
+ dvb->fe[0] = dvb_attach(mb86a20s_attach,
+ &c3tech_duo_mb86a20s_config,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0] != NULL)
+ dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &c3tech_duo_tda18271_config);
+ break;
case EM28174_BOARD_PCTV_460E:
/* attach demod */
dvb->fe[0] = dvb_attach(tda10071_attach,
- &em28xx_tda10071_config, &dev->i2c_adap);
+ &em28xx_tda10071_config, &dev->i2c_adap[dev->def_i2c_bus]);
/* attach SEC */
if (dvb->fe[0])
- dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap,
+ dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_a8293_config);
break;
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* disable I2C-gate */
@@ -1200,7 +1227,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach tuner */
if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
- &dev->i2c_adap, 0x60)) {
+ &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free;
@@ -1218,12 +1245,12 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* attach tuner */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
@@ -1236,7 +1263,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1244,7 +1271,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach the demodulator. */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
result = -EINVAL;
goto out_free;
@@ -1255,7 +1282,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
- &dev->i2c_adap);
+ &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
@@ -1263,7 +1290,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* Attach the demodulator. */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap,
+ &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
result = -EINVAL;
goto out_free;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 8532c1d4fd46..4851cc2e4a4d 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -5,6 +5,7 @@
Markus Rechberger <mrechberger@gmail.com>
Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
+ Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.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
@@ -41,14 +42,6 @@ static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-#define dprintk2(lvl, fmt, args...) \
-do { \
- if (i2c_debug >= lvl) { \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __func__ , ##args); \
- } \
-} while (0)
-
/*
* em2800_i2c_send_bytes()
* send up to 4 bytes to the em2800 i2c device
@@ -76,8 +69,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
/* trigger write */
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
if (ret != 2 + len) {
- em28xx_warn("failed to trigger write to i2c address 0x%x "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
/* wait for completion */
@@ -89,8 +82,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
} else if (ret == 0x94 + len - 1) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to get i2c transfer status from "
- "bridge register (error=%i)\n", ret);
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
@@ -118,8 +111,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
buf2[0] = addr;
ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2);
if (ret != 2) {
- em28xx_warn("failed to trigger read from i2c address 0x%x "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
@@ -132,8 +125,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
} else if (ret == 0x94 + len - 1) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to get i2c transfer status from "
- "bridge register (error=%i)\n", ret);
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
@@ -144,9 +137,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
/* get the received message */
ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
if (ret != len) {
- em28xx_warn("reading from i2c device at 0x%x failed: "
- "couldn't get the received message from the bridge "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n",
+ addr, ret);
return (ret < 0) ? ret : -EIO;
}
for (i = 0; i < len; i++)
@@ -180,19 +172,20 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
if (len < 1 || len > 64)
return -EOPNOTSUPP;
- /* NOTE: limited by the USB ctrl message constraints
- * Zero length reads always succeed, even if no device is connected */
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
/* Write to i2c device */
ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len);
if (ret != len) {
if (ret < 0) {
- em28xx_warn("writing to i2c device at 0x%x failed "
- "(error=%i)\n", addr, ret);
+ em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
return ret;
} else {
- em28xx_warn("%i bytes write to i2c device at 0x%x "
- "requested, but %i bytes written\n",
+ em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
len, addr, ret);
return -EIO;
}
@@ -207,14 +200,16 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
} else if (ret == 0x10) {
return -ENODEV;
} else if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from "
- "bridge (error=%i)\n", ret);
+ em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ ret);
return ret;
}
msleep(5);
- /* NOTE: do we really have to wait for success ?
- Never seen anything else than 0x00 or 0x10
- (even with high payload) ... */
+ /*
+ * NOTE: do we really have to wait for success ?
+ * Never seen anything else than 0x00 or 0x10
+ * (even with high payload) ...
+ */
}
em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
return -EIO;
@@ -230,29 +225,32 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
if (len < 1 || len > 64)
return -EOPNOTSUPP;
- /* NOTE: limited by the USB ctrl message constraints
- * Zero length reads always succeed, even if no device is connected */
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
/* Read data from i2c device */
ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len);
- if (ret != len) {
- if (ret < 0) {
- em28xx_warn("reading from i2c device at 0x%x failed "
- "(error=%i)\n", addr, ret);
- return ret;
- } else {
- em28xx_warn("%i bytes requested from i2c device at "
- "0x%x, but %i bytes received\n",
- len, addr, ret);
- return -EIO;
- }
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
}
+ /*
+ * NOTE: some devices with two i2c busses have the bad habit to return 0
+ * bytes if we are on bus B AND there was no write attempt to the
+ * specified slave address before AND no device is present at the
+ * requested slave address.
+ * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * spamming the system log on device probing and do nothing here.
+ */
/* Check success of the i2c operation */
ret = dev->em28xx_read_reg(dev, 0x05);
if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from "
- "bridge (error=%i)\n", ret);
+ em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ ret);
return ret;
}
if (ret > 0) {
@@ -282,77 +280,254 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr)
}
/*
+ * em25xx_bus_B_send_bytes
+ * write bytes to the i2c device
+ */
+static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
+ u16 len)
+{
+ int ret;
+
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
+
+ /* Set register and write value */
+ ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len);
+ if (ret != len) {
+ if (ret < 0) {
+ em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ } else {
+ em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n",
+ len, addr, ret);
+ return -EIO;
+ }
+ }
+ /* Check success */
+ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
+ /*
+ * NOTE: the only error we've seen so far is
+ * 0x01 when the slave device is not present
+ */
+ if (!ret)
+ return len;
+ else if (ret > 0)
+ return -ENODEV;
+
+ return ret;
+ /*
+ * NOTE: With chip types (other chip IDs) which actually don't support
+ * this operation, it seems to succeed ALWAYS ! (even if there is no
+ * slave device or even no second i2c bus provided)
+ */
+}
+
+/*
+ * em25xx_bus_B_recv_bytes
+ * read bytes from the i2c device
+ */
+static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
+ u16 len)
+{
+ int ret;
+
+ if (len < 1 || len > 64)
+ return -EOPNOTSUPP;
+ /*
+ * NOTE: limited by the USB ctrl message constraints
+ * Zero length reads always succeed, even if no device is connected
+ */
+
+ /* Read value */
+ ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len);
+ if (ret < 0) {
+ em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ /*
+ * NOTE: some devices with two i2c busses have the bad habit to return 0
+ * bytes if we are on bus B AND there was no write attempt to the
+ * specified slave address before AND no device is present at the
+ * requested slave address.
+ * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * spamming the system log on device probing and do nothing here.
+ */
+
+ /* Check success */
+ ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000);
+ /*
+ * NOTE: the only error we've seen so far is
+ * 0x01 when the slave device is not present
+ */
+ if (!ret)
+ return len;
+ else if (ret > 0)
+ return -ENODEV;
+
+ return ret;
+ /*
+ * NOTE: With chip types (other chip IDs) which actually don't support
+ * this operation, it seems to succeed ALWAYS ! (even if there is no
+ * slave device or even no second i2c bus provided)
+ */
+}
+
+/*
+ * em25xx_bus_B_check_for_device()
+ * check if there is a i2c device at the supplied address
+ */
+static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr)
+{
+ u8 buf;
+ int ret;
+
+ ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+ /*
+ * NOTE: With chips which do not support this operation,
+ * it seems to succeed ALWAYS ! (even if no device connected)
+ */
+}
+
+static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ int rc = -EOPNOTSUPP;
+
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_check_for_device(dev, addr);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_check_for_device(dev, addr);
+ if (rc == -ENODEV) {
+ if (i2c_debug)
+ printk(" no device\n");
+ }
+ return rc;
+}
+
+static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
+ struct i2c_msg msg)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ u16 addr = msg.addr << 1;
+ int byte, rc = -EOPNOTSUPP;
+
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
+ if (i2c_debug) {
+ for (byte = 0; byte < msg.len; byte++)
+ printk(" %02x", msg.buf[byte]);
+ }
+ return rc;
+}
+
+static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
+ struct i2c_msg msg, int stop)
+{
+ struct em28xx *dev = i2c_bus->dev;
+ u16 addr = msg.addr << 1;
+ int byte, rc = -EOPNOTSUPP;
+
+ if (i2c_debug) {
+ for (byte = 0; byte < msg.len; byte++)
+ printk(" %02x", msg.buf[byte]);
+ }
+ if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
+ rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
+ rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len);
+ else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
+ rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len);
+ return rc;
+}
+
+/*
* em28xx_i2c_xfer()
* the main i2c transfer function
*/
static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
- struct em28xx *dev = i2c_adap->algo_data;
- int addr, rc, i, byte;
+ struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
+ struct em28xx *dev = i2c_bus->dev;
+ unsigned bus = i2c_bus->bus;
+ int addr, rc, i;
+ u8 reg;
+
+ rc = rt_mutex_trylock(&dev->i2c_bus_lock);
+ if (rc < 0)
+ return rc;
+
+ /* Switch I2C bus if needed */
+ if (bus != dev->cur_i2c_bus &&
+ i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) {
+ if (bus == 1)
+ reg = EM2874_I2C_SECONDARY_BUS_SELECT;
+ else
+ reg = 0;
+ em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg,
+ EM2874_I2C_SECONDARY_BUS_SELECT);
+ dev->cur_i2c_bus = bus;
+ }
- if (num <= 0)
+ if (num <= 0) {
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return 0;
+ }
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- dprintk2(2, "%s %s addr=%x len=%d:",
- (msgs[i].flags & I2C_M_RD) ? "read" : "write",
- i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
+ if (i2c_debug)
+ printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
+ dev->name, __func__ ,
+ (msgs[i].flags & I2C_M_RD) ? "read" : "write",
+ i == num - 1 ? "stop" : "nonstop",
+ addr, msgs[i].len);
if (!msgs[i].len) { /* no len: check only for device presence */
- if (dev->board.is_em2800)
- rc = em2800_i2c_check_for_device(dev, addr);
- else
- rc = em28xx_i2c_check_for_device(dev, addr);
+ rc = i2c_check_for_device(i2c_bus, addr);
if (rc == -ENODEV) {
- if (i2c_debug >= 2)
- printk(" no device\n");
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
- if (dev->board.is_em2800)
- rc = em2800_i2c_recv_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- else
- rc = em28xx_i2c_recv_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- if (i2c_debug >= 2) {
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
- }
+ rc = i2c_recv_bytes(i2c_bus, msgs[i]);
} else {
/* write bytes */
- if (i2c_debug >= 2) {
- for (byte = 0; byte < msgs[i].len; byte++)
- printk(" %02x", msgs[i].buf[byte]);
- }
- if (dev->board.is_em2800)
- rc = em2800_i2c_send_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len);
- else
- rc = em28xx_i2c_send_bytes(dev, addr,
- msgs[i].buf,
- msgs[i].len,
- i == num - 1);
+ rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
}
if (rc < 0) {
- if (i2c_debug >= 2)
+ if (i2c_debug)
printk(" ERROR: %i\n", rc);
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
- if (i2c_debug >= 2)
+ if (i2c_debug)
printk("\n");
}
+ rt_mutex_unlock(&dev->i2c_bus_lock);
return num;
}
-/* based on linux/sunrpc/svcauth.h and linux/hash.h
+/*
+ * based on linux/sunrpc/svcauth.h and linux/hash.h
* The original hash function returns a different value, if arch is x86_64
- * or i386.
+ * or i386.
*/
static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
{
@@ -375,127 +550,230 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
return (hash >> (32 - bits)) & 0xffffffffUL;
}
-static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
+/*
+ * Helper function to read data blocks from i2c clients with 8 or 16 bit
+ * address width, 8 bit register width and auto incrementation been activated
+ */
+static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr,
+ bool addr_w16, u16 len, u8 *data)
{
- unsigned char buf, *p = eedata;
- struct em28xx_eeprom *em_eeprom = (void *)eedata;
- int i, err, size = len, block, block_max;
-
- if (dev->chip_id == CHIP_ID_EM2874 ||
- dev->chip_id == CHIP_ID_EM28174 ||
- dev->chip_id == CHIP_ID_EM2884) {
- /* Empia switched to a 16-bit addressable eeprom in newer
- devices. While we could certainly write a routine to read
- the eeprom, there is nothing of use in there that cannot be
- accessed through registers, and there is the risk that we
- could corrupt the eeprom (since a 16-bit read call is
- interpreted as a write call by 8-bit eeproms).
- */
- return 0;
+ int remain = len, rsize, rsize_max, ret;
+ u8 buf[2];
+
+ /* Sanity check */
+ if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1))
+ return -EINVAL;
+ /* Select address */
+ buf[0] = addr >> 8;
+ buf[1] = addr & 0xff;
+ ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16);
+ if (ret < 0)
+ return ret;
+ /* Read data */
+ if (dev->board.is_em2800)
+ rsize_max = 4;
+ else
+ rsize_max = 64;
+ while (remain > 0) {
+ if (remain > rsize_max)
+ rsize = rsize_max;
+ else
+ rsize = remain;
+
+ ret = i2c_master_recv(&dev->i2c_client[bus], data, rsize);
+ if (ret < 0)
+ return ret;
+
+ remain -= rsize;
+ data += rsize;
}
- dev->i2c_client.addr = 0xa0 >> 1;
+ return len;
+}
+
+static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
+ u8 **eedata, u16 *eedata_len)
+{
+ const u16 len = 256;
+ /*
+ * FIXME common length/size for bytes to read, to display, hash
+ * calculation and returned device dataset. Simplifies the code a lot,
+ * but we might have to deal with multiple sizes in the future !
+ */
+ int i, err;
+ struct em28xx_eeprom *dev_config;
+ u8 buf, *data;
+
+ *eedata = NULL;
+ *eedata_len = 0;
+
+ /* EEPROM is always on i2c bus 0 on all known devices. */
+
+ dev->i2c_client[bus].addr = 0xa0 >> 1;
/* Check if board has eeprom */
- err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
if (err < 0) {
- em28xx_errdev("board has no eeprom\n");
- memset(eedata, 0, len);
+ em28xx_info("board has no eeprom\n");
return -ENODEV;
}
- buf = 0;
-
- err = i2c_master_send(&dev->i2c_client, &buf, 1);
- if (err != 1) {
- printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
- dev->name, err);
- return err;
+ data = kzalloc(len, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ /* Read EEPROM content */
+ err = em28xx_i2c_read_block(dev, bus, 0x0000,
+ dev->eeprom_addrwidth_16bit,
+ len, data);
+ if (err != len) {
+ em28xx_errdev("failed to read eeprom (err=%d)\n", err);
+ goto error;
}
- if (dev->board.is_em2800)
- block_max = 4;
- else
- block_max = 64;
-
- while (size > 0) {
- if (size > block_max)
- block = block_max;
- else
- block = size;
-
- if (block !=
- (err = i2c_master_recv(&dev->i2c_client, p, block))) {
- printk(KERN_WARNING
- "%s: i2c eeprom read error (err=%d)\n",
- dev->name, err);
- return err;
- }
- size -= block;
- p += block;
- }
+ /* Display eeprom content */
for (i = 0; i < len; i++) {
- if (0 == (i % 16))
- printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i);
- printk(" %02x", eedata[i]);
+ if (0 == (i % 16)) {
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("i2c eeprom %04x:", i);
+ else
+ em28xx_info("i2c eeprom %02x:", i);
+ }
+ printk(" %02x", data[i]);
if (15 == (i % 16))
printk("\n");
}
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
+
+ if (dev->eeprom_addrwidth_16bit &&
+ data[0] == 0x26 && data[3] == 0x00) {
+ /* new eeprom format; size 4-64kb */
+ u16 mc_start;
+ u16 hwconf_offset;
+
+ dev->hash = em28xx_hash_mem(data, len, 32);
+ mc_start = (data[1] << 8) + 4; /* usually 0x0004 */
+
+ em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
+ data[0], data[1], data[2], data[3], dev->hash);
+ em28xx_info("EEPROM info:\n");
+ em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n",
+ mc_start, data[2]);
+ /*
+ * boot configuration (address 0x0002):
+ * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz
+ * [1] always selects 12 kb RAM
+ * [2] USB device speed: 1 = force Full Speed; 0 = auto detect
+ * [4] 1 = force fast mode and no suspend for device testing
+ * [5:7] USB PHY tuning registers; determined by device
+ * characterization
+ */
+
+ /*
+ * Read hardware config dataset offset from address
+ * (microcode start + 46)
+ */
+ err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2,
+ data);
+ if (err != 2) {
+ em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
+ err);
+ goto error;
+ }
- if (em_eeprom->id == 0x9567eb1a)
- dev->hash = em28xx_hash_mem(eedata, len, 32);
+ /* Calculate hardware config dataset start address */
+ hwconf_offset = mc_start + data[0] + (data[1] << 8);
+
+ /* Read hardware config dataset */
+ /*
+ * NOTE: the microcode copy can be multiple pages long, but
+ * we assume the hardware config dataset is the same as in
+ * the old eeprom and not longer than 256 bytes.
+ * tveeprom is currently also limited to 256 bytes.
+ */
+ err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len,
+ data);
+ if (err != len) {
+ em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n",
+ err);
+ goto error;
+ }
- printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n",
- dev->name, em_eeprom->id, dev->hash);
+ /* Verify hardware config dataset */
+ /* NOTE: not all devices provide this type of dataset */
+ if (data[0] != 0x1a || data[1] != 0xeb ||
+ data[2] != 0x67 || data[3] != 0x95) {
+ em28xx_info("\tno hardware configuration dataset found in eeprom\n");
+ kfree(data);
+ return 0;
+ }
- printk(KERN_INFO "%s: EEPROM info:\n", dev->name);
+ /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */
+
+ } else if (!dev->eeprom_addrwidth_16bit &&
+ data[0] == 0x1a && data[1] == 0xeb &&
+ data[2] == 0x67 && data[3] == 0x95) {
+ dev->hash = em28xx_hash_mem(data, len, 32);
+ em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n",
+ data[0], data[1], data[2], data[3], dev->hash);
+ em28xx_info("EEPROM info:\n");
+ } else {
+ em28xx_info("unknown eeprom format or eeprom corrupted !\n");
+ err = -ENODEV;
+ goto error;
+ }
- switch (em_eeprom->chip_conf >> 4 & 0x3) {
+ *eedata = data;
+ *eedata_len = len;
+ dev_config = (void *)eedata;
+
+ switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
case 0:
- printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name);
+ em28xx_info("\tNo audio on board.\n");
break;
case 1:
- printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n",
- dev->name);
+ em28xx_info("\tAC97 audio (5 sample rates)\n");
break;
case 2:
- printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n",
- dev->name);
+ em28xx_info("\tI2S audio, sample rate=32k\n");
break;
case 3:
- printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n",
- dev->name);
+ em28xx_info("\tI2S audio, 3 sample rates\n");
break;
}
- if (em_eeprom->chip_conf & 1 << 3)
- printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name);
+ if (le16_to_cpu(dev_config->chip_conf) & 1 << 3)
+ em28xx_info("\tUSB Remote wakeup capable\n");
- if (em_eeprom->chip_conf & 1 << 2)
- printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name);
+ if (le16_to_cpu(dev_config->chip_conf) & 1 << 2)
+ em28xx_info("\tUSB Self power capable\n");
- switch (em_eeprom->chip_conf & 0x3) {
+ switch (le16_to_cpu(dev_config->chip_conf) & 0x3) {
case 0:
- printk(KERN_INFO "%s:\t500mA max power\n", dev->name);
+ em28xx_info("\t500mA max power\n");
break;
case 1:
- printk(KERN_INFO "%s:\t400mA max power\n", dev->name);
+ em28xx_info("\t400mA max power\n");
break;
case 2:
- printk(KERN_INFO "%s:\t300mA max power\n", dev->name);
+ em28xx_info("\t300mA max power\n");
break;
case 3:
- printk(KERN_INFO "%s:\t200mA max power\n", dev->name);
+ em28xx_info("\t200mA max power\n");
break;
}
- printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
- dev->name,
- em_eeprom->string_idx_table,
- em_eeprom->string1,
- em_eeprom->string2,
- em_eeprom->string3);
+ em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
+ dev_config->string_idx_table,
+ le16_to_cpu(dev_config->string1),
+ le16_to_cpu(dev_config->string2),
+ le16_to_cpu(dev_config->string3));
return 0;
+
+error:
+ kfree(data);
+ return err;
}
/* ----------------------------------------------------------- */
@@ -503,13 +781,20 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
/*
* functionality()
*/
-static u32 functionality(struct i2c_adapter *adap)
+static u32 functionality(struct i2c_adapter *i2c_adap)
{
- struct em28xx *dev = adap->algo_data;
- u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
- if (dev->board.is_em2800)
- func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
- return func_flags;
+ struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data;
+
+ if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) ||
+ (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) {
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+ } else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) {
+ return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) &
+ ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA;
+ }
+
+ WARN(1, "Unknown i2c bus algorithm.\n");
+ return 0;
}
static struct i2c_algorithm em28xx_algo = {
@@ -556,7 +841,7 @@ static char *i2c_devs[128] = {
* do_i2c_scan()
* check i2c address range for devices
*/
-void em28xx_do_i2c_scan(struct em28xx *dev)
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus)
{
u8 i2c_devicelist[128];
unsigned char buf;
@@ -565,55 +850,68 @@ void em28xx_do_i2c_scan(struct em28xx *dev)
memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist));
for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
- dev->i2c_client.addr = i;
- rc = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ dev->i2c_client[bus].addr = i;
+ rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0);
if (rc < 0)
continue;
i2c_devicelist[i] = i;
- printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n",
- dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n",
+ i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???");
}
- dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
- ARRAY_SIZE(i2c_devicelist), 32);
+ if (bus == dev->def_i2c_bus)
+ dev->i2c_hash = em28xx_hash_mem(i2c_devicelist,
+ ARRAY_SIZE(i2c_devicelist), 32);
}
/*
* em28xx_i2c_register()
* register i2c bus
*/
-int em28xx_i2c_register(struct em28xx *dev)
+int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+ enum em28xx_i2c_algo_type algo_type)
{
int retval;
BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg);
BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req);
- dev->i2c_adap = em28xx_adap_template;
- dev->i2c_adap.dev.parent = &dev->udev->dev;
- strcpy(dev->i2c_adap.name, dev->name);
- dev->i2c_adap.algo_data = dev;
- i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
- retval = i2c_add_adapter(&dev->i2c_adap);
+ if (bus >= NUM_I2C_BUSES)
+ return -ENODEV;
+
+ dev->i2c_adap[bus] = em28xx_adap_template;
+ dev->i2c_adap[bus].dev.parent = &dev->udev->dev;
+ strcpy(dev->i2c_adap[bus].name, dev->name);
+
+ dev->i2c_bus[bus].bus = bus;
+ dev->i2c_bus[bus].algo_type = algo_type;
+ dev->i2c_bus[bus].dev = dev;
+ dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
+ i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev);
+
+ retval = i2c_add_adapter(&dev->i2c_adap[bus]);
if (retval < 0) {
em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
__func__, retval);
return retval;
}
- dev->i2c_client = em28xx_client_template;
- dev->i2c_client.adapter = &dev->i2c_adap;
+ dev->i2c_client[bus] = em28xx_client_template;
+ dev->i2c_client[bus].adapter = &dev->i2c_adap[bus];
- retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
- if ((retval < 0) && (retval != -ENODEV)) {
- em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
- __func__, retval);
+ /* Up to now, all eeproms are at bus 0 */
+ if (!bus) {
+ retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
+ if ((retval < 0) && (retval != -ENODEV)) {
+ em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
+ __func__, retval);
- return retval;
+ return retval;
+ }
}
if (i2c_scan)
- em28xx_do_i2c_scan(dev);
+ em28xx_do_i2c_scan(dev, bus);
return 0;
}
@@ -622,8 +920,11 @@ int em28xx_i2c_register(struct em28xx *dev)
* em28xx_i2c_unregister()
* unregister i2c_bus
*/
-int em28xx_i2c_unregister(struct em28xx *dev)
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus)
{
- i2c_del_adapter(&dev->i2c_adap);
+ if (bus >= NUM_I2C_BUSES)
+ return -ENODEV;
+
+ i2c_del_adapter(&dev->i2c_adap[bus]);
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 1bef990b3f18..466b19d0d767 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -280,11 +280,12 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
+ struct em28xx *dev = ir->dev;
static u32 ir_key;
int rc;
struct i2c_client client;
- client.adapter = &ir->dev->i2c_adap;
+ client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
client.addr = ir->i2c_dev_addr;
rc = ir->get_key_i2c(&client, &ir_key);
@@ -461,7 +462,7 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
};
while (addr_list[i] != I2C_CLIENT_END) {
- if (i2c_probe_func_quick_read(&dev->i2c_adap, addr_list[i]) == 1)
+ if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1)
return addr_list[i];
i++;
}
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 885089e22bcd..622871db04aa 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -48,7 +48,7 @@
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03
- /* GPIO/GPO registers */
+/* GPIO/GPO registers */
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
@@ -120,12 +120,23 @@
#define EM28XX_R1E_CWIDTH 0x1e
#define EM28XX_R1F_CHEIGHT 0x1f
-#define EM28XX_R20_YGAIN 0x20
-#define EM28XX_R21_YOFFSET 0x21
-#define EM28XX_R22_UVGAIN 0x22
-#define EM28XX_R23_UOFFSET 0x23
-#define EM28XX_R24_VOFFSET 0x24
-#define EM28XX_R25_SHARPNESS 0x25
+#define EM28XX_R20_YGAIN 0x20 /* contrast [0:4] */
+#define CONTRAST_DEFAULT 0x10
+
+#define EM28XX_R21_YOFFSET 0x21 /* brightness */ /* signed */
+#define BRIGHTNESS_DEFAULT 0x00
+
+#define EM28XX_R22_UVGAIN 0x22 /* saturation [0:4] */
+#define SATURATION_DEFAULT 0x10
+
+#define EM28XX_R23_UOFFSET 0x23 /* blue balance */ /* signed */
+#define BLUE_BALANCE_DEFAULT 0x00
+
+#define EM28XX_R24_VOFFSET 0x24 /* red balance */ /* signed */
+#define RED_BALANCE_DEFAULT 0x00
+
+#define EM28XX_R25_SHARPNESS 0x25 /* sharpness [0:4] */
+#define SHARPNESS_DEFAULT 0x00
#define EM28XX_R26_COMPR 0x26
#define EM28XX_R27_OUTFMT 0x27
@@ -152,8 +163,17 @@
#define EM28XX_R31_HSCALEHIGH 0x31
#define EM28XX_R32_VSCALELOW 0x32
#define EM28XX_R33_VSCALEHIGH 0x33
+#define EM28XX_HVSCALE_MAX 0x3fff /* => 20% */
+
#define EM28XX_R34_VBI_START_H 0x34
#define EM28XX_R35_VBI_START_V 0x35
+/*
+ * NOTE: the EM276x (and EM25xx, EM277x/8x ?) (camera bridges) use these
+ * registers for a different unknown purpose.
+ * => register 0x34 is set to capture width / 16
+ * => register 0x35 is set to capture height / 16
+ */
+
#define EM28XX_R36_VBI_WIDTH 0x36
#define EM28XX_R37_VBI_HEIGHT 0x37
@@ -206,6 +226,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2860 = 34,
CHIP_ID_EM2870 = 35,
CHIP_ID_EM2883 = 36,
+ CHIP_ID_EM2765 = 54,
CHIP_ID_EM2874 = 65,
CHIP_ID_EM2884 = 68,
CHIP_ID_EM28174 = 113,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 32bd7de5dec1..32d60e5546bc 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -52,7 +52,7 @@
#define DRIVER_DESC "Empia em28xx based USB video device driver"
-#define EM28XX_VERSION "0.1.3"
+#define EM28XX_VERSION "0.2.0"
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
@@ -76,6 +76,16 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
+
+#define EM25XX_FRMDATAHDR_BYTE1 0x02
+#define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20
+#define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02
+#define EM25XX_FRMDATAHDR_BYTE2_FRAME_ID 0x01
+#define EM25XX_FRMDATAHDR_BYTE2_MASK (EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE | \
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_ID)
+
+
static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
@@ -408,6 +418,62 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
em28xx_copy_video(dev, buf, data_pkt, data_len);
}
+/*
+ * Process data packet according to the em25xx/em276x/7x/8x frame data format
+ */
+static inline void process_frame_data_em25xx(struct em28xx *dev,
+ unsigned char *data_pkt,
+ unsigned int data_len)
+{
+ struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
+ struct em28xx_dmaqueue *dmaq = &dev->vidq;
+ bool frame_end = 0;
+
+ /* Check for header */
+ /* NOTE: at least with bulk transfers, only the first packet
+ * has a header and has always set the FRAME_END bit */
+ if (data_len >= 2) { /* em25xx header is only 2 bytes long */
+ if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
+ ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
+ dev->top_field = !(data_pkt[1] &
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_ID);
+ frame_end = data_pkt[1] &
+ EM25XX_FRMDATAHDR_BYTE2_FRAME_END;
+ data_pkt += 2;
+ data_len -= 2;
+ }
+
+ /* Finish field and prepare next (BULK only) */
+ if (dev->analog_xfer_bulk && frame_end) {
+ buf = finish_field_prepare_next(dev, buf, dmaq);
+ dev->usb_ctl.vid_buf = buf;
+ }
+ /* NOTE: in ISOC mode when a new frame starts and buf==NULL,
+ * we COULD already prepare a buffer here to avoid skipping the
+ * first frame.
+ */
+ }
+
+ /* Copy data */
+ if (buf != NULL && data_len > 0)
+ em28xx_copy_video(dev, buf, data_pkt, data_len);
+
+ /* Finish frame (ISOC only) => avoids lag of 1 frame */
+ if (!dev->analog_xfer_bulk && frame_end) {
+ buf = finish_field_prepare_next(dev, buf, dmaq);
+ dev->usb_ctl.vid_buf = buf;
+ }
+
+ /* NOTE: Tested with USB bulk transfers only !
+ * The wording in the datasheet suggests that isoc might work different.
+ * The current code assumes that with isoc transfers each packet has a
+ * header like with the other em28xx devices.
+ */
+ /* NOTE: Support for interlaced mode is pure theory. It has not been
+ * tested and it is unknown if these devices actually support it. */
+ /* NOTE: No VBI support yet (these chips likely do not support VBI). */
+}
+
/* Processes and copies the URB data content (video and VBI data) */
static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
{
@@ -460,7 +526,13 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
continue;
}
- process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len);
+ if (dev->is_em25xx)
+ process_frame_data_em25xx(dev,
+ usb_data_pkt, usb_data_len);
+ else
+ process_frame_data_em28xx(dev,
+ usb_data_pkt, usb_data_len);
+
}
return 1;
}
@@ -700,6 +772,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_video_qops;
@@ -713,6 +786,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
q = &dev->vb_vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct em28xx_buffer);
q->ops = &em28xx_vbi_qops;
@@ -782,33 +856,45 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
+ int ret = -EINVAL;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
dev->mute = ctrl->val;
+ ret = em28xx_audio_analog_set(dev);
break;
case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->val;
+ ret = em28xx_audio_analog_set(dev);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = em28xx_write_reg(dev, EM28XX_R20_YGAIN, ctrl->val);
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ret = em28xx_write_reg(dev, EM28XX_R21_YOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ ret = em28xx_write_reg(dev, EM28XX_R22_UVGAIN, ctrl->val);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = em28xx_write_reg(dev, EM28XX_R23_UOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = em28xx_write_reg(dev, EM28XX_R24_VOFFSET, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ ret = em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, ctrl->val);
break;
}
- return em28xx_audio_analog_set(dev);
+ return (ret < 0) ? ret : 0;
}
const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
.s_ctrl = em28xx_s_ctrl,
};
-static int check_dev(struct em28xx *dev)
-{
- if (dev->disconnected) {
- em28xx_errdev("v4l2 ioctl: device not present\n");
- return -ENODEV;
- }
- return 0;
-}
-
-static void get_scale(struct em28xx *dev,
+static void size_to_scale(struct em28xx *dev,
unsigned int width, unsigned int height,
unsigned int *hscale, unsigned int *vscale)
{
@@ -816,12 +902,23 @@ static void get_scale(struct em28xx *dev,
unsigned int maxh = norm_maxh(dev);
*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
- if (*hscale >= 0x4000)
- *hscale = 0x3fff;
+ if (*hscale > EM28XX_HVSCALE_MAX)
+ *hscale = EM28XX_HVSCALE_MAX;
*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
- if (*vscale >= 0x4000)
- *vscale = 0x3fff;
+ if (*vscale > EM28XX_HVSCALE_MAX)
+ *vscale = EM28XX_HVSCALE_MAX;
+}
+
+static void scale_to_size(struct em28xx *dev,
+ unsigned int hscale, unsigned int vscale,
+ unsigned int *width, unsigned int *height)
+{
+ unsigned int maxw = norm_maxw(dev);
+ unsigned int maxh = norm_maxh(dev);
+
+ *width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+ *height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
}
/* ------------------------------------------------------------------
@@ -898,10 +995,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
1, 0);
}
- get_scale(dev, width, height, &hscale, &vscale);
-
- width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
- height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+ size_to_scale(dev, width, height, &hscale, &vscale);
+ scale_to_size(dev, hscale, vscale, &width, &height);
f->fmt.pix.width = width;
f->fmt.pix.height = height;
@@ -932,7 +1027,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
dev->height = height;
/* set new image size */
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
@@ -957,13 +1052,6 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- if (dev->board.is_webcam)
- return -ENOTTY;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
*norm = dev->norm;
@@ -974,48 +1062,35 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- if (dev->board.is_webcam)
- return -ENOTTY;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
struct v4l2_format f;
- int rc;
- if (dev->board.is_webcam)
- return -ENOTTY;
- if (*norm == dev->norm)
+ if (norm == dev->norm)
return 0;
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (dev->streaming_users > 0)
return -EBUSY;
- dev->norm = *norm;
+ dev->norm = norm;
/* Adjusts width/height, if needed */
f.fmt.pix.width = 720;
- f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576;
+ f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576;
vidioc_try_fmt_vid_cap(file, priv, &f);
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
@@ -1030,9 +1105,6 @@ static int vidioc_g_parm(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
int rc = 0;
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
if (dev->board.is_webcam)
rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
@@ -1050,12 +1122,6 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- if (!dev->board.is_webcam)
- return -ENOTTY;
-
- if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
}
@@ -1116,11 +1182,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (i >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1136,9 +1197,6 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
switch (a->index) {
case EM28XX_AMUX_VIDEO:
strcpy(a->name, "Television");
@@ -1179,10 +1237,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
-
- if (!dev->audio_mode.has_audio)
- return -EINVAL;
-
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
if (0 == INPUT(a->index)->type)
@@ -1202,11 +1256,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != t->index)
return -EINVAL;
@@ -1218,15 +1267,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != t->index)
return -EINVAL;
@@ -1249,39 +1293,22 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
+ struct v4l2_frequency new_freq = *f;
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
if (0 != f->tuner)
return -EINVAL;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
- dev->ctl_freq = f->frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ dev->ctl_freq = new_freq.frequency;
return 0;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int em28xx_reg_len(int reg)
-{
- switch (reg) {
- case EM28XX_R40_AC97LSB:
- case EM28XX_R30_HSCALELOW:
- case EM28XX_R32_VSCALELOW:
- return 2;
- default:
- return 1;
- }
-}
-
static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1290,9 +1317,9 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
- if (v4l2_chip_match_host(&chip->match))
- chip->ident = V4L2_IDENT_NONE;
+ if (chip->match.type == V4L2_CHIP_MATCH_BRIDGE) {
+ if (chip->match.addr > 1)
+ return -EINVAL;
return 0;
}
if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
@@ -1304,6 +1331,33 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_chip_info(struct file *file, void *priv,
+ struct v4l2_dbg_chip_info *chip)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ if (chip->match.addr > 1)
+ return -EINVAL;
+ if (chip->match.addr == 1)
+ strlcpy(chip->name, "ac97", sizeof(chip->name));
+ else
+ strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ return 0;
+}
+
+static int em28xx_reg_len(int reg)
+{
+ switch (reg) {
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
+ return 2;
+ default:
+ return 1;
+ }
+}
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -1313,6 +1367,12 @@ static int vidioc_g_register(struct file *file, void *priv,
int ret;
switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_BRIDGE:
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (!reg->match.addr)
+ break;
+ /* fall-through */
case V4L2_CHIP_MATCH_AC97:
ret = em28xx_read_ac97(dev, reg->reg);
if (ret < 0)
@@ -1329,8 +1389,7 @@ static int vidioc_g_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
return 0;
default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ return -EINVAL;
}
/* Match host */
@@ -1356,13 +1415,19 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
__le16 buf;
switch (reg->match.type) {
+ case V4L2_CHIP_MATCH_BRIDGE:
+ if (reg->match.addr > 1)
+ return -EINVAL;
+ if (!reg->match.addr)
+ break;
+ /* fall-through */
case V4L2_CHIP_MATCH_AC97:
return em28xx_write_ac97(dev, reg->reg, reg->val);
case V4L2_CHIP_MATCH_I2C_DRIVER:
@@ -1373,8 +1438,7 @@ static int vidioc_s_register(struct file *file, void *priv,
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
return 0;
default:
- if (!v4l2_chip_match_host(&reg->match))
- return -EINVAL;
+ return -EINVAL;
}
/* Match host */
@@ -1386,26 +1450,6 @@ static int vidioc_s_register(struct file *file, void *priv,
#endif
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cc)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- cc->bounds.left = 0;
- cc->bounds.top = 0;
- cc->bounds.width = dev->width;
- cc->bounds.height = dev->height;
- cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
-
- return 0;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -1482,8 +1526,12 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
/* Report a continuous range */
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise.min_width = 48;
- fsize->stepwise.min_height = 32;
+ scale_to_size(dev, EM28XX_HVSCALE_MAX, EM28XX_HVSCALE_MAX,
+ &fsize->stepwise.min_width, &fsize->stepwise.min_height);
+ if (fsize->stepwise.min_width < 48)
+ fsize->stepwise.min_width = 48;
+ if (fsize->stepwise.min_height < 38)
+ fsize->stepwise.min_height = 38;
fsize->stepwise.max_width = maxw;
fsize->stepwise.max_height = maxh;
fsize->stepwise.step_width = 1;
@@ -1522,35 +1570,6 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
- struct v4l2_format *format)
-{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
-
- format->fmt.vbi.samples_per_line = dev->vbi_width;
- format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- format->fmt.vbi.offset = 0;
- format->fmt.vbi.flags = 0;
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
- memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
-
- /* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- format->fmt.vbi.start[0] = 6;
- format->fmt.vbi.start[1] = 318;
- }
-
- return 0;
-}
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -1564,7 +1583,6 @@ static int radio_g_tuner(struct file *file, void *priv,
return -EINVAL;
strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
@@ -1572,7 +1590,7 @@ static int radio_g_tuner(struct file *file, void *priv,
}
static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
@@ -1749,11 +1767,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
- .vidioc_cropcap = vidioc_cropcap,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -1778,10 +1795,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
- .vidioc_g_chip_ident = vidioc_g_chip_ident,
#endif
};
@@ -1808,7 +1826,9 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_chip_info = vidioc_g_chip_info,
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
@@ -1887,9 +1907,42 @@ int em28xx_register_analog_devices(struct em28xx *dev)
(EM28XX_XCLK_AUDIO_UNMUTE | val));
em28xx_set_outfmt(dev);
- em28xx_colorlevels_set_default(dev);
em28xx_compression_disable(dev);
+ /* Add image controls */
+ /* NOTE: at this point, the subdevices are already registered, so bridge
+ * controls are only added/enabled when no subdevice provides them */
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_CONTRAST,
+ 0, 0x1f, 1, CONTRAST_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_BRIGHTNESS,
+ -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_SATURATION,
+ 0, 0x1f, 1, SATURATION_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE,
+ -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_RED_BALANCE,
+ -0x30, 0x30, 1, RED_BALANCE_DEFAULT);
+ if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS))
+ v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ V4L2_CID_SHARPNESS,
+ 0, 0x0f, 1, SHARPNESS_DEFAULT);
+
+ /* Reset image controls */
+ em28xx_colorlevels_set_default(dev);
+ v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+ if (dev->ctrl_handler.error)
+ return dev->ctrl_handler.error;
+
/* allocate and fill video video_device struct */
dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
if (!dev->vdev) {
@@ -1899,6 +1952,25 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->vdev->queue = &dev->vb_vidq;
dev->vdev->queue->lock = &dev->vb_queue_lock;
+ /* disable inapplicable ioctls */
+ if (dev->board.is_webcam) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD);
+ } else {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ }
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY);
+ }
+ if (!dev->audio_mode.has_audio) {
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO);
+ }
+
/* register v4l2 video video_device */
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
@@ -1916,6 +1988,19 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->vbi_dev->queue = &dev->vb_vbiq;
dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+ /* disable inapplicable ioctls */
+ v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ if (dev->tuner_type == TUNER_ABSENT) {
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY);
+ }
+ if (!dev->audio_mode.has_audio) {
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO);
+ }
+
/* register v4l2 vbi video_device */
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 5f0b2c59e846..a9323b63d8e5 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -42,28 +42,28 @@
#include "em28xx-reg.h"
/* Boards supported by driver */
-#define EM2800_BOARD_UNKNOWN 0
-#define EM2820_BOARD_UNKNOWN 1
-#define EM2820_BOARD_TERRATEC_CINERGY_250 2
-#define EM2820_BOARD_PINNACLE_USB_2 3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
-#define EM2820_BOARD_MSI_VOX_USB_2 5
-#define EM2800_BOARD_TERRATEC_CINERGY_200 6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
-#define EM2800_BOARD_KWORLD_USB2800 8
-#define EM2820_BOARD_PINNACLE_DVC_90 9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
-#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
-#define EM2800_BOARD_VGEAR_POCKETTV 15
-#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16
-#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
-#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
-#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
-#define EM2800_BOARD_GRABBEEX_USB2800 21
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
+#define EM2800_BOARD_VGEAR_POCKETTV 15
+#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19
+#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20
+#define EM2800_BOARD_GRABBEEX_USB2800 21
#define EM2750_BOARD_UNKNOWN 22
#define EM2750_BOARD_DLCW_130 23
#define EM2820_BOARD_DLINK_USB_TV 24
@@ -99,36 +99,37 @@
#define EM2882_BOARD_KWORLD_VS_DVBT 54
#define EM2882_BOARD_TERRATEC_HYBRID_XS 55
#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
-#define EM2883_BOARD_KWORLD_HYBRID_330U 57
+#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
#define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61
#define EM2820_BOARD_GADMEI_TVR200 62
-#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
-#define EM2860_BOARD_EASYCAP 64
+#define EM2860_BOARD_KAIOMY_TVNPC_U2 63
+#define EM2860_BOARD_EASYCAP 64
#define EM2820_BOARD_IODATA_GVMVP_SZ 65
#define EM2880_BOARD_EMPIRE_DUAL_TV 66
#define EM2860_BOARD_TERRATEC_GRABBY 67
#define EM2860_BOARD_TERRATEC_AV350 68
#define EM2882_BOARD_KWORLD_ATSC_315U 69
#define EM2882_BOARD_EVGA_INDTUBE 70
-#define EM2820_BOARD_SILVERCREST_WEBCAM 71
-#define EM2861_BOARD_GADMEI_UTV330PLUS 72
-#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
+#define EM2820_BOARD_SILVERCREST_WEBCAM 71
+#define EM2861_BOARD_GADMEI_UTV330PLUS 72
+#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
#define EM2800_BOARD_VC211A 74
#define EM2882_BOARD_DIKOM_DK300 75
#define EM2870_BOARD_KWORLD_A340 76
#define EM2874_BOARD_LEADERSHIP_ISDBT 77
-#define EM28174_BOARD_PCTV_290E 78
+#define EM28174_BOARD_PCTV_290E 78
#define EM2884_BOARD_TERRATEC_H5 79
-#define EM28174_BOARD_PCTV_460E 80
+#define EM28174_BOARD_PCTV_460E 80
#define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81
#define EM2884_BOARD_CINERGY_HTC_STICK 82
-#define EM2860_BOARD_HT_VIDBOX_NW03 83
-#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
-#define EM2884_BOARD_PCTV_510E 85
-#define EM2884_BOARD_PCTV_520E 86
+#define EM2860_BOARD_HT_VIDBOX_NW03 83
+#define EM2874_BOARD_MAXMEDIA_UB425_TC 84
+#define EM2884_BOARD_PCTV_510E 85
+#define EM2884_BOARD_PCTV_520E 86
#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87
+#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -157,6 +158,9 @@
#define EM28XX_NUM_BUFS 5
#define EM28XX_DVB_NUM_BUFS 5
+/* max number of I2C buses on em28xx devices */
+#define NUM_I2C_BUSES 2
+
/* isoc transfers: number of packets for each buffer
windows requests only 64 packets .. so we better do the same
this is what I found out for all alternate numbers there!
@@ -172,27 +176,6 @@
#define EM28XX_INTERLACED_DEFAULT 1
-/*
-#define (use usbview if you want to get the other alternate number infos)
-#define
-#define alternate number 2
-#define Endpoint Address: 82
- Direction: in
- Attribute: 1
- Type: Isoc
- Max Packet Size: 1448
- Interval: 125us
-
- alternate number 7
-
- Endpoint Address: 82
- Direction: in
- Attribute: 1
- Type: Isoc
- Max Packet Size: 3072
- Interval: 125us
-*/
-
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_XFER_TIMEOUT 20
@@ -381,6 +364,7 @@ enum em28xx_sensor {
EM28XX_MT9V011,
EM28XX_MT9M001,
EM28XX_MT9M111,
+ EM28XX_OV2640,
};
enum em28xx_adecoder {
@@ -393,6 +377,7 @@ struct em28xx_board {
int vchannels;
int tuner_type;
int tuner_addr;
+ unsigned def_i2c_bus; /* Default I2C bus */
/* i2c flags */
unsigned int tda9887_conf;
@@ -426,15 +411,15 @@ struct em28xx_board {
};
struct em28xx_eeprom {
- u32 id; /* 0x9567eb1a */
- u16 vendor_ID;
- u16 product_ID;
+ u8 id[4]; /* 1a eb 67 95 */
+ __le16 vendor_ID;
+ __le16 product_ID;
- u16 chip_conf;
+ __le16 chip_conf;
- u16 board_conf;
+ __le16 board_conf;
- u16 string1, string2, string3;
+ __le16 string1, string2, string3;
u8 string_idx_table;
};
@@ -477,6 +462,20 @@ struct em28xx_fh {
enum v4l2_buf_type type;
};
+enum em28xx_i2c_algo_type {
+ EM28XX_I2C_ALGO_EM28XX = 0,
+ EM28XX_I2C_ALGO_EM2800,
+ EM28XX_I2C_ALGO_EM25XX_BUS_B,
+};
+
+struct em28xx_i2c_bus {
+ struct em28xx *dev;
+
+ unsigned bus;
+ enum em28xx_i2c_algo_type algo_type;
+};
+
+
/* main device struct */
struct em28xx {
/* generic device properties */
@@ -484,6 +483,7 @@ struct em28xx {
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
+ unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
unsigned char disconnected:1; /* device has been diconnected */
@@ -491,8 +491,6 @@ struct em28xx {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
- /* provides ac97 mute and volume overrides */
- struct v4l2_ctrl_handler ac97_ctrl_handler;
struct em28xx_board board;
/* Webcam specific fields */
@@ -511,8 +509,8 @@ struct em28xx {
unsigned int is_audio_only:1;
/* Controls audio streaming */
- struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
- atomic_t stream_started; /* stream should be running if true */
+ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
+ atomic_t stream_started; /* stream should be running if true */
struct em28xx_fmt *format;
@@ -530,9 +528,17 @@ struct em28xx {
int tuner_type; /* type of the tuner */
int tuner_addr; /* tuner address */
int tda9887_conf;
+
/* i2c i/o */
- struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
+ struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
+ struct i2c_client i2c_client[NUM_I2C_BUSES];
+ struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES];
+
+ unsigned char eeprom_addrwidth_16bit:1;
+ unsigned def_i2c_bus; /* Default I2C bus */
+ unsigned cur_i2c_bus; /* Current I2C bus */
+ struct rt_mutex i2c_bus_lock;
+
/* video for linux */
int users; /* user count for exclusive use */
int streaming_users; /* Number of actively streaming users */
@@ -584,7 +590,9 @@ struct em28xx {
/* resources in use */
unsigned int resources;
- unsigned char eedata[256];
+ /* eeprom content */
+ u8 *eedata;
+ u16 eedata_len;
/* Isoc control struct */
struct em28xx_dmaqueue vidq;
@@ -600,7 +608,7 @@ struct em28xx {
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
- u8 dvb_ep_bulk; /* address of bulk endpoint for DVC */
+ u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
int alt; /* alternate setting */
int max_pkt_size; /* max packet size of the selected ep at alt */
int packet_multiplier; /* multiplier for wMaxPacketSize, used for
@@ -651,16 +659,12 @@ struct em28xx_ops {
};
/* Provided by em28xx-i2c.c */
-void em28xx_do_i2c_scan(struct em28xx *dev);
-int em28xx_i2c_register(struct em28xx *dev);
-int em28xx_i2c_unregister(struct em28xx *dev);
+void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus);
+int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
+ enum em28xx_i2c_algo_type algo_type);
+int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus);
/* Provided by em28xx-core.c */
-
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count);
-void em28xx_queue_unusedframes(struct em28xx *dev);
-void em28xx_release_buffers(struct em28xx *dev);
-
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
char *buf, int len);
int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg);
@@ -693,7 +697,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
(struct em28xx *dev, struct urb *urb));
void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
-int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
void em28xx_wake_i2c(struct em28xx *dev);
@@ -712,16 +715,18 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
/* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device *udev, int model);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
-extern const unsigned int em28xx_bcount;
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_release_resources(struct em28xx *dev);
/* Provided by em28xx-vbi.c */
extern struct vb2_ops em28xx_vbi_qops;
+/* Provided by em28xx-camera.c */
+int em28xx_detect_sensor(struct em28xx *dev);
+int em28xx_init_camera(struct em28xx *dev);
+
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
@@ -744,72 +749,6 @@ static inline int em28xx_compression_disable(struct em28xx *dev)
return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
}
-static inline int em28xx_contrast_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
-}
-
-static inline int em28xx_brightness_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
-}
-
-static inline int em28xx_saturation_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
-}
-
-static inline int em28xx_u_balance_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
-}
-
-static inline int em28xx_v_balance_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
-}
-
-static inline int em28xx_gamma_get(struct em28xx *dev)
-{
- return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
-}
-
-static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
-}
-
-static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
-}
-
-static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
-}
-
-static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
-{
- u8 tmp = (u8) val;
- return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
-}
-
/*FIXME: maxw should be dependent of alt mode */
static inline unsigned int norm_maxw(struct em28xx *dev)
{
diff --git a/drivers/media/usb/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h
deleted file mode 100644
index d625eafe63eb..000000000000
--- a/drivers/media/usb/gspca/autogain_functions.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Functions for auto gain.
- *
- * Copyright (C) 2010-2011 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifdef WANT_REGULAR_AUTOGAIN
-/* auto gain and exposure algorithm based on the knee algorithm described here:
- http://ytse.tricolour.net/docs/LowLightOptimization.html
-
- Returns 0 if no changes were made, 1 if the gain and or exposure settings
- where changed. */
-static inline int auto_gain_n_exposure(
- struct gspca_dev *gspca_dev,
- int avg_lum,
- int desired_avg_lum,
- int deadzone,
- int gain_knee,
- int exposure_knee)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i, steps, gain, orig_gain, exposure, orig_exposure;
- int retval = 0;
-
- orig_gain = gain = sd->ctrls[GAIN].val;
- orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
-
- /* If we are of a multiple of deadzone, do multiple steps to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = abs(desired_avg_lum - avg_lum) / deadzone;
-
- PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
- avg_lum, desired_avg_lum, steps);
-
- for (i = 0; i < steps; i++) {
- if (avg_lum > desired_avg_lum) {
- if (gain > gain_knee)
- gain--;
- else if (exposure > exposure_knee)
- exposure--;
- else if (gain > sd->ctrls[GAIN].def)
- gain--;
- else if (exposure > sd->ctrls[EXPOSURE].min)
- exposure--;
- else if (gain > sd->ctrls[GAIN].min)
- gain--;
- else
- break;
- } else {
- if (gain < sd->ctrls[GAIN].def)
- gain++;
- else if (exposure < exposure_knee)
- exposure++;
- else if (gain < gain_knee)
- gain++;
- else if (exposure < sd->ctrls[EXPOSURE].max)
- exposure++;
- else if (gain < sd->ctrls[GAIN].max)
- gain++;
- else
- break;
- }
- }
-
- if (gain != orig_gain) {
- sd->ctrls[GAIN].val = gain;
- setgain(gspca_dev);
- retval = 1;
- }
- if (exposure != orig_exposure) {
- sd->ctrls[EXPOSURE].val = exposure;
- setexposure(gspca_dev);
- retval = 1;
- }
-
- if (retval)
- PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
- gain, exposure);
- return retval;
-}
-#endif
-
-#ifdef WANT_COARSE_EXPO_AUTOGAIN
-/* Autogain + exposure algorithm for cameras with a coarse exposure control
- (usually this means we can only control the clockdiv to change exposure)
- As changing the clockdiv so that the fps drops from 30 to 15 fps for
- example, will lead to a huge exposure change (it effectively doubles),
- this algorithm normally tries to only adjust the gain (between 40 and
- 80 %) and if that does not help, only then changes exposure. This leads
- to a much more stable image then using the knee algorithm which at
- certain points of the knee graph will only try to adjust exposure,
- which leads to oscilating as one exposure step is huge.
-
- Note this assumes that the sd struct for the cam in question has
- exp_too_low_cnt and exp_too_high_cnt int members for use by this function.
-
- Returns 0 if no changes were made, 1 if the gain and or exposure settings
- where changed. */
-static inline int coarse_grained_expo_autogain(
- struct gspca_dev *gspca_dev,
- int avg_lum,
- int desired_avg_lum,
- int deadzone)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int steps, gain, orig_gain, exposure, orig_exposure;
- int gain_low, gain_high;
- int retval = 0;
-
- orig_gain = gain = sd->ctrls[GAIN].val;
- orig_exposure = exposure = sd->ctrls[EXPOSURE].val;
-
- gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2;
- gain_low += sd->ctrls[GAIN].min;
- gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4;
- gain_high += sd->ctrls[GAIN].min;
-
- /* If we are of a multiple of deadzone, do multiple steps to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = (desired_avg_lum - avg_lum) / deadzone;
-
- PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
- avg_lum, desired_avg_lum, steps);
-
- if ((gain + steps) > gain_high &&
- exposure < sd->ctrls[EXPOSURE].max) {
- gain = gain_high;
- sd->exp_too_low_cnt++;
- sd->exp_too_high_cnt = 0;
- } else if ((gain + steps) < gain_low &&
- exposure > sd->ctrls[EXPOSURE].min) {
- gain = gain_low;
- sd->exp_too_high_cnt++;
- sd->exp_too_low_cnt = 0;
- } else {
- gain += steps;
- if (gain > sd->ctrls[GAIN].max)
- gain = sd->ctrls[GAIN].max;
- else if (gain < sd->ctrls[GAIN].min)
- gain = sd->ctrls[GAIN].min;
- sd->exp_too_high_cnt = 0;
- sd->exp_too_low_cnt = 0;
- }
-
- if (sd->exp_too_high_cnt > 3) {
- exposure--;
- sd->exp_too_high_cnt = 0;
- } else if (sd->exp_too_low_cnt > 3) {
- exposure++;
- sd->exp_too_low_cnt = 0;
- }
-
- if (gain != orig_gain) {
- sd->ctrls[GAIN].val = gain;
- setgain(gspca_dev);
- retval = 1;
- }
- if (exposure != orig_exposure) {
- sd->ctrls[EXPOSURE].val = exposure;
- setexposure(gspca_dev);
- retval = 1;
- }
-
- if (retval)
- PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
- gain, exposure);
- return retval;
-}
-#endif
diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c
index 352f32190e68..05f406deae13 100644
--- a/drivers/media/usb/gspca/benq.c
+++ b/drivers/media/usb/gspca/benq.c
@@ -186,7 +186,7 @@ static void sd_isoc_irq(struct urb *urb)
/* check the packet status and length */
if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ
|| urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) {
- PDEBUG(D_ERR, "ISOC bad lengths %d / %d",
+ PERR("ISOC bad lengths %d / %d",
urb0->iso_frame_desc[i].actual_length,
urb->iso_frame_desc[i].actual_length);
gspca_dev->last_packet_type = DISCARD_PACKET;
diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c
index c9052f20435e..38714df31ac4 100644
--- a/drivers/media/usb/gspca/conex.c
+++ b/drivers/media/usb/gspca/conex.c
@@ -73,12 +73,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
usb_control_msg(dev,
usb_rcvctrlpipe(dev, 0),
0,
@@ -113,13 +112,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_w: buffer overflow\n");
+ PERR("reg_w: buffer overflow\n");
return;
}
PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -689,7 +687,7 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
reg_w_val(gspca_dev, 0x0053, 0x00);
} while (--retry);
if (retry == 0)
- PDEBUG(D_ERR, "Damned Errors sending jpeg Table");
+ PERR("Damned Errors sending jpeg Table");
/* send the qtable now */
reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */
length = 8;
diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c
index 1dcdd9f95f1c..064b53043b15 100644
--- a/drivers/media/usb/gspca/cpia1.c
+++ b/drivers/media/usb/gspca/cpia1.c
@@ -421,8 +421,7 @@ static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)
pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
} else {
- PDEBUG(D_ERR, "Unexpected first byte of command: %x",
- command[0]);
+ PERR("Unexpected first byte of command: %x", command[0]);
return -EINVAL;
}
@@ -701,7 +700,7 @@ static void reset_camera_params(struct gspca_dev *gspca_dev)
params->qx3.cradled = 0;
}
-static void printstatus(struct cam_params *params)
+static void printstatus(struct gspca_dev *gspca_dev, struct cam_params *params)
{
PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x",
params->status.systemState, params->status.grabState,
@@ -725,10 +724,9 @@ static int goto_low_power(struct gspca_dev *gspca_dev)
if (sd->params.status.systemState != LO_POWER_STATE) {
if (sd->params.status.systemState != WARM_BOOT_STATE) {
- PDEBUG(D_ERR,
- "unexpected state after lo power cmd: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected state after lo power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
}
return -EIO;
}
@@ -756,9 +754,9 @@ static int goto_high_power(struct gspca_dev *gspca_dev)
return ret;
if (sd->params.status.systemState != HI_POWER_STATE) {
- PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected state after hi power cmd: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
return -EIO;
}
@@ -1449,8 +1447,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->params.version.firmwareVersion = 0;
get_version_information(gspca_dev);
if (sd->params.version.firmwareVersion != 1) {
- PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",
- sd->params.version.firmwareVersion);
+ PERR("only firmware version 1 is supported (got: %d)",
+ sd->params.version.firmwareVersion);
return -ENODEV;
}
@@ -1475,9 +1473,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Start the camera in low power mode */
if (goto_low_power(gspca_dev)) {
if (sd->params.status.systemState != WARM_BOOT_STATE) {
- PDEBUG(D_ERR, "unexpected systemstate: %02x",
- sd->params.status.systemState);
- printstatus(&sd->params);
+ PERR("unexpected systemstate: %02x",
+ sd->params.status.systemState);
+ printstatus(gspca_dev, &sd->params);
return -ENODEV;
}
@@ -1523,9 +1521,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
return ret;
if (sd->params.status.fatalError) {
- PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x",
- sd->params.status.fatalError,
- sd->params.status.vpStatus);
+ PERR("fatal_error: %04x, vp_status: %04x",
+ sd->params.status.fatalError, sd->params.status.vpStatus);
return -EIO;
}
diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c
index 38f68e11c3a2..26c9ee1f1045 100644
--- a/drivers/media/usb/gspca/etoms.c
+++ b/drivers/media/usb/gspca/etoms.c
@@ -163,12 +163,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
usb_control_msg(dev,
usb_rcvctrlpipe(dev, 0),
0,
@@ -201,13 +200,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
{
struct usb_device *dev = gspca_dev->dev;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
pr_err("reg_w: buffer overflow\n");
return;
}
PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer);
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -274,7 +272,7 @@ static int et_video(struct gspca_dev *gspca_dev,
: 0); /* stopvideo */
ret = Et_WaitStatus(gspca_dev);
if (ret != 0)
- PDEBUG(D_ERR, "timeout video on/off");
+ PERR("timeout video on/off");
return ret;
}
@@ -768,9 +766,7 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
-#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
-#endif
{}
};
diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c
index ced3b71f14e5..cb1e64ca59c9 100644
--- a/drivers/media/usb/gspca/gl860/gl860.c
+++ b/drivers/media/usb/gspca/gl860/gl860.c
@@ -58,115 +58,135 @@ MODULE_PARM_DESC(sensor,
/*============================ webcam controls =============================*/
-/* Functions to get and set a control value */
-#define SD_SETGET(thename) \
-static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
-{\
- struct sd *sd = (struct sd *) gspca_dev;\
-\
- sd->vcur.thename = val;\
- if (gspca_dev->streaming)\
- sd->waitSet = 1;\
- return 0;\
-} \
-static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
-{\
- struct sd *sd = (struct sd *) gspca_dev;\
-\
- *val = sd->vcur.thename;\
- return 0;\
-}
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
-SD_SETGET(mirror)
-SD_SETGET(flip)
-SD_SETGET(AC50Hz)
-SD_SETGET(backlight)
-SD_SETGET(brightness)
-SD_SETGET(gamma)
-SD_SETGET(hue)
-SD_SETGET(saturation)
-SD_SETGET(sharpness)
-SD_SETGET(whitebal)
-SD_SETGET(contrast)
-
-#define GL860_NCTRLS 11
-
-/* control table */
-static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
-static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
-
-#define SET_MY_CTRL(theid, \
- thetype, thelabel, thename) \
- if (sd->vmax.thename != 0) {\
- sd_ctrls[nCtrls].qctrl.id = theid;\
- sd_ctrls[nCtrls].qctrl.type = thetype;\
- strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\
- sd_ctrls[nCtrls].qctrl.minimum = 0;\
- sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\
- sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\
- sd_ctrls[nCtrls].qctrl.step = \
- (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\
- sd_ctrls[nCtrls].set = sd_set_##thename;\
- sd_ctrls[nCtrls].get = sd_get_##thename;\
- nCtrls++;\
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sd->vcur.brightness = ctrl->val;
+ break;
+ case V4L2_CID_CONTRAST:
+ sd->vcur.contrast = ctrl->val;
+ break;
+ case V4L2_CID_SATURATION:
+ sd->vcur.saturation = ctrl->val;
+ break;
+ case V4L2_CID_HUE:
+ sd->vcur.hue = ctrl->val;
+ break;
+ case V4L2_CID_GAMMA:
+ sd->vcur.gamma = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ sd->vcur.mirror = ctrl->val;
+ break;
+ case V4L2_CID_VFLIP:
+ sd->vcur.flip = ctrl->val;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ sd->vcur.AC50Hz = ctrl->val;
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ sd->vcur.whitebal = ctrl->val;
+ break;
+ case V4L2_CID_SHARPNESS:
+ sd->vcur.sharpness = ctrl->val;
+ break;
+ case V4L2_CID_BACKLIGHT_COMPENSATION:
+ sd->vcur.backlight = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
}
-static int gl860_build_control_table(struct gspca_dev *gspca_dev)
+ if (gspca_dev->streaming)
+ sd->waitSet = 1;
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct ctrl *sd_ctrls;
- int nCtrls = 0;
-
- if (_MI1320_)
- sd_ctrls = sd_ctrls_mi1320;
- else if (_MI2020_)
- sd_ctrls = sd_ctrls_mi2020;
- else if (_OV2640_)
- sd_ctrls = sd_ctrls_ov2640;
- else if (_OV9655_)
- sd_ctrls = sd_ctrls_ov9655;
- else
- return 0;
-
- memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl));
-
- SET_MY_CTRL(V4L2_CID_BRIGHTNESS,
- V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness)
- SET_MY_CTRL(V4L2_CID_SHARPNESS,
- V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness)
- SET_MY_CTRL(V4L2_CID_CONTRAST,
- V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast)
- SET_MY_CTRL(V4L2_CID_GAMMA,
- V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma)
- SET_MY_CTRL(V4L2_CID_HUE,
- V4L2_CTRL_TYPE_INTEGER, "Palette", hue)
- SET_MY_CTRL(V4L2_CID_SATURATION,
- V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation)
- SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE,
- V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal)
- SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION,
- V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight)
-
- SET_MY_CTRL(V4L2_CID_HFLIP,
- V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror)
- SET_MY_CTRL(V4L2_CID_VFLIP,
- V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip)
- SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY,
- V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz)
-
- return nCtrls;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 11);
+
+ if (sd->vmax.brightness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, sd->vmax.brightness, 1,
+ sd->vcur.brightness);
+
+ if (sd->vmax.contrast)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_CONTRAST,
+ 0, sd->vmax.contrast, 1,
+ sd->vcur.contrast);
+
+ if (sd->vmax.saturation)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SATURATION,
+ 0, sd->vmax.saturation, 1,
+ sd->vcur.saturation);
+
+ if (sd->vmax.hue)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HUE,
+ 0, sd->vmax.hue, 1, sd->vcur.hue);
+
+ if (sd->vmax.gamma)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAMMA,
+ 0, sd->vmax.gamma, 1, sd->vcur.gamma);
+
+ if (sd->vmax.mirror)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HFLIP,
+ 0, sd->vmax.mirror, 1, sd->vcur.mirror);
+
+ if (sd->vmax.flip)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_VFLIP,
+ 0, sd->vmax.flip, 1, sd->vcur.flip);
+
+ if (sd->vmax.AC50Hz)
+ v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ sd->vmax.AC50Hz, 0, sd->vcur.AC50Hz);
+
+ if (sd->vmax.whitebal)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ 0, sd->vmax.whitebal, 1, sd->vcur.whitebal);
+
+ if (sd->vmax.sharpness)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SHARPNESS,
+ 0, sd->vmax.sharpness, 1,
+ sd->vcur.sharpness);
+
+ if (sd->vmax.backlight)
+ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BACKLIGHT_COMPENSATION,
+ 0, sd->vmax.backlight, 1,
+ sd->vcur.backlight);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ return 0;
}
/*==================== sud-driver structure initialisation =================*/
static const struct sd_desc sd_desc_mi1320 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_mi1320,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -176,10 +196,9 @@ static const struct sd_desc sd_desc_mi1320 = {
static const struct sd_desc sd_desc_mi2020 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_mi2020,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -189,10 +208,9 @@ static const struct sd_desc sd_desc_mi2020 = {
static const struct sd_desc sd_desc_ov2640 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_ov2640,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -202,10 +220,9 @@ static const struct sd_desc sd_desc_ov2640 = {
static const struct sd_desc sd_desc_ov9655 = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls_ov9655,
- .nctrls = GL860_NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stop0 = sd_stop0,
@@ -371,7 +388,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
dev_init_settings(gspca_dev);
if (AC50Hz != 0xff)
((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz;
- gl860_build_control_table(gspca_dev);
return 0;
}
@@ -566,7 +582,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n",
r, pref, req, val, index, len);
else if (len > 1 && r < len)
- PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
+ PERR("short ctrl transfer %d/%d", r, len);
msleep(1);
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 3564bdbb2ea3..5995ec4de6bc 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -60,14 +60,14 @@ MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(GSPCA_VERSION);
-#ifdef GSPCA_DEBUG
-int gspca_debug = D_ERR | D_PROBE;
+int gspca_debug;
EXPORT_SYMBOL(gspca_debug);
-static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
+static void PDEBUG_MODE(struct gspca_dev *gspca_dev, int debug, char *txt,
+ __u32 pixfmt, int w, int h)
{
if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') {
- PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d",
+ PDEBUG(debug, "%s %c%c%c%c %dx%d",
txt,
pixfmt & 0xff,
(pixfmt >> 8) & 0xff,
@@ -75,15 +75,12 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h)
pixfmt >> 24,
w, h);
} else {
- PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d",
+ PDEBUG(debug, "%s 0x%08x %dx%d",
txt,
pixfmt,
w, h);
}
}
-#else
-#define PDEBUG_MODE(txt, pixfmt, w, h)
-#endif
/* specific memory types - !! should be different from V4L2_MEMORY_xxx */
#define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */
@@ -129,7 +126,7 @@ static void int_irq(struct urb *urb)
case 0:
if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev,
urb->transfer_buffer, urb->actual_length) < 0) {
- PDEBUG(D_ERR, "Unknown packet received");
+ PERR("Unknown packet received");
}
break;
@@ -143,7 +140,7 @@ static void int_irq(struct urb *urb)
break;
default:
- PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status);
+ PERR("URB error %i, resubmitting", urb->status);
urb->status = 0;
ret = 0;
}
@@ -229,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
- PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
+ PERR("submit int URB failed with error %i", ret);
goto error_submit;
}
gspca_dev->int_urb = urb;
@@ -315,7 +312,7 @@ static void fill_frame(struct gspca_dev *gspca_dev,
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
urb->status = 0;
goto resubmit;
}
@@ -388,7 +385,7 @@ static void bulk_irq(struct urb *urb)
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
urb->status = 0;
goto resubmit;
}
@@ -460,7 +457,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
/* append the packet to the frame buffer */
if (len > 0) {
if (gspca_dev->image_len + len > gspca_dev->frsz) {
- PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ PERR("frame overflow %d > %d",
gspca_dev->image_len + len,
gspca_dev->frsz);
packet_type = DISCARD_PACKET;
@@ -570,11 +567,10 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
gspca_dev->urb[i] = NULL;
usb_kill_urb(urb);
- if (urb->transfer_buffer != NULL)
- usb_free_coherent(gspca_dev->dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
+ usb_free_coherent(gspca_dev->dev,
+ urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_dma);
usb_free_urb(urb);
}
}
@@ -960,9 +956,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* the bandwidth is not wide enough
* negotiate or try a lower alternate setting */
retry:
- PDEBUG(D_ERR|D_STREAM,
- "alt %d - bandwidth not wide enough - trying again",
- alt);
+ PERR("alt %d - bandwidth not wide enough, trying again", alt);
msleep(20); /* wait for kill complete */
if (gspca_dev->sd_desc->isoc_nego) {
ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
@@ -984,7 +978,6 @@ out:
static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
{
- struct gspca_ctrl *ctrl;
int i;
i = gspca_dev->cam.nmodes - 1; /* take the highest mode */
@@ -993,17 +986,8 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
- /* set the current control values to their default values
- * which may have changed in sd_init() */
/* does nothing if ctrl_handler == NULL */
v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
- ctrl = gspca_dev->cam.ctrls;
- if (ctrl != NULL) {
- for (i = 0;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrl++)
- ctrl->val = ctrl->def;
- }
}
static int wxh_to_mode(struct gspca_dev *gspca_dev,
@@ -1055,7 +1039,7 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct gspca_dev *gspca_dev = video_drvdata(file);
@@ -1137,10 +1121,9 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_CONF)
- PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
-#endif
+ PDEBUG_MODE(gspca_dev, D_CONF, "try fmt cap",
+ fmt->fmt.pix.pixelformat, w, h);
+
/* search the closest mode for width and height */
mode = wxh_to_mode(gspca_dev, w, h);
@@ -1153,8 +1136,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
fmt->fmt.pix.pixelformat);
if (mode2 >= 0)
mode = mode2;
-/* else
- ; * no chance, return this mode */
}
fmt->fmt.pix = gspca_dev->cam.cam_mode[mode];
/* some drivers use priv internally, zero it before giving it to
@@ -1290,15 +1271,6 @@ static int dev_open(struct file *file)
if (!try_module_get(gspca_dev->module))
return -ENODEV;
-#ifdef GSPCA_DEBUG
- /* activate the v4l2 debug */
- if (gspca_debug & D_V4L2)
- gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL
- | V4L2_DEBUG_IOCTL_ARG;
- else
- gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
- | V4L2_DEBUG_IOCTL_ARG);
-#endif
return v4l2_fh_open(file);
}
@@ -1357,134 +1329,6 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int get_ctrl(struct gspca_dev *gspca_dev,
- int id)
-{
- const struct ctrl *ctrls;
- int i;
-
- for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrls++) {
- if (gspca_dev->ctrl_dis & (1 << i))
- continue;
- if (id == ctrls->qctrl.id)
- return i;
- }
- return -1;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *q_ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- struct gspca_ctrl *gspca_ctrl;
- int i, idx;
- u32 id;
-
- id = q_ctrl->id;
- if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
- id &= V4L2_CTRL_ID_MASK;
- id++;
- idx = -1;
- for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
- if (gspca_dev->ctrl_dis & (1 << i))
- continue;
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
- continue;
- if (idx >= 0
- && gspca_dev->sd_desc->ctrls[i].qctrl.id
- > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
- continue;
- idx = i;
- }
- } else {
- idx = get_ctrl(gspca_dev, id);
- }
- if (idx < 0)
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
- memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
- if (gspca_dev->cam.ctrls != NULL) {
- gspca_ctrl = &gspca_dev->cam.ctrls[idx];
- q_ctrl->default_value = gspca_ctrl->def;
- q_ctrl->minimum = gspca_ctrl->min;
- q_ctrl->maximum = gspca_ctrl->max;
- }
- if (gspca_dev->ctrl_inac & (1 << idx))
- q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- struct gspca_ctrl *gspca_ctrl;
- int idx;
-
- idx = get_ctrl(gspca_dev, ctrl->id);
- if (idx < 0)
- return -EINVAL;
- if (gspca_dev->ctrl_inac & (1 << idx))
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
- if (gspca_dev->cam.ctrls != NULL) {
- gspca_ctrl = &gspca_dev->cam.ctrls[idx];
- if (ctrl->value < gspca_ctrl->min
- || ctrl->value > gspca_ctrl->max)
- return -ERANGE;
- } else {
- gspca_ctrl = NULL;
- if (ctrl->value < ctrls->qctrl.minimum
- || ctrl->value > ctrls->qctrl.maximum)
- return -ERANGE;
- }
- PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
- gspca_dev->usb_err = 0;
- if (ctrls->set != NULL)
- return ctrls->set(gspca_dev, ctrl->value);
- if (gspca_ctrl != NULL) {
- gspca_ctrl->val = ctrl->value;
- if (ctrls->set_control != NULL
- && gspca_dev->streaming)
- ctrls->set_control(gspca_dev);
- }
- return gspca_dev->usb_err;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
- const struct ctrl *ctrls;
- int idx;
-
- idx = get_ctrl(gspca_dev, ctrl->id);
- if (idx < 0)
- return -EINVAL;
- ctrls = &gspca_dev->sd_desc->ctrls[idx];
-
- gspca_dev->usb_err = 0;
- if (ctrls->get != NULL)
- return ctrls->get(gspca_dev, &ctrl->value);
- if (gspca_dev->cam.ctrls != NULL)
- ctrl->value = gspca_dev->cam.ctrls[idx].val;
- return 0;
-}
-
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *qmenu)
-{
- struct gspca_dev *gspca_dev = video_drvdata(file);
-
- if (!gspca_dev->sd_desc->querymenu)
- return -ENOTTY;
- return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
-}
-
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
@@ -1621,14 +1465,8 @@ static int vidioc_streamon(struct file *file, void *priv,
if (ret < 0)
goto out;
}
-#ifdef GSPCA_DEBUG
- if (gspca_debug & D_STREAM) {
- PDEBUG_MODE("stream on OK",
- gspca_dev->pixfmt,
- gspca_dev->width,
- gspca_dev->height);
- }
-#endif
+ PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt,
+ gspca_dev->width, gspca_dev->height);
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
@@ -1879,8 +1717,7 @@ static int vidioc_dqbuf(struct file *file, void *priv,
if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
frame->v4l2_buf.bytesused)) {
- PDEBUG(D_ERR|D_STREAM,
- "dqbuf cp to user failed");
+ PERR("dqbuf cp to user failed");
ret = -EFAULT;
}
}
@@ -2092,8 +1929,7 @@ static ssize_t dev_read(struct file *file, char __user *data,
count = frame->v4l2_buf.bytesused;
ret = copy_to_user(data, frame->data, count);
if (ret != 0) {
- PDEBUG(D_ERR|D_STREAM,
- "read cp to user lack %d / %zd", ret, count);
+ PERR("read cp to user lack %d / %zd", ret, count);
ret = -EFAULT;
goto out;
}
@@ -2125,10 +1961,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_streamon = vidioc_streamon,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_querymenu = vidioc_querymenu,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
@@ -2157,22 +1989,6 @@ static const struct video_device gspca_template = {
.release = video_device_release_empty, /* We use v4l2_dev.release */
};
-/* initialize the controls */
-static void ctrls_init(struct gspca_dev *gspca_dev)
-{
- struct gspca_ctrl *ctrl;
- int i;
-
- for (i = 0, ctrl = gspca_dev->cam.ctrls;
- i < gspca_dev->sd_desc->nctrls;
- i++, ctrl++) {
- ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
- ctrl->val = ctrl->def;
- ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
- ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
- }
-}
-
/*
* probe and create a new gspca device
*
@@ -2249,8 +2065,6 @@ int gspca_dev_probe2(struct usb_interface *intf,
ret = sd_desc->config(gspca_dev, id);
if (ret < 0)
goto out;
- if (gspca_dev->cam.ctrls != NULL)
- ctrls_init(gspca_dev);
ret = sd_desc->init(gspca_dev);
if (ret < 0)
goto out;
@@ -2450,10 +2264,6 @@ static void __exit gspca_exit(void)
module_init(gspca_init);
module_exit(gspca_exit);
-#ifdef GSPCA_DEBUG
module_param_named(debug, gspca_debug, int, 0644);
MODULE_PARM_DESC(debug,
- "Debug (bit) 0x01:error 0x02:probe 0x04:config"
- " 0x08:stream 0x10:frame 0x20:packet"
- " 0x0100: v4l2");
-#endif
+ "1:probe 2:config 3:stream 4:frame 5:packet 6:usbi 7:usbo");
diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h
index 5559932bf2f5..ef8efeb80070 100644
--- a/drivers/media/usb/gspca/gspca.h
+++ b/drivers/media/usb/gspca/gspca.h
@@ -10,30 +10,26 @@
#include <media/v4l2-device.h>
#include <linux/mutex.h>
-/* compilation option */
-/*#define GSPCA_DEBUG 1*/
-#ifdef GSPCA_DEBUG
-/* GSPCA our debug messages */
+
+/* GSPCA debug codes */
+
+#define D_PROBE 1
+#define D_CONF 2
+#define D_STREAM 3
+#define D_FRAM 4
+#define D_PACK 5
+#define D_USBI 6
+#define D_USBO 7
+
extern int gspca_debug;
-#define PDEBUG(level, fmt, ...) \
-do { \
- if (gspca_debug & (level)) \
- pr_info(fmt, ##__VA_ARGS__); \
-} while (0)
-#define D_ERR 0x01
-#define D_PROBE 0x02
-#define D_CONF 0x04
-#define D_STREAM 0x08
-#define D_FRAM 0x10
-#define D_PACK 0x20
-#define D_USBI 0x00
-#define D_USBO 0x00
-#define D_V4L2 0x0100
-#else
-#define PDEBUG(level, fmt, ...) do {} while(0)
-#endif
+
+#define PDEBUG(level, fmt, ...) \
+ v4l2_dbg(level, gspca_debug, &gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__)
+
+#define PERR(fmt, ...) \
+ v4l2_err(&gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__)
#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
/* image transfers */
@@ -46,20 +42,11 @@ struct framerates {
int nrates;
};
-/* control definition */
-struct gspca_ctrl {
- s16 val; /* current value */
- s16 def; /* default value */
- s16 min, max; /* minimum and maximum values */
-};
-
/* device information - set at probe time */
struct cam {
const struct v4l2_pix_format *cam_mode; /* size nmodes */
const struct framerates *mode_framerates; /* must have size nmodes,
* just like cam_mode */
- struct gspca_ctrl *ctrls; /* control table - size nctrls */
- /* may be NULL */
u32 bulk_size; /* buffer size when image transfer by bulk */
u32 input_flags; /* value for ENUM_INPUT status flags */
u8 nmodes; /* size of cam_mode */
@@ -87,14 +74,14 @@ typedef int (*cam_get_jpg_op) (struct gspca_dev *,
struct v4l2_jpegcompression *);
typedef int (*cam_set_jpg_op) (struct gspca_dev *,
const struct v4l2_jpegcompression *);
-typedef int (*cam_reg_op) (struct gspca_dev *,
+typedef int (*cam_get_reg_op) (struct gspca_dev *,
struct v4l2_dbg_register *);
+typedef int (*cam_set_reg_op) (struct gspca_dev *,
+ const struct v4l2_dbg_register *);
typedef int (*cam_ident_op) (struct gspca_dev *,
struct v4l2_dbg_chip_ident *);
typedef void (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
-typedef int (*cam_qmnu_op) (struct gspca_dev *,
- struct v4l2_querymenu *);
typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
@@ -102,20 +89,10 @@ typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev,
u8 *data,
int len);
-struct ctrl {
- struct v4l2_queryctrl qctrl;
- int (*set)(struct gspca_dev *, __s32);
- int (*get)(struct gspca_dev *, __s32 *);
- cam_v_op set_control;
-};
-
/* subdriver description */
struct sd_desc {
/* information */
const char *name; /* sub-driver name */
-/* controls */
- const struct ctrl *ctrls; /* static control definition */
- int nctrls;
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
@@ -130,12 +107,11 @@ struct sd_desc {
cam_v_op dq_callback; /* called when a frame has been dequeued */
cam_get_jpg_op get_jcomp;
cam_set_jpg_op set_jcomp;
- cam_qmnu_op querymenu;
cam_streamparm_op get_streamparm;
cam_streamparm_op set_streamparm;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- cam_reg_op set_register;
- cam_reg_op get_register;
+ cam_set_reg_op set_register;
+ cam_get_reg_op get_register;
#endif
cam_ident_op get_chip_ident;
#if IS_ENABLED(CONFIG_INPUT)
@@ -174,8 +150,6 @@ struct gspca_dev {
struct cam cam; /* device information */
const struct sd_desc *sd_desc; /* subdriver description */
- unsigned ctrl_dis; /* disabled controls (bit map) */
- unsigned ctrl_inac; /* inactive controls (bit map) */
struct v4l2_ctrl_handler ctrl_handler;
/* autogain and exposure or gain control cluster, these are global as
diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c
index 1ba29fe7fada..8da3dde38385 100644
--- a/drivers/media/usb/gspca/jeilinj.c
+++ b/drivers/media/usb/gspca/jeilinj.c
@@ -266,7 +266,7 @@ static int jlj_start(struct gspca_dev *gspca_dev)
msleep(2);
setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
if (gspca_dev->usb_err < 0)
- PDEBUG(D_ERR, "Start streaming command failed");
+ PERR("Start streaming command failed");
return gspca_dev->usb_err;
}
diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c
index 61e25dbf2447..39c96bb4c985 100644
--- a/drivers/media/usb/gspca/konica.c
+++ b/drivers/media/usb/gspca/konica.c
@@ -277,7 +277,7 @@ static void sd_isoc_irq(struct urb *urb)
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR, "urb status: %d", urb->status);
+ PERR("urb status: %d", urb->status);
st = usb_submit_urb(urb, GFP_ATOMIC);
if (st < 0)
pr_err("resubmit urb error %d\n", st);
@@ -295,33 +295,30 @@ static void sd_isoc_irq(struct urb *urb)
sd->last_data_urb = NULL;
if (!data_urb || data_urb->start_frame != status_urb->start_frame) {
- PDEBUG(D_ERR|D_PACK, "lost sync on frames");
+ PERR("lost sync on frames");
goto resubmit;
}
if (data_urb->number_of_packets != status_urb->number_of_packets) {
- PDEBUG(D_ERR|D_PACK,
- "no packets does not match, data: %d, status: %d",
- data_urb->number_of_packets,
- status_urb->number_of_packets);
+ PERR("no packets does not match, data: %d, status: %d",
+ data_urb->number_of_packets,
+ status_urb->number_of_packets);
goto resubmit;
}
for (i = 0; i < status_urb->number_of_packets; i++) {
if (data_urb->iso_frame_desc[i].status ||
status_urb->iso_frame_desc[i].status) {
- PDEBUG(D_ERR|D_PACK,
- "pkt %d data-status %d, status-status %d", i,
- data_urb->iso_frame_desc[i].status,
- status_urb->iso_frame_desc[i].status);
+ PERR("pkt %d data-status %d, status-status %d", i,
+ data_urb->iso_frame_desc[i].status,
+ status_urb->iso_frame_desc[i].status);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
if (status_urb->iso_frame_desc[i].actual_length != 1) {
- PDEBUG(D_ERR|D_PACK,
- "bad status packet length %d",
- status_urb->iso_frame_desc[i].actual_length);
+ PERR("bad status packet length %d",
+ status_urb->iso_frame_desc[i].actual_length);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
@@ -366,12 +363,11 @@ resubmit:
if (data_urb) {
st = usb_submit_urb(data_urb, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK,
- "usb_submit_urb(data_urb) ret %d", st);
+ PERR("usb_submit_urb(data_urb) ret %d", st);
}
st = usb_submit_urb(status_urb, GFP_ATOMIC);
if (st < 0)
- pr_err("usb_submit_urb(status_urb) ret %d\n", st);
+ PERR("usb_submit_urb(status_urb) ret %d\n", st);
}
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/usb/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h
index 51af3ee3ab85..19eb1a64f9d6 100644
--- a/drivers/media/usb/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/usb/gspca/m5602/m5602_bridge.h
@@ -136,16 +136,33 @@ struct sd {
/* A pointer to the currently connected sensor */
const struct m5602_sensor *sensor;
- struct sd_desc *desc;
-
- /* Sensor private data */
- void *sensor_priv;
-
/* The current frame's id, used to detect frame boundaries */
u8 frame_id;
/* The current frame count */
u32 frame_count;
+
+ /* Camera rotation polling thread for "flipable" cams */
+ struct task_struct *rotation_thread;
+
+ struct { /* auto-white-bal + green/red/blue balance control cluster */
+ struct v4l2_ctrl *auto_white_bal;
+ struct v4l2_ctrl *red_bal;
+ struct v4l2_ctrl *blue_bal;
+ struct v4l2_ctrl *green_bal;
+ };
+ struct { /* autoexpo / expo cluster */
+ struct v4l2_ctrl *autoexpo;
+ struct v4l2_ctrl *expo;
+ };
+ struct { /* autogain / gain cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ };
+ struct { /* hflip/vflip cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
};
int m5602_read_bridge(
diff --git a/drivers/media/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c
index ed22638978ce..d926e62cb80b 100644
--- a/drivers/media/usb/gspca/m5602/m5602_core.c
+++ b/drivers/media/usb/gspca/m5602/m5602_core.c
@@ -41,6 +41,7 @@ MODULE_DEVICE_TABLE(usb, m5602_table);
int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -62,6 +63,7 @@ int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -98,6 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
u8 *i2c_data, const u8 len)
{
int err, i;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
if (!len || len > sd->sensor->i2c_regW)
return -EINVAL;
@@ -147,6 +150,7 @@ int m5602_write_sensor(struct sd *sd, const u8 address,
{
int err, i;
u8 *p;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -252,6 +256,16 @@ static int m5602_init(struct gspca_dev *gspca_dev)
return err;
}
+static int m5602_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (!sd->sensor->init_controls)
+ return 0;
+
+ return sd->sensor->init_controls(sd);
+}
+
static int m5602_start_transfer(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -336,11 +350,12 @@ static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
sd->sensor->stop(sd);
}
-/* sub-driver description, the ctrl and nctrl is filled at probe time */
-static struct sd_desc sd_desc = {
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.config = m5602_configure,
.init = m5602_init,
+ .init_controls = m5602_init_controls,
.start = m5602_start_transfer,
.stopN = m5602_stop_transfer,
.pkt_scan = m5602_urb_complete
@@ -355,7 +370,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
int err;
cam = &gspca_dev->cam;
- sd->desc = &sd_desc;
if (dump_bridge)
m5602_dump_bridge(sd);
@@ -368,7 +382,7 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
return 0;
fail:
- PDEBUG(D_ERR, "ALi m5602 webcam failed");
+ PERR("ALi m5602 webcam failed");
cam->cam_mode = NULL;
cam->nmodes = 0;
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
index 6268aa24ec5d..cfa4663f8934 100644
--- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
@@ -20,22 +20,8 @@
#include "m5602_mt9m111.h"
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl);
+static void mt9m111_dump_registers(struct sd *sd);
static struct v4l2_pix_format mt9m111_modes[] = {
{
@@ -50,118 +36,27 @@ static struct v4l2_pix_format mt9m111_modes[] = {
}
};
-static const struct ctrl mt9m111_ctrls[] = {
-#define VFLIP_IDX 0
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_vflip,
- .get = mt9m111_get_vflip
- },
-#define HFLIP_IDX 1
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_hflip,
- .get = mt9m111_get_hflip
- },
-#define GAIN_IDX 2
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0,
- .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
- .step = 1,
- .default_value = MT9M111_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_gain,
- .get = mt9m111_get_gain
- },
-#define AUTO_WHITE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = mt9m111_set_auto_white_balance,
- .get = mt9m111_get_auto_white_balance
- },
-#define GREEN_BALANCE_IDX 4
- {
- {
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_green_balance,
- .get = mt9m111_get_green_balance
- },
-#define BLUE_BALANCE_IDX 5
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_blue_balance,
- .get = mt9m111_get_blue_balance
- },
-#define RED_BALANCE_IDX 5
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_red_balance,
- .get = mt9m111_get_red_balance
- },
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+ .s_ctrl = mt9m111_s_ctrl,
};
-static void mt9m111_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = {
+ .ops = &mt9m111_ctrl_ops,
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .name = "Green Balance",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 0x7ff,
+ .step = 1,
+ .def = MT9M111_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+};
int mt9m111_probe(struct sd *sd)
{
u8 data[2] = {0x00, 0x00};
int i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == MT9M111_SENSOR) {
@@ -200,19 +95,8 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
- GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = mt9m111_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
- sd->desc->ctrls = mt9m111_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
- sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -220,7 +104,6 @@ sensor_found:
int mt9m111_init(struct sd *sd)
{
int i, err = 0;
- s32 *sensor_settings = sd->sensor_priv;
/* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -241,30 +124,45 @@ int mt9m111_init(struct sd *sd)
if (dump_sensor)
mt9m111_dump_registers(sd);
- err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = mt9m111_set_green_balance(&sd->gspca_dev,
- sensor_settings[GREEN_BALANCE_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = mt9m111_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
+int mt9m111_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 7);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 0);
+ sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 0x7ff, 1,
+ MT9M111_RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1,
+ MT9M111_BLUE_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0,
+ (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1,
+ MT9M111_DEFAULT_GAIN);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = mt9m111_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ return 0;
}
int mt9m111_start(struct sd *sd)
@@ -272,7 +170,7 @@ int mt9m111_start(struct sd *sd)
int i, err = 0;
u8 data[2];
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@@ -333,26 +231,11 @@ int mt9m111_start(struct sd *sd)
switch (width) {
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
- data[0] = MT9M111_RMB_OVER_SIZED;
- data[1] = MT9M111_RMB_ROW_SKIP_2X |
- MT9M111_RMB_COLUMN_SKIP_2X |
- (sensor_settings[VFLIP_IDX] << 0) |
- (sensor_settings[HFLIP_IDX] << 1);
-
- err = m5602_write_sensor(sd,
- MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
break;
case 320:
- PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
- data[0] = MT9M111_RMB_OVER_SIZED;
- data[1] = MT9M111_RMB_ROW_SKIP_4X |
- MT9M111_RMB_COLUMN_SKIP_4X |
- (sensor_settings[VFLIP_IDX] << 0) |
- (sensor_settings[HFLIP_IDX] << 1);
- err = m5602_write_sensor(sd,
- MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ PDEBUG(D_CONF, "Configuring camera for QVGA mode");
break;
}
return err;
@@ -361,105 +244,46 @@ int mt9m111_start(struct sd *sd)
void mt9m111_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- int err;
- u8 data[2] = {0x00, 0x00};
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-
- sensor_settings[VFLIP_IDX] = val;
-
- /* The mt9m111 is flipped by default */
- val = !val;
-
- /* Set the correct page map */
- err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
- if (err < 0)
- return err;
-
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
- if (err < 0)
- return err;
-
- data[1] = (data[1] & 0xfe) | val;
- err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
- data, 2);
- return err;
-}
-
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return 0;
}
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int hflip;
+ int vflip;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
- sensor_settings[HFLIP_IDX] = val;
+ PDEBUG(D_CONF, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val);
/* The mt9m111 is flipped by default */
- val = !val;
+ hflip = !sd->hflip->val;
+ vflip = !sd->vflip->val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
- if (err < 0)
- return err;
-
- data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
+ data[0] = MT9M111_RMB_OVER_SIZED;
+ if (gspca_dev->width == 640) {
+ data[1] = MT9M111_RMB_ROW_SKIP_2X |
+ MT9M111_RMB_COLUMN_SKIP_2X |
+ (hflip << 1) | vflip;
+ } else {
+ data[1] = MT9M111_RMB_ROW_SKIP_4X |
+ MT9M111_RMB_COLUMN_SKIP_4X |
+ (hflip << 1) | vflip;
+ }
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
return err;
}
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
-
- return 0;
-}
-
static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
int err;
u8 data[2];
@@ -467,33 +291,19 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
if (err < 0)
return err;
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
- PDEBUG(D_V4L2, "Set auto white balance %d", val);
+ PDEBUG(D_CONF, "Set auto white balance %d", val);
return err;
}
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val) {
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read auto white balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err, tmp;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[GAIN_IDX] = val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -518,7 +328,7 @@ static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
data[1] = (tmp & 0xff);
data[0] = (tmp & 0xff00) >> 8;
- PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
+ PDEBUG(D_CONF, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
data[1], data[0]);
err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
@@ -532,13 +342,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[GREEN_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set green balance %d", val);
+ PDEBUG(D_CONF, "Set green balance %d", val);
err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
data, 2);
if (err < 0)
@@ -548,66 +356,68 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
data, 2);
}
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GREEN_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read green balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[BLUE_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set blue balance %d", val);
+ PDEBUG(D_CONF, "Set blue balance %d", val);
return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
data, 2);
}
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue balance %d", *val);
- return 0;
-}
-
static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[RED_BALANCE_IDX] = val;
data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8;
- PDEBUG(D_V4L2, "Set red balance %d", val);
+ PDEBUG(D_CONF, "Set red balance %d", val);
return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
data, 2);
}
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int err;
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red balance %d", *val);
- return 0;
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val);
+ if (err)
+ return err;
+ err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = mt9m111_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = mt9m111_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
}
static void mt9m111_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
index 8c672b5c8c6a..07448d35e3cd 100644
--- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
@@ -110,6 +110,7 @@ extern bool dump_sensor;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
+int mt9m111_init_controls(struct sd *sd);
int mt9m111_start(struct sd *sd);
void mt9m111_disconnect(struct sd *sd);
@@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = {
.probe = mt9m111_probe,
.init = mt9m111_init,
+ .init_controls = mt9m111_init_controls,
.disconnect = mt9m111_disconnect,
.start = mt9m111_start,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
index 9a14835c128f..64b3b03a9141 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov7660.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
@@ -20,111 +20,8 @@
#include "m5602_ov7660.h"
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl ov7660_ctrls[] = {
-#define GAIN_IDX 1
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = OV7660_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov7660_set_gain,
- .get = ov7660_get_gain
- },
-#define BLUE_BALANCE_IDX 2
-#define RED_BALANCE_IDX 3
-#define AUTO_WHITE_BALANCE_IDX 4
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_white_balance,
- .get = ov7660_get_auto_white_balance
- },
-#define AUTO_GAIN_CTRL_IDX 5
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_gain,
- .get = ov7660_get_auto_gain
- },
-#define AUTO_EXPOSURE_IDX 6
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov7660_set_auto_exposure,
- .get = ov7660_get_auto_exposure
- },
-#define HFLIP_IDX 7
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov7660_set_hflip,
- .get = ov7660_get_hflip
- },
-#define VFLIP_IDX 8
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov7660_set_vflip,
- .get = ov7660_get_vflip
- },
-
-};
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov7660_dump_registers(struct sd *sd);
static struct v4l2_pix_format ov7660_modes[] = {
{
@@ -140,15 +37,15 @@ static struct v4l2_pix_format ov7660_modes[] = {
}
};
-static void ov7660_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov7660_ctrl_ops = {
+ .s_ctrl = ov7660_s_ctrl,
+};
int ov7660_probe(struct sd *sd)
{
int err = 0, i;
u8 prod_id = 0, ver_id = 0;
- s32 *sensor_settings;
-
if (force_sensor) {
if (force_sensor == OV7660_SENSOR) {
pr_info("Forcing an %s sensor\n", ov7660.name);
@@ -191,27 +88,15 @@ int ov7660_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = ov7660_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
- sd->desc->ctrls = ov7660_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
- sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
int ov7660_init(struct sd *sd)
{
- int i, err = 0;
- s32 *sensor_settings = sd->sensor_priv;
+ int i, err;
/* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
@@ -226,38 +111,47 @@ int ov7660_init(struct sd *sd)
err = m5602_write_sensor(sd,
init_ov7660[i][1], data, 1);
}
+ if (err < 0)
+ return err;
}
if (dump_sensor)
ov7660_dump_registers(sd);
- err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = ov7660_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+int ov7660_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
- err = ov7660_set_auto_gain(&sd->gspca_dev,
- sensor_settings[AUTO_GAIN_CTRL_IDX]);
- if (err < 0)
- return err;
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- err = ov7660_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- if (err < 0)
- return err;
- err = ov7660_set_hflip(&sd->gspca_dev,
- sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
- err = ov7660_set_vflip(&sd->gspca_dev,
- sensor_settings[VFLIP_IDX]);
+ sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0,
+ 255, 1, OV7660_DEFAULT_GAIN);
- return err;
+ sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
+
+ return 0;
}
int ov7660_start(struct sd *sd)
@@ -275,56 +169,29 @@ void ov7660_disconnect(struct sd *sd)
ov7660_stop(sd);
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
- return 0;
}
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
- u8 i2c_data;
+ u8 i2c_data = val;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Setting gain to %d", val);
-
- sensor_settings[GAIN_IDX] = val;
+ PDEBUG(D_CONF, "Setting gain to %d", val);
err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
return err;
}
-
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- return 0;
-}
-
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -335,26 +202,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err;
}
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
- PDEBUG(D_V4L2, "Read auto gain control %d", *val);
- return 0;
-}
-
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+ PDEBUG(D_CONF, "Set auto gain control to %d", val);
- sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -364,94 +219,69 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
}
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
- return 0;
-}
-
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure control to %d", val);
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0)
return err;
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
}
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return 0;
-}
-
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+ PDEBUG(D_CONF, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val);
- sensor_settings[HFLIP_IDX] = val;
-
- i2c_data = ((val & 0x01) << 5) |
- (sensor_settings[VFLIP_IDX] << 4);
+ i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
return err;
}
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
int err;
- u8 i2c_data;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- sensor_settings[VFLIP_IDX] = val;
- i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
- err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
- if (err < 0)
- return err;
-
- /* When vflip is toggled we need to readjust the bridge hsync/vsync */
- if (gspca_dev->streaming)
- err = ov7660_start(sd);
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err = ov7660_set_auto_gain(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov7660_set_gain(gspca_dev, sd->gain->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = ov7660_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
return err;
}
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
index 2b6a13b508f7..6fece1ce1232 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
@@ -90,6 +90,8 @@ extern bool dump_sensor;
int ov7660_probe(struct sd *sd);
int ov7660_init(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_init_controls(struct sd *sd);
int ov7660_start(struct sd *sd);
int ov7660_stop(struct sd *sd);
void ov7660_disconnect(struct sd *sd);
@@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = {
.i2c_regW = 1,
.probe = ov7660_probe,
.init = ov7660_init,
+ .init_controls = ov7660_init_controls,
.start = ov7660_start,
.stop = ov7660_stop,
.disconnect = ov7660_disconnect,
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
index 2114a8b90ec9..59bc62bfae26 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
@@ -20,26 +20,8 @@
#include "m5602_ov9650.h"
-static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov9650_dump_registers(struct sd *sd);
/* Vertically and horizontally flips the image if matched, needed for machines
where the sensor is mounted upside down */
@@ -113,140 +95,6 @@ static
{}
};
-static const struct ctrl ov9650_ctrls[] = {
-#define EXPOSURE_IDX 0
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x1ff,
- .step = 0x4,
- .default_value = EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_exposure,
- .get = ov9650_get_exposure
- },
-#define GAIN_IDX 1
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x3ff,
- .step = 0x1,
- .default_value = GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_gain,
- .get = ov9650_get_gain
- },
-#define RED_BALANCE_IDX 2
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_red_balance,
- .get = ov9650_get_red_balance
- },
-#define BLUE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_blue_balance,
- .get = ov9650_get_blue_balance
- },
-#define HFLIP_IDX 4
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_hflip,
- .get = ov9650_get_hflip
- },
-#define VFLIP_IDX 5
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_vflip,
- .get = ov9650_get_vflip
- },
-#define AUTO_WHITE_BALANCE_IDX 6
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_white_balance,
- .get = ov9650_get_auto_white_balance
- },
-#define AUTO_GAIN_CTRL_IDX 7
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_gain,
- .get = ov9650_get_auto_gain
- },
-#define AUTO_EXPOSURE_IDX 8
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = ov9650_set_auto_exposure,
- .get = ov9650_get_auto_exposure
- }
-
-};
-
static struct v4l2_pix_format ov9650_modes[] = {
{
176,
@@ -291,13 +139,15 @@ static struct v4l2_pix_format ov9650_modes[] = {
}
};
-static void ov9650_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov9650_ctrl_ops = {
+ .s_ctrl = ov9650_s_ctrl,
+};
int ov9650_probe(struct sd *sd)
{
int err = 0;
u8 prod_id = 0, ver_id = 0, i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == OV9650_SENSOR) {
@@ -338,19 +188,9 @@ int ov9650_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = ov9650_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
- sd->desc->ctrls = ov9650_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
- for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
- sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -358,7 +198,6 @@ int ov9650_init(struct sd *sd)
{
int i, err = 0;
u8 data;
- s32 *sensor_settings = sd->sensor_priv;
if (dump_sensor)
ov9650_dump_registers(sd);
@@ -372,46 +211,52 @@ int ov9650_init(struct sd *sd)
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
}
- err = ov9650_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = ov9650_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- if (err < 0)
- return err;
+int ov9650_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 9);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 255, 1,
+ RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+ BLUE_GAIN_DEFAULT);
+
+ sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
+ sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, 0x1ff, 4, EXPOSURE_DEFAULT);
+
+ sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0,
+ 0x3ff, 1, GAIN_DEFAULT);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = ov9650_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- err = ov9650_set_auto_gain(&sd->gspca_dev,
- sensor_settings[AUTO_GAIN_CTRL_IDX]);
- return err;
+ return 0;
}
int ov9650_start(struct sd *sd)
@@ -419,17 +264,17 @@ int ov9650_start(struct sd *sd)
u8 data;
int i, err = 0;
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
int hor_offs = OV9650_LEFT_OFFSET;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if ((!dmi_check_system(ov9650_flip_dmi_table) &&
- sensor_settings[VFLIP_IDX]) ||
+ sd->vflip->val) ||
(dmi_check_system(ov9650_flip_dmi_table) &&
- !sensor_settings[VFLIP_IDX]))
+ !sd->vflip->val))
ver_offs--;
if (width <= 320)
@@ -508,7 +353,7 @@ int ov9650_start(struct sd *sd)
switch (width) {
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -516,7 +361,7 @@ int ov9650_start(struct sd *sd)
break;
case 352:
- PDEBUG(D_V4L2, "Configuring camera for CIF mode");
+ PDEBUG(D_CONF, "Configuring camera for CIF mode");
data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -524,7 +369,7 @@ int ov9650_start(struct sd *sd)
break;
case 320:
- PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+ PDEBUG(D_CONF, "Configuring camera for QVGA mode");
data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -532,7 +377,7 @@ int ov9650_start(struct sd *sd)
break;
case 176:
- PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
+ PDEBUG(D_CONF, "Configuring camera for QCIF mode");
data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
OV9650_RAW_RGB_SELECT;
@@ -553,29 +398,16 @@ void ov9650_disconnect(struct sd *sd)
ov9650_stop(sd);
sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read exposure %d", *val);
- return 0;
}
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- PDEBUG(D_V4L2, "Set exposure to %d", val);
+ PDEBUG(D_CONF, "Set exposure to %d", val);
- sensor_settings[EXPOSURE_IDX] = val;
/* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f;
err = m5602_write_sensor(sd, OV9650_AECHM,
@@ -596,26 +428,13 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
- return 0;
-}
-
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Setting gain to %d", val);
-
- sensor_settings[GAIN_IDX] = val;
+ PDEBUG(D_CONF, "Setting gain to %d", val);
/* The 2 MSB */
/* Read the OV9650_VREF register first to avoid
@@ -637,117 +456,46 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red gain %d", *val);
- return 0;
-}
-
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set red gain to %d", val);
-
- sensor_settings[RED_BALANCE_IDX] = val;
+ PDEBUG(D_CONF, "Set red gain to %d", val);
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
return err;
}
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
- return 0;
-}
-
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set blue gain to %d", val);
- sensor_settings[BLUE_BALANCE_IDX] = val;
+ PDEBUG(D_CONF, "Set blue gain to %d", val);
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
return err;
}
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return 0;
-}
-
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
- sensor_settings[HFLIP_IDX] = val;
-
- if (!dmi_check_system(ov9650_flip_dmi_table))
- i2c_data = ((val & 0x01) << 5) |
- (sensor_settings[VFLIP_IDX] << 4);
- else
- i2c_data = ((val & 0x01) << 5) |
- (!sensor_settings[VFLIP_IDX] << 4);
-
- err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-
- return err;
-}
-
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- int err;
- u8 i2c_data;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- sensor_settings[VFLIP_IDX] = val;
+ PDEBUG(D_CONF, "Set hvflip to %d %d", hflip, vflip);
if (dmi_check_system(ov9650_flip_dmi_table))
- val = !val;
+ vflip = !vflip;
- i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
+ i2c_data = (hflip << 5) | (vflip << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
return err;
@@ -759,57 +507,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
- return 0;
-}
-
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure control to %d", val);
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- return 0;
-}
-
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -820,26 +545,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err;
}
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
- PDEBUG(D_V4L2, "Read auto gain control %d", *val);
- return 0;
-}
-
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+ PDEBUG(D_CONF, "Set auto gain control to %d", val);
- sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
return err;
@@ -849,6 +562,48 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = ov9650_set_auto_exposure(gspca_dev, ctrl->val);
+ if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+ return err;
+ err = ov9650_set_exposure(gspca_dev, sd->expo->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err = ov9650_set_auto_gain(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = ov9650_set_gain(gspca_dev, sd->gain->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = ov9650_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
static void ov9650_dump_registers(struct sd *sd)
{
int address;
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.h b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
index f7aa5bf68983..f9f5870da60f 100644
--- a/drivers/media/usb/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
@@ -139,6 +139,7 @@ extern bool dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
+int ov9650_init_controls(struct sd *sd);
int ov9650_start(struct sd *sd);
int ov9650_stop(struct sd *sd);
void ov9650_disconnect(struct sd *sd);
@@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = {
.i2c_regW = 1,
.probe = ov9650_probe,
.init = ov9650_init,
+ .init_controls = ov9650_init_controls,
.start = ov9650_start,
.stop = ov9650_stop,
.disconnect = ov9650_disconnect,
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c
index b8771698cbcb..4bf5c43424b7 100644
--- a/drivers/media/usb/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c
@@ -20,28 +20,8 @@
#include "m5602_po1030.h"
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 val);
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val);
-static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 val);
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 *val);
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
+static void po1030_dump_registers(struct sd *sd);
static struct v4l2_pix_format po1030_modes[] = {
{
@@ -56,146 +36,26 @@ static struct v4l2_pix_format po1030_modes[] = {
}
};
-static const struct ctrl po1030_ctrls[] = {
-#define GAIN_IDX 0
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x4f,
- .step = 0x1,
- .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_gain,
- .get = po1030_get_gain
- },
-#define EXPOSURE_IDX 1
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x02ff,
- .step = 0x1,
- .default_value = PO1030_EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_exposure,
- .get = po1030_get_exposure
- },
-#define RED_BALANCE_IDX 2
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_red_balance,
- .get = po1030_get_red_balance
- },
-#define BLUE_BALANCE_IDX 3
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_blue_balance,
- .get = po1030_get_blue_balance
- },
-#define HFLIP_IDX 4
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_hflip,
- .get = po1030_get_hflip
- },
-#define VFLIP_IDX 5
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_vflip,
- .get = po1030_get_vflip
- },
-#define AUTO_WHITE_BALANCE_IDX 6
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_auto_white_balance,
- .get = po1030_get_auto_white_balance
- },
-#define AUTO_EXPOSURE_IDX 7
- {
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_auto_exposure,
- .get = po1030_get_auto_exposure
- },
-#define GREEN_BALANCE_IDX 8
- {
- {
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_green_balance,
- .get = po1030_get_green_balance
- },
+static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
+ .s_ctrl = po1030_s_ctrl,
};
-static void po1030_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
+ .ops = &po1030_ctrl_ops,
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .name = "Green Balance",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .max = 255,
+ .step = 1,
+ .def = PO1030_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+};
int po1030_probe(struct sd *sd)
{
u8 dev_id_h = 0, i;
- s32 *sensor_settings;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == PO1030_SENSOR) {
@@ -229,26 +89,14 @@ int po1030_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = po1030_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
- sd->desc->ctrls = po1030_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
- sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
int po1030_init(struct sd *sd)
{
- s32 *sensor_settings = sd->sensor_priv;
int i, err = 0;
/* Init the sensor */
@@ -279,46 +127,50 @@ int po1030_init(struct sd *sd)
if (dump_sensor)
po1030_dump_registers(sd);
- err = po1030_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_red_balance(&sd->gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
- if (err < 0)
- return err;
-
- err = po1030_set_blue_balance(&sd->gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ return 0;
+}
- err = po1030_set_green_balance(&sd->gspca_dev,
- sensor_settings[GREEN_BALANCE_IDX]);
- if (err < 0)
- return err;
+int po1030_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 9);
+
+ sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 0);
+ sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 255, 1,
+ PO1030_RED_GAIN_DEFAULT);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+ PO1030_BLUE_GAIN_DEFAULT);
+
+ sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
+ sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
+
+ sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
+ 0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
- err = po1030_set_auto_white_balance(&sd->gspca_dev,
- sensor_settings[AUTO_WHITE_BALANCE_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+ v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+ v4l2_ctrl_cluster(2, &sd->hflip);
- err = po1030_set_auto_exposure(&sd->gspca_dev,
- sensor_settings[AUTO_EXPOSURE_IDX]);
- return err;
+ return 0;
}
int po1030_start(struct sd *sd)
@@ -448,28 +300,16 @@ int po1030_start(struct sd *sd)
return err;
}
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Exposure read as %d", *val);
- return 0;
-}
-
static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[EXPOSURE_IDX] = val;
- PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
+ PDEBUG(D_CONF, "Set exposure to %d", val & 0xffff);
i2c_data = ((val & 0xff00) >> 8);
- PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
+ PDEBUG(D_CONF, "Set exposure to high byte to 0x%x",
i2c_data);
err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
@@ -478,7 +318,7 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
i2c_data = (val & 0xff);
- PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
+ PDEBUG(D_CONF, "Set exposure to low byte to 0x%x",
i2c_data);
err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
&i2c_data, 1);
@@ -486,91 +326,32 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read global gain %d", *val);
- return 0;
-}
-
static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[GAIN_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set global gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read hflip %d", *val);
-
- return 0;
-}
-
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- u8 i2c_data;
- int err;
-
- sensor_settings[HFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set hflip %d", val);
- err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
- if (err < 0)
- return err;
-
- i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
-
- err = m5602_write_sensor(sd, PO1030_CONTROL2,
- &i2c_data, 1);
-
- return err;
-}
-
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vflip %d", *val);
-
- return 0;
-}
-
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[VFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set vflip %d", val);
+ PDEBUG(D_CONF, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0)
return err;
- i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
+ i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
+ (sd->vflip->val << 6);
err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1);
@@ -578,81 +359,41 @@ static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[RED_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read red gain %d", *val);
- return 0;
-}
-
static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[RED_BALANCE_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set red gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_RED_GAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
- return 0;
-}
-
static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[BLUE_BALANCE_IDX] = val;
-
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set blue gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
&i2c_data, 1);
return err;
}
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GREEN_BALANCE_IDX];
- PDEBUG(D_V4L2, "Read green gain %d", *val);
-
- return 0;
-}
-
static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[GREEN_BALANCE_IDX] = val;
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
+ PDEBUG(D_CONF, "Set green gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
&i2c_data, 1);
@@ -663,63 +404,36 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
&i2c_data, 1);
}
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
- PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
-
- return 0;
-}
-
static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
-
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0)
return err;
- PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ PDEBUG(D_CONF, "Set auto white balance to %d", val);
i2c_data = (i2c_data & 0xfe) | (val & 0x01);
err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
return err;
}
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
- __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTO_EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Auto exposure is %d", *val);
- return 0;
-}
-
static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0)
return err;
- PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+ PDEBUG(D_CONF, "Set auto exposure to %d", val);
+ val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
}
@@ -727,7 +441,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
void po1030_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
+}
+
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
+ if (err || ctrl->val)
+ return err;
+ err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
+ if (err)
+ return err;
+ err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
+ if (err)
+ return err;
+ err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
+ if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+ return err;
+ err = po1030_set_exposure(gspca_dev, sd->expo->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = po1030_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = po1030_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
}
static void po1030_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.h b/drivers/media/usb/gspca/m5602/m5602_po1030.h
index 81a2bcb88fe3..a6ab76149bd0 100644
--- a/drivers/media/usb/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.h
@@ -151,6 +151,7 @@ extern bool dump_sensor;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
+int po1030_init_controls(struct sd *sd);
int po1030_start(struct sd *sd);
void po1030_disconnect(struct sd *sd);
@@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = {
.probe = po1030_probe,
.init = po1030_init,
+ .init_controls = po1030_init_controls,
.start = po1030_start,
.disconnect = po1030_disconnect,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
index c8e1572eb502..7d12599458e2 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
@@ -20,18 +20,12 @@
#include "m5602_s5k4aa.h"
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
+static void s5k4aa_dump_registers(struct sd *sd);
+
+static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
+ .s_ctrl = s5k4aa_s_ctrl,
+};
static
const
@@ -147,104 +141,12 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
}
};
-static const struct ctrl s5k4aa_ctrls[] = {
-#define VFLIP_IDX 0
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_vflip,
- .get = s5k4aa_get_vflip
- },
-#define HFLIP_IDX 1
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_hflip,
- .get = s5k4aa_get_hflip
- },
-#define GAIN_IDX 2
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = S5K4AA_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_gain,
- .get = s5k4aa_get_gain
- },
-#define EXPOSURE_IDX 3
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 13,
- .maximum = 0xfff,
- .step = 1,
- .default_value = 0x100,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_exposure,
- .get = s5k4aa_get_exposure
- },
-#define NOISE_SUPP_IDX 4
- {
- {
- .id = V4L2_CID_PRIVATE_BASE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Noise suppression (smoothing)",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- .set = s5k4aa_set_noise,
- .get = s5k4aa_get_noise
- },
-#define BRIGHTNESS_IDX 5
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0x1f,
- .step = 1,
- .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
- },
- .set = s5k4aa_set_brightness,
- .get = s5k4aa_get_brightness
- },
-
-};
-
-static void s5k4aa_dump_registers(struct sd *sd);
-
int s5k4aa_probe(struct sd *sd)
{
u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int i, err = 0;
- s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == S5K4AA_SENSOR) {
@@ -303,19 +205,8 @@ int s5k4aa_probe(struct sd *sd)
pr_info("Detected a s5k4aa sensor\n");
sensor_found:
- sensor_settings = kmalloc(
- ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
- sd->desc->ctrls = s5k4aa_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
-
- for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
- sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
return 0;
}
@@ -325,11 +216,11 @@ int s5k4aa_start(struct sd *sd)
int i, err = 0;
u8 data[2];
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
case 1280:
- PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
+ PDEBUG(D_CONF, "Configuring camera for SXGA mode");
for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
switch (SXGA_s5k4aa[i][0]) {
@@ -359,13 +250,10 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL;
}
}
- err = s5k4aa_set_noise(&sd->gspca_dev, 0);
- if (err < 0)
- return err;
break;
case 640:
- PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+ PDEBUG(D_CONF, "Configuring camera for VGA mode");
for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
switch (VGA_s5k4aa[i][0]) {
@@ -395,37 +283,12 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL;
}
}
- err = s5k4aa_set_noise(&sd->gspca_dev, 1);
- if (err < 0)
- return err;
break;
}
if (err < 0)
return err;
- err = s5k4aa_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
- if (err < 0)
- return err;
-
- err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
- if (err < 0)
- return err;
-
- return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ return 0;
}
int s5k4aa_init(struct sd *sd)
@@ -466,13 +329,36 @@ int s5k4aa_init(struct sd *sd)
return err;
}
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int s5k4aa_init_controls(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- *val = sensor_settings[EXPOSURE_IDX];
- PDEBUG(D_V4L2, "Read exposure %d", *val);
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
+ 13, 0xfff, 1, 0x100);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
+ 0, 127, 1, S5K4AA_DEFAULT_GAIN);
+
+ v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
+ 0, 1, 1, 1);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
}
@@ -480,12 +366,10 @@ static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[EXPOSURE_IDX] = val;
- PDEBUG(D_V4L2, "Set exposure to %d", val);
+ PDEBUG(D_CONF, "Set exposure to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -499,27 +383,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
- sensor_settings[VFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+ PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -528,93 +400,48 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
if (err < 0)
return err;
- if (dmi_check_system(s5k4aa_vflip_dmi_table))
- val = !val;
+ if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
+ hflip = !hflip;
+ vflip = !vflip;
+ }
- data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+ data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
return err;
- if (val)
+ if (hflip)
data &= 0xfe;
else
data |= 0x01;
- err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- return err;
-}
-
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return 0;
-}
-
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- u8 data = S5K4AA_PAGE_MAP_2;
- int err;
-
- sensor_settings[HFLIP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
- err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- if (err < 0)
- return err;
-
- err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
- if (err < 0)
- return err;
-
- if (dmi_check_system(s5k4aa_vflip_dmi_table))
- val = !val;
-
- data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
- err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
return err;
- err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
return err;
- if (val)
+ if (vflip)
data &= 0xfe;
else
data |= 0x01;
- err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- return err;
-}
-
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ if (err < 0)
+ return err;
- *val = sensor_settings[GAIN_IDX];
- PDEBUG(D_V4L2, "Read gain %d", *val);
return 0;
}
static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[GAIN_IDX] = val;
-
- PDEBUG(D_V4L2, "Set gain to %d", val);
+ PDEBUG(D_CONF, "Set gain to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -625,26 +452,13 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BRIGHTNESS_IDX];
- PDEBUG(D_V4L2, "Read brightness %d", *val);
- return 0;
-}
-
static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[BRIGHTNESS_IDX] = val;
-
- PDEBUG(D_V4L2, "Set brightness to %d", val);
+ PDEBUG(D_CONF, "Set brightness to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -653,26 +467,13 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
}
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[NOISE_SUPP_IDX];
- PDEBUG(D_V4L2, "Read noise %d", *val);
- return 0;
-}
-
static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- sensor_settings[NOISE_SUPP_IDX] = val;
-
- PDEBUG(D_V4L2, "Set noise to %d", val);
+ PDEBUG(D_CONF, "Set noise to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
@@ -681,10 +482,41 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
}
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ int err;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = s5k4aa_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ err = s5k4aa_set_noise(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = s5k4aa_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err;
+}
+
void s5k4aa_disconnect(struct sd *sd)
{
sd->sensor = NULL;
- kfree(sd->sensor_priv);
}
static void s5k4aa_dump_registers(struct sd *sd)
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
index 8e0035e731c7..9953e9766954 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
@@ -69,6 +69,7 @@ extern bool dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
+int s5k4aa_init_controls(struct sd *sd);
int s5k4aa_start(struct sd *sd);
void s5k4aa_disconnect(struct sd *sd);
@@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = {
.probe = s5k4aa_probe,
.init = s5k4aa_init,
+ .init_controls = s5k4aa_init_controls,
.start = s5k4aa_start,
.disconnect = s5k4aa_disconnect,
};
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
index 1de743a02b02..7cbc3a00bda8 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
@@ -21,16 +21,11 @@
#include <linux/kthread.h>
#include "m5602_s5k83a.h"
-static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
+ .s_ctrl = s5k83a_s_ctrl,
+};
static struct v4l2_pix_format s5k83a_modes[] = {
{
@@ -46,83 +41,6 @@ static struct v4l2_pix_format s5k83a_modes[] = {
}
};
-static const struct ctrl s5k83a_ctrls[] = {
-#define GAIN_IDX 0
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_gain,
- .get = s5k83a_get_gain
-
- },
-#define BRIGHTNESS_IDX 1
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_BRIGHTNESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_brightness,
- .get = s5k83a_get_brightness,
- },
-#define EXPOSURE_IDX 2
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = S5K83A_MAXIMUM_EXPOSURE,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_exposure,
- .get = s5k83a_get_exposure
- },
-#define HFLIP_IDX 3
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_hflip,
- .get = s5k83a_get_hflip
- },
-#define VFLIP_IDX 4
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_vflip,
- .get = s5k83a_get_vflip
- }
-};
-
static void s5k83a_dump_registers(struct sd *sd);
static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
static int s5k83a_set_led_indication(struct sd *sd, u8 val);
@@ -131,9 +49,9 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
int s5k83a_probe(struct sd *sd)
{
- struct s5k83a_priv *sens_priv;
u8 prod_id = 0, ver_id = 0;
int i, err = 0;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
if (force_sensor) {
if (force_sensor == S5K83A_SENSOR) {
@@ -173,38 +91,18 @@ int s5k83a_probe(struct sd *sd)
pr_info("Detected a s5k83a sensor\n");
sensor_found:
- sens_priv = kmalloc(
- sizeof(struct s5k83a_priv), GFP_KERNEL);
- if (!sens_priv)
- return -ENOMEM;
-
- sens_priv->settings =
- kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
- if (!sens_priv->settings) {
- kfree(sens_priv);
- return -ENOMEM;
- }
-
sd->gspca_dev.cam.cam_mode = s5k83a_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
- sd->desc->ctrls = s5k83a_ctrls;
- sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
/* null the pointer! thread is't running now */
- sens_priv->rotation_thread = NULL;
-
- for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
- sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+ sd->rotation_thread = NULL;
- sd->sensor_priv = sens_priv;
return 0;
}
int s5k83a_init(struct sd *sd)
{
int i, err = 0;
- s32 *sensor_settings =
- ((struct s5k83a_priv *) sd->sensor_priv)->settings;
for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
u8 data[2] = {0x00, 0x00};
@@ -237,33 +135,44 @@ int s5k83a_init(struct sd *sd)
if (dump_sensor)
s5k83a_dump_registers(sd);
- err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- if (err < 0)
- return err;
+ return err;
+}
- err = s5k83a_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
- if (err < 0)
- return err;
+int s5k83a_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
- err = s5k83a_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
+ sd->gspca_dev.vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
- err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
- if (err < 0)
- return err;
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
- err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, S5K83A_MAXIMUM_EXPOSURE, 1,
+ S5K83A_DEFAULT_EXPOSURE);
- return err;
+ v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
+ 0, 255, 1, S5K83A_DEFAULT_GAIN);
+
+ sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->hflip);
+
+ return 0;
}
static int rotation_thread_function(void *data)
{
struct sd *sd = (struct sd *) data;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
u8 reg, previous_rotation = 0;
__s32 vflip, hflip;
@@ -277,8 +186,8 @@ static int rotation_thread_function(void *data)
previous_rotation = reg;
pr_info("Camera was flipped\n");
- s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
- s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+ hflip = sd->hflip->val;
+ vflip = sd->vflip->val;
if (reg) {
vflip = !vflip;
@@ -294,26 +203,25 @@ static int rotation_thread_function(void *data)
/* return to "front" flip */
if (previous_rotation) {
- s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
- s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+ hflip = sd->hflip->val;
+ vflip = sd->vflip->val;
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
}
- sens_priv->rotation_thread = NULL;
+ sd->rotation_thread = NULL;
return 0;
}
int s5k83a_start(struct sd *sd)
{
int i, err = 0;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
/* Create another thread, polling the GPIO ports of the camera to check
if it got rotated. This is how the windows driver does it so we have
to assume that there is no better way of accomplishing this */
- sens_priv->rotation_thread = kthread_create(rotation_thread_function,
- sd, "rotation thread");
- wake_up_process(sens_priv->rotation_thread);
+ sd->rotation_thread = kthread_create(rotation_thread_function,
+ sd, "rotation thread");
+ wake_up_process(sd->rotation_thread);
/* Preinit the sensor */
for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
@@ -333,32 +241,17 @@ int s5k83a_start(struct sd *sd)
int s5k83a_stop(struct sd *sd)
{
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- if (sens_priv->rotation_thread)
- kthread_stop(sens_priv->rotation_thread);
+ if (sd->rotation_thread)
+ kthread_stop(sd->rotation_thread);
return s5k83a_set_led_indication(sd, 0);
}
void s5k83a_disconnect(struct sd *sd)
{
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
s5k83a_stop(sd);
sd->sensor = NULL;
- kfree(sens_priv->settings);
- kfree(sens_priv);
-}
-
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[GAIN_IDX];
- return 0;
}
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -366,9 +259,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[GAIN_IDX] = val;
data[0] = 0x00;
data[1] = 0x20;
@@ -391,60 +281,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[BRIGHTNESS_IDX];
- return 0;
-}
-
static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[1];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
- sens_priv->settings[BRIGHTNESS_IDX] = val;
data[0] = val;
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
return err;
}
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[EXPOSURE_IDX];
- return 0;
-}
-
static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
- sens_priv->settings[EXPOSURE_IDX] = val;
data[0] = 0;
data[1] = val;
err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
return err;
}
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[VFLIP_IDX];
- return 0;
-}
-
static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
__s32 vflip, __s32 hflip)
{
@@ -476,60 +335,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
return err;
}
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
{
int err;
u8 reg;
- __s32 hflip;
struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[VFLIP_IDX] = val;
-
- s5k83a_get_hflip(gspca_dev, &hflip);
+ int hflip = sd->hflip->val;
+ int vflip = sd->vflip->val;
err = s5k83a_get_rotation(sd, &reg);
if (err < 0)
return err;
if (reg) {
- val = !val;
hflip = !hflip;
+ vflip = !vflip;
}
- err = s5k83a_set_flip_real(gspca_dev, val, hflip);
+ err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
return err;
}
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- *val = sens_priv->settings[HFLIP_IDX];
- return 0;
-}
-
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
int err;
- u8 reg;
- __s32 vflip;
- struct sd *sd = (struct sd *) gspca_dev;
- struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
- sens_priv->settings[HFLIP_IDX] = val;
- s5k83a_get_vflip(gspca_dev, &vflip);
-
- err = s5k83a_get_rotation(sd, &reg);
- if (err < 0)
- return err;
- if (reg) {
- val = !val;
- vflip = !vflip;
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = s5k83a_set_brightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = s5k83a_set_exposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = s5k83a_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ err = s5k83a_set_hvflip(gspca_dev);
+ break;
+ default:
+ return -EINVAL;
}
- err = s5k83a_set_flip_real(gspca_dev, vflip, val);
return err;
}
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
index 79952247b534..d61b918228df 100644
--- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
@@ -45,6 +45,7 @@ extern bool dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
+int s5k83a_init_controls(struct sd *sd);
int s5k83a_start(struct sd *sd);
int s5k83a_stop(struct sd *sd);
void s5k83a_disconnect(struct sd *sd);
@@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = {
.name = "S5K83A",
.probe = s5k83a_probe,
.init = s5k83a_init,
+ .init_controls = s5k83a_init_controls,
.start = s5k83a_start,
.stop = s5k83a_stop,
.disconnect = s5k83a_disconnect,
@@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = {
.i2c_regW = 2,
};
-struct s5k83a_priv {
- /* We use another thread periodically
- probing the orientation of the camera */
- struct task_struct *rotation_thread;
- s32 *settings;
-};
-
static const unsigned char preinit_s5k83a[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
diff --git a/drivers/media/usb/gspca/m5602/m5602_sensor.h b/drivers/media/usb/gspca/m5602/m5602_sensor.h
index edff4f1f586f..48341b4d607b 100644
--- a/drivers/media/usb/gspca/m5602/m5602_sensor.h
+++ b/drivers/media/usb/gspca/m5602/m5602_sensor.h
@@ -57,6 +57,9 @@ struct m5602_sensor {
/* Performs a initialization sequence */
int (*init)(struct sd *sd);
+ /* Controls initialization, maybe NULL */
+ int (*init_controls)(struct sd *sd);
+
/* Executed when the camera starts to send data */
int (*start)(struct sd *sd);
diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c
index 8f4714df5990..68bb2f359666 100644
--- a/drivers/media/usb/gspca/mr97310a.c
+++ b/drivers/media/usb/gspca/mr97310a.c
@@ -289,7 +289,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev)
return err_code;
}
if (status != 0x0a)
- PDEBUG(D_ERR, "status is %02x", status);
+ PERR("status is %02x", status);
tries = 0;
while (tries < 4) {
@@ -330,7 +330,7 @@ static void stream_stop(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0] = 0x01;
gspca_dev->usb_buf[1] = 0x00;
if (mr_write(gspca_dev, 2) < 0)
- PDEBUG(D_ERR, "Stream Stop failed");
+ PERR("Stream Stop failed");
}
static void lcd_stop(struct gspca_dev *gspca_dev)
@@ -338,7 +338,7 @@ static void lcd_stop(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0] = 0x19;
gspca_dev->usb_buf[1] = 0x54;
if (mr_write(gspca_dev, 2) < 0)
- PDEBUG(D_ERR, "LCD Stop failed");
+ PERR("LCD Stop failed");
}
static int isoc_enable(struct gspca_dev *gspca_dev)
@@ -1026,7 +1026,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n;
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index 9ad19a7ef81b..a3958ee86816 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -2034,6 +2034,7 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
/* Write a OV519 register */
static void reg_w(struct sd *sd, u16 index, u16 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret, req = 0;
if (sd->gspca_dev.usb_err < 0)
@@ -2071,7 +2072,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value)
sd->gspca_dev.usb_buf, 1, 500);
leave:
if (ret < 0) {
- pr_err("reg_w %02x failed %d\n", index, ret);
+ PERR("reg_w %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
return;
}
@@ -2081,6 +2082,7 @@ leave:
/* returns: negative is error, pos or zero is data */
static int reg_r(struct sd *sd, u16 index)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
int req;
@@ -2110,7 +2112,7 @@ static int reg_r(struct sd *sd, u16 index)
PDEBUG(D_USBI, "GET %02x 0000 %04x %02x",
req, index, ret);
} else {
- pr_err("reg_r %02x failed %d\n", index, ret);
+ PERR("reg_r %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2121,6 +2123,7 @@ static int reg_r(struct sd *sd, u16 index)
static int reg_r8(struct sd *sd,
u16 index)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2135,7 +2138,7 @@ static int reg_r8(struct sd *sd,
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
} else {
- pr_err("reg_r8 %02x failed %d\n", index, ret);
+ PERR("reg_r8 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2174,6 +2177,7 @@ static void reg_w_mask(struct sd *sd,
*/
static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2188,13 +2192,14 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
0, index,
sd->gspca_dev.usb_buf, n, 500);
if (ret < 0) {
- pr_err("reg_w32 %02x failed %d\n", index, ret);
+ PERR("reg_w32 %02x failed %d\n", index, ret);
sd->gspca_dev.usb_err = ret;
}
}
static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, retries;
PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value);
@@ -2228,6 +2233,7 @@ static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
static int ov511_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, value, retries;
/* Two byte write cycle */
@@ -2300,6 +2306,8 @@ static void ov518_i2c_w(struct sd *sd,
u8 reg,
u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value);
/* Select camera register */
@@ -2325,6 +2333,7 @@ static void ov518_i2c_w(struct sd *sd,
*/
static int ov518_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int value;
/* Select camera register */
@@ -2345,6 +2354,7 @@ static int ov518_i2c_r(struct sd *sd, u8 reg)
static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2357,7 +2367,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
(u16) value, (u16) reg, NULL, 0, 500);
if (ret < 0) {
- pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret);
+ PERR("ovfx2_i2c_w %02x failed %d\n", reg, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2366,6 +2376,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
static int ovfx2_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret;
if (sd->gspca_dev.usb_err < 0)
@@ -2381,7 +2392,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg)
ret = sd->gspca_dev.usb_buf[0];
PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret);
} else {
- pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret);
+ PERR("ovfx2_i2c_r %02x failed %d\n", reg, ret);
sd->gspca_dev.usb_err = ret;
}
@@ -2478,6 +2489,8 @@ static void i2c_w_mask(struct sd *sd,
* registers while the camera is streaming */
static inline void ov51x_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "stopping");
sd->stopped = 1;
switch (sd->bridge) {
@@ -2507,6 +2520,8 @@ static inline void ov51x_stop(struct sd *sd)
* actually stopped (for performance). */
static inline void ov51x_restart(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "restarting");
if (!sd->stopped)
return;
@@ -2545,6 +2560,7 @@ static void ov51x_set_slave_ids(struct sd *sd, u8 slave);
static int init_ov_sensor(struct sd *sd, u8 slave)
{
int i;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
ov51x_set_slave_ids(sd, slave);
@@ -2624,10 +2640,11 @@ static void write_i2c_regvals(struct sd *sd,
/* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */
static void ov_hires_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int high, low;
if (sd->bridge != BRIDGE_OVFX2) {
- pr_err("error hires sensors only supported with ovfx2\n");
+ PERR("error hires sensors only supported with ovfx2\n");
return;
}
@@ -2662,7 +2679,7 @@ static void ov_hires_configure(struct sd *sd)
}
break;
}
- pr_err("Error unknown sensor type: %02x%02x\n", high, low);
+ PERR("Error unknown sensor type: %02x%02x\n", high, low);
}
/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
@@ -2670,6 +2687,7 @@ static void ov_hires_configure(struct sd *sd)
*/
static void ov8xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc;
PDEBUG(D_PROBE, "starting ov8xx0 configuration");
@@ -2677,13 +2695,13 @@ static void ov8xx0_configure(struct sd *sd)
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
- PDEBUG(D_ERR, "Error detecting sensor type");
+ PERR("Error detecting sensor type");
return;
}
if ((rc & 3) == 1)
sd->sensor = SEN_OV8610;
else
- pr_err("Unknown image sensor version: %d\n", rc & 3);
+ PERR("Unknown image sensor version: %d\n", rc & 3);
}
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
@@ -2691,6 +2709,7 @@ static void ov8xx0_configure(struct sd *sd)
*/
static void ov7xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc, high, low;
PDEBUG(D_PROBE, "starting OV7xx0 configuration");
@@ -2701,7 +2720,7 @@ static void ov7xx0_configure(struct sd *sd)
/* add OV7670 here
* it appears to be wrongly detected as a 7610 by default */
if (rc < 0) {
- pr_err("Error detecting sensor type\n");
+ PERR("Error detecting sensor type\n");
return;
}
if ((rc & 3) == 3) {
@@ -2729,19 +2748,19 @@ static void ov7xx0_configure(struct sd *sd)
/* try to read product id registers */
high = i2c_r(sd, 0x0a);
if (high < 0) {
- pr_err("Error detecting camera chip PID\n");
+ PERR("Error detecting camera chip PID\n");
return;
}
low = i2c_r(sd, 0x0b);
if (low < 0) {
- pr_err("Error detecting camera chip VER\n");
+ PERR("Error detecting camera chip VER\n");
return;
}
if (high == 0x76) {
switch (low) {
case 0x30:
- pr_err("Sensor is an OV7630/OV7635\n");
- pr_err("7630 is not supported by this driver\n");
+ PERR("Sensor is an OV7630/OV7635\n");
+ PERR("7630 is not supported by this driver\n");
return;
case 0x40:
PDEBUG(D_PROBE, "Sensor is an OV7645");
@@ -2760,7 +2779,7 @@ static void ov7xx0_configure(struct sd *sd)
sd->sensor = SEN_OV7660;
break;
default:
- pr_err("Unknown sensor: 0x76%02x\n", low);
+ PERR("Unknown sensor: 0x76%02x\n", low);
return;
}
} else {
@@ -2768,20 +2787,22 @@ static void ov7xx0_configure(struct sd *sd)
sd->sensor = SEN_OV7620;
}
} else {
- pr_err("Unknown image sensor version: %d\n", rc & 3);
+ PERR("Unknown image sensor version: %d\n", rc & 3);
}
}
/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
static void ov6xx0_configure(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int rc;
+
PDEBUG(D_PROBE, "starting OV6xx0 configuration");
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
- pr_err("Error detecting sensor type\n");
+ PERR("Error detecting sensor type\n");
return;
}
@@ -2810,7 +2831,7 @@ static void ov6xx0_configure(struct sd *sd)
pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n");
break;
default:
- pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc);
+ PERR("FATAL: Unknown sensor version: 0x%02x\n", rc);
return;
}
@@ -2907,6 +2928,7 @@ static void ov51x_upload_quan_tables(struct sd *sd)
7, 7, 7, 7, 7, 7, 8, 8
};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
const unsigned char *pYTable, *pUVTable;
unsigned char val0, val1;
int i, size, reg = R51x_COMP_LUT_BEGIN;
@@ -3300,7 +3322,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
ov_hires_configure(sd);
} else {
- pr_err("Can't determine sensor slave IDs\n");
+ PERR("Can't determine sensor slave IDs\n");
goto error;
}
@@ -3433,7 +3455,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
return gspca_dev->usb_err;
error:
- PDEBUG(D_ERR, "OV519 Config failed");
+ PERR("OV519 Config failed");
return -EINVAL;
}
@@ -3459,6 +3481,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
*/
static void ov511_mode_init_regs(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int hsegs, vsegs, packet_size, fps, needed;
int interlaced = 0;
struct usb_host_interface *alt;
@@ -3467,7 +3490,7 @@ static void ov511_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- pr_err("Couldn't get altsetting\n");
+ PERR("Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO;
return;
}
@@ -3583,6 +3606,7 @@ static void ov511_mode_init_regs(struct sd *sd)
*/
static void ov518_mode_init_regs(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int hsegs, vsegs, packet_size;
struct usb_host_interface *alt;
struct usb_interface *intf;
@@ -3590,7 +3614,7 @@ static void ov518_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- pr_err("Couldn't get altsetting\n");
+ PERR("Couldn't get altsetting\n");
sd->gspca_dev.usb_err = -EIO;
return;
}
@@ -3750,6 +3774,8 @@ static void ov519_mode_init_regs(struct sd *sd)
/* windows reads 0x55 at this point, why? */
};
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
/******** Set the mode ********/
switch (sd->sensor) {
default:
@@ -3865,11 +3891,10 @@ static void ov519_mode_init_regs(struct sd *sd)
static void mode_init_ov_sensor_regs(struct sd *sd)
{
- struct gspca_dev *gspca_dev;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int qvga, xstart, xend, ystart, yend;
u8 v;
- gspca_dev = &sd->gspca_dev;
qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
/******** Mode (VGA/QVGA) and sensor specific regs ********/
@@ -4304,7 +4329,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
/* Frame end */
if ((in[9] + 1) * 8 != gspca_dev->width ||
(in[10] + 1) * 8 != gspca_dev->height) {
- PDEBUG(D_ERR, "Invalid frame size, got: %dx%d,"
+ PERR("Invalid frame size, got: %dx%d,"
" requested: %dx%d\n",
(in[9] + 1) * 8, (in[10] + 1) * 8,
gspca_dev->width, gspca_dev->height);
@@ -4355,7 +4380,7 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
except that they may contain part of the footer), are
numbered 0 */
else if (sd->packet_nr == 0 || data[len]) {
- PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)",
+ PERR("Invalid packet nr: %d (expect: %d)",
(int)data[len], (int)sd->packet_nr);
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
@@ -4898,7 +4923,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
if (hdl->error) {
- pr_err("Could not initialize controls\n");
+ PERR("Could not initialize controls\n");
return hdl->error;
}
if (gspca_dev->autogain)
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index bb09d7884b89..2e28c81a03ab 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -690,7 +690,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
case 0x03:
break;
default:
- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+ PERR("sccb status 0x%02x, attempt %d/5",
data, i + 1);
}
}
diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c
index 3b75097dd34e..83519be94e58 100644
--- a/drivers/media/usb/gspca/pac207.c
+++ b/drivers/media/usb/gspca/pac207.c
@@ -373,7 +373,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n;
diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c
index add6f725ba50..6008c8d546a3 100644
--- a/drivers/media/usb/gspca/pac7302.c
+++ b/drivers/media/usb/gspca/pac7302.c
@@ -344,13 +344,10 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
reg_w_page(gspca_dev, page3, page3_len);
break;
default:
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- PDEBUG(D_ERR|D_STREAM,
- "Incorrect variable sequence");
+ PERR("Incorrect variable sequence");
return;
}
-#endif
while (len > 0) {
if (len < 8) {
reg_w_buf(gspca_dev,
@@ -795,7 +792,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *image;
u8 *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
@@ -843,7 +840,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
u8 index;
u8 value;
diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c
index a12dfbf6e051..1a5bdc853a80 100644
--- a/drivers/media/usb/gspca/pac7311.c
+++ b/drivers/media/usb/gspca/pac7311.c
@@ -262,8 +262,7 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
break;
default:
if (len > USB_BUF_SZ) {
- PDEBUG(D_ERR|D_STREAM,
- "Incorrect variable sequence");
+ PERR("Incorrect variable sequence");
return;
}
while (len > 0) {
@@ -575,7 +574,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *image;
unsigned char *sof;
- sof = pac_find_sof(&sd->sof_read, data, len);
+ sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
diff --git a/drivers/media/usb/gspca/pac_common.h b/drivers/media/usb/gspca/pac_common.h
index 8462a7c1a338..fbc5e226c3e4 100644
--- a/drivers/media/usb/gspca/pac_common.h
+++ b/drivers/media/usb/gspca/pac_common.h
@@ -71,7 +71,7 @@ static const unsigned char pac_sof_marker[5] =
+----------+
*/
-static unsigned char *pac_find_sof(u8 *sof_read,
+static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, u8 *sof_read,
unsigned char *m, int len)
{
int i;
diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c
index 03fa3fd940b4..39b6b2e02963 100644
--- a/drivers/media/usb/gspca/sn9c2028.c
+++ b/drivers/media/usb/gspca/sn9c2028.c
@@ -650,13 +650,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
result = sn9c2028_read1(gspca_dev);
if (result < 0)
- PDEBUG(D_ERR, "Camera Stop read failed");
+ PERR("Camera Stop read failed");
memset(data, 0, 6);
data[0] = 0x14;
result = sn9c2028_command(gspca_dev, data);
if (result < 0)
- PDEBUG(D_ERR, "Camera Stop command failed");
+ PERR("Camera Stop command failed");
}
/* Include sn9c2028 sof detection functions */
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 4ec544f4a845..ead9a1f58513 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1598,7 +1598,7 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
}
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c
index 104ae25275b4..3fe207e038c7 100644
--- a/drivers/media/usb/gspca/sonixb.c
+++ b/drivers/media/usb/gspca/sonixb.c
@@ -1379,27 +1379,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
}
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu)
-{
- switch (menu->id) {
- case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
- }
- return -EINVAL;
-}
-
#if IS_ENABLED(CONFIG_INPUT)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
@@ -1428,7 +1407,6 @@ static const struct sd_desc sd_desc = {
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
- .querymenu = sd_querymenu,
.dq_callback = do_autogain,
#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c
index 671d0c6dece3..3b5ccb1c4cdf 100644
--- a/drivers/media/usb/gspca/sonixj.c
+++ b/drivers/media/usb/gspca/sonixj.c
@@ -31,32 +31,26 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
MODULE_LICENSE("GPL");
-/* controls */
-enum e_ctrl {
- BRIGHTNESS,
- CONTRAST,
- COLORS,
- BLUE,
- RED,
- GAMMA,
- EXPOSURE,
- AUTOGAIN,
- GAIN,
- HFLIP,
- VFLIP,
- SHARPNESS,
- ILLUM,
- FREQ,
- NCTRLS /* number of controls */
-};
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- struct gspca_ctrl ctrls[NCTRLS];
-
atomic_t avg_lum;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct { /* red/blue balance control cluster */
+ struct v4l2_ctrl *red_bal;
+ struct v4l2_ctrl *blue_bal;
+ };
+ struct { /* hflip/vflip control cluster */
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+ };
+ struct v4l2_ctrl *gamma;
+ struct v4l2_ctrl *illum;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *freq;
u32 exposure;
struct work_struct work;
@@ -127,283 +121,6 @@ static void qual_upd(struct work_struct *work);
#define SEN_CLK_EN 0x20 /* enable sensor clock */
#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */
-/* V4L2 controls supported by the driver */
-static void setbrightness(struct gspca_dev *gspca_dev);
-static void setcontrast(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
-static void setredblue(struct gspca_dev *gspca_dev);
-static void setgamma(struct gspca_dev *gspca_dev);
-static void setexposure(struct gspca_dev *gspca_dev);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static void setgain(struct gspca_dev *gspca_dev);
-static void sethvflip(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static void setillum(struct gspca_dev *gspca_dev);
-static void setfreq(struct gspca_dev *gspca_dev);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x80,
- },
- .set_control = setbrightness
- },
-[CONTRAST] = {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
-#define CONTRAST_MAX 127
- .maximum = CONTRAST_MAX,
- .step = 1,
- .default_value = 20,
- },
- .set_control = setcontrast
- },
-[COLORS] = {
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 40,
- .step = 1,
-#define COLORS_DEF 25
- .default_value = COLORS_DEF,
- },
- .set_control = setcolors
- },
-[BLUE] = {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 24,
- .maximum = 40,
- .step = 1,
- .default_value = 32,
- },
- .set_control = setredblue
- },
-[RED] = {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 24,
- .maximum = 40,
- .step = 1,
- .default_value = 32,
- },
- .set_control = setredblue
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0,
- .maximum = 40,
- .step = 1,
-#define GAMMA_DEF 20
- .default_value = GAMMA_DEF,
- },
- .set_control = setgamma
- },
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 500,
- .maximum = 1500,
- .step = 1,
- .default_value = 1024
- },
- .set_control = setexposure
- },
-[AUTOGAIN] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = sd_setautogain,
- },
-[GAIN] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 4,
- .maximum = 49,
- .step = 1,
- .default_value = 15
- },
- .set_control = setgain
- },
-[HFLIP] = {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = sethvflip
- },
-[VFLIP] = {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vflip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = sethvflip
- },
-[SHARPNESS] = {
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 90,
- },
- .set_control = setsharpness
- },
-[ILLUM] = {
- {
- .id = V4L2_CID_ILLUMINATORS_1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Illuminator / infrared",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = setillum
- },
-/* ov7630/ov7648/ov7660 only */
-[FREQ] = {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Light frequency filter",
- .minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
- .step = 1,
- .default_value = 1,
- },
- .set_control = setfreq
- },
-};
-
-/* table of the disabled controls */
-static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_GC0307] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_HV7131R] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << FREQ),
-
-[SENSOR_MI0360] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MI0360B] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MO4000] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_MT9V111] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_OM6802] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_OV7630] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP),
-
-[SENSOR_OV7648] = (1 << EXPOSURE) |
- (1 << GAIN) |
- (1 << HFLIP),
-
-[SENSOR_OV7660] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP),
-
-[SENSOR_PO1030] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_PO2030N] = (1 << FREQ),
-
-[SENSOR_SOI768] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-
-[SENSOR_SP80708] = (1 << EXPOSURE) |
- (1 << AUTOGAIN) |
- (1 << GAIN) |
- (1 << HFLIP) |
- (1 << VFLIP) |
- (1 << FREQ),
-};
-
static const struct v4l2_pix_format cif_mode[] = {
{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 352,
@@ -1442,12 +1159,11 @@ static void reg_r(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
+
ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
0,
@@ -1496,12 +1212,12 @@ static void reg_w(struct gspca_dev *gspca_dev,
return;
PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
value, buffer[0], buffer[1]);
-#ifdef GSPCA_DEBUG
+
if (len > USB_BUF_SZ) {
- pr_err("reg_w: buffer overflow\n");
+ PERR("reg_w: buffer overflow\n");
return;
}
-#endif
+
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
@@ -1822,7 +1538,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode);
}
cam->npkt = 24; /* 24 packets per ISOC message */
- cam->ctrls = sd->ctrls;
sd->ag_cnt = -1;
sd->quality = QUALITY_DEF;
@@ -1888,9 +1603,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
break;
}
- if (sd->sensor == SENSOR_OM6802)
- sd->ctrls[SHARPNESS].def = 0x10;
-
/* Note we do not disable the sensor clock here (power saving mode),
as that also disables the button on the cam. */
reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1899,13 +1611,92 @@ static int sd_init(struct gspca_dev *gspca_dev)
sn9c1xx = sn_tb[sd->sensor];
sd->i2c_addr = sn9c1xx[9];
- gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
- if (!(sd->flags & F_ILLUM))
- gspca_dev->ctrl_dis |= (1 << ILLUM);
-
return gspca_dev->usb_err;
}
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 14);
+
+ sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+#define CONTRAST_MAX 127
+ sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, CONTRAST_MAX, 1, 20);
+#define COLORS_DEF 25
+ sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 40, 1, COLORS_DEF);
+ sd->red_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 24, 40, 1, 32);
+ sd->blue_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 24, 40, 1, 32);
+#define GAMMA_DEF 20
+ sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 40, 1, GAMMA_DEF);
+
+ if (sd->sensor == SENSOR_OM6802)
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 255, 1, 16);
+ else
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 255, 1, 90);
+
+ if (sd->flags & F_ILLUM)
+ sd->illum = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 500, 1500, 1, 1024);
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 4, 49, 1, 15);
+ sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ }
+
+ if (sd->sensor != SENSOR_ADCM1700 && sd->sensor != SENSOR_OV7660 &&
+ sd->sensor != SENSOR_PO1030 && sd->sensor != SENSOR_SOI768 &&
+ sd->sensor != SENSOR_SP80708)
+ gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+
+ if (sd->sensor == SENSOR_HV7131R || sd->sensor == SENSOR_OV7630 ||
+ sd->sensor == SENSOR_OV7648 || sd->sensor == SENSOR_PO2030N)
+ sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ if (sd->sensor == SENSOR_OV7630 || sd->sensor == SENSOR_OV7648 ||
+ sd->sensor == SENSOR_OV7660)
+ sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->red_bal);
+ if (sd->sensor == SENSOR_PO2030N) {
+ v4l2_ctrl_cluster(2, &sd->vflip);
+ v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
+ }
+
+ return 0;
+}
+
static u32 expo_adjust(struct gspca_dev *gspca_dev,
u32 expo)
{
@@ -2014,10 +1805,9 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
- int brightness;
+ int brightness = sd->brightness->val;
u8 k2;
- brightness = sd->ctrls[BRIGHTNESS].val;
k2 = (brightness - 0x80) >> 2;
switch (sd->sensor) {
case SENSOR_ADCM1700:
@@ -2064,7 +1854,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
u8 k2;
u8 contrast[6];
- k2 = sd->ctrls[CONTRAST].val * 37 / (CONTRAST_MAX + 1)
+ k2 = sd->contrast->val * 37 / (CONTRAST_MAX + 1)
+ 37; /* 37..73 */
contrast[0] = (k2 + 1) / 2; /* red */
contrast[1] = 0;
@@ -2090,7 +1880,7 @@ static void setcolors(struct gspca_dev *gspca_dev)
60, -51, -9 /* VR VG VB */
};
- colors = sd->ctrls[COLORS].val;
+ colors = sd->saturation->val;
if (sd->sensor == SENSOR_MI0360B)
uv = uv_mi0360b;
else
@@ -2112,14 +1902,14 @@ static void setredblue(struct gspca_dev *gspca_dev)
{0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10};
/* 0x40 = normal value = gain x 1 */
- rg1b[3] = sd->ctrls[RED].val * 2;
- rg1b[5] = sd->ctrls[BLUE].val * 2;
+ rg1b[3] = sd->red_bal->val * 2;
+ rg1b[5] = sd->blue_bal->val * 2;
i2c_w8(gspca_dev, rg1b);
return;
}
- reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val);
+ reg_w1(gspca_dev, 0x05, sd->red_bal->val);
/* reg_w1(gspca_dev, 0x07, 32); */
- reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
+ reg_w1(gspca_dev, 0x06, sd->blue_bal->val);
}
static void setgamma(struct gspca_dev *gspca_dev)
@@ -2153,7 +1943,7 @@ static void setgamma(struct gspca_dev *gspca_dev)
break;
}
- val = sd->ctrls[GAMMA].val;
+ val = sd->gamma->val;
for (i = 0; i < sizeof gamma; i++)
gamma[i] = gamma_base[i]
+ delta[i] * (val - GAMMA_DEF) / 32;
@@ -2168,11 +1958,11 @@ static void setexposure(struct gspca_dev *gspca_dev)
u8 rexpo[] = /* 1a: expo H, 1b: expo M */
{0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10};
- rexpo[3] = sd->ctrls[EXPOSURE].val >> 8;
+ rexpo[3] = gspca_dev->exposure->val >> 8;
i2c_w8(gspca_dev, rexpo);
msleep(6);
rexpo[2] = 0x1b;
- rexpo[3] = sd->ctrls[EXPOSURE].val;
+ rexpo[3] = gspca_dev->exposure->val;
i2c_w8(gspca_dev, rexpo);
}
}
@@ -2181,8 +1971,6 @@ static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
- return;
switch (sd->sensor) {
case SENSOR_OV7630:
case SENSOR_OV7648: {
@@ -2192,13 +1980,13 @@ static void setautogain(struct gspca_dev *gspca_dev)
comb = 0xc0;
else
comb = 0xa0;
- if (sd->ctrls[AUTOGAIN].val)
+ if (gspca_dev->autogain->val)
comb |= 0x03;
i2c_w1(&sd->gspca_dev, 0x13, comb);
return;
}
}
- if (sd->ctrls[AUTOGAIN].val)
+ if (gspca_dev->autogain->val)
sd->ag_cnt = AG_CNT_START;
else
sd->ag_cnt = -1;
@@ -2212,7 +2000,7 @@ static void setgain(struct gspca_dev *gspca_dev)
u8 rgain[] = /* 15: gain */
{0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15};
- rgain[3] = sd->ctrls[GAIN].val;
+ rgain[3] = gspca_dev->gain->val;
i2c_w8(gspca_dev, rgain);
}
}
@@ -2225,19 +2013,19 @@ static void sethvflip(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_HV7131R:
comn = 0x18; /* clkdiv = 1, ablcen = 1 */
- if (sd->ctrls[VFLIP].val)
+ if (sd->vflip->val)
comn |= 0x01;
i2c_w1(gspca_dev, 0x01, comn); /* sctra */
break;
case SENSOR_OV7630:
comn = 0x02;
- if (!sd->ctrls[VFLIP].val)
+ if (!sd->vflip->val)
comn |= 0x80;
i2c_w1(gspca_dev, 0x75, comn);
break;
case SENSOR_OV7648:
comn = 0x06;
- if (sd->ctrls[VFLIP].val)
+ if (sd->vflip->val)
comn |= 0x80;
i2c_w1(gspca_dev, 0x75, comn);
break;
@@ -2251,9 +2039,9 @@ static void sethvflip(struct gspca_dev *gspca_dev)
* bit3-0: X
*/
comn = 0x0a;
- if (sd->ctrls[HFLIP].val)
+ if (sd->hflip->val)
comn |= 0x80;
- if (sd->ctrls[VFLIP].val)
+ if (sd->vflip->val)
comn |= 0x40;
i2c_w1(&sd->gspca_dev, 0x1e, comn);
break;
@@ -2264,23 +2052,21 @@ static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val);
+ reg_w1(gspca_dev, 0x99, sd->sharpness->val);
}
static void setillum(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << ILLUM))
- return;
switch (sd->sensor) {
case SENSOR_ADCM1700:
reg_w1(gspca_dev, 0x02, /* gpio */
- sd->ctrls[ILLUM].val ? 0x64 : 0x60);
+ sd->illum->val ? 0x64 : 0x60);
break;
case SENSOR_MT9V111:
reg_w1(gspca_dev, 0x02,
- sd->ctrls[ILLUM].val ? 0x77 : 0x74);
+ sd->illum->val ? 0x77 : 0x74);
/* should have been: */
/* 0x55 : 0x54); * 370i */
/* 0x66 : 0x64); * Clip */
@@ -2292,13 +2078,11 @@ static void setfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << FREQ))
- return;
if (sd->sensor == SENSOR_OV7660) {
u8 com8;
com8 = 0xdf; /* auto gain/wb/expo */
- switch (sd->ctrls[FREQ].val) {
+ switch (sd->freq->val) {
case 0: /* Banding filter disabled */
i2c_w1(gspca_dev, 0x13, com8 | 0x20);
break;
@@ -2326,7 +2110,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
break;
}
- switch (sd->ctrls[FREQ].val) {
+ switch (sd->freq->val) {
case 0: /* Banding filter disabled */
break;
case 1: /* 50 hz (filter on and framerate adj) */
@@ -2698,17 +2482,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
sd->reg01 = reg01;
sd->reg17 = reg17;
- sethvflip(gspca_dev);
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
- setcolors(gspca_dev);
- setautogain(gspca_dev);
- if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) {
- setexposure(gspca_dev);
- setgain(gspca_dev);
- }
- setfreq(gspca_dev);
-
sd->pktsz = sd->npkt = 0;
sd->nchg = sd->short_mark = 0;
sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
@@ -2803,9 +2576,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
}
-#define WANT_REGULAR_AUTOGAIN
-#include "autogain_functions.h"
-
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2825,7 +2595,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
PDEBUG(D_FRAM, "mean lum %d", delta);
if (sd->sensor == SENSOR_PO2030N) {
- auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta,
+ gspca_expo_autogain(gspca_dev, delta, luma_mean, luma_delta,
15, 1024);
return;
}
@@ -3042,39 +2812,53 @@ marker_found:
}
}
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct sd *sd = (struct sd *) gspca_dev;
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
- sd->ctrls[AUTOGAIN].val = val;
- if (val)
- gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
- else
- gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN);
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
- return gspca_dev->usb_err;
-}
+ gspca_dev->usb_err = 0;
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu)
-{
- switch (menu->id) {
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ setbrightness(gspca_dev);
+ break;
+ case V4L2_CID_CONTRAST:
+ setcontrast(gspca_dev);
+ break;
+ case V4L2_CID_SATURATION:
+ setcolors(gspca_dev);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ setredblue(gspca_dev);
+ break;
+ case V4L2_CID_GAMMA:
+ setgamma(gspca_dev);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ setautogain(gspca_dev);
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ break;
+ case V4L2_CID_VFLIP:
+ sethvflip(gspca_dev);
+ break;
+ case V4L2_CID_SHARPNESS:
+ setsharpness(gspca_dev);
+ break;
+ case V4L2_CID_ILLUMINATORS_1:
+ setillum(gspca_dev);
+ break;
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
+ setfreq(gspca_dev);
break;
+ default:
+ return -EINVAL;
}
- return -EINVAL;
+ return gspca_dev->usb_err;
}
#if IS_ENABLED(CONFIG_INPUT)
@@ -3099,16 +2883,14 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
- .querymenu = sd_querymenu,
#if IS_ENABLED(CONFIG_INPUT)
.int_pkt_scan = sd_int_pkt_scan,
#endif
diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c
index 14d635277d71..688592b289ea 100644
--- a/drivers/media/usb/gspca/spca1528.c
+++ b/drivers/media/usb/gspca/spca1528.c
@@ -146,7 +146,7 @@ static void wait_status_0(struct gspca_dev *gspca_dev)
w += 15;
msleep(w);
} while (--i > 0);
- PDEBUG(D_ERR, "wait_status_0 timeout");
+ PERR("wait_status_0 timeout");
gspca_dev->usb_err = -ETIME;
}
@@ -164,7 +164,7 @@ static void wait_status_1(struct gspca_dev *gspca_dev)
return;
}
} while (--i > 0);
- PDEBUG(D_ERR, "wait_status_1 timeout");
+ PERR("wait_status_1 timeout");
gspca_dev->usb_err = -ETIME;
}
diff --git a/drivers/media/usb/gspca/spca500.c b/drivers/media/usb/gspca/spca500.c
index 25cb68d0556d..9f8bf51fd64b 100644
--- a/drivers/media/usb/gspca/spca500.c
+++ b/drivers/media/usb/gspca/spca500.c
@@ -489,7 +489,7 @@ static int spca500_full_reset(struct gspca_dev *gspca_dev)
return err;
err = reg_r_wait(gspca_dev, 0x06, 0, 0);
if (err < 0) {
- PDEBUG(D_ERR, "reg_r_wait() failed");
+ PERR("reg_r_wait() failed");
return err;
}
/* all ok */
@@ -505,7 +505,7 @@ static int spca500_full_reset(struct gspca_dev *gspca_dev)
static int spca500_synch310(struct gspca_dev *gspca_dev)
{
if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
- PDEBUG(D_ERR, "Set packet size: set interface error");
+ PERR("Set packet size: set interface error");
goto error;
}
spca500_ping310(gspca_dev);
@@ -519,7 +519,7 @@ static int spca500_synch310(struct gspca_dev *gspca_dev)
if (usb_set_interface(gspca_dev->dev,
gspca_dev->iface,
gspca_dev->alt) < 0) {
- PDEBUG(D_ERR, "Set packet size: set interface error");
+ PERR("Set packet size: set interface error");
goto error;
}
return 0;
@@ -544,7 +544,7 @@ static void spca500_reinit(struct gspca_dev *gspca_dev)
err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
qtable_pocketdv);
if (err < 0)
- PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");
+ PERR("spca50x_setup_qtable failed on init");
/* set qtable index */
reg_w(gspca_dev, 0x00, 0x8880, 2);
@@ -639,7 +639,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0x00, 0x8800, 0x8840,
qtable_creative_pccam);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
/* Init SDRAM - needed for SDRAM access */
reg_w(gspca_dev, 0x00, 0x870a, 0x04);
@@ -647,7 +647,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
msleep(500);
if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
- PDEBUG(D_ERR, "reg_r_wait() failed");
+ PERR("reg_r_wait() failed");
reg_r(gspca_dev, 0x816b, 1);
Data = gspca_dev->usb_buf[0];
@@ -660,13 +660,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* enable drop packet */
err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
if (err < 0)
- PDEBUG(D_ERR, "failed to enable drop packet");
+ PERR("failed to enable drop packet");
reg_w(gspca_dev, 0x00, 0x8880, 3);
err = spca50x_setup_qtable(gspca_dev,
0x00, 0x8800, 0x8840,
qtable_creative_pccam);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
/* Init SDRAM - needed for SDRAM access */
reg_w(gspca_dev, 0x00, 0x870a, 0x04);
@@ -675,7 +675,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
- PDEBUG(D_ERR, "reg_r_wait() failed");
+ PERR("reg_r_wait() failed");
reg_r(gspca_dev, 0x816b, 1);
Data = gspca_dev->usb_buf[0];
@@ -689,18 +689,18 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* do a full reset */
err = spca500_full_reset(gspca_dev);
if (err < 0)
- PDEBUG(D_ERR, "spca500_full_reset failed");
+ PERR("spca500_full_reset failed");
/* enable drop packet */
err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
if (err < 0)
- PDEBUG(D_ERR, "failed to enable drop packet");
+ PERR("failed to enable drop packet");
reg_w(gspca_dev, 0x00, 0x8880, 3);
err = spca50x_setup_qtable(gspca_dev,
0x00, 0x8800, 0x8840,
qtable_creative_pccam);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
spca500_setmode(gspca_dev, xmult, ymult);
reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
@@ -709,7 +709,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
- PDEBUG(D_ERR, "reg_r_wait() failed");
+ PERR("reg_r_wait() failed");
reg_r(gspca_dev, 0x816b, 1);
Data = gspca_dev->usb_buf[0];
@@ -722,7 +722,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* do a full reset */
err = spca500_full_reset(gspca_dev);
if (err < 0)
- PDEBUG(D_ERR, "spca500_full_reset failed");
+ PERR("spca500_full_reset failed");
/* enable drop packet */
reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
reg_w(gspca_dev, 0x00, 0x8880, 0);
@@ -730,7 +730,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0x00, 0x8800, 0x8840,
qtable_kodak_ez200);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
spca500_setmode(gspca_dev, xmult, ymult);
reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
@@ -739,7 +739,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
- PDEBUG(D_ERR, "reg_r_wait() failed");
+ PERR("reg_r_wait() failed");
reg_r(gspca_dev, 0x816b, 1);
Data = gspca_dev->usb_buf[0];
@@ -765,7 +765,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
err = spca50x_setup_qtable(gspca_dev,
0x00, 0x8800, 0x8840, qtable_pocketdv);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
reg_w(gspca_dev, 0x00, 0x8880, 2);
/* familycam Quicksmart pocketDV stuff */
@@ -795,7 +795,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0x00, 0x8800,
0x8840, qtable_creative_pccam);
if (err < 0)
- PDEBUG(D_ERR, "spca50x_setup_qtable failed");
+ PERR("spca50x_setup_qtable failed");
reg_w(gspca_dev, 0x00, 0x8880, 3);
reg_w(gspca_dev, 0x00, 0x800a, 0x00);
/* Init SDRAM - needed for SDRAM access */
diff --git a/drivers/media/usb/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c
index 3b7f777785b4..d92fd17d6701 100644
--- a/drivers/media/usb/gspca/spca501.c
+++ b/drivers/media/usb/gspca/spca501.c
@@ -1756,10 +1756,11 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
{}
};
-static int reg_write(struct usb_device *dev,
- __u16 req, __u16 index, __u16 value)
+static int reg_write(struct gspca_dev *gspca_dev,
+ __u16 req, __u16 index, __u16 value)
{
int ret;
+ struct usb_device *dev = gspca_dev->dev;
ret = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -1774,17 +1775,15 @@ static int reg_write(struct usb_device *dev,
}
-static int write_vector(struct gspca_dev *gspca_dev,
- const __u16 data[][3])
+static int write_vector(struct gspca_dev *gspca_dev, const __u16 data[][3])
{
- struct usb_device *dev = gspca_dev->dev;
int ret, i = 0;
while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
- ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ ret = reg_write(gspca_dev, data[i][0], data[i][2],
+ data[i][1]);
if (ret < 0) {
- PDEBUG(D_ERR,
- "Reg write failed for 0x%02x,0x%02x,0x%02x",
+ PERR("Reg write failed for 0x%02x,0x%02x,0x%02x",
data[i][0], data[i][1], data[i][2]);
return ret;
}
@@ -1795,30 +1794,28 @@ static int write_vector(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
{
- reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, val);
+ reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x12, val);
}
static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
{
- reg_write(gspca_dev->dev, 0x00, 0x00,
- (val >> 8) & 0xff);
- reg_write(gspca_dev->dev, 0x00, 0x01,
- val & 0xff);
+ reg_write(gspca_dev, 0x00, 0x00, (val >> 8) & 0xff);
+ reg_write(gspca_dev, 0x00, 0x01, val & 0xff);
}
static void setcolors(struct gspca_dev *gspca_dev, s32 val)
{
- reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, val);
+ reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x0c, val);
}
static void setblue_balance(struct gspca_dev *gspca_dev, s32 val)
{
- reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, val);
+ reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x11, val);
}
static void setred_balance(struct gspca_dev *gspca_dev, s32 val)
{
- reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, val);
+ reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x13, val);
}
/* this function is called at probe time */
@@ -1868,7 +1865,6 @@ error:
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int mode;
switch (sd->subtype) {
@@ -1895,20 +1891,20 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Enable ISO packet machine CTRL reg=2,
* index=1 bitmask=0x2 (bit ordinal 1) */
- reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94);
+ reg_write(gspca_dev, SPCA50X_REG_USB, 0x6, 0x94);
switch (mode) {
case 0: /* 640x480 */
- reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a);
+ reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x004a);
break;
case 1: /* 320x240 */
- reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a);
+ reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x104a);
break;
default:
/* case 2: * 160x120 */
- reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a);
+ reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x204a);
break;
}
- reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02);
+ reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x01, 0x02);
return 0;
}
@@ -1917,7 +1913,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
{
/* Disable ISO packet
* machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */
- reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00);
+ reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x01, 0x00);
}
/* called on streamoff with alt 0 and on disconnect */
@@ -1925,7 +1921,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
if (!gspca_dev->present)
return;
- reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00);
+ reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x05, 0x00);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/usb/gspca/spca505.c b/drivers/media/usb/gspca/spca505.c
index bc7d67c3cb04..232b330d2dd3 100644
--- a/drivers/media/usb/gspca/spca505.c
+++ b/drivers/media/usb/gspca/spca505.c
@@ -544,10 +544,11 @@ static const u8 spca505b_open_data_ccd[][3] = {
{}
};
-static int reg_write(struct usb_device *dev,
+static int reg_write(struct gspca_dev *gspca_dev,
u16 req, u16 index, u16 value)
{
int ret;
+ struct usb_device *dev = gspca_dev->dev;
ret = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -584,11 +585,11 @@ static int reg_read(struct gspca_dev *gspca_dev,
static int write_vector(struct gspca_dev *gspca_dev,
const u8 data[][3])
{
- struct usb_device *dev = gspca_dev->dev;
int ret, i = 0;
while (data[i][0] != 0) {
- ret = reg_write(dev, data[i][0], data[i][2], data[i][1]);
+ ret = reg_write(gspca_dev, data[i][0], data[i][2],
+ data[i][1]);
if (ret < 0)
return ret;
i++;
@@ -629,14 +630,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
{
- reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6);
- reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2);
+ reg_write(gspca_dev, 0x05, 0x00, (255 - brightness) >> 6);
+ reg_write(gspca_dev, 0x05, 0x01, (255 - brightness) << 2);
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int ret, mode;
static u8 mode_tb[][3] = {
/* r00 r06 r07 */
@@ -654,9 +654,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
ret = reg_read(gspca_dev, 0x06, 0x16);
if (ret < 0) {
- PDEBUG(D_ERR|D_CONF,
- "register read failed err: %d",
- ret);
+ PERR("register read failed err: %d", ret);
return ret;
}
if (ret != 0x0101) {
@@ -664,22 +662,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
ret);
}
- ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a);
+ ret = reg_write(gspca_dev, 0x06, 0x16, 0x0a);
if (ret < 0)
return ret;
- reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12);
+ reg_write(gspca_dev, 0x05, 0xc2, 0x12);
/* necessary because without it we can see stream
* only once after loading module */
/* stopping usb registers Tomasz change */
- reg_write(dev, 0x02, 0x00, 0x00);
+ reg_write(gspca_dev, 0x02, 0x00, 0x00);
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
- reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
- reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
- reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
+ reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]);
+ reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]);
+ reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]);
- return reg_write(dev, SPCA50X_REG_USB,
+ return reg_write(gspca_dev, SPCA50X_REG_USB,
SPCA50X_USB_CTRL,
SPCA50X_CUSB_ENABLE);
}
@@ -687,7 +685,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
/* Disable ISO packet machine */
- reg_write(gspca_dev->dev, 0x02, 0x00, 0x00);
+ reg_write(gspca_dev, 0x02, 0x00, 0x00);
}
/* called on streamoff with alt 0 and on disconnect */
@@ -697,11 +695,11 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
return;
/* This maybe reset or power control */
- reg_write(gspca_dev->dev, 0x03, 0x03, 0x20);
- reg_write(gspca_dev->dev, 0x03, 0x01, 0x00);
- reg_write(gspca_dev->dev, 0x03, 0x00, 0x01);
- reg_write(gspca_dev->dev, 0x05, 0x10, 0x01);
- reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f);
+ reg_write(gspca_dev, 0x03, 0x03, 0x20);
+ reg_write(gspca_dev, 0x03, 0x01, 0x00);
+ reg_write(gspca_dev, 0x03, 0x00, 0x01);
+ reg_write(gspca_dev, 0x05, 0x10, 0x01);
+ reg_write(gspca_dev, 0x05, 0x11, 0x0f);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/usb/gspca/spca508.c b/drivers/media/usb/gspca/spca508.c
index 1286b4170b88..75f2beb2ea5a 100644
--- a/drivers/media/usb/gspca/spca508.c
+++ b/drivers/media/usb/gspca/spca508.c
@@ -1241,10 +1241,10 @@ static const u16 spca508_vista_init_data[][2] = {
{}
};
-static int reg_write(struct usb_device *dev,
- u16 index, u16 value)
+static int reg_write(struct gspca_dev *gspca_dev, u16 index, u16 value)
{
int ret;
+ struct usb_device *dev = gspca_dev->dev;
ret = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
@@ -1286,22 +1286,21 @@ static int reg_read(struct gspca_dev *gspca_dev,
static int ssi_w(struct gspca_dev *gspca_dev,
u16 reg, u16 val)
{
- struct usb_device *dev = gspca_dev->dev;
int ret, retry;
- ret = reg_write(dev, 0x8802, reg >> 8);
+ ret = reg_write(gspca_dev, 0x8802, reg >> 8);
if (ret < 0)
goto out;
- ret = reg_write(dev, 0x8801, reg & 0x00ff);
+ ret = reg_write(gspca_dev, 0x8801, reg & 0x00ff);
if (ret < 0)
goto out;
if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */
- ret = reg_write(dev, 0x8805, val & 0x00ff);
+ ret = reg_write(gspca_dev, 0x8805, val & 0x00ff);
if (ret < 0)
goto out;
val >>= 8;
}
- ret = reg_write(dev, 0x8800, val);
+ ret = reg_write(gspca_dev, 0x8800, val);
if (ret < 0)
goto out;
@@ -1314,8 +1313,7 @@ static int ssi_w(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_buf[0] == 0)
break;
if (--retry <= 0) {
- PDEBUG(D_ERR, "ssi_w busy %02x",
- gspca_dev->usb_buf[0]);
+ PERR("ssi_w busy %02x", gspca_dev->usb_buf[0]);
ret = -1;
break;
}
@@ -1329,7 +1327,6 @@ out:
static int write_vector(struct gspca_dev *gspca_dev,
const u16 (*data)[2])
{
- struct usb_device *dev = gspca_dev->dev;
int ret = 0;
while ((*data)[1] != 0) {
@@ -1337,7 +1334,8 @@ static int write_vector(struct gspca_dev *gspca_dev,
if ((*data)[1] == 0xdd00) /* delay */
msleep((*data)[0]);
else
- ret = reg_write(dev, (*data)[1], (*data)[0]);
+ ret = reg_write(gspca_dev, (*data)[1],
+ (*data)[0]);
} else {
ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]);
}
@@ -1363,8 +1361,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
spca508cs110_init_data, /* MicroInnovationIC200 4 */
spca508_init_data, /* ViewQuestVQ110 5 */
};
-
-#ifdef GSPCA_DEBUG
int data1, data2;
/* Read from global register the USB product and vendor IDs, just to
@@ -1381,7 +1377,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
data1 = reg_read(gspca_dev, 0x8621);
PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
-#endif
cam = &gspca_dev->cam;
cam->cam_mode = sif_mode;
@@ -1404,26 +1399,26 @@ static int sd_start(struct gspca_dev *gspca_dev)
int mode;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- reg_write(gspca_dev->dev, 0x8500, mode);
+ reg_write(gspca_dev, 0x8500, mode);
switch (mode) {
case 0:
case 1:
- reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */
+ reg_write(gspca_dev, 0x8700, 0x28); /* clock */
break;
default:
/* case 2: */
/* case 3: */
- reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */
+ reg_write(gspca_dev, 0x8700, 0x23); /* clock */
break;
}
- reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20);
+ reg_write(gspca_dev, 0x8112, 0x10 | 0x20);
return 0;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
/* Video ISO disable, Video Drop Packet enable: */
- reg_write(gspca_dev->dev, 0x8112, 0x20);
+ reg_write(gspca_dev, 0x8112, 0x20);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -1450,10 +1445,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
{
/* MX seem contrast */
- reg_write(gspca_dev->dev, 0x8651, brightness);
- reg_write(gspca_dev->dev, 0x8652, brightness);
- reg_write(gspca_dev->dev, 0x8653, brightness);
- reg_write(gspca_dev->dev, 0x8654, brightness);
+ reg_write(gspca_dev, 0x8651, brightness);
+ reg_write(gspca_dev, 0x8652, brightness);
+ reg_write(gspca_dev, 0x8653, brightness);
+ reg_write(gspca_dev, 0x8654, brightness);
}
static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/usb/gspca/spca561.c b/drivers/media/usb/gspca/spca561.c
index d1db3d8f6522..403d71cd65d9 100644
--- a/drivers/media/usb/gspca/spca561.c
+++ b/drivers/media/usb/gspca/spca561.c
@@ -285,9 +285,10 @@ static const __u16 spca561_161rev12A_data2[][2] = {
{}
};
-static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
+static void reg_w_val(struct gspca_dev *gspca_dev, __u16 index, __u8 value)
{
int ret;
+ struct usb_device *dev = gspca_dev->dev;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0, /* request */
@@ -301,12 +302,11 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
static void write_vector(struct gspca_dev *gspca_dev,
const __u16 data[][2])
{
- struct usb_device *dev = gspca_dev->dev;
int i;
i = 0;
while (data[i][1] != 0) {
- reg_w_val(dev, data[i][1], data[i][0]);
+ reg_w_val(gspca_dev, data[i][1], data[i][0]);
i++;
}
}
@@ -339,9 +339,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg)
{
int retry = 60;
- reg_w_val(gspca_dev->dev, 0x8801, reg);
- reg_w_val(gspca_dev->dev, 0x8805, value);
- reg_w_val(gspca_dev->dev, 0x8800, value >> 8);
+ reg_w_val(gspca_dev, 0x8801, reg);
+ reg_w_val(gspca_dev, 0x8805, value);
+ reg_w_val(gspca_dev, 0x8800, value >> 8);
do {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf[0])
@@ -355,9 +355,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode)
int retry = 60;
__u8 value;
- reg_w_val(gspca_dev->dev, 0x8804, 0x92);
- reg_w_val(gspca_dev->dev, 0x8801, reg);
- reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01);
+ reg_w_val(gspca_dev, 0x8804, 0x92);
+ reg_w_val(gspca_dev, 0x8801, reg);
+ reg_w_val(gspca_dev, 0x8802, mode | 0x01);
do {
reg_r(gspca_dev, 0x8803, 1);
if (!gspca_dev->usb_buf[0]) {
@@ -459,14 +459,13 @@ static int sd_init_72a(struct gspca_dev *gspca_dev)
write_sensor_72a(gspca_dev, rev72a_init_sensor1);
write_vector(gspca_dev, rev72a_init_data2);
write_sensor_72a(gspca_dev, rev72a_init_sensor2);
- reg_w_val(gspca_dev->dev, 0x8112, 0x30);
+ reg_w_val(gspca_dev, 0x8112, 0x30);
return 0;
}
static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
__u16 reg;
if (sd->chip_revision == Rev012A)
@@ -474,16 +473,15 @@ static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
else
reg = 0x8611;
- reg_w_val(dev, reg + 0, val); /* R */
- reg_w_val(dev, reg + 1, val); /* Gr */
- reg_w_val(dev, reg + 2, val); /* B */
- reg_w_val(dev, reg + 3, val); /* Gb */
+ reg_w_val(gspca_dev, reg + 0, val); /* R */
+ reg_w_val(gspca_dev, reg + 1, val); /* Gr */
+ reg_w_val(gspca_dev, reg + 2, val); /* B */
+ reg_w_val(gspca_dev, reg + 3, val); /* Gb */
}
static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
__u8 blue, red;
__u16 reg;
@@ -496,11 +494,11 @@ static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
reg = 0x8651;
red += contrast - 0x20;
blue += contrast - 0x20;
- reg_w_val(dev, 0x8652, contrast + 0x20); /* Gr */
- reg_w_val(dev, 0x8654, contrast + 0x20); /* Gb */
+ reg_w_val(gspca_dev, 0x8652, contrast + 0x20); /* Gr */
+ reg_w_val(gspca_dev, 0x8654, contrast + 0x20); /* Gb */
}
- reg_w_val(dev, reg, red);
- reg_w_val(dev, reg + 2, blue);
+ reg_w_val(gspca_dev, reg, red);
+ reg_w_val(gspca_dev, reg + 2, blue);
}
/* rev 12a only */
@@ -570,7 +568,6 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val)
static int sd_start_12a(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
int mode;
static const __u8 Reg8391[8] =
{0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00};
@@ -578,34 +575,33 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
if (mode <= 1) {
/* Use compression on 320x240 and above */
- reg_w_val(dev, 0x8500, 0x10 | mode);
+ reg_w_val(gspca_dev, 0x8500, 0x10 | mode);
} else {
/* I couldn't get the compression to work below 320x240
* Fortunately at these resolutions the bandwidth
* is sufficient to push raw frames at ~20fps */
- reg_w_val(dev, 0x8500, mode);
+ reg_w_val(gspca_dev, 0x8500, mode);
} /* -- qq@kuku.eu.org */
gspca_dev->usb_buf[0] = 0xaa;
gspca_dev->usb_buf[1] = 0x00;
reg_w_buf(gspca_dev, 0x8307, 2);
/* clock - lower 0x8X values lead to fps > 30 */
- reg_w_val(gspca_dev->dev, 0x8700, 0x8a);
+ reg_w_val(gspca_dev, 0x8700, 0x8a);
/* 0x8f 0x85 0x27 clock */
- reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
- reg_w_val(gspca_dev->dev, 0x850b, 0x03);
+ reg_w_val(gspca_dev, 0x8112, 0x1e | 0x20);
+ reg_w_val(gspca_dev, 0x850b, 0x03);
memcpy(gspca_dev->usb_buf, Reg8391, 8);
reg_w_buf(gspca_dev, 0x8391, 8);
reg_w_buf(gspca_dev, 0x8390, 8);
/* Led ON (bit 3 -> 0 */
- reg_w_val(gspca_dev->dev, 0x8114, 0x00);
+ reg_w_val(gspca_dev, 0x8114, 0x00);
return 0;
}
static int sd_start_72a(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int Clck;
int mode;
@@ -630,15 +626,15 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
Clck = 0x21;
break;
}
- reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */
- reg_w_val(dev, 0x8702, 0x81);
- reg_w_val(dev, 0x8500, mode); /* mode */
+ reg_w_val(gspca_dev, 0x8700, Clck); /* 0x27 clock */
+ reg_w_val(gspca_dev, 0x8702, 0x81);
+ reg_w_val(gspca_dev, 0x8500, mode); /* mode */
write_sensor_72a(gspca_dev, rev72a_init_sensor2);
setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue),
v4l2_ctrl_g_ctrl(sd->contrast));
/* setbrightness(gspca_dev); * fixme: bad values */
setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
- reg_w_val(dev, 0x8112, 0x10 | 0x20);
+ reg_w_val(gspca_dev, 0x8112, 0x10 | 0x20);
return 0;
}
@@ -647,12 +643,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
if (sd->chip_revision == Rev012A) {
- reg_w_val(gspca_dev->dev, 0x8112, 0x0e);
+ reg_w_val(gspca_dev, 0x8112, 0x0e);
/* Led Off (bit 3 -> 1 */
- reg_w_val(gspca_dev->dev, 0x8114, 0x08);
+ reg_w_val(gspca_dev, 0x8114, 0x08);
} else {
- reg_w_val(gspca_dev->dev, 0x8112, 0x20);
-/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */
+ reg_w_val(gspca_dev, 0x8112, 0x20);
+/* reg_w_val(gspca_dev, 0x8102, 0x00); ?? */
}
}
@@ -736,7 +732,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* This should never happen */
if (len < 2) {
- PDEBUG(D_ERR, "Short SOF packet, ignoring");
+ PERR("Short SOF packet, ignoring");
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
}
diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c
index 1d99f10a3e19..a7ae0ec9fa91 100644
--- a/drivers/media/usb/gspca/sq905.c
+++ b/drivers/media/usb/gspca/sq905.c
@@ -387,7 +387,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
if (ret < 0) {
- PDEBUG(D_ERR, "Start streaming command failed");
+ PERR("Start streaming command failed");
return ret;
}
/* Start the workqueue function to do the streaming */
diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c
index 410cdcbb55d4..acb19fb9a3df 100644
--- a/drivers/media/usb/gspca/sq905c.c
+++ b/drivers/media/usb/gspca/sq905c.c
@@ -215,13 +215,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0);
if (ret < 0) {
- PDEBUG(D_ERR, "Get version command failed");
+ PERR("Get version command failed");
return ret;
}
ret = sq905c_read(gspca_dev, 0xf5, 0, 20);
if (ret < 0) {
- PDEBUG(D_ERR, "Reading version command failed");
+ PERR("Reading version command failed");
return ret;
}
/* Note we leave out the usb id and the manufacturing date */
@@ -286,7 +286,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
if (ret < 0) {
- PDEBUG(D_ERR, "Start streaming command failed");
+ PERR("Start streaming command failed");
return ret;
}
/* Start the workqueue function to do the streaming */
diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c
index 7e8748b31e85..b10d0821111c 100644
--- a/drivers/media/usb/gspca/sq930x.c
+++ b/drivers/media/usb/gspca/sq930x.c
@@ -541,13 +541,11 @@ static void ucbus_write(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return;
-#ifdef GSPCA_DEBUG
if ((batchsize - 1) * 3 > USB_BUF_SZ) {
- pr_err("Bug: usb_buf overflow\n");
+ PERR("Bug: usb_buf overflow\n");
gspca_dev->usb_err = -ENOMEM;
return;
}
-#endif
for (;;) {
len = ncmds;
diff --git a/drivers/media/usb/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c
index 67605272aaa8..9c0827631b9c 100644
--- a/drivers/media/usb/gspca/stv0680.c
+++ b/drivers/media/usb/gspca/stv0680.c
@@ -86,7 +86,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret)
{
stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */
- PDEBUG(D_ERR, "last error: %i, command = 0x%x",
+ PERR("last error: %i, command = 0x%x",
gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
return ret;
}
@@ -98,7 +98,7 @@ static int stv0680_get_video_mode(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0] = 0x0f;
if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) {
- PDEBUG(D_ERR, "Get_Camera_Mode failed");
+ PERR("Get_Camera_Mode failed");
return stv0680_handle_error(gspca_dev, -EIO);
}
@@ -116,13 +116,13 @@ static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode)
gspca_dev->usb_buf[0] = mode;
if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) {
- PDEBUG(D_ERR, "Set_Camera_Mode failed");
+ PERR("Set_Camera_Mode failed");
return stv0680_handle_error(gspca_dev, -EIO);
}
/* Verify we got what we've asked for */
if (stv0680_get_video_mode(gspca_dev) != mode) {
- PDEBUG(D_ERR, "Error setting camera video mode!");
+ PERR("Error setting camera video mode!");
return -EIO;
}
@@ -146,7 +146,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* ping camera to be sure STV0680 is present */
if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 ||
gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) {
- PDEBUG(D_ERR, "STV(e): camera ping failed!!");
+ PERR("STV(e): camera ping failed!!");
return stv0680_handle_error(gspca_dev, -ENODEV);
}
@@ -156,7 +156,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 ||
gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) {
- PDEBUG(D_ERR, "Could not get descriptor 0200.");
+ PERR("Could not get descriptor 0200.");
return stv0680_handle_error(gspca_dev, -ENODEV);
}
if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02)
@@ -167,7 +167,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
return stv0680_handle_error(gspca_dev, -ENODEV);
if (!(gspca_dev->usb_buf[7] & 0x09)) {
- PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode");
+ PERR("Camera supports neither CIF nor QVGA mode");
return -ENODEV;
}
if (gspca_dev->usb_buf[7] & 0x01)
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c
index 657160b4a1f7..55ee7a61c67f 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -42,8 +42,10 @@ static bool dump_sensor;
int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
+
u8 len = (i2c_data > 0xff) ? 2 : 1;
buf[0] = i2c_data & 0xff;
@@ -62,6 +64,7 @@ int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -110,6 +113,7 @@ static int stv06xx_write_sensor_finish(struct sd *sd)
int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
{
int err, i, j;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -139,6 +143,7 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
{
int err, i, j;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -170,6 +175,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
@@ -283,7 +289,7 @@ static int stv06xx_start(struct gspca_dev *gspca_dev)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- PDEBUG(D_ERR, "Couldn't get altsetting");
+ PERR("Couldn't get altsetting");
return -EIO;
}
@@ -341,7 +347,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
if (ret < 0)
- PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret);
+ PERR("set alt 1 err %d", ret);
return ret;
}
@@ -406,7 +412,7 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
len -= 4;
if (len < chunk_len) {
- PDEBUG(D_ERR, "URB packet length is smaller"
+ PERR("URB packet length is smaller"
" than the specified chunk length");
gspca_dev->last_packet_type = DISCARD_PACKET;
return;
@@ -449,7 +455,7 @@ frame_data:
sd->to_skip = gspca_dev->width * 4;
if (chunk_len)
- PDEBUG(D_ERR, "Chunk length is "
+ PERR("Chunk length is "
"non-zero on a SOF");
break;
@@ -463,7 +469,7 @@ frame_data:
NULL, 0);
if (chunk_len)
- PDEBUG(D_ERR, "Chunk length is "
+ PERR("Chunk length is "
"non-zero on a EOF");
break;
@@ -596,7 +602,6 @@ MODULE_DEVICE_TABLE(usb, device_table);
static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- PDEBUG(D_PROBE, "Probing for a stv06xx device");
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
THIS_MODULE);
}
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
index 06fa54c5efb2..2220b70d47e6 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c
@@ -255,7 +255,7 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
if (err < 0)
return err;
}
- PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
+ PDEBUG(D_CONF, "Writing exposure %d, rowexp %d, srowexp %d",
val, rowexp, srowexp);
return err;
}
@@ -280,7 +280,7 @@ static int hdcs_set_gains(struct sd *sd, u8 g)
static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
- PDEBUG(D_V4L2, "Writing gain %d", val);
+ PDEBUG(D_CONF, "Writing gain %d", val);
return hdcs_set_gains((struct sd *) gspca_dev,
val & 0xff);
}
@@ -467,6 +467,8 @@ static int hdcs_probe_1020(struct sd *sd)
static int hdcs_start(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "Starting stream");
return hdcs_set_state(sd, HDCS_STATE_RUN);
@@ -474,6 +476,8 @@ static int hdcs_start(struct sd *sd)
static int hdcs_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "Halting stream");
return hdcs_set_state(sd, HDCS_STATE_SLEEP);
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
index cdfc3d05ab6b..8206b7743300 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
@@ -190,6 +190,7 @@ static int pb0100_start(struct sd *sd)
int err, packet_size, max_packet_size;
struct usb_host_interface *alt;
struct usb_interface *intf;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct cam *cam = &sd->gspca_dev.cam;
u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
@@ -239,6 +240,7 @@ static int pb0100_start(struct sd *sd)
static int pb0100_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int err;
err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
@@ -334,7 +336,7 @@ static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
if (!err)
err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
- PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
+ PDEBUG(D_CONF, "Set green gain to %d, status: %d", val, err);
if (!err)
err = pb0100_set_red_balance(gspca_dev, ctrls->red->val);
@@ -357,7 +359,7 @@ static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
val = 255;
err = stv06xx_write_sensor(sd, PB_RGAIN, val);
- PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
+ PDEBUG(D_CONF, "Set red gain to %d, status: %d", val, err);
return err;
}
@@ -375,7 +377,7 @@ static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
val = 255;
err = stv06xx_write_sensor(sd, PB_BGAIN, val);
- PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
+ PDEBUG(D_CONF, "Set blue gain to %d, status: %d", val, err);
return err;
}
@@ -386,7 +388,7 @@ static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
int err;
err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
- PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
+ PDEBUG(D_CONF, "Set exposure to %d, status: %d", val, err);
return err;
}
@@ -406,7 +408,7 @@ static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
val = 0;
err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
- PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
+ PDEBUG(D_CONF, "Set autogain to %d (natural: %d), status: %d",
val, ctrls->natural->val, err);
return err;
@@ -428,7 +430,7 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
if (!err)
err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
- PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
+ PDEBUG(D_CONF, "Set autogain target to %d, status: %d", val, err);
return err;
}
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
index 8a57990dfe0f..515a9e121653 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c
@@ -279,6 +279,8 @@ static int st6422_start(struct sd *sd)
static int st6422_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
+
PDEBUG(D_STREAM, "Halting stream");
return 0;
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
index e95fa8997d22..bf3e5c317a26 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c
@@ -131,6 +131,7 @@ static int vv6410_init(struct sd *sd)
static int vv6410_start(struct sd *sd)
{
int err;
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
struct cam *cam = &sd->gspca_dev.cam;
u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
@@ -163,6 +164,7 @@ static int vv6410_start(struct sd *sd)
static int vv6410_stop(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int err;
/* Turn off LED */
@@ -208,7 +210,7 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
else
i2c_data &= ~VV6410_HFLIP;
- PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+ PDEBUG(D_CONF, "Set horizontal flip to %d", val);
err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
return (err < 0) ? err : 0;
@@ -229,7 +231,7 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
else
i2c_data &= ~VV6410_VFLIP;
- PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+ PDEBUG(D_CONF, "Set vertical flip to %d", val);
err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
return (err < 0) ? err : 0;
@@ -240,7 +242,7 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
struct sd *sd = (struct sd *) gspca_dev;
- PDEBUG(D_V4L2, "Set analog gain to %d", val);
+ PDEBUG(D_CONF, "Set analog gain to %d", val);
err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
return (err < 0) ? err : 0;
@@ -257,7 +259,7 @@ static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
fine = val % VV6410_CIF_LINELENGTH;
coarse = min(512, val / VV6410_CIF_LINELENGTH);
- PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d",
+ PDEBUG(D_CONF, "Set coarse exposure to %d, fine expsure to %d",
coarse, fine);
err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index 9ccfcb1c6479..af8767a9bd4c 100644
--- a/drivers/media/usb/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
@@ -251,12 +251,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
{
int ret;
-#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
- pr_err("reg_r: buffer overflow\n");
+ PERR("reg_r: buffer overflow\n");
return;
}
-#endif
if (gspca_dev->usb_err < 0)
return;
ret = usb_control_msg(gspca_dev->dev,
@@ -357,12 +355,14 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
}
-#ifdef GSPCA_DEBUG
static void spca504_read_info(struct gspca_dev *gspca_dev)
{
int i;
u8 info[6];
+ if (gspca_debug < D_STREAM)
+ return;
+
for (i = 0; i < 6; i++) {
reg_r(gspca_dev, 0, i, 1);
info[i] = gspca_dev->usb_buf[0];
@@ -373,7 +373,6 @@ static void spca504_read_info(struct gspca_dev *gspca_dev)
info[0], info[1], info[2],
info[3], info[4], info[5]);
}
-#endif
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req,
@@ -432,11 +431,13 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
}
}
-#ifdef GSPCA_DEBUG
static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
{
u8 *data;
+ if (gspca_debug < D_STREAM)
+ return;
+
data = gspca_dev->usb_buf;
reg_r(gspca_dev, 0x20, 0, 5);
PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
@@ -444,7 +445,6 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
reg_r(gspca_dev, 0x23, 0, 64);
reg_r(gspca_dev, 0x23, 1, 64);
}
-#endif
static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
{
@@ -457,9 +457,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
reg_w_riv(gspca_dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
-#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
-#endif
+
reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
reg_r(gspca_dev, 0x24, 8, 1);
@@ -645,14 +644,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* fall thru */
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
-#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
-#endif
break;
case BRIDGE_SPCA536:
-#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
-#endif
reg_r(gspca_dev, 0x00, 0x5002, 1);
reg_w_1(gspca_dev, 0x24, 0, 0, 0);
reg_r(gspca_dev, 0x24, 0, 1);
@@ -678,9 +673,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504: */
PDEBUG(D_STREAM, "Opening SPCA504");
if (sd->subtype == AiptekMiniPenCam13) {
-#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
-#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -752,9 +745,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case BRIDGE_SPCA504:
if (sd->subtype == AiptekMiniPenCam13) {
-#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
-#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -766,9 +757,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
0, 0, 0x9d, 1);
} else {
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
-#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
-#endif
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
}
diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c
index e50079503d96..c00ac57de510 100644
--- a/drivers/media/usb/gspca/vc032x.c
+++ b/drivers/media/usb/gspca/vc032x.c
@@ -2927,7 +2927,6 @@ static void reg_r(struct gspca_dev *gspca_dev,
u16 len)
{
reg_r_i(gspca_dev, req, index, len);
-#ifdef GSPCA_DEBUG
if (gspca_dev->usb_err < 0)
return;
if (len == 1)
@@ -2936,7 +2935,6 @@ static void reg_r(struct gspca_dev *gspca_dev,
else
PDEBUG(D_USBI, "GET %02x 0001 %04x %*ph",
req, index, 3, gspca_dev->usb_buf);
-#endif
}
static void reg_w_i(struct gspca_dev *gspca_dev,
@@ -2964,11 +2962,9 @@ static void reg_w(struct gspca_dev *gspca_dev,
u16 value,
u16 index)
{
-#ifdef GSPCA_DEBUG
if (gspca_dev->usb_err < 0)
return;
PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
-#endif
reg_w_i(gspca_dev, req, value, index);
}
@@ -3044,8 +3040,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
if (value == 0 && ptsensor_info->IdAdd == 0x82)
value = read_sensor_register(gspca_dev, 0x83);
if (value != 0) {
- PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
- value, i);
+ PDEBUG(D_PROBE, "Sensor ID %04x (%d)", value, i);
if (value == ptsensor_info->VpId)
return ptsensor_info->sensorId;
@@ -3069,14 +3064,12 @@ static void i2c_write(struct gspca_dev *gspca_dev,
{
int retry;
-#ifdef GSPCA_DEBUG
if (gspca_dev->usb_err < 0)
return;
if (size == 1)
PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
else
PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
-#endif
reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
reg_w_i(gspca_dev, 0xa0, size, 0xb334);
diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c
index 9e3a909e0a00..2165da0c7ce1 100644
--- a/drivers/media/usb/gspca/w996Xcf.c
+++ b/drivers/media/usb/gspca/w996Xcf.c
@@ -232,6 +232,7 @@ static void w9968cf_smbus_write_nack(struct sd *sd)
static void w9968cf_smbus_read_ack(struct sd *sd)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int sda;
/* Ensure SDA is high before raising clock to avoid a spurious stop */
@@ -248,6 +249,7 @@ static void w9968cf_smbus_read_ack(struct sd *sd)
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
u16* data = (u16 *)sd->gspca_dev.usb_buf;
data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
@@ -297,6 +299,7 @@ static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
static int w9968cf_i2c_r(struct sd *sd, u8 reg)
{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret = 0;
u8 value;
@@ -326,7 +329,7 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
ret = value;
PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
} else
- PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+ PERR("i2c read [0x%02x] failed", reg);
return ret;
}
diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c
index a8dc421f9f1f..cbfc2f921427 100644
--- a/drivers/media/usb/gspca/zc3xx.c
+++ b/drivers/media/usb/gspca/zc3xx.c
@@ -6259,12 +6259,11 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */
PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
if (retword == 0x2030) {
-#ifdef GSPCA_DEBUG
u8 retbyte;
retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
-#endif
+
send_unknown(gspca_dev, SENSOR_PO2030);
return retword;
}
diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c
index 5c6193536399..8247c19d6260 100644
--- a/drivers/media/usb/hdpvr/hdpvr-core.c
+++ b/drivers/media/usb/hdpvr/hdpvr-core.c
@@ -174,6 +174,7 @@ static int device_authorization(struct hdpvr_device *dev)
case HDPVR_FIRMWARE_VERSION_AC3:
case HDPVR_FIRMWARE_VERSION_0X12:
case HDPVR_FIRMWARE_VERSION_0X15:
+ case HDPVR_FIRMWARE_VERSION_0X1E:
dev->flags |= HDPVR_FLAG_AC3_CAP;
break;
default:
@@ -196,6 +197,7 @@ static int device_authorization(struct hdpvr_device *dev)
hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0);
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n",
print_buf);
+ kfree(print_buf);
#endif
msleep(100);
@@ -385,12 +387,6 @@ static int hdpvr_probe(struct usb_interface *interface,
}
mutex_unlock(&dev->io_mutex);
- if (hdpvr_register_videodev(dev, &interface->dev,
- video_nr[atomic_inc_return(&dev_nr)])) {
- v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
- goto error;
- }
-
#if IS_ENABLED(CONFIG_I2C)
retval = hdpvr_register_i2c_adapter(dev);
if (retval < 0) {
@@ -413,6 +409,13 @@ static int hdpvr_probe(struct usb_interface *interface,
}
#endif
+ retval = hdpvr_register_videodev(dev, &interface->dev,
+ video_nr[atomic_inc_return(&dev_nr)]);
+ if (retval < 0) {
+ v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
+ goto error;
+ }
+
/* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
video_device_node_name(dev->video_dev));
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index da6b77912222..774ba0e820be 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -10,6 +10,7 @@
*/
#include <linux/kernel.h>
+#include <linux/kconfig.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -20,9 +21,11 @@
#include <linux/workqueue.h>
#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include "hdpvr.h"
#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */
@@ -34,8 +37,23 @@
list_size(&dev->free_buff_list), \
list_size(&dev->rec_buff_list)); }
+static const struct v4l2_dv_timings hdpvr_dv_timings[] = {
+ V4L2_DV_BT_CEA_720X480I59_94,
+ V4L2_DV_BT_CEA_720X576I50,
+ V4L2_DV_BT_CEA_720X480P59_94,
+ V4L2_DV_BT_CEA_720X576P50,
+ V4L2_DV_BT_CEA_1280X720P50,
+ V4L2_DV_BT_CEA_1280X720P60,
+ V4L2_DV_BT_CEA_1920X1080I50,
+ V4L2_DV_BT_CEA_1920X1080I60,
+};
+
+/* Use 480i59 as the default timings */
+#define HDPVR_DEF_DV_TIMINGS_IDX (0)
+
struct hdpvr_fh {
- struct hdpvr_device *dev;
+ struct v4l2_fh fh;
+ bool legacy_mode;
};
static uint list_size(struct list_head *list)
@@ -359,53 +377,29 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
static int hdpvr_open(struct file *file)
{
- struct hdpvr_device *dev;
- struct hdpvr_fh *fh;
- int retval = -ENOMEM;
-
- dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
- if (!dev) {
- pr_err("open failing with with ENODEV\n");
- retval = -ENODEV;
- goto err;
- }
-
- fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL);
- if (!fh) {
- v4l2_err(&dev->v4l2_dev, "Out of memory\n");
- goto err;
- }
- /* lock the device to allow correctly handling errors
- * in resumption */
- mutex_lock(&dev->io_mutex);
- dev->open_count++;
- mutex_unlock(&dev->io_mutex);
+ struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- fh->dev = dev;
-
- /* save our object in the file's private structure */
+ if (fh == NULL)
+ return -ENOMEM;
+ fh->legacy_mode = true;
+ v4l2_fh_init(&fh->fh, video_devdata(file));
+ v4l2_fh_add(&fh->fh);
file->private_data = fh;
-
- retval = 0;
-err:
- return retval;
+ return 0;
}
static int hdpvr_release(struct file *file)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
-
- if (!dev)
- return -ENODEV;
+ struct hdpvr_device *dev = video_drvdata(file);
mutex_lock(&dev->io_mutex);
- if (!(--dev->open_count) && dev->status == STATUS_STREAMING)
+ if (file->private_data == dev->owner) {
hdpvr_stop_streaming(dev);
-
+ dev->owner = NULL;
+ }
mutex_unlock(&dev->io_mutex);
- return 0;
+ return v4l2_fh_release(file);
}
/*
@@ -415,8 +409,7 @@ static int hdpvr_release(struct file *file)
static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
loff_t *pos)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
struct hdpvr_buffer *buf = NULL;
struct urb *urb;
unsigned int ret = 0;
@@ -425,9 +418,6 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
if (*pos)
return -ESPIPE;
- if (!dev)
- return -ENODEV;
-
mutex_lock(&dev->io_mutex);
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
@@ -439,6 +429,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
mutex_unlock(&dev->io_mutex);
goto err;
}
+ dev->owner = file->private_data;
print_buffer_status();
}
mutex_unlock(&dev->io_mutex);
@@ -516,23 +507,23 @@ err:
static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct hdpvr_buffer *buf = NULL;
- struct hdpvr_fh *fh = filp->private_data;
- struct hdpvr_device *dev = fh->dev;
- unsigned int mask = 0;
+ struct hdpvr_device *dev = video_drvdata(filp);
+ unsigned int mask = v4l2_ctrl_poll(filp, wait);
- mutex_lock(&dev->io_mutex);
+ if (!(req_events & (POLLIN | POLLRDNORM)))
+ return mask;
- if (!video_is_registered(dev->video_dev)) {
- mutex_unlock(&dev->io_mutex);
- return -EIO;
- }
+ mutex_lock(&dev->io_mutex);
if (dev->status == STATUS_IDLE) {
if (hdpvr_start_streaming(dev)) {
v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"start_streaming failed\n");
dev->status = STATUS_IDLE;
+ } else {
+ dev->owner = filp->private_data;
}
print_buffer_status();
@@ -574,36 +565,188 @@ static int vidioc_querycap(struct file *file, void *priv,
strcpy(cap->driver, "hdpvr");
strcpy(cap->card, "Hauppauge HD PVR");
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-static int vidioc_s_std(struct file *file, void *private_data,
- v4l2_std_id *std)
+static int vidioc_s_std(struct file *file, void *_fh,
+ v4l2_std_id std)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
u8 std_type = 1;
- if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60))
+ if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
+ return -ENODATA;
+ if (dev->status != STATUS_IDLE)
+ return -EBUSY;
+ if (std & V4L2_STD_525_60)
std_type = 0;
+ dev->cur_std = std;
+ dev->width = 720;
+ dev->height = std_type ? 576 : 480;
return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type);
}
+static int vidioc_g_std(struct file *file, void *_fh,
+ v4l2_std_id *std)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+
+ if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT)
+ return -ENODATA;
+ *std = dev->cur_std;
+ return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_video_info *vid_info;
+ struct hdpvr_fh *fh = _fh;
+
+ *a = V4L2_STD_ALL;
+ if (dev->options.video_input == HDPVR_COMPONENT)
+ return fh->legacy_mode ? 0 : -ENODATA;
+ vid_info = get_video_info(dev);
+ if (vid_info == NULL)
+ return 0;
+ if (vid_info->width == 720 &&
+ (vid_info->height == 480 || vid_info->height == 576)) {
+ *a = (vid_info->height == 480) ?
+ V4L2_STD_525_60 : V4L2_STD_625_50;
+ }
+ kfree(vid_info);
+ return 0;
+}
+
+static int vidioc_s_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+ int i;
+
+ fh->legacy_mode = false;
+ if (dev->options.video_input)
+ return -ENODATA;
+ if (dev->status != STATUS_IDLE)
+ return -EBUSY;
+ for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
+ if (v4l_match_dv_timings(timings, hdpvr_dv_timings + i, 0))
+ break;
+ if (i == ARRAY_SIZE(hdpvr_dv_timings))
+ return -EINVAL;
+ dev->cur_dv_timings = hdpvr_dv_timings[i];
+ dev->width = hdpvr_dv_timings[i].bt.width;
+ dev->height = hdpvr_dv_timings[i].bt.height;
+ return 0;
+}
+
+static int vidioc_g_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+
+ fh->legacy_mode = false;
+ if (dev->options.video_input)
+ return -ENODATA;
+ *timings = dev->cur_dv_timings;
+ return 0;
+}
+
+static int vidioc_query_dv_timings(struct file *file, void *_fh,
+ struct v4l2_dv_timings *timings)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+ struct hdpvr_video_info *vid_info;
+ bool interlaced;
+ int ret = 0;
+ int i;
+
+ fh->legacy_mode = false;
+ if (dev->options.video_input)
+ return -ENODATA;
+ vid_info = get_video_info(dev);
+ if (vid_info == NULL)
+ return -ENOLCK;
+ interlaced = vid_info->fps <= 30;
+ for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) {
+ const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt;
+ unsigned hsize;
+ unsigned vsize;
+ unsigned fps;
+
+ hsize = bt->hfrontporch + bt->hsync + bt->hbackporch + bt->width;
+ vsize = bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch +
+ bt->height;
+ fps = (unsigned)bt->pixelclock / (hsize * vsize);
+ if (bt->width != vid_info->width ||
+ bt->height != vid_info->height ||
+ bt->interlaced != interlaced ||
+ (fps != vid_info->fps && fps + 1 != vid_info->fps))
+ continue;
+ *timings = hdpvr_dv_timings[i];
+ break;
+ }
+ if (i == ARRAY_SIZE(hdpvr_dv_timings))
+ ret = -ERANGE;
+ kfree(vid_info);
+ return ret;
+}
+
+static int vidioc_enum_dv_timings(struct file *file, void *_fh,
+ struct v4l2_enum_dv_timings *timings)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+
+ fh->legacy_mode = false;
+ memset(timings->reserved, 0, sizeof(timings->reserved));
+ if (dev->options.video_input)
+ return -ENODATA;
+ if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings))
+ return -EINVAL;
+ timings->timings = hdpvr_dv_timings[timings->index];
+ return 0;
+}
+
+static int vidioc_dv_timings_cap(struct file *file, void *_fh,
+ struct v4l2_dv_timings_cap *cap)
+{
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+
+ fh->legacy_mode = false;
+ if (dev->options.video_input)
+ return -ENODATA;
+ cap->type = V4L2_DV_BT_656_1120;
+ cap->bt.min_width = 720;
+ cap->bt.max_width = 1920;
+ cap->bt.min_height = 480;
+ cap->bt.max_height = 1080;
+ cap->bt.min_pixelclock = 27000000;
+ cap->bt.max_pixelclock = 74250000;
+ cap->bt.standards = V4L2_DV_BT_STD_CEA861;
+ cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE;
+ return 0;
+}
+
static const char *iname[] = {
[HDPVR_COMPONENT] = "Component",
[HDPVR_SVIDEO] = "S-Video",
[HDPVR_COMPOSITE] = "Composite",
};
-static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
+static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
unsigned int n;
n = i->index;
@@ -617,27 +760,42 @@ static int vidioc_enum_input(struct file *file, void *priv,
i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF;
- i->std = dev->video_dev->tvnorms;
+ i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS;
+ i->std = n ? V4L2_STD_ALL : 0;
return 0;
}
-static int vidioc_s_input(struct file *file, void *private_data,
+static int vidioc_s_input(struct file *file, void *_fh,
unsigned int index)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
int retval;
if (index >= HDPVR_VIDEO_INPUTS)
return -EINVAL;
if (dev->status != STATUS_IDLE)
- return -EAGAIN;
+ return -EBUSY;
retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1);
- if (!retval)
+ if (!retval) {
dev->options.video_input = index;
+ /*
+ * Unfortunately gstreamer calls ENUMSTD and bails out if it
+ * won't find any formats, even though component input is
+ * selected. This means that we have to leave tvnorms at
+ * V4L2_STD_ALL. We cannot use the 'legacy' trick since
+ * tvnorms is set at the device node level and not at the
+ * filehandle level.
+ *
+ * Comment this out for now, but if the legacy mode can be
+ * removed in the future, then this code should be enabled
+ * again.
+ dev->video_dev->tvnorms =
+ (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0;
+ */
+ }
return retval;
}
@@ -645,8 +803,7 @@ static int vidioc_s_input(struct file *file, void *private_data,
static int vidioc_g_input(struct file *file, void *private_data,
unsigned int *index)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
*index = dev->options.video_input;
return 0;
@@ -679,15 +836,14 @@ static int vidioc_enumaudio(struct file *file, void *priv,
static int vidioc_s_audio(struct file *file, void *private_data,
const struct v4l2_audio *audio)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
int retval;
if (audio->index >= HDPVR_AUDIO_INPUTS)
return -EINVAL;
if (dev->status != STATUS_IDLE)
- return -EAGAIN;
+ return -EBUSY;
retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec);
if (!retval)
@@ -699,8 +855,7 @@ static int vidioc_s_audio(struct file *file, void *private_data,
static int vidioc_g_audio(struct file *file, void *private_data,
struct v4l2_audio *audio)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev = video_drvdata(file);
audio->index = dev->options.audio_input;
audio->capability = V4L2_AUDCAP_STEREO;
@@ -709,335 +864,69 @@ static int vidioc_g_audio(struct file *file, void *private_data,
return 0;
}
-static const s32 supported_v4l2_ctrls[] = {
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_SHARPNESS,
- V4L2_CID_MPEG_AUDIO_ENCODING,
- V4L2_CID_MPEG_VIDEO_ENCODING,
- V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
- V4L2_CID_MPEG_VIDEO_BITRATE,
- V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
-};
-
-static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc,
- int ac3, int fw_ver)
-{
- int err;
-
- if (fw_ver > 0x15) {
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- }
- } else {
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80);
- }
- }
-
- switch (qc->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_AUDIO_ENCODING_AAC,
- ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3
- : V4L2_MPEG_AUDIO_ENCODING_AAC,
- 1, V4L2_MPEG_AUDIO_ENCODING_AAC);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
-
-/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */
-/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
-
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000,
- 6500000);
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000,
- 9000000);
- if (!err && opt->bitrate_mode == HDPVR_CONSTANT)
- qc->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return err;
- default:
- return -EINVAL;
- }
-}
-
-static int vidioc_queryctrl(struct file *file, void *private_data,
- struct v4l2_queryctrl *qc)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, next;
- u32 id = qc->id;
-
- memset(qc, 0, sizeof(*qc));
-
- next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
- qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
-
- for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) {
- if (next) {
- if (qc->id < supported_v4l2_ctrls[i])
- qc->id = supported_v4l2_ctrls[i];
- else
- continue;
- }
-
- if (qc->id == supported_v4l2_ctrls[i])
- return fill_queryctrl(&dev->options, qc,
- dev->flags & HDPVR_FLAG_AC3_CAP,
- dev->fw_ver);
-
- if (qc->id < supported_v4l2_ctrls[i])
- break;
- }
-
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *private_data,
- struct v4l2_control *ctrl)
+static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
+ struct hdpvr_device *dev =
+ container_of(ctrl->handler, struct hdpvr_device, hdl);
switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dev->options.brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dev->options.contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dev->options.saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dev->options.hue;
- break;
- case V4L2_CID_SHARPNESS:
- ctrl->value = dev->options.sharpness;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ dev->video_bitrate->val >= dev->video_bitrate_peak->val)
+ dev->video_bitrate_peak->val =
+ dev->video_bitrate->val + 100000;
break;
- default:
- return -EINVAL;
}
return 0;
}
-static int vidioc_s_ctrl(struct file *file, void *private_data,
- struct v4l2_control *ctrl)
+static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int retval;
+ struct hdpvr_device *dev =
+ container_of(ctrl->handler, struct hdpvr_device, hdl);
+ struct hdpvr_options *opt = &dev->options;
+ int ret = -EINVAL;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value);
- if (!retval)
- dev->options.brightness = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val);
+ if (ret)
+ break;
+ dev->options.brightness = ctrl->val;
+ return 0;
case V4L2_CID_CONTRAST:
- retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value);
- if (!retval)
- dev->options.contrast = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val);
+ if (ret)
+ break;
+ dev->options.contrast = ctrl->val;
+ return 0;
case V4L2_CID_SATURATION:
- retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value);
- if (!retval)
- dev->options.saturation = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val);
+ if (ret)
+ break;
+ dev->options.saturation = ctrl->val;
+ return 0;
case V4L2_CID_HUE:
- retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value);
- if (!retval)
- dev->options.hue = ctrl->value;
- break;
+ ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val);
+ if (ret)
+ break;
+ dev->options.hue = ctrl->val;
+ return 0;
case V4L2_CID_SHARPNESS:
- retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value);
- if (!retval)
- dev->options.sharpness = ctrl->value;
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-
-static int hdpvr_get_ctrl(struct hdpvr_options *opt,
- struct v4l2_ext_control *ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- ctrl->value = opt->audio_codec;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
- break;
-/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */
-/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT
- ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
- : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- ctrl->value = opt->bitrate * 100000;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- ctrl->value = opt->peak_bitrate * 100000;
- break;
- case V4L2_CID_MPEG_STREAM_TYPE:
- ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_get_ctrl(&dev->options, ctrl);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
-
- }
-
- return -EINVAL;
-}
-
-
-static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
-{
- int ret = -EINVAL;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC ||
- (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3))
- ret = 0;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
- ret = 0;
- break;
-/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
-/* if (ctrl->value == 0 || ctrl->value == 128) */
-/* ret = 0; */
-/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR ||
- ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
- ret = 0;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- {
- uint bitrate = ctrl->value / 100000;
- if (bitrate >= 10 && bitrate <= 135)
- ret = 0;
- break;
- }
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- {
- uint peak_bitrate = ctrl->value / 100000;
- if (peak_bitrate >= 10 && peak_bitrate <= 202)
- ret = 0;
- break;
- }
- case V4L2_CID_MPEG_STREAM_TYPE:
- if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
- ret = 0;
- break;
- default:
- return -EINVAL;
- }
- return ret;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_try_ctrl(ctrl,
- dev->flags & HDPVR_FLAG_AC3_CAP);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
- }
-
- return -EINVAL;
-}
-
-
-static int hdpvr_set_ctrl(struct hdpvr_device *dev,
- struct v4l2_ext_control *ctrl)
-{
- struct hdpvr_options *opt = &dev->options;
- int ret = 0;
-
- switch (ctrl->id) {
+ ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val);
+ if (ret)
+ break;
+ dev->options.sharpness = ctrl->val;
+ return 0;
case V4L2_CID_MPEG_AUDIO_ENCODING:
if (dev->flags & HDPVR_FLAG_AC3_CAP) {
- opt->audio_codec = ctrl->value;
- ret = hdpvr_set_audio(dev, opt->audio_input,
+ opt->audio_codec = ctrl->val;
+ return hdpvr_set_audio(dev, opt->audio_input,
opt->audio_codec);
}
- break;
+ return 0;
case V4L2_CID_MPEG_VIDEO_ENCODING:
- break;
+ return 0;
/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */
/* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */
/* opt->gop_mode |= 0x2; */
@@ -1050,86 +939,41 @@ static int hdpvr_set_ctrl(struct hdpvr_device *dev,
/* opt->gop_mode); */
/* } */
/* break; */
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR &&
- opt->bitrate_mode != HDPVR_CONSTANT) {
- opt->bitrate_mode = HDPVR_CONSTANT;
- hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
- opt->bitrate_mode);
- }
- if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
- opt->bitrate_mode == HDPVR_CONSTANT) {
- opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: {
+ uint peak_bitrate = dev->video_bitrate_peak->val / 100000;
+ uint bitrate = dev->video_bitrate->val / 100000;
+
+ if (ctrl->is_new) {
+ if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ opt->bitrate_mode = HDPVR_CONSTANT;
+ else
+ opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE;
hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE,
opt->bitrate_mode);
+ v4l2_ctrl_activate(dev->video_bitrate_peak,
+ ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
}
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE: {
- uint bitrate = ctrl->value / 100000;
-
- opt->bitrate = bitrate;
- if (bitrate >= opt->peak_bitrate)
- opt->peak_bitrate = bitrate+1;
-
- hdpvr_set_bitrate(dev);
- break;
- }
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: {
- uint peak_bitrate = ctrl->value / 100000;
-
- if (opt->bitrate_mode == HDPVR_CONSTANT)
- break;
- if (opt->bitrate < peak_bitrate) {
+ if (dev->video_bitrate_peak->is_new ||
+ dev->video_bitrate->is_new) {
+ opt->bitrate = bitrate;
opt->peak_bitrate = peak_bitrate;
hdpvr_set_bitrate(dev);
- } else
- ret = -EINVAL;
- break;
+ }
+ return 0;
}
case V4L2_CID_MPEG_STREAM_TYPE:
- break;
+ return 0;
default:
- return -EINVAL;
+ break;
}
return ret;
}
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- int i, err = 0;
-
- if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- err = hdpvr_try_ctrl(ctrl,
- dev->flags & HDPVR_FLAG_AC3_CAP);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- err = hdpvr_set_ctrl(dev, ctrl);
- if (err) {
- ctrls->error_idx = i;
- break;
- }
- }
- return err;
-
- }
-
- return -EINVAL;
-}
-
static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
struct v4l2_fmtdesc *f)
{
-
- if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->index != 0)
return -EINVAL;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
@@ -1139,56 +983,92 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data,
return 0;
}
-static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_format *f)
{
- struct hdpvr_fh *fh = file->private_data;
- struct hdpvr_device *dev = fh->dev;
- struct hdpvr_video_info *vid_info;
-
- if (!dev)
- return -ENODEV;
-
- vid_info = get_video_info(dev);
- if (!vid_info)
- return -EFAULT;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct hdpvr_device *dev = video_drvdata(file);
+ struct hdpvr_fh *fh = _fh;
+
+ /*
+ * The original driver would always returns the current detected
+ * resolution as the format (and EFAULT if it couldn't be detected).
+ * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a
+ * better way of doing this, but to stay compatible with existing
+ * applications we assume legacy mode every time an application opens
+ * the device. Only if one of the new DV_TIMINGS ioctls is called
+ * will the filehandle go into 'normal' mode where g_fmt returns the
+ * last set format.
+ */
+ if (fh->legacy_mode) {
+ struct hdpvr_video_info *vid_info;
+
+ vid_info = get_video_info(dev);
+ if (!vid_info)
+ return -EFAULT;
+ f->fmt.pix.width = vid_info->width;
+ f->fmt.pix.height = vid_info->height;
+ kfree(vid_info);
+ } else {
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ }
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.width = vid_info->width;
- f->fmt.pix.height = vid_info->height;
f->fmt.pix.sizeimage = dev->bulk_in_size;
- f->fmt.pix.colorspace = 0;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.field = V4L2_FIELD_ANY;
-
- kfree(vid_info);
+ f->fmt.pix.priv = 0;
+ if (f->fmt.pix.width == 720) {
+ /* SDTV formats */
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ } else {
+ /* HDTV formats */
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ }
return 0;
}
static int vidioc_encoder_cmd(struct file *filp, void *priv,
struct v4l2_encoder_cmd *a)
{
- struct hdpvr_fh *fh = filp->private_data;
- struct hdpvr_device *dev = fh->dev;
- int res;
+ struct hdpvr_device *dev = video_drvdata(filp);
+ int res = 0;
mutex_lock(&dev->io_mutex);
+ a->flags = 0;
- memset(&a->raw, 0, sizeof(a->raw));
switch (a->cmd) {
case V4L2_ENC_CMD_START:
- a->flags = 0;
+ if (dev->owner && filp->private_data != dev->owner) {
+ res = -EBUSY;
+ break;
+ }
+ if (dev->status == STATUS_STREAMING)
+ break;
res = hdpvr_start_streaming(dev);
+ if (!res)
+ dev->owner = filp->private_data;
+ else
+ dev->status = STATUS_IDLE;
break;
case V4L2_ENC_CMD_STOP:
+ if (dev->owner && filp->private_data != dev->owner) {
+ res = -EBUSY;
+ break;
+ }
+ if (dev->status == STATUS_IDLE)
+ break;
res = hdpvr_stop_streaming(dev);
+ if (!res)
+ dev->owner = NULL;
break;
default:
v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
"Unsupported encoder cmd %d\n", a->cmd);
res = -EINVAL;
+ break;
}
+
mutex_unlock(&dev->io_mutex);
return res;
}
@@ -1196,6 +1076,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv,
static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
struct v4l2_encoder_cmd *a)
{
+ a->flags = 0;
switch (a->cmd) {
case V4L2_ENC_CMD_START:
case V4L2_ENC_CMD_STOP:
@@ -1208,22 +1089,28 @@ static int vidioc_try_encoder_cmd(struct file *filp, void *priv,
static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_querystd = vidioc_querystd,
+ .vidioc_s_dv_timings = vidioc_s_dv_timings,
+ .vidioc_g_dv_timings = vidioc_g_dv_timings,
+ .vidioc_query_dv_timings= vidioc_query_dv_timings,
+ .vidioc_enum_dv_timings = vidioc_enum_dv_timings,
+ .vidioc_dv_timings_cap = vidioc_dv_timings_cap,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_enumaudio = vidioc_enumaudio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_encoder_cmd = vidioc_encoder_cmd,
.vidioc_try_encoder_cmd = vidioc_try_encoder_cmd,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static void hdpvr_device_release(struct video_device *vdev)
@@ -1236,9 +1123,10 @@ static void hdpvr_device_release(struct video_device *vdev)
mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&dev->hdl);
/* deregister I2C adapter */
-#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
mutex_lock(&dev->i2c_mutex);
i2c_del_adapter(&dev->i2c_adapter);
mutex_unlock(&dev->i2c_mutex);
@@ -1249,41 +1137,112 @@ static void hdpvr_device_release(struct video_device *vdev)
}
static const struct video_device hdpvr_video_template = {
-/* .type = VFL_TYPE_GRABBER, */
-/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */
.fops = &hdpvr_fops,
.release = hdpvr_device_release,
.ioctl_ops = &hdpvr_ioctl_ops,
- .tvnorms =
- V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B |
- V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I |
- V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N |
- V4L2_STD_PAL_60,
- .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M |
- V4L2_STD_PAL_60,
+ .tvnorms = V4L2_STD_ALL,
+};
+
+static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = {
+ .try_ctrl = hdpvr_try_ctrl,
+ .s_ctrl = hdpvr_s_ctrl,
};
int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
int devnum)
{
+ struct v4l2_ctrl_handler *hdl = &dev->hdl;
+ bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP;
+ int res;
+
+ dev->cur_std = V4L2_STD_525_60;
+ dev->width = 720;
+ dev->height = 480;
+ dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX];
+ v4l2_ctrl_handler_init(hdl, 11);
+ if (dev->fw_ver > 0x15) {
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+ } else {
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_HUE, 0x0, 0xff, 1, 0x80);
+ v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80);
+ }
+
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC,
+ 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC);
+ v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
+
+ dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+
+ dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 1000000, 13500000, 100000, 6500000);
+ dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 1100000, 20200000, 100000, 9000000);
+ dev->v4l2_dev.ctrl_handler = hdl;
+ if (hdl->error) {
+ res = hdl->error;
+ v4l2_err(&dev->v4l2_dev, "Could not register controls\n");
+ goto error;
+ }
+ v4l2_ctrl_cluster(3, &dev->video_mode);
+ res = v4l2_ctrl_handler_setup(hdl);
+ if (res < 0) {
+ v4l2_err(&dev->v4l2_dev, "Could not setup controls\n");
+ goto error;
+ }
+
/* setup and register video device */
dev->video_dev = video_device_alloc();
if (!dev->video_dev) {
v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n");
+ res = -ENOMEM;
goto error;
}
- *(dev->video_dev) = hdpvr_video_template;
+ *dev->video_dev = hdpvr_video_template;
strcpy(dev->video_dev->name, "Hauppauge HD PVR");
- dev->video_dev->parent = parent;
+ dev->video_dev->v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(dev->video_dev, dev);
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->video_dev->flags);
- if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) {
+ res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum);
+ if (res < 0) {
v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
goto error;
}
return 0;
error:
- return -ENOMEM;
+ v4l2_ctrl_handler_free(hdl);
+ return res;
}
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index fea3c6926997..1478f3d57630 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -16,6 +16,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/ir-kbd-i2c.h>
#define HDPVR_MAX 8
@@ -37,6 +38,7 @@
#define HDPVR_FIRMWARE_VERSION_AC3 0x0d
#define HDPVR_FIRMWARE_VERSION_0X12 0x12
#define HDPVR_FIRMWARE_VERSION_0X15 0x15
+#define HDPVR_FIRMWARE_VERSION_0X1E 0x1e
/* #define HDPVR_DEBUG */
@@ -65,10 +67,19 @@ struct hdpvr_options {
struct hdpvr_device {
/* the v4l device for this device */
struct video_device *video_dev;
+ /* the control handler for this device */
+ struct v4l2_ctrl_handler hdl;
/* the usb device for this device */
struct usb_device *udev;
/* v4l2-device unused */
struct v4l2_device v4l2_dev;
+ struct { /* video mode/bitrate control cluster */
+ struct v4l2_ctrl *video_mode;
+ struct v4l2_ctrl *video_bitrate;
+ struct v4l2_ctrl *video_bitrate_peak;
+ };
+ /* v4l2 format */
+ uint width, height;
/* the max packet size of the bulk endpoint */
size_t bulk_in_size;
@@ -77,11 +88,11 @@ struct hdpvr_device {
/* holds the current device status */
__u8 status;
- /* count the number of openers */
- uint open_count;
- /* holds the cureent set options */
+ /* holds the current set options */
struct hdpvr_options options;
+ v4l2_std_id cur_std;
+ struct v4l2_dv_timings cur_dv_timings;
uint flags;
@@ -99,6 +110,8 @@ struct hdpvr_device {
struct workqueue_struct *workqueue;
/**/
struct work_struct worker;
+ /* current stream owner */
+ struct v4l2_fh *owner;
/* I2C adapter */
struct i2c_adapter i2c_adapter;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 299751a8b06b..e11267f35d87 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -5165,7 +5165,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- struct v4l2_dbg_match *match, u64 reg_id,
+ const struct v4l2_dbg_match *match, u64 reg_id,
int setFl, u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
index 8060fc666eeb..91bae930cd79 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
@@ -240,7 +240,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *,
- struct v4l2_dbg_match *match, u64 reg_id,
+ const struct v4l2_dbg_match *match, u64 reg_id,
int setFl, u64 *val_ptr);
/* The following entry points are all lower level things you normally don't
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 34c3b6e80e86..a8a65fa57930 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -196,13 +196,13 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
return ret;
}
-static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std)
+static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std)
{
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
return pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std);
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), std);
}
static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std)
@@ -352,7 +352,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
return pvr2_hdw_get_tuner_status(hdw, vt);
}
-static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt)
{
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
@@ -365,7 +365,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
vt->audmode);
}
-static int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf)
{
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
@@ -815,7 +815,7 @@ static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_regist
return ret;
}
-static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+static int pvr2_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *req)
{
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 5ec15cb1ed26..77bbf7889659 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -1001,6 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
pdev->vb_queue.ops = &pwc_vb_queue_ops;
pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(&pdev->vb_queue);
if (rc < 0) {
PWC_ERROR("Oops, could not initialize vb2 queue.\n");
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 498c57ea5d32..ab97e7d0b4f2 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -43,12 +43,14 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/usb.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <linux/vmalloc.h>
-#include <linux/usb.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#define S2255_VERSION "1.22.1"
#define FIRMWARE_FILE_NAME "f2255usb.bin"
@@ -217,12 +219,15 @@ struct s2255_dev;
struct s2255_channel {
struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *jpegqual_ctrl;
int resources;
struct s2255_dmaqueue vidq;
struct s2255_bufferi buffer;
struct s2255_mode mode;
+ v4l2_std_id std;
/* jpeg compression */
- struct v4l2_jpegcompression jc;
+ unsigned jpegqual;
/* capture parameters (for high quality mode full size) */
struct v4l2_captureparm cap_parm;
int cur_frame;
@@ -292,6 +297,8 @@ struct s2255_buffer {
};
struct s2255_fh {
+ /* this must be the first field in this struct */
+ struct v4l2_fh fh;
struct s2255_dev *dev;
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
@@ -306,7 +313,7 @@ struct s2255_fh {
/* Need DSP version 5+ for video status feature */
#define S2255_MIN_DSP_STATUS 5
#define S2255_MIN_DSP_COLORFILTER 8
-#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC)
+#define S2255_NORMS (V4L2_STD_ALL)
/* private V4L2 controls */
@@ -336,7 +343,7 @@ struct s2255_fh {
*/
#define S2255_V4L2_YC_ON 1
#define S2255_V4L2_YC_OFF 0
-#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_S2255_COLORFILTER (V4L2_CID_USER_S2255_BASE + 0)
/* frame prefix size (sent once every frame) */
#define PREFIX_SIZE 512
@@ -409,11 +416,6 @@ MODULE_DEVICE_TABLE(usb, s2255_table);
/* JPEG formats must be defined last to support jpeg_enable parameter */
static const struct s2255_fmt formats[] = {
{
- .name = "4:2:2, planar, YUV422P",
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .depth = 16
-
- }, {
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16
@@ -423,6 +425,11 @@ static const struct s2255_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16
}, {
+ .name = "4:2:2, planar, YUV422P",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 16
+
+ }, {
.name = "8bpp GREY",
.fourcc = V4L2_PIX_FMT_GREY,
.depth = 8
@@ -437,27 +444,27 @@ static const struct s2255_fmt formats[] = {
}
};
-static int norm_maxw(struct video_device *vdev)
+static int norm_maxw(struct s2255_channel *channel)
{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
+ return (channel->std & V4L2_STD_525_60) ?
LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
}
-static int norm_maxh(struct video_device *vdev)
+static int norm_maxh(struct s2255_channel *channel)
{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
+ return (channel->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
}
-static int norm_minw(struct video_device *vdev)
+static int norm_minw(struct s2255_channel *channel)
{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
+ return (channel->std & V4L2_STD_525_60) ?
LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
}
-static int norm_minh(struct video_device *vdev)
+static int norm_minh(struct s2255_channel *channel)
{
- return (vdev->current_norm & V4L2_STD_NTSC) ?
+ return (channel->std & V4L2_STD_525_60) ?
(NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
}
@@ -515,7 +522,7 @@ static void s2255_timer(unsigned long user_data)
/* this loads the firmware asynchronously.
- Originally this was done synchroously in probe.
+ Originally this was done synchronously in probe.
But it is better to load it asynchronously here than block
inside the probe function. Blocking inside probe affects boot time.
FW loading is triggered by the timer in the probe function
@@ -719,10 +726,10 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
if (channel->fmt == NULL)
return -EINVAL;
- if ((w < norm_minw(&channel->vdev)) ||
- (w > norm_maxw(&channel->vdev)) ||
- (h < norm_minh(&channel->vdev)) ||
- (h > norm_maxh(&channel->vdev))) {
+ if ((w < norm_minw(channel)) ||
+ (w > norm_maxw(channel)) ||
+ (h < norm_minh(channel)) ||
+ (h > norm_maxh(channel))) {
dprintk(4, "invalid buffer prepare\n");
return -EINVAL;
}
@@ -810,37 +817,17 @@ static void res_free(struct s2255_fh *fh)
dprintk(1, "res: put\n");
}
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *qmenu)
-{
- static const char *colorfilter[] = {
- "Off",
- "On",
- NULL
- };
- if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) {
- int i;
- const char **menu_items = colorfilter;
- for (i = 0; i < qmenu->index && menu_items[i]; i++)
- ; /* do nothing (from v4l2-common.c) */
- if (menu_items[i] == NULL || menu_items[i][0] == '\0')
- return -EINVAL;
- strlcpy(qmenu->name, menu_items[qmenu->index],
- sizeof(qmenu->name));
- return 0;
- }
- return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev;
+
strlcpy(cap->driver, "s2255", sizeof(cap->driver));
strlcpy(cap->card, "s2255", sizeof(cap->card));
usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -865,13 +852,20 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_channel *channel = fh->channel;
+ int is_ntsc = channel->std & V4L2_STD_525_60;
f->fmt.pix.width = channel->width;
f->fmt.pix.height = channel->height;
- f->fmt.pix.field = fh->vb_vidq.field;
+ if (f->fmt.pix.height >=
+ (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ else
+ f->fmt.pix.field = V4L2_FIELD_TOP;
f->fmt.pix.pixelformat = channel->fmt->fourcc;
f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
return 0;
}
@@ -880,12 +874,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
const struct s2255_fmt *fmt;
enum v4l2_field field;
- int b_any_field = 0;
struct s2255_fh *fh = priv;
struct s2255_channel *channel = fh->channel;
- int is_ntsc;
- is_ntsc =
- (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
+ int is_ntsc = channel->std & V4L2_STD_525_60;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -893,8 +884,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
field = f->fmt.pix.field;
- if (field == V4L2_FIELD_ANY)
- b_any_field = 1;
dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n",
__func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height);
@@ -902,24 +891,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* NTSC */
if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) {
f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2;
- if (b_any_field) {
- field = V4L2_FIELD_SEQ_TB;
- } else if (!((field == V4L2_FIELD_INTERLACED) ||
- (field == V4L2_FIELD_SEQ_TB) ||
- (field == V4L2_FIELD_INTERLACED_TB))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
+ field = V4L2_FIELD_INTERLACED;
} else {
f->fmt.pix.height = NUM_LINES_1CIFS_NTSC;
- if (b_any_field) {
- field = V4L2_FIELD_TOP;
- } else if (!((field == V4L2_FIELD_TOP) ||
- (field == V4L2_FIELD_BOTTOM))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
-
+ field = V4L2_FIELD_TOP;
}
if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC)
f->fmt.pix.width = LINE_SZ_4CIFS_NTSC;
@@ -933,41 +908,25 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
/* PAL */
if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) {
f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2;
- if (b_any_field) {
- field = V4L2_FIELD_SEQ_TB;
- } else if (!((field == V4L2_FIELD_INTERLACED) ||
- (field == V4L2_FIELD_SEQ_TB) ||
- (field == V4L2_FIELD_INTERLACED_TB))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
+ field = V4L2_FIELD_INTERLACED;
} else {
f->fmt.pix.height = NUM_LINES_1CIFS_PAL;
- if (b_any_field) {
- field = V4L2_FIELD_TOP;
- } else if (!((field == V4L2_FIELD_TOP) ||
- (field == V4L2_FIELD_BOTTOM))) {
- dprintk(1, "unsupported field setting\n");
- return -EINVAL;
- }
+ field = V4L2_FIELD_TOP;
}
- if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) {
+ if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL)
f->fmt.pix.width = LINE_SZ_4CIFS_PAL;
- field = V4L2_FIELD_SEQ_TB;
- } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) {
+ else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL)
f->fmt.pix.width = LINE_SZ_2CIFS_PAL;
- field = V4L2_FIELD_TOP;
- } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) {
+ else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL)
f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
- field = V4L2_FIELD_TOP;
- } else {
+ else
f->fmt.pix.width = LINE_SZ_1CIFS_PAL;
- field = V4L2_FIELD_TOP;
- }
}
f->fmt.pix.field = field;
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
dprintk(50, "%s: set width %d height %d field %d\n", __func__,
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
return 0;
@@ -1012,8 +971,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
channel->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
- if (channel->width > norm_minw(&channel->vdev)) {
- if (channel->height > norm_minh(&channel->vdev)) {
+ if (channel->width > norm_minw(channel)) {
+ if (channel->height > norm_minh(channel)) {
if (channel->cap_parm.capturemode &
V4L2_MODE_HIGHQUALITY)
mode.scale = SCALE_4CIFSI;
@@ -1035,7 +994,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
case V4L2_PIX_FMT_MJPEG:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_JPG;
- mode.color |= (channel->jc.quality << 8);
+ mode.color |= (channel->jpegqual << 8);
break;
case V4L2_PIX_FMT_YUV422P:
mode.color &= ~MASK_COLOR;
@@ -1198,6 +1157,8 @@ static int s2255_set_mode(struct s2255_channel *channel,
__le32 *buffer;
unsigned long chn_rev;
struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ int i;
+
chn_rev = G_chnmap[channel->idx];
dprintk(3, "%s channel: %d\n", __func__, channel->idx);
/* if JPEG, set the quality */
@@ -1205,7 +1166,7 @@ static int s2255_set_mode(struct s2255_channel *channel,
mode->color &= ~MASK_COLOR;
mode->color |= COLOR_JPG;
mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (channel->jc.quality << 8);
+ mode->color |= (channel->jpegqual << 8);
}
/* save the mode */
channel->mode = *mode;
@@ -1220,7 +1181,8 @@ static int s2255_set_mode(struct s2255_channel *channel,
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_SET_MODE;
- memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+ for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++)
+ buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]);
channel->setmode_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (debug)
@@ -1332,12 +1294,14 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
{
struct s2255_fh *fh = priv;
struct s2255_mode mode;
struct videobuf_queue *q = &fh->vb_vidq;
+ struct s2255_channel *channel = fh->channel;
int ret = 0;
+
mutex_lock(&q->vb_lock);
if (videobuf_queue_is_busy(q)) {
dprintk(1, "queue busy\n");
@@ -1350,24 +1314,30 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
goto out_s_std;
}
mode = fh->channel->mode;
- if (*i & V4L2_STD_NTSC) {
- dprintk(4, "%s NTSC\n", __func__);
+ if (i & V4L2_STD_525_60) {
+ dprintk(4, "%s 60 Hz\n", __func__);
/* if changing format, reset frame decimation/intervals */
if (mode.format != FORMAT_NTSC) {
mode.restart = 1;
mode.format = FORMAT_NTSC;
mode.fdec = FDEC_1;
+ channel->width = LINE_SZ_4CIFS_NTSC;
+ channel->height = NUM_LINES_4CIFS_NTSC * 2;
}
- } else if (*i & V4L2_STD_PAL) {
- dprintk(4, "%s PAL\n", __func__);
+ } else if (i & V4L2_STD_625_50) {
+ dprintk(4, "%s 50 Hz\n", __func__);
if (mode.format != FORMAT_PAL) {
mode.restart = 1;
mode.format = FORMAT_PAL;
mode.fdec = FDEC_1;
+ channel->width = LINE_SZ_4CIFS_PAL;
+ channel->height = NUM_LINES_4CIFS_PAL * 2;
}
} else {
ret = -EINVAL;
+ goto out_s_std;
}
+ fh->channel->std = i;
if (mode.restart)
s2255_set_mode(fh->channel, &mode);
out_s_std:
@@ -1375,6 +1345,14 @@ out_s_std:
return ret;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ struct s2255_fh *fh = priv;
+
+ *i = fh->channel->std;
+ return 0;
+}
+
/* Sensoray 2255 is a multiple channel capture device.
It does not have a "crossbar" of inputs.
We use one V4L device per channel. The user must
@@ -1427,110 +1405,36 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-/* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dev *dev = fh->dev;
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT);
- break;
- case V4L2_CID_CONTRAST:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST);
- break;
- case V4L2_CID_SATURATION:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION);
- break;
- case V4L2_CID_HUE:
- v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE);
- break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
- strlcpy(qc->name, "Color Filter", sizeof(qc->name));
- qc->type = V4L2_CTRL_TYPE_MENU;
- qc->minimum = 0;
- qc->maximum = 1;
- qc->step = 1;
- qc->default_value = 1;
- qc->flags = 0;
- break;
- default:
- return -EINVAL;
- }
- dprintk(4, "%s, id %d\n", __func__, qc->id);
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_channel *channel = fh->channel;
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = channel->mode.bright;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = channel->mode.contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = channel->mode.saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = channel->mode.hue;
- break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
- ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
- break;
- default:
- return -EINVAL;
- }
- dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int s2255_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct s2255_fh *fh = priv;
- struct s2255_channel *channel = fh->channel;
- struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_channel *channel =
+ container_of(ctrl->handler, struct s2255_channel, hdl);
struct s2255_mode mode;
+
mode = channel->mode;
dprintk(4, "%s\n", __func__);
+
/* update the mode to the corresponding value */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- mode.bright = ctrl->value;
+ mode.bright = ctrl->val;
break;
case V4L2_CID_CONTRAST:
- mode.contrast = ctrl->value;
+ mode.contrast = ctrl->val;
break;
case V4L2_CID_HUE:
- mode.hue = ctrl->value;
+ mode.hue = ctrl->val;
break;
case V4L2_CID_SATURATION:
- mode.saturation = ctrl->value;
+ mode.saturation = ctrl->val;
break;
- case V4L2_CID_PRIVATE_COLORFILTER:
- if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
- return -EINVAL;
- if ((dev->pid == 0x2257) && (channel->idx > 1))
- return -EINVAL;
+ case V4L2_CID_S2255_COLORFILTER:
mode.color &= ~MASK_INPUT_TYPE;
- mode.color |= ((ctrl->value ? 0 : 1) << 16);
+ mode.color |= !ctrl->val << 16;
break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ channel->jpegqual = ctrl->val;
+ return 0;
default:
return -EINVAL;
}
@@ -1539,7 +1443,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
some V4L programs restart stream unnecessarily
after a s_crtl.
*/
- s2255_set_mode(fh->channel, &mode);
+ s2255_set_mode(channel, &mode);
return 0;
}
@@ -1548,7 +1452,9 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_channel *channel = fh->channel;
- *jc = channel->jc;
+
+ memset(jc, 0, sizeof(*jc));
+ jc->quality = channel->jpegqual;
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1560,7 +1466,7 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct s2255_channel *channel = fh->channel;
if (jc->quality < 0 || jc->quality > 100)
return -EINVAL;
- channel->jc.quality = jc->quality;
+ v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality);
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1573,7 +1479,6 @@ static int vidioc_g_parm(struct file *file, void *priv,
struct s2255_channel *channel = fh->channel;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- memset(sp, 0, sizeof(struct v4l2_streamparm));
sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
sp->parm.capture.capturemode = channel->cap_parm.capturemode;
def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
@@ -1643,36 +1548,64 @@ static int vidioc_s_parm(struct file *file, void *priv,
return 0;
}
+#define NUM_SIZE_ENUMS 3
+static const struct v4l2_frmsize_discrete ntsc_sizes[] = {
+ { 640, 480 },
+ { 640, 240 },
+ { 320, 240 },
+};
+static const struct v4l2_frmsize_discrete pal_sizes[] = {
+ { 704, 576 },
+ { 704, 288 },
+ { 352, 288 },
+};
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fe)
+{
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ int is_ntsc = channel->std & V4L2_STD_525_60;
+ const struct s2255_fmt *fmt;
+
+ if (fe->index >= NUM_SIZE_ENUMS)
+ return -EINVAL;
+
+ fmt = format_by_fourcc(fe->pixel_format);
+ if (fmt == NULL)
+ return -EINVAL;
+ fe->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fe->discrete = is_ntsc ? ntsc_sizes[fe->index] : pal_sizes[fe->index];
+ return 0;
+}
+
static int vidioc_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fe)
{
- int is_ntsc = 0;
+ struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
+ const struct s2255_fmt *fmt;
+ const struct v4l2_frmsize_discrete *sizes;
+ int is_ntsc = channel->std & V4L2_STD_525_60;
#define NUM_FRAME_ENUMS 4
int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5};
+ int i;
+
if (fe->index >= NUM_FRAME_ENUMS)
return -EINVAL;
- switch (fe->width) {
- case 640:
- if (fe->height != 240 && fe->height != 480)
- return -EINVAL;
- is_ntsc = 1;
- break;
- case 320:
- if (fe->height != 240)
- return -EINVAL;
- is_ntsc = 1;
- break;
- case 704:
- if (fe->height != 288 && fe->height != 576)
- return -EINVAL;
- break;
- case 352:
- if (fe->height != 288)
- return -EINVAL;
- break;
- default:
+
+ fmt = format_by_fourcc(fe->pixel_format);
+ if (fmt == NULL)
return -EINVAL;
- }
+
+ sizes = is_ntsc ? ntsc_sizes : pal_sizes;
+ for (i = 0; i < NUM_SIZE_ENUMS; i++, sizes++)
+ if (fe->width == sizes->width &&
+ fe->height == sizes->height)
+ break;
+ if (i == NUM_SIZE_ENUMS)
+ return -EINVAL;
+
fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fe->discrete.denominator = is_ntsc ? 30000 : 25000;
fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index];
@@ -1757,7 +1690,9 @@ static int __s2255_open(struct file *file)
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
- file->private_data = fh;
+ v4l2_fh_init(&fh->fh, vdev);
+ v4l2_fh_add(&fh->fh);
+ file->private_data = &fh->fh;
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->channel = channel;
@@ -1800,12 +1735,13 @@ static unsigned int s2255_poll(struct file *file,
{
struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev;
- int rc;
+ int rc = v4l2_ctrl_poll(file, wait);
+
dprintk(100, "%s\n", __func__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
mutex_lock(&dev->lock);
- rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
+ rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait);
mutex_unlock(&dev->lock);
return rc;
}
@@ -1852,6 +1788,8 @@ static int s2255_release(struct file *file)
videobuf_mmap_free(&fh->vb_vidq);
mutex_unlock(&dev->lock);
dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
kfree(fh);
return 0;
}
@@ -1886,7 +1824,6 @@ static const struct v4l2_file_operations s2255_fops_v4l = {
};
static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
- .vidioc_querymenu = vidioc_querymenu,
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
@@ -1897,26 +1834,33 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_g_parm = vidioc_g_parm,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static void s2255_video_device_release(struct video_device *vdev)
{
struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
- dprintk(4, "%s, chnls: %d \n", __func__,
+ struct s2255_channel *channel =
+ container_of(vdev, struct s2255_channel, vdev);
+
+ v4l2_ctrl_handler_free(&channel->hdl);
+ dprintk(4, "%s, chnls: %d\n", __func__,
atomic_read(&dev->num_channels));
+
if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
@@ -1928,7 +1872,20 @@ static struct video_device template = {
.ioctl_ops = &s2255_ioctl_ops,
.release = s2255_video_device_release,
.tvnorms = S2255_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
+};
+
+static const struct v4l2_ctrl_ops s2255_ctrl_ops = {
+ .s_ctrl = s2255_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config color_filter_ctrl = {
+ .ops = &s2255_ctrl_ops,
+ .name = "Color Filter",
+ .id = V4L2_CID_S2255_COLORFILTER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .step = 1,
+ .def = 1,
};
static int s2255_probe_v4l(struct s2255_dev *dev)
@@ -1945,11 +1902,36 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
for (i = 0; i < MAX_CHANNELS; i++) {
channel = &dev->channel[i];
INIT_LIST_HEAD(&channel->vidq.active);
+
+ v4l2_ctrl_handler_init(&channel->hdl, 6);
+ v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT);
+ v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST);
+ v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION);
+ v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops,
+ V4L2_CID_HUE, 0, 255, 1, DEF_HUE);
+ channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl,
+ &s2255_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ 0, 100, 1, S2255_DEF_JPEG_QUAL);
+ if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER &&
+ (dev->pid != 0x2257 || channel->idx <= 1))
+ v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL);
+ if (channel->hdl.error) {
+ ret = channel->hdl.error;
+ v4l2_ctrl_handler_free(&channel->hdl);
+ dev_err(&dev->udev->dev, "couldn't register control\n");
+ break;
+ }
channel->vidq.dev = dev;
/* register 4 video devices */
channel->vdev = template;
+ channel->vdev.ctrl_handler = &channel->hdl;
channel->vdev.lock = &dev->lock;
channel->vdev.v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags);
video_set_drvdata(&channel->vdev, channel);
if (video_nr == -1)
ret = video_register_device(&channel->vdev,
@@ -2300,9 +2282,10 @@ static int s2255_board_init(struct s2255_dev *dev)
channel->mode = mode_def;
if (dev->pid == 0x2257 && j > 1)
channel->mode.color |= (1 << 16);
- channel->jc.quality = S2255_DEF_JPEG_QUAL;
+ channel->jpegqual = S2255_DEF_JPEG_QUAL;
channel->width = LINE_SZ_4CIFS_NTSC;
channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ channel->std = V4L2_STD_NTSC_M;
channel->fmt = &formats[0];
channel->mode.restart = 1;
channel->req_image_size = get_transfer_size(&mode_def);
@@ -2531,7 +2514,7 @@ static int s2255_probe(struct usb_interface *interface,
return -ENOMEM;
}
atomic_set(&dev->num_channels, 0);
- dev->pid = id->idProduct;
+ dev->pid = le16_to_cpu(id->idProduct);
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
goto errorFWDATA1;
@@ -2601,7 +2584,7 @@ static int s2255_probe(struct usb_interface *interface,
/* make sure firmware is the latest */
__le32 *pRel;
pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4];
- printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel);
+ printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel));
dev->dsp_fw_ver = le32_to_cpu(*pRel);
if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER)
printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index de2c10289eec..03761c6f472f 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -35,16 +35,23 @@ module_param_named(debug, sms_dbg, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
#define USB1_BUFFER_SIZE 0x1000
-#define USB2_BUFFER_SIZE 0x4000
+#define USB2_BUFFER_SIZE 0x2000
#define MAX_BUFFERS 50
#define MAX_URBS 10
struct smsusb_device_t;
+enum smsusb_state {
+ SMSUSB_DISCONNECTED,
+ SMSUSB_SUSPENDED,
+ SMSUSB_ACTIVE
+};
+
struct smsusb_urb_t {
+ struct list_head entry;
struct smscore_buffer_t *cb;
- struct smsusb_device_t *dev;
+ struct smsusb_device_t *dev;
struct urb urb;
};
@@ -57,11 +64,23 @@ struct smsusb_device_t {
int response_alignment;
int buffer_size;
+
+ unsigned char in_ep;
+ unsigned char out_ep;
+ enum smsusb_state state;
};
static int smsusb_submit_urb(struct smsusb_device_t *dev,
struct smsusb_urb_t *surb);
+/**
+ * Completing URB's callback handler - top half (interrupt context)
+ * adds completing sms urb to the global surbs list and activtes the worker
+ * thread the surb
+ * IMPORTANT - blocking functions must not be called from here !!!
+
+ * @param urb pointer to a completing urb object
+ */
static void smsusb_onresponse(struct urb *urb)
{
struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
@@ -74,26 +93,26 @@ static void smsusb_onresponse(struct urb *urb)
}
if ((urb->actual_length > 0) && (urb->status == 0)) {
- struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p;
smsendian_handle_message_header(phdr);
- if (urb->actual_length >= phdr->msgLength) {
- surb->cb->size = phdr->msgLength;
+ if (urb->actual_length >= phdr->msg_length) {
+ surb->cb->size = phdr->msg_length;
if (dev->response_alignment &&
- (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
+ (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) {
surb->cb->offset =
dev->response_alignment +
- ((phdr->msgFlags >> 8) & 3);
+ ((phdr->msg_flags >> 8) & 3);
/* sanity check */
- if (((int) phdr->msgLength +
+ if (((int) phdr->msg_length +
surb->cb->offset) > urb->actual_length) {
sms_err("invalid response "
"msglen %d offset %d "
"size %d",
- phdr->msgLength,
+ phdr->msg_length,
surb->cb->offset,
urb->actual_length);
goto exit_and_resubmit;
@@ -102,16 +121,22 @@ static void smsusb_onresponse(struct urb *urb)
/* move buffer pointer and
* copy header to its new location */
memcpy((char *) phdr + surb->cb->offset,
- phdr, sizeof(struct SmsMsgHdr_ST));
+ phdr, sizeof(struct sms_msg_hdr));
} else
surb->cb->offset = 0;
+ sms_debug("received %s(%d) size: %d",
+ smscore_translate_msg(phdr->msg_type),
+ phdr->msg_type, phdr->msg_length);
+
+ smsendian_handle_rx_message((struct sms_msg_data *) phdr);
+
smscore_onresponse(dev->coredev, surb->cb);
surb->cb = NULL;
} else {
sms_err("invalid response "
"msglen %d actual %d",
- phdr->msgLength, urb->actual_length);
+ phdr->msg_length, urb->actual_length);
}
} else
sms_err("error, urb status %d, %d bytes",
@@ -136,7 +161,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev,
usb_fill_bulk_urb(
&surb->urb,
dev->udev,
- usb_rcvbulkpipe(dev->udev, 0x81),
+ usb_rcvbulkpipe(dev->udev, dev->in_ep),
surb->cb->p,
dev->buffer_size,
smsusb_onresponse,
@@ -181,9 +206,18 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev)
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
{
struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
+ struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
int dummy;
- smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
+ if (dev->state != SMSUSB_ACTIVE)
+ return -ENOENT;
+
+ sms_debug("sending %s(%d) size: %d",
+ smscore_translate_msg(phdr->msg_type), phdr->msg_type,
+ phdr->msg_length);
+
+ smsendian_handle_tx_message((struct sms_msg_data *) phdr);
+ smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
buffer, size, &dummy, 1000);
}
@@ -276,15 +310,15 @@ static void smsusb1_detectmode(void *context, int *mode)
static int smsusb1_setmode(void *context, int mode)
{
- struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
- sizeof(struct SmsMsgHdr_ST), 0 };
+ struct sms_msg_hdr msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
+ sizeof(struct sms_msg_hdr), 0 };
if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
sms_err("invalid firmware id specified %d", mode);
return -EINVAL;
}
- return smsusb_sendrequest(context, &Msg, sizeof(Msg));
+ return smsusb_sendrequest(context, &msg, sizeof(msg));
}
static void smsusb_term_device(struct usb_interface *intf)
@@ -292,13 +326,15 @@ static void smsusb_term_device(struct usb_interface *intf)
struct smsusb_device_t *dev = usb_get_intfdata(intf);
if (dev) {
+ dev->state = SMSUSB_DISCONNECTED;
+
smsusb_stop_streaming(dev);
/* unregister from smscore */
if (dev->coredev)
smscore_unregister_device(dev->coredev);
- sms_info("device %p destroyed", dev);
+ sms_info("device 0x%p destroyed", dev);
kfree(dev);
}
@@ -321,6 +357,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
memset(&params, 0, sizeof(params));
usb_set_intfdata(intf, dev);
dev->udev = interface_to_usbdev(intf);
+ dev->state = SMSUSB_DISCONNECTED;
params.device_type = sms_get_board(board_id)->type;
@@ -331,21 +368,29 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
params.setmode_handler = smsusb1_setmode;
params.detectmode_handler = smsusb1_detectmode;
break;
- default:
+ case SMS_UNKNOWN_TYPE:
sms_err("Unspecified sms device type!");
/* fall-thru */
- case SMS_NOVA_A0:
- case SMS_NOVA_B0:
- case SMS_VEGA:
+ default:
dev->buffer_size = USB2_BUFFER_SIZE;
dev->response_alignment =
le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
- sizeof(struct SmsMsgHdr_ST);
+ sizeof(struct sms_msg_hdr);
params.flags |= SMS_DEVICE_FAMILY2;
break;
}
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+ if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN)
+ dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
+ else
+ dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress;
+ }
+
+ sms_info("in_ep = %02x, out_ep = %02x",
+ dev->in_ep, dev->out_ep);
+
params.device = &dev->udev->dev;
params.buffer_size = dev->buffer_size;
params.num_buffers = MAX_BUFFERS;
@@ -363,6 +408,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
smscore_set_board_id(dev->coredev, board_id);
+ dev->coredev->is_usb_device = true;
+
/* initialize urbs */
for (i = 0; i < MAX_URBS; i++) {
dev->surbs[i].dev = dev;
@@ -377,6 +424,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
return rc;
}
+ dev->state = SMSUSB_ACTIVE;
+
rc = smscore_start_device(dev->coredev);
if (rc < 0) {
sms_err("smscore_start_device(...) failed");
@@ -384,7 +433,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
return rc;
}
- sms_info("device %p created", dev);
+ sms_info("device 0x%p created", dev);
return rc;
}
@@ -396,12 +445,21 @@ static int smsusb_probe(struct usb_interface *intf,
char devpath[32];
int i, rc;
- rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
- rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+ sms_info("interface number %d",
+ intf->cur_altsetting->desc.bInterfaceNumber);
- if (intf->num_altsetting > 0) {
- rc = usb_set_interface(
- udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
+ if (sms_get_board(id->driver_info)->intf_num !=
+ intf->cur_altsetting->desc.bInterfaceNumber) {
+ sms_err("interface number is %d expecting %d",
+ sms_get_board(id->driver_info)->intf_num,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ return -ENODEV;
+ }
+
+ if (intf->num_altsetting > 1) {
+ rc = usb_set_interface(udev,
+ intf->cur_altsetting->desc.bInterfaceNumber,
+ 0);
if (rc < 0) {
sms_err("usb_set_interface failed, rc %d", rc);
return rc;
@@ -410,19 +468,27 @@ static int smsusb_probe(struct usb_interface *intf,
sms_info("smsusb_probe %d",
intf->cur_altsetting->desc.bInterfaceNumber);
- for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
sms_info("endpoint %d %02x %02x %d", i,
intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
intf->cur_altsetting->endpoint[i].desc.bmAttributes,
intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
-
+ if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress &
+ USB_DIR_IN)
+ rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev,
+ intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
+ else
+ rc = usb_clear_halt(udev, usb_sndbulkpipe(udev,
+ intf->cur_altsetting->endpoint[i].desc.bEndpointAddress));
+ }
if ((udev->actconfig->desc.bNumInterfaces == 2) &&
(intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
sms_err("rom interface 0 is not used");
return -ENODEV;
}
- if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+ if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) {
+ sms_info("stellar device was found.");
snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
udev->bus->busnum, udev->devpath);
sms_info("stellar device was found.");
@@ -445,7 +511,9 @@ static void smsusb_disconnect(struct usb_interface *intf)
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
struct smsusb_device_t *dev = usb_get_intfdata(intf);
- printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
+ printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event);
+ dev->state = SMSUSB_SUSPENDED;
+ /*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/
smsusb_stop_streaming(dev);
return 0;
}
@@ -456,9 +524,9 @@ static int smsusb_resume(struct usb_interface *intf)
struct smsusb_device_t *dev = usb_get_intfdata(intf);
struct usb_device *udev = interface_to_usbdev(intf);
- printk(KERN_INFO "%s: Entering.\n", __func__);
- usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
- usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
+ printk(KERN_INFO "%s Entering.\n", __func__);
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, dev->in_ep));
+ usb_clear_halt(udev, usb_sndbulkpipe(udev, dev->out_ep));
for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
@@ -546,6 +614,26 @@ static const struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0xf5a0),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x187f, 0x0202),
+ .driver_info = SMS1XXX_BOARD_SIANO_NICE },
+ { USB_DEVICE(0x187f, 0x0301),
+ .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+ { USB_DEVICE(0x187f, 0x0302),
+ .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+ { USB_DEVICE(0x187f, 0x0310),
+ .driver_info = SMS1XXX_BOARD_SIANO_MING },
+ { USB_DEVICE(0x187f, 0x0500),
+ .driver_info = SMS1XXX_BOARD_SIANO_PELE },
+ { USB_DEVICE(0x187f, 0x0600),
+ .driver_info = SMS1XXX_BOARD_SIANO_RIO },
+ { USB_DEVICE(0x187f, 0x0700),
+ .driver_info = SMS1XXX_BOARD_SIANO_DENVER_2160 },
+ { USB_DEVICE(0x187f, 0x0800),
+ .driver_info = SMS1XXX_BOARD_SIANO_DENVER_1530 },
+ { USB_DEVICE(0x19D2, 0x0086),
+ .driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD },
+ { USB_DEVICE(0x19D2, 0x0078),
+ .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD },
{ } /* Terminating entry */
};
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 6694f9e2ca57..a59153d2f8bf 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -375,7 +375,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
struct stk1160 *dev = video_drvdata(file);
struct vb2_queue *q = &dev->vb_vidq;
@@ -388,7 +388,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
return -ENODEV;
/* We need to set this now, before we call stk1160_set_std */
- dev->norm = *norm;
+ dev->norm = norm;
/* This is taken from saa7115 video decoder */
if (dev->norm & V4L2_STD_525_60) {
@@ -458,7 +458,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
switch (chip->match.type) {
- case V4L2_CHIP_MATCH_HOST:
+ case V4L2_CHIP_MATCH_BRIDGE:
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
return 0;
@@ -476,9 +476,6 @@ static int vidioc_g_register(struct file *file, void *priv,
u8 val;
switch (reg->match.type) {
- case V4L2_CHIP_MATCH_AC97:
- /* TODO: Support me please :-( */
- return -EINVAL;
case V4L2_CHIP_MATCH_I2C_DRIVER:
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
return 0;
@@ -500,13 +497,11 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct stk1160 *dev = video_drvdata(file);
switch (reg->match.type) {
- case V4L2_CHIP_MATCH_AC97:
- return -EINVAL;
case V4L2_CHIP_MATCH_I2C_DRIVER:
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
return 0;
@@ -687,6 +682,7 @@ int stk1160_vb2_setup(struct stk1160 *dev)
q->buf_struct_size = sizeof(struct stk1160_buffer);
q->ops = &stk1160_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
rc = vb2_queue_init(q);
if (rc < 0)
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index 4cbab085e348..c43c8d32be40 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -35,6 +35,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include "stk-webcam.h"
@@ -63,7 +64,39 @@ static struct usb_device_id stkwebcam_table[] = {
};
MODULE_DEVICE_TABLE(usb, stkwebcam_table);
-/* The stk webcam laptop module is mounted upside down in some laptops :( */
+/*
+ * The stk webcam laptop module is mounted upside down in some laptops :(
+ *
+ * Some background information (thanks to Hans de Goede for providing this):
+ *
+ * 1) Once upon a time the stkwebcam driver was written
+ *
+ * 2) The webcam in question was used mostly in Asus laptop models, including
+ * the laptop of the original author of the driver, and in these models, in
+ * typical Asus fashion (see the long long list for uvc cams inside v4l-utils),
+ * they mounted the webcam-module the wrong way up. So the hflip and vflip
+ * module options were given a default value of 1 (the correct value for
+ * upside down mounted models)
+ *
+ * 3) Years later I got a bug report from a user with a laptop with stkwebcam,
+ * where the module was actually mounted the right way up, and thus showed
+ * upside down under Linux. So now I was facing the choice of 2 options:
+ *
+ * a) Add a not-upside-down list to stkwebcam, which overrules the default.
+ *
+ * b) Do it like all the other drivers do, and make the default right for
+ * cams mounted the proper way and add an upside-down model list, with
+ * models where we need to flip-by-default.
+ *
+ * Despite knowing that going b) would cause a period of pain where we were
+ * building the table I opted to go for option b), since a) is just too ugly,
+ * and worse different from how every other driver does it leading to
+ * confusion in the long run. This change was made in kernel 3.6.
+ *
+ * So for any user report about upside-down images since kernel 3.6 ask them
+ * to provide the output of 'sudo dmidecode' so the laptop can be added in
+ * the table below.
+ */
static const struct dmi_system_id stk_upside_down_dmi_table[] = {
{
.ident = "ASUS G1",
@@ -71,6 +104,12 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G1")
}
+ }, {
+ .ident = "ASUS F3JC",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
+ }
},
{}
};
@@ -565,31 +604,31 @@ static void stk_free_buffers(struct stk_camera *dev)
static int v4l_stk_open(struct file *fp)
{
- static int first_init = 1; /* webcam LED management */
- struct stk_camera *dev;
- struct video_device *vdev;
-
- vdev = video_devdata(fp);
- dev = vdev_to_camera(vdev);
+ struct stk_camera *dev = video_drvdata(fp);
+ int err;
if (dev == NULL || !is_present(dev))
return -ENXIO;
- if (!first_init)
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ if (!dev->first_init)
stk_camera_write_reg(dev, 0x0, 0x24);
else
- first_init = 0;
-
- fp->private_data = dev;
- usb_autopm_get_interface(dev->interface);
+ dev->first_init = 0;
- return 0;
+ err = v4l2_fh_open(fp);
+ if (!err)
+ usb_autopm_get_interface(dev->interface);
+ mutex_unlock(&dev->lock);
+ return err;
}
static int v4l_stk_release(struct file *fp)
{
- struct stk_camera *dev = fp->private_data;
+ struct stk_camera *dev = video_drvdata(fp);
+ mutex_lock(&dev->lock);
if (dev->owner == fp) {
stk_stop_stream(dev);
stk_free_buffers(dev);
@@ -600,22 +639,22 @@ static int v4l_stk_release(struct file *fp)
if (is_present(dev))
usb_autopm_put_interface(dev->interface);
-
- return 0;
+ mutex_unlock(&dev->lock);
+ return v4l2_fh_release(fp);
}
-static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
+static ssize_t stk_read(struct file *fp, char __user *buf,
size_t count, loff_t *f_pos)
{
int i;
int ret;
unsigned long flags;
struct stk_sio_buffer *sbuf;
- struct stk_camera *dev = fp->private_data;
+ struct stk_camera *dev = video_drvdata(fp);
if (!is_present(dev))
return -EIO;
- if (dev->owner && dev->owner != fp)
+ if (dev->owner && (!dev->reading || dev->owner != fp))
return -EBUSY;
dev->owner = fp;
if (!is_streaming(dev)) {
@@ -623,6 +662,7 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
|| stk_allocate_buffers(dev, 3)
|| stk_start_stream(dev))
return -ENOMEM;
+ dev->reading = 1;
spin_lock_irqsave(&dev->spinlock, flags);
for (i = 0; i < dev->n_sbufs; i++) {
list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
@@ -665,9 +705,23 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
return count;
}
+static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct stk_camera *dev = video_drvdata(fp);
+ int ret;
+
+ if (mutex_lock_interruptible(&dev->lock))
+ return -ERESTARTSYS;
+ ret = stk_read(fp, buf, count, f_pos);
+ mutex_unlock(&dev->lock);
+ return ret;
+}
+
static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
{
- struct stk_camera *dev = fp->private_data;
+ struct stk_camera *dev = video_drvdata(fp);
+ unsigned res = v4l2_ctrl_poll(fp, wait);
poll_wait(fp, &dev->wait_frame, wait);
@@ -675,9 +729,9 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
return POLLERR;
if (!list_empty(&dev->sio_full))
- return POLLIN | POLLRDNORM;
+ return res | POLLIN | POLLRDNORM;
- return 0;
+ return res;
}
@@ -703,7 +757,7 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
unsigned int i;
int ret;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- struct stk_camera *dev = fp->private_data;
+ struct stk_camera *dev = video_drvdata(fp);
struct stk_sio_buffer *sbuf = NULL;
if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
@@ -733,12 +787,15 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
static int stk_vidioc_querycap(struct file *filp,
void *priv, struct v4l2_capability *cap)
{
+ struct stk_camera *dev = video_drvdata(filp);
+
strcpy(cap->driver, "stk");
strcpy(cap->card, "stk");
- cap->version = DRIVER_VERSION_NUM;
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -762,111 +819,28 @@ static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
{
- if (i != 0)
- return -EINVAL;
- else
- return 0;
-}
-
-/* from vivi.c */
-static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
-{
- return 0;
-}
-
-/* List of all V4Lv2 controls supported by the driver */
-static struct v4l2_queryctrl stk_controls[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0xffff,
- .step = 0x0100,
- .default_value = 0x6000,
- },
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Horizontal Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
-};
-
-static int stk_vidioc_queryctrl(struct file *filp,
- void *priv, struct v4l2_queryctrl *c)
-{
- int i;
- int nbr;
- nbr = ARRAY_SIZE(stk_controls);
-
- for (i = 0; i < nbr; i++) {
- if (stk_controls[i].id == c->id) {
- memcpy(c, &stk_controls[i],
- sizeof(struct v4l2_queryctrl));
- return 0;
- }
- }
- return -EINVAL;
+ return i ? -EINVAL : 0;
}
-static int stk_vidioc_g_ctrl(struct file *filp,
- void *priv, struct v4l2_control *c)
+static int stk_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct stk_camera *dev = priv;
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = dev->vsettings.brightness;
- break;
- case V4L2_CID_HFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- c->value = !dev->vsettings.hflip;
- else
- c->value = dev->vsettings.hflip;
- break;
- case V4L2_CID_VFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- c->value = !dev->vsettings.vflip;
- else
- c->value = dev->vsettings.vflip;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
+ struct stk_camera *dev =
+ container_of(ctrl->handler, struct stk_camera, hdl);
-static int stk_vidioc_s_ctrl(struct file *filp,
- void *priv, struct v4l2_control *c)
-{
- struct stk_camera *dev = priv;
- switch (c->id) {
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- dev->vsettings.brightness = c->value;
- return stk_sensor_set_brightness(dev, c->value >> 8);
+ return stk_sensor_set_brightness(dev, ctrl->val);
case V4L2_CID_HFLIP:
if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.hflip = !c->value;
+ dev->vsettings.hflip = !ctrl->val;
else
- dev->vsettings.hflip = c->value;
+ dev->vsettings.hflip = ctrl->val;
return 0;
case V4L2_CID_VFLIP:
if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.vflip = !c->value;
+ dev->vsettings.vflip = !ctrl->val;
else
- dev->vsettings.vflip = c->value;
+ dev->vsettings.vflip = ctrl->val;
return 0;
default:
return -EINVAL;
@@ -921,7 +895,7 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_format *f)
{
struct v4l2_pix_format *pix_format = &f->fmt.pix;
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
int i;
for (i = 0; i < ARRAY_SIZE(stk_sizes) &&
@@ -942,11 +916,12 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
pix_format->bytesperline = 2 * pix_format->width;
pix_format->sizeimage = pix_format->bytesperline
* pix_format->height;
+ pix_format->priv = 0;
return 0;
}
-static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *fmtd)
+static int stk_try_fmt_vid_cap(struct file *filp,
+ struct v4l2_format *fmtd, int *idx)
{
int i;
switch (fmtd->fmt.pix.pixelformat) {
@@ -968,11 +943,13 @@ static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
< abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
fmtd->fmt.pix.height = stk_sizes[i-1].h;
fmtd->fmt.pix.width = stk_sizes[i-1].w;
- fmtd->fmt.pix.priv = i - 1;
+ if (idx)
+ *idx = i - 1;
} else {
fmtd->fmt.pix.height = stk_sizes[i].h;
fmtd->fmt.pix.width = stk_sizes[i].w;
- fmtd->fmt.pix.priv = i;
+ if (idx)
+ *idx = i;
}
fmtd->fmt.pix.field = V4L2_FIELD_NONE;
@@ -983,9 +960,16 @@ static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
* fmtd->fmt.pix.height;
+ fmtd->fmt.pix.priv = 0;
return 0;
}
+static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
+ void *priv, struct v4l2_format *fmtd)
+{
+ return stk_try_fmt_vid_cap(filp, fmtd, NULL);
+}
+
static int stk_setup_format(struct stk_camera *dev)
{
int i = 0;
@@ -1026,7 +1010,8 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_format *fmtd)
{
int ret;
- struct stk_camera *dev = priv;
+ int idx;
+ struct stk_camera *dev = video_drvdata(filp);
if (dev == NULL)
return -ENODEV;
@@ -1034,17 +1019,16 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
return -ENODEV;
if (is_streaming(dev))
return -EBUSY;
- if (dev->owner && dev->owner != filp)
+ if (dev->owner)
return -EBUSY;
- ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd);
+ ret = stk_try_fmt_vid_cap(filp, fmtd, &idx);
if (ret)
return ret;
- dev->owner = filp;
dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
stk_free_buffers(dev);
dev->frame_size = fmtd->fmt.pix.sizeimage;
- dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m;
+ dev->vsettings.mode = stk_sizes[idx].m;
stk_initialise(dev);
return stk_setup_format(dev);
@@ -1053,7 +1037,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
static int stk_vidioc_reqbufs(struct file *filp,
void *priv, struct v4l2_requestbuffers *rb)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
if (dev == NULL)
return -ENODEV;
@@ -1062,6 +1046,13 @@ static int stk_vidioc_reqbufs(struct file *filp,
if (is_streaming(dev)
|| (dev->owner && dev->owner != filp))
return -EBUSY;
+ stk_free_buffers(dev);
+ if (rb->count == 0) {
+ stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
+ unset_initialised(dev);
+ dev->owner = NULL;
+ return 0;
+ }
dev->owner = filp;
/*FIXME If they ask for zero, we must stop streaming and free */
@@ -1079,7 +1070,7 @@ static int stk_vidioc_reqbufs(struct file *filp,
static int stk_vidioc_querybuf(struct file *filp,
void *priv, struct v4l2_buffer *buf)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
struct stk_sio_buffer *sbuf;
if (buf->index >= dev->n_sbufs)
@@ -1092,7 +1083,7 @@ static int stk_vidioc_querybuf(struct file *filp,
static int stk_vidioc_qbuf(struct file *filp,
void *priv, struct v4l2_buffer *buf)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
struct stk_sio_buffer *sbuf;
unsigned long flags;
@@ -1116,7 +1107,7 @@ static int stk_vidioc_qbuf(struct file *filp,
static int stk_vidioc_dqbuf(struct file *filp,
void *priv, struct v4l2_buffer *buf)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
struct stk_sio_buffer *sbuf;
unsigned long flags;
int ret;
@@ -1149,7 +1140,7 @@ static int stk_vidioc_dqbuf(struct file *filp,
static int stk_vidioc_streamon(struct file *filp,
void *priv, enum v4l2_buf_type type)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
if (is_streaming(dev))
return 0;
if (dev->sio_bufs == NULL)
@@ -1161,7 +1152,7 @@ static int stk_vidioc_streamon(struct file *filp,
static int stk_vidioc_streamoff(struct file *filp,
void *priv, enum v4l2_buf_type type)
{
- struct stk_camera *dev = priv;
+ struct stk_camera *dev = video_drvdata(filp);
unsigned long flags;
int i;
stk_stop_stream(dev);
@@ -1206,6 +1197,10 @@ static int stk_vidioc_enum_framesizes(struct file *filp,
}
}
+static const struct v4l2_ctrl_ops stk_ctrl_ops = {
+ .s_ctrl = stk_s_ctrl,
+};
+
static struct v4l2_file_operations v4l_stk_fops = {
.owner = THIS_MODULE,
.open = v4l_stk_open,
@@ -1213,7 +1208,7 @@ static struct v4l2_file_operations v4l_stk_fops = {
.read = v4l_stk_read,
.poll = v4l_stk_poll,
.mmap = v4l_stk_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
@@ -1225,18 +1220,17 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
.vidioc_enum_input = stk_vidioc_enum_input,
.vidioc_s_input = stk_vidioc_s_input,
.vidioc_g_input = stk_vidioc_g_input,
- .vidioc_s_std = stk_vidioc_s_std,
.vidioc_reqbufs = stk_vidioc_reqbufs,
.vidioc_querybuf = stk_vidioc_querybuf,
.vidioc_qbuf = stk_vidioc_qbuf,
.vidioc_dqbuf = stk_vidioc_dqbuf,
.vidioc_streamon = stk_vidioc_streamon,
.vidioc_streamoff = stk_vidioc_streamoff,
- .vidioc_queryctrl = stk_vidioc_queryctrl,
- .vidioc_g_ctrl = stk_vidioc_g_ctrl,
- .vidioc_s_ctrl = stk_vidioc_s_ctrl,
.vidioc_g_parm = stk_vidioc_g_parm,
.vidioc_enum_framesizes = stk_vidioc_enum_framesizes,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static void stk_v4l_dev_release(struct video_device *vd)
@@ -1251,8 +1245,6 @@ static void stk_v4l_dev_release(struct video_device *vd)
static struct video_device stk_v4l_data = {
.name = "stkwebcam",
- .tvnorms = V4L2_STD_UNKNOWN,
- .current_norm = V4L2_STD_UNKNOWN,
.fops = &v4l_stk_fops,
.ioctl_ops = &v4l_stk_ioctl_ops,
.release = stk_v4l_dev_release,
@@ -1264,8 +1256,11 @@ static int stk_register_video_device(struct stk_camera *dev)
int err;
dev->vdev = stk_v4l_data;
+ dev->vdev.lock = &dev->lock;
dev->vdev.debug = debug;
- dev->vdev.parent = &dev->interface->dev;
+ dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
+ video_set_drvdata(&dev->vdev, dev);
err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
if (err)
STK_ERROR("v4l registration failed\n");
@@ -1281,8 +1276,9 @@ static int stk_register_video_device(struct stk_camera *dev)
static int stk_camera_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- int i;
+ struct v4l2_ctrl_handler *hdl;
int err = 0;
+ int i;
struct stk_camera *dev = NULL;
struct usb_device *udev = interface_to_usbdev(interface);
@@ -1294,9 +1290,31 @@ static int stk_camera_probe(struct usb_interface *interface,
STK_ERROR("Out of memory !\n");
return -ENOMEM;
}
+ err = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
+ if (err < 0) {
+ dev_err(&udev->dev, "couldn't register v4l2_device\n");
+ kfree(dev);
+ return err;
+ }
+ hdl = &dev->hdl;
+ v4l2_ctrl_handler_init(hdl, 3);
+ v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 0xff, 0x1, 0x60);
+ v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 1);
+ if (hdl->error) {
+ err = hdl->error;
+ dev_err(&udev->dev, "couldn't register control\n");
+ goto error;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
spin_lock_init(&dev->spinlock);
+ mutex_init(&dev->lock);
init_waitqueue_head(&dev->wait_frame);
+ dev->first_init = 1; /* webcam LED management */
dev->udev = udev;
dev->interface = interface;
@@ -1337,7 +1355,6 @@ static int stk_camera_probe(struct usb_interface *interface,
err = -ENODEV;
goto error;
}
- dev->vsettings.brightness = 0x7fff;
dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
dev->vsettings.mode = MODE_VGA;
dev->frame_size = 640 * 480 * 2;
@@ -1354,6 +1371,8 @@ static int stk_camera_probe(struct usb_interface *interface,
return 0;
error:
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
return err;
}
@@ -1371,6 +1390,8 @@ static void stk_camera_disconnect(struct usb_interface *interface)
video_device_node_name(&dev->vdev));
video_unregister_device(&dev->vdev);
+ v4l2_ctrl_handler_free(&dev->hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h
index 9f6736637571..9bbfa3d9bfdd 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.h
+++ b/drivers/media/usb/stkwebcam/stk-webcam.h
@@ -23,6 +23,8 @@
#define STKWEBCAM_H
#include <linux/usb.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-common.h>
#define DRIVER_VERSION "v0.0.1"
@@ -59,7 +61,6 @@ enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
struct stk_video {
enum stk_mode mode;
- int brightness;
__u32 palette;
int hflip;
int vflip;
@@ -91,11 +92,15 @@ struct regval {
};
struct stk_camera {
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
struct video_device vdev;
struct usb_device *udev;
struct usb_interface *interface;
int webcam_model;
struct file *owner;
+ struct mutex lock;
+ int first_init;
u8 isoc_ep;
@@ -113,6 +118,7 @@ struct stk_camera {
int frame_size;
/* Streaming buffers */
+ int reading;
unsigned int n_sbufs;
struct stk_sio_buffer *sio_bufs;
struct list_head sio_avail;
diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h
index 5dd73b7857d1..9e23ad32d2fe 100644
--- a/drivers/media/usb/tlg2300/pd-common.h
+++ b/drivers/media/usb/tlg2300/pd-common.h
@@ -10,6 +10,7 @@
#include <linux/poll.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include "dvb_frontend.h"
#include "dvbdev.h"
@@ -25,7 +26,6 @@
#define POSEIDON_STATE_ANALOG (0x0001)
#define POSEIDON_STATE_FM (0x0002)
#define POSEIDON_STATE_DVBT (0x0004)
-#define POSEIDON_STATE_VBI (0x0008)
#define POSEIDON_STATE_DISCONNECT (0x0080)
#define PM_SUSPEND_DELAY 3
@@ -35,11 +35,11 @@
#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2)
#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2)
-#define TUNER_FREQ_MIN (45000000)
-#define TUNER_FREQ_MAX (862000000)
+#define TUNER_FREQ_MIN (45000000U)
+#define TUNER_FREQ_MAX (862000000U)
struct vbi_data {
- struct video_device *v_dev;
+ struct video_device v_dev;
struct video_data *video;
struct front_face *front;
@@ -62,7 +62,8 @@ struct running_context {
struct video_data {
/* v4l2 video device */
- struct video_device *v_dev;
+ struct video_device v_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
/* the working context */
struct running_context context;
@@ -115,10 +116,10 @@ struct poseidon_audio {
struct radio_data {
__u32 fm_freq;
- int users;
unsigned int is_radio_streaming;
int pre_emphasis;
- struct video_device *fm_dev;
+ struct video_device fm_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
};
#define DVB_SBUF_NUM 4
@@ -233,7 +234,6 @@ void dvb_stop_streaming(struct pd_dvb_adapter *);
/* FM */
int poseidon_fm_init(struct poseidon *);
int poseidon_fm_exit(struct poseidon *);
-struct video_device *vdev_init(struct poseidon *, struct video_device *);
/* vendor command ops */
int send_set_req(struct poseidon*, u8, s32, s32*);
@@ -249,7 +249,6 @@ void free_all_urb_generic(struct urb **urb_array, int num);
/* misc */
void poseidon_delete(struct kref *kref);
-void destroy_video_device(struct video_device **v_dev);
extern int debug_mode;
void set_debug_mode(struct video_device *vfd, int debug_mode);
@@ -269,13 +268,4 @@ void set_debug_mode(struct video_device *vfd, int debug_mode);
log();\
} while (0)
-#define logs(f) do { \
- if ((debug_mode & 0x4) && \
- (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \
- log("type : VBI");\
- \
- if ((debug_mode & 0x8) && \
- (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \
- log("type : VIDEO");\
- } while (0)
#endif
diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c
index 7b1f6ebd0e2c..e07e4c699cc2 100644
--- a/drivers/media/usb/tlg2300/pd-main.c
+++ b/drivers/media/usb/tlg2300/pd-main.c
@@ -55,7 +55,6 @@ MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
#define TLG2300_FIRMWARE "tlg2300_firmware.bin"
static const char *firmware_name = TLG2300_FIRMWARE;
-static struct usb_driver poseidon_driver;
static LIST_HEAD(pd_device_list);
/*
@@ -268,7 +267,8 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
static inline int get_autopm_ref(struct poseidon *pd)
{
return pd->video_data.users + pd->vbi_data.users + pd->audio.users
- + atomic_read(&pd->dvb_data.users) + pd->radio_data.users;
+ + atomic_read(&pd->dvb_data.users) +
+ !list_empty(&pd->radio_data.fm_dev.fh_list);
}
/* fixup something for poseidon */
@@ -316,7 +316,7 @@ static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg)
if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) {
pd->msg.event = PM_EVENT_AUTO_SUSPEND;
pd->pm_resume = NULL; /* a good guard */
- printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n");
+ printk(KERN_DEBUG "TLG2300 auto suspend\n");
}
return 0;
}
@@ -331,7 +331,7 @@ static int poseidon_resume(struct usb_interface *intf)
if (!pd)
return 0;
- printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n");
+ printk(KERN_DEBUG "TLG2300 resume\n");
if (!is_working(pd)) {
if (PM_EVENT_AUTO_SUSPEND == pd->msg.event)
@@ -431,15 +431,11 @@ static int poseidon_probe(struct usb_interface *interface,
usb_set_intfdata(interface, pd);
if (new_one) {
- struct device *dev = &interface->dev;
-
logpm(pd);
mutex_init(&pd->lock);
/* register v4l2 device */
- snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s",
- dev->driver->name, dev_name(dev));
- ret = v4l2_device_register(NULL, &pd->v4l2_dev);
+ ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev);
/* register devices in directory /dev */
ret = pd_video_init(pd);
@@ -530,7 +526,7 @@ module_init(poseidon_init);
module_exit(poseidon_exit);
MODULE_AUTHOR("Telegent Systems");
-MODULE_DESCRIPTION("For tlg2300-based USB device ");
+MODULE_DESCRIPTION("For tlg2300-based USB device");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.2");
MODULE_FIRMWARE(TLG2300_FIRMWARE);
diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c
index 25eeb166aa0b..ea6070ba835e 100644
--- a/drivers/media/usb/tlg2300/pd-radio.c
+++ b/drivers/media/usb/tlg2300/pd-radio.c
@@ -9,6 +9,8 @@
#include <linux/mm.h>
#include <linux/mutex.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
#include <linux/sched.h>
#include "pd-common.h"
@@ -18,8 +20,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency);
static int poseidon_fm_close(struct file *filp);
static int poseidon_fm_open(struct file *filp);
-#define TUNER_FREQ_MIN_FM 76000000
-#define TUNER_FREQ_MAX_FM 108000000
+#define TUNER_FREQ_MIN_FM 76000000U
+#define TUNER_FREQ_MAX_FM 108000000U
#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1)
static int preemphasis[MAX_PREEMPHASIS] = {
@@ -77,13 +79,9 @@ static int pm_fm_resume(struct poseidon *p)
static int poseidon_fm_open(struct file *filp)
{
- struct video_device *vfd = video_devdata(filp);
- struct poseidon *p = video_get_drvdata(vfd);
+ struct poseidon *p = video_drvdata(filp);
int ret = 0;
- if (!p)
- return -1;
-
mutex_lock(&p->lock);
if (p->state & POSEIDON_STATE_DISCONNECT) {
ret = -ENODEV;
@@ -94,9 +92,14 @@ static int poseidon_fm_open(struct file *filp)
ret = -EBUSY;
goto out;
}
+ ret = v4l2_fh_open(filp);
+ if (ret)
+ goto out;
usb_autopm_get_interface(p->interface);
if (0 == p->state) {
+ struct video_device *vfd = &p->radio_data.fm_dev;
+
/* default pre-emphasis */
if (p->radio_data.pre_emphasis == 0)
p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR;
@@ -109,9 +112,7 @@ static int poseidon_fm_open(struct file *filp)
}
p->state |= POSEIDON_STATE_FM;
}
- p->radio_data.users++;
kref_get(&p->kref);
- filp->private_data = p;
out:
mutex_unlock(&p->lock);
return ret;
@@ -119,13 +120,12 @@ out:
static int poseidon_fm_close(struct file *filp)
{
- struct poseidon *p = filp->private_data;
+ struct poseidon *p = video_drvdata(filp);
struct radio_data *fm = &p->radio_data;
uint32_t status;
mutex_lock(&p->lock);
- fm->users--;
- if (0 == fm->users)
+ if (v4l2_fh_is_singular_file(filp))
p->state &= ~POSEIDON_STATE_FM;
if (fm->is_radio_streaming && filp == p->file_for_stream) {
@@ -136,19 +136,23 @@ static int poseidon_fm_close(struct file *filp)
mutex_unlock(&p->lock);
kref_put(&p->kref, poseidon_delete);
- filp->private_data = NULL;
- return 0;
+ return v4l2_fh_release(filp);
}
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
- struct poseidon *p = file->private_data;
+ struct poseidon *p = video_drvdata(file);
strlcpy(v->driver, "tele-radio", sizeof(v->driver));
strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ /* Report all capabilities of the USB device */
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
return 0;
}
@@ -156,27 +160,29 @@ static const struct v4l2_file_operations poseidon_fm_fops = {
.owner = THIS_MODULE,
.open = poseidon_fm_open,
.release = poseidon_fm_close,
- .ioctl = video_ioctl2,
+ .poll = v4l2_ctrl_poll,
+ .unlocked_ioctl = video_ioctl2,
};
static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
+ struct poseidon *p = video_drvdata(file);
struct tuner_fm_sig_stat_s fm_stat = {};
int ret, status, count = 5;
- struct poseidon *p = file->private_data;
if (vt->index != 0)
return -EINVAL;
vt->type = V4L2_TUNER_RADIO;
- vt->capability = V4L2_TUNER_CAP_STEREO;
- vt->rangelow = TUNER_FREQ_MIN_FM / 62500;
- vt->rangehigh = TUNER_FREQ_MAX_FM / 62500;
+ vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+ vt->rangelow = TUNER_FREQ_MIN_FM * 2 / 125;
+ vt->rangehigh = TUNER_FREQ_MAX_FM * 2 / 125;
vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
vt->audmode = V4L2_TUNER_MODE_STEREO;
vt->signal = 0;
vt->afc = 0;
+ strlcpy(vt->name, "Radio", sizeof(vt->name));
mutex_lock(&p->lock);
ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
@@ -205,8 +211,10 @@ static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv,
static int fm_get_freq(struct file *file, void *priv,
struct v4l2_frequency *argp)
{
- struct poseidon *p = file->private_data;
+ struct poseidon *p = video_drvdata(file);
+ if (argp->tuner)
+ return -EINVAL;
argp->frequency = p->radio_data.fm_freq;
return 0;
}
@@ -221,11 +229,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency)
ret = send_set_req(p, TUNER_AUD_ANA_STD,
p->radio_data.pre_emphasis, &status);
- freq = (frequency * 125) * 500 / 1000;/* kHZ */
- if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) {
- ret = -EINVAL;
- goto error;
- }
+ freq = (frequency * 125) / 2; /* Hz */
+ freq = clamp(freq, TUNER_FREQ_MIN_FM, TUNER_FREQ_MAX_FM);
ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status);
if (ret < 0)
@@ -240,18 +245,20 @@ static int set_frequency(struct poseidon *p, __u32 frequency)
TLG_TUNE_PLAY_SVC_START, &status);
p->radio_data.is_radio_streaming = 1;
}
- p->radio_data.fm_freq = frequency;
+ p->radio_data.fm_freq = freq * 2 / 125;
error:
mutex_unlock(&p->lock);
return ret;
}
static int fm_set_freq(struct file *file, void *priv,
- struct v4l2_frequency *argp)
+ const struct v4l2_frequency *argp)
{
- struct poseidon *p = file->private_data;
+ struct poseidon *p = video_drvdata(file);
- p->file_for_stream = file;
+ if (argp->tuner)
+ return -EINVAL;
+ p->file_for_stream = file;
#ifdef CONFIG_PM
p->pm_suspend = pm_fm_suspend;
p->pm_resume = pm_fm_resume;
@@ -259,163 +266,75 @@ static int fm_set_freq(struct file *file, void *priv,
return set_frequency(p, argp->frequency);
}
-static int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *arg)
-{
- return 0;
-}
-
-static int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh,
- struct v4l2_ext_controls *ctrls)
-{
- struct poseidon *p = file->private_data;
- int i;
-
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
- return -EINVAL;
-
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
- continue;
-
- if (i < MAX_PREEMPHASIS)
- ctrl->value = p->radio_data.pre_emphasis;
- }
- return 0;
-}
-
-static int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh,
- struct v4l2_ext_controls *ctrls)
-{
- int i;
-
- if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX)
- return -EINVAL;
-
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = ctrls->controls + i;
-
- if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS)
- continue;
-
- if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) {
- struct poseidon *p = file->private_data;
- int pre_emphasis = preemphasis[ctrl->value];
- u32 status;
-
- send_set_req(p, TUNER_AUD_ANA_STD,
- pre_emphasis, &status);
- p->radio_data.pre_emphasis = pre_emphasis;
- }
- }
- return 0;
-}
-
-static int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl)
{
- return 0;
-}
-
-static int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *ctrl)
-{
- if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL))
- return -EINVAL;
+ struct poseidon *p = container_of(ctrl->handler, struct poseidon,
+ radio_data.ctrl_handler);
+ int pre_emphasis;
+ u32 status;
- ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
- if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) {
- /* return the next supported control */
- ctrl->id = V4L2_CID_TUNE_PREEMPHASIS;
- v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED,
- V4L2_PREEMPHASIS_75_uS, 1,
- V4L2_PREEMPHASIS_50_uS);
- ctrl->flags = V4L2_CTRL_FLAG_UPDATE;
+ switch (ctrl->id) {
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ pre_emphasis = preemphasis[ctrl->val];
+ send_set_req(p, TUNER_AUD_ANA_STD, pre_emphasis, &status);
+ p->radio_data.pre_emphasis = pre_emphasis;
return 0;
}
return -EINVAL;
}
-static int tlg_fm_vidioc_querymenu(struct file *file, void *fh,
- struct v4l2_querymenu *qmenu)
-{
- return v4l2_ctrl_query_menu(qmenu, NULL, NULL);
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt)
{
return vt->index > 0 ? -EINVAL : 0;
}
-static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *va)
-{
- return (va->index != 0) ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
-{
- a->index = 0;
- a->mode = 0;
- a->capability = V4L2_AUDCAP_STEREO;
- strcpy(a->name, "Radio");
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, u32 i)
-{
- return (i != 0) ? -EINVAL : 0;
-}
-static int vidioc_g_input(struct file *filp, void *priv, u32 *i)
-{
- return (*i != 0) ? -EINVAL : 0;
-}
+static const struct v4l2_ctrl_ops tlg_fm_ctrl_ops = {
+ .s_ctrl = tlg_fm_s_ctrl,
+};
static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = tlg_fm_vidioc_queryctrl,
- .vidioc_querymenu = tlg_fm_vidioc_querymenu,
- .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl,
- .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl,
- .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl,
- .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_tuner = tlg_fm_vidioc_g_tuner,
.vidioc_g_frequency = fm_get_freq,
.vidioc_s_frequency = fm_set_freq,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device poseidon_fm_template = {
.name = "Telegent-Radio",
.fops = &poseidon_fm_fops,
.minor = -1,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &poseidon_fm_ioctl_ops,
};
int poseidon_fm_init(struct poseidon *p)
{
- struct video_device *fm_dev;
-
- fm_dev = vdev_init(p, &poseidon_fm_template);
- if (fm_dev == NULL)
- return -1;
-
- if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) {
- video_device_release(fm_dev);
- return -1;
+ struct video_device *vfd = &p->radio_data.fm_dev;
+ struct v4l2_ctrl_handler *hdl = &p->radio_data.ctrl_handler;
+
+ *vfd = poseidon_fm_template;
+
+ set_frequency(p, TUNER_FREQ_MIN_FM);
+ v4l2_ctrl_handler_init(hdl, 1);
+ v4l2_ctrl_new_std_menu(hdl, &tlg_fm_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS,
+ V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS);
+ if (hdl->error) {
+ v4l2_ctrl_handler_free(hdl);
+ return hdl->error;
}
- p->radio_data.fm_dev = fm_dev;
- return 0;
+ vfd->v4l2_dev = &p->v4l2_dev;
+ vfd->ctrl_handler = hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
+ video_set_drvdata(vfd, p);
+ return video_register_device(vfd, VFL_TYPE_RADIO, -1);
}
int poseidon_fm_exit(struct poseidon *p)
{
- destroy_video_device(&p->radio_data.fm_dev);
+ video_unregister_device(&p->radio_data.fm_dev);
+ v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler);
return 0;
}
diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c
index 21723378bb8f..8df668d06552 100644
--- a/drivers/media/usb/tlg2300/pd-video.c
+++ b/drivers/media/usb/tlg2300/pd-video.c
@@ -8,6 +8,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-dev.h>
+#include <media/v4l2-ctrls.h>
#include "pd-common.h"
#include "vendorcmds.h"
@@ -82,31 +83,6 @@ static const struct pd_input pd_inputs[] = {
};
static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs);
-struct poseidon_control {
- struct v4l2_queryctrl v4l2_ctrl;
- enum cmd_custom_param_id vc_id;
-};
-
-static struct poseidon_control controls[] = {
- {
- { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
- "brightness", 0, 10000, 1, 100, 0, },
- CUST_PARM_ID_BRIGHTNESS_CTRL
- }, {
- { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
- "contrast", 0, 10000, 1, 100, 0, },
- CUST_PARM_ID_CONTRAST_CTRL,
- }, {
- { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
- "hue", 0, 10000, 1, 100, 0, },
- CUST_PARM_ID_HUE_CTRL,
- }, {
- { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
- "saturation", 0, 10000, 1, 100, 0, },
- CUST_PARM_ID_SATURATION_CTRL,
- },
-};
-
struct video_std_to_audio_std {
v4l2_std_id video_std;
int audio_std;
@@ -142,17 +118,20 @@ static int get_audio_std(v4l2_std_id v4l2_std)
static int vidioc_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- struct front_face *front = fh;
- struct poseidon *p = front->pd;
-
- logs(front);
+ struct video_device *vdev = video_devdata(file);
+ struct poseidon *p = video_get_drvdata(vdev);
strcpy(cap->driver, "tele-video");
strcpy(cap->card, "Telegent Poseidon");
usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
- V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
+ cap->device_caps = V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ if (vdev->vfl_type == VFL_TYPE_VBI)
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
+ V4L2_CAP_RADIO | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
return 0;
}
@@ -223,7 +202,6 @@ static void submit_frame(struct front_face *front)
*/
static void end_field(struct video_data *video)
{
- /* logs(video->front); */
if (1 == video->field_count)
submit_frame(video->front);
else
@@ -718,17 +696,10 @@ static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
struct front_face *front = fh;
struct poseidon *pd = front->pd;
- logs(front);
f->fmt.pix = pd->video_data.context.pix;
return 0;
}
-static int vidioc_try_fmt(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- return 0;
-}
-
/*
* VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while
* Mplayer calls them in the reverse order.
@@ -787,7 +758,6 @@ static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
struct front_face *front = fh;
struct poseidon *pd = front->pd;
- logs(front);
/* stop VBI here */
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
return -EINVAL;
@@ -828,11 +798,10 @@ static int vidioc_g_fmt_vbi(struct file *file, void *fh,
vbi_fmt->count[1] = V4L_PAL_VBI_LINES;
}
vbi_fmt->flags = V4L2_VBI_UNSYNC;
- logs(front);
return 0;
}
-static int set_std(struct poseidon *pd, v4l2_std_id *norm)
+static int set_std(struct poseidon *pd, v4l2_std_id norm)
{
struct video_data *video = &pd->video_data;
struct vbi_data *vbi = &pd->vbi_data;
@@ -842,7 +811,7 @@ static int set_std(struct poseidon *pd, v4l2_std_id *norm)
int height;
for (i = 0; i < POSEIDON_TVNORMS; i++) {
- if (*norm & poseidon_tvnorms[i].v4l2_id) {
+ if (norm & poseidon_tvnorms[i].v4l2_id) {
param = poseidon_tvnorms[i].tlg_tvnorm;
log("name : %s", poseidon_tvnorms[i].name);
goto found;
@@ -877,17 +846,23 @@ out:
return ret;
}
-static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm)
{
struct front_face *front = fh;
- logs(front);
+
return set_std(front->pd, norm);
}
-static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
+static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
{
struct front_face *front = fh;
+ *norm = front->pd->video_data.context.tvnormid;
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
+{
if (in->index >= POSEIDON_INPUTS)
return -EINVAL;
strcpy(in->name, pd_inputs[in->index].name);
@@ -897,11 +872,10 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
* the audio input index mixed with this video input,
* Poseidon only have one audio/video, set to "0"
*/
- in->audioset = 0;
+ in->audioset = 1;
in->tuner = 0;
in->std = V4L2_STD_ALL;
in->status = 0;
- logs(front);
return 0;
}
@@ -911,7 +885,6 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
struct poseidon *pd = front->pd;
struct running_context *context = &pd->video_data.context;
- logs(front);
*i = context->sig_index;
return 0;
}
@@ -934,68 +907,28 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
return 0;
}
-static struct poseidon_control *check_control_id(__u32 id)
-{
- struct poseidon_control *control = &controls[0];
- int array_size = ARRAY_SIZE(controls);
-
- for (; control < &controls[array_size]; control++)
- if (control->v4l2_ctrl.id == id)
- return control;
- return NULL;
-}
-
-static int vidioc_queryctrl(struct file *file, void *fh,
- struct v4l2_queryctrl *a)
-{
- struct poseidon_control *control = NULL;
-
- control = check_control_id(a->id);
- if (!control)
- return -EINVAL;
-
- *a = control->v4l2_ctrl;
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- struct poseidon_control *control = NULL;
- struct tuner_custom_parameter_s tuner_param;
- s32 ret = 0, cmd_status;
-
- control = check_control_id(ctrl->id);
- if (!control)
- return -EINVAL;
-
- mutex_lock(&pd->lock);
- ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id,
- &tuner_param, &cmd_status, sizeof(tuner_param));
- mutex_unlock(&pd->lock);
-
- if (ret || cmd_status)
- return -1;
-
- ctrl->value = tuner_param.param_value;
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+static int tlg_s_ctrl(struct v4l2_ctrl *c)
{
+ struct poseidon *pd = container_of(c->handler, struct poseidon,
+ video_data.ctrl_handler);
struct tuner_custom_parameter_s param = {0};
- struct poseidon_control *control = NULL;
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
s32 ret = 0, cmd_status, params;
- control = check_control_id(a->id);
- if (!control)
- return -EINVAL;
-
- param.param_value = a->value;
- param.param_id = control->vc_id;
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ param.param_id = CUST_PARM_ID_BRIGHTNESS_CTRL;
+ break;
+ case V4L2_CID_CONTRAST:
+ param.param_id = CUST_PARM_ID_CONTRAST_CTRL;
+ break;
+ case V4L2_CID_HUE:
+ param.param_id = CUST_PARM_ID_HUE_CTRL;
+ break;
+ case V4L2_CID_SATURATION:
+ param.param_id = CUST_PARM_ID_SATURATION_CTRL;
+ break;
+ }
+ param.param_value = c->val;
params = *(s32 *)&param; /* temp code */
mutex_lock(&pd->lock);
@@ -1079,7 +1012,6 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner)
tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub;
tuner->audmode = pd_audio_modes[index].v4l2_audio_mode;
tuner->afc = 0;
- logs(front);
return 0;
}
@@ -1099,7 +1031,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index)
return ret;
}
-static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a)
+static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a)
{
struct front_face *front = fh;
struct poseidon *pd = front->pd;
@@ -1107,7 +1039,6 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a)
if (0 != a->index)
return -EINVAL;
- logs(front);
for (index = 0; index < POSEIDON_AUDIOMODS; index++)
if (a->audmode == pd_audio_modes[index].v4l2_audio_mode)
return pd_vidioc_s_tuner(pd, index);
@@ -1128,51 +1059,51 @@ static int vidioc_g_frequency(struct file *file, void *fh,
return 0;
}
-static int set_frequency(struct poseidon *pd, __u32 frequency)
+static int set_frequency(struct poseidon *pd, u32 *frequency)
{
s32 ret = 0, param, cmd_status;
struct running_context *context = &pd->video_data.context;
- param = frequency * 62500 / 1000;
- if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000)
- return -EINVAL;
+ *frequency = clamp(*frequency,
+ TUNER_FREQ_MIN / 62500, TUNER_FREQ_MAX / 62500);
+ param = (*frequency) * 62500 / 1000;
mutex_lock(&pd->lock);
ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status);
ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
msleep(250); /* wait for a while until the hardware is ready. */
- context->freq = frequency;
+ context->freq = *frequency;
mutex_unlock(&pd->lock);
return ret;
}
static int vidioc_s_frequency(struct file *file, void *fh,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct front_face *front = fh;
struct poseidon *pd = front->pd;
+ u32 frequency = freq->frequency;
- logs(front);
+ if (freq->tuner)
+ return -EINVAL;
#ifdef CONFIG_PM
pd->pm_suspend = pm_video_suspend;
pd->pm_resume = pm_video_resume;
#endif
- return set_frequency(pd, freq->frequency);
+ return set_frequency(pd, &frequency);
}
static int vidioc_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *b)
{
struct front_face *front = file->private_data;
- logs(front);
return videobuf_reqbufs(&front->q, b);
}
static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
struct front_face *front = file->private_data;
- logs(front);
return videobuf_querybuf(&front->q, b);
}
@@ -1261,7 +1192,6 @@ static int vidioc_streamon(struct file *file, void *fh,
{
struct front_face *front = fh;
- logs(front);
if (unlikely(type != front->type))
return -EINVAL;
return videobuf_streamon(&front->q);
@@ -1272,7 +1202,6 @@ static int vidioc_streamoff(struct file *file, void *fh,
{
struct front_face *front = file->private_data;
- logs(front);
if (unlikely(type != front->type))
return -EINVAL;
return videobuf_streamoff(&front->q);
@@ -1341,11 +1270,11 @@ static int restore_v4l2_context(struct poseidon *pd,
pd_video_checkmode(pd);
- set_std(pd, &context->tvnormid);
+ set_std(pd, context->tvnormid);
vidioc_s_input(NULL, front, context->sig_index);
pd_vidioc_s_tuner(pd, context->audio_idx);
pd_vidioc_s_fmt(pd, &context->pix);
- set_frequency(pd, context->freq);
+ set_frequency(pd, &context->freq);
return 0;
}
@@ -1406,12 +1335,14 @@ static int pd_video_open(struct file *file)
mutex_lock(&pd->lock);
usb_autopm_get_interface(pd->interface);
- if (vfd->vfl_type == VFL_TYPE_GRABBER
- && !(pd->state & POSEIDON_STATE_ANALOG)) {
- front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
- if (!front)
- goto out;
-
+ if (pd->state && !(pd->state & POSEIDON_STATE_ANALOG)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
+ if (!front)
+ goto out;
+ if (vfd->vfl_type == VFL_TYPE_GRABBER) {
pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */
init_video_context(&pd->video_data.context);
@@ -1422,7 +1353,6 @@ static int pd_video_open(struct file *file)
goto out;
}
- pd->state |= POSEIDON_STATE_ANALOG;
front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pd->video_data.users++;
set_debug_mode(vfd, debug_mode);
@@ -1433,13 +1363,7 @@ static int pd_video_open(struct file *file)
V4L2_FIELD_INTERLACED,/* video is interlacd */
sizeof(struct videobuf_buffer),/*it's enough*/
front, NULL);
- } else if (vfd->vfl_type == VFL_TYPE_VBI
- && !(pd->state & POSEIDON_STATE_VBI)) {
- front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
- if (!front)
- goto out;
-
- pd->state |= POSEIDON_STATE_VBI;
+ } else {
front->type = V4L2_BUF_TYPE_VBI_CAPTURE;
pd->vbi_data.front = front;
pd->vbi_data.users++;
@@ -1450,19 +1374,15 @@ static int pd_video_open(struct file *file)
V4L2_FIELD_NONE, /* vbi is NONE mode */
sizeof(struct videobuf_buffer),
front, NULL);
- } else {
- /* maybe add FM support here */
- log("other ");
- ret = -EINVAL;
- goto out;
}
- front->pd = pd;
- front->curr_frame = NULL;
+ pd->state |= POSEIDON_STATE_ANALOG;
+ front->pd = pd;
+ front->curr_frame = NULL;
INIT_LIST_HEAD(&front->active);
spin_lock_init(&front->queue_lock);
- file->private_data = front;
+ file->private_data = front;
kref_get(&pd->kref);
mutex_unlock(&pd->lock);
@@ -1479,12 +1399,9 @@ static int pd_video_release(struct file *file)
struct poseidon *pd = front->pd;
s32 cmd_status = 0;
- logs(front);
mutex_lock(&pd->lock);
if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- pd->state &= ~POSEIDON_STATE_ANALOG;
-
/* stop the device, and free the URBs */
usb_transfer_stop(&pd->video_data);
free_all_urb(&pd->video_data);
@@ -1496,10 +1413,11 @@ static int pd_video_release(struct file *file)
pd->file_for_stream = NULL;
pd->video_data.users--;
} else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- pd->state &= ~POSEIDON_STATE_VBI;
pd->vbi_data.front = NULL;
pd->vbi_data.users--;
}
+ if (!pd->vbi_data.users && !pd->video_data.users)
+ pd->state &= ~POSEIDON_STATE_ANALOG;
videobuf_stop(&front->q);
videobuf_mmap_free(&front->q);
@@ -1551,7 +1469,6 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt,
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
/* Input */
.vidioc_g_input = vidioc_g_input,
@@ -1566,6 +1483,7 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
/* Tuner ioctls */
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
@@ -1579,59 +1497,29 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
/* Stream on/off */
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-
- /* Control handling */
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
};
static struct video_device pd_video_template = {
.name = "Telegent-Video",
.fops = &pd_video_fops,
.minor = -1,
- .release = video_device_release,
+ .release = video_device_release_empty,
.tvnorms = V4L2_STD_ALL,
.ioctl_ops = &pd_video_ioctl_ops,
};
-struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp)
-{
- struct video_device *vfd;
-
- vfd = video_device_alloc();
- if (vfd == NULL)
- return NULL;
- *vfd = *tmp;
- vfd->minor = -1;
- vfd->v4l2_dev = &pd->v4l2_dev;
- /*vfd->parent = &(pd->udev->dev); */
- vfd->release = video_device_release;
- video_set_drvdata(vfd, pd);
- return vfd;
-}
-
-void destroy_video_device(struct video_device **v_dev)
-{
- struct video_device *dev = *v_dev;
-
- if (dev == NULL)
- return;
-
- if (video_is_registered(dev))
- video_unregister_device(dev);
- else
- video_device_release(dev);
- *v_dev = NULL;
-}
+static const struct v4l2_ctrl_ops tlg_ctrl_ops = {
+ .s_ctrl = tlg_s_ctrl,
+};
void pd_video_exit(struct poseidon *pd)
{
struct video_data *video = &pd->video_data;
struct vbi_data *vbi = &pd->vbi_data;
- destroy_video_device(&video->v_dev);
- destroy_video_device(&vbi->v_dev);
+ video_unregister_device(&video->v_dev);
+ video_unregister_device(&vbi->v_dev);
+ v4l2_ctrl_handler_free(&video->ctrl_handler);
log();
}
@@ -1639,23 +1527,39 @@ int pd_video_init(struct poseidon *pd)
{
struct video_data *video = &pd->video_data;
struct vbi_data *vbi = &pd->vbi_data;
+ struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
+ u32 freq = TUNER_FREQ_MIN / 62500;
int ret = -ENOMEM;
- video->v_dev = vdev_init(pd, &pd_video_template);
- if (video->v_dev == NULL)
- goto out;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ 0, 10000, 1, 100);
+ v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_CONTRAST,
+ 0, 10000, 1, 100);
+ v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_HUE,
+ 0, 10000, 1, 100);
+ v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_SATURATION,
+ 0, 10000, 1, 100);
+ if (hdl->error) {
+ v4l2_ctrl_handler_free(hdl);
+ return hdl->error;
+ }
+ set_frequency(pd, &freq);
+ video->v_dev = pd_video_template;
+ video->v_dev.v4l2_dev = &pd->v4l2_dev;
+ video->v_dev.ctrl_handler = hdl;
+ video_set_drvdata(&video->v_dev, pd);
- ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1);
+ ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1);
if (ret != 0)
goto out;
/* VBI uses the same template as video */
- vbi->v_dev = vdev_init(pd, &pd_video_template);
- if (vbi->v_dev == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1);
+ vbi->v_dev = pd_video_template;
+ vbi->v_dev.v4l2_dev = &pd->v4l2_dev;
+ vbi->v_dev.ctrl_handler = hdl;
+ video_set_drvdata(&vbi->v_dev, pd);
+ ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1);
if (ret != 0)
goto out;
log("register VIDEO/VBI devices");
@@ -1665,4 +1569,3 @@ out:
pd_video_exit(pd);
return ret;
}
-
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 1a6857929c15..a78de1d1bc9e 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1056,13 +1056,13 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
int rc = 0;
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
- dev->norm = *norm;
+ dev->norm = norm;
rc = tm6000_init_analog_mode(dev);
fh->width = dev->width;
@@ -1134,7 +1134,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
dev->input = i;
- rc = vidioc_s_std(file, priv, &dev->vfd->current_norm);
+ rc = vidioc_s_std(file, priv, dev->vfd->current_norm);
return rc;
}
@@ -1215,7 +1215,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
@@ -1255,7 +1255,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct tm6000_fh *fh = priv;
struct tm6000_core *dev = fh->dev;
@@ -1293,18 +1293,14 @@ static int radio_g_tuner(struct file *file, void *priv,
}
static int radio_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct tm6000_fh *fh = file->private_data;
struct tm6000_core *dev = fh->dev;
if (0 != t->index)
return -EINVAL;
- if (t->audmode > V4L2_TUNER_MODE_STEREO)
- t->audmode = V4L2_TUNER_MODE_STEREO;
-
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
-
return 0;
}
diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index e40718552850..21b9049c7b3f 100644
--- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
@@ -930,11 +930,11 @@ static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (dvbdmxfeed->type == DMX_TYPE_TS) {
switch (dvbdmxfeed->pes_type) {
- case DMX_TS_PES_VIDEO:
- case DMX_TS_PES_AUDIO:
- case DMX_TS_PES_TELETEXT:
- case DMX_TS_PES_PCR:
- case DMX_TS_PES_OTHER:
+ case DMX_PES_VIDEO:
+ case DMX_PES_AUDIO:
+ case DMX_PES_TELETEXT:
+ case DMX_PES_PCR:
+ case DMX_PES_OTHER:
break;
default:
return -EINVAL;
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index 504c81230339..e52c3b97f304 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -951,34 +951,34 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed)
switch (dvbdmxfeed->pes_type) {
- case DMX_TS_PES_VIDEO:
- dprintk(" pes_type: DMX_TS_PES_VIDEO\n");
+ case DMX_PES_VIDEO:
+ dprintk(" pes_type: DMX_PES_VIDEO\n");
dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid;
dec->video_filter = dvbdmxfeed->filter;
ttusb_dec_set_pids(dec);
break;
- case DMX_TS_PES_AUDIO:
- dprintk(" pes_type: DMX_TS_PES_AUDIO\n");
+ case DMX_PES_AUDIO:
+ dprintk(" pes_type: DMX_PES_AUDIO\n");
dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid;
dec->audio_filter = dvbdmxfeed->filter;
ttusb_dec_set_pids(dec);
break;
- case DMX_TS_PES_TELETEXT:
+ case DMX_PES_TELETEXT:
dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid;
- dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n");
+ dprintk(" pes_type: DMX_PES_TELETEXT(not supported)\n");
return -ENOSYS;
- case DMX_TS_PES_PCR:
- dprintk(" pes_type: DMX_TS_PES_PCR\n");
+ case DMX_PES_PCR:
+ dprintk(" pes_type: DMX_PES_PCR\n");
dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid;
ttusb_dec_set_pids(dec);
break;
- case DMX_TS_PES_OTHER:
- dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n");
+ case DMX_PES_OTHER:
+ dprintk(" pes_type: DMX_PES_OTHER(not supported)\n");
return -ENOSYS;
default:
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index cd1fe78a5532..d34c2afe2c24 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -483,7 +483,7 @@ static int vidioc_g_register(struct file *file, void *priv,
}
static int vidioc_s_register(struct file *file, void *priv,
- struct v4l2_dbg_register *reg)
+ const struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int err_code;
@@ -595,11 +595,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- usbvision->tvnorm_id = *id;
+ usbvision->tvnorm_id = id;
call_all(usbvision, core, s_std, usbvision->tvnorm_id);
/* propagate the change to the decoder */
@@ -628,7 +628,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *vt)
+ const struct v4l2_tuner *vt)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -657,7 +657,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *freq)
+ const struct v4l2_frequency *freq)
{
struct usb_usbvision *usbvision = video_drvdata(file);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 61e28dec991d..a2f4501c23ca 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1487,7 +1487,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
step = mapping->get(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
if (!(step & value))
- return -ERANGE;
+ return -EINVAL;
}
break;
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 6c233a54ce40..cd962be860ca 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -149,6 +149,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
queue->queue.ops = &uvc_queue_qops;
queue->queue.mem_ops = &vb2_vmalloc_memops;
+ queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 976d029e9925..8c05565a240e 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -67,6 +67,7 @@ config VIDEOBUF2_MEMOPS
config VIDEOBUF2_DMA_CONTIG
tristate
+ depends on HAS_DMA
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
select DMA_SHARED_BUFFER
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index a9d355230e8e..aa50c46314b7 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -9,8 +9,11 @@ videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
ifeq ($(CONFIG_COMPAT),y)
videodev-objs += v4l2-compat-ioctl32.o
endif
+ifeq ($(CONFIG_OF),y)
+ videodev-objs += v4l2-of.o
+endif
-obj-$(CONFIG_VIDEO_DEV) += videodev.o
+obj-$(CONFIG_VIDEO_V4L2) += videodev.o
obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index b5a8aac2e126..ddc9379eb276 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -132,7 +132,7 @@ struct tuner {
bool standby; /* Standby mode */
unsigned int type; /* chip type id */
- unsigned int config;
+ void *config;
const char *name;
};
@@ -218,26 +218,6 @@ static void fe_standby(struct dvb_frontend *fe)
fe_tuner_ops->sleep(fe);
}
-static int fe_has_signal(struct dvb_frontend *fe)
-{
- u16 strength = 0;
-
- if (fe->ops.tuner_ops.get_rf_strength)
- fe->ops.tuner_ops.get_rf_strength(fe, &strength);
-
- return strength;
-}
-
-static int fe_get_afc(struct dvb_frontend *fe)
-{
- s32 afc = 0;
-
- if (fe->ops.tuner_ops.get_afc)
- fe->ops.tuner_ops.get_afc(fe, &afc);
-
- return 0;
-}
-
static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
{
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -253,11 +233,9 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg)
static void tuner_status(struct dvb_frontend *fe);
-static struct analog_demod_ops tuner_analog_ops = {
+static const struct analog_demod_ops tuner_analog_ops = {
.set_params = fe_set_params,
.standby = fe_standby,
- .has_signal = fe_has_signal,
- .get_afc = fe_get_afc,
.set_config = fe_set_config,
.tuner_status = tuner_status
};
@@ -272,9 +250,8 @@ static struct analog_demod_ops tuner_analog_ops = {
* @c: i2c_client descriptoy
* @type: type of the tuner (e. g. tuner number)
* @new_mode_mask: Indicates if tuner supports TV and/or Radio
- * @new_config: an optional parameter ranging from 0-255 used by
- a few tuners to adjust an internal parameter,
- like LNA mode
+ * @new_config: an optional parameter used by a few tuners to adjust
+ internal parameters, like LNA mode
* @tuner_callback: an optional function to be called when switching
* to analog mode
*
@@ -282,7 +259,7 @@ static struct analog_demod_ops tuner_analog_ops = {
* by tun_setup structure. It contains several per-tuner initialization "magic"
*/
static void set_type(struct i2c_client *c, unsigned int type,
- unsigned int new_mode_mask, unsigned int new_config,
+ unsigned int new_mode_mask, void *new_config,
int (*tuner_callback) (void *dev, int component, int cmd, int arg))
{
struct tuner *t = to_tuner(i2c_get_clientdata(c));
@@ -297,8 +274,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
t->type = type;
- /* prevent invalid config values */
- t->config = new_config < 256 ? new_config : 0;
+ t->config = new_config;
if (tuner_callback != NULL) {
tuner_dbg("defining GPIO callback\n");
t->fe.callback = tuner_callback;
@@ -316,11 +292,8 @@ static void set_type(struct i2c_client *c, unsigned int type,
break;
case TUNER_PHILIPS_TDA8290:
{
- struct tda829x_config cfg = {
- .lna_cfg = t->config,
- };
if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter,
- t->i2c->addr, &cfg))
+ t->i2c->addr, t->config))
goto attach_failed;
break;
}
@@ -409,7 +382,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
case TUNER_NXP_TDA18271:
{
struct tda18271_config cfg = {
- .config = t->config,
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
@@ -453,6 +425,11 @@ static void set_type(struct i2c_client *c, unsigned int type,
memcpy(analog_ops, &tuner_analog_ops,
sizeof(struct analog_demod_ops));
+ if (fe_tuner_ops->get_rf_strength)
+ analog_ops->has_signal = fe_tuner_ops->get_rf_strength;
+ if (fe_tuner_ops->get_afc)
+ analog_ops->get_afc = fe_tuner_ops->get_afc;
+
} else {
t->name = analog_ops->info.name;
}
@@ -506,7 +483,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd,
struct tuner *t = to_tuner(sd);
struct i2c_client *c = v4l2_get_subdevdata(sd);
- tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n",
+ tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=%p\n",
tun_setup->type,
tun_setup->addr,
tun_setup->mode_mask,
@@ -1073,9 +1050,12 @@ static void tuner_status(struct dvb_frontend *fe)
if (tuner_status & TUNER_STATUS_STEREO)
tuner_info("Stereo: yes\n");
}
- if (analog_ops->has_signal)
- tuner_info("Signal strength: %d\n",
- analog_ops->has_signal(fe));
+ if (analog_ops->has_signal) {
+ u16 signal;
+
+ if (!analog_ops->has_signal(fe, &signal))
+ tuner_info("Signal strength: %hu\n", signal);
+ }
}
/*
@@ -1134,7 +1114,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
return 0;
}
-static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
+static int tuner_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f)
{
struct tuner *t = to_tuner(sd);
@@ -1193,9 +1173,13 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
if (check_mode(t, vt->type) == -EINVAL)
return 0;
if (vt->type == t->mode && analog_ops->get_afc)
- vt->afc = analog_ops->get_afc(&t->fe);
- if (analog_ops->has_signal)
- vt->signal = analog_ops->has_signal(&t->fe);
+ analog_ops->get_afc(&t->fe, &vt->afc);
+ if (vt->type == t->mode && analog_ops->has_signal) {
+ u16 signal = (u16)vt->signal;
+
+ if (!analog_ops->has_signal(&t->fe, &signal))
+ vt->signal = signal;
+ }
if (vt->type != V4L2_TUNER_RADIO) {
vt->capability |= V4L2_TUNER_CAP_NORM;
vt->rangelow = tv_range[0] * 16;
@@ -1233,7 +1217,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
* Note: vt->type should be initialized before calling it.
* This is done by either video_ioctl2 or by the bridge driver.
*/
-static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+static int tuner_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
{
struct tuner *t = to_tuner(sd);
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index aa044f491666..3fed63f4e026 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -230,7 +230,7 @@ EXPORT_SYMBOL(v4l2_ctrl_next);
int v4l2_chip_match_host(const struct v4l2_dbg_match *match)
{
switch (match->type) {
- case V4L2_CHIP_MATCH_HOST:
+ case V4L2_CHIP_MATCH_BRIDGE:
return match->addr == 0;
default:
return 0;
@@ -251,12 +251,11 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match
if (c->driver == NULL || c->driver->driver.name == NULL)
return 0;
len = strlen(c->driver->driver.name);
- /* legacy drivers have a ' suffix, don't try to match that */
- if (len && c->driver->driver.name[len - 1] == '\'')
- len--;
return len && !strncmp(c->driver->driver.name, match->name, len);
case V4L2_CHIP_MATCH_I2C_ADDR:
return c->addr == match->addr;
+ case V4L2_CHIP_MATCH_SUBDEV:
+ return 1;
default:
return 0;
}
@@ -551,53 +550,6 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
EXPORT_SYMBOL_GPL(v4l_bound_align_image);
/**
- * v4l_fill_dv_preset_info - fill description of a digital video preset
- * @preset - preset value
- * @info - pointer to struct v4l2_dv_enum_preset
- *
- * drivers can use this helper function to fill description of dv preset
- * in info.
- */
-int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
-{
- static const struct v4l2_dv_preset_info {
- u16 width;
- u16 height;
- const char *name;
- } dv_presets[] = {
- { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */
- { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */
- { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */
- { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */
- { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */
- { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */
- { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */
- { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */
- { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */
- { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */
- { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */
- { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */
- { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */
- { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */
- { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */
- { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */
- { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */
- { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */
- { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */
- };
-
- if (info == NULL || preset >= ARRAY_SIZE(dv_presets))
- return -EINVAL;
-
- info->preset = preset;
- info->width = dv_presets[preset].width;
- info->height = dv_presets[preset].height;
- strlcpy(info->name, dv_presets[preset].name, sizeof(info->name));
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
-
-/**
* v4l_match_dv_timings - check if two timings match
* @t1 - compare this v4l2_dv_timings struct...
* @t2 - with this struct.
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 7157af301b14..f1295519f285 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -1076,10 +1076,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_G_CHIP_IDENT:
case VIDIOC_S_HW_FREQ_SEEK:
- case VIDIOC_ENUM_DV_PRESETS:
- case VIDIOC_S_DV_PRESET:
- case VIDIOC_G_DV_PRESET:
- case VIDIOC_QUERY_DV_PRESET:
case VIDIOC_S_DV_TIMINGS:
case VIDIOC_G_DV_TIMINGS:
case VIDIOC_DQEVENT:
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 6b28b5800500..ebb8e48619a2 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -234,6 +234,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"Average",
"Center Weighted",
"Spot",
+ "Matrix",
NULL
};
static const char * const camera_auto_focus_range[] = {
@@ -297,8 +298,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"Text",
NULL
};
- static const char * const tune_preemphasis[] = {
- "No Preemphasis",
+ static const char * const tune_emphasis[] = {
+ "None",
"50 Microseconds",
"75 Microseconds",
NULL,
@@ -508,7 +509,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
case V4L2_CID_SCENE_MODE:
return scene_mode;
case V4L2_CID_TUNE_PREEMPHASIS:
- return tune_preemphasis;
+ return tune_emphasis;
+ case V4L2_CID_TUNE_DEEMPHASIS:
+ return tune_emphasis;
case V4L2_CID_FLASH_LED_MODE:
return flash_led_mode;
case V4L2_CID_FLASH_STROBE_SOURCE:
@@ -695,6 +698,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS";
case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count";
case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control";
+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -799,6 +803,9 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present";
case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range";
+ case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls";
+ case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis";
+ case V4L2_CID_RDS_RECEPTION: return "RDS Reception";
default:
return NULL;
}
@@ -844,8 +851,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:
case V4L2_CID_WIDE_DYNAMIC_RANGE:
case V4L2_CID_IMAGE_STABILIZATION:
+ case V4L2_CID_RDS_RECEPTION:
*type = V4L2_CTRL_TYPE_BOOLEAN;
*min = 0;
*max = *step = 1;
@@ -904,6 +913,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_DV_TX_RGB_RANGE:
case V4L2_CID_DV_RX_RGB_RANGE:
case V4L2_CID_TEST_PATTERN:
+ case V4L2_CID_TUNE_DEEMPHASIS:
*type = V4L2_CTRL_TYPE_MENU;
break;
case V4L2_CID_LINK_FREQ:
@@ -926,6 +936,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_IMAGE_SOURCE_CLASS:
case V4L2_CID_IMAGE_PROC_CLASS:
case V4L2_CID_DV_CLASS:
+ case V4L2_CID_FM_RX_CLASS:
*type = V4L2_CTRL_TYPE_CTRL_CLASS;
/* You can neither read not write these */
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -1362,11 +1373,13 @@ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
}
/* Initialize the handler */
-int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
- unsigned nr_of_controls_hint)
+int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint,
+ struct lock_class_key *key, const char *name)
{
hdl->lock = &hdl->_lock;
mutex_init(hdl->lock);
+ lockdep_set_class_and_name(hdl->lock, key, name);
INIT_LIST_HEAD(&hdl->ctrls);
INIT_LIST_HEAD(&hdl->ctrl_refs);
hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
@@ -1375,7 +1388,7 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
hdl->error = hdl->buckets ? 0 : -ENOMEM;
return hdl->error;
}
-EXPORT_SYMBOL(v4l2_ctrl_handler_init);
+EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
/* Free all controls and control refs */
void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index de1e9ab7db99..5923c5dfacd5 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -592,8 +592,9 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
#ifdef CONFIG_VIDEO_ADV_DEBUG
- SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register);
- SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register);
+ set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
+ set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
#endif
SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
/* yes, really vidioc_subscribe_event */
@@ -685,7 +686,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
- SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
}
if (is_tx) {
@@ -708,9 +708,6 @@ static void determine_valid_ioctls(struct video_device *vdev)
(ops->vidioc_g_std || vdev->current_norm)))
set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
- SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets);
- SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset);
- SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset);
SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index aa6e7c788db2..f81bda1a48ec 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -35,6 +35,8 @@
memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
+#define is_valid_ioctl(vfd, cmd) test_bit(_IOC_NR(cmd), (vfd)->valid_ioctls)
+
struct std_descr {
v4l2_std_id std;
const char *descr;
@@ -167,9 +169,11 @@ static void v4l_print_querycap(const void *arg, bool write_only)
{
const struct v4l2_capability *p = arg;
- pr_cont("driver=%s, card=%s, bus=%s, version=0x%08x, "
+ pr_cont("driver=%.*s, card=%.*s, bus=%.*s, version=0x%08x, "
"capabilities=0x%08x, device_caps=0x%08x\n",
- p->driver, p->card, p->bus_info,
+ (int)sizeof(p->driver), p->driver,
+ (int)sizeof(p->card), p->card,
+ (int)sizeof(p->bus_info), p->bus_info,
p->version, p->capabilities, p->device_caps);
}
@@ -177,20 +181,21 @@ static void v4l_print_enuminput(const void *arg, bool write_only)
{
const struct v4l2_input *p = arg;
- pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, tuner=%u, "
+ pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, tuner=%u, "
"std=0x%08Lx, status=0x%x, capabilities=0x%x\n",
- p->index, p->name, p->type, p->audioset, p->tuner,
- (unsigned long long)p->std, p->status, p->capabilities);
+ p->index, (int)sizeof(p->name), p->name, p->type, p->audioset,
+ p->tuner, (unsigned long long)p->std, p->status,
+ p->capabilities);
}
static void v4l_print_enumoutput(const void *arg, bool write_only)
{
const struct v4l2_output *p = arg;
- pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, "
+ pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, "
"modulator=%u, std=0x%08Lx, capabilities=0x%x\n",
- p->index, p->name, p->type, p->audioset, p->modulator,
- (unsigned long long)p->std, p->capabilities);
+ p->index, (int)sizeof(p->name), p->name, p->type, p->audioset,
+ p->modulator, (unsigned long long)p->std, p->capabilities);
}
static void v4l_print_audio(const void *arg, bool write_only)
@@ -200,8 +205,9 @@ static void v4l_print_audio(const void *arg, bool write_only)
if (write_only)
pr_cont("index=%u, mode=0x%x\n", p->index, p->mode);
else
- pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n",
- p->index, p->name, p->capability, p->mode);
+ pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n",
+ p->index, (int)sizeof(p->name), p->name,
+ p->capability, p->mode);
}
static void v4l_print_audioout(const void *arg, bool write_only)
@@ -211,21 +217,22 @@ static void v4l_print_audioout(const void *arg, bool write_only)
if (write_only)
pr_cont("index=%u\n", p->index);
else
- pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n",
- p->index, p->name, p->capability, p->mode);
+ pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n",
+ p->index, (int)sizeof(p->name), p->name,
+ p->capability, p->mode);
}
static void v4l_print_fmtdesc(const void *arg, bool write_only)
{
const struct v4l2_fmtdesc *p = arg;
- pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%s'\n",
+ pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%.*s'\n",
p->index, prt_names(p->type, v4l2_type_names),
p->flags, (p->pixelformat & 0xff),
(p->pixelformat >> 8) & 0xff,
(p->pixelformat >> 16) & 0xff,
(p->pixelformat >> 24) & 0xff,
- p->description);
+ (int)sizeof(p->description), p->description);
}
static void v4l_print_format(const void *arg, bool write_only)
@@ -348,9 +355,9 @@ static void v4l_print_modulator(const void *arg, bool write_only)
if (write_only)
pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans);
else
- pr_cont("index=%u, name=%s, capability=0x%x, "
+ pr_cont("index=%u, name=%.*s, capability=0x%x, "
"rangelow=%u, rangehigh=%u, txsubchans=0x%x\n",
- p->index, p->name, p->capability,
+ p->index, (int)sizeof(p->name), p->name, p->capability,
p->rangelow, p->rangehigh, p->txsubchans);
}
@@ -361,10 +368,10 @@ static void v4l_print_tuner(const void *arg, bool write_only)
if (write_only)
pr_cont("index=%u, audmode=%u\n", p->index, p->audmode);
else
- pr_cont("index=%u, name=%s, type=%u, capability=0x%x, "
+ pr_cont("index=%u, name=%.*s, type=%u, capability=0x%x, "
"rangelow=%u, rangehigh=%u, signal=%u, afc=%d, "
"rxsubchans=0x%x, audmode=%u\n",
- p->index, p->name, p->type,
+ p->index, (int)sizeof(p->name), p->name, p->type,
p->capability, p->rangelow,
p->rangehigh, p->signal, p->afc,
p->rxsubchans, p->audmode);
@@ -382,9 +389,9 @@ static void v4l_print_standard(const void *arg, bool write_only)
{
const struct v4l2_standard *p = arg;
- pr_cont("index=%u, id=0x%Lx, name=%s, fps=%u/%u, "
+ pr_cont("index=%u, id=0x%Lx, name=%.*s, fps=%u/%u, "
"framelines=%u\n", p->index,
- (unsigned long long)p->id, p->name,
+ (unsigned long long)p->id, (int)sizeof(p->name), p->name,
p->frameperiod.numerator,
p->frameperiod.denominator,
p->framelines);
@@ -504,9 +511,9 @@ static void v4l_print_queryctrl(const void *arg, bool write_only)
{
const struct v4l2_queryctrl *p = arg;
- pr_cont("id=0x%x, type=%d, name=%s, min/max=%d/%d, "
+ pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%d/%d, "
"step=%d, default=%d, flags=0x%08x\n",
- p->id, p->type, p->name,
+ p->id, p->type, (int)sizeof(p->name), p->name,
p->minimum, p->maximum,
p->step, p->default_value, p->flags);
}
@@ -623,39 +630,39 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only)
pr_cont("type=%u, ", p->match.type);
if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
- pr_cont("name=%s, ", p->match.name);
+ pr_cont("name=%.*s, ",
+ (int)sizeof(p->match.name), p->match.name);
else
pr_cont("addr=%u, ", p->match.addr);
pr_cont("chip_ident=%u, revision=0x%x\n",
p->ident, p->revision);
}
-static void v4l_print_dbg_register(const void *arg, bool write_only)
+static void v4l_print_dbg_chip_info(const void *arg, bool write_only)
{
- const struct v4l2_dbg_register *p = arg;
+ const struct v4l2_dbg_chip_info *p = arg;
pr_cont("type=%u, ", p->match.type);
if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
- pr_cont("name=%s, ", p->match.name);
+ pr_cont("name=%.*s, ",
+ (int)sizeof(p->match.name), p->match.name);
else
pr_cont("addr=%u, ", p->match.addr);
- pr_cont("reg=0x%llx, val=0x%llx\n",
- p->reg, p->val);
+ pr_cont("name=%.*s\n", (int)sizeof(p->name), p->name);
}
-static void v4l_print_dv_enum_presets(const void *arg, bool write_only)
-{
- const struct v4l2_dv_enum_preset *p = arg;
-
- pr_cont("index=%u, preset=%u, name=%s, width=%u, height=%u\n",
- p->index, p->preset, p->name, p->width, p->height);
-}
-
-static void v4l_print_dv_preset(const void *arg, bool write_only)
+static void v4l_print_dbg_register(const void *arg, bool write_only)
{
- const struct v4l2_dv_preset *p = arg;
+ const struct v4l2_dbg_register *p = arg;
- pr_cont("preset=%u\n", p->preset);
+ pr_cont("type=%u, ", p->match.type);
+ if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ pr_cont("name=%.*s, ",
+ (int)sizeof(p->match.name), p->match.name);
+ else
+ pr_cont("addr=%u, ", p->match.addr);
+ pr_cont("reg=0x%llx, val=0x%llx\n",
+ p->reg, p->val);
}
static void v4l_print_dv_timings(const void *arg, bool write_only)
@@ -997,20 +1004,17 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,
static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vfd = video_devdata(file);
struct v4l2_input *p = arg;
/*
- * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS &
+ * We set the flags for CAP_DV_TIMINGS &
* CAP_STD here based on ioctl handler provided by the
* driver. If the driver doesn't support these
* for a specific input, it must override these flags.
*/
- if (ops->vidioc_s_std)
+ if (is_valid_ioctl(vfd, VIDIOC_S_STD))
p->capabilities |= V4L2_IN_CAP_STD;
- if (ops->vidioc_s_dv_preset)
- p->capabilities |= V4L2_IN_CAP_PRESETS;
- if (ops->vidioc_s_dv_timings)
- p->capabilities |= V4L2_IN_CAP_DV_TIMINGS;
return ops->vidioc_enum_input(file, fh, p);
}
@@ -1018,20 +1022,17 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
+ struct video_device *vfd = video_devdata(file);
struct v4l2_output *p = arg;
/*
- * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS &
+ * We set the flags for CAP_DV_TIMINGS &
* CAP_STD here based on ioctl handler provided by the
* driver. If the driver doesn't support these
* for a specific output, it must override these flags.
*/
- if (ops->vidioc_s_std)
+ if (is_valid_ioctl(vfd, VIDIOC_S_STD))
p->capabilities |= V4L2_OUT_CAP_STD;
- if (ops->vidioc_s_dv_preset)
- p->capabilities |= V4L2_OUT_CAP_PRESETS;
- if (ops->vidioc_s_dv_timings)
- p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS;
return ops->vidioc_enum_output(file, fh, p);
}
@@ -1316,7 +1317,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct video_device *vfd = video_devdata(file);
- struct v4l2_frequency *p = arg;
+ const struct v4l2_frequency *p = arg;
enum v4l2_tuner_type type;
type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
@@ -1383,15 +1384,15 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct video_device *vfd = video_devdata(file);
- v4l2_std_id *id = arg, norm;
+ v4l2_std_id id = *(v4l2_std_id *)arg, norm;
int ret;
- norm = (*id) & vfd->tvnorms;
+ norm = id & vfd->tvnorms;
if (vfd->tvnorms && !norm) /* Check if std is supported */
return -EINVAL;
/* Calls the specific handler */
- ret = ops->vidioc_s_std(file, fh, &norm);
+ ret = ops->vidioc_s_std(file, fh, norm);
/* Updates standard information */
if (ret >= 0)
@@ -1513,7 +1514,7 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops,
p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return -EINVAL;
p->parm.capture.readbuffers = 2;
- if (ops->vidioc_g_std)
+ if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std)
ret = ops->vidioc_g_std(file, fh, &std);
if (ret == 0)
v4l2_video_std_frame_period(std,
@@ -1792,10 +1793,23 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops,
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
struct v4l2_dbg_register *p = arg;
+ struct video_device *vfd = video_devdata(file);
+ struct v4l2_subdev *sd;
+ int idx = 0;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- return ops->vidioc_g_register(file, fh, p);
+ if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) {
+ if (vfd->v4l2_dev == NULL)
+ return -EINVAL;
+ v4l2_device_for_each_subdev(sd, vfd->v4l2_dev)
+ if (p->match.addr == idx++)
+ return v4l2_subdev_call(sd, core, g_register, p);
+ return -EINVAL;
+ }
+ if (ops->vidioc_g_register)
+ return ops->vidioc_g_register(file, fh, p);
+ return -EINVAL;
#else
return -ENOTTY;
#endif
@@ -1805,11 +1819,24 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct v4l2_dbg_register *p = arg;
+ const struct v4l2_dbg_register *p = arg;
+ struct video_device *vfd = video_devdata(file);
+ struct v4l2_subdev *sd;
+ int idx = 0;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- return ops->vidioc_s_register(file, fh, p);
+ if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) {
+ if (vfd->v4l2_dev == NULL)
+ return -EINVAL;
+ v4l2_device_for_each_subdev(sd, vfd->v4l2_dev)
+ if (p->match.addr == idx++)
+ return v4l2_subdev_call(sd, core, s_register, p);
+ return -EINVAL;
+ }
+ if (ops->vidioc_s_register)
+ return ops->vidioc_s_register(file, fh, p);
+ return -EINVAL;
#else
return -ENOTTY;
#endif
@@ -1822,9 +1849,59 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops,
p->ident = V4L2_IDENT_NONE;
p->revision = 0;
+ if (p->match.type == V4L2_CHIP_MATCH_SUBDEV)
+ return -EINVAL;
return ops->vidioc_g_chip_ident(file, fh, p);
}
+static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops,
+ struct file *file, void *fh, void *arg)
+{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ struct video_device *vfd = video_devdata(file);
+ struct v4l2_dbg_chip_info *p = arg;
+ struct v4l2_subdev *sd;
+ int idx = 0;
+
+ switch (p->match.type) {
+ case V4L2_CHIP_MATCH_BRIDGE:
+ if (ops->vidioc_s_register)
+ p->flags |= V4L2_CHIP_FL_WRITABLE;
+ if (ops->vidioc_g_register)
+ p->flags |= V4L2_CHIP_FL_READABLE;
+ if (vfd->v4l2_dev)
+ strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name));
+ else if (vfd->parent)
+ strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name));
+ else
+ strlcpy(p->name, "bridge", sizeof(p->name));
+ if (ops->vidioc_g_chip_info)
+ return ops->vidioc_g_chip_info(file, fh, arg);
+ if (p->match.addr)
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CHIP_MATCH_SUBDEV:
+ if (vfd->v4l2_dev == NULL)
+ break;
+ v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) {
+ if (p->match.addr != idx++)
+ continue;
+ if (sd->ops->core && sd->ops->core->s_register)
+ p->flags |= V4L2_CHIP_FL_WRITABLE;
+ if (sd->ops->core && sd->ops->core->g_register)
+ p->flags |= V4L2_CHIP_FL_READABLE;
+ strlcpy(p->name, sd->name, sizeof(p->name));
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+#else
+ return -ENOTTY;
+#endif
+}
+
static int v4l_dqevent(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
@@ -1873,7 +1950,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
return -EINVAL;
if (ops->vidioc_enum_freq_bands)
return ops->vidioc_enum_freq_bands(file, fh, p);
- if (ops->vidioc_g_tuner) {
+ if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) {
struct v4l2_tuner t = {
.index = p->tuner,
.type = type,
@@ -1891,7 +1968,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB;
return 0;
}
- if (ops->vidioc_g_modulator) {
+ if (is_valid_ioctl(vfd, VIDIOC_G_MODULATOR)) {
struct v4l2_modulator m = {
.index = p->tuner,
};
@@ -2028,10 +2105,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0),
IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0),
IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO),
- IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0),
- IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO),
- IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0),
- IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0),
IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO),
IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0),
IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0),
@@ -2043,6 +2116,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0),
IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)),
IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0),
+ IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)),
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -2147,11 +2221,6 @@ static long __video_do_ioctl(struct file *file,
}
write_only = _IOC_DIR(cmd) == _IOC_WRITE;
- if (write_only && debug > V4L2_DEBUG_IOCTL) {
- v4l_printk_ioctl(video_device_node_name(vfd), cmd);
- pr_cont(": ");
- info->debug(arg, write_only);
- }
if (info->flags & INFO_FL_STD) {
typedef int (*vidioc_op)(struct file *file, void *fh, void *p);
const void *p = vfd->ioctl_ops;
@@ -2170,16 +2239,10 @@ static long __video_do_ioctl(struct file *file,
done:
if (debug) {
- if (write_only && debug > V4L2_DEBUG_IOCTL) {
- if (ret < 0)
- printk(KERN_DEBUG "%s: error %ld\n",
- video_device_node_name(vfd), ret);
- return ret;
- }
v4l_printk_ioctl(video_device_node_name(vfd), cmd);
if (ret < 0)
- pr_cont(": error %ld\n", ret);
- else if (debug == V4L2_DEBUG_IOCTL)
+ pr_cont(": error %ld", ret);
+ if (debug == V4L2_DEBUG_IOCTL)
pr_cont("\n");
else if (_IOC_DIR(cmd) == _IOC_NONE)
info->debug(arg, write_only);
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index da99cf727162..66f599fcb829 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -230,12 +230,15 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
dprintk("No input buffers available\n");
return;
}
+ spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags);
if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) {
+ spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags);
spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
dprintk("No output buffers available\n");
return;
}
+ spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags);
spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags);
if (m2m_dev->m2m_ops->job_ready
@@ -405,10 +408,35 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamon);
int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
enum v4l2_buf_type type)
{
- struct vb2_queue *vq;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct v4l2_m2m_queue_ctx *q_ctx;
+ unsigned long flags_job, flags;
+ int ret;
- vq = v4l2_m2m_get_vq(m2m_ctx, type);
- return vb2_streamoff(vq, type);
+ q_ctx = get_queue_ctx(m2m_ctx, type);
+ ret = vb2_streamoff(&q_ctx->q, type);
+ if (ret)
+ return ret;
+
+ m2m_dev = m2m_ctx->m2m_dev;
+ spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job);
+ /* We should not be scheduled anymore, since we're dropping a queue. */
+ INIT_LIST_HEAD(&m2m_ctx->queue);
+ m2m_ctx->job_flags = 0;
+
+ spin_lock_irqsave(&q_ctx->rdy_spinlock, flags);
+ /* Drop queue, since streamoff returns device to the same state as after
+ * calling reqbufs. */
+ INIT_LIST_HEAD(&q_ctx->rdy_queue);
+ spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
+
+ if (m2m_dev->curr_ctx == m2m_ctx) {
+ m2m_dev->curr_ctx = NULL;
+ wake_up(&m2m_ctx->finished);
+ }
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c
new file mode 100644
index 000000000000..aa59639d013c
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-of.c
@@ -0,0 +1,266 @@
+/*
+ * V4L2 OF binding parsing library
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Copyright (C) 2012 Renesas Electronics Corp.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <media/v4l2-of.h>
+
+static void v4l2_of_parse_csi_bus(const struct device_node *node,
+ struct v4l2_of_endpoint *endpoint)
+{
+ struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2;
+ u32 data_lanes[ARRAY_SIZE(bus->data_lanes)];
+ struct property *prop;
+ bool have_clk_lane = false;
+ unsigned int flags = 0;
+ u32 v;
+
+ prop = of_find_property(node, "data-lanes", NULL);
+ if (prop) {
+ const __be32 *lane = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(data_lanes); i++) {
+ lane = of_prop_next_u32(prop, lane, &data_lanes[i]);
+ if (!lane)
+ break;
+ }
+ bus->num_data_lanes = i;
+ while (i--)
+ bus->data_lanes[i] = data_lanes[i];
+ }
+
+ if (!of_property_read_u32(node, "clock-lanes", &v)) {
+ bus->clock_lane = v;
+ have_clk_lane = true;
+ }
+
+ if (of_get_property(node, "clock-noncontinuous", &v))
+ flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
+ else if (have_clk_lane || bus->num_data_lanes > 0)
+ flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+ bus->flags = flags;
+ endpoint->bus_type = V4L2_MBUS_CSI2;
+}
+
+static void v4l2_of_parse_parallel_bus(const struct device_node *node,
+ struct v4l2_of_endpoint *endpoint)
+{
+ struct v4l2_of_bus_parallel *bus = &endpoint->bus.parallel;
+ unsigned int flags = 0;
+ u32 v;
+
+ if (!of_property_read_u32(node, "hsync-active", &v))
+ flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
+ V4L2_MBUS_HSYNC_ACTIVE_LOW;
+
+ if (!of_property_read_u32(node, "vsync-active", &v))
+ flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
+ V4L2_MBUS_VSYNC_ACTIVE_LOW;
+
+ if (!of_property_read_u32(node, "pclk-sample", &v))
+ flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
+ V4L2_MBUS_PCLK_SAMPLE_FALLING;
+
+ if (!of_property_read_u32(node, "field-even-active", &v))
+ flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
+ V4L2_MBUS_FIELD_EVEN_LOW;
+ if (flags)
+ endpoint->bus_type = V4L2_MBUS_PARALLEL;
+ else
+ endpoint->bus_type = V4L2_MBUS_BT656;
+
+ if (!of_property_read_u32(node, "data-active", &v))
+ flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
+ V4L2_MBUS_DATA_ACTIVE_LOW;
+
+ if (of_get_property(node, "slave-mode", &v))
+ flags |= V4L2_MBUS_SLAVE;
+ else
+ flags |= V4L2_MBUS_MASTER;
+
+ if (!of_property_read_u32(node, "bus-width", &v))
+ bus->bus_width = v;
+
+ if (!of_property_read_u32(node, "data-shift", &v))
+ bus->data_shift = v;
+
+ bus->flags = flags;
+
+}
+
+/**
+ * v4l2_of_parse_endpoint() - parse all endpoint node properties
+ * @node: pointer to endpoint device_node
+ * @endpoint: pointer to the V4L2 OF endpoint data structure
+ *
+ * All properties are optional. If none are found, we don't set any flags.
+ * This means the port has a static configuration and no properties have
+ * to be specified explicitly.
+ * If any properties that identify the bus as parallel are found and
+ * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise
+ * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
+ * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
+ * The caller should hold a reference to @node.
+ */
+void v4l2_of_parse_endpoint(const struct device_node *node,
+ struct v4l2_of_endpoint *endpoint)
+{
+ struct device_node *port_node = of_get_parent(node);
+
+ memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head));
+
+ endpoint->local_node = node;
+ /*
+ * It doesn't matter whether the two calls below succeed.
+ * If they don't then the default value 0 is used.
+ */
+ of_property_read_u32(port_node, "reg", &endpoint->port);
+ of_property_read_u32(node, "reg", &endpoint->id);
+
+ v4l2_of_parse_csi_bus(node, endpoint);
+ /*
+ * Parse the parallel video bus properties only if none
+ * of the MIPI CSI-2 specific properties were found.
+ */
+ if (endpoint->bus.mipi_csi2.flags == 0)
+ v4l2_of_parse_parallel_bus(node, endpoint);
+
+ of_node_put(port_node);
+}
+EXPORT_SYMBOL(v4l2_of_parse_endpoint);
+
+/**
+ * v4l2_of_get_next_endpoint() - get next endpoint node
+ * @parent: pointer to the parent device node
+ * @prev: previous endpoint node, or NULL to get first
+ *
+ * Return: An 'endpoint' node pointer with refcount incremented. Refcount
+ * of the passed @prev node is not decremented, the caller have to use
+ * of_node_put() on it when done.
+ */
+struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
+ struct device_node *prev)
+{
+ struct device_node *endpoint;
+ struct device_node *port = NULL;
+
+ if (!parent)
+ return NULL;
+
+ if (!prev) {
+ struct device_node *node;
+ /*
+ * It's the first call, we have to find a port subnode
+ * within this node or within an optional 'ports' node.
+ */
+ node = of_get_child_by_name(parent, "ports");
+ if (node)
+ parent = node;
+
+ for_each_child_of_node(parent, node) {
+ if (!of_node_cmp(node->name, "port")) {
+ port = node;
+ break;
+ }
+ }
+ if (port) {
+ /* Found a port, get an endpoint. */
+ endpoint = of_get_next_child(port, NULL);
+ of_node_put(port);
+ } else {
+ endpoint = NULL;
+ }
+
+ if (!endpoint)
+ pr_err("%s(): no endpoint nodes specified for %s\n",
+ __func__, parent->full_name);
+ } else {
+ port = of_get_parent(prev);
+ if (!port)
+ /* Hm, has someone given us the root node ?... */
+ return NULL;
+
+ /* Avoid dropping prev node refcount to 0. */
+ of_node_get(prev);
+ endpoint = of_get_next_child(port, prev);
+ if (endpoint) {
+ of_node_put(port);
+ return endpoint;
+ }
+
+ /* No more endpoints under this port, try the next one. */
+ do {
+ port = of_get_next_child(parent, port);
+ if (!port)
+ return NULL;
+ } while (of_node_cmp(port->name, "port"));
+
+ /* Pick up the first endpoint in this port. */
+ endpoint = of_get_next_child(port, NULL);
+ of_node_put(port);
+ }
+
+ return endpoint;
+}
+EXPORT_SYMBOL(v4l2_of_get_next_endpoint);
+
+/**
+ * v4l2_of_get_remote_port_parent() - get remote port's parent node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote device node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *v4l2_of_get_remote_port_parent(
+ const struct device_node *node)
+{
+ struct device_node *np;
+ unsigned int depth;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+
+ /* Walk 3 levels up only if there is 'ports' node. */
+ for (depth = 3; depth && np; depth--) {
+ np = of_get_next_parent(np);
+ if (depth == 2 && of_node_cmp(np->name, "ports"))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(v4l2_of_get_remote_port_parent);
+
+/**
+ * v4l2_of_get_remote_port() - get remote port node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote port node associated with remote endpoint node linked
+ * to @node. Use of_node_put() on it when done.
+ */
+struct device_node *v4l2_of_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ /* Get remote endpoint node. */
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+ return of_get_parent(np);
+}
+EXPORT_SYMBOL(v4l2_of_get_remote_port);
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 3a43ba0959bf..67f572c3fba2 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -27,7 +27,6 @@ struct videobuf_dma_contig_memory {
u32 magic;
void *vaddr;
dma_addr_t dma_handle;
- bool cached;
unsigned long size;
};
@@ -43,26 +42,8 @@ static int __videobuf_dc_alloc(struct device *dev,
unsigned long size, gfp_t flags)
{
mem->size = size;
- if (mem->cached) {
- mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA);
- if (mem->vaddr) {
- int err;
-
- mem->dma_handle = dma_map_single(dev, mem->vaddr,
- mem->size,
- DMA_FROM_DEVICE);
- err = dma_mapping_error(dev, mem->dma_handle);
- if (err) {
- dev_err(dev, "dma_map_single failed\n");
-
- free_pages_exact(mem->vaddr, mem->size);
- mem->vaddr = NULL;
- return err;
- }
- }
- } else
- mem->vaddr = dma_alloc_coherent(dev, mem->size,
- &mem->dma_handle, flags);
+ mem->vaddr = dma_alloc_coherent(dev, mem->size,
+ &mem->dma_handle, flags);
if (!mem->vaddr) {
dev_err(dev, "memory alloc size %ld failed\n", mem->size);
@@ -77,14 +58,7 @@ static int __videobuf_dc_alloc(struct device *dev,
static void __videobuf_dc_free(struct device *dev,
struct videobuf_dma_contig_memory *mem)
{
- if (mem->cached) {
- if (!mem->vaddr)
- return;
- dma_unmap_single(dev, mem->dma_handle, mem->size,
- DMA_FROM_DEVICE);
- free_pages_exact(mem->vaddr, mem->size);
- } else
- dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
+ dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
mem->vaddr = NULL;
}
@@ -234,7 +208,7 @@ out_up:
return ret;
}
-static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
+static struct videobuf_buffer *__videobuf_alloc(size_t size)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
@@ -244,22 +218,11 @@ static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
vb->priv = ((char *)vb) + size;
mem = vb->priv;
mem->magic = MAGIC_DC_MEM;
- mem->cached = cached;
}
return vb;
}
-static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size)
-{
- return __videobuf_alloc_vb(size, false);
-}
-
-static struct videobuf_buffer *__videobuf_alloc_cached(size_t size)
-{
- return __videobuf_alloc_vb(size, true);
-}
-
static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -310,19 +273,6 @@ static int __videobuf_iolock(struct videobuf_queue *q,
return 0;
}
-static int __videobuf_sync(struct videobuf_queue *q,
- struct videobuf_buffer *buf)
-{
- struct videobuf_dma_contig_memory *mem = buf->priv;
- BUG_ON(!mem);
- MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
- dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
- DMA_FROM_DEVICE);
-
- return 0;
-}
-
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_buffer *buf,
struct vm_area_struct *vma)
@@ -331,8 +281,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_mapping *map;
int retval;
unsigned long size;
- unsigned long pos, start = vma->vm_start;
- struct page *page;
dev_dbg(q->dev, "%s\n", __func__);
@@ -359,43 +307,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
size = vma->vm_end - vma->vm_start;
size = (size < mem->size) ? size : mem->size;
- if (!mem->cached) {
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = remap_pfn_range(vma, vma->vm_start,
- mem->dma_handle >> PAGE_SHIFT,
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ retval = remap_pfn_range(vma, vma->vm_start,
+ mem->dma_handle >> PAGE_SHIFT,
size, vma->vm_page_prot);
- if (retval) {
- dev_err(q->dev, "mmap: remap failed with error %d. ",
- retval);
- dma_free_coherent(q->dev, mem->size,
- mem->vaddr, mem->dma_handle);
- goto error;
- }
- } else {
- pos = (unsigned long)mem->vaddr;
-
- while (size > 0) {
- page = virt_to_page((void *)pos);
- if (NULL == page) {
- dev_err(q->dev, "mmap: virt_to_page failed\n");
- __videobuf_dc_free(q->dev, mem);
- goto error;
- }
- retval = vm_insert_page(vma, start, page);
- if (retval) {
- dev_err(q->dev, "mmap: insert failed with error %d\n",
- retval);
- __videobuf_dc_free(q->dev, mem);
- goto error;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
-
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
+ if (retval) {
+ dev_err(q->dev, "mmap: remap failed with error %d. ",
+ retval);
+ dma_free_coherent(q->dev, mem->size,
+ mem->vaddr, mem->dma_handle);
+ goto error;
}
vma->vm_ops = &videobuf_vm_ops;
@@ -417,17 +338,8 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc_vb = __videobuf_alloc_uncached,
- .iolock = __videobuf_iolock,
- .mmap_mapper = __videobuf_mmap_mapper,
- .vaddr = __videobuf_to_vaddr,
-};
-
-static struct videobuf_qtype_ops qops_cached = {
- .magic = MAGIC_QTYPE_OPS,
- .alloc_vb = __videobuf_alloc_cached,
+ .alloc_vb = __videobuf_alloc,
.iolock = __videobuf_iolock,
- .sync = __videobuf_sync,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = __videobuf_to_vaddr,
};
@@ -447,20 +359,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
}
EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
-void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
- const struct videobuf_queue_ops *ops,
- struct device *dev,
- spinlock_t *irqlock,
- enum v4l2_buf_type type,
- enum v4l2_field field,
- unsigned int msize,
- void *priv, struct mutex *ext_lock)
-{
- videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &qops_cached, ext_lock);
-}
-EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached);
-
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index db1235dcb328..7d833eefaf4e 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -54,10 +54,15 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
void *mem_priv;
int plane;
- /* Allocate memory for all planes in this buffer */
+ /*
+ * Allocate memory for all planes in this buffer
+ * NOTE: mmapped areas should be page aligned
+ */
for (plane = 0; plane < vb->num_planes; ++plane) {
+ unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
+
mem_priv = call_memop(q, alloc, q->alloc_ctx[plane],
- q->plane_sizes[plane]);
+ size, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -403,7 +408,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
* Clear any buffer state related flags.
*/
b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
- b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ b->flags |= q->timestamp_type;
switch (vb->state) {
case VB2_BUF_STATE_QUEUED:
@@ -855,7 +860,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
return;
dprintk(4, "Done processing on buffer %d, state: %d\n",
- vb->v4l2_buf.index, vb->state);
+ vb->v4l2_buf.index, state);
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
@@ -1852,6 +1857,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
struct vb2_buffer *vb;
unsigned int buffer, plane;
int ret;
+ unsigned long length;
if (q->memory != V4L2_MEMORY_MMAP) {
dprintk(1, "Queue is not currently set up for mmap\n");
@@ -1886,6 +1892,18 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
vb = q->bufs[buffer];
+ /*
+ * MMAP requires page_aligned buffers.
+ * The buffer length was page_aligned at __vb2_buf_mem_alloc(),
+ * so, we need to do the same here.
+ */
+ length = PAGE_ALIGN(vb->v4l2_planes[plane].length);
+ if (length < (vma->vm_end - vma->vm_start)) {
+ dprintk(1,
+ "MMAP invalid, as it would overflow buffer length\n");
+ return -EINVAL;
+ }
+
ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma);
if (ret)
return ret;
@@ -2039,9 +2057,13 @@ int vb2_queue_init(struct vb2_queue *q)
WARN_ON(!q->type) ||
WARN_ON(!q->io_modes) ||
WARN_ON(!q->ops->queue_setup) ||
- WARN_ON(!q->ops->buf_queue))
+ WARN_ON(!q->ops->buf_queue) ||
+ WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK))
return -EINVAL;
+ /* Warn that the driver should choose an appropriate timestamp type */
+ WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN);
+
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 10beaee7f0ae..fd56f2563201 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -152,7 +152,7 @@ static void vb2_dc_put(void *buf_priv)
kfree(buf);
}
-static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size)
+static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
{
struct vb2_dc_conf *conf = alloc_ctx;
struct device *dev = conf->dev;
@@ -162,10 +162,8 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size)
if (!buf)
return ERR_PTR(-ENOMEM);
- /* align image size to PAGE_SIZE */
- size = PAGE_ALIGN(size);
-
- buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL);
+ buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr,
+ GFP_KERNEL | gfp_flags);
if (!buf->vaddr) {
dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size);
kfree(buf);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 25c3b360e1ad..16ae3dcc7e29 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -21,6 +21,15 @@
#include <media/videobuf2-memops.h>
#include <media/videobuf2-dma-sg.h>
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "vb2-dma-sg: " fmt, ## arg); \
+ } while (0)
+
struct vb2_dma_sg_buf {
void *vaddr;
struct page **pages;
@@ -33,7 +42,7 @@ struct vb2_dma_sg_buf {
static void vb2_dma_sg_put(void *buf_priv);
-static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
+static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
{
struct vb2_dma_sg_buf *buf;
int i;
@@ -46,7 +55,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
buf->write = 0;
buf->offset = 0;
buf->sg_desc.size = size;
- buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ /* size is already page aligned */
+ buf->sg_desc.num_pages = size >> PAGE_SHIFT;
buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages *
sizeof(*buf->sg_desc.sglist));
@@ -60,7 +70,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
goto fail_pages_array_alloc;
for (i = 0; i < buf->sg_desc.num_pages; ++i) {
- buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
+ buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO |
+ __GFP_NOWARN | gfp_flags);
if (NULL == buf->pages[i])
goto fail_pages_alloc;
sg_set_page(&buf->sg_desc.sglist[i],
@@ -73,7 +84,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size)
atomic_inc(&buf->refcount);
- printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n",
+ dprintk(1, "%s: Allocated buffer of %d pages\n",
__func__, buf->sg_desc.num_pages);
return buf;
@@ -96,7 +107,7 @@ static void vb2_dma_sg_put(void *buf_priv)
int i = buf->sg_desc.num_pages;
if (atomic_dec_and_test(&buf->refcount)) {
- printk(KERN_DEBUG "%s: Freeing buffer of %d pages\n", __func__,
+ dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
buf->sg_desc.num_pages);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
@@ -162,7 +173,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
return buf;
userptr_fail_get_user_pages:
- printk(KERN_DEBUG "get_user_pages requested/got: %d/%d]\n",
+ dprintk(1, "get_user_pages requested/got: %d/%d]\n",
num_pages_from_user, buf->sg_desc.num_pages);
while (--num_pages_from_user >= 0)
put_page(buf->pages[num_pages_from_user]);
@@ -185,7 +196,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
struct vb2_dma_sg_buf *buf = buf_priv;
int i = buf->sg_desc.num_pages;
- printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n",
+ dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
__func__, buf->sg_desc.num_pages);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages);
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index a47fd4f589a1..313d9771b2bc 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -35,11 +35,11 @@ struct vb2_vmalloc_buf {
static void vb2_vmalloc_put(void *buf_priv);
-static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size)
+static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
{
struct vb2_vmalloc_buf *buf;
- buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags);
if (!buf)
return NULL;
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index df0873694858..cadf1cc19aaf 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <linux/pm.h>
#include <memory/jedec_ddr.h>
#include "emif.h"
#include "of_memory.h"
@@ -256,6 +257,41 @@ static void set_lpmode(struct emif_data *emif, u8 lpmode)
u32 temp;
void __iomem *base = emif->base;
+ /*
+ * Workaround for errata i743 - LPDDR2 Power-Down State is Not
+ * Efficient
+ *
+ * i743 DESCRIPTION:
+ * The EMIF supports power-down state for low power. The EMIF
+ * automatically puts the SDRAM into power-down after the memory is
+ * not accessed for a defined number of cycles and the
+ * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set to 0x4.
+ * As the EMIF supports automatic output impedance calibration, a ZQ
+ * calibration long command is issued every time it exits active
+ * power-down and precharge power-down modes. The EMIF waits and
+ * blocks any other command during this calibration.
+ * The EMIF does not allow selective disabling of ZQ calibration upon
+ * exit of power-down mode. Due to very short periods of power-down
+ * cycles, ZQ calibration overhead creates bandwidth issues and
+ * increases overall system power consumption. On the other hand,
+ * issuing ZQ calibration long commands when exiting self-refresh is
+ * still required.
+ *
+ * WORKAROUND
+ * Because there is no power consumption benefit of the power-down due
+ * to the calibration and there is a performance risk, the guideline
+ * is to not allow power-down state and, therefore, to not have set
+ * the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field to 0x4.
+ */
+ if ((emif->plat_data->ip_rev == EMIF_4D) &&
+ (EMIF_LP_MODE_PWR_DN == lpmode)) {
+ WARN_ONCE(1,
+ "REG_LP_MODE = LP_MODE_PWR_DN(4) is prohibited by"
+ "erratum i743 switch to LP_MODE_SELF_REFRESH(2)\n");
+ /* rollback LP_MODE to Self-refresh mode */
+ lpmode = EMIF_LP_MODE_SELF_REFRESH;
+ }
+
temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
temp &= ~LP_MODE_MASK;
temp |= (lpmode << LP_MODE_SHIFT);
@@ -715,6 +751,8 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
u32 timeout_perf = EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER;
u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD;
+ u32 mask;
+ u8 shift;
struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
@@ -728,37 +766,59 @@ static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
/* Timeout based on DDR frequency */
timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
- /* The value to be set in register is "log2(timeout) - 3" */
+ /*
+ * The value to be set in register is "log2(timeout) - 3"
+ * if timeout < 16 load 0 in register
+ * if timeout is not a power of 2, round to next highest power of 2
+ */
if (timeout < 16) {
timeout = 0;
} else {
- timeout = __fls(timeout) - 3;
if (timeout & (timeout - 1))
- timeout++;
+ timeout <<= 1;
+ timeout = __fls(timeout) - 3;
}
switch (lpmode) {
case EMIF_LP_MODE_CLOCK_STOP:
- pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
- SR_TIM_MASK | PD_TIM_MASK;
+ shift = CS_TIM_SHIFT;
+ mask = CS_TIM_MASK;
break;
case EMIF_LP_MODE_SELF_REFRESH:
/* Workaround for errata i735 */
if (timeout < 6)
timeout = 6;
- pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
- CS_TIM_MASK | PD_TIM_MASK;
+ shift = SR_TIM_SHIFT;
+ mask = SR_TIM_MASK;
break;
case EMIF_LP_MODE_PWR_DN:
- pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
- CS_TIM_MASK | SR_TIM_MASK;
+ shift = PD_TIM_SHIFT;
+ mask = PD_TIM_MASK;
break;
case EMIF_LP_MODE_DISABLE:
default:
- pwr_mgmt_ctrl = CS_TIM_MASK |
- PD_TIM_MASK | SR_TIM_MASK;
+ mask = 0;
+ shift = 0;
+ break;
}
+ /* Round to maximum in case of overflow, BUT warn! */
+ if (lpmode != EMIF_LP_MODE_DISABLE && timeout > mask >> shift) {
+ pr_err("TIMEOUT Overflow - lpmode=%d perf=%d pwr=%d freq=%d\n",
+ lpmode,
+ timeout_perf,
+ timeout_pwr,
+ freq_threshold);
+ WARN(1, "timeout=0x%02x greater than 0x%02x. Using max\n",
+ timeout, mask >> shift);
+ timeout = mask >> shift;
+ }
+
+ /* Setup required timing */
+ pwr_mgmt_ctrl = (timeout << shift) & mask;
+ /* setup a default mask for rest of the modes */
+ pwr_mgmt_ctrl |= (SR_TIM_MASK | CS_TIM_MASK | PD_TIM_MASK) &
+ ~mask;
/* No CS_TIM in EMIF_4D5 */
if (ip_rev == EMIF_4D5)
@@ -815,6 +875,8 @@ static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+ writel(regs->pwr_mgmt_ctrl_shdw,
+ base + EMIF_POWER_MANAGEMENT_CTRL_SHDW);
/* Settings specific for EMIF4D5 */
if (emif->plat_data->ip_rev != EMIF_4D5)
@@ -892,6 +954,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
{
u32 old_temp_level;
irqreturn_t ret = IRQ_HANDLED;
+ struct emif_custom_configs *custom_configs;
spin_lock_irqsave(&emif_lock, irq_state);
old_temp_level = emif->temperature_level;
@@ -904,6 +967,29 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
goto out;
}
+ custom_configs = emif->plat_data->custom_configs;
+
+ /*
+ * IF we detect higher than "nominal rating" from DDR sensor
+ * on an unsupported DDR part, shutdown system
+ */
+ if (custom_configs && !(custom_configs->mask &
+ EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART)) {
+ if (emif->temperature_level >= SDRAM_TEMP_HIGH_DERATE_REFRESH) {
+ dev_err(emif->dev,
+ "%s:NOT Extended temperature capable memory."
+ "Converting MR4=0x%02x as shutdown event\n",
+ __func__, emif->temperature_level);
+ /*
+ * Temperature far too high - do kernel_power_off()
+ * from thread context
+ */
+ emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN;
+ ret = IRQ_WAKE_THREAD;
+ goto out;
+ }
+ }
+
if (emif->temperature_level < old_temp_level ||
emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
/*
@@ -965,7 +1051,14 @@ static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
- kernel_power_off();
+
+ /* If we have Power OFF ability, use it, else try restarting */
+ if (pm_power_off) {
+ kernel_power_off();
+ } else {
+ WARN(1, "FIXME: NO pm_power_off!!! trying restart\n");
+ kernel_restart("SDRAM Over-temp Emergency restart");
+ }
return IRQ_HANDLED;
}
@@ -1170,7 +1263,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
{
struct emif_custom_configs *cust_cfgs = NULL;
int len;
- const int *lpmode, *poll_intvl;
+ const __be32 *lpmode, *poll_intvl;
lpmode = of_get_property(np_emif, "low-power-mode", &len);
poll_intvl = of_get_property(np_emif, "temp-alert-poll-interval", &len);
@@ -1184,7 +1277,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
if (lpmode) {
cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_LPMODE;
- cust_cfgs->lpmode = *lpmode;
+ cust_cfgs->lpmode = be32_to_cpup(lpmode);
of_property_read_u32(np_emif,
"low-power-mode-timeout-performance",
&cust_cfgs->lpmode_timeout_performance);
@@ -1199,9 +1292,13 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif,
if (poll_intvl) {
cust_cfgs->mask |=
EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL;
- cust_cfgs->temp_alert_poll_interval_ms = *poll_intvl;
+ cust_cfgs->temp_alert_poll_interval_ms =
+ be32_to_cpup(poll_intvl);
}
+ if (of_find_property(np_emif, "extended-temp-part", &len))
+ cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART;
+
if (!is_custom_config_valid(cust_cfgs, emif->dev)) {
devm_kfree(emif->dev, cust_cfgs);
return;
@@ -1407,7 +1504,7 @@ static struct emif_data *__init_or_module get_device_details(
if (pd->timings) {
temp = devm_kzalloc(dev, size, GFP_KERNEL);
if (temp) {
- memcpy(temp, pd->timings, sizeof(*pd->timings));
+ memcpy(temp, pd->timings, size);
pd->timings = temp;
} else {
dev_warn(dev, "%s:%d: allocation error\n", __func__,
@@ -1841,18 +1938,8 @@ static struct platform_driver emif_driver = {
},
};
-static int __init_or_module emif_register(void)
-{
- return platform_driver_probe(&emif_driver, emif_probe);
-}
-
-static void __exit emif_unregister(void)
-{
- platform_driver_unregister(&emif_driver);
-}
+module_platform_driver_probe(emif_driver, emif_probe);
-module_init(emif_register);
-module_exit(emif_unregister);
MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:emif");
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
index 0b975986777d..f4ae074badc3 100644
--- a/drivers/memory/tegra30-mc.c
+++ b/drivers/memory/tegra30-mc.c
@@ -268,6 +268,7 @@ static const u32 tegra30_mc_ctx[] = {
MC_INTMASK,
};
+#ifdef CONFIG_PM
static int tegra30_mc_suspend(struct device *dev)
{
int i;
@@ -291,6 +292,7 @@ static int tegra30_mc_resume(struct device *dev)
mc_readl(mc, MC_TIMING_CONTROL);
return 0;
}
+#endif
static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
tegra30_mc_suspend,
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
index a7c5b31c0d50..9718661c1fb6 100644
--- a/drivers/memstick/host/r592.c
+++ b/drivers/memstick/host/r592.c
@@ -847,7 +847,7 @@ static void r592_remove(struct pci_dev *pdev)
dev->dummy_dma_page_physical_address);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int r592_suspend(struct device *core_dev)
{
struct pci_dev *pdev = to_pci_dev(core_dev);
@@ -870,10 +870,10 @@ static int r592_resume(struct device *core_dev)
r592_update_card_detect(dev);
return 0;
}
-
-SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume);
#endif
+static SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume);
+
MODULE_DEVICE_TABLE(pci, r592_pci_id_tbl);
static struct pci_driver r852_pci_driver = {
@@ -881,9 +881,7 @@ static struct pci_driver r852_pci_driver = {
.id_table = r592_pci_id_tbl,
.probe = r592_probe,
.remove = r592_remove,
-#ifdef CONFIG_PM
.driver.pm = &r592_pm_ops,
-#endif
};
static __init int r592_module_init(void)
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 5451beff183f..a60c188c2bd9 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -687,6 +687,11 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
}
size = size >> 16;
size *= 4;
+ if (size > sizeof(rmsg)) {
+ rcode = -EINVAL;
+ goto sg_list_cleanup;
+ }
+
/* Copy in the user's I2O command */
if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
@@ -922,6 +927,11 @@ static int i2o_cfg_passthru(unsigned long arg)
}
size = size >> 16;
size *= 4;
+ if (size > sizeof(rmsg)) {
+ rcode = -EFAULT;
+ goto sg_list_cleanup;
+ }
+
/* Copy in the user's I2O command */
if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index c346941a2515..ca86581d02ce 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -991,7 +991,7 @@ config MFD_PM8XXX
config MFD_PM8921_CORE
tristate "Qualcomm PM8921 PMIC chip"
- depends on MSM_SSBI
+ depends on SSBI && BROKEN
select MFD_CORE
select MFD_PM8XXX
help
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 2ec7725f4a08..a9bb140bc86b 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -753,6 +753,7 @@ static struct mfd_cell ab3100_devs[] = {
},
{
.name = "ab3100-regulators",
+ .of_compatible = "stericsson,ab3100-regulators",
.id = -1,
},
{
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 7c84ced2e01b..f276352cc9ef 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -95,6 +95,7 @@
#define AB8500_IT_MASK22_REG 0x55
#define AB8500_IT_MASK23_REG 0x56
#define AB8500_IT_MASK24_REG 0x57
+#define AB8500_IT_MASK25_REG 0x58
/*
* latch hierarchy registers
@@ -102,15 +103,25 @@
#define AB8500_IT_LATCHHIER1_REG 0x60
#define AB8500_IT_LATCHHIER2_REG 0x61
#define AB8500_IT_LATCHHIER3_REG 0x62
+#define AB8540_IT_LATCHHIER4_REG 0x63
#define AB8500_IT_LATCHHIER_NUM 3
+#define AB8540_IT_LATCHHIER_NUM 4
#define AB8500_REV_REG 0x80
#define AB8500_IC_NAME_REG 0x82
#define AB8500_SWITCH_OFF_STATUS 0x00
#define AB8500_TURN_ON_STATUS 0x00
+#define AB8505_TURN_ON_STATUS_2 0x04
+#define AB8500_CH_USBCH_STAT1_REG 0x02
+#define VBUS_DET_DBNC100 0x02
+#define VBUS_DET_DBNC1 0x01
+
+static DEFINE_SPINLOCK(on_stat_lock);
+static u8 turn_on_stat_mask = 0xFF;
+static u8 turn_on_stat_set;
static bool no_bm; /* No battery management */
module_param(no_bm, bool, S_IRUGO);
@@ -130,9 +141,15 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
};
-/* AB9540 support */
+/* AB9540 / AB8505 support */
static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
- 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+ 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
+};
+
+/* AB8540 support */
+static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
+ 0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23,
+ 25, 26, 27, 28, 29, 30, 31,
};
static const char ab8500_version_str[][7] = {
@@ -352,6 +369,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
is_ab8500_1p1_or_earlier(ab8500))
continue;
+ if (ab8500->irq_reg_offset[i] < 0)
+ continue;
+
ab8500->oldmask[i] = new;
reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
@@ -423,6 +443,18 @@ static struct irq_chip ab8500_irq_chip = {
.irq_set_type = ab8500_irq_set_type,
};
+static void update_latch_offset(u8 *offset, int i)
+{
+ /* Fix inconsistent ITFromLatch25 bit mapping... */
+ if (unlikely(*offset == 17))
+ *offset = 24;
+ /* Fix inconsistent ab8540 bit mapping... */
+ if (unlikely(*offset == 16))
+ *offset = 25;
+ if ((i==3) && (*offset >= 24))
+ *offset += 2;
+}
+
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
int latch_offset, u8 latch_val)
{
@@ -474,9 +506,7 @@ static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
latch_bit = __ffs(hier_val);
latch_offset = (hier_offset << 3) + latch_bit;
- /* Fix inconsistent ITFromLatch25 bit mapping... */
- if (unlikely(latch_offset == 17))
- latch_offset = 24;
+ update_latch_offset(&latch_offset, hier_offset);
status = get_register_interruptible(ab8500,
AB8500_INTERRUPT,
@@ -504,7 +534,7 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
dev_vdbg(ab8500->dev, "interrupt\n");
/* Hierarchical interrupt version */
- for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
+ for (i = 0; i < (ab8500->it_latchhier_num); i++) {
int status;
u8 hier_val;
@@ -520,63 +550,6 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-/**
- * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
- *
- * @ab8500: ab8500_irq controller to operate on.
- * @irq: index of the interrupt requested in the chip IRQs
- *
- * Useful for drivers to request their own IRQs.
- */
-static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
-{
- if (!ab8500)
- return -EINVAL;
-
- return irq_create_mapping(ab8500->domain, irq);
-}
-
-static irqreturn_t ab8500_irq(int irq, void *dev)
-{
- struct ab8500 *ab8500 = dev;
- int i;
-
- dev_vdbg(ab8500->dev, "interrupt\n");
-
- atomic_inc(&ab8500->transfer_ongoing);
-
- for (i = 0; i < ab8500->mask_size; i++) {
- int regoffset = ab8500->irq_reg_offset[i];
- int status;
- u8 value;
-
- /*
- * Interrupt register 12 doesn't exist prior to AB8500 version
- * 2.0
- */
- if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
- continue;
-
- status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
- AB8500_IT_LATCH1_REG + regoffset, &value);
- if (status < 0 || value == 0)
- continue;
-
- do {
- int bit = __ffs(value);
- int line = i * 8 + bit;
- int virq = ab8500_irq_get_virq(ab8500, line);
-
- handle_nested_irq(virq);
- ab8500_debug_register_interrupt(line);
- value &= ~(1 << bit);
-
- } while (value);
- }
- atomic_dec(&ab8500->transfer_ongoing);
- return IRQ_HANDLED;
-}
-
static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq)
{
@@ -607,7 +580,9 @@ static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
{
int num_irqs;
- if (is_ab9540(ab8500))
+ if (is_ab8540(ab8500))
+ num_irqs = AB8540_NR_IRQS;
+ else if (is_ab9540(ab8500))
num_irqs = AB9540_NR_IRQS;
else if (is_ab8505(ab8500))
num_irqs = AB8505_NR_IRQS;
@@ -650,6 +625,15 @@ static struct resource ab8500_gpadc_resources[] = {
},
};
+static struct resource ab8505_gpadc_resources[] = {
+ {
+ .name = "SW_CONV_END",
+ .start = AB8500_INT_GP_SW_ADC_CONV_END,
+ .end = AB8500_INT_GP_SW_ADC_CONV_END,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource ab8500_rtc_resources[] = {
{
.name = "60S",
@@ -973,6 +957,30 @@ static struct resource ab8505_iddet_resources[] = {
.end = AB8505_INT_KEYSTUCK,
.flags = IORESOURCE_IRQ,
},
+ {
+ .name = "VBUS_DET_R",
+ .start = AB8500_INT_VBUS_DET_R,
+ .end = AB8500_INT_VBUS_DET_R,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS_DET_F",
+ .start = AB8500_INT_VBUS_DET_F,
+ .end = AB8500_INT_VBUS_DET_F,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_DET_PLUGR",
+ .start = AB8500_INT_ID_DET_PLUGR,
+ .end = AB8500_INT_ID_DET_PLUGR,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ID_DET_PLUGF",
+ .start = AB8500_INT_ID_DET_PLUGF,
+ .end = AB8500_INT_ID_DET_PLUGF,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct resource ab8500_temp_resources[] = {
@@ -984,7 +992,42 @@ static struct resource ab8500_temp_resources[] = {
},
};
-static struct mfd_cell abx500_common_devs[] = {
+static struct mfd_cell ab8500_bm_devs[] = {
+ {
+ .name = "ab8500-charger",
+ .of_compatible = "stericsson,ab8500-charger",
+ .num_resources = ARRAY_SIZE(ab8500_charger_resources),
+ .resources = ab8500_charger_resources,
+ .platform_data = &ab8500_bm_data,
+ .pdata_size = sizeof(ab8500_bm_data),
+ },
+ {
+ .name = "ab8500-btemp",
+ .of_compatible = "stericsson,ab8500-btemp",
+ .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
+ .resources = ab8500_btemp_resources,
+ .platform_data = &ab8500_bm_data,
+ .pdata_size = sizeof(ab8500_bm_data),
+ },
+ {
+ .name = "ab8500-fg",
+ .of_compatible = "stericsson,ab8500-fg",
+ .num_resources = ARRAY_SIZE(ab8500_fg_resources),
+ .resources = ab8500_fg_resources,
+ .platform_data = &ab8500_bm_data,
+ .pdata_size = sizeof(ab8500_bm_data),
+ },
+ {
+ .name = "ab8500-chargalg",
+ .of_compatible = "stericsson,ab8500-chargalg",
+ .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
+ .resources = ab8500_chargalg_resources,
+ .platform_data = &ab8500_bm_data,
+ .pdata_size = sizeof(ab8500_bm_data),
+ },
+};
+
+static struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
@@ -1007,7 +1050,6 @@ static struct mfd_cell abx500_common_devs[] = {
},
{
.name = "ab8500-gpadc",
- .of_compatible = "stericsson,ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
},
@@ -1024,6 +1066,7 @@ static struct mfd_cell abx500_common_devs[] = {
.resources = ab8500_av_acc_detect_resources,
},
{
+
.name = "ab8500-poweron-key",
.of_compatible = "stericsson,ab8500-poweron-key",
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -1053,82 +1096,220 @@ static struct mfd_cell abx500_common_devs[] = {
.of_compatible = "stericsson,ab8500-denc",
},
{
+ .name = "ab8500-gpio",
+ .of_compatible = "stericsson,ab8500-gpio",
+ },
+ {
.name = "abx500-temp",
.of_compatible = "stericsson,abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
.resources = ab8500_temp_resources,
},
+ {
+ .name = "ab8500-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab8500-codec",
+ },
};
-static struct mfd_cell ab8500_bm_devs[] = {
+static struct mfd_cell ab9540_devs[] = {
+#ifdef CONFIG_DEBUG_FS
{
- .name = "ab8500-charger",
- .of_compatible = "stericsson,ab8500-charger",
- .num_resources = ARRAY_SIZE(ab8500_charger_resources),
- .resources = ab8500_charger_resources,
- .platform_data = &ab8500_bm_data,
- .pdata_size = sizeof(ab8500_bm_data),
+ .name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
},
+#endif
{
- .name = "ab8500-btemp",
- .of_compatible = "stericsson,ab8500-btemp",
- .num_resources = ARRAY_SIZE(ab8500_btemp_resources),
- .resources = ab8500_btemp_resources,
- .platform_data = &ab8500_bm_data,
- .pdata_size = sizeof(ab8500_bm_data),
+ .name = "ab8500-sysctrl",
},
{
- .name = "ab8500-fg",
- .of_compatible = "stericsson,ab8500-fg",
- .num_resources = ARRAY_SIZE(ab8500_fg_resources),
- .resources = ab8500_fg_resources,
- .platform_data = &ab8500_bm_data,
- .pdata_size = sizeof(ab8500_bm_data),
+ .name = "ab8500-regulator",
},
{
- .name = "ab8500-chargalg",
- .of_compatible = "stericsson,ab8500-chargalg",
- .num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
- .resources = ab8500_chargalg_resources,
- .platform_data = &ab8500_bm_data,
- .pdata_size = sizeof(ab8500_bm_data),
+ .name = "abx500-clk",
+ .of_compatible = "stericsson,abx500-clk",
+ },
+ {
+ .name = "ab8500-gpadc",
+ .of_compatible = "stericsson,ab8500-gpadc",
+ .num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
+ .resources = ab8500_gpadc_resources,
+ },
+ {
+ .name = "ab8500-rtc",
+ .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+ .resources = ab8500_rtc_resources,
+ },
+ {
+ .name = "ab8500-acc-det",
+ .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+ .resources = ab8500_av_acc_detect_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 1,
+ },
+ {
+ .name = "ab8500-leds",
+ },
+ {
+ .name = "abx500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
+ },
+ {
+ .name = "pinctrl-ab9540",
+ .of_compatible = "stericsson,ab9540-gpio",
+ },
+ {
+ .name = "ab9540-usb",
+ .num_resources = ARRAY_SIZE(ab8500_usb_resources),
+ .resources = ab8500_usb_resources,
+ },
+ {
+ .name = "ab9540-codec",
+ },
+ {
+ .name = "ab-iddet",
+ .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
+ .resources = ab8505_iddet_resources,
},
};
-static struct mfd_cell ab8500_devs[] = {
+/* Device list for ab8505 */
+static struct mfd_cell ab8505_devs[] = {
+#ifdef CONFIG_DEBUG_FS
{
- .name = "pinctrl-ab8500",
- .of_compatible = "stericsson,ab8500-gpio",
+ .name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
+ },
+#endif
+ {
+ .name = "ab8500-sysctrl",
+ },
+ {
+ .name = "ab8500-regulator",
+ },
+ {
+ .name = "abx500-clk",
+ .of_compatible = "stericsson,abx500-clk",
+ },
+ {
+ .name = "ab8500-gpadc",
+ .num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
+ .resources = ab8505_gpadc_resources,
+ },
+ {
+ .name = "ab8500-rtc",
+ .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+ .resources = ab8500_rtc_resources,
+ },
+ {
+ .name = "ab8500-acc-det",
+ .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+ .resources = ab8500_av_acc_detect_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 1,
+ },
+ {
+ .name = "ab8500-leds",
+ },
+ {
+ .name = "ab8500-gpio",
},
{
.name = "ab8500-usb",
- .of_compatible = "stericsson,ab8500-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
{
.name = "ab8500-codec",
- .of_compatible = "stericsson,ab8500-codec",
+ },
+ {
+ .name = "ab-iddet",
+ .num_resources = ARRAY_SIZE(ab8505_iddet_resources),
+ .resources = ab8505_iddet_resources,
},
};
-static struct mfd_cell ab9540_devs[] = {
+static struct mfd_cell ab8540_devs[] = {
+#ifdef CONFIG_DEBUG_FS
{
- .name = "pinctrl-ab9540",
- .of_compatible = "stericsson,ab9540-gpio",
+ .name = "ab8500-debug",
+ .num_resources = ARRAY_SIZE(ab8500_debug_resources),
+ .resources = ab8500_debug_resources,
+ },
+#endif
+ {
+ .name = "ab8500-sysctrl",
},
{
- .name = "ab9540-usb",
+ .name = "ab8500-regulator",
+ },
+ {
+ .name = "abx500-clk",
+ .of_compatible = "stericsson,abx500-clk",
+ },
+ {
+ .name = "ab8500-gpadc",
+ .num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
+ .resources = ab8505_gpadc_resources,
+ },
+ {
+ .name = "ab8500-rtc",
+ .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+ .resources = ab8500_rtc_resources,
+ },
+ {
+ .name = "ab8500-acc-det",
+ .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+ .resources = ab8500_av_acc_detect_resources,
+ },
+ {
+ .name = "ab8500-poweron-key",
+ .num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+ .resources = ab8500_poweronkey_db_resources,
+ },
+ {
+ .name = "ab8500-pwm",
+ .id = 1,
+ },
+ {
+ .name = "ab8500-leds",
+ },
+ {
+ .name = "abx500-temp",
+ .num_resources = ARRAY_SIZE(ab8500_temp_resources),
+ .resources = ab8500_temp_resources,
+ },
+ {
+ .name = "ab8500-gpio",
+ },
+ {
+ .name = "ab8540-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
{
- .name = "ab9540-codec",
+ .name = "ab8540-codec",
},
-};
-
-/* Device list common to ab9540 and ab8505 */
-static struct mfd_cell ab9540_ab8505_devs[] = {
{
.name = "ab-iddet",
.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
@@ -1142,6 +1323,7 @@ static ssize_t show_chip_id(struct device *dev,
struct ab8500 *ab8500;
ab8500 = dev_get_drvdata(dev);
+
return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
}
@@ -1171,6 +1353,15 @@ static ssize_t show_switch_off_status(struct device *dev,
return sprintf(buf, "%#x\n", value);
}
+/* use mask and set to override the register turn_on_stat value */
+void ab8500_override_turn_on_stat(u8 mask, u8 set)
+{
+ spin_lock(&on_stat_lock);
+ turn_on_stat_mask = mask;
+ turn_on_stat_set = set;
+ spin_unlock(&on_stat_lock);
+}
+
/*
* ab8500 has turned on due to (TURN_ON_STATUS):
* 0x01 PORnVbat
@@ -1194,9 +1385,38 @@ static ssize_t show_turn_on_status(struct device *dev,
AB8500_TURN_ON_STATUS, &value);
if (ret < 0)
return ret;
+
+ /*
+ * In L9540, turn_on_status register is not updated correctly if
+ * the device is rebooted with AC/USB charger connected. Due to
+ * this, the device boots android instead of entering into charge
+ * only mode. Read the AC/USB status register to detect the charger
+ * presence and update the turn on status manually.
+ */
+ if (is_ab9540(ab8500)) {
+ spin_lock(&on_stat_lock);
+ value = (value & turn_on_stat_mask) | turn_on_stat_set;
+ spin_unlock(&on_stat_lock);
+ }
+
return sprintf(buf, "%#x\n", value);
}
+static ssize_t show_turn_on_status_2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ u8 value;
+ struct ab8500 *ab8500;
+
+ ab8500 = dev_get_drvdata(dev);
+ ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
+ AB8505_TURN_ON_STATUS_2, &value);
+ if (ret < 0)
+ return ret;
+ return sprintf(buf, "%#x\n", (value & 0x1));
+}
+
static ssize_t show_ab9540_dbbrstn(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1253,6 +1473,7 @@ exit:
static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+static DEVICE_ATTR(turn_on_status_2, S_IRUGO, show_turn_on_status_2, NULL);
static DEVICE_ATTR(dbbrstn, S_IRUGO | S_IWUSR,
show_ab9540_dbbrstn, store_ab9540_dbbrstn);
@@ -1263,6 +1484,11 @@ static struct attribute *ab8500_sysfs_entries[] = {
NULL,
};
+static struct attribute *ab8505_sysfs_entries[] = {
+ &dev_attr_turn_on_status_2.attr,
+ NULL,
+};
+
static struct attribute *ab9540_sysfs_entries[] = {
&dev_attr_chip_id.attr,
&dev_attr_switch_off_status.attr,
@@ -1275,6 +1501,10 @@ static struct attribute_group ab8500_attr_group = {
.attrs = ab8500_sysfs_entries,
};
+static struct attribute_group ab8505_attr_group = {
+ .attrs = ab8505_sysfs_entries,
+};
+
static struct attribute_group ab9540_attr_group = {
.attrs = ab9540_sysfs_entries,
};
@@ -1290,6 +1520,15 @@ static int ab8500_probe(struct platform_device *pdev)
"Battery level lower than power on reset threshold",
"Power on key 1 pressed longer than 10 seconds",
"DB8500 thermal shutdown"};
+ static char *turn_on_status[] = {
+ "Battery rising (Vbat)",
+ "Power On Key 1 dbF",
+ "Power On Key 2 dbF",
+ "RTC Alarm",
+ "Main Charger Detect",
+ "Vbus Detect (USB)",
+ "USB ID Detect",
+ "UART Factory Mode Detect"};
struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
const struct platform_device_id *platid = platform_get_device_id(pdev);
enum ab8500_version version = AB8500_VERSION_UNDEFINED;
@@ -1351,13 +1590,20 @@ static int ab8500_probe(struct platform_device *pdev)
ab8500->chip_id >> 4,
ab8500->chip_id & 0x0F);
- /* Configure AB8500 or AB9540 IRQ */
- if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+ /* Configure AB8540 */
+ if (is_ab8540(ab8500)) {
+ ab8500->mask_size = AB8540_NUM_IRQ_REGS;
+ ab8500->irq_reg_offset = ab8540_irq_regoffset;
+ ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
+ }/* Configure AB8500 or AB9540 IRQ */
+ else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
ab8500->mask_size = AB9540_NUM_IRQ_REGS;
ab8500->irq_reg_offset = ab9540_irq_regoffset;
+ ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
} else {
ab8500->mask_size = AB8500_NUM_IRQ_REGS;
ab8500->irq_reg_offset = ab8500_irq_regoffset;
+ ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
}
ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL);
if (!ab8500->mask)
@@ -1396,10 +1642,36 @@ static int ab8500_probe(struct platform_device *pdev)
} else {
printk(KERN_CONT " None\n");
}
+ ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
+ AB8500_TURN_ON_STATUS, &value);
+ if (ret < 0)
+ return ret;
+ dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
+
+ if (value) {
+ for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
+ if (value & 1)
+ printk("\"%s\" ", turn_on_status[i]);
+ value = value >> 1;
+ }
+ printk("\n");
+ } else {
+ printk("None\n");
+ }
if (plat && plat->init)
plat->init(ab8500);
+ if (is_ab9540(ab8500)) {
+ ret = get_register_interruptible(ab8500, AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT1_REG, &value);
+ if (ret < 0)
+ return ret;
+ if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
+ ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
+ AB8500_VBUS_DET);
+ }
+
/* Clear and mask all interrupts */
for (i = 0; i < ab8500->mask_size; i++) {
/*
@@ -1410,6 +1682,9 @@ static int ab8500_probe(struct platform_device *pdev)
is_ab8500_1p1_or_earlier(ab8500))
continue;
+ if (ab8500->irq_reg_offset[i] < 0)
+ continue;
+
get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
&value);
@@ -1428,26 +1703,10 @@ static int ab8500_probe(struct platform_device *pdev)
if (ret)
return ret;
- /* Activate this feature only in ab9540 */
- /* till tests are done on ab8500 1p2 or later*/
- if (is_ab9540(ab8500)) {
- ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
- ab8500_hierarchical_irq,
- IRQF_ONESHOT | IRQF_NO_SUSPEND,
- "ab8500", ab8500);
- }
- else {
- ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
- ab8500_irq,
- IRQF_ONESHOT | IRQF_NO_SUSPEND,
- "ab8500", ab8500);
- if (ret)
- return ret;
- }
-
- ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
- ARRAY_SIZE(abx500_common_devs), NULL,
- ab8500->irq_base, ab8500->domain);
+ ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
+ ab8500_hierarchical_irq,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "ab8500", ab8500);
if (ret)
return ret;
@@ -1455,6 +1714,14 @@ static int ab8500_probe(struct platform_device *pdev)
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base, ab8500->domain);
+ else if (is_ab8540(ab8500))
+ ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
+ ARRAY_SIZE(ab8540_devs), NULL,
+ ab8500->irq_base, ab8500->domain);
+ else if (is_ab8505(ab8500))
+ ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
+ ARRAY_SIZE(ab8505_devs), NULL,
+ ab8500->irq_base, ab8500->domain);
else
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
@@ -1462,13 +1729,6 @@ static int ab8500_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (is_ab9540(ab8500) || is_ab8505(ab8500))
- ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
- ARRAY_SIZE(ab9540_ab8505_devs), NULL,
- ab8500->irq_base, ab8500->domain);
- if (ret)
- return ret;
-
if (!no_bm) {
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
@@ -1478,12 +1738,19 @@ static int ab8500_probe(struct platform_device *pdev)
dev_err(ab8500->dev, "error adding bm devices\n");
}
- if (is_ab9540(ab8500))
+ if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+ ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
ret = sysfs_create_group(&ab8500->dev->kobj,
&ab9540_attr_group);
else
ret = sysfs_create_group(&ab8500->dev->kobj,
&ab8500_attr_group);
+
+ if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+ ab8500->chip_id >= AB8500_CUT2P0)
+ ret = sysfs_create_group(&ab8500->dev->kobj,
+ &ab8505_attr_group);
+
if (ret)
dev_err(ab8500->dev, "error creating sysfs entries\n");
@@ -1494,11 +1761,16 @@ static int ab8500_remove(struct platform_device *pdev)
{
struct ab8500 *ab8500 = platform_get_drvdata(pdev);
- if (is_ab9540(ab8500))
+ if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+ ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
else
sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
+ if ((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+ ab8500->chip_id >= AB8500_CUT2P0)
+ sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group);
+
mfd_remove_devices(ab8500->dev);
return 0;
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 45fe3c50eb03..b88bbbc15f1e 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -80,6 +80,7 @@
#include <linux/interrupt.h>
#include <linux/kobject.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
@@ -90,6 +91,9 @@
#include <linux/ctype.h>
#endif
+/* TODO: this file should not reference IRQ_DB8500_AB8500! */
+#include <mach/irqs.h>
+
static u32 debug_bank;
static u32 debug_address;
@@ -101,6 +105,11 @@ static int num_irqs;
static struct device_attribute **dev_attr;
static char **event_name;
+static u8 avg_sample = SAMPLE_16;
+static u8 trig_edge = RISING_EDGE;
+static u8 conv_type = ADC_SW;
+static u8 trig_timer;
+
/**
* struct ab8500_reg_range
* @first: the first address of the range
@@ -150,7 +159,9 @@ static struct hwreg_cfg hwreg_cfg = {
#define AB8500_REV_REG 0x80
-static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges *debug_ranges;
+
+struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
[0x0] = {
.num_ranges = 0,
.range = NULL,
@@ -354,7 +365,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
{
.first = 0xf5,
- .last = 0xf6,
+ .last = 0xf6,
},
},
},
@@ -479,6 +490,781 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
},
};
+struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
+ [0x0] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x04,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x52,
+ .last = 0x52,
+ },
+ {
+ .first = 0x54,
+ .last = 0x57,
+ },
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x17,
+ },
+ {
+ .first = 0x20,
+ .last = 0x20,
+ },
+ {
+ .first = 0x30,
+ .last = 0x30,
+ },
+ {
+ .first = 0x32,
+ .last = 0x3A,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x03,
+ .last = 0x11,
+ },
+ {
+ .first = 0x80,
+ .last = 0x86,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 6,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x06,
+ },
+ {
+ .first = 0x08,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x30,
+ },
+ {
+ .first = 0x40,
+ .last = 0x48,
+ },
+ /* 0x80-0x8B is SIM registers and should
+ * not be accessed from here */
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ {
+ .first = 0x91,
+ .last = 0x94,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [AB8500_RESERVED] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x08,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x02,
+ .last = 0x03,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x57,
+ },
+ {
+ .first = 0x60,
+ .last = 0x60,
+ },
+ {
+ .first = 0xA0,
+ .last = 0xA7,
+ },
+ {
+ .first = 0xAF,
+ .last = 0xB2,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC2,
+ },
+ {
+ .first = 0xF5,
+ .last = 0xF5,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x83,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 11,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x04,
+ },
+ {
+ .first = 0x06,
+ .last = 0x07,
+ },
+ {
+ .first = 0x09,
+ .last = 0x09,
+ },
+ {
+ .first = 0x0B,
+ .last = 0x0C,
+ },
+ {
+ .first = 0x12,
+ .last = 0x15,
+ },
+ {
+ .first = 0x18,
+ .last = 0x18,
+ },
+ /* Latch registers should not be read here */
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ {
+ .first = 0x46,
+ .last = 0x49,
+ },
+ {
+ .first = 0x4B,
+ .last = 0x4D,
+ },
+ {
+ .first = 0x52,
+ .last = 0x55,
+ },
+ {
+ .first = 0x58,
+ .last = 0x58,
+ },
+ /* LatchHier registers should not be read here */
+ },
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x14,
+ },
+ {
+ .first = 0x16,
+ .last = 0x17,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x06,
+ },
+ {
+ .first = 0x10,
+ .last = 0x16,
+ },
+ {
+ .first = 0x20,
+ .last = 0x26,
+ },
+ {
+ .first = 0x30,
+ .last = 0x36,
+ },
+ {
+ .first = 0x40,
+ .last = 0x46,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x6B,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [AB8500_DEVELOPMENT] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x05,
+ .last = 0x05,
+ },
+ },
+ },
+ [AB8500_DEBUG] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x05,
+ .last = 0x07,
+ },
+ },
+ },
+ [AB8500_PROD_TEST] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_STE_TEST] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x15,
+ },
+ },
+ },
+};
+
+struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = {
+ [AB8500_M_FSM_RANK] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0B,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL1_BLOCK] = {
+ .num_ranges = 6,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x04,
+ },
+ {
+ .first = 0x42,
+ .last = 0x42,
+ },
+ {
+ .first = 0x50,
+ .last = 0x54,
+ },
+ {
+ .first = 0x57,
+ .last = 0x57,
+ },
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x90,
+ .last = 0x90,
+ },
+ },
+ },
+ [AB8500_SYS_CTRL2_BLOCK] = {
+ .num_ranges = 5,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x0F,
+ .last = 0x10,
+ },
+ {
+ .first = 0x20,
+ .last = 0x21,
+ },
+ {
+ .first = 0x32,
+ .last = 0x3C,
+ },
+ {
+ .first = 0x40,
+ .last = 0x42,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL1] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x03,
+ .last = 0x15,
+ },
+ {
+ .first = 0x20,
+ .last = 0x20,
+ },
+ {
+ .first = 0x80,
+ .last = 0x85,
+ },
+ {
+ .first = 0x87,
+ .last = 0x88,
+ },
+ },
+ },
+ [AB8500_REGU_CTRL2] = {
+ .num_ranges = 8,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x06,
+ },
+ {
+ .first = 0x08,
+ .last = 0x15,
+ },
+ {
+ .first = 0x17,
+ .last = 0x19,
+ },
+ {
+ .first = 0x1B,
+ .last = 0x1D,
+ },
+ {
+ .first = 0x1F,
+ .last = 0x2F,
+ },
+ {
+ .first = 0x31,
+ .last = 0x3A,
+ },
+ {
+ .first = 0x43,
+ .last = 0x44,
+ },
+ {
+ .first = 0x48,
+ .last = 0x49,
+ },
+ },
+ },
+ [AB8500_USB] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x80,
+ .last = 0x83,
+ },
+ {
+ .first = 0x87,
+ .last = 0x8A,
+ },
+ {
+ .first = 0x91,
+ .last = 0x94,
+ },
+ },
+ },
+ [AB8500_TVOUT] = {
+ .num_ranges = 0,
+ .range = NULL
+ },
+ [AB8500_DBI] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x07,
+ },
+ {
+ .first = 0x10,
+ .last = 0x11,
+ },
+ {
+ .first = 0x20,
+ .last = 0x21,
+ },
+ {
+ .first = 0x30,
+ .last = 0x43,
+ },
+ },
+ },
+ [AB8500_ECI_AV_ACC] = {
+ .num_ranges = 2,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x03,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [AB8500_RESERVED] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_GPADC] = {
+ .num_ranges = 4,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x01,
+ },
+ {
+ .first = 0x04,
+ .last = 0x06,
+ },
+ {
+ .first = 0x09,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_CHARGER] = {
+ .num_ranges = 10,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x02,
+ .last = 0x05,
+ },
+ {
+ .first = 0x40,
+ .last = 0x44,
+ },
+ {
+ .first = 0x50,
+ .last = 0x57,
+ },
+ {
+ .first = 0x60,
+ .last = 0x60,
+ },
+ {
+ .first = 0x70,
+ .last = 0x70,
+ },
+ {
+ .first = 0xA0,
+ .last = 0xA9,
+ },
+ {
+ .first = 0xAF,
+ .last = 0xB2,
+ },
+ {
+ .first = 0xC0,
+ .last = 0xC6,
+ },
+ {
+ .first = 0xF5,
+ .last = 0xF5,
+ },
+ },
+ },
+ [AB8500_GAS_GAUGE] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x00,
+ },
+ {
+ .first = 0x07,
+ .last = 0x0A,
+ },
+ {
+ .first = 0x10,
+ .last = 0x14,
+ },
+ },
+ },
+ [AB8500_AUDIO] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x9f,
+ },
+ },
+ },
+ [AB8500_INTERRUPT] = {
+ .num_ranges = 6,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x05,
+ },
+ {
+ .first = 0x0B,
+ .last = 0x0D,
+ },
+ {
+ .first = 0x12,
+ .last = 0x20,
+ },
+ /* Latch registers should not be read here */
+ {
+ .first = 0x40,
+ .last = 0x45,
+ },
+ {
+ .first = 0x4B,
+ .last = 0x4D,
+ },
+ {
+ .first = 0x52,
+ .last = 0x60,
+ },
+ /* LatchHier registers should not be read here */
+ },
+ },
+ [AB8500_RTC] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x07,
+ },
+ {
+ .first = 0x0B,
+ .last = 0x18,
+ },
+ {
+ .first = 0x20,
+ .last = 0x25,
+ },
+ },
+ },
+ [AB8500_MISC] = {
+ .num_ranges = 9,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x06,
+ },
+ {
+ .first = 0x10,
+ .last = 0x16,
+ },
+ {
+ .first = 0x20,
+ .last = 0x26,
+ },
+ {
+ .first = 0x30,
+ .last = 0x36,
+ },
+ {
+ .first = 0x40,
+ .last = 0x49,
+ },
+ {
+ .first = 0x50,
+ .last = 0x50,
+ },
+ {
+ .first = 0x60,
+ .last = 0x6B,
+ },
+ {
+ .first = 0x70,
+ .last = 0x74,
+ },
+ {
+ .first = 0x80,
+ .last = 0x82,
+ },
+ },
+ },
+ [AB8500_DEVELOPMENT] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x01,
+ },
+ {
+ .first = 0x06,
+ .last = 0x06,
+ },
+ {
+ .first = 0x10,
+ .last = 0x21,
+ },
+ },
+ },
+ [AB8500_DEBUG] = {
+ .num_ranges = 3,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x01,
+ .last = 0x0C,
+ },
+ {
+ .first = 0x0E,
+ .last = 0x11,
+ },
+ {
+ .first = 0x80,
+ .last = 0x81,
+ },
+ },
+ },
+ [AB8500_PROD_TEST] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_STE_TEST] = {
+ .num_ranges = 0,
+ .range = NULL,
+ },
+ [AB8500_OTP_EMUL] = {
+ .num_ranges = 1,
+ .range = (struct ab8500_reg_range[]) {
+ {
+ .first = 0x00,
+ .last = 0x3F,
+ },
+ },
+ },
+};
+
+
static irqreturn_t ab8500_debug_handler(int irq, void *data)
{
char buf[16];
@@ -520,19 +1306,16 @@ static int ab8500_registers_print(struct device *dev, u32 bank,
}
if (s) {
- err = seq_printf(s, " [%u/0x%02X]: 0x%02X\n",
+ err = seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n",
bank, reg, value);
if (err < 0) {
- dev_err(dev,
- "seq_printf overflow bank=%d reg=%d\n",
- bank, reg);
/* Error is not returned here since
* the output is wanted in any case */
return 0;
}
} else {
- printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank,
- reg, value);
+ printk(KERN_INFO" [0x%02X/0x%02X]: 0x%02X\n",
+ bank, reg, value);
}
}
}
@@ -546,7 +1329,7 @@ static int ab8500_print_bank_registers(struct seq_file *s, void *p)
seq_printf(s, AB8500_NAME_STRING " register values:\n");
- seq_printf(s, " bank %u:\n", bank);
+ seq_printf(s, " bank 0x%02X:\n", bank);
ab8500_registers_print(dev, bank, s);
return 0;
@@ -573,10 +1356,8 @@ static int ab8500_print_all_banks(struct seq_file *s, void *p)
seq_printf(s, AB8500_NAME_STRING " register values:\n");
- for (i = 1; i < AB8500_NUM_BANKS; i++) {
- err = seq_printf(s, " bank %u:\n", i);
- if (err < 0)
- dev_err(dev, "seq_printf overflow, bank=%d\n", i);
+ for (i = 0; i < AB8500_NUM_BANKS; i++) {
+ err = seq_printf(s, " bank 0x%02X:\n", i);
ab8500_registers_print(dev, i, s);
}
@@ -591,11 +1372,68 @@ void ab8500_dump_all_banks(struct device *dev)
printk(KERN_INFO"ab8500 register values:\n");
for (i = 1; i < AB8500_NUM_BANKS; i++) {
- printk(KERN_INFO" bank %u:\n", i);
+ printk(KERN_INFO" bank 0x%02X:\n", i);
ab8500_registers_print(dev, i, NULL);
}
}
+/* Space for 500 registers. */
+#define DUMP_MAX_REGS 700
+struct ab8500_register_dump
+{
+ u8 bank;
+ u8 reg;
+ u8 value;
+} ab8500_complete_register_dump[DUMP_MAX_REGS];
+
+extern int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+
+/* This shall only be called upon kernel panic! */
+void ab8500_dump_all_banks_to_mem(void)
+{
+ int i, r = 0;
+ u8 bank;
+ int err = 0;
+
+ pr_info("Saving all ABB registers at \"ab8500_complete_register_dump\" "
+ "for crash analyze.\n");
+
+ for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
+ for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+ u8 reg;
+
+ for (reg = debug_ranges[bank].range[i].first;
+ reg <= debug_ranges[bank].range[i].last;
+ reg++) {
+ u8 value;
+
+ err = prcmu_abb_read(bank, reg, &value, 1);
+
+ if (err < 0)
+ goto out;
+
+ ab8500_complete_register_dump[r].bank = bank;
+ ab8500_complete_register_dump[r].reg = reg;
+ ab8500_complete_register_dump[r].value = value;
+
+ r++;
+
+ if (r >= DUMP_MAX_REGS) {
+ pr_err("%s: too many register to dump!\n",
+ __func__);
+ err = -EINVAL;
+ goto out;
+ }
+ }
+ }
+ }
+out:
+ if (err >= 0)
+ pr_info("Saved all ABB registers.\n");
+ else
+ pr_info("Failed to save all ABB registers.\n");
+}
+
static int ab8500_all_banks_open(struct inode *inode, struct file *file)
{
struct seq_file *s;
@@ -625,7 +1463,7 @@ static const struct file_operations ab8500_all_banks_fops = {
static int ab8500_bank_print(struct seq_file *s, void *p)
{
- return seq_printf(s, "%d\n", debug_bank);
+ return seq_printf(s, "0x%02X\n", debug_bank);
}
static int ab8500_bank_open(struct inode *inode, struct file *file)
@@ -641,7 +1479,6 @@ static ssize_t ab8500_bank_write(struct file *file,
unsigned long user_bank;
int err;
- /* Get userspace string and assure termination */
err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
if (err)
return err;
@@ -667,14 +1504,13 @@ static int ab8500_address_open(struct inode *inode, struct file *file)
}
static ssize_t ab8500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_address;
int err;
- /* Get userspace string and assure termination */
err = kstrtoul_from_user(user_buf, count, 0, &user_address);
if (err)
return err;
@@ -684,6 +1520,7 @@ static ssize_t ab8500_address_write(struct file *file,
return -EINVAL;
}
debug_address = user_address;
+
return count;
}
@@ -711,14 +1548,13 @@ static int ab8500_val_open(struct inode *inode, struct file *file)
}
static ssize_t ab8500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_val;
int err;
- /* Get userspace string and assure termination */
err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
return err;
@@ -741,22 +1577,46 @@ static ssize_t ab8500_val_write(struct file *file,
* Interrupt status
*/
static u32 num_interrupts[AB8500_MAX_NR_IRQS];
+static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
static int num_interrupt_lines;
+bool __attribute__((weak)) suspend_test_wake_cause_interrupt_is_mine(u32 my_int)
+{
+ return false;
+}
+
void ab8500_debug_register_interrupt(int line)
{
- if (line < num_interrupt_lines)
+ if (line < num_interrupt_lines) {
num_interrupts[line]++;
+ if (suspend_test_wake_cause_interrupt_is_mine(IRQ_DB8500_AB8500))
+ num_wake_interrupts[line]++;
+ }
}
static int ab8500_interrupts_print(struct seq_file *s, void *p)
{
int line;
- seq_printf(s, "irq: number of\n");
+ seq_printf(s, "name: number: number of: wake:\n");
- for (line = 0; line < num_interrupt_lines; line++)
- seq_printf(s, "%3i: %6i\n", line, num_interrupts[line]);
+ for (line = 0; line < num_interrupt_lines; line++) {
+ struct irq_desc *desc = irq_to_desc(line + irq_first);
+ struct irqaction *action = desc->action;
+
+ seq_printf(s, "%3i: %6i %4i", line,
+ num_interrupts[line],
+ num_wake_interrupts[line]);
+
+ if (desc && desc->name)
+ seq_printf(s, "-%-8s", desc->name);
+ if (action) {
+ seq_printf(s, " %s", action->name);
+ while ((action = action->next) != NULL)
+ seq_printf(s, ", %s", action->name);
+ }
+ seq_putc(s, '\n');
+ }
return 0;
}
@@ -801,6 +1661,79 @@ static int ab8500_hwreg_open(struct inode *inode, struct file *file)
return single_open(file, ab8500_hwreg_print, inode->i_private);
}
+#define AB8500_SUPPLY_CONTROL_CONFIG_1 0x01
+#define AB8500_SUPPLY_CONTROL_REG 0x00
+#define AB8500_FIRST_SIM_REG 0x80
+#define AB8500_LAST_SIM_REG 0x8B
+#define AB8505_LAST_SIM_REG 0x8C
+
+static int ab8500_print_modem_registers(struct seq_file *s, void *p)
+{
+ struct device *dev = s->private;
+ struct ab8500 *ab8500;
+ int err;
+ u8 value;
+ u8 orig_value;
+ u32 bank = AB8500_REGU_CTRL2;
+ u32 last_sim_reg = AB8500_LAST_SIM_REG;
+ u32 reg;
+
+ ab8500 = dev_get_drvdata(dev->parent);
+ dev_warn(dev, "WARNING! This operation can interfer with modem side\n"
+ "and should only be done with care\n");
+
+ err = abx500_get_register_interruptible(dev,
+ AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, &orig_value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+ /* Config 1 will allow APE side to read SIM registers */
+ err = abx500_set_register_interruptible(dev,
+ AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG,
+ AB8500_SUPPLY_CONTROL_CONFIG_1);
+ if (err < 0) {
+ dev_err(dev, "ab->write fail %d\n", err);
+ return err;
+ }
+
+ seq_printf(s, " bank 0x%02X:\n", bank);
+
+ if (is_ab9540(ab8500) || is_ab8505(ab8500))
+ last_sim_reg = AB8505_LAST_SIM_REG;
+
+ for (reg = AB8500_FIRST_SIM_REG; reg <= last_sim_reg; reg++) {
+ err = abx500_get_register_interruptible(dev,
+ bank, reg, &value);
+ if (err < 0) {
+ dev_err(dev, "ab->read fail %d\n", err);
+ return err;
+ }
+ err = seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n",
+ bank, reg, value);
+ }
+ err = abx500_set_register_interruptible(dev,
+ AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, orig_value);
+ if (err < 0) {
+ dev_err(dev, "ab->write fail %d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static int ab8500_modem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_print_modem_registers, inode->i_private);
+}
+
+static const struct file_operations ab8500_modem_fops = {
+ .open = ab8500_modem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
{
int bat_ctrl_raw;
@@ -808,12 +1741,13 @@ static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
+ bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL,
+ avg_sample, trig_edge, trig_timer, conv_type);
bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- BAT_CTRL, bat_ctrl_raw);
+ BAT_CTRL, bat_ctrl_raw);
return seq_printf(s, "%d,0x%X\n",
- bat_ctrl_convert, bat_ctrl_raw);
+ bat_ctrl_convert, bat_ctrl_raw);
}
static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file)
@@ -836,16 +1770,17 @@ static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
+ btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL,
+ avg_sample, trig_edge, trig_timer, conv_type);
btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
- btemp_ball_raw);
+ btemp_ball_raw);
return seq_printf(s,
- "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
+ "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
}
static int ab8500_gpadc_btemp_ball_open(struct inode *inode,
- struct file *file)
+ struct file *file)
{
return single_open(file, ab8500_gpadc_btemp_ball_print, inode->i_private);
}
@@ -865,19 +1800,20 @@ static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
+ main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V,
+ avg_sample, trig_edge, trig_timer, conv_type);
main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- MAIN_CHARGER_V, main_charger_v_raw);
+ MAIN_CHARGER_V, main_charger_v_raw);
return seq_printf(s, "%d,0x%X\n",
main_charger_v_convert, main_charger_v_raw);
}
static int ab8500_gpadc_main_charger_v_open(struct inode *inode,
- struct file *file)
+ struct file *file)
{
return single_open(file, ab8500_gpadc_main_charger_v_print,
- inode->i_private);
+ inode->i_private);
}
static const struct file_operations ab8500_gpadc_main_charger_v_fops = {
@@ -895,19 +1831,20 @@ static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
+ acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1,
+ avg_sample, trig_edge, trig_timer, conv_type);
acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
- acc_detect1_raw);
+ acc_detect1_raw);
return seq_printf(s, "%d,0x%X\n",
- acc_detect1_convert, acc_detect1_raw);
+ acc_detect1_convert, acc_detect1_raw);
}
static int ab8500_gpadc_acc_detect1_open(struct inode *inode,
- struct file *file)
+ struct file *file)
{
return single_open(file, ab8500_gpadc_acc_detect1_print,
- inode->i_private);
+ inode->i_private);
}
static const struct file_operations ab8500_gpadc_acc_detect1_fops = {
@@ -925,19 +1862,20 @@ static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
+ acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2,
+ avg_sample, trig_edge, trig_timer, conv_type);
acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- ACC_DETECT2, acc_detect2_raw);
+ ACC_DETECT2, acc_detect2_raw);
return seq_printf(s, "%d,0x%X\n",
- acc_detect2_convert, acc_detect2_raw);
+ acc_detect2_convert, acc_detect2_raw);
}
static int ab8500_gpadc_acc_detect2_open(struct inode *inode,
struct file *file)
{
return single_open(file, ab8500_gpadc_acc_detect2_print,
- inode->i_private);
+ inode->i_private);
}
static const struct file_operations ab8500_gpadc_acc_detect2_fops = {
@@ -955,12 +1893,13 @@ static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
+ aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1,
+ avg_sample, trig_edge, trig_timer, conv_type);
aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
- aux1_raw);
+ aux1_raw);
return seq_printf(s, "%d,0x%X\n",
- aux1_convert, aux1_raw);
+ aux1_convert, aux1_raw);
}
static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file)
@@ -983,9 +1922,10 @@ static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
+ aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2,
+ avg_sample, trig_edge, trig_timer, conv_type);
aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
- aux2_raw);
+ aux2_raw);
return seq_printf(s, "%d,0x%X\n",
aux2_convert, aux2_raw);
@@ -1011,16 +1951,17 @@ static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
+ main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V,
+ avg_sample, trig_edge, trig_timer, conv_type);
main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
- main_bat_v_raw);
+ main_bat_v_raw);
return seq_printf(s, "%d,0x%X\n",
- main_bat_v_convert, main_bat_v_raw);
+ main_bat_v_convert, main_bat_v_raw);
}
static int ab8500_gpadc_main_bat_v_open(struct inode *inode,
- struct file *file)
+ struct file *file)
{
return single_open(file, ab8500_gpadc_main_bat_v_print, inode->i_private);
}
@@ -1040,12 +1981,13 @@ static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
+ vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V,
+ avg_sample, trig_edge, trig_timer, conv_type);
vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
- vbus_v_raw);
+ vbus_v_raw);
return seq_printf(s, "%d,0x%X\n",
- vbus_v_convert, vbus_v_raw);
+ vbus_v_convert, vbus_v_raw);
}
static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file)
@@ -1068,19 +2010,20 @@ static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
+ main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C,
+ avg_sample, trig_edge, trig_timer, conv_type);
main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- MAIN_CHARGER_C, main_charger_c_raw);
+ MAIN_CHARGER_C, main_charger_c_raw);
return seq_printf(s, "%d,0x%X\n",
- main_charger_c_convert, main_charger_c_raw);
+ main_charger_c_convert, main_charger_c_raw);
}
static int ab8500_gpadc_main_charger_c_open(struct inode *inode,
struct file *file)
{
return single_open(file, ab8500_gpadc_main_charger_c_print,
- inode->i_private);
+ inode->i_private);
}
static const struct file_operations ab8500_gpadc_main_charger_c_fops = {
@@ -1098,19 +2041,20 @@ static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
+ usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C,
+ avg_sample, trig_edge, trig_timer, conv_type);
usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- USB_CHARGER_C, usb_charger_c_raw);
+ USB_CHARGER_C, usb_charger_c_raw);
return seq_printf(s, "%d,0x%X\n",
- usb_charger_c_convert, usb_charger_c_raw);
+ usb_charger_c_convert, usb_charger_c_raw);
}
static int ab8500_gpadc_usb_charger_c_open(struct inode *inode,
struct file *file)
{
return single_open(file, ab8500_gpadc_usb_charger_c_print,
- inode->i_private);
+ inode->i_private);
}
static const struct file_operations ab8500_gpadc_usb_charger_c_fops = {
@@ -1128,12 +2072,13 @@ static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
+ bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V,
+ avg_sample, trig_edge, trig_timer, conv_type);
bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
- BK_BAT_V, bk_bat_v_raw);
+ BK_BAT_V, bk_bat_v_raw);
return seq_printf(s, "%d,0x%X\n",
- bk_bat_v_convert, bk_bat_v_raw);
+ bk_bat_v_convert, bk_bat_v_raw);
}
static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file)
@@ -1156,12 +2101,13 @@ static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
struct ab8500_gpadc *gpadc;
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
- die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
+ die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP,
+ avg_sample, trig_edge, trig_timer, conv_type);
die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
- die_temp_raw);
+ die_temp_raw);
return seq_printf(s, "%d,0x%X\n",
- die_temp_convert, die_temp_raw);
+ die_temp_convert, die_temp_raw);
}
static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file)
@@ -1177,6 +2123,453 @@ static const struct file_operations ab8500_gpadc_die_temp_fops = {
.owner = THIS_MODULE,
};
+static int ab8500_gpadc_usb_id_print(struct seq_file *s, void *p)
+{
+ int usb_id_raw;
+ int usb_id_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ usb_id_raw = ab8500_gpadc_read_raw(gpadc, USB_ID,
+ avg_sample, trig_edge, trig_timer, conv_type);
+ usb_id_convert = ab8500_gpadc_ad_to_voltage(gpadc, USB_ID,
+ usb_id_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ usb_id_convert, usb_id_raw);
+}
+
+static int ab8500_gpadc_usb_id_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_usb_id_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_usb_id_fops = {
+ .open = ab8500_gpadc_usb_id_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_xtal_temp_print(struct seq_file *s, void *p)
+{
+ int xtal_temp_raw;
+ int xtal_temp_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ xtal_temp_raw = ab8500_gpadc_read_raw(gpadc, XTAL_TEMP,
+ avg_sample, trig_edge, trig_timer, conv_type);
+ xtal_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, XTAL_TEMP,
+ xtal_temp_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ xtal_temp_convert, xtal_temp_raw);
+}
+
+static int ab8540_gpadc_xtal_temp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8540_gpadc_xtal_temp_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_xtal_temp_fops = {
+ .open = ab8540_gpadc_xtal_temp_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_true_meas_print(struct seq_file *s, void *p)
+{
+ int vbat_true_meas_raw;
+ int vbat_true_meas_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ vbat_true_meas_raw = ab8500_gpadc_read_raw(gpadc, VBAT_TRUE_MEAS,
+ avg_sample, trig_edge, trig_timer, conv_type);
+ vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBAT_TRUE_MEAS,
+ vbat_true_meas_raw);
+
+ return seq_printf(s, "%d,0x%X\n",
+ vbat_true_meas_convert, vbat_true_meas_raw);
+}
+
+static int ab8540_gpadc_vbat_true_meas_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8540_gpadc_vbat_true_meas_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_true_meas_fops = {
+ .open = ab8540_gpadc_vbat_true_meas_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_bat_ctrl_and_ibat_print(struct seq_file *s, void *p)
+{
+ int bat_ctrl_raw;
+ int bat_ctrl_convert;
+ int ibat_raw;
+ int ibat_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ bat_ctrl_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_CTRL_AND_IBAT,
+ avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+
+ bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, BAT_CTRL,
+ bat_ctrl_raw);
+ ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+ ibat_raw);
+
+ return seq_printf(s, "%d,0x%X\n" "%d,0x%X\n",
+ bat_ctrl_convert, bat_ctrl_raw,
+ ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_bat_ctrl_and_ibat_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8540_gpadc_bat_ctrl_and_ibat_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_bat_ctrl_and_ibat_fops = {
+ .open = ab8540_gpadc_bat_ctrl_and_ibat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_meas_and_ibat_print(struct seq_file *s, void *p)
+{
+ int vbat_meas_raw;
+ int vbat_meas_convert;
+ int ibat_raw;
+ int ibat_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ vbat_meas_raw = ab8500_gpadc_double_read_raw(gpadc, VBAT_MEAS_AND_IBAT,
+ avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+ vbat_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
+ vbat_meas_raw);
+ ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+ ibat_raw);
+
+ return seq_printf(s, "%d,0x%X\n" "%d,0x%X\n",
+ vbat_meas_convert, vbat_meas_raw,
+ ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_vbat_meas_and_ibat_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8540_gpadc_vbat_meas_and_ibat_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_meas_and_ibat_fops = {
+ .open = ab8540_gpadc_vbat_meas_and_ibat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_true_meas_and_ibat_print(struct seq_file *s, void *p)
+{
+ int vbat_true_meas_raw;
+ int vbat_true_meas_convert;
+ int ibat_raw;
+ int ibat_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ vbat_true_meas_raw = ab8500_gpadc_double_read_raw(gpadc,
+ VBAT_TRUE_MEAS_AND_IBAT, avg_sample, trig_edge,
+ trig_timer, conv_type, &ibat_raw);
+ vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+ VBAT_TRUE_MEAS, vbat_true_meas_raw);
+ ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+ ibat_raw);
+
+ return seq_printf(s, "%d,0x%X\n" "%d,0x%X\n",
+ vbat_true_meas_convert, vbat_true_meas_raw,
+ ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_vbat_true_meas_and_ibat_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8540_gpadc_vbat_true_meas_and_ibat_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_true_meas_and_ibat_fops = {
+ .open = ab8540_gpadc_vbat_true_meas_and_ibat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_bat_temp_and_ibat_print(struct seq_file *s, void *p)
+{
+ int bat_temp_raw;
+ int bat_temp_convert;
+ int ibat_raw;
+ int ibat_convert;
+ struct ab8500_gpadc *gpadc;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ bat_temp_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_TEMP_AND_IBAT,
+ avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+ bat_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
+ bat_temp_raw);
+ ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+ ibat_raw);
+
+ return seq_printf(s, "%d,0x%X\n" "%d,0x%X\n",
+ bat_temp_convert, bat_temp_raw,
+ ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_bat_temp_and_ibat_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ab8540_gpadc_bat_temp_and_ibat_print,
+ inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_bat_temp_and_ibat_fops = {
+ .open = ab8540_gpadc_bat_temp_and_ibat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_otp_cal_print(struct seq_file *s, void *p)
+{
+ struct ab8500_gpadc *gpadc;
+ u16 vmain_l, vmain_h, btemp_l, btemp_h;
+ u16 vbat_l, vbat_h, ibat_l, ibat_h;
+
+ gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+ ab8540_gpadc_get_otp(gpadc, &vmain_l, &vmain_h, &btemp_l, &btemp_h,
+ &vbat_l, &vbat_h, &ibat_l, &ibat_h);
+ return seq_printf(s, "VMAIN_L:0x%X\n"
+ "VMAIN_H:0x%X\n"
+ "BTEMP_L:0x%X\n"
+ "BTEMP_H:0x%X\n"
+ "VBAT_L:0x%X\n"
+ "VBAT_H:0x%X\n"
+ "IBAT_L:0x%X\n"
+ "IBAT_H:0x%X\n",
+ vmain_l, vmain_h, btemp_l, btemp_h, vbat_l, vbat_h, ibat_l, ibat_h);
+}
+
+static int ab8540_gpadc_otp_cal_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8540_gpadc_otp_cal_print, inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_otp_calib_fops = {
+ .open = ab8540_gpadc_otp_cal_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "%d\n", avg_sample);
+}
+
+static int ab8500_gpadc_avg_sample_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_avg_sample_print,
+ inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ unsigned long user_avg_sample;
+ int err;
+
+ err = kstrtoul_from_user(user_buf, count, 0, &user_avg_sample);
+ if (err)
+ return err;
+
+ if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4)
+ || (user_avg_sample == SAMPLE_8)
+ || (user_avg_sample == SAMPLE_16)) {
+ avg_sample = (u8) user_avg_sample;
+ } else {
+ dev_err(dev, "debugfs error input: "
+ "should be egal to 1, 4, 8 or 16\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ab8500_gpadc_avg_sample_fops = {
+ .open = ab8500_gpadc_avg_sample_open,
+ .read = seq_read,
+ .write = ab8500_gpadc_avg_sample_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_trig_edge_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "%d\n", trig_edge);
+}
+
+static int ab8500_gpadc_trig_edge_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_trig_edge_print,
+ inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ unsigned long user_trig_edge;
+ int err;
+
+ err = kstrtoul_from_user(user_buf, count, 0, &user_trig_edge);
+ if (err)
+ return err;
+
+ if ((user_trig_edge == RISING_EDGE)
+ || (user_trig_edge == FALLING_EDGE)) {
+ trig_edge = (u8) user_trig_edge;
+ } else {
+ dev_err(dev, "Wrong input:\n"
+ "Enter 0. Rising edge\n"
+ "Enter 1. Falling edge\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ab8500_gpadc_trig_edge_fops = {
+ .open = ab8500_gpadc_trig_edge_open,
+ .read = seq_read,
+ .write = ab8500_gpadc_trig_edge_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_trig_timer_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "%d\n", trig_timer);
+}
+
+static int ab8500_gpadc_trig_timer_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_trig_timer_print,
+ inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ unsigned long user_trig_timer;
+ int err;
+
+ err = kstrtoul_from_user(user_buf, count, 0, &user_trig_timer);
+ if (err)
+ return err;
+
+ if ((user_trig_timer >= 0) && (user_trig_timer <= 255)) {
+ trig_timer = (u8) user_trig_timer;
+ } else {
+ dev_err(dev, "debugfs error input: "
+ "should be beetween 0 to 255\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ab8500_gpadc_trig_timer_fops = {
+ .open = ab8500_gpadc_trig_timer_open,
+ .read = seq_read,
+ .write = ab8500_gpadc_trig_timer_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_conv_type_print(struct seq_file *s, void *p)
+{
+ return seq_printf(s, "%d\n", conv_type);
+}
+
+static int ab8500_gpadc_conv_type_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ab8500_gpadc_conv_type_print,
+ inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct device *dev = ((struct seq_file *)(file->private_data))->private;
+ unsigned long user_conv_type;
+ int err;
+
+ err = kstrtoul_from_user(user_buf, count, 0, &user_conv_type);
+ if (err)
+ return err;
+
+ if ((user_conv_type == ADC_SW)
+ || (user_conv_type == ADC_HW)) {
+ conv_type = (u8) user_conv_type;
+ } else {
+ dev_err(dev, "Wrong input:\n"
+ "Enter 0. ADC SW conversion\n"
+ "Enter 1. ADC HW conversion\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ab8500_gpadc_conv_type_fops = {
+ .open = ab8500_gpadc_conv_type_open,
+ .read = seq_read,
+ .write = ab8500_gpadc_conv_type_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
/*
* return length of an ASCII numerical value, 0 is string is not a
* numerical value.
@@ -1352,7 +2745,7 @@ static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
struct file *file)
{
return single_open(file, ab8500_subscribe_unsubscribe_print,
- inode->i_private);
+ inode->i_private);
}
/*
@@ -1382,21 +2775,14 @@ static ssize_t ab8500_subscribe_write(struct file *file,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
unsigned long user_val;
int err;
unsigned int irq_index;
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
+ err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
- return -EINVAL;
+ return err;
+
if (user_val < irq_first) {
dev_err(dev, "debugfs error input < %d\n", irq_first);
return -EINVAL;
@@ -1416,7 +2802,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
*/
dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
GFP_KERNEL);
- event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
+ event_name[irq_index] = kmalloc(count, GFP_KERNEL);
sprintf(event_name[irq_index], "%lu", user_val);
dev_attr[irq_index]->show = show_irq;
dev_attr[irq_index]->store = NULL;
@@ -1438,7 +2824,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
return err;
}
- return buf_size;
+ return count;
}
static ssize_t ab8500_unsubscribe_write(struct file *file,
@@ -1446,21 +2832,14 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
unsigned long user_val;
int err;
unsigned int irq_index;
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
+ err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
- return -EINVAL;
+ return err;
+
if (user_val < irq_first) {
dev_err(dev, "debugfs error input < %d\n", irq_first);
return -EINVAL;
@@ -1485,7 +2864,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
kfree(event_name[irq_index]);
kfree(dev_attr[irq_index]);
- return buf_size;
+ return count;
}
/*
@@ -1583,7 +2962,7 @@ static int ab8500_debug_probe(struct platform_device *plf)
irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
if (irq_first < 0) {
dev_err(&plf->dev, "First irq not found, err %d\n",
- irq_first);
+ irq_first);
ret = irq_first;
goto out_freeevent_name;
}
@@ -1591,9 +2970,9 @@ static int ab8500_debug_probe(struct platform_device *plf)
irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
if (irq_last < 0) {
dev_err(&plf->dev, "Last irq not found, err %d\n",
- irq_last);
+ irq_last);
ret = irq_last;
- goto out_freeevent_name;
+ goto out_freeevent_name;
}
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
@@ -1601,124 +2980,198 @@ static int ab8500_debug_probe(struct platform_device *plf)
goto err;
ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
- ab8500_dir);
+ ab8500_dir);
if (!ab8500_gpadc_dir)
goto err;
file = debugfs_create_file("all-bank-registers", S_IRUGO,
- ab8500_dir, &plf->dev, &ab8500_registers_fops);
+ ab8500_dir, &plf->dev, &ab8500_registers_fops);
if (!file)
goto err;
file = debugfs_create_file("all-banks", S_IRUGO,
- ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
+ ab8500_dir, &plf->dev, &ab8500_all_banks_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_bank_fops);
+ file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_bank_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_address_fops);
+ file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_address_fops);
if (!file)
goto err;
- file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_val_fops);
+ file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_val_fops);
if (!file)
goto err;
- file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
+ file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
if (!file)
goto err;
- if (is_ab8500(ab8500))
+ if (is_ab8500(ab8500)) {
+ debug_ranges = ab8500_debug_ranges;
num_interrupt_lines = AB8500_NR_IRQS;
- else if (is_ab8505(ab8500))
+ } else if (is_ab8505(ab8500)) {
+ debug_ranges = ab8505_debug_ranges;
num_interrupt_lines = AB8505_NR_IRQS;
- else if (is_ab9540(ab8500))
+ } else if (is_ab9540(ab8500)) {
+ debug_ranges = ab8505_debug_ranges;
num_interrupt_lines = AB9540_NR_IRQS;
+ } else if (is_ab8540(ab8500)) {
+ debug_ranges = ab8540_debug_ranges;
+ num_interrupt_lines = AB8540_NR_IRQS;
+ }
file = debugfs_create_file("interrupts", (S_IRUGO),
- ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
+ ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
if (!file)
goto err;
- file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
+ file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
if (!file)
goto err;
- file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
- ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
+ file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
if (!file)
goto err;
- file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
+ file = debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_dir, &plf->dev, &ab8500_modem_fops);
if (!file)
goto err;
- file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
+ file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
if (!file)
goto err;
- file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
+ file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
if (!file)
goto err;
- file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
+ file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
if (!file)
goto err;
- file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
+ file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
if (!file)
goto err;
- file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
+ file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
if (!file)
goto err;
- file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
+ file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
if (!file)
goto err;
- file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
+ file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
if (!file)
goto err;
- file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
+ file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
if (!file)
goto err;
- file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
+ file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
+ if (!file)
+ goto err;
+
+ file = debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_id_fops);
+ if (!file)
+ goto err;
+
+ if (is_ab8540(ab8500)) {
+ file = debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_xtal_temp_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev,
+ &ab8540_gpadc_vbat_true_meas_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("batctrl_and_ibat",
+ (S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+ &plf->dev, &ab8540_gpadc_bat_ctrl_and_ibat_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("vbatmeas_and_ibat",
+ (S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+ &plf->dev,
+ &ab8540_gpadc_vbat_meas_and_ibat_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("vbattruemeas_and_ibat",
+ (S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+ &plf->dev,
+ &ab8540_gpadc_vbat_true_meas_and_ibat_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("battemp_and_ibat",
+ (S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+ &plf->dev, &ab8540_gpadc_bat_temp_and_ibat_fops);
+ if (!file)
+ goto err;
+ file = debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_otp_calib_fops);
+ if (!file)
+ goto err;
+ }
+ file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_avg_sample_fops);
if (!file)
goto err;
- file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
+ file = debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_edge_fops);
if (!file)
goto err;
- file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
+ file = debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_timer_fops);
if (!file)
goto err;
- file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
- ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
+ file = debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_conv_type_fops);
if (!file)
goto err;
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 5f341a50ee5a..65f72284185d 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -37,6 +37,13 @@
#define AB8500_GPADC_AUTODATAL_REG 0x07
#define AB8500_GPADC_AUTODATAH_REG 0x08
#define AB8500_GPADC_MUX_CTRL_REG 0x09
+#define AB8540_GPADC_MANDATA2L_REG 0x09
+#define AB8540_GPADC_MANDATA2H_REG 0x0A
+#define AB8540_GPADC_APEAAX_REG 0x10
+#define AB8540_GPADC_APEAAT_REG 0x11
+#define AB8540_GPADC_APEAAM_REG 0x12
+#define AB8540_GPADC_APEAAH_REG 0x13
+#define AB8540_GPADC_APEAAL_REG 0x14
/*
* OTP register offsets
@@ -49,19 +56,29 @@
#define AB8500_GPADC_CAL_5 0x13
#define AB8500_GPADC_CAL_6 0x14
#define AB8500_GPADC_CAL_7 0x15
+/* New calibration for 8540 */
+#define AB8540_GPADC_OTP4_REG_7 0x38
+#define AB8540_GPADC_OTP4_REG_6 0x39
+#define AB8540_GPADC_OTP4_REG_5 0x3A
/* gpadc constants */
#define EN_VINTCORE12 0x04
#define EN_VTVOUT 0x02
#define EN_GPADC 0x01
#define DIS_GPADC 0x00
-#define SW_AVG_16 0x60
+#define AVG_1 0x00
+#define AVG_4 0x20
+#define AVG_8 0x40
+#define AVG_16 0x60
#define ADC_SW_CONV 0x04
#define EN_ICHAR 0x80
#define BTEMP_PULL_UP 0x08
#define EN_BUF 0x40
#define DIS_ZERO 0x00
#define GPADC_BUSY 0x01
+#define EN_FALLING 0x10
+#define EN_TRIG_EDGE 0x02
+#define EN_VBIAS_XTAL_TEMP 0x02
/* GPADC constants from AB8500 spec, UM0836 */
#define ADC_RESOLUTION 1024
@@ -80,8 +97,21 @@
#define ADC_CH_BKBAT_MIN 0
#define ADC_CH_BKBAT_MAX 3200
+/* GPADC constants from AB8540 spec */
+#define ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat*/
+#define ADC_CH_IBAT_MAX 6000
+#define ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat*/
+#define ADC_CH_IBAT_MAX_V 60
+#define IBAT_VDROP_L (-56) /* mV */
+#define IBAT_VDROP_H 56
+
/* This is used to not lose precision when dividing to get gain and offset */
-#define CALIB_SCALE 1000
+#define CALIB_SCALE 1000
+/*
+ * Number of bits shift used to not lose precision
+ * when dividing to get ibat gain.
+ */
+#define CALIB_SHIFT_IBAT 20
/* Time in ms before disabling regulator */
#define GPADC_AUDOSUSPEND_DELAY 1
@@ -92,6 +122,7 @@ enum cal_channels {
ADC_INPUT_VMAIN = 0,
ADC_INPUT_BTEMP,
ADC_INPUT_VBAT,
+ ADC_INPUT_IBAT,
NBR_CAL_INPUTS,
};
@@ -102,8 +133,10 @@ enum cal_channels {
* @offset: Offset of the ADC channel
*/
struct adc_cal_data {
- u64 gain;
- u64 offset;
+ s64 gain;
+ s64 offset;
+ u16 otp_calib_hi;
+ u16 otp_calib_lo;
};
/**
@@ -116,7 +149,10 @@ struct adc_cal_data {
* the completion of gpadc conversion
* @ab8500_gpadc_lock: structure of type mutex
* @regu: pointer to the struct regulator
- * @irq: interrupt number that is used by gpadc
+ * @irq_sw: interrupt number that is used by gpadc for Sw
+ * conversion
+ * @irq_hw: interrupt number that is used by gpadc for Hw
+ * conversion
* @cal_data array of ADC calibration data structs
*/
struct ab8500_gpadc {
@@ -126,7 +162,8 @@ struct ab8500_gpadc {
struct completion ab8500_gpadc_complete;
struct mutex ab8500_gpadc_lock;
struct regulator *regu;
- int irq;
+ int irq_sw;
+ int irq_hw;
struct adc_cal_data cal_data[NBR_CAL_INPUTS];
};
@@ -171,6 +208,7 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE;
break;
+ case XTAL_TEMP:
case BAT_CTRL:
case BTEMP_BALL:
case ACC_DETECT1:
@@ -189,6 +227,7 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
break;
case MAIN_BAT_V:
+ case VBAT_TRUE_MEAS:
/* For some reason we don't have calibrated data */
if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) {
res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX -
@@ -232,6 +271,20 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
ADC_RESOLUTION;
break;
+ case IBAT_VIRTUAL_CHANNEL:
+ /* For some reason we don't have calibrated data */
+ if (!gpadc->cal_data[ADC_INPUT_IBAT].gain) {
+ res = ADC_CH_IBAT_MIN + (ADC_CH_IBAT_MAX -
+ ADC_CH_IBAT_MIN) * ad_value /
+ ADC_RESOLUTION;
+ break;
+ }
+ /* Here we can use the calibrated data */
+ res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_IBAT].gain +
+ gpadc->cal_data[ADC_INPUT_IBAT].offset)
+ >> CALIB_SHIFT_IBAT;
+ break;
+
default:
dev_err(gpadc->dev,
"unknown channel, not possible to convert\n");
@@ -244,25 +297,35 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
EXPORT_SYMBOL(ab8500_gpadc_ad_to_voltage);
/**
- * ab8500_gpadc_convert() - gpadc conversion
+ * ab8500_gpadc_sw_hw_convert() - gpadc conversion
* @channel: analog channel to be converted to digital data
+ * @avg_sample: number of ADC sample to average
+ * @trig_egde: selected ADC trig edge
+ * @trig_timer: selected ADC trigger delay timer
+ * @conv_type: selected conversion type (HW or SW conversion)
*
* This function converts the selected analog i/p to digital
* data.
*/
-int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
+int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
{
int ad_value;
int voltage;
- ad_value = ab8500_gpadc_read_raw(gpadc, channel);
- if (ad_value < 0) {
- dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n", channel);
+ ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
+ trig_edge, trig_timer, conv_type);
+/* On failure retry a second time */
+ if (ad_value < 0)
+ ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
+ trig_edge, trig_timer, conv_type);
+if (ad_value < 0) {
+ dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n",
+ channel);
return ad_value;
}
voltage = ab8500_gpadc_ad_to_voltage(gpadc, channel, ad_value);
-
if (voltage < 0)
dev_err(gpadc->dev, "GPADC to voltage conversion failed ch:"
" %d AD: 0x%x\n", channel, ad_value);
@@ -274,21 +337,46 @@ EXPORT_SYMBOL(ab8500_gpadc_convert);
/**
* ab8500_gpadc_read_raw() - gpadc read
* @channel: analog channel to be read
+ * @avg_sample: number of ADC sample to average
+ * @trig_edge: selected trig edge
+ * @trig_timer: selected ADC trigger delay timer
+ * @conv_type: selected conversion type (HW or SW conversion)
*
- * This function obtains the raw ADC value, this then needs
- * to be converted by calling ab8500_gpadc_ad_to_voltage()
+ * This function obtains the raw ADC value for an hardware conversion,
+ * this then needs to be converted by calling ab8500_gpadc_ad_to_voltage()
*/
-int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
+int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
+{
+ int raw_data;
+ raw_data = ab8500_gpadc_double_read_raw(gpadc, channel,
+ avg_sample, trig_edge, trig_timer, conv_type, NULL);
+ return raw_data;
+}
+
+int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
+ int *ibat)
{
int ret;
int looplimit = 0;
- u8 val, low_data, high_data;
+ unsigned long completion_timeout;
+ u8 val, low_data, high_data, low_data2, high_data2;
+ u8 val_reg1 = 0;
+ unsigned int delay_min = 0;
+ unsigned int delay_max = 0;
+ u8 data_low_addr, data_high_addr;
if (!gpadc)
return -ENODEV;
- mutex_lock(&gpadc->ab8500_gpadc_lock);
+ /* check if convertion is supported */
+ if ((gpadc->irq_sw < 0) && (conv_type == ADC_SW))
+ return -ENOTSUPP;
+ if ((gpadc->irq_hw < 0) && (conv_type == ADC_HW))
+ return -ENOTSUPP;
+ mutex_lock(&gpadc->ab8500_gpadc_lock);
/* Enable VTVout LDO this is required for GPADC */
pm_runtime_get_sync(gpadc->dev);
@@ -309,16 +397,34 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
}
/* Enable GPADC */
- ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
- AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
- if (ret < 0) {
- dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
- goto out;
+ val_reg1 |= EN_GPADC;
+
+ /* Select the channel source and set average samples */
+ switch (avg_sample) {
+ case SAMPLE_1:
+ val = channel | AVG_1;
+ break;
+ case SAMPLE_4:
+ val = channel | AVG_4;
+ break;
+ case SAMPLE_8:
+ val = channel | AVG_8;
+ break;
+ default:
+ val = channel | AVG_16;
+ break;
}
- /* Select the channel source and set average samples to 16 */
- ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
- AB8500_GPADC_CTRL2_REG, (channel | SW_AVG_16));
+ if (conv_type == ADC_HW) {
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val);
+ val_reg1 |= EN_TRIG_EDGE;
+ if (trig_edge)
+ val_reg1 |= EN_FALLING;
+ }
+ else
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val);
if (ret < 0) {
dev_err(gpadc->dev,
"gpadc_conversion: set avg samples failed\n");
@@ -333,71 +439,129 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
switch (channel) {
case MAIN_CHARGER_C:
case USB_CHARGER_C:
- ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
- AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
- EN_BUF | EN_ICHAR,
- EN_BUF | EN_ICHAR);
+ val_reg1 |= EN_BUF | EN_ICHAR;
break;
case BTEMP_BALL:
if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
- /* Turn on btemp pull-up on ABB 3.0 */
- ret = abx500_mask_and_set_register_interruptible(
- gpadc->dev,
- AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
- EN_BUF | BTEMP_PULL_UP,
- EN_BUF | BTEMP_PULL_UP);
-
- /*
- * Delay might be needed for ABB8500 cut 3.0, if not, remove
- * when hardware will be available
- */
- usleep_range(1000, 1000);
+ val_reg1 |= EN_BUF | BTEMP_PULL_UP;
+ /*
+ * Delay might be needed for ABB8500 cut 3.0, if not,
+ * remove when hardware will be availible
+ */
+ delay_min = 1000; /* Delay in micro seconds */
+ delay_max = 10000; /* large range to optimise sleep mode */
break;
}
/* Intentional fallthrough */
default:
- ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
- AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
+ val_reg1 |= EN_BUF;
break;
}
+
+ /* Write configuration to register */
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL1_REG, val_reg1);
if (ret < 0) {
dev_err(gpadc->dev,
- "gpadc_conversion: select falling edge failed\n");
+ "gpadc_conversion: set Control register failed\n");
goto out;
}
- ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
- AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
- if (ret < 0) {
- dev_err(gpadc->dev,
- "gpadc_conversion: start s/w conversion failed\n");
- goto out;
+ if (delay_min != 0)
+ usleep_range(delay_min, delay_max);
+
+ if (conv_type == ADC_HW) {
+ /* Set trigger delay timer */
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: trig timer failed\n");
+ goto out;
+ }
+ completion_timeout = 2 * HZ;
+ data_low_addr = AB8500_GPADC_AUTODATAL_REG;
+ data_high_addr = AB8500_GPADC_AUTODATAH_REG;
+ } else {
+ /* Start SW conversion */
+ ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+ ADC_SW_CONV, ADC_SW_CONV);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: start s/w conv failed\n");
+ goto out;
+ }
+ completion_timeout = msecs_to_jiffies(CONVERSION_TIME);
+ data_low_addr = AB8500_GPADC_MANDATAL_REG;
+ data_high_addr = AB8500_GPADC_MANDATAH_REG;
}
+
/* wait for completion of conversion */
if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
- msecs_to_jiffies(CONVERSION_TIME))) {
+ completion_timeout)) {
dev_err(gpadc->dev,
- "timeout: didn't receive GPADC conversion interrupt\n");
+ "timeout didn't receive GPADC conv interrupt\n");
ret = -EINVAL;
goto out;
}
/* Read the converted RAW data */
- ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
- AB8500_GPADC_MANDATAL_REG, &low_data);
+ ret = abx500_get_register_interruptible(gpadc->dev,
+ AB8500_GPADC, data_low_addr, &low_data);
if (ret < 0) {
dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
goto out;
}
- ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
- AB8500_GPADC_MANDATAH_REG, &high_data);
+ ret = abx500_get_register_interruptible(gpadc->dev,
+ AB8500_GPADC, data_high_addr, &high_data);
if (ret < 0) {
- dev_err(gpadc->dev,
- "gpadc_conversion: read high data failed\n");
+ dev_err(gpadc->dev, "gpadc_conversion: read high data failed\n");
goto out;
}
+ /* Check if double convertion is required */
+ if ((channel == BAT_CTRL_AND_IBAT) ||
+ (channel == VBAT_MEAS_AND_IBAT) ||
+ (channel == VBAT_TRUE_MEAS_AND_IBAT) ||
+ (channel == BAT_TEMP_AND_IBAT)) {
+
+ if (conv_type == ADC_HW) {
+ /* not supported */
+ ret = -ENOTSUPP;
+ dev_err(gpadc->dev,
+ "gpadc_conversion: only SW double conversion supported\n");
+ goto out;
+ } else {
+ /* Read the converted RAW data 2 */
+ ret = abx500_get_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8540_GPADC_MANDATA2L_REG,
+ &low_data2);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: read sw low data 2 failed\n");
+ goto out;
+ }
+
+ ret = abx500_get_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8540_GPADC_MANDATA2H_REG,
+ &high_data2);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: read sw high data 2 failed\n");
+ goto out;
+ }
+ if (ibat != NULL) {
+ *ibat = (high_data2 << 8) | low_data2;
+ } else {
+ dev_warn(gpadc->dev,
+ "gpadc_conversion: ibat not stored\n");
+ }
+
+ }
+ }
+
/* Disable GPADC */
ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
@@ -406,6 +570,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
goto out;
}
+ /* Disable VTVout LDO this is required for GPADC */
pm_runtime_mark_last_busy(gpadc->dev);
pm_runtime_put_autosuspend(gpadc->dev);
@@ -422,9 +587,7 @@ out:
*/
(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
AB8500_GPADC_CTRL1_REG, DIS_GPADC);
-
pm_runtime_put(gpadc->dev);
-
mutex_unlock(&gpadc->ab8500_gpadc_lock);
dev_err(gpadc->dev,
"gpadc_conversion: Failed to AD convert channel %d\n", channel);
@@ -433,16 +596,16 @@ out:
EXPORT_SYMBOL(ab8500_gpadc_read_raw);
/**
- * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
+ * ab8500_bm_gpadcconvend_handler() - isr for gpadc conversion completion
* @irq: irq number
* @data: pointer to the data passed during request irq
*
- * This is a interrupt service routine for s/w gpadc conversion completion.
+ * This is a interrupt service routine for gpadc conversion completion.
* Notifies the gpadc completion is completed and the converted raw value
* can be read from the registers.
* Returns IRQ status(IRQ_HANDLED)
*/
-static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
+static irqreturn_t ab8500_bm_gpadcconvend_handler(int irq, void *_gpadc)
{
struct ab8500_gpadc *gpadc = _gpadc;
@@ -461,15 +624,27 @@ static int otp_cal_regs[] = {
AB8500_GPADC_CAL_7,
};
+static int otp4_cal_regs[] = {
+ AB8540_GPADC_OTP4_REG_7,
+ AB8540_GPADC_OTP4_REG_6,
+ AB8540_GPADC_OTP4_REG_5,
+};
+
static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
{
int i;
int ret[ARRAY_SIZE(otp_cal_regs)];
u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)];
-
+ int ret_otp4[ARRAY_SIZE(otp4_cal_regs)];
+ u8 gpadc_otp4[ARRAY_SIZE(otp4_cal_regs)];
int vmain_high, vmain_low;
int btemp_high, btemp_low;
int vbat_high, vbat_low;
+ int ibat_high, ibat_low;
+ s64 V_gain, V_offset, V2A_gain, V2A_offset;
+ struct ab8500 *ab8500;
+
+ ab8500 = gpadc->parent;
/* First we read all OTP registers and store the error code */
for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) {
@@ -489,7 +664,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
* bt_h/l = btemp_high/low
* vb_h/l = vbat_high/low
*
- * Data bits:
+ * Data bits 8500/9540:
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
* |.......|.......|.......|.......|.......|.......|.......|.......
* | | vm_h9 | vm_h8
@@ -507,6 +682,35 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
* | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
* |.......|.......|.......|.......|.......|.......|.......|.......
*
+ * Data bits 8540:
+ * OTP2
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * |
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | vm_h9 | vm_h8 | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ *
+ * Data bits 8540:
+ * OTP4
+ * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | | ib_h9 | ib_h8 | ib_h7
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | ib_h6 | ib_h5 | ib_h4 | ib_h3 | ib_h2 | ib_h1 | ib_h0 | ib_l5
+ * |.......|.......|.......|.......|.......|.......|.......|.......
+ * | ib_l4 | ib_l3 | ib_l2 | ib_l1 | ib_l0 |
+ *
*
* Ideal output ADC codes corresponding to injected input voltages
* during manufacturing is:
@@ -519,38 +723,116 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
* vbat_low: Vin = 2380mV / ADC ideal code = 33
*/
- /* Calculate gain and offset for VMAIN if all reads succeeded */
- if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
- vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
- ((gpadc_cal[1] & 0x3F) << 2) |
- ((gpadc_cal[2] & 0xC0) >> 6));
+ if (is_ab8540(ab8500)) {
+ /* Calculate gain and offset for VMAIN if all reads succeeded*/
+ if (!(ret[1] < 0 || ret[2] < 0)) {
+ vmain_high = (((gpadc_cal[1] & 0xFF) << 2) |
+ ((gpadc_cal[2] & 0xC0) >> 6));
+ vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+
+ gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi =
+ (u16)vmain_high;
+ gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo =
+ (u16)vmain_low;
+
+ gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
+ (19500 - 315) / (vmain_high - vmain_low);
+ gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE *
+ 19500 - (CALIB_SCALE * (19500 - 315) /
+ (vmain_high - vmain_low)) * vmain_high;
+ } else {
+ gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+ }
- vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+ /* Read IBAT calibration Data */
+ for (i = 0; i < ARRAY_SIZE(otp4_cal_regs); i++) {
+ ret_otp4[i] = abx500_get_register_interruptible(
+ gpadc->dev, AB8500_OTP_EMUL,
+ otp4_cal_regs[i], &gpadc_otp4[i]);
+ if (ret_otp4[i] < 0)
+ dev_err(gpadc->dev,
+ "%s: read otp4 reg 0x%02x failed\n",
+ __func__, otp4_cal_regs[i]);
+ }
- gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
- (19500 - 315) / (vmain_high - vmain_low);
+ /* Calculate gain and offset for IBAT if all reads succeeded */
+ if (!(ret_otp4[0] < 0 || ret_otp4[1] < 0 || ret_otp4[2] < 0)) {
+ ibat_high = (((gpadc_otp4[0] & 0x07) << 7) |
+ ((gpadc_otp4[1] & 0xFE) >> 1));
+ ibat_low = (((gpadc_otp4[1] & 0x01) << 5) |
+ ((gpadc_otp4[2] & 0xF8) >> 3));
+
+ gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi =
+ (u16)ibat_high;
+ gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo =
+ (u16)ibat_low;
+
+ V_gain = ((IBAT_VDROP_H - IBAT_VDROP_L)
+ << CALIB_SHIFT_IBAT) / (ibat_high - ibat_low);
+
+ V_offset = (IBAT_VDROP_H << CALIB_SHIFT_IBAT) -
+ (((IBAT_VDROP_H - IBAT_VDROP_L) <<
+ CALIB_SHIFT_IBAT) / (ibat_high - ibat_low))
+ * ibat_high;
+ /*
+ * Result obtained is in mV (at a scale factor),
+ * we need to calculate gain and offset to get mA
+ */
+ V2A_gain = (ADC_CH_IBAT_MAX - ADC_CH_IBAT_MIN)/
+ (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V);
+ V2A_offset = ((ADC_CH_IBAT_MAX_V * ADC_CH_IBAT_MIN -
+ ADC_CH_IBAT_MAX * ADC_CH_IBAT_MIN_V)
+ << CALIB_SHIFT_IBAT)
+ / (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V);
+
+ gpadc->cal_data[ADC_INPUT_IBAT].gain = V_gain * V2A_gain;
+ gpadc->cal_data[ADC_INPUT_IBAT].offset = V_offset *
+ V2A_gain + V2A_offset;
+ } else {
+ gpadc->cal_data[ADC_INPUT_IBAT].gain = 0;
+ }
- gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 -
- (CALIB_SCALE * (19500 - 315) /
- (vmain_high - vmain_low)) * vmain_high;
+ dev_dbg(gpadc->dev, "IBAT gain %llu offset %llu\n",
+ gpadc->cal_data[ADC_INPUT_IBAT].gain,
+ gpadc->cal_data[ADC_INPUT_IBAT].offset);
} else {
- gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+ /* Calculate gain and offset for VMAIN if all reads succeeded */
+ if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
+ vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
+ ((gpadc_cal[1] & 0x3F) << 2) |
+ ((gpadc_cal[2] & 0xC0) >> 6));
+ vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+
+ gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi =
+ (u16)vmain_high;
+ gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo =
+ (u16)vmain_low;
+
+ gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
+ (19500 - 315) / (vmain_high - vmain_low);
+
+ gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE *
+ 19500 - (CALIB_SCALE * (19500 - 315) /
+ (vmain_high - vmain_low)) * vmain_high;
+ } else {
+ gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+ }
}
/* Calculate gain and offset for BTEMP if all reads succeeded */
if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) {
btemp_high = (((gpadc_cal[2] & 0x01) << 9) |
- (gpadc_cal[3] << 1) |
- ((gpadc_cal[4] & 0x80) >> 7));
-
+ (gpadc_cal[3] << 1) | ((gpadc_cal[4] & 0x80) >> 7));
btemp_low = ((gpadc_cal[4] & 0x7C) >> 2);
+ gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi = (u16)btemp_high;
+ gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo = (u16)btemp_low;
+
gpadc->cal_data[ADC_INPUT_BTEMP].gain =
CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low);
-
gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 -
- (CALIB_SCALE * (1300 - 21) /
- (btemp_high - btemp_low)) * btemp_high;
+ (CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low))
+ * btemp_high;
} else {
gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0;
}
@@ -560,9 +842,11 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]);
vbat_low = ((gpadc_cal[6] & 0xFC) >> 2);
+ gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi = (u16)vbat_high;
+ gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo = (u16)vbat_low;
+
gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE *
(4700 - 2380) / (vbat_high - vbat_low);
-
gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 -
(CALIB_SCALE * (4700 - 2380) /
(vbat_high - vbat_low)) * vbat_high;
@@ -608,6 +892,31 @@ static int ab8500_gpadc_runtime_idle(struct device *dev)
return 0;
}
+static int ab8500_gpadc_suspend(struct device *dev)
+{
+ struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+ mutex_lock(&gpadc->ab8500_gpadc_lock);
+
+ pm_runtime_get_sync(dev);
+
+ regulator_disable(gpadc->regu);
+ return 0;
+}
+
+static int ab8500_gpadc_resume(struct device *dev)
+{
+ struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+ regulator_enable(gpadc->regu);
+
+ pm_runtime_mark_last_busy(gpadc->dev);
+ pm_runtime_put_autosuspend(gpadc->dev);
+
+ mutex_unlock(&gpadc->ab8500_gpadc_lock);
+ return 0;
+}
+
static int ab8500_gpadc_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -619,13 +928,13 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
return -ENOMEM;
}
- gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
- if (gpadc->irq < 0) {
- dev_err(&pdev->dev, "failed to get platform irq-%d\n",
- gpadc->irq);
- ret = gpadc->irq;
- goto fail;
- }
+ gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END");
+ if (gpadc->irq_sw < 0)
+ dev_err(gpadc->dev, "failed to get platform sw_conv_end irq\n");
+
+ gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
+ if (gpadc->irq_hw < 0)
+ dev_err(gpadc->dev, "failed to get platform hw_conv_end irq\n");
gpadc->dev = &pdev->dev;
gpadc->parent = dev_get_drvdata(pdev->dev.parent);
@@ -634,15 +943,31 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
/* Initialize completion used to notify completion of conversion */
init_completion(&gpadc->ab8500_gpadc_complete);
- /* Register interrupt - SwAdcComplete */
- ret = request_threaded_irq(gpadc->irq, NULL,
- ab8500_bm_gpswadcconvend_handler,
- IRQF_ONESHOT | IRQF_NO_SUSPEND | IRQF_SHARED,
- "ab8500-gpadc", gpadc);
- if (ret < 0) {
- dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
- gpadc->irq);
- goto fail;
+ /* Register interrupts */
+ if (gpadc->irq_sw >= 0) {
+ ret = request_threaded_irq(gpadc->irq_sw, NULL,
+ ab8500_bm_gpadcconvend_handler,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-sw",
+ gpadc);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "Failed to register interrupt irq: %d\n",
+ gpadc->irq_sw);
+ goto fail;
+ }
+ }
+
+ if (gpadc->irq_hw >= 0) {
+ ret = request_threaded_irq(gpadc->irq_hw, NULL,
+ ab8500_bm_gpadcconvend_handler,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-hw",
+ gpadc);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "Failed to register interrupt irq: %d\n",
+ gpadc->irq_hw);
+ goto fail_irq;
+ }
}
/* VTVout LDO used to power up ab8500-GPADC */
@@ -669,11 +994,13 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
ab8500_gpadc_read_calibration_data(gpadc);
list_add_tail(&gpadc->node, &ab8500_gpadc_list);
dev_dbg(gpadc->dev, "probe success\n");
+
return 0;
fail_enable:
fail_irq:
- free_irq(gpadc->irq, gpadc);
+ free_irq(gpadc->irq_sw, gpadc);
+ free_irq(gpadc->irq_hw, gpadc);
fail:
kfree(gpadc);
gpadc = NULL;
@@ -687,7 +1014,10 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
/* remove this gpadc entry from the list */
list_del(&gpadc->node);
/* remove interrupt - completion of Sw ADC conversion */
- free_irq(gpadc->irq, gpadc);
+ if (gpadc->irq_sw >= 0)
+ free_irq(gpadc->irq_sw, gpadc);
+ if (gpadc->irq_hw >= 0)
+ free_irq(gpadc->irq_hw, gpadc);
pm_runtime_get_sync(gpadc->dev);
pm_runtime_disable(gpadc->dev);
@@ -707,6 +1037,9 @@ static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
ab8500_gpadc_runtime_resume,
ab8500_gpadc_runtime_idle)
+ SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
+ ab8500_gpadc_resume)
+
};
static struct platform_driver ab8500_gpadc_driver = {
@@ -729,10 +1062,30 @@ static void __exit ab8500_gpadc_exit(void)
platform_driver_unregister(&ab8500_gpadc_driver);
}
+/**
+ * ab8540_gpadc_get_otp() - returns OTP values
+ *
+ */
+void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
+ u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
+ u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h)
+{
+ *vmain_l = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo;
+ *vmain_h = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi;
+ *btemp_l = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo;
+ *btemp_h = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi;
+ *vbat_l = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo;
+ *vbat_h = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi;
+ *ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
+ *ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
+ return ;
+}
+
subsys_initcall_sync(ab8500_gpadc_init);
module_exit(ab8500_gpadc_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson");
+MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson,"
+ "M'boumba Cedric Madianga");
MODULE_ALIAS("platform:ab8500_gpadc");
MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 108fd86552f0..272479cdb107 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -15,19 +15,30 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
+/* RtcCtrl bits */
+#define AB8500_ALARM_MIN_LOW 0x08
+#define AB8500_ALARM_MIN_MID 0x09
+#define RTC_CTRL 0x0B
+#define RTC_ALARM_ENABLE 0x4
+
static struct device *sysctrl_dev;
void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
- static char *pss[] = {"ab8500_ac", "ab8500_usb"};
+ static char *pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
int i;
bool charger_present = false;
union power_supply_propval val;
struct power_supply *psy;
int ret;
+ if (sysctrl_dev == NULL) {
+ pr_err("%s: sysctrl not initialized\n", __func__);
+ return;
+ }
+
/*
* If we have a charger connected and we're powering off,
* reboot into charge-only mode.
@@ -74,6 +85,63 @@ shutdown:
}
}
+/*
+ * Use the AB WD to reset the platform. It will perform a hard
+ * reset instead of a soft reset. Write the reset reason to
+ * the AB before reset, which can be read upon restart.
+ */
+void ab8500_restart(char mode, const char *cmd)
+{
+ struct ab8500_platform_data *plat;
+ struct ab8500_sysctrl_platform_data *pdata;
+ u16 reason = 0;
+ u8 val;
+
+ if (sysctrl_dev == NULL) {
+ pr_err("%s: sysctrl not initialized\n", __func__);
+ return;
+ }
+
+ plat = dev_get_platdata(sysctrl_dev->parent);
+ pdata = plat->sysctrl;
+ if (pdata->reboot_reason_code)
+ reason = pdata->reboot_reason_code(cmd);
+ else
+ pr_warn("[%s] No reboot reason set. Default reason %d\n",
+ __func__, reason);
+
+ /*
+ * Disable RTC alarm, just a precaution so that no alarm
+ * is running when WD reset is executed.
+ */
+ abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
+ RTC_CTRL , &val);
+ abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+ RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
+
+ /*
+ * Android is not using the RTC alarm registers during reboot
+ * so we borrow them for writing the reason of reset
+ */
+
+ /* reason[8 LSB] */
+ val = reason & 0xFF;
+ abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+ AB8500_ALARM_MIN_LOW , val);
+
+ /* reason[8 MSB] */
+ val = (reason>>8) & 0xFF;
+ abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+ AB8500_ALARM_MIN_MID , val);
+
+ /* Setting WD timeout to 0 */
+ ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
+
+ /* Setting the parameters to AB8500 WD*/
+ ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
+ AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
+}
+
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -85,7 +153,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
u8 bank;
if (sysctrl_dev == NULL)
- return -EAGAIN;
+ return -EINVAL;
bank = (reg >> 8);
if (!valid_bank(bank))
@@ -101,7 +169,7 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
u8 bank;
if (sysctrl_dev == NULL)
- return -EAGAIN;
+ return -EINVAL;
bank = (reg >> 8);
if (!valid_bank(bank))
@@ -114,28 +182,36 @@ EXPORT_SYMBOL(ab8500_sysctrl_write);
static int ab8500_sysctrl_probe(struct platform_device *pdev)
{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
- sysctrl_dev = &pdev->dev;
plat = dev_get_platdata(pdev->dev.parent);
+
+ if (!(plat && plat->sysctrl))
+ return -EINVAL;
+
if (plat->pm_power_off)
pm_power_off = ab8500_power_off;
pdata = plat->sysctrl;
if (pdata) {
- int ret, i, j;
+ int last, ret, i, j;
+
+ if (is_ab8505(ab8500))
+ last = AB8500_SYSCLKREQ4RFCLKBUF;
+ else
+ last = AB8500_SYSCLKREQ8RFCLKBUF;
- for (i = AB8500_SYSCLKREQ1RFCLKBUF;
- i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
+ for (i = AB8500_SYSCLKREQ1RFCLKBUF; i <= last; i++) {
j = i - AB8500_SYSCLKREQ1RFCLKBUF;
ret = ab8500_sysctrl_write(i, 0xff,
- pdata->initial_req_buf_config[j]);
+ pdata->initial_req_buf_config[j]);
dev_dbg(&pdev->dev,
- "Setting SysClkReq%dRfClkBuf 0x%X\n",
- j + 1,
- pdata->initial_req_buf_config[j]);
+ "Setting SysClkReq%dRfClkBuf 0x%X\n",
+ j + 1,
+ pdata->initial_req_buf_config[j]);
if (ret < 0) {
dev_err(&pdev->dev,
"unable to set sysClkReq%dRfClkBuf: "
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index d4b297cbd801..ecc137ffa8c3 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
-#include <linux/msm_ssbi.h>
+#include <linux/ssbi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/core.h>
@@ -35,7 +35,7 @@ static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
- return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+ return ssbi_read(pmic->dev->parent, addr, val, 1);
}
static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
@@ -43,7 +43,7 @@ static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
- return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+ return ssbi_write(pmic->dev->parent, addr, &val, 1);
}
static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
@@ -52,7 +52,7 @@ static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
- return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+ return ssbi_read(pmic->dev->parent, addr, buf, cnt);
}
static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
@@ -61,7 +61,7 @@ static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
- return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+ return ssbi_write(pmic->dev->parent, addr, buf, cnt);
}
static int pm8921_read_irq_stat(const struct device *dev, int irq)
@@ -124,7 +124,7 @@ static int pm8921_probe(struct platform_device *pdev)
}
/* Read PMIC chip revision */
- rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+ rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
if (rc) {
pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
goto err_read_rev;
@@ -133,7 +133,7 @@ static int pm8921_probe(struct platform_device *pdev)
rev = val;
/* Read PMIC chip revision 2 */
- rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+ rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
if (rc) {
pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
REG_HWREV_2, rc);
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index a433f580aa4c..ca2aed6bc830 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -331,6 +331,10 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
{ 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
{ 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
+ { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */
+ { 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */
+ { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */
+ { 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */
{ 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
{ 0x000002CB, 0x0000 }, /* R715 - Isolation control */
{ 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
@@ -1090,6 +1094,10 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_DETECT_1:
case ARIZONA_MIC_DETECT_2:
case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_MIC_DETECT_LEVEL_1:
+ case ARIZONA_MIC_DETECT_LEVEL_2:
+ case ARIZONA_MIC_DETECT_LEVEL_3:
+ case ARIZONA_MIC_DETECT_LEVEL_4:
case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
case ARIZONA_ISOLATION_CONTROL:
case ARIZONA_JACK_DETECT_ANALOGUE:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index e83fdfe0c8ca..c002d8660e30 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -93,6 +93,14 @@ config ATMEL_TCB_CLKSRC_BLOCK
TC can be used for other purposes, such as PWM generation and
interval timing.
+config DUMMY_IRQ
+ tristate "Dummy IRQ handler"
+ default n
+ ---help---
+ This module accepts a single 'irq' parameter, which it should register for.
+ The sole purpose of this module is to help with debugging of systems on
+ which spurious IRQs would happen on disabled IRQ vector.
+
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT
@@ -398,7 +406,7 @@ config DS1682
config SPEAR13XX_PCIE_GADGET
bool "PCIe gadget support for SPEAr13XX platform"
- depends on ARCH_SPEAR13XX
+ depends on ARCH_SPEAR13XX && BROKEN
default n
help
This option enables gadget support for PCIe controller. If
@@ -418,7 +426,7 @@ config TI_DAC7512
config VMWARE_BALLOON
tristate "VMware Balloon Driver"
- depends on X86
+ depends on X86 && HYPERVISOR_GUEST
help
This is VMware physical memory management driver which acts
like a "balloon" that can be inflated to reclaim physical pages
@@ -510,6 +518,15 @@ config LATTICE_ECP3_CONFIG
If unsure, say N.
+config SRAM
+ bool "Generic on-chip SRAM driver"
+ depends on HAS_IOMEM
+ select GENERIC_ALLOCATOR
+ help
+ This driver allows you to declare a memory region to be managed by
+ the genalloc API. It is supposed to be used for small on-chip SRAM
+ areas found on many SoCs.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 35a1463c72d9..c235d5b68311 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
+obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -49,6 +50,6 @@ obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/
-obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
+obj-$(CONFIG_SRAM) += sram.o
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index d648b0893027..5b5fd8416b3e 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -272,19 +272,8 @@ static int apds9802als_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
-{
- als_set_power_state(client, false);
- return 0;
-}
-
-static int apds9802als_resume(struct i2c_client *client)
-{
- als_set_default_config(client);
- return 0;
-}
-static int apds9802als_runtime_suspend(struct device *dev)
+static int apds9802als_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -292,7 +281,7 @@ static int apds9802als_runtime_suspend(struct device *dev)
return 0;
}
-static int apds9802als_runtime_resume(struct device *dev)
+static int apds9802als_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -300,16 +289,12 @@ static int apds9802als_runtime_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops apds9802als_pm_ops = {
- .runtime_suspend = apds9802als_runtime_suspend,
- .runtime_resume = apds9802als_runtime_resume,
-};
+static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend,
+ apds9802als_resume, NULL);
#define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
#else /* CONFIG_PM */
-#define apds9802als_suspend NULL
-#define apds9802als_resume NULL
#define APDS9802ALS_PM_OPS NULL
#endif /* CONFIG_PM */
@@ -327,8 +312,6 @@ static struct i2c_driver apds9802als_driver = {
},
.probe = apds9802als_probe,
.remove = apds9802als_remove,
- .suspend = apds9802als_suspend,
- .resume = apds9802als_resume,
.id_table = apds9802als_id,
};
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index 0e67f8263cd8..98f9bb26492a 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -700,9 +700,6 @@ static ssize_t apds990x_lux_calib_store(struct device *dev,
if (strict_strtoul(buf, 0, &value))
return -EINVAL;
- if (chip->lux_calib > APDS_RANGE)
- return -EINVAL;
-
chip->lux_calib = value;
return len;
@@ -1204,7 +1201,7 @@ static int apds990x_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int apds990x_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -1227,10 +1224,6 @@ static int apds990x_resume(struct device *dev)
return 0;
}
-#else
-#define apds990x_suspend NULL
-#define apds990x_resume NULL
-#define apds990x_shutdown NULL
#endif
#ifdef CONFIG_PM_RUNTIME
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c
index fe8616a8d287..48651ef0028c 100644
--- a/drivers/misc/arm-charlcd.c
+++ b/drivers/misc/arm-charlcd.c
@@ -378,18 +378,7 @@ static struct platform_driver charlcd_driver = {
.remove = __exit_p(charlcd_remove),
};
-static int __init charlcd_init(void)
-{
- return platform_driver_probe(&charlcd_driver, charlcd_probe);
-}
-
-static void __exit charlcd_exit(void)
-{
- platform_driver_unregister(&charlcd_driver);
-}
-
-module_init(charlcd_init);
-module_exit(charlcd_exit);
+module_platform_driver_probe(charlcd_driver, charlcd_probe);
MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>");
MODULE_DESCRIPTION("ARM Character LCD Driver");
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
index 28f5aaa19d4a..494d0500bda6 100644
--- a/drivers/misc/atmel_pwm.c
+++ b/drivers/misc/atmel_pwm.c
@@ -393,17 +393,7 @@ static struct platform_driver atmel_pwm_driver = {
*/
};
-static int __init pwm_init(void)
-{
- return platform_driver_probe(&atmel_pwm_driver, pwm_probe);
-}
-module_init(pwm_init);
-
-static void __exit pwm_exit(void)
-{
- platform_driver_unregister(&atmel_pwm_driver);
-}
-module_exit(pwm_exit);
+module_platform_driver_probe(atmel_pwm_driver, pwm_probe);
MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index 2ed8fc3be7e6..f4975f7d0d5b 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -1310,7 +1310,7 @@ static int bh1770_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int bh1770_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -1346,11 +1346,6 @@ static int bh1770_resume(struct device *dev)
}
return ret;
}
-
-#else
-#define bh1770_suspend NULL
-#define bh1770_shutdown NULL
-#define bh1770_resume NULL
#endif
#ifdef CONFIG_PM_RUNTIME
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index cf03d0abf33e..818f3a0e62bf 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -196,7 +196,7 @@ static int bh1780_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int bh1780_suspend(struct device *dev)
{
struct bh1780_data *ddata;
@@ -235,11 +235,9 @@ static int bh1780_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
+
static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume);
-#define BH1780_PMOPS (&bh1780_pm)
-#else
-#define BH1780_PMOPS NULL
-#endif /* CONFIG_PM */
static const struct i2c_device_id bh1780_id[] = {
{ "bh1780", 0 },
@@ -252,7 +250,7 @@ static struct i2c_driver bh1780_driver = {
.id_table = bh1780_id,
.driver = {
.name = "bh1780",
- .pm = BH1780_PMOPS,
+ .pm = &bh1780_pm,
},
};
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index 9858f36dad8b..effd8c6b2b94 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -24,8 +24,11 @@
static int mfgpt_reset_timers;
module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
-MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; "
- "required by some broken BIOSes (ie, TinyBIOS < 0.99).");
+MODULE_PARM_DESC(mfgptfix, "Try to reset the MFGPT timers during init; "
+ "required by some broken BIOSes (ie, TinyBIOS < 0.99) or kexec "
+ "(1 = reset the MFGPT using an undocumented bit, "
+ "2 = perform a soft reset by unconfiguring all timers); "
+ "use what works best for you.");
struct cs5535_mfgpt_timer {
struct cs5535_mfgpt_chip *chip;
@@ -256,6 +259,28 @@ static void reset_all_timers(void)
}
/*
+ * This is another sledgehammer to reset all MFGPT timers.
+ * Instead of using the undocumented bit method it clears
+ * IRQ, NMI and RESET settings.
+ */
+static void soft_reset(void)
+{
+ int i;
+ struct cs5535_mfgpt_timer t;
+
+ for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+ t.nr = i;
+
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_RESET, 0);
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_RESET, 0);
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_NMI, 0);
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_NMI, 0);
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP1, MFGPT_EVENT_IRQ, 0);
+ cs5535_mfgpt_toggle_event(&t, MFGPT_CMP2, MFGPT_EVENT_IRQ, 0);
+ }
+}
+
+/*
* Check whether any MFGPTs are available for the kernel to use. In most
* cases, firmware that uses AMD's VSA code will claim all timers during
* bootup; we certainly don't want to take them if they're already in use.
@@ -271,15 +296,17 @@ static int scan_timers(struct cs5535_mfgpt_chip *mfgpt)
int i;
/* bios workaround */
- if (mfgpt_reset_timers)
+ if (mfgpt_reset_timers == 1)
reset_all_timers();
+ else if (mfgpt_reset_timers == 2)
+ soft_reset();
/* just to be safe, protect this section w/ lock */
spin_lock_irqsave(&mfgpt->lock, flags);
for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
timer.nr = i;
val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
- if (!(val & MFGPT_SETUP_SETUP)) {
+ if (!(val & MFGPT_SETUP_SETUP) || mfgpt_reset_timers == 2) {
__set_bit(i, mfgpt->avail);
timers++;
}
@@ -294,6 +321,12 @@ static int cs5535_mfgpt_probe(struct platform_device *pdev)
struct resource *res;
int err = -EIO, t;
+ if (mfgpt_reset_timers < 0 || mfgpt_reset_timers > 2) {
+ dev_err(&pdev->dev, "Bad mfgpt_reset_timers value: %i\n",
+ mfgpt_reset_timers);
+ goto done;
+ }
+
/* There are two ways to get the MFGPT base address; one is by
* fetching it from MSR_LBAR_MFGPT, the other is by reading the
* PCI BAR info. The latter method is easier (especially across
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c
new file mode 100644
index 000000000000..7014167e2c61
--- /dev/null
+++ b/drivers/misc/dummy-irq.c
@@ -0,0 +1,59 @@
+/*
+ * Dummy IRQ handler driver.
+ *
+ * This module only registers itself as a handler that is specified to it
+ * by the 'irq' parameter.
+ *
+ * The sole purpose of this module is to help with debugging of systems on
+ * which spurious IRQs would happen on disabled IRQ vector.
+ *
+ * Copyright (C) 2013 Jiri Kosina
+ */
+
+/*
+ * 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/irq.h>
+#include <linux/interrupt.h>
+
+static int irq;
+
+static irqreturn_t dummy_interrupt(int irq, void *dev_id)
+{
+ static int count = 0;
+
+ if (count == 0) {
+ printk(KERN_INFO "dummy-irq: interrupt occured on IRQ %d\n",
+ irq);
+ count++;
+ }
+
+ return IRQ_NONE;
+}
+
+static int __init dummy_irq_init(void)
+{
+ if (request_irq(irq, &dummy_interrupt, IRQF_SHARED, "dummy_irq", &irq)) {
+ printk(KERN_ERR "dummy-irq: cannot register IRQ %d\n", irq);
+ return -EIO;
+ }
+ printk(KERN_INFO "dummy-irq: registered for IRQ %d\n", irq);
+ return 0;
+}
+
+static void __exit dummy_irq_exit(void)
+{
+ printk(KERN_INFO "dummy-irq unloaded\n");
+ free_irq(irq, &irq);
+}
+
+module_init(dummy_irq_init);
+module_exit(dummy_irq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jiri Kosina");
+module_param(irq, uint, 0444);
+MODULE_PARM_DESC(irq, "The IRQ to register for");
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index b08cf8a08789..ad8fd8e64937 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -412,7 +412,7 @@ static int at25_probe(struct spi_device *spi)
mutex_init(&at25->lock);
at25->chip = chip;
at25->spi = spi_dev_get(spi);
- dev_set_drvdata(&spi->dev, at25);
+ spi_set_drvdata(spi, at25);
at25->addrlen = addrlen;
/* Export the EEPROM bytes through sysfs, since that's convenient.
@@ -463,7 +463,7 @@ static int at25_remove(struct spi_device *spi)
{
struct at25_data *at25;
- at25 = dev_get_drvdata(&spi->dev);
+ at25 = spi_get_drvdata(spi);
sysfs_remove_bin_file(&spi->dev.kobj, &at25->bin);
kfree(at25);
return 0;
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index a6b5d5e73485..94cfc1212577 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -363,7 +363,7 @@ static int eeprom_93xx46_probe(struct spi_device *spi)
dev_err(&spi->dev, "can't create erase interface\n");
}
- dev_set_drvdata(&spi->dev, edev);
+ spi_set_drvdata(spi, edev);
return 0;
fail:
kfree(edev);
@@ -372,13 +372,13 @@ fail:
static int eeprom_93xx46_remove(struct spi_device *spi)
{
- struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev);
+ struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
if (!(edev->pdata->flags & EE_READONLY))
device_remove_file(&spi->dev, &dev_attr_erase);
sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(edev);
return 0;
}
diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c
index 16d7179e2f9b..96787ec15cad 100644
--- a/drivers/misc/ep93xx_pwm.c
+++ b/drivers/misc/ep93xx_pwm.c
@@ -365,18 +365,7 @@ static struct platform_driver ep93xx_pwm_driver = {
.remove = __exit_p(ep93xx_pwm_remove),
};
-static int __init ep93xx_pwm_init(void)
-{
- return platform_driver_probe(&ep93xx_pwm_driver, ep93xx_pwm_probe);
-}
-
-static void __exit ep93xx_pwm_exit(void)
-{
- platform_driver_unregister(&ep93xx_pwm_driver);
-}
-
-module_init(ep93xx_pwm_init);
-module_exit(ep93xx_pwm_exit);
+module_platform_driver_probe(ep93xx_pwm_driver, ep93xx_pwm_probe);
MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, "
"H Hartley Sweeten <hsweeten@visionengravers.com>");
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
index e8cbb1c59f4c..a725c79c35f5 100644
--- a/drivers/misc/fsa9480.c
+++ b/drivers/misc/fsa9480.c
@@ -474,10 +474,11 @@ static int fsa9480_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
+static int fsa9480_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
struct fsa9480_platform_data *pdata = usbsw->pdata;
@@ -490,8 +491,9 @@ static int fsa9480_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
-static int fsa9480_resume(struct i2c_client *client)
+static int fsa9480_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
int dev1, dev2;
@@ -515,12 +517,14 @@ static int fsa9480_resume(struct i2c_client *client)
return 0;
}
+static SIMPLE_DEV_PM_OPS(fsa9480_pm_ops, fsa9480_suspend, fsa9480_resume);
+#define FSA9480_PM_OPS (&fsa9480_pm_ops)
+
#else
-#define fsa9480_suspend NULL
-#define fsa9480_resume NULL
+#define FSA9480_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id fsa9480_id[] = {
{"fsa9480", 0},
@@ -531,11 +535,10 @@ MODULE_DEVICE_TABLE(i2c, fsa9480_id);
static struct i2c_driver fsa9480_i2c_driver = {
.driver = {
.name = "fsa9480",
+ .pm = FSA9480_PM_OPS,
},
.probe = fsa9480_probe,
.remove = fsa9480_remove,
- .resume = fsa9480_resume,
- .suspend = fsa9480_suspend,
.id_table = fsa9480_id,
};
diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c
index 29b306c6bdb3..c5145b3fcce8 100644
--- a/drivers/misc/isl29003.c
+++ b/drivers/misc/isl29003.c
@@ -409,18 +409,20 @@ static int isl29003_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int isl29003_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct isl29003_data *data = i2c_get_clientdata(client);
data->power_state_before_suspend = isl29003_get_power_state(client);
return isl29003_set_power_state(client, 0);
}
-static int isl29003_resume(struct i2c_client *client)
+static int isl29003_resume(struct device *dev)
{
int i;
+ struct i2c_client *client = to_i2c_client(dev);
struct isl29003_data *data = i2c_get_clientdata(client);
/* restore registers from cache */
@@ -432,10 +434,12 @@ static int isl29003_resume(struct i2c_client *client)
data->power_state_before_suspend);
}
+static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
+#define ISL29003_PM_OPS (&isl29003_pm_ops)
+
#else
-#define isl29003_suspend NULL
-#define isl29003_resume NULL
-#endif /* CONFIG_PM */
+#define ISL29003_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id isl29003_id[] = {
{ "isl29003", 0 },
@@ -447,9 +451,8 @@ static struct i2c_driver isl29003_driver = {
.driver = {
.name = ISL29003_DRV_NAME,
.owner = THIS_MODULE,
+ .pm = ISL29003_PM_OPS,
},
- .suspend = isl29003_suspend,
- .resume = isl29003_resume,
.probe = isl29003_probe,
.remove = isl29003_remove,
.id_table = isl29003_id,
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index 155700bfd2b6..bb26f086bd8b 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -69,7 +69,7 @@ static const struct ecp3_dev ecp3_dev[] = {
static void firmware_load(const struct firmware *fw, void *context)
{
struct spi_device *spi = (struct spi_device *)context;
- struct fpga_data *data = dev_get_drvdata(&spi->dev);
+ struct fpga_data *data = spi_get_drvdata(spi);
u8 *buffer;
int ret;
u8 txbuf[8];
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index d21b4d006a55..c76fa31e9bf6 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -10,10 +10,9 @@ config INTEL_MEI
<http://software.intel.com/en-us/manageability/>
config INTEL_MEI_ME
- bool "ME Enabled Intel Chipsets"
- depends on INTEL_MEI
+ tristate "ME Enabled Intel Chipsets"
+ select INTEL_MEI
depends on X86 && PCI && WATCHDOG_CORE
- default y
help
MEI support for ME Enabled Intel chipsets.
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 040af6c7b147..08698a466268 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -10,5 +10,10 @@ mei-objs += client.o
mei-objs += main.o
mei-objs += amthif.o
mei-objs += wd.o
-mei-$(CONFIG_INTEL_MEI_ME) += pci-me.o
-mei-$(CONFIG_INTEL_MEI_ME) += hw-me.o
+mei-objs += bus.o
+mei-objs += nfc.o
+mei-$(CONFIG_DEBUG_FS) += debugfs.o
+
+obj-$(CONFIG_INTEL_MEI_ME) += mei-me.o
+mei-me-objs := pci-me.o
+mei-me-objs += hw-me.o
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index c86d7e3839a4..b3e50984d2c8 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -60,7 +60,7 @@ void mei_amthif_reset_params(struct mei_device *dev)
}
/**
- * mei_amthif_host_init_ - mei initialization amthif client.
+ * mei_amthif_host_init - mei initialization amthif client.
*
* @dev: the device structure
*
@@ -433,7 +433,7 @@ unsigned int mei_amthif_poll(struct mei_device *dev,
/**
- * mei_amthif_irq_process_completed - processes completed iamthif operation.
+ * mei_amthif_irq_write_completed - processes completed iamthif operation.
*
* @dev: the device structure.
* @slots: free slots.
@@ -449,7 +449,7 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_msg_hdr mei_hdr;
struct mei_cl *cl = cb->cl;
size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index;
- size_t msg_slots = mei_data2slots(len);
+ u32 msg_slots = mei_data2slots(len);
mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
@@ -505,14 +505,15 @@ int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
* mei_amthif_irq_read_message - read routine after ISR to
* handle the read amthif message
*
- * @complete_list: An instance of our list structure
* @dev: the device structure
* @mei_hdr: header of amthif message
+ * @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
*/
-int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
- struct mei_device *dev, struct mei_msg_hdr *mei_hdr)
+int mei_amthif_irq_read_msg(struct mei_device *dev,
+ struct mei_msg_hdr *mei_hdr,
+ struct mei_cl_cb *complete_list)
{
struct mei_cl_cb *cb;
unsigned char *buffer;
@@ -530,8 +531,7 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
if (!mei_hdr->msg_complete)
return 0;
- dev_dbg(&dev->pdev->dev,
- "amthif_message_buffer_index =%d\n",
+ dev_dbg(&dev->pdev->dev, "amthif_message_buffer_index =%d\n",
mei_hdr->length);
dev_dbg(&dev->pdev->dev, "completed amthif read.\n ");
@@ -566,12 +566,13 @@ int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list,
*/
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots)
{
+ u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
- if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr)
- + sizeof(struct hbm_flow_control))) {
+ if (*slots < msg_slots)
return -EMSGSIZE;
- }
- *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
+
+ *slots -= msg_slots;
+
if (mei_hbm_cl_flow_control_req(dev, &dev->iamthif_cl)) {
dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n");
return -EIO;
@@ -703,7 +704,7 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file)
/**
* mei_amthif_release - the release function
*
-* @inode: pointer to inode structure
+* @dev: device structure
* @file: pointer to file structure
*
* returns 0 on success, <0 on error
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
new file mode 100644
index 000000000000..1e935eacaa7f
--- /dev/null
+++ b/drivers/misc/mei/bus.c
@@ -0,0 +1,528 @@
+/*
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "hw-me.h"
+#include "client.h"
+
+#define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
+#define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
+
+static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver = to_mei_cl_driver(drv);
+ const struct mei_cl_device_id *id;
+
+ if (!device)
+ return 0;
+
+ if (!driver || !driver->id_table)
+ return 0;
+
+ id = driver->id_table;
+
+ while (id->name[0]) {
+ if (!strcmp(dev_name(dev), id->name))
+ return 1;
+
+ id++;
+ }
+
+ return 0;
+}
+
+static int mei_cl_device_probe(struct device *dev)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver;
+ struct mei_cl_device_id id;
+
+ if (!device)
+ return 0;
+
+ driver = to_mei_cl_driver(dev->driver);
+ if (!driver || !driver->probe)
+ return -ENODEV;
+
+ dev_dbg(dev, "Device probe\n");
+
+ strncpy(id.name, dev_name(dev), MEI_CL_NAME_SIZE);
+
+ return driver->probe(device, &id);
+}
+
+static int mei_cl_device_remove(struct device *dev)
+{
+ struct mei_cl_device *device = to_mei_cl_device(dev);
+ struct mei_cl_driver *driver;
+
+ if (!device || !dev->driver)
+ return 0;
+
+ if (device->event_cb) {
+ device->event_cb = NULL;
+ cancel_work_sync(&device->event_work);
+ }
+
+ driver = to_mei_cl_driver(dev->driver);
+ if (!driver->remove) {
+ dev->driver = NULL;
+
+ return 0;
+ }
+
+ return driver->remove(device);
+}
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "mei:%s\n", dev_name(dev));
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute mei_cl_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ if (add_uevent_var(env, "MODALIAS=mei:%s", dev_name(dev)))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct bus_type mei_cl_bus_type = {
+ .name = "mei",
+ .dev_attrs = mei_cl_dev_attrs,
+ .match = mei_cl_device_match,
+ .probe = mei_cl_device_probe,
+ .remove = mei_cl_device_remove,
+ .uevent = mei_cl_uevent,
+};
+
+static void mei_cl_dev_release(struct device *dev)
+{
+ kfree(to_mei_cl_device(dev));
+}
+
+static struct device_type mei_cl_device_type = {
+ .release = mei_cl_dev_release,
+};
+
+static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
+ uuid_le uuid)
+{
+ struct mei_cl *cl, *next;
+
+ list_for_each_entry_safe(cl, next, &dev->device_list, device_link) {
+ if (!uuid_le_cmp(uuid, cl->device_uuid))
+ return cl;
+ }
+
+ return NULL;
+}
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+ uuid_le uuid, char *name,
+ struct mei_cl_ops *ops)
+{
+ struct mei_cl_device *device;
+ struct mei_cl *cl;
+ int status;
+
+ cl = mei_bus_find_mei_cl_by_uuid(dev, uuid);
+ if (cl == NULL)
+ return NULL;
+
+ device = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
+ if (!device)
+ return NULL;
+
+ device->cl = cl;
+ device->ops = ops;
+
+ device->dev.parent = &dev->pdev->dev;
+ device->dev.bus = &mei_cl_bus_type;
+ device->dev.type = &mei_cl_device_type;
+
+ dev_set_name(&device->dev, "%s", name);
+
+ status = device_register(&device->dev);
+ if (status) {
+ dev_err(&dev->pdev->dev, "Failed to register MEI device\n");
+ kfree(device);
+ return NULL;
+ }
+
+ cl->device = device;
+
+ dev_dbg(&device->dev, "client %s registered\n", name);
+
+ return device;
+}
+EXPORT_SYMBOL_GPL(mei_cl_add_device);
+
+void mei_cl_remove_device(struct mei_cl_device *device)
+{
+ device_unregister(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_remove_device);
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver, struct module *owner)
+{
+ int err;
+
+ driver->driver.name = driver->name;
+ driver->driver.owner = owner;
+ driver->driver.bus = &mei_cl_bus_type;
+
+ err = driver_register(&driver->driver);
+ if (err)
+ return err;
+
+ pr_debug("mei: driver [%s] registered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver)
+{
+ driver_unregister(&driver->driver);
+
+ pr_debug("mei: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
+
+static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+ bool blocking)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ int id;
+ int rets;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ if (cl->state != MEI_FILE_CONNECTED)
+ return -ENODEV;
+
+ /* Check if we have an ME client device */
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0)
+ return -ENODEV;
+
+ if (length > dev->me_clients[id].props.max_msg_length)
+ return -EINVAL;
+
+ cb = mei_io_cb_init(cl, NULL);
+ if (!cb)
+ return -ENOMEM;
+
+ rets = mei_io_cb_alloc_req_buf(cb, length);
+ if (rets < 0) {
+ mei_io_cb_free(cb);
+ return rets;
+ }
+
+ memcpy(cb->request_buffer.data, buf, length);
+
+ mutex_lock(&dev->device_lock);
+
+ rets = mei_cl_write(cl, cb, blocking);
+
+ mutex_unlock(&dev->device_lock);
+ if (rets < 0)
+ mei_io_cb_free(cb);
+
+ return rets;
+}
+
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ struct mei_device *dev;
+ struct mei_cl_cb *cb;
+ size_t r_length;
+ int err;
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (!cl->read_cb) {
+ err = mei_cl_read_start(cl, length);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ return err;
+ }
+ }
+
+ if (cl->reading_state != MEI_READ_COMPLETE &&
+ !waitqueue_active(&cl->rx_wait)) {
+ mutex_unlock(&dev->device_lock);
+
+ if (wait_event_interruptible(cl->rx_wait,
+ (MEI_READ_COMPLETE == cl->reading_state))) {
+ if (signal_pending(current))
+ return -EINTR;
+ return -ERESTARTSYS;
+ }
+
+ mutex_lock(&dev->device_lock);
+ }
+
+ cb = cl->read_cb;
+
+ if (cl->reading_state != MEI_READ_COMPLETE) {
+ r_length = 0;
+ goto out;
+ }
+
+ r_length = min_t(size_t, length, cb->buf_idx);
+
+ memcpy(buf, cb->response_buffer.data, r_length);
+
+ mei_io_cb_free(cb);
+ cl->reading_state = MEI_IDLE;
+ cl->read_cb = NULL;
+
+out:
+ mutex_unlock(&dev->device_lock);
+
+ return r_length;
+}
+
+inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ return ___mei_cl_send(cl, buf, length, 0);
+}
+
+inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+{
+ return ___mei_cl_send(cl, buf, length, 1);
+}
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ if (device->ops && device->ops->send)
+ return device->ops->send(device, buf, length);
+
+ return __mei_cl_send(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_send);
+
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+{
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ if (device->ops && device->ops->recv)
+ return device->ops->recv(device, buf, length);
+
+ return __mei_cl_recv(cl, buf, length);
+}
+EXPORT_SYMBOL_GPL(mei_cl_recv);
+
+static void mei_bus_event_work(struct work_struct *work)
+{
+ struct mei_cl_device *device;
+
+ device = container_of(work, struct mei_cl_device, event_work);
+
+ if (device->event_cb)
+ device->event_cb(device, device->events, device->event_context);
+
+ device->events = 0;
+
+ /* Prepare for the next read */
+ mei_cl_read_start(device->cl, 0);
+}
+
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+ mei_cl_event_cb_t event_cb, void *context)
+{
+ if (device->event_cb)
+ return -EALREADY;
+
+ device->events = 0;
+ device->event_cb = event_cb;
+ device->event_context = context;
+ INIT_WORK(&device->event_work, mei_bus_event_work);
+
+ mei_cl_read_start(device->cl, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
+
+void *mei_cl_get_drvdata(const struct mei_cl_device *device)
+{
+ return dev_get_drvdata(&device->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
+
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
+{
+ dev_set_drvdata(&device->dev, data);
+}
+EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
+
+int mei_cl_enable_device(struct mei_cl_device *device)
+{
+ int err;
+ struct mei_device *dev;
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ cl->state = MEI_FILE_CONNECTING;
+
+ err = mei_cl_connect(cl, NULL);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev, "Could not connect to the ME client");
+
+ return err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (device->event_cb && !cl->read_cb)
+ mei_cl_read_start(device->cl, 0);
+
+ if (!device->ops || !device->ops->enable)
+ return 0;
+
+ return device->ops->enable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_enable_device);
+
+int mei_cl_disable_device(struct mei_cl_device *device)
+{
+ int err;
+ struct mei_device *dev;
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (cl->state != MEI_FILE_CONNECTED) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev, "Already disconnected");
+
+ return 0;
+ }
+
+ cl->state = MEI_FILE_DISCONNECTING;
+
+ err = mei_cl_disconnect(cl);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not disconnect from the ME client");
+
+ return err;
+ }
+
+ /* Flush queues and remove any pending read */
+ mei_cl_flush_queues(cl);
+
+ if (cl->read_cb) {
+ struct mei_cl_cb *cb = NULL;
+
+ cb = mei_cl_find_read_cb(cl);
+ /* Remove entry from read list */
+ if (cb)
+ list_del(&cb->list);
+
+ cb = cl->read_cb;
+ cl->read_cb = NULL;
+
+ if (cb) {
+ mei_io_cb_free(cb);
+ cb = NULL;
+ }
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (!device->ops || !device->ops->disable)
+ return 0;
+
+ return device->ops->disable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_disable_device);
+
+void mei_cl_bus_rx_event(struct mei_cl *cl)
+{
+ struct mei_cl_device *device = cl->device;
+
+ if (!device || !device->event_cb)
+ return;
+
+ set_bit(MEI_CL_EVENT_RX, &device->events);
+
+ schedule_work(&device->event_work);
+}
+
+int __init mei_cl_bus_init(void)
+{
+ return bus_register(&mei_cl_bus_type);
+}
+
+void __exit mei_cl_bus_exit(void)
+{
+ bus_unregister(&mei_cl_bus_type);
+}
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1569afe935de..e310ca6ed1a3 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -109,7 +109,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
* mei_io_cb_init - allocate and initialize io callback
*
* @cl - mei client
- * @file: pointer to file structure
+ * @fp: pointer to file structure
*
* returns mei_cl_cb pointer or NULL;
*/
@@ -132,8 +132,8 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
/**
* mei_io_cb_alloc_req_buf - allocate request buffer
*
- * @cb - io callback structure
- * @size: size of the buffer
+ * @cb: io callback structure
+ * @length: size of the buffer
*
* returns 0 on success
* -EINVAL if cb is NULL
@@ -154,10 +154,10 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
return 0;
}
/**
- * mei_io_cb_alloc_req_buf - allocate respose buffer
+ * mei_io_cb_alloc_resp_buf - allocate respose buffer
*
- * @cb - io callback structure
- * @size: size of the buffer
+ * @cb: io callback structure
+ * @length: size of the buffer
*
* returns 0 on success
* -EINVAL if cb is NULL
@@ -183,7 +183,6 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
/**
* mei_cl_flush_queues - flushes queue lists belonging to cl.
*
- * @dev: the device structure
* @cl: host client
*/
int mei_cl_flush_queues(struct mei_cl *cl)
@@ -216,6 +215,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->rx_wait);
init_waitqueue_head(&cl->tx_wait);
INIT_LIST_HEAD(&cl->link);
+ INIT_LIST_HEAD(&cl->device_link);
cl->reading_state = MEI_IDLE;
cl->writing_state = MEI_IDLE;
cl->dev = dev;
@@ -243,7 +243,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
/**
* mei_cl_find_read_cb - find this cl's callback in the read list
*
- * @dev: device structure
+ * @cl: host client
+ *
* returns cb on success, NULL on error
*/
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
@@ -262,6 +263,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
*
* @cl - host client
* @id - fixed host id or -1 for genereting one
+ *
* returns 0 on success
* -EINVAL on incorrect values
* -ENONET if client not found
@@ -301,7 +303,7 @@ int mei_cl_link(struct mei_cl *cl, int id)
/**
* mei_cl_unlink - remove me_cl from the list
*
- * @dev: the device structure
+ * @cl: host client
*/
int mei_cl_unlink(struct mei_cl *cl)
{
@@ -357,6 +359,9 @@ void mei_host_client_init(struct work_struct *work)
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
+ else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+ mei_nfc_host_init(dev);
+
}
dev->dev_state = MEI_DEV_ENABLED;
@@ -534,7 +539,6 @@ out:
/**
* mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
*
- * @dev: the device structure
* @cl: private data of the file object
*
* returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
@@ -575,8 +579,8 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
/**
* mei_cl_flow_ctrl_reduce - reduces flow_control.
*
- * @dev: the device structure
* @cl: private data of the file object
+ *
* @returns
* 0 on success
* -ENOENT when me client is not found
@@ -614,13 +618,13 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
}
/**
- * mei_cl_start_read - the start read client message function.
+ * mei_cl_read_start - the start read client message function.
*
* @cl: host client
*
* returns 0 on success, <0 on failure.
*/
-int mei_cl_read_start(struct mei_cl *cl)
+int mei_cl_read_start(struct mei_cl *cl, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -653,8 +657,9 @@ int mei_cl_read_start(struct mei_cl *cl)
if (!cb)
return -ENOMEM;
- rets = mei_io_cb_alloc_resp_buf(cb,
- dev->me_clients[i].props.max_msg_length);
+ /* always allocate at least client max message */
+ length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
+ rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto err;
@@ -677,6 +682,111 @@ err:
}
/**
+ * mei_cl_write - submit a write cb to mei device
+ assumes device_lock is locked
+ *
+ * @cl: host client
+ * @cl: write callback with filled data
+ *
+ * returns numbe of bytes sent on success, <0 on failure.
+ */
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
+{
+ struct mei_device *dev;
+ struct mei_msg_data *buf;
+ struct mei_msg_hdr mei_hdr;
+ int rets;
+
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ if (WARN_ON(!cb))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+
+ buf = &cb->request_buffer;
+
+ dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size);
+
+
+ cb->fop_type = MEI_FOP_WRITE;
+
+ rets = mei_cl_flow_ctrl_creds(cl);
+ if (rets < 0)
+ goto err;
+
+ /* Host buffer is not ready, we queue the request */
+ if (rets == 0 || !dev->hbuf_is_ready) {
+ cb->buf_idx = 0;
+ /* unseting complete will enqueue the cb for write */
+ mei_hdr.msg_complete = 0;
+ cl->writing_state = MEI_WRITING;
+ rets = buf->size;
+ goto out;
+ }
+
+ dev->hbuf_is_ready = false;
+
+ /* Check for a maximum length */
+ if (buf->size > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
+ mei_hdr.msg_complete = 0;
+ } else {
+ mei_hdr.length = buf->size;
+ mei_hdr.msg_complete = 1;
+ }
+
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
+
+ dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
+ MEI_HDR_PRM(&mei_hdr));
+
+
+ if (mei_write_message(dev, &mei_hdr, buf->data)) {
+ rets = -EIO;
+ goto err;
+ }
+
+ cl->writing_state = MEI_WRITING;
+ cb->buf_idx = mei_hdr.length;
+
+ rets = buf->size;
+out:
+ if (mei_hdr.msg_complete) {
+ if (mei_cl_flow_ctrl_reduce(cl)) {
+ rets = -ENODEV;
+ goto err;
+ }
+ list_add_tail(&cb->list, &dev->write_waiting_list.list);
+ } else {
+ list_add_tail(&cb->list, &dev->write_list.list);
+ }
+
+
+ if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
+
+ mutex_unlock(&dev->device_lock);
+ if (wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE)) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ else
+ rets = -ERESTARTSYS;
+ }
+ mutex_lock(&dev->device_lock);
+ }
+err:
+ return rets;
+}
+
+
+
+/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
* @dev - mei device
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index 214b2397ec3e..cfdb144526aa 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -86,17 +86,16 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl);
*/
bool mei_cl_is_other_connecting(struct mei_cl *cl);
int mei_cl_disconnect(struct mei_cl *cl);
-
-int mei_cl_read_start(struct mei_cl *cl);
-
int mei_cl_connect(struct mei_cl *cl, struct file *file);
+int mei_cl_read_start(struct mei_cl *cl, size_t length);
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking);
void mei_host_client_init(struct work_struct *work);
+
void mei_cl_all_disconnect(struct mei_device *dev);
void mei_cl_all_read_wakeup(struct mei_device *dev);
void mei_cl_all_write_clear(struct mei_device *dev);
-
#endif /* _MEI_CLIENT_H_ */
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
new file mode 100644
index 000000000000..e3870f22d238
--- /dev/null
+++ b/drivers/misc/mei/debugfs.c
@@ -0,0 +1,143 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2012-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/pci.h>
+
+#include <linux/mei.h>
+
+#include "mei_dev.h"
+#include "hw.h"
+
+static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_device *dev = fp->private_data;
+ struct mei_me_client *cl;
+ const size_t bufsz = 1024;
+ char *buf = kzalloc(bufsz, GFP_KERNEL);
+ int i;
+ int pos = 0;
+ int ret;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ " |id|addr| UUID |con|msg len|\n");
+
+ mutex_lock(&dev->device_lock);
+
+ /* if the driver is not enabled the list won't b consitent */
+ if (dev->dev_state != MEI_DEV_ENABLED)
+ goto out;
+
+ for (i = 0; i < dev->me_clients_num; i++) {
+ cl = &dev->me_clients[i];
+
+ /* skip me clients that cannot be connected */
+ if (cl->props.max_number_of_connections == 0)
+ continue;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%2d|%2d|%4d|%pUl|%3d|%7d|\n",
+ i, cl->client_id,
+ cl->props.fixed_address,
+ &cl->props.protocol_name,
+ cl->props.max_number_of_connections,
+ cl->props.max_msg_length);
+ }
+out:
+ mutex_unlock(&dev->device_lock);
+ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations mei_dbgfs_fops_meclients = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_meclients,
+ .llseek = generic_file_llseek,
+};
+
+static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct mei_device *dev = fp->private_data;
+ const size_t bufsz = 1024;
+ char *buf = kzalloc(bufsz, GFP_KERNEL);
+ int pos = 0;
+ int ret;
+
+ if (!buf)
+ return -ENOMEM;
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%s\n",
+ mei_dev_state_str(dev->dev_state));
+ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+static const struct file_operations mei_dbgfs_fops_devstate = {
+ .open = simple_open,
+ .read = mei_dbgfs_read_devstate,
+ .llseek = generic_file_llseek,
+};
+
+/**
+ * mei_dbgfs_deregister - Remove the debugfs files and directories
+ * @mei - pointer to mei device private dat
+ */
+void mei_dbgfs_deregister(struct mei_device *dev)
+{
+ if (!dev->dbgfs_dir)
+ return;
+ debugfs_remove_recursive(dev->dbgfs_dir);
+ dev->dbgfs_dir = NULL;
+}
+
+/**
+ * Add the debugfs files
+ *
+ */
+int mei_dbgfs_register(struct mei_device *dev, const char *name)
+{
+ struct dentry *dir, *f;
+ dir = debugfs_create_dir(name, NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ f = debugfs_create_file("meclients", S_IRUSR, dir,
+ dev, &mei_dbgfs_fops_meclients);
+ if (!f) {
+ dev_err(&dev->pdev->dev, "meclients: registration failed\n");
+ goto err;
+ }
+ f = debugfs_create_file("devstate", S_IRUSR, dir,
+ dev, &mei_dbgfs_fops_devstate);
+ if (!f) {
+ dev_err(&dev->pdev->dev, "devstate: registration failed\n");
+ goto err;
+ }
+ dev->dbgfs_dir = dir;
+ return 0;
+err:
+ mei_dbgfs_deregister(dev);
+ return -ENODEV;
+}
+
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index fb9e63ba3bb1..6916045166eb 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -52,7 +52,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
sizeof(struct mei_me_client), GFP_KERNEL);
if (!clients) {
dev_err(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
- dev->dev_state = MEI_DEV_RESETING;
+ dev->dev_state = MEI_DEV_RESETTING;
mei_reset(dev, 1);
return;
}
@@ -62,6 +62,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev)
/**
* mei_hbm_cl_hdr - construct client hbm header
+ *
* @cl: - client
* @hbm_cmd: host bus message command
* @buf: buffer for cl header
@@ -123,12 +124,33 @@ static bool is_treat_specially_client(struct mei_cl *cl,
return false;
}
+int mei_hbm_start_wait(struct mei_device *dev)
+{
+ int ret;
+ if (dev->hbm_state > MEI_HBM_START)
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
+ dev->hbm_state == MEI_HBM_IDLE ||
+ dev->hbm_state > MEI_HBM_START,
+ mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
+ mutex_lock(&dev->device_lock);
+
+ if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
+ dev->hbm_state = MEI_HBM_IDLE;
+ dev_err(&dev->pdev->dev, "wating for mei start failed\n");
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
/**
* mei_hbm_start_req - sends start request message.
*
* @dev: the device structure
*/
-void mei_hbm_start_req(struct mei_device *dev)
+int mei_hbm_start_req(struct mei_device *dev)
{
struct mei_msg_hdr *mei_hdr = &dev->wr_msg.hdr;
struct hbm_host_version_request *start_req;
@@ -143,18 +165,19 @@ void mei_hbm_start_req(struct mei_device *dev)
start_req->host_version.major_version = HBM_MAJOR_VERSION;
start_req->host_version.minor_version = HBM_MINOR_VERSION;
- dev->recvd_msg = false;
+ dev->hbm_state = MEI_HBM_IDLE;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
- dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
- dev->dev_state = MEI_DEV_RESETING;
+ dev_err(&dev->pdev->dev, "version message writet failed\n");
+ dev->dev_state = MEI_DEV_RESETTING;
mei_reset(dev, 1);
+ return -ENODEV;
}
- dev->init_clients_state = MEI_START_MESSAGE;
+ dev->hbm_state = MEI_HBM_START;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
- return ;
+ return 0;
}
-/**
+/*
* mei_hbm_enum_clients_req - sends enumeration client request message.
*
* @dev: the device structure
@@ -174,17 +197,17 @@ static void mei_hbm_enum_clients_req(struct mei_device *dev)
enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
- dev->dev_state = MEI_DEV_RESETING;
- dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
+ dev->dev_state = MEI_DEV_RESETTING;
+ dev_err(&dev->pdev->dev, "enumeration request write failed.\n");
mei_reset(dev, 1);
}
- dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE;
+ dev->hbm_state = MEI_HBM_ENUM_CLIENTS;
dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT;
return;
}
/**
- * mei_hbm_prop_requsest - request property for a single client
+ * mei_hbm_prop_req - request property for a single client
*
* @dev: the device structure
*
@@ -208,6 +231,7 @@ static int mei_hbm_prop_req(struct mei_device *dev)
/* We got all client properties */
if (next_client_index == MEI_CLIENTS_MAX) {
+ dev->hbm_state = MEI_HBM_STARTED;
schedule_work(&dev->init_work);
return 0;
@@ -226,8 +250,8 @@ static int mei_hbm_prop_req(struct mei_device *dev)
prop_req->address = next_client_index;
if (mei_write_message(dev, mei_hdr, dev->wr_msg.data)) {
- dev->dev_state = MEI_DEV_RESETING;
- dev_err(&dev->pdev->dev, "Properties request command failed\n");
+ dev->dev_state = MEI_DEV_RESETTING;
+ dev_err(&dev->pdev->dev, "properties request write failed\n");
mei_reset(dev, 1);
return -EIO;
@@ -283,9 +307,9 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
}
/**
- * add_single_flow_creds - adds single buffer credentials.
+ * mei_hbm_add_single_flow_creds - adds single buffer credentials.
*
- * @file: private data ot the file object.
+ * @dev: the device structure
* @flow: flow control.
*/
static void mei_hbm_add_single_flow_creds(struct mei_device *dev,
@@ -477,7 +501,7 @@ static void mei_hbm_cl_connect_res(struct mei_device *dev,
/**
- * mei_client_disconnect_request - disconnect request initiated by me
+ * mei_hbm_fw_disconnect_req - disconnect request initiated by me
* host sends disoconnect response
*
* @dev: the device structure.
@@ -542,27 +566,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
dev->version = version_res->me_max_version;
dev_dbg(&dev->pdev->dev, "version mismatch.\n");
+ dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_msg.hdr,
dev->wr_msg.data);
mei_write_message(dev, &dev->wr_msg.hdr,
dev->wr_msg.data);
+
return;
}
dev->version.major_version = HBM_MAJOR_VERSION;
dev->version.minor_version = HBM_MINOR_VERSION;
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
- dev->init_clients_state == MEI_START_MESSAGE) {
+ dev->hbm_state == MEI_HBM_START) {
dev->init_clients_timer = 0;
mei_hbm_enum_clients_req(dev);
} else {
- dev->recvd_msg = false;
- dev_dbg(&dev->pdev->dev, "reset due to received hbm: host start\n");
+ dev_err(&dev->pdev->dev, "reset: wrong host start response\n");
mei_reset(dev, 1);
return;
}
- dev->recvd_msg = true;
+ wake_up_interruptible(&dev->wait_recvd_msg);
dev_dbg(&dev->pdev->dev, "host start response message received.\n");
break;
@@ -591,23 +616,20 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
me_client = &dev->me_clients[dev->me_client_presentation_num];
if (props_res->status || !dev->me_clients) {
- dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n");
+ dev_err(&dev->pdev->dev, "reset: properties response hbm wrong status.\n");
mei_reset(dev, 1);
return;
}
if (me_client->client_id != props_res->address) {
- dev_err(&dev->pdev->dev,
- "Host client properties reply mismatch\n");
+ dev_err(&dev->pdev->dev, "reset: host properties response address mismatch\n");
mei_reset(dev, 1);
-
return;
}
if (dev->dev_state != MEI_DEV_INIT_CLIENTS ||
- dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) {
- dev_err(&dev->pdev->dev,
- "Unexpected client properties reply\n");
+ dev->hbm_state != MEI_HBM_CLIENT_PROPERTIES) {
+ dev_err(&dev->pdev->dev, "reset: unexpected properties response\n");
mei_reset(dev, 1);
return;
@@ -626,26 +648,28 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
enum_res = (struct hbm_host_enum_response *) mei_msg;
memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
- dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
+ dev->hbm_state == MEI_HBM_ENUM_CLIENTS) {
dev->init_clients_timer = 0;
dev->me_client_presentation_num = 0;
dev->me_client_index = 0;
mei_hbm_me_cl_allocate(dev);
- dev->init_clients_state =
- MEI_CLIENT_PROPERTIES_MESSAGE;
+ dev->hbm_state = MEI_HBM_CLIENT_PROPERTIES;
/* first property reqeust */
mei_hbm_prop_req(dev);
} else {
- dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n");
+ dev_err(&dev->pdev->dev, "reset: unexpected enumeration response hbm.\n");
mei_reset(dev, 1);
return;
}
break;
case HOST_STOP_RES_CMD:
+
+ if (dev->hbm_state != MEI_HBM_STOP)
+ dev_err(&dev->pdev->dev, "unexpected stop response hbm.\n");
dev->dev_state = MEI_DEV_DISABLED;
- dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
+ dev_info(&dev->pdev->dev, "reset: FW stop response.\n");
mei_reset(dev, 1);
break;
@@ -657,6 +681,7 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
case ME_STOP_REQ_CMD:
+ dev->hbm_state = MEI_HBM_STOP;
mei_hbm_stop_req_prepare(dev, &dev->wr_ext_msg.hdr,
dev->wr_ext_msg.data);
break;
diff --git a/drivers/misc/mei/hbm.h b/drivers/misc/mei/hbm.h
index b552afbaf85c..e80dc24ef3e2 100644
--- a/drivers/misc/mei/hbm.h
+++ b/drivers/misc/mei/hbm.h
@@ -17,6 +17,27 @@
#ifndef _MEI_HBM_H_
#define _MEI_HBM_H_
+struct mei_device;
+struct mei_msg_hdr;
+struct mei_cl;
+
+/**
+ * enum mei_hbm_state - host bus message protocol state
+ *
+ * @MEI_HBM_IDLE : protocol not started
+ * @MEI_HBM_START : start request message was sent
+ * @MEI_HBM_ENUM_CLIENTS : enumeration request was sent
+ * @MEI_HBM_CLIENT_PROPERTIES : acquiring clients properties
+ */
+enum mei_hbm_state {
+ MEI_HBM_IDLE = 0,
+ MEI_HBM_START,
+ MEI_HBM_ENUM_CLIENTS,
+ MEI_HBM_CLIENT_PROPERTIES,
+ MEI_HBM_STARTED,
+ MEI_HBM_STOP,
+};
+
void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr);
static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
@@ -28,8 +49,8 @@ static inline void mei_hbm_hdr(struct mei_msg_hdr *hdr, size_t length)
hdr->reserved = 0;
}
-void mei_hbm_start_req(struct mei_device *dev);
-
+int mei_hbm_start_req(struct mei_device *dev);
+int mei_hbm_start_wait(struct mei_device *dev);
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl);
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl);
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 45ea7185c003..822170f00348 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -26,14 +26,14 @@
/**
- * mei_reg_read - Reads 32bit data from the mei device
+ * mei_me_reg_read - Reads 32bit data from the mei device
*
* @dev: the device structure
* @offset: offset from which to read the data
*
* returns register value (u32)
*/
-static inline u32 mei_reg_read(const struct mei_me_hw *hw,
+static inline u32 mei_me_reg_read(const struct mei_me_hw *hw,
unsigned long offset)
{
return ioread32(hw->mem_addr + offset);
@@ -41,20 +41,20 @@ static inline u32 mei_reg_read(const struct mei_me_hw *hw,
/**
- * mei_reg_write - Writes 32bit data to the mei device
+ * mei_me_reg_write - Writes 32bit data to the mei device
*
* @dev: the device structure
* @offset: offset from which to write the data
* @value: register value to write (u32)
*/
-static inline void mei_reg_write(const struct mei_me_hw *hw,
+static inline void mei_me_reg_write(const struct mei_me_hw *hw,
unsigned long offset, u32 value)
{
iowrite32(value, hw->mem_addr + offset);
}
/**
- * mei_mecbrw_read - Reads 32bit data from ME circular buffer
+ * mei_me_mecbrw_read - Reads 32bit data from ME circular buffer
* read window register
*
* @dev: the device structure
@@ -63,18 +63,18 @@ static inline void mei_reg_write(const struct mei_me_hw *hw,
*/
static u32 mei_me_mecbrw_read(const struct mei_device *dev)
{
- return mei_reg_read(to_me_hw(dev), ME_CB_RW);
+ return mei_me_reg_read(to_me_hw(dev), ME_CB_RW);
}
/**
- * mei_mecsr_read - Reads 32bit data from the ME CSR
+ * mei_me_mecsr_read - Reads 32bit data from the ME CSR
*
* @dev: the device structure
*
* returns ME_CSR_HA register value (u32)
*/
-static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
+static inline u32 mei_me_mecsr_read(const struct mei_me_hw *hw)
{
- return mei_reg_read(hw, ME_CSR_HA);
+ return mei_me_reg_read(hw, ME_CSR_HA);
}
/**
@@ -86,7 +86,7 @@ static inline u32 mei_mecsr_read(const struct mei_me_hw *hw)
*/
static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
{
- return mei_reg_read(hw, H_CSR);
+ return mei_me_reg_read(hw, H_CSR);
}
/**
@@ -98,12 +98,12 @@ static inline u32 mei_hcsr_read(const struct mei_me_hw *hw)
static inline void mei_hcsr_set(struct mei_me_hw *hw, u32 hcsr)
{
hcsr &= ~H_IS;
- mei_reg_write(hw, H_CSR, hcsr);
+ mei_me_reg_write(hw, H_CSR, hcsr);
}
/**
- * me_hw_config - configure hw dependent settings
+ * mei_me_hw_config - configure hw dependent settings
*
* @dev: mei device
*/
@@ -123,7 +123,7 @@ static void mei_me_intr_clear(struct mei_device *dev)
struct mei_me_hw *hw = to_me_hw(dev);
u32 hcsr = mei_hcsr_read(hw);
if ((hcsr & H_IS) == H_IS)
- mei_reg_write(hw, H_CSR, hcsr);
+ mei_me_reg_write(hw, H_CSR, hcsr);
}
/**
* mei_me_intr_enable - enables mei device interrupts
@@ -152,10 +152,24 @@ static void mei_me_intr_disable(struct mei_device *dev)
}
/**
+ * mei_me_hw_reset_release - release device from the reset
+ *
+ * @dev: the device structure
+ */
+static void mei_me_hw_reset_release(struct mei_device *dev)
+{
+ struct mei_me_hw *hw = to_me_hw(dev);
+ u32 hcsr = mei_hcsr_read(hw);
+
+ hcsr |= H_IG;
+ hcsr &= ~H_RST;
+ mei_hcsr_set(hw, hcsr);
+}
+/**
* mei_me_hw_reset - resets fw via mei csr register.
*
* @dev: the device structure
- * @interrupts_enabled: if interrupt should be enabled after reset.
+ * @intr_enable: if interrupt should be enabled after reset.
*/
static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
{
@@ -169,18 +183,14 @@ static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
if (intr_enable)
hcsr |= H_IE;
else
- hcsr &= ~H_IE;
-
- mei_hcsr_set(hw, hcsr);
-
- hcsr = mei_hcsr_read(hw) | H_IG;
- hcsr &= ~H_RST;
+ hcsr |= ~H_IE;
mei_hcsr_set(hw, hcsr);
- hcsr = mei_hcsr_read(hw);
+ if (dev->dev_state == MEI_DEV_POWER_DOWN)
+ mei_me_hw_reset_release(dev);
- dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
+ dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
}
/**
@@ -218,10 +228,42 @@ static bool mei_me_host_is_ready(struct mei_device *dev)
static bool mei_me_hw_is_ready(struct mei_device *dev)
{
struct mei_me_hw *hw = to_me_hw(dev);
- hw->me_hw_state = mei_mecsr_read(hw);
+ hw->me_hw_state = mei_me_mecsr_read(hw);
return (hw->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA;
}
+static int mei_me_hw_ready_wait(struct mei_device *dev)
+{
+ int err;
+ if (mei_me_hw_is_ready(dev))
+ return 0;
+
+ mutex_unlock(&dev->device_lock);
+ err = wait_event_interruptible_timeout(dev->wait_hw_ready,
+ dev->recvd_hw_ready, MEI_INTEROP_TIMEOUT);
+ mutex_lock(&dev->device_lock);
+ if (!err && !dev->recvd_hw_ready) {
+ dev_err(&dev->pdev->dev,
+ "wait hw ready failed. status = 0x%x\n", err);
+ return -ETIMEDOUT;
+ }
+
+ dev->recvd_hw_ready = false;
+ return 0;
+}
+
+static int mei_me_hw_start(struct mei_device *dev)
+{
+ int ret = mei_me_hw_ready_wait(dev);
+ if (ret)
+ return ret;
+ dev_dbg(&dev->pdev->dev, "hw is ready\n");
+
+ mei_me_host_set_ready(dev);
+ return ret;
+}
+
+
/**
* mei_hbuf_filled_slots - gets number of device filled buffer slots
*
@@ -243,7 +285,7 @@ static unsigned char mei_hbuf_filled_slots(struct mei_device *dev)
}
/**
- * mei_hbuf_is_empty - checks if host buffer is empty.
+ * mei_me_hbuf_is_empty - checks if host buffer is empty.
*
* @dev: the device structure
*
@@ -295,10 +337,11 @@ static int mei_me_write_message(struct mei_device *dev,
unsigned char *buf)
{
struct mei_me_hw *hw = to_me_hw(dev);
- unsigned long rem, dw_cnt;
+ unsigned long rem;
unsigned long length = header->length;
u32 *reg_buf = (u32 *)buf;
u32 hcsr;
+ u32 dw_cnt;
int i;
int empty_slots;
@@ -311,16 +354,16 @@ static int mei_me_write_message(struct mei_device *dev,
if (empty_slots < 0 || dw_cnt > empty_slots)
return -EIO;
- mei_reg_write(hw, H_CB_WW, *((u32 *) header));
+ mei_me_reg_write(hw, H_CB_WW, *((u32 *) header));
for (i = 0; i < length / 4; i++)
- mei_reg_write(hw, H_CB_WW, reg_buf[i]);
+ mei_me_reg_write(hw, H_CB_WW, reg_buf[i]);
rem = length & 0x3;
if (rem > 0) {
u32 reg = 0;
memcpy(&reg, &buf[length - rem], rem);
- mei_reg_write(hw, H_CB_WW, reg);
+ mei_me_reg_write(hw, H_CB_WW, reg);
}
hcsr = mei_hcsr_read(hw) | H_IG;
@@ -344,7 +387,7 @@ static int mei_me_count_full_read_slots(struct mei_device *dev)
char read_ptr, write_ptr;
unsigned char buffer_depth, filled_slots;
- hw->me_hw_state = mei_mecsr_read(hw);
+ hw->me_hw_state = mei_me_mecsr_read(hw);
buffer_depth = (unsigned char)((hw->me_hw_state & ME_CBD_HRA) >> 24);
read_ptr = (char) ((hw->me_hw_state & ME_CBRP_HRA) >> 8);
write_ptr = (char) ((hw->me_hw_state & ME_CBWP_HRA) >> 16);
@@ -404,7 +447,7 @@ irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id)
return IRQ_NONE;
/* clear H_IS bit in H_CSR */
- mei_reg_write(hw, H_CSR, csr_reg);
+ mei_me_reg_write(hw, H_CSR, csr_reg);
return IRQ_WAKE_THREAD;
}
@@ -423,12 +466,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
{
struct mei_device *dev = (struct mei_device *) dev_id;
struct mei_cl_cb complete_list;
- struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
- struct mei_cl *cl;
s32 slots;
int rets;
- bool bus_message_received;
-
dev_dbg(&dev->pdev->dev, "function called after ISR to handle the interrupt processing.\n");
/* initialize our complete list */
@@ -442,7 +481,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if ME wants a reset */
if (!mei_hw_is_ready(dev) &&
- dev->dev_state != MEI_DEV_RESETING &&
+ dev->dev_state != MEI_DEV_RESETTING &&
dev->dev_state != MEI_DEV_INITIALIZING) {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
mei_reset(dev, 1);
@@ -455,18 +494,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
if (mei_hw_is_ready(dev)) {
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
- mei_host_set_ready(dev);
-
- dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
- /* link is established * start sending messages. */
-
- dev->dev_state = MEI_DEV_INIT_CLIENTS;
+ dev->recvd_hw_ready = true;
+ wake_up_interruptible(&dev->wait_hw_ready);
- mei_hbm_start_req(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
} else {
- dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+ dev_dbg(&dev->pdev->dev, "Reset Completed.\n");
+ mei_me_hw_reset_release(dev);
mutex_unlock(&dev->device_lock);
return IRQ_HANDLED;
}
@@ -488,44 +523,20 @@ end:
dev_dbg(&dev->pdev->dev, "end of bottom half function.\n");
dev->hbuf_is_ready = mei_hbuf_is_ready(dev);
- bus_message_received = false;
- if (dev->recvd_msg && waitqueue_active(&dev->wait_recvd_msg)) {
- dev_dbg(&dev->pdev->dev, "received waiting bus message\n");
- bus_message_received = true;
- }
mutex_unlock(&dev->device_lock);
- if (bus_message_received) {
- dev_dbg(&dev->pdev->dev, "wake up dev->wait_recvd_msg\n");
- wake_up_interruptible(&dev->wait_recvd_msg);
- bus_message_received = false;
- }
- if (list_empty(&complete_list.list))
- return IRQ_HANDLED;
+ mei_irq_compl_handler(dev, &complete_list);
- list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) {
- cl = cb_pos->cl;
- list_del(&cb_pos->list);
- if (cl) {
- if (cl != &dev->iamthif_cl) {
- dev_dbg(&dev->pdev->dev, "completing call back.\n");
- mei_irq_complete_handler(cl, cb_pos);
- cb_pos = NULL;
- } else if (cl == &dev->iamthif_cl) {
- mei_amthif_complete(dev, cb_pos);
- }
- }
- }
return IRQ_HANDLED;
}
static const struct mei_hw_ops mei_me_hw_ops = {
- .host_set_ready = mei_me_host_set_ready,
.host_is_ready = mei_me_host_is_ready,
.hw_is_ready = mei_me_hw_is_ready,
.hw_reset = mei_me_hw_reset,
- .hw_config = mei_me_hw_config,
+ .hw_config = mei_me_hw_config,
+ .hw_start = mei_me_hw_start,
.intr_clear = mei_me_intr_clear,
.intr_enable = mei_me_intr_enable,
@@ -543,7 +554,7 @@ static const struct mei_hw_ops mei_me_hw_ops = {
};
/**
- * init_mei_device - allocates and initializes the mei device structure
+ * mei_me_dev_init - allocates and initializes the mei device structure
*
* @pdev: The pci device structure
*
@@ -560,14 +571,6 @@ struct mei_device *mei_me_dev_init(struct pci_dev *pdev)
mei_device_init(dev);
- INIT_LIST_HEAD(&dev->wd_cl.link);
- INIT_LIST_HEAD(&dev->iamthif_cl.link);
- mei_io_list_init(&dev->amthif_cmd_list);
- mei_io_list_init(&dev->amthif_rd_complete_list);
-
- INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
- INIT_WORK(&dev->init_work, mei_host_client_init);
-
dev->ops = &mei_me_hw_ops;
dev->pdev = pdev;
diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h
index 8518d3eeb838..80bd829fbd9a 100644
--- a/drivers/misc/mei/hw-me.h
+++ b/drivers/misc/mei/hw-me.h
@@ -36,12 +36,6 @@ struct mei_me_hw {
struct mei_device *mei_me_dev_init(struct pci_dev *pdev);
-/* get slots (dwords) from a message length + header (bytes) */
-static inline unsigned char mei_data2slots(size_t length)
-{
- return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
-}
-
irqreturn_t mei_me_irq_quick_handler(int irq, void *dev_id);
irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id);
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 6ec530168afb..713d89fedc46 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -14,6 +14,7 @@
*
*/
+#include <linux/export.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/wait.h>
@@ -22,6 +23,7 @@
#include <linux/mei.h>
#include "mei_dev.h"
+#include "hbm.h"
#include "client.h"
const char *mei_dev_state_str(int state)
@@ -31,9 +33,8 @@ const char *mei_dev_state_str(int state)
MEI_DEV_STATE(INITIALIZING);
MEI_DEV_STATE(INIT_CLIENTS);
MEI_DEV_STATE(ENABLED);
- MEI_DEV_STATE(RESETING);
+ MEI_DEV_STATE(RESETTING);
MEI_DEV_STATE(DISABLED);
- MEI_DEV_STATE(RECOVERING_FROM_RESET);
MEI_DEV_STATE(POWER_DOWN);
MEI_DEV_STATE(POWER_UP);
default:
@@ -46,7 +47,9 @@ void mei_device_init(struct mei_device *dev)
{
/* setup our list array */
INIT_LIST_HEAD(&dev->file_list);
+ INIT_LIST_HEAD(&dev->device_list);
mutex_init(&dev->device_lock);
+ init_waitqueue_head(&dev->wait_hw_ready);
init_waitqueue_head(&dev->wait_recvd_msg);
init_waitqueue_head(&dev->wait_stop_wd);
dev->dev_state = MEI_DEV_INITIALIZING;
@@ -56,19 +59,27 @@ void mei_device_init(struct mei_device *dev)
mei_io_list_init(&dev->write_waiting_list);
mei_io_list_init(&dev->ctrl_wr_list);
mei_io_list_init(&dev->ctrl_rd_list);
+
+ INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
+ INIT_WORK(&dev->init_work, mei_host_client_init);
+
+ INIT_LIST_HEAD(&dev->wd_cl.link);
+ INIT_LIST_HEAD(&dev->iamthif_cl.link);
+ mei_io_list_init(&dev->amthif_cmd_list);
+ mei_io_list_init(&dev->amthif_rd_complete_list);
+
}
+EXPORT_SYMBOL_GPL(mei_device_init);
/**
- * mei_hw_init - initializes host and fw to start work.
+ * mei_start - initializes host and fw to start work.
*
* @dev: the device structure
*
* returns 0 on success, <0 on failure.
*/
-int mei_hw_init(struct mei_device *dev)
+int mei_start(struct mei_device *dev)
{
- int ret = 0;
-
mutex_lock(&dev->device_lock);
/* acknowledge interrupt and stop interupts */
@@ -76,29 +87,15 @@ int mei_hw_init(struct mei_device *dev)
mei_hw_config(dev);
- dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "reset in start the mei device.\n");
mei_reset(dev, 1);
- /* wait for ME to turn on ME_RDY */
- if (!dev->recvd_msg) {
- mutex_unlock(&dev->device_lock);
- ret = wait_event_interruptible_timeout(dev->wait_recvd_msg,
- dev->recvd_msg,
- mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT));
- mutex_lock(&dev->device_lock);
- }
-
- if (ret <= 0 && !dev->recvd_msg) {
- dev->dev_state = MEI_DEV_DISABLED;
- dev_dbg(&dev->pdev->dev,
- "wait_event_interruptible_timeout failed"
- "on wait for ME to turn on ME_RDY.\n");
+ if (mei_hbm_start_wait(dev)) {
+ dev_err(&dev->pdev->dev, "HBM haven't started");
goto err;
}
-
if (!mei_host_is_ready(dev)) {
dev_err(&dev->pdev->dev, "host is not ready.\n");
goto err;
@@ -115,7 +112,6 @@ int mei_hw_init(struct mei_device *dev)
goto err;
}
- dev->recvd_msg = false;
dev_dbg(&dev->pdev->dev, "link layer has been established.\n");
mutex_unlock(&dev->device_lock);
@@ -126,6 +122,7 @@ err:
mutex_unlock(&dev->device_lock);
return -ENODEV;
}
+EXPORT_SYMBOL_GPL(mei_start);
/**
* mei_reset - resets host and fw.
@@ -137,9 +134,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
{
bool unexpected;
- if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET)
- return;
-
unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN &&
@@ -147,11 +141,12 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
mei_hw_reset(dev, interrupts_enabled);
+ dev->hbm_state = MEI_HBM_IDLE;
if (dev->dev_state != MEI_DEV_INITIALIZING) {
if (dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN)
- dev->dev_state = MEI_DEV_RESETING;
+ dev->dev_state = MEI_DEV_RESETTING;
mei_cl_all_disconnect(dev);
@@ -176,13 +171,50 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
+ if (!interrupts_enabled) {
+ dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n");
+ return;
+ }
+
+ mei_hw_start(dev);
+
+ dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
+ /* link is established * start sending messages. */
+
+ dev->dev_state = MEI_DEV_INIT_CLIENTS;
+
+ mei_hbm_start_req(dev);
+
/* wake up all readings so they can be interrupted */
mei_cl_all_read_wakeup(dev);
/* remove all waiting requests */
mei_cl_all_write_clear(dev);
}
+EXPORT_SYMBOL_GPL(mei_reset);
+
+void mei_stop(struct mei_device *dev)
+{
+ dev_dbg(&dev->pdev->dev, "stopping the device.\n");
+
+ mutex_lock(&dev->device_lock);
+
+ cancel_delayed_work(&dev->timer_work);
+ mei_wd_stop(dev);
+
+ mei_nfc_host_exit();
+
+ dev->dev_state = MEI_DEV_POWER_DOWN;
+ mei_reset(dev, 0);
+
+ mutex_unlock(&dev->device_lock);
+
+ flush_scheduled_work();
+
+ mei_watchdog_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(mei_stop);
diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 3535b2676c97..2ad736989410 100644
--- a/drivers/misc/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -15,6 +15,7 @@
*/
+#include <linux/export.h>
#include <linux/pci.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
@@ -30,103 +31,153 @@
/**
- * mei_complete_handler - processes completed operation.
+ * mei_cl_complete_handler - processes completed operation for a client
*
* @cl: private data of the file object.
- * @cb_pos: callback block.
+ * @cb: callback block.
*/
-void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos)
+static void mei_cl_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb)
{
- if (cb_pos->fop_type == MEI_FOP_WRITE) {
- mei_io_cb_free(cb_pos);
- cb_pos = NULL;
+ if (cb->fop_type == MEI_FOP_WRITE) {
+ mei_io_cb_free(cb);
+ cb = NULL;
cl->writing_state = MEI_WRITE_COMPLETE;
if (waitqueue_active(&cl->tx_wait))
wake_up_interruptible(&cl->tx_wait);
- } else if (cb_pos->fop_type == MEI_FOP_READ &&
+ } else if (cb->fop_type == MEI_FOP_READ &&
MEI_READING == cl->reading_state) {
cl->reading_state = MEI_READ_COMPLETE;
if (waitqueue_active(&cl->rx_wait))
wake_up_interruptible(&cl->rx_wait);
+ else
+ mei_cl_bus_rx_event(cl);
+
+ }
+}
+
+/**
+ * mei_irq_compl_handler - dispatch complete handelers
+ * for the completed callbacks
+ *
+ * @dev - mei device
+ * @compl_list - list of completed cbs
+ */
+void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *compl_list)
+{
+ struct mei_cl_cb *cb, *next;
+ struct mei_cl *cl;
+
+ list_for_each_entry_safe(cb, next, &compl_list->list, list) {
+ cl = cb->cl;
+ list_del(&cb->list);
+ if (!cl)
+ continue;
+ dev_dbg(&dev->pdev->dev, "completing call back.\n");
+ if (cl == &dev->iamthif_cl)
+ mei_amthif_complete(dev, cb);
+ else
+ mei_cl_complete_handler(cl, cb);
}
}
+EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
/**
- * _mei_irq_thread_state_ok - checks if mei header matches file private data
+ * mei_cl_hbm_equal - check if hbm is addressed to the client
*
- * @cl: private data of the file object
+ * @cl: host client
* @mei_hdr: header of mei client message
*
- * returns !=0 if matches, 0 if no match.
+ * returns true if matches, false otherwise
+ */
+static inline int mei_cl_hbm_equal(struct mei_cl *cl,
+ struct mei_msg_hdr *mei_hdr)
+{
+ return cl->host_client_id == mei_hdr->host_addr &&
+ cl->me_client_id == mei_hdr->me_addr;
+}
+/**
+ * mei_cl_is_reading - checks if the client
+ is the one to read this message
+ *
+ * @cl: mei client
+ * @mei_hdr: header of mei message
+ *
+ * returns true on match and false otherwise
*/
-static int _mei_irq_thread_state_ok(struct mei_cl *cl,
- struct mei_msg_hdr *mei_hdr)
+static bool mei_cl_is_reading(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
{
- return (cl->host_client_id == mei_hdr->host_addr &&
- cl->me_client_id == mei_hdr->me_addr &&
+ return mei_cl_hbm_equal(cl, mei_hdr) &&
cl->state == MEI_FILE_CONNECTED &&
- MEI_READ_COMPLETE != cl->reading_state);
+ cl->reading_state != MEI_READ_COMPLETE;
}
/**
- * mei_irq_thread_read_client_message - bottom half read routine after ISR to
- * handle the read mei client message data processing.
+ * mei_irq_read_client_message - process client message
*
- * @complete_list: An instance of our list structure
* @dev: the device structure
* @mei_hdr: header of mei client message
+ * @complete_list: An instance of our list structure
*
* returns 0 on success, <0 on failure.
*/
-static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list,
- struct mei_device *dev,
- struct mei_msg_hdr *mei_hdr)
+static int mei_cl_irq_read_msg(struct mei_device *dev,
+ struct mei_msg_hdr *mei_hdr,
+ struct mei_cl_cb *complete_list)
{
struct mei_cl *cl;
- struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL;
+ struct mei_cl_cb *cb, *next;
unsigned char *buffer = NULL;
- dev_dbg(&dev->pdev->dev, "start client msg\n");
- if (list_empty(&dev->read_list.list))
- goto quit;
+ list_for_each_entry_safe(cb, next, &dev->read_list.list, list) {
+ cl = cb->cl;
+ if (!cl || !mei_cl_is_reading(cl, mei_hdr))
+ continue;
- list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) {
- cl = cb_pos->cl;
- if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
- cl->reading_state = MEI_READING;
- buffer = cb_pos->response_buffer.data + cb_pos->buf_idx;
+ cl->reading_state = MEI_READING;
- if (cb_pos->response_buffer.size <
- mei_hdr->length + cb_pos->buf_idx) {
- dev_dbg(&dev->pdev->dev, "message overflow.\n");
- list_del(&cb_pos->list);
+ if (cb->response_buffer.size == 0 ||
+ cb->response_buffer.data == NULL) {
+ dev_err(&dev->pdev->dev, "response buffer is not allocated.\n");
+ list_del(&cb->list);
+ return -ENOMEM;
+ }
+
+ if (cb->response_buffer.size < mei_hdr->length + cb->buf_idx) {
+ dev_dbg(&dev->pdev->dev, "message overflow. size %d len %d idx %ld\n",
+ cb->response_buffer.size,
+ mei_hdr->length, cb->buf_idx);
+ buffer = krealloc(cb->response_buffer.data,
+ mei_hdr->length + cb->buf_idx,
+ GFP_KERNEL);
+
+ if (!buffer) {
+ dev_err(&dev->pdev->dev, "allocation failed.\n");
+ list_del(&cb->list);
return -ENOMEM;
}
- if (buffer)
- mei_read_slots(dev, buffer, mei_hdr->length);
-
- cb_pos->buf_idx += mei_hdr->length;
- if (mei_hdr->msg_complete) {
- cl->status = 0;
- list_del(&cb_pos->list);
- dev_dbg(&dev->pdev->dev,
- "completed read H cl = %d, ME cl = %d, length = %lu\n",
- cl->host_client_id,
- cl->me_client_id,
- cb_pos->buf_idx);
-
- list_add_tail(&cb_pos->list,
- &complete_list->list);
- }
-
- break;
+ cb->response_buffer.data = buffer;
+ cb->response_buffer.size =
+ mei_hdr->length + cb->buf_idx;
}
+ buffer = cb->response_buffer.data + cb->buf_idx;
+ mei_read_slots(dev, buffer, mei_hdr->length);
+
+ cb->buf_idx += mei_hdr->length;
+ if (mei_hdr->msg_complete) {
+ cl->status = 0;
+ list_del(&cb->list);
+ dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n",
+ cl->host_client_id,
+ cl->me_client_id,
+ cb->buf_idx);
+ list_add_tail(&cb->list, &complete_list->list);
+ }
+ break;
}
-quit:
dev_dbg(&dev->pdev->dev, "message read\n");
if (!buffer) {
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
@@ -153,31 +204,33 @@ static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots,
struct mei_cl *cl,
struct mei_cl_cb *cmpl_list)
{
- if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
- sizeof(struct hbm_client_connect_request)))
- return -EBADMSG;
+ u32 msg_slots =
+ mei_data2slots(sizeof(struct hbm_client_connect_request));
- *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
+ if (*slots < msg_slots)
+ return -EMSGSIZE;
+
+ *slots -= msg_slots;
if (mei_hbm_cl_disconnect_req(dev, cl)) {
cl->status = 0;
cb_pos->buf_idx = 0;
list_move_tail(&cb_pos->list, &cmpl_list->list);
- return -EMSGSIZE;
- } else {
- cl->state = MEI_FILE_DISCONNECTING;
- cl->status = 0;
- cb_pos->buf_idx = 0;
- list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
- cl->timer_count = MEI_CONNECT_TIMEOUT;
+ return -EIO;
}
+ cl->state = MEI_FILE_DISCONNECTING;
+ cl->status = 0;
+ cb_pos->buf_idx = 0;
+ list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list);
+ cl->timer_count = MEI_CONNECT_TIMEOUT;
+
return 0;
}
/**
- * _mei_hb_read - processes read related operation.
+ * _mei_irq_thread_read - processes read related operation.
*
* @dev: the device structure.
* @slots: free slots.
@@ -192,14 +245,15 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots,
struct mei_cl *cl,
struct mei_cl_cb *cmpl_list)
{
- if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
- sizeof(struct hbm_flow_control))) {
+ u32 msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
+
+ if (*slots < msg_slots) {
/* return the cancel routine */
list_del(&cb_pos->list);
- return -EBADMSG;
+ return -EMSGSIZE;
}
- *slots -= mei_data2slots(sizeof(struct hbm_flow_control));
+ *slots -= msg_slots;
if (mei_hbm_cl_flow_control_req(dev, cl)) {
cl->status = -ENODEV;
@@ -229,15 +283,19 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots,
struct mei_cl *cl,
struct mei_cl_cb *cmpl_list)
{
- if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) +
- sizeof(struct hbm_client_connect_request))) {
+ u32 msg_slots =
+ mei_data2slots(sizeof(struct hbm_client_connect_request));
+
+ if (*slots < msg_slots) {
/* return the cancel routine */
list_del(&cb_pos->list);
- return -EBADMSG;
+ return -EMSGSIZE;
}
+ *slots -= msg_slots;
+
cl->state = MEI_FILE_CONNECTING;
- *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request));
+
if (mei_hbm_cl_connect_req(dev, cl)) {
cl->status = -ENODEV;
cb_pos->buf_idx = 0;
@@ -266,7 +324,7 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
struct mei_msg_hdr mei_hdr;
struct mei_cl *cl = cb->cl;
size_t len = cb->request_buffer.size - cb->buf_idx;
- size_t msg_slots = mei_data2slots(len);
+ u32 msg_slots = mei_data2slots(len);
mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id;
@@ -298,19 +356,20 @@ static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots,
return -ENODEV;
}
- if (mei_cl_flow_ctrl_reduce(cl))
- return -ENODEV;
cl->status = 0;
cb->buf_idx += mei_hdr.length;
- if (mei_hdr.msg_complete)
+ if (mei_hdr.msg_complete) {
+ if (mei_cl_flow_ctrl_reduce(cl))
+ return -ENODEV;
list_move_tail(&cb->list, &dev->write_waiting_list.list);
+ }
return 0;
}
/**
- * mei_irq_thread_read_handler - bottom half read routine after ISR to
+ * mei_irq_read_handler - bottom half read routine after ISR to
* handle the read processing.
*
* @dev: the device structure
@@ -350,8 +409,7 @@ int mei_irq_read_handler(struct mei_device *dev,
" client = %d, ME client = %d\n",
cl_pos->host_client_id,
cl_pos->me_client_id);
- if (cl_pos->host_client_id == mei_hdr->host_addr &&
- cl_pos->me_client_id == mei_hdr->me_addr)
+ if (mei_cl_hbm_equal(cl_pos, mei_hdr))
break;
}
@@ -362,7 +420,7 @@ int mei_irq_read_handler(struct mei_device *dev,
}
}
if (((*slots) * sizeof(u32)) < mei_hdr->length) {
- dev_dbg(&dev->pdev->dev,
+ dev_err(&dev->pdev->dev,
"we can't read the message slots =%08x.\n",
*slots);
/* we can't read the message */
@@ -378,20 +436,19 @@ int mei_irq_read_handler(struct mei_device *dev,
} else if (mei_hdr->host_addr == dev->iamthif_cl.host_client_id &&
(MEI_FILE_CONNECTED == dev->iamthif_cl.state) &&
(dev->iamthif_state == MEI_IAMTHIF_READING)) {
- dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
+ dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n");
dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
- ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr);
+ ret = mei_amthif_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret)
goto end;
} else {
- dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_client_message.\n");
- ret = mei_irq_thread_read_client_message(cmpl_list,
- dev, mei_hdr);
+ dev_dbg(&dev->pdev->dev, "call mei_cl_irq_read_msg.\n");
+ dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(mei_hdr));
+ ret = mei_cl_irq_read_msg(dev, mei_hdr, cmpl_list);
if (ret)
goto end;
-
}
/* reset the number of slots and header */
@@ -400,7 +457,7 @@ int mei_irq_read_handler(struct mei_device *dev,
if (*slots == -EOVERFLOW) {
/* overflow - reset */
- dev_dbg(&dev->pdev->dev, "resetting due to slots overflow.\n");
+ dev_err(&dev->pdev->dev, "resetting due to slots overflow.\n");
/* set the event since message has been read */
ret = -ERANGE;
goto end;
@@ -408,6 +465,7 @@ int mei_irq_read_handler(struct mei_device *dev,
end:
return ret;
}
+EXPORT_SYMBOL_GPL(mei_irq_read_handler);
/**
@@ -419,8 +477,7 @@ end:
*
* returns 0 on success, <0 on failure.
*/
-int mei_irq_write_handler(struct mei_device *dev,
- struct mei_cl_cb *cmpl_list)
+int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list)
{
struct mei_cl *cl;
@@ -559,6 +616,7 @@ int mei_irq_write_handler(struct mei_device *dev,
}
return 0;
}
+EXPORT_SYMBOL_GPL(mei_irq_write_handler);
@@ -586,8 +644,8 @@ void mei_timer(struct work_struct *work)
if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
if (dev->init_clients_timer) {
if (--dev->init_clients_timer == 0) {
- dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
- dev->init_clients_state);
+ dev_err(&dev->pdev->dev, "reset: init clients timeout hbm_state = %d.\n",
+ dev->hbm_state);
mei_reset(dev, 1);
}
}
@@ -598,7 +656,7 @@ void mei_timer(struct work_struct *work)
list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
if (cl_pos->timer_count) {
if (--cl_pos->timer_count == 0) {
- dev_dbg(&dev->pdev->dev, "HECI reset due to connect/disconnect timeout.\n");
+ dev_err(&dev->pdev->dev, "reset: connect/disconnect timeout.\n");
mei_reset(dev, 1);
goto out;
}
@@ -607,7 +665,7 @@ void mei_timer(struct work_struct *work)
if (dev->iamthif_stall_timer) {
if (--dev->iamthif_stall_timer == 0) {
- dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
+ dev_err(&dev->pdev->dev, "reset: amthif hanged.\n");
mei_reset(dev, 1);
dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0;
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 903f809b21f7..7c44c8dbae42 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -48,7 +48,7 @@
*
* @inode: pointer to inode structure
* @file: pointer to file structure
- *
+ e
* returns 0 on success, <0 on error
*/
static int mei_open(struct inode *inode, struct file *file)
@@ -244,7 +244,7 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
goto out;
}
- err = mei_cl_read_start(cl);
+ err = mei_cl_read_start(cl, length);
if (err && err != -EBUSY) {
dev_dbg(&dev->pdev->dev,
"mei start read failure with status = %d\n", err);
@@ -292,9 +292,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
}
/* now copy the data to user space */
copy_buffer:
- dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n",
- cb->response_buffer.size);
- dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx);
+ dev_dbg(&dev->pdev->dev, "buf.size = %d buf.idx= %ld\n",
+ cb->response_buffer.size, cb->buf_idx);
if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) {
rets = -EMSGSIZE;
goto free;
@@ -342,11 +341,10 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
{
struct mei_cl *cl = file->private_data;
struct mei_cl_cb *write_cb = NULL;
- struct mei_msg_hdr mei_hdr;
struct mei_device *dev;
unsigned long timeout = 0;
int rets;
- int i;
+ int id;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -357,24 +355,24 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
- goto err;
+ goto out;
}
- i = mei_me_cl_by_id(dev, cl->me_client_id);
- if (i < 0) {
+ id = mei_me_cl_by_id(dev, cl->me_client_id);
+ if (id < 0) {
rets = -ENODEV;
- goto err;
+ goto out;
}
- if (length > dev->me_clients[i].props.max_msg_length || length <= 0) {
+ if (length > dev->me_clients[id].props.max_msg_length || length <= 0) {
rets = -EMSGSIZE;
- goto err;
+ goto out;
}
if (cl->state != MEI_FILE_CONNECTED) {
- rets = -ENODEV;
dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d",
cl->host_client_id, cl->me_client_id);
- goto err;
+ rets = -ENODEV;
+ goto out;
}
if (cl == &dev->iamthif_cl) {
write_cb = mei_amthif_find_read_list_entry(dev, file);
@@ -412,17 +410,15 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (!write_cb) {
dev_err(&dev->pdev->dev, "write cb allocation failed\n");
rets = -ENOMEM;
- goto err;
+ goto out;
}
rets = mei_io_cb_alloc_req_buf(write_cb, length);
if (rets)
- goto err;
-
- dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length);
+ goto out;
rets = copy_from_user(write_cb->request_buffer.data, ubuf, length);
if (rets)
- goto err;
+ goto out;
cl->sm_state = 0;
if (length == 4 &&
@@ -440,65 +436,17 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
if (rets) {
dev_err(&dev->pdev->dev,
"amthif write failed with status = %d\n", rets);
- goto err;
+ goto out;
}
mutex_unlock(&dev->device_lock);
return length;
}
- write_cb->fop_type = MEI_FOP_WRITE;
-
- dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n",
- cl->host_client_id, cl->me_client_id);
- rets = mei_cl_flow_ctrl_creds(cl);
- if (rets < 0)
- goto err;
-
- if (rets == 0 || !dev->hbuf_is_ready) {
- write_cb->buf_idx = 0;
- mei_hdr.msg_complete = 0;
- cl->writing_state = MEI_WRITING;
- goto out;
- }
-
- dev->hbuf_is_ready = false;
- if (length > mei_hbuf_max_len(dev)) {
- mei_hdr.length = mei_hbuf_max_len(dev);
- mei_hdr.msg_complete = 0;
- } else {
- mei_hdr.length = length;
- mei_hdr.msg_complete = 1;
- }
- mei_hdr.host_addr = cl->host_client_id;
- mei_hdr.me_addr = cl->me_client_id;
- mei_hdr.reserved = 0;
-
- dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
- MEI_HDR_PRM(&mei_hdr));
- if (mei_write_message(dev, &mei_hdr, write_cb->request_buffer.data)) {
- rets = -ENODEV;
- goto err;
- }
- cl->writing_state = MEI_WRITING;
- write_cb->buf_idx = mei_hdr.length;
-
+ rets = mei_cl_write(cl, write_cb, false);
out:
- if (mei_hdr.msg_complete) {
- if (mei_cl_flow_ctrl_reduce(cl)) {
- rets = -ENODEV;
- goto err;
- }
- list_add_tail(&write_cb->list, &dev->write_waiting_list.list);
- } else {
- list_add_tail(&write_cb->list, &dev->write_list.list);
- }
-
mutex_unlock(&dev->device_lock);
- return length;
-
-err:
- mutex_unlock(&dev->device_lock);
- mei_io_cb_free(write_cb);
+ if (rets < 0)
+ mei_io_cb_free(write_cb);
return rets;
}
@@ -753,17 +701,44 @@ static struct miscdevice mei_misc_device = {
.minor = MISC_DYNAMIC_MINOR,
};
-int mei_register(struct device *dev)
+
+int mei_register(struct mei_device *dev)
{
- mei_misc_device.parent = dev;
- return misc_register(&mei_misc_device);
+ int ret;
+ mei_misc_device.parent = &dev->pdev->dev;
+ ret = misc_register(&mei_misc_device);
+ if (ret)
+ return ret;
+
+ if (mei_dbgfs_register(dev, mei_misc_device.name))
+ dev_err(&dev->pdev->dev, "cannot register debugfs\n");
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(mei_register);
-void mei_deregister(void)
+void mei_deregister(struct mei_device *dev)
{
+ mei_dbgfs_deregister(dev);
misc_deregister(&mei_misc_device);
mei_misc_device.parent = NULL;
}
+EXPORT_SYMBOL_GPL(mei_deregister);
+
+static int __init mei_init(void)
+{
+ return mei_cl_bus_init();
+}
+
+static void __exit mei_exit(void)
+{
+ mei_cl_bus_exit();
+}
+
+module_init(mei_init);
+module_exit(mei_exit);
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index cb80166161f0..4de5140e7379 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -21,9 +21,11 @@
#include <linux/watchdog.h>
#include <linux/poll.h>
#include <linux/mei.h>
+#include <linux/mei_cl_bus.h>
#include "hw.h"
#include "hw-me-regs.h"
+#include "hbm.h"
/*
* watch dog definition
@@ -95,22 +97,14 @@ enum mei_dev_state {
MEI_DEV_INITIALIZING = 0,
MEI_DEV_INIT_CLIENTS,
MEI_DEV_ENABLED,
- MEI_DEV_RESETING,
+ MEI_DEV_RESETTING,
MEI_DEV_DISABLED,
- MEI_DEV_RECOVERING_FROM_RESET,
MEI_DEV_POWER_DOWN,
MEI_DEV_POWER_UP
};
const char *mei_dev_state_str(int state);
-/* init clients states*/
-enum mei_init_clients_states {
- MEI_START_MESSAGE = 0,
- MEI_ENUM_CLIENTS_MESSAGE,
- MEI_CLIENT_PROPERTIES_MESSAGE
-};
-
enum iamthif_states {
MEI_IAMTHIF_IDLE,
MEI_IAMTHIF_WRITING,
@@ -153,7 +147,7 @@ enum mei_cb_file_ops {
/*
* Intel MEI message data struct
*/
-struct mei_message_data {
+struct mei_msg_data {
u32 size;
unsigned char *data;
};
@@ -184,8 +178,8 @@ struct mei_cl_cb {
struct list_head list;
struct mei_cl *cl;
enum mei_cb_file_ops fop_type;
- struct mei_message_data request_buffer;
- struct mei_message_data response_buffer;
+ struct mei_msg_data request_buffer;
+ struct mei_msg_data response_buffer;
unsigned long buf_idx;
unsigned long read_time;
struct file *file_object;
@@ -209,15 +203,20 @@ struct mei_cl {
enum mei_file_transaction_states writing_state;
int sm_state;
struct mei_cl_cb *read_cb;
+
+ /* MEI CL bus data */
+ struct mei_cl_device *device;
+ struct list_head device_link;
+ uuid_le device_uuid;
};
/** struct mei_hw_ops
*
- * @host_set_ready - notify FW that host side is ready
* @host_is_ready - query for host readiness
* @hw_is_ready - query if hw is ready
* @hw_reset - reset hw
+ * @hw_start - start hw after reset
* @hw_config - configure hw
* @intr_clear - clear pending interrupts
@@ -237,11 +236,11 @@ struct mei_cl {
*/
struct mei_hw_ops {
- void (*host_set_ready) (struct mei_device *dev);
bool (*host_is_ready) (struct mei_device *dev);
bool (*hw_is_ready) (struct mei_device *dev);
void (*hw_reset) (struct mei_device *dev, bool enable);
+ int (*hw_start) (struct mei_device *dev);
void (*hw_config) (struct mei_device *dev);
void (*intr_clear) (struct mei_device *dev);
@@ -263,9 +262,77 @@ struct mei_hw_ops {
unsigned char *buf, unsigned long len);
};
+/* MEI bus API*/
+
+/**
+ * struct mei_cl_ops - MEI CL device ops
+ * This structure allows ME host clients to implement technology
+ * specific operations.
+ *
+ * @enable: Enable an MEI CL device. Some devices require specific
+ * HECI commands to initialize completely.
+ * @disable: Disable an MEI CL device.
+ * @send: Tx hook for the device. This allows ME host clients to trap
+ * the device driver buffers before actually physically
+ * pushing it to the ME.
+ * @recv: Rx hook for the device. This allows ME host clients to trap the
+ * ME buffers before forwarding them to the device driver.
+ */
+struct mei_cl_ops {
+ int (*enable)(struct mei_cl_device *device);
+ int (*disable)(struct mei_cl_device *device);
+ int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
+ int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
+};
+
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+ uuid_le uuid, char *name,
+ struct mei_cl_ops *ops);
+void mei_cl_remove_device(struct mei_cl_device *device);
+
+int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+void mei_cl_bus_rx_event(struct mei_cl *cl);
+int mei_cl_bus_init(void);
+void mei_cl_bus_exit(void);
+
+
+/**
+ * struct mei_cl_device - MEI device handle
+ * An mei_cl_device pointer is returned from mei_add_device()
+ * and links MEI bus clients to their actual ME host client pointer.
+ * Drivers for MEI devices will get an mei_cl_device pointer
+ * when being probed and shall use it for doing ME bus I/O.
+ *
+ * @dev: linux driver model device pointer
+ * @uuid: me client uuid
+ * @cl: mei client
+ * @ops: ME transport ops
+ * @event_cb: Drivers register this callback to get asynchronous ME
+ * events (e.g. Rx buffer pending) notifications.
+ * @events: Events bitmask sent to the driver.
+ * @priv_data: client private data
+ */
+struct mei_cl_device {
+ struct device dev;
+
+ struct mei_cl *cl;
+
+ const struct mei_cl_ops *ops;
+
+ struct work_struct event_work;
+ mei_cl_event_cb_t event_cb;
+ void *event_context;
+ unsigned long events;
+
+ void *priv_data;
+};
+
/**
* struct mei_device - MEI private device struct
+ * @hbm_state - state of host bus message protocol
* @mem_addr - mem mapped base register address
* @hbuf_depth - depth of hardware host/write buffer is slots
@@ -296,11 +363,12 @@ struct mei_device {
*/
struct mutex device_lock; /* device lock */
struct delayed_work timer_work; /* MEI timer delayed work (timeouts) */
- bool recvd_msg;
+ bool recvd_hw_ready;
/*
* waiting queue for receive message from FW
*/
+ wait_queue_head_t wait_hw_ready;
wait_queue_head_t wait_recvd_msg;
wait_queue_head_t wait_stop_wd;
@@ -308,7 +376,7 @@ struct mei_device {
* mei device states
*/
enum mei_dev_state dev_state;
- enum mei_init_clients_states init_clients_state;
+ enum mei_hbm_state hbm_state;
u16 init_clients_timer;
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
@@ -365,6 +433,14 @@ struct mei_device {
struct work_struct init_work;
+ /* List of bus devices */
+ struct list_head device_list;
+
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *dbgfs_dir;
+#endif /* CONFIG_DEBUG_FS */
+
+
const struct mei_hw_ops *ops;
char hw[0] __aligned(sizeof(void *));
};
@@ -374,13 +450,24 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
return msecs_to_jiffies(sec * MSEC_PER_SEC);
}
+/**
+ * mei_data2slots - get slots - number of (dwords) from a message length
+ * + size of the mei header
+ * @length - size of the messages in bytes
+ * returns - number of slots
+ */
+static inline u32 mei_data2slots(size_t length)
+{
+ return DIV_ROUND_UP(sizeof(struct mei_msg_hdr) + length, 4);
+}
/*
* mei init function prototypes
*/
void mei_device_init(struct mei_device *dev);
void mei_reset(struct mei_device *dev, int interrupts);
-int mei_hw_init(struct mei_device *dev);
+int mei_start(struct mei_device *dev);
+void mei_stop(struct mei_device *dev);
/*
* MEI interrupt functions prototype
@@ -391,8 +478,7 @@ int mei_irq_read_handler(struct mei_device *dev,
struct mei_cl_cb *cmpl_list, s32 *slots);
int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
-
-void mei_irq_complete_handler(struct mei_cl *cl, struct mei_cl_cb *cb_pos);
+void mei_irq_compl_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list);
/*
* AMTHIF - AMT Host Interface Functions
@@ -416,6 +502,25 @@ struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev,
void mei_amthif_run_next_cmd(struct mei_device *dev);
+int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
+ struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
+
+void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb);
+int mei_amthif_irq_read_msg(struct mei_device *dev,
+ struct mei_msg_hdr *mei_hdr,
+ struct mei_cl_cb *complete_list);
+int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
+
+/*
+ * NFC functions
+ */
+int mei_nfc_host_init(struct mei_device *dev);
+void mei_nfc_host_exit(void);
+
+/*
+ * NFC Client UUID
+ */
+extern const uuid_le mei_nfc_guid;
int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots,
struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list);
@@ -454,6 +559,11 @@ static inline void mei_hw_reset(struct mei_device *dev, bool enable)
dev->ops->hw_reset(dev, enable);
}
+static inline void mei_hw_start(struct mei_device *dev)
+{
+ dev->ops->hw_start(dev);
+}
+
static inline void mei_clear_interrupts(struct mei_device *dev)
{
dev->ops->intr_clear(dev);
@@ -469,10 +579,6 @@ static inline void mei_disable_interrupts(struct mei_device *dev)
dev->ops->intr_disable(dev);
}
-static inline void mei_host_set_ready(struct mei_device *dev)
-{
- dev->ops->host_set_ready(dev);
-}
static inline bool mei_host_is_ready(struct mei_device *dev)
{
return dev->ops->host_is_ready(dev);
@@ -520,8 +626,19 @@ static inline int mei_count_full_read_slots(struct mei_device *dev)
return dev->ops->rdbuf_full_slots(dev);
}
-int mei_register(struct device *dev);
-void mei_deregister(void);
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+int mei_dbgfs_register(struct mei_device *dev, const char *name);
+void mei_dbgfs_deregister(struct mei_device *dev);
+#else
+static inline int mei_dbgfs_register(struct mei_device *dev, const char *name)
+{
+ return 0;
+}
+static inline void mei_dbgfs_deregister(struct mei_device *dev) {}
+#endif /* CONFIG_DEBUG_FS */
+
+int mei_register(struct mei_device *dev);
+void mei_deregister(struct mei_device *dev);
#define MEI_HDR_FMT "hdr:host=%02d me=%02d len=%d comp=%1d"
#define MEI_HDR_PRM(hdr) \
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
new file mode 100644
index 000000000000..3adf8a70f26e
--- /dev/null
+++ b/drivers/misc/mei/nfc.c
@@ -0,0 +1,554 @@
+/*
+ *
+ * Intel Management Engine Interface (Intel MEI) Linux driver
+ * Copyright (c) 2003-2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/mei_cl_bus.h>
+
+#include "mei_dev.h"
+#include "client.h"
+
+struct mei_nfc_cmd {
+ u8 command;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+ u8 sub_command;
+ u8 data[];
+} __packed;
+
+struct mei_nfc_reply {
+ u8 command;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+ u8 sub_command;
+ u8 reply_status;
+ u8 data[];
+} __packed;
+
+struct mei_nfc_if_version {
+ u8 radio_version_sw[3];
+ u8 reserved[3];
+ u8 radio_version_hw[3];
+ u8 i2c_addr;
+ u8 fw_ivn;
+ u8 vendor_id;
+ u8 radio_type;
+} __packed;
+
+struct mei_nfc_connect {
+ u8 fw_ivn;
+ u8 vendor_id;
+} __packed;
+
+struct mei_nfc_connect_resp {
+ u8 fw_ivn;
+ u8 vendor_id;
+ u16 me_major;
+ u16 me_minor;
+ u16 me_hotfix;
+ u16 me_build;
+} __packed;
+
+struct mei_nfc_hci_hdr {
+ u8 cmd;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+} __packed;
+
+#define MEI_NFC_CMD_MAINTENANCE 0x00
+#define MEI_NFC_CMD_HCI_SEND 0x01
+#define MEI_NFC_CMD_HCI_RECV 0x02
+
+#define MEI_NFC_SUBCMD_CONNECT 0x00
+#define MEI_NFC_SUBCMD_IF_VERSION 0x01
+
+#define MEI_NFC_HEADER_SIZE 10
+
+/** mei_nfc_dev - NFC mei device
+ *
+ * @cl: NFC host client
+ * @cl_info: NFC info host client
+ * @init_work: perform connection to the info client
+ * @fw_ivn: NFC Intervace Version Number
+ * @vendor_id: NFC manufacturer ID
+ * @radio_type: NFC radio type
+ */
+struct mei_nfc_dev {
+ struct mei_cl *cl;
+ struct mei_cl *cl_info;
+ struct work_struct init_work;
+ wait_queue_head_t send_wq;
+ u8 fw_ivn;
+ u8 vendor_id;
+ u8 radio_type;
+ char *bus_name;
+
+ u16 req_id;
+ u16 recv_req_id;
+};
+
+static struct mei_nfc_dev nfc_dev;
+
+/* UUIDs for NFC F/W clients */
+const uuid_le mei_nfc_guid = UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50,
+ 0x94, 0xd4, 0x50, 0x26,
+ 0x67, 0x23, 0x77, 0x5c);
+
+static const uuid_le mei_nfc_info_guid = UUID_LE(0xd2de1625, 0x382d, 0x417d,
+ 0x48, 0xa4, 0xef, 0xab,
+ 0xba, 0x8a, 0x12, 0x06);
+
+/* Vendors */
+#define MEI_NFC_VENDOR_INSIDE 0x00
+#define MEI_NFC_VENDOR_NXP 0x01
+
+/* Radio types */
+#define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
+#define MEI_NFC_VENDOR_NXP_PN544 0x01
+
+static void mei_nfc_free(struct mei_nfc_dev *ndev)
+{
+ if (ndev->cl) {
+ list_del(&ndev->cl->device_link);
+ mei_cl_unlink(ndev->cl);
+ kfree(ndev->cl);
+ }
+
+ if (ndev->cl_info) {
+ list_del(&ndev->cl_info->device_link);
+ mei_cl_unlink(ndev->cl_info);
+ kfree(ndev->cl_info);
+ }
+}
+
+static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+
+ if (!ndev->cl)
+ return -ENODEV;
+
+ dev = ndev->cl->dev;
+
+ switch (ndev->vendor_id) {
+ case MEI_NFC_VENDOR_INSIDE:
+ switch (ndev->radio_type) {
+ case MEI_NFC_VENDOR_INSIDE_UREAD:
+ ndev->bus_name = "microread";
+ return 0;
+
+ default:
+ dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+ ndev->radio_type);
+
+ return -EINVAL;
+ }
+
+ case MEI_NFC_VENDOR_NXP:
+ switch (ndev->radio_type) {
+ case MEI_NFC_VENDOR_NXP_PN544:
+ ndev->bus_name = "pn544";
+ return 0;
+ default:
+ dev_err(&dev->pdev->dev, "Unknow radio type 0x%x\n",
+ ndev->radio_type);
+
+ return -EINVAL;
+ }
+
+ default:
+ dev_err(&dev->pdev->dev, "Unknow vendor ID 0x%x\n",
+ ndev->vendor_id);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mei_nfc_connect(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+ struct mei_cl *cl;
+ struct mei_nfc_cmd *cmd, *reply;
+ struct mei_nfc_connect *connect;
+ struct mei_nfc_connect_resp *connect_resp;
+ size_t connect_length, connect_resp_length;
+ int bytes_recv, ret;
+
+ cl = ndev->cl;
+ dev = cl->dev;
+
+ connect_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect);
+
+ connect_resp_length = sizeof(struct mei_nfc_cmd) +
+ sizeof(struct mei_nfc_connect_resp);
+
+ cmd = kzalloc(connect_length, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+ connect = (struct mei_nfc_connect *)cmd->data;
+
+ reply = kzalloc(connect_resp_length, GFP_KERNEL);
+ if (!reply) {
+ kfree(cmd);
+ return -ENOMEM;
+ }
+
+ connect_resp = (struct mei_nfc_connect_resp *)reply->data;
+
+ cmd->command = MEI_NFC_CMD_MAINTENANCE;
+ cmd->data_size = 3;
+ cmd->sub_command = MEI_NFC_SUBCMD_CONNECT;
+ connect->fw_ivn = ndev->fw_ivn;
+ connect->vendor_id = ndev->vendor_id;
+
+ ret = __mei_cl_send(cl, (u8 *)cmd, connect_length);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not send connect cmd\n");
+ goto err;
+ }
+
+ bytes_recv = __mei_cl_recv(cl, (u8 *)reply, connect_resp_length);
+ if (bytes_recv < 0) {
+ dev_err(&dev->pdev->dev, "Could not read connect response\n");
+ ret = bytes_recv;
+ goto err;
+ }
+
+ dev_info(&dev->pdev->dev, "IVN 0x%x Vendor ID 0x%x\n",
+ connect_resp->fw_ivn, connect_resp->vendor_id);
+
+ dev_info(&dev->pdev->dev, "ME FW %d.%d.%d.%d\n",
+ connect_resp->me_major, connect_resp->me_minor,
+ connect_resp->me_hotfix, connect_resp->me_build);
+
+ ret = 0;
+
+err:
+ kfree(reply);
+ kfree(cmd);
+
+ return ret;
+}
+
+static int mei_nfc_if_version(struct mei_nfc_dev *ndev)
+{
+ struct mei_device *dev;
+ struct mei_cl *cl;
+
+ struct mei_nfc_cmd cmd;
+ struct mei_nfc_reply *reply = NULL;
+ struct mei_nfc_if_version *version;
+ size_t if_version_length;
+ int bytes_recv, ret;
+
+ cl = ndev->cl_info;
+ dev = cl->dev;
+
+ memset(&cmd, 0, sizeof(struct mei_nfc_cmd));
+ cmd.command = MEI_NFC_CMD_MAINTENANCE;
+ cmd.data_size = 1;
+ cmd.sub_command = MEI_NFC_SUBCMD_IF_VERSION;
+
+ ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd));
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not send IF version cmd\n");
+ return ret;
+ }
+
+ /* to be sure on the stack we alloc memory */
+ if_version_length = sizeof(struct mei_nfc_reply) +
+ sizeof(struct mei_nfc_if_version);
+
+ reply = kzalloc(if_version_length, GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+
+ bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length);
+ if (bytes_recv < 0 || bytes_recv < sizeof(struct mei_nfc_reply)) {
+ dev_err(&dev->pdev->dev, "Could not read IF version\n");
+ ret = -EIO;
+ goto err;
+ }
+
+ version = (struct mei_nfc_if_version *)reply->data;
+
+ ndev->fw_ivn = version->fw_ivn;
+ ndev->vendor_id = version->vendor_id;
+ ndev->radio_type = version->radio_type;
+
+err:
+ kfree(reply);
+ return ret;
+}
+
+static int mei_nfc_enable(struct mei_cl_device *cldev)
+{
+ struct mei_device *dev;
+ struct mei_nfc_dev *ndev = &nfc_dev;
+ int ret;
+
+ dev = ndev->cl->dev;
+
+ ret = mei_nfc_connect(ndev);
+ if (ret < 0) {
+ dev_err(&dev->pdev->dev, "Could not connect to NFC");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mei_nfc_disable(struct mei_cl_device *cldev)
+{
+ return 0;
+}
+
+static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+ struct mei_device *dev;
+ struct mei_nfc_dev *ndev;
+ struct mei_nfc_hci_hdr *hdr;
+ u8 *mei_buf;
+ int err;
+
+ ndev = (struct mei_nfc_dev *) cldev->priv_data;
+ dev = ndev->cl->dev;
+
+ mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
+ if (!mei_buf)
+ return -ENOMEM;
+
+ hdr = (struct mei_nfc_hci_hdr *) mei_buf;
+ hdr->cmd = MEI_NFC_CMD_HCI_SEND;
+ hdr->status = 0;
+ hdr->req_id = ndev->req_id;
+ hdr->reserved = 0;
+ hdr->data_size = length;
+
+ memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
+
+ err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
+ if (err < 0)
+ return err;
+
+ kfree(mei_buf);
+
+ if (!wait_event_interruptible_timeout(ndev->send_wq,
+ ndev->recv_req_id == ndev->req_id, HZ)) {
+ dev_err(&dev->pdev->dev, "NFC MEI command timeout\n");
+ err = -ETIMEDOUT;
+ } else {
+ ndev->req_id++;
+ }
+
+ return err;
+}
+
+static int mei_nfc_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
+{
+ struct mei_nfc_dev *ndev;
+ struct mei_nfc_hci_hdr *hci_hdr;
+ int received_length;
+
+ ndev = (struct mei_nfc_dev *)cldev->priv_data;
+
+ received_length = __mei_cl_recv(ndev->cl, buf, length);
+ if (received_length < 0)
+ return received_length;
+
+ hci_hdr = (struct mei_nfc_hci_hdr *) buf;
+
+ if (hci_hdr->cmd == MEI_NFC_CMD_HCI_SEND) {
+ ndev->recv_req_id = hci_hdr->req_id;
+ wake_up(&ndev->send_wq);
+
+ return 0;
+ }
+
+ return received_length;
+}
+
+static struct mei_cl_ops nfc_ops = {
+ .enable = mei_nfc_enable,
+ .disable = mei_nfc_disable,
+ .send = mei_nfc_send,
+ .recv = mei_nfc_recv,
+};
+
+static void mei_nfc_init(struct work_struct *work)
+{
+ struct mei_device *dev;
+ struct mei_cl_device *cldev;
+ struct mei_nfc_dev *ndev;
+ struct mei_cl *cl_info;
+
+ ndev = container_of(work, struct mei_nfc_dev, init_work);
+
+ cl_info = ndev->cl_info;
+ dev = cl_info->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (mei_cl_connect(cl_info, NULL) < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not connect to the NFC INFO ME client");
+
+ goto err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (mei_nfc_if_version(ndev) < 0) {
+ dev_err(&dev->pdev->dev, "Could not get the NFC interfave version");
+
+ goto err;
+ }
+
+ dev_info(&dev->pdev->dev,
+ "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
+ ndev->fw_ivn, ndev->vendor_id, ndev->radio_type);
+
+ mutex_lock(&dev->device_lock);
+
+ if (mei_cl_disconnect(cl_info) < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not disconnect the NFC INFO ME client");
+
+ goto err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (mei_nfc_build_bus_name(ndev) < 0) {
+ dev_err(&dev->pdev->dev,
+ "Could not build the bus ID name\n");
+ return;
+ }
+
+ cldev = mei_cl_add_device(dev, mei_nfc_guid, ndev->bus_name, &nfc_ops);
+ if (!cldev) {
+ dev_err(&dev->pdev->dev,
+ "Could not add the NFC device to the MEI bus\n");
+
+ goto err;
+ }
+
+ cldev->priv_data = ndev;
+
+
+ return;
+
+err:
+ mei_nfc_free(ndev);
+
+ return;
+}
+
+
+int mei_nfc_host_init(struct mei_device *dev)
+{
+ struct mei_nfc_dev *ndev = &nfc_dev;
+ struct mei_cl *cl_info, *cl = NULL;
+ int i, ret;
+
+ /* already initialzed */
+ if (ndev->cl_info)
+ return 0;
+
+ cl_info = mei_cl_allocate(dev);
+ cl = mei_cl_allocate(dev);
+
+ if (!cl || !cl_info) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* check for valid client id */
+ i = mei_me_cl_by_uuid(dev, &mei_nfc_info_guid);
+ if (i < 0) {
+ dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ cl_info->me_client_id = dev->me_clients[i].client_id;
+
+ ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
+ if (ret)
+ goto err;
+
+ cl_info->device_uuid = mei_nfc_info_guid;
+
+ list_add_tail(&cl_info->device_link, &dev->device_list);
+
+ /* check for valid client id */
+ i = mei_me_cl_by_uuid(dev, &mei_nfc_guid);
+ if (i < 0) {
+ dev_info(&dev->pdev->dev, "nfc: failed to find the client\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ cl->me_client_id = dev->me_clients[i].client_id;
+
+ ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
+ if (ret)
+ goto err;
+
+ cl->device_uuid = mei_nfc_guid;
+
+ list_add_tail(&cl->device_link, &dev->device_list);
+
+ ndev->cl_info = cl_info;
+ ndev->cl = cl;
+ ndev->req_id = 1;
+
+ INIT_WORK(&ndev->init_work, mei_nfc_init);
+ init_waitqueue_head(&ndev->send_wq);
+ schedule_work(&ndev->init_work);
+
+ return 0;
+
+err:
+ mei_nfc_free(ndev);
+
+ return ret;
+}
+
+void mei_nfc_host_exit(void)
+{
+ struct mei_nfc_dev *ndev = &nfc_dev;
+
+ if (ndev->cl && ndev->cl->device)
+ mei_cl_remove_device(ndev->cl->device);
+
+ mei_nfc_free(ndev);
+}
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index b40ec0601ab0..a727464e9c3f 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -47,7 +47,7 @@
static struct pci_dev *mei_pdev;
/* mei_pci_tbl - PCI Device ID Table */
-static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
+static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
@@ -86,18 +86,19 @@ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
{0, }
};
-MODULE_DEVICE_TABLE(pci, mei_pci_tbl);
+MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl);
static DEFINE_MUTEX(mei_mutex);
/**
* mei_quirk_probe - probe for devices that doesn't valid ME interface
+ *
* @pdev: PCI device structure
* @ent: entry into pci_device_table
*
* returns true if ME Interface is valid, false otherwise
*/
-static bool mei_quirk_probe(struct pci_dev *pdev,
+static bool mei_me_quirk_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
u32 reg;
@@ -119,7 +120,7 @@ static bool mei_quirk_probe(struct pci_dev *pdev,
*
* returns 0 on success, <0 on failure.
*/
-static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct mei_device *dev;
struct mei_me_hw *hw;
@@ -127,7 +128,7 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mutex_lock(&mei_mutex);
- if (!mei_quirk_probe(pdev, ent)) {
+ if (!mei_me_quirk_probe(pdev, ent)) {
err = -ENODEV;
goto end;
}
@@ -184,20 +185,19 @@ static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto disable_msi;
}
- if (mei_hw_init(dev)) {
+ if (mei_start(dev)) {
dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV;
goto release_irq;
}
- err = mei_register(&pdev->dev);
+ err = mei_register(dev);
if (err)
goto release_irq;
mei_pdev = pdev;
pci_set_drvdata(pdev, dev);
-
schedule_delayed_work(&dev->timer_work, HZ);
mutex_unlock(&mei_mutex);
@@ -233,7 +233,7 @@ end:
* mei_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device.
*/
-static void mei_remove(struct pci_dev *pdev)
+static void mei_me_remove(struct pci_dev *pdev)
{
struct mei_device *dev;
struct mei_me_hw *hw;
@@ -247,44 +247,12 @@ static void mei_remove(struct pci_dev *pdev)
hw = to_me_hw(dev);
- mutex_lock(&dev->device_lock);
-
- cancel_delayed_work(&dev->timer_work);
- mei_wd_stop(dev);
+ dev_err(&pdev->dev, "stop\n");
+ mei_stop(dev);
mei_pdev = NULL;
- if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
- dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
- mei_cl_disconnect(&dev->iamthif_cl);
- }
- if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
- dev->wd_cl.state = MEI_FILE_DISCONNECTING;
- mei_cl_disconnect(&dev->wd_cl);
- }
-
- /* Unregistering watchdog device */
- mei_watchdog_unregister(dev);
-
- /* remove entry if already in list */
- dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
-
- if (dev->open_handle_count > 0)
- dev->open_handle_count--;
- mei_cl_unlink(&dev->wd_cl);
-
- if (dev->open_handle_count > 0)
- dev->open_handle_count--;
- mei_cl_unlink(&dev->iamthif_cl);
-
- dev->iamthif_current_cb = NULL;
- dev->me_clients_num = 0;
-
- mutex_unlock(&dev->device_lock);
-
- flush_scheduled_work();
-
/* disable interrupts */
mei_disable_interrupts(dev);
@@ -295,44 +263,37 @@ static void mei_remove(struct pci_dev *pdev)
if (hw->mem_addr)
pci_iounmap(pdev, hw->mem_addr);
+ mei_deregister(dev);
+
kfree(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
- mei_deregister();
}
#ifdef CONFIG_PM
-static int mei_pci_suspend(struct device *device)
+static int mei_me_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct mei_device *dev = pci_get_drvdata(pdev);
- int err;
if (!dev)
return -ENODEV;
- mutex_lock(&dev->device_lock);
- cancel_delayed_work(&dev->timer_work);
+ dev_err(&pdev->dev, "suspend\n");
- /* Stop watchdog if exists */
- err = mei_wd_stop(dev);
- /* Set new mei state */
- if (dev->dev_state == MEI_DEV_ENABLED ||
- dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
- dev->dev_state = MEI_DEV_POWER_DOWN;
- mei_reset(dev, 0);
- }
- mutex_unlock(&dev->device_lock);
+ mei_stop(dev);
+
+ mei_disable_interrupts(dev);
free_irq(pdev->irq, dev);
pci_disable_msi(pdev);
- return err;
+ return 0;
}
-static int mei_pci_resume(struct device *device)
+static int mei_me_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
struct mei_device *dev;
@@ -372,24 +333,24 @@ static int mei_pci_resume(struct device *device)
return err;
}
-static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
-#define MEI_PM_OPS (&mei_pm_ops)
+static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
+#define MEI_ME_PM_OPS (&mei_me_pm_ops)
#else
-#define MEI_PM_OPS NULL
+#define MEI_ME_PM_OPS NULL
#endif /* CONFIG_PM */
/*
* PCI driver structure
*/
-static struct pci_driver mei_driver = {
+static struct pci_driver mei_me_driver = {
.name = KBUILD_MODNAME,
- .id_table = mei_pci_tbl,
- .probe = mei_probe,
- .remove = mei_remove,
- .shutdown = mei_remove,
- .driver.pm = MEI_PM_OPS,
+ .id_table = mei_me_pci_tbl,
+ .probe = mei_me_probe,
+ .remove = mei_me_remove,
+ .shutdown = mei_me_remove,
+ .driver.pm = MEI_ME_PM_OPS,
};
-module_pci_driver(mei_driver);
+module_pci_driver(mei_me_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 2413247fc392..6251a4ee7067 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -58,6 +58,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
* mei_wd_host_init - connect to the watchdog client
*
* @dev: the device structure
+ *
* returns -ENENT if wd client cannot be found
* -EIO if write has failed
* 0 on success
@@ -317,7 +318,8 @@ end:
*
* returns 0 if success, negative errno code for failure
*/
-static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
+static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev,
+ unsigned int timeout)
{
struct mei_device *dev;
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
new file mode 100644
index 000000000000..437192e43006
--- /dev/null
+++ b/drivers/misc/sram.c
@@ -0,0 +1,121 @@
+/*
+ * Generic on-chip SRAM allocation driver
+ *
+ * Copyright (C) 2012 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+
+#define SRAM_GRANULARITY 32
+
+struct sram_dev {
+ struct gen_pool *pool;
+ struct clk *clk;
+};
+
+static int sram_probe(struct platform_device *pdev)
+{
+ void __iomem *virt_base;
+ struct sram_dev *sram;
+ struct resource *res;
+ unsigned long size;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ size = resource_size(res);
+
+ virt_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!virt_base)
+ return -EADDRNOTAVAIL;
+
+ sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
+ if (!sram)
+ return -ENOMEM;
+
+ sram->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(sram->clk))
+ sram->clk = NULL;
+ else
+ clk_prepare_enable(sram->clk);
+
+ sram->pool = devm_gen_pool_create(&pdev->dev, ilog2(SRAM_GRANULARITY), -1);
+ if (!sram->pool)
+ return -ENOMEM;
+
+ ret = gen_pool_add_virt(sram->pool, (unsigned long)virt_base,
+ res->start, size, -1);
+ if (ret < 0) {
+ gen_pool_destroy(sram->pool);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, sram);
+
+ dev_dbg(&pdev->dev, "SRAM pool: %ld KiB @ 0x%p\n", size / 1024, virt_base);
+
+ return 0;
+}
+
+static int sram_remove(struct platform_device *pdev)
+{
+ struct sram_dev *sram = platform_get_drvdata(pdev);
+
+ if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
+ dev_dbg(&pdev->dev, "removed while SRAM allocated\n");
+
+ gen_pool_destroy(sram->pool);
+
+ if (sram->clk)
+ clk_disable_unprepare(sram->clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id sram_dt_ids[] = {
+ { .compatible = "mmio-sram" },
+ {}
+};
+#endif
+
+static struct platform_driver sram_driver = {
+ .driver = {
+ .name = "sram",
+ .of_match_table = of_match_ptr(sram_dt_ids),
+ },
+ .probe = sram_probe,
+ .remove = sram_remove,
+};
+
+static int __init sram_init(void)
+{
+ return platform_driver_register(&sram_driver);
+}
+
+postcore_initcall(sram_init);
diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c
index 1e7bc0eb081e..1dfde4d543db 100644
--- a/drivers/misc/tsl2550.c
+++ b/drivers/misc/tsl2550.c
@@ -417,24 +417,26 @@ static int tsl2550_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
+static int tsl2550_suspend(struct device *dev)
{
- return tsl2550_set_power_state(client, 0);
+ return tsl2550_set_power_state(to_i2c_client(dev), 0);
}
-static int tsl2550_resume(struct i2c_client *client)
+static int tsl2550_resume(struct device *dev)
{
- return tsl2550_set_power_state(client, 1);
+ return tsl2550_set_power_state(to_i2c_client(dev), 1);
}
+static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume);
+#define TSL2550_PM_OPS (&tsl2550_pm_ops)
+
#else
-#define tsl2550_suspend NULL
-#define tsl2550_resume NULL
+#define TSL2550_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id tsl2550_id[] = {
{ "tsl2550", 0 },
@@ -446,9 +448,8 @@ static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
.owner = THIS_MODULE,
+ .pm = TSL2550_PM_OPS,
},
- .suspend = tsl2550_suspend,
- .resume = tsl2550_resume,
.probe = tsl2550_probe,
.remove = tsl2550_remove,
.id_table = tsl2550_id,
diff --git a/drivers/misc/vmw_vmci/Kconfig b/drivers/misc/vmw_vmci/Kconfig
index 39c2ecadb273..ea98f7e9ccd1 100644
--- a/drivers/misc/vmw_vmci/Kconfig
+++ b/drivers/misc/vmw_vmci/Kconfig
@@ -4,7 +4,7 @@
config VMWARE_VMCI
tristate "VMware VMCI Driver"
- depends on X86 && PCI
+ depends on X86 && PCI && NET
help
This is VMware's Virtual Machine Communication Interface. It enables
high-speed communication between host and guest in a virtual
diff --git a/drivers/misc/vmw_vmci/vmci_datagram.c b/drivers/misc/vmw_vmci/vmci_datagram.c
index ed5c433cd493..f3cdd904fe4d 100644
--- a/drivers/misc/vmw_vmci/vmci_datagram.c
+++ b/drivers/misc/vmw_vmci/vmci_datagram.c
@@ -42,9 +42,11 @@ struct datagram_entry {
struct delayed_datagram_info {
struct datagram_entry *entry;
- struct vmci_datagram msg;
struct work_struct work;
bool in_dg_host_queue;
+ /* msg and msg_payload must be together. */
+ struct vmci_datagram msg;
+ u8 msg_payload[];
};
/* Number of in-flight host->host datagrams */
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
index c931dfe6a59c..f093cea0d060 100644
--- a/drivers/mmc/card/sdio_uart.c
+++ b/drivers/mmc/card/sdio_uart.c
@@ -134,7 +134,6 @@ static void sdio_uart_port_put(struct sdio_uart_port *port)
static void sdio_uart_port_remove(struct sdio_uart_port *port)
{
struct sdio_func *func;
- struct tty_struct *tty;
BUG_ON(sdio_uart_table[port->index] != port);
@@ -155,12 +154,8 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
sdio_claim_host(func);
port->func = NULL;
mutex_unlock(&port->func_lock);
- tty = tty_port_tty_get(&port->port);
/* tty_hangup is async so is this safe as is ?? */
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&port->port, false);
mutex_unlock(&port->port.mutex);
sdio_release_irq(func);
sdio_disable_func(func);
@@ -492,11 +487,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
wake_up_interruptible(&port->port.open_wait);
else {
/* DCD drop - hang up if tty attached */
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&port->port, false);
}
}
if (status & UART_MSR_DCTS) {
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 08a3cf2a7610..9290bb51a06a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -120,8 +120,8 @@ static void mmc_should_fail_request(struct mmc_host *host,
!should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
return;
- data->error = data_errors[random32() % ARRAY_SIZE(data_errors)];
- data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9;
+ data->error = data_errors[prandom_u32() % ARRAY_SIZE(data_errors)];
+ data->bytes_xfered = (prandom_u32() % (data->bytes_xfered >> 9)) << 9;
}
#else /* CONFIG_FAIL_MMC_REQUEST */
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 7009f17ad6cd..50adbd155f35 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -543,25 +543,7 @@ static struct pcmcia_driver sdricoh_driver = {
.suspend = sdricoh_pcmcia_suspend,
.resume = sdricoh_pcmcia_resume,
};
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdricoh_drv_init(void)
-{
- return pcmcia_register_driver(&sdricoh_driver);
-}
-
-static void __exit sdricoh_drv_exit(void)
-{
- pcmcia_unregister_driver(&sdricoh_driver);
-}
-
-module_init(sdricoh_drv_init);
-module_exit(sdricoh_drv_exit);
+module_pcmcia_driver(sdricoh_driver);
module_param(switchlocked, uint, 0444);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 92ab30ab00dc..dc571ebc1aa0 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1123,33 +1123,6 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file,
}
#endif
-static inline unsigned long get_vm_size(struct vm_area_struct *vma)
-{
- return vma->vm_end - vma->vm_start;
-}
-
-static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
-{
- return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
-}
-
-/*
- * Set a new vm offset.
- *
- * Verify that the incoming offset really works as a page offset,
- * and that the offset and size fit in a resource_size_t.
- */
-static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
-{
- pgoff_t pgoff = off >> PAGE_SHIFT;
- if (off != (resource_size_t) pgoff << PAGE_SHIFT)
- return -EINVAL;
- if (off + get_vm_size(vma) - 1 < off)
- return -EINVAL;
- vma->vm_pgoff = pgoff;
- return 0;
-}
-
/*
* set up a mapping for shared memory segments
*/
@@ -1159,45 +1132,17 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
struct mtd_file_info *mfi = file->private_data;
struct mtd_info *mtd = mfi->mtd;
struct map_info *map = mtd->priv;
- resource_size_t start, off;
- unsigned long len, vma_len;
/* This is broken because it assumes the MTD device is map-based
and that mtd->priv is a valid struct map_info. It should be
replaced with something that uses the mtd_get_unmapped_area()
operation properly. */
if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
- off = get_vm_offset(vma);
- start = map->phys;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
- start &= PAGE_MASK;
- vma_len = get_vm_size(vma);
-
- /* Overflow in off+len? */
- if (vma_len + off < off)
- return -EINVAL;
- /* Does it fit in the mapping? */
- if (vma_len + off > len)
- return -EINVAL;
-
- off += start;
- /* Did that overflow? */
- if (off < start)
- return -EINVAL;
- if (set_vm_offset(vma, off) < 0)
- return -EINVAL;
- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
-
#ifdef pgprot_noncached
- if (file->f_flags & O_DSYNC || off >= __pa(high_memory))
+ if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#endif
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
+ return vm_iomap_memory(vma, map->phys, map->size);
}
return -ENOSYS;
#else
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 87f1d39ca551..3835321b8cf3 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -151,6 +151,7 @@ config MACVTAP
config VXLAN
tristate "Virtual eXtensible Local Area Network (VXLAN)"
depends on INET
+ select NET_IP_TUNNEL
---help---
This allows one to create vxlan virtual interfaces that provide
Layer 2 Networks over Layer 3 Networks. VXLAN is often used
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index f5a89164e779..4ce6ca5f3d36 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -106,20 +106,4 @@ config IPDDP_ENCAP
IP packets inside AppleTalk frames; this is useful if your Linux box
is stuck on an AppleTalk network (which hopefully contains a
decapsulator somewhere). Please see
- <file:Documentation/networking/ipddp.txt> for more information. If
- you said Y to "AppleTalk-IP driver support" above and you say Y
- here, then you cannot say Y to "AppleTalk-IP to IP Decapsulation
- support", below.
-
-config IPDDP_DECAP
- bool "Appletalk-IP to IP Decapsulation support"
- depends on IPDDP
- help
- If you say Y here, the AppleTalk-IP code will be able to decapsulate
- AppleTalk-IP frames to IP packets; this is useful if you want your
- Linux box to act as an Internet gateway for an AppleTalk network.
- Please see <file:Documentation/networking/ipddp.txt> for more
- information. If you said Y to "AppleTalk-IP driver support" above
- and you say Y here, then you cannot say Y to "IP to AppleTalk-IP
- Encapsulation support", above.
-
+ <file:Documentation/networking/ipddp.txt> for more information.
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index 5bed4c4e2508..74dc1875f9cd 100644
--- a/drivers/net/arcnet/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -333,16 +333,4 @@ static struct pcmcia_driver com20020_cs_driver = {
.suspend = com20020_suspend,
.resume = com20020_resume,
};
-
-static int __init init_com20020_cs(void)
-{
- return pcmcia_register_driver(&com20020_cs_driver);
-}
-
-static void __exit exit_com20020_cs(void)
-{
- pcmcia_unregister_driver(&com20020_cs_driver);
-}
-
-module_init(init_com20020_cs);
-module_exit(exit_com20020_cs);
+module_pcmcia_driver(com20020_cs_driver);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index f5e052723029..e02cc265723a 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -514,7 +514,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb->dev = client_info->slave->dev;
if (client_info->tag) {
- skb = vlan_put_tag(skb, client_info->vlan_id);
+ skb = vlan_put_tag(skb, htons(ETH_P_8021Q), client_info->vlan_id);
if (!skb) {
pr_err("%s: Error: failed to insert VLAN tag\n",
client_info->slave->bond->dev->name);
@@ -1014,7 +1014,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
continue;
}
- skb = vlan_put_tag(skb, vlan->vlan_id);
+ skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan->vlan_id);
if (!skb) {
pr_err("%s: Error: failed to insert VLAN tag\n",
bond->dev->name);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6bbd90e1123c..d0aade04e49a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -428,14 +428,15 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
* @bond_dev: bonding net device that got called
* @vid: vlan id being added
*/
-static int bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid)
+static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
+ __be16 proto, u16 vid)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *stop_at;
int i, res;
bond_for_each_slave(bond, slave, i) {
- res = vlan_vid_add(slave->dev, vid);
+ res = vlan_vid_add(slave->dev, proto, vid);
if (res)
goto unwind;
}
@@ -453,7 +454,7 @@ unwind:
/* unwind from head to the slave that failed */
stop_at = slave;
bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at)
- vlan_vid_del(slave->dev, vid);
+ vlan_vid_del(slave->dev, proto, vid);
return res;
}
@@ -463,14 +464,15 @@ unwind:
* @bond_dev: bonding net device that got called
* @vid: vlan id being removed
*/
-static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)
+static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
+ __be16 proto, u16 vid)
{
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave;
int i, res;
bond_for_each_slave(bond, slave, i)
- vlan_vid_del(slave->dev, vid);
+ vlan_vid_del(slave->dev, proto, vid);
res = bond_del_vlan(bond, vid);
if (res) {
@@ -488,7 +490,8 @@ static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *sla
int res;
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
- res = vlan_vid_add(slave_dev, vlan->vlan_id);
+ res = vlan_vid_add(slave_dev, htons(ETH_P_8021Q),
+ vlan->vlan_id);
if (res)
pr_warning("%s: Failed to add vlan id %d to device %s\n",
bond->dev->name, vlan->vlan_id,
@@ -504,7 +507,7 @@ static void bond_del_vlans_from_slave(struct bonding *bond,
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
if (!vlan->vlan_id)
continue;
- vlan_vid_del(slave_dev, vlan->vlan_id);
+ vlan_vid_del(slave_dev, htons(ETH_P_8021Q), vlan->vlan_id);
}
}
@@ -779,7 +782,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
/* rejoin all groups on vlan devices */
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
- vlan_dev = __vlan_find_dev_deep(bond_dev,
+ vlan_dev = __vlan_find_dev_deep(bond_dev, htons(ETH_P_8021Q),
vlan->vlan_id);
if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev);
@@ -796,9 +799,8 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mcast_work.work);
- rcu_read_lock();
+
bond_resend_igmp_join_requests(bond);
- rcu_read_unlock();
}
/*
@@ -846,8 +848,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_ALLMULTI)
dev_set_allmulti(old_active->dev, -1);
+ netif_addr_lock_bh(bond->dev);
netdev_for_each_mc_addr(ha, bond->dev)
dev_mc_del(old_active->dev, ha->addr);
+ netif_addr_unlock_bh(bond->dev);
}
if (new_active) {
@@ -858,8 +862,10 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_ALLMULTI)
dev_set_allmulti(new_active->dev, 1);
+ netif_addr_lock_bh(bond->dev);
netdev_for_each_mc_addr(ha, bond->dev)
dev_mc_add(new_active->dev, ha->addr);
+ netif_addr_unlock_bh(bond->dev);
}
}
@@ -1901,11 +1907,31 @@ err_dest_symlinks:
bond_destroy_slave_symlinks(bond_dev, slave_dev);
err_detach:
+ if (!USES_PRIMARY(bond->params.mode)) {
+ netif_addr_lock_bh(bond_dev);
+ bond_mc_list_flush(bond_dev, slave_dev);
+ netif_addr_unlock_bh(bond_dev);
+ }
+ bond_del_vlans_from_slave(bond, slave_dev);
write_lock_bh(&bond->lock);
bond_detach_slave(bond, new_slave);
- write_unlock_bh(&bond->lock);
+ if (bond->primary_slave == new_slave)
+ bond->primary_slave = NULL;
+ if (bond->curr_active_slave == new_slave) {
+ bond_change_active_slave(bond, NULL);
+ write_unlock_bh(&bond->lock);
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
+ bond_select_active_slave(bond);
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
+ } else {
+ write_unlock_bh(&bond->lock);
+ }
+ slave_disable_netpoll(new_slave);
err_close:
+ slave_dev->priv_flags &= ~IFF_BONDING;
dev_close(slave_dev);
err_unset_master:
@@ -1976,12 +2002,11 @@ static int __bond_release_one(struct net_device *bond_dev,
return -EINVAL;
}
+ write_unlock_bh(&bond->lock);
/* unregister rx_handler early so bond_handle_frame wouldn't be called
* for this slave anymore.
*/
netdev_rx_handler_unregister(slave_dev);
- write_unlock_bh(&bond->lock);
- synchronize_net();
write_lock_bh(&bond->lock);
if (!all && !bond->params.fail_over_mac) {
@@ -2511,7 +2536,8 @@ static int bond_has_this_ip(struct bonding *bond, __be32 ip)
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
rcu_read_lock();
- vlan_dev = __vlan_find_dev_deep(bond->dev, vlan->vlan_id);
+ vlan_dev = __vlan_find_dev_deep(bond->dev, htons(ETH_P_8021Q),
+ vlan->vlan_id);
rcu_read_unlock();
if (vlan_dev && ip == bond_confirm_addr(vlan_dev, 0, ip))
return 1;
@@ -2540,7 +2566,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
return;
}
if (vlan_id) {
- skb = vlan_put_tag(skb, vlan_id);
+ skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (!skb) {
pr_err("failed to insert VLAN tag\n");
return;
@@ -2602,6 +2628,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
rcu_read_lock();
vlan_dev = __vlan_find_dev_deep(bond->dev,
+ htons(ETH_P_8021Q),
vlan->vlan_id);
rcu_read_unlock();
if (vlan_dev == rt->dst.dev) {
@@ -3169,11 +3196,20 @@ static int bond_slave_netdev_event(unsigned long event,
struct net_device *slave_dev)
{
struct slave *slave = bond_slave_get_rtnl(slave_dev);
- struct bonding *bond = slave->bond;
- struct net_device *bond_dev = slave->bond->dev;
+ struct bonding *bond;
+ struct net_device *bond_dev;
u32 old_speed;
u8 old_duplex;
+ /* A netdev event can be generated while enslaving a device
+ * before netdev_rx_handler_register is called in which case
+ * slave will be NULL
+ */
+ if (!slave)
+ return NOTIFY_DONE;
+ bond_dev = slave->bond->dev;
+ bond = slave->bond;
+
switch (event) {
case NETDEV_UNREGISTER:
if (bond->setup_by_slave)
@@ -3287,20 +3323,22 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
*/
static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
{
- struct ethhdr *data = (struct ethhdr *)skb->data;
- struct iphdr *iph;
- struct ipv6hdr *ipv6h;
+ const struct ethhdr *data;
+ const struct iphdr *iph;
+ const struct ipv6hdr *ipv6h;
u32 v6hash;
- __be32 *s, *d;
+ const __be32 *s, *d;
if (skb->protocol == htons(ETH_P_IP) &&
- skb_network_header_len(skb) >= sizeof(*iph)) {
+ pskb_network_may_pull(skb, sizeof(*iph))) {
iph = ip_hdr(skb);
+ data = (struct ethhdr *)skb->data;
return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
(data->h_dest[5] ^ data->h_source[5])) % count;
} else if (skb->protocol == htons(ETH_P_IPV6) &&
- skb_network_header_len(skb) >= sizeof(*ipv6h)) {
+ pskb_network_may_pull(skb, sizeof(*ipv6h))) {
ipv6h = ipv6_hdr(skb);
+ data = (struct ethhdr *)skb->data;
s = &ipv6h->saddr.s6_addr32[0];
d = &ipv6h->daddr.s6_addr32[0];
v6hash = (s[1] ^ d[1]) ^ (s[2] ^ d[2]) ^ (s[3] ^ d[3]);
@@ -3319,33 +3357,36 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb, int count)
static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
{
u32 layer4_xor = 0;
- struct iphdr *iph;
- struct ipv6hdr *ipv6h;
- __be32 *s, *d;
- __be16 *layer4hdr;
+ const struct iphdr *iph;
+ const struct ipv6hdr *ipv6h;
+ const __be32 *s, *d;
+ const __be16 *l4 = NULL;
+ __be16 _l4[2];
+ int noff = skb_network_offset(skb);
+ int poff;
if (skb->protocol == htons(ETH_P_IP) &&
- skb_network_header_len(skb) >= sizeof(*iph)) {
+ pskb_may_pull(skb, noff + sizeof(*iph))) {
iph = ip_hdr(skb);
- if (!ip_is_fragment(iph) &&
- (iph->protocol == IPPROTO_TCP ||
- iph->protocol == IPPROTO_UDP) &&
- (skb_headlen(skb) - skb_network_offset(skb) >=
- iph->ihl * sizeof(u32) + sizeof(*layer4hdr) * 2)) {
- layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
- layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1));
+ poff = proto_ports_offset(iph->protocol);
+
+ if (!ip_is_fragment(iph) && poff >= 0) {
+ l4 = skb_header_pointer(skb, noff + (iph->ihl << 2) + poff,
+ sizeof(_l4), &_l4);
+ if (l4)
+ layer4_xor = ntohs(l4[0] ^ l4[1]);
}
return (layer4_xor ^
((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
} else if (skb->protocol == htons(ETH_P_IPV6) &&
- skb_network_header_len(skb) >= sizeof(*ipv6h)) {
+ pskb_may_pull(skb, noff + sizeof(*ipv6h))) {
ipv6h = ipv6_hdr(skb);
- if ((ipv6h->nexthdr == IPPROTO_TCP ||
- ipv6h->nexthdr == IPPROTO_UDP) &&
- (skb_headlen(skb) - skb_network_offset(skb) >=
- sizeof(*ipv6h) + sizeof(*layer4hdr) * 2)) {
- layer4hdr = (__be16 *)(ipv6h + 1);
- layer4_xor = ntohs(*layer4hdr ^ *(layer4hdr + 1));
+ poff = proto_ports_offset(ipv6h->nexthdr);
+ if (poff >= 0) {
+ l4 = skb_header_pointer(skb, noff + sizeof(*ipv6h) + poff,
+ sizeof(_l4), &_l4);
+ if (l4)
+ layer4_xor = ntohs(l4[0] ^ l4[1]);
}
s = &ipv6h->saddr.s6_addr32[0];
d = &ipv6h->daddr.s6_addr32[0];
@@ -4223,6 +4264,37 @@ void bond_set_mode_ops(struct bonding *bond, int mode)
}
}
+static int bond_ethtool_get_settings(struct net_device *bond_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i;
+ unsigned long speed = 0;
+
+ ecmd->duplex = DUPLEX_UNKNOWN;
+ ecmd->port = PORT_OTHER;
+
+ /* Since SLAVE_IS_OK returns false for all inactive or down slaves, we
+ * do not need to check mode. Though link speed might not represent
+ * the true receive or transmit bandwidth (not all modes are symmetric)
+ * this is an accurate maximum.
+ */
+ read_lock(&bond->lock);
+ bond_for_each_slave(bond, slave, i) {
+ if (SLAVE_IS_OK(slave)) {
+ if (slave->speed != SPEED_UNKNOWN)
+ speed += slave->speed;
+ if (ecmd->duplex == DUPLEX_UNKNOWN &&
+ slave->duplex != DUPLEX_UNKNOWN)
+ ecmd->duplex = slave->duplex;
+ }
+ }
+ ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
+ read_unlock(&bond->lock);
+ return 0;
+}
+
static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
struct ethtool_drvinfo *drvinfo)
{
@@ -4234,6 +4306,7 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
static const struct ethtool_ops bond_ethtool_ops = {
.get_drvinfo = bond_ethtool_get_drvinfo,
+ .get_settings = bond_ethtool_get_settings,
.get_link = ethtool_op_get_link,
};
@@ -4324,9 +4397,9 @@ static void bond_setup(struct net_device *bond_dev)
*/
bond_dev->hw_features = BOND_VLAN_FEATURES |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
bond_dev->features |= bond_dev->hw_features;
@@ -4847,9 +4920,18 @@ static int __net_init bond_net_init(struct net *net)
static void __net_exit bond_net_exit(struct net *net)
{
struct bond_net *bn = net_generic(net, bond_net_id);
+ struct bonding *bond, *tmp_bond;
+ LIST_HEAD(list);
bond_destroy_sysfs(bn);
bond_destroy_proc_dir(bn);
+
+ /* Kill off any bonds created after unregistering bond rtnl ops */
+ rtnl_lock();
+ list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list)
+ unregister_netdevice_queue(bond->dev, &list);
+ unregister_netdevice_many(&list);
+ rtnl_unlock();
}
static struct pernet_operations bond_net_ops = {
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index db103e03ba05..ea7a388f4843 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -527,7 +527,7 @@ static ssize_t bonding_store_arp_interval(struct device *d,
goto out;
}
if (new_value < 0) {
- pr_err("%s: Invalid arp_interval value %d not in range 1-%d; rejected.\n",
+ pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n",
bond->dev->name, new_value, INT_MAX);
ret = -EINVAL;
goto out;
@@ -542,14 +542,15 @@ static ssize_t bonding_store_arp_interval(struct device *d,
pr_info("%s: Setting ARP monitoring interval to %d.\n",
bond->dev->name, new_value);
bond->params.arp_interval = new_value;
- if (bond->params.miimon) {
- pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
- bond->dev->name, bond->dev->name);
- bond->params.miimon = 0;
- }
- if (!bond->params.arp_targets[0]) {
- pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
- bond->dev->name);
+ if (new_value) {
+ if (bond->params.miimon) {
+ pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
+ bond->dev->name, bond->dev->name);
+ bond->params.miimon = 0;
+ }
+ if (!bond->params.arp_targets[0])
+ pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
+ bond->dev->name);
}
if (bond->dev->flags & IFF_UP) {
/* If the interface is up, we may need to fire off
@@ -557,10 +558,13 @@ static ssize_t bonding_store_arp_interval(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- cancel_delayed_work_sync(&bond->mii_work);
- queue_delayed_work(bond->wq, &bond->arp_work, 0);
+ if (!new_value) {
+ cancel_delayed_work_sync(&bond->arp_work);
+ } else {
+ cancel_delayed_work_sync(&bond->mii_work);
+ queue_delayed_work(bond->wq, &bond->arp_work, 0);
+ }
}
-
out:
rtnl_unlock();
return ret;
@@ -702,7 +706,7 @@ static ssize_t bonding_store_downdelay(struct device *d,
}
if (new_value < 0) {
pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
- bond->dev->name, new_value, 1, INT_MAX);
+ bond->dev->name, new_value, 0, INT_MAX);
ret = -EINVAL;
goto out;
} else {
@@ -757,8 +761,8 @@ static ssize_t bonding_store_updelay(struct device *d,
goto out;
}
if (new_value < 0) {
- pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
- bond->dev->name, new_value, 1, INT_MAX);
+ pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n",
+ bond->dev->name, new_value, 0, INT_MAX);
ret = -EINVAL;
goto out;
} else {
@@ -968,37 +972,37 @@ static ssize_t bonding_store_miimon(struct device *d,
}
if (new_value < 0) {
pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n",
- bond->dev->name, new_value, 1, INT_MAX);
+ bond->dev->name, new_value, 0, INT_MAX);
ret = -EINVAL;
goto out;
- } else {
- pr_info("%s: Setting MII monitoring interval to %d.\n",
- bond->dev->name, new_value);
- bond->params.miimon = new_value;
- if (bond->params.updelay)
- pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
- bond->dev->name,
- bond->params.updelay * bond->params.miimon);
- if (bond->params.downdelay)
- pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
- bond->dev->name,
- bond->params.downdelay * bond->params.miimon);
- if (bond->params.arp_interval) {
- pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
- bond->dev->name);
- bond->params.arp_interval = 0;
- if (bond->params.arp_validate) {
- bond->params.arp_validate =
- BOND_ARP_VALIDATE_NONE;
- }
- }
-
- if (bond->dev->flags & IFF_UP) {
- /* If the interface is up, we may need to fire off
- * the MII timer. If the interface is down, the
- * timer will get fired off when the open function
- * is called.
- */
+ }
+ pr_info("%s: Setting MII monitoring interval to %d.\n",
+ bond->dev->name, new_value);
+ bond->params.miimon = new_value;
+ if (bond->params.updelay)
+ pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
+ bond->dev->name,
+ bond->params.updelay * bond->params.miimon);
+ if (bond->params.downdelay)
+ pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
+ bond->dev->name,
+ bond->params.downdelay * bond->params.miimon);
+ if (new_value && bond->params.arp_interval) {
+ pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
+ bond->dev->name);
+ bond->params.arp_interval = 0;
+ if (bond->params.arp_validate)
+ bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
+ }
+ if (bond->dev->flags & IFF_UP) {
+ /* If the interface is up, we may need to fire off
+ * the MII timer. If the interface is down, the
+ * timer will get fired off when the open function
+ * is called.
+ */
+ if (!new_value) {
+ cancel_delayed_work_sync(&bond->mii_work);
+ } else {
cancel_delayed_work_sync(&bond->arp_work);
queue_delayed_work(bond->wq, &bond->mii_work, 0);
}
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 60c2142373c9..a966128c2a7a 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -32,13 +32,6 @@ config CAIF_SPI_SYNC
help to synchronize to the next transfer in case of over or under-runs.
This option also needs to be enabled on the modem.
-config CAIF_SHM
- tristate "CAIF shared memory protocol driver"
- depends on CAIF && U5500_MBOX
- default n
- ---help---
- The CAIF shared memory protocol driver for the STE UX5500 platform.
-
config CAIF_HSI
tristate "CAIF HSI transport driver"
depends on CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 91dff861560f..15a9d2fc753d 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -7,9 +7,5 @@ obj-$(CONFIG_CAIF_TTY) += caif_serial.o
cfspi_slave-objs := caif_spi.o caif_spi_slave.o
obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
-# Shared memory
-caif_shm-objs := caif_shmcore.o caif_shm_u5500.o
-obj-$(CONFIG_CAIF_SHM) += caif_shm.o
-
# HSI interface
obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 0def8b3106f4..5e40a8b68cbe 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -1,8 +1,7 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Author: Daniel Martensson / daniel.martensson@stericsson.com
- * Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com
+ * Author: Daniel Martensson
+ * Dmitry.Tarnyagin / dmitry.tarnyagin@lockless.no
* License terms: GNU General Public License (GPL) version 2.
*/
@@ -25,7 +24,7 @@
#include <net/caif/caif_hsi.h>
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_AUTHOR("Daniel Martensson");
MODULE_DESCRIPTION("CAIF HSI driver");
/* Returns the number of padding bytes for alignment. */
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 666891a9a248..77be3cb0b5fe 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -21,7 +21,7 @@
#include <linux/debugfs.h>
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Sjur Brendeland<sjur.brandeland@stericsson.com>");
+MODULE_AUTHOR("Sjur Brendeland");
MODULE_DESCRIPTION("CAIF serial device TTY line discipline");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_CAIF);
@@ -88,11 +88,9 @@ static inline void update_tty_status(struct ser_device *ser)
{
ser->tty_status =
ser->tty->stopped << 5 |
- ser->tty->hw_stopped << 4 |
ser->tty->flow_stopped << 3 |
ser->tty->packet << 2 |
- ser->tty->port->low_latency << 1 |
- ser->tty->warned;
+ ser->tty->port->low_latency << 1;
}
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
{
diff --git a/drivers/net/caif/caif_shm_u5500.c b/drivers/net/caif/caif_shm_u5500.c
deleted file mode 100644
index 89d76b7b325a..000000000000
--- a/drivers/net/caif/caif_shm_u5500.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Author: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <mach/mbox-db5500.h>
-#include <net/caif/caif_shm.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("CAIF Shared Memory protocol driver");
-
-#define MAX_SHM_INSTANCES 1
-
-enum {
- MBX_ACC0,
- MBX_ACC1,
- MBX_DSP
-};
-
-static struct shmdev_layer shmdev_lyr[MAX_SHM_INSTANCES];
-
-static unsigned int shm_start;
-static unsigned int shm_size;
-
-module_param(shm_size, uint , 0440);
-MODULE_PARM_DESC(shm_total_size, "Start of SHM shared memory");
-
-module_param(shm_start, uint , 0440);
-MODULE_PARM_DESC(shm_total_start, "Total Size of SHM shared memory");
-
-static int shmdev_send_msg(u32 dev_id, u32 mbx_msg)
-{
- /* Always block until msg is written successfully */
- mbox_send(shmdev_lyr[dev_id].hmbx, mbx_msg, true);
- return 0;
-}
-
-static int shmdev_mbx_setup(void *pshmdrv_cb, struct shmdev_layer *pshm_dev,
- void *pshm_drv)
-{
- /*
- * For UX5500, we have only 1 SHM instance which uses MBX0
- * for communication with the peer modem
- */
- pshm_dev->hmbx = mbox_setup(MBX_ACC0, pshmdrv_cb, pshm_drv);
-
- if (!pshm_dev->hmbx)
- return -ENODEV;
- else
- return 0;
-}
-
-static int __init caif_shmdev_init(void)
-{
- int i, result;
-
- /* Loop is currently overkill, there is only one instance */
- for (i = 0; i < MAX_SHM_INSTANCES; i++) {
-
- shmdev_lyr[i].shm_base_addr = shm_start;
- shmdev_lyr[i].shm_total_sz = shm_size;
-
- if (((char *)shmdev_lyr[i].shm_base_addr == NULL)
- || (shmdev_lyr[i].shm_total_sz <= 0)) {
- pr_warn("ERROR,"
- "Shared memory Address and/or Size incorrect"
- ", Bailing out ...\n");
- result = -EINVAL;
- goto clean;
- }
-
- pr_info("SHM AREA (instance %d) STARTS"
- " AT %p\n", i, (char *)shmdev_lyr[i].shm_base_addr);
-
- shmdev_lyr[i].shm_id = i;
- shmdev_lyr[i].pshmdev_mbxsend = shmdev_send_msg;
- shmdev_lyr[i].pshmdev_mbxsetup = shmdev_mbx_setup;
-
- /*
- * Finally, CAIF core module is called with details in place:
- * 1. SHM base address
- * 2. SHM size
- * 3. MBX handle
- */
- result = caif_shmcore_probe(&shmdev_lyr[i]);
- if (result) {
- pr_warn("ERROR[%d],"
- "Could not probe SHM core (instance %d)"
- " Bailing out ...\n", result, i);
- goto clean;
- }
- }
-
- return 0;
-
-clean:
- /*
- * For now, we assume that even if one instance of SHM fails, we bail
- * out of the driver support completely. For this, we need to release
- * any memory allocated and unregister any instance of SHM net device.
- */
- for (i = 0; i < MAX_SHM_INSTANCES; i++) {
- if (shmdev_lyr[i].pshm_netdev)
- unregister_netdev(shmdev_lyr[i].pshm_netdev);
- }
- return result;
-}
-
-static void __exit caif_shmdev_exit(void)
-{
- int i;
-
- for (i = 0; i < MAX_SHM_INSTANCES; i++) {
- caif_shmcore_remove(shmdev_lyr[i].pshm_netdev);
- kfree((void *)shmdev_lyr[i].shm_base_addr);
- }
-
-}
-
-module_init(caif_shmdev_init);
-module_exit(caif_shmdev_exit);
diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c
deleted file mode 100644
index bce8bac311c9..000000000000
--- a/drivers/net/caif/caif_shmcore.c
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Authors: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com,
- * Daniel Martensson / daniel.martensson@stericsson.com
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/io.h>
-
-#include <net/caif/caif_device.h>
-#include <net/caif/caif_shm.h>
-
-#define NR_TX_BUF 6
-#define NR_RX_BUF 6
-#define TX_BUF_SZ 0x2000
-#define RX_BUF_SZ 0x2000
-
-#define CAIF_NEEDED_HEADROOM 32
-
-#define CAIF_FLOW_ON 1
-#define CAIF_FLOW_OFF 0
-
-#define LOW_WATERMARK 3
-#define HIGH_WATERMARK 4
-
-/* Maximum number of CAIF buffers per shared memory buffer. */
-#define SHM_MAX_FRMS_PER_BUF 10
-
-/*
- * Size in bytes of the descriptor area
- * (With end of descriptor signalling)
- */
-#define SHM_CAIF_DESC_SIZE ((SHM_MAX_FRMS_PER_BUF + 1) * \
- sizeof(struct shm_pck_desc))
-
-/*
- * Offset to the first CAIF frame within a shared memory buffer.
- * Aligned on 32 bytes.
- */
-#define SHM_CAIF_FRM_OFS (SHM_CAIF_DESC_SIZE + (SHM_CAIF_DESC_SIZE % 32))
-
-/* Number of bytes for CAIF shared memory header. */
-#define SHM_HDR_LEN 1
-
-/* Number of padding bytes for the complete CAIF frame. */
-#define SHM_FRM_PAD_LEN 4
-
-#define CAIF_MAX_MTU 4096
-
-#define SHM_SET_FULL(x) (((x+1) & 0x0F) << 0)
-#define SHM_GET_FULL(x) (((x >> 0) & 0x0F) - 1)
-
-#define SHM_SET_EMPTY(x) (((x+1) & 0x0F) << 4)
-#define SHM_GET_EMPTY(x) (((x >> 4) & 0x0F) - 1)
-
-#define SHM_FULL_MASK (0x0F << 0)
-#define SHM_EMPTY_MASK (0x0F << 4)
-
-struct shm_pck_desc {
- /*
- * Offset from start of shared memory area to start of
- * shared memory CAIF frame.
- */
- u32 frm_ofs;
- u32 frm_len;
-};
-
-struct buf_list {
- unsigned char *desc_vptr;
- u32 phy_addr;
- u32 index;
- u32 len;
- u32 frames;
- u32 frm_ofs;
- struct list_head list;
-};
-
-struct shm_caif_frm {
- /* Number of bytes of padding before the CAIF frame. */
- u8 hdr_ofs;
-};
-
-struct shmdrv_layer {
- /* caif_dev_common must always be first in the structure*/
- struct caif_dev_common cfdev;
-
- u32 shm_tx_addr;
- u32 shm_rx_addr;
- u32 shm_base_addr;
- u32 tx_empty_available;
- spinlock_t lock;
-
- struct list_head tx_empty_list;
- struct list_head tx_pend_list;
- struct list_head tx_full_list;
- struct list_head rx_empty_list;
- struct list_head rx_pend_list;
- struct list_head rx_full_list;
-
- struct workqueue_struct *pshm_tx_workqueue;
- struct workqueue_struct *pshm_rx_workqueue;
-
- struct work_struct shm_tx_work;
- struct work_struct shm_rx_work;
-
- struct sk_buff_head sk_qhead;
- struct shmdev_layer *pshm_dev;
-};
-
-static int shm_netdev_open(struct net_device *shm_netdev)
-{
- netif_wake_queue(shm_netdev);
- return 0;
-}
-
-static int shm_netdev_close(struct net_device *shm_netdev)
-{
- netif_stop_queue(shm_netdev);
- return 0;
-}
-
-int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv)
-{
- struct buf_list *pbuf;
- struct shmdrv_layer *pshm_drv;
- struct list_head *pos;
- u32 avail_emptybuff = 0;
- unsigned long flags = 0;
-
- pshm_drv = priv;
-
- /* Check for received buffers. */
- if (mbx_msg & SHM_FULL_MASK) {
- int idx;
-
- spin_lock_irqsave(&pshm_drv->lock, flags);
-
- /* Check whether we have any outstanding buffers. */
- if (list_empty(&pshm_drv->rx_empty_list)) {
-
- /* Release spin lock. */
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* We print even in IRQ context... */
- pr_warn("No empty Rx buffers to fill: "
- "mbx_msg:%x\n", mbx_msg);
-
- /* Bail out. */
- goto err_sync;
- }
-
- pbuf =
- list_entry(pshm_drv->rx_empty_list.next,
- struct buf_list, list);
- idx = pbuf->index;
-
- /* Check buffer synchronization. */
- if (idx != SHM_GET_FULL(mbx_msg)) {
-
- /* We print even in IRQ context... */
- pr_warn(
- "phyif_shm_mbx_msg_cb: RX full out of sync:"
- " idx:%d, msg:%x SHM_GET_FULL(mbx_msg):%x\n",
- idx, mbx_msg, SHM_GET_FULL(mbx_msg));
-
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* Bail out. */
- goto err_sync;
- }
-
- list_del_init(&pbuf->list);
- list_add_tail(&pbuf->list, &pshm_drv->rx_full_list);
-
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* Schedule RX work queue. */
- if (!work_pending(&pshm_drv->shm_rx_work))
- queue_work(pshm_drv->pshm_rx_workqueue,
- &pshm_drv->shm_rx_work);
- }
-
- /* Check for emptied buffers. */
- if (mbx_msg & SHM_EMPTY_MASK) {
- int idx;
-
- spin_lock_irqsave(&pshm_drv->lock, flags);
-
- /* Check whether we have any outstanding buffers. */
- if (list_empty(&pshm_drv->tx_full_list)) {
-
- /* We print even in IRQ context... */
- pr_warn("No TX to empty: msg:%x\n", mbx_msg);
-
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* Bail out. */
- goto err_sync;
- }
-
- pbuf =
- list_entry(pshm_drv->tx_full_list.next,
- struct buf_list, list);
- idx = pbuf->index;
-
- /* Check buffer synchronization. */
- if (idx != SHM_GET_EMPTY(mbx_msg)) {
-
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* We print even in IRQ context... */
- pr_warn("TX empty "
- "out of sync:idx:%d, msg:%x\n", idx, mbx_msg);
-
- /* Bail out. */
- goto err_sync;
- }
- list_del_init(&pbuf->list);
-
- /* Reset buffer parameters. */
- pbuf->frames = 0;
- pbuf->frm_ofs = SHM_CAIF_FRM_OFS;
-
- list_add_tail(&pbuf->list, &pshm_drv->tx_empty_list);
-
- /* Check the available no. of buffers in the empty list */
- list_for_each(pos, &pshm_drv->tx_empty_list)
- avail_emptybuff++;
-
- /* Check whether we have to wake up the transmitter. */
- if ((avail_emptybuff > HIGH_WATERMARK) &&
- (!pshm_drv->tx_empty_available)) {
- pshm_drv->tx_empty_available = 1;
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
- pshm_drv->cfdev.flowctrl
- (pshm_drv->pshm_dev->pshm_netdev,
- CAIF_FLOW_ON);
-
-
- /* Schedule the work queue. if required */
- if (!work_pending(&pshm_drv->shm_tx_work))
- queue_work(pshm_drv->pshm_tx_workqueue,
- &pshm_drv->shm_tx_work);
- } else
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
- }
-
- return 0;
-
-err_sync:
- return -EIO;
-}
-
-static void shm_rx_work_func(struct work_struct *rx_work)
-{
- struct shmdrv_layer *pshm_drv;
- struct buf_list *pbuf;
- unsigned long flags = 0;
- struct sk_buff *skb;
- char *p;
- int ret;
-
- pshm_drv = container_of(rx_work, struct shmdrv_layer, shm_rx_work);
-
- while (1) {
-
- struct shm_pck_desc *pck_desc;
-
- spin_lock_irqsave(&pshm_drv->lock, flags);
-
- /* Check for received buffers. */
- if (list_empty(&pshm_drv->rx_full_list)) {
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
- break;
- }
-
- pbuf =
- list_entry(pshm_drv->rx_full_list.next, struct buf_list,
- list);
- list_del_init(&pbuf->list);
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- /* Retrieve pointer to start of the packet descriptor area. */
- pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr;
-
- /*
- * Check whether descriptor contains a CAIF shared memory
- * frame.
- */
- while (pck_desc->frm_ofs) {
- unsigned int frm_buf_ofs;
- unsigned int frm_pck_ofs;
- unsigned int frm_pck_len;
- /*
- * Check whether offset is within buffer limits
- * (lower).
- */
- if (pck_desc->frm_ofs <
- (pbuf->phy_addr - pshm_drv->shm_base_addr))
- break;
- /*
- * Check whether offset is within buffer limits
- * (higher).
- */
- if (pck_desc->frm_ofs >
- ((pbuf->phy_addr - pshm_drv->shm_base_addr) +
- pbuf->len))
- break;
-
- /* Calculate offset from start of buffer. */
- frm_buf_ofs =
- pck_desc->frm_ofs - (pbuf->phy_addr -
- pshm_drv->shm_base_addr);
-
- /*
- * Calculate offset and length of CAIF packet while
- * taking care of the shared memory header.
- */
- frm_pck_ofs =
- frm_buf_ofs + SHM_HDR_LEN +
- (*(pbuf->desc_vptr + frm_buf_ofs));
- frm_pck_len =
- (pck_desc->frm_len - SHM_HDR_LEN -
- (*(pbuf->desc_vptr + frm_buf_ofs)));
-
- /* Check whether CAIF packet is within buffer limits */
- if ((frm_pck_ofs + pck_desc->frm_len) > pbuf->len)
- break;
-
- /* Get a suitable CAIF packet and copy in data. */
- skb = netdev_alloc_skb(pshm_drv->pshm_dev->pshm_netdev,
- frm_pck_len + 1);
-
- if (skb == NULL) {
- pr_info("OOM: Try next frame in descriptor\n");
- break;
- }
-
- p = skb_put(skb, frm_pck_len);
- memcpy(p, pbuf->desc_vptr + frm_pck_ofs, frm_pck_len);
-
- skb->protocol = htons(ETH_P_CAIF);
- skb_reset_mac_header(skb);
- skb->dev = pshm_drv->pshm_dev->pshm_netdev;
-
- /* Push received packet up the stack. */
- ret = netif_rx_ni(skb);
-
- if (!ret) {
- pshm_drv->pshm_dev->pshm_netdev->stats.
- rx_packets++;
- pshm_drv->pshm_dev->pshm_netdev->stats.
- rx_bytes += pck_desc->frm_len;
- } else
- ++pshm_drv->pshm_dev->pshm_netdev->stats.
- rx_dropped;
- /* Move to next packet descriptor. */
- pck_desc++;
- }
-
- spin_lock_irqsave(&pshm_drv->lock, flags);
- list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list);
-
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- }
-
- /* Schedule the work queue. if required */
- if (!work_pending(&pshm_drv->shm_tx_work))
- queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work);
-
-}
-
-static void shm_tx_work_func(struct work_struct *tx_work)
-{
- u32 mbox_msg;
- unsigned int frmlen, avail_emptybuff, append = 0;
- unsigned long flags = 0;
- struct buf_list *pbuf = NULL;
- struct shmdrv_layer *pshm_drv;
- struct shm_caif_frm *frm;
- struct sk_buff *skb;
- struct shm_pck_desc *pck_desc;
- struct list_head *pos;
-
- pshm_drv = container_of(tx_work, struct shmdrv_layer, shm_tx_work);
-
- do {
- /* Initialize mailbox message. */
- mbox_msg = 0x00;
- avail_emptybuff = 0;
-
- spin_lock_irqsave(&pshm_drv->lock, flags);
-
- /* Check for pending receive buffers. */
- if (!list_empty(&pshm_drv->rx_pend_list)) {
-
- pbuf = list_entry(pshm_drv->rx_pend_list.next,
- struct buf_list, list);
-
- list_del_init(&pbuf->list);
- list_add_tail(&pbuf->list, &pshm_drv->rx_empty_list);
- /*
- * Value index is never changed,
- * so read access should be safe.
- */
- mbox_msg |= SHM_SET_EMPTY(pbuf->index);
- }
-
- skb = skb_peek(&pshm_drv->sk_qhead);
-
- if (skb == NULL)
- goto send_msg;
- /* Check the available no. of buffers in the empty list */
- list_for_each(pos, &pshm_drv->tx_empty_list)
- avail_emptybuff++;
-
- if ((avail_emptybuff < LOW_WATERMARK) &&
- pshm_drv->tx_empty_available) {
- /* Update blocking condition. */
- pshm_drv->tx_empty_available = 0;
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
- pshm_drv->cfdev.flowctrl
- (pshm_drv->pshm_dev->pshm_netdev,
- CAIF_FLOW_OFF);
- spin_lock_irqsave(&pshm_drv->lock, flags);
- }
- /*
- * We simply return back to the caller if we do not have space
- * either in Tx pending list or Tx empty list. In this case,
- * we hold the received skb in the skb list, waiting to
- * be transmitted once Tx buffers become available
- */
- if (list_empty(&pshm_drv->tx_empty_list))
- goto send_msg;
-
- /* Get the first free Tx buffer. */
- pbuf = list_entry(pshm_drv->tx_empty_list.next,
- struct buf_list, list);
- do {
- if (append) {
- skb = skb_peek(&pshm_drv->sk_qhead);
- if (skb == NULL)
- break;
- }
-
- frm = (struct shm_caif_frm *)
- (pbuf->desc_vptr + pbuf->frm_ofs);
-
- frm->hdr_ofs = 0;
- frmlen = 0;
- frmlen += SHM_HDR_LEN + frm->hdr_ofs + skb->len;
-
- /* Add tail padding if needed. */
- if (frmlen % SHM_FRM_PAD_LEN)
- frmlen += SHM_FRM_PAD_LEN -
- (frmlen % SHM_FRM_PAD_LEN);
-
- /*
- * Verify that packet, header and additional padding
- * can fit within the buffer frame area.
- */
- if (frmlen >= (pbuf->len - pbuf->frm_ofs))
- break;
-
- if (!append) {
- list_del_init(&pbuf->list);
- append = 1;
- }
-
- skb = skb_dequeue(&pshm_drv->sk_qhead);
- if (skb == NULL)
- break;
- /* Copy in CAIF frame. */
- skb_copy_bits(skb, 0, pbuf->desc_vptr +
- pbuf->frm_ofs + SHM_HDR_LEN +
- frm->hdr_ofs, skb->len);
-
- pshm_drv->pshm_dev->pshm_netdev->stats.tx_packets++;
- pshm_drv->pshm_dev->pshm_netdev->stats.tx_bytes +=
- frmlen;
- dev_kfree_skb_irq(skb);
-
- /* Fill in the shared memory packet descriptor area. */
- pck_desc = (struct shm_pck_desc *) (pbuf->desc_vptr);
- /* Forward to current frame. */
- pck_desc += pbuf->frames;
- pck_desc->frm_ofs = (pbuf->phy_addr -
- pshm_drv->shm_base_addr) +
- pbuf->frm_ofs;
- pck_desc->frm_len = frmlen;
- /* Terminate packet descriptor area. */
- pck_desc++;
- pck_desc->frm_ofs = 0;
- /* Update buffer parameters. */
- pbuf->frames++;
- pbuf->frm_ofs += frmlen + (frmlen % 32);
-
- } while (pbuf->frames < SHM_MAX_FRMS_PER_BUF);
-
- /* Assign buffer as full. */
- list_add_tail(&pbuf->list, &pshm_drv->tx_full_list);
- append = 0;
- mbox_msg |= SHM_SET_FULL(pbuf->index);
-send_msg:
- spin_unlock_irqrestore(&pshm_drv->lock, flags);
-
- if (mbox_msg)
- pshm_drv->pshm_dev->pshmdev_mbxsend
- (pshm_drv->pshm_dev->shm_id, mbox_msg);
- } while (mbox_msg);
-}
-
-static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev)
-{
- struct shmdrv_layer *pshm_drv;
-
- pshm_drv = netdev_priv(shm_netdev);
-
- skb_queue_tail(&pshm_drv->sk_qhead, skb);
-
- /* Schedule Tx work queue. for deferred processing of skbs*/
- if (!work_pending(&pshm_drv->shm_tx_work))
- queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work);
-
- return 0;
-}
-
-static const struct net_device_ops netdev_ops = {
- .ndo_open = shm_netdev_open,
- .ndo_stop = shm_netdev_close,
- .ndo_start_xmit = shm_netdev_tx,
-};
-
-static void shm_netdev_setup(struct net_device *pshm_netdev)
-{
- struct shmdrv_layer *pshm_drv;
- pshm_netdev->netdev_ops = &netdev_ops;
-
- pshm_netdev->mtu = CAIF_MAX_MTU;
- pshm_netdev->type = ARPHRD_CAIF;
- pshm_netdev->hard_header_len = CAIF_NEEDED_HEADROOM;
- pshm_netdev->tx_queue_len = 0;
- pshm_netdev->destructor = free_netdev;
-
- pshm_drv = netdev_priv(pshm_netdev);
-
- /* Initialize structures in a clean state. */
- memset(pshm_drv, 0, sizeof(struct shmdrv_layer));
-
- pshm_drv->cfdev.link_select = CAIF_LINK_LOW_LATENCY;
-}
-
-int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
-{
- int result, j;
- struct shmdrv_layer *pshm_drv = NULL;
-
- pshm_dev->pshm_netdev = alloc_netdev(sizeof(struct shmdrv_layer),
- "cfshm%d", shm_netdev_setup);
- if (!pshm_dev->pshm_netdev)
- return -ENOMEM;
-
- pshm_drv = netdev_priv(pshm_dev->pshm_netdev);
- pshm_drv->pshm_dev = pshm_dev;
-
- /*
- * Initialization starts with the verification of the
- * availability of MBX driver by calling its setup function.
- * MBX driver must be available by this time for proper
- * functioning of SHM driver.
- */
- if ((pshm_dev->pshmdev_mbxsetup
- (caif_shmdrv_rx_cb, pshm_dev, pshm_drv)) != 0) {
- pr_warn("Could not config. SHM Mailbox,"
- " Bailing out.....\n");
- free_netdev(pshm_dev->pshm_netdev);
- return -ENODEV;
- }
-
- skb_queue_head_init(&pshm_drv->sk_qhead);
-
- pr_info("SHM DEVICE[%d] PROBED BY DRIVER, NEW SHM DRIVER"
- " INSTANCE AT pshm_drv =0x%p\n",
- pshm_drv->pshm_dev->shm_id, pshm_drv);
-
- if (pshm_dev->shm_total_sz <
- (NR_TX_BUF * TX_BUF_SZ + NR_RX_BUF * RX_BUF_SZ)) {
-
- pr_warn("ERROR, Amount of available"
- " Phys. SHM cannot accommodate current SHM "
- "driver configuration, Bailing out ...\n");
- free_netdev(pshm_dev->pshm_netdev);
- return -ENOMEM;
- }
-
- pshm_drv->shm_base_addr = pshm_dev->shm_base_addr;
- pshm_drv->shm_tx_addr = pshm_drv->shm_base_addr;
-
- if (pshm_dev->shm_loopback)
- pshm_drv->shm_rx_addr = pshm_drv->shm_tx_addr;
- else
- pshm_drv->shm_rx_addr = pshm_dev->shm_base_addr +
- (NR_TX_BUF * TX_BUF_SZ);
-
- spin_lock_init(&pshm_drv->lock);
- INIT_LIST_HEAD(&pshm_drv->tx_empty_list);
- INIT_LIST_HEAD(&pshm_drv->tx_pend_list);
- INIT_LIST_HEAD(&pshm_drv->tx_full_list);
-
- INIT_LIST_HEAD(&pshm_drv->rx_empty_list);
- INIT_LIST_HEAD(&pshm_drv->rx_pend_list);
- INIT_LIST_HEAD(&pshm_drv->rx_full_list);
-
- INIT_WORK(&pshm_drv->shm_tx_work, shm_tx_work_func);
- INIT_WORK(&pshm_drv->shm_rx_work, shm_rx_work_func);
-
- pshm_drv->pshm_tx_workqueue =
- create_singlethread_workqueue("shm_tx_work");
- pshm_drv->pshm_rx_workqueue =
- create_singlethread_workqueue("shm_rx_work");
-
- for (j = 0; j < NR_TX_BUF; j++) {
- struct buf_list *tx_buf =
- kmalloc(sizeof(struct buf_list), GFP_KERNEL);
-
- if (tx_buf == NULL) {
- free_netdev(pshm_dev->pshm_netdev);
- return -ENOMEM;
- }
- tx_buf->index = j;
- tx_buf->phy_addr = pshm_drv->shm_tx_addr + (TX_BUF_SZ * j);
- tx_buf->len = TX_BUF_SZ;
- tx_buf->frames = 0;
- tx_buf->frm_ofs = SHM_CAIF_FRM_OFS;
-
- if (pshm_dev->shm_loopback)
- tx_buf->desc_vptr = (unsigned char *)tx_buf->phy_addr;
- else
- /*
- * FIXME: the result of ioremap is not a pointer - arnd
- */
- tx_buf->desc_vptr =
- ioremap(tx_buf->phy_addr, TX_BUF_SZ);
-
- list_add_tail(&tx_buf->list, &pshm_drv->tx_empty_list);
- }
-
- for (j = 0; j < NR_RX_BUF; j++) {
- struct buf_list *rx_buf =
- kmalloc(sizeof(struct buf_list), GFP_KERNEL);
-
- if (rx_buf == NULL) {
- free_netdev(pshm_dev->pshm_netdev);
- return -ENOMEM;
- }
- rx_buf->index = j;
- rx_buf->phy_addr = pshm_drv->shm_rx_addr + (RX_BUF_SZ * j);
- rx_buf->len = RX_BUF_SZ;
-
- if (pshm_dev->shm_loopback)
- rx_buf->desc_vptr = (unsigned char *)rx_buf->phy_addr;
- else
- rx_buf->desc_vptr =
- ioremap(rx_buf->phy_addr, RX_BUF_SZ);
- list_add_tail(&rx_buf->list, &pshm_drv->rx_empty_list);
- }
-
- pshm_drv->tx_empty_available = 1;
- result = register_netdev(pshm_dev->pshm_netdev);
- if (result)
- pr_warn("ERROR[%d], SHM could not, "
- "register with NW FRMWK Bailing out ...\n", result);
-
- return result;
-}
-
-void caif_shmcore_remove(struct net_device *pshm_netdev)
-{
- struct buf_list *pbuf;
- struct shmdrv_layer *pshm_drv = NULL;
-
- pshm_drv = netdev_priv(pshm_netdev);
-
- while (!(list_empty(&pshm_drv->tx_pend_list))) {
- pbuf =
- list_entry(pshm_drv->tx_pend_list.next,
- struct buf_list, list);
-
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- while (!(list_empty(&pshm_drv->tx_full_list))) {
- pbuf =
- list_entry(pshm_drv->tx_full_list.next,
- struct buf_list, list);
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- while (!(list_empty(&pshm_drv->tx_empty_list))) {
- pbuf =
- list_entry(pshm_drv->tx_empty_list.next,
- struct buf_list, list);
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- while (!(list_empty(&pshm_drv->rx_full_list))) {
- pbuf =
- list_entry(pshm_drv->tx_full_list.next,
- struct buf_list, list);
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- while (!(list_empty(&pshm_drv->rx_pend_list))) {
- pbuf =
- list_entry(pshm_drv->tx_pend_list.next,
- struct buf_list, list);
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- while (!(list_empty(&pshm_drv->rx_empty_list))) {
- pbuf =
- list_entry(pshm_drv->rx_empty_list.next,
- struct buf_list, list);
- list_del(&pbuf->list);
- kfree(pbuf);
- }
-
- /* Destroy work queues. */
- destroy_workqueue(pshm_drv->pshm_tx_workqueue);
- destroy_workqueue(pshm_drv->pshm_rx_workqueue);
-
- unregister_netdev(pshm_netdev);
-}
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index b71ce9bf0afb..155db68e13ba 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -1,7 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * Author: Daniel Martensson
* License terms: GNU General Public License (GPL) version 2.
*/
@@ -29,7 +28,7 @@
#endif /* CONFIG_CAIF_SPI_SYNC */
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_AUTHOR("Daniel Martensson");
MODULE_DESCRIPTION("CAIF SPI driver");
/* Returns the number of padding bytes for alignment. */
@@ -864,6 +863,7 @@ static int __init cfspi_init_module(void)
driver_remove_file(&cfspi_spi_driver.driver,
&driver_attr_up_head_align);
err_create_up_head_align:
+ platform_driver_unregister(&cfspi_spi_driver);
err_dev_register:
return result;
}
diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c
index e139e133fc79..ee92ad5a6cf8 100644
--- a/drivers/net/caif/caif_spi_slave.c
+++ b/drivers/net/caif/caif_spi_slave.c
@@ -1,7 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Author: Daniel Martensson / Daniel.Martensson@stericsson.com
+ * Author: Daniel Martensson
* License terms: GNU General Public License (GPL) version 2.
*/
#include <linux/init.h>
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 9862b2e07644..e456b70933c2 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -65,7 +65,7 @@ config CAN_LEDS
config CAN_AT91
tristate "Atmel AT91 onchip CAN controller"
- depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9X5
+ depends on ARM
---help---
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors.
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index 44f363792b59..db52f4414def 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
@@ -155,19 +156,20 @@ struct at91_priv {
canid_t mb0_id;
};
-static const struct at91_devtype_data at91_devtype_data[] = {
- [AT91_DEVTYPE_SAM9263] = {
- .rx_first = 1,
- .rx_split = 8,
- .rx_last = 11,
- .tx_shift = 2,
- },
- [AT91_DEVTYPE_SAM9X5] = {
- .rx_first = 0,
- .rx_split = 4,
- .rx_last = 5,
- .tx_shift = 1,
- },
+static const struct at91_devtype_data at91_at91sam9263_data = {
+ .rx_first = 1,
+ .rx_split = 8,
+ .rx_last = 11,
+ .tx_shift = 2,
+ .type = AT91_DEVTYPE_SAM9263,
+};
+
+static const struct at91_devtype_data at91_at91sam9x5_data = {
+ .rx_first = 0,
+ .rx_split = 4,
+ .rx_last = 5,
+ .tx_shift = 1,
+ .type = AT91_DEVTYPE_SAM9X5,
};
static const struct can_bittiming_const at91_bittiming_const = {
@@ -1249,10 +1251,42 @@ static struct attribute_group at91_sysfs_attr_group = {
.attrs = at91_sysfs_attrs,
};
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_can_dt_ids[] = {
+ {
+ .compatible = "atmel,at91sam9x5-can",
+ .data = &at91_at91sam9x5_data,
+ }, {
+ .compatible = "atmel,at91sam9263-can",
+ .data = &at91_at91sam9263_data,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, at91_can_dt_ids);
+#else
+#define at91_can_dt_ids NULL
+#endif
+
+static const struct at91_devtype_data *at91_can_get_driver_data(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_node(at91_can_dt_ids, pdev->dev.of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "no matching node found in dtb\n");
+ return NULL;
+ }
+ return (const struct at91_devtype_data *)match->data;
+ }
+ return (const struct at91_devtype_data *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
static int at91_can_probe(struct platform_device *pdev)
{
const struct at91_devtype_data *devtype_data;
- enum at91_devtype devtype;
struct net_device *dev;
struct at91_priv *priv;
struct resource *res;
@@ -1260,8 +1294,12 @@ static int at91_can_probe(struct platform_device *pdev)
void __iomem *addr;
int err, irq;
- devtype = pdev->id_entry->driver_data;
- devtype_data = &at91_devtype_data[devtype];
+ devtype_data = at91_can_get_driver_data(pdev);
+ if (!devtype_data) {
+ dev_err(&pdev->dev, "no driver data\n");
+ err = -ENODEV;
+ goto exit;
+ }
clk = clk_get(&pdev->dev, "can_clk");
if (IS_ERR(clk)) {
@@ -1310,7 +1348,6 @@ static int at91_can_probe(struct platform_device *pdev)
priv->dev = dev;
priv->reg_base = addr;
priv->devtype_data = *devtype_data;
- priv->devtype_data.type = devtype;
priv->clk = clk;
priv->pdata = pdev->dev.platform_data;
priv->mb0_id = 0x7ff;
@@ -1373,10 +1410,10 @@ static int at91_can_remove(struct platform_device *pdev)
static const struct platform_device_id at91_can_id_table[] = {
{
.name = "at91_can",
- .driver_data = AT91_DEVTYPE_SAM9263,
+ .driver_data = (kernel_ulong_t)&at91_at91sam9x5_data,
}, {
.name = "at91sam9x5_can",
- .driver_data = AT91_DEVTYPE_SAM9X5,
+ .driver_data = (kernel_ulong_t)&at91_at91sam9263_data,
}, {
/* sentinel */
}
@@ -1389,6 +1426,7 @@ static struct platform_driver at91_can_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
+ .of_match_table = at91_can_dt_ids,
},
.id_table = at91_can_id_table,
};
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 6a0532176b69..d4a15e82bfc0 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -412,7 +412,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
return 0;
}
-irqreturn_t bfin_can_interrupt(int irq, void *dev_id)
+static irqreturn_t bfin_can_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct bfin_can_priv *priv = netdev_priv(dev);
@@ -504,7 +504,7 @@ static int bfin_can_close(struct net_device *dev)
return 0;
}
-struct net_device *alloc_bfin_candev(void)
+static struct net_device *alloc_bfin_candev(void)
{
struct net_device *dev;
struct bfin_can_priv *priv;
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index f32b9fc6a983..8cda23bf0614 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -269,7 +269,7 @@ struct mcp251x_priv {
#define MCP251X_IS(_model) \
static inline int mcp251x_is_##_model(struct spi_device *spi) \
{ \
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev); \
+ struct mcp251x_priv *priv = spi_get_drvdata(spi); \
return priv->model == CAN_MCP251X_MCP##_model; \
}
@@ -305,7 +305,7 @@ static void mcp251x_clean(struct net_device *net)
*/
static int mcp251x_spi_trans(struct spi_device *spi, int len)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct spi_transfer t = {
.tx_buf = priv->spi_tx_buf,
.rx_buf = priv->spi_rx_buf,
@@ -333,7 +333,7 @@ static int mcp251x_spi_trans(struct spi_device *spi, int len)
static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
u8 val = 0;
priv->spi_tx_buf[0] = INSTRUCTION_READ;
@@ -348,7 +348,7 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
uint8_t *v1, uint8_t *v2)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_READ;
priv->spi_tx_buf[1] = reg;
@@ -361,7 +361,7 @@ static void mcp251x_read_2regs(struct spi_device *spi, uint8_t reg,
static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
priv->spi_tx_buf[1] = reg;
@@ -373,7 +373,7 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
u8 mask, uint8_t val)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
priv->spi_tx_buf[1] = reg;
@@ -386,7 +386,7 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
int len, int tx_buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (mcp251x_is_2510(spi)) {
int i;
@@ -403,7 +403,7 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
int tx_buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
u32 sid, eid, exide, rtr;
u8 buf[SPI_TRANSFER_BUF_LEN];
@@ -434,7 +434,7 @@ static void mcp251x_hw_tx(struct spi_device *spi, struct can_frame *frame,
static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
int buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (mcp251x_is_2510(spi)) {
int i, len;
@@ -454,7 +454,7 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
static void mcp251x_hw_rx(struct spi_device *spi, int buf_idx)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct sk_buff *skb;
struct can_frame *frame;
u8 buf[SPI_TRANSFER_BUF_LEN];
@@ -550,7 +550,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
static int mcp251x_set_normal_mode(struct spi_device *spi)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
unsigned long timeout;
/* Enable interrupts */
@@ -620,7 +620,7 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
static int mcp251x_hw_reset(struct spi_device *spi)
{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
int ret;
unsigned long timeout;
@@ -929,6 +929,7 @@ static int mcp251x_open(struct net_device *net)
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+ unsigned long flags;
int ret;
ret = open_candev(net);
@@ -945,9 +946,14 @@ static int mcp251x_open(struct net_device *net)
priv->tx_skb = NULL;
priv->tx_len = 0;
+ flags = IRQF_ONESHOT;
+ if (pdata->irq_flags)
+ flags |= pdata->irq_flags;
+ else
+ flags |= IRQF_TRIGGER_FALLING;
+
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
- pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
- DEVICE_NAME, priv);
+ flags, DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
if (pdata->transceiver_enable)
@@ -1020,7 +1026,7 @@ static int mcp251x_can_probe(struct spi_device *spi)
CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY;
priv->model = spi_get_device_id(spi)->driver_data;
priv->net = net;
- dev_set_drvdata(&spi->dev, priv);
+ spi_set_drvdata(spi, priv);
priv->spi = spi;
mutex_init(&priv->mcp_lock);
@@ -1118,7 +1124,7 @@ error_out:
static int mcp251x_can_remove(struct spi_device *spi)
{
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct net_device *net = priv->net;
unregister_candev(net);
@@ -1138,11 +1144,13 @@ static int mcp251x_can_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+
+static int mcp251x_can_suspend(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
struct net_device *net = priv->net;
priv->force_quit = 1;
@@ -1170,10 +1178,11 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
return 0;
}
-static int mcp251x_can_resume(struct spi_device *spi)
+static int mcp251x_can_resume(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
+ struct mcp251x_priv *priv = spi_get_drvdata(spi);
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
pdata->power_enable(1);
@@ -1191,11 +1200,11 @@ static int mcp251x_can_resume(struct spi_device *spi)
enable_irq(spi->irq);
return 0;
}
-#else
-#define mcp251x_can_suspend NULL
-#define mcp251x_can_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
+ mcp251x_can_resume);
+
static const struct spi_device_id mcp251x_id_table[] = {
{ "mcp2510", CAN_MCP251X_MCP2510 },
{ "mcp2515", CAN_MCP251X_MCP2515 },
@@ -1207,29 +1216,15 @@ MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
static struct spi_driver mcp251x_can_driver = {
.driver = {
.name = DEVICE_NAME,
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .pm = &mcp251x_can_pm_ops,
},
.id_table = mcp251x_id_table,
.probe = mcp251x_can_probe,
.remove = mcp251x_can_remove,
- .suspend = mcp251x_can_suspend,
- .resume = mcp251x_can_resume,
};
-
-static int __init mcp251x_can_init(void)
-{
- return spi_register_driver(&mcp251x_can_driver);
-}
-
-static void __exit mcp251x_can_exit(void)
-{
- spi_unregister_driver(&mcp251x_can_driver);
-}
-
-module_init(mcp251x_can_init);
-module_exit(mcp251x_can_exit);
+module_spi_driver(mcp251x_can_driver);
MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "
"Christian Pellegrin <chripell@evolware.org>");
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index b39ca5b3ea7f..ff2ba86cd4a4 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -46,6 +46,7 @@ config CAN_EMS_PCI
config CAN_PEAK_PCMCIA
tristate "PEAK PCAN-PC Card"
depends on PCMCIA
+ depends on HAS_IOPORT
---help---
This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
from PEAK-System (http://www.peak-system.com). To compile this
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 36d298da2af6..3752342a678a 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -168,12 +168,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- priv->write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, SJA1000_MOD, 1);
- priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- res = priv->read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, SJA1000_CDR);
if (res == CDR_PELICAN)
return 1;
diff --git a/drivers/net/can/sja1000/ems_pcmcia.c b/drivers/net/can/sja1000/ems_pcmcia.c
index 5c2f3fbbf5ae..9e535f2ef52b 100644
--- a/drivers/net/can/sja1000/ems_pcmcia.c
+++ b/drivers/net/can/sja1000/ems_pcmcia.c
@@ -126,11 +126,11 @@ static irqreturn_t ems_pcmcia_interrupt(int irq, void *dev_id)
static inline int ems_pcmcia_check_chan(struct sja1000_priv *priv)
{
/* Make sure SJA1000 is in reset mode */
- ems_pcmcia_write_reg(priv, REG_MOD, 1);
- ems_pcmcia_write_reg(priv, REG_CDR, CDR_PELICAN);
+ ems_pcmcia_write_reg(priv, SJA1000_MOD, 1);
+ ems_pcmcia_write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- if (ems_pcmcia_read_reg(priv, REG_CDR) == CDR_PELICAN)
+ if (ems_pcmcia_read_reg(priv, SJA1000_CDR) == CDR_PELICAN)
return 1;
return 0;
@@ -316,15 +316,4 @@ static struct pcmcia_driver ems_pcmcia_driver = {
.remove = ems_pcmcia_remove,
.id_table = ems_pcmcia_tbl,
};
-
-static int __init ems_pcmcia_init(void)
-{
- return pcmcia_register_driver(&ems_pcmcia_driver);
-}
-module_init(ems_pcmcia_init);
-
-static void __exit ems_pcmcia_exit(void)
-{
- pcmcia_unregister_driver(&ems_pcmcia_driver);
-}
-module_exit(ems_pcmcia_exit);
+module_pcmcia_driver(ems_pcmcia_driver);
diff --git a/drivers/net/can/sja1000/kvaser_pci.c b/drivers/net/can/sja1000/kvaser_pci.c
index 37b0381f532e..217585b97cd3 100644
--- a/drivers/net/can/sja1000/kvaser_pci.c
+++ b/drivers/net/can/sja1000/kvaser_pci.c
@@ -159,9 +159,9 @@ static int number_of_sja1000_chip(void __iomem *base_addr)
for (i = 0; i < MAX_NO_OF_CHANNELS; i++) {
/* reset chip */
iowrite8(MOD_RM, base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
status = ioread8(base_addr +
- (i * KVASER_PCI_PORT_BYTES) + REG_MOD);
+ (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD);
/* check reset bit */
if (!(status & MOD_RM))
break;
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index d1e7f1006ddd..6b6f0ad75090 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -402,7 +402,7 @@ static void peak_pciec_write_reg(const struct sja1000_priv *priv,
int c = (priv->reg_base - card->reg_base) / PEAK_PCI_CHAN_SIZE;
/* sja1000 register changes control the leds state */
- if (port == REG_MOD)
+ if (port == SJA1000_MOD)
switch (val) {
case MOD_RM:
/* Reset Mode: set led on */
diff --git a/drivers/net/can/sja1000/peak_pcmcia.c b/drivers/net/can/sja1000/peak_pcmcia.c
index 1a7020ba37f5..f7ad754dd2aa 100644
--- a/drivers/net/can/sja1000/peak_pcmcia.c
+++ b/drivers/net/can/sja1000/peak_pcmcia.c
@@ -196,7 +196,7 @@ static void pcan_write_canreg(const struct sja1000_priv *priv, int port, u8 v)
int c = (priv->reg_base - card->ioport_addr) / PCC_CHAN_SIZE;
/* sja1000 register changes control the leds state */
- if (port == REG_MOD)
+ if (port == SJA1000_MOD)
switch (v) {
case MOD_RM:
/* Reset Mode: set led on */
@@ -509,11 +509,11 @@ static void pcan_free_channels(struct pcan_pccard *card)
static inline int pcan_channel_present(struct sja1000_priv *priv)
{
/* make sure SJA1000 is in reset mode */
- pcan_write_canreg(priv, REG_MOD, 1);
- pcan_write_canreg(priv, REG_CDR, CDR_PELICAN);
+ pcan_write_canreg(priv, SJA1000_MOD, 1);
+ pcan_write_canreg(priv, SJA1000_CDR, CDR_PELICAN);
/* read reset-values */
- if (pcan_read_canreg(priv, REG_CDR) == CDR_PELICAN)
+ if (pcan_read_canreg(priv, SJA1000_CDR) == CDR_PELICAN)
return 1;
return 0;
@@ -740,15 +740,4 @@ static struct pcmcia_driver pcan_driver = {
.remove = pcan_remove,
.id_table = pcan_table,
};
-
-static int __init pcan_init(void)
-{
- return pcmcia_register_driver(&pcan_driver);
-}
-module_init(pcan_init);
-
-static void __exit pcan_exit(void)
-{
- pcmcia_unregister_driver(&pcan_driver);
-}
-module_exit(pcan_exit);
+module_pcmcia_driver(pcan_driver);
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index a042cdc260dc..c52c1e96bf90 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -348,20 +348,20 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
*/
if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
REG_CR_BASICCAN_INITIAL &&
- (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
- (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
+ (priv->read_reg(priv, SJA1000_SR) == REG_SR_BASICCAN_INITIAL) &&
+ (priv->read_reg(priv, SJA1000_IR) == REG_IR_BASICCAN_INITIAL))
flag = 1;
/* Bring the SJA1000 into the PeliCAN mode*/
- priv->write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, CDR_PELICAN);
/*
* Check registers after reset in the PeliCAN mode.
* See states on p. 23 of the Datasheet.
*/
- if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
- priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
+ if (priv->read_reg(priv, SJA1000_MOD) == REG_MOD_PELICAN_INITIAL &&
+ priv->read_reg(priv, SJA1000_SR) == REG_SR_PELICAN_INITIAL &&
+ priv->read_reg(priv, SJA1000_IR) == REG_IR_PELICAN_INITIAL)
return flag;
return 0;
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index daf4013a8fc7..7164a999f50f 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -91,14 +91,14 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
* the write_reg() operation - especially on SMP systems.
*/
spin_lock_irqsave(&priv->cmdreg_lock, flags);
- priv->write_reg(priv, REG_CMR, val);
- priv->read_reg(priv, REG_SR);
+ priv->write_reg(priv, SJA1000_CMR, val);
+ priv->read_reg(priv, SJA1000_SR);
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
}
static int sja1000_is_absent(struct sja1000_priv *priv)
{
- return (priv->read_reg(priv, REG_MOD) == 0xFF);
+ return (priv->read_reg(priv, SJA1000_MOD) == 0xFF);
}
static int sja1000_probe_chip(struct net_device *dev)
@@ -116,11 +116,11 @@ static int sja1000_probe_chip(struct net_device *dev)
static void set_reset_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
/* disable interrupts */
- priv->write_reg(priv, REG_IER, IRQ_OFF);
+ priv->write_reg(priv, SJA1000_IER, IRQ_OFF);
for (i = 0; i < 100; i++) {
/* check reset bit */
@@ -129,9 +129,10 @@ static void set_reset_mode(struct net_device *dev)
return;
}
- priv->write_reg(priv, REG_MOD, MOD_RM); /* reset chip */
+ /* reset chip */
+ priv->write_reg(priv, SJA1000_MOD, MOD_RM);
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+ status = priv->read_reg(priv, SJA1000_MOD);
}
netdev_err(dev, "setting SJA1000 into reset mode failed!\n");
@@ -140,7 +141,7 @@ static void set_reset_mode(struct net_device *dev)
static void set_normal_mode(struct net_device *dev)
{
struct sja1000_priv *priv = netdev_priv(dev);
- unsigned char status = priv->read_reg(priv, REG_MOD);
+ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i;
for (i = 0; i < 100; i++) {
@@ -149,22 +150,22 @@ static void set_normal_mode(struct net_device *dev)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
- priv->write_reg(priv, REG_IER, IRQ_ALL);
+ priv->write_reg(priv, SJA1000_IER, IRQ_ALL);
else
- priv->write_reg(priv, REG_IER,
+ priv->write_reg(priv, SJA1000_IER,
IRQ_ALL & ~IRQ_BEI);
return;
}
/* set chip to normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
- priv->write_reg(priv, REG_MOD, MOD_LOM);
+ priv->write_reg(priv, SJA1000_MOD, MOD_LOM);
else
- priv->write_reg(priv, REG_MOD, 0x00);
+ priv->write_reg(priv, SJA1000_MOD, 0x00);
udelay(10);
- status = priv->read_reg(priv, REG_MOD);
+ status = priv->read_reg(priv, SJA1000_MOD);
}
netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
@@ -179,9 +180,9 @@ static void sja1000_start(struct net_device *dev)
set_reset_mode(dev);
/* Clear error counters and error code capture */
- priv->write_reg(priv, REG_TXERR, 0x0);
- priv->write_reg(priv, REG_RXERR, 0x0);
- priv->read_reg(priv, REG_ECC);
+ priv->write_reg(priv, SJA1000_TXERR, 0x0);
+ priv->write_reg(priv, SJA1000_RXERR, 0x0);
+ priv->read_reg(priv, SJA1000_ECC);
/* leave reset mode */
set_normal_mode(dev);
@@ -217,8 +218,8 @@ static int sja1000_set_bittiming(struct net_device *dev)
netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1);
- priv->write_reg(priv, REG_BTR0, btr0);
- priv->write_reg(priv, REG_BTR1, btr1);
+ priv->write_reg(priv, SJA1000_BTR0, btr0);
+ priv->write_reg(priv, SJA1000_BTR1, btr1);
return 0;
}
@@ -228,8 +229,8 @@ static int sja1000_get_berr_counter(const struct net_device *dev,
{
struct sja1000_priv *priv = netdev_priv(dev);
- bec->txerr = priv->read_reg(priv, REG_TXERR);
- bec->rxerr = priv->read_reg(priv, REG_RXERR);
+ bec->txerr = priv->read_reg(priv, SJA1000_TXERR);
+ bec->rxerr = priv->read_reg(priv, SJA1000_RXERR);
return 0;
}
@@ -247,20 +248,20 @@ static void chipset_init(struct net_device *dev)
struct sja1000_priv *priv = netdev_priv(dev);
/* set clock divider and output control register */
- priv->write_reg(priv, REG_CDR, priv->cdr | CDR_PELICAN);
+ priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
/* set acceptance filter (accept all) */
- priv->write_reg(priv, REG_ACCC0, 0x00);
- priv->write_reg(priv, REG_ACCC1, 0x00);
- priv->write_reg(priv, REG_ACCC2, 0x00);
- priv->write_reg(priv, REG_ACCC3, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC0, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC1, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC2, 0x00);
+ priv->write_reg(priv, SJA1000_ACCC3, 0x00);
- priv->write_reg(priv, REG_ACCM0, 0xFF);
- priv->write_reg(priv, REG_ACCM1, 0xFF);
- priv->write_reg(priv, REG_ACCM2, 0xFF);
- priv->write_reg(priv, REG_ACCM3, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
+ priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
- priv->write_reg(priv, REG_OCR, priv->ocr | OCR_MODE_NORMAL);
+ priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
}
/*
@@ -289,21 +290,21 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
id = cf->can_id;
if (id & CAN_RTR_FLAG)
- fi |= FI_RTR;
+ fi |= SJA1000_FI_RTR;
if (id & CAN_EFF_FLAG) {
- fi |= FI_FF;
- dreg = EFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x1fe00000) >> (5 + 16));
- priv->write_reg(priv, REG_ID2, (id & 0x001fe000) >> (5 + 8));
- priv->write_reg(priv, REG_ID3, (id & 0x00001fe0) >> 5);
- priv->write_reg(priv, REG_ID4, (id & 0x0000001f) << 3);
+ fi |= SJA1000_FI_FF;
+ dreg = SJA1000_EFF_BUF;
+ priv->write_reg(priv, SJA1000_FI, fi);
+ priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> 21);
+ priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> 13);
+ priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> 5);
+ priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << 3);
} else {
- dreg = SFF_BUF;
- priv->write_reg(priv, REG_FI, fi);
- priv->write_reg(priv, REG_ID1, (id & 0x000007f8) >> 3);
- priv->write_reg(priv, REG_ID2, (id & 0x00000007) << 5);
+ dreg = SJA1000_SFF_BUF;
+ priv->write_reg(priv, SJA1000_FI, fi);
+ priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> 3);
+ priv->write_reg(priv, SJA1000_ID2, (id & 0x00000007) << 5);
}
for (i = 0; i < dlc; i++)
@@ -335,25 +336,25 @@ static void sja1000_rx(struct net_device *dev)
if (skb == NULL)
return;
- fi = priv->read_reg(priv, REG_FI);
+ fi = priv->read_reg(priv, SJA1000_FI);
- if (fi & FI_FF) {
+ if (fi & SJA1000_FI_FF) {
/* extended frame format (EFF) */
- dreg = EFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << (5 + 16))
- | (priv->read_reg(priv, REG_ID2) << (5 + 8))
- | (priv->read_reg(priv, REG_ID3) << 5)
- | (priv->read_reg(priv, REG_ID4) >> 3);
+ dreg = SJA1000_EFF_BUF;
+ id = (priv->read_reg(priv, SJA1000_ID1) << 21)
+ | (priv->read_reg(priv, SJA1000_ID2) << 13)
+ | (priv->read_reg(priv, SJA1000_ID3) << 5)
+ | (priv->read_reg(priv, SJA1000_ID4) >> 3);
id |= CAN_EFF_FLAG;
} else {
/* standard frame format (SFF) */
- dreg = SFF_BUF;
- id = (priv->read_reg(priv, REG_ID1) << 3)
- | (priv->read_reg(priv, REG_ID2) >> 5);
+ dreg = SJA1000_SFF_BUF;
+ id = (priv->read_reg(priv, SJA1000_ID1) << 3)
+ | (priv->read_reg(priv, SJA1000_ID2) >> 5);
}
cf->can_dlc = get_can_dlc(fi & 0x0F);
- if (fi & FI_RTR) {
+ if (fi & SJA1000_FI_RTR) {
id |= CAN_RTR_FLAG;
} else {
for (i = 0; i < cf->can_dlc; i++)
@@ -414,7 +415,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
priv->can.can_stats.bus_error++;
stats->rx_errors++;
- ecc = priv->read_reg(priv, REG_ECC);
+ ecc = priv->read_reg(priv, SJA1000_ECC);
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
@@ -448,7 +449,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (isrc & IRQ_ALI) {
/* arbitration lost interrupt */
netdev_dbg(dev, "arbitration lost interrupt\n");
- alc = priv->read_reg(priv, REG_ALC);
+ alc = priv->read_reg(priv, SJA1000_ALC);
priv->can.can_stats.arbitration_lost++;
stats->tx_errors++;
cf->can_id |= CAN_ERR_LOSTARB;
@@ -457,8 +458,8 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
state == CAN_STATE_ERROR_PASSIVE)) {
- uint8_t rxerr = priv->read_reg(priv, REG_RXERR);
- uint8_t txerr = priv->read_reg(priv, REG_TXERR);
+ uint8_t rxerr = priv->read_reg(priv, SJA1000_RXERR);
+ uint8_t txerr = priv->read_reg(priv, SJA1000_TXERR);
cf->can_id |= CAN_ERR_CRTL;
if (state == CAN_STATE_ERROR_WARNING) {
priv->can.can_stats.error_warning++;
@@ -494,15 +495,16 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
int n = 0;
/* Shared interrupts and IRQ off? */
- if (priv->read_reg(priv, REG_IER) == IRQ_OFF)
+ if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
return IRQ_NONE;
if (priv->pre_irq)
priv->pre_irq(priv);
- while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
+ while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
+ (n < SJA1000_MAX_IRQ)) {
n++;
- status = priv->read_reg(priv, REG_SR);
+ status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller due to hw unplug */
if (status == 0xFF && sja1000_is_absent(priv))
return IRQ_NONE;
@@ -519,7 +521,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
} else {
/* transmission complete */
stats->tx_bytes +=
- priv->read_reg(priv, REG_FI) & 0xf;
+ priv->read_reg(priv, SJA1000_FI) & 0xf;
stats->tx_packets++;
can_get_echo_skb(dev, 0);
}
@@ -530,7 +532,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
/* receive interrupt */
while (status & SR_RBS) {
sja1000_rx(dev);
- status = priv->read_reg(priv, REG_SR);
+ status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller */
if (status == 0xFF && sja1000_is_absent(priv))
return IRQ_NONE;
diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h
index afa99847a510..9d46398f8154 100644
--- a/drivers/net/can/sja1000/sja1000.h
+++ b/drivers/net/can/sja1000/sja1000.h
@@ -54,46 +54,46 @@
#define SJA1000_MAX_IRQ 20 /* max. number of interrupts handled in ISR */
/* SJA1000 registers - manual section 6.4 (Pelican Mode) */
-#define REG_MOD 0x00
-#define REG_CMR 0x01
-#define REG_SR 0x02
-#define REG_IR 0x03
-#define REG_IER 0x04
-#define REG_ALC 0x0B
-#define REG_ECC 0x0C
-#define REG_EWL 0x0D
-#define REG_RXERR 0x0E
-#define REG_TXERR 0x0F
-#define REG_ACCC0 0x10
-#define REG_ACCC1 0x11
-#define REG_ACCC2 0x12
-#define REG_ACCC3 0x13
-#define REG_ACCM0 0x14
-#define REG_ACCM1 0x15
-#define REG_ACCM2 0x16
-#define REG_ACCM3 0x17
-#define REG_RMC 0x1D
-#define REG_RBSA 0x1E
+#define SJA1000_MOD 0x00
+#define SJA1000_CMR 0x01
+#define SJA1000_SR 0x02
+#define SJA1000_IR 0x03
+#define SJA1000_IER 0x04
+#define SJA1000_ALC 0x0B
+#define SJA1000_ECC 0x0C
+#define SJA1000_EWL 0x0D
+#define SJA1000_RXERR 0x0E
+#define SJA1000_TXERR 0x0F
+#define SJA1000_ACCC0 0x10
+#define SJA1000_ACCC1 0x11
+#define SJA1000_ACCC2 0x12
+#define SJA1000_ACCC3 0x13
+#define SJA1000_ACCM0 0x14
+#define SJA1000_ACCM1 0x15
+#define SJA1000_ACCM2 0x16
+#define SJA1000_ACCM3 0x17
+#define SJA1000_RMC 0x1D
+#define SJA1000_RBSA 0x1E
/* Common registers - manual section 6.5 */
-#define REG_BTR0 0x06
-#define REG_BTR1 0x07
-#define REG_OCR 0x08
-#define REG_CDR 0x1F
+#define SJA1000_BTR0 0x06
+#define SJA1000_BTR1 0x07
+#define SJA1000_OCR 0x08
+#define SJA1000_CDR 0x1F
-#define REG_FI 0x10
-#define SFF_BUF 0x13
-#define EFF_BUF 0x15
+#define SJA1000_FI 0x10
+#define SJA1000_SFF_BUF 0x13
+#define SJA1000_EFF_BUF 0x15
-#define FI_FF 0x80
-#define FI_RTR 0x40
+#define SJA1000_FI_FF 0x80
+#define SJA1000_FI_RTR 0x40
-#define REG_ID1 0x11
-#define REG_ID2 0x12
-#define REG_ID3 0x13
-#define REG_ID4 0x14
+#define SJA1000_ID1 0x11
+#define SJA1000_ID2 0x12
+#define SJA1000_ID3 0x13
+#define SJA1000_ID4 0x14
-#define CAN_RAM 0x20
+#define SJA1000_CAN_RAM 0x20
/* mode register */
#define MOD_RM 0x01
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index 6433b81256cd..8e0c4a001939 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -96,8 +96,8 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
struct net_device *dev;
struct sja1000_priv *priv;
struct resource res;
- const u32 *prop;
- int err, irq, res_size, prop_size;
+ u32 prop;
+ int err, irq, res_size;
void __iomem *base;
err = of_address_to_resource(np, 0, &res);
@@ -138,27 +138,27 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
priv->read_reg = sja1000_ofp_read_reg;
priv->write_reg = sja1000_ofp_write_reg;
- prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->can.clock.freq = *prop / 2;
+ err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
+ if (!err)
+ priv->can.clock.freq = prop / 2;
else
priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
- prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= *prop & OCR_MODE_MASK;
+ err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
+ if (!err)
+ priv->ocr |= prop & OCR_MODE_MASK;
else
priv->ocr |= OCR_MODE_NORMAL; /* default */
- prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
- if (prop && (prop_size == sizeof(u32)))
- priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+ err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
+ if (!err)
+ priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
else
priv->ocr |= OCR_TX0_PULLDOWN; /* default */
- prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
- if (prop && (prop_size == sizeof(u32)) && *prop) {
- u32 divider = priv->can.clock.freq * 2 / *prop;
+ err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
+ if (!err && prop) {
+ u32 divider = priv->can.clock.freq * 2 / prop;
if (divider > 1)
priv->cdr |= divider / 2 - 1;
@@ -168,8 +168,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
priv->cdr |= CDR_CLK_OFF; /* default */
}
- prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
- if (!prop)
+ if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
priv->cdr |= CDR_CBP; /* default */
priv->irq_flags = IRQF_SHARED;
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
index c2c0a5bb0b21..498605f833dd 100644
--- a/drivers/net/can/softing/softing_cs.c
+++ b/drivers/net/can/softing/softing_cs.c
@@ -27,7 +27,7 @@
#include "softing_platform.h"
static int softingcs_index;
-static spinlock_t softingcs_index_lock;
+static DEFINE_SPINLOCK(softingcs_index_lock);
static int softingcs_reset(struct platform_device *pdev, int v);
static int softingcs_enable_irq(struct platform_device *pdev, int v);
@@ -340,19 +340,7 @@ static struct pcmcia_driver softingcs_driver = {
.remove = softingcs_remove,
};
-static int __init softingcs_start(void)
-{
- spin_lock_init(&softingcs_index_lock);
- return pcmcia_register_driver(&softingcs_driver);
-}
-
-static void __exit softingcs_stop(void)
-{
- pcmcia_unregister_driver(&softingcs_driver);
-}
-
-module_init(softingcs_start);
-module_exit(softingcs_stop);
+module_pcmcia_driver(softingcs_driver);
MODULE_DESCRIPTION("softing CANcard driver"
", links PCMCIA card to softing driver");
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index f36ff99fd394..adb4bf5eb4b4 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -306,6 +306,7 @@ static int el3_isa_match(struct device *pdev, unsigned int ndev)
if (!dev)
return -ENOMEM;
+ SET_NETDEV_DEV(dev, pdev);
netdev_boot_setup_check(dev);
if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509-isa")) {
@@ -595,6 +596,7 @@ static int __init el3_eisa_probe (struct device *device)
return -ENOMEM;
}
+ SET_NETDEV_DEV(dev, device);
netdev_boot_setup_check(dev);
el3_dev_fill(dev, phys_addr, ioaddr, irq, if_port, EL3_EISA);
diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c
index ffd8de28a76a..6fc994fa4abe 100644
--- a/drivers/net/ethernet/3com/3c574_cs.c
+++ b/drivers/net/ethernet/3com/3c574_cs.c
@@ -1165,16 +1165,4 @@ static struct pcmcia_driver tc574_driver = {
.suspend = tc574_suspend,
.resume = tc574_resume,
};
-
-static int __init init_tc574(void)
-{
- return pcmcia_register_driver(&tc574_driver);
-}
-
-static void __exit exit_tc574(void)
-{
- pcmcia_unregister_driver(&tc574_driver);
-}
-
-module_init(init_tc574);
-module_exit(exit_tc574);
+module_pcmcia_driver(tc574_driver);
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index a556c01e011b..078480aaa168 100644
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -928,16 +928,4 @@ static struct pcmcia_driver tc589_driver = {
.suspend = tc589_suspend,
.resume = tc589_resume,
};
-
-static int __init init_tc589(void)
-{
- return pcmcia_register_driver(&tc589_driver);
-}
-
-static void __exit exit_tc589(void)
-{
- pcmcia_unregister_driver(&tc589_driver);
-}
-
-module_init(init_tc589);
-module_exit(exit_tc589);
+module_pcmcia_driver(tc589_driver);
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index 27aaaf99e73e..144942f6372b 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -1690,7 +1690,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read
skb_checksum_none_assert(new_skb);
if (rx->rxStatus & TYPHOON_RX_VLAN)
- __vlan_hwaccel_put_tag(new_skb,
+ __vlan_hwaccel_put_tag(new_skb, htons(ETH_P_8021Q),
ntohl(rx->vlanTag) & 0xffff);
netif_receive_skb(new_skb);
@@ -2445,9 +2445,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
* settings -- so we only allow the user to toggle the TX processing.
*/
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_TX;
dev->features = dev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM;
if(register_netdev(dev) < 0) {
err_msg = "unable to register netdev";
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index cab306a9888e..e1d26433d619 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -828,7 +828,7 @@ static int ax_probe(struct platform_device *pdev)
struct ei_device *ei_local;
struct ax_device *ax;
struct resource *irq, *mem, *mem2;
- resource_size_t mem_size, mem2_size = 0;
+ unsigned long mem_size, mem2_size = 0;
int ret = 0;
dev = ax__alloc_ei_netdev(sizeof(struct ax_device));
diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c
index e1b3941bd149..d801c1410fb0 100644
--- a/drivers/net/ethernet/8390/axnet_cs.c
+++ b/drivers/net/ethernet/8390/axnet_cs.c
@@ -728,19 +728,7 @@ static struct pcmcia_driver axnet_cs_driver = {
.suspend = axnet_suspend,
.resume = axnet_resume,
};
-
-static int __init init_axnet_cs(void)
-{
- return pcmcia_register_driver(&axnet_cs_driver);
-}
-
-static void __exit exit_axnet_cs(void)
-{
- pcmcia_unregister_driver(&axnet_cs_driver);
-}
-
-module_init(init_axnet_cs);
-module_exit(exit_axnet_cs);
+module_pcmcia_driver(axnet_cs_driver);
/*====================================================================*/
diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
index de1af0bfed4c..46c5aadaca8e 100644
--- a/drivers/net/ethernet/8390/pcnet_cs.c
+++ b/drivers/net/ethernet/8390/pcnet_cs.c
@@ -1694,16 +1694,4 @@ static struct pcmcia_driver pcnet_driver = {
.suspend = pcnet_suspend,
.resume = pcnet_resume,
};
-
-static int __init init_pcnet_cs(void)
-{
- return pcmcia_register_driver(&pcnet_driver);
-}
-
-static void __exit exit_pcnet_cs(void)
-{
- pcmcia_unregister_driver(&pcnet_driver);
-}
-
-module_init(init_pcnet_cs);
-module_exit(exit_pcnet_cs);
+module_pcmcia_driver(pcnet_driver);
diff --git a/drivers/net/ethernet/adaptec/starfire.c b/drivers/net/ethernet/adaptec/starfire.c
index 549b77500579..8b04bfc20cfb 100644
--- a/drivers/net/ethernet/adaptec/starfire.c
+++ b/drivers/net/ethernet/adaptec/starfire.c
@@ -594,7 +594,8 @@ static const struct ethtool_ops ethtool_ops;
#ifdef VLAN_SUPPORT
-static int netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int netdev_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct netdev_private *np = netdev_priv(dev);
@@ -608,7 +609,8 @@ static int netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int netdev_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct netdev_private *np = netdev_priv(dev);
@@ -702,7 +704,7 @@ static int starfire_init_one(struct pci_dev *pdev,
#endif /* ZEROCOPY */
#ifdef VLAN_SUPPORT
- dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
#endif /* VLAN_RX_KILL_VID */
#ifdef ADDR_64BITS
dev->features |= NETIF_F_HIGHDMA;
@@ -1496,7 +1498,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
printk(KERN_DEBUG " netdev_rx() vlanid = %d\n",
vlid);
}
- __vlan_hwaccel_put_tag(skb, vlid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlid);
}
#endif /* VLAN_SUPPORT */
netif_receive_skb(skb);
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index a175d0be1ae1..ee705771bd2c 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -188,10 +188,9 @@ static int desc_list_init(struct net_device *dev)
/* allocate a new skb for next time receive */
new_skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN);
- if (!new_skb) {
- pr_notice("init: low on mem - packet dropped\n");
+ if (!new_skb)
goto init_error;
- }
+
skb_reserve(new_skb, NET_IP_ALIGN);
/* Invidate the data cache of skb->data range when it is write back
* cache. It will prevent overwritting the new data from DMA
@@ -1236,7 +1235,6 @@ static void bfin_mac_rx(struct net_device *dev)
new_skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN);
if (!new_skb) {
- netdev_notice(dev, "rx: low on mem - packet dropped\n");
dev->stats.rx_dropped++;
goto out;
}
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index 0be2195e5034..269295403fc4 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1464,35 +1464,23 @@ static int greth_of_probe(struct platform_device *ofdev)
}
/* Allocate TX descriptor ring in coherent memory */
- greth->tx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
- 1024,
- &greth->tx_bd_base_phys,
- GFP_KERNEL);
-
+ greth->tx_bd_base = dma_alloc_coherent(greth->dev, 1024,
+ &greth->tx_bd_base_phys,
+ GFP_KERNEL | __GFP_ZERO);
if (!greth->tx_bd_base) {
- if (netif_msg_probe(greth))
- dev_err(&dev->dev, "could not allocate descriptor memory.\n");
err = -ENOMEM;
goto error3;
}
- memset(greth->tx_bd_base, 0, 1024);
-
/* Allocate RX descriptor ring in coherent memory */
- greth->rx_bd_base = (struct greth_bd *) dma_alloc_coherent(greth->dev,
- 1024,
- &greth->rx_bd_base_phys,
- GFP_KERNEL);
-
+ greth->rx_bd_base = dma_alloc_coherent(greth->dev, 1024,
+ &greth->rx_bd_base_phys,
+ GFP_KERNEL | __GFP_ZERO);
if (!greth->rx_bd_base) {
- if (netif_msg_probe(greth))
- dev_err(greth->dev, "could not allocate descriptor memory.\n");
err = -ENOMEM;
goto error4;
}
- memset(greth->rx_bd_base, 0, 1024);
-
/* Get MAC address from: module param, OF property or ID prom */
for (i = 0; i < 6; i++) {
if (macaddr[i] != 0)
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index c0bc41a784ca..b7894f8af9d1 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -472,7 +472,7 @@ static int acenic_probe_one(struct pci_dev *pdev,
ap->name = pci_name(pdev);
dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
dev->watchdog_timeo = 5*HZ;
@@ -2019,7 +2019,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
/* send it up */
if ((bd_flags & BD_FLG_VLAN_TAG))
- __vlan_hwaccel_put_tag(skb, retdesc->vlan);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), retdesc->vlan);
netif_rx(skb);
dev->stats.rx_packets++;
diff --git a/drivers/net/ethernet/amd/7990.c b/drivers/net/ethernet/amd/7990.c
index 6e722dc37db7..65926a956575 100644
--- a/drivers/net/ethernet/amd/7990.c
+++ b/drivers/net/ethernet/amd/7990.c
@@ -318,8 +318,6 @@ static int lance_rx (struct net_device *dev)
struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
if (!skb) {
- printk ("%s: Memory squeeze, deferring packet.\n",
- dev->name);
dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
diff --git a/drivers/net/ethernet/amd/a2065.c b/drivers/net/ethernet/amd/a2065.c
index 3789affbc0e5..0866e7627433 100644
--- a/drivers/net/ethernet/amd/a2065.c
+++ b/drivers/net/ethernet/amd/a2065.c
@@ -293,7 +293,6 @@ static int lance_rx(struct net_device *dev)
struct sk_buff *skb = netdev_alloc_skb(dev, len + 2);
if (!skb) {
- netdev_warn(dev, "Memory squeeze, deferring packet\n");
dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
diff --git a/drivers/net/ethernet/amd/am79c961a.c b/drivers/net/ethernet/amd/am79c961a.c
index 60e2b701afe7..9793767996a2 100644
--- a/drivers/net/ethernet/amd/am79c961a.c
+++ b/drivers/net/ethernet/amd/am79c961a.c
@@ -528,7 +528,6 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv)
dev->stats.rx_packets++;
} else {
am_writeword (dev, hdraddr + 2, RMD_OWN);
- printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
dev->stats.rx_dropped++;
break;
}
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 42d4e6ad58a5..8e6b665a6726 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -793,7 +793,7 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
#if AMD8111E_VLAN_TAG_USED
if (vtag == TT_VLAN_TAGGED){
u16 vlan_tag = le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info);
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
}
#endif
netif_receive_skb(skb);
@@ -1869,7 +1869,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
#if AMD8111E_VLAN_TAG_USED
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX ;
#endif
lp = netdev_priv(dev);
@@ -1907,7 +1907,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev,
netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32);
#if AMD8111E_VLAN_TAG_USED
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
#endif
/* Probe the external PHY */
amd8111e_probe_ext_phy(dev);
diff --git a/drivers/net/ethernet/amd/ariadne.c b/drivers/net/ethernet/amd/ariadne.c
index 98f4522fd17b..c178eb4c8166 100644
--- a/drivers/net/ethernet/amd/ariadne.c
+++ b/drivers/net/ethernet/amd/ariadne.c
@@ -193,7 +193,6 @@ static int ariadne_rx(struct net_device *dev)
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
- netdev_warn(dev, "Memory squeeze, deferring packet\n");
for (i = 0; i < RX_RING_SIZE; i++)
if (lowb(priv->rx_ring[(entry + i) % RX_RING_SIZE]->RMD1) & RF_OWN)
break;
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index 84219df72f51..e8d0ef508f48 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -996,8 +996,6 @@ static int lance_rx( struct net_device *dev )
else {
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
- DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
- dev->name ));
for( i = 0; i < RX_RING_SIZE; i++ )
if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
RMD1_OWN_CHIP)
@@ -1149,9 +1147,7 @@ static struct net_device *atarilance_dev;
static int __init atarilance_module_init(void)
{
atarilance_dev = atarilance_probe(-1);
- if (IS_ERR(atarilance_dev))
- return PTR_ERR(atarilance_dev);
- return 0;
+ return PTR_RET(atarilance_dev);
}
static void __exit atarilance_module_exit(void)
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index de774d419144..688aede742c7 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -727,7 +727,6 @@ static int au1000_rx(struct net_device *dev)
frmlen -= 4; /* Remove FCS */
skb = netdev_alloc_skb(dev, frmlen + 2);
if (skb == NULL) {
- netdev_err(dev, "Memory squeeze, dropping packet.\n");
dev->stats.rx_dropped++;
continue;
}
diff --git a/drivers/net/ethernet/amd/declance.c b/drivers/net/ethernet/amd/declance.c
index baca0bd1b393..3d86ffeb4e15 100644
--- a/drivers/net/ethernet/amd/declance.c
+++ b/drivers/net/ethernet/amd/declance.c
@@ -607,8 +607,6 @@ static int lance_rx(struct net_device *dev)
skb = netdev_alloc_skb(dev, len + 2);
if (skb == 0) {
- printk("%s: Memory squeeze, deferring packet.\n",
- dev->name);
dev->stats.rx_dropped++;
*rds_ptr(rd, mblength, lp->type) = 0;
*rds_ptr(rd, rmd1, lp->type) =
diff --git a/drivers/net/ethernet/amd/mvme147.c b/drivers/net/ethernet/amd/mvme147.c
index 9af3c307862c..a51497c9d2af 100644
--- a/drivers/net/ethernet/amd/mvme147.c
+++ b/drivers/net/ethernet/amd/mvme147.c
@@ -188,9 +188,7 @@ static struct net_device *dev_mvme147_lance;
int __init init_module(void)
{
dev_mvme147_lance = mvme147lance_probe(-1);
- if (IS_ERR(dev_mvme147_lance))
- return PTR_ERR(dev_mvme147_lance);
- return 0;
+ return PTR_RET(dev_mvme147_lance);
}
void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/amd/ni65.c b/drivers/net/ethernet/amd/ni65.c
index 013b65108536..26fc0ce0faa3 100644
--- a/drivers/net/ethernet/amd/ni65.c
+++ b/drivers/net/ethernet/amd/ni65.c
@@ -1238,7 +1238,7 @@ MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
int __init init_module(void)
{
dev_ni65 = ni65_probe(-1);
- return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0;
+ return PTR_RET(dev_ni65);
}
void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 9f59bf63514b..d4ed89130c52 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -1508,16 +1508,4 @@ static struct pcmcia_driver nmclan_cs_driver = {
.suspend = nmclan_suspend,
.resume = nmclan_resume,
};
-
-static int __init init_nmclan_cs(void)
-{
- return pcmcia_register_driver(&nmclan_cs_driver);
-}
-
-static void __exit exit_nmclan_cs(void)
-{
- pcmcia_unregister_driver(&nmclan_cs_driver);
-}
-
-module_init(init_nmclan_cs);
-module_exit(exit_nmclan_cs);
+module_pcmcia_driver(nmclan_cs_driver);
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index 797f847edf13..ed2130727643 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -1166,7 +1166,6 @@ static void pcnet32_rx_entry(struct net_device *dev,
skb = netdev_alloc_skb(dev, pkt_len + NET_IP_ALIGN);
if (skb == NULL) {
- netif_err(lp, drv, dev, "Memory squeeze, dropping packet\n");
dev->stats.rx_dropped++;
return;
}
diff --git a/drivers/net/ethernet/amd/sun3lance.c b/drivers/net/ethernet/amd/sun3lance.c
index 74b3891b6483..4375abe61da1 100644
--- a/drivers/net/ethernet/amd/sun3lance.c
+++ b/drivers/net/ethernet/amd/sun3lance.c
@@ -812,9 +812,6 @@ static int lance_rx( struct net_device *dev )
else {
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
- DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
- dev->name ));
-
dev->stats.rx_dropped++;
head->msg_length = 0;
head->flag |= RMD1_OWN_CHIP;
@@ -943,9 +940,7 @@ static struct net_device *sun3lance_dev;
int __init init_module(void)
{
sun3lance_dev = sun3lance_probe(-1);
- if (IS_ERR(sun3lance_dev))
- return PTR_ERR(sun3lance_dev);
- return 0;
+ return PTR_RET(sun3lance_dev);
}
void __exit cleanup_module(void)
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index 6a40290d3727..f47b780892e9 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -536,8 +536,6 @@ static void lance_rx_dvma(struct net_device *dev)
skb = netdev_alloc_skb(dev, len + 2);
if (skb == NULL) {
- printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
- dev->name);
dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
@@ -708,8 +706,6 @@ static void lance_rx_pio(struct net_device *dev)
skb = netdev_alloc_skb(dev, len + 2);
if (skb == NULL) {
- printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
- dev->name);
dev->stats.rx_dropped++;
sbus_writew(0, &rd->mblength);
sbus_writeb(LE_R1_OWN, &rd->rmd1_bits);
@@ -1377,10 +1373,9 @@ static int sparc_lance_probe_one(struct platform_device *op,
dma_alloc_coherent(&op->dev,
sizeof(struct lance_init_block),
&lp->init_block_dvma, GFP_ATOMIC);
- if (!lp->init_block_mem) {
- printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
+ if (!lp->init_block_mem)
goto fail;
- }
+
lp->pio_buffer = 0;
lp->init_ring = lance_init_ring_dvma;
lp->rx = lance_rx_dvma;
diff --git a/drivers/net/ethernet/apple/macmace.c b/drivers/net/ethernet/apple/macmace.c
index a206779c68cf..4ce8ceb62205 100644
--- a/drivers/net/ethernet/apple/macmace.c
+++ b/drivers/net/ethernet/apple/macmace.c
@@ -386,20 +386,16 @@ static int mace_open(struct net_device *dev)
/* Allocate the DMA ring buffers */
mp->tx_ring = dma_alloc_coherent(mp->device,
- N_TX_RING * MACE_BUFF_SIZE,
- &mp->tx_ring_phys, GFP_KERNEL);
- if (mp->tx_ring == NULL) {
- printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name);
+ N_TX_RING * MACE_BUFF_SIZE,
+ &mp->tx_ring_phys, GFP_KERNEL);
+ if (mp->tx_ring == NULL)
goto out1;
- }
mp->rx_ring = dma_alloc_coherent(mp->device,
- N_RX_RING * MACE_BUFF_SIZE,
- &mp->rx_ring_phys, GFP_KERNEL);
- if (mp->rx_ring == NULL) {
- printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name);
+ N_RX_RING * MACE_BUFF_SIZE,
+ &mp->rx_ring_phys, GFP_KERNEL);
+ if (mp->rx_ring == NULL)
goto out2;
- }
mace_dma_off(dev);
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
index 21e261ffbe10..3ef7092e3f1c 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_hw.c
@@ -810,7 +810,7 @@ int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc)
if (wufc & AT_WUFC_LNKC) {
wol_ctrl |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
- dev_dbg(&pdev->dev, "%s: write phy MII_IER faild.\n",
+ dev_dbg(&pdev->dev, "%s: write phy MII_IER failed.\n",
atl1c_driver_name);
}
}
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 1f07fc633ab9..0ba900762b13 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -417,7 +417,7 @@ static void atl1c_set_multi(struct net_device *netdev)
static void __atl1c_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
{
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* enable VLAN tag insert/strip */
*mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
} else {
@@ -494,10 +494,10 @@ static netdev_features_t atl1c_fix_features(struct net_device *netdev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
if (netdev->mtu > MAX_TSO_FRAME_SIZE)
features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
@@ -510,7 +510,7 @@ static int atl1c_set_features(struct net_device *netdev,
{
netdev_features_t changed = netdev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
atl1c_vlan_mode(netdev, features);
return 0;
@@ -1809,7 +1809,7 @@ rrs_checked:
AT_TAG_TO_VLAN(rrs->vlan_tag, vlan);
vlan = le16_to_cpu(vlan);
- __vlan_hwaccel_put_tag(skb, vlan);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
}
netif_receive_skb(skb);
@@ -2475,13 +2475,13 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
atl1c_set_ethtool_ops(netdev);
/* TODO: add when ready */
- netdev->hw_features = NETIF_F_SG |
- NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_TSO |
+ netdev->hw_features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_TSO |
NETIF_F_TSO6;
- netdev->features = netdev->hw_features |
- NETIF_F_HW_VLAN_TX;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_CTAG_TX;
return 0;
}
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e.h b/drivers/net/ethernet/atheros/atl1e/atl1e.h
index 829b5ad71d0d..b5fd934585e9 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e.h
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e.h
@@ -186,7 +186,7 @@ struct atl1e_tpd_desc {
/* how about 0x2000 */
#define MAX_TX_BUF_LEN 0x2000
#define MAX_TX_BUF_SHIFT 13
-/*#define MAX_TX_BUF_LEN 0x3000 */
+#define MAX_TSO_SEG_SIZE 0x3c00
/* rrs word 1 bit 0:31 */
#define RRS_RX_CSUM_MASK 0xFFFF
@@ -438,7 +438,6 @@ struct atl1e_adapter {
struct atl1e_hw hw;
struct atl1e_hw_stats hw_stats;
- bool have_msi;
u32 wol;
u16 link_speed;
u16 link_duplex;
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index 92f4734f860d..0688bb82b442 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -315,7 +315,7 @@ static void atl1e_set_multi(struct net_device *netdev)
static void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
{
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* enable VLAN tag insert/strip */
*mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
} else {
@@ -378,10 +378,10 @@ static netdev_features_t atl1e_fix_features(struct net_device *netdev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -391,7 +391,7 @@ static int atl1e_set_features(struct net_device *netdev,
{
netdev_features_t changed = netdev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
atl1e_vlan_mode(netdev, features);
return 0;
@@ -1420,11 +1420,9 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
packet_size = ((prrs->word1 >> RRS_PKT_SIZE_SHIFT) &
RRS_PKT_SIZE_MASK) - 4; /* CRC */
skb = netdev_alloc_skb_ip_align(netdev, packet_size);
- if (skb == NULL) {
- netdev_warn(netdev,
- "Memory squeeze, deferring packet\n");
+ if (skb == NULL)
goto skip_pkt;
- }
+
memcpy(skb->data, (u8 *)(prrs + 1), packet_size);
skb_put(skb, packet_size);
skb->protocol = eth_type_trans(skb, netdev);
@@ -1437,7 +1435,7 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
netdev_dbg(netdev,
"RXD VLAN TAG<RRD>=0x%04x\n",
prrs->vtag);
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
}
netif_receive_skb(skb);
@@ -1849,34 +1847,19 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter)
struct net_device *netdev = adapter->netdev;
free_irq(adapter->pdev->irq, netdev);
-
- if (adapter->have_msi)
- pci_disable_msi(adapter->pdev);
}
static int atl1e_request_irq(struct atl1e_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
- int flags = 0;
int err = 0;
- adapter->have_msi = true;
- err = pci_enable_msi(pdev);
- if (err) {
- netdev_dbg(netdev,
- "Unable to allocate MSI interrupt Error: %d\n", err);
- adapter->have_msi = false;
- }
-
- if (!adapter->have_msi)
- flags |= IRQF_SHARED;
- err = request_irq(pdev->irq, atl1e_intr, flags, netdev->name, netdev);
+ err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name,
+ netdev);
if (err) {
netdev_dbg(adapter->netdev,
"Unable to allocate interrupt Error: %d\n", err);
- if (adapter->have_msi)
- pci_disable_msi(pdev);
return err;
}
netdev_dbg(netdev, "atl1e_request_irq OK\n");
@@ -2215,9 +2198,9 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
atl1e_set_ethtool_ops(netdev);
netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
- NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_RX;
netdev->features = netdev->hw_features | NETIF_F_LLTX |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_TX;
return 0;
}
@@ -2344,6 +2327,7 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->reset_task, atl1e_reset_task);
INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
+ netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);
err = register_netdev(netdev);
if (err) {
netdev_err(netdev, "register netdevice failed\n");
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 5b0d9931c720..fa0915f3999b 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -2024,7 +2024,7 @@ rrd_ok:
((rrd->vlan_tag & 7) << 13) |
((rrd->vlan_tag & 8) << 9);
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
}
netif_receive_skb(skb);
@@ -2774,7 +2774,7 @@ static int atl1_close(struct net_device *netdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int atl1_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2876,23 +2876,18 @@ static int atl1_resume(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(atl1_pm_ops, atl1_suspend, atl1_resume);
-#define ATL1_PM_OPS (&atl1_pm_ops)
-
-#else
-
-static int atl1_suspend(struct device *dev) { return 0; }
-
-#define ATL1_PM_OPS NULL
-#endif
static void atl1_shutdown(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1_adapter *adapter = netdev_priv(netdev);
+#ifdef CONFIG_PM_SLEEP
atl1_suspend(&pdev->dev);
+#endif
pci_wake_from_d3(pdev, adapter->wol);
pci_set_power_state(pdev, PCI_D3hot);
}
@@ -3023,10 +3018,10 @@ static int atl1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->features = NETIF_F_HW_CSUM;
netdev->features |= NETIF_F_SG;
- netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+ netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO |
- NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_RX;
/* is this valid? see atl1_setup_mac_ctrl() */
netdev->features |= NETIF_F_RXCSUM;
@@ -3147,7 +3142,7 @@ static struct pci_driver atl1_driver = {
.probe = atl1_probe,
.remove = atl1_remove,
.shutdown = atl1_shutdown,
- .driver.pm = ATL1_PM_OPS,
+ .driver.pm = &atl1_pm_ops,
};
/**
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index 1278b47022e0..265ce1b752ed 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -363,7 +363,7 @@ static inline void atl2_irq_disable(struct atl2_adapter *adapter)
static void __atl2_vlan_mode(netdev_features_t features, u32 *ctrl)
{
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* enable VLAN tag insert/strip */
*ctrl |= MAC_CTRL_RMV_VLAN;
} else {
@@ -399,10 +399,10 @@ static netdev_features_t atl2_fix_features(struct net_device *netdev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -412,7 +412,7 @@ static int atl2_set_features(struct net_device *netdev,
{
netdev_features_t changed = netdev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
atl2_vlan_mode(netdev, features);
return 0;
@@ -437,9 +437,6 @@ static void atl2_intr_rx(struct atl2_adapter *adapter)
/* alloc new buffer */
skb = netdev_alloc_skb_ip_align(netdev, rx_size);
if (NULL == skb) {
- printk(KERN_WARNING
- "%s: Mem squeeze, deferring packet.\n",
- netdev->name);
/*
* Check that some rx space is free. If not,
* free one and mark stats->rx_dropped++.
@@ -455,7 +452,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter)
((rxd->status.vtag&7) << 13) |
((rxd->status.vtag&8) << 9);
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
}
netif_rx(skb);
netdev->stats.rx_bytes += rx_size;
@@ -890,7 +887,7 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb,
skb->len-copy_len);
offset = ((u32)(skb->len-copy_len + 3) & ~3);
}
-#ifdef NETIF_F_HW_VLAN_TX
+#ifdef NETIF_F_HW_VLAN_CTAG_TX
if (vlan_tx_tag_present(skb)) {
u16 vlan_tag = vlan_tx_tag_get(skb);
vlan_tag = (vlan_tag << 4) |
@@ -1416,8 +1413,8 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -EIO;
- netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_RX;
- netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+ netdev->hw_features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_RX;
+ netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
/* Init PHY as early as possible due to power saving issue */
atl2_phy_init(&adapter->hw);
diff --git a/drivers/net/ethernet/atheros/atlx/atlx.c b/drivers/net/ethernet/atheros/atlx/atlx.c
index f82eb1699464..46a622cceee4 100644
--- a/drivers/net/ethernet/atheros/atlx/atlx.c
+++ b/drivers/net/ethernet/atheros/atlx/atlx.c
@@ -220,7 +220,7 @@ static void atlx_link_chg_task(struct work_struct *work)
static void __atlx_vlan_mode(netdev_features_t features, u32 *ctrl)
{
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* enable VLAN tag insert/strip */
*ctrl |= MAC_CTRL_RMV_VLAN;
} else {
@@ -257,10 +257,10 @@ static netdev_features_t atlx_fix_features(struct net_device *netdev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -270,7 +270,7 @@ static int atlx_set_features(struct net_device *netdev,
{
netdev_features_t changed = netdev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
atlx_vlan_mode(netdev, features);
return 0;
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 7d81e059e811..0b3e23ec37f7 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -862,27 +862,25 @@ static int bcm_enet_open(struct net_device *dev)
/* allocate rx dma ring */
size = priv->rx_ring_size * sizeof(struct bcm_enet_desc);
- p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL);
+ p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!p) {
- dev_err(kdev, "cannot allocate rx ring %u\n", size);
ret = -ENOMEM;
goto out_freeirq_tx;
}
- memset(p, 0, size);
priv->rx_desc_alloc_size = size;
priv->rx_desc_cpu = p;
/* allocate tx dma ring */
size = priv->tx_ring_size * sizeof(struct bcm_enet_desc);
- p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL);
+ p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!p) {
- dev_err(kdev, "cannot allocate tx ring\n");
ret = -ENOMEM;
goto out_free_rx_ring;
}
- memset(p, 0, size);
priv->tx_desc_alloc_size = size;
priv->tx_desc_cpu = p;
@@ -1619,7 +1617,6 @@ static int bcm_enet_probe(struct platform_device *pdev)
struct resource *res_mem, *res_irq, *res_irq_rx, *res_irq_tx;
struct mii_bus *bus;
const char *clk_name;
- unsigned int iomem_size;
int i, ret;
/* stop if shared driver failed, assume driver->probe will be
@@ -1644,17 +1641,12 @@ static int bcm_enet_probe(struct platform_device *pdev)
if (ret)
goto out;
- iomem_size = resource_size(res_mem);
- if (!request_mem_region(res_mem->start, iomem_size, "bcm63xx_enet")) {
- ret = -EBUSY;
- goto out;
- }
-
- priv->base = ioremap(res_mem->start, iomem_size);
+ priv->base = devm_request_and_ioremap(&pdev->dev, res_mem);
if (priv->base == NULL) {
ret = -ENOMEM;
- goto out_release_mem;
+ goto out;
}
+
dev->irq = priv->irq = res_irq->start;
priv->irq_rx = res_irq_rx->start;
priv->irq_tx = res_irq_tx->start;
@@ -1674,9 +1666,9 @@ static int bcm_enet_probe(struct platform_device *pdev)
priv->mac_clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(priv->mac_clk)) {
ret = PTR_ERR(priv->mac_clk);
- goto out_unmap;
+ goto out;
}
- clk_enable(priv->mac_clk);
+ clk_prepare_enable(priv->mac_clk);
/* initialize default and fetch platform data */
priv->rx_ring_size = BCMENET_DEF_RX_DESC;
@@ -1705,7 +1697,7 @@ static int bcm_enet_probe(struct platform_device *pdev)
priv->phy_clk = NULL;
goto out_put_clk_mac;
}
- clk_enable(priv->phy_clk);
+ clk_prepare_enable(priv->phy_clk);
}
/* do minimal hardware init to be able to probe mii bus */
@@ -1733,7 +1725,8 @@ static int bcm_enet_probe(struct platform_device *pdev)
* if a slave is not present on hw */
bus->phy_mask = ~(1 << priv->phy_id);
- bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ bus->irq = devm_kzalloc(&pdev->dev, sizeof(int) * PHY_MAX_ADDR,
+ GFP_KERNEL);
if (!bus->irq) {
ret = -ENOMEM;
goto out_free_mdio;
@@ -1794,10 +1787,8 @@ static int bcm_enet_probe(struct platform_device *pdev)
return 0;
out_unregister_mdio:
- if (priv->mii_bus) {
+ if (priv->mii_bus)
mdiobus_unregister(priv->mii_bus);
- kfree(priv->mii_bus->irq);
- }
out_free_mdio:
if (priv->mii_bus)
@@ -1807,19 +1798,13 @@ out_uninit_hw:
/* turn off mdc clock */
enet_writel(priv, 0, ENET_MIISC_REG);
if (priv->phy_clk) {
- clk_disable(priv->phy_clk);
+ clk_disable_unprepare(priv->phy_clk);
clk_put(priv->phy_clk);
}
out_put_clk_mac:
- clk_disable(priv->mac_clk);
+ clk_disable_unprepare(priv->mac_clk);
clk_put(priv->mac_clk);
-
-out_unmap:
- iounmap(priv->base);
-
-out_release_mem:
- release_mem_region(res_mem->start, iomem_size);
out:
free_netdev(dev);
return ret;
@@ -1833,7 +1818,6 @@ static int bcm_enet_remove(struct platform_device *pdev)
{
struct bcm_enet_priv *priv;
struct net_device *dev;
- struct resource *res;
/* stop netdevice */
dev = platform_get_drvdata(pdev);
@@ -1845,7 +1829,6 @@ static int bcm_enet_remove(struct platform_device *pdev)
if (priv->has_phy) {
mdiobus_unregister(priv->mii_bus);
- kfree(priv->mii_bus->irq);
mdiobus_free(priv->mii_bus);
} else {
struct bcm63xx_enet_platform_data *pd;
@@ -1856,17 +1839,12 @@ static int bcm_enet_remove(struct platform_device *pdev)
bcm_enet_mdio_write_mii);
}
- /* release device resources */
- iounmap(priv->base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
/* disable hw block clocks */
if (priv->phy_clk) {
- clk_disable(priv->phy_clk);
+ clk_disable_unprepare(priv->phy_clk);
clk_put(priv->phy_clk);
}
- clk_disable(priv->mac_clk);
+ clk_disable_unprepare(priv->mac_clk);
clk_put(priv->mac_clk);
platform_set_drvdata(pdev, NULL);
@@ -1889,31 +1867,20 @@ struct platform_driver bcm63xx_enet_driver = {
static int bcm_enet_shared_probe(struct platform_device *pdev)
{
struct resource *res;
- unsigned int iomem_size;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- iomem_size = resource_size(res);
- if (!request_mem_region(res->start, iomem_size, "bcm63xx_enet_dma"))
- return -EBUSY;
-
- bcm_enet_shared_base = ioremap(res->start, iomem_size);
- if (!bcm_enet_shared_base) {
- release_mem_region(res->start, iomem_size);
+ bcm_enet_shared_base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!bcm_enet_shared_base)
return -ENOMEM;
- }
+
return 0;
}
static int bcm_enet_shared_remove(struct platform_device *pdev)
{
- struct resource *res;
-
- iounmap(bcm_enet_shared_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
return 0;
}
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index da5f4397f87c..eec0af45b859 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <bcm47xx_nvram.h>
@@ -244,10 +245,8 @@ static int bgmac_dma_rx_skb_for_slot(struct bgmac *bgmac,
/* Alloc skb */
slot->skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
- if (!slot->skb) {
- bgmac_err(bgmac, "Allocation of skb failed!\n");
+ if (!slot->skb)
return -ENOMEM;
- }
/* Poison - if everything goes fine, hardware will overwrite it */
rx = (struct bgmac_rx_header *)slot->skb->data;
@@ -1313,6 +1312,73 @@ static const struct ethtool_ops bgmac_ethtool_ops = {
};
/**************************************************
+ * MII
+ **************************************************/
+
+static int bgmac_mii_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ return bgmac_phy_read(bus->priv, mii_id, regnum);
+}
+
+static int bgmac_mii_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ return bgmac_phy_write(bus->priv, mii_id, regnum, value);
+}
+
+static int bgmac_mii_register(struct bgmac *bgmac)
+{
+ struct mii_bus *mii_bus;
+ int i, err = 0;
+
+ mii_bus = mdiobus_alloc();
+ if (!mii_bus)
+ return -ENOMEM;
+
+ mii_bus->name = "bgmac mii bus";
+ sprintf(mii_bus->id, "%s-%d-%d", "bgmac", bgmac->core->bus->num,
+ bgmac->core->core_unit);
+ mii_bus->priv = bgmac;
+ mii_bus->read = bgmac_mii_read;
+ mii_bus->write = bgmac_mii_write;
+ mii_bus->parent = &bgmac->core->dev;
+ mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
+
+ mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+ if (!mii_bus->irq) {
+ err = -ENOMEM;
+ goto err_free_bus;
+ }
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ mii_bus->irq[i] = PHY_POLL;
+
+ err = mdiobus_register(mii_bus);
+ if (err) {
+ bgmac_err(bgmac, "Registration of mii bus failed\n");
+ goto err_free_irq;
+ }
+
+ bgmac->mii_bus = mii_bus;
+
+ return err;
+
+err_free_irq:
+ kfree(mii_bus->irq);
+err_free_bus:
+ mdiobus_free(mii_bus);
+ return err;
+}
+
+static void bgmac_mii_unregister(struct bgmac *bgmac)
+{
+ struct mii_bus *mii_bus = bgmac->mii_bus;
+
+ mdiobus_unregister(mii_bus);
+ kfree(mii_bus->irq);
+ mdiobus_free(mii_bus);
+}
+
+/**************************************************
* BCMA bus ops
**************************************************/
@@ -1404,11 +1470,18 @@ static int bgmac_probe(struct bcma_device *core)
if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
+ err = bgmac_mii_register(bgmac);
+ if (err) {
+ bgmac_err(bgmac, "Cannot register MDIO\n");
+ err = -ENOTSUPP;
+ goto err_dma_free;
+ }
+
err = register_netdev(bgmac->net_dev);
if (err) {
bgmac_err(bgmac, "Cannot register net device\n");
err = -ENOTSUPP;
- goto err_dma_free;
+ goto err_mii_unregister;
}
netif_carrier_off(net_dev);
@@ -1417,6 +1490,8 @@ static int bgmac_probe(struct bcma_device *core)
return 0;
+err_mii_unregister:
+ bgmac_mii_unregister(bgmac);
err_dma_free:
bgmac_dma_free(bgmac);
@@ -1433,6 +1508,7 @@ static void bgmac_remove(struct bcma_device *core)
netif_napi_del(&bgmac->napi);
unregister_netdev(bgmac->net_dev);
+ bgmac_mii_unregister(bgmac);
bgmac_dma_free(bgmac);
bcma_set_drvdata(core, NULL);
free_netdev(bgmac->net_dev);
diff --git a/drivers/net/ethernet/broadcom/bgmac.h b/drivers/net/ethernet/broadcom/bgmac.h
index 4ede614c81f8..98d4b5fcc070 100644
--- a/drivers/net/ethernet/broadcom/bgmac.h
+++ b/drivers/net/ethernet/broadcom/bgmac.h
@@ -399,6 +399,7 @@ struct bgmac {
struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
struct net_device *net_dev;
struct napi_struct napi;
+ struct mii_bus *mii_bus;
/* DMA */
struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 2f0ba8f2fd6c..5d204492c603 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -416,7 +416,7 @@ static int bnx2_unregister_cnic(struct net_device *dev)
return 0;
}
-struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
+static struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
{
struct bnx2 *bp = netdev_priv(dev);
struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
@@ -854,12 +854,11 @@ bnx2_alloc_mem(struct bnx2 *bp)
sizeof(struct statistics_block);
status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size,
- &bp->status_blk_mapping, GFP_KERNEL);
+ &bp->status_blk_mapping,
+ GFP_KERNEL | __GFP_ZERO);
if (status_blk == NULL)
goto alloc_mem_err;
- memset(status_blk, 0, bp->status_stats_size);
-
bnapi = &bp->bnx2_napi[0];
bnapi->status_blk.msi = status_blk;
bnapi->hw_tx_cons_ptr =
@@ -3212,7 +3211,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
}
if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
- __vlan_hwaccel_put_tag(skb, rx_hdr->l2_fhdr_vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag);
skb->protocol = eth_type_trans(skb, bp->dev);
@@ -3554,7 +3553,7 @@ bnx2_set_rx_mode(struct net_device *dev)
rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
- if (!(dev->features & NETIF_F_HW_VLAN_RX) &&
+ if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
if (dev->flags & IFF_PROMISC) {
@@ -7696,7 +7695,7 @@ bnx2_fix_features(struct net_device *dev, netdev_features_t features)
struct bnx2 *bp = netdev_priv(dev);
if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
- features |= NETIF_F_HW_VLAN_RX;
+ features |= NETIF_F_HW_VLAN_CTAG_RX;
return features;
}
@@ -7707,12 +7706,12 @@ bnx2_set_features(struct net_device *dev, netdev_features_t features)
struct bnx2 *bp = netdev_priv(dev);
/* TSO with VLAN tag won't work with current firmware */
- if (features & NETIF_F_HW_VLAN_TX)
+ if (features & NETIF_F_HW_VLAN_CTAG_TX)
dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
else
dev->vlan_features &= ~NETIF_F_ALL_TSO;
- if ((!!(features & NETIF_F_HW_VLAN_RX) !=
+ if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) !=
!!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
netif_running(dev)) {
bnx2_netif_stop(bp, false);
@@ -8552,7 +8551,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
dev->vlan_features = dev->hw_features;
- dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
dev->features |= dev->hw_features;
dev->priv_flags |= IFF_UNICAST_FLT;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index e4605a965084..3dba2a70a00e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -26,8 +26,8 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.78.02-0"
-#define DRV_MODULE_RELDATE "2013/01/14"
+#define DRV_MODULE_VERSION "1.78.17-0"
+#define DRV_MODULE_RELDATE "2013/04/11"
#define BNX2X_BC_VER 0x040200
#if defined(CONFIG_DCB)
@@ -492,7 +492,6 @@ enum bnx2x_tpa_mode_t {
struct bnx2x_fastpath {
struct bnx2x *bp; /* parent */
-#define BNX2X_NAPI_WEIGHT 128
struct napi_struct napi;
union host_hc_status_block status_blk;
/* chip independed shortcuts into sb structure */
@@ -613,9 +612,10 @@ struct bnx2x_fastpath {
* START_BD - describes packed
* START_BD(splitted) - includes unpaged data segment for GSO
* PARSING_BD - for TSO and CSUM data
+ * PARSING_BD2 - for encapsulation data
* Frag BDs - decribes pages for frags
*/
-#define BDS_PER_TX_PKT 3
+#define BDS_PER_TX_PKT 4
#define MAX_BDS_PER_TX_PKT (MAX_SKB_FRAGS + BDS_PER_TX_PKT)
/* max BDs per tx packet including next pages */
#define MAX_DESC_PER_TX_PKT (MAX_BDS_PER_TX_PKT + \
@@ -730,18 +730,24 @@ struct bnx2x_fastpath {
#define SKB_CS(skb) (*(u16 *)(skb_transport_header(skb) + \
skb->csum_offset))
-#define pbd_tcp_flags(skb) (ntohl(tcp_flag_word(tcp_hdr(skb)))>>16 & 0xff)
+#define pbd_tcp_flags(tcp_hdr) (ntohl(tcp_flag_word(tcp_hdr))>>16 & 0xff)
-#define XMIT_PLAIN 0
-#define XMIT_CSUM_V4 0x1
-#define XMIT_CSUM_V6 0x2
-#define XMIT_CSUM_TCP 0x4
-#define XMIT_GSO_V4 0x8
-#define XMIT_GSO_V6 0x10
+#define XMIT_PLAIN 0
+#define XMIT_CSUM_V4 (1 << 0)
+#define XMIT_CSUM_V6 (1 << 1)
+#define XMIT_CSUM_TCP (1 << 2)
+#define XMIT_GSO_V4 (1 << 3)
+#define XMIT_GSO_V6 (1 << 4)
+#define XMIT_CSUM_ENC_V4 (1 << 5)
+#define XMIT_CSUM_ENC_V6 (1 << 6)
+#define XMIT_GSO_ENC_V4 (1 << 7)
+#define XMIT_GSO_ENC_V6 (1 << 8)
-#define XMIT_CSUM (XMIT_CSUM_V4 | XMIT_CSUM_V6)
-#define XMIT_GSO (XMIT_GSO_V4 | XMIT_GSO_V6)
+#define XMIT_CSUM_ENC (XMIT_CSUM_ENC_V4 | XMIT_CSUM_ENC_V6)
+#define XMIT_GSO_ENC (XMIT_GSO_ENC_V4 | XMIT_GSO_ENC_V6)
+#define XMIT_CSUM (XMIT_CSUM_V4 | XMIT_CSUM_V6 | XMIT_CSUM_ENC)
+#define XMIT_GSO (XMIT_GSO_V4 | XMIT_GSO_V6 | XMIT_GSO_ENC)
/* stuff added to make the code fit 80Col */
#define CQE_TYPE(cqe_fp_flags) ((cqe_fp_flags) & ETH_FAST_PATH_RX_CQE_TYPE)
@@ -844,6 +850,9 @@ struct bnx2x_common {
#define CHIP_IS_57840_VF(bp) (CHIP_NUM(bp) == CHIP_NUM_57840_VF)
#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \
CHIP_IS_57711E(bp))
+#define CHIP_IS_57811xx(bp) (CHIP_IS_57811(bp) || \
+ CHIP_IS_57811_MF(bp) || \
+ CHIP_IS_57811_VF(bp))
#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \
CHIP_IS_57712_MF(bp) || \
CHIP_IS_57712_VF(bp))
@@ -853,9 +862,7 @@ struct bnx2x_common {
CHIP_IS_57810(bp) || \
CHIP_IS_57810_MF(bp) || \
CHIP_IS_57810_VF(bp) || \
- CHIP_IS_57811(bp) || \
- CHIP_IS_57811_MF(bp) || \
- CHIP_IS_57811_VF(bp) || \
+ CHIP_IS_57811xx(bp) || \
CHIP_IS_57840(bp) || \
CHIP_IS_57840_MF(bp) || \
CHIP_IS_57840_VF(bp))
@@ -1215,14 +1222,16 @@ enum {
BNX2X_SP_RTNL_ENABLE_SRIOV,
BNX2X_SP_RTNL_VFPF_MCAST,
BNX2X_SP_RTNL_VFPF_STORM_RX_MODE,
+ BNX2X_SP_RTNL_HYPERVISOR_VLAN,
};
struct bnx2x_prev_path_list {
+ struct list_head list;
u8 bus;
u8 slot;
u8 path;
- struct list_head list;
+ u8 aer;
u8 undi;
};
@@ -1269,6 +1278,8 @@ struct bnx2x {
#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
#ifdef CONFIG_BNX2X_SRIOV
+ /* protects vf2pf mailbox from simultaneous access */
+ struct mutex vf2pf_mutex;
/* vf pf channel mailbox contains request and response buffers */
struct bnx2x_vf_mbx_msg *vf2pf_mbox;
dma_addr_t vf2pf_mbox_mapping;
@@ -1281,6 +1292,8 @@ struct bnx2x {
dma_addr_t pf2vf_bulletin_mapping;
struct pf_vf_bulletin_content old_bulletin;
+
+ u16 requested_nr_virtfn;
#endif /* CONFIG_BNX2X_SRIOV */
struct net_device *dev;
@@ -1944,12 +1957,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
bool is_pf);
-#define BNX2X_ILT_ZALLOC(x, y, size) \
- do { \
- x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
- if (x) \
- memset(x, 0, size); \
- } while (0)
+#define BNX2X_ILT_ZALLOC(x, y, size) \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, \
+ GFP_KERNEL | __GFP_ZERO)
#define BNX2X_ILT_FREE(x, y, size) \
do { \
@@ -2286,7 +2296,7 @@ static const u32 dmae_reg_go_c[] = {
DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
};
-void bnx2x_set_ethtool_ops(struct net_device *netdev);
+void bnx2x_set_ethtool_ops(struct bnx2x *bp, struct net_device *netdev);
void bnx2x_notify_link_changed(struct bnx2x *bp);
#define BNX2X_MF_SD_PROTOCOL(bp) \
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 4046f97378c2..b8fbe266ab68 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -451,7 +451,8 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
* Compute number of aggregated segments, and gso_type.
*/
static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
- u16 len_on_bd, unsigned int pkt_len)
+ u16 len_on_bd, unsigned int pkt_len,
+ u16 num_of_coalesced_segs)
{
/* TPA aggregation won't have either IP options or TCP options
* other than timestamp or IPv6 extension headers.
@@ -480,8 +481,7 @@ static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
/* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count
* to skb_shinfo(skb)->gso_segs
*/
- NAPI_GRO_CB(skb)->count = DIV_ROUND_UP(pkt_len - hdrs_len,
- skb_shinfo(skb)->gso_size);
+ NAPI_GRO_CB(skb)->count = num_of_coalesced_segs;
}
static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
@@ -537,7 +537,8 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* This is needed in order to enable forwarding support */
if (frag_size)
bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd,
- le16_to_cpu(cqe->pkt_len));
+ le16_to_cpu(cqe->pkt_len),
+ le16_to_cpu(cqe->num_of_coalesced_segs));
#ifdef BNX2X_STOP_ON_ERROR
if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) {
@@ -641,6 +642,14 @@ static void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb)
th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
&iph->saddr, &iph->daddr, 0);
}
+
+static void bnx2x_gro_csum(struct bnx2x *bp, struct sk_buff *skb,
+ void (*gro_func)(struct bnx2x*, struct sk_buff*))
+{
+ skb_set_network_header(skb, 0);
+ gro_func(bp, skb);
+ tcp_gro_complete(skb);
+}
#endif
static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
@@ -648,19 +657,17 @@ static void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp,
{
#ifdef CONFIG_INET
if (skb_shinfo(skb)->gso_size) {
- skb_set_network_header(skb, 0);
switch (be16_to_cpu(skb->protocol)) {
case ETH_P_IP:
- bnx2x_gro_ip_csum(bp, skb);
+ bnx2x_gro_csum(bp, skb, bnx2x_gro_ip_csum);
break;
case ETH_P_IPV6:
- bnx2x_gro_ipv6_csum(bp, skb);
+ bnx2x_gro_csum(bp, skb, bnx2x_gro_ipv6_csum);
break;
default:
- BNX2X_ERR("FW GRO supports only IPv4/IPv6, not 0x%04x\n",
+ BNX2X_ERR("Error: FW GRO supports only IPv4/IPv6, not 0x%04x\n",
be16_to_cpu(skb->protocol));
}
- tcp_gro_complete(skb);
}
#endif
napi_gro_receive(&fp->napi, skb);
@@ -718,7 +725,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
if (!bnx2x_fill_frag_skb(bp, fp, tpa_info, pages,
skb, cqe, cqe_idx)) {
if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN)
- __vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tpa_info->vlan_tag);
bnx2x_gro_receive(bp, fp, skb);
} else {
DP(NETIF_MSG_RX_STATUS,
@@ -993,7 +1000,7 @@ reuse_rx:
if (le16_to_cpu(cqe_fp->pars_flags.flags) &
PARSING_FLAGS_VLAN)
- __vlan_hwaccel_put_tag(skb,
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(cqe_fp->vlan_tag));
napi_gro_receive(&fp->napi, skb);
@@ -1037,6 +1044,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
DP(NETIF_MSG_INTR,
"got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n",
fp->index, fp->fw_sb_id, fp->igu_sb_id);
+
bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0);
#ifdef BNX2X_STOP_ON_ERROR
@@ -1718,7 +1726,7 @@ static int bnx2x_req_irq(struct bnx2x *bp)
return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev);
}
-static int bnx2x_setup_irqs(struct bnx2x *bp)
+int bnx2x_setup_irqs(struct bnx2x *bp)
{
int rc = 0;
if (bp->flags & USING_MSIX_FLAG &&
@@ -2009,7 +2017,7 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
* Cleans the object that have internal lists without sending
* ramrods. Should be run when interrutps are disabled.
*/
-static void bnx2x_squeeze_objects(struct bnx2x *bp)
+void bnx2x_squeeze_objects(struct bnx2x *bp)
{
int rc;
unsigned long ramrod_flags = 0, vlan_mac_flags = 0;
@@ -2574,6 +2582,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
}
+ bnx2x_pre_irq_nic_init(bp);
+
/* Connect to IRQs */
rc = bnx2x_setup_irqs(bp);
if (rc) {
@@ -2583,11 +2593,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
LOAD_ERROR_EXIT(bp, load_error2);
}
- /* Setup NIC internals and enable interrupts */
- bnx2x_nic_init(bp, load_code);
-
/* Init per-function objects */
if (IS_PF(bp)) {
+ /* Setup NIC internals and enable interrupts */
+ bnx2x_post_irq_nic_init(bp, load_code);
+
bnx2x_init_bp_objs(bp);
bnx2x_iov_nic_init(bp);
@@ -2614,6 +2624,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
}
+ /* initialize FW coalescing state machines in RAM */
+ bnx2x_update_coalesce(bp);
+
/* setup the leading queue */
rc = bnx2x_setup_leading(bp);
if (rc) {
@@ -2654,7 +2667,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
if (IS_PF(bp))
rc = bnx2x_set_eth_mac(bp, true);
else /* vf */
- rc = bnx2x_vfpf_set_mac(bp);
+ rc = bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index,
+ true);
if (rc) {
BNX2X_ERR("Setting Ethernet MAC failed\n");
LOAD_ERROR_EXIT(bp, load_error3);
@@ -2774,7 +2788,7 @@ load_error0:
#endif /* ! BNX2X_STOP_ON_ERROR */
}
-static int bnx2x_drain_tx_queues(struct bnx2x *bp)
+int bnx2x_drain_tx_queues(struct bnx2x *bp)
{
u8 rc = 0, cos, i;
@@ -2923,9 +2937,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
bnx2x_free_fp_mem_cnic(bp);
if (IS_PF(bp)) {
- bnx2x_free_mem(bp);
if (CNIC_LOADED(bp))
bnx2x_free_mem_cnic(bp);
+ bnx2x_free_mem(bp);
}
bp->state = BNX2X_STATE_CLOSED;
bp->cnic_loaded = false;
@@ -3086,11 +3100,11 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
* to ease the pain of our fellow microcode engineers
* we use one mapping for both BDs
*/
-static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
- struct bnx2x_fp_txdata *txdata,
- struct sw_tx_bd *tx_buf,
- struct eth_tx_start_bd **tx_bd, u16 hlen,
- u16 bd_prod, int nbd)
+static u16 bnx2x_tx_split(struct bnx2x *bp,
+ struct bnx2x_fp_txdata *txdata,
+ struct sw_tx_bd *tx_buf,
+ struct eth_tx_start_bd **tx_bd, u16 hlen,
+ u16 bd_prod)
{
struct eth_tx_start_bd *h_tx_bd = *tx_bd;
struct eth_tx_bd *d_tx_bd;
@@ -3098,11 +3112,10 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
int old_len = le16_to_cpu(h_tx_bd->nbytes);
/* first fix first BD */
- h_tx_bd->nbd = cpu_to_le16(nbd);
h_tx_bd->nbytes = cpu_to_le16(hlen);
- DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d (%x:%x) nbd %d\n",
- h_tx_bd->nbytes, h_tx_bd->addr_hi, h_tx_bd->addr_lo, h_tx_bd->nbd);
+ DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d (%x:%x)\n",
+ h_tx_bd->nbytes, h_tx_bd->addr_hi, h_tx_bd->addr_lo);
/* now get a new data BD
* (after the pbd) and fill it */
@@ -3131,7 +3144,7 @@ static noinline u16 bnx2x_tx_split(struct bnx2x *bp,
#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32)))
#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16)))
-static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
+static __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
{
__sum16 tsum = (__force __sum16) csum;
@@ -3146,30 +3159,47 @@ static inline __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix)
return bswab16(tsum);
}
-static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
+static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
{
u32 rc;
+ __u8 prot = 0;
+ __be16 protocol;
if (skb->ip_summed != CHECKSUM_PARTIAL)
- rc = XMIT_PLAIN;
+ return XMIT_PLAIN;
- else {
- if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) {
- rc = XMIT_CSUM_V6;
- if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
- rc |= XMIT_CSUM_TCP;
+ protocol = vlan_get_protocol(skb);
+ if (protocol == htons(ETH_P_IPV6)) {
+ rc = XMIT_CSUM_V6;
+ prot = ipv6_hdr(skb)->nexthdr;
+ } else {
+ rc = XMIT_CSUM_V4;
+ prot = ip_hdr(skb)->protocol;
+ }
+ if (!CHIP_IS_E1x(bp) && skb->encapsulation) {
+ if (inner_ip_hdr(skb)->version == 6) {
+ rc |= XMIT_CSUM_ENC_V6;
+ if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+ rc |= XMIT_CSUM_TCP;
} else {
- rc = XMIT_CSUM_V4;
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+ rc |= XMIT_CSUM_ENC_V4;
+ if (inner_ip_hdr(skb)->protocol == IPPROTO_TCP)
rc |= XMIT_CSUM_TCP;
}
}
+ if (prot == IPPROTO_TCP)
+ rc |= XMIT_CSUM_TCP;
- if (skb_is_gso_v6(skb))
- rc |= XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6;
- else if (skb_is_gso(skb))
- rc |= XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP;
+ if (skb_is_gso_v6(skb)) {
+ rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
+ if (rc & XMIT_CSUM_ENC)
+ rc |= XMIT_GSO_ENC_V6;
+ } else if (skb_is_gso(skb)) {
+ rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
+ if (rc & XMIT_CSUM_ENC)
+ rc |= XMIT_GSO_ENC_V4;
+ }
return rc;
}
@@ -3254,14 +3284,23 @@ exit_lbl:
}
#endif
-static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
- u32 xmit_type)
+static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
+ u32 xmit_type)
{
+ struct ipv6hdr *ipv6;
+
*parsing_data |= (skb_shinfo(skb)->gso_size <<
ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
ETH_TX_PARSE_BD_E2_LSO_MSS;
- if ((xmit_type & XMIT_GSO_V6) &&
- (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
+
+ if (xmit_type & XMIT_GSO_ENC_V6)
+ ipv6 = inner_ipv6_hdr(skb);
+ else if (xmit_type & XMIT_GSO_V6)
+ ipv6 = ipv6_hdr(skb);
+ else
+ ipv6 = NULL;
+
+ if (ipv6 && ipv6->nexthdr == NEXTHDR_IPV6)
*parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
}
@@ -3272,13 +3311,13 @@ static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
* @pbd: parse BD
* @xmit_type: xmit flags
*/
-static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
- struct eth_tx_parse_bd_e1x *pbd,
- u32 xmit_type)
+static void bnx2x_set_pbd_gso(struct sk_buff *skb,
+ struct eth_tx_parse_bd_e1x *pbd,
+ u32 xmit_type)
{
pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq);
- pbd->tcp_flags = pbd_tcp_flags(skb);
+ pbd->tcp_flags = pbd_tcp_flags(tcp_hdr(skb));
if (xmit_type & XMIT_GSO_V4) {
pbd->ip_id = bswab16(ip_hdr(skb)->id);
@@ -3298,6 +3337,40 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
}
/**
+ * bnx2x_set_pbd_csum_enc - update PBD with checksum and return header length
+ *
+ * @bp: driver handle
+ * @skb: packet skb
+ * @parsing_data: data to be updated
+ * @xmit_type: xmit flags
+ *
+ * 57712/578xx related, when skb has encapsulation
+ */
+static u8 bnx2x_set_pbd_csum_enc(struct bnx2x *bp, struct sk_buff *skb,
+ u32 *parsing_data, u32 xmit_type)
+{
+ *parsing_data |=
+ ((((u8 *)skb_inner_transport_header(skb) - skb->data) >> 1) <<
+ ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) &
+ ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W;
+
+ if (xmit_type & XMIT_CSUM_TCP) {
+ *parsing_data |= ((inner_tcp_hdrlen(skb) / 4) <<
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
+ ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
+
+ return skb_inner_transport_header(skb) +
+ inner_tcp_hdrlen(skb) - skb->data;
+ }
+
+ /* We support checksum offload for TCP and UDP only.
+ * No need to pass the UDP header length - it's a constant.
+ */
+ return skb_inner_transport_header(skb) +
+ sizeof(struct udphdr) - skb->data;
+}
+
+/**
* bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length
*
* @bp: driver handle
@@ -3305,15 +3378,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
* @parsing_data: data to be updated
* @xmit_type: xmit flags
*
- * 57712 related
+ * 57712/578xx related
*/
-static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
- u32 *parsing_data, u32 xmit_type)
+static u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
+ u32 *parsing_data, u32 xmit_type)
{
*parsing_data |=
((((u8 *)skb_transport_header(skb) - skb->data) >> 1) <<
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
- ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
+ ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) &
+ ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W;
if (xmit_type & XMIT_CSUM_TCP) {
*parsing_data |= ((tcp_hdrlen(skb) / 4) <<
@@ -3328,17 +3401,15 @@ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data;
}
-static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
- struct eth_tx_start_bd *tx_start_bd, u32 xmit_type)
+/* set FW indication according to inner or outer protocols if tunneled */
+static void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
+ struct eth_tx_start_bd *tx_start_bd,
+ u32 xmit_type)
{
tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM;
- if (xmit_type & XMIT_CSUM_V4)
- tx_start_bd->bd_flags.as_bitfield |=
- ETH_TX_BD_FLAGS_IP_CSUM;
- else
- tx_start_bd->bd_flags.as_bitfield |=
- ETH_TX_BD_FLAGS_IPV6;
+ if (xmit_type & (XMIT_CSUM_ENC_V6 | XMIT_CSUM_V6))
+ tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6;
if (!(xmit_type & XMIT_CSUM_TCP))
tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IS_UDP;
@@ -3352,9 +3423,9 @@ static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb,
* @pbd: parse BD to be updated
* @xmit_type: xmit flags
*/
-static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
- struct eth_tx_parse_bd_e1x *pbd,
- u32 xmit_type)
+static u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
+ struct eth_tx_parse_bd_e1x *pbd,
+ u32 xmit_type)
{
u8 hlen = (skb_network_header(skb) - skb->data) >> 1;
@@ -3400,6 +3471,75 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
return hlen;
}
+static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
+ struct eth_tx_parse_bd_e2 *pbd_e2,
+ struct eth_tx_parse_2nd_bd *pbd2,
+ u16 *global_data,
+ u32 xmit_type)
+{
+ u16 hlen_w = 0;
+ u8 outerip_off, outerip_len = 0;
+ /* from outer IP to transport */
+ hlen_w = (skb_inner_transport_header(skb) -
+ skb_network_header(skb)) >> 1;
+
+ /* transport len */
+ if (xmit_type & XMIT_CSUM_TCP)
+ hlen_w += inner_tcp_hdrlen(skb) >> 1;
+ else
+ hlen_w += sizeof(struct udphdr) >> 1;
+
+ pbd2->fw_ip_hdr_to_payload_w = hlen_w;
+
+ if (xmit_type & XMIT_CSUM_ENC_V4) {
+ struct iphdr *iph = ip_hdr(skb);
+ pbd2->fw_ip_csum_wo_len_flags_frag =
+ bswab16(csum_fold((~iph->check) -
+ iph->tot_len - iph->frag_off));
+ } else {
+ pbd2->fw_ip_hdr_to_payload_w =
+ hlen_w - ((sizeof(struct ipv6hdr)) >> 1);
+ }
+
+ pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq);
+
+ pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb));
+
+ if (xmit_type & XMIT_GSO_V4) {
+ pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id);
+
+ pbd_e2->data.tunnel_data.pseudo_csum =
+ bswab16(~csum_tcpudp_magic(
+ inner_ip_hdr(skb)->saddr,
+ inner_ip_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+
+ outerip_len = ip_hdr(skb)->ihl << 1;
+ } else {
+ pbd_e2->data.tunnel_data.pseudo_csum =
+ bswab16(~csum_ipv6_magic(
+ &inner_ipv6_hdr(skb)->saddr,
+ &inner_ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0));
+ }
+
+ outerip_off = (skb_network_header(skb) - skb->data) >> 1;
+
+ *global_data |=
+ outerip_off |
+ (!!(xmit_type & XMIT_CSUM_V6) <<
+ ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT) |
+ (outerip_len <<
+ ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) |
+ ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
+ ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT);
+
+ if (ip_hdr(skb)->protocol == IPPROTO_UDP) {
+ SET_FLAG(*global_data, ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST, 1);
+ pbd2->tunnel_udp_hdr_start_w = skb_transport_offset(skb) >> 1;
+ }
+}
+
/* called with netif_tx_lock
* bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
* netif_wake_queue()
@@ -3415,6 +3555,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
+ struct eth_tx_parse_2nd_bd *pbd2 = NULL;
u32 pbd_e2_parsing_data = 0;
u16 pkt_prod, bd_prod;
int nbd, txq_index;
@@ -3482,7 +3623,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
mac_type = MULTICAST_ADDRESS;
}
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
/* First, check if we need to linearize the skb (due to FW
restrictions). No need to check fragmentation if page size > 8K
(there will be no violation to FW restrictions) */
@@ -3530,12 +3671,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
first_bd = tx_start_bd;
tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
- SET_FLAG(tx_start_bd->general_data,
- ETH_TX_START_BD_PARSE_NBDS,
- 0);
- /* header nbd */
- SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_HDR_NBDS, 1);
+ /* header nbd: indirectly zero other flags! */
+ tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT;
/* remember the first BD of the packet */
tx_buf->first_bd = txdata->tx_bd_prod;
@@ -3555,19 +3693,16 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* when transmitting in a vf, start bd must hold the ethertype
* for fw to enforce it
*/
-#ifndef BNX2X_STOP_ON_ERROR
- if (IS_VF(bp)) {
-#endif
+ if (IS_VF(bp))
tx_start_bd->vlan_or_ethertype =
cpu_to_le16(ntohs(eth->h_proto));
-#ifndef BNX2X_STOP_ON_ERROR
- } else {
+ else
/* used by FW for packet accounting */
tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
- }
-#endif
}
+ nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
+
/* turn on parsing and get a BD */
bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
@@ -3577,23 +3712,58 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!CHIP_IS_E1x(bp)) {
pbd_e2 = &txdata->tx_desc_ring[bd_prod].parse_bd_e2;
memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
- /* Set PBD in checksum offload case */
- if (xmit_type & XMIT_CSUM)
+
+ if (xmit_type & XMIT_CSUM_ENC) {
+ u16 global_data = 0;
+
+ /* Set PBD in enc checksum offload case */
+ hlen = bnx2x_set_pbd_csum_enc(bp, skb,
+ &pbd_e2_parsing_data,
+ xmit_type);
+
+ /* turn on 2nd parsing and get a BD */
+ bd_prod = TX_BD(NEXT_TX_IDX(bd_prod));
+
+ pbd2 = &txdata->tx_desc_ring[bd_prod].parse_2nd_bd;
+
+ memset(pbd2, 0, sizeof(*pbd2));
+
+ pbd_e2->data.tunnel_data.ip_hdr_start_inner_w =
+ (skb_inner_network_header(skb) -
+ skb->data) >> 1;
+
+ if (xmit_type & XMIT_GSO_ENC)
+ bnx2x_update_pbds_gso_enc(skb, pbd_e2, pbd2,
+ &global_data,
+ xmit_type);
+
+ pbd2->global_data = cpu_to_le16(global_data);
+
+ /* add addition parse BD indication to start BD */
+ SET_FLAG(tx_start_bd->general_data,
+ ETH_TX_START_BD_PARSE_NBDS, 1);
+ /* set encapsulation flag in start BD */
+ SET_FLAG(tx_start_bd->general_data,
+ ETH_TX_START_BD_TUNNEL_EXIST, 1);
+ nbd++;
+ } else if (xmit_type & XMIT_CSUM) {
+ /* Set PBD in checksum offload case w/o encapsulation */
hlen = bnx2x_set_pbd_csum_e2(bp, skb,
&pbd_e2_parsing_data,
xmit_type);
+ }
- if (IS_MF_SI(bp) || IS_VF(bp)) {
- /* fill in the MAC addresses in the PBD - for local
- * switching
- */
- bnx2x_set_fw_mac_addr(&pbd_e2->src_mac_addr_hi,
- &pbd_e2->src_mac_addr_mid,
- &pbd_e2->src_mac_addr_lo,
+ /* Add the macs to the parsing BD this is a vf */
+ if (IS_VF(bp)) {
+ /* override GRE parameters in BD */
+ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
+ &pbd_e2->data.mac_addr.src_mid,
+ &pbd_e2->data.mac_addr.src_lo,
eth->h_source);
- bnx2x_set_fw_mac_addr(&pbd_e2->dst_mac_addr_hi,
- &pbd_e2->dst_mac_addr_mid,
- &pbd_e2->dst_mac_addr_lo,
+
+ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+ &pbd_e2->data.mac_addr.dst_mid,
+ &pbd_e2->data.mac_addr.dst_lo,
eth->h_dest);
}
@@ -3615,14 +3785,13 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Setup the data pointer of the first BD of the packet */
tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
- nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb));
pkt_size = tx_start_bd->nbytes;
DP(NETIF_MSG_TX_QUEUED,
- "first bd @%p addr (%x:%x) nbd %d nbytes %d flags %x vlan %x\n",
+ "first bd @%p addr (%x:%x) nbytes %d flags %x vlan %x\n",
tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo,
- le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes),
+ le16_to_cpu(tx_start_bd->nbytes),
tx_start_bd->bd_flags.as_bitfield,
le16_to_cpu(tx_start_bd->vlan_or_ethertype));
@@ -3635,10 +3804,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO;
- if (unlikely(skb_headlen(skb) > hlen))
+ if (unlikely(skb_headlen(skb) > hlen)) {
+ nbd++;
bd_prod = bnx2x_tx_split(bp, txdata, tx_buf,
&tx_start_bd, hlen,
- bd_prod, ++nbd);
+ bd_prod);
+ }
if (!CHIP_IS_E1x(bp))
bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
xmit_type);
@@ -3728,9 +3899,13 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pbd_e2)
DP(NETIF_MSG_TX_QUEUED,
"PBD (E2) @%p dst %x %x %x src %x %x %x parsing_data %x\n",
- pbd_e2, pbd_e2->dst_mac_addr_hi, pbd_e2->dst_mac_addr_mid,
- pbd_e2->dst_mac_addr_lo, pbd_e2->src_mac_addr_hi,
- pbd_e2->src_mac_addr_mid, pbd_e2->src_mac_addr_lo,
+ pbd_e2,
+ pbd_e2->data.mac_addr.dst_hi,
+ pbd_e2->data.mac_addr.dst_mid,
+ pbd_e2->data.mac_addr.dst_lo,
+ pbd_e2->data.mac_addr.src_hi,
+ pbd_e2->data.mac_addr.src_mid,
+ pbd_e2->data.mac_addr.src_lo,
pbd_e2->parsing_data);
DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod);
@@ -4580,11 +4755,11 @@ static void storm_memset_hc_disable(struct bnx2x *bp, u8 port,
u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT);
u32 addr = BAR_CSTRORM_INTMEM +
CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index);
- u16 flags = REG_RD16(bp, addr);
+ u8 flags = REG_RD8(bp, addr);
/* clear and set */
flags &= ~HC_INDEX_DATA_HC_ENABLED;
flags |= enable_flag;
- REG_WR16(bp, addr, flags);
+ REG_WR8(bp, addr, flags);
DP(NETIF_MSG_IFUP,
"port %x fw_sb_id %d sb_index %d disable %d\n",
port, fw_sb_id, sb_index, disable);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index aee7671ff4c1..151675d66b0d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -50,13 +50,13 @@ extern int int_mode;
} \
} while (0)
-#define BNX2X_PCI_ALLOC(x, y, size) \
- do { \
- x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- memset((void *)x, 0, size); \
- } while (0)
+#define BNX2X_PCI_ALLOC(x, y, size) \
+do { \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, \
+ GFP_KERNEL | __GFP_ZERO); \
+ if (x == NULL) \
+ goto alloc_mem_err; \
+} while (0)
#define BNX2X_ALLOC(x, size) \
do { \
@@ -295,16 +295,29 @@ void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
void bnx2x_nic_init_cnic(struct bnx2x *bp);
/**
- * bnx2x_nic_init - init driver internals.
+ * bnx2x_preirq_nic_init - init driver internals.
*
* @bp: driver handle
*
* Initializes:
- * - rings
+ * - fastpath object
+ * - fastpath rings
+ * etc.
+ */
+void bnx2x_pre_irq_nic_init(struct bnx2x *bp);
+
+/**
+ * bnx2x_postirq_nic_init - init driver internals.
+ *
+ * @bp: driver handle
+ * @load_code: COMMON, PORT or FUNCTION
+ *
+ * Initializes:
* - status blocks
+ * - slowpath rings
* - etc.
*/
-void bnx2x_nic_init(struct bnx2x *bp, u32 load_code);
+void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code);
/**
* bnx2x_alloc_mem_cnic - allocate driver's memory for cnic.
*
@@ -496,7 +509,10 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* setup_tc callback */
int bnx2x_setup_tc(struct net_device *dev, u8 num_tc);
+int bnx2x_get_vf_config(struct net_device *dev, int vf,
+ struct ifla_vf_info *ivi);
int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
+int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);
/* select_queue callback */
u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
@@ -834,7 +850,7 @@ static inline void bnx2x_add_all_napi_cnic(struct bnx2x *bp)
/* Add NAPI objects */
for_each_rx_queue_cnic(bp, i)
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
- bnx2x_poll, BNX2X_NAPI_WEIGHT);
+ bnx2x_poll, NAPI_POLL_WEIGHT);
}
static inline void bnx2x_add_all_napi(struct bnx2x *bp)
@@ -844,7 +860,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
/* Add NAPI objects */
for_each_eth_queue(bp, i)
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
- bnx2x_poll, BNX2X_NAPI_WEIGHT);
+ bnx2x_poll, NAPI_POLL_WEIGHT);
}
static inline void bnx2x_del_all_napi_cnic(struct bnx2x *bp)
@@ -970,6 +986,9 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
else /* CHIP_IS_E1X */
start_params->network_cos_mode = FW_WRR;
+ start_params->gre_tunnel_mode = IPGRE_TUNNEL;
+ start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS;
+
return bnx2x_func_state_change(bp, &func_params);
}
@@ -1396,4 +1415,8 @@ static inline bool bnx2x_is_valid_ether_addr(struct bnx2x *bp, u8 *addr)
*
*/
void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
+
+int bnx2x_drain_tx_queues(struct bnx2x *bp);
+void bnx2x_squeeze_objects(struct bnx2x *bp);
+
#endif /* BNX2X_CMN_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 91ecd6a00d05..4b077a7f16af 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -591,7 +591,7 @@ static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)
DCBX_READ_REMOTE_MIB);
if (rc) {
- BNX2X_ERR("Faild to read remote mib from FW\n");
+ BNX2X_ERR("Failed to read remote mib from FW\n");
return rc;
}
@@ -619,7 +619,7 @@ static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
DCBX_READ_LOCAL_MIB);
if (rc) {
- BNX2X_ERR("Faild to read local mib from FW\n");
+ BNX2X_ERR("Failed to read local mib from FW\n");
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index edfa67adf2f9..ce1a91618677 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -1364,11 +1364,27 @@ static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf,
return rc;
}
+static int bnx2x_nvram_read32(struct bnx2x *bp, u32 offset, u32 *buf,
+ int buf_size)
+{
+ int rc;
+
+ rc = bnx2x_nvram_read(bp, offset, (u8 *)buf, buf_size);
+
+ if (!rc) {
+ __be32 *be = (__be32 *)buf;
+
+ while ((buf_size -= 4) >= 0)
+ *buf++ = be32_to_cpu(*be++);
+ }
+
+ return rc;
+}
+
static int bnx2x_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 *eebuf)
{
struct bnx2x *bp = netdev_priv(dev);
- int rc;
if (!netif_running(dev)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
@@ -1383,9 +1399,7 @@ static int bnx2x_get_eeprom(struct net_device *dev,
/* parameters already validated in ethtool_get_eeprom */
- rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
-
- return rc;
+ return bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
}
static int bnx2x_get_module_eeprom(struct net_device *dev,
@@ -1393,10 +1407,9 @@ static int bnx2x_get_module_eeprom(struct net_device *dev,
u8 *data)
{
struct bnx2x *bp = netdev_priv(dev);
- int rc = 0, phy_idx;
+ int rc = -EINVAL, phy_idx;
u8 *user_data = data;
- int remaining_len = ee->len, xfer_size;
- unsigned int page_off = ee->offset;
+ unsigned int start_addr = ee->offset, xfer_size = 0;
if (!netif_running(dev)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
@@ -1405,21 +1418,52 @@ static int bnx2x_get_module_eeprom(struct net_device *dev,
}
phy_idx = bnx2x_get_cur_phy_idx(bp);
- bnx2x_acquire_phy_lock(bp);
- while (!rc && remaining_len > 0) {
- xfer_size = (remaining_len > SFP_EEPROM_PAGE_SIZE) ?
- SFP_EEPROM_PAGE_SIZE : remaining_len;
+
+ /* Read A0 section */
+ if (start_addr < ETH_MODULE_SFF_8079_LEN) {
+ /* Limit transfer size to the A0 section boundary */
+ if (start_addr + ee->len > ETH_MODULE_SFF_8079_LEN)
+ xfer_size = ETH_MODULE_SFF_8079_LEN - start_addr;
+ else
+ xfer_size = ee->len;
+ bnx2x_acquire_phy_lock(bp);
rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx],
&bp->link_params,
- page_off,
+ I2C_DEV_ADDR_A0,
+ start_addr,
xfer_size,
user_data);
- remaining_len -= xfer_size;
+ bnx2x_release_phy_lock(bp);
+ if (rc) {
+ DP(BNX2X_MSG_ETHTOOL, "Failed reading A0 section\n");
+
+ return -EINVAL;
+ }
user_data += xfer_size;
- page_off += xfer_size;
+ start_addr += xfer_size;
}
- bnx2x_release_phy_lock(bp);
+ /* Read A2 section */
+ if ((start_addr >= ETH_MODULE_SFF_8079_LEN) &&
+ (start_addr < ETH_MODULE_SFF_8472_LEN)) {
+ xfer_size = ee->len - xfer_size;
+ /* Limit transfer size to the A2 section boundary */
+ if (start_addr + xfer_size > ETH_MODULE_SFF_8472_LEN)
+ xfer_size = ETH_MODULE_SFF_8472_LEN - start_addr;
+ start_addr -= ETH_MODULE_SFF_8079_LEN;
+ bnx2x_acquire_phy_lock(bp);
+ rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx],
+ &bp->link_params,
+ I2C_DEV_ADDR_A2,
+ start_addr,
+ xfer_size,
+ user_data);
+ bnx2x_release_phy_lock(bp);
+ if (rc) {
+ DP(BNX2X_MSG_ETHTOOL, "Failed reading A2 section\n");
+ return -EINVAL;
+ }
+ }
return rc;
}
@@ -1427,24 +1471,50 @@ static int bnx2x_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo)
{
struct bnx2x *bp = netdev_priv(dev);
- int phy_idx;
+ int phy_idx, rc;
+ u8 sff8472_comp, diag_type;
+
if (!netif_running(dev)) {
- DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
}
-
phy_idx = bnx2x_get_cur_phy_idx(bp);
- switch (bp->link_params.phy[phy_idx].media_type) {
- case ETH_PHY_SFPP_10G_FIBER:
- case ETH_PHY_SFP_1G_FIBER:
- case ETH_PHY_DA_TWINAX:
+ bnx2x_acquire_phy_lock(bp);
+ rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx],
+ &bp->link_params,
+ I2C_DEV_ADDR_A0,
+ SFP_EEPROM_SFF_8472_COMP_ADDR,
+ SFP_EEPROM_SFF_8472_COMP_SIZE,
+ &sff8472_comp);
+ bnx2x_release_phy_lock(bp);
+ if (rc) {
+ DP(BNX2X_MSG_ETHTOOL, "Failed reading SFF-8472 comp field\n");
+ return -EINVAL;
+ }
+
+ bnx2x_acquire_phy_lock(bp);
+ rc = bnx2x_read_sfp_module_eeprom(&bp->link_params.phy[phy_idx],
+ &bp->link_params,
+ I2C_DEV_ADDR_A0,
+ SFP_EEPROM_DIAG_TYPE_ADDR,
+ SFP_EEPROM_DIAG_TYPE_SIZE,
+ &diag_type);
+ bnx2x_release_phy_lock(bp);
+ if (rc) {
+ DP(BNX2X_MSG_ETHTOOL, "Failed reading Diag Type field\n");
+ return -EINVAL;
+ }
+
+ if (!sff8472_comp ||
+ (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ)) {
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
- return 0;
- default:
- return -EOPNOTSUPP;
+ } else {
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
}
+ return 0;
}
static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val,
@@ -1496,9 +1566,8 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
int buf_size)
{
int rc;
- u32 cmd_flags;
- u32 align_offset;
- __be32 val;
+ u32 cmd_flags, align_offset, val;
+ __be32 val_be;
if (offset + buf_size > bp->common.flash_size) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
@@ -1517,16 +1586,16 @@ static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf,
cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST);
align_offset = (offset & ~0x03);
- rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags);
+ rc = bnx2x_nvram_read_dword(bp, align_offset, &val_be, cmd_flags);
if (rc == 0) {
- val &= ~(0xff << BYTE_OFFSET(offset));
- val |= (*data_buf << BYTE_OFFSET(offset));
-
/* nvram data is returned as an array of bytes
* convert it back to cpu order
*/
- val = be32_to_cpu(val);
+ val = be32_to_cpu(val_be);
+
+ val &= ~le32_to_cpu(0xff << BYTE_OFFSET(offset));
+ val |= le32_to_cpu(*data_buf << BYTE_OFFSET(offset));
rc = bnx2x_nvram_write_dword(bp, align_offset, val,
cmd_flags);
@@ -1820,12 +1889,15 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
bp->link_params.req_flow_ctrl[cfg_idx] =
BNX2X_FLOW_CTRL_AUTO;
}
- bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_NONE;
+ bp->link_params.req_fc_auto_adv = 0;
if (epause->rx_pause)
bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_RX;
if (epause->tx_pause)
bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_TX;
+
+ if (!bp->link_params.req_fc_auto_adv)
+ bp->link_params.req_fc_auto_adv |= BNX2X_FLOW_CTRL_NONE;
}
DP(BNX2X_MSG_ETHTOOL,
@@ -2526,14 +2598,168 @@ static int bnx2x_test_ext_loopback(struct bnx2x *bp)
return rc;
}
+struct code_entry {
+ u32 sram_start_addr;
+ u32 code_attribute;
+#define CODE_IMAGE_TYPE_MASK 0xf0800003
+#define CODE_IMAGE_VNTAG_PROFILES_DATA 0xd0000003
+#define CODE_IMAGE_LENGTH_MASK 0x007ffffc
+#define CODE_IMAGE_TYPE_EXTENDED_DIR 0xe0000000
+ u32 nvm_start_addr;
+};
+
+#define CODE_ENTRY_MAX 16
+#define CODE_ENTRY_EXTENDED_DIR_IDX 15
+#define MAX_IMAGES_IN_EXTENDED_DIR 64
+#define NVRAM_DIR_OFFSET 0x14
+
+#define EXTENDED_DIR_EXISTS(code) \
+ ((code & CODE_IMAGE_TYPE_MASK) == CODE_IMAGE_TYPE_EXTENDED_DIR && \
+ (code & CODE_IMAGE_LENGTH_MASK) != 0)
+
#define CRC32_RESIDUAL 0xdebb20e3
+#define CRC_BUFF_SIZE 256
+
+static int bnx2x_nvram_crc(struct bnx2x *bp,
+ int offset,
+ int size,
+ u8 *buff)
+{
+ u32 crc = ~0;
+ int rc = 0, done = 0;
+
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+ "NVRAM CRC from 0x%08x to 0x%08x\n", offset, offset + size);
+
+ while (done < size) {
+ int count = min_t(int, size - done, CRC_BUFF_SIZE);
+
+ rc = bnx2x_nvram_read(bp, offset + done, buff, count);
+
+ if (rc)
+ return rc;
+
+ crc = crc32_le(crc, buff, count);
+ done += count;
+ }
+
+ if (crc != CRC32_RESIDUAL)
+ rc = -EINVAL;
+
+ return rc;
+}
+
+static int bnx2x_test_nvram_dir(struct bnx2x *bp,
+ struct code_entry *entry,
+ u8 *buff)
+{
+ size_t size = entry->code_attribute & CODE_IMAGE_LENGTH_MASK;
+ u32 type = entry->code_attribute & CODE_IMAGE_TYPE_MASK;
+ int rc;
+
+ /* Zero-length images and AFEX profiles do not have CRC */
+ if (size == 0 || type == CODE_IMAGE_VNTAG_PROFILES_DATA)
+ return 0;
+
+ rc = bnx2x_nvram_crc(bp, entry->nvm_start_addr, size, buff);
+ if (rc)
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+ "image %x has failed crc test (rc %d)\n", type, rc);
+
+ return rc;
+}
+
+static int bnx2x_test_dir_entry(struct bnx2x *bp, u32 addr, u8 *buff)
+{
+ int rc;
+ struct code_entry entry;
+
+ rc = bnx2x_nvram_read32(bp, addr, (u32 *)&entry, sizeof(entry));
+ if (rc)
+ return rc;
+
+ return bnx2x_test_nvram_dir(bp, &entry, buff);
+}
+
+static int bnx2x_test_nvram_ext_dirs(struct bnx2x *bp, u8 *buff)
+{
+ u32 rc, cnt, dir_offset = NVRAM_DIR_OFFSET;
+ struct code_entry entry;
+ int i;
+
+ rc = bnx2x_nvram_read32(bp,
+ dir_offset +
+ sizeof(entry) * CODE_ENTRY_EXTENDED_DIR_IDX,
+ (u32 *)&entry, sizeof(entry));
+ if (rc)
+ return rc;
+
+ if (!EXTENDED_DIR_EXISTS(entry.code_attribute))
+ return 0;
+
+ rc = bnx2x_nvram_read32(bp, entry.nvm_start_addr,
+ &cnt, sizeof(u32));
+ if (rc)
+ return rc;
+
+ dir_offset = entry.nvm_start_addr + 8;
+
+ for (i = 0; i < cnt && i < MAX_IMAGES_IN_EXTENDED_DIR; i++) {
+ rc = bnx2x_test_dir_entry(bp, dir_offset +
+ sizeof(struct code_entry) * i,
+ buff);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int bnx2x_test_nvram_dirs(struct bnx2x *bp, u8 *buff)
+{
+ u32 rc, dir_offset = NVRAM_DIR_OFFSET;
+ int i;
+
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "NVRAM DIRS CRC test-set\n");
+
+ for (i = 0; i < CODE_ENTRY_EXTENDED_DIR_IDX; i++) {
+ rc = bnx2x_test_dir_entry(bp, dir_offset +
+ sizeof(struct code_entry) * i,
+ buff);
+ if (rc)
+ return rc;
+ }
+
+ return bnx2x_test_nvram_ext_dirs(bp, buff);
+}
+
+struct crc_pair {
+ int offset;
+ int size;
+};
+
+static int bnx2x_test_nvram_tbl(struct bnx2x *bp,
+ const struct crc_pair *nvram_tbl, u8 *buf)
+{
+ int i;
+
+ for (i = 0; nvram_tbl[i].size; i++) {
+ int rc = bnx2x_nvram_crc(bp, nvram_tbl[i].offset,
+ nvram_tbl[i].size, buf);
+ if (rc) {
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
+ "nvram_tbl[%d] has failed crc test (rc %d)\n",
+ i, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
static int bnx2x_test_nvram(struct bnx2x *bp)
{
- static const struct {
- int offset;
- int size;
- } nvram_tbl[] = {
+ const struct crc_pair nvram_tbl[] = {
{ 0, 0x14 }, /* bootstrap */
{ 0x14, 0xec }, /* dir */
{ 0x100, 0x350 }, /* manuf_info */
@@ -2542,30 +2768,33 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
{ 0x708, 0x70 }, /* manuf_key_info */
{ 0, 0 }
};
- __be32 *buf;
- u8 *data;
- int i, rc;
- u32 magic, crc;
+ const struct crc_pair nvram_tbl2[] = {
+ { 0x7e8, 0x350 }, /* manuf_info2 */
+ { 0xb38, 0xf0 }, /* feature_info */
+ { 0, 0 }
+ };
+
+ u8 *buf;
+ int rc;
+ u32 magic;
if (BP_NOMCP(bp))
return 0;
- buf = kmalloc(0x350, GFP_KERNEL);
+ buf = kmalloc(CRC_BUFF_SIZE, GFP_KERNEL);
if (!buf) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "kmalloc failed\n");
rc = -ENOMEM;
goto test_nvram_exit;
}
- data = (u8 *)buf;
- rc = bnx2x_nvram_read(bp, 0, data, 4);
+ rc = bnx2x_nvram_read32(bp, 0, &magic, sizeof(magic));
if (rc) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"magic value read (rc %d)\n", rc);
goto test_nvram_exit;
}
- magic = be32_to_cpu(buf[0]);
if (magic != 0x669955aa) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"wrong magic value (0x%08x)\n", magic);
@@ -2573,25 +2802,26 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
goto test_nvram_exit;
}
- for (i = 0; nvram_tbl[i].size; i++) {
+ DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM, "Port 0 CRC test-set\n");
+ rc = bnx2x_test_nvram_tbl(bp, nvram_tbl, buf);
+ if (rc)
+ goto test_nvram_exit;
- rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data,
- nvram_tbl[i].size);
- if (rc) {
- DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
- "nvram_tbl[%d] read data (rc %d)\n", i, rc);
- goto test_nvram_exit;
- }
+ if (!CHIP_IS_E1x(bp) && !CHIP_IS_57811xx(bp)) {
+ u32 hide = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+ SHARED_HW_CFG_HIDE_PORT1;
- crc = ether_crc_le(nvram_tbl[i].size, data);
- if (crc != CRC32_RESIDUAL) {
+ if (!hide) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
- "nvram_tbl[%d] wrong crc value (0x%08x)\n", i, crc);
- rc = -ENODEV;
- goto test_nvram_exit;
+ "Port 1 CRC test-set\n");
+ rc = bnx2x_test_nvram_tbl(bp, nvram_tbl2, buf);
+ if (rc)
+ goto test_nvram_exit;
}
}
+ rc = bnx2x_test_nvram_dirs(bp, buf);
+
test_nvram_exit:
kfree(buf);
return rc;
@@ -3232,7 +3462,32 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info,
};
-void bnx2x_set_ethtool_ops(struct net_device *netdev)
+static const struct ethtool_ops bnx2x_vf_ethtool_ops = {
+ .get_settings = bnx2x_get_settings,
+ .set_settings = bnx2x_set_settings,
+ .get_drvinfo = bnx2x_get_drvinfo,
+ .get_msglevel = bnx2x_get_msglevel,
+ .set_msglevel = bnx2x_set_msglevel,
+ .get_link = bnx2x_get_link,
+ .get_coalesce = bnx2x_get_coalesce,
+ .get_ringparam = bnx2x_get_ringparam,
+ .set_ringparam = bnx2x_set_ringparam,
+ .get_sset_count = bnx2x_get_sset_count,
+ .get_strings = bnx2x_get_strings,
+ .get_ethtool_stats = bnx2x_get_ethtool_stats,
+ .get_rxnfc = bnx2x_get_rxnfc,
+ .set_rxnfc = bnx2x_set_rxnfc,
+ .get_rxfh_indir_size = bnx2x_get_rxfh_indir_size,
+ .get_rxfh_indir = bnx2x_get_rxfh_indir,
+ .set_rxfh_indir = bnx2x_set_rxfh_indir,
+ .get_channels = bnx2x_get_channels,
+ .set_channels = bnx2x_set_channels,
+};
+
+void bnx2x_set_ethtool_ops(struct bnx2x *bp, struct net_device *netdev)
{
- SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
+ if (IS_PF(bp))
+ SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops);
+ else /* vf */
+ SET_ETHTOOL_OPS(netdev, &bnx2x_vf_ethtool_ops);
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
index e5f808377c91..84aecdf06f7a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h
@@ -30,31 +30,31 @@
* IRO[138].m2) + ((sbId) * IRO[138].m3))
#define CSTORM_IGU_MODE_OFFSET (IRO[157].base)
#define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
- (IRO[316].base + ((pfId) * IRO[316].m1))
-#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
(IRO[317].base + ((pfId) * IRO[317].m1))
+#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+ (IRO[318].base + ((pfId) * IRO[318].m1))
#define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \
- (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2))
+ (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
- (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2))
+ (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2))
#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
- (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
+ (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2))
#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
- (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2))
+ (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
#define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
- (IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2))
+ (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2))
#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
- (IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2))
+ (IRO[315].base + ((pfId) * IRO[315].m1) + ((iscsiEqId) * IRO[315].m2))
#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
- (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
+ (IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2))
#define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
- (IRO[315].base + ((pfId) * IRO[315].m1))
+ (IRO[316].base + ((pfId) * IRO[316].m1))
#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
- (IRO[307].base + ((pfId) * IRO[307].m1))
+ (IRO[308].base + ((pfId) * IRO[308].m1))
#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
- (IRO[306].base + ((pfId) * IRO[306].m1))
+ (IRO[307].base + ((pfId) * IRO[307].m1))
#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
- (IRO[305].base + ((pfId) * IRO[305].m1))
+ (IRO[306].base + ((pfId) * IRO[306].m1))
#define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
(IRO[151].base + ((funcId) * IRO[151].m1))
#define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \
@@ -114,7 +114,7 @@
#define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
(IRO[268].base + ((pfId) * IRO[268].m1))
#define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
- (IRO[277].base + ((pfId) * IRO[277].m1))
+ (IRO[278].base + ((pfId) * IRO[278].m1))
#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
(IRO[264].base + ((pfId) * IRO[264].m1))
#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
@@ -136,35 +136,32 @@
#define USTORM_ASSERT_LIST_INDEX_OFFSET (IRO[177].base)
#define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \
(IRO[176].base + ((assertListEntry) * IRO[176].m1))
-#define USTORM_CQE_PAGE_NEXT_OFFSET(portId, clientId) \
- (IRO[205].base + ((portId) * IRO[205].m1) + ((clientId) * \
- IRO[205].m2))
#define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
(IRO[183].base + ((portId) * IRO[183].m1))
#define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
- (IRO[318].base + ((pfId) * IRO[318].m1))
+ (IRO[319].base + ((pfId) * IRO[319].m1))
#define USTORM_FUNC_EN_OFFSET(funcId) \
(IRO[178].base + ((funcId) * IRO[178].m1))
#define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
- (IRO[282].base + ((pfId) * IRO[282].m1))
-#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
(IRO[283].base + ((pfId) * IRO[283].m1))
+#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
+ (IRO[284].base + ((pfId) * IRO[284].m1))
#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
- (IRO[287].base + ((pfId) * IRO[287].m1))
+ (IRO[288].base + ((pfId) * IRO[288].m1))
#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
- (IRO[284].base + ((pfId) * IRO[284].m1))
+ (IRO[285].base + ((pfId) * IRO[285].m1))
#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
- (IRO[280].base + ((pfId) * IRO[280].m1))
+ (IRO[281].base + ((pfId) * IRO[281].m1))
#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
- (IRO[279].base + ((pfId) * IRO[279].m1))
+ (IRO[280].base + ((pfId) * IRO[280].m1))
#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
- (IRO[278].base + ((pfId) * IRO[278].m1))
+ (IRO[279].base + ((pfId) * IRO[279].m1))
#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
- (IRO[281].base + ((pfId) * IRO[281].m1))
+ (IRO[282].base + ((pfId) * IRO[282].m1))
#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
- (IRO[285].base + ((pfId) * IRO[285].m1))
-#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
(IRO[286].base + ((pfId) * IRO[286].m1))
+#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
+ (IRO[287].base + ((pfId) * IRO[287].m1))
#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \
(IRO[182].base + ((pfId) * IRO[182].m1))
#define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
@@ -190,39 +187,39 @@
#define XSTORM_FUNC_EN_OFFSET(funcId) \
(IRO[47].base + ((funcId) * IRO[47].m1))
#define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
- (IRO[295].base + ((pfId) * IRO[295].m1))
+ (IRO[296].base + ((pfId) * IRO[296].m1))
#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
- (IRO[298].base + ((pfId) * IRO[298].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
(IRO[299].base + ((pfId) * IRO[299].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
(IRO[300].base + ((pfId) * IRO[300].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
(IRO[301].base + ((pfId) * IRO[301].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
(IRO[302].base + ((pfId) * IRO[302].m1))
-#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
(IRO[303].base + ((pfId) * IRO[303].m1))
-#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
(IRO[304].base + ((pfId) * IRO[304].m1))
+#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
+ (IRO[305].base + ((pfId) * IRO[305].m1))
#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
- (IRO[294].base + ((pfId) * IRO[294].m1))
+ (IRO[295].base + ((pfId) * IRO[295].m1))
#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
- (IRO[293].base + ((pfId) * IRO[293].m1))
+ (IRO[294].base + ((pfId) * IRO[294].m1))
#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
- (IRO[292].base + ((pfId) * IRO[292].m1))
+ (IRO[293].base + ((pfId) * IRO[293].m1))
#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
- (IRO[297].base + ((pfId) * IRO[297].m1))
+ (IRO[298].base + ((pfId) * IRO[298].m1))
#define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
- (IRO[296].base + ((pfId) * IRO[296].m1))
+ (IRO[297].base + ((pfId) * IRO[297].m1))
#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \
- (IRO[291].base + ((pfId) * IRO[291].m1))
+ (IRO[292].base + ((pfId) * IRO[292].m1))
#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
- (IRO[290].base + ((pfId) * IRO[290].m1))
+ (IRO[291].base + ((pfId) * IRO[291].m1))
#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \
- (IRO[289].base + ((pfId) * IRO[289].m1))
+ (IRO[290].base + ((pfId) * IRO[290].m1))
#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \
- (IRO[288].base + ((pfId) * IRO[288].m1))
+ (IRO[289].base + ((pfId) * IRO[289].m1))
#define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \
(IRO[44].base + ((pfId) * IRO[44].m1))
#define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
@@ -389,4 +386,8 @@
#define UNDEF_IRO 0x80000000
+/* used for defining the amount of FCoE tasks supported for PF */
+#define MAX_FCOE_FUNCS_PER_ENGINE 2
+#define MAX_NUM_FCOE_TASKS_PER_ENGINE 4096
+
#endif /* BNX2X_FW_DEFS_H */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 037860ecc343..12f00a40cdf0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -114,6 +114,10 @@ struct license_key {
#define EPIO_CFG_EPIO30 0x0000001f
#define EPIO_CFG_EPIO31 0x00000020
+struct mac_addr {
+ u32 upper;
+ u32 lower;
+};
struct shared_hw_cfg { /* NVRAM Offset */
/* Up to 16 bytes of NULL-terminated string */
@@ -508,7 +512,22 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_PAUSE_ON_HOST_RING_DISABLED 0x00000000
#define PORT_HW_CFG_PAUSE_ON_HOST_RING_ENABLED 0x00000001
- u32 reserved0[6]; /* 0x178 */
+ /* SFP+ Tx Equalization: NIC recommended and tested value is 0xBEB2
+ * LOM recommended and tested value is 0xBEB2. Using a different
+ * value means using a value not tested by BRCM
+ */
+ u32 sfi_tap_values; /* 0x178 */
+ #define PORT_HW_CFG_TX_EQUALIZATION_MASK 0x0000FFFF
+ #define PORT_HW_CFG_TX_EQUALIZATION_SHIFT 0
+
+ /* SFP+ Tx driver broadcast IDRIVER: NIC recommended and tested
+ * value is 0x2. LOM recommended and tested value is 0x2. Using a
+ * different value means using a value not tested by BRCM
+ */
+ #define PORT_HW_CFG_TX_DRV_BROADCAST_MASK 0x000F0000
+ #define PORT_HW_CFG_TX_DRV_BROADCAST_SHIFT 16
+
+ u32 reserved0[5]; /* 0x17c */
u32 aeu_int_mask; /* 0x190 */
@@ -2821,8 +2840,8 @@ struct afex_stats {
#define BCM_5710_FW_MAJOR_VERSION 7
#define BCM_5710_FW_MINOR_VERSION 8
-#define BCM_5710_FW_REVISION_VERSION 2
-#define BCM_5710_FW_ENGINEERING_VERSION 0
+#define BCM_5710_FW_REVISION_VERSION 17
+#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
@@ -3513,11 +3532,14 @@ struct client_init_tx_data {
#define CLIENT_INIT_TX_DATA_BCAST_ACCEPT_ALL_SHIFT 2
#define CLIENT_INIT_TX_DATA_ACCEPT_ANY_VLAN (0x1<<3)
#define CLIENT_INIT_TX_DATA_ACCEPT_ANY_VLAN_SHIFT 3
-#define CLIENT_INIT_TX_DATA_RESERVED1 (0xFFF<<4)
-#define CLIENT_INIT_TX_DATA_RESERVED1_SHIFT 4
+#define CLIENT_INIT_TX_DATA_RESERVED0 (0xFFF<<4)
+#define CLIENT_INIT_TX_DATA_RESERVED0_SHIFT 4
u8 default_vlan_flg;
u8 force_default_pri_flg;
- __le32 reserved3;
+ u8 tunnel_lso_inc_ip_id;
+ u8 refuse_outband_vlan_flg;
+ u8 tunnel_non_lso_pcsum_location;
+ u8 reserved1;
};
/*
@@ -3551,6 +3573,11 @@ struct client_update_ramrod_data {
__le16 silent_vlan_mask;
u8 silent_vlan_removal_flg;
u8 silent_vlan_change_flg;
+ u8 refuse_outband_vlan_flg;
+ u8 refuse_outband_vlan_change_flg;
+ u8 tx_switching_flg;
+ u8 tx_switching_change_flg;
+ __le32 reserved1;
__le32 echo;
};
@@ -3620,7 +3647,8 @@ struct eth_classify_header {
*/
struct eth_classify_mac_cmd {
struct eth_classify_cmd_header header;
- __le32 reserved0;
+ __le16 reserved0;
+ __le16 inner_mac;
__le16 mac_lsb;
__le16 mac_mid;
__le16 mac_msb;
@@ -3633,7 +3661,8 @@ struct eth_classify_mac_cmd {
*/
struct eth_classify_pair_cmd {
struct eth_classify_cmd_header header;
- __le32 reserved0;
+ __le16 reserved0;
+ __le16 inner_mac;
__le16 mac_lsb;
__le16 mac_mid;
__le16 mac_msb;
@@ -3855,8 +3884,68 @@ struct eth_halt_ramrod_data {
/*
- * Command for setting multicast classification for a client
+ * destination and source mac address.
+ */
+struct eth_mac_addresses {
+#if defined(__BIG_ENDIAN)
+ __le16 dst_mid;
+ __le16 dst_lo;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 dst_lo;
+ __le16 dst_mid;
+#endif
+#if defined(__BIG_ENDIAN)
+ __le16 src_lo;
+ __le16 dst_hi;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 dst_hi;
+ __le16 src_lo;
+#endif
+#if defined(__BIG_ENDIAN)
+ __le16 src_hi;
+ __le16 src_mid;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 src_mid;
+ __le16 src_hi;
+#endif
+};
+
+/* tunneling related data */
+struct eth_tunnel_data {
+#if defined(__BIG_ENDIAN)
+ __le16 dst_mid;
+ __le16 dst_lo;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 dst_lo;
+ __le16 dst_mid;
+#endif
+#if defined(__BIG_ENDIAN)
+ __le16 reserved0;
+ __le16 dst_hi;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 dst_hi;
+ __le16 reserved0;
+#endif
+#if defined(__BIG_ENDIAN)
+ u8 reserved1;
+ u8 ip_hdr_start_inner_w;
+ __le16 pseudo_csum;
+#elif defined(__LITTLE_ENDIAN)
+ __le16 pseudo_csum;
+ u8 ip_hdr_start_inner_w;
+ u8 reserved1;
+#endif
+};
+
+/* union for mac addresses and for tunneling data.
+ * considered as tunneling data only if (tunnel_exist == 1).
*/
+union eth_mac_addr_or_tunnel_data {
+ struct eth_mac_addresses mac_addr;
+ struct eth_tunnel_data tunnel_data;
+};
+
+/*Command for setting multicast classification for a client */
struct eth_multicast_rules_cmd {
u8 cmd_general_data;
#define ETH_MULTICAST_RULES_CMD_RX_CMD (0x1<<0)
@@ -3874,7 +3963,6 @@ struct eth_multicast_rules_cmd {
struct regpair reserved3;
};
-
/*
* parameters for multicast classification ramrod
*/
@@ -3883,7 +3971,6 @@ struct eth_multicast_rules_ramrod_data {
struct eth_multicast_rules_cmd rules[MULTICAST_RULES_COUNT];
};
-
/*
* Place holder for ramrods protocol specific data
*/
@@ -3947,11 +4034,14 @@ struct eth_rss_update_ramrod_data {
#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 4
#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<5)
#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 5
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<6)
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 6
#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<7)
#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 7
u8 rss_result_mask;
u8 rss_mode;
- __le32 __reserved2;
+ __le16 udp_4tuple_dst_port_mask;
+ __le16 udp_4tuple_dst_port_value;
u8 indirection_table[T_ETH_INDIRECTION_TABLE_SIZE];
__le32 rss_key[T_ETH_RSS_KEY];
__le32 echo;
@@ -4115,6 +4205,23 @@ enum eth_tpa_update_command {
MAX_ETH_TPA_UPDATE_COMMAND
};
+/* In case of LSO over IPv4 tunnel, whether to increment
+ * IP ID on external IP header or internal IP header
+ */
+enum eth_tunnel_lso_inc_ip_id {
+ EXT_HEADER,
+ INT_HEADER,
+ MAX_ETH_TUNNEL_LSO_INC_IP_ID
+};
+
+/* In case tunnel exist and L4 checksum offload,
+ * the pseudo checksum location, on packet or on BD.
+ */
+enum eth_tunnel_non_lso_pcsum_location {
+ PCSUM_ON_PKT,
+ PCSUM_ON_BD,
+ MAX_ETH_TUNNEL_NON_LSO_PCSUM_LOCATION
+};
/*
* Tx regular BD structure
@@ -4166,8 +4273,8 @@ struct eth_tx_start_bd {
#define ETH_TX_START_BD_FORCE_VLAN_MODE_SHIFT 4
#define ETH_TX_START_BD_PARSE_NBDS (0x3<<5)
#define ETH_TX_START_BD_PARSE_NBDS_SHIFT 5
-#define ETH_TX_START_BD_RESREVED (0x1<<7)
-#define ETH_TX_START_BD_RESREVED_SHIFT 7
+#define ETH_TX_START_BD_TUNNEL_EXIST (0x1<<7)
+#define ETH_TX_START_BD_TUNNEL_EXIST_SHIFT 7
};
/*
@@ -4216,15 +4323,10 @@ struct eth_tx_parse_bd_e1x {
* Tx parsing BD structure for ETH E2
*/
struct eth_tx_parse_bd_e2 {
- __le16 dst_mac_addr_lo;
- __le16 dst_mac_addr_mid;
- __le16 dst_mac_addr_hi;
- __le16 src_mac_addr_lo;
- __le16 src_mac_addr_mid;
- __le16 src_mac_addr_hi;
+ union eth_mac_addr_or_tunnel_data data;
__le32 parsing_data;
-#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W (0x7FF<<0)
-#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT 0
+#define ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W (0x7FF<<0)
+#define ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT 0
#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW (0xF<<11)
#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT 11
#define ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR (0x1<<15)
@@ -4236,8 +4338,51 @@ struct eth_tx_parse_bd_e2 {
};
/*
- * The last BD in the BD memory will hold a pointer to the next BD memory
+ * Tx 2nd parsing BD structure for ETH packet
*/
+struct eth_tx_parse_2nd_bd {
+ __le16 global_data;
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W (0xF<<0)
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W_SHIFT 0
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER (0x1<<4)
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT 4
+#define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN (0x1<<5)
+#define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT 5
+#define ETH_TX_PARSE_2ND_BD_NS_FLG (0x1<<6)
+#define ETH_TX_PARSE_2ND_BD_NS_FLG_SHIFT 6
+#define ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST (0x1<<7)
+#define ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST_SHIFT 7
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W (0x1F<<8)
+#define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT 8
+#define ETH_TX_PARSE_2ND_BD_RESERVED0 (0x7<<13)
+#define ETH_TX_PARSE_2ND_BD_RESERVED0_SHIFT 13
+ __le16 reserved1;
+ u8 tcp_flags;
+#define ETH_TX_PARSE_2ND_BD_FIN_FLG (0x1<<0)
+#define ETH_TX_PARSE_2ND_BD_FIN_FLG_SHIFT 0
+#define ETH_TX_PARSE_2ND_BD_SYN_FLG (0x1<<1)
+#define ETH_TX_PARSE_2ND_BD_SYN_FLG_SHIFT 1
+#define ETH_TX_PARSE_2ND_BD_RST_FLG (0x1<<2)
+#define ETH_TX_PARSE_2ND_BD_RST_FLG_SHIFT 2
+#define ETH_TX_PARSE_2ND_BD_PSH_FLG (0x1<<3)
+#define ETH_TX_PARSE_2ND_BD_PSH_FLG_SHIFT 3
+#define ETH_TX_PARSE_2ND_BD_ACK_FLG (0x1<<4)
+#define ETH_TX_PARSE_2ND_BD_ACK_FLG_SHIFT 4
+#define ETH_TX_PARSE_2ND_BD_URG_FLG (0x1<<5)
+#define ETH_TX_PARSE_2ND_BD_URG_FLG_SHIFT 5
+#define ETH_TX_PARSE_2ND_BD_ECE_FLG (0x1<<6)
+#define ETH_TX_PARSE_2ND_BD_ECE_FLG_SHIFT 6
+#define ETH_TX_PARSE_2ND_BD_CWR_FLG (0x1<<7)
+#define ETH_TX_PARSE_2ND_BD_CWR_FLG_SHIFT 7
+ u8 reserved2;
+ u8 tunnel_udp_hdr_start_w;
+ u8 fw_ip_hdr_to_payload_w;
+ __le16 fw_ip_csum_wo_len_flags_frag;
+ __le16 hw_ip_id;
+ __le32 tcp_send_seq;
+};
+
+/* The last BD in the BD memory will hold a pointer to the next BD memory */
struct eth_tx_next_bd {
__le32 addr_lo;
__le32 addr_hi;
@@ -4252,6 +4397,7 @@ union eth_tx_bd_types {
struct eth_tx_bd reg_bd;
struct eth_tx_parse_bd_e1x parse_bd_e1x;
struct eth_tx_parse_bd_e2 parse_bd_e2;
+ struct eth_tx_parse_2nd_bd parse_2nd_bd;
struct eth_tx_next_bd next_bd;
};
@@ -4663,10 +4809,10 @@ enum common_spqe_cmd_id {
RAMROD_CMD_ID_COMMON_STOP_TRAFFIC,
RAMROD_CMD_ID_COMMON_START_TRAFFIC,
RAMROD_CMD_ID_COMMON_AFEX_VIF_LISTS,
+ RAMROD_CMD_ID_COMMON_SET_TIMESYNC,
MAX_COMMON_SPQE_CMD_ID
};
-
/*
* Per-protocol connection types
*/
@@ -4863,7 +5009,7 @@ struct vf_flr_event_data {
*/
struct malicious_vf_event_data {
u8 vf_id;
- u8 reserved0;
+ u8 err_id;
u16 reserved1;
u32 reserved2;
u32 reserved3;
@@ -4969,10 +5115,10 @@ enum event_ring_opcode {
EVENT_RING_OPCODE_CLASSIFICATION_RULES,
EVENT_RING_OPCODE_FILTERS_RULES,
EVENT_RING_OPCODE_MULTICAST_RULES,
+ EVENT_RING_OPCODE_SET_TIMESYNC,
MAX_EVENT_RING_OPCODE
};
-
/*
* Modes for fairness algorithm
*/
@@ -5010,14 +5156,18 @@ struct flow_control_configuration {
*/
struct function_start_data {
u8 function_mode;
- u8 reserved;
+ u8 allow_npar_tx_switching;
__le16 sd_vlan_tag;
__le16 vif_id;
u8 path_id;
u8 network_cos_mode;
+ u8 dmae_cmd_id;
+ u8 gre_tunnel_mode;
+ u8 gre_tunnel_rss;
+ u8 nvgre_clss_en;
+ __le16 reserved1[2];
};
-
struct function_update_data {
u8 vif_id_change_flg;
u8 afex_default_vlan_change_flg;
@@ -5027,14 +5177,19 @@ struct function_update_data {
__le16 afex_default_vlan;
u8 allowed_priorities;
u8 network_cos_mode;
+ u8 lb_mode_en_change_flg;
u8 lb_mode_en;
u8 tx_switch_suspend_change_flg;
u8 tx_switch_suspend;
u8 echo;
- __le16 reserved1;
+ u8 reserved1;
+ u8 update_gre_cfg_flg;
+ u8 gre_tunnel_mode;
+ u8 gre_tunnel_rss;
+ u8 nvgre_clss_en;
+ u32 reserved3;
};
-
/*
* FW version stored in the Xstorm RAM
*/
@@ -5061,6 +5216,22 @@ struct fw_version {
#define __FW_VERSION_RESERVED_SHIFT 4
};
+/* GRE RSS Mode */
+enum gre_rss_mode {
+ GRE_OUTER_HEADERS_RSS,
+ GRE_INNER_HEADERS_RSS,
+ NVGRE_KEY_ENTROPY_RSS,
+ MAX_GRE_RSS_MODE
+};
+
+/* GRE Tunnel Mode */
+enum gre_tunnel_type {
+ NO_GRE_TUNNEL,
+ NVGRE_TUNNEL,
+ L2GRE_TUNNEL,
+ IPGRE_TUNNEL,
+ MAX_GRE_TUNNEL_TYPE
+};
/*
* Dynamic Host-Coalescing - Driver(host) counters
@@ -5224,6 +5395,26 @@ enum ip_ver {
MAX_IP_VER
};
+/*
+ * Malicious VF error ID
+ */
+enum malicious_vf_error_id {
+ VF_PF_CHANNEL_NOT_READY,
+ ETH_ILLEGAL_BD_LENGTHS,
+ ETH_PACKET_TOO_SHORT,
+ ETH_PAYLOAD_TOO_BIG,
+ ETH_ILLEGAL_ETH_TYPE,
+ ETH_ILLEGAL_LSO_HDR_LEN,
+ ETH_TOO_MANY_BDS,
+ ETH_ZERO_HDR_NBDS,
+ ETH_START_BD_NOT_SET,
+ ETH_ILLEGAL_PARSE_NBDS,
+ ETH_IPV6_AND_CHECKSUM,
+ ETH_VLAN_FLG_INCORRECT,
+ ETH_ILLEGAL_LSO_MSS,
+ ETH_TUNNEL_NOT_SUPPORTED,
+ MAX_MALICIOUS_VF_ERROR_ID
+};
/*
* Multi-function modes
@@ -5368,7 +5559,6 @@ struct protocol_common_spe {
union protocol_common_specific_data data;
};
-
/*
* The send queue element
*/
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 77ebae0ac64a..9d64b988ab34 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -27,6 +27,10 @@
#include "bnx2x.h"
#include "bnx2x_cmn.h"
+typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
+ struct link_params *params,
+ u8 dev_addr, u16 addr, u8 byte_cnt,
+ u8 *o_buf, u8);
/********************************************************/
#define ETH_HLEN 14
/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
@@ -152,6 +156,7 @@
#define SFP_EEPROM_CON_TYPE_ADDR 0x2
#define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
#define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
+ #define SFP_EEPROM_CON_TYPE_VAL_RJ45 0x22
#define SFP_EEPROM_COMP_CODE_ADDR 0x3
@@ -3127,11 +3132,6 @@ static int bnx2x_bsc_read(struct link_params *params,
int rc = 0;
struct bnx2x *bp = params->bp;
- if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) {
- DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid);
- return -EINVAL;
- }
-
if (xfer_cnt > 16) {
DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n",
xfer_cnt);
@@ -3426,13 +3426,19 @@ static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
switch (phy->req_flow_ctrl) {
case BNX2X_FLOW_CTRL_AUTO:
- if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
+ switch (params->req_fc_auto_adv) {
+ case BNX2X_FLOW_CTRL_BOTH:
*ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
- else
+ break;
+ case BNX2X_FLOW_CTRL_RX:
+ case BNX2X_FLOW_CTRL_TX:
*ieee_fc |=
- MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+ break;
+ default:
+ break;
+ }
break;
-
case BNX2X_FLOW_CTRL_TX:
*ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
break;
@@ -3629,6 +3635,16 @@ static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
* init configuration, and set/clear SGMII flag. Internal
* phy init is done purely in phy_init stage.
*/
+#define WC_TX_DRIVER(post2, idriver, ipre) \
+ ((post2 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | \
+ (idriver << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | \
+ (ipre << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET))
+
+#define WC_TX_FIR(post, main, pre) \
+ ((post << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | \
+ (main << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | \
+ (pre << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET))
+
static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
struct link_params *params,
struct link_vars *vars)
@@ -3728,7 +3744,7 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
if (((vars->line_speed == SPEED_AUTO_NEG) &&
(phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
(vars->line_speed == SPEED_1000)) {
- u32 addr = MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2;
+ u16 addr = MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2;
an_adv |= (1<<5);
/* Enable CL37 1G Parallel Detect */
@@ -3753,20 +3769,13 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy,
/* Set Transmit PMD settings */
lane = bnx2x_get_warpcore_lane(phy, params);
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
- MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
- ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
- (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
+ MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
+ WC_TX_DRIVER(0x02, 0x06, 0x09));
/* Configure the next lane if dual mode */
if (phy->flags & FLAGS_WC_DUAL_MODE)
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_TX0_TX_DRIVER + 0x10*(lane+1),
- ((0x02 <<
- MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
- (0x06 <<
- MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x09 <<
- MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
+ WC_TX_DRIVER(0x02, 0x06, 0x09));
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL,
0x03f0);
@@ -3909,6 +3918,8 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
{
struct bnx2x *bp = params->bp;
u16 misc1_val, tap_val, tx_driver_val, lane, val;
+ u32 cfg_tap_val, tx_drv_brdct, tx_equal;
+
/* Hold rxSeqStart */
bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, 0x8000);
@@ -3952,23 +3963,33 @@ static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy,
if (is_xfi) {
misc1_val |= 0x5;
- tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
- (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
- (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
- tx_driver_val =
- ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
- (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
-
+ tap_val = WC_TX_FIR(0x08, 0x37, 0x00);
+ tx_driver_val = WC_TX_DRIVER(0x00, 0x02, 0x03);
} else {
+ cfg_tap_val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_hw_config[params->port].
+ sfi_tap_values));
+
+ tx_equal = cfg_tap_val & PORT_HW_CFG_TX_EQUALIZATION_MASK;
+
+ tx_drv_brdct = (cfg_tap_val &
+ PORT_HW_CFG_TX_DRV_BROADCAST_MASK) >>
+ PORT_HW_CFG_TX_DRV_BROADCAST_SHIFT;
+
misc1_val |= 0x9;
- tap_val = ((0x0f << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
- (0x2b << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
- (0x02 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET));
- tx_driver_val =
- ((0x03 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
- (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET));
+
+ /* TAP values are controlled by nvram, if value there isn't 0 */
+ if (tx_equal)
+ tap_val = (u16)tx_equal;
+ else
+ tap_val = WC_TX_FIR(0x0f, 0x2b, 0x02);
+
+ if (tx_drv_brdct)
+ tx_driver_val = WC_TX_DRIVER(0x03, (u16)tx_drv_brdct,
+ 0x06);
+ else
+ tx_driver_val = WC_TX_DRIVER(0x03, 0x02, 0x06);
}
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val);
@@ -4105,15 +4126,11 @@ static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp,
/* Set Transmit PMD settings */
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
MDIO_WC_REG_TX_FIR_TAP,
- ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) |
- (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) |
- (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) |
- MDIO_WC_REG_TX_FIR_TAP_ENABLE));
+ (WC_TX_FIR(0x12, 0x2d, 0x00) |
+ MDIO_WC_REG_TX_FIR_TAP_ENABLE));
bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD,
- MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
- ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) |
- (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) |
- (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)));
+ MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane,
+ WC_TX_DRIVER(0x02, 0x02, 0x02));
}
static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy,
@@ -4750,8 +4767,8 @@ void bnx2x_link_status_update(struct link_params *params,
port_mb[port].link_status));
/* Force link UP in non LOOPBACK_EXT loopback mode(s) */
- if (bp->link_params.loopback_mode != LOOPBACK_NONE &&
- bp->link_params.loopback_mode != LOOPBACK_EXT)
+ if (params->loopback_mode != LOOPBACK_NONE &&
+ params->loopback_mode != LOOPBACK_EXT)
vars->link_status |= LINK_STATUS_LINK_UP;
if (bnx2x_eee_has_cap(params))
@@ -7758,7 +7775,8 @@ static void bnx2x_sfp_set_transmitter(struct link_params *params,
static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
struct link_params *params,
- u16 addr, u8 byte_cnt, u8 *o_buf)
+ u8 dev_addr, u16 addr, u8 byte_cnt,
+ u8 *o_buf, u8 is_init)
{
struct bnx2x *bp = params->bp;
u16 val = 0;
@@ -7771,7 +7789,7 @@ static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
/* Set the read command byte count */
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
- (byte_cnt | 0xa000));
+ (byte_cnt | (dev_addr << 8)));
/* Set the read command address */
bnx2x_cl45_write(bp, phy,
@@ -7845,6 +7863,7 @@ static void bnx2x_warpcore_power_module(struct link_params *params,
}
static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
struct link_params *params,
+ u8 dev_addr,
u16 addr, u8 byte_cnt,
u8 *o_buf, u8 is_init)
{
@@ -7869,7 +7888,7 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
usleep_range(1000, 2000);
bnx2x_warpcore_power_module(params, 1);
}
- rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt,
+ rc = bnx2x_bsc_read(params, phy, dev_addr, addr32, 0, byte_cnt,
data_array);
} while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT));
@@ -7885,7 +7904,8 @@ static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy,
static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
struct link_params *params,
- u16 addr, u8 byte_cnt, u8 *o_buf)
+ u8 dev_addr, u16 addr, u8 byte_cnt,
+ u8 *o_buf, u8 is_init)
{
struct bnx2x *bp = params->bp;
u16 val, i;
@@ -7896,6 +7916,15 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
return -EINVAL;
}
+ /* Set 2-wire transfer rate of SFP+ module EEPROM
+ * to 100Khz since some DACs(direct attached cables) do
+ * not work at 400Khz.
+ */
+ bnx2x_cl45_write(bp, phy,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+ ((dev_addr << 8) | 1));
+
/* Need to read from 1.8000 to clear it */
bnx2x_cl45_read(bp, phy,
MDIO_PMA_DEVAD,
@@ -7968,26 +7997,44 @@ static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
return -EINVAL;
}
-
int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
- struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf)
+ struct link_params *params, u8 dev_addr,
+ u16 addr, u16 byte_cnt, u8 *o_buf)
{
- int rc = -EOPNOTSUPP;
+ int rc = 0;
+ struct bnx2x *bp = params->bp;
+ u8 xfer_size;
+ u8 *user_data = o_buf;
+ read_sfp_module_eeprom_func_p read_func;
+
+ if ((dev_addr != 0xa0) && (dev_addr != 0xa2)) {
+ DP(NETIF_MSG_LINK, "invalid dev_addr 0x%x\n", dev_addr);
+ return -EINVAL;
+ }
+
switch (phy->type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
- rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
- byte_cnt, o_buf);
- break;
+ read_func = bnx2x_8726_read_sfp_module_eeprom;
+ break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
- rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
- byte_cnt, o_buf);
- break;
+ read_func = bnx2x_8727_read_sfp_module_eeprom;
+ break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
- rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr,
- byte_cnt, o_buf, 0);
- break;
+ read_func = bnx2x_warpcore_read_sfp_module_eeprom;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ while (!rc && (byte_cnt > 0)) {
+ xfer_size = (byte_cnt > SFP_EEPROM_PAGE_SIZE) ?
+ SFP_EEPROM_PAGE_SIZE : byte_cnt;
+ rc = read_func(phy, params, dev_addr, addr, xfer_size,
+ user_data, 0);
+ byte_cnt -= xfer_size;
+ user_data += xfer_size;
+ addr += xfer_size;
}
return rc;
}
@@ -8004,6 +8051,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
/* First check for copper cable */
if (bnx2x_read_sfp_module_eeprom(phy,
params,
+ I2C_DEV_ADDR_A0,
SFP_EEPROM_CON_TYPE_ADDR,
2,
(u8 *)val) != 0) {
@@ -8021,6 +8069,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
*/
if (bnx2x_read_sfp_module_eeprom(phy,
params,
+ I2C_DEV_ADDR_A0,
SFP_EEPROM_FC_TX_TECH_ADDR,
1,
&copper_module_type) != 0) {
@@ -8049,20 +8098,24 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
break;
}
case SFP_EEPROM_CON_TYPE_VAL_LC:
+ case SFP_EEPROM_CON_TYPE_VAL_RJ45:
check_limiting_mode = 1;
if ((val[1] & (SFP_EEPROM_COMP_CODE_SR_MASK |
SFP_EEPROM_COMP_CODE_LR_MASK |
SFP_EEPROM_COMP_CODE_LRM_MASK)) == 0) {
- DP(NETIF_MSG_LINK, "1G Optic module detected\n");
+ DP(NETIF_MSG_LINK, "1G SFP module detected\n");
gport = params->port;
phy->media_type = ETH_PHY_SFP_1G_FIBER;
- phy->req_line_speed = SPEED_1000;
- if (!CHIP_IS_E1x(bp))
- gport = BP_PATH(bp) + (params->port << 1);
- netdev_err(bp->dev, "Warning: Link speed was forced to 1000Mbps."
- " Current SFP module in port %d is not"
- " compliant with 10G Ethernet\n",
- gport);
+ if (phy->req_line_speed != SPEED_1000) {
+ phy->req_line_speed = SPEED_1000;
+ if (!CHIP_IS_E1x(bp)) {
+ gport = BP_PATH(bp) +
+ (params->port << 1);
+ }
+ netdev_err(bp->dev,
+ "Warning: Link speed was forced to 1000Mbps. Current SFP module in port %d is not compliant with 10G Ethernet\n",
+ gport);
+ }
} else {
int idx, cfg_idx = 0;
DP(NETIF_MSG_LINK, "10G Optic module detected\n");
@@ -8101,6 +8154,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
u8 options[SFP_EEPROM_OPTIONS_SIZE];
if (bnx2x_read_sfp_module_eeprom(phy,
params,
+ I2C_DEV_ADDR_A0,
SFP_EEPROM_OPTIONS_ADDR,
SFP_EEPROM_OPTIONS_SIZE,
options) != 0) {
@@ -8167,6 +8221,7 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
/* Format the warning message */
if (bnx2x_read_sfp_module_eeprom(phy,
params,
+ I2C_DEV_ADDR_A0,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
(u8 *)vendor_name))
@@ -8175,6 +8230,7 @@ static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
if (bnx2x_read_sfp_module_eeprom(phy,
params,
+ I2C_DEV_ADDR_A0,
SFP_EEPROM_PART_NO_ADDR,
SFP_EEPROM_PART_NO_SIZE,
(u8 *)vendor_pn))
@@ -8205,12 +8261,13 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
for (timeout = 0; timeout < 60; timeout++) {
if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
- rc = bnx2x_warpcore_read_sfp_module_eeprom(phy,
- params, 1,
- 1, &val, 1);
+ rc = bnx2x_warpcore_read_sfp_module_eeprom(
+ phy, params, I2C_DEV_ADDR_A0, 1, 1, &val,
+ 1);
else
- rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1,
- &val);
+ rc = bnx2x_read_sfp_module_eeprom(phy, params,
+ I2C_DEV_ADDR_A0,
+ 1, 1, &val);
if (rc == 0) {
DP(NETIF_MSG_LINK,
"SFP+ module initialization took %d ms\n",
@@ -8219,7 +8276,8 @@ static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
}
usleep_range(5000, 10000);
}
- rc = bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val);
+ rc = bnx2x_read_sfp_module_eeprom(phy, params, I2C_DEV_ADDR_A0,
+ 1, 1, &val);
return rc;
}
@@ -8376,15 +8434,6 @@ static void bnx2x_8727_specific_func(struct bnx2x_phy *phy,
bnx2x_cl45_write(bp, phy,
MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL,
val);
-
- /* Set 2-wire transfer rate of SFP+ module EEPROM
- * to 100Khz since some DACs(direct attached cables) do
- * not work at 400Khz.
- */
- bnx2x_cl45_write(bp, phy,
- MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
- 0xa001);
break;
default:
DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n",
@@ -9528,8 +9577,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
} else {
/* For 32-bit registers in 848xx, access via MDIO2ARM i/f. */
/* (1) set reg 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
- for (i = 0; i < ARRAY_SIZE(reg_set);
- i++)
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
bnx2x_cl45_write(bp, phy, reg_set[i].devad,
reg_set[i].reg, reg_set[i].val);
@@ -10281,7 +10329,8 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE;
/* Determine if EEE was negotiated */
- if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
+ if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) ||
+ (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834))
bnx2x_eee_an_resolve(phy, params, vars);
}
@@ -12242,7 +12291,7 @@ static void bnx2x_init_bmac_loopback(struct link_params *params,
bnx2x_xgxs_deassert(params);
- /* set bmac loopback */
+ /* Set bmac loopback */
bnx2x_bmac_enable(params, vars, 1, 1);
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
@@ -12261,7 +12310,7 @@ static void bnx2x_init_emac_loopback(struct link_params *params,
vars->phy_flags = PHY_XGXS_FLAG;
bnx2x_xgxs_deassert(params);
- /* set bmac loopback */
+ /* Set bmac loopback */
bnx2x_emac_enable(params, vars, 1);
bnx2x_emac_program(params, vars);
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
@@ -12521,6 +12570,7 @@ int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
params->req_line_speed[0], params->req_flow_ctrl[0]);
DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
params->req_line_speed[1], params->req_flow_ctrl[1]);
+ DP(NETIF_MSG_LINK, "req_adv_flow_ctrl 0x%x\n", params->req_fc_auto_adv);
vars->link_status = 0;
vars->phy_link_up = 0;
vars->link_up = 0;
@@ -13437,23 +13487,27 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
{
struct bnx2x *bp = params->bp;
u16 base_page, next_page, not_kr2_device, lane;
- int sigdet = bnx2x_warpcore_get_sigdet(phy, params);
-
- if (!sigdet) {
- if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE))
- bnx2x_kr2_recovery(params, vars, phy);
- return;
- }
+ int sigdet;
/* Once KR2 was disabled, wait 5 seconds before checking KR2 recovery
- * since some switches tend to reinit the AN process and clear the
- * advertised BP/NP after ~2 seconds causing the KR2 to be disabled
+ * Since some switches tend to reinit the AN process and clear the
+ * the advertised BP/NP after ~2 seconds causing the KR2 to be disabled
* and recovered many times
*/
if (vars->check_kr2_recovery_cnt > 0) {
vars->check_kr2_recovery_cnt--;
return;
}
+
+ sigdet = bnx2x_warpcore_get_sigdet(phy, params);
+ if (!sigdet) {
+ if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
+ bnx2x_kr2_recovery(params, vars, phy);
+ DP(NETIF_MSG_LINK, "No sigdet\n");
+ }
+ return;
+ }
+
lane = bnx2x_get_warpcore_lane(phy, params);
CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
MDIO_AER_BLOCK_AER_REG, lane);
@@ -13465,8 +13519,10 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
/* CL73 has not begun yet */
if (base_page == 0) {
- if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE))
+ if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
bnx2x_kr2_recovery(params, vars, phy);
+ DP(NETIF_MSG_LINK, "No BP\n");
+ }
return;
}
@@ -13482,7 +13538,7 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
if (!not_kr2_device) {
DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page,
- next_page);
+ next_page);
bnx2x_kr2_recovery(params, vars, phy);
}
return;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index 56c2aae4e2c8..4df45234fdc0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -41,6 +41,9 @@
#define SPEED_AUTO_NEG 0
#define SPEED_20000 20000
+#define I2C_DEV_ADDR_A0 0xa0
+#define I2C_DEV_ADDR_A2 0xa2
+
#define SFP_EEPROM_PAGE_SIZE 16
#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
#define SFP_EEPROM_VENDOR_NAME_SIZE 16
@@ -54,6 +57,15 @@
#define SFP_EEPROM_SERIAL_SIZE 16
#define SFP_EEPROM_DATE_ADDR 0x54 /* ASCII YYMMDD */
#define SFP_EEPROM_DATE_SIZE 6
+#define SFP_EEPROM_DIAG_TYPE_ADDR 0x5c
+#define SFP_EEPROM_DIAG_TYPE_SIZE 1
+#define SFP_EEPROM_DIAG_ADDR_CHANGE_REQ (1<<2)
+#define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e
+#define SFP_EEPROM_SFF_8472_COMP_SIZE 1
+
+#define SFP_EEPROM_A2_CHECKSUM_RANGE 0x5e
+#define SFP_EEPROM_A2_CC_DMI_ADDR 0x5f
+
#define PWR_FLT_ERR_MSG_LEN 250
#define XGXS_EXT_PHY_TYPE(ext_phy_config) \
@@ -420,8 +432,8 @@ void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy);
/* Read "byte_cnt" bytes from address "addr" from the SFP+ EEPROM */
int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
- struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf);
+ struct link_params *params, u8 dev_addr,
+ u16 addr, u16 byte_cnt, u8 *o_buf);
void bnx2x_hw_reset_phy(struct link_params *params);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index e81a747ea8ce..b4c9dea93a53 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -75,8 +75,6 @@
#define FW_FILE_NAME_E1H "bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
#define FW_FILE_NAME_E2 "bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
-#define MAC_LEADING_ZERO_CNT (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
-
/* Time in jiffies before concluding the transmitter is hung */
#define TX_TIMEOUT (5*HZ)
@@ -2955,14 +2953,16 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
__set_bit(BNX2X_Q_FLG_ACTIVE, &flags);
/* tx only connections collect statistics (on the same index as the
- * parent connection). The statistics are zeroed when the parent
- * connection is initialized.
+ * parent connection). The statistics are zeroed when the parent
+ * connection is initialized.
*/
__set_bit(BNX2X_Q_FLG_STATS, &flags);
if (zero_stats)
__set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
+ __set_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, &flags);
+ __set_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, &flags);
#ifdef BNX2X_STOP_ON_ERROR
__set_bit(BNX2X_Q_FLG_TX_SEC, &flags);
@@ -3227,16 +3227,29 @@ static void bnx2x_drv_info_ether_stat(struct bnx2x *bp)
{
struct eth_stats_info *ether_stat =
&bp->slowpath->drv_info_to_mcp.ether_stat;
+ struct bnx2x_vlan_mac_obj *mac_obj =
+ &bp->sp_objs->mac_obj;
+ int i;
strlcpy(ether_stat->version, DRV_MODULE_VERSION,
ETH_STAT_INFO_VERSION_LEN);
- bp->sp_objs[0].mac_obj.get_n_elements(bp, &bp->sp_objs[0].mac_obj,
- DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
- ether_stat->mac_local);
-
+ /* get DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED macs, placing them in the
+ * mac_local field in ether_stat struct. The base address is offset by 2
+ * bytes to account for the field being 8 bytes but a mac address is
+ * only 6 bytes. Likewise, the stride for the get_n_elements function is
+ * 2 bytes to compensate from the 6 bytes of a mac to the 8 bytes
+ * allocated by the ether_stat struct, so the macs will land in their
+ * proper positions.
+ */
+ for (i = 0; i < DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED; i++)
+ memset(ether_stat->mac_local + i, 0,
+ sizeof(ether_stat->mac_local[0]));
+ mac_obj->get_n_elements(bp, &bp->sp_objs[0].mac_obj,
+ DRV_INFO_ETH_STAT_NUM_MACS_REQUIRED,
+ ether_stat->mac_local + MAC_PAD, MAC_PAD,
+ ETH_ALEN);
ether_stat->mtu_size = bp->dev->mtu;
-
if (bp->dev->features & NETIF_F_RXCSUM)
ether_stat->feature_flags |= FEATURE_ETH_CHKSUM_OFFLOAD_MASK;
if (bp->dev->features & NETIF_F_TSO)
@@ -3258,8 +3271,7 @@ static void bnx2x_drv_info_fcoe_stat(struct bnx2x *bp)
if (!CNIC_LOADED(bp))
return;
- memcpy(fcoe_stat->mac_local + MAC_LEADING_ZERO_CNT,
- bp->fip_mac, ETH_ALEN);
+ memcpy(fcoe_stat->mac_local + MAC_PAD, bp->fip_mac, ETH_ALEN);
fcoe_stat->qos_priority =
app->traffic_type_priority[LLFC_TRAFFIC_TYPE_FCOE];
@@ -3361,8 +3373,8 @@ static void bnx2x_drv_info_iscsi_stat(struct bnx2x *bp)
if (!CNIC_LOADED(bp))
return;
- memcpy(iscsi_stat->mac_local + MAC_LEADING_ZERO_CNT,
- bp->cnic_eth_dev.iscsi_mac, ETH_ALEN);
+ memcpy(iscsi_stat->mac_local + MAC_PAD, bp->cnic_eth_dev.iscsi_mac,
+ ETH_ALEN);
iscsi_stat->qos_priority =
app->traffic_type_priority[LLFC_TRAFFIC_TYPE_ISCSI];
@@ -4947,7 +4959,7 @@ static void bnx2x_after_function_update(struct bnx2x *bp)
q);
}
- if (!NO_FCOE(bp)) {
+ if (!NO_FCOE(bp) && CNIC_ENABLED(bp)) {
fp = &bp->fp[FCOE_IDX(bp)];
queue_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
@@ -6018,10 +6030,11 @@ void bnx2x_nic_init_cnic(struct bnx2x *bp)
mmiowb();
}
-void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
+void bnx2x_pre_irq_nic_init(struct bnx2x *bp)
{
int i;
+ /* Setup NIC internals and enable interrupts */
for_each_eth_queue(bp, i)
bnx2x_init_eth_fp(bp, i);
@@ -6030,17 +6043,26 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
bnx2x_init_rx_rings(bp);
bnx2x_init_tx_rings(bp);
- if (IS_VF(bp))
+ if (IS_VF(bp)) {
+ bnx2x_memset_stats(bp);
return;
+ }
- /* Initialize MOD_ABS interrupts */
- bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
- bp->common.shmem_base, bp->common.shmem2_base,
- BP_PORT(bp));
+ if (IS_PF(bp)) {
+ /* Initialize MOD_ABS interrupts */
+ bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
+ bp->common.shmem_base,
+ bp->common.shmem2_base, BP_PORT(bp));
+
+ /* initialize the default status block and sp ring */
+ bnx2x_init_def_sb(bp);
+ bnx2x_update_dsb_idx(bp);
+ bnx2x_init_sp_ring(bp);
+ }
+}
- bnx2x_init_def_sb(bp);
- bnx2x_update_dsb_idx(bp);
- bnx2x_init_sp_ring(bp);
+void bnx2x_post_irq_nic_init(struct bnx2x *bp, u32 load_code)
+{
bnx2x_init_eq_ring(bp);
bnx2x_init_internal(bp, load_code);
bnx2x_pf_init(bp);
@@ -6058,12 +6080,7 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
AEU_INPUTS_ATTN_BITS_SPIO5);
}
-/* end of nic init */
-
-/*
- * gzip service functions
- */
-
+/* gzip service functions */
static int bnx2x_gunzip_init(struct bnx2x *bp)
{
bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
@@ -7757,6 +7774,8 @@ void bnx2x_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping,
BCM_PAGE_SIZE * NUM_EQ_PAGES);
+ BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, SRC_T2_SZ);
+
bnx2x_iov_free_mem(bp);
}
@@ -7773,7 +7792,7 @@ int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
sizeof(struct
host_hc_status_block_e1x));
- if (CONFIGURE_NIC_MODE(bp))
+ if (CONFIGURE_NIC_MODE(bp) && !bp->t2)
/* allocate searcher T2 table, as it wan't allocated before */
BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
@@ -7796,7 +7815,7 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
{
int i, allocated, context_size;
- if (!CONFIGURE_NIC_MODE(bp))
+ if (!CONFIGURE_NIC_MODE(bp) && !bp->t2)
/* allocate searcher T2 table */
BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
@@ -7917,8 +7936,6 @@ int bnx2x_del_all_macs(struct bnx2x *bp,
int bnx2x_set_eth_mac(struct bnx2x *bp, bool set)
{
- unsigned long ramrod_flags = 0;
-
if (is_zero_ether_addr(bp->dev->dev_addr) &&
(IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp))) {
DP(NETIF_MSG_IFUP | NETIF_MSG_IFDOWN,
@@ -7926,12 +7943,18 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set)
return 0;
}
- DP(NETIF_MSG_IFUP, "Adding Eth MAC\n");
+ if (IS_PF(bp)) {
+ unsigned long ramrod_flags = 0;
- __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
- /* Eth MAC is set on RSS leading client (fp[0]) */
- return bnx2x_set_mac_one(bp, bp->dev->dev_addr, &bp->sp_objs->mac_obj,
- set, BNX2X_ETH_MAC, &ramrod_flags);
+ DP(NETIF_MSG_IFUP, "Adding Eth MAC\n");
+ __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+ return bnx2x_set_mac_one(bp, bp->dev->dev_addr,
+ &bp->sp_objs->mac_obj, set,
+ BNX2X_ETH_MAC, &ramrod_flags);
+ } else { /* vf */
+ return bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr,
+ bp->fp->index, true);
+ }
}
int bnx2x_setup_leading(struct bnx2x *bp)
@@ -9525,6 +9548,10 @@ sp_rtnl_not_reset:
bnx2x_vfpf_storm_rx_mode(bp);
}
+ if (test_and_clear_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+ &bp->sp_rtnl_state))
+ bnx2x_pf_set_vfs_vlan(bp);
+
/* work which needs rtnl lock not-taken (as it takes the lock itself and
* can be called from other contexts as well)
*/
@@ -9532,8 +9559,10 @@ sp_rtnl_not_reset:
/* enable SR-IOV if applicable */
if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
- &bp->sp_rtnl_state))
+ &bp->sp_rtnl_state)) {
+ bnx2x_disable_sriov(bp);
bnx2x_enable_sriov(bp);
+ }
}
static void bnx2x_period_task(struct work_struct *work)
@@ -9701,6 +9730,31 @@ static struct bnx2x_prev_path_list *
return NULL;
}
+static int bnx2x_prev_path_mark_eeh(struct bnx2x *bp)
+{
+ struct bnx2x_prev_path_list *tmp_list;
+ int rc;
+
+ rc = down_interruptible(&bnx2x_prev_sem);
+ if (rc) {
+ BNX2X_ERR("Received %d when tried to take lock\n", rc);
+ return rc;
+ }
+
+ tmp_list = bnx2x_prev_path_get_entry(bp);
+ if (tmp_list) {
+ tmp_list->aer = 1;
+ rc = 0;
+ } else {
+ BNX2X_ERR("path %d: Entry does not exist for eeh; Flow occurs before initial insmod is over ?\n",
+ BP_PATH(bp));
+ }
+
+ up(&bnx2x_prev_sem);
+
+ return rc;
+}
+
static bool bnx2x_prev_is_path_marked(struct bnx2x *bp)
{
struct bnx2x_prev_path_list *tmp_list;
@@ -9709,14 +9763,15 @@ static bool bnx2x_prev_is_path_marked(struct bnx2x *bp)
if (down_trylock(&bnx2x_prev_sem))
return false;
- list_for_each_entry(tmp_list, &bnx2x_prev_list, list) {
- if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot &&
- bp->pdev->bus->number == tmp_list->bus &&
- BP_PATH(bp) == tmp_list->path) {
+ tmp_list = bnx2x_prev_path_get_entry(bp);
+ if (tmp_list) {
+ if (tmp_list->aer) {
+ DP(NETIF_MSG_HW, "Path %d was marked by AER\n",
+ BP_PATH(bp));
+ } else {
rc = true;
BNX2X_DEV_INFO("Path %d was already cleaned from previous drivers\n",
BP_PATH(bp));
- break;
}
}
@@ -9730,6 +9785,28 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
struct bnx2x_prev_path_list *tmp_list;
int rc;
+ rc = down_interruptible(&bnx2x_prev_sem);
+ if (rc) {
+ BNX2X_ERR("Received %d when tried to take lock\n", rc);
+ return rc;
+ }
+
+ /* Check whether the entry for this path already exists */
+ tmp_list = bnx2x_prev_path_get_entry(bp);
+ if (tmp_list) {
+ if (!tmp_list->aer) {
+ BNX2X_ERR("Re-Marking the path.\n");
+ } else {
+ DP(NETIF_MSG_HW, "Removing AER indication from path %d\n",
+ BP_PATH(bp));
+ tmp_list->aer = 0;
+ }
+ up(&bnx2x_prev_sem);
+ return 0;
+ }
+ up(&bnx2x_prev_sem);
+
+ /* Create an entry for this path and add it */
tmp_list = kmalloc(sizeof(struct bnx2x_prev_path_list), GFP_KERNEL);
if (!tmp_list) {
BNX2X_ERR("Failed to allocate 'bnx2x_prev_path_list'\n");
@@ -9739,6 +9816,7 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
tmp_list->bus = bp->pdev->bus->number;
tmp_list->slot = PCI_SLOT(bp->pdev->devfn);
tmp_list->path = BP_PATH(bp);
+ tmp_list->aer = 0;
tmp_list->undi = after_undi ? (1 << BP_PORT(bp)) : 0;
rc = down_interruptible(&bnx2x_prev_sem);
@@ -9746,8 +9824,8 @@ static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
BNX2X_ERR("Received %d when tried to take lock\n", rc);
kfree(tmp_list);
} else {
- BNX2X_DEV_INFO("Marked path [%d] - finished previous unload\n",
- BP_PATH(bp));
+ DP(NETIF_MSG_HW, "Marked path [%d] - finished previous unload\n",
+ BP_PATH(bp));
list_add(&tmp_list->list, &bnx2x_prev_list);
up(&bnx2x_prev_sem);
}
@@ -9878,6 +9956,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
REG_RD(bp, NIG_REG_NIG_INT_STS_CLR_0);
}
}
+ if (!CHIP_IS_E1x(bp))
+ /* block FW from writing to host */
+ REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0);
+
/* wait until BRB is empty */
tmp_reg = REG_RD(bp, BRB1_REG_NUM_OF_FULL_BLOCKS);
while (timer_count) {
@@ -9986,6 +10068,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
}
do {
+ int aer = 0;
/* Lock MCP using an unload request */
fw = bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS, 0);
if (!fw) {
@@ -9994,7 +10077,18 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
break;
}
- if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON) {
+ rc = down_interruptible(&bnx2x_prev_sem);
+ if (rc) {
+ BNX2X_ERR("Cannot check for AER; Received %d when tried to take lock\n",
+ rc);
+ } else {
+ /* If Path is marked by EEH, ignore unload status */
+ aer = !!(bnx2x_prev_path_get_entry(bp) &&
+ bnx2x_prev_path_get_entry(bp)->aer);
+ up(&bnx2x_prev_sem);
+ }
+
+ if (fw == FW_MSG_CODE_DRV_UNLOAD_COMMON || aer) {
rc = bnx2x_prev_unload_common(bp);
break;
}
@@ -10034,8 +10128,12 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp)
id = ((val & 0xffff) << 16);
val = REG_RD(bp, MISC_REG_CHIP_REV);
id |= ((val & 0xf) << 12);
- val = REG_RD(bp, MISC_REG_CHIP_METAL);
- id |= ((val & 0xff) << 4);
+
+ /* Metal is read from PCI regs, but we can't access >=0x400 from
+ * the configuration space (so we need to reg_rd)
+ */
+ val = REG_RD(bp, PCICFG_OFFSET + PCI_ID_VAL3);
+ id |= (((val >> 24) & 0xf) << 4);
val = REG_RD(bp, MISC_REG_BOND_ID);
id |= (val & 0xf);
bp->common.chip_id = id;
@@ -10571,10 +10669,12 @@ static void bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.speed_cap_mask[0] =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].speed_capability_mask);
+ dev_info.port_hw_config[port].speed_capability_mask) &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_MASK;
bp->link_params.speed_cap_mask[1] =
SHMEM_RD(bp,
- dev_info.port_hw_config[port].speed_capability_mask2);
+ dev_info.port_hw_config[port].speed_capability_mask2) &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_MASK;
bp->port.link_config[0] =
SHMEM_RD(bp, dev_info.port_feature_config[port].link_config);
@@ -10699,6 +10799,12 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
(max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >>
BNX2X_MAX_FCOE_INIT_CONN_SHIFT;
+ /* Calculate the number of maximum allowed FCoE tasks */
+ bp->cnic_eth_dev.max_fcoe_exchanges = MAX_NUM_FCOE_TASKS_PER_ENGINE;
+ if (IS_MF(bp) || CHIP_MODE_IS_4_PORT(bp))
+ bp->cnic_eth_dev.max_fcoe_exchanges /=
+ MAX_FCOE_FUNCS_PER_ENGINE;
+
/* Read the WWN: */
if (!IS_MF(bp)) {
/* Port info */
@@ -10812,14 +10918,12 @@ static void bnx2x_get_cnic_mac_hwinfo(struct bnx2x *bp)
}
}
- if (IS_MF_STORAGE_SD(bp))
- /* Zero primary MAC configuration */
- memset(bp->dev->dev_addr, 0, ETH_ALEN);
-
- if (IS_MF_FCOE_AFEX(bp) || IS_MF_FCOE_SD(bp))
- /* use FIP MAC as primary MAC */
+ /* If this is a storage-only interface, use SAN mac as
+ * primary MAC. Notice that for SD this is already the case,
+ * as the SAN mac was copied from the primary MAC.
+ */
+ if (IS_MF_FCOE_AFEX(bp))
memcpy(bp->dev->dev_addr, fip_mac, ETH_ALEN);
-
} else {
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].
iscsi_mac_upper);
@@ -11056,6 +11160,9 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
} else
BNX2X_DEV_INFO("illegal OV for SD\n");
break;
+ case SHARED_FEAT_CFG_FORCE_SF_MODE_FORCED_SF:
+ bp->mf_config[vn] = 0;
+ break;
default:
/* Unknown configuration: reset mf_config */
bp->mf_config[vn] = 0;
@@ -11402,26 +11509,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
* net_device service functions
*/
-static int bnx2x_open_epilog(struct bnx2x *bp)
-{
- /* Enable sriov via delayed work. This must be done via delayed work
- * because it causes the probe of the vf devices to be run, which invoke
- * register_netdevice which must have rtnl lock taken. As we are holding
- * the lock right now, that could only work if the probe would not take
- * the lock. However, as the probe of the vf may be called from other
- * contexts as well (such as passthrough to vm failes) it can't assume
- * the lock is being held for it. Using delayed work here allows the
- * probe code to simply take the lock (i.e. wait for it to be released
- * if it is being held).
- */
- smp_mb__before_clear_bit();
- set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
- smp_mb__after_clear_bit();
- schedule_delayed_work(&bp->sp_rtnl_task, 0);
-
- return 0;
-}
-
/* called with rtnl_lock */
static int bnx2x_open(struct net_device *dev)
{
@@ -11791,6 +11878,8 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_setup_tc = bnx2x_setup_tc,
#ifdef CONFIG_BNX2X_SRIOV
.ndo_set_vf_mac = bnx2x_set_vf_mac,
+ .ndo_set_vf_vlan = bnx2x_set_vf_vlan,
+ .ndo_get_vf_config = bnx2x_get_vf_config,
#endif
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
@@ -11953,19 +12042,26 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
dev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &bnx2x_netdev_ops;
- bnx2x_set_ethtool_ops(dev);
+ bnx2x_set_ethtool_ops(bp, dev);
dev->priv_flags |= IFF_UNICAST_FLT;
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO |
- NETIF_F_RXHASH | NETIF_F_HW_VLAN_TX;
+ NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX;
+ if (!CHIP_IS_E1x(bp)) {
+ dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL;
+ dev->hw_enc_features =
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
+ NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL;
+ }
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA;
- dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX;
+ dev->features |= dev->hw_features | NETIF_F_HW_VLAN_CTAG_RX;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
@@ -12447,7 +12543,7 @@ static int bnx2x_init_one(struct pci_dev *pdev,
* l2 connections.
*/
if (IS_VF(bp)) {
- bnx2x_vf_map_doorbells(bp);
+ bp->doorbells = bnx2x_vf_doorbells(bp);
rc = bnx2x_vf_pci_alloc(bp);
if (rc)
goto init_one_exit;
@@ -12475,13 +12571,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
goto init_one_exit;
}
- /* Enable SRIOV if capability found in configuration space.
- * Once the generic SR-IOV framework makes it in from the
- * pci tree this will be revised, to allow dynamic control
- * over the number of VFs. Right now, change the num of vfs
- * param below to enable SR-IOV.
- */
- rc = bnx2x_iov_init_one(bp, int_mode, 0/*num vfs*/);
+ /* Enable SRIOV if capability found in configuration space */
+ rc = bnx2x_iov_init_one(bp, int_mode, BNX2X_MAX_NUM_OF_VFS);
if (rc)
goto init_one_exit;
@@ -12493,16 +12584,6 @@ static int bnx2x_init_one(struct pci_dev *pdev,
if (CHIP_IS_E1x(bp))
bp->flags |= NO_FCOE_FLAG;
- /* disable FCOE for 57840 device, until FW supports it */
- switch (ent->driver_data) {
- case BCM57840_O:
- case BCM57840_4_10:
- case BCM57840_2_20:
- case BCM57840_MFO:
- case BCM57840_MF:
- bp->flags |= NO_FCOE_FLAG;
- }
-
/* Set bp->num_queues for MSI-X mode*/
bnx2x_set_num_queues(bp);
@@ -12636,9 +12717,7 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
{
- int i;
-
- bp->state = BNX2X_STATE_ERROR;
+ bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
bp->rx_mode = BNX2X_RX_MODE_NONE;
@@ -12647,29 +12726,21 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
/* Stop Tx */
bnx2x_tx_disable(bp);
-
- bnx2x_netif_stop(bp, 0);
/* Delete all NAPI objects */
bnx2x_del_all_napi(bp);
if (CNIC_LOADED(bp))
bnx2x_del_all_napi_cnic(bp);
+ netdev_reset_tc(bp->dev);
del_timer_sync(&bp->timer);
+ cancel_delayed_work(&bp->sp_task);
+ cancel_delayed_work(&bp->period_task);
- bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
- /* Release IRQs */
- bnx2x_free_irq(bp);
-
- /* Free SKBs, SGEs, TPA pool and driver internals */
- bnx2x_free_skbs(bp);
-
- for_each_rx_queue(bp, i)
- bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-
- bnx2x_free_mem(bp);
+ spin_lock_bh(&bp->stats_lock);
+ bp->stats_state = STATS_STATE_DISABLED;
+ spin_unlock_bh(&bp->stats_lock);
- bp->state = BNX2X_STATE_CLOSED;
+ bnx2x_save_statistics(bp);
netif_carrier_off(bp->dev);
@@ -12705,6 +12776,8 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
rtnl_lock();
+ BNX2X_ERR("IO error detected\n");
+
netif_device_detach(dev);
if (state == pci_channel_io_perm_failure) {
@@ -12715,6 +12788,8 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
if (netif_running(dev))
bnx2x_eeh_nic_unload(bp);
+ bnx2x_prev_path_mark_eeh(bp);
+
pci_disable_device(pdev);
rtnl_unlock();
@@ -12733,9 +12808,10 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnx2x *bp = netdev_priv(dev);
+ int i;
rtnl_lock();
-
+ BNX2X_ERR("IO slot reset initializing...\n");
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev,
"Cannot re-enable PCI device after reset\n");
@@ -12745,10 +12821,47 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
+ pci_save_state(pdev);
if (netif_running(dev))
bnx2x_set_power_state(bp, PCI_D0);
+ if (netif_running(dev)) {
+ BNX2X_ERR("IO slot reset --> driver unload\n");
+ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
+ u32 v;
+
+ v = SHMEM2_RD(bp,
+ drv_capabilities_flag[BP_FW_MB_IDX(bp)]);
+ SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)],
+ v & ~DRV_FLAGS_CAPABILITIES_LOADED_L2);
+ }
+ bnx2x_drain_tx_queues(bp);
+ bnx2x_send_unload_req(bp, UNLOAD_RECOVERY);
+ bnx2x_netif_stop(bp, 1);
+ bnx2x_free_irq(bp);
+
+ /* Report UNLOAD_DONE to MCP */
+ bnx2x_send_unload_done(bp, true);
+
+ bp->sp_state = 0;
+ bp->port.pmf = 0;
+
+ bnx2x_prev_unload(bp);
+
+ /* We should have resetted the engine, so It's fair to
+ * assume the FW will no longer write to the bnx2x driver.
+ */
+ bnx2x_squeeze_objects(bp);
+ bnx2x_free_skbs(bp);
+ for_each_rx_queue(bp, i)
+ bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+ bnx2x_free_fp_mem(bp);
+ bnx2x_free_mem(bp);
+
+ bp->state = BNX2X_STATE_CLOSED;
+ }
+
rtnl_unlock();
return PCI_ERS_RESULT_RECOVERED;
@@ -12775,6 +12888,9 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
bnx2x_eeh_recover(bp);
+ bp->fw_seq = SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
+ DRV_MSG_SEQ_NUMBER_MASK;
+
if (netif_running(dev))
bnx2x_nic_load(bp, LOAD_NORMAL);
@@ -12797,6 +12913,9 @@ static struct pci_driver bnx2x_pci_driver = {
.suspend = bnx2x_suspend,
.resume = bnx2x_resume,
.err_handler = &bnx2x_err_handler,
+#ifdef CONFIG_BNX2X_SRIOV
+ .sriov_configure = bnx2x_sriov_configure,
+#endif
};
static int __init bnx2x_init(void)
@@ -13354,6 +13473,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev)
RCU_INIT_POINTER(bp->cnic_ops, NULL);
mutex_unlock(&bp->cnic_mutex);
synchronize_rcu();
+ bp->cnic_enabled = false;
kfree(bp->cnic_kwq);
bp->cnic_kwq = NULL;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index 791eb2d53011..d22bc40091ec 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -1491,10 +1491,6 @@
/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1
Port. */
#define MISC_REG_BOND_ID 0xa400
-/* [R 8] These bits indicate the metal revision of the chip. This value
- starts at 0x00 for each all-layer tape-out and increments by one for each
- tape-out. */
-#define MISC_REG_CHIP_METAL 0xa404
/* [R 16] These bits indicate the part number for the chip. */
#define MISC_REG_CHIP_NUM 0xa408
/* [R 4] These bits indicate the base revision of the chip. This value
@@ -6331,6 +6327,8 @@
#define PCI_PM_DATA_B 0x414
#define PCI_ID_VAL1 0x434
#define PCI_ID_VAL2 0x438
+#define PCI_ID_VAL3 0x43c
+
#define GRC_CONFIG_REG_PF_INIT_VF 0x624
#define GRC_CR_PF_INIT_VF_PF_FIRST_VF_NUM_MASK 0xf
/* First VF_NUM for PF is encoded in this register.
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 7306416bc90d..32a9609cc98b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -30,8 +30,6 @@
#define BNX2X_MAX_EMUL_MULTI 16
-#define MAC_LEADING_ZERO_CNT (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
-
/**** Exe Queue interfaces ****/
/**
@@ -444,30 +442,21 @@ static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
}
static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
- int n, u8 *buf)
+ int n, u8 *base, u8 stride, u8 size)
{
struct bnx2x_vlan_mac_registry_elem *pos;
- u8 *next = buf;
+ u8 *next = base;
int counter = 0;
/* traverse list */
list_for_each_entry(pos, &o->head, link) {
if (counter < n) {
- /* place leading zeroes in buffer */
- memset(next, 0, MAC_LEADING_ZERO_CNT);
-
- /* place mac after leading zeroes*/
- memcpy(next + MAC_LEADING_ZERO_CNT, pos->u.mac.mac,
- ETH_ALEN);
-
- /* calculate address of next element and
- * advance counter
- */
+ memcpy(next, &pos->u, size);
counter++;
- next = buf + counter * ALIGN(ETH_ALEN, sizeof(u32));
+ DP(BNX2X_MSG_SP, "copied element number %d to address %p element was:\n",
+ counter, next);
+ next += stride + size;
- DP(BNX2X_MSG_SP, "copied element number %d to address %p element was %pM\n",
- counter, next, pos->u.mac.mac);
}
}
return counter * ETH_ALEN;
@@ -487,7 +476,8 @@ static int bnx2x_check_mac_add(struct bnx2x *bp,
/* Check if a requested MAC already exists */
list_for_each_entry(pos, &o->head, link)
- if (!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN))
+ if (!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN) &&
+ (data->mac.is_inner_mac == pos->u.mac.is_inner_mac))
return -EEXIST;
return 0;
@@ -520,7 +510,9 @@ static int bnx2x_check_vlan_mac_add(struct bnx2x *bp,
list_for_each_entry(pos, &o->head, link)
if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
(!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
- ETH_ALEN)))
+ ETH_ALEN)) &&
+ (data->vlan_mac.is_inner_mac ==
+ pos->u.vlan_mac.is_inner_mac))
return -EEXIST;
return 0;
@@ -538,7 +530,8 @@ static struct bnx2x_vlan_mac_registry_elem *
DP(BNX2X_MSG_SP, "Checking MAC %pM for DEL command\n", data->mac.mac);
list_for_each_entry(pos, &o->head, link)
- if (!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN))
+ if ((!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN)) &&
+ (data->mac.is_inner_mac == pos->u.mac.is_inner_mac))
return pos;
return NULL;
@@ -573,7 +566,9 @@ static struct bnx2x_vlan_mac_registry_elem *
list_for_each_entry(pos, &o->head, link)
if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
(!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac,
- ETH_ALEN)))
+ ETH_ALEN)) &&
+ (data->vlan_mac.is_inner_mac ==
+ pos->u.vlan_mac.is_inner_mac))
return pos;
return NULL;
@@ -770,6 +765,8 @@ static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb,
&rule_entry->mac.mac_mid,
&rule_entry->mac.mac_lsb, mac);
+ rule_entry->mac.inner_mac =
+ cpu_to_le16(elem->cmd_data.vlan_mac.u.mac.is_inner_mac);
/* MOVE: Add a rule that will add this MAC to the target Queue */
if (cmd == BNX2X_VLAN_MAC_MOVE) {
@@ -786,6 +783,9 @@ static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb,
&rule_entry->mac.mac_mid,
&rule_entry->mac.mac_lsb, mac);
+ rule_entry->mac.inner_mac =
+ cpu_to_le16(elem->cmd_data.vlan_mac.
+ u.mac.is_inner_mac);
}
/* Set the ramrod data header */
@@ -974,7 +974,8 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
&rule_entry->pair.mac_mid,
&rule_entry->pair.mac_lsb, mac);
-
+ rule_entry->pair.inner_mac =
+ cpu_to_le16(elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac);
/* MOVE: Add a rule that will add this MAC to the target Queue */
if (cmd == BNX2X_VLAN_MAC_MOVE) {
rule_entry++;
@@ -991,6 +992,9 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
&rule_entry->pair.mac_mid,
&rule_entry->pair.mac_lsb, mac);
+ rule_entry->pair.inner_mac =
+ cpu_to_le16(elem->cmd_data.vlan_mac.u.
+ vlan_mac.is_inner_mac);
}
/* Set the ramrod data header */
@@ -1854,6 +1858,7 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
return rc;
}
list_del(&exeq_pos->link);
+ bnx2x_exe_queue_free_elem(bp, exeq_pos);
}
}
@@ -2012,6 +2017,7 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp,
vlan_obj->check_move = bnx2x_check_move;
vlan_obj->ramrod_cmd =
RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;
+ vlan_obj->get_n_elements = bnx2x_get_n_elements;
/* Exe Queue */
bnx2x_exe_queue_init(bp,
@@ -4426,6 +4432,12 @@ static void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o,
tx_data->force_default_pri_flg =
test_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, flags);
+ tx_data->tunnel_lso_inc_ip_id =
+ test_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, flags);
+ tx_data->tunnel_non_lso_pcsum_location =
+ test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? PCSUM_ON_PKT :
+ PCSUM_ON_BD;
+
tx_data->tx_status_block_id = params->fw_sb_id;
tx_data->tx_sb_index_number = params->sb_cq_index;
tx_data->tss_leading_client_id = params->tss_leading_cl_id;
@@ -5669,17 +5681,18 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
memset(rdata, 0, sizeof(*rdata));
/* Fill the ramrod data with provided parameters */
- rdata->function_mode = (u8)start_params->mf_mode;
- rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
- rdata->path_id = BP_PATH(bp);
- rdata->network_cos_mode = start_params->network_cos_mode;
-
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ rdata->function_mode = (u8)start_params->mf_mode;
+ rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag);
+ rdata->path_id = BP_PATH(bp);
+ rdata->network_cos_mode = start_params->network_cos_mode;
+ rdata->gre_tunnel_mode = start_params->gre_tunnel_mode;
+ rdata->gre_tunnel_rss = start_params->gre_tunnel_rss;
+
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_START, 0,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index ff907609b9fc..43c00bc84a08 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -100,6 +100,7 @@ struct bnx2x_raw_obj {
/************************* VLAN-MAC commands related parameters ***************/
struct bnx2x_mac_ramrod_data {
u8 mac[ETH_ALEN];
+ u8 is_inner_mac;
};
struct bnx2x_vlan_ramrod_data {
@@ -108,6 +109,7 @@ struct bnx2x_vlan_ramrod_data {
struct bnx2x_vlan_mac_ramrod_data {
u8 mac[ETH_ALEN];
+ u8 is_inner_mac;
u16 vlan;
};
@@ -313,8 +315,9 @@ struct bnx2x_vlan_mac_obj {
*
* @return number of copied bytes
*/
- int (*get_n_elements)(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
- int n, u8 *buf);
+ int (*get_n_elements)(struct bnx2x *bp,
+ struct bnx2x_vlan_mac_obj *o, int n, u8 *base,
+ u8 stride, u8 size);
/**
* Checks if ADD-ramrod with the given params may be performed.
@@ -824,7 +827,9 @@ enum {
BNX2X_Q_FLG_TX_SEC,
BNX2X_Q_FLG_ANTI_SPOOF,
BNX2X_Q_FLG_SILENT_VLAN_REM,
- BNX2X_Q_FLG_FORCE_DEFAULT_PRI
+ BNX2X_Q_FLG_FORCE_DEFAULT_PRI,
+ BNX2X_Q_FLG_PCSUM_ON_PKT,
+ BNX2X_Q_FLG_TUN_INC_INNER_IP_ID
};
/* Queue type options: queue type may be a compination of below. */
@@ -842,6 +847,7 @@ enum bnx2x_q_type {
#define BNX2X_MULTI_TX_COS_E3B0 3
#define BNX2X_MULTI_TX_COS 3 /* Maximum possible */
+#define MAC_PAD (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
struct bnx2x_queue_init_params {
struct {
@@ -1118,6 +1124,15 @@ struct bnx2x_func_start_params {
/* Function cos mode */
u8 network_cos_mode;
+
+ /* NVGRE classification enablement */
+ u8 nvgre_clss_en;
+
+ /* NO_GRE_TUNNEL/NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */
+ u8 gre_tunnel_mode;
+
+ /* GRE_OUTER_HEADERS_RSS/GRE_INNER_HEADERS_RSS/NVGRE_KEY_ENTROPY_RSS */
+ u8 gre_tunnel_rss;
};
struct bnx2x_func_switch_update_params {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 6adfa2093581..2ce7c7471367 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -20,7 +20,9 @@
#include "bnx2x.h"
#include "bnx2x_init.h"
#include "bnx2x_cmn.h"
+#include "bnx2x_sp.h"
#include <linux/crc32.h>
+#include <linux/if_vlan.h>
/* General service functions */
static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
@@ -555,8 +557,7 @@ static int bnx2x_vfop_config_list(struct bnx2x *bp,
rc = bnx2x_config_vlan_mac(bp, vlan_mac);
if (rc >= 0) {
cnt += pos->add ? 1 : -1;
- list_del(&pos->link);
- list_add(&pos->link, &rollback_list);
+ list_move(&pos->link, &rollback_list);
rc = 0;
} else if (rc == -EEXIST) {
rc = 0;
@@ -958,6 +959,12 @@ op_err:
BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
op_done:
case BNX2X_VFOP_QSETUP_DONE:
+ vf->cfg_flags |= VF_CFG_VLAN;
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+ &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
bnx2x_vfop_end(bp, vf, vfop);
return;
default:
@@ -1459,7 +1466,6 @@ static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid)
return bnx2x_is_pcie_pending(dev);
unknown_dev:
- BNX2X_ERR("Unknown device\n");
return false;
}
@@ -1926,20 +1932,22 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
/* SRIOV can be enabled only with MSIX */
if (int_mode_param == BNX2X_INT_MODE_MSI ||
- int_mode_param == BNX2X_INT_MODE_INTX)
+ int_mode_param == BNX2X_INT_MODE_INTX) {
BNX2X_ERR("Forced MSI/INTx mode is incompatible with SRIOV\n");
+ return 0;
+ }
err = -EIO;
/* verify ari is enabled */
if (!bnx2x_ari_enabled(bp->pdev)) {
- BNX2X_ERR("ARI not supported, SRIOV can not be enabled\n");
- return err;
+ BNX2X_ERR("ARI not supported (check pci bridge ARI forwarding), SRIOV can not be enabled\n");
+ return 0;
}
/* verify igu is in normal mode */
if (CHIP_INT_MODE_IS_BC(bp)) {
BNX2X_ERR("IGU not normal mode, SRIOV can not be enabled\n");
- return err;
+ return 0;
}
/* allocate the vfs database */
@@ -1964,8 +1972,10 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
if (iov->total == 0)
goto failed;
- /* calculate the actual number of VFs */
- iov->nr_virtfn = min_t(u16, iov->total, (u16)num_vfs_param);
+ iov->nr_virtfn = min_t(u16, iov->total, num_vfs_param);
+
+ DP(BNX2X_MSG_IOV, "num_vfs_param was %d, nr_virtfn was %d\n",
+ num_vfs_param, iov->nr_virtfn);
/* allocate the vf array */
bp->vfdb->vfs = kzalloc(sizeof(struct bnx2x_virtf) *
@@ -2378,8 +2388,8 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
goto get_vf;
case EVENT_RING_OPCODE_MALICIOUS_VF:
abs_vfid = elem->message.data.malicious_vf_event.vf_id;
- DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d\n",
- abs_vfid);
+ DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d err_id=0x%x\n",
+ abs_vfid, elem->message.data.malicious_vf_event.err_id);
goto get_vf;
default:
return 1;
@@ -2436,8 +2446,8 @@ get_vf:
/* Do nothing for now */
break;
case EVENT_RING_OPCODE_MALICIOUS_VF:
- DP(BNX2X_MSG_IOV, "got VF [%d] MALICIOUS notification\n",
- vf->abs_vfid);
+ DP(BNX2X_MSG_IOV, "Got VF MALICIOUS notification abs_vfid=%d error id %x\n",
+ abs_vfid, elem->message.data.malicious_vf_event.err_id);
/* Do nothing for now */
break;
}
@@ -3012,21 +3022,138 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
vf->op_current = CHANNEL_TLV_NONE;
}
-void bnx2x_enable_sriov(struct bnx2x *bp)
+int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
{
- int rc = 0;
- /* disbale sriov in case it is still enabled */
+ struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev));
+
+ DP(BNX2X_MSG_IOV, "bnx2x_sriov_configure called with %d, BNX2X_NR_VIRTFN(bp) was %d\n",
+ num_vfs_param, BNX2X_NR_VIRTFN(bp));
+
+ /* HW channel is only operational when PF is up */
+ if (bp->state != BNX2X_STATE_OPEN) {
+ BNX2X_ERR("VF num configurtion via sysfs not supported while PF is down");
+ return -EINVAL;
+ }
+
+ /* we are always bound by the total_vfs in the configuration space */
+ if (num_vfs_param > BNX2X_NR_VIRTFN(bp)) {
+ BNX2X_ERR("truncating requested number of VFs (%d) down to maximum allowed (%d)\n",
+ num_vfs_param, BNX2X_NR_VIRTFN(bp));
+ num_vfs_param = BNX2X_NR_VIRTFN(bp);
+ }
+
+ bp->requested_nr_virtfn = num_vfs_param;
+ if (num_vfs_param == 0) {
+ pci_disable_sriov(dev);
+ return 0;
+ } else {
+ return bnx2x_enable_sriov(bp);
+ }
+}
+
+int bnx2x_enable_sriov(struct bnx2x *bp)
+{
+ int rc = 0, req_vfs = bp->requested_nr_virtfn;
+
+ rc = pci_enable_sriov(bp->pdev, req_vfs);
+ if (rc) {
+ BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
+ return rc;
+ }
+ DP(BNX2X_MSG_IOV, "sriov enabled (%d vfs)\n", req_vfs);
+ return req_vfs;
+}
+
+void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
+{
+ int vfidx;
+ struct pf_vf_bulletin_content *bulletin;
+
+ DP(BNX2X_MSG_IOV, "configuring vlan for VFs from sp-task\n");
+ for_each_vf(bp, vfidx) {
+ bulletin = BP_VF_BULLETIN(bp, vfidx);
+ if (BP_VF(bp, vfidx)->cfg_flags & VF_CFG_VLAN)
+ bnx2x_set_vf_vlan(bp->dev, vfidx, bulletin->vlan, 0);
+ }
+}
+
+void bnx2x_disable_sriov(struct bnx2x *bp)
+{
pci_disable_sriov(bp->pdev);
- DP(BNX2X_MSG_IOV, "sriov disabled\n");
+}
+
+static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx,
+ struct bnx2x_virtf *vf)
+{
+ if (!IS_SRIOV(bp)) {
+ BNX2X_ERR("vf ndo called though sriov is disabled\n");
+ return -EINVAL;
+ }
+
+ if (vfidx >= BNX2X_NR_VIRTFN(bp)) {
+ BNX2X_ERR("vf ndo called for uninitialized VF. vfidx was %d BNX2X_NR_VIRTFN was %d\n",
+ vfidx, BNX2X_NR_VIRTFN(bp));
+ return -EINVAL;
+ }
+
+ if (!vf) {
+ BNX2X_ERR("vf ndo called but vf was null. vfidx was %d\n",
+ vfidx);
+ return -EINVAL;
+ }
- /* enable sriov */
- DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
- rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
+ return 0;
+}
+
+int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
+ struct ifla_vf_info *ivi)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+ struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+ struct bnx2x_vlan_mac_obj *vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj);
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+ int rc;
+
+ /* sanity */
+ rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
if (rc)
- BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
- else
- DP(BNX2X_MSG_IOV, "sriov enabled\n");
+ return rc;
+ if (!mac_obj || !vlan_obj || !bulletin) {
+ BNX2X_ERR("VF partially initialized\n");
+ return -EINVAL;
+ }
+
+ ivi->vf = vfidx;
+ ivi->qos = 0;
+ ivi->tx_rate = 10000; /* always 10G. TBA take from link struct */
+ ivi->spoofchk = 1; /*always enabled */
+ if (vf->state == VF_ENABLED) {
+ /* mac and vlan are in vlan_mac objects */
+ mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac,
+ 0, ETH_ALEN);
+ vlan_obj->get_n_elements(bp, vlan_obj, 1, (u8 *)&ivi->vlan,
+ 0, VLAN_HLEN);
+ } else {
+ /* mac */
+ if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
+ /* mac configured by ndo so its in bulletin board */
+ memcpy(&ivi->mac, bulletin->mac, ETH_ALEN);
+ else
+ /* funtion has not been loaded yet. Show mac as 0s */
+ memset(&ivi->mac, 0, ETH_ALEN);
+
+ /* vlan */
+ if (bulletin->valid_bitmap & (1 << VLAN_VALID))
+ /* vlan configured by ndo so its in bulletin board */
+ memcpy(&ivi->vlan, &bulletin->vlan, VLAN_HLEN);
+ else
+ /* funtion has not been loaded yet. Show vlans as 0s */
+ memset(&ivi->vlan, 0, VLAN_HLEN);
+ }
+
+ return 0;
}
/* New mac for VF. Consider these cases:
@@ -3044,23 +3171,19 @@ void bnx2x_enable_sriov(struct bnx2x *bp)
* VF to configure any mac for itself except for this mac. In case of a race
* where the VF fails to see the new post on its bulletin board before sending a
* mac configuration request, the PF will simply fail the request and VF can try
- * again after consulting its bulletin board
+ * again after consulting its bulletin board.
*/
-int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
{
struct bnx2x *bp = netdev_priv(dev);
- int rc, q_logical_state, vfidx = queue;
+ int rc, q_logical_state;
struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
- /* if SRIOV is disabled there is nothing to do (and somewhere, someone
- * has erred).
- */
- if (!IS_SRIOV(bp)) {
- BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
- return -EINVAL;
- }
-
+ /* sanity */
+ rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+ if (rc)
+ return rc;
if (!is_valid_ether_addr(mac)) {
BNX2X_ERR("mac address invalid\n");
return -EINVAL;
@@ -3085,7 +3208,7 @@ int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
if (vf->state == VF_ENABLED &&
q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
/* configure the mac in device on this vf's queue */
- unsigned long flags = 0;
+ unsigned long ramrod_flags = 0;
struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
/* must lock vfpf channel to protect against vf flows */
@@ -3106,14 +3229,133 @@ int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
}
/* configure the new mac to device */
- __set_bit(RAMROD_COMP_WAIT, &flags);
+ __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
- BNX2X_ETH_MAC, &flags);
+ BNX2X_ETH_MAC, &ramrod_flags);
bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
}
- return rc;
+ return 0;
+}
+
+int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc, q_logical_state;
+ struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+ /* sanity */
+ rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf);
+ if (rc)
+ return rc;
+
+ if (vlan > 4095) {
+ BNX2X_ERR("illegal vlan value %d\n", vlan);
+ return -EINVAL;
+ }
+
+ DP(BNX2X_MSG_IOV, "configuring VF %d with VLAN %d qos %d\n",
+ vfidx, vlan, 0);
+
+ /* update PF's copy of the VF's bulletin. No point in posting the vlan
+ * to the VF since it doesn't have anything to do with it. But it useful
+ * to store it here in case the VF is not up yet and we can only
+ * configure the vlan later when it does.
+ */
+ bulletin->valid_bitmap |= 1 << VLAN_VALID;
+ bulletin->vlan = vlan;
+
+ /* is vf initialized and queue set up? */
+ q_logical_state =
+ bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+ if (vf->state == VF_ENABLED &&
+ q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+ /* configure the vlan in device on this vf's queue */
+ unsigned long ramrod_flags = 0;
+ unsigned long vlan_mac_flags = 0;
+ struct bnx2x_vlan_mac_obj *vlan_obj =
+ &bnx2x_vfq(vf, 0, vlan_obj);
+ struct bnx2x_vlan_mac_ramrod_params ramrod_param;
+ struct bnx2x_queue_state_params q_params = {NULL};
+ struct bnx2x_queue_update_params *update_params;
+
+ memset(&ramrod_param, 0, sizeof(ramrod_param));
+
+ /* must lock vfpf channel to protect against vf flows */
+ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
+
+ /* remove existing vlans */
+ __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+ rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags,
+ &ramrod_flags);
+ if (rc) {
+ BNX2X_ERR("failed to delete vlans\n");
+ return -EINVAL;
+ }
+
+ /* send queue update ramrod to configure default vlan and silent
+ * vlan removal
+ */
+ __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+ q_params.cmd = BNX2X_Q_CMD_UPDATE;
+ q_params.q_obj = &bnx2x_vfq(vf, 0, sp_obj);
+ update_params = &q_params.params.update;
+ __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG,
+ &update_params->update_flags);
+ __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
+ &update_params->update_flags);
+
+ if (vlan == 0) {
+ /* if vlan is 0 then we want to leave the VF traffic
+ * untagged, and leave the incoming traffic untouched
+ * (i.e. do not remove any vlan tags).
+ */
+ __clear_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
+ &update_params->update_flags);
+ __clear_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
+ &update_params->update_flags);
+ } else {
+ /* configure the new vlan to device */
+ __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+ ramrod_param.vlan_mac_obj = vlan_obj;
+ ramrod_param.ramrod_flags = ramrod_flags;
+ ramrod_param.user_req.u.vlan.vlan = vlan;
+ ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD;
+ rc = bnx2x_config_vlan_mac(bp, &ramrod_param);
+ if (rc) {
+ BNX2X_ERR("failed to configure vlan\n");
+ return -EINVAL;
+ }
+
+ /* configure default vlan to vf queue and set silent
+ * vlan removal (the vf remains unaware of this vlan).
+ */
+ update_params = &q_params.params.update;
+ __set_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN,
+ &update_params->update_flags);
+ __set_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM,
+ &update_params->update_flags);
+ update_params->def_vlan = vlan;
+ }
+
+ /* Update the Queue state */
+ rc = bnx2x_queue_state_change(bp, &q_params);
+ if (rc) {
+ BNX2X_ERR("Failed to configure default VLAN\n");
+ return rc;
+ }
+
+ /* clear the flag indicating that this VF needs its vlan
+ * (will only be set if the HV configured th Vlan before vf was
+ * and we were called because the VF came up later
+ */
+ vf->cfg_flags &= ~VF_CFG_VLAN;
+
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
+ }
+ return 0;
}
/* crc is the first field in the bulletin board. compute the crc over the
@@ -3165,20 +3407,26 @@ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
}
+ /* the vlan in bulletin board is valid and is new */
+ if (bulletin.valid_bitmap & 1 << VLAN_VALID)
+ memcpy(&bulletin.vlan, &bp->old_bulletin.vlan, VLAN_HLEN);
+
/* copy new bulletin board to bp */
bp->old_bulletin = bulletin;
return PFVF_BULLETIN_UPDATED;
}
-void bnx2x_vf_map_doorbells(struct bnx2x *bp)
+void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
{
/* vf doorbells are embedded within the regview */
- bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
+ return bp->regview + PXP_VF_ADDR_DB_START;
}
int bnx2x_vf_pci_alloc(struct bnx2x *bp)
{
+ mutex_init(&bp->vf2pf_mutex);
+
/* allocate vf2pf mailbox for vf to pf channel */
BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
sizeof(struct bnx2x_vf_mbx_msg));
@@ -3196,3 +3444,26 @@ alloc_mem_err:
sizeof(union pf_vf_bulletin));
return -ENOMEM;
}
+
+int bnx2x_open_epilog(struct bnx2x *bp)
+{
+ /* Enable sriov via delayed work. This must be done via delayed work
+ * because it causes the probe of the vf devices to be run, which invoke
+ * register_netdevice which must have rtnl lock taken. As we are holding
+ * the lock right now, that could only work if the probe would not take
+ * the lock. However, as the probe of the vf may be called from other
+ * contexts as well (such as passthrough to vm failes) it can't assume
+ * the lock is being held for it. Using delayed work here allows the
+ * probe code to simply take the lock (i.e. wait for it to be released
+ * if it is being held). We only want to do this if the number of VFs
+ * was set before PF driver was loaded.
+ */
+ if (IS_SRIOV(bp) && BNX2X_NR_VIRTFN(bp)) {
+ smp_mb__before_clear_bit();
+ set_bit(BNX2X_SP_RTNL_ENABLE_SRIOV, &bp->sp_rtnl_state);
+ smp_mb__after_clear_bit();
+ schedule_delayed_work(&bp->sp_rtnl_task, 0);
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index b4050173add9..d67ddc554c0f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -193,6 +193,7 @@ struct bnx2x_virtf {
#define VF_CFG_TPA 0x0004
#define VF_CFG_INT_SIMD 0x0008
#define VF_CACHE_LINE 0x0010
+#define VF_CFG_VLAN 0x0020
u8 state;
#define VF_FREE 0 /* VF ready to be acquired holds no resc */
@@ -712,6 +713,7 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
u16 length);
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length);
+void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv);
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
bool bnx2x_tlv_supported(u16 tlvtype);
@@ -731,7 +733,7 @@ int bnx2x_vfpf_init(struct bnx2x *bp);
void bnx2x_vfpf_close_vf(struct bnx2x *bp);
int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
-int bnx2x_vfpf_set_mac(struct bnx2x *bp);
+int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set);
int bnx2x_vfpf_set_mcast(struct net_device *dev);
int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
@@ -750,13 +752,17 @@ static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
}
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
-void bnx2x_vf_map_doorbells(struct bnx2x *bp);
+void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp);
int bnx2x_vf_pci_alloc(struct bnx2x *bp);
-void bnx2x_enable_sriov(struct bnx2x *bp);
+int bnx2x_enable_sriov(struct bnx2x *bp);
+void bnx2x_disable_sriov(struct bnx2x *bp);
static inline int bnx2x_vf_headroom(struct bnx2x *bp)
{
return bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
}
+void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp);
+int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs);
+int bnx2x_open_epilog(struct bnx2x *bp);
#else /* CONFIG_BNX2X_SRIOV */
@@ -779,7 +785,8 @@ static inline void bnx2x_iov_init_dmae(struct bnx2x *bp) {}
static inline int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
int num_vfs_param) {return 0; }
static inline void bnx2x_iov_remove_one(struct bnx2x *bp) {}
-static inline void bnx2x_enable_sriov(struct bnx2x *bp) {}
+static inline int bnx2x_enable_sriov(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_disable_sriov(struct bnx2x *bp) {}
static inline int bnx2x_vfpf_acquire(struct bnx2x *bp,
u8 tx_count, u8 rx_count) {return 0; }
static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
@@ -787,7 +794,8 @@ static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; }
static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
-static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr,
+ u8 vf_qid, bool set) {return 0; }
static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
@@ -802,8 +810,15 @@ static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp
return PFVF_BULLETIN_UNCHANGED;
}
-static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; }
+static inline void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
+{
+ return NULL;
+}
+
static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {}
+static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; }
+static inline int bnx2x_open_epilog(struct bnx2x *bp) {return 0; }
#endif /* CONFIG_BNX2X_SRIOV */
#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 4397f8b76f2e..2ca3d94fcec2 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -1547,11 +1547,51 @@ static void bnx2x_prep_fw_stats_req(struct bnx2x *bp)
}
}
+void bnx2x_memset_stats(struct bnx2x *bp)
+{
+ int i;
+
+ /* function stats */
+ for_each_queue(bp, i) {
+ struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[i];
+
+ memset(&fp_stats->old_tclient, 0,
+ sizeof(fp_stats->old_tclient));
+ memset(&fp_stats->old_uclient, 0,
+ sizeof(fp_stats->old_uclient));
+ memset(&fp_stats->old_xclient, 0,
+ sizeof(fp_stats->old_xclient));
+ if (bp->stats_init) {
+ memset(&fp_stats->eth_q_stats, 0,
+ sizeof(fp_stats->eth_q_stats));
+ memset(&fp_stats->eth_q_stats_old, 0,
+ sizeof(fp_stats->eth_q_stats_old));
+ }
+ }
+
+ memset(&bp->dev->stats, 0, sizeof(bp->dev->stats));
+
+ if (bp->stats_init) {
+ memset(&bp->net_stats_old, 0, sizeof(bp->net_stats_old));
+ memset(&bp->fw_stats_old, 0, sizeof(bp->fw_stats_old));
+ memset(&bp->eth_stats_old, 0, sizeof(bp->eth_stats_old));
+ memset(&bp->eth_stats, 0, sizeof(bp->eth_stats));
+ memset(&bp->func_stats, 0, sizeof(bp->func_stats));
+ }
+
+ bp->stats_state = STATS_STATE_DISABLED;
+
+ if (bp->port.pmf && bp->port.port_stx)
+ bnx2x_port_stats_base_init(bp);
+
+ /* mark the end of statistics initializiation */
+ bp->stats_init = false;
+}
+
void bnx2x_stats_init(struct bnx2x *bp)
{
int /*abs*/port = BP_PORT(bp);
int mb_idx = BP_FW_MB_IDX(bp);
- int i;
bp->stats_pending = 0;
bp->executer_idx = 0;
@@ -1587,36 +1627,11 @@ void bnx2x_stats_init(struct bnx2x *bp)
&(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2);
}
- /* function stats */
- for_each_queue(bp, i) {
- struct bnx2x_fp_stats *fp_stats = &bp->fp_stats[i];
-
- memset(&fp_stats->old_tclient, 0,
- sizeof(fp_stats->old_tclient));
- memset(&fp_stats->old_uclient, 0,
- sizeof(fp_stats->old_uclient));
- memset(&fp_stats->old_xclient, 0,
- sizeof(fp_stats->old_xclient));
- if (bp->stats_init) {
- memset(&fp_stats->eth_q_stats, 0,
- sizeof(fp_stats->eth_q_stats));
- memset(&fp_stats->eth_q_stats_old, 0,
- sizeof(fp_stats->eth_q_stats_old));
- }
- }
-
/* Prepare statistics ramrod data */
bnx2x_prep_fw_stats_req(bp);
- memset(&bp->dev->stats, 0, sizeof(bp->dev->stats));
+ /* Clean SP from previous statistics */
if (bp->stats_init) {
- memset(&bp->net_stats_old, 0, sizeof(bp->net_stats_old));
- memset(&bp->fw_stats_old, 0, sizeof(bp->fw_stats_old));
- memset(&bp->eth_stats_old, 0, sizeof(bp->eth_stats_old));
- memset(&bp->eth_stats, 0, sizeof(bp->eth_stats));
- memset(&bp->func_stats, 0, sizeof(bp->func_stats));
-
- /* Clean SP from previous statistics */
if (bp->func_stx) {
memset(bnx2x_sp(bp, func_stats), 0,
sizeof(struct host_func_stats));
@@ -1626,13 +1641,7 @@ void bnx2x_stats_init(struct bnx2x *bp)
}
}
- bp->stats_state = STATS_STATE_DISABLED;
-
- if (bp->port.pmf && bp->port.port_stx)
- bnx2x_port_stats_base_init(bp);
-
- /* mark the end of statistics initializiation */
- bp->stats_init = false;
+ bnx2x_memset_stats(bp);
}
void bnx2x_save_statistics(struct bnx2x *bp)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index 198f6f1c9ad5..d117f472816c 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -540,8 +540,8 @@ struct bnx2x_fw_port_stats_old {
/* forward */
struct bnx2x;
+void bnx2x_memset_stats(struct bnx2x *bp);
void bnx2x_stats_init(struct bnx2x *bp);
-
void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
/**
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 531eebf40d60..928b074d7d80 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -36,6 +36,8 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
u16 type, u16 length)
{
+ mutex_lock(&bp->vf2pf_mutex);
+
DP(BNX2X_MSG_IOV, "preparing to send %d tlv over vf pf channel\n",
type);
@@ -49,6 +51,15 @@ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
first_tlv->resp_msg_offset = sizeof(bp->vf2pf_mbox->req);
}
+/* releases the mailbox */
+void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv)
+{
+ DP(BNX2X_MSG_IOV, "done sending [%d] tlv over vf pf channel\n",
+ first_tlv->tl.type);
+
+ mutex_unlock(&bp->vf2pf_mutex);
+}
+
/* list the types and lengths of the tlvs on the buffer */
void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
{
@@ -181,8 +192,10 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
- if (bnx2x_get_vf_id(bp, &vf_id))
- return -EAGAIN;
+ if (bnx2x_get_vf_id(bp, &vf_id)) {
+ rc = -EAGAIN;
+ goto out;
+ }
req->vfdev_info.vf_id = vf_id;
req->vfdev_info.vf_os = 0;
@@ -213,7 +226,7 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* PF timeout */
if (rc)
- return rc;
+ goto out;
/* copy acquire response from buffer to bp */
memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
@@ -253,7 +266,8 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
/* PF reports error */
BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
bp->acquire_resp.hdr.status);
- return -EAGAIN;
+ rc = -EAGAIN;
+ goto out;
}
}
@@ -279,20 +293,24 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
bp->acquire_resp.resc.current_mac_addr,
ETH_ALEN);
- return 0;
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
+ return rc;
}
int bnx2x_vfpf_release(struct bnx2x *bp)
{
struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- u32 rc = 0, vf_id;
+ u32 rc, vf_id;
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
- if (bnx2x_get_vf_id(bp, &vf_id))
- return -EAGAIN;
+ if (bnx2x_get_vf_id(bp, &vf_id)) {
+ rc = -EAGAIN;
+ goto out;
+ }
req->vf_id = vf_id;
@@ -308,7 +326,8 @@ int bnx2x_vfpf_release(struct bnx2x *bp)
if (rc)
/* PF timeout */
- return rc;
+ goto out;
+
if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
/* PF released us */
DP(BNX2X_MSG_SP, "vf released\n");
@@ -316,10 +335,13 @@ int bnx2x_vfpf_release(struct bnx2x *bp)
/* PF reports error */
BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
resp->hdr.status);
- return -EAGAIN;
+ rc = -EAGAIN;
+ goto out;
}
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
- return 0;
+ return rc;
}
/* Tell PF about SB addresses */
@@ -350,16 +372,20 @@ int bnx2x_vfpf_init(struct bnx2x *bp)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc)
- return rc;
+ goto out;
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
resp->hdr.status);
- return -EAGAIN;
+ rc = -EAGAIN;
+ goto out;
}
DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
- return 0;
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
+
+ return rc;
}
/* CLOSE VF - opposite to INIT_VF */
@@ -380,6 +406,9 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp)
for_each_queue(bp, i)
bnx2x_vfpf_teardown_queue(bp, i);
+ /* remove mac */
+ bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index, false);
+
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
@@ -401,6 +430,8 @@ void bnx2x_vfpf_close_vf(struct bnx2x *bp)
BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
resp->hdr.status);
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
+
free_irq:
/* Disable HW interrupts, NAPI */
bnx2x_netif_stop(bp, 0);
@@ -435,7 +466,6 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
/* calculate queue flags */
flags |= VFPF_QUEUE_FLG_STATS;
flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
- flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
flags |= VFPF_QUEUE_FLG_VLAN;
DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
@@ -486,8 +516,11 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
fp_idx, resp->hdr.status);
- return -EINVAL;
+ rc = -EINVAL;
}
+
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
+
return rc;
}
@@ -515,41 +548,46 @@ int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
if (rc) {
BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
rc);
- return rc;
+ goto out;
}
/* PF failed the transaction */
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
resp->hdr.status);
- return -EINVAL;
+ rc = -EINVAL;
}
- return 0;
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
+ return rc;
}
/* request pf to add a mac for the vf */
-int bnx2x_vfpf_set_mac(struct bnx2x *bp)
+int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set)
{
struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc;
+ struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+ int rc = 0;
/* clear mailbox and prep first tlv */
bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
sizeof(*req));
req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
- req->vf_qid = 0;
+ req->vf_qid = vf_qid;
req->n_mac_vlan_filters = 1;
- req->filters[0].flags =
- VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
+
+ req->filters[0].flags = VFPF_Q_FILTER_DEST_MAC_VALID;
+ if (set)
+ req->filters[0].flags |= VFPF_Q_FILTER_SET_MAC;
/* sample bulletin board for new mac */
bnx2x_sample_bulletin(bp);
/* copy mac from device to request */
- memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
+ memcpy(req->filters[0].mac, addr, ETH_ALEN);
/* add list termination tlv */
bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
@@ -562,7 +600,7 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc) {
BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
- return rc;
+ goto out;
}
/* failure may mean PF was configured with a new mac for us */
@@ -570,6 +608,9 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
DP(BNX2X_MSG_IOV,
"vfpf SET MAC failed. Check bulletin board for new posts\n");
+ /* copy mac from bulletin to device */
+ memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+
/* check if bulletin board was updated */
if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
/* copy mac from device to request */
@@ -587,8 +628,10 @@ int bnx2x_vfpf_set_mac(struct bnx2x *bp)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
- return -EINVAL;
+ rc = -EINVAL;
}
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0;
}
@@ -643,14 +686,16 @@ int bnx2x_vfpf_set_mcast(struct net_device *dev)
rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
if (rc) {
BNX2X_ERR("Sending a message failed: %d\n", rc);
- return rc;
+ goto out;
}
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
resp->hdr.status);
- return -EINVAL;
+ rc = -EINVAL;
}
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
return 0;
}
@@ -689,7 +734,8 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
break;
default:
BNX2X_ERR("BAD rx mode (%d)\n", mode);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
@@ -708,8 +754,10 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
- return -EINVAL;
+ rc = -EINVAL;
}
+out:
+ bnx2x_vfpf_finalize(bp, &req->first_tlv);
return rc;
}
@@ -1004,7 +1052,7 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
}
/* convert MBX queue-flags to standard SP queue-flags */
-static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
+static void bnx2x_vf_mbx_set_q_flags(struct bnx2x *bp, u32 mbx_q_flags,
unsigned long *sp_q_flags)
{
if (mbx_q_flags & VFPF_QUEUE_FLG_TPA)
@@ -1015,8 +1063,6 @@ static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
__set_bit(BNX2X_Q_FLG_TPA_GRO, sp_q_flags);
if (mbx_q_flags & VFPF_QUEUE_FLG_STATS)
__set_bit(BNX2X_Q_FLG_STATS, sp_q_flags);
- if (mbx_q_flags & VFPF_QUEUE_FLG_OV)
- __set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
if (mbx_q_flags & VFPF_QUEUE_FLG_VLAN)
__set_bit(BNX2X_Q_FLG_VLAN, sp_q_flags);
if (mbx_q_flags & VFPF_QUEUE_FLG_COS)
@@ -1025,6 +1071,10 @@ static void bnx2x_vf_mbx_set_q_flags(u32 mbx_q_flags,
__set_bit(BNX2X_Q_FLG_HC, sp_q_flags);
if (mbx_q_flags & VFPF_QUEUE_FLG_DHC)
__set_bit(BNX2X_Q_FLG_DHC, sp_q_flags);
+
+ /* outer vlan removal is set according to the PF's multi fuction mode */
+ if (IS_MF_SD(bp))
+ __set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
}
static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
@@ -1075,11 +1125,11 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
init_p->tx.hc_rate = setup_q->txq.hc_rate;
init_p->tx.sb_cq_index = setup_q->txq.sb_index;
- bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+ bnx2x_vf_mbx_set_q_flags(bp, setup_q->txq.flags,
&init_p->tx.flags);
/* tx setup - flags */
- bnx2x_vf_mbx_set_q_flags(setup_q->txq.flags,
+ bnx2x_vf_mbx_set_q_flags(bp, setup_q->txq.flags,
&setup_p->flags);
/* tx setup - general, nothing */
@@ -1107,11 +1157,11 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
/* rx init */
init_p->rx.hc_rate = setup_q->rxq.hc_rate;
init_p->rx.sb_cq_index = setup_q->rxq.sb_index;
- bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+ bnx2x_vf_mbx_set_q_flags(bp, setup_q->rxq.flags,
&init_p->rx.flags);
/* rx setup - flags */
- bnx2x_vf_mbx_set_q_flags(setup_q->rxq.flags,
+ bnx2x_vf_mbx_set_q_flags(bp, setup_q->rxq.flags,
&setup_p->flags);
/* rx setup - general */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
index bfc80baec00d..41708faab575 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -328,9 +328,15 @@ struct pf_vf_bulletin_content {
#define MAC_ADDR_VALID 0 /* alert the vf that a new mac address
* is available for it
*/
+#define VLAN_VALID 1 /* when set, the vf should not access
+ * the vfpf channel
+ */
u8 mac[ETH_ALEN];
- u8 padding[2];
+ u8 mac_padding[2];
+
+ u16 vlan;
+ u8 vlan_padding[6];
};
union pf_vf_bulletin {
@@ -353,6 +359,7 @@ enum channel_tlvs {
CHANNEL_TLV_LIST_END,
CHANNEL_TLV_FLR,
CHANNEL_TLV_PF_SET_MAC,
+ CHANNEL_TLV_PF_SET_VLAN,
CHANNEL_TLV_MAX
};
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 149a3a038491..40649a8bf390 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -5544,8 +5544,10 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI))
cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
- if (CNIC_SUPPORTS_FCOE(cp))
+ if (CNIC_SUPPORTS_FCOE(cp)) {
cdev->max_fcoe_conn = ethdev->max_fcoe_conn;
+ cdev->max_fcoe_exchanges = ethdev->max_fcoe_exchanges;
+ }
if (cdev->max_fcoe_conn > BNX2X_FCOE_NUM_CONNECTIONS)
cdev->max_fcoe_conn = BNX2X_FCOE_NUM_CONNECTIONS;
diff --git a/drivers/net/ethernet/broadcom/cnic_if.h b/drivers/net/ethernet/broadcom/cnic_if.h
index 0c9367a0f57d..ec9bb9ad4bb3 100644
--- a/drivers/net/ethernet/broadcom/cnic_if.h
+++ b/drivers/net/ethernet/broadcom/cnic_if.h
@@ -195,6 +195,7 @@ struct cnic_eth_dev {
u32 max_fcoe_conn;
u32 max_rdma_conn;
u32 fcoe_init_cid;
+ u32 max_fcoe_exchanges;
u32 fcoe_wwn_port_name_hi;
u32 fcoe_wwn_port_name_lo;
u32 fcoe_wwn_node_name_hi;
@@ -313,6 +314,8 @@ struct cnic_dev {
int max_fcoe_conn;
int max_rdma_conn;
+ int max_fcoe_exchanges;
+
union drv_info_to_mcp *stats_addr;
struct fcoe_capabilities *fcoe_cap;
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index e9b35da375cb..e80bfb60c3ef 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -831,11 +831,8 @@ static int sbdma_add_rcvbuffer(struct sbmac_softc *sc, struct sbmacdma *d,
sb_new = netdev_alloc_skb(dev, ENET_PACKET_SIZE +
SMP_CACHE_BYTES * 2 +
NET_IP_ALIGN);
- if (sb_new == NULL) {
- pr_info("%s: sk_buff allocation failed\n",
- d->sbdma_eth->sbm_dev->name);
+ if (sb_new == NULL)
return -ENOBUFS;
- }
sbdma_align_skb(sb_new, SMP_CACHE_BYTES, NET_IP_ALIGN);
}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 67d2663b3974..728d42ab2a76 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 130
+#define TG3_MIN_NUM 131
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "February 14, 2013"
+#define DRV_MODULE_RELDATE "April 09, 2013"
#define RESET_KIND_SHUTDOWN 0
#define RESET_KIND_INIT 1
@@ -212,6 +212,7 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define TG3_FW_UPDATE_FREQ_SEC (TG3_FW_UPDATE_TIMEOUT_SEC / 2)
#define FIRMWARE_TG3 "tigon/tg3.bin"
+#define FIRMWARE_TG357766 "tigon/tg357766.bin"
#define FIRMWARE_TG3TSO "tigon/tg3_tso.bin"
#define FIRMWARE_TG3TSO5 "tigon/tg3_tso5.bin"
@@ -1873,6 +1874,20 @@ static void tg3_link_report(struct tg3 *tp)
tp->link_up = netif_carrier_ok(tp->dev);
}
+static u32 tg3_decode_flowctrl_1000T(u32 adv)
+{
+ u32 flowctrl = 0;
+
+ if (adv & ADVERTISE_PAUSE_CAP) {
+ flowctrl |= FLOW_CTRL_RX;
+ if (!(adv & ADVERTISE_PAUSE_ASYM))
+ flowctrl |= FLOW_CTRL_TX;
+ } else if (adv & ADVERTISE_PAUSE_ASYM)
+ flowctrl |= FLOW_CTRL_TX;
+
+ return flowctrl;
+}
+
static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
{
u16 miireg;
@@ -1889,6 +1904,20 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
return miireg;
}
+static u32 tg3_decode_flowctrl_1000X(u32 adv)
+{
+ u32 flowctrl = 0;
+
+ if (adv & ADVERTISE_1000XPAUSE) {
+ flowctrl |= FLOW_CTRL_RX;
+ if (!(adv & ADVERTISE_1000XPSE_ASYM))
+ flowctrl |= FLOW_CTRL_TX;
+ } else if (adv & ADVERTISE_1000XPSE_ASYM)
+ flowctrl |= FLOW_CTRL_TX;
+
+ return flowctrl;
+}
+
static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
@@ -2199,7 +2228,7 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
tg3_writephy(tp, MII_TG3_MISC_SHDW, reg);
}
-static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
+static void tg3_phy_toggle_automdix(struct tg3 *tp, bool enable)
{
u32 phy;
@@ -2291,7 +2320,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
tg3_phy_toggle_auxctl_smdsp(tp, false);
}
-static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
+static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
{
u32 val;
@@ -2301,7 +2330,7 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
tp->setlpicnt = 0;
if (tp->link_config.autoneg == AUTONEG_ENABLE &&
- current_link_up == 1 &&
+ current_link_up &&
tp->link_config.active_duplex == DUPLEX_FULL &&
(tp->link_config.active_speed == SPEED_100 ||
tp->link_config.active_speed == SPEED_1000)) {
@@ -2323,7 +2352,7 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
}
if (!tp->setlpicnt) {
- if (current_link_up == 1 &&
+ if (current_link_up &&
!tg3_phy_toggle_auxctl_smdsp(tp, true)) {
tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000);
tg3_phy_toggle_auxctl_smdsp(tp, false);
@@ -2530,6 +2559,13 @@ static void tg3_carrier_off(struct tg3 *tp)
tp->link_up = false;
}
+static void tg3_warn_mgmt_link_flap(struct tg3 *tp)
+{
+ if (tg3_flag(tp, ENABLE_ASF))
+ netdev_warn(tp->dev,
+ "Management side-band traffic will be interrupted during phy settings change\n");
+}
+
/* This will reset the tigon3 PHY if there is no valid
* link unless the FORCE argument is non-zero.
*/
@@ -2669,7 +2705,7 @@ out:
if (tg3_chip_rev_id(tp) == CHIPREV_ID_5762_A0)
tg3_phydsp_write(tp, 0xffb, 0x4000);
- tg3_phy_toggle_automdix(tp, 1);
+ tg3_phy_toggle_automdix(tp, true);
tg3_phy_set_wirespeed(tp);
return 0;
}
@@ -2925,6 +2961,9 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
{
u32 val;
+ if (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)
+ return;
+
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) {
if (tg3_asic_rev(tp) == ASIC_REV_5704) {
u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -3448,11 +3487,58 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
#define TX_CPU_SCRATCH_SIZE 0x04000
/* tp->lock is held. */
-static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
+static int tg3_pause_cpu(struct tg3 *tp, u32 cpu_base)
{
int i;
+ const int iters = 10000;
+
+ for (i = 0; i < iters; i++) {
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
+ if (tr32(cpu_base + CPU_MODE) & CPU_MODE_HALT)
+ break;
+ }
+
+ return (i == iters) ? -EBUSY : 0;
+}
+
+/* tp->lock is held. */
+static int tg3_rxcpu_pause(struct tg3 *tp)
+{
+ int rc = tg3_pause_cpu(tp, RX_CPU_BASE);
+
+ tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+ tw32_f(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT);
+ udelay(10);
+
+ return rc;
+}
+
+/* tp->lock is held. */
+static int tg3_txcpu_pause(struct tg3 *tp)
+{
+ return tg3_pause_cpu(tp, TX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static void tg3_resume_cpu(struct tg3 *tp, u32 cpu_base)
+{
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32_f(cpu_base + CPU_MODE, 0x00000000);
+}
- BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
+/* tp->lock is held. */
+static void tg3_rxcpu_resume(struct tg3 *tp)
+{
+ tg3_resume_cpu(tp, RX_CPU_BASE);
+}
+
+/* tp->lock is held. */
+static int tg3_halt_cpu(struct tg3 *tp, u32 cpu_base)
+{
+ int rc;
+
+ BUG_ON(cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
if (tg3_asic_rev(tp) == ASIC_REV_5906) {
u32 val = tr32(GRC_VCPU_EXT_CTRL);
@@ -3460,17 +3546,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
return 0;
}
- if (offset == RX_CPU_BASE) {
- for (i = 0; i < 10000; i++) {
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32(offset + CPU_MODE, CPU_MODE_HALT);
- if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
- break;
- }
-
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32_f(offset + CPU_MODE, CPU_MODE_HALT);
- udelay(10);
+ if (cpu_base == RX_CPU_BASE) {
+ rc = tg3_rxcpu_pause(tp);
} else {
/*
* There is only an Rx CPU for the 5750 derivative in the
@@ -3479,17 +3556,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
if (tg3_flag(tp, IS_SSB_CORE))
return 0;
- for (i = 0; i < 10000; i++) {
- tw32(offset + CPU_STATE, 0xffffffff);
- tw32(offset + CPU_MODE, CPU_MODE_HALT);
- if (tr32(offset + CPU_MODE) & CPU_MODE_HALT)
- break;
- }
+ rc = tg3_txcpu_pause(tp);
}
- if (i >= 10000) {
+ if (rc) {
netdev_err(tp->dev, "%s timed out, %s CPU\n",
- __func__, offset == RX_CPU_BASE ? "RX" : "TX");
+ __func__, cpu_base == RX_CPU_BASE ? "RX" : "TX");
return -ENODEV;
}
@@ -3499,19 +3571,41 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
return 0;
}
-struct fw_info {
- unsigned int fw_base;
- unsigned int fw_len;
- const __be32 *fw_data;
-};
+static int tg3_fw_data_len(struct tg3 *tp,
+ const struct tg3_firmware_hdr *fw_hdr)
+{
+ int fw_len;
+
+ /* Non fragmented firmware have one firmware header followed by a
+ * contiguous chunk of data to be written. The length field in that
+ * header is not the length of data to be written but the complete
+ * length of the bss. The data length is determined based on
+ * tp->fw->size minus headers.
+ *
+ * Fragmented firmware have a main header followed by multiple
+ * fragments. Each fragment is identical to non fragmented firmware
+ * with a firmware header followed by a contiguous chunk of data. In
+ * the main header, the length field is unused and set to 0xffffffff.
+ * In each fragment header the length is the entire size of that
+ * fragment i.e. fragment data + header length. Data length is
+ * therefore length field in the header minus TG3_FW_HDR_LEN.
+ */
+ if (tp->fw_len == 0xffffffff)
+ fw_len = be32_to_cpu(fw_hdr->len);
+ else
+ fw_len = tp->fw->size;
+
+ return (fw_len - TG3_FW_HDR_LEN) / sizeof(u32);
+}
/* tp->lock is held. */
static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
u32 cpu_scratch_base, int cpu_scratch_size,
- struct fw_info *info)
+ const struct tg3_firmware_hdr *fw_hdr)
{
- int err, lock_err, i;
+ int err, i;
void (*write_op)(struct tg3 *, u32, u32);
+ int total_len = tp->fw->size;
if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
netdev_err(tp->dev,
@@ -3520,30 +3614,49 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base,
return -EINVAL;
}
- if (tg3_flag(tp, 5705_PLUS))
+ if (tg3_flag(tp, 5705_PLUS) && tg3_asic_rev(tp) != ASIC_REV_57766)
write_op = tg3_write_mem;
else
write_op = tg3_write_indirect_reg32;
- /* It is possible that bootcode is still loading at this point.
- * Get the nvram lock first before halting the cpu.
- */
- lock_err = tg3_nvram_lock(tp);
- err = tg3_halt_cpu(tp, cpu_base);
- if (!lock_err)
- tg3_nvram_unlock(tp);
- if (err)
- goto out;
+ if (tg3_asic_rev(tp) != ASIC_REV_57766) {
+ /* It is possible that bootcode is still loading at this point.
+ * Get the nvram lock first before halting the cpu.
+ */
+ int lock_err = tg3_nvram_lock(tp);
+ err = tg3_halt_cpu(tp, cpu_base);
+ if (!lock_err)
+ tg3_nvram_unlock(tp);
+ if (err)
+ goto out;
- for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
- write_op(tp, cpu_scratch_base + i, 0);
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
- for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
- write_op(tp, (cpu_scratch_base +
- (info->fw_base & 0xffff) +
- (i * sizeof(u32))),
- be32_to_cpu(info->fw_data[i]));
+ for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+ write_op(tp, cpu_scratch_base + i, 0);
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32(cpu_base + CPU_MODE,
+ tr32(cpu_base + CPU_MODE) | CPU_MODE_HALT);
+ } else {
+ /* Subtract additional main header for fragmented firmware and
+ * advance to the first fragment
+ */
+ total_len -= TG3_FW_HDR_LEN;
+ fw_hdr++;
+ }
+
+ do {
+ u32 *fw_data = (u32 *)(fw_hdr + 1);
+ for (i = 0; i < tg3_fw_data_len(tp, fw_hdr); i++)
+ write_op(tp, cpu_scratch_base +
+ (be32_to_cpu(fw_hdr->base_addr) & 0xffff) +
+ (i * sizeof(u32)),
+ be32_to_cpu(fw_data[i]));
+
+ total_len -= be32_to_cpu(fw_hdr->len);
+
+ /* Advance to next fragment */
+ fw_hdr = (struct tg3_firmware_hdr *)
+ ((void *)fw_hdr + be32_to_cpu(fw_hdr->len));
+ } while (total_len > 0);
err = 0;
@@ -3552,13 +3665,33 @@ out:
}
/* tp->lock is held. */
+static int tg3_pause_cpu_and_set_pc(struct tg3 *tp, u32 cpu_base, u32 pc)
+{
+ int i;
+ const int iters = 5;
+
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32_f(cpu_base + CPU_PC, pc);
+
+ for (i = 0; i < iters; i++) {
+ if (tr32(cpu_base + CPU_PC) == pc)
+ break;
+ tw32(cpu_base + CPU_STATE, 0xffffffff);
+ tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
+ tw32_f(cpu_base + CPU_PC, pc);
+ udelay(1000);
+ }
+
+ return (i == iters) ? -EBUSY : 0;
+}
+
+/* tp->lock is held. */
static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
{
- struct fw_info info;
- const __be32 *fw_data;
- int err, i;
+ const struct tg3_firmware_hdr *fw_hdr;
+ int err;
- fw_data = (void *)tp->fw->data;
+ fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
/* Firmware blob starts with version numbers, followed by
start address and length. We are setting complete length.
@@ -3566,60 +3699,117 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
Remainder is the blob to be loaded contiguously
from start address. */
- info.fw_base = be32_to_cpu(fw_data[1]);
- info.fw_len = tp->fw->size - 12;
- info.fw_data = &fw_data[3];
-
err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
- &info);
+ fw_hdr);
if (err)
return err;
err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE,
- &info);
+ fw_hdr);
if (err)
return err;
/* Now startup only the RX cpu. */
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
-
- for (i = 0; i < 5; i++) {
- if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
- break;
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT);
- tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
- udelay(1000);
- }
- if (i >= 5) {
+ err = tg3_pause_cpu_and_set_pc(tp, RX_CPU_BASE,
+ be32_to_cpu(fw_hdr->base_addr));
+ if (err) {
netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
"should be %08x\n", __func__,
- tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
+ tr32(RX_CPU_BASE + CPU_PC),
+ be32_to_cpu(fw_hdr->base_addr));
return -ENODEV;
}
- tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32_f(RX_CPU_BASE + CPU_MODE, 0x00000000);
+
+ tg3_rxcpu_resume(tp);
return 0;
}
+static int tg3_validate_rxcpu_state(struct tg3 *tp)
+{
+ const int iters = 1000;
+ int i;
+ u32 val;
+
+ /* Wait for boot code to complete initialization and enter service
+ * loop. It is then safe to download service patches
+ */
+ for (i = 0; i < iters; i++) {
+ if (tr32(RX_CPU_HWBKPT) == TG3_SBROM_IN_SERVICE_LOOP)
+ break;
+
+ udelay(10);
+ }
+
+ if (i == iters) {
+ netdev_err(tp->dev, "Boot code not ready for service patches\n");
+ return -EBUSY;
+ }
+
+ val = tg3_read_indirect_reg32(tp, TG3_57766_FW_HANDSHAKE);
+ if (val & 0xff) {
+ netdev_warn(tp->dev,
+ "Other patches exist. Not downloading EEE patch\n");
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_load_57766_firmware(struct tg3 *tp)
+{
+ struct tg3_firmware_hdr *fw_hdr;
+
+ if (!tg3_flag(tp, NO_NVRAM))
+ return;
+
+ if (tg3_validate_rxcpu_state(tp))
+ return;
+
+ if (!tp->fw)
+ return;
+
+ /* This firmware blob has a different format than older firmware
+ * releases as given below. The main difference is we have fragmented
+ * data to be written to non-contiguous locations.
+ *
+ * In the beginning we have a firmware header identical to other
+ * firmware which consists of version, base addr and length. The length
+ * here is unused and set to 0xffffffff.
+ *
+ * This is followed by a series of firmware fragments which are
+ * individually identical to previous firmware. i.e. they have the
+ * firmware header and followed by data for that fragment. The version
+ * field of the individual fragment header is unused.
+ */
+
+ fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
+ if (be32_to_cpu(fw_hdr->base_addr) != TG3_57766_FW_BASE_ADDR)
+ return;
+
+ if (tg3_rxcpu_pause(tp))
+ return;
+
+ /* tg3_load_firmware_cpu() will always succeed for the 57766 */
+ tg3_load_firmware_cpu(tp, 0, TG3_57766_FW_BASE_ADDR, 0, fw_hdr);
+
+ tg3_rxcpu_resume(tp);
+}
+
/* tp->lock is held. */
static int tg3_load_tso_firmware(struct tg3 *tp)
{
- struct fw_info info;
- const __be32 *fw_data;
+ const struct tg3_firmware_hdr *fw_hdr;
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
- int err, i;
+ int err;
- if (tg3_flag(tp, HW_TSO_1) ||
- tg3_flag(tp, HW_TSO_2) ||
- tg3_flag(tp, HW_TSO_3))
+ if (!tg3_flag(tp, FW_TSO))
return 0;
- fw_data = (void *)tp->fw->data;
+ fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
/* Firmware blob starts with version numbers, followed by
start address and length. We are setting complete length.
@@ -3627,10 +3817,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
Remainder is the blob to be loaded contiguously
from start address. */
- info.fw_base = be32_to_cpu(fw_data[1]);
cpu_scratch_size = tp->fw_len;
- info.fw_len = tp->fw->size - 12;
- info.fw_data = &fw_data[3];
if (tg3_asic_rev(tp) == ASIC_REV_5705) {
cpu_base = RX_CPU_BASE;
@@ -3643,36 +3830,28 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
err = tg3_load_firmware_cpu(tp, cpu_base,
cpu_scratch_base, cpu_scratch_size,
- &info);
+ fw_hdr);
if (err)
return err;
/* Now startup the cpu. */
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32_f(cpu_base + CPU_PC, info.fw_base);
-
- for (i = 0; i < 5; i++) {
- if (tr32(cpu_base + CPU_PC) == info.fw_base)
- break;
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
- tw32_f(cpu_base + CPU_PC, info.fw_base);
- udelay(1000);
- }
- if (i >= 5) {
+ err = tg3_pause_cpu_and_set_pc(tp, cpu_base,
+ be32_to_cpu(fw_hdr->base_addr));
+ if (err) {
netdev_err(tp->dev,
"%s fails to set CPU PC, is %08x should be %08x\n",
- __func__, tr32(cpu_base + CPU_PC), info.fw_base);
+ __func__, tr32(cpu_base + CPU_PC),
+ be32_to_cpu(fw_hdr->base_addr));
return -ENODEV;
}
- tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32_f(cpu_base + CPU_MODE, 0x00000000);
+
+ tg3_resume_cpu(tp, cpu_base);
return 0;
}
/* tp->lock is held. */
-static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
+static void __tg3_set_mac_addr(struct tg3 *tp, bool skip_mac_1)
{
u32 addr_high, addr_low;
int i;
@@ -3735,7 +3914,7 @@ static int tg3_power_up(struct tg3 *tp)
return err;
}
-static int tg3_setup_phy(struct tg3 *, int);
+static int tg3_setup_phy(struct tg3 *, bool);
static int tg3_power_down_prepare(struct tg3 *tp)
{
@@ -3807,7 +3986,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER;
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
- tg3_setup_phy(tp, 0);
+ tg3_setup_phy(tp, false);
}
if (tg3_asic_rev(tp) == ASIC_REV_5906) {
@@ -3848,7 +4027,13 @@ static int tg3_power_down_prepare(struct tg3 *tp)
if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
mac_mode = MAC_MODE_PORT_MODE_GMII;
- else
+ else if (tp->phy_flags &
+ TG3_PHYFLG_KEEP_LINK_ON_PWRDN) {
+ if (tp->link_config.active_speed == SPEED_1000)
+ mac_mode = MAC_MODE_PORT_MODE_GMII;
+ else
+ mac_mode = MAC_MODE_PORT_MODE_MII;
+ } else
mac_mode = MAC_MODE_PORT_MODE_MII;
mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
@@ -4102,12 +4287,16 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
u32 adv, fc;
- if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
+ !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)) {
adv = ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full;
if (tg3_flag(tp, WOL_SPEED_100MB))
adv |= ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full;
+ if (tp->phy_flags & TG3_PHYFLG_1G_ON_VAUX_OK)
+ adv |= ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full;
fc = FLOW_CTRL_TX | FLOW_CTRL_RX;
} else {
@@ -4121,6 +4310,15 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_phy_autoneg_cfg(tp, adv, fc);
+ if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
+ (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN)) {
+ /* Normally during power down we want to autonegotiate
+ * the lowest possible speed for WOL. However, to avoid
+ * link flap, we leave it untouched.
+ */
+ return;
+ }
+
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
} else {
@@ -4177,6 +4375,103 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
}
}
+static int tg3_phy_pull_config(struct tg3 *tp)
+{
+ int err;
+ u32 val;
+
+ err = tg3_readphy(tp, MII_BMCR, &val);
+ if (err)
+ goto done;
+
+ if (!(val & BMCR_ANENABLE)) {
+ tp->link_config.autoneg = AUTONEG_DISABLE;
+ tp->link_config.advertising = 0;
+ tg3_flag_clear(tp, PAUSE_AUTONEG);
+
+ err = -EIO;
+
+ switch (val & (BMCR_SPEED1000 | BMCR_SPEED100)) {
+ case 0:
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+ goto done;
+
+ tp->link_config.speed = SPEED_10;
+ break;
+ case BMCR_SPEED100:
+ if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
+ goto done;
+
+ tp->link_config.speed = SPEED_100;
+ break;
+ case BMCR_SPEED1000:
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
+ tp->link_config.speed = SPEED_1000;
+ break;
+ }
+ /* Fall through */
+ default:
+ goto done;
+ }
+
+ if (val & BMCR_FULLDPLX)
+ tp->link_config.duplex = DUPLEX_FULL;
+ else
+ tp->link_config.duplex = DUPLEX_HALF;
+
+ tp->link_config.flowctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
+
+ err = 0;
+ goto done;
+ }
+
+ tp->link_config.autoneg = AUTONEG_ENABLE;
+ tp->link_config.advertising = ADVERTISED_Autoneg;
+ tg3_flag_set(tp, PAUSE_AUTONEG);
+
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
+ u32 adv;
+
+ err = tg3_readphy(tp, MII_ADVERTISE, &val);
+ if (err)
+ goto done;
+
+ adv = mii_adv_to_ethtool_adv_t(val & ADVERTISE_ALL);
+ tp->link_config.advertising |= adv | ADVERTISED_TP;
+
+ tp->link_config.flowctrl = tg3_decode_flowctrl_1000T(val);
+ } else {
+ tp->link_config.advertising |= ADVERTISED_FIBRE;
+ }
+
+ if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
+ u32 adv;
+
+ if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) {
+ err = tg3_readphy(tp, MII_CTRL1000, &val);
+ if (err)
+ goto done;
+
+ adv = mii_ctrl1000_to_ethtool_adv_t(val);
+ } else {
+ err = tg3_readphy(tp, MII_ADVERTISE, &val);
+ if (err)
+ goto done;
+
+ adv = tg3_decode_flowctrl_1000X(val);
+ tp->link_config.flowctrl = adv;
+
+ val &= (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL);
+ adv = mii_adv_to_ethtool_adv_x(val);
+ }
+
+ tp->link_config.advertising |= adv;
+ }
+
+done:
+ return err;
+}
+
static int tg3_init_5401phy_dsp(struct tg3 *tp)
{
int err;
@@ -4196,6 +4491,32 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
return err;
}
+static bool tg3_phy_eee_config_ok(struct tg3 *tp)
+{
+ u32 val;
+ u32 tgtadv = 0;
+ u32 advertising = tp->link_config.advertising;
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+ return true;
+
+ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
+ return false;
+
+ val &= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+
+
+ if (advertising & ADVERTISED_100baseT_Full)
+ tgtadv |= MDIO_AN_EEE_ADV_100TX;
+ if (advertising & ADVERTISED_1000baseT_Full)
+ tgtadv |= MDIO_AN_EEE_ADV_1000T;
+
+ if (val != tgtadv)
+ return false;
+
+ return true;
+}
+
static bool tg3_phy_copper_an_config_ok(struct tg3 *tp, u32 *lcladv)
{
u32 advmsk, tgtadv, advertising;
@@ -4262,7 +4583,7 @@ static bool tg3_phy_copper_fetch_rmtadv(struct tg3 *tp, u32 *rmtadv)
return true;
}
-static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)
+static bool tg3_test_and_report_link_chg(struct tg3 *tp, bool curr_link_up)
{
if (curr_link_up != tp->link_up) {
if (curr_link_up) {
@@ -4280,23 +4601,28 @@ static bool tg3_test_and_report_link_chg(struct tg3 *tp, int curr_link_up)
return false;
}
-static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
+static void tg3_clear_mac_status(struct tg3 *tp)
{
- int current_link_up;
+ tw32(MAC_EVENT, 0);
+
+ tw32_f(MAC_STATUS,
+ MAC_STATUS_SYNC_CHANGED |
+ MAC_STATUS_CFG_CHANGED |
+ MAC_STATUS_MI_COMPLETION |
+ MAC_STATUS_LNKSTATE_CHANGED);
+ udelay(40);
+}
+
+static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
+{
+ bool current_link_up;
u32 bmsr, val;
u32 lcl_adv, rmt_adv;
u16 current_speed;
u8 current_duplex;
int i, err;
- tw32(MAC_EVENT, 0);
-
- tw32_f(MAC_STATUS,
- (MAC_STATUS_SYNC_CHANGED |
- MAC_STATUS_CFG_CHANGED |
- MAC_STATUS_MI_COMPLETION |
- MAC_STATUS_LNKSTATE_CHANGED));
- udelay(40);
+ tg3_clear_mac_status(tp);
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
tw32_f(MAC_MI_MODE,
@@ -4316,7 +4642,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
!(bmsr & BMSR_LSTATUS))
- force_reset = 1;
+ force_reset = true;
}
if (force_reset)
tg3_phy_reset(tp);
@@ -4380,7 +4706,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
}
- current_link_up = 0;
+ current_link_up = false;
current_speed = SPEED_UNKNOWN;
current_duplex = DUPLEX_UNKNOWN;
tp->phy_flags &= ~TG3_PHYFLG_MDIX_STATE;
@@ -4439,21 +4765,31 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
tp->link_config.active_duplex = current_duplex;
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ bool eee_config_ok = tg3_phy_eee_config_ok(tp);
+
if ((bmcr & BMCR_ANENABLE) &&
+ eee_config_ok &&
tg3_phy_copper_an_config_ok(tp, &lcl_adv) &&
tg3_phy_copper_fetch_rmtadv(tp, &rmt_adv))
- current_link_up = 1;
+ current_link_up = true;
+
+ /* EEE settings changes take effect only after a phy
+ * reset. If we have skipped a reset due to Link Flap
+ * Avoidance being enabled, do it now.
+ */
+ if (!eee_config_ok &&
+ (tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+ !force_reset)
+ tg3_phy_reset(tp);
} else {
if (!(bmcr & BMCR_ANENABLE) &&
tp->link_config.speed == current_speed &&
- tp->link_config.duplex == current_duplex &&
- tp->link_config.flowctrl ==
- tp->link_config.active_flowctrl) {
- current_link_up = 1;
+ tp->link_config.duplex == current_duplex) {
+ current_link_up = true;
}
}
- if (current_link_up == 1 &&
+ if (current_link_up &&
tp->link_config.active_duplex == DUPLEX_FULL) {
u32 reg, bit;
@@ -4473,11 +4809,11 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
}
relink:
- if (current_link_up == 0 || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
+ if (!current_link_up || (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
tg3_phy_copper_begin(tp);
if (tg3_flag(tp, ROBOSWITCH)) {
- current_link_up = 1;
+ current_link_up = true;
/* FIXME: when BCM5325 switch is used use 100 MBit/s */
current_speed = SPEED_1000;
current_duplex = DUPLEX_FULL;
@@ -4488,11 +4824,11 @@ relink:
tg3_readphy(tp, MII_BMSR, &bmsr);
if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
- current_link_up = 1;
+ current_link_up = true;
}
tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
- if (current_link_up == 1) {
+ if (current_link_up) {
if (tp->link_config.active_speed == SPEED_100 ||
tp->link_config.active_speed == SPEED_10)
tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
@@ -4528,7 +4864,7 @@ relink:
tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
if (tg3_asic_rev(tp) == ASIC_REV_5700) {
- if (current_link_up == 1 &&
+ if (current_link_up &&
tg3_5700_link_polarity(tp, tp->link_config.active_speed))
tp->mac_mode |= MAC_MODE_LINK_POLARITY;
else
@@ -4559,7 +4895,7 @@ relink:
udelay(40);
if (tg3_asic_rev(tp) == ASIC_REV_5700 &&
- current_link_up == 1 &&
+ current_link_up &&
tp->link_config.active_speed == SPEED_1000 &&
(tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
udelay(120);
@@ -4999,19 +5335,19 @@ static void tg3_init_bcm8002(struct tg3 *tp)
tg3_writephy(tp, 0x10, 0x8011);
}
-static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
+static bool tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
{
u16 flowctrl;
+ bool current_link_up;
u32 sg_dig_ctrl, sg_dig_status;
u32 serdes_cfg, expected_sg_dig_ctrl;
int workaround, port_a;
- int current_link_up;
serdes_cfg = 0;
expected_sg_dig_ctrl = 0;
workaround = 0;
port_a = 1;
- current_link_up = 0;
+ current_link_up = false;
if (tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A0 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_5704_A1) {
@@ -5042,7 +5378,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
}
if (mac_status & MAC_STATUS_PCS_SYNCED) {
tg3_setup_flow_control(tp, 0, 0);
- current_link_up = 1;
+ current_link_up = true;
}
goto out;
}
@@ -5063,7 +5399,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
MAC_STATUS_RCVD_CFG)) ==
MAC_STATUS_PCS_SYNCED)) {
tp->serdes_counter--;
- current_link_up = 1;
+ current_link_up = true;
goto out;
}
restart_autoneg:
@@ -5098,7 +5434,7 @@ restart_autoneg:
mii_adv_to_ethtool_adv_x(remote_adv);
tg3_setup_flow_control(tp, local_adv, remote_adv);
- current_link_up = 1;
+ current_link_up = true;
tp->serdes_counter = 0;
tp->phy_flags &= ~TG3_PHYFLG_PARALLEL_DETECT;
} else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
@@ -5126,7 +5462,7 @@ restart_autoneg:
if ((mac_status & MAC_STATUS_PCS_SYNCED) &&
!(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0);
- current_link_up = 1;
+ current_link_up = true;
tp->phy_flags |=
TG3_PHYFLG_PARALLEL_DETECT;
tp->serdes_counter =
@@ -5144,9 +5480,9 @@ out:
return current_link_up;
}
-static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
+static bool tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
{
- int current_link_up = 0;
+ bool current_link_up = false;
if (!(mac_status & MAC_STATUS_PCS_SYNCED))
goto out;
@@ -5173,7 +5509,7 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
tg3_setup_flow_control(tp, local_adv, remote_adv);
- current_link_up = 1;
+ current_link_up = true;
}
for (i = 0; i < 30; i++) {
udelay(20);
@@ -5188,15 +5524,15 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
}
mac_status = tr32(MAC_STATUS);
- if (current_link_up == 0 &&
+ if (!current_link_up &&
(mac_status & MAC_STATUS_PCS_SYNCED) &&
!(mac_status & MAC_STATUS_RCVD_CFG))
- current_link_up = 1;
+ current_link_up = true;
} else {
tg3_setup_flow_control(tp, 0, 0);
/* Forcing 1000FD link up. */
- current_link_up = 1;
+ current_link_up = true;
tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
udelay(40);
@@ -5209,13 +5545,13 @@ out:
return current_link_up;
}
-static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_fiber_phy(struct tg3 *tp, bool force_reset)
{
u32 orig_pause_cfg;
u16 orig_active_speed;
u8 orig_active_duplex;
u32 mac_status;
- int current_link_up;
+ bool current_link_up;
int i;
orig_pause_cfg = tp->link_config.active_flowctrl;
@@ -5252,7 +5588,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
udelay(40);
- current_link_up = 0;
+ current_link_up = false;
tp->link_config.rmt_adv = 0;
mac_status = tr32(MAC_STATUS);
@@ -5277,7 +5613,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
- current_link_up = 0;
+ current_link_up = false;
if (tp->link_config.autoneg == AUTONEG_ENABLE &&
tp->serdes_counter == 0) {
tw32_f(MAC_MODE, (tp->mac_mode |
@@ -5287,7 +5623,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
}
}
- if (current_link_up == 1) {
+ if (current_link_up) {
tp->link_config.active_speed = SPEED_1000;
tp->link_config.active_duplex = DUPLEX_FULL;
tw32(MAC_LED_CTRL, (tp->led_ctrl |
@@ -5312,33 +5648,63 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
return 0;
}
-static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_fiber_mii_phy(struct tg3 *tp, bool force_reset)
{
- int current_link_up, err = 0;
+ int err = 0;
u32 bmsr, bmcr;
- u16 current_speed;
- u8 current_duplex;
- u32 local_adv, remote_adv;
+ u16 current_speed = SPEED_UNKNOWN;
+ u8 current_duplex = DUPLEX_UNKNOWN;
+ bool current_link_up = false;
+ u32 local_adv, remote_adv, sgsr;
+
+ if ((tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720) &&
+ !tg3_readphy(tp, SERDES_TG3_1000X_STATUS, &sgsr) &&
+ (sgsr & SERDES_TG3_SGMII_MODE)) {
+
+ if (force_reset)
+ tg3_phy_reset(tp);
+
+ tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
+
+ if (!(sgsr & SERDES_TG3_LINK_UP)) {
+ tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ } else {
+ current_link_up = true;
+ if (sgsr & SERDES_TG3_SPEED_1000) {
+ current_speed = SPEED_1000;
+ tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+ } else if (sgsr & SERDES_TG3_SPEED_100) {
+ current_speed = SPEED_100;
+ tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+ } else {
+ current_speed = SPEED_10;
+ tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+ }
+
+ if (sgsr & SERDES_TG3_FULL_DUPLEX)
+ current_duplex = DUPLEX_FULL;
+ else
+ current_duplex = DUPLEX_HALF;
+ }
+
+ tw32_f(MAC_MODE, tp->mac_mode);
+ udelay(40);
+
+ tg3_clear_mac_status(tp);
+
+ goto fiber_setup_done;
+ }
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
- tw32(MAC_EVENT, 0);
-
- tw32_f(MAC_STATUS,
- (MAC_STATUS_SYNC_CHANGED |
- MAC_STATUS_CFG_CHANGED |
- MAC_STATUS_MI_COMPLETION |
- MAC_STATUS_LNKSTATE_CHANGED));
- udelay(40);
+ tg3_clear_mac_status(tp);
if (force_reset)
tg3_phy_reset(tp);
- current_link_up = 0;
- current_speed = SPEED_UNKNOWN;
- current_duplex = DUPLEX_UNKNOWN;
tp->link_config.rmt_adv = 0;
err |= tg3_readphy(tp, MII_BMSR, &bmsr);
@@ -5424,7 +5790,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
if (bmsr & BMSR_LSTATUS) {
current_speed = SPEED_1000;
- current_link_up = 1;
+ current_link_up = true;
if (bmcr & BMCR_FULLDPLX)
current_duplex = DUPLEX_FULL;
else
@@ -5451,12 +5817,13 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
} else if (!tg3_flag(tp, 5780_CLASS)) {
/* Link is up via parallel detect */
} else {
- current_link_up = 0;
+ current_link_up = false;
}
}
}
- if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+fiber_setup_done:
+ if (current_link_up && current_duplex == DUPLEX_FULL)
tg3_setup_flow_control(tp, local_adv, remote_adv);
tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
@@ -5535,7 +5902,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
}
}
-static int tg3_setup_phy(struct tg3 *tp, int force_reset)
+static int tg3_setup_phy(struct tg3 *tp, bool force_reset)
{
u32 val;
int err;
@@ -5625,10 +5992,13 @@ static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE |
- SOF_TIMESTAMPING_TX_HARDWARE |
- SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE;
+ SOF_TIMESTAMPING_SOFTWARE;
+
+ if (tg3_flag(tp, PTP_CAPABLE)) {
+ info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ }
if (tp->ptp_clock)
info->phc_index = ptp_clock_index(tp->ptp_clock);
@@ -6348,7 +6718,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
if (desc->type_flags & RXD_FLAG_VLAN &&
!(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG))
- __vlan_hwaccel_put_tag(skb,
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
desc->err_vlan & RXD_VLAN_MASK);
napi_gro_receive(&tnapi->napi, skb);
@@ -6436,7 +6806,7 @@ static void tg3_poll_link(struct tg3 *tp)
MAC_STATUS_LNKSTATE_CHANGED));
udelay(40);
} else
- tg3_setup_phy(tp, 0);
+ tg3_setup_phy(tp, false);
spin_unlock(&tp->lock);
}
}
@@ -7533,7 +7903,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
u32 val, bmcr, mac_mode, ptest = 0;
tg3_phy_toggle_apd(tp, false);
- tg3_phy_toggle_automdix(tp, 0);
+ tg3_phy_toggle_automdix(tp, false);
if (extlpbk && tg3_phy_set_extloopbk(tp))
return -EIO;
@@ -7641,7 +8011,7 @@ static void tg3_set_loopback(struct net_device *dev, netdev_features_t features)
spin_lock_bh(&tp->lock);
tg3_mac_loopback(tp, false);
/* Force link status check */
- tg3_setup_phy(tp, 1);
+ tg3_setup_phy(tp, true);
spin_unlock_bh(&tp->lock);
netdev_info(dev, "Internal MAC loopback mode disabled.\n");
}
@@ -8039,11 +8409,9 @@ static int tg3_mem_rx_acquire(struct tg3 *tp)
tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev,
TG3_RX_RCB_RING_BYTES(tp),
&tnapi->rx_rcb_mapping,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!tnapi->rx_rcb)
goto err_out;
-
- memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
}
return 0;
@@ -8093,12 +8461,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
tp->hw_stats = dma_alloc_coherent(&tp->pdev->dev,
sizeof(struct tg3_hw_stats),
&tp->stats_mapping,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!tp->hw_stats)
goto err_out;
- memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
-
for (i = 0; i < tp->irq_cnt; i++) {
struct tg3_napi *tnapi = &tp->napi[i];
struct tg3_hw_status *sblk;
@@ -8106,11 +8472,10 @@ static int tg3_alloc_consistent(struct tg3 *tp)
tnapi->hw_status = dma_alloc_coherent(&tp->pdev->dev,
TG3_HW_STATUS_SIZE,
&tnapi->status_mapping,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!tnapi->hw_status)
goto err_out;
- memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
sblk = tnapi->hw_status;
if (tg3_flag(tp, ENABLE_RSS)) {
@@ -8157,7 +8522,7 @@ err_out:
/* To stop a block, clear the enable bit and poll till it
* clears. tp->lock is held.
*/
-static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int silent)
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, bool silent)
{
unsigned int i;
u32 val;
@@ -8201,7 +8566,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
}
/* tp->lock is held. */
-static int tg3_abort_hw(struct tg3 *tp, int silent)
+static int tg3_abort_hw(struct tg3 *tp, bool silent)
{
int i, err;
@@ -8561,6 +8926,9 @@ static int tg3_chip_reset(struct tg3 *tp)
/* Reprobe ASF enable state. */
tg3_flag_clear(tp, ENABLE_ASF);
+ tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK |
+ TG3_PHYFLG_KEEP_LINK_ON_PWRDN);
+
tg3_flag_clear(tp, ASF_NEW_HANDSHAKE);
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
@@ -8572,6 +8940,12 @@ static int tg3_chip_reset(struct tg3 *tp)
tp->last_event_jiffies = jiffies;
if (tg3_flag(tp, 5750_PLUS))
tg3_flag_set(tp, ASF_NEW_HANDSHAKE);
+
+ tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &nic_cfg);
+ if (nic_cfg & NIC_SRAM_1G_ON_VAUX_OK)
+ tp->phy_flags |= TG3_PHYFLG_1G_ON_VAUX_OK;
+ if (nic_cfg & NIC_SRAM_LNK_FLAP_AVOID)
+ tp->phy_flags |= TG3_PHYFLG_KEEP_LINK_ON_PWRDN;
}
}
@@ -8582,7 +8956,7 @@ static void tg3_get_nstats(struct tg3 *, struct rtnl_link_stats64 *);
static void tg3_get_estats(struct tg3 *, struct tg3_ethtool_stats *);
/* tp->lock is held. */
-static int tg3_halt(struct tg3 *tp, int kind, int silent)
+static int tg3_halt(struct tg3 *tp, int kind, bool silent)
{
int err;
@@ -8593,7 +8967,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
tg3_abort_hw(tp, silent);
err = tg3_chip_reset(tp);
- __tg3_set_mac_addr(tp, 0);
+ __tg3_set_mac_addr(tp, false);
tg3_write_sig_legacy(tp, kind);
tg3_write_sig_post_reset(tp, kind);
@@ -8617,7 +8991,8 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
{
struct tg3 *tp = netdev_priv(dev);
struct sockaddr *addr = p;
- int err = 0, skip_mac_1 = 0;
+ int err = 0;
+ bool skip_mac_1 = false;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
@@ -8638,7 +9013,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
/* Skip MAC addr 1 if ASF is using it. */
if ((addr0_high != addr1_high || addr0_low != addr1_low) &&
!(addr1_high == 0 && addr1_low == 0))
- skip_mac_1 = 1;
+ skip_mac_1 = true;
}
spin_lock_bh(&tp->lock);
__tg3_set_mac_addr(tp, skip_mac_1);
@@ -9057,7 +9432,7 @@ static void tg3_rss_write_indir_tbl(struct tg3 *tp)
}
/* tp->lock is held. */
-static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
+static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
{
u32 val, rdmac_mode;
int i, err, limit;
@@ -9106,6 +9481,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
}
+ if ((tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+ !(tp->phy_flags & TG3_PHYFLG_USER_CONFIGURED)) {
+ tg3_phy_pull_config(tp);
+ tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+ }
+
if (reset_phy)
tg3_phy_reset(tp);
@@ -9444,7 +9825,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_rings_reset(tp);
/* Initialize MAC address and backoff seed. */
- __tg3_set_mac_addr(tp, 0);
+ __tg3_set_mac_addr(tp, false);
/* MTU + ethernet header + FCS + optional VLAN tag */
tw32(MAC_RX_MTU_SIZE,
@@ -9781,6 +10162,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
}
+ if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+ /* Ignore any errors for the firmware download. If download
+ * fails, the device will operate with EEE disabled
+ */
+ tg3_load_57766_firmware(tp);
+ }
+
if (tg3_flag(tp, TSO_CAPABLE)) {
err = tg3_load_tso_firmware(tp);
if (err)
@@ -9888,7 +10276,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER;
- err = tg3_setup_phy(tp, 0);
+ err = tg3_setup_phy(tp, false);
if (err)
return err;
@@ -9968,7 +10356,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Called at device open time to get the chip ready for
* packet processing. Invoked with tp->lock held.
*/
-static int tg3_init_hw(struct tg3 *tp, int reset_phy)
+static int tg3_init_hw(struct tg3 *tp, bool reset_phy)
{
tg3_switch_clocks(tp);
@@ -10229,7 +10617,7 @@ static void tg3_timer(unsigned long __opaque)
phy_event = 1;
if (phy_event)
- tg3_setup_phy(tp, 0);
+ tg3_setup_phy(tp, false);
} else if (tg3_flag(tp, POLL_SERDES)) {
u32 mac_stat = tr32(MAC_STATUS);
int need_setup = 0;
@@ -10252,7 +10640,7 @@ static void tg3_timer(unsigned long __opaque)
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
}
- tg3_setup_phy(tp, 0);
+ tg3_setup_phy(tp, false);
}
} else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
tg3_flag(tp, 5780_CLASS)) {
@@ -10338,7 +10726,7 @@ static void tg3_timer_stop(struct tg3 *tp)
/* Restart hardware after configuration changes, self-test, etc.
* Invoked with tp->lock held.
*/
-static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+static int tg3_restart_hw(struct tg3 *tp, bool reset_phy)
__releases(tp->lock)
__acquires(tp->lock)
{
@@ -10388,7 +10776,7 @@ static void tg3_reset_task(struct work_struct *work)
}
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- err = tg3_init_hw(tp, 1);
+ err = tg3_init_hw(tp, true);
if (err)
goto out;
@@ -10558,7 +10946,7 @@ static int tg3_test_msi(struct tg3 *tp)
tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_init_hw(tp, 1);
+ err = tg3_init_hw(tp, true);
tg3_full_unlock(tp);
@@ -10570,7 +10958,7 @@ static int tg3_test_msi(struct tg3 *tp)
static int tg3_request_firmware(struct tg3 *tp)
{
- const __be32 *fw_data;
+ const struct tg3_firmware_hdr *fw_hdr;
if (request_firmware(&tp->fw, tp->fw_needed, &tp->pdev->dev)) {
netdev_err(tp->dev, "Failed to load firmware \"%s\"\n",
@@ -10578,15 +10966,15 @@ static int tg3_request_firmware(struct tg3 *tp)
return -ENOENT;
}
- fw_data = (void *)tp->fw->data;
+ fw_hdr = (struct tg3_firmware_hdr *)tp->fw->data;
/* Firmware blob starts with version numbers, followed by
* start address and _full_ length including BSS sections
* (which must be longer than the actual data, of course
*/
- tp->fw_len = be32_to_cpu(fw_data[2]); /* includes bss */
- if (tp->fw_len < (tp->fw->size - 12)) {
+ tp->fw_len = be32_to_cpu(fw_hdr->len); /* includes bss */
+ if (tp->fw_len < (tp->fw->size - TG3_FW_HDR_LEN)) {
netdev_err(tp->dev, "bogus length %d in \"%s\"\n",
tp->fw_len, tp->fw_needed);
release_firmware(tp->fw);
@@ -10885,7 +11273,15 @@ static int tg3_open(struct net_device *dev)
if (tp->fw_needed) {
err = tg3_request_firmware(tp);
- if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
+ if (tg3_asic_rev(tp) == ASIC_REV_57766) {
+ if (err) {
+ netdev_warn(tp->dev, "EEE capability disabled\n");
+ tp->phy_flags &= ~TG3_PHYFLG_EEE_CAP;
+ } else if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+ netdev_warn(tp->dev, "EEE capability restored\n");
+ tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+ }
+ } else if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0) {
if (err)
return err;
} else if (err) {
@@ -10910,7 +11306,9 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp);
- err = tg3_start(tp, true, true, true);
+ err = tg3_start(tp,
+ !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN),
+ true, true);
if (err) {
tg3_frob_aux_power(tp, false);
pci_set_power_state(tp->pdev, PCI_D3hot);
@@ -11416,8 +11814,12 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.duplex = cmd->duplex;
}
+ tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+
+ tg3_warn_mgmt_link_flap(tp);
+
if (netif_running(dev))
- tg3_setup_phy(tp, 1);
+ tg3_setup_phy(tp, true);
tg3_full_unlock(tp);
@@ -11494,6 +11896,8 @@ static int tg3_nway_reset(struct net_device *dev)
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
return -EINVAL;
+ tg3_warn_mgmt_link_flap(tp);
+
if (tg3_flag(tp, USE_PHYLIB)) {
if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
@@ -11571,7 +11975,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_restart_hw(tp, 1);
+ err = tg3_restart_hw(tp, false);
if (!err)
tg3_netif_start(tp);
}
@@ -11606,6 +12010,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
struct tg3 *tp = netdev_priv(dev);
int err = 0;
+ if (tp->link_config.autoneg == AUTONEG_ENABLE)
+ tg3_warn_mgmt_link_flap(tp);
+
if (tg3_flag(tp, USE_PHYLIB)) {
u32 newadv;
struct phy_device *phydev;
@@ -11692,7 +12099,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_restart_hw(tp, 1);
+ err = tg3_restart_hw(tp, false);
if (!err)
tg3_netif_start(tp);
}
@@ -11700,6 +12107,8 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tg3_full_unlock(tp);
}
+ tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+
return err;
}
@@ -12760,7 +13169,7 @@ static int tg3_test_loopback(struct tg3 *tp, u64 *data, bool do_extlpbk)
goto done;
}
- err = tg3_reset_hw(tp, 1);
+ err = tg3_reset_hw(tp, true);
if (err) {
data[TG3_MAC_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
data[TG3_PHY_LOOPB_TEST] = TG3_LOOPBACK_FAILED;
@@ -12927,7 +13336,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tg3_flag_set(tp, INIT_COMPLETE);
- err2 = tg3_restart_hw(tp, 1);
+ err2 = tg3_restart_hw(tp, true);
if (!err2)
tg3_netif_start(tp);
}
@@ -13244,7 +13653,8 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
static int tg3_change_mtu(struct net_device *dev, int new_mtu)
{
struct tg3 *tp = netdev_priv(dev);
- int err, reset_phy = 0;
+ int err;
+ bool reset_phy = false;
if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
return -EINVAL;
@@ -13271,7 +13681,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
* breaks all requests to 256 bytes.
*/
if (tg3_asic_rev(tp) == ASIC_REV_57766)
- reset_phy = 1;
+ reset_phy = true;
err = tg3_restart_hw(tp, reset_phy);
@@ -13837,6 +14247,12 @@ static void tg3_get_5720_nvram_info(struct tg3 *tp)
case FLASH_5762_EEPROM_LD:
nvmpinstrp = FLASH_5720_EEPROM_LD;
break;
+ case FLASH_5720VENDOR_M_ST_M45PE20:
+ /* This pinstrap supports multiple sizes, so force it
+ * to read the actual size from location 0xf0.
+ */
+ nvmpinstrp = FLASH_5720VENDOR_ST_45USPT;
+ break;
}
}
@@ -14289,14 +14705,18 @@ static void tg3_get_eeprom_hw_cfg(struct tg3 *tp)
(cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN))
tp->phy_flags |= TG3_PHYFLG_ENABLE_APD;
- if (tg3_flag(tp, PCI_EXPRESS) &&
- tg3_asic_rev(tp) != ASIC_REV_5785 &&
- !tg3_flag(tp, 57765_PLUS)) {
+ if (tg3_flag(tp, PCI_EXPRESS)) {
u32 cfg3;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
- if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
+ if (tg3_asic_rev(tp) != ASIC_REV_5785 &&
+ !tg3_flag(tp, 57765_PLUS) &&
+ (cfg3 & NIC_SRAM_ASPM_DEBOUNCE))
tg3_flag_set(tp, ASPM_WORKAROUND);
+ if (cfg3 & NIC_SRAM_LNK_FLAP_AVOID)
+ tp->phy_flags |= TG3_PHYFLG_KEEP_LINK_ON_PWRDN;
+ if (cfg3 & NIC_SRAM_1G_ON_VAUX_OK)
+ tp->phy_flags |= TG3_PHYFLG_1G_ON_VAUX_OK;
}
if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE)
@@ -14450,6 +14870,12 @@ static int tg3_phy_probe(struct tg3 *tp)
}
}
+ if (!tg3_flag(tp, ENABLE_ASF) &&
+ !(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+ !(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
+ tp->phy_flags &= ~(TG3_PHYFLG_1G_ON_VAUX_OK |
+ TG3_PHYFLG_KEEP_LINK_ON_PWRDN);
+
if (tg3_flag(tp, USE_PHYLIB))
return tg3_phy_init(tp);
@@ -14515,6 +14941,7 @@ static int tg3_phy_probe(struct tg3 *tp)
if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
(tg3_asic_rev(tp) == ASIC_REV_5719 ||
tg3_asic_rev(tp) == ASIC_REV_5720 ||
+ tg3_asic_rev(tp) == ASIC_REV_57766 ||
tg3_asic_rev(tp) == ASIC_REV_5762 ||
(tg3_asic_rev(tp) == ASIC_REV_5717 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
@@ -14524,7 +14951,8 @@ static int tg3_phy_probe(struct tg3 *tp)
tg3_phy_init_link_config(tp);
- if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+ if (!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
+ !(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
!tg3_flag(tp, ENABLE_APE) &&
!tg3_flag(tp, ENABLE_ASF)) {
u32 bmsr, dummy;
@@ -14604,8 +15032,11 @@ static void tg3_read_vpd(struct tg3 *tp)
if (j + len > block_end)
goto partno;
- memcpy(tp->fw_ver, &vpd_data[j], len);
- strncat(tp->fw_ver, " bc ", vpdlen - len - 1);
+ if (len >= sizeof(tp->fw_ver))
+ len = sizeof(tp->fw_ver) - 1;
+ memset(tp->fw_ver, 0, sizeof(tp->fw_ver));
+ snprintf(tp->fw_ver, sizeof(tp->fw_ver), "%.*s bc ", len,
+ &vpd_data[j]);
}
partno:
@@ -15297,7 +15728,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
} else if (tg3_asic_rev(tp) != ASIC_REV_5700 &&
tg3_asic_rev(tp) != ASIC_REV_5701 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_5705_A0) {
- tg3_flag_set(tp, TSO_BUG);
+ tg3_flag_set(tp, FW_TSO);
+ tg3_flag_set(tp, TSO_BUG);
if (tg3_asic_rev(tp) == ASIC_REV_5705)
tp->fw_needed = FIRMWARE_TG3TSO5;
else
@@ -15308,7 +15740,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
if (tg3_flag(tp, HW_TSO_1) ||
tg3_flag(tp, HW_TSO_2) ||
tg3_flag(tp, HW_TSO_3) ||
- tp->fw_needed) {
+ tg3_flag(tp, FW_TSO)) {
/* For firmware TSO, assume ASF is disabled.
* We'll disable TSO later if we discover ASF
* is enabled in tg3_get_eeprom_hw_cfg().
@@ -15323,6 +15755,9 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
if (tg3_chip_rev_id(tp) == CHIPREV_ID_5701_A0)
tp->fw_needed = FIRMWARE_TG3;
+ if (tg3_asic_rev(tp) == ASIC_REV_57766)
+ tp->fw_needed = FIRMWARE_TG357766;
+
tp->irq_max = 1;
if (tg3_flag(tp, 5750_PLUS)) {
@@ -15595,7 +16030,7 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
*/
tg3_get_eeprom_hw_cfg(tp);
- if (tp->fw_needed && tg3_flag(tp, ENABLE_ASF)) {
+ if (tg3_flag(tp, FW_TSO) && tg3_flag(tp, ENABLE_ASF)) {
tg3_flag_clear(tp, TSO_CAPABLE);
tg3_flag_clear(tp, TSO_BUG);
tp->fw_needed = NULL;
@@ -15783,6 +16218,11 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
udelay(50);
tg3_nvram_init(tp);
+ /* If the device has an NVRAM, no need to load patch firmware */
+ if (tg3_asic_rev(tp) == ASIC_REV_57766 &&
+ !tg3_flag(tp, NO_NVRAM))
+ tp->fw_needed = NULL;
+
grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
@@ -16141,7 +16581,7 @@ out:
}
static int tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma,
- int size, int to_device)
+ int size, bool to_device)
{
struct tg3_internal_buffer_desc test_desc;
u32 sram_dma_descs;
@@ -16341,7 +16781,7 @@ static int tg3_test_dma(struct tg3 *tp)
p[i] = i;
/* Send the buffer to the chip. */
- ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
+ ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, true);
if (ret) {
dev_err(&tp->pdev->dev,
"%s: Buffer write failed. err = %d\n",
@@ -16364,7 +16804,7 @@ static int tg3_test_dma(struct tg3 *tp)
}
#endif
/* Now read it back. */
- ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
+ ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, false);
if (ret) {
dev_err(&tp->pdev->dev, "%s: Buffer read failed. "
"err = %d\n", __func__, ret);
@@ -16760,7 +17200,7 @@ static int tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
- features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
/* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
@@ -17045,7 +17485,7 @@ static int tg3_suspend(struct device *device)
tg3_full_lock(tp, 0);
tg3_flag_set(tp, INIT_COMPLETE);
- err2 = tg3_restart_hw(tp, 1);
+ err2 = tg3_restart_hw(tp, true);
if (err2)
goto out;
@@ -17079,7 +17519,8 @@ static int tg3_resume(struct device *device)
tg3_full_lock(tp, 0);
tg3_flag_set(tp, INIT_COMPLETE);
- err = tg3_restart_hw(tp, 1);
+ err = tg3_restart_hw(tp,
+ !(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN));
if (err)
goto out;
@@ -17095,15 +17536,9 @@ out:
return err;
}
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
-#define TG3_PM_OPS (&tg3_pm_ops)
-
-#else
-
-#define TG3_PM_OPS NULL
-
-#endif /* CONFIG_PM_SLEEP */
/**
* tg3_io_error_detected - called when PCI error is detected
@@ -17218,7 +17653,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
tg3_full_lock(tp, 0);
tg3_flag_set(tp, INIT_COMPLETE);
- err = tg3_restart_hw(tp, 1);
+ err = tg3_restart_hw(tp, true);
if (err) {
tg3_full_unlock(tp);
netdev_err(netdev, "Cannot restart hardware after reset.\n");
@@ -17251,7 +17686,7 @@ static struct pci_driver tg3_driver = {
.probe = tg3_init_one,
.remove = tg3_remove_one,
.err_handler = &tg3_err_handler,
- .driver.pm = TG3_PM_OPS,
+ .driver.pm = &tg3_pm_ops,
};
static int __init tg3_init(void)
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 8d7d4c2ab5d6..9b2d3ac2474a 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -2198,6 +2198,8 @@
#define NIC_SRAM_DATA_CFG_3 0x00000d3c
#define NIC_SRAM_ASPM_DEBOUNCE 0x00000002
+#define NIC_SRAM_LNK_FLAP_AVOID 0x00400000
+#define NIC_SRAM_1G_ON_VAUX_OK 0x00800000
#define NIC_SRAM_DATA_CFG_4 0x00000d60
#define NIC_SRAM_GMII_MODE 0x00000002
@@ -2222,6 +2224,12 @@
#define NIC_SRAM_MBUF_POOL_BASE5705 0x00010000
#define NIC_SRAM_MBUF_POOL_SIZE5705 0x0000e000
+#define TG3_SRAM_RXCPU_SCRATCH_BASE_57766 0x00030000
+#define TG3_SRAM_RXCPU_SCRATCH_SIZE_57766 0x00010000
+#define TG3_57766_FW_BASE_ADDR 0x00030000
+#define TG3_57766_FW_HANDSHAKE 0x0003fccc
+#define TG3_SBROM_IN_SERVICE_LOOP 0x51
+
#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700 128
#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755 64
#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906 32
@@ -2365,6 +2373,13 @@
#define MII_TG3_FET_SHDW_AUXSTAT2 0x1b
#define MII_TG3_FET_SHDW_AUXSTAT2_APD 0x0020
+/* Serdes PHY Register Definitions */
+#define SERDES_TG3_1000X_STATUS 0x14
+#define SERDES_TG3_SGMII_MODE 0x0001
+#define SERDES_TG3_LINK_UP 0x0002
+#define SERDES_TG3_FULL_DUPLEX 0x0004
+#define SERDES_TG3_SPEED_100 0x0008
+#define SERDES_TG3_SPEED_1000 0x0010
/* APE registers. Accessible through BAR1 */
#define TG3_APE_GPIO_MSG 0x0008
@@ -3009,17 +3024,18 @@ enum TG3_FLAGS {
TG3_FLAG_JUMBO_CAPABLE,
TG3_FLAG_CHIP_RESETTING,
TG3_FLAG_INIT_COMPLETE,
- TG3_FLAG_TSO_BUG,
TG3_FLAG_MAX_RXPEND_64,
- TG3_FLAG_TSO_CAPABLE,
TG3_FLAG_PCI_EXPRESS, /* BCM5785 + pci_is_pcie() */
TG3_FLAG_ASF_NEW_HANDSHAKE,
TG3_FLAG_HW_AUTONEG,
TG3_FLAG_IS_NIC,
TG3_FLAG_FLASH,
+ TG3_FLAG_FW_TSO,
TG3_FLAG_HW_TSO_1,
TG3_FLAG_HW_TSO_2,
TG3_FLAG_HW_TSO_3,
+ TG3_FLAG_TSO_CAPABLE,
+ TG3_FLAG_TSO_BUG,
TG3_FLAG_ICH_WORKAROUND,
TG3_FLAG_1SHOT_MSI,
TG3_FLAG_NO_FWARE_REPORTED,
@@ -3064,6 +3080,13 @@ enum TG3_FLAGS {
TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */
};
+struct tg3_firmware_hdr {
+ __be32 version; /* unused for fragments */
+ __be32 base_addr;
+ __be32 len;
+};
+#define TG3_FW_HDR_LEN (sizeof(struct tg3_firmware_hdr))
+
struct tg3 {
/* begin "general, frequently-used members" cacheline section */
@@ -3267,6 +3290,7 @@ struct tg3 {
#define TG3_PHYFLG_IS_LOW_POWER 0x00000001
#define TG3_PHYFLG_IS_CONNECTED 0x00000002
#define TG3_PHYFLG_USE_MI_INTERRUPT 0x00000004
+#define TG3_PHYFLG_USER_CONFIGURED 0x00000008
#define TG3_PHYFLG_PHY_SERDES 0x00000010
#define TG3_PHYFLG_MII_SERDES 0x00000020
#define TG3_PHYFLG_ANY_SERDES (TG3_PHYFLG_PHY_SERDES | \
@@ -3284,6 +3308,8 @@ struct tg3 {
#define TG3_PHYFLG_SERDES_PREEMPHASIS 0x00010000
#define TG3_PHYFLG_PARALLEL_DETECT 0x00020000
#define TG3_PHYFLG_EEE_CAP 0x00040000
+#define TG3_PHYFLG_1G_ON_VAUX_OK 0x00080000
+#define TG3_PHYFLG_KEEP_LINK_ON_PWRDN 0x00100000
#define TG3_PHYFLG_MDIX_STATE 0x00200000
u32 led_ctrl;
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 3227fdde521b..f2b73ffa9122 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -76,7 +76,7 @@ static void bfa_ioc_pf_disabled(struct bfa_ioc *ioc);
static void bfa_ioc_pf_failed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_hwfailed(struct bfa_ioc *ioc);
static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
-static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
+static void bfa_ioc_boot(struct bfa_ioc *ioc, enum bfi_fwboot_type boot_type,
u32 boot_param);
static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 7cce42dc2f20..ce4a030d3d0c 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -610,7 +610,7 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
rcb->rxq->rx_bytes += length;
if (flags & BNA_CQ_EF_VLAN)
- __vlan_hwaccel_put_tag(skb, ntohs(cmpl->vlan_tag));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
if (BNAD_RXBUF_IS_PAGE(unmap_q->type))
napi_gro_frags(&rx_ctrl->napi);
@@ -1264,9 +1264,8 @@ bnad_mem_alloc(struct bnad *bnad,
mem_info->mdl[i].len = mem_info->len;
mem_info->mdl[i].kva =
dma_alloc_coherent(&bnad->pcidev->dev,
- mem_info->len, &dma_pa,
- GFP_KERNEL);
-
+ mem_info->len, &dma_pa,
+ GFP_KERNEL);
if (mem_info->mdl[i].kva == NULL)
goto err_return;
@@ -3069,8 +3068,7 @@ bnad_change_mtu(struct net_device *netdev, int new_mtu)
}
static int
-bnad_vlan_rx_add_vid(struct net_device *netdev,
- unsigned short vid)
+bnad_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct bnad *bnad = netdev_priv(netdev);
unsigned long flags;
@@ -3091,8 +3089,7 @@ bnad_vlan_rx_add_vid(struct net_device *netdev,
}
static int
-bnad_vlan_rx_kill_vid(struct net_device *netdev,
- unsigned short vid)
+bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct bnad *bnad = netdev_priv(netdev);
unsigned long flags;
@@ -3171,14 +3168,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_TX;
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
netdev->features |= netdev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
index 3becdb2deb46..cc9a185f0abb 100644
--- a/drivers/net/ethernet/cadence/at91_ether.c
+++ b/drivers/net/ethernet/cadence/at91_ether.c
@@ -47,22 +47,19 @@ static int at91ether_start(struct net_device *dev)
int i;
lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev,
- MAX_RX_DESCR * sizeof(struct macb_dma_desc),
- &lp->rx_ring_dma, GFP_KERNEL);
- if (!lp->rx_ring) {
- netdev_err(dev, "unable to alloc rx ring DMA buffer\n");
+ (MAX_RX_DESCR *
+ sizeof(struct macb_dma_desc)),
+ &lp->rx_ring_dma, GFP_KERNEL);
+ if (!lp->rx_ring)
return -ENOMEM;
- }
lp->rx_buffers = dma_alloc_coherent(&lp->pdev->dev,
- MAX_RX_DESCR * MAX_RBUFF_SZ,
- &lp->rx_buffers_dma, GFP_KERNEL);
+ MAX_RX_DESCR * MAX_RBUFF_SZ,
+ &lp->rx_buffers_dma, GFP_KERNEL);
if (!lp->rx_buffers) {
- netdev_err(dev, "unable to alloc rx data DMA buffer\n");
-
dma_free_coherent(&lp->pdev->dev,
- MAX_RX_DESCR * sizeof(struct macb_dma_desc),
- lp->rx_ring, lp->rx_ring_dma);
+ MAX_RX_DESCR * sizeof(struct macb_dma_desc),
+ lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL;
return -ENOMEM;
}
@@ -209,7 +206,6 @@ static void at91ether_rx(struct net_device *dev)
netif_rx(skb);
} else {
lp->stats.rx_dropped++;
- netdev_notice(dev, "Memory squeeze, dropping packet.\n");
}
if (lp->rx_ring[lp->rx_tail].ctrl & MACB_BIT(RX_MHASH_MATCH))
@@ -303,42 +299,7 @@ static const struct of_device_id at91ether_dt_ids[] = {
{ .compatible = "cdns,emac" },
{ /* sentinel */ }
};
-
MODULE_DEVICE_TABLE(of, at91ether_dt_ids);
-
-static int at91ether_get_phy_mode_dt(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (np)
- return of_get_phy_mode(np);
-
- return -ENODEV;
-}
-
-static int at91ether_get_hwaddr_dt(struct macb *bp)
-{
- struct device_node *np = bp->pdev->dev.of_node;
-
- if (np) {
- const char *mac = of_get_mac_address(np);
- if (mac) {
- memcpy(bp->dev->dev_addr, mac, ETH_ALEN);
- return 0;
- }
- }
-
- return -ENODEV;
-}
-#else
-static int at91ether_get_phy_mode_dt(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-static int at91ether_get_hwaddr_dt(struct macb *bp)
-{
- return -ENODEV;
-}
#endif
/* Detect MAC & PHY and perform ethernet interface initialization */
@@ -352,6 +313,7 @@ static int __init at91ether_probe(struct platform_device *pdev)
struct macb *lp;
int res;
u32 reg;
+ const char *mac;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
@@ -403,11 +365,13 @@ static int __init at91ether_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- res = at91ether_get_hwaddr_dt(lp);
- if (res < 0)
+ mac = of_get_mac_address(pdev->dev.of_node);
+ if (mac)
+ memcpy(lp->dev->dev_addr, mac, ETH_ALEN);
+ else
macb_get_hwaddr(lp);
- res = at91ether_get_phy_mode_dt(pdev);
+ res = of_get_phy_mode(pdev->dev.of_node);
if (res < 0) {
if (board_data && board_data->is_rmii)
lp->phy_interface = PHY_INTERFACE_MODE_RMII;
@@ -430,7 +394,8 @@ static int __init at91ether_probe(struct platform_device *pdev)
if (res)
goto err_disable_clock;
- if (macb_mii_init(lp) != 0)
+ res = macb_mii_init(lp);
+ if (res)
goto err_out_unregister_netdev;
/* will be enabled in open() */
@@ -519,18 +484,7 @@ static struct platform_driver at91ether_driver = {
},
};
-static int __init at91ether_init(void)
-{
- return platform_driver_probe(&at91ether_driver, at91ether_probe);
-}
-
-static void __exit at91ether_exit(void)
-{
- platform_driver_unregister(&at91ether_driver);
-}
-
-module_init(at91ether_init)
-module_exit(at91ether_exit)
+module_platform_driver_probe(at91ether_driver, at91ether_probe);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 79039439bfdc..6be513deb17f 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -485,6 +485,8 @@ static void macb_tx_interrupt(struct macb *bp)
status = macb_readl(bp, TSR);
macb_writel(bp, TSR, status);
+ macb_writel(bp, ISR, MACB_BIT(TCOMP));
+
netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
(unsigned long)status);
@@ -736,6 +738,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
* now.
*/
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
+ macb_writel(bp, ISR, MACB_BIT(RCOMP));
if (napi_schedule_prep(&bp->napi)) {
netdev_vdbg(bp->dev, "scheduling RX softirq\n");
@@ -1054,6 +1057,7 @@ static void macb_configure_dma(struct macb *bp)
dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64);
dmacfg |= GEM_BF(FBLDO, 16);
dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
+ dmacfg &= ~GEM_BIT(ENDIA);
gem_writel(bp, DMACFG, dmacfg);
}
}
@@ -1472,41 +1476,7 @@ static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,gem" },
{ /* sentinel */ }
};
-
MODULE_DEVICE_TABLE(of, macb_dt_ids);
-
-static int macb_get_phy_mode_dt(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (np)
- return of_get_phy_mode(np);
-
- return -ENODEV;
-}
-
-static int macb_get_hwaddr_dt(struct macb *bp)
-{
- struct device_node *np = bp->pdev->dev.of_node;
- if (np) {
- const char *mac = of_get_mac_address(np);
- if (mac) {
- memcpy(bp->dev->dev_addr, mac, ETH_ALEN);
- return 0;
- }
- }
-
- return -ENODEV;
-}
-#else
-static int macb_get_phy_mode_dt(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-static int macb_get_hwaddr_dt(struct macb *bp)
-{
- return -ENODEV;
-}
#endif
static int __init macb_probe(struct platform_device *pdev)
@@ -1519,6 +1489,7 @@ static int __init macb_probe(struct platform_device *pdev)
u32 config;
int err = -ENXIO;
struct pinctrl *pinctrl;
+ const char *mac;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -1557,14 +1528,14 @@ static int __init macb_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get macb_clk\n");
goto err_out_free_dev;
}
- clk_enable(bp->pclk);
+ clk_prepare_enable(bp->pclk);
bp->hclk = clk_get(&pdev->dev, "hclk");
if (IS_ERR(bp->hclk)) {
dev_err(&pdev->dev, "failed to get hclk\n");
goto err_out_put_pclk;
}
- clk_enable(bp->hclk);
+ clk_prepare_enable(bp->hclk);
bp->regs = ioremap(regs->start, resource_size(regs));
if (!bp->regs) {
@@ -1592,11 +1563,13 @@ static int __init macb_probe(struct platform_device *pdev)
config |= macb_dbw(bp);
macb_writel(bp, NCFGR, config);
- err = macb_get_hwaddr_dt(bp);
- if (err < 0)
+ mac = of_get_mac_address(pdev->dev.of_node);
+ if (mac)
+ memcpy(bp->dev->dev_addr, mac, ETH_ALEN);
+ else
macb_get_hwaddr(bp);
- err = macb_get_phy_mode_dt(pdev);
+ err = of_get_phy_mode(pdev->dev.of_node);
if (err < 0) {
pdata = pdev->dev.platform_data;
if (pdata && pdata->is_rmii)
@@ -1629,9 +1602,9 @@ static int __init macb_probe(struct platform_device *pdev)
goto err_out_free_irq;
}
- if (macb_mii_init(bp) != 0) {
+ err = macb_mii_init(bp);
+ if (err)
goto err_out_unregister_netdev;
- }
platform_set_drvdata(pdev, dev);
@@ -1654,9 +1627,9 @@ err_out_free_irq:
err_out_iounmap:
iounmap(bp->regs);
err_out_disable_clocks:
- clk_disable(bp->hclk);
+ clk_disable_unprepare(bp->hclk);
clk_put(bp->hclk);
- clk_disable(bp->pclk);
+ clk_disable_unprepare(bp->pclk);
err_out_put_pclk:
clk_put(bp->pclk);
err_out_free_dev:
@@ -1683,9 +1656,9 @@ static int __exit macb_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(bp->regs);
- clk_disable(bp->hclk);
+ clk_disable_unprepare(bp->hclk);
clk_put(bp->hclk);
- clk_disable(bp->pclk);
+ clk_disable_unprepare(bp->pclk);
clk_put(bp->pclk);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
@@ -1703,8 +1676,8 @@ static int macb_suspend(struct platform_device *pdev, pm_message_t state)
netif_carrier_off(netdev);
netif_device_detach(netdev);
- clk_disable(bp->hclk);
- clk_disable(bp->pclk);
+ clk_disable_unprepare(bp->hclk);
+ clk_disable_unprepare(bp->pclk);
return 0;
}
@@ -1714,8 +1687,8 @@ static int macb_resume(struct platform_device *pdev)
struct net_device *netdev = platform_get_drvdata(pdev);
struct macb *bp = netdev_priv(netdev);
- clk_enable(bp->pclk);
- clk_enable(bp->hclk);
+ clk_prepare_enable(bp->pclk);
+ clk_prepare_enable(bp->hclk);
netif_device_attach(netdev);
@@ -1737,18 +1710,7 @@ static struct platform_driver macb_driver = {
},
};
-static int __init macb_init(void)
-{
- return platform_driver_probe(&macb_driver, macb_probe);
-}
-
-static void __exit macb_exit(void)
-{
- platform_driver_unregister(&macb_driver);
-}
-
-module_init(macb_init);
-module_exit(macb_exit);
+module_platform_driver_probe(macb_driver, macb_probe);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 570908b93578..993d70380688 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -173,6 +173,8 @@
/* Bitfields in DMACFG. */
#define GEM_FBLDO_OFFSET 0
#define GEM_FBLDO_SIZE 5
+#define GEM_ENDIA_OFFSET 7
+#define GEM_ENDIA_SIZE 1
#define GEM_RXBMS_OFFSET 8
#define GEM_RXBMS_SIZE 2
#define GEM_TXPBMS_OFFSET 10
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index a170065b5973..4a1f2fa812ab 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -163,6 +163,7 @@
#define XGMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
/* XGMAC_INT_STAT reg */
+#define XGMAC_INT_STAT_PMTIM 0x00800000 /* PMT Interrupt Mask */
#define XGMAC_INT_STAT_PMT 0x0080 /* PMT Interrupt Status */
#define XGMAC_INT_STAT_LPI 0x0040 /* LPI Interrupt Status */
@@ -960,6 +961,9 @@ static int xgmac_hw_init(struct net_device *dev)
writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS);
writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA);
+ /* Mask power mgt interrupt */
+ writel(XGMAC_INT_STAT_PMTIM, ioaddr + XGMAC_INT_STAT);
+
/* XGMAC requires AXI bus init. This is a 'magic number' for now */
writel(0x0077000E, ioaddr + XGMAC_DMA_AXI_BUS);
@@ -1141,6 +1145,9 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit)
struct sk_buff *skb;
int frame_len;
+ if (!dma_ring_cnt(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ))
+ break;
+
entry = priv->rx_tail;
p = priv->dma_rx + entry;
if (desc_get_owner(p))
@@ -1475,7 +1482,7 @@ static int xgmac_set_features(struct net_device *dev, netdev_features_t features
u32 ctrl;
struct xgmac_priv *priv = netdev_priv(dev);
void __iomem *ioaddr = priv->base;
- u32 changed = dev->features ^ features;
+ netdev_features_t changed = dev->features ^ features;
if (!(changed & NETIF_F_RXCSUM))
return 0;
@@ -1825,7 +1832,7 @@ static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode)
unsigned int pmt = 0;
if (mode & WAKE_MAGIC)
- pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT;
+ pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT_EN;
if (mode & WAKE_UCAST)
pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_GLBL_UNICAST;
@@ -1879,12 +1886,9 @@ static int xgmac_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(xgmac_pm_ops, xgmac_suspend, xgmac_resume);
-#define XGMAC_PM_OPS (&xgmac_pm_ops)
-#else
-#define XGMAC_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id xgmac_of_match[] = {
{ .compatible = "calxeda,hb-xgmac", },
@@ -1899,7 +1903,7 @@ static struct platform_driver xgmac_driver = {
},
.probe = xgmac_probe,
.remove = xgmac_remove,
- .driver.pm = XGMAC_PM_OPS,
+ .driver.pm = &xgmac_pm_ops,
};
module_platform_driver(xgmac_driver);
diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index 20d2085f61c5..9624cfe7df57 100644
--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -856,10 +856,10 @@ static netdev_features_t t1_fix_features(struct net_device *dev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -869,7 +869,7 @@ static int t1_set_features(struct net_device *dev, netdev_features_t features)
netdev_features_t changed = dev->features ^ features;
struct adapter *adapter = dev->ml_priv;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
t1_vlan_mode(adapter, features);
return 0;
@@ -1085,8 +1085,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->features |= NETIF_F_HIGHDMA;
if (vlan_tso_capable(adapter)) {
netdev->features |=
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- netdev->hw_features |= NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
/* T204: disable TSO */
if (!(is_T2(adapter)) || bi->port_number != 4) {
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index 482976925154..8061fb0ef7ed 100644
--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -734,7 +734,7 @@ void t1_vlan_mode(struct adapter *adapter, netdev_features_t features)
{
struct sge *sge = adapter->sge;
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
sge->sge_control |= F_VLAN_XTRACT;
else
sge->sge_control &= ~F_VLAN_XTRACT;
@@ -835,7 +835,7 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
struct sk_buff *skb;
dma_addr_t mapping;
- skb = alloc_skb(q->rx_buffer_size, GFP_ATOMIC);
+ skb = dev_alloc_skb(q->rx_buffer_size);
if (!skb)
break;
@@ -1046,11 +1046,10 @@ static inline struct sk_buff *get_packet(struct pci_dev *pdev,
const struct freelQ_ce *ce = &fl->centries[fl->cidx];
if (len < copybreak) {
- skb = alloc_skb(len + 2, GFP_ATOMIC);
+ skb = netdev_alloc_skb_ip_align(NULL, len);
if (!skb)
goto use_orig_buf;
- skb_reserve(skb, 2); /* align IP header */
skb_put(skb, len);
pci_dma_sync_single_for_cpu(pdev,
dma_unmap_addr(ce, dma_addr),
@@ -1387,7 +1386,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
if (p->vlan_valid) {
st->vlan_xtract++;
- __vlan_hwaccel_put_tag(skb, ntohs(p->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(p->vlan));
}
netif_receive_skb(skb);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index 2b5e62193cea..71497e835f42 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -1181,14 +1181,15 @@ static void cxgb_vlan_mode(struct net_device *dev, netdev_features_t features)
if (adapter->params.rev > 0) {
t3_set_vlan_accel(adapter, 1 << pi->port_id,
- features & NETIF_F_HW_VLAN_RX);
+ features & NETIF_F_HW_VLAN_CTAG_RX);
} else {
/* single control for all ports */
- unsigned int i, have_vlans = features & NETIF_F_HW_VLAN_RX;
+ unsigned int i, have_vlans = features & NETIF_F_HW_VLAN_CTAG_RX;
for_each_port(adapter, i)
have_vlans |=
- adapter->port[i]->features & NETIF_F_HW_VLAN_RX;
+ adapter->port[i]->features &
+ NETIF_F_HW_VLAN_CTAG_RX;
t3_set_vlan_accel(adapter, 1, have_vlans);
}
@@ -2563,10 +2564,10 @@ static netdev_features_t cxgb_fix_features(struct net_device *dev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -2575,7 +2576,7 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
{
netdev_features_t changed = dev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
cxgb_vlan_mode(dev, features);
return 0;
@@ -3288,8 +3289,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len - 1;
netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX;
- netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_TX;
+ NETIF_F_TSO | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX;
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_CTAG_TX;
netdev->vlan_features |= netdev->features & VLAN_FEAT;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 4232767862b5..0c96e5fe99cc 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -185,7 +185,7 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter,
if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
rcu_read_lock();
if (vlan && vlan != VLAN_VID_MASK) {
- dev = __vlan_find_dev_deep(dev, vlan);
+ dev = __vlan_find_dev_deep(dev, htons(ETH_P_8021Q), vlan);
} else if (netif_is_bond_slave(dev)) {
struct net_device *upper_dev;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 9d67eb794c4b..f12e6b85a653 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -2030,7 +2030,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
if (p->vlan_valid) {
qs->port_stats[SGE_PSTAT_VLANEX]++;
- __vlan_hwaccel_put_tag(skb, ntohs(p->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(p->vlan));
}
if (rq->polling) {
if (lro)
@@ -2132,7 +2132,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
if (cpl->vlan_valid) {
qs->port_stats[SGE_PSTAT_VLANEX]++;
- __vlan_hwaccel_put_tag(skb, ntohs(cpl->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cpl->vlan));
}
napi_gro_frags(&qs->napi);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 6db997c78a5f..681804b30a3f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -54,6 +54,10 @@
#define FW_VERSION_MINOR 1
#define FW_VERSION_MICRO 0
+#define FW_VERSION_MAJOR_T5 0
+#define FW_VERSION_MINOR_T5 0
+#define FW_VERSION_MICRO_T5 0
+
#define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
enum {
@@ -66,7 +70,9 @@ enum {
enum {
MEM_EDC0,
MEM_EDC1,
- MEM_MC
+ MEM_MC,
+ MEM_MC0 = MEM_MC,
+ MEM_MC1
};
enum {
@@ -74,8 +80,10 @@ enum {
MEMWIN0_BASE = 0x1b800,
MEMWIN1_APERTURE = 32768,
MEMWIN1_BASE = 0x28000,
+ MEMWIN1_BASE_T5 = 0x52000,
MEMWIN2_APERTURE = 65536,
MEMWIN2_BASE = 0x30000,
+ MEMWIN2_BASE_T5 = 0x54000,
};
enum dev_master {
@@ -431,6 +439,7 @@ struct sge_txq {
spinlock_t db_lock;
int db_disabled;
unsigned short db_pidx;
+ u64 udb;
};
struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
@@ -504,13 +513,44 @@ struct sge {
struct l2t_data;
+#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
+#define CHELSIO_CHIP_VERSION(code) ((code) >> 4)
+#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
+
+#define CHELSIO_T4 0x4
+#define CHELSIO_T5 0x5
+
+enum chip_type {
+ T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 0),
+ T4_A2 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
+ T4_A3 = CHELSIO_CHIP_CODE(CHELSIO_T4, 2),
+ T4_FIRST_REV = T4_A1,
+ T4_LAST_REV = T4_A3,
+
+ T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
+ T5_FIRST_REV = T5_A1,
+ T5_LAST_REV = T5_A1,
+};
+
+#ifdef CONFIG_PCI_IOV
+
+/* T4 supports SRIOV on PF0-3 and T5 on PF0-7. However, the Serial
+ * Configuration initialization for T5 only has SR-IOV functionality enabled
+ * on PF0-3 in order to simplify everything.
+ */
+#define NUM_OF_PF_WITH_SRIOV 4
+
+#endif
+
struct adapter {
void __iomem *regs;
+ void __iomem *bar2;
struct pci_dev *pdev;
struct device *pdev_dev;
unsigned int mbox;
unsigned int fn;
unsigned int flags;
+ enum chip_type chip;
int msg_enable;
@@ -673,6 +713,16 @@ enum {
VLAN_REWRITE
};
+static inline int is_t5(enum chip_type chip)
+{
+ return (chip >= T5_FIRST_REV && chip <= T5_LAST_REV);
+}
+
+static inline int is_t4(enum chip_type chip)
+{
+ return (chip >= T4_FIRST_REV && chip <= T4_LAST_REV);
+}
+
static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr)
{
return readl(adap->regs + reg_addr);
@@ -858,7 +908,8 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq);
int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags);
-int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *parity);
+int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
+ u64 *parity);
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index e707e31abd81..c59ec3ddaa66 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -68,8 +68,8 @@
#include "t4fw_api.h"
#include "l2t.h"
-#define DRV_VERSION "1.3.0-ko"
-#define DRV_DESC "Chelsio T4 Network Driver"
+#define DRV_VERSION "2.0.0-ko"
+#define DRV_DESC "Chelsio T4/T5 Network Driver"
/*
* Max interrupt hold-off timer value in us. Queues fall back to this value
@@ -229,11 +229,51 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
CH_DEVICE(0x440a, 4),
CH_DEVICE(0x440d, 4),
CH_DEVICE(0x440e, 4),
+ CH_DEVICE(0x5001, 4),
+ CH_DEVICE(0x5002, 4),
+ CH_DEVICE(0x5003, 4),
+ CH_DEVICE(0x5004, 4),
+ CH_DEVICE(0x5005, 4),
+ CH_DEVICE(0x5006, 4),
+ CH_DEVICE(0x5007, 4),
+ CH_DEVICE(0x5008, 4),
+ CH_DEVICE(0x5009, 4),
+ CH_DEVICE(0x500A, 4),
+ CH_DEVICE(0x500B, 4),
+ CH_DEVICE(0x500C, 4),
+ CH_DEVICE(0x500D, 4),
+ CH_DEVICE(0x500E, 4),
+ CH_DEVICE(0x500F, 4),
+ CH_DEVICE(0x5010, 4),
+ CH_DEVICE(0x5011, 4),
+ CH_DEVICE(0x5012, 4),
+ CH_DEVICE(0x5013, 4),
+ CH_DEVICE(0x5401, 4),
+ CH_DEVICE(0x5402, 4),
+ CH_DEVICE(0x5403, 4),
+ CH_DEVICE(0x5404, 4),
+ CH_DEVICE(0x5405, 4),
+ CH_DEVICE(0x5406, 4),
+ CH_DEVICE(0x5407, 4),
+ CH_DEVICE(0x5408, 4),
+ CH_DEVICE(0x5409, 4),
+ CH_DEVICE(0x540A, 4),
+ CH_DEVICE(0x540B, 4),
+ CH_DEVICE(0x540C, 4),
+ CH_DEVICE(0x540D, 4),
+ CH_DEVICE(0x540E, 4),
+ CH_DEVICE(0x540F, 4),
+ CH_DEVICE(0x5410, 4),
+ CH_DEVICE(0x5411, 4),
+ CH_DEVICE(0x5412, 4),
+ CH_DEVICE(0x5413, 4),
{ 0, }
};
#define FW_FNAME "cxgb4/t4fw.bin"
+#define FW5_FNAME "cxgb4/t5fw.bin"
#define FW_CFNAME "cxgb4/t4-config.txt"
+#define FW5_CFNAME "cxgb4/t5-config.txt"
MODULE_DESCRIPTION(DRV_DESC);
MODULE_AUTHOR("Chelsio Communications");
@@ -241,6 +281,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, cxgb4_pci_tbl);
MODULE_FIRMWARE(FW_FNAME);
+MODULE_FIRMWARE(FW5_FNAME);
/*
* Normally we're willing to become the firmware's Master PF but will be happy
@@ -319,7 +360,10 @@ static bool vf_acls;
module_param(vf_acls, bool, 0644);
MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement");
-static unsigned int num_vf[4];
+/* Configure the number of PCI-E Virtual Function which are to be instantiated
+ * on SR-IOV Capable Physical Functions.
+ */
+static unsigned int num_vf[NUM_OF_PF_WITH_SRIOV];
module_param_array(num_vf, uint, NULL, 0644);
MODULE_PARM_DESC(num_vf, "number of VFs for each of PFs 0-3");
@@ -515,7 +559,7 @@ static int link_start(struct net_device *dev)
* that step explicitly.
*/
ret = t4_set_rxmode(pi->adapter, mb, pi->viid, dev->mtu, -1, -1, -1,
- !!(dev->features & NETIF_F_HW_VLAN_RX), true);
+ !!(dev->features & NETIF_F_HW_VLAN_CTAG_RX), true);
if (ret == 0) {
ret = t4_change_mac(pi->adapter, mb, pi->viid,
pi->xact_addr_filt, dev->dev_addr, true,
@@ -601,6 +645,21 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
u8 opcode = ((const struct rss_header *)rsp)->opcode;
rsp++; /* skip RSS header */
+
+ /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG.
+ */
+ if (unlikely(opcode == CPL_FW4_MSG &&
+ ((const struct cpl_fw4_msg *)rsp)->type == FW_TYPE_RSSCPL)) {
+ rsp++;
+ opcode = ((const struct rss_header *)rsp)->opcode;
+ rsp++;
+ if (opcode != CPL_SGE_EGR_UPDATE) {
+ dev_err(q->adap->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n"
+ , opcode);
+ goto out;
+ }
+ }
+
if (likely(opcode == CPL_SGE_EGR_UPDATE)) {
const struct cpl_sge_egr_update *p = (void *)rsp;
unsigned int qid = EGR_QID(ntohl(p->opcode_qid));
@@ -635,6 +694,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
} else
dev_err(q->adap->pdev_dev,
"unexpected CPL %#x on FW event queue\n", opcode);
+out:
return 0;
}
@@ -652,6 +712,12 @@ static int uldrx_handler(struct sge_rspq *q, const __be64 *rsp,
{
struct sge_ofld_rxq *rxq = container_of(q, struct sge_ofld_rxq, rspq);
+ /* FW can send CPLs encapsulated in a CPL_FW4_MSG.
+ */
+ if (((const struct rss_header *)rsp)->opcode == CPL_FW4_MSG &&
+ ((const struct cpl_fw4_msg *)(rsp + 1))->type == FW_TYPE_RSSCPL)
+ rsp += 2;
+
if (ulds[q->uld].rx_handler(q->adap->uld_handle[q->uld], rsp, gl)) {
rxq->stats.nomem++;
return -1;
@@ -1002,21 +1068,36 @@ freeout: t4_free_sge_resources(adap);
static int upgrade_fw(struct adapter *adap)
{
int ret;
- u32 vers;
+ u32 vers, exp_major;
const struct fw_hdr *hdr;
const struct firmware *fw;
struct device *dev = adap->pdev_dev;
+ char *fw_file_name;
- ret = request_firmware(&fw, FW_FNAME, dev);
+ switch (CHELSIO_CHIP_VERSION(adap->chip)) {
+ case CHELSIO_T4:
+ fw_file_name = FW_FNAME;
+ exp_major = FW_VERSION_MAJOR;
+ break;
+ case CHELSIO_T5:
+ fw_file_name = FW5_FNAME;
+ exp_major = FW_VERSION_MAJOR_T5;
+ break;
+ default:
+ dev_err(dev, "Unsupported chip type, %x\n", adap->chip);
+ return -EINVAL;
+ }
+
+ ret = request_firmware(&fw, fw_file_name, dev);
if (ret < 0) {
- dev_err(dev, "unable to load firmware image " FW_FNAME
- ", error %d\n", ret);
+ dev_err(dev, "unable to load firmware image %s, error %d\n",
+ fw_file_name, ret);
return ret;
}
hdr = (const struct fw_hdr *)fw->data;
vers = ntohl(hdr->fw_ver);
- if (FW_HDR_FW_VER_MAJOR_GET(vers) != FW_VERSION_MAJOR) {
+ if (FW_HDR_FW_VER_MAJOR_GET(vers) != exp_major) {
ret = -EINVAL; /* wrong major version, won't do */
goto out;
}
@@ -1024,18 +1105,15 @@ static int upgrade_fw(struct adapter *adap)
/*
* If the flash FW is unusable or we found something newer, load it.
*/
- if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != FW_VERSION_MAJOR ||
+ if (FW_HDR_FW_VER_MAJOR_GET(adap->params.fw_vers) != exp_major ||
vers > adap->params.fw_vers) {
dev_info(dev, "upgrading firmware ...\n");
ret = t4_fw_upgrade(adap, adap->mbox, fw->data, fw->size,
/*force=*/false);
if (!ret)
- dev_info(dev, "firmware successfully upgraded to "
- FW_FNAME " (%d.%d.%d.%d)\n",
- FW_HDR_FW_VER_MAJOR_GET(vers),
- FW_HDR_FW_VER_MINOR_GET(vers),
- FW_HDR_FW_VER_MICRO_GET(vers),
- FW_HDR_FW_VER_BUILD_GET(vers));
+ dev_info(dev,
+ "firmware upgraded to version %pI4 from %s\n",
+ &hdr->fw_ver, fw_file_name);
else
dev_err(dev, "firmware upgrade failed! err=%d\n", -ret);
} else {
@@ -1308,6 +1386,8 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
"VLANinsertions ",
"GROpackets ",
"GROmerged ",
+ "WriteCoalSuccess ",
+ "WriteCoalFail ",
};
static int get_sset_count(struct net_device *dev, int sset)
@@ -1321,10 +1401,15 @@ static int get_sset_count(struct net_device *dev, int sset)
}
#define T4_REGMAP_SIZE (160 * 1024)
+#define T5_REGMAP_SIZE (332 * 1024)
static int get_regs_len(struct net_device *dev)
{
- return T4_REGMAP_SIZE;
+ struct adapter *adap = netdev2adap(dev);
+ if (is_t4(adap->chip))
+ return T4_REGMAP_SIZE;
+ else
+ return T5_REGMAP_SIZE;
}
static int get_eeprom_len(struct net_device *dev)
@@ -1398,11 +1483,25 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
+ u32 val1, val2;
t4_get_port_stats(adapter, pi->tx_chan, (struct port_stats *)data);
data += sizeof(struct port_stats) / sizeof(u64);
collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
+ data += sizeof(struct queue_port_stats) / sizeof(u64);
+ if (!is_t4(adapter->chip)) {
+ t4_write_reg(adapter, SGE_STAT_CFG, STATSOURCE_T5(7));
+ val1 = t4_read_reg(adapter, SGE_STAT_TOTAL);
+ val2 = t4_read_reg(adapter, SGE_STAT_MATCH);
+ *data = val1 - val2;
+ data++;
+ *data = val2;
+ data++;
+ } else {
+ memset(data, 0, 2 * sizeof(u64));
+ *data += 2;
+ }
}
/*
@@ -1413,7 +1512,8 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
*/
static inline unsigned int mk_adap_vers(const struct adapter *ap)
{
- return 4 | (ap->params.rev << 10) | (1 << 16);
+ return CHELSIO_CHIP_VERSION(ap->chip) |
+ (CHELSIO_CHIP_RELEASE(ap->chip) << 10) | (1 << 16);
}
static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start,
@@ -1428,7 +1528,7 @@ static void reg_block_dump(struct adapter *ap, void *buf, unsigned int start,
static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *buf)
{
- static const unsigned int reg_ranges[] = {
+ static const unsigned int t4_reg_ranges[] = {
0x1008, 0x1108,
0x1180, 0x11b4,
0x11fc, 0x123c,
@@ -1648,13 +1748,452 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
0x27e00, 0x27e04
};
+ static const unsigned int t5_reg_ranges[] = {
+ 0x1008, 0x1148,
+ 0x1180, 0x11b4,
+ 0x11fc, 0x123c,
+ 0x1280, 0x173c,
+ 0x1800, 0x18fc,
+ 0x3000, 0x3028,
+ 0x3060, 0x30d8,
+ 0x30e0, 0x30fc,
+ 0x3140, 0x357c,
+ 0x35a8, 0x35cc,
+ 0x35ec, 0x35ec,
+ 0x3600, 0x5624,
+ 0x56cc, 0x575c,
+ 0x580c, 0x5814,
+ 0x5890, 0x58bc,
+ 0x5940, 0x59dc,
+ 0x59fc, 0x5a18,
+ 0x5a60, 0x5a9c,
+ 0x5b9c, 0x5bfc,
+ 0x6000, 0x6040,
+ 0x6058, 0x614c,
+ 0x7700, 0x7798,
+ 0x77c0, 0x78fc,
+ 0x7b00, 0x7c54,
+ 0x7d00, 0x7efc,
+ 0x8dc0, 0x8de0,
+ 0x8df8, 0x8e84,
+ 0x8ea0, 0x8f84,
+ 0x8fc0, 0x90f8,
+ 0x9400, 0x9470,
+ 0x9600, 0x96f4,
+ 0x9800, 0x9808,
+ 0x9820, 0x983c,
+ 0x9850, 0x9864,
+ 0x9c00, 0x9c6c,
+ 0x9c80, 0x9cec,
+ 0x9d00, 0x9d6c,
+ 0x9d80, 0x9dec,
+ 0x9e00, 0x9e6c,
+ 0x9e80, 0x9eec,
+ 0x9f00, 0x9f6c,
+ 0x9f80, 0xa020,
+ 0xd004, 0xd03c,
+ 0xdfc0, 0xdfe0,
+ 0xe000, 0x11088,
+ 0x1109c, 0x1117c,
+ 0x11190, 0x11204,
+ 0x19040, 0x1906c,
+ 0x19078, 0x19080,
+ 0x1908c, 0x19124,
+ 0x19150, 0x191b0,
+ 0x191d0, 0x191e8,
+ 0x19238, 0x19290,
+ 0x193f8, 0x19474,
+ 0x19490, 0x194cc,
+ 0x194f0, 0x194f8,
+ 0x19c00, 0x19c60,
+ 0x19c94, 0x19e10,
+ 0x19e50, 0x19f34,
+ 0x19f40, 0x19f50,
+ 0x19f90, 0x19fe4,
+ 0x1a000, 0x1a06c,
+ 0x1a0b0, 0x1a120,
+ 0x1a128, 0x1a138,
+ 0x1a190, 0x1a1c4,
+ 0x1a1fc, 0x1a1fc,
+ 0x1e008, 0x1e00c,
+ 0x1e040, 0x1e04c,
+ 0x1e284, 0x1e290,
+ 0x1e2c0, 0x1e2c0,
+ 0x1e2e0, 0x1e2e0,
+ 0x1e300, 0x1e384,
+ 0x1e3c0, 0x1e3c8,
+ 0x1e408, 0x1e40c,
+ 0x1e440, 0x1e44c,
+ 0x1e684, 0x1e690,
+ 0x1e6c0, 0x1e6c0,
+ 0x1e6e0, 0x1e6e0,
+ 0x1e700, 0x1e784,
+ 0x1e7c0, 0x1e7c8,
+ 0x1e808, 0x1e80c,
+ 0x1e840, 0x1e84c,
+ 0x1ea84, 0x1ea90,
+ 0x1eac0, 0x1eac0,
+ 0x1eae0, 0x1eae0,
+ 0x1eb00, 0x1eb84,
+ 0x1ebc0, 0x1ebc8,
+ 0x1ec08, 0x1ec0c,
+ 0x1ec40, 0x1ec4c,
+ 0x1ee84, 0x1ee90,
+ 0x1eec0, 0x1eec0,
+ 0x1eee0, 0x1eee0,
+ 0x1ef00, 0x1ef84,
+ 0x1efc0, 0x1efc8,
+ 0x1f008, 0x1f00c,
+ 0x1f040, 0x1f04c,
+ 0x1f284, 0x1f290,
+ 0x1f2c0, 0x1f2c0,
+ 0x1f2e0, 0x1f2e0,
+ 0x1f300, 0x1f384,
+ 0x1f3c0, 0x1f3c8,
+ 0x1f408, 0x1f40c,
+ 0x1f440, 0x1f44c,
+ 0x1f684, 0x1f690,
+ 0x1f6c0, 0x1f6c0,
+ 0x1f6e0, 0x1f6e0,
+ 0x1f700, 0x1f784,
+ 0x1f7c0, 0x1f7c8,
+ 0x1f808, 0x1f80c,
+ 0x1f840, 0x1f84c,
+ 0x1fa84, 0x1fa90,
+ 0x1fac0, 0x1fac0,
+ 0x1fae0, 0x1fae0,
+ 0x1fb00, 0x1fb84,
+ 0x1fbc0, 0x1fbc8,
+ 0x1fc08, 0x1fc0c,
+ 0x1fc40, 0x1fc4c,
+ 0x1fe84, 0x1fe90,
+ 0x1fec0, 0x1fec0,
+ 0x1fee0, 0x1fee0,
+ 0x1ff00, 0x1ff84,
+ 0x1ffc0, 0x1ffc8,
+ 0x30000, 0x30030,
+ 0x30100, 0x30144,
+ 0x30190, 0x301d0,
+ 0x30200, 0x30318,
+ 0x30400, 0x3052c,
+ 0x30540, 0x3061c,
+ 0x30800, 0x30834,
+ 0x308c0, 0x30908,
+ 0x30910, 0x309ac,
+ 0x30a00, 0x30a04,
+ 0x30a0c, 0x30a2c,
+ 0x30a44, 0x30a50,
+ 0x30a74, 0x30c24,
+ 0x30d08, 0x30d14,
+ 0x30d1c, 0x30d20,
+ 0x30d3c, 0x30d50,
+ 0x31200, 0x3120c,
+ 0x31220, 0x31220,
+ 0x31240, 0x31240,
+ 0x31600, 0x31600,
+ 0x31608, 0x3160c,
+ 0x31a00, 0x31a1c,
+ 0x31e04, 0x31e20,
+ 0x31e38, 0x31e3c,
+ 0x31e80, 0x31e80,
+ 0x31e88, 0x31ea8,
+ 0x31eb0, 0x31eb4,
+ 0x31ec8, 0x31ed4,
+ 0x31fb8, 0x32004,
+ 0x32208, 0x3223c,
+ 0x32600, 0x32630,
+ 0x32a00, 0x32abc,
+ 0x32b00, 0x32b70,
+ 0x33000, 0x33048,
+ 0x33060, 0x3309c,
+ 0x330f0, 0x33148,
+ 0x33160, 0x3319c,
+ 0x331f0, 0x332e4,
+ 0x332f8, 0x333e4,
+ 0x333f8, 0x33448,
+ 0x33460, 0x3349c,
+ 0x334f0, 0x33548,
+ 0x33560, 0x3359c,
+ 0x335f0, 0x336e4,
+ 0x336f8, 0x337e4,
+ 0x337f8, 0x337fc,
+ 0x33814, 0x33814,
+ 0x3382c, 0x3382c,
+ 0x33880, 0x3388c,
+ 0x338e8, 0x338ec,
+ 0x33900, 0x33948,
+ 0x33960, 0x3399c,
+ 0x339f0, 0x33ae4,
+ 0x33af8, 0x33b10,
+ 0x33b28, 0x33b28,
+ 0x33b3c, 0x33b50,
+ 0x33bf0, 0x33c10,
+ 0x33c28, 0x33c28,
+ 0x33c3c, 0x33c50,
+ 0x33cf0, 0x33cfc,
+ 0x34000, 0x34030,
+ 0x34100, 0x34144,
+ 0x34190, 0x341d0,
+ 0x34200, 0x34318,
+ 0x34400, 0x3452c,
+ 0x34540, 0x3461c,
+ 0x34800, 0x34834,
+ 0x348c0, 0x34908,
+ 0x34910, 0x349ac,
+ 0x34a00, 0x34a04,
+ 0x34a0c, 0x34a2c,
+ 0x34a44, 0x34a50,
+ 0x34a74, 0x34c24,
+ 0x34d08, 0x34d14,
+ 0x34d1c, 0x34d20,
+ 0x34d3c, 0x34d50,
+ 0x35200, 0x3520c,
+ 0x35220, 0x35220,
+ 0x35240, 0x35240,
+ 0x35600, 0x35600,
+ 0x35608, 0x3560c,
+ 0x35a00, 0x35a1c,
+ 0x35e04, 0x35e20,
+ 0x35e38, 0x35e3c,
+ 0x35e80, 0x35e80,
+ 0x35e88, 0x35ea8,
+ 0x35eb0, 0x35eb4,
+ 0x35ec8, 0x35ed4,
+ 0x35fb8, 0x36004,
+ 0x36208, 0x3623c,
+ 0x36600, 0x36630,
+ 0x36a00, 0x36abc,
+ 0x36b00, 0x36b70,
+ 0x37000, 0x37048,
+ 0x37060, 0x3709c,
+ 0x370f0, 0x37148,
+ 0x37160, 0x3719c,
+ 0x371f0, 0x372e4,
+ 0x372f8, 0x373e4,
+ 0x373f8, 0x37448,
+ 0x37460, 0x3749c,
+ 0x374f0, 0x37548,
+ 0x37560, 0x3759c,
+ 0x375f0, 0x376e4,
+ 0x376f8, 0x377e4,
+ 0x377f8, 0x377fc,
+ 0x37814, 0x37814,
+ 0x3782c, 0x3782c,
+ 0x37880, 0x3788c,
+ 0x378e8, 0x378ec,
+ 0x37900, 0x37948,
+ 0x37960, 0x3799c,
+ 0x379f0, 0x37ae4,
+ 0x37af8, 0x37b10,
+ 0x37b28, 0x37b28,
+ 0x37b3c, 0x37b50,
+ 0x37bf0, 0x37c10,
+ 0x37c28, 0x37c28,
+ 0x37c3c, 0x37c50,
+ 0x37cf0, 0x37cfc,
+ 0x38000, 0x38030,
+ 0x38100, 0x38144,
+ 0x38190, 0x381d0,
+ 0x38200, 0x38318,
+ 0x38400, 0x3852c,
+ 0x38540, 0x3861c,
+ 0x38800, 0x38834,
+ 0x388c0, 0x38908,
+ 0x38910, 0x389ac,
+ 0x38a00, 0x38a04,
+ 0x38a0c, 0x38a2c,
+ 0x38a44, 0x38a50,
+ 0x38a74, 0x38c24,
+ 0x38d08, 0x38d14,
+ 0x38d1c, 0x38d20,
+ 0x38d3c, 0x38d50,
+ 0x39200, 0x3920c,
+ 0x39220, 0x39220,
+ 0x39240, 0x39240,
+ 0x39600, 0x39600,
+ 0x39608, 0x3960c,
+ 0x39a00, 0x39a1c,
+ 0x39e04, 0x39e20,
+ 0x39e38, 0x39e3c,
+ 0x39e80, 0x39e80,
+ 0x39e88, 0x39ea8,
+ 0x39eb0, 0x39eb4,
+ 0x39ec8, 0x39ed4,
+ 0x39fb8, 0x3a004,
+ 0x3a208, 0x3a23c,
+ 0x3a600, 0x3a630,
+ 0x3aa00, 0x3aabc,
+ 0x3ab00, 0x3ab70,
+ 0x3b000, 0x3b048,
+ 0x3b060, 0x3b09c,
+ 0x3b0f0, 0x3b148,
+ 0x3b160, 0x3b19c,
+ 0x3b1f0, 0x3b2e4,
+ 0x3b2f8, 0x3b3e4,
+ 0x3b3f8, 0x3b448,
+ 0x3b460, 0x3b49c,
+ 0x3b4f0, 0x3b548,
+ 0x3b560, 0x3b59c,
+ 0x3b5f0, 0x3b6e4,
+ 0x3b6f8, 0x3b7e4,
+ 0x3b7f8, 0x3b7fc,
+ 0x3b814, 0x3b814,
+ 0x3b82c, 0x3b82c,
+ 0x3b880, 0x3b88c,
+ 0x3b8e8, 0x3b8ec,
+ 0x3b900, 0x3b948,
+ 0x3b960, 0x3b99c,
+ 0x3b9f0, 0x3bae4,
+ 0x3baf8, 0x3bb10,
+ 0x3bb28, 0x3bb28,
+ 0x3bb3c, 0x3bb50,
+ 0x3bbf0, 0x3bc10,
+ 0x3bc28, 0x3bc28,
+ 0x3bc3c, 0x3bc50,
+ 0x3bcf0, 0x3bcfc,
+ 0x3c000, 0x3c030,
+ 0x3c100, 0x3c144,
+ 0x3c190, 0x3c1d0,
+ 0x3c200, 0x3c318,
+ 0x3c400, 0x3c52c,
+ 0x3c540, 0x3c61c,
+ 0x3c800, 0x3c834,
+ 0x3c8c0, 0x3c908,
+ 0x3c910, 0x3c9ac,
+ 0x3ca00, 0x3ca04,
+ 0x3ca0c, 0x3ca2c,
+ 0x3ca44, 0x3ca50,
+ 0x3ca74, 0x3cc24,
+ 0x3cd08, 0x3cd14,
+ 0x3cd1c, 0x3cd20,
+ 0x3cd3c, 0x3cd50,
+ 0x3d200, 0x3d20c,
+ 0x3d220, 0x3d220,
+ 0x3d240, 0x3d240,
+ 0x3d600, 0x3d600,
+ 0x3d608, 0x3d60c,
+ 0x3da00, 0x3da1c,
+ 0x3de04, 0x3de20,
+ 0x3de38, 0x3de3c,
+ 0x3de80, 0x3de80,
+ 0x3de88, 0x3dea8,
+ 0x3deb0, 0x3deb4,
+ 0x3dec8, 0x3ded4,
+ 0x3dfb8, 0x3e004,
+ 0x3e208, 0x3e23c,
+ 0x3e600, 0x3e630,
+ 0x3ea00, 0x3eabc,
+ 0x3eb00, 0x3eb70,
+ 0x3f000, 0x3f048,
+ 0x3f060, 0x3f09c,
+ 0x3f0f0, 0x3f148,
+ 0x3f160, 0x3f19c,
+ 0x3f1f0, 0x3f2e4,
+ 0x3f2f8, 0x3f3e4,
+ 0x3f3f8, 0x3f448,
+ 0x3f460, 0x3f49c,
+ 0x3f4f0, 0x3f548,
+ 0x3f560, 0x3f59c,
+ 0x3f5f0, 0x3f6e4,
+ 0x3f6f8, 0x3f7e4,
+ 0x3f7f8, 0x3f7fc,
+ 0x3f814, 0x3f814,
+ 0x3f82c, 0x3f82c,
+ 0x3f880, 0x3f88c,
+ 0x3f8e8, 0x3f8ec,
+ 0x3f900, 0x3f948,
+ 0x3f960, 0x3f99c,
+ 0x3f9f0, 0x3fae4,
+ 0x3faf8, 0x3fb10,
+ 0x3fb28, 0x3fb28,
+ 0x3fb3c, 0x3fb50,
+ 0x3fbf0, 0x3fc10,
+ 0x3fc28, 0x3fc28,
+ 0x3fc3c, 0x3fc50,
+ 0x3fcf0, 0x3fcfc,
+ 0x40000, 0x4000c,
+ 0x40040, 0x40068,
+ 0x40080, 0x40144,
+ 0x40180, 0x4018c,
+ 0x40200, 0x40298,
+ 0x402ac, 0x4033c,
+ 0x403f8, 0x403fc,
+ 0x41300, 0x413c4,
+ 0x41400, 0x4141c,
+ 0x41480, 0x414d0,
+ 0x44000, 0x44078,
+ 0x440c0, 0x44278,
+ 0x442c0, 0x44478,
+ 0x444c0, 0x44678,
+ 0x446c0, 0x44878,
+ 0x448c0, 0x449fc,
+ 0x45000, 0x45068,
+ 0x45080, 0x45084,
+ 0x450a0, 0x450b0,
+ 0x45200, 0x45268,
+ 0x45280, 0x45284,
+ 0x452a0, 0x452b0,
+ 0x460c0, 0x460e4,
+ 0x47000, 0x4708c,
+ 0x47200, 0x47250,
+ 0x47400, 0x47420,
+ 0x47600, 0x47618,
+ 0x47800, 0x47814,
+ 0x48000, 0x4800c,
+ 0x48040, 0x48068,
+ 0x48080, 0x48144,
+ 0x48180, 0x4818c,
+ 0x48200, 0x48298,
+ 0x482ac, 0x4833c,
+ 0x483f8, 0x483fc,
+ 0x49300, 0x493c4,
+ 0x49400, 0x4941c,
+ 0x49480, 0x494d0,
+ 0x4c000, 0x4c078,
+ 0x4c0c0, 0x4c278,
+ 0x4c2c0, 0x4c478,
+ 0x4c4c0, 0x4c678,
+ 0x4c6c0, 0x4c878,
+ 0x4c8c0, 0x4c9fc,
+ 0x4d000, 0x4d068,
+ 0x4d080, 0x4d084,
+ 0x4d0a0, 0x4d0b0,
+ 0x4d200, 0x4d268,
+ 0x4d280, 0x4d284,
+ 0x4d2a0, 0x4d2b0,
+ 0x4e0c0, 0x4e0e4,
+ 0x4f000, 0x4f08c,
+ 0x4f200, 0x4f250,
+ 0x4f400, 0x4f420,
+ 0x4f600, 0x4f618,
+ 0x4f800, 0x4f814,
+ 0x50000, 0x500cc,
+ 0x50400, 0x50400,
+ 0x50800, 0x508cc,
+ 0x50c00, 0x50c00,
+ 0x51000, 0x5101c,
+ 0x51300, 0x51308,
+ };
+
int i;
struct adapter *ap = netdev2adap(dev);
+ static const unsigned int *reg_ranges;
+ int arr_size = 0, buf_size = 0;
+
+ if (is_t4(ap->chip)) {
+ reg_ranges = &t4_reg_ranges[0];
+ arr_size = ARRAY_SIZE(t4_reg_ranges);
+ buf_size = T4_REGMAP_SIZE;
+ } else {
+ reg_ranges = &t5_reg_ranges[0];
+ arr_size = ARRAY_SIZE(t5_reg_ranges);
+ buf_size = T5_REGMAP_SIZE;
+ }
regs->version = mk_adap_vers(ap);
- memset(buf, 0, T4_REGMAP_SIZE);
- for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2)
+ memset(buf, 0, buf_size);
+ for (i = 0; i < arr_size; i += 2)
reg_block_dump(ap, buf, reg_ranges[i], reg_ranges[i + 1]);
}
@@ -2205,14 +2744,14 @@ static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
netdev_features_t changed = dev->features ^ features;
int err;
- if (!(changed & NETIF_F_HW_VLAN_RX))
+ if (!(changed & NETIF_F_HW_VLAN_CTAG_RX))
return 0;
err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1,
-1, -1, -1,
- !!(features & NETIF_F_HW_VLAN_RX), true);
+ !!(features & NETIF_F_HW_VLAN_CTAG_RX), true);
if (unlikely(err))
- dev->features = features ^ NETIF_F_HW_VLAN_RX;
+ dev->features = features ^ NETIF_F_HW_VLAN_CTAG_RX;
return err;
}
@@ -2363,8 +2902,8 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
int ret, ofst;
__be32 data[16];
- if (mem == MEM_MC)
- ret = t4_mc_read(adap, pos, data, NULL);
+ if ((mem == MEM_MC) || (mem == MEM_MC1))
+ ret = t4_mc_read(adap, mem % MEM_MC, pos, data, NULL);
else
ret = t4_edc_read(adap, mem, pos, data, NULL);
if (ret)
@@ -2405,18 +2944,37 @@ static void add_debugfs_mem(struct adapter *adap, const char *name,
static int setup_debugfs(struct adapter *adap)
{
int i;
+ u32 size;
if (IS_ERR_OR_NULL(adap->debugfs_root))
return -1;
i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE);
- if (i & EDRAM0_ENABLE)
- add_debugfs_mem(adap, "edc0", MEM_EDC0, 5);
- if (i & EDRAM1_ENABLE)
- add_debugfs_mem(adap, "edc1", MEM_EDC1, 5);
- if (i & EXT_MEM_ENABLE)
- add_debugfs_mem(adap, "mc", MEM_MC,
- EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR)));
+ if (i & EDRAM0_ENABLE) {
+ size = t4_read_reg(adap, MA_EDRAM0_BAR);
+ add_debugfs_mem(adap, "edc0", MEM_EDC0, EDRAM_SIZE_GET(size));
+ }
+ if (i & EDRAM1_ENABLE) {
+ size = t4_read_reg(adap, MA_EDRAM1_BAR);
+ add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM_SIZE_GET(size));
+ }
+ if (is_t4(adap->chip)) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
+ if (i & EXT_MEM_ENABLE)
+ add_debugfs_mem(adap, "mc", MEM_MC,
+ EXT_MEM_SIZE_GET(size));
+ } else {
+ if (i & EXT_MEM_ENABLE) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
+ add_debugfs_mem(adap, "mc0", MEM_MC0,
+ EXT_MEM_SIZE_GET(size));
+ }
+ if (i & EXT_MEM1_ENABLE) {
+ size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR);
+ add_debugfs_mem(adap, "mc1", MEM_MC1,
+ EXT_MEM_SIZE_GET(size));
+ }
+ }
if (adap->l2t)
debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap,
&t4_l2t_fops);
@@ -2747,10 +3305,18 @@ EXPORT_SYMBOL(cxgb4_port_chan);
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
{
struct adapter *adap = netdev2adap(dev);
- u32 v;
+ u32 v1, v2, lp_count, hp_count;
- v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
- return lpfifo ? G_LP_COUNT(v) : G_HP_COUNT(v);
+ v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
+ v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2);
+ if (is_t4(adap->chip)) {
+ lp_count = G_LP_COUNT(v1);
+ hp_count = G_HP_COUNT(v1);
+ } else {
+ lp_count = G_LP_COUNT_T5(v1);
+ hp_count = G_HP_COUNT_T5(v2);
+ }
+ return lpfifo ? lp_count : hp_count;
}
EXPORT_SYMBOL(cxgb4_dbfifo_count);
@@ -2853,6 +3419,25 @@ out:
}
EXPORT_SYMBOL(cxgb4_sync_txq_pidx);
+void cxgb4_disable_db_coalescing(struct net_device *dev)
+{
+ struct adapter *adap;
+
+ adap = netdev2adap(dev);
+ t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE,
+ F_NOCOALESCE);
+}
+EXPORT_SYMBOL(cxgb4_disable_db_coalescing);
+
+void cxgb4_enable_db_coalescing(struct net_device *dev)
+{
+ struct adapter *adap;
+
+ adap = netdev2adap(dev);
+ t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, 0);
+}
+EXPORT_SYMBOL(cxgb4_enable_db_coalescing);
+
static struct pci_driver cxgb4_driver;
static void check_neigh_update(struct neighbour *neigh)
@@ -2888,14 +3473,23 @@ static struct notifier_block cxgb4_netevent_nb = {
static void drain_db_fifo(struct adapter *adap, int usecs)
{
- u32 v;
+ u32 v1, v2, lp_count, hp_count;
do {
+ v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
+ v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2);
+ if (is_t4(adap->chip)) {
+ lp_count = G_LP_COUNT(v1);
+ hp_count = G_HP_COUNT(v1);
+ } else {
+ lp_count = G_LP_COUNT_T5(v1);
+ hp_count = G_HP_COUNT_T5(v2);
+ }
+
+ if (lp_count == 0 && hp_count == 0)
+ break;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(usecs));
- v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
- if (G_LP_COUNT(v) == 0 && G_HP_COUNT(v) == 0)
- break;
} while (1);
}
@@ -3004,24 +3598,62 @@ static void process_db_drop(struct work_struct *work)
adap = container_of(work, struct adapter, db_drop_task);
+ if (is_t4(adap->chip)) {
+ disable_dbs(adap);
+ notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
+ drain_db_fifo(adap, 1);
+ recover_all_queues(adap);
+ enable_dbs(adap);
+ } else {
+ u32 dropped_db = t4_read_reg(adap, 0x010ac);
+ u16 qid = (dropped_db >> 15) & 0x1ffff;
+ u16 pidx_inc = dropped_db & 0x1fff;
+ unsigned int s_qpp;
+ unsigned short udb_density;
+ unsigned long qpshift;
+ int page;
+ u32 udb;
+
+ dev_warn(adap->pdev_dev,
+ "Dropped DB 0x%x qid %d bar2 %d coalesce %d pidx %d\n",
+ dropped_db, qid,
+ (dropped_db >> 14) & 1,
+ (dropped_db >> 13) & 1,
+ pidx_inc);
+
+ drain_db_fifo(adap, 1);
+
+ s_qpp = QUEUESPERPAGEPF1 * adap->fn;
+ udb_density = 1 << QUEUESPERPAGEPF0_GET(t4_read_reg(adap,
+ SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp);
+ qpshift = PAGE_SHIFT - ilog2(udb_density);
+ udb = qid << qpshift;
+ udb &= PAGE_MASK;
+ page = udb / PAGE_SIZE;
+ udb += (qid - (page * udb_density)) * 128;
+
+ writel(PIDX(pidx_inc), adap->bar2 + udb + 8);
+
+ /* Re-enable BAR2 WC */
+ t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15);
+ }
+
t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0);
- disable_dbs(adap);
- notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
- drain_db_fifo(adap, 1);
- recover_all_queues(adap);
- enable_dbs(adap);
}
void t4_db_full(struct adapter *adap)
{
- t4_set_reg_field(adap, SGE_INT_ENABLE3,
- DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
- queue_work(workq, &adap->db_full_task);
+ if (is_t4(adap->chip)) {
+ t4_set_reg_field(adap, SGE_INT_ENABLE3,
+ DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
+ queue_work(workq, &adap->db_full_task);
+ }
}
void t4_db_dropped(struct adapter *adap)
{
- queue_work(workq, &adap->db_drop_task);
+ if (is_t4(adap->chip))
+ queue_work(workq, &adap->db_drop_task);
}
static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -3566,17 +4198,27 @@ void t4_fatal_err(struct adapter *adap)
static void setup_memwin(struct adapter *adap)
{
- u32 bar0;
+ u32 bar0, mem_win0_base, mem_win1_base, mem_win2_base;
bar0 = pci_resource_start(adap->pdev, 0); /* truncation intentional */
+ if (is_t4(adap->chip)) {
+ mem_win0_base = bar0 + MEMWIN0_BASE;
+ mem_win1_base = bar0 + MEMWIN1_BASE;
+ mem_win2_base = bar0 + MEMWIN2_BASE;
+ } else {
+ /* For T5, only relative offset inside the PCIe BAR is passed */
+ mem_win0_base = MEMWIN0_BASE;
+ mem_win1_base = MEMWIN1_BASE_T5;
+ mem_win2_base = MEMWIN2_BASE_T5;
+ }
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0),
- (bar0 + MEMWIN0_BASE) | BIR(0) |
+ mem_win0_base | BIR(0) |
WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1),
- (bar0 + MEMWIN1_BASE) | BIR(0) |
+ mem_win1_base | BIR(0) |
WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
- (bar0 + MEMWIN2_BASE) | BIR(0) |
+ mem_win2_base | BIR(0) |
WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
}
@@ -3745,6 +4387,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
unsigned long mtype = 0, maddr = 0;
u32 finiver, finicsum, cfcsum;
int ret, using_flash;
+ char *fw_config_file, fw_config_file_path[256];
/*
* Reset device if necessary.
@@ -3761,7 +4404,21 @@ static int adap_init0_config(struct adapter *adapter, int reset)
* then use that. Otherwise, use the configuration file stored
* in the adapter flash ...
*/
- ret = request_firmware(&cf, FW_CFNAME, adapter->pdev_dev);
+ switch (CHELSIO_CHIP_VERSION(adapter->chip)) {
+ case CHELSIO_T4:
+ fw_config_file = FW_CFNAME;
+ break;
+ case CHELSIO_T5:
+ fw_config_file = FW5_CFNAME;
+ break;
+ default:
+ dev_err(adapter->pdev_dev, "Device %d is not supported\n",
+ adapter->pdev->device);
+ ret = -EINVAL;
+ goto bye;
+ }
+
+ ret = request_firmware(&cf, fw_config_file, adapter->pdev_dev);
if (ret < 0) {
using_flash = 1;
mtype = FW_MEMTYPE_CF_FLASH;
@@ -3877,6 +4534,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
if (ret < 0)
goto bye;
+ sprintf(fw_config_file_path, "/lib/firmware/%s", fw_config_file);
/*
* Return successfully and note that we're operating with parameters
* not supplied by the driver, rather than from hard-wired
@@ -3887,7 +4545,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
"Configuration File %s, version %#x, computed checksum %#x\n",
(using_flash
? "in device FLASH"
- : "/lib/firmware/" FW_CFNAME),
+ : fw_config_file_path),
finiver, cfcsum);
return 0;
@@ -4354,6 +5012,15 @@ static int adap_init0(struct adapter *adap)
adap->tids.aftid_end = val[1];
}
+ /* If we're running on newer firmware, let it know that we're
+ * prepared to deal with encapsulated CPL messages. Older
+ * firmware won't understand this and we'll just get
+ * unencapsulated messages ...
+ */
+ params[0] = FW_PARAM_PFVF(CPLFW4MSG_ENCAP);
+ val[0] = 1;
+ (void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val);
+
/*
* Get device capabilities so we can determine what resources we need
* to manage.
@@ -4814,7 +5481,8 @@ static void print_port_info(const struct net_device *dev)
sprintf(bufp, "BASE-%s", base[pi->port_type]);
netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
- adap->params.vpd.id, adap->params.rev, buf,
+ adap->params.vpd.id,
+ CHELSIO_CHIP_RELEASE(adap->params.rev), buf,
is_offload(adap) ? "R" : "", adap->params.pci.width, spd,
(adap->flags & USING_MSIX) ? " MSI-X" :
(adap->flags & USING_MSI) ? " MSI" : "");
@@ -4854,10 +5522,11 @@ static void free_some_resources(struct adapter *adapter)
#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
+#define SEGMENT_SIZE 128
static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int func, i, err;
+ int func, i, err, s_qpp, qpp, num_seg;
struct port_info *pi;
bool highdma = false;
struct adapter *adapter = NULL;
@@ -4934,7 +5603,34 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = t4_prep_adapter(adapter);
if (err)
- goto out_unmap_bar;
+ goto out_unmap_bar0;
+
+ if (!is_t4(adapter->chip)) {
+ s_qpp = QUEUESPERPAGEPF1 * adapter->fn;
+ qpp = 1 << QUEUESPERPAGEPF0_GET(t4_read_reg(adapter,
+ SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp);
+ num_seg = PAGE_SIZE / SEGMENT_SIZE;
+
+ /* Each segment size is 128B. Write coalescing is enabled only
+ * when SGE_EGRESS_QUEUES_PER_PAGE_PF reg value for the
+ * queue is less no of segments that can be accommodated in
+ * a page size.
+ */
+ if (qpp > num_seg) {
+ dev_err(&pdev->dev,
+ "Incorrect number of egress queues per page\n");
+ err = -EINVAL;
+ goto out_unmap_bar0;
+ }
+ adapter->bar2 = ioremap_wc(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ if (!adapter->bar2) {
+ dev_err(&pdev->dev, "cannot map device bar2 region\n");
+ err = -ENOMEM;
+ goto out_unmap_bar0;
+ }
+ }
+
setup_memwin(adapter);
err = adap_init0(adapter);
setup_memwin_rdma(adapter);
@@ -4963,7 +5659,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features = NETIF_F_SG | TSO_FLAGS |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM | NETIF_F_RXHASH |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
if (highdma)
netdev->hw_features |= NETIF_F_HIGHDMA;
netdev->features |= netdev->hw_features;
@@ -5063,6 +5759,9 @@ sriov:
out_free_dev:
free_some_resources(adapter);
out_unmap_bar:
+ if (!is_t4(adapter->chip))
+ iounmap(adapter->bar2);
+ out_unmap_bar0:
iounmap(adapter->regs);
out_free_adapter:
kfree(adapter);
@@ -5113,6 +5812,8 @@ static void remove_one(struct pci_dev *pdev)
free_some_resources(adapter);
iounmap(adapter->regs);
+ if (!is_t4(adapter->chip))
+ iounmap(adapter->bar2);
kfree(adapter);
pci_disable_pcie_error_reporting(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index e2bbc7f3e2de..4faf4d067ee7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -269,4 +269,7 @@ struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len, unsigned int pull_len);
int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size);
int cxgb4_flush_eq_cache(struct net_device *dev);
+void cxgb4_disable_db_coalescing(struct net_device *dev);
+void cxgb4_enable_db_coalescing(struct net_device *dev);
+
#endif /* !__CXGB4_OFLD_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index fe9a2ea3588b..2bfbb206b35a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -506,10 +506,14 @@ static void unmap_rx_buf(struct adapter *adap, struct sge_fl *q)
static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
{
+ u32 val;
if (q->pend_cred >= 8) {
+ val = PIDX(q->pend_cred / 8);
+ if (!is_t4(adap->chip))
+ val |= DBTYPE(1);
wmb();
t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL), DBPRIO(1) |
- QID(q->cntxt_id) | PIDX(q->pend_cred / 8));
+ QID(q->cntxt_id) | val);
q->pend_cred &= 7;
}
}
@@ -812,6 +816,22 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
*end = 0;
}
+/* This function copies 64 byte coalesced work request to
+ * memory mapped BAR2 space(user space writes).
+ * For coalesced WR SGE, fetches data from the FIFO instead of from Host.
+ */
+static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
+{
+ int count = 8;
+
+ while (count) {
+ writeq(*src, dst);
+ src++;
+ dst++;
+ count--;
+ }
+}
+
/**
* ring_tx_db - check and potentially ring a Tx queue's doorbell
* @adap: the adapter
@@ -822,11 +842,25 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
*/
static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
{
+ unsigned int *wr, index;
+
wmb(); /* write descriptors before telling HW */
spin_lock(&q->db_lock);
if (!q->db_disabled) {
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(q->cntxt_id) | PIDX(n));
+ if (is_t4(adap->chip)) {
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
+ QID(q->cntxt_id) | PIDX(n));
+ } else {
+ if (n == 1) {
+ index = q->pidx ? (q->pidx - 1) : (q->size - 1);
+ wr = (unsigned int *)&q->desc[index];
+ cxgb_pio_copy((u64 __iomem *)
+ (adap->bar2 + q->udb + 64),
+ (u64 *)wr);
+ } else
+ writel(n, adap->bar2 + q->udb + 8);
+ wmb();
+ }
}
q->db_pidx = q->pidx;
spin_unlock(&q->db_lock);
@@ -1555,7 +1589,6 @@ static noinline int handle_trace_pkt(struct adapter *adap,
const struct pkt_gl *gl)
{
struct sk_buff *skb;
- struct cpl_trace_pkt *p;
skb = cxgb4_pktgl_to_skb(gl, RX_PULL_LEN, RX_PULL_LEN);
if (unlikely(!skb)) {
@@ -1563,8 +1596,11 @@ static noinline int handle_trace_pkt(struct adapter *adap,
return 0;
}
- p = (struct cpl_trace_pkt *)skb->data;
- __skb_pull(skb, sizeof(*p));
+ if (is_t4(adap->chip))
+ __skb_pull(skb, sizeof(struct cpl_trace_pkt));
+ else
+ __skb_pull(skb, sizeof(struct cpl_t5_trace_pkt));
+
skb_reset_mac_header(skb);
skb->protocol = htons(0xffff);
skb->dev = adap->port[0];
@@ -1597,7 +1633,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
skb->rxhash = (__force u32)pkt->rsshdr.hash_val;
if (unlikely(pkt->vlan_ex)) {
- __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan));
rxq->stats.vlan_ex++;
}
ret = napi_gro_frags(&rxq->rspq.napi);
@@ -1625,8 +1661,10 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
const struct cpl_rx_pkt *pkt;
struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq);
struct sge *s = &q->adap->sge;
+ int cpl_trace_pkt = is_t4(q->adap->chip) ?
+ CPL_TRACE_PKT : CPL_TRACE_PKT_T5;
- if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT))
+ if (unlikely(*(u8 *)rsp == cpl_trace_pkt))
return handle_trace_pkt(q->adap, si);
pkt = (const struct cpl_rx_pkt *)rsp;
@@ -1667,7 +1705,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
skb_checksum_none_assert(skb);
if (unlikely(pkt->vlan_ex)) {
- __vlan_hwaccel_put_tag(skb, ntohs(pkt->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan));
rxq->stats.vlan_ex++;
}
netif_receive_skb(skb);
@@ -2143,11 +2181,27 @@ err:
static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id)
{
+ q->cntxt_id = id;
+ if (!is_t4(adap->chip)) {
+ unsigned int s_qpp;
+ unsigned short udb_density;
+ unsigned long qpshift;
+ int page;
+
+ s_qpp = QUEUESPERPAGEPF1 * adap->fn;
+ udb_density = 1 << QUEUESPERPAGEPF0_GET((t4_read_reg(adap,
+ SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp));
+ qpshift = PAGE_SHIFT - ilog2(udb_density);
+ q->udb = q->cntxt_id << qpshift;
+ q->udb &= PAGE_MASK;
+ page = q->udb / PAGE_SIZE;
+ q->udb += (q->cntxt_id - (page * udb_density)) * 128;
+ }
+
q->in_use = 0;
q->cidx = q->pidx = 0;
q->stops = q->restarts = 0;
q->stat = (void *)&q->desc[q->size];
- q->cntxt_id = id;
spin_lock_init(&q->db_lock);
adap->sge.egr_map[id - adap->sge.egr_start] = q;
}
@@ -2587,11 +2641,20 @@ static int t4_sge_init_hard(struct adapter *adap)
* Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
* and generate an interrupt when this occurs so we can recover.
*/
- t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
- V_HP_INT_THRESH(M_HP_INT_THRESH) |
- V_LP_INT_THRESH(M_LP_INT_THRESH),
- V_HP_INT_THRESH(dbfifo_int_thresh) |
- V_LP_INT_THRESH(dbfifo_int_thresh));
+ if (is_t4(adap->chip)) {
+ t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
+ V_HP_INT_THRESH(M_HP_INT_THRESH) |
+ V_LP_INT_THRESH(M_LP_INT_THRESH),
+ V_HP_INT_THRESH(dbfifo_int_thresh) |
+ V_LP_INT_THRESH(dbfifo_int_thresh));
+ } else {
+ t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
+ V_LP_INT_THRESH_T5(M_LP_INT_THRESH_T5),
+ V_LP_INT_THRESH_T5(dbfifo_int_thresh));
+ t4_set_reg_field(adap, SGE_DBFIFO_STATUS2,
+ V_HP_INT_THRESH_T5(M_HP_INT_THRESH_T5),
+ V_HP_INT_THRESH_T5(dbfifo_int_thresh));
+ }
t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP,
F_ENABLE_DROP);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 8049268ce0f2..d02d4e8c4417 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -282,6 +282,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
* t4_mc_read - read from MC through backdoor accesses
* @adap: the adapter
* @addr: address of first byte requested
+ * @idx: which MC to access
* @data: 64 bytes of data containing the requested address
* @ecc: where to store the corresponding 64-bit ECC word
*
@@ -289,22 +290,38 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
* that covers the requested address @addr. If @parity is not %NULL it
* is assigned the 64-bit ECC word for the read data.
*/
-int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc)
+int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
{
int i;
+ u32 mc_bist_cmd, mc_bist_cmd_addr, mc_bist_cmd_len;
+ u32 mc_bist_status_rdata, mc_bist_data_pattern;
+
+ if (is_t4(adap->chip)) {
+ mc_bist_cmd = MC_BIST_CMD;
+ mc_bist_cmd_addr = MC_BIST_CMD_ADDR;
+ mc_bist_cmd_len = MC_BIST_CMD_LEN;
+ mc_bist_status_rdata = MC_BIST_STATUS_RDATA;
+ mc_bist_data_pattern = MC_BIST_DATA_PATTERN;
+ } else {
+ mc_bist_cmd = MC_REG(MC_P_BIST_CMD, idx);
+ mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR, idx);
+ mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN, idx);
+ mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA, idx);
+ mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN, idx);
+ }
- if (t4_read_reg(adap, MC_BIST_CMD) & START_BIST)
+ if (t4_read_reg(adap, mc_bist_cmd) & START_BIST)
return -EBUSY;
- t4_write_reg(adap, MC_BIST_CMD_ADDR, addr & ~0x3fU);
- t4_write_reg(adap, MC_BIST_CMD_LEN, 64);
- t4_write_reg(adap, MC_BIST_DATA_PATTERN, 0xc);
- t4_write_reg(adap, MC_BIST_CMD, BIST_OPCODE(1) | START_BIST |
+ t4_write_reg(adap, mc_bist_cmd_addr, addr & ~0x3fU);
+ t4_write_reg(adap, mc_bist_cmd_len, 64);
+ t4_write_reg(adap, mc_bist_data_pattern, 0xc);
+ t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE(1) | START_BIST |
BIST_CMD_GAP(1));
- i = t4_wait_op_done(adap, MC_BIST_CMD, START_BIST, 0, 10, 1);
+ i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST, 0, 10, 1);
if (i)
return i;
-#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+#define MC_DATA(i) MC_BIST_STATUS_REG(mc_bist_status_rdata, i)
for (i = 15; i >= 0; i--)
*data++ = htonl(t4_read_reg(adap, MC_DATA(i)));
@@ -329,20 +346,39 @@ int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc)
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
{
int i;
+ u32 edc_bist_cmd, edc_bist_cmd_addr, edc_bist_cmd_len;
+ u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata;
+
+ if (is_t4(adap->chip)) {
+ edc_bist_cmd = EDC_REG(EDC_BIST_CMD, idx);
+ edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR, idx);
+ edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN, idx);
+ edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN,
+ idx);
+ edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA,
+ idx);
+ } else {
+ edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD, idx);
+ edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx);
+ edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx);
+ edc_bist_cmd_data_pattern =
+ EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx);
+ edc_bist_status_rdata =
+ EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx);
+ }
- idx *= EDC_STRIDE;
- if (t4_read_reg(adap, EDC_BIST_CMD + idx) & START_BIST)
+ if (t4_read_reg(adap, edc_bist_cmd) & START_BIST)
return -EBUSY;
- t4_write_reg(adap, EDC_BIST_CMD_ADDR + idx, addr & ~0x3fU);
- t4_write_reg(adap, EDC_BIST_CMD_LEN + idx, 64);
- t4_write_reg(adap, EDC_BIST_DATA_PATTERN + idx, 0xc);
- t4_write_reg(adap, EDC_BIST_CMD + idx,
+ t4_write_reg(adap, edc_bist_cmd_addr, addr & ~0x3fU);
+ t4_write_reg(adap, edc_bist_cmd_len, 64);
+ t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc);
+ t4_write_reg(adap, edc_bist_cmd,
BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST);
- i = t4_wait_op_done(adap, EDC_BIST_CMD + idx, START_BIST, 0, 10, 1);
+ i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST, 0, 10, 1);
if (i)
return i;
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(edc_bist_status_rdata, i))
for (i = 15; i >= 0; i--)
*data++ = htonl(t4_read_reg(adap, EDC_DATA(i)));
@@ -366,6 +402,7 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
{
int i;
+ u32 win_pf = is_t4(adap->chip) ? 0 : V_PFNUM(adap->fn);
/*
* Setup offset into PCIE memory window. Address must be a
@@ -374,7 +411,7 @@ static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
* values.)
*/
t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
- addr & ~(MEMWIN0_APERTURE - 1));
+ (addr & ~(MEMWIN0_APERTURE - 1)) | win_pf);
t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
/* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
@@ -410,6 +447,7 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
__be32 *buf, int dir)
{
u32 pos, start, end, offset, memoffset;
+ u32 edc_size, mc_size;
int ret = 0;
__be32 *data;
@@ -423,13 +461,21 @@ static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
if (!data)
return -ENOMEM;
- /*
- * Offset into the region of memory which is being accessed
+ /* Offset into the region of memory which is being accessed
* MEM_EDC0 = 0
* MEM_EDC1 = 1
- * MEM_MC = 2
+ * MEM_MC = 2 -- T4
+ * MEM_MC0 = 2 -- For T5
+ * MEM_MC1 = 3 -- For T5
*/
- memoffset = (mtype * (5 * 1024 * 1024));
+ edc_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR));
+ if (mtype != MEM_MC1)
+ memoffset = (mtype * (edc_size * 1024 * 1024));
+ else {
+ mc_size = EXT_MEM_SIZE_GET(t4_read_reg(adap,
+ MA_EXT_MEMORY_BAR));
+ memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+ }
/* Determine the PCIE_MEM_ACCESS_OFFSET */
addr = addr + memoffset;
@@ -497,9 +543,9 @@ int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
}
#define EEPROM_STAT_ADDR 0x7bfc
-#define VPD_LEN 512
#define VPD_BASE 0x400
#define VPD_BASE_OLD 0
+#define VPD_LEN 1024
/**
* t4_seeprom_wp - enable/disable EEPROM write protection
@@ -856,6 +902,7 @@ int t4_check_fw_version(struct adapter *adapter)
{
u32 api_vers[2];
int ret, major, minor, micro;
+ int exp_major, exp_minor, exp_micro;
ret = get_fw_version(adapter, &adapter->params.fw_vers);
if (!ret)
@@ -870,17 +917,35 @@ int t4_check_fw_version(struct adapter *adapter)
major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers);
minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers);
micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers);
+
+ switch (CHELSIO_CHIP_VERSION(adapter->chip)) {
+ case CHELSIO_T4:
+ exp_major = FW_VERSION_MAJOR;
+ exp_minor = FW_VERSION_MINOR;
+ exp_micro = FW_VERSION_MICRO;
+ break;
+ case CHELSIO_T5:
+ exp_major = FW_VERSION_MAJOR_T5;
+ exp_minor = FW_VERSION_MINOR_T5;
+ exp_micro = FW_VERSION_MICRO_T5;
+ break;
+ default:
+ dev_err(adapter->pdev_dev, "Unsupported chip type, %x\n",
+ adapter->chip);
+ return -EINVAL;
+ }
+
memcpy(adapter->params.api_vers, api_vers,
sizeof(adapter->params.api_vers));
- if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */
+ if (major != exp_major) { /* major mismatch - fail */
dev_err(adapter->pdev_dev,
"card FW has major version %u, driver wants %u\n",
- major, FW_VERSION_MAJOR);
+ major, exp_major);
return -EINVAL;
}
- if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO)
+ if (minor == exp_minor && micro == exp_micro)
return 0; /* perfect match */
/* Minor/micro version mismatch. Report it but often it's OK. */
@@ -1246,6 +1311,45 @@ static void pcie_intr_handler(struct adapter *adapter)
{ 0 }
};
+ static struct intr_info t5_pcie_intr_info[] = {
+ { MSTGRPPERR, "Master Response Read Queue parity error",
+ -1, 1 },
+ { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
+ { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
+ { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
+ -1, 1 },
+ { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
+ -1, 1 },
+ { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
+ { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
+ { DREQWRPERR, "PCI DMA channel write request parity error",
+ -1, 1 },
+ { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
+ { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR, "PCI FID parity error", -1, 1 },
+ { VFIDPERR, "PCI INTx clear parity error", -1, 1 },
+ { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
+ { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
+ { IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
+ -1, 1 },
+ { IPRXDATAGRPPERR, "PCI IP Rx data group parity error", -1, 1 },
+ { RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
+ { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
+ { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
+ { READRSPERR, "Outbound read error", -1, 0 },
+ { 0 }
+ };
+
int fat;
fat = t4_handle_intr_status(adapter,
@@ -1254,7 +1358,10 @@ static void pcie_intr_handler(struct adapter *adapter)
t4_handle_intr_status(adapter,
PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
pcie_port_intr_info) +
- t4_handle_intr_status(adapter, PCIE_INT_CAUSE, pcie_intr_info);
+ t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
+ is_t4(adapter->chip) ?
+ pcie_intr_info : t5_pcie_intr_info);
+
if (fat)
t4_fatal_err(adapter);
}
@@ -1664,7 +1771,14 @@ static void ncsi_intr_handler(struct adapter *adap)
*/
static void xgmac_intr_handler(struct adapter *adap, int port)
{
- u32 v = t4_read_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
+ u32 v, int_cause_reg;
+
+ if (is_t4(adap->chip))
+ int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE);
+ else
+ int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE);
+
+ v = t4_read_reg(adap, int_cause_reg);
v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
if (!v)
@@ -2126,7 +2240,9 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
u32 bgmap = get_mps_bg_map(adap, idx);
#define GET_STAT(name) \
- t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_##name##_L))
+ t4_read_reg64(adap, \
+ (is_t4(adap->chip) ? PORT_REG(idx, MPS_PORT_STAT_##name##_L) : \
+ T5_PORT_REG(idx, MPS_PORT_STAT_##name##_L)))
#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L)
p->tx_octets = GET_STAT(TX_PORT_BYTES);
@@ -2205,14 +2321,26 @@ void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
const u8 *addr)
{
+ u32 mag_id_reg_l, mag_id_reg_h, port_cfg_reg;
+
+ if (is_t4(adap->chip)) {
+ mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO);
+ mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI);
+ port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2);
+ } else {
+ mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO);
+ mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI);
+ port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2);
+ }
+
if (addr) {
- t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO),
+ t4_write_reg(adap, mag_id_reg_l,
(addr[2] << 24) | (addr[3] << 16) |
(addr[4] << 8) | addr[5]);
- t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI),
+ t4_write_reg(adap, mag_id_reg_h,
(addr[0] << 8) | addr[1]);
}
- t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), MAGICEN,
+ t4_set_reg_field(adap, port_cfg_reg, MAGICEN,
addr ? MAGICEN : 0);
}
@@ -2235,16 +2363,23 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
u64 mask0, u64 mask1, unsigned int crc, bool enable)
{
int i;
+ u32 port_cfg_reg;
+
+ if (is_t4(adap->chip))
+ port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2);
+ else
+ port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2);
if (!enable) {
- t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2),
- PATEN, 0);
+ t4_set_reg_field(adap, port_cfg_reg, PATEN, 0);
return 0;
}
if (map > 0xff)
return -EINVAL;
-#define EPIO_REG(name) PORT_REG(port, XGMAC_PORT_EPIO_##name)
+#define EPIO_REG(name) \
+ (is_t4(adap->chip) ? PORT_REG(port, XGMAC_PORT_EPIO_##name) : \
+ T5_PORT_REG(port, MAC_PORT_EPIO_##name))
t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
t4_write_reg(adap, EPIO_REG(DATA2), mask1);
@@ -2322,24 +2457,24 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
* @addr: address of first byte requested aligned on 32b.
* @data: len bytes to hold the data read
* @len: amount of data to read from window. Must be <=
- * MEMWIN0_APERATURE after adjusting for 16B alignment
- * requirements of the the memory window.
+ * MEMWIN0_APERATURE after adjusting for 16B for T4 and
+ * 128B for T5 alignment requirements of the the memory window.
*
* Read len bytes of data from MC starting at @addr.
*/
int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len)
{
- int i;
- int off;
+ int i, off;
+ u32 win_pf = is_t4(adap->chip) ? 0 : V_PFNUM(adap->fn);
- /*
- * Align on a 16B boundary.
+ /* Align on a 2KB boundary.
*/
- off = addr & 15;
+ off = addr & MEMWIN0_APERTURE;
if ((addr & 3) || (len + off) > MEMWIN0_APERTURE)
return -EINVAL;
- t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET, addr & ~15);
+ t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
+ (addr & ~MEMWIN0_APERTURE) | win_pf);
t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
for (i = 0; i < len; i += 4)
@@ -3162,6 +3297,9 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
int i, ret;
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p;
+ unsigned int max_naddr = is_t4(adap->chip) ?
+ NUM_MPS_CLS_SRAM_L_INSTANCES :
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
if (naddr > 7)
return -EINVAL;
@@ -3187,8 +3325,8 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
u16 index = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx));
if (idx)
- idx[i] = index >= NEXACT_MAC ? 0xffff : index;
- if (index < NEXACT_MAC)
+ idx[i] = index >= max_naddr ? 0xffff : index;
+ if (index < max_naddr)
ret++;
else if (hash)
*hash |= (1ULL << hash_mac_addr(addr[i]));
@@ -3221,6 +3359,9 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
int ret, mode;
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p = c.u.exact;
+ unsigned int max_mac_addr = is_t4(adap->chip) ?
+ NUM_MPS_CLS_SRAM_L_INSTANCES :
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
if (idx < 0) /* new allocation */
idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
@@ -3238,7 +3379,7 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0) {
ret = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx));
- if (ret >= NEXACT_MAC)
+ if (ret >= max_mac_addr)
ret = -ENOMEM;
}
return ret;
@@ -3547,7 +3688,8 @@ static int get_flash_params(struct adapter *adap)
*/
int t4_prep_adapter(struct adapter *adapter)
{
- int ret;
+ int ret, ver;
+ uint16_t device_id;
ret = t4_wait_dev_ready(adapter);
if (ret < 0)
@@ -3562,6 +3704,28 @@ int t4_prep_adapter(struct adapter *adapter)
return ret;
}
+ /* Retrieve adapter's device ID
+ */
+ pci_read_config_word(adapter->pdev, PCI_DEVICE_ID, &device_id);
+ ver = device_id >> 12;
+ switch (ver) {
+ case CHELSIO_T4:
+ adapter->chip = CHELSIO_CHIP_CODE(CHELSIO_T4,
+ adapter->params.rev);
+ break;
+ case CHELSIO_T5:
+ adapter->chip = CHELSIO_CHIP_CODE(CHELSIO_T5,
+ adapter->params.rev);
+ break;
+ default:
+ dev_err(adapter->pdev_dev, "Device %d is not supported\n",
+ device_id);
+ return -EINVAL;
+ }
+
+ /* Reassign the updated revision field */
+ adapter->params.rev = adapter->chip;
+
init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
/*
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index f534ed7e10e9..1d1623be9f1e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -47,7 +47,6 @@ enum {
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
- NEXACT_MAC = 336, /* # of exact MAC address filters */
L2T_SIZE = 4096, /* # of L2T entries */
MBOX_LEN = 64, /* mailbox size in bytes */
TRACE_LEN = 112, /* length of trace data and mask */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 261d17703adc..01d484441200 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -74,6 +74,7 @@ enum {
CPL_PASS_ESTABLISH = 0x41,
CPL_RX_DATA_DDP = 0x42,
CPL_PASS_ACCEPT_REQ = 0x44,
+ CPL_TRACE_PKT_T5 = 0x48,
CPL_RDMA_READ_REQ = 0x60,
@@ -157,6 +158,7 @@ union opcode_tid {
};
#define CPL_OPCODE(x) ((x) << 24)
+#define G_CPL_OPCODE(x) (((x) >> 24) & 0xFF)
#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid))
#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF)
@@ -287,6 +289,23 @@ struct cpl_act_open_req {
__be32 opt2;
};
+#define S_FILTER_TUPLE 24
+#define M_FILTER_TUPLE 0xFFFFFFFFFF
+#define V_FILTER_TUPLE(x) ((x) << S_FILTER_TUPLE)
+#define G_FILTER_TUPLE(x) (((x) >> S_FILTER_TUPLE) & M_FILTER_TUPLE)
+struct cpl_t5_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;
+};
+
struct cpl_act_open_req6 {
WR_HDR;
union opcode_tid ot;
@@ -566,6 +585,11 @@ struct cpl_rx_pkt {
#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN)
#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN)
+#define S_RX_T5_ETHHDR_LEN 0
+#define M_RX_T5_ETHHDR_LEN 0x3F
+#define V_RX_T5_ETHHDR_LEN(x) ((x) << S_RX_T5_ETHHDR_LEN)
+#define G_RX_T5_ETHHDR_LEN(x) (((x) >> S_RX_T5_ETHHDR_LEN) & M_RX_T5_ETHHDR_LEN)
+
#define S_RX_MACIDX 8
#define M_RX_MACIDX 0x1FF
#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX)
@@ -612,6 +636,28 @@ struct cpl_trace_pkt {
__be64 tstamp;
};
+struct cpl_t5_trace_pkt {
+ __u8 opcode;
+ __u8 intf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 runt:4;
+ __u8 filter_hit:4;
+ __u8:6;
+ __u8 err:1;
+ __u8 trunc:1;
+#else
+ __u8 filter_hit:4;
+ __u8 runt:4;
+ __u8 trunc:1;
+ __u8 err:1;
+ __u8:6;
+#endif
+ __be16 rsvd;
+ __be16 len;
+ __be64 tstamp;
+ __be64 rsvd1;
+};
+
struct cpl_l2t_write_req {
WR_HDR;
union opcode_tid ot;
@@ -643,6 +689,15 @@ struct cpl_sge_egr_update {
__be16 pidx;
};
+/* cpl_fw*.type values */
+enum {
+ FW_TYPE_CMD_RPL = 0,
+ FW_TYPE_WR_RPL = 1,
+ FW_TYPE_CQE = 2,
+ FW_TYPE_OFLD_CONNECTION_WR_RPL = 3,
+ FW_TYPE_RSSCPL = 4,
+};
+
struct cpl_fw4_pld {
u8 opcode;
u8 rsvd0[3];
@@ -692,6 +747,7 @@ enum {
FW6_TYPE_WR_RPL = 1,
FW6_TYPE_CQE = 2,
FW6_TYPE_OFLD_CONNECTION_WR_RPL = 3,
+ FW6_TYPE_RSSCPL = FW_TYPE_RSSCPL,
};
struct cpl_fw6_msg_ofld_connection_wr_rpl {
@@ -742,4 +798,12 @@ struct ulp_mem_io {
#define ULP_MEMIO_LOCK(x) ((x) << 31)
};
+#define S_T5_ULP_MEMIO_IMM 23
+#define V_T5_ULP_MEMIO_IMM(x) ((x) << S_T5_ULP_MEMIO_IMM)
+#define F_T5_ULP_MEMIO_IMM V_T5_ULP_MEMIO_IMM(1U)
+
+#define S_T5_ULP_MEMIO_ORDER 22
+#define V_T5_ULP_MEMIO_ORDER(x) ((x) << S_T5_ULP_MEMIO_ORDER)
+#define F_T5_ULP_MEMIO_ORDER V_T5_ULP_MEMIO_ORDER(1U)
+
#endif /* __T4_MSG_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 83ec5f7844ac..ef146c0ba481 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -68,9 +68,14 @@
#define QID_SHIFT 15
#define QID(x) ((x) << QID_SHIFT)
#define DBPRIO(x) ((x) << 14)
+#define DBTYPE(x) ((x) << 13)
#define PIDX_MASK 0x00003fffU
#define PIDX_SHIFT 0
#define PIDX(x) ((x) << PIDX_SHIFT)
+#define S_PIDX_T5 0
+#define M_PIDX_T5 0x1fffU
+#define PIDX_T5(x) (((x) >> S_PIDX_T5) & M_PIDX_T5)
+
#define SGE_PF_GTS 0x4
#define INGRESSQID_MASK 0xffff0000U
@@ -152,6 +157,8 @@
#define QUEUESPERPAGEPF0_MASK 0x0000000fU
#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK)
+#define QUEUESPERPAGEPF1 4
+
#define SGE_INT_CAUSE1 0x1024
#define SGE_INT_CAUSE2 0x1030
#define SGE_INT_CAUSE3 0x103c
@@ -234,6 +241,10 @@
#define SGE_DOORBELL_CONTROL 0x10a8
#define ENABLE_DROP (1 << 13)
+#define S_NOCOALESCE 26
+#define V_NOCOALESCE(x) ((x) << S_NOCOALESCE)
+#define F_NOCOALESCE V_NOCOALESCE(1U)
+
#define SGE_TIMER_VALUE_0_AND_1 0x10b8
#define TIMERVALUE0_MASK 0xffff0000U
#define TIMERVALUE0_SHIFT 16
@@ -272,17 +283,36 @@
#define S_HP_INT_THRESH 28
#define M_HP_INT_THRESH 0xfU
#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH)
+#define S_LP_INT_THRESH_T5 18
+#define V_LP_INT_THRESH_T5(x) ((x) << S_LP_INT_THRESH_T5)
+#define M_LP_COUNT_T5 0x3ffffU
+#define G_LP_COUNT_T5(x) (((x) >> S_LP_COUNT) & M_LP_COUNT_T5)
#define M_HP_COUNT 0x7ffU
#define S_HP_COUNT 16
#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT)
#define S_LP_INT_THRESH 12
#define M_LP_INT_THRESH 0xfU
+#define M_LP_INT_THRESH_T5 0xfffU
#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH)
#define M_LP_COUNT 0x7ffU
#define S_LP_COUNT 0
#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT)
#define A_SGE_DBFIFO_STATUS 0x10a4
+#define SGE_STAT_TOTAL 0x10e4
+#define SGE_STAT_MATCH 0x10e8
+
+#define SGE_STAT_CFG 0x10ec
+#define S_STATSOURCE_T5 9
+#define STATSOURCE_T5(x) ((x) << S_STATSOURCE_T5)
+
+#define SGE_DBFIFO_STATUS2 0x1118
+#define M_HP_COUNT_T5 0x3ffU
+#define G_HP_COUNT_T5(x) ((x) & M_HP_COUNT_T5)
+#define S_HP_INT_THRESH_T5 10
+#define M_HP_INT_THRESH_T5 0xfU
+#define V_HP_INT_THRESH_T5(x) ((x) << S_HP_INT_THRESH_T5)
+
#define S_ENABLE_DROP 13
#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP)
#define F_ENABLE_DROP V_ENABLE_DROP(1U)
@@ -331,8 +361,27 @@
#define MSIADDRHPERR 0x00000002U
#define MSIADDRLPERR 0x00000001U
+#define READRSPERR 0x20000000U
+#define TRGT1GRPPERR 0x10000000U
+#define IPSOTPERR 0x08000000U
+#define IPRXDATAGRPPERR 0x02000000U
+#define IPRXHDRGRPPERR 0x01000000U
+#define MAGRPPERR 0x00400000U
+#define VFIDPERR 0x00200000U
+#define HREQWRPERR 0x00010000U
+#define DREQWRPERR 0x00002000U
+#define MSTTAGQPERR 0x00000400U
+#define PIOREQGRPPERR 0x00000100U
+#define PIOCPLGRPPERR 0x00000080U
+#define MSIXSTIPERR 0x00000004U
+#define MSTTIMEOUTPERR 0x00000002U
+#define MSTGRPPERR 0x00000001U
+
#define PCIE_NONFAT_ERR 0x3010
#define PCIE_MEM_ACCESS_BASE_WIN 0x3068
+#define S_PCIEOFST 10
+#define M_PCIEOFST 0x3fffffU
+#define GET_PCIEOFST(x) (((x) >> S_PCIEOFST) & M_PCIEOFST)
#define PCIEOFST_MASK 0xfffffc00U
#define BIR_MASK 0x00000300U
#define BIR_SHIFT 8
@@ -342,6 +391,9 @@
#define WINDOW(x) ((x) << WINDOW_SHIFT)
#define PCIE_MEM_ACCESS_OFFSET 0x306c
+#define S_PFNUM 0
+#define V_PFNUM(x) ((x) << S_PFNUM)
+
#define PCIE_FW 0x30b8
#define PCIE_FW_ERR 0x80000000U
#define PCIE_FW_INIT 0x40000000U
@@ -407,12 +459,18 @@
#define MC_BIST_STATUS_RDATA 0x7688
+#define MA_EDRAM0_BAR 0x77c0
+#define MA_EDRAM1_BAR 0x77c4
+#define EDRAM_SIZE_MASK 0xfffU
+#define EDRAM_SIZE_GET(x) ((x) & EDRAM_SIZE_MASK)
+
#define MA_EXT_MEMORY_BAR 0x77c8
#define EXT_MEM_SIZE_MASK 0x00000fffU
#define EXT_MEM_SIZE_SHIFT 0
#define EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT)
#define MA_TARGET_MEM_ENABLE 0x77d8
+#define EXT_MEM1_ENABLE 0x00000010U
#define EXT_MEM_ENABLE 0x00000004U
#define EDRAM1_ENABLE 0x00000002U
#define EDRAM0_ENABLE 0x00000001U
@@ -431,6 +489,7 @@
#define MA_PCIE_FW 0x30b8
#define MA_PARITY_ERROR_STATUS 0x77f4
+#define MA_EXT_MEMORY1_BAR 0x7808
#define EDC_0_BASE_ADDR 0x7900
#define EDC_BIST_CMD 0x7904
@@ -801,6 +860,15 @@
#define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c
#define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610
#define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614
+#define MAC_PORT_CFG2 0x818
+#define MAC_PORT_MAGIC_MACID_LO 0x824
+#define MAC_PORT_MAGIC_MACID_HI 0x828
+#define MAC_PORT_EPIO_DATA0 0x8c0
+#define MAC_PORT_EPIO_DATA1 0x8c4
+#define MAC_PORT_EPIO_DATA2 0x8c8
+#define MAC_PORT_EPIO_DATA3 0x8cc
+#define MAC_PORT_EPIO_OP 0x8d0
+
#define MPS_CMN_CTL 0x9000
#define NUMPORTS_MASK 0x00000003U
#define NUMPORTS_SHIFT 0
@@ -1063,6 +1131,7 @@
#define ADDRESS_SHIFT 0
#define ADDRESS(x) ((x) << ADDRESS_SHIFT)
+#define MAC_PORT_INT_CAUSE 0x8dc
#define XGMAC_PORT_INT_CAUSE 0x10dc
#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28
@@ -1101,4 +1170,33 @@
#define V_PORT(x) ((x) << S_PORT)
#define F_PORT V_PORT(1U)
+#define NUM_MPS_CLS_SRAM_L_INSTANCES 336
+#define NUM_MPS_T5_CLS_SRAM_L_INSTANCES 512
+
+#define T5_PORT0_BASE 0x30000
+#define T5_PORT_STRIDE 0x4000
+#define T5_PORT_BASE(idx) (T5_PORT0_BASE + (idx) * T5_PORT_STRIDE)
+#define T5_PORT_REG(idx, reg) (T5_PORT_BASE(idx) + (reg))
+
+#define MC_0_BASE_ADDR 0x40000
+#define MC_1_BASE_ADDR 0x48000
+#define MC_STRIDE (MC_1_BASE_ADDR - MC_0_BASE_ADDR)
+#define MC_REG(reg, idx) (reg + MC_STRIDE * idx)
+
+#define MC_P_BIST_CMD 0x41400
+#define MC_P_BIST_CMD_ADDR 0x41404
+#define MC_P_BIST_CMD_LEN 0x41408
+#define MC_P_BIST_DATA_PATTERN 0x4140c
+#define MC_P_BIST_STATUS_RDATA 0x41488
+#define EDC_T50_BASE_ADDR 0x50000
+#define EDC_H_BIST_CMD 0x50004
+#define EDC_H_BIST_CMD_ADDR 0x50008
+#define EDC_H_BIST_CMD_LEN 0x5000c
+#define EDC_H_BIST_DATA_PATTERN 0x50010
+#define EDC_H_BIST_STATUS_RDATA 0x50028
+
+#define EDC_T51_BASE_ADDR 0x50800
+#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
+#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
+
#endif /* __T4_REGS_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index a0dcccd846c9..d1c755f78aaf 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -574,7 +574,7 @@ struct fw_eth_tx_pkt_vm_wr {
__be16 vlantci;
};
-#define FW_CMD_MAX_TIMEOUT 3000
+#define FW_CMD_MAX_TIMEOUT 10000
/*
* If a host driver does a HELLO and discovers that there's already a MASTER
@@ -973,7 +973,9 @@ enum fw_params_param_pfvf {
FW_PARAMS_PARAM_PFVF_EQ_START = 0x2B,
FW_PARAMS_PARAM_PFVF_EQ_END = 0x2C,
FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_START = 0x2D,
- FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_END = 0x2E
+ FW_PARAMS_PARAM_PFVF_ACTIVE_FILTER_END = 0x2E,
+ FW_PARAMS_PARAM_PFVF_ETHOFLD_END = 0x30,
+ FW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP = 0x31
};
/*
@@ -1758,6 +1760,25 @@ enum fw_port_module_type {
FW_PORT_MOD_TYPE_NONE = FW_PORT_CMD_MODTYPE_MASK
};
+enum fw_port_mod_sub_type {
+ FW_PORT_MOD_SUB_TYPE_NA,
+ FW_PORT_MOD_SUB_TYPE_MV88E114X = 0x1,
+ FW_PORT_MOD_SUB_TYPE_TN8022 = 0x2,
+ FW_PORT_MOD_SUB_TYPE_AQ1202 = 0x3,
+ FW_PORT_MOD_SUB_TYPE_88x3120 = 0x4,
+ FW_PORT_MOD_SUB_TYPE_BCM84834 = 0x5,
+ FW_PORT_MOD_SUB_TYPE_BT_VSC8634 = 0x8,
+
+ /* The following will never been in the VPD. They are TWINAX cable
+ * lengths decoded from SFP+ module i2c PROMs. These should
+ * almost certainly go somewhere else ...
+ */
+ FW_PORT_MOD_SUB_TYPE_TWINAX_1 = 0x9,
+ FW_PORT_MOD_SUB_TYPE_TWINAX_3 = 0xA,
+ FW_PORT_MOD_SUB_TYPE_TWINAX_5 = 0xB,
+ FW_PORT_MOD_SUB_TYPE_TWINAX_7 = 0xC,
+};
+
/* port stats */
#define FW_NUM_PORT_STATS 50
#define FW_NUM_PORT_TX_STATS 23
@@ -2123,11 +2144,11 @@ struct fw_hdr {
u8 intfver_ri;
u8 intfver_iscsipdu;
u8 intfver_iscsi;
+ u8 intfver_fcoepdu;
u8 intfver_fcoe;
- u8 reserved2;
+ __u32 reserved2;
__u32 reserved3;
__u32 reserved4;
- __u32 reserved5;
__be32 flags;
__be32 reserved6[23];
};
@@ -2137,6 +2158,17 @@ struct fw_hdr {
#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
+enum fw_hdr_intfver {
+ FW_HDR_INTFVER_NIC = 0x00,
+ FW_HDR_INTFVER_VNIC = 0x00,
+ FW_HDR_INTFVER_OFLD = 0x00,
+ FW_HDR_INTFVER_RI = 0x00,
+ FW_HDR_INTFVER_ISCSIPDU = 0x00,
+ FW_HDR_INTFVER_ISCSI = 0x00,
+ FW_HDR_INTFVER_FCOEPDU = 0x00,
+ FW_HDR_INTFVER_FCOE = 0x00,
+};
+
enum fw_hdr_flags {
FW_HDR_FLAGS_RESET_HALT = 0x00000001,
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
index 68eaa9c88c7d..be5c7ef6ca93 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
@@ -344,6 +344,7 @@ struct adapter {
unsigned long registered_device_map;
unsigned long open_device_map;
unsigned long flags;
+ enum chip_type chip;
struct adapter_params params;
/* queue and interrupt resources */
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index 56b46ab2d4c5..40c22e7de15c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -54,8 +54,8 @@
/*
* Generic information about the driver.
*/
-#define DRV_VERSION "1.0.0"
-#define DRV_DESC "Chelsio T4 Virtual Function (VF) Network Driver"
+#define DRV_VERSION "2.0.0-ko"
+#define DRV_DESC "Chelsio T4/T5 Virtual Function (VF) Network Driver"
/*
* Module Parameters.
@@ -409,6 +409,20 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
break;
}
+ case CPL_FW4_MSG: {
+ /* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG.
+ */
+ const struct cpl_sge_egr_update *p = (void *)(rsp + 3);
+ opcode = G_CPL_OPCODE(ntohl(p->opcode_qid));
+ if (opcode != CPL_SGE_EGR_UPDATE) {
+ dev_err(adapter->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n"
+ , opcode);
+ break;
+ }
+ cpl = (void *)p;
+ /*FALLTHROUGH*/
+ }
+
case CPL_SGE_EGR_UPDATE: {
/*
* We've received an Egress Queue Status Update message. We
@@ -1050,7 +1064,7 @@ static inline unsigned int mk_adap_vers(const struct adapter *adapter)
/*
* Chip version 4, revision 0x3f (cxgb4vf).
*/
- return 4 | (0x3f << 10);
+ return CHELSIO_CHIP_VERSION(adapter->chip) | (0x3f << 10);
}
/*
@@ -1100,10 +1114,10 @@ static netdev_features_t cxgb4vf_fix_features(struct net_device *dev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -1114,9 +1128,9 @@ static int cxgb4vf_set_features(struct net_device *dev,
struct port_info *pi = netdev_priv(dev);
netdev_features_t changed = dev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1,
- features & NETIF_F_HW_VLAN_TX, 0);
+ features & NETIF_F_HW_VLAN_CTAG_TX, 0);
return 0;
}
@@ -2072,6 +2086,7 @@ static int adap_init0(struct adapter *adapter)
struct sge *s = &adapter->sge;
unsigned int ethqsets;
int err;
+ u32 param, val = 0;
/*
* Wait for the device to become ready before proceeding ...
@@ -2099,6 +2114,15 @@ static int adap_init0(struct adapter *adapter)
return err;
}
+ switch (adapter->pdev->device >> 12) {
+ case CHELSIO_T4:
+ adapter->chip = CHELSIO_CHIP_CODE(CHELSIO_T4, 0);
+ break;
+ case CHELSIO_T5:
+ adapter->chip = CHELSIO_CHIP_CODE(CHELSIO_T5, 0);
+ break;
+ }
+
/*
* Grab basic operational parameters. These will predominantly have
* been set up by the Physical Function Driver or will be hard coded
@@ -2144,6 +2168,16 @@ static int adap_init0(struct adapter *adapter)
return err;
}
+ /* If we're running on newer firmware, let it know that we're
+ * prepared to deal with encapsulated CPL messages. Older
+ * firmware won't understand this and we'll just get
+ * unencapsulated messages ...
+ */
+ param = FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) |
+ FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP);
+ val = 1;
+ (void) t4vf_set_params(adapter, 1, &param, &val);
+
/*
* Retrieve our RX interrupt holdoff timer values and counter
* threshold values from the SGE parameters.
@@ -2614,11 +2648,12 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
netdev->hw_features = NETIF_F_SG | TSO_FLAGS |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM;
netdev->vlan_features = NETIF_F_SG | TSO_FLAGS |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HIGHDMA;
- netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_TX;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_CTAG_TX;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
@@ -2888,6 +2923,26 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
CH_DEVICE(0x480a, 0), /* T404-bt */
CH_DEVICE(0x480d, 0), /* T480-cr */
CH_DEVICE(0x480e, 0), /* T440-lp-cr */
+ CH_DEVICE(0x5800, 0), /* T580-dbg */
+ CH_DEVICE(0x5801, 0), /* T520-cr */
+ CH_DEVICE(0x5802, 0), /* T522-cr */
+ CH_DEVICE(0x5803, 0), /* T540-cr */
+ CH_DEVICE(0x5804, 0), /* T520-bch */
+ CH_DEVICE(0x5805, 0), /* T540-bch */
+ CH_DEVICE(0x5806, 0), /* T540-ch */
+ CH_DEVICE(0x5807, 0), /* T520-so */
+ CH_DEVICE(0x5808, 0), /* T520-cx */
+ CH_DEVICE(0x5809, 0), /* T520-bt */
+ CH_DEVICE(0x580a, 0), /* T504-bt */
+ CH_DEVICE(0x580b, 0), /* T520-sr */
+ CH_DEVICE(0x580c, 0), /* T504-bt */
+ CH_DEVICE(0x580d, 0), /* T580-cr */
+ CH_DEVICE(0x580e, 0), /* T540-lp-cr */
+ CH_DEVICE(0x580f, 0), /* Amsterdam */
+ CH_DEVICE(0x5810, 0), /* T580-lp-cr */
+ CH_DEVICE(0x5811, 0), /* T520-lp-cr */
+ CH_DEVICE(0x5812, 0), /* T560-cr */
+ CH_DEVICE(0x5813, 0), /* T580-cr */
{ 0, }
};
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index 9488032d6d2d..df296af20bd5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -528,17 +528,21 @@ static void unmap_rx_buf(struct adapter *adapter, struct sge_fl *fl)
*/
static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
{
+ u32 val;
+
/*
* The SGE keeps track of its Producer and Consumer Indices in terms
* of Egress Queue Units so we can only tell it about integral numbers
* of multiples of Free List Entries per Egress Queue Units ...
*/
if (fl->pend_cred >= FL_PER_EQ_UNIT) {
+ val = PIDX(fl->pend_cred / FL_PER_EQ_UNIT);
+ if (!is_t4(adapter->chip))
+ val |= DBTYPE(1);
wmb();
t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
DBPRIO(1) |
- QID(fl->cntxt_id) |
- PIDX(fl->pend_cred / FL_PER_EQ_UNIT));
+ QID(fl->cntxt_id) | val);
fl->pend_cred %= FL_PER_EQ_UNIT;
}
}
@@ -1478,7 +1482,8 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
skb_record_rx_queue(skb, rxq->rspq.idx);
if (pkt->vlan_ex) {
- __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan));
+ __vlan_hwaccel_put_tag(skb, cpu_to_be16(ETH_P_8021Q),
+ be16_to_cpu(pkt->vlan));
rxq->stats.vlan_ex++;
}
ret = napi_gro_frags(&rxq->rspq.napi);
@@ -1547,7 +1552,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
if (pkt->vlan_ex) {
rxq->stats.vlan_ex++;
- __vlan_hwaccel_put_tag(skb, be16_to_cpu(pkt->vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(pkt->vlan));
}
netif_receive_skb(skb);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
index 283f9d0d37fd..53cbfed21d0b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
@@ -38,6 +38,25 @@
#include "../cxgb4/t4fw_api.h"
+#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
+#define CHELSIO_CHIP_VERSION(code) ((code) >> 4)
+#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
+
+#define CHELSIO_T4 0x4
+#define CHELSIO_T5 0x5
+
+enum chip_type {
+ T4_A1 = CHELSIO_CHIP_CODE(CHELSIO_T4, 0),
+ T4_A2 = CHELSIO_CHIP_CODE(CHELSIO_T4, 1),
+ T4_A3 = CHELSIO_CHIP_CODE(CHELSIO_T4, 2),
+ T4_FIRST_REV = T4_A1,
+ T4_LAST_REV = T4_A3,
+
+ T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
+ T5_FIRST_REV = T5_A1,
+ T5_LAST_REV = T5_A1,
+};
+
/*
* The "len16" field of a Firmware Command Structure ...
*/
@@ -232,6 +251,11 @@ static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
return t4vf_wr_mbox_core(adapter, cmd, size, rpl, false);
}
+static inline int is_t4(enum chip_type chip)
+{
+ return (chip >= T4_FIRST_REV && chip <= T4_LAST_REV);
+}
+
int t4vf_wait_dev_ready(struct adapter *);
int t4vf_port_init(struct adapter *, int);
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
index 7127c7b9efde..9f96dc3bb112 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
@@ -1027,8 +1027,11 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
unsigned nfilters = 0;
unsigned int rem = naddr;
struct fw_vi_mac_cmd cmd, rpl;
+ unsigned int max_naddr = is_t4(adapter->chip) ?
+ NUM_MPS_CLS_SRAM_L_INSTANCES :
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
- if (naddr > FW_CLS_TCAM_NUM_ENTRIES)
+ if (naddr > max_naddr)
return -EINVAL;
for (offset = 0; offset < naddr; /**/) {
@@ -1069,10 +1072,10 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
if (idx)
idx[offset+i] =
- (index >= FW_CLS_TCAM_NUM_ENTRIES
+ (index >= max_naddr
? 0xffff
: index);
- if (index < FW_CLS_TCAM_NUM_ENTRIES)
+ if (index < max_naddr)
nfilters++;
else if (hash)
*hash |= (1ULL << hash_mac_addr(addr[offset+i]));
@@ -1118,6 +1121,9 @@ int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
struct fw_vi_mac_exact *p = &cmd.u.exact[0];
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[1]), 16);
+ unsigned int max_naddr = is_t4(adapter->chip) ?
+ NUM_MPS_CLS_SRAM_L_INSTANCES :
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
/*
* If this is a new allocation, determine whether it should be
@@ -1140,7 +1146,7 @@ int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
if (ret == 0) {
p = &rpl.u.exact[0];
ret = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
- if (ret >= FW_CLS_TCAM_NUM_ENTRIES)
+ if (ret >= max_naddr)
ret = -ENOMEM;
}
return ret;
diff --git a/drivers/net/ethernet/cirrus/cs89x0.c b/drivers/net/ethernet/cirrus/cs89x0.c
index 138446957786..19f642a45f40 100644
--- a/drivers/net/ethernet/cirrus/cs89x0.c
+++ b/drivers/net/ethernet/cirrus/cs89x0.c
@@ -101,23 +101,6 @@ static char version[] __initdata =
* them to system IRQ numbers. This mapping is card specific and is set to
* the configuration of the Cirrus Eval board for this chip.
*/
-#if defined(CONFIG_MACH_IXDP2351)
-#define CS89x0_NONISA_IRQ
-static unsigned int netcard_portlist[] __used __initdata = {
- IXDP2351_VIRT_CS8900_BASE, 0
-};
-static unsigned int cs8900_irq_map[] = {
- IRQ_IXDP2351_CS8900, 0, 0, 0
-};
-#elif defined(CONFIG_ARCH_IXDP2X01)
-#define CS89x0_NONISA_IRQ
-static unsigned int netcard_portlist[] __used __initdata = {
- IXDP2X01_CS8900_VIRT_BASE, 0
-};
-static unsigned int cs8900_irq_map[] = {
- IRQ_IXDP2X01_CS8900, 0, 0, 0
-};
-#else
#ifndef CONFIG_CS89x0_PLATFORM
static unsigned int netcard_portlist[] __used __initdata = {
0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240,
@@ -127,7 +110,6 @@ static unsigned int cs8900_irq_map[] = {
10, 11, 12, 5
};
#endif
-#endif
#if DEBUGGING
static unsigned int net_debug = DEBUGGING;
@@ -210,32 +192,6 @@ static int __init media_fn(char *str)
__setup("cs89x0_media=", media_fn);
#endif
-#if defined(CONFIG_MACH_IXDP2351)
-static u16
-readword(unsigned long base_addr, int portno)
-{
- return __raw_readw(base_addr + (portno << 1));
-}
-
-static void
-writeword(unsigned long base_addr, int portno, u16 value)
-{
- __raw_writew(value, base_addr + (portno << 1));
-}
-#elif defined(CONFIG_ARCH_IXDP2X01)
-static u16
-readword(unsigned long base_addr, int portno)
-{
- return __raw_readl(base_addr + (portno << 1));
-}
-
-static void
-writeword(unsigned long base_addr, int portno, u16 value)
-{
- __raw_writel(value, base_addr + (portno << 1));
-}
-#endif
-
static void readwords(struct net_local *lp, int portno, void *buf, int length)
{
u8 *buf8 = (u8 *)buf;
@@ -478,9 +434,6 @@ dma_rx(struct net_device *dev)
/* Malloc up new buffer. */
skb = netdev_alloc_skb(dev, length + 2);
if (skb == NULL) {
- /* I don't think we want to do this to a stressed system */
- cs89_dbg(0, err, "%s: Memory squeeze, dropping packet\n",
- dev->name);
dev->stats.rx_dropped++;
/* AKPM: advance bp to the next frame */
@@ -731,9 +684,6 @@ net_rx(struct net_device *dev)
/* Malloc up new buffer. */
skb = netdev_alloc_skb(dev, length + 2);
if (skb == NULL) {
-#if 0 /* Again, this seems a cruel thing to do */
- pr_warn("%s: Memory squeeze, dropping packet\n", dev->name);
-#endif
dev->stats.rx_dropped++;
return;
}
@@ -908,7 +858,7 @@ net_open(struct net_device *dev)
goto bad_out;
}
} else {
-#if !defined(CS89x0_NONISA_IRQ) && !defined(CONFIG_CS89x0_PLATFORM)
+#if !defined(CONFIG_CS89x0_PLATFORM)
if (((1 << dev->irq) & lp->irq_map) == 0) {
pr_err("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
dev->name, dev->irq, lp->irq_map);
@@ -1321,9 +1271,7 @@ static const struct net_device_ops net_ops = {
static void __init reset_chip(struct net_device *dev)
{
#if !defined(CONFIG_MACH_MX31ADS)
-#if !defined(CS89x0_NONISA_IRQ)
struct net_local *lp = netdev_priv(dev);
-#endif /* CS89x0_NONISA_IRQ */
int reset_start_time;
writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
@@ -1331,7 +1279,6 @@ static void __init reset_chip(struct net_device *dev)
/* wait 30 ms */
msleep(30);
-#if !defined(CS89x0_NONISA_IRQ)
if (lp->chip_type != CS8900) {
/* Hardware problem requires PNP registers to be reconfigured after a reset */
iowrite16(PP_CS8920_ISAINT, lp->virt_addr + ADD_PORT);
@@ -1344,7 +1291,6 @@ static void __init reset_chip(struct net_device *dev)
iowrite8((dev->mem_start >> 8) & 0xff,
lp->virt_addr + DATA_PORT + 1);
}
-#endif /* CS89x0_NONISA_IRQ */
/* Wait until the chip is reset */
reset_start_time = jiffies;
@@ -1579,9 +1525,6 @@ cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
i = lp->isa_config & INT_NO_MASK;
#ifndef CONFIG_CS89x0_PLATFORM
if (lp->chip_type == CS8900) {
-#ifdef CS89x0_NONISA_IRQ
- i = cs8900_irq_map[0];
-#else
/* Translate the IRQ using the IRQ mapping table. */
if (i >= ARRAY_SIZE(cs8900_irq_map))
pr_err("invalid ISA interrupt number %d\n", i);
@@ -1599,7 +1542,6 @@ cs89x0_probe1(struct net_device *dev, void __iomem *ioaddr, int modular)
lp->irq_map = ((irq_map_buff[0] >> 8) |
(irq_map_buff[1] << 8));
}
-#endif
}
#endif
if (!dev->irq)
@@ -1978,18 +1920,6 @@ static struct platform_driver cs89x0_driver = {
.remove = cs89x0_platform_remove,
};
-static int __init cs89x0_init(void)
-{
- return platform_driver_probe(&cs89x0_driver, cs89x0_platform_probe);
-}
-
-module_init(cs89x0_init);
-
-static void __exit cs89x0_cleanup(void)
-{
- platform_driver_unregister(&cs89x0_driver);
-}
-
-module_exit(cs89x0_cleanup);
+module_platform_driver_probe(cs89x0_driver, cs89x0_platform_probe);
#endif /* CONFIG_CS89x0_PLATFORM */
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 354cbb78ed50..67b0388b6e68 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -887,18 +887,7 @@ static struct platform_driver ep93xx_eth_driver = {
},
};
-static int __init ep93xx_eth_init_module(void)
-{
- printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
- return platform_driver_register(&ep93xx_eth_driver);
-}
-
-static void __exit ep93xx_eth_cleanup_module(void)
-{
- platform_driver_unregister(&ep93xx_eth_driver);
-}
+module_platform_driver(ep93xx_eth_driver);
-module_init(ep93xx_eth_init_module);
-module_exit(ep93xx_eth_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ep93xx-eth");
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c
index bf0fc56dba19..4b6e5695b263 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.c
@@ -212,7 +212,7 @@ int enic_dev_deinit_done(struct enic *enic, int *status)
}
/* rtnl lock is held */
-int enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct enic *enic = netdev_priv(netdev);
int err;
@@ -225,7 +225,7 @@ int enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
}
/* rtnl lock is held */
-int enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct enic *enic = netdev_priv(netdev);
int err;
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h
index da1cba3c410e..08bded051b93 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.h
@@ -46,8 +46,8 @@ int enic_dev_packet_filter(struct enic *enic, int directed, int multicast,
int broadcast, int promisc, int allmulti);
int enic_dev_add_addr(struct enic *enic, u8 *addr);
int enic_dev_del_addr(struct enic *enic, u8 *addr);
-int enic_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
-int enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
+int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
+int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
int enic_dev_notify_unset(struct enic *enic);
int enic_dev_hang_notify(struct enic *enic);
int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index ec1a233622c6..635f55992d7e 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -1300,7 +1300,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
}
if (vlan_stripped)
- __vlan_hwaccel_put_tag(skb, vlan_tci);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
if (netdev->features & NETIF_F_GRO)
napi_gro_receive(&enic->napi[q_number], skb);
@@ -2496,9 +2496,9 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->watchdog_timeo = 2 * HZ;
netdev->ethtool_ops = &enic_ethtool_ops;
- netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
if (ENIC_SETTING(enic, LOOP)) {
- netdev->features &= ~NETIF_F_HW_VLAN_TX;
+ netdev->features &= ~NETIF_F_HW_VLAN_CTAG_TX;
enic->loop_enable = 1;
enic->loop_tag = enic->config.loop_tag;
dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);
diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c
index 605b22283be1..97455c573db5 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c
@@ -308,6 +308,9 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
if (status & STAT_ERROR) {
err = (int)readq(&devcmd->args[0]);
+ if (err == ERR_EINVAL &&
+ cmd == CMD_CAPABILITY)
+ return err;
if (err != ERR_ECMDUNKNOWN ||
cmd != CMD_CAPABILITY)
pr_err("Error %d devcmd %d\n",
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 8cdf02503d13..9105465b2a1a 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -257,6 +257,107 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
tmp = readl(reg);
}
+/*
+ * Sleep, either by using msleep() or if we are suspending, then
+ * use mdelay() to sleep.
+ */
+static void dm9000_msleep(board_info_t *db, unsigned int ms)
+{
+ if (db->in_suspend)
+ mdelay(ms);
+ else
+ msleep(ms);
+}
+
+/* Read a word from phyxcer */
+static int
+dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
+{
+ board_info_t *db = netdev_priv(dev);
+ unsigned long flags;
+ unsigned int reg_save;
+ int ret;
+
+ mutex_lock(&db->addr_lock);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ /* Save previous register address */
+ reg_save = readb(db->io_addr);
+
+ /* Fill the phyxcer register into REG_0C */
+ iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+ /* Issue phyxcer read command */
+ iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);
+
+ writeb(reg_save, db->io_addr);
+ spin_unlock_irqrestore(&db->lock, flags);
+
+ dm9000_msleep(db, 1); /* Wait read complete */
+
+ spin_lock_irqsave(&db->lock, flags);
+ reg_save = readb(db->io_addr);
+
+ iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
+
+ /* The read data keeps on REG_0D & REG_0E */
+ ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
+
+ /* restore the previous address */
+ writeb(reg_save, db->io_addr);
+ spin_unlock_irqrestore(&db->lock, flags);
+
+ mutex_unlock(&db->addr_lock);
+
+ dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
+ return ret;
+}
+
+/* Write a word to phyxcer */
+static void
+dm9000_phy_write(struct net_device *dev,
+ int phyaddr_unused, int reg, int value)
+{
+ board_info_t *db = netdev_priv(dev);
+ unsigned long flags;
+ unsigned long reg_save;
+
+ dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
+ mutex_lock(&db->addr_lock);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ /* Save previous register address */
+ reg_save = readb(db->io_addr);
+
+ /* Fill the phyxcer register into REG_0C */
+ iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+ /* Fill the written data into REG_0D & REG_0E */
+ iow(db, DM9000_EPDRL, value);
+ iow(db, DM9000_EPDRH, value >> 8);
+
+ /* Issue phyxcer write command */
+ iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);
+
+ writeb(reg_save, db->io_addr);
+ spin_unlock_irqrestore(&db->lock, flags);
+
+ dm9000_msleep(db, 1); /* Wait write complete */
+
+ spin_lock_irqsave(&db->lock, flags);
+ reg_save = readb(db->io_addr);
+
+ iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */
+
+ /* restore the previous address */
+ writeb(reg_save, db->io_addr);
+
+ spin_unlock_irqrestore(&db->lock, flags);
+ mutex_unlock(&db->addr_lock);
+}
+
/* dm9000_set_io
*
* select the specified set of io routines to use with the
@@ -795,6 +896,9 @@ dm9000_init_dm9000(struct net_device *dev)
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
+ dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */
+ dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */
+
ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
/* if wol is needed, then always set NCR_WAKEEN otherwise we end
@@ -1201,109 +1305,6 @@ dm9000_open(struct net_device *dev)
return 0;
}
-/*
- * Sleep, either by using msleep() or if we are suspending, then
- * use mdelay() to sleep.
- */
-static void dm9000_msleep(board_info_t *db, unsigned int ms)
-{
- if (db->in_suspend)
- mdelay(ms);
- else
- msleep(ms);
-}
-
-/*
- * Read a word from phyxcer
- */
-static int
-dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
-{
- board_info_t *db = netdev_priv(dev);
- unsigned long flags;
- unsigned int reg_save;
- int ret;
-
- mutex_lock(&db->addr_lock);
-
- spin_lock_irqsave(&db->lock,flags);
-
- /* Save previous register address */
- reg_save = readb(db->io_addr);
-
- /* Fill the phyxcer register into REG_0C */
- iow(db, DM9000_EPAR, DM9000_PHY | reg);
-
- iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS); /* Issue phyxcer read command */
-
- writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock,flags);
-
- dm9000_msleep(db, 1); /* Wait read complete */
-
- spin_lock_irqsave(&db->lock,flags);
- reg_save = readb(db->io_addr);
-
- iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */
-
- /* The read data keeps on REG_0D & REG_0E */
- ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
-
- /* restore the previous address */
- writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock,flags);
-
- mutex_unlock(&db->addr_lock);
-
- dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
- return ret;
-}
-
-/*
- * Write a word to phyxcer
- */
-static void
-dm9000_phy_write(struct net_device *dev,
- int phyaddr_unused, int reg, int value)
-{
- board_info_t *db = netdev_priv(dev);
- unsigned long flags;
- unsigned long reg_save;
-
- dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
- mutex_lock(&db->addr_lock);
-
- spin_lock_irqsave(&db->lock,flags);
-
- /* Save previous register address */
- reg_save = readb(db->io_addr);
-
- /* Fill the phyxcer register into REG_0C */
- iow(db, DM9000_EPAR, DM9000_PHY | reg);
-
- /* Fill the written data into REG_0D & REG_0E */
- iow(db, DM9000_EPDRL, value);
- iow(db, DM9000_EPDRH, value >> 8);
-
- iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW); /* Issue phyxcer write command */
-
- writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock, flags);
-
- dm9000_msleep(db, 1); /* Wait write complete */
-
- spin_lock_irqsave(&db->lock,flags);
- reg_save = readb(db->io_addr);
-
- iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */
-
- /* restore the previous address */
- writeb(reg_save, db->io_addr);
-
- spin_unlock_irqrestore(&db->lock, flags);
- mutex_unlock(&db->addr_lock);
-}
-
static void
dm9000_shutdown(struct net_device *dev)
{
@@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev)
db->flags |= DM9000_PLATF_SIMPLE_PHY;
#endif
- dm9000_reset(db);
+ /* Fixing bug on dm9000_probe, takeover dm9000_reset(db),
+ * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo
+ * while probe stage.
+ */
+
+ iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST);
/* try multiple times, DM9000 sometimes gets the read wrong */
for (i = 0; i < 8; i++) {
@@ -1687,22 +1693,7 @@ static struct platform_driver dm9000_driver = {
.remove = dm9000_drv_remove,
};
-static int __init
-dm9000_init(void)
-{
- printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
-
- return platform_driver_register(&dm9000_driver);
-}
-
-static void __exit
-dm9000_cleanup(void)
-{
- platform_driver_unregister(&dm9000_driver);
-}
-
-module_init(dm9000_init);
-module_exit(dm9000_cleanup);
+module_platform_driver(dm9000_driver);
MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
diff --git a/drivers/net/ethernet/davicom/dm9000.h b/drivers/net/ethernet/davicom/dm9000.h
index 55688bd1a3ef..9ce058adabab 100644
--- a/drivers/net/ethernet/davicom/dm9000.h
+++ b/drivers/net/ethernet/davicom/dm9000.h
@@ -69,7 +69,9 @@
#define NCR_WAKEEN (1<<6)
#define NCR_FCOL (1<<4)
#define NCR_FDX (1<<3)
-#define NCR_LBK (3<<1)
+
+#define NCR_RESERVED (3<<1)
+#define NCR_MAC_LBK (1<<1)
#define NCR_RST (1<<0)
#define NSR_SPEED (1<<7)
@@ -167,5 +169,12 @@
#define ISR_LNKCHNG (1<<5)
#define ISR_UNDERRUN (1<<4)
+/* Davicom MII registers.
+ */
+
+#define MII_DM_DSPCR 0x1b /* DSP Control Register */
+
+#define DSPCR_INIT_PARAM 0xE100 /* DSP init parameter */
+
#endif /* _DM9000X_H_ */
diff --git a/drivers/net/ethernet/dec/tulip/xircom_cb.c b/drivers/net/ethernet/dec/tulip/xircom_cb.c
index 88feced9a629..cdbcd1643141 100644
--- a/drivers/net/ethernet/dec/tulip/xircom_cb.c
+++ b/drivers/net/ethernet/dec/tulip/xircom_cb.c
@@ -236,17 +236,14 @@ static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
private->rx_buffer = dma_alloc_coherent(d, 8192,
&private->rx_dma_handle,
GFP_KERNEL);
- if (private->rx_buffer == NULL) {
- pr_err("%s: no memory for rx buffer\n", __func__);
+ if (private->rx_buffer == NULL)
goto rx_buf_fail;
- }
+
private->tx_buffer = dma_alloc_coherent(d, 8192,
&private->tx_dma_handle,
GFP_KERNEL);
- if (private->tx_buffer == NULL) {
- pr_err("%s: no memory for tx buffer\n", __func__);
+ if (private->tx_buffer == NULL)
goto tx_buf_fail;
- }
SET_NETDEV_DEV(dev, &pdev->dev);
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index 110d26f4c602..afa8e3af2c4d 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -580,12 +580,9 @@ alloc_list (struct net_device *dev)
skb = netdev_alloc_skb_ip_align(dev, np->rx_buf_sz);
np->rx_skbuff[i] = skb;
- if (skb == NULL) {
- printk (KERN_ERR
- "%s: alloc_list: allocate Rx buffer error! ",
- dev->name);
+ if (skb == NULL)
break;
- }
+
/* Rubicon now supports 40 bits of addressing space. */
np->rx_ring[i].fraginfo =
cpu_to_le64 ( pci_map_single (
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 29aff55f2eea..234ce6f07544 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -214,6 +214,7 @@ struct be_tx_stats {
};
struct be_tx_obj {
+ u32 db_offset;
struct be_queue_info q;
struct be_queue_info cq;
/* Remember the skbs that were transmitted */
@@ -292,7 +293,7 @@ struct be_drv_stats {
u32 rx_in_range_errors;
u32 rx_out_range_errors;
u32 rx_frame_too_long;
- u32 rx_address_mismatch_drops;
+ u32 rx_address_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -328,6 +329,7 @@ enum vf_state {
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
+#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11)
struct phy_info {
u8 transceiver;
@@ -434,6 +436,8 @@ struct be_adapter {
u8 wol_cap;
bool wol;
u32 uc_macs; /* Count of secondary UC MAC programmed */
+ u16 asic_rev;
+ u16 qnq_vid;
u32 msg_enable;
int be_get_temp_freq;
u16 max_mcast_mac;
@@ -445,6 +449,7 @@ struct be_adapter {
u16 max_event_queues;
u32 if_cap_flags;
u8 pf_number;
+ u64 rss_flags;
};
#define be_physfn(adapter) (!adapter->virtfn)
@@ -648,6 +653,11 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter)
}
}
+static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
+{
+ return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
+}
+
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, u8 link_status);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 3c9b4f12e3e5..25d3290b8cac 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -263,6 +263,27 @@ static void be_async_grp5_evt_process(struct be_adapter *adapter,
}
}
+static void be_async_dbg_evt_process(struct be_adapter *adapter,
+ u32 trailer, struct be_mcc_compl *cmp)
+{
+ u8 event_type = 0;
+ struct be_async_event_qnq *evt = (struct be_async_event_qnq *) cmp;
+
+ event_type = (trailer >> ASYNC_TRAILER_EVENT_TYPE_SHIFT) &
+ ASYNC_TRAILER_EVENT_TYPE_MASK;
+
+ switch (event_type) {
+ case ASYNC_DEBUG_EVENT_TYPE_QNQ:
+ if (evt->valid)
+ adapter->qnq_vid = le16_to_cpu(evt->vlan_tag);
+ adapter->flags |= BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
+ break;
+ default:
+ dev_warn(&adapter->pdev->dev, "Unknown debug event\n");
+ break;
+ }
+}
+
static inline bool is_link_state_evt(u32 trailer)
{
return ((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
@@ -277,6 +298,13 @@ static inline bool is_grp5_evt(u32 trailer)
ASYNC_EVENT_CODE_GRP_5);
}
+static inline bool is_dbg_evt(u32 trailer)
+{
+ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
+ ASYNC_TRAILER_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_QNQ);
+}
+
static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
{
struct be_queue_info *mcc_cq = &adapter->mcc_obj.cq;
@@ -325,6 +353,9 @@ int be_process_mcc(struct be_adapter *adapter)
else if (is_grp5_evt(compl->flags))
be_async_grp5_evt_process(adapter,
compl->flags, compl);
+ else if (is_dbg_evt(compl->flags))
+ be_async_dbg_evt_process(adapter,
+ compl->flags, compl);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
status = be_mcc_compl_process(adapter, compl);
atomic_dec(&mcc_obj->q.used);
@@ -687,10 +718,8 @@ static struct be_mcc_wrb *wrb_from_mccq(struct be_adapter *adapter)
if (!mccq->created)
return NULL;
- if (atomic_read(&mccq->used) >= mccq->len) {
- dev_err(&adapter->pdev->dev, "Out of MCCQ wrbs\n");
+ if (atomic_read(&mccq->used) >= mccq->len)
return NULL;
- }
wrb = queue_head_node(mccq);
queue_head_inc(mccq);
@@ -1022,6 +1051,7 @@ int be_cmd_mccq_ext_create(struct be_adapter *adapter,
/* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
req->async_event_bitmap[0] = cpu_to_le32(0x00000022);
+ req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ);
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -1095,15 +1125,14 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
return status;
}
-int be_cmd_txq_create(struct be_adapter *adapter,
- struct be_queue_info *txq,
- struct be_queue_info *cq)
+int be_cmd_txq_create(struct be_adapter *adapter, struct be_tx_obj *txo)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_eth_tx_create *req;
+ struct be_queue_info *txq = &txo->q;
+ struct be_queue_info *cq = &txo->cq;
struct be_dma_mem *q_mem = &txq->dma_mem;
- void *ctxt;
- int status;
+ int status, ver = 0;
spin_lock_bh(&adapter->mcc_lock);
@@ -1114,34 +1143,37 @@ int be_cmd_txq_create(struct be_adapter *adapter,
}
req = embedded_payload(wrb);
- ctxt = &req->context;
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
OPCODE_ETH_TX_CREATE, sizeof(*req), wrb, NULL);
if (lancer_chip(adapter)) {
req->hdr.version = 1;
- AMAP_SET_BITS(struct amap_tx_context, if_id, ctxt,
- adapter->if_handle);
+ req->if_id = cpu_to_le16(adapter->if_handle);
+ } else if (BEx_chip(adapter)) {
+ if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC)
+ req->hdr.version = 2;
+ } else { /* For SH */
+ req->hdr.version = 2;
}
req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
req->ulp_num = BE_ULP1_NUM;
req->type = BE_ETH_TX_RING_TYPE_STANDARD;
-
- AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt,
- be_encoded_q_len(txq->len));
- AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
- AMAP_SET_BITS(struct amap_tx_context, cq_id_send, ctxt, cq->id);
-
- be_dws_cpu_to_le(ctxt, sizeof(req->context));
-
+ req->cq_id = cpu_to_le16(cq->id);
+ req->queue_size = be_encoded_q_len(txq->len);
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+ ver = req->hdr.version;
+
status = be_mcc_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
txq->id = le16_to_cpu(resp->cid);
+ if (ver == 2)
+ txo->db_offset = le32_to_cpu(resp->db_offset);
+ else
+ txo->db_offset = DB_TXULP1_OFFSET;
txq->created = true;
}
@@ -1834,7 +1866,7 @@ err:
/* Uses mbox */
int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
- u32 *mode, u32 *caps)
+ u32 *mode, u32 *caps, u16 *asic_rev)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_query_fw_cfg *req;
@@ -1855,6 +1887,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
*port_num = le32_to_cpu(resp->phys_port);
*mode = le32_to_cpu(resp->function_mode);
*caps = le32_to_cpu(resp->function_caps);
+ *asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF;
}
mutex_unlock(&adapter->mbox_lock);
@@ -1897,7 +1930,8 @@ int be_cmd_reset_function(struct be_adapter *adapter)
return status;
}
-int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
+int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
+ u32 rss_hash_opts, u16 table_size)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_rss_config *req;
@@ -1916,16 +1950,12 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL);
req->if_id = cpu_to_le32(adapter->if_handle);
- req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
- RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6);
+ req->enable_rss = cpu_to_le16(rss_hash_opts);
+ req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
- if (lancer_chip(adapter) || skyhawk_chip(adapter)) {
+ if (lancer_chip(adapter) || skyhawk_chip(adapter))
req->hdr.version = 1;
- req->enable_rss |= cpu_to_le16(RSS_ENABLE_UDP_IPV4 |
- RSS_ENABLE_UDP_IPV6);
- }
- req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1);
memcpy(req->cpu_table, rsstable, table_size);
memcpy(req->hash, myhash, sizeof(myhash));
be_dws_cpu_to_le(req->hash, sizeof(req->hash));
@@ -2343,7 +2373,6 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_seeprom_read *req;
- struct be_sge *sge;
int status;
spin_lock_bh(&adapter->mcc_lock);
@@ -2354,7 +2383,6 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
goto err;
}
req = nonemb_cmd->va;
- sge = nonembedded_sgl(wrb);
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_SEEPROM_READ, sizeof(*req), wrb,
@@ -2461,6 +2489,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
struct mgmt_controller_attrib *attribs;
struct be_dma_mem attribs_cmd;
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+
memset(&attribs_cmd, 0, sizeof(struct be_dma_mem));
attribs_cmd.size = sizeof(struct be_cmd_resp_cntl_attribs);
attribs_cmd.va = pci_alloc_consistent(adapter->pdev, attribs_cmd.size,
@@ -2468,12 +2499,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
if (!attribs_cmd.va) {
dev_err(&adapter->pdev->dev,
"Memory allocation failure\n");
- return -ENOMEM;
+ status = -ENOMEM;
+ goto err;
}
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
-
wrb = wrb_from_mbox(adapter);
if (!wrb) {
status = -EBUSY;
@@ -2493,8 +2522,9 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter)
err:
mutex_unlock(&adapter->mbox_lock);
- pci_free_consistent(adapter->pdev, attribs_cmd.size, attribs_cmd.va,
- attribs_cmd.dma);
+ if (attribs_cmd.va)
+ pci_free_consistent(adapter->pdev, attribs_cmd.size,
+ attribs_cmd.va, attribs_cmd.dma);
return status;
}
@@ -2667,10 +2697,8 @@ int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array,
cmd.size = sizeof(struct be_cmd_req_set_mac_list);
cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size,
&cmd.dma, GFP_KERNEL);
- if (!cmd.va) {
- dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+ if (!cmd.va)
return -ENOMEM;
- }
spin_lock_bh(&adapter->mcc_lock);
@@ -2794,6 +2822,9 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
CMD_SUBSYSTEM_ETH))
return -EPERM;
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+
memset(&cmd, 0, sizeof(struct be_dma_mem));
cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1);
cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
@@ -2801,12 +2832,10 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
if (!cmd.va) {
dev_err(&adapter->pdev->dev,
"Memory allocation failure\n");
- return -ENOMEM;
+ status = -ENOMEM;
+ goto err;
}
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
-
wrb = wrb_from_mbox(adapter);
if (!wrb) {
status = -EBUSY;
@@ -2837,7 +2866,8 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
}
err:
mutex_unlock(&adapter->mbox_lock);
- pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
+ if (cmd.va)
+ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
return status;
}
@@ -2942,14 +2972,15 @@ static struct be_nic_resource_desc *be_get_nic_desc(u8 *buf, u32 desc_count,
int i;
for (i = 0; i < desc_count; i++) {
- desc->desc_len = RESOURCE_DESC_SIZE;
+ desc->desc_len = desc->desc_len ? : RESOURCE_DESC_SIZE;
if (((void *)desc + desc->desc_len) >
(void *)(buf + max_buf_size)) {
desc = NULL;
break;
}
- if (desc->desc_type == NIC_RESOURCE_DESC_TYPE_ID)
+ if (desc->desc_type == NIC_RESOURCE_DESC_TYPE_V0 ||
+ desc->desc_type == NIC_RESOURCE_DESC_TYPE_V1)
break;
desc = (void *)desc + desc->desc_len;
@@ -2969,16 +3000,18 @@ int be_cmd_get_func_config(struct be_adapter *adapter)
int status;
struct be_dma_mem cmd;
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+
memset(&cmd, 0, sizeof(struct be_dma_mem));
cmd.size = sizeof(struct be_cmd_resp_get_func_config);
cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
&cmd.dma);
if (!cmd.va) {
dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
- return -ENOMEM;
+ status = -ENOMEM;
+ goto err;
}
- if (mutex_lock_interruptible(&adapter->mbox_lock))
- return -1;
wrb = wrb_from_mbox(adapter);
if (!wrb) {
@@ -2992,6 +3025,9 @@ int be_cmd_get_func_config(struct be_adapter *adapter)
OPCODE_COMMON_GET_FUNC_CONFIG,
cmd.size, wrb, &cmd);
+ if (skyhawk_chip(adapter))
+ req->hdr.version = 1;
+
status = be_mbox_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_get_func_config *resp = cmd.va;
@@ -3018,28 +3054,46 @@ int be_cmd_get_func_config(struct be_adapter *adapter)
}
err:
mutex_unlock(&adapter->mbox_lock);
- pci_free_consistent(adapter->pdev, cmd.size,
- cmd.va, cmd.dma);
+ if (cmd.va)
+ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma);
return status;
}
- /* Uses sync mcc */
-int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
- u8 domain)
+/* Uses mbox */
+int be_cmd_get_profile_config_mbox(struct be_adapter *adapter,
+ u8 domain, struct be_dma_mem *cmd)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_get_profile_config *req;
int status;
- struct be_dma_mem cmd;
- memset(&cmd, 0, sizeof(struct be_dma_mem));
- cmd.size = sizeof(struct be_cmd_resp_get_profile_config);
- cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
- &cmd.dma);
- if (!cmd.va) {
- dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
- return -ENOMEM;
- }
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+ wrb = wrb_from_mbox(adapter);
+
+ req = cmd->va;
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PROFILE_CONFIG,
+ cmd->size, wrb, cmd);
+
+ req->type = ACTIVE_PROFILE_TYPE;
+ req->hdr.domain = domain;
+ if (!lancer_chip(adapter))
+ req->hdr.version = 1;
+
+ status = be_mbox_notify_wait(adapter);
+
+ mutex_unlock(&adapter->mbox_lock);
+ return status;
+}
+
+/* Uses sync mcc */
+int be_cmd_get_profile_config_mccq(struct be_adapter *adapter,
+ u8 domain, struct be_dma_mem *cmd)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_profile_config *req;
+ int status;
spin_lock_bh(&adapter->mcc_lock);
@@ -3049,16 +3103,47 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
goto err;
}
- req = cmd.va;
-
+ req = cmd->va;
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_PROFILE_CONFIG,
- cmd.size, wrb, &cmd);
+ cmd->size, wrb, cmd);
req->type = ACTIVE_PROFILE_TYPE;
req->hdr.domain = domain;
+ if (!lancer_chip(adapter))
+ req->hdr.version = 1;
status = be_mcc_notify_wait(adapter);
+
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+/* Uses sync mcc, if MCCQ is already created otherwise mbox */
+int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
+ u16 *txq_count, u8 domain)
+{
+ struct be_queue_info *mccq = &adapter->mcc_obj.q;
+ struct be_dma_mem cmd;
+ int status;
+
+ memset(&cmd, 0, sizeof(struct be_dma_mem));
+ if (!lancer_chip(adapter))
+ cmd.size = sizeof(struct be_cmd_resp_get_profile_config_v1);
+ else
+ cmd.size = sizeof(struct be_cmd_resp_get_profile_config);
+ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size,
+ &cmd.dma);
+ if (!cmd.va) {
+ dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+ return -ENOMEM;
+ }
+
+ if (!mccq->created)
+ status = be_cmd_get_profile_config_mbox(adapter, domain, &cmd);
+ else
+ status = be_cmd_get_profile_config_mccq(adapter, domain, &cmd);
if (!status) {
struct be_cmd_resp_get_profile_config *resp = cmd.va;
u32 desc_count = le32_to_cpu(resp->desc_count);
@@ -3071,12 +3156,15 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
status = -EINVAL;
goto err;
}
- *cap_flags = le32_to_cpu(desc->cap_flags);
+ if (cap_flags)
+ *cap_flags = le32_to_cpu(desc->cap_flags);
+ if (txq_count)
+ *txq_count = le32_to_cpu(desc->txq_count);
}
err:
- spin_unlock_bh(&adapter->mcc_lock);
- pci_free_consistent(adapter->pdev, cmd.size,
- cmd.va, cmd.dma);
+ if (cmd.va)
+ pci_free_consistent(adapter->pdev, cmd.size,
+ cmd.va, cmd.dma);
return status;
}
@@ -3105,7 +3193,7 @@ int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
req->hdr.domain = domain;
req->desc_count = cpu_to_le32(1);
- req->nic_desc.desc_type = NIC_RESOURCE_DESC_TYPE_ID;
+ req->nic_desc.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
req->nic_desc.desc_len = RESOURCE_DESC_SIZE;
req->nic_desc.flags = (1 << QUN) | (1 << IMM) | (1 << NOSV);
req->nic_desc.pf_num = adapter->pf_number;
@@ -3202,6 +3290,31 @@ err:
return status;
}
+int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_intr_set *req;
+ int status;
+
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+
+ wrb = wrb_from_mbox(adapter);
+
+ req = embedded_payload(wrb);
+
+ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_INTERRUPT_ENABLE, sizeof(*req),
+ wrb, NULL);
+
+ req->intr_enabled = intr_enable;
+
+ status = be_mbox_notify_wait(adapter);
+
+ mutex_unlock(&adapter->mbox_lock);
+ return status;
+}
+
int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
{
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 96970860c915..a855668e0cc5 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -84,6 +84,9 @@ struct be_mcc_compl {
#define ASYNC_EVENT_QOS_SPEED 0x1
#define ASYNC_EVENT_COS_PRIORITY 0x2
#define ASYNC_EVENT_PVID_STATE 0x3
+#define ASYNC_EVENT_CODE_QNQ 0x6
+#define ASYNC_DEBUG_EVENT_TYPE_QNQ 1
+
struct be_async_event_trailer {
u32 code;
};
@@ -144,6 +147,16 @@ struct be_async_event_grp5_pvid_state {
struct be_async_event_trailer trailer;
} __packed;
+/* async event indicating outer VLAN tag in QnQ */
+struct be_async_event_qnq {
+ u8 valid; /* Indicates if outer VLAN is valid */
+ u8 rsvd0;
+ u16 vlan_tag;
+ u32 event_tag;
+ u8 rsvd1[4];
+ struct be_async_event_trailer trailer;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -188,6 +201,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
#define OPCODE_COMMON_GET_PORT_NAME 77
+#define OPCODE_COMMON_SET_INTERRUPT_ENABLE 89
#define OPCODE_COMMON_GET_PHY_DETAILS 102
#define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103
#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
@@ -473,46 +487,27 @@ struct be_cmd_resp_mcc_create {
#define BE_ETH_TX_RING_TYPE_STANDARD 2
#define BE_ULP1_NUM 1
-/* Pseudo amap definition in which each bit of the actual structure is defined
- * as a byte: used to calculate offset/shift/mask of each field */
-struct amap_tx_context {
- u8 if_id[16]; /* dword 0 */
- u8 tx_ring_size[4]; /* dword 0 */
- u8 rsvd1[26]; /* dword 0 */
- u8 pci_func_id[8]; /* dword 1 */
- u8 rsvd2[9]; /* dword 1 */
- u8 ctx_valid; /* dword 1 */
- u8 cq_id_send[16]; /* dword 2 */
- u8 rsvd3[16]; /* dword 2 */
- u8 rsvd4[32]; /* dword 3 */
- u8 rsvd5[32]; /* dword 4 */
- u8 rsvd6[32]; /* dword 5 */
- u8 rsvd7[32]; /* dword 6 */
- u8 rsvd8[32]; /* dword 7 */
- u8 rsvd9[32]; /* dword 8 */
- u8 rsvd10[32]; /* dword 9 */
- u8 rsvd11[32]; /* dword 10 */
- u8 rsvd12[32]; /* dword 11 */
- u8 rsvd13[32]; /* dword 12 */
- u8 rsvd14[32]; /* dword 13 */
- u8 rsvd15[32]; /* dword 14 */
- u8 rsvd16[32]; /* dword 15 */
-} __packed;
-
struct be_cmd_req_eth_tx_create {
struct be_cmd_req_hdr hdr;
u8 num_pages;
u8 ulp_num;
- u8 type;
- u8 bound_port;
- u8 context[sizeof(struct amap_tx_context) / 8];
+ u16 type;
+ u16 if_id;
+ u8 queue_size;
+ u8 rsvd0;
+ u32 rsvd1;
+ u16 cq_id;
+ u16 rsvd2;
+ u32 rsvd3[13];
struct phys_addr pages[8];
} __packed;
struct be_cmd_resp_eth_tx_create {
struct be_cmd_resp_hdr hdr;
u16 cid;
- u16 rsvd0;
+ u16 rid;
+ u32 db_offset;
+ u32 rsvd0[4];
} __packed;
/******************** Create RxQ ***************************/
@@ -608,8 +603,8 @@ struct be_port_rxf_stats_v0 {
u32 rx_in_range_errors; /* dword 10*/
u32 rx_out_range_errors; /* dword 11*/
u32 rx_frame_too_long; /* dword 12*/
- u32 rx_address_mismatch_drops; /* dword 13*/
- u32 rx_vlan_mismatch_drops; /* dword 14*/
+ u32 rx_address_filtered; /* dword 13*/
+ u32 rx_vlan_filtered; /* dword 14*/
u32 rx_dropped_too_small; /* dword 15*/
u32 rx_dropped_too_short; /* dword 16*/
u32 rx_dropped_header_too_small; /* dword 17*/
@@ -815,8 +810,8 @@ struct lancer_pport_stats {
u32 rx_control_frames_unknown_opcode_hi;
u32 rx_in_range_errors;
u32 rx_out_of_range_errors;
- u32 rx_address_mismatch_drops;
- u32 rx_vlan_mismatch_drops;
+ u32 rx_address_filtered;
+ u32 rx_vlan_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -1066,7 +1061,6 @@ struct be_cmd_resp_modify_eq_delay {
} __packed;
/******************** Get FW Config *******************/
-#define BE_FUNCTION_CAPS_RSS 0x2
/* The HW can come up in either of the following multi-channel modes
* based on the skew/IPL.
*/
@@ -1109,6 +1103,9 @@ struct be_cmd_resp_query_fw_cfg {
#define RSS_ENABLE_UDP_IPV4 0x10
#define RSS_ENABLE_UDP_IPV6 0x20
+#define L3_RSS_FLAGS (RXH_IP_DST | RXH_IP_SRC)
+#define L4_RSS_FLAGS (RXH_L4_B_0_1 | RXH_L4_B_2_3)
+
struct be_cmd_req_rss_config {
struct be_cmd_req_hdr hdr;
u32 if_id;
@@ -1592,7 +1589,7 @@ struct be_port_rxf_stats_v1 {
u32 rx_in_range_errors;
u32 rx_out_range_errors;
u32 rx_frame_too_long;
- u32 rx_address_mismatch_drops;
+ u32 rx_address_filtered;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
@@ -1706,9 +1703,11 @@ struct be_cmd_req_set_ext_fat_caps {
struct be_fat_conf_params set_params;
};
-#define RESOURCE_DESC_SIZE 72
-#define NIC_RESOURCE_DESC_TYPE_ID 0x41
+#define RESOURCE_DESC_SIZE 88
+#define NIC_RESOURCE_DESC_TYPE_V0 0x41
+#define NIC_RESOURCE_DESC_TYPE_V1 0x51
#define MAX_RESOURCE_DESC 4
+#define MAX_RESOURCE_DESC_V1 32
/* QOS unit number */
#define QUN 4
@@ -1755,7 +1754,7 @@ struct be_cmd_req_get_func_config {
};
struct be_cmd_resp_get_func_config {
- struct be_cmd_req_hdr hdr;
+ struct be_cmd_resp_hdr hdr;
u32 desc_count;
u8 func_param[MAX_RESOURCE_DESC * RESOURCE_DESC_SIZE];
};
@@ -1774,6 +1773,12 @@ struct be_cmd_resp_get_profile_config {
u8 func_param[MAX_RESOURCE_DESC * RESOURCE_DESC_SIZE];
};
+struct be_cmd_resp_get_profile_config_v1 {
+ struct be_cmd_req_hdr hdr;
+ u32 desc_count;
+ u8 func_param[MAX_RESOURCE_DESC_V1 * RESOURCE_DESC_SIZE];
+};
+
struct be_cmd_req_set_profile_config {
struct be_cmd_req_hdr hdr;
u32 rsvd;
@@ -1791,6 +1796,12 @@ struct be_cmd_enable_disable_vf {
u8 rsvd[3];
};
+struct be_cmd_req_intr_set {
+ struct be_cmd_req_hdr hdr;
+ u8 intr_enabled;
+ u8 rsvd[3];
+};
+
static inline bool check_privilege(struct be_adapter *adapter, u32 flags)
{
return flags & adapter->cmd_privileges ? true : false;
@@ -1834,8 +1845,7 @@ extern int be_cmd_mccq_create(struct be_adapter *adapter,
struct be_queue_info *mccq,
struct be_queue_info *cq);
extern int be_cmd_txq_create(struct be_adapter *adapter,
- struct be_queue_info *txq,
- struct be_queue_info *cq);
+ struct be_tx_obj *txo);
extern int be_cmd_rxq_create(struct be_adapter *adapter,
struct be_queue_info *rxq, u16 cq_id,
u16 frag_size, u32 if_id, u32 rss, u8 *rss_id);
@@ -1862,11 +1872,11 @@ extern int be_cmd_set_flow_control(struct be_adapter *adapter,
u32 tx_fc, u32 rx_fc);
extern int be_cmd_get_flow_control(struct be_adapter *adapter,
u32 *tx_fc, u32 *rx_fc);
-extern int be_cmd_query_fw_cfg(struct be_adapter *adapter,
- u32 *port_num, u32 *function_mode, u32 *function_caps);
+extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num,
+ u32 *function_mode, u32 *function_caps, u16 *asic_rev);
extern int be_cmd_reset_function(struct be_adapter *adapter);
extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable,
- u16 table_size);
+ u32 rss_hash_opts, u16 table_size);
extern int be_process_mcc(struct be_adapter *adapter);
extern int be_cmd_set_beacon_state(struct be_adapter *adapter,
u8 port_num, u8 beacon, u8 status, u8 state);
@@ -1931,10 +1941,11 @@ extern int lancer_test_and_set_rdy_state(struct be_adapter *adapter);
extern int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name);
extern int be_cmd_get_func_config(struct be_adapter *adapter);
extern int be_cmd_get_profile_config(struct be_adapter *adapter, u32 *cap_flags,
- u8 domain);
+ u16 *txq_count, u8 domain);
extern int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
u8 domain);
extern int be_cmd_get_if_id(struct be_adapter *adapter,
struct be_vf_cfg *vf_cfg, int vf_num);
extern int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
+extern int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 76b302f30c87..5733cde88e2c 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -54,7 +54,7 @@ static const struct be_ethtool_stat et_stats[] = {
/* Received packets dropped when they don't pass the unicast or
* multicast address filtering.
*/
- {DRVSTAT_INFO(rx_address_mismatch_drops)},
+ {DRVSTAT_INFO(rx_address_filtered)},
/* Received packets dropped when IP packet length field is less than
* the IP header length field.
*/
@@ -680,7 +680,8 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
if (be_is_wol_supported(adapter)) {
wol->supported |= WAKE_MAGIC;
- wol->wolopts |= WAKE_MAGIC;
+ if (adapter->wol)
+ wol->wolopts |= WAKE_MAGIC;
} else
wol->wolopts = 0;
memset(&wol->sopass, 0, sizeof(wol->sopass));
@@ -719,10 +720,8 @@ be_test_ddr_dma(struct be_adapter *adapter)
ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size,
&ddrdma_cmd.dma, GFP_KERNEL);
- if (!ddrdma_cmd.va) {
- dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
+ if (!ddrdma_cmd.va)
return -ENOMEM;
- }
for (i = 0; i < 2; i++) {
ret = be_cmd_ddr_dma_test(adapter, pattern[i],
@@ -757,6 +756,12 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
int status;
u8 link_status = 0;
+ if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
+ dev_err(&adapter->pdev->dev, "Self test not supported\n");
+ test->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
+
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
if (test->flags & ETH_TEST_FL_OFFLINE) {
@@ -845,11 +850,8 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size,
&eeprom_cmd.dma, GFP_KERNEL);
- if (!eeprom_cmd.va) {
- dev_err(&adapter->pdev->dev,
- "Memory allocation failure. Could not read eeprom\n");
+ if (!eeprom_cmd.va)
return -ENOMEM;
- }
status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
@@ -939,6 +941,159 @@ static void be_set_msg_level(struct net_device *netdev, u32 level)
return;
}
+static u64 be_get_rss_hash_opts(struct be_adapter *adapter, u64 flow_type)
+{
+ u64 data = 0;
+
+ switch (flow_type) {
+ case TCP_V4_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV4)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_TCP_IPV4)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V4_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV4)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_UDP_IPV4)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case TCP_V6_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV6)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_TCP_IPV6)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V6_FLOW:
+ if (adapter->rss_flags & RSS_ENABLE_IPV6)
+ data |= RXH_IP_DST | RXH_IP_SRC;
+ if (adapter->rss_flags & RSS_ENABLE_UDP_IPV6)
+ data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ }
+
+ return data;
+}
+
+static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (!be_multi_rxq(adapter)) {
+ dev_info(&adapter->pdev->dev,
+ "ethtool::get_rxnfc: RX flow hashing is disabled\n");
+ return -EINVAL;
+ }
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXFH:
+ cmd->data = be_get_rss_hash_opts(adapter, cmd->flow_type);
+ break;
+ case ETHTOOL_GRXRINGS:
+ cmd->data = adapter->num_rx_qs - 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int be_set_rss_hash_opts(struct be_adapter *adapter,
+ struct ethtool_rxnfc *cmd)
+{
+ struct be_rx_obj *rxo;
+ int status = 0, i, j;
+ u8 rsstable[128];
+ u32 rss_flags = adapter->rss_flags;
+
+ if (cmd->data != L3_RSS_FLAGS &&
+ cmd->data != (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ return -EINVAL;
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_TCP_IPV4;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV4 |
+ RSS_ENABLE_TCP_IPV4;
+ break;
+ case TCP_V6_FLOW:
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_TCP_IPV6;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV6 |
+ RSS_ENABLE_TCP_IPV6;
+ break;
+ case UDP_V4_FLOW:
+ if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
+ BEx_chip(adapter))
+ return -EINVAL;
+
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_UDP_IPV4;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV4 |
+ RSS_ENABLE_UDP_IPV4;
+ break;
+ case UDP_V6_FLOW:
+ if ((cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS)) &&
+ BEx_chip(adapter))
+ return -EINVAL;
+
+ if (cmd->data == L3_RSS_FLAGS)
+ rss_flags &= ~RSS_ENABLE_UDP_IPV6;
+ else if (cmd->data == (L3_RSS_FLAGS | L4_RSS_FLAGS))
+ rss_flags |= RSS_ENABLE_IPV6 |
+ RSS_ENABLE_UDP_IPV6;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (rss_flags == adapter->rss_flags)
+ return status;
+
+ if (be_multi_rxq(adapter)) {
+ for (j = 0; j < 128; j += adapter->num_rx_qs - 1) {
+ for_all_rss_queues(adapter, rxo, i) {
+ if ((j + i) >= 128)
+ break;
+ rsstable[j + i] = rxo->rss_id;
+ }
+ }
+ }
+ status = be_cmd_rss_config(adapter, rsstable, rss_flags, 128);
+ if (!status)
+ adapter->rss_flags = rss_flags;
+
+ return status;
+}
+
+static int be_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!be_multi_rxq(adapter)) {
+ dev_err(&adapter->pdev->dev,
+ "ethtool::set_rxnfc: RX flow hashing is disabled\n");
+ return -EINVAL;
+ }
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ status = be_set_rss_hash_opts(adapter, cmd);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return status;
+}
+
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
@@ -962,4 +1117,6 @@ const struct ethtool_ops be_ethtool_ops = {
.get_regs = be_get_regs,
.flash_device = be_do_flash,
.self_test = be_self_test,
+ .get_rxnfc = be_get_rxnfc,
+ .set_rxnfc = be_set_rxnfc,
};
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 62dc220695f7..3c1099b47f2a 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -72,6 +72,10 @@
*/
#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
+/********* PCI Function Capability *********/
+#define BE_FUNCTION_CAPS_RSS 0x2
+#define BE_FUNCTION_CAPS_SUPER_NIC 0x40
+
/********* Power management (WOL) **********/
#define PCICFG_PM_CONTROL_OFFSET 0x44
#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */
@@ -495,7 +499,8 @@ struct flash_file_hdr_g3 {
u32 antidote;
u32 num_imgs;
u8 build[24];
- u8 rsvd[32];
+ u8 asic_type_rev;
+ u8 rsvd[31];
};
struct flash_section_hdr {
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 08e54f3d288b..4babc8a4a543 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -146,20 +146,16 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
q->entry_size = entry_size;
mem->size = len * entry_size;
mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!mem->va)
return -ENOMEM;
- memset(mem->va, 0, mem->size);
return 0;
}
-static void be_intr_set(struct be_adapter *adapter, bool enable)
+static void be_reg_intr_set(struct be_adapter *adapter, bool enable)
{
u32 reg, enabled;
- if (adapter->eeh_error)
- return;
-
pci_read_config_dword(adapter->pdev, PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET,
&reg);
enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
@@ -175,6 +171,22 @@ static void be_intr_set(struct be_adapter *adapter, bool enable)
PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET, reg);
}
+static void be_intr_set(struct be_adapter *adapter, bool enable)
+{
+ int status = 0;
+
+ /* On lancer interrupts can't be controlled via this register */
+ if (lancer_chip(adapter))
+ return;
+
+ if (adapter->eeh_error)
+ return;
+
+ status = be_cmd_intr_set(adapter, enable);
+ if (status)
+ be_reg_intr_set(adapter, enable);
+}
+
static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
{
u32 val = 0;
@@ -185,14 +197,15 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
iowrite32(val, adapter->db + DB_RQ_OFFSET);
}
-static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
+static void be_txq_notify(struct be_adapter *adapter, struct be_tx_obj *txo,
+ u16 posted)
{
u32 val = 0;
- val |= qid & DB_TXULP_RING_ID_MASK;
+ val |= txo->q.id & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
wmb();
- iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
+ iowrite32(val, adapter->db + txo->db_offset);
}
static void be_eq_notify(struct be_adapter *adapter, u16 qid,
@@ -340,9 +353,9 @@ static void populate_be_v0_stats(struct be_adapter *adapter)
drvs->rx_input_fifo_overflow_drop = port_stats->rx_input_fifo_overflow;
drvs->rx_dropped_header_too_small =
port_stats->rx_dropped_header_too_small;
- drvs->rx_address_mismatch_drops =
- port_stats->rx_address_mismatch_drops +
- port_stats->rx_vlan_mismatch_drops;
+ drvs->rx_address_filtered =
+ port_stats->rx_address_filtered +
+ port_stats->rx_vlan_filtered;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
@@ -391,7 +404,7 @@ static void populate_be_v1_stats(struct be_adapter *adapter)
port_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop =
port_stats->rx_input_fifo_overflow_drop;
- drvs->rx_address_mismatch_drops = port_stats->rx_address_mismatch_drops;
+ drvs->rx_address_filtered = port_stats->rx_address_filtered;
drvs->rx_alignment_symbol_errors =
port_stats->rx_alignment_symbol_errors;
drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop;
@@ -432,9 +445,9 @@ static void populate_lancer_stats(struct be_adapter *adapter)
drvs->rx_dropped_header_too_small =
pport_stats->rx_dropped_header_too_small;
drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
- drvs->rx_address_mismatch_drops =
- pport_stats->rx_address_mismatch_drops +
- pport_stats->rx_vlan_mismatch_drops;
+ drvs->rx_address_filtered =
+ pport_stats->rx_address_filtered +
+ pport_stats->rx_vlan_filtered;
drvs->rx_alignment_symbol_errors = pport_stats->rx_symbol_errors_lo;
drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo;
@@ -626,13 +639,8 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
return vlan_tag;
}
-static int be_vlan_tag_chk(struct be_adapter *adapter, struct sk_buff *skb)
-{
- return vlan_tx_tag_present(skb) || adapter->pvid;
-}
-
static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
- struct sk_buff *skb, u32 wrb_cnt, u32 len)
+ struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan)
{
u16 vlan_tag;
@@ -659,8 +667,9 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
}
+ /* To skip HW VLAN tagging: evt = 1, compl = 0 */
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, !skip_hw_vlan);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
- AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
}
@@ -683,7 +692,8 @@ static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
}
static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
- struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
+ struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb,
+ bool skip_hw_vlan)
{
dma_addr_t busaddr;
int i, copied = 0;
@@ -732,7 +742,7 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
queue_head_inc(txq);
}
- wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied);
+ wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan);
be_dws_cpu_to_le(hdr, sizeof(*hdr));
return copied;
@@ -749,7 +759,8 @@ dma_err:
}
static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
- struct sk_buff *skb)
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
{
u16 vlan_tag = 0;
@@ -759,13 +770,72 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
if (vlan_tx_tag_present(skb)) {
vlan_tag = be_get_tx_vlan_tag(adapter, skb);
- __vlan_put_tag(skb, vlan_tag);
+ skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+ if (skb)
+ skb->vlan_tci = 0;
+ }
+
+ if (qnq_async_evt_rcvd(adapter) && adapter->pvid) {
+ if (!vlan_tag)
+ vlan_tag = adapter->pvid;
+ if (skip_hw_vlan)
+ *skip_hw_vlan = true;
+ }
+
+ if (vlan_tag) {
+ skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+ if (unlikely(!skb))
+ return skb;
+
skb->vlan_tci = 0;
}
+ /* Insert the outer VLAN, if any */
+ if (adapter->qnq_vid) {
+ vlan_tag = adapter->qnq_vid;
+ skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+ if (unlikely(!skb))
+ return skb;
+ if (skip_hw_vlan)
+ *skip_hw_vlan = true;
+ }
+
return skb;
}
+static bool be_ipv6_exthdr_check(struct sk_buff *skb)
+{
+ struct ethhdr *eh = (struct ethhdr *)skb->data;
+ u16 offset = ETH_HLEN;
+
+ if (eh->h_proto == htons(ETH_P_IPV6)) {
+ struct ipv6hdr *ip6h = (struct ipv6hdr *)(skb->data + offset);
+
+ offset += sizeof(struct ipv6hdr);
+ if (ip6h->nexthdr != NEXTHDR_TCP &&
+ ip6h->nexthdr != NEXTHDR_UDP) {
+ struct ipv6_opt_hdr *ehdr =
+ (struct ipv6_opt_hdr *) (skb->data + offset);
+
+ /* offending pkt: 2nd byte following IPv6 hdr is 0xff */
+ if (ehdr->hdrlen == 0xff)
+ return true;
+ }
+ }
+ return false;
+}
+
+static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb)
+{
+ return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid;
+}
+
+static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb)
+{
+ return BE3_chip(adapter) &&
+ be_ipv6_exthdr_check(skb);
+}
+
static netdev_tx_t be_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
@@ -776,33 +846,64 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
u32 wrb_cnt = 0, copied = 0;
u32 start = txq->head, eth_hdr_len;
bool dummy_wrb, stopped = false;
+ bool skip_hw_vlan = false;
+ struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
VLAN_ETH_HLEN : ETH_HLEN;
- /* HW has a bug which considers padding bytes as legal
- * and modifies the IPv4 hdr's 'tot_len' field
+ /* For padded packets, BE HW modifies tot_len field in IP header
+ * incorrecly when VLAN tag is inserted by HW.
*/
- if (skb->len <= 60 && be_vlan_tag_chk(adapter, skb) &&
- is_ipv4_pkt(skb)) {
+ if (skb->len <= 60 && vlan_tx_tag_present(skb) && is_ipv4_pkt(skb)) {
ip = (struct iphdr *)ip_hdr(skb);
pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
}
+ /* If vlan tag is already inlined in the packet, skip HW VLAN
+ * tagging in UMC mode
+ */
+ if ((adapter->function_mode & UMC_ENABLED) &&
+ veh->h_vlan_proto == htons(ETH_P_8021Q))
+ skip_hw_vlan = true;
+
/* HW has a bug wherein it will calculate CSUM for VLAN
* pkts even though it is disabled.
* Manually insert VLAN in pkt.
*/
if (skb->ip_summed != CHECKSUM_PARTIAL &&
- be_vlan_tag_chk(adapter, skb)) {
- skb = be_insert_vlan_in_pkt(adapter, skb);
+ vlan_tx_tag_present(skb)) {
+ skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan);
+ if (unlikely(!skb))
+ goto tx_drop;
+ }
+
+ /* HW may lockup when VLAN HW tagging is requested on
+ * certain ipv6 packets. Drop such pkts if the HW workaround to
+ * skip HW tagging is not enabled by FW.
+ */
+ if (unlikely(be_ipv6_tx_stall_chk(adapter, skb) &&
+ (adapter->pvid || adapter->qnq_vid) &&
+ !qnq_async_evt_rcvd(adapter)))
+ goto tx_drop;
+
+ /* Manual VLAN tag insertion to prevent:
+ * ASIC lockup when the ASIC inserts VLAN tag into
+ * certain ipv6 packets. Insert VLAN tags in driver,
+ * and set event, completion, vlan bits accordingly
+ * in the Tx WRB.
+ */
+ if (be_ipv6_tx_stall_chk(adapter, skb) &&
+ be_vlan_tag_tx_chk(adapter, skb)) {
+ skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan);
if (unlikely(!skb))
goto tx_drop;
}
wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
- copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb);
+ copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb,
+ skip_hw_vlan);
if (copied) {
int gso_segs = skb_shinfo(skb)->gso_segs;
@@ -821,7 +922,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
stopped = true;
}
- be_txq_notify(adapter, txq->id, wrb_cnt);
+ be_txq_notify(adapter, txo, wrb_cnt);
be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped);
} else {
@@ -890,7 +991,7 @@ set_vlan_promisc:
return status;
}
-static int be_vlan_add_vid(struct net_device *netdev, u16 vid)
+static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
@@ -916,7 +1017,7 @@ ret:
return status;
}
-static int be_vlan_rem_vid(struct net_device *netdev, u16 vid)
+static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status = 0;
@@ -1371,7 +1472,7 @@ static void be_rx_compl_process(struct be_rx_obj *rxo,
if (rxcp->vlanf)
- __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rxcp->vlan_tag);
netif_receive_skb(skb);
}
@@ -1427,7 +1528,7 @@ void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct napi_struct *napi,
skb->rxhash = rxcp->rss_hash;
if (rxcp->vlanf)
- __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rxcp->vlan_tag);
napi_gro_frags(napi);
}
@@ -1957,7 +2058,7 @@ static int be_tx_qs_create(struct be_adapter *adapter)
if (status)
return status;
- status = be_cmd_txq_create(adapter, &txo->q, &txo->cq);
+ status = be_cmd_txq_create(adapter, txo);
if (status)
return status;
}
@@ -2435,9 +2536,6 @@ static int be_close(struct net_device *netdev)
be_roce_dev_close(adapter);
- if (!lancer_chip(adapter))
- be_intr_set(adapter, false);
-
for_all_evt_queues(adapter, eqo, i)
napi_disable(&eqo->napi);
@@ -2499,9 +2597,19 @@ static int be_rx_qs_create(struct be_adapter *adapter)
rsstable[j + i] = rxo->rss_id;
}
}
- rc = be_cmd_rss_config(adapter, rsstable, 128);
- if (rc)
+ adapter->rss_flags = RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 |
+ RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6;
+
+ if (!BEx_chip(adapter))
+ adapter->rss_flags |= RSS_ENABLE_UDP_IPV4 |
+ RSS_ENABLE_UDP_IPV6;
+
+ rc = be_cmd_rss_config(adapter, rsstable, adapter->rss_flags,
+ 128);
+ if (rc) {
+ adapter->rss_flags = 0;
return rc;
+ }
}
/* First time posting */
@@ -2525,9 +2633,6 @@ static int be_open(struct net_device *netdev)
be_irq_register(adapter);
- if (!lancer_chip(adapter))
- be_intr_set(adapter, true);
-
for_all_rx_queues(adapter, rxo, i)
be_cq_notify(adapter, rxo->cq.id, true, 0);
@@ -2562,10 +2667,9 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config);
cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (cmd.va == NULL)
return -1;
- memset(cmd.va, 0, cmd.size);
if (enable) {
status = pci_write_config_dword(adapter->pdev,
@@ -2713,7 +2817,8 @@ static int be_vfs_if_create(struct be_adapter *adapter)
for_all_vfs(adapter, vf_cfg, vf) {
if (!BE3_chip(adapter))
- be_cmd_get_profile_config(adapter, &cap_flags, vf + 1);
+ be_cmd_get_profile_config(adapter, &cap_flags,
+ NULL, vf + 1);
/* If a FW profile exists, then cap_flags are updated */
en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
@@ -2877,11 +2982,14 @@ static void be_get_resources(struct be_adapter *adapter)
u16 dev_num_vfs;
int pos, status;
bool profile_present = false;
+ u16 txq_count = 0;
if (!BEx_chip(adapter)) {
status = be_cmd_get_func_config(adapter);
if (!status)
profile_present = true;
+ } else if (BE3_chip(adapter) && be_physfn(adapter)) {
+ be_cmd_get_profile_config(adapter, NULL, &txq_count, 0);
}
if (profile_present) {
@@ -2919,7 +3027,9 @@ static void be_get_resources(struct be_adapter *adapter)
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;
adapter->max_mcast_mac = BE_MAX_MC;
- adapter->max_tx_queues = MAX_TX_QS;
+ adapter->max_tx_queues = txq_count ? txq_count : MAX_TX_QS;
+ adapter->max_tx_queues = min_t(u16, adapter->max_tx_queues,
+ MAX_TX_QS);
adapter->max_rss_queues = (adapter->be3_native) ?
BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
adapter->max_event_queues = BE3_MAX_RSS_QS;
@@ -2953,7 +3063,8 @@ static int be_get_config(struct be_adapter *adapter)
status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
&adapter->function_mode,
- &adapter->function_caps);
+ &adapter->function_caps,
+ &adapter->asic_rev);
if (status)
goto err;
@@ -3214,7 +3325,7 @@ static int be_flash(struct be_adapter *adapter, const u8 *img,
return 0;
}
-/* For BE2 and BE3 */
+/* For BE2, BE3 and BE3-R */
static int be_flash_BEx(struct be_adapter *adapter,
const struct firmware *fw,
struct be_dma_mem *flash_cmd,
@@ -3457,11 +3568,9 @@ static int lancer_fw_download(struct be_adapter *adapter,
flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
+ LANCER_FW_DOWNLOAD_CHUNK;
flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
- &flash_cmd.dma, GFP_KERNEL);
+ &flash_cmd.dma, GFP_KERNEL);
if (!flash_cmd.va) {
status = -ENOMEM;
- dev_err(&adapter->pdev->dev,
- "Memory allocation failure while flashing\n");
goto lancer_fw_exit;
}
@@ -3529,18 +3638,22 @@ lancer_fw_exit:
#define UFI_TYPE2 2
#define UFI_TYPE3 3
+#define UFI_TYPE3R 10
#define UFI_TYPE4 4
static int be_get_ufi_type(struct be_adapter *adapter,
- struct flash_file_hdr_g2 *fhdr)
+ struct flash_file_hdr_g3 *fhdr)
{
if (fhdr == NULL)
goto be_get_ufi_exit;
if (skyhawk_chip(adapter) && fhdr->build[0] == '4')
return UFI_TYPE4;
- else if (BE3_chip(adapter) && fhdr->build[0] == '3')
- return UFI_TYPE3;
- else if (BE2_chip(adapter) && fhdr->build[0] == '2')
+ else if (BE3_chip(adapter) && fhdr->build[0] == '3') {
+ if (fhdr->asic_type_rev == 0x10)
+ return UFI_TYPE3R;
+ else
+ return UFI_TYPE3;
+ } else if (BE2_chip(adapter) && fhdr->build[0] == '2')
return UFI_TYPE2;
be_get_ufi_exit:
@@ -3551,7 +3664,6 @@ be_get_ufi_exit:
static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
{
- struct flash_file_hdr_g2 *fhdr;
struct flash_file_hdr_g3 *fhdr3;
struct image_hdr *img_hdr_ptr = NULL;
struct be_dma_mem flash_cmd;
@@ -3563,29 +3675,41 @@ static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
&flash_cmd.dma, GFP_KERNEL);
if (!flash_cmd.va) {
status = -ENOMEM;
- dev_err(&adapter->pdev->dev,
- "Memory allocation failure while flashing\n");
goto be_fw_exit;
}
p = fw->data;
- fhdr = (struct flash_file_hdr_g2 *)p;
+ fhdr3 = (struct flash_file_hdr_g3 *)p;
- ufi_type = be_get_ufi_type(adapter, fhdr);
+ ufi_type = be_get_ufi_type(adapter, fhdr3);
- fhdr3 = (struct flash_file_hdr_g3 *)fw->data;
num_imgs = le32_to_cpu(fhdr3->num_imgs);
for (i = 0; i < num_imgs; i++) {
img_hdr_ptr = (struct image_hdr *)(fw->data +
(sizeof(struct flash_file_hdr_g3) +
i * sizeof(struct image_hdr)));
if (le32_to_cpu(img_hdr_ptr->imageid) == 1) {
- if (ufi_type == UFI_TYPE4)
+ switch (ufi_type) {
+ case UFI_TYPE4:
status = be_flash_skyhawk(adapter, fw,
&flash_cmd, num_imgs);
- else if (ufi_type == UFI_TYPE3)
+ break;
+ case UFI_TYPE3R:
status = be_flash_BEx(adapter, fw, &flash_cmd,
num_imgs);
+ break;
+ case UFI_TYPE3:
+ /* Do not flash this ufi on BE3-R cards */
+ if (adapter->asic_rev < 0x10)
+ status = be_flash_BEx(adapter, fw,
+ &flash_cmd,
+ num_imgs);
+ else {
+ status = -1;
+ dev_err(&adapter->pdev->dev,
+ "Can't load BE3 UFI on BE3R\n");
+ }
+ }
}
}
@@ -3662,12 +3786,12 @@ static void be_netdev_init(struct net_device *netdev)
netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_TX;
if (be_multi_rxq(adapter))
netdev->hw_features |= NETIF_F_RXHASH;
netdev->features |= netdev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
@@ -3791,12 +3915,13 @@ static int be_ctrl_init(struct be_adapter *adapter)
rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
rx_filter->va = dma_alloc_coherent(&adapter->pdev->dev, rx_filter->size,
- &rx_filter->dma, GFP_KERNEL);
+ &rx_filter->dma,
+ GFP_KERNEL | __GFP_ZERO);
if (rx_filter->va == NULL) {
status = -ENOMEM;
goto free_mbox;
}
- memset(rx_filter->va, 0, rx_filter->size);
+
mutex_init(&adapter->mbox_lock);
spin_lock_init(&adapter->mcc_lock);
spin_lock_init(&adapter->mcc_cq_lock);
@@ -3838,10 +3963,9 @@ static int be_stats_init(struct be_adapter *adapter)
cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (cmd->va == NULL)
return -1;
- memset(cmd->va, 0, cmd->size);
return 0;
}
@@ -3853,6 +3977,7 @@ static void be_remove(struct pci_dev *pdev)
return;
be_roce_dev_remove(adapter);
+ be_intr_set(adapter, false);
cancel_delayed_work_sync(&adapter->func_recovery_work);
@@ -4107,6 +4232,11 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (!status) {
+ status = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (status < 0) {
+ dev_err(&pdev->dev, "dma_set_coherent_mask failed\n");
+ goto free_netdev;
+ }
netdev->features |= NETIF_F_HIGHDMA;
} else {
status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
@@ -4131,22 +4261,22 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
goto ctrl_clean;
}
- /* tell fw we're ready to fire cmds */
- status = be_cmd_fw_init(adapter);
- if (status)
- goto ctrl_clean;
-
if (be_reset_required(adapter)) {
status = be_cmd_reset_function(adapter);
if (status)
goto ctrl_clean;
+
+ /* Wait for interrupts to quiesce after an FLR */
+ msleep(100);
}
- /* The INTR bit may be set in the card when probed by a kdump kernel
- * after a crash.
- */
- if (!lancer_chip(adapter))
- be_intr_set(adapter, false);
+ /* Allow interrupts for other ULPs running on NIC function */
+ be_intr_set(adapter, true);
+
+ /* tell fw we're ready to fire cmds */
+ status = be_cmd_fw_init(adapter);
+ if (status)
+ goto ctrl_clean;
status = be_stats_init(adapter);
if (status)
@@ -4357,12 +4487,12 @@ static void be_eeh_resume(struct pci_dev *pdev)
pci_save_state(pdev);
- /* tell fw we're ready to fire cmds */
- status = be_cmd_fw_init(adapter);
+ status = be_cmd_reset_function(adapter);
if (status)
goto err;
- status = be_cmd_reset_function(adapter);
+ /* tell fw we're ready to fire cmds */
+ status = be_cmd_fw_init(adapter);
if (status)
goto err;
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c
index 55d32aa0a093..f3d126dcc104 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.c
+++ b/drivers/net/ethernet/emulex/benet/be_roce.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h
index db4ea8081c07..276572998463 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.h
+++ b/drivers/net/ethernet/emulex/benet/be_roce.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 - 2011 Emulex
+ * Copyright (C) 2005 - 2013 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 7c361d1db94c..21b85fb7d05f 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -780,12 +780,11 @@ static int ftgmac100_alloc_buffers(struct ftgmac100 *priv)
priv->descs = dma_alloc_coherent(priv->dev,
sizeof(struct ftgmac100_descs),
- &priv->descs_dma_addr, GFP_KERNEL);
+ &priv->descs_dma_addr,
+ GFP_KERNEL | __GFP_ZERO);
if (!priv->descs)
return -ENOMEM;
- memset(priv->descs, 0, sizeof(struct ftgmac100_descs));
-
/* initialize RX ring */
ftgmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
@@ -1350,22 +1349,7 @@ static struct platform_driver ftgmac100_driver = {
},
};
-/******************************************************************************
- * initialization / finalization
- *****************************************************************************/
-static int __init ftgmac100_init(void)
-{
- pr_info("Loading version " DRV_VERSION " ...\n");
- return platform_driver_register(&ftgmac100_driver);
-}
-
-static void __exit ftgmac100_exit(void)
-{
- platform_driver_unregister(&ftgmac100_driver);
-}
-
-module_init(ftgmac100_init);
-module_exit(ftgmac100_exit);
+module_platform_driver(ftgmac100_driver);
MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>");
MODULE_DESCRIPTION("FTGMAC100 driver");
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index b5ea8fbd8a76..a6eda8d83138 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -732,13 +732,13 @@ static int ftmac100_alloc_buffers(struct ftmac100 *priv)
{
int i;
- priv->descs = dma_alloc_coherent(priv->dev, sizeof(struct ftmac100_descs),
- &priv->descs_dma_addr, GFP_KERNEL);
+ priv->descs = dma_alloc_coherent(priv->dev,
+ sizeof(struct ftmac100_descs),
+ &priv->descs_dma_addr,
+ GFP_KERNEL | __GFP_ZERO);
if (!priv->descs)
return -ENOMEM;
- memset(priv->descs, 0, sizeof(struct ftmac100_descs));
-
/* initialize RX ring */
ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]);
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index b7d58fe6f531..549ce13b92ac 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -2,7 +2,8 @@
# Makefile for the Freescale network device drivers.
#
-obj-$(CONFIG_FEC) += fec.o fec_ptp.o
+obj-$(CONFIG_FEC) += fec.o
+fec-objs :=fec_main.o fec_ptp.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index eb4372962839..d44f65bac1d4 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -52,6 +52,7 @@
#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
+#define FEC_RACC 0x1C4 /* Receive Accelerator function */
#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
@@ -164,9 +165,11 @@ struct bufdesc_ex {
#define BD_ENET_TX_CSL ((ushort)0x0001)
#define BD_ENET_TX_STATS ((ushort)0x03ff) /* All status bits */
-/*enhanced buffer desciptor control/status used by Ethernet transmit*/
+/*enhanced buffer descriptor control/status used by Ethernet transmit*/
#define BD_ENET_TX_INT 0x40000000
#define BD_ENET_TX_TS 0x20000000
+#define BD_ENET_TX_PINS 0x10000000
+#define BD_ENET_TX_IINS 0x08000000
/* This device has up to three irqs on some platforms */
@@ -190,6 +193,10 @@ struct bufdesc_ex {
#define BD_ENET_RX_INT 0x00800000
#define BD_ENET_RX_PTP ((ushort)0x0400)
+#define BD_ENET_RX_ICE 0x00000020
+#define BD_ENET_RX_PCR 0x00000010
+#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
+#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
* tx_bd_base always point to the base of the buffer descriptors. The
@@ -247,6 +254,7 @@ struct fec_enet_private {
int pause_flag;
struct napi_struct napi;
+ int csum_flags;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps;
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec_main.c
index 911d0253dbb2..b9748f14ea78 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -29,12 +29,17 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
@@ -53,11 +58,6 @@
#include <asm/cacheflush.h>
-#ifndef CONFIG_ARM
-#include <asm/coldfire.h>
-#include <asm/mcfsim.h>
-#endif
-
#include "fec.h"
#if defined(CONFIG_ARM)
@@ -107,6 +107,9 @@ static struct platform_device_id fec_devtype[] = {
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
FEC_QUIRK_HAS_BUFDESC_EX,
}, {
+ .name = "mvf-fec",
+ .driver_data = FEC_QUIRK_ENET_MAC,
+ }, {
/* sentinel */
}
};
@@ -117,6 +120,7 @@ enum imx_fec_type {
IMX27_FEC, /* runs on i.mx27/35/51 */
IMX28_FEC,
IMX6Q_FEC,
+ MVF_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
@@ -124,6 +128,7 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
+ { .compatible = "fsl,mvf-fec", .data = &fec_devtype[MVF_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -177,6 +182,11 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define PKT_MINBUF_SIZE 64
#define PKT_MAXBLR_SIZE 1520
+/* FEC receive acceleration */
+#define FEC_RACC_IPDIS (1 << 1)
+#define FEC_RACC_PRODIS (1 << 2)
+#define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS)
+
/*
* The 5270/5271/5280/5282/532x RX control register also contains maximum frame
* size bits. Other FEC hardware does not, so we need to take that into
@@ -237,6 +247,21 @@ static void *swap_buffer(void *bufaddr, int len)
return bufaddr;
}
+static int
+fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
+{
+ /* Only run for packets requiring a checksum. */
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
+ if (unlikely(skb_cow_head(skb, 0)))
+ return -1;
+
+ *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) = 0;
+
+ return 0;
+}
+
static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
@@ -249,7 +274,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
unsigned int index;
if (!fep->link) {
- /* Link is down or autonegotiation is in progress. */
+ /* Link is down or auto-negotiation is in progress. */
return NETDEV_TX_BUSY;
}
@@ -262,10 +287,16 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since ndev->tbusy should be set.
*/
- printk("%s: tx queue full!.\n", ndev->name);
+ netdev_err(ndev, "tx queue full!\n");
return NETDEV_TX_BUSY;
}
+ /* Protocol checksum off-load for TCP and UDP. */
+ if (fec_enet_clear_csum(skb, ndev)) {
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
/* Clear all of the status flags */
status &= ~BD_ENET_TX_STATS;
@@ -322,8 +353,14 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
} else {
-
ebdp->cbd_esc = BD_ENET_TX_INT;
+
+ /* Enable protocol checksum flags
+ * We do not bother with the IP Checksum bits as they
+ * are done by the kernel
+ */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ ebdp->cbd_esc |= BD_ENET_TX_PINS;
}
}
/* If this was the last BD in the ring, start at the beginning again. */
@@ -345,6 +382,53 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NETDEV_TX_OK;
}
+/* Init RX & TX buffer descriptors
+ */
+static void fec_enet_bd_init(struct net_device *dev)
+{
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct bufdesc *bdp;
+ unsigned int i;
+
+ /* Initialize the receive buffer descriptors. */
+ bdp = fep->rx_bd_base;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page. */
+ if (bdp->cbd_bufaddr)
+ bdp->cbd_sc = BD_ENET_RX_EMPTY;
+ else
+ bdp->cbd_sc = 0;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
+ }
+
+ /* Set the last buffer to wrap */
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ fep->cur_rx = fep->rx_bd_base;
+
+ /* ...and the same for transmit */
+ bdp = fep->tx_bd_base;
+ fep->cur_tx = bdp;
+ for (i = 0; i < TX_RING_SIZE; i++) {
+
+ /* Initialize the BD for every fragment in the page. */
+ bdp->cbd_sc = 0;
+ if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) {
+ dev_kfree_skb_any(fep->tx_skbuff[i]);
+ fep->tx_skbuff[i] = NULL;
+ }
+ bdp->cbd_bufaddr = 0;
+ bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
+ }
+
+ /* Set the last buffer to wrap */
+ bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+ bdp->cbd_sc |= BD_SC_WRAP;
+ fep->dirty_tx = bdp;
+}
+
/* This function is called to start or restart the FEC during a link
* change. This only happens when switching between half and full
* duplex.
@@ -356,6 +440,7 @@ fec_restart(struct net_device *ndev, int duplex)
const struct platform_device_id *id_entry =
platform_get_device_id(fep->pdev);
int i;
+ u32 val;
u32 temp_mac[2];
u32 rcntl = OPT_FRAME_SIZE | 0x04;
u32 ecntl = 0x2; /* ETHEREN */
@@ -388,6 +473,8 @@ fec_restart(struct net_device *ndev, int duplex)
/* Set maximum receive buffer size. */
writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
+ fec_enet_bd_init(ndev);
+
/* Set receive and transmit descriptor base. */
writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
if (fep->bufdesc_ex)
@@ -397,7 +484,6 @@ fec_restart(struct net_device *ndev, int duplex)
writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
* RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
- fep->cur_rx = fep->rx_bd_base;
for (i = 0; i <= TX_RING_MOD_MASK; i++) {
if (fep->tx_skbuff[i]) {
@@ -421,6 +507,14 @@ fec_restart(struct net_device *ndev, int duplex)
/* Set MII speed */
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
+ /* set RX checksum */
+ val = readl(fep->hwp + FEC_RACC);
+ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
+ val |= FEC_RACC_OPTIONS;
+ else
+ val &= ~FEC_RACC_OPTIONS;
+ writel(val, fep->hwp + FEC_RACC);
+
/*
* The phy interface and speed need to get configured
* differently on enet-mac.
@@ -478,7 +572,7 @@ fec_restart(struct net_device *ndev, int duplex)
fep->phy_dev && fep->phy_dev->pause)) {
rcntl |= FEC_ENET_FCE;
- /* set FIFO thresh hold parameter to reduce overrun */
+ /* set FIFO threshold parameter to reduce overrun */
writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
@@ -526,7 +620,7 @@ fec_stop(struct net_device *ndev)
writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
udelay(10);
if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
- printk("fec_stop : Graceful transmit stop did not complete !\n");
+ netdev_err(ndev, "Graceful transmit stop did not complete!\n");
}
/* Whack a reset. We should wait for this. */
@@ -624,7 +718,7 @@ fec_enet_tx(struct net_device *ndev)
}
if (status & BD_ENET_TX_READY)
- printk("HEY! Enet xmit interrupt and TX_READY.\n");
+ netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n");
/* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK.
@@ -692,7 +786,7 @@ fec_enet_rx(struct net_device *ndev, int budget)
* the last indicator should be set.
*/
if ((status & BD_ENET_RX_LAST) == 0)
- printk("FEC ENET: rcv is not +last\n");
+ netdev_err(ndev, "rcv is not +last\n");
if (!fep->opened)
goto rx_processing_done;
@@ -743,8 +837,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
skb = netdev_alloc_skb(ndev, pkt_len - 4 + NET_IP_ALIGN);
if (unlikely(!skb)) {
- printk("%s: Memory squeeze, dropping packet.\n",
- ndev->name);
ndev->stats.rx_dropped++;
} else {
skb_reserve(skb, NET_IP_ALIGN);
@@ -768,6 +860,18 @@ fec_enet_rx(struct net_device *ndev, int budget)
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
}
+ if (fep->bufdesc_ex &&
+ (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
+ struct bufdesc_ex *ebdp =
+ (struct bufdesc_ex *)bdp;
+ if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
+ /* don't check it */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb_checksum_none_assert(skb);
+ }
+ }
+
if (!skb_defer_rx_timestamp(skb))
napi_gro_receive(&fep->napi, skb);
}
@@ -868,7 +972,6 @@ static void fec_get_mac(struct net_device *ndev)
*/
iap = macaddr;
-#ifdef CONFIG_OF
/*
* 2) from device tree data
*/
@@ -880,7 +983,6 @@ static void fec_get_mac(struct net_device *ndev)
iap = (unsigned char *) mac;
}
}
-#endif
/*
* 3) from flash or fuse (via platform data)
@@ -954,6 +1056,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
} else {
if (fep->link) {
fec_stop(ndev);
+ fep->link = phy_dev->link;
status_change = 1;
}
}
@@ -983,7 +1086,7 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
usecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
fep->mii_timeout = 1;
- printk(KERN_ERR "FEC: MDIO read timeout\n");
+ netdev_err(fep->netdev, "MDIO read timeout\n");
return -ETIMEDOUT;
}
@@ -1011,7 +1114,7 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
usecs_to_jiffies(FEC_MII_TIMEOUT));
if (time_left == 0) {
fep->mii_timeout = 1;
- printk(KERN_ERR "FEC: MDIO write timeout\n");
+ netdev_err(fep->netdev, "MDIO write timeout\n");
return -ETIMEDOUT;
}
@@ -1051,9 +1154,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
}
if (phy_id >= PHY_MAX_ADDR) {
- printk(KERN_INFO
- "%s: no PHY, assuming direct connection to switch\n",
- ndev->name);
+ netdev_info(ndev, "no PHY, assuming direct connection to switch\n");
strncpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);
phy_id = 0;
}
@@ -1062,7 +1163,7 @@ static int fec_enet_mii_probe(struct net_device *ndev)
phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
fep->phy_interface);
if (IS_ERR(phy_dev)) {
- printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name);
+ netdev_err(ndev, "could not attach to PHY\n");
return PTR_ERR(phy_dev);
}
@@ -1080,11 +1181,9 @@ static int fec_enet_mii_probe(struct net_device *ndev)
fep->link = 0;
fep->full_duplex = 0;
- printk(KERN_INFO
- "%s: Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
- ndev->name,
- fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
- fep->phy_dev->irq);
+ netdev_info(ndev, "Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+ fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
+ fep->phy_dev->irq);
return 0;
}
@@ -1394,7 +1493,7 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
if (fep->bufdesc_ex) {
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
- ebdp->cbd_esc = BD_ENET_RX_INT;
+ ebdp->cbd_esc = BD_ENET_TX_INT;
}
bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
@@ -1559,7 +1658,7 @@ fec_set_mac_address(struct net_device *ndev, void *p)
* Polled functionality used by netconsole and others in non interrupt mode
*
*/
-void fec_poll_controller(struct net_device *dev)
+static void fec_poll_controller(struct net_device *dev)
{
int i;
struct fec_enet_private *fep = netdev_priv(dev);
@@ -1574,6 +1673,33 @@ void fec_poll_controller(struct net_device *dev)
}
#endif
+static int fec_set_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ struct fec_enet_private *fep = netdev_priv(netdev);
+ netdev_features_t changed = features ^ netdev->features;
+
+ netdev->features = features;
+
+ /* Receive checksum has been changed */
+ if (changed & NETIF_F_RXCSUM) {
+ if (features & NETIF_F_RXCSUM)
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+ else
+ fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev)) {
+ fec_stop(netdev);
+ fec_restart(netdev, fep->phy_dev->duplex);
+ netif_wake_queue(netdev);
+ } else {
+ fec_restart(netdev, fep->phy_dev->duplex);
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops fec_netdev_ops = {
.ndo_open = fec_enet_open,
.ndo_stop = fec_enet_close,
@@ -1587,6 +1713,7 @@ static const struct net_device_ops fec_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = fec_poll_controller,
#endif
+ .ndo_set_features = fec_set_features,
};
/*
@@ -1597,17 +1724,14 @@ static int fec_enet_init(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
struct bufdesc *cbd_base;
- struct bufdesc *bdp;
- unsigned int i;
/* Allocate memory for buffer descriptors. */
cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
- GFP_KERNEL);
- if (!cbd_base) {
- printk("FEC: allocate descriptor memory failed?\n");
+ GFP_KERNEL);
+ if (!cbd_base)
return -ENOMEM;
- }
+ memset(cbd_base, 0, PAGE_SIZE);
spin_lock_init(&fep->hw_lock);
fep->netdev = ndev;
@@ -1631,34 +1755,12 @@ static int fec_enet_init(struct net_device *ndev)
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
- /* Initialize the receive buffer descriptors. */
- bdp = fep->rx_bd_base;
- for (i = 0; i < RX_RING_SIZE; i++) {
-
- /* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
- }
-
- /* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
- bdp->cbd_sc |= BD_SC_WRAP;
-
- /* ...and the same for transmit */
- bdp = fep->tx_bd_base;
- fep->cur_tx = bdp;
- for (i = 0; i < TX_RING_SIZE; i++) {
-
- /* Initialize the BD for every fragment in the page. */
- bdp->cbd_sc = 0;
- bdp->cbd_bufaddr = 0;
- bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
- }
-
- /* Set the last buffer to wrap */
- bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
- bdp->cbd_sc |= BD_SC_WRAP;
- fep->dirty_tx = bdp;
+ /* enable hw accelerator */
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
fec_restart(ndev, 0);
@@ -1666,16 +1768,6 @@ static int fec_enet_init(struct net_device *ndev)
}
#ifdef CONFIG_OF
-static int fec_get_phy_mode_dt(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (np)
- return of_get_phy_mode(np);
-
- return -ENODEV;
-}
-
static void fec_reset_phy(struct platform_device *pdev)
{
int err, phy_reset;
@@ -1704,11 +1796,6 @@ static void fec_reset_phy(struct platform_device *pdev)
gpio_set_value(phy_reset, 1);
}
#else /* CONFIG_OF */
-static int fec_get_phy_mode_dt(struct platform_device *pdev)
-{
- return -ENODEV;
-}
-
static void fec_reset_phy(struct platform_device *pdev)
{
/*
@@ -1739,16 +1826,10 @@ fec_probe(struct platform_device *pdev)
if (!r)
return -ENXIO;
- r = request_mem_region(r->start, resource_size(r), pdev->name);
- if (!r)
- return -EBUSY;
-
/* Init network device */
ndev = alloc_etherdev(sizeof(struct fec_enet_private));
- if (!ndev) {
- ret = -ENOMEM;
- goto failed_alloc_etherdev;
- }
+ if (!ndev)
+ return -ENOMEM;
SET_NETDEV_DEV(ndev, &pdev->dev);
@@ -1760,7 +1841,7 @@ fec_probe(struct platform_device *pdev)
(pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
- fep->hwp = ioremap(r->start, resource_size(r));
+ fep->hwp = devm_request_and_ioremap(&pdev->dev, r);
fep->pdev = pdev;
fep->dev_id = dev_id++;
@@ -1773,7 +1854,7 @@ fec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
- ret = fec_get_phy_mode_dt(pdev);
+ ret = of_get_phy_mode(pdev->dev.of_node);
if (ret < 0) {
pdata = pdev->dev.platform_data;
if (pdata)
@@ -1863,6 +1944,9 @@ fec_probe(struct platform_device *pdev)
if (ret)
goto failed_register;
+ if (fep->bufdesc_ex && fep->ptp_clock)
+ netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
+
return 0;
failed_register:
@@ -1882,11 +1966,8 @@ failed_regulator:
clk_disable_unprepare(fep->clk_ptp);
failed_pin:
failed_clk:
- iounmap(fep->hwp);
failed_ioremap:
free_netdev(ndev);
-failed_alloc_etherdev:
- release_mem_region(r->start, resource_size(r));
return ret;
}
@@ -1896,7 +1977,6 @@ fec_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
- struct resource *r;
int i;
unregister_netdev(ndev);
@@ -1912,19 +1992,14 @@ fec_drv_remove(struct platform_device *pdev)
if (irq > 0)
free_irq(irq, ndev);
}
- iounmap(fep->hwp);
free_netdev(ndev);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- BUG_ON(!r);
- release_mem_region(r->start, resource_size(r));
-
platform_set_drvdata(pdev, NULL);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int
fec_suspend(struct device *dev)
{
@@ -1956,24 +2031,15 @@ fec_resume(struct device *dev)
return 0;
}
+#endif /* CONFIG_PM_SLEEP */
-static const struct dev_pm_ops fec_pm_ops = {
- .suspend = fec_suspend,
- .resume = fec_resume,
- .freeze = fec_suspend,
- .thaw = fec_resume,
- .poweroff = fec_suspend,
- .restore = fec_resume,
-};
-#endif
+static SIMPLE_DEV_PM_OPS(fec_pm_ops, fec_suspend, fec_resume);
static struct platform_driver fec_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &fec_pm_ops,
-#endif
.of_match_table = fec_dt_ids,
},
.id_table = fec_devtype,
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index 77943a6a1b8c..9bc15e2365bb 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -14,6 +14,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/dma-mapping.h>
#include <linux/module.h>
@@ -858,13 +860,11 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* Reserve FEC control zone */
rv = of_address_to_resource(np, 0, &mem);
if (rv) {
- printk(KERN_ERR DRIVER_NAME ": "
- "Error while parsing device node resource\n" );
+ pr_err("Error while parsing device node resource\n");
goto err_netdev;
}
if (resource_size(&mem) < sizeof(struct mpc52xx_fec)) {
- printk(KERN_ERR DRIVER_NAME
- " - invalid resource size (%lx < %x), check mpc52xx_devices.c\n",
+ pr_err("invalid resource size (%lx < %x), check mpc52xx_devices.c\n",
(unsigned long)resource_size(&mem),
sizeof(struct mpc52xx_fec));
rv = -EINVAL;
@@ -902,7 +902,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)
priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
- printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
+ pr_err("Can not init SDMA tasks\n");
rv = -ENOMEM;
goto err_rx_tx_dmatsk;
}
@@ -982,8 +982,8 @@ static int mpc52xx_fec_probe(struct platform_device *op)
/* We're done ! */
dev_set_drvdata(&op->dev, ndev);
- printk(KERN_INFO "%s: %s MAC %pM\n",
- ndev->name, op->dev.of_node->full_name, ndev->dev_addr);
+ netdev_info(ndev, "%s MAC %pM\n",
+ op->dev.of_node->full_name, ndev->dev_addr);
return 0;
@@ -1094,7 +1094,7 @@ mpc52xx_fec_init(void)
int ret;
ret = platform_driver_register(&mpc52xx_fec_mdio_driver);
if (ret) {
- printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n");
+ pr_err("failed to register mdio driver\n");
return ret;
}
#endif
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 0d8df400a479..25fc960cbf0e 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -17,6 +17,8 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -128,7 +130,6 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
}
-EXPORT_SYMBOL(fec_ptp_start_cyclecounter);
/**
* fec_ptp_adjfreq - adjust ptp cycle frequency
@@ -319,7 +320,6 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0;
}
-EXPORT_SYMBOL(fec_ptp_ioctl);
/**
* fec_time_keep - call timecounter_read every second to avoid timer overrun
@@ -381,8 +381,5 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)
if (IS_ERR(fep->ptp_clock)) {
fep->ptp_clock = NULL;
pr_err("ptp_clock_register failed\n");
- } else {
- pr_info("registered PHC device on %s\n", ndev->name);
}
}
-EXPORT_SYMBOL(fec_ptp_init);
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 46df28893c10..edc120094c34 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -177,8 +177,6 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
received++;
netif_receive_skb(skb);
} else {
- dev_warn(fep->dev,
- "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -309,8 +307,6 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
received++;
netif_rx(skb);
} else {
- dev_warn(fep->dev,
- "Memory squeeze, dropping packet.\n");
fep->stats.rx_dropped++;
skbn = skb;
}
@@ -505,11 +501,9 @@ void fs_init_bds(struct net_device *dev)
*/
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
skb = netdev_alloc_skb(dev, ENET_RX_FRSIZE);
- if (skb == NULL) {
- dev_warn(fep->dev,
- "Memory squeeze, unable to allocate skb\n");
+ if (skb == NULL)
break;
- }
+
skb_align(skb, ENET_RX_ALIGN);
fep->rx_skbuff[i] = skb;
CBDW_BUFADDR(bdp,
@@ -593,13 +587,8 @@ static struct sk_buff *tx_skb_align_workaround(struct net_device *dev,
/* Alloc new skb */
new_skb = netdev_alloc_skb(dev, skb->len + 4);
- if (!new_skb) {
- if (net_ratelimit()) {
- dev_warn(fep->dev,
- "Memory squeeze, dropping tx packet.\n");
- }
+ if (!new_skb)
return NULL;
- }
/* Make sure new skb is properly aligned */
skb_align(new_skb, 4);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index d2c5441d1bf0..2375a01715a0 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -132,7 +132,7 @@ static int gfar_poll(struct napi_struct *napi, int budget);
static void gfar_netpoll(struct net_device *dev);
#endif
int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
-static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
+static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
int amount_pull, struct napi_struct *napi);
void gfar_halt(struct net_device *dev);
@@ -245,14 +245,13 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
/* Allocate memory for the buffer descriptors */
vaddr = dma_alloc_coherent(dev,
- sizeof(struct txbd8) * priv->total_tx_ring_size +
- sizeof(struct rxbd8) * priv->total_rx_ring_size,
- &addr, GFP_KERNEL);
- if (!vaddr) {
- netif_err(priv, ifup, ndev,
- "Could not allocate buffer descriptors!\n");
+ (priv->total_tx_ring_size *
+ sizeof(struct txbd8)) +
+ (priv->total_rx_ring_size *
+ sizeof(struct rxbd8)),
+ &addr, GFP_KERNEL);
+ if (!vaddr)
return -ENOMEM;
- }
for (i = 0; i < priv->num_tx_queues; i++) {
tx_queue = priv->tx_queue[i];
@@ -342,7 +341,7 @@ static void gfar_init_mac(struct net_device *ndev)
gfar_init_tx_rx_base(priv);
/* Configure the coalescing support */
- gfar_configure_coalescing(priv, 0xFF, 0xFF);
+ gfar_configure_coalescing_all(priv);
/* set this when rx hw offload (TOE) functions are being used */
priv->uses_rxfcb = 0;
@@ -387,7 +386,7 @@ static void gfar_init_mac(struct net_device *ndev)
priv->uses_rxfcb = 1;
}
- if (ndev->features & NETIF_F_HW_VLAN_RX) {
+ if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) {
rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
priv->uses_rxfcb = 1;
}
@@ -691,7 +690,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
}
for (i = 0; i < priv->num_tx_queues; i++)
- priv->tx_queue[i] = NULL;
+ priv->tx_queue[i] = NULL;
for (i = 0; i < priv->num_rx_queues; i++)
priv->rx_queue[i] = NULL;
@@ -1051,8 +1050,9 @@ static int gfar_probe(struct platform_device *ofdev)
}
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
- dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- dev->features |= NETIF_F_HW_VLAN_RX;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
}
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
@@ -1817,25 +1817,15 @@ void gfar_start(struct net_device *dev)
dev->trans_start = jiffies; /* prevent tx timeout */
}
-void gfar_configure_coalescing(struct gfar_private *priv,
+static void gfar_configure_coalescing(struct gfar_private *priv,
unsigned long tx_mask, unsigned long rx_mask)
{
struct gfar __iomem *regs = priv->gfargrp[0].regs;
u32 __iomem *baddr;
- int i = 0;
-
- /* Backward compatible case ---- even if we enable
- * multiple queues, there's only single reg to program
- */
- gfar_write(&regs->txic, 0);
- if (likely(priv->tx_queue[0]->txcoalescing))
- gfar_write(&regs->txic, priv->tx_queue[0]->txic);
-
- gfar_write(&regs->rxic, 0);
- if (unlikely(priv->rx_queue[0]->rxcoalescing))
- gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
if (priv->mode == MQ_MG_MODE) {
+ int i = 0;
+
baddr = &regs->txic0;
for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
gfar_write(baddr + i, 0);
@@ -1849,9 +1839,25 @@ void gfar_configure_coalescing(struct gfar_private *priv,
if (likely(priv->rx_queue[i]->rxcoalescing))
gfar_write(baddr + i, priv->rx_queue[i]->rxic);
}
+ } else {
+ /* Backward compatible case -- even if we enable
+ * multiple queues, there's only single reg to program
+ */
+ gfar_write(&regs->txic, 0);
+ if (likely(priv->tx_queue[0]->txcoalescing))
+ gfar_write(&regs->txic, priv->tx_queue[0]->txic);
+
+ gfar_write(&regs->rxic, 0);
+ if (unlikely(priv->rx_queue[0]->rxcoalescing))
+ gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
}
}
+void gfar_configure_coalescing_all(struct gfar_private *priv)
+{
+ gfar_configure_coalescing(priv, 0xFF, 0xFF);
+}
+
static int register_grp_irqs(struct gfar_priv_grp *grp)
{
struct gfar_private *priv = grp->priv;
@@ -1941,7 +1947,7 @@ int startup_gfar(struct net_device *ndev)
phy_start(priv->phydev);
- gfar_configure_coalescing(priv, 0xFF, 0xFF);
+ gfar_configure_coalescing_all(priv);
return 0;
@@ -2343,7 +2349,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
local_irq_save(flags);
lock_rx_qs(priv);
- if (features & NETIF_F_HW_VLAN_TX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_TX) {
/* Enable VLAN tag insertion */
tempval = gfar_read(&regs->tctrl);
tempval |= TCTRL_VLINS;
@@ -2355,7 +2361,7 @@ void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
gfar_write(&regs->tctrl, tempval);
}
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* Enable VLAN tag extraction */
tempval = gfar_read(&regs->rctrl);
tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
@@ -2469,12 +2475,11 @@ static void gfar_align_skb(struct sk_buff *skb)
}
/* Interrupt Handler for Transmit complete */
-static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
+static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
{
struct net_device *dev = tx_queue->dev;
struct netdev_queue *txq;
struct gfar_private *priv = netdev_priv(dev);
- struct gfar_priv_rx_q *rx_queue = NULL;
struct txbd8 *bdp, *next = NULL;
struct txbd8 *lbdp = NULL;
struct txbd8 *base = tx_queue->tx_bd_base;
@@ -2489,7 +2494,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
u32 lstatus;
size_t buflen;
- rx_queue = priv->rx_queue[tqi];
txq = netdev_get_tx_queue(dev, tqi);
bdp = tx_queue->dirty_tx;
skb_dirtytx = tx_queue->skb_dirtytx;
@@ -2571,8 +2575,6 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
tx_queue->dirty_tx = bdp;
netdev_tx_completed_queue(txq, howmany, bytes_sent);
-
- return howmany;
}
static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
@@ -2694,8 +2696,6 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
struct gfar_private *priv = netdev_priv(dev);
struct rxfcb *fcb = NULL;
- gro_result_t ret;
-
/* fcb is at the beginning if exists */
fcb = (struct rxfcb *)skb->data;
@@ -2725,19 +2725,17 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, dev);
- /* There's need to check for NETIF_F_HW_VLAN_RX here.
+ /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here.
* Even if vlan rx accel is disabled, on some chips
* RXFCB_VLN is pseudo randomly set.
*/
- if (dev->features & NETIF_F_HW_VLAN_RX &&
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX &&
fcb->flags & RXFCB_VLN)
- __vlan_hwaccel_put_tag(skb, fcb->vlctl);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), fcb->vlctl);
/* Send the packet up the stack */
- ret = napi_gro_receive(napi, skb);
+ napi_gro_receive(napi, skb);
- if (unlikely(GRO_DROP == ret))
- atomic64_inc(&priv->extra_stats.kernel_dropped);
}
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
@@ -2835,62 +2833,82 @@ static int gfar_poll(struct napi_struct *napi, int budget)
struct gfar __iomem *regs = gfargrp->regs;
struct gfar_priv_tx_q *tx_queue = NULL;
struct gfar_priv_rx_q *rx_queue = NULL;
- int rx_cleaned = 0, budget_per_queue = 0, rx_cleaned_per_queue = 0;
- int tx_cleaned = 0, i, left_over_budget = budget;
- unsigned long serviced_queues = 0;
- int num_queues = 0;
-
- num_queues = gfargrp->num_rx_queues;
- budget_per_queue = budget/num_queues;
+ int work_done = 0, work_done_per_q = 0;
+ int i, budget_per_q = 0;
+ int has_tx_work;
+ unsigned long rstat_rxf;
+ int num_act_queues;
/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived
*/
gfar_write(&regs->ievent, IEVENT_RTX_MASK);
- while (num_queues && left_over_budget) {
- budget_per_queue = left_over_budget/num_queues;
- left_over_budget = 0;
+ rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;
+
+ num_act_queues = bitmap_weight(&rstat_rxf, MAX_RX_QS);
+ if (num_act_queues)
+ budget_per_q = budget/num_act_queues;
+
+ while (1) {
+ has_tx_work = 0;
+ for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
+ tx_queue = priv->tx_queue[i];
+ /* run Tx cleanup to completion */
+ if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
+ gfar_clean_tx_ring(tx_queue);
+ has_tx_work = 1;
+ }
+ }
for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
- if (test_bit(i, &serviced_queues))
+ /* skip queue if not active */
+ if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
continue;
+
rx_queue = priv->rx_queue[i];
- tx_queue = priv->tx_queue[rx_queue->qindex];
-
- tx_cleaned += gfar_clean_tx_ring(tx_queue);
- rx_cleaned_per_queue =
- gfar_clean_rx_ring(rx_queue, budget_per_queue);
- rx_cleaned += rx_cleaned_per_queue;
- if (rx_cleaned_per_queue < budget_per_queue) {
- left_over_budget = left_over_budget +
- (budget_per_queue -
- rx_cleaned_per_queue);
- set_bit(i, &serviced_queues);
- num_queues--;
+ work_done_per_q =
+ gfar_clean_rx_ring(rx_queue, budget_per_q);
+ work_done += work_done_per_q;
+
+ /* finished processing this queue */
+ if (work_done_per_q < budget_per_q) {
+ /* clear active queue hw indication */
+ gfar_write(&regs->rstat,
+ RSTAT_CLEAR_RXF0 >> i);
+ rstat_rxf &= ~(RSTAT_CLEAR_RXF0 >> i);
+ num_act_queues--;
+
+ if (!num_act_queues)
+ break;
+ /* recompute budget per Rx queue */
+ budget_per_q =
+ (budget - work_done) / num_act_queues;
}
}
- }
- if (tx_cleaned)
- return budget;
+ if (work_done >= budget)
+ break;
- if (rx_cleaned < budget) {
- napi_complete(napi);
+ if (!num_act_queues && !has_tx_work) {
- /* Clear the halt bit in RSTAT */
- gfar_write(&regs->rstat, gfargrp->rstat);
+ napi_complete(napi);
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ /* Clear the halt bit in RSTAT */
+ gfar_write(&regs->rstat, gfargrp->rstat);
- /* If we are coalescing interrupts, update the timer
- * Otherwise, clear it
- */
- gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
- gfargrp->tx_bit_map);
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+
+ /* If we are coalescing interrupts, update the timer
+ * Otherwise, clear it
+ */
+ gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
+ gfargrp->tx_bit_map);
+ break;
+ }
}
- return rx_cleaned;
+ return work_done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index 63a28d294e20..04b552cd419d 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -291,7 +291,9 @@ extern const char gfar_driver_version[];
#define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK)
-#define RSTAT_CLEAR_RHALT 0x00800000
+#define RSTAT_CLEAR_RHALT 0x00800000
+#define RSTAT_CLEAR_RXF0 0x00000080
+#define RSTAT_RXF_MASK 0x000000ff
#define TCTRL_IPCSEN 0x00004000
#define TCTRL_TUCSEN 0x00002000
@@ -627,7 +629,6 @@ struct rmon_mib
};
struct gfar_extra_stats {
- atomic64_t kernel_dropped;
atomic64_t rx_large;
atomic64_t rx_short;
atomic64_t rx_nonoctet;
@@ -1180,8 +1181,7 @@ extern void stop_gfar(struct net_device *dev);
extern void gfar_halt(struct net_device *dev);
extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
int enable, u32 regnum, u32 read);
-extern void gfar_configure_coalescing(struct gfar_private *priv,
- unsigned long tx_mask, unsigned long rx_mask);
+extern void gfar_configure_coalescing_all(struct gfar_private *priv);
void gfar_init_sysfs(struct net_device *dev);
int gfar_set_features(struct net_device *dev, netdev_features_t features);
extern void gfar_check_rx_parser_mode(struct gfar_private *priv);
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 75e89acf4912..21cd88124ca9 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -66,7 +66,6 @@ static void gfar_gdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo);
static const char stat_gstrings[][ETH_GSTRING_LEN] = {
- "rx-dropped-by-kernel",
"rx-large-frame-errors",
"rx-short-frame-errors",
"rx-non-octet-errors",
@@ -390,14 +389,14 @@ static int gfar_scoalesce(struct net_device *dev,
/* Check the bounds of the values */
if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
- pr_info("Coalescing is limited to %d microseconds\n",
- GFAR_MAX_COAL_USECS);
+ netdev_info(dev, "Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
return -EINVAL;
}
if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
- pr_info("Coalescing is limited to %d frames\n",
- GFAR_MAX_COAL_FRAMES);
+ netdev_info(dev, "Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
return -EINVAL;
}
@@ -419,14 +418,14 @@ static int gfar_scoalesce(struct net_device *dev,
/* Check the bounds of the values */
if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
- pr_info("Coalescing is limited to %d microseconds\n",
- GFAR_MAX_COAL_USECS);
+ netdev_info(dev, "Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
return -EINVAL;
}
if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
- pr_info("Coalescing is limited to %d frames\n",
- GFAR_MAX_COAL_FRAMES);
+ netdev_info(dev, "Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
return -EINVAL;
}
@@ -436,7 +435,7 @@ static int gfar_scoalesce(struct net_device *dev,
gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
}
- gfar_configure_coalescing(priv, 0xFF, 0xFF);
+ gfar_configure_coalescing_all(priv);
return 0;
}
@@ -543,7 +542,7 @@ int gfar_set_features(struct net_device *dev, netdev_features_t features)
int err = 0, i = 0;
netdev_features_t changed = dev->features ^ features;
- if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+ if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
gfar_vlan_mode(dev, features);
if (!(changed & NETIF_F_RXCSUM))
@@ -736,7 +735,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow,
cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP;
break;
default:
- pr_err("Right now this class is not supported\n");
+ netdev_err(priv->ndev,
+ "Right now this class is not supported\n");
ret = 0;
goto err;
}
@@ -752,7 +752,8 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow,
}
if (i == MAX_FILER_IDX + 1) {
- pr_err("No parse rule found, can't create hash rules\n");
+ netdev_err(priv->ndev,
+ "No parse rule found, can't create hash rules\n");
ret = 0;
goto err;
}
@@ -1569,7 +1570,7 @@ static int gfar_process_filer_changes(struct gfar_private *priv)
gfar_cluster_filer(tab);
gfar_optimize_filer_masks(tab);
- pr_debug("\n\tSummary:\n"
+ pr_debug("\tSummary:\n"
"\tData on hardware: %d\n"
"\tCompression rate: %d%%\n",
tab->index, 100 - (100 * tab->index) / i);
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index 2e5daee0438a..576e4b858fce 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -17,6 +17,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
@@ -127,7 +130,6 @@ struct gianfar_ptp_registers {
#define DRIVER "gianfar_ptp"
#define DEFAULT_CKSEL 1
-#define N_ALARM 1 /* first alarm is used internally to reset fipers */
#define N_EXT_TS 2
#define REG_SIZE sizeof(struct gianfar_ptp_registers)
@@ -410,7 +412,7 @@ static struct ptp_clock_info ptp_gianfar_caps = {
.owner = THIS_MODULE,
.name = "gianfar clock",
.max_adj = 512000,
- .n_alarm = N_ALARM,
+ .n_alarm = 0,
.n_ext_ts = N_EXT_TS,
.n_per_out = 0,
.pps = 1,
diff --git a/drivers/net/ethernet/freescale/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c
index cd14a4d449c2..acb55af7e3f3 100644
--- a/drivers/net/ethernet/freescale/gianfar_sysfs.c
+++ b/drivers/net/ethernet/freescale/gianfar_sysfs.c
@@ -337,5 +337,5 @@ void gfar_init_sysfs(struct net_device *dev)
rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve);
rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off);
if (rc)
- dev_err(&dev->dev, "Error creating gianfar sysfs files.\n");
+ dev_err(&dev->dev, "Error creating gianfar sysfs files\n");
}
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index 0a70bb55d1b0..e04c59818f60 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -12,6 +12,9 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -50,12 +53,6 @@
#define ugeth_dbg(format, arg...) \
ugeth_printk(KERN_DEBUG , format , ## arg)
-#define ugeth_err(format, arg...) \
- ugeth_printk(KERN_ERR , format , ## arg)
-#define ugeth_info(format, arg...) \
- ugeth_printk(KERN_INFO , format , ## arg)
-#define ugeth_warn(format, arg...) \
- ugeth_printk(KERN_WARNING , format , ## arg)
#ifdef UGETH_VERBOSE_DEBUG
#define ugeth_vdbg ugeth_dbg
@@ -281,7 +278,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
for (i = 0; i < num_entries; i++) {
if ((snum = qe_get_snum()) < 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("fill_init_enet_entries: Can not get SNUM.");
+ pr_err("Can not get SNUM\n");
return snum;
}
if ((i == 0) && skip_page_for_first_entry)
@@ -292,7 +289,7 @@ static int fill_init_enet_entries(struct ucc_geth_private *ugeth,
qe_muram_alloc(thread_size, thread_alignment);
if (IS_ERR_VALUE(init_enet_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err("fill_init_enet_entries: Can not allocate DPRAM memory.");
+ pr_err("Can not allocate DPRAM memory\n");
qe_put_snum((u8) snum);
return -ENOMEM;
}
@@ -365,10 +362,9 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth,
init_enet_offset =
(in_be32(p_start) &
ENET_INIT_PARAM_PTR_MASK);
- ugeth_info("Init enet entry %d:", i);
- ugeth_info("Base address: 0x%08x",
- (u32)
- qe_muram_addr(init_enet_offset));
+ pr_info("Init enet entry %d:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)qe_muram_addr(init_enet_offset));
mem_disp(qe_muram_addr(init_enet_offset),
thread_size);
}
@@ -396,8 +392,8 @@ static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
{
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
- if (!(paddr_num < NUM_OF_PADDRS)) {
- ugeth_warn("%s: Illagel paddr_num.", __func__);
+ if (paddr_num >= NUM_OF_PADDRS) {
+ pr_warn("%s: Invalid paddr_num: %u\n", __func__, paddr_num);
return -EINVAL;
}
@@ -573,7 +569,7 @@ static void dump_bds(struct ucc_geth_private *ugeth)
length =
(ugeth->ug_info->bdRingLenTx[i] *
sizeof(struct qe_bd));
- ugeth_info("TX BDs[%d]", i);
+ pr_info("TX BDs[%d]\n", i);
mem_disp(ugeth->p_tx_bd_ring[i], length);
}
}
@@ -582,7 +578,7 @@ static void dump_bds(struct ucc_geth_private *ugeth)
length =
(ugeth->ug_info->bdRingLenRx[i] *
sizeof(struct qe_bd));
- ugeth_info("RX BDs[%d]", i);
+ pr_info("RX BDs[%d]\n", i);
mem_disp(ugeth->p_rx_bd_ring[i], length);
}
}
@@ -592,93 +588,93 @@ static void dump_regs(struct ucc_geth_private *ugeth)
{
int i;
- ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num + 1);
- ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs);
-
- ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->maccfg1,
- in_be32(&ugeth->ug_regs->maccfg1));
- ugeth_info("maccfg2 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->maccfg2,
- in_be32(&ugeth->ug_regs->maccfg2));
- ugeth_info("ipgifg : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->ipgifg,
- in_be32(&ugeth->ug_regs->ipgifg));
- ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->hafdup,
- in_be32(&ugeth->ug_regs->hafdup));
- ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->ifctl,
- in_be32(&ugeth->ug_regs->ifctl));
- ugeth_info("ifstat : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->ifstat,
- in_be32(&ugeth->ug_regs->ifstat));
- ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->macstnaddr1,
- in_be32(&ugeth->ug_regs->macstnaddr1));
- ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->macstnaddr2,
- in_be32(&ugeth->ug_regs->macstnaddr2));
- ugeth_info("uempr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->uempr,
- in_be32(&ugeth->ug_regs->uempr));
- ugeth_info("utbipar : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->utbipar,
- in_be32(&ugeth->ug_regs->utbipar));
- ugeth_info("uescr : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->ug_regs->uescr,
- in_be16(&ugeth->ug_regs->uescr));
- ugeth_info("tx64 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->tx64,
- in_be32(&ugeth->ug_regs->tx64));
- ugeth_info("tx127 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->tx127,
- in_be32(&ugeth->ug_regs->tx127));
- ugeth_info("tx255 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->tx255,
- in_be32(&ugeth->ug_regs->tx255));
- ugeth_info("rx64 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rx64,
- in_be32(&ugeth->ug_regs->rx64));
- ugeth_info("rx127 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rx127,
- in_be32(&ugeth->ug_regs->rx127));
- ugeth_info("rx255 : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rx255,
- in_be32(&ugeth->ug_regs->rx255));
- ugeth_info("txok : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->txok,
- in_be32(&ugeth->ug_regs->txok));
- ugeth_info("txcf : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->ug_regs->txcf,
- in_be16(&ugeth->ug_regs->txcf));
- ugeth_info("tmca : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->tmca,
- in_be32(&ugeth->ug_regs->tmca));
- ugeth_info("tbca : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->tbca,
- in_be32(&ugeth->ug_regs->tbca));
- ugeth_info("rxfok : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rxfok,
- in_be32(&ugeth->ug_regs->rxfok));
- ugeth_info("rxbok : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rxbok,
- in_be32(&ugeth->ug_regs->rxbok));
- ugeth_info("rbyt : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rbyt,
- in_be32(&ugeth->ug_regs->rbyt));
- ugeth_info("rmca : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rmca,
- in_be32(&ugeth->ug_regs->rmca));
- ugeth_info("rbca : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->rbca,
- in_be32(&ugeth->ug_regs->rbca));
- ugeth_info("scar : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->scar,
- in_be32(&ugeth->ug_regs->scar));
- ugeth_info("scam : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->scam,
- in_be32(&ugeth->ug_regs->scam));
+ pr_info("UCC%d Geth registers:\n", ugeth->ug_info->uf_info.ucc_num + 1);
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->ug_regs);
+
+ pr_info("maccfg1 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->maccfg1,
+ in_be32(&ugeth->ug_regs->maccfg1));
+ pr_info("maccfg2 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->maccfg2,
+ in_be32(&ugeth->ug_regs->maccfg2));
+ pr_info("ipgifg : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->ipgifg,
+ in_be32(&ugeth->ug_regs->ipgifg));
+ pr_info("hafdup : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->hafdup,
+ in_be32(&ugeth->ug_regs->hafdup));
+ pr_info("ifctl : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->ifctl,
+ in_be32(&ugeth->ug_regs->ifctl));
+ pr_info("ifstat : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->ifstat,
+ in_be32(&ugeth->ug_regs->ifstat));
+ pr_info("macstnaddr1: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->macstnaddr1,
+ in_be32(&ugeth->ug_regs->macstnaddr1));
+ pr_info("macstnaddr2: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->macstnaddr2,
+ in_be32(&ugeth->ug_regs->macstnaddr2));
+ pr_info("uempr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->uempr,
+ in_be32(&ugeth->ug_regs->uempr));
+ pr_info("utbipar : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->utbipar,
+ in_be32(&ugeth->ug_regs->utbipar));
+ pr_info("uescr : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->ug_regs->uescr,
+ in_be16(&ugeth->ug_regs->uescr));
+ pr_info("tx64 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->tx64,
+ in_be32(&ugeth->ug_regs->tx64));
+ pr_info("tx127 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->tx127,
+ in_be32(&ugeth->ug_regs->tx127));
+ pr_info("tx255 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->tx255,
+ in_be32(&ugeth->ug_regs->tx255));
+ pr_info("rx64 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rx64,
+ in_be32(&ugeth->ug_regs->rx64));
+ pr_info("rx127 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rx127,
+ in_be32(&ugeth->ug_regs->rx127));
+ pr_info("rx255 : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rx255,
+ in_be32(&ugeth->ug_regs->rx255));
+ pr_info("txok : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->txok,
+ in_be32(&ugeth->ug_regs->txok));
+ pr_info("txcf : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->ug_regs->txcf,
+ in_be16(&ugeth->ug_regs->txcf));
+ pr_info("tmca : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->tmca,
+ in_be32(&ugeth->ug_regs->tmca));
+ pr_info("tbca : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->tbca,
+ in_be32(&ugeth->ug_regs->tbca));
+ pr_info("rxfok : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rxfok,
+ in_be32(&ugeth->ug_regs->rxfok));
+ pr_info("rxbok : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rxbok,
+ in_be32(&ugeth->ug_regs->rxbok));
+ pr_info("rbyt : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rbyt,
+ in_be32(&ugeth->ug_regs->rbyt));
+ pr_info("rmca : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rmca,
+ in_be32(&ugeth->ug_regs->rmca));
+ pr_info("rbca : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->rbca,
+ in_be32(&ugeth->ug_regs->rbca));
+ pr_info("scar : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->scar,
+ in_be32(&ugeth->ug_regs->scar));
+ pr_info("scam : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->ug_regs->scam,
+ in_be32(&ugeth->ug_regs->scam));
if (ugeth->p_thread_data_tx) {
int numThreadsTxNumerical;
@@ -703,13 +699,13 @@ static void dump_regs(struct ucc_geth_private *ugeth)
break;
}
- ugeth_info("Thread data TXs:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_thread_data_tx);
+ pr_info("Thread data TXs:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_thread_data_tx);
for (i = 0; i < numThreadsTxNumerical; i++) {
- ugeth_info("Thread data TX[%d]:", i);
- ugeth_info("Base address: 0x%08x",
- (u32) & ugeth->p_thread_data_tx[i]);
+ pr_info("Thread data TX[%d]:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)&ugeth->p_thread_data_tx[i]);
mem_disp((u8 *) & ugeth->p_thread_data_tx[i],
sizeof(struct ucc_geth_thread_data_tx));
}
@@ -737,270 +733,260 @@ static void dump_regs(struct ucc_geth_private *ugeth)
break;
}
- ugeth_info("Thread data RX:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_thread_data_rx);
+ pr_info("Thread data RX:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_thread_data_rx);
for (i = 0; i < numThreadsRxNumerical; i++) {
- ugeth_info("Thread data RX[%d]:", i);
- ugeth_info("Base address: 0x%08x",
- (u32) & ugeth->p_thread_data_rx[i]);
+ pr_info("Thread data RX[%d]:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)&ugeth->p_thread_data_rx[i]);
mem_disp((u8 *) & ugeth->p_thread_data_rx[i],
sizeof(struct ucc_geth_thread_data_rx));
}
}
if (ugeth->p_exf_glbl_param) {
- ugeth_info("EXF global param:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_exf_glbl_param);
+ pr_info("EXF global param:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_exf_glbl_param);
mem_disp((u8 *) ugeth->p_exf_glbl_param,
sizeof(*ugeth->p_exf_glbl_param));
}
if (ugeth->p_tx_glbl_pram) {
- ugeth_info("TX global param:");
- ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram);
- ugeth_info("temoder : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_tx_glbl_pram->temoder,
- in_be16(&ugeth->p_tx_glbl_pram->temoder));
- ugeth_info("sqptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->sqptr,
- in_be32(&ugeth->p_tx_glbl_pram->sqptr));
- ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer,
- in_be32(&ugeth->p_tx_glbl_pram->
- schedulerbasepointer));
- ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr,
- in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr));
- ugeth_info("tstate : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->tstate,
- in_be32(&ugeth->p_tx_glbl_pram->tstate));
- ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[0],
- ugeth->p_tx_glbl_pram->iphoffset[0]);
- ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[1],
- ugeth->p_tx_glbl_pram->iphoffset[1]);
- ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[2],
- ugeth->p_tx_glbl_pram->iphoffset[2]);
- ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[3],
- ugeth->p_tx_glbl_pram->iphoffset[3]);
- ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[4],
- ugeth->p_tx_glbl_pram->iphoffset[4]);
- ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[5],
- ugeth->p_tx_glbl_pram->iphoffset[5]);
- ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[6],
- ugeth->p_tx_glbl_pram->iphoffset[6]);
- ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_tx_glbl_pram->iphoffset[7],
- ugeth->p_tx_glbl_pram->iphoffset[7]);
- ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[0],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0]));
- ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[1],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1]));
- ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[2],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2]));
- ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[3],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3]));
- ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[4],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4]));
- ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[5],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5]));
- ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[6],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6]));
- ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->vtagtable[7],
- in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7]));
- ugeth_info("tqptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_tx_glbl_pram->tqptr,
- in_be32(&ugeth->p_tx_glbl_pram->tqptr));
+ pr_info("TX global param:\n");
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->p_tx_glbl_pram);
+ pr_info("temoder : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_tx_glbl_pram->temoder,
+ in_be16(&ugeth->p_tx_glbl_pram->temoder));
+ pr_info("sqptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->sqptr,
+ in_be32(&ugeth->p_tx_glbl_pram->sqptr));
+ pr_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->schedulerbasepointer,
+ in_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer));
+ pr_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->txrmonbaseptr,
+ in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr));
+ pr_info("tstate : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->tstate,
+ in_be32(&ugeth->p_tx_glbl_pram->tstate));
+ pr_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[0],
+ ugeth->p_tx_glbl_pram->iphoffset[0]);
+ pr_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[1],
+ ugeth->p_tx_glbl_pram->iphoffset[1]);
+ pr_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[2],
+ ugeth->p_tx_glbl_pram->iphoffset[2]);
+ pr_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[3],
+ ugeth->p_tx_glbl_pram->iphoffset[3]);
+ pr_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[4],
+ ugeth->p_tx_glbl_pram->iphoffset[4]);
+ pr_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[5],
+ ugeth->p_tx_glbl_pram->iphoffset[5]);
+ pr_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[6],
+ ugeth->p_tx_glbl_pram->iphoffset[6]);
+ pr_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_tx_glbl_pram->iphoffset[7],
+ ugeth->p_tx_glbl_pram->iphoffset[7]);
+ pr_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[0],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0]));
+ pr_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[1],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1]));
+ pr_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[2],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2]));
+ pr_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[3],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3]));
+ pr_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[4],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4]));
+ pr_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[5],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5]));
+ pr_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[6],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6]));
+ pr_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->vtagtable[7],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7]));
+ pr_info("tqptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_tx_glbl_pram->tqptr,
+ in_be32(&ugeth->p_tx_glbl_pram->tqptr));
}
if (ugeth->p_rx_glbl_pram) {
- ugeth_info("RX global param:");
- ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_glbl_pram);
- ugeth_info("remoder : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->remoder,
- in_be32(&ugeth->p_rx_glbl_pram->remoder));
- ugeth_info("rqptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->rqptr,
- in_be32(&ugeth->p_rx_glbl_pram->rqptr));
- ugeth_info("typeorlen : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->typeorlen,
- in_be16(&ugeth->p_rx_glbl_pram->typeorlen));
- ugeth_info("rxgstpack : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_rx_glbl_pram->rxgstpack,
- ugeth->p_rx_glbl_pram->rxgstpack);
- ugeth_info("rxrmonbaseptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr,
- in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr));
- ugeth_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->intcoalescingptr,
- in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr));
- ugeth_info("rstate : addr - 0x%08x, val - 0x%02x",
- (u32) & ugeth->p_rx_glbl_pram->rstate,
- ugeth->p_rx_glbl_pram->rstate);
- ugeth_info("mrblr : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->mrblr,
- in_be16(&ugeth->p_rx_glbl_pram->mrblr));
- ugeth_info("rbdqptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->rbdqptr,
- in_be32(&ugeth->p_rx_glbl_pram->rbdqptr));
- ugeth_info("mflr : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->mflr,
- in_be16(&ugeth->p_rx_glbl_pram->mflr));
- ugeth_info("minflr : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->minflr,
- in_be16(&ugeth->p_rx_glbl_pram->minflr));
- ugeth_info("maxd1 : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->maxd1,
- in_be16(&ugeth->p_rx_glbl_pram->maxd1));
- ugeth_info("maxd2 : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->maxd2,
- in_be16(&ugeth->p_rx_glbl_pram->maxd2));
- ugeth_info("ecamptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->ecamptr,
- in_be32(&ugeth->p_rx_glbl_pram->ecamptr));
- ugeth_info("l2qt : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l2qt,
- in_be32(&ugeth->p_rx_glbl_pram->l2qt));
- ugeth_info("l3qt[0] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[0],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[0]));
- ugeth_info("l3qt[1] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[1],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[1]));
- ugeth_info("l3qt[2] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[2],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[2]));
- ugeth_info("l3qt[3] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[3],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[3]));
- ugeth_info("l3qt[4] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[4],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[4]));
- ugeth_info("l3qt[5] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[5],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[5]));
- ugeth_info("l3qt[6] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[6],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[6]));
- ugeth_info("l3qt[7] : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->l3qt[7],
- in_be32(&ugeth->p_rx_glbl_pram->l3qt[7]));
- ugeth_info("vlantype : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->vlantype,
- in_be16(&ugeth->p_rx_glbl_pram->vlantype));
- ugeth_info("vlantci : addr - 0x%08x, val - 0x%04x",
- (u32) & ugeth->p_rx_glbl_pram->vlantci,
- in_be16(&ugeth->p_rx_glbl_pram->vlantci));
+ pr_info("RX global param:\n");
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->p_rx_glbl_pram);
+ pr_info("remoder : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->remoder,
+ in_be32(&ugeth->p_rx_glbl_pram->remoder));
+ pr_info("rqptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->rqptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rqptr));
+ pr_info("typeorlen : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->typeorlen,
+ in_be16(&ugeth->p_rx_glbl_pram->typeorlen));
+ pr_info("rxgstpack : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_rx_glbl_pram->rxgstpack,
+ ugeth->p_rx_glbl_pram->rxgstpack);
+ pr_info("rxrmonbaseptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->rxrmonbaseptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr));
+ pr_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->intcoalescingptr,
+ in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr));
+ pr_info("rstate : addr - 0x%08x, val - 0x%02x\n",
+ (u32)&ugeth->p_rx_glbl_pram->rstate,
+ ugeth->p_rx_glbl_pram->rstate);
+ pr_info("mrblr : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->mrblr,
+ in_be16(&ugeth->p_rx_glbl_pram->mrblr));
+ pr_info("rbdqptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->rbdqptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rbdqptr));
+ pr_info("mflr : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->mflr,
+ in_be16(&ugeth->p_rx_glbl_pram->mflr));
+ pr_info("minflr : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->minflr,
+ in_be16(&ugeth->p_rx_glbl_pram->minflr));
+ pr_info("maxd1 : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->maxd1,
+ in_be16(&ugeth->p_rx_glbl_pram->maxd1));
+ pr_info("maxd2 : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->maxd2,
+ in_be16(&ugeth->p_rx_glbl_pram->maxd2));
+ pr_info("ecamptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->ecamptr,
+ in_be32(&ugeth->p_rx_glbl_pram->ecamptr));
+ pr_info("l2qt : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l2qt,
+ in_be32(&ugeth->p_rx_glbl_pram->l2qt));
+ pr_info("l3qt[0] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[0],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[0]));
+ pr_info("l3qt[1] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[1],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[1]));
+ pr_info("l3qt[2] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[2],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[2]));
+ pr_info("l3qt[3] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[3],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[3]));
+ pr_info("l3qt[4] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[4],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[4]));
+ pr_info("l3qt[5] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[5],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[5]));
+ pr_info("l3qt[6] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[6],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[6]));
+ pr_info("l3qt[7] : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->l3qt[7],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[7]));
+ pr_info("vlantype : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->vlantype,
+ in_be16(&ugeth->p_rx_glbl_pram->vlantype));
+ pr_info("vlantci : addr - 0x%08x, val - 0x%04x\n",
+ (u32)&ugeth->p_rx_glbl_pram->vlantci,
+ in_be16(&ugeth->p_rx_glbl_pram->vlantci));
for (i = 0; i < 64; i++)
- ugeth_info
- ("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x",
- i,
- (u32) & ugeth->p_rx_glbl_pram->addressfiltering[i],
- ugeth->p_rx_glbl_pram->addressfiltering[i]);
- ugeth_info("exfGlobalParam : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_glbl_pram->exfGlobalParam,
- in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam));
+ pr_info("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x\n",
+ i,
+ (u32)&ugeth->p_rx_glbl_pram->addressfiltering[i],
+ ugeth->p_rx_glbl_pram->addressfiltering[i]);
+ pr_info("exfGlobalParam : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_glbl_pram->exfGlobalParam,
+ in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam));
}
if (ugeth->p_send_q_mem_reg) {
- ugeth_info("Send Q memory registers:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_send_q_mem_reg);
+ pr_info("Send Q memory registers:\n");
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->p_send_q_mem_reg);
for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
- ugeth_info("SQQD[%d]:", i);
- ugeth_info("Base address: 0x%08x",
- (u32) & ugeth->p_send_q_mem_reg->sqqd[i]);
+ pr_info("SQQD[%d]:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)&ugeth->p_send_q_mem_reg->sqqd[i]);
mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i],
sizeof(struct ucc_geth_send_queue_qd));
}
}
if (ugeth->p_scheduler) {
- ugeth_info("Scheduler:");
- ugeth_info("Base address: 0x%08x", (u32) ugeth->p_scheduler);
+ pr_info("Scheduler:\n");
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->p_scheduler);
mem_disp((u8 *) ugeth->p_scheduler,
sizeof(*ugeth->p_scheduler));
}
if (ugeth->p_tx_fw_statistics_pram) {
- ugeth_info("TX FW statistics pram:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_tx_fw_statistics_pram);
+ pr_info("TX FW statistics pram:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_tx_fw_statistics_pram);
mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram,
sizeof(*ugeth->p_tx_fw_statistics_pram));
}
if (ugeth->p_rx_fw_statistics_pram) {
- ugeth_info("RX FW statistics pram:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_rx_fw_statistics_pram);
+ pr_info("RX FW statistics pram:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_rx_fw_statistics_pram);
mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram,
sizeof(*ugeth->p_rx_fw_statistics_pram));
}
if (ugeth->p_rx_irq_coalescing_tbl) {
- ugeth_info("RX IRQ coalescing tables:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_rx_irq_coalescing_tbl);
+ pr_info("RX IRQ coalescing tables:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)ugeth->p_rx_irq_coalescing_tbl);
for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
- ugeth_info("RX IRQ coalescing table entry[%d]:", i);
- ugeth_info("Base address: 0x%08x",
- (u32) & ugeth->p_rx_irq_coalescing_tbl->
- coalescingentry[i]);
- ugeth_info
- ("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_irq_coalescing_tbl->
- coalescingentry[i].interruptcoalescingmaxvalue,
- in_be32(&ugeth->p_rx_irq_coalescing_tbl->
- coalescingentry[i].
- interruptcoalescingmaxvalue));
- ugeth_info
- ("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_irq_coalescing_tbl->
- coalescingentry[i].interruptcoalescingcounter,
- in_be32(&ugeth->p_rx_irq_coalescing_tbl->
- coalescingentry[i].
- interruptcoalescingcounter));
+ pr_info("RX IRQ coalescing table entry[%d]:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i]);
+ pr_info("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].interruptcoalescingmaxvalue,
+ in_be32(&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].
+ interruptcoalescingmaxvalue));
+ pr_info("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].interruptcoalescingcounter,
+ in_be32(&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].
+ interruptcoalescingcounter));
}
}
if (ugeth->p_rx_bd_qs_tbl) {
- ugeth_info("RX BD QS tables:");
- ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_bd_qs_tbl);
+ pr_info("RX BD QS tables:\n");
+ pr_info("Base address: 0x%08x\n", (u32)ugeth->p_rx_bd_qs_tbl);
for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
- ugeth_info("RX BD QS table[%d]:", i);
- ugeth_info("Base address: 0x%08x",
- (u32) & ugeth->p_rx_bd_qs_tbl[i]);
- ugeth_info
- ("bdbaseptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr,
- in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr));
- ugeth_info
- ("bdptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr,
- in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr));
- ugeth_info
- ("externalbdbaseptr: addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
- in_be32(&ugeth->p_rx_bd_qs_tbl[i].
- externalbdbaseptr));
- ugeth_info
- ("externalbdptr : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdptr,
- in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr));
- ugeth_info("ucode RX Prefetched BDs:");
- ugeth_info("Base address: 0x%08x",
- (u32)
- qe_muram_addr(in_be32
- (&ugeth->p_rx_bd_qs_tbl[i].
- bdbaseptr)));
+ pr_info("RX BD QS table[%d]:\n", i);
+ pr_info("Base address: 0x%08x\n",
+ (u32)&ugeth->p_rx_bd_qs_tbl[i]);
+ pr_info("bdbaseptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr));
+ pr_info("bdptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_bd_qs_tbl[i].bdptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr));
+ pr_info("externalbdbaseptr: addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].
+ externalbdbaseptr));
+ pr_info("externalbdptr : addr - 0x%08x, val - 0x%08x\n",
+ (u32)&ugeth->p_rx_bd_qs_tbl[i].externalbdptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr));
+ pr_info("ucode RX Prefetched BDs:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32)qe_muram_addr(in_be32
+ (&ugeth->p_rx_bd_qs_tbl[i].
+ bdbaseptr)));
mem_disp((u8 *)
qe_muram_addr(in_be32
(&ugeth->p_rx_bd_qs_tbl[i].
@@ -1010,9 +996,9 @@ static void dump_regs(struct ucc_geth_private *ugeth)
}
if (ugeth->p_init_enet_param_shadow) {
int size;
- ugeth_info("Init enet param shadow:");
- ugeth_info("Base address: 0x%08x",
- (u32) ugeth->p_init_enet_param_shadow);
+ pr_info("Init enet param shadow:\n");
+ pr_info("Base address: 0x%08x\n",
+ (u32) ugeth->p_init_enet_param_shadow);
mem_disp((u8 *) ugeth->p_init_enet_param_shadow,
sizeof(*ugeth->p_init_enet_param_shadow));
@@ -1392,12 +1378,11 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
struct phy_device *tbiphy;
if (!ug_info->tbi_node)
- ugeth_warn("TBI mode requires that the device "
- "tree specify a tbi-handle\n");
+ pr_warn("TBI mode requires that the device tree specify a tbi-handle\n");
tbiphy = of_phy_find_device(ug_info->tbi_node);
if (!tbiphy)
- ugeth_warn("Could not get TBI device\n");
+ pr_warn("Could not get TBI device\n");
value = phy_read(tbiphy, ENET_TBI_MII_CR);
value &= ~0x1000; /* Turn off autonegotiation */
@@ -1409,8 +1394,7 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2);
if (ret_val != 0) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.",
- __func__);
+ pr_err("Preamble length must be between 3 and 7 inclusive\n");
return ret_val;
}
@@ -1520,7 +1504,7 @@ static int ugeth_enable(struct ucc_geth_private *ugeth, enum comm_dir mode)
/* check if the UCC number is in range. */
if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: ucc_num out of range.", __func__);
+ pr_err("ucc_num out of range\n");
return -EINVAL;
}
@@ -1549,7 +1533,7 @@ static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode)
/* check if the UCC number is in range. */
if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: ucc_num out of range.", __func__);
+ pr_err("ucc_num out of range\n");
return -EINVAL;
}
@@ -1648,7 +1632,7 @@ static void adjust_link(struct net_device *dev)
break;
default:
if (netif_msg_link(ugeth))
- ugeth_warn(
+ pr_warn(
"%s: Ack! Speed (%d) is not 10/100/1000!",
dev->name, phydev->speed);
break;
@@ -2103,8 +2087,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
(uf_info->bd_mem_part == MEM_PART_MURAM))) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Bad memory partition value.",
- __func__);
+ pr_err("Bad memory partition value\n");
return -EINVAL;
}
@@ -2114,9 +2097,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
(ug_info->bdRingLenRx[i] %
UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) {
if (netif_msg_probe(ugeth))
- ugeth_err
- ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.",
- __func__);
+ pr_err("Rx BD ring length must be multiple of 4, no smaller than 8\n");
return -EINVAL;
}
}
@@ -2125,9 +2106,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
for (i = 0; i < ug_info->numQueuesTx; i++) {
if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) {
if (netif_msg_probe(ugeth))
- ugeth_err
- ("%s: Tx BD ring length must be no smaller than 2.",
- __func__);
+ pr_err("Tx BD ring length must be no smaller than 2\n");
return -EINVAL;
}
}
@@ -2136,23 +2115,21 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
if ((uf_info->max_rx_buf_length == 0) ||
(uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) {
if (netif_msg_probe(ugeth))
- ugeth_err
- ("%s: max_rx_buf_length must be non-zero multiple of 128.",
- __func__);
+ pr_err("max_rx_buf_length must be non-zero multiple of 128\n");
return -EINVAL;
}
/* num Tx queues */
if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: number of tx queues too large.", __func__);
+ pr_err("number of tx queues too large\n");
return -EINVAL;
}
/* num Rx queues */
if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: number of rx queues too large.", __func__);
+ pr_err("number of rx queues too large\n");
return -EINVAL;
}
@@ -2160,10 +2137,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) {
if (ug_info->l2qt[i] >= ug_info->numQueuesRx) {
if (netif_msg_probe(ugeth))
- ugeth_err
- ("%s: VLAN priority table entry must not be"
- " larger than number of Rx queues.",
- __func__);
+ pr_err("VLAN priority table entry must not be larger than number of Rx queues\n");
return -EINVAL;
}
}
@@ -2172,18 +2146,14 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) {
if (ug_info->l3qt[i] >= ug_info->numQueuesRx) {
if (netif_msg_probe(ugeth))
- ugeth_err
- ("%s: IP priority table entry must not be"
- " larger than number of Rx queues.",
- __func__);
+ pr_err("IP priority table entry must not be larger than number of Rx queues\n");
return -EINVAL;
}
}
if (ug_info->cam && !ug_info->ecamptr) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
- __func__);
+ pr_err("If cam mode is chosen, must supply cam ptr\n");
return -EINVAL;
}
@@ -2191,9 +2161,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
UCC_GETH_NUM_OF_STATION_ADDRESSES_1) &&
ug_info->rxExtendedFiltering) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Number of station addresses greater than 1 "
- "not allowed in extended parsing mode.",
- __func__);
+ pr_err("Number of station addresses greater than 1 not allowed in extended parsing mode\n");
return -EINVAL;
}
@@ -2207,7 +2175,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
/* Initialize the general fast UCC block. */
if (ucc_fast_init(uf_info, &ugeth->uccf)) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Failed to init uccf.", __func__);
+ pr_err("Failed to init uccf\n");
return -ENOMEM;
}
@@ -2222,7 +2190,7 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs));
if (!ugeth->ug_regs) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Failed to ioremap regs.", __func__);
+ pr_err("Failed to ioremap regs\n");
return -ENOMEM;
}
@@ -2273,9 +2241,7 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)
}
if (!ugeth->p_tx_bd_ring[j]) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate memory for Tx bd rings.",
- __func__);
+ pr_err("Can not allocate memory for Tx bd rings\n");
return -ENOMEM;
}
/* Zero unused end of bd ring, according to spec */
@@ -2293,8 +2259,7 @@ static int ucc_geth_alloc_tx(struct ucc_geth_private *ugeth)
if (ugeth->tx_skbuff[j] == NULL) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Could not allocate tx_skbuff",
- __func__);
+ pr_err("Could not allocate tx_skbuff\n");
return -ENOMEM;
}
@@ -2353,9 +2318,7 @@ static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth)
}
if (!ugeth->p_rx_bd_ring[j]) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate memory for Rx bd rings.",
- __func__);
+ pr_err("Can not allocate memory for Rx bd rings\n");
return -ENOMEM;
}
}
@@ -2369,8 +2332,7 @@ static int ucc_geth_alloc_rx(struct ucc_geth_private *ugeth)
if (ugeth->rx_skbuff[j] == NULL) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Could not allocate rx_skbuff",
- __func__);
+ pr_err("Could not allocate rx_skbuff\n");
return -ENOMEM;
}
@@ -2438,8 +2400,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
break;
default:
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Bad number of Rx threads value.",
- __func__);
+ pr_err("Bad number of Rx threads value\n");
return -EINVAL;
break;
}
@@ -2462,8 +2423,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
break;
default:
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Bad number of Tx threads value.",
- __func__);
+ pr_err("Bad number of Tx threads value\n");
return -EINVAL;
break;
}
@@ -2512,8 +2472,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
&ug_regs->ipgifg);
if (ret_val != 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: IPGIFG initialization parameter too large.",
- __func__);
+ pr_err("IPGIFG initialization parameter too large\n");
return ret_val;
}
@@ -2529,8 +2488,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
&ug_regs->hafdup);
if (ret_val != 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Half Duplex initialization parameter too large.",
- __func__);
+ pr_err("Half Duplex initialization parameter too large\n");
return ret_val;
}
@@ -2567,9 +2525,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_tx_glbl_pram\n");
return -ENOMEM;
}
ugeth->p_tx_glbl_pram =
@@ -2589,9 +2545,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_THREAD_DATA_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_thread_data_tx\n");
return -ENOMEM;
}
@@ -2618,9 +2572,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_send_q_mem_reg\n");
return -ENOMEM;
}
@@ -2661,9 +2613,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_SCHEDULER_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->scheduler_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_scheduler.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_scheduler\n");
return -ENOMEM;
}
@@ -2710,10 +2660,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_TX_STATISTICS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_tx_fw_statistics_pram.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_tx_fw_statistics_pram\n");
return -ENOMEM;
}
ugeth->p_tx_fw_statistics_pram =
@@ -2750,9 +2697,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_rx_glbl_pram\n");
return -ENOMEM;
}
ugeth->p_rx_glbl_pram =
@@ -2771,9 +2716,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_THREAD_DATA_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_thread_data_rx\n");
return -ENOMEM;
}
@@ -2794,9 +2737,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_RX_STATISTICS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_rx_fw_statistics_pram.", __func__);
+ pr_err("Can not allocate DPRAM memory for p_rx_fw_statistics_pram\n");
return -ENOMEM;
}
ugeth->p_rx_fw_statistics_pram =
@@ -2816,9 +2757,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+ 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_rx_irq_coalescing_tbl.", __func__);
+ pr_err("Can not allocate DPRAM memory for p_rx_irq_coalescing_tbl\n");
return -ENOMEM;
}
@@ -2884,9 +2823,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_rx_bd_qs_tbl\n");
return -ENOMEM;
}
@@ -2961,8 +2898,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (ug_info->rxExtendedFiltering) {
if (!ug_info->extendedFilteringChainPointer) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Null Extended Filtering Chain Pointer.",
- __func__);
+ pr_err("Null Extended Filtering Chain Pointer\n");
return -EINVAL;
}
@@ -2973,9 +2909,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for"
- " p_exf_glbl_param.", __func__);
+ pr_err("Can not allocate DPRAM memory for p_exf_glbl_param\n");
return -ENOMEM;
}
@@ -3020,9 +2954,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
if (!(ugeth->p_init_enet_param_shadow =
kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate memory for"
- " p_UccInitEnetParamShadows.", __func__);
+ pr_err("Can not allocate memory for p_UccInitEnetParamShadows\n");
return -ENOMEM;
}
/* Zero out *p_init_enet_param_shadow */
@@ -3055,8 +2987,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
(ug_info->largestexternallookupkeysize !=
QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Invalid largest External Lookup Key Size.",
- __func__);
+ pr_err("Invalid largest External Lookup Key Size\n");
return -EINVAL;
}
ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =
@@ -3081,8 +3012,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
, size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
ug_info->riscRx, 1)) != 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
- __func__);
+ pr_err("Can not fill p_init_enet_param_shadow\n");
return ret_val;
}
@@ -3096,8 +3026,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
ug_info->riscTx, 0)) != 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
- __func__);
+ pr_err("Can not fill p_init_enet_param_shadow\n");
return ret_val;
}
@@ -3105,8 +3034,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
for (i = 0; i < ug_info->numQueuesRx; i++) {
if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Can not fill Rx bds with buffers.",
- __func__);
+ pr_err("Can not fill Rx bds with buffers\n");
return ret_val;
}
}
@@ -3115,9 +3043,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
if (IS_ERR_VALUE(init_enet_pram_offset)) {
if (netif_msg_ifup(ugeth))
- ugeth_err
- ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
- __func__);
+ pr_err("Can not allocate DPRAM memory for p_init_enet_pram\n");
return -ENOMEM;
}
p_init_enet_pram =
@@ -3266,8 +3192,8 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
(!(bd_status & (R_F | R_L))) ||
(bd_status & R_ERRORS_FATAL)) {
if (netif_msg_rx_err(ugeth))
- ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
- __func__, __LINE__, (u32) skb);
+ pr_err("%d: ERROR!!! skb - 0x%08x\n",
+ __LINE__, (u32)skb);
dev_kfree_skb(skb);
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
@@ -3290,7 +3216,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
skb = get_new_skb(ugeth, bd);
if (!skb) {
if (netif_msg_rx_err(ugeth))
- ugeth_warn("%s: No Rx Data Buffer", __func__);
+ pr_warn("No Rx Data Buffer\n");
dev->stats.rx_dropped++;
break;
}
@@ -3481,25 +3407,19 @@ static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
err = ucc_struct_init(ugeth);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot configure internal struct, "
- "aborting.", dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot configure internal struct, aborting\n");
goto err;
}
err = ucc_geth_startup(ugeth);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot configure net device, aborting.",
- dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot configure net device, aborting\n");
goto err;
}
err = adjust_enet_interface(ugeth);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot configure net device, aborting.",
- dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot configure net device, aborting\n");
goto err;
}
@@ -3516,8 +3436,7 @@ static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot enable net device, aborting\n");
goto err;
}
@@ -3538,35 +3457,27 @@ static int ucc_geth_open(struct net_device *dev)
/* Test station address */
if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Multicast address used for station "
- "address - is this what you wanted?",
- __func__);
+ netif_err(ugeth, ifup, dev,
+ "Multicast address used for station address - is this what you wanted?\n");
return -EINVAL;
}
err = init_phy(dev);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot initialize PHY, aborting.",
- dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot initialize PHY, aborting\n");
return err;
}
err = ucc_geth_init_mac(ugeth);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot initialize MAC, aborting.",
- dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot initialize MAC, aborting\n");
goto err;
}
err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler,
0, "UCC Geth", dev);
if (err) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot get IRQ for net device, aborting.",
- dev->name);
+ netif_err(ugeth, ifup, dev, "Cannot get IRQ for net device, aborting\n");
goto err;
}
@@ -3704,8 +3615,7 @@ static int ucc_geth_resume(struct platform_device *ofdev)
err = ucc_geth_init_mac(ugeth);
if (err) {
- ugeth_err("%s: Cannot initialize MAC, aborting.",
- ndev->name);
+ netdev_err(ndev, "Cannot initialize MAC, aborting\n");
return err;
}
}
@@ -3825,8 +3735,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
ug_info = &ugeth_info[ucc_num];
if (ug_info == NULL) {
if (netif_msg_probe(&debug))
- ugeth_err("%s: [%d] Missing additional data!",
- __func__, ucc_num);
+ pr_err("[%d] Missing additional data!\n", ucc_num);
return -ENODEV;
}
@@ -3837,8 +3746,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
ug_info->uf_info.rx_clock = qe_clock_source(sprop);
if ((ug_info->uf_info.rx_clock < QE_CLK_NONE) ||
(ug_info->uf_info.rx_clock > QE_CLK24)) {
- printk(KERN_ERR
- "ucc_geth: invalid rx-clock-name property\n");
+ pr_err("invalid rx-clock-name property\n");
return -EINVAL;
}
} else {
@@ -3846,13 +3754,11 @@ static int ucc_geth_probe(struct platform_device* ofdev)
if (!prop) {
/* If both rx-clock-name and rx-clock are missing,
we want to tell people to use rx-clock-name. */
- printk(KERN_ERR
- "ucc_geth: missing rx-clock-name property\n");
+ pr_err("missing rx-clock-name property\n");
return -EINVAL;
}
if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
- printk(KERN_ERR
- "ucc_geth: invalid rx-clock propperty\n");
+ pr_err("invalid rx-clock propperty\n");
return -EINVAL;
}
ug_info->uf_info.rx_clock = *prop;
@@ -3863,20 +3769,17 @@ static int ucc_geth_probe(struct platform_device* ofdev)
ug_info->uf_info.tx_clock = qe_clock_source(sprop);
if ((ug_info->uf_info.tx_clock < QE_CLK_NONE) ||
(ug_info->uf_info.tx_clock > QE_CLK24)) {
- printk(KERN_ERR
- "ucc_geth: invalid tx-clock-name property\n");
+ pr_err("invalid tx-clock-name property\n");
return -EINVAL;
}
} else {
prop = of_get_property(np, "tx-clock", NULL);
if (!prop) {
- printk(KERN_ERR
- "ucc_geth: missing tx-clock-name property\n");
+ pr_err("missing tx-clock-name property\n");
return -EINVAL;
}
if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
- printk(KERN_ERR
- "ucc_geth: invalid tx-clock property\n");
+ pr_err("invalid tx-clock property\n");
return -EINVAL;
}
ug_info->uf_info.tx_clock = *prop;
@@ -3949,7 +3852,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
}
if (netif_msg_probe(&debug))
- printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d)\n",
+ pr_info("UCC%1d at 0x%8x (irq = %d)\n",
ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
ug_info->uf_info.irq);
@@ -3988,8 +3891,8 @@ static int ucc_geth_probe(struct platform_device* ofdev)
err = register_netdev(dev);
if (err) {
if (netif_msg_probe(ugeth))
- ugeth_err("%s: Cannot register net device, aborting.",
- dev->name);
+ pr_err("%s: Cannot register net device, aborting\n",
+ dev->name);
free_netdev(dev);
return err;
}
@@ -4047,7 +3950,7 @@ static int __init ucc_geth_init(void)
int i, ret;
if (netif_msg_drv(&debug))
- printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+ pr_info(DRV_DESC "\n");
for (i = 0; i < 8; i++)
memcpy(&(ugeth_info[i]), &ugeth_primary_info,
sizeof(ugeth_primary_info));
diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
index 1ebf7128ec04..e79aaf9ae52a 100644
--- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
+++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c
@@ -38,7 +38,7 @@
#include "ucc_geth.h"
-static char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
+static const char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-64-frames",
"tx-65-127-frames",
"tx-128-255-frames",
@@ -59,7 +59,7 @@ static char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
"rx-dropped-frames",
};
-static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+static const char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-single-collision",
"tx-multiple-collision",
"tx-late-collsion",
@@ -74,7 +74,7 @@ static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-jumbo-frames",
};
-static char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+static const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
"rx-crc-errors",
"rx-alignment-errors",
"rx-in-range-length-errors",
@@ -160,8 +160,7 @@ uec_set_pauseparam(struct net_device *netdev,
if (ugeth->phydev->autoneg) {
if (netif_running(netdev)) {
/* FIXME: automatically restart */
- printk(KERN_INFO
- "Please re-open the interface.\n");
+ netdev_info(netdev, "Please re-open the interface\n");
}
} else {
struct ucc_geth_info *ug_info = ugeth->ug_info;
@@ -240,18 +239,18 @@ uec_set_ringparam(struct net_device *netdev,
int queue = 0, ret = 0;
if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
- printk("%s: RxBD ring size must be no smaller than %d.\n",
- netdev->name, UCC_GETH_RX_BD_RING_SIZE_MIN);
+ netdev_info(netdev, "RxBD ring size must be no smaller than %d\n",
+ UCC_GETH_RX_BD_RING_SIZE_MIN);
return -EINVAL;
}
if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
- printk("%s: RxBD ring size must be multiple of %d.\n",
- netdev->name, UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
+ netdev_info(netdev, "RxBD ring size must be multiple of %d\n",
+ UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
return -EINVAL;
}
if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
- printk("%s: TxBD ring size must be no smaller than %d.\n",
- netdev->name, UCC_GETH_TX_BD_RING_SIZE_MIN);
+ netdev_info(netdev, "TxBD ring size must be no smaller than %d\n",
+ UCC_GETH_TX_BD_RING_SIZE_MIN);
return -EINVAL;
}
@@ -260,8 +259,7 @@ uec_set_ringparam(struct net_device *netdev,
if (netif_running(netdev)) {
/* FIXME: restart automatically */
- printk(KERN_INFO
- "Please re-open the interface.\n");
+ netdev_info(netdev, "Please re-open the interface\n");
}
return ret;
diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
index 2418faf2251a..ef46b58cb4e9 100644
--- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
+++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c
@@ -705,19 +705,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = {
.suspend = fmvj18x_suspend,
.resume = fmvj18x_resume,
};
-
-static int __init init_fmvj18x_cs(void)
-{
- return pcmcia_register_driver(&fmvj18x_cs_driver);
-}
-
-static void __exit exit_fmvj18x_cs(void)
-{
- pcmcia_unregister_driver(&fmvj18x_cs_driver);
-}
-
-module_init(init_fmvj18x_cs);
-module_exit(exit_fmvj18x_cs);
+module_pcmcia_driver(fmvj18x_cs_driver);
/*====================================================================*/
@@ -1003,8 +991,6 @@ static void fjn_rx(struct net_device *dev)
}
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
- netdev_notice(dev, "Memory squeeze, dropping packet (len %d)\n",
- pkt_len);
outb(F_SKP_PKT, ioaddr + RX_SKIP);
dev->stats.rx_dropped++;
break;
diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c
index 1c54e229e3cc..e38816145395 100644
--- a/drivers/net/ethernet/i825xx/82596.c
+++ b/drivers/net/ethernet/i825xx/82596.c
@@ -798,16 +798,14 @@ static inline int i596_rx(struct net_device *dev)
#ifdef __mc68000__
cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
#endif
- }
- else
+ } else {
skb = netdev_alloc_skb(dev, pkt_len + 2);
+ }
memory_squeeze:
if (skb == NULL) {
/* XXX tulip.c can defer packets here!! */
- printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
dev->stats.rx_dropped++;
- }
- else {
+ } else {
if (!rx_in_place) {
/* 16 byte align the data fields */
skb_reserve(skb, 2);
diff --git a/drivers/net/ethernet/i825xx/lib82596.c b/drivers/net/ethernet/i825xx/lib82596.c
index f045ea4dc514..d653bac4cfc4 100644
--- a/drivers/net/ethernet/i825xx/lib82596.c
+++ b/drivers/net/ethernet/i825xx/lib82596.c
@@ -715,14 +715,12 @@ static inline int i596_rx(struct net_device *dev)
rbd->v_data = newskb->data;
rbd->b_data = SWAP32(dma_addr);
DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
- } else
+ } else {
skb = netdev_alloc_skb_ip_align(dev, pkt_len);
+ }
memory_squeeze:
if (skb == NULL) {
/* XXX tulip.c can defer packets here!! */
- printk(KERN_ERR
- "%s: i596_rx Memory squeeze, dropping packet.\n",
- dev->name);
dev->stats.rx_dropped++;
} else {
if (!rx_in_place) {
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 328f47c92e26..90ea0b1673ca 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -402,7 +402,6 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
- netdev_info(dev, "Unable to allocate enough skb in the array\n");
pr->rq1_skba.os_skbs = fill_wqes - i;
break;
}
@@ -432,10 +431,8 @@ static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
for (i = 0; i < nr_rq1a; i++) {
skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
- if (!skb_arr_rq1[i]) {
- netdev_info(dev, "Not enough memory to allocate skb array\n");
+ if (!skb_arr_rq1[i])
break;
- }
}
/* Ring doorbell */
ehea_update_rq1a(pr->qp, i - 1);
@@ -695,10 +692,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
- if (!skb) {
- netdev_err(dev, "Not enough memory to allocate skb\n");
+ if (!skb)
break;
- }
}
skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
cqe->num_bytes_transfered - 4);
@@ -730,7 +725,8 @@ static int ehea_proc_rwqes(struct net_device *dev,
processed_bytes += skb->len;
if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
- __vlan_hwaccel_put_tag(skb, cqe->vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ cqe->vlan_tag);
napi_gro_receive(&pr->napi, skb);
} else {
@@ -2115,7 +2111,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-static int ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int ehea_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
@@ -2153,7 +2149,7 @@ out:
return err;
}
-static int ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int ehea_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct ehea_port *port = netdev_priv(dev);
struct ehea_adapter *adapter = port->adapter;
@@ -3025,12 +3021,12 @@ static struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev->netdev_ops = &ehea_netdev_ops;
ehea_set_ethtool_ops(dev);
- dev->hw_features = NETIF_F_SG | NETIF_F_TSO
- | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX;
- dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
- | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
- | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
- | NETIF_F_RXCSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_TSO |
+ NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_CTAG_TX;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO |
+ NETIF_F_HIGHDMA | NETIF_F_IP_CSUM |
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXCSUM;
dev->vlan_features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HIGHDMA |
NETIF_F_IP_CSUM;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
diff --git a/drivers/net/ethernet/ibm/emac/debug.c b/drivers/net/ethernet/ibm/emac/debug.c
index b16b4828b64d..a559f326bf63 100644
--- a/drivers/net/ethernet/ibm/emac/debug.c
+++ b/drivers/net/ethernet/ibm/emac/debug.c
@@ -245,7 +245,7 @@ static void emac_sysrq_handler(int key)
static struct sysrq_key_op emac_sysrq_op = {
.handler = emac_sysrq_handler,
- .help_msg = "emaC",
+ .help_msg = "emac(c)",
.action_msg = "Show EMAC(s) status",
};
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 1f7ecf57181e..610ed223d1db 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -637,17 +637,12 @@ static int mal_probe(struct platform_device *ofdev)
bd_size = sizeof(struct mal_descriptor) *
(NUM_TX_BUFF * mal->num_tx_chans +
NUM_RX_BUFF * mal->num_rx_chans);
- mal->bd_virt =
- dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
- GFP_KERNEL);
+ mal->bd_virt = dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (mal->bd_virt == NULL) {
- printk(KERN_ERR
- "mal%d: out of memory allocating RX/TX descriptors!\n",
- index);
err = -ENOMEM;
goto fail_unmap;
}
- memset(mal->bd_virt, 0, bd_size);
for (i = 0; i < mal->num_tx_chans; ++i)
set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index c859771a9902..302d59401065 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -556,11 +556,9 @@ static int ibmveth_open(struct net_device *netdev)
adapter->rx_queue.queue_len = sizeof(struct ibmveth_rx_q_entry) *
rxq_entries;
adapter->rx_queue.queue_addr =
- dma_alloc_coherent(dev, adapter->rx_queue.queue_len,
- &adapter->rx_queue.queue_dma, GFP_KERNEL);
-
+ dma_alloc_coherent(dev, adapter->rx_queue.queue_len,
+ &adapter->rx_queue.queue_dma, GFP_KERNEL);
if (!adapter->rx_queue.queue_addr) {
- netdev_err(netdev, "unable to allocate rx queue pages\n");
rc = -ENOMEM;
goto err_out;
}
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c
index ec800b093e7e..d2bea3f07c73 100644
--- a/drivers/net/ethernet/intel/e100.c
+++ b/drivers/net/ethernet/intel/e100.c
@@ -870,7 +870,7 @@ err_unlock:
}
static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
- void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
+ int (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
{
struct cb *cb;
unsigned long flags;
@@ -888,10 +888,13 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
nic->cbs_avail--;
cb->skb = skb;
+ err = cb_prepare(nic, cb, skb);
+ if (err)
+ goto err_unlock;
+
if (unlikely(!nic->cbs_avail))
err = -ENOSPC;
- cb_prepare(nic, cb, skb);
/* Order is important otherwise we'll be in a race with h/w:
* set S-bit in current first, then clear S-bit in previous. */
@@ -1091,7 +1094,7 @@ static void e100_get_defaults(struct nic *nic)
nic->mii.mdio_write = mdio_write;
}
-static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+static int e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
struct config *config = &cb->u.config;
u8 *c = (u8 *)config;
@@ -1181,6 +1184,7 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
"[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+ return 0;
}
/*************************************************************************
@@ -1331,7 +1335,7 @@ static const struct firmware *e100_request_firmware(struct nic *nic)
return fw;
}
-static void e100_setup_ucode(struct nic *nic, struct cb *cb,
+static int e100_setup_ucode(struct nic *nic, struct cb *cb,
struct sk_buff *skb)
{
const struct firmware *fw = (void *)skb;
@@ -1358,6 +1362,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb,
cb->u.ucode[min_size] |= cpu_to_le32((BUNDLESMALL) ? 0xFFFF : 0xFF80);
cb->command = cpu_to_le16(cb_ucode | cb_el);
+ return 0;
}
static inline int e100_load_ucode_wait(struct nic *nic)
@@ -1400,18 +1405,20 @@ static inline int e100_load_ucode_wait(struct nic *nic)
return err;
}
-static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
+static int e100_setup_iaaddr(struct nic *nic, struct cb *cb,
struct sk_buff *skb)
{
cb->command = cpu_to_le16(cb_iaaddr);
memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN);
+ return 0;
}
-static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+static int e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
cb->command = cpu_to_le16(cb_dump);
cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr +
offsetof(struct mem, dump_buf));
+ return 0;
}
static int e100_phy_check_without_mii(struct nic *nic)
@@ -1581,7 +1588,7 @@ static int e100_hw_init(struct nic *nic)
return 0;
}
-static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+static int e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
{
struct net_device *netdev = nic->netdev;
struct netdev_hw_addr *ha;
@@ -1596,6 +1603,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &ha->addr,
ETH_ALEN);
}
+ return 0;
}
static void e100_set_multicast_list(struct net_device *netdev)
@@ -1756,11 +1764,18 @@ static void e100_watchdog(unsigned long data)
round_jiffies(jiffies + E100_WATCHDOG_PERIOD));
}
-static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+static int e100_xmit_prepare(struct nic *nic, struct cb *cb,
struct sk_buff *skb)
{
+ dma_addr_t dma_addr;
cb->command = nic->tx_command;
+ dma_addr = pci_map_single(nic->pdev,
+ skb->data, skb->len, PCI_DMA_TODEVICE);
+ /* If we can't map the skb, have the upper layer try later */
+ if (pci_dma_mapping_error(nic->pdev, dma_addr))
+ return -ENOMEM;
+
/*
* Use the last 4 bytes of the SKB payload packet as the CRC, used for
* testing, ie sending frames with bad CRC.
@@ -1777,11 +1792,10 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
cb->u.tcb.tcb_byte_count = 0;
cb->u.tcb.threshold = nic->tx_threshold;
cb->u.tcb.tbd_count = 1;
- cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
- skb->data, skb->len, PCI_DMA_TODEVICE));
- /* check for mapping failure? */
+ cb->u.tcb.tbd.buf_addr = cpu_to_le32(dma_addr);
cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
skb_tx_timestamp(skb);
+ return 0;
}
static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 43462d596a4e..82a967c95598 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -1020,12 +1020,11 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!txdr->desc) {
ret_val = 2;
goto err_nomem;
}
- memset(txdr->desc, 0, txdr->size);
txdr->next_to_use = txdr->next_to_clean = 0;
ew32(TDBAL, ((u64)txdr->dma & 0x00000000FFFFFFFF));
@@ -1053,6 +1052,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
txdr->buffer_info[i].dma =
dma_map_single(&pdev->dev, skb->data, skb->len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(&pdev->dev, txdr->buffer_info[i].dma)) {
+ ret_val = 4;
+ goto err_nomem;
+ }
tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
tx_desc->lower.data = cpu_to_le32(skb->len);
tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
@@ -1069,18 +1072,17 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
rxdr->buffer_info = kcalloc(rxdr->count, sizeof(struct e1000_buffer),
GFP_KERNEL);
if (!rxdr->buffer_info) {
- ret_val = 4;
+ ret_val = 5;
goto err_nomem;
}
rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!rxdr->desc) {
- ret_val = 5;
+ ret_val = 6;
goto err_nomem;
}
- memset(rxdr->desc, 0, rxdr->size);
rxdr->next_to_use = rxdr->next_to_clean = 0;
rctl = er32(RCTL);
@@ -1101,7 +1103,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
if (!skb) {
- ret_val = 6;
+ ret_val = 7;
goto err_nomem;
}
skb_reserve(skb, NET_IP_ALIGN);
@@ -1110,6 +1112,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
rxdr->buffer_info[i].dma =
dma_map_single(&pdev->dev, skb->data,
E1000_RXBUFFER_2048, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, rxdr->buffer_info[i].dma)) {
+ ret_val = 8;
+ goto err_nomem;
+ }
rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 8502c625dbef..59ad007dd5aa 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -166,8 +166,10 @@ static void e1000_vlan_mode(struct net_device *netdev,
netdev_features_t features);
static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter,
bool filter_on);
-static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
-static int e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
+static int e1000_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid);
+static int e1000_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid);
static void e1000_restore_vlan(struct e1000_adapter *adapter);
#ifdef CONFIG_PM
@@ -333,7 +335,7 @@ static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
if (!test_bit(vid, adapter->active_vlans)) {
if (hw->mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) {
- e1000_vlan_rx_add_vid(netdev, vid);
+ e1000_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
adapter->mng_vlan_id = vid;
} else {
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -341,7 +343,8 @@ static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
(vid != old_vid) &&
!test_bit(old_vid, adapter->active_vlans))
- e1000_vlan_rx_kill_vid(netdev, old_vid);
+ e1000_vlan_rx_kill_vid(netdev, htons(ETH_P_8021Q),
+ old_vid);
} else {
adapter->mng_vlan_id = vid;
}
@@ -809,10 +812,10 @@ static netdev_features_t e1000_fix_features(struct net_device *netdev,
/* Since there is no support for separate Rx/Tx vlan accel
* enable/disable make sure Tx flag is always in same state as Rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -823,7 +826,7 @@ static int e1000_set_features(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
e1000_vlan_mode(netdev, features);
if (!(changed & (NETIF_F_RXCSUM | NETIF_F_RXALL)))
@@ -1058,9 +1061,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (hw->mac_type >= e1000_82543) {
netdev->hw_features = NETIF_F_SG |
NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_RX;
- netdev->features = NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_RX;
+ netdev->features = NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
}
if ((hw->mac_type >= e1000_82544) &&
@@ -1457,7 +1460,8 @@ static int e1000_close(struct net_device *netdev)
if ((hw->mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
!test_bit(adapter->mng_vlan_id, adapter->active_vlans)) {
- e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+ e1000_vlan_rx_kill_vid(netdev, htons(ETH_P_8021Q),
+ adapter->mng_vlan_id);
}
return 0;
@@ -1516,8 +1520,6 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
if (!txdr->desc) {
setup_tx_desc_die:
vfree(txdr->buffer_info);
- e_err(probe, "Unable to allocate memory for the Tx descriptor "
- "ring\n");
return -ENOMEM;
}
@@ -1707,10 +1709,7 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
GFP_KERNEL);
-
if (!rxdr->desc) {
- e_err(probe, "Unable to allocate memory for the Rx descriptor "
- "ring\n");
setup_rx_desc_die:
vfree(rxdr->buffer_info);
return -ENOMEM;
@@ -1729,8 +1728,6 @@ setup_rx_desc_die:
if (!rxdr->desc) {
dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
olddma);
- e_err(probe, "Unable to allocate memory for the Rx "
- "descriptor ring\n");
goto setup_rx_desc_die;
}
@@ -4006,7 +4003,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
if (status & E1000_RXD_STAT_VP) {
u16 vid = le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
napi_gro_receive(&adapter->napi, skb);
}
@@ -4792,7 +4789,7 @@ static void __e1000_vlan_mode(struct e1000_adapter *adapter,
u32 ctrl;
ctrl = er32(CTRL);
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
/* enable VLAN tag insert/strip */
ctrl |= E1000_CTRL_VME;
} else {
@@ -4844,7 +4841,8 @@ static void e1000_vlan_mode(struct net_device *netdev,
e1000_irq_enable(adapter);
}
-static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int e1000_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -4869,7 +4867,8 @@ static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return 0;
}
-static int e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int e1000_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -4903,7 +4902,7 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter)
e1000_vlan_filter_on_off(adapter, true);
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- e1000_vlan_rx_add_vid(adapter->netdev, vid);
+ e1000_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index e0991388664c..b71c8502a2b3 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -37,7 +37,9 @@
* "index + 5".
*/
static const u16 e1000_gg82563_cable_length_table[] = {
- 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+ 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF
+};
+
#define GG82563_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_gg82563_cable_length_table)
@@ -116,7 +118,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
nvm->type = e1000_nvm_eeprom_spi;
size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
- E1000_EECD_SIZE_EX_SHIFT);
+ E1000_EECD_SIZE_EX_SHIFT);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
@@ -393,7 +395,7 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
* before the device has completed the "Page Select" MDI
* transaction. So we wait 200us after each MDI command...
*/
- udelay(200);
+ usleep_range(200, 400);
/* ...and verify the command was successful. */
ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
@@ -403,17 +405,17 @@ static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
return -E1000_ERR_PHY;
}
- udelay(200);
+ usleep_range(200, 400);
ret_val = e1000e_read_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
- udelay(200);
+ usleep_range(200, 400);
} else {
ret_val = e1000e_read_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
}
e1000_release_phy_80003es2lan(hw);
@@ -462,7 +464,7 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
* before the device has completed the "Page Select" MDI
* transaction. So we wait 200us after each MDI command...
*/
- udelay(200);
+ usleep_range(200, 400);
/* ...and verify the command was successful. */
ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp);
@@ -472,17 +474,17 @@ static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
return -E1000_ERR_PHY;
}
- udelay(200);
+ usleep_range(200, 400);
ret_val = e1000e_write_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ MAX_PHY_REG_ADDRESS &
+ offset, data);
- udelay(200);
+ usleep_range(200, 400);
} else {
ret_val = e1000e_write_phy_reg_mdic(hw,
- MAX_PHY_REG_ADDRESS & offset,
- data);
+ MAX_PHY_REG_ADDRESS &
+ offset, data);
}
e1000_release_phy_80003es2lan(hw);
@@ -580,7 +582,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
e_dbg("Waiting for forced speed/duplex link on GG82563 phy.\n");
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
- 100000, &link);
+ 100000, &link);
if (ret_val)
return ret_val;
@@ -595,7 +597,7 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
/* Try once more */
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
- 100000, &link);
+ 100000, &link);
if (ret_val)
return ret_val;
}
@@ -666,14 +668,12 @@ static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
s32 ret_val;
if (hw->phy.media_type == e1000_media_type_copper) {
- ret_val = e1000e_get_speed_and_duplex_copper(hw,
- speed,
- duplex);
+ ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
hw->phy.ops.cfg_on_link_up(hw);
} else {
ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
- speed,
- duplex);
+ speed,
+ duplex);
}
return ret_val;
@@ -754,9 +754,9 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Initialize identification LED */
ret_val = mac->ops.id_led_init(hw);
+ /* An error is not fatal and we should not stop init due to this */
if (ret_val)
e_dbg("Error initializing identification LED\n");
- /* This is not fatal and we should not stop init due to this */
/* Disabling VLAN filtering */
e_dbg("Initializing the IEEE VLAN\n");
@@ -784,14 +784,14 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy */
reg_data = er32(TXDCTL(0));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
ew32(TXDCTL(0), reg_data);
/* ...for both queues. */
reg_data = er32(TXDCTL(1));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
ew32(TXDCTL(1), reg_data);
/* Enable retransmit on late collisions */
@@ -818,13 +818,12 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
/* default to true to enable the MDIC W/A */
hw->dev_spec.e80003es2lan.mdic_wa_enable = true;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET >>
- E1000_KMRNCTRLSTA_OFFSET_SHIFT,
- &i);
+ ret_val =
+ e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET >>
+ E1000_KMRNCTRLSTA_OFFSET_SHIFT, &i);
if (!ret_val) {
if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) ==
- E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
+ E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO)
hw->dev_spec.e80003es2lan.mdic_wa_enable = false;
}
@@ -891,7 +890,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
- u32 ctrl_ext;
+ u32 reg;
u16 data;
ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data);
@@ -954,22 +953,19 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
}
/* Bypass Rx and Tx FIFO's */
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
- E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
- E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ reg = E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL;
+ data = (E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, reg, data);
if (ret_val)
return ret_val;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
- &data);
+ reg = E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE;
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, reg, &data);
if (ret_val)
return ret_val;
data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE,
- data);
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, reg, data);
if (ret_val)
return ret_val;
@@ -982,9 +978,9 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- ctrl_ext = er32(CTRL_EXT);
- ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
- ew32(CTRL_EXT, ctrl_ext);
+ reg = er32(CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
+ ew32(CTRL_EXT, reg);
ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
if (ret_val)
@@ -1049,27 +1045,29 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
* polling the phy; this fixes erroneous timeouts at 10Mbps.
*/
ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
- 0xFFFF);
+ 0xFFFF);
if (ret_val)
return ret_val;
ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
- &reg_data);
+ &reg_data);
if (ret_val)
return ret_val;
reg_data |= 0x3F;
ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
- reg_data);
+ reg_data);
if (ret_val)
return ret_val;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
- &reg_data);
+ ret_val =
+ e1000_read_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ &reg_data);
if (ret_val)
return ret_val;
reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
- reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
if (ret_val)
return ret_val;
@@ -1096,7 +1094,7 @@ static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
if (hw->phy.media_type == e1000_media_type_copper) {
ret_val = e1000e_get_speed_and_duplex_copper(hw, &speed,
- &duplex);
+ &duplex);
if (ret_val)
return ret_val;
@@ -1125,9 +1123,10 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
u16 reg_data, reg_data2;
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
- reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
if (ret_val)
return ret_val;
@@ -1171,9 +1170,10 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
u32 i = 0;
reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw,
- E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
- reg_data);
+ ret_val =
+ e1000_write_kmrn_reg_80003es2lan(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
if (ret_val)
return ret_val;
@@ -1220,7 +1220,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
return ret_val;
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
@@ -1255,7 +1255,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
return ret_val;
kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | data;
+ E1000_KMRNCTRLSTA_OFFSET) | data;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
@@ -1419,4 +1419,3 @@ const struct e1000_info e1000_es2_info = {
.phy_ops = &es2_phy_ops,
.nvm_ops = &es2_nvm_ops,
};
-
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 2faffbde179e..7380442a3829 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -184,7 +184,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
default:
nvm->type = e1000_nvm_eeprom_spi;
size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
- E1000_EECD_SIZE_EX_SHIFT);
+ E1000_EECD_SIZE_EX_SHIFT);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
*/
@@ -437,7 +437,7 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
return ret_val;
phy->id = (u32)(phy_id << 16);
- udelay(20);
+ usleep_range(20, 40);
ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
if (ret_val)
return ret_val;
@@ -482,7 +482,7 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
if (!(swsm & E1000_SWSM_SMBI))
break;
- udelay(50);
+ usleep_range(50, 100);
i++;
}
@@ -499,7 +499,7 @@ static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
if (er32(SWSM) & E1000_SWSM_SWESMBI)
break;
- udelay(50);
+ usleep_range(50, 100);
}
if (i == fw_timeout) {
@@ -526,6 +526,7 @@ static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
ew32(SWSM, swsm);
}
+
/**
* e1000_get_hw_semaphore_82573 - Acquire hardware semaphore
* @hw: pointer to the HW structure
@@ -846,9 +847,9 @@ static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
}
for (i = 0; i < words; i++) {
- eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
- ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
- E1000_NVM_RW_REG_START;
+ eewr = ((data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset + i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START);
ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
if (ret_val)
@@ -875,8 +876,7 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
s32 timeout = PHY_CFG_TIMEOUT;
while (timeout) {
- if (er32(EEMNGCTL) &
- E1000_NVM_CFG_DONE_PORT_0)
+ if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0)
break;
usleep_range(1000, 2000);
timeout--;
@@ -1022,7 +1022,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
}
if (hw->nvm.type == e1000_nvm_flash_hw) {
- udelay(10);
+ usleep_range(10, 20);
ctrl_ext = er32(CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_EE_RST;
ew32(CTRL_EXT, ctrl_ext);
@@ -1095,9 +1095,9 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
/* Initialize identification LED */
ret_val = mac->ops.id_led_init(hw);
+ /* An error is not fatal and we should not stop init due to this */
if (ret_val)
e_dbg("Error initializing identification LED\n");
- /* This is not fatal and we should not stop init due to this */
/* Disabling VLAN filtering */
e_dbg("Initializing the IEEE VLAN\n");
@@ -1122,9 +1122,8 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy */
reg_data = er32(TXDCTL(0));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB |
- E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC);
ew32(TXDCTL(0), reg_data);
/* ...for both queues. */
@@ -1140,9 +1139,9 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
break;
default:
reg_data = er32(TXDCTL(1));
- reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB |
- E1000_TXDCTL_COUNT_DESC;
+ reg_data = ((reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC);
ew32(TXDCTL(1), reg_data);
break;
}
@@ -1530,7 +1529,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
status = er32(STATUS);
er32(RXCW);
/* SYNCH bit and IV bit are sticky */
- udelay(10);
+ usleep_range(10, 20);
rxcw = er32(RXCW);
if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) {
@@ -1633,7 +1632,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
* the IV bit and restart Autoneg
*/
for (i = 0; i < AN_RETRY_COUNT; i++) {
- udelay(10);
+ usleep_range(10, 20);
rxcw = er32(RXCW);
if ((rxcw & E1000_RXCW_SYNCH) &&
(rxcw & E1000_RXCW_C))
@@ -2066,4 +2065,3 @@ const struct e1000_info e1000_82583_info = {
.phy_ops = &e82_phy_ops_bm,
.nvm_ops = &e82571_nvm_ops,
};
-
diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h
index 85cb1a3b7cd4..08e24dc3dc0e 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.h
+++ b/drivers/net/ethernet/intel/e1000e/82571.h
@@ -44,6 +44,8 @@
#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */
#define E1000_EIAC_MASK_82574 0x01F00000
+#define E1000_IVAR_INT_ALLOC_VALID 0x8
+
/* Manageability Operation Mode mask */
#define E1000_NVM_INIT_CTRL2_MNGM 0x6000
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index fc3a4fe1ac71..351c94a0cf74 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -66,7 +66,7 @@
#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
#define E1000_CTRL_EXT_EIAME 0x01000000
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
-#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Int ACK Auto-mask */
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
#define E1000_CTRL_EXT_LSECCK 0x00001000
#define E1000_CTRL_EXT_PHYPDEN 0x00100000
@@ -216,6 +216,8 @@
#define E1000_CTRL_MEHE 0x00080000 /* Memory Error Handling Enable */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
+#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 /* PHY PM enable */
#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
#define E1000_CTRL_RST 0x04000000 /* Global reset */
#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
@@ -234,17 +236,17 @@
#define E1000_STATUS_FUNC_SHIFT 2
#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master Req status */
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
-
#define ADVERTISE_10_HALF 0x0001
#define ADVERTISE_10_FULL 0x0002
#define ADVERTISE_100_HALF 0x0004
@@ -311,6 +313,7 @@
/* SerDes Control */
#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+#define E1000_SCTL_ENABLE_SERDES_LOOPBACK 0x0410
/* Receive Checksum Control */
#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
@@ -400,7 +403,8 @@
#define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */
#define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */
#define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */
-#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+/* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_INT_ASSERTED 0x80000000
#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
@@ -583,13 +587,13 @@
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES)
-#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */
-#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
-#define E1000_NVM_RW_REG_START 1 /* Start operation */
-#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
-#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */
-#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */
-#define E1000_FLASH_UPDATES 2000
+#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM r/w regs */
+#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START 1 /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE 1 /* Flag for polling write complete */
+#define E1000_NVM_POLL_READ 0 /* Flag for polling read complete */
+#define E1000_FLASH_UPDATES 2000
/* NVM Word Offsets */
#define NVM_COMPAT 0x0003
@@ -785,6 +789,7 @@
GG82563_REG(194, 18) /* Inband Control */
/* MDI Control */
+#define E1000_MDIC_REG_MASK 0x001F0000
#define E1000_MDIC_REG_SHIFT 16
#define E1000_MDIC_PHY_SHIFT 21
#define E1000_MDIC_OP_WRITE 0x04000000
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index fcc758138b8a..82f1c84282db 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -46,6 +46,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
#include <linux/mii.h>
+#include <linux/mdio.h>
#include "hw.h"
struct e1000_info;
@@ -61,7 +62,6 @@ struct e1000_info;
#define e_notice(format, arg...) \
netdev_notice(adapter->netdev, format, ## arg)
-
/* Interrupt modes, as used by the IntMode parameter */
#define E1000E_INT_MODE_LEGACY 0
#define E1000E_INT_MODE_MSI 1
@@ -239,9 +239,8 @@ struct e1000_adapter {
u16 tx_itr;
u16 rx_itr;
- /* Tx */
- struct e1000_ring *tx_ring /* One per active queue */
- ____cacheline_aligned_in_smp;
+ /* Tx - one ring per active queue */
+ struct e1000_ring *tx_ring ____cacheline_aligned_in_smp;
u32 tx_fifo_limit;
struct napi_struct napi;
@@ -352,6 +351,8 @@ struct e1000_adapter {
struct timecounter tc;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
+
+ u16 eee_advert;
};
struct e1000_info {
@@ -487,8 +488,8 @@ extern int e1000e_setup_tx_resources(struct e1000_ring *ring);
extern void e1000e_free_rx_resources(struct e1000_ring *ring);
extern void e1000e_free_tx_resources(struct e1000_ring *ring);
extern struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
- struct rtnl_link_stats64
- *stats);
+ struct rtnl_link_stats64
+ *stats);
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
@@ -558,12 +559,14 @@ static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
return hw->nvm.ops.update(hw);
}
-static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
{
return hw->nvm.ops.read(hw, offset, words, data);
}
-static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
{
return hw->nvm.ops.write(hw, offset, words, data);
}
@@ -597,7 +600,7 @@ static inline s32 __ew32_prepare(struct e1000_hw *hw)
s32 i = E1000_ICH_FWSM_PCIM2PCI_COUNT;
while ((er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI) && --i)
- udelay(50);
+ usleep_range(50, 100);
return i;
}
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index f91a8f3f9d48..7c8ca658d553 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -35,12 +35,11 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
-#include <linux/mdio.h>
#include <linux/pm_runtime.h>
#include "e1000.h"
-enum {NETDEV_STATS, E1000_STATS};
+enum { NETDEV_STATS, E1000_STATS };
struct e1000_stats {
char stat_string[ETH_GSTRING_LEN];
@@ -121,6 +120,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
"Interrupt test (offline)", "Loopback test (offline)",
"Link test (on/offline)"
};
+
#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test)
static int e1000_get_settings(struct net_device *netdev,
@@ -197,8 +197,7 @@ static int e1000_get_settings(struct net_device *netdev,
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if ((hw->phy.media_type == e1000_media_type_copper) &&
netif_carrier_ok(netdev))
- ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
- ETH_TP_MDI;
+ ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X : ETH_TP_MDI;
else
ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;
@@ -224,8 +223,7 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
/* Fiber NICs only allow 1000 gbps Full duplex */
if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
- spd != SPEED_1000 &&
- dplx != DUPLEX_FULL) {
+ (spd != SPEED_1000) && (dplx != DUPLEX_FULL)) {
goto err_inval;
}
@@ -298,12 +296,10 @@ static int e1000_set_settings(struct net_device *netdev,
hw->mac.autoneg = 1;
if (hw->phy.media_type == e1000_media_type_fiber)
hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
- ADVERTISED_FIBRE |
- ADVERTISED_Autoneg;
+ ADVERTISED_FIBRE | ADVERTISED_Autoneg;
else
hw->phy.autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ ADVERTISED_TP | ADVERTISED_Autoneg;
ecmd->advertising = hw->phy.autoneg_advertised;
if (adapter->fc_autoneg)
hw->fc.requested_mode = e1000_fc_default;
@@ -346,7 +342,7 @@ static void e1000_get_pauseparam(struct net_device *netdev,
struct e1000_hw *hw = &adapter->hw;
pause->autoneg =
- (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+ (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
if (hw->fc.current_mode == e1000_fc_rx_pause) {
pause->rx_pause = 1;
@@ -435,7 +431,7 @@ static void e1000_get_regs(struct net_device *netdev,
memset(p, 0, E1000_REGS_LEN * sizeof(u32));
regs->version = (1 << 24) | (adapter->pdev->revision << 16) |
- adapter->pdev->device;
+ adapter->pdev->device;
regs_buff[0] = er32(CTRL);
regs_buff[1] = er32(STATUS);
@@ -503,8 +499,8 @@ static int e1000_get_eeprom(struct net_device *netdev,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
- eeprom_buff = kmalloc(sizeof(u16) *
- (last_word - first_word + 1), GFP_KERNEL);
+ eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
+ GFP_KERNEL);
if (!eeprom_buff)
return -ENOMEM;
@@ -515,7 +511,7 @@ static int e1000_get_eeprom(struct net_device *netdev,
} else {
for (i = 0; i < last_word - first_word + 1; i++) {
ret_val = e1000_read_nvm(hw, first_word + i, 1,
- &eeprom_buff[i]);
+ &eeprom_buff[i]);
if (ret_val)
break;
}
@@ -553,7 +549,8 @@ static int e1000_set_eeprom(struct net_device *netdev,
if (eeprom->len == 0)
return -EOPNOTSUPP;
- if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
+ if (eeprom->magic !=
+ (adapter->pdev->vendor | (adapter->pdev->device << 16)))
return -EFAULT;
if (adapter->flags & FLAG_READ_ONLY_NVM)
@@ -579,7 +576,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
/* need read/modify/write of last changed EEPROM word */
/* only the first byte of the word is being modified */
ret_val = e1000_read_nvm(hw, last_word, 1,
- &eeprom_buff[last_word - first_word]);
+ &eeprom_buff[last_word - first_word]);
if (ret_val)
goto out;
@@ -618,8 +615,7 @@ static void e1000_get_drvinfo(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- strlcpy(drvinfo->driver, e1000e_driver_name,
- sizeof(drvinfo->driver));
+ strlcpy(drvinfo->driver, e1000e_driver_name, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, e1000e_driver_version,
sizeof(drvinfo->version));
@@ -627,10 +623,10 @@ static void e1000_get_drvinfo(struct net_device *netdev,
* PCI-E controllers
*/
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%d.%d-%d",
- (adapter->eeprom_vers & 0xF000) >> 12,
- (adapter->eeprom_vers & 0x0FF0) >> 4,
- (adapter->eeprom_vers & 0x000F));
+ "%d.%d-%d",
+ (adapter->eeprom_vers & 0xF000) >> 12,
+ (adapter->eeprom_vers & 0x0FF0) >> 4,
+ (adapter->eeprom_vers & 0x000F));
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
sizeof(drvinfo->bus_info));
@@ -756,7 +752,8 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data,
{
u32 pat, val;
static const u32 test[] = {
- 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+ };
for (pat = 0; pat < ARRAY_SIZE(test); pat++) {
E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset,
(test[pat] & write));
@@ -786,6 +783,7 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data,
}
return 0;
}
+
#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write) \
do { \
if (reg_pattern_test(adapter, data, reg, offset, mask, write)) \
@@ -813,16 +811,16 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
u32 wlock_mac = 0;
/* The status register is Read Only, so a write should fail.
- * Some bits that get toggled are ignored.
+ * Some bits that get toggled are ignored. There are several bits
+ * on newer hardware that are r/w.
*/
switch (mac->type) {
- /* there are several bits on newer hardware that are r/w */
case e1000_82571:
case e1000_82572:
case e1000_80003es2lan:
toggle = 0x7FFFF3FF;
break;
- default:
+ default:
toggle = 0x7FFFF033;
break;
}
@@ -928,7 +926,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
}
/* If Checksum is not Correct return error else test passed */
- if ((checksum != (u16) NVM_SUM) && !(*data))
+ if ((checksum != (u16)NVM_SUM) && !(*data))
*data = 2;
return *data;
@@ -936,7 +934,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
static irqreturn_t e1000_test_intr(int __always_unused irq, void *data)
{
- struct net_device *netdev = (struct net_device *) data;
+ struct net_device *netdev = (struct net_device *)data;
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -969,8 +967,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
if (!request_irq(irq, e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
netdev)) {
shared_int = 0;
- } else if (request_irq(irq, e1000_test_intr, IRQF_SHARED,
- netdev->name, netdev)) {
+ } else if (request_irq(irq, e1000_test_intr, IRQF_SHARED, netdev->name,
+ netdev)) {
*data = 1;
ret_val = -1;
goto out;
@@ -1080,28 +1078,33 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
struct e1000_ring *tx_ring = &adapter->test_tx_ring;
struct e1000_ring *rx_ring = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
+ struct e1000_buffer *buffer_info;
int i;
if (tx_ring->desc && tx_ring->buffer_info) {
for (i = 0; i < tx_ring->count; i++) {
- if (tx_ring->buffer_info[i].dma)
+ buffer_info = &tx_ring->buffer_info[i];
+
+ if (buffer_info->dma)
dma_unmap_single(&pdev->dev,
- tx_ring->buffer_info[i].dma,
- tx_ring->buffer_info[i].length,
- DMA_TO_DEVICE);
- if (tx_ring->buffer_info[i].skb)
- dev_kfree_skb(tx_ring->buffer_info[i].skb);
+ buffer_info->dma,
+ buffer_info->length,
+ DMA_TO_DEVICE);
+ if (buffer_info->skb)
+ dev_kfree_skb(buffer_info->skb);
}
}
if (rx_ring->desc && rx_ring->buffer_info) {
for (i = 0; i < rx_ring->count; i++) {
- if (rx_ring->buffer_info[i].dma)
+ buffer_info = &rx_ring->buffer_info[i];
+
+ if (buffer_info->dma)
dma_unmap_single(&pdev->dev,
- rx_ring->buffer_info[i].dma,
- 2048, DMA_FROM_DEVICE);
- if (rx_ring->buffer_info[i].skb)
- dev_kfree_skb(rx_ring->buffer_info[i].skb);
+ buffer_info->dma,
+ 2048, DMA_FROM_DEVICE);
+ if (buffer_info->skb)
+ dev_kfree_skb(buffer_info->skb);
}
}
@@ -1138,8 +1141,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
tx_ring->count = E1000_DEFAULT_TXD;
tx_ring->buffer_info = kcalloc(tx_ring->count,
- sizeof(struct e1000_buffer),
- GFP_KERNEL);
+ sizeof(struct e1000_buffer), GFP_KERNEL);
if (!tx_ring->buffer_info) {
ret_val = 1;
goto err_nomem;
@@ -1156,8 +1158,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
- ew32(TDBAL(0), ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
- ew32(TDBAH(0), ((u64) tx_ring->dma >> 32));
+ ew32(TDBAL(0), ((u64)tx_ring->dma & 0x00000000FFFFFFFF));
+ ew32(TDBAH(0), ((u64)tx_ring->dma >> 32));
ew32(TDLEN(0), tx_ring->count * sizeof(struct e1000_tx_desc));
ew32(TDH(0), 0);
ew32(TDT(0), 0);
@@ -1179,8 +1181,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
tx_ring->buffer_info[i].skb = skb;
tx_ring->buffer_info[i].length = skb->len;
tx_ring->buffer_info[i].dma =
- dma_map_single(&pdev->dev, skb->data, skb->len,
- DMA_TO_DEVICE);
+ dma_map_single(&pdev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev,
tx_ring->buffer_info[i].dma)) {
ret_val = 4;
@@ -1200,8 +1202,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
rx_ring->count = E1000_DEFAULT_RXD;
rx_ring->buffer_info = kcalloc(rx_ring->count,
- sizeof(struct e1000_buffer),
- GFP_KERNEL);
+ sizeof(struct e1000_buffer), GFP_KERNEL);
if (!rx_ring->buffer_info) {
ret_val = 5;
goto err_nomem;
@@ -1220,16 +1221,16 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
rctl = er32(RCTL);
if (!(adapter->flags2 & FLAG2_NO_DISABLE_RX))
ew32(RCTL, rctl & ~E1000_RCTL_EN);
- ew32(RDBAL(0), ((u64) rx_ring->dma & 0xFFFFFFFF));
- ew32(RDBAH(0), ((u64) rx_ring->dma >> 32));
+ ew32(RDBAL(0), ((u64)rx_ring->dma & 0xFFFFFFFF));
+ ew32(RDBAH(0), ((u64)rx_ring->dma >> 32));
ew32(RDLEN(0), rx_ring->size);
ew32(RDH(0), 0);
ew32(RDT(0), 0);
rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
- E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE |
- E1000_RCTL_SBP | E1000_RCTL_SECRC |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
- (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE |
+ E1000_RCTL_SBP | E1000_RCTL_SECRC |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
ew32(RCTL, rctl);
for (i = 0; i < rx_ring->count; i++) {
@@ -1244,8 +1245,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
skb_reserve(skb, NET_IP_ALIGN);
rx_ring->buffer_info[i].skb = skb;
rx_ring->buffer_info[i].dma =
- dma_map_single(&pdev->dev, skb->data, 2048,
- DMA_FROM_DEVICE);
+ dma_map_single(&pdev->dev, skb->data, 2048,
+ DMA_FROM_DEVICE);
if (dma_mapping_error(&pdev->dev,
rx_ring->buffer_info[i].dma)) {
ret_val = 8;
@@ -1296,7 +1297,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
ew32(CTRL, ctrl_reg);
e1e_flush();
- udelay(500);
+ usleep_range(500, 1000);
return 0;
}
@@ -1322,7 +1323,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
/* Assert SW reset for above settings to take effect */
hw->phy.ops.commit(hw);
- mdelay(1);
+ usleep_range(1000, 2000);
/* Force Full Duplex */
e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x000C);
@@ -1363,7 +1364,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
/* force 1000, set loopback */
e1e_wphy(hw, MII_BMCR, 0x4140);
- mdelay(250);
+ msleep(250);
/* Now set up the MAC to the same speed/duplex as the PHY. */
ctrl_reg = er32(CTRL);
@@ -1395,7 +1396,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
if (hw->phy.type == e1000_phy_m88)
e1000_phy_disable_receiver(adapter);
- udelay(500);
+ usleep_range(500, 1000);
return 0;
}
@@ -1431,8 +1432,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
/* special write to serdes control register to enable SerDes analog
* loopback
*/
-#define E1000_SERDES_LB_ON 0x410
- ew32(SCTL, E1000_SERDES_LB_ON);
+ ew32(SCTL, E1000_SCTL_ENABLE_SERDES_LOOPBACK);
e1e_flush();
usleep_range(10000, 20000);
@@ -1526,8 +1526,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
case e1000_82572:
if (hw->phy.media_type == e1000_media_type_fiber ||
hw->phy.media_type == e1000_media_type_internal_serdes) {
-#define E1000_SERDES_LB_OFF 0x400
- ew32(SCTL, E1000_SERDES_LB_OFF);
+ ew32(SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
e1e_flush();
usleep_range(10000, 20000);
break;
@@ -1564,7 +1563,7 @@ static int e1000_check_lbtest_frame(struct sk_buff *skb,
frame_size &= ~1;
if (*(skb->data + 3) == 0xFF)
if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
- (*(skb->data + frame_size / 2 + 12) == 0xAF))
+ (*(skb->data + frame_size / 2 + 12) == 0xAF))
return 0;
return 13;
}
@@ -1575,6 +1574,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
struct e1000_ring *rx_ring = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
struct e1000_hw *hw = &adapter->hw;
+ struct e1000_buffer *buffer_info;
int i, j, k, l;
int lc;
int good_cnt;
@@ -1595,14 +1595,17 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
k = 0;
l = 0;
- for (j = 0; j <= lc; j++) { /* loop count loop */
- for (i = 0; i < 64; i++) { /* send the packets */
- e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb,
- 1024);
+ /* loop count loop */
+ for (j = 0; j <= lc; j++) {
+ /* send the packets */
+ for (i = 0; i < 64; i++) {
+ buffer_info = &tx_ring->buffer_info[k];
+
+ e1000_create_lbtest_frame(buffer_info->skb, 1024);
dma_sync_single_for_device(&pdev->dev,
- tx_ring->buffer_info[k].dma,
- tx_ring->buffer_info[k].length,
- DMA_TO_DEVICE);
+ buffer_info->dma,
+ buffer_info->length,
+ DMA_TO_DEVICE);
k++;
if (k == tx_ring->count)
k = 0;
@@ -1612,13 +1615,16 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
msleep(200);
time = jiffies; /* set the start time for the receive */
good_cnt = 0;
- do { /* receive the sent packets */
+ /* receive the sent packets */
+ do {
+ buffer_info = &rx_ring->buffer_info[l];
+
dma_sync_single_for_cpu(&pdev->dev,
- rx_ring->buffer_info[l].dma, 2048,
- DMA_FROM_DEVICE);
+ buffer_info->dma, 2048,
+ DMA_FROM_DEVICE);
- ret_val = e1000_check_lbtest_frame(
- rx_ring->buffer_info[l].skb, 1024);
+ ret_val = e1000_check_lbtest_frame(buffer_info->skb,
+ 1024);
if (!ret_val)
good_cnt++;
l++;
@@ -1637,7 +1643,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
ret_val = 14; /* error code for time out error */
break;
}
- } /* end loop count loop */
+ }
return ret_val;
}
@@ -1696,7 +1702,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
/* On some Phy/switch combinations, link establishment
* can take a few seconds more than expected.
*/
- msleep(5000);
+ msleep_interruptible(5000);
if (!(er32(STATUS) & E1000_STATUS_LU))
*data = 1;
@@ -1980,12 +1986,12 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
switch (e1000_gstrings_stats[i].type) {
case NETDEV_STATS:
- p = (char *) &net_stats +
- e1000_gstrings_stats[i].stat_offset;
+ p = (char *)&net_stats +
+ e1000_gstrings_stats[i].stat_offset;
break;
case E1000_STATS:
- p = (char *) adapter +
- e1000_gstrings_stats[i].stat_offset;
+ p = (char *)adapter +
+ e1000_gstrings_stats[i].stat_offset;
break;
default:
data[i] = 0;
@@ -1993,7 +1999,7 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
}
data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
- sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
}
}
@@ -2069,23 +2075,20 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl;
- u32 status, ret_val;
+ u16 cap_addr, lpa_addr, pcs_stat_addr, phy_data;
+ u32 ret_val;
- if (!(adapter->flags & FLAG_IS_ICH) ||
- !(adapter->flags2 & FLAG2_HAS_EEE))
+ if (!(adapter->flags2 & FLAG2_HAS_EEE))
return -EOPNOTSUPP;
switch (hw->phy.type) {
case e1000_phy_82579:
cap_addr = I82579_EEE_CAPABILITY;
- adv_addr = I82579_EEE_ADVERTISEMENT;
lpa_addr = I82579_EEE_LP_ABILITY;
pcs_stat_addr = I82579_EEE_PCS_STATUS;
break;
case e1000_phy_i217:
cap_addr = I217_EEE_CAPABILITY;
- adv_addr = I217_EEE_ADVERTISEMENT;
lpa_addr = I217_EEE_LP_ABILITY;
pcs_stat_addr = I217_EEE_PCS_STATUS;
break;
@@ -2104,10 +2107,7 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data);
/* EEE Advertised */
- ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data);
- if (ret_val)
- goto release;
- edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+ edata->advertised = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
/* EEE Link Partner Advertised */
ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data);
@@ -2125,25 +2125,11 @@ release:
if (ret_val)
return -ENODATA;
- e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl);
- status = er32(STATUS);
-
/* Result of the EEE auto negotiation - there is no register that
* has the status of the EEE negotiation so do a best-guess based
- * on whether both Tx and Rx LPI indications have been received or
- * base it on the link speed, the EEE advertised speeds on both ends
- * and the speeds on which EEE is enabled locally.
+ * on whether Tx or Rx LPI indications have been received.
*/
- if (((phy_data & E1000_EEE_TX_LPI_RCVD) &&
- (phy_data & E1000_EEE_RX_LPI_RCVD)) ||
- ((status & E1000_STATUS_SPEED_100) &&
- (edata->advertised & ADVERTISED_100baseT_Full) &&
- (edata->lp_advertised & ADVERTISED_100baseT_Full) &&
- (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) ||
- ((status & E1000_STATUS_SPEED_1000) &&
- (edata->advertised & ADVERTISED_1000baseT_Full) &&
- (edata->lp_advertised & ADVERTISED_1000baseT_Full) &&
- (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE)))
+ if (phy_data & (E1000_EEE_TX_LPI_RCVD | E1000_EEE_RX_LPI_RCVD))
edata->eee_active = true;
edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable;
@@ -2160,19 +2146,10 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
struct ethtool_eee eee_curr;
s32 ret_val;
- if (!(adapter->flags & FLAG_IS_ICH) ||
- !(adapter->flags2 & FLAG2_HAS_EEE))
- return -EOPNOTSUPP;
-
ret_val = e1000e_get_eee(netdev, &eee_curr);
if (ret_val)
return ret_val;
- if (eee_curr.advertised != edata->advertised) {
- e_err("Setting EEE advertisement is not supported\n");
- return -EINVAL;
- }
-
if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
e_err("Setting EEE tx-lpi is not supported\n");
return -EINVAL;
@@ -2183,16 +2160,21 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
return -EINVAL;
}
- if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) {
- hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
-
- /* reset the link */
- if (netif_running(netdev))
- e1000e_reinit_locked(adapter);
- else
- e1000e_reset(adapter);
+ if (edata->advertised & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
+ e_err("EEE advertisement supports only 100TX and/or 1000T full-duplex\n");
+ return -EINVAL;
}
+ adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
+
+ hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
+
+ /* reset the link */
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+
return 0;
}
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 1e6b889aee87..84850f7a23e4 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -167,7 +167,7 @@ enum e1000_1000t_rx_status {
e1000_1000t_rx_status_undefined = 0xFF
};
-enum e1000_rev_polarity{
+enum e1000_rev_polarity {
e1000_rev_polarity_normal = 0,
e1000_rev_polarity_reversed,
e1000_rev_polarity_undefined = 0xFF
@@ -545,7 +545,7 @@ struct e1000_mac_info {
u16 mta_reg_count;
/* Maximum size of the MTA register table in all supported adapters */
- #define MAX_MTA_REG 128
+#define MAX_MTA_REG 128
u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 121a865c7fbd..ad9d8f2dd868 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -61,15 +61,15 @@
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
struct ich8_hsfsts {
- u16 flcdone :1; /* bit 0 Flash Cycle Done */
- u16 flcerr :1; /* bit 1 Flash Cycle Error */
- u16 dael :1; /* bit 2 Direct Access error Log */
- u16 berasesz :2; /* bit 4:3 Sector Erase Size */
- u16 flcinprog :1; /* bit 5 flash cycle in Progress */
- u16 reserved1 :2; /* bit 13:6 Reserved */
- u16 reserved2 :6; /* bit 13:6 Reserved */
- u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
- u16 flockdn :1; /* bit 15 Flash Config Lock-Down */
+ u16 flcdone:1; /* bit 0 Flash Cycle Done */
+ u16 flcerr:1; /* bit 1 Flash Cycle Error */
+ u16 dael:1; /* bit 2 Direct Access error Log */
+ u16 berasesz:2; /* bit 4:3 Sector Erase Size */
+ u16 flcinprog:1; /* bit 5 flash cycle in Progress */
+ u16 reserved1:2; /* bit 13:6 Reserved */
+ u16 reserved2:6; /* bit 13:6 Reserved */
+ u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
+ u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
} hsf_status;
u16 regval;
};
@@ -78,11 +78,11 @@ union ich8_hws_flash_status {
/* Offset 06h FLCTL */
union ich8_hws_flash_ctrl {
struct ich8_hsflctl {
- u16 flcgo :1; /* 0 Flash Cycle Go */
- u16 flcycle :2; /* 2:1 Flash Cycle */
- u16 reserved :5; /* 7:3 Reserved */
- u16 fldbcount :2; /* 9:8 Flash Data Byte Count */
- u16 flockdn :6; /* 15:10 Reserved */
+ u16 flcgo:1; /* 0 Flash Cycle Go */
+ u16 flcycle:2; /* 2:1 Flash Cycle */
+ u16 reserved:5; /* 7:3 Reserved */
+ u16 fldbcount:2; /* 9:8 Flash Data Byte Count */
+ u16 flockdn:6; /* 15:10 Reserved */
} hsf_ctrl;
u16 regval;
};
@@ -90,10 +90,10 @@ union ich8_hws_flash_ctrl {
/* ICH Flash Region Access Permissions */
union ich8_hws_flash_regacc {
struct ich8_flracc {
- u32 grra :8; /* 0:7 GbE region Read Access */
- u32 grwa :8; /* 8:15 GbE region Write Access */
- u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */
- u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */
+ u32 grra:8; /* 0:7 GbE region Read Access */
+ u32 grwa:8; /* 8:15 GbE region Write Access */
+ u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
+ u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
} hsf_flregacc;
u16 regval;
};
@@ -142,6 +142,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
+static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
{
@@ -312,7 +313,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
ew32(CTRL, mac_reg);
e1e_flush();
- udelay(10);
+ usleep_range(10, 20);
mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
ew32(CTRL, mac_reg);
e1e_flush();
@@ -548,8 +549,8 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
/* find total size of the NVM, then cut in half since the total
* size represents two separate NVM banks.
*/
- nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
- << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size = ((sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT);
nvm->flash_bank_size /= 2;
/* Adjust to word count */
nvm->flash_bank_size /= sizeof(u16);
@@ -636,6 +637,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
if (mac->type == e1000_pch_lpt) {
mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
mac->ops.rar_set = e1000_rar_set_pch_lpt;
+ mac->ops.setup_physical_interface =
+ e1000_setup_copper_link_pch_lpt;
}
/* Enable PCS Lock-loss workaround for ICH8 */
@@ -692,7 +695,7 @@ s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data)
*
* Assumes the SW/FW/HW Semaphore is already acquired.
**/
-static s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
+s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
{
return __e1000_access_emi_reg_locked(hw, addr, &data, false);
}
@@ -709,11 +712,22 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
s32 ret_val;
- u16 lpi_ctrl;
+ u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data;
- if ((hw->phy.type != e1000_phy_82579) &&
- (hw->phy.type != e1000_phy_i217))
+ switch (hw->phy.type) {
+ case e1000_phy_82579:
+ lpa = I82579_EEE_LP_ABILITY;
+ pcs_status = I82579_EEE_PCS_STATUS;
+ adv_addr = I82579_EEE_ADVERTISEMENT;
+ break;
+ case e1000_phy_i217:
+ lpa = I217_EEE_LP_ABILITY;
+ pcs_status = I217_EEE_PCS_STATUS;
+ adv_addr = I217_EEE_ADVERTISEMENT;
+ break;
+ default:
return 0;
+ }
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
@@ -728,34 +742,24 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
/* Enable EEE if not disabled by user */
if (!dev_spec->eee_disable) {
- u16 lpa, pcs_status, data;
-
/* Save off link partner's EEE ability */
- switch (hw->phy.type) {
- case e1000_phy_82579:
- lpa = I82579_EEE_LP_ABILITY;
- pcs_status = I82579_EEE_PCS_STATUS;
- break;
- case e1000_phy_i217:
- lpa = I217_EEE_LP_ABILITY;
- pcs_status = I217_EEE_PCS_STATUS;
- break;
- default:
- ret_val = -E1000_ERR_PHY;
- goto release;
- }
ret_val = e1000_read_emi_reg_locked(hw, lpa,
&dev_spec->eee_lp_ability);
if (ret_val)
goto release;
+ /* Read EEE advertisement */
+ ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv);
+ if (ret_val)
+ goto release;
+
/* Enable EEE only for speeds in which the link partner is
- * EEE capable.
+ * EEE capable and for which we advertise EEE.
*/
- if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+ if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
- if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+ if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
e1e_rphy_locked(hw, MII_LPA, &data);
if (data & LPA_100FULL)
lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
@@ -767,13 +771,13 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
dev_spec->eee_lp_ability &=
~I82579_EEE_100_SUPPORTED;
}
-
- /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
- ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
- if (ret_val)
- goto release;
}
+ /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+ ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+ if (ret_val)
+ goto release;
+
ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
release:
hw->phy.ops.release(hw);
@@ -835,6 +839,94 @@ release:
}
/**
+ * e1000_platform_pm_pch_lpt - Set platform power management values
+ * @hw: pointer to the HW structure
+ * @link: bool indicating link status
+ *
+ * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like"
+ * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed
+ * when link is up (which must not exceed the maximum latency supported
+ * by the platform), otherwise specify there is no LTR requirement.
+ * Unlike true-PCIe devices which set the LTR maximum snoop/no-snoop
+ * latencies in the LTR Extended Capability Structure in the PCIe Extended
+ * Capability register set, on this device LTR is set by writing the
+ * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and
+ * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB)
+ * message to the PMC.
+ **/
+static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
+{
+ u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) |
+ link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND;
+ u16 lat_enc = 0; /* latency encoded */
+
+ if (link) {
+ u16 speed, duplex, scale = 0;
+ u16 max_snoop, max_nosnoop;
+ u16 max_ltr_enc; /* max LTR latency encoded */
+ s64 lat_ns; /* latency (ns) */
+ s64 value;
+ u32 rxa;
+
+ if (!hw->adapter->max_frame_size) {
+ e_dbg("max_frame_size not set.\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+ if (!speed) {
+ e_dbg("Speed not set.\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ /* Rx Packet Buffer Allocation size (KB) */
+ rxa = er32(PBA) & E1000_PBA_RXA_MASK;
+
+ /* Determine the maximum latency tolerated by the device.
+ *
+ * Per the PCIe spec, the tolerated latencies are encoded as
+ * a 3-bit encoded scale (only 0-5 are valid) multiplied by
+ * a 10-bit value (0-1023) to provide a range from 1 ns to
+ * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns,
+ * 1=2^5ns, 2=2^10ns,...5=2^25ns.
+ */
+ lat_ns = ((s64)rxa * 1024 -
+ (2 * (s64)hw->adapter->max_frame_size)) * 8 * 1000;
+ if (lat_ns < 0)
+ lat_ns = 0;
+ else
+ do_div(lat_ns, speed);
+
+ value = lat_ns;
+ while (value > PCI_LTR_VALUE_MASK) {
+ scale++;
+ value = DIV_ROUND_UP(value, (1 << 5));
+ }
+ if (scale > E1000_LTRV_SCALE_MAX) {
+ e_dbg("Invalid LTR latency scale %d\n", scale);
+ return -E1000_ERR_CONFIG;
+ }
+ lat_enc = (u16)((scale << PCI_LTR_SCALE_SHIFT) | value);
+
+ /* Determine the maximum latency tolerated by the platform */
+ pci_read_config_word(hw->adapter->pdev, E1000_PCI_LTR_CAP_LPT,
+ &max_snoop);
+ pci_read_config_word(hw->adapter->pdev,
+ E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop);
+ max_ltr_enc = max_t(u16, max_snoop, max_nosnoop);
+
+ if (lat_enc > max_ltr_enc)
+ lat_enc = max_ltr_enc;
+ }
+
+ /* Set Snoop and No-Snoop latencies the same */
+ reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT);
+ ew32(LTRV, reg);
+
+ return 0;
+}
+
+/**
* e1000_check_for_copper_link_ich8lan - Check for link (Copper)
* @hw: pointer to the HW structure
*
@@ -871,6 +963,34 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
return ret_val;
}
+ /* When connected at 10Mbps half-duplex, 82579 parts are excessively
+ * aggressive resulting in many collisions. To avoid this, increase
+ * the IPG and reduce Rx latency in the PHY.
+ */
+ if ((hw->mac.type == e1000_pch2lan) && link) {
+ u32 reg;
+ reg = er32(STATUS);
+ if (!(reg & (E1000_STATUS_FD | E1000_STATUS_SPEED_MASK))) {
+ reg = er32(TIPG);
+ reg &= ~E1000_TIPG_IPGT_MASK;
+ reg |= 0xFF;
+ ew32(TIPG, reg);
+
+ /* Reduce Rx latency in analog PHY */
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val =
+ e1000_write_emi_reg_locked(hw, I82579_RX_CONFIG, 0);
+
+ hw->phy.ops.release(hw);
+
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
/* Work-around I218 hang issue */
if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) ||
(hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V)) {
@@ -879,6 +999,15 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
return ret_val;
}
+ if (hw->mac.type == e1000_pch_lpt) {
+ /* Set platform power management values for
+ * Latency Tolerance Reporting (LTR)
+ */
+ ret_val = e1000_platform_pm_pch_lpt(hw, link);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Clear link partner's EEE ability */
hw->dev_spec.ich8lan.eee_lp_ability = 0;
@@ -1002,10 +1131,6 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
(er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
adapter->flags2 |= FLAG2_PCIM2PCI_ARBITER_WA;
- /* Disable EEE by default until IEEE802.3az spec is finalized */
- if (adapter->flags2 & FLAG2_HAS_EEE)
- adapter->hw.dev_spec.ich8lan.eee_disable = true;
-
return 0;
}
@@ -1134,9 +1259,9 @@ static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
u32 fwsm;
fwsm = er32(FWSM);
- return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
- ((fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+ return ((fwsm & E1000_ICH_FWSM_FW_VALID) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)));
}
/**
@@ -1153,7 +1278,7 @@ static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw)
fwsm = er32(FWSM);
return (fwsm & E1000_ICH_FWSM_FW_VALID) &&
- (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
+ (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
}
/**
@@ -1440,8 +1565,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
word_addr = (u16)(cnf_base_addr << 1);
for (i = 0; i < cnf_size; i++) {
- ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1,
- &reg_data);
+ ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1, &reg_data);
if (ret_val)
goto release;
@@ -1501,13 +1625,13 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
if (ret_val)
goto release;
- status_reg &= BM_CS_STATUS_LINK_UP |
- BM_CS_STATUS_RESOLVED |
- BM_CS_STATUS_SPEED_MASK;
+ status_reg &= (BM_CS_STATUS_LINK_UP |
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK);
if (status_reg == (BM_CS_STATUS_LINK_UP |
- BM_CS_STATUS_RESOLVED |
- BM_CS_STATUS_SPEED_1000))
+ BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_1000))
k1_enable = false;
}
@@ -1516,13 +1640,13 @@ static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
if (ret_val)
goto release;
- status_reg &= HV_M_STATUS_LINK_UP |
- HV_M_STATUS_AUTONEG_COMPLETE |
- HV_M_STATUS_SPEED_MASK;
+ status_reg &= (HV_M_STATUS_LINK_UP |
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_MASK);
if (status_reg == (HV_M_STATUS_LINK_UP |
- HV_M_STATUS_AUTONEG_COMPLETE |
- HV_M_STATUS_SPEED_1000))
+ HV_M_STATUS_AUTONEG_COMPLETE |
+ HV_M_STATUS_SPEED_1000))
k1_enable = false;
}
@@ -1579,7 +1703,7 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
if (ret_val)
return ret_val;
- udelay(20);
+ usleep_range(20, 40);
ctrl_ext = er32(CTRL_EXT);
ctrl_reg = er32(CTRL);
@@ -1589,11 +1713,11 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
e1e_flush();
- udelay(20);
+ usleep_range(20, 40);
ew32(CTRL, ctrl_reg);
ew32(CTRL_EXT, ctrl_ext);
e1e_flush();
- udelay(20);
+ usleep_range(20, 40);
return 0;
}
@@ -1667,7 +1791,6 @@ release:
return ret_val;
}
-
/**
* e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode
* @hw: pointer to the HW structure
@@ -1834,7 +1957,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
* SHRAL/H) and initial CRC values to the MAC
*/
for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
- u8 mac_addr[ETH_ALEN] = {0};
+ u8 mac_addr[ETH_ALEN] = { 0 };
u32 addr_high, addr_low;
addr_high = er32(RAH(i));
@@ -1865,8 +1988,8 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
ew32(RCTL, mac_reg);
ret_val = e1000e_read_kmrn_reg(hw,
- E1000_KMRNCTRLSTA_CTRL_OFFSET,
- &data);
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
if (ret_val)
return ret_val;
ret_val = e1000e_write_kmrn_reg(hw,
@@ -1875,8 +1998,8 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
if (ret_val)
return ret_val;
ret_val = e1000e_read_kmrn_reg(hw,
- E1000_KMRNCTRLSTA_HD_CTRL,
- &data);
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
if (ret_val)
return ret_val;
data &= ~(0xF << 8);
@@ -1923,8 +2046,8 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
ew32(RCTL, mac_reg);
ret_val = e1000e_read_kmrn_reg(hw,
- E1000_KMRNCTRLSTA_CTRL_OFFSET,
- &data);
+ E1000_KMRNCTRLSTA_CTRL_OFFSET,
+ &data);
if (ret_val)
return ret_val;
ret_val = e1000e_write_kmrn_reg(hw,
@@ -1933,8 +2056,8 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
if (ret_val)
return ret_val;
ret_val = e1000e_read_kmrn_reg(hw,
- E1000_KMRNCTRLSTA_HD_CTRL,
- &data);
+ E1000_KMRNCTRLSTA_HD_CTRL,
+ &data);
if (ret_val)
return ret_val;
data &= ~(0xF << 8);
@@ -2100,7 +2223,7 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
do {
data = er32(STATUS);
data &= E1000_STATUS_LAN_INIT_DONE;
- udelay(100);
+ usleep_range(100, 200);
} while ((!data) && --loop);
/* If basic configuration is incomplete before the above loop
@@ -2445,7 +2568,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
/* Check bank 0 */
ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
- &sig_byte);
+ &sig_byte);
if (ret_val)
return ret_val;
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
@@ -2456,8 +2579,8 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
/* Check bank 1 */
ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
- bank1_offset,
- &sig_byte);
+ bank1_offset,
+ &sig_byte);
if (ret_val)
return ret_val;
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
@@ -2510,8 +2633,8 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
ret_val = 0;
for (i = 0; i < words; i++) {
- if (dev_spec->shadow_ram[offset+i].modified) {
- data[i] = dev_spec->shadow_ram[offset+i].value;
+ if (dev_spec->shadow_ram[offset + i].modified) {
+ data[i] = dev_spec->shadow_ram[offset + i].value;
} else {
ret_val = e1000_read_flash_word_ich8lan(hw,
act_offset + i,
@@ -2696,8 +2819,8 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
return -E1000_ERR_NVM;
- flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
- hw->nvm.flash_base_addr;
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
do {
udelay(1);
@@ -2714,8 +2837,9 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_READ_COMMAND_TIMEOUT);
+ ret_val =
+ e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
/* Check if FCERR is set to 1, if set to 1, clear it
* and try the whole sequence a few more times, else
@@ -2774,8 +2898,8 @@ static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
nvm->ops.acquire(hw);
for (i = 0; i < words; i++) {
- dev_spec->shadow_ram[offset+i].modified = true;
- dev_spec->shadow_ram[offset+i].value = data[i];
+ dev_spec->shadow_ram[offset + i].modified = true;
+ dev_spec->shadow_ram[offset + i].value = data[i];
}
nvm->ops.release(hw);
@@ -2844,8 +2968,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
data = dev_spec->shadow_ram[i].value;
} else {
ret_val = e1000_read_flash_word_ich8lan(hw, i +
- old_bank_offset,
- &data);
+ old_bank_offset,
+ &data);
if (ret_val)
break;
}
@@ -2863,7 +2987,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
/* Convert offset to bytes. */
act_offset = (i + new_bank_offset) << 1;
- udelay(100);
+ usleep_range(100, 200);
/* Write the bytes to the new bank. */
ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
act_offset,
@@ -2871,10 +2995,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
if (ret_val)
break;
- udelay(100);
+ usleep_range(100, 200);
ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
- act_offset + 1,
- (u8)(data >> 8));
+ act_offset + 1,
+ (u8)(data >> 8));
if (ret_val)
break;
}
@@ -3050,8 +3174,8 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
offset > ICH_FLASH_LINEAR_ADDR_MASK)
return -E1000_ERR_NVM;
- flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
- hw->nvm.flash_base_addr;
+ flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr);
do {
udelay(1);
@@ -3062,7 +3186,7 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
- hsflctl.hsf_ctrl.fldbcount = size -1;
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
@@ -3078,8 +3202,9 @@ static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
/* check if FCERR is set to 1 , if set to 1, clear it
* and try the whole sequence a few more times else done
*/
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ ret_val =
+ e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
if (!ret_val)
break;
@@ -3138,7 +3263,7 @@ static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
for (program_retries = 0; program_retries < 100; program_retries++) {
e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset);
- udelay(100);
+ usleep_range(100, 200);
ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
if (!ret_val)
break;
@@ -3209,8 +3334,10 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
flash_linear_addr = hw->nvm.flash_base_addr;
flash_linear_addr += (bank) ? flash_bank_size : 0;
- for (j = 0; j < iteration ; j++) {
+ for (j = 0; j < iteration; j++) {
do {
+ u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT;
+
/* Steps */
ret_val = e1000_flash_cycle_init_ich8lan(hw);
if (ret_val)
@@ -3230,8 +3357,7 @@ static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
flash_linear_addr += (j * sector_size);
ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
- ret_val = e1000_flash_cycle_ich8lan(hw,
- ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ ret_val = e1000_flash_cycle_ich8lan(hw, timeout);
if (!ret_val)
break;
@@ -3270,8 +3396,7 @@ static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
return ret_val;
}
- if (*data == ID_LED_RESERVED_0000 ||
- *data == ID_LED_RESERVED_FFFF)
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
*data = ID_LED_DEFAULT_ICH8LAN;
return 0;
@@ -3511,9 +3636,9 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
/* Initialize identification LED */
ret_val = mac->ops.id_led_init(hw);
+ /* An error is not fatal and we should not stop init due to this */
if (ret_val)
e_dbg("Error initializing identification LED\n");
- /* This is not fatal and we should not stop init due to this */
/* Setup the receive address. */
e1000e_init_rx_addrs(hw, mac->rar_entry_count);
@@ -3541,16 +3666,16 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
/* Set the transmit descriptor write-back policy for both queues */
txdctl = er32(TXDCTL(0));
- txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB;
- txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
- E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB);
+ txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
ew32(TXDCTL(0), txdctl);
txdctl = er32(TXDCTL(1));
- txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
- E1000_TXDCTL_FULL_TX_DESC_WB;
- txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
- E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB);
+ txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH);
ew32(TXDCTL(1), txdctl);
/* ICH8 has opposite polarity of no_snoop bits.
@@ -3559,7 +3684,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
if (mac->type == e1000_ich8lan)
snoop = PCIE_ICH8_SNOOP_ALL;
else
- snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
+ snoop = (u32)~(PCIE_NO_SNOOP_ALL);
e1000e_set_pcie_no_snoop(hw, snoop);
ctrl_ext = er32(CTRL_EXT);
@@ -3575,6 +3700,7 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
return ret_val;
}
+
/**
* e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
* @hw: pointer to the HW structure
@@ -3686,8 +3812,7 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
*/
hw->fc.current_mode = hw->fc.requested_mode;
- e_dbg("After fix-ups FlowControl is now = %x\n",
- hw->fc.current_mode);
+ e_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
/* Continue to configure the copper link. */
ret_val = hw->mac.ops.setup_physical_interface(hw);
@@ -3737,12 +3862,12 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
if (ret_val)
return ret_val;
ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- &reg_data);
+ &reg_data);
if (ret_val)
return ret_val;
reg_data |= 0x3F;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
- reg_data);
+ reg_data);
if (ret_val)
return ret_val;
@@ -3760,7 +3885,6 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
break;
case e1000_phy_82577:
case e1000_phy_82579:
- case e1000_phy_i217:
ret_val = e1000_copper_link_setup_82577(hw);
if (ret_val)
return ret_val;
@@ -3796,6 +3920,31 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
}
/**
+ * e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY specific link setup function and then calls the
+ * generic setup_copper_link to finish configuring the link for
+ * Lynxpoint PCH devices
+ **/
+static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ ret_val = e1000_copper_link_setup_82577(hw);
+ if (ret_val)
+ return ret_val;
+
+ return e1000e_setup_copper_link(hw);
+}
+
+/**
* e1000_get_link_up_info_ich8lan - Get current link speed and duplex
* @hw: pointer to the HW structure
* @speed: pointer to store current link speed
@@ -3815,8 +3964,7 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
return ret_val;
if ((hw->mac.type == e1000_ich8lan) &&
- (hw->phy.type == e1000_phy_igp_3) &&
- (*speed == SPEED_1000)) {
+ (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) {
ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
}
@@ -3899,7 +4047,7 @@ static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
* /disabled - false).
**/
void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
- bool state)
+ bool state)
{
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
@@ -3981,12 +4129,12 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
return;
ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
- &reg_data);
+ &reg_data);
if (ret_val)
return;
reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
- reg_data);
+ reg_data);
if (ret_val)
return;
reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h
index 8bf4655c2e17..80034a2b297c 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.h
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h
@@ -211,7 +211,8 @@
#define I82579_MSE_THRESHOLD 0x084F /* 82579 Mean Square Error Threshold */
#define I82577_MSE_THRESHOLD 0x0887 /* 82577 Mean Square Error Threshold */
#define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */
-#define I82579_EEE_PCS_STATUS 0x182D /* IEEE MMD Register 3.1 >> 8 */
+#define I82579_RX_CONFIG 0x3412 /* Receive configuration */
+#define I82579_EEE_PCS_STATUS 0x182E /* IEEE MMD Register 3.1 >> 8 */
#define I82579_EEE_CAPABILITY 0x0410 /* IEEE MMD Register 3.20 */
#define I82579_EEE_ADVERTISEMENT 0x040E /* IEEE MMD Register 7.60 */
#define I82579_EEE_LP_ABILITY 0x040F /* IEEE MMD Register 7.61 */
@@ -249,13 +250,6 @@
/* Proprietary Latency Tolerance Reporting PCI Capability */
#define E1000_PCI_LTR_CAP_LPT 0xA8
-/* OBFF Control & Threshold Defines */
-#define E1000_SVCR_OFF_EN 0x00000001
-#define E1000_SVCR_OFF_MASKINT 0x00001000
-#define E1000_SVCR_OFF_TIMER_MASK 0xFFFF0000
-#define E1000_SVCR_OFF_TIMER_SHIFT 16
-#define E1000_SVT_OFF_HWM_MASK 0x0000001F
-
void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
bool state);
@@ -267,4 +261,5 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
+s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
#endif /* _E1000E_ICH8LAN_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index b78e02174601..2480c1091873 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -596,7 +596,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
* serdes media type.
*/
/* SYNCH bit and IV bit are sticky. */
- udelay(10);
+ usleep_range(10, 20);
rxcw = er32(RXCW);
if (rxcw & E1000_RXCW_SYNCH) {
if (!(rxcw & E1000_RXCW_IV)) {
@@ -613,7 +613,7 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
status = er32(STATUS);
if (status & E1000_STATUS_LU) {
/* SYNCH bit and IV bit are sticky, so reread rxcw. */
- udelay(10);
+ usleep_range(10, 20);
rxcw = er32(RXCW);
if (rxcw & E1000_RXCW_SYNCH) {
if (!(rxcw & E1000_RXCW_IV)) {
@@ -1382,7 +1382,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
if (!(swsm & E1000_SWSM_SMBI))
break;
- udelay(50);
+ usleep_range(50, 100);
i++;
}
@@ -1400,7 +1400,7 @@ s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
if (er32(SWSM) & E1000_SWSM_SWESMBI)
break;
- udelay(50);
+ usleep_range(50, 100);
}
if (i == timeout) {
@@ -1600,15 +1600,28 @@ s32 e1000e_blink_led_generic(struct e1000_hw *hw)
ledctl_blink = E1000_LEDCTL_LED0_BLINK |
(E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
} else {
- /* set the blink bit for each LED that's "on" (0x0E)
- * in ledctl_mode2
+ /* Set the blink bit for each LED that's "on" (0x0E)
+ * (or "off" if inverted) in ledctl_mode2. The blink
+ * logic in hardware only works when mode is set to "on"
+ * so it must be changed accordingly when the mode is
+ * "off" and inverted.
*/
ledctl_blink = hw->mac.ledctl_mode2;
- for (i = 0; i < 4; i++)
- if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
- E1000_LEDCTL_MODE_LED_ON)
- ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
- (i * 8));
+ for (i = 0; i < 32; i += 8) {
+ u32 mode = (hw->mac.ledctl_mode2 >> i) &
+ E1000_LEDCTL_LED0_MODE_MASK;
+ u32 led_default = hw->mac.ledctl_default >> i;
+
+ if ((!(led_default & E1000_LEDCTL_LED0_IVRT) &&
+ (mode == E1000_LEDCTL_MODE_LED_ON)) ||
+ ((led_default & E1000_LEDCTL_LED0_IVRT) &&
+ (mode == E1000_LEDCTL_MODE_LED_OFF))) {
+ ledctl_blink &=
+ ~(E1000_LEDCTL_LED0_MODE_MASK << i);
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_MODE_LED_ON) << i;
+ }
+ }
}
ew32(LEDCTL, ledctl_blink);
@@ -1712,7 +1725,7 @@ s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
while (timeout) {
if (!(er32(STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
break;
- udelay(100);
+ usleep_range(100, 200);
timeout--;
}
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 948b86ffa4f0..a27e3bcc3249 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -55,7 +55,7 @@
#define DRV_EXTRAVERSION "-k"
-#define DRV_VERSION "2.2.14" DRV_EXTRAVERSION
+#define DRV_VERSION "2.3.2" DRV_EXTRAVERSION
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
@@ -219,9 +219,8 @@ static void e1000e_dump(struct e1000_adapter *adapter)
if (netdev) {
dev_info(&adapter->pdev->dev, "Net device Info\n");
pr_info("Device Name state trans_start last_rx\n");
- pr_info("%-15s %016lX %016lX %016lX\n",
- netdev->name, netdev->state, netdev->trans_start,
- netdev->last_rx);
+ pr_info("%-15s %016lX %016lX %016lX\n", netdev->name,
+ netdev->state, netdev->trans_start, netdev->last_rx);
}
/* Print Registers */
@@ -555,7 +554,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
if (staterr & E1000_RXD_STAT_VP)
- __vlan_hwaccel_put_tag(skb, tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
napi_gro_receive(&adapter->napi, skb);
}
@@ -755,8 +754,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_ring *rx_ring,
cpu_to_le64(ps_page->dma);
}
- skb = __netdev_alloc_skb_ip_align(netdev,
- adapter->rx_ps_bsize0,
+ skb = __netdev_alloc_skb_ip_align(netdev, adapter->rx_ps_bsize0,
gfp);
if (!skb) {
@@ -848,11 +846,16 @@ check_page:
}
}
- if (!buffer_info->dma)
+ if (!buffer_info->dma) {
buffer_info->dma = dma_map_page(&pdev->dev,
- buffer_info->page, 0,
- PAGE_SIZE,
+ buffer_info->page, 0,
+ PAGE_SIZE,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+ }
rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -937,10 +940,8 @@ static bool e1000_clean_rx_irq(struct e1000_ring *rx_ring, int *work_done,
cleaned = true;
cleaned_count++;
- dma_unmap_single(&pdev->dev,
- buffer_info->dma,
- adapter->rx_buffer_len,
- DMA_FROM_DEVICE);
+ dma_unmap_single(&pdev->dev, buffer_info->dma,
+ adapter->rx_buffer_len, DMA_FROM_DEVICE);
buffer_info->dma = 0;
length = le16_to_cpu(rx_desc->wb.upper.length);
@@ -1068,8 +1069,8 @@ static void e1000_put_txbuf(struct e1000_ring *tx_ring,
static void e1000_print_hw_hang(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter,
- print_hang_task);
+ struct e1000_adapter,
+ print_hang_task);
struct net_device *netdev = adapter->netdev;
struct e1000_ring *tx_ring = adapter->tx_ring;
unsigned int i = tx_ring->next_to_clean;
@@ -1082,8 +1083,7 @@ static void e1000_print_hw_hang(struct work_struct *work)
if (test_bit(__E1000_DOWN, &adapter->state))
return;
- if (!adapter->tx_hang_recheck &&
- (adapter->flags2 & FLAG2_DMA_BURST)) {
+ if (!adapter->tx_hang_recheck && (adapter->flags2 & FLAG2_DMA_BURST)) {
/* May be block on write-back, flush and detect again
* flush pending descriptor writebacks to memory
*/
@@ -1125,19 +1125,10 @@ static void e1000_print_hw_hang(struct work_struct *work)
"PHY 1000BASE-T Status <%x>\n"
"PHY Extended Status <%x>\n"
"PCI Status <%x>\n",
- readl(tx_ring->head),
- readl(tx_ring->tail),
- tx_ring->next_to_use,
- tx_ring->next_to_clean,
- tx_ring->buffer_info[eop].time_stamp,
- eop,
- jiffies,
- eop_desc->upper.fields.status,
- er32(STATUS),
- phy_status,
- phy_1000t_status,
- phy_ext_status,
- pci_status);
+ readl(tx_ring->head), readl(tx_ring->tail), tx_ring->next_to_use,
+ tx_ring->next_to_clean, tx_ring->buffer_info[eop].time_stamp,
+ eop, jiffies, eop_desc->upper.fields.status, er32(STATUS),
+ phy_status, phy_1000t_status, phy_ext_status, pci_status);
/* Suggest workaround for known h/w issue */
if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE))
@@ -1430,7 +1421,7 @@ copydone:
e1000_rx_hash(netdev, rx_desc->wb.lower.hi_dword.rss, skb);
if (rx_desc->wb.upper.header_status &
- cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
+ cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
adapter->rx_hdr_split++;
e1000_receive_skb(adapter, netdev, skb, staterr,
@@ -1468,7 +1459,7 @@ next_desc:
* e1000_consume_page - helper function
**/
static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
- u16 length)
+ u16 length)
{
bi->page = NULL;
skb->len += length;
@@ -1495,7 +1486,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
- unsigned int total_rx_bytes=0, total_rx_packets=0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+ struct skb_shared_info *shinfo;
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
@@ -1541,7 +1533,6 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
rx_ring->rx_skb_top = NULL;
goto next_desc;
}
-
#define rxtop (rx_ring->rx_skb_top)
if (!(staterr & E1000_RXD_STAT_EOP)) {
/* this descriptor is only the beginning (or middle) */
@@ -1549,12 +1540,13 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
/* this is the beginning of a chain */
rxtop = skb;
skb_fill_page_desc(rxtop, 0, buffer_info->page,
- 0, length);
+ 0, length);
} else {
/* this is the middle of a chain */
- skb_fill_page_desc(rxtop,
- skb_shinfo(rxtop)->nr_frags,
- buffer_info->page, 0, length);
+ shinfo = skb_shinfo(rxtop);
+ skb_fill_page_desc(rxtop, shinfo->nr_frags,
+ buffer_info->page, 0,
+ length);
/* re-use the skb, only consumed the page */
buffer_info->skb = skb;
}
@@ -1563,9 +1555,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
} else {
if (rxtop) {
/* end of the chain */
- skb_fill_page_desc(rxtop,
- skb_shinfo(rxtop)->nr_frags,
- buffer_info->page, 0, length);
+ shinfo = skb_shinfo(rxtop);
+ skb_fill_page_desc(rxtop, shinfo->nr_frags,
+ buffer_info->page, 0,
+ length);
/* re-use the current skb, we only consumed the
* page
*/
@@ -1590,10 +1583,10 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_ring *rx_ring, int *work_done,
skb_put(skb, length);
} else {
skb_fill_page_desc(skb, 0,
- buffer_info->page, 0,
- length);
+ buffer_info->page, 0,
+ length);
e1000_consume_page(buffer_info, skb,
- length);
+ length);
}
}
}
@@ -1666,8 +1659,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
DMA_FROM_DEVICE);
else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq)
dma_unmap_page(&pdev->dev, buffer_info->dma,
- PAGE_SIZE,
- DMA_FROM_DEVICE);
+ PAGE_SIZE, DMA_FROM_DEVICE);
else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
dma_unmap_single(&pdev->dev, buffer_info->dma,
adapter->rx_ps_bsize0,
@@ -1720,7 +1712,8 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
static void e1000e_downshift_workaround(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter, downshift_task);
+ struct e1000_adapter,
+ downshift_task);
if (test_bit(__E1000_DOWN, &adapter->state))
return;
@@ -1913,7 +1906,6 @@ static irqreturn_t e1000_intr_msix_tx(int __always_unused irq, void *data)
struct e1000_hw *hw = &adapter->hw;
struct e1000_ring *tx_ring = adapter->tx_ring;
-
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
@@ -1970,7 +1962,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
ew32(RFCTL, rfctl);
}
-#define E1000_IVAR_INT_ALLOC_VALID 0x8
/* Configure Rx vector */
rx_ring->ims_val = E1000_IMS_RXQ0;
adapter->eiac_mask |= rx_ring->ims_val;
@@ -2045,8 +2036,9 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
if (adapter->flags & FLAG_HAS_MSIX) {
adapter->num_vectors = 3; /* RxQ0, TxQ0 and other */
adapter->msix_entries = kcalloc(adapter->num_vectors,
- sizeof(struct msix_entry),
- GFP_KERNEL);
+ sizeof(struct
+ msix_entry),
+ GFP_KERNEL);
if (adapter->msix_entries) {
for (i = 0; i < adapter->num_vectors; i++)
adapter->msix_entries[i].entry = i;
@@ -2490,7 +2482,7 @@ static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
switch (itr_setting) {
case lowest_latency:
/* handle TSO and jumbo frames */
- if (bytes/packets > 8000)
+ if (bytes / packets > 8000)
retval = bulk_latency;
else if ((packets < 5) && (bytes > 512))
retval = low_latency;
@@ -2498,13 +2490,13 @@ static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
case low_latency: /* 50 usec aka 20000 ints/s */
if (bytes > 10000) {
/* this if handles the TSO accounting */
- if (bytes/packets > 8000)
+ if (bytes / packets > 8000)
retval = bulk_latency;
- else if ((packets < 10) || ((bytes/packets) > 1200))
+ else if ((packets < 10) || ((bytes / packets) > 1200))
retval = bulk_latency;
else if ((packets > 35))
retval = lowest_latency;
- } else if (bytes/packets > 2000) {
+ } else if (bytes / packets > 2000) {
retval = bulk_latency;
} else if (packets <= 2 && bytes < 512) {
retval = lowest_latency;
@@ -2556,8 +2548,8 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
current_itr = max(adapter->rx_itr, adapter->tx_itr);
- switch (current_itr) {
/* counts and packets in update_itr are dependent on these numbers */
+ switch (current_itr) {
case lowest_latency:
new_itr = 70000;
break;
@@ -2578,8 +2570,7 @@ set_itr_now:
* increasing
*/
new_itr = new_itr > adapter->itr ?
- min(adapter->itr + (new_itr >> 2), new_itr) :
- new_itr;
+ min(adapter->itr + (new_itr >> 2), new_itr) : new_itr;
adapter->itr = new_itr;
adapter->rx_ring->itr_val = new_itr;
if (adapter->msix_entries)
@@ -2681,7 +2672,8 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
return work_done;
}
-static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int e1000_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -2706,7 +2698,8 @@ static int e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return 0;
}
-static int e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int e1000_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -2750,7 +2743,8 @@ static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter)
ew32(RCTL, rctl);
if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) {
- e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+ e1000_vlan_rx_kill_vid(netdev, htons(ETH_P_8021Q),
+ adapter->mng_vlan_id);
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
}
}
@@ -2810,24 +2804,23 @@ static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
u16 vid = adapter->hw.mng_cookie.vlan_id;
u16 old_vid = adapter->mng_vlan_id;
- if (adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
- e1000_vlan_rx_add_vid(netdev, vid);
+ if (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+ e1000_vlan_rx_add_vid(netdev, htons(ETH_P_8021Q), vid);
adapter->mng_vlan_id = vid;
}
if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid))
- e1000_vlan_rx_kill_vid(netdev, old_vid);
+ e1000_vlan_rx_kill_vid(netdev, htons(ETH_P_8021Q), old_vid);
}
static void e1000_restore_vlan(struct e1000_adapter *adapter)
{
u16 vid;
- e1000_vlan_rx_add_vid(adapter->netdev, 0);
+ e1000_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), 0);
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- e1000_vlan_rx_add_vid(adapter->netdev, vid);
+ e1000_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
@@ -3002,8 +2995,8 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
rctl = er32(RCTL);
rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
- E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
- (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
/* Do not Store bad packets */
rctl &= ~E1000_RCTL_SBP;
@@ -3089,19 +3082,17 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
/* Enable Packet split descriptors */
rctl |= E1000_RCTL_DTYP_PS;
- psrctl |= adapter->rx_ps_bsize0 >>
- E1000_PSRCTL_BSIZE0_SHIFT;
+ psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT;
switch (adapter->rx_ps_pages) {
case 3:
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE3_SHIFT;
+ psrctl |= PAGE_SIZE << E1000_PSRCTL_BSIZE3_SHIFT;
+ /* fall-through */
case 2:
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE2_SHIFT;
+ psrctl |= PAGE_SIZE << E1000_PSRCTL_BSIZE2_SHIFT;
+ /* fall-through */
case 1:
- psrctl |= PAGE_SIZE >>
- E1000_PSRCTL_BSIZE1_SHIFT;
+ psrctl |= PAGE_SIZE >> E1000_PSRCTL_BSIZE1_SHIFT;
break;
}
@@ -3275,7 +3266,7 @@ static int e1000e_write_mc_addr_list(struct net_device *netdev)
/* update_mc_addr_list expects a packed array of only addresses. */
i = 0;
netdev_for_each_mc_addr(ha, netdev)
- memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
+ memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
hw->mac.ops.update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
@@ -3385,7 +3376,7 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
ew32(RCTL, rctl);
- if (netdev->features & NETIF_F_HW_VLAN_RX)
+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
e1000e_vlan_strip_enable(adapter);
else
e1000e_vlan_strip_disable(adapter);
@@ -3752,8 +3743,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
* but don't include ethernet FCS because hardware appends it
*/
min_tx_space = (adapter->max_frame_size +
- sizeof(struct e1000_tx_desc) -
- ETH_FCS_LEN) * 2;
+ sizeof(struct e1000_tx_desc) - ETH_FCS_LEN) * 2;
min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
/* software strips receive CRC, so leave room for it */
@@ -3856,13 +3846,13 @@ void e1000e_reset(struct e1000_adapter *adapter)
if ((adapter->max_frame_size * 2) > (pba << 10)) {
if (!(adapter->flags2 & FLAG2_DISABLE_AIM)) {
dev_info(&adapter->pdev->dev,
- "Interrupt Throttle Rate turned off\n");
+ "Interrupt Throttle Rate off\n");
adapter->flags2 |= FLAG2_DISABLE_AIM;
e1000e_write_itr(adapter, 0);
}
} else if (adapter->flags2 & FLAG2_DISABLE_AIM) {
dev_info(&adapter->pdev->dev,
- "Interrupt Throttle Rate turned on\n");
+ "Interrupt Throttle Rate on\n");
adapter->flags2 &= ~FLAG2_DISABLE_AIM;
adapter->itr = 20000;
e1000e_write_itr(adapter, adapter->itr);
@@ -3893,6 +3883,38 @@ void e1000e_reset(struct e1000_adapter *adapter)
/* initialize systim and reset the ns time counter */
e1000e_config_hwtstamp(adapter);
+ /* Set EEE advertisement as appropriate */
+ if (adapter->flags2 & FLAG2_HAS_EEE) {
+ s32 ret_val;
+ u16 adv_addr;
+
+ switch (hw->phy.type) {
+ case e1000_phy_82579:
+ adv_addr = I82579_EEE_ADVERTISEMENT;
+ break;
+ case e1000_phy_i217:
+ adv_addr = I217_EEE_ADVERTISEMENT;
+ break;
+ default:
+ dev_err(&adapter->pdev->dev,
+ "Invalid PHY type setting EEE advertisement\n");
+ return;
+ }
+
+ ret_val = hw->phy.ops.acquire(hw);
+ if (ret_val) {
+ dev_err(&adapter->pdev->dev,
+ "EEE advertisement - unable to acquire PHY\n");
+ return;
+ }
+
+ e1000_write_emi_reg_locked(hw, adv_addr,
+ hw->dev_spec.ich8lan.eee_disable ?
+ 0 : adapter->eee_advert);
+
+ hw->phy.ops.release(hw);
+ }
+
if (!netif_running(adapter->netdev) &&
!test_bit(__E1000_TESTING, &adapter->state)) {
e1000_power_down_phy(adapter);
@@ -3994,6 +4016,8 @@ void e1000e_down(struct e1000_adapter *adapter)
e1000_irq_disable(adapter);
+ napi_synchronize(&adapter->napi);
+
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -4261,8 +4285,7 @@ static int e1000_open(struct net_device *netdev)
e1000e_power_up_phy(adapter);
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
- if ((adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+ if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
e1000_update_mng_vlan(adapter);
/* DMA latency requirement to workaround jumbo issue */
@@ -4351,12 +4374,13 @@ static int e1000_close(struct net_device *netdev)
pm_runtime_get_sync(&pdev->dev);
- napi_disable(&adapter->napi);
-
if (!test_bit(__E1000_DOWN, &adapter->state)) {
e1000e_down(adapter);
e1000_free_irq(adapter);
}
+
+ napi_disable(&adapter->napi);
+
e1000_power_down_phy(adapter);
e1000e_free_tx_resources(adapter->tx_ring);
@@ -4365,9 +4389,9 @@ static int e1000_close(struct net_device *netdev)
/* kill manageability vlan ID if supported, but not if a vlan with
* the same ID is registered on the host OS (let 8021q kill it)
*/
- if (adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN)
- e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+ if (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN)
+ e1000_vlan_rx_kill_vid(netdev, htons(ETH_P_8021Q),
+ adapter->mng_vlan_id);
/* If AMT is enabled, let the firmware know that the network
* interface is now closed
@@ -4382,6 +4406,7 @@ static int e1000_close(struct net_device *netdev)
return 0;
}
+
/**
* e1000_set_mac - Change the Ethernet Address of the NIC
* @netdev: network interface device structure
@@ -4432,7 +4457,8 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
static void e1000e_update_phy_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter, update_phy_task);
+ struct e1000_adapter,
+ update_phy_task);
if (test_bit(__E1000_DOWN, &adapter->state))
return;
@@ -4449,7 +4475,7 @@ static void e1000e_update_phy_task(struct work_struct *work)
**/
static void e1000_update_phy_info(unsigned long data)
{
- struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ struct e1000_adapter *adapter = (struct e1000_adapter *)data;
if (test_bit(__E1000_DOWN, &adapter->state))
return;
@@ -4616,18 +4642,16 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
* our own version based on RUC and ROC
*/
netdev->stats.rx_errors = adapter->stats.rxerrc +
- adapter->stats.crcerrs + adapter->stats.algnerrc +
- adapter->stats.ruc + adapter->stats.roc +
- adapter->stats.cexterr;
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc + adapter->stats.cexterr;
netdev->stats.rx_length_errors = adapter->stats.ruc +
- adapter->stats.roc;
+ adapter->stats.roc;
netdev->stats.rx_crc_errors = adapter->stats.crcerrs;
netdev->stats.rx_frame_errors = adapter->stats.algnerrc;
netdev->stats.rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
- netdev->stats.tx_errors = adapter->stats.ecol +
- adapter->stats.latecol;
+ netdev->stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol;
netdev->stats.tx_aborted_errors = adapter->stats.ecol;
netdev->stats.tx_window_errors = adapter->stats.latecol;
netdev->stats.tx_carrier_errors = adapter->stats.tncrs;
@@ -4785,7 +4809,7 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter)
**/
static void e1000_watchdog(unsigned long data)
{
- struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ struct e1000_adapter *adapter = (struct e1000_adapter *)data;
/* Do the rest outside of interrupt context */
schedule_work(&adapter->watchdog_task);
@@ -4796,7 +4820,8 @@ static void e1000_watchdog(unsigned long data)
static void e1000_watchdog_task(struct work_struct *work)
{
struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter, watchdog_task);
+ struct e1000_adapter,
+ watchdog_task);
struct net_device *netdev = adapter->netdev;
struct e1000_mac_info *mac = &adapter->hw.mac;
struct e1000_phy_info *phy = &adapter->hw.phy;
@@ -4830,8 +4855,8 @@ static void e1000_watchdog_task(struct work_struct *work)
/* update snapshot of PHY registers on LSC */
e1000_phy_read_status(adapter);
mac->ops.get_link_up_info(&adapter->hw,
- &adapter->link_speed,
- &adapter->link_duplex);
+ &adapter->link_speed,
+ &adapter->link_duplex);
e1000_print_link_info(adapter);
/* check if SmartSpeed worked */
@@ -4944,7 +4969,7 @@ static void e1000_watchdog_task(struct work_struct *work)
adapter->flags |= FLAG_RESTART_NOW;
else
pm_schedule_suspend(netdev->dev.parent,
- LINK_TIMEOUT);
+ LINK_TIMEOUT);
}
}
@@ -4979,8 +5004,8 @@ link_up:
*/
u32 goc = (adapter->gotc + adapter->gorc) / 10000;
u32 dif = (adapter->gotc > adapter->gorc ?
- adapter->gotc - adapter->gorc :
- adapter->gorc - adapter->gotc) / 10000;
+ adapter->gotc - adapter->gorc :
+ adapter->gorc - adapter->gotc) / 10000;
u32 itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
e1000e_write_itr(adapter, itr);
@@ -5059,14 +5084,14 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
iph->tot_len = 0;
iph->check = 0;
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- 0, IPPROTO_TCP, 0);
+ 0, IPPROTO_TCP, 0);
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb_transport_offset(skb) - 1;
} else if (skb_is_gso_v6(skb)) {
ipv6_hdr(skb)->payload_len = 0;
tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- 0, IPPROTO_TCP, 0);
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
ipcse = 0;
}
ipcss = skb_network_offset(skb);
@@ -5075,7 +5100,7 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
- E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
+ E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
i = tx_ring->next_to_use;
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
@@ -5145,8 +5170,7 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
context_desc->lower_setup.ip_config = 0;
context_desc->upper_setup.tcp_fields.tucss = css;
- context_desc->upper_setup.tcp_fields.tucso =
- css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
context_desc->upper_setup.tcp_fields.tucse = 0;
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(cmd_len);
@@ -5219,7 +5243,8 @@ static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
buffer_info->time_stamp = jiffies;
buffer_info->next_to_watch = i;
buffer_info->dma = skb_frag_dma_map(&pdev->dev, frag,
- offset, size, DMA_TO_DEVICE);
+ offset, size,
+ DMA_TO_DEVICE);
buffer_info->mapped_as_page = true;
if (dma_mapping_error(&pdev->dev, buffer_info->dma))
goto dma_error;
@@ -5268,7 +5293,7 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
if (tx_flags & E1000_TX_FLAGS_TSO) {
txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
- E1000_TXD_CMD_TSE;
+ E1000_TXD_CMD_TSE;
txd_upper |= E1000_TXD_POPTS_TXSM << 8;
if (tx_flags & E1000_TX_FLAGS_IPV4)
@@ -5299,8 +5324,8 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
buffer_info = &tx_ring->buffer_info[i];
tx_desc = E1000_TX_DESC(*tx_ring, i);
tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
- tx_desc->lower.data =
- cpu_to_le32(txd_lower | buffer_info->length);
+ tx_desc->lower.data = cpu_to_le32(txd_lower |
+ buffer_info->length);
tx_desc->upper.data = cpu_to_le32(txd_upper);
i++;
@@ -5350,11 +5375,11 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
return 0;
- if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP))
+ if (((struct ethhdr *)skb->data)->h_proto != htons(ETH_P_IP))
return 0;
{
- const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14);
+ const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data + 14);
struct udphdr *udp;
if (ip->protocol != IPPROTO_UDP)
@@ -5579,7 +5604,7 @@ static void e1000_reset_task(struct work_struct *work)
* Returns the address of the device statistics structure.
**/
struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
- struct rtnl_link_stats64 *stats)
+ struct rtnl_link_stats64 *stats)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -5600,18 +5625,15 @@ struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev,
* our own version based on RUC and ROC
*/
stats->rx_errors = adapter->stats.rxerrc +
- adapter->stats.crcerrs + adapter->stats.algnerrc +
- adapter->stats.ruc + adapter->stats.roc +
- adapter->stats.cexterr;
- stats->rx_length_errors = adapter->stats.ruc +
- adapter->stats.roc;
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc + adapter->stats.cexterr;
+ stats->rx_length_errors = adapter->stats.ruc + adapter->stats.roc;
stats->rx_crc_errors = adapter->stats.crcerrs;
stats->rx_frame_errors = adapter->stats.algnerrc;
stats->rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
- stats->tx_errors = adapter->stats.ecol +
- adapter->stats.latecol;
+ stats->tx_errors = adapter->stats.ecol + adapter->stats.latecol;
stats->tx_aborted_errors = adapter->stats.ecol;
stats->tx_window_errors = adapter->stats.latecol;
stats->tx_carrier_errors = adapter->stats.tncrs;
@@ -5680,9 +5702,9 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* adjust allocation if LPE protects us, and we aren't using SBP */
if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
- (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
+ (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
- + ETH_FCS_LEN;
+ + ETH_FCS_LEN;
if (netif_running(netdev))
e1000e_up(adapter);
@@ -5861,7 +5883,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
phy_reg &= ~(BM_RCTL_MO_MASK);
if (mac_reg & E1000_RCTL_MO_3)
phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT)
- << BM_RCTL_MO_SHIFT);
+ << BM_RCTL_MO_SHIFT);
if (mac_reg & E1000_RCTL_BAM)
phy_reg |= BM_RCTL_BAM;
if (mac_reg & E1000_RCTL_PMCF)
@@ -5930,10 +5952,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
}
ctrl = er32(CTRL);
- /* advertise wake from D3Cold */
- #define E1000_CTRL_ADVD3WUC 0x00100000
- /* phy power management enable */
- #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
ctrl |= E1000_CTRL_ADVD3WUC;
if (!(adapter->flags2 & FLAG2_HAS_PHY_WAKEUP))
ctrl |= E1000_CTRL_EN_PHY_PWR_MGMT;
@@ -5977,8 +5995,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
*/
e1000e_release_hw_control(adapter);
- pci_clear_master(pdev);
-
/* The pci-e switch on some quad port adapters will report a
* correctable error when the MAC transitions from D0 to D3. To
* prevent this we need to mask off the correctable errors on the
@@ -6077,24 +6093,24 @@ static int __e1000_resume(struct pci_dev *pdev)
e1e_rphy(&adapter->hw, BM_WUS, &phy_data);
if (phy_data) {
e_info("PHY Wakeup cause - %s\n",
- phy_data & E1000_WUS_EX ? "Unicast Packet" :
- phy_data & E1000_WUS_MC ? "Multicast Packet" :
- phy_data & E1000_WUS_BC ? "Broadcast Packet" :
- phy_data & E1000_WUS_MAG ? "Magic Packet" :
- phy_data & E1000_WUS_LNKC ?
- "Link Status Change" : "other");
+ phy_data & E1000_WUS_EX ? "Unicast Packet" :
+ phy_data & E1000_WUS_MC ? "Multicast Packet" :
+ phy_data & E1000_WUS_BC ? "Broadcast Packet" :
+ phy_data & E1000_WUS_MAG ? "Magic Packet" :
+ phy_data & E1000_WUS_LNKC ?
+ "Link Status Change" : "other");
}
e1e_wphy(&adapter->hw, BM_WUS, ~0);
} else {
u32 wus = er32(WUS);
if (wus) {
e_info("MAC Wakeup cause - %s\n",
- wus & E1000_WUS_EX ? "Unicast Packet" :
- wus & E1000_WUS_MC ? "Multicast Packet" :
- wus & E1000_WUS_BC ? "Broadcast Packet" :
- wus & E1000_WUS_MAG ? "Magic Packet" :
- wus & E1000_WUS_LNKC ? "Link Status Change" :
- "other");
+ wus & E1000_WUS_EX ? "Unicast Packet" :
+ wus & E1000_WUS_MC ? "Multicast Packet" :
+ wus & E1000_WUS_BC ? "Broadcast Packet" :
+ wus & E1000_WUS_MAG ? "Magic Packet" :
+ wus & E1000_WUS_LNKC ? "Link Status Change" :
+ "other");
}
ew32(WUS, ~0);
}
@@ -6369,7 +6385,7 @@ static void e1000_print_device_info(struct e1000_adapter *adapter)
e_info("(PCI Express:2.5GT/s:%s) %pM\n",
/* bus width */
((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
- "Width x1"),
+ "Width x1"),
/* MAC address */
netdev->dev_addr);
e_info("Intel(R) PRO/%s Network Connection\n",
@@ -6409,7 +6425,7 @@ static int e1000_set_features(struct net_device *netdev,
if (changed & (NETIF_F_TSO | NETIF_F_TSO6))
adapter->flags |= FLAG_TSO_FORCE;
- if (!(changed & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX |
+ if (!(changed & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_RXFCS |
NETIF_F_RXALL)))
return 0;
@@ -6479,7 +6495,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
resource_size_t flash_start, flash_len;
static int cards_found;
u16 aspm_disable_flag = 0;
- int i, err, pci_using_dac;
+ int bars, i, err, pci_using_dac;
u16 eeprom_data = 0;
u16 eeprom_apme_mask = E1000_EEPROM_APME;
@@ -6506,15 +6522,16 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = dma_set_coherent_mask(&pdev->dev,
DMA_BIT_MASK(32));
if (err) {
- dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
goto err_dma;
}
}
}
- err = pci_request_selected_regions_exclusive(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM),
- e1000e_driver_name);
+ bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ err = pci_request_selected_regions_exclusive(pdev, bars,
+ e1000e_driver_name);
if (err)
goto err_pci_reg;
@@ -6567,6 +6584,10 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_flashmap;
}
+ /* Set default EEE advertisement */
+ if (adapter->flags2 & FLAG2_HAS_EEE)
+ adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
+
/* construct the net_device struct */
netdev->netdev_ops = &e1000e_netdev_ops;
e1000e_set_ethtool_ops(netdev);
@@ -6615,8 +6636,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Set initial default active device features */
netdev->features = (NETIF_F_SG |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXHASH |
@@ -6630,7 +6651,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features |= NETIF_F_RXALL;
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
- netdev->features |= NETIF_F_HW_VLAN_FILTER;
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
netdev->vlan_features |= (NETIF_F_SG |
NETIF_F_TSO |
@@ -6683,11 +6704,11 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
init_timer(&adapter->watchdog_timer);
adapter->watchdog_timer.function = e1000_watchdog;
- adapter->watchdog_timer.data = (unsigned long) adapter;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
init_timer(&adapter->phy_info_timer);
adapter->phy_info_timer.function = e1000_update_phy_info;
- adapter->phy_info_timer.data = (unsigned long) adapter;
+ adapter->phy_info_timer.data = (unsigned long)adapter;
INIT_WORK(&adapter->reset_task, e1000_reset_task);
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
@@ -6795,7 +6816,7 @@ err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_selected_regions(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM));
+ pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
pci_disable_device(pdev);
@@ -6865,7 +6886,7 @@ static void e1000_remove(struct pci_dev *pdev)
if (adapter->hw.flash_address)
iounmap(adapter->hw.flash_address);
pci_release_selected_regions(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM));
+ pci_select_bars(pdev, IORESOURCE_MEM));
free_netdev(netdev);
@@ -6886,7 +6907,8 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP),
+ board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 },
@@ -6962,8 +6984,8 @@ MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
#ifdef CONFIG_PM
static const struct dev_pm_ops e1000_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
- SET_RUNTIME_PM_OPS(e1000_runtime_suspend,
- e1000_runtime_resume, e1000_idle)
+ SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume,
+ e1000_idle)
};
#endif
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index 84fecc268162..44ddc0a0ee0e 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -630,7 +630,7 @@ void e1000e_reload_nvm_generic(struct e1000_hw *hw)
{
u32 ctrl_ext;
- udelay(10);
+ usleep_range(10, 20);
ctrl_ext = er32(CTRL_EXT);
ctrl_ext |= E1000_CTRL_EXT_EE_RST;
ew32(CTRL_EXT, ctrl_ext);
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 98da75dff936..c16bd75b6caa 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -45,7 +45,7 @@
unsigned int copybreak = COPYBREAK_DEFAULT;
module_param(copybreak, uint, 0644);
MODULE_PARM_DESC(copybreak,
- "Maximum size of packet that is copied to a new buffer on receive");
+ "Maximum size of packet that is copied to a new buffer on receive");
/* All parameters are treated the same, as an integer array of values.
* This macro just reduces the need to repeat the same declaration code
@@ -143,7 +143,8 @@ E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
*
* Default Value: 1 (enabled)
*/
-E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
+E1000_PARAM(WriteProtectNVM,
+ "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
/* Enable CRC Stripping
*
@@ -160,13 +161,18 @@ struct e1000_option {
const char *err;
int def;
union {
- struct { /* range_option info */
+ /* range_option info */
+ struct {
int min;
int max;
} r;
- struct { /* list_option info */
+ /* list_option info */
+ struct {
int nr;
- struct e1000_opt_list { int i; char *str; } *p;
+ struct e1000_opt_list {
+ int i;
+ char *str;
+ } *p;
} l;
} arg;
};
@@ -246,7 +252,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
"Using defaults for all values\n");
}
- { /* Transmit Interrupt Delay */
+ /* Transmit Interrupt Delay */
+ {
static const struct e1000_option opt = {
.type = range_option,
.name = "Transmit Interrupt Delay",
@@ -265,7 +272,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->tx_int_delay = opt.def;
}
}
- { /* Transmit Absolute Interrupt Delay */
+ /* Transmit Absolute Interrupt Delay */
+ {
static const struct e1000_option opt = {
.type = range_option,
.name = "Transmit Absolute Interrupt Delay",
@@ -284,7 +292,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->tx_abs_int_delay = opt.def;
}
}
- { /* Receive Interrupt Delay */
+ /* Receive Interrupt Delay */
+ {
static struct e1000_option opt = {
.type = range_option,
.name = "Receive Interrupt Delay",
@@ -303,7 +312,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->rx_int_delay = opt.def;
}
}
- { /* Receive Absolute Interrupt Delay */
+ /* Receive Absolute Interrupt Delay */
+ {
static const struct e1000_option opt = {
.type = range_option,
.name = "Receive Absolute Interrupt Delay",
@@ -322,7 +332,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->rx_abs_int_delay = opt.def;
}
}
- { /* Interrupt Throttling Rate */
+ /* Interrupt Throttling Rate */
+ {
static const struct e1000_option opt = {
.type = range_option,
.name = "Interrupt Throttling Rate (ints/sec)",
@@ -392,7 +403,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
break;
}
}
- { /* Interrupt Mode */
+ /* Interrupt Mode */
+ {
static struct e1000_option opt = {
.type = range_option,
.name = "Interrupt Mode",
@@ -435,7 +447,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
kfree(opt.err);
#endif
}
- { /* Smart Power Down */
+ /* Smart Power Down */
+ {
static const struct e1000_option opt = {
.type = enable_option,
.name = "PHY Smart Power Down",
@@ -450,7 +463,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->flags |= FLAG_SMART_POWER_DOWN;
}
}
- { /* CRC Stripping */
+ /* CRC Stripping */
+ {
static const struct e1000_option opt = {
.type = enable_option,
.name = "CRC Stripping",
@@ -470,27 +484,28 @@ void e1000e_check_options(struct e1000_adapter *adapter)
adapter->flags2 |= FLAG2_DFLT_CRC_STRIPPING;
}
}
- { /* Kumeran Lock Loss Workaround */
+ /* Kumeran Lock Loss Workaround */
+ {
static const struct e1000_option opt = {
.type = enable_option,
.name = "Kumeran Lock Loss Workaround",
.err = "defaulting to Enabled",
.def = OPTION_ENABLED
};
+ bool enabled = opt.def;
if (num_KumeranLockLoss > bd) {
unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
- if (hw->mac.type == e1000_ich8lan)
- e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
- kmrn_lock_loss);
- } else {
- if (hw->mac.type == e1000_ich8lan)
- e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
- opt.def);
+ enabled = kmrn_lock_loss;
}
+
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+ enabled);
}
- { /* Write-protect NVM */
+ /* Write-protect NVM */
+ {
static const struct e1000_option opt = {
.type = enable_option,
.name = "Write-protect NVM",
@@ -500,7 +515,8 @@ void e1000e_check_options(struct e1000_adapter *adapter)
if (adapter->flags & FLAG_IS_ICH) {
if (num_WriteProtectNVM > bd) {
- unsigned int write_protect_nvm = WriteProtectNVM[bd];
+ unsigned int write_protect_nvm =
+ WriteProtectNVM[bd];
e1000_validate_option(&write_protect_nvm, &opt,
adapter);
if (write_protect_nvm)
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 0930c136aa31..59c76a6815a0 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -37,7 +37,9 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
/* Cable length tables */
static const u16 e1000_m88_cable_length_table[] = {
- 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED
+};
+
#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_m88_cable_length_table)
@@ -49,7 +51,9 @@ static const u16 e1000_igp_2_cable_length_table[] = {
66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82,
87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95,
100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
- 124};
+ 124
+};
+
#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
ARRAY_SIZE(e1000_igp_2_cable_length_table)
@@ -67,8 +71,7 @@ s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
manc = er32(MANC);
- return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
- E1000_BLK_PHY_RESET : 0;
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : 0;
}
/**
@@ -94,7 +97,7 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw)
return ret_val;
phy->id = (u32)(phy_id << 16);
- udelay(20);
+ usleep_range(20, 40);
ret_val = e1e_rphy(hw, MII_PHYSID2, &phy_id);
if (ret_val)
return ret_val;
@@ -175,7 +178,13 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
e_dbg("MDI Error\n");
return -E1000_ERR_PHY;
}
- *data = (u16) mdic;
+ if (((mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT) != offset) {
+ e_dbg("MDI Read offset error - requested %d, returned %d\n",
+ offset,
+ (mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+ return -E1000_ERR_PHY;
+ }
+ *data = (u16)mdic;
/* Allow some time after each MDIC transaction to avoid
* reading duplicate data in the next MDIC transaction.
@@ -233,6 +242,12 @@ s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
e_dbg("MDI Error\n");
return -E1000_ERR_PHY;
}
+ if (((mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT) != offset) {
+ e_dbg("MDI Write offset error - requested %d, returned %d\n",
+ offset,
+ (mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+ return -E1000_ERR_PHY;
+ }
/* Allow some time after each MDIC transaction to avoid
* reading duplicate data in the next MDIC transaction.
@@ -324,7 +339,7 @@ s32 e1000_set_page_igp(struct e1000_hw *hw, u16 page)
* semaphores before exiting.
**/
static s32 __e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data,
- bool locked)
+ bool locked)
{
s32 ret_val = 0;
@@ -391,7 +406,7 @@ s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data)
* at the offset. Release any acquired semaphores before exiting.
**/
static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
- bool locked)
+ bool locked)
{
s32 ret_val = 0;
@@ -410,8 +425,7 @@ static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data,
(u16)offset);
if (!ret_val)
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS &
- offset,
- data);
+ offset, data);
if (!locked)
hw->phy.ops.release(hw);
@@ -458,7 +472,7 @@ s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data)
* Release any acquired semaphores before exiting.
**/
static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
- bool locked)
+ bool locked)
{
u32 kmrnctrlsta;
@@ -531,7 +545,7 @@ s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data)
* before exiting.
**/
static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
- bool locked)
+ bool locked)
{
u32 kmrnctrlsta;
@@ -772,8 +786,7 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
phy_data |= M88E1000_EPSCR_TX_CLK_25;
- if ((phy->revision == 2) &&
- (phy->id == M88E1111_I_PHY_ID)) {
+ if ((phy->revision == 2) && (phy->id == M88E1111_I_PHY_ID)) {
/* 82573L PHY - set the downshift counter to 5x. */
phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
@@ -1296,7 +1309,7 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
e_dbg("Waiting for forced speed/duplex link on M88 phy.\n");
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
- 100000, &link);
+ 100000, &link);
if (ret_val)
return ret_val;
@@ -1319,7 +1332,7 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
/* Try once more */
ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
- 100000, &link);
+ 100000, &link);
if (ret_val)
return ret_val;
}
@@ -1609,9 +1622,9 @@ s32 e1000_check_polarity_m88(struct e1000_hw *hw)
ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
if (!ret_val)
- phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -1653,9 +1666,9 @@ s32 e1000_check_polarity_igp(struct e1000_hw *hw)
ret_val = e1e_rphy(hw, offset, &data);
if (!ret_val)
- phy->cable_polarity = (data & mask)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -1685,9 +1698,9 @@ s32 e1000_check_polarity_ife(struct e1000_hw *hw)
ret_val = e1e_rphy(hw, offset, &phy_data);
if (!ret_val)
- phy->cable_polarity = (phy_data & mask)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((phy_data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -1733,7 +1746,7 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw)
* Polls the PHY status register for link, 'iterations' number of times.
**/
s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
- u32 usec_interval, bool *success)
+ u32 usec_interval, bool *success)
{
s32 ret_val = 0;
u16 i, phy_status;
@@ -1756,7 +1769,7 @@ s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
if (phy_status & BMSR_LSTATUS)
break;
if (usec_interval >= 1000)
- mdelay(usec_interval/1000);
+ mdelay(usec_interval / 1000);
else
udelay(usec_interval);
}
@@ -1791,8 +1804,8 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ index = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT);
if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1)
return -E1000_ERR_PHY;
@@ -1824,10 +1837,10 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
u16 cur_agc_index, max_agc_index = 0;
u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = {
- IGP02E1000_PHY_AGC_A,
- IGP02E1000_PHY_AGC_B,
- IGP02E1000_PHY_AGC_C,
- IGP02E1000_PHY_AGC_D
+ IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D
};
/* Read the AGC registers for all channels */
@@ -1841,8 +1854,8 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
* that can be put into the lookup table to obtain the
* approximate cable length.
*/
- cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
- IGP02E1000_AGC_LENGTH_MASK;
+ cur_agc_index = ((phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK);
/* Array index bound check. */
if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
@@ -1865,8 +1878,8 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
/* Calculate cable length with the error range of +/- 10 meters. */
- phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
- (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->min_cable_length = (((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0);
phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
@@ -2040,9 +2053,9 @@ s32 e1000_get_phy_info_ife(struct e1000_hw *hw)
return ret_val;
} else {
/* Polarity is forced */
- phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
}
ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
@@ -2119,7 +2132,7 @@ s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
ew32(CTRL, ctrl);
e1e_flush();
- udelay(150);
+ usleep_range(150, 300);
phy->ops.release(hw);
@@ -2375,13 +2388,13 @@ s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data)
/* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
- (page << page_shift));
+ (page << page_shift));
if (ret_val)
goto release;
}
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
+ data);
release:
hw->phy.ops.release(hw);
@@ -2433,13 +2446,13 @@ s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data)
/* Page is shifted left, PHY expects (page x 32) */
ret_val = e1000e_write_phy_reg_mdic(hw, page_select,
- (page << page_shift));
+ (page << page_shift));
if (ret_val)
goto release;
}
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
+ data);
release:
hw->phy.ops.release(hw);
return ret_val;
@@ -2674,7 +2687,7 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,
if (read) {
/* Read the Wakeup register page value using opcode 0x12 */
ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
- data);
+ data);
} else {
/* Write the Wakeup register page value using opcode 0x12 */
ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,
@@ -2763,7 +2776,7 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
if (page > 0 && page < HV_INTC_FC_PAGE_START) {
ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
- data, true);
+ data, true);
goto out;
}
@@ -2786,8 +2799,7 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data,
e_dbg("reading PHY page %d (or 0x%x shifted) reg 0x%x\n", page,
page << IGP_PAGE_SHIFT, reg);
- ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
- data);
+ ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, data);
out:
if (!locked)
hw->phy.ops.release(hw);
@@ -2871,7 +2883,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
if (page > 0 && page < HV_INTC_FC_PAGE_START) {
ret_val = e1000_access_phy_debug_regs_hv(hw, offset,
- &data, false);
+ &data, false);
goto out;
}
@@ -2910,7 +2922,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data,
page << IGP_PAGE_SHIFT, reg);
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg,
- data);
+ data);
out:
if (!locked)
@@ -2988,15 +3000,15 @@ static u32 e1000_get_phy_addr_for_hv_page(u32 page)
* These accesses done with PHY address 2 and without using pages.
**/
static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset,
- u16 *data, bool read)
+ u16 *data, bool read)
{
s32 ret_val;
u32 addr_reg;
u32 data_reg;
/* This takes care of the difference with desktop vs mobile phy */
- addr_reg = (hw->phy.type == e1000_phy_82578) ?
- I82578_ADDR_REG : I82577_ADDR_REG;
+ addr_reg = ((hw->phy.type == e1000_phy_82578) ?
+ I82578_ADDR_REG : I82577_ADDR_REG);
data_reg = addr_reg + 1;
/* All operations in this function are phy address 2 */
@@ -3050,8 +3062,8 @@ s32 e1000_link_stall_workaround_hv(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- data &= BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
- BM_CS_STATUS_SPEED_MASK;
+ data &= (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
+ BM_CS_STATUS_SPEED_MASK);
if (data != (BM_CS_STATUS_LINK_UP | BM_CS_STATUS_RESOLVED |
BM_CS_STATUS_SPEED_1000))
@@ -3086,9 +3098,9 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw)
ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data);
if (!ret_val)
- phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ phy->cable_polarity = ((data & I82577_PHY_STATUS2_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal);
return ret_val;
}
@@ -3215,8 +3227,8 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
- I82577_DSTATUS_CABLE_LENGTH_SHIFT;
+ length = ((phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
+ I82577_DSTATUS_CABLE_LENGTH_SHIFT);
if (length == E1000_CABLE_LENGTH_UNDEFINED)
return -E1000_ERR_PHY;
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index b477fa53ec94..065f8c80d4f2 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -145,8 +145,7 @@ static int e1000e_phc_settime(struct ptp_clock_info *ptp,
unsigned long flags;
u64 ns;
- ns = ts->tv_sec * NSEC_PER_SEC;
- ns += ts->tv_nsec;
+ ns = timespec_to_ns(ts);
/* reset the timecounter */
spin_lock_irqsave(&adapter->systim_lock, flags);
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 12b1d8480808..ff6a17cb1362 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -100,6 +100,7 @@ static bool igb_sgmii_uses_mdio_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
reg = rd32(E1000_MDICNFG);
@@ -149,6 +150,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
phy->ops.read_reg = igb_read_phy_reg_82580;
phy->ops.write_reg = igb_write_phy_reg_82580;
break;
@@ -174,13 +176,14 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
/* Verify phy id and set remaining function pointers */
switch (phy->id) {
+ case M88E1545_E_PHY_ID:
case I347AT4_E_PHY_ID:
case M88E1112_E_PHY_ID:
case M88E1111_I_PHY_ID:
phy->type = e1000_phy_m88;
+ phy->ops.check_polarity = igb_check_polarity_m88;
phy->ops.get_phy_info = igb_get_phy_info_m88;
- if (phy->id == I347AT4_E_PHY_ID ||
- phy->id == M88E1112_E_PHY_ID)
+ if (phy->id != M88E1111_I_PHY_ID)
phy->ops.get_cable_length =
igb_get_cable_length_m88_gen2;
else
@@ -227,7 +230,7 @@ out:
* igb_init_nvm_params_82575 - Init NVM func ptrs.
* @hw: pointer to the HW structure
**/
-s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
+static s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
{
struct e1000_nvm_info *nvm = &hw->nvm;
u32 eecd = rd32(E1000_EECD);
@@ -287,6 +290,7 @@ s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
nvm->ops.read = igb_read_nvm_spi;
nvm->ops.write = igb_write_nvm_spi;
break;
+ case e1000_i354:
case e1000_i350:
nvm->ops.validate = igb_validate_nvm_checksum_i350;
nvm->ops.update = igb_update_nvm_checksum_i350;
@@ -352,6 +356,7 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
break;
case e1000_i350:
+ case e1000_i354:
mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
break;
default:
@@ -384,6 +389,9 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
dev_spec->eee_disable = false;
else
dev_spec->eee_disable = true;
+ /* Allow a single clear of the SW semaphore on I210 and newer */
+ if (mac->type >= e1000_i210)
+ dev_spec->clear_semaphore_once = true;
/* physical interface link setup */
mac->ops.setup_physical_interface =
(hw->phy.media_type == e1000_media_type_copper)
@@ -435,8 +443,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
mac->type = e1000_i350;
break;
case E1000_DEV_ID_I210_COPPER:
- case E1000_DEV_ID_I210_COPPER_OEM1:
- case E1000_DEV_ID_I210_COPPER_IT:
case E1000_DEV_ID_I210_FIBER:
case E1000_DEV_ID_I210_SERDES:
case E1000_DEV_ID_I210_SGMII:
@@ -445,14 +451,18 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_I211_COPPER:
mac->type = e1000_i211;
break;
+ case E1000_DEV_ID_I354_BACKPLANE_1GBPS:
+ case E1000_DEV_ID_I354_SGMII:
+ case E1000_DEV_ID_I354_BACKPLANE_2_5GBPS:
+ mac->type = e1000_i354;
+ break;
default:
return -E1000_ERR_MAC_INIT;
break;
}
/* Set media type */
- /*
- * The 82575 uses bits 22:23 for link mode. The mode can be changed
+ /* The 82575 uses bits 22:23 for link mode. The mode can be changed
* based on the EEPROM. We cannot rely upon device ID. There
* is no distinguishable difference between fiber and internal
* SerDes mode on the 82575. There can be an external PHY attached
@@ -621,8 +631,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
u32 ctrl_ext;
u32 mdic;
- /*
- * For SGMII PHYs, we try the list of possible addresses until
+ /* For SGMII PHYs, we try the list of possible addresses until
* we find one that works. For non-SGMII PHYs
* (e.g. integrated copper PHYs), an address of 1 should
* work. The result of this function should mean phy->phy_addr
@@ -644,6 +653,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
mdic = rd32(E1000_MDICNFG);
@@ -665,8 +675,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
wrfl();
msleep(300);
- /*
- * The address field in the I2CCMD register is 3 bits and 0 is invalid.
+ /* The address field in the I2CCMD register is 3 bits and 0 is invalid.
* Therefore, we need to test 1-7
*/
for (phy->addr = 1; phy->addr < 8; phy->addr++) {
@@ -674,8 +683,7 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
if (ret_val == 0) {
hw_dbg("Vendor ID 0x%08X read at address %u\n",
phy_id, phy->addr);
- /*
- * At the time of this writing, The M88 part is
+ /* At the time of this writing, The M88 part is
* the only supported SGMII PHY product.
*/
if (phy_id == M88_VENDOR)
@@ -711,15 +719,13 @@ static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
{
s32 ret_val;
- /*
- * This isn't a true "hard" reset, but is the only reset
+ /* This isn't a true "hard" reset, but is the only reset
* available to us at this time.
*/
hw_dbg("Soft resetting SGMII attached PHY...\n");
- /*
- * SFP documentation requires the following to configure the SPF module
+ /* SFP documentation requires the following to configure the SPF module
* to work on SGMII. No further documentation is given.
*/
ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
@@ -774,8 +780,7 @@ static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
data &= ~IGP02E1000_PM_D0_LPLU;
ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
data);
- /*
- * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
@@ -838,8 +843,7 @@ static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active)
} else {
data &= ~E1000_82580_PM_D0_LPLU;
- /*
- * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
@@ -867,7 +871,7 @@ static s32 igb_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active)
* During driver activity, SmartSpeed should be enabled so performance is
* maintained.
**/
-s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
+static s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
{
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val = 0;
@@ -877,8 +881,7 @@ s32 igb_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
if (!active) {
data &= ~E1000_82580_PM_D3_LPLU;
- /*
- * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
@@ -964,8 +967,7 @@ static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
if (!(swfw_sync & (fwmask | swmask)))
break;
- /*
- * Firmware currently using resource (fwmask)
+ /* Firmware currently using resource (fwmask)
* or other software thread using resource (swmask)
*/
igb_put_hw_semaphore(hw);
@@ -1065,8 +1067,7 @@ static s32 igb_check_for_link_82575(struct e1000_hw *hw)
if (hw->phy.media_type != e1000_media_type_copper) {
ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed,
&duplex);
- /*
- * Use this flag to determine if link needs to be checked or
+ /* Use this flag to determine if link needs to be checked or
* not. If we have link clear the flag so that we do not
* continue to check for link.
*/
@@ -1135,15 +1136,13 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
*speed = 0;
*duplex = 0;
- /*
- * Read the PCS Status register for link state. For non-copper mode,
+ /* Read the PCS Status register for link state. For non-copper mode,
* the status register is not accurate. The PCS status register is
* used instead.
*/
pcs = rd32(E1000_PCS_LSTAT);
- /*
- * The link up bit determines when link is up on autoneg. The sync ok
+ /* The link up bit determines when link is up on autoneg. The sync ok
* gets set once both sides sync up and agree upon link. Stable link
* can be determined by checking for both link up and link sync ok
*/
@@ -1214,8 +1213,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
u32 ctrl, icr;
s32 ret_val;
- /*
- * Prevent the PCI-E bus from sticking if there is no TLP connection
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
* on the last TLP read/write transaction when MAC is reset.
*/
ret_val = igb_disable_pcie_master(hw);
@@ -1244,8 +1242,7 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
ret_val = igb_get_auto_rd_done(hw);
if (ret_val) {
- /*
- * When auto config read does not complete, do not
+ /* When auto config read does not complete, do not
* return with an error. This can happen in situations
* where there is no eeprom and prevents getting link.
*/
@@ -1287,7 +1284,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
/* Disabling VLAN filtering */
hw_dbg("Initializing the IEEE VLAN\n");
- if (hw->mac.type == e1000_i350)
+ if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
igb_clear_vfta_i350(hw);
else
igb_clear_vfta(hw);
@@ -1308,8 +1305,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
/* Setup link and flow control */
ret_val = igb_setup_link(hw);
- /*
- * Clear all of the statistics registers (clear on read). It is
+ /* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
* because the symbol error count will increment wildly if there
* is no link.
@@ -1364,6 +1360,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
switch (hw->phy.id) {
case I347AT4_E_PHY_ID:
case M88E1112_E_PHY_ID:
+ case M88E1545_E_PHY_ID:
case I210_I_PHY_ID:
ret_val = igb_copper_link_setup_m88_gen2(hw);
break;
@@ -1412,17 +1409,17 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
return ret_val;
- /*
- * On the 82575, SerDes loopback mode persists until it is
+ /* On the 82575, SerDes loopback mode persists until it is
* explicitly turned off or a power cycle is performed. A read to
* the register does not indicate its status. Therefore, we ensure
* loopback mode is disabled during initialization.
*/
wr32(E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
- /* power on the sfp cage if present */
+ /* power on the sfp cage if present and turn on I2C */
ctrl_ext = rd32(E1000_CTRL_EXT);
ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
+ ctrl_ext |= E1000_CTRL_I2C_ENA;
wr32(E1000_CTRL_EXT, ctrl_ext);
ctrl_reg = rd32(E1000_CTRL);
@@ -1466,8 +1463,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
pcs_autoneg = false;
}
- /*
- * non-SGMII modes only supports a speed of 1000/Full for the
+ /* non-SGMII modes only supports a speed of 1000/Full for the
* link so it is best to just force the MAC and let the pcs
* link either autoneg or be forced to 1000/Full
*/
@@ -1481,8 +1477,7 @@ static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw)
wr32(E1000_CTRL, ctrl_reg);
- /*
- * New SerDes mode allows for forcing speed or autonegotiating speed
+ /* New SerDes mode allows for forcing speed or autonegotiating speed
* at 1gb. Autoneg should be default set by most drivers. This is the
* mode that will be compatible with older link partners and switches.
* However, both are supported by the hardware and some drivers/tools.
@@ -1592,8 +1587,7 @@ static s32 igb_read_mac_addr_82575(struct e1000_hw *hw)
{
s32 ret_val = 0;
- /*
- * If there's an alternate MAC address place it in RAR0
+ /* If there's an alternate MAC address place it in RAR0
* so that it will override the Si installed default perm
* address.
*/
@@ -1777,8 +1771,7 @@ static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
goto out;
- /*
- * if capababilities version is type 1 we can write the
+ /* if capabilities version is type 1 we can write the
* timeout of 10ms to 200ms through the GCR register
*/
if (!(gcr & E1000_GCR_CAP_VER2)) {
@@ -1786,8 +1779,7 @@ static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
goto out;
}
- /*
- * for version 2 capabilities we need to write the config space
+ /* for version 2 capabilities we need to write the config space
* directly in order to set the completion timeout value for
* 16ms to 55ms
*/
@@ -1825,6 +1817,7 @@ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
reg_offset = E1000_DTXSWC;
break;
case e1000_i350:
+ case e1000_i354:
reg_offset = E1000_TXSWC;
break;
default:
@@ -1866,6 +1859,7 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
wr32(E1000_DTXSWC, dtxswc);
break;
+ case e1000_i354:
case e1000_i350:
dtxswc = rd32(E1000_TXSWC);
if (enable)
@@ -1879,7 +1873,6 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
break;
}
-
}
/**
@@ -1914,7 +1907,6 @@ static s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
{
s32 ret_val;
-
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
goto out;
@@ -2016,8 +2008,7 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
/* Get current control state. */
ctrl = rd32(E1000_CTRL);
- /*
- * Prevent the PCI-E bus from sticking if there is no TLP connection
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
* on the last TLP read/write transaction when MAC is reset.
*/
ret_val = igb_disable_pcie_master(hw);
@@ -2052,18 +2043,13 @@ static s32 igb_reset_hw_82580(struct e1000_hw *hw)
ret_val = igb_get_auto_rd_done(hw);
if (ret_val) {
- /*
- * When auto config read does not complete, do not
+ /* When auto config read does not complete, do not
* return with an error. This can happen in situations
* where there is no eeprom and prevents getting link.
*/
hw_dbg("Auto Read Done did not complete\n");
}
- /* If EEPROM is not present, run manual init scripts */
- if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0)
- igb_reset_init_script_82575(hw);
-
/* clear global device reset status bit */
wr32(E1000_STATUS, E1000_STAT_DEV_RST_SET);
@@ -2197,7 +2183,8 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw)
if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) {
/* if checksums compatibility bit is set validate checksums
- * for all 4 ports. */
+ * for all 4 ports.
+ */
eeprom_regions_count = 4;
}
@@ -2309,6 +2296,41 @@ out:
}
/**
+ * __igb_access_emi_reg - Read/write EMI register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: pointer to value to read/write from/to the EMI address
+ * @read: boolean flag to indicate read or write
+ **/
+static s32 __igb_access_emi_reg(struct e1000_hw *hw, u16 address,
+ u16 *data, bool read)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_EMIADD, address);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = hw->phy.ops.read_reg(hw, E1000_EMIDATA, data);
+ else
+ ret_val = hw->phy.ops.write_reg(hw, E1000_EMIDATA, *data);
+
+ return ret_val;
+}
+
+/**
+ * igb_read_emi_reg - Read Extended Management Interface register
+ * @hw: pointer to the HW structure
+ * @addr: EMI address to program
+ * @data: value to be read from the EMI address
+ **/
+s32 igb_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data)
+{
+ return __igb_access_emi_reg(hw, addr, data, true);
+}
+
+/**
* igb_set_eee_i350 - Enable/disable EEE support
* @hw: pointer to the HW structure
*
@@ -2338,7 +2360,6 @@ s32 igb_set_eee_i350(struct e1000_hw *hw)
if (eee_su & E1000_EEE_SU_LPI_CLK_STP)
hw_dbg("LPI Clock Stop Bit should not be set!\n");
-
} else {
ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN |
E1000_IPCNFG_EEE_100M_AN);
@@ -2355,6 +2376,108 @@ out:
return ret_val;
}
+/**
+ * igb_set_eee_i354 - Enable/disable EEE support
+ * @hw: pointer to the HW structure
+ *
+ * Enable/disable EEE legacy mode based on setting in dev_spec structure.
+ *
+ **/
+s32 igb_set_eee_i354(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 phy_data;
+
+ if ((hw->phy.media_type != e1000_media_type_copper) ||
+ (phy->id != M88E1545_E_PHY_ID))
+ goto out;
+
+ if (!hw->dev_spec._82575.eee_disable) {
+ /* Switch to PHY page 18. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1545_PAGE_ADDR, 18);
+ if (ret_val)
+ goto out;
+
+ ret_val = phy->ops.read_reg(hw, E1000_M88E1545_EEE_CTRL_1,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= E1000_M88E1545_EEE_CTRL_1_MS;
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1545_EEE_CTRL_1,
+ phy_data);
+ if (ret_val)
+ goto out;
+
+ /* Return the PHY to page 0. */
+ ret_val = phy->ops.write_reg(hw, E1000_M88E1545_PAGE_ADDR, 0);
+ if (ret_val)
+ goto out;
+
+ /* Turn on EEE advertisement. */
+ ret_val = igb_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data |= E1000_EEE_ADV_100_SUPPORTED |
+ E1000_EEE_ADV_1000_SUPPORTED;
+ ret_val = igb_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ phy_data);
+ } else {
+ /* Turn off EEE advertisement. */
+ ret_val = igb_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ phy_data &= ~(E1000_EEE_ADV_100_SUPPORTED |
+ E1000_EEE_ADV_1000_SUPPORTED);
+ ret_val = igb_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
+ E1000_EEE_ADV_DEV_I354,
+ phy_data);
+ }
+
+out:
+ return ret_val;
+}
+
+/**
+ * igb_get_eee_status_i354 - Get EEE status
+ * @hw: pointer to the HW structure
+ * @status: EEE status
+ *
+ * Get EEE status by guessing based on whether Tx or Rx LPI indications have
+ * been received.
+ **/
+s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val = 0;
+ u16 phy_data;
+
+ /* Check if EEE is supported on this device. */
+ if ((hw->phy.media_type != e1000_media_type_copper) ||
+ (phy->id != M88E1545_E_PHY_ID))
+ goto out;
+
+ ret_val = igb_read_xmdio_reg(hw, E1000_PCS_STATUS_ADDR_I354,
+ E1000_PCS_STATUS_DEV_I354,
+ &phy_data);
+ if (ret_val)
+ goto out;
+
+ *status = phy_data & (E1000_PCS_STATUS_TX_LPI_RCVD |
+ E1000_PCS_STATUS_RX_LPI_RCVD) ? true : false;
+
+out:
+ return ret_val;
+}
+
static const u8 e1000_emc_temp_data[4] = {
E1000_EMC_INTERNAL_DATA,
E1000_EMC_DIODE1_DATA,
@@ -2368,11 +2491,12 @@ static const u8 e1000_emc_therm_limit[4] = {
E1000_EMC_DIODE3_THERM_LIMIT
};
-/* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
+/**
+ * igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
* @hw: pointer to hardware structure
*
* Updates the temperatures in mac.thermal_sensor_data
- */
+ **/
s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
{
s32 status = E1000_SUCCESS;
@@ -2420,12 +2544,13 @@ s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
return status;
}
-/* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
+/**
+ * igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
* @hw: pointer to hardware structure
*
* Sets the thermal sensor thresholds according to the NVM map
* and save off the threshold and location values into mac.thermal_sensor_data
- */
+ **/
s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
{
s32 status = E1000_SUCCESS;
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h
index 73ab41f0e032..74a1506b4235 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.h
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.h
@@ -263,7 +263,9 @@ void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *, bool, int);
void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
u16 igb_rxpbs_adjust_82580(u32 data);
+s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
s32 igb_set_eee_i350(struct e1000_hw *);
+s32 igb_set_eee_i354(struct e1000_hw *);
s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 7e13337d3b9d..31a0f82cc650 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -138,8 +138,7 @@
#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */
#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
-/*
- * Use byte values for the following shift parameters
+/* Use byte values for the following shift parameters
* Usage:
* psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
* E1000_PSRCTL_BSIZE0_MASK) |
@@ -237,11 +236,14 @@
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000
/* BMC external code execution disabled */
+#define E1000_STATUS_2P5_SKU 0x00001000 /* Val of 2.5GBE SKU strap */
+#define E1000_STATUS_2P5_SKU_OVER 0x00002000 /* Val of 2.5GBE SKU Over */
/* Constants used to intrepret the masked PCI-X bus speed. */
#define SPEED_10 10
#define SPEED_100 100
#define SPEED_1000 1000
+#define SPEED_2500 2500
#define HALF_DUPLEX 1
#define FULL_DUPLEX 2
@@ -382,8 +384,7 @@
#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
/* TCP Timer */
-/*
- * This defines the bits that are set in the Interrupt Mask
+/* This defines the bits that are set in the Interrupt Mask
* Set/Read Register. Each bit is documented below:
* o RXT0 = Receiver Timer Interrupt (ring 0)
* o TXDW = Transmit Descriptor Written Back
@@ -440,8 +441,7 @@
#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
/* Receive Address */
-/*
- * Number of high/low register pairs in the RAR. The RAR (Receive Address
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
* Registers) holds the directed and multicast addresses that we monitor.
* Technically, we have 16 spots. However, we reserve one of these spots
* (RAR[15]) for our directed address used by controllers with
@@ -760,8 +760,7 @@
#define MAX_PHY_MULTI_PAGE_REG 0xF
/* Bit definitions for valid PHY IDs. */
-/*
- * I = Integrated
+/* I = Integrated
* E = External
*/
#define M88E1111_I_PHY_ID 0x01410CC0
@@ -772,6 +771,7 @@
#define I350_I_PHY_ID 0x015403B0
#define M88_VENDOR 0x0141
#define I210_I_PHY_ID 0x01410C00
+#define M88E1545_E_PHY_ID 0x01410EA0
/* M88E1000 Specific Registers */
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
@@ -791,8 +791,7 @@
#define M88E1000_PSCR_AUTO_X_1000T 0x0040
/* Auto crossover enabled all speeds */
#define M88E1000_PSCR_AUTO_X_MODE 0x0060
-/*
- * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
+/* 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold
* 0=Normal 10BASE-T Rx Threshold
*/
/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */
@@ -802,8 +801,7 @@
#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
-/*
- * 0 = <50M
+/* 0 = <50M
* 1 = 50-80M
* 2 = 80-110M
* 3 = 110-140M
@@ -816,20 +814,17 @@
#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
/* M88E1000 Extended PHY Specific Control Register */
-/*
- * 1 = Lost lock detect enabled.
+/* 1 = Lost lock detect enabled.
* Will assert lost lock and bring
* link down if idle not seen
* within 1ms in 1000BASE-T
*/
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
+/* Number of times we will attempt to autonegotiate before downshifting if we
* are the master
*/
#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
+/* Number of times we will attempt to autonegotiate before downshifting if we
* are the slave
*/
#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
@@ -844,8 +839,7 @@
/* i347-AT4 Extended PHY Specific Control Register */
-/*
- * Number of times we will attempt to autonegotiate before downshifting if we
+/* Number of times we will attempt to autonegotiate before downshifting if we
* are the master
*/
#define I347AT4_PSCR_DOWNSHIFT_ENABLE 0x0800
@@ -895,6 +889,22 @@
#define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */
#define E1000_EEE_SU_LPI_CLK_STP 0X00800000 /* EEE LPI Clock Stop */
#define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
+#define E1000_EEE_LP_ADV_ADDR_I350 0x040F /* EEE LP Advertisement */
+#define E1000_EEE_LP_ADV_DEV_I210 7 /* EEE LP Adv Device */
+#define E1000_EEE_LP_ADV_ADDR_I210 61 /* EEE LP Adv Register */
+#define E1000_MMDAC_FUNC_DATA 0x4000 /* Data, no post increment */
+#define E1000_M88E1545_PAGE_ADDR 0x16 /* Page Offset Register */
+#define E1000_M88E1545_EEE_CTRL_1 0x0
+#define E1000_M88E1545_EEE_CTRL_1_MS 0x0001 /* EEE Master/Slave */
+#define E1000_EEE_ADV_DEV_I354 7
+#define E1000_EEE_ADV_ADDR_I354 60
+#define E1000_EEE_ADV_100_SUPPORTED (1 << 1) /* 100BaseTx EEE Supported */
+#define E1000_EEE_ADV_1000_SUPPORTED (1 << 2) /* 1000BaseT EEE Supported */
+#define E1000_PCS_STATUS_DEV_I354 3
+#define E1000_PCS_STATUS_ADDR_I354 1
+#define E1000_PCS_STATUS_TX_LPI_IND 0x0200 /* Tx in LPI state */
+#define E1000_PCS_STATUS_RX_LPI_RCVD 0x0400
+#define E1000_PCS_STATUS_TX_LPI_RCVD 0x0800
/* SerDes Control */
#define E1000_GEN_CTL_READY 0x80000000
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index 0d5cf9c63d0d..488abb24a54f 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -38,38 +38,39 @@
struct e1000_hw;
-#define E1000_DEV_ID_82576 0x10C9
-#define E1000_DEV_ID_82576_FIBER 0x10E6
-#define E1000_DEV_ID_82576_SERDES 0x10E7
-#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
-#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
-#define E1000_DEV_ID_82576_NS 0x150A
-#define E1000_DEV_ID_82576_NS_SERDES 0x1518
-#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
-#define E1000_DEV_ID_82575EB_COPPER 0x10A7
-#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
-#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
-#define E1000_DEV_ID_82580_COPPER 0x150E
-#define E1000_DEV_ID_82580_FIBER 0x150F
-#define E1000_DEV_ID_82580_SERDES 0x1510
-#define E1000_DEV_ID_82580_SGMII 0x1511
-#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
-#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
-#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
-#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
-#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
-#define E1000_DEV_ID_DH89XXCC_SFP 0x0440
-#define E1000_DEV_ID_I350_COPPER 0x1521
-#define E1000_DEV_ID_I350_FIBER 0x1522
-#define E1000_DEV_ID_I350_SERDES 0x1523
-#define E1000_DEV_ID_I350_SGMII 0x1524
+#define E1000_DEV_ID_82576 0x10C9
+#define E1000_DEV_ID_82576_FIBER 0x10E6
+#define E1000_DEV_ID_82576_SERDES 0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
+#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526
+#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_NS_SERDES 0x1518
+#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
+#define E1000_DEV_ID_82575EB_COPPER 0x10A7
+#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
+#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
+#define E1000_DEV_ID_82580_COPPER 0x150E
+#define E1000_DEV_ID_82580_FIBER 0x150F
+#define E1000_DEV_ID_82580_SERDES 0x1510
+#define E1000_DEV_ID_82580_SGMII 0x1511
+#define E1000_DEV_ID_82580_COPPER_DUAL 0x1516
+#define E1000_DEV_ID_82580_QUAD_FIBER 0x1527
+#define E1000_DEV_ID_DH89XXCC_SGMII 0x0438
+#define E1000_DEV_ID_DH89XXCC_SERDES 0x043A
+#define E1000_DEV_ID_DH89XXCC_BACKPLANE 0x043C
+#define E1000_DEV_ID_DH89XXCC_SFP 0x0440
+#define E1000_DEV_ID_I350_COPPER 0x1521
+#define E1000_DEV_ID_I350_FIBER 0x1522
+#define E1000_DEV_ID_I350_SERDES 0x1523
+#define E1000_DEV_ID_I350_SGMII 0x1524
#define E1000_DEV_ID_I210_COPPER 0x1533
-#define E1000_DEV_ID_I210_COPPER_OEM1 0x1534
-#define E1000_DEV_ID_I210_COPPER_IT 0x1535
#define E1000_DEV_ID_I210_FIBER 0x1536
#define E1000_DEV_ID_I210_SERDES 0x1537
#define E1000_DEV_ID_I210_SGMII 0x1538
#define E1000_DEV_ID_I211_COPPER 0x1539
+#define E1000_DEV_ID_I354_BACKPLANE_1GBPS 0x1F40
+#define E1000_DEV_ID_I354_SGMII 0x1F41
+#define E1000_DEV_ID_I354_BACKPLANE_2_5GBPS 0x1F45
#define E1000_REVISION_2 2
#define E1000_REVISION_4 4
@@ -90,6 +91,7 @@ enum e1000_mac_type {
e1000_82576,
e1000_82580,
e1000_i350,
+ e1000_i354,
e1000_i210,
e1000_i211,
e1000_num_macs /* List is 1-based, so subtract 1 for true count. */
@@ -98,7 +100,8 @@ enum e1000_mac_type {
enum e1000_media_type {
e1000_media_type_unknown = 0,
e1000_media_type_copper = 1,
- e1000_media_type_internal_serdes = 2,
+ e1000_media_type_fiber = 2,
+ e1000_media_type_internal_serdes = 3,
e1000_num_media_types
};
@@ -524,6 +527,7 @@ struct e1000_dev_spec_82575 {
bool sgmii_active;
bool global_device_reset;
bool eee_disable;
+ bool clear_semaphore_once;
};
struct e1000_hw {
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index 6a42344f24f1..ddb3cf51b9b9 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -44,10 +44,42 @@
static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
{
u32 swsm;
- s32 ret_val = E1000_SUCCESS;
s32 timeout = hw->nvm.word_size + 1;
s32 i = 0;
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = rd32(E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ udelay(50);
+ i++;
+ }
+
+ if (i == timeout) {
+ /* In rare circumstances, the SW semaphore may already be held
+ * unintentionally. Clear the semaphore once before giving up.
+ */
+ if (hw->dev_spec._82575.clear_semaphore_once) {
+ hw->dev_spec._82575.clear_semaphore_once = false;
+ igb_put_hw_semaphore(hw);
+ for (i = 0; i < timeout; i++) {
+ swsm = rd32(E1000_SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ udelay(50);
+ }
+ }
+
+ /* If we do not have the semaphore here, we have to give up. */
+ if (i == timeout) {
+ hw_dbg("Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_NVM;
+ }
+ }
+
/* Get the FW semaphore. */
for (i = 0; i < timeout; i++) {
swsm = rd32(E1000_SWSM);
@@ -64,12 +96,10 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
/* Release semaphores */
igb_put_hw_semaphore(hw);
hw_dbg("Driver can't access the NVM\n");
- ret_val = -E1000_ERR_NVM;
- goto out;
+ return -E1000_ERR_NVM;
}
-out:
- return ret_val;
+ return E1000_SUCCESS;
}
/**
@@ -99,23 +129,6 @@ void igb_release_nvm_i210(struct e1000_hw *hw)
}
/**
- * igb_put_hw_semaphore_i210 - Release hardware semaphore
- * @hw: pointer to the HW structure
- *
- * Release hardware semaphore used to access the PHY or NVM
- */
-static void igb_put_hw_semaphore_i210(struct e1000_hw *hw)
-{
- u32 swsm;
-
- swsm = rd32(E1000_SWSM);
-
- swsm &= ~E1000_SWSM_SWESMBI;
-
- wr32(E1000_SWSM, swsm);
-}
-
-/**
* igb_acquire_swfw_sync_i210 - Acquire SW/FW semaphore
* @hw: pointer to the HW structure
* @mask: specifies which semaphore to acquire
@@ -138,13 +151,11 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
}
swfw_sync = rd32(E1000_SW_FW_SYNC);
- if (!(swfw_sync & fwmask))
+ if (!(swfw_sync & (fwmask | swmask)))
break;
- /*
- * Firmware currently using resource (fwmask)
- */
- igb_put_hw_semaphore_i210(hw);
+ /* Firmware currently using resource (fwmask) */
+ igb_put_hw_semaphore(hw);
mdelay(5);
i++;
}
@@ -158,7 +169,7 @@ s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
swfw_sync |= swmask;
wr32(E1000_SW_FW_SYNC, swfw_sync);
- igb_put_hw_semaphore_i210(hw);
+ igb_put_hw_semaphore(hw);
out:
return ret_val;
}
@@ -182,7 +193,7 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
swfw_sync &= ~mask;
wr32(E1000_SW_FW_SYNC, swfw_sync);
- igb_put_hw_semaphore_i210(hw);
+ igb_put_hw_semaphore(hw);
}
/**
@@ -203,7 +214,8 @@ s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
/* We cannot hold synchronization semaphores for too long,
* because of forceful takeover procedure. However it is more efficient
- * to read in bursts than synchronizing access for each word. */
+ * to read in bursts than synchronizing access for each word.
+ */
for (i = 0; i < words; i += E1000_EERD_EEWR_MAX_COUNT) {
count = (words - i) / E1000_EERD_EEWR_MAX_COUNT > 0 ?
E1000_EERD_EEWR_MAX_COUNT : (words - i);
@@ -242,8 +254,7 @@ static s32 igb_write_nvm_srwr(struct e1000_hw *hw, u16 offset, u16 words,
u32 attempts = 100000;
s32 ret_val = E1000_SUCCESS;
- /*
- * A check for invalid values: offset too large, too many words,
+ /* A check for invalid values: offset too large, too many words,
* too many words for the offset, and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
@@ -294,7 +305,7 @@ out:
*
* If error code is returned, data and Shadow RAM may be inconsistent - buffer
* partially written.
- */
+ **/
s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
u16 *data)
{
@@ -326,7 +337,7 @@ s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
/**
* igb_read_nvm_i211 - Read NVM wrapper function for I211
* @hw: pointer to the HW structure
- * @address: the word address (aka eeprom offset) to read
+ * @words: number of words to read
* @data: pointer to the data read
*
* Wrapper function to return data formerly found in the NVM.
@@ -549,8 +560,7 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
- /*
- * Replace the read function with semaphore grabbing with
+ /* Replace the read function with semaphore grabbing with
* the one that skips this for a while.
* We have semaphore taken already here.
*/
@@ -570,7 +580,6 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
return status;
}
-
/**
* igb_update_nvm_checksum_i210 - Update EEPROM checksum
* @hw: pointer to the HW structure
@@ -585,8 +594,7 @@ s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
u16 checksum = 0;
u16 i, nvm_data;
- /*
- * Read the first word from the EEPROM. If this times out or fails, do
+ /* Read the first word from the EEPROM. If this times out or fails, do
* not continue or we could be in for a very long wait while every
* EEPROM read fails
*/
@@ -597,8 +605,7 @@ s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
}
if (hw->nvm.ops.acquire(hw) == E1000_SUCCESS) {
- /*
- * Do not use hw->nvm.ops.write, hw->nvm.ops.read
+ /* Do not use hw->nvm.ops.write, hw->nvm.ops.read
* because we do not want to take the synchronization
* semaphores twice here.
*/
@@ -635,7 +642,7 @@ out:
* igb_pool_flash_update_done_i210 - Pool FLUDONE status.
* @hw: pointer to the HW structure
*
- */
+ **/
static s32 igb_pool_flash_update_done_i210(struct e1000_hw *hw)
{
s32 ret_val = -E1000_ERR_NVM;
@@ -714,3 +721,68 @@ s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data)
out:
return ret_val;
}
+
+/**
+ * __igb_access_xmdio_reg - Read/write XMDIO register
+ * @hw: pointer to the HW structure
+ * @address: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: pointer to value to read/write from/to the XMDIO address
+ * @read: boolean flag to indicate read or write
+ **/
+static s32 __igb_access_xmdio_reg(struct e1000_hw *hw, u16 address,
+ u8 dev_addr, u16 *data, bool read)
+{
+ s32 ret_val = E1000_SUCCESS;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, address);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, E1000_MMDAC_FUNC_DATA |
+ dev_addr);
+ if (ret_val)
+ return ret_val;
+
+ if (read)
+ ret_val = hw->phy.ops.read_reg(hw, E1000_MMDAAD, data);
+ else
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAAD, *data);
+ if (ret_val)
+ return ret_val;
+
+ /* Recalibrate the device back to 0 */
+ ret_val = hw->phy.ops.write_reg(hw, E1000_MMDAC, 0);
+ if (ret_val)
+ return ret_val;
+
+ return ret_val;
+}
+
+/**
+ * igb_read_xmdio_reg - Read XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be read from the EMI address
+ **/
+s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 *data)
+{
+ return __igb_access_xmdio_reg(hw, addr, dev_addr, data, true);
+}
+
+/**
+ * igb_write_xmdio_reg - Write XMDIO register
+ * @hw: pointer to the HW structure
+ * @addr: XMDIO address to program
+ * @dev_addr: device address to program
+ * @data: value to be written to the XMDIO address
+ **/
+s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data)
+{
+ return __igb_access_xmdio_reg(hw, addr, dev_addr, &data, false);
+}
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index e4e1a73b7c75..bfc08e05c907 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -45,6 +45,10 @@ extern s32 igb_read_nvm_i211(struct e1000_hw *hw, u16 offset, u16 words,
u16 *data);
extern s32 igb_read_invm_version(struct e1000_hw *hw,
struct e1000_fw_version *invm_ver);
+extern s32 igb_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
+ u16 *data);
+extern s32 igb_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
+ u16 data);
#define E1000_STM_OPCODE 0xDB00
#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index a5c7200b9a71..2559d70a2321 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -214,7 +214,7 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
else
vfta &= ~mask;
}
- if (hw->mac.type == e1000_i350)
+ if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
igb_write_vfta_i350(hw, index, vfta);
else
igb_write_vfta(hw, index, vfta);
@@ -230,8 +230,8 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
* Checks the nvm for an alternate MAC address. An alternate MAC address
* can be setup by pre-boot software and must be treated like a permanent
* address and must override the actual permanent MAC address. If an
- * alternate MAC address is fopund it is saved in the hw struct and
- * prgrammed into RAR0 and the cuntion returns success, otherwise the
+ * alternate MAC address is found it is saved in the hw struct and
+ * programmed into RAR0 and the function returns success, otherwise the
* function returns an error.
**/
s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
@@ -241,8 +241,7 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
u16 offset, nvm_alt_mac_addr_offset, nvm_data;
u8 alt_mac_addr[ETH_ALEN];
- /*
- * Alternate MAC address is handled by the option ROM for 82580
+ /* Alternate MAC address is handled by the option ROM for 82580
* and newer. SW support not required.
*/
if (hw->mac.type >= e1000_82580)
@@ -285,8 +284,7 @@ s32 igb_check_alt_mac_addr(struct e1000_hw *hw)
goto out;
}
- /*
- * We have a valid alternate MAC address, and we want to treat it the
+ /* We have a valid alternate MAC address, and we want to treat it the
* same as the normal permanent MAC address stored by the HW into the
* RAR. Do this by mapping this address into RAR0.
*/
@@ -309,8 +307,7 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
{
u32 rar_low, rar_high;
- /*
- * HW expects these in little endian so we reverse the byte order
+ /* HW expects these in little endian so we reverse the byte order
* from network order (big endian) to little endian
*/
rar_low = ((u32) addr[0] |
@@ -323,8 +320,7 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
if (rar_low || rar_high)
rar_high |= E1000_RAH_AV;
- /*
- * Some bridges will combine consecutive 32-bit writes into
+ /* Some bridges will combine consecutive 32-bit writes into
* a single burst write, which will malfunction on some parts.
* The flushes avoid this.
*/
@@ -348,8 +344,7 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
{
u32 hash_bit, hash_reg, mta;
- /*
- * The MTA is a register array of 32-bit registers. It is
+ /* The MTA is a register array of 32-bit registers. It is
* treated like an array of (32*mta_reg_count) bits. We want to
* set bit BitArray[hash_value]. So we figure out what register
* the bit is in, read it, OR in the new bit, then write
@@ -386,15 +381,13 @@ static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
/* Register count multiplied by bits per register */
hash_mask = (hw->mac.mta_reg_count * 32) - 1;
- /*
- * For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ /* For a mc_filter_type of 0, bit_shift is the number of left-shifts
* where 0xFF would still fall within the hash mask.
*/
while (hash_mask >> bit_shift != 0xFF)
bit_shift++;
- /*
- * The portion of the address that is used for the hash table
+ /* The portion of the address that is used for the hash table
* is determined by the mc_filter_type setting.
* The algorithm is such that there is a total of 8 bits of shifting.
* The bit_shift for a mc_filter_type of 0 represents the number of
@@ -536,8 +529,7 @@ s32 igb_check_for_copper_link(struct e1000_hw *hw)
s32 ret_val;
bool link;
- /*
- * We only want to go out to the PHY registers to see if Auto-Neg
+ /* We only want to go out to the PHY registers to see if Auto-Neg
* has completed and/or if our link status has changed. The
* get_link_status flag is set upon receiving a Link Status
* Change or Rx Sequence Error interrupt.
@@ -547,8 +539,7 @@ s32 igb_check_for_copper_link(struct e1000_hw *hw)
goto out;
}
- /*
- * First we want to see if the MII Status Register reports
+ /* First we want to see if the MII Status Register reports
* link. If so, then we want to get the current speed/duplex
* of the PHY.
*/
@@ -561,14 +552,12 @@ s32 igb_check_for_copper_link(struct e1000_hw *hw)
mac->get_link_status = false;
- /*
- * Check if there was DownShift, must be checked
+ /* Check if there was DownShift, must be checked
* immediately after link-up
*/
igb_check_downshift(hw);
- /*
- * If we are forcing speed/duplex, then we simply return since
+ /* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
*/
if (!mac->autoneg) {
@@ -576,15 +565,13 @@ s32 igb_check_for_copper_link(struct e1000_hw *hw)
goto out;
}
- /*
- * Auto-Neg is enabled. Auto Speed Detection takes care
+ /* Auto-Neg is enabled. Auto Speed Detection takes care
* of MAC speed/duplex configuration. So we only need to
* configure Collision Distance in the MAC.
*/
igb_config_collision_dist(hw);
- /*
- * Configure Flow Control now that Auto-Neg has completed.
+ /* Configure Flow Control now that Auto-Neg has completed.
* First, we need to restore the desired flow control
* settings because we may have had to re-autoneg with a
* different link partner.
@@ -611,15 +598,13 @@ s32 igb_setup_link(struct e1000_hw *hw)
{
s32 ret_val = 0;
- /*
- * In the case of the phy reset being blocked, we already have a link.
+ /* In the case of the phy reset being blocked, we already have a link.
* We do not need to set it up again.
*/
if (igb_check_reset_block(hw))
goto out;
- /*
- * If requested flow control is set to default, set flow control
+ /* If requested flow control is set to default, set flow control
* based on the EEPROM flow control settings.
*/
if (hw->fc.requested_mode == e1000_fc_default) {
@@ -628,8 +613,7 @@ s32 igb_setup_link(struct e1000_hw *hw)
goto out;
}
- /*
- * We want to save off the original Flow Control configuration just
+ /* We want to save off the original Flow Control configuration just
* in case we get disconnected and then reconnected into a different
* hub or switch with different Flow Control capabilities.
*/
@@ -642,8 +626,7 @@ s32 igb_setup_link(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Initialize the flow control address, type, and PAUSE timer
+ /* Initialize the flow control address, type, and PAUSE timer
* registers to their default values. This is done even if flow
* control is disabled, because it does not hurt anything to
* initialize these registers.
@@ -696,16 +679,14 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
s32 ret_val = 0;
u32 fcrtl = 0, fcrth = 0;
- /*
- * Set the flow control receive threshold registers. Normally,
+ /* Set the flow control receive threshold registers. Normally,
* these registers will be set to a default threshold that may be
* adjusted later by the driver's runtime code. However, if the
* ability to transmit pause frames is not enabled, then these
* registers will be set to 0.
*/
if (hw->fc.current_mode & e1000_fc_tx_pause) {
- /*
- * We need to set up the Receive Threshold high and low water
+ /* We need to set up the Receive Threshold high and low water
* marks as well as (optionally) enabling the transmission of
* XON frames.
*/
@@ -733,8 +714,7 @@ static s32 igb_set_default_fc(struct e1000_hw *hw)
s32 ret_val = 0;
u16 nvm_data;
- /*
- * Read and store word 0x0F of the EEPROM. This word contains bits
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
* that determine the hardware's default PAUSE (flow control) mode,
* a bit that determines whether the HW defaults to enabling or
* disabling auto-negotiation, and the direction of the
@@ -778,8 +758,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
ctrl = rd32(E1000_CTRL);
- /*
- * Because we didn't get link via the internal auto-negotiation
+ /* Because we didn't get link via the internal auto-negotiation
* mechanism (we either forced link or we got link via PHY
* auto-neg), we have to manually enable/disable transmit an
* receive flow control.
@@ -843,8 +822,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
u16 speed, duplex;
- /*
- * Check for the case where we have fiber media and auto-neg failed
+ /* Check for the case where we have fiber media and auto-neg failed
* so we had to force link. In this case, we need to force the
* configuration of the MAC to match the "fc" parameter.
*/
@@ -861,15 +839,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
goto out;
}
- /*
- * Check for the case where we have copper media and auto-neg is
+ /* Check for the case where we have copper media and auto-neg is
* enabled. In this case, we need to check and see if Auto-Neg
* has completed, and if so, how the PHY and link partner has
* flow control configured.
*/
if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) {
- /*
- * Read the MII Status Register and check to see if AutoNeg
+ /* Read the MII Status Register and check to see if AutoNeg
* has completed. We read this twice because this reg has
* some "sticky" (latched) bits.
*/
@@ -888,8 +864,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
goto out;
}
- /*
- * The AutoNeg process has completed, so we now need to
+ /* The AutoNeg process has completed, so we now need to
* read both the Auto Negotiation Advertisement
* Register (Address 4) and the Auto_Negotiation Base
* Page Ability Register (Address 5) to determine how
@@ -904,8 +879,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Two bits in the Auto Negotiation Advertisement Register
+ /* Two bits in the Auto Negotiation Advertisement Register
* (Address 4) and two bits in the Auto Negotiation Base
* Page Ability Register (Address 5) determine flow control
* for both the PHY and the link partner. The following
@@ -940,8 +914,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
*/
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
- /*
- * Now we need to check if the user selected RX ONLY
+ /* Now we need to check if the user selected RX ONLY
* of pause frames. In this case, we had to advertise
* FULL flow control because we could not advertise RX
* ONLY. Hence, we must now check to see if we need to
@@ -956,8 +929,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
"RX PAUSE frames only.\r\n");
}
}
- /*
- * For receiving PAUSE frames ONLY.
+ /* For receiving PAUSE frames ONLY.
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
@@ -971,8 +943,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
hw->fc.current_mode = e1000_fc_tx_pause;
hw_dbg("Flow Control = TX PAUSE frames only.\r\n");
}
- /*
- * For transmitting PAUSE frames ONLY.
+ /* For transmitting PAUSE frames ONLY.
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
@@ -986,8 +957,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
- /*
- * Per the IEEE spec, at this point flow control should be
+ /* Per the IEEE spec, at this point flow control should be
* disabled. However, we want to consider that we could
* be connected to a legacy switch that doesn't advertise
* desired flow control, but can be forced on the link
@@ -1007,9 +977,9 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if ((hw->fc.requested_mode == e1000_fc_none ||
- hw->fc.requested_mode == e1000_fc_tx_pause) ||
- hw->fc.strict_ieee) {
+ else if ((hw->fc.requested_mode == e1000_fc_none) ||
+ (hw->fc.requested_mode == e1000_fc_tx_pause) ||
+ (hw->fc.strict_ieee)) {
hw->fc.current_mode = e1000_fc_none;
hw_dbg("Flow Control = NONE.\r\n");
} else {
@@ -1017,8 +987,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
- /*
- * Now we need to do one last check... If we auto-
+ /* Now we need to do one last check... If we auto-
* negotiated to HALF DUPLEX, flow control should not be
* enabled per IEEE 802.3 spec.
*/
@@ -1031,8 +1000,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
if (duplex == HALF_DUPLEX)
hw->fc.current_mode = e1000_fc_none;
- /*
- * Now we call a subroutine to actually force the MAC
+ /* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
*/
ret_val = igb_force_mac_fc(hw);
@@ -1203,6 +1171,17 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
hw_dbg("Half Duplex\n");
}
+ /* Check if it is an I354 2.5Gb backplane connection. */
+ if (hw->mac.type == e1000_i354) {
+ if ((status & E1000_STATUS_2P5_SKU) &&
+ !(status & E1000_STATUS_2P5_SKU_OVER)) {
+ *speed = SPEED_2500;
+ *duplex = FULL_DUPLEX;
+ hw_dbg("2500 Mbs, ");
+ hw_dbg("Full Duplex\n");
+ }
+ }
+
return 0;
}
@@ -1427,8 +1406,7 @@ s32 igb_blink_led(struct e1000_hw *hw)
u32 ledctl_blink = 0;
u32 i;
- /*
- * set the blink bit for each LED that's "on" (0x0E)
+ /* set the blink bit for each LED that's "on" (0x0E)
* in ledctl_mode2
*/
ledctl_blink = hw->mac.ledctl_mode2;
@@ -1467,7 +1445,7 @@ s32 igb_led_off(struct e1000_hw *hw)
* @hw: pointer to the HW structure
*
* Returns 0 (0) if successful, else returns -10
- * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused
* the master requests to be disabled.
*
* Disables PCI-Express master access and verifies there are no pending
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h
index e6d6ce433261..5e13e83cc608 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.h
@@ -35,8 +35,7 @@
#include "e1000_defines.h"
#include "e1000_i210.h"
-/*
- * Functions that should not be called directly from drivers but can be used
+/* Functions that should not be called directly from drivers but can be used
* by other files in this 'shared code'
*/
s32 igb_blink_led(struct e1000_hw *hw);
@@ -49,15 +48,15 @@ s32 igb_get_auto_rd_done(struct e1000_hw *hw);
s32 igb_get_bus_info_pcie(struct e1000_hw *hw);
s32 igb_get_hw_semaphore(struct e1000_hw *hw);
s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
- u16 *duplex);
+ u16 *duplex);
s32 igb_id_led_init(struct e1000_hw *hw);
s32 igb_led_off(struct e1000_hw *hw);
void igb_update_mc_addr_list(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count);
+ u8 *mc_addr_list, u32 mc_addr_count);
s32 igb_setup_link(struct e1000_hw *hw);
s32 igb_validate_mdi_setting(struct e1000_hw *hw);
s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
- u32 offset, u8 data);
+ u32 offset, u8 data);
void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
void igb_clear_vfta(struct e1000_hw *hw);
@@ -80,12 +79,12 @@ enum e1000_mng_mode {
e1000_mng_mode_host_if_only
};
-#define E1000_FACTPS_MNGCG 0x20000000
+#define E1000_FACTPS_MNGCG 0x20000000
-#define E1000_FWSM_MODE_MASK 0xE
-#define E1000_FWSM_MODE_SHIFT 1
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
-#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
extern void e1000_init_function_pointers_82575(struct e1000_hw *hw);
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c
index 38e0df350904..dac1447fabf7 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c
@@ -196,7 +196,8 @@ out:
* returns SUCCESS if it successfully received a message notification and
* copied it into the receive buffer.
**/
-static s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+static s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
+ u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
s32 ret_val = -E1000_ERR_MBX;
@@ -222,7 +223,8 @@ out:
* returns SUCCESS if it successfully copied message into the buffer and
* received an ack to that message within delay * timeout period
**/
-static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+static s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size,
+ u16 mbx_id)
{
struct e1000_mbx_info *mbx = &hw->mbx;
s32 ret_val = -E1000_ERR_MBX;
@@ -325,7 +327,6 @@ static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
s32 ret_val = -E1000_ERR_MBX;
u32 p2v_mailbox;
-
/* Take ownership of the buffer */
wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
@@ -347,7 +348,7 @@ static s32 igb_obtain_mbx_lock_pf(struct e1000_hw *hw, u16 vf_number)
* returns SUCCESS if it successfully copied message into the buffer
**/
static s32 igb_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
- u16 vf_number)
+ u16 vf_number)
{
s32 ret_val;
u16 i;
@@ -388,7 +389,7 @@ out_no_write:
* a message due to a VF request so no polling for message is needed.
**/
static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
- u16 vf_number)
+ u16 vf_number)
{
s32 ret_val;
u16 i;
diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h
index c13b56d9edb2..de9bba41acf3 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mbx.h
+++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h
@@ -30,42 +30,42 @@
#include "e1000_hw.h"
-#define E1000_P2VMAILBOX_STS 0x00000001 /* Initiate message send to VF */
-#define E1000_P2VMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
-#define E1000_P2VMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
-#define E1000_P2VMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
-#define E1000_P2VMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
+#define E1000_P2VMAILBOX_STS 0x00000001 /* Initiate message send to VF */
+#define E1000_P2VMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
+#define E1000_P2VMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_PFU 0x00000008 /* PF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_RVFU 0x00000010 /* Reset VFU - used when VF stuck */
-#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
-#define E1000_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
-#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
-#define E1000_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
+#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
+#define E1000_MBVFICR_VFREQ_VF1 0x00000001 /* bit for VF 1 message */
+#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
+#define E1000_MBVFICR_VFACK_VF1 0x00010000 /* bit for VF 1 ack */
-#define E1000_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
+#define E1000_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
* PF. The reverse is true if it is E1000_PF_*.
* Message ACK's are the value or'd with 0xF0000000
*/
-#define E1000_VT_MSGTYPE_ACK 0x80000000 /* Messages below or'd with
- * this are the ACK */
-#define E1000_VT_MSGTYPE_NACK 0x40000000 /* Messages below or'd with
- * this are the NACK */
-#define E1000_VT_MSGTYPE_CTS 0x20000000 /* Indicates that VF is still
- clear to send requests */
-#define E1000_VT_MSGINFO_SHIFT 16
+/* Messages below or'd with this are the ACK */
+#define E1000_VT_MSGTYPE_ACK 0x80000000
+/* Messages below or'd with this are the NACK */
+#define E1000_VT_MSGTYPE_NACK 0x40000000
+/* Indicates that VF is still clear to send requests */
+#define E1000_VT_MSGTYPE_CTS 0x20000000
+#define E1000_VT_MSGINFO_SHIFT 16
/* bits 23:16 are used for exra info for certain messages */
-#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VT_MSGINFO_MASK (0xFF << E1000_VT_MSGINFO_SHIFT)
-#define E1000_VF_RESET 0x01 /* VF requests reset */
-#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
-#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
-#define E1000_VF_SET_VLAN 0x04 /* VF requests to set VLAN */
-#define E1000_VF_SET_LPE 0x05 /* VF requests to set VMOLR.LPE */
-#define E1000_VF_SET_PROMISC 0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
-#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
+#define E1000_VF_RESET 0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests to set MAC addr */
+#define E1000_VF_SET_MULTICAST 0x03 /* VF requests to set MC addr */
+#define E1000_VF_SET_VLAN 0x04 /* VF requests to set VLAN */
+#define E1000_VF_SET_LPE 0x05 /* VF requests to set VMOLR.LPE */
+#define E1000_VF_SET_PROMISC 0x06 /*VF requests to clear VMOLR.ROPE/MPME*/
+#define E1000_VF_SET_PROMISC_MULTICAST (0x02 << E1000_VT_MSGINFO_SHIFT)
-#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
+#define E1000_PF_CONTROL_MSG 0x0100 /* PF control message */
s32 igb_read_mbx(struct e1000_hw *, u32 *, u16, u16);
s32 igb_write_mbx(struct e1000_hw *, u32 *, u16, u16);
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index 5b62adbe134d..7f9cd7cbd353 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -289,15 +289,14 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw)
udelay(1);
timeout = NVM_MAX_RETRY_SPI;
- /*
- * Read "Status Register" repeatedly until the LSB is cleared.
+ /* Read "Status Register" repeatedly until the LSB is cleared.
* The EEPROM will signal that the command has been completed
* by clearing bit 0 of the internal status register. If it's
* not cleared within 'timeout', then error out.
*/
while (timeout) {
igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
- hw->nvm.opcode_bits);
+ hw->nvm.opcode_bits);
spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8);
if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
break;
@@ -335,8 +334,7 @@ s32 igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
u16 word_in;
u8 read_opcode = NVM_READ_OPCODE_SPI;
- /*
- * A check for invalid values: offset too large, too many words,
+ /* A check for invalid values: offset too large, too many words,
* and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
@@ -363,8 +361,7 @@ s32 igb_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
igb_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
igb_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
- /*
- * Read the data. SPI NVMs increment the address with each byte
+ /* Read the data. SPI NVMs increment the address with each byte
* read and will roll over if reading beyond the end. This allows
* us to read the whole NVM from any offset
*/
@@ -395,8 +392,7 @@ s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
u32 i, eerd = 0;
s32 ret_val = 0;
- /*
- * A check for invalid values: offset too large, too many words,
+ /* A check for invalid values: offset too large, too many words,
* and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
@@ -408,7 +404,7 @@ s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
for (i = 0; i < words; i++) {
eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
- E1000_NVM_RW_REG_START;
+ E1000_NVM_RW_REG_START;
wr32(E1000_EERD, eerd);
ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
@@ -441,8 +437,7 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
s32 ret_val = -E1000_ERR_NVM;
u16 widx = 0;
- /*
- * A check for invalid values: offset too large, too many words,
+ /* A check for invalid values: offset too large, too many words,
* and not enough words.
*/
if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
@@ -472,8 +467,7 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
igb_standby_nvm(hw);
- /*
- * Some SPI eeproms use the 8th address bit embedded in the
+ /* Some SPI eeproms use the 8th address bit embedded in the
* opcode
*/
if ((nvm->address_bits == 8) && (offset >= 128))
@@ -538,8 +532,7 @@ s32 igb_read_part_string(struct e1000_hw *hw, u8 *part_num, u32 part_num_size)
goto out;
}
- /*
- * if nvm_data is not ptr guard the PBA must be in legacy format which
+ /* if nvm_data is not ptr guard the PBA must be in legacy format which
* means pointer is actually our second data word for the PBA number
* and we can decode it into an ascii string
*/
@@ -728,6 +721,7 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
case e1000_82575:
case e1000_82576:
case e1000_82580:
+ case e1000_i354:
case e1000_i350:
case e1000_i210:
break;
@@ -746,6 +740,7 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
switch (hw->mac.type) {
case e1000_i210:
+ case e1000_i354:
case e1000_i350:
/* find combo image version */
hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset);
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index 2918c979b5bb..115b0da6e013 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -33,29 +33,29 @@
static s32 igb_phy_setup_autoneg(struct e1000_hw *hw);
static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
- u16 *phy_ctrl);
+ u16 *phy_ctrl);
static s32 igb_wait_autoneg(struct e1000_hw *hw);
static s32 igb_set_master_slave_mode(struct e1000_hw *hw);
/* Cable length tables */
-static const u16 e1000_m88_cable_length_table[] =
- { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+static const u16 e1000_m88_cable_length_table[] = {
+ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
#define M88E1000_CABLE_LENGTH_TABLE_SIZE \
- (sizeof(e1000_m88_cable_length_table) / \
- sizeof(e1000_m88_cable_length_table[0]))
-
-static const u16 e1000_igp_2_cable_length_table[] =
- { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
- 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
- 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
- 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
- 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
- 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
- 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
- 104, 109, 114, 118, 121, 124};
+ (sizeof(e1000_m88_cable_length_table) / \
+ sizeof(e1000_m88_cable_length_table[0]))
+
+static const u16 e1000_igp_2_cable_length_table[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
- (sizeof(e1000_igp_2_cable_length_table) / \
- sizeof(e1000_igp_2_cable_length_table[0]))
+ (sizeof(e1000_igp_2_cable_length_table) / \
+ sizeof(e1000_igp_2_cable_length_table[0]))
/**
* igb_check_reset_block - Check if PHY reset is blocked
@@ -71,8 +71,7 @@ s32 igb_check_reset_block(struct e1000_hw *hw)
manc = rd32(E1000_MANC);
- return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
- E1000_BLK_PHY_RESET : 0;
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : 0;
}
/**
@@ -149,8 +148,7 @@ s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
goto out;
}
- /*
- * Set up Op-code, Phy Address, and register offset in the MDI
+ /* Set up Op-code, Phy Address, and register offset in the MDI
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
@@ -160,8 +158,7 @@ s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
wr32(E1000_MDIC, mdic);
- /*
- * Poll the ready bit to see if the MDI read completed
+ /* Poll the ready bit to see if the MDI read completed
* Increasing the time out as testing showed failures with
* the lower time out
*/
@@ -207,8 +204,7 @@ s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
goto out;
}
- /*
- * Set up Op-code, Phy Address, and register offset in the MDI
+ /* Set up Op-code, Phy Address, and register offset in the MDI
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
@@ -219,8 +215,7 @@ s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
wr32(E1000_MDIC, mdic);
- /*
- * Poll the ready bit to see if the MDI read completed
+ /* Poll the ready bit to see if the MDI read completed
* Increasing the time out as testing showed failures with
* the lower time out
*/
@@ -259,15 +254,13 @@ s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
struct e1000_phy_info *phy = &hw->phy;
u32 i, i2ccmd = 0;
-
- /*
- * Set up Op-code, Phy Address, and register address in the I2CCMD
+ /* Set up Op-code, Phy Address, and register address in the I2CCMD
* register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
- (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
- (E1000_I2CCMD_OPCODE_READ));
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ (E1000_I2CCMD_OPCODE_READ));
wr32(E1000_I2CCMD, i2ccmd);
@@ -317,15 +310,14 @@ s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
/* Swap the data bytes for the I2C interface */
phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
- /*
- * Set up Op-code, Phy Address, and register address in the I2CCMD
+ /* Set up Op-code, Phy Address, and register address in the I2CCMD
* register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
- (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
- E1000_I2CCMD_OPCODE_WRITE |
- phy_data_swapped);
+ (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_WRITE |
+ phy_data_swapped);
wr32(E1000_I2CCMD, i2ccmd);
@@ -371,8 +363,8 @@ s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
if (offset > MAX_PHY_MULTI_PAGE_REG) {
ret_val = igb_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (u16)offset);
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
if (ret_val) {
hw->phy.ops.release(hw);
goto out;
@@ -410,8 +402,8 @@ s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
if (offset > MAX_PHY_MULTI_PAGE_REG) {
ret_val = igb_write_phy_reg_mdic(hw,
- IGP01E1000_PHY_PAGE_SELECT,
- (u16)offset);
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
if (ret_val) {
hw->phy.ops.release(hw);
goto out;
@@ -419,7 +411,7 @@ s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
}
ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
+ data);
hw->phy.ops.release(hw);
@@ -439,7 +431,6 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw)
s32 ret_val;
u16 phy_data;
-
if (phy->reset_disable) {
ret_val = 0;
goto out;
@@ -472,8 +463,7 @@ s32 igb_copper_link_setup_82580(struct e1000_hw *hw)
if (ret_val)
goto out;
phy_data &= ~I82580_PHY_CTRL2_MDIX_CFG_MASK;
- /*
- * Options:
+ /* Options:
* 0 - Auto (default)
* 1 - MDI mode
* 2 - MDI-X mode
@@ -520,8 +510,7 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
- /*
- * Options:
+ /* Options:
* MDI/MDI-X = 0 (default)
* 0 - Auto for all speeds
* 1 - MDI mode
@@ -546,8 +535,7 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
break;
}
- /*
- * Options:
+ /* Options:
* disable_polarity_correction = 0 (default)
* Automatic Correction for Reversed Cable Polarity
* 0 - Disabled
@@ -562,12 +550,11 @@ s32 igb_copper_link_setup_m88(struct e1000_hw *hw)
goto out;
if (phy->revision < E1000_REVISION_4) {
- /*
- * Force TX_CLK in the Extended PHY Specific Control Register
+ /* Force TX_CLK in the Extended PHY Specific Control Register
* to 25MHz clock.
*/
ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL,
- &phy_data);
+ &phy_data);
if (ret_val)
goto out;
@@ -630,8 +617,7 @@ s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Options:
+ /* Options:
* MDI/MDI-X = 0 (default)
* 0 - Auto for all speeds
* 1 - MDI mode
@@ -659,8 +645,7 @@ s32 igb_copper_link_setup_m88_gen2(struct e1000_hw *hw)
break;
}
- /*
- * Options:
+ /* Options:
* disable_polarity_correction = 0 (default)
* Automatic Correction for Reversed Cable Polarity
* 0 - Disabled
@@ -714,14 +699,12 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
goto out;
}
- /*
- * Wait 100ms for MAC to configure PHY from NVM settings, to avoid
+ /* Wait 100ms for MAC to configure PHY from NVM settings, to avoid
* timeout issues when LFS is enabled.
*/
msleep(100);
- /*
- * The NVM settings will configure LPLU in D3 for
+ /* The NVM settings will configure LPLU in D3 for
* non-IGP1 PHYs.
*/
if (phy->type == e1000_phy_igp) {
@@ -765,8 +748,7 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw)
/* set auto-master slave resolution settings */
if (hw->mac.autoneg) {
- /*
- * when autonegotiation advertisement is only 1000Mbps then we
+ /* when autonegotiation advertisement is only 1000Mbps then we
* should disable SmartSpeed and enable Auto MasterSlave
* resolution as hardware default.
*/
@@ -844,14 +826,12 @@ static s32 igb_copper_link_autoneg(struct e1000_hw *hw)
s32 ret_val;
u16 phy_ctrl;
- /*
- * Perform some bounds checking on the autoneg advertisement
+ /* Perform some bounds checking on the autoneg advertisement
* parameter.
*/
phy->autoneg_advertised &= phy->autoneg_mask;
- /*
- * If autoneg_advertised is zero, we assume it was not defaulted
+ /* If autoneg_advertised is zero, we assume it was not defaulted
* by the calling code so we set to advertise full capability.
*/
if (phy->autoneg_advertised == 0)
@@ -865,8 +845,7 @@ static s32 igb_copper_link_autoneg(struct e1000_hw *hw)
}
hw_dbg("Restarting Auto-Neg\n");
- /*
- * Restart auto-negotiation by setting the Auto Neg Enable bit and
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
* the Auto Neg Restart bit in the PHY control register.
*/
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl);
@@ -878,8 +857,7 @@ static s32 igb_copper_link_autoneg(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Does the user want to wait for Auto-Neg to complete here, or
+ /* Does the user want to wait for Auto-Neg to complete here, or
* check at a later time (for example, callback routine).
*/
if (phy->autoneg_wait_to_complete) {
@@ -928,16 +906,14 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
goto out;
}
- /*
- * Need to parse both autoneg_advertised and fc and set up
+ /* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
* autoneg_advertised software override. Since we can advertise
* a plethora of combinations, we need to check each bit
* individually.
*/
- /*
- * First we clear all the 10/100 mb speed bits in the Auto-Neg
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
* Advertisement Register (Address 4) and the 1000 mb speed bits in
* the 1000Base-T Control Register (Address 9).
*/
@@ -983,8 +959,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
}
- /*
- * Check for a software override of the flow control settings, and
+ /* Check for a software override of the flow control settings, and
* setup the PHY advertisement registers accordingly. If
* auto-negotiation is enabled, then software will have to set the
* "PAUSE" bits to the correct value in the Auto-Negotiation
@@ -1003,15 +978,13 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
*/
switch (hw->fc.current_mode) {
case e1000_fc_none:
- /*
- * Flow control (RX & TX) is completely disabled by a
+ /* Flow control (RX & TX) is completely disabled by a
* software over-ride.
*/
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
case e1000_fc_rx_pause:
- /*
- * RX Flow control is enabled, and TX Flow control is
+ /* RX Flow control is enabled, and TX Flow control is
* disabled, by a software over-ride.
*
* Since there really isn't a way to advertise that we are
@@ -1023,16 +996,14 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
case e1000_fc_tx_pause:
- /*
- * TX Flow control is enabled, and RX Flow control is
+ /* TX Flow control is enabled, and RX Flow control is
* disabled, by a software over-ride.
*/
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
break;
case e1000_fc_full:
- /*
- * Flow control (both RX and TX) is enabled by a software
+ /* Flow control (both RX and TX) is enabled by a software
* over-ride.
*/
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
@@ -1075,18 +1046,15 @@ s32 igb_setup_copper_link(struct e1000_hw *hw)
s32 ret_val;
bool link;
-
if (hw->mac.autoneg) {
- /*
- * Setup autoneg and flow control advertisement and perform
+ /* Setup autoneg and flow control advertisement and perform
* autonegotiation.
*/
ret_val = igb_copper_link_autoneg(hw);
if (ret_val)
goto out;
} else {
- /*
- * PHY will be set to 10H, 10F, 100H or 100F
+ /* PHY will be set to 10H, 10F, 100H or 100F
* depending on user settings.
*/
hw_dbg("Forcing Speed and Duplex\n");
@@ -1097,14 +1065,10 @@ s32 igb_setup_copper_link(struct e1000_hw *hw)
}
}
- /*
- * Check link status. Wait up to 100 microseconds for link to become
+ /* Check link status. Wait up to 100 microseconds for link to become
* valid.
*/
- ret_val = igb_phy_has_link(hw,
- COPPER_LINK_UP_LIMIT,
- 10,
- &link);
+ ret_val = igb_phy_has_link(hw, COPPER_LINK_UP_LIMIT, 10, &link);
if (ret_val)
goto out;
@@ -1145,8 +1109,7 @@ s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
* forced whenever speed and duplex are forced.
*/
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
@@ -1167,10 +1130,7 @@ s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
if (phy->autoneg_wait_to_complete) {
hw_dbg("Waiting for forced speed/duplex link on IGP phy.\n");
- ret_val = igb_phy_has_link(hw,
- PHY_FORCE_LIMIT,
- 100000,
- &link);
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 10000, &link);
if (ret_val)
goto out;
@@ -1178,10 +1138,7 @@ s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw)
hw_dbg("Link taking longer than expected.\n");
/* Try once more */
- ret_val = igb_phy_has_link(hw,
- PHY_FORCE_LIMIT,
- 100000,
- &link);
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 10000, &link);
if (ret_val)
goto out;
}
@@ -1209,8 +1166,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
/* I210 and I211 devices support Auto-Crossover in forced operation. */
if (phy->type != e1000_phy_i210) {
- /*
- * Clear Auto-Crossover to force MDI manually. M88E1000
+ /* Clear Auto-Crossover to force MDI manually. M88E1000
* requires MDI forced whenever speed and duplex are forced.
*/
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL,
@@ -1266,13 +1222,12 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
if (!reset_dsp)
hw_dbg("Link taking longer than expected.\n");
else {
- /*
- * We didn't get link.
+ /* We didn't get link.
* Reset the DSP and cross our fingers.
*/
ret_val = phy->ops.write_reg(hw,
- M88E1000_PHY_PAGE_SELECT,
- 0x001d);
+ M88E1000_PHY_PAGE_SELECT,
+ 0x001d);
if (ret_val)
goto out;
ret_val = igb_phy_reset_dsp(hw);
@@ -1298,8 +1253,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Resetting the phy means we need to re-force TX_CLK in the
+ /* Resetting the phy means we need to re-force TX_CLK in the
* Extended PHY Specific Control Register to 25MHz clock from
* the reset value of 2.5MHz.
*/
@@ -1308,8 +1262,7 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * In addition, we must re-enable CRS on Tx for both half and full
+ /* In addition, we must re-enable CRS on Tx for both half and full
* duplex.
*/
ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -1336,7 +1289,7 @@ out:
* take affect.
**/
static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
- u16 *phy_ctrl)
+ u16 *phy_ctrl)
{
struct e1000_mac_info *mac = &hw->mac;
u32 ctrl;
@@ -1417,8 +1370,7 @@ s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
data);
if (ret_val)
goto out;
- /*
- * LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
* during Dx states where the power conservation is most
* important. During driver activity we should enable
* SmartSpeed, so performance is maintained.
@@ -1461,13 +1413,13 @@ s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active)
/* When LPLU is enabled, we should disable SmartSpeed */
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
- &data);
+ &data);
if (ret_val)
goto out;
data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
- data);
+ data);
}
out:
@@ -1556,8 +1508,7 @@ static s32 igb_check_polarity_igp(struct e1000_hw *hw)
s32 ret_val;
u16 data, offset, mask;
- /*
- * Polarity is determined based on the speed of
+ /* Polarity is determined based on the speed of
* our connection.
*/
ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data);
@@ -1569,8 +1520,7 @@ static s32 igb_check_polarity_igp(struct e1000_hw *hw)
offset = IGP01E1000_PHY_PCS_INIT_REG;
mask = IGP01E1000_PHY_POLARITY_MASK;
} else {
- /*
- * This really only applies to 10Mbps since
+ /* This really only applies to 10Mbps since
* there is no polarity for 100Mbps (always 0).
*/
offset = IGP01E1000_PHY_PORT_STATUS;
@@ -1589,7 +1539,7 @@ out:
}
/**
- * igb_wait_autoneg - Wait for auto-neg compeletion
+ * igb_wait_autoneg - Wait for auto-neg completion
* @hw: pointer to the HW structure
*
* Waits for auto-negotiation to complete or for the auto-negotiation time
@@ -1613,8 +1563,7 @@ static s32 igb_wait_autoneg(struct e1000_hw *hw)
msleep(100);
}
- /*
- * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
* has completed.
*/
return ret_val;
@@ -1630,21 +1579,19 @@ static s32 igb_wait_autoneg(struct e1000_hw *hw)
* Polls the PHY status register for link, 'iterations' number of times.
**/
s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
- u32 usec_interval, bool *success)
+ u32 usec_interval, bool *success)
{
s32 ret_val = 0;
u16 i, phy_status;
for (i = 0; i < iterations; i++) {
- /*
- * Some PHYs require the PHY_STATUS register to be read
+ /* Some PHYs require the PHY_STATUS register to be read
* twice due to the link bit being sticky. No harm doing
* it across the board.
*/
ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status);
- if (ret_val) {
- /*
- * If the first read fails, another entity may have
+ if (ret_val && usec_interval > 0) {
+ /* If the first read fails, another entity may have
* ownership of the resources, wait and try again to
* see if they have relinquished the resources yet.
*/
@@ -1735,6 +1682,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
phy->max_cable_length = phy_data / (is_cm ? 100 : 1);
phy->cable_length = phy_data / (is_cm ? 100 : 1);
break;
+ case M88E1545_E_PHY_ID:
case I347AT4_E_PHY_ID:
/* Remember the original page select and set it to 7 */
ret_val = phy->ops.read_reg(hw, I347AT4_PAGE_SELECT,
@@ -1834,10 +1782,10 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
u16 cur_agc_index, max_agc_index = 0;
u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = {
- IGP02E1000_PHY_AGC_A,
- IGP02E1000_PHY_AGC_B,
- IGP02E1000_PHY_AGC_C,
- IGP02E1000_PHY_AGC_D
+ IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D
};
/* Read the AGC registers for all channels */
@@ -1846,8 +1794,7 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Getting bits 15:9, which represent the combination of
+ /* Getting bits 15:9, which represent the combination of
* coarse and fine gain values. The result is a number
* that can be put into the lookup table to obtain the
* approximate cable length.
@@ -2167,15 +2114,13 @@ s32 igb_phy_init_script_igp3(struct e1000_hw *hw)
hw->phy.ops.write_reg(hw, 0x1796, 0x0008);
/* Change cg_icount + enable integbp for channels BCD */
hw->phy.ops.write_reg(hw, 0x1798, 0xD008);
- /*
- * Change cg_icount + enable integbp + change prop_factor_master
+ /* Change cg_icount + enable integbp + change prop_factor_master
* to 8 for channel A
*/
hw->phy.ops.write_reg(hw, 0x1898, 0xD918);
/* Disable AHT in Slave mode on channel A */
hw->phy.ops.write_reg(hw, 0x187A, 0x0800);
- /*
- * Enable LPLU and disable AN to 1000 in non-D0a states,
+ /* Enable LPLU and disable AN to 1000 in non-D0a states,
* Enable SPD+B2B
*/
hw->phy.ops.write_reg(hw, 0x0019, 0x008D);
@@ -2257,8 +2202,8 @@ static s32 igb_check_polarity_82580(struct e1000_hw *hw)
if (!ret_val)
phy->cable_polarity = (data & I82580_PHY_STATUS2_REV_POLARITY)
- ? e1000_rev_polarity_reversed
- : e1000_rev_polarity_normal;
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
return ret_val;
}
@@ -2278,7 +2223,6 @@ s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)
u16 phy_data;
bool link;
-
ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data);
if (ret_val)
goto out;
@@ -2289,8 +2233,7 @@ s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)
if (ret_val)
goto out;
- /*
- * Clear Auto-Crossover to force MDI manually. 82580 requires MDI
+ /* Clear Auto-Crossover to force MDI manually. 82580 requires MDI
* forced whenever speed and duplex are forced.
*/
ret_val = phy->ops.read_reg(hw, I82580_PHY_CTRL_2, &phy_data);
@@ -2310,10 +2253,7 @@ s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)
if (phy->autoneg_wait_to_complete) {
hw_dbg("Waiting for forced speed/duplex link on 82580 phy\n");
- ret_val = igb_phy_has_link(hw,
- PHY_FORCE_LIMIT,
- 100000,
- &link);
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
if (ret_val)
goto out;
@@ -2321,10 +2261,7 @@ s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw)
hw_dbg("Link taking longer than expected.\n");
/* Try once more */
- ret_val = igb_phy_has_link(hw,
- PHY_FORCE_LIMIT,
- 100000,
- &link);
+ ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, 100000, &link);
if (ret_val)
goto out;
}
@@ -2349,7 +2286,6 @@ s32 igb_get_phy_info_82580(struct e1000_hw *hw)
u16 data;
bool link;
-
ret_val = igb_phy_has_link(hw, 1, 0, &link);
if (ret_val)
goto out;
@@ -2383,12 +2319,12 @@ s32 igb_get_phy_info_82580(struct e1000_hw *hw)
goto out;
phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
- ? e1000_1000t_rx_status_ok
- : e1000_1000t_rx_status_not_ok;
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
} else {
phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
phy->local_rx = e1000_1000t_rx_status_undefined;
@@ -2412,13 +2348,12 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw)
s32 ret_val;
u16 phy_data, length;
-
ret_val = phy->ops.read_reg(hw, I82580_PHY_DIAG_STATUS, &phy_data);
if (ret_val)
goto out;
length = (phy_data & I82580_DSTATUS_CABLE_LENGTH) >>
- I82580_DSTATUS_CABLE_LENGTH_SHIFT;
+ I82580_DSTATUS_CABLE_LENGTH_SHIFT;
if (length == E1000_CABLE_LENGTH_UNDEFINED)
ret_val = -E1000_ERR_PHY;
diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h
index 15343286082e..82632c6c53af 100644
--- a/drivers/net/ethernet/intel/igb/e1000_regs.h
+++ b/drivers/net/ethernet/intel/igb/e1000_regs.h
@@ -65,6 +65,7 @@
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
+#define E1000_LEDMUX 0x08130 /* LED MUX Control */
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_PBS 0x01008 /* Packet Buffer Size */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
@@ -83,6 +84,9 @@
#define E1000_I2C_DATA_IN 0x00001000 /* I2C- Data In */
#define E1000_I2C_CLK_OE_N 0x00002000 /* I2C- Clock Output Enable */
#define E1000_I2C_CLK_IN 0x00004000 /* I2C- Clock In */
+#define E1000_MPHY_ADDR_CTRL 0x0024 /* GbE MPHY Address Control */
+#define E1000_MPHY_DATA 0x0E10 /* GBE MPHY Data */
+#define E1000_MPHY_STAT 0x0E0C /* GBE MPHY Statistics */
/* IEEE 1588 TIMESYNCH */
#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
@@ -117,21 +121,21 @@
#define E1000_RQDPC(_n) (0x0C030 + ((_n) * 0x40))
/* DMA Coalescing registers */
-#define E1000_DMACR 0x02508 /* Control Register */
-#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */
-#define E1000_DMCTLX 0x02514 /* Time to Lx Request */
-#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
-#define E1000_DMCCNT 0x05DD4 /* Current Rx Count */
-#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */
-#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
+#define E1000_DMACR 0x02508 /* Control Register */
+#define E1000_DMCTXTH 0x03550 /* Transmit Threshold */
+#define E1000_DMCTLX 0x02514 /* Time to Lx Request */
+#define E1000_DMCRTRH 0x05DD0 /* Receive Packet Rate Threshold */
+#define E1000_DMCCNT 0x05DD4 /* Current Rx Count */
+#define E1000_FCRTC 0x02170 /* Flow Control Rx high watermark */
+#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
/* TX Rate Limit Registers */
-#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select - WO */
-#define E1000_RTTBCNRM 0x3690 /* Tx BCN Rate-scheduler MMW */
-#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config - WO */
+#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select - WO */
+#define E1000_RTTBCNRM 0x3690 /* Tx BCN Rate-scheduler MMW */
+#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config - WO */
/* Split and Replication RX Control - RW */
-#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
+#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */
/* Thermal sensor configuration and status registers */
#define E1000_THMJT 0x08100 /* Junction Temperature */
@@ -140,8 +144,7 @@
#define E1000_THHIGHTC 0x0810C /* High Threshold Control */
#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
-/*
- * Convenience macros
+/* Convenience macros
*
* Note: "_n" is the queue number of the register to be written to.
*
@@ -287,7 +290,7 @@
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
#define E1000_RA 0x05400 /* Receive Address - RW Array */
-#define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */
+#define E1000_RA2 0x054E0 /* 2nd half of Rx address array - RW Array */
#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4))
#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
(0x054E0 + ((_i - 16) * 8)))
@@ -360,21 +363,25 @@
(readl(hw->hw_addr + reg + ((offset) << 2)))
/* DMA Coalescing registers */
-#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
+#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
/* Energy Efficient Ethernet "EEE" register */
-#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */
-#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet */
-#define E1000_EEE_SU 0X0E34 /* EEE Setup */
+#define E1000_IPCNFG 0x0E38 /* Internal PHY Configuration */
+#define E1000_EEER 0x0E30 /* Energy Efficient Ethernet */
+#define E1000_EEE_SU 0X0E34 /* EEE Setup */
+#define E1000_EMIADD 0x10 /* Extended Memory Indirect Address */
+#define E1000_EMIDATA 0x11 /* Extended Memory Indirect Data */
+#define E1000_MMDAC 13 /* MMD Access Control */
+#define E1000_MMDAAD 14 /* MMD Access Address/Data */
/* Thermal Sensor Register */
-#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
+#define E1000_THSTAT 0x08110 /* Thermal Sensor Status */
/* OS2BMC Registers */
-#define E1000_B2OSPC 0x08FE0 /* BMC2OS packets sent by BMC */
-#define E1000_B2OGPRC 0x04158 /* BMC2OS packets received by host */
-#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
-#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
+#define E1000_B2OSPC 0x08FE0 /* BMC2OS packets sent by BMC */
+#define E1000_B2OGPRC 0x04158 /* BMC2OS packets received by host */
+#define E1000_O2BGPTC 0x08FE4 /* OS2BMC packets received by BMC */
+#define E1000_O2BSPC 0x0415C /* OS2BMC packets transmitted by host */
#define E1000_SRWR 0x12018 /* Shadow Ram Write Register - RW */
#define E1000_I210_FLMNGCTL 0x12038
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 25151401c2ab..9d6c075e232d 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -44,54 +44,54 @@
struct igb_adapter;
-#define E1000_PCS_CFG_IGN_SD 1
+#define E1000_PCS_CFG_IGN_SD 1
/* Interrupt defines */
-#define IGB_START_ITR 648 /* ~6000 ints/sec */
-#define IGB_4K_ITR 980
-#define IGB_20K_ITR 196
-#define IGB_70K_ITR 56
+#define IGB_START_ITR 648 /* ~6000 ints/sec */
+#define IGB_4K_ITR 980
+#define IGB_20K_ITR 196
+#define IGB_70K_ITR 56
/* TX/RX descriptor defines */
-#define IGB_DEFAULT_TXD 256
-#define IGB_DEFAULT_TX_WORK 128
-#define IGB_MIN_TXD 80
-#define IGB_MAX_TXD 4096
+#define IGB_DEFAULT_TXD 256
+#define IGB_DEFAULT_TX_WORK 128
+#define IGB_MIN_TXD 80
+#define IGB_MAX_TXD 4096
-#define IGB_DEFAULT_RXD 256
-#define IGB_MIN_RXD 80
-#define IGB_MAX_RXD 4096
+#define IGB_DEFAULT_RXD 256
+#define IGB_MIN_RXD 80
+#define IGB_MAX_RXD 4096
-#define IGB_DEFAULT_ITR 3 /* dynamic */
-#define IGB_MAX_ITR_USECS 10000
-#define IGB_MIN_ITR_USECS 10
-#define NON_Q_VECTORS 1
-#define MAX_Q_VECTORS 8
+#define IGB_DEFAULT_ITR 3 /* dynamic */
+#define IGB_MAX_ITR_USECS 10000
+#define IGB_MIN_ITR_USECS 10
+#define NON_Q_VECTORS 1
+#define MAX_Q_VECTORS 8
/* Transmit and receive queues */
-#define IGB_MAX_RX_QUEUES 8
-#define IGB_MAX_RX_QUEUES_82575 4
-#define IGB_MAX_RX_QUEUES_I211 2
-#define IGB_MAX_TX_QUEUES 8
-#define IGB_MAX_VF_MC_ENTRIES 30
-#define IGB_MAX_VF_FUNCTIONS 8
-#define IGB_MAX_VFTA_ENTRIES 128
-#define IGB_82576_VF_DEV_ID 0x10CA
-#define IGB_I350_VF_DEV_ID 0x1520
+#define IGB_MAX_RX_QUEUES 8
+#define IGB_MAX_RX_QUEUES_82575 4
+#define IGB_MAX_RX_QUEUES_I211 2
+#define IGB_MAX_TX_QUEUES 8
+#define IGB_MAX_VF_MC_ENTRIES 30
+#define IGB_MAX_VF_FUNCTIONS 8
+#define IGB_MAX_VFTA_ENTRIES 128
+#define IGB_82576_VF_DEV_ID 0x10CA
+#define IGB_I350_VF_DEV_ID 0x1520
/* NVM version defines */
-#define IGB_MAJOR_MASK 0xF000
-#define IGB_MINOR_MASK 0x0FF0
-#define IGB_BUILD_MASK 0x000F
-#define IGB_COMB_VER_MASK 0x00FF
-#define IGB_MAJOR_SHIFT 12
-#define IGB_MINOR_SHIFT 4
-#define IGB_COMB_VER_SHFT 8
-#define IGB_NVM_VER_INVALID 0xFFFF
-#define IGB_ETRACK_SHIFT 16
-#define NVM_ETRACK_WORD 0x0042
-#define NVM_COMB_VER_OFF 0x0083
-#define NVM_COMB_VER_PTR 0x003d
+#define IGB_MAJOR_MASK 0xF000
+#define IGB_MINOR_MASK 0x0FF0
+#define IGB_BUILD_MASK 0x000F
+#define IGB_COMB_VER_MASK 0x00FF
+#define IGB_MAJOR_SHIFT 12
+#define IGB_MINOR_SHIFT 4
+#define IGB_COMB_VER_SHFT 8
+#define IGB_NVM_VER_INVALID 0xFFFF
+#define IGB_ETRACK_SHIFT 16
+#define NVM_ETRACK_WORD 0x0042
+#define NVM_COMB_VER_OFF 0x0083
+#define NVM_COMB_VER_PTR 0x003d
struct vf_data_storage {
unsigned char vf_mac_addresses[ETH_ALEN];
@@ -103,6 +103,7 @@ struct vf_data_storage {
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
u16 tx_rate;
+ bool spoofchk_enabled;
};
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
@@ -121,14 +122,14 @@ struct vf_data_storage {
* descriptors until either it has this many to write back, or the
* ITR timer expires.
*/
-#define IGB_RX_PTHRESH 8
-#define IGB_RX_HTHRESH 8
-#define IGB_TX_PTHRESH 8
-#define IGB_TX_HTHRESH 1
-#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
- adapter->msix_entries) ? 1 : 4)
-#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
- adapter->msix_entries) ? 1 : 16)
+#define IGB_RX_PTHRESH ((hw->mac.type == e1000_i354) ? 12 : 8)
+#define IGB_RX_HTHRESH 8
+#define IGB_TX_PTHRESH ((hw->mac.type == e1000_i354) ? 20 : 8)
+#define IGB_TX_HTHRESH 1
+#define IGB_RX_WTHRESH ((hw->mac.type == e1000_82576 && \
+ adapter->msix_entries) ? 1 : 4)
+#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \
+ adapter->msix_entries) ? 1 : 16)
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
@@ -140,17 +141,17 @@ struct vf_data_storage {
#define IGB_RX_BUFSZ IGB_RXBUFFER_2048
/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */
-#define AUTO_ALL_MODES 0
-#define IGB_EEPROM_APME 0x0400
+#define AUTO_ALL_MODES 0
+#define IGB_EEPROM_APME 0x0400
#ifndef IGB_MASTER_SLAVE
/* Switch to override PHY master/slave setting */
#define IGB_MASTER_SLAVE e1000_ms_hw_default
#endif
-#define IGB_MNG_VLAN_NONE -1
+#define IGB_MNG_VLAN_NONE -1
enum igb_tx_flags {
/* cmd_type flags */
@@ -164,11 +165,10 @@ enum igb_tx_flags {
};
/* VLAN info */
-#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000
#define IGB_TX_FLAGS_VLAN_SHIFT 16
-/*
- * The largest size we can write to the descriptor is 65535. In order to
+/* The largest size we can write to the descriptor is 65535. In order to
* maintain a power of two alignment we have to limit ourselves to 32K.
*/
#define IGB_MAX_TXD_PWR 15
@@ -178,8 +178,17 @@ enum igb_tx_flags {
#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IGB_MAX_DATA_PER_TXD)
#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+/* EEPROM byte offsets */
+#define IGB_SFF_8472_SWAP 0x5C
+#define IGB_SFF_8472_COMP 0x5E
+
+/* Bitmasks */
+#define IGB_SFF_ADDRESSING_MODE 0x4
+#define IGB_SFF_8472_UNSUP 0x00
+
/* wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer */
+ * so a DMA handle can be stored along with the buffer
+ */
struct igb_tx_buffer {
union e1000_adv_tx_desc *next_to_watch;
unsigned long time_stamp;
@@ -284,25 +293,17 @@ struct igb_q_vector {
enum e1000_ring_flags_t {
IGB_RING_FLAG_RX_SCTP_CSUM,
IGB_RING_FLAG_RX_LB_VLAN_BSWAP,
- IGB_RING_FLAG_RX_BUILD_SKB_ENABLED,
IGB_RING_FLAG_TX_CTX_IDX,
IGB_RING_FLAG_TX_DETECT_HANG
};
-#define ring_uses_build_skb(ring) \
- test_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-#define set_ring_build_skb_enabled(ring) \
- set_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-#define clear_ring_build_skb_enabled(ring) \
- clear_bit(IGB_RING_FLAG_RX_BUILD_SKB_ENABLED, &(ring)->flags)
-
#define IGB_TXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS)
-#define IGB_RX_DESC(R, i) \
+#define IGB_RX_DESC(R, i) \
(&(((union e1000_adv_rx_desc *)((R)->desc))[i]))
-#define IGB_TX_DESC(R, i) \
+#define IGB_TX_DESC(R, i) \
(&(((union e1000_adv_tx_desc *)((R)->desc))[i]))
-#define IGB_TX_CTXTDESC(R, i) \
+#define IGB_TX_CTXTDESC(R, i) \
(&(((struct e1000_adv_tx_context_desc *)((R)->desc))[i]))
/* igb_test_staterr - tests bits within Rx descriptor status and error fields */
@@ -461,12 +462,12 @@ struct igb_adapter {
#define IGB_FLAG_WOL_SUPPORTED (1 << 8)
/* DMA Coalescing defines */
-#define IGB_MIN_TXPBSIZE 20408
-#define IGB_TX_BUF_4096 4096
-#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */
+#define IGB_MIN_TXPBSIZE 20408
+#define IGB_TX_BUF_4096 4096
+#define IGB_DMCTLX_DCFLUSH_DIS 0x80000000 /* Disable DMA Coal Flush */
-#define IGB_82576_TSYNC_SHIFT 19
-#define IGB_TS_HDR_LEN 16
+#define IGB_82576_TSYNC_SHIFT 19
+#define IGB_TS_HDR_LEN 16
enum e1000_state_t {
__IGB_TESTING,
__IGB_RESETTING,
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index a3830a8ba4c1..7876240fa74e 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/highmem.h>
+#include <linux/mdio.h>
#include "igb.h"
@@ -178,44 +179,67 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
ecmd->phy_address = hw->phy.addr;
+ ecmd->transceiver = XCVR_INTERNAL;
} else {
- ecmd->supported = (SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg);
+ ecmd->supported = (SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg |
+ SUPPORTED_Pause);
+ if (hw->mac.type == e1000_i354)
+ ecmd->supported |= SUPPORTED_2500baseX_Full;
+
+ ecmd->advertising = ADVERTISED_FIBRE;
+
+ switch (adapter->link_speed) {
+ case SPEED_2500:
+ ecmd->advertising = ADVERTISED_2500baseX_Full;
+ break;
+ case SPEED_1000:
+ ecmd->advertising = ADVERTISED_1000baseT_Full;
+ break;
+ case SPEED_100:
+ ecmd->advertising = ADVERTISED_100baseT_Full;
+ break;
+ default:
+ break;
+ }
- ecmd->advertising = (ADVERTISED_1000baseT_Full |
- ADVERTISED_FIBRE |
- ADVERTISED_Autoneg |
- ADVERTISED_Pause);
+ if (hw->mac.autoneg == 1)
+ ecmd->advertising |= ADVERTISED_Autoneg;
ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
}
- ecmd->transceiver = XCVR_INTERNAL;
-
status = rd32(E1000_STATUS);
if (status & E1000_STATUS_LU) {
-
- if ((status & E1000_STATUS_SPEED_1000) ||
- hw->phy.media_type != e1000_media_type_copper)
- ethtool_cmd_speed_set(ecmd, SPEED_1000);
+ if ((hw->mac.type == e1000_i354) &&
+ (status & E1000_STATUS_2P5_SKU) &&
+ !(status & E1000_STATUS_2P5_SKU_OVER))
+ ecmd->speed = SPEED_2500;
+ else if (status & E1000_STATUS_SPEED_1000)
+ ecmd->speed = SPEED_1000;
else if (status & E1000_STATUS_SPEED_100)
- ethtool_cmd_speed_set(ecmd, SPEED_100);
+ ecmd->speed = SPEED_100;
else
- ethtool_cmd_speed_set(ecmd, SPEED_10);
-
+ ecmd->speed = SPEED_10;
if ((status & E1000_STATUS_FD) ||
hw->phy.media_type != e1000_media_type_copper)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ethtool_cmd_speed_set(ecmd, -1);
+ ecmd->speed = -1;
ecmd->duplex = -1;
}
- ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ if ((hw->phy.media_type == e1000_media_type_fiber) ||
+ hw->mac.autoneg)
+ ecmd->autoneg = AUTONEG_ENABLE;
+ else
+ ecmd->autoneg = AUTONEG_DISABLE;
/* MDI-X => 2; MDI =>1; Invalid =>0 */
if (hw->phy.media_type == e1000_media_type_copper)
@@ -238,15 +262,15 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
struct e1000_hw *hw = &adapter->hw;
/* When SoL/IDER sessions are active, autoneg/speed/duplex
- * cannot be changed */
+ * cannot be changed
+ */
if (igb_check_reset_block(hw)) {
dev_err(&adapter->pdev->dev,
"Cannot change link characteristics when SoL/IDER is active.\n");
return -EINVAL;
}
- /*
- * MDI setting is only allowed when autoneg enabled because
+ /* MDI setting is only allowed when autoneg enabled because
* some hardware doesn't allow MDI setting when speed or
* duplex is forced.
*/
@@ -266,9 +290,31 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->mac.autoneg = 1;
- hw->phy.autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+ switch (adapter->link_speed) {
+ case SPEED_2500:
+ hw->phy.autoneg_advertised =
+ ADVERTISED_2500baseX_Full;
+ break;
+ case SPEED_1000:
+ hw->phy.autoneg_advertised =
+ ADVERTISED_1000baseT_Full;
+ break;
+ case SPEED_100:
+ hw->phy.autoneg_advertised =
+ ADVERTISED_100baseT_Full;
+ break;
+ default:
+ break;
+ }
+ } else {
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
+ }
ecmd->advertising = hw->phy.autoneg_advertised;
if (adapter->fc_autoneg)
hw->fc.requested_mode = e1000_fc_default;
@@ -283,8 +329,7 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
/* MDI-X => 2; MDI => 1; Auto => 3 */
if (ecmd->eth_tp_mdix_ctrl) {
- /*
- * fix up the value for auto (3 => 0) as zero is mapped
+ /* fix up the value for auto (3 => 0) as zero is mapped
* internally to auto
*/
if (ecmd->eth_tp_mdix_ctrl == ETH_TP_MDI_AUTO)
@@ -309,8 +354,7 @@ static u32 igb_get_link(struct net_device *netdev)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_mac_info *mac = &adapter->hw.mac;
- /*
- * If the link is not reported up to netdev, interrupts are disabled,
+ /* If the link is not reported up to netdev, interrupts are disabled,
* and so the physical link state may have changed since we last
* looked. Set get_link_status to make sure that the true link
* state is interrogated, rather than pulling a cached and possibly
@@ -430,7 +474,8 @@ static void igb_get_regs(struct net_device *netdev,
/* Interrupt */
/* Reading EICS for EICR because they read the
- * same but EICS does not clear on read */
+ * same but EICS does not clear on read
+ */
regs_buff[13] = rd32(E1000_EICS);
regs_buff[14] = rd32(E1000_EICS);
regs_buff[15] = rd32(E1000_EIMS);
@@ -438,7 +483,8 @@ static void igb_get_regs(struct net_device *netdev,
regs_buff[17] = rd32(E1000_EIAC);
regs_buff[18] = rd32(E1000_EIAM);
/* Reading ICS for ICR because they read the
- * same but ICS does not clear on read */
+ * same but ICS does not clear on read
+ */
regs_buff[19] = rd32(E1000_ICS);
regs_buff[20] = rd32(E1000_ICS);
regs_buff[21] = rd32(E1000_IMS);
@@ -688,12 +734,12 @@ static int igb_get_eeprom(struct net_device *netdev,
if (hw->nvm.type == e1000_nvm_eeprom_spi)
ret_val = hw->nvm.ops.read(hw, first_word,
- last_word - first_word + 1,
- eeprom_buff);
+ last_word - first_word + 1,
+ eeprom_buff);
else {
for (i = 0; i < last_word - first_word + 1; i++) {
ret_val = hw->nvm.ops.read(hw, first_word + i, 1,
- &eeprom_buff[i]);
+ &eeprom_buff[i]);
if (ret_val)
break;
}
@@ -740,15 +786,17 @@ static int igb_set_eeprom(struct net_device *netdev,
ptr = (void *)eeprom_buff;
if (eeprom->offset & 1) {
- /* need read/modify/write of first changed EEPROM word */
- /* only the second byte of the word is being modified */
+ /* need read/modify/write of first changed EEPROM word
+ * only the second byte of the word is being modified
+ */
ret_val = hw->nvm.ops.read(hw, first_word, 1,
&eeprom_buff[0]);
ptr++;
}
if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) {
- /* need read/modify/write of last changed EEPROM word */
- /* only the first byte of the word is being modified */
+ /* need read/modify/write of last changed EEPROM word
+ * only the first byte of the word is being modified
+ */
ret_val = hw->nvm.ops.read(hw, last_word, 1,
&eeprom_buff[last_word - first_word]);
}
@@ -763,10 +811,11 @@ static int igb_set_eeprom(struct net_device *netdev,
eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
ret_val = hw->nvm.ops.write(hw, first_word,
- last_word - first_word + 1, eeprom_buff);
+ last_word - first_word + 1, eeprom_buff);
/* Update the checksum over the first part of the EEPROM if needed
- * and flush shadow RAM for 82573 controllers */
+ * and flush shadow RAM for 82573 controllers
+ */
if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG)))
hw->nvm.ops.update(hw);
@@ -783,8 +832,7 @@ static void igb_get_drvinfo(struct net_device *netdev,
strlcpy(drvinfo->driver, igb_driver_name, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, igb_driver_version, sizeof(drvinfo->version));
- /*
- * EEPROM image version # is reported as firmware version # for
+ /* EEPROM image version # is reported as firmware version # for
* 82575 controllers
*/
strlcpy(drvinfo->fw_version, adapter->fw_version,
@@ -847,9 +895,11 @@ static int igb_set_ringparam(struct net_device *netdev,
}
if (adapter->num_tx_queues > adapter->num_rx_queues)
- temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring));
+ temp_ring = vmalloc(adapter->num_tx_queues *
+ sizeof(struct igb_ring));
else
- temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring));
+ temp_ring = vmalloc(adapter->num_rx_queues *
+ sizeof(struct igb_ring));
if (!temp_ring) {
err = -ENOMEM;
@@ -858,10 +908,9 @@ static int igb_set_ringparam(struct net_device *netdev,
igb_down(adapter);
- /*
- * We can't just free everything and then setup again,
+ /* We can't just free everything and then setup again,
* because the ISRs in MSI-X mode get passed pointers
- * to the tx and rx ring structs.
+ * to the Tx and Rx ring structs.
*/
if (new_tx_count != adapter->tx_ring_count) {
for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -1199,6 +1248,7 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
switch (adapter->hw.mac.type) {
case e1000_i350:
+ case e1000_i354:
test = reg_test_i350;
toggle = 0x7FEFF3FF;
break;
@@ -1361,6 +1411,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
ics_mask = 0x77DCFED5;
break;
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
ics_mask = 0x77DCFED5;
@@ -1627,17 +1678,12 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
wr32(E1000_CONNSW, reg);
/* Unset sigdetect for SERDES loopback on
- * 82580 and i350 devices.
+ * 82580 and newer devices.
*/
- switch (hw->mac.type) {
- case e1000_82580:
- case e1000_i350:
+ if (hw->mac.type >= e1000_82580) {
reg = rd32(E1000_PCS_CFG0);
reg |= E1000_PCS_CFG_IGN_SD;
wr32(E1000_PCS_CFG0, reg);
- break;
- default:
- break;
}
/* Set PCS register for forced speed */
@@ -1723,8 +1769,8 @@ static int igb_check_lbtest_frame(struct igb_rx_buffer *rx_buffer,
}
static int igb_clean_test_rings(struct igb_ring *rx_ring,
- struct igb_ring *tx_ring,
- unsigned int size)
+ struct igb_ring *tx_ring,
+ unsigned int size)
{
union e1000_adv_rx_desc *rx_desc;
struct igb_rx_buffer *rx_buffer_info;
@@ -1737,7 +1783,7 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring,
rx_desc = IGB_RX_DESC(rx_ring, rx_ntc);
while (igb_test_staterr(rx_desc, E1000_RXD_STAT_DD)) {
- /* check rx buffer */
+ /* check Rx buffer */
rx_buffer_info = &rx_ring->rx_buffer_info[rx_ntc];
/* sync Rx buffer for CPU read */
@@ -1756,11 +1802,11 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring,
IGB_RX_BUFSZ,
DMA_FROM_DEVICE);
- /* unmap buffer on tx side */
+ /* unmap buffer on Tx side */
tx_buffer_info = &tx_ring->tx_buffer_info[tx_ntc];
igb_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
- /* increment rx/tx next to clean counters */
+ /* increment Rx/Tx next to clean counters */
rx_ntc++;
if (rx_ntc == rx_ring->count)
rx_ntc = 0;
@@ -1801,8 +1847,7 @@ static int igb_run_loopback_test(struct igb_adapter *adapter)
igb_create_lbtest_frame(skb, size);
skb_put(skb, size);
- /*
- * Calculate the loop count based on the largest descriptor ring
+ /* Calculate the loop count based on the largest descriptor ring
* The idea is to wrap the largest ring a number of times using 64
* send/receive pairs during each loop
*/
@@ -1829,7 +1874,7 @@ static int igb_run_loopback_test(struct igb_adapter *adapter)
break;
}
- /* allow 200 milliseconds for packets to go from tx to rx */
+ /* allow 200 milliseconds for packets to go from Tx to Rx */
msleep(200);
good_cnt = igb_clean_test_rings(rx_ring, tx_ring, size);
@@ -1848,13 +1893,21 @@ static int igb_run_loopback_test(struct igb_adapter *adapter)
static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
{
/* PHY loopback cannot be performed if SoL/IDER
- * sessions are active */
+ * sessions are active
+ */
if (igb_check_reset_block(&adapter->hw)) {
dev_err(&adapter->pdev->dev,
"Cannot do PHY loopback test when SoL/IDER is active.\n");
*data = 0;
goto out;
}
+
+ if (adapter->hw.mac.type == e1000_i354) {
+ dev_info(&adapter->pdev->dev,
+ "Loopback test not supported on i354.\n");
+ *data = 0;
+ goto out;
+ }
*data = igb_setup_desc_rings(adapter);
if (*data)
goto out;
@@ -1879,7 +1932,8 @@ static int igb_link_test(struct igb_adapter *adapter, u64 *data)
hw->mac.serdes_has_link = false;
/* On some blade server designs, link establishment
- * could take as long as 2-3 minutes */
+ * could take as long as 2-3 minutes
+ */
do {
hw->mac.ops.check_for_link(&adapter->hw);
if (hw->mac.serdes_has_link)
@@ -1922,7 +1976,8 @@ static void igb_diag_test(struct net_device *netdev,
igb_power_up_link(adapter);
/* Link test performed before hardware reset so autoneg doesn't
- * interfere with test result */
+ * interfere with test result
+ */
if (igb_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1987,8 +2042,8 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
struct igb_adapter *adapter = netdev_priv(netdev);
wol->supported = WAKE_UCAST | WAKE_MCAST |
- WAKE_BCAST | WAKE_MAGIC |
- WAKE_PHY;
+ WAKE_BCAST | WAKE_MAGIC |
+ WAKE_PHY;
wol->wolopts = 0;
if (!(adapter->flags & IGB_FLAG_WOL_SUPPORTED))
@@ -2263,7 +2318,7 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
sprintf(p, "rx_queue_%u_alloc_failed", i);
p += ETH_GSTRING_LEN;
}
-/* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
+ /* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */
break;
}
}
@@ -2283,6 +2338,7 @@ static int igb_get_ts_info(struct net_device *dev,
case e1000_82576:
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
info->so_timestamping =
@@ -2362,7 +2418,7 @@ static int igb_get_rss_hash_opts(struct igb_adapter *adapter,
}
static int igb_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
- u32 *rule_locs)
+ u32 *rule_locs)
{
struct igb_adapter *adapter = netdev_priv(dev);
int ret = -EOPNOTSUPP;
@@ -2506,7 +2562,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u32 ipcnfg, eeer;
+ u32 ipcnfg, eeer, ret_val;
+ u16 phy_data;
if ((hw->mac.type < e1000_i350) ||
(hw->phy.media_type != e1000_media_type_copper))
@@ -2525,6 +2582,32 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
if (ipcnfg & E1000_IPCNFG_EEE_100M_AN)
edata->advertised |= ADVERTISED_100baseT_Full;
+ /* EEE Link Partner Advertised */
+ switch (hw->mac.type) {
+ case e1000_i350:
+ ret_val = igb_read_emi_reg(hw, E1000_EEE_LP_ADV_ADDR_I350,
+ &phy_data);
+ if (ret_val)
+ return -ENODATA;
+
+ edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+ break;
+ case e1000_i210:
+ case e1000_i211:
+ ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210,
+ E1000_EEE_LP_ADV_DEV_I210,
+ &phy_data);
+ if (ret_val)
+ return -ENODATA;
+
+ edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+
+ break;
+ default:
+ break;
+ }
+
if (eeer & E1000_EEER_EEE_NEG)
edata->eee_active = true;
@@ -2600,6 +2683,85 @@ static int igb_set_eee(struct net_device *netdev,
return 0;
}
+static int igb_get_module_info(struct net_device *netdev,
+ struct ethtool_modinfo *modinfo)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 status = E1000_SUCCESS;
+ u16 sff8472_rev, addr_mode;
+ bool page_swap = false;
+
+ if ((hw->phy.media_type == e1000_media_type_copper) ||
+ (hw->phy.media_type == e1000_media_type_unknown))
+ return -EOPNOTSUPP;
+
+ /* Check whether we support SFF-8472 or not */
+ status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev);
+ if (status != E1000_SUCCESS)
+ return -EIO;
+
+ /* addressing mode is not supported */
+ status = igb_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode);
+ if (status != E1000_SUCCESS)
+ return -EIO;
+
+ /* addressing mode is not supported */
+ if ((addr_mode & 0xFF) & IGB_SFF_ADDRESSING_MODE) {
+ hw_dbg("Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
+ page_swap = true;
+ }
+
+ if ((sff8472_rev & 0xFF) == IGB_SFF_8472_UNSUP || page_swap) {
+ /* We have an SFP, but it does not support SFF-8472 */
+ modinfo->type = ETH_MODULE_SFF_8079;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+ } else {
+ /* We have an SFP which supports a revision of SFF-8472 */
+ modinfo->type = ETH_MODULE_SFF_8472;
+ modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+ }
+
+ return 0;
+}
+
+static int igb_get_module_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *ee, u8 *data)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 status = E1000_SUCCESS;
+ u16 *dataword;
+ u16 first_word, last_word;
+ int i = 0;
+
+ if (ee->len == 0)
+ return -EINVAL;
+
+ first_word = ee->offset >> 1;
+ last_word = (ee->offset + ee->len - 1) >> 1;
+
+ dataword = kmalloc(sizeof(u16) * (last_word - first_word + 1),
+ GFP_KERNEL);
+ if (!dataword)
+ return -ENOMEM;
+
+ /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
+ for (i = 0; i < last_word - first_word + 1; i++) {
+ status = igb_read_phy_reg_i2c(hw, first_word + i, &dataword[i]);
+ if (status != E1000_SUCCESS)
+ /* Error occurred while reading module */
+ return -EIO;
+
+ be16_to_cpus(&dataword[i]);
+ }
+
+ memcpy(data, (u8 *)dataword + (ee->offset & 1), ee->len);
+ kfree(dataword);
+
+ return 0;
+}
+
static int igb_ethtool_begin(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -2614,36 +2776,38 @@ static void igb_ethtool_complete(struct net_device *netdev)
}
static const struct ethtool_ops igb_ethtool_ops = {
- .get_settings = igb_get_settings,
- .set_settings = igb_set_settings,
- .get_drvinfo = igb_get_drvinfo,
- .get_regs_len = igb_get_regs_len,
- .get_regs = igb_get_regs,
- .get_wol = igb_get_wol,
- .set_wol = igb_set_wol,
- .get_msglevel = igb_get_msglevel,
- .set_msglevel = igb_set_msglevel,
- .nway_reset = igb_nway_reset,
- .get_link = igb_get_link,
- .get_eeprom_len = igb_get_eeprom_len,
- .get_eeprom = igb_get_eeprom,
- .set_eeprom = igb_set_eeprom,
- .get_ringparam = igb_get_ringparam,
- .set_ringparam = igb_set_ringparam,
- .get_pauseparam = igb_get_pauseparam,
- .set_pauseparam = igb_set_pauseparam,
- .self_test = igb_diag_test,
- .get_strings = igb_get_strings,
- .set_phys_id = igb_set_phys_id,
- .get_sset_count = igb_get_sset_count,
- .get_ethtool_stats = igb_get_ethtool_stats,
- .get_coalesce = igb_get_coalesce,
- .set_coalesce = igb_set_coalesce,
- .get_ts_info = igb_get_ts_info,
+ .get_settings = igb_get_settings,
+ .set_settings = igb_set_settings,
+ .get_drvinfo = igb_get_drvinfo,
+ .get_regs_len = igb_get_regs_len,
+ .get_regs = igb_get_regs,
+ .get_wol = igb_get_wol,
+ .set_wol = igb_set_wol,
+ .get_msglevel = igb_get_msglevel,
+ .set_msglevel = igb_set_msglevel,
+ .nway_reset = igb_nway_reset,
+ .get_link = igb_get_link,
+ .get_eeprom_len = igb_get_eeprom_len,
+ .get_eeprom = igb_get_eeprom,
+ .set_eeprom = igb_set_eeprom,
+ .get_ringparam = igb_get_ringparam,
+ .set_ringparam = igb_set_ringparam,
+ .get_pauseparam = igb_get_pauseparam,
+ .set_pauseparam = igb_set_pauseparam,
+ .self_test = igb_diag_test,
+ .get_strings = igb_get_strings,
+ .set_phys_id = igb_set_phys_id,
+ .get_sset_count = igb_get_sset_count,
+ .get_ethtool_stats = igb_get_ethtool_stats,
+ .get_coalesce = igb_get_coalesce,
+ .set_coalesce = igb_set_coalesce,
+ .get_ts_info = igb_get_ts_info,
.get_rxnfc = igb_get_rxnfc,
.set_rxnfc = igb_set_rxnfc,
.get_eee = igb_get_eee,
.set_eee = igb_set_eee,
+ .get_module_info = igb_get_module_info,
+ .get_module_eeprom = igb_get_module_eeprom,
.begin = igb_ethtool_begin,
.complete = igb_ethtool_complete,
};
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c
index 0478a1abe541..58f1ce967aeb 100644
--- a/drivers/net/ethernet/intel/igb/igb_hwmon.c
+++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c
@@ -45,21 +45,21 @@ static struct i2c_board_info i350_sensor_info = {
/* hwmon callback functions */
static ssize_t igb_hwmon_show_location(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
- dev_attr);
+ dev_attr);
return sprintf(buf, "loc%u\n",
igb_attr->sensor->location);
}
static ssize_t igb_hwmon_show_temp(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
- dev_attr);
+ dev_attr);
unsigned int value;
/* reset the temp field */
@@ -74,11 +74,11 @@ static ssize_t igb_hwmon_show_temp(struct device *dev,
}
static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
- dev_attr);
+ dev_attr);
unsigned int value = igb_attr->sensor->caution_thresh;
/* display millidegree */
@@ -88,11 +88,11 @@ static ssize_t igb_hwmon_show_cautionthresh(struct device *dev,
}
static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr,
- dev_attr);
+ dev_attr);
unsigned int value = igb_attr->sensor->max_op_thresh;
/* display millidegree */
@@ -111,7 +111,8 @@ static ssize_t igb_hwmon_show_maxopthresh(struct device *dev,
* the data structures we need to get the data to display.
*/
static int igb_add_hwmon_attr(struct igb_adapter *adapter,
- unsigned int offset, int type) {
+ unsigned int offset, int type)
+{
int rc;
unsigned int n_attr;
struct hwmon_attr *igb_attr;
@@ -217,7 +218,7 @@ int igb_sysfs_init(struct igb_adapter *adapter)
*/
n_attrs = E1000_MAX_SENSORS * 4;
igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!igb_hwmon->hwmon_list) {
rc = -ENOMEM;
goto err;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 8496adfc6a68..64cbe0dfe043 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -60,9 +60,9 @@
#include <linux/i2c.h>
#include "igb.h"
-#define MAJ 4
-#define MIN 1
-#define BUILD 2
+#define MAJ 5
+#define MIN 0
+#define BUILD 3
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD) "-k"
char igb_driver_name[] = "igb";
@@ -77,6 +77,9 @@ static const struct e1000_info *igb_info_tbl[] = {
};
static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 },
@@ -156,8 +159,8 @@ static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
static void igb_tx_timeout(struct net_device *);
static void igb_reset_task(struct work_struct *);
static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features);
-static int igb_vlan_rx_add_vid(struct net_device *, u16);
-static int igb_vlan_rx_kill_vid(struct net_device *, u16);
+static int igb_vlan_rx_add_vid(struct net_device *, __be16, u16);
+static int igb_vlan_rx_kill_vid(struct net_device *, __be16, u16);
static void igb_restore_vlan(struct igb_adapter *);
static void igb_rar_set_qsel(struct igb_adapter *, u8 *, u32 , u8);
static void igb_ping_all_vfs(struct igb_adapter *);
@@ -169,13 +172,14 @@ static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos);
static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+static int igb_ndo_set_vf_spoofchk(struct net_device *netdev, int vf,
+ bool setting);
static int igb_ndo_get_vf_config(struct net_device *netdev, int vf,
struct ifla_vf_info *ivi);
static void igb_check_vf_rate_limit(struct igb_adapter *);
#ifdef CONFIG_PCI_IOV
static int igb_vf_configure(struct igb_adapter *adapter, int vf);
-static bool igb_vfs_are_assigned(struct igb_adapter *adapter);
#endif
#ifdef CONFIG_PM
@@ -292,9 +296,7 @@ static const struct igb_reg_info igb_reg_info_tbl[] = {
{}
};
-/*
- * igb_regdump - register printout routine
- */
+/* igb_regdump - register printout routine */
static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
{
int n = 0;
@@ -360,9 +362,7 @@ static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
regs[2], regs[3]);
}
-/*
- * igb_dump - Print registers, tx-rings and rx-rings
- */
+/* igb_dump - Print registers, Tx-rings and Rx-rings */
static void igb_dump(struct igb_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -569,12 +569,13 @@ exit:
return;
}
-/* igb_get_i2c_data - Reads the I2C SDA data bit
+/**
+ * igb_get_i2c_data - Reads the I2C SDA data bit
* @hw: pointer to hardware structure
* @i2cctl: Current value of I2CCTL register
*
* Returns the I2C data bit value
- */
+ **/
static int igb_get_i2c_data(void *data)
{
struct igb_adapter *adapter = (struct igb_adapter *)data;
@@ -584,12 +585,13 @@ static int igb_get_i2c_data(void *data)
return ((i2cctl & E1000_I2C_DATA_IN) != 0);
}
-/* igb_set_i2c_data - Sets the I2C data bit
+/**
+ * igb_set_i2c_data - Sets the I2C data bit
* @data: pointer to hardware structure
* @state: I2C data value (0 or 1) to set
*
* Sets the I2C data bit
- */
+ **/
static void igb_set_i2c_data(void *data, int state)
{
struct igb_adapter *adapter = (struct igb_adapter *)data;
@@ -608,12 +610,13 @@ static void igb_set_i2c_data(void *data, int state)
}
-/* igb_set_i2c_clk - Sets the I2C SCL clock
+/**
+ * igb_set_i2c_clk - Sets the I2C SCL clock
* @data: pointer to hardware structure
* @state: state to set clock
*
* Sets the I2C clock line to state
- */
+ **/
static void igb_set_i2c_clk(void *data, int state)
{
struct igb_adapter *adapter = (struct igb_adapter *)data;
@@ -631,11 +634,12 @@ static void igb_set_i2c_clk(void *data, int state)
wrfl();
}
-/* igb_get_i2c_clk - Gets the I2C SCL clock state
+/**
+ * igb_get_i2c_clk - Gets the I2C SCL clock state
* @data: pointer to hardware structure
*
* Gets the I2C clock state
- */
+ **/
static int igb_get_i2c_clk(void *data)
{
struct igb_adapter *adapter = (struct igb_adapter *)data;
@@ -655,8 +659,10 @@ static const struct i2c_algo_bit_data igb_i2c_algo = {
};
/**
- * igb_get_hw_dev - return device
- * used by hardware layer to print debugging information
+ * igb_get_hw_dev - return device
+ * @hw: pointer to hardware structure
+ *
+ * used by hardware layer to print debugging information
**/
struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
{
@@ -665,10 +671,10 @@ struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
}
/**
- * igb_init_module - Driver Registration Routine
+ * igb_init_module - Driver Registration Routine
*
- * igb_init_module is the first routine called when the driver is
- * loaded. All it does is register with the PCI subsystem.
+ * igb_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
**/
static int __init igb_init_module(void)
{
@@ -688,10 +694,10 @@ static int __init igb_init_module(void)
module_init(igb_init_module);
/**
- * igb_exit_module - Driver Exit Cleanup Routine
+ * igb_exit_module - Driver Exit Cleanup Routine
*
- * igb_exit_module is called just before the driver is removed
- * from memory.
+ * igb_exit_module is called just before the driver is removed
+ * from memory.
**/
static void __exit igb_exit_module(void)
{
@@ -705,11 +711,11 @@ module_exit(igb_exit_module);
#define Q_IDX_82576(i) (((i & 0x1) << 3) + (i >> 1))
/**
- * igb_cache_ring_register - Descriptor ring to register mapping
- * @adapter: board private structure to initialize
+ * igb_cache_ring_register - Descriptor ring to register mapping
+ * @adapter: board private structure to initialize
*
- * Once we know the feature-set enabled for the device, we'll cache
- * the register offset the descriptor ring is assigned to.
+ * Once we know the feature-set enabled for the device, we'll cache
+ * the register offset the descriptor ring is assigned to.
**/
static void igb_cache_ring_register(struct igb_adapter *adapter)
{
@@ -726,11 +732,12 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
if (adapter->vfs_allocated_count) {
for (; i < adapter->rss_queues; i++)
adapter->rx_ring[i]->reg_idx = rbase_offset +
- Q_IDX_82576(i);
+ Q_IDX_82576(i);
}
case e1000_82575:
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
default:
@@ -785,9 +792,10 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
switch (hw->mac.type) {
case e1000_82575:
/* The 82575 assigns vectors using a bitmask, which matches the
- bitmask for the EICR/EIMS/EIMC registers. To assign one
- or more queues to a vector, we write the appropriate bits
- into the MSIXBM register for that vector. */
+ * bitmask for the EICR/EIMS/EIMC registers. To assign one
+ * or more queues to a vector, we write the appropriate bits
+ * into the MSIXBM register for that vector.
+ */
if (rx_queue > IGB_N0_QUEUE)
msixbm = E1000_EICR_RX_QUEUE0 << rx_queue;
if (tx_queue > IGB_N0_QUEUE)
@@ -798,8 +806,7 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
q_vector->eims_value = msixbm;
break;
case e1000_82576:
- /*
- * 82576 uses a table that essentially consists of 2 columns
+ /* 82576 uses a table that essentially consists of 2 columns
* with 8 rows. The ordering is column-major so we use the
* lower 3 bits as the row index, and the 4th bit as the
* column offset.
@@ -816,10 +823,10 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
break;
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
- /*
- * On 82580 and newer adapters the scheme is similar to 82576
+ /* On 82580 and newer adapters the scheme is similar to 82576
* however instead of ordering column-major we have things
* ordered row-major. So we traverse the table by using
* bit 0 as the column offset, and the remaining bits as the
@@ -848,10 +855,11 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
}
/**
- * igb_configure_msix - Configure MSI-X hardware
+ * igb_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure to initialize
*
- * igb_configure_msix sets up the hardware to properly
- * generate MSI-X interrupts.
+ * igb_configure_msix sets up the hardware to properly
+ * generate MSI-X interrupts.
**/
static void igb_configure_msix(struct igb_adapter *adapter)
{
@@ -875,8 +883,7 @@ static void igb_configure_msix(struct igb_adapter *adapter)
wr32(E1000_CTRL_EXT, tmp);
/* enable msix_other interrupt */
- array_wr32(E1000_MSIXBM(0), vector++,
- E1000_EIMS_OTHER);
+ array_wr32(E1000_MSIXBM(0), vector++, E1000_EIMS_OTHER);
adapter->eims_other = E1000_EIMS_OTHER;
break;
@@ -884,13 +891,15 @@ static void igb_configure_msix(struct igb_adapter *adapter)
case e1000_82576:
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
case e1000_i211:
/* Turn on MSI-X capability first, or our settings
- * won't stick. And it will take days to debug. */
+ * won't stick. And it will take days to debug.
+ */
wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE |
- E1000_GPIE_PBA | E1000_GPIE_EIAME |
- E1000_GPIE_NSICR);
+ E1000_GPIE_PBA | E1000_GPIE_EIAME |
+ E1000_GPIE_NSICR);
/* enable msix_other interrupt */
adapter->eims_other = 1 << vector;
@@ -912,10 +921,11 @@ static void igb_configure_msix(struct igb_adapter *adapter)
}
/**
- * igb_request_msix - Initialize MSI-X interrupts
+ * igb_request_msix - Initialize MSI-X interrupts
+ * @adapter: board private structure to initialize
*
- * igb_request_msix allocates MSI-X vectors and requests interrupts from the
- * kernel.
+ * igb_request_msix allocates MSI-X vectors and requests interrupts from the
+ * kernel.
**/
static int igb_request_msix(struct igb_adapter *adapter)
{
@@ -924,7 +934,7 @@ static int igb_request_msix(struct igb_adapter *adapter)
int i, err = 0, vector = 0, free_vector = 0;
err = request_irq(adapter->msix_entries[vector].vector,
- igb_msix_other, 0, netdev->name, adapter);
+ igb_msix_other, 0, netdev->name, adapter);
if (err)
goto err_out;
@@ -948,8 +958,8 @@ static int igb_request_msix(struct igb_adapter *adapter)
sprintf(q_vector->name, "%s-unused", netdev->name);
err = request_irq(adapter->msix_entries[vector].vector,
- igb_msix_ring, 0, q_vector->name,
- q_vector);
+ igb_msix_ring, 0, q_vector->name,
+ q_vector);
if (err)
goto err_free;
}
@@ -982,13 +992,13 @@ static void igb_reset_interrupt_capability(struct igb_adapter *adapter)
}
/**
- * igb_free_q_vector - Free memory allocated for specific interrupt vector
- * @adapter: board private structure to initialize
- * @v_idx: Index of vector to be freed
+ * igb_free_q_vector - Free memory allocated for specific interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_idx: Index of vector to be freed
*
- * This function frees the memory allocated to the q_vector. In addition if
- * NAPI is enabled it will delete any references to the NAPI struct prior
- * to freeing the q_vector.
+ * This function frees the memory allocated to the q_vector. In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
**/
static void igb_free_q_vector(struct igb_adapter *adapter, int v_idx)
{
@@ -1003,20 +1013,19 @@ static void igb_free_q_vector(struct igb_adapter *adapter, int v_idx)
adapter->q_vector[v_idx] = NULL;
netif_napi_del(&q_vector->napi);
- /*
- * ixgbe_get_stats64() might access the rings on this vector,
+ /* ixgbe_get_stats64() might access the rings on this vector,
* we must wait a grace period before freeing it.
*/
kfree_rcu(q_vector, rcu);
}
/**
- * igb_free_q_vectors - Free memory allocated for interrupt vectors
- * @adapter: board private structure to initialize
+ * igb_free_q_vectors - Free memory allocated for interrupt vectors
+ * @adapter: board private structure to initialize
*
- * This function frees the memory allocated to the q_vectors. In addition if
- * NAPI is enabled it will delete any references to the NAPI struct prior
- * to freeing the q_vector.
+ * This function frees the memory allocated to the q_vectors. In addition if
+ * NAPI is enabled it will delete any references to the NAPI struct prior
+ * to freeing the q_vector.
**/
static void igb_free_q_vectors(struct igb_adapter *adapter)
{
@@ -1031,10 +1040,11 @@ static void igb_free_q_vectors(struct igb_adapter *adapter)
}
/**
- * igb_clear_interrupt_scheme - reset the device to a state of no interrupts
+ * igb_clear_interrupt_scheme - reset the device to a state of no interrupts
+ * @adapter: board private structure to initialize
*
- * This function resets the device so that it has 0 rx queues, tx queues, and
- * MSI-X interrupts allocated.
+ * This function resets the device so that it has 0 Rx queues, Tx queues, and
+ * MSI-X interrupts allocated.
*/
static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
{
@@ -1043,10 +1053,12 @@ static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
}
/**
- * igb_set_interrupt_capability - set MSI or MSI-X if supported
+ * igb_set_interrupt_capability - set MSI or MSI-X if supported
+ * @adapter: board private structure to initialize
+ * @msix: boolean value of MSIX capability
*
- * Attempt to configure interrupts using the best available
- * capabilities of the hardware and kernel.
+ * Attempt to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
**/
static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix)
{
@@ -1063,10 +1075,10 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix)
else
adapter->num_tx_queues = adapter->rss_queues;
- /* start with one vector for every rx queue */
+ /* start with one vector for every Rx queue */
numvecs = adapter->num_rx_queues;
- /* if tx handler is separate add 1 for every tx queue */
+ /* if Tx handler is separate add 1 for every Tx queue */
if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
numvecs += adapter->num_tx_queues;
@@ -1128,16 +1140,16 @@ static void igb_add_ring(struct igb_ring *ring,
}
/**
- * igb_alloc_q_vector - Allocate memory for a single interrupt vector
- * @adapter: board private structure to initialize
- * @v_count: q_vectors allocated on adapter, used for ring interleaving
- * @v_idx: index of vector in adapter struct
- * @txr_count: total number of Tx rings to allocate
- * @txr_idx: index of first Tx ring to allocate
- * @rxr_count: total number of Rx rings to allocate
- * @rxr_idx: index of first Rx ring to allocate
+ * igb_alloc_q_vector - Allocate memory for a single interrupt vector
+ * @adapter: board private structure to initialize
+ * @v_count: q_vectors allocated on adapter, used for ring interleaving
+ * @v_idx: index of vector in adapter struct
+ * @txr_count: total number of Tx rings to allocate
+ * @txr_idx: index of first Tx ring to allocate
+ * @rxr_count: total number of Rx rings to allocate
+ * @rxr_idx: index of first Rx ring to allocate
*
- * We allocate one q_vector. If allocation fails we return -ENOMEM.
+ * We allocate one q_vector. If allocation fails we return -ENOMEM.
**/
static int igb_alloc_q_vector(struct igb_adapter *adapter,
int v_count, int v_idx,
@@ -1179,6 +1191,17 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
/* initialize pointer to rings */
ring = q_vector->ring;
+ /* intialize ITR */
+ if (rxr_count) {
+ /* rx or rx/tx vector */
+ if (!adapter->rx_itr_setting || adapter->rx_itr_setting > 3)
+ q_vector->itr_val = adapter->rx_itr_setting;
+ } else {
+ /* tx only vector */
+ if (!adapter->tx_itr_setting || adapter->tx_itr_setting > 3)
+ q_vector->itr_val = adapter->tx_itr_setting;
+ }
+
if (txr_count) {
/* assign generic ring traits */
ring->dev = &adapter->pdev->dev;
@@ -1221,9 +1244,9 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
/*
- * On i350, i210, and i211, loopback VLAN packets
+ * On i350, i354, i210, and i211, loopback VLAN packets
* have the tag byte-swapped.
- * */
+ */
if (adapter->hw.mac.type >= e1000_i350)
set_bit(IGB_RING_FLAG_RX_LB_VLAN_BSWAP, &ring->flags);
@@ -1240,11 +1263,11 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter,
/**
- * igb_alloc_q_vectors - Allocate memory for interrupt vectors
- * @adapter: board private structure to initialize
+ * igb_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @adapter: board private structure to initialize
*
- * We allocate one q_vector per queue interrupt. If allocation fails we
- * return -ENOMEM.
+ * We allocate one q_vector per queue interrupt. If allocation fails we
+ * return -ENOMEM.
**/
static int igb_alloc_q_vectors(struct igb_adapter *adapter)
{
@@ -1298,9 +1321,11 @@ err_out:
}
/**
- * igb_init_interrupt_scheme - initialize interrupts, allocate queues/vectors
+ * igb_init_interrupt_scheme - initialize interrupts, allocate queues/vectors
+ * @adapter: board private structure to initialize
+ * @msix: boolean value of MSIX capability
*
- * This function initializes the interrupts and allocates all of the queues.
+ * This function initializes the interrupts and allocates all of the queues.
**/
static int igb_init_interrupt_scheme(struct igb_adapter *adapter, bool msix)
{
@@ -1325,10 +1350,11 @@ err_alloc_q_vectors:
}
/**
- * igb_request_irq - initialize interrupts
+ * igb_request_irq - initialize interrupts
+ * @adapter: board private structure to initialize
*
- * Attempts to configure interrupts using the best available
- * capabilities of the hardware and kernel.
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
**/
static int igb_request_irq(struct igb_adapter *adapter)
{
@@ -1394,15 +1420,14 @@ static void igb_free_irq(struct igb_adapter *adapter)
}
/**
- * igb_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
+ * igb_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
**/
static void igb_irq_disable(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- /*
- * we need to be careful when disabling interrupts. The VFs are also
+ /* we need to be careful when disabling interrupts. The VFs are also
* mapped into these registers and so clearing the bits can cause
* issues on the VF drivers so we only need to clear what we set
*/
@@ -1427,8 +1452,8 @@ static void igb_irq_disable(struct igb_adapter *adapter)
}
/**
- * igb_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
+ * igb_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
**/
static void igb_irq_enable(struct igb_adapter *adapter)
{
@@ -1477,13 +1502,12 @@ static void igb_update_mng_vlan(struct igb_adapter *adapter)
}
/**
- * igb_release_hw_control - release control of the h/w to f/w
- * @adapter: address of board private structure
- *
- * igb_release_hw_control resets CTRL_EXT:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that the
- * driver is no longer loaded.
+ * igb_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
*
+ * igb_release_hw_control resets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded.
**/
static void igb_release_hw_control(struct igb_adapter *adapter)
{
@@ -1497,13 +1521,12 @@ static void igb_release_hw_control(struct igb_adapter *adapter)
}
/**
- * igb_get_hw_control - get control of the h/w from f/w
- * @adapter: address of board private structure
- *
- * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
- * For ASF and Pass Through versions of f/w this means that
- * the driver is loaded.
+ * igb_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
*
+ * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded.
**/
static void igb_get_hw_control(struct igb_adapter *adapter)
{
@@ -1517,8 +1540,8 @@ static void igb_get_hw_control(struct igb_adapter *adapter)
}
/**
- * igb_configure - configure the hardware for RX and TX
- * @adapter: private board structure
+ * igb_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
**/
static void igb_configure(struct igb_adapter *adapter)
{
@@ -1541,7 +1564,8 @@ static void igb_configure(struct igb_adapter *adapter)
/* call igb_desc_unused which always leaves
* at least 1 descriptor unused to make sure
- * next_to_use != next_to_clean */
+ * next_to_use != next_to_clean
+ */
for (i = 0; i < adapter->num_rx_queues; i++) {
struct igb_ring *ring = adapter->rx_ring[i];
igb_alloc_rx_buffers(ring, igb_desc_unused(ring));
@@ -1549,8 +1573,8 @@ static void igb_configure(struct igb_adapter *adapter)
}
/**
- * igb_power_up_link - Power up the phy/serdes link
- * @adapter: address of board private structure
+ * igb_power_up_link - Power up the phy/serdes link
+ * @adapter: address of board private structure
**/
void igb_power_up_link(struct igb_adapter *adapter)
{
@@ -1563,8 +1587,8 @@ void igb_power_up_link(struct igb_adapter *adapter)
}
/**
- * igb_power_down_link - Power down the phy/serdes link
- * @adapter: address of board private structure
+ * igb_power_down_link - Power down the phy/serdes link
+ * @adapter: address of board private structure
*/
static void igb_power_down_link(struct igb_adapter *adapter)
{
@@ -1575,8 +1599,8 @@ static void igb_power_down_link(struct igb_adapter *adapter)
}
/**
- * igb_up - Open the interface and prepare it to handle traffic
- * @adapter: board private structure
+ * igb_up - Open the interface and prepare it to handle traffic
+ * @adapter: board private structure
**/
int igb_up(struct igb_adapter *adapter)
{
@@ -1624,7 +1648,8 @@ void igb_down(struct igb_adapter *adapter)
int i;
/* signal that we're down so the interrupt handler does not
- * reschedule our watchdog timer */
+ * reschedule our watchdog timer
+ */
set_bit(__IGB_DOWN, &adapter->state);
/* disable receives in the hardware */
@@ -1694,6 +1719,7 @@ void igb_reset(struct igb_adapter *adapter)
*/
switch (mac->type) {
case e1000_i350:
+ case e1000_i354:
case e1000_82580:
pba = rd32(E1000_RXPBS);
pba = igb_rxpbs_adjust_82580(pba);
@@ -1720,14 +1746,16 @@ void igb_reset(struct igb_adapter *adapter)
* rounded up to the next 1KB and expressed in KB. Likewise,
* the Rx FIFO should be large enough to accommodate at least
* one full receive packet and is similarly rounded up and
- * expressed in KB. */
+ * expressed in KB.
+ */
pba = rd32(E1000_PBA);
/* upper 16 bits has Tx packet buffer allocation size in KB */
tx_space = pba >> 16;
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
- /* the tx fifo also stores 16 bytes of information about the tx
- * but don't include ethernet FCS because hardware appends it */
+ /* the Tx fifo also stores 16 bytes of information about the Tx
+ * but don't include ethernet FCS because hardware appends it
+ */
min_tx_space = (adapter->max_frame_size +
sizeof(union e1000_adv_tx_desc) -
ETH_FCS_LEN) * 2;
@@ -1740,13 +1768,15 @@ void igb_reset(struct igb_adapter *adapter)
/* If current Tx allocation is less than the min Tx FIFO size,
* and the min Tx FIFO size is less than the current Rx FIFO
- * allocation, take space away from current Rx allocation */
+ * allocation, take space away from current Rx allocation
+ */
if (tx_space < min_tx_space &&
((min_tx_space - tx_space) < pba)) {
pba = pba - (min_tx_space - tx_space);
- /* if short on rx space, rx wins and must trump tx
- * adjustment */
+ /* if short on Rx space, Rx wins and must trump Tx
+ * adjustment
+ */
if (pba < min_rx_space)
pba = min_rx_space;
}
@@ -1758,7 +1788,8 @@ void igb_reset(struct igb_adapter *adapter)
* (or the size used for early receive) above it in the Rx FIFO.
* Set it to the lower of:
* - 90% of the Rx FIFO size, or
- * - the full Rx FIFO size minus one full frame */
+ * - the full Rx FIFO size minus one full frame
+ */
hwm = min(((pba << 10) * 9 / 10),
((pba << 10) - 2 * adapter->max_frame_size));
@@ -1789,8 +1820,7 @@ void igb_reset(struct igb_adapter *adapter)
if (hw->mac.ops.init_hw(hw))
dev_err(&pdev->dev, "Hardware Error\n");
- /*
- * Flow control settings reset on hardware reset, so guarantee flow
+ /* Flow control settings reset on hardware reset, so guarantee flow
* control is off when forcing speed.
*/
if (!hw->mac.autoneg)
@@ -1826,14 +1856,13 @@ void igb_reset(struct igb_adapter *adapter)
static netdev_features_t igb_fix_features(struct net_device *netdev,
netdev_features_t features)
{
- /*
- * Since there is no support for separate rx/tx vlan accel
- * enable/disable make sure tx flag is always in same state as rx.
+ /* Since there is no support for separate Rx/Tx vlan accel
+ * enable/disable make sure Tx flag is always in same state as Rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -1844,7 +1873,7 @@ static int igb_set_features(struct net_device *netdev,
netdev_features_t changed = netdev->features ^ features;
struct igb_adapter *adapter = netdev_priv(netdev);
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
igb_vlan_mode(netdev, features);
if (!(changed & NETIF_F_RXALL))
@@ -1876,6 +1905,7 @@ static const struct net_device_ops igb_netdev_ops = {
.ndo_set_vf_mac = igb_ndo_set_vf_mac,
.ndo_set_vf_vlan = igb_ndo_set_vf_vlan,
.ndo_set_vf_tx_rate = igb_ndo_set_vf_bw,
+ .ndo_set_vf_spoofchk = igb_ndo_set_vf_spoofchk,
.ndo_get_vf_config = igb_ndo_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = igb_netpoll,
@@ -1887,7 +1917,6 @@ static const struct net_device_ops igb_netdev_ops = {
/**
* igb_set_fw_version - Configure version string for ethtool
* @adapter: adapter struct
- *
**/
void igb_set_fw_version(struct igb_adapter *adapter)
{
@@ -1923,10 +1952,10 @@ void igb_set_fw_version(struct igb_adapter *adapter)
return;
}
-/* igb_init_i2c - Init I2C interface
+/**
+ * igb_init_i2c - Init I2C interface
* @adapter: pointer to adapter structure
- *
- */
+ **/
static s32 igb_init_i2c(struct igb_adapter *adapter)
{
s32 status = E1000_SUCCESS;
@@ -1951,15 +1980,15 @@ static s32 igb_init_i2c(struct igb_adapter *adapter)
}
/**
- * igb_probe - Device Initialization Routine
- * @pdev: PCI device information struct
- * @ent: entry in igb_pci_tbl
+ * igb_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in igb_pci_tbl
*
- * Returns 0 on success, negative on failure
+ * Returns 0 on success, negative on failure
*
- * igb_probe initializes an adapter identified by a pci_dev structure.
- * The OS initialization, configuring of the adapter private structure,
- * and a hardware reset occur.
+ * igb_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
**/
static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1996,18 +2025,19 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} else {
err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
- err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ err = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(32));
if (err) {
- dev_err(&pdev->dev, "No usable DMA "
- "configuration, aborting\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting\n");
goto err_dma;
}
}
}
err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
- IORESOURCE_MEM),
- igb_driver_name);
+ IORESOURCE_MEM),
+ igb_driver_name);
if (err)
goto err_pci_reg;
@@ -2085,8 +2115,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev,
"PHY reset is blocked due to SOL/IDER session.\n");
- /*
- * features is initialized to 0 in allocation, it might have bits
+ /* features is initialized to 0 in allocation, it might have bits
* set by igb_sw_init so we should use an or instead of an
* assignment.
*/
@@ -2097,15 +2126,15 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_TSO6 |
NETIF_F_RXHASH |
NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_TX;
/* copy netdev features into list of user selectable features */
netdev->hw_features |= netdev->features;
netdev->hw_features |= NETIF_F_RXALL;
/* set this bit last since it cannot be part of hw_features */
- netdev->features |= NETIF_F_HW_VLAN_FILTER;
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
netdev->vlan_features |= NETIF_F_TSO |
NETIF_F_TSO6 |
@@ -2130,11 +2159,11 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->en_mng_pt = igb_enable_mng_pass_thru(hw);
/* before reading the NVM, reset the controller to put the device in a
- * known good starting state */
+ * known good starting state
+ */
hw->mac.ops.reset_hw(hw);
- /*
- * make sure the NVM is good , i211 parts have special NVM that
+ /* make sure the NVM is good , i211 parts have special NVM that
* doesn't contain a checksum
*/
if (hw->mac.type != e1000_i211) {
@@ -2161,9 +2190,9 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
igb_set_fw_version(adapter);
setup_timer(&adapter->watchdog_timer, igb_watchdog,
- (unsigned long) adapter);
+ (unsigned long) adapter);
setup_timer(&adapter->phy_info_timer, igb_update_phy_info,
- (unsigned long) adapter);
+ (unsigned long) adapter);
INIT_WORK(&adapter->reset_task, igb_reset_task);
INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
@@ -2185,8 +2214,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Check the NVM for wake support on non-port A ports */
if (hw->mac.type >= e1000_82580)
hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
- NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
- &eeprom_data);
+ NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
+ &eeprom_data);
else if (hw->bus.func == 1)
hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
@@ -2195,7 +2224,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* now that we have the eeprom settings, apply the special cases where
* the eeprom may be wrong or the board simply won't support wake on
- * lan on a particular port */
+ * lan on a particular port
+ */
switch (pdev->device) {
case E1000_DEV_ID_82575GB_QUAD_COPPER:
adapter->flags &= ~IGB_FLAG_WOL_SUPPORTED;
@@ -2204,7 +2234,8 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
/* Wake events only supported on port A for dual fiber
- * regardless of eeprom setting */
+ * regardless of eeprom setting
+ */
if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1)
adapter->flags &= ~IGB_FLAG_WOL_SUPPORTED;
break;
@@ -2274,8 +2305,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (hw->mac.type == e1000_i350 && hw->bus.func == 0) {
u16 ets_word;
- /*
- * Read the NVM to determine if this i350 device supports an
+ /* Read the NVM to determine if this i350 device supports an
* external thermal sensor.
*/
hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_word);
@@ -2294,17 +2324,20 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
igb_ptp_init(adapter);
dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
- /* print bus type/speed/width info */
- dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
- netdev->name,
- ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" :
- (hw->bus.speed == e1000_bus_speed_5000) ? "5.0Gb/s" :
- "unknown"),
- ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
- (hw->bus.width == e1000_bus_width_pcie_x2) ? "Width x2" :
- (hw->bus.width == e1000_bus_width_pcie_x1) ? "Width x1" :
- "unknown"),
- netdev->dev_addr);
+ /* print bus type/speed/width info, not applicable to i354 */
+ if (hw->mac.type != e1000_i354) {
+ dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
+ netdev->name,
+ ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" :
+ (hw->bus.speed == e1000_bus_speed_5000) ? "5.0Gb/s" :
+ "unknown"),
+ ((hw->bus.width == e1000_bus_width_pcie_x4) ?
+ "Width x4" :
+ (hw->bus.width == e1000_bus_width_pcie_x2) ?
+ "Width x2" :
+ (hw->bus.width == e1000_bus_width_pcie_x1) ?
+ "Width x1" : "unknown"), netdev->dev_addr);
+ }
ret_val = igb_read_part_string(hw, part_str, E1000_PBANUM_LENGTH);
if (ret_val)
@@ -2321,6 +2354,13 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case e1000_i211:
igb_set_eee_i350(hw);
break;
+ case e1000_i354:
+ if (hw->phy.media_type == e1000_media_type_copper) {
+ if ((rd32(E1000_CTRL_EXT) &
+ E1000_CTRL_EXT_LINK_MODE_SGMII))
+ igb_set_eee_i354(hw);
+ }
+ break;
default:
break;
}
@@ -2344,7 +2384,7 @@ err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_selected_regions(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM));
+ pci_select_bars(pdev, IORESOURCE_MEM));
err_pci_reg:
err_dma:
pci_disable_device(pdev);
@@ -2361,7 +2401,7 @@ static int igb_disable_sriov(struct pci_dev *pdev)
/* reclaim resources allocated to VFs */
if (adapter->vf_data) {
/* disable iov and allow time for transactions to clear */
- if (igb_vfs_are_assigned(adapter)) {
+ if (pci_vfs_assigned(pdev)) {
dev_warn(&pdev->dev,
"Cannot deallocate SR-IOV virtual functions while they are assigned - VFs will not be deallocated\n");
return -EPERM;
@@ -2444,26 +2484,24 @@ out:
}
#endif
-/*
+/**
* igb_remove_i2c - Cleanup I2C interface
* @adapter: pointer to adapter structure
- *
- */
+ **/
static void igb_remove_i2c(struct igb_adapter *adapter)
{
-
/* free the adapter bus structure */
i2c_del_adapter(&adapter->i2c_adap);
}
/**
- * igb_remove - Device Removal Routine
- * @pdev: PCI device information struct
+ * igb_remove - Device Removal Routine
+ * @pdev: PCI device information struct
*
- * igb_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device. The could be caused by a
- * Hot-Plug event, or because the driver is going to be removed from
- * memory.
+ * igb_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
**/
static void igb_remove(struct pci_dev *pdev)
{
@@ -2477,8 +2515,7 @@ static void igb_remove(struct pci_dev *pdev)
#endif
igb_remove_i2c(adapter);
igb_ptp_stop(adapter);
- /*
- * The watchdog timer may be rescheduled, so explicitly
+ /* The watchdog timer may be rescheduled, so explicitly
* disable watchdog from being rescheduled.
*/
set_bit(__IGB_DOWN, &adapter->state);
@@ -2498,7 +2535,8 @@ static void igb_remove(struct pci_dev *pdev)
#endif
/* Release control of h/w to f/w. If f/w is AMT enabled, this
- * would have already happened in close and is redundant. */
+ * would have already happened in close and is redundant.
+ */
igb_release_hw_control(adapter);
unregister_netdev(netdev);
@@ -2513,7 +2551,7 @@ static void igb_remove(struct pci_dev *pdev)
if (hw->flash_address)
iounmap(hw->flash_address);
pci_release_selected_regions(pdev,
- pci_select_bars(pdev, IORESOURCE_MEM));
+ pci_select_bars(pdev, IORESOURCE_MEM));
kfree(adapter->shadow_vfta);
free_netdev(netdev);
@@ -2524,13 +2562,13 @@ static void igb_remove(struct pci_dev *pdev)
}
/**
- * igb_probe_vfs - Initialize vf data storage and add VFs to pci config space
- * @adapter: board private structure to initialize
+ * igb_probe_vfs - Initialize vf data storage and add VFs to pci config space
+ * @adapter: board private structure to initialize
*
- * This function initializes the vf specific data storage and then attempts to
- * allocate the VFs. The reason for ordering it this way is because it is much
- * mor expensive time wise to disable SR-IOV than it is to allocate and free
- * the memory for the VFs.
+ * This function initializes the vf specific data storage and then attempts to
+ * allocate the VFs. The reason for ordering it this way is because it is much
+ * mor expensive time wise to disable SR-IOV than it is to allocate and free
+ * the memory for the VFs.
**/
static void igb_probe_vfs(struct igb_adapter *adapter)
{
@@ -2576,6 +2614,7 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
}
/* fall through */
case e1000_82580:
+ case e1000_i354:
default:
max_rss_queues = IGB_MAX_RX_QUEUES;
break;
@@ -2590,8 +2629,7 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
/* Device supports enough interrupts without queue pairing. */
break;
case e1000_82576:
- /*
- * If VFs are going to be allocated with RSS queues then we
+ /* If VFs are going to be allocated with RSS queues then we
* should pair the queues in order to conserve interrupts due
* to limited supply.
*/
@@ -2601,10 +2639,10 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
/* fall through */
case e1000_82580:
case e1000_i350:
+ case e1000_i354:
case e1000_i210:
default:
- /*
- * If rss_queues > half of max_rss_queues, pair the queues in
+ /* If rss_queues > half of max_rss_queues, pair the queues in
* order to conserve interrupts due to limited supply.
*/
if (adapter->rss_queues > (max_rss_queues / 2))
@@ -2614,12 +2652,12 @@ static void igb_init_queue_configuration(struct igb_adapter *adapter)
}
/**
- * igb_sw_init - Initialize general software structures (struct igb_adapter)
- * @adapter: board private structure to initialize
+ * igb_sw_init - Initialize general software structures (struct igb_adapter)
+ * @adapter: board private structure to initialize
*
- * igb_sw_init initializes the Adapter private data structure.
- * Fields are initialized based on PCI device information and
- * OS network device settings (MTU size).
+ * igb_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
**/
static int igb_sw_init(struct igb_adapter *adapter)
{
@@ -2689,16 +2727,16 @@ static int igb_sw_init(struct igb_adapter *adapter)
}
/**
- * igb_open - Called when a network interface is made active
- * @netdev: network interface device structure
+ * igb_open - Called when a network interface is made active
+ * @netdev: network interface device structure
*
- * Returns 0 on success, negative value on failure
+ * Returns 0 on success, negative value on failure
*
- * The open entry point is called when a network interface is made
- * active by the system (IFF_UP). At this point all resources needed
- * for transmit and receive operations are allocated, the interrupt
- * handler is registered with the OS, the watchdog timer is started,
- * and the stack is notified that the interface is ready.
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
**/
static int __igb_open(struct net_device *netdev, bool resuming)
{
@@ -2734,7 +2772,8 @@ static int __igb_open(struct net_device *netdev, bool resuming)
/* before we allocate an interrupt, we must be ready to handle it.
* Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
* as soon as we call pci_request_irq, so we have to setup our
- * clean_rx handler before we do so. */
+ * clean_rx handler before we do so.
+ */
igb_configure(adapter);
err = igb_request_irq(adapter);
@@ -2803,15 +2842,15 @@ static int igb_open(struct net_device *netdev)
}
/**
- * igb_close - Disables a network interface
- * @netdev: network interface device structure
+ * igb_close - Disables a network interface
+ * @netdev: network interface device structure
*
- * Returns 0, this is not allowed to fail
+ * Returns 0, this is not allowed to fail
*
- * The close entry point is called when an interface is de-activated
- * by the OS. The hardware is still under the driver's control, but
- * needs to be disabled. A global MAC reset is issued to stop the
- * hardware, and all transmit and receive resources are freed.
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the driver's control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
**/
static int __igb_close(struct net_device *netdev, bool suspending)
{
@@ -2840,10 +2879,10 @@ static int igb_close(struct net_device *netdev)
}
/**
- * igb_setup_tx_resources - allocate Tx resources (Descriptors)
- * @tx_ring: tx descriptor ring (for a specific queue) to setup
+ * igb_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @tx_ring: tx descriptor ring (for a specific queue) to setup
*
- * Return 0 on success, negative on failure
+ * Return 0 on success, negative on failure
**/
int igb_setup_tx_resources(struct igb_ring *tx_ring)
{
@@ -2878,11 +2917,11 @@ err:
}
/**
- * igb_setup_all_tx_resources - wrapper to allocate Tx resources
- * (Descriptors) for all queues
- * @adapter: board private structure
+ * igb_setup_all_tx_resources - wrapper to allocate Tx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
*
- * Return 0 on success, negative on failure
+ * Return 0 on success, negative on failure
**/
static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
{
@@ -2904,8 +2943,8 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter)
}
/**
- * igb_setup_tctl - configure the transmit control registers
- * @adapter: Board private structure
+ * igb_setup_tctl - configure the transmit control registers
+ * @adapter: Board private structure
**/
void igb_setup_tctl(struct igb_adapter *adapter)
{
@@ -2930,11 +2969,11 @@ void igb_setup_tctl(struct igb_adapter *adapter)
}
/**
- * igb_configure_tx_ring - Configure transmit ring after Reset
- * @adapter: board private structure
- * @ring: tx ring to configure
+ * igb_configure_tx_ring - Configure transmit ring after Reset
+ * @adapter: board private structure
+ * @ring: tx ring to configure
*
- * Configure a transmit ring after a reset.
+ * Configure a transmit ring after a reset.
**/
void igb_configure_tx_ring(struct igb_adapter *adapter,
struct igb_ring *ring)
@@ -2950,9 +2989,9 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
mdelay(10);
wr32(E1000_TDLEN(reg_idx),
- ring->count * sizeof(union e1000_adv_tx_desc));
+ ring->count * sizeof(union e1000_adv_tx_desc));
wr32(E1000_TDBAL(reg_idx),
- tdba & 0x00000000ffffffffULL);
+ tdba & 0x00000000ffffffffULL);
wr32(E1000_TDBAH(reg_idx), tdba >> 32);
ring->tail = hw->hw_addr + E1000_TDT(reg_idx);
@@ -2968,10 +3007,10 @@ void igb_configure_tx_ring(struct igb_adapter *adapter,
}
/**
- * igb_configure_tx - Configure transmit Unit after Reset
- * @adapter: board private structure
+ * igb_configure_tx - Configure transmit Unit after Reset
+ * @adapter: board private structure
*
- * Configure the Tx unit of the MAC after a reset.
+ * Configure the Tx unit of the MAC after a reset.
**/
static void igb_configure_tx(struct igb_adapter *adapter)
{
@@ -2982,10 +3021,10 @@ static void igb_configure_tx(struct igb_adapter *adapter)
}
/**
- * igb_setup_rx_resources - allocate Rx resources (Descriptors)
- * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ * igb_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @rx_ring: Rx descriptor ring (for a specific queue) to setup
*
- * Returns 0 on success, negative on failure
+ * Returns 0 on success, negative on failure
**/
int igb_setup_rx_resources(struct igb_ring *rx_ring)
{
@@ -3021,11 +3060,11 @@ err:
}
/**
- * igb_setup_all_rx_resources - wrapper to allocate Rx resources
- * (Descriptors) for all queues
- * @adapter: board private structure
+ * igb_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
*
- * Return 0 on success, negative on failure
+ * Return 0 on success, negative on failure
**/
static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
{
@@ -3047,8 +3086,8 @@ static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
}
/**
- * igb_setup_mrqc - configure the multiple receive queue control registers
- * @adapter: Board private structure
+ * igb_setup_mrqc - configure the multiple receive queue control registers
+ * @adapter: Board private structure
**/
static void igb_setup_mrqc(struct igb_adapter *adapter)
{
@@ -3081,8 +3120,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
break;
}
- /*
- * Populate the indirection table 4 entries at a time. To do this
+ /* Populate the indirection table 4 entries at a time. To do this
* we are generating the results for n and n+2 and then interleaving
* those with the results with n+1 and n+3.
*/
@@ -3098,8 +3136,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
wr32(E1000_RETA(j), reta);
}
- /*
- * Disable raw packet checksumming so that RSS hash is placed in
+ /* Disable raw packet checksumming so that RSS hash is placed in
* descriptor on writeback. No need to enable TCP/UDP/IP checksum
* offloads as they are enabled by default
*/
@@ -3129,7 +3166,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
/* If VMDq is enabled then we set the appropriate mode for that, else
* we default to RSS so that an RSS hash is calculated per packet even
- * if we are only using one queue */
+ * if we are only using one queue
+ */
if (adapter->vfs_allocated_count) {
if (hw->mac.type > e1000_82575) {
/* Set the default pool for the PF's first queue */
@@ -3154,8 +3192,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
}
/**
- * igb_setup_rctl - configure the receive control registers
- * @adapter: Board private structure
+ * igb_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
**/
void igb_setup_rctl(struct igb_adapter *adapter)
{
@@ -3170,8 +3208,7 @@ void igb_setup_rctl(struct igb_adapter *adapter)
rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF |
(hw->mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
- /*
- * enable stripping of CRC. It's unlikely this will break BMC
+ /* enable stripping of CRC. It's unlikely this will break BMC
* redirection as it did with e1000. Newer features require
* that the HW strips the CRC.
*/
@@ -3198,7 +3235,8 @@ void igb_setup_rctl(struct igb_adapter *adapter)
/* This is useful for sniffing bad packets. */
if (adapter->netdev->features & NETIF_F_RXALL) {
/* UPE and MPE will be handled by normal PROMISC logic
- * in e1000e_set_rx_mode */
+ * in e1000e_set_rx_mode
+ */
rctl |= (E1000_RCTL_SBP | /* Receive bad packets */
E1000_RCTL_BAM | /* RX All Bcast Pkts */
E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
@@ -3221,7 +3259,8 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
u32 vmolr;
/* if it isn't the PF check to see if VFs are enabled and
- * increase the size to support vlan tags */
+ * increase the size to support vlan tags
+ */
if (vfn < adapter->vfs_allocated_count &&
adapter->vf_data[vfn].vlans_enabled)
size += VLAN_TAG_SIZE;
@@ -3235,10 +3274,10 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
}
/**
- * igb_rlpml_set - set maximum receive packet size
- * @adapter: board private structure
+ * igb_rlpml_set - set maximum receive packet size
+ * @adapter: board private structure
*
- * Configure maximum receivable packet size.
+ * Configure maximum receivable packet size.
**/
static void igb_rlpml_set(struct igb_adapter *adapter)
{
@@ -3248,8 +3287,7 @@ static void igb_rlpml_set(struct igb_adapter *adapter)
if (pf_id) {
igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
- /*
- * If we're in VMDQ or SR-IOV mode, then set global RLPML
+ /* If we're in VMDQ or SR-IOV mode, then set global RLPML
* to our max jumbo frame size, in case we need to enable
* jumbo frames on one of the rings later.
* This will not pass over-length frames into the default
@@ -3267,17 +3305,16 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
struct e1000_hw *hw = &adapter->hw;
u32 vmolr;
- /*
- * This register exists only on 82576 and newer so if we are older then
+ /* This register exists only on 82576 and newer so if we are older then
* we should exit and do nothing
*/
if (hw->mac.type < e1000_82576)
return;
vmolr = rd32(E1000_VMOLR(vfn));
- vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
if (aupe)
- vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
+ vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
else
vmolr &= ~(E1000_VMOLR_AUPE); /* Tagged packets ONLY */
@@ -3286,25 +3323,24 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
if (adapter->rss_queues > 1 && vfn == adapter->vfs_allocated_count)
vmolr |= E1000_VMOLR_RSSE; /* enable RSS */
- /*
- * for VMDq only allow the VFs and pool 0 to accept broadcast and
+ /* for VMDq only allow the VFs and pool 0 to accept broadcast and
* multicast packets
*/
if (vfn <= adapter->vfs_allocated_count)
- vmolr |= E1000_VMOLR_BAM; /* Accept broadcast */
+ vmolr |= E1000_VMOLR_BAM; /* Accept broadcast */
wr32(E1000_VMOLR(vfn), vmolr);
}
/**
- * igb_configure_rx_ring - Configure a receive ring after Reset
- * @adapter: board private structure
- * @ring: receive ring to be configured
+ * igb_configure_rx_ring - Configure a receive ring after Reset
+ * @adapter: board private structure
+ * @ring: receive ring to be configured
*
- * Configure the Rx unit of the MAC after a reset.
+ * Configure the Rx unit of the MAC after a reset.
**/
void igb_configure_rx_ring(struct igb_adapter *adapter,
- struct igb_ring *ring)
+ struct igb_ring *ring)
{
struct e1000_hw *hw = &adapter->hw;
u64 rdba = ring->dma;
@@ -3319,7 +3355,7 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
rdba & 0x00000000ffffffffULL);
wr32(E1000_RDBAH(reg_idx), rdba >> 32);
wr32(E1000_RDLEN(reg_idx),
- ring->count * sizeof(union e1000_adv_rx_desc));
+ ring->count * sizeof(union e1000_adv_rx_desc));
/* initialize head and tail */
ring->tail = hw->hw_addr + E1000_RDT(reg_idx);
@@ -3350,25 +3386,11 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
wr32(E1000_RXDCTL(reg_idx), rxdctl);
}
-static void igb_set_rx_buffer_len(struct igb_adapter *adapter,
- struct igb_ring *rx_ring)
-{
-#define IGB_MAX_BUILD_SKB_SIZE \
- (SKB_WITH_OVERHEAD(IGB_RX_BUFSZ) - \
- (NET_SKB_PAD + NET_IP_ALIGN + IGB_TS_HDR_LEN))
-
- /* set build_skb flag */
- if (adapter->max_frame_size <= IGB_MAX_BUILD_SKB_SIZE)
- set_ring_build_skb_enabled(rx_ring);
- else
- clear_ring_build_skb_enabled(rx_ring);
-}
-
/**
- * igb_configure_rx - Configure receive Unit after Reset
- * @adapter: board private structure
+ * igb_configure_rx - Configure receive Unit after Reset
+ * @adapter: board private structure
*
- * Configure the Rx unit of the MAC after a reset.
+ * Configure the Rx unit of the MAC after a reset.
**/
static void igb_configure_rx(struct igb_adapter *adapter)
{
@@ -3379,22 +3401,20 @@ static void igb_configure_rx(struct igb_adapter *adapter)
/* set the correct pool for the PF default MAC address in entry 0 */
igb_rar_set_qsel(adapter, adapter->hw.mac.addr, 0,
- adapter->vfs_allocated_count);
+ adapter->vfs_allocated_count);
/* Setup the HW Rx Head and Tail Descriptor Pointers and
- * the Base and Length of the Rx Descriptor Ring */
- for (i = 0; i < adapter->num_rx_queues; i++) {
- struct igb_ring *rx_ring = adapter->rx_ring[i];
- igb_set_rx_buffer_len(adapter, rx_ring);
- igb_configure_rx_ring(adapter, rx_ring);
- }
+ * the Base and Length of the Rx Descriptor Ring
+ */
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ igb_configure_rx_ring(adapter, adapter->rx_ring[i]);
}
/**
- * igb_free_tx_resources - Free Tx Resources per Queue
- * @tx_ring: Tx descriptor ring for a specific queue
+ * igb_free_tx_resources - Free Tx Resources per Queue
+ * @tx_ring: Tx descriptor ring for a specific queue
*
- * Free all transmit software resources
+ * Free all transmit software resources
**/
void igb_free_tx_resources(struct igb_ring *tx_ring)
{
@@ -3414,10 +3434,10 @@ void igb_free_tx_resources(struct igb_ring *tx_ring)
}
/**
- * igb_free_all_tx_resources - Free Tx Resources for All Queues
- * @adapter: board private structure
+ * igb_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
*
- * Free all transmit software resources
+ * Free all transmit software resources
**/
static void igb_free_all_tx_resources(struct igb_adapter *adapter)
{
@@ -3450,8 +3470,8 @@ void igb_unmap_and_free_tx_resource(struct igb_ring *ring,
}
/**
- * igb_clean_tx_ring - Free Tx Buffers
- * @tx_ring: ring to be cleaned
+ * igb_clean_tx_ring - Free Tx Buffers
+ * @tx_ring: ring to be cleaned
**/
static void igb_clean_tx_ring(struct igb_ring *tx_ring)
{
@@ -3481,8 +3501,8 @@ static void igb_clean_tx_ring(struct igb_ring *tx_ring)
}
/**
- * igb_clean_all_tx_rings - Free Tx Buffers for all queues
- * @adapter: board private structure
+ * igb_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
**/
static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
{
@@ -3493,10 +3513,10 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter)
}
/**
- * igb_free_rx_resources - Free Rx Resources
- * @rx_ring: ring to clean the resources from
+ * igb_free_rx_resources - Free Rx Resources
+ * @rx_ring: ring to clean the resources from
*
- * Free all receive software resources
+ * Free all receive software resources
**/
void igb_free_rx_resources(struct igb_ring *rx_ring)
{
@@ -3516,10 +3536,10 @@ void igb_free_rx_resources(struct igb_ring *rx_ring)
}
/**
- * igb_free_all_rx_resources - Free Rx Resources for All Queues
- * @adapter: board private structure
+ * igb_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
*
- * Free all receive software resources
+ * Free all receive software resources
**/
static void igb_free_all_rx_resources(struct igb_adapter *adapter)
{
@@ -3530,8 +3550,8 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter)
}
/**
- * igb_clean_rx_ring - Free Rx Buffers per Queue
- * @rx_ring: ring to free buffers from
+ * igb_clean_rx_ring - Free Rx Buffers per Queue
+ * @rx_ring: ring to free buffers from
**/
static void igb_clean_rx_ring(struct igb_ring *rx_ring)
{
@@ -3573,8 +3593,8 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
}
/**
- * igb_clean_all_rx_rings - Free Rx Buffers for all queues
- * @adapter: board private structure
+ * igb_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
**/
static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
{
@@ -3585,11 +3605,11 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter)
}
/**
- * igb_set_mac - Change the Ethernet Address of the NIC
- * @netdev: network interface device structure
- * @p: pointer to an address structure
+ * igb_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
*
- * Returns 0 on success, negative on failure
+ * Returns 0 on success, negative on failure
**/
static int igb_set_mac(struct net_device *netdev, void *p)
{
@@ -3605,19 +3625,19 @@ static int igb_set_mac(struct net_device *netdev, void *p)
/* set the correct pool for the new PF MAC address in entry 0 */
igb_rar_set_qsel(adapter, hw->mac.addr, 0,
- adapter->vfs_allocated_count);
+ adapter->vfs_allocated_count);
return 0;
}
/**
- * igb_write_mc_addr_list - write multicast addresses to MTA
- * @netdev: network interface device structure
+ * igb_write_mc_addr_list - write multicast addresses to MTA
+ * @netdev: network interface device structure
*
- * Writes multicast address list to the MTA hash table.
- * Returns: -ENOMEM on failure
- * 0 on no addresses written
- * X on writing X addresses to MTA
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ * 0 on no addresses written
+ * X on writing X addresses to MTA
**/
static int igb_write_mc_addr_list(struct net_device *netdev)
{
@@ -3650,13 +3670,13 @@ static int igb_write_mc_addr_list(struct net_device *netdev)
}
/**
- * igb_write_uc_addr_list - write unicast addresses to RAR table
- * @netdev: network interface device structure
+ * igb_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
*
- * Writes unicast address list to the RAR table.
- * Returns: -ENOMEM on failure/insufficient address space
- * 0 on no addresses written
- * X on writing X addresses to the RAR table
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ * 0 on no addresses written
+ * X on writing X addresses to the RAR table
**/
static int igb_write_uc_addr_list(struct net_device *netdev)
{
@@ -3677,8 +3697,8 @@ static int igb_write_uc_addr_list(struct net_device *netdev)
if (!rar_entries)
break;
igb_rar_set_qsel(adapter, ha->addr,
- rar_entries--,
- vfn);
+ rar_entries--,
+ vfn);
count++;
}
}
@@ -3693,13 +3713,13 @@ static int igb_write_uc_addr_list(struct net_device *netdev)
}
/**
- * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
- * @netdev: network interface device structure
+ * igb_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
*
- * The set_rx_mode entry point is called whenever the unicast or multicast
- * address lists or the network interface flags are updated. This routine is
- * responsible for configuring the hardware for proper unicast, multicast,
- * promiscuous mode, and all-multi behavior.
+ * The set_rx_mode entry point is called whenever the unicast or multicast
+ * address lists or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
+ * promiscuous mode, and all-multi behavior.
**/
static void igb_set_rx_mode(struct net_device *netdev)
{
@@ -3716,6 +3736,10 @@ static void igb_set_rx_mode(struct net_device *netdev)
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
if (netdev->flags & IFF_PROMISC) {
+ u32 mrqc = rd32(E1000_MRQC);
+ /* retain VLAN HW filtering if in VT mode */
+ if (mrqc & E1000_MRQC_ENABLE_VMDQ)
+ rctl |= E1000_RCTL_VFE;
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
} else {
@@ -3723,8 +3747,7 @@ static void igb_set_rx_mode(struct net_device *netdev)
rctl |= E1000_RCTL_MPE;
vmolr |= E1000_VMOLR_MPME;
} else {
- /*
- * Write addresses to the MTA, if the attempt fails
+ /* Write addresses to the MTA, if the attempt fails
* then we should just turn on promiscuous mode so
* that we can at least receive multicast traffic
*/
@@ -3736,8 +3759,7 @@ static void igb_set_rx_mode(struct net_device *netdev)
vmolr |= E1000_VMOLR_ROMPE;
}
}
- /*
- * Write addresses to available RAR registers, if there is not
+ /* Write addresses to available RAR registers, if there is not
* sufficient space to store all the addresses then enable
* unicast promiscuous mode
*/
@@ -3750,8 +3772,7 @@ static void igb_set_rx_mode(struct net_device *netdev)
}
wr32(E1000_RCTL, rctl);
- /*
- * In order to support SR-IOV and eventually VMDq it is necessary to set
+ /* In order to support SR-IOV and eventually VMDq it is necessary to set
* the VMOLR to enable the appropriate modes. Without this workaround
* we will have issues with VLAN tag stripping not being done for frames
* that are only arriving because we are the default pool
@@ -3760,7 +3781,7 @@ static void igb_set_rx_mode(struct net_device *netdev)
return;
vmolr |= rd32(E1000_VMOLR(vfn)) &
- ~(E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_ROMPE);
+ ~(E1000_VMOLR_ROPE | E1000_VMOLR_MPME | E1000_VMOLR_ROMPE);
wr32(E1000_VMOLR(vfn), vmolr);
igb_restore_vf_multicasts(adapter);
}
@@ -3805,7 +3826,8 @@ static void igb_spoof_check(struct igb_adapter *adapter)
}
/* Need to wait a few seconds after link up to get diagnostic information from
- * the phy */
+ * the phy
+ */
static void igb_update_phy_info(unsigned long data)
{
struct igb_adapter *adapter = (struct igb_adapter *) data;
@@ -3813,8 +3835,8 @@ static void igb_update_phy_info(unsigned long data)
}
/**
- * igb_has_link - check shared code for link and determine up/down
- * @adapter: pointer to driver private info
+ * igb_has_link - check shared code for link and determine up/down
+ * @adapter: pointer to driver private info
**/
bool igb_has_link(struct igb_adapter *adapter)
{
@@ -3859,17 +3881,16 @@ static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event)
ctrl_ext = rd32(E1000_CTRL_EXT);
if ((hw->phy.media_type == e1000_media_type_copper) &&
- !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII)) {
+ !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII))
ret = !!(thstat & event);
- }
}
return ret;
}
/**
- * igb_watchdog - Timer Call-back
- * @data: pointer to adapter cast into an unsigned long
+ * igb_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
**/
static void igb_watchdog(unsigned long data)
{
@@ -3881,9 +3902,10 @@ static void igb_watchdog(unsigned long data)
static void igb_watchdog_task(struct work_struct *work)
{
struct igb_adapter *adapter = container_of(work,
- struct igb_adapter,
- watchdog_task);
+ struct igb_adapter,
+ watchdog_task);
struct e1000_hw *hw = &adapter->hw;
+ struct e1000_phy_info *phy = &hw->phy;
struct net_device *netdev = adapter->netdev;
u32 link;
int i;
@@ -3896,8 +3918,8 @@ static void igb_watchdog_task(struct work_struct *work)
if (!netif_carrier_ok(netdev)) {
u32 ctrl;
hw->mac.ops.get_speed_and_duplex(hw,
- &adapter->link_speed,
- &adapter->link_duplex);
+ &adapter->link_speed,
+ &adapter->link_duplex);
ctrl = rd32(E1000_CTRL);
/* Links status message must follow this format */
@@ -3912,6 +3934,11 @@ static void igb_watchdog_task(struct work_struct *work)
(ctrl & E1000_CTRL_RFCE) ? "RX" :
(ctrl & E1000_CTRL_TFCE) ? "TX" : "None");
+ /* check if SmartSpeed worked */
+ igb_check_downshift(hw);
+ if (phy->speed_downgraded)
+ netdev_warn(netdev, "Link Speed was downgraded by SmartSpeed\n");
+
/* check for thermal sensor event */
if (igb_thermal_sensor_event(hw,
E1000_THSTAT_LINK_THROTTLE)) {
@@ -3980,7 +4007,8 @@ static void igb_watchdog_task(struct work_struct *work)
/* We've lost link, so the controller stops DMA,
* but we've got queued Tx work that's never going
* to get done, so reset controller to flush Tx.
- * (Do the reset outside of interrupt context). */
+ * (Do the reset outside of interrupt context).
+ */
if (igb_desc_unused(tx_ring) + 1 < tx_ring->count) {
adapter->tx_timeout_count++;
schedule_work(&adapter->reset_task);
@@ -3993,7 +4021,7 @@ static void igb_watchdog_task(struct work_struct *work)
set_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
}
- /* Cause software interrupt to ensure rx ring is cleaned */
+ /* Cause software interrupt to ensure Rx ring is cleaned */
if (adapter->msix_entries) {
u32 eics = 0;
for (i = 0; i < adapter->num_q_vectors; i++)
@@ -4020,20 +4048,20 @@ enum latency_range {
};
/**
- * igb_update_ring_itr - update the dynamic ITR value based on packet size
+ * igb_update_ring_itr - update the dynamic ITR value based on packet size
+ * @q_vector: pointer to q_vector
*
- * Stores a new ITR value based on strictly on packet size. This
- * algorithm is less sophisticated than that used in igb_update_itr,
- * due to the difficulty of synchronizing statistics across multiple
- * receive rings. The divisors and thresholds used by this function
- * were determined based on theoretical maximum wire speed and testing
- * data, in order to minimize response time while increasing bulk
- * throughput.
- * This functionality is controlled by the InterruptThrottleRate module
- * parameter (see igb_param.c)
- * NOTE: This function is called only when operating in a multiqueue
- * receive environment.
- * @q_vector: pointer to q_vector
+ * Stores a new ITR value based on strictly on packet size. This
+ * algorithm is less sophisticated than that used in igb_update_itr,
+ * due to the difficulty of synchronizing statistics across multiple
+ * receive rings. The divisors and thresholds used by this function
+ * were determined based on theoretical maximum wire speed and testing
+ * data, in order to minimize response time while increasing bulk
+ * throughput.
+ * This functionality is controlled by the InterruptThrottleRate module
+ * parameter (see igb_param.c)
+ * NOTE: This function is called only when operating in a multiqueue
+ * receive environment.
**/
static void igb_update_ring_itr(struct igb_q_vector *q_vector)
{
@@ -4094,20 +4122,21 @@ clear_counts:
}
/**
- * igb_update_itr - update the dynamic ITR value based on statistics
- * Stores a new ITR value based on packets and byte
- * counts during the last interrupt. The advantage of per interrupt
- * computation is faster updates and more accurate ITR for the current
- * traffic pattern. Constants in this function were computed
- * based on theoretical maximum wire speed and thresholds were set based
- * on testing data as well as attempting to minimize response time
- * while increasing bulk throughput.
- * this functionality is controlled by the InterruptThrottleRate module
- * parameter (see igb_param.c)
- * NOTE: These calculations are only valid when operating in a single-
- * queue environment.
- * @q_vector: pointer to q_vector
- * @ring_container: ring info to update the itr for
+ * igb_update_itr - update the dynamic ITR value based on statistics
+ * @q_vector: pointer to q_vector
+ * @ring_container: ring info to update the itr for
+ *
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ * this functionality is controlled by the InterruptThrottleRate module
+ * parameter (see igb_param.c)
+ * NOTE: These calculations are only valid when operating in a single-
+ * queue environment.
**/
static void igb_update_itr(struct igb_q_vector *q_vector,
struct igb_ring_container *ring_container)
@@ -4205,12 +4234,12 @@ set_itr_now:
if (new_itr != q_vector->itr_val) {
/* this attempts to bias the interrupt rate towards Bulk
* by adding intermediate steps when interrupt rate is
- * increasing */
+ * increasing
+ */
new_itr = new_itr > q_vector->itr_val ?
- max((new_itr * q_vector->itr_val) /
- (new_itr + (q_vector->itr_val >> 2)),
- new_itr) :
- new_itr;
+ max((new_itr * q_vector->itr_val) /
+ (new_itr + (q_vector->itr_val >> 2)),
+ new_itr) : new_itr;
/* Don't write the value here; it resets the adapter's
* internal timer, and causes us to delay far longer than
* we should between interrupts. Instead, we write the ITR
@@ -4337,8 +4366,8 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
default:
if (unlikely(net_ratelimit())) {
dev_warn(tx_ring->dev,
- "partial checksum but proto=%x!\n",
- first->protocol);
+ "partial checksum but proto=%x!\n",
+ first->protocol);
}
break;
}
@@ -4361,8 +4390,8 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
default:
if (unlikely(net_ratelimit())) {
dev_warn(tx_ring->dev,
- "partial checksum but l4 proto=%x!\n",
- l4_hdr);
+ "partial checksum but l4 proto=%x!\n",
+ l4_hdr);
}
break;
}
@@ -4514,8 +4543,7 @@ static void igb_tx_map(struct igb_ring *tx_ring,
/* set the timestamp */
first->time_stamp = jiffies;
- /*
- * Force memory writes to complete before letting h/w know there
+ /* Force memory writes to complete before letting h/w know there
* are new descriptors to fetch. (Only applicable for weak-ordered
* memory model archs, such as IA-64).
*
@@ -4536,7 +4564,8 @@ static void igb_tx_map(struct igb_ring *tx_ring,
writel(i, tx_ring->tail);
/* we need this if more than one processor can write to our tail
- * at a time, it syncronizes IO on IA64/Altix systems */
+ * at a time, it synchronizes IO on IA64/Altix systems
+ */
mmiowb();
return;
@@ -4566,11 +4595,13 @@ static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
/* Herbert's original patch had:
* smp_mb__after_netif_stop_queue();
- * but since that doesn't exist yet, just open code it. */
+ * but since that doesn't exist yet, just open code it.
+ */
smp_mb();
/* We need to check again in a case another CPU has just
- * made room available. */
+ * made room available.
+ */
if (igb_desc_unused(tx_ring) < size)
return -EBUSY;
@@ -4594,7 +4625,6 @@ static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
struct igb_ring *tx_ring)
{
- struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
struct igb_tx_buffer *first;
int tso;
u32 tx_flags = 0;
@@ -4629,15 +4659,18 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
skb_tx_timestamp(skb);
- if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
- !(adapter->ptp_tx_skb))) {
- skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
- tx_flags |= IGB_TX_FLAGS_TSTAMP;
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
- adapter->ptp_tx_skb = skb_get(skb);
- adapter->ptp_tx_start = jiffies;
- if (adapter->hw.mac.type == e1000_82576)
- schedule_work(&adapter->ptp_tx_work);
+ if (!(adapter->ptp_tx_skb)) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ tx_flags |= IGB_TX_FLAGS_TSTAMP;
+
+ adapter->ptp_tx_skb = skb_get(skb);
+ adapter->ptp_tx_start = jiffies;
+ if (adapter->hw.mac.type == e1000_82576)
+ schedule_work(&adapter->ptp_tx_work);
+ }
}
if (vlan_tx_tag_present(skb)) {
@@ -4694,8 +4727,7 @@ static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- /*
- * The minimum packet size with TCTL.PSP set is 17 so pad the skb
+ /* The minimum packet size with TCTL.PSP set is 17 so pad the skb
* in order to meet this minimum size requirement.
*/
if (unlikely(skb->len < 17)) {
@@ -4709,8 +4741,8 @@ static netdev_tx_t igb_xmit_frame(struct sk_buff *skb,
}
/**
- * igb_tx_timeout - Respond to a Tx Hang
- * @netdev: network interface device structure
+ * igb_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
**/
static void igb_tx_timeout(struct net_device *netdev)
{
@@ -4739,13 +4771,12 @@ static void igb_reset_task(struct work_struct *work)
}
/**
- * igb_get_stats64 - Get System Network Statistics
- * @netdev: network interface device structure
- * @stats: rtnl_link_stats64 pointer
- *
+ * igb_get_stats64 - Get System Network Statistics
+ * @netdev: network interface device structure
+ * @stats: rtnl_link_stats64 pointer
**/
static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev,
- struct rtnl_link_stats64 *stats)
+ struct rtnl_link_stats64 *stats)
{
struct igb_adapter *adapter = netdev_priv(netdev);
@@ -4758,11 +4789,11 @@ static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev,
}
/**
- * igb_change_mtu - Change the Maximum Transfer Unit
- * @netdev: network interface device structure
- * @new_mtu: new value for maximum frame size
+ * igb_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
*
- * Returns 0 on success, negative on failure
+ * Returns 0 on success, negative on failure
**/
static int igb_change_mtu(struct net_device *netdev, int new_mtu)
{
@@ -4805,10 +4836,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
}
/**
- * igb_update_stats - Update the board statistics counters
- * @adapter: board private structure
+ * igb_update_stats - Update the board statistics counters
+ * @adapter: board private structure
**/
-
void igb_update_stats(struct igb_adapter *adapter,
struct rtnl_link_stats64 *net_stats)
{
@@ -4823,8 +4853,7 @@ void igb_update_stats(struct igb_adapter *adapter,
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
- /*
- * Prevent stats update while adapter is being reset, or if the pci
+ /* Prevent stats update while adapter is being reset, or if the pci
* connection is down.
*/
if (adapter->link_speed == 0)
@@ -4958,7 +4987,8 @@ void igb_update_stats(struct igb_adapter *adapter,
/* Rx Errors */
/* RLEC on some newer hardware can be incorrect so build
- * our own version based on RUC and ROC */
+ * our own version based on RUC and ROC
+ */
net_stats->rx_errors = adapter->stats.rxerrc +
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
@@ -5017,7 +5047,8 @@ static irqreturn_t igb_msix_other(int irq, void *data)
adapter->stats.doosync++;
/* The DMA Out of Sync is also indication of a spoof event
* in IOV mode. Check the Wrong VM Behavior register to
- * see if it is really a spoof event. */
+ * see if it is really a spoof event.
+ */
igb_check_wvbr(adapter);
}
@@ -5091,8 +5122,7 @@ static void igb_update_tx_dca(struct igb_adapter *adapter,
if (hw->mac.type != e1000_82575)
txctrl <<= E1000_DCA_TXCTRL_CPUID_SHIFT;
- /*
- * We can enable relaxed ordering for reads, but not writes when
+ /* We can enable relaxed ordering for reads, but not writes when
* DCA is enabled. This is due to a known issue in some chipsets
* which will cause the DCA tag to be cleared.
*/
@@ -5113,8 +5143,7 @@ static void igb_update_rx_dca(struct igb_adapter *adapter,
if (hw->mac.type != e1000_82575)
rxctrl <<= E1000_DCA_RXCTRL_CPUID_SHIFT;
- /*
- * We can enable relaxed ordering for reads, but not writes when
+ /* We can enable relaxed ordering for reads, but not writes when
* DCA is enabled. This is due to a known issue in some chipsets
* which will cause the DCA tag to be cleared.
*/
@@ -5183,7 +5212,8 @@ static int __igb_notify_dca(struct device *dev, void *data)
case DCA_PROVIDER_REMOVE:
if (adapter->flags & IGB_FLAG_DCA_ENABLED) {
/* without this a class_device is left
- * hanging around in the sysfs model */
+ * hanging around in the sysfs model
+ */
dca_remove_requester(dev);
dev_info(&pdev->dev, "DCA disabled\n");
adapter->flags &= ~IGB_FLAG_DCA_ENABLED;
@@ -5196,12 +5226,12 @@ static int __igb_notify_dca(struct device *dev, void *data)
}
static int igb_notify_dca(struct notifier_block *nb, unsigned long event,
- void *p)
+ void *p)
{
int ret_val;
ret_val = driver_for_each_device(&igb_driver.driver, NULL, &event,
- __igb_notify_dca);
+ __igb_notify_dca);
return ret_val ? NOTIFY_BAD : NOTIFY_DONE;
}
@@ -5215,40 +5245,10 @@ static int igb_vf_configure(struct igb_adapter *adapter, int vf)
eth_zero_addr(mac_addr);
igb_set_vf_mac(adapter, vf, mac_addr);
- return 0;
-}
-
-static bool igb_vfs_are_assigned(struct igb_adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- struct pci_dev *vfdev;
- int dev_id;
-
- switch (adapter->hw.mac.type) {
- case e1000_82576:
- dev_id = IGB_82576_VF_DEV_ID;
- break;
- case e1000_i350:
- dev_id = IGB_I350_VF_DEV_ID;
- break;
- default:
- return false;
- }
-
- /* loop through all the VFs to see if we own any that are assigned */
- vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
- while (vfdev) {
- /* if we don't own it we don't care */
- if (vfdev->is_virtfn && vfdev->physfn == pdev) {
- /* if it is assigned we cannot release it */
- if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
- return true;
- }
-
- vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, vfdev);
- }
+ /* By default spoof check is enabled for all VFs */
+ adapter->vf_data[vf].spoofchk_enabled = true;
- return false;
+ return 0;
}
#endif
@@ -5273,7 +5273,7 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
struct vf_data_storage *vf_data = &adapter->vf_data[vf];
vf_data->flags &= ~(IGB_VF_FLAG_UNI_PROMISC |
- IGB_VF_FLAG_MULTI_PROMISC);
+ IGB_VF_FLAG_MULTI_PROMISC);
vmolr &= ~(E1000_VMOLR_ROPE | E1000_VMOLR_ROMPE | E1000_VMOLR_MPME);
if (*msgbuf & E1000_VF_SET_PROMISC_MULTICAST) {
@@ -5281,8 +5281,7 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
vf_data->flags |= IGB_VF_FLAG_MULTI_PROMISC;
*msgbuf &= ~E1000_VF_SET_PROMISC_MULTICAST;
} else {
- /*
- * if we have hashes and we are clearing a multicast promisc
+ /* if we have hashes and we are clearing a multicast promisc
* flag we need to write the hashes to the MTA as this step
* was previously skipped
*/
@@ -5303,7 +5302,6 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
return -EINVAL;
return 0;
-
}
static int igb_set_vf_multicasts(struct igb_adapter *adapter,
@@ -5510,30 +5508,91 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev,
"Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
if (test_bit(__IGB_DOWN, &adapter->state)) {
dev_warn(&adapter->pdev->dev,
- "The VF VLAN has been set,"
- " but the PF device is not up.\n");
+ "The VF VLAN has been set, but the PF device is not up.\n");
dev_warn(&adapter->pdev->dev,
- "Bring the PF device up before"
- " attempting to use the VF device.\n");
+ "Bring the PF device up before attempting to use the VF device.\n");
}
} else {
igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
- false, vf);
+ false, vf);
igb_set_vmvir(adapter, vlan, vf);
igb_set_vmolr(adapter, vf, true);
adapter->vf_data[vf].pf_vlan = 0;
adapter->vf_data[vf].pf_qos = 0;
- }
+ }
out:
- return err;
+ return err;
+}
+
+static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ int i;
+ u32 reg;
+
+ /* Find the vlan filter for this id */
+ for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+ reg = rd32(E1000_VLVF(i));
+ if ((reg & E1000_VLVF_VLANID_ENABLE) &&
+ vid == (reg & E1000_VLVF_VLANID_MASK))
+ break;
+ }
+
+ if (i >= E1000_VLVF_ARRAY_SIZE)
+ i = -1;
+
+ return i;
}
static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
+ struct e1000_hw *hw = &adapter->hw;
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
+ int err = 0;
+
+ /* If in promiscuous mode we need to make sure the PF also has
+ * the VLAN filter set.
+ */
+ if (add && (adapter->netdev->flags & IFF_PROMISC))
+ err = igb_vlvf_set(adapter, vid, add,
+ adapter->vfs_allocated_count);
+ if (err)
+ goto out;
- return igb_vlvf_set(adapter, vid, add, vf);
+ err = igb_vlvf_set(adapter, vid, add, vf);
+
+ if (err)
+ goto out;
+
+ /* Go through all the checks to see if the VLAN filter should
+ * be wiped completely.
+ */
+ if (!add && (adapter->netdev->flags & IFF_PROMISC)) {
+ u32 vlvf, bits;
+
+ int regndx = igb_find_vlvf_entry(adapter, vid);
+ if (regndx < 0)
+ goto out;
+ /* See if any other pools are set for this VLAN filter
+ * entry other than the PF.
+ */
+ vlvf = bits = rd32(E1000_VLVF(regndx));
+ bits &= 1 << (E1000_VLVF_POOLSEL_SHIFT +
+ adapter->vfs_allocated_count);
+ /* If the filter was removed then ensure PF pool bit
+ * is cleared if the PF only added itself to the pool
+ * because the PF is in promiscuous mode.
+ */
+ if ((vlvf & VLAN_VID_MASK) == vid &&
+ !test_bit(vid, adapter->active_vlans) &&
+ !bits)
+ igb_vlvf_set(adapter, vid, add,
+ adapter->vfs_allocated_count);
+ }
+
+out:
+ return err;
}
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
@@ -5603,8 +5662,7 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
{
- /*
- * The VF MAC Address is stored in a packed array of bytes
+ /* The VF MAC Address is stored in a packed array of bytes
* starting at the second 32 bit word of the msg array
*/
unsigned char *addr = (char *)&msg[1];
@@ -5653,11 +5711,9 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
if (msgbuf[0] & (E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK))
return;
- /*
- * until the vf completes a reset it should not be
+ /* until the vf completes a reset it should not be
* allowed to start any configuration.
*/
-
if (msgbuf[0] == E1000_VF_RESET) {
igb_vf_reset_msg(adapter, vf);
return;
@@ -5677,9 +5733,8 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
else
dev_warn(&pdev->dev,
- "VF %d attempted to override administratively "
- "set MAC address\nReload the VF driver to "
- "resume operations\n", vf);
+ "VF %d attempted to override administratively set MAC address\nReload the VF driver to resume operations\n",
+ vf);
break;
case E1000_VF_SET_PROMISC:
retval = igb_set_vf_promisc(adapter, msgbuf, vf);
@@ -5694,9 +5749,8 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
retval = -1;
if (vf_data->pf_vlan)
dev_warn(&pdev->dev,
- "VF %d attempted to override administratively "
- "set VLAN tag\nReload the VF driver to "
- "resume operations\n", vf);
+ "VF %d attempted to override administratively set VLAN tag\nReload the VF driver to resume operations\n",
+ vf);
else
retval = igb_set_vf_vlan(adapter, msgbuf, vf);
break;
@@ -5765,9 +5819,9 @@ static void igb_set_uta(struct igb_adapter *adapter)
}
/**
- * igb_intr_msi - Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a network interface device structure
+ * igb_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
**/
static irqreturn_t igb_intr_msi(int irq, void *data)
{
@@ -5810,9 +5864,9 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
}
/**
- * igb_intr - Legacy Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a network interface device structure
+ * igb_intr - Legacy Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
**/
static irqreturn_t igb_intr(int irq, void *data)
{
@@ -5820,11 +5874,13 @@ static irqreturn_t igb_intr(int irq, void *data)
struct igb_q_vector *q_vector = adapter->q_vector[0];
struct e1000_hw *hw = &adapter->hw;
/* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No
- * need for the IMC write */
+ * need for the IMC write
+ */
u32 icr = rd32(E1000_ICR);
/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
- * not set, then the adapter didn't send an interrupt */
+ * not set, then the adapter didn't send an interrupt
+ */
if (!(icr & E1000_ICR_INT_ASSERTED))
return IRQ_NONE;
@@ -5883,15 +5939,15 @@ static void igb_ring_irq_enable(struct igb_q_vector *q_vector)
}
/**
- * igb_poll - NAPI Rx polling callback
- * @napi: napi polling structure
- * @budget: count of how many packets we should handle
+ * igb_poll - NAPI Rx polling callback
+ * @napi: napi polling structure
+ * @budget: count of how many packets we should handle
**/
static int igb_poll(struct napi_struct *napi, int budget)
{
struct igb_q_vector *q_vector = container_of(napi,
- struct igb_q_vector,
- napi);
+ struct igb_q_vector,
+ napi);
bool clean_complete = true;
#ifdef CONFIG_IGB_DCA
@@ -5916,10 +5972,10 @@ static int igb_poll(struct napi_struct *napi, int budget)
}
/**
- * igb_clean_tx_irq - Reclaim resources after transmit completes
- * @q_vector: pointer to q_vector containing needed info
+ * igb_clean_tx_irq - Reclaim resources after transmit completes
+ * @q_vector: pointer to q_vector containing needed info
*
- * returns true if ring is completely cleaned
+ * returns true if ring is completely cleaned
**/
static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
{
@@ -6025,7 +6081,8 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
struct e1000_hw *hw = &adapter->hw;
/* Detect a transmit hang in hardware, this serializes the
- * check with the clearing of time_stamp and movement of i */
+ * check with the clearing of time_stamp and movement of i
+ */
clear_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
if (tx_buffer->next_to_watch &&
time_after(jiffies, tx_buffer->time_stamp +
@@ -6064,8 +6121,8 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
if (unlikely(total_packets &&
- netif_carrier_ok(tx_ring->netdev) &&
- igb_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
+ netif_carrier_ok(tx_ring->netdev) &&
+ igb_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD)) {
/* Make sure that anybody stopping the queue after this
* sees the new next_to_clean.
*/
@@ -6086,11 +6143,11 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
}
/**
- * igb_reuse_rx_page - page flip buffer and store it back on the ring
- * @rx_ring: rx descriptor ring to store buffers on
- * @old_buff: donor buffer to have page reused
+ * igb_reuse_rx_page - page flip buffer and store it back on the ring
+ * @rx_ring: rx descriptor ring to store buffers on
+ * @old_buff: donor buffer to have page reused
*
- * Synchronizes page for reuse by the adapter
+ * Synchronizes page for reuse by the adapter
**/
static void igb_reuse_rx_page(struct igb_ring *rx_ring,
struct igb_rx_buffer *old_buff)
@@ -6150,19 +6207,19 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
}
/**
- * igb_add_rx_frag - Add contents of Rx buffer to sk_buff
- * @rx_ring: rx descriptor ring to transact packets on
- * @rx_buffer: buffer containing page to add
- * @rx_desc: descriptor containing length of buffer written by hardware
- * @skb: sk_buff to place the data into
+ * igb_add_rx_frag - Add contents of Rx buffer to sk_buff
+ * @rx_ring: rx descriptor ring to transact packets on
+ * @rx_buffer: buffer containing page to add
+ * @rx_desc: descriptor containing length of buffer written by hardware
+ * @skb: sk_buff to place the data into
*
- * This function will add the data contained in rx_buffer->page to the skb.
- * This is done either through a direct copy if the data in the buffer is
- * less than the skb header size, otherwise it will just attach the page as
- * a frag to the skb.
+ * This function will add the data contained in rx_buffer->page to the skb.
+ * This is done either through a direct copy if the data in the buffer is
+ * less than the skb header size, otherwise it will just attach the page as
+ * a frag to the skb.
*
- * The function will then update the page offset if necessary and return
- * true if the buffer can be reused by the adapter.
+ * The function will then update the page offset if necessary and return
+ * true if the buffer can be reused by the adapter.
**/
static bool igb_add_rx_frag(struct igb_ring *rx_ring,
struct igb_rx_buffer *rx_buffer,
@@ -6203,78 +6260,6 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,
return igb_can_reuse_rx_page(rx_buffer, page, truesize);
}
-static struct sk_buff *igb_build_rx_buffer(struct igb_ring *rx_ring,
- union e1000_adv_rx_desc *rx_desc)
-{
- struct igb_rx_buffer *rx_buffer;
- struct sk_buff *skb;
- struct page *page;
- void *page_addr;
- unsigned int size = le16_to_cpu(rx_desc->wb.upper.length);
-#if (PAGE_SIZE < 8192)
- unsigned int truesize = IGB_RX_BUFSZ;
-#else
- unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
- SKB_DATA_ALIGN(NET_SKB_PAD +
- NET_IP_ALIGN +
- size);
-#endif
-
- /* If we spanned a buffer we have a huge mess so test for it */
- BUG_ON(unlikely(!igb_test_staterr(rx_desc, E1000_RXD_STAT_EOP)));
-
- rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
- page = rx_buffer->page;
- prefetchw(page);
-
- page_addr = page_address(page) + rx_buffer->page_offset;
-
- /* prefetch first cache line of first page */
- prefetch(page_addr + NET_SKB_PAD + NET_IP_ALIGN);
-#if L1_CACHE_BYTES < 128
- prefetch(page_addr + L1_CACHE_BYTES + NET_SKB_PAD + NET_IP_ALIGN);
-#endif
-
- /* build an skb to around the page buffer */
- skb = build_skb(page_addr, truesize);
- if (unlikely(!skb)) {
- rx_ring->rx_stats.alloc_failed++;
- return NULL;
- }
-
- /* we are reusing so sync this buffer for CPU use */
- dma_sync_single_range_for_cpu(rx_ring->dev,
- rx_buffer->dma,
- rx_buffer->page_offset,
- IGB_RX_BUFSZ,
- DMA_FROM_DEVICE);
-
- /* update pointers within the skb to store the data */
- skb_reserve(skb, NET_IP_ALIGN + NET_SKB_PAD);
- __skb_put(skb, size);
-
- /* pull timestamp out of packet data */
- if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) {
- igb_ptp_rx_pktstamp(rx_ring->q_vector, skb->data, skb);
- __skb_pull(skb, IGB_TS_HDR_LEN);
- }
-
- if (igb_can_reuse_rx_page(rx_buffer, page, truesize)) {
- /* hand second half of page back to the ring */
- igb_reuse_rx_page(rx_ring, rx_buffer);
- } else {
- /* we are not reusing the buffer so unmap it */
- dma_unmap_page(rx_ring->dev, rx_buffer->dma,
- PAGE_SIZE, DMA_FROM_DEVICE);
- }
-
- /* clear contents of buffer_info */
- rx_buffer->dma = 0;
- rx_buffer->page = NULL;
-
- return skb;
-}
-
static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
@@ -6305,8 +6290,7 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
return NULL;
}
- /*
- * we will be copying header into skb->data in
+ /* we will be copying header into skb->data in
* pskb_may_pull so it is in our interest to prefetch
* it now to avoid a possible cache miss
*/
@@ -6354,8 +6338,7 @@ static inline void igb_rx_checksum(struct igb_ring *ring,
if (igb_test_staterr(rx_desc,
E1000_RXDEXT_STATERR_TCPE |
E1000_RXDEXT_STATERR_IPE)) {
- /*
- * work around errata with sctp packets where the TCPE aka
+ /* work around errata with sctp packets where the TCPE aka
* L4E bit is set incorrectly on 64 byte (60 byte w/o crc)
* packets, (aka let the stack check the crc32c)
*/
@@ -6386,15 +6369,15 @@ static inline void igb_rx_hash(struct igb_ring *ring,
}
/**
- * igb_is_non_eop - process handling of non-EOP buffers
- * @rx_ring: Rx ring being processed
- * @rx_desc: Rx descriptor for current buffer
- * @skb: current socket buffer containing buffer in progress
+ * igb_is_non_eop - process handling of non-EOP buffers
+ * @rx_ring: Rx ring being processed
+ * @rx_desc: Rx descriptor for current buffer
+ * @skb: current socket buffer containing buffer in progress
*
- * This function updates next to clean. If the buffer is an EOP buffer
- * this function exits returning false, otherwise it will place the
- * sk_buff in the next buffer to be chained and return true indicating
- * that this is in fact a non-EOP buffer.
+ * This function updates next to clean. If the buffer is an EOP buffer
+ * this function exits returning false, otherwise it will place the
+ * sk_buff in the next buffer to be chained and return true indicating
+ * that this is in fact a non-EOP buffer.
**/
static bool igb_is_non_eop(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc)
@@ -6414,15 +6397,15 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring,
}
/**
- * igb_get_headlen - determine size of header for LRO/GRO
- * @data: pointer to the start of the headers
- * @max_len: total length of section to find headers in
+ * igb_get_headlen - determine size of header for LRO/GRO
+ * @data: pointer to the start of the headers
+ * @max_len: total length of section to find headers in
*
- * This function is meant to determine the length of headers that will
- * be recognized by hardware for LRO, and GRO offloads. The main
- * motivation of doing this is to only perform one pull for IPv4 TCP
- * packets so that we can do basic things like calculating the gso_size
- * based on the average data per packet.
+ * This function is meant to determine the length of headers that will
+ * be recognized by hardware for LRO, and GRO offloads. The main
+ * motivation of doing this is to only perform one pull for IPv4 TCP
+ * packets so that we can do basic things like calculating the gso_size
+ * based on the average data per packet.
**/
static unsigned int igb_get_headlen(unsigned char *data,
unsigned int max_len)
@@ -6473,7 +6456,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
return hdr.network - data;
/* record next protocol if header is present */
- if (!hdr.ipv4->frag_off)
+ if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
nexthdr = hdr.ipv4->protocol;
} else if (protocol == __constant_htons(ETH_P_IPV6)) {
if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
@@ -6509,8 +6492,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
hdr.network += sizeof(struct udphdr);
}
- /*
- * If everything has gone correctly hdr.network should be the
+ /* If everything has gone correctly hdr.network should be the
* data section of the packet and will be the end of the header.
* If not then it probably represents the end of the last recognized
* header.
@@ -6522,17 +6504,17 @@ static unsigned int igb_get_headlen(unsigned char *data,
}
/**
- * igb_pull_tail - igb specific version of skb_pull_tail
- * @rx_ring: rx descriptor ring packet is being transacted on
- * @rx_desc: pointer to the EOP Rx descriptor
- * @skb: pointer to current skb being adjusted
+ * igb_pull_tail - igb specific version of skb_pull_tail
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being adjusted
*
- * This function is an igb specific version of __pskb_pull_tail. The
- * main difference between this version and the original function is that
- * this function can make several assumptions about the state of things
- * that allow for significant optimizations versus the standard function.
- * As a result we can do things like drop a frag and maintain an accurate
- * truesize for the skb.
+ * This function is an igb specific version of __pskb_pull_tail. The
+ * main difference between this version and the original function is that
+ * this function can make several assumptions about the state of things
+ * that allow for significant optimizations versus the standard function.
+ * As a result we can do things like drop a frag and maintain an accurate
+ * truesize for the skb.
*/
static void igb_pull_tail(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc,
@@ -6542,8 +6524,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
unsigned char *va;
unsigned int pull_len;
- /*
- * it is valid to use page_address instead of kmap since we are
+ /* it is valid to use page_address instead of kmap since we are
* working with pages allocated out of the lomem pool per
* alloc_page(GFP_ATOMIC)
*/
@@ -6563,8 +6544,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
va += IGB_TS_HDR_LEN;
}
- /*
- * we need the header to contain the greater of either ETH_HLEN or
+ /* we need the header to contain the greater of either ETH_HLEN or
* 60 bytes if the skb->len is less than 60 for skb_pad.
*/
pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
@@ -6580,24 +6560,23 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
}
/**
- * igb_cleanup_headers - Correct corrupted or empty headers
- * @rx_ring: rx descriptor ring packet is being transacted on
- * @rx_desc: pointer to the EOP Rx descriptor
- * @skb: pointer to current skb being fixed
+ * igb_cleanup_headers - Correct corrupted or empty headers
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being fixed
*
- * Address the case where we are pulling data in on pages only
- * and as such no data is present in the skb header.
+ * Address the case where we are pulling data in on pages only
+ * and as such no data is present in the skb header.
*
- * In addition if skb is not at least 60 bytes we need to pad it so that
- * it is large enough to qualify as a valid Ethernet frame.
+ * In addition if skb is not at least 60 bytes we need to pad it so that
+ * it is large enough to qualify as a valid Ethernet frame.
*
- * Returns true if an error was encountered and skb was freed.
+ * Returns true if an error was encountered and skb was freed.
**/
static bool igb_cleanup_headers(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
-
if (unlikely((igb_test_staterr(rx_desc,
E1000_RXDEXT_ERR_FRAME_ERR_MASK)))) {
struct net_device *netdev = rx_ring->netdev;
@@ -6624,14 +6603,14 @@ static bool igb_cleanup_headers(struct igb_ring *rx_ring,
}
/**
- * igb_process_skb_fields - Populate skb header fields from Rx descriptor
- * @rx_ring: rx descriptor ring packet is being transacted on
- * @rx_desc: pointer to the EOP Rx descriptor
- * @skb: pointer to current skb being populated
+ * igb_process_skb_fields - Populate skb header fields from Rx descriptor
+ * @rx_ring: rx descriptor ring packet is being transacted on
+ * @rx_desc: pointer to the EOP Rx descriptor
+ * @skb: pointer to current skb being populated
*
- * This function checks the ring, descriptor, and packet information in
- * order to populate the hash, checksum, VLAN, timestamp, protocol, and
- * other fields within the skb.
+ * This function checks the ring, descriptor, and packet information in
+ * order to populate the hash, checksum, VLAN, timestamp, protocol, and
+ * other fields within the skb.
**/
static void igb_process_skb_fields(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc,
@@ -6645,7 +6624,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring,
igb_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
- if ((dev->features & NETIF_F_HW_VLAN_RX) &&
+ if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
u16 vid;
if (igb_test_staterr(rx_desc, E1000_RXDEXT_STATERR_LB) &&
@@ -6654,7 +6633,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring,
else
vid = le16_to_cpu(rx_desc->wb.upper.vlan);
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
skb_record_rx_queue(skb, rx_ring->queue_index);
@@ -6690,10 +6669,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
rmb();
/* retrieve a buffer from the ring */
- if (ring_uses_build_skb(rx_ring))
- skb = igb_build_rx_buffer(rx_ring, rx_desc);
- else
- skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
+ skb = igb_fetch_rx_buffer(rx_ring, rx_desc, skb);
/* exit if we failed to retrieve a buffer */
if (!skb)
@@ -6762,8 +6738,7 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
/* map page for use */
dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
- /*
- * if mapping failed free memory back to system since
+ /* if mapping failed free memory back to system since
* there isn't much point in holding memory we can't use
*/
if (dma_mapping_error(rx_ring->dev, dma)) {
@@ -6780,17 +6755,9 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring,
return true;
}
-static inline unsigned int igb_rx_offset(struct igb_ring *rx_ring)
-{
- if (ring_uses_build_skb(rx_ring))
- return NET_SKB_PAD + NET_IP_ALIGN;
- else
- return 0;
-}
-
/**
- * igb_alloc_rx_buffers - Replace used receive buffers; packet split
- * @adapter: address of board private structure
+ * igb_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
**/
void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
{
@@ -6810,13 +6777,10 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
if (!igb_alloc_mapped_page(rx_ring, bi))
break;
- /*
- * Refresh the desc even if buffer_addrs didn't change
+ /* Refresh the desc even if buffer_addrs didn't change
* because each write-back erases this info.
*/
- rx_desc->read.pkt_addr = cpu_to_le64(bi->dma +
- bi->page_offset +
- igb_rx_offset(rx_ring));
+ rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
rx_desc++;
bi++;
@@ -6842,8 +6806,7 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
/* update next to alloc since we have filled the ring */
rx_ring->next_to_alloc = i;
- /*
- * Force memory writes to complete before letting h/w
+ /* Force memory writes to complete before letting h/w
* know there are new descriptors to fetch. (Only
* applicable for weak-ordered memory model archs,
* such as IA-64).
@@ -6928,7 +6891,7 @@ static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 ctrl, rctl;
- bool enable = !!(features & NETIF_F_HW_VLAN_RX);
+ bool enable = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
if (enable) {
/* enable VLAN tag insert/strip */
@@ -6950,7 +6913,8 @@ static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
igb_rlpml_set(adapter);
}
-static int igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int igb_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -6967,7 +6931,8 @@ static int igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return 0;
}
-static int igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int igb_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -6993,7 +6958,7 @@ static void igb_restore_vlan(struct igb_adapter *adapter)
igb_vlan_mode(adapter->netdev, adapter->netdev->features);
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- igb_vlan_rx_add_vid(adapter->netdev, vid);
+ igb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx)
@@ -7004,15 +6969,24 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx)
mac->autoneg = 0;
/* Make sure dplx is at most 1 bit and lsb of speed is not set
- * for the switch() below to work */
+ * for the switch() below to work
+ */
if ((spd & 1) || (dplx & ~1))
goto err_inval;
- /* Fiber NIC's only allow 1000 Gbps Full duplex */
- if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) &&
- spd != SPEED_1000 &&
- dplx != DUPLEX_FULL)
- goto err_inval;
+ /* Fiber NIC's only allow 1000 gbps Full duplex
+ * and 100Mbps Full duplex for 100baseFx sfp
+ */
+ if (adapter->hw.phy.media_type == e1000_media_type_internal_serdes) {
+ switch (spd + dplx) {
+ case SPEED_10 + DUPLEX_HALF:
+ case SPEED_10 + DUPLEX_FULL:
+ case SPEED_100 + DUPLEX_HALF:
+ goto err_inval;
+ default:
+ break;
+ }
+ }
switch (spd + dplx) {
case SPEED_10 + DUPLEX_HALF:
@@ -7111,7 +7085,8 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake,
igb_power_up_link(adapter);
/* Release control of h/w to f/w. If f/w is AMT enabled, this
- * would have already happened in close and is redundant. */
+ * would have already happened in close and is redundant.
+ */
igb_release_hw_control(adapter);
pci_disable_device(pdev);
@@ -7173,7 +7148,8 @@ static int igb_resume(struct device *dev)
igb_reset(adapter);
/* let the f/w know that the h/w is now under the control of the
- * driver. */
+ * driver.
+ */
igb_get_hw_control(adapter);
wr32(E1000_WUS, ~0);
@@ -7309,8 +7285,7 @@ static int igb_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-/*
- * Polling 'interrupt' - used by things like netconsole to send skbs
+/* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
* the interrupt routine is executing.
*/
@@ -7333,13 +7308,13 @@ static void igb_netpoll(struct net_device *netdev)
#endif /* CONFIG_NET_POLL_CONTROLLER */
/**
- * igb_io_error_detected - called when PCI error is detected
- * @pdev: Pointer to PCI device
- * @state: The current pci connection state
+ * igb_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
*
- * This function is called after a PCI bus error affecting
- * this device has been detected.
- */
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ **/
static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
@@ -7360,12 +7335,12 @@ static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
}
/**
- * igb_io_slot_reset - called after the pci bus has been reset.
- * @pdev: Pointer to PCI device
+ * igb_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
*
- * Restart the card from scratch, as if from a cold-boot. Implementation
- * resembles the first-half of the igb_resume routine.
- */
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the igb_resume routine.
+ **/
static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -7393,8 +7368,9 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
err = pci_cleanup_aer_uncorrect_error_status(pdev);
if (err) {
- dev_err(&pdev->dev, "pci_cleanup_aer_uncorrect_error_status "
- "failed 0x%0x\n", err);
+ dev_err(&pdev->dev,
+ "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+ err);
/* non-fatal, continue */
}
@@ -7402,12 +7378,12 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev)
}
/**
- * igb_io_resume - called when traffic can start flowing again.
- * @pdev: Pointer to PCI device
+ * igb_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
*
- * This callback is called when the error recovery driver tells us that
- * its OK to resume normal operation. Implementation resembles the
- * second-half of the igb_resume routine.
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the igb_resume routine.
*/
static void igb_io_resume(struct pci_dev *pdev)
{
@@ -7424,12 +7400,13 @@ static void igb_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
/* let the f/w know that the h/w is now under the control of the
- * driver. */
+ * driver.
+ */
igb_get_hw_control(adapter);
}
static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
- u8 qsel)
+ u8 qsel)
{
u32 rar_low, rar_high;
struct e1000_hw *hw = &adapter->hw;
@@ -7438,7 +7415,7 @@ static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
* from network order (big endian) to little endian
*/
rar_low = ((u32) addr[0] | ((u32) addr[1] << 8) |
- ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
/* Indicate to hardware the Address is Valid. */
@@ -7456,11 +7433,12 @@ static void igb_rar_set_qsel(struct igb_adapter *adapter, u8 *addr, u32 index,
}
static int igb_set_vf_mac(struct igb_adapter *adapter,
- int vf, unsigned char *mac_addr)
+ int vf, unsigned char *mac_addr)
{
struct e1000_hw *hw = &adapter->hw;
/* VF MAC addresses start at end of receive addresses and moves
- * torwards the first, as a result a collision should not be possible */
+ * towards the first, as a result a collision should not be possible
+ */
int rar_entry = hw->mac.rar_entry_count - (vf + 1);
memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
@@ -7477,13 +7455,13 @@ static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
return -EINVAL;
adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
- dev_info(&adapter->pdev->dev, "Reload the VF driver to make this"
- " change effective.");
+ dev_info(&adapter->pdev->dev,
+ "Reload the VF driver to make this change effective.");
if (test_bit(__IGB_DOWN, &adapter->state)) {
- dev_warn(&adapter->pdev->dev, "The VF MAC address has been set,"
- " but the PF device is not up.\n");
- dev_warn(&adapter->pdev->dev, "Bring the PF device up before"
- " attempting to use the VF device.\n");
+ dev_warn(&adapter->pdev->dev,
+ "The VF MAC address has been set, but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev,
+ "Bring the PF device up before attempting to use the VF device.\n");
}
return igb_set_vf_mac(adapter, vf, mac);
}
@@ -7510,19 +7488,19 @@ static void igb_set_vf_rate_limit(struct e1000_hw *hw, int vf, int tx_rate,
/* Calculate the rate factor values to set */
rf_int = link_speed / tx_rate;
rf_dec = (link_speed - (rf_int * tx_rate));
- rf_dec = (rf_dec * (1<<E1000_RTTBCNRC_RF_INT_SHIFT)) / tx_rate;
+ rf_dec = (rf_dec * (1 << E1000_RTTBCNRC_RF_INT_SHIFT)) /
+ tx_rate;
bcnrc_val = E1000_RTTBCNRC_RS_ENA;
- bcnrc_val |= ((rf_int<<E1000_RTTBCNRC_RF_INT_SHIFT) &
- E1000_RTTBCNRC_RF_INT_MASK);
+ bcnrc_val |= ((rf_int << E1000_RTTBCNRC_RF_INT_SHIFT) &
+ E1000_RTTBCNRC_RF_INT_MASK);
bcnrc_val |= (rf_dec & E1000_RTTBCNRC_RF_DEC_MASK);
} else {
bcnrc_val = 0;
}
wr32(E1000_RTTDQSEL, vf); /* vf X uses queue X */
- /*
- * Set global transmit compensation time to the MMW_SIZE in RTTBCNRM
+ /* Set global transmit compensation time to the MMW_SIZE in RTTBCNRM
* register. MMW_SIZE=0x014 if 9728-byte jumbo is supported.
*/
wr32(E1000_RTTBCNRM, 0x14);
@@ -7544,8 +7522,7 @@ static void igb_check_vf_rate_limit(struct igb_adapter *adapter)
reset_rate = true;
adapter->vf_rate_link_speed = 0;
dev_info(&adapter->pdev->dev,
- "Link speed has been changed. VF Transmit "
- "rate is disabled\n");
+ "Link speed has been changed. VF Transmit rate is disabled\n");
}
for (i = 0; i < adapter->vfs_allocated_count; i++) {
@@ -7553,8 +7530,8 @@ static void igb_check_vf_rate_limit(struct igb_adapter *adapter)
adapter->vf_data[i].tx_rate = 0;
igb_set_vf_rate_limit(&adapter->hw, i,
- adapter->vf_data[i].tx_rate,
- actual_link_speed);
+ adapter->vf_data[i].tx_rate,
+ actual_link_speed);
}
}
@@ -7580,6 +7557,33 @@ static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
return 0;
}
+static int igb_ndo_set_vf_spoofchk(struct net_device *netdev, int vf,
+ bool setting)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 reg_val, reg_offset;
+
+ if (!adapter->vfs_allocated_count)
+ return -EOPNOTSUPP;
+
+ if (vf >= adapter->vfs_allocated_count)
+ return -EINVAL;
+
+ reg_offset = (hw->mac.type == e1000_82576) ? E1000_DTXSWC : E1000_TXSWC;
+ reg_val = rd32(reg_offset);
+ if (setting)
+ reg_val |= ((1 << vf) |
+ (1 << (vf + E1000_DTXSWC_VLAN_SPOOF_SHIFT)));
+ else
+ reg_val &= ~((1 << vf) |
+ (1 << (vf + E1000_DTXSWC_VLAN_SPOOF_SHIFT)));
+ wr32(reg_offset, reg_val);
+
+ adapter->vf_data[vf].spoofchk_enabled = setting;
+ return E1000_SUCCESS;
+}
+
static int igb_ndo_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi)
{
@@ -7591,6 +7595,7 @@ static int igb_ndo_get_vf_config(struct net_device *netdev,
ivi->tx_rate = adapter->vf_data[vf].tx_rate;
ivi->vlan = adapter->vf_data[vf].pf_vlan;
ivi->qos = adapter->vf_data[vf].pf_qos;
+ ivi->spoofchk = adapter->vf_data[vf].spoofchk_enabled;
return 0;
}
@@ -7603,6 +7608,7 @@ static void igb_vmm_control(struct igb_adapter *adapter)
case e1000_82575:
case e1000_i210:
case e1000_i211:
+ case e1000_i354:
default:
/* replication is not supported for 82575 */
return;
@@ -7625,7 +7631,7 @@ static void igb_vmm_control(struct igb_adapter *adapter)
igb_vmdq_set_loopback_pf(hw, true);
igb_vmdq_set_replication_pf(hw, true);
igb_vmdq_set_anti_spoofing_pf(hw, true,
- adapter->vfs_allocated_count);
+ adapter->vfs_allocated_count);
} else {
igb_vmdq_set_loopback_pf(hw, false);
igb_vmdq_set_replication_pf(hw, false);
@@ -7645,8 +7651,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
/* force threshold to 0. */
wr32(E1000_DMCTXTH, 0);
- /*
- * DMA Coalescing high water mark needs to be greater
+ /* DMA Coalescing high water mark needs to be greater
* than the Rx threshold. Set hwm to PBA - max frame
* size in 16B units, capping it at PBA - 6KB.
*/
@@ -7659,8 +7664,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
& E1000_FCRTC_RTH_COAL_MASK);
wr32(E1000_FCRTC, reg);
- /*
- * Set the DMA Coalescing Rx threshold to PBA - 2 * max
+ /* Set the DMA Coalescing Rx threshold to PBA - 2 * max
* frame size, capping it at PBA - 10KB.
*/
dmac_thr = pba - adapter->max_frame_size / 512;
@@ -7678,11 +7682,12 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
reg |= (1000 >> 5);
/* Disable BMC-to-OS Watchdog Enable */
- reg &= ~E1000_DMACR_DC_BMC2OSW_EN;
+ if (hw->mac.type != e1000_i354)
+ reg &= ~E1000_DMACR_DC_BMC2OSW_EN;
+
wr32(E1000_DMACR, reg);
- /*
- * no lower threshold to disable
+ /* no lower threshold to disable
* coalescing(smart fifb)-UTRESH=0
*/
wr32(E1000_DMCRTRH, 0);
@@ -7691,15 +7696,13 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
wr32(E1000_DMCTLX, reg);
- /*
- * free space in tx packet buffer to wake from
+ /* free space in tx packet buffer to wake from
* DMA coal
*/
wr32(E1000_DMCTXTH, (IGB_MIN_TXPBSIZE -
(IGB_TX_BUF_4096 + adapter->max_frame_size)) >> 6);
- /*
- * make low power state decision controlled
+ /* make low power state decision controlled
* by DMA coal
*/
reg = rd32(E1000_PCIEMISC);
@@ -7713,7 +7716,8 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
}
}
-/* igb_read_i2c_byte - Reads 8 bit word over I2C
+/**
+ * igb_read_i2c_byte - Reads 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to read
* @dev_addr: device address
@@ -7721,9 +7725,9 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
*
* Performs byte read operation over I2C interface at
* a specified device address.
- */
+ **/
s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data)
+ u8 dev_addr, u8 *data)
{
struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
struct i2c_client *this_client = adapter->i2c_client;
@@ -7750,7 +7754,8 @@ s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
}
}
-/* igb_write_i2c_byte - Writes 8 bit word over I2C
+/**
+ * igb_write_i2c_byte - Writes 8 bit word over I2C
* @hw: pointer to hardware structure
* @byte_offset: byte offset to write
* @dev_addr: device address
@@ -7758,9 +7763,9 @@ s32 igb_read_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
*
* Performs byte write operation over I2C interface at
* a specified device address.
- */
+ **/
s32 igb_write_i2c_byte(struct e1000_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data)
+ u8 dev_addr, u8 data)
{
struct igb_adapter *adapter = container_of(hw, struct igb_adapter, hw);
struct i2c_client *this_client = adapter->i2c_client;
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 0a237507ee85..7e8c477b0ab9 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -1,5 +1,4 @@
-/*
- * PTP Hardware Clock (PHC) driver for the Intel 82576 and 82580
+/* PTP Hardware Clock (PHC) driver for the Intel 82576 and 82580
*
* Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com>
*
@@ -27,8 +26,7 @@
#define INCVALUE_MASK 0x7fffffff
#define ISGN 0x80000000
-/*
- * The 82580 timesync updates the system timer every 8ns by 8ns,
+/* The 82580 timesync updates the system timer every 8ns by 8ns,
* and this update value cannot be reprogrammed.
*
* Neither the 82576 nor the 82580 offer registers wide enough to hold
@@ -77,10 +75,7 @@
#define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT)
#define IGB_NBITS_82580 40
-/*
- * SYSTIM read access for the 82576
- */
-
+/* SYSTIM read access for the 82576 */
static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
{
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
@@ -97,10 +92,7 @@ static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
return val;
}
-/*
- * SYSTIM read access for the 82580
- */
-
+/* SYSTIM read access for the 82580 */
static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
{
struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc);
@@ -108,8 +100,7 @@ static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
u64 val;
u32 lo, hi, jk;
- /*
- * The timestamp latches on lowest register read. For the 82580
+ /* The timestamp latches on lowest register read. For the 82580
* the lowest register is SYSTIMR instead of SYSTIML. However we only
* need to provide nanosecond resolution, so we just ignore it.
*/
@@ -123,17 +114,13 @@ static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
return val;
}
-/*
- * SYSTIM read access for I210/I211
- */
-
+/* SYSTIM read access for I210/I211 */
static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
{
struct e1000_hw *hw = &adapter->hw;
u32 sec, nsec, jk;
- /*
- * The timestamp latches on lowest register read. For I210/I211, the
+ /* The timestamp latches on lowest register read. For I210/I211, the
* lowest register is SYSTIMR. Since we only need to provide nanosecond
* resolution, we can ignore it.
*/
@@ -150,8 +137,7 @@ static void igb_ptp_write_i210(struct igb_adapter *adapter,
{
struct e1000_hw *hw = &adapter->hw;
- /*
- * Writing the SYSTIMR register is not necessary as it only provides
+ /* Writing the SYSTIMR register is not necessary as it only provides
* sub-nanosecond resolution.
*/
wr32(E1000_SYSTIML, ts->tv_nsec);
@@ -185,6 +171,7 @@ static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
switch (adapter->hw.mac.type) {
case e1000_82576:
case e1000_82580:
+ case e1000_i354:
case e1000_i350:
spin_lock_irqsave(&adapter->tmreg_lock, flags);
@@ -207,10 +194,7 @@ static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter,
}
}
-/*
- * PTP clock operations
- */
-
+/* PTP clock operations */
static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb)
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
@@ -387,7 +371,7 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp,
*
* This work function polls the TSYNCTXCTL valid bit to determine when a
* timestamp has been taken for the current stored skb.
- */
+ **/
void igb_ptp_tx_work(struct work_struct *work)
{
struct igb_adapter *adapter = container_of(work, struct igb_adapter,
@@ -437,7 +421,7 @@ static void igb_ptp_overflow_check(struct work_struct *work)
* dropped an Rx packet that was timestamped when the ring is full. The
* particular error is rare but leaves the device in a state unable to timestamp
* any future packets.
- */
+ **/
void igb_ptp_rx_hang(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -481,7 +465,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
* If we were asked to do hardware stamping and such a time stamp is
* available, then it must have been for this skb here because we only
* allow only one such packet into the queue.
- */
+ **/
void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
@@ -506,15 +490,14 @@ void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
* This function is meant to retrieve a timestamp from the first buffer of an
* incoming frame. The value is stored in little endian format starting on
* byte 8.
- */
+ **/
void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector,
unsigned char *va,
struct sk_buff *skb)
{
__le64 *regval = (__le64 *)va;
- /*
- * The timestamp is recorded in little endian format.
+ /* The timestamp is recorded in little endian format.
* DWORD: 0 1 2 3
* Field: Reserved Reserved SYSTIML SYSTIMH
*/
@@ -529,7 +512,7 @@ void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector,
*
* This function is meant to retrieve a timestamp from the internal registers
* of the adapter and store it in the skb.
- */
+ **/
void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
struct sk_buff *skb)
{
@@ -537,8 +520,7 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
struct e1000_hw *hw = &adapter->hw;
u64 regval;
- /*
- * If this bit is set, then the RX registers contain the time stamp. No
+ /* If this bit is set, then the RX registers contain the time stamp. No
* other packet will be time stamped until we read these registers, so
* read the registers to make them available again. Because only one
* packet can be time stamped at a time, we know that the register
@@ -574,7 +556,6 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
* type has to be specified. Matching the kind of event packet is
* not supported, with the exception of "all V2 events regardless of
* level 2 or 4".
- *
**/
int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
@@ -655,10 +636,9 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
return 0;
}
- /*
- * Per-packet timestamping only works if all packets are
+ /* Per-packet timestamping only works if all packets are
* timestamped, so enable timestamping in all packets as
- * long as one rx filter was configured.
+ * long as one Rx filter was configured.
*/
if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
@@ -756,6 +736,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
break;
case e1000_82580:
+ case e1000_i354:
case e1000_i350:
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
@@ -844,6 +825,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)
switch (adapter->hw.mac.type) {
case e1000_82576:
case e1000_82580:
+ case e1000_i354:
case e1000_i350:
cancel_delayed_work_sync(&adapter->ptp_overflow_work);
break;
@@ -888,6 +870,7 @@ void igb_ptp_reset(struct igb_adapter *adapter)
wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576);
break;
case e1000_82580:
+ case e1000_i354:
case e1000_i350:
case e1000_i210:
case e1000_i211:
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index d60cd4393415..93eb7ee06d3e 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -116,7 +116,7 @@ static void igbvf_receive_skb(struct igbvf_adapter *adapter,
else
vid = le16_to_cpu(vlan) & E1000_RXD_SPC_VLAN_MASK;
if (test_bit(vid, adapter->active_vlans))
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
napi_gro_receive(&adapter->rx_ring->napi, skb);
@@ -447,7 +447,6 @@ int igbvf_setup_tx_resources(struct igbvf_adapter *adapter,
tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
&tx_ring->dma, GFP_KERNEL);
-
if (!tx_ring->desc)
goto err;
@@ -488,7 +487,6 @@ int igbvf_setup_rx_resources(struct igbvf_adapter *adapter,
rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
&rx_ring->dma, GFP_KERNEL);
-
if (!rx_ring->desc)
goto err;
@@ -1232,7 +1230,8 @@ static void igbvf_set_rlpml(struct igbvf_adapter *adapter)
e1000_rlpml_set_vf(hw, max_frame_size);
}
-static int igbvf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int igbvf_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct igbvf_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -1245,7 +1244,8 @@ static int igbvf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return 0;
}
-static int igbvf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int igbvf_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct igbvf_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -1264,7 +1264,7 @@ static void igbvf_restore_vlan(struct igbvf_adapter *adapter)
u16 vid;
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- igbvf_vlan_rx_add_vid(adapter->netdev, vid);
+ igbvf_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
/**
@@ -2724,9 +2724,9 @@ static int igbvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_RXCSUM;
netdev->features = netdev->hw_features |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index ea4808373435..fce3e92f9d11 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -101,8 +101,10 @@ static void ixgb_tx_timeout_task(struct work_struct *work);
static void ixgb_vlan_strip_enable(struct ixgb_adapter *adapter);
static void ixgb_vlan_strip_disable(struct ixgb_adapter *adapter);
-static int ixgb_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
-static int ixgb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
+static int ixgb_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid);
+static int ixgb_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid);
static void ixgb_restore_vlan(struct ixgb_adapter *adapter);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -332,8 +334,8 @@ ixgb_fix_features(struct net_device *netdev, netdev_features_t features)
* Tx VLAN insertion does not work per HW design when Rx stripping is
* disabled.
*/
- if (!(features & NETIF_F_HW_VLAN_RX))
- features &= ~NETIF_F_HW_VLAN_TX;
+ if (!(features & NETIF_F_HW_VLAN_CTAG_RX))
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -344,7 +346,7 @@ ixgb_set_features(struct net_device *netdev, netdev_features_t features)
struct ixgb_adapter *adapter = netdev_priv(netdev);
netdev_features_t changed = features ^ netdev->features;
- if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_RX)))
+ if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_CTAG_RX)))
return 0;
adapter->rx_csum = !!(features & NETIF_F_RXCSUM);
@@ -479,10 +481,10 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->hw_features = NETIF_F_SG |
NETIF_F_TSO |
NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
netdev->features = netdev->hw_features |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_FILTER;
netdev->hw_features |= NETIF_F_RXCSUM;
if (pci_using_dac) {
@@ -717,14 +719,11 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (!txdr->desc) {
vfree(txdr->buffer_info);
- netif_err(adapter, probe, adapter->netdev,
- "Unable to allocate transmit descriptor memory\n");
return -ENOMEM;
}
- memset(txdr->desc, 0, txdr->size);
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
@@ -807,8 +806,6 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
if (!rxdr->desc) {
vfree(rxdr->buffer_info);
- netif_err(adapter, probe, adapter->netdev,
- "Unable to allocate receive descriptors\n");
return -ENOMEM;
}
memset(rxdr->desc, 0, rxdr->size);
@@ -1145,7 +1142,7 @@ ixgb_set_multi(struct net_device *netdev)
}
alloc_failed:
- if (netdev->features & NETIF_F_HW_VLAN_RX)
+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
ixgb_vlan_strip_enable(adapter);
else
ixgb_vlan_strip_disable(adapter);
@@ -2085,8 +2082,8 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)
skb->protocol = eth_type_trans(skb, netdev);
if (status & IXGB_RX_DESC_STATUS_VP)
- __vlan_hwaccel_put_tag(skb,
- le16_to_cpu(rx_desc->special));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ le16_to_cpu(rx_desc->special));
netif_receive_skb(skb);
@@ -2159,6 +2156,10 @@ map_skb:
skb->data,
adapter->rx_buffer_len,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
rx_desc = IXGB_RX_DESC(*rx_ring, i);
rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);
@@ -2168,7 +2169,8 @@ map_skb:
rx_desc->status = 0;
- if (++i == rx_ring->count) i = 0;
+ if (++i == rx_ring->count)
+ i = 0;
buffer_info = &rx_ring->buffer_info[i];
}
@@ -2209,7 +2211,7 @@ ixgb_vlan_strip_disable(struct ixgb_adapter *adapter)
}
static int
-ixgb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+ixgb_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
u32 vfta, index;
@@ -2226,7 +2228,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
}
static int
-ixgb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+ixgb_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
u32 vfta, index;
@@ -2248,7 +2250,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)
u16 vid;
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- ixgb_vlan_rx_add_vid(adapter->netdev, vid);
+ ixgb_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index a8e10cff7a89..ca932387a80f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -740,6 +740,11 @@ extern void ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter);
extern void ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter);
extern void ixgbe_dbg_init(void);
extern void ixgbe_dbg_exit(void);
+#else
+static inline void ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter) {}
+static inline void ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter) {}
+static inline void ixgbe_dbg_init(void) {}
+static inline void ixgbe_dbg_exit(void) {}
#endif /* CONFIG_DEBUG_FS */
static inline struct netdev_queue *txring_txq(const struct ixgbe_ring *ring)
{
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index d0113fc97b6f..4a5bfb6b3af0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1305,6 +1305,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
.release_swfw_sync = &ixgbe_release_swfw_sync,
.get_thermal_sensor_data = NULL,
.init_thermal_sensor_thresh = NULL,
+ .mng_fw_enabled = NULL,
};
static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 203a00c24330..0b82d38bc97d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -59,12 +59,34 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
bool autoneg_wait_to_complete);
static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
+static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
+{
+ u32 fwsm, manc, factps;
+
+ fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+ if ((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT)
+ return false;
+
+ manc = IXGBE_READ_REG(hw, IXGBE_MANC);
+ if (!(manc & IXGBE_MANC_RCV_TCO_EN))
+ return false;
+
+ factps = IXGBE_READ_REG(hw, IXGBE_FACTPS);
+ if (factps & IXGBE_FACTPS_MNGCG)
+ return false;
+
+ return true;
+}
+
static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
- /* enable the laser control functions for SFP+ fiber */
- if (mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) {
+ /* enable the laser control functions for SFP+ fiber
+ * and MNG not enabled
+ */
+ if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
+ !hw->mng_fw_enabled) {
mac->ops.disable_tx_laser =
&ixgbe_disable_tx_laser_multispeed_fiber;
mac->ops.enable_tx_laser =
@@ -145,9 +167,9 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
}
/* Restart DSP and set SFI mode */
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw,
- IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL));
-
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) |
+ IXGBE_AUTOC_LMS_10G_SERIAL));
+ hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
ret_val = ixgbe_reset_pipeline_82599(hw);
if (got_lock) {
@@ -244,6 +266,8 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
/* Determine 1G link capabilities off of SFP+ type */
if (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) {
*speed = IXGBE_LINK_SPEED_1GB_FULL;
@@ -563,7 +587,8 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
return status;
/* Flap the tx laser if it has not already been done */
- hw->mac.ops.flap_tx_laser(hw);
+ if (hw->mac.ops.flap_tx_laser)
+ hw->mac.ops.flap_tx_laser(hw);
/*
* Wait for the controller to acquire link. Per IEEE 802.3ap,
@@ -615,7 +640,8 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
return status;
/* Flap the tx laser if it has not already been done */
- hw->mac.ops.flap_tx_laser(hw);
+ if (hw->mac.ops.flap_tx_laser)
+ hw->mac.ops.flap_tx_laser(hw);
/* Wait for the link partner to also set speed */
msleep(100);
@@ -777,12 +803,9 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
bool autoneg_wait_to_complete)
{
s32 status = 0;
- u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ u32 autoc, pma_pmd_1g, link_mode, start_autoc;
u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
- u32 start_autoc = autoc;
u32 orig_autoc = 0;
- u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
- u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK;
u32 links_reg;
u32 i;
@@ -805,9 +828,14 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
/* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
if (hw->mac.orig_link_settings_stored)
- orig_autoc = hw->mac.orig_autoc;
+ autoc = hw->mac.orig_autoc;
else
- orig_autoc = autoc;
+ autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ orig_autoc = autoc;
+ start_autoc = hw->mac.cached_autoc;
+ link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
+ pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
@@ -861,6 +889,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
/* Restart link */
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+ hw->mac.cached_autoc = autoc;
ixgbe_reset_pipeline_82599(hw);
if (got_lock)
@@ -932,7 +961,8 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
{
ixgbe_link_speed link_speed;
s32 status;
- u32 ctrl, i, autoc, autoc2;
+ u32 ctrl, i, autoc2;
+ u32 curr_lms;
bool link_up = false;
/* Call adapter stop to disable tx/rx and clear interrupts */
@@ -964,6 +994,13 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
if (hw->phy.reset_disable == false && hw->phy.ops.reset != NULL)
hw->phy.ops.reset(hw);
+ /* remember AUTOC from before we reset */
+ if (hw->mac.cached_autoc)
+ curr_lms = hw->mac.cached_autoc & IXGBE_AUTOC_LMS_MASK;
+ else
+ curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) &
+ IXGBE_AUTOC_LMS_MASK;
+
mac_reset_top:
/*
* Issue global reset to the MAC. Needs to be SW reset if link is up.
@@ -1012,14 +1049,35 @@ mac_reset_top:
* stored off yet. Otherwise restore the stored original
* values since the reset operation sets back to defaults.
*/
- autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+
+ /* Enable link if disabled in NVM */
+ if (autoc2 & IXGBE_AUTOC2_LINK_DISABLE_MASK) {
+ autoc2 &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2);
+ IXGBE_WRITE_FLUSH(hw);
+ }
+
if (hw->mac.orig_link_settings_stored == false) {
- hw->mac.orig_autoc = autoc;
+ hw->mac.orig_autoc = hw->mac.cached_autoc;
hw->mac.orig_autoc2 = autoc2;
hw->mac.orig_link_settings_stored = true;
} else {
- if (autoc != hw->mac.orig_autoc) {
+
+ /* If MNG FW is running on a multi-speed device that
+ * doesn't autoneg with out driver support we need to
+ * leave LMS in the state it was before we MAC reset.
+ * Likewise if we support WoL we don't want change the
+ * LMS state either.
+ */
+ if ((hw->phy.multispeed_fiber && hw->mng_fw_enabled) ||
+ hw->wol_enabled)
+ hw->mac.orig_autoc =
+ (hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) |
+ curr_lms;
+
+ if (hw->mac.cached_autoc != hw->mac.orig_autoc) {
/* Need SW/FW semaphore around AUTOC writes if LESM is
* on, likewise reset_pipeline requires us to hold
* this lock as it also writes to AUTOC.
@@ -1035,6 +1093,7 @@ mac_reset_top:
}
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc);
+ hw->mac.cached_autoc = hw->mac.orig_autoc;
ixgbe_reset_pipeline_82599(hw);
if (got_lock)
@@ -2135,10 +2194,19 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw,
**/
s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
{
- s32 i, autoc_reg, ret_val;
- s32 anlp1_reg = 0;
+ s32 ret_val;
+ u32 anlp1_reg = 0;
+ u32 i, autoc_reg, autoc2_reg;
+
+ /* Enable link if disabled in NVM */
+ autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+ if (autoc2_reg & IXGBE_AUTOC2_LINK_DISABLE_MASK) {
+ autoc2_reg &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg);
+ IXGBE_WRITE_FLUSH(hw);
+ }
- autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ autoc_reg = hw->mac.cached_autoc;
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
/* Write AUTOC register with toggled LMS[2] bit and Restart_AN */
@@ -2216,7 +2284,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
.release_swfw_sync = &ixgbe_release_swfw_sync,
.get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic,
.init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic,
-
+ .mng_fw_enabled = &ixgbe_mng_enabled,
};
static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 99e472ebaa75..9bcdeb89af5a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -592,6 +592,36 @@ s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr)
return 0;
}
+enum ixgbe_bus_width ixgbe_convert_bus_width(u16 link_status)
+{
+ switch (link_status & IXGBE_PCI_LINK_WIDTH) {
+ case IXGBE_PCI_LINK_WIDTH_1:
+ return ixgbe_bus_width_pcie_x1;
+ case IXGBE_PCI_LINK_WIDTH_2:
+ return ixgbe_bus_width_pcie_x2;
+ case IXGBE_PCI_LINK_WIDTH_4:
+ return ixgbe_bus_width_pcie_x4;
+ case IXGBE_PCI_LINK_WIDTH_8:
+ return ixgbe_bus_width_pcie_x8;
+ default:
+ return ixgbe_bus_width_unknown;
+ }
+}
+
+enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status)
+{
+ switch (link_status & IXGBE_PCI_LINK_SPEED) {
+ case IXGBE_PCI_LINK_SPEED_2500:
+ return ixgbe_bus_speed_2500;
+ case IXGBE_PCI_LINK_SPEED_5000:
+ return ixgbe_bus_speed_5000;
+ case IXGBE_PCI_LINK_SPEED_8000:
+ return ixgbe_bus_speed_8000;
+ default:
+ return ixgbe_bus_speed_unknown;
+ }
+}
+
/**
* ixgbe_get_bus_info_generic - Generic set PCI bus info
* @hw: pointer to hardware structure
@@ -610,35 +640,8 @@ s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
pci_read_config_word(adapter->pdev, IXGBE_PCI_LINK_STATUS,
&link_status);
- switch (link_status & IXGBE_PCI_LINK_WIDTH) {
- case IXGBE_PCI_LINK_WIDTH_1:
- hw->bus.width = ixgbe_bus_width_pcie_x1;
- break;
- case IXGBE_PCI_LINK_WIDTH_2:
- hw->bus.width = ixgbe_bus_width_pcie_x2;
- break;
- case IXGBE_PCI_LINK_WIDTH_4:
- hw->bus.width = ixgbe_bus_width_pcie_x4;
- break;
- case IXGBE_PCI_LINK_WIDTH_8:
- hw->bus.width = ixgbe_bus_width_pcie_x8;
- break;
- default:
- hw->bus.width = ixgbe_bus_width_unknown;
- break;
- }
-
- switch (link_status & IXGBE_PCI_LINK_SPEED) {
- case IXGBE_PCI_LINK_SPEED_2500:
- hw->bus.speed = ixgbe_bus_speed_2500;
- break;
- case IXGBE_PCI_LINK_SPEED_5000:
- hw->bus.speed = ixgbe_bus_speed_5000;
- break;
- default:
- hw->bus.speed = ixgbe_bus_speed_unknown;
- break;
- }
+ hw->bus.width = ixgbe_convert_bus_width(link_status);
+ hw->bus.speed = ixgbe_convert_bus_speed(link_status);
mac->ops.set_lan_id(hw);
@@ -1125,7 +1128,7 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
}
for (i = 0; i < words; i++) {
- eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) +
+ eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
IXGBE_EEPROM_RW_REG_START;
IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index bc3948ead6e0..22eee38868f1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -40,6 +40,8 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw);
s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
u32 pba_num_size);
s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr);
+enum ixgbe_bus_width ixgbe_convert_bus_width(u16 link_status);
+enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status);
s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw);
void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw);
s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index c3f1afd86906..d3754722adb4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -231,6 +231,10 @@ static int ixgbe_get_settings(struct net_device *netdev,
case ixgbe_sfp_type_lr:
case ixgbe_sfp_type_srlr_core0:
case ixgbe_sfp_type_srlr_core1:
+ case ixgbe_sfp_type_1g_sx_core0:
+ case ixgbe_sfp_type_1g_sx_core1:
+ case ixgbe_sfp_type_1g_lx_core0:
+ case ixgbe_sfp_type_1g_lx_core1:
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
ecmd->port = PORT_FIBRE;
@@ -246,12 +250,6 @@ static int ixgbe_get_settings(struct net_device *netdev,
ecmd->advertising |= ADVERTISED_TP;
ecmd->port = PORT_TP;
break;
- case ixgbe_sfp_type_1g_sx_core0:
- case ixgbe_sfp_type_1g_sx_core1:
- ecmd->supported |= SUPPORTED_FIBRE;
- ecmd->advertising |= ADVERTISED_FIBRE;
- ecmd->port = PORT_FIBRE;
- break;
case ixgbe_sfp_type_unknown:
default:
ecmd->supported |= SUPPORTED_FIBRE;
@@ -442,7 +440,8 @@ static void ixgbe_get_regs(struct net_device *netdev,
memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
- regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+ regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+ hw->device_id;
/* General Registers */
regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
@@ -1611,16 +1610,9 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
u32 reg_data;
- /* X540 needs to set the MACC.FLU bit to force link up */
- if (adapter->hw.mac.type == ixgbe_mac_X540) {
- reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
- reg_data |= IXGBE_MACC_FLU;
- IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
- }
- /* right now we only support MAC loopback in the driver */
- reg_data = IXGBE_READ_REG(hw, IXGBE_HLREG0);
/* Setup MAC loopback */
+ reg_data = IXGBE_READ_REG(hw, IXGBE_HLREG0);
reg_data |= IXGBE_HLREG0_LPBK;
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, reg_data);
@@ -1628,10 +1620,19 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
reg_data |= IXGBE_FCTRL_BAM | IXGBE_FCTRL_SBP | IXGBE_FCTRL_MPE;
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg_data);
- reg_data = IXGBE_READ_REG(hw, IXGBE_AUTOC);
- reg_data &= ~IXGBE_AUTOC_LMS_MASK;
- reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU;
- IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
+ /* X540 needs to set the MACC.FLU bit to force link up */
+ if (adapter->hw.mac.type == ixgbe_mac_X540) {
+ reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
+ reg_data |= IXGBE_MACC_FLU;
+ IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
+ } else {
+ if (hw->mac.orig_autoc) {
+ reg_data = hw->mac.orig_autoc | IXGBE_AUTOC_FLU;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
+ } else {
+ return 10;
+ }
+ }
IXGBE_WRITE_FLUSH(hw);
usleep_range(10000, 20000);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index db5611ae407e..d30fbdd81fca 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -63,7 +63,7 @@ char ixgbe_default_device_descr[] =
static char ixgbe_default_device_descr[] =
"Intel(R) 10 Gigabit Network Connection";
#endif
-#define DRV_VERSION "3.11.33-k"
+#define DRV_VERSION "3.13.10-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
"Copyright (c) 1999-2013 Intel Corporation.";
@@ -149,6 +149,52 @@ MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
+ u32 reg, u16 *value)
+{
+ int pos = 0;
+ struct pci_dev *parent_dev;
+ struct pci_bus *parent_bus;
+
+ parent_bus = adapter->pdev->bus->parent;
+ if (!parent_bus)
+ return -1;
+
+ parent_dev = parent_bus->self;
+ if (!parent_dev)
+ return -1;
+
+ pos = pci_find_capability(parent_dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return -1;
+
+ pci_read_config_word(parent_dev, pos + reg, value);
+ return 0;
+}
+
+static s32 ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 link_status = 0;
+ int err;
+
+ hw->bus.type = ixgbe_bus_type_pci_express;
+
+ /* Get the negotiated link width and speed from PCI config space of the
+ * parent, as this device is behind a switch
+ */
+ err = ixgbe_read_pci_cfg_word_parent(adapter, 18, &link_status);
+
+ /* assume caller will handle error case */
+ if (err)
+ return err;
+
+ hw->bus.width = ixgbe_convert_bus_width(link_status);
+ hw->bus.speed = ixgbe_convert_bus_speed(link_status);
+
+ return 0;
+}
+
static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
{
if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -1337,7 +1383,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
return hdr.network - data;
/* record next protocol if header is present */
- if (!hdr.ipv4->frag_off)
+ if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
nexthdr = hdr.ipv4->protocol;
} else if (protocol == __constant_htons(ETH_P_IPV6)) {
if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
@@ -1442,10 +1488,10 @@ static void ixgbe_process_skb_fields(struct ixgbe_ring *rx_ring,
ixgbe_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
- if ((dev->features & NETIF_F_HW_VLAN_RX) &&
+ if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) {
u16 vid = le16_to_cpu(rx_desc->wb.upper.vlan);
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
skb_record_rx_queue(skb, rx_ring->queue_index);
@@ -2049,6 +2095,9 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector,
*/
/* what was last interrupt timeslice? */
timepassed_us = q_vector->itr >> 2;
+ if (timepassed_us == 0)
+ return;
+
bytes_perint = bytes / timepassed_us; /* bytes/usec */
switch (itr_setting) {
@@ -2405,6 +2454,16 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
* with the write to EICR.
*/
eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
+
+ /* The lower 16bits of the EICR register are for the queue interrupts
+ * which should be masked here in order to not accidently clear them if
+ * the bits are high when ixgbe_msix_other is called. There is a race
+ * condition otherwise which results in possible performance loss
+ * especially if the ixgbe_msix_other interrupt is triggering
+ * consistently (as it would when PPS is turned on for the X540 device)
+ */
+ eicr &= 0xFFFF0000;
+
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
if (eicr & IXGBE_EICR_LSC)
@@ -3421,7 +3480,8 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
hw->mac.ops.enable_rx_dma(hw, rxctrl);
}
-static int ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int ixgbe_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
@@ -3433,7 +3493,8 @@ static int ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return 0;
}
-static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
@@ -3538,10 +3599,10 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
{
u16 vid;
- ixgbe_vlan_rx_add_vid(adapter->netdev, 0);
+ ixgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), 0);
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
+ ixgbe_vlan_rx_add_vid(adapter->netdev, htons(ETH_P_8021Q), vid);
}
/**
@@ -3676,7 +3737,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
- if (netdev->features & NETIF_F_HW_VLAN_RX)
+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
ixgbe_vlan_strip_enable(adapter);
else
ixgbe_vlan_strip_disable(adapter);
@@ -5077,14 +5138,14 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake)
netif_device_detach(netdev);
+ rtnl_lock();
if (netif_running(netdev)) {
- rtnl_lock();
ixgbe_down(adapter);
ixgbe_free_irq(adapter);
ixgbe_free_all_tx_resources(adapter);
ixgbe_free_all_rx_resources(adapter);
- rtnl_unlock();
}
+ rtnl_unlock();
ixgbe_clear_interrupt_scheme(adapter);
@@ -6425,9 +6486,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
struct ixgbe_tx_buffer *first;
int tso;
u32 tx_flags = 0;
-#if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD
unsigned short f;
-#endif
u16 count = TXD_USE_COUNT(skb_headlen(skb));
__be16 protocol = skb->protocol;
u8 hdr_len = 0;
@@ -6439,12 +6498,9 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
* + 1 desc for context descriptor,
* otherwise try next time
*/
-#if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD
for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
-#else
- count += skb_shinfo(skb)->nr_frags;
-#endif
+
if (ixgbe_maybe_stop_tx(tx_ring, count + 3)) {
tx_ring->tx_stats.tx_busy++;
return NETDEV_TX_BUSY;
@@ -6983,7 +7039,7 @@ static int ixgbe_set_features(struct net_device *netdev,
break;
}
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
ixgbe_vlan_strip_enable(adapter);
else
ixgbe_vlan_strip_disable(adapter);
@@ -7007,7 +7063,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
int err;
if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
- return -EOPNOTSUPP;
+ return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
/* Hardware does not support aging addresses so if a
* ndm_state is given only allow permanent addresses
@@ -7038,44 +7094,6 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
}
-static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr)
-{
- struct ixgbe_adapter *adapter = netdev_priv(dev);
- int err = -EOPNOTSUPP;
-
- if (ndm->ndm_state & NUD_PERMANENT) {
- pr_info("%s: FDB only supports static addresses\n",
- ixgbe_driver_name);
- return -EINVAL;
- }
-
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
- if (is_unicast_ether_addr(addr))
- err = dev_uc_del(dev, addr);
- else if (is_multicast_ether_addr(addr))
- err = dev_mc_del(dev, addr);
- else
- err = -EINVAL;
- }
-
- return err;
-}
-
-static int ixgbe_ndo_fdb_dump(struct sk_buff *skb,
- struct netlink_callback *cb,
- struct net_device *dev,
- int idx)
-{
- struct ixgbe_adapter *adapter = netdev_priv(dev);
-
- if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
- idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
-
- return idx;
-}
-
static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
struct nlmsghdr *nlh)
{
@@ -7171,8 +7189,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_set_features = ixgbe_set_features,
.ndo_fix_features = ixgbe_fix_features,
.ndo_fdb_add = ixgbe_ndo_fdb_add,
- .ndo_fdb_del = ixgbe_ndo_fdb_del,
- .ndo_fdb_dump = ixgbe_ndo_fdb_dump,
.ndo_bridge_setlink = ixgbe_ndo_bridge_setlink,
.ndo_bridge_getlink = ixgbe_ndo_bridge_getlink,
};
@@ -7202,9 +7218,19 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
/* only support first port */
if (hw->bus.func != 0)
break;
+ case IXGBE_SUBDEV_ID_82599_SP_560FLR:
case IXGBE_SUBDEV_ID_82599_SFP:
case IXGBE_SUBDEV_ID_82599_RNDC:
case IXGBE_SUBDEV_ID_82599_ECNA_DP:
+ case IXGBE_SUBDEV_ID_82599_LOM_SFP:
+ is_wol_supported = 1;
+ break;
+ }
+ break;
+ case IXGBE_DEV_ID_82599EN_SFP:
+ /* Only this subdevice supports WOL */
+ switch (subdevice_id) {
+ case IXGBE_SUBDEV_ID_82599EN_SFP_OCP1:
is_wol_supported = 1;
break;
}
@@ -7369,6 +7395,10 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_sw_init;
+ /* Cache if MNG FW is up so we don't have to read the REG later */
+ if (hw->mac.ops.mng_fw_enabled)
+ hw->mng_fw_enabled = hw->mac.ops.mng_fw_enabled(hw);
+
/* Make it possible the adapter to be woken up via WOL */
switch (adapter->hw.mac.type) {
case ixgbe_mac_82599EB:
@@ -7425,9 +7455,9 @@ skip_sriov:
netdev->features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_TSO |
NETIF_F_TSO6 |
NETIF_F_RXHASH |
@@ -7521,7 +7551,9 @@ skip_sriov:
/* WOL not supported for all devices */
adapter->wol = 0;
hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap);
- if (ixgbe_wol_supported(adapter, pdev->device, pdev->subsystem_device))
+ hw->wol_enabled = ixgbe_wol_supported(adapter, pdev->device,
+ pdev->subsystem_device);
+ if (hw->wol_enabled)
adapter->wol = IXGBE_WUFC_MAG;
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
@@ -7532,10 +7564,13 @@ skip_sriov:
/* pick up the PCI bus settings for reporting later */
hw->mac.ops.get_bus_info(hw);
+ if (hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP)
+ ixgbe_get_parent_bus_info(adapter);
/* print bus type/speed/width info */
e_dev_info("(PCI Express:%s:%s) %pM\n",
- (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
+ (hw->bus.speed == ixgbe_bus_speed_8000 ? "8.0GT/s" :
+ hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" :
"Unknown"),
(hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
@@ -7615,9 +7650,13 @@ skip_sriov:
e_err(probe, "failed to allocate sysfs resources\n");
#endif /* CONFIG_IXGBE_HWMON */
-#ifdef CONFIG_DEBUG_FS
ixgbe_dbg_adapter_init(adapter);
-#endif /* CONFIG_DEBUG_FS */
+
+ /* Need link setup for MNG FW, else wait for IXGBE_UP */
+ if (hw->mng_fw_enabled && hw->mac.ops.setup_link)
+ hw->mac.ops.setup_link(hw,
+ IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
+ true);
return 0;
@@ -7653,9 +7692,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
struct net_device *netdev = adapter->netdev;
-#ifdef CONFIG_DEBUG_FS
ixgbe_dbg_adapter_exit(adapter);
-#endif /*CONFIG_DEBUG_FS */
set_bit(__IXGBE_DOWN, &adapter->state);
cancel_work_sync(&adapter->service_task);
@@ -7918,16 +7955,19 @@ static int __init ixgbe_init_module(void)
pr_info("%s - version %s\n", ixgbe_driver_string, ixgbe_driver_version);
pr_info("%s\n", ixgbe_copyright);
-#ifdef CONFIG_DEBUG_FS
ixgbe_dbg_init();
-#endif /* CONFIG_DEBUG_FS */
+
+ ret = pci_register_driver(&ixgbe_driver);
+ if (ret) {
+ ixgbe_dbg_exit();
+ return ret;
+ }
#ifdef CONFIG_IXGBE_DCA
dca_register_notify(&dca_notifier);
#endif
- ret = pci_register_driver(&ixgbe_driver);
- return ret;
+ return 0;
}
module_init(ixgbe_init_module);
@@ -7945,9 +7985,7 @@ static void __exit ixgbe_exit_module(void)
#endif
pci_unregister_driver(&ixgbe_driver);
-#ifdef CONFIG_DEBUG_FS
ixgbe_dbg_exit();
-#endif /* CONFIG_DEBUG_FS */
rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 060d2ad2ac96..e5691ccbce9d 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -956,6 +956,13 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
else
hw->phy.sfp_type =
ixgbe_sfp_type_1g_sx_core1;
+ } else if (comp_codes_1g & IXGBE_SFF_1GBASELX_CAPABLE) {
+ if (hw->bus.lan_id == 0)
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_lx_core0;
+ else
+ hw->phy.sfp_type =
+ ixgbe_sfp_type_1g_lx_core1;
} else {
hw->phy.sfp_type = ixgbe_sfp_type_unknown;
}
@@ -1043,6 +1050,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (comp_codes_10g == 0 &&
!(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
@@ -1058,10 +1067,12 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
hw->mac.ops.get_device_caps(hw, &enforce_sfp);
if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) &&
- !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) ||
- (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1) ||
- (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0) ||
- (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1))) {
+ !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
+ hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
/* Make sure we're a supported PHY type */
if (hw->phy.type == ixgbe_phy_sfp_intel) {
status = 0;
@@ -1125,10 +1136,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
* SR modules
*/
if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core0 ||
sfp_type == ixgbe_sfp_type_1g_cu_core0 ||
sfp_type == ixgbe_sfp_type_1g_sx_core0)
sfp_type = ixgbe_sfp_type_srlr_core0;
else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 ||
+ sfp_type == ixgbe_sfp_type_1g_lx_core1 ||
sfp_type == ixgbe_sfp_type_1g_cu_core1 ||
sfp_type == ixgbe_sfp_type_1g_sx_core1)
sfp_type = ixgbe_sfp_type_srlr_core1;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index d44b4d21268c..1e7d587c4e57 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -35,7 +35,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/ipv6.h>
-#ifdef NETIF_F_HW_VLAN_TX
+#ifdef NETIF_F_HW_VLAN_CTAG_TX
#include <linux/if_vlan.h>
#endif
@@ -661,13 +661,7 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
bool enable = ((event_mask & 0x10000000U) != 0);
if (enable) {
- eth_random_addr(vf_mac_addr);
- e_info(probe, "IOV: VF %d is enabled MAC %pM\n",
- vfn, vf_mac_addr);
- /*
- * Store away the VF "permananet" MAC address, it will ask
- * for it later.
- */
+ eth_zero_addr(vf_mac_addr);
memcpy(adapter->vfinfo[vfn].vf_mac_addresses, vf_mac_addr, 6);
}
@@ -688,7 +682,8 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
ixgbe_vf_reset_event(adapter, vf);
/* set vf mac address */
- ixgbe_set_vf_mac(adapter, vf, vf_mac);
+ if (!is_zero_ether_addr(vf_mac))
+ ixgbe_set_vf_mac(adapter, vf, vf_mac);
vf_shift = vf % 32;
reg_offset = vf / 32;
@@ -729,8 +724,16 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
IXGBE_WRITE_REG(hw, IXGBE_VMECM(reg_offset), reg);
/* reply to reset with ack and vf mac address */
- msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
- memcpy(addr, vf_mac, ETH_ALEN);
+ msgbuf[0] = IXGBE_VF_RESET;
+ if (!is_zero_ether_addr(vf_mac)) {
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_ACK;
+ memcpy(addr, vf_mac, ETH_ALEN);
+ } else {
+ msgbuf[0] |= IXGBE_VT_MSGTYPE_NACK;
+ dev_warn(&adapter->pdev->dev,
+ "VF %d has no MAC address assigned, you may have to assign one manually\n",
+ vf);
+ }
/*
* Piggyback the multicast filter type so VF can compute the
@@ -1049,6 +1052,12 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
return -EINVAL;
if (vlan || qos) {
+ if (adapter->vfinfo[vf].pf_vlan)
+ err = ixgbe_set_vf_vlan(adapter, false,
+ adapter->vfinfo[vf].pf_vlan,
+ vf);
+ if (err)
+ goto out;
err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
if (err)
goto out;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 6652e96c352d..70c6aa3d3f95 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -56,10 +56,13 @@
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_SUBDEV_ID_82599_RNDC 0x1F72
#define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0
+#define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B
#define IXGBE_SUBDEV_ID_82599_ECNA_DP 0x0470
+#define IXGBE_SUBDEV_ID_82599_LOM_SFP 0x8976
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D
#define IXGBE_DEV_ID_82599EN_SFP 0x1557
+#define IXGBE_SUBDEV_ID_82599EN_SFP_OCP1 0x0001
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C
@@ -729,6 +732,13 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_MDEF_EXT(_i) (0x05160 + ((_i) * 4)) /* 8 of these (0-7) */
#define IXGBE_LSWFW 0x15014
+/* Management Bit Fields and Masks */
+#define IXGBE_MANC_RCV_TCO_EN 0x00020000 /* Rcv TCO packet enable */
+
+/* Firmware Semaphore Register */
+#define IXGBE_FWSM_MODE_MASK 0xE
+#define IXGBE_FWSM_FW_MODE_PT 0x4
+
/* ARC Subsystem registers */
#define IXGBE_HICR 0x15F00
#define IXGBE_FWSTS 0x15F0C
@@ -1019,6 +1029,7 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_CTRL_RST_MASK (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST)
/* FACTPS */
+#define IXGBE_FACTPS_MNGCG 0x20000000 /* Manageblility Clock Gated */
#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */
/* MHADD Bit Masks */
@@ -1582,6 +1593,7 @@ enum {
#define IXGBE_AUTOC2_10G_KR (0x0 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
#define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
#define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC2_LINK_DISABLE_MASK 0x70000000
#define IXGBE_MACC_FLU 0x00000001
#define IXGBE_MACC_FSV_10G 0x00030000
@@ -1827,6 +1839,7 @@ enum {
#define IXGBE_PCI_LINK_SPEED 0xF
#define IXGBE_PCI_LINK_SPEED_2500 0x1
#define IXGBE_PCI_LINK_SPEED_5000 0x2
+#define IXGBE_PCI_LINK_SPEED_8000 0x3
#define IXGBE_PCI_HEADER_TYPE_REGISTER 0x0E
#define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
#define IXGBE_PCI_DEVICE_CONTROL2_16ms 0x0005
@@ -2600,6 +2613,8 @@ enum ixgbe_sfp_type {
ixgbe_sfp_type_1g_cu_core1 = 10,
ixgbe_sfp_type_1g_sx_core0 = 11,
ixgbe_sfp_type_1g_sx_core1 = 12,
+ ixgbe_sfp_type_1g_lx_core0 = 13,
+ ixgbe_sfp_type_1g_lx_core1 = 14,
ixgbe_sfp_type_not_present = 0xFFFE,
ixgbe_sfp_type_unknown = 0xFFFF
};
@@ -2650,6 +2665,7 @@ enum ixgbe_bus_speed {
ixgbe_bus_speed_133 = 133,
ixgbe_bus_speed_2500 = 2500,
ixgbe_bus_speed_5000 = 5000,
+ ixgbe_bus_speed_8000 = 8000,
ixgbe_bus_speed_reserved
};
@@ -2859,6 +2875,7 @@ struct ixgbe_mac_operations {
s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8);
s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
+ bool (*mng_fw_enabled)(struct ixgbe_hw *hw);
};
struct ixgbe_phy_operations {
@@ -2912,6 +2929,7 @@ struct ixgbe_mac_info {
u32 max_tx_queues;
u32 max_rx_queues;
u32 orig_autoc;
+ u32 cached_autoc;
u32 orig_autoc2;
bool orig_link_settings_stored;
bool autotry_restart;
@@ -2986,6 +3004,8 @@ struct ixgbe_hw {
bool adapter_stopped;
bool force_full_reset;
bool allow_unsupported_sfp;
+ bool mng_fw_enabled;
+ bool wol_enabled;
};
struct ixgbe_info {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index 66c5e946284e..389324f5929a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -854,6 +854,7 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
.enable_rx_buff = &ixgbe_enable_rx_buff_generic,
.get_thermal_sensor_data = NULL,
.init_thermal_sensor_thresh = NULL,
+ .mng_fw_enabled = NULL,
};
static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index fc0af9a3bb35..fff0d9867529 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -44,8 +44,8 @@ struct ixgbevf_tx_buffer {
struct sk_buff *skb;
dma_addr_t dma;
unsigned long time_stamp;
+ union ixgbe_adv_tx_desc *next_to_watch;
u16 length;
- u16 next_to_watch;
u16 mapped_as_page;
};
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 2b6cb5ca48ee..1f5166ad6bb5 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -76,12 +76,9 @@ static const struct ixgbevf_info *ixgbevf_info_tbl[] = {
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
* Class, Class Mask, private data (not used) }
*/
-static struct pci_device_id ixgbevf_pci_tbl[] = {
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF),
- board_82599_vf},
- {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF),
- board_X540_vf},
-
+static DEFINE_PCI_DEVICE_TABLE(ixgbevf_pci_tbl) = {
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_VF), board_82599_vf },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540_VF), board_X540_vf },
/* required last entry */
{0, }
};
@@ -190,28 +187,37 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
struct ixgbevf_adapter *adapter = q_vector->adapter;
union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
struct ixgbevf_tx_buffer *tx_buffer_info;
- unsigned int i, eop, count = 0;
+ unsigned int i, count = 0;
unsigned int total_bytes = 0, total_packets = 0;
if (test_bit(__IXGBEVF_DOWN, &adapter->state))
return true;
i = tx_ring->next_to_clean;
- eop = tx_ring->tx_buffer_info[i].next_to_watch;
- eop_desc = IXGBEVF_TX_DESC(tx_ring, eop);
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ eop_desc = tx_buffer_info->next_to_watch;
- while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
- (count < tx_ring->count)) {
+ do {
bool cleaned = false;
- rmb(); /* read buffer_info after eop_desc */
- /* eop could change between read and DD-check */
- if (unlikely(eop != tx_ring->tx_buffer_info[i].next_to_watch))
- goto cont_loop;
+
+ /* if next_to_watch is not set then there is no work pending */
+ if (!eop_desc)
+ break;
+
+ /* prevent any other reads prior to eop_desc */
+ read_barrier_depends();
+
+ /* if DD is not set pending work has not been completed */
+ if (!(eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)))
+ break;
+
+ /* clear next_to_watch to prevent false hangs */
+ tx_buffer_info->next_to_watch = NULL;
+
for ( ; !cleaned; count++) {
struct sk_buff *skb;
tx_desc = IXGBEVF_TX_DESC(tx_ring, i);
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- cleaned = (i == eop);
+ cleaned = (tx_desc == eop_desc);
skb = tx_buffer_info->skb;
if (cleaned && skb) {
@@ -234,12 +240,12 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
i++;
if (i == tx_ring->count)
i = 0;
+
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
}
-cont_loop:
- eop = tx_ring->tx_buffer_info[i].next_to_watch;
- eop_desc = IXGBEVF_TX_DESC(tx_ring, eop);
- }
+ eop_desc = tx_buffer_info->next_to_watch;
+ } while (count < tx_ring->count);
tx_ring->next_to_clean = i;
@@ -285,7 +291,7 @@ static void ixgbevf_receive_skb(struct ixgbevf_q_vector *q_vector,
u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
if (is_vlan && test_bit(tag & VLAN_VID_MASK, adapter->active_vlans))
- __vlan_hwaccel_put_tag(skb, tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag);
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
napi_gro_receive(&q_vector->napi, skb);
@@ -1173,7 +1179,8 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)
}
}
-static int ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+static int ixgbevf_vlan_rx_add_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
@@ -1198,7 +1205,8 @@ static int ixgbevf_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
return err;
}
-static int ixgbevf_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static int ixgbevf_vlan_rx_kill_vid(struct net_device *netdev,
+ __be16 proto, u16 vid)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
@@ -1221,7 +1229,8 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
u16 vid;
for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
- ixgbevf_vlan_rx_add_vid(adapter->netdev, vid);
+ ixgbevf_vlan_rx_add_vid(adapter->netdev,
+ htons(ETH_P_8021Q), vid);
}
static int ixgbevf_write_uc_addr_list(struct net_device *netdev)
@@ -2046,6 +2055,7 @@ static int ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
+ struct net_device *netdev = adapter->netdev;
int err;
/* PCI config space info */
@@ -2065,18 +2075,26 @@ static int ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
err = hw->mac.ops.reset_hw(hw);
if (err) {
dev_info(&pdev->dev,
- "PF still in reset state, assigning new address\n");
- eth_hw_addr_random(adapter->netdev);
- memcpy(adapter->hw.mac.addr, adapter->netdev->dev_addr,
- adapter->netdev->addr_len);
+ "PF still in reset state. Is the PF interface up?\n");
} else {
err = hw->mac.ops.init_hw(hw);
if (err) {
pr_err("init_shared_code failed: %d\n", err);
goto out;
}
- memcpy(adapter->netdev->dev_addr, adapter->hw.mac.addr,
- adapter->netdev->addr_len);
+ err = hw->mac.ops.get_mac_addr(hw, hw->mac.addr);
+ if (err)
+ dev_info(&pdev->dev, "Error reading MAC address\n");
+ else if (is_zero_ether_addr(adapter->hw.mac.addr))
+ dev_info(&pdev->dev,
+ "MAC address not assigned by administrator.\n");
+ memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len);
+ }
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ dev_info(&pdev->dev, "Assigning random MAC address\n");
+ eth_hw_addr_random(netdev);
+ memcpy(hw->mac.addr, netdev->dev_addr, netdev->addr_len);
}
/* lock to protect mailbox accesses */
@@ -2425,9 +2443,6 @@ int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter,
&rx_ring->dma, GFP_KERNEL);
if (!rx_ring->desc) {
- hw_dbg(&adapter->hw,
- "Unable to allocate memory for "
- "the receive descriptor ring\n");
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
goto alloc_failed;
@@ -2822,8 +2837,7 @@ static bool ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
}
static int ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags,
- unsigned int first)
+ struct sk_buff *skb, u32 tx_flags)
{
struct ixgbevf_tx_buffer *tx_buffer_info;
unsigned int len;
@@ -2848,7 +2862,6 @@ static int ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
size, DMA_TO_DEVICE);
if (dma_mapping_error(tx_ring->dev, tx_buffer_info->dma))
goto dma_error;
- tx_buffer_info->next_to_watch = i;
len -= size;
total -= size;
@@ -2878,7 +2891,6 @@ static int ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
tx_buffer_info->dma))
goto dma_error;
tx_buffer_info->mapped_as_page = true;
- tx_buffer_info->next_to_watch = i;
len -= size;
total -= size;
@@ -2897,8 +2909,6 @@ static int ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
else
i = i - 1;
tx_ring->tx_buffer_info[i].skb = skb;
- tx_ring->tx_buffer_info[first].next_to_watch = i;
- tx_ring->tx_buffer_info[first].time_stamp = jiffies;
return count;
@@ -2907,7 +2917,6 @@ dma_error:
/* clear timestamp and dma mappings for failed tx_buffer_info map */
tx_buffer_info->dma = 0;
- tx_buffer_info->next_to_watch = 0;
count--;
/* clear timestamp and dma mappings for remaining portion of packet */
@@ -2924,7 +2933,8 @@ dma_error:
}
static void ixgbevf_tx_queue(struct ixgbevf_ring *tx_ring, int tx_flags,
- int count, u32 paylen, u8 hdr_len)
+ int count, unsigned int first, u32 paylen,
+ u8 hdr_len)
{
union ixgbe_adv_tx_desc *tx_desc = NULL;
struct ixgbevf_tx_buffer *tx_buffer_info;
@@ -2975,6 +2985,16 @@ static void ixgbevf_tx_queue(struct ixgbevf_ring *tx_ring, int tx_flags,
tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+ tx_ring->tx_buffer_info[first].time_stamp = jiffies;
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+
+ tx_ring->tx_buffer_info[first].next_to_watch = tx_desc;
tx_ring->next_to_use = i;
}
@@ -3066,15 +3086,8 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= IXGBE_TX_FLAGS_CSUM;
ixgbevf_tx_queue(tx_ring, tx_flags,
- ixgbevf_tx_map(tx_ring, skb, tx_flags, first),
- skb->len, hdr_len);
- /*
- * Force memory writes to complete before letting h/w
- * know there are new descriptors to fetch. (Only
- * applicable for weak-ordered memory model archs,
- * such as IA-64).
- */
- wmb();
+ ixgbevf_tx_map(tx_ring, skb, tx_flags),
+ first, skb->len, hdr_len);
writel(tx_ring->next_to_use, adapter->hw.hw_addr + tx_ring->tail);
@@ -3400,9 +3413,9 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_RXCSUM;
netdev->features = netdev->hw_features |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index 0c94557b53df..387b52635bc0 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -109,7 +109,12 @@ static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
if (ret_val)
return ret_val;
- if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
+ /* New versions of the PF may NACK the reset return message
+ * to indicate that no MAC address has yet been assigned for
+ * the VF.
+ */
+ if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK) &&
+ msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_NACK))
return IXGBE_ERR_INVALID_MAC_ADDR;
memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 0519afa413d2..070a6f1a0577 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1059,7 +1059,7 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx)
if (rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_TAGON)) {
u16 vid = le16_to_cpu(rxdesc->descwb.vlan);
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
NET_STAT(jme).rx_bytes += 4;
}
jme->jme_rx(skb);
@@ -3030,8 +3030,8 @@ jme_init_one(struct pci_dev *pdev,
NETIF_F_SG |
NETIF_F_TSO |
NETIF_F_TSO6 |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index edfba9370922..a49e81bdf8e8 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -21,8 +21,8 @@ if NET_VENDOR_MARVELL
config MV643XX_ETH
tristate "Marvell Discovery (643XX) and Orion ethernet support"
depends on (MV64X60 || PPC32 || PLAT_ORION) && INET
- select INET_LRO
select PHYLIB
+ select MVMDIO
---help---
This driver supports the gigabit ethernet MACs in the
Marvell Discovery PPC/MIPS chipset family (MV643XX) and
@@ -33,19 +33,17 @@ config MV643XX_ETH
config MVMDIO
tristate "Marvell MDIO interface support"
+ select PHYLIB
---help---
This driver supports the MDIO interface found in the network
interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
Dove, Armada 370 and Armada XP).
- For now, this driver is only needed for the MVNETA driver
- (used on Armada 370 and XP), but it could be used in the
- future by the MV643XX_ETH driver.
+ This driver is used by the MV643XX_ETH and MVNETA drivers.
config MVNETA
tristate "Marvell Armada 370/XP network interface support"
depends on MACH_ARMADA_370_XP
- select PHYLIB
select MVMDIO
---help---
This driver supports the network interface units in the
diff --git a/drivers/net/ethernet/marvell/Makefile b/drivers/net/ethernet/marvell/Makefile
index 7f63b4aac434..5c4a7765ff0e 100644
--- a/drivers/net/ethernet/marvell/Makefile
+++ b/drivers/net/ethernet/marvell/Makefile
@@ -2,8 +2,8 @@
# Makefile for the Marvell device drivers.
#
-obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
obj-$(CONFIG_MVMDIO) += mvmdio.o
+obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
obj-$(CONFIG_MVNETA) += mvneta.o
obj-$(CONFIG_PXA168_ETH) += pxa168_eth.o
obj-$(CONFIG_SKGE) += skge.o
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index 6562c736a1d8..d0afeea181fb 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -20,6 +20,8 @@
* Copyright (C) 2007-2008 Marvell Semiconductor
* Lennert Buytenhek <buytenh@marvell.com>
*
+ * Copyright (C) 2013 Michael Stapelberg <michael@stapelberg.de>
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
@@ -54,8 +56,8 @@
#include <linux/phy.h>
#include <linux/mv643xx_eth.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/types.h>
-#include <linux/inet_lro.h>
#include <linux/slab.h>
#include <linux/clk.h>
@@ -67,14 +69,6 @@ static char mv643xx_eth_driver_version[] = "1.4";
* Registers shared between all ports.
*/
#define PHY_ADDR 0x0000
-#define SMI_REG 0x0004
-#define SMI_BUSY 0x10000000
-#define SMI_READ_VALID 0x08000000
-#define SMI_OPCODE_READ 0x04000000
-#define SMI_OPCODE_WRITE 0x00000000
-#define ERR_INT_CAUSE 0x0080
-#define ERR_INT_SMI_DONE 0x00000010
-#define ERR_INT_MASK 0x0084
#define WINDOW_BASE(w) (0x0200 + ((w) << 3))
#define WINDOW_SIZE(w) (0x0204 + ((w) << 3))
#define WINDOW_REMAP_HIGH(w) (0x0280 + ((w) << 2))
@@ -264,25 +258,6 @@ struct mv643xx_eth_shared_private {
void __iomem *base;
/*
- * Points at the right SMI instance to use.
- */
- struct mv643xx_eth_shared_private *smi;
-
- /*
- * Provides access to local SMI interface.
- */
- struct mii_bus *smi_bus;
-
- /*
- * If we have access to the error interrupt pin (which is
- * somewhat misnamed as it not only reflects internal errors
- * but also reflects SMI completion), use that to wait for
- * SMI access completion instead of polling the SMI busy bit.
- */
- int err_interrupt;
- wait_queue_head_t smi_busy_wait;
-
- /*
* Per-port MBUS window access register value.
*/
u32 win_protect;
@@ -293,7 +268,7 @@ struct mv643xx_eth_shared_private {
int extended_rx_coal_limit;
int tx_bw_control;
int tx_csum_limit;
-
+ struct clk *clk;
};
#define TX_BW_CONTROL_ABSENT 0
@@ -341,12 +316,6 @@ struct mib_counters {
u32 rx_overrun;
};
-struct lro_counters {
- u32 lro_aggregated;
- u32 lro_flushed;
- u32 lro_no_desc;
-};
-
struct rx_queue {
int index;
@@ -360,9 +329,6 @@ struct rx_queue {
dma_addr_t rx_desc_dma;
int rx_desc_area_size;
struct sk_buff **rx_skb;
-
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_arr[8];
};
struct tx_queue {
@@ -398,8 +364,6 @@ struct mv643xx_eth_private {
spinlock_t mib_counters_lock;
struct mib_counters mib_counters;
- struct lro_counters lro_counters;
-
struct work_struct tx_timeout_task;
struct napi_struct napi;
@@ -435,9 +399,7 @@ struct mv643xx_eth_private {
/*
* Hardware-specific parameters.
*/
-#if defined(CONFIG_HAVE_CLK)
struct clk *clk;
-#endif
unsigned int t_clk;
};
@@ -530,42 +492,12 @@ static void txq_maybe_wake(struct tx_queue *txq)
}
}
-
-/* rx napi ******************************************************************/
-static int
-mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
- u64 *hdr_flags, void *priv)
-{
- unsigned long cmd_sts = (unsigned long)priv;
-
- /*
- * Make sure that this packet is Ethernet II, is not VLAN
- * tagged, is IPv4, has a valid IP header, and is TCP.
- */
- if ((cmd_sts & (RX_IP_HDR_OK | RX_PKT_IS_IPV4 |
- RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_MASK |
- RX_PKT_IS_VLAN_TAGGED)) !=
- (RX_IP_HDR_OK | RX_PKT_IS_IPV4 |
- RX_PKT_IS_ETHERNETV2 | RX_PKT_LAYER4_TYPE_TCP_IPV4))
- return -1;
-
- skb_reset_network_header(skb);
- skb_set_transport_header(skb, ip_hdrlen(skb));
- *iphdr = ip_hdr(skb);
- *tcph = tcp_hdr(skb);
- *hdr_flags = LRO_IPV4 | LRO_TCP;
-
- return 0;
-}
-
static int rxq_process(struct rx_queue *rxq, int budget)
{
struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
struct net_device_stats *stats = &mp->dev->stats;
- int lro_flush_needed;
int rx;
- lro_flush_needed = 0;
rx = 0;
while (rx < budget && rxq->rx_desc_count) {
struct rx_desc *rx_desc;
@@ -626,12 +558,7 @@ static int rxq_process(struct rx_queue *rxq, int budget)
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->protocol = eth_type_trans(skb, mp->dev);
- if (skb->dev->features & NETIF_F_LRO &&
- skb->ip_summed == CHECKSUM_UNNECESSARY) {
- lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts);
- lro_flush_needed = 1;
- } else
- netif_receive_skb(skb);
+ napi_gro_receive(&mp->napi, skb);
continue;
@@ -651,9 +578,6 @@ err:
dev_kfree_skb(skb);
}
- if (lro_flush_needed)
- lro_flush_all(&rxq->lro_mgr);
-
if (rx < budget)
mp->work_rx &= ~(1 << rxq->index);
@@ -1120,97 +1044,6 @@ out_write:
wrlp(mp, PORT_SERIAL_CONTROL, pscr);
}
-static irqreturn_t mv643xx_eth_err_irq(int irq, void *dev_id)
-{
- struct mv643xx_eth_shared_private *msp = dev_id;
-
- if (readl(msp->base + ERR_INT_CAUSE) & ERR_INT_SMI_DONE) {
- writel(~ERR_INT_SMI_DONE, msp->base + ERR_INT_CAUSE);
- wake_up(&msp->smi_busy_wait);
- return IRQ_HANDLED;
- }
-
- return IRQ_NONE;
-}
-
-static int smi_is_done(struct mv643xx_eth_shared_private *msp)
-{
- return !(readl(msp->base + SMI_REG) & SMI_BUSY);
-}
-
-static int smi_wait_ready(struct mv643xx_eth_shared_private *msp)
-{
- if (msp->err_interrupt == NO_IRQ) {
- int i;
-
- for (i = 0; !smi_is_done(msp); i++) {
- if (i == 10)
- return -ETIMEDOUT;
- msleep(10);
- }
-
- return 0;
- }
-
- if (!smi_is_done(msp)) {
- wait_event_timeout(msp->smi_busy_wait, smi_is_done(msp),
- msecs_to_jiffies(100));
- if (!smi_is_done(msp))
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int smi_bus_read(struct mii_bus *bus, int addr, int reg)
-{
- struct mv643xx_eth_shared_private *msp = bus->priv;
- void __iomem *smi_reg = msp->base + SMI_REG;
- int ret;
-
- if (smi_wait_ready(msp)) {
- pr_warn("SMI bus busy timeout\n");
- return -ETIMEDOUT;
- }
-
- writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg);
-
- if (smi_wait_ready(msp)) {
- pr_warn("SMI bus busy timeout\n");
- return -ETIMEDOUT;
- }
-
- ret = readl(smi_reg);
- if (!(ret & SMI_READ_VALID)) {
- pr_warn("SMI bus read not valid\n");
- return -ENODEV;
- }
-
- return ret & 0xffff;
-}
-
-static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val)
-{
- struct mv643xx_eth_shared_private *msp = bus->priv;
- void __iomem *smi_reg = msp->base + SMI_REG;
-
- if (smi_wait_ready(msp)) {
- pr_warn("SMI bus busy timeout\n");
- return -ETIMEDOUT;
- }
-
- writel(SMI_OPCODE_WRITE | (reg << 21) |
- (addr << 16) | (val & 0xffff), smi_reg);
-
- if (smi_wait_ready(msp)) {
- pr_warn("SMI bus busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-
/* statistics ***************************************************************/
static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
{
@@ -1236,26 +1069,6 @@ static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
return stats;
}
-static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp)
-{
- u32 lro_aggregated = 0;
- u32 lro_flushed = 0;
- u32 lro_no_desc = 0;
- int i;
-
- for (i = 0; i < mp->rxq_count; i++) {
- struct rx_queue *rxq = mp->rxq + i;
-
- lro_aggregated += rxq->lro_mgr.stats.aggregated;
- lro_flushed += rxq->lro_mgr.stats.flushed;
- lro_no_desc += rxq->lro_mgr.stats.no_desc;
- }
-
- mp->lro_counters.lro_aggregated = lro_aggregated;
- mp->lro_counters.lro_flushed = lro_flushed;
- mp->lro_counters.lro_no_desc = lro_no_desc;
-}
-
static inline u32 mib_read(struct mv643xx_eth_private *mp, int offset)
{
return rdl(mp, MIB_COUNTERS(mp->port_num) + offset);
@@ -1419,10 +1232,6 @@ struct mv643xx_eth_stats {
{ #m, FIELD_SIZEOF(struct mib_counters, m), \
-1, offsetof(struct mv643xx_eth_private, mib_counters.m) }
-#define LROSTAT(m) \
- { #m, FIELD_SIZEOF(struct lro_counters, m), \
- -1, offsetof(struct mv643xx_eth_private, lro_counters.m) }
-
static const struct mv643xx_eth_stats mv643xx_eth_stats[] = {
SSTAT(rx_packets),
SSTAT(tx_packets),
@@ -1464,9 +1273,6 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = {
MIBSTAT(late_collision),
MIBSTAT(rx_discard),
MIBSTAT(rx_overrun),
- LROSTAT(lro_aggregated),
- LROSTAT(lro_flushed),
- LROSTAT(lro_no_desc),
};
static int
@@ -1523,6 +1329,34 @@ mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp,
return 0;
}
+static void
+mv643xx_eth_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct mv643xx_eth_private *mp = netdev_priv(dev);
+ wol->supported = 0;
+ wol->wolopts = 0;
+ if (mp->phy)
+ phy_ethtool_get_wol(mp->phy, wol);
+}
+
+static int
+mv643xx_eth_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct mv643xx_eth_private *mp = netdev_priv(dev);
+ int err;
+
+ if (mp->phy == NULL)
+ return -EOPNOTSUPP;
+
+ err = phy_ethtool_set_wol(mp->phy, wol);
+ /* Given that mv643xx_eth works without the marvell-specific PHY driver,
+ * this debugging hint is useful to have.
+ */
+ if (err == -EOPNOTSUPP)
+ netdev_info(dev, "The PHY does not support set_wol, was CONFIG_MARVELL_PHY enabled?\n");
+ return err;
+}
+
static int
mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -1668,7 +1502,6 @@ static void mv643xx_eth_get_ethtool_stats(struct net_device *dev,
mv643xx_eth_get_stats(dev);
mib_counters_update(mp);
- mv643xx_eth_grab_lro_stats(mp);
for (i = 0; i < ARRAY_SIZE(mv643xx_eth_stats); i++) {
const struct mv643xx_eth_stats *stat;
@@ -1708,6 +1541,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
.get_sset_count = mv643xx_eth_get_sset_count,
.get_ts_info = ethtool_op_get_ts_info,
+ .get_wol = mv643xx_eth_get_wol,
+ .set_wol = mv643xx_eth_set_wol,
};
@@ -1939,19 +1774,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
nexti * sizeof(struct rx_desc);
}
- rxq->lro_mgr.dev = mp->dev;
- memset(&rxq->lro_mgr.stats, 0, sizeof(rxq->lro_mgr.stats));
- rxq->lro_mgr.features = LRO_F_NAPI;
- rxq->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
- rxq->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
- rxq->lro_mgr.max_desc = ARRAY_SIZE(rxq->lro_arr);
- rxq->lro_mgr.max_aggr = 32;
- rxq->lro_mgr.frag_align_pad = 0;
- rxq->lro_mgr.lro_arr = rxq->lro_arr;
- rxq->lro_mgr.get_skb_header = mv643xx_get_skb_header;
-
- memset(&rxq->lro_arr, 0, sizeof(rxq->lro_arr));
-
return 0;
@@ -2635,66 +2457,26 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
struct mv643xx_eth_shared_private *msp;
const struct mbus_dram_target_info *dram;
struct resource *res;
- int ret;
if (!mv643xx_eth_version_printed++)
pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n",
mv643xx_eth_driver_version);
- ret = -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
- goto out;
+ return -EINVAL;
- ret = -ENOMEM;
- msp = kzalloc(sizeof(*msp), GFP_KERNEL);
+ msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL);
if (msp == NULL)
- goto out;
+ return -ENOMEM;
msp->base = ioremap(res->start, resource_size(res));
if (msp->base == NULL)
- goto out_free;
-
- /*
- * Set up and register SMI bus.
- */
- if (pd == NULL || pd->shared_smi == NULL) {
- msp->smi_bus = mdiobus_alloc();
- if (msp->smi_bus == NULL)
- goto out_unmap;
-
- msp->smi_bus->priv = msp;
- msp->smi_bus->name = "mv643xx_eth smi";
- msp->smi_bus->read = smi_bus_read;
- msp->smi_bus->write = smi_bus_write,
- snprintf(msp->smi_bus->id, MII_BUS_ID_SIZE, "%s-%d",
- pdev->name, pdev->id);
- msp->smi_bus->parent = &pdev->dev;
- msp->smi_bus->phy_mask = 0xffffffff;
- if (mdiobus_register(msp->smi_bus) < 0)
- goto out_free_mii_bus;
- msp->smi = msp;
- } else {
- msp->smi = platform_get_drvdata(pd->shared_smi);
- }
-
- msp->err_interrupt = NO_IRQ;
- init_waitqueue_head(&msp->smi_busy_wait);
+ return -ENOMEM;
- /*
- * Check whether the error interrupt is hooked up.
- */
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res != NULL) {
- int err;
-
- err = request_irq(res->start, mv643xx_eth_err_irq,
- IRQF_SHARED, "mv643xx_eth", msp);
- if (!err) {
- writel(ERR_INT_SMI_DONE, msp->base + ERR_INT_MASK);
- msp->err_interrupt = res->start;
- }
- }
+ msp->clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(msp->clk))
+ clk_prepare_enable(msp->clk);
/*
* (Re-)program MBUS remapping windows if we are asked to.
@@ -2710,30 +2492,15 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, msp);
return 0;
-
-out_free_mii_bus:
- mdiobus_free(msp->smi_bus);
-out_unmap:
- iounmap(msp->base);
-out_free:
- kfree(msp);
-out:
- return ret;
}
static int mv643xx_eth_shared_remove(struct platform_device *pdev)
{
struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
- struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
- if (pd == NULL || pd->shared_smi == NULL) {
- mdiobus_unregister(msp->smi_bus);
- mdiobus_free(msp->smi_bus);
- }
- if (msp->err_interrupt != NO_IRQ)
- free_irq(msp->err_interrupt, msp);
iounmap(msp->base);
- kfree(msp);
+ if (!IS_ERR(msp->clk))
+ clk_disable_unprepare(msp->clk);
return 0;
}
@@ -2794,14 +2561,21 @@ static void set_params(struct mv643xx_eth_private *mp,
mp->txq_count = pd->tx_queue_count ? : 1;
}
+static void mv643xx_eth_adjust_link(struct net_device *dev)
+{
+ struct mv643xx_eth_private *mp = netdev_priv(dev);
+
+ mv643xx_adjust_pscr(mp);
+}
+
static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
int phy_addr)
{
- struct mii_bus *bus = mp->shared->smi->smi_bus;
struct phy_device *phydev;
int start;
int num;
int i;
+ char phy_id[MII_BUS_ID_SIZE + 3];
if (phy_addr == MV643XX_ETH_PHY_ADDR_DEFAULT) {
start = phy_addr_get(mp) & 0x1f;
@@ -2811,17 +2585,19 @@ static struct phy_device *phy_scan(struct mv643xx_eth_private *mp,
num = 1;
}
- phydev = NULL;
+ /* Attempt to connect to the PHY using orion-mdio */
+ phydev = ERR_PTR(-ENODEV);
for (i = 0; i < num; i++) {
int addr = (start + i) & 0x1f;
- if (bus->phy_map[addr] == NULL)
- mdiobus_scan(bus, addr);
+ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
+ "orion-mdio-mii", addr);
- if (phydev == NULL) {
- phydev = bus->phy_map[addr];
- if (phydev != NULL)
- phy_addr_set(mp, addr);
+ phydev = phy_connect(mp->dev, phy_id, mv643xx_eth_adjust_link,
+ PHY_INTERFACE_MODE_GMII);
+ if (!IS_ERR(phydev)) {
+ phy_addr_set(mp, addr);
+ break;
}
}
@@ -2834,8 +2610,6 @@ static void phy_init(struct mv643xx_eth_private *mp, int speed, int duplex)
phy_reset(mp);
- phy_attach(mp->dev, dev_name(&phy->dev), PHY_INTERFACE_MODE_GMII);
-
if (speed == 0) {
phy->autoneg = AUTONEG_ENABLE;
phy->speed = 0;
@@ -2932,22 +2706,27 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
* it to override the default.
*/
mp->t_clk = 133000000;
-#if defined(CONFIG_HAVE_CLK)
- mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0"));
+ mp->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(mp->clk)) {
clk_prepare_enable(mp->clk);
mp->t_clk = clk_get_rate(mp->clk);
}
-#endif
+
set_params(mp, pd);
netif_set_real_num_tx_queues(dev, mp->txq_count);
netif_set_real_num_rx_queues(dev, mp->rxq_count);
- if (pd->phy_addr != MV643XX_ETH_PHY_NONE)
+ if (pd->phy_addr != MV643XX_ETH_PHY_NONE) {
mp->phy = phy_scan(mp, pd->phy_addr);
- if (mp->phy != NULL)
+ if (IS_ERR(mp->phy)) {
+ err = PTR_ERR(mp->phy);
+ if (err == -ENODEV)
+ err = -EPROBE_DEFER;
+ goto out;
+ }
phy_init(mp, pd->speed, pd->duplex);
+ }
SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
@@ -2982,8 +2761,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->watchdog_timeo = 2 * HZ;
dev->base_addr = 0;
- dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_RXCSUM | NETIF_F_LRO;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM;
@@ -3014,12 +2792,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
return 0;
out:
-#if defined(CONFIG_HAVE_CLK)
- if (!IS_ERR(mp->clk)) {
+ if (!IS_ERR(mp->clk))
clk_disable_unprepare(mp->clk);
- clk_put(mp->clk);
- }
-#endif
free_netdev(dev);
return err;
@@ -3034,12 +2808,8 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
phy_detach(mp->phy);
cancel_work_sync(&mp->tx_timeout_task);
-#if defined(CONFIG_HAVE_CLK)
- if (!IS_ERR(mp->clk)) {
+ if (!IS_ERR(mp->clk))
clk_disable_unprepare(mp->clk);
- clk_put(mp->clk);
- }
-#endif
free_netdev(mp->dev);
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 77b7c80262f4..e2f662660313 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -24,10 +24,14 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/phy.h>
-#include <linux/of_address.h>
-#include <linux/of_mdio.h>
+#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of_mdio.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
#define MVMDIO_SMI_DATA_SHIFT 0
#define MVMDIO_SMI_PHY_ADDR_SHIFT 16
@@ -36,33 +40,59 @@
#define MVMDIO_SMI_WRITE_OPERATION 0
#define MVMDIO_SMI_READ_VALID BIT(27)
#define MVMDIO_SMI_BUSY BIT(28)
+#define MVMDIO_ERR_INT_CAUSE 0x007C
+#define MVMDIO_ERR_INT_SMI_DONE 0x00000010
+#define MVMDIO_ERR_INT_MASK 0x0080
struct orion_mdio_dev {
struct mutex lock;
- void __iomem *smireg;
+ void __iomem *regs;
+ struct clk *clk;
+ /*
+ * If we have access to the error interrupt pin (which is
+ * somewhat misnamed as it not only reflects internal errors
+ * but also reflects SMI completion), use that to wait for
+ * SMI access completion instead of polling the SMI busy bit.
+ */
+ int err_interrupt;
+ wait_queue_head_t smi_busy_wait;
};
+static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
+{
+ return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
+}
+
/* Wait for the SMI unit to be ready for another operation
*/
static int orion_mdio_wait_ready(struct mii_bus *bus)
{
struct orion_mdio_dev *dev = bus->priv;
int count;
- u32 val;
- count = 0;
- while (1) {
- val = readl(dev->smireg);
- if (!(val & MVMDIO_SMI_BUSY))
- break;
+ if (dev->err_interrupt <= 0) {
+ count = 0;
+ while (1) {
+ if (orion_mdio_smi_is_done(dev))
+ break;
- if (count > 100) {
- dev_err(bus->parent, "Timeout: SMI busy for too long\n");
- return -ETIMEDOUT;
- }
+ if (count > 100) {
+ dev_err(bus->parent,
+ "Timeout: SMI busy for too long\n");
+ return -ETIMEDOUT;
+ }
- udelay(10);
- count++;
+ udelay(10);
+ count++;
+ }
+ } else {
+ if (!orion_mdio_smi_is_done(dev)) {
+ wait_event_timeout(dev->smi_busy_wait,
+ orion_mdio_smi_is_done(dev),
+ msecs_to_jiffies(100));
+ if (!orion_mdio_smi_is_done(dev))
+ return -ETIMEDOUT;
+ }
}
return 0;
@@ -87,12 +117,12 @@ static int orion_mdio_read(struct mii_bus *bus, int mii_id,
writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
(regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
MVMDIO_SMI_READ_OPERATION),
- dev->smireg);
+ dev->regs);
/* Wait for the value to become available */
count = 0;
while (1) {
- val = readl(dev->smireg);
+ val = readl(dev->regs);
if (val & MVMDIO_SMI_READ_VALID)
break;
@@ -129,7 +159,7 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id,
(regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
MVMDIO_SMI_WRITE_OPERATION |
(value << MVMDIO_SMI_DATA_SHIFT)),
- dev->smireg);
+ dev->regs);
mutex_unlock(&dev->lock);
@@ -141,13 +171,34 @@ static int orion_mdio_reset(struct mii_bus *bus)
return 0;
}
+static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
+{
+ struct orion_mdio_dev *dev = dev_id;
+
+ if (readl(dev->regs + MVMDIO_ERR_INT_CAUSE) &
+ MVMDIO_ERR_INT_SMI_DONE) {
+ writel(~MVMDIO_ERR_INT_SMI_DONE,
+ dev->regs + MVMDIO_ERR_INT_CAUSE);
+ wake_up(&dev->smi_busy_wait);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
static int orion_mdio_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
struct mii_bus *bus;
struct orion_mdio_dev *dev;
int i, ret;
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No SMI register address given\n");
+ return -ENODEV;
+ }
+
bus = mdiobus_alloc_size(sizeof(struct orion_mdio_dev));
if (!bus) {
dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
@@ -172,36 +223,66 @@ static int orion_mdio_probe(struct platform_device *pdev)
bus->irq[i] = PHY_POLL;
dev = bus->priv;
- dev->smireg = of_iomap(pdev->dev.of_node, 0);
- if (!dev->smireg) {
- dev_err(&pdev->dev, "No SMI register address given in DT\n");
- kfree(bus->irq);
- mdiobus_free(bus);
- return -ENODEV;
+ dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!dev->regs) {
+ dev_err(&pdev->dev, "Unable to remap SMI register\n");
+ ret = -ENODEV;
+ goto out_mdio;
+ }
+
+ init_waitqueue_head(&dev->smi_busy_wait);
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(dev->clk))
+ clk_prepare_enable(dev->clk);
+
+ dev->err_interrupt = platform_get_irq(pdev, 0);
+ if (dev->err_interrupt != -ENXIO) {
+ ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
+ orion_mdio_err_irq,
+ IRQF_SHARED, pdev->name, dev);
+ if (ret)
+ goto out_mdio;
+
+ writel(MVMDIO_ERR_INT_SMI_DONE,
+ dev->regs + MVMDIO_ERR_INT_MASK);
}
mutex_init(&dev->lock);
- ret = of_mdiobus_register(bus, np);
+ if (pdev->dev.of_node)
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ else
+ ret = mdiobus_register(bus);
if (ret < 0) {
dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
- iounmap(dev->smireg);
- kfree(bus->irq);
- mdiobus_free(bus);
- return ret;
+ goto out_mdio;
}
platform_set_drvdata(pdev, bus);
return 0;
+
+out_mdio:
+ if (!IS_ERR(dev->clk))
+ clk_disable_unprepare(dev->clk);
+ kfree(bus->irq);
+ mdiobus_free(bus);
+ return ret;
}
static int orion_mdio_remove(struct platform_device *pdev)
{
struct mii_bus *bus = platform_get_drvdata(pdev);
+ struct orion_mdio_dev *dev = bus->priv;
+
+ writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
mdiobus_unregister(bus);
kfree(bus->irq);
mdiobus_free(bus);
+ if (!IS_ERR(dev->clk))
+ clk_disable_unprepare(dev->clk);
+
return 0;
}
@@ -225,3 +306,4 @@ module_platform_driver(orion_mdio_driver);
MODULE_DESCRIPTION("Marvell MDIO interface driver");
MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:orion-mdio");
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index cd345b8969bc..c96678555233 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -374,7 +374,6 @@ static int rxq_number = 8;
static int txq_number = 8;
static int rxq_def;
-static int txq_def;
#define MVNETA_DRIVER_NAME "mvneta"
#define MVNETA_DRIVER_VERSION "1.0"
@@ -1475,7 +1474,8 @@ error:
static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
{
struct mvneta_port *pp = netdev_priv(dev);
- struct mvneta_tx_queue *txq = &pp->txqs[txq_def];
+ u16 txq_id = skb_get_queue_mapping(skb);
+ struct mvneta_tx_queue *txq = &pp->txqs[txq_id];
struct mvneta_tx_desc *tx_desc;
struct netdev_queue *nq;
int frags = 0;
@@ -1485,7 +1485,7 @@ static int mvneta_tx(struct sk_buff *skb, struct net_device *dev)
goto out;
frags = skb_shinfo(skb)->nr_frags + 1;
- nq = netdev_get_tx_queue(dev, txq_def);
+ nq = netdev_get_tx_queue(dev, txq_id);
/* Get a descriptor for the first part of the packet */
tx_desc = mvneta_txq_next_desc_get(txq);
@@ -1969,13 +1969,8 @@ static int mvneta_rxq_init(struct mvneta_port *pp,
rxq->descs = dma_alloc_coherent(pp->dev->dev.parent,
rxq->size * MVNETA_DESC_ALIGNED_SIZE,
&rxq->descs_phys, GFP_KERNEL);
- if (rxq->descs == NULL) {
- netdev_err(pp->dev,
- "rxq=%d: Can't allocate %d bytes for %d RX descr\n",
- rxq->id, rxq->size * MVNETA_DESC_ALIGNED_SIZE,
- rxq->size);
+ if (rxq->descs == NULL)
return -ENOMEM;
- }
BUG_ON(rxq->descs !=
PTR_ALIGN(rxq->descs, MVNETA_CPU_D_CACHE_LINE_SIZE));
@@ -2029,13 +2024,8 @@ static int mvneta_txq_init(struct mvneta_port *pp,
txq->descs = dma_alloc_coherent(pp->dev->dev.parent,
txq->size * MVNETA_DESC_ALIGNED_SIZE,
&txq->descs_phys, GFP_KERNEL);
- if (txq->descs == NULL) {
- netdev_err(pp->dev,
- "txQ=%d: Can't allocate %d bytes for %d TX descr\n",
- txq->id, txq->size * MVNETA_DESC_ALIGNED_SIZE,
- txq->size);
+ if (txq->descs == NULL)
return -ENOMEM;
- }
/* Make sure descriptor address is cache line size aligned */
BUG_ON(txq->descs !=
@@ -2689,7 +2679,7 @@ static int mvneta_probe(struct platform_device *pdev)
return -EINVAL;
}
- dev = alloc_etherdev_mq(sizeof(struct mvneta_port), 8);
+ dev = alloc_etherdev_mqs(sizeof(struct mvneta_port), txq_number, rxq_number);
if (!dev)
return -ENOMEM;
@@ -2771,16 +2761,17 @@ static int mvneta_probe(struct platform_device *pdev)
netif_napi_add(dev, &pp->napi, mvneta_poll, pp->weight);
+ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->vlan_features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->priv_flags |= IFF_UNICAST_FLT;
+
err = register_netdev(dev);
if (err < 0) {
dev_err(&pdev->dev, "failed to register\n");
goto err_deinit;
}
- dev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
- dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM;
- dev->priv_flags |= IFF_UNICAST_FLT;
-
netdev_info(dev, "mac: %pM\n", dev->dev_addr);
platform_set_drvdata(pdev, pp->dev);
@@ -2843,4 +2834,3 @@ module_param(rxq_number, int, S_IRUGO);
module_param(txq_number, int, S_IRUGO);
module_param(rxq_def, int, S_IRUGO);
-module_param(txq_def, int, S_IRUGO);
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 037ed866c22f..339bb323cb0c 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -584,12 +584,14 @@ static int init_hash_table(struct pxa168_eth_private *pep)
*/
if (pep->htpr == NULL) {
pep->htpr = dma_alloc_coherent(pep->dev->dev.parent,
- HASH_ADDR_TABLE_SIZE,
- &pep->htpr_dma, GFP_KERNEL);
+ HASH_ADDR_TABLE_SIZE,
+ &pep->htpr_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (pep->htpr == NULL)
return -ENOMEM;
+ } else {
+ memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE);
}
- memset(pep->htpr, 0, HASH_ADDR_TABLE_SIZE);
wrl(pep, HTPR, pep->htpr_dma);
return 0;
}
@@ -1023,13 +1025,11 @@ static int rxq_init(struct net_device *dev)
size = pep->rx_ring_size * sizeof(struct rx_desc);
pep->rx_desc_area_size = size;
pep->p_rx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size,
- &pep->rx_desc_dma, GFP_KERNEL);
- if (!pep->p_rx_desc_area) {
- printk(KERN_ERR "%s: Cannot alloc RX ring (size %d bytes)\n",
- dev->name, size);
+ &pep->rx_desc_dma,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!pep->p_rx_desc_area)
goto out;
- }
- memset((void *)pep->p_rx_desc_area, 0, size);
+
/* initialize the next_desc_ptr links in the Rx descriptors ring */
p_rx_desc = pep->p_rx_desc_area;
for (i = 0; i < rx_desc_num; i++) {
@@ -1086,13 +1086,10 @@ static int txq_init(struct net_device *dev)
size = pep->tx_ring_size * sizeof(struct tx_desc);
pep->tx_desc_area_size = size;
pep->p_tx_desc_area = dma_alloc_coherent(pep->dev->dev.parent, size,
- &pep->tx_desc_dma, GFP_KERNEL);
- if (!pep->p_tx_desc_area) {
- printk(KERN_ERR "%s: Cannot allocate Tx Ring (size %d bytes)\n",
- dev->name, size);
+ &pep->tx_desc_dma,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!pep->p_tx_desc_area)
goto out;
- }
- memset((void *)pep->p_tx_desc_area, 0, pep->tx_desc_area_size);
/* Initialize the next_desc_ptr links in the Tx descriptors ring */
p_tx_desc = pep->p_tx_desc_area;
for (i = 0; i < tx_desc_num; i++) {
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index fc07ca35721b..256ae789c143 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -1067,7 +1067,7 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space)
sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp);
sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2);
- tp = space - 2048/8;
+ tp = space - 8192/8;
sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp);
sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4);
} else {
@@ -1421,14 +1421,14 @@ static void sky2_vlan_mode(struct net_device *dev, netdev_features_t features)
struct sky2_hw *hw = sky2->hw;
u16 port = sky2->port;
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
RX_VLAN_STRIP_ON);
else
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
RX_VLAN_STRIP_OFF);
- if (features & NETIF_F_HW_VLAN_TX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_TX) {
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_VLAN_TAG_ON);
@@ -2713,7 +2713,7 @@ static void sky2_rx_tag(struct sky2_port *sky2, u16 length)
struct sk_buff *skb;
skb = sky2->rx_ring[sky2->rx_next].skb;
- __vlan_hwaccel_put_tag(skb, be16_to_cpu(length));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(length));
}
static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
@@ -4406,7 +4406,7 @@ static int sky2_set_features(struct net_device *dev, netdev_features_t features)
if (changed & NETIF_F_RXHASH)
rx_set_rss(dev, features);
- if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+ if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
sky2_vlan_mode(dev, features);
return 0;
@@ -4793,7 +4793,8 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
dev->hw_features |= NETIF_F_RXHASH;
if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) {
- dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features |= SKY2_VLAN_OFFLOADS;
}
diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h
index 615ac63ea860..ec6dcd80152b 100644
--- a/drivers/net/ethernet/marvell/sky2.h
+++ b/drivers/net/ethernet/marvell/sky2.h
@@ -2074,7 +2074,7 @@ enum {
GM_IS_RX_FF_OR = 1<<1, /* Receive FIFO Overrun */
GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */
-#define GMAC_DEF_MSK GM_IS_TX_FF_UR
+#define GMAC_DEF_MSK (GM_IS_TX_FF_UR | GM_IS_RX_FF_OR)
};
/* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */
diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile
index 293127d28b33..3e9c70f15b42 100644
--- a/drivers/net/ethernet/mellanox/mlx4/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx4/Makefile
@@ -6,5 +6,5 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
obj-$(CONFIG_MLX4_EN) += mlx4_en.o
mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
- en_resources.o en_netdev.o en_selftest.o
+ en_resources.o en_netdev.o en_selftest.o en_clock.o
mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index fdc5f23d8e9f..1df56cc50ee9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1490,6 +1490,69 @@ out:
return ret;
}
+static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
+{
+ int port, err;
+ struct mlx4_vport_state *vp_admin;
+ struct mlx4_vport_oper_state *vp_oper;
+
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+ vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
+ vp_oper->state = *vp_admin;
+ if (MLX4_VGT != vp_admin->default_vlan) {
+ err = __mlx4_register_vlan(&priv->dev, port,
+ vp_admin->default_vlan, &(vp_oper->vlan_idx));
+ if (err) {
+ vp_oper->vlan_idx = NO_INDX;
+ mlx4_warn((&priv->dev),
+ "No vlan resorces slave %d, port %d\n",
+ slave, port);
+ return err;
+ }
+ mlx4_dbg((&(priv->dev)), "alloc vlan %d idx %d slave %d port %d\n",
+ (int)(vp_oper->state.default_vlan),
+ vp_oper->vlan_idx, slave, port);
+ }
+ if (vp_admin->spoofchk) {
+ vp_oper->mac_idx = __mlx4_register_mac(&priv->dev,
+ port,
+ vp_admin->mac);
+ if (0 > vp_oper->mac_idx) {
+ err = vp_oper->mac_idx;
+ vp_oper->mac_idx = NO_INDX;
+ mlx4_warn((&priv->dev),
+ "No mac resorces slave %d, port %d\n",
+ slave, port);
+ return err;
+ }
+ mlx4_dbg((&(priv->dev)), "alloc mac %llx idx %d slave %d port %d\n",
+ vp_oper->state.mac, vp_oper->mac_idx, slave, port);
+ }
+ }
+ return 0;
+}
+
+static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave)
+{
+ int port;
+ struct mlx4_vport_oper_state *vp_oper;
+
+ for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+ if (NO_INDX != vp_oper->vlan_idx) {
+ __mlx4_unregister_vlan(&priv->dev,
+ port, vp_oper->vlan_idx);
+ vp_oper->vlan_idx = NO_INDX;
+ }
+ if (NO_INDX != vp_oper->mac_idx) {
+ __mlx4_unregister_mac(&priv->dev, port, vp_oper->mac_idx);
+ vp_oper->mac_idx = NO_INDX;
+ }
+ }
+ return;
+}
+
static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
u16 param, u8 toggle)
{
@@ -1510,6 +1573,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (cmd == MLX4_COMM_CMD_RESET) {
mlx4_warn(dev, "Received reset from slave:%d\n", slave);
slave_state[slave].active = false;
+ mlx4_master_deactivate_admin_state(priv, slave);
for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
slave_state[slave].event_eq[i].eqn = -1;
slave_state[slave].event_eq[i].token = 0;
@@ -1556,6 +1620,8 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
if (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR2)
goto reset_slave;
slave_state[slave].vhcr_dma |= param;
+ if (mlx4_master_activate_admin_state(priv, slave))
+ goto reset_slave;
slave_state[slave].active = true;
mlx4_dispatch_event(dev, MLX4_DEV_EVENT_SLAVE_INIT, slave);
break;
@@ -1732,6 +1798,18 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
if (!priv->mfunc.master.slave_state)
goto err_comm;
+ priv->mfunc.master.vf_admin =
+ kzalloc(dev->num_slaves *
+ sizeof(struct mlx4_vf_admin_state), GFP_KERNEL);
+ if (!priv->mfunc.master.vf_admin)
+ goto err_comm_admin;
+
+ priv->mfunc.master.vf_oper =
+ kzalloc(dev->num_slaves *
+ sizeof(struct mlx4_vf_oper_state), GFP_KERNEL);
+ if (!priv->mfunc.master.vf_oper)
+ goto err_comm_oper;
+
for (i = 0; i < dev->num_slaves; ++i) {
s_state = &priv->mfunc.master.slave_state[i];
s_state->last_cmd = MLX4_COMM_CMD_RESET;
@@ -1752,6 +1830,10 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
goto err_slaves;
}
INIT_LIST_HEAD(&s_state->mcast_filters[port]);
+ priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
+ priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
+ priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
+ priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
}
spin_lock_init(&s_state->lock);
}
@@ -1800,6 +1882,10 @@ err_slaves:
for (port = 1; port <= MLX4_MAX_PORTS; port++)
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
}
+ kfree(priv->mfunc.master.vf_oper);
+err_comm_oper:
+ kfree(priv->mfunc.master.vf_admin);
+err_comm_admin:
kfree(priv->mfunc.master.slave_state);
err_comm:
iounmap(priv->mfunc.comm);
@@ -1837,10 +1923,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE,
&priv->mfunc.vhcr_dma,
GFP_KERNEL);
- if (!priv->mfunc.vhcr) {
- mlx4_err(dev, "Couldn't allocate VHCR.\n");
+ if (!priv->mfunc.vhcr)
goto err_hcr;
- }
}
priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
@@ -1876,6 +1960,8 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]);
}
kfree(priv->mfunc.master.slave_state);
+ kfree(priv->mfunc.master.vf_admin);
+ kfree(priv->mfunc.master.vf_oper);
}
iounmap(priv->mfunc.comm);
@@ -1986,3 +2072,115 @@ u32 mlx4_comm_get_version(void)
{
return ((u32) CMD_CHAN_IF_REV << 8) | (u32) CMD_CHAN_VER;
}
+
+static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
+{
+ if ((vf < 0) || (vf >= dev->num_vfs)) {
+ mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs);
+ return -EINVAL;
+ }
+
+ return vf+1;
+}
+
+int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if (!mlx4_is_master(dev))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ s_info->mac = mac;
+ mlx4_info(dev, "default mac on vf %d port %d to %llX will take afect only after vf restart\n",
+ vf, port, s_info->mac);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
+
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if ((!mlx4_is_master(dev)) ||
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
+ return -EPROTONOSUPPORT;
+
+ if ((vlan > 4095) || (qos > 7))
+ return -EINVAL;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ if ((0 == vlan) && (0 == qos))
+ s_info->default_vlan = MLX4_VGT;
+ else
+ s_info->default_vlan = vlan;
+ s_info->default_qos = qos;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
+
+int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if ((!mlx4_is_master(dev)) ||
+ !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FSM))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ s_info->spoofchk = setting;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_spoofchk);
+
+int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ int slave;
+
+ if (!mlx4_is_master(dev))
+ return -EPROTONOSUPPORT;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ ivf->vf = vf;
+
+ /* need to convert it to a func */
+ ivf->mac[0] = ((s_info->mac >> (5*8)) & 0xff);
+ ivf->mac[1] = ((s_info->mac >> (4*8)) & 0xff);
+ ivf->mac[2] = ((s_info->mac >> (3*8)) & 0xff);
+ ivf->mac[3] = ((s_info->mac >> (2*8)) & 0xff);
+ ivf->mac[4] = ((s_info->mac >> (1*8)) & 0xff);
+ ivf->mac[5] = ((s_info->mac) & 0xff);
+
+ ivf->vlan = s_info->default_vlan;
+ ivf->qos = s_info->default_qos;
+ ivf->tx_rate = s_info->tx_rate;
+ ivf->spoofchk = s_info->spoofchk;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_vf_config);
diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c
index 0706623cfb96..004e4231af67 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cq.c
@@ -240,9 +240,10 @@ static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
__mlx4_cq_free_icm(dev, cqn);
}
-int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
- struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
- unsigned vector, int collapsed)
+int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
+ struct mlx4_mtt *mtt, struct mlx4_uar *uar, u64 db_rec,
+ struct mlx4_cq *cq, unsigned vector, int collapsed,
+ int timestamp_en)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cq_table *cq_table = &priv->cq_table;
@@ -276,6 +277,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
memset(cq_context, 0, sizeof *cq_context);
cq_context->flags = cpu_to_be32(!!collapsed << 18);
+ if (timestamp_en)
+ cq_context->flags |= cpu_to_be32(1 << 19);
+
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
cq_context->comp_eqn = priv->eq_table.eq[vector].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
new file mode 100644
index 000000000000..fd6441071319
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2012 Mellanox Technologies. 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.
+ *
+ */
+
+#include <linux/mlx4/device.h>
+
+#include "mlx4_en.h"
+
+int mlx4_en_timestamp_config(struct net_device *dev, int tx_type, int rx_filter)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int port_up = 0;
+ int err = 0;
+
+ mutex_lock(&mdev->state_lock);
+ if (priv->port_up) {
+ port_up = 1;
+ mlx4_en_stop_port(dev, 1);
+ }
+
+ mlx4_en_free_resources(priv);
+
+ en_warn(priv, "Changing Time Stamp configuration\n");
+
+ priv->hwtstamp_config.tx_type = tx_type;
+ priv->hwtstamp_config.rx_filter = rx_filter;
+
+ if (rx_filter != HWTSTAMP_FILTER_NONE)
+ dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+ else
+ dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+
+ err = mlx4_en_alloc_resources(priv);
+ if (err) {
+ en_err(priv, "Failed reallocating port resources\n");
+ goto out;
+ }
+ if (port_up) {
+ err = mlx4_en_start_port(dev);
+ if (err)
+ en_err(priv, "Failed starting port\n");
+ }
+
+out:
+ mutex_unlock(&mdev->state_lock);
+ netdev_features_change(dev);
+ return err;
+}
+
+/* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
+ */
+static cycle_t mlx4_en_read_clock(const struct cyclecounter *tc)
+{
+ struct mlx4_en_dev *mdev =
+ container_of(tc, struct mlx4_en_dev, cycles);
+ struct mlx4_dev *dev = mdev->dev;
+
+ return mlx4_read_clock(dev) & tc->mask;
+}
+
+u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
+{
+ u64 hi, lo;
+ struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;
+
+ lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo);
+ hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16;
+
+ return hi | lo;
+}
+
+void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
+ struct skb_shared_hwtstamps *hwts,
+ u64 timestamp)
+{
+ u64 nsec;
+
+ nsec = timecounter_cyc2time(&mdev->clock, timestamp);
+
+ memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
+ hwts->hwtstamp = ns_to_ktime(nsec);
+}
+
+void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
+{
+ struct mlx4_dev *dev = mdev->dev;
+ u64 ns;
+
+ memset(&mdev->cycles, 0, sizeof(mdev->cycles));
+ mdev->cycles.read = mlx4_en_read_clock;
+ mdev->cycles.mask = CLOCKSOURCE_MASK(48);
+ /* Using shift to make calculation more accurate. Since current HW
+ * clock frequency is 427 MHz, and cycles are given using a 48 bits
+ * register, the biggest shift when calculating using u64, is 14
+ * (max_cycles * multiplier < 2^64)
+ */
+ mdev->cycles.shift = 14;
+ mdev->cycles.mult =
+ clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
+
+ timecounter_init(&mdev->clock, &mdev->cycles,
+ ktime_to_ns(ktime_get_real()));
+
+ /* Calculate period in seconds to call the overflow watchdog - to make
+ * sure counter is checked at least once every wrap around.
+ */
+ ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask);
+ do_div(ns, NSEC_PER_SEC / 2 / HZ);
+ mdev->overflow_period = ns;
+}
+
+void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
+{
+ bool timeout = time_is_before_jiffies(mdev->last_overflow_check +
+ mdev->overflow_period);
+
+ if (timeout) {
+ timecounter_read(&mdev->clock);
+ mdev->last_overflow_check = jiffies;
+ }
+}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index b8d0854a7ad1..1e6c594d6d04 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -77,6 +77,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
struct mlx4_en_dev *mdev = priv->mdev;
int err = 0;
char name[25];
+ int timestamp_en = 0;
struct cpu_rmap *rmap =
#ifdef CONFIG_RFS_ACCEL
priv->dev->rx_cpu_rmap;
@@ -123,8 +124,13 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
if (!cq->is_tx)
cq->size = priv->rx_ring[cq->ring].actual_size;
- err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar,
- cq->wqres.db.dma, &cq->mcq, cq->vector, 0);
+ if ((cq->is_tx && priv->hwtstamp_config.tx_type) ||
+ (!cq->is_tx && priv->hwtstamp_config.rx_filter))
+ timestamp_en = 1;
+
+ err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt,
+ &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq,
+ cq->vector, 0, timestamp_en);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index b799ab12a291..0f91222ea3d7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -186,7 +186,7 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev,
static u8 mlx4_en_dcbnl_getdcbx(struct net_device *dev)
{
- return DCB_CAP_DCBX_VER_IEEE;
+ return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE;
}
static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode)
@@ -253,3 +253,11 @@ const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = {
.getdcbx = mlx4_en_dcbnl_getdcbx,
.setdcbx = mlx4_en_dcbnl_setdcbx,
};
+
+const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops = {
+ .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc,
+ .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc,
+
+ .getdcbx = mlx4_en_dcbnl_getdcbx,
+ .setdcbx = mlx4_en_dcbnl_setdcbx,
+};
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 00f25b5f297f..bcf4d118e98c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1147,6 +1147,35 @@ out:
return err;
}
+static int mlx4_en_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ int ret;
+
+ ret = ethtool_op_get_ts_info(dev, info);
+ if (ret)
+ return ret;
+
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) {
+ info->so_timestamping |=
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ info->tx_types =
+ (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters =
+ (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_ALL);
+ }
+
+ return ret;
+}
+
const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo,
.get_settings = mlx4_en_get_settings,
@@ -1173,6 +1202,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.set_rxfh_indir = mlx4_en_set_rxfh_indir,
.get_channels = mlx4_en_get_channels,
.set_channels = mlx4_en_set_channels,
+ .get_ts_info = mlx4_en_get_ts_info,
};
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index fc27800e9c38..a5c9df07a7d0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -300,6 +300,11 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
mdev->pndev[i] = NULL;
}
+
+ /* Initialize time stamp mechanism */
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ mlx4_en_init_timestamp(mdev);
+
return mdev;
err_mr:
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index f278b10ef714..a69a908614e6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -356,7 +356,8 @@ static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv)
}
#endif
-static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int mlx4_en_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
@@ -381,7 +382,8 @@ static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
@@ -411,8 +413,8 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
{
- unsigned int i;
- for (i = ETH_ALEN - 1; i; --i) {
+ int i;
+ for (i = ETH_ALEN - 1; i >= 0; --i) {
dst_mac[i] = src_mac & 0xff;
src_mac >>= 8;
}
@@ -1359,6 +1361,27 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
mutex_unlock(&mdev->state_lock);
}
+/* mlx4_en_service_task - Run service task for tasks that needed to be done
+ * periodically
+ */
+static void mlx4_en_service_task(struct work_struct *work)
+{
+ struct delayed_work *delay = to_delayed_work(work);
+ struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
+ service_task);
+ struct mlx4_en_dev *mdev = priv->mdev;
+
+ mutex_lock(&mdev->state_lock);
+ if (mdev->device_up) {
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ mlx4_en_ptp_overflow_check(mdev);
+
+ queue_delayed_work(mdev->workqueue, &priv->service_task,
+ SERVICE_TASK_DELAY);
+ }
+ mutex_unlock(&mdev->state_lock);
+}
+
static void mlx4_en_linkstate(struct work_struct *work)
{
struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
@@ -1863,6 +1886,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
cancel_delayed_work(&priv->stats_task);
+ cancel_delayed_work(&priv->service_task);
/* flush any pending task for this netdev */
flush_workqueue(mdev->workqueue);
@@ -1914,6 +1938,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
+ struct hwtstamp_config config;
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ /* device doesn't support time stamping */
+ if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS))
+ return -EINVAL;
+
+ /* TX HW timestamp */
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ case HWTSTAMP_TX_ON:
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ /* RX HW timestamp */
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
+ config.tx_type = HWTSTAMP_TX_OFF;
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(config)) ? -EFAULT : 0;
+}
+
+static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return mlx4_en_hwtstamp_ioctl(dev, ifr);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int mlx4_en_set_features(struct net_device *netdev,
netdev_features_t features)
{
@@ -1931,77 +2024,40 @@ static int mlx4_en_set_features(struct net_device *netdev,
}
-static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr, u16 flags)
+static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_dev *mdev = priv->mdev->dev;
- int err;
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+ u64 mac_u64 = mlx4_en_mac_to_u64(mac);
- if (!mlx4_is_mfunc(mdev))
- return -EOPNOTSUPP;
-
- /* Hardware does not support aging addresses, allow only
- * permanent addresses if ndm_state is given
- */
- if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
- en_info(priv, "Add FDB only supports static addresses\n");
+ if (!is_valid_ether_addr(mac))
return -EINVAL;
- }
-
- if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
- err = dev_uc_add_excl(dev, addr);
- else if (is_multicast_ether_addr(addr))
- err = dev_mc_add_excl(dev, addr);
- else
- err = -EINVAL;
-
- /* Only return duplicate errors if NLM_F_EXCL is set */
- if (err == -EEXIST && !(flags & NLM_F_EXCL))
- err = 0;
- return err;
+ return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
}
-static int mlx4_en_fdb_del(struct ndmsg *ndm,
- struct nlattr *tb[],
- struct net_device *dev,
- const unsigned char *addr)
+static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_dev *mdev = priv->mdev->dev;
- int err;
-
- if (!mlx4_is_mfunc(mdev))
- return -EOPNOTSUPP;
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
- if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
- en_info(priv, "Del FDB only supports static addresses\n");
- return -EINVAL;
- }
+ return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos);
+}
- if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
- err = dev_uc_del(dev, addr);
- else if (is_multicast_ether_addr(addr))
- err = dev_mc_del(dev, addr);
- else
- err = -EINVAL;
+static int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
- return err;
+ return mlx4_set_vf_spoofchk(mdev->dev, en_priv->port, vf, setting);
}
-static int mlx4_en_fdb_dump(struct sk_buff *skb,
- struct netlink_callback *cb,
- struct net_device *dev, int idx)
+static int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivf)
{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- struct mlx4_dev *mdev = priv->mdev->dev;
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
- if (mlx4_is_mfunc(mdev))
- idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
-
- return idx;
+ return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf);
}
static const struct net_device_ops mlx4_netdev_ops = {
@@ -2014,9 +2070,37 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_set_mac_address = mlx4_en_set_mac,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = mlx4_en_change_mtu,
+ .ndo_do_ioctl = mlx4_en_ioctl,
+ .ndo_tx_timeout = mlx4_en_tx_timeout,
+ .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = mlx4_en_netpoll,
+#endif
+ .ndo_set_features = mlx4_en_set_features,
+ .ndo_setup_tc = mlx4_en_setup_tc,
+#ifdef CONFIG_RFS_ACCEL
+ .ndo_rx_flow_steer = mlx4_en_filter_rfs,
+#endif
+};
+
+static const struct net_device_ops mlx4_netdev_ops_master = {
+ .ndo_open = mlx4_en_open,
+ .ndo_stop = mlx4_en_close,
+ .ndo_start_xmit = mlx4_en_xmit,
+ .ndo_select_queue = mlx4_en_select_queue,
+ .ndo_get_stats = mlx4_en_get_stats,
+ .ndo_set_rx_mode = mlx4_en_set_rx_mode,
+ .ndo_set_mac_address = mlx4_en_set_mac,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = mlx4_en_change_mtu,
.ndo_tx_timeout = mlx4_en_tx_timeout,
.ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid,
+ .ndo_set_vf_mac = mlx4_en_set_vf_mac,
+ .ndo_set_vf_vlan = mlx4_en_set_vf_vlan,
+ .ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk,
+ .ndo_get_vf_config = mlx4_en_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = mlx4_en_netpoll,
#endif
@@ -2025,9 +2109,6 @@ static const struct net_device_ops mlx4_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
#endif
- .ndo_fdb_add = mlx4_en_fdb_add,
- .ndo_fdb_del = mlx4_en_fdb_del,
- .ndo_fdb_dump = mlx4_en_fdb_dump,
};
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
@@ -2088,9 +2169,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
+ INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
#ifdef CONFIG_MLX4_EN_DCB
- if (!mlx4_is_slave(priv->mdev->dev))
- dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
+ if (!mlx4_is_slave(priv->mdev->dev)) {
+ if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
+ dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
+ } else {
+ en_info(priv, "enabling only PFC DCB ops\n");
+ dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops;
+ }
+ }
#endif
for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
@@ -2122,6 +2210,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
spin_lock_init(&priv->filters_lock);
#endif
+ /* Initialize time stamping config */
+ priv->hwtstamp_config.flags = 0;
+ priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
+ priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+
/* Allocate page for receive rings */
err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
@@ -2134,7 +2227,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
/*
* Initialize netdev entry points
*/
- dev->netdev_ops = &mlx4_netdev_ops;
+ if (mlx4_is_master(priv->mdev->dev))
+ dev->netdev_ops = &mlx4_netdev_ops_master;
+ else
+ dev->netdev_ops = &mlx4_netdev_ops;
dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
@@ -2152,8 +2248,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_RXHASH;
dev->features = dev->hw_features | NETIF_F_HIGHDMA |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
dev->hw_features |= NETIF_F_LOOPBACK;
if (mdev->dev->caps.steering_mode ==
@@ -2199,6 +2295,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
mlx4_en_set_default_moderation(priv);
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ queue_delayed_work(mdev->workqueue, &priv->service_task,
+ SERVICE_TASK_DELAY);
+
return 0;
out:
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index 10c24c784b70..91f2b2c43c12 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -42,6 +42,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
int user_prio, struct mlx4_qp_context *context)
{
struct mlx4_en_dev *mdev = priv->mdev;
+ struct net_device *dev = priv->dev;
memset(context, 0, sizeof *context);
context->flags = cpu_to_be32(7 << 16 | rss << MLX4_RSS_QPC_FLAG_OFFSET);
@@ -65,6 +66,8 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->cqn_send = cpu_to_be32(cqn);
context->cqn_recv = cpu_to_be32(cqn);
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);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index c7f856308e1a..02aee1ebd203 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -320,6 +320,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
}
ring->buf = ring->wqres.buf.direct.buf;
+ ring->hwtstamp_rx_filter = priv->hwtstamp_config.rx_filter;
+
return 0;
err_hwq:
@@ -554,6 +556,7 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,
int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_cqe *cqe;
struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring];
struct mlx4_en_rx_alloc *frags;
@@ -565,6 +568,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
int polled = 0;
int ip_summed;
int factor = priv->cqe_factor;
+ u64 timestamp;
if (!priv->port_up)
return 0;
@@ -669,19 +673,27 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
gro_skb->data_len = length;
gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (cqe->vlan_my_qpn &
- cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) {
+ if ((cqe->vlan_my_qpn &
+ cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
+ (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
u16 vid = be16_to_cpu(cqe->sl_vid);
- __vlan_hwaccel_put_tag(gro_skb, vid);
+ __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
}
if (dev->features & NETIF_F_RXHASH)
gro_skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
skb_record_rx_queue(gro_skb, cq->ring);
- napi_gro_frags(&cq->napi);
+ if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
+ timestamp = mlx4_en_get_cqe_ts(cqe);
+ mlx4_en_fill_hwtstamps(mdev,
+ skb_hwtstamps(gro_skb),
+ timestamp);
+ }
+
+ napi_gro_frags(&cq->napi);
goto next;
}
@@ -714,9 +726,16 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
if (dev->features & NETIF_F_RXHASH)
skb->rxhash = be32_to_cpu(cqe->immed_rss_invalid);
- if (be32_to_cpu(cqe->vlan_my_qpn) &
- MLX4_CQE_VLAN_PRESENT_MASK)
- __vlan_hwaccel_put_tag(skb, be16_to_cpu(cqe->sl_vid));
+ if ((be32_to_cpu(cqe->vlan_my_qpn) &
+ MLX4_CQE_VLAN_PRESENT_MASK) &&
+ (dev->features & NETIF_F_HW_VLAN_CTAG_RX))
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid));
+
+ if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
+ timestamp = mlx4_en_get_cqe_ts(cqe);
+ mlx4_en_fill_hwtstamps(mdev, skb_hwtstamps(skb),
+ timestamp);
+ }
/* Push it up the stack */
netif_receive_skb(skb);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
index 3488c6d9e6b5..2448f0d669e6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c
@@ -58,10 +58,9 @@ static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv)
/* build the pkt before xmit */
skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN);
- if (!skb) {
- en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n");
+ if (!skb)
return -ENOMEM;
- }
+
skb_reserve(skb, NET_IP_ALIGN);
ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr));
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 49308cc65ee7..4e6877a032a8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -118,6 +118,8 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
} else
ring->bf_enabled = true;
+ ring->hwtstamp_tx_type = priv->hwtstamp_config.tx_type;
+
return 0;
err_map:
@@ -192,8 +194,9 @@ void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
struct mlx4_en_tx_ring *ring,
- int index, u8 owner)
+ int index, u8 owner, u64 timestamp)
{
+ struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_tx_info *tx_info = &ring->tx_info[index];
struct mlx4_en_tx_desc *tx_desc = ring->buf + index * TXBB_SIZE;
struct mlx4_wqe_data_seg *data = (void *) tx_desc + tx_info->data_offset;
@@ -204,6 +207,12 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
int i;
__be32 *ptr = (__be32 *)tx_desc;
__be32 stamp = cpu_to_be32(STAMP_VAL | (!!owner << STAMP_SHIFT));
+ struct skb_shared_hwtstamps hwts;
+
+ if (timestamp) {
+ mlx4_en_fill_hwtstamps(mdev, &hwts, timestamp);
+ skb_tstamp_tx(skb, &hwts);
+ }
/* Optimize the common case when there are no wraparounds */
if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
@@ -289,7 +298,7 @@ int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring)
while (ring->cons != ring->prod) {
ring->last_nr_txbb = mlx4_en_free_tx_desc(priv, ring,
ring->cons & ring->size_mask,
- !!(ring->cons & ring->size));
+ !!(ring->cons & ring->size), 0);
ring->cons += ring->last_nr_txbb;
cnt++;
}
@@ -318,6 +327,7 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
u32 packets = 0;
u32 bytes = 0;
int factor = priv->cqe_factor;
+ u64 timestamp = 0;
if (!priv->port_up)
return;
@@ -341,11 +351,14 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
do {
txbbs_skipped += ring->last_nr_txbb;
ring_index = (ring_index + ring->last_nr_txbb) & size_mask;
+ if (ring->tx_info[ring_index].ts_requested)
+ timestamp = mlx4_en_get_cqe_ts(cqe);
+
/* free next descriptor */
ring->last_nr_txbb = mlx4_en_free_tx_desc(
priv, ring, ring_index,
!!((ring->cons + txbbs_skipped) &
- ring->size));
+ ring->size), timestamp);
packets++;
bytes += ring->tx_info[ring_index].nr_bytes;
} while (ring_index != new_index);
@@ -629,6 +642,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
tx_info->skb = skb;
tx_info->nr_txbb = nr_txbb;
+ /*
+ * For timestamping add flag to skb_shinfo and
+ * set flag for further reference
+ */
+ if (ring->hwtstamp_tx_type == HWTSTAMP_TX_ON &&
+ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ tx_info->ts_requested = 1;
+ }
+
/* Prepare ctrl segement apart opcode+ownership, which depends on
* whether LSO is used */
tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
@@ -729,6 +752,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
if (bounce)
tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
+ skb_tx_timestamp(skb);
+
if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tx_tag_present(skb)) {
*(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
op_own |= htonl((bf_index & 0xffff) << 8);
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index f6245579962d..b147bdd40768 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -91,7 +91,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[ 8] = "P_Key violation counter",
[ 9] = "Q_Key violation counter",
[10] = "VMM",
- [12] = "DPDP",
+ [12] = "Dual Port Different Protocol (DPDP) support",
[15] = "Big LSO headers",
[16] = "MW support",
[17] = "APM support",
@@ -109,6 +109,8 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[41] = "Unicast VEP steering support",
[42] = "Multicast VEP steering support",
[48] = "Counters support",
+ [53] = "Port ETS Scheduler support",
+ [55] = "Port link type sensing support",
[59] = "Port management change event support",
[61] = "64 byte EQE support",
[62] = "64 byte CQE support",
@@ -128,7 +130,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[1] = "RSS Toeplitz Hash Function support",
[2] = "RSS XOR Hash Function support",
[3] = "Device manage flow steering support",
- [4] = "Automatic mac reassignment support"
+ [4] = "Automatic MAC reassignment support",
+ [5] = "Time stamping support"
};
int i;
@@ -442,6 +445,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38
#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b
#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c
+#define QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET 0x3e
#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f
#define QUERY_DEV_CAP_EXT_FLAGS_OFFSET 0x40
#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44
@@ -464,6 +468,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_RSVD_XRC_OFFSET 0x66
#define QUERY_DEV_CAP_MAX_XRC_OFFSET 0x67
#define QUERY_DEV_CAP_MAX_COUNTERS_OFFSET 0x68
+#define QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET 0x70
#define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76
#define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77
#define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80
@@ -558,6 +563,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->fs_max_num_qp_per_entry = field;
MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
dev_cap->stat_rate_support = stat_rate;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+ if (field & 0x80)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_TS;
MLX4_GET(ext_flags, outbox, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
MLX4_GET(flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
dev_cap->flags = flags | (u64)ext_flags << 32;
@@ -648,6 +656,12 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
MLX4_GET(dev_cap->max_counters, outbox,
QUERY_DEV_CAP_MAX_COUNTERS_OFFSET);
+ MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET);
+ if (field32 & (1 << 26))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL;
+ if (field32 & (1 << 20))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_FSM;
+
if (dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
for (i = 1; i <= dev_cap->num_ports; ++i) {
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
@@ -777,6 +791,11 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
+ /* For guests, disable timestamp */
+ MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+ field &= 0x7f;
+ MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
+
/* For guests, report Blueflame disabled */
MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_BF_OFFSET);
field &= 0x7f;
@@ -804,6 +823,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_cmd_mailbox *outbox,
struct mlx4_cmd_info *cmd)
{
+ struct mlx4_priv *priv = mlx4_priv(dev);
u64 def_mac;
u8 port_type;
u16 short_field;
@@ -821,6 +841,9 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
/* set slave default_mac address */
MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
def_mac += slave << 8;
+ /* if config MAC in DB use it */
+ if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
+ def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
/* get port type - currently only eth is enabled */
@@ -1006,6 +1029,9 @@ int mlx4_QUERY_FW(struct mlx4_dev *dev)
#define QUERY_FW_COMM_BASE_OFFSET 0x40
#define QUERY_FW_COMM_BAR_OFFSET 0x48
+#define QUERY_FW_CLOCK_OFFSET 0x50
+#define QUERY_FW_CLOCK_BAR 0x58
+
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
@@ -1080,6 +1106,12 @@ int mlx4_QUERY_FW(struct mlx4_dev *dev)
fw->comm_bar, fw->comm_base);
mlx4_dbg(dev, "FW size %d KB\n", fw->fw_pages >> 2);
+ MLX4_GET(fw->clock_offset, outbox, QUERY_FW_CLOCK_OFFSET);
+ MLX4_GET(fw->clock_bar, outbox, QUERY_FW_CLOCK_BAR);
+ fw->clock_bar = (fw->clock_bar >> 6) * 2;
+ mlx4_dbg(dev, "Internal clock bar:%d offset:0x%llx\n",
+ fw->clock_bar, fw->clock_offset);
+
/*
* Round up number of system pages needed in case
* MLX4_ICM_PAGE_SIZE < PAGE_SIZE.
@@ -1367,6 +1399,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
u8 byte_field;
#define QUERY_HCA_GLOBAL_CAPS_OFFSET 0x04
+#define QUERY_HCA_CORE_CLOCK_OFFSET 0x0c
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
@@ -1381,6 +1414,7 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev,
goto out;
MLX4_GET(param->global_caps, outbox, QUERY_HCA_GLOBAL_CAPS_OFFSET);
+ MLX4_GET(param->hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
/* QPC/EEC/CQC/EQC/RDMARC attributes */
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index 151c2bb380a6..fdf41665a059 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -162,6 +162,7 @@ struct mlx4_init_hca_param {
u64 global_caps;
u16 log_mc_entry_sz;
u16 log_mc_hash_sz;
+ u16 hca_core_clock; /* Internal Clock Frequency (in MHz) */
u8 log_num_qps;
u8 log_num_srqs;
u8 log_num_cqs;
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 16abde20e1fc..0d32a82458bf 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -513,6 +513,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz;
+ dev->caps.hca_core_clock = hca_param.hca_core_clock;
+
memset(&dev_cap, 0, sizeof(dev_cap));
dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp;
err = mlx4_dev_cap(dev, &dev_cap);
@@ -1226,8 +1228,53 @@ static void unmap_bf_area(struct mlx4_dev *dev)
io_mapping_free(mlx4_priv(dev)->bf_mapping);
}
+cycle_t mlx4_read_clock(struct mlx4_dev *dev)
+{
+ u32 clockhi, clocklo, clockhi1;
+ cycle_t cycles;
+ int i;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ for (i = 0; i < 10; i++) {
+ clockhi = swab32(readl(priv->clock_mapping));
+ clocklo = swab32(readl(priv->clock_mapping + 4));
+ clockhi1 = swab32(readl(priv->clock_mapping));
+ if (clockhi == clockhi1)
+ break;
+ }
+
+ cycles = (u64) clockhi << 32 | (u64) clocklo;
+
+ return cycles;
+}
+EXPORT_SYMBOL_GPL(mlx4_read_clock);
+
+
+static int map_internal_clock(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ priv->clock_mapping =
+ ioremap(pci_resource_start(dev->pdev, priv->fw.clock_bar) +
+ priv->fw.clock_offset, MLX4_CLOCK_SIZE);
+
+ if (!priv->clock_mapping)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void unmap_internal_clock(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ if (priv->clock_mapping)
+ iounmap(priv->clock_mapping);
+}
+
static void mlx4_close_hca(struct mlx4_dev *dev)
{
+ unmap_internal_clock(dev);
unmap_bf_area(dev);
if (mlx4_is_slave(dev))
mlx4_slave_exit(dev);
@@ -1445,6 +1492,37 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
mlx4_err(dev, "INIT_HCA command failed, aborting.\n");
goto err_free_icm;
}
+ /*
+ * If TS is supported by FW
+ * read HCA frequency by QUERY_HCA command
+ */
+ if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) {
+ memset(&init_hca, 0, sizeof(init_hca));
+ err = mlx4_QUERY_HCA(dev, &init_hca);
+ if (err) {
+ mlx4_err(dev, "QUERY_HCA command failed, disable timestamp.\n");
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
+ } else {
+ dev->caps.hca_core_clock =
+ init_hca.hca_core_clock;
+ }
+
+ /* In case we got HCA frequency 0 - disable timestamping
+ * to avoid dividing by zero
+ */
+ if (!dev->caps.hca_core_clock) {
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
+ mlx4_err(dev,
+ "HCA frequency is 0. Timestamping is not supported.");
+ } else if (map_internal_clock(dev)) {
+ /*
+ * Map internal clock,
+ * in case of failure disable timestamping
+ */
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
+ mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported.\n");
+ }
+ }
} else {
err = mlx4_init_slave(dev);
if (err) {
@@ -1478,6 +1556,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
return 0;
unmap_bf:
+ unmap_internal_clock(dev);
unmap_bf_area(dev);
err_close:
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 52685524708d..ffc78d2cb0cf 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -1125,28 +1125,11 @@ static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
return err;
}
-int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
- u8 port, int block_mcast_loopback,
- enum mlx4_protocol prot, u64 *reg_id)
+int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ u8 gid[16], u8 port,
+ int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id)
{
-
- switch (dev->caps.steering_mode) {
- case MLX4_STEERING_MODE_A0:
- if (prot == MLX4_PROT_ETH)
- return 0;
-
- case MLX4_STEERING_MODE_B0:
- if (prot == MLX4_PROT_ETH)
- gid[7] |= (MLX4_MC_STEER << 1);
-
- if (mlx4_is_mfunc(dev))
- return mlx4_QP_ATTACH(dev, qp, gid, 1,
- block_mcast_loopback, prot);
- return mlx4_qp_attach_common(dev, qp, gid,
- block_mcast_loopback, prot,
- MLX4_MC_STEER);
-
- case MLX4_STEERING_MODE_DEVICE_MANAGED: {
struct mlx4_spec_list spec = { {NULL} };
__be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
@@ -1180,8 +1163,32 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
list_add_tail(&spec.list, &rule.list);
return mlx4_flow_attach(dev, &rule, reg_id);
- }
+}
+int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ u8 port, int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_A0:
+ if (prot == MLX4_PROT_ETH)
+ return 0;
+
+ case MLX4_STEERING_MODE_B0:
+ if (prot == MLX4_PROT_ETH)
+ gid[7] |= (MLX4_MC_STEER << 1);
+
+ if (mlx4_is_mfunc(dev))
+ return mlx4_QP_ATTACH(dev, qp, gid, 1,
+ block_mcast_loopback, prot);
+ return mlx4_qp_attach_common(dev, qp, gid,
+ block_mcast_loopback, prot,
+ MLX4_MC_STEER);
+
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
+ block_mcast_loopback,
+ prot, reg_id);
default:
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index d738454116a0..eac3dae10efe 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -87,7 +87,8 @@ enum {
MLX4_HCR_SIZE = 0x0001c,
MLX4_CLR_INT_SIZE = 0x00008,
MLX4_SLAVE_COMM_BASE = 0x0,
- MLX4_COMM_PAGESIZE = 0x1000
+ MLX4_COMM_PAGESIZE = 0x1000,
+ MLX4_CLOCK_SIZE = 0x00008
};
enum {
@@ -403,6 +404,7 @@ struct mlx4_fw {
u64 clr_int_base;
u64 catas_offset;
u64 comm_base;
+ u64 clock_offset;
struct mlx4_icm *fw_icm;
struct mlx4_icm *aux_icm;
u32 catas_size;
@@ -410,6 +412,7 @@ struct mlx4_fw {
u8 clr_int_bar;
u8 catas_bar;
u8 comm_bar;
+ u8 clock_bar;
};
struct mlx4_comm {
@@ -470,6 +473,30 @@ struct mlx4_slave_state {
enum slave_port_state port_state[MLX4_MAX_PORTS + 1];
};
+#define MLX4_VGT 4095
+#define NO_INDX (-1)
+
+struct mlx4_vport_state {
+ u64 mac;
+ u16 default_vlan;
+ u8 default_qos;
+ u32 tx_rate;
+ bool spoofchk;
+};
+
+struct mlx4_vf_admin_state {
+ struct mlx4_vport_state vport[MLX4_MAX_PORTS + 1];
+};
+
+struct mlx4_vport_oper_state {
+ struct mlx4_vport_state state;
+ int mac_idx;
+ int vlan_idx;
+};
+struct mlx4_vf_oper_state {
+ struct mlx4_vport_oper_state vport[MLX4_MAX_PORTS + 1];
+};
+
struct slave_list {
struct mutex mutex;
struct list_head res_list[MLX4_NUM_OF_RESOURCE_TYPE];
@@ -500,6 +527,8 @@ struct mlx4_master_qp0_state {
struct mlx4_mfunc_master_ctx {
struct mlx4_slave_state *slave_state;
+ struct mlx4_vf_admin_state *vf_admin;
+ struct mlx4_vf_oper_state *vf_oper;
struct mlx4_master_qp0_state qp0_state[MLX4_MAX_PORTS + 1];
int init_port_ref[MLX4_MAX_PORTS + 1];
u16 max_mtu[MLX4_MAX_PORTS + 1];
@@ -826,6 +855,7 @@ struct mlx4_priv {
struct list_head bf_list;
struct mutex bf_mutex;
struct io_mapping *bf_mapping;
+ void __iomem *clock_mapping;
int reserved_mtts;
int fs_hash_mode;
u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
@@ -1127,6 +1157,8 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index);
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz);
/* resource tracker functions*/
@@ -1190,6 +1222,10 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
int block_mcast_loopback, enum mlx4_protocol prot,
enum mlx4_steer_type steer);
+int mlx4_trans_to_dmfs_attach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ u8 gid[16], u8 port,
+ int block_mcast_loopback,
+ enum mlx4_protocol prot, u64 *reg_id);
int mlx4_SET_MCAST_FLTR_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index f710b7ce0dcb..b1d7657b2bf5 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -40,6 +40,7 @@
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
#ifdef CONFIG_MLX4_EN_DCB
#include <linux/dcbnl.h>
#endif
@@ -77,6 +78,7 @@
#define STAMP_SHIFT 31
#define STAMP_VAL 0x7fffffff
#define STATS_DELAY (HZ / 4)
+#define SERVICE_TASK_DELAY (HZ / 4)
#define MAX_NUM_OF_FS_RULES 256
#define MLX4_EN_FILTER_HASH_SHIFT 4
@@ -207,6 +209,7 @@ struct mlx4_en_tx_info {
u8 linear;
u8 data_offset;
u8 inl;
+ u8 ts_requested;
};
@@ -262,6 +265,7 @@ struct mlx4_en_tx_ring {
struct mlx4_bf bf;
bool bf_enabled;
struct netdev_queue *tx_queue;
+ int hwtstamp_tx_type;
};
struct mlx4_en_rx_desc {
@@ -288,6 +292,7 @@ struct mlx4_en_rx_ring {
unsigned long packets;
unsigned long csum_ok;
unsigned long csum_none;
+ int hwtstamp_rx_filter;
};
struct mlx4_en_cq {
@@ -348,6 +353,10 @@ struct mlx4_en_dev {
u32 priv_pdn;
spinlock_t uar_lock;
u8 mac_removed[MLX4_MAX_PORTS + 1];
+ struct cyclecounter cycles;
+ struct timecounter clock;
+ unsigned long last_overflow_check;
+ unsigned long overflow_period;
};
@@ -512,6 +521,7 @@ struct mlx4_en_priv {
struct work_struct watchdog_task;
struct work_struct linkstate_task;
struct delayed_work stats_task;
+ struct delayed_work service_task;
struct mlx4_en_perf_stats pstats;
struct mlx4_en_pkt_stats pkstats;
struct mlx4_en_port_stats port_stats;
@@ -525,6 +535,7 @@ struct mlx4_en_priv {
struct device *ddev;
int base_tx_qpn;
struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
+ struct hwtstamp_config hwtstamp_config;
#ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets;
@@ -624,6 +635,7 @@ int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
#ifdef CONFIG_MLX4_EN_DCB
extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops;
+extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_pfc_ops;
#endif
int mlx4_en_setup_tc(struct net_device *dev, u8 up);
@@ -636,9 +648,21 @@ void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv,
#define MLX4_EN_NUM_SELF_TEST 5
void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
u64 mlx4_en_mac_to_u64(u8 *addr);
+void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev);
/*
- * Globals
+ * Functions for time stamping
+ */
+u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe);
+void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
+ struct skb_shared_hwtstamps *hwts,
+ u64 timestamp);
+void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev);
+int mlx4_en_timestamp_config(struct net_device *dev,
+ int tx_type,
+ int rx_filter);
+
+/* Globals
*/
extern const struct ethtool_ops mlx4_en_ethtool_ops;
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 10c57c86388b..946e0af5faef 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -32,6 +32,7 @@
#include <linux/errno.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <linux/export.h>
#include <linux/mlx4/cmd.h>
@@ -140,8 +141,9 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
}
if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
- /* MAC already registered, Must not have duplicates */
- err = -EEXIST;
+ /* MAC already registered, increment ref count */
+ err = i;
+ ++table->refs[i];
goto out;
}
}
@@ -164,7 +166,7 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
table->entries[free] = 0;
goto out;
}
-
+ table->refs[free] = 1;
err = free;
++table->total;
out:
@@ -205,12 +207,16 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
struct mlx4_mac_table *table = &info->mac_table;
int index;
- index = find_index(dev, table, mac);
-
mutex_lock(&table->mutex);
+ index = find_index(dev, table, mac);
if (validate_index(dev, table, index))
goto out;
+ if (--table->refs[index]) {
+ mlx4_dbg(dev, "Have more references for index %d,"
+ "no need to modify mac table\n", index);
+ goto out;
+ }
table->entries[index] = 0;
mlx4_set_port_mac_table(dev, port, table->entries);
@@ -304,7 +310,7 @@ int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
}
EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
-static int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
int *index)
{
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -378,7 +384,7 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
}
EXPORT_SYMBOL_GPL(mlx4_register_vlan);
-static void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
{
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -517,7 +523,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
/* Mtu is configured as the max MTU among all the
* the functions on the port. */
mtu = be16_to_cpu(gen_context->mtu);
- mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port]);
+ mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
+ ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
prev_mtu = slave_st->mtu[port];
slave_st->mtu[port] = mtu;
if (mtu > master->max_mtu[port])
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 1391b52f443a..e12e0d2e0ee0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -75,6 +75,7 @@ struct res_gid {
u8 gid[16];
enum mlx4_protocol prot;
enum mlx4_steer_type steer;
+ u64 reg_id;
};
enum res_qp_states {
@@ -352,6 +353,47 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
}
}
+static int update_vport_qp_param(struct mlx4_dev *dev,
+ struct mlx4_cmd_mailbox *inbox,
+ u8 slave)
+{
+ struct mlx4_qp_context *qpc = inbox->buf + 8;
+ struct mlx4_vport_oper_state *vp_oper;
+ struct mlx4_priv *priv;
+ u32 qp_type;
+ int port;
+
+ port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
+ priv = mlx4_priv(dev);
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+ if (MLX4_VGT != vp_oper->state.default_vlan) {
+ qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+ if (MLX4_QP_ST_RC == qp_type)
+ return -EINVAL;
+
+ qpc->pri_path.vlan_index = vp_oper->vlan_idx;
+ qpc->pri_path.fl = (1 << 6) | (1 << 2); /* set cv bit and hide_cqe_vlan bit*/
+ qpc->pri_path.feup |= 1 << 3; /* set fvl bit */
+ qpc->pri_path.sched_queue &= 0xC7;
+ qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
+ mlx4_dbg(dev, "qp %d port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n",
+ be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+ (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan,
+ vp_oper->vlan_idx, (int)(qpc->pri_path.feup),
+ (int)(qpc->pri_path.fl));
+ }
+ if (vp_oper->state.spoofchk) {
+ qpc->pri_path.feup |= 1 << 5; /* set fsm bit */;
+ qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
+ mlx4_dbg(dev, "spoof qp %d port %d feup 0x%x, myLmc 0x%x mindx %d\n",
+ be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
+ (int)qpc->pri_path.feup, (int)qpc->pri_path.grh_mylmc,
+ vp_oper->mac_idx);
+ }
+ return 0;
+}
+
static int mpt_mask(struct mlx4_dev *dev)
{
return dev->caps.num_mpts - 1;
@@ -2797,6 +2839,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
update_pkey_index(dev, slave, inbox);
update_gid(dev, inbox, (u8)slave);
adjust_proxy_tun_qkey(dev, vhcr, qpc);
+ err = update_vport_qp_param(dev, inbox, slave);
+ if (err)
+ return err;
return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
}
@@ -2934,7 +2979,7 @@ static struct res_gid *find_gid(struct mlx4_dev *dev, int slave,
static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
u8 *gid, enum mlx4_protocol prot,
- enum mlx4_steer_type steer)
+ enum mlx4_steer_type steer, u64 reg_id)
{
struct res_gid *res;
int err;
@@ -2951,6 +2996,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
memcpy(res->gid, gid, 16);
res->prot = prot;
res->steer = steer;
+ res->reg_id = reg_id;
list_add_tail(&res->list, &rqp->mcg_list);
err = 0;
}
@@ -2961,7 +3007,7 @@ static int add_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
u8 *gid, enum mlx4_protocol prot,
- enum mlx4_steer_type steer)
+ enum mlx4_steer_type steer, u64 *reg_id)
{
struct res_gid *res;
int err;
@@ -2971,6 +3017,7 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
if (!res || res->prot != prot || res->steer != steer)
err = -EINVAL;
else {
+ *reg_id = res->reg_id;
list_del(&res->list);
kfree(res);
err = 0;
@@ -2980,6 +3027,37 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
return err;
}
+static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ int block_loopback, enum mlx4_protocol prot,
+ enum mlx4_steer_type type, u64 *reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5],
+ block_loopback, prot,
+ reg_id);
+ case MLX4_STEERING_MODE_B0:
+ return mlx4_qp_attach_common(dev, qp, gid,
+ block_loopback, prot, type);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
+ enum mlx4_protocol prot, enum mlx4_steer_type type,
+ u64 reg_id)
+{
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ return mlx4_flow_detach(dev, reg_id);
+ case MLX4_STEERING_MODE_B0:
+ return mlx4_qp_detach_common(dev, qp, gid, prot, type);
+ default:
+ return -EINVAL;
+ }
+}
+
int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
@@ -2992,14 +3070,12 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
int err;
int qpn;
struct res_qp *rqp;
+ u64 reg_id = 0;
int attach = vhcr->op_modifier;
int block_loopback = vhcr->in_modifier >> 31;
u8 steer_type_mask = 2;
enum mlx4_steer_type type = (gid[7] & steer_type_mask) >> 1;
- if (dev->caps.steering_mode != MLX4_STEERING_MODE_B0)
- return -EINVAL;
-
qpn = vhcr->in_modifier & 0xffffff;
err = get_res(dev, slave, qpn, RES_QP, &rqp);
if (err)
@@ -3007,30 +3083,32 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
qp.qpn = qpn;
if (attach) {
- err = add_mcg_res(dev, slave, rqp, gid, prot, type);
- if (err)
+ err = qp_attach(dev, &qp, gid, block_loopback, prot,
+ type, &reg_id);
+ if (err) {
+ pr_err("Fail to attach rule to qp 0x%x\n", qpn);
goto ex_put;
-
- err = mlx4_qp_attach_common(dev, &qp, gid,
- block_loopback, prot, type);
+ }
+ err = add_mcg_res(dev, slave, rqp, gid, prot, type, reg_id);
if (err)
- goto ex_rem;
+ goto ex_detach;
} else {
- err = rem_mcg_res(dev, slave, rqp, gid, prot, type);
+ err = rem_mcg_res(dev, slave, rqp, gid, prot, type, &reg_id);
if (err)
goto ex_put;
- err = mlx4_qp_detach_common(dev, &qp, gid, prot, type);
- }
+ err = qp_detach(dev, &qp, gid, prot, type, reg_id);
+ if (err)
+ pr_err("Fail to detach rule from qp 0x%x reg_id = 0x%llx\n",
+ qpn, reg_id);
+ }
put_res(dev, slave, qpn, RES_QP);
- return 0;
+ return err;
-ex_rem:
- /* ignore error return below, already in error */
- (void) rem_mcg_res(dev, slave, rqp, gid, prot, type);
+ex_detach:
+ qp_detach(dev, &qp, gid, prot, type, reg_id);
ex_put:
put_res(dev, slave, qpn, RES_QP);
-
return err;
}
@@ -3266,9 +3344,16 @@ static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
struct mlx4_qp qp; /* dummy for calling attach/detach */
list_for_each_entry_safe(rgid, tmp, &rqp->mcg_list, list) {
- qp.qpn = rqp->local_qpn;
- (void) mlx4_qp_detach_common(dev, &qp, rgid->gid, rgid->prot,
- rgid->steer);
+ switch (dev->caps.steering_mode) {
+ case MLX4_STEERING_MODE_DEVICE_MANAGED:
+ mlx4_flow_detach(dev, rgid->reg_id);
+ break;
+ case MLX4_STEERING_MODE_B0:
+ qp.qpn = rqp->local_qpn;
+ (void) mlx4_qp_detach_common(dev, &qp, rgid->gid,
+ rgid->prot, rgid->steer);
+ break;
+ }
list_del(&rgid->list);
kfree(rgid);
}
diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c
index 07a6ebc47c92..b6c60fdef4ff 100644
--- a/drivers/net/ethernet/micrel/ks8695net.c
+++ b/drivers/net/ethernet/micrel/ks8695net.c
@@ -1622,25 +1622,7 @@ static struct platform_driver ks8695_driver = {
.resume = ks8695_drv_resume,
};
-/* Module interface */
-
-static int __init
-ks8695_init(void)
-{
- printk(KERN_INFO "%s Ethernet driver, V%s\n",
- MODULENAME, MODULEVERSION);
-
- return platform_driver_register(&ks8695_driver);
-}
-
-static void __exit
-ks8695_cleanup(void)
-{
- platform_driver_unregister(&ks8695_driver);
-}
-
-module_init(ks8695_init);
-module_exit(ks8695_cleanup);
+module_platform_driver(ks8695_driver);
MODULE_AUTHOR("Simtec Electronics");
MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver");
diff --git a/drivers/net/ethernet/micrel/ks8851.c b/drivers/net/ethernet/micrel/ks8851.c
index 33bcb63d56a2..727b546a9eb8 100644
--- a/drivers/net/ethernet/micrel/ks8851.c
+++ b/drivers/net/ethernet/micrel/ks8851.c
@@ -528,7 +528,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
for (; rxfc != 0; rxfc--) {
rxh = ks8851_rdreg32(ks, KS_RXFHSR);
rxstat = rxh & 0xffff;
- rxlen = rxh >> 16;
+ rxlen = (rxh >> 16) & 0xfff;
netif_dbg(ks, rx_status, ks->netdev,
"rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen);
@@ -1364,37 +1364,37 @@ static int ks8851_read_selftest(struct ks8851_net *ks)
/* driver bus management functions */
-#ifdef CONFIG_PM
-static int ks8851_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+
+static int ks8851_suspend(struct device *dev)
{
- struct ks8851_net *ks = dev_get_drvdata(&spi->dev);
- struct net_device *dev = ks->netdev;
+ struct ks8851_net *ks = dev_get_drvdata(dev);
+ struct net_device *netdev = ks->netdev;
- if (netif_running(dev)) {
- netif_device_detach(dev);
- ks8851_net_stop(dev);
+ if (netif_running(netdev)) {
+ netif_device_detach(netdev);
+ ks8851_net_stop(netdev);
}
return 0;
}
-static int ks8851_resume(struct spi_device *spi)
+static int ks8851_resume(struct device *dev)
{
- struct ks8851_net *ks = dev_get_drvdata(&spi->dev);
- struct net_device *dev = ks->netdev;
+ struct ks8851_net *ks = dev_get_drvdata(dev);
+ struct net_device *netdev = ks->netdev;
- if (netif_running(dev)) {
- ks8851_net_open(dev);
- netif_device_attach(dev);
+ if (netif_running(netdev)) {
+ ks8851_net_open(netdev);
+ netif_device_attach(netdev);
}
return 0;
}
-#else
-#define ks8851_suspend NULL
-#define ks8851_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ks8851_pm_ops, ks8851_suspend, ks8851_resume);
+
static int ks8851_probe(struct spi_device *spi)
{
struct net_device *ndev;
@@ -1456,7 +1456,7 @@ static int ks8851_probe(struct spi_device *spi)
SET_ETHTOOL_OPS(ndev, &ks8851_ethtool_ops);
SET_NETDEV_DEV(ndev, &spi->dev);
- dev_set_drvdata(&spi->dev, ks);
+ spi_set_drvdata(spi, ks);
ndev->if_port = IF_PORT_100BASET;
ndev->netdev_ops = &ks8851_netdev_ops;
@@ -1516,7 +1516,7 @@ err_irq:
static int ks8851_remove(struct spi_device *spi)
{
- struct ks8851_net *priv = dev_get_drvdata(&spi->dev);
+ struct ks8851_net *priv = spi_get_drvdata(spi);
if (netif_msg_drv(priv))
dev_info(&spi->dev, "remove\n");
@@ -1532,25 +1532,12 @@ static struct spi_driver ks8851_driver = {
.driver = {
.name = "ks8851",
.owner = THIS_MODULE,
+ .pm = &ks8851_pm_ops,
},
.probe = ks8851_probe,
.remove = ks8851_remove,
- .suspend = ks8851_suspend,
- .resume = ks8851_resume,
};
-
-static int __init ks8851_init(void)
-{
- return spi_register_driver(&ks8851_driver);
-}
-
-static void __exit ks8851_exit(void)
-{
- spi_unregister_driver(&ks8851_driver);
-}
-
-module_init(ks8851_init);
-module_exit(ks8851_exit);
+module_spi_driver(ks8851_driver);
MODULE_DESCRIPTION("KS8851 Network driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index a343066f7b43..ddaf138ce0d4 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -792,20 +792,35 @@ static void ks_rcv(struct ks_net *ks, struct net_device *netdev)
frame_hdr = ks->frame_head_info;
while (ks->frame_cnt--) {
+ if (unlikely(!(frame_hdr->sts & RXFSHR_RXFV) ||
+ frame_hdr->len >= RX_BUF_SIZE ||
+ frame_hdr->len <= 0)) {
+
+ /* discard an invalid packet */
+ ks_wrreg16(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
+ netdev->stats.rx_dropped++;
+ if (!(frame_hdr->sts & RXFSHR_RXFV))
+ netdev->stats.rx_frame_errors++;
+ else
+ netdev->stats.rx_length_errors++;
+ frame_hdr++;
+ continue;
+ }
+
skb = netdev_alloc_skb(netdev, frame_hdr->len + 16);
- if (likely(skb && (frame_hdr->sts & RXFSHR_RXFV) &&
- (frame_hdr->len < RX_BUF_SIZE) && frame_hdr->len)) {
+ if (likely(skb)) {
skb_reserve(skb, 2);
/* read data block including CRC 4 bytes */
ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len);
- skb_put(skb, frame_hdr->len);
+ skb_put(skb, frame_hdr->len - 4);
skb->protocol = eth_type_trans(skb, netdev);
netif_rx(skb);
+ /* exclude CRC size */
+ netdev->stats.rx_bytes += frame_hdr->len - 4;
+ netdev->stats.rx_packets++;
} else {
- pr_err("%s: err:skb alloc\n", __func__);
ks_wrreg16(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
- if (skb)
- dev_kfree_skb_irq(skb);
+ netdev->stats.rx_dropped++;
}
frame_hdr++;
}
@@ -877,6 +892,8 @@ static irqreturn_t ks_irq(int irq, void *pw)
ks_wrreg16(ks, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
}
+ if (unlikely(status & IRQ_RXOI))
+ ks->netdev->stats.rx_over_errors++;
/* this should be the last in IRQ handler*/
ks_restore_cmd_reg(ks);
return IRQ_HANDLED;
@@ -1015,6 +1032,9 @@ static int ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
if (likely(ks_tx_fifo_space(ks) >= skb->len + 12)) {
ks_write_qmu(ks, skb->data, skb->len);
+ /* add tx statistics */
+ netdev->stats.tx_bytes += skb->len;
+ netdev->stats.tx_packets++;
dev_kfree_skb(skb);
} else
retv = NETDEV_TX_BUSY;
diff --git a/drivers/net/ethernet/microchip/enc28j60.c b/drivers/net/ethernet/microchip/enc28j60.c
index 5d98a9f7bfc7..c7b40aa21f22 100644
--- a/drivers/net/ethernet/microchip/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -1566,7 +1566,7 @@ static int enc28j60_probe(struct spi_device *spi)
INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler);
INIT_WORK(&priv->irq_work, enc28j60_irq_work_handler);
INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler);
- dev_set_drvdata(&spi->dev, priv); /* spi to priv reference */
+ spi_set_drvdata(spi, priv); /* spi to priv reference */
SET_NETDEV_DEV(dev, &spi->dev);
if (!enc28j60_chipset_init(dev)) {
@@ -1618,7 +1618,7 @@ error_alloc:
static int enc28j60_remove(struct spi_device *spi)
{
- struct enc28j60_net *priv = dev_get_drvdata(&spi->dev);
+ struct enc28j60_net *priv = spi_get_drvdata(spi);
if (netif_msg_drv(priv))
printk(KERN_DEBUG DRV_NAME ": remove\n");
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index 4f9937e026e5..7be9788ed0f6 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -1281,7 +1281,8 @@ myri10ge_vlan_rx(struct net_device *dev, void *addr, struct sk_buff *skb)
va = addr;
va += MXGEFW_PAD;
veh = (struct vlan_ethhdr *)va;
- if ((dev->features & NETIF_F_HW_VLAN_RX) == NETIF_F_HW_VLAN_RX &&
+ if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) ==
+ NETIF_F_HW_VLAN_CTAG_RX &&
veh->h_vlan_proto == htons(ETH_P_8021Q)) {
/* fixup csum if needed */
if (skb->ip_summed == CHECKSUM_COMPLETE) {
@@ -1289,7 +1290,7 @@ myri10ge_vlan_rx(struct net_device *dev, void *addr, struct sk_buff *skb)
skb->csum = csum_sub(skb->csum, vsum);
}
/* pop tag */
- __vlan_hwaccel_put_tag(skb, ntohs(veh->h_vlan_TCI));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(veh->h_vlan_TCI));
memmove(va + VLAN_HLEN, va, 2 * ETH_ALEN);
skb->len -= VLAN_HLEN;
skb->data_len -= VLAN_HLEN;
@@ -3592,10 +3593,9 @@ static int myri10ge_alloc_slices(struct myri10ge_priv *mgp)
bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry);
ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
&ss->rx_done.bus,
- GFP_KERNEL);
+ GFP_KERNEL | __GFP_ZERO);
if (ss->rx_done.entry == NULL)
goto abort;
- memset(ss->rx_done.entry, 0, bytes);
bytes = sizeof(*ss->fw_stats);
ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes,
&ss->fw_stats_bus,
@@ -3888,8 +3888,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->mtu = myri10ge_initial_mtu;
netdev->hw_features = mgp->features | NETIF_F_RXCSUM;
- /* fake NETIF_F_HW_VLAN_RX for good GRO performance */
- netdev->hw_features |= NETIF_F_HW_VLAN_RX;
+ /* fake NETIF_F_HW_VLAN_CTAG_RX for good GRO performance */
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
netdev->features = netdev->hw_features;
diff --git a/drivers/net/ethernet/natsemi/jazzsonic.c b/drivers/net/ethernet/natsemi/jazzsonic.c
index b0b361546365..c20766c2f65b 100644
--- a/drivers/net/ethernet/natsemi/jazzsonic.c
+++ b/drivers/net/ethernet/natsemi/jazzsonic.c
@@ -175,13 +175,13 @@ static int sonic_probe1(struct net_device *dev)
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
- if ((lp->descriptors = dma_alloc_coherent(lp->device,
- SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
- &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
- dev_name(lp->device));
+ lp->descriptors = dma_alloc_coherent(lp->device,
+ SIZEOF_SONIC_DESC *
+ SONIC_BUS_SCALE(lp->dma_bitmode),
+ &lp->descriptors_laddr,
+ GFP_KERNEL);
+ if (lp->descriptors == NULL)
goto out;
- }
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->descriptors;
diff --git a/drivers/net/ethernet/natsemi/macsonic.c b/drivers/net/ethernet/natsemi/macsonic.c
index 0ffde69c8d01..346a4e025c34 100644
--- a/drivers/net/ethernet/natsemi/macsonic.c
+++ b/drivers/net/ethernet/natsemi/macsonic.c
@@ -202,13 +202,13 @@ static int macsonic_init(struct net_device *dev)
/* Allocate the entire chunk of memory for the descriptors.
Note that this cannot cross a 64K boundary. */
- if ((lp->descriptors = dma_alloc_coherent(lp->device,
- SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
- &lp->descriptors_laddr, GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n",
- dev_name(lp->device));
+ lp->descriptors = dma_alloc_coherent(lp->device,
+ SIZEOF_SONIC_DESC *
+ SONIC_BUS_SCALE(lp->dma_bitmode),
+ &lp->descriptors_laddr,
+ GFP_KERNEL);
+ if (lp->descriptors == NULL)
return -ENOMEM;
- }
/* Now set up the pointers to point to the appropriate places */
lp->cda = lp->descriptors;
diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c
index 77c070de621e..d3b47003a575 100644
--- a/drivers/net/ethernet/natsemi/ns83820.c
+++ b/drivers/net/ethernet/natsemi/ns83820.c
@@ -911,7 +911,7 @@ static void rx_irq(struct net_device *ndev)
unsigned short tag;
tag = ntohs(extsts & EXTSTS_VTG_MASK);
- __vlan_hwaccel_put_tag(skb, tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_IPV6), tag);
}
#endif
rx_rc = netif_rx(skb);
@@ -2193,7 +2193,7 @@ static int ns83820_init_one(struct pci_dev *pci_dev,
#ifdef NS83820_VLAN_ACCEL_SUPPORT
/* We also support hardware vlan acceleration */
- ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
#endif
if (using_dac) {
diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c
index 46795e403467..1bd419dbda6d 100644
--- a/drivers/net/ethernet/natsemi/sonic.c
+++ b/drivers/net/ethernet/natsemi/sonic.c
@@ -424,7 +424,6 @@ static void sonic_rx(struct net_device *dev)
/* Malloc up new buffer. */
new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
if (new_skb == NULL) {
- printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
diff --git a/drivers/net/ethernet/natsemi/xtsonic.c b/drivers/net/ethernet/natsemi/xtsonic.c
index 5e4748e855f6..c2e0256fe3df 100644
--- a/drivers/net/ethernet/natsemi/xtsonic.c
+++ b/drivers/net/ethernet/natsemi/xtsonic.c
@@ -197,14 +197,12 @@ static int __init sonic_probe1(struct net_device *dev)
* We also allocate extra space for a pointer to allow freeing
* this structure later on (in xtsonic_cleanup_module()).
*/
- lp->descriptors =
- dma_alloc_coherent(lp->device,
- SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
- &lp->descriptors_laddr, GFP_KERNEL);
-
+ lp->descriptors = dma_alloc_coherent(lp->device,
+ SIZEOF_SONIC_DESC *
+ SONIC_BUS_SCALE(lp->dma_bitmode),
+ &lp->descriptors_laddr,
+ GFP_KERNEL);
if (lp->descriptors == NULL) {
- printk(KERN_ERR "%s: couldn't alloc DMA memory for "
- " descriptors.\n", dev_name(lp->device));
err = -ENOMEM;
goto out;
}
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index bfd887382e19..51b00941302c 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -80,6 +80,7 @@
#include <linux/slab.h>
#include <linux/prefetch.h>
#include <net/tcp.h>
+#include <net/checksum.h>
#include <asm/div64.h>
#include <asm/irq.h>
@@ -7919,7 +7920,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_RXCSUM | NETIF_F_LRO;
dev->features |= dev->hw_features |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
if (sp->device_type & XFRAME_II_DEVICE) {
dev->hw_features |= NETIF_F_UFO;
if (ufo)
@@ -8337,16 +8338,13 @@ static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
{
struct iphdr *ip = lro->iph;
struct tcphdr *tcp = lro->tcph;
- __sum16 nchk;
struct swStat *swstats = &sp->mac_control.stats_info->sw_stat;
DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__);
/* Update L3 header */
+ csum_replace2(&ip->check, ip->tot_len, htons(lro->total_len));
ip->tot_len = htons(lro->total_len);
- ip->check = 0;
- nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
- ip->check = nchk;
/* Update L4 header */
tcp->ack_seq = lro->tcp_ack;
@@ -8557,7 +8555,7 @@ static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag)
skb->protocol = eth_type_trans(skb, dev);
if (vlan_tag && sp->vlan_strip_flag)
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
if (sp->config.napi)
netif_receive_skb(skb);
else
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index 794444e09492..cbfaed5f2f8d 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -312,7 +312,7 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
if (ext_info->vlan &&
ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)
- __vlan_hwaccel_put_tag(skb, ext_info->vlan);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ext_info->vlan);
napi_gro_receive(ring->napi_p, skb);
vxge_debug_entryexit(VXGE_TRACE,
@@ -3300,12 +3300,13 @@ static void vxge_tx_watchdog(struct net_device *dev)
/**
* vxge_vlan_rx_add_vid
* @dev: net device pointer.
+ * @proto: vlan protocol
* @vid: vid
*
* Add the vlan id to the devices vlan id table
*/
static int
-vxge_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+vxge_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct vxgedev *vdev = netdev_priv(dev);
struct vxge_vpath *vpath;
@@ -3323,14 +3324,15 @@ vxge_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
}
/**
- * vxge_vlan_rx_add_vid
+ * vxge_vlan_rx_kill_vid
* @dev: net device pointer.
+ * @proto: vlan protocol
* @vid: vid
*
* Remove the vlan id from the device's vlan id table
*/
static int
-vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+vxge_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct vxgedev *vdev = netdev_priv(dev);
struct vxge_vpath *vpath;
@@ -3415,12 +3417,12 @@ static int vxge_device_register(struct __vxge_hw_device *hldev,
ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6 |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_TX;
if (vdev->config.rth_steering != NO_STEERING)
ndev->hw_features |= NETIF_F_RXHASH;
ndev->features |= ndev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->netdev_ops = &vxge_netdev_ops;
diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c
index 63e7af44366f..cb9e63831500 100644
--- a/drivers/net/ethernet/netx-eth.c
+++ b/drivers/net/ethernet/netx-eth.c
@@ -152,8 +152,6 @@ static void netx_eth_receive(struct net_device *ndev)
skb = netdev_alloc_skb(ndev, len);
if (unlikely(skb == NULL)) {
- printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
- ndev->name);
ndev->stats.rx_dropped++;
return;
}
diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
index 162da8975b05..3df8287b7452 100644
--- a/drivers/net/ethernet/nuvoton/w90p910_ether.c
+++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c
@@ -287,23 +287,16 @@ static int w90p910_init_desc(struct net_device *dev)
ether = netdev_priv(dev);
pdev = ether->pdev;
- ether->tdesc = (struct tran_pdesc *)
- dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
- &ether->tdesc_phys, GFP_KERNEL);
-
- if (!ether->tdesc) {
- dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
+ ether->tdesc = dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
+ &ether->tdesc_phys, GFP_KERNEL);
+ if (!ether->tdesc)
return -ENOMEM;
- }
-
- ether->rdesc = (struct recv_pdesc *)
- dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
- &ether->rdesc_phys, GFP_KERNEL);
+ ether->rdesc = dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
+ &ether->rdesc_phys, GFP_KERNEL);
if (!ether->rdesc) {
- dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
- ether->tdesc, ether->tdesc_phys);
+ ether->tdesc, ether->tdesc_phys);
return -ENOMEM;
}
@@ -737,7 +730,6 @@ static void netdev_rx(struct net_device *dev)
data = ether->rdesc->recv_buf[ether->cur_rx];
skb = netdev_alloc_skb(dev, length + 2);
if (!skb) {
- dev_err(&pdev->dev, "get skb buffer error\n");
ether->stats.rx_dropped++;
return;
}
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index 0b8de12bcbca..b003fe53c8e2 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -2200,6 +2200,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ring_desc *start_tx;
struct ring_desc *prev_tx;
struct nv_skb_map *prev_tx_ctx;
+ struct nv_skb_map *tmp_tx_ctx = NULL, *start_tx_ctx = NULL;
unsigned long flags;
/* add fragments to entries count */
@@ -2261,12 +2262,31 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
do {
prev_tx = put_tx;
prev_tx_ctx = np->put_tx_ctx;
+ if (!start_tx_ctx)
+ start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx;
+
bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size;
np->put_tx_ctx->dma = skb_frag_dma_map(
&np->pci_dev->dev,
frag, offset,
bcnt,
DMA_TO_DEVICE);
+ if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) {
+
+ /* Unwind the mapped fragments */
+ do {
+ nv_unmap_txskb(np, start_tx_ctx);
+ if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
+ tmp_tx_ctx = np->first_tx_ctx;
+ } while (tmp_tx_ctx != np->put_tx_ctx);
+ kfree_skb(skb);
+ np->put_tx_ctx = start_tx_ctx;
+ u64_stats_update_begin(&np->swstats_tx_syncp);
+ np->stat_tx_dropped++;
+ u64_stats_update_end(&np->swstats_tx_syncp);
+ return NETDEV_TX_OK;
+ }
+
np->put_tx_ctx->dma_len = bcnt;
np->put_tx_ctx->dma_single = 0;
put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
@@ -2327,7 +2347,8 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
struct ring_desc_ex *start_tx;
struct ring_desc_ex *prev_tx;
struct nv_skb_map *prev_tx_ctx;
- struct nv_skb_map *start_tx_ctx;
+ struct nv_skb_map *start_tx_ctx = NULL;
+ struct nv_skb_map *tmp_tx_ctx = NULL;
unsigned long flags;
/* add fragments to entries count */
@@ -2392,11 +2413,29 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
prev_tx = put_tx;
prev_tx_ctx = np->put_tx_ctx;
bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size;
+ if (!start_tx_ctx)
+ start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx;
np->put_tx_ctx->dma = skb_frag_dma_map(
&np->pci_dev->dev,
frag, offset,
bcnt,
DMA_TO_DEVICE);
+
+ if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) {
+
+ /* Unwind the mapped fragments */
+ do {
+ nv_unmap_txskb(np, start_tx_ctx);
+ if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
+ tmp_tx_ctx = np->first_tx_ctx;
+ } while (tmp_tx_ctx != np->put_tx_ctx);
+ kfree_skb(skb);
+ np->put_tx_ctx = start_tx_ctx;
+ u64_stats_update_begin(&np->swstats_tx_syncp);
+ np->stat_tx_dropped++;
+ u64_stats_update_end(&np->swstats_tx_syncp);
+ return NETDEV_TX_OK;
+ }
np->put_tx_ctx->dma_len = bcnt;
np->put_tx_ctx->dma_single = 0;
put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
@@ -2922,15 +2961,15 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
/*
- * There's need to check for NETIF_F_HW_VLAN_RX here.
- * Even if vlan rx accel is disabled,
+ * There's need to check for NETIF_F_HW_VLAN_CTAG_RX
+ * here. Even if vlan rx accel is disabled,
* NV_RX3_VLAN_TAG_PRESENT is pseudo randomly set.
*/
- if (dev->features & NETIF_F_HW_VLAN_RX &&
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX &&
vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
u16 vid = vlanflags & NV_RX3_VLAN_TAG_MASK;
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
napi_gro_receive(&np->napi, skb);
u64_stats_update_begin(&np->swstats_rx_syncp);
@@ -4777,7 +4816,7 @@ static netdev_features_t nv_fix_features(struct net_device *dev,
netdev_features_t features)
{
/* vlan is dependent on rx checksum offload */
- if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+ if (features & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
features |= NETIF_F_RXCSUM;
return features;
@@ -4789,12 +4828,12 @@ static void nv_vlan_mode(struct net_device *dev, netdev_features_t features)
spin_lock_irq(&np->lock);
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
np->txrxctl_bits |= NVREG_TXRXCTL_VLANSTRIP;
else
np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANSTRIP;
- if (features & NETIF_F_HW_VLAN_TX)
+ if (features & NETIF_F_HW_VLAN_CTAG_TX)
np->txrxctl_bits |= NVREG_TXRXCTL_VLANINS;
else
np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANINS;
@@ -4831,7 +4870,7 @@ static int nv_set_features(struct net_device *dev, netdev_features_t features)
spin_unlock_irq(&np->lock);
}
- if (changed & (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX))
+ if (changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX))
nv_vlan_mode(dev, features);
return 0;
@@ -5025,7 +5064,6 @@ static int nv_loopback_test(struct net_device *dev)
pkt_len = ETH_DATA_LEN;
tx_skb = netdev_alloc_skb(dev, pkt_len);
if (!tx_skb) {
- netdev_err(dev, "netdev_alloc_skb() failed during loopback test\n");
ret = 0;
goto out;
}
@@ -5667,7 +5705,8 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
np->vlanctl_bits = 0;
if (id->driver_data & DEV_HAS_VLAN) {
np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE;
- dev->hw_features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
+ dev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_TX;
}
dev->features |= dev->hw_features;
@@ -5958,7 +5997,8 @@ static int nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
"csum " : "",
- dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
+ dev->features & (NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_TX) ?
"vlan " : "",
dev->features & (NETIF_F_LOOPBACK) ?
"loopback " : "",
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index efa29b712d5f..55a5548d6add 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -1409,9 +1409,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
dma_alloc_coherent(&pldat->pdev->dev,
pldat->dma_buff_size, &dma_handle,
GFP_KERNEL);
-
if (pldat->dma_buff_base_v == NULL) {
- dev_err(&pdev->dev, "error getting DMA region.\n");
ret = -ENOMEM;
goto err_out_free_irq;
}
@@ -1434,13 +1432,11 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
/* Get MAC address from current HW setting (POR state is all zeros) */
__lpc_get_mac(pldat, ndev->dev_addr);
-#ifdef CONFIG_OF_NET
if (!is_valid_ether_addr(ndev->dev_addr)) {
const char *macaddr = of_get_mac_address(pdev->dev.of_node);
if (macaddr)
memcpy(ndev->dev_addr, macaddr, ETH_ALEN);
}
-#endif
if (!is_valid_ether_addr(ndev->dev_addr))
eth_hw_addr_random(ndev);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 73ce7dd6b954..0c1c65a9ce5e 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -1469,13 +1469,11 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter,
size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY;
rx_ring->rx_buff_pool = dma_alloc_coherent(&pdev->dev, size,
- &rx_ring->rx_buff_pool_logic,
- GFP_KERNEL);
- if (!rx_ring->rx_buff_pool) {
- pr_err("Unable to allocate memory for the receive pool buffer\n");
+ &rx_ring->rx_buff_pool_logic,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!rx_ring->rx_buff_pool)
return -ENOMEM;
- }
- memset(rx_ring->rx_buff_pool, 0, size);
+
rx_ring->rx_buff_pool_size = size;
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
@@ -1774,13 +1772,12 @@ int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter,
tx_ring->size = tx_ring->count * (int)sizeof(struct pch_gbe_tx_desc);
tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
- &tx_ring->dma, GFP_KERNEL);
+ &tx_ring->dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!tx_ring->desc) {
vfree(tx_ring->buffer_info);
- pr_err("Unable to allocate memory for the transmit descriptor ring\n");
return -ENOMEM;
}
- memset(tx_ring->desc, 0, tx_ring->size);
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
@@ -1820,14 +1817,12 @@ int pch_gbe_setup_rx_resources(struct pch_gbe_adapter *adapter,
rx_ring->size = rx_ring->count * (int)sizeof(struct pch_gbe_rx_desc);
rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
- &rx_ring->dma, GFP_KERNEL);
-
+ &rx_ring->dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!rx_ring->desc) {
- pr_err("Unable to allocate memory for the receive descriptor ring\n");
vfree(rx_ring->buffer_info);
return -ENOMEM;
}
- memset(rx_ring->desc, 0, rx_ring->size);
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
for (desNo = 0; desNo < rx_ring->count; desNo++) {
@@ -2268,7 +2263,7 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
if (err) {
adapter->rx_buffer_len = old_rx_buffer_len;
pch_gbe_up(adapter);
- return -ENOMEM;
+ return err;
} else {
netdev->mtu = new_mtu;
adapter->hw.mac.max_frame_size = max_frame;
diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c
index b1cfbb75ff1e..a5f0b5da6149 100644
--- a/drivers/net/ethernet/pasemi/pasemi_mac.c
+++ b/drivers/net/ethernet/pasemi/pasemi_mac.c
@@ -441,12 +441,11 @@ static int pasemi_mac_setup_rx_resources(const struct net_device *dev)
ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
RX_RING_SIZE * sizeof(u64),
- &ring->buf_dma, GFP_KERNEL);
+ &ring->buf_dma,
+ GFP_KERNEL | __GFP_ZERO);
if (!ring->buffers)
goto out_ring_desc;
- memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
-
write_dma_reg(PAS_DMA_RXCHAN_BASEL(chno),
PAS_DMA_RXCHAN_BASEL_BRBL(ring->chan.ring_dma));
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index a8669adecc97..0e1797295a48 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -35,6 +35,16 @@ config QLCNIC
This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet
devices.
+config QLCNIC_SRIOV
+ bool "QLOGIC QLCNIC 83XX family SR-IOV Support"
+ depends on QLCNIC && PCI_IOV
+ default y
+ ---help---
+ This configuration parameter enables Single Root Input Output
+ Virtualization support for QLE83XX Converged Ethernet devices.
+ This allows for virtual function acceleration in virtualized
+ environments.
+
config QLGE
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
depends on PCI
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index eb3dfdbb642b..322a36b76727 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -955,9 +955,10 @@ typedef struct nx_mac_list_s {
uint8_t mac_addr[ETH_ALEN+2];
} nx_mac_list_t;
-struct nx_vlan_ip_list {
+struct nx_ip_list {
struct list_head list;
__be32 ip_addr;
+ bool master;
};
/*
@@ -1605,7 +1606,7 @@ struct netxen_adapter {
struct net_device *netdev;
struct pci_dev *pdev;
struct list_head mac_list;
- struct list_head vlan_ip_list;
+ struct list_head ip_list;
spinlock_t tx_clean_lock;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 4782dcfde736..7692dfd4f262 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/if_vlan.h>
+#include <net/checksum.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
@@ -1641,9 +1642,8 @@ netxen_process_lro(struct netxen_adapter *adapter,
th = (struct tcphdr *)((skb->data + vhdr_len) + (iph->ihl << 2));
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ csum_replace2(&iph->check, iph->tot_len, htons(length));
iph->tot_len = htons(length);
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
th->psh = push;
th->seq = htonl(seq_number);
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index 501f49207da5..af951f343ff6 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -90,7 +90,7 @@ static irqreturn_t netxen_intr(int irq, void *data);
static irqreturn_t netxen_msi_intr(int irq, void *data);
static irqreturn_t netxen_msix_intr(int irq, void *data);
-static void netxen_free_vlan_ip_list(struct netxen_adapter *);
+static void netxen_free_ip_list(struct netxen_adapter *, bool);
static void netxen_restore_indev_addr(struct net_device *dev, unsigned long);
static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *stats);
@@ -1345,7 +1345,7 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
}
if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
- netdev->hw_features |= NETIF_F_HW_VLAN_TX;
+ netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)
netdev->hw_features |= NETIF_F_LRO;
@@ -1450,7 +1450,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
- INIT_LIST_HEAD(&adapter->vlan_ip_list);
+ INIT_LIST_HEAD(&adapter->ip_list);
err = netxen_setup_pci_map(adapter);
if (err)
@@ -1585,7 +1585,7 @@ static void netxen_nic_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->tx_timeout_task);
- netxen_free_vlan_ip_list(adapter);
+ netxen_free_ip_list(adapter, false);
netxen_nic_detach(adapter);
nx_decr_dev_ref_cnt(adapter);
@@ -3137,62 +3137,77 @@ netxen_destip_supported(struct netxen_adapter *adapter)
}
static void
-netxen_free_vlan_ip_list(struct netxen_adapter *adapter)
+netxen_free_ip_list(struct netxen_adapter *adapter, bool master)
{
- struct nx_vlan_ip_list *cur;
- struct list_head *head = &adapter->vlan_ip_list;
+ struct nx_ip_list *cur, *tmp_cur;
- while (!list_empty(head)) {
- cur = list_entry(head->next, struct nx_vlan_ip_list, list);
- netxen_config_ipaddr(adapter, cur->ip_addr, NX_IP_DOWN);
- list_del(&cur->list);
- kfree(cur);
+ list_for_each_entry_safe(cur, tmp_cur, &adapter->ip_list, list) {
+ if (master) {
+ if (cur->master) {
+ netxen_config_ipaddr(adapter, cur->ip_addr,
+ NX_IP_DOWN);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+ } else {
+ netxen_config_ipaddr(adapter, cur->ip_addr, NX_IP_DOWN);
+ list_del(&cur->list);
+ kfree(cur);
+ }
}
-
}
-static void
-netxen_list_config_vlan_ip(struct netxen_adapter *adapter,
+
+static bool
+netxen_list_config_ip(struct netxen_adapter *adapter,
struct in_ifaddr *ifa, unsigned long event)
{
struct net_device *dev;
- struct nx_vlan_ip_list *cur, *tmp_cur;
+ struct nx_ip_list *cur, *tmp_cur;
struct list_head *head;
+ bool ret = false;
dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
if (dev == NULL)
- return;
-
- if (!is_vlan_dev(dev))
- return;
+ goto out;
switch (event) {
case NX_IP_UP:
- list_for_each(head, &adapter->vlan_ip_list) {
- cur = list_entry(head, struct nx_vlan_ip_list, list);
+ list_for_each(head, &adapter->ip_list) {
+ cur = list_entry(head, struct nx_ip_list, list);
if (cur->ip_addr == ifa->ifa_address)
- return;
+ goto out;
}
- cur = kzalloc(sizeof(struct nx_vlan_ip_list), GFP_ATOMIC);
+ cur = kzalloc(sizeof(struct nx_ip_list), GFP_ATOMIC);
if (cur == NULL)
- return;
-
+ goto out;
+ if (dev->priv_flags & IFF_802_1Q_VLAN)
+ dev = vlan_dev_real_dev(dev);
+ cur->master = !!netif_is_bond_master(dev);
cur->ip_addr = ifa->ifa_address;
- list_add_tail(&cur->list, &adapter->vlan_ip_list);
+ list_add_tail(&cur->list, &adapter->ip_list);
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+ ret = true;
break;
case NX_IP_DOWN:
list_for_each_entry_safe(cur, tmp_cur,
- &adapter->vlan_ip_list, list) {
+ &adapter->ip_list, list) {
if (cur->ip_addr == ifa->ifa_address) {
list_del(&cur->list);
kfree(cur);
+ netxen_config_ipaddr(adapter, ifa->ifa_address,
+ NX_IP_DOWN);
+ ret = true;
break;
}
}
}
+out:
+ return ret;
}
+
static void
netxen_config_indev_addr(struct netxen_adapter *adapter,
struct net_device *dev, unsigned long event)
@@ -3209,14 +3224,10 @@ netxen_config_indev_addr(struct netxen_adapter *adapter,
for_ifa(indev) {
switch (event) {
case NETDEV_UP:
- netxen_config_ipaddr(adapter,
- ifa->ifa_address, NX_IP_UP);
- netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP);
+ netxen_list_config_ip(adapter, ifa, NX_IP_UP);
break;
case NETDEV_DOWN:
- netxen_config_ipaddr(adapter,
- ifa->ifa_address, NX_IP_DOWN);
- netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
+ netxen_list_config_ip(adapter, ifa, NX_IP_DOWN);
break;
default:
break;
@@ -3231,23 +3242,78 @@ netxen_restore_indev_addr(struct net_device *netdev, unsigned long event)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
- struct nx_vlan_ip_list *pos, *tmp_pos;
+ struct nx_ip_list *pos, *tmp_pos;
unsigned long ip_event;
ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN;
netxen_config_indev_addr(adapter, netdev, event);
- list_for_each_entry_safe(pos, tmp_pos, &adapter->vlan_ip_list, list) {
+ list_for_each_entry_safe(pos, tmp_pos, &adapter->ip_list, list) {
netxen_config_ipaddr(adapter, pos->ip_addr, ip_event);
}
}
+static inline bool
+netxen_config_checkdev(struct net_device *dev)
+{
+ struct netxen_adapter *adapter;
+
+ if (!is_netxen_netdev(dev))
+ return false;
+ adapter = netdev_priv(dev);
+ if (!adapter)
+ return false;
+ if (!netxen_destip_supported(adapter))
+ return false;
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ return false;
+
+ return true;
+}
+
+/**
+ * netxen_config_master - configure addresses based on master
+ * @dev: netxen device
+ * @event: netdev event
+ */
+static void netxen_config_master(struct net_device *dev, unsigned long event)
+{
+ struct net_device *master, *slave;
+ struct netxen_adapter *adapter = netdev_priv(dev);
+
+ rcu_read_lock();
+ master = netdev_master_upper_dev_get_rcu(dev);
+ /*
+ * This is the case where the netxen nic is being
+ * enslaved and is dev_open()ed in bond_enslave()
+ * Now we should program the bond's (and its vlans')
+ * addresses in the netxen NIC.
+ */
+ if (master && netif_is_bond_master(master) &&
+ !netif_is_bond_slave(dev)) {
+ netxen_config_indev_addr(adapter, master, event);
+ for_each_netdev_rcu(&init_net, slave)
+ if (slave->priv_flags & IFF_802_1Q_VLAN &&
+ vlan_dev_real_dev(slave) == master)
+ netxen_config_indev_addr(adapter, slave, event);
+ }
+ rcu_read_unlock();
+ /*
+ * This is the case where the netxen nic is being
+ * released and is dev_close()ed in bond_release()
+ * just before IFF_BONDING is stripped.
+ */
+ if (!master && dev->priv_flags & IFF_BONDING)
+ netxen_free_ip_list(adapter, true);
+}
+
static int netxen_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
struct net_device *dev = (struct net_device *)ptr;
struct net_device *orig_dev = dev;
+ struct net_device *slave;
recheck:
if (dev == NULL)
@@ -3257,19 +3323,28 @@ recheck:
dev = vlan_dev_real_dev(dev);
goto recheck;
}
-
- if (!is_netxen_netdev(dev))
- goto done;
-
- adapter = netdev_priv(dev);
-
- if (!adapter)
- goto done;
-
- if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
- goto done;
-
- netxen_config_indev_addr(adapter, orig_dev, event);
+ if (event == NETDEV_UP || event == NETDEV_DOWN) {
+ /* If this is a bonding device, look for netxen-based slaves*/
+ if (netif_is_bond_master(dev)) {
+ rcu_read_lock();
+ for_each_netdev_in_bond_rcu(dev, slave) {
+ if (!netxen_config_checkdev(slave))
+ continue;
+ adapter = netdev_priv(slave);
+ netxen_config_indev_addr(adapter,
+ orig_dev, event);
+ }
+ rcu_read_unlock();
+ } else {
+ if (!netxen_config_checkdev(dev))
+ goto done;
+ adapter = netdev_priv(dev);
+ /* Act only if the actual netxen is the target */
+ if (orig_dev == dev)
+ netxen_config_master(dev, event);
+ netxen_config_indev_addr(adapter, orig_dev, event);
+ }
+ }
done:
return NOTIFY_DONE;
}
@@ -3279,12 +3354,12 @@ netxen_inetaddr_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
- struct net_device *dev;
-
+ struct net_device *dev, *slave;
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+ unsigned long ip_event;
dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
-
+ ip_event = (event == NETDEV_UP) ? NX_IP_UP : NX_IP_DOWN;
recheck:
if (dev == NULL)
goto done;
@@ -3293,31 +3368,24 @@ recheck:
dev = vlan_dev_real_dev(dev);
goto recheck;
}
-
- if (!is_netxen_netdev(dev))
- goto done;
-
- adapter = netdev_priv(dev);
-
- if (!adapter || !netxen_destip_supported(adapter))
- goto done;
-
- if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
- goto done;
-
- switch (event) {
- case NETDEV_UP:
- netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
- netxen_list_config_vlan_ip(adapter, ifa, NX_IP_UP);
- break;
- case NETDEV_DOWN:
- netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
- netxen_list_config_vlan_ip(adapter, ifa, NX_IP_DOWN);
- break;
- default:
- break;
+ if (event == NETDEV_UP || event == NETDEV_DOWN) {
+ /* If this is a bonding device, look for netxen-based slaves*/
+ if (netif_is_bond_master(dev)) {
+ rcu_read_lock();
+ for_each_netdev_in_bond_rcu(dev, slave) {
+ if (!netxen_config_checkdev(slave))
+ continue;
+ adapter = netdev_priv(slave);
+ netxen_list_config_ip(adapter, ifa, ip_event);
+ }
+ rcu_read_unlock();
+ } else {
+ if (!netxen_config_checkdev(dev))
+ goto done;
+ adapter = netdev_priv(dev);
+ netxen_list_config_ip(adapter, ifa, ip_event);
+ }
}
-
done:
return NOTIFY_DONE;
}
@@ -3334,7 +3402,7 @@ static void
netxen_restore_indev_addr(struct net_device *dev, unsigned long event)
{ }
static void
-netxen_free_vlan_ip_list(struct netxen_adapter *adapter)
+netxen_free_ip_list(struct netxen_adapter *adapter, bool master)
{ }
#endif
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index 8fd38cb6d26a..91a8fcd6c246 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -312,7 +312,6 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev,
qdev->lrg_buffer_len);
if (unlikely(!lrg_buf_cb->skb)) {
- netdev_err(qdev->ndev, "failed netdev_alloc_skb()\n");
qdev->lrg_buf_skb_check++;
} else {
/*
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index 7722a203e388..4b1fb3faa3b7 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -8,4 +8,6 @@ qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
qlcnic_sysfs.o qlcnic_minidump.o qlcnic_83xx_hw.o \
qlcnic_83xx_init.o qlcnic_83xx_vnic.o \
- qlcnic_minidump.o
+ qlcnic_minidump.o qlcnic_sriov_common.o
+
+qlcnic-$(CONFIG_QLCNIC_SRIOV) += qlcnic_sriov_pf.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index ba3c72fce1f2..90c253b145ef 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -37,9 +37,9 @@
#include "qlcnic_83xx_hw.h"
#define _QLCNIC_LINUX_MAJOR 5
-#define _QLCNIC_LINUX_MINOR 1
-#define _QLCNIC_LINUX_SUBVERSION 35
-#define QLCNIC_LINUX_VERSIONID "5.1.35"
+#define _QLCNIC_LINUX_MINOR 2
+#define _QLCNIC_LINUX_SUBVERSION 42
+#define QLCNIC_LINUX_VERSIONID "5.2.42"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -347,8 +347,14 @@ struct qlcnic_rx_buffer {
* Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
* adjusted based on configured MTU.
*/
-#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3
-#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256
+#define QLCNIC_INTR_COAL_TYPE_RX 1
+#define QLCNIC_INTR_COAL_TYPE_TX 2
+
+#define QLCNIC_DEF_INTR_COALESCE_RX_TIME_US 3
+#define QLCNIC_DEF_INTR_COALESCE_RX_PACKETS 256
+
+#define QLCNIC_DEF_INTR_COALESCE_TX_TIME_US 64
+#define QLCNIC_DEF_INTR_COALESCE_TX_PACKETS 64
#define QLCNIC_INTR_DEFAULT 0x04
#define QLCNIC_CONFIG_INTR_COALESCE 3
@@ -359,6 +365,8 @@ struct qlcnic_nic_intr_coalesce {
u8 sts_ring_mask;
u16 rx_packets;
u16 rx_time_us;
+ u16 tx_packets;
+ u16 tx_time_us;
u16 flag;
u32 timer_out;
};
@@ -449,6 +457,7 @@ struct qlcnic_hardware_context {
struct qlc_83xx_idc idc;
struct qlc_83xx_fw_info fw_info;
struct qlcnic_intrpt_config *intr_tbl;
+ struct qlcnic_sriov *sriov;
u32 *reg_tbl;
u32 *ext_reg_tbl;
u32 mbox_aen[QLC_83XX_MBX_AEN_CNT];
@@ -510,13 +519,13 @@ struct qlcnic_host_sds_ring {
int irq;
dma_addr_t phys_addr;
- char name[IFNAMSIZ+4];
+ char name[IFNAMSIZ + 12];
} ____cacheline_internodealigned_in_smp;
struct qlcnic_host_tx_ring {
int irq;
void __iomem *crb_intr_mask;
- char name[IFNAMSIZ+4];
+ char name[IFNAMSIZ + 12];
u16 ctx_id;
u32 producer;
u32 sw_consumer;
@@ -896,6 +905,7 @@ struct qlcnic_ipaddr {
#define QLCNIC_FW_RESET_OWNER 0x2000
#define QLCNIC_FW_HANG 0x4000
#define QLCNIC_FW_LRO_MSS_CAP 0x8000
+#define QLCNIC_TX_INTR_SHARED 0x10000
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
@@ -914,7 +924,10 @@ struct qlcnic_ipaddr {
#define __QLCNIC_AER 5
#define __QLCNIC_DIAG_RES_ALLOC 6
#define __QLCNIC_LED_ENABLE 7
-#define __QLCNIC_ELB_INPROGRESS 8
+#define __QLCNIC_ELB_INPROGRESS 8
+#define __QLCNIC_SRIOV_ENABLE 10
+#define __QLCNIC_SRIOV_CAPABLE 11
+#define __QLCNIC_MBX_POLL_ENABLE 12
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -935,7 +948,7 @@ struct qlcnic_ipaddr {
struct qlcnic_filter {
struct hlist_node fnode;
u8 faddr[ETH_ALEN];
- __le16 vlan_id;
+ u16 vlan_id;
unsigned long ftime;
};
@@ -972,9 +985,11 @@ struct qlcnic_adapter {
u8 fw_fail_cnt;
u8 tx_timeo_cnt;
u8 need_fw_reset;
+ u8 reset_ctx_cnt;
u16 is_up;
- u16 pvid;
+ u16 rx_pvid;
+ u16 tx_pvid;
u32 irq;
u32 heartbeat;
@@ -1006,9 +1021,11 @@ struct qlcnic_adapter {
struct workqueue_struct *qlcnic_wq;
struct delayed_work fw_work;
struct delayed_work idc_aen_work;
+ struct delayed_work mbx_poll_work;
struct qlcnic_filter_hash fhash;
struct qlcnic_filter_hash rx_fhash;
+ struct list_head vf_mc_list;
spinlock_t tx_clean_lock;
spinlock_t mac_learn_lock;
@@ -1051,7 +1068,11 @@ struct qlcnic_info_le {
u8 total_pf;
u8 total_rss_engines;
__le16 max_vports;
- u8 reserved2[64];
+ __le16 linkstate_reg_offset;
+ __le16 bit_offsets;
+ __le16 max_local_ipv6_addrs;
+ __le16 max_remote_ipv6_addrs;
+ u8 reserved2[56];
} __packed;
struct qlcnic_info {
@@ -1083,6 +1104,10 @@ struct qlcnic_info {
u8 total_pf;
u8 total_rss_engines;
u16 max_vports;
+ u16 linkstate_reg_offset;
+ u16 bit_offsets;
+ u16 max_local_ipv6_addrs;
+ u16 max_remote_ipv6_addrs;
};
struct qlcnic_pci_info_le {
@@ -1348,6 +1373,7 @@ struct _cdrp_cmd {
struct qlcnic_cmd_args {
struct _cdrp_cmd req;
struct _cdrp_cmd rsp;
+ int op_type;
};
int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
@@ -1430,9 +1456,10 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
void qlcnic_set_multi(struct net_device *netdev);
-int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *);
+void __qlcnic_set_multi(struct net_device *, u16);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16);
int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
-void qlcnic_free_mac_list(struct qlcnic_adapter *adapter);
+void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter);
int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *);
@@ -1455,7 +1482,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
int qlcnic_set_max_rss(struct qlcnic_adapter *, u8, size_t);
-int qlcnic_validate_max_rss(u8, u8);
+int qlcnic_validate_max_rss(struct qlcnic_adapter *, __u32);
void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
int qlcnic_enable_msix(struct qlcnic_adapter *, u32);
@@ -1509,8 +1536,13 @@ int qlcnic_init_pci_info(struct qlcnic_adapter *);
int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
int qlcnic_reset_npar_config(struct qlcnic_adapter *);
int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
-void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int,
- __le16);
+void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16);
+int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
+int qlcnic_read_mac_addr(struct qlcnic_adapter *);
+int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);
+void qlcnic_sriov_vf_schedule_multi(struct net_device *);
+void qlcnic_vf_add_mc_list(struct net_device *, u16);
+
/*
* QLOGIC Board information
*/
@@ -1567,11 +1599,14 @@ struct qlcnic_hardware_ops {
int (*create_rx_ctx) (struct qlcnic_adapter *);
int (*create_tx_ctx) (struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *, int);
+ void (*del_rx_ctx) (struct qlcnic_adapter *);
+ void (*del_tx_ctx) (struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *);
int (*setup_link_event) (struct qlcnic_adapter *, int);
int (*get_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *, u8);
int (*get_pci_info) (struct qlcnic_adapter *, struct qlcnic_pci_info *);
int (*set_nic_info) (struct qlcnic_adapter *, struct qlcnic_info *);
- int (*change_macvlan) (struct qlcnic_adapter *, u8*, __le16, u8);
+ int (*change_macvlan) (struct qlcnic_adapter *, u8*, u16, u8);
void (*napi_enable) (struct qlcnic_adapter *);
void (*napi_disable) (struct qlcnic_adapter *);
void (*config_intr_coal) (struct qlcnic_adapter *);
@@ -1580,8 +1615,9 @@ struct qlcnic_hardware_ops {
int (*config_loopback) (struct qlcnic_adapter *, u8);
int (*clear_loopback) (struct qlcnic_adapter *, u8);
int (*config_promisc_mode) (struct qlcnic_adapter *, u32);
- void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, __le16);
+ void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16);
int (*get_board_info) (struct qlcnic_adapter *);
+ void (*free_mac_list) (struct qlcnic_adapter *);
};
extern struct qlcnic_nic_template qlcnic_vf_ops;
@@ -1635,7 +1671,10 @@ static inline int qlcnic_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
static inline int qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
struct qlcnic_cmd_args *cmd)
{
- return adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+ if (adapter->ahw->hw_ops->mbx_cmd)
+ return adapter->ahw->hw_ops->mbx_cmd(adapter, cmd);
+
+ return -EIO;
}
static inline void qlcnic_get_func_no(struct qlcnic_adapter *adapter)
@@ -1655,12 +1694,14 @@ static inline void qlcnic_api_unlock(struct qlcnic_adapter *adapter)
static inline void qlcnic_add_sysfs(struct qlcnic_adapter *adapter)
{
- adapter->ahw->hw_ops->add_sysfs(adapter);
+ if (adapter->ahw->hw_ops->add_sysfs)
+ adapter->ahw->hw_ops->add_sysfs(adapter);
}
static inline void qlcnic_remove_sysfs(struct qlcnic_adapter *adapter)
{
- adapter->ahw->hw_ops->remove_sysfs(adapter);
+ if (adapter->ahw->hw_ops->remove_sysfs)
+ adapter->ahw->hw_ops->remove_sysfs(adapter);
}
static inline void
@@ -1681,6 +1722,17 @@ static inline int qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
return adapter->ahw->hw_ops->create_tx_ctx(adapter, ptr, ring);
}
+static inline void qlcnic_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->hw_ops->del_rx_ctx(adapter);
+}
+
+static inline void qlcnic_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *ptr)
+{
+ return adapter->ahw->hw_ops->del_tx_ctx(adapter, ptr);
+}
+
static inline int qlcnic_linkevent_request(struct qlcnic_adapter *adapter,
int enable)
{
@@ -1706,7 +1758,7 @@ static inline int qlcnic_set_nic_info(struct qlcnic_adapter *adapter,
}
static inline int qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter,
- u8 *addr, __le16 id, u8 cmd)
+ u8 *addr, u16 id, u8 cmd)
{
return adapter->ahw->hw_ops->change_macvlan(adapter, addr, id, cmd);
}
@@ -1765,7 +1817,7 @@ static inline int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter,
}
static inline void qlcnic_change_filter(struct qlcnic_adapter *adapter,
- u64 *addr, __le16 id)
+ u64 *addr, u16 id)
{
adapter->ahw->hw_ops->change_l2_filter(adapter, addr, id);
}
@@ -1775,15 +1827,22 @@ static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
return adapter->ahw->hw_ops->get_board_info(adapter);
}
+static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
+{
+ return adapter->ahw->hw_ops->free_mac_list(adapter);
+}
+
static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
u32 key)
{
- adapter->nic_ops->request_reset(adapter, key);
+ if (adapter->nic_ops->request_reset)
+ adapter->nic_ops->request_reset(adapter, key);
}
static inline void qlcnic_cancel_idc_work(struct qlcnic_adapter *adapter)
{
- adapter->nic_ops->cancel_idc_work(adapter);
+ if (adapter->nic_ops->cancel_idc_work)
+ adapter->nic_ops->cancel_idc_work(adapter);
}
static inline irqreturn_t
@@ -1819,6 +1878,7 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
writel(0xfbff, adapter->tgt_mask_reg);
}
+extern const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
@@ -1830,7 +1890,9 @@ extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
} while (0)
#define PCI_DEVICE_ID_QLOGIC_QLE834X 0x8030
+#define PCI_DEVICE_ID_QLOGIC_VF_QLE834X 0x8430
#define PCI_DEVICE_ID_QLOGIC_QLE824X 0x8020
+
static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
{
unsigned short device = adapter->pdev->device;
@@ -1840,8 +1902,23 @@ static inline bool qlcnic_82xx_check(struct qlcnic_adapter *adapter)
static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
{
unsigned short device = adapter->pdev->device;
- return (device == PCI_DEVICE_ID_QLOGIC_QLE834X) ? true : false;
+ bool status;
+
+ status = ((device == PCI_DEVICE_ID_QLOGIC_QLE834X) ||
+ (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X)) ? true : false;
+
+ return status;
}
+static inline bool qlcnic_sriov_pf_check(struct qlcnic_adapter *adapter)
+{
+ return (adapter->ahw->op_mode == QLCNIC_SRIOV_PF_FUNC) ? true : false;
+}
+static inline bool qlcnic_sriov_vf_check(struct qlcnic_adapter *adapter)
+{
+ unsigned short device = adapter->pdev->device;
+
+ return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false;
+}
#endif /* __QLCNIC_H_ */
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index cd5ae8813cb3..ea790a93ee7c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -6,6 +6,7 @@
*/
#include "qlcnic.h"
+#include "qlcnic_sriov.h"
#include <linux/if_vlan.h>
#include <linux/ipv6.h>
#include <linux/ethtool.h>
@@ -13,100 +14,7 @@
#define QLCNIC_MAX_TX_QUEUES 1
#define RSS_HASHTYPE_IP_TCP 0x3
-
-/* status descriptor mailbox data
- * @phy_addr: physical address of buffer
- * @sds_ring_size: buffer size
- * @intrpt_id: interrupt id
- * @intrpt_val: source of interrupt
- */
-struct qlcnic_sds_mbx {
- u64 phy_addr;
- u8 rsvd1[16];
- u16 sds_ring_size;
- u16 rsvd2[3];
- u16 intrpt_id;
- u8 intrpt_val;
- u8 rsvd3[5];
-} __packed;
-
-/* receive descriptor buffer data
- * phy_addr_reg: physical address of regular buffer
- * phy_addr_jmb: physical address of jumbo buffer
- * reg_ring_sz: size of regular buffer
- * reg_ring_len: no. of entries in regular buffer
- * jmb_ring_len: no. of entries in jumbo buffer
- * jmb_ring_sz: size of jumbo buffer
- */
-struct qlcnic_rds_mbx {
- u64 phy_addr_reg;
- u64 phy_addr_jmb;
- u16 reg_ring_sz;
- u16 reg_ring_len;
- u16 jmb_ring_sz;
- u16 jmb_ring_len;
-} __packed;
-
-/* host producers for regular and jumbo rings */
-struct __host_producer_mbx {
- u32 reg_buf;
- u32 jmb_buf;
-} __packed;
-
-/* Receive context mailbox data outbox registers
- * @state: state of the context
- * @vport_id: virtual port id
- * @context_id: receive context id
- * @num_pci_func: number of pci functions of the port
- * @phy_port: physical port id
- */
-struct qlcnic_rcv_mbx_out {
- u8 rcv_num;
- u8 sts_num;
- u16 ctx_id;
- u8 state;
- u8 num_pci_func;
- u8 phy_port;
- u8 vport_id;
- u32 host_csmr[QLCNIC_MAX_RING_SETS];
- struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
-} __packed;
-
-struct qlcnic_add_rings_mbx_out {
- u8 rcv_num;
- u8 sts_num;
- u16 ctx_id;
- u32 host_csmr[QLCNIC_MAX_RING_SETS];
- struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
-} __packed;
-
-/* Transmit context mailbox inbox registers
- * @phys_addr: DMA address of the transmit buffer
- * @cnsmr_index: host consumer index
- * @size: legth of transmit buffer ring
- * @intr_id: interrput id
- * @src: src of interrupt
- */
-struct qlcnic_tx_mbx {
- u64 phys_addr;
- u64 cnsmr_index;
- u16 size;
- u16 intr_id;
- u8 src;
- u8 rsvd[3];
-} __packed;
-
-/* Transmit context mailbox outbox registers
- * @host_prod: host producer index
- * @ctx_id: transmit context id
- * @state: state of the transmit context
- */
-struct qlcnic_tx_mbx_out {
- u32 host_prod;
- u16 ctx_id;
- u8 state;
- u8 rsvd;
-} __packed;
+#define QLC_83XX_FW_MBX_CMD 0
static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
@@ -156,9 +64,11 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
{QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
{QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
{QLCNIC_CMD_ADD_RCV_RINGS, 130, 26},
+ {QLCNIC_CMD_CONFIG_VPORT, 4, 4},
+ {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
};
-static const u32 qlcnic_83xx_ext_reg_tbl[] = {
+const u32 qlcnic_83xx_ext_reg_tbl[] = {
0x38CC, /* Global Reset */
0x38F0, /* Wildcard */
0x38FC, /* Informant */
@@ -204,7 +114,7 @@ static const u32 qlcnic_83xx_ext_reg_tbl[] = {
0x34A4, /* QLC_83XX_ASIC_TEMP */
};
-static const u32 qlcnic_83xx_reg_tbl[] = {
+const u32 qlcnic_83xx_reg_tbl[] = {
0x34A8, /* PEG_HALT_STAT1 */
0x34AC, /* PEG_HALT_STAT2 */
0x34B0, /* FW_HEARTBEAT */
@@ -247,6 +157,8 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
.process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag,
.create_rx_ctx = qlcnic_83xx_create_rx_ctx,
.create_tx_ctx = qlcnic_83xx_create_tx_ctx,
+ .del_rx_ctx = qlcnic_83xx_del_rx_ctx,
+ .del_tx_ctx = qlcnic_83xx_del_tx_ctx,
.setup_link_event = qlcnic_83xx_setup_link_event,
.get_nic_info = qlcnic_83xx_get_nic_info,
.get_pci_info = qlcnic_83xx_get_pci_info,
@@ -260,6 +172,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
.config_promisc_mode = qlcnic_83xx_nic_set_promisc,
.change_l2_filter = qlcnic_83xx_change_l2_filter,
.get_board_info = qlcnic_83xx_get_port_info,
+ .free_mac_list = qlcnic_82xx_free_mac_list,
};
static struct qlcnic_nic_template qlcnic_83xx_ops = {
@@ -355,14 +268,20 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter, u8 num_intr)
num_intr));
/* account for AEN interrupt MSI-X based interrupts */
num_msix += 1;
- num_msix += adapter->max_drv_tx_rings;
+
+ if (!(adapter->flags & QLCNIC_TX_INTR_SHARED))
+ num_msix += adapter->max_drv_tx_rings;
+
err = qlcnic_enable_msix(adapter, num_msix);
if (err == -ENOMEM)
return err;
if (adapter->flags & QLCNIC_MSIX_ENABLED)
num_msix = adapter->ahw->num_msix;
- else
+ else {
+ if (qlcnic_sriov_vf_check(adapter))
+ return -EINVAL;
num_msix = 1;
+ }
/* setup interrupt mapping table for fw */
ahw->intr_tbl = vzalloc(num_msix *
sizeof(struct qlcnic_intrpt_config));
@@ -421,12 +340,13 @@ inline void qlcnic_83xx_enable_legacy_msix_mbx_intr(struct qlcnic_adapter
writel(0, adapter->ahw->pci_base0 + mask);
}
-inline void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
+void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *adapter)
{
u32 mask;
mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
writel(1, adapter->ahw->pci_base0 + mask);
+ QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
}
static inline void qlcnic_83xx_get_mbx_data(struct qlcnic_adapter *adapter,
@@ -482,7 +402,8 @@ static void qlcnic_83xx_poll_process_aen(struct qlcnic_adapter *adapter)
event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
if (event & QLCNIC_MBX_ASYNC_EVENT)
- qlcnic_83xx_process_aen(adapter);
+ __qlcnic_83xx_process_aen(adapter);
+
out:
qlcnic_83xx_enable_legacy_msix_mbx_intr(adapter);
spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
@@ -535,17 +456,15 @@ done:
void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
{
- u32 val = 0, num_msix = adapter->ahw->num_msix - 1;
+ u32 num_msix;
+
+ qlcnic_83xx_disable_mbx_intr(adapter);
if (adapter->flags & QLCNIC_MSIX_ENABLED)
num_msix = adapter->ahw->num_msix - 1;
else
num_msix = 0;
- QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, val);
-
- qlcnic_83xx_disable_mbx_intr(adapter);
-
msleep(20);
synchronize_irq(adapter->msix_entries[num_msix].vector);
free_irq(adapter->msix_entries[num_msix].vector, adapter);
@@ -595,7 +514,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
void qlcnic_83xx_get_func_no(struct qlcnic_adapter *adapter)
{
u32 val = QLCRDX(adapter->ahw, QLCNIC_INFORMANT);
- adapter->ahw->pci_func = val & 0xf;
+ adapter->ahw->pci_func = (val >> 24) & 0xff;
}
int qlcnic_83xx_cam_lock(struct qlcnic_adapter *adapter)
@@ -707,6 +626,11 @@ void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
ahw->fw_hal_version = 2;
qlcnic_get_func_no(adapter);
+ if (qlcnic_sriov_vf_check(adapter)) {
+ qlcnic_sriov_vf_set_ops(adapter);
+ return;
+ }
+
/* Determine function privilege level */
op_mode = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
if (op_mode == QLC_83XX_DEFAULT_OPMODE)
@@ -722,6 +646,9 @@ void qlcnic_83xx_check_vf(struct qlcnic_adapter *adapter,
ahw->fw_hal_version);
adapter->nic_ops = &qlcnic_vf_ops;
} else {
+ if (pci_find_ext_capability(adapter->pdev,
+ PCI_EXT_CAP_ID_SRIOV))
+ set_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state);
adapter->nic_ops = &qlcnic_83xx_ops;
}
}
@@ -755,7 +682,7 @@ static void qlcnic_dump_mbx(struct qlcnic_adapter *adapter,
}
/* Mailbox response for mac rcode */
-static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
+u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
{
u32 fw_data;
u8 mac_cmd_rcode;
@@ -769,7 +696,7 @@ static u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
return 1;
}
-static u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
+u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
{
u32 data;
unsigned long wait_time = 0;
@@ -832,7 +759,7 @@ poll:
/* Get the FW response data */
fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
- qlcnic_83xx_process_aen(adapter);
+ __qlcnic_83xx_process_aen(adapter);
mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
if (mbx_val)
goto poll;
@@ -884,6 +811,7 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
size = ARRAY_SIZE(qlcnic_83xx_mbx_tbl);
for (i = 0; i < size; i++) {
if (type == mbx_tbl[i].cmd) {
+ mbx->op_type = QLC_83XX_FW_MBX_CMD;
mbx->req.num = mbx_tbl[i].in_args;
mbx->rsp.num = mbx_tbl[i].out_args;
mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
@@ -901,10 +829,10 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx,
memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
temp = adapter->ahw->fw_hal_version << 29;
mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp);
- break;
+ return 0;
}
}
- return 0;
+ return -EINVAL;
}
void qlcnic_83xx_idc_aen_work(struct work_struct *work)
@@ -935,7 +863,7 @@ static void qlcnic_83xx_handle_idc_comp_aen(struct qlcnic_adapter *adapter,
return;
}
-void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+void __qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
{
u32 event[QLC_83XX_MBX_AEN_CNT];
int i;
@@ -960,6 +888,9 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
break;
case QLCNIC_MBX_TIME_EXTEND_EVENT:
break;
+ case QLCNIC_MBX_BC_EVENT:
+ qlcnic_sriov_handle_bc_event(adapter, event[1]);
+ break;
case QLCNIC_MBX_SFP_INSERT_EVENT:
dev_info(&adapter->pdev->dev, "SFP+ Insert AEN:0x%x.\n",
QLCNIC_MBX_RSP(event[0]));
@@ -977,6 +908,53 @@ void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
}
+static void qlcnic_83xx_process_aen(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 resp, event;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ahw->mbx_lock, flags);
+
+ resp = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
+ if (resp & QLCNIC_SET_OWNER) {
+ event = readl(QLCNIC_MBX_FW(ahw, 0));
+ if (event & QLCNIC_MBX_ASYNC_EVENT)
+ __qlcnic_83xx_process_aen(adapter);
+ }
+
+ spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+}
+
+static void qlcnic_83xx_mbx_poll_work(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter;
+
+ adapter = container_of(work, struct qlcnic_adapter, mbx_poll_work.work);
+
+ if (!test_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))
+ return;
+
+ qlcnic_83xx_process_aen(adapter);
+ queue_delayed_work(adapter->qlcnic_wq, &adapter->mbx_poll_work,
+ (HZ / 10));
+}
+
+void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *adapter)
+{
+ if (test_and_set_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))
+ return;
+
+ INIT_DELAYED_WORK(&adapter->mbx_poll_work, qlcnic_83xx_mbx_poll_work);
+}
+
+void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *adapter)
+{
+ if (!test_and_clear_bit(__QLCNIC_MBX_POLL_ENABLE, &adapter->state))
+ return;
+ cancel_delayed_work_sync(&adapter->mbx_poll_work);
+}
+
static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
{
int index, i, err, sds_mbx_size;
@@ -1004,7 +982,8 @@ static int qlcnic_83xx_add_rings(struct qlcnic_adapter *adapter)
sds = &recv_ctx->sds_rings[i];
sds->consumer = 0;
memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
- sds_mbx.phy_addr = sds->phys_addr;
+ sds_mbx.phy_addr_low = LSD(sds->phys_addr);
+ sds_mbx.phy_addr_high = MSD(sds->phys_addr);
sds_mbx.sds_ring_size = sds->num_desc;
if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -1050,6 +1029,32 @@ out:
return err;
}
+void qlcnic_83xx_del_rx_ctx(struct qlcnic_adapter *adapter)
+{
+ int err;
+ u32 temp = 0;
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX))
+ return;
+
+ if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
+ cmd.req.arg[0] |= (0x3 << 29);
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_pf_set_interface_id_del_rx_ctx(adapter, &temp);
+
+ cmd.req.arg[1] = recv_ctx->context_id | temp;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "Failed to destroy rx ctx in firmware\n");
+
+ recv_ctx->state = QLCNIC_HOST_CTX_STATE_FREED;
+ qlcnic_free_mbx_args(&cmd);
+}
+
int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
{
int i, err, index, sds_mbx_size, rds_mbx_size;
@@ -1080,9 +1085,17 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
/* set mailbox hdr and capabilities */
qlcnic_alloc_mbx_args(&cmd, adapter,
QLCNIC_CMD_CREATE_RX_CTX);
+
+ if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
+ cmd.req.arg[0] |= (0x3 << 29);
+
cmd.req.arg[1] = cap;
cmd.req.arg[5] = 1 | (num_rds << 5) | (num_sds << 8) |
(QLC_83XX_HOST_RDS_MODE_UNIQUE << 16);
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_pf_set_interface_id_create_rx_ctx(adapter,
+ &cmd.req.arg[6]);
/* set up status rings, mbx 8-57/87 */
index = QLC_83XX_HOST_SDS_MBX_IDX;
for (i = 0; i < num_sds; i++) {
@@ -1090,7 +1103,8 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
sds = &recv_ctx->sds_rings[i];
sds->consumer = 0;
memset(sds->desc_head, 0, STATUS_DESC_RINGSIZE(sds));
- sds_mbx.phy_addr = sds->phys_addr;
+ sds_mbx.phy_addr_low = LSD(sds->phys_addr);
+ sds_mbx.phy_addr_high = MSD(sds->phys_addr);
sds_mbx.sds_ring_size = sds->num_desc;
if (adapter->flags & QLCNIC_MSIX_ENABLED)
intrpt_id = ahw->intr_tbl[i].id;
@@ -1110,13 +1124,15 @@ int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *adapter)
rds = &recv_ctx->rds_rings[0];
rds->producer = 0;
memset(&rds_mbx, 0, rds_mbx_size);
- rds_mbx.phy_addr_reg = rds->phys_addr;
+ rds_mbx.phy_addr_reg_low = LSD(rds->phys_addr);
+ rds_mbx.phy_addr_reg_high = MSD(rds->phys_addr);
rds_mbx.reg_ring_sz = rds->dma_size;
rds_mbx.reg_ring_len = rds->num_desc;
/* Jumbo ring */
rds = &recv_ctx->rds_rings[1];
rds->producer = 0;
- rds_mbx.phy_addr_jmb = rds->phys_addr;
+ rds_mbx.phy_addr_jmb_low = LSD(rds->phys_addr);
+ rds_mbx.phy_addr_jmb_high = MSD(rds->phys_addr);
rds_mbx.jmb_ring_sz = rds->dma_size;
rds_mbx.jmb_ring_len = rds->num_desc;
buf = &cmd.req.arg[index];
@@ -1163,16 +1179,39 @@ out:
return err;
}
+void qlcnic_83xx_del_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
+{
+ struct qlcnic_cmd_args cmd;
+ u32 temp = 0;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX))
+ return;
+
+ if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
+ cmd.req.arg[0] |= (0x3 << 29);
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_pf_set_interface_id_del_tx_ctx(adapter, &temp);
+
+ cmd.req.arg[1] = tx_ring->ctx_id | temp;
+ if (qlcnic_issue_cmd(adapter, &cmd))
+ dev_err(&adapter->pdev->dev,
+ "Failed to destroy tx ctx in firmware\n");
+ qlcnic_free_mbx_args(&cmd);
+}
+
int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx, int ring)
{
int err;
u16 msix_id;
- u32 *buf, intr_mask;
+ u32 *buf, intr_mask, temp = 0;
struct qlcnic_cmd_args cmd;
struct qlcnic_tx_mbx mbx;
struct qlcnic_tx_mbx_out *mbx_out;
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 msix_vector;
/* Reset host resources */
tx->producer = 0;
@@ -1182,13 +1221,21 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
memset(&mbx, 0, sizeof(struct qlcnic_tx_mbx));
/* setup mailbox inbox registerss */
- mbx.phys_addr = tx->phys_addr;
- mbx.cnsmr_index = tx->hw_cons_phys_addr;
+ mbx.phys_addr_low = LSD(tx->phys_addr);
+ mbx.phys_addr_high = MSD(tx->phys_addr);
+ mbx.cnsmr_index_low = LSD(tx->hw_cons_phys_addr);
+ mbx.cnsmr_index_high = MSD(tx->hw_cons_phys_addr);
mbx.size = tx->num_desc;
- if (adapter->flags & QLCNIC_MSIX_ENABLED)
- msix_id = ahw->intr_tbl[adapter->max_sds_rings + ring].id;
- else
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if (!(adapter->flags & QLCNIC_TX_INTR_SHARED))
+ msix_vector = adapter->max_sds_rings + ring;
+ else
+ msix_vector = adapter->max_sds_rings - 1;
+ msix_id = ahw->intr_tbl[msix_vector].id;
+ } else {
msix_id = QLCRDX(ahw, QLCNIC_DEF_INT_ID);
+ }
+
if (adapter->ahw->diag_test != QLCNIC_LOOPBACK_TEST)
mbx.intr_id = msix_id;
else
@@ -1196,8 +1243,15 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
mbx.src = 0;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CREATE_TX_CTX);
+
+ if (qlcnic_sriov_pf_check(adapter) || qlcnic_sriov_vf_check(adapter))
+ cmd.req.arg[0] |= (0x3 << 29);
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_pf_set_interface_id_create_tx_ctx(adapter, &temp);
+
cmd.req.arg[1] = QLCNIC_CAP0_LEGACY_CONTEXT;
- cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES;
+ cmd.req.arg[5] = QLCNIC_MAX_TX_QUEUES | temp;
buf = &cmd.req.arg[6];
memcpy(buf, &mbx, sizeof(struct qlcnic_tx_mbx));
/* send the mailbox command*/
@@ -1210,7 +1264,8 @@ int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *adapter,
mbx_out = (struct qlcnic_tx_mbx_out *)&cmd.rsp.arg[2];
tx->crb_cmd_producer = ahw->pci_base0 + mbx_out->host_prod;
tx->ctx_id = mbx_out->ctx_id;
- if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
intr_mask = ahw->intr_tbl[adapter->max_sds_rings + ring].src;
tx->crb_intr_mask = ahw->pci_base0 + intr_mask;
}
@@ -1267,7 +1322,8 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
/* disable and free mailbox interrupt */
- qlcnic_83xx_free_mbx_intr(adapter);
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_free_mbx_intr(adapter);
adapter->ahw->loopback_state = 0;
adapter->ahw->hw_ops->setup_link_event(adapter, 1);
}
@@ -1295,12 +1351,14 @@ static void qlcnic_83xx_diag_free_res(struct net_device *netdev,
qlcnic_detach(adapter);
if (adapter->ahw->diag_test == QLCNIC_LOOPBACK_TEST) {
- err = qlcnic_83xx_setup_mbx_intr(adapter);
- if (err) {
- dev_err(&adapter->pdev->dev,
- "%s: failed to setup mbx interrupt\n",
- __func__);
- goto out;
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "%s: failed to setup mbx interrupt\n",
+ __func__);
+ goto out;
+ }
}
}
adapter->ahw->diag_test = 0;
@@ -1373,12 +1431,60 @@ mbx_err:
}
}
+int qlcnic_83xx_set_led(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err = -EIO, active = 1;
+
+ if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ netdev_warn(netdev,
+ "LED test is not supported in non-privileged mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state))
+ return -EBUSY;
+
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ break;
+
+ err = qlcnic_83xx_config_led(adapter, active, 0);
+ if (err)
+ netdev_err(netdev, "Failed to set LED blink state\n");
+ break;
+ case ETHTOOL_ID_INACTIVE:
+ active = 0;
+
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ break;
+
+ err = qlcnic_83xx_config_led(adapter, active, 0);
+ if (err)
+ netdev_err(netdev, "Failed to reset LED blink state\n");
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!active || err)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+ return err;
+}
+
void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *adapter,
int enable)
{
struct qlcnic_cmd_args cmd;
int status;
+ if (qlcnic_sriov_vf_check(adapter))
+ return;
+
if (enable) {
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_INIT_NIC_FUNC);
cmd.req.arg[1] = BIT_0 | BIT_31;
@@ -1441,24 +1547,35 @@ int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *adapter, int enable)
return err;
}
+static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,
+ u32 *interface_id)
+{
+ if (qlcnic_sriov_pf_check(adapter)) {
+ qlcnic_pf_set_interface_id_promisc(adapter, interface_id);
+ } else {
+ if (!qlcnic_sriov_vf_check(adapter))
+ *interface_id = adapter->recv_ctx->context_id << 16;
+ }
+}
+
int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
{
int err;
- u32 temp;
+ u32 temp = 0;
struct qlcnic_cmd_args cmd;
if (adapter->recv_ctx->state == QLCNIC_HOST_CTX_STATE_FREED)
return -EIO;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_MAC_RX_MODE);
- temp = adapter->recv_ctx->context_id << 16;
+ qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
cmd.req.arg[1] = (mode ? 1 : 0) | temp;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err)
dev_info(&adapter->pdev->dev,
"Promiscous mode config failed\n");
- qlcnic_free_mbx_args(&cmd);
+ qlcnic_free_mbx_args(&cmd);
return err;
}
@@ -1490,7 +1607,9 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
/* Poll for link up event before running traffic */
do {
msleep(500);
- qlcnic_83xx_process_aen(adapter);
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_process_aen(adapter);
+
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
dev_info(&adapter->pdev->dev,
"Firmware didn't sent link up event to loopback request\n");
@@ -1500,6 +1619,12 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
}
} while ((adapter->ahw->linkup && ahw->has_link_events) != 1);
+ /* Make sure carrier is off and queue is stopped during loopback */
+ if (netif_running(netdev)) {
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+
ret = qlcnic_do_lb_test(adapter, mode);
qlcnic_83xx_clear_lb_mode(adapter, mode);
@@ -1544,7 +1669,9 @@ int qlcnic_83xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
/* Wait for Link and IDC Completion AEN */
do {
msleep(300);
- qlcnic_83xx_process_aen(adapter);
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_process_aen(adapter);
+
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
dev_err(&adapter->pdev->dev,
"FW did not generate IDC completion AEN\n");
@@ -1584,7 +1711,9 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
/* Wait for Link and IDC Completion AEN */
do {
msleep(300);
- qlcnic_83xx_process_aen(adapter);
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_process_aen(adapter);
+
if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP) {
dev_err(&adapter->pdev->dev,
"Firmware didn't sent IDC completion AEN\n");
@@ -1598,21 +1727,31 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
return status;
}
+static void qlcnic_83xx_set_interface_id_ipaddr(struct qlcnic_adapter *adapter,
+ u32 *interface_id)
+{
+ if (qlcnic_sriov_pf_check(adapter)) {
+ qlcnic_pf_set_interface_id_ipaddr(adapter, interface_id);
+ } else {
+ if (!qlcnic_sriov_vf_check(adapter))
+ *interface_id = adapter->recv_ctx->context_id << 16;
+ }
+}
+
void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
int mode)
{
int err;
- u32 temp, temp_ip;
+ u32 temp = 0, temp_ip;
struct qlcnic_cmd_args cmd;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIGURE_IP_ADDR);
- if (mode == QLCNIC_IP_UP) {
- temp = adapter->recv_ctx->context_id << 16;
+ qlcnic_83xx_set_interface_id_ipaddr(adapter, &temp);
+
+ if (mode == QLCNIC_IP_UP)
cmd.req.arg[1] = 1 | temp;
- } else {
- temp = adapter->recv_ctx->context_id << 16;
+ else
cmd.req.arg[1] = 2 | temp;
- }
/*
* Adapter needs IP address in network byte order.
@@ -1629,6 +1768,7 @@ void qlcnic_83xx_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip,
dev_err(&adapter->netdev->dev,
"could not notify %s IP 0x%x request\n",
(mode == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
+
qlcnic_free_mbx_args(&cmd);
}
@@ -1695,11 +1835,22 @@ int qlcnic_83xx_config_rss(struct qlcnic_adapter *adapter, int enable)
}
+static void qlcnic_83xx_set_interface_id_macaddr(struct qlcnic_adapter *adapter,
+ u32 *interface_id)
+{
+ if (qlcnic_sriov_pf_check(adapter)) {
+ qlcnic_pf_set_interface_id_macaddr(adapter, interface_id);
+ } else {
+ if (!qlcnic_sriov_vf_check(adapter))
+ *interface_id = adapter->recv_ctx->context_id << 16;
+ }
+}
+
int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
- __le16 vlan_id, u8 op)
+ u16 vlan_id, u8 op)
{
int err;
- u32 *buf;
+ u32 *buf, temp = 0;
struct qlcnic_cmd_args cmd;
struct qlcnic_macvlan_mbx mv;
@@ -1709,11 +1860,21 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN);
if (err)
return err;
- cmd.req.arg[1] = op | (1 << 8) |
- (adapter->recv_ctx->context_id << 16);
- mv.vlan = le16_to_cpu(vlan_id);
- memcpy(&mv.mac, addr, ETH_ALEN);
+ if (vlan_id)
+ op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
+ QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;
+
+ cmd.req.arg[1] = op | (1 << 8);
+ qlcnic_83xx_set_interface_id_macaddr(adapter, &temp);
+ cmd.req.arg[1] |= temp;
+ mv.vlan = vlan_id;
+ mv.mac_addr0 = addr[0];
+ mv.mac_addr1 = addr[1];
+ mv.mac_addr2 = addr[2];
+ mv.mac_addr3 = addr[3];
+ mv.mac_addr4 = addr[4];
+ mv.mac_addr5 = addr[5];
buf = &cmd.req.arg[2];
memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
err = qlcnic_issue_cmd(adapter, &cmd);
@@ -1726,7 +1887,7 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
}
void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *adapter, u64 *addr,
- __le16 vlan_id)
+ u16 vlan_id)
{
u8 mac[ETH_ALEN];
memcpy(&mac, addr, ETH_ALEN);
@@ -1776,7 +1937,7 @@ int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
{
int err;
- u32 temp;
+ u16 temp;
struct qlcnic_cmd_args cmd;
struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
@@ -1784,10 +1945,18 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
return;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTR_COAL);
- cmd.req.arg[1] = 1 | (adapter->recv_ctx->context_id << 16);
+ if (coal->type == QLCNIC_INTR_COAL_TYPE_RX) {
+ temp = adapter->recv_ctx->context_id;
+ cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_RX | temp << 16;
+ temp = coal->rx_time_us;
+ cmd.req.arg[2] = coal->rx_packets | temp << 16;
+ } else if (coal->type == QLCNIC_INTR_COAL_TYPE_TX) {
+ temp = adapter->tx_ring->ctx_id;
+ cmd.req.arg[1] = QLCNIC_INTR_COAL_TYPE_TX | temp << 16;
+ temp = coal->tx_time_us;
+ cmd.req.arg[2] = coal->tx_packets | temp << 16;
+ }
cmd.req.arg[3] = coal->flag;
- temp = coal->rx_time_us << 16;
- cmd.req.arg[2] = coal->rx_packets | temp;
err = qlcnic_issue_cmd(adapter, &cmd);
if (err != QLCNIC_RCODE_SUCCESS)
dev_info(&adapter->pdev->dev,
@@ -1826,7 +1995,7 @@ irqreturn_t qlcnic_83xx_handle_aen(int irq, void *data)
event = readl(QLCNIC_MBX_FW(adapter->ahw, 0));
if (event & QLCNIC_MBX_ASYNC_EVENT)
- qlcnic_83xx_process_aen(adapter);
+ __qlcnic_83xx_process_aen(adapter);
out:
mask = QLCRDX(adapter->ahw, QLCNIC_DEF_INT_MASK);
writel(0, adapter->ahw->pci_base0 + mask);
@@ -2002,14 +2171,17 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *adapter, bool op_type)
{
int i, index, err;
- bool type;
u8 max_ints;
- u32 val, temp;
+ u32 val, temp, type;
struct qlcnic_cmd_args cmd;
max_ints = adapter->ahw->num_msix - 1;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_INTRPT);
cmd.req.arg[1] = max_ints;
+
+ if (qlcnic_sriov_vf_check(adapter))
+ cmd.req.arg[1] |= (adapter->ahw->pci_func << 8) | BIT_16;
+
for (i = 0, index = 2; i < max_ints; i++) {
type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
val = type | (adapter->ahw->intr_tbl[i].type << 4);
@@ -2163,7 +2335,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
return 0;
}
-static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *adapter)
{
int ret;
u32 cmd;
@@ -2181,7 +2353,7 @@ static int qlcnic_83xx_enable_flash_write_op(struct qlcnic_adapter *adapter)
return 0;
}
-static int qlcnic_83xx_disable_flash_write_op(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)
{
int ret;
@@ -2255,7 +2427,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
return -EIO;
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
- ret = qlcnic_83xx_enable_flash_write_op(adapter);
+ ret = qlcnic_83xx_enable_flash_write(adapter);
if (ret) {
qlcnic_83xx_unlock_flash(adapter);
dev_err(&adapter->pdev->dev,
@@ -2297,7 +2469,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
}
if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
- ret = qlcnic_83xx_disable_flash_write_op(adapter);
+ ret = qlcnic_83xx_disable_flash_write(adapter);
if (ret) {
qlcnic_83xx_unlock_flash(adapter);
dev_err(&adapter->pdev->dev,
@@ -2337,8 +2509,8 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
u32 temp;
int ret = -EIO;
- if ((count < QLC_83XX_FLASH_BULK_WRITE_MIN) ||
- (count > QLC_83XX_FLASH_BULK_WRITE_MAX)) {
+ if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
+ (count > QLC_83XX_FLASH_WRITE_MAX)) {
dev_err(&adapter->pdev->dev,
"%s: Invalid word count\n", __func__);
return -EIO;
@@ -2616,13 +2788,19 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
{
+ u8 pci_func;
int err;
u32 config = 0, state;
struct qlcnic_cmd_args cmd;
struct qlcnic_hardware_context *ahw = adapter->ahw;
- state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(ahw->pci_func));
- if (!QLC_83xx_FUNC_VAL(state, ahw->pci_func)) {
+ if (qlcnic_sriov_vf_check(adapter))
+ pci_func = adapter->portnum;
+ else
+ pci_func = ahw->pci_func;
+
+ state = readl(ahw->pci_base0 + QLC_83XX_LINK_STATE(pci_func));
+ if (!QLC_83xx_FUNC_VAL(state, pci_func)) {
dev_info(&adapter->pdev->dev, "link state down\n");
return config;
}
@@ -2752,6 +2930,9 @@ static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
/* fill in MAC rx frame stats */
for (k += 6; k < 80; k += 2)
data = qlcnic_83xx_copy_stats(cmd, data, k);
+ /* fill in eSwitch stats */
+ for (; k < total_regs; k += 2)
+ data = qlcnic_83xx_copy_stats(cmd, data, k);
break;
case QLC_83XX_STAT_RX:
for (k = 2; k < 8; k += 2)
@@ -2780,6 +2961,7 @@ static u64 *qlcnic_83xx_fill_stats(struct qlcnic_adapter *adapter,
void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
{
struct qlcnic_cmd_args cmd;
+ struct net_device *netdev = adapter->netdev;
int ret = 0;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_STATISTICS);
@@ -2789,7 +2971,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_TX, &ret);
if (ret) {
- dev_info(&adapter->pdev->dev, "Error getting MAC stats\n");
+ netdev_err(netdev, "Error getting Tx stats\n");
goto out;
}
/* Get MAC stats */
@@ -2799,8 +2981,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_MAC, &ret);
if (ret) {
- dev_info(&adapter->pdev->dev,
- "Error getting Rx stats\n");
+ netdev_err(netdev, "Error getting MAC stats\n");
goto out;
}
/* Get Rx stats */
@@ -2810,8 +2991,7 @@ void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data)
data = qlcnic_83xx_fill_stats(adapter, &cmd, data,
QLC_83XX_STAT_RX, &ret);
if (ret)
- dev_info(&adapter->pdev->dev,
- "Error getting Tx stats\n");
+ netdev_err(netdev, "Error getting Rx stats\n");
out:
qlcnic_free_mbx_args(&cmd);
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 61f81f6c84a9..1f1d85e6f2af 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -12,6 +12,8 @@
#include <linux/etherdevice.h>
#include "qlcnic_hw.h"
+#define QLCNIC_83XX_BAR0_LENGTH 0x4000
+
/* Directly mapped registers */
#define QLC_83XX_CRB_WIN_BASE 0x3800
#define QLC_83XX_CRB_WIN_FUNC(f) (QLC_83XX_CRB_WIN_BASE+((f)*4))
@@ -86,6 +88,153 @@
#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
+/* status descriptor mailbox data
+ * @phy_addr_{low|high}: physical address of buffer
+ * @sds_ring_size: buffer size
+ * @intrpt_id: interrupt id
+ * @intrpt_val: source of interrupt
+ */
+struct qlcnic_sds_mbx {
+ u32 phy_addr_low;
+ u32 phy_addr_high;
+ u32 rsvd1[4];
+#if defined(__LITTLE_ENDIAN)
+ u16 sds_ring_size;
+ u16 rsvd2;
+ u16 rsvd3[2];
+ u16 intrpt_id;
+ u8 intrpt_val;
+ u8 rsvd4;
+#elif defined(__BIG_ENDIAN)
+ u16 rsvd2;
+ u16 sds_ring_size;
+ u16 rsvd3[2];
+ u8 rsvd4;
+ u8 intrpt_val;
+ u16 intrpt_id;
+#endif
+ u32 rsvd5;
+} __packed;
+
+/* receive descriptor buffer data
+ * phy_addr_reg_{low|high}: physical address of regular buffer
+ * phy_addr_jmb_{low|high}: physical address of jumbo buffer
+ * reg_ring_sz: size of regular buffer
+ * reg_ring_len: no. of entries in regular buffer
+ * jmb_ring_len: no. of entries in jumbo buffer
+ * jmb_ring_sz: size of jumbo buffer
+ */
+struct qlcnic_rds_mbx {
+ u32 phy_addr_reg_low;
+ u32 phy_addr_reg_high;
+ u32 phy_addr_jmb_low;
+ u32 phy_addr_jmb_high;
+#if defined(__LITTLE_ENDIAN)
+ u16 reg_ring_sz;
+ u16 reg_ring_len;
+ u16 jmb_ring_sz;
+ u16 jmb_ring_len;
+#elif defined(__BIG_ENDIAN)
+ u16 reg_ring_len;
+ u16 reg_ring_sz;
+ u16 jmb_ring_len;
+ u16 jmb_ring_sz;
+#endif
+} __packed;
+
+/* host producers for regular and jumbo rings */
+struct __host_producer_mbx {
+ u32 reg_buf;
+ u32 jmb_buf;
+} __packed;
+
+/* Receive context mailbox data outbox registers
+ * @state: state of the context
+ * @vport_id: virtual port id
+ * @context_id: receive context id
+ * @num_pci_func: number of pci functions of the port
+ * @phy_port: physical port id
+ */
+struct qlcnic_rcv_mbx_out {
+#if defined(__LITTLE_ENDIAN)
+ u8 rcv_num;
+ u8 sts_num;
+ u16 ctx_id;
+ u8 state;
+ u8 num_pci_func;
+ u8 phy_port;
+ u8 vport_id;
+#elif defined(__BIG_ENDIAN)
+ u16 ctx_id;
+ u8 sts_num;
+ u8 rcv_num;
+ u8 vport_id;
+ u8 phy_port;
+ u8 num_pci_func;
+ u8 state;
+#endif
+ u32 host_csmr[QLCNIC_MAX_RING_SETS];
+ struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+struct qlcnic_add_rings_mbx_out {
+#if defined(__LITTLE_ENDIAN)
+ u8 rcv_num;
+ u8 sts_num;
+ u16 ctx_id;
+#elif defined(__BIG_ENDIAN)
+ u16 ctx_id;
+ u8 sts_num;
+ u8 rcv_num;
+#endif
+ u32 host_csmr[QLCNIC_MAX_RING_SETS];
+ struct __host_producer_mbx host_prod[QLCNIC_MAX_RING_SETS];
+} __packed;
+
+/* Transmit context mailbox inbox registers
+ * @phys_addr_{low|high}: DMA address of the transmit buffer
+ * @cnsmr_index_{low|high}: host consumer index
+ * @size: legth of transmit buffer ring
+ * @intr_id: interrput id
+ * @src: src of interrupt
+ */
+struct qlcnic_tx_mbx {
+ u32 phys_addr_low;
+ u32 phys_addr_high;
+ u32 cnsmr_index_low;
+ u32 cnsmr_index_high;
+#if defined(__LITTLE_ENDIAN)
+ u16 size;
+ u16 intr_id;
+ u8 src;
+ u8 rsvd[3];
+#elif defined(__BIG_ENDIAN)
+ u16 intr_id;
+ u16 size;
+ u8 rsvd[3];
+ u8 src;
+#endif
+} __packed;
+
+/* Transmit context mailbox outbox registers
+ * @host_prod: host producer index
+ * @ctx_id: transmit context id
+ * @state: state of the transmit context
+ */
+
+struct qlcnic_tx_mbx_out {
+ u32 host_prod;
+#if defined(__LITTLE_ENDIAN)
+ u16 ctx_id;
+ u8 state;
+ u8 rsvd;
+#elif defined(__BIG_ENDIAN)
+ u8 rsvd;
+ u8 state;
+ u16 ctx_id;
+#endif
+} __packed;
+
struct qlcnic_intrpt_config {
u8 type;
u8 enabled;
@@ -94,8 +243,23 @@ struct qlcnic_intrpt_config {
};
struct qlcnic_macvlan_mbx {
- u8 mac[ETH_ALEN];
+#if defined(__LITTLE_ENDIAN)
+ u8 mac_addr0;
+ u8 mac_addr1;
+ u8 mac_addr2;
+ u8 mac_addr3;
+ u8 mac_addr4;
+ u8 mac_addr5;
u16 vlan;
+#elif defined(__BIG_ENDIAN)
+ u8 mac_addr3;
+ u8 mac_addr2;
+ u8 mac_addr1;
+ u8 mac_addr0;
+ u16 vlan;
+ u8 mac_addr5;
+ u8 mac_addr4;
+#endif
};
struct qlc_83xx_fw_info {
@@ -153,6 +317,18 @@ struct qlc_83xx_idc {
char **name;
};
+/* Device States */
+enum qlcnic_83xx_states {
+ QLC_83XX_IDC_DEV_UNKNOWN,
+ QLC_83XX_IDC_DEV_COLD,
+ QLC_83XX_IDC_DEV_INIT,
+ QLC_83XX_IDC_DEV_READY,
+ QLC_83XX_IDC_DEV_NEED_RESET,
+ QLC_83XX_IDC_DEV_NEED_QUISCENT,
+ QLC_83XX_IDC_DEV_FAILED,
+ QLC_83XX_IDC_DEV_QUISCENT
+};
+
#define QLCNIC_MBX_RSP(reg) LSW(reg)
#define QLCNIC_MBX_NUM_REGS(reg) (MSW(reg) & 0x1FF)
#define QLCNIC_MBX_STATUS(reg) (((reg) >> 25) & 0x7F)
@@ -205,7 +381,7 @@ struct qlc_83xx_idc {
#define QLC_83XX_STAT_MAC 1
#define QLC_83XX_TX_STAT_REGS 14
#define QLC_83XX_RX_STAT_REGS 40
-#define QLC_83XX_MAC_STAT_REGS 80
+#define QLC_83XX_MAC_STAT_REGS 94
#define QLC_83XX_GET_FUNC_PRIVILEGE(VAL, FN) (0x3 & ((VAL) >> (FN * 2)))
#define QLC_83XX_SET_FUNC_OPMODE(VAL, FN) ((VAL) << (FN * 2))
@@ -226,6 +402,7 @@ struct qlc_83xx_idc {
#define QLC_83XX_GET_FW_LRO_MSS_CAPABILITY(val) (val & 0x20000)
#define QLC_83XX_VIRTUAL_NIC_MODE 0xFF
#define QLC_83XX_DEFAULT_MODE 0x0
+#define QLC_83XX_SRIOV_MODE 0x1
#define QLCNIC_BRDTYPE_83XX_10G 0x0083
#define QLC_83XX_FLASH_SPI_STATUS 0x2808E010
@@ -242,8 +419,8 @@ struct qlc_83xx_idc {
#define QLC_83XX_FLASH_BULK_WRITE_CMD 0xcadcadca
#define QLC_83XX_FLASH_READ_RETRY_COUNT 5000
#define QLC_83XX_FLASH_STATUS_READY 0x6
-#define QLC_83XX_FLASH_BULK_WRITE_MIN 2
-#define QLC_83XX_FLASH_BULK_WRITE_MAX 64
+#define QLC_83XX_FLASH_WRITE_MIN 2
+#define QLC_83XX_FLASH_WRITE_MAX 64
#define QLC_83XX_FLASH_STATUS_REG_POLL_DELAY 1
#define QLC_83XX_ERASE_MODE 1
#define QLC_83XX_WRITE_MODE 2
@@ -336,7 +513,7 @@ int qlcnic_83xx_clear_lb_mode(struct qlcnic_adapter *, u8);
int qlcnic_83xx_config_hw_lro(struct qlcnic_adapter *, int);
int qlcnic_83xx_config_rss(struct qlcnic_adapter *, int);
int qlcnic_83xx_config_intr_coalesce(struct qlcnic_adapter *);
-void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, __le16);
+void qlcnic_83xx_change_l2_filter(struct qlcnic_adapter *, u64 *, u16);
int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info *);
int qlcnic_83xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
void qlcnic_83xx_register_nic_idc_func(struct qlcnic_adapter *, int);
@@ -351,11 +528,14 @@ int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
int qlcnic_83xx_create_tx_ctx(struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *, int);
+void qlcnic_83xx_del_rx_ctx(struct qlcnic_adapter *);
+void qlcnic_83xx_del_tx_ctx(struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *);
int qlcnic_83xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
int qlcnic_83xx_setup_link_event(struct qlcnic_adapter *, int);
void qlcnic_83xx_process_rcv_ring_diag(struct qlcnic_host_sds_ring *);
int qlcnic_83xx_config_intrpt(struct qlcnic_adapter *, bool);
-int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8);
int qlcnic_83xx_get_mac_address(struct qlcnic_adapter *, u8 *);
void qlcnic_83xx_configure_mac(struct qlcnic_adapter *, u8 *, u8,
struct qlcnic_cmd_args *);
@@ -368,6 +548,7 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *);
irqreturn_t qlcnic_83xx_handle_aen(int, void *);
int qlcnic_83xx_get_port_info(struct qlcnic_adapter *);
void qlcnic_83xx_enable_mbx_intrpt(struct qlcnic_adapter *);
+void qlcnic_83xx_disable_mbx_intr(struct qlcnic_adapter *);
irqreturn_t qlcnic_83xx_clear_legacy_intr(struct qlcnic_adapter *);
irqreturn_t qlcnic_83xx_intr(int, void *);
irqreturn_t qlcnic_83xx_tmp_intr(int, void *);
@@ -377,7 +558,7 @@ void qlcnic_83xx_disable_intr(struct qlcnic_adapter *,
struct qlcnic_host_sds_ring *);
void qlcnic_83xx_check_vf(struct qlcnic_adapter *,
const struct pci_device_id *);
-void qlcnic_83xx_process_aen(struct qlcnic_adapter *);
+void __qlcnic_83xx_process_aen(struct qlcnic_adapter *);
int qlcnic_83xx_get_port_config(struct qlcnic_adapter *);
int qlcnic_83xx_set_port_config(struct qlcnic_adapter *);
int qlcnic_enable_eswitch(struct qlcnic_adapter *, u8, u8);
@@ -401,7 +582,7 @@ int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *);
int qlcnic_83xx_flash_read32(struct qlcnic_adapter *, u32, u8 *, int);
int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *,
u32, u8 *, int);
-int qlcnic_83xx_init(struct qlcnic_adapter *);
+int qlcnic_83xx_init(struct qlcnic_adapter *, int);
int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *);
int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
void qlcnic_83xx_idc_poll_dev_state(struct work_struct *);
@@ -434,5 +615,12 @@ int qlcnic_83xx_get_regs_len(struct qlcnic_adapter *);
int qlcnic_83xx_get_registers(struct qlcnic_adapter *, u32 *);
int qlcnic_83xx_loopback_test(struct net_device *, u8);
int qlcnic_83xx_interrupt_test(struct net_device *);
+int qlcnic_83xx_set_led(struct net_device *, enum ethtool_phys_id_state);
int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
+int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
+int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
+u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
+u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *);
+void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);
+void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *);
#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index 5c033f268ca5..ab1d8d99cbd5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -5,6 +5,7 @@
* See LICENSE.qlcnic for copyright and licensing details.
*/
+#include "qlcnic_sriov.h"
#include "qlcnic.h"
#include "qlcnic_hw.h"
@@ -24,13 +25,24 @@
#define QLC_83XX_OPCODE_TMPL_END 0x0080
#define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100
+/* EPORT control registers */
+#define QLC_83XX_RESET_CONTROL 0x28084E50
+#define QLC_83XX_RESET_REG 0x28084E60
+#define QLC_83XX_RESET_PORT0 0x28084E70
+#define QLC_83XX_RESET_PORT1 0x28084E80
+#define QLC_83XX_RESET_PORT2 0x28084E90
+#define QLC_83XX_RESET_PORT3 0x28084EA0
+#define QLC_83XX_RESET_SRESHIM 0x28084EB0
+#define QLC_83XX_RESET_EPGSHIM 0x28084EC0
+#define QLC_83XX_RESET_ETHERPCS 0x28084ED0
+
static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
-static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
/* Template header */
struct qlc_83xx_reset_hdr {
+#if defined(__LITTLE_ENDIAN)
u16 version;
u16 signature;
u16 size;
@@ -39,14 +51,31 @@ struct qlc_83xx_reset_hdr {
u16 checksum;
u16 init_offset;
u16 start_offset;
+#elif defined(__BIG_ENDIAN)
+ u16 signature;
+ u16 version;
+ u16 entries;
+ u16 size;
+ u16 checksum;
+ u16 hdr_size;
+ u16 start_offset;
+ u16 init_offset;
+#endif
} __packed;
/* Command entry header. */
struct qlc_83xx_entry_hdr {
- u16 cmd;
- u16 size;
- u16 count;
- u16 delay;
+#if defined(__LITTLE_ENDIAN)
+ u16 cmd;
+ u16 size;
+ u16 count;
+ u16 delay;
+#elif defined(__BIG_ENDIAN)
+ u16 size;
+ u16 cmd;
+ u16 delay;
+ u16 count;
+#endif
} __packed;
/* Generic poll command */
@@ -60,10 +89,17 @@ struct qlc_83xx_rmw {
u32 mask;
u32 xor_value;
u32 or_value;
+#if defined(__LITTLE_ENDIAN)
u8 shl;
u8 shr;
u8 index_a;
u8 rsvd;
+#elif defined(__BIG_ENDIAN)
+ u8 rsvd;
+ u8 index_a;
+ u8 shr;
+ u8 shl;
+#endif
} __packed;
/* Generic command with 2 DWORD */
@@ -90,18 +126,6 @@ static const char *const qlc_83xx_idc_states[] = {
"Quiesce"
};
-/* Device States */
-enum qlcnic_83xx_states {
- QLC_83XX_IDC_DEV_UNKNOWN,
- QLC_83XX_IDC_DEV_COLD,
- QLC_83XX_IDC_DEV_INIT,
- QLC_83XX_IDC_DEV_READY,
- QLC_83XX_IDC_DEV_NEED_RESET,
- QLC_83XX_IDC_DEV_NEED_QUISCENT,
- QLC_83XX_IDC_DEV_FAILED,
- QLC_83XX_IDC_DEV_QUISCENT
-};
-
static int
qlcnic_83xx_idc_check_driver_presence_reg(struct qlcnic_adapter *adapter)
{
@@ -137,7 +161,8 @@ static int qlcnic_83xx_idc_update_audit_reg(struct qlcnic_adapter *adapter,
return -EBUSY;
}
- val = adapter->portnum & 0xf;
+ val = QLCRDX(adapter->ahw, QLC_83XX_IDC_DRV_AUDIT);
+ val |= (adapter->portnum & 0xf);
val |= mode << 7;
if (mode)
seconds = jiffies / HZ - adapter->ahw->idc.sec_counter;
@@ -376,14 +401,18 @@ static void qlcnic_83xx_idc_detach_driver(struct qlcnic_adapter *adapter)
struct net_device *netdev = adapter->netdev;
netif_device_detach(netdev);
+
/* Disable mailbox interrupt */
- QLCWRX(adapter->ahw, QLCNIC_MBX_INTR_ENBL, 0);
+ qlcnic_83xx_disable_mbx_intr(adapter);
qlcnic_down(adapter, netdev);
for (i = 0; i < adapter->ahw->num_msix; i++) {
adapter->ahw->intr_tbl[i].id = i;
adapter->ahw->intr_tbl[i].enabled = 0;
adapter->ahw->intr_tbl[i].src = 0;
}
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_sriov_pf_reset(adapter);
}
/**
@@ -585,9 +614,15 @@ static int qlcnic_83xx_idc_check_fan_failure(struct qlcnic_adapter *adapter)
static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
{
+ int err;
+
/* register for NIC IDC AEN Events */
qlcnic_83xx_register_nic_idc_func(adapter, 1);
+ err = qlcnic_sriov_pf_reinit(adapter);
+ if (err)
+ return err;
+
qlcnic_83xx_enable_mbx_intrpt(adapter);
if (qlcnic_83xx_configure_opmode(adapter)) {
@@ -1350,6 +1385,19 @@ static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
qlcnic_83xx_unlock_driver(adapter);
}
+static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter)
+{
+ QLCWR32(adapter, QLC_83XX_RESET_REG, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_PORT0, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_PORT1, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_PORT2, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_PORT3, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_SRESHIM, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_EPGSHIM, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_ETHERPCS, 0);
+ QLCWR32(adapter, QLC_83XX_RESET_CONTROL, 1);
+}
+
static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
{
u32 heartbeat, peg_status;
@@ -1371,6 +1419,7 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
if (ret) {
dev_err(&p_dev->pdev->dev, "firmware hang detected\n");
+ qlcnic_83xx_take_eport_out_of_reset(p_dev);
qlcnic_83xx_disable_pause_frames(p_dev);
peg_status = QLC_SHARED_REG_RD32(p_dev,
QLCNIC_PEG_HALT_STATUS1);
@@ -1893,6 +1942,9 @@ int qlcnic_83xx_config_default_opmode(struct qlcnic_adapter *adapter)
qlcnic_get_func_no(adapter);
op_mode = QLCRDX(ahw, QLC_83XX_DRV_OP_MODE);
+ if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state))
+ op_mode = QLC_83XX_DEFAULT_OPMODE;
+
if (op_mode == QLC_83XX_DEFAULT_OPMODE) {
adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver;
ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
@@ -1922,6 +1974,16 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
ahw->max_mac_filters = nic_info.max_mac_filters;
ahw->max_mtu = nic_info.max_mtu;
+ /* VNIC mode is detected by BIT_23 in capabilities. This bit is also
+ * set in case device is SRIOV capable. VNIC and SRIOV are mutually
+ * exclusive. So in case of sriov capable device load driver in
+ * default mode
+ */
+ if (test_bit(__QLCNIC_SRIOV_CAPABLE, &adapter->state)) {
+ ahw->nic_mode = QLC_83XX_DEFAULT_MODE;
+ return ahw->nic_mode;
+ }
+
if (ahw->capabilities & BIT_23)
ahw->nic_mode = QLC_83XX_VIRTUAL_NIC_MODE;
else
@@ -1930,7 +1992,7 @@ int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter)
return ahw->nic_mode;
}
-static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter)
{
int ret;
@@ -2008,10 +2070,13 @@ static void qlcnic_83xx_clear_function_resources(struct qlcnic_adapter *adapter)
}
}
-int qlcnic_83xx_init(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ if (qlcnic_sriov_vf_check(adapter))
+ return qlcnic_sriov_vf_init(adapter, pci_using_dac);
+
if (qlcnic_83xx_check_hw_status(adapter))
return -EIO;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index a69097c6b84d..43562c256379 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -382,8 +382,7 @@ out_free_rq:
return err;
}
-static void
-qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *adapter)
{
int err;
struct qlcnic_cmd_args cmd;
@@ -422,22 +421,20 @@ int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter,
rq_size = SIZEOF_HOSTRQ_TX(struct qlcnic_hostrq_tx_ctx);
rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
- &rq_phys_addr, GFP_KERNEL);
+ &rq_phys_addr, GFP_KERNEL | __GFP_ZERO);
if (!rq_addr)
return -ENOMEM;
rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx);
rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size,
- &rsp_phys_addr, GFP_KERNEL);
+ &rsp_phys_addr, GFP_KERNEL | __GFP_ZERO);
if (!rsp_addr) {
err = -ENOMEM;
goto out_free_rq;
}
- memset(rq_addr, 0, rq_size);
prq = rq_addr;
- memset(rsp_addr, 0, rsp_size);
prsp = rsp_addr;
prq->host_rsp_dma_addr = cpu_to_le64(rsp_phys_addr);
@@ -486,13 +483,13 @@ out_free_rq:
return err;
}
-static void
-qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter,
- struct qlcnic_host_tx_ring *tx_ring)
+void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring)
{
struct qlcnic_cmd_args cmd;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX);
+
cmd.req.arg[1] = tx_ring->ctx_id;
if (qlcnic_issue_cmd(adapter, &cmd))
dev_err(&adapter->pdev->dev,
@@ -532,20 +529,15 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
ptr = (__le32 *)dma_alloc_coherent(&pdev->dev, sizeof(u32),
&tx_ring->hw_cons_phys_addr,
GFP_KERNEL);
-
- if (ptr == NULL) {
- dev_err(&pdev->dev, "failed to allocate tx consumer\n");
+ if (ptr == NULL)
return -ENOMEM;
- }
+
tx_ring->hw_consumer = ptr;
/* cmd desc ring */
addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
&tx_ring->phys_addr,
GFP_KERNEL);
-
if (addr == NULL) {
- dev_err(&pdev->dev,
- "failed to allocate tx desc ring\n");
err = -ENOMEM;
goto err_out_free;
}
@@ -556,11 +548,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
addr = dma_alloc_coherent(&adapter->pdev->dev,
- RCV_DESC_RINGSIZE(rds_ring),
- &rds_ring->phys_addr, GFP_KERNEL);
+ RCV_DESC_RINGSIZE(rds_ring),
+ &rds_ring->phys_addr, GFP_KERNEL);
if (addr == NULL) {
- dev_err(&pdev->dev,
- "failed to allocate rds ring [%d]\n", ring);
err = -ENOMEM;
goto err_out_free;
}
@@ -572,11 +562,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
sds_ring = &recv_ctx->sds_rings[ring];
addr = dma_alloc_coherent(&adapter->pdev->dev,
- STATUS_DESC_RINGSIZE(sds_ring),
- &sds_ring->phys_addr, GFP_KERNEL);
+ STATUS_DESC_RINGSIZE(sds_ring),
+ &sds_ring->phys_addr, GFP_KERNEL);
if (addr == NULL) {
- dev_err(&pdev->dev,
- "failed to allocate sds ring [%d]\n", ring);
err = -ENOMEM;
goto err_out_free;
}
@@ -616,13 +604,12 @@ int qlcnic_fw_create_ctx(struct qlcnic_adapter *dev)
&dev->tx_ring[ring],
ring);
if (err) {
- qlcnic_fw_cmd_destroy_rx_ctx(dev);
+ qlcnic_fw_cmd_del_rx_ctx(dev);
if (ring == 0)
goto err_out;
for (i = 0; i < ring; i++)
- qlcnic_fw_cmd_destroy_tx_ctx(dev,
- &dev->tx_ring[i]);
+ qlcnic_fw_cmd_del_tx_ctx(dev, &dev->tx_ring[i]);
goto err_out;
}
@@ -644,10 +631,10 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
int ring;
if (test_and_clear_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) {
- qlcnic_fw_cmd_destroy_rx_ctx(adapter);
+ qlcnic_fw_cmd_del_rx_ctx(adapter);
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++)
- qlcnic_fw_cmd_destroy_tx_ctx(adapter,
- &adapter->tx_ring[ring]);
+ qlcnic_fw_cmd_del_tx_ctx(adapter,
+ &adapter->tx_ring[ring]);
if (qlcnic_83xx_check(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED)) {
@@ -655,7 +642,7 @@ void qlcnic_fw_destroy_ctx(struct qlcnic_adapter *adapter)
qlcnic_83xx_config_intrpt(adapter, 0);
}
/* Allow dma queues to drain after context reset */
- mdelay(20);
+ msleep(20);
}
}
@@ -753,10 +740,9 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter,
size_t nic_size = sizeof(struct qlcnic_info_le);
nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
- &nic_dma_t, GFP_KERNEL);
+ &nic_dma_t, GFP_KERNEL | __GFP_ZERO);
if (!nic_info_addr)
return -ENOMEM;
- memset(nic_info_addr, 0, nic_size);
nic_info = nic_info_addr;
@@ -804,11 +790,10 @@ int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *adapter,
return err;
nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
- &nic_dma_t, GFP_KERNEL);
+ &nic_dma_t, GFP_KERNEL | __GFP_ZERO);
if (!nic_info_addr)
return -ENOMEM;
- memset(nic_info_addr, 0, nic_size);
nic_info = nic_info_addr;
nic_info->pci_func = cpu_to_le16(nic->pci_func);
@@ -854,10 +839,10 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;
pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size,
- &pci_info_dma_t, GFP_KERNEL);
+ &pci_info_dma_t,
+ GFP_KERNEL | __GFP_ZERO);
if (!pci_info_addr)
return -ENOMEM;
- memset(pci_info_addr, 0, pci_size);
npar = pci_info_addr;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
@@ -949,12 +934,9 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
}
stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
- &stats_dma_t, GFP_KERNEL);
- if (!stats_addr) {
- dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
+ &stats_dma_t, GFP_KERNEL | __GFP_ZERO);
+ if (!stats_addr)
return -ENOMEM;
- }
- memset(stats_addr, 0, stats_size);
arg1 = func | QLCNIC_STATS_VERSION << 8 | QLCNIC_STATS_PORT << 12;
arg1 |= rx_tx << 15 | stats_size << 16;
@@ -1003,13 +985,10 @@ int qlcnic_get_mac_stats(struct qlcnic_adapter *adapter,
return -ENOMEM;
stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
- &stats_dma_t, GFP_KERNEL);
- if (!stats_addr) {
- dev_err(&adapter->pdev->dev,
- "%s: Unable to allocate memory.\n", __func__);
+ &stats_dma_t, GFP_KERNEL | __GFP_ZERO);
+ if (!stats_addr)
return -ENOMEM;
- }
- memset(stats_addr, 0, stats_size);
+
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_MAC_STATS);
cmd.req.arg[1] = stats_size << 16;
cmd.req.arg[2] = MSD(stats_dma_t);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 5641f8ec49ab..08efb4635007 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -115,6 +115,13 @@ static const char qlcnic_83xx_mac_stats_strings[][ETH_GSTRING_LEN] = {
"mac_rx_dropped",
"mac_crc_error",
"mac_align_error",
+ "eswitch_frames",
+ "eswitch_bytes",
+ "eswitch_multicast_frames",
+ "eswitch_broadcast_frames",
+ "eswitch_unicast_frames",
+ "eswitch_error_free_frames",
+ "eswitch_error_free_bytes",
};
#define QLCNIC_STATS_LEN ARRAY_SIZE(qlcnic_gstrings_stats)
@@ -149,7 +156,8 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
static inline int qlcnic_82xx_statistics(void)
{
- return QLCNIC_STATS_LEN + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+ return ARRAY_SIZE(qlcnic_device_gstrings_stats) +
+ ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
}
static inline int qlcnic_83xx_statistics(void)
@@ -634,7 +642,7 @@ static int qlcnic_set_channels(struct net_device *dev,
channel->tx_count != channel->max_tx)
return -EINVAL;
- err = qlcnic_validate_max_rss(channel->max_rx, channel->rx_count);
+ err = qlcnic_validate_max_rss(adapter, channel->rx_count);
if (err)
return err;
@@ -858,9 +866,11 @@ clear_diag_irq:
return ret;
}
-#define QLCNIC_ILB_PKT_SIZE 64
-#define QLCNIC_NUM_ILB_PKT 16
-#define QLCNIC_ILB_MAX_RCV_LOOP 10
+#define QLCNIC_ILB_PKT_SIZE 64
+#define QLCNIC_NUM_ILB_PKT 16
+#define QLCNIC_ILB_MAX_RCV_LOOP 10
+#define QLCNIC_LB_PKT_POLL_DELAY_MSEC 1
+#define QLCNIC_LB_PKT_POLL_COUNT 20
static void qlcnic_create_loopback_buff(unsigned char *data, u8 mac[])
{
@@ -897,9 +907,9 @@ int qlcnic_do_lb_test(struct qlcnic_adapter *adapter, u8 mode)
loop = 0;
do {
- msleep(1);
+ msleep(QLCNIC_LB_PKT_POLL_DELAY_MSEC);
qlcnic_process_rcv_ring_diag(sds_ring);
- if (loop++ > QLCNIC_ILB_MAX_RCV_LOOP)
+ if (loop++ > QLCNIC_LB_PKT_POLL_COUNT)
break;
} while (!adapter->ahw->diag_cnt);
@@ -1070,8 +1080,7 @@ qlcnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static void
-qlcnic_fill_stats(u64 *data, void *stats, int type)
+static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
{
if (type == QLCNIC_MAC_STATS) {
struct qlcnic_mac_statistics *mac_stats =
@@ -1120,6 +1129,7 @@ qlcnic_fill_stats(u64 *data, void *stats, int type)
*data++ = QLCNIC_FILL_STATS(esw_stats->local_frames);
*data++ = QLCNIC_FILL_STATS(esw_stats->numbytes);
}
+ return data;
}
static void qlcnic_get_ethtool_stats(struct net_device *dev,
@@ -1147,7 +1157,7 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
/* Retrieve MAC statistics from firmware */
memset(&mac_stats, 0, sizeof(struct qlcnic_mac_statistics));
qlcnic_get_mac_stats(adapter, &mac_stats);
- qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
+ data = qlcnic_fill_stats(data, &mac_stats, QLCNIC_MAC_STATS);
}
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
@@ -1159,7 +1169,7 @@ static void qlcnic_get_ethtool_stats(struct net_device *dev,
if (ret)
return;
- qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
+ data = qlcnic_fill_stats(data, &port_stats.rx, QLCNIC_ESW_STATS);
ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
if (ret)
@@ -1176,7 +1186,8 @@ static int qlcnic_set_led(struct net_device *dev,
int err = -EIO, active = 1;
if (qlcnic_83xx_check(adapter))
- return -EOPNOTSUPP;
+ return qlcnic_83xx_set_led(dev, state);
+
if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
netdev_warn(dev, "LED test not supported for non "
"privilege function\n");
@@ -1292,6 +1303,9 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ethcoal)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_nic_intr_coalesce *coal;
+ u32 rx_coalesce_usecs, rx_max_frames;
+ u32 tx_coalesce_usecs, tx_max_frames;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
return -EINVAL;
@@ -1302,8 +1316,8 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
*/
if (ethcoal->rx_coalesce_usecs > 0xffff ||
ethcoal->rx_max_coalesced_frames > 0xffff ||
- ethcoal->tx_coalesce_usecs ||
- ethcoal->tx_max_coalesced_frames ||
+ ethcoal->tx_coalesce_usecs > 0xffff ||
+ ethcoal->tx_max_coalesced_frames > 0xffff ||
ethcoal->rx_coalesce_usecs_irq ||
ethcoal->rx_max_coalesced_frames_irq ||
ethcoal->tx_coalesce_usecs_irq ||
@@ -1323,18 +1337,55 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
ethcoal->tx_max_coalesced_frames_high)
return -EINVAL;
- if (!ethcoal->rx_coalesce_usecs ||
- !ethcoal->rx_max_coalesced_frames) {
- adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
- adapter->ahw->coal.rx_time_us =
- QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
- adapter->ahw->coal.rx_packets =
- QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ coal = &adapter->ahw->coal;
+
+ if (qlcnic_83xx_check(adapter)) {
+ if (!ethcoal->tx_coalesce_usecs ||
+ !ethcoal->tx_max_coalesced_frames ||
+ !ethcoal->rx_coalesce_usecs ||
+ !ethcoal->rx_max_coalesced_frames) {
+ coal->flag = QLCNIC_INTR_DEFAULT;
+ coal->type = QLCNIC_INTR_COAL_TYPE_RX;
+ coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
+ coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
+ coal->tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
+ coal->tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
+ } else {
+ tx_coalesce_usecs = ethcoal->tx_coalesce_usecs;
+ tx_max_frames = ethcoal->tx_max_coalesced_frames;
+ rx_coalesce_usecs = ethcoal->rx_coalesce_usecs;
+ rx_max_frames = ethcoal->rx_max_coalesced_frames;
+ coal->flag = 0;
+
+ if ((coal->rx_time_us == rx_coalesce_usecs) &&
+ (coal->rx_packets == rx_max_frames)) {
+ coal->type = QLCNIC_INTR_COAL_TYPE_TX;
+ coal->tx_time_us = tx_coalesce_usecs;
+ coal->tx_packets = tx_max_frames;
+ } else if ((coal->tx_time_us == tx_coalesce_usecs) &&
+ (coal->tx_packets == tx_max_frames)) {
+ coal->type = QLCNIC_INTR_COAL_TYPE_RX;
+ coal->rx_time_us = rx_coalesce_usecs;
+ coal->rx_packets = rx_max_frames;
+ } else {
+ coal->type = QLCNIC_INTR_COAL_TYPE_RX;
+ coal->rx_time_us = rx_coalesce_usecs;
+ coal->rx_packets = rx_max_frames;
+ coal->tx_time_us = tx_coalesce_usecs;
+ coal->tx_packets = tx_max_frames;
+ }
+ }
} else {
- adapter->ahw->coal.flag = 0;
- adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
- adapter->ahw->coal.rx_packets =
- ethcoal->rx_max_coalesced_frames;
+ if (!ethcoal->rx_coalesce_usecs ||
+ !ethcoal->rx_max_coalesced_frames) {
+ coal->flag = QLCNIC_INTR_DEFAULT;
+ coal->rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
+ coal->rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
+ } else {
+ coal->flag = 0;
+ coal->rx_time_us = ethcoal->rx_coalesce_usecs;
+ coal->rx_packets = ethcoal->rx_max_coalesced_frames;
+ }
}
qlcnic_config_intr_coalesce(adapter);
@@ -1352,6 +1403,8 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev,
ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
+ ethcoal->tx_coalesce_usecs = adapter->ahw->coal.tx_time_us;
+ ethcoal->tx_max_coalesced_frames = adapter->ahw->coal.tx_packets;
return 0;
}
@@ -1537,3 +1590,25 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_dump_data = qlcnic_get_dump_data,
.set_dump = qlcnic_set_dump,
};
+
+const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops = {
+ .get_settings = qlcnic_get_settings,
+ .get_drvinfo = qlcnic_get_drvinfo,
+ .get_regs_len = qlcnic_get_regs_len,
+ .get_regs = qlcnic_get_regs,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = qlcnic_get_eeprom_len,
+ .get_eeprom = qlcnic_get_eeprom,
+ .get_ringparam = qlcnic_get_ringparam,
+ .set_ringparam = qlcnic_set_ringparam,
+ .get_channels = qlcnic_get_channels,
+ .get_pauseparam = qlcnic_get_pauseparam,
+ .get_wol = qlcnic_get_wol,
+ .get_strings = qlcnic_get_strings,
+ .get_ethtool_stats = qlcnic_get_ethtool_stats,
+ .get_sset_count = qlcnic_get_sset_count,
+ .get_coalesce = qlcnic_get_intr_coalesce,
+ .set_coalesce = qlcnic_set_intr_coalesce,
+ .set_msglevel = qlcnic_set_msglevel,
+ .get_msglevel = qlcnic_get_msglevel,
+};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
index 44197ca1456c..c0f0c0d0a790 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
@@ -669,7 +669,7 @@ enum {
#define QLCNIC_CMDPEG_CHECK_RETRY_COUNT 60
#define QLCNIC_CMDPEG_CHECK_DELAY 500
#define QLCNIC_HEARTBEAT_PERIOD_MSECS 200
-#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 45
+#define QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT 10
#define QLCNIC_MAX_MC_COUNT 38
#define QLCNIC_WATCHDOG_TIMEOUTVALUE 5
@@ -714,7 +714,9 @@ enum {
QLCNIC_MGMT_FUNC = 0,
QLCNIC_PRIV_FUNC = 1,
QLCNIC_NON_PRIV_FUNC = 2,
- QLCNIC_UNKNOWN_FUNC_MODE = 3
+ QLCNIC_SRIOV_PF_FUNC = 3,
+ QLCNIC_SRIOV_VF_FUNC = 4,
+ QLCNIC_UNKNOWN_FUNC_MODE = 5
};
enum {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index f89cc7a3fe6c..6a6512ba9f38 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -423,7 +423,7 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
}
int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
- __le16 vlan_id, u8 op)
+ u16 vlan_id, u8 op)
{
struct qlcnic_nic_req req;
struct qlcnic_mac_req *mac_req;
@@ -441,7 +441,7 @@ int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
memcpy(mac_req->mac_addr, addr, 6);
vlan_req = (struct qlcnic_vlan_req *)&req.words[1];
- vlan_req->vlan_id = vlan_id;
+ vlan_req->vlan_id = cpu_to_le16(vlan_id);
return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
}
@@ -468,7 +468,7 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
return err;
}
-int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
{
struct list_head *head;
struct qlcnic_mac_list_s *cur;
@@ -487,7 +487,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
memcpy(cur->mac_addr, addr, ETH_ALEN);
if (qlcnic_sre_macaddr_change(adapter,
- cur->mac_addr, 0, QLCNIC_MAC_ADD)) {
+ cur->mac_addr, vlan, QLCNIC_MAC_ADD)) {
kfree(cur);
return -EIO;
}
@@ -496,7 +496,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
return 0;
}
-void qlcnic_set_multi(struct net_device *netdev)
+void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct netdev_hw_addr *ha;
@@ -508,8 +508,9 @@ void qlcnic_set_multi(struct net_device *netdev)
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
- qlcnic_nic_add_mac(adapter, adapter->mac_addr);
- qlcnic_nic_add_mac(adapter, bcast_addr);
+ if (!qlcnic_sriov_vf_check(adapter))
+ qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);
+ qlcnic_nic_add_mac(adapter, bcast_addr, vlan);
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
@@ -523,23 +524,55 @@ void qlcnic_set_multi(struct net_device *netdev)
goto send_fw_cmd;
}
- if (!netdev_mc_empty(netdev)) {
+ if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) {
netdev_for_each_mc_addr(ha, netdev) {
- qlcnic_nic_add_mac(adapter, ha->addr);
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan);
}
}
+ if (qlcnic_sriov_vf_check(adapter))
+ qlcnic_vf_add_mc_list(netdev, vlan);
+
send_fw_cmd:
- if (mode == VPORT_MISS_MODE_ACCEPT_ALL && !adapter->fdb_mac_learn) {
- qlcnic_alloc_lb_filters_mem(adapter);
- adapter->drv_mac_learn = true;
- } else {
- adapter->drv_mac_learn = false;
+ if (!qlcnic_sriov_vf_check(adapter)) {
+ if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
+ !adapter->fdb_mac_learn) {
+ qlcnic_alloc_lb_filters_mem(adapter);
+ adapter->drv_mac_learn = true;
+ } else {
+ adapter->drv_mac_learn = false;
+ }
}
qlcnic_nic_set_promisc(adapter, mode);
}
+void qlcnic_set_multi(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct netdev_hw_addr *ha;
+ struct qlcnic_mac_list_s *cur;
+
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
+ return;
+ if (qlcnic_sriov_vf_check(adapter)) {
+ if (!netdev_mc_empty(netdev)) {
+ netdev_for_each_mc_addr(ha, netdev) {
+ cur = kzalloc(sizeof(struct qlcnic_mac_list_s),
+ GFP_ATOMIC);
+ if (cur == NULL)
+ break;
+ memcpy(cur->mac_addr,
+ ha->addr, ETH_ALEN);
+ list_add_tail(&cur->list, &adapter->vf_mc_list);
+ }
+ }
+ qlcnic_sriov_vf_schedule_multi(adapter->netdev);
+ return;
+ }
+ __qlcnic_set_multi(netdev, 0);
+}
+
int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
{
struct qlcnic_nic_req req;
@@ -559,7 +592,7 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
(struct cmd_desc_type0 *)&req, 1);
}
-void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
+void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)
{
struct qlcnic_mac_list_s *cur;
struct list_head *head = &adapter->mac_list;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 5b8749eda11f..95b1b5732838 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -83,6 +83,8 @@ enum qlcnic_regs {
#define QLCNIC_CMD_CONFIG_PORT 0x2e
#define QLCNIC_CMD_TEMP_SIZE 0x2f
#define QLCNIC_CMD_GET_TEMP_HDR 0x30
+#define QLCNIC_CMD_BC_EVENT_SETUP 0x31
+#define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_GET_MAC_STATS 0x37
#define QLCNIC_CMD_SET_DRV_VER 0x38
#define QLCNIC_CMD_CONFIGURE_RSS 0x41
@@ -114,6 +116,7 @@ enum qlcnic_regs {
#define QLCNIC_SET_FAC_DEF_MAC 5
#define QLCNIC_MBX_LINK_EVENT 0x8001
+#define QLCNIC_MBX_BC_EVENT 0x8002
#define QLCNIC_MBX_COMP_EVENT 0x8100
#define QLCNIC_MBX_REQUEST_EVENT 0x8101
#define QLCNIC_MBX_TIME_EXTEND_EVENT 0x8102
@@ -156,7 +159,7 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
struct net_device *netdev);
void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
- u64 *uaddr, __le16 vlan_id);
+ u64 *uaddr, u16 vlan_id);
void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter);
int qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int);
void qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
@@ -175,7 +178,10 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
int qlcnic_82xx_fw_cmd_create_rx_ctx(struct qlcnic_adapter *);
int qlcnic_82xx_fw_cmd_create_tx_ctx(struct qlcnic_adapter *,
struct qlcnic_host_tx_ring *tx_ring, int);
-int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, __le16, u8);
+void qlcnic_82xx_fw_cmd_del_rx_ctx(struct qlcnic_adapter *);
+void qlcnic_82xx_fw_cmd_del_tx_ctx(struct qlcnic_adapter *,
+ struct qlcnic_host_tx_ring *);
+int qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *, u8 *, u16, u8);
int qlcnic_82xx_get_mac_address(struct qlcnic_adapter *, u8*);
int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
int qlcnic_82xx_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 0e630061bff3..d3f8797efcc3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -9,6 +9,7 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
+#include <net/checksum.h>
#include "qlcnic.h"
@@ -146,7 +147,10 @@ static inline u8 qlcnic_mac_hash(u64 mac)
static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
u16 handle, u8 ring_id)
{
- if (adapter->pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X)
+ unsigned short device = adapter->pdev->device;
+
+ if ((device == PCI_DEVICE_ID_QLOGIC_QLE834X) ||
+ (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X))
return handle | (ring_id << 15);
else
return handle;
@@ -158,7 +162,7 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
}
void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
- int loopback_pkt, __le16 vlan_id)
+ int loopback_pkt, u16 vlan_id)
{
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
struct qlcnic_filter *fil, *tmp_fil;
@@ -236,7 +240,7 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
}
void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
- __le16 vlan_id)
+ u16 vlan_id)
{
struct cmd_desc_type0 *hwdesc;
struct qlcnic_nic_req *req;
@@ -261,7 +265,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
- vlan_req->vlan_id = vlan_id;
+ vlan_req->vlan_id = cpu_to_le16(vlan_id);
tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
smp_mb();
@@ -277,7 +281,7 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
struct net_device *netdev = adapter->netdev;
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
u64 src_addr = 0;
- __le16 vlan_id = 0;
+ u16 vlan_id = 0;
u8 hindex;
if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
@@ -340,14 +344,14 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
flags = FLAGS_VLAN_OOB;
vlan_tci = vlan_tx_tag_get(skb);
}
- if (unlikely(adapter->pvid)) {
+ if (unlikely(adapter->tx_pvid)) {
if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
return -EIO;
if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
goto set_flags;
flags = FLAGS_VLAN_OOB;
- vlan_tci = adapter->pvid;
+ vlan_tci = adapter->tx_pvid;
}
set_flags:
qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
@@ -358,8 +362,7 @@ set_flags:
memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
}
opcode = TX_ETHER_PKT;
- if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
- skb_shinfo(skb)->gso_size > 0) {
+ if (skb_is_gso(skb)) {
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
first_desc->total_hdr_length = hdr_len;
@@ -976,10 +979,10 @@ static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter,
memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
skb_pull(skb, VLAN_HLEN);
}
- if (!adapter->pvid)
+ if (!adapter->rx_pvid)
return 0;
- if (*vlan_tag == adapter->pvid) {
+ if (*vlan_tag == adapter->rx_pvid) {
/* Outer vlan tag. Packet should follow non-vlan path */
*vlan_tag = 0xffff;
return 0;
@@ -1025,8 +1028,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
t_vid = 0;
is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
- qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
- cpu_to_le16(t_vid));
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
}
if (length > rds_ring->skb_size)
@@ -1046,7 +1048,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
napi_gro_receive(&sds_ring->napi, skb);
@@ -1103,8 +1105,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
t_vid = 0;
is_lb_pkt = qlcnic_82xx_is_lb_pkt(sts_data0);
- qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
- cpu_to_le16(t_vid));
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
}
if (timestamp)
@@ -1132,9 +1133,8 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
iph = (struct iphdr *)skb->data;
th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ csum_replace2(&iph->check, iph->tot_len, htons(length));
iph->tot_len = htons(length);
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
th->psh = push;
@@ -1150,7 +1150,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
}
if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
netif_receive_skb(skb);
adapter->stats.lro_pkts++;
@@ -1497,8 +1497,7 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
t_vid = 0;
is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
- qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
- cpu_to_le16(t_vid));
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
}
if (length > rds_ring->skb_size)
@@ -1515,7 +1514,7 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
napi_gro_receive(&sds_ring->napi, skb);
@@ -1567,8 +1566,7 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
t_vid = 0;
is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
- qlcnic_add_lb_filter(adapter, skb, is_lb_pkt,
- cpu_to_le16(t_vid));
+ qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
}
if (qlcnic_83xx_is_tstamp(sts_data[1]))
data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
@@ -1595,9 +1593,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
iph = (struct iphdr *)skb->data;
th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ csum_replace2(&iph->check, iph->tot_len, htons(length));
iph->tot_len = htons(length);
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
th->psh = push;
@@ -1613,7 +1610,7 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
}
if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
netif_receive_skb(skb);
@@ -1692,6 +1689,29 @@ skip:
return count;
}
+static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget)
+{
+ int tx_complete;
+ int work_done;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_adapter *adapter;
+ struct qlcnic_host_tx_ring *tx_ring;
+
+ sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+ adapter = sds_ring->adapter;
+ /* tx ring count = 1 */
+ tx_ring = adapter->tx_ring;
+
+ tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
+ work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
+ if ((work_done < budget) && tx_complete) {
+ napi_complete(&sds_ring->napi);
+ qlcnic_83xx_enable_intr(adapter, sds_ring);
+ }
+
+ return work_done;
+}
+
static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
{
int tx_complete;
@@ -1769,7 +1789,8 @@ void qlcnic_83xx_napi_enable(struct qlcnic_adapter *adapter)
qlcnic_83xx_enable_intr(adapter, sds_ring);
}
- if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
napi_enable(&tx_ring->napi);
@@ -1796,7 +1817,8 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
napi_disable(&sds_ring->napi);
}
- if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
qlcnic_83xx_disable_tx_intr(adapter, tx_ring);
@@ -1809,7 +1831,7 @@ void qlcnic_83xx_napi_disable(struct qlcnic_adapter *adapter)
int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
struct net_device *netdev)
{
- int ring, max_sds_rings;
+ int ring, max_sds_rings, temp;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_host_tx_ring *tx_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
@@ -1820,14 +1842,23 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
max_sds_rings = adapter->max_sds_rings;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- if (adapter->flags & QLCNIC_MSIX_ENABLED)
- netif_napi_add(netdev, &sds_ring->napi,
- qlcnic_83xx_rx_poll,
- QLCNIC_NETDEV_WEIGHT * 2);
- else
+ if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if (!(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_83xx_rx_poll,
+ QLCNIC_NETDEV_WEIGHT * 2);
+ } else {
+ temp = QLCNIC_NETDEV_WEIGHT / max_sds_rings;
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_83xx_msix_sriov_vf_poll,
+ temp);
+ }
+
+ } else {
netif_napi_add(netdev, &sds_ring->napi,
qlcnic_83xx_poll,
QLCNIC_NETDEV_WEIGHT / max_sds_rings);
+ }
}
if (qlcnic_alloc_tx_rings(adapter, netdev)) {
@@ -1835,7 +1866,8 @@ int qlcnic_83xx_napi_add(struct qlcnic_adapter *adapter,
return -ENOMEM;
}
- if (adapter->flags & QLCNIC_MSIX_ENABLED) {
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
netif_napi_add(netdev, &tx_ring->napi,
@@ -1861,7 +1893,8 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *adapter)
qlcnic_free_sds_rings(adapter->recv_ctx);
- if ((adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ if ((adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
for (ring = 0; ring < adapter->max_drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
netif_napi_del(&tx_ring->napi);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 28a6d4838364..264d5a4f8153 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include "qlcnic.h"
+#include "qlcnic_sriov.h"
#include "qlcnic_hw.h"
#include <linux/swab.h>
@@ -85,8 +86,8 @@ static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
-static int qlcnic_vlan_rx_add(struct net_device *, u16);
-static int qlcnic_vlan_rx_del(struct net_device *, u16);
+static int qlcnic_vlan_rx_add(struct net_device *, __be16, u16);
+static int qlcnic_vlan_rx_del(struct net_device *, __be16, u16);
#define QLCNIC_IS_TSO_CAPABLE(adapter) \
((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
@@ -109,6 +110,7 @@ static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
+ ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X),
{0,}
};
@@ -154,25 +156,112 @@ static const u32 qlcnic_reg_tbl[] = {
};
static const struct qlcnic_board_info qlcnic_boards[] = {
- {0x1077, 0x8020, 0x1077, 0x203,
- "8200 Series Single Port 10GbE Converged Network Adapter"
- "(TCP/IP Networking)"},
- {0x1077, 0x8020, 0x1077, 0x207,
- "8200 Series Dual Port 10GbE Converged Network Adapter"
- "(TCP/IP Networking)"},
- {0x1077, 0x8020, 0x1077, 0x20b,
- "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter"},
- {0x1077, 0x8020, 0x1077, 0x20c,
- "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter"},
- {0x1077, 0x8020, 0x1077, 0x20f,
- "3200 Series Single Port 10Gb Intelligent Ethernet Adapter"},
- {0x1077, 0x8020, 0x103c, 0x3733,
- "NC523SFP 10Gb 2-port Server Adapter"},
- {0x1077, 0x8020, 0x103c, 0x3346,
- "CN1000Q Dual Port Converged Network Adapter"},
- {0x1077, 0x8020, 0x1077, 0x210,
- "QME8242-k 10GbE Dual Port Mezzanine Card"},
- {0x1077, 0x8020, 0x0, 0x0, "cLOM8214 1/10GbE Controller"},
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x24e,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x243,
+ "8300 Series Single Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x24a,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x246,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x252,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x26e,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x260,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x266,
+ "8300 Series Single Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x269,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x271,
+ "8300 Series Dual Port 10GbE Converged Network Adapter "
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE834X,
+ 0x0, 0x0, "8300 Series 1/10GbE Controller" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x203,
+ "8200 Series Single Port 10GbE Converged Network Adapter"
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x207,
+ "8200 Series Dual Port 10GbE Converged Network Adapter"
+ "(TCP/IP Networking)" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x20b,
+ "3200 Series Dual Port 10Gb Intelligent Ethernet Adapter" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x20c,
+ "3200 Series Quad Port 1Gb Intelligent Ethernet Adapter" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x20f,
+ "3200 Series Single Port 10Gb Intelligent Ethernet Adapter" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ 0x103c, 0x3733,
+ "NC523SFP 10Gb 2-port Server Adapter" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ 0x103c, 0x3346,
+ "CN1000Q Dual Port Converged Network Adapter" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ PCI_VENDOR_ID_QLOGIC,
+ 0x210,
+ "QME8242-k 10GbE Dual Port Mezzanine Card" },
+ { PCI_VENDOR_ID_QLOGIC,
+ PCI_DEVICE_ID_QLOGIC_QLE824X,
+ 0x0, 0x0, "cLOM8214 1/10GbE Controller" },
};
#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(qlcnic_boards)
@@ -198,8 +287,7 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
recv_ctx->sds_rings = NULL;
}
-static int
-qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
+int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
{
u8 mac_addr[ETH_ALEN];
struct net_device *netdev = adapter->netdev;
@@ -225,6 +313,9 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
+ if (qlcnic_sriov_vf_check(adapter))
+ return -EINVAL;
+
if ((adapter->flags & QLCNIC_MAC_OVERRIDE_DISABLED))
return -EOPNOTSUPP;
@@ -253,11 +344,8 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int err = -EOPNOTSUPP;
- if (!adapter->fdb_mac_learn) {
- pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
- __func__);
- return err;
- }
+ if (!adapter->fdb_mac_learn)
+ return ndo_dflt_fdb_del(ndm, tb, netdev, addr);
if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
if (is_unicast_ether_addr(addr))
@@ -277,11 +365,8 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct qlcnic_adapter *adapter = netdev_priv(netdev);
int err = 0;
- if (!adapter->fdb_mac_learn) {
- pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
- __func__);
- return -EOPNOTSUPP;
- }
+ if (!adapter->fdb_mac_learn)
+ return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
pr_info("%s: FDB e-switch is not enabled\n", __func__);
@@ -292,7 +377,7 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
return err;
if (is_unicast_ether_addr(addr))
- err = qlcnic_nic_add_mac(adapter, addr);
+ err = qlcnic_nic_add_mac(adapter, addr, 0);
else if (is_multicast_ether_addr(addr))
err = dev_mc_add_excl(netdev, addr);
else
@@ -306,11 +391,8 @@ static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb,
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- if (!adapter->fdb_mac_learn) {
- pr_info("%s: Driver mac learn is enabled, FDB operation not allowed\n",
- __func__);
- return -EOPNOTSUPP;
- }
+ if (!adapter->fdb_mac_learn)
+ return ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx);
@@ -346,6 +428,12 @@ static const struct net_device_ops qlcnic_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
+#ifdef CONFIG_QLCNIC_SRIOV
+ .ndo_set_vf_mac = qlcnic_sriov_set_vf_mac,
+ .ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate,
+ .ndo_get_vf_config = qlcnic_sriov_get_vf_config,
+ .ndo_set_vf_vlan = qlcnic_sriov_set_vf_vlan,
+#endif
};
static const struct net_device_ops qlcnic_netdev_failed_ops = {
@@ -387,6 +475,8 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.process_lb_rcv_ring_diag = qlcnic_82xx_process_rcv_ring_diag,
.create_rx_ctx = qlcnic_82xx_fw_cmd_create_rx_ctx,
.create_tx_ctx = qlcnic_82xx_fw_cmd_create_tx_ctx,
+ .del_rx_ctx = qlcnic_82xx_fw_cmd_del_rx_ctx,
+ .del_tx_ctx = qlcnic_82xx_fw_cmd_del_tx_ctx,
.setup_link_event = qlcnic_82xx_linkevent_request,
.get_nic_info = qlcnic_82xx_get_nic_info,
.get_pci_info = qlcnic_82xx_get_pci_info,
@@ -402,13 +492,22 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
.config_promisc_mode = qlcnic_82xx_nic_set_promisc,
.change_l2_filter = qlcnic_82xx_change_filter,
.get_board_info = qlcnic_82xx_get_board_info,
+ .free_mac_list = qlcnic_82xx_free_mac_list,
};
int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
{
struct pci_dev *pdev = adapter->pdev;
int err = -1, i;
- int max_tx_rings;
+ int max_tx_rings, tx_vector;
+
+ if (adapter->flags & QLCNIC_TX_INTR_SHARED) {
+ max_tx_rings = 0;
+ tx_vector = 0;
+ } else {
+ max_tx_rings = adapter->max_drv_tx_rings;
+ tx_vector = 1;
+ }
if (!adapter->msix_entries) {
adapter->msix_entries = kcalloc(num_msix,
@@ -431,7 +530,6 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
if (qlcnic_83xx_check(adapter)) {
adapter->ahw->num_msix = num_msix;
/* subtract mail box and tx ring vectors */
- max_tx_rings = adapter->max_drv_tx_rings;
adapter->max_sds_rings = num_msix -
max_tx_rings - 1;
} else {
@@ -444,11 +542,11 @@ int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
"Unable to allocate %d MSI-X interrupt vectors\n",
num_msix);
if (qlcnic_83xx_check(adapter)) {
- if (err < QLC_83XX_MINIMUM_VECTOR)
+ if (err < (QLC_83XX_MINIMUM_VECTOR - tx_vector))
return err;
- err -= (adapter->max_drv_tx_rings + 1);
+ err -= (max_tx_rings + 1);
num_msix = rounddown_pow_of_two(err);
- num_msix += (adapter->max_drv_tx_rings + 1);
+ num_msix += (max_tx_rings + 1);
} else {
num_msix = rounddown_pow_of_two(err);
}
@@ -542,11 +640,10 @@ void qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
}
}
-static void
-qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
+static void qlcnic_cleanup_pci_map(struct qlcnic_hardware_context *ahw)
{
- if (adapter->ahw->pci_base0 != NULL)
- iounmap(adapter->ahw->pci_base0);
+ if (ahw->pci_base0 != NULL)
+ iounmap(ahw->pci_base0);
}
static int qlcnic_get_act_pci_func(struct qlcnic_adapter *adapter)
@@ -721,6 +818,7 @@ static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
*bar = QLCNIC_82XX_BAR0_LENGTH;
break;
case PCI_DEVICE_ID_QLOGIC_QLE834X:
+ case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
*bar = QLCNIC_83XX_BAR0_LENGTH;
break;
default:
@@ -751,7 +849,7 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
return -EIO;
}
- dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+ dev_info(&pdev->dev, "%dKB memory map\n", (int)(mem_len >> 10));
ahw->pci_base0 = mem_ptr0;
ahw->pci_len0 = pci_len0;
@@ -891,24 +989,50 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
else
adapter->flags |= QLCNIC_TAGGING_ENABLED;
- if (esw_cfg->vlan_id)
- adapter->pvid = esw_cfg->vlan_id;
- else
- adapter->pvid = 0;
+ if (esw_cfg->vlan_id) {
+ adapter->rx_pvid = esw_cfg->vlan_id;
+ adapter->tx_pvid = esw_cfg->vlan_id;
+ } else {
+ adapter->rx_pvid = 0;
+ adapter->tx_pvid = 0;
+ }
}
static int
-qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid)
+qlcnic_vlan_rx_add(struct net_device *netdev, __be16 proto, u16 vid)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ if (qlcnic_sriov_vf_check(adapter)) {
+ err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 1);
+ if (err) {
+ netdev_err(netdev,
+ "Cannot add VLAN filter for VLAN id %d, err=%d",
+ vid, err);
+ return err;
+ }
+ }
+
set_bit(vid, adapter->vlans);
return 0;
}
static int
-qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid)
+qlcnic_vlan_rx_del(struct net_device *netdev, __be16 proto, u16 vid)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ int err;
+
+ if (qlcnic_sriov_vf_check(adapter)) {
+ err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 0);
+ if (err) {
+ netdev_err(netdev,
+ "Cannot delete VLAN filter for VLAN id %d, err=%d",
+ vid, err);
+ return err;
+ }
+ }
qlcnic_restore_indev_addr(netdev, NETDEV_DOWN);
clear_bit(vid, adapter->vlans);
@@ -1250,7 +1374,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
irq_handler_t handler;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_host_tx_ring *tx_ring;
- int err, ring;
+ int err, ring, num_sds_rings;
unsigned long flags = 0;
struct net_device *netdev = adapter->netdev;
@@ -1281,10 +1405,20 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
if (qlcnic_82xx_check(adapter) ||
(qlcnic_83xx_check(adapter) &&
(adapter->flags & QLCNIC_MSIX_ENABLED))) {
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ num_sds_rings = adapter->max_sds_rings;
+ for (ring = 0; ring < num_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- snprintf(sds_ring->name, sizeof(int) + IFNAMSIZ,
- "%s[%d]", netdev->name, ring);
+ if (qlcnic_82xx_check(adapter) &&
+ (ring == (num_sds_rings - 1)))
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "qlcnic-%s[Tx0+Rx%d]",
+ netdev->name, ring);
+ else
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "qlcnic-%s[Rx%d]",
+ netdev->name, ring);
err = request_irq(sds_ring->irq, handler, flags,
sds_ring->name, sds_ring);
if (err)
@@ -1292,14 +1426,14 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
}
}
if (qlcnic_83xx_check(adapter) &&
- (adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ (adapter->flags & QLCNIC_MSIX_ENABLED) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
handler = qlcnic_msix_tx_intr;
for (ring = 0; ring < adapter->max_drv_tx_rings;
ring++) {
tx_ring = &adapter->tx_ring[ring];
- snprintf(tx_ring->name, sizeof(int) + IFNAMSIZ,
- "%s[%d]", netdev->name,
- adapter->max_sds_rings + ring);
+ snprintf(tx_ring->name, sizeof(tx_ring->name),
+ "qlcnic-%s[Tx%d]", netdev->name, ring);
err = request_irq(tx_ring->irq, handler, flags,
tx_ring->name, tx_ring);
if (err)
@@ -1328,7 +1462,8 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
free_irq(sds_ring->irq, sds_ring);
}
}
- if (qlcnic_83xx_check(adapter)) {
+ if (qlcnic_83xx_check(adapter) &&
+ !(adapter->flags & QLCNIC_TX_INTR_SHARED)) {
for (ring = 0; ring < adapter->max_drv_tx_rings;
ring++) {
tx_ring = &adapter->tx_ring[ring];
@@ -1418,9 +1553,12 @@ void __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
if (!test_and_clear_bit(__QLCNIC_DEV_UP, &adapter->state))
return;
+ if (qlcnic_sriov_vf_check(adapter))
+ qlcnic_sriov_cleanup_async_list(&adapter->ahw->sriov->bc);
smp_mb();
spin_lock(&adapter->tx_clean_lock);
netif_carrier_off(netdev);
+ adapter->ahw->linkup = 0;
netif_tx_disable(netdev);
qlcnic_free_mac_list(adapter);
@@ -1545,7 +1683,9 @@ out:
static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
int err = 0;
+
adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
GFP_KERNEL);
if (!adapter->recv_ctx) {
@@ -1553,9 +1693,14 @@ static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
goto err_out;
}
/* Initialize interrupt coalesce parameters */
- adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
- adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
- adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ ahw->coal.flag = QLCNIC_INTR_DEFAULT;
+ ahw->coal.type = QLCNIC_INTR_COAL_TYPE_RX;
+ ahw->coal.rx_time_us = QLCNIC_DEF_INTR_COALESCE_RX_TIME_US;
+ ahw->coal.rx_packets = QLCNIC_DEF_INTR_COALESCE_RX_PACKETS;
+ if (qlcnic_83xx_check(adapter)) {
+ ahw->coal.tx_time_us = QLCNIC_DEF_INTR_COALESCE_TX_TIME_US;
+ ahw->coal.tx_packets = QLCNIC_DEF_INTR_COALESCE_TX_PACKETS;
+ }
/* clear stats */
memset(&adapter->stats, 0, sizeof(adapter->stats));
err_out:
@@ -1685,7 +1830,7 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
return err;
}
-static int
+int
qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
int pci_using_dac)
{
@@ -1701,11 +1846,14 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
qlcnic_change_mtu(netdev, netdev->mtu);
- SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
+ if (qlcnic_sriov_vf_check(adapter))
+ SET_ETHTOOL_OPS(netdev, &qlcnic_sriov_vf_ethtool_ops);
+ else
+ SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_IPV6_CSUM | NETIF_F_GRO |
- NETIF_F_HW_VLAN_RX);
+ NETIF_F_HW_VLAN_CTAG_RX);
netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM);
@@ -1720,7 +1868,10 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
}
if (qlcnic_vlan_tx_check(adapter))
- netdev->features |= (NETIF_F_HW_VLAN_TX);
+ netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX);
+
+ if (qlcnic_sriov_vf_check(adapter))
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
netdev->features |= NETIF_F_LRO;
@@ -1820,6 +1971,9 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 capab2;
char board_name[QLCNIC_MAX_BOARD_NAME_LEN + 19]; /* MAC + ": " + name */
+ if (pdev->is_virtfn)
+ return -ENODEV;
+
err = pci_enable_device(pdev);
if (err)
return err;
@@ -1844,12 +1998,18 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!ahw)
goto err_out_free_res;
- if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE824X) {
+ switch (ent->device) {
+ case PCI_DEVICE_ID_QLOGIC_QLE824X:
ahw->hw_ops = &qlcnic_hw_ops;
- ahw->reg_tbl = (u32 *)qlcnic_reg_tbl;
- } else if (ent->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+ ahw->reg_tbl = (u32 *) qlcnic_reg_tbl;
+ break;
+ case PCI_DEVICE_ID_QLOGIC_QLE834X:
qlcnic_83xx_register_map(ahw);
- } else {
+ break;
+ case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
+ qlcnic_sriov_vf_register_map(ahw);
+ break;
+ default:
goto err_out_free_hw_res;
}
@@ -1911,11 +2071,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
} else if (qlcnic_83xx_check(adapter)) {
qlcnic_83xx_check_vf(adapter, ent);
adapter->portnum = adapter->ahw->pci_func;
- err = qlcnic_83xx_init(adapter);
+ err = qlcnic_83xx_init(adapter, pci_using_dac);
if (err) {
dev_err(&pdev->dev, "%s: failed\n", __func__);
goto err_out_free_hw;
}
+ if (qlcnic_sriov_vf_check(adapter))
+ return 0;
} else {
dev_err(&pdev->dev,
"%s: failed. Please Reboot\n", __func__);
@@ -1932,6 +2094,12 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
module_name(THIS_MODULE),
board_name, adapter->ahw->revision_id);
}
+
+ if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x &&
+ !!qlcnic_use_msi)
+ dev_warn(&pdev->dev,
+ "83xx adapter do not support MSI interrupts\n");
+
err = qlcnic_setup_intr(adapter, 0);
if (err) {
dev_err(&pdev->dev, "Failed to setup interrupt\n");
@@ -1999,7 +2167,7 @@ err_out_free_netdev:
free_netdev(netdev);
err_out_iounmap:
- qlcnic_cleanup_pci_map(adapter);
+ qlcnic_cleanup_pci_map(ahw);
err_out_free_hw_res:
kfree(ahw);
@@ -2024,11 +2192,13 @@ static void qlcnic_remove(struct pci_dev *pdev)
return;
netdev = adapter->netdev;
+ qlcnic_sriov_pf_disable(adapter);
qlcnic_cancel_idc_work(adapter);
ahw = adapter->ahw;
unregister_netdev(netdev);
+ qlcnic_sriov_cleanup(adapter);
if (qlcnic_83xx_check(adapter)) {
qlcnic_83xx_free_mbx_intr(adapter);
@@ -2054,7 +2224,7 @@ static void qlcnic_remove(struct pci_dev *pdev)
qlcnic_remove_sysfs(adapter);
- qlcnic_cleanup_pci_map(adapter);
+ qlcnic_cleanup_pci_map(adapter->ahw);
qlcnic_release_firmware(adapter);
@@ -2084,6 +2254,7 @@ static int __qlcnic_shutdown(struct pci_dev *pdev)
if (netif_running(netdev))
qlcnic_down(adapter, netdev);
+ qlcnic_sriov_cleanup(adapter);
if (qlcnic_82xx_check(adapter))
qlcnic_clr_all_drv_state(adapter, 0);
@@ -3205,20 +3376,40 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
return err;
}
-int qlcnic_validate_max_rss(u8 max_hw, u8 val)
+int qlcnic_validate_max_rss(struct qlcnic_adapter *adapter,
+ __u32 val)
{
+ struct net_device *netdev = adapter->netdev;
+ u8 max_hw = adapter->ahw->max_rx_ques;
u32 max_allowed;
- if (max_hw > QLC_MAX_SDS_RINGS) {
- max_hw = QLC_MAX_SDS_RINGS;
- pr_info("max rss reset to %d\n", QLC_MAX_SDS_RINGS);
+ if (val > QLC_MAX_SDS_RINGS) {
+ netdev_err(netdev, "RSS value should not be higher than %u\n",
+ QLC_MAX_SDS_RINGS);
+ return -EINVAL;
}
max_allowed = rounddown_pow_of_two(min_t(int, max_hw,
num_online_cpus()));
if ((val > max_allowed) || (val < 2) || !is_power_of_2(val)) {
- pr_info("rss_ring valid range [2 - %x] in powers of 2\n",
- max_allowed);
+ if (!is_power_of_2(val))
+ netdev_err(netdev, "RSS value should be a power of 2\n");
+
+ if (val < 2)
+ netdev_err(netdev, "RSS value should not be lower than 2\n");
+
+ if (val > max_hw)
+ netdev_err(netdev,
+ "RSS value should not be higher than[%u], the max RSS rings supported by the adapter\n",
+ max_hw);
+
+ if (val > num_online_cpus())
+ netdev_err(netdev,
+ "RSS value should not be higher than[%u], number of online CPUs in the system\n",
+ num_online_cpus());
+
+ netdev_err(netdev, "Unable to configure %u RSS rings\n", val);
+
return -EINVAL;
}
return 0;
@@ -3238,8 +3429,10 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
qlcnic_detach(adapter);
- if (qlcnic_83xx_check(adapter))
+ if (qlcnic_83xx_check(adapter)) {
qlcnic_83xx_free_mbx_intr(adapter);
+ qlcnic_83xx_enable_mbx_poll(adapter);
+ }
qlcnic_teardown_intr(adapter);
err = qlcnic_setup_intr(adapter, data);
@@ -3253,6 +3446,7 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data, size_t len)
/* register for NIC IDC AEN Events */
qlcnic_83xx_register_nic_idc_func(adapter, 1);
err = qlcnic_83xx_setup_mbx_intr(adapter);
+ qlcnic_83xx_disable_mbx_poll(adapter);
if (err) {
dev_err(&adapter->pdev->dev,
"failed to setup mbx interrupt\n");
@@ -3318,7 +3512,7 @@ void qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
rcu_read_lock();
for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
- dev = __vlan_find_dev_deep(netdev, vid);
+ dev = __vlan_find_dev_deep(netdev, htons(ETH_P_8021Q), vid);
if (!dev)
continue;
qlcnic_config_indev_addr(adapter, dev, event);
@@ -3432,7 +3626,10 @@ static struct pci_driver qlcnic_driver = {
.resume = qlcnic_resume,
#endif
.shutdown = qlcnic_shutdown,
- .err_handler = &qlcnic_err_handler
+ .err_handler = &qlcnic_err_handler,
+#ifdef CONFIG_QLCNIC_SRIOV
+ .sriov_configure = qlcnic_pci_sriov_configure,
+#endif
};
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index abbd22c814a6..4b9bab18ebd9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -810,11 +810,8 @@ static int __qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter,
tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
&tmp_addr_t, GFP_KERNEL);
- if (!tmp_addr) {
- dev_err(&adapter->pdev->dev,
- "Can't get memory for FW dump template\n");
+ if (!tmp_addr)
return -ENOMEM;
- }
if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_TEMP_HDR)) {
err = -ENOMEM;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
new file mode 100644
index 000000000000..d85fbb57c25b
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -0,0 +1,263 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#ifndef _QLCNIC_83XX_SRIOV_H_
+#define _QLCNIC_83XX_SRIOV_H_
+
+#include "qlcnic.h"
+#include <linux/types.h>
+#include <linux/pci.h>
+
+extern const u32 qlcnic_83xx_reg_tbl[];
+extern const u32 qlcnic_83xx_ext_reg_tbl[];
+
+struct qlcnic_bc_payload {
+ u64 payload[126];
+};
+
+struct qlcnic_bc_hdr {
+#if defined(__LITTLE_ENDIAN)
+ u8 version;
+ u8 msg_type:4;
+ u8 rsvd1:3;
+ u8 op_type:1;
+ u8 num_cmds;
+ u8 num_frags;
+ u8 frag_num;
+ u8 cmd_op;
+ u16 seq_id;
+ u64 rsvd3;
+#elif defined(__BIG_ENDIAN)
+ u8 num_frags;
+ u8 num_cmds;
+ u8 op_type:1;
+ u8 rsvd1:3;
+ u8 msg_type:4;
+ u8 version;
+ u16 seq_id;
+ u8 cmd_op;
+ u8 frag_num;
+ u64 rsvd3;
+#endif
+};
+
+enum qlcnic_bc_commands {
+ QLCNIC_BC_CMD_CHANNEL_INIT = 0x0,
+ QLCNIC_BC_CMD_CHANNEL_TERM = 0x1,
+ QLCNIC_BC_CMD_GET_ACL = 0x2,
+ QLCNIC_BC_CMD_CFG_GUEST_VLAN = 0x3,
+};
+
+#define QLC_BC_CMD 1
+
+struct qlcnic_trans_list {
+ /* Lock for manipulating list */
+ spinlock_t lock;
+ struct list_head wait_list;
+ int count;
+};
+
+enum qlcnic_trans_state {
+ QLC_INIT = 0,
+ QLC_WAIT_FOR_CHANNEL_FREE,
+ QLC_WAIT_FOR_RESP,
+ QLC_ABORT,
+ QLC_END,
+};
+
+struct qlcnic_bc_trans {
+ u8 func_id;
+ u8 active;
+ u8 curr_rsp_frag;
+ u8 curr_req_frag;
+ u16 cmd_id;
+ u16 req_pay_size;
+ u16 rsp_pay_size;
+ u32 trans_id;
+ enum qlcnic_trans_state trans_state;
+ struct list_head list;
+ struct qlcnic_bc_hdr *req_hdr;
+ struct qlcnic_bc_hdr *rsp_hdr;
+ struct qlcnic_bc_payload *req_pay;
+ struct qlcnic_bc_payload *rsp_pay;
+ struct completion resp_cmpl;
+ struct qlcnic_vf_info *vf;
+};
+
+enum qlcnic_vf_state {
+ QLC_BC_VF_SEND = 0,
+ QLC_BC_VF_RECV,
+ QLC_BC_VF_CHANNEL,
+ QLC_BC_VF_STATE,
+ QLC_BC_VF_FLR,
+ QLC_BC_VF_SOFT_FLR,
+};
+
+enum qlcnic_vlan_mode {
+ QLC_NO_VLAN_MODE = 0,
+ QLC_PVID_MODE,
+ QLC_GUEST_VLAN_MODE,
+};
+
+struct qlcnic_resources {
+ u16 num_tx_mac_filters;
+ u16 num_rx_ucast_mac_filters;
+ u16 num_rx_mcast_mac_filters;
+
+ u16 num_txvlan_keys;
+
+ u16 num_rx_queues;
+ u16 num_tx_queues;
+
+ u16 num_rx_buf_rings;
+ u16 num_rx_status_rings;
+
+ u16 num_destip;
+ u32 num_lro_flows_supported;
+ u16 max_local_ipv6_addrs;
+ u16 max_remote_ipv6_addrs;
+};
+
+struct qlcnic_vport {
+ u16 handle;
+ u16 max_tx_bw;
+ u16 min_tx_bw;
+ u8 vlan_mode;
+ u16 vlan;
+ u8 qos;
+ u8 mac[6];
+};
+
+struct qlcnic_vf_info {
+ u8 pci_func;
+ u16 rx_ctx_id;
+ u16 tx_ctx_id;
+ unsigned long state;
+ struct completion ch_free_cmpl;
+ struct work_struct trans_work;
+ struct work_struct flr_work;
+ /* It synchronizes commands sent from VF */
+ struct mutex send_cmd_lock;
+ struct qlcnic_bc_trans *send_cmd;
+ struct qlcnic_bc_trans *flr_trans;
+ struct qlcnic_trans_list rcv_act;
+ struct qlcnic_trans_list rcv_pend;
+ struct qlcnic_adapter *adapter;
+ struct qlcnic_vport *vp;
+};
+
+struct qlcnic_async_work_list {
+ struct list_head list;
+ struct work_struct work;
+ void *ptr;
+};
+
+struct qlcnic_back_channel {
+ u16 trans_counter;
+ struct workqueue_struct *bc_trans_wq;
+ struct workqueue_struct *bc_async_wq;
+ struct workqueue_struct *bc_flr_wq;
+ struct list_head async_list;
+};
+
+struct qlcnic_sriov {
+ u16 vp_handle;
+ u8 num_vfs;
+ u8 any_vlan;
+ u8 vlan_mode;
+ u16 num_allowed_vlans;
+ u16 *allowed_vlans;
+ u16 vlan;
+ struct qlcnic_resources ff_max;
+ struct qlcnic_back_channel bc;
+ struct qlcnic_vf_info *vf_info;
+};
+
+int qlcnic_sriov_init(struct qlcnic_adapter *, int);
+void qlcnic_sriov_cleanup(struct qlcnic_adapter *);
+void __qlcnic_sriov_cleanup(struct qlcnic_adapter *);
+void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *);
+int qlcnic_sriov_vf_init(struct qlcnic_adapter *, int);
+void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *);
+int qlcnic_sriov_func_to_index(struct qlcnic_adapter *, u8);
+int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *, u8);
+void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *, u32);
+int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *, u8);
+void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *);
+void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *);
+int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *,
+ struct qlcnic_bc_trans *);
+int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *,
+ struct qlcnic_info *, u16);
+int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8);
+
+static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter)
+{
+ return test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state) ? true : false;
+}
+
+#ifdef CONFIG_QLCNIC_SRIOV
+void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *,
+ struct qlcnic_bc_trans *,
+ struct qlcnic_cmd_args *);
+void qlcnic_sriov_pf_disable(struct qlcnic_adapter *);
+void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *);
+int qlcnic_pci_sriov_configure(struct pci_dev *, int);
+void qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *, u32 *);
+void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *, u32 *);
+void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *, struct qlcnic_vf_info *);
+bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *,
+ struct qlcnic_bc_trans *,
+ struct qlcnic_vf_info *);
+void qlcnic_sriov_pf_reset(struct qlcnic_adapter *);
+int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *);
+int qlcnic_sriov_set_vf_mac(struct net_device *, int, u8 *);
+int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int);
+int qlcnic_sriov_get_vf_config(struct net_device *, int ,
+ struct ifla_vf_info *);
+int qlcnic_sriov_set_vf_vlan(struct net_device *, int, u16, u8);
+#else
+static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
+static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {}
+static inline void
+qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id) {}
+static inline void
+qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id) {}
+static inline void
+qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id) {}
+static inline void
+qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id) {}
+static inline void
+qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *adapter, u32 *int_id)
+{}
+static inline void
+qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter, u32 *int_id)
+{}
+static inline void
+qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *int_id)
+{}
+static inline void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf) {}
+static inline bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans,
+ struct qlcnic_vf_info *vf)
+{ return false; }
+static inline void qlcnic_sriov_pf_reset(struct qlcnic_adapter *adapter) {}
+static inline int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *adapter)
+{ return 0; }
+#endif
+
+#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
new file mode 100644
index 000000000000..44d547d78b84
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -0,0 +1,1954 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic_sriov.h"
+#include "qlcnic.h"
+#include "qlcnic_83xx_hw.h"
+#include <linux/types.h>
+
+#define QLC_BC_COMMAND 0
+#define QLC_BC_RESPONSE 1
+
+#define QLC_MBOX_RESP_TIMEOUT (10 * HZ)
+#define QLC_MBOX_CH_FREE_TIMEOUT (10 * HZ)
+
+#define QLC_BC_MSG 0
+#define QLC_BC_CFREE 1
+#define QLC_BC_FLR 2
+#define QLC_BC_HDR_SZ 16
+#define QLC_BC_PAYLOAD_SZ (1024 - QLC_BC_HDR_SZ)
+
+#define QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF 2048
+#define QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF 512
+
+#define QLC_83XX_VF_RESET_FAIL_THRESH 8
+#define QLC_BC_CMD_MAX_RETRY_CNT 5
+
+static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *);
+static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32);
+static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *);
+static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
+static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
+static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
+ struct qlcnic_cmd_args *);
+
+static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
+ .read_crb = qlcnic_83xx_read_crb,
+ .write_crb = qlcnic_83xx_write_crb,
+ .read_reg = qlcnic_83xx_rd_reg_indirect,
+ .write_reg = qlcnic_83xx_wrt_reg_indirect,
+ .get_mac_address = qlcnic_83xx_get_mac_address,
+ .setup_intr = qlcnic_83xx_setup_intr,
+ .alloc_mbx_args = qlcnic_83xx_alloc_mbx_args,
+ .mbx_cmd = qlcnic_sriov_vf_mbx_op,
+ .get_func_no = qlcnic_83xx_get_func_no,
+ .api_lock = qlcnic_83xx_cam_lock,
+ .api_unlock = qlcnic_83xx_cam_unlock,
+ .process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag,
+ .create_rx_ctx = qlcnic_83xx_create_rx_ctx,
+ .create_tx_ctx = qlcnic_83xx_create_tx_ctx,
+ .del_rx_ctx = qlcnic_83xx_del_rx_ctx,
+ .del_tx_ctx = qlcnic_83xx_del_tx_ctx,
+ .setup_link_event = qlcnic_83xx_setup_link_event,
+ .get_nic_info = qlcnic_83xx_get_nic_info,
+ .get_pci_info = qlcnic_83xx_get_pci_info,
+ .set_nic_info = qlcnic_83xx_set_nic_info,
+ .change_macvlan = qlcnic_83xx_sre_macaddr_change,
+ .napi_enable = qlcnic_83xx_napi_enable,
+ .napi_disable = qlcnic_83xx_napi_disable,
+ .config_intr_coal = qlcnic_83xx_config_intr_coal,
+ .config_rss = qlcnic_83xx_config_rss,
+ .config_hw_lro = qlcnic_83xx_config_hw_lro,
+ .config_promisc_mode = qlcnic_83xx_nic_set_promisc,
+ .change_l2_filter = qlcnic_83xx_change_l2_filter,
+ .get_board_info = qlcnic_83xx_get_port_info,
+ .free_mac_list = qlcnic_sriov_vf_free_mac_list,
+};
+
+static struct qlcnic_nic_template qlcnic_sriov_vf_ops = {
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_config_led,
+ .cancel_idc_work = qlcnic_sriov_vf_cancel_fw_work,
+ .napi_add = qlcnic_83xx_napi_add,
+ .napi_del = qlcnic_83xx_napi_del,
+ .config_ipaddr = qlcnic_83xx_config_ipaddr,
+ .clear_legacy_intr = qlcnic_83xx_clear_legacy_intr,
+};
+
+static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = {
+ {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2},
+ {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2},
+ {QLCNIC_BC_CMD_GET_ACL, 3, 14},
+ {QLCNIC_BC_CMD_CFG_GUEST_VLAN, 2, 2},
+};
+
+static inline bool qlcnic_sriov_bc_msg_check(u32 val)
+{
+ return (val & (1 << QLC_BC_MSG)) ? true : false;
+}
+
+static inline bool qlcnic_sriov_channel_free_check(u32 val)
+{
+ return (val & (1 << QLC_BC_CFREE)) ? true : false;
+}
+
+static inline bool qlcnic_sriov_flr_check(u32 val)
+{
+ return (val & (1 << QLC_BC_FLR)) ? true : false;
+}
+
+static inline u8 qlcnic_sriov_target_func_id(u32 val)
+{
+ return (val >> 4) & 0xff;
+}
+
+static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id)
+{
+ struct pci_dev *dev = adapter->pdev;
+ int pos;
+ u16 stride, offset;
+
+ if (qlcnic_sriov_vf_check(adapter))
+ return 0;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
+ pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
+ pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
+
+ return (dev->devfn + offset + stride * vf_id) & 0xff;
+}
+
+int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
+{
+ struct qlcnic_sriov *sriov;
+ struct qlcnic_back_channel *bc;
+ struct workqueue_struct *wq;
+ struct qlcnic_vport *vp;
+ struct qlcnic_vf_info *vf;
+ int err, i;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return -EIO;
+
+ sriov = kzalloc(sizeof(struct qlcnic_sriov), GFP_KERNEL);
+ if (!sriov)
+ return -ENOMEM;
+
+ adapter->ahw->sriov = sriov;
+ sriov->num_vfs = num_vfs;
+ bc = &sriov->bc;
+ sriov->vf_info = kzalloc(sizeof(struct qlcnic_vf_info) *
+ num_vfs, GFP_KERNEL);
+ if (!sriov->vf_info) {
+ err = -ENOMEM;
+ goto qlcnic_free_sriov;
+ }
+
+ wq = create_singlethread_workqueue("bc-trans");
+ if (wq == NULL) {
+ err = -ENOMEM;
+ dev_err(&adapter->pdev->dev,
+ "Cannot create bc-trans workqueue\n");
+ goto qlcnic_free_vf_info;
+ }
+
+ bc->bc_trans_wq = wq;
+
+ wq = create_singlethread_workqueue("async");
+ if (wq == NULL) {
+ err = -ENOMEM;
+ dev_err(&adapter->pdev->dev, "Cannot create async workqueue\n");
+ goto qlcnic_destroy_trans_wq;
+ }
+
+ bc->bc_async_wq = wq;
+ INIT_LIST_HEAD(&bc->async_list);
+
+ for (i = 0; i < num_vfs; i++) {
+ vf = &sriov->vf_info[i];
+ vf->adapter = adapter;
+ vf->pci_func = qlcnic_sriov_virtid_fn(adapter, i);
+ mutex_init(&vf->send_cmd_lock);
+ INIT_LIST_HEAD(&vf->rcv_act.wait_list);
+ INIT_LIST_HEAD(&vf->rcv_pend.wait_list);
+ spin_lock_init(&vf->rcv_act.lock);
+ spin_lock_init(&vf->rcv_pend.lock);
+ init_completion(&vf->ch_free_cmpl);
+
+ if (qlcnic_sriov_pf_check(adapter)) {
+ vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
+ if (!vp) {
+ err = -ENOMEM;
+ goto qlcnic_destroy_async_wq;
+ }
+ sriov->vf_info[i].vp = vp;
+ vp->max_tx_bw = MAX_BW;
+ random_ether_addr(vp->mac);
+ dev_info(&adapter->pdev->dev,
+ "MAC Address %pM is configured for VF %d\n",
+ vp->mac, i);
+ }
+ }
+
+ return 0;
+
+qlcnic_destroy_async_wq:
+ destroy_workqueue(bc->bc_async_wq);
+
+qlcnic_destroy_trans_wq:
+ destroy_workqueue(bc->bc_trans_wq);
+
+qlcnic_free_vf_info:
+ kfree(sriov->vf_info);
+
+qlcnic_free_sriov:
+ kfree(adapter->ahw->sriov);
+ return err;
+}
+
+void qlcnic_sriov_cleanup_list(struct qlcnic_trans_list *t_list)
+{
+ struct qlcnic_bc_trans *trans;
+ struct qlcnic_cmd_args cmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&t_list->lock, flags);
+
+ while (!list_empty(&t_list->wait_list)) {
+ trans = list_first_entry(&t_list->wait_list,
+ struct qlcnic_bc_trans, list);
+ list_del(&trans->list);
+ t_list->count--;
+ cmd.req.arg = (u32 *)trans->req_pay;
+ cmd.rsp.arg = (u32 *)trans->rsp_pay;
+ qlcnic_free_mbx_args(&cmd);
+ qlcnic_sriov_cleanup_transaction(trans);
+ }
+
+ spin_unlock_irqrestore(&t_list->lock, flags);
+}
+
+void __qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_back_channel *bc = &sriov->bc;
+ struct qlcnic_vf_info *vf;
+ int i;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return;
+
+ qlcnic_sriov_cleanup_async_list(bc);
+ destroy_workqueue(bc->bc_async_wq);
+
+ for (i = 0; i < sriov->num_vfs; i++) {
+ vf = &sriov->vf_info[i];
+ qlcnic_sriov_cleanup_list(&vf->rcv_pend);
+ cancel_work_sync(&vf->trans_work);
+ qlcnic_sriov_cleanup_list(&vf->rcv_act);
+ }
+
+ destroy_workqueue(bc->bc_trans_wq);
+
+ for (i = 0; i < sriov->num_vfs; i++)
+ kfree(sriov->vf_info[i].vp);
+
+ kfree(sriov->vf_info);
+ kfree(adapter->ahw->sriov);
+}
+
+static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
+{
+ qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
+ qlcnic_sriov_cfg_bc_intr(adapter, 0);
+ __qlcnic_sriov_cleanup(adapter);
+}
+
+void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
+{
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_sriov_pf_cleanup(adapter);
+
+ if (qlcnic_sriov_vf_check(adapter))
+ qlcnic_sriov_vf_cleanup(adapter);
+}
+
+static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
+ u32 *pay, u8 pci_func, u8 size)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ unsigned long flags;
+ u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val;
+ u16 opcode;
+ u8 mbx_err_code;
+ int i, j;
+
+ opcode = ((struct qlcnic_bc_hdr *)hdr)->cmd_op;
+
+ if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+ dev_info(&adapter->pdev->dev,
+ "Mailbox cmd attempted, 0x%x\n", opcode);
+ dev_info(&adapter->pdev->dev, "Mailbox detached\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&ahw->mbx_lock, flags);
+
+ mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+ if (mbx_val) {
+ QLCDB(adapter, DRV, "Mailbox cmd attempted, 0x%x\n", opcode);
+ spin_unlock_irqrestore(&ahw->mbx_lock, flags);
+ return QLCNIC_RCODE_TIMEOUT;
+ }
+ /* Fill in mailbox registers */
+ val = size + (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
+ mbx_cmd = 0x31 | (val << 16) | (adapter->ahw->fw_hal_version << 29);
+
+ writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 0));
+ mbx_cmd = 0x1 | (1 << 4);
+
+ if (qlcnic_sriov_pf_check(adapter))
+ mbx_cmd |= (pci_func << 5);
+
+ writel(mbx_cmd, QLCNIC_MBX_HOST(ahw, 1));
+ for (i = 2, j = 0; j < (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
+ i++, j++) {
+ writel(*(hdr++), QLCNIC_MBX_HOST(ahw, i));
+ }
+ for (j = 0; j < size; j++, i++)
+ writel(*(pay++), QLCNIC_MBX_HOST(ahw, i));
+
+ /* Signal FW about the impending command */
+ QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
+
+ /* Waiting for the mailbox cmd to complete and while waiting here
+ * some AEN might arrive. If more than 5 seconds expire we can
+ * assume something is wrong.
+ */
+poll:
+ rsp = qlcnic_83xx_mbx_poll(adapter);
+ if (rsp != QLCNIC_RCODE_TIMEOUT) {
+ /* Get the FW response data */
+ fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
+ if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
+ __qlcnic_83xx_process_aen(adapter);
+ mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
+ if (mbx_val)
+ goto poll;
+ }
+ mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
+ rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
+ opcode = QLCNIC_MBX_RSP(fw_data);
+
+ switch (mbx_err_code) {
+ case QLCNIC_MBX_RSP_OK:
+ case QLCNIC_MBX_PORT_RSP_OK:
+ rsp = QLCNIC_RCODE_SUCCESS;
+ break;
+ default:
+ if (opcode == QLCNIC_CMD_CONFIG_MAC_VLAN) {
+ rsp = qlcnic_83xx_mac_rcode(adapter);
+ if (!rsp)
+ goto out;
+ }
+ dev_err(&adapter->pdev->dev,
+ "MBX command 0x%x failed with err:0x%x\n",
+ opcode, mbx_err_code);
+ rsp = mbx_err_code;
+ break;
+ }
+ goto out;
+ }
+
+ dev_err(&adapter->pdev->dev, "MBX command 0x%x timed out\n",
+ QLCNIC_MBX_RSP(mbx_cmd));
+ rsp = QLCNIC_RCODE_TIMEOUT;
+out:
+ /* clear fw mbx control register */
+ QLCWRX(ahw, QLCNIC_FW_MBX_CTRL, QLCNIC_CLR_OWNER);
+ spin_unlock_irqrestore(&adapter->ahw->mbx_lock, flags);
+ return rsp;
+}
+
+static void qlcnic_sriov_vf_cfg_buff_desc(struct qlcnic_adapter *adapter)
+{
+ adapter->num_rxd = QLC_DEFAULT_RCV_DESCRIPTORS_SRIOV_VF;
+ adapter->max_rxd = MAX_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = QLC_DEFAULT_JUMBO_RCV_DESCRIPTORS_SRIOV_VF;
+ adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
+ adapter->max_rds_rings = MAX_RDS_RINGS;
+}
+
+int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info, u16 vport_id)
+{
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
+ int err;
+ u32 status;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO);
+ if (err)
+ return err;
+
+ cmd.req.arg[1] = vport_id << 16 | 0x1;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get vport info, err=%d\n", err);
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+ }
+
+ status = cmd.rsp.arg[2] & 0xffff;
+ if (status & BIT_0)
+ npar_info->min_tx_bw = MSW(cmd.rsp.arg[2]);
+ if (status & BIT_1)
+ npar_info->max_tx_bw = LSW(cmd.rsp.arg[3]);
+ if (status & BIT_2)
+ npar_info->max_tx_ques = MSW(cmd.rsp.arg[3]);
+ if (status & BIT_3)
+ npar_info->max_tx_mac_filters = LSW(cmd.rsp.arg[4]);
+ if (status & BIT_4)
+ npar_info->max_rx_mcast_mac_filters = MSW(cmd.rsp.arg[4]);
+ if (status & BIT_5)
+ npar_info->max_rx_ucast_mac_filters = LSW(cmd.rsp.arg[5]);
+ if (status & BIT_6)
+ npar_info->max_rx_ip_addr = MSW(cmd.rsp.arg[5]);
+ if (status & BIT_7)
+ npar_info->max_rx_lro_flow = LSW(cmd.rsp.arg[6]);
+ if (status & BIT_8)
+ npar_info->max_rx_status_rings = MSW(cmd.rsp.arg[6]);
+ if (status & BIT_9)
+ npar_info->max_rx_buf_rings = LSW(cmd.rsp.arg[7]);
+
+ npar_info->max_rx_ques = MSW(cmd.rsp.arg[7]);
+ npar_info->max_tx_vlan_keys = LSW(cmd.rsp.arg[8]);
+ npar_info->max_local_ipv6_addrs = MSW(cmd.rsp.arg[8]);
+ npar_info->max_remote_ipv6_addrs = LSW(cmd.rsp.arg[9]);
+
+ dev_info(dev, "\n\tmin_tx_bw: %d, max_tx_bw: %d max_tx_ques: %d,\n"
+ "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
+ "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
+ "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
+ "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n"
+ "\tlocal_ipv6_addr: %d, remote_ipv6_addr: %d\n",
+ npar_info->min_tx_bw, npar_info->max_tx_bw,
+ npar_info->max_tx_ques, npar_info->max_tx_mac_filters,
+ npar_info->max_rx_mcast_mac_filters,
+ npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
+ npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
+ npar_info->max_rx_buf_rings, npar_info->max_rx_ques,
+ npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs,
+ npar_info->max_remote_ipv6_addrs);
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_set_pvid_mode(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ adapter->rx_pvid = (cmd->rsp.arg[1] >> 16) & 0xffff;
+ adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
+ return 0;
+}
+
+static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ int i, num_vlans;
+ u16 *vlans;
+
+ if (sriov->allowed_vlans)
+ return 0;
+
+ sriov->any_vlan = cmd->rsp.arg[2] & 0xf;
+ if (!sriov->any_vlan)
+ return 0;
+
+ sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16;
+ num_vlans = sriov->num_allowed_vlans;
+ sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL);
+ if (!sriov->allowed_vlans)
+ return -ENOMEM;
+
+ vlans = (u16 *)&cmd->rsp.arg[3];
+ for (i = 0; i < num_vlans; i++)
+ sriov->allowed_vlans[i] = vlans[i];
+
+ return 0;
+}
+
+static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_cmd_args cmd;
+ int ret;
+
+ ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, QLCNIC_BC_CMD_GET_ACL);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret) {
+ dev_err(&adapter->pdev->dev, "Failed to get ACL, err=%d\n",
+ ret);
+ } else {
+ sriov->vlan_mode = cmd.rsp.arg[1] & 0x3;
+ switch (sriov->vlan_mode) {
+ case QLC_GUEST_VLAN_MODE:
+ ret = qlcnic_sriov_set_guest_vlan_mode(adapter, &cmd);
+ break;
+ case QLC_PVID_MODE:
+ ret = qlcnic_sriov_set_pvid_mode(adapter, &cmd);
+ break;
+ }
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+ return ret;
+}
+
+static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_info nic_info;
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err;
+
+ err = qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, 0);
+ if (err)
+ return err;
+
+ err = qlcnic_get_nic_info(adapter, &nic_info, ahw->pci_func);
+ if (err)
+ return -EIO;
+
+ err = qlcnic_sriov_get_vf_acl(adapter);
+ if (err)
+ return err;
+
+ if (qlcnic_83xx_get_port_info(adapter))
+ return -EIO;
+
+ qlcnic_sriov_vf_cfg_buff_desc(adapter);
+ adapter->flags |= QLCNIC_ADAPTER_INITIALIZED;
+ dev_info(&adapter->pdev->dev, "HAL Version: %d\n",
+ adapter->ahw->fw_hal_version);
+
+ ahw->physical_port = (u8) nic_info.phys_port;
+ ahw->switch_mode = nic_info.switch_mode;
+ ahw->max_mtu = nic_info.max_mtu;
+ ahw->op_mode = nic_info.op_mode;
+ ahw->capabilities = nic_info.capabilities;
+ return 0;
+}
+
+static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
+ int pci_using_dac)
+{
+ int err;
+
+ INIT_LIST_HEAD(&adapter->vf_mc_list);
+ if (!qlcnic_use_msi_x && !!qlcnic_use_msi)
+ dev_warn(&adapter->pdev->dev,
+ "83xx adapter do not support MSI interrupts\n");
+
+ err = qlcnic_setup_intr(adapter, 1);
+ if (err) {
+ dev_err(&adapter->pdev->dev, "Failed to setup interrupt\n");
+ goto err_out_disable_msi;
+ }
+
+ err = qlcnic_83xx_setup_mbx_intr(adapter);
+ if (err)
+ goto err_out_disable_msi;
+
+ err = qlcnic_sriov_init(adapter, 1);
+ if (err)
+ goto err_out_disable_mbx_intr;
+
+ err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
+ if (err)
+ goto err_out_cleanup_sriov;
+
+ err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
+ if (err)
+ goto err_out_disable_bc_intr;
+
+ err = qlcnic_sriov_vf_init_driver(adapter);
+ if (err)
+ goto err_out_send_channel_term;
+
+ err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);
+ if (err)
+ goto err_out_send_channel_term;
+
+ pci_set_drvdata(adapter->pdev, adapter);
+ dev_info(&adapter->pdev->dev, "%s: XGbE port initialized\n",
+ adapter->netdev->name);
+ qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
+ adapter->ahw->idc.delay);
+ return 0;
+
+err_out_send_channel_term:
+ qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
+
+err_out_disable_bc_intr:
+ qlcnic_sriov_cfg_bc_intr(adapter, 0);
+
+err_out_cleanup_sriov:
+ __qlcnic_sriov_cleanup(adapter);
+
+err_out_disable_mbx_intr:
+ qlcnic_83xx_free_mbx_intr(adapter);
+
+err_out_disable_msi:
+ qlcnic_teardown_intr(adapter);
+ return err;
+}
+
+static int qlcnic_sriov_check_dev_ready(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+
+ do {
+ msleep(20);
+ if (++adapter->fw_fail_cnt > QLC_BC_CMD_MAX_RETRY_CNT)
+ return -EIO;
+ state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+ } while (state != QLC_83XX_IDC_DEV_READY);
+
+ return 0;
+}
+
+int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err;
+
+ spin_lock_init(&ahw->mbx_lock);
+ set_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+ set_bit(QLC_83XX_MODULE_LOADED, &ahw->idc.status);
+ ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+ ahw->reset_context = 0;
+ adapter->fw_fail_cnt = 0;
+ ahw->msix_supported = 1;
+ adapter->need_fw_reset = 0;
+ adapter->flags |= QLCNIC_TX_INTR_SHARED;
+
+ err = qlcnic_sriov_check_dev_ready(adapter);
+ if (err)
+ return err;
+
+ err = qlcnic_sriov_setup_vf(adapter, pci_using_dac);
+ if (err)
+ return err;
+
+ if (qlcnic_read_mac_addr(adapter))
+ dev_warn(&adapter->pdev->dev, "failed to read mac addr\n");
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return 0;
+}
+
+void qlcnic_sriov_vf_set_ops(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+ ahw->op_mode = QLCNIC_SRIOV_VF_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d Non Privileged SRIOV function\n",
+ ahw->fw_hal_version);
+ adapter->nic_ops = &qlcnic_sriov_vf_ops;
+ set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
+ return;
+}
+
+void qlcnic_sriov_vf_register_map(struct qlcnic_hardware_context *ahw)
+{
+ ahw->hw_ops = &qlcnic_sriov_vf_hw_ops;
+ ahw->reg_tbl = (u32 *)qlcnic_83xx_reg_tbl;
+ ahw->ext_reg_tbl = (u32 *)qlcnic_83xx_ext_reg_tbl;
+}
+
+static u32 qlcnic_sriov_get_bc_paysize(u32 real_pay_size, u8 curr_frag)
+{
+ u32 pay_size;
+
+ pay_size = real_pay_size / ((curr_frag + 1) * QLC_BC_PAYLOAD_SZ);
+
+ if (pay_size)
+ pay_size = QLC_BC_PAYLOAD_SZ;
+ else
+ pay_size = real_pay_size % QLC_BC_PAYLOAD_SZ;
+
+ return pay_size;
+}
+
+int qlcnic_sriov_func_to_index(struct qlcnic_adapter *adapter, u8 pci_func)
+{
+ struct qlcnic_vf_info *vf_info = adapter->ahw->sriov->vf_info;
+ u8 i;
+
+ if (qlcnic_sriov_vf_check(adapter))
+ return 0;
+
+ for (i = 0; i < adapter->ahw->sriov->num_vfs; i++) {
+ if (vf_info[i].pci_func == pci_func)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static inline int qlcnic_sriov_alloc_bc_trans(struct qlcnic_bc_trans **trans)
+{
+ *trans = kzalloc(sizeof(struct qlcnic_bc_trans), GFP_ATOMIC);
+ if (!*trans)
+ return -ENOMEM;
+
+ init_completion(&(*trans)->resp_cmpl);
+ return 0;
+}
+
+static inline int qlcnic_sriov_alloc_bc_msg(struct qlcnic_bc_hdr **hdr,
+ u32 size)
+{
+ *hdr = kzalloc(sizeof(struct qlcnic_bc_hdr) * size, GFP_ATOMIC);
+ if (!*hdr)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
+{
+ const struct qlcnic_mailbox_metadata *mbx_tbl;
+ int i, size;
+
+ mbx_tbl = qlcnic_sriov_bc_mbx_tbl;
+ size = ARRAY_SIZE(qlcnic_sriov_bc_mbx_tbl);
+
+ for (i = 0; i < size; i++) {
+ if (type == mbx_tbl[i].cmd) {
+ mbx->op_type = QLC_BC_CMD;
+ mbx->req.num = mbx_tbl[i].in_args;
+ mbx->rsp.num = mbx_tbl[i].out_args;
+ mbx->req.arg = kcalloc(mbx->req.num, sizeof(u32),
+ GFP_ATOMIC);
+ if (!mbx->req.arg)
+ return -ENOMEM;
+ mbx->rsp.arg = kcalloc(mbx->rsp.num, sizeof(u32),
+ GFP_ATOMIC);
+ if (!mbx->rsp.arg) {
+ kfree(mbx->req.arg);
+ mbx->req.arg = NULL;
+ return -ENOMEM;
+ }
+ memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num);
+ memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
+ mbx->req.arg[0] = (type | (mbx->req.num << 16) |
+ (3 << 29));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd,
+ u16 seq, u8 msg_type)
+{
+ struct qlcnic_bc_hdr *hdr;
+ int i;
+ u32 num_regs, bc_pay_sz;
+ u16 remainder;
+ u8 cmd_op, num_frags, t_num_frags;
+
+ bc_pay_sz = QLC_BC_PAYLOAD_SZ;
+ if (msg_type == QLC_BC_COMMAND) {
+ trans->req_pay = (struct qlcnic_bc_payload *)cmd->req.arg;
+ trans->rsp_pay = (struct qlcnic_bc_payload *)cmd->rsp.arg;
+ num_regs = cmd->req.num;
+ trans->req_pay_size = (num_regs * 4);
+ num_regs = cmd->rsp.num;
+ trans->rsp_pay_size = (num_regs * 4);
+ cmd_op = cmd->req.arg[0] & 0xff;
+ remainder = (trans->req_pay_size) % (bc_pay_sz);
+ num_frags = (trans->req_pay_size) / (bc_pay_sz);
+ if (remainder)
+ num_frags++;
+ t_num_frags = num_frags;
+ if (qlcnic_sriov_alloc_bc_msg(&trans->req_hdr, num_frags))
+ return -ENOMEM;
+ remainder = (trans->rsp_pay_size) % (bc_pay_sz);
+ num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
+ if (remainder)
+ num_frags++;
+ if (qlcnic_sriov_alloc_bc_msg(&trans->rsp_hdr, num_frags))
+ return -ENOMEM;
+ num_frags = t_num_frags;
+ hdr = trans->req_hdr;
+ } else {
+ cmd->req.arg = (u32 *)trans->req_pay;
+ cmd->rsp.arg = (u32 *)trans->rsp_pay;
+ cmd_op = cmd->req.arg[0] & 0xff;
+ remainder = (trans->rsp_pay_size) % (bc_pay_sz);
+ num_frags = (trans->rsp_pay_size) / (bc_pay_sz);
+ if (remainder)
+ num_frags++;
+ cmd->req.num = trans->req_pay_size / 4;
+ cmd->rsp.num = trans->rsp_pay_size / 4;
+ hdr = trans->rsp_hdr;
+ }
+
+ trans->trans_id = seq;
+ trans->cmd_id = cmd_op;
+ for (i = 0; i < num_frags; i++) {
+ hdr[i].version = 2;
+ hdr[i].msg_type = msg_type;
+ hdr[i].op_type = cmd->op_type;
+ hdr[i].num_cmds = 1;
+ hdr[i].num_frags = num_frags;
+ hdr[i].frag_num = i + 1;
+ hdr[i].cmd_op = cmd_op;
+ hdr[i].seq_id = seq;
+ }
+ return 0;
+}
+
+static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *trans)
+{
+ if (!trans)
+ return;
+ kfree(trans->req_hdr);
+ kfree(trans->rsp_hdr);
+ kfree(trans);
+}
+
+static int qlcnic_sriov_clear_trans(struct qlcnic_vf_info *vf,
+ struct qlcnic_bc_trans *trans, u8 type)
+{
+ struct qlcnic_trans_list *t_list;
+ unsigned long flags;
+ int ret = 0;
+
+ if (type == QLC_BC_RESPONSE) {
+ t_list = &vf->rcv_act;
+ spin_lock_irqsave(&t_list->lock, flags);
+ t_list->count--;
+ list_del(&trans->list);
+ if (t_list->count > 0)
+ ret = 1;
+ spin_unlock_irqrestore(&t_list->lock, flags);
+ }
+ if (type == QLC_BC_COMMAND) {
+ while (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
+ msleep(100);
+ vf->send_cmd = NULL;
+ clear_bit(QLC_BC_VF_SEND, &vf->state);
+ }
+ return ret;
+}
+
+static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ work_func_t func)
+{
+ if (test_bit(QLC_BC_VF_FLR, &vf->state) ||
+ vf->adapter->need_fw_reset)
+ return;
+
+ INIT_WORK(&vf->trans_work, func);
+ queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
+}
+
+static inline void qlcnic_sriov_wait_for_resp(struct qlcnic_bc_trans *trans)
+{
+ struct completion *cmpl = &trans->resp_cmpl;
+
+ if (wait_for_completion_timeout(cmpl, QLC_MBOX_RESP_TIMEOUT))
+ trans->trans_state = QLC_END;
+ else
+ trans->trans_state = QLC_ABORT;
+
+ return;
+}
+
+static void qlcnic_sriov_handle_multi_frags(struct qlcnic_bc_trans *trans,
+ u8 type)
+{
+ if (type == QLC_BC_RESPONSE) {
+ trans->curr_rsp_frag++;
+ if (trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
+ trans->trans_state = QLC_INIT;
+ else
+ trans->trans_state = QLC_END;
+ } else {
+ trans->curr_req_frag++;
+ if (trans->curr_req_frag < trans->req_hdr->num_frags)
+ trans->trans_state = QLC_INIT;
+ else
+ trans->trans_state = QLC_WAIT_FOR_RESP;
+ }
+}
+
+static void qlcnic_sriov_wait_for_channel_free(struct qlcnic_bc_trans *trans,
+ u8 type)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct completion *cmpl = &vf->ch_free_cmpl;
+
+ if (!wait_for_completion_timeout(cmpl, QLC_MBOX_CH_FREE_TIMEOUT)) {
+ trans->trans_state = QLC_ABORT;
+ return;
+ }
+
+ clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
+ qlcnic_sriov_handle_multi_frags(trans, type);
+}
+
+static void qlcnic_sriov_pull_bc_msg(struct qlcnic_adapter *adapter,
+ u32 *hdr, u32 *pay, u32 size)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 fw_mbx;
+ u8 i, max = 2, hdr_size, j;
+
+ hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
+ max = (size / sizeof(u32)) + hdr_size;
+
+ fw_mbx = readl(QLCNIC_MBX_FW(ahw, 0));
+ for (i = 2, j = 0; j < hdr_size; i++, j++)
+ *(hdr++) = readl(QLCNIC_MBX_FW(ahw, i));
+ for (; j < max; i++, j++)
+ *(pay++) = readl(QLCNIC_MBX_FW(ahw, i));
+}
+
+static int __qlcnic_sriov_issue_bc_post(struct qlcnic_vf_info *vf)
+{
+ int ret = -EBUSY;
+ u32 timeout = 10000;
+
+ do {
+ if (!test_and_set_bit(QLC_BC_VF_CHANNEL, &vf->state)) {
+ ret = 0;
+ break;
+ }
+ mdelay(1);
+ } while (--timeout);
+
+ return ret;
+}
+
+static int qlcnic_sriov_issue_bc_post(struct qlcnic_bc_trans *trans, u8 type)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ u32 pay_size, hdr_size;
+ u32 *hdr, *pay;
+ int ret;
+ u8 pci_func = trans->func_id;
+
+ if (__qlcnic_sriov_issue_bc_post(vf))
+ return -EBUSY;
+
+ if (type == QLC_BC_COMMAND) {
+ hdr = (u32 *)(trans->req_hdr + trans->curr_req_frag);
+ pay = (u32 *)(trans->req_pay + trans->curr_req_frag);
+ hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
+ pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
+ trans->curr_req_frag);
+ pay_size = (pay_size / sizeof(u32));
+ } else {
+ hdr = (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag);
+ pay = (u32 *)(trans->rsp_pay + trans->curr_rsp_frag);
+ hdr_size = (sizeof(struct qlcnic_bc_hdr) / sizeof(u32));
+ pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
+ trans->curr_rsp_frag);
+ pay_size = (pay_size / sizeof(u32));
+ }
+
+ ret = qlcnic_sriov_post_bc_msg(vf->adapter, hdr, pay,
+ pci_func, pay_size);
+ return ret;
+}
+
+static int __qlcnic_sriov_send_bc_msg(struct qlcnic_bc_trans *trans,
+ struct qlcnic_vf_info *vf, u8 type)
+{
+ bool flag = true;
+ int err = -EIO;
+
+ while (flag) {
+ if (test_bit(QLC_BC_VF_FLR, &vf->state) ||
+ vf->adapter->need_fw_reset)
+ trans->trans_state = QLC_ABORT;
+
+ switch (trans->trans_state) {
+ case QLC_INIT:
+ trans->trans_state = QLC_WAIT_FOR_CHANNEL_FREE;
+ if (qlcnic_sriov_issue_bc_post(trans, type))
+ trans->trans_state = QLC_ABORT;
+ break;
+ case QLC_WAIT_FOR_CHANNEL_FREE:
+ qlcnic_sriov_wait_for_channel_free(trans, type);
+ break;
+ case QLC_WAIT_FOR_RESP:
+ qlcnic_sriov_wait_for_resp(trans);
+ break;
+ case QLC_END:
+ err = 0;
+ flag = false;
+ break;
+ case QLC_ABORT:
+ err = -EIO;
+ flag = false;
+ clear_bit(QLC_BC_VF_CHANNEL, &vf->state);
+ break;
+ default:
+ err = -EIO;
+ flag = false;
+ }
+ }
+ return err;
+}
+
+static int qlcnic_sriov_send_bc_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans, int pci_func)
+{
+ struct qlcnic_vf_info *vf;
+ int err, index = qlcnic_sriov_func_to_index(adapter, pci_func);
+
+ if (index < 0)
+ return -EIO;
+
+ vf = &adapter->ahw->sriov->vf_info[index];
+ trans->vf = vf;
+ trans->func_id = pci_func;
+
+ if (!test_bit(QLC_BC_VF_STATE, &vf->state)) {
+ if (qlcnic_sriov_pf_check(adapter))
+ return -EIO;
+ if (qlcnic_sriov_vf_check(adapter) &&
+ trans->cmd_id != QLCNIC_BC_CMD_CHANNEL_INIT)
+ return -EIO;
+ }
+
+ mutex_lock(&vf->send_cmd_lock);
+ vf->send_cmd = trans;
+ err = __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_COMMAND);
+ qlcnic_sriov_clear_trans(vf, trans, QLC_BC_COMMAND);
+ mutex_unlock(&vf->send_cmd_lock);
+ return err;
+}
+
+static void __qlcnic_sriov_process_bc_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+#ifdef CONFIG_QLCNIC_SRIOV
+ if (qlcnic_sriov_pf_check(adapter)) {
+ qlcnic_sriov_pf_process_bc_cmd(adapter, trans, cmd);
+ return;
+ }
+#endif
+ cmd->rsp.arg[0] |= (0x9 << 25);
+ return;
+}
+
+static void qlcnic_sriov_process_bc_cmd(struct work_struct *work)
+{
+ struct qlcnic_vf_info *vf = container_of(work, struct qlcnic_vf_info,
+ trans_work);
+ struct qlcnic_bc_trans *trans = NULL;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ struct qlcnic_cmd_args cmd;
+ u8 req;
+
+ if (adapter->need_fw_reset)
+ return;
+
+ if (test_bit(QLC_BC_VF_FLR, &vf->state))
+ return;
+
+ trans = list_first_entry(&vf->rcv_act.wait_list,
+ struct qlcnic_bc_trans, list);
+ adapter = vf->adapter;
+
+ if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, trans->req_hdr->seq_id,
+ QLC_BC_RESPONSE))
+ goto cleanup_trans;
+
+ __qlcnic_sriov_process_bc_cmd(adapter, trans, &cmd);
+ trans->trans_state = QLC_INIT;
+ __qlcnic_sriov_send_bc_msg(trans, vf, QLC_BC_RESPONSE);
+
+cleanup_trans:
+ qlcnic_free_mbx_args(&cmd);
+ req = qlcnic_sriov_clear_trans(vf, trans, QLC_BC_RESPONSE);
+ qlcnic_sriov_cleanup_transaction(trans);
+ if (req)
+ qlcnic_sriov_schedule_bc_cmd(adapter->ahw->sriov, vf,
+ qlcnic_sriov_process_bc_cmd);
+}
+
+static void qlcnic_sriov_handle_bc_resp(struct qlcnic_bc_hdr *hdr,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_bc_trans *trans;
+ u32 pay_size;
+
+ if (test_and_set_bit(QLC_BC_VF_SEND, &vf->state))
+ return;
+
+ trans = vf->send_cmd;
+
+ if (trans == NULL)
+ goto clear_send;
+
+ if (trans->trans_id != hdr->seq_id)
+ goto clear_send;
+
+ pay_size = qlcnic_sriov_get_bc_paysize(trans->rsp_pay_size,
+ trans->curr_rsp_frag);
+ qlcnic_sriov_pull_bc_msg(vf->adapter,
+ (u32 *)(trans->rsp_hdr + trans->curr_rsp_frag),
+ (u32 *)(trans->rsp_pay + trans->curr_rsp_frag),
+ pay_size);
+ if (++trans->curr_rsp_frag < trans->rsp_hdr->num_frags)
+ goto clear_send;
+
+ complete(&trans->resp_cmpl);
+
+clear_send:
+ clear_bit(QLC_BC_VF_SEND, &vf->state);
+}
+
+int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_bc_trans *trans)
+{
+ struct qlcnic_trans_list *t_list = &vf->rcv_act;
+
+ t_list->count++;
+ list_add_tail(&trans->list, &t_list->wait_list);
+ if (t_list->count == 1)
+ qlcnic_sriov_schedule_bc_cmd(sriov, vf,
+ qlcnic_sriov_process_bc_cmd);
+ return 0;
+}
+
+static int qlcnic_sriov_add_act_list(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_bc_trans *trans)
+{
+ struct qlcnic_trans_list *t_list = &vf->rcv_act;
+
+ spin_lock(&t_list->lock);
+
+ __qlcnic_sriov_add_act_list(sriov, vf, trans);
+
+ spin_unlock(&t_list->lock);
+ return 0;
+}
+
+static void qlcnic_sriov_handle_pending_trans(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_bc_hdr *hdr)
+{
+ struct qlcnic_bc_trans *trans = NULL;
+ struct list_head *node;
+ u32 pay_size, curr_frag;
+ u8 found = 0, active = 0;
+
+ spin_lock(&vf->rcv_pend.lock);
+ if (vf->rcv_pend.count > 0) {
+ list_for_each(node, &vf->rcv_pend.wait_list) {
+ trans = list_entry(node, struct qlcnic_bc_trans, list);
+ if (trans->trans_id == hdr->seq_id) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ curr_frag = trans->curr_req_frag;
+ pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
+ curr_frag);
+ qlcnic_sriov_pull_bc_msg(vf->adapter,
+ (u32 *)(trans->req_hdr + curr_frag),
+ (u32 *)(trans->req_pay + curr_frag),
+ pay_size);
+ trans->curr_req_frag++;
+ if (trans->curr_req_frag >= hdr->num_frags) {
+ vf->rcv_pend.count--;
+ list_del(&trans->list);
+ active = 1;
+ }
+ }
+ spin_unlock(&vf->rcv_pend.lock);
+
+ if (active)
+ if (qlcnic_sriov_add_act_list(sriov, vf, trans))
+ qlcnic_sriov_cleanup_transaction(trans);
+
+ return;
+}
+
+static void qlcnic_sriov_handle_bc_cmd(struct qlcnic_sriov *sriov,
+ struct qlcnic_bc_hdr *hdr,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_bc_trans *trans;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ struct qlcnic_cmd_args cmd;
+ u32 pay_size;
+ int err;
+ u8 cmd_op;
+
+ if (adapter->need_fw_reset)
+ return;
+
+ if (!test_bit(QLC_BC_VF_STATE, &vf->state) &&
+ hdr->op_type != QLC_BC_CMD &&
+ hdr->cmd_op != QLCNIC_BC_CMD_CHANNEL_INIT)
+ return;
+
+ if (hdr->frag_num > 1) {
+ qlcnic_sriov_handle_pending_trans(sriov, vf, hdr);
+ return;
+ }
+
+ cmd_op = hdr->cmd_op;
+ if (qlcnic_sriov_alloc_bc_trans(&trans))
+ return;
+
+ if (hdr->op_type == QLC_BC_CMD)
+ err = qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op);
+ else
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, cmd_op);
+
+ if (err) {
+ qlcnic_sriov_cleanup_transaction(trans);
+ return;
+ }
+
+ cmd.op_type = hdr->op_type;
+ if (qlcnic_sriov_prepare_bc_hdr(trans, &cmd, hdr->seq_id,
+ QLC_BC_COMMAND)) {
+ qlcnic_free_mbx_args(&cmd);
+ qlcnic_sriov_cleanup_transaction(trans);
+ return;
+ }
+
+ pay_size = qlcnic_sriov_get_bc_paysize(trans->req_pay_size,
+ trans->curr_req_frag);
+ qlcnic_sriov_pull_bc_msg(vf->adapter,
+ (u32 *)(trans->req_hdr + trans->curr_req_frag),
+ (u32 *)(trans->req_pay + trans->curr_req_frag),
+ pay_size);
+ trans->func_id = vf->pci_func;
+ trans->vf = vf;
+ trans->trans_id = hdr->seq_id;
+ trans->curr_req_frag++;
+
+ if (qlcnic_sriov_soft_flr_check(adapter, trans, vf))
+ return;
+
+ if (trans->curr_req_frag == trans->req_hdr->num_frags) {
+ if (qlcnic_sriov_add_act_list(sriov, vf, trans)) {
+ qlcnic_free_mbx_args(&cmd);
+ qlcnic_sriov_cleanup_transaction(trans);
+ }
+ } else {
+ spin_lock(&vf->rcv_pend.lock);
+ list_add_tail(&trans->list, &vf->rcv_pend.wait_list);
+ vf->rcv_pend.count++;
+ spin_unlock(&vf->rcv_pend.lock);
+ }
+}
+
+static void qlcnic_sriov_handle_msg_event(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_bc_hdr hdr;
+ u32 *ptr = (u32 *)&hdr;
+ u8 msg_type, i;
+
+ for (i = 2; i < 6; i++)
+ ptr[i - 2] = readl(QLCNIC_MBX_FW(vf->adapter->ahw, i));
+ msg_type = hdr.msg_type;
+
+ switch (msg_type) {
+ case QLC_BC_COMMAND:
+ qlcnic_sriov_handle_bc_cmd(sriov, &hdr, vf);
+ break;
+ case QLC_BC_RESPONSE:
+ qlcnic_sriov_handle_bc_resp(&hdr, vf);
+ break;
+ }
+}
+
+static void qlcnic_sriov_handle_flr_event(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_adapter *adapter = vf->adapter;
+
+ if (qlcnic_sriov_pf_check(adapter))
+ qlcnic_sriov_pf_handle_flr(sriov, vf);
+ else
+ dev_err(&adapter->pdev->dev,
+ "Invalid event to VF. VF should not get FLR event\n");
+}
+
+void qlcnic_sriov_handle_bc_event(struct qlcnic_adapter *adapter, u32 event)
+{
+ struct qlcnic_vf_info *vf;
+ struct qlcnic_sriov *sriov;
+ int index;
+ u8 pci_func;
+
+ sriov = adapter->ahw->sriov;
+ pci_func = qlcnic_sriov_target_func_id(event);
+ index = qlcnic_sriov_func_to_index(adapter, pci_func);
+
+ if (index < 0)
+ return;
+
+ vf = &sriov->vf_info[index];
+ vf->pci_func = pci_func;
+
+ if (qlcnic_sriov_channel_free_check(event))
+ complete(&vf->ch_free_cmpl);
+
+ if (qlcnic_sriov_flr_check(event)) {
+ qlcnic_sriov_handle_flr_event(sriov, vf);
+ return;
+ }
+
+ if (qlcnic_sriov_bc_msg_check(event))
+ qlcnic_sriov_handle_msg_event(sriov, vf);
+}
+
+int qlcnic_sriov_cfg_bc_intr(struct qlcnic_adapter *adapter, u8 enable)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
+ return 0;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_BC_EVENT_SETUP))
+ return -ENOMEM;
+
+ if (enable)
+ cmd.req.arg[1] = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
+
+ err = qlcnic_83xx_mbx_op(adapter, &cmd);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to %s bc events, err=%d\n",
+ (enable ? "enable" : "disable"), err);
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_retry_bc_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans)
+{
+ u8 max = QLC_BC_CMD_MAX_RETRY_CNT;
+ u32 state;
+
+ state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+ if (state == QLC_83XX_IDC_DEV_READY) {
+ msleep(20);
+ clear_bit(QLC_BC_VF_CHANNEL, &trans->vf->state);
+ trans->trans_state = QLC_INIT;
+ if (++adapter->fw_fail_cnt > max)
+ return -EIO;
+ else
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *adapter,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_bc_trans *trans;
+ int err;
+ u32 rsp_data, opcode, mbx_err_code, rsp;
+ u16 seq = ++adapter->ahw->sriov->bc.trans_counter;
+ u8 func = ahw->pci_func;
+
+ rsp = qlcnic_sriov_alloc_bc_trans(&trans);
+ if (rsp)
+ return rsp;
+
+ rsp = qlcnic_sriov_prepare_bc_hdr(trans, cmd, seq, QLC_BC_COMMAND);
+ if (rsp)
+ goto cleanup_transaction;
+
+retry:
+ if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
+ rsp = -EIO;
+ QLCDB(adapter, DRV, "MBX not Ready!(cmd 0x%x) for VF 0x%x\n",
+ QLCNIC_MBX_RSP(cmd->req.arg[0]), func);
+ goto err_out;
+ }
+
+ err = qlcnic_sriov_send_bc_cmd(adapter, trans, func);
+ if (err) {
+ dev_err(dev, "MBX command 0x%x timed out for VF %d\n",
+ (cmd->req.arg[0] & 0xffff), func);
+ rsp = QLCNIC_RCODE_TIMEOUT;
+
+ /* After adapter reset PF driver may take some time to
+ * respond to VF's request. Retry request till maximum retries.
+ */
+ if ((trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) &&
+ !qlcnic_sriov_retry_bc_cmd(adapter, trans))
+ goto retry;
+
+ goto err_out;
+ }
+
+ rsp_data = cmd->rsp.arg[0];
+ mbx_err_code = QLCNIC_MBX_STATUS(rsp_data);
+ opcode = QLCNIC_MBX_RSP(cmd->req.arg[0]);
+
+ if ((mbx_err_code == QLCNIC_MBX_RSP_OK) ||
+ (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) {
+ rsp = QLCNIC_RCODE_SUCCESS;
+ } else {
+ rsp = mbx_err_code;
+ if (!rsp)
+ rsp = 1;
+ dev_err(dev,
+ "MBX command 0x%x failed with err:0x%x for VF %d\n",
+ opcode, mbx_err_code, func);
+ }
+
+err_out:
+ if (rsp == QLCNIC_RCODE_TIMEOUT) {
+ ahw->reset_context = 1;
+ adapter->need_fw_reset = 1;
+ clear_bit(QLC_83XX_MBX_READY, &ahw->idc.status);
+ }
+
+cleanup_transaction:
+ qlcnic_sriov_cleanup_transaction(trans);
+ return rsp;
+}
+
+int qlcnic_sriov_channel_cfg_cmd(struct qlcnic_adapter *adapter, u8 cmd_op)
+{
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_vf_info *vf = &adapter->ahw->sriov->vf_info[0];
+ int ret;
+
+ if (qlcnic_sriov_alloc_bc_mbx_args(&cmd, cmd_op))
+ return -ENOMEM;
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed bc channel %s %d\n", cmd_op ? "term" : "init",
+ ret);
+ goto out;
+ }
+
+ cmd_op = (cmd.rsp.arg[0] & 0xff);
+ if (cmd.rsp.arg[0] >> 25 == 2)
+ return 2;
+ if (cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
+ set_bit(QLC_BC_VF_STATE, &vf->state);
+ else
+ clear_bit(QLC_BC_VF_STATE, &vf->state);
+
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return ret;
+}
+
+void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_mac_list_s *cur;
+ struct list_head *head, tmp_list;
+
+ INIT_LIST_HEAD(&tmp_list);
+ head = &adapter->vf_mc_list;
+ netif_addr_lock_bh(netdev);
+
+ while (!list_empty(head)) {
+ cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
+ list_move(&cur->list, &tmp_list);
+ }
+
+ netif_addr_unlock_bh(netdev);
+
+ while (!list_empty(&tmp_list)) {
+ cur = list_entry((&tmp_list)->next,
+ struct qlcnic_mac_list_s, list);
+ qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
+
+void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc)
+{
+ struct list_head *head = &bc->async_list;
+ struct qlcnic_async_work_list *entry;
+
+ while (!list_empty(head)) {
+ entry = list_entry(head->next, struct qlcnic_async_work_list,
+ list);
+ cancel_work_sync(&entry->work);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+}
+
+static void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ u16 vlan;
+
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
+ return;
+
+ vlan = adapter->ahw->sriov->vlan;
+ __qlcnic_set_multi(netdev, vlan);
+}
+
+static void qlcnic_sriov_handle_async_multi(struct work_struct *work)
+{
+ struct qlcnic_async_work_list *entry;
+ struct net_device *netdev;
+
+ entry = container_of(work, struct qlcnic_async_work_list, work);
+ netdev = (struct net_device *)entry->ptr;
+
+ qlcnic_sriov_vf_set_multi(netdev);
+ return;
+}
+
+static struct qlcnic_async_work_list *
+qlcnic_sriov_get_free_node_async_work(struct qlcnic_back_channel *bc)
+{
+ struct list_head *node;
+ struct qlcnic_async_work_list *entry = NULL;
+ u8 empty = 0;
+
+ list_for_each(node, &bc->async_list) {
+ entry = list_entry(node, struct qlcnic_async_work_list, list);
+ if (!work_pending(&entry->work)) {
+ empty = 1;
+ break;
+ }
+ }
+
+ if (!empty) {
+ entry = kzalloc(sizeof(struct qlcnic_async_work_list),
+ GFP_ATOMIC);
+ if (entry == NULL)
+ return NULL;
+ list_add_tail(&entry->list, &bc->async_list);
+ }
+
+ return entry;
+}
+
+static void qlcnic_sriov_schedule_bc_async_work(struct qlcnic_back_channel *bc,
+ work_func_t func, void *data)
+{
+ struct qlcnic_async_work_list *entry = NULL;
+
+ entry = qlcnic_sriov_get_free_node_async_work(bc);
+ if (!entry)
+ return;
+
+ entry->ptr = data;
+ INIT_WORK(&entry->work, func);
+ queue_work(bc->bc_async_wq, &entry->work);
+}
+
+void qlcnic_sriov_vf_schedule_multi(struct net_device *netdev)
+{
+
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;
+
+ if (adapter->need_fw_reset)
+ return;
+
+ qlcnic_sriov_schedule_bc_async_work(bc, qlcnic_sriov_handle_async_multi,
+ netdev);
+}
+
+static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
+ qlcnic_83xx_enable_mbx_intrpt(adapter);
+
+ err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
+ if (err)
+ return err;
+
+ err = qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_INIT);
+ if (err)
+ goto err_out_cleanup_bc_intr;
+
+ err = qlcnic_sriov_vf_init_driver(adapter);
+ if (err)
+ goto err_out_term_channel;
+
+ return 0;
+
+err_out_term_channel:
+ qlcnic_sriov_channel_cfg_cmd(adapter, QLCNIC_BC_CMD_CHANNEL_TERM);
+
+err_out_cleanup_bc_intr:
+ qlcnic_sriov_cfg_bc_intr(adapter, 0);
+ return err;
+}
+
+static void qlcnic_sriov_vf_attach(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (netif_running(netdev)) {
+ if (!qlcnic_up(adapter, netdev))
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
+
+ netif_device_attach(netdev);
+}
+
+static void qlcnic_sriov_vf_detach(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_intrpt_config *intr_tbl = ahw->intr_tbl;
+ struct net_device *netdev = adapter->netdev;
+ u8 i, max_ints = ahw->num_msix - 1;
+
+ qlcnic_83xx_disable_mbx_intr(adapter);
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ qlcnic_down(adapter, netdev);
+
+ for (i = 0; i < max_ints; i++) {
+ intr_tbl[i].id = i;
+ intr_tbl[i].enabled = 0;
+ intr_tbl[i].src = 0;
+ }
+ ahw->reset_context = 0;
+}
+
+static int qlcnic_sriov_vf_handle_dev_ready(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct device *dev = &adapter->pdev->dev;
+ struct qlc_83xx_idc *idc = &ahw->idc;
+ u8 func = ahw->pci_func;
+ u32 state;
+
+ if ((idc->prev_state == QLC_83XX_IDC_DEV_NEED_RESET) ||
+ (idc->prev_state == QLC_83XX_IDC_DEV_INIT)) {
+ if (!qlcnic_sriov_vf_reinit_driver(adapter)) {
+ qlcnic_sriov_vf_attach(adapter);
+ adapter->fw_fail_cnt = 0;
+ dev_info(dev,
+ "%s: Reinitalization of VF 0x%x done after FW reset\n",
+ __func__, func);
+ } else {
+ dev_err(dev,
+ "%s: Reinitialization of VF 0x%x failed after FW reset\n",
+ __func__, func);
+ state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE);
+ dev_info(dev, "Current state 0x%x after FW reset\n",
+ state);
+ }
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct device *dev = &adapter->pdev->dev;
+ struct qlc_83xx_idc *idc = &ahw->idc;
+ u8 func = ahw->pci_func;
+ u32 state;
+
+ adapter->reset_ctx_cnt++;
+
+ /* Skip the context reset and check if FW is hung */
+ if (adapter->reset_ctx_cnt < 3) {
+ adapter->need_fw_reset = 1;
+ clear_bit(QLC_83XX_MBX_READY, &idc->status);
+ dev_info(dev,
+ "Resetting context, wait here to check if FW is in failed state\n");
+ return 0;
+ }
+
+ /* Check if number of resets exceed the threshold.
+ * If it exceeds the threshold just fail the VF.
+ */
+ if (adapter->reset_ctx_cnt > QLC_83XX_VF_RESET_FAIL_THRESH) {
+ clear_bit(QLC_83XX_MODULE_LOADED, &idc->status);
+ adapter->tx_timeo_cnt = 0;
+ adapter->fw_fail_cnt = 0;
+ adapter->reset_ctx_cnt = 0;
+ qlcnic_sriov_vf_detach(adapter);
+ dev_err(dev,
+ "Device context resets have exceeded the threshold, device interface will be shutdown\n");
+ return -EIO;
+ }
+
+ dev_info(dev, "Resetting context of VF 0x%x\n", func);
+ dev_info(dev, "%s: Context reset count %d for VF 0x%x\n",
+ __func__, adapter->reset_ctx_cnt, func);
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ adapter->need_fw_reset = 1;
+ clear_bit(QLC_83XX_MBX_READY, &idc->status);
+ qlcnic_sriov_vf_detach(adapter);
+ adapter->need_fw_reset = 0;
+
+ if (!qlcnic_sriov_vf_reinit_driver(adapter)) {
+ qlcnic_sriov_vf_attach(adapter);
+ adapter->netdev->trans_start = jiffies;
+ adapter->tx_timeo_cnt = 0;
+ adapter->reset_ctx_cnt = 0;
+ adapter->fw_fail_cnt = 0;
+ dev_info(dev, "Done resetting context for VF 0x%x\n", func);
+ } else {
+ dev_err(dev, "%s: Reinitialization of VF 0x%x failed\n",
+ __func__, func);
+ state = QLCRDX(ahw, QLC_83XX_IDC_DEV_STATE);
+ dev_info(dev, "%s: Current state 0x%x\n", __func__, state);
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_vf_idc_ready_state(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int ret = 0;
+
+ if (ahw->idc.prev_state != QLC_83XX_IDC_DEV_READY)
+ ret = qlcnic_sriov_vf_handle_dev_ready(adapter);
+ else if (ahw->reset_context)
+ ret = qlcnic_sriov_vf_handle_context_reset(adapter);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return ret;
+}
+
+static int qlcnic_sriov_vf_idc_failed_state(struct qlcnic_adapter *adapter)
+{
+ struct qlc_83xx_idc *idc = &adapter->ahw->idc;
+
+ dev_err(&adapter->pdev->dev, "Device is in failed state\n");
+ if (idc->prev_state == QLC_83XX_IDC_DEV_READY)
+ qlcnic_sriov_vf_detach(adapter);
+
+ clear_bit(QLC_83XX_MODULE_LOADED, &idc->status);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return -EIO;
+}
+
+static int
+qlcnic_sriov_vf_idc_need_quiescent_state(struct qlcnic_adapter *adapter)
+{
+ struct qlc_83xx_idc *idc = &adapter->ahw->idc;
+
+ dev_info(&adapter->pdev->dev, "Device is in quiescent state\n");
+ if (idc->prev_state == QLC_83XX_IDC_DEV_READY) {
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ adapter->tx_timeo_cnt = 0;
+ adapter->reset_ctx_cnt = 0;
+ clear_bit(QLC_83XX_MBX_READY, &idc->status);
+ qlcnic_sriov_vf_detach(adapter);
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_vf_idc_init_reset_state(struct qlcnic_adapter *adapter)
+{
+ struct qlc_83xx_idc *idc = &adapter->ahw->idc;
+ u8 func = adapter->ahw->pci_func;
+
+ if (idc->prev_state == QLC_83XX_IDC_DEV_READY) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware hang detected by VF 0x%x\n", func);
+ set_bit(__QLCNIC_RESETTING, &adapter->state);
+ adapter->tx_timeo_cnt = 0;
+ adapter->reset_ctx_cnt = 0;
+ clear_bit(QLC_83XX_MBX_READY, &idc->status);
+ qlcnic_sriov_vf_detach(adapter);
+ }
+ return 0;
+}
+
+static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter)
+{
+ dev_err(&adapter->pdev->dev, "%s: Device in unknown state\n", __func__);
+ return 0;
+}
+
+static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work)
+{
+ struct qlcnic_adapter *adapter;
+ struct qlc_83xx_idc *idc;
+ int ret = 0;
+
+ adapter = container_of(work, struct qlcnic_adapter, fw_work.work);
+ idc = &adapter->ahw->idc;
+ idc->curr_state = QLCRDX(adapter->ahw, QLC_83XX_IDC_DEV_STATE);
+
+ switch (idc->curr_state) {
+ case QLC_83XX_IDC_DEV_READY:
+ ret = qlcnic_sriov_vf_idc_ready_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_NEED_RESET:
+ case QLC_83XX_IDC_DEV_INIT:
+ ret = qlcnic_sriov_vf_idc_init_reset_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_NEED_QUISCENT:
+ ret = qlcnic_sriov_vf_idc_need_quiescent_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_FAILED:
+ ret = qlcnic_sriov_vf_idc_failed_state(adapter);
+ break;
+ case QLC_83XX_IDC_DEV_QUISCENT:
+ break;
+ default:
+ ret = qlcnic_sriov_vf_idc_unknown_state(adapter);
+ }
+
+ idc->prev_state = idc->curr_state;
+ if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status))
+ qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state,
+ idc->delay);
+}
+
+static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter)
+{
+ while (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ msleep(20);
+
+ clear_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ cancel_delayed_work_sync(&adapter->fw_work);
+}
+
+static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov,
+ u16 vid, u8 enable)
+{
+ u16 vlan = sriov->vlan;
+ u8 allowed = 0;
+ int i;
+
+ if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE)
+ return -EINVAL;
+
+ if (enable) {
+ if (vlan)
+ return -EINVAL;
+
+ if (sriov->any_vlan) {
+ for (i = 0; i < sriov->num_allowed_vlans; i++) {
+ if (sriov->allowed_vlans[i] == vid)
+ allowed = 1;
+ }
+
+ if (!allowed)
+ return -EINVAL;
+ }
+ } else {
+ if (!vlan || vlan != vid)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter,
+ u16 vid, u8 enable)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_cmd_args cmd;
+ int ret;
+
+ if (vid == 0)
+ return 0;
+
+ ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd,
+ QLCNIC_BC_CMD_CFG_GUEST_VLAN);
+ if (ret)
+ return ret;
+
+ cmd.req.arg[1] = (enable & 1) | vid << 16;
+
+ qlcnic_sriov_cleanup_async_list(&sriov->bc);
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure guest VLAN, err=%d\n", ret);
+ } else {
+ qlcnic_free_mac_list(adapter);
+
+ if (enable)
+ sriov->vlan = vid;
+ else
+ sriov->vlan = 0;
+
+ qlcnic_sriov_vf_set_multi(adapter->netdev);
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+ return ret;
+}
+
+static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter)
+{
+ struct list_head *head = &adapter->mac_list;
+ struct qlcnic_mac_list_s *cur;
+ u16 vlan;
+
+ vlan = adapter->ahw->sriov->vlan;
+
+ while (!list_empty(head)) {
+ cur = list_entry(head->next, struct qlcnic_mac_list_s, list);
+ qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+ vlan, QLCNIC_MAC_DEL);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
new file mode 100644
index 000000000000..c81be2da119b
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -0,0 +1,1780 @@
+/*
+ * QLogic qlcnic NIC Driver
+ * Copyright (c) 2009-2013 QLogic Corporation
+ *
+ * See LICENSE.qlcnic for copyright and licensing details.
+ */
+
+#include "qlcnic_sriov.h"
+#include "qlcnic.h"
+#include <linux/types.h>
+
+#define QLCNIC_SRIOV_VF_MAX_MAC 1
+#define QLC_VF_MIN_TX_RATE 100
+#define QLC_VF_MAX_TX_RATE 9999
+
+static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
+
+struct qlcnic_sriov_cmd_handler {
+ int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *);
+};
+
+struct qlcnic_sriov_fw_cmd_handler {
+ u32 cmd;
+ int (*fn) (struct qlcnic_bc_trans *, struct qlcnic_cmd_args *);
+};
+
+static int qlcnic_sriov_pf_set_vport_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info,
+ u16 vport_id)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO))
+ return -ENOMEM;
+
+ cmd.req.arg[1] = (vport_id << 16) | 0x1;
+ cmd.req.arg[2] = npar_info->bit_offsets;
+ cmd.req.arg[2] |= npar_info->min_tx_bw << 16;
+ cmd.req.arg[3] = npar_info->max_tx_bw | (npar_info->max_tx_ques << 16);
+ cmd.req.arg[4] = npar_info->max_tx_mac_filters;
+ cmd.req.arg[4] |= npar_info->max_rx_mcast_mac_filters << 16;
+ cmd.req.arg[5] = npar_info->max_rx_ucast_mac_filters |
+ (npar_info->max_rx_ip_addr << 16);
+ cmd.req.arg[6] = npar_info->max_rx_lro_flow |
+ (npar_info->max_rx_status_rings << 16);
+ cmd.req.arg[7] = npar_info->max_rx_buf_rings |
+ (npar_info->max_rx_ques << 16);
+ cmd.req.arg[8] = npar_info->max_tx_vlan_keys;
+ cmd.req.arg[8] |= npar_info->max_local_ipv6_addrs << 16;
+ cmd.req.arg[9] = npar_info->max_remote_ipv6_addrs;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "Failed to set vport info, err=%d\n", err);
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *info, u16 func)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_resources *res = &sriov->ff_max;
+ u32 temp, num_vf_macs, num_vfs, max;
+ int ret = -EIO, vpid, id;
+ struct qlcnic_vport *vp;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);
+ if (vpid < 0)
+ return -EINVAL;
+
+ num_vfs = sriov->num_vfs;
+ max = num_vfs + 1;
+ info->bit_offsets = 0xffff;
+ info->max_tx_ques = res->num_tx_queues / max;
+ info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters;
+ num_vf_macs = QLCNIC_SRIOV_VF_MAX_MAC;
+
+ if (adapter->ahw->pci_func == func) {
+ temp = res->num_rx_mcast_mac_filters - (num_vfs * num_vf_macs);
+ info->max_rx_ucast_mac_filters = temp;
+ temp = res->num_tx_mac_filters - (num_vfs * num_vf_macs);
+ info->max_tx_mac_filters = temp;
+ info->min_tx_bw = 0;
+ info->max_tx_bw = MAX_BW;
+ } else {
+ id = qlcnic_sriov_func_to_index(adapter, func);
+ if (id < 0)
+ return id;
+ vp = sriov->vf_info[id].vp;
+ info->min_tx_bw = vp->min_tx_bw;
+ info->max_tx_bw = vp->max_tx_bw;
+ info->max_rx_ucast_mac_filters = num_vf_macs;
+ info->max_tx_mac_filters = num_vf_macs;
+ }
+
+ info->max_rx_ip_addr = res->num_destip / max;
+ info->max_rx_status_rings = res->num_rx_status_rings / max;
+ info->max_rx_buf_rings = res->num_rx_buf_rings / max;
+ info->max_rx_ques = res->num_rx_queues / max;
+ info->max_rx_lro_flow = res->num_lro_flows_supported / max;
+ info->max_tx_vlan_keys = res->num_txvlan_keys;
+ info->max_local_ipv6_addrs = res->max_local_ipv6_addrs;
+ info->max_remote_ipv6_addrs = res->max_remote_ipv6_addrs;
+
+ ret = qlcnic_sriov_pf_set_vport_info(adapter, info, vpid);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void qlcnic_sriov_pf_set_ff_max_res(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *info)
+{
+ struct qlcnic_resources *ff_max = &adapter->ahw->sriov->ff_max;
+
+ ff_max->num_tx_mac_filters = info->max_tx_mac_filters;
+ ff_max->num_rx_ucast_mac_filters = info->max_rx_ucast_mac_filters;
+ ff_max->num_rx_mcast_mac_filters = info->max_rx_mcast_mac_filters;
+ ff_max->num_txvlan_keys = info->max_tx_vlan_keys;
+ ff_max->num_rx_queues = info->max_rx_ques;
+ ff_max->num_tx_queues = info->max_tx_ques;
+ ff_max->num_lro_flows_supported = info->max_rx_lro_flow;
+ ff_max->num_destip = info->max_rx_ip_addr;
+ ff_max->num_rx_buf_rings = info->max_rx_buf_rings;
+ ff_max->num_rx_status_rings = info->max_rx_status_rings;
+ ff_max->max_remote_ipv6_addrs = info->max_remote_ipv6_addrs;
+ ff_max->max_local_ipv6_addrs = info->max_local_ipv6_addrs;
+}
+
+static int qlcnic_sriov_get_pf_info(struct qlcnic_adapter *adapter,
+ struct qlcnic_info *npar_info)
+{
+ int err;
+ struct qlcnic_cmd_args cmd;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_NIC_INFO))
+ return -ENOMEM;
+
+ cmd.req.arg[1] = 0x2;
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get PF info, err=%d\n", err);
+ goto out;
+ }
+
+ npar_info->total_pf = cmd.rsp.arg[2] & 0xff;
+ npar_info->total_rss_engines = (cmd.rsp.arg[2] >> 8) & 0xff;
+ npar_info->max_vports = MSW(cmd.rsp.arg[2]);
+ npar_info->max_tx_ques = LSW(cmd.rsp.arg[3]);
+ npar_info->max_tx_mac_filters = MSW(cmd.rsp.arg[3]);
+ npar_info->max_rx_mcast_mac_filters = LSW(cmd.rsp.arg[4]);
+ npar_info->max_rx_ucast_mac_filters = MSW(cmd.rsp.arg[4]);
+ npar_info->max_rx_ip_addr = LSW(cmd.rsp.arg[5]);
+ npar_info->max_rx_lro_flow = MSW(cmd.rsp.arg[5]);
+ npar_info->max_rx_status_rings = LSW(cmd.rsp.arg[6]);
+ npar_info->max_rx_buf_rings = MSW(cmd.rsp.arg[6]);
+ npar_info->max_rx_ques = LSW(cmd.rsp.arg[7]);
+ npar_info->max_tx_vlan_keys = MSW(cmd.rsp.arg[7]);
+ npar_info->max_local_ipv6_addrs = LSW(cmd.rsp.arg[8]);
+ npar_info->max_remote_ipv6_addrs = MSW(cmd.rsp.arg[8]);
+
+ qlcnic_sriov_pf_set_ff_max_res(adapter, npar_info);
+ dev_info(&adapter->pdev->dev,
+ "\n\ttotal_pf: %d,\n"
+ "\n\ttotal_rss_engines: %d max_vports: %d max_tx_ques %d,\n"
+ "\tmax_tx_mac_filters: %d max_rx_mcast_mac_filters: %d,\n"
+ "\tmax_rx_ucast_mac_filters: 0x%x, max_rx_ip_addr: %d,\n"
+ "\tmax_rx_lro_flow: %d max_rx_status_rings: %d,\n"
+ "\tmax_rx_buf_rings: %d, max_rx_ques: %d, max_tx_vlan_keys %d\n"
+ "\tmax_local_ipv6_addrs: %d, max_remote_ipv6_addrs: %d\n",
+ npar_info->total_pf, npar_info->total_rss_engines,
+ npar_info->max_vports, npar_info->max_tx_ques,
+ npar_info->max_tx_mac_filters,
+ npar_info->max_rx_mcast_mac_filters,
+ npar_info->max_rx_ucast_mac_filters, npar_info->max_rx_ip_addr,
+ npar_info->max_rx_lro_flow, npar_info->max_rx_status_rings,
+ npar_info->max_rx_buf_rings, npar_info->max_rx_ques,
+ npar_info->max_tx_vlan_keys, npar_info->max_local_ipv6_addrs,
+ npar_info->max_remote_ipv6_addrs);
+
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static void qlcnic_sriov_pf_reset_vport_handle(struct qlcnic_adapter *adapter,
+ u8 func)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vport *vp;
+ int index;
+
+ if (adapter->ahw->pci_func == func) {
+ sriov->vp_handle = 0;
+ } else {
+ index = qlcnic_sriov_func_to_index(adapter, func);
+ if (index < 0)
+ return;
+ vp = sriov->vf_info[index].vp;
+ vp->handle = 0;
+ }
+}
+
+static void qlcnic_sriov_pf_set_vport_handle(struct qlcnic_adapter *adapter,
+ u16 vport_handle, u8 func)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vport *vp;
+ int index;
+
+ if (adapter->ahw->pci_func == func) {
+ sriov->vp_handle = vport_handle;
+ } else {
+ index = qlcnic_sriov_func_to_index(adapter, func);
+ if (index < 0)
+ return;
+ vp = sriov->vf_info[index].vp;
+ vp->handle = vport_handle;
+ }
+}
+
+static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *adapter,
+ u8 func)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vf_info *vf_info;
+ int index;
+
+ if (adapter->ahw->pci_func == func) {
+ return sriov->vp_handle;
+ } else {
+ index = qlcnic_sriov_func_to_index(adapter, func);
+ if (index >= 0) {
+ vf_info = &sriov->vf_info[index];
+ return vf_info->vp->handle;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int qlcnic_sriov_pf_config_vport(struct qlcnic_adapter *adapter,
+ u8 flag, u16 func)
+{
+ struct qlcnic_cmd_args cmd;
+ int ret;
+ int vpid;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_VPORT))
+ return -ENOMEM;
+
+ if (flag) {
+ cmd.req.arg[3] = func << 8;
+ } else {
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);
+ if (vpid < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ cmd.req.arg[3] = ((vpid & 0xffff) << 8) | 1;
+ }
+
+ ret = qlcnic_issue_cmd(adapter, &cmd);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "Failed %s vport, err %d for func 0x%x\n",
+ (flag ? "enable" : "disable"), ret, func);
+ goto out;
+ }
+
+ if (flag) {
+ vpid = cmd.rsp.arg[2] & 0xffff;
+ qlcnic_sriov_pf_set_vport_handle(adapter, vpid, func);
+ } else {
+ qlcnic_sriov_pf_reset_vport_handle(adapter, func);
+ }
+
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return ret;
+}
+
+static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
+ u8 enable)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ if (err)
+ return err;
+
+ cmd.req.arg[1] = 0x4;
+ if (enable)
+ cmd.req.arg[1] |= BIT_16;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure VLAN filtering, err=%d\n", err);
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter,
+ u8 func, u8 enable)
+{
+ struct qlcnic_cmd_args cmd;
+ int err = -EIO;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_TOGGLE_ESWITCH))
+ return -ENOMEM;
+
+ cmd.req.arg[0] |= (3 << 29);
+ cmd.req.arg[1] = ((func & 0xf) << 2) | BIT_6 | BIT_1;
+ if (enable)
+ cmd.req.arg[1] |= BIT_0;
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to enable sriov eswitch%d\n", err);
+ err = -EIO;
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static void qlcnic_sriov_pf_del_flr_queue(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_back_channel *bc = &sriov->bc;
+ int i;
+
+ for (i = 0; i < sriov->num_vfs; i++)
+ cancel_work_sync(&sriov->vf_info[i].flr_work);
+
+ destroy_workqueue(bc->bc_flr_wq);
+}
+
+static int qlcnic_sriov_pf_create_flr_queue(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_back_channel *bc = &adapter->ahw->sriov->bc;
+ struct workqueue_struct *wq;
+
+ wq = create_singlethread_workqueue("qlcnic-flr");
+ if (wq == NULL) {
+ dev_err(&adapter->pdev->dev, "Cannot create FLR workqueue\n");
+ return -ENOMEM;
+ }
+
+ bc->bc_flr_wq = wq;
+ return 0;
+}
+
+void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter)
+{
+ u8 func = adapter->ahw->pci_func;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return;
+
+ qlcnic_sriov_pf_del_flr_queue(adapter);
+ qlcnic_sriov_cfg_bc_intr(adapter, 0);
+ qlcnic_sriov_pf_config_vport(adapter, 0, func);
+ qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
+ qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 0);
+ __qlcnic_sriov_cleanup(adapter);
+ adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
+ clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
+}
+
+void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter)
+{
+ if (!qlcnic_sriov_pf_check(adapter))
+ return;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return;
+
+ pci_disable_sriov(adapter->pdev);
+ netdev_info(adapter->netdev,
+ "SR-IOV is disabled successfully on port %d\n",
+ adapter->portnum);
+}
+
+static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+
+ qlcnic_sriov_pf_disable(adapter);
+
+ qlcnic_sriov_pf_cleanup(adapter);
+
+ /* After disabling SRIOV re-init the driver in default mode
+ configure opmode based on op_mode of function
+ */
+ if (qlcnic_83xx_configure_opmode(adapter))
+ return -EIO;
+
+ if (netif_running(netdev))
+ __qlcnic_up(adapter, netdev);
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_info nic_info, pf_info, vp_info;
+ int err;
+ u8 func = ahw->pci_func;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return 0;
+
+ err = qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 1);
+ if (err)
+ return err;
+
+ err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1);
+ if (err)
+ goto disable_vlan_filtering;
+
+ err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
+ if (err)
+ goto disable_eswitch;
+
+ err = qlcnic_sriov_get_pf_info(adapter, &pf_info);
+ if (err)
+ goto delete_vport;
+
+ err = qlcnic_get_nic_info(adapter, &nic_info, func);
+ if (err)
+ goto delete_vport;
+
+ err = qlcnic_sriov_pf_cal_res_limit(adapter, &vp_info, func);
+ if (err)
+ goto delete_vport;
+
+ err = qlcnic_sriov_cfg_bc_intr(adapter, 1);
+ if (err)
+ goto delete_vport;
+
+ ahw->physical_port = (u8) nic_info.phys_port;
+ ahw->switch_mode = nic_info.switch_mode;
+ ahw->max_mtu = nic_info.max_mtu;
+ ahw->capabilities = nic_info.capabilities;
+ ahw->nic_mode = QLC_83XX_SRIOV_MODE;
+ return err;
+
+delete_vport:
+ qlcnic_sriov_pf_config_vport(adapter, 0, func);
+
+disable_eswitch:
+ qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0);
+
+disable_vlan_filtering:
+ qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 0);
+
+ return err;
+}
+
+static int qlcnic_sriov_pf_enable(struct qlcnic_adapter *adapter, int num_vfs)
+{
+ int err;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return 0;
+
+ err = pci_enable_sriov(adapter->pdev, num_vfs);
+ if (err)
+ qlcnic_sriov_pf_cleanup(adapter);
+
+ return err;
+}
+
+static int __qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter,
+ int num_vfs)
+{
+ int err = 0;
+
+ set_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
+ adapter->ahw->op_mode = QLCNIC_SRIOV_PF_FUNC;
+
+ err = qlcnic_sriov_init(adapter, num_vfs);
+ if (err)
+ goto clear_op_mode;
+
+ err = qlcnic_sriov_pf_create_flr_queue(adapter);
+ if (err)
+ goto sriov_cleanup;
+
+ err = qlcnic_sriov_pf_init(adapter);
+ if (err)
+ goto del_flr_queue;
+
+ err = qlcnic_sriov_pf_enable(adapter, num_vfs);
+ return err;
+
+del_flr_queue:
+ qlcnic_sriov_pf_del_flr_queue(adapter);
+
+sriov_cleanup:
+ __qlcnic_sriov_cleanup(adapter);
+
+clear_op_mode:
+ clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state);
+ adapter->ahw->op_mode = QLCNIC_MGMT_FUNC;
+ return err;
+}
+
+static int qlcnic_pci_sriov_enable(struct qlcnic_adapter *adapter, int num_vfs)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err;
+
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
+ netdev_err(netdev,
+ "SR-IOV cannot be enabled, when legacy interrupts are enabled\n");
+ return -EIO;
+ }
+
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+
+ err = __qlcnic_pci_sriov_enable(adapter, num_vfs);
+ if (err) {
+ netdev_info(netdev, "Failed to enable SR-IOV on port %d\n",
+ adapter->portnum);
+
+ err = -EIO;
+ if (qlcnic_83xx_configure_opmode(adapter))
+ goto error;
+ } else {
+ netdev_info(netdev,
+ "SR-IOV is enabled successfully on port %d\n",
+ adapter->portnum);
+ /* Return number of vfs enabled */
+ err = num_vfs;
+ }
+ if (netif_running(netdev))
+ __qlcnic_up(adapter, netdev);
+
+error:
+ return err;
+}
+
+int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+ struct qlcnic_adapter *adapter = pci_get_drvdata(dev);
+ int err;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ if (num_vfs == 0)
+ err = qlcnic_pci_sriov_disable(adapter);
+ else
+ err = qlcnic_pci_sriov_enable(adapter, num_vfs);
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return err;
+}
+
+static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
+{
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_vport *vp;
+ int err, id;
+
+ id = qlcnic_sriov_func_to_index(adapter, func);
+ if (id < 0)
+ return id;
+
+ vp = adapter->ahw->sriov->vf_info[id].vp;
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+ if (err)
+ return err;
+
+ cmd.req.arg[1] = 0x3 | func << 16;
+ if (vp->vlan_mode == QLC_PVID_MODE) {
+ cmd.req.arg[2] |= BIT_6;
+ cmd.req.arg[3] |= vp->vlan << 8;
+ }
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (err)
+ dev_err(&adapter->pdev->dev, "Failed to set ACL, err=%d\n",
+ err);
+
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter,
+ u16 func)
+{
+ struct qlcnic_info defvp_info;
+ int err;
+
+ err = qlcnic_sriov_pf_cal_res_limit(adapter, &defvp_info, func);
+ if (err)
+ return -EIO;
+
+ err = qlcnic_sriov_set_vf_acl(adapter, func);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+ u16 func = vf->pci_func;
+
+ cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
+ cmd->rsp.arg[0] |= (1 << 16);
+
+ if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
+ err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
+ if (!err) {
+ err = qlcnic_sriov_set_vf_vport_info(adapter, func);
+ if (err)
+ qlcnic_sriov_pf_config_vport(adapter, 0, func);
+ }
+ } else {
+ err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
+ }
+
+ if (err)
+ goto err_out;
+
+ cmd->rsp.arg[0] |= (1 << 25);
+
+ if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT)
+ set_bit(QLC_BC_VF_STATE, &vf->state);
+ else
+ clear_bit(QLC_BC_VF_STATE, &vf->state);
+
+ return err;
+
+err_out:
+ cmd->rsp.arg[0] |= (2 << 25);
+ return err;
+}
+
+static int qlcnic_sriov_cfg_vf_def_mac(struct qlcnic_adapter *adapter,
+ struct qlcnic_vport *vp,
+ u16 func, u16 vlan, u8 op)
+{
+ struct qlcnic_cmd_args cmd;
+ struct qlcnic_macvlan_mbx mv;
+ u8 *addr;
+ int err;
+ u32 *buf;
+ int vpid;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_CONFIG_MAC_VLAN))
+ return -ENOMEM;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter, func);
+ if (vpid < 0) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (vlan)
+ op = ((op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
+ QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL);
+
+ cmd.req.arg[1] = op | (1 << 8) | (3 << 6);
+ cmd.req.arg[1] |= ((vpid & 0xffff) << 16) | BIT_31;
+
+ addr = vp->mac;
+ mv.vlan = vlan;
+ mv.mac_addr0 = addr[0];
+ mv.mac_addr1 = addr[1];
+ mv.mac_addr2 = addr[2];
+ mv.mac_addr3 = addr[3];
+ mv.mac_addr4 = addr[4];
+ mv.mac_addr5 = addr[5];
+ buf = &cmd.req.arg[2];
+ memcpy(buf, &mv, sizeof(struct qlcnic_macvlan_mbx));
+
+ err = qlcnic_issue_cmd(adapter, &cmd);
+
+ if (err)
+ dev_err(&adapter->pdev->dev,
+ "MAC-VLAN %s to CAM failed, err=%d.\n",
+ ((op == 1) ? "add " : "delete "), err);
+
+out:
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
+static int qlcnic_sriov_validate_create_rx_ctx(struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[0] >> 29) != 0x3)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = tran->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ struct qlcnic_rcv_mbx_out *mbx_out;
+ int err;
+ u16 vlan;
+
+ err = qlcnic_sriov_validate_create_rx_ctx(cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ cmd->req.arg[6] = vf->vp->handle;
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ vlan = vf->vp->vlan;
+ if (!err) {
+ mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1];
+ vf->rx_ctx_id = mbx_out->ctx_id;
+ qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func,
+ vlan, QLCNIC_MAC_ADD);
+ } else {
+ vf->rx_ctx_id = 0;
+ }
+
+ return err;
+}
+
+static int qlcnic_sriov_pf_mac_address_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ u8 type, *mac;
+
+ type = cmd->req.arg[1];
+ switch (type) {
+ case QLCNIC_SET_STATION_MAC:
+ case QLCNIC_SET_FAC_DEF_MAC:
+ cmd->rsp.arg[0] = (2 << 25);
+ break;
+ case QLCNIC_GET_CURRENT_MAC:
+ cmd->rsp.arg[0] = (1 << 25);
+ mac = vf->vp->mac;
+ cmd->rsp.arg[2] = mac[1] | ((mac[0] << 8) & 0xff00);
+ cmd->rsp.arg[1] = mac[5] | ((mac[4] << 8) & 0xff00) |
+ ((mac[3]) << 16 & 0xff0000) |
+ ((mac[2]) << 24 & 0xff000000);
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_validate_create_tx_ctx(struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[0] >> 29) != 0x3)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_create_tx_ctx_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ struct qlcnic_tx_mbx_out *mbx_out;
+ int err;
+
+ err = qlcnic_sriov_validate_create_tx_ctx(cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ cmd->req.arg[5] |= vf->vp->handle << 16;
+ err = qlcnic_issue_cmd(adapter, cmd);
+ if (!err) {
+ mbx_out = (struct qlcnic_tx_mbx_out *)&cmd->rsp.arg[2];
+ vf->tx_ctx_id = mbx_out->ctx_id;
+ } else {
+ vf->tx_ctx_id = 0;
+ }
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_del_rx_ctx(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[0] >> 29) != 0x3)
+ return -EINVAL;
+
+ if ((cmd->req.arg[1] & 0xffff) != vf->rx_ctx_id)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+ u16 vlan;
+
+ err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ vlan = vf->vp->vlan;
+ qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func,
+ vlan, QLCNIC_MAC_DEL);
+ cmd->req.arg[1] |= vf->vp->handle << 16;
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ if (!err)
+ vf->rx_ctx_id = 0;
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_del_tx_ctx(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[0] >> 29) != 0x3)
+ return -EINVAL;
+
+ if ((cmd->req.arg[1] & 0xffff) != vf->tx_ctx_id)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_del_tx_ctx_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_del_tx_ctx(vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ cmd->req.arg[1] |= vf->vp->handle << 16;
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ if (!err)
+ vf->tx_ctx_id = 0;
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_cfg_lro(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[1] >> 16) != vf->rx_ctx_id)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_cfg_lro_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_cfg_lro(vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_pf_cfg_ip_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err = -EIO;
+ u8 op;
+
+ op = cmd->req.arg[1] & 0xff;
+
+ cmd->req.arg[1] |= vf->vp->handle << 16;
+ cmd->req.arg[1] |= BIT_31;
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_validate_cfg_intrpt(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if (((cmd->req.arg[1] >> 8) & 0xff) != vf->pci_func)
+ return -EINVAL;
+
+ if (!(cmd->req.arg[1] & BIT_16))
+ return -EINVAL;
+
+ if ((cmd->req.arg[1] & 0xff) != 0x1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_cfg_intrpt_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_cfg_intrpt(vf, cmd);
+ if (err)
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ else
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_mtu(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if (cmd->req.arg[1] != vf->rx_ctx_id)
+ return -EINVAL;
+
+ if (cmd->req.arg[2] > adapter->ahw->max_mtu)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_set_mtu_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_mtu(adapter, vf, cmd);
+ if (err)
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ else
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_get_nic_info(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if (cmd->req.arg[1] & BIT_31) {
+ if (((cmd->req.arg[1] >> 16) & 0x7fff) != vf->pci_func)
+ return -EINVAL;
+ } else {
+ cmd->req.arg[1] |= vf->vp->handle << 16;
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_get_nic_info_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_get_nic_info(vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_validate_cfg_rss(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if (cmd->req.arg[1] != vf->rx_ctx_id)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_cfg_rss_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_cfg_rss(vf, cmd);
+ if (err)
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ else
+ err = qlcnic_issue_cmd(adapter, cmd);
+
+ return err;
+}
+
+static int qlcnic_sriov_validate_cfg_intrcoal(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
+ u16 ctx_id, pkts, time;
+
+ ctx_id = cmd->req.arg[1] >> 16;
+ pkts = cmd->req.arg[2] & 0xffff;
+ time = cmd->req.arg[2] >> 16;
+
+ if (ctx_id != vf->rx_ctx_id)
+ return -EINVAL;
+ if (pkts > coal->rx_packets)
+ return -EINVAL;
+ if (time < coal->rx_time_us)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_cfg_intrcoal_cmd(struct qlcnic_bc_trans *tran,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = tran->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_cfg_intrcoal(adapter, vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_macvlan_mbx *macvlan;
+ struct qlcnic_vport *vp = vf->vp;
+ u8 op, new_op;
+
+ if (!(cmd->req.arg[1] & BIT_8))
+ return -EINVAL;
+
+ cmd->req.arg[1] |= (vf->vp->handle << 16);
+ cmd->req.arg[1] |= BIT_31;
+
+ macvlan = (struct qlcnic_macvlan_mbx *)&cmd->req.arg[2];
+ if (!(macvlan->mac_addr0 & BIT_0)) {
+ dev_err(&adapter->pdev->dev,
+ "MAC address change is not allowed from VF %d",
+ vf->pci_func);
+ return -EINVAL;
+ }
+
+ if (vp->vlan_mode == QLC_PVID_MODE) {
+ op = cmd->req.arg[1] & 0x7;
+ cmd->req.arg[1] &= ~0x7;
+ new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ?
+ QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL;
+ cmd->req.arg[3] |= vp->vlan << 16;
+ cmd->req.arg[1] |= new_op;
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_cfg_macvlan_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_cfg_macvlan(adapter, vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_validate_linkevent(struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ if ((cmd->req.arg[1] >> 16) != vf->rx_ctx_id)
+ return -EINVAL;
+
+ if (!(cmd->req.arg[1] & BIT_8))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_linkevent_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ err = qlcnic_sriov_validate_linkevent(vf, cmd);
+ if (err) {
+ cmd->rsp.arg[0] |= (0x6 << 25);
+ return err;
+ }
+
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_pf_cfg_promisc_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ int err;
+
+ cmd->req.arg[1] |= vf->vp->handle << 16;
+ cmd->req.arg[1] |= BIT_31;
+ err = qlcnic_issue_cmd(adapter, cmd);
+ return err;
+}
+
+static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = trans->vf;
+ struct qlcnic_vport *vp = vf->vp;
+ u8 cmd_op, mode = vp->vlan_mode;
+
+ cmd_op = trans->req_hdr->cmd_op;
+ cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25;
+
+ switch (mode) {
+ case QLC_GUEST_VLAN_MODE:
+ cmd->rsp.arg[1] = mode | 1 << 8;
+ cmd->rsp.arg[2] = 1 << 16;
+ break;
+ case QLC_PVID_MODE:
+ cmd->rsp.arg[1] = mode | 1 << 8 | vp->vlan << 16;
+ break;
+ }
+
+ return 0;
+}
+
+static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf)
+
+{
+ struct qlcnic_vport *vp = vf->vp;
+
+ if (!vp->vlan)
+ return -EINVAL;
+
+ if (!vf->rx_ctx_id) {
+ vp->vlan = 0;
+ return 0;
+ }
+
+ qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
+ vp->vlan, QLCNIC_MAC_DEL);
+ vp->vlan = 0;
+ qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
+ 0, QLCNIC_MAC_ADD);
+ return 0;
+}
+
+static int qlcnic_sriov_pf_add_guest_vlan(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vport *vp = vf->vp;
+ int err = -EIO;
+
+ if (vp->vlan)
+ return err;
+
+ if (!vf->rx_ctx_id) {
+ vp->vlan = cmd->req.arg[1] >> 16;
+ return 0;
+ }
+
+ err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
+ 0, QLCNIC_MAC_DEL);
+ if (err)
+ return err;
+
+ vp->vlan = cmd->req.arg[1] >> 16;
+ err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
+ vp->vlan, QLCNIC_MAC_ADD);
+
+ if (err) {
+ qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func,
+ 0, QLCNIC_MAC_ADD);
+ vp->vlan = 0;
+ }
+
+ return err;
+}
+
+static int qlcnic_sriov_pf_cfg_guest_vlan_cmd(struct qlcnic_bc_trans *tran,
+ struct qlcnic_cmd_args *cmd)
+{
+ struct qlcnic_vf_info *vf = tran->vf;
+ struct qlcnic_adapter *adapter = vf->adapter;
+ struct qlcnic_vport *vp = vf->vp;
+ int err = -EIO;
+ u8 op;
+
+ if (vp->vlan_mode != QLC_GUEST_VLAN_MODE) {
+ cmd->rsp.arg[0] |= 2 << 25;
+ return err;
+ }
+
+ op = cmd->req.arg[1] & 0xf;
+
+ if (op)
+ err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd);
+ else
+ err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf);
+
+ cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25;
+ return err;
+}
+
+static const int qlcnic_pf_passthru_supp_cmds[] = {
+ QLCNIC_CMD_GET_STATISTICS,
+ QLCNIC_CMD_GET_PORT_CONFIG,
+ QLCNIC_CMD_GET_LINK_STATUS,
+};
+
+static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = {
+ [QLCNIC_BC_CMD_CHANNEL_INIT] = {&qlcnic_sriov_pf_channel_cfg_cmd},
+ [QLCNIC_BC_CMD_CHANNEL_TERM] = {&qlcnic_sriov_pf_channel_cfg_cmd},
+ [QLCNIC_BC_CMD_GET_ACL] = {&qlcnic_sriov_pf_get_acl_cmd},
+ [QLCNIC_BC_CMD_CFG_GUEST_VLAN] = {&qlcnic_sriov_pf_cfg_guest_vlan_cmd},
+};
+
+static const struct qlcnic_sriov_fw_cmd_handler qlcnic_pf_fw_cmd_hdlr[] = {
+ {QLCNIC_CMD_CREATE_RX_CTX, qlcnic_sriov_pf_create_rx_ctx_cmd},
+ {QLCNIC_CMD_CREATE_TX_CTX, qlcnic_sriov_pf_create_tx_ctx_cmd},
+ {QLCNIC_CMD_MAC_ADDRESS, qlcnic_sriov_pf_mac_address_cmd},
+ {QLCNIC_CMD_DESTROY_RX_CTX, qlcnic_sriov_pf_del_rx_ctx_cmd},
+ {QLCNIC_CMD_DESTROY_TX_CTX, qlcnic_sriov_pf_del_tx_ctx_cmd},
+ {QLCNIC_CMD_CONFIGURE_HW_LRO, qlcnic_sriov_pf_cfg_lro_cmd},
+ {QLCNIC_CMD_CONFIGURE_IP_ADDR, qlcnic_sriov_pf_cfg_ip_cmd},
+ {QLCNIC_CMD_CONFIG_INTRPT, qlcnic_sriov_pf_cfg_intrpt_cmd},
+ {QLCNIC_CMD_SET_MTU, qlcnic_sriov_pf_set_mtu_cmd},
+ {QLCNIC_CMD_GET_NIC_INFO, qlcnic_sriov_pf_get_nic_info_cmd},
+ {QLCNIC_CMD_CONFIGURE_RSS, qlcnic_sriov_pf_cfg_rss_cmd},
+ {QLCNIC_CMD_CONFIG_INTR_COAL, qlcnic_sriov_pf_cfg_intrcoal_cmd},
+ {QLCNIC_CMD_CONFIG_MAC_VLAN, qlcnic_sriov_pf_cfg_macvlan_cmd},
+ {QLCNIC_CMD_GET_LINK_EVENT, qlcnic_sriov_pf_linkevent_cmd},
+ {QLCNIC_CMD_CONFIGURE_MAC_RX_MODE, qlcnic_sriov_pf_cfg_promisc_cmd},
+};
+
+void qlcnic_sriov_pf_process_bc_cmd(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans,
+ struct qlcnic_cmd_args *cmd)
+{
+ u8 size, cmd_op;
+
+ cmd_op = trans->req_hdr->cmd_op;
+
+ if (trans->req_hdr->op_type == QLC_BC_CMD) {
+ size = ARRAY_SIZE(qlcnic_pf_bc_cmd_hdlr);
+ if (cmd_op < size) {
+ qlcnic_pf_bc_cmd_hdlr[cmd_op].fn(trans, cmd);
+ return;
+ }
+ } else {
+ int i;
+ size = ARRAY_SIZE(qlcnic_pf_fw_cmd_hdlr);
+ for (i = 0; i < size; i++) {
+ if (cmd_op == qlcnic_pf_fw_cmd_hdlr[i].cmd) {
+ qlcnic_pf_fw_cmd_hdlr[i].fn(trans, cmd);
+ return;
+ }
+ }
+
+ size = ARRAY_SIZE(qlcnic_pf_passthru_supp_cmds);
+ for (i = 0; i < size; i++) {
+ if (cmd_op == qlcnic_pf_passthru_supp_cmds[i]) {
+ qlcnic_issue_cmd(adapter, cmd);
+ return;
+ }
+ }
+ }
+
+ cmd->rsp.arg[0] |= (0x9 << 25);
+}
+
+void qlcnic_pf_set_interface_id_create_rx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= vpid;
+}
+
+void qlcnic_pf_set_interface_id_del_rx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= vpid << 16;
+}
+
+void qlcnic_pf_set_interface_id_create_tx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ int vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= vpid << 16;
+}
+
+void qlcnic_pf_set_interface_id_del_tx_ctx(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= vpid << 16;
+}
+
+void qlcnic_pf_set_interface_id_promisc(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= (vpid << 16) | BIT_31;
+}
+
+void qlcnic_pf_set_interface_id_ipaddr(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= (vpid << 16) | BIT_31;
+}
+
+void qlcnic_pf_set_interface_id_macaddr(struct qlcnic_adapter *adapter,
+ u32 *int_id)
+{
+ u16 vpid;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter,
+ adapter->ahw->pci_func);
+ *int_id |= (vpid << 16) | BIT_31;
+}
+
+static void qlcnic_sriov_del_rx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_cmd_args cmd;
+ int vpid;
+
+ if (!vf->rx_ctx_id)
+ return;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_RX_CTX))
+ return;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);
+ if (vpid >= 0) {
+ cmd.req.arg[1] = vf->rx_ctx_id | (vpid & 0xffff) << 16;
+ if (qlcnic_issue_cmd(adapter, &cmd))
+ dev_err(&adapter->pdev->dev,
+ "Failed to delete Tx ctx in firmware for func 0x%x\n",
+ vf->pci_func);
+ else
+ vf->rx_ctx_id = 0;
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+}
+
+static void qlcnic_sriov_del_tx_ctx(struct qlcnic_adapter *adapter,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_cmd_args cmd;
+ int vpid;
+
+ if (!vf->tx_ctx_id)
+ return;
+
+ if (qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_DESTROY_TX_CTX))
+ return;
+
+ vpid = qlcnic_sriov_pf_get_vport_handle(adapter, vf->pci_func);
+ if (vpid >= 0) {
+ cmd.req.arg[1] |= vf->tx_ctx_id | (vpid & 0xffff) << 16;
+ if (qlcnic_issue_cmd(adapter, &cmd))
+ dev_err(&adapter->pdev->dev,
+ "Failed to delete Tx ctx in firmware for func 0x%x\n",
+ vf->pci_func);
+ else
+ vf->tx_ctx_id = 0;
+ }
+
+ qlcnic_free_mbx_args(&cmd);
+}
+
+static int qlcnic_sriov_add_act_list_irqsave(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ struct qlcnic_bc_trans *trans)
+{
+ struct qlcnic_trans_list *t_list = &vf->rcv_act;
+ unsigned long flag;
+
+ spin_lock_irqsave(&t_list->lock, flag);
+
+ __qlcnic_sriov_add_act_list(sriov, vf, trans);
+
+ spin_unlock_irqrestore(&t_list->lock, flag);
+ return 0;
+}
+
+static void __qlcnic_sriov_process_flr(struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_adapter *adapter = vf->adapter;
+
+ qlcnic_sriov_cleanup_list(&vf->rcv_pend);
+ cancel_work_sync(&vf->trans_work);
+ qlcnic_sriov_cleanup_list(&vf->rcv_act);
+
+ if (test_bit(QLC_BC_VF_SOFT_FLR, &vf->state)) {
+ qlcnic_sriov_del_tx_ctx(adapter, vf);
+ qlcnic_sriov_del_rx_ctx(adapter, vf);
+ }
+
+ qlcnic_sriov_pf_config_vport(adapter, 0, vf->pci_func);
+
+ clear_bit(QLC_BC_VF_FLR, &vf->state);
+ if (test_bit(QLC_BC_VF_SOFT_FLR, &vf->state)) {
+ qlcnic_sriov_add_act_list_irqsave(adapter->ahw->sriov, vf,
+ vf->flr_trans);
+ clear_bit(QLC_BC_VF_SOFT_FLR, &vf->state);
+ vf->flr_trans = NULL;
+ }
+}
+
+static void qlcnic_sriov_pf_process_flr(struct work_struct *work)
+{
+ struct qlcnic_vf_info *vf;
+
+ vf = container_of(work, struct qlcnic_vf_info, flr_work);
+ __qlcnic_sriov_process_flr(vf);
+ return;
+}
+
+static void qlcnic_sriov_schedule_flr(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf,
+ work_func_t func)
+{
+ if (test_bit(__QLCNIC_RESETTING, &vf->adapter->state))
+ return;
+
+ INIT_WORK(&vf->flr_work, func);
+ queue_work(sriov->bc.bc_flr_wq, &vf->flr_work);
+}
+
+static void qlcnic_sriov_handle_soft_flr(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+
+ set_bit(QLC_BC_VF_FLR, &vf->state);
+ clear_bit(QLC_BC_VF_STATE, &vf->state);
+ set_bit(QLC_BC_VF_SOFT_FLR, &vf->state);
+ vf->flr_trans = trans;
+ qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
+ netdev_info(adapter->netdev, "Software FLR for PCI func %d\n",
+ vf->pci_func);
+}
+
+bool qlcnic_sriov_soft_flr_check(struct qlcnic_adapter *adapter,
+ struct qlcnic_bc_trans *trans,
+ struct qlcnic_vf_info *vf)
+{
+ struct qlcnic_bc_hdr *hdr = trans->req_hdr;
+
+ if ((hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) &&
+ (hdr->op_type == QLC_BC_CMD) &&
+ test_bit(QLC_BC_VF_STATE, &vf->state)) {
+ qlcnic_sriov_handle_soft_flr(adapter, trans, vf);
+ return true;
+ }
+
+ return false;
+}
+
+void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
+ struct qlcnic_vf_info *vf)
+{
+ struct net_device *dev = vf->adapter->netdev;
+
+ if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
+ clear_bit(QLC_BC_VF_FLR, &vf->state);
+ return;
+ }
+
+ if (test_and_set_bit(QLC_BC_VF_FLR, &vf->state)) {
+ netdev_info(dev, "FLR for PCI func %d in progress\n",
+ vf->pci_func);
+ return;
+ }
+
+ qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
+ netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
+}
+
+void qlcnic_sriov_pf_reset(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct qlcnic_sriov *sriov = ahw->sriov;
+ struct qlcnic_vf_info *vf;
+ u16 num_vfs = sriov->num_vfs;
+ int i;
+
+ for (i = 0; i < num_vfs; i++) {
+ vf = &sriov->vf_info[i];
+ vf->rx_ctx_id = 0;
+ vf->tx_ctx_id = 0;
+ cancel_work_sync(&vf->flr_work);
+ __qlcnic_sriov_process_flr(vf);
+ clear_bit(QLC_BC_VF_STATE, &vf->state);
+ }
+
+ qlcnic_sriov_pf_reset_vport_handle(adapter, ahw->pci_func);
+ QLCWRX(ahw, QLCNIC_MBX_INTR_ENBL, (ahw->num_msix - 1) << 8);
+}
+
+int qlcnic_sriov_pf_reinit(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err;
+
+ if (!qlcnic_sriov_enable_check(adapter))
+ return 0;
+
+ ahw->op_mode = QLCNIC_SRIOV_PF_FUNC;
+
+ err = qlcnic_sriov_pf_init(adapter);
+ if (err)
+ return err;
+
+ dev_info(&adapter->pdev->dev, "%s: op_mode %d\n",
+ __func__, ahw->op_mode);
+ return err;
+}
+
+int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ int i, num_vfs = sriov->num_vfs;
+ struct qlcnic_vf_info *vf_info;
+ u8 *curr_mac;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (!is_valid_ether_addr(mac) || vf >= num_vfs)
+ return -EINVAL;
+
+ if (!compare_ether_addr(adapter->mac_addr, mac)) {
+ netdev_err(netdev, "MAC address is already in use by the PF\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_vfs; i++) {
+ vf_info = &sriov->vf_info[i];
+ if (!compare_ether_addr(vf_info->vp->mac, mac)) {
+ netdev_err(netdev,
+ "MAC address is already in use by VF %d\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ vf_info = &sriov->vf_info[vf];
+ curr_mac = vf_info->vp->mac;
+
+ if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
+ netdev_err(netdev,
+ "MAC address change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n",
+ vf);
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(curr_mac, mac, netdev->addr_len);
+ netdev_info(netdev, "MAC Address %pM is configured for VF %d\n",
+ mac, vf);
+ return 0;
+}
+
+int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, int tx_rate)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vf_info *vf_info;
+ struct qlcnic_info nic_info;
+ struct qlcnic_vport *vp;
+ u16 vpid;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (vf >= sriov->num_vfs)
+ return -EINVAL;
+
+ if (tx_rate >= 10000 || tx_rate < 100) {
+ netdev_err(netdev,
+ "Invalid Tx rate, allowed range is [%d - %d]",
+ QLC_VF_MIN_TX_RATE, QLC_VF_MAX_TX_RATE);
+ return -EINVAL;
+ }
+
+ if (tx_rate == 0)
+ tx_rate = 10000;
+
+ vf_info = &sriov->vf_info[vf];
+ vp = vf_info->vp;
+ vpid = vp->handle;
+
+ if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
+ if (qlcnic_sriov_get_vf_vport_info(adapter, &nic_info, vpid))
+ return -EIO;
+
+ nic_info.max_tx_bw = tx_rate / 100;
+ nic_info.bit_offsets = BIT_0;
+
+ if (qlcnic_sriov_pf_set_vport_info(adapter, &nic_info, vpid))
+ return -EIO;
+ }
+
+ vp->max_tx_bw = tx_rate / 100;
+ netdev_info(netdev,
+ "Setting Tx rate %d (Mbps), %d %% of PF bandwidth, for VF %d\n",
+ tx_rate, vp->max_tx_bw, vf);
+ return 0;
+}
+
+int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
+ u16 vlan, u8 qos)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vf_info *vf_info;
+ struct qlcnic_vport *vp;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (vf >= sriov->num_vfs || qos > 7)
+ return -EINVAL;
+
+ if (vlan > MAX_VLAN_ID) {
+ netdev_err(netdev,
+ "Invalid VLAN ID, allowed range is [0 - %d]\n",
+ MAX_VLAN_ID);
+ return -EINVAL;
+ }
+
+ vf_info = &sriov->vf_info[vf];
+ vp = vf_info->vp;
+ if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
+ netdev_err(netdev,
+ "VLAN change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n",
+ vf);
+ return -EOPNOTSUPP;
+ }
+
+ switch (vlan) {
+ case 4095:
+ vp->vlan_mode = QLC_GUEST_VLAN_MODE;
+ break;
+ case 0:
+ vp->vlan_mode = QLC_NO_VLAN_MODE;
+ vp->vlan = 0;
+ vp->qos = 0;
+ break;
+ default:
+ vp->vlan_mode = QLC_PVID_MODE;
+ vp->vlan = vlan;
+ vp->qos = qos;
+ }
+
+ netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n",
+ vlan, qos, vf);
+ return 0;
+}
+
+int qlcnic_sriov_get_vf_config(struct net_device *netdev,
+ int vf, struct ifla_vf_info *ivi)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vport *vp;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (vf >= sriov->num_vfs)
+ return -EINVAL;
+
+ vp = sriov->vf_info[vf].vp;
+ memcpy(&ivi->mac, vp->mac, ETH_ALEN);
+ ivi->vlan = vp->vlan;
+ ivi->qos = vp->qos;
+ if (vp->max_tx_bw == MAX_BW)
+ ivi->tx_rate = 0;
+ else
+ ivi->tx_rate = vp->max_tx_bw * 100;
+
+ ivi->vf = vf;
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 987fb6f8adc3..4e22e794a186 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -21,8 +21,6 @@
#include <linux/aer.h>
#include <linux/log2.h>
-#include <linux/sysfs.h>
-
#define QLC_STATUS_UNSUPPORTED_CMD -2
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
@@ -200,10 +198,10 @@ beacon_err:
}
err = qlcnic_config_led(adapter, b_state, b_rate);
- if (!err)
+ if (!err) {
err = len;
- else
ahw->beacon_state = b_state;
+ }
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
@@ -886,6 +884,244 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
return size;
}
+static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
+{
+ unsigned char *p_read_buf;
+ int ret, count;
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ if (!size)
+ return QL_STATUS_INVALID_PARAM;
+ if (!buf)
+ return QL_STATUS_INVALID_PARAM;
+
+ count = size / sizeof(u32);
+
+ if (size % sizeof(u32))
+ count++;
+
+ p_read_buf = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+ if (!p_read_buf)
+ return -ENOMEM;
+ if (qlcnic_83xx_lock_flash(adapter) != 0) {
+ kfree(p_read_buf);
+ return -EIO;
+ }
+
+ ret = qlcnic_83xx_lockless_flash_read32(adapter, offset, p_read_buf,
+ count);
+
+ if (ret) {
+ qlcnic_83xx_unlock_flash(adapter);
+ kfree(p_read_buf);
+ return ret;
+ }
+
+ qlcnic_83xx_unlock_flash(adapter);
+ memcpy(buf, p_read_buf, size);
+ kfree(p_read_buf);
+
+ return size;
+}
+
+static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter,
+ char *buf, loff_t offset,
+ size_t size)
+{
+ int i, ret, count;
+ unsigned char *p_cache, *p_src;
+
+ p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+ if (!p_cache)
+ return -ENOMEM;
+
+ memcpy(p_cache, buf, size);
+ p_src = p_cache;
+ count = size / sizeof(u32);
+
+ if (qlcnic_83xx_lock_flash(adapter) != 0) {
+ kfree(p_cache);
+ return -EIO;
+ }
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_enable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+
+ for (i = 0; i < count / QLC_83XX_FLASH_WRITE_MAX; i++) {
+ ret = qlcnic_83xx_flash_bulk_write(adapter, offset,
+ (u32 *)p_src,
+ QLC_83XX_FLASH_WRITE_MAX);
+
+ if (ret) {
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_disable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+
+ p_src = p_src + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX;
+ offset = offset + sizeof(u32)*QLC_83XX_FLASH_WRITE_MAX;
+ }
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_disable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return 0;
+}
+
+static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter,
+ char *buf, loff_t offset, size_t size)
+{
+ int i, ret, count;
+ unsigned char *p_cache, *p_src;
+
+ p_cache = kcalloc(size, sizeof(unsigned char), GFP_KERNEL);
+ if (!p_cache)
+ return -ENOMEM;
+
+ memcpy(p_cache, buf, size);
+ p_src = p_cache;
+ count = size / sizeof(u32);
+
+ if (qlcnic_83xx_lock_flash(adapter) != 0) {
+ kfree(p_cache);
+ return -EIO;
+ }
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_enable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ ret = qlcnic_83xx_flash_write32(adapter, offset, (u32 *)p_src);
+ if (ret) {
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_disable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+
+ p_src = p_src + sizeof(u32);
+ offset = offset + sizeof(u32);
+ }
+
+ if (adapter->ahw->fdt.mfg_id == adapter->flash_mfg_id) {
+ ret = qlcnic_83xx_disable_flash_write(adapter);
+ if (ret) {
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+ return -EIO;
+ }
+ }
+
+ kfree(p_cache);
+ qlcnic_83xx_unlock_flash(adapter);
+
+ return 0;
+}
+
+static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
+{
+ int ret;
+ static int flash_mode;
+ unsigned long data;
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ if (!buf)
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = kstrtoul(buf, 16, &data);
+
+ switch (data) {
+ case QLC_83XX_FLASH_SECTOR_ERASE_CMD:
+ flash_mode = QLC_83XX_ERASE_MODE;
+ ret = qlcnic_83xx_erase_flash_sector(adapter, offset);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s failed at %d\n", __func__, __LINE__);
+ return -EIO;
+ }
+ break;
+
+ case QLC_83XX_FLASH_BULK_WRITE_CMD:
+ flash_mode = QLC_83XX_BULK_WRITE_MODE;
+ break;
+
+ case QLC_83XX_FLASH_WRITE_CMD:
+ flash_mode = QLC_83XX_WRITE_MODE;
+ break;
+ default:
+ if (flash_mode == QLC_83XX_BULK_WRITE_MODE) {
+ ret = qlcnic_83xx_sysfs_flash_bulk_write(adapter, buf,
+ offset, size);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s failed at %d\n",
+ __func__, __LINE__);
+ return -EIO;
+ }
+ }
+
+ if (flash_mode == QLC_83XX_WRITE_MODE) {
+ ret = qlcnic_83xx_sysfs_flash_write(adapter, buf,
+ offset, size);
+ if (ret) {
+ dev_err(&adapter->pdev->dev,
+ "%s failed at %d\n", __func__,
+ __LINE__);
+ return -EIO;
+ }
+ }
+ }
+
+ return size;
+}
+
static struct device_attribute dev_attr_bridged_mode = {
.attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
.show = qlcnic_show_bridged_mode,
@@ -960,6 +1196,13 @@ static struct bin_attribute bin_attr_pm_config = {
.write = qlcnic_sysfs_write_pm_config,
};
+static struct bin_attribute bin_attr_flash = {
+ .attr = {.name = "flash", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_83xx_sysfs_flash_read_handler,
+ .write = qlcnic_83xx_sysfs_flash_write_handler,
+};
+
void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
@@ -1048,10 +1291,18 @@ void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter)
void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *adapter)
{
+ struct device *dev = &adapter->pdev->dev;
+
qlcnic_create_diag_entries(adapter);
+
+ if (sysfs_create_bin_file(&dev->kobj, &bin_attr_flash))
+ dev_info(dev, "failed to create flash sysfs entry\n");
}
void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *adapter)
{
+ struct device *dev = &adapter->pdev->dev;
+
qlcnic_remove_diag_entries(adapter);
+ sysfs_remove_bin_file(&dev->kobj, &bin_attr_flash);
}
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge.h b/drivers/net/ethernet/qlogic/qlge/qlge.h
index a131d7b5d2fe..7e8d68263963 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge.h
+++ b/drivers/net/ethernet/qlogic/qlge/qlge.h
@@ -18,7 +18,7 @@
*/
#define DRV_NAME "qlge"
#define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver "
-#define DRV_VERSION "v1.00.00.31"
+#define DRV_VERSION "v1.00.00.32"
#define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
index 6f316ab23257..0780e039b271 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
@@ -379,13 +379,13 @@ static int ql_get_settings(struct net_device *ndev,
ecmd->supported = SUPPORTED_10000baseT_Full;
ecmd->advertising = ADVERTISED_10000baseT_Full;
- ecmd->autoneg = AUTONEG_ENABLE;
ecmd->transceiver = XCVR_EXTERNAL;
if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
STS_LINK_TYPE_10GBASET) {
ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
ecmd->port = PORT_TP;
+ ecmd->autoneg = AUTONEG_ENABLE;
} else {
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index b13ab544a7eb..87463bc701a6 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -409,7 +409,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
(qdev->
func << CAM_OUT_FUNC_SHIFT) |
(0 << CAM_OUT_CQ_ID_SHIFT));
- if (qdev->ndev->features & NETIF_F_HW_VLAN_RX)
+ if (qdev->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
cam_output |= CAM_OUT_RV;
/* route to NIC core */
ql_write32(qdev, MAC_ADDR_DATA, cam_output);
@@ -1211,8 +1211,6 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
netdev_alloc_skb(qdev->ndev,
SMALL_BUFFER_SIZE);
if (sbq_desc->p.skb == NULL) {
- netif_err(qdev, probe, qdev->ndev,
- "Couldn't get an skb.\n");
rx_ring->sbq_clean_idx = clean_idx;
return;
}
@@ -1434,11 +1432,13 @@ map_error:
}
/* Categorizing receive firmware frame errors */
-static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err)
+static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err,
+ struct rx_ring *rx_ring)
{
struct nic_stats *stats = &qdev->nic_stats;
stats->rx_err_count++;
+ rx_ring->rx_errors++;
switch (rx_err & IB_MAC_IOCB_RSP_ERR_MASK) {
case IB_MAC_IOCB_RSP_ERR_CODE_ERR:
@@ -1474,6 +1474,12 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring);
struct napi_struct *napi = &rx_ring->napi;
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+ put_page(lbq_desc->p.pg_chunk.page);
+ return;
+ }
napi->dev = qdev->ndev;
skb = napi_get_frags(napi);
@@ -1500,7 +1506,7 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_record_rx_queue(skb, rx_ring->cq_id);
if (vlan_id != 0xffff)
- __vlan_hwaccel_put_tag(skb, vlan_id);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
napi_gro_frags(napi);
}
@@ -1519,8 +1525,6 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
skb = netdev_alloc_skb(ndev, length);
if (!skb) {
- netif_err(qdev, drv, qdev->ndev,
- "Couldn't get an skb, need to unwind!.\n");
rx_ring->rx_dropped++;
put_page(lbq_desc->p.pg_chunk.page);
return;
@@ -1529,6 +1533,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
addr = lbq_desc->p.pg_chunk.va;
prefetch(addr);
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+ goto err_out;
+ }
+
/* The max framesize filter on this chip is set higher than
* MTU since FCoE uses 2k frames.
*/
@@ -1578,7 +1588,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
skb_record_rx_queue(skb, rx_ring->cq_id);
if (vlan_id != 0xffff)
- __vlan_hwaccel_put_tag(skb, vlan_id);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY)
napi_gro_receive(napi, skb);
else
@@ -1605,8 +1615,6 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
/* Allocate new_skb and copy */
new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN);
if (new_skb == NULL) {
- netif_err(qdev, probe, qdev->ndev,
- "No skb available, drop the packet.\n");
rx_ring->rx_dropped++;
return;
}
@@ -1614,6 +1622,13 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
memcpy(skb_put(new_skb, length), skb->data, length);
skb = new_skb;
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
/* loopback self test for ethtool */
if (test_bit(QL_SELFTEST, &qdev->flags)) {
ql_check_lb_frame(qdev, skb);
@@ -1676,7 +1691,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
skb_record_rx_queue(skb, rx_ring->cq_id);
if (vlan_id != 0xffff)
- __vlan_hwaccel_put_tag(skb, vlan_id);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY)
napi_gro_receive(&rx_ring->napi, skb);
else
@@ -1919,6 +1934,13 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
return;
}
+ /* Frame error, so drop the packet. */
+ if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
+ ql_categorize_rx_err(qdev, ib_mac_rsp->flags2, rx_ring);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
/* The max framesize filter on this chip is set higher than
* MTU since FCoE uses 2k frames.
*/
@@ -1981,7 +2003,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
rx_ring->rx_bytes += skb->len;
skb_record_rx_queue(skb, rx_ring->cq_id);
if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && (vlan_id != 0))
- __vlan_hwaccel_put_tag(skb, vlan_id);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY)
napi_gro_receive(&rx_ring->napi, skb);
else
@@ -2000,12 +2022,6 @@ static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
- /* Frame error, so drop the packet. */
- if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) {
- ql_categorize_rx_err(qdev, ib_mac_rsp->flags2);
- return (unsigned long)length;
- }
-
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
/* The data and headers are split into
* separate buffers.
@@ -2285,7 +2301,7 @@ static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features)
{
struct ql_adapter *qdev = netdev_priv(ndev);
- if (features & NETIF_F_HW_VLAN_RX) {
+ if (features & NETIF_F_HW_VLAN_CTAG_RX) {
ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK |
NIC_RCV_CFG_VLAN_MATCH_AND_NON);
} else {
@@ -2300,10 +2316,10 @@ static netdev_features_t qlge_fix_features(struct net_device *ndev,
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
- if (features & NETIF_F_HW_VLAN_RX)
- features |= NETIF_F_HW_VLAN_TX;
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ features |= NETIF_F_HW_VLAN_CTAG_TX;
else
- features &= ~NETIF_F_HW_VLAN_TX;
+ features &= ~NETIF_F_HW_VLAN_CTAG_TX;
return features;
}
@@ -2313,7 +2329,7 @@ static int qlge_set_features(struct net_device *ndev,
{
netdev_features_t changed = ndev->features ^ features;
- if (changed & NETIF_F_HW_VLAN_RX)
+ if (changed & NETIF_F_HW_VLAN_CTAG_RX)
qlge_vlan_mode(ndev, features);
return 0;
@@ -2332,7 +2348,7 @@ static int __qlge_vlan_rx_add_vid(struct ql_adapter *qdev, u16 vid)
return err;
}
-static int qlge_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
+static int qlge_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status;
@@ -2363,7 +2379,7 @@ static int __qlge_vlan_rx_kill_vid(struct ql_adapter *qdev, u16 vid)
return err;
}
-static int qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
+static int qlge_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status;
@@ -4671,9 +4687,9 @@ static int qlge_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
NETIF_F_TSO | NETIF_F_TSO_ECN |
- NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_RXCSUM;
ndev->features = ndev->hw_features |
- NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->vlan_features = ndev->hw_features;
if (test_bit(QL_DMA64, &qdev->flags))
diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c
index 5b4103db70f5..e9dc84943cfc 100644
--- a/drivers/net/ethernet/rdc/r6040.c
+++ b/drivers/net/ethernet/rdc/r6040.c
@@ -224,11 +224,14 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg)
break;
}
+ if (limit < 0)
+ return -ETIMEDOUT;
+
return ioread16(ioaddr + MMRD);
}
/* Write a word data from PHY Chip */
-static void r6040_phy_write(void __iomem *ioaddr,
+static int r6040_phy_write(void __iomem *ioaddr,
int phy_addr, int reg, u16 val)
{
int limit = MAC_DEF_TIMEOUT;
@@ -243,6 +246,8 @@ static void r6040_phy_write(void __iomem *ioaddr,
if (!(cmd & MDIO_WRITE))
break;
}
+
+ return (limit < 0) ? -ETIMEDOUT : 0;
}
static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
@@ -261,9 +266,7 @@ static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
struct r6040_private *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
- r6040_phy_write(ioaddr, phy_addr, reg, value);
-
- return 0;
+ return r6040_phy_write(ioaddr, phy_addr, reg, value);
}
static int r6040_mdiobus_reset(struct mii_bus *bus)
@@ -347,7 +350,6 @@ static int r6040_alloc_rxbufs(struct net_device *dev)
do {
skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
if (!skb) {
- netdev_err(dev, "failed to alloc skb for rx\n");
rc = -ENOMEM;
goto err_exit;
}
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index b62a32484f6a..7d1fb9ad1296 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -431,7 +431,7 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
cp->dev->stats.rx_bytes += skb->len;
if (opts2 & RxVlanTagged)
- __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
napi_gro_receive(&cp->napi, skb);
}
@@ -1438,7 +1438,7 @@ static int cp_set_features(struct net_device *dev, netdev_features_t features)
else
cp->cpcmd &= ~RxChkSum;
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
cp->cpcmd |= RxVlanOn;
else
cp->cpcmd &= ~RxVlanOn;
@@ -1955,14 +1955,14 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->ethtool_ops = &cp_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
if (pci_using_dac)
dev->features |= NETIF_F_HIGHDMA;
/* disabled by default until verified */
dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c
index 1276ac71353a..3ccedeb8aba0 100644
--- a/drivers/net/ethernet/realtek/8139too.c
+++ b/drivers/net/ethernet/realtek/8139too.c
@@ -2041,8 +2041,6 @@ keep_pkt:
netif_receive_skb (skb);
} else {
- if (net_ratelimit())
- netdev_warn(dev, "Memory squeeze, dropping packet\n");
dev->stats.rx_dropped++;
}
received++;
diff --git a/drivers/net/ethernet/realtek/atp.c b/drivers/net/ethernet/realtek/atp.c
index 9f2d416de750..d77d60ea8202 100644
--- a/drivers/net/ethernet/realtek/atp.c
+++ b/drivers/net/ethernet/realtek/atp.c
@@ -782,8 +782,6 @@ static void net_rx(struct net_device *dev)
skb = netdev_alloc_skb(dev, pkt_len + 2);
if (skb == NULL) {
- printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n",
- dev->name);
dev->stats.rx_dropped++;
goto done;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 28fb50a1e9c3..79c520b64fdd 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -47,7 +47,9 @@
#define FIRMWARE_8402_1 "rtl_nic/rtl8402-1.fw"
#define FIRMWARE_8411_1 "rtl_nic/rtl8411-1.fw"
#define FIRMWARE_8106E_1 "rtl_nic/rtl8106e-1.fw"
-#define FIRMWARE_8168G_1 "rtl_nic/rtl8168g-1.fw"
+#define FIRMWARE_8106E_2 "rtl_nic/rtl8106e-2.fw"
+#define FIRMWARE_8168G_2 "rtl_nic/rtl8168g-2.fw"
+#define FIRMWARE_8168G_3 "rtl_nic/rtl8168g-3.fw"
#ifdef RTL8169_DEBUG
#define assert(expr) \
@@ -140,6 +142,8 @@ enum mac_version {
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
+ RTL_GIGA_MAC_VER_42,
+ RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_NONE = 0xff,
};
@@ -262,10 +266,16 @@ static const struct {
_R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_1,
JUMBO_1K, true),
[RTL_GIGA_MAC_VER_40] =
- _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_1,
+ _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_2,
JUMBO_9K, false),
[RTL_GIGA_MAC_VER_41] =
_R("RTL8168g/8111g", RTL_TD_1, NULL, JUMBO_9K, false),
+ [RTL_GIGA_MAC_VER_42] =
+ _R("RTL8168g/8111g", RTL_TD_1, FIRMWARE_8168G_3,
+ JUMBO_9K, false),
+ [RTL_GIGA_MAC_VER_43] =
+ _R("RTL8106e", RTL_TD_1, FIRMWARE_8106E_2,
+ JUMBO_1K, true),
};
#undef _R
@@ -329,6 +339,7 @@ enum rtl_registers {
#define RXCFG_FIFO_SHIFT 13
/* No threshold before first PCI xfer */
#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
+#define RX_EARLY_OFF (1 << 11)
#define RXCFG_DMA_SHIFT 8
/* Unlimited maximum PCI burst. */
#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
@@ -513,6 +524,7 @@ enum rtl_register_content {
PMEnable = (1 << 0), /* Power Management Enable */
/* Config2 register p. 25 */
+ ClkReqEn = (1 << 7), /* Clock Request Enable */
MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */
PCI_Clock_66MHz = 0x01,
PCI_Clock_33MHz = 0x00,
@@ -533,6 +545,7 @@ enum rtl_register_content {
Spi_en = (1 << 3),
LanWake = (1 << 1), /* LanWake enable/disable */
PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
+ ASPM_en = (1 << 0), /* ASPM enable */
/* TBICSR p.28 */
TBIReset = 0x80000000,
@@ -814,7 +827,9 @@ MODULE_FIRMWARE(FIRMWARE_8168F_2);
MODULE_FIRMWARE(FIRMWARE_8402_1);
MODULE_FIRMWARE(FIRMWARE_8411_1);
MODULE_FIRMWARE(FIRMWARE_8106E_1);
-MODULE_FIRMWARE(FIRMWARE_8168G_1);
+MODULE_FIRMWARE(FIRMWARE_8106E_2);
+MODULE_FIRMWARE(FIRMWARE_8168G_2);
+MODULE_FIRMWARE(FIRMWARE_8168G_3);
static void rtl_lock_work(struct rtl8169_private *tp)
{
@@ -1024,14 +1039,6 @@ static u16 r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
(RTL_R32(GPHY_OCP) & 0xffff) : ~0;
}
-static void rtl_w1w0_phy_ocp(struct rtl8169_private *tp, int reg, int p, int m)
-{
- int val;
-
- val = r8168_phy_ocp_read(tp, reg);
- r8168_phy_ocp_write(tp, reg, (val | p) & ~m);
-}
-
static void r8168_mac_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -1077,6 +1084,21 @@ static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
}
+static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
+{
+ if (reg == 0x1f) {
+ tp->ocp_base = value << 4;
+ return;
+ }
+
+ r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
+}
+
+static int mac_mcu_read(struct rtl8169_private *tp, int reg)
+{
+ return r8168_mac_ocp_read(tp, tp->ocp_base + reg);
+}
+
DECLARE_RTL_COND(rtl_phyar_cond)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -1771,16 +1793,17 @@ static void __rtl8169_set_features(struct net_device *dev,
netdev_features_t changed = features ^ dev->features;
void __iomem *ioaddr = tp->mmio_addr;
- if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)))
+ if (!(changed & (NETIF_F_RXALL | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_CTAG_RX)))
return;
- if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_RX)) {
+ if (changed & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX)) {
if (features & NETIF_F_RXCSUM)
tp->cp_cmd |= RxChkSum;
else
tp->cp_cmd &= ~RxChkSum;
- if (dev->features & NETIF_F_HW_VLAN_RX)
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX)
tp->cp_cmd |= RxVlan;
else
tp->cp_cmd &= ~RxVlan;
@@ -1820,7 +1843,7 @@ static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
u32 opts2 = le32_to_cpu(desc->opts2);
if (opts2 & RxVlanTag)
- __vlan_hwaccel_put_tag(skb, swab16(opts2 & 0xffff));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), swab16(opts2 & 0xffff));
}
static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -2028,6 +2051,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
int mac_version;
} mac_info[] = {
/* 8168G family. */
+ { 0x7cf00000, 0x50900000, RTL_GIGA_MAC_VER_42 },
{ 0x7cf00000, 0x4c100000, RTL_GIGA_MAC_VER_41 },
{ 0x7cf00000, 0x4c000000, RTL_GIGA_MAC_VER_40 },
@@ -2116,6 +2140,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
netif_notice(tp, probe, dev,
"unknown MAC, using family default\n");
tp->mac_version = default_version;
+ } else if (tp->mac_version == RTL_GIGA_MAC_VER_42) {
+ tp->mac_version = tp->mii.supports_gmii ?
+ RTL_GIGA_MAC_VER_42 :
+ RTL_GIGA_MAC_VER_43;
}
}
@@ -2142,9 +2170,7 @@ static void rtl_writephy_batch(struct rtl8169_private *tp,
#define PHY_DATA_OR 0x10000000
#define PHY_DATA_AND 0x20000000
#define PHY_BJMPN 0x30000000
-#define PHY_READ_EFUSE 0x40000000
-#define PHY_READ_MAC_BYTE 0x50000000
-#define PHY_WRITE_MAC_BYTE 0x60000000
+#define PHY_MDIO_CHG 0x40000000
#define PHY_CLEAR_READCOUNT 0x70000000
#define PHY_WRITE 0x80000000
#define PHY_READCOUNT_EQ_SKIP 0x90000000
@@ -2153,7 +2179,6 @@ static void rtl_writephy_batch(struct rtl8169_private *tp,
#define PHY_WRITE_PREVIOUS 0xc0000000
#define PHY_SKIPN 0xd0000000
#define PHY_DELAY_MS 0xe0000000
-#define PHY_WRITE_ERI_WORD 0xf0000000
struct fw_info {
u32 magic;
@@ -2230,7 +2255,7 @@ static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
- case PHY_READ_EFUSE:
+ case PHY_MDIO_CHG:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
@@ -2261,9 +2286,6 @@ static bool rtl_fw_data_ok(struct rtl8169_private *tp, struct net_device *dev,
}
break;
- case PHY_READ_MAC_BYTE:
- case PHY_WRITE_MAC_BYTE:
- case PHY_WRITE_ERI_WORD:
default:
netif_err(tp, ifup, tp->dev,
"Invalid action 0x%08x\n", action);
@@ -2294,10 +2316,13 @@ out:
static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
+ struct mdio_ops org, *ops = &tp->mdio_ops;
u32 predata, count;
size_t index;
predata = count = 0;
+ org.write = ops->write;
+ org.read = ops->read;
for (index = 0; index < pa->size; ) {
u32 action = le32_to_cpu(pa->code[index]);
@@ -2324,8 +2349,15 @@ static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
case PHY_BJMPN:
index -= regno;
break;
- case PHY_READ_EFUSE:
- predata = rtl8168d_efuse_read(tp, regno);
+ case PHY_MDIO_CHG:
+ if (data == 0) {
+ ops->write = org.write;
+ ops->read = org.read;
+ } else if (data == 1) {
+ ops->write = mac_mcu_write;
+ ops->read = mac_mcu_read;
+ }
+
index++;
break;
case PHY_CLEAR_READCOUNT:
@@ -2361,13 +2393,13 @@ static void rtl_phy_write_fw(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
index++;
break;
- case PHY_READ_MAC_BYTE:
- case PHY_WRITE_MAC_BYTE:
- case PHY_WRITE_ERI_WORD:
default:
BUG();
}
}
+
+ ops->write = org.write;
+ ops->read = org.read;
}
static void rtl_release_firmware(struct rtl8169_private *tp)
@@ -3368,51 +3400,68 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp)
static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp)
{
- static const u16 mac_ocp_patch[] = {
- 0xe008, 0xe01b, 0xe01d, 0xe01f,
- 0xe021, 0xe023, 0xe025, 0xe027,
- 0x49d2, 0xf10d, 0x766c, 0x49e2,
- 0xf00a, 0x1ec0, 0x8ee1, 0xc60a,
-
- 0x77c0, 0x4870, 0x9fc0, 0x1ea0,
- 0xc707, 0x8ee1, 0x9d6c, 0xc603,
- 0xbe00, 0xb416, 0x0076, 0xe86c,
- 0xc602, 0xbe00, 0x0000, 0xc602,
-
- 0xbe00, 0x0000, 0xc602, 0xbe00,
- 0x0000, 0xc602, 0xbe00, 0x0000,
- 0xc602, 0xbe00, 0x0000, 0xc602,
- 0xbe00, 0x0000, 0xc602, 0xbe00,
-
- 0x0000, 0x0000, 0x0000, 0x0000
- };
- u32 i;
+ rtl_apply_firmware(tp);
- /* Patch code for GPHY reset */
- for (i = 0; i < ARRAY_SIZE(mac_ocp_patch); i++)
- r8168_mac_ocp_write(tp, 0xf800 + 2*i, mac_ocp_patch[i]);
- r8168_mac_ocp_write(tp, 0xfc26, 0x8000);
- r8168_mac_ocp_write(tp, 0xfc28, 0x0075);
+ rtl_writephy(tp, 0x1f, 0x0a46);
+ if (rtl_readphy(tp, 0x10) & 0x0100) {
+ rtl_writephy(tp, 0x1f, 0x0bcc);
+ rtl_w1w0_phy(tp, 0x12, 0x0000, 0x8000);
+ } else {
+ rtl_writephy(tp, 0x1f, 0x0bcc);
+ rtl_w1w0_phy(tp, 0x12, 0x8000, 0x0000);
+ }
- rtl_apply_firmware(tp);
+ rtl_writephy(tp, 0x1f, 0x0a46);
+ if (rtl_readphy(tp, 0x13) & 0x0100) {
+ rtl_writephy(tp, 0x1f, 0x0c41);
+ rtl_w1w0_phy(tp, 0x15, 0x0002, 0x0000);
+ } else {
+ rtl_writephy(tp, 0x1f, 0x0c41);
+ rtl_w1w0_phy(tp, 0x15, 0x0000, 0x0002);
+ }
- if (r8168_phy_ocp_read(tp, 0xa460) & 0x0100)
- rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x8000);
- else
- rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x8000, 0x0000);
+ /* Enable PHY auto speed down */
+ rtl_writephy(tp, 0x1f, 0x0a44);
+ rtl_w1w0_phy(tp, 0x11, 0x000c, 0x0000);
+
+ rtl_writephy(tp, 0x1f, 0x0bcc);
+ rtl_w1w0_phy(tp, 0x14, 0x0100, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0a44);
+ rtl_w1w0_phy(tp, 0x11, 0x00c0, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0a43);
+ rtl_writephy(tp, 0x13, 0x8084);
+ rtl_w1w0_phy(tp, 0x14, 0x0000, 0x6000);
+ rtl_w1w0_phy(tp, 0x10, 0x1003, 0x0000);
+
+ /* EEE auto-fallback function */
+ rtl_writephy(tp, 0x1f, 0x0a4b);
+ rtl_w1w0_phy(tp, 0x11, 0x0004, 0x0000);
+
+ /* Enable UC LPF tune function */
+ rtl_writephy(tp, 0x1f, 0x0a43);
+ rtl_writephy(tp, 0x13, 0x8012);
+ rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
- if (r8168_phy_ocp_read(tp, 0xa466) & 0x0100)
- rtl_w1w0_phy_ocp(tp, 0xc41a, 0x0002, 0x0000);
- else
- rtl_w1w0_phy_ocp(tp, 0xbcc4, 0x0000, 0x0002);
+ rtl_writephy(tp, 0x1f, 0x0c42);
+ rtl_w1w0_phy(tp, 0x11, 0x4000, 0x2000);
- rtl_w1w0_phy_ocp(tp, 0xa442, 0x000c, 0x0000);
- rtl_w1w0_phy_ocp(tp, 0xa4b2, 0x0004, 0x0000);
+ /* Improve SWR Efficiency */
+ rtl_writephy(tp, 0x1f, 0x0bcd);
+ rtl_writephy(tp, 0x14, 0x5065);
+ rtl_writephy(tp, 0x14, 0xd065);
+ rtl_writephy(tp, 0x1f, 0x0bc8);
+ rtl_writephy(tp, 0x11, 0x5655);
+ rtl_writephy(tp, 0x1f, 0x0bcd);
+ rtl_writephy(tp, 0x14, 0x1065);
+ rtl_writephy(tp, 0x14, 0x9065);
+ rtl_writephy(tp, 0x14, 0x1065);
- r8168_phy_ocp_write(tp, 0xa436, 0x8012);
- rtl_w1w0_phy_ocp(tp, 0xa438, 0x8000, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+}
- rtl_w1w0_phy_ocp(tp, 0xc422, 0x4000, 0x2000);
+static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp)
+{
+ rtl_apply_firmware(tp);
}
static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
@@ -3600,6 +3649,10 @@ static void rtl_hw_phy_config(struct net_device *dev)
case RTL_GIGA_MAC_VER_40:
rtl8168g_1_hw_phy_config(tp);
break;
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
+ rtl8168g_2_hw_phy_config(tp);
+ break;
case RTL_GIGA_MAC_VER_41:
default:
@@ -3808,6 +3861,8 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
break;
case RTL_GIGA_MAC_VER_40:
case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
ops->write = r8168g_mdio_write;
ops->read = r8168g_mdio_read;
break;
@@ -3818,6 +3873,30 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
}
}
+static void rtl_speed_down(struct rtl8169_private *tp)
+{
+ u32 adv;
+ int lpa;
+
+ rtl_writephy(tp, 0x1f, 0x0000);
+ lpa = rtl_readphy(tp, MII_LPA);
+
+ if (lpa & (LPA_10HALF | LPA_10FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full;
+ else if (lpa & (LPA_100HALF | LPA_100FULL))
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+ else
+ adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+ (tp->mii.supports_gmii ?
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full : 0);
+
+ rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
+ adv);
+}
+
static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
@@ -3835,6 +3914,8 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_39:
case RTL_GIGA_MAC_VER_40:
case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
RTL_W32(RxConfig, RTL_R32(RxConfig) |
AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
break;
@@ -3848,9 +3929,7 @@ static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
return false;
- rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, MII_BMCR, 0x0000);
-
+ rtl_speed_down(tp);
rtl_wol_suspend_quirk(tp);
return true;
@@ -3944,6 +4023,8 @@ static void r8168_phy_power_down(struct rtl8169_private *tp)
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_32:
case RTL_GIGA_MAC_VER_33:
+ case RTL_GIGA_MAC_VER_40:
+ case RTL_GIGA_MAC_VER_41:
rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
break;
@@ -4005,6 +4086,11 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_33:
RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
break;
+ case RTL_GIGA_MAC_VER_40:
+ case RTL_GIGA_MAC_VER_41:
+ rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0x00000000,
+ 0xfc000000, ERIAR_EXGMAC);
+ break;
}
}
@@ -4022,6 +4108,11 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_33:
RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
break;
+ case RTL_GIGA_MAC_VER_40:
+ case RTL_GIGA_MAC_VER_41:
+ rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000,
+ 0x00000000, ERIAR_EXGMAC);
+ break;
}
r8168_phy_power_up(tp);
@@ -4058,6 +4149,7 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_30:
case RTL_GIGA_MAC_VER_37:
case RTL_GIGA_MAC_VER_39:
+ case RTL_GIGA_MAC_VER_43:
ops->down = r810x_pll_power_down;
ops->up = r810x_pll_power_up;
break;
@@ -4085,6 +4177,7 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_38:
case RTL_GIGA_MAC_VER_40:
case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
ops->down = r8168_pll_power_down;
ops->up = r8168_pll_power_up;
break;
@@ -4127,6 +4220,12 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_34:
RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
break;
+ case RTL_GIGA_MAC_VER_40:
+ case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
+ RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
+ break;
default:
RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST);
break;
@@ -4283,6 +4382,8 @@ static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
*/
case RTL_GIGA_MAC_VER_40:
case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
default:
ops->disable = NULL;
ops->enable = NULL;
@@ -4390,6 +4491,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
tp->mac_version == RTL_GIGA_MAC_VER_37 ||
tp->mac_version == RTL_GIGA_MAC_VER_40 ||
tp->mac_version == RTL_GIGA_MAC_VER_41 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_42 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_43 ||
tp->mac_version == RTL_GIGA_MAC_VER_38) {
RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
@@ -5105,6 +5208,8 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
+ RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+
rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x080002, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
@@ -5116,6 +5221,7 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+ rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f, ERIAR_EXGMAC);
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
@@ -5127,7 +5233,26 @@ static void rtl_hw_start_8168g_1(struct rtl8169_private *tp)
/* Adjust EEE LED frequency */
RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
- rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x02, ERIAR_EXGMAC);
+ rtl_w1w0_eri(tp, 0x2fc, ERIAR_MASK_0001, 0x01, 0x06, ERIAR_EXGMAC);
+ rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
+}
+
+static void rtl_hw_start_8168g_2(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ static const struct ephy_info e_info_8168g_2[] = {
+ { 0x00, 0x0000, 0x0008 },
+ { 0x0c, 0x3df0, 0x0200 },
+ { 0x19, 0xffff, 0xfc00 },
+ { 0x1e, 0xffff, 0x20eb }
+ };
+
+ rtl_hw_start_8168g_1(tp);
+
+ /* disable aspm and clock request before access ephy */
+ RTL_W8(Config2, RTL_R8(Config2) & ~ClkReqEn);
+ RTL_W8(Config5, RTL_R8(Config5) & ~ASPM_en);
+ rtl_ephy_init(tp, e_info_8168g_2, ARRAY_SIZE(e_info_8168g_2));
}
static void rtl_hw_start_8168(struct net_device *dev)
@@ -5155,10 +5280,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
rtl_set_rx_tx_desc_registers(tp, ioaddr);
- rtl_set_rx_mode(dev);
-
- RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
- (InterFrameGap << TxInterFrameGapShift));
+ rtl_set_rx_tx_config_registers(tp);
RTL_R8(IntrMask);
@@ -5235,6 +5357,9 @@ static void rtl_hw_start_8168(struct net_device *dev)
case RTL_GIGA_MAC_VER_41:
rtl_hw_start_8168g_1(tp);
break;
+ case RTL_GIGA_MAC_VER_42:
+ rtl_hw_start_8168g_2(tp);
+ break;
default:
printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
@@ -5242,9 +5367,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
break;
}
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(Cfg9346, Cfg9346_Lock);
+ rtl_set_rx_mode(dev);
RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
}
@@ -5402,6 +5529,17 @@ static void rtl_hw_start_8101(struct net_device *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
+
+ rtl_set_rx_max_size(ioaddr, rx_buf_sz);
+
+ tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ rtl_set_rx_tx_config_registers(tp);
+
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_07:
rtl_hw_start_8102e_1(tp);
@@ -5429,28 +5567,21 @@ static void rtl_hw_start_8101(struct net_device *dev)
case RTL_GIGA_MAC_VER_39:
rtl_hw_start_8106(tp);
break;
+ case RTL_GIGA_MAC_VER_43:
+ rtl_hw_start_8168g_2(tp);
+ break;
}
RTL_W8(Cfg9346, Cfg9346_Lock);
- RTL_W8(MaxTxPacketSize, TxPacketMax);
-
- rtl_set_rx_max_size(ioaddr, rx_buf_sz);
-
- tp->cp_cmd &= ~R810X_CPCMD_QUIRK_MASK;
- RTL_W16(CPlusCmd, tp->cp_cmd);
-
RTL_W16(IntrMitigate, 0x0000);
- rtl_set_rx_tx_desc_registers(tp, ioaddr);
-
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- rtl_set_rx_tx_config_registers(tp);
-
- RTL_R8(IntrMask);
rtl_set_rx_mode(dev);
+ RTL_R8(IntrMask);
+
RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
}
@@ -5765,6 +5896,14 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
goto err_stop_0;
}
+ /* 8168evl does not automatically pad to minimum length. */
+ if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 &&
+ skb->len < ETH_ZLEN)) {
+ if (skb_padto(skb, ETH_ZLEN))
+ goto err_update_stats;
+ skb_put(skb, ETH_ZLEN - skb->len);
+ }
+
if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
goto err_stop_0;
@@ -5836,6 +5975,7 @@ err_dma_1:
rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
err_dma_0:
dev_kfree_skb(skb);
+err_update_stats:
dev->stats.tx_dropped++;
return NETDEV_TX_OK;
@@ -6722,6 +6862,8 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_40:
case RTL_GIGA_MAC_VER_41:
+ case RTL_GIGA_MAC_VER_42:
+ case RTL_GIGA_MAC_VER_43:
rtl_hw_init_8168g(tp);
break;
@@ -6904,16 +7046,17 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* don't enable SG, IP_CSUM and TSO by default - it might not work
* properly for all devices */
dev->features |= NETIF_F_RXCSUM |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
- NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
NETIF_F_HIGHDMA;
if (tp->mac_version == RTL_GIGA_MAC_VER_05)
/* 8110SCd requires hardware Rx VLAN - disallow toggling */
- dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
+ dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
dev->hw_features |= NETIF_F_RXALL;
dev->hw_features |= NETIF_F_RXFCS;
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index 24c2305d7948..bed9841d728c 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -8,7 +8,8 @@ config SH_ETH
(CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \
- CPU_SUBTYPE_SH7757 || ARCH_R8A7740 || ARCH_R8A7779)
+ CPU_SUBTYPE_SH7757 || ARCH_R8A7740 || \
+ ARCH_R8A7778 || ARCH_R8A7779)
select CRC32
select NET_CORE
select MII
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index bf5e3cf97c4d..33dc6f2418f2 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -2,7 +2,8 @@
* SuperH Ethernet device driver
*
* Copyright (C) 2006-2012 Nobuhiro Iwamatsu
- * Copyright (C) 2008-2012 Renesas Solutions Corp.
+ * Copyright (C) 2008-2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Cogent Embedded, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -49,6 +50,269 @@
NETIF_MSG_RX_ERR| \
NETIF_MSG_TX_ERR)
+static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [EDSR] = 0x0000,
+ [EDMR] = 0x0400,
+ [EDTRR] = 0x0408,
+ [EDRRR] = 0x0410,
+ [EESR] = 0x0428,
+ [EESIPR] = 0x0430,
+ [TDLAR] = 0x0010,
+ [TDFAR] = 0x0014,
+ [TDFXR] = 0x0018,
+ [TDFFR] = 0x001c,
+ [RDLAR] = 0x0030,
+ [RDFAR] = 0x0034,
+ [RDFXR] = 0x0038,
+ [RDFFR] = 0x003c,
+ [TRSCER] = 0x0438,
+ [RMFCR] = 0x0440,
+ [TFTR] = 0x0448,
+ [FDR] = 0x0450,
+ [RMCR] = 0x0458,
+ [RPADIR] = 0x0460,
+ [FCFTR] = 0x0468,
+ [CSMR] = 0x04E4,
+
+ [ECMR] = 0x0500,
+ [ECSR] = 0x0510,
+ [ECSIPR] = 0x0518,
+ [PIR] = 0x0520,
+ [PSR] = 0x0528,
+ [PIPR] = 0x052c,
+ [RFLR] = 0x0508,
+ [APR] = 0x0554,
+ [MPR] = 0x0558,
+ [PFTCR] = 0x055c,
+ [PFRCR] = 0x0560,
+ [TPAUSER] = 0x0564,
+ [GECMR] = 0x05b0,
+ [BCULR] = 0x05b4,
+ [MAHR] = 0x05c0,
+ [MALR] = 0x05c8,
+ [TROCR] = 0x0700,
+ [CDCR] = 0x0708,
+ [LCCR] = 0x0710,
+ [CEFCR] = 0x0740,
+ [FRECR] = 0x0748,
+ [TSFRCR] = 0x0750,
+ [TLFRCR] = 0x0758,
+ [RFCR] = 0x0760,
+ [CERCR] = 0x0768,
+ [CEECR] = 0x0770,
+ [MAFCR] = 0x0778,
+ [RMII_MII] = 0x0790,
+
+ [ARSTR] = 0x0000,
+ [TSU_CTRST] = 0x0004,
+ [TSU_FWEN0] = 0x0010,
+ [TSU_FWEN1] = 0x0014,
+ [TSU_FCM] = 0x0018,
+ [TSU_BSYSL0] = 0x0020,
+ [TSU_BSYSL1] = 0x0024,
+ [TSU_PRISL0] = 0x0028,
+ [TSU_PRISL1] = 0x002c,
+ [TSU_FWSL0] = 0x0030,
+ [TSU_FWSL1] = 0x0034,
+ [TSU_FWSLC] = 0x0038,
+ [TSU_QTAG0] = 0x0040,
+ [TSU_QTAG1] = 0x0044,
+ [TSU_FWSR] = 0x0050,
+ [TSU_FWINMK] = 0x0054,
+ [TSU_ADQT0] = 0x0048,
+ [TSU_ADQT1] = 0x004c,
+ [TSU_VTAG0] = 0x0058,
+ [TSU_VTAG1] = 0x005c,
+ [TSU_ADSBSY] = 0x0060,
+ [TSU_TEN] = 0x0064,
+ [TSU_POST1] = 0x0070,
+ [TSU_POST2] = 0x0074,
+ [TSU_POST3] = 0x0078,
+ [TSU_POST4] = 0x007c,
+ [TSU_ADRH0] = 0x0100,
+ [TSU_ADRL0] = 0x0104,
+ [TSU_ADRH31] = 0x01f8,
+ [TSU_ADRL31] = 0x01fc,
+
+ [TXNLCR0] = 0x0080,
+ [TXALCR0] = 0x0084,
+ [RXNLCR0] = 0x0088,
+ [RXALCR0] = 0x008c,
+ [FWNLCR0] = 0x0090,
+ [FWALCR0] = 0x0094,
+ [TXNLCR1] = 0x00a0,
+ [TXALCR1] = 0x00a0,
+ [RXNLCR1] = 0x00a8,
+ [RXALCR1] = 0x00ac,
+ [FWNLCR1] = 0x00b0,
+ [FWALCR1] = 0x00b4,
+};
+
+static const u16 sh_eth_offset_fast_rcar[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [ECMR] = 0x0300,
+ [RFLR] = 0x0308,
+ [ECSR] = 0x0310,
+ [ECSIPR] = 0x0318,
+ [PIR] = 0x0320,
+ [PSR] = 0x0328,
+ [RDMLR] = 0x0340,
+ [IPGR] = 0x0350,
+ [APR] = 0x0354,
+ [MPR] = 0x0358,
+ [RFCF] = 0x0360,
+ [TPAUSER] = 0x0364,
+ [TPAUSECR] = 0x0368,
+ [MAHR] = 0x03c0,
+ [MALR] = 0x03c8,
+ [TROCR] = 0x03d0,
+ [CDCR] = 0x03d4,
+ [LCCR] = 0x03d8,
+ [CNDCR] = 0x03dc,
+ [CEFCR] = 0x03e4,
+ [FRECR] = 0x03e8,
+ [TSFRCR] = 0x03ec,
+ [TLFRCR] = 0x03f0,
+ [RFCR] = 0x03f4,
+ [MAFCR] = 0x03f8,
+
+ [EDMR] = 0x0200,
+ [EDTRR] = 0x0208,
+ [EDRRR] = 0x0210,
+ [TDLAR] = 0x0218,
+ [RDLAR] = 0x0220,
+ [EESR] = 0x0228,
+ [EESIPR] = 0x0230,
+ [TRSCER] = 0x0238,
+ [RMFCR] = 0x0240,
+ [TFTR] = 0x0248,
+ [FDR] = 0x0250,
+ [RMCR] = 0x0258,
+ [TFUCR] = 0x0264,
+ [RFOCR] = 0x0268,
+ [FCFTR] = 0x0270,
+ [TRIMD] = 0x027c,
+};
+
+static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [ECMR] = 0x0100,
+ [RFLR] = 0x0108,
+ [ECSR] = 0x0110,
+ [ECSIPR] = 0x0118,
+ [PIR] = 0x0120,
+ [PSR] = 0x0128,
+ [RDMLR] = 0x0140,
+ [IPGR] = 0x0150,
+ [APR] = 0x0154,
+ [MPR] = 0x0158,
+ [TPAUSER] = 0x0164,
+ [RFCF] = 0x0160,
+ [TPAUSECR] = 0x0168,
+ [BCFRR] = 0x016c,
+ [MAHR] = 0x01c0,
+ [MALR] = 0x01c8,
+ [TROCR] = 0x01d0,
+ [CDCR] = 0x01d4,
+ [LCCR] = 0x01d8,
+ [CNDCR] = 0x01dc,
+ [CEFCR] = 0x01e4,
+ [FRECR] = 0x01e8,
+ [TSFRCR] = 0x01ec,
+ [TLFRCR] = 0x01f0,
+ [RFCR] = 0x01f4,
+ [MAFCR] = 0x01f8,
+ [RTRATE] = 0x01fc,
+
+ [EDMR] = 0x0000,
+ [EDTRR] = 0x0008,
+ [EDRRR] = 0x0010,
+ [TDLAR] = 0x0018,
+ [RDLAR] = 0x0020,
+ [EESR] = 0x0028,
+ [EESIPR] = 0x0030,
+ [TRSCER] = 0x0038,
+ [RMFCR] = 0x0040,
+ [TFTR] = 0x0048,
+ [FDR] = 0x0050,
+ [RMCR] = 0x0058,
+ [TFUCR] = 0x0064,
+ [RFOCR] = 0x0068,
+ [FCFTR] = 0x0070,
+ [RPADIR] = 0x0078,
+ [TRIMD] = 0x007c,
+ [RBWAR] = 0x00c8,
+ [RDFAR] = 0x00cc,
+ [TBRAR] = 0x00d4,
+ [TDFAR] = 0x00d8,
+};
+
+static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
+ [ECMR] = 0x0160,
+ [ECSR] = 0x0164,
+ [ECSIPR] = 0x0168,
+ [PIR] = 0x016c,
+ [MAHR] = 0x0170,
+ [MALR] = 0x0174,
+ [RFLR] = 0x0178,
+ [PSR] = 0x017c,
+ [TROCR] = 0x0180,
+ [CDCR] = 0x0184,
+ [LCCR] = 0x0188,
+ [CNDCR] = 0x018c,
+ [CEFCR] = 0x0194,
+ [FRECR] = 0x0198,
+ [TSFRCR] = 0x019c,
+ [TLFRCR] = 0x01a0,
+ [RFCR] = 0x01a4,
+ [MAFCR] = 0x01a8,
+ [IPGR] = 0x01b4,
+ [APR] = 0x01b8,
+ [MPR] = 0x01bc,
+ [TPAUSER] = 0x01c4,
+ [BCFR] = 0x01cc,
+
+ [ARSTR] = 0x0000,
+ [TSU_CTRST] = 0x0004,
+ [TSU_FWEN0] = 0x0010,
+ [TSU_FWEN1] = 0x0014,
+ [TSU_FCM] = 0x0018,
+ [TSU_BSYSL0] = 0x0020,
+ [TSU_BSYSL1] = 0x0024,
+ [TSU_PRISL0] = 0x0028,
+ [TSU_PRISL1] = 0x002c,
+ [TSU_FWSL0] = 0x0030,
+ [TSU_FWSL1] = 0x0034,
+ [TSU_FWSLC] = 0x0038,
+ [TSU_QTAGM0] = 0x0040,
+ [TSU_QTAGM1] = 0x0044,
+ [TSU_ADQT0] = 0x0048,
+ [TSU_ADQT1] = 0x004c,
+ [TSU_FWSR] = 0x0050,
+ [TSU_FWINMK] = 0x0054,
+ [TSU_ADSBSY] = 0x0060,
+ [TSU_TEN] = 0x0064,
+ [TSU_POST1] = 0x0070,
+ [TSU_POST2] = 0x0074,
+ [TSU_POST3] = 0x0078,
+ [TSU_POST4] = 0x007c,
+
+ [TXNLCR0] = 0x0080,
+ [TXALCR0] = 0x0084,
+ [RXNLCR0] = 0x0088,
+ [RXALCR0] = 0x008c,
+ [FWNLCR0] = 0x0090,
+ [FWALCR0] = 0x0094,
+ [TXNLCR1] = 0x00a0,
+ [TXALCR1] = 0x00a0,
+ [RXNLCR1] = 0x00a8,
+ [RXALCR1] = 0x00ac,
+ [FWNLCR1] = 0x00b0,
+ [FWALCR1] = 0x00b4,
+
+ [TSU_ADRH0] = 0x0100,
+ [TSU_ADRL0] = 0x0104,
+ [TSU_ADRL31] = 0x01fc,
+};
+
#if defined(CONFIG_CPU_SUBTYPE_SH7734) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \
defined(CONFIG_ARCH_R8A7740)
@@ -78,7 +342,7 @@ static void sh_eth_select_mii(struct net_device *ndev)
#endif
/* There is CPU dependent code */
-#if defined(CONFIG_CPU_SUBTYPE_SH7724) || defined(CONFIG_ARCH_R8A7779)
+#if defined(CONFIG_ARCH_R8A7778) || defined(CONFIG_ARCH_R8A7779)
#define SH_ETH_RESET_DEFAULT 1
static void sh_eth_set_duplex(struct net_device *ndev)
{
@@ -93,18 +357,60 @@ static void sh_eth_set_duplex(struct net_device *ndev)
static void sh_eth_set_rate(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
- unsigned int bits = ECMR_RTM;
-#if defined(CONFIG_ARCH_R8A7779)
- bits |= ECMR_ELB;
-#endif
+ switch (mdp->speed) {
+ case 10: /* 10BASE */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_ELB, ECMR);
+ break;
+ case 100:/* 100BASE */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_ELB, ECMR);
+ break;
+ default:
+ break;
+ }
+}
+
+/* R8A7778/9 */
+static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+ .set_duplex = sh_eth_set_duplex,
+ .set_rate = sh_eth_set_rate,
+
+ .ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
+ .ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
+ .eesipr_value = 0x01ff009f,
+
+ .tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
+ .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
+ EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
+ .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
+
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .hw_swap = 1,
+};
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define SH_ETH_RESET_DEFAULT 1
+static void sh_eth_set_duplex(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+
+ if (mdp->duplex) /* Full */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
+ else /* Half */
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
+}
+
+static void sh_eth_set_rate(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
switch (mdp->speed) {
case 10: /* 10BASE */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~bits, ECMR);
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_RTM, ECMR);
break;
case 100:/* 100BASE */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | bits, ECMR);
+ sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_RTM, ECMR);
break;
default:
break;
@@ -592,7 +898,7 @@ static int sh_eth_check_reset(struct net_device *ndev)
cnt--;
}
if (cnt < 0) {
- printk(KERN_ERR "Device reset fail\n");
+ pr_err("Device reset fail\n");
ret = -ETIMEDOUT;
}
return ret;
@@ -908,11 +1214,8 @@ static int sh_eth_ring_init(struct net_device *ndev)
/* Allocate all Rx descriptors. */
rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma,
- GFP_KERNEL);
-
+ GFP_KERNEL);
if (!mdp->rx_ring) {
- dev_err(&ndev->dev, "Cannot allocate Rx Ring (size %d bytes)\n",
- rx_ringsize);
ret = -ENOMEM;
goto desc_ring_free;
}
@@ -922,10 +1225,8 @@ static int sh_eth_ring_init(struct net_device *ndev)
/* Allocate all Tx descriptors. */
tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma,
- GFP_KERNEL);
+ GFP_KERNEL);
if (!mdp->tx_ring) {
- dev_err(&ndev->dev, "Cannot allocate Tx Ring (size %d bytes)\n",
- tx_ringsize);
ret = -ENOMEM;
goto desc_ring_free;
}
@@ -1216,10 +1517,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
if (felic_stat & ECSR_LCHNG) {
/* Link Changed */
if (mdp->cd->no_psr || mdp->no_ether_link) {
- if (mdp->link == PHY_DOWN)
- link_stat = 0;
- else
- link_stat = PHY_ST_LINK;
+ goto ignore_link;
} else {
link_stat = (sh_eth_read(ndev, PSR));
if (mdp->ether_link_active_low)
@@ -1242,6 +1540,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
}
}
+ignore_link:
if (intr_status & EESR_TWB) {
/* Write buck end. unused write back interrupt */
if (intr_status & EESR_TABT) /* Transmit Abort int */
@@ -1326,12 +1625,18 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
struct sh_eth_private *mdp = netdev_priv(ndev);
struct sh_eth_cpu_data *cd = mdp->cd;
irqreturn_t ret = IRQ_NONE;
- u32 intr_status = 0;
+ unsigned long intr_status;
spin_lock(&mdp->lock);
- /* Get interrpt stat */
+ /* Get interrupt status */
intr_status = sh_eth_read(ndev, EESR);
+ /* Mask it with the interrupt mask, forcing ECI interrupt to be always
+ * enabled since it's the one that comes thru regardless of the mask,
+ * and we need to fully handle it in sh_eth_error() in order to quench
+ * it as it doesn't get cleared by just writing 1 to the ECI bit...
+ */
+ intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI;
/* Clear interrupt */
if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
@@ -1373,7 +1678,7 @@ static void sh_eth_adjust_link(struct net_device *ndev)
struct phy_device *phydev = mdp->phydev;
int new_state = 0;
- if (phydev->link != PHY_DOWN) {
+ if (phydev->link) {
if (phydev->duplex != mdp->duplex) {
new_state = 1;
mdp->duplex = phydev->duplex;
@@ -1387,17 +1692,21 @@ static void sh_eth_adjust_link(struct net_device *ndev)
if (mdp->cd->set_rate)
mdp->cd->set_rate(ndev);
}
- if (mdp->link == PHY_DOWN) {
+ if (!mdp->link) {
sh_eth_write(ndev,
(sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR);
new_state = 1;
mdp->link = phydev->link;
+ if (mdp->cd->no_psr || mdp->no_ether_link)
+ sh_eth_rcv_snd_enable(ndev);
}
} else if (mdp->link) {
new_state = 1;
- mdp->link = PHY_DOWN;
+ mdp->link = 0;
mdp->speed = 0;
mdp->duplex = -1;
+ if (mdp->cd->no_psr || mdp->no_ether_link)
+ sh_eth_rcv_snd_disable(ndev);
}
if (new_state && netif_msg_link(mdp))
@@ -1414,7 +1723,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
mdp->mii_bus->id , mdp->phy_id);
- mdp->link = PHY_DOWN;
+ mdp->link = 0;
mdp->speed = 0;
mdp->duplex = -1;
@@ -2139,7 +2448,8 @@ static int sh_eth_get_vtag_index(struct sh_eth_private *mdp)
return TSU_VTAG1;
}
-static int sh_eth_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
+static int sh_eth_vlan_rx_add_vid(struct net_device *ndev,
+ __be16 proto, u16 vid)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
int vtag_reg_index = sh_eth_get_vtag_index(mdp);
@@ -2169,7 +2479,8 @@ static int sh_eth_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
return 0;
}
-static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
+static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
+ __be16 proto, u16 vid)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
int vtag_reg_index = sh_eth_get_vtag_index(mdp);
@@ -2220,7 +2531,6 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)
/* MDIO bus release function */
static int sh_mdio_release(struct net_device *ndev)
{
- struct sh_eth_private *mdp = netdev_priv(ndev);
struct mii_bus *bus = dev_get_drvdata(&ndev->dev);
/* unregister mdio bus */
@@ -2229,15 +2539,9 @@ static int sh_mdio_release(struct net_device *ndev)
/* remove mdio bus info from net_device */
dev_set_drvdata(&ndev->dev, NULL);
- /* free interrupts memory */
- kfree(bus->irq);
-
/* free bitbang info */
free_mdio_bitbang(bus);
- /* free bitbang memory */
- kfree(mdp->bitbang);
-
return 0;
}
@@ -2250,7 +2554,8 @@ static int sh_mdio_init(struct net_device *ndev, int id,
struct sh_eth_private *mdp = netdev_priv(ndev);
/* create bit control struct for PHY */
- bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ bitbang = devm_kzalloc(&ndev->dev, sizeof(struct bb_info),
+ GFP_KERNEL);
if (!bitbang) {
ret = -ENOMEM;
goto out;
@@ -2259,18 +2564,17 @@ static int sh_mdio_init(struct net_device *ndev, int id,
/* bitbang init */
bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
bitbang->set_gate = pd->set_mdio_gate;
- bitbang->mdi_msk = 0x08;
- bitbang->mdo_msk = 0x04;
- bitbang->mmd_msk = 0x02;/* MMD */
- bitbang->mdc_msk = 0x01;
+ bitbang->mdi_msk = PIR_MDI;
+ bitbang->mdo_msk = PIR_MDO;
+ bitbang->mmd_msk = PIR_MMD;
+ bitbang->mdc_msk = PIR_MDC;
bitbang->ctrl.ops = &bb_ops;
/* MII controller setting */
- mdp->bitbang = bitbang;
mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
if (!mdp->mii_bus) {
ret = -ENOMEM;
- goto out_free_bitbang;
+ goto out;
}
/* Hook up MII support for ethtool */
@@ -2280,7 +2584,9 @@ static int sh_mdio_init(struct net_device *ndev, int id,
mdp->pdev->name, id);
/* PHY IRQ */
- mdp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ mdp->mii_bus->irq = devm_kzalloc(&ndev->dev,
+ sizeof(int) * PHY_MAX_ADDR,
+ GFP_KERNEL);
if (!mdp->mii_bus->irq) {
ret = -ENOMEM;
goto out_free_bus;
@@ -2292,21 +2598,15 @@ static int sh_mdio_init(struct net_device *ndev, int id,
/* register mdio bus */
ret = mdiobus_register(mdp->mii_bus);
if (ret)
- goto out_free_irq;
+ goto out_free_bus;
dev_set_drvdata(&ndev->dev, mdp->mii_bus);
return 0;
-out_free_irq:
- kfree(mdp->mii_bus->irq);
-
out_free_bus:
free_mdio_bitbang(mdp->mii_bus);
-out_free_bitbang:
- kfree(bitbang);
-
out:
return ret;
}
@@ -2319,6 +2619,9 @@ static const u16 *sh_eth_get_register_offset(int register_type)
case SH_ETH_REG_GIGABIT:
reg_offset = sh_eth_offset_gigabit;
break;
+ case SH_ETH_REG_FAST_RCAR:
+ reg_offset = sh_eth_offset_fast_rcar;
+ break;
case SH_ETH_REG_FAST_SH4:
reg_offset = sh_eth_offset_fast_sh4;
break;
@@ -2326,7 +2629,7 @@ static const u16 *sh_eth_get_register_offset(int register_type)
reg_offset = sh_eth_offset_fast_sh3_sh2;
break;
default:
- printk(KERN_ERR "Unknown register type (%d)\n", register_type);
+ pr_err("Unknown register type (%d)\n", register_type);
break;
}
@@ -2356,7 +2659,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
struct resource *res;
struct net_device *ndev = NULL;
struct sh_eth_private *mdp = NULL;
- struct sh_eth_plat_data *pd;
+ struct sh_eth_plat_data *pd = pdev->dev.platform_data;
/* get base addr */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2394,10 +2697,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp = netdev_priv(ndev);
mdp->num_tx_ring = TX_RING_SIZE;
mdp->num_rx_ring = RX_RING_SIZE;
- mdp->addr = ioremap(res->start, resource_size(res));
- if (mdp->addr == NULL) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "ioremap failed.\n");
+ mdp->addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mdp->addr)) {
+ ret = PTR_ERR(mdp->addr);
goto out_release;
}
@@ -2406,7 +2708,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_resume(&pdev->dev);
- pd = (struct sh_eth_plat_data *)(pdev->dev.platform_data);
/* get PHY ID */
mdp->phy_id = pd->phy;
mdp->phy_interface = pd->phy_interface;
@@ -2434,6 +2735,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
/* read and set MAC address */
read_mac_address(ndev, pd->mac_addr);
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ dev_warn(&pdev->dev,
+ "no valid MAC address supplied, using a random one.\n");
+ eth_hw_addr_random(ndev);
+ }
/* ioremap the TSU registers */
if (mdp->cd->tsu) {
@@ -2444,15 +2750,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
ret = -ENODEV;
goto out_release;
}
- mdp->tsu_addr = ioremap(rtsu->start,
- resource_size(rtsu));
- if (mdp->tsu_addr == NULL) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "TSU ioremap failed.\n");
+ mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu);
+ if (IS_ERR(mdp->tsu_addr)) {
+ ret = PTR_ERR(mdp->tsu_addr);
goto out_release;
}
mdp->port = devno % 2;
- ndev->features = NETIF_F_HW_VLAN_FILTER;
+ ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER;
}
/* initialize first or needed device */
@@ -2489,10 +2793,6 @@ out_unregister:
out_release:
/* net_dev free */
- if (mdp && mdp->addr)
- iounmap(mdp->addr);
- if (mdp && mdp->tsu_addr)
- iounmap(mdp->tsu_addr);
if (ndev)
free_netdev(ndev);
@@ -2503,14 +2803,10 @@ out:
static int sh_eth_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
- struct sh_eth_private *mdp = netdev_priv(ndev);
- if (mdp->cd->tsu)
- iounmap(mdp->tsu_addr);
sh_mdio_release(ndev);
unregister_netdev(ndev);
pm_runtime_disable(&pdev->dev);
- iounmap(mdp->addr);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index e6655678458e..1ddc9f235bcb 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -156,225 +156,6 @@ enum {
SH_ETH_MAX_REGISTER_OFFSET,
};
-static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = {
- [EDSR] = 0x0000,
- [EDMR] = 0x0400,
- [EDTRR] = 0x0408,
- [EDRRR] = 0x0410,
- [EESR] = 0x0428,
- [EESIPR] = 0x0430,
- [TDLAR] = 0x0010,
- [TDFAR] = 0x0014,
- [TDFXR] = 0x0018,
- [TDFFR] = 0x001c,
- [RDLAR] = 0x0030,
- [RDFAR] = 0x0034,
- [RDFXR] = 0x0038,
- [RDFFR] = 0x003c,
- [TRSCER] = 0x0438,
- [RMFCR] = 0x0440,
- [TFTR] = 0x0448,
- [FDR] = 0x0450,
- [RMCR] = 0x0458,
- [RPADIR] = 0x0460,
- [FCFTR] = 0x0468,
- [CSMR] = 0x04E4,
-
- [ECMR] = 0x0500,
- [ECSR] = 0x0510,
- [ECSIPR] = 0x0518,
- [PIR] = 0x0520,
- [PSR] = 0x0528,
- [PIPR] = 0x052c,
- [RFLR] = 0x0508,
- [APR] = 0x0554,
- [MPR] = 0x0558,
- [PFTCR] = 0x055c,
- [PFRCR] = 0x0560,
- [TPAUSER] = 0x0564,
- [GECMR] = 0x05b0,
- [BCULR] = 0x05b4,
- [MAHR] = 0x05c0,
- [MALR] = 0x05c8,
- [TROCR] = 0x0700,
- [CDCR] = 0x0708,
- [LCCR] = 0x0710,
- [CEFCR] = 0x0740,
- [FRECR] = 0x0748,
- [TSFRCR] = 0x0750,
- [TLFRCR] = 0x0758,
- [RFCR] = 0x0760,
- [CERCR] = 0x0768,
- [CEECR] = 0x0770,
- [MAFCR] = 0x0778,
- [RMII_MII] = 0x0790,
-
- [ARSTR] = 0x0000,
- [TSU_CTRST] = 0x0004,
- [TSU_FWEN0] = 0x0010,
- [TSU_FWEN1] = 0x0014,
- [TSU_FCM] = 0x0018,
- [TSU_BSYSL0] = 0x0020,
- [TSU_BSYSL1] = 0x0024,
- [TSU_PRISL0] = 0x0028,
- [TSU_PRISL1] = 0x002c,
- [TSU_FWSL0] = 0x0030,
- [TSU_FWSL1] = 0x0034,
- [TSU_FWSLC] = 0x0038,
- [TSU_QTAG0] = 0x0040,
- [TSU_QTAG1] = 0x0044,
- [TSU_FWSR] = 0x0050,
- [TSU_FWINMK] = 0x0054,
- [TSU_ADQT0] = 0x0048,
- [TSU_ADQT1] = 0x004c,
- [TSU_VTAG0] = 0x0058,
- [TSU_VTAG1] = 0x005c,
- [TSU_ADSBSY] = 0x0060,
- [TSU_TEN] = 0x0064,
- [TSU_POST1] = 0x0070,
- [TSU_POST2] = 0x0074,
- [TSU_POST3] = 0x0078,
- [TSU_POST4] = 0x007c,
- [TSU_ADRH0] = 0x0100,
- [TSU_ADRL0] = 0x0104,
- [TSU_ADRH31] = 0x01f8,
- [TSU_ADRL31] = 0x01fc,
-
- [TXNLCR0] = 0x0080,
- [TXALCR0] = 0x0084,
- [RXNLCR0] = 0x0088,
- [RXALCR0] = 0x008c,
- [FWNLCR0] = 0x0090,
- [FWALCR0] = 0x0094,
- [TXNLCR1] = 0x00a0,
- [TXALCR1] = 0x00a0,
- [RXNLCR1] = 0x00a8,
- [RXALCR1] = 0x00ac,
- [FWNLCR1] = 0x00b0,
- [FWALCR1] = 0x00b4,
-};
-
-static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
- [ECMR] = 0x0100,
- [RFLR] = 0x0108,
- [ECSR] = 0x0110,
- [ECSIPR] = 0x0118,
- [PIR] = 0x0120,
- [PSR] = 0x0128,
- [RDMLR] = 0x0140,
- [IPGR] = 0x0150,
- [APR] = 0x0154,
- [MPR] = 0x0158,
- [TPAUSER] = 0x0164,
- [RFCF] = 0x0160,
- [TPAUSECR] = 0x0168,
- [BCFRR] = 0x016c,
- [MAHR] = 0x01c0,
- [MALR] = 0x01c8,
- [TROCR] = 0x01d0,
- [CDCR] = 0x01d4,
- [LCCR] = 0x01d8,
- [CNDCR] = 0x01dc,
- [CEFCR] = 0x01e4,
- [FRECR] = 0x01e8,
- [TSFRCR] = 0x01ec,
- [TLFRCR] = 0x01f0,
- [RFCR] = 0x01f4,
- [MAFCR] = 0x01f8,
- [RTRATE] = 0x01fc,
-
- [EDMR] = 0x0000,
- [EDTRR] = 0x0008,
- [EDRRR] = 0x0010,
- [TDLAR] = 0x0018,
- [RDLAR] = 0x0020,
- [EESR] = 0x0028,
- [EESIPR] = 0x0030,
- [TRSCER] = 0x0038,
- [RMFCR] = 0x0040,
- [TFTR] = 0x0048,
- [FDR] = 0x0050,
- [RMCR] = 0x0058,
- [TFUCR] = 0x0064,
- [RFOCR] = 0x0068,
- [FCFTR] = 0x0070,
- [RPADIR] = 0x0078,
- [TRIMD] = 0x007c,
- [RBWAR] = 0x00c8,
- [RDFAR] = 0x00cc,
- [TBRAR] = 0x00d4,
- [TDFAR] = 0x00d8,
-};
-
-static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
- [ECMR] = 0x0160,
- [ECSR] = 0x0164,
- [ECSIPR] = 0x0168,
- [PIR] = 0x016c,
- [MAHR] = 0x0170,
- [MALR] = 0x0174,
- [RFLR] = 0x0178,
- [PSR] = 0x017c,
- [TROCR] = 0x0180,
- [CDCR] = 0x0184,
- [LCCR] = 0x0188,
- [CNDCR] = 0x018c,
- [CEFCR] = 0x0194,
- [FRECR] = 0x0198,
- [TSFRCR] = 0x019c,
- [TLFRCR] = 0x01a0,
- [RFCR] = 0x01a4,
- [MAFCR] = 0x01a8,
- [IPGR] = 0x01b4,
- [APR] = 0x01b8,
- [MPR] = 0x01bc,
- [TPAUSER] = 0x01c4,
- [BCFR] = 0x01cc,
-
- [ARSTR] = 0x0000,
- [TSU_CTRST] = 0x0004,
- [TSU_FWEN0] = 0x0010,
- [TSU_FWEN1] = 0x0014,
- [TSU_FCM] = 0x0018,
- [TSU_BSYSL0] = 0x0020,
- [TSU_BSYSL1] = 0x0024,
- [TSU_PRISL0] = 0x0028,
- [TSU_PRISL1] = 0x002c,
- [TSU_FWSL0] = 0x0030,
- [TSU_FWSL1] = 0x0034,
- [TSU_FWSLC] = 0x0038,
- [TSU_QTAGM0] = 0x0040,
- [TSU_QTAGM1] = 0x0044,
- [TSU_ADQT0] = 0x0048,
- [TSU_ADQT1] = 0x004c,
- [TSU_FWSR] = 0x0050,
- [TSU_FWINMK] = 0x0054,
- [TSU_ADSBSY] = 0x0060,
- [TSU_TEN] = 0x0064,
- [TSU_POST1] = 0x0070,
- [TSU_POST2] = 0x0074,
- [TSU_POST3] = 0x0078,
- [TSU_POST4] = 0x007c,
-
- [TXNLCR0] = 0x0080,
- [TXALCR0] = 0x0084,
- [RXNLCR0] = 0x0088,
- [RXALCR0] = 0x008c,
- [FWNLCR0] = 0x0090,
- [FWALCR0] = 0x0094,
- [TXNLCR1] = 0x00a0,
- [TXALCR1] = 0x00a0,
- [RXNLCR1] = 0x00a8,
- [RXALCR1] = 0x00ac,
- [FWNLCR1] = 0x00b0,
- [FWALCR1] = 0x00b4,
-
- [TSU_ADRH0] = 0x0100,
- [TSU_ADRL0] = 0x0104,
- [TSU_ADRL31] = 0x01fc,
-
-};
-
/* Driver's parameters */
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
#define SH4_SKB_RX_ALIGN 32
@@ -705,7 +486,6 @@ struct sh_eth_private {
const u16 *reg_offset;
void __iomem *addr;
void __iomem *tsu_addr;
- struct bb_info *bitbang;
u32 num_rx_ring;
u32 num_tx_ring;
dma_addr_t rx_desc_dma;
@@ -723,7 +503,7 @@ struct sh_eth_private {
u32 phy_id; /* PHY ID */
struct mii_bus *mii_bus; /* MDIO bus control */
struct phy_device *phydev; /* PHY device control */
- enum phy_state link;
+ int link;
phy_interface_t phy_interface;
int msg_enable;
int speed;
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 21683e2b1ff4..b6739afeaca1 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -998,6 +998,7 @@ static int s6gmac_probe(struct platform_device *pdev)
mb = mdiobus_alloc();
if (!mb) {
printk(KERN_ERR DRV_PRMT "error allocating mii bus\n");
+ res = -ENOMEM;
goto errmii;
}
mb->name = "s6gmac_mii";
@@ -1053,20 +1054,7 @@ static struct platform_driver s6gmac_driver = {
},
};
-static int __init s6gmac_init(void)
-{
- printk(KERN_INFO DRV_PRMT "S6 GMAC ethernet driver\n");
- return platform_driver_register(&s6gmac_driver);
-}
-
-
-static void __exit s6gmac_exit(void)
-{
- platform_driver_unregister(&s6gmac_driver);
-}
-
-module_init(s6gmac_init);
-module_exit(s6gmac_exit);
+module_platform_driver(s6gmac_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
diff --git a/drivers/net/ethernet/seeq/ether3.c b/drivers/net/ethernet/seeq/ether3.c
index 3aca57853ed4..bdac936a68bc 100644
--- a/drivers/net/ethernet/seeq/ether3.c
+++ b/drivers/net/ethernet/seeq/ether3.c
@@ -651,8 +651,11 @@ if (next_ptr < RX_START || next_ptr >= RX_END) {
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
received ++;
- } else
- goto dropping;
+ } else {
+ ether3_outw(next_ptr >> 8, REG_RECVEND);
+ dev->stats.rx_dropped++;
+ goto done;
+ }
} else {
struct net_device_stats *stats = &dev->stats;
ether3_outw(next_ptr >> 8, REG_RECVEND);
@@ -679,21 +682,6 @@ done:
}
return maxcnt;
-
-dropping:{
- static unsigned long last_warned;
-
- ether3_outw(next_ptr >> 8, REG_RECVEND);
- /*
- * Don't print this message too many times...
- */
- if (time_after(jiffies, last_warned + 10 * HZ)) {
- last_warned = jiffies;
- printk("%s: memory squeeze, dropping packet.\n", dev->name);
- }
- dev->stats.rx_dropped++;
- goto done;
- }
}
/*
diff --git a/drivers/net/ethernet/seeq/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c
index 0fde9ca28269..0ad5694b41f8 100644
--- a/drivers/net/ethernet/seeq/sgiseeq.c
+++ b/drivers/net/ethernet/seeq/sgiseeq.c
@@ -381,8 +381,6 @@ memory_squeeze:
dev->stats.rx_packets++;
dev->stats.rx_bytes += len;
} else {
- printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
- dev->name);
dev->stats.rx_dropped++;
}
} else {
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 435b4f1e3488..4136ccc4a954 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -24,7 +24,7 @@ config SFC_MCDI_MON
bool "Solarflare SFC9000-family hwmon support"
depends on SFC && HWMON && !(SFC=y && HWMON=m)
default y
- ----help---
+ ---help---
This exposes the on-board firmware-managed sensors as a
hardware monitor device.
config SFC_SRIOV
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 0bc00991d310..01b99206139a 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -22,6 +22,7 @@
#include <linux/topology.h>
#include <linux/gfp.h>
#include <linux/cpu_rmap.h>
+#include <linux/aer.h>
#include "net_driver.h"
#include "efx.h"
#include "nic.h"
@@ -71,21 +72,21 @@ const char *const efx_loopback_mode_names[] = {
const unsigned int efx_reset_type_max = RESET_TYPE_MAX;
const char *const efx_reset_type_names[] = {
- [RESET_TYPE_INVISIBLE] = "INVISIBLE",
- [RESET_TYPE_ALL] = "ALL",
- [RESET_TYPE_WORLD] = "WORLD",
- [RESET_TYPE_DISABLE] = "DISABLE",
- [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG",
- [RESET_TYPE_INT_ERROR] = "INT_ERROR",
- [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY",
- [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
- [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
- [RESET_TYPE_TX_SKIP] = "TX_SKIP",
- [RESET_TYPE_MC_FAILURE] = "MC_FAILURE",
+ [RESET_TYPE_INVISIBLE] = "INVISIBLE",
+ [RESET_TYPE_ALL] = "ALL",
+ [RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL",
+ [RESET_TYPE_WORLD] = "WORLD",
+ [RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE",
+ [RESET_TYPE_DISABLE] = "DISABLE",
+ [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG",
+ [RESET_TYPE_INT_ERROR] = "INT_ERROR",
+ [RESET_TYPE_RX_RECOVERY] = "RX_RECOVERY",
+ [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH",
+ [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH",
+ [RESET_TYPE_TX_SKIP] = "TX_SKIP",
+ [RESET_TYPE_MC_FAILURE] = "MC_FAILURE",
};
-#define EFX_MAX_MTU (9 * 1024)
-
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
* queued onto this work queue. This is not a per-nic work queue, because
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
@@ -117,9 +118,12 @@ MODULE_PARM_DESC(separate_tx_channels,
static int napi_weight = 64;
/* This is the time (in jiffies) between invocations of the hardware
- * monitor. On Falcon-based NICs, this will:
+ * monitor.
+ * On Falcon-based NICs, this will:
* - Check the on-board hardware monitor;
* - Poll the link state and reconfigure the hardware as necessary.
+ * On Siena-based NICs for power systems with EEH support, this will give EEH a
+ * chance to start.
*/
static unsigned int efx_monitor_interval = 1 * HZ;
@@ -203,13 +207,14 @@ static void efx_stop_all(struct efx_nic *efx);
#define EFX_ASSERT_RESET_SERIALISED(efx) \
do { \
if ((efx->state == STATE_READY) || \
+ (efx->state == STATE_RECOVERY) || \
(efx->state == STATE_DISABLED)) \
ASSERT_RTNL(); \
} while (0)
static int efx_check_disabled(struct efx_nic *efx)
{
- if (efx->state == STATE_DISABLED) {
+ if (efx->state == STATE_DISABLED || efx->state == STATE_RECOVERY) {
netif_err(efx, drv, efx->net_dev,
"device is disabled due to earlier errors\n");
return -EIO;
@@ -242,15 +247,9 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
struct efx_rx_queue *rx_queue =
efx_channel_get_rx_queue(channel);
- /* Deliver last RX packet. */
- if (channel->rx_pkt) {
- __efx_rx_packet(channel, channel->rx_pkt);
- channel->rx_pkt = NULL;
- }
- if (rx_queue->enabled) {
- efx_rx_strategy(channel);
+ efx_rx_flush_packet(channel);
+ if (rx_queue->enabled)
efx_fast_push_rx_descriptors(rx_queue);
- }
}
return spent;
@@ -625,20 +624,51 @@ fail:
*/
static void efx_start_datapath(struct efx_nic *efx)
{
+ bool old_rx_scatter = efx->rx_scatter;
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
struct efx_channel *channel;
+ size_t rx_buf_len;
/* Calculate the rx buffer allocation parameters required to
* support the current MTU, including padding for header
* alignment and overruns.
*/
- efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
- EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
- efx->type->rx_buffer_hash_size +
- efx->type->rx_buffer_padding);
- efx->rx_buffer_order = get_order(efx->rx_buffer_len +
- sizeof(struct efx_rx_page_state));
+ efx->rx_dma_len = (efx->type->rx_buffer_hash_size +
+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_padding);
+ rx_buf_len = (sizeof(struct efx_rx_page_state) +
+ EFX_PAGE_IP_ALIGN + efx->rx_dma_len);
+ if (rx_buf_len <= PAGE_SIZE) {
+ efx->rx_scatter = false;
+ efx->rx_buffer_order = 0;
+ } else if (efx->type->can_rx_scatter) {
+ BUILD_BUG_ON(sizeof(struct efx_rx_page_state) +
+ EFX_PAGE_IP_ALIGN + EFX_RX_USR_BUF_SIZE >
+ PAGE_SIZE / 2);
+ efx->rx_scatter = true;
+ efx->rx_dma_len = EFX_RX_USR_BUF_SIZE;
+ efx->rx_buffer_order = 0;
+ } else {
+ efx->rx_scatter = false;
+ efx->rx_buffer_order = get_order(rx_buf_len);
+ }
+
+ efx_rx_config_page_split(efx);
+ if (efx->rx_buffer_order)
+ netif_dbg(efx, drv, efx->net_dev,
+ "RX buf len=%u; page order=%u batch=%u\n",
+ efx->rx_dma_len, efx->rx_buffer_order,
+ efx->rx_pages_per_batch);
+ else
+ netif_dbg(efx, drv, efx->net_dev,
+ "RX buf len=%u step=%u bpp=%u; page batch=%u\n",
+ efx->rx_dma_len, efx->rx_page_buf_step,
+ efx->rx_bufs_per_page, efx->rx_pages_per_batch);
+
+ /* RX filters also have scatter-enabled flags */
+ if (efx->rx_scatter != old_rx_scatter)
+ efx_filter_update_rx_scatter(efx);
/* We must keep at least one descriptor in a TX ring empty.
* We could avoid this when the queue size does not exactly
@@ -655,16 +685,12 @@ static void efx_start_datapath(struct efx_nic *efx)
efx_for_each_channel_tx_queue(tx_queue, channel)
efx_init_tx_queue(tx_queue);
- /* The rx buffer allocation strategy is MTU dependent */
- efx_rx_strategy(channel);
-
efx_for_each_channel_rx_queue(rx_queue, channel) {
efx_init_rx_queue(rx_queue);
efx_nic_generate_fill_event(rx_queue);
}
- WARN_ON(channel->rx_pkt != NULL);
- efx_rx_strategy(channel);
+ WARN_ON(channel->rx_pkt_n_frags);
}
if (netif_device_present(efx->net_dev))
@@ -683,7 +709,7 @@ static void efx_stop_datapath(struct efx_nic *efx)
BUG_ON(efx->port_enabled);
/* Only perform flush if dma is enabled */
- if (dev->is_busmaster) {
+ if (dev->is_busmaster && efx->state != STATE_RECOVERY) {
rc = efx_nic_flush_queues(efx);
if (rc && EFX_WORKAROUND_7803(efx)) {
@@ -1596,13 +1622,15 @@ static void efx_start_all(struct efx_nic *efx)
efx_start_port(efx);
efx_start_datapath(efx);
- /* Start the hardware monitor if there is one. Otherwise (we're link
- * event driven), we have to poll the PHY because after an event queue
- * flush, we could have a missed a link state change */
- if (efx->type->monitor != NULL) {
+ /* Start the hardware monitor if there is one */
+ if (efx->type->monitor != NULL)
queue_delayed_work(efx->workqueue, &efx->monitor_work,
efx_monitor_interval);
- } else {
+
+ /* If link state detection is normally event-driven, we have
+ * to poll now because we could have missed a change
+ */
+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) {
mutex_lock(&efx->mac_lock);
if (efx->phy_op->poll(efx))
efx_link_status_changed(efx);
@@ -2309,7 +2337,9 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
out:
/* Leave device stopped if necessary */
- disabled = rc || method == RESET_TYPE_DISABLE;
+ disabled = rc ||
+ method == RESET_TYPE_DISABLE ||
+ method == RESET_TYPE_RECOVER_OR_DISABLE;
rc2 = efx_reset_up(efx, method, !disabled);
if (rc2) {
disabled = true;
@@ -2328,13 +2358,48 @@ out:
return rc;
}
+/* Try recovery mechanisms.
+ * For now only EEH is supported.
+ * Returns 0 if the recovery mechanisms are unsuccessful.
+ * Returns a non-zero value otherwise.
+ */
+static int efx_try_recovery(struct efx_nic *efx)
+{
+#ifdef CONFIG_EEH
+ /* A PCI error can occur and not be seen by EEH because nothing
+ * happens on the PCI bus. In this case the driver may fail and
+ * schedule a 'recover or reset', leading to this recovery handler.
+ * Manually call the eeh failure check function.
+ */
+ struct eeh_dev *eehdev =
+ of_node_to_eeh_dev(pci_device_to_OF_node(efx->pci_dev));
+
+ if (eeh_dev_check_failure(eehdev)) {
+ /* The EEH mechanisms will handle the error and reset the
+ * device if necessary.
+ */
+ return 1;
+ }
+#endif
+ return 0;
+}
+
/* The worker thread exists so that code that cannot sleep can
* schedule a reset for later.
*/
static void efx_reset_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
- unsigned long pending = ACCESS_ONCE(efx->reset_pending);
+ unsigned long pending;
+ enum reset_type method;
+
+ pending = ACCESS_ONCE(efx->reset_pending);
+ method = fls(pending) - 1;
+
+ if ((method == RESET_TYPE_RECOVER_OR_DISABLE ||
+ method == RESET_TYPE_RECOVER_OR_ALL) &&
+ efx_try_recovery(efx))
+ return;
if (!pending)
return;
@@ -2346,7 +2411,7 @@ static void efx_reset_work(struct work_struct *data)
* it cannot change again.
*/
if (efx->state == STATE_READY)
- (void)efx_reset(efx, fls(pending) - 1);
+ (void)efx_reset(efx, method);
rtnl_unlock();
}
@@ -2355,11 +2420,20 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
{
enum reset_type method;
+ if (efx->state == STATE_RECOVERY) {
+ netif_dbg(efx, drv, efx->net_dev,
+ "recovering: skip scheduling %s reset\n",
+ RESET_TYPE(type));
+ return;
+ }
+
switch (type) {
case RESET_TYPE_INVISIBLE:
case RESET_TYPE_ALL:
+ case RESET_TYPE_RECOVER_OR_ALL:
case RESET_TYPE_WORLD:
case RESET_TYPE_DISABLE:
+ case RESET_TYPE_RECOVER_OR_DISABLE:
method = type;
netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
RESET_TYPE(method));
@@ -2569,6 +2643,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
efx_fini_struct(efx);
pci_set_drvdata(pci_dev, NULL);
free_netdev(efx->net_dev);
+
+ pci_disable_pcie_error_reporting(pci_dev);
};
/* NIC VPD information
@@ -2741,6 +2817,11 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
netif_warn(efx, probe, efx->net_dev,
"failed to create MTDs (%d)\n", rc);
+ rc = pci_enable_pcie_error_reporting(pci_dev);
+ if (rc && rc != -EINVAL)
+ netif_warn(efx, probe, efx->net_dev,
+ "pci_enable_pcie_error_reporting failed (%d)\n", rc);
+
return 0;
fail4:
@@ -2865,12 +2946,112 @@ static const struct dev_pm_ops efx_pm_ops = {
.restore = efx_pm_resume,
};
+/* A PCI error affecting this device was detected.
+ * At this point MMIO and DMA may be disabled.
+ * Stop the software path and request a slot reset.
+ */
+static pci_ers_result_t efx_io_error_detected(struct pci_dev *pdev,
+ enum pci_channel_state state)
+{
+ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
+ struct efx_nic *efx = pci_get_drvdata(pdev);
+
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ rtnl_lock();
+
+ if (efx->state != STATE_DISABLED) {
+ efx->state = STATE_RECOVERY;
+ efx->reset_pending = 0;
+
+ efx_device_detach_sync(efx);
+
+ efx_stop_all(efx);
+ efx_stop_interrupts(efx, false);
+
+ status = PCI_ERS_RESULT_NEED_RESET;
+ } else {
+ /* If the interface is disabled we don't want to do anything
+ * with it.
+ */
+ status = PCI_ERS_RESULT_RECOVERED;
+ }
+
+ rtnl_unlock();
+
+ pci_disable_device(pdev);
+
+ return status;
+}
+
+/* Fake a successfull reset, which will be performed later in efx_io_resume. */
+static pci_ers_result_t efx_io_slot_reset(struct pci_dev *pdev)
+{
+ struct efx_nic *efx = pci_get_drvdata(pdev);
+ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
+ int rc;
+
+ if (pci_enable_device(pdev)) {
+ netif_err(efx, hw, efx->net_dev,
+ "Cannot re-enable PCI device after reset.\n");
+ status = PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ rc = pci_cleanup_aer_uncorrect_error_status(pdev);
+ if (rc) {
+ netif_err(efx, hw, efx->net_dev,
+ "pci_cleanup_aer_uncorrect_error_status failed (%d)\n", rc);
+ /* Non-fatal error. Continue. */
+ }
+
+ return status;
+}
+
+/* Perform the actual reset and resume I/O operations. */
+static void efx_io_resume(struct pci_dev *pdev)
+{
+ struct efx_nic *efx = pci_get_drvdata(pdev);
+ int rc;
+
+ rtnl_lock();
+
+ if (efx->state == STATE_DISABLED)
+ goto out;
+
+ rc = efx_reset(efx, RESET_TYPE_ALL);
+ if (rc) {
+ netif_err(efx, hw, efx->net_dev,
+ "efx_reset failed after PCI error (%d)\n", rc);
+ } else {
+ efx->state = STATE_READY;
+ netif_dbg(efx, hw, efx->net_dev,
+ "Done resetting and resuming IO after PCI error.\n");
+ }
+
+out:
+ rtnl_unlock();
+}
+
+/* For simplicity and reliability, we always require a slot reset and try to
+ * reset the hardware when a pci error affecting the device is detected.
+ * We leave both the link_reset and mmio_enabled callback unimplemented:
+ * with our request for slot reset the mmio_enabled callback will never be
+ * called, and the link_reset callback is not used by AER or EEH mechanisms.
+ */
+static struct pci_error_handlers efx_err_handlers = {
+ .error_detected = efx_io_error_detected,
+ .slot_reset = efx_io_slot_reset,
+ .resume = efx_io_resume,
+};
+
static struct pci_driver efx_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = efx_pci_table,
.probe = efx_pci_probe,
.remove = efx_pci_remove,
.driver.pm = &efx_pm_ops,
+ .err_handler = &efx_err_handlers,
};
/**************************************************************************
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index d2f790df6dcb..8372da239b43 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -33,17 +33,22 @@ extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
/* RX */
+extern void efx_rx_config_page_split(struct efx_nic *efx);
extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
-extern void efx_rx_strategy(struct efx_channel *channel);
extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
extern void efx_rx_slow_fill(unsigned long context);
-extern void __efx_rx_packet(struct efx_channel *channel,
- struct efx_rx_buffer *rx_buf);
-extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+extern void __efx_rx_packet(struct efx_channel *channel);
+extern void efx_rx_packet(struct efx_rx_queue *rx_queue,
+ unsigned int index, unsigned int n_frags,
unsigned int len, u16 flags);
+static inline void efx_rx_flush_packet(struct efx_channel *channel)
+{
+ if (channel->rx_pkt_n_frags)
+ __efx_rx_packet(channel);
+}
extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_MAX_DMAQ_SIZE 4096UL
@@ -67,6 +72,7 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
extern int efx_probe_filters(struct efx_nic *efx);
extern void efx_restore_filters(struct efx_nic *efx);
extern void efx_remove_filters(struct efx_nic *efx);
+extern void efx_filter_update_rx_scatter(struct efx_nic *efx);
extern s32 efx_filter_insert_filter(struct efx_nic *efx,
struct efx_filter_spec *spec,
bool replace);
diff --git a/drivers/net/ethernet/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h
index 182dbe2cc6e4..ab8fb5889e55 100644
--- a/drivers/net/ethernet/sfc/enum.h
+++ b/drivers/net/ethernet/sfc/enum.h
@@ -137,8 +137,12 @@ enum efx_loopback_mode {
* Reset methods are numbered in order of increasing scope.
*
* @RESET_TYPE_INVISIBLE: Reset datapath and MAC (Falcon only)
+ * @RESET_TYPE_RECOVER_OR_ALL: Try to recover. Apply RESET_TYPE_ALL
+ * if unsuccessful.
* @RESET_TYPE_ALL: Reset datapath, MAC and PHY
* @RESET_TYPE_WORLD: Reset as much as possible
+ * @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if
+ * unsuccessful.
* @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled
* @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog
* @RESET_TYPE_INT_ERROR: reset due to internal error
@@ -150,9 +154,11 @@ enum efx_loopback_mode {
*/
enum reset_type {
RESET_TYPE_INVISIBLE = 0,
- RESET_TYPE_ALL = 1,
- RESET_TYPE_WORLD = 2,
- RESET_TYPE_DISABLE = 3,
+ RESET_TYPE_RECOVER_OR_ALL = 1,
+ RESET_TYPE_ALL = 2,
+ RESET_TYPE_WORLD = 3,
+ RESET_TYPE_RECOVER_OR_DISABLE = 4,
+ RESET_TYPE_DISABLE = 5,
RESET_TYPE_MAX_METHOD,
RESET_TYPE_TX_WATCHDOG,
RESET_TYPE_INT_ERROR,
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 8e61cd06f66a..6e768175e7e0 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -154,6 +154,7 @@ static const struct efx_ethtool_stat efx_ethtool_stats[] = {
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_nodesc_trunc),
};
/* Number of ethtool statistics */
@@ -978,7 +979,8 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
rule->m_ext.data[1]))
return -EINVAL;
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, 0,
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
+ efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
(rule->ring_cookie == RX_CLS_FLOW_DISC) ?
0xfff : rule->ring_cookie);
diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c
index 49bcd196e10d..4486102fa9b3 100644
--- a/drivers/net/ethernet/sfc/falcon.c
+++ b/drivers/net/ethernet/sfc/falcon.c
@@ -1546,10 +1546,6 @@ static int falcon_probe_nic(struct efx_nic *efx)
static void falcon_init_rx_cfg(struct efx_nic *efx)
{
- /* Prior to Siena the RX DMA engine will split each frame at
- * intervals of RX_USR_BUF_SIZE (32-byte units). We set it to
- * be so large that that never happens. */
- const unsigned huge_buf_size = (3 * 4096) >> 5;
/* RX control FIFO thresholds (32 entries) */
const unsigned ctrl_xon_thr = 20;
const unsigned ctrl_xoff_thr = 25;
@@ -1557,10 +1553,15 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
efx_reado(efx, &reg, FR_AZ_RX_CFG);
if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
- /* Data FIFO size is 5.5K */
+ /* Data FIFO size is 5.5K. The RX DMA engine only
+ * supports scattering for user-mode queues, but will
+ * split DMA writes at intervals of RX_USR_BUF_SIZE
+ * (32-byte units) even for kernel-mode queues. We
+ * set it to be so large that that never happens.
+ */
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_USR_BUF_SIZE,
- huge_buf_size);
+ (3 * 4096) >> 5);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_MAC_TH, 512 >> 8);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XOFF_MAC_TH, 2048 >> 8);
EFX_SET_OWORD_FIELD(reg, FRF_AA_RX_XON_TX_TH, ctrl_xon_thr);
@@ -1569,7 +1570,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
/* Data FIFO size is 80K; register fields moved */
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_DESC_PUSH_EN, 0);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_USR_BUF_SIZE,
- huge_buf_size);
+ EFX_RX_USR_BUF_SIZE >> 5);
/* Send XON and XOFF at ~3 * max MTU away from empty/full */
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8);
EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8);
@@ -1815,6 +1816,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
.evq_rptr_tbl_base = FR_AA_EVQ_RPTR_KER,
.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
.rx_buffer_padding = 0x24,
+ .can_rx_scatter = false,
.max_interrupt_mode = EFX_INT_MODE_MSI,
.phys_addr_channels = 4,
.timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH,
@@ -1865,6 +1867,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
.rx_buffer_hash_size = 0x10,
.rx_buffer_padding = 0,
+ .can_rx_scatter = true,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
* interrupt handler only supports 32
diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c
index 8af42cd1feda..2397f0e8d3eb 100644
--- a/drivers/net/ethernet/sfc/filter.c
+++ b/drivers/net/ethernet/sfc/filter.c
@@ -66,6 +66,10 @@ struct efx_filter_state {
#endif
};
+static void efx_filter_table_clear_entry(struct efx_nic *efx,
+ struct efx_filter_table *table,
+ unsigned int filter_idx);
+
/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
* key derived from the n-tuple. The initial LFSR state is 0xffff. */
static u16 efx_filter_hash(u32 key)
@@ -168,6 +172,25 @@ static void efx_filter_push_rx_config(struct efx_nic *efx)
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED,
!!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
EFX_FILTER_FLAG_RX_RSS));
+
+ /* There is a single bit to enable RX scatter for all
+ * unmatched packets. Only set it if scatter is
+ * enabled in both filter specs.
+ */
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_BZ_SCATTER_ENBL_NO_MATCH_Q,
+ !!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
+ table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
+ EFX_FILTER_FLAG_RX_SCATTER));
+ } else if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
+ /* We don't expose 'default' filters because unmatched
+ * packets always go to the queue number found in the
+ * RSS table. But we still need to set the RX scatter
+ * bit here.
+ */
+ EFX_SET_OWORD_FIELD(
+ filter_ctl, FRF_BZ_SCATTER_ENBL_NO_MATCH_Q,
+ efx->rx_scatter);
}
efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
@@ -409,9 +432,18 @@ static void efx_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table = &state->table[EFX_FILTER_TABLE_RX_DEF];
struct efx_filter_spec *spec = &table->spec[filter_idx];
+ enum efx_filter_flags flags = 0;
+
+ /* If there's only one channel then disable RSS for non VF
+ * traffic, thereby allowing VFs to use RSS when the PF can't.
+ */
+ if (efx->n_rx_channels > 1)
+ flags |= EFX_FILTER_FLAG_RX_RSS;
- efx_filter_init_rx(spec, EFX_FILTER_PRI_MANUAL,
- EFX_FILTER_FLAG_RX_RSS, 0);
+ if (efx->rx_scatter)
+ flags |= EFX_FILTER_FLAG_RX_SCATTER;
+
+ efx_filter_init_rx(spec, EFX_FILTER_PRI_MANUAL, flags, 0);
spec->type = EFX_FILTER_UC_DEF + filter_idx;
table->used_bitmap[0] |= 1 << filter_idx;
}
@@ -463,13 +495,6 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
break;
}
- case EFX_FILTER_TABLE_RX_DEF:
- /* One filter spec per type */
- BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
- BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
- EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
- return spec->type - EFX_FILTER_UC_DEF;
-
case EFX_FILTER_TABLE_RX_MAC: {
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
EFX_POPULATE_OWORD_7(
@@ -520,42 +545,6 @@ static bool efx_filter_equal(const struct efx_filter_spec *left,
return true;
}
-static int efx_filter_search(struct efx_filter_table *table,
- struct efx_filter_spec *spec, u32 key,
- bool for_insert, unsigned int *depth_required)
-{
- unsigned hash, incr, filter_idx, depth, depth_max;
-
- hash = efx_filter_hash(key);
- incr = efx_filter_increment(key);
-
- filter_idx = hash & (table->size - 1);
- depth = 1;
- depth_max = (for_insert ?
- (spec->priority <= EFX_FILTER_PRI_HINT ?
- FILTER_CTL_SRCH_HINT_MAX : FILTER_CTL_SRCH_MAX) :
- table->search_depth[spec->type]);
-
- for (;;) {
- /* Return success if entry is used and matches this spec
- * or entry is unused and we are trying to insert.
- */
- if (test_bit(filter_idx, table->used_bitmap) ?
- efx_filter_equal(spec, &table->spec[filter_idx]) :
- for_insert) {
- *depth_required = depth;
- return filter_idx;
- }
-
- /* Return failure if we reached the maximum search depth */
- if (depth == depth_max)
- return for_insert ? -EBUSY : -ENOENT;
-
- filter_idx = (filter_idx + incr) & (table->size - 1);
- ++depth;
- }
-}
-
/*
* Construct/deconstruct external filter IDs. At least the RX filter
* IDs must be ordered by matching priority, for RX NFC semantics.
@@ -650,44 +639,111 @@ u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
* efx_filter_insert_filter - add or replace a filter
* @efx: NIC in which to insert the filter
* @spec: Specification for the filter
- * @replace: Flag for whether the specified filter may replace a filter
- * with an identical match expression and equal or lower priority
+ * @replace_equal: Flag for whether the specified filter may replace an
+ * existing filter with equal priority
*
* On success, return the filter ID.
* On failure, return a negative error code.
+ *
+ * If an existing filter has equal match values to the new filter
+ * spec, then the new filter might replace it, depending on the
+ * relative priorities. If the existing filter has lower priority, or
+ * if @replace_equal is set and it has equal priority, then it is
+ * replaced. Otherwise the function fails, returning -%EPERM if
+ * the existing filter has higher priority or -%EEXIST if it has
+ * equal priority.
*/
s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
- bool replace)
+ bool replace_equal)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table = efx_filter_spec_table(state, spec);
- struct efx_filter_spec *saved_spec;
efx_oword_t filter;
- unsigned int filter_idx, depth = 0;
- u32 key;
+ int rep_index, ins_index;
+ unsigned int depth = 0;
int rc;
if (!table || table->size == 0)
return -EINVAL;
- key = efx_filter_build(&filter, spec);
-
netif_vdbg(efx, hw, efx->net_dev,
"%s: type %d search_depth=%d", __func__, spec->type,
table->search_depth[spec->type]);
- spin_lock_bh(&state->lock);
+ if (table->id == EFX_FILTER_TABLE_RX_DEF) {
+ /* One filter spec per type */
+ BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
+ BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
+ EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
+ rep_index = spec->type - EFX_FILTER_INDEX_UC_DEF;
+ ins_index = rep_index;
- rc = efx_filter_search(table, spec, key, true, &depth);
- if (rc < 0)
- goto out;
- filter_idx = rc;
- BUG_ON(filter_idx >= table->size);
- saved_spec = &table->spec[filter_idx];
-
- if (test_bit(filter_idx, table->used_bitmap)) {
- /* Should we replace the existing filter? */
- if (!replace) {
+ spin_lock_bh(&state->lock);
+ } else {
+ /* Search concurrently for
+ * (1) a filter to be replaced (rep_index): any filter
+ * with the same match values, up to the current
+ * search depth for this type, and
+ * (2) the insertion point (ins_index): (1) or any
+ * free slot before it or up to the maximum search
+ * depth for this priority
+ * We fail if we cannot find (2).
+ *
+ * We can stop once either
+ * (a) we find (1), in which case we have definitely
+ * found (2) as well; or
+ * (b) we have searched exhaustively for (1), and have
+ * either found (2) or searched exhaustively for it
+ */
+ u32 key = efx_filter_build(&filter, spec);
+ unsigned int hash = efx_filter_hash(key);
+ unsigned int incr = efx_filter_increment(key);
+ unsigned int max_rep_depth = table->search_depth[spec->type];
+ unsigned int max_ins_depth =
+ spec->priority <= EFX_FILTER_PRI_HINT ?
+ FILTER_CTL_SRCH_HINT_MAX : FILTER_CTL_SRCH_MAX;
+ unsigned int i = hash & (table->size - 1);
+
+ ins_index = -1;
+ depth = 1;
+
+ spin_lock_bh(&state->lock);
+
+ for (;;) {
+ if (!test_bit(i, table->used_bitmap)) {
+ if (ins_index < 0)
+ ins_index = i;
+ } else if (efx_filter_equal(spec, &table->spec[i])) {
+ /* Case (a) */
+ if (ins_index < 0)
+ ins_index = i;
+ rep_index = i;
+ break;
+ }
+
+ if (depth >= max_rep_depth &&
+ (ins_index >= 0 || depth >= max_ins_depth)) {
+ /* Case (b) */
+ if (ins_index < 0) {
+ rc = -EBUSY;
+ goto out;
+ }
+ rep_index = -1;
+ break;
+ }
+
+ i = (i + incr) & (table->size - 1);
+ ++depth;
+ }
+ }
+
+ /* If we found a filter to be replaced, check whether we
+ * should do so
+ */
+ if (rep_index >= 0) {
+ struct efx_filter_spec *saved_spec = &table->spec[rep_index];
+
+ if (spec->priority == saved_spec->priority && !replace_equal) {
rc = -EEXIST;
goto out;
}
@@ -695,11 +751,14 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
rc = -EPERM;
goto out;
}
- } else {
- __set_bit(filter_idx, table->used_bitmap);
+ }
+
+ /* Insert the filter */
+ if (ins_index != rep_index) {
+ __set_bit(ins_index, table->used_bitmap);
++table->used;
}
- *saved_spec = *spec;
+ table->spec[ins_index] = *spec;
if (table->id == EFX_FILTER_TABLE_RX_DEF) {
efx_filter_push_rx_config(efx);
@@ -713,13 +772,19 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
}
efx_writeo(efx, &filter,
- table->offset + table->step * filter_idx);
+ table->offset + table->step * ins_index);
+
+ /* If we were able to replace a filter by inserting
+ * at a lower depth, clear the replaced filter
+ */
+ if (ins_index != rep_index && rep_index >= 0)
+ efx_filter_table_clear_entry(efx, table, rep_index);
}
netif_vdbg(efx, hw, efx->net_dev,
"%s: filter type %d index %d rxq %u set",
- __func__, spec->type, filter_idx, spec->dmaq_id);
- rc = efx_filter_make_id(spec, filter_idx);
+ __func__, spec->type, ins_index, spec->dmaq_id);
+ rc = efx_filter_make_id(spec, ins_index);
out:
spin_unlock_bh(&state->lock);
@@ -1060,6 +1125,50 @@ void efx_remove_filters(struct efx_nic *efx)
kfree(state);
}
+/* Update scatter enable flags for filters pointing to our own RX queues */
+void efx_filter_update_rx_scatter(struct efx_nic *efx)
+{
+ struct efx_filter_state *state = efx->filter_state;
+ enum efx_filter_table_id table_id;
+ struct efx_filter_table *table;
+ efx_oword_t filter;
+ unsigned int filter_idx;
+
+ spin_lock_bh(&state->lock);
+
+ for (table_id = EFX_FILTER_TABLE_RX_IP;
+ table_id <= EFX_FILTER_TABLE_RX_DEF;
+ table_id++) {
+ table = &state->table[table_id];
+
+ for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
+ if (!test_bit(filter_idx, table->used_bitmap) ||
+ table->spec[filter_idx].dmaq_id >=
+ efx->n_rx_channels)
+ continue;
+
+ if (efx->rx_scatter)
+ table->spec[filter_idx].flags |=
+ EFX_FILTER_FLAG_RX_SCATTER;
+ else
+ table->spec[filter_idx].flags &=
+ ~EFX_FILTER_FLAG_RX_SCATTER;
+
+ if (table_id == EFX_FILTER_TABLE_RX_DEF)
+ /* Pushed by efx_filter_push_rx_config() */
+ continue;
+
+ efx_filter_build(&filter, &table->spec[filter_idx]);
+ efx_writeo(efx, &filter,
+ table->offset + table->step * filter_idx);
+ }
+ }
+
+ efx_filter_push_rx_config(efx);
+
+ spin_unlock_bh(&state->lock);
+}
+
#ifdef CONFIG_RFS_ACCEL
int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index 0095ce95150b..97dd8f18c001 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -667,7 +667,7 @@ fail:
int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
u16 *fw_subtype_list, u32 *capabilities)
{
- uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMIN];
+ uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LENMAX];
size_t outlen, offset, i;
int port_num = efx_port_num(efx);
int rc;
diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h
index 9d426d0457bd..c5c9747861ba 100644
--- a/drivers/net/ethernet/sfc/mcdi_pcol.h
+++ b/drivers/net/ethernet/sfc/mcdi_pcol.h
@@ -553,6 +553,7 @@
#define MC_CMD_PTP_MODE_V1_VLAN 0x1 /* enum */
#define MC_CMD_PTP_MODE_V2 0x2 /* enum */
#define MC_CMD_PTP_MODE_V2_VLAN 0x3 /* enum */
+#define MC_CMD_PTP_MODE_V2_ENHANCED 0x4 /* enum */
/* MC_CMD_PTP_IN_DISABLE msgrequest */
#define MC_CMD_PTP_IN_DISABLE_LEN 8
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 0a90abd2421b..9bd433a095c5 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -69,6 +69,12 @@
#define EFX_TXQ_TYPES 4
#define EFX_MAX_TX_QUEUES (EFX_TXQ_TYPES * EFX_MAX_CHANNELS)
+/* Maximum possible MTU the driver supports */
+#define EFX_MAX_MTU (9 * 1024)
+
+/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page. */
+#define EFX_RX_USR_BUF_SIZE 1824
+
/* Forward declare Precision Time Protocol (PTP) support structure. */
struct efx_ptp_data;
@@ -206,25 +212,23 @@ struct efx_tx_queue {
/**
* struct efx_rx_buffer - An Efx RX data buffer
* @dma_addr: DMA base address of the buffer
- * @skb: The associated socket buffer. Valid iff !(@flags & %EFX_RX_BUF_PAGE).
- * Will be %NULL if the buffer slot is currently free.
- * @page: The associated page buffer. Valif iff @flags & %EFX_RX_BUF_PAGE.
+ * @page: The associated page buffer.
* Will be %NULL if the buffer slot is currently free.
- * @page_offset: Offset within page. Valid iff @flags & %EFX_RX_BUF_PAGE.
- * @len: Buffer length, in bytes.
- * @flags: Flags for buffer and packet state.
+ * @page_offset: If pending: offset in @page of DMA base address.
+ * If completed: offset in @page of Ethernet header.
+ * @len: If pending: length for DMA descriptor.
+ * If completed: received length, excluding hash prefix.
+ * @flags: Flags for buffer and packet state. These are only set on the
+ * first buffer of a scattered packet.
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
- union {
- struct sk_buff *skb;
- struct page *page;
- } u;
+ struct page *page;
u16 page_offset;
u16 len;
u16 flags;
};
-#define EFX_RX_BUF_PAGE 0x0001
+#define EFX_RX_BUF_LAST_IN_PAGE 0x0001
#define EFX_RX_PKT_CSUMMED 0x0002
#define EFX_RX_PKT_DISCARD 0x0004
@@ -260,14 +264,23 @@ struct efx_rx_page_state {
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
+ * @scatter_n: Number of buffers used by current packet
+ * @page_ring: The ring to store DMA mapped pages for reuse.
+ * @page_add: Counter to calculate the write pointer for the recycle ring.
+ * @page_remove: Counter to calculate the read pointer for the recycle ring.
+ * @page_recycle_count: The number of pages that have been recycled.
+ * @page_recycle_failed: The number of pages that couldn't be recycled because
+ * the kernel still held a reference to them.
+ * @page_recycle_full: The number of pages that were released because the
+ * recycle ring was full.
+ * @page_ptr_mask: The number of pages in the RX recycle ring minus 1.
* @max_fill: RX descriptor maximum fill level (<= ring size)
* @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
* (<= @max_fill)
* @min_fill: RX descriptor minimum non-zero fill level.
* This records the minimum fill level observed when a ring
* refill was triggered.
- * @alloc_page_count: RX allocation strategy counter.
- * @alloc_skb_count: RX allocation strategy counter.
+ * @recycle_count: RX buffer recycle counter.
* @slow_fill: Timer used to defer efx_nic_generate_fill_event().
*/
struct efx_rx_queue {
@@ -279,15 +292,22 @@ struct efx_rx_queue {
bool enabled;
bool flush_pending;
- int added_count;
- int notified_count;
- int removed_count;
+ unsigned int added_count;
+ unsigned int notified_count;
+ unsigned int removed_count;
+ unsigned int scatter_n;
+ struct page **page_ring;
+ unsigned int page_add;
+ unsigned int page_remove;
+ unsigned int page_recycle_count;
+ unsigned int page_recycle_failed;
+ unsigned int page_recycle_full;
+ unsigned int page_ptr_mask;
unsigned int max_fill;
unsigned int fast_fill_trigger;
unsigned int min_fill;
unsigned int min_overfill;
- unsigned int alloc_page_count;
- unsigned int alloc_skb_count;
+ unsigned int recycle_count;
struct timer_list slow_fill;
unsigned int slow_fill_count;
};
@@ -336,10 +356,6 @@ enum efx_rx_alloc_method {
* @event_test_cpu: Last CPU to handle interrupt or test event for this channel
* @irq_count: Number of IRQs since last adaptive moderation decision
* @irq_mod_score: IRQ moderation score
- * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
- * and diagnostic counters
- * @rx_alloc_push_pages: RX allocation method currently in use for pushing
- * descriptors
* @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
* @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
* @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
@@ -347,6 +363,12 @@ enum efx_rx_alloc_method {
* @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
* @n_rx_overlength: Count of RX_OVERLENGTH errors
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
+ * @n_rx_nodesc_trunc: Number of RX packets truncated and then dropped due to
+ * lack of descriptors
+ * @rx_pkt_n_frags: Number of fragments in next packet to be delivered by
+ * __efx_rx_packet(), or zero if there is none
+ * @rx_pkt_index: Ring index of first buffer for next packet to be delivered
+ * by __efx_rx_packet(), if @rx_pkt_n_frags != 0
* @rx_queue: RX queue for this channel
* @tx_queue: TX queues for this channel
*/
@@ -371,9 +393,6 @@ struct efx_channel {
unsigned int rfs_filters_added;
#endif
- int rx_alloc_level;
- int rx_alloc_push_pages;
-
unsigned n_rx_tobe_disc;
unsigned n_rx_ip_hdr_chksum_err;
unsigned n_rx_tcp_udp_chksum_err;
@@ -381,11 +400,10 @@ struct efx_channel {
unsigned n_rx_frm_trunc;
unsigned n_rx_overlength;
unsigned n_skbuff_leaks;
+ unsigned int n_rx_nodesc_trunc;
- /* Used to pipeline received packets in order to optimise memory
- * access with prefetches.
- */
- struct efx_rx_buffer *rx_pkt;
+ unsigned int rx_pkt_n_frags;
+ unsigned int rx_pkt_index;
struct efx_rx_queue rx_queue;
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES];
@@ -410,7 +428,7 @@ struct efx_channel_type {
void (*post_remove)(struct efx_channel *);
void (*get_name)(struct efx_channel *, char *buf, size_t len);
struct efx_channel *(*copy)(const struct efx_channel *);
- void (*receive_skb)(struct efx_channel *, struct sk_buff *);
+ bool (*receive_skb)(struct efx_channel *, struct sk_buff *);
bool keep_eventq;
};
@@ -446,6 +464,7 @@ enum nic_state {
STATE_UNINIT = 0, /* device being probed/removed or is frozen */
STATE_READY = 1, /* hardware ready and netdev registered */
STATE_DISABLED = 2, /* device disabled due to hardware errors */
+ STATE_RECOVERY = 3, /* device recovering from PCI error */
};
/*
@@ -684,10 +703,13 @@ struct vfdi_status;
* @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
* @n_tx_channels: Number of channels used for TX
- * @rx_buffer_len: RX buffer length
+ * @rx_dma_len: Current maximum RX DMA length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @rx_buffer_truesize: Amortised allocation size of an RX buffer,
+ * for use in sk_buff::truesize
* @rx_hash_key: Toeplitz hash key for RSS
* @rx_indir_table: Indirection table for RSS
+ * @rx_scatter: Scatter mode enabled for receives
* @int_error_count: Number of internal errors seen recently
* @int_error_expire: Time at which error count will be expired
* @irq_status: Interrupt status buffer
@@ -800,10 +822,15 @@ struct efx_nic {
unsigned rss_spread;
unsigned tx_channel_offset;
unsigned n_tx_channels;
- unsigned int rx_buffer_len;
+ unsigned int rx_dma_len;
unsigned int rx_buffer_order;
+ unsigned int rx_buffer_truesize;
+ unsigned int rx_page_buf_step;
+ unsigned int rx_bufs_per_page;
+ unsigned int rx_pages_per_batch;
u8 rx_hash_key[40];
u32 rx_indir_table[128];
+ bool rx_scatter;
unsigned int_error_count;
unsigned long int_error_expire;
@@ -934,8 +961,9 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @evq_ptr_tbl_base: Event queue pointer table base address
* @evq_rptr_tbl_base: Event queue read-pointer table base address
* @max_dma_mask: Maximum possible DMA mask
- * @rx_buffer_hash_size: Size of hash at start of RX buffer
- * @rx_buffer_padding: Size of padding at end of RX buffer
+ * @rx_buffer_hash_size: Size of hash at start of RX packet
+ * @rx_buffer_padding: Size of padding at end of RX packet
+ * @can_rx_scatter: NIC is able to scatter packet to multiple buffers
* @max_interrupt_mode: Highest capability interrupt mode supported
* from &enum efx_init_mode.
* @phys_addr_channels: Number of channels with physically addressed
@@ -983,6 +1011,7 @@ struct efx_nic_type {
u64 max_dma_mask;
unsigned int rx_buffer_hash_size;
unsigned int rx_buffer_padding;
+ bool can_rx_scatter;
unsigned int max_interrupt_mode;
unsigned int phys_addr_channels;
unsigned int timer_period_max;
diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c
index eaa8e874a3cb..b0503cd8c2a0 100644
--- a/drivers/net/ethernet/sfc/nic.c
+++ b/drivers/net/ethernet/sfc/nic.c
@@ -305,11 +305,11 @@ int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
unsigned int len)
{
buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len,
- &buffer->dma_addr, GFP_ATOMIC);
+ &buffer->dma_addr,
+ GFP_ATOMIC | __GFP_ZERO);
if (!buffer->addr)
return -ENOMEM;
buffer->len = len;
- memset(buffer->addr, 0, len);
return 0;
}
@@ -592,12 +592,22 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
bool iscsi_digest_en = is_b0;
+ bool jumbo_en;
+
+ /* For kernel-mode queues in Falcon A1, the JUMBO flag enables
+ * DMA to continue after a PCIe page boundary (and scattering
+ * is not possible). In Falcon B0 and Siena, it enables
+ * scatter.
+ */
+ jumbo_en = !is_b0 || efx->rx_scatter;
netif_dbg(efx, hw, efx->net_dev,
"RX queue %d ring in special buffers %d-%d\n",
efx_rx_queue_index(rx_queue), rx_queue->rxd.index,
rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+ rx_queue->scatter_n = 0;
+
/* Pin RX descriptor ring */
efx_init_special_buffer(efx, &rx_queue->rxd);
@@ -614,8 +624,7 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
FRF_AZ_RX_DESCQ_SIZE,
__ffs(rx_queue->rxd.entries),
FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ ,
- /* For >=B0 this is scatter so disable */
- FRF_AZ_RX_DESCQ_JUMBO, !is_b0,
+ FRF_AZ_RX_DESCQ_JUMBO, jumbo_en,
FRF_AZ_RX_DESCQ_EN, 1);
efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
efx_rx_queue_index(rx_queue));
@@ -969,13 +978,24 @@ static u16 efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
EFX_RX_PKT_DISCARD : 0;
}
-/* Handle receive events that are not in-order. */
-static void
+/* Handle receive events that are not in-order. Return true if this
+ * can be handled as a partial packet discard, false if it's more
+ * serious.
+ */
+static bool
efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
{
+ struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
struct efx_nic *efx = rx_queue->efx;
unsigned expected, dropped;
+ if (rx_queue->scatter_n &&
+ index == ((rx_queue->removed_count + rx_queue->scatter_n - 1) &
+ rx_queue->ptr_mask)) {
+ ++channel->n_rx_nodesc_trunc;
+ return true;
+ }
+
expected = rx_queue->removed_count & rx_queue->ptr_mask;
dropped = (index - expected) & rx_queue->ptr_mask;
netif_info(efx, rx_err, efx->net_dev,
@@ -984,6 +1004,7 @@ efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index)
efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+ return false;
}
/* Handle a packet received event
@@ -999,7 +1020,7 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt;
unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt;
unsigned expected_ptr;
- bool rx_ev_pkt_ok;
+ bool rx_ev_pkt_ok, rx_ev_sop, rx_ev_cont;
u16 flags;
struct efx_rx_queue *rx_queue;
struct efx_nic *efx = channel->efx;
@@ -1007,21 +1028,56 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
if (unlikely(ACCESS_ONCE(efx->reset_pending)))
return;
- /* Basic packet information */
- rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
- rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK);
- rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
- WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT));
- WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1);
+ rx_ev_cont = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT);
+ rx_ev_sop = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP);
WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) !=
channel->channel);
rx_queue = efx_channel_get_rx_queue(channel);
rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR);
- expected_ptr = rx_queue->removed_count & rx_queue->ptr_mask;
- if (unlikely(rx_ev_desc_ptr != expected_ptr))
- efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+ expected_ptr = ((rx_queue->removed_count + rx_queue->scatter_n) &
+ rx_queue->ptr_mask);
+
+ /* Check for partial drops and other errors */
+ if (unlikely(rx_ev_desc_ptr != expected_ptr) ||
+ unlikely(rx_ev_sop != (rx_queue->scatter_n == 0))) {
+ if (rx_ev_desc_ptr != expected_ptr &&
+ !efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr))
+ return;
+
+ /* Discard all pending fragments */
+ if (rx_queue->scatter_n) {
+ efx_rx_packet(
+ rx_queue,
+ rx_queue->removed_count & rx_queue->ptr_mask,
+ rx_queue->scatter_n, 0, EFX_RX_PKT_DISCARD);
+ rx_queue->removed_count += rx_queue->scatter_n;
+ rx_queue->scatter_n = 0;
+ }
+
+ /* Return if there is no new fragment */
+ if (rx_ev_desc_ptr != expected_ptr)
+ return;
+
+ /* Discard new fragment if not SOP */
+ if (!rx_ev_sop) {
+ efx_rx_packet(
+ rx_queue,
+ rx_queue->removed_count & rx_queue->ptr_mask,
+ 1, 0, EFX_RX_PKT_DISCARD);
+ ++rx_queue->removed_count;
+ return;
+ }
+ }
+
+ ++rx_queue->scatter_n;
+ if (rx_ev_cont)
+ return;
+
+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
if (likely(rx_ev_pkt_ok)) {
/* If packet is marked as OK and packet type is TCP/IP or
@@ -1049,7 +1105,11 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
channel->irq_mod_score += 2;
/* Handle received packet */
- efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, flags);
+ efx_rx_packet(rx_queue,
+ rx_queue->removed_count & rx_queue->ptr_mask,
+ rx_queue->scatter_n, rx_ev_byte_cnt, flags);
+ rx_queue->removed_count += rx_queue->scatter_n;
+ rx_queue->scatter_n = 0;
}
/* If this flush done event corresponds to a &struct efx_tx_queue, then
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index 3f93624fc273..07f6baa15c0c 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -99,6 +99,9 @@
#define PTP_V2_VERSION_LENGTH 1
#define PTP_V2_VERSION_OFFSET 29
+#define PTP_V2_UUID_LENGTH 8
+#define PTP_V2_UUID_OFFSET 48
+
/* Although PTP V2 UUIDs are comprised a ClockIdentity (8) and PortNumber (2),
* the MC only captures the last six bytes of the clock identity. These values
* reflect those, not the ones used in the standard. The standard permits
@@ -429,13 +432,10 @@ static int efx_ptp_process_times(struct efx_nic *efx, u8 *synch_buf,
unsigned number_readings = (response_length /
MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_LEN);
unsigned i;
- unsigned min;
- unsigned min_set = 0;
unsigned total;
unsigned ngood = 0;
unsigned last_good = 0;
struct efx_ptp_data *ptp = efx->ptp_data;
- bool min_valid = false;
u32 last_sec;
u32 start_sec;
struct timespec delta;
@@ -443,35 +443,17 @@ static int efx_ptp_process_times(struct efx_nic *efx, u8 *synch_buf,
if (number_readings == 0)
return -EAGAIN;
- /* Find minimum value in this set of results, discarding clearly
- * erroneous results.
+ /* Read the set of results and increment stats for any results that
+ * appera to be erroneous.
*/
for (i = 0; i < number_readings; i++) {
efx_ptp_read_timeset(synch_buf, &ptp->timeset[i]);
synch_buf += MC_CMD_PTP_OUT_SYNCHRONIZE_TIMESET_LEN;
- if (ptp->timeset[i].window > SYNCHRONISATION_GRANULARITY_NS) {
- if (min_valid) {
- if (ptp->timeset[i].window < min_set)
- min_set = ptp->timeset[i].window;
- } else {
- min_valid = true;
- min_set = ptp->timeset[i].window;
- }
- }
- }
-
- if (min_valid) {
- if (ptp->base_sync_valid && (min_set > ptp->base_sync_ns))
- min = ptp->base_sync_ns;
- else
- min = min_set;
- } else {
- min = SYNCHRONISATION_GRANULARITY_NS;
}
- /* Discard excessively long synchronise durations. The MC times
- * when it finishes reading the host time so the corrected window
- * time should be fairly constant for a given platform.
+ /* Find the last good host-MC synchronization result. The MC times
+ * when it finishes reading the host time so the corrected window time
+ * should be fairly constant for a given platform.
*/
total = 0;
for (i = 0; i < number_readings; i++)
@@ -489,8 +471,8 @@ static int efx_ptp_process_times(struct efx_nic *efx, u8 *synch_buf,
if (ngood == 0) {
netif_warn(efx, drv, efx->net_dev,
- "PTP no suitable synchronisations %dns %dns\n",
- ptp->base_sync_ns, min_set);
+ "PTP no suitable synchronisations %dns\n",
+ ptp->base_sync_ns);
return -EAGAIN;
}
@@ -1006,43 +988,53 @@ bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb)
* the receive timestamp from the MC - this will probably occur after the
* packet arrival because of the processing in the MC.
*/
-static void efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
+static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
{
struct efx_nic *efx = channel->efx;
struct efx_ptp_data *ptp = efx->ptp_data;
struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb;
- u8 *data;
+ u8 *match_data_012, *match_data_345;
unsigned int version;
match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS);
/* Correct version? */
if (ptp->mode == MC_CMD_PTP_MODE_V1) {
- if (skb->len < PTP_V1_MIN_LENGTH) {
- netif_receive_skb(skb);
- return;
+ if (!pskb_may_pull(skb, PTP_V1_MIN_LENGTH)) {
+ return false;
}
version = ntohs(*(__be16 *)&skb->data[PTP_V1_VERSION_OFFSET]);
if (version != PTP_VERSION_V1) {
- netif_receive_skb(skb);
- return;
+ return false;
}
+
+ /* PTP V1 uses all six bytes of the UUID to match the packet
+ * to the timestamp
+ */
+ match_data_012 = skb->data + PTP_V1_UUID_OFFSET;
+ match_data_345 = skb->data + PTP_V1_UUID_OFFSET + 3;
} else {
- if (skb->len < PTP_V2_MIN_LENGTH) {
- netif_receive_skb(skb);
- return;
+ if (!pskb_may_pull(skb, PTP_V2_MIN_LENGTH)) {
+ return false;
}
version = skb->data[PTP_V2_VERSION_OFFSET];
-
- BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2);
- BUILD_BUG_ON(PTP_V1_UUID_OFFSET != PTP_V2_MC_UUID_OFFSET);
- BUILD_BUG_ON(PTP_V1_UUID_LENGTH != PTP_V2_MC_UUID_LENGTH);
- BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET);
- BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH);
-
if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) {
- netif_receive_skb(skb);
- return;
+ return false;
+ }
+
+ /* The original V2 implementation uses bytes 2-7 of
+ * the UUID to match the packet to the timestamp. This
+ * discards two of the bytes of the MAC address used
+ * to create the UUID (SF bug 33070). The PTP V2
+ * enhanced mode fixes this issue and uses bytes 0-2
+ * and byte 5-7 of the UUID.
+ */
+ match_data_345 = skb->data + PTP_V2_UUID_OFFSET + 5;
+ if (ptp->mode == MC_CMD_PTP_MODE_V2) {
+ match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 2;
+ } else {
+ match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 0;
+ BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED);
}
}
@@ -1056,14 +1048,19 @@ static void efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
timestamps = skb_hwtstamps(skb);
memset(timestamps, 0, sizeof(*timestamps));
+ /* We expect the sequence number to be in the same position in
+ * the packet for PTP V1 and V2
+ */
+ BUILD_BUG_ON(PTP_V1_SEQUENCE_OFFSET != PTP_V2_SEQUENCE_OFFSET);
+ BUILD_BUG_ON(PTP_V1_SEQUENCE_LENGTH != PTP_V2_SEQUENCE_LENGTH);
+
/* Extract UUID/Sequence information */
- data = skb->data + PTP_V1_UUID_OFFSET;
- match->words[0] = (data[0] |
- (data[1] << 8) |
- (data[2] << 16) |
- (data[3] << 24));
- match->words[1] = (data[4] |
- (data[5] << 8) |
+ match->words[0] = (match_data_012[0] |
+ (match_data_012[1] << 8) |
+ (match_data_012[2] << 16) |
+ (match_data_345[0] << 24));
+ match->words[1] = (match_data_345[1] |
+ (match_data_345[2] << 8) |
(skb->data[PTP_V1_SEQUENCE_OFFSET +
PTP_V1_SEQUENCE_LENGTH - 1] <<
16));
@@ -1073,6 +1070,8 @@ static void efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
skb_queue_tail(&ptp->rxq, skb);
queue_work(ptp->workwq, &ptp->work);
+
+ return true;
}
/* Transmit a PTP packet. This has to be transmitted by the MC
@@ -1167,7 +1166,7 @@ static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
* timestamped
*/
init->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
- new_mode = MC_CMD_PTP_MODE_V2;
+ new_mode = MC_CMD_PTP_MODE_V2_ENHANCED;
enable_wanted = true;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
@@ -1186,7 +1185,14 @@ static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
if (init->tx_type != HWTSTAMP_TX_OFF)
enable_wanted = true;
+ /* Old versions of the firmware do not support the improved
+ * UUID filtering option (SF bug 33070). If the firmware does
+ * not accept the enhanced mode, fall back to the standard PTP
+ * v2 UUID filtering.
+ */
rc = efx_ptp_change_mode(efx, enable_wanted, new_mode);
+ if ((rc != 0) && (new_mode == MC_CMD_PTP_MODE_V2_ENHANCED))
+ rc = efx_ptp_change_mode(efx, enable_wanted, MC_CMD_PTP_MODE_V2);
if (rc != 0)
return rc;
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index bb579a6128c8..e73e30bac10e 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -16,6 +16,7 @@
#include <linux/udp.h>
#include <linux/prefetch.h>
#include <linux/moduleparam.h>
+#include <linux/iommu.h>
#include <net/ip.h>
#include <net/checksum.h>
#include "net_driver.h"
@@ -24,85 +25,39 @@
#include "selftest.h"
#include "workarounds.h"
-/* Number of RX descriptors pushed at once. */
-#define EFX_RX_BATCH 8
+/* Preferred number of descriptors to fill at once */
+#define EFX_RX_PREFERRED_BATCH 8U
-/* Maximum size of a buffer sharing a page */
-#define EFX_RX_HALF_PAGE ((PAGE_SIZE >> 1) - sizeof(struct efx_rx_page_state))
+/* Number of RX buffers to recycle pages for. When creating the RX page recycle
+ * ring, this number is divided by the number of buffers per page to calculate
+ * the number of pages to store in the RX page recycle ring.
+ */
+#define EFX_RECYCLE_RING_SIZE_IOMMU 4096
+#define EFX_RECYCLE_RING_SIZE_NOIOMMU (2 * EFX_RX_PREFERRED_BATCH)
/* Size of buffer allocated for skb header area. */
#define EFX_SKB_HEADERS 64u
-/*
- * rx_alloc_method - RX buffer allocation method
- *
- * This driver supports two methods for allocating and using RX buffers:
- * each RX buffer may be backed by an skb or by an order-n page.
- *
- * When GRO is in use then the second method has a lower overhead,
- * since we don't have to allocate then free skbs on reassembled frames.
- *
- * Values:
- * - RX_ALLOC_METHOD_AUTO = 0
- * - RX_ALLOC_METHOD_SKB = 1
- * - RX_ALLOC_METHOD_PAGE = 2
- *
- * The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
- * controlled by the parameters below.
- *
- * - Since pushing and popping descriptors are separated by the rx_queue
- * size, so the watermarks should be ~rxd_size.
- * - The performance win by using page-based allocation for GRO is less
- * than the performance hit of using page-based allocation of non-GRO,
- * so the watermarks should reflect this.
- *
- * Per channel we maintain a single variable, updated by each channel:
- *
- * rx_alloc_level += (gro_performed ? RX_ALLOC_FACTOR_GRO :
- * RX_ALLOC_FACTOR_SKB)
- * Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
- * limits the hysteresis), and update the allocation strategy:
- *
- * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_GRO ?
- * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
- */
-static int rx_alloc_method = RX_ALLOC_METHOD_AUTO;
-
-#define RX_ALLOC_LEVEL_GRO 0x2000
-#define RX_ALLOC_LEVEL_MAX 0x3000
-#define RX_ALLOC_FACTOR_GRO 1
-#define RX_ALLOC_FACTOR_SKB (-2)
-
/* This is the percentage fill level below which new RX descriptors
* will be added to the RX descriptor ring.
*/
static unsigned int rx_refill_threshold;
+/* Each packet can consume up to ceil(max_frame_len / buffer_size) buffers */
+#define EFX_RX_MAX_FRAGS DIV_ROUND_UP(EFX_MAX_FRAME_LEN(EFX_MAX_MTU), \
+ EFX_RX_USR_BUF_SIZE)
+
/*
* RX maximum head room required.
*
- * This must be at least 1 to prevent overflow and at least 2 to allow
- * pipelined receives.
+ * This must be at least 1 to prevent overflow, plus one packet-worth
+ * to allow pipelined receives.
*/
-#define EFX_RXD_HEAD_ROOM 2
+#define EFX_RXD_HEAD_ROOM (1 + EFX_RX_MAX_FRAGS)
-/* Offset of ethernet header within page */
-static inline unsigned int efx_rx_buf_offset(struct efx_nic *efx,
- struct efx_rx_buffer *buf)
+static inline u8 *efx_rx_buf_va(struct efx_rx_buffer *buf)
{
- return buf->page_offset + efx->type->rx_buffer_hash_size;
-}
-static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
-{
- return PAGE_SIZE << efx->rx_buffer_order;
-}
-
-static u8 *efx_rx_buf_eh(struct efx_nic *efx, struct efx_rx_buffer *buf)
-{
- if (buf->flags & EFX_RX_BUF_PAGE)
- return page_address(buf->u.page) + efx_rx_buf_offset(efx, buf);
- else
- return (u8 *)buf->u.skb->data + efx->type->rx_buffer_hash_size;
+ return page_address(buf->page) + buf->page_offset;
}
static inline u32 efx_rx_buf_hash(const u8 *eh)
@@ -119,66 +74,81 @@ static inline u32 efx_rx_buf_hash(const u8 *eh)
#endif
}
-/**
- * efx_init_rx_buffers_skb - create EFX_RX_BATCH skb-based RX buffers
- *
- * @rx_queue: Efx RX queue
- *
- * This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
- * struct efx_rx_buffer for each one. Return a negative error code or 0
- * on success. May fail having only inserted fewer than EFX_RX_BATCH
- * buffers.
- */
-static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
+static inline struct efx_rx_buffer *
+efx_rx_buf_next(struct efx_rx_queue *rx_queue, struct efx_rx_buffer *rx_buf)
+{
+ if (unlikely(rx_buf == efx_rx_buffer(rx_queue, rx_queue->ptr_mask)))
+ return efx_rx_buffer(rx_queue, 0);
+ else
+ return rx_buf + 1;
+}
+
+static inline void efx_sync_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf,
+ unsigned int len)
+{
+ dma_sync_single_for_cpu(&efx->pci_dev->dev, rx_buf->dma_addr, len,
+ DMA_FROM_DEVICE);
+}
+
+void efx_rx_config_page_split(struct efx_nic *efx)
+{
+ efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + EFX_PAGE_IP_ALIGN,
+ L1_CACHE_BYTES);
+ efx->rx_bufs_per_page = efx->rx_buffer_order ? 1 :
+ ((PAGE_SIZE - sizeof(struct efx_rx_page_state)) /
+ efx->rx_page_buf_step);
+ efx->rx_buffer_truesize = (PAGE_SIZE << efx->rx_buffer_order) /
+ efx->rx_bufs_per_page;
+ efx->rx_pages_per_batch = DIV_ROUND_UP(EFX_RX_PREFERRED_BATCH,
+ efx->rx_bufs_per_page);
+}
+
+/* Check the RX page recycle ring for a page that can be reused. */
+static struct page *efx_reuse_page(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
- struct net_device *net_dev = efx->net_dev;
- struct efx_rx_buffer *rx_buf;
- struct sk_buff *skb;
- int skb_len = efx->rx_buffer_len;
- unsigned index, count;
+ struct page *page;
+ struct efx_rx_page_state *state;
+ unsigned index;
- for (count = 0; count < EFX_RX_BATCH; ++count) {
- index = rx_queue->added_count & rx_queue->ptr_mask;
- rx_buf = efx_rx_buffer(rx_queue, index);
-
- rx_buf->u.skb = skb = netdev_alloc_skb(net_dev, skb_len);
- if (unlikely(!skb))
- return -ENOMEM;
-
- /* Adjust the SKB for padding */
- skb_reserve(skb, NET_IP_ALIGN);
- rx_buf->len = skb_len - NET_IP_ALIGN;
- rx_buf->flags = 0;
-
- rx_buf->dma_addr = dma_map_single(&efx->pci_dev->dev,
- skb->data, rx_buf->len,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&efx->pci_dev->dev,
- rx_buf->dma_addr))) {
- dev_kfree_skb_any(skb);
- rx_buf->u.skb = NULL;
- return -EIO;
- }
+ index = rx_queue->page_remove & rx_queue->page_ptr_mask;
+ page = rx_queue->page_ring[index];
+ if (page == NULL)
+ return NULL;
+
+ rx_queue->page_ring[index] = NULL;
+ /* page_remove cannot exceed page_add. */
+ if (rx_queue->page_remove != rx_queue->page_add)
+ ++rx_queue->page_remove;
- ++rx_queue->added_count;
- ++rx_queue->alloc_skb_count;
+ /* If page_count is 1 then we hold the only reference to this page. */
+ if (page_count(page) == 1) {
+ ++rx_queue->page_recycle_count;
+ return page;
+ } else {
+ state = page_address(page);
+ dma_unmap_page(&efx->pci_dev->dev, state->dma_addr,
+ PAGE_SIZE << efx->rx_buffer_order,
+ DMA_FROM_DEVICE);
+ put_page(page);
+ ++rx_queue->page_recycle_failed;
}
- return 0;
+ return NULL;
}
/**
- * efx_init_rx_buffers_page - create EFX_RX_BATCH page-based RX buffers
+ * efx_init_rx_buffers - create EFX_RX_BATCH page-based RX buffers
*
* @rx_queue: Efx RX queue
*
- * This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
- * and populates struct efx_rx_buffers for each one. Return a negative error
- * code or 0 on success. If a single page can be split between two buffers,
- * then the page will either be inserted fully, or not at at all.
+ * This allocates a batch of pages, maps them for DMA, and populates
+ * struct efx_rx_buffers for each one. Return a negative error code or
+ * 0 on success. If a single page can be used for multiple buffers,
+ * then the page will either be inserted fully, or not at all.
*/
-static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
+static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
@@ -188,150 +158,140 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
dma_addr_t dma_addr;
unsigned index, count;
- /* We can split a page between two buffers */
- BUILD_BUG_ON(EFX_RX_BATCH & 1);
-
- for (count = 0; count < EFX_RX_BATCH; ++count) {
- page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
- efx->rx_buffer_order);
- if (unlikely(page == NULL))
- return -ENOMEM;
- dma_addr = dma_map_page(&efx->pci_dev->dev, page, 0,
- efx_rx_buf_size(efx),
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(&efx->pci_dev->dev, dma_addr))) {
- __free_pages(page, efx->rx_buffer_order);
- return -EIO;
+ count = 0;
+ do {
+ page = efx_reuse_page(rx_queue);
+ if (page == NULL) {
+ page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(page == NULL))
+ return -ENOMEM;
+ dma_addr =
+ dma_map_page(&efx->pci_dev->dev, page, 0,
+ PAGE_SIZE << efx->rx_buffer_order,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(&efx->pci_dev->dev,
+ dma_addr))) {
+ __free_pages(page, efx->rx_buffer_order);
+ return -EIO;
+ }
+ state = page_address(page);
+ state->dma_addr = dma_addr;
+ } else {
+ state = page_address(page);
+ dma_addr = state->dma_addr;
}
- state = page_address(page);
- state->refcnt = 0;
- state->dma_addr = dma_addr;
dma_addr += sizeof(struct efx_rx_page_state);
page_offset = sizeof(struct efx_rx_page_state);
- split:
- index = rx_queue->added_count & rx_queue->ptr_mask;
- rx_buf = efx_rx_buffer(rx_queue, index);
- rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
- rx_buf->u.page = page;
- rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN;
- rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
- rx_buf->flags = EFX_RX_BUF_PAGE;
- ++rx_queue->added_count;
- ++rx_queue->alloc_page_count;
- ++state->refcnt;
-
- if ((~count & 1) && (efx->rx_buffer_len <= EFX_RX_HALF_PAGE)) {
- /* Use the second half of the page */
+ do {
+ index = rx_queue->added_count & rx_queue->ptr_mask;
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->page = page;
+ rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN;
+ rx_buf->len = efx->rx_dma_len;
+ rx_buf->flags = 0;
+ ++rx_queue->added_count;
get_page(page);
- dma_addr += (PAGE_SIZE >> 1);
- page_offset += (PAGE_SIZE >> 1);
- ++count;
- goto split;
- }
- }
+ dma_addr += efx->rx_page_buf_step;
+ page_offset += efx->rx_page_buf_step;
+ } while (page_offset + efx->rx_page_buf_step <= PAGE_SIZE);
+
+ rx_buf->flags = EFX_RX_BUF_LAST_IN_PAGE;
+ } while (++count < efx->rx_pages_per_batch);
return 0;
}
+/* Unmap a DMA-mapped page. This function is only called for the final RX
+ * buffer in a page.
+ */
static void efx_unmap_rx_buffer(struct efx_nic *efx,
- struct efx_rx_buffer *rx_buf,
- unsigned int used_len)
+ struct efx_rx_buffer *rx_buf)
{
- if ((rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.page) {
- struct efx_rx_page_state *state;
-
- state = page_address(rx_buf->u.page);
- if (--state->refcnt == 0) {
- dma_unmap_page(&efx->pci_dev->dev,
- state->dma_addr,
- efx_rx_buf_size(efx),
- DMA_FROM_DEVICE);
- } else if (used_len) {
- dma_sync_single_for_cpu(&efx->pci_dev->dev,
- rx_buf->dma_addr, used_len,
- DMA_FROM_DEVICE);
- }
- } else if (!(rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.skb) {
- dma_unmap_single(&efx->pci_dev->dev, rx_buf->dma_addr,
- rx_buf->len, DMA_FROM_DEVICE);
+ struct page *page = rx_buf->page;
+
+ if (page) {
+ struct efx_rx_page_state *state = page_address(page);
+ dma_unmap_page(&efx->pci_dev->dev,
+ state->dma_addr,
+ PAGE_SIZE << efx->rx_buffer_order,
+ DMA_FROM_DEVICE);
}
}
-static void efx_free_rx_buffer(struct efx_nic *efx,
- struct efx_rx_buffer *rx_buf)
+static void efx_free_rx_buffer(struct efx_rx_buffer *rx_buf)
{
- if ((rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.page) {
- __free_pages(rx_buf->u.page, efx->rx_buffer_order);
- rx_buf->u.page = NULL;
- } else if (!(rx_buf->flags & EFX_RX_BUF_PAGE) && rx_buf->u.skb) {
- dev_kfree_skb_any(rx_buf->u.skb);
- rx_buf->u.skb = NULL;
+ if (rx_buf->page) {
+ put_page(rx_buf->page);
+ rx_buf->page = NULL;
}
}
-static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
+/* Attempt to recycle the page if there is an RX recycle ring; the page can
+ * only be added if this is the final RX buffer, to prevent pages being used in
+ * the descriptor ring and appearing in the recycle ring simultaneously.
+ */
+static void efx_recycle_rx_page(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
{
- efx_unmap_rx_buffer(rx_queue->efx, rx_buf, 0);
- efx_free_rx_buffer(rx_queue->efx, rx_buf);
-}
+ struct page *page = rx_buf->page;
+ struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned index;
-/* Attempt to resurrect the other receive buffer that used to share this page,
- * which had previously been passed up to the kernel and freed. */
-static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
-{
- struct efx_rx_page_state *state = page_address(rx_buf->u.page);
- struct efx_rx_buffer *new_buf;
- unsigned fill_level, index;
-
- /* +1 because efx_rx_packet() incremented removed_count. +1 because
- * we'd like to insert an additional descriptor whilst leaving
- * EFX_RXD_HEAD_ROOM for the non-recycle path */
- fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
- if (unlikely(fill_level > rx_queue->max_fill)) {
- /* We could place "state" on a list, and drain the list in
- * efx_fast_push_rx_descriptors(). For now, this will do. */
+ /* Only recycle the page after processing the final buffer. */
+ if (!(rx_buf->flags & EFX_RX_BUF_LAST_IN_PAGE))
return;
- }
- ++state->refcnt;
- get_page(rx_buf->u.page);
+ index = rx_queue->page_add & rx_queue->page_ptr_mask;
+ if (rx_queue->page_ring[index] == NULL) {
+ unsigned read_index = rx_queue->page_remove &
+ rx_queue->page_ptr_mask;
- index = rx_queue->added_count & rx_queue->ptr_mask;
- new_buf = efx_rx_buffer(rx_queue, index);
- new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
- new_buf->u.page = rx_buf->u.page;
- new_buf->len = rx_buf->len;
- new_buf->flags = EFX_RX_BUF_PAGE;
- ++rx_queue->added_count;
+ /* The next slot in the recycle ring is available, but
+ * increment page_remove if the read pointer currently
+ * points here.
+ */
+ if (read_index == index)
+ ++rx_queue->page_remove;
+ rx_queue->page_ring[index] = page;
+ ++rx_queue->page_add;
+ return;
+ }
+ ++rx_queue->page_recycle_full;
+ efx_unmap_rx_buffer(efx, rx_buf);
+ put_page(rx_buf->page);
}
-/* Recycle the given rx buffer directly back into the rx_queue. There is
- * always room to add this buffer, because we've just popped a buffer. */
-static void efx_recycle_rx_buffer(struct efx_channel *channel,
- struct efx_rx_buffer *rx_buf)
+static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
{
- struct efx_nic *efx = channel->efx;
- struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
- struct efx_rx_buffer *new_buf;
- unsigned index;
-
- rx_buf->flags &= EFX_RX_BUF_PAGE;
-
- if ((rx_buf->flags & EFX_RX_BUF_PAGE) &&
- efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
- page_count(rx_buf->u.page) == 1)
- efx_resurrect_rx_buffer(rx_queue, rx_buf);
+ /* Release the page reference we hold for the buffer. */
+ if (rx_buf->page)
+ put_page(rx_buf->page);
+
+ /* If this is the last buffer in a page, unmap and free it. */
+ if (rx_buf->flags & EFX_RX_BUF_LAST_IN_PAGE) {
+ efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
+ efx_free_rx_buffer(rx_buf);
+ }
+ rx_buf->page = NULL;
+}
- index = rx_queue->added_count & rx_queue->ptr_mask;
- new_buf = efx_rx_buffer(rx_queue, index);
+/* Recycle the pages that are used by buffers that have just been received. */
+static void efx_recycle_rx_buffers(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf,
+ unsigned int n_frags)
+{
+ struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
- memcpy(new_buf, rx_buf, sizeof(*new_buf));
- rx_buf->u.page = NULL;
- ++rx_queue->added_count;
+ do {
+ efx_recycle_rx_page(channel, rx_buf);
+ rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
+ } while (--n_frags);
}
/**
@@ -348,8 +308,8 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
*/
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
- struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
- unsigned fill_level;
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int fill_level, batch_size;
int space, rc = 0;
/* Calculate current fill level, and exit if we don't need to fill */
@@ -364,28 +324,26 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
rx_queue->min_fill = fill_level;
}
+ batch_size = efx->rx_pages_per_batch * efx->rx_bufs_per_page;
space = rx_queue->max_fill - fill_level;
- EFX_BUG_ON_PARANOID(space < EFX_RX_BATCH);
+ EFX_BUG_ON_PARANOID(space < batch_size);
netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
"RX queue %d fast-filling descriptor ring from"
- " level %d to level %d using %s allocation\n",
+ " level %d to level %d\n",
efx_rx_queue_index(rx_queue), fill_level,
- rx_queue->max_fill,
- channel->rx_alloc_push_pages ? "page" : "skb");
+ rx_queue->max_fill);
+
do {
- if (channel->rx_alloc_push_pages)
- rc = efx_init_rx_buffers_page(rx_queue);
- else
- rc = efx_init_rx_buffers_skb(rx_queue);
+ rc = efx_init_rx_buffers(rx_queue);
if (unlikely(rc)) {
/* Ensure that we don't leave the rx queue empty */
if (rx_queue->added_count == rx_queue->removed_count)
efx_schedule_slow_fill(rx_queue);
goto out;
}
- } while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
+ } while ((space -= batch_size) >= batch_size);
netif_vdbg(rx_queue->efx, rx_status, rx_queue->efx->net_dev,
"RX queue %d fast-filled descriptor ring "
@@ -408,7 +366,7 @@ void efx_rx_slow_fill(unsigned long context)
static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf,
- int len, bool *leak_packet)
+ int len)
{
struct efx_nic *efx = rx_queue->efx;
unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
@@ -428,11 +386,6 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
"RX event (0x%x > 0x%x+0x%x). Leaking\n",
efx_rx_queue_index(rx_queue), len, max_len,
efx->type->rx_buffer_padding);
- /* If this buffer was skb-allocated, then the meta
- * data at the end of the skb will be trashed. So
- * we have no choice but to leak the fragment.
- */
- *leak_packet = !(rx_buf->flags & EFX_RX_BUF_PAGE);
efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
} else {
if (net_ratelimit())
@@ -448,212 +401,238 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
/* Pass a received packet up through GRO. GRO can handle pages
* regardless of checksum state and skbs with a good checksum.
*/
-static void efx_rx_packet_gro(struct efx_channel *channel,
- struct efx_rx_buffer *rx_buf,
- const u8 *eh)
+static void
+efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
+ unsigned int n_frags, u8 *eh)
{
struct napi_struct *napi = &channel->napi_str;
gro_result_t gro_result;
+ struct efx_nic *efx = channel->efx;
+ struct sk_buff *skb;
- if (rx_buf->flags & EFX_RX_BUF_PAGE) {
- struct efx_nic *efx = channel->efx;
- struct page *page = rx_buf->u.page;
- struct sk_buff *skb;
+ skb = napi_get_frags(napi);
+ if (unlikely(!skb)) {
+ while (n_frags--) {
+ put_page(rx_buf->page);
+ rx_buf->page = NULL;
+ rx_buf = efx_rx_buf_next(&channel->rx_queue, rx_buf);
+ }
+ return;
+ }
- rx_buf->u.page = NULL;
+ if (efx->net_dev->features & NETIF_F_RXHASH)
+ skb->rxhash = efx_rx_buf_hash(eh);
+ skb->ip_summed = ((rx_buf->flags & EFX_RX_PKT_CSUMMED) ?
+ CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
+
+ for (;;) {
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ rx_buf->page, rx_buf->page_offset,
+ rx_buf->len);
+ rx_buf->page = NULL;
+ skb->len += rx_buf->len;
+ if (skb_shinfo(skb)->nr_frags == n_frags)
+ break;
+
+ rx_buf = efx_rx_buf_next(&channel->rx_queue, rx_buf);
+ }
- skb = napi_get_frags(napi);
- if (!skb) {
- put_page(page);
- return;
- }
+ skb->data_len = skb->len;
+ skb->truesize += n_frags * efx->rx_buffer_truesize;
+
+ skb_record_rx_queue(skb, channel->rx_queue.core_index);
+
+ gro_result = napi_gro_frags(napi);
+ if (gro_result != GRO_DROP)
+ channel->irq_mod_score += 2;
+}
- if (efx->net_dev->features & NETIF_F_RXHASH)
- skb->rxhash = efx_rx_buf_hash(eh);
+/* Allocate and construct an SKB around page fragments */
+static struct sk_buff *efx_rx_mk_skb(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf,
+ unsigned int n_frags,
+ u8 *eh, int hdr_len)
+{
+ struct efx_nic *efx = channel->efx;
+ struct sk_buff *skb;
- skb_fill_page_desc(skb, 0, page,
- efx_rx_buf_offset(efx, rx_buf), rx_buf->len);
+ /* Allocate an SKB to store the headers */
+ skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
+ if (unlikely(skb == NULL))
+ return NULL;
- skb->len = rx_buf->len;
- skb->data_len = rx_buf->len;
- skb->truesize += rx_buf->len;
- skb->ip_summed = ((rx_buf->flags & EFX_RX_PKT_CSUMMED) ?
- CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
+ EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
- skb_record_rx_queue(skb, channel->rx_queue.core_index);
+ skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
+ memcpy(__skb_put(skb, hdr_len), eh, hdr_len);
- gro_result = napi_gro_frags(napi);
- } else {
- struct sk_buff *skb = rx_buf->u.skb;
+ /* Append the remaining page(s) onto the frag list */
+ if (rx_buf->len > hdr_len) {
+ rx_buf->page_offset += hdr_len;
+ rx_buf->len -= hdr_len;
- EFX_BUG_ON_PARANOID(!(rx_buf->flags & EFX_RX_PKT_CSUMMED));
- rx_buf->u.skb = NULL;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ for (;;) {
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ rx_buf->page, rx_buf->page_offset,
+ rx_buf->len);
+ rx_buf->page = NULL;
+ skb->len += rx_buf->len;
+ skb->data_len += rx_buf->len;
+ if (skb_shinfo(skb)->nr_frags == n_frags)
+ break;
- gro_result = napi_gro_receive(napi, skb);
+ rx_buf = efx_rx_buf_next(&channel->rx_queue, rx_buf);
+ }
+ } else {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ n_frags = 0;
}
- if (gro_result == GRO_NORMAL) {
- channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
- } else if (gro_result != GRO_DROP) {
- channel->rx_alloc_level += RX_ALLOC_FACTOR_GRO;
- channel->irq_mod_score += 2;
- }
+ skb->truesize += n_frags * efx->rx_buffer_truesize;
+
+ /* Move past the ethernet header */
+ skb->protocol = eth_type_trans(skb, efx->net_dev);
+
+ return skb;
}
void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
- unsigned int len, u16 flags)
+ unsigned int n_frags, unsigned int len, u16 flags)
{
struct efx_nic *efx = rx_queue->efx;
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
struct efx_rx_buffer *rx_buf;
- bool leak_packet = false;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->flags |= flags;
- /* This allows the refill path to post another buffer.
- * EFX_RXD_HEAD_ROOM ensures that the slot we are using
- * isn't overwritten yet.
- */
- rx_queue->removed_count++;
-
- /* Validate the length encoded in the event vs the descriptor pushed */
- efx_rx_packet__check_len(rx_queue, rx_buf, len, &leak_packet);
+ /* Validate the number of fragments and completed length */
+ if (n_frags == 1) {
+ efx_rx_packet__check_len(rx_queue, rx_buf, len);
+ } else if (unlikely(n_frags > EFX_RX_MAX_FRAGS) ||
+ unlikely(len <= (n_frags - 1) * EFX_RX_USR_BUF_SIZE) ||
+ unlikely(len > n_frags * EFX_RX_USR_BUF_SIZE) ||
+ unlikely(!efx->rx_scatter)) {
+ /* If this isn't an explicit discard request, either
+ * the hardware or the driver is broken.
+ */
+ WARN_ON(!(len == 0 && rx_buf->flags & EFX_RX_PKT_DISCARD));
+ rx_buf->flags |= EFX_RX_PKT_DISCARD;
+ }
netif_vdbg(efx, rx_status, efx->net_dev,
- "RX queue %d received id %x at %llx+%x %s%s\n",
+ "RX queue %d received ids %x-%x len %d %s%s\n",
efx_rx_queue_index(rx_queue), index,
- (unsigned long long)rx_buf->dma_addr, len,
+ (index + n_frags - 1) & rx_queue->ptr_mask, len,
(rx_buf->flags & EFX_RX_PKT_CSUMMED) ? " [SUMMED]" : "",
(rx_buf->flags & EFX_RX_PKT_DISCARD) ? " [DISCARD]" : "");
- /* Discard packet, if instructed to do so */
+ /* Discard packet, if instructed to do so. Process the
+ * previous receive first.
+ */
if (unlikely(rx_buf->flags & EFX_RX_PKT_DISCARD)) {
- if (unlikely(leak_packet))
- channel->n_skbuff_leaks++;
- else
- efx_recycle_rx_buffer(channel, rx_buf);
-
- /* Don't hold off the previous receive */
- rx_buf = NULL;
- goto out;
+ efx_rx_flush_packet(channel);
+ put_page(rx_buf->page);
+ efx_recycle_rx_buffers(channel, rx_buf, n_frags);
+ return;
}
- /* Release and/or sync DMA mapping - assumes all RX buffers
- * consumed in-order per RX queue
+ if (n_frags == 1)
+ rx_buf->len = len;
+
+ /* Release and/or sync the DMA mapping - assumes all RX buffers
+ * consumed in-order per RX queue.
*/
- efx_unmap_rx_buffer(efx, rx_buf, len);
+ efx_sync_rx_buffer(efx, rx_buf, rx_buf->len);
/* Prefetch nice and early so data will (hopefully) be in cache by
* the time we look at it.
*/
- prefetch(efx_rx_buf_eh(efx, rx_buf));
+ prefetch(efx_rx_buf_va(rx_buf));
+
+ rx_buf->page_offset += efx->type->rx_buffer_hash_size;
+ rx_buf->len -= efx->type->rx_buffer_hash_size;
+
+ if (n_frags > 1) {
+ /* Release/sync DMA mapping for additional fragments.
+ * Fix length for last fragment.
+ */
+ unsigned int tail_frags = n_frags - 1;
+
+ for (;;) {
+ rx_buf = efx_rx_buf_next(rx_queue, rx_buf);
+ if (--tail_frags == 0)
+ break;
+ efx_sync_rx_buffer(efx, rx_buf, EFX_RX_USR_BUF_SIZE);
+ }
+ rx_buf->len = len - (n_frags - 1) * EFX_RX_USR_BUF_SIZE;
+ efx_sync_rx_buffer(efx, rx_buf, rx_buf->len);
+ }
+
+ /* All fragments have been DMA-synced, so recycle buffers and pages. */
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ efx_recycle_rx_buffers(channel, rx_buf, n_frags);
/* Pipeline receives so that we give time for packet headers to be
* prefetched into cache.
*/
- rx_buf->len = len - efx->type->rx_buffer_hash_size;
-out:
- if (channel->rx_pkt)
- __efx_rx_packet(channel, channel->rx_pkt);
- channel->rx_pkt = rx_buf;
+ efx_rx_flush_packet(channel);
+ channel->rx_pkt_n_frags = n_frags;
+ channel->rx_pkt_index = index;
}
-static void efx_rx_deliver(struct efx_channel *channel,
- struct efx_rx_buffer *rx_buf)
+static void efx_rx_deliver(struct efx_channel *channel, u8 *eh,
+ struct efx_rx_buffer *rx_buf,
+ unsigned int n_frags)
{
struct sk_buff *skb;
+ u16 hdr_len = min_t(u16, rx_buf->len, EFX_SKB_HEADERS);
- /* We now own the SKB */
- skb = rx_buf->u.skb;
- rx_buf->u.skb = NULL;
+ skb = efx_rx_mk_skb(channel, rx_buf, n_frags, eh, hdr_len);
+ if (unlikely(skb == NULL)) {
+ efx_free_rx_buffer(rx_buf);
+ return;
+ }
+ skb_record_rx_queue(skb, channel->rx_queue.core_index);
/* Set the SKB flags */
skb_checksum_none_assert(skb);
- /* Record the rx_queue */
- skb_record_rx_queue(skb, channel->rx_queue.core_index);
-
- /* Pass the packet up */
if (channel->type->receive_skb)
- channel->type->receive_skb(channel, skb);
- else
- netif_receive_skb(skb);
+ if (channel->type->receive_skb(channel, skb))
+ return;
- /* Update allocation strategy method */
- channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ /* Pass the packet up */
+ netif_receive_skb(skb);
}
/* Handle a received packet. Second half: Touches packet payload. */
-void __efx_rx_packet(struct efx_channel *channel, struct efx_rx_buffer *rx_buf)
+void __efx_rx_packet(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
- u8 *eh = efx_rx_buf_eh(efx, rx_buf);
+ struct efx_rx_buffer *rx_buf =
+ efx_rx_buffer(&channel->rx_queue, channel->rx_pkt_index);
+ u8 *eh = efx_rx_buf_va(rx_buf);
/* If we're in loopback test, then pass the packet directly to the
* loopback layer, and free the rx_buf here
*/
if (unlikely(efx->loopback_selftest)) {
efx_loopback_rx_packet(efx, eh, rx_buf->len);
- efx_free_rx_buffer(efx, rx_buf);
- return;
- }
-
- if (!(rx_buf->flags & EFX_RX_BUF_PAGE)) {
- struct sk_buff *skb = rx_buf->u.skb;
-
- prefetch(skb_shinfo(skb));
-
- skb_reserve(skb, efx->type->rx_buffer_hash_size);
- skb_put(skb, rx_buf->len);
-
- if (efx->net_dev->features & NETIF_F_RXHASH)
- skb->rxhash = efx_rx_buf_hash(eh);
-
- /* Move past the ethernet header. rx_buf->data still points
- * at the ethernet header */
- skb->protocol = eth_type_trans(skb, efx->net_dev);
-
- skb_record_rx_queue(skb, channel->rx_queue.core_index);
+ efx_free_rx_buffer(rx_buf);
+ goto out;
}
if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM)))
rx_buf->flags &= ~EFX_RX_PKT_CSUMMED;
- if (likely(rx_buf->flags & (EFX_RX_BUF_PAGE | EFX_RX_PKT_CSUMMED)) &&
- !channel->type->receive_skb)
- efx_rx_packet_gro(channel, rx_buf, eh);
+ if (!channel->type->receive_skb)
+ efx_rx_packet_gro(channel, rx_buf, channel->rx_pkt_n_frags, eh);
else
- efx_rx_deliver(channel, rx_buf);
-}
-
-void efx_rx_strategy(struct efx_channel *channel)
-{
- enum efx_rx_alloc_method method = rx_alloc_method;
-
- if (channel->type->receive_skb) {
- channel->rx_alloc_push_pages = false;
- return;
- }
-
- /* Only makes sense to use page based allocation if GRO is enabled */
- if (!(channel->efx->net_dev->features & NETIF_F_GRO)) {
- method = RX_ALLOC_METHOD_SKB;
- } else if (method == RX_ALLOC_METHOD_AUTO) {
- /* Constrain the rx_alloc_level */
- if (channel->rx_alloc_level < 0)
- channel->rx_alloc_level = 0;
- else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
- channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
-
- /* Decide on the allocation method */
- method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_GRO) ?
- RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
- }
-
- /* Push the option */
- channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
+ efx_rx_deliver(channel, eh, rx_buf, channel->rx_pkt_n_frags);
+out:
+ channel->rx_pkt_n_frags = 0;
}
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
@@ -683,9 +662,32 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
kfree(rx_queue->buffer);
rx_queue->buffer = NULL;
}
+
return rc;
}
+static void efx_init_rx_recycle_ring(struct efx_nic *efx,
+ struct efx_rx_queue *rx_queue)
+{
+ unsigned int bufs_in_recycle_ring, page_ring_size;
+
+ /* Set the RX recycle ring size */
+#ifdef CONFIG_PPC64
+ bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_IOMMU;
+#else
+ if (efx->pci_dev->dev.iommu_group)
+ bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_IOMMU;
+ else
+ bufs_in_recycle_ring = EFX_RECYCLE_RING_SIZE_NOIOMMU;
+#endif /* CONFIG_PPC64 */
+
+ page_ring_size = roundup_pow_of_two(bufs_in_recycle_ring /
+ efx->rx_bufs_per_page);
+ rx_queue->page_ring = kcalloc(page_ring_size,
+ sizeof(*rx_queue->page_ring), GFP_KERNEL);
+ rx_queue->page_ptr_mask = page_ring_size - 1;
+}
+
void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
@@ -699,10 +701,18 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
rx_queue->notified_count = 0;
rx_queue->removed_count = 0;
rx_queue->min_fill = -1U;
+ efx_init_rx_recycle_ring(efx, rx_queue);
+
+ rx_queue->page_remove = 0;
+ rx_queue->page_add = rx_queue->page_ptr_mask + 1;
+ rx_queue->page_recycle_count = 0;
+ rx_queue->page_recycle_failed = 0;
+ rx_queue->page_recycle_full = 0;
/* Initialise limit fields */
max_fill = efx->rxq_entries - EFX_RXD_HEAD_ROOM;
- max_trigger = max_fill - EFX_RX_BATCH;
+ max_trigger =
+ max_fill - efx->rx_pages_per_batch * efx->rx_bufs_per_page;
if (rx_refill_threshold != 0) {
trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
if (trigger > max_trigger)
@@ -722,6 +732,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
{
int i;
+ struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
@@ -733,13 +744,32 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
- /* Release RX buffers NB start at index 0 not current HW ptr */
+ /* Release RX buffers from the current read ptr to the write ptr */
if (rx_queue->buffer) {
- for (i = 0; i <= rx_queue->ptr_mask; i++) {
- rx_buf = efx_rx_buffer(rx_queue, i);
+ for (i = rx_queue->removed_count; i < rx_queue->added_count;
+ i++) {
+ unsigned index = i & rx_queue->ptr_mask;
+ rx_buf = efx_rx_buffer(rx_queue, index);
efx_fini_rx_buffer(rx_queue, rx_buf);
}
}
+
+ /* Unmap and release the pages in the recycle ring. Remove the ring. */
+ for (i = 0; i <= rx_queue->page_ptr_mask; i++) {
+ struct page *page = rx_queue->page_ring[i];
+ struct efx_rx_page_state *state;
+
+ if (page == NULL)
+ continue;
+
+ state = page_address(page);
+ dma_unmap_page(&efx->pci_dev->dev, state->dma_addr,
+ PAGE_SIZE << efx->rx_buffer_order,
+ DMA_FROM_DEVICE);
+ put_page(page);
+ }
+ kfree(rx_queue->page_ring);
+ rx_queue->page_ring = NULL;
}
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
@@ -754,9 +784,6 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
}
-module_param(rx_alloc_method, int, 0644);
-MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
-
module_param(rx_refill_threshold, uint, 0444);
MODULE_PARM_DESC(rx_refill_threshold,
"RX descriptor ring refill threshold (%)");
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index ba40f67e4f05..51669244d154 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -202,7 +202,7 @@ out:
static enum reset_type siena_map_reset_reason(enum reset_type reason)
{
- return RESET_TYPE_ALL;
+ return RESET_TYPE_RECOVER_OR_ALL;
}
static int siena_map_reset_flags(u32 *flags)
@@ -245,6 +245,22 @@ static int siena_reset_hw(struct efx_nic *efx, enum reset_type method)
return efx_mcdi_reset_port(efx);
}
+#ifdef CONFIG_EEH
+/* When a PCI device is isolated from the bus, a subsequent MMIO read is
+ * required for the kernel EEH mechanisms to notice. As the Solarflare driver
+ * was written to minimise MMIO read (for latency) then a periodic call to check
+ * the EEH status of the device is required so that device recovery can happen
+ * in a timely fashion.
+ */
+static void siena_monitor(struct efx_nic *efx)
+{
+ struct eeh_dev *eehdev =
+ of_node_to_eeh_dev(pci_device_to_OF_node(efx->pci_dev));
+
+ eeh_dev_check_failure(eehdev);
+}
+#endif
+
static int siena_probe_nvconfig(struct efx_nic *efx)
{
u32 caps = 0;
@@ -398,6 +414,8 @@ static int siena_init_nic(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_INSRT_HDR, 1);
EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_HASH_ALG, 1);
EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_IP_HASH, 1);
+ EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_USR_BUF_SIZE,
+ EFX_RX_USR_BUF_SIZE >> 5);
efx_writeo(efx, &temp, FR_AZ_RX_CFG);
/* Set hash key for IPv4 */
@@ -665,7 +683,11 @@ const struct efx_nic_type siena_a0_nic_type = {
.init = siena_init_nic,
.dimension_resources = siena_dimension_resources,
.fini = efx_port_dummy_op_void,
+#ifdef CONFIG_EEH
+ .monitor = siena_monitor,
+#else
.monitor = NULL,
+#endif
.map_reset_reason = siena_map_reset_reason,
.map_reset_flags = siena_map_reset_flags,
.reset = siena_reset_hw,
@@ -698,6 +720,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH),
.rx_buffer_hash_size = 0x10,
.rx_buffer_padding = 0,
+ .can_rx_scatter = true,
.max_interrupt_mode = EFX_INT_MODE_MSIX,
.phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
* interrupt handler only supports 32
diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c
index 79ad9c94a21b..4bdbaad9932d 100644
--- a/drivers/net/ethernet/sgi/meth.c
+++ b/drivers/net/ethernet/sgi/meth.c
@@ -213,10 +213,11 @@ static int meth_init_tx_ring(struct meth_private *priv)
{
/* Init TX ring */
priv->tx_ring = dma_alloc_coherent(NULL, TX_RING_BUFFER_SIZE,
- &priv->tx_ring_dma, GFP_ATOMIC);
+ &priv->tx_ring_dma,
+ GFP_ATOMIC | __GFP_ZERO);
if (!priv->tx_ring)
return -ENOMEM;
- memset(priv->tx_ring, 0, TX_RING_BUFFER_SIZE);
+
priv->tx_count = priv->tx_read = priv->tx_write = 0;
mace->eth.tx_ring_base = priv->tx_ring_dma;
/* Now init skb save area */
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index efca14eaefa9..eb4aea3fe793 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -1187,8 +1187,14 @@ sis900_init_rx_ring(struct net_device *net_dev)
}
sis_priv->rx_skbuff[i] = skb;
sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;
- sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,
- skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,
+ skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
+ sis_priv->rx_ring[i].bufptr))) {
+ dev_kfree_skb(skb);
+ sis_priv->rx_skbuff[i] = NULL;
+ break;
+ }
}
sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);
@@ -1621,6 +1627,14 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
/* set the transmit buffer descriptor and enable Transmit State Machine */
sis_priv->tx_ring[entry].bufptr = pci_map_single(sis_priv->pci_dev,
skb->data, skb->len, PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
+ sis_priv->tx_ring[entry].bufptr))) {
+ dev_kfree_skb(skb);
+ sis_priv->tx_skbuff[entry] = NULL;
+ net_dev->stats.tx_dropped++;
+ spin_unlock_irqrestore(&sis_priv->lock, flags);
+ return NETDEV_TX_OK;
+ }
sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
sw32(cr, TxENA | sr32(cr));
@@ -1824,9 +1838,15 @@ static int sis900_rx(struct net_device *net_dev)
refill_rx_ring:
sis_priv->rx_skbuff[entry] = skb;
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
- sis_priv->rx_ring[entry].bufptr =
+ sis_priv->rx_ring[entry].bufptr =
pci_map_single(sis_priv->pci_dev, skb->data,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
+ sis_priv->rx_ring[entry].bufptr))) {
+ dev_kfree_skb_irq(skb);
+ sis_priv->rx_skbuff[entry] = NULL;
+ break;
+ }
}
sis_priv->cur_rx++;
entry = sis_priv->cur_rx % NUM_RX_DESC;
@@ -1841,23 +1861,26 @@ refill_rx_ring:
entry = sis_priv->dirty_rx % NUM_RX_DESC;
if (sis_priv->rx_skbuff[entry] == NULL) {
- if ((skb = netdev_alloc_skb(net_dev, RX_BUF_SIZE)) == NULL) {
+ skb = netdev_alloc_skb(net_dev, RX_BUF_SIZE);
+ if (skb == NULL) {
/* not enough memory for skbuff, this makes a
* "hole" on the buffer ring, it is not clear
* how the hardware will react to this kind
* of degenerated buffer */
- if (netif_msg_rx_err(sis_priv))
- printk(KERN_INFO "%s: Memory squeeze, "
- "deferring packet.\n",
- net_dev->name);
net_dev->stats.rx_dropped++;
break;
}
sis_priv->rx_skbuff[entry] = skb;
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
- sis_priv->rx_ring[entry].bufptr =
+ sis_priv->rx_ring[entry].bufptr =
pci_map_single(sis_priv->pci_dev, skb->data,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
+ sis_priv->rx_ring[entry].bufptr))) {
+ dev_kfree_skb_irq(skb);
+ sis_priv->rx_skbuff[entry] = NULL;
+ break;
+ }
}
}
/* re-enable the potentially idle receive state matchine */
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index 5a689af516e9..bb4c1674ff99 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_SMSC
bool "SMC (SMSC)/Western Digital devices"
default y
- depends on ARM || ISA || MAC || ARM || MIPS || M32R || SUPERH || \
+ depends on ARM || ISA || MAC || ARM64 || MIPS || M32R || SUPERH || \
BLACKFIN || MN10300 || COLDFIRE || PCI || PCMCIA
---help---
If you have a network (Ethernet) card belonging to this class, say Y
@@ -40,7 +40,7 @@ config SMC91X
select NET_CORE
select MII
depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
- MN10300 || COLDFIRE)
+ MN10300 || COLDFIRE || ARM64)
---help---
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c
index 50823da9dc1e..e85c2e7e8246 100644
--- a/drivers/net/ethernet/smsc/smc9194.c
+++ b/drivers/net/ethernet/smsc/smc9194.c
@@ -1223,9 +1223,7 @@ static void smc_rcv(struct net_device *dev)
dev->stats.multicast++;
skb = netdev_alloc_skb(dev, packet_length + 5);
-
if ( skb == NULL ) {
- printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
dev->stats.rx_dropped++;
goto done;
}
diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c
index 04393b5fef71..656d2e2ebfc9 100644
--- a/drivers/net/ethernet/smsc/smc91c92_cs.c
+++ b/drivers/net/ethernet/smsc/smc91c92_cs.c
@@ -2054,16 +2054,4 @@ static struct pcmcia_driver smc91c92_cs_driver = {
.suspend = smc91c92_suspend,
.resume = smc91c92_resume,
};
-
-static int __init init_smc91c92_cs(void)
-{
- return pcmcia_register_driver(&smc91c92_cs_driver);
-}
-
-static void __exit exit_smc91c92_cs(void)
-{
- pcmcia_unregister_driver(&smc91c92_cs_driver);
-}
-
-module_init(init_smc91c92_cs);
-module_exit(exit_smc91c92_cs);
+module_pcmcia_driver(smc91c92_cs_driver);
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 591650a8de38..dfbf978315df 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -465,8 +465,6 @@ static inline void smc_rcv(struct net_device *dev)
*/
skb = netdev_alloc_skb(dev, packet_len);
if (unlikely(skb == NULL)) {
- printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
- dev->name);
SMC_WAIT_MMU_BUSY(lp);
SMC_SET_MMU_CMD(lp, MC_RELEASE);
dev->stats.rx_dropped++;
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index da5cc9a3b34c..48e2b99bec51 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -2115,7 +2115,7 @@ static int smsc911x_init(struct net_device *dev)
spin_lock_init(&pdata->dev_lock);
spin_lock_init(&pdata->mac_lock);
- if (pdata->ioaddr == 0) {
+ if (pdata->ioaddr == NULL) {
SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000");
return -ENODEV;
}
diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c
index d457fa2d7509..ffa5c4ad1210 100644
--- a/drivers/net/ethernet/smsc/smsc9420.c
+++ b/drivers/net/ethernet/smsc/smsc9420.c
@@ -848,10 +848,8 @@ static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index)
BUG_ON(pd->rx_buffers[index].skb);
BUG_ON(pd->rx_buffers[index].mapping);
- if (unlikely(!skb)) {
- smsc_warn(RX_ERR, "Failed to allocate new skb!");
+ if (unlikely(!skb))
return -ENOMEM;
- }
mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb),
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index c0ea838c78d1..f695a50bac47 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -5,6 +5,7 @@ config STMMAC_ETH
select MII
select PHYLIB
select CRC32
+ select PTP_1588_CLOCK
---help---
This is the driver for the Ethernet IPs are built around a
Synopsys IP Core and only tested on the STMicroelectronics
@@ -54,22 +55,4 @@ config STMMAC_DA
By default, the DMA arbitration scheme is based on Round-robin
(rx:tx priority is 1:1).
-choice
- prompt "Select the DMA TX/RX descriptor operating modes"
- depends on STMMAC_ETH
- ---help---
- This driver supports DMA descriptor to operate both in dual buffer
- (RING) and linked-list(CHAINED) mode. In RING mode each descriptor
- points to two data buffer pointers whereas in CHAINED mode they
- points to only one data buffer pointer.
-
-config STMMAC_RING
- bool "Enable Descriptor Ring Mode"
-
-config STMMAC_CHAINED
- bool "Enable Descriptor Chained Mode"
-
-endchoice
-
-
endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c8e8ea60ac19..356a9dd32be7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -1,9 +1,7 @@
obj-$(CONFIG_STMMAC_ETH) += stmmac.o
-stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
-stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
- dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
+stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
+ chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
- mmc_core.o $(stmmac-y)
+ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 0668659803ed..d234ab540b29 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -28,9 +28,9 @@
#include "stmmac.h"
-unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
- struct stmmac_priv *priv = (struct stmmac_priv *) p;
+ struct stmmac_priv *priv = (struct stmmac_priv *)p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
struct dma_desc *desc = priv->dma_tx + entry;
@@ -47,7 +47,8 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
- priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
+ priv->tx_skbuff_dma[entry] = desc->des2;
+ priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
while (len != 0) {
entry = (++priv->cur_tx) % txsize;
@@ -57,8 +58,9 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
- priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
- csum);
+ priv->tx_skbuff_dma[entry] = desc->des2;
+ priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
+ STMMAC_CHAIN_MODE);
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
len -= bmax;
@@ -67,8 +69,9 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
- priv->hw->desc->prepare_tx_desc(desc, 0, len,
- csum);
+ priv->tx_skbuff_dma[entry] = desc->des2;
+ priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+ STMMAC_CHAIN_MODE);
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
len = 0;
@@ -89,49 +92,70 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
-{
-}
-
-static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
-{
-}
-
-static void stmmac_clean_desc3(struct dma_desc *p)
-{
-}
-
-static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
- unsigned int size)
+static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
+ unsigned int size, unsigned int extend_desc)
{
/*
* In chained mode the des3 points to the next element in the ring.
* The latest element has to point to the head.
*/
int i;
- struct dma_desc *p = des;
dma_addr_t dma_phy = phy_addr;
- for (i = 0; i < (size - 1); i++) {
- dma_phy += sizeof(struct dma_desc);
- p->des3 = (unsigned int)dma_phy;
- p++;
+ if (extend_desc) {
+ struct dma_extended_desc *p = (struct dma_extended_desc *)des;
+ for (i = 0; i < (size - 1); i++) {
+ dma_phy += sizeof(struct dma_extended_desc);
+ p->basic.des3 = (unsigned int)dma_phy;
+ p++;
+ }
+ p->basic.des3 = (unsigned int)phy_addr;
+
+ } else {
+ struct dma_desc *p = (struct dma_desc *)des;
+ for (i = 0; i < (size - 1); i++) {
+ dma_phy += sizeof(struct dma_desc);
+ p->des3 = (unsigned int)dma_phy;
+ p++;
+ }
+ p->des3 = (unsigned int)phy_addr;
}
- p->des3 = (unsigned int)phy_addr;
}
-static int stmmac_set_16kib_bfsize(int mtu)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
+{
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (priv->hwts_rx_en && !priv->extend_desc)
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_rx_phy +
+ (((priv->dirty_rx) + 1) %
+ priv->dma_rx_size) *
+ sizeof(struct dma_desc));
+}
+
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
{
- /* Not supported */
- return 0;
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_tx_phy +
+ (((priv->dirty_tx + 1) %
+ priv->dma_tx_size) *
+ sizeof(struct dma_desc)));
}
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_chain_mode_ops chain_mode_ops = {
+ .init = stmmac_init_dma_chain,
.is_jumbo_frm = stmmac_is_jumbo_frm,
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
- .init_desc3 = stmmac_init_desc3,
- .init_dma_chain = stmmac_init_dma_chain,
.clean_desc3 = stmmac_clean_desc3,
- .set_16kib_bfsize = stmmac_set_16kib_bfsize,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 186d14806122..7788fbe44f0a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -117,6 +117,36 @@ struct stmmac_extra_stats {
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
+ /* Extended RDES status */
+ unsigned long ip_hdr_err;
+ unsigned long ip_payload_err;
+ unsigned long ip_csum_bypassed;
+ unsigned long ipv4_pkt_rcvd;
+ unsigned long ipv6_pkt_rcvd;
+ unsigned long rx_msg_type_ext_no_ptp;
+ unsigned long rx_msg_type_sync;
+ unsigned long rx_msg_type_follow_up;
+ unsigned long rx_msg_type_delay_req;
+ unsigned long rx_msg_type_delay_resp;
+ unsigned long rx_msg_type_pdelay_req;
+ unsigned long rx_msg_type_pdelay_resp;
+ unsigned long rx_msg_type_pdelay_follow_up;
+ unsigned long ptp_frame_type;
+ unsigned long ptp_ver;
+ unsigned long timestamp_dropped;
+ unsigned long av_pkt_rcvd;
+ unsigned long av_tagged_pkt_rcvd;
+ unsigned long vlan_tag_priority_val;
+ unsigned long l3_filter_match;
+ unsigned long l4_filter_match;
+ unsigned long l3_l4_filter_no_match;
+ /* PCS */
+ unsigned long irq_pcs_ane_n;
+ unsigned long irq_pcs_link_n;
+ unsigned long irq_rgmii_n;
+ unsigned long pcs_link;
+ unsigned long pcs_duplex;
+ unsigned long pcs_speed;
};
/* CSR Frequency Access Defines*/
@@ -138,37 +168,43 @@ struct stmmac_extra_stats {
#define FLOW_TX 2
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
-#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
+/* PCS defines */
+#define STMMAC_PCS_RGMII (1 << 0)
+#define STMMAC_PCS_SGMII (1 << 1)
+#define STMMAC_PCS_TBI (1 << 2)
+#define STMMAC_PCS_RTBI (1 << 3)
+
+#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
/* DAM HW feature register fields */
-#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
-#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
-#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
-#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
-#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
-#define DMA_HW_FEAT_ADDMACADRSEL 0x00000020 /* Multiple MAC Addr Reg */
-#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
-#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
-#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
-#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
-#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
-#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
-#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 Timestamp */
-#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 Adv Timestamp */
-#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
-#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
-#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
-#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP csum Offload(Type 1) in Rx */
-#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP csum Offload(Type 2) in Rx */
-#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
-#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. of additional Rx Channels */
-#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. of additional Tx Channels */
-#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate (Enhanced Descriptor) */
-#define DMA_HW_FEAT_INTTSEN 0x02000000 /* Timestamping with Internal
- System Time */
-#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
-#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN Insertion */
-#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */
+#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
+#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
+#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
+#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
+#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
+#define DMA_HW_FEAT_ADDMAC 0x00000020 /* Multiple MAC Addr Reg */
+#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
+#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
+#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
+#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
+#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
+#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
+#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 */
+#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 PTPv2 */
+#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
+#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
+#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
+#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP COE (Type 1) in Rx */
+#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP COE (Type 2) in Rx */
+#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
+#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. additional Rx Channels */
+#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. additional Tx Channels */
+#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate Descriptor */
+/* Timestamping with Internal System Time */
+#define DMA_HW_FEAT_INTTSEN 0x02000000
+#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
+#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN */
+#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
#define DEFAULT_DMA_PBL 8
/* Max/Min RI Watchdog Timer count value */
@@ -180,7 +216,8 @@ struct stmmac_extra_stats {
#define STMMAC_TX_MAX_FRAMES 256
#define STMMAC_TX_FRAMES 64
-enum rx_frame_status { /* IPC status */
+/* Rx IPC status */
+enum rx_frame_status {
good_frame = 0,
discard_frame = 1,
csum_none = 2,
@@ -194,17 +231,25 @@ enum dma_irq_status {
handle_tx = 0x8,
};
-enum core_specific_irq_mask {
- core_mmc_tx_irq = 1,
- core_mmc_rx_irq = 2,
- core_mmc_rx_csum_offload_irq = 4,
- core_irq_receive_pmt_irq = 8,
- core_irq_tx_path_in_lpi_mode = 16,
- core_irq_tx_path_exit_lpi_mode = 32,
- core_irq_rx_path_in_lpi_mode = 64,
- core_irq_rx_path_exit_lpi_mode = 128,
+#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 1)
+#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 2)
+#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 3)
+#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 4)
+
+#define CORE_PCS_ANE_COMPLETE (1 << 5)
+#define CORE_PCS_LINK_STATUS (1 << 6)
+#define CORE_RGMII_IRQ (1 << 7)
+
+struct rgmii_adv {
+ unsigned int pause;
+ unsigned int duplex;
+ unsigned int lp_pause;
+ unsigned int lp_duplex;
};
+#define STMMAC_PCS_PAUSE 1
+#define STMMAC_PCS_ASYM_PAUSE 2
+
/* DMA HW capabilities */
struct dma_features {
unsigned int mbps_10_100;
@@ -217,9 +262,9 @@ struct dma_features {
unsigned int pmt_remote_wake_up;
unsigned int pmt_magic_frame;
unsigned int rmon;
- /* IEEE 1588-2002*/
+ /* IEEE 1588-2002 */
unsigned int time_stamp;
- /* IEEE 1588-2008*/
+ /* IEEE 1588-2008 */
unsigned int atime_stamp;
/* 802.3az - Energy-Efficient Ethernet (EEE) */
unsigned int eee;
@@ -232,7 +277,7 @@ struct dma_features {
/* TX and RX number of channels */
unsigned int number_rx_channel;
unsigned int number_tx_channel;
- /* Alternate (enhanced) DESC mode*/
+ /* Alternate (enhanced) DESC mode */
unsigned int enh_desc;
};
@@ -255,23 +300,26 @@ struct dma_features {
#define STMMAC_DEFAULT_LIT_LS_TIMER 0x3E8
#define STMMAC_DEFAULT_TWT_LS_TIMER 0x0
+#define STMMAC_CHAIN_MODE 0x1
+#define STMMAC_RING_MODE 0x2
+
struct stmmac_desc_ops {
/* DMA RX descriptor ring initialization */
- void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
- int disable_rx_ic);
+ void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
+ int end);
/* DMA TX descriptor ring initialization */
- void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size);
+ void (*init_tx_desc) (struct dma_desc *p, int mode, int end);
/* Invoked by the xmit function to prepare the tx descriptor */
void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
- int csum_flag);
+ int csum_flag, int mode);
/* Set/get the owner of the descriptor */
void (*set_tx_owner) (struct dma_desc *p);
int (*get_tx_owner) (struct dma_desc *p);
/* Invoked by the xmit function to close the tx descriptor */
void (*close_tx_desc) (struct dma_desc *p);
/* Clean the tx descriptor as soon as the tx irq is received */
- void (*release_tx_desc) (struct dma_desc *p);
+ void (*release_tx_desc) (struct dma_desc *p, int mode);
/* Clear interrupt on tx frame completion. When this bit is
* set an interrupt happens as soon as the frame is transmitted */
void (*clear_tx_ic) (struct dma_desc *p);
@@ -290,12 +338,22 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
+ void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x,
+ struct dma_extended_desc *p);
+ /* Set tx timestamp enable bit */
+ void (*enable_tx_timestamp) (struct dma_desc *p);
+ /* get tx timestamp status */
+ int (*get_tx_timestamp_status) (struct dma_desc *p);
+ /* get timestamp value */
+ u64(*get_timestamp) (void *desc, u32 ats);
+ /* get rx timestamp status */
+ int (*get_rx_timestamp_status) (void *desc, u32 ats);
};
struct stmmac_dma_ops {
/* DMA core initialization */
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
- int burst_len, u32 dma_tx, u32 dma_rx);
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds);
/* Dump DMA registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Set tx/rx threshold in the csr6 register
@@ -321,13 +379,14 @@ struct stmmac_dma_ops {
struct stmmac_ops {
/* MAC core initialization */
- void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
+ void (*core_init) (void __iomem *ioaddr);
/* Enable and verify that the IPC module is supported */
int (*rx_ipc) (void __iomem *ioaddr);
/* Dump MAC registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Handle extra events on specific interrupts hw dependent */
- int (*host_irq_status) (void __iomem *ioaddr);
+ int (*host_irq_status) (void __iomem *ioaddr,
+ struct stmmac_extra_stats *x);
/* Multicast filter setting */
void (*set_filter) (struct net_device *dev, int id);
/* Flow control setting */
@@ -344,6 +403,18 @@ struct stmmac_ops {
void (*reset_eee_mode) (void __iomem *ioaddr);
void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
void (*set_eee_pls) (void __iomem *ioaddr, int link);
+ void (*ctrl_ane) (void __iomem *ioaddr, bool restart);
+ void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv);
+};
+
+struct stmmac_hwtimestamp {
+ void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
+ void (*config_sub_second_increment) (void __iomem *ioaddr);
+ int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
+ int (*config_addend) (void __iomem *ioaddr, u32 addend);
+ int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub);
+ u64(*get_systime) (void __iomem *ioaddr);
};
struct mac_link {
@@ -360,19 +431,28 @@ struct mii_regs {
struct stmmac_ring_mode_ops {
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
- void (*refill_desc3) (int bfsize, struct dma_desc *p);
- void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
- void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
- unsigned int size);
- void (*clean_desc3) (struct dma_desc *p);
+ void (*refill_desc3) (void *priv, struct dma_desc *p);
+ void (*init_desc3) (struct dma_desc *p);
+ void (*clean_desc3) (void *priv, struct dma_desc *p);
int (*set_16kib_bfsize) (int mtu);
};
+struct stmmac_chain_mode_ops {
+ void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
+ unsigned int extend_desc);
+ unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
+ unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+ void (*refill_desc3) (void *priv, struct dma_desc *p);
+ void (*clean_desc3) (void *priv, struct dma_desc *p);
+};
+
struct mac_device_info {
- const struct stmmac_ops *mac;
- const struct stmmac_desc_ops *desc;
- const struct stmmac_dma_ops *dma;
- const struct stmmac_ring_mode_ops *ring;
+ const struct stmmac_ops *mac;
+ const struct stmmac_desc_ops *desc;
+ const struct stmmac_dma_ops *dma;
+ const struct stmmac_ring_mode_ops *ring;
+ const struct stmmac_chain_mode_ops *chain;
+ const struct stmmac_hwtimestamp *ptp;
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
unsigned int synopsys_uid;
@@ -390,5 +470,6 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
extern const struct stmmac_ring_mode_ops ring_mode_ops;
+extern const struct stmmac_chain_mode_ops chain_mode_ops;
#endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 223adf95fd03..ad3996038018 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -24,6 +24,7 @@
#ifndef __DESCS_H__
#define __DESCS_H__
+/* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc {
/* Receive descriptor */
union {
@@ -60,7 +61,7 @@ struct dma_desc {
} rx;
struct {
/* RDES0 */
- u32 payload_csum_error:1;
+ u32 rx_mac_addr:1;
u32 crc_error:1;
u32 dribbling:1;
u32 error_gmii:1;
@@ -162,13 +163,57 @@ struct dma_desc {
unsigned int des3;
};
+/* Extended descriptor structure (supported by new SYNP GMAC generations) */
+struct dma_extended_desc {
+ struct dma_desc basic;
+ union {
+ struct {
+ u32 ip_payload_type:3;
+ u32 ip_hdr_err:1;
+ u32 ip_payload_err:1;
+ u32 ip_csum_bypassed:1;
+ u32 ipv4_pkt_rcvd:1;
+ u32 ipv6_pkt_rcvd:1;
+ u32 msg_type:4;
+ u32 ptp_frame_type:1;
+ u32 ptp_ver:1;
+ u32 timestamp_dropped:1;
+ u32 reserved:1;
+ u32 av_pkt_rcvd:1;
+ u32 av_tagged_pkt_rcvd:1;
+ u32 vlan_tag_priority_val:3;
+ u32 reserved3:3;
+ u32 l3_filter_match:1;
+ u32 l4_filter_match:1;
+ u32 l3_l4_filter_no_match:2;
+ u32 reserved4:4;
+ } erx;
+ struct {
+ u32 reserved;
+ } etx;
+ } des4;
+ unsigned int des5; /* Reserved */
+ unsigned int des6; /* Tx/Rx Timestamp Low */
+ unsigned int des7; /* Tx/Rx Timestamp High */
+};
+
/* Transmit checksum insertion control */
enum tdes_csum_insertion {
cic_disabled = 0, /* Checksum Insertion Control */
cic_only_ip = 1, /* Only IP header */
- cic_no_pseudoheader = 2, /* IP header but pseudoheader
- * is not calculated */
+ /* IP header but pseudoheader is not calculated */
+ cic_no_pseudoheader = 2,
cic_full = 3, /* IP header and pseudoheader */
};
+/* Extended RDES4 definitions */
+#define RDES_EXT_NO_PTP 0
+#define RDES_EXT_SYNC 0x1
+#define RDES_EXT_FOLLOW_UP 0x2
+#define RDES_EXT_DELAY_REQ 0x3
+#define RDES_EXT_DELAY_RESP 0x4
+#define RDES_EXT_PDELAY_REQ 0x5
+#define RDES_EXT_PDELAY_RESP 0x6
+#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
+
#endif /* __DESCS_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs_com.h b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
index 7ee9499a6e38..6f2cc78c5cf5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs_com.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs_com.h
@@ -30,26 +30,28 @@
#ifndef __DESC_COM_H__
#define __DESC_COM_H__
-#if defined(CONFIG_STMMAC_RING)
-static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+/* Specific functions used for Ring mode */
+
+/* Enhanced descriptors */
+static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
{
p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
if (end)
p->des01.erx.end_ring = 1;
}
-static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+static inline void ehn_desc_tx_set_on_ring(struct dma_desc *p, int end)
{
if (end)
p->des01.etx.end_ring = 1;
}
-static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
{
p->des01.etx.end_ring = ter;
}
-static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_4KiB)) {
p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
@@ -58,25 +60,26 @@ static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
p->des01.etx.buffer1_size = len;
}
-static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+/* Normal descriptors */
+static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
{
p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
if (end)
p->des01.rx.end_ring = 1;
}
-static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+static inline void ndesc_tx_set_on_ring(struct dma_desc *p, int end)
{
if (end)
p->des01.tx.end_ring = 1;
}
-static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
{
p->des01.tx.end_ring = ter;
}
-static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
{
if (unlikely(len > BUF_SIZE_2KiB)) {
p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
@@ -85,47 +88,47 @@ static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
p->des01.tx.buffer1_size = len;
}
-#else
+/* Specific functions used for Chain mode */
-static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+/* Enhanced descriptors */
+static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p, int end)
{
p->des01.erx.second_address_chained = 1;
}
-static inline void ehn_desc_tx_set_on_ring_chain(struct dma_desc *p, int end)
+static inline void ehn_desc_tx_set_on_chain(struct dma_desc *p, int end)
{
p->des01.etx.second_address_chained = 1;
}
-static inline void enh_desc_end_tx_desc(struct dma_desc *p, int ter)
+static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
{
p->des01.etx.second_address_chained = 1;
}
-static inline void enh_set_tx_desc_len(struct dma_desc *p, int len)
+static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
p->des01.etx.buffer1_size = len;
}
-static inline void ndesc_rx_set_on_ring_chain(struct dma_desc *p, int end)
+/* Normal descriptors */
+static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
{
p->des01.rx.second_address_chained = 1;
}
-static inline void ndesc_tx_set_on_ring_chain(struct dma_desc *p, int ring_size)
+static inline void ndesc_tx_set_on_chain(struct dma_desc *p, int ring_size)
{
p->des01.tx.second_address_chained = 1;
}
-static inline void ndesc_end_tx_desc(struct dma_desc *p, int ter)
+static inline void ndesc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
{
p->des01.tx.second_address_chained = 1;
}
-static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
+static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
{
p->des01.tx.buffer1_size = len;
}
-#endif
-
#endif /* __DESC_COM_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 7ad56afd6324..c12aabb8cf93 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -89,13 +89,46 @@ enum power_event {
(reg * 8))
#define GMAC_MAX_PERFECT_ADDRESSES 32
+/* PCS registers (AN/TBI/SGMII/RGMII) offset */
#define GMAC_AN_CTRL 0x000000c0 /* AN control */
#define GMAC_AN_STATUS 0x000000c4 /* AN status */
#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
-#define GMAC_ANE_LINK 0x000000cc /* Auto-Neg. link partener ability */
+#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
#define GMAC_TBI 0x000000d4 /* TBI extend status */
-#define GMAC_GMII_STATUS 0x000000d8 /* S/R-GMII status */
+#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
+
+/* AN Configuration defines */
+#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
+#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
+#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
+#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
+#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
+#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
+
+/* AN Status defines */
+#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
+#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
+#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
+#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
+
+/* Register 54 (SGMII/RGMII status register) */
+#define GMAC_S_R_GMII_LINK 0x8
+#define GMAC_S_R_GMII_SPEED 0x5
+#define GMAC_S_R_GMII_SPEED_SHIFT 0x1
+#define GMAC_S_R_GMII_MODE 0x1
+#define GMAC_S_R_GMII_SPEED_125 2
+#define GMAC_S_R_GMII_SPEED_25 1
+
+/* Common ADV and LPA defines */
+#define GMAC_ANE_FD (1 << 5)
+#define GMAC_ANE_HD (1 << 6)
+#define GMAC_ANE_PSE (3 << 7)
+#define GMAC_ANE_PSE_SHIFT 7
+
+ /* GMAC Configuration defines */
+#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
+#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
/* GMAC Configuration defines */
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
@@ -108,19 +141,19 @@ enum inter_frame_gap {
GMAC_CONTROL_IFG_80 = 0x00020000,
GMAC_CONTROL_IFG_40 = 0x000e0000,
};
-#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense during tx */
-#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
-#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
-#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
-#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
-#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
-#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
-#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
-#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
-#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad/FCS Stripping */
-#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
-#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
-#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
+#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense */
+#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
+#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
+#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
+#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
+#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
+#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
+#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
+#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
+#define GMAC_CONTROL_ACS 0x00000080 /* Auto Pad/FCS Stripping */
+#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
+#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
+#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
GMAC_CONTROL_JE | GMAC_CONTROL_BE)
@@ -151,15 +184,16 @@ enum inter_frame_gap {
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
-#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
+#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
/* Programmable burst length (passed thorugh platform)*/
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
#define DMA_BUS_MODE_PBL_SHIFT 8
+#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
enum rx_tx_priority_ratio {
- double_ratio = 0x00004000, /*2:1 */
- triple_ratio = 0x00008000, /*3:1 */
- quadruple_ratio = 0x0000c000, /*4:1 */
+ double_ratio = 0x00004000, /* 2:1 */
+ triple_ratio = 0x00008000, /* 3:1 */
+ quadruple_ratio = 0x0000c000, /* 4:1 */
};
#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
@@ -179,9 +213,10 @@ enum rx_tx_priority_ratio {
#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
-#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */
-#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
-#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
+/* Disable Drop TCP/IP csum error */
+#define DMA_CONTROL_DT 0x04000000
+#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
+#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
/* Threshold for Activating the FC */
enum rfa {
act_full_minus_1 = 0x00800000,
@@ -196,7 +231,7 @@ enum rfd {
deac_full_minus_3 = 0x00401000,
deac_full_minus_4 = 0x00401800,
};
-#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
+#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
enum ttc_control {
DMA_CONTROL_TTC_64 = 0x00000000,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index bfe022605498..7e05e8d0f1c2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -28,6 +28,7 @@
#include <linux/crc32.h>
#include <linux/slab.h>
+#include <linux/ethtool.h>
#include <asm/io.h>
#include "dwmac1000.h"
@@ -71,22 +72,22 @@ static void dwmac1000_dump_regs(void __iomem *ioaddr)
}
static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
- unsigned int reg_n)
+ unsigned int reg_n)
{
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
+ GMAC_ADDR_LOW(reg_n));
}
static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
- unsigned int reg_n)
+ unsigned int reg_n)
{
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
- GMAC_ADDR_LOW(reg_n));
+ GMAC_ADDR_LOW(reg_n));
}
static void dwmac1000_set_filter(struct net_device *dev, int id)
{
- void __iomem *ioaddr = (void __iomem *) dev->base_addr;
+ void __iomem *ioaddr = (void __iomem *)dev->base_addr;
unsigned int value = 0;
unsigned int perfect_addr_number;
@@ -96,7 +97,7 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
if (dev->flags & IFF_PROMISC)
value = GMAC_FRAME_FILTER_PR;
else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
- || (dev->flags & IFF_ALLMULTI)) {
+ || (dev->flags & IFF_ALLMULTI)) {
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
@@ -110,12 +111,13 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
memset(mc_filter, 0, sizeof(mc_filter));
netdev_for_each_mc_addr(ha, dev) {
/* The upper 6 bits of the calculated CRC are used to
- index the contens of the hash table */
- int bit_nr =
- bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
+ * index the contens of the hash table
+ */
+ int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
/* The most significant bit determines the register to
* use (H/L) while the other 5 bits determine the bit
- * within the register. */
+ * within the register.
+ */
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
}
writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
@@ -128,10 +130,11 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
else
perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2;
- /* Handle multiple unicast addresses (perfect filtering)*/
+ /* Handle multiple unicast addresses (perfect filtering) */
if (netdev_uc_count(dev) > perfect_addr_number)
- /* Switch to promiscuous mode is more than 16 addrs
- are required */
+ /* Switch to promiscuous mode if more than 16 addrs
+ * are required
+ */
value |= GMAC_FRAME_FILTER_PR;
else {
int reg = 1;
@@ -149,13 +152,13 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
#endif
writel(value, ioaddr + GMAC_FRAME_FILTER);
- CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
- "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
- readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
+ CHIP_DBG(KERN_INFO "\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
+ readl(ioaddr + GMAC_FRAME_FILTER),
+ readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
}
static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
- unsigned int fc, unsigned int pause_time)
+ unsigned int fc, unsigned int pause_time)
{
unsigned int flow = 0;
@@ -193,74 +196,106 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
writel(pmt, ioaddr + GMAC_PMT);
}
-
-static int dwmac1000_irq_status(void __iomem *ioaddr)
+static int dwmac1000_irq_status(void __iomem *ioaddr,
+ struct stmmac_extra_stats *x)
{
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
- int status = 0;
+ int ret = 0;
/* Not used events (e.g. MMC interrupts) are not handled. */
if ((intr_status & mmc_tx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_TX_INTR));
- status |= core_mmc_tx_irq;
+ readl(ioaddr + GMAC_MMC_TX_INTR));
+ x->mmc_tx_irq_n++;
}
if (unlikely(intr_status & mmc_rx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_INTR));
- status |= core_mmc_rx_irq;
+ readl(ioaddr + GMAC_MMC_RX_INTR));
+ x->mmc_rx_irq_n++;
}
if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
- status |= core_mmc_rx_csum_offload_irq;
+ readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ x->mmc_rx_csum_offload_irq_n++;
}
if (unlikely(intr_status & pmt_irq)) {
CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
- /* clear the PMT bits 5 and 6 by reading the PMT
- * status register. */
+ /* clear the PMT bits 5 and 6 by reading the PMT status reg */
readl(ioaddr + GMAC_PMT);
- status |= core_irq_receive_pmt_irq;
+ x->irq_receive_pmt_irq_n++;
}
/* MAC trx/rx EEE LPI entry/exit interrupts */
if (intr_status & lpiis_irq) {
/* Clean LPI interrupt by reading the Reg 12 */
- u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
+ ret = readl(ioaddr + LPI_CTRL_STATUS);
- if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
+ if (ret & LPI_CTRL_STATUS_TLPIEN) {
CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
- status |= core_irq_tx_path_in_lpi_mode;
+ x->irq_tx_path_in_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_TLPIEX) {
+ if (ret & LPI_CTRL_STATUS_TLPIEX) {
CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
- status |= core_irq_tx_path_exit_lpi_mode;
+ x->irq_tx_path_exit_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_RLPIEN) {
+ if (ret & LPI_CTRL_STATUS_RLPIEN) {
CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
- status |= core_irq_rx_path_in_lpi_mode;
+ x->irq_rx_path_in_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_RLPIEX) {
+ if (ret & LPI_CTRL_STATUS_RLPIEX) {
CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
- status |= core_irq_rx_path_exit_lpi_mode;
+ x->irq_rx_path_exit_lpi_mode_n++;
+ }
+ }
+
+ if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC PCS ANE IRQ\n");
+ readl(ioaddr + GMAC_AN_STATUS);
+ x->irq_pcs_ane_n++;
+ }
+ if (intr_status & rgmii_irq) {
+ u32 status = readl(ioaddr + GMAC_S_R_GMII);
+ CHIP_DBG(KERN_INFO "GMAC RGMII/SGMII interrupt\n");
+ x->irq_rgmii_n++;
+
+ /* Save and dump the link status. */
+ if (status & GMAC_S_R_GMII_LINK) {
+ int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
+ GMAC_S_R_GMII_SPEED_SHIFT;
+ x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
+
+ if (speed_value == GMAC_S_R_GMII_SPEED_125)
+ x->pcs_speed = SPEED_1000;
+ else if (speed_value == GMAC_S_R_GMII_SPEED_25)
+ x->pcs_speed = SPEED_100;
+ else
+ x->pcs_speed = SPEED_10;
+
+ x->pcs_link = 1;
+ pr_debug("Link is Up - %d/%s\n", (int)x->pcs_speed,
+ x->pcs_duplex ? "Full" : "Half");
+ } else {
+ x->pcs_link = 0;
+ pr_debug("Link is Down\n");
}
}
- return status;
+ return ret;
}
-static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
+static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
{
u32 value;
/* Enable the link status receive on RGMII, SGMII ore SMII
* receive path and instruct the transmit to enter in LPI
- * state. */
+ * state.
+ */
value = readl(ioaddr + LPI_CTRL_STATUS);
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
writel(value, ioaddr + LPI_CTRL_STATUS);
}
-static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
+static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
{
u32 value;
@@ -269,7 +304,7 @@ static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
writel(value, ioaddr + LPI_CTRL_STATUS);
}
-static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
+static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
{
u32 value;
@@ -283,7 +318,7 @@ static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
writel(value, ioaddr + LPI_CTRL_STATUS);
}
-static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
+static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
{
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
@@ -297,6 +332,41 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
writel(value, ioaddr + LPI_TIMER_CTRL);
}
+static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
+{
+ u32 value;
+
+ value = readl(ioaddr + GMAC_AN_CTRL);
+ /* auto negotiation enable and External Loopback enable */
+ value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
+
+ if (restart)
+ value |= GMAC_AN_CTRL_RAN;
+
+ writel(value, ioaddr + GMAC_AN_CTRL);
+}
+
+static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv)
+{
+ u32 value = readl(ioaddr + GMAC_ANE_ADV);
+
+ if (value & GMAC_ANE_FD)
+ adv->duplex = DUPLEX_FULL;
+ if (value & GMAC_ANE_HD)
+ adv->duplex |= DUPLEX_HALF;
+
+ adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
+
+ value = readl(ioaddr + GMAC_ANE_LPA);
+
+ if (value & GMAC_ANE_FD)
+ adv->lp_duplex = DUPLEX_FULL;
+ if (value & GMAC_ANE_HD)
+ adv->lp_duplex = DUPLEX_HALF;
+
+ adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
+}
+
static const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
.rx_ipc = dwmac1000_rx_ipc_enable,
@@ -307,10 +377,12 @@ static const struct stmmac_ops dwmac1000_ops = {
.pmt = dwmac1000_pmt,
.set_umac_addr = dwmac1000_set_umac_addr,
.get_umac_addr = dwmac1000_get_umac_addr,
- .set_eee_mode = dwmac1000_set_eee_mode,
- .reset_eee_mode = dwmac1000_reset_eee_mode,
- .set_eee_timer = dwmac1000_set_eee_timer,
- .set_eee_pls = dwmac1000_set_eee_pls,
+ .set_eee_mode = dwmac1000_set_eee_mode,
+ .reset_eee_mode = dwmac1000_reset_eee_mode,
+ .set_eee_timer = dwmac1000_set_eee_timer,
+ .set_eee_pls = dwmac1000_set_eee_pls,
+ .ctrl_ane = dwmac1000_ctrl_ane,
+ .get_adv = dwmac1000_get_adv,
};
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index bf83c03bfd06..2c431b616058 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -30,8 +30,8 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
-static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
@@ -60,7 +60,7 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
* depending on pbl value.
*/
value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
- (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+ (pbl << DMA_BUS_MODE_RPBL_SHIFT));
/* Set the Fixed burst mode */
if (fb)
@@ -73,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
#ifdef CONFIG_STMMAC_DA
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
#endif
+
+ if (atds)
+ value |= DMA_BUS_MODE_ATDS;
+
writel(value, ioaddr + DMA_BUS_MODE);
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
@@ -90,14 +94,16 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
*
* For Non Fixed Burst Mode: provide the maximum value of the
* burst length. Any burst equal or below the provided burst
- * length would be allowed to perform. */
+ * length would be allowed to perform.
+ */
writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
- /* The base address of the RX/TX descriptor lists must be written into
- * DMA CSR3 and CSR4, respectively. */
+ /* RX/TX descriptor base address lists must be written into
+ * DMA CSR3 and CSR4, respectively
+ */
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
@@ -105,7 +111,7 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
}
static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
- int rxmode)
+ int rxmode)
{
u32 csr6 = readl(ioaddr + DMA_CONTROL);
@@ -114,11 +120,12 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
/* Transmit COE type 2 cannot be done in cut-through mode. */
csr6 |= DMA_CONTROL_TSF;
/* Operating on second frame increase the performance
- * especially when transmit store-and-forward is used.*/
+ * especially when transmit store-and-forward is used.
+ */
csr6 |= DMA_CONTROL_OSF;
} else {
- CHIP_DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode"
- " (threshold = %d)\n", txmode);
+ CHIP_DBG(KERN_DEBUG "GMAC: disabling TX SF (threshold %d)\n",
+ txmode);
csr6 &= ~DMA_CONTROL_TSF;
csr6 &= DMA_CONTROL_TC_TX_MASK;
/* Set the transmit threshold */
@@ -138,8 +145,8 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n");
csr6 |= DMA_CONTROL_RSF;
} else {
- CHIP_DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode"
- " (threshold = %d)\n", rxmode);
+ CHIP_DBG(KERN_DEBUG "GMAC: disable RX SF mode (threshold %d)\n",
+ rxmode);
csr6 &= ~DMA_CONTROL_RSF;
csr6 &= DMA_CONTROL_TC_RX_MASK;
if (rxmode <= 32)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index f83210e7c221..007bb2be3f10 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -47,8 +47,7 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
{
pr_info("\t----------------------------------------------\n"
"\t DWMAC 100 CSR (base addr = 0x%p)\n"
- "\t----------------------------------------------\n",
- ioaddr);
+ "\t----------------------------------------------\n", ioaddr);
pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
readl(ioaddr + MAC_CONTROL));
pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
@@ -72,7 +71,8 @@ static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
return 0;
}
-static int dwmac100_irq_status(void __iomem *ioaddr)
+static int dwmac100_irq_status(void __iomem *ioaddr,
+ struct stmmac_extra_stats *x)
{
return 0;
}
@@ -91,7 +91,7 @@ static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
static void dwmac100_set_filter(struct net_device *dev, int id)
{
- void __iomem *ioaddr = (void __iomem *) dev->base_addr;
+ void __iomem *ioaddr = (void __iomem *)dev->base_addr;
u32 value = readl(ioaddr + MAC_CONTROL);
if (dev->flags & IFF_PROMISC) {
@@ -112,7 +112,8 @@ static void dwmac100_set_filter(struct net_device *dev, int id)
struct netdev_hw_addr *ha;
/* Perfect filter mode for physical address and Hash
- filter for multicast */
+ * filter for multicast
+ */
value |= MAC_CONTROL_HP;
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
MAC_CONTROL_IF | MAC_CONTROL_HO);
@@ -120,12 +121,13 @@ static void dwmac100_set_filter(struct net_device *dev, int id)
memset(mc_filter, 0, sizeof(mc_filter));
netdev_for_each_mc_addr(ha, dev) {
/* The upper 6 bits of the calculated CRC are used to
- * index the contens of the hash table */
- int bit_nr =
- ether_crc(ETH_ALEN, ha->addr) >> 26;
+ * index the contens of the hash table
+ */
+ int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
/* The most significant bit determines the register to
* use (H/L) while the other 5 bits determine the bit
- * within the register. */
+ * within the register.
+ */
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
}
writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
@@ -134,10 +136,9 @@ static void dwmac100_set_filter(struct net_device *dev, int id)
writel(value, ioaddr + MAC_CONTROL);
- CHIP_DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
- "HI 0x%08x, LO 0x%08x\n",
- __func__, readl(ioaddr + MAC_CONTROL),
- readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
+ CHIP_DBG(KERN_INFO "%s: Filter: 0x%08x Hash: HI 0x%08x, LO 0x%08x\n",
+ __func__, readl(ioaddr + MAC_CONTROL),
+ readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
}
static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
@@ -150,9 +151,7 @@ static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
writel(flow, ioaddr + MAC_FLOW_CTRL);
}
-/* No PMT module supported for this Ethernet Controller.
- * Tested on ST platforms only.
- */
+/* No PMT module supported on ST boards with this Eth chip. */
static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
{
return;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index c2b4d55a79b6..67551c154138 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -32,8 +32,8 @@
#include "dwmac100.h"
#include "dwmac_dma.h"
-static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
@@ -52,22 +52,25 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb,
/* Enable Application Access by writing to DMA CSR0 */
writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
- ioaddr + DMA_BUS_MODE);
+ ioaddr + DMA_BUS_MODE);
/* Mask interrupts by writing to CSR7 */
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
- /* The base address of the RX/TX descriptor lists must be written into
- * DMA CSR3 and CSR4, respectively. */
+ /* RX/TX descriptor base addr lists must be written into
+ * DMA CSR3 and CSR4, respectively
+ */
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
return 0;
}
-/* Store and Forward capability is not used at all..
- * The transmit threshold can be programmed by
- * setting the TTC bits in the DMA control register.*/
+/* Store and Forward capability is not used at all.
+ *
+ * The transmit threshold can be programmed by setting the TTC bits in the DMA
+ * control register.
+ */
static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
int rxmode)
{
@@ -90,16 +93,15 @@ static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
CHIP_DBG(KERN_DEBUG "DWMAC 100 DMA CSR\n");
for (i = 0; i < 9; i++)
pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
- (DMA_BUS_MODE + i * 4),
- readl(ioaddr + DMA_BUS_MODE + i * 4));
+ (DMA_BUS_MODE + i * 4),
+ readl(ioaddr + DMA_BUS_MODE + i * 4));
CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
- DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
+ DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
- DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
+ DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
}
-/* DMA controller has two counters to track the number of
- * the receive missed frames. */
+/* DMA controller has two counters to track the number of the missed frames. */
static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
void __iomem *ioaddr)
{
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index ab4896ecac1c..8e5662ce488b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -102,7 +102,7 @@
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
-#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
+#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
extern void dwmac_enable_dma_transmission(void __iomem *ioaddr);
extern void dwmac_enable_dma_irq(void __iomem *ioaddr);
@@ -112,6 +112,6 @@ extern void dwmac_dma_stop_tx(void __iomem *ioaddr);
extern void dwmac_dma_start_rx(void __iomem *ioaddr);
extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
extern int dwmac_dma_interrupt(void __iomem *ioaddr,
- struct stmmac_extra_stats *x);
+ struct stmmac_extra_stats *x);
#endif /* __DWMAC_DMA_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 2fc8ef95f97a..0fbc8fafa706 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -150,6 +150,57 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
+static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
+ struct dma_extended_desc *p)
+{
+ if (unlikely(p->basic.des01.erx.rx_mac_addr)) {
+ if (p->des4.erx.ip_hdr_err)
+ x->ip_hdr_err++;
+ if (p->des4.erx.ip_payload_err)
+ x->ip_payload_err++;
+ if (p->des4.erx.ip_csum_bypassed)
+ x->ip_csum_bypassed++;
+ if (p->des4.erx.ipv4_pkt_rcvd)
+ x->ipv4_pkt_rcvd++;
+ if (p->des4.erx.ipv6_pkt_rcvd)
+ x->ipv6_pkt_rcvd++;
+ if (p->des4.erx.msg_type == RDES_EXT_SYNC)
+ x->rx_msg_type_sync++;
+ else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
+ x->rx_msg_type_follow_up++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_delay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
+ x->rx_msg_type_delay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_pdelay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
+ x->rx_msg_type_pdelay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
+ x->rx_msg_type_pdelay_follow_up++;
+ else
+ x->rx_msg_type_ext_no_ptp++;
+ if (p->des4.erx.ptp_frame_type)
+ x->ptp_frame_type++;
+ if (p->des4.erx.ptp_ver)
+ x->ptp_ver++;
+ if (p->des4.erx.timestamp_dropped)
+ x->timestamp_dropped++;
+ if (p->des4.erx.av_pkt_rcvd)
+ x->av_pkt_rcvd++;
+ if (p->des4.erx.av_tagged_pkt_rcvd)
+ x->av_tagged_pkt_rcvd++;
+ if (p->des4.erx.vlan_tag_priority_val)
+ x->vlan_tag_priority_val++;
+ if (p->des4.erx.l3_filter_match)
+ x->l3_filter_match++;
+ if (p->des4.erx.l4_filter_match)
+ x->l4_filter_match++;
+ if (p->des4.erx.l3_l4_filter_no_match)
+ x->l3_l4_filter_no_match++;
+ }
+}
+
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct dma_desc *p)
{
@@ -198,7 +249,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
* At any rate, we need to understand if the CSUM hw computation is ok
* and report this info to the upper layers. */
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
- p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
+ p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
if (unlikely(p->des01.erx.dribbling)) {
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
@@ -225,34 +276,32 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->rx_vlan++;
}
#endif
+
return ret;
}
-static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
- int disable_rx_ic)
+static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
+ int mode, int end)
{
- int i;
- for (i = 0; i < ring_size; i++) {
- p->des01.erx.own = 1;
- p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
+ p->des01.erx.own = 1;
+ p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
- ehn_desc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+ if (mode == STMMAC_CHAIN_MODE)
+ ehn_desc_rx_set_on_chain(p, end);
+ else
+ ehn_desc_rx_set_on_ring(p, end);
- if (disable_rx_ic)
- p->des01.erx.disable_ic = 1;
- p++;
- }
+ if (disable_rx_ic)
+ p->des01.erx.disable_ic = 1;
}
-static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
- int i;
-
- for (i = 0; i < ring_size; i++) {
- p->des01.etx.own = 0;
- ehn_desc_tx_set_on_ring_chain(p, (i == ring_size - 1));
- p++;
- }
+ p->des01.etx.own = 0;
+ if (mode == STMMAC_CHAIN_MODE)
+ ehn_desc_tx_set_on_chain(p, end);
+ else
+ ehn_desc_tx_set_on_ring(p, end);
}
static int enh_desc_get_tx_owner(struct dma_desc *p)
@@ -280,20 +329,26 @@ static int enh_desc_get_tx_ls(struct dma_desc *p)
return p->des01.etx.last_segment;
}
-static void enh_desc_release_tx_desc(struct dma_desc *p)
+static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
{
int ter = p->des01.etx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
- enh_desc_end_tx_desc(p, ter);
+ if (mode == STMMAC_CHAIN_MODE)
+ enh_desc_end_tx_desc_on_chain(p, ter);
+ else
+ enh_desc_end_tx_desc_on_ring(p, ter);
}
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
- int csum_flag)
+ int csum_flag, int mode)
{
p->des01.etx.first_segment = is_fs;
- enh_set_tx_desc_len(p, len);
+ if (mode == STMMAC_CHAIN_MODE)
+ enh_set_tx_desc_len_on_chain(p, len);
+ else
+ enh_set_tx_desc_len_on_ring(p, len);
if (likely(csum_flag))
p->des01.etx.checksum_insertion = cic_full;
@@ -323,6 +378,49 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.erx.frame_length;
}
+static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.etx.time_stamp_enable = 1;
+}
+
+static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.etx.time_stamp_status;
+}
+
+static u64 enh_desc_get_timestamp(void *desc, u32 ats)
+{
+ u64 ns;
+
+ if (ats) {
+ struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
+ ns = p->des6;
+ /* convert high/sec time stamp value to nanosecond */
+ ns += p->des7 * 1000000000ULL;
+ } else {
+ struct dma_desc *p = (struct dma_desc *)desc;
+ ns = p->des2;
+ ns += p->des3 * 1000000000ULL;
+ }
+
+ return ns;
+}
+
+static int enh_desc_get_rx_timestamp_status(void *desc, u32 ats)
+{
+ if (ats) {
+ struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
+ return p->basic.des01.erx.ipc_csum_error;
+ } else {
+ struct dma_desc *p = (struct dma_desc *)desc;
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is corrupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+ }
+}
+
const struct stmmac_desc_ops enh_desc_ops = {
.tx_status = enh_desc_get_tx_status,
.rx_status = enh_desc_get_rx_status,
@@ -339,4 +437,9 @@ const struct stmmac_desc_ops enh_desc_ops = {
.set_tx_owner = enh_desc_set_tx_owner,
.set_rx_owner = enh_desc_set_rx_owner,
.get_rx_frame_len = enh_desc_get_rx_frame_len,
+ .rx_extended_status = enh_desc_get_ext_status,
+ .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
+ .get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
+ .get_timestamp = enh_desc_get_timestamp,
+ .get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h
index 67995ef25251..48ec001566b5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc.h
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h
@@ -28,8 +28,7 @@
/* MMC control register */
/* When set, all counter are reset */
#define MMC_CNTRL_COUNTER_RESET 0x1
-/* When set, do not roll over zero
- * after reaching the max value*/
+/* When set, do not roll over zero after reaching the max value*/
#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
index 0c74a702d461..50617c5a0bdb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
{
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
}
/* This reads the MAC core counters (if actaully supported).
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 68962c549a2d..11775b99afc5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -79,8 +79,8 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
struct net_device_stats *stats = (struct net_device_stats *)data;
if (unlikely(p->des01.rx.last_descriptor == 0)) {
- pr_warning("ndesc Error: Oversized Ethernet "
- "frame spanned multiple buffers\n");
+ pr_warn("%s: Oversized frame spanned multiple buffers\n",
+ __func__);
stats->rx_length_errors++;
return discard_frame;
}
@@ -122,30 +122,28 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
return ret;
}
-static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
- int disable_rx_ic)
+static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
+ int end)
{
- int i;
- for (i = 0; i < ring_size; i++) {
- p->des01.rx.own = 1;
- p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+ p->des01.rx.own = 1;
+ p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
- ndesc_rx_set_on_ring_chain(p, (i == ring_size - 1));
+ if (mode == STMMAC_CHAIN_MODE)
+ ndesc_rx_set_on_chain(p, end);
+ else
+ ndesc_rx_set_on_ring(p, end);
- if (disable_rx_ic)
- p->des01.rx.disable_ic = 1;
- p++;
- }
+ if (disable_rx_ic)
+ p->des01.rx.disable_ic = 1;
}
-static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
{
- int i;
- for (i = 0; i < ring_size; i++) {
- p->des01.tx.own = 0;
- ndesc_tx_set_on_ring_chain(p, (i == (ring_size - 1)));
- p++;
- }
+ p->des01.tx.own = 0;
+ if (mode == STMMAC_CHAIN_MODE)
+ ndesc_tx_set_on_chain(p, end);
+ else
+ ndesc_tx_set_on_ring(p, end);
}
static int ndesc_get_tx_owner(struct dma_desc *p)
@@ -173,19 +171,25 @@ static int ndesc_get_tx_ls(struct dma_desc *p)
return p->des01.tx.last_segment;
}
-static void ndesc_release_tx_desc(struct dma_desc *p)
+static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
{
int ter = p->des01.tx.end_ring;
memset(p, 0, offsetof(struct dma_desc, des2));
- ndesc_end_tx_desc(p, ter);
+ if (mode == STMMAC_CHAIN_MODE)
+ ndesc_end_tx_desc_on_chain(p, ter);
+ else
+ ndesc_end_tx_desc_on_ring(p, ter);
}
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
- int csum_flag)
+ int csum_flag, int mode)
{
p->des01.tx.first_segment = is_fs;
- norm_set_tx_desc_len(p, len);
+ if (mode == STMMAC_CHAIN_MODE)
+ norm_set_tx_desc_len_on_chain(p, len);
+ else
+ norm_set_tx_desc_len_on_ring(p, len);
if (likely(csum_flag))
p->des01.tx.checksum_insertion = cic_full;
@@ -215,6 +219,39 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.rx.frame_length;
}
+static void ndesc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.tx.time_stamp_enable = 1;
+}
+
+static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.tx.time_stamp_status;
+}
+
+static u64 ndesc_get_timestamp(void *desc, u32 ats)
+{
+ struct dma_desc *p = (struct dma_desc *)desc;
+ u64 ns;
+
+ ns = p->des2;
+ /* convert high/sec time stamp value to nanosecond */
+ ns += p->des3 * 1000000000ULL;
+
+ return ns;
+}
+
+static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
+{
+ struct dma_desc *p = (struct dma_desc *)desc;
+
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is corrupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+}
+
const struct stmmac_desc_ops ndesc_ops = {
.tx_status = ndesc_get_tx_status,
.rx_status = ndesc_get_rx_status,
@@ -231,4 +268,8 @@ const struct stmmac_desc_ops ndesc_ops = {
.set_tx_owner = ndesc_set_tx_owner,
.set_rx_owner = ndesc_set_rx_owner,
.get_rx_frame_len = ndesc_get_rx_frame_len,
+ .enable_tx_timestamp = ndesc_enable_tx_timestamp,
+ .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
+ .get_timestamp = ndesc_get_timestamp,
+ .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 4b785e10f2ed..c9d942a5c335 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -30,7 +30,7 @@
static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
{
- struct stmmac_priv *priv = (struct stmmac_priv *) p;
+ struct stmmac_priv *priv = (struct stmmac_priv *)p;
unsigned int txsize = priv->dma_tx_size;
unsigned int entry = priv->cur_tx % txsize;
struct dma_desc *desc = priv->dma_tx + entry;
@@ -48,25 +48,30 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
- csum);
+ priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
+ STMMAC_RING_MODE);
wmb();
entry = (++priv->cur_tx) % txsize;
desc = priv->dma_tx + entry;
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
+ priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
+ STMMAC_RING_MODE);
wmb();
priv->hw->desc->set_tx_owner(desc);
priv->tx_skbuff[entry] = NULL;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
- priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
+ priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
+ STMMAC_RING_MODE);
}
return entry;
@@ -82,27 +87,23 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
- /* Fill DES3 in case of RING mode */
- if (bfsize >= BUF_SIZE_8KiB)
- p->des3 = p->des2 + BUF_SIZE_8KiB;
-}
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
-/* In ring mode we need to fill the desc3 because it is used
- * as buffer */
-static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
-{
- if (unlikely(des3_as_data_buf))
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+ if (unlikely(priv->plat->has_gmac))
+ /* Fill DES3 in case of RING mode */
+ if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
-static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
- unsigned int size)
+/* In ring mode we need to fill the desc3 because it is used as buffer */
+static void stmmac_init_desc3(struct dma_desc *p)
{
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
-static void stmmac_clean_desc3(struct dma_desc *p)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
{
if (unlikely(p->des3))
p->des3 = 0;
@@ -121,7 +122,6 @@ const struct stmmac_ring_mode_ops ring_mode_ops = {
.jumbo_frm = stmmac_jumbo_frm,
.refill_desc3 = stmmac_refill_desc3,
.init_desc3 = stmmac_init_desc3,
- .init_dma_chain = stmmac_init_dma_chain,
.clean_desc3 = stmmac_clean_desc3,
.set_16kib_bfsize = stmmac_set_16kib_bfsize,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b05df8983be5..c922fde929a1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -24,43 +24,56 @@
#define __STMMAC_H__
#define STMMAC_RESOURCE_NAME "stmmaceth"
-#define DRV_MODULE_VERSION "Nov_2012"
+#define DRV_MODULE_VERSION "March_2013"
#include <linux/clk.h>
#include <linux/stmmac.h>
#include <linux/phy.h>
#include <linux/pci.h>
#include "common.h"
+#include <linux/ptp_clock_kernel.h>
struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
- struct dma_desc *dma_tx ____cacheline_aligned;
- dma_addr_t dma_tx_phy;
+ struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
+ struct dma_desc *dma_tx;
struct sk_buff **tx_skbuff;
unsigned int cur_tx;
unsigned int dirty_tx;
unsigned int dma_tx_size;
+ u32 tx_count_frames;
+ u32 tx_coal_frames;
+ u32 tx_coal_timer;
+ dma_addr_t *tx_skbuff_dma;
+ dma_addr_t dma_tx_phy;
int tx_coalesce;
+ int hwts_tx_en;
+ spinlock_t tx_lock;
+ bool tx_path_in_lpi_mode;
+ struct timer_list txtimer;
- struct dma_desc *dma_rx ;
+ struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
+ struct dma_extended_desc *dma_erx;
+ struct sk_buff **rx_skbuff;
unsigned int cur_rx;
unsigned int dirty_rx;
- struct sk_buff **rx_skbuff;
+ unsigned int dma_rx_size;
+ unsigned int dma_buf_sz;
+ u32 rx_riwt;
+ int hwts_rx_en;
dma_addr_t *rx_skbuff_dma;
+ dma_addr_t dma_rx_phy;
+ struct napi_struct napi ____cacheline_aligned_in_smp;
+
+ void __iomem *ioaddr;
struct net_device *dev;
- dma_addr_t dma_rx_phy;
- unsigned int dma_rx_size;
- unsigned int dma_buf_sz;
struct device *device;
struct mac_device_info *hw;
- void __iomem *ioaddr;
-
- struct stmmac_extra_stats xstats;
- struct napi_struct napi;
int no_csum_insertion;
+ spinlock_t lock;
- struct phy_device *phydev;
+ struct phy_device *phydev ____cacheline_aligned_in_smp;
int oldlink;
int speed;
int oldduplex;
@@ -69,30 +82,31 @@ struct stmmac_priv {
struct mii_bus *mii;
int mii_irq[PHY_MAX_ADDR];
- u32 msg_enable;
- spinlock_t lock;
- spinlock_t tx_lock;
- int wolopts;
- int wol_irq;
+ struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
struct plat_stmmacenet_data *plat;
- struct stmmac_counters mmc;
struct dma_features dma_cap;
+ struct stmmac_counters mmc;
int hw_cap_support;
+ int synopsys_id;
+ u32 msg_enable;
+ int wolopts;
+ int wol_irq;
struct clk *stmmac_clk;
int clk_csr;
- int synopsys_id;
struct timer_list eee_ctrl_timer;
- bool tx_path_in_lpi_mode;
int lpi_irq;
int eee_enabled;
int eee_active;
int tx_lpi_timer;
- struct timer_list txtimer;
- u32 tx_count_frames;
- u32 tx_coal_frames;
- u32 tx_coal_timer;
+ int pcs;
+ unsigned int mode;
+ int extend_desc;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_ops;
+ unsigned int default_addend;
+ u32 adv_ts;
int use_riwt;
- u32 rx_riwt;
+ spinlock_t ptp_lock;
};
extern int phyaddr;
@@ -102,6 +116,9 @@ extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
+extern const struct stmmac_hwtimestamp stmmac_ptp;
+extern int stmmac_ptp_register(struct stmmac_priv *priv);
+extern void stmmac_ptp_unregister(struct stmmac_priv *priv);
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
int stmmac_resume(struct net_device *ndev);
@@ -125,6 +142,7 @@ static inline int stmmac_register_platform(void)
return err;
}
+
static inline void stmmac_unregister_platform(void)
{
platform_driver_unregister(&stmmac_pltfr_driver);
@@ -136,6 +154,7 @@ static inline int stmmac_register_platform(void)
return 0;
}
+
static inline void stmmac_unregister_platform(void)
{
}
@@ -153,6 +172,7 @@ static inline int stmmac_register_pci(void)
return err;
}
+
static inline void stmmac_unregister_pci(void)
{
pci_unregister_driver(&stmmac_pci_driver);
@@ -164,6 +184,7 @@ static inline int stmmac_register_pci(void)
return 0;
}
+
static inline void stmmac_unregister_pci(void)
{
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index d1ac39c1b05d..c5f9cb85c8ef 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -27,6 +27,7 @@
#include <linux/interrupt.h>
#include <linux/mii.h>
#include <linux/phy.h>
+#include <linux/net_tstamp.h>
#include <asm/io.h>
#include "stmmac.h"
@@ -108,6 +109,33 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
+ /* Extended RDES status */
+ STMMAC_STAT(ip_hdr_err),
+ STMMAC_STAT(ip_payload_err),
+ STMMAC_STAT(ip_csum_bypassed),
+ STMMAC_STAT(ipv4_pkt_rcvd),
+ STMMAC_STAT(ipv6_pkt_rcvd),
+ STMMAC_STAT(rx_msg_type_ext_no_ptp),
+ STMMAC_STAT(rx_msg_type_sync),
+ STMMAC_STAT(rx_msg_type_follow_up),
+ STMMAC_STAT(rx_msg_type_delay_req),
+ STMMAC_STAT(rx_msg_type_delay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_req),
+ STMMAC_STAT(rx_msg_type_pdelay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_follow_up),
+ STMMAC_STAT(ptp_frame_type),
+ STMMAC_STAT(ptp_ver),
+ STMMAC_STAT(timestamp_dropped),
+ STMMAC_STAT(av_pkt_rcvd),
+ STMMAC_STAT(av_tagged_pkt_rcvd),
+ STMMAC_STAT(vlan_tag_priority_val),
+ STMMAC_STAT(l3_filter_match),
+ STMMAC_STAT(l4_filter_match),
+ STMMAC_STAT(l3_l4_filter_no_match),
+ /* PCS */
+ STMMAC_STAT(irq_pcs_ane_n),
+ STMMAC_STAT(irq_pcs_link_n),
+ STMMAC_STAT(irq_rgmii_n),
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
@@ -219,6 +247,70 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = priv->phydev;
int rc;
+
+ if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
+ struct rgmii_adv adv;
+
+ if (!priv->xstats.pcs_link) {
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ cmd->duplex = DUPLEX_UNKNOWN;
+ return 0;
+ }
+ cmd->duplex = priv->xstats.pcs_duplex;
+
+ ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
+
+ /* Get and convert ADV/LP_ADV from the HW AN registers */
+ if (priv->hw->mac->get_adv)
+ priv->hw->mac->get_adv(priv->ioaddr, &adv);
+ else
+ return -EOPNOTSUPP; /* should never happen indeed */
+
+ /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
+
+ if (adv.pause & STMMAC_PCS_PAUSE)
+ cmd->advertising |= ADVERTISED_Pause;
+ if (adv.pause & STMMAC_PCS_ASYM_PAUSE)
+ cmd->advertising |= ADVERTISED_Asym_Pause;
+ if (adv.lp_pause & STMMAC_PCS_PAUSE)
+ cmd->lp_advertising |= ADVERTISED_Pause;
+ if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE)
+ cmd->lp_advertising |= ADVERTISED_Asym_Pause;
+
+ /* Reg49[3] always set because ANE is always supported */
+ cmd->autoneg = ADVERTISED_Autoneg;
+ cmd->supported |= SUPPORTED_Autoneg;
+ cmd->advertising |= ADVERTISED_Autoneg;
+ cmd->lp_advertising |= ADVERTISED_Autoneg;
+
+ if (adv.duplex) {
+ cmd->supported |= (SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_10baseT_Full);
+ cmd->advertising |= (ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full);
+ } else {
+ cmd->supported |= (SUPPORTED_1000baseT_Half |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_10baseT_Half);
+ cmd->advertising |= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half);
+ }
+ if (adv.lp_duplex)
+ cmd->lp_advertising |= (ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full);
+ else
+ cmd->lp_advertising |= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half);
+ cmd->port = PORT_OTHER;
+
+ return 0;
+ }
+
if (phy == NULL) {
pr_err("%s: %s: PHY is not registered\n",
__func__, dev->name);
@@ -243,6 +335,30 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
struct phy_device *phy = priv->phydev;
int rc;
+ if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
+ u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
+
+ /* Only support ANE */
+ if (cmd->autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ mask &= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full);
+
+ spin_lock(&priv->lock);
+ if (priv->hw->mac->ctrl_ane)
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 1);
+ spin_unlock(&priv->lock);
+ }
+
+ return 0;
+ }
+
spin_lock(&priv->lock);
rc = phy_ethtool_sset(phy, cmd);
spin_unlock(&priv->lock);
@@ -312,6 +428,9 @@ stmmac_get_pauseparam(struct net_device *netdev,
{
struct stmmac_priv *priv = netdev_priv(netdev);
+ if (priv->pcs) /* FIXME */
+ return;
+
spin_lock(&priv->lock);
pause->rx_pause = 0;
@@ -335,6 +454,9 @@ stmmac_set_pauseparam(struct net_device *netdev,
int new_pause = FLOW_OFF;
int ret = 0;
+ if (priv->pcs) /* FIXME */
+ return -EOPNOTSUPP;
+
spin_lock(&priv->lock);
if (pause->rx_pause)
@@ -604,6 +726,38 @@ static int stmmac_set_coalesce(struct net_device *dev,
return 0;
}
+static int stmmac_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) {
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ if (priv->ptp_clock)
+ info->phc_index = ptp_clock_index(priv->ptp_clock);
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_ALL));
+ return 0;
+ } else
+ return ethtool_op_get_ts_info(dev, info);
+}
+
static const struct ethtool_ops stmmac_ethtool_ops = {
.begin = stmmac_check_if_running,
.get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -623,7 +777,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_eee = stmmac_ethtool_op_get_eee,
.set_eee = stmmac_ethtool_op_set_eee,
.get_sset_count = stmmac_get_sset_count,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = stmmac_get_ts_info,
.get_coalesce = stmmac_get_coalesce,
.set_coalesce = stmmac_set_coalesce,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
new file mode 100644
index 000000000000..def7e75e1d57
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This implements all the API for managing HW timestamp & PTP.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include "common.h"
+#include "stmmac_ptp.h"
+
+static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
+{
+ writel(data, ioaddr + PTP_TCR);
+}
+
+static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr + PTP_TCR);
+ unsigned long data;
+
+ /* Convert the ptp_clock to nano second
+ * formula = (1/ptp_clock) * 1000000000
+ * where, ptp_clock = 50MHz.
+ */
+ data = (1000000000ULL / 50000000);
+
+ /* 0.465ns accuracy */
+ if (value & PTP_TCR_TSCTRLSSR)
+ data = (data * 100) / 465;
+
+ writel(data, ioaddr + PTP_SSIR);
+}
+
+static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
+{
+ int limit;
+ u32 value;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(nsec, ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSINIT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time initialize to complete */
+ limit = 10;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
+{
+ u32 value;
+ int limit;
+
+ writel(addend, ioaddr + PTP_TAR);
+ /* issue command to update the addend value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSADDREG;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present addend update to complete */
+ limit = 10;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub)
+{
+ u32 value;
+ int limit;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
+ ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSUPDT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time adjust/update to complete */
+ limit = 10;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static u64 stmmac_get_systime(void __iomem *ioaddr)
+{
+ u64 ns;
+
+ ns = readl(ioaddr + PTP_STNSR);
+ /* convert sec time value to nanosecond */
+ ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
+
+ return ns;
+}
+
+const struct stmmac_hwtimestamp stmmac_ptp = {
+ .config_hw_tstamping = stmmac_config_hw_tstamping,
+ .init_systime = stmmac_init_systime,
+ .config_sub_second_increment = stmmac_config_sub_second_increment,
+ .config_addend = stmmac_config_addend,
+ .adjust_systime = stmmac_adjust_systime,
+ .get_systime = stmmac_get_systime,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 39c6c5524633..618446ae1ec1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -46,7 +46,9 @@
#ifdef CONFIG_STMMAC_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#endif
+#endif /* CONFIG_STMMAC_DEBUG_FS */
+#include <linux/net_tstamp.h>
+#include "stmmac_ptp.h"
#include "stmmac.h"
#undef STMMAC_DEBUG
@@ -79,14 +81,14 @@
#define JUMBO_LEN 9000
/* Module parameters */
-#define TX_TIMEO 5000 /* default 5 seconds */
+#define TX_TIMEO 5000
static int watchdog = TX_TIMEO;
module_param(watchdog, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds");
+MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds (default 5s)");
-static int debug = -1; /* -1: default, 0: no output, 16: all */
+static int debug = -1;
module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)");
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
int phyaddr = -1;
module_param(phyaddr, int, S_IRUGO);
@@ -130,6 +132,13 @@ module_param(eee_timer, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
#define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
+/* By default the driver will use the ring mode to manage tx and rx descriptors
+ * but passing this value so user can force to use the chain instead of the ring
+ */
+static unsigned int chain_mode;
+module_param(chain_mode, int, S_IRUGO);
+MODULE_PARM_DESC(chain_mode, "To use chain instead of ring mode");
+
static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
#ifdef CONFIG_STMMAC_DEBUG_FS
@@ -164,6 +173,18 @@ static void stmmac_verify_args(void)
eee_timer = STMMAC_DEFAULT_LPI_TIMER;
}
+/**
+ * stmmac_clk_csr_set - dynamically set the MDC clock
+ * @priv: driver private structure
+ * Description: this is to dynamically set the MDC clock according to the csr
+ * clock input.
+ * Note:
+ * If a specific clk_csr value is passed from the platform
+ * this means that the CSR Clock Range selection cannot be
+ * changed at run-time and it is fixed (as reported in the driver
+ * documentation). Viceversa the driver will try to set the MDC
+ * clock dynamically according to the actual clock input.
+ */
static void stmmac_clk_csr_set(struct stmmac_priv *priv)
{
u32 clk_rate;
@@ -171,7 +192,12 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
clk_rate = clk_get_rate(priv->stmmac_clk);
/* Platform provided default clk_csr would be assumed valid
- * for all other cases except for the below mentioned ones. */
+ * for all other cases except for the below mentioned ones.
+ * For values higher than the IEEE 802.3 specified frequency
+ * we can not estimate the proper divider as it is not known
+ * the frequency of clk_csr_i. So we do not change the default
+ * divider.
+ */
if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) {
if (clk_rate < CSR_F_35M)
priv->clk_csr = STMMAC_CSR_20_35M;
@@ -185,10 +211,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
priv->clk_csr = STMMAC_CSR_150_250M;
else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
priv->clk_csr = STMMAC_CSR_250_300M;
- } /* For values higher than the IEEE 802.3 specified frequency
- * we can not estimate the proper divider as it is not known
- * the frequency of clk_csr_i. So we do not change the default
- * divider. */
+ }
}
#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
@@ -213,18 +236,25 @@ static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
}
-/* On some ST platforms, some HW system configuraton registers have to be
- * set according to the link speed negotiated.
+/**
+ * stmmac_hw_fix_mac_speed: callback for speed selection
+ * @priv: driver private structure
+ * Description: on some platforms (e.g. ST), some HW system configuraton
+ * registers have to be set according to the link speed negotiated.
*/
static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
{
struct phy_device *phydev = priv->phydev;
if (likely(priv->plat->fix_mac_speed))
- priv->plat->fix_mac_speed(priv->plat->bsp_priv,
- phydev->speed);
+ priv->plat->fix_mac_speed(priv->plat->bsp_priv, phydev->speed);
}
+/**
+ * stmmac_enable_eee_mode: Check and enter in LPI mode
+ * @priv: driver private structure
+ * Description: this function is to verify and enter in LPI mode for EEE.
+ */
static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
{
/* Check and enter in LPI mode */
@@ -233,19 +263,24 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
priv->hw->mac->set_eee_mode(priv->ioaddr);
}
+/**
+ * stmmac_disable_eee_mode: disable/exit from EEE
+ * @priv: driver private structure
+ * Description: this function is to exit and disable EEE in case of
+ * LPI state is true. This is called by the xmit.
+ */
void stmmac_disable_eee_mode(struct stmmac_priv *priv)
{
- /* Exit and disable EEE in case of we are are in LPI state. */
priv->hw->mac->reset_eee_mode(priv->ioaddr);
del_timer_sync(&priv->eee_ctrl_timer);
priv->tx_path_in_lpi_mode = false;
}
/**
- * stmmac_eee_ctrl_timer
+ * stmmac_eee_ctrl_timer: EEE TX SW timer.
* @arg : data hook
* Description:
- * If there is no data transfer and if we are not in LPI state,
+ * if there is no data transfer and if we are not in LPI state,
* then MAC Transmitter can be moved to LPI state.
*/
static void stmmac_eee_ctrl_timer(unsigned long arg)
@@ -257,8 +292,8 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
}
/**
- * stmmac_eee_init
- * @priv: private device pointer
+ * stmmac_eee_init: init EEE
+ * @priv: driver private structure
* Description:
* If the EEE support has been enabled while configuring the driver,
* if the GMAC actually supports the EEE (from the HW cap reg) and the
@@ -294,16 +329,359 @@ out:
return ret;
}
+/**
+ * stmmac_eee_adjust: adjust HW EEE according to the speed
+ * @priv: driver private structure
+ * Description:
+ * When the EEE has been already initialised we have to
+ * modify the PLS bit in the LPI ctrl & status reg according
+ * to the PHY link status. For this reason.
+ */
static void stmmac_eee_adjust(struct stmmac_priv *priv)
{
- /* When the EEE has been already initialised we have to
- * modify the PLS bit in the LPI ctrl & status reg according
- * to the PHY link status. For this reason.
- */
if (priv->eee_enabled)
priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
}
+/* stmmac_get_tx_hwtstamp: get HW TX timestamps
+ * @priv: driver private structure
+ * @entry : descriptor index to be used.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read timestamp from the descriptor & pass it to stack.
+ * and also perform some sanity checks.
+ */
+static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
+ unsigned int entry, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps shhwtstamp;
+ u64 ns;
+ void *desc = NULL;
+
+ if (!priv->hwts_tx_en)
+ return;
+
+ /* exit if skb doesn't support hw tstamp */
+ if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
+ return;
+
+ if (priv->adv_ts)
+ desc = (priv->dma_etx + entry);
+ else
+ desc = (priv->dma_tx + entry);
+
+ /* check tx tstamp status */
+ if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc))
+ return;
+
+ /* get the valid tstamp */
+ ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
+
+ memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp.hwtstamp = ns_to_ktime(ns);
+ /* pass tstamp to stack */
+ skb_tstamp_tx(skb, &shhwtstamp);
+
+ return;
+}
+
+/* stmmac_get_rx_hwtstamp: get HW RX timestamps
+ * @priv: driver private structure
+ * @entry : descriptor index to be used.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read received packet's timestamp from the descriptor
+ * and pass it to stack. It also perform some sanity checks.
+ */
+static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv,
+ unsigned int entry, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamp = NULL;
+ u64 ns;
+ void *desc = NULL;
+
+ if (!priv->hwts_rx_en)
+ return;
+
+ if (priv->adv_ts)
+ desc = (priv->dma_erx + entry);
+ else
+ desc = (priv->dma_rx + entry);
+
+ /* exit if rx tstamp is not valid */
+ if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts))
+ return;
+
+ /* get valid tstamp */
+ ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
+ shhwtstamp = skb_hwtstamps(skb);
+ memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * stmmac_hwtstamp_ioctl - control hardware timestamping.
+ * @dev: device pointer.
+ * @ifr: An IOCTL specefic structure, that can contain a pointer to
+ * a proprietary structure used to pass information to the driver.
+ * Description:
+ * This function configures the MAC to enable/disable both outgoing(TX)
+ * and incoming(RX) packets time stamping based on user input.
+ * Return Value:
+ * 0 on success and an appropriate -ve integer on failure.
+ */
+static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct hwtstamp_config config;
+ struct timespec now;
+ u64 temp = 0;
+ u32 ptp_v2 = 0;
+ u32 tstamp_all = 0;
+ u32 ptp_over_ipv4_udp = 0;
+ u32 ptp_over_ipv6_udp = 0;
+ u32 ptp_over_ethernet = 0;
+ u32 snap_type_sel = 0;
+ u32 ts_master_en = 0;
+ u32 ts_event_en = 0;
+ u32 value = 0;
+
+ if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
+ netdev_alert(priv->dev, "No support for HW time stamping\n");
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_from_user(&config, ifr->ifr_data,
+ sizeof(struct hwtstamp_config)))
+ return -EFAULT;
+
+ pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
+ __func__, config.flags, config.tx_type, config.rx_filter);
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ if (priv->adv_ts) {
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ /* time stamp no incoming packet at all */
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ /* PTP v1, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ /* PTP v1, UDP, Sync packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ /* PTP v1, UDP, Delay_req packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ /* PTP v2, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ /* PTP v2, UDP, Sync packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ /* PTP v2, UDP, Delay_req packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ /* PTP v2/802.AS1 any layer, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ /* PTP v2/802.AS1, any layer, Sync packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ /* PTP v2/802.AS1, any layer, Delay_req packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ case HWTSTAMP_FILTER_ALL:
+ /* time stamp any incoming packet */
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ tstamp_all = PTP_TCR_TSENALL;
+ break;
+
+ default:
+ return -ERANGE;
+ }
+ } else {
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+ default:
+ /* PTP v1, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
+ }
+ }
+ priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
+
+ if (!priv->hwts_tx_en && !priv->hwts_rx_en)
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
+ else {
+ value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
+ tstamp_all | ptp_v2 | ptp_over_ethernet |
+ ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
+ ts_master_en | snap_type_sel);
+
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
+
+ /* program Sub Second Increment reg */
+ priv->hw->ptp->config_sub_second_increment(priv->ioaddr);
+
+ /* calculate default added value:
+ * formula is :
+ * addend = (2^32)/freq_div_ratio;
+ * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
+ * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
+ * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
+ * achive 20ns accuracy.
+ *
+ * 2^x * y == (y << x), hence
+ * 2^32 * 50000000 ==> (50000000 << 32)
+ */
+ temp = (u64) (50000000ULL << 32);
+ priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK);
+ priv->hw->ptp->config_addend(priv->ioaddr,
+ priv->default_addend);
+
+ /* initialize system time */
+ getnstimeofday(&now);
+ priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec,
+ now.tv_nsec);
+ }
+
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
+}
+
+/**
+ * stmmac_init_ptp: init PTP
+ * @priv: driver private structure
+ * Description: this is to verify if the HW supports the PTPv1 or v2.
+ * This is done by looking at the HW cap. register.
+ * Also it registers the ptp driver.
+ */
+static int stmmac_init_ptp(struct stmmac_priv *priv)
+{
+ if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+ return -EOPNOTSUPP;
+
+ if (netif_msg_hw(priv)) {
+ if (priv->dma_cap.time_stamp) {
+ pr_debug("IEEE 1588-2002 Time Stamp supported\n");
+ priv->adv_ts = 0;
+ }
+ if (priv->dma_cap.atime_stamp && priv->extend_desc) {
+ pr_debug
+ ("IEEE 1588-2008 Advanced Time Stamp supported\n");
+ priv->adv_ts = 1;
+ }
+ }
+
+ priv->hw->ptp = &stmmac_ptp;
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+ return stmmac_ptp_register(priv);
+}
+
+static void stmmac_release_ptp(struct stmmac_priv *priv)
+{
+ stmmac_ptp_unregister(priv);
+}
+
/**
* stmmac_adjust_link
* @dev: net device structure
@@ -349,7 +727,7 @@ static void stmmac_adjust_link(struct net_device *dev)
case 1000:
if (likely(priv->plat->has_gmac))
ctrl &= ~priv->hw->link.port;
- stmmac_hw_fix_mac_speed(priv);
+ stmmac_hw_fix_mac_speed(priv);
break;
case 100:
case 10:
@@ -367,8 +745,8 @@ static void stmmac_adjust_link(struct net_device *dev)
break;
default:
if (netif_msg_link(priv))
- pr_warning("%s: Speed (%d) is not 10"
- " or 100!\n", dev->name, phydev->speed);
+ pr_warn("%s: Speed (%d) not 10/100\n",
+ dev->name, phydev->speed);
break;
}
@@ -399,6 +777,31 @@ static void stmmac_adjust_link(struct net_device *dev)
}
/**
+ * stmmac_check_pcs_mode: verify if RGMII/SGMII is supported
+ * @priv: driver private structure
+ * Description: this is to verify if the HW supports the PCS.
+ * Physical Coding Sublayer (PCS) interface that can be used when the MAC is
+ * configured for the TBI, RTBI, or SGMII PHY interface.
+ */
+static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
+{
+ int interface = priv->plat->interface;
+
+ if (priv->dma_cap.pcs) {
+ if ((interface & PHY_INTERFACE_MODE_RGMII) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_ID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_TXID)) {
+ pr_debug("STMMAC: PCS RGMII support enable\n");
+ priv->pcs = STMMAC_PCS_RGMII;
+ } else if (interface & PHY_INTERFACE_MODE_SGMII) {
+ pr_debug("STMMAC: PCS SGMII support enable\n");
+ priv->pcs = STMMAC_PCS_SGMII;
+ }
+ }
+}
+
+/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
* Description: it initializes the driver's PHY state, and attaches the PHY
@@ -419,10 +822,10 @@ static int stmmac_init_phy(struct net_device *dev)
if (priv->plat->phy_bus_name)
snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
- priv->plat->phy_bus_name, priv->plat->bus_id);
+ priv->plat->phy_bus_name, priv->plat->bus_id);
else
snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
- priv->plat->bus_id);
+ priv->plat->bus_id);
snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
priv->plat->phy_addr);
@@ -461,29 +864,57 @@ static int stmmac_init_phy(struct net_device *dev)
}
/**
- * display_ring
- * @p: pointer to the ring.
+ * stmmac_display_ring: display ring
+ * @head: pointer to the head of the ring passed.
* @size: size of the ring.
- * Description: display all the descriptors within the ring.
+ * @extend_desc: to verify if extended descriptors are used.
+ * Description: display the control/status and buffer descriptors.
*/
-static void display_ring(struct dma_desc *p, int size)
+static void stmmac_display_ring(void *head, int size, int extend_desc)
{
- struct tmp_s {
- u64 a;
- unsigned int b;
- unsigned int c;
- };
int i;
+ struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
+ struct dma_desc *p = (struct dma_desc *)head;
+
for (i = 0; i < size; i++) {
- struct tmp_s *x = (struct tmp_s *)(p + i);
- pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
- i, (unsigned int)virt_to_phys(&p[i]),
- (unsigned int)(x->a), (unsigned int)((x->a) >> 32),
- x->b, x->c);
+ u64 x;
+ if (extend_desc) {
+ x = *(u64 *) ep;
+ pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+ i, (unsigned int)virt_to_phys(ep),
+ (unsigned int)x, (unsigned int)(x >> 32),
+ ep->basic.des2, ep->basic.des3);
+ ep++;
+ } else {
+ x = *(u64 *) p;
+ pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x",
+ i, (unsigned int)virt_to_phys(p),
+ (unsigned int)x, (unsigned int)(x >> 32),
+ p->des2, p->des3);
+ p++;
+ }
pr_info("\n");
}
}
+static void stmmac_display_rings(struct stmmac_priv *priv)
+{
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int rxsize = priv->dma_rx_size;
+
+ if (priv->extend_desc) {
+ pr_info("Extended RX descriptor ring:\n");
+ stmmac_display_ring((void *)priv->dma_erx, rxsize, 1);
+ pr_info("Extended TX descriptor ring:\n");
+ stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
+ } else {
+ pr_info("RX descriptor ring:\n");
+ stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
+ pr_info("TX descriptor ring:\n");
+ stmmac_display_ring((void *)priv->dma_tx, txsize, 0);
+ }
+}
+
static int stmmac_set_bfsize(int mtu, int bufsize)
{
int ret = bufsize;
@@ -501,6 +932,65 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
}
/**
+ * stmmac_clear_descriptors: clear descriptors
+ * @priv: driver private structure
+ * Description: this function is called to clear the tx and rx descriptors
+ * in case of both basic and extended descriptors are used.
+ */
+static void stmmac_clear_descriptors(struct stmmac_priv *priv)
+{
+ int i;
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int rxsize = priv->dma_rx_size;
+
+ /* Clear the Rx/Tx descriptors */
+ for (i = 0; i < rxsize; i++)
+ if (priv->extend_desc)
+ priv->hw->desc->init_rx_desc(&priv->dma_erx[i].basic,
+ priv->use_riwt, priv->mode,
+ (i == rxsize - 1));
+ else
+ priv->hw->desc->init_rx_desc(&priv->dma_rx[i],
+ priv->use_riwt, priv->mode,
+ (i == rxsize - 1));
+ for (i = 0; i < txsize; i++)
+ if (priv->extend_desc)
+ priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic,
+ priv->mode,
+ (i == txsize - 1));
+ else
+ priv->hw->desc->init_tx_desc(&priv->dma_tx[i],
+ priv->mode,
+ (i == txsize - 1));
+}
+
+static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
+ int i)
+{
+ struct sk_buff *skb;
+
+ skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
+ GFP_KERNEL);
+ if (unlikely(skb == NULL)) {
+ pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+ return 1;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ priv->rx_skbuff[i] = skb;
+ priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
+ priv->dma_buf_sz,
+ DMA_FROM_DEVICE);
+
+ p->des2 = priv->rx_skbuff_dma[i];
+
+ if ((priv->mode == STMMAC_RING_MODE) &&
+ (priv->dma_buf_sz == BUF_SIZE_16KiB))
+ priv->hw->ring->init_desc3(p);
+
+ return 0;
+}
+
+/**
* init_dma_desc_rings - init the RX/TX descriptor rings
* @dev: net device structure
* Description: this function initializes the DMA RX/TX descriptors
@@ -511,110 +1001,114 @@ static void init_dma_desc_rings(struct net_device *dev)
{
int i;
struct stmmac_priv *priv = netdev_priv(dev);
- struct sk_buff *skb;
unsigned int txsize = priv->dma_tx_size;
unsigned int rxsize = priv->dma_rx_size;
- unsigned int bfsize;
- int dis_ic = 0;
- int des3_as_data_buf = 0;
+ unsigned int bfsize = 0;
/* Set the max buffer size according to the DESC mode
- * and the MTU. Note that RING mode allows 16KiB bsize. */
- bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+ * and the MTU. Note that RING mode allows 16KiB bsize.
+ */
+ if (priv->mode == STMMAC_RING_MODE)
+ bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
- if (bfsize == BUF_SIZE_16KiB)
- des3_as_data_buf = 1;
- else
+ if (bfsize < BUF_SIZE_16KiB)
bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
txsize, rxsize, bfsize);
- priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
- GFP_KERNEL);
- priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
- GFP_KERNEL);
- priv->dma_rx =
- (struct dma_desc *)dma_alloc_coherent(priv->device,
- rxsize *
+ if (priv->extend_desc) {
+ priv->dma_erx = dma_alloc_coherent(priv->device, rxsize *
+ sizeof(struct
+ dma_extended_desc),
+ &priv->dma_rx_phy,
+ GFP_KERNEL);
+ priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
+ sizeof(struct
+ dma_extended_desc),
+ &priv->dma_tx_phy,
+ GFP_KERNEL);
+ if ((!priv->dma_erx) || (!priv->dma_etx))
+ return;
+ } else {
+ priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
- priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
- GFP_KERNEL);
- priv->dma_tx =
- (struct dma_desc *)dma_alloc_coherent(priv->device,
- txsize *
+ priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
sizeof(struct dma_desc),
&priv->dma_tx_phy,
GFP_KERNEL);
-
- if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
- pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
- return;
+ if ((!priv->dma_rx) || (!priv->dma_tx))
+ return;
}
- DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
- "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
- dev->name, priv->dma_rx, priv->dma_tx,
- (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
+ priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
+ GFP_KERNEL);
+ priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
+ GFP_KERNEL);
+ priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
+ GFP_KERNEL);
+ priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
+ GFP_KERNEL);
+ if (netif_msg_drv(priv))
+ pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
+ (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
/* RX INITIALIZATION */
- DBG(probe, INFO, "stmmac: SKB addresses:\n"
- "skb\t\tskb data\tdma data\n");
-
+ DBG(probe, INFO, "stmmac: SKB addresses:\nskb\t\tskb data\tdma data\n");
for (i = 0; i < rxsize; i++) {
- struct dma_desc *p = priv->dma_rx + i;
+ struct dma_desc *p;
+ if (priv->extend_desc)
+ p = &((priv->dma_erx + i)->basic);
+ else
+ p = priv->dma_rx + i;
- skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
- GFP_KERNEL);
- if (unlikely(skb == NULL)) {
- pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+ if (stmmac_init_rx_buffers(priv, p, i))
break;
- }
- skb_reserve(skb, NET_IP_ALIGN);
- priv->rx_skbuff[i] = skb;
- priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
- bfsize, DMA_FROM_DEVICE);
-
- p->des2 = priv->rx_skbuff_dma[i];
-
- priv->hw->ring->init_desc3(des3_as_data_buf, p);
DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
- priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
+ priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
}
priv->cur_rx = 0;
priv->dirty_rx = (unsigned int)(i - rxsize);
priv->dma_buf_sz = bfsize;
buf_sz = bfsize;
+ /* Setup the chained descriptor addresses */
+ if (priv->mode == STMMAC_CHAIN_MODE) {
+ if (priv->extend_desc) {
+ priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
+ rxsize, 1);
+ priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
+ txsize, 1);
+ } else {
+ priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
+ rxsize, 0);
+ priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
+ txsize, 0);
+ }
+ }
+
/* TX INITIALIZATION */
for (i = 0; i < txsize; i++) {
+ struct dma_desc *p;
+ if (priv->extend_desc)
+ p = &((priv->dma_etx + i)->basic);
+ else
+ p = priv->dma_tx + i;
+ p->des2 = 0;
+ priv->tx_skbuff_dma[i] = 0;
priv->tx_skbuff[i] = NULL;
- priv->dma_tx[i].des2 = 0;
}
- /* In case of Chained mode this sets the des3 to the next
- * element in the chain */
- priv->hw->ring->init_dma_chain(priv->dma_rx, priv->dma_rx_phy, rxsize);
- priv->hw->ring->init_dma_chain(priv->dma_tx, priv->dma_tx_phy, txsize);
-
priv->dirty_tx = 0;
priv->cur_tx = 0;
- if (priv->use_riwt)
- dis_ic = 1;
- /* Clear the Rx/Tx descriptors */
- priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
- priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
+ stmmac_clear_descriptors(priv);
- if (netif_msg_hw(priv)) {
- pr_info("RX descriptor ring:\n");
- display_ring(priv->dma_rx, rxsize);
- pr_info("TX descriptor ring:\n");
- display_ring(priv->dma_tx, txsize);
- }
+ if (netif_msg_hw(priv))
+ stmmac_display_rings(priv);
}
static void dma_free_rx_skbufs(struct stmmac_priv *priv)
@@ -637,13 +1131,20 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
for (i = 0; i < priv->dma_tx_size; i++) {
if (priv->tx_skbuff[i] != NULL) {
- struct dma_desc *p = priv->dma_tx + i;
- if (p->des2)
- dma_unmap_single(priv->device, p->des2,
+ struct dma_desc *p;
+ if (priv->extend_desc)
+ p = &((priv->dma_etx + i)->basic);
+ else
+ p = priv->dma_tx + i;
+
+ if (priv->tx_skbuff_dma[i])
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[i],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
+ priv->tx_skbuff_dma[i] = 0;
}
}
}
@@ -654,29 +1155,38 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
dma_free_rx_skbufs(priv);
dma_free_tx_skbufs(priv);
- /* Free the region of consistent memory previously allocated for
- * the DMA */
- dma_free_coherent(priv->device,
- priv->dma_tx_size * sizeof(struct dma_desc),
- priv->dma_tx, priv->dma_tx_phy);
- dma_free_coherent(priv->device,
- priv->dma_rx_size * sizeof(struct dma_desc),
- priv->dma_rx, priv->dma_rx_phy);
+ /* Free DMA regions of consistent memory previously allocated */
+ if (!priv->extend_desc) {
+ dma_free_coherent(priv->device,
+ priv->dma_tx_size * sizeof(struct dma_desc),
+ priv->dma_tx, priv->dma_tx_phy);
+ dma_free_coherent(priv->device,
+ priv->dma_rx_size * sizeof(struct dma_desc),
+ priv->dma_rx, priv->dma_rx_phy);
+ } else {
+ dma_free_coherent(priv->device, priv->dma_tx_size *
+ sizeof(struct dma_extended_desc),
+ priv->dma_etx, priv->dma_tx_phy);
+ dma_free_coherent(priv->device, priv->dma_rx_size *
+ sizeof(struct dma_extended_desc),
+ priv->dma_erx, priv->dma_rx_phy);
+ }
kfree(priv->rx_skbuff_dma);
kfree(priv->rx_skbuff);
+ kfree(priv->tx_skbuff_dma);
kfree(priv->tx_skbuff);
}
/**
* stmmac_dma_operation_mode - HW DMA operation mode
- * @priv : pointer to the private device structure.
+ * @priv: driver private structure
* Description: it sets the DMA operation mode: tx/rx DMA thresholds
* or Store-And-Forward capability.
*/
static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
{
if (likely(priv->plat->force_sf_dma_mode ||
- ((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) {
+ ((priv->plat->tx_coe) && (!priv->no_csum_insertion)))) {
/*
* In case of GMAC, SF mode can be enabled
* to perform the TX COE in HW. This depends on:
@@ -684,8 +1194,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
* 2) There is no bugged Jumbo frame support
* that needs to not insert csum in the TDES.
*/
- priv->hw->dma->dma_mode(priv->ioaddr,
- SF_DMA_MODE, SF_DMA_MODE);
+ priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);
tc = SF_DMA_MODE;
} else
priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
@@ -693,7 +1202,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
/**
* stmmac_tx_clean:
- * @priv: private data pointer
+ * @priv: driver private structure
* Description: it reclaims resources after transmission completes.
*/
static void stmmac_tx_clean(struct stmmac_priv *priv)
@@ -708,40 +1217,50 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
int last;
unsigned int entry = priv->dirty_tx % txsize;
struct sk_buff *skb = priv->tx_skbuff[entry];
- struct dma_desc *p = priv->dma_tx + entry;
+ struct dma_desc *p;
+
+ if (priv->extend_desc)
+ p = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ p = priv->dma_tx + entry;
/* Check if the descriptor is owned by the DMA. */
if (priv->hw->desc->get_tx_owner(p))
break;
- /* Verify tx error by looking at the last segment */
+ /* Verify tx error by looking at the last segment. */
last = priv->hw->desc->get_tx_ls(p);
if (likely(last)) {
int tx_error =
- priv->hw->desc->tx_status(&priv->dev->stats,
- &priv->xstats, p,
- priv->ioaddr);
+ priv->hw->desc->tx_status(&priv->dev->stats,
+ &priv->xstats, p,
+ priv->ioaddr);
if (likely(tx_error == 0)) {
priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++;
} else
priv->dev->stats.tx_errors++;
+
+ stmmac_get_tx_hwtstamp(priv, entry, skb);
}
TX_DBG("%s: curr %d, dirty %d\n", __func__,
- priv->cur_tx, priv->dirty_tx);
+ priv->cur_tx, priv->dirty_tx);
- if (likely(p->des2))
- dma_unmap_single(priv->device, p->des2,
+ if (likely(priv->tx_skbuff_dma[entry])) {
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[entry],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
- priv->hw->ring->clean_desc3(p);
+ priv->tx_skbuff_dma[entry] = 0;
+ }
+ priv->hw->ring->clean_desc3(priv, p);
if (likely(skb != NULL)) {
dev_kfree_skb(skb);
priv->tx_skbuff[entry] = NULL;
}
- priv->hw->desc->release_tx_desc(p);
+ priv->hw->desc->release_tx_desc(p, priv->mode);
priv->dirty_tx++;
}
@@ -749,7 +1268,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
netif_tx_lock(priv->dev);
if (netif_queue_stopped(priv->dev) &&
- stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
+ stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
TX_DBG("%s: restart transmit\n", __func__);
netif_wake_queue(priv->dev);
}
@@ -773,20 +1292,29 @@ static inline void stmmac_disable_dma_irq(struct stmmac_priv *priv)
priv->hw->dma->disable_dma_irq(priv->ioaddr);
}
-
/**
- * stmmac_tx_err:
- * @priv: pointer to the private device structure
+ * stmmac_tx_err: irq tx error mng function
+ * @priv: driver private structure
* Description: it cleans the descriptors and restarts the transmission
* in case of errors.
*/
static void stmmac_tx_err(struct stmmac_priv *priv)
{
+ int i;
+ int txsize = priv->dma_tx_size;
netif_stop_queue(priv->dev);
priv->hw->dma->stop_tx(priv->ioaddr);
dma_free_tx_skbufs(priv);
- priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+ for (i = 0; i < txsize; i++)
+ if (priv->extend_desc)
+ priv->hw->desc->init_tx_desc(&priv->dma_etx[i].basic,
+ priv->mode,
+ (i == txsize - 1));
+ else
+ priv->hw->desc->init_tx_desc(&priv->dma_tx[i],
+ priv->mode,
+ (i == txsize - 1));
priv->dirty_tx = 0;
priv->cur_tx = 0;
priv->hw->dma->start_tx(priv->ioaddr);
@@ -795,6 +1323,14 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
netif_wake_queue(priv->dev);
}
+/**
+ * stmmac_dma_interrupt: DMA ISR
+ * @priv: driver private structure
+ * Description: this is the DMA ISR. It is called by the main ISR.
+ * It calls the dwmac dma routine to understand which type of interrupt
+ * happened. In case of there is a Normal interrupt and either TX or RX
+ * interrupt happened so the NAPI is scheduled.
+ */
static void stmmac_dma_interrupt(struct stmmac_priv *priv)
{
int status;
@@ -817,13 +1353,16 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
stmmac_tx_err(priv);
}
+/**
+ * stmmac_mmc_setup: setup the Mac Management Counters (MMC)
+ * @priv: driver private structure
+ * Description: this masks the MMC irq, in fact, the counters are managed in SW.
+ */
static void stmmac_mmc_setup(struct stmmac_priv *priv)
{
unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
- MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
+ MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
- /* Mask MMC irq, counters are managed in SW and registers
- * are cleared on each READ eventually. */
dwmac_mmc_intr_all_mask(priv->ioaddr);
if (priv->dma_cap.rmon) {
@@ -837,8 +1376,7 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
{
u32 hwid = priv->hw->synopsys_uid;
- /* Only check valid Synopsys Id because old MAC chips
- * have no HW registers where get the ID */
+ /* Check Synopsys Id (not available on old chips) */
if (likely(hwid)) {
u32 uid = ((hwid & 0x0000ff00) >> 8);
u32 synid = (hwid & 0x000000ff);
@@ -852,14 +1390,24 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
}
/**
- * stmmac_selec_desc_mode
- * @priv : private structure
- * Description: select the Enhanced/Alternate or Normal descriptors
+ * stmmac_selec_desc_mode: to select among: normal/alternate/extend descriptors
+ * @priv: driver private structure
+ * Description: select the Enhanced/Alternate or Normal descriptors.
+ * In case of Enhanced/Alternate, it looks at the extended descriptors are
+ * supported by the HW cap. register.
*/
static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
{
if (priv->plat->enh_desc) {
pr_info(" Enhanced/Alternate descriptors\n");
+
+ /* GMAC older than 3.50 has no extended descriptors */
+ if (priv->synopsys_id >= DWMAC_CORE_3_50) {
+ pr_info("\tEnabled extended descriptors\n");
+ priv->extend_desc = 1;
+ } else
+ pr_warn("Extended descriptors not supported\n");
+
priv->hw->desc = &enh_desc_ops;
} else {
pr_info(" Normal descriptors\n");
@@ -868,8 +1416,8 @@ static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
}
/**
- * stmmac_get_hw_features
- * @priv : private device pointer
+ * stmmac_get_hw_features: get MAC capabilities from the HW cap. register.
+ * @priv: driver private structure
* Description:
* new GMAC chip generations have a new register to indicate the
* presence of the optional feature/functions.
@@ -887,69 +1435,78 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)
priv->dma_cap.mbps_1000 = (hw_cap & DMA_HW_FEAT_GMIISEL) >> 1;
priv->dma_cap.half_duplex = (hw_cap & DMA_HW_FEAT_HDSEL) >> 2;
priv->dma_cap.hash_filter = (hw_cap & DMA_HW_FEAT_HASHSEL) >> 4;
- priv->dma_cap.multi_addr =
- (hw_cap & DMA_HW_FEAT_ADDMACADRSEL) >> 5;
+ priv->dma_cap.multi_addr = (hw_cap & DMA_HW_FEAT_ADDMAC) >> 5;
priv->dma_cap.pcs = (hw_cap & DMA_HW_FEAT_PCSSEL) >> 6;
priv->dma_cap.sma_mdio = (hw_cap & DMA_HW_FEAT_SMASEL) >> 8;
priv->dma_cap.pmt_remote_wake_up =
- (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
+ (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9;
priv->dma_cap.pmt_magic_frame =
- (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
+ (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10;
/* MMC */
priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11;
- /* IEEE 1588-2002*/
+ /* IEEE 1588-2002 */
priv->dma_cap.time_stamp =
- (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
- /* IEEE 1588-2008*/
+ (hw_cap & DMA_HW_FEAT_TSVER1SEL) >> 12;
+ /* IEEE 1588-2008 */
priv->dma_cap.atime_stamp =
- (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
+ (hw_cap & DMA_HW_FEAT_TSVER2SEL) >> 13;
/* 802.3az - Energy-Efficient Ethernet (EEE) */
priv->dma_cap.eee = (hw_cap & DMA_HW_FEAT_EEESEL) >> 14;
priv->dma_cap.av = (hw_cap & DMA_HW_FEAT_AVSEL) >> 15;
/* TX and RX csum */
priv->dma_cap.tx_coe = (hw_cap & DMA_HW_FEAT_TXCOESEL) >> 16;
priv->dma_cap.rx_coe_type1 =
- (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
+ (hw_cap & DMA_HW_FEAT_RXTYP1COE) >> 17;
priv->dma_cap.rx_coe_type2 =
- (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
+ (hw_cap & DMA_HW_FEAT_RXTYP2COE) >> 18;
priv->dma_cap.rxfifo_over_2048 =
- (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
+ (hw_cap & DMA_HW_FEAT_RXFIFOSIZE) >> 19;
/* TX and RX number of channels */
priv->dma_cap.number_rx_channel =
- (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
+ (hw_cap & DMA_HW_FEAT_RXCHCNT) >> 20;
priv->dma_cap.number_tx_channel =
- (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
- /* Alternate (enhanced) DESC mode*/
- priv->dma_cap.enh_desc =
- (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
+ (hw_cap & DMA_HW_FEAT_TXCHCNT) >> 22;
+ /* Alternate (enhanced) DESC mode */
+ priv->dma_cap.enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24;
}
return hw_cap;
}
+/**
+ * stmmac_check_ether_addr: check if the MAC addr is valid
+ * @priv: driver private structure
+ * Description:
+ * it is to verify if the MAC address is valid, in case of failures it
+ * generates a random MAC address
+ */
static void stmmac_check_ether_addr(struct stmmac_priv *priv)
{
- /* verify if the MAC address is valid, in case of failures it
- * generates a random MAC address */
if (!is_valid_ether_addr(priv->dev->dev_addr)) {
priv->hw->mac->get_umac_addr((void __iomem *)
priv->dev->base_addr,
priv->dev->dev_addr, 0);
- if (!is_valid_ether_addr(priv->dev->dev_addr))
+ if (!is_valid_ether_addr(priv->dev->dev_addr))
eth_hw_addr_random(priv->dev);
}
- pr_warning("%s: device MAC address %pM\n", priv->dev->name,
- priv->dev->dev_addr);
+ pr_warn("%s: device MAC address %pM\n", priv->dev->name,
+ priv->dev->dev_addr);
}
+/**
+ * stmmac_init_dma_engine: DMA init.
+ * @priv: driver private structure
+ * Description:
+ * It inits the DMA invoking the specific MAC/GMAC callback.
+ * Some DMA parameters can be passed from the platform;
+ * in case of these are not passed a default is kept for the MAC or GMAC.
+ */
static int stmmac_init_dma_engine(struct stmmac_priv *priv)
{
int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;
int mixed_burst = 0;
+ int atds = 0;
- /* Some DMA parameters can be passed from the platform;
- * in case of these are not passed we keep a default
- * (good for all the chips) and init the DMA! */
if (priv->plat->dma_cfg) {
pbl = priv->plat->dma_cfg->pbl;
fixed_burst = priv->plat->dma_cfg->fixed_burst;
@@ -957,13 +1514,16 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
burst_len = priv->plat->dma_cfg->burst_len;
}
+ if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
+ atds = 1;
+
return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
burst_len, priv->dma_tx_phy,
- priv->dma_rx_phy);
+ priv->dma_rx_phy, atds);
}
/**
- * stmmac_tx_timer:
+ * stmmac_tx_timer: mitigation sw timer for tx.
* @data: data pointer
* Description:
* This is the timer handler to directly invoke the stmmac_tx_clean.
@@ -976,8 +1536,8 @@ static void stmmac_tx_timer(unsigned long data)
}
/**
- * stmmac_tx_timer:
- * @priv: private data structure
+ * stmmac_init_tx_coalesce: init tx mitigation options.
+ * @priv: driver private structure
* Description:
* This inits the transmit coalesce parameters: i.e. timer rate,
* timer handler and default threshold used for enabling the
@@ -1012,10 +1572,14 @@ static int stmmac_open(struct net_device *dev)
stmmac_check_ether_addr(priv);
- ret = stmmac_init_phy(dev);
- if (unlikely(ret)) {
- pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
- goto open_error;
+ if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
+ priv->pcs != STMMAC_PCS_RTBI) {
+ ret = stmmac_init_phy(dev);
+ if (ret) {
+ pr_err("%s: Cannot attach to PHY (error: %d)\n",
+ __func__, ret);
+ goto open_error;
+ }
}
/* Create and initialize the TX/RX descriptors chains. */
@@ -1043,7 +1607,7 @@ static int stmmac_open(struct net_device *dev)
/* Request the IRQ lines */
ret = request_irq(dev->irq, stmmac_interrupt,
- IRQF_SHARED, dev->name, dev);
+ IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
__func__, dev->irq, ret);
@@ -1055,8 +1619,8 @@ static int stmmac_open(struct net_device *dev)
ret = request_irq(priv->wol_irq, stmmac_interrupt,
IRQF_SHARED, dev->name, dev);
if (unlikely(ret < 0)) {
- pr_err("%s: ERROR: allocating the ext WoL IRQ %d "
- "(error: %d)\n", __func__, priv->wol_irq, ret);
+ pr_err("%s: ERROR: allocating the WoL IRQ %d (%d)\n",
+ __func__, priv->wol_irq, ret);
goto open_error_wolirq;
}
}
@@ -1084,10 +1648,14 @@ static int stmmac_open(struct net_device *dev)
stmmac_mmc_setup(priv);
+ ret = stmmac_init_ptp(priv);
+ if (ret)
+ pr_warn("%s: failed PTP initialisation\n", __func__);
+
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
if (ret < 0)
- pr_warning("%s: failed debugFS registration\n", __func__);
+ pr_warn("%s: failed debugFS registration\n", __func__);
#endif
/* Start the ball rolling... */
DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
@@ -1104,7 +1672,13 @@ static int stmmac_open(struct net_device *dev)
phy_start(priv->phydev);
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
- priv->eee_enabled = stmmac_eee_init(priv);
+
+ /* Using PCS we cannot dial with the phy registers at this stage
+ * so we do not support extra feature like EEE.
+ */
+ if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
+ priv->pcs != STMMAC_PCS_RTBI)
+ priv->eee_enabled = stmmac_eee_init(priv);
stmmac_init_tx_coalesce(priv);
@@ -1113,6 +1687,9 @@ static int stmmac_open(struct net_device *dev)
priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
}
+ if (priv->pcs && priv->hw->mac->ctrl_ane)
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 0);
+
napi_enable(&priv->napi);
netif_start_queue(dev);
@@ -1184,21 +1761,25 @@ static int stmmac_release(struct net_device *dev)
#endif
clk_disable_unprepare(priv->stmmac_clk);
+ stmmac_release_ptp(priv);
+
return 0;
}
/**
- * stmmac_xmit:
+ * stmmac_xmit: Tx entry point of the driver
* @skb : the socket buffer
* @dev : device pointer
- * Description : Tx entry point of the driver.
+ * Description : this is the tx entry point of the driver.
+ * It programs the chain or the ring and supports oversized frames
+ * and SG feature.
*/
static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int txsize = priv->dma_tx_size;
unsigned int entry;
- int i, csum_insertion = 0;
+ int i, csum_insertion = 0, is_jumbo = 0;
int nfrags = skb_shinfo(skb)->nr_frags;
struct dma_desc *desc, *first;
unsigned int nopaged_len = skb_headlen(skb);
@@ -1207,8 +1788,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
/* This is a hard error, log it. */
- pr_err("%s: BUG! Tx Ring full when queue awake\n",
- __func__);
+ pr_err("%s: Tx Ring full when queue awake\n", __func__);
}
return NETDEV_TX_BUSY;
}
@@ -1222,10 +1802,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef STMMAC_XMIT_DEBUG
if ((skb->len > ETH_FRAME_LEN) || nfrags)
- pr_debug("stmmac xmit: [entry %d]\n"
- "\tskb addr %p - len: %d - nopaged_len: %d\n"
+ pr_debug("%s: [entry %d]: skb addr %p len: %d nopagedlen: %d\n"
"\tn_frags: %d - ip_summed: %d - %s gso\n"
- "\ttx_count_frames %d\n", entry,
+ "\ttx_count_frames %d\n", __func__, entry,
skb, skb->len, nopaged_len, nfrags, skb->ip_summed,
!skb_is_gso(skb) ? "isn't" : "is",
priv->tx_count_frames);
@@ -1233,7 +1812,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
- desc = priv->dma_tx + entry;
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
+
first = desc;
#ifdef STMMAC_XMIT_DEBUG
@@ -1244,28 +1827,46 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
priv->tx_skbuff[entry] = skb;
- if (priv->hw->ring->is_jumbo_frm(skb->len, priv->plat->enh_desc)) {
- entry = priv->hw->ring->jumbo_frm(priv, skb, csum_insertion);
- desc = priv->dma_tx + entry;
+ /* To program the descriptors according to the size of the frame */
+ if (priv->mode == STMMAC_RING_MODE) {
+ is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
+ priv->plat->enh_desc);
+ if (unlikely(is_jumbo))
+ entry = priv->hw->ring->jumbo_frm(priv, skb,
+ csum_insertion);
} else {
+ is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
+ priv->plat->enh_desc);
+ if (unlikely(is_jumbo))
+ entry = priv->hw->chain->jumbo_frm(priv, skb,
+ csum_insertion);
+ }
+ if (likely(!is_jumbo)) {
desc->des2 = dma_map_single(priv->device, skb->data,
- nopaged_len, DMA_TO_DEVICE);
+ nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
- csum_insertion);
- }
+ csum_insertion, priv->mode);
+ } else
+ desc = first;
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
int len = skb_frag_size(frag);
entry = (++priv->cur_tx) % txsize;
- desc = priv->dma_tx + entry;
+ if (priv->extend_desc)
+ desc = (struct dma_desc *)(priv->dma_etx + entry);
+ else
+ desc = priv->dma_tx + entry;
TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->tx_skbuff[entry] = NULL;
- priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
+ priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
+ priv->mode);
wmb();
priv->hw->desc->set_tx_owner(desc);
wmb();
@@ -1298,11 +1899,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef STMMAC_XMIT_DEBUG
if (netif_msg_pktdata(priv)) {
- pr_info("stmmac xmit: current=%d, dirty=%d, entry=%d, "
- "first=%p, nfrags=%d\n",
- (priv->cur_tx % txsize), (priv->dirty_tx % txsize),
- entry, first, nfrags);
- display_ring(priv->dma_tx, txsize);
+ pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d"
+ __func__, (priv->cur_tx % txsize),
+ (priv->dirty_tx % txsize), entry, first, nfrags);
+ if (priv->extend_desc)
+ stmmac_display_ring((void *)priv->dma_etx, txsize, 1);
+ else
+ stmmac_display_ring((void *)priv->dma_tx, txsize, 0);
+
pr_info(">>> frame to be transmitted: ");
print_pkt(skb->data, skb->len);
}
@@ -1314,7 +1918,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
- skb_tx_timestamp(skb);
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ /* declare that device is doing timestamping */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ priv->hw->desc->enable_tx_timestamp(first);
+ }
+
+ if (!priv->hwts_tx_en)
+ skb_tx_timestamp(skb);
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
@@ -1323,14 +1935,26 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+/**
+ * stmmac_rx_refill: refill used skb preallocated buffers
+ * @priv: driver private structure
+ * Description : this is to reallocate the skb for the reception process
+ * that is based on zero-copy.
+ */
static inline void stmmac_rx_refill(struct stmmac_priv *priv)
{
unsigned int rxsize = priv->dma_rx_size;
int bfsize = priv->dma_buf_sz;
- struct dma_desc *p = priv->dma_rx;
for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) {
unsigned int entry = priv->dirty_rx % rxsize;
+ struct dma_desc *p;
+
+ if (priv->extend_desc)
+ p = (struct dma_desc *)(priv->dma_erx + entry);
+ else
+ p = priv->dma_rx + entry;
+
if (likely(priv->rx_skbuff[entry] == NULL)) {
struct sk_buff *skb;
@@ -1344,80 +1968,116 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
dma_map_single(priv->device, skb->data, bfsize,
DMA_FROM_DEVICE);
- (p + entry)->des2 = priv->rx_skbuff_dma[entry];
+ p->des2 = priv->rx_skbuff_dma[entry];
- if (unlikely(priv->plat->has_gmac))
- priv->hw->ring->refill_desc3(bfsize, p + entry);
+ priv->hw->ring->refill_desc3(priv, p);
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
wmb();
- priv->hw->desc->set_rx_owner(p + entry);
+ priv->hw->desc->set_rx_owner(p);
wmb();
}
}
+/**
+ * stmmac_rx_refill: refill used skb preallocated buffers
+ * @priv: driver private structure
+ * @limit: napi bugget.
+ * Description : this the function called by the napi poll method.
+ * It gets all the frames inside the ring.
+ */
static int stmmac_rx(struct stmmac_priv *priv, int limit)
{
unsigned int rxsize = priv->dma_rx_size;
unsigned int entry = priv->cur_rx % rxsize;
unsigned int next_entry;
unsigned int count = 0;
- struct dma_desc *p = priv->dma_rx + entry;
- struct dma_desc *p_next;
+ int coe = priv->plat->rx_coe;
#ifdef STMMAC_RX_DEBUG
if (netif_msg_hw(priv)) {
pr_debug(">>> stmmac_rx: descriptor ring:\n");
- display_ring(priv->dma_rx, rxsize);
+ if (priv->extend_desc)
+ stmmac_display_ring((void *)priv->dma_erx, rxsize, 1);
+ else
+ stmmac_display_ring((void *)priv->dma_rx, rxsize, 0);
}
#endif
- while (!priv->hw->desc->get_rx_owner(p)) {
+ while (count < limit) {
int status;
+ struct dma_desc *p;
- if (count >= limit)
+ if (priv->extend_desc)
+ p = (struct dma_desc *)(priv->dma_erx + entry);
+ else
+ p = priv->dma_rx + entry;
+
+ if (priv->hw->desc->get_rx_owner(p))
break;
count++;
next_entry = (++priv->cur_rx) % rxsize;
- p_next = priv->dma_rx + next_entry;
- prefetch(p_next);
+ if (priv->extend_desc)
+ prefetch(priv->dma_erx + next_entry);
+ else
+ prefetch(priv->dma_rx + next_entry);
/* read the status of the incoming frame */
- status = (priv->hw->desc->rx_status(&priv->dev->stats,
- &priv->xstats, p));
- if (unlikely(status == discard_frame))
+ status = priv->hw->desc->rx_status(&priv->dev->stats,
+ &priv->xstats, p);
+ if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status))
+ priv->hw->desc->rx_extended_status(&priv->dev->stats,
+ &priv->xstats,
+ priv->dma_erx +
+ entry);
+ if (unlikely(status == discard_frame)) {
priv->dev->stats.rx_errors++;
- else {
+ if (priv->hwts_rx_en && !priv->extend_desc) {
+ /* DESC2 & DESC3 will be overwitten by device
+ * with timestamp value, hence reinitialize
+ * them in stmmac_rx_refill() function so that
+ * device can reuse it.
+ */
+ priv->rx_skbuff[entry] = NULL;
+ dma_unmap_single(priv->device,
+ priv->rx_skbuff_dma[entry],
+ priv->dma_buf_sz,
+ DMA_FROM_DEVICE);
+ }
+ } else {
struct sk_buff *skb;
int frame_len;
- frame_len = priv->hw->desc->get_rx_frame_len(p,
- priv->plat->rx_coe);
+ frame_len = priv->hw->desc->get_rx_frame_len(p, coe);
+
/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
- * Type frames (LLC/LLC-SNAP) */
+ * Type frames (LLC/LLC-SNAP)
+ */
if (unlikely(status != llc_snap))
frame_len -= ETH_FCS_LEN;
#ifdef STMMAC_RX_DEBUG
if (frame_len > ETH_FRAME_LEN)
pr_debug("\tRX frame size %d, COE status: %d\n",
- frame_len, status);
+ frame_len, status);
if (netif_msg_hw(priv))
pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
- p, entry, p->des2);
+ p, entry, p->des2);
#endif
skb = priv->rx_skbuff[entry];
if (unlikely(!skb)) {
pr_err("%s: Inconsistent Rx descriptor chain\n",
- priv->dev->name);
+ priv->dev->name);
priv->dev->stats.rx_dropped++;
break;
}
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;
+ stmmac_get_rx_hwtstamp(priv, entry, skb);
+
skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
@@ -1430,7 +2090,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
#endif
skb->protocol = eth_type_trans(skb, priv->dev);
- if (unlikely(!priv->plat->rx_coe))
+ if (unlikely(!coe))
skb_checksum_none_assert(skb);
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1441,7 +2101,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
priv->dev->stats.rx_bytes += frame_len;
}
entry = next_entry;
- p = p_next; /* use prefetched values */
}
stmmac_rx_refill(priv);
@@ -1499,18 +2158,16 @@ static int stmmac_config(struct net_device *dev, struct ifmap *map)
/* Don't allow changing the I/O address */
if (map->base_addr != dev->base_addr) {
- pr_warning("%s: can't change I/O address\n", dev->name);
+ pr_warn("%s: can't change I/O address\n", dev->name);
return -EOPNOTSUPP;
}
/* Don't allow changing the IRQ */
if (map->irq != dev->irq) {
- pr_warning("%s: can't change IRQ number %d\n",
- dev->name, dev->irq);
+ pr_warn("%s: not change IRQ number %d\n", dev->name, dev->irq);
return -EOPNOTSUPP;
}
- /* ignore other fields */
return 0;
}
@@ -1570,7 +2227,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
}
static netdev_features_t stmmac_fix_features(struct net_device *dev,
- netdev_features_t features)
+ netdev_features_t features)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -1584,13 +2241,22 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
/* Some GMAC devices have a bugged Jumbo frame support that
* needs to have the Tx COE disabled for oversized frames
* (due to limited buffer sizes). In this case we disable
- * the TX csum insertionin the TDES and not use SF. */
+ * the TX csum insertionin the TDES and not use SF.
+ */
if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
features &= ~NETIF_F_ALL_CSUM;
return features;
}
+/**
+ * stmmac_interrupt - main ISR
+ * @irq: interrupt number.
+ * @dev_id: to pass the net device pointer.
+ * Description: this is the main driver interrupt service routine.
+ * It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI
+ * interrupts.
+ */
static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
@@ -1604,30 +2270,14 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
/* To handle GMAC own interrupts */
if (priv->plat->has_gmac) {
int status = priv->hw->mac->host_irq_status((void __iomem *)
- dev->base_addr);
+ dev->base_addr,
+ &priv->xstats);
if (unlikely(status)) {
- if (status & core_mmc_tx_irq)
- priv->xstats.mmc_tx_irq_n++;
- if (status & core_mmc_rx_irq)
- priv->xstats.mmc_rx_irq_n++;
- if (status & core_mmc_rx_csum_offload_irq)
- priv->xstats.mmc_rx_csum_offload_irq_n++;
- if (status & core_irq_receive_pmt_irq)
- priv->xstats.irq_receive_pmt_irq_n++;
-
/* For LPI we need to save the tx status */
- if (status & core_irq_tx_path_in_lpi_mode) {
- priv->xstats.irq_tx_path_in_lpi_mode_n++;
+ if (status & CORE_IRQ_TX_PATH_IN_LPI_MODE)
priv->tx_path_in_lpi_mode = true;
- }
- if (status & core_irq_tx_path_exit_lpi_mode) {
- priv->xstats.irq_tx_path_exit_lpi_mode_n++;
+ if (status & CORE_IRQ_TX_PATH_EXIT_LPI_MODE)
priv->tx_path_in_lpi_mode = false;
- }
- if (status & core_irq_rx_path_in_lpi_mode)
- priv->xstats.irq_rx_path_in_lpi_mode_n++;
- if (status & core_irq_rx_path_exit_lpi_mode)
- priv->xstats.irq_rx_path_exit_lpi_mode_n++;
}
}
@@ -1639,7 +2289,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling receive - used by NETCONSOLE and other diagnostic tools
- * to allow network I/O with interrupts disabled. */
+ * to allow network I/O with interrupts disabled.
+ */
static void stmmac_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
@@ -1655,21 +2306,30 @@ static void stmmac_poll_controller(struct net_device *dev)
* a proprietary structure used to pass information to the driver.
* @cmd: IOCTL command
* Description:
- * Currently there are no special functionality supported in IOCTL, just the
- * phy_mii_ioctl(...) can be invoked.
+ * Currently it supports the phy_mii_ioctl(...) and HW time stamping.
*/
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- int ret;
+ int ret = -EOPNOTSUPP;
if (!netif_running(dev))
return -EINVAL;
- if (!priv->phydev)
- return -EINVAL;
-
- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ return -EINVAL;
+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ break;
+ case SIOCSHWTSTAMP:
+ ret = stmmac_hwtstamp_ioctl(dev, rq);
+ break;
+ default:
+ break;
+ }
return ret;
}
@@ -1679,40 +2339,51 @@ static struct dentry *stmmac_fs_dir;
static struct dentry *stmmac_rings_status;
static struct dentry *stmmac_dma_cap;
-static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
+static void sysfs_display_ring(void *head, int size, int extend_desc,
+ struct seq_file *seq)
{
- struct tmp_s {
- u64 a;
- unsigned int b;
- unsigned int c;
- };
int i;
- struct net_device *dev = seq->private;
- struct stmmac_priv *priv = netdev_priv(dev);
+ struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
+ struct dma_desc *p = (struct dma_desc *)head;
- seq_printf(seq, "=======================\n");
- seq_printf(seq, " RX descriptor ring\n");
- seq_printf(seq, "=======================\n");
-
- for (i = 0; i < priv->dma_rx_size; i++) {
- struct tmp_s *x = (struct tmp_s *)(priv->dma_rx + i);
- seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
- i, (unsigned int)(x->a),
- (unsigned int)((x->a) >> 32), x->b, x->c);
+ for (i = 0; i < size; i++) {
+ u64 x;
+ if (extend_desc) {
+ x = *(u64 *) ep;
+ seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+ i, (unsigned int)virt_to_phys(ep),
+ (unsigned int)x, (unsigned int)(x >> 32),
+ ep->basic.des2, ep->basic.des3);
+ ep++;
+ } else {
+ x = *(u64 *) p;
+ seq_printf(seq, "%d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
+ i, (unsigned int)virt_to_phys(ep),
+ (unsigned int)x, (unsigned int)(x >> 32),
+ p->des2, p->des3);
+ p++;
+ }
seq_printf(seq, "\n");
}
+}
- seq_printf(seq, "\n");
- seq_printf(seq, "=======================\n");
- seq_printf(seq, " TX descriptor ring\n");
- seq_printf(seq, "=======================\n");
+static int stmmac_sysfs_ring_read(struct seq_file *seq, void *v)
+{
+ struct net_device *dev = seq->private;
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int rxsize = priv->dma_rx_size;
- for (i = 0; i < priv->dma_tx_size; i++) {
- struct tmp_s *x = (struct tmp_s *)(priv->dma_tx + i);
- seq_printf(seq, "[%d] DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
- i, (unsigned int)(x->a),
- (unsigned int)((x->a) >> 32), x->b, x->c);
- seq_printf(seq, "\n");
+ if (priv->extend_desc) {
+ seq_printf(seq, "Extended RX descriptor ring:\n");
+ sysfs_display_ring((void *)priv->dma_erx, rxsize, 1, seq);
+ seq_printf(seq, "Extended TX descriptor ring:\n");
+ sysfs_display_ring((void *)priv->dma_etx, txsize, 1, seq);
+ } else {
+ seq_printf(seq, "RX descriptor ring:\n");
+ sysfs_display_ring((void *)priv->dma_rx, rxsize, 0, seq);
+ seq_printf(seq, "TX descriptor ring:\n");
+ sysfs_display_ring((void *)priv->dma_tx, txsize, 0, seq);
}
return 0;
@@ -1817,8 +2488,8 @@ static int stmmac_init_fs(struct net_device *dev)
/* Entry to report DMA RX/TX rings */
stmmac_rings_status = debugfs_create_file("descriptors_status",
- S_IRUGO, stmmac_fs_dir, dev,
- &stmmac_rings_status_fops);
+ S_IRUGO, stmmac_fs_dir, dev,
+ &stmmac_rings_status_fops);
if (!stmmac_rings_status || IS_ERR(stmmac_rings_status)) {
pr_info("ERROR creating stmmac ring debugfs file\n");
@@ -1868,7 +2539,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
/**
* stmmac_hw_init - Init the MAC device
- * @priv : pointer to the private device structure.
+ * @priv: driver private structure
* Description: this function detects which MAC device
* (GMAC/MAC10-100) has to attached, checks the HW capability
* (if supported) and sets the driver's features (for example
@@ -1877,7 +2548,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
*/
static int stmmac_hw_init(struct stmmac_priv *priv)
{
- int ret = 0;
+ int ret;
struct mac_device_info *mac;
/* Identify the MAC HW device */
@@ -1892,12 +2563,23 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
priv->hw = mac;
- /* To use the chained or ring mode */
- priv->hw->ring = &ring_mode_ops;
-
/* Get and dump the chip ID */
priv->synopsys_id = stmmac_get_synopsys_id(priv);
+ /* To use alternate (extended) or normal descriptor structures */
+ stmmac_selec_desc_mode(priv);
+
+ /* To use the chained or ring mode */
+ if (chain_mode) {
+ priv->hw->chain = &chain_mode_ops;
+ pr_info(" Chain mode enabled\n");
+ priv->mode = STMMAC_CHAIN_MODE;
+ } else {
+ priv->hw->ring = &ring_mode_ops;
+ pr_info(" Ring mode enabled\n");
+ priv->mode = STMMAC_RING_MODE;
+ }
+
/* Get the HW capability (new GMAC newer than 3.50a) */
priv->hw_cap_support = stmmac_get_hw_features(priv);
if (priv->hw_cap_support) {
@@ -1921,14 +2603,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
} else
pr_info(" No HW DMA feature register supported");
- /* Select the enhnaced/normal descriptor structures */
- stmmac_selec_desc_mode(priv);
-
- /* Enable the IPC (Checksum Offload) and check if the feature has been
- * enabled during the core configuration. */
ret = priv->hw->mac->rx_ipc(priv->ioaddr);
if (!ret) {
- pr_warning(" RX IPC Checksum Offload not configured.\n");
+ pr_warn(" RX IPC Checksum Offload not configured.\n");
priv->plat->rx_coe = STMMAC_RX_COE_NONE;
}
@@ -1943,7 +2620,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
device_set_wakeup_capable(priv->device, 1);
}
- return ret;
+ return 0;
}
/**
@@ -1984,12 +2661,15 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
stmmac_verify_args();
/* Override with kernel parameters if supplied XXX CRS XXX
- * this needs to have multiple instances */
+ * this needs to have multiple instances
+ */
if ((phyaddr >= 0) && (phyaddr <= 31))
priv->plat->phy_addr = phyaddr;
/* Init MAC and get the capabilities */
- stmmac_hw_init(priv);
+ ret = stmmac_hw_init(priv);
+ if (ret)
+ goto error_free_netdev;
ndev->netdev_ops = &stmmac_netdev_ops;
@@ -1999,7 +2679,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
- ndev->features |= NETIF_F_HW_VLAN_RX;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
#endif
priv->msg_enable = netif_msg_init(debug, default_msg_level);
@@ -2029,7 +2709,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
priv->stmmac_clk = clk_get(priv->device, STMMAC_RESOURCE_NAME);
if (IS_ERR(priv->stmmac_clk)) {
- pr_warning("%s: warning: cannot get CSR clock\n", __func__);
+ pr_warn("%s: warning: cannot get CSR clock\n", __func__);
goto error_clk_get;
}
@@ -2044,12 +2724,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
else
priv->clk_csr = priv->plat->clk_csr;
- /* MDIO bus Registration */
- ret = stmmac_mdio_register(ndev);
- if (ret < 0) {
- pr_debug("%s: MDIO bus (id: %d) registration failed",
- __func__, priv->plat->bus_id);
- goto error_mdio_register;
+ stmmac_check_pcs_mode(priv);
+
+ if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
+ priv->pcs != STMMAC_PCS_RTBI) {
+ /* MDIO bus Registration */
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+ pr_debug("%s: MDIO bus (id: %d) registration failed",
+ __func__, priv->plat->bus_id);
+ goto error_mdio_register;
+ }
}
return priv;
@@ -2060,6 +2745,7 @@ error_clk_get:
unregister_netdev(ndev);
error_netdev_register:
netif_napi_del(&priv->napi);
+error_free_netdev:
free_netdev(ndev);
return NULL;
@@ -2081,7 +2767,9 @@ int stmmac_dvr_remove(struct net_device *ndev)
priv->hw->dma->stop_tx(priv->ioaddr);
stmmac_set_mac(priv->ioaddr, false);
- stmmac_mdio_unregister(ndev);
+ if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
+ priv->pcs != STMMAC_PCS_RTBI)
+ stmmac_mdio_unregister(ndev);
netif_carrier_off(ndev);
unregister_netdev(ndev);
free_netdev(ndev);
@@ -2093,7 +2781,6 @@ int stmmac_dvr_remove(struct net_device *ndev)
int stmmac_suspend(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
- int dis_ic = 0;
unsigned long flags;
if (!ndev || !netif_running(ndev))
@@ -2107,18 +2794,13 @@ int stmmac_suspend(struct net_device *ndev)
netif_device_detach(ndev);
netif_stop_queue(ndev);
- if (priv->use_riwt)
- dis_ic = 1;
-
napi_disable(&priv->napi);
/* Stop TX/RX DMA */
priv->hw->dma->stop_tx(priv->ioaddr);
priv->hw->dma->stop_rx(priv->ioaddr);
- /* Clear the Rx/Tx descriptors */
- priv->hw->desc->init_rx_desc(priv->dma_rx, priv->dma_rx_size,
- dis_ic);
- priv->hw->desc->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+
+ stmmac_clear_descriptors(priv);
/* Enable Power down mode by programming the PMT regs */
if (device_may_wakeup(priv->device))
@@ -2146,7 +2828,8 @@ int stmmac_resume(struct net_device *ndev)
* automatically as soon as a magic packet or a Wake-up frame
* is received. Anyway, it's better to manually clear
* this bit because it can generate problems while resuming
- * from another devices (e.g. serial console). */
+ * from another devices (e.g. serial console).
+ */
if (device_may_wakeup(priv->device))
priv->hw->mac->pmt(priv->ioaddr, 0);
else
@@ -2257,6 +2940,9 @@ static int __init stmmac_cmdline_opt(char *str)
} else if (!strncmp(opt, "eee_timer:", 10)) {
if (kstrtoint(opt + 10, 0, &eee_timer))
goto err;
+ } else if (!strncmp(opt, "chain_mode:", 11)) {
+ if (kstrtoint(opt + 11, 0, &chain_mode))
+ goto err;
}
}
return 0;
@@ -2267,7 +2953,7 @@ err:
}
__setup("stmmaceth=", stmmac_cmdline_opt);
-#endif
+#endif /* MODULE */
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet device driver");
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index 0b9829fe3eea..cc15039eaa47 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -177,7 +177,7 @@ int stmmac_mdio_register(struct net_device *ndev)
new_bus->write = &stmmac_mdio_write;
new_bus->reset = &stmmac_mdio_reset;
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
- new_bus->name, priv->plat->bus_id);
+ new_bus->name, priv->plat->bus_id);
new_bus->priv = ndev;
new_bus->irq = irqlist;
new_bus->phy_mask = mdio_bus_data->phy_mask;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 19b3a2567a46..023b7c29cb2f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -88,7 +88,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
continue;
addr = pci_iomap(pdev, i, 0);
if (addr == NULL) {
- pr_err("%s: ERROR: cannot map register memory, aborting",
+ pr_err("%s: ERROR: cannot map register memory aborting",
__func__);
ret = -EIO;
goto err_out_map_failed;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index b43d68b40e50..1d3780f55ba2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -88,11 +88,9 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
if (!res)
return -ENODEV;
- addr = devm_request_and_ioremap(dev, res);
- if (!addr) {
- pr_err("%s: ERROR: memory mapping failed", __func__);
- return -ENOMEM;
- }
+ addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
if (pdev->dev.of_node) {
plat_dat = devm_kzalloc(&pdev->dev,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
new file mode 100644
index 000000000000..b8b0eeed0f92
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ PTP 1588 clock using the STMMAC.
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+*******************************************************************************/
+#include "stmmac.h"
+#include "stmmac_ptp.h"
+
+/**
+ * stmmac_adjust_freq
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ppb: desired period change in parts ber billion
+ *
+ * Description: this function will adjust the frequency of hardware clock.
+ */
+static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+ u32 diff, addend;
+ int neg_adj = 0;
+ u64 adj;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+
+ addend = priv->default_addend;
+ adj = addend;
+ adj *= ppb;
+ diff = div_u64(adj, 1000000000ULL);
+ addend = neg_adj ? (addend - diff) : (addend + diff);
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ priv->hw->ptp->config_addend(priv->ioaddr, addend);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_adjust_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @delta: desired change in nanoseconds
+ *
+ * Description: this function will shift/adjust the hardware clock time.
+ */
+static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+ u32 sec, nsec;
+ u32 quotient, reminder;
+ int neg_adj = 0;
+
+ if (delta < 0) {
+ neg_adj = 1;
+ delta = -delta;
+ }
+
+ quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
+ sec = quotient;
+ nsec = reminder;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_get_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: pointer to hold time/result
+ *
+ * Description: this function will read the current time from the
+ * hardware clock and store it in @ts.
+ */
+static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+ u64 ns;
+ u32 reminder;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ ns = priv->hw->ptp->get_systime(priv->ioaddr);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &reminder);
+ ts->tv_nsec = reminder;
+
+ return 0;
+}
+
+/**
+ * stmmac_set_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: time value to set
+ *
+ * Description: this function will set the current time on the
+ * hardware clock.
+ */
+static int stmmac_set_time(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ return 0;
+}
+
+static int stmmac_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+/* structure describing a PTP hardware clock */
+static struct ptp_clock_info stmmac_ptp_clock_ops = {
+ .owner = THIS_MODULE,
+ .name = "stmmac_ptp_clock",
+ .max_adj = 62500000,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjfreq = stmmac_adjust_freq,
+ .adjtime = stmmac_adjust_time,
+ .gettime = stmmac_get_time,
+ .settime = stmmac_set_time,
+ .enable = stmmac_enable,
+};
+
+/**
+ * stmmac_ptp_register
+ * @priv: driver private structure
+ * Description: this function will register the ptp clock driver
+ * to kernel. It also does some house keeping work.
+ */
+int stmmac_ptp_register(struct stmmac_priv *priv)
+{
+ spin_lock_init(&priv->ptp_lock);
+ priv->ptp_clock_ops = stmmac_ptp_clock_ops;
+
+ priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
+ priv->device);
+ if (IS_ERR(priv->ptp_clock)) {
+ priv->ptp_clock = NULL;
+ pr_err("ptp_clock_register() failed on %s\n", priv->dev->name);
+ } else
+ pr_debug("Added PTP HW clock successfully on %s\n",
+ priv->dev->name);
+
+ return 0;
+}
+
+/**
+ * stmmac_ptp_unregister
+ * @priv: driver private structure
+ * Description: this function will remove/unregister the ptp clock driver
+ * from the kernel.
+ */
+void stmmac_ptp_unregister(struct stmmac_priv *priv)
+{
+ if (priv->ptp_clock) {
+ ptp_clock_unregister(priv->ptp_clock);
+ pr_debug("Removed PTP HW clock successfully on %s\n",
+ priv->dev->name);
+ }
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
new file mode 100644
index 000000000000..3dbc047622fa
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ PTP Header file
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+******************************************************************************/
+
+#ifndef __STMMAC_PTP_H__
+#define __STMMAC_PTP_H__
+
+#define STMMAC_SYSCLOCK 62500000
+
+/* IEEE 1588 PTP register offsets */
+#define PTP_TCR 0x0700 /* Timestamp Control Reg */
+#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
+#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
+#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
+#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
+#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
+#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
+#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
+#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
+#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
+#define PTP_TSR 0x0728 /* Timestamp Status */
+
+#define PTP_STNSUR_ADDSUB_SHIFT 31
+
+/* PTP TCR defines */
+#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
+#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
+#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
+#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
+/* Timestamp Interrupt Trigger Enable */
+#define PTP_TCR_TSTRIG 0x00000010
+#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
+#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
+/* Timestamp Digital or Binary Rollover Control */
+#define PTP_TCR_TSCTRLSSR 0x00000200
+
+/* Enable PTP packet Processing for Version 2 Format */
+#define PTP_TCR_TSVER2ENA 0x00000400
+/* Enable Processing of PTP over Ethernet Frames */
+#define PTP_TCR_TSIPENA 0x00000800
+/* Enable Processing of PTP Frames Sent over IPv6-UDP */
+#define PTP_TCR_TSIPV6ENA 0x00001000
+/* Enable Processing of PTP Frames Sent over IPv4-UDP */
+#define PTP_TCR_TSIPV4ENA 0x00002000
+/* Enable Timestamp Snapshot for Event Messages */
+#define PTP_TCR_TSEVNTENA 0x00004000
+/* Enable Snapshot for Messages Relevant to Master */
+#define PTP_TCR_TSMSTRENA 0x00008000
+/* Select PTP packets for Taking Snapshots */
+#define PTP_TCR_SNAPTYPSEL_1 0x00010000
+/* Enable MAC address for PTP Frame Filtering */
+#define PTP_TCR_TSENMACADDR 0x00040000
+
+#endif /* __STMMAC_PTP_H__ */
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index e4c1c88e4c2a..95cff98d8a34 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -6618,7 +6618,7 @@ static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
(len << TXHDR_LEN_SHIFT) |
((l3off / 2) << TXHDR_L3START_SHIFT) |
(ihl << TXHDR_IHL_SHIFT) |
- ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) |
+ ((eth_proto_inner < ETH_P_802_3_MIN) ? TXHDR_LLC : 0) |
((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) |
(ipv6 ? TXHDR_IP_VER : 0) |
csum_bits);
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index 5fafca065305..054975939a18 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -1169,10 +1169,8 @@ static int bigmac_ether_init(struct platform_device *op,
bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
PAGE_SIZE,
&bp->bblock_dvma, GFP_ATOMIC);
- if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {
- printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");
+ if (bp->bmac_block == NULL || bp->bblock_dvma == 0)
goto fail_and_cleanup;
- }
/* Get the board revision of this BigMAC. */
bp->board_rev = of_getintprop_default(bp->bigmac_op->dev.of_node,
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index a1bff49a8155..436fa9d5a071 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2752,10 +2752,8 @@ static int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe)
&hp->hblock_dvma,
GFP_ATOMIC);
err = -ENOMEM;
- if (!hp->happy_block) {
- printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
+ if (!hp->happy_block)
goto err_out_iounmap;
- }
/* Force check of the link first time we are brought up. */
hp->linkcheck = 0;
@@ -3068,14 +3066,11 @@ static int happy_meal_pci_probe(struct pci_dev *pdev,
hp->happy_bursts = DMA_BURSTBITS;
#endif
- hp->happy_block = (struct hmeal_init_block *)
- dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
-
+ hp->happy_block = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+ &hp->hblock_dvma, GFP_KERNEL);
err = -ENODEV;
- if (!hp->happy_block) {
- printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n");
+ if (!hp->happy_block)
goto err_out_iounmap;
- }
hp->linkcheck = 0;
hp->timer_state = asleep;
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 49bf3e2eb652..8182591bc187 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -414,7 +414,7 @@ static void qe_rx(struct sunqe *qep)
struct qe_rxd *this;
struct sunqe_buffers *qbufs = qep->buffers;
__u32 qbufs_dvma = qep->buffers_dvma;
- int elem = qep->rx_new, drops = 0;
+ int elem = qep->rx_new;
u32 flags;
this = &rxbase[elem];
@@ -436,7 +436,6 @@ static void qe_rx(struct sunqe *qep)
} else {
skb = netdev_alloc_skb(dev, len + 2);
if (skb == NULL) {
- drops++;
dev->stats.rx_dropped++;
} else {
skb_reserve(skb, 2);
@@ -456,8 +455,6 @@ static void qe_rx(struct sunqe *qep)
this = &rxbase[elem];
}
qep->rx_new = elem;
- if (drops)
- printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", qep->dev->name);
}
static void qe_tx_reclaim(struct sunqe *qep);
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index e15cc71b826d..571452e786d5 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -733,7 +733,7 @@ static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
* @ndev: network device
* @vid: VLAN vid to add
*/
-static int bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid)
+static int bdx_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
__bdx_vlan_rx_vid(ndev, vid, 1);
return 0;
@@ -744,7 +744,7 @@ static int bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid)
* @ndev: network device
* @vid: VLAN vid to kill
*/
-static int bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid)
+static int bdx_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
__bdx_vlan_rx_vid(ndev, vid, 0);
return 0;
@@ -1102,10 +1102,9 @@ static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
dno = bdx_rxdb_available(db) - 1;
while (dno > 0) {
skb = netdev_alloc_skb(priv->ndev, f->m.pktsz + NET_IP_ALIGN);
- if (!skb) {
- pr_err("NO MEM: netdev_alloc_skb failed\n");
+ if (!skb)
break;
- }
+
skb_reserve(skb, NET_IP_ALIGN);
idx = bdx_rxdb_alloc_elem(db);
@@ -1149,7 +1148,7 @@ NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan,
priv->ndev->name,
GET_RXD_VLAN_ID(rxd_vlan),
GET_RXD_VTAG(rxd_val1));
- __vlan_hwaccel_put_tag(skb, GET_RXD_VLAN_TCI(rxd_vlan));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), GET_RXD_VLAN_TCI(rxd_vlan));
}
netif_receive_skb(skb);
}
@@ -2018,12 +2017,12 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* so we can have them same for all ports of the board */
ndev->if_port = port;
ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
- | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM
+ | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_RXCSUM
/*| NETIF_F_FRAGLIST */
;
ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
- NETIF_F_TSO | NETIF_F_HW_VLAN_TX;
+ NETIF_F_TSO | NETIF_F_HW_VLAN_CTAG_TX;
if (pci_using_dac)
ndev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index df32a090d08e..59c43918883e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -126,6 +126,13 @@ do { \
#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
+#define CPSW_INTPACEEN (0x3f << 16)
+#define CPSW_INTPRESCALE_MASK (0x7FF << 0)
+#define CPSW_CMINTMAX_CNT 63
+#define CPSW_CMINTMIN_CNT 2
+#define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT)
+#define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1)
+
#define cpsw_enable_irq(priv) \
do { \
u32 i; \
@@ -139,6 +146,10 @@ do { \
disable_irq_nosync(priv->irqs_table[i]); \
} while (0);
+#define cpsw_slave_index(priv) \
+ ((priv->data.dual_emac) ? priv->emac_port : \
+ priv->data.active_slave)
+
static int debug_level;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)");
@@ -160,6 +171,15 @@ struct cpsw_wr_regs {
u32 rx_en;
u32 tx_en;
u32 misc_en;
+ u32 mem_allign1[8];
+ u32 rx_thresh_stat;
+ u32 rx_stat;
+ u32 tx_stat;
+ u32 misc_stat;
+ u32 mem_allign2[8];
+ u32 rx_imax;
+ u32 tx_imax;
+
};
struct cpsw_ss_regs {
@@ -314,6 +334,8 @@ struct cpsw_priv {
struct cpsw_host_regs __iomem *host_port_regs;
u32 msg_enable;
u32 version;
+ u32 coal_intvl;
+ u32 bus_freq_mhz;
struct net_device_stats stats;
int rx_packet_max;
int host_port;
@@ -326,6 +348,7 @@ struct cpsw_priv {
/* snapshot of IRQ numbers */
u32 irqs_table[4];
u32 num_irqs;
+ bool irq_enabled;
struct cpts *cpts;
u32 emac_port;
};
@@ -333,12 +356,15 @@ struct cpsw_priv {
#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
#define for_each_slave(priv, func, arg...) \
do { \
- int idx; \
+ struct cpsw_slave *slave; \
+ int n; \
if (priv->data.dual_emac) \
(func)((priv)->slaves + priv->emac_port, ##arg);\
else \
- for (idx = 0; idx < (priv)->data.slaves; idx++) \
- (func)((priv)->slaves + idx, ##arg); \
+ for (n = (priv)->data.slaves, \
+ slave = (priv)->slaves; \
+ n; n--) \
+ (func)(slave++, ##arg); \
} while (0)
#define cpsw_get_slave_ndev(priv, __slave_no__) \
(priv->slaves[__slave_no__].ndev)
@@ -436,7 +462,7 @@ void cpsw_tx_handler(void *token, int len, int status)
* queue is stopped then start the queue as we have free desc for tx
*/
if (unlikely(netif_queue_stopped(ndev)))
- netif_start_queue(ndev);
+ netif_wake_queue(ndev);
cpts_tx_timestamp(priv->cpts, skb);
priv->stats.tx_packets++;
priv->stats.tx_bytes += len;
@@ -446,62 +472,69 @@ void cpsw_tx_handler(void *token, int len, int status)
void cpsw_rx_handler(void *token, int len, int status)
{
struct sk_buff *skb = token;
+ struct sk_buff *new_skb;
struct net_device *ndev = skb->dev;
struct cpsw_priv *priv = netdev_priv(ndev);
int ret = 0;
cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
- /* free and bail if we are shutting down */
- if (unlikely(!netif_running(ndev)) ||
- unlikely(!netif_carrier_ok(ndev))) {
+ if (unlikely(status < 0)) {
+ /* the interface is going down, skbs are purged */
dev_kfree_skb_any(skb);
return;
}
- if (likely(status >= 0)) {
+
+ new_skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max);
+ if (new_skb) {
skb_put(skb, len);
cpts_rx_timestamp(priv->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
netif_receive_skb(skb);
priv->stats.rx_bytes += len;
priv->stats.rx_packets++;
- skb = NULL;
- }
-
- if (unlikely(!netif_running(ndev))) {
- if (skb)
- dev_kfree_skb_any(skb);
- return;
+ } else {
+ priv->stats.rx_dropped++;
+ new_skb = skb;
}
- if (likely(!skb)) {
- skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max);
- if (WARN_ON(!skb))
- return;
-
- ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
- }
- WARN_ON(ret < 0);
+ ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data,
+ skb_tailroom(new_skb), 0);
+ if (WARN_ON(ret < 0))
+ dev_kfree_skb_any(new_skb);
}
static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
{
struct cpsw_priv *priv = dev_id;
+ u32 rx, tx, rx_thresh;
- if (likely(netif_running(priv->ndev))) {
- cpsw_intr_disable(priv);
+ rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat);
+ rx = __raw_readl(&priv->wr_regs->rx_stat);
+ tx = __raw_readl(&priv->wr_regs->tx_stat);
+ if (!rx_thresh && !rx && !tx)
+ return IRQ_NONE;
+
+ cpsw_intr_disable(priv);
+ if (priv->irq_enabled == true) {
cpsw_disable_irq(priv);
+ priv->irq_enabled = false;
+ }
+
+ if (netif_running(priv->ndev)) {
napi_schedule(&priv->napi);
- } else {
- priv = cpsw_get_slave_priv(priv, 1);
- if (likely(priv) && likely(netif_running(priv->ndev))) {
- cpsw_intr_disable(priv);
- cpsw_disable_irq(priv);
- napi_schedule(&priv->napi);
- }
+ return IRQ_HANDLED;
+ }
+
+ priv = cpsw_get_slave_priv(priv, 1);
+ if (!priv)
+ return IRQ_NONE;
+
+ if (netif_running(priv->ndev)) {
+ napi_schedule(&priv->napi);
+ return IRQ_HANDLED;
}
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
static int cpsw_poll(struct napi_struct *napi, int budget)
@@ -515,10 +548,16 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
num_rx = cpdma_chan_process(priv->rxch, budget);
if (num_rx < budget) {
+ struct cpsw_priv *prim_cpsw;
+
napi_complete(napi);
cpsw_intr_enable(priv);
cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
- cpsw_enable_irq(priv);
+ prim_cpsw = cpsw_get_slave_priv(priv, 0);
+ if (prim_cpsw->irq_enabled == false) {
+ cpsw_enable_irq(priv);
+ prim_cpsw->irq_enabled = true;
+ }
}
if (num_rx || num_tx)
@@ -612,6 +651,77 @@ static void cpsw_adjust_link(struct net_device *ndev)
}
}
+static int cpsw_get_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ coal->rx_coalesce_usecs = priv->coal_intvl;
+ return 0;
+}
+
+static int cpsw_set_coalesce(struct net_device *ndev,
+ struct ethtool_coalesce *coal)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ u32 int_ctrl;
+ u32 num_interrupts = 0;
+ u32 prescale = 0;
+ u32 addnl_dvdr = 1;
+ u32 coal_intvl = 0;
+
+ if (!coal->rx_coalesce_usecs)
+ return -EINVAL;
+
+ coal_intvl = coal->rx_coalesce_usecs;
+
+ int_ctrl = readl(&priv->wr_regs->int_control);
+ prescale = priv->bus_freq_mhz * 4;
+
+ if (coal_intvl < CPSW_CMINTMIN_INTVL)
+ coal_intvl = CPSW_CMINTMIN_INTVL;
+
+ if (coal_intvl > CPSW_CMINTMAX_INTVL) {
+ /* Interrupt pacer works with 4us Pulse, we can
+ * throttle further by dilating the 4us pulse.
+ */
+ addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale;
+
+ if (addnl_dvdr > 1) {
+ prescale *= addnl_dvdr;
+ if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr))
+ coal_intvl = (CPSW_CMINTMAX_INTVL
+ * addnl_dvdr);
+ } else {
+ addnl_dvdr = 1;
+ coal_intvl = CPSW_CMINTMAX_INTVL;
+ }
+ }
+
+ num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
+ writel(num_interrupts, &priv->wr_regs->rx_imax);
+ writel(num_interrupts, &priv->wr_regs->tx_imax);
+
+ int_ctrl |= CPSW_INTPACEEN;
+ int_ctrl &= (~CPSW_INTPRESCALE_MASK);
+ int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK);
+ writel(int_ctrl, &priv->wr_regs->int_control);
+
+ cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl);
+ if (priv->data.dual_emac) {
+ int i;
+
+ for (i = 0; i < priv->data.slaves; i++) {
+ priv = netdev_priv(priv->slaves[i].ndev);
+ priv->coal_intvl = coal_intvl;
+ }
+ } else {
+ priv->coal_intvl = coal_intvl;
+ }
+
+ return 0;
+}
+
static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
{
static char *leader = "........................................";
@@ -643,14 +753,14 @@ static inline int cpsw_tx_packet_submit(struct net_device *ndev,
{
if (!priv->data.dual_emac)
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 0, GFP_KERNEL);
+ skb->len, 0);
if (ndev == cpsw_get_slave_ndev(priv, 0))
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 1, GFP_KERNEL);
+ skb->len, 1);
else
return cpdma_chan_submit(priv->txch, skb, skb->data,
- skb->len, 2, GFP_KERNEL);
+ skb->len, 2);
}
static inline void cpsw_add_dual_emac_def_ale_entries(
@@ -774,9 +884,19 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
}
}
+static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
+{
+ if (!slave->phy)
+ return;
+ phy_stop(slave->phy);
+ phy_disconnect(slave->phy);
+ slave->phy = NULL;
+}
+
static int cpsw_ndo_open(struct net_device *ndev)
{
struct cpsw_priv *priv = netdev_priv(ndev);
+ struct cpsw_priv *prim_cpsw;
int i, ret;
u32 reg;
@@ -819,14 +939,16 @@ static int cpsw_ndo_open(struct net_device *ndev)
struct sk_buff *skb;
ret = -ENOMEM;
- skb = netdev_alloc_skb_ip_align(priv->ndev,
- priv->rx_packet_max);
+ skb = __netdev_alloc_skb_ip_align(priv->ndev,
+ priv->rx_packet_max, GFP_KERNEL);
if (!skb)
- break;
+ goto err_cleanup;
ret = cpdma_chan_submit(priv->rxch, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
- if (WARN_ON(ret < 0))
- break;
+ skb_tailroom(skb), 0);
+ if (ret < 0) {
+ kfree_skb(skb);
+ goto err_cleanup;
+ }
}
/* continue even if we didn't manage to submit all
* receive descs
@@ -834,6 +956,22 @@ static int cpsw_ndo_open(struct net_device *ndev)
cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
}
+ /* Enable Interrupt pacing if configured */
+ if (priv->coal_intvl != 0) {
+ struct ethtool_coalesce coal;
+
+ coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
+ cpsw_set_coalesce(ndev, &coal);
+ }
+
+ prim_cpsw = cpsw_get_slave_priv(priv, 0);
+ if (prim_cpsw->irq_enabled == false) {
+ if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) {
+ prim_cpsw->irq_enabled = true;
+ cpsw_enable_irq(prim_cpsw);
+ }
+ }
+
cpdma_ctlr_start(priv->dma);
cpsw_intr_enable(priv);
napi_enable(&priv->napi);
@@ -843,15 +981,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
if (priv->data.dual_emac)
priv->slaves[priv->emac_port].open_stat = true;
return 0;
-}
-static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
-{
- if (!slave->phy)
- return;
- phy_stop(slave->phy);
- phy_disconnect(slave->phy);
- slave->phy = NULL;
+err_cleanup:
+ cpdma_ctlr_stop(priv->dma);
+ for_each_slave(priv, cpsw_slave_stop, priv);
+ pm_runtime_put_sync(&priv->pdev->dev);
+ netif_carrier_off(priv->ndev);
+ return ret;
}
static int cpsw_ndo_stop(struct net_device *ndev)
@@ -942,7 +1078,7 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)
static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
{
- struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
+ struct cpsw_slave *slave = &priv->slaves[priv->data.active_slave];
u32 ts_en, seq_id;
if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) {
@@ -971,7 +1107,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
if (priv->data.dual_emac)
slave = &priv->slaves[priv->emac_port];
else
- slave = &priv->slaves[priv->data.cpts_active_slave];
+ slave = &priv->slaves[priv->data.active_slave];
ctrl = slave_read(slave, CPSW2_CONTROL);
ctrl &= ~CTRL_ALL_TS_MASK;
@@ -1056,14 +1192,26 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
+ struct cpsw_priv *priv = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(req);
+ int slave_no = cpsw_slave_index(priv);
+
if (!netif_running(dev))
return -EINVAL;
+ switch (cmd) {
#ifdef CONFIG_TI_CPTS
- if (cmd == SIOCSHWTSTAMP)
+ case SIOCSHWTSTAMP:
return cpsw_hwtstamp_ioctl(dev, req);
#endif
- return -ENOTSUPP;
+ case SIOCGMIIPHY:
+ data->phy_id = priv->slaves[slave_no].phy->addr;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
}
static void cpsw_ndo_tx_timeout(struct net_device *ndev)
@@ -1138,7 +1286,7 @@ clean_vid:
}
static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
- unsigned short vid)
+ __be16 proto, u16 vid)
{
struct cpsw_priv *priv = netdev_priv(ndev);
@@ -1150,7 +1298,7 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
}
static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
- unsigned short vid)
+ __be16 proto, u16 vid)
{
struct cpsw_priv *priv = netdev_priv(ndev);
int ret;
@@ -1244,12 +1392,39 @@ static int cpsw_get_ts_info(struct net_device *ndev,
return 0;
}
+static int cpsw_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *ecmd)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int slave_no = cpsw_slave_index(priv);
+
+ if (priv->slaves[slave_no].phy)
+ return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int slave_no = cpsw_slave_index(priv);
+
+ if (priv->slaves[slave_no].phy)
+ return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd);
+ else
+ return -EOPNOTSUPP;
+}
+
static const struct ethtool_ops cpsw_ethtool_ops = {
.get_drvinfo = cpsw_get_drvinfo,
.get_msglevel = cpsw_get_msglevel,
.set_msglevel = cpsw_set_msglevel,
.get_link = ethtool_op_get_link,
.get_ts_info = cpsw_get_ts_info,
+ .get_settings = cpsw_get_settings,
+ .set_settings = cpsw_set_settings,
+ .get_coalesce = cpsw_get_coalesce,
+ .set_coalesce = cpsw_set_coalesce,
};
static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1282,12 +1457,12 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
}
data->slaves = prop;
- if (of_property_read_u32(node, "cpts_active_slave", &prop)) {
- pr_err("Missing cpts_active_slave property in the DT.\n");
+ if (of_property_read_u32(node, "active_slave", &prop)) {
+ pr_err("Missing active_slave property in the DT.\n");
ret = -EINVAL;
goto error_ret;
}
- data->cpts_active_slave = prop;
+ data->active_slave = prop;
if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {
pr_err("Missing cpts_clock_mult property in the DT.\n");
@@ -1380,7 +1555,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
if (data->dual_emac) {
- if (of_property_read_u32(node, "dual_emac_res_vlan",
+ if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
&prop)) {
pr_err("Missing dual_emac_res_vlan in DT.\n");
slave_data->dual_emac_res_vlan = i+1;
@@ -1437,6 +1612,9 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
priv_sl2->slaves = priv->slaves;
priv_sl2->clk = priv->clk;
+ priv_sl2->coal_intvl = 0;
+ priv_sl2->bus_freq_mhz = priv->bus_freq_mhz;
+
priv_sl2->cpsw_res = priv->cpsw_res;
priv_sl2->regs = priv->regs;
priv_sl2->host_port = priv->host_port;
@@ -1455,8 +1633,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
priv_sl2->irqs_table[i] = priv->irqs_table[i];
priv_sl2->num_irqs = priv->num_irqs;
}
-
- ndev->features |= NETIF_F_HW_VLAN_FILTER;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->netdev_ops = &cpsw_netdev_ops;
SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
@@ -1476,7 +1653,7 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
static int cpsw_probe(struct platform_device *pdev)
{
- struct cpsw_platform_data *data = pdev->dev.platform_data;
+ struct cpsw_platform_data *data;
struct net_device *ndev;
struct cpsw_priv *priv;
struct cpdma_params dma_params;
@@ -1501,6 +1678,7 @@ static int cpsw_probe(struct platform_device *pdev)
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
priv->rx_packet_max = max(rx_packet_max, 128);
priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
+ priv->irq_enabled = true;
if (!ndev) {
pr_err("error allocating cpts\n");
goto clean_ndev_ret;
@@ -1546,6 +1724,8 @@ static int cpsw_probe(struct platform_device *pdev)
ret = -ENODEV;
goto clean_slave_ret;
}
+ priv->coal_intvl = 0;
+ priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000;
priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!priv->cpsw_res) {
@@ -1687,12 +1867,12 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_ale_ret;
}
priv->irqs_table[k] = i;
- priv->num_irqs = k;
+ priv->num_irqs = k + 1;
}
k++;
}
- ndev->features |= NETIF_F_HW_VLAN_FILTER;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->netdev_ops = &cpsw_netdev_ops;
SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops);
@@ -1725,7 +1905,8 @@ static int cpsw_probe(struct platform_device *pdev)
return 0;
clean_irq_ret:
- free_irq(ndev->irq, priv);
+ for (i = 0; i < priv->num_irqs; i++)
+ free_irq(priv->irqs_table[i], priv);
clean_ale_ret:
cpsw_ale_destroy(priv->ale);
clean_dma_ret:
@@ -1748,7 +1929,8 @@ clean_slave_ret:
pm_runtime_disable(&pdev->dev);
kfree(priv->slaves);
clean_ndev_ret:
- free_netdev(ndev);
+ kfree(priv->data.slave_data);
+ free_netdev(priv->ndev);
return ret;
}
@@ -1756,12 +1938,17 @@ static int cpsw_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct cpsw_priv *priv = netdev_priv(ndev);
+ int i;
- pr_info("removing device");
platform_set_drvdata(pdev, NULL);
+ if (priv->data.dual_emac)
+ unregister_netdev(cpsw_get_slave_ndev(priv, 1));
+ unregister_netdev(ndev);
cpts_unregister(priv->cpts);
- free_irq(ndev->irq, priv);
+ for (i = 0; i < priv->num_irqs; i++)
+ free_irq(priv->irqs_table[i], priv);
+
cpsw_ale_destroy(priv->ale);
cpdma_chan_destroy(priv->txch);
cpdma_chan_destroy(priv->rxch);
@@ -1775,8 +1962,10 @@ static int cpsw_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
clk_put(priv->clk);
kfree(priv->slaves);
+ kfree(priv->data.slave_data);
+ if (priv->data.dual_emac)
+ free_netdev(cpsw_get_slave_ndev(priv, 1));
free_netdev(ndev);
-
return 0;
}
@@ -1812,6 +2001,7 @@ static const struct of_device_id cpsw_of_mtable[] = {
{ .compatible = "ti,cpsw", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static struct platform_driver cpsw_driver = {
.driver = {
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 463597f919f1..8c351f100aca 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -94,7 +94,7 @@ static int cpts_fifo_read(struct cpts *cpts, int match)
case CPTS_EV_HW:
break;
default:
- pr_err("cpts: unkown event type\n");
+ pr_err("cpts: unknown event type\n");
break;
}
if (type == match)
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index ee13dc78430c..49dfd592ac1e 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/delay.h>
#include "davinci_cpdma.h"
@@ -312,14 +313,16 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr)
}
if (ctlr->params.has_soft_reset) {
- unsigned long timeout = jiffies + HZ/10;
+ unsigned timeout = 10 * 100;
dma_reg_write(ctlr, CPDMA_SOFTRESET, 1);
- while (time_before(jiffies, timeout)) {
+ while (timeout) {
if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0)
break;
+ udelay(10);
+ timeout--;
}
- WARN_ON(!time_before(jiffies, timeout));
+ WARN_ON(!timeout);
}
for (i = 0; i < ctlr->num_chan; i++) {
@@ -673,7 +676,7 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan,
}
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, int directed, gfp_t gfp_mask)
+ int len, int directed)
{
struct cpdma_ctlr *ctlr = chan->ctlr;
struct cpdma_desc __iomem *desc;
@@ -773,6 +776,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
struct cpdma_ctlr *ctlr = chan->ctlr;
struct cpdma_desc __iomem *desc;
int status, outlen;
+ int cb_status = 0;
struct cpdma_desc_pool *pool = ctlr->pool;
dma_addr_t desc_dma;
unsigned long flags;
@@ -808,8 +812,12 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
}
spin_unlock_irqrestore(&chan->lock, flags);
+ if (unlikely(status & CPDMA_DESC_TD_COMPLETE))
+ cb_status = -ENOSYS;
+ else
+ cb_status = status;
- __cpdma_chan_free(chan, desc, outlen, status);
+ __cpdma_chan_free(chan, desc, outlen, cb_status);
return status;
unlock_ret:
@@ -868,7 +876,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
struct cpdma_desc_pool *pool = ctlr->pool;
unsigned long flags;
int ret;
- unsigned long timeout;
+ unsigned timeout;
spin_lock_irqsave(&chan->lock, flags);
if (chan->state != CPDMA_STATE_ACTIVE) {
@@ -883,14 +891,15 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
dma_reg_write(ctlr, chan->td, chan_linear(chan));
/* wait for teardown complete */
- timeout = jiffies + HZ/10; /* 100 msec */
- while (time_before(jiffies, timeout)) {
+ timeout = 100 * 100; /* 100 ms */
+ while (timeout) {
u32 cp = chan_read(chan, cp);
if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE)
break;
- cpu_relax();
+ udelay(10);
+ timeout--;
}
- WARN_ON(!time_before(jiffies, timeout));
+ WARN_ON(!timeout);
chan_write(chan, cp, CPDMA_TEARDOWN_VALUE);
/* handle completed packets */
@@ -1031,3 +1040,5 @@ unlock_ret:
return ret;
}
EXPORT_SYMBOL_GPL(cpdma_control_set);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index d9bcc6032fdc..86dee487f2f0 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -89,7 +89,7 @@ int cpdma_chan_dump(struct cpdma_chan *chan);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
- int len, int directed, gfp_t gfp_mask);
+ int len, int directed);
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index ae1b77aa199f..860e15ddfbcb 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -1037,7 +1037,7 @@ static void emac_rx_handler(void *token, int len, int status)
recycle:
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
+ skb_tailroom(skb), 0);
WARN_ON(ret == -ENOMEM);
if (unlikely(ret < 0))
@@ -1053,7 +1053,7 @@ static void emac_tx_handler(void *token, int len, int status)
* queue is stopped then start the queue as we have free desc for tx
*/
if (unlikely(netif_queue_stopped(ndev)))
- netif_start_queue(ndev);
+ netif_wake_queue(ndev);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
dev_kfree_skb_any(skb);
@@ -1092,7 +1092,7 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
skb_tx_timestamp(skb);
ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len,
- 0, GFP_KERNEL);
+ 0);
if (unlikely(ret_code != 0)) {
if (netif_msg_tx_err(priv) && net_ratelimit())
dev_err(emac_dev, "DaVinci EMAC: desc submit failed");
@@ -1438,7 +1438,7 @@ static int emac_poll(struct napi_struct *napi, int budget)
* Polled functionality used by netconsole and others in non interrupt mode
*
*/
-void emac_poll_controller(struct net_device *ndev)
+static void emac_poll_controller(struct net_device *ndev)
{
struct emac_priv *priv = netdev_priv(ndev);
@@ -1558,7 +1558,7 @@ static int emac_dev_open(struct net_device *ndev)
break;
ret = cpdma_chan_submit(priv->rxchan, skb, skb->data,
- skb_tailroom(skb), 0, GFP_KERNEL);
+ skb_tailroom(skb), 0);
if (WARN_ON(ret < 0))
break;
}
@@ -1865,21 +1865,18 @@ static int davinci_emac_probe(struct platform_device *pdev)
/* obtain emac clock from kernel */
- emac_clk = clk_get(&pdev->dev, NULL);
+ emac_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(emac_clk)) {
dev_err(&pdev->dev, "failed to get EMAC clock\n");
return -EBUSY;
}
emac_bus_frequency = clk_get_rate(emac_clk);
- clk_put(emac_clk);
/* TODO: Probe PHY here if possible */
ndev = alloc_etherdev(sizeof(struct emac_priv));
- if (!ndev) {
- rc = -ENOMEM;
- goto no_ndev;
- }
+ if (!ndev)
+ return -ENOMEM;
platform_set_drvdata(pdev, ndev);
priv = netdev_priv(ndev);
@@ -1893,7 +1890,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
rc = -ENODEV;
- goto probe_quit;
+ goto no_pdata;
}
/* MAC addr and PHY mask , RMII enable info from platform_data */
@@ -1913,23 +1910,23 @@ static int davinci_emac_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev,"error getting res\n");
rc = -ENOENT;
- goto probe_quit;
+ goto no_pdata;
}
priv->emac_base_phys = res->start + pdata->ctrl_reg_offset;
size = resource_size(res);
- if (!request_mem_region(res->start, size, ndev->name)) {
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ size, ndev->name)) {
dev_err(&pdev->dev, "failed request_mem_region() for regs\n");
rc = -ENXIO;
- goto probe_quit;
+ goto no_pdata;
}
- priv->remap_addr = ioremap(res->start, size);
+ priv->remap_addr = devm_ioremap(&pdev->dev, res->start, size);
if (!priv->remap_addr) {
dev_err(&pdev->dev, "unable to map IO\n");
rc = -ENOMEM;
- release_mem_region(res->start, size);
- goto probe_quit;
+ goto no_pdata;
}
priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset;
ndev->base_addr = (unsigned long)priv->remap_addr;
@@ -1962,7 +1959,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
if (!priv->dma) {
dev_err(&pdev->dev, "error initializing DMA\n");
rc = -ENOMEM;
- goto no_dma;
+ goto no_pdata;
}
priv->txchan = cpdma_chan_create(priv->dma, tx_chan_num(EMAC_DEF_TX_CH),
@@ -1971,14 +1968,14 @@ static int davinci_emac_probe(struct platform_device *pdev)
emac_rx_handler);
if (WARN_ON(!priv->txchan || !priv->rxchan)) {
rc = -ENOMEM;
- goto no_irq_res;
+ goto no_cpdma_chan;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "error getting irq res\n");
rc = -ENOENT;
- goto no_irq_res;
+ goto no_cpdma_chan;
}
ndev->irq = res->start;
@@ -2000,7 +1997,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
if (rc) {
dev_err(&pdev->dev, "error in register_netdev\n");
rc = -ENODEV;
- goto no_irq_res;
+ goto no_cpdma_chan;
}
@@ -2015,20 +2012,14 @@ static int davinci_emac_probe(struct platform_device *pdev)
return 0;
-no_irq_res:
+no_cpdma_chan:
if (priv->txchan)
cpdma_chan_destroy(priv->txchan);
if (priv->rxchan)
cpdma_chan_destroy(priv->rxchan);
cpdma_ctlr_destroy(priv->dma);
-no_dma:
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
- iounmap(priv->remap_addr);
-
-probe_quit:
+no_pdata:
free_netdev(ndev);
-no_ndev:
return rc;
}
@@ -2041,14 +2032,12 @@ no_ndev:
*/
static int davinci_emac_remove(struct platform_device *pdev)
{
- struct resource *res;
struct net_device *ndev = platform_get_drvdata(pdev);
struct emac_priv *priv = netdev_priv(ndev);
dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n");
platform_set_drvdata(pdev, NULL);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (priv->txchan)
cpdma_chan_destroy(priv->txchan);
@@ -2056,10 +2045,7 @@ static int davinci_emac_remove(struct platform_device *pdev)
cpdma_chan_destroy(priv->rxchan);
cpdma_ctlr_destroy(priv->dma);
- release_mem_region(res->start, resource_size(res));
-
unregister_netdev(ndev);
- iounmap(priv->remap_addr);
free_netdev(ndev);
return 0;
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index d04a622b08d4..12aec173564c 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -485,6 +485,7 @@ static const struct of_device_id davinci_mdio_of_mtable[] = {
{ .compatible = "ti,davinci_mdio", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable);
static struct platform_driver davinci_mdio_driver = {
.driver = {
diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c
index 22725386c5de..60c400f6d01f 100644
--- a/drivers/net/ethernet/ti/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -320,6 +320,7 @@ static void tlan_remove_one(struct pci_dev *pdev)
free_netdev(dev);
pci_set_drvdata(pdev, NULL);
+ cancel_work_sync(&priv->tlan_tqueue);
}
static void tlan_start(struct net_device *dev)
@@ -1911,10 +1912,8 @@ static void tlan_reset_lists(struct net_device *dev)
list->frame_size = TLAN_MAX_FRAME_SIZE;
list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER;
skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5);
- if (!skb) {
- netdev_err(dev, "Out of memory for received data\n");
+ if (!skb)
break;
- }
list->buffer[0].address = pci_map_single(priv->pci_dev,
skb->data,
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index 445c0595c997..ad32af67e618 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -58,13 +58,6 @@ MODULE_DESCRIPTION("Gelic Network driver");
MODULE_LICENSE("GPL");
-static inline void gelic_card_enable_rxdmac(struct gelic_card *card);
-static inline void gelic_card_disable_rxdmac(struct gelic_card *card);
-static inline void gelic_card_disable_txdmac(struct gelic_card *card);
-static inline void gelic_card_reset_chain(struct gelic_card *card,
- struct gelic_descr_chain *chain,
- struct gelic_descr *start_descr);
-
/* set irq_mask */
int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask)
{
@@ -78,12 +71,12 @@ int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask)
return status;
}
-static inline void gelic_card_rx_irq_on(struct gelic_card *card)
+static void gelic_card_rx_irq_on(struct gelic_card *card)
{
card->irq_mask |= GELIC_CARD_RXINT;
gelic_card_set_irq_mask(card, card->irq_mask);
}
-static inline void gelic_card_rx_irq_off(struct gelic_card *card)
+static void gelic_card_rx_irq_off(struct gelic_card *card)
{
card->irq_mask &= ~GELIC_CARD_RXINT;
gelic_card_set_irq_mask(card, card->irq_mask);
@@ -127,6 +120,120 @@ static int gelic_card_set_link_mode(struct gelic_card *card, int mode)
return 0;
}
+/**
+ * gelic_card_disable_txdmac - disables the transmit DMA controller
+ * @card: card structure
+ *
+ * gelic_card_disable_txdmac terminates processing on the DMA controller by
+ * turing off DMA and issuing a force end
+ */
+static void gelic_card_disable_txdmac(struct gelic_card *card)
+{
+ int status;
+
+ /* this hvc blocks until the DMA in progress really stopped */
+ status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card));
+ if (status)
+ dev_err(ctodev(card),
+ "lv1_net_stop_tx_dma failed, status=%d\n", status);
+}
+
+/**
+ * gelic_card_enable_rxdmac - enables the receive DMA controller
+ * @card: card structure
+ *
+ * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
+ * in the GDADMACCNTR register
+ */
+static void gelic_card_enable_rxdmac(struct gelic_card *card)
+{
+ int status;
+
+#ifdef DEBUG
+ if (gelic_descr_get_status(card->rx_chain.head) !=
+ GELIC_DESCR_DMA_CARDOWNED) {
+ printk(KERN_ERR "%s: status=%x\n", __func__,
+ be32_to_cpu(card->rx_chain.head->dmac_cmd_status));
+ printk(KERN_ERR "%s: nextphy=%x\n", __func__,
+ be32_to_cpu(card->rx_chain.head->next_descr_addr));
+ printk(KERN_ERR "%s: head=%p\n", __func__,
+ card->rx_chain.head);
+ }
+#endif
+ status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
+ card->rx_chain.head->bus_addr, 0);
+ if (status)
+ dev_info(ctodev(card),
+ "lv1_net_start_rx_dma failed, status=%d\n", status);
+}
+
+/**
+ * gelic_card_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * gelic_card_disable_rxdmac terminates processing on the DMA controller by
+ * turing off DMA and issuing a force end
+ */
+static void gelic_card_disable_rxdmac(struct gelic_card *card)
+{
+ int status;
+
+ /* this hvc blocks until the DMA in progress really stopped */
+ status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card));
+ if (status)
+ dev_err(ctodev(card),
+ "lv1_net_stop_rx_dma failed, %d\n", status);
+}
+
+/**
+ * gelic_descr_set_status -- sets the status of a descriptor
+ * @descr: descriptor to change
+ * @status: status to set in the descriptor
+ *
+ * changes the status to the specified value. Doesn't change other bits
+ * in the status
+ */
+static void gelic_descr_set_status(struct gelic_descr *descr,
+ enum gelic_descr_dma_status status)
+{
+ descr->dmac_cmd_status = cpu_to_be32(status |
+ (be32_to_cpu(descr->dmac_cmd_status) &
+ ~GELIC_DESCR_DMA_STAT_MASK));
+ /*
+ * dma_cmd_status field is used to indicate whether the descriptor
+ * is valid or not.
+ * Usually caller of this function wants to inform that to the
+ * hardware, so we assure here the hardware sees the change.
+ */
+ wmb();
+}
+
+/**
+ * gelic_card_reset_chain - reset status of a descriptor chain
+ * @card: card structure
+ * @chain: address of chain
+ * @start_descr: address of descriptor array
+ *
+ * Reset the status of dma descriptors to ready state
+ * and re-initialize the hardware chain for later use
+ */
+static void gelic_card_reset_chain(struct gelic_card *card,
+ struct gelic_descr_chain *chain,
+ struct gelic_descr *start_descr)
+{
+ struct gelic_descr *descr;
+
+ for (descr = start_descr; start_descr != descr->next; descr++) {
+ gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
+ descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
+ }
+
+ chain->head = start_descr;
+ chain->tail = (descr - 1);
+
+ (descr - 1)->next_descr_addr = 0;
+}
+
void gelic_card_up(struct gelic_card *card)
{
pr_debug("%s: called\n", __func__);
@@ -183,29 +290,6 @@ gelic_descr_get_status(struct gelic_descr *descr)
}
/**
- * gelic_descr_set_status -- sets the status of a descriptor
- * @descr: descriptor to change
- * @status: status to set in the descriptor
- *
- * changes the status to the specified value. Doesn't change other bits
- * in the status
- */
-static void gelic_descr_set_status(struct gelic_descr *descr,
- enum gelic_descr_dma_status status)
-{
- descr->dmac_cmd_status = cpu_to_be32(status |
- (be32_to_cpu(descr->dmac_cmd_status) &
- ~GELIC_DESCR_DMA_STAT_MASK));
- /*
- * dma_cmd_status field is used to indicate whether the descriptor
- * is valid or not.
- * Usually caller of this function wants to inform that to the
- * hardware, so we assure here the hardware sees the change.
- */
- wmb();
-}
-
-/**
* gelic_card_free_chain - free descriptor chain
* @card: card structure
* @descr_in: address of desc
@@ -286,31 +370,6 @@ iommu_error:
}
/**
- * gelic_card_reset_chain - reset status of a descriptor chain
- * @card: card structure
- * @chain: address of chain
- * @start_descr: address of descriptor array
- *
- * Reset the status of dma descriptors to ready state
- * and re-initialize the hardware chain for later use
- */
-static void gelic_card_reset_chain(struct gelic_card *card,
- struct gelic_descr_chain *chain,
- struct gelic_descr *start_descr)
-{
- struct gelic_descr *descr;
-
- for (descr = start_descr; start_descr != descr->next; descr++) {
- gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
- descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
- }
-
- chain->head = start_descr;
- chain->tail = (descr - 1);
-
- (descr - 1)->next_descr_addr = 0;
-}
-/**
* gelic_descr_prepare_rx - reinitializes a rx descriptor
* @card: card structure
* @descr: descriptor to re-init
@@ -599,71 +658,6 @@ void gelic_net_set_multi(struct net_device *netdev)
}
/**
- * gelic_card_enable_rxdmac - enables the receive DMA controller
- * @card: card structure
- *
- * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
- * in the GDADMACCNTR register
- */
-static inline void gelic_card_enable_rxdmac(struct gelic_card *card)
-{
- int status;
-
-#ifdef DEBUG
- if (gelic_descr_get_status(card->rx_chain.head) !=
- GELIC_DESCR_DMA_CARDOWNED) {
- printk(KERN_ERR "%s: status=%x\n", __func__,
- be32_to_cpu(card->rx_chain.head->dmac_cmd_status));
- printk(KERN_ERR "%s: nextphy=%x\n", __func__,
- be32_to_cpu(card->rx_chain.head->next_descr_addr));
- printk(KERN_ERR "%s: head=%p\n", __func__,
- card->rx_chain.head);
- }
-#endif
- status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
- card->rx_chain.head->bus_addr, 0);
- if (status)
- dev_info(ctodev(card),
- "lv1_net_start_rx_dma failed, status=%d\n", status);
-}
-
-/**
- * gelic_card_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * gelic_card_disable_rxdmac terminates processing on the DMA controller by
- * turing off DMA and issuing a force end
- */
-static inline void gelic_card_disable_rxdmac(struct gelic_card *card)
-{
- int status;
-
- /* this hvc blocks until the DMA in progress really stopped */
- status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card));
- if (status)
- dev_err(ctodev(card),
- "lv1_net_stop_rx_dma failed, %d\n", status);
-}
-
-/**
- * gelic_card_disable_txdmac - disables the transmit DMA controller
- * @card: card structure
- *
- * gelic_card_disable_txdmac terminates processing on the DMA controller by
- * turing off DMA and issuing a force end
- */
-static inline void gelic_card_disable_txdmac(struct gelic_card *card)
-{
- int status;
-
- /* this hvc blocks until the DMA in progress really stopped */
- status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card));
- if (status)
- dev_err(ctodev(card),
- "lv1_net_stop_tx_dma failed, status=%d\n", status);
-}
-
-/**
* gelic_net_stop - called upon ifconfig down
* @netdev: interface device structure
*
@@ -746,7 +740,7 @@ static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr,
}
}
-static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+static struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
unsigned short tag)
{
struct vlan_ethhdr *veth;
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index f1b91fd7e41c..c655fe60121e 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -352,8 +352,7 @@ spider_net_init_chain(struct spider_net_card *card,
alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);
chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
- &chain->dma_addr, GFP_KERNEL);
-
+ &chain->dma_addr, GFP_KERNEL);
if (!chain->hwring)
return -ENOMEM;
@@ -2330,8 +2329,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
if (SPIDER_NET_RX_CSUM_DEFAULT)
netdev->features |= NETIF_F_RXCSUM;
netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX;
- /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- * NETIF_F_HW_VLAN_FILTER */
+ /* some time: NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+ * NETIF_F_HW_VLAN_CTAG_FILTER */
netdev->irq = card->pdev->irq;
card->num_rx_ints = 0;
diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 8fa947a2d929..3c69a0460832 100644
--- a/drivers/net/ethernet/tundra/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -1308,27 +1308,16 @@ static int tsi108_open(struct net_device *dev)
data->id, dev->irq, dev->name);
}
- data->rxring = dma_alloc_coherent(NULL, rxring_size,
- &data->rxdma, GFP_KERNEL);
-
- if (!data->rxring) {
- printk(KERN_DEBUG
- "TSI108_ETH: failed to allocate memory for rxring!\n");
+ data->rxring = dma_alloc_coherent(NULL, rxring_size, &data->rxdma,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!data->rxring)
return -ENOMEM;
- } else {
- memset(data->rxring, 0, rxring_size);
- }
-
- data->txring = dma_alloc_coherent(NULL, txring_size,
- &data->txdma, GFP_KERNEL);
+ data->txring = dma_alloc_coherent(NULL, txring_size, &data->txdma,
+ GFP_KERNEL | __GFP_ZERO);
if (!data->txring) {
- printk(KERN_DEBUG
- "TSI108_ETH: failed to allocate memory for txring!\n");
pci_free_consistent(0, rxring_size, data->rxring, data->rxdma);
return -ENOMEM;
- } else {
- memset(data->txring, 0, txring_size);
}
for (i = 0; i < TSI108_RXRING_LEN; i++) {
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index 185c721c52d7..ca98acabf1b4 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -508,8 +508,10 @@ static struct rtnl_link_stats64 *rhine_get_stats64(struct net_device *dev,
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static int rhine_close(struct net_device *dev);
-static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
-static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
+static int rhine_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid);
+static int rhine_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid);
static void rhine_restart_tx(struct net_device *dev);
static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool low)
@@ -1026,8 +1028,9 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
if (pdev->revision >= VT6105M)
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
/* dev->name not defined before register_netdev()! */
rc = register_netdev(dev);
@@ -1414,7 +1417,7 @@ static void rhine_update_vcam(struct net_device *dev)
rhine_set_vlan_cam_mask(ioaddr, vCAMmask);
}
-static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int rhine_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -1425,7 +1428,7 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int rhine_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -1933,7 +1936,7 @@ static int rhine_rx(struct net_device *dev, int limit)
skb->protocol = eth_type_trans(skb, dev);
if (unlikely(desc_length & DescTag))
- __vlan_hwaccel_put_tag(skb, vlan_tci);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
netif_receive_skb(skb);
u64_stats_update_begin(&rp->rx_stats.syncp);
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index 1bc7f9fd2583..fb6248956ee2 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -525,7 +525,8 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
}
-static int velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int velocity_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -536,7 +537,8 @@ static int velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int velocity_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2078,7 +2080,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
if (rd->rdesc0.RSR & RSR_DETAG) {
u16 vid = swab16(le16_to_cpu(rd->rdesc1.PQTAG));
- __vlan_hwaccel_put_tag(skb, vid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
}
netif_rx(skb);
@@ -2810,9 +2812,10 @@ static int velocity_found1(struct pci_dev *pdev,
dev->ethtool_ops = &velocity_ethtool_ops;
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HW_VLAN_TX;
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM;
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_HW_VLAN_CTAG_TX;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_IP_CSUM;
ret = register_netdev(dev);
if (ret < 0)
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index 545043cc4c0b..a518dcab396e 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -754,7 +754,7 @@ static int w5100_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int w5100_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -787,7 +787,7 @@ static int w5100_resume(struct device *dev)
}
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(w5100_pm_ops, w5100_suspend, w5100_resume);
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 7cbd0e6fc6f3..6e00e3f94ce4 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -666,7 +666,7 @@ static int w5300_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int w5300_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -699,7 +699,7 @@ static int w5300_resume(struct device *dev)
}
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(w5300_pm_ops, w5300_suspend, w5300_resume);
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 9fc2ada4c3c2..57c2e5ef2804 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -245,39 +245,30 @@ static int temac_dma_bd_init(struct net_device *ndev)
/* returns a virtual address and a physical address. */
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->tx_bd_v) * TX_BD_NUM,
- &lp->tx_bd_p, GFP_KERNEL);
- if (!lp->tx_bd_v) {
- dev_err(&ndev->dev,
- "unable to allocate DMA TX buffer descriptors");
+ &lp->tx_bd_p, GFP_KERNEL | __GFP_ZERO);
+ if (!lp->tx_bd_v)
goto out;
- }
+
lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->rx_bd_v) * RX_BD_NUM,
- &lp->rx_bd_p, GFP_KERNEL);
- if (!lp->rx_bd_v) {
- dev_err(&ndev->dev,
- "unable to allocate DMA RX buffer descriptors");
+ &lp->rx_bd_p, GFP_KERNEL | __GFP_ZERO);
+ if (!lp->rx_bd_v)
goto out;
- }
- memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM);
for (i = 0; i < TX_BD_NUM; i++) {
lp->tx_bd_v[i].next = lp->tx_bd_p +
sizeof(*lp->tx_bd_v) * ((i + 1) % TX_BD_NUM);
}
- memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM);
for (i = 0; i < RX_BD_NUM; i++) {
lp->rx_bd_v[i].next = lp->rx_bd_p +
sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
skb = netdev_alloc_skb_ip_align(ndev,
XTE_MAX_JUMBO_FRAME_SIZE);
-
- if (skb == 0) {
- dev_err(&ndev->dev, "alloc_skb error %d\n", i);
+ if (!skb)
goto out;
- }
+
lp->rx_skb[i] = skb;
/* returns physical address of skb->data */
lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
@@ -789,9 +780,7 @@ static void ll_temac_recv(struct net_device *ndev)
new_skb = netdev_alloc_skb_ip_align(ndev,
XTE_MAX_JUMBO_FRAME_SIZE);
-
- if (new_skb == 0) {
- dev_err(&ndev->dev, "no memory for new sk_buff\n");
+ if (!new_skb) {
spin_unlock_irqrestore(&lp->rx_lock, flags);
return;
}
@@ -1029,9 +1018,9 @@ static int temac_of_probe(struct platform_device *op)
ndev->features |= NETIF_F_HW_CSUM; /* Can checksum all the packets. */
ndev->features |= NETIF_F_IPV6_CSUM; /* Can checksum IPV6 TCP/UDP */
ndev->features |= NETIF_F_HIGHDMA; /* Can DMA to high memory. */
- ndev->features |= NETIF_F_HW_VLAN_TX; /* Transmit VLAN hw accel */
- ndev->features |= NETIF_F_HW_VLAN_RX; /* Receive VLAN hw acceleration */
- ndev->features |= NETIF_F_HW_VLAN_FILTER; /* Receive VLAN filtering */
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_TX; /* Transmit VLAN hw accel */
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX; /* Receive VLAN hw acceleration */
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; /* Receive VLAN filtering */
ndev->features |= NETIF_F_VLAN_CHALLENGED; /* cannot handle VLAN pkts */
ndev->features |= NETIF_F_GSO; /* Enable software GSO. */
ndev->features |= NETIF_F_MULTI_QUEUE; /* Has multiple TX/RX queues */
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 278c9db3b5b8..24748e8367a1 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -204,41 +204,31 @@ static int axienet_dma_bd_init(struct net_device *ndev)
lp->tx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->tx_bd_v) * TX_BD_NUM,
&lp->tx_bd_p,
- GFP_KERNEL);
- if (!lp->tx_bd_v) {
- dev_err(&ndev->dev, "unable to allocate DMA Tx buffer "
- "descriptors");
+ GFP_KERNEL | __GFP_ZERO);
+ if (!lp->tx_bd_v)
goto out;
- }
lp->rx_bd_v = dma_alloc_coherent(ndev->dev.parent,
sizeof(*lp->rx_bd_v) * RX_BD_NUM,
&lp->rx_bd_p,
- GFP_KERNEL);
- if (!lp->rx_bd_v) {
- dev_err(&ndev->dev, "unable to allocate DMA Rx buffer "
- "descriptors");
+ GFP_KERNEL | __GFP_ZERO);
+ if (!lp->rx_bd_v)
goto out;
- }
- memset(lp->tx_bd_v, 0, sizeof(*lp->tx_bd_v) * TX_BD_NUM);
for (i = 0; i < TX_BD_NUM; i++) {
lp->tx_bd_v[i].next = lp->tx_bd_p +
sizeof(*lp->tx_bd_v) *
((i + 1) % TX_BD_NUM);
}
- memset(lp->rx_bd_v, 0, sizeof(*lp->rx_bd_v) * RX_BD_NUM);
for (i = 0; i < RX_BD_NUM; i++) {
lp->rx_bd_v[i].next = lp->rx_bd_p +
sizeof(*lp->rx_bd_v) *
((i + 1) % RX_BD_NUM);
skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size);
- if (!skb) {
- dev_err(&ndev->dev, "alloc_skb error %d\n", i);
+ if (!skb)
goto out;
- }
lp->rx_bd_v[i].sw_id_offset = (u32) skb;
lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
@@ -777,10 +767,9 @@ static void axienet_recv(struct net_device *ndev)
packets++;
new_skb = netdev_alloc_skb_ip_align(ndev, lp->max_frm_size);
- if (!new_skb) {
- dev_err(&ndev->dev, "no memory for new sk_buff\n");
+ if (!new_skb)
return;
- }
+
cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
lp->max_frm_size,
DMA_FROM_DEVICE);
diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c
index 98e09d0d3ce2..bdd20b888cf6 100644
--- a/drivers/net/ethernet/xircom/xirc2ps_cs.c
+++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c
@@ -1041,7 +1041,6 @@ xirc2ps_interrupt(int irq, void *dev_id)
/* 1 extra so we can use insw */
skb = netdev_alloc_skb(dev, pktlen + 3);
if (!skb) {
- pr_notice("low memory, packet dropped (size=%u)\n", pktlen);
dev->stats.rx_dropped++;
} else { /* okay get the packet */
skb_reserve(skb, 2);
@@ -1775,21 +1774,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = {
.suspend = xirc2ps_suspend,
.resume = xirc2ps_resume,
};
-
-static int __init
-init_xirc2ps_cs(void)
-{
- return pcmcia_register_driver(&xirc2ps_cs_driver);
-}
-
-static void __exit
-exit_xirc2ps_cs(void)
-{
- pcmcia_unregister_driver(&xirc2ps_cs_driver);
-}
-
-module_init(init_xirc2ps_cs);
-module_exit(exit_xirc2ps_cs);
+module_pcmcia_driver(xirc2ps_cs_driver);
#ifndef MODULE
static int __init setup_xirc2ps_cs(char *str)
diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c
index 502c8ff1d985..4c8ddc944d51 100644
--- a/drivers/net/fddi/defxx.c
+++ b/drivers/net/fddi/defxx.c
@@ -1070,13 +1070,10 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name,
(PI_ALIGN_K_DESC_BLK - 1);
bp->kmalloced = top_v = dma_alloc_coherent(bp->bus_dev, alloc_size,
&bp->kmalloced_dma,
- GFP_ATOMIC);
- if (top_v == NULL) {
- printk("%s: Could not allocate memory for host buffers "
- "and structures!\n", print_name);
+ GFP_ATOMIC | __GFP_ZERO);
+ if (top_v == NULL)
return DFX_K_FAILURE;
- }
- memset(top_v, 0, alloc_size); /* zero out memory before continuing */
+
top_p = bp->kmalloced_dma; /* get physical address of buffer */
/*
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 4cf8f1017aad..b2d863f2ea42 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -866,7 +866,7 @@ static int yam_open(struct net_device *dev)
printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq);
- if (!dev || !yp->bitrate)
+ if (!yp->bitrate)
return -ENXIO;
if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT ||
dev->irq < 2 || dev->irq > 15) {
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 1cd77483da50..2b0480416b31 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -470,8 +470,10 @@ static void netvsc_send_completion(struct hv_device *device,
packet->trans_id;
/* Notify the layer above us */
- nvsc_packet->completion.send.send_completion(
- nvsc_packet->completion.send.send_completion_ctx);
+ if (nvsc_packet)
+ nvsc_packet->completion.send.send_completion(
+ nvsc_packet->completion.send.
+ send_completion_ctx);
num_outstanding_sends =
atomic_dec_return(&net_device->num_outstanding_sends);
@@ -498,6 +500,7 @@ int netvsc_send(struct hv_device *device,
int ret = 0;
struct nvsp_message sendMessage;
struct net_device *ndev;
+ u64 req_id;
net_device = get_outbound_net_device(device);
if (!net_device)
@@ -518,20 +521,24 @@ int netvsc_send(struct hv_device *device,
0xFFFFFFFF;
sendMessage.msg.v1_msg.send_rndis_pkt.send_buf_section_size = 0;
+ if (packet->completion.send.send_completion)
+ req_id = (ulong)packet;
+ else
+ req_id = 0;
+
if (packet->page_buf_cnt) {
ret = vmbus_sendpacket_pagebuffer(device->channel,
packet->page_buf,
packet->page_buf_cnt,
&sendMessage,
sizeof(struct nvsp_message),
- (unsigned long)packet);
+ req_id);
} else {
ret = vmbus_sendpacket(device->channel, &sendMessage,
sizeof(struct nvsp_message),
- (unsigned long)packet,
+ req_id,
VM_PKT_DATA_INBAND,
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-
}
if (ret == 0) {
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 5f85205cd12b..088c55496191 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -241,13 +241,11 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
if (status == 1) {
netif_carrier_on(net);
- netif_wake_queue(net);
ndev_ctx = netdev_priv(net);
schedule_delayed_work(&ndev_ctx->dwork, 0);
schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
} else {
netif_carrier_off(net);
- netif_tx_disable(net);
}
}
@@ -431,7 +429,7 @@ static int netvsc_probe(struct hv_device *dev,
/* TODO: Add GSO and Checksum offload */
net->hw_features = NETIF_F_SG;
- net->features = NETIF_F_SG | NETIF_F_HW_VLAN_TX;
+ net->features = NETIF_F_SG | NETIF_F_HW_VLAN_CTAG_TX;
SET_ETHTOOL_OPS(net, &ethtool_ops);
SET_NETDEV_DEV(net, &dev->device);
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 2b657d4d63a8..0775f0aefd1e 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -61,9 +61,6 @@ struct rndis_request {
static void rndis_filter_send_completion(void *ctx);
-static void rndis_filter_send_request_completion(void *ctx);
-
-
static struct rndis_device *get_rndis_device(void)
{
@@ -241,10 +238,7 @@ static int rndis_filter_send_request(struct rndis_device *dev,
packet->page_buf[0].len;
}
- packet->completion.send.send_completion_ctx = req;/* packet; */
- packet->completion.send.send_completion =
- rndis_filter_send_request_completion;
- packet->completion.send.send_completion_tid = (unsigned long)dev;
+ packet->completion.send.send_completion = NULL;
ret = netvsc_send(dev->net_dev->dev, packet);
return ret;
@@ -999,9 +993,3 @@ static void rndis_filter_send_completion(void *ctx)
/* Pass it back to the original handler */
filter_pkt->completion(filter_pkt->completion_ctx);
}
-
-
-static void rndis_filter_send_request_completion(void *ctx)
-{
- /* Noop */
-}
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index fc1687ea4a42..6f10b4964726 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -51,7 +51,7 @@ struct at86rf230_local {
struct ieee802154_dev *dev;
spinlock_t lock;
- bool irq_disabled;
+ bool irq_busy;
bool is_tx;
};
@@ -219,6 +219,9 @@ struct at86rf230_local {
#define IRQ_PLL_UNL (1 << 1)
#define IRQ_PLL_LOCK (1 << 0)
+#define IRQ_ACTIVE_HIGH 0
+#define IRQ_ACTIVE_LOW 1
+
#define STATE_P_ON 0x00 /* BUSY */
#define STATE_BUSY_RX 0x01
#define STATE_BUSY_TX 0x02
@@ -233,8 +236,8 @@ struct at86rf230_local {
#define STATE_SLEEP 0x0F
#define STATE_BUSY_RX_AACK 0x11
#define STATE_BUSY_TX_ARET 0x12
-#define STATE_BUSY_RX_AACK_ON 0x16
-#define STATE_BUSY_TX_ARET_ON 0x19
+#define STATE_RX_AACK_ON 0x16
+#define STATE_TX_ARET_ON 0x19
#define STATE_RX_ON_NOCLK 0x1C
#define STATE_RX_AACK_ON_NOCLK 0x1D
#define STATE_BUSY_RX_AACK_NOCLK 0x1E
@@ -544,7 +547,7 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
unsigned long flags;
spin_lock(&lp->lock);
- if (lp->irq_disabled) {
+ if (lp->irq_busy) {
spin_unlock(&lp->lock);
return -EBUSY;
}
@@ -619,6 +622,52 @@ err:
return -EINVAL;
}
+static int
+at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
+ struct ieee802154_hw_addr_filt *filt,
+ unsigned long changed)
+{
+ struct at86rf230_local *lp = dev->priv;
+
+ if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+ dev_vdbg(&lp->spi->dev,
+ "at86rf230_set_hw_addr_filt called for saddr\n");
+ __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr);
+ __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8);
+ }
+
+ if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+ dev_vdbg(&lp->spi->dev,
+ "at86rf230_set_hw_addr_filt called for pan id\n");
+ __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id);
+ __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8);
+ }
+
+ if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+ dev_vdbg(&lp->spi->dev,
+ "at86rf230_set_hw_addr_filt called for IEEE addr\n");
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]);
+ at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]);
+ }
+
+ if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+ dev_vdbg(&lp->spi->dev,
+ "at86rf230_set_hw_addr_filt called for panc change\n");
+ if (filt->pan_coord)
+ at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1);
+ else
+ at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 0);
+ }
+
+ return 0;
+}
+
static struct ieee802154_ops at86rf230_ops = {
.owner = THIS_MODULE,
.xmit = at86rf230_xmit,
@@ -626,6 +675,7 @@ static struct ieee802154_ops at86rf230_ops = {
.set_channel = at86rf230_channel,
.start = at86rf230_start,
.stop = at86rf230_stop,
+ .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
};
static void at86rf230_irqwork(struct work_struct *work)
@@ -658,8 +708,16 @@ static void at86rf230_irqwork(struct work_struct *work)
}
spin_lock_irqsave(&lp->lock, flags);
- lp->irq_disabled = 0;
+ lp->irq_busy = 0;
spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static void at86rf230_irqwork_level(struct work_struct *work)
+{
+ struct at86rf230_local *lp =
+ container_of(work, struct at86rf230_local, irqwork);
+
+ at86rf230_irqwork(work);
enable_irq(lp->spi->irq);
}
@@ -668,10 +726,8 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
{
struct at86rf230_local *lp = data;
- disable_irq_nosync(irq);
-
spin_lock(&lp->lock);
- lp->irq_disabled = 1;
+ lp->irq_busy = 1;
spin_unlock(&lp->lock);
schedule_work(&lp->irqwork);
@@ -679,11 +735,23 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t at86rf230_isr_level(int irq, void *data)
+{
+ disable_irq_nosync(irq);
+
+ return at86rf230_isr(irq, data);
+}
+
+static int at86rf230_irq_polarity(struct at86rf230_local *lp, int pol)
+{
+ return at86rf230_write_subreg(lp, SR_IRQ_POLARITY, pol);
+}
static int at86rf230_hw_init(struct at86rf230_local *lp)
{
+ struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data;
+ int rc, irq_pol;
u8 status;
- int rc;
rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
if (rc)
@@ -701,12 +769,17 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
dev_info(&lp->spi->dev, "Status: %02x\n", status);
}
- rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, 0xff); /* IRQ_TRX_UR |
- * IRQ_CCA_ED |
- * IRQ_TRX_END |
- * IRQ_PLL_UNL |
- * IRQ_PLL_LOCK
- */
+ /* configure irq polarity, defaults to high active */
+ if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
+ irq_pol = IRQ_ACTIVE_LOW;
+ else
+ irq_pol = IRQ_ACTIVE_HIGH;
+
+ rc = at86rf230_irq_polarity(lp, irq_pol);
+ if (rc)
+ return rc;
+
+ rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END);
if (rc)
return rc;
@@ -751,37 +824,38 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
return 0;
}
-static int at86rf230_fill_data(struct spi_device *spi)
+static void at86rf230_fill_data(struct spi_device *spi)
{
struct at86rf230_local *lp = spi_get_drvdata(spi);
struct at86rf230_platform_data *pdata = spi->dev.platform_data;
- if (!pdata) {
- dev_err(&spi->dev, "no platform_data\n");
- return -EINVAL;
- }
-
lp->rstn = pdata->rstn;
lp->slp_tr = pdata->slp_tr;
lp->dig2 = pdata->dig2;
-
- return 0;
}
static int at86rf230_probe(struct spi_device *spi)
{
+ struct at86rf230_platform_data *pdata;
struct ieee802154_dev *dev;
struct at86rf230_local *lp;
- u8 man_id_0, man_id_1;
- int rc;
+ u8 man_id_0, man_id_1, status;
+ irq_handler_t irq_handler;
+ work_func_t irq_worker;
+ int rc, supported = 0;
const char *chip;
- int supported = 0;
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ specified\n");
return -EINVAL;
}
+ pdata = spi->dev.platform_data;
+ if (!pdata) {
+ dev_err(&spi->dev, "no platform_data\n");
+ return -EINVAL;
+ }
+
dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
if (!dev)
return -ENOMEM;
@@ -791,23 +865,28 @@ static int at86rf230_probe(struct spi_device *spi)
lp->spi = spi;
- dev->priv = lp;
dev->parent = &spi->dev;
dev->extra_tx_headroom = 0;
/* We do support only 2.4 Ghz */
dev->phy->channels_supported[0] = 0x7FFF800;
dev->flags = IEEE802154_HW_OMIT_CKSUM;
+ if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ irq_worker = at86rf230_irqwork;
+ irq_handler = at86rf230_isr;
+ } else {
+ irq_worker = at86rf230_irqwork_level;
+ irq_handler = at86rf230_isr_level;
+ }
+
mutex_init(&lp->bmux);
- INIT_WORK(&lp->irqwork, at86rf230_irqwork);
+ INIT_WORK(&lp->irqwork, irq_worker);
spin_lock_init(&lp->lock);
init_completion(&lp->tx_complete);
spi_set_drvdata(spi, lp);
- rc = at86rf230_fill_data(spi);
- if (rc)
- goto err_fill;
+ at86rf230_fill_data(spi);
rc = gpio_request(lp->rstn, "rstn");
if (rc)
@@ -882,18 +961,23 @@ static int at86rf230_probe(struct spi_device *spi)
if (rc)
goto err_gpio_dir;
- rc = request_irq(spi->irq, at86rf230_isr, IRQF_SHARED,
+ rc = request_irq(spi->irq, irq_handler,
+ IRQF_SHARED | pdata->irq_type,
dev_name(&spi->dev), lp);
if (rc)
goto err_gpio_dir;
+ /* Read irq status register to reset irq line */
+ rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
+ if (rc)
+ goto err_irq;
+
rc = ieee802154_register_device(lp->dev);
if (rc)
goto err_irq;
return rc;
- ieee802154_unregister_device(lp->dev);
err_irq:
free_irq(spi->irq, lp);
flush_work(&lp->irqwork);
@@ -903,7 +987,6 @@ err_gpio_dir:
err_slp_tr:
gpio_free(lp->rstn);
err_rstn:
-err_fill:
spi_set_drvdata(spi, NULL);
mutex_destroy(&lp->bmux);
ieee802154_free_device(lp->dev);
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
index 8f1c25676d44..bf0d55e2dd63 100644
--- a/drivers/net/ieee802154/fakehard.c
+++ b/drivers/net/ieee802154/fakehard.c
@@ -106,26 +106,6 @@ static u8 fake_get_dsn(const struct net_device *dev)
}
/**
- * fake_get_bsn - Retrieve the BSN of the device.
- * @dev: The network device to retrieve the BSN for.
- *
- * Returns the IEEE 802.15.4 BSN for the network device.
- * The BSN is the sequence number which will be added to each
- * beacon frame sent by the MAC.
- *
- * BSN means 'Beacon Sequence Number'.
- *
- * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
- * document.
- */
-static u8 fake_get_bsn(const struct net_device *dev)
-{
- BUG_ON(dev->type != ARPHRD_IEEE802154);
-
- return 0x00; /* BSN are implemented in HW, so return just 0 */
-}
-
-/**
* fake_assoc_req - Make an association request to the HW.
* @dev: The network device which we are associating to a network.
* @addr: The coordinator with which we wish to associate.
@@ -264,7 +244,6 @@ static struct ieee802154_mlme_ops fake_mlme = {
.get_pan_id = fake_get_pan_id,
.get_short_addr = fake_get_short_addr,
.get_dsn = fake_get_dsn,
- .get_bsn = fake_get_bsn,
};
static int ieee802154_fake_open(struct net_device *dev)
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index 3f2c7aaf28c4..ede3ce4912f9 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -22,8 +22,10 @@
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
#include <net/wpan-phy.h>
#include <net/mac802154.h>
+#include <net/ieee802154.h>
/* MRF24J40 Short Address Registers */
#define REG_RXMCR 0x00 /* Receive MAC control */
@@ -91,9 +93,8 @@ struct mrf24j40 {
#define MRF24J40_READLONG(reg) (1 << 15 | (reg) << 5)
#define MRF24J40_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4)
-/* Maximum speed to run the device at. TODO: Get the real max value from
- * someone at Microchip since it isn't in the datasheet. */
-#define MAX_SPI_SPEED_HZ 1000000
+/* The datasheet indicates the theoretical maximum for SCK to be 10MHz */
+#define MAX_SPI_SPEED_HZ 10000000
#define printdev(X) (&X->spi->dev)
@@ -349,7 +350,9 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
if (ret)
goto err;
val |= 0x1;
- val &= ~0x4;
+ /* Set TXNACKREQ if the ACK bit is set in the packet. */
+ if (skb->data[0] & IEEE802154_FC_ACK_REQ)
+ val |= 0x4;
write_short_reg(devrec, REG_TXNCON, val);
INIT_COMPLETION(devrec->tx_complete);
@@ -361,6 +364,7 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
if (ret == -ERESTARTSYS)
goto err;
if (ret == 0) {
+ dev_warn(printdev(devrec), "Timeout waiting for TX interrupt\n");
ret = -ETIMEDOUT;
goto err;
}
@@ -370,7 +374,7 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
if (ret)
goto err;
if (val & 0x1) {
- dev_err(printdev(devrec), "Error Sending. Retry count exceeded\n");
+ dev_dbg(printdev(devrec), "Error Sending. Retry count exceeded\n");
ret = -ECOMM; /* TODO: Better error code ? */
} else
dev_dbg(printdev(devrec), "Packet Sent\n");
@@ -477,7 +481,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
int i;
for (i = 0; i < 8; i++)
write_short_reg(devrec, REG_EADR0+i,
- filt->ieee_addr[i]);
+ filt->ieee_addr[7-i]);
#ifdef DEBUG
printk(KERN_DEBUG "Set long addr to: ");
@@ -623,6 +627,7 @@ static int mrf24j40_probe(struct spi_device *spi)
int ret = -ENOMEM;
u8 val;
struct mrf24j40 *devrec;
+ struct pinctrl *pinctrl;
printk(KERN_INFO "mrf24j40: probe(). IRQ: %d\n", spi->irq);
@@ -633,6 +638,11 @@ static int mrf24j40_probe(struct spi_device *spi)
if (!devrec->buf)
goto err_buf;
+ pinctrl = devm_pinctrl_get_select_default(&spi->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&spi->dev,
+ "pinctrl pins are not configured from the driver");
+
spi->mode = SPI_MODE_0; /* TODO: Is this appropriate for right here? */
if (spi->max_speed_hz > MAX_SPI_SPEED_HZ)
spi->max_speed_hz = MAX_SPI_SPEED_HZ;
@@ -641,7 +651,7 @@ static int mrf24j40_probe(struct spi_device *spi)
init_completion(&devrec->tx_complete);
INIT_WORK(&devrec->irqwork, mrf24j40_isrwork);
devrec->spi = spi;
- dev_set_drvdata(&spi->dev, devrec);
+ spi_set_drvdata(spi, devrec);
/* Register with the 802154 subsystem */
@@ -713,7 +723,7 @@ err_devrec:
static int mrf24j40_remove(struct spi_device *spi)
{
- struct mrf24j40 *devrec = dev_get_drvdata(&spi->dev);
+ struct mrf24j40 *devrec = spi_get_drvdata(spi);
dev_dbg(printdev(devrec), "remove\n");
@@ -725,7 +735,7 @@ static int mrf24j40_remove(struct spi_device *spi)
* complete? */
/* Clean up the SPI stuff. */
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(devrec->buf);
kfree(devrec);
return 0;
@@ -749,18 +759,7 @@ static struct spi_driver mrf24j40_driver = {
.remove = mrf24j40_remove,
};
-static int __init mrf24j40_init(void)
-{
- return spi_register_driver(&mrf24j40_driver);
-}
-
-static void __exit mrf24j40_exit(void)
-{
- spi_unregister_driver(&mrf24j40_driver);
-}
-
-module_init(mrf24j40_init);
-module_exit(mrf24j40_exit);
+module_spi_driver(mrf24j40_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alan Ott");
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 82164381f778..dc9f6a45515d 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -166,7 +166,8 @@ static const struct net_device_ops ifb_netdev_ops = {
#define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \
NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6 | \
- NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
+ NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX | \
+ NETIF_F_HW_VLAN_STAG_TX)
static void ifb_setup(struct net_device *dev)
{
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 9cea451a6081..3adb43ce138f 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -352,21 +352,19 @@ static int ali_ircc_open(int i, chipio_t *info)
/* Allocate memory if needed */
self->rx_buff.head =
dma_alloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
+ &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->rx_buff.head == NULL) {
err = -ENOMEM;
goto err_out2;
}
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
self->tx_buff.head =
dma_alloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
+ &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->tx_buff.head == NULL) {
err = -ENOMEM;
goto err_out3;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index b5151e4ced61..7a1f684edcb5 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/types.h>
+#include <linux/ioport.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
@@ -882,12 +883,12 @@ static int au1k_irda_probe(struct platform_device *pdev)
goto out;
err = -EBUSY;
- aup->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+ aup->ioarea = request_mem_region(r->start, resource_size(r),
pdev->name);
if (!aup->ioarea)
goto out;
- aup->iobase = ioremap_nocache(r->start, r->end - r->start + 1);
+ aup->iobase = ioremap_nocache(r->start, resource_size(r));
if (!aup->iobase)
goto out2;
@@ -952,18 +953,7 @@ static struct platform_driver au1k_irda_driver = {
.remove = au1k_irda_remove,
};
-static int __init au1k_irda_load(void)
-{
- return platform_driver_register(&au1k_irda_driver);
-}
-
-static void __exit au1k_irda_unload(void)
-{
- return platform_driver_unregister(&au1k_irda_driver);
-}
+module_platform_driver(au1k_irda_driver);
MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
-
-module_init(au1k_irda_load);
-module_exit(au1k_irda_unload);
diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c
index fed4a05d55c7..a06fca61c9a0 100644
--- a/drivers/net/irda/bfin_sir.c
+++ b/drivers/net/irda/bfin_sir.c
@@ -389,7 +389,8 @@ static int bfin_sir_startup(struct bfin_sir_port *port, struct net_device *dev)
set_dma_callback(port->rx_dma_channel, bfin_sir_dma_rx_int, dev);
set_dma_callback(port->tx_dma_channel, bfin_sir_dma_tx_int, dev);
- port->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
+ port->rx_dma_buf.buf = dma_alloc_coherent(NULL, PAGE_SIZE,
+ &dma_handle, GFP_DMA);
port->rx_dma_buf.head = 0;
port->rx_dma_buf.tail = 0;
port->rx_dma_nrows = 0;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 2a4f2f153244..9cf836b57c49 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -431,22 +431,20 @@ static int __init nsc_ircc_open(chipio_t *info)
/* Allocate memory if needed */
self->rx_buff.head =
dma_alloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
+ &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->rx_buff.head == NULL) {
err = -ENOMEM;
goto out2;
}
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
self->tx_buff.head =
dma_alloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
+ &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->tx_buff.head == NULL) {
err = -ENOMEM;
goto out3;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 858de05bdb7d..964b116a0ab7 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -700,12 +700,12 @@ static int pxa_irda_start(struct net_device *dev)
err = -ENOMEM;
si->dma_rx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
- &si->dma_rx_buff_phy, GFP_KERNEL );
+ &si->dma_rx_buff_phy, GFP_KERNEL);
if (!si->dma_rx_buff)
goto err_dma_rx_buff;
si->dma_tx_buff = dma_alloc_coherent(si->dev, IRDA_FRAME_SIZE_LIMIT,
- &si->dma_tx_buff_phy, GFP_KERNEL );
+ &si->dma_tx_buff_phy, GFP_KERNEL);
if (!si->dma_tx_buff)
goto err_dma_tx_buff;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 5290952b60c2..aa05dad75335 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -563,24 +563,15 @@ static int smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma,
self->rx_buff.head =
dma_alloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
- if (self->rx_buff.head == NULL) {
- IRDA_ERROR("%s, Can't allocate memory for receive buffer!\n",
- driver_name);
+ &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO);
+ if (self->rx_buff.head == NULL)
goto err_out2;
- }
self->tx_buff.head =
dma_alloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
- if (self->tx_buff.head == NULL) {
- IRDA_ERROR("%s, Can't allocate memory for transmit buffer!\n",
- driver_name);
+ &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO);
+ if (self->tx_buff.head == NULL)
goto err_out3;
- }
-
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index f9033c6a888c..51f2bc376101 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -364,21 +364,19 @@ static int via_ircc_open(struct pci_dev *pdev, chipio_t *info, unsigned int id)
/* Allocate memory if needed */
self->rx_buff.head =
dma_alloc_coherent(&pdev->dev, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
+ &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->rx_buff.head == NULL) {
err = -ENOMEM;
goto err_out2;
}
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
self->tx_buff.head =
dma_alloc_coherent(&pdev->dev, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
+ &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->tx_buff.head == NULL) {
err = -ENOMEM;
goto err_out3;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index f5bb92f15880..bb8857a158a6 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -216,22 +216,19 @@ static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
/* Allocate memory if needed */
self->rx_buff.head =
dma_alloc_coherent(NULL, self->rx_buff.truesize,
- &self->rx_buff_dma, GFP_KERNEL);
+ &self->rx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->rx_buff.head == NULL) {
err = -ENOMEM;
goto err_out1;
}
- memset(self->rx_buff.head, 0, self->rx_buff.truesize);
-
self->tx_buff.head =
dma_alloc_coherent(NULL, self->tx_buff.truesize,
- &self->tx_buff_dma, GFP_KERNEL);
+ &self->tx_buff_dma, GFP_KERNEL | __GFP_ZERO);
if (self->tx_buff.head == NULL) {
err = -ENOMEM;
goto err_out2;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
self->rx_buff.in_frame = FALSE;
self->rx_buff.state = OUTSIDE_FRAME;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 73abbc1655d5..d5a141c7c4e7 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -46,9 +46,16 @@ struct macvlan_port {
static void macvlan_port_destroy(struct net_device *dev);
-#define macvlan_port_get_rcu(dev) \
- ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data))
-#define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data)
+static struct macvlan_port *macvlan_port_get_rcu(const struct net_device *dev)
+{
+ return rcu_dereference(dev->rx_handler_data);
+}
+
+static struct macvlan_port *macvlan_port_get_rtnl(const struct net_device *dev)
+{
+ return rtnl_dereference(dev->rx_handler_data);
+}
+
#define macvlan_port_exists(dev) (dev->priv_flags & IFF_MACVLAN_PORT)
static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
@@ -464,7 +471,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
- NETIF_F_HW_VLAN_FILTER)
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -560,21 +567,21 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
}
static int macvlan_vlan_rx_add_vid(struct net_device *dev,
- unsigned short vid)
+ __be16 proto, u16 vid)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
- return vlan_vid_add(lowerdev, vid);
+ return vlan_vid_add(lowerdev, proto, vid);
}
static int macvlan_vlan_rx_kill_vid(struct net_device *dev,
- unsigned short vid)
+ __be16 proto, u16 vid)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
- vlan_vid_del(lowerdev, vid);
+ vlan_vid_del(lowerdev, proto, vid);
return 0;
}
@@ -703,7 +710,7 @@ static int macvlan_port_create(struct net_device *dev)
static void macvlan_port_destroy(struct net_device *dev)
{
- struct macvlan_port *port = macvlan_port_get(dev);
+ struct macvlan_port *port = macvlan_port_get_rtnl(dev);
dev->priv_flags &= ~IFF_MACVLAN_PORT;
netdev_rx_handler_unregister(dev);
@@ -772,7 +779,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
return err;
}
- port = macvlan_port_get(lowerdev);
+ port = macvlan_port_get_rtnl(lowerdev);
/* Only 1 macvlan device can be created in passthru mode */
if (port->passthru)
@@ -921,7 +928,7 @@ static int macvlan_device_event(struct notifier_block *unused,
if (!macvlan_port_exists(dev))
return NOTIFY_DONE;
- port = macvlan_port_get(dev);
+ port = macvlan_port_get_rtnl(dev);
switch (event) {
case NETDEV_CHANGE:
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index a449439bd653..59e9605de316 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -725,6 +725,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
goto err_kfree;
}
+ skb_probe_transport_header(skb, ETH_HLEN);
+
rcu_read_lock_bh();
vlan = rcu_dereference_bh(q->vlan);
/* copy skb_ubuf_info for callback when skb has no error */
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index ec40ba882f61..ff2e45e9cb54 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -159,7 +159,7 @@ static int lxt973a2_update_link(struct phy_device *phydev)
return 0;
}
-int lxt973a2_read_status(struct phy_device *phydev)
+static int lxt973a2_read_status(struct phy_device *phydev)
{
int adv;
int err;
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 22dec9c7ef05..202fe1ff1987 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -7,6 +7,8 @@
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*
+ * Copyright (c) 2013 Michael Stapelberg <michael@stapelberg.de>
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -80,6 +82,28 @@
#define MII_88E1318S_PHY_MSCR1_REG 16
#define MII_88E1318S_PHY_MSCR1_PAD_ODD BIT(6)
+/* Copper Specific Interrupt Enable Register */
+#define MII_88E1318S_PHY_CSIER 0x12
+/* WOL Event Interrupt Enable */
+#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
+
+/* LED Timer Control Register */
+#define MII_88E1318S_PHY_LED_PAGE 0x03
+#define MII_88E1318S_PHY_LED_TCR 0x12
+#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
+#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
+#define MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW BIT(11)
+
+/* Magic Packet MAC address registers */
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD2 0x17
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18
+#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19
+
+#define MII_88E1318S_PHY_WOL_PAGE 0x11
+#define MII_88E1318S_PHY_WOL_CTRL 0x10
+#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)
+#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
+
#define MII_88E1121_PHY_LED_CTRL 16
#define MII_88E1121_PHY_LED_PAGE 3
#define MII_88E1121_PHY_LED_DEF 0x0030
@@ -696,6 +720,107 @@ static int m88e1121_did_interrupt(struct phy_device *phydev)
return 0;
}
+static void m88e1318_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+
+ if (phy_write(phydev, MII_MARVELL_PHY_PAGE,
+ MII_88E1318S_PHY_WOL_PAGE) < 0)
+ return;
+
+ if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
+ MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
+ wol->wolopts |= WAKE_MAGIC;
+
+ if (phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00) < 0)
+ return;
+}
+
+static int m88e1318_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+ int err, oldpage, temp;
+
+ oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ /* Explicitly switch to page 0x00, just to be sure */
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x00);
+ if (err < 0)
+ return err;
+
+ /* Enable the WOL interrupt */
+ temp = phy_read(phydev, MII_88E1318S_PHY_CSIER);
+ temp |= MII_88E1318S_PHY_CSIER_WOL_EIE;
+ err = phy_write(phydev, MII_88E1318S_PHY_CSIER, temp);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+ MII_88E1318S_PHY_LED_PAGE);
+ if (err < 0)
+ return err;
+
+ /* Setup LED[2] as interrupt pin (active low) */
+ temp = phy_read(phydev, MII_88E1318S_PHY_LED_TCR);
+ temp &= ~MII_88E1318S_PHY_LED_TCR_FORCE_INT;
+ temp |= MII_88E1318S_PHY_LED_TCR_INTn_ENABLE;
+ temp |= MII_88E1318S_PHY_LED_TCR_INT_ACTIVE_LOW;
+ err = phy_write(phydev, MII_88E1318S_PHY_LED_TCR, temp);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+ MII_88E1318S_PHY_WOL_PAGE);
+ if (err < 0)
+ return err;
+
+ /* Store the device address for the magic packet */
+ err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD2,
+ ((phydev->attached_dev->dev_addr[5] << 8) |
+ phydev->attached_dev->dev_addr[4]));
+ if (err < 0)
+ return err;
+ err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD1,
+ ((phydev->attached_dev->dev_addr[3] << 8) |
+ phydev->attached_dev->dev_addr[2]));
+ if (err < 0)
+ return err;
+ err = phy_write(phydev, MII_88E1318S_PHY_MAGIC_PACKET_WORD0,
+ ((phydev->attached_dev->dev_addr[1] << 8) |
+ phydev->attached_dev->dev_addr[0]));
+ if (err < 0)
+ return err;
+
+ /* Clear WOL status and enable magic packet matching */
+ temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
+ temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
+ temp |= MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
+ err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
+ if (err < 0)
+ return err;
+ } else {
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
+ MII_88E1318S_PHY_WOL_PAGE);
+ if (err < 0)
+ return err;
+
+ /* Clear WOL status and disable magic packet matching */
+ temp = phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL);
+ temp |= MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS;
+ temp &= ~MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE;
+ err = phy_write(phydev, MII_88E1318S_PHY_WOL_CTRL, temp);
+ if (err < 0)
+ return err;
+ }
+
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static struct phy_driver marvell_drivers[] = {
{
.phy_id = MARVELL_PHY_ID_88E1101,
@@ -772,6 +897,8 @@ static struct phy_driver marvell_drivers[] = {
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.did_interrupt = &m88e1121_did_interrupt,
+ .get_wol = &m88e1318_get_wol,
+ .set_wol = &m88e1318_set_wol,
.driver = { .owner = THIS_MODULE },
},
{
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 27274986ab56..a47f9236d966 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -235,17 +235,7 @@ static struct platform_driver mdio_gpio_driver = {
},
};
-static int __init mdio_gpio_init(void)
-{
- return platform_driver_register(&mdio_gpio_driver);
-}
-module_init(mdio_gpio_init);
-
-static void __exit mdio_gpio_exit(void)
-{
- platform_driver_unregister(&mdio_gpio_driver);
-}
-module_exit(mdio_gpio_exit);
+module_platform_driver(mdio_gpio_driver);
MODULE_ALIAS("platform:mdio-gpio");
MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
index 09297fe05ae5..b51fa1f469b0 100644
--- a/drivers/net/phy/mdio-octeon.c
+++ b/drivers/net/phy/mdio-octeon.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2009,2011 Cavium, Inc.
+ * Copyright (C) 2009-2012 Cavium, Inc.
*/
#include <linux/platform_device.h>
@@ -27,30 +27,98 @@
#define SMI_CLK 0x18
#define SMI_EN 0x20
+enum octeon_mdiobus_mode {
+ UNINIT = 0,
+ C22,
+ C45
+};
+
struct octeon_mdiobus {
struct mii_bus *mii_bus;
u64 register_base;
resource_size_t mdio_phys;
resource_size_t regsize;
+ enum octeon_mdiobus_mode mode;
int phy_irq[PHY_MAX_ADDR];
};
+static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p,
+ enum octeon_mdiobus_mode m)
+{
+ union cvmx_smix_clk smi_clk;
+
+ if (m == p->mode)
+ return;
+
+ smi_clk.u64 = cvmx_read_csr(p->register_base + SMI_CLK);
+ smi_clk.s.mode = (m == C45) ? 1 : 0;
+ smi_clk.s.preamble = 1;
+ cvmx_write_csr(p->register_base + SMI_CLK, smi_clk.u64);
+ p->mode = m;
+}
+
+static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p,
+ int phy_id, int regnum)
+{
+ union cvmx_smix_cmd smi_cmd;
+ union cvmx_smix_wr_dat smi_wr;
+ int timeout = 1000;
+
+ octeon_mdiobus_set_mode(p, C45);
+
+ smi_wr.u64 = 0;
+ smi_wr.s.dat = regnum & 0xffff;
+ cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64);
+
+ regnum = (regnum >> 16) & 0x1f;
+
+ smi_cmd.u64 = 0;
+ smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */
+ smi_cmd.s.phy_adr = phy_id;
+ smi_cmd.s.reg_adr = regnum;
+ cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
+
+ do {
+ /* Wait 1000 clocks so we don't saturate the RSL bus
+ * doing reads.
+ */
+ __delay(1000);
+ smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT);
+ } while (smi_wr.s.pending && --timeout);
+
+ if (timeout <= 0)
+ return -EIO;
+ return 0;
+}
+
static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
{
struct octeon_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd;
union cvmx_smix_rd_dat smi_rd;
+ unsigned int op = 1; /* MDIO_CLAUSE_22_READ */
int timeout = 1000;
+ if (regnum & MII_ADDR_C45) {
+ int r = octeon_mdiobus_c45_addr(p, phy_id, regnum);
+ if (r < 0)
+ return r;
+
+ regnum = (regnum >> 16) & 0x1f;
+ op = 3; /* MDIO_CLAUSE_45_READ */
+ } else {
+ octeon_mdiobus_set_mode(p, C22);
+ }
+
+
smi_cmd.u64 = 0;
- smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
+ smi_cmd.s.phy_op = op;
smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum;
cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
do {
- /*
- * Wait 1000 clocks so we don't saturate the RSL bus
+ /* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
__delay(1000);
@@ -69,21 +137,33 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
struct octeon_mdiobus *p = bus->priv;
union cvmx_smix_cmd smi_cmd;
union cvmx_smix_wr_dat smi_wr;
+ unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */
int timeout = 1000;
+
+ if (regnum & MII_ADDR_C45) {
+ int r = octeon_mdiobus_c45_addr(p, phy_id, regnum);
+ if (r < 0)
+ return r;
+
+ regnum = (regnum >> 16) & 0x1f;
+ op = 1; /* MDIO_CLAUSE_45_WRITE */
+ } else {
+ octeon_mdiobus_set_mode(p, C22);
+ }
+
smi_wr.u64 = 0;
smi_wr.s.dat = val;
cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64);
smi_cmd.u64 = 0;
- smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
+ smi_cmd.s.phy_op = op;
smi_cmd.s.phy_adr = phy_id;
smi_cmd.s.reg_adr = regnum;
cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64);
do {
- /*
- * Wait 1000 clocks so we don't saturate the RSL bus
+ /* Wait 1000 clocks so we don't saturate the RSL bus
* doing reads.
*/
__delay(1000);
@@ -197,18 +277,7 @@ void octeon_mdiobus_force_mod_depencency(void)
}
EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
-static int __init octeon_mdiobus_mod_init(void)
-{
- return platform_driver_register(&octeon_mdiobus_driver);
-}
-
-static void __exit octeon_mdiobus_mod_exit(void)
-{
- platform_driver_unregister(&octeon_mdiobus_driver);
-}
-
-module_init(octeon_mdiobus_mod_init);
-module_exit(octeon_mdiobus_mod_exit);
+module_platform_driver(octeon_mdiobus_driver);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index abf7b6153d00..2510435f34ed 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -53,6 +53,18 @@
#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14)
#define KSZ8051_RMII_50MHZ_CLK (1 << 7)
+static int ksz_config_flags(struct phy_device *phydev)
+{
+ int regval;
+
+ if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
+ regval = phy_read(phydev, MII_KSZPHY_CTRL);
+ regval |= KSZ8051_RMII_50MHZ_CLK;
+ return phy_write(phydev, MII_KSZPHY_CTRL, regval);
+ }
+ return 0;
+}
+
static int kszphy_ack_interrupt(struct phy_device *phydev)
{
/* bit[7..0] int status, which is a read and clear register. */
@@ -114,22 +126,19 @@ static int kszphy_config_init(struct phy_device *phydev)
static int ksz8021_config_init(struct phy_device *phydev)
{
+ int rc;
const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
phy_write(phydev, MII_KSZPHY_OMSO, val);
- return 0;
+ rc = ksz_config_flags(phydev);
+ return rc < 0 ? rc : 0;
}
static int ks8051_config_init(struct phy_device *phydev)
{
- int regval;
-
- if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
- regval = phy_read(phydev, MII_KSZPHY_CTRL);
- regval |= KSZ8051_RMII_50MHZ_CLK;
- phy_write(phydev, MII_KSZPHY_CTRL, regval);
- }
+ int rc;
- return 0;
+ rc = ksz_config_flags(phydev);
+ return rc < 0 ? rc : 0;
}
#define KSZ8873MLL_GLOBAL_CONTROL_4 0x06
@@ -192,6 +201,19 @@ static struct phy_driver ksphy_driver[] = {
.config_intr = kszphy_config_intr,
.driver = { .owner = THIS_MODULE,},
}, {
+ .phy_id = PHY_ID_KSZ8031,
+ .phy_id_mask = 0x00ffffff,
+ .name = "Micrel KSZ8031",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = ksz8021_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = kszphy_ack_interrupt,
+ .config_intr = kszphy_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+}, {
.phy_id = PHY_ID_KSZ8041,
.phy_id_mask = 0x00fffff0,
.name = "Micrel KSZ8041",
@@ -325,6 +347,7 @@ static struct mdio_device_id __maybe_unused micrel_tbl[] = {
{ PHY_ID_KSZ8001, 0x00ffffff },
{ PHY_ID_KS8737, 0x00fffff0 },
{ PHY_ID_KSZ8021, 0x00ffffff },
+ { PHY_ID_KSZ8031, 0x00ffffff },
{ PHY_ID_KSZ8041, 0x00fffff0 },
{ PHY_ID_KSZ8051, 0x00fffff0 },
{ PHY_ID_KSZ8061, 0x00fffff0 },
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index ef9ea9248223..c14f14741b3f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -463,33 +463,6 @@ void phy_stop_machine(struct phy_device *phydev)
}
/**
- * phy_force_reduction - reduce PHY speed/duplex settings by one step
- * @phydev: target phy_device struct
- *
- * Description: Reduces the speed/duplex settings by one notch,
- * in this order--
- * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
- * The function bottoms out at 10/HALF.
- */
-static void phy_force_reduction(struct phy_device *phydev)
-{
- int idx;
-
- idx = phy_find_setting(phydev->speed, phydev->duplex);
-
- idx++;
-
- idx = phy_find_valid(idx, phydev->supported);
-
- phydev->speed = settings[idx].speed;
- phydev->duplex = settings[idx].duplex;
-
- pr_info("Trying %d/%s\n",
- phydev->speed, DUPLEX_FULL == phydev->duplex ? "FULL" : "HALF");
-}
-
-
-/**
* phy_error - enter HALTED state for this PHY device
* @phydev: target phy_device struct
*
@@ -818,30 +791,11 @@ void phy_state_machine(struct work_struct *work)
phydev->adjust_link(phydev->attached_dev);
} else if (0 == phydev->link_timeout--) {
- int idx;
-
needs_aneg = 1;
/* If we have the magic_aneg bit,
* we try again */
if (phydev->drv->flags & PHY_HAS_MAGICANEG)
break;
-
- /* The timer expired, and we still
- * don't have a setting, so we try
- * forcing it until we find one that
- * works, starting from the fastest speed,
- * and working our way down */
- idx = phy_find_valid(0, phydev->supported);
-
- phydev->speed = settings[idx].speed;
- phydev->duplex = settings[idx].duplex;
-
- phydev->autoneg = AUTONEG_DISABLE;
-
- pr_info("Trying %d/%s\n",
- phydev->speed,
- DUPLEX_FULL == phydev->duplex ?
- "FULL" : "HALF");
}
break;
case PHY_NOLINK:
@@ -866,10 +820,8 @@ void phy_state_machine(struct work_struct *work)
phydev->state = PHY_RUNNING;
netif_carrier_on(phydev->attached_dev);
} else {
- if (0 == phydev->link_timeout--) {
- phy_force_reduction(phydev);
+ if (0 == phydev->link_timeout--)
needs_aneg = 1;
- }
}
phydev->adjust_link(phydev->attached_dev);
@@ -1188,3 +1140,19 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
return 0;
}
EXPORT_SYMBOL(phy_ethtool_set_eee);
+
+int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+ if (phydev->drv->set_wol)
+ return phydev->drv->set_wol(phydev, wol);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(phy_ethtool_set_wol);
+
+void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+ if (phydev->drv->get_wol)
+ phydev->drv->get_wol(phydev, wol);
+}
+EXPORT_SYMBOL(phy_ethtool_get_wol);
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index 5c87eef40bf9..d11c93e69e03 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -281,7 +281,7 @@ static int ks8995_probe(struct spi_device *spi)
mutex_init(&ks->lock);
ks->pdata = pdata;
ks->spi = spi_dev_get(spi);
- dev_set_drvdata(&spi->dev, ks);
+ spi_set_drvdata(spi, ks);
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
@@ -325,7 +325,7 @@ static int ks8995_probe(struct spi_device *spi)
return 0;
err_drvdata:
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(ks);
return err;
}
@@ -334,10 +334,10 @@ static int ks8995_remove(struct spi_device *spi)
{
struct ks8995_data *ks8995;
- ks8995 = dev_get_drvdata(&spi->dev);
+ ks8995 = spi_get_drvdata(spi);
sysfs_remove_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(ks8995);
return 0;
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 2585c383e623..3492b5391273 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -61,7 +61,7 @@ MODULE_DESCRIPTION("Vitesse PHY driver");
MODULE_AUTHOR("Kriston Carson");
MODULE_LICENSE("GPL");
-int vsc824x_add_skew(struct phy_device *phydev)
+static int vsc824x_add_skew(struct phy_device *phydev)
{
int err;
int extcon;
@@ -81,7 +81,6 @@ int vsc824x_add_skew(struct phy_device *phydev)
return err;
}
-EXPORT_SYMBOL(vsc824x_add_skew);
static int vsc824x_config_init(struct phy_device *phydev)
{
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index bed62d9c53c8..1f7bef90b467 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -560,7 +560,7 @@ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
* so don't forget to remove it.
*/
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
return eth->h_proto;
rawp = skb->data;
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index a031f6b456b4..9c889e0303dd 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -314,7 +314,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
/* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_async_flush_output(ap);
- err = tty_perform_flush(tty, arg);
+ err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
case FIONREAD:
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 1a12033d2efa..925d3e295bac 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -105,64 +105,15 @@ static const struct ppp_channel_ops sync_ops = {
};
/*
- * Utility procedures to print a buffer in hex/ascii
+ * Utility procedure to print a buffer in hex/ascii
*/
static void
-ppp_print_hex (register __u8 * out, const __u8 * in, int count)
-{
- register __u8 next_ch;
- static const char hex[] = "0123456789ABCDEF";
-
- while (count-- > 0) {
- next_ch = *in++;
- *out++ = hex[(next_ch >> 4) & 0x0F];
- *out++ = hex[next_ch & 0x0F];
- ++out;
- }
-}
-
-static void
-ppp_print_char (register __u8 * out, const __u8 * in, int count)
-{
- register __u8 next_ch;
-
- while (count-- > 0) {
- next_ch = *in++;
-
- if (next_ch < 0x20 || next_ch > 0x7e)
- *out++ = '.';
- else {
- *out++ = next_ch;
- if (next_ch == '%') /* printk/syslogd has a bug !! */
- *out++ = '%';
- }
- }
- *out = '\0';
-}
-
-static void
ppp_print_buffer (const char *name, const __u8 *buf, int count)
{
- __u8 line[44];
-
if (name != NULL)
printk(KERN_DEBUG "ppp_synctty: %s, count = %d\n", name, count);
- while (count > 8) {
- memset (line, 32, 44);
- ppp_print_hex (line, buf, 8);
- ppp_print_char (&line[8 * 3], buf, 8);
- printk(KERN_DEBUG "%s\n", line);
- count -= 8;
- buf += 8;
- }
-
- if (count > 0) {
- memset (line, 32, 44);
- ppp_print_hex (line, buf, count);
- ppp_print_char (&line[8 * 3], buf, count);
- printk(KERN_DEBUG "%s\n", line);
- }
+ print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, count);
}
@@ -355,7 +306,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
/* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_sync_flush_output(ap);
- err = tty_perform_flush(tty, arg);
+ err = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
case FIONREAD:
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
index c3011af68e91..c853d84fd99f 100644
--- a/drivers/net/team/Kconfig
+++ b/drivers/net/team/Kconfig
@@ -37,6 +37,18 @@ config NET_TEAM_MODE_ROUNDROBIN
To compile this team mode as a module, choose M here: the module
will be called team_mode_roundrobin.
+config NET_TEAM_MODE_RANDOM
+ tristate "Random mode support"
+ depends on NET_TEAM
+ ---help---
+ Basic mode where port used for transmitting packets is selected
+ randomly.
+
+ All added ports are setup to have team's device address.
+
+ To compile this team mode as a module, choose M here: the module
+ will be called team_mode_random.
+
config NET_TEAM_MODE_ACTIVEBACKUP
tristate "Active-backup mode support"
depends on NET_TEAM
diff --git a/drivers/net/team/Makefile b/drivers/net/team/Makefile
index 975763014e5a..c57e85889751 100644
--- a/drivers/net/team/Makefile
+++ b/drivers/net/team/Makefile
@@ -5,5 +5,6 @@
obj-$(CONFIG_NET_TEAM) += team.o
obj-$(CONFIG_NET_TEAM_MODE_BROADCAST) += team_mode_broadcast.o
obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o
+obj-$(CONFIG_NET_TEAM_MODE_RANDOM) += team_mode_random.o
obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o
obj-$(CONFIG_NET_TEAM_MODE_LOADBALANCE) += team_mode_loadbalance.o
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index bf3419297875..7c43261975bd 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -73,11 +73,24 @@ static int team_port_set_orig_dev_addr(struct team_port *port)
return __set_port_dev_addr(port->dev, port->orig.dev_addr);
}
-int team_port_set_team_dev_addr(struct team_port *port)
+static int team_port_set_team_dev_addr(struct team *team,
+ struct team_port *port)
+{
+ return __set_port_dev_addr(port->dev, team->dev->dev_addr);
+}
+
+int team_modeop_port_enter(struct team *team, struct team_port *port)
+{
+ return team_port_set_team_dev_addr(team, port);
+}
+EXPORT_SYMBOL(team_modeop_port_enter);
+
+void team_modeop_port_change_dev_addr(struct team *team,
+ struct team_port *port)
{
- return __set_port_dev_addr(port->dev, port->team->dev->dev_addr);
+ team_port_set_team_dev_addr(team, port);
}
-EXPORT_SYMBOL(team_port_set_team_dev_addr);
+EXPORT_SYMBOL(team_modeop_port_change_dev_addr);
static void team_refresh_port_linkup(struct team_port *port)
{
@@ -490,9 +503,9 @@ static bool team_dummy_transmit(struct team *team, struct sk_buff *skb)
return false;
}
-rx_handler_result_t team_dummy_receive(struct team *team,
- struct team_port *port,
- struct sk_buff *skb)
+static rx_handler_result_t team_dummy_receive(struct team *team,
+ struct team_port *port,
+ struct sk_buff *skb)
{
return RX_HANDLER_ANOTHER;
}
@@ -1491,8 +1504,8 @@ static void team_set_rx_mode(struct net_device *dev)
rcu_read_lock();
list_for_each_entry_rcu(port, &team->port_list, list) {
- dev_uc_sync(port->dev, dev);
- dev_mc_sync(port->dev, dev);
+ dev_uc_sync_multiple(port->dev, dev);
+ dev_mc_sync_multiple(port->dev, dev);
}
rcu_read_unlock();
}
@@ -1585,7 +1598,7 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
return stats;
}
-static int team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
+static int team_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct team *team = netdev_priv(dev);
struct team_port *port;
@@ -1597,7 +1610,7 @@ static int team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
*/
mutex_lock(&team->lock);
list_for_each_entry(port, &team->port_list, list) {
- err = vlan_vid_add(port->dev, vid);
+ err = vlan_vid_add(port->dev, proto, vid);
if (err)
goto unwind;
}
@@ -1607,20 +1620,20 @@ static int team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
unwind:
list_for_each_entry_continue_reverse(port, &team->port_list, list)
- vlan_vid_del(port->dev, vid);
+ vlan_vid_del(port->dev, proto, vid);
mutex_unlock(&team->lock);
return err;
}
-static int team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+static int team_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
{
struct team *team = netdev_priv(dev);
struct team_port *port;
rcu_read_lock();
list_for_each_entry_rcu(port, &team->port_list, list)
- vlan_vid_del(port->dev, vid);
+ vlan_vid_del(port->dev, proto, vid);
rcu_read_unlock();
return 0;
@@ -1828,9 +1841,9 @@ static void team_setup(struct net_device *dev)
dev->features |= NETIF_F_LLTX;
dev->features |= NETIF_F_GRO;
dev->hw_features = TEAM_VLAN_FEATURES |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
dev->features |= dev->hw_features;
diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c
index c5db428e73fa..c366cd299c06 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -46,20 +46,10 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
return sum_ret;
}
-static int bc_port_enter(struct team *team, struct team_port *port)
-{
- return team_port_set_team_dev_addr(port);
-}
-
-static void bc_port_change_dev_addr(struct team *team, struct team_port *port)
-{
- team_port_set_team_dev_addr(port);
-}
-
static const struct team_mode_ops bc_mode_ops = {
.transmit = bc_transmit,
- .port_enter = bc_port_enter,
- .port_change_dev_addr = bc_port_change_dev_addr,
+ .port_enter = team_modeop_port_enter,
+ .port_change_dev_addr = team_modeop_port_change_dev_addr,
};
static const struct team_mode bc_mode = {
diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c
new file mode 100644
index 000000000000..9eabfaa22f3e
--- /dev/null
+++ b/drivers/net/team/team_mode_random.c
@@ -0,0 +1,71 @@
+/*
+ * drivers/net/team/team_mode_random.c - Random mode for team
+ * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/reciprocal_div.h>
+#include <linux/if_team.h>
+
+static u32 random_N(unsigned int N)
+{
+ return reciprocal_divide(random32(), N);
+}
+
+static bool rnd_transmit(struct team *team, struct sk_buff *skb)
+{
+ struct team_port *port;
+ int port_index;
+
+ port_index = random_N(team->en_port_count);
+ port = team_get_port_by_index_rcu(team, port_index);
+ port = team_get_first_port_txable_rcu(team, port);
+ if (unlikely(!port))
+ goto drop;
+ if (team_dev_queue_xmit(team, port, skb))
+ return false;
+ return true;
+
+drop:
+ dev_kfree_skb_any(skb);
+ return false;
+}
+
+static const struct team_mode_ops rnd_mode_ops = {
+ .transmit = rnd_transmit,
+ .port_enter = team_modeop_port_enter,
+ .port_change_dev_addr = team_modeop_port_change_dev_addr,
+};
+
+static const struct team_mode rnd_mode = {
+ .kind = "random",
+ .owner = THIS_MODULE,
+ .ops = &rnd_mode_ops,
+};
+
+static int __init rnd_init_module(void)
+{
+ return team_mode_register(&rnd_mode);
+}
+
+static void __exit rnd_cleanup_module(void)
+{
+ team_mode_unregister(&rnd_mode);
+}
+
+module_init(rnd_init_module);
+module_exit(rnd_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jiri@resnulli.us>");
+MODULE_DESCRIPTION("Random mode for team");
+MODULE_ALIAS("team-mode-random");
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index 105135aa8f05..d268e4de781b 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -25,26 +25,6 @@ static struct rr_priv *rr_priv(struct team *team)
return (struct rr_priv *) &team->mode_priv;
}
-static struct team_port *__get_first_port_up(struct team *team,
- struct team_port *port)
-{
- struct team_port *cur;
-
- if (team_port_txable(port))
- return port;
- cur = port;
- list_for_each_entry_continue_rcu(cur, &team->port_list, list)
- if (team_port_txable(port))
- return cur;
- list_for_each_entry_rcu(cur, &team->port_list, list) {
- if (cur == port)
- break;
- if (team_port_txable(port))
- return cur;
- }
- return NULL;
-}
-
static bool rr_transmit(struct team *team, struct sk_buff *skb)
{
struct team_port *port;
@@ -52,7 +32,7 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb)
port_index = rr_priv(team)->sent_packets++ % team->en_port_count;
port = team_get_port_by_index_rcu(team, port_index);
- port = __get_first_port_up(team, port);
+ port = team_get_first_port_txable_rcu(team, port);
if (unlikely(!port))
goto drop;
if (team_dev_queue_xmit(team, port, skb))
@@ -64,20 +44,10 @@ drop:
return false;
}
-static int rr_port_enter(struct team *team, struct team_port *port)
-{
- return team_port_set_team_dev_addr(port);
-}
-
-static void rr_port_change_dev_addr(struct team *team, struct team_port *port)
-{
- team_port_set_team_dev_addr(port);
-}
-
static const struct team_mode_ops rr_mode_ops = {
.transmit = rr_transmit,
- .port_enter = rr_port_enter,
- .port_change_dev_addr = rr_port_change_dev_addr,
+ .port_enter = team_modeop_port_enter,
+ .port_change_dev_addr = team_modeop_port_change_dev_addr,
};
static const struct team_mode rr_mode = {
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index b7c457adc0dc..f042b0373e5d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -409,14 +409,12 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
{
struct tun_file *ntfile;
struct tun_struct *tun;
- struct net_device *dev;
tun = rtnl_dereference(tfile->tun);
if (tun && !tfile->detached) {
u16 index = tfile->queue_index;
BUG_ON(index >= tun->numqueues);
- dev = tun->dev;
rcu_assign_pointer(tun->tfiles[index],
tun->tfiles[tun->numqueues - 1]);
@@ -1205,6 +1203,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
skb_reset_network_header(skb);
+ skb_probe_transport_header(skb, 0);
+
rxhash = skb_get_rxhash(skb);
netif_rx_ni(skb);
@@ -1471,14 +1471,17 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
if (!tun)
return -EBADFD;
- if (flags & ~(MSG_DONTWAIT|MSG_TRUNC))
- return -EINVAL;
+ if (flags & ~(MSG_DONTWAIT|MSG_TRUNC)) {
+ ret = -EINVAL;
+ goto out;
+ }
ret = tun_do_read(tun, tfile, iocb, m->msg_iov, total_len,
flags & MSG_DONTWAIT);
if (ret > total_len) {
m->msg_flags |= MSG_TRUNC;
ret = flags & MSG_TRUNC ? ret : total_len;
}
+out:
tun_put(tun);
return ret;
}
@@ -1593,8 +1596,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
return err;
if (tun->flags & TUN_TAP_MQ &&
- (tun->numqueues + tun->numdisabled > 1))
- return err;
+ (tun->numqueues + tun->numdisabled > 1)) {
+ /* One or more queue has already been attached, no need
+ * to initialize the device again.
+ */
+ return 0;
+ }
}
else {
char *name;
@@ -1656,6 +1663,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
TUN_USER_FEATURES;
dev->features = dev->hw_features;
+ dev->vlan_features = dev->features;
INIT_LIST_HEAD(&tun->disabled);
err = tun_attach(tun, file);
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 709753469099..ad5d1e4384db 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -55,11 +55,7 @@ static void asix_status(struct usbnet *dev, struct urb *urb)
event = urb->transfer_buffer;
link = event->link & 0x01;
if (netif_carrier_ok(dev->net) != link) {
- if (link) {
- netif_carrier_on(dev->net);
- usbnet_defer_kevent (dev, EVENT_LINK_RESET );
- } else
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, link, 1);
netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
}
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 71c27d8d214f..bd8758fa38c1 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -352,11 +352,7 @@ static void ax88179_status(struct usbnet *dev, struct urb *urb)
link = (((__force u32)event->intdata1) & AX_INT_PPLS_LINK) >> 16;
if (netif_carrier_ok(dev->net) != link) {
- if (link)
- usbnet_defer_kevent(dev, EVENT_LINK_RESET);
- else
- netif_carrier_off(dev->net);
-
+ usbnet_link_change(dev, link, 1);
netdev_info(dev->net, "ax88179 - Link status is: %d\n", link);
}
}
@@ -455,7 +451,7 @@ static int ax88179_resume(struct usb_interface *intf)
u16 tmp16;
u8 tmp8;
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, 0, 0);
/* Power up ethernet PHY */
tmp16 = 0;
@@ -1068,7 +1064,7 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
/* Restart autoneg */
mii_nway_restart(&dev->mii);
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, 0, 0);
return 0;
}
@@ -1356,7 +1352,7 @@ static int ax88179_reset(struct usbnet *dev)
/* Restart autoneg */
mii_nway_restart(&dev->mii);
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, 0, 0);
return 0;
}
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 57136dc1b887..4ff71d619cd8 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -406,10 +406,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
netif_dbg(dev, timer, dev->net, "CDC: carrier %s\n",
event->wValue ? "on" : "off");
- if (event->wValue)
- netif_carrier_on(dev->net);
- else
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, !!event->wValue, 0);
break;
case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */
netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n",
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index 16c842997291..872819851aef 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -101,7 +101,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->flags |= IFF_NOARP;
/* no need to put the VLAN tci in the packet headers */
- dev->net->features |= NETIF_F_HW_VLAN_TX;
+ dev->net->features |= NETIF_F_HW_VLAN_CTAG_TX;
err:
return ret;
}
@@ -134,7 +134,7 @@ static struct sk_buff *cdc_mbim_tx_fixup(struct usbnet *dev, struct sk_buff *skb
goto error;
if (skb) {
- if (skb->len <= sizeof(ETH_HLEN))
+ if (skb->len <= ETH_HLEN)
goto error;
/* mapping VLANs to MBIM sessions:
@@ -221,7 +221,7 @@ static struct sk_buff *cdc_mbim_process_dgram(struct usbnet *dev, u8 *buf, size_
/* map MBIM session to VLAN */
if (tci)
- vlan_put_tag(skb, tci);
+ vlan_put_tag(skb, htons(ETH_P_8021Q), tci);
err:
return skb;
}
@@ -323,6 +323,11 @@ static int cdc_mbim_suspend(struct usb_interface *intf, pm_message_t message)
goto error;
}
+ /*
+ * Both usbnet_suspend() and subdriver->suspend() MUST return 0
+ * in system sleep context, otherwise, the resume callback has
+ * to recover device from previous suspend failure.
+ */
ret = usbnet_suspend(intf, message);
if (ret < 0)
goto error;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 4709fa3497cf..43afde8f48d2 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -362,8 +362,8 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
u8 iface_no;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (ctx == NULL)
- return -ENODEV;
+ if (!ctx)
+ return -ENOMEM;
hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
@@ -610,7 +610,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
* (carrier is OFF) during attach, so the IP network stack does not
* start IPv6 negotiation and more.
*/
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, 0, 0);
return ret;
}
@@ -1106,12 +1106,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
" %sconnected\n",
ctx->netdev->name, ctx->connected ? "" : "dis");
- if (ctx->connected)
- netif_carrier_on(dev->net);
- else {
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, ctx->connected, 0);
+ if (!ctx->connected)
ctx->tx_speed = ctx->rx_speed = 0;
- }
break;
case USB_CDC_NOTIFY_SPEED_CHANGE:
@@ -1124,8 +1121,9 @@ static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
break;
default:
- dev_err(&dev->udev->dev, "NCM: unexpected "
- "notification 0x%02x!\n", event->bNotificationType);
+ dev_dbg(&dev->udev->dev,
+ "NCM: unexpected notification 0x%02x!\n",
+ event->bNotificationType);
break;
}
}
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 174e5ecea4cc..2dbb9460349d 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -524,12 +524,7 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
link = !!(buf[0] & 0x40);
if (netif_carrier_ok(dev->net) != link) {
- if (link) {
- netif_carrier_on(dev->net);
- usbnet_defer_kevent (dev, EVENT_LINK_RESET);
- }
- else
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, link, 1);
netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
}
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index e2dd3249b6bd..cba1d46e672e 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1925,7 +1925,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
int status = urb->status;
- struct tty_struct *tty;
/* sanity check */
if (!serial) {
@@ -1941,11 +1940,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
return;
}
hso_put_activity(serial->parent);
- tty = tty_port_tty_get(&serial->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&serial->port);
hso_kick_transmit(serial);
D1(" ");
@@ -2008,12 +2003,8 @@ static void ctrl_callback(struct urb *urb)
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
spin_unlock(&serial->serial_lock);
} else {
- struct tty_struct *tty = tty_port_tty_get(&serial->port);
hso_put_activity(serial->parent);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&serial->port);
/* response to a write command */
hso_kick_transmit(serial);
}
@@ -3133,18 +3124,13 @@ static void hso_serial_ref_free(struct kref *ref)
static void hso_free_interface(struct usb_interface *interface)
{
struct hso_serial *hso_dev;
- struct tty_struct *tty;
int i;
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] &&
(serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]);
- tty = tty_port_tty_get(&hso_dev->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&hso_dev->port, false);
mutex_lock(&hso_dev->parent->mutex);
hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex);
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index 3f3f566afa0b..03832d3780aa 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -576,11 +576,7 @@ static void mcs7830_status(struct usbnet *dev, struct urb *urb)
*/
if (data->link_counter > 20) {
data->link_counter = 0;
- if (link) {
- netif_carrier_on(dev->net);
- usbnet_defer_kevent(dev, EVENT_LINK_RESET);
- } else
- netif_carrier_off(dev->net);
+ usbnet_link_change(dev, link, 0);
netdev_dbg(dev->net, "Link Status is: %d\n", link);
}
} else
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 73051d10ead2..09699054b54f 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2005 Petko Manolov (petkan@users.sourceforge.net)
+ * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.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
@@ -26,6 +26,9 @@
* v0.5.1 ethtool support added
* v0.5.5 rx socket buffers are in a pool and the their allocation
* is out of the interrupt routine.
+ * ...
+ * v0.9.3 simplified [get|set]_register(s), async update registers
+ * logic revisited, receive skb_pool removed.
*/
#include <linux/sched.h>
@@ -45,8 +48,8 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.6.14 (2006/09/27)"
-#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
+#define DRIVER_VERSION "v0.9.3 (2013/04/25)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@nucleusys.com>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
static const char driver_name[] = "pegasus";
@@ -108,251 +111,137 @@ MODULE_PARM_DESC(msg_level, "Override default message level");
MODULE_DEVICE_TABLE(usb, pegasus_ids);
static const struct net_device_ops pegasus_netdev_ops;
-static int update_eth_regs_async(pegasus_t *);
-/* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback(struct urb *urb)
+/*****/
+
+static void async_ctrl_callback(struct urb *urb)
{
- pegasus_t *pegasus = urb->context;
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
int status = urb->status;
- if (!pegasus)
- return;
-
- switch (status) {
- case 0:
- if (pegasus->flags & ETH_REGS_CHANGE) {
- pegasus->flags &= ~ETH_REGS_CHANGE;
- pegasus->flags |= ETH_REGS_CHANGED;
- update_eth_regs_async(pegasus);
- return;
- }
- break;
- case -EINPROGRESS:
- return;
- case -ENOENT:
- break;
- default:
- if (net_ratelimit())
- netif_dbg(pegasus, drv, pegasus->net,
- "%s, status %d\n", __func__, status);
- break;
- }
- pegasus->flags &= ~ETH_REGS_CHANGED;
- wake_up(&pegasus->ctrl_wait);
+ if (status < 0)
+ dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
+ kfree(req);
+ usb_free_urb(urb);
}
-static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
- void *data)
+static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
- char *buffer;
- DECLARE_WAITQUEUE(wait, current);
-
- buffer = kmalloc(size, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (pegasus->flags & ETH_REGS_CHANGED)
- schedule();
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_RUNNING);
-
- pegasus->dr.bRequestType = PEGASUS_REQT_READ;
- pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
- pegasus->dr.wValue = cpu_to_le16(0);
- pegasus->dr.wIndex = cpu_to_le16(indx);
- pegasus->dr.wLength = cpu_to_le16(size);
- pegasus->ctrl_urb->transfer_buffer_length = size;
-
- usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
- usb_rcvctrlpipe(pegasus->usb, 0),
- (char *) &pegasus->dr,
- buffer, size, ctrl_callback, pegasus);
-
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
-
- /* using ATOMIC, we'd never wake up if we slept */
- if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
- set_current_state(TASK_RUNNING);
- if (ret == -ENODEV)
- netif_device_detach(pegasus->net);
- if (net_ratelimit())
- netif_err(pegasus, drv, pegasus->net,
- "%s, status %d\n", __func__, ret);
- goto out;
- }
-
- schedule();
-out:
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- memcpy(data, buffer, size);
- kfree(buffer);
+ ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0),
+ PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0,
+ indx, data, size, 1000);
+ if (ret < 0)
+ netif_dbg(pegasus, drv, pegasus->net,
+ "%s returned %d\n", __func__, ret);
return ret;
}
-static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
- void *data)
+static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
- char *buffer;
- DECLARE_WAITQUEUE(wait, current);
-
- buffer = kmemdup(data, size, GFP_KERNEL);
- if (!buffer) {
- netif_warn(pegasus, drv, pegasus->net,
- "out of memory in %s\n", __func__);
- return -ENOMEM;
- }
-
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (pegasus->flags & ETH_REGS_CHANGED)
- schedule();
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_RUNNING);
-
- pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
- pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
- pegasus->dr.wValue = cpu_to_le16(0);
- pegasus->dr.wIndex = cpu_to_le16(indx);
- pegasus->dr.wLength = cpu_to_le16(size);
- pegasus->ctrl_urb->transfer_buffer_length = size;
-
- usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
- usb_sndctrlpipe(pegasus->usb, 0),
- (char *) &pegasus->dr,
- buffer, size, ctrl_callback, pegasus);
-
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
-
- if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
- if (ret == -ENODEV)
- netif_device_detach(pegasus->net);
- netif_err(pegasus, drv, pegasus->net,
- "%s, status %d\n", __func__, ret);
- goto out;
- }
-
- schedule();
-out:
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- kfree(buffer);
+ ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
+ PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0,
+ indx, data, size, 100);
+ if (ret < 0)
+ netif_dbg(pegasus, drv, pegasus->net,
+ "%s returned %d\n", __func__, ret);
return ret;
}
static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
{
int ret;
- char *tmp;
- DECLARE_WAITQUEUE(wait, current);
-
- tmp = kmemdup(&data, 1, GFP_KERNEL);
- if (!tmp) {
- netif_warn(pegasus, drv, pegasus->net,
- "out of memory in %s\n", __func__);
- return -ENOMEM;
- }
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (pegasus->flags & ETH_REGS_CHANGED)
- schedule();
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_RUNNING);
-
- pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
- pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
- pegasus->dr.wValue = cpu_to_le16(data);
- pegasus->dr.wIndex = cpu_to_le16(indx);
- pegasus->dr.wLength = cpu_to_le16(1);
- pegasus->ctrl_urb->transfer_buffer_length = 1;
-
- usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
- usb_sndctrlpipe(pegasus->usb, 0),
- (char *) &pegasus->dr,
- tmp, 1, ctrl_callback, pegasus);
-
- add_wait_queue(&pegasus->ctrl_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
-
- if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
- if (ret == -ENODEV)
- netif_device_detach(pegasus->net);
- if (net_ratelimit())
- netif_err(pegasus, drv, pegasus->net,
- "%s, status %d\n", __func__, ret);
- goto out;
- }
-
- schedule();
-out:
- remove_wait_queue(&pegasus->ctrl_wait, &wait);
- kfree(tmp);
+ ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0),
+ PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data,
+ indx, &data, 1, 1000);
+ if (ret < 0)
+ netif_dbg(pegasus, drv, pegasus->net,
+ "%s returned %d\n", __func__, ret);
return ret;
}
static int update_eth_regs_async(pegasus_t *pegasus)
{
- int ret;
-
- pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
- pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
- pegasus->dr.wValue = cpu_to_le16(0);
- pegasus->dr.wIndex = cpu_to_le16(EthCtrl0);
- pegasus->dr.wLength = cpu_to_le16(3);
- pegasus->ctrl_urb->transfer_buffer_length = 3;
-
- usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
- usb_sndctrlpipe(pegasus->usb, 0),
- (char *) &pegasus->dr,
- pegasus->eth_regs, 3, ctrl_callback, pegasus);
-
- if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
+ int ret = -ENOMEM;
+ struct urb *async_urb;
+ struct usb_ctrlrequest *req;
+
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
+ if (req == NULL)
+ return ret;
+
+ async_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (async_urb == NULL) {
+ kfree(req);
+ return ret;
+ }
+ req->bRequestType = PEGASUS_REQT_WRITE;
+ req->bRequest = PEGASUS_REQ_SET_REGS;
+ req->wValue = cpu_to_le16(0);
+ req->wIndex = cpu_to_le16(EthCtrl0);
+ req->wLength = cpu_to_le16(3);
+
+ usb_fill_control_urb(async_urb, pegasus->usb,
+ usb_sndctrlpipe(pegasus->usb, 0), (void *)req,
+ pegasus->eth_regs, 3, async_ctrl_callback, req);
+
+ ret = usb_submit_urb(async_urb, GFP_ATOMIC);
+ if (ret) {
if (ret == -ENODEV)
netif_device_detach(pegasus->net);
netif_err(pegasus, drv, pegasus->net,
- "%s, status %d\n", __func__, ret);
+ "%s returned %d\n", __func__, ret);
}
-
return ret;
}
-/* Returns 0 on success, error on failure */
-static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
+static int __mii_op(pegasus_t *p, __u8 phy, __u8 indx, __u16 *regd, __u8 cmd)
{
int i;
__u8 data[4] = { phy, 0, 0, indx };
__le16 regdi;
- int ret;
+ int ret = -ETIMEDOUT;
- set_register(pegasus, PhyCtrl, 0);
- set_registers(pegasus, PhyAddr, sizeof(data), data);
- set_register(pegasus, PhyCtrl, (indx | PHY_READ));
+ if (cmd & PHY_WRITE) {
+ __le16 *t = (__le16 *) & data[1];
+ *t = cpu_to_le16(*regd);
+ }
+ set_register(p, PhyCtrl, 0);
+ set_registers(p, PhyAddr, sizeof(data), data);
+ set_register(p, PhyCtrl, (indx | cmd));
for (i = 0; i < REG_TIMEOUT; i++) {
- ret = get_registers(pegasus, PhyCtrl, 1, data);
- if (ret == -ESHUTDOWN)
+ ret = get_registers(p, PhyCtrl, 1, data);
+ if (ret < 0)
goto fail;
if (data[0] & PHY_DONE)
break;
}
-
if (i >= REG_TIMEOUT)
goto fail;
-
- ret = get_registers(pegasus, PhyData, 2, &regdi);
- *regd = le16_to_cpu(regdi);
+ if (cmd & PHY_READ) {
+ ret = get_registers(p, PhyData, 2, &regdi);
+ *regd = le16_to_cpu(regdi);
+ return ret;
+ }
+ return 0;
+fail:
+ netif_dbg(p, drv, p->net, "%s failed\n", __func__);
return ret;
+}
-fail:
- netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
+/* Returns non-negative int on success, error on failure */
+static int read_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
+{
+ return __mii_op(pegasus, phy, indx, regd, PHY_READ);
+}
- return ret;
+/* Returns zero on success, error on failure */
+static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd)
+{
+ return __mii_op(pegasus, phy, indx, regd, PHY_WRITE);
}
static int mdio_read(struct net_device *dev, int phy_id, int loc)
@@ -364,40 +253,11 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)
return (int)res;
}
-static int write_mii_word(pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd)
-{
- int i;
- __u8 data[4] = { phy, 0, 0, indx };
- int ret;
-
- data[1] = (u8) regd;
- data[2] = (u8) (regd >> 8);
- set_register(pegasus, PhyCtrl, 0);
- set_registers(pegasus, PhyAddr, sizeof(data), data);
- set_register(pegasus, PhyCtrl, (indx | PHY_WRITE));
- for (i = 0; i < REG_TIMEOUT; i++) {
- ret = get_registers(pegasus, PhyCtrl, 1, data);
- if (ret == -ESHUTDOWN)
- goto fail;
- if (data[0] & PHY_DONE)
- break;
- }
-
- if (i >= REG_TIMEOUT)
- goto fail;
-
- return ret;
-
-fail:
- netif_warn(pegasus, drv, pegasus->net, "%s failed\n", __func__);
- return -ETIMEDOUT;
-}
-
static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
{
pegasus_t *pegasus = netdev_priv(dev);
- write_mii_word(pegasus, phy_id, loc, val);
+ write_mii_word(pegasus, phy_id, loc, (__u16 *)&val);
}
static int read_eprom_word(pegasus_t *pegasus, __u8 index, __u16 *retdata)
@@ -434,7 +294,6 @@ fail:
static inline void enable_eprom_write(pegasus_t *pegasus)
{
__u8 tmp;
- int ret;
get_registers(pegasus, EthCtrl2, 1, &tmp);
set_register(pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE);
@@ -443,7 +302,6 @@ static inline void enable_eprom_write(pegasus_t *pegasus)
static inline void disable_eprom_write(pegasus_t *pegasus)
{
__u8 tmp;
- int ret;
get_registers(pegasus, EthCtrl2, 1, &tmp);
set_register(pegasus, EpromCtrl, 0);
@@ -537,7 +395,8 @@ static inline int reset_mac(pegasus_t *pegasus)
if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
__u16 auxmode;
read_mii_word(pegasus, 3, 0x1b, &auxmode);
- write_mii_word(pegasus, 3, 0x1b, auxmode | 4);
+ auxmode |= 4;
+ write_mii_word(pegasus, 3, 0x1b, &auxmode);
}
return 0;
@@ -569,57 +428,13 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
u16 auxmode;
read_mii_word(pegasus, 0, 0x1b, &auxmode);
- write_mii_word(pegasus, 0, 0x1b, auxmode | 4);
+ auxmode |= 4;
+ write_mii_word(pegasus, 0, 0x1b, &auxmode);
}
return ret;
}
-static void fill_skb_pool(pegasus_t *pegasus)
-{
- int i;
-
- for (i = 0; i < RX_SKBS; i++) {
- if (pegasus->rx_pool[i])
- continue;
- pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);
- /*
- ** we give up if the allocation fail. the tasklet will be
- ** rescheduled again anyway...
- */
- if (pegasus->rx_pool[i] == NULL)
- return;
- skb_reserve(pegasus->rx_pool[i], 2);
- }
-}
-
-static void free_skb_pool(pegasus_t *pegasus)
-{
- int i;
-
- for (i = 0; i < RX_SKBS; i++) {
- if (pegasus->rx_pool[i]) {
- dev_kfree_skb(pegasus->rx_pool[i]);
- pegasus->rx_pool[i] = NULL;
- }
- }
-}
-
-static inline struct sk_buff *pull_skb(pegasus_t * pegasus)
-{
- int i;
- struct sk_buff *skb;
-
- for (i = 0; i < RX_SKBS; i++) {
- if (likely(pegasus->rx_pool[i] != NULL)) {
- skb = pegasus->rx_pool[i];
- pegasus->rx_pool[i] = NULL;
- return skb;
- }
- }
- return NULL;
-}
-
static void read_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
@@ -704,9 +519,8 @@ static void read_bulk_callback(struct urb *urb)
if (pegasus->flags & PEGASUS_UNPLUG)
return;
- spin_lock(&pegasus->rx_pool_lock);
- pegasus->rx_skb = pull_skb(pegasus);
- spin_unlock(&pegasus->rx_pool_lock);
+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net, PEGASUS_MTU,
+ GFP_ATOMIC);
if (pegasus->rx_skb == NULL)
goto tl_sched;
@@ -734,24 +548,23 @@ tl_sched:
static void rx_fixup(unsigned long data)
{
pegasus_t *pegasus;
- unsigned long flags;
int status;
pegasus = (pegasus_t *) data;
if (pegasus->flags & PEGASUS_UNPLUG)
return;
- spin_lock_irqsave(&pegasus->rx_pool_lock, flags);
- fill_skb_pool(pegasus);
if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb)
goto try_again;
if (pegasus->rx_skb == NULL)
- pegasus->rx_skb = pull_skb(pegasus);
+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net,
+ PEGASUS_MTU,
+ GFP_ATOMIC);
if (pegasus->rx_skb == NULL) {
netif_warn(pegasus, rx_err, pegasus->net, "low on memory\n");
tasklet_schedule(&pegasus->rx_tl);
- goto done;
+ return;
}
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
@@ -767,8 +580,6 @@ try_again:
} else {
pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
}
-done:
- spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);
}
static void write_bulk_callback(struct urb *urb)
@@ -963,7 +774,6 @@ static void free_all_urbs(pegasus_t *pegasus)
usb_free_urb(pegasus->intr_urb);
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
}
static void unlink_all_urbs(pegasus_t *pegasus)
@@ -971,48 +781,42 @@ static void unlink_all_urbs(pegasus_t *pegasus)
usb_kill_urb(pegasus->intr_urb);
usb_kill_urb(pegasus->tx_urb);
usb_kill_urb(pegasus->rx_urb);
- usb_kill_urb(pegasus->ctrl_urb);
}
static int alloc_urbs(pegasus_t *pegasus)
{
- pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->ctrl_urb)
- return 0;
+ int res = -ENOMEM;
+
pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->rx_urb) {
- usb_free_urb(pegasus->ctrl_urb);
- return 0;
+ return res;
}
pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->tx_urb) {
usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
- return 0;
+ return res;
}
pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!pegasus->intr_urb) {
usb_free_urb(pegasus->tx_urb);
usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
- return 0;
+ return res;
}
- return 1;
+ return 0;
}
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = netdev_priv(net);
- int res;
+ int res=-ENOMEM;
if (pegasus->rx_skb == NULL)
- pegasus->rx_skb = pull_skb(pegasus);
- /*
- ** Note: no point to free the pool. it is empty :-)
- */
+ pegasus->rx_skb = __netdev_alloc_skb_ip_align(pegasus->net,
+ PEGASUS_MTU,
+ GFP_KERNEL);
if (!pegasus->rx_skb)
- return -ENOMEM;
+ goto exit;
res = set_registers(pegasus, EthID, 6, net->dev_addr);
@@ -1038,13 +842,13 @@ static int pegasus_open(struct net_device *net)
usb_kill_urb(pegasus->rx_urb);
goto exit;
}
- if ((res = enable_net_traffic(net, pegasus->usb))) {
+ res = enable_net_traffic(net, pegasus->usb);
+ if (res < 0) {
netif_dbg(pegasus, ifup, net,
"can't enable_net_traffic() - %d\n", res);
res = -EIO;
usb_kill_urb(pegasus->rx_urb);
usb_kill_urb(pegasus->intr_urb);
- free_skb_pool(pegasus);
goto exit;
}
set_carrier(net);
@@ -1195,7 +999,7 @@ static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE + 2:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+ write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, &data[2]);
res = 0;
break;
default:
@@ -1219,11 +1023,7 @@ static void pegasus_set_multicast(struct net_device *net)
pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
}
-
- pegasus->ctrl_urb->status = 0;
-
- pegasus->flags |= ETH_REGS_CHANGE;
- ctrl_callback(pegasus->ctrl_urb);
+ update_eth_regs_async(pegasus);
}
static __u8 mii_phy_probe(pegasus_t *pegasus)
@@ -1340,9 +1140,9 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus = netdev_priv(net);
pegasus->dev_index = dev_index;
- init_waitqueue_head(&pegasus->ctrl_wait);
- if (!alloc_urbs(pegasus)) {
+ res = alloc_urbs(pegasus);
+ if (res < 0) {
dev_err(&intf->dev, "can't allocate %s\n", "urbs");
goto out1;
}
@@ -1364,7 +1164,6 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->mii.mdio_write = mdio_write;
pegasus->mii.phy_id_mask = 0x1f;
pegasus->mii.reg_num_mask = 0x1f;
- spin_lock_init(&pegasus->rx_pool_lock);
pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
@@ -1376,7 +1175,6 @@ static int pegasus_probe(struct usb_interface *intf,
goto out2;
}
set_ethernet_addr(pegasus);
- fill_skb_pool(pegasus);
if (pegasus->features & PEGASUS_II) {
dev_info(&intf->dev, "setup Pegasus II specific registers\n");
setup_pegasus_II(pegasus);
@@ -1394,17 +1192,13 @@ static int pegasus_probe(struct usb_interface *intf,
if (res)
goto out3;
queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
- CARRIER_CHECK_DELAY);
-
- dev_info(&intf->dev, "%s, %s, %pM\n",
- net->name,
- usb_dev_id[dev_index].name,
- net->dev_addr);
+ CARRIER_CHECK_DELAY);
+ dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
+ usb_dev_id[dev_index].name, net->dev_addr);
return 0;
out3:
usb_set_intfdata(intf, NULL);
- free_skb_pool(pegasus);
out2:
free_all_urbs(pegasus);
out1:
@@ -1429,7 +1223,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
unregister_netdev(pegasus->net);
unlink_all_urbs(pegasus);
free_all_urbs(pegasus);
- free_skb_pool(pegasus);
if (pegasus->rx_skb != NULL) {
dev_kfree_skb(pegasus->rx_skb);
pegasus->rx_skb = NULL;
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index 65b78b35b73c..d15646244fdf 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net)
+ * Copyright (c) 1999-2013 Petko Manolov (petkan@nucleusys.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
@@ -13,7 +13,6 @@
#define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1536
-#define RX_SKBS 4
#define EPROM_WRITE 0x01
#define EPROM_READ 0x02
@@ -34,8 +33,6 @@
#define CTRL_URB_SLEEP 0x00000020
#define PEGASUS_UNPLUG 0x00000040
#define PEGASUS_RX_URB_FAIL 0x00000080
-#define ETH_REGS_CHANGE 0x40000000
-#define ETH_REGS_CHANGED 0x80000000
#define RX_MULTICAST 2
#define RX_PROMISCUOUS 4
@@ -96,12 +93,8 @@ typedef struct pegasus {
int intr_interval;
struct tasklet_struct rx_tl;
struct delayed_work carrier_check;
- struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
- struct sk_buff *rx_pool[RX_SKBS];
+ struct urb *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *rx_skb;
- struct usb_ctrlrequest dr;
- wait_queue_head_t ctrl_wait;
- spinlock_t rx_pool_lock;
int chip;
unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU];
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 968d5d50751d..5a88e72090ce 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
@@ -52,6 +53,96 @@ struct qmi_wwan_state {
struct usb_interface *data;
};
+/* default ethernet address used by the modem */
+static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
+
+/* Make up an ethernet header if the packet doesn't have one.
+ *
+ * A firmware bug common among several devices cause them to send raw
+ * IP packets under some circumstances. There is no way for the
+ * driver/host to know when this will happen. And even when the bug
+ * hits, some packets will still arrive with an intact header.
+ *
+ * The supported devices are only capably of sending IPv4, IPv6 and
+ * ARP packets on a point-to-point link. Any packet with an ethernet
+ * header will have either our address or a broadcast/multicast
+ * address as destination. ARP packets will always have a header.
+ *
+ * This means that this function will reliably add the appropriate
+ * header iff necessary, provided our hardware address does not start
+ * with 4 or 6.
+ *
+ * Another common firmware bug results in all packets being addressed
+ * to 00:a0:c6:00:00:00 despite the host address being different.
+ * This function will also fixup such packets.
+ */
+static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ __be16 proto;
+
+ /* usbnet rx_complete guarantees that skb->len is at least
+ * hard_header_len, so we can inspect the dest address without
+ * checking skb->len
+ */
+ switch (skb->data[0] & 0xf0) {
+ case 0x40:
+ proto = htons(ETH_P_IP);
+ break;
+ case 0x60:
+ proto = htons(ETH_P_IPV6);
+ break;
+ case 0x00:
+ if (is_multicast_ether_addr(skb->data))
+ return 1;
+ /* possibly bogus destination - rewrite just in case */
+ skb_reset_mac_header(skb);
+ goto fix_dest;
+ default:
+ /* pass along other packets without modifications */
+ return 1;
+ }
+ if (skb_headroom(skb) < ETH_HLEN)
+ return 0;
+ skb_push(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ eth_hdr(skb)->h_proto = proto;
+ memset(eth_hdr(skb)->h_source, 0, ETH_ALEN);
+fix_dest:
+ memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN);
+ return 1;
+}
+
+/* very simplistic detection of IPv4 or IPv6 headers */
+static bool possibly_iphdr(const char *data)
+{
+ return (data[0] & 0xd0) == 0x40;
+}
+
+/* disallow addresses which may be confused with IP headers */
+static int qmi_wwan_mac_addr(struct net_device *dev, void *p)
+{
+ int ret;
+ struct sockaddr *addr = p;
+
+ ret = eth_prepare_mac_addr_change(dev, p);
+ if (ret < 0)
+ return ret;
+ if (possibly_iphdr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+ eth_commit_mac_addr_change(dev, p);
+ return 0;
+}
+
+static const struct net_device_ops qmi_wwan_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = qmi_wwan_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
/* using a counter to merge subdriver requests with our own into a combined state */
static int qmi_wwan_manage_power(struct usbnet *dev, int on)
{
@@ -229,6 +320,18 @@ next_desc:
usb_driver_release_interface(driver, info->data);
}
+ /* Never use the same address on both ends of the link, even
+ * if the buggy firmware told us to.
+ */
+ if (!compare_ether_addr(dev->net->dev_addr, default_modem_addr))
+ eth_hw_addr_random(dev->net);
+
+ /* make MAC addr easily distinguishable from an IP header */
+ if (possibly_iphdr(dev->net->dev_addr)) {
+ dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */
+ dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */
+ }
+ dev->net->netdev_ops = &qmi_wwan_netdev_ops;
err:
return status;
}
@@ -271,6 +374,11 @@ static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
struct qmi_wwan_state *info = (void *)&dev->data;
int ret;
+ /*
+ * Both usbnet_suspend() and subdriver->suspend() MUST return 0
+ * in system sleep context, otherwise, the resume callback has
+ * to recover device from previous suspend failure.
+ */
ret = usbnet_suspend(intf, message);
if (ret < 0)
goto err;
@@ -307,6 +415,7 @@ static const struct driver_info qmi_wwan_info = {
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
+ .rx_fixup = qmi_wwan_rx_fixup,
};
#define HUAWEI_VENDOR_ID 0x12D1
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index 79ab2435d9d3..a923d61c6fc5 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -413,11 +413,10 @@ static void sierra_net_handle_lsi(struct usbnet *dev, char *data,
if (link_up) {
sierra_net_set_ctx_index(priv, hh->msgspecific.byte);
priv->link_up = 1;
- netif_carrier_on(dev->net);
} else {
priv->link_up = 0;
- netif_carrier_off(dev->net);
}
+ usbnet_link_change(dev, link_up, 0);
}
static void sierra_net_dosync(struct usbnet *dev)
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 9abe51710f22..75409748c774 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -914,8 +914,12 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
{
struct usbnet *dev = netdev_priv(netdev);
+ int ret;
+
+ if (new_mtu > MAX_SINGLE_PACKET_SIZE)
+ return -EINVAL;
- int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu);
+ ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);
if (ret < 0) {
netdev_warn(dev->net, "Failed to set mac rx frame length\n");
return ret;
@@ -1324,7 +1328,7 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf);
- ret = smsc75xx_set_rx_max_frame_length(dev, 1514);
+ ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN);
if (ret < 0) {
netdev_warn(dev->net, "Failed to set max rx frame length\n");
return ret;
@@ -2011,7 +2015,11 @@ static int smsc75xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc75xx_enter_suspend0(dev);
done:
- if (ret)
+ /*
+ * TODO: resume() might need to handle the suspend failure
+ * in system sleep
+ */
+ if (ret && PMSG_IS_AUTO(message))
usbnet_resume(intf);
return ret;
}
@@ -2134,8 +2142,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))
dev->net->stats.rx_frame_errors++;
} else {
- /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
- if (unlikely(size > (ETH_FRAME_LEN + 12))) {
+ /* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */
+ if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) {
netif_dbg(dev, rx_err, dev->net,
"size err rx_cmd_a=0x%08x\n",
rx_cmd_a);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index e6d2dea1373c..3f38ba868f61 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1660,7 +1660,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc95xx_enter_suspend0(dev);
done:
- if (ret)
+ /*
+ * TODO: resume() might need to handle the suspend failure
+ * in system sleep
+ */
+ if (ret && PMSG_IS_AUTO(message))
usbnet_resume(intf);
return ret;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 51f3192f3931..1e5a9b72650e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -938,6 +938,27 @@ static const struct ethtool_ops usbnet_ethtool_ops = {
/*-------------------------------------------------------------------------*/
+static void __handle_link_change(struct usbnet *dev)
+{
+ if (!test_bit(EVENT_DEV_OPEN, &dev->flags))
+ return;
+
+ if (!netif_carrier_ok(dev->net)) {
+ /* kill URBs for reading packets to save bus bandwidth */
+ unlink_urbs(dev, &dev->rxq);
+
+ /*
+ * tx_timeout will unlink URBs for sending packets and
+ * tx queue is stopped by netcore after link becomes off
+ */
+ } else {
+ /* submitting URBs for reading packets */
+ tasklet_schedule(&dev->bh);
+ }
+
+ clear_bit(EVENT_LINK_CHANGE, &dev->flags);
+}
+
/* work that cannot be done in interrupt context uses keventd.
*
* NOTE: with 2.5 we could do more of this using completion callbacks,
@@ -1035,8 +1056,14 @@ skip_reset:
} else {
usb_autopm_put_interface(dev->intf);
}
+
+ /* handle link change from link resetting */
+ __handle_link_change(dev);
}
+ if (test_bit (EVENT_LINK_CHANGE, &dev->flags))
+ __handle_link_change(dev);
+
if (dev->flags)
netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags);
}
@@ -1286,6 +1313,7 @@ static void usbnet_bh (unsigned long param)
// or are we maybe short a few urbs?
} else if (netif_running (dev->net) &&
netif_device_present (dev->net) &&
+ netif_carrier_ok(dev->net) &&
!timer_pending (&dev->delay) &&
!test_bit (EVENT_RX_HALT, &dev->flags)) {
int temp = dev->rxq.qlen;
@@ -1521,7 +1549,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
netif_device_attach (net);
if (dev->driver_info->flags & FLAG_LINK_INTR)
- netif_carrier_off(net);
+ usbnet_link_change(dev, 0, 0);
return 0;
@@ -1653,6 +1681,21 @@ int usbnet_manage_power(struct usbnet *dev, int on)
}
EXPORT_SYMBOL(usbnet_manage_power);
+void usbnet_link_change(struct usbnet *dev, bool link, bool need_reset)
+{
+ /* update link after link is reseted */
+ if (link && !need_reset)
+ netif_carrier_on(dev->net);
+ else
+ netif_carrier_off(dev->net);
+
+ if (need_reset && link)
+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
+ else
+ usbnet_defer_kevent(dev, EVENT_LINK_CHANGE);
+}
+EXPORT_SYMBOL(usbnet_link_change);
+
/*-------------------------------------------------------------------------*/
static int __usbnet_read_cmd(struct usbnet *dev, u8 cmd, u8 reqtype,
u16 value, u16 index, void *data, u16 size)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 07a4af0aa3dc..177f911f5946 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -255,7 +255,8 @@ static const struct net_device_ops veth_netdev_ops = {
#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | \
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | \
+ NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_STAG_RX )
static void veth_setup(struct net_device *dev)
{
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 57ac4b0294bc..50077753a0e5 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -154,7 +154,7 @@ struct padded_vnet_hdr {
*/
static int vq2txq(struct virtqueue *vq)
{
- return (virtqueue_get_queue_index(vq) - 1) / 2;
+ return (vq->index - 1) / 2;
}
static int txq2vq(int txq)
@@ -164,7 +164,7 @@ static int txq2vq(int txq)
static int vq2rxq(struct virtqueue *vq)
{
- return virtqueue_get_queue_index(vq) / 2;
+ return vq->index / 2;
}
static int rxq2vq(int rxq)
@@ -1006,7 +1006,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
kfree(buf);
}
-static int virtnet_vlan_rx_add_vid(struct net_device *dev, u16 vid)
+static int virtnet_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct virtnet_info *vi = netdev_priv(dev);
struct scatterlist sg;
@@ -1019,7 +1020,8 @@ static int virtnet_vlan_rx_add_vid(struct net_device *dev, u16 vid)
return 0;
}
-static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
+static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct virtnet_info *vi = netdev_priv(dev);
struct scatterlist sg;
@@ -1376,7 +1378,7 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
if (vi->has_cvq) {
vi->cvq = vqs[total_vqs - 1];
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN))
- vi->dev->features |= NETIF_F_HW_VLAN_FILTER;
+ vi->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
}
for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -1511,6 +1513,8 @@ static int virtnet_probe(struct virtio_device *vdev)
/* (!csum && gso) case will be fixed by register_netdev() */
}
+ dev->vlan_features = dev->features;
+
/* Configuration may specify what MAC to use. Otherwise random. */
if (virtio_config_val_len(vdev, VIRTIO_NET_F_MAC,
offsetof(struct virtio_net_config, mac),
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index eae7a03d4f9b..55a62cae2cb4 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1293,7 +1293,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skb->protocol = eth_type_trans(skb, adapter->netdev);
if (unlikely(rcd->ts))
- __vlan_hwaccel_put_tag(skb, rcd->tci);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
if (adapter->netdev->features & NETIF_F_LRO)
netif_receive_skb(skb);
@@ -1931,7 +1931,7 @@ vmxnet3_restore_vlan(struct vmxnet3_adapter *adapter)
static int
-vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+vmxnet3_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
@@ -1953,7 +1953,7 @@ vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
static int
-vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
@@ -2107,7 +2107,7 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
devRead->misc.uptFeatures |= UPT1_F_LRO;
devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS);
}
- if (adapter->netdev->features & NETIF_F_HW_VLAN_RX)
+ if (adapter->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
@@ -2669,14 +2669,15 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64)
struct net_device *netdev = adapter->netdev;
netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
- NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_TSO | NETIF_F_TSO6 |
NETIF_F_LRO;
if (dma64)
netdev->hw_features |= NETIF_F_HIGHDMA;
netdev->vlan_features = netdev->hw_features &
- ~(NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
- netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_FILTER;
+ ~(NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX);
+ netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 63a124340cbe..600ab56c0008 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -263,7 +263,8 @@ int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
unsigned long flags;
netdev_features_t changed = features ^ netdev->features;
- if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_RX)) {
+ if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO |
+ NETIF_F_HW_VLAN_CTAG_RX)) {
if (features & NETIF_F_RXCSUM)
adapter->shared->devRead.misc.uptFeatures |=
UPT1_F_RXCSUM;
@@ -279,7 +280,7 @@ int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
adapter->shared->devRead.misc.uptFeatures &=
~UPT1_F_LRO;
- if (features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
adapter->shared->devRead.misc.uptFeatures |=
UPT1_F_RXVLAN;
else
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 7cee7a3068ec..ba81f3c39a83 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1,14 +1,13 @@
/*
* VXLAN: Virtual eXtensible Local Area Network
*
- * Copyright (c) 2012 Vyatta Inc.
+ * Copyright (c) 2012-2013 Vyatta Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* TODO
- * - use IANA UDP port number (when defined)
* - IPv6 (not in RFC)
*/
@@ -33,7 +32,7 @@
#include <net/arp.h>
#include <net/ndisc.h>
#include <net/ip.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/icmp.h>
#include <net/udp.h>
#include <net/rtnetlink.h>
@@ -65,7 +64,10 @@ struct vxlanhdr {
__be32 vx_vni;
};
-/* UDP port for VXLAN traffic. */
+/* UDP port for VXLAN traffic.
+ * The IANA assigned port is 4789, but the Linux default is 8472
+ * for compatability with early adopters.
+ */
static unsigned int vxlan_port __read_mostly = 8472;
module_param_named(udp_port, vxlan_port, uint, 0444);
MODULE_PARM_DESC(udp_port, "Destination UDP port");
@@ -81,35 +83,34 @@ struct vxlan_net {
struct hlist_head vni_list[VNI_HASH_SIZE];
};
+struct vxlan_rdst {
+ struct rcu_head rcu;
+ __be32 remote_ip;
+ __be16 remote_port;
+ u32 remote_vni;
+ u32 remote_ifindex;
+ struct vxlan_rdst *remote_next;
+};
+
/* Forwarding table entry */
struct vxlan_fdb {
struct hlist_node hlist; /* linked list of entries */
struct rcu_head rcu;
unsigned long updated; /* jiffies */
unsigned long used;
- __be32 remote_ip;
+ struct vxlan_rdst remote;
u16 state; /* see ndm_state */
+ u8 flags; /* see ndm_flags */
u8 eth_addr[ETH_ALEN];
};
-/* Per-cpu network traffic stats */
-struct vxlan_stats {
- u64 rx_packets;
- u64 rx_bytes;
- u64 tx_packets;
- u64 tx_bytes;
- struct u64_stats_sync syncp;
-};
-
/* Pseudo network device */
struct vxlan_dev {
struct hlist_node hlist;
struct net_device *dev;
- struct vxlan_stats __percpu *stats;
- __u32 vni; /* virtual network id */
- __be32 gaddr; /* multicast group */
+ struct vxlan_rdst default_dst; /* default destination */
__be32 saddr; /* source address */
- unsigned int link; /* link to multicast over */
+ __be16 dst_port;
__u16 port_min; /* source port range */
__u16 port_max;
__u8 tos; /* TOS override */
@@ -147,7 +148,7 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id)
struct vxlan_dev *vxlan;
hlist_for_each_entry_rcu(vxlan, vni_head(net, id), hlist) {
- if (vxlan->vni == id)
+ if (vxlan->default_dst.remote_vni == id)
return vxlan;
}
@@ -157,7 +158,8 @@ static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id)
/* Fill in neighbour message in skbuff. */
static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
const struct vxlan_fdb *fdb,
- u32 portid, u32 seq, int type, unsigned int flags)
+ u32 portid, u32 seq, int type, unsigned int flags,
+ const struct vxlan_rdst *rdst)
{
unsigned long now = jiffies;
struct nda_cacheinfo ci;
@@ -176,19 +178,29 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (type == RTM_GETNEIGH) {
ndm->ndm_family = AF_INET;
- send_ip = fdb->remote_ip != 0;
+ send_ip = rdst->remote_ip != htonl(INADDR_ANY);
send_eth = !is_zero_ether_addr(fdb->eth_addr);
} else
ndm->ndm_family = AF_BRIDGE;
ndm->ndm_state = fdb->state;
ndm->ndm_ifindex = vxlan->dev->ifindex;
- ndm->ndm_flags = NTF_SELF;
+ ndm->ndm_flags = fdb->flags;
ndm->ndm_type = NDA_DST;
if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr))
goto nla_put_failure;
- if (send_ip && nla_put_be32(skb, NDA_DST, fdb->remote_ip))
+ if (send_ip && nla_put_be32(skb, NDA_DST, rdst->remote_ip))
+ goto nla_put_failure;
+
+ if (rdst->remote_port && rdst->remote_port != vxlan->dst_port &&
+ nla_put_be16(skb, NDA_PORT, rdst->remote_port))
+ goto nla_put_failure;
+ if (rdst->remote_vni != vxlan->default_dst.remote_vni &&
+ nla_put_be32(skb, NDA_VNI, rdst->remote_vni))
+ goto nla_put_failure;
+ if (rdst->remote_ifindex &&
+ nla_put_u32(skb, NDA_IFINDEX, rdst->remote_ifindex))
goto nla_put_failure;
ci.ndm_used = jiffies_to_clock_t(now - fdb->used);
@@ -211,6 +223,9 @@ static inline size_t vxlan_nlmsg_size(void)
return NLMSG_ALIGN(sizeof(struct ndmsg))
+ nla_total_size(ETH_ALEN) /* NDA_LLADDR */
+ nla_total_size(sizeof(__be32)) /* NDA_DST */
+ + nla_total_size(sizeof(__be16)) /* NDA_PORT */
+ + nla_total_size(sizeof(__be32)) /* NDA_VNI */
+ + nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */
+ nla_total_size(sizeof(struct nda_cacheinfo));
}
@@ -225,7 +240,7 @@ static void vxlan_fdb_notify(struct vxlan_dev *vxlan,
if (skb == NULL)
goto errout;
- err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0);
+ err = vxlan_fdb_info(skb, vxlan, fdb, 0, 0, type, 0, &fdb->remote);
if (err < 0) {
/* -EMSGSIZE implies BUG in vxlan_nlmsg_size() */
WARN_ON(err == -EMSGSIZE);
@@ -247,7 +262,8 @@ static void vxlan_ip_miss(struct net_device *dev, __be32 ipa)
memset(&f, 0, sizeof f);
f.state = NUD_STALE;
- f.remote_ip = ipa; /* goes to NDA_DST */
+ f.remote.remote_ip = ipa; /* goes to NDA_DST */
+ f.remote.remote_vni = VXLAN_N_VID;
vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
}
@@ -300,10 +316,39 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
return NULL;
}
+/* Add/update destinations for multicast */
+static int vxlan_fdb_append(struct vxlan_fdb *f,
+ __be32 ip, __be16 port, __u32 vni, __u32 ifindex)
+{
+ struct vxlan_rdst *rd_prev, *rd;
+
+ rd_prev = NULL;
+ for (rd = &f->remote; rd; rd = rd->remote_next) {
+ if (rd->remote_ip == ip &&
+ rd->remote_port == port &&
+ rd->remote_vni == vni &&
+ rd->remote_ifindex == ifindex)
+ return 0;
+ rd_prev = rd;
+ }
+ rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
+ if (rd == NULL)
+ return -ENOBUFS;
+ rd->remote_ip = ip;
+ rd->remote_port = port;
+ rd->remote_vni = vni;
+ rd->remote_ifindex = ifindex;
+ rd->remote_next = NULL;
+ rd_prev->remote_next = rd;
+ return 1;
+}
+
/* Add new entry to forwarding table -- assumes lock held */
static int vxlan_fdb_create(struct vxlan_dev *vxlan,
const u8 *mac, __be32 ip,
- __u16 state, __u16 flags)
+ __u16 state, __u16 flags,
+ __be16 port, __u32 vni, __u32 ifindex,
+ __u8 ndm_flags)
{
struct vxlan_fdb *f;
int notify = 0;
@@ -320,6 +365,19 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
f->updated = jiffies;
notify = 1;
}
+ if (f->flags != ndm_flags) {
+ f->flags = ndm_flags;
+ f->updated = jiffies;
+ notify = 1;
+ }
+ if ((flags & NLM_F_APPEND) &&
+ is_multicast_ether_addr(f->eth_addr)) {
+ int rc = vxlan_fdb_append(f, ip, port, vni, ifindex);
+
+ if (rc < 0)
+ return rc;
+ notify |= rc;
+ }
} else {
if (!(flags & NLM_F_CREATE))
return -ENOENT;
@@ -333,8 +391,13 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
return -ENOMEM;
notify = 1;
- f->remote_ip = ip;
+ f->remote.remote_ip = ip;
+ f->remote.remote_port = port;
+ f->remote.remote_vni = vni;
+ f->remote.remote_ifindex = ifindex;
+ f->remote.remote_next = NULL;
f->state = state;
+ f->flags = ndm_flags;
f->updated = f->used = jiffies;
memcpy(f->eth_addr, mac, ETH_ALEN);
@@ -349,6 +412,19 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
return 0;
}
+static void vxlan_fdb_free(struct rcu_head *head)
+{
+ struct vxlan_fdb *f = container_of(head, struct vxlan_fdb, rcu);
+
+ while (f->remote.remote_next) {
+ struct vxlan_rdst *rd = f->remote.remote_next;
+
+ f->remote.remote_next = rd->remote_next;
+ kfree(rd);
+ }
+ kfree(f);
+}
+
static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
{
netdev_dbg(vxlan->dev,
@@ -358,7 +434,7 @@ static void vxlan_fdb_destroy(struct vxlan_dev *vxlan, struct vxlan_fdb *f)
vxlan_fdb_notify(vxlan, f, RTM_DELNEIGH);
hlist_del_rcu(&f->hlist);
- kfree_rcu(f, rcu);
+ call_rcu(&f->rcu, vxlan_fdb_free);
}
/* Add static entry (via netlink) */
@@ -367,7 +443,10 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
const unsigned char *addr, u16 flags)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct net *net = dev_net(vxlan->dev);
__be32 ip;
+ __be16 port;
+ u32 vni, ifindex;
int err;
if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_REACHABLE))) {
@@ -384,8 +463,36 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
ip = nla_get_be32(tb[NDA_DST]);
+ if (tb[NDA_PORT]) {
+ if (nla_len(tb[NDA_PORT]) != sizeof(__be16))
+ return -EINVAL;
+ port = nla_get_be16(tb[NDA_PORT]);
+ } else
+ port = vxlan->dst_port;
+
+ if (tb[NDA_VNI]) {
+ if (nla_len(tb[NDA_VNI]) != sizeof(u32))
+ return -EINVAL;
+ vni = nla_get_u32(tb[NDA_VNI]);
+ } else
+ vni = vxlan->default_dst.remote_vni;
+
+ if (tb[NDA_IFINDEX]) {
+ struct net_device *tdev;
+
+ if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
+ return -EINVAL;
+ ifindex = nla_get_u32(tb[NDA_IFINDEX]);
+ tdev = dev_get_by_index(net, ifindex);
+ if (!tdev)
+ return -EADDRNOTAVAIL;
+ dev_put(tdev);
+ } else
+ ifindex = 0;
+
spin_lock_bh(&vxlan->hash_lock);
- err = vxlan_fdb_create(vxlan, addr, ip, ndm->ndm_state, flags);
+ err = vxlan_fdb_create(vxlan, addr, ip, ndm->ndm_state, flags,
+ port, vni, ifindex, ndm->ndm_flags);
spin_unlock_bh(&vxlan->hash_lock);
return err;
@@ -423,18 +530,21 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
int err;
hlist_for_each_entry_rcu(f, &vxlan->fdb_head[h], hlist) {
- if (idx < cb->args[0])
- goto skip;
-
- err = vxlan_fdb_info(skb, vxlan, f,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- RTM_NEWNEIGH,
- NLM_F_MULTI);
- if (err < 0)
- break;
+ struct vxlan_rdst *rd;
+ for (rd = &f->remote; rd; rd = rd->remote_next) {
+ if (idx < cb->args[0])
+ goto skip;
+
+ err = vxlan_fdb_info(skb, vxlan, f,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNEIGH,
+ NLM_F_MULTI, rd);
+ if (err < 0)
+ break;
skip:
- ++idx;
+ ++idx;
+ }
}
}
@@ -454,22 +564,25 @@ static void vxlan_snoop(struct net_device *dev,
f = vxlan_find_mac(vxlan, src_mac);
if (likely(f)) {
f->used = jiffies;
- if (likely(f->remote_ip == src_ip))
+ if (likely(f->remote.remote_ip == src_ip))
return;
if (net_ratelimit())
netdev_info(dev,
"%pM migrated from %pI4 to %pI4\n",
- src_mac, &f->remote_ip, &src_ip);
+ src_mac, &f->remote.remote_ip, &src_ip);
- f->remote_ip = src_ip;
+ f->remote.remote_ip = src_ip;
f->updated = jiffies;
} else {
/* learned new entry */
spin_lock(&vxlan->hash_lock);
err = vxlan_fdb_create(vxlan, src_mac, src_ip,
NUD_REACHABLE,
- NLM_F_EXCL|NLM_F_CREATE);
+ NLM_F_EXCL|NLM_F_CREATE,
+ vxlan->dst_port,
+ vxlan->default_dst.remote_vni,
+ 0, NTF_SELF);
spin_unlock(&vxlan->hash_lock);
}
}
@@ -490,7 +603,7 @@ static bool vxlan_group_used(struct vxlan_net *vn,
if (!netif_running(vxlan->dev))
continue;
- if (vxlan->gaddr == this->gaddr)
+ if (vxlan->default_dst.remote_ip == this->default_dst.remote_ip)
return true;
}
@@ -504,8 +617,8 @@ static int vxlan_join_group(struct net_device *dev)
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
struct sock *sk = vn->sock->sk;
struct ip_mreqn mreq = {
- .imr_multiaddr.s_addr = vxlan->gaddr,
- .imr_ifindex = vxlan->link,
+ .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
+ .imr_ifindex = vxlan->default_dst.remote_ifindex,
};
int err;
@@ -532,8 +645,8 @@ static int vxlan_leave_group(struct net_device *dev)
int err = 0;
struct sock *sk = vn->sock->sk;
struct ip_mreqn mreq = {
- .imr_multiaddr.s_addr = vxlan->gaddr,
- .imr_ifindex = vxlan->link,
+ .imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
+ .imr_ifindex = vxlan->default_dst.remote_ifindex,
};
/* Only leave group when last vxlan is done. */
@@ -556,7 +669,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct iphdr *oip;
struct vxlanhdr *vxh;
struct vxlan_dev *vxlan;
- struct vxlan_stats *stats;
+ struct pcpu_tstats *stats;
__u32 vni;
int err;
@@ -632,7 +745,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
}
}
- stats = this_cpu_ptr(vxlan->stats);
+ stats = this_cpu_ptr(vxlan->dev->tstats);
u64_stats_update_begin(&stats->syncp);
stats->rx_packets++;
stats->rx_bytes += skb->len;
@@ -691,7 +804,6 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
n = neigh_lookup(&arp_tbl, &tip, dev);
if (n) {
- struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
struct sk_buff *reply;
@@ -701,7 +813,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
}
f = vxlan_find_mac(vxlan, n->ha);
- if (f && f->remote_ip == 0) {
+ if (f && f->remote.remote_ip == htonl(INADDR_ANY)) {
/* bridge-local neighbor */
neigh_release(n);
goto out;
@@ -763,28 +875,6 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
return false;
}
-/* Extract dsfield from inner protocol */
-static inline u8 vxlan_get_dsfield(const struct iphdr *iph,
- const struct sk_buff *skb)
-{
- if (skb->protocol == htons(ETH_P_IP))
- return iph->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- return ipv6_get_dsfield((const struct ipv6hdr *)iph);
- else
- return 0;
-}
-
-/* Propogate ECN bits out */
-static inline u8 vxlan_ecn_encap(u8 tos,
- const struct iphdr *iph,
- const struct sk_buff *skb)
-{
- u8 inner = vxlan_get_dsfield(iph, skb);
-
- return INET_ECN_encapsulate(tos, inner);
-}
-
static void vxlan_sock_free(struct sk_buff *skb)
{
sock_put(skb->sk);
@@ -807,7 +897,7 @@ static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
* better and maybe available from hardware
* secondary choice is to use jhash on the Ethernet header
*/
-static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
+static __be16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
{
unsigned int range = (vxlan->port_max - vxlan->port_min) + 1;
u32 hash;
@@ -817,71 +907,78 @@ static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
hash = jhash(skb->data, 2 * ETH_ALEN,
(__force u32) skb->protocol);
- return (((u64) hash * range) >> 32) + vxlan->port_min;
+ return htons((((u64) hash * range) >> 32) + vxlan->port_min);
}
-/* Transmit local packets over Vxlan
- *
- * Outer IP header inherits ECN and DF from inner header.
- * Outer UDP destination is the VXLAN assigned port.
- * source port is based on hash of flow
- */
-static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
+static int handle_offloads(struct sk_buff *skb)
+{
+ if (skb_is_gso(skb)) {
+ int err = skb_unclone(skb, GFP_ATOMIC);
+ if (unlikely(err))
+ return err;
+
+ skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL;
+ } else if (skb->ip_summed != CHECKSUM_PARTIAL)
+ skb->ip_summed = CHECKSUM_NONE;
+
+ return 0;
+}
+
+/* Bypass encapsulation if the destination is local */
+static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
+ struct vxlan_dev *dst_vxlan)
+{
+ struct pcpu_tstats *tx_stats = this_cpu_ptr(src_vxlan->dev->tstats);
+ struct pcpu_tstats *rx_stats = this_cpu_ptr(dst_vxlan->dev->tstats);
+
+ skb->pkt_type = PACKET_HOST;
+ skb->encapsulation = 0;
+ skb->dev = dst_vxlan->dev;
+ __skb_pull(skb, skb_network_offset(skb));
+
+ if (dst_vxlan->flags & VXLAN_F_LEARN)
+ vxlan_snoop(skb->dev, htonl(INADDR_LOOPBACK),
+ eth_hdr(skb)->h_source);
+
+ u64_stats_update_begin(&tx_stats->syncp);
+ tx_stats->tx_packets++;
+ tx_stats->tx_bytes += skb->len;
+ u64_stats_update_end(&tx_stats->syncp);
+
+ if (netif_rx(skb) == NET_RX_SUCCESS) {
+ u64_stats_update_begin(&rx_stats->syncp);
+ rx_stats->rx_packets++;
+ rx_stats->rx_bytes += skb->len;
+ u64_stats_update_end(&rx_stats->syncp);
+ } else {
+ skb->dev->stats.rx_dropped++;
+ }
+}
+
+static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
+ struct vxlan_rdst *rdst, bool did_rsc)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct rtable *rt;
const struct iphdr *old_iph;
- struct ethhdr *eth;
struct iphdr *iph;
struct vxlanhdr *vxh;
struct udphdr *uh;
struct flowi4 fl4;
- unsigned int pkt_len = skb->len;
__be32 dst;
- __u16 src_port;
+ __be16 src_port, dst_port;
+ u32 vni;
__be16 df = 0;
__u8 tos, ttl;
- int err;
- bool did_rsc = false;
- const struct vxlan_fdb *f;
-
- skb_reset_mac_header(skb);
- eth = eth_hdr(skb);
- if ((vxlan->flags & VXLAN_F_PROXY) && ntohs(eth->h_proto) == ETH_P_ARP)
- return arp_reduce(dev, skb);
- else if ((vxlan->flags&VXLAN_F_RSC) && ntohs(eth->h_proto) == ETH_P_IP)
- did_rsc = route_shortcircuit(dev, skb);
-
- f = vxlan_find_mac(vxlan, eth->h_dest);
- if (f == NULL) {
- did_rsc = false;
- dst = vxlan->gaddr;
- if (!dst && (vxlan->flags & VXLAN_F_L2MISS) &&
- !is_multicast_ether_addr(eth->h_dest))
- vxlan_fdb_miss(vxlan, eth->h_dest);
- } else
- dst = f->remote_ip;
+ dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port;
+ vni = rdst->remote_vni;
+ dst = rdst->remote_ip;
if (!dst) {
if (did_rsc) {
- __skb_pull(skb, skb_network_offset(skb));
- skb->ip_summed = CHECKSUM_NONE;
- skb->pkt_type = PACKET_HOST;
-
/* short-circuited back to local bridge */
- if (netif_rx(skb) == NET_RX_SUCCESS) {
- struct vxlan_stats *stats =
- this_cpu_ptr(vxlan->stats);
-
- u64_stats_update_begin(&stats->syncp);
- stats->tx_packets++;
- stats->tx_bytes += pkt_len;
- u64_stats_update_end(&stats->syncp);
- } else {
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
- }
+ vxlan_encap_bypass(skb, vxlan, vxlan);
return NETDEV_TX_OK;
}
goto drop;
@@ -904,12 +1001,12 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
tos = vxlan->tos;
if (tos == 1)
- tos = vxlan_get_dsfield(old_iph, skb);
+ tos = ip_tunnel_get_dsfield(old_iph, skb);
src_port = vxlan_src_port(vxlan, skb);
memset(&fl4, 0, sizeof(fl4));
- fl4.flowi4_oif = vxlan->link;
+ fl4.flowi4_oif = rdst->remote_ifindex;
fl4.flowi4_tos = RT_TOS(tos);
fl4.daddr = dst;
fl4.saddr = vxlan->saddr;
@@ -928,6 +1025,19 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_error;
}
+ /* Bypass encapsulation if the destination is local */
+ if (rt->rt_flags & RTCF_LOCAL &&
+ !(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) {
+ struct vxlan_dev *dst_vxlan;
+
+ ip_rt_put(rt);
+ dst_vxlan = vxlan_find_vni(dev_net(dev), vni);
+ if (!dst_vxlan)
+ goto tx_error;
+ vxlan_encap_bypass(skb, vxlan, dst_vxlan);
+ return NETDEV_TX_OK;
+ }
+
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
IPSKB_REROUTED);
@@ -936,14 +1046,14 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
vxh->vx_flags = htonl(VXLAN_FLAGS);
- vxh->vx_vni = htonl(vxlan->vni << 8);
+ vxh->vx_vni = htonl(vni << 8);
__skb_push(skb, sizeof(*uh));
skb_reset_transport_header(skb);
uh = udp_hdr(skb);
- uh->dest = htons(vxlan_port);
- uh->source = htons(src_port);
+ uh->dest = dst_port;
+ uh->source = src_port;
uh->len = htons(skb->len);
uh->check = 0;
@@ -955,7 +1065,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
iph->ihl = sizeof(struct iphdr) >> 2;
iph->frag_off = df;
iph->protocol = IPPROTO_UDP;
- iph->tos = vxlan_ecn_encap(tos, old_iph, skb);
+ iph->tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
iph->daddr = dst;
iph->saddr = fl4.saddr;
iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
@@ -965,22 +1075,10 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
vxlan_set_owner(dev, skb);
- /* See iptunnel_xmit() */
- if (skb->ip_summed != CHECKSUM_PARTIAL)
- skb->ip_summed = CHECKSUM_NONE;
-
- err = ip_local_out(skb);
- if (likely(net_xmit_eval(err) == 0)) {
- struct vxlan_stats *stats = this_cpu_ptr(vxlan->stats);
+ if (handle_offloads(skb))
+ goto drop;
- u64_stats_update_begin(&stats->syncp);
- stats->tx_packets++;
- stats->tx_bytes += pkt_len;
- u64_stats_update_end(&stats->syncp);
- } else {
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
- }
+ iptunnel_xmit(skb, dev);
return NETDEV_TX_OK;
drop:
@@ -994,6 +1092,65 @@ tx_free:
return NETDEV_TX_OK;
}
+/* Transmit local packets over Vxlan
+ *
+ * Outer IP header inherits ECN and DF from inner header.
+ * Outer UDP destination is the VXLAN assigned port.
+ * source port is based on hash of flow
+ */
+static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct ethhdr *eth;
+ bool did_rsc = false;
+ struct vxlan_rdst *rdst0, *rdst;
+ struct vxlan_fdb *f;
+ int rc1, rc;
+
+ skb_reset_mac_header(skb);
+ eth = eth_hdr(skb);
+
+ if ((vxlan->flags & VXLAN_F_PROXY) && ntohs(eth->h_proto) == ETH_P_ARP)
+ return arp_reduce(dev, skb);
+
+ f = vxlan_find_mac(vxlan, eth->h_dest);
+ did_rsc = false;
+
+ if (f && (f->flags & NTF_ROUTER) && (vxlan->flags & VXLAN_F_RSC) &&
+ ntohs(eth->h_proto) == ETH_P_IP) {
+ did_rsc = route_shortcircuit(dev, skb);
+ if (did_rsc)
+ f = vxlan_find_mac(vxlan, eth->h_dest);
+ }
+
+ if (f == NULL) {
+ rdst0 = &vxlan->default_dst;
+
+ if (rdst0->remote_ip == htonl(INADDR_ANY) &&
+ (vxlan->flags & VXLAN_F_L2MISS) &&
+ !is_multicast_ether_addr(eth->h_dest))
+ vxlan_fdb_miss(vxlan, eth->h_dest);
+ } else
+ rdst0 = &f->remote;
+
+ rc = NETDEV_TX_OK;
+
+ /* if there are multiple destinations, send copies */
+ for (rdst = rdst0->remote_next; rdst; rdst = rdst->remote_next) {
+ struct sk_buff *skb1;
+
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+ rc1 = vxlan_xmit_one(skb1, dev, rdst, did_rsc);
+ if (rc == NETDEV_TX_OK)
+ rc = rc1;
+ }
+
+ rc1 = vxlan_xmit_one(skb, dev, rdst0, did_rsc);
+ if (rc == NETDEV_TX_OK)
+ rc = rc1;
+ return rc;
+}
+
/* Walk the forwarding table and purge stale entries */
static void vxlan_cleanup(unsigned long arg)
{
@@ -1034,10 +1191,8 @@ static void vxlan_cleanup(unsigned long arg)
/* Setup stats when device is created */
static int vxlan_init(struct net_device *dev)
{
- struct vxlan_dev *vxlan = netdev_priv(dev);
-
- vxlan->stats = alloc_percpu(struct vxlan_stats);
- if (!vxlan->stats)
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
return -ENOMEM;
return 0;
@@ -1049,7 +1204,7 @@ static int vxlan_open(struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
int err;
- if (vxlan->gaddr) {
+ if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
err = vxlan_join_group(dev);
if (err)
return err;
@@ -1083,7 +1238,7 @@ static int vxlan_stop(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- if (vxlan->gaddr)
+ if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)))
vxlan_leave_group(dev);
del_timer_sync(&vxlan->age_timer);
@@ -1093,49 +1248,6 @@ static int vxlan_stop(struct net_device *dev)
return 0;
}
-/* Merge per-cpu statistics */
-static struct rtnl_link_stats64 *vxlan_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
-{
- struct vxlan_dev *vxlan = netdev_priv(dev);
- struct vxlan_stats tmp, sum = { 0 };
- unsigned int cpu;
-
- for_each_possible_cpu(cpu) {
- unsigned int start;
- const struct vxlan_stats *stats
- = per_cpu_ptr(vxlan->stats, cpu);
-
- do {
- start = u64_stats_fetch_begin_bh(&stats->syncp);
- memcpy(&tmp, stats, sizeof(tmp));
- } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
-
- sum.tx_bytes += tmp.tx_bytes;
- sum.tx_packets += tmp.tx_packets;
- sum.rx_bytes += tmp.rx_bytes;
- sum.rx_packets += tmp.rx_packets;
- }
-
- stats->tx_bytes = sum.tx_bytes;
- stats->tx_packets = sum.tx_packets;
- stats->rx_bytes = sum.rx_bytes;
- stats->rx_packets = sum.rx_packets;
-
- stats->multicast = dev->stats.multicast;
- stats->rx_length_errors = dev->stats.rx_length_errors;
- stats->rx_frame_errors = dev->stats.rx_frame_errors;
- stats->rx_errors = dev->stats.rx_errors;
-
- stats->tx_dropped = dev->stats.tx_dropped;
- stats->tx_carrier_errors = dev->stats.tx_carrier_errors;
- stats->tx_aborted_errors = dev->stats.tx_aborted_errors;
- stats->collisions = dev->stats.collisions;
- stats->tx_errors = dev->stats.tx_errors;
-
- return stats;
-}
-
/* Stub, nothing needs to be done. */
static void vxlan_set_multicast_list(struct net_device *dev)
{
@@ -1146,7 +1258,7 @@ static const struct net_device_ops vxlan_netdev_ops = {
.ndo_open = vxlan_open,
.ndo_stop = vxlan_stop,
.ndo_start_xmit = vxlan_xmit,
- .ndo_get_stats64 = vxlan_stats64,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_set_rx_mode = vxlan_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -1163,9 +1275,7 @@ static struct device_type vxlan_type = {
static void vxlan_free(struct net_device *dev)
{
- struct vxlan_dev *vxlan = netdev_priv(dev);
-
- free_percpu(vxlan->stats);
+ free_percpu(dev->tstats);
free_netdev(dev);
}
@@ -1189,8 +1299,10 @@ static void vxlan_setup(struct net_device *dev)
dev->features |= NETIF_F_NETNS_LOCAL;
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
dev->features |= NETIF_F_RXCSUM;
+ dev->features |= NETIF_F_GSO_SOFTWARE;
dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
@@ -1203,6 +1315,7 @@ static void vxlan_setup(struct net_device *dev)
inet_get_local_port_range(&low, &high);
vxlan->port_min = low;
vxlan->port_max = high;
+ vxlan->dst_port = htons(vxlan_port);
vxlan->dev = dev;
@@ -1225,6 +1338,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_RSC] = { .type = NLA_U8 },
[IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
};
static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -1250,14 +1364,6 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
return -ERANGE;
}
- if (data[IFLA_VXLAN_GROUP]) {
- __be32 gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
- if (!IN_MULTICAST(ntohl(gaddr))) {
- pr_debug("group address is not IPv4 multicast\n");
- return -EADDRNOTAVAIL;
- }
- }
-
if (data[IFLA_VXLAN_PORT_RANGE]) {
const struct ifla_vxlan_port_range *p
= nla_data(data[IFLA_VXLAN_PORT_RANGE]);
@@ -1288,6 +1394,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_rdst *dst = &vxlan->default_dst;
__u32 vni;
int err;
@@ -1299,21 +1406,21 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
pr_info("duplicate VNI %u\n", vni);
return -EEXIST;
}
- vxlan->vni = vni;
+ dst->remote_vni = vni;
if (data[IFLA_VXLAN_GROUP])
- vxlan->gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
+ dst->remote_ip = nla_get_be32(data[IFLA_VXLAN_GROUP]);
if (data[IFLA_VXLAN_LOCAL])
vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]);
if (data[IFLA_VXLAN_LINK] &&
- (vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
+ (dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
struct net_device *lowerdev
- = __dev_get_by_index(net, vxlan->link);
+ = __dev_get_by_index(net, dst->remote_ifindex);
if (!lowerdev) {
- pr_info("ifindex %d does not exist\n", vxlan->link);
+ pr_info("ifindex %d does not exist\n", dst->remote_ifindex);
return -ENODEV;
}
@@ -1361,11 +1468,14 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
vxlan->port_max = ntohs(p->high);
}
+ if (data[IFLA_VXLAN_PORT])
+ vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]);
+
SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops);
err = register_netdevice(dev);
if (!err)
- hlist_add_head_rcu(&vxlan->hlist, vni_head(net, vxlan->vni));
+ hlist_add_head_rcu(&vxlan->hlist, vni_head(net, dst->remote_vni));
return err;
}
@@ -1396,24 +1506,26 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */
nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */
nla_total_size(sizeof(struct ifla_vxlan_port_range)) +
+ nla_total_size(sizeof(__be16))+ /* IFLA_VXLAN_PORT */
0;
}
static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
{
const struct vxlan_dev *vxlan = netdev_priv(dev);
+ const struct vxlan_rdst *dst = &vxlan->default_dst;
struct ifla_vxlan_port_range ports = {
.low = htons(vxlan->port_min),
.high = htons(vxlan->port_max),
};
- if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni))
+ if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni))
goto nla_put_failure;
- if (vxlan->gaddr && nla_put_be32(skb, IFLA_VXLAN_GROUP, vxlan->gaddr))
+ if (dst->remote_ip && nla_put_be32(skb, IFLA_VXLAN_GROUP, dst->remote_ip))
goto nla_put_failure;
- if (vxlan->link && nla_put_u32(skb, IFLA_VXLAN_LINK, vxlan->link))
+ if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex))
goto nla_put_failure;
if (vxlan->saddr && nla_put_be32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
@@ -1431,7 +1543,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_VXLAN_L3MISS,
!!(vxlan->flags & VXLAN_F_L3MISS)) ||
nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) ||
- nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax))
+ nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) ||
+ nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port))
goto nla_put_failure;
if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
@@ -1555,10 +1668,11 @@ static void __exit vxlan_cleanup_module(void)
{
rtnl_link_unregister(&vxlan_link_ops);
unregister_pernet_device(&vxlan_net_ops);
+ rcu_barrier();
}
module_exit(vxlan_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_VERSION(VXLAN_VERSION);
-MODULE_AUTHOR("Stephen Hemminger <shemminger@vyatta.com>");
+MODULE_AUTHOR("Stephen Hemminger <stephen@networkplumber.org>");
MODULE_ALIAS_RTNL_LINK("vxlan");
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 3d339e04efb7..f9a24e599dee 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1293,7 +1293,8 @@ static int adm8211_config(struct ieee80211_hw *dev, u32 changed)
{
struct adm8211_priv *priv = dev->priv;
struct ieee80211_conf *conf = &dev->conf;
- int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int channel =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
if (channel != priv->channel) {
priv->channel = channel;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index 956024a636e6..14128fd265ac 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -180,16 +180,7 @@ static struct pcmcia_driver airo_driver = {
.suspend = airo_suspend,
.resume = airo_resume,
};
-
-static int __init airo_cs_init(void)
-{
- return pcmcia_register_driver(&airo_driver);
-}
-
-static void __exit airo_cs_cleanup(void)
-{
- pcmcia_unregister_driver(&airo_driver);
-}
+module_pcmcia_driver(airo_driver);
/*
This program is free software; you can redistribute it and/or
@@ -229,6 +220,3 @@ static void __exit airo_cs_cleanup(void)
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
-
-module_init(airo_cs_init);
-module_exit(airo_cs_cleanup);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 5ac5f7ae2721..34c8a33cac06 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1943,12 +1943,12 @@ static int at76_config(struct ieee80211_hw *hw, u32 changed)
struct at76_priv *priv = hw->priv;
at76_dbg(DBG_MAC80211, "%s(): channel %d",
- __func__, hw->conf.channel->hw_value);
+ __func__, hw->conf.chandef.chan->hw_value);
at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
mutex_lock(&priv->mtx);
- priv->channel = hw->conf.channel->hw_value;
+ priv->channel = hw->conf.chandef.chan->hw_value;
if (is_valid_ether_addr(priv->bssid))
at76_join(priv);
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 7157f7d311c5..17d7fece35d2 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -457,14 +457,14 @@ static int ar5523_set_chan(struct ar5523 *ar)
memset(&reset, 0, sizeof(reset));
reset.flags |= cpu_to_be32(UATH_CHAN_2GHZ);
reset.flags |= cpu_to_be32(UATH_CHAN_OFDM);
- reset.freq = cpu_to_be32(conf->channel->center_freq);
+ reset.freq = cpu_to_be32(conf->chandef.chan->center_freq);
reset.maxrdpower = cpu_to_be32(50); /* XXX */
reset.channelchange = cpu_to_be32(1);
reset.keeprccontent = cpu_to_be32(0);
ar5523_dbg(ar, "set chan flags 0x%x freq %d\n",
be32_to_cpu(reset.flags),
- conf->channel->center_freq);
+ conf->chandef.chan->center_freq);
return ar5523_cmd_write(ar, WDCMSG_RESET, &reset, sizeof(reset), 0);
}
@@ -594,7 +594,7 @@ static void ar5523_data_rx_cb(struct urb *urb)
rx_status = IEEE80211_SKB_RXCB(data->skb);
memset(rx_status, 0, sizeof(*rx_status));
rx_status->freq = be32_to_cpu(desc->channel);
- rx_status->band = hw->conf.channel->band;
+ rx_status->band = hw->conf.chandef.chan->band;
rx_status->signal = -95 + be32_to_cpu(desc->rssi);
ieee80211_rx_irqsafe(hw, data->skb);
@@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
-static void ar5523_flush(struct ieee80211_hw *hw, bool drop)
+static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ar5523 *ar = hw->priv;
@@ -1153,13 +1153,13 @@ static int ar5523_get_wlan_mode(struct ar5523 *ar,
struct ieee80211_sta *sta;
u32 sta_rate_set;
- band = ar->hw->wiphy->bands[ar->hw->conf.channel->band];
+ band = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band];
sta = ieee80211_find_sta(ar->vif, bss_conf->bssid);
if (!sta) {
ar5523_info(ar, "STA not found!\n");
return WLAN_MODE_11b;
}
- sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
+ sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
if (sta_rate_set & 1) {
@@ -1197,11 +1197,11 @@ static void ar5523_create_rateset(struct ar5523 *ar,
ar5523_info(ar, "STA not found. Cannot set rates\n");
sta_rate_set = bss_conf->basic_rates;
} else
- sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
+ sta_rate_set = sta->supp_rates[ar->hw->conf.chandef.chan->band];
ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set);
- band = ar->hw->wiphy->bands[ar->hw->conf.channel->band];
+ band = ar->hw->wiphy->bands[ar->hw->conf.chandef.chan->band];
for (bit = 0; bit < band->n_bitrates; bit++) {
BUG_ON(i >= AR5523_MAX_NRATES);
ar5523_dbg(ar, "Considering rate %d : %d\n",
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index f60b3899afc4..1b3a34f7f224 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -10,6 +10,7 @@ ath5k-y += phy.o
ath5k-y += reset.o
ath5k-y += attach.o
ath5k-y += base.o
+CFLAGS_base.o += -I$(src)
ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 3150def17193..2d691b8b95b9 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1523,7 +1523,8 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah);
void ath5k_eeprom_detach(struct ath5k_hw *ah);
-
+int ath5k_eeprom_mode_from_channel(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel);
/* Protocol Control Unit Functions */
/* Helpers */
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 1d264c0f5a9b..9b20d9ee2719 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2639,7 +2639,7 @@ int ath5k_start(struct ieee80211_hw *hw)
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
- ah->curchan = ah->hw->conf.channel;
+ ah->curchan = ah->hw->conf.chandef.chan;
ah->imask = AR5K_INT_RXOK
| AR5K_INT_RXERR
| AR5K_INT_RXEOL
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index b7e0258887e7..94d34ee02265 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -1779,7 +1779,8 @@ ath5k_eeprom_detach(struct ath5k_hw *ah)
}
int
-ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
+ath5k_eeprom_mode_from_channel(struct ath5k_hw *ah,
+ struct ieee80211_channel *channel)
{
switch (channel->hw_value) {
case AR5K_MODE_11A:
@@ -1789,6 +1790,7 @@ ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel)
case AR5K_MODE_11B:
return AR5K_EEPROM_MODE_11B;
default:
- return -1;
+ ATH5K_WARN(ah, "channel is not A/B/G!");
+ return AR5K_EEPROM_MODE_11A;
}
}
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h
index 94a9bbea6874..693296ee9693 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath/ath5k/eeprom.h
@@ -493,6 +493,3 @@ struct ath5k_eeprom_info {
/* Antenna raw switch tables */
u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
-
-int
-ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 4264341533ea..06f86f435711 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -202,7 +202,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ah->lock);
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = ath5k_chan_set(ah, conf->channel);
+ ret = ath5k_chan_set(ah, conf->chandef.chan);
if (ret < 0)
goto unlock;
}
@@ -678,7 +678,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
memcpy(survey, &ah->survey, sizeof(*survey));
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->noise = ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a78afa98c650..d6bc7cb61bfb 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1612,11 +1612,7 @@ ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
ah->ah_cal_mask |= AR5K_CALIBRATION_NF;
- ee_mode = ath5k_eeprom_mode_from_channel(ah->ah_current_channel);
- if (WARN_ON(ee_mode < 0)) {
- ah->ah_cal_mask &= ~AR5K_CALIBRATION_NF;
- return;
- }
+ ee_mode = ath5k_eeprom_mode_from_channel(ah, ah->ah_current_channel);
/* completed NF calibration, test threshold */
nf = ath5k_hw_read_measured_noise_floor(ah);
@@ -2317,12 +2313,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
def_ant = ah->ah_def_ant;
- ee_mode = ath5k_eeprom_mode_from_channel(channel);
- if (ee_mode < 0) {
- ATH5K_ERR(ah,
- "invalid channel: %d\n", channel->center_freq);
- return;
- }
+ ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
switch (ant_mode) {
case AR5K_ANTMODE_DEFAULT:
@@ -3622,12 +3613,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
return -EINVAL;
}
- ee_mode = ath5k_eeprom_mode_from_channel(channel);
- if (ee_mode < 0) {
- ATH5K_ERR(ah,
- "invalid channel: %d\n", channel->center_freq);
- return -EINVAL;
- }
+ ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
/* Initialize TX power table */
switch (ah->ah_radio) {
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index e2d8b2cf19eb..a3399c4f13a9 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -984,9 +984,7 @@ ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
if (ah->ah_version == AR5K_AR5210)
return;
- ee_mode = ath5k_eeprom_mode_from_channel(channel);
- if (WARN_ON(ee_mode < 0))
- return;
+ ee_mode = ath5k_eeprom_mode_from_channel(ah, channel);
/* Adjust power delta for channel 14 */
if (channel->center_freq == 2484)
diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h
index 00f015819344..c6eef519bb61 100644
--- a/drivers/net/wireless/ath/ath5k/trace.h
+++ b/drivers/net/wireless/ath/ath5k/trace.h
@@ -97,7 +97,7 @@ TRACE_EVENT(ath5k_tx_complete,
#if defined(CONFIG_ATH5K_TRACER) && !defined(__CHECKER__)
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH ../../drivers/net/wireless/ath/ath5k
+#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig
index 630c83db056e..e39e5860a2e9 100644
--- a/drivers/net/wireless/ath/ath6kl/Kconfig
+++ b/drivers/net/wireless/ath/ath6kl/Kconfig
@@ -30,6 +30,15 @@ config ATH6KL_DEBUG
---help---
Enables debug support
+config ATH6KL_TRACING
+ bool "Atheros ath6kl tracing support"
+ depends on ATH6KL
+ depends on EVENT_TRACING
+ ---help---
+ Select this to ath6kl use tracing infrastructure.
+
+ If unsure, say Y to make it easier to debug problems.
+
config ATH6KL_REGDOMAIN
bool "Atheros ath6kl regdomain support"
depends on ATH6KL
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
index cab0ec0d5380..dc2b3b46781e 100644
--- a/drivers/net/wireless/ath/ath6kl/Makefile
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -35,10 +35,15 @@ ath6kl_core-y += txrx.o
ath6kl_core-y += wmi.o
ath6kl_core-y += core.o
ath6kl_core-y += recovery.o
+
ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
+ath6kl_core-$(CONFIG_ATH6KL_TRACING) += trace.o
obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
ath6kl_sdio-y += sdio.o
obj-$(CONFIG_ATH6KL_USB) += ath6kl_usb.o
ath6kl_usb-y += usb.o
+
+# for tracing framework to find trace.h
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 752ffc4f4166..5c9736a94e54 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -402,7 +402,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
if (type == NL80211_IFTYPE_STATION ||
type == NL80211_IFTYPE_AP || type == NL80211_IFTYPE_ADHOC) {
for (i = 0; i < ar->vif_max; i++) {
- if ((ar->avail_idx_map >> i) & BIT(0)) {
+ if ((ar->avail_idx_map) & BIT(i)) {
*if_idx = i;
return true;
}
@@ -412,7 +412,7 @@ static bool ath6kl_is_valid_iftype(struct ath6kl *ar, enum nl80211_iftype type,
if (type == NL80211_IFTYPE_P2P_CLIENT ||
type == NL80211_IFTYPE_P2P_GO) {
for (i = ar->max_norm_iface; i < ar->vif_max; i++) {
- if ((ar->avail_idx_map >> i) & BIT(0)) {
+ if ((ar->avail_idx_map) & BIT(i)) {
*if_idx = i;
return true;
}
@@ -1535,7 +1535,9 @@ static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy,
ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
+ rtnl_lock();
ath6kl_cfg80211_vif_cleanup(vif);
+ rtnl_unlock();
return 0;
}
@@ -2990,13 +2992,15 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
{
struct ath6kl *ar = ath6kl_priv(dev);
struct ath6kl_vif *vif = netdev_priv(dev);
+ int err;
if (vif->nw_type != AP_NETWORK)
return -EOPNOTSUPP;
- /* Use this only for authorizing/unauthorizing a station */
- if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
- return -EOPNOTSUPP;
+ err = cfg80211_check_station_change(wiphy, params,
+ CFG80211_STA_AP_MLME_CLIENT);
+ if (err)
+ return err;
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx,
@@ -3659,7 +3663,6 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
vif->sme_state = SME_DISCONNECTED;
set_bit(WLAN_ENABLED, &vif->flags);
ar->wlan_pwr_state = WLAN_POWER_STATE_ON;
- set_bit(NETDEV_REGISTERED, &vif->flags);
if (type == NL80211_IFTYPE_ADHOC)
ar->ibss_if_active = true;
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 61b2f98b4e77..26b0f92424e1 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -560,7 +560,6 @@ enum ath6kl_vif_state {
WMM_ENABLED,
NETQ_STOPPED,
DTIM_EXPIRED,
- NETDEV_REGISTERED,
CLEAR_BSSFILTER_ON_BEACON,
DTIM_PERIOD_AVAIL,
WLAN_ENABLED,
@@ -936,8 +935,6 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no,
u8 win_sz);
void ath6kl_wakeup_event(void *dev);
-void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
- bool wait_fot_compltn, bool cold_reset);
void ath6kl_init_control_info(struct ath6kl_vif *vif);
struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready);
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 15cfe30e54fd..fe38b836cb26 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -56,6 +56,60 @@ int ath6kl_printk(const char *level, const char *fmt, ...)
}
EXPORT_SYMBOL(ath6kl_printk);
+int ath6kl_info(const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ ret = ath6kl_printk(KERN_INFO, "%pV", &vaf);
+ trace_ath6kl_log_info(&vaf);
+ va_end(args);
+
+ return ret;
+}
+EXPORT_SYMBOL(ath6kl_info);
+
+int ath6kl_err(const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ ret = ath6kl_printk(KERN_ERR, "%pV", &vaf);
+ trace_ath6kl_log_err(&vaf);
+ va_end(args);
+
+ return ret;
+}
+EXPORT_SYMBOL(ath6kl_err);
+
+int ath6kl_warn(const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf);
+ trace_ath6kl_log_warn(&vaf);
+ va_end(args);
+
+ return ret;
+}
+EXPORT_SYMBOL(ath6kl_warn);
+
#ifdef CONFIG_ATH6KL_DEBUG
void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
@@ -63,15 +117,15 @@ void ath6kl_dbg(enum ATH6K_DEBUG_MASK mask, const char *fmt, ...)
struct va_format vaf;
va_list args;
- if (!(debug_mask & mask))
- return;
-
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
+ if (debug_mask & mask)
+ ath6kl_printk(KERN_DEBUG, "%pV", &vaf);
+
+ trace_ath6kl_log_dbg(mask, &vaf);
va_end(args);
}
@@ -87,6 +141,10 @@ void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
}
+
+ /* tracing code doesn't like null strings :/ */
+ trace_ath6kl_log_dbg_dump(msg ? msg : "", prefix ? prefix : "",
+ buf, len);
}
EXPORT_SYMBOL(ath6kl_dbg_dump);
@@ -1752,8 +1810,10 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar,
&fops_tgt_stats);
- debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar,
- &fops_credit_dist_stats);
+ if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO)
+ debugfs_create_file("credit_dist_stats", S_IRUSR,
+ ar->debugfs_phy, ar,
+ &fops_credit_dist_stats);
debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR,
ar->debugfs_phy, ar, &fops_endpoint_stats);
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index f97cd4ead543..74369de00fb5 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -19,6 +19,7 @@
#define DEBUG_H
#include "hif.h"
+#include "trace.h"
enum ATH6K_DEBUG_MASK {
ATH6KL_DBG_CREDIT = BIT(0),
@@ -51,13 +52,9 @@ enum ATH6K_DEBUG_MASK {
extern unsigned int debug_mask;
extern __printf(2, 3)
int ath6kl_printk(const char *level, const char *fmt, ...);
-
-#define ath6kl_info(fmt, ...) \
- ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__)
-#define ath6kl_err(fmt, ...) \
- ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__)
-#define ath6kl_warn(fmt, ...) \
- ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__)
+extern __printf(1, 2) int ath6kl_info(const char *fmt, ...);
+extern __printf(1, 2) int ath6kl_err(const char *fmt, ...);
+extern __printf(1, 2) int ath6kl_warn(const char *fmt, ...);
enum ath6kl_war {
ATH6KL_WAR_INVALID_RATE,
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c
index a6b614421fa4..fea7709b5dda 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.c
+++ b/drivers/net/wireless/ath/ath6kl/hif.c
@@ -22,6 +22,7 @@
#include "target.h"
#include "hif-ops.h"
#include "debug.h"
+#include "trace.h"
#define MAILBOX_FOR_BLOCK_SIZE 1
@@ -436,6 +437,8 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done)
ath6kl_dump_registers(dev, &dev->irq_proc_reg,
&dev->irq_en_reg);
+ trace_ath6kl_sdio_irq(&dev->irq_en_reg,
+ sizeof(dev->irq_en_reg));
/* Update only those registers that are enabled */
host_int_status = dev->irq_proc_reg.host_int_status &
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
index fbb78dfe078f..65e5b719093d 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
@@ -19,6 +19,8 @@
#include "hif.h"
#include "debug.h"
#include "hif-ops.h"
+#include "trace.h"
+
#include <asm/unaligned.h>
#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask))
@@ -537,6 +539,8 @@ static int ath6kl_htc_tx_issue(struct htc_target *target,
packet->buf, padded_len,
HIF_WR_ASYNC_BLOCK_INC, packet);
+ trace_ath6kl_htc_tx(status, packet->endpoint, packet->buf, send_len);
+
return status;
}
@@ -757,7 +761,8 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
{
struct htc_target *target = endpoint->target;
struct hif_scatter_req *scat_req = NULL;
- int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0;
+ int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0, i;
+ struct htc_packet *packet;
int status;
u32 txb_mask;
u8 ac = WMM_NUM_AC;
@@ -832,6 +837,13 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
ath6kl_dbg(ATH6KL_DBG_HTC,
"htc tx scatter bytes %d entries %d\n",
scat_req->len, scat_req->scat_entries);
+
+ for (i = 0; i < scat_req->scat_entries; i++) {
+ packet = scat_req->scat_list[i].packet;
+ trace_ath6kl_htc_tx(packet->status, packet->endpoint,
+ packet->buf, packet->act_len);
+ }
+
ath6kl_hif_submit_scat_req(target->dev, scat_req, false);
if (status)
@@ -1903,6 +1915,7 @@ static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint,
ath6kl_dbg(ATH6KL_DBG_HTC,
"htc rx complete ep %d packet 0x%p\n",
endpoint->eid, packet);
+
endpoint->ep_cb.rx(endpoint->target, packet);
}
@@ -2011,6 +2024,9 @@ static int ath6kl_htc_rx_process_packets(struct htc_target *target,
list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) {
ep = &target->endpoint[packet->endpoint];
+ trace_ath6kl_htc_rx(packet->status, packet->endpoint,
+ packet->buf, packet->act_len);
+
/* process header for each of the recv packet */
status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds,
n_lk_ahd);
@@ -2291,6 +2307,9 @@ static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target)
if (ath6kl_htc_rx_packet(target, packet, packet->act_len))
goto fail_ctrl_rx;
+ trace_ath6kl_htc_rx(packet->status, packet->endpoint,
+ packet->buf, packet->act_len);
+
/* process receive header */
packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL);
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index 281390178e3d..67aa924ed8b3 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -988,8 +988,6 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
htc_hdr = (struct htc_frame_hdr *) netdata;
- ep = &target->endpoint[htc_hdr->eid];
-
if (htc_hdr->eid >= ENDPOINT_MAX) {
ath6kl_dbg(ATH6KL_DBG_HTC,
"HTC Rx: invalid EndpointID=%d\n",
@@ -997,6 +995,7 @@ static int ath6kl_htc_pipe_rx_complete(struct ath6kl *ar, struct sk_buff *skb,
status = -EINVAL;
goto free_skb;
}
+ ep = &target->endpoint[htc_hdr->eid];
payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len));
@@ -1168,8 +1167,8 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target)
}
if (count <= 0) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Timeout!\n", __func__);
- return -ECOMM;
+ ath6kl_warn("htc pipe control receive timeout!\n");
+ return -ETIMEDOUT;
}
return 0;
@@ -1582,16 +1581,16 @@ static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
return status;
if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg len:%d!\n",
- target->pipe.ctrl_response_len);
+ ath6kl_warn("invalid htc pipe ready msg len: %d\n",
+ target->pipe.ctrl_response_len);
return -ECOMM;
}
ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;
if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg : 0x%X !\n",
- ready_msg->ver2_0_info.msg_id);
+ ath6kl_warn("invalid htc pipe ready msg: 0x%x\n",
+ ready_msg->ver2_0_info.msg_id);
return -ECOMM;
}
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 5d434cf88f35..40ffee6184fd 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -201,8 +201,8 @@ struct sk_buff *ath6kl_buf_alloc(int size)
u16 reserved;
/* Add chacheline space at front and back of buffer */
- reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
- sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES;
+ reserved = roundup((2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET +
+ sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES, 4);
skb = dev_alloc_skb(size + reserved);
if (skb)
@@ -1549,10 +1549,89 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
return NULL;
}
+
+static const struct fw_capa_str_map {
+ int id;
+ const char *name;
+} fw_capa_map[] = {
+ { ATH6KL_FW_CAPABILITY_HOST_P2P, "host-p2p" },
+ { ATH6KL_FW_CAPABILITY_SCHED_SCAN, "sched-scan" },
+ { ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX, "sta-p2pdev-duplex" },
+ { ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT, "inactivity-timeout" },
+ { ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, "rsn-cap-override" },
+ { ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, "wow-mc-filter" },
+ { ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, "bmiss-enhance" },
+ { ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, "sscan-match-list" },
+ { ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD, "rssi-scan-thold" },
+ { ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR, "custom-mac-addr" },
+ { ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, "tx-err-notify" },
+ { ATH6KL_FW_CAPABILITY_REGDOMAIN, "regdomain" },
+ { ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, "sched-scan-v2" },
+ { ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL, "hb-poll" },
+};
+
+static const char *ath6kl_init_get_fw_capa_name(unsigned int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fw_capa_map); i++) {
+ if (fw_capa_map[i].id == id)
+ return fw_capa_map[i].name;
+ }
+
+ return "<unknown>";
+}
+
+static void ath6kl_init_get_fwcaps(struct ath6kl *ar, char *buf, size_t buf_len)
+{
+ u8 *data = (u8 *) ar->fw_capabilities;
+ size_t trunc_len, len = 0;
+ int i, index, bit;
+ char *trunc = "...";
+
+ for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
+ index = i / 8;
+ bit = i % 8;
+
+ if (index >= sizeof(ar->fw_capabilities) * 4)
+ break;
+
+ if (buf_len - len < 4) {
+ ath6kl_warn("firmware capability buffer too small!\n");
+
+ /* add "..." to the end of string */
+ trunc_len = strlen(trunc) + 1;
+ strncpy(buf + buf_len - trunc_len, trunc, trunc_len);
+
+ return;
+ }
+
+ if (data[index] & (1 << bit)) {
+ len += scnprintf(buf + len, buf_len - len, "%s,",
+ ath6kl_init_get_fw_capa_name(i));
+ }
+ }
+
+ /* overwrite the last comma */
+ if (len > 0)
+ len--;
+
+ buf[len] = '\0';
+}
+
+static int ath6kl_init_hw_reset(struct ath6kl *ar)
+{
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "cold resetting the device");
+
+ return ath6kl_diag_write32(ar, RESET_CONTROL_ADDRESS,
+ cpu_to_le32(RESET_CONTROL_COLD_RST));
+}
+
static int __ath6kl_init_hw_start(struct ath6kl *ar)
{
long timeleft;
int ret, i;
+ char buf[200];
ath6kl_dbg(ATH6KL_DBG_BOOT, "hw start\n");
@@ -1569,24 +1648,35 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar)
goto err_power_off;
/* Do we need to finish the BMI phase */
- /* FIXME: return error from ath6kl_bmi_done() */
- if (ath6kl_bmi_done(ar)) {
- ret = -EIO;
+ ret = ath6kl_bmi_done(ar);
+ if (ret)
goto err_power_off;
- }
/*
* The reason we have to wait for the target here is that the
* driver layer has to init BMI in order to set the host block
* size.
*/
- if (ath6kl_htc_wait_target(ar->htc_target)) {
- ret = -EIO;
+ ret = ath6kl_htc_wait_target(ar->htc_target);
+
+ if (ret == -ETIMEDOUT) {
+ /*
+ * Most likely USB target is in odd state after reboot and
+ * needs a reset. A cold reset makes the whole device
+ * disappear from USB bus and initialisation starts from
+ * beginning.
+ */
+ ath6kl_warn("htc wait target timed out, resetting device\n");
+ ath6kl_init_hw_reset(ar);
+ goto err_power_off;
+ } else if (ret) {
+ ath6kl_err("htc wait target failed: %d\n", ret);
goto err_power_off;
}
- if (ath6kl_init_service_ep(ar)) {
- ret = -EIO;
+ ret = ath6kl_init_service_ep(ar);
+ if (ret) {
+ ath6kl_err("Endpoint service initilisation failed: %d\n", ret);
goto err_cleanup_scatter;
}
@@ -1617,6 +1707,8 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar)
ar->wiphy->fw_version,
ar->fw_api,
test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+ ath6kl_init_get_fwcaps(ar, buf, sizeof(buf));
+ ath6kl_info("firmware supports: %s\n", buf);
}
if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
@@ -1765,9 +1857,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
* Try to reset the device if we can. The driver may have been
* configure NOT to reset the target during a debug session.
*/
- ath6kl_dbg(ATH6KL_DBG_TRC,
- "attempting to reset target on instance destroy\n");
- ath6kl_reset_device(ar, ar->target_type, true, true);
+ ath6kl_init_hw_reset(ar);
up(&ar->sem);
}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index bd50b6b7b492..d4fcfcad57d0 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -345,39 +345,6 @@ out:
return ret;
}
-/* FIXME: move to a better place, target.h? */
-#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
-#define AR6004_RESET_CONTROL_ADDRESS 0x00004000
-
-void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
- bool wait_fot_compltn, bool cold_reset)
-{
- int status = 0;
- u32 address;
- __le32 data;
-
- if (target_type != TARGET_TYPE_AR6003 &&
- target_type != TARGET_TYPE_AR6004)
- return;
-
- data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
- cpu_to_le32(RESET_CONTROL_MBOX_RST);
-
- switch (target_type) {
- case TARGET_TYPE_AR6003:
- address = AR6003_RESET_CONTROL_ADDRESS;
- break;
- case TARGET_TYPE_AR6004:
- address = AR6004_RESET_CONTROL_ADDRESS;
- break;
- }
-
- status = ath6kl_diag_write32(ar, address, data);
-
- if (status)
- ath6kl_err("failed to reset target\n");
-}
-
static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif)
{
u8 index;
@@ -1327,9 +1294,11 @@ void init_netdev(struct net_device *dev)
dev->watchdog_timeo = ATH6KL_TX_TIMEOUT;
dev->needed_headroom = ETH_HLEN;
- dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) +
- sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH
- + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES;
+ dev->needed_headroom += roundup(sizeof(struct ath6kl_llc_snap_hdr) +
+ sizeof(struct wmi_data_hdr) +
+ HTC_HDR_LENGTH +
+ WMI_MAX_TX_META_SZ +
+ ATH6KL_HTC_ALIGN_BYTES, 4);
dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index d111980d44c0..fb141454c6d2 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -28,6 +28,7 @@
#include "target.h"
#include "debug.h"
#include "cfg80211.h"
+#include "trace.h"
struct ath6kl_sdio {
struct sdio_func *func;
@@ -179,6 +180,8 @@ static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr,
request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len);
ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len);
+ trace_ath6kl_sdio(addr, request, buf, len);
+
return ret;
}
@@ -309,6 +312,13 @@ static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio,
sdio_claim_host(ar_sdio->func);
mmc_set_data_timeout(&data, ar_sdio->func->card);
+
+ trace_ath6kl_sdio_scat(scat_req->addr,
+ scat_req->req,
+ scat_req->len,
+ scat_req->scat_entries,
+ scat_req->scat_list);
+
/* synchronous call to process request */
mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req);
@@ -1123,10 +1133,12 @@ static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
HIF_WR_SYNC_BYTE_INC);
- if (ret)
+ if (ret) {
ath6kl_err("unable to send the bmi data to the device\n");
+ return ret;
+ }
- return ret;
+ return 0;
}
static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
index a98c12ba70c1..a580a629a0da 100644
--- a/drivers/net/wireless/ath/ath6kl/target.h
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -25,7 +25,7 @@
#define AR6004_BOARD_DATA_SZ 6144
#define AR6004_BOARD_EXT_DATA_SZ 0
-#define RESET_CONTROL_ADDRESS 0x00000000
+#define RESET_CONTROL_ADDRESS 0x00004000
#define RESET_CONTROL_COLD_RST 0x00000100
#define RESET_CONTROL_MBOX_RST 0x00000004
diff --git a/drivers/net/wireless/ath/ath6kl/trace.c b/drivers/net/wireless/ath/ath6kl/trace.c
new file mode 100644
index 000000000000..e7d64b1285cb
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/trace.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(ath6kl_sdio);
+EXPORT_TRACEPOINT_SYMBOL(ath6kl_sdio_scat);
diff --git a/drivers/net/wireless/ath/ath6kl/trace.h b/drivers/net/wireless/ath/ath6kl/trace.h
new file mode 100644
index 000000000000..1a1ea7881b4d
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/trace.h
@@ -0,0 +1,332 @@
+#if !defined(_ATH6KL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+
+#include <net/cfg80211.h>
+#include <linux/skbuff.h>
+#include <linux/tracepoint.h>
+#include "wmi.h"
+#include "hif.h"
+
+#if !defined(_ATH6KL_TRACE_H)
+static inline unsigned int ath6kl_get_wmi_id(void *buf, size_t buf_len)
+{
+ struct wmi_cmd_hdr *hdr = buf;
+
+ if (buf_len < sizeof(*hdr))
+ return 0;
+
+ return le16_to_cpu(hdr->cmd_id);
+}
+#endif /* __ATH6KL_TRACE_H */
+
+#define _ATH6KL_TRACE_H
+
+/* create empty functions when tracing is disabled */
+#if !defined(CONFIG_ATH6KL_TRACING)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(...)
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(evt_class, name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif /* !CONFIG_ATH6KL_TRACING || __CHECKER__ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ath6kl
+
+TRACE_EVENT(ath6kl_wmi_cmd,
+ TP_PROTO(void *buf, size_t buf_len),
+
+ TP_ARGS(buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->id = ath6kl_get_wmi_id(buf, buf_len);
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "id %d len %zd",
+ __entry->id, __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath6kl_wmi_event,
+ TP_PROTO(void *buf, size_t buf_len),
+
+ TP_ARGS(buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, id)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->id = ath6kl_get_wmi_id(buf, buf_len);
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "id %d len %zd",
+ __entry->id, __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath6kl_sdio,
+ TP_PROTO(unsigned int addr, int flags,
+ void *buf, size_t buf_len),
+
+ TP_ARGS(addr, flags, buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, tx)
+ __field(unsigned int, addr)
+ __field(int, flags)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->addr = addr;
+ __entry->flags = flags;
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+
+ if (flags & HIF_WRITE)
+ __entry->tx = 1;
+ else
+ __entry->tx = 0;
+ ),
+
+ TP_printk(
+ "%s addr 0x%x flags 0x%x len %zd\n",
+ __entry->tx ? "tx" : "rx",
+ __entry->addr,
+ __entry->flags,
+ __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath6kl_sdio_scat,
+ TP_PROTO(unsigned int addr, int flags, unsigned int total_len,
+ unsigned int entries, struct hif_scatter_item *list),
+
+ TP_ARGS(addr, flags, total_len, entries, list),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, tx)
+ __field(unsigned int, addr)
+ __field(int, flags)
+ __field(unsigned int, entries)
+ __field(size_t, total_len)
+ __dynamic_array(unsigned int, len_array, entries)
+ __dynamic_array(u8, data, total_len)
+ ),
+
+ TP_fast_assign(
+ unsigned int *len_array;
+ int i, offset = 0;
+ size_t len;
+
+ __entry->addr = addr;
+ __entry->flags = flags;
+ __entry->entries = entries;
+ __entry->total_len = total_len;
+
+ if (flags & HIF_WRITE)
+ __entry->tx = 1;
+ else
+ __entry->tx = 0;
+
+ len_array = __get_dynamic_array(len_array);
+
+ for (i = 0; i < entries; i++) {
+ len = list[i].len;
+
+ memcpy((u8 *) __get_dynamic_array(data) + offset,
+ list[i].buf, len);
+
+ len_array[i] = len;
+ offset += len;
+ }
+ ),
+
+ TP_printk(
+ "%s addr 0x%x flags 0x%x entries %d total_len %zd\n",
+ __entry->tx ? "tx" : "rx",
+ __entry->addr,
+ __entry->flags,
+ __entry->entries,
+ __entry->total_len
+ )
+);
+
+TRACE_EVENT(ath6kl_sdio_irq,
+ TP_PROTO(void *buf, size_t buf_len),
+
+ TP_ARGS(buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "irq len %zd\n", __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath6kl_htc_rx,
+ TP_PROTO(int status, int endpoint, void *buf,
+ size_t buf_len),
+
+ TP_ARGS(status, endpoint, buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(int, status)
+ __field(int, endpoint)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->status = status;
+ __entry->endpoint = endpoint;
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "status %d endpoint %d len %zd\n",
+ __entry->status,
+ __entry->endpoint,
+ __entry->buf_len
+ )
+);
+
+TRACE_EVENT(ath6kl_htc_tx,
+ TP_PROTO(int status, int endpoint, void *buf,
+ size_t buf_len),
+
+ TP_ARGS(status, endpoint, buf, buf_len),
+
+ TP_STRUCT__entry(
+ __field(int, status)
+ __field(int, endpoint)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __entry->status = status;
+ __entry->endpoint = endpoint;
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "status %d endpoint %d len %zd\n",
+ __entry->status,
+ __entry->endpoint,
+ __entry->buf_len
+ )
+);
+
+#define ATH6KL_MSG_MAX 200
+
+DECLARE_EVENT_CLASS(ath6kl_log_event,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf),
+ TP_STRUCT__entry(
+ __dynamic_array(char, msg, ATH6KL_MSG_MAX)
+ ),
+ TP_fast_assign(
+ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+ ATH6KL_MSG_MAX,
+ vaf->fmt,
+ *vaf->va) >= ATH6KL_MSG_MAX);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(ath6kl_log_event, ath6kl_log_err,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(ath6kl_log_event, ath6kl_log_warn,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(ath6kl_log_event, ath6kl_log_info,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+TRACE_EVENT(ath6kl_log_dbg,
+ TP_PROTO(unsigned int level, struct va_format *vaf),
+ TP_ARGS(level, vaf),
+ TP_STRUCT__entry(
+ __field(unsigned int, level)
+ __dynamic_array(char, msg, ATH6KL_MSG_MAX)
+ ),
+ TP_fast_assign(
+ __entry->level = level;
+ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+ ATH6KL_MSG_MAX,
+ vaf->fmt,
+ *vaf->va) >= ATH6KL_MSG_MAX);
+ ),
+ TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(ath6kl_log_dbg_dump,
+ TP_PROTO(const char *msg, const char *prefix,
+ const void *buf, size_t buf_len),
+
+ TP_ARGS(msg, prefix, buf, buf_len),
+
+ TP_STRUCT__entry(
+ __string(msg, msg)
+ __string(prefix, prefix)
+ __field(size_t, buf_len)
+ __dynamic_array(u8, buf, buf_len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(msg, msg);
+ __assign_str(prefix, prefix);
+ __entry->buf_len = buf_len;
+ memcpy(__get_dynamic_array(buf), buf, buf_len);
+ ),
+
+ TP_printk(
+ "%s/%s\n", __get_str(prefix), __get_str(msg)
+ )
+);
+
+#endif /* _ ATH6KL_TRACE_H || TRACE_HEADER_MULTI_READ*/
+
+/* we don't want to use include/trace/events */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 78b369286579..ebb24045a8ae 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -20,6 +20,7 @@
#include "core.h"
#include "debug.h"
#include "htc-ops.h"
+#include "trace.h"
/*
* tid - tid_mux0..tid_mux3
@@ -288,6 +289,8 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
int status = 0;
struct ath6kl_cookie *cookie = NULL;
+ trace_ath6kl_wmi_cmd(skb->data, skb->len);
+
if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) {
dev_kfree_skb(skb);
return -EACCES;
@@ -1324,7 +1327,7 @@ void ath6kl_rx(struct htc_target *target, struct htc_packet *packet)
__func__, ar, ept, skb, packet->buf,
packet->act_len, status);
- if (status || !(skb->data + HTC_HDR_LENGTH)) {
+ if (status || packet->act_len < HTC_HDR_LENGTH) {
dev_kfree_skb(skb);
return;
}
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 5fcd342762de..bed0d337712d 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -856,11 +856,9 @@ static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
int ret;
if (size > 0) {
- buf = kmalloc(size, GFP_KERNEL);
+ buf = kmemdup(data, size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
-
- memcpy(buf, data, size);
}
/* note: if successful returns number of bytes transfered */
@@ -872,8 +870,9 @@ static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
size, 1000);
if (ret < 0) {
- ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
- __func__, ret);
+ ath6kl_warn("Failed to submit usb control message: %d\n", ret);
+ kfree(buf);
+ return ret;
}
kfree(buf);
@@ -903,8 +902,9 @@ static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
size, 2 * HZ);
if (ret < 0) {
- ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
- __func__, ret);
+ ath6kl_warn("Failed to read usb control message: %d\n", ret);
+ kfree(buf);
+ return ret;
}
memcpy((u8 *) data, buf, size);
@@ -961,8 +961,10 @@ static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
ar_usb->diag_resp_buffer, &resp_len);
- if (ret)
+ if (ret) {
+ ath6kl_warn("diag read32 failed: %d\n", ret);
return ret;
+ }
resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
ar_usb->diag_resp_buffer;
@@ -976,6 +978,7 @@ static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
+ int ret;
cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;
@@ -984,12 +987,17 @@ static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
cmd->address = cpu_to_le32(address);
cmd->value = data;
- return ath6kl_usb_ctrl_msg_exchange(ar_usb,
- ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
- (u8 *) cmd,
- sizeof(*cmd),
- 0, NULL, NULL);
+ ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
+ ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
+ (u8 *) cmd,
+ sizeof(*cmd),
+ 0, NULL, NULL);
+ if (ret) {
+ ath6kl_warn("diag_write32 failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
}
static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
@@ -1001,7 +1009,7 @@ static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
ret = ath6kl_usb_submit_ctrl_in(ar_usb,
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
0, 0, buf, len);
- if (ret != 0) {
+ if (ret) {
ath6kl_err("Unable to read the bmi data from the device: %d\n",
ret);
return ret;
@@ -1019,7 +1027,7 @@ static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
ret = ath6kl_usb_submit_ctrl_out(ar_usb,
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
0, 0, buf, len);
- if (ret != 0) {
+ if (ret) {
ath6kl_err("unable to send the bmi data to the device: %d\n",
ret);
return ret;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index d76b5bd81a0d..87aefb4c4c23 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -20,6 +20,7 @@
#include "core.h"
#include "debug.h"
#include "testmode.h"
+#include "trace.h"
#include "../regd.h"
#include "../regd_common.h"
@@ -2028,6 +2029,9 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
if (!sband)
continue;
+ if (WARN_ON(band >= ATH6KL_NUM_BANDS))
+ break;
+
ratemask = rates[band];
supp_rates = sc->supp_rates[band].rates;
num_rates = 0;
@@ -4086,6 +4090,8 @@ int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb)
return -EINVAL;
}
+ trace_ath6kl_wmi_event(skb->data, skb->len);
+
return ath6kl_wmi_proc_events(wmi, skb);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index fd69376ecc83..391da5ad6a99 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -18,6 +18,7 @@
#include "hw-ops.h"
#include "../regd.h"
#include "ar9002_phy.h"
+#include "ar5008_initvals.h"
/* All code below is for AR5008, AR9001, AR9002 */
@@ -43,23 +44,16 @@ static const int m2ThreshLowExt_off = 127;
static const int m1ThreshExt_off = 127;
static const int m2ThreshExt_off = 127;
+static const struct ar5416IniArray bank0 = STATIC_INI_ARRAY(ar5416Bank0);
+static const struct ar5416IniArray bank1 = STATIC_INI_ARRAY(ar5416Bank1);
+static const struct ar5416IniArray bank2 = STATIC_INI_ARRAY(ar5416Bank2);
+static const struct ar5416IniArray bank3 = STATIC_INI_ARRAY(ar5416Bank3);
+static const struct ar5416IniArray bank7 = STATIC_INI_ARRAY(ar5416Bank7);
-static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array,
- int col)
-{
- int i;
-
- for (i = 0; i < array->ia_rows; i++)
- bank[i] = INI_RA(array, i, col);
-}
-
-
-#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \
- ar5008_write_rf_array(ah, iniarray, regData, &(regWr))
-
-static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array,
- u32 *data, unsigned int *writecnt)
+static void ar5008_write_bank6(struct ath_hw *ah, unsigned int *writecnt)
{
+ struct ar5416IniArray *array = &ah->iniBank6;
+ u32 *data = ah->analogBank6Data;
int r;
ENABLE_REGWRITE_BUFFER(ah);
@@ -165,7 +159,7 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
/* write Bank 6 with new params */
- REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
+ ar5008_write_bank6(ah, &reg_writes);
}
/**
@@ -469,31 +463,16 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
*/
static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
{
-#define ATH_ALLOC_BANK(bank, size) do { \
- bank = devm_kzalloc(ah->dev, sizeof(u32) * size, GFP_KERNEL); \
- if (!bank) \
- goto error; \
- } while (0);
-
- struct ath_common *common = ath9k_hw_common(ah);
+ int size = ah->iniBank6.ia_rows * sizeof(u32);
if (AR_SREV_9280_20_OR_LATER(ah))
return 0;
- ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
- ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
- ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
+ ah->analogBank6Data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
+ if (!ah->analogBank6Data)
+ return -ENOMEM;
return 0;
-#undef ATH_ALLOC_BANK
-error:
- ath_err(common, "Cannot allocate RF banks\n");
- return -ENOMEM;
}
@@ -517,6 +496,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
u32 ob5GHz = 0, db5GHz = 0;
u32 ob2GHz = 0, db2GHz = 0;
int regWrites = 0;
+ int i;
/*
* Software does not need to program bank data
@@ -529,25 +509,8 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
/* Setup rf parameters */
eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
- /* Setup Bank 0 Write */
- ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1);
-
- /* Setup Bank 1 Write */
- ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1);
-
- /* Setup Bank 2 Write */
- ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1);
-
- /* Setup Bank 6 Write */
- ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
- modesIndex);
- {
- int i;
- for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
- ah->analogBank6Data[i] =
- INI_RA(&ah->iniBank6TPC, i, modesIndex);
- }
- }
+ for (i = 0; i < ah->iniBank6.ia_rows; i++)
+ ah->analogBank6Data[i] = INI_RA(&ah->iniBank6, i, modesIndex);
/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
if (eepMinorRev >= 2) {
@@ -568,22 +531,13 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
}
}
- /* Setup Bank 7 Setup */
- ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
-
/* Write Analog registers */
- REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
- regWrites);
- REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
- regWrites);
+ REG_WRITE_ARRAY(&bank0, 1, regWrites);
+ REG_WRITE_ARRAY(&bank1, 1, regWrites);
+ REG_WRITE_ARRAY(&bank2, 1, regWrites);
+ REG_WRITE_ARRAY(&bank3, modesIndex, regWrites);
+ ar5008_write_bank6(ah, &regWrites);
+ REG_WRITE_ARRAY(&bank7, 1, regWrites);
return true;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index c55e5bbafc46..9f589744a9f9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -731,7 +731,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
@@ -745,7 +746,8 @@ static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
@@ -841,7 +843,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT)) {
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index f053d978540e..830daa12feb6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -67,12 +67,10 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
} else if (AR_SREV_9100_OR_LATER(ah)) {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100);
INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100);
- INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100);
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100);
} else {
INIT_INI_ARRAY(&ah->iniModes, ar5416Modes);
INIT_INI_ARRAY(&ah->iniCommon, ar5416Common);
- INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC);
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac);
}
@@ -80,20 +78,11 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
/* Common for AR5416, AR913x, AR9160 */
INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain);
- INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0);
- INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1);
- INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2);
- INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3);
- INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7);
-
- /* Common for AR5416, AR9160 */
- if (!AR_SREV_9100(ah))
- INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6);
-
/* Common for AR913x, AR9160 */
if (!AR_SREV_5416(ah))
- INIT_INI_ARRAY(&ah->iniBank6TPC,
- ar5416Bank6TPC_9100);
+ INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6TPC_9100);
+ else
+ INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6TPC);
}
/* iniAddac needs to be modified for these chips */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index f76c3ca07a45..639ba7d18ea4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1126,7 +1126,8 @@ skip_tx_iqcal:
ar9003_hw_rtt_disable(ah);
ath_dbg(common, CALIBRATE,
- "offset calibration failed to complete in 1ms; noisy environment?\n");
+ "offset calibration failed to complete in %d ms; noisy environment?\n",
+ AH_WAIT_TIMEOUT / 1000);
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 881e989ea470..e6b92ff265fd 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3606,6 +3606,12 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
+ if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
+ value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
+ REG_RMW_FIELD(ah, switch_chain_reg[0],
+ AR_SWITCH_TABLE_ALL, value);
+ }
+
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if ((ah->rxchainmask & BIT(chain)) ||
(ah->txchainmask & BIT(chain))) {
@@ -3772,6 +3778,17 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
AR_PHY_EXT_ATTEN_CTL_2,
};
+ if ((AR_SREV_9462(ah)) && (ah->rxchainmask == 0x2)) {
+ value = ar9003_hw_atten_chain_get(ah, 1, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[0],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+ value = ar9003_hw_atten_chain_get_margin(ah, 1, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[0],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+ value);
+ }
+
/* Test value. if 0 then attenuation is unused. Don't load anything. */
for (i = 0; i < 3; i++) {
if (ah->txchainmask & BIT(i)) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
index ccc42a71b436..999ab08c34e6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
@@ -37,28 +37,28 @@ static const u32 ar9462_pciephy_clkreq_enable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18253ede},
{0x00018c04, 0x000801d8},
- {0x00018c08, 0x0003580c},
+ {0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_baseband_postamble[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
{0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a800d},
{0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a01ae},
- {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
+ {0x00009824, 0x63c640de, 0x5ac640d0, 0x5ac640d0, 0x63c640da},
{0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x09143e81},
{0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
{0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
{0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
- {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a2},
{0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
{0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8},
{0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
- {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3236605e, 0x32365a5e},
{0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e3c, 0xcf946222, 0xcf946222, 0xcfd5c782, 0xcfd5c282},
+ {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c282},
{0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -82,9 +82,9 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
{0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
{0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a3a4, 0x00000010, 0x00000010, 0x00000000, 0x00000000},
+ {0x0000a3a4, 0x00000050, 0x00000050, 0x00000000, 0x00000000},
{0x0000a3a8, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa},
- {0x0000a3ac, 0xaaaaaa00, 0xaaaaaa30, 0xaaaaaa00, 0xaaaaaa00},
+ {0x0000a3ac, 0xaaaaaa00, 0xaa30aa30, 0xaaaaaa00, 0xaaaaaa00},
{0x0000a41c, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
{0x0000a420, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce},
{0x0000a424, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce},
@@ -363,14 +363,14 @@ static const u32 ar9462_pciephy_clkreq_disable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18213ede},
{0x00018c04, 0x000801d8},
- {0x00018c08, 0x0003580c},
+ {0x00018c08, 0x0003780c},
};
static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = {
/* Addr allmodes */
{0x00018c00, 0x18212ede},
{0x00018c04, 0x000801d8},
- {0x00018c08, 0x0003580c},
+ {0x00018c08, 0x0003780c},
};
static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
@@ -775,7 +775,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
{0x00009fc0, 0x803e4788},
{0x00009fc4, 0x0001efb5},
{0x00009fcc, 0x40000014},
- {0x00009fd0, 0x01193b93},
+ {0x00009fd0, 0x0a193b93},
{0x0000a20c, 0x00000000},
{0x0000a220, 0x00000000},
{0x0000a224, 0x00000000},
@@ -850,7 +850,7 @@ static const u32 ar9462_2p0_baseband_core[][2] = {
{0x0000a7cc, 0x00000000},
{0x0000a7d0, 0x00000000},
{0x0000a7d4, 0x00000004},
- {0x0000a7dc, 0x00000001},
+ {0x0000a7dc, 0x00000000},
{0x0000a7f0, 0x80000000},
{0x0000a8d0, 0x004b6a8e},
{0x0000a8d4, 0x00000820},
@@ -886,7 +886,7 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
{0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a410, 0x000050da, 0x000050da, 0x000050de, 0x000050de},
{0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
@@ -906,20 +906,20 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
{0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
{0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
{0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
- {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
- {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
- {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
+ {0x0000a548, 0x55025eb3, 0x55025eb3, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x58025ef3, 0x58025ef3, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001a84, 0x44001a84},
{0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
{0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
{0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
{0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
- {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
- {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a564, 0x751ffff6, 0x751ffff6, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x751ffff6, 0x751ffff6, 0x58001ef0, 0x58001ef0},
+ {0x0000a56c, 0x751ffff6, 0x751ffff6, 0x5a001ef4, 0x5a001ef4},
+ {0x0000a570, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+ {0x0000a574, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+ {0x0000a578, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
+ {0x0000a57c, 0x751ffff6, 0x751ffff6, 0x5c001ff6, 0x5c001ff6},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -1053,7 +1053,6 @@ static const u32 ar9462_2p0_mac_core[][2] = {
{0x00008044, 0x00000000},
{0x00008048, 0x00000000},
{0x0000804c, 0xffffffff},
- {0x00008050, 0xffffffff},
{0x00008054, 0x00000000},
{0x00008058, 0x00000000},
{0x0000805c, 0x000fc78f},
@@ -1117,9 +1116,9 @@ static const u32 ar9462_2p0_mac_core[][2] = {
{0x000081f8, 0x00000000},
{0x000081fc, 0x00000000},
{0x00008240, 0x00100000},
- {0x00008244, 0x0010f424},
+ {0x00008244, 0x0010f400},
{0x00008248, 0x00000800},
- {0x0000824c, 0x0001e848},
+ {0x0000824c, 0x0001e800},
{0x00008250, 0x00000000},
{0x00008254, 0x00000000},
{0x00008258, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
index 28fd99203f64..bdee2ed67219 100644
--- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
@@ -519,7 +519,7 @@ static const u32 ar9580_1p0_mac_core[][2] = {
{0x00008258, 0x00000000},
{0x0000825c, 0x40000000},
{0x00008260, 0x00080922},
- {0x00008264, 0x9bc00010},
+ {0x00008264, 0x9d400010},
{0x00008268, 0xffffffff},
{0x0000826c, 0x0000ffff},
{0x00008270, 0x00000000},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a56b2416e2f9..8a1888d02070 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -234,6 +234,7 @@ struct ath_buf {
dma_addr_t bf_daddr; /* physical addr of desc */
dma_addr_t bf_buf_addr; /* physical addr of data buffer, for DMA */
bool bf_stale;
+ struct ieee80211_tx_rate rates[4];
struct ath_buf_state bf_state;
};
@@ -311,6 +312,7 @@ struct ath_rx_edma {
struct ath_rx {
u8 defant;
u8 rxotherant;
+ bool discard_next;
u32 *rxlink;
u32 num_pkts;
unsigned int rxfilter;
@@ -657,11 +659,10 @@ enum sc_op_flags {
struct ath_rate_table;
struct ath9k_vif_iter_data {
- const u8 *hw_macaddr; /* phy's hardware address, set
- * before starting iteration for
- * valid bssid mask.
- */
+ u8 hw_macaddr[ETH_ALEN]; /* address of the first vif */
u8 mask[ETH_ALEN]; /* bssid mask */
+ bool has_hw_macaddr;
+
int naps; /* number of AP vifs */
int nmeshes; /* number of mesh vifs */
int nstations; /* number of station vifs */
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 5f05c26d1ec4..2ff570f7f8ff 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -79,7 +79,7 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
u8 chainmask = ah->txchainmask;
u8 rate = 0;
- sband = &sc->sbands[common->hw->conf.channel->band];
+ sband = &sc->sbands[common->hw->conf.chandef.chan->band];
rate = sband->bitrates[rateidx].hw_value;
if (vif->bss_conf.use_short_preamble)
rate |= sband->bitrates[rateidx].hw_value_short;
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 1e8508530e98..7304e7585009 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -208,7 +208,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
return true;
ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
- currCal->calData->calType, conf->channel->center_freq);
+ currCal->calData->calType, conf->chandef.chan->center_freq);
ah->caldata->CalValid &= ~currCal->calData->calType;
currCal->calState = CAL_WAITING;
@@ -369,7 +369,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
struct ieee80211_channel *c = chan->chan;
struct ath9k_hw_cal_data *caldata = ah->caldata;
- chan->channelFlags &= (~CHANNEL_CW_INT);
if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
ath_dbg(common, CALIBRATE,
"NF did not complete in calibration window\n");
@@ -384,7 +383,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
ath_dbg(common, CALIBRATE,
"noise floor failed detected; detected %d, threshold %d\n",
nf, nfThresh);
- chan->channelFlags |= CHANNEL_CW_INT;
}
if (!caldata) {
@@ -410,7 +408,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
int i, j;
ah->caldata->channel = chan->channel;
- ah->caldata->channelFlags = chan->channelFlags & ~CHANNEL_CW_INT;
+ ah->caldata->channelFlags = chan->channelFlags;
ah->caldata->chanmode = chan->chanmode;
h = ah->caldata->nfCalHist;
default_nf = ath9k_hw_get_default_nf(ah, chan);
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 60dcb6c22db9..3d70b8c2bcdd 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -33,6 +33,12 @@ struct ar5416IniArray {
u32 ia_columns;
};
+#define STATIC_INI_ARRAY(array) { \
+ .ia_array = (u32 *)(array), \
+ .ia_rows = ARRAY_SIZE(array), \
+ .ia_columns = ARRAY_SIZE(array[0]), \
+ }
+
#define INIT_INI_ARRAY(iniarray, array) do { \
(iniarray)->ia_array = (u32 *)(array); \
(iniarray)->ia_rows = ARRAY_SIZE(array); \
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 905f1b313961..344fdde1d7a3 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -27,20 +27,6 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
-int ath9k_cmn_padpos(__le16 frame_control)
-{
- int padpos = 24;
- if (ieee80211_has_a4(frame_control)) {
- padpos += ETH_ALEN;
- }
- if (ieee80211_is_data_qos(frame_control)) {
- padpos += IEEE80211_QOS_CTL_LEN;
- }
-
- return padpos;
-}
-EXPORT_SYMBOL(ath9k_cmn_padpos);
-
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
@@ -133,13 +119,14 @@ EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
struct ath_hw *ah)
{
- struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
struct ath9k_channel *channel;
u8 chan_idx;
chan_idx = curchan->hw_value;
channel = &ah->channels[chan_idx];
- ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type);
+ ath9k_cmn_update_ichannel(channel, curchan,
+ cfg80211_get_chandef_type(&hw->conf.chandef));
return channel;
}
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index 050ca4a4850d..207d06995b15 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -40,9 +40,8 @@
x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
} while (0)
#define ATH_EP_RND(x, mul) \
- ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+ (((x) + ((mul)/2)) / (mul))
-int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
struct ieee80211_channel *chan,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 3714b971d18e..e6307b86363a 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -537,6 +537,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
PR("AMPDUs Completed:", a_completed);
PR("AMPDUs Retried: ", a_retries);
PR("AMPDUs XRetried: ", a_xretries);
+ PR("TXERR Filtered: ", txerr_filtered);
PR("FIFO Underrun: ", fifo_underrun);
PR("TXOP Exceeded: ", xtxop);
PR("TXTIMER Expiry: ", timer_exp);
@@ -756,6 +757,8 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
TX_STAT_INC(qnum, completed);
}
+ if (ts->ts_status & ATH9K_TXERR_FILT)
+ TX_STAT_INC(qnum, txerr_filtered);
if (ts->ts_status & ATH9K_TXERR_FIFO)
TX_STAT_INC(qnum, fifo_underrun);
if (ts->ts_status & ATH9K_TXERR_XTXOP)
@@ -1909,6 +1912,7 @@ static const char ath9k_gstrings_stats[][ETH_GSTRING_LEN] = {
AMKSTR(d_tx_desc_cfg_err),
AMKSTR(d_tx_data_underrun),
AMKSTR(d_tx_delim_underrun),
+ "d_rx_crc_err",
"d_rx_decrypt_crc_err",
"d_rx_phy_err",
"d_rx_mic_err",
@@ -1989,6 +1993,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw,
AWDATA(data_underrun);
AWDATA(delim_underrun);
+ AWDATA_RX(crc_err);
AWDATA_RX(decrypt_crc_err);
AWDATA_RX(phy_err);
AWDATA_RX(mic_err);
@@ -2067,7 +2072,7 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_modal_eeprom);
sc->rfs_chan_spec_scan = relay_open("spectral_scan",
sc->debug.debugfs_phy,
- 262144, 4, &rfs_spec_scan_cb,
+ 1024, 256, &rfs_spec_scan_cb,
NULL);
debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR,
sc->debug.debugfs_phy, sc,
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 410d6d8f1aa7..794a7ec83a24 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -142,6 +142,7 @@ struct ath_interrupt_stats {
* @a_completed: Total AMPDUs completed
* @a_retries: No. of AMPDUs retried (SW)
* @a_xretries: No. of AMPDUs dropped due to xretries
+ * @txerr_filtered: No. of frames with TXERR_FILT flag set.
* @fifo_underrun: FIFO underrun occurrences
Valid only for:
- non-aggregate condition.
@@ -168,6 +169,7 @@ struct ath_tx_stats {
u32 a_completed;
u32 a_retries;
u32 a_xretries;
+ u32 txerr_filtered;
u32 fifo_underrun;
u32 xtxop;
u32 timer_exp;
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
index ecc81792f2dc..7187d3671512 100644
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -55,12 +55,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc,
u8 rssi;
u16 dur;
- ath_dbg(ath9k_hw_common(sc->sc_ah), DFS,
- "pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n",
- ard->pulse_bw_info,
- ard->pulse_length_pri, ard->rssi,
- ard->pulse_length_ext, ard->ext_rssi);
-
/*
* Only the last 2 bits of the BW info are relevant, they indicate
* which channel the radar was detected in.
@@ -193,9 +187,7 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
DFS_STAT_INC(sc, pulses_processed);
if (pd != NULL && pd->add_pulse(pd, &pe)) {
DFS_STAT_INC(sc, radar_detected);
- /*
- * TODO: forward radar event to DFS management layer
- */
+ ieee80211_radar_detected(sc->hw);
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 55d28072adeb..b7611b7bbe43 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -105,6 +105,24 @@ static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
return count;
}
+static ssize_t write_file_simulate_radar(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+
+ ieee80211_radar_detected(sc->hw);
+
+ return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+ .write = write_file_simulate_radar,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static const struct file_operations fops_dfs_stats = {
.read = read_file_dfs,
.write = write_file_dfs,
@@ -117,4 +135,6 @@ void ath9k_dfs_init_debug(struct ath_softc *sc)
{
debugfs_create_file("dfs_stats", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dfs_stats);
+ debugfs_create_file("dfs_simulate_radar", S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_simulate_radar);
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
index 467b60014b7b..491305c81fce 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
@@ -19,6 +19,7 @@
#include "dfs_pattern_detector.h"
#include "dfs_pri_detector.h"
+#include "ath9k.h"
/*
* tolerated deviation of radar time stamp in usecs on both sides
@@ -142,15 +143,16 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)
{
u32 sz, i;
struct channel_detector *cd;
+ struct ath_common *common = ath9k_hw_common(dpd->ah);
- cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+ cd = kmalloc(sizeof(*cd), GFP_ATOMIC);
if (cd == NULL)
goto fail;
INIT_LIST_HEAD(&cd->head);
cd->freq = freq;
sz = sizeof(cd->detectors) * dpd->num_radar_types;
- cd->detectors = kzalloc(sz, GFP_KERNEL);
+ cd->detectors = kzalloc(sz, GFP_ATOMIC);
if (cd->detectors == NULL)
goto fail;
@@ -165,7 +167,8 @@ channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)
return cd;
fail:
- pr_err("failed to allocate channel_detector for freq=%d\n", freq);
+ ath_dbg(common, DFS,
+ "failed to allocate channel_detector for freq=%d\n", freq);
channel_detector_exit(dpd, cd);
return NULL;
}
@@ -216,34 +219,34 @@ static bool
dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event)
{
u32 i;
- bool ts_wraparound;
struct channel_detector *cd;
- if (dpd->region == NL80211_DFS_UNSET) {
- /*
- * pulses received for a non-supported or un-initialized
- * domain are treated as detected radars
- */
+ /*
+ * pulses received for a non-supported or un-initialized
+ * domain are treated as detected radars for fail-safety
+ */
+ if (dpd->region == NL80211_DFS_UNSET)
return true;
- }
cd = channel_detector_get(dpd, event->freq);
if (cd == NULL)
return false;
- ts_wraparound = (event->ts < dpd->last_pulse_ts);
dpd->last_pulse_ts = event->ts;
- if (ts_wraparound) {
- /*
- * reset detector on time stamp wraparound
- * with monotonic time stamps, this should never happen
- */
- pr_warn("DFS: time stamp wraparound detected, resetting\n");
+ /* reset detector on time stamp wraparound, caused by TSF reset */
+ if (event->ts < dpd->last_pulse_ts)
dpd_reset(dpd);
- }
+
/* do type individual pattern matching */
for (i = 0; i < dpd->num_radar_types; i++) {
- if (cd->detectors[i]->add_pulse(cd->detectors[i], event) != 0) {
+ struct pri_detector *pd = cd->detectors[i];
+ struct pri_sequence *ps = pd->add_pulse(pd, event);
+ if (ps != NULL) {
+ ath_dbg(ath9k_hw_common(dpd->ah), DFS,
+ "DFS: radar found on freq=%d: id=%d, pri=%d, "
+ "count=%d, count_false=%d\n",
+ event->freq, pd->rs->type_id,
+ ps->pri, ps->count, ps->count_falses);
channel_detector_reset(dpd, cd);
return true;
}
@@ -285,9 +288,10 @@ static struct dfs_pattern_detector default_dpd = {
};
struct dfs_pattern_detector *
-dfs_pattern_detector_init(enum nl80211_dfs_regions region)
+dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region)
{
struct dfs_pattern_detector *dpd;
+ struct ath_common *common = ath9k_hw_common(ah);
dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);
if (dpd == NULL)
@@ -296,10 +300,11 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region)
*dpd = default_dpd;
INIT_LIST_HEAD(&dpd->channel_detectors);
+ dpd->ah = ah;
if (dpd->set_dfs_domain(dpd, region))
return dpd;
- pr_err("Could not set DFS domain to %d. ", region);
+ ath_dbg(common, DFS,"Could not set DFS domain to %d", region);
kfree(dpd);
return NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
index cda52f39f28a..90a5abcc4265 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
@@ -80,6 +80,8 @@ struct dfs_pattern_detector {
enum nl80211_dfs_regions region;
u8 num_radar_types;
u64 last_pulse_ts;
+ /* needed for ath_dbg() */
+ struct ath_hw *ah;
const struct radar_detector_specs *radar_spec;
struct list_head channel_detectors;
@@ -92,10 +94,10 @@ struct dfs_pattern_detector {
*/
#if defined(CONFIG_ATH9K_DFS_CERTIFIED)
extern struct dfs_pattern_detector *
-dfs_pattern_detector_init(enum nl80211_dfs_regions region);
+dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region);
#else
static inline struct dfs_pattern_detector *
-dfs_pattern_detector_init(enum nl80211_dfs_regions region)
+dfs_pattern_detector_init(struct ath_hw *ah, enum nl80211_dfs_regions region)
{
return NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
index 91b8dceeadb1..5ba4b6fe37c0 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
@@ -23,28 +23,6 @@
#include "dfs_debug.h"
/**
- * struct pri_sequence - sequence of pulses matching one PRI
- * @head: list_head
- * @pri: pulse repetition interval (PRI) in usecs
- * @dur: duration of sequence in usecs
- * @count: number of pulses in this sequence
- * @count_falses: number of not matching pulses in this sequence
- * @first_ts: time stamp of first pulse in usecs
- * @last_ts: time stamp of last pulse in usecs
- * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
- */
-struct pri_sequence {
- struct list_head head;
- u32 pri;
- u32 dur;
- u32 count;
- u32 count_falses;
- u64 first_ts;
- u64 last_ts;
- u64 deadline_ts;
-};
-
-/**
* struct pulse_elem - elements in pulse queue
* @ts: time stamp in usecs
*/
@@ -218,7 +196,7 @@ static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
{
struct pulse_elem *p = pool_get_pulse_elem();
if (p == NULL) {
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
if (p == NULL) {
DFS_POOL_STAT_INC(pulse_alloc_error);
return false;
@@ -299,7 +277,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
ps.deadline_ts = ps.first_ts + ps.dur;
new_ps = pool_get_pseq_elem();
if (new_ps == NULL) {
- new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL);
+ new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC);
if (new_ps == NULL) {
DFS_POOL_STAT_INC(pseq_alloc_error);
return false;
@@ -393,8 +371,8 @@ static void pri_detector_exit(struct pri_detector *de)
kfree(de);
}
-static bool pri_detector_add_pulse(struct pri_detector *de,
- struct pulse_event *event)
+static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,
+ struct pulse_event *event)
{
u32 max_updated_seq;
struct pri_sequence *ps;
@@ -403,38 +381,33 @@ static bool pri_detector_add_pulse(struct pri_detector *de,
/* ignore pulses not within width range */
if ((rs->width_min > event->width) || (rs->width_max < event->width))
- return false;
+ return NULL;
if ((ts - de->last_ts) < rs->max_pri_tolerance)
/* if delta to last pulse is too short, don't use this pulse */
- return false;
+ return NULL;
de->last_ts = ts;
max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts);
if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) {
- pr_err("failed to create pulse sequences\n");
pri_detector_reset(de, ts);
return false;
}
ps = pseq_handler_check_detection(de);
- if (ps != NULL) {
- pr_info("DFS: radar found: pri=%d, count=%d, count_false=%d\n",
- ps->pri, ps->count, ps->count_falses);
- pri_detector_reset(de, ts);
- return true;
- }
- pulse_queue_enqueue(de, ts);
- return false;
+ if (ps == NULL)
+ pulse_queue_enqueue(de, ts);
+
+ return ps;
}
-struct pri_detector *
-pri_detector_init(const struct radar_detector_specs *rs)
+struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs)
{
struct pri_detector *de;
- de = kzalloc(sizeof(*de), GFP_KERNEL);
+
+ de = kzalloc(sizeof(*de), GFP_ATOMIC);
if (de == NULL)
return NULL;
de->exit = pri_detector_exit;
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h
index 81cde9f28e44..723962d1abc6 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h
@@ -20,9 +20,31 @@
#include <linux/list.h>
/**
+ * struct pri_sequence - sequence of pulses matching one PRI
+ * @head: list_head
+ * @pri: pulse repetition interval (PRI) in usecs
+ * @dur: duration of sequence in usecs
+ * @count: number of pulses in this sequence
+ * @count_falses: number of not matching pulses in this sequence
+ * @first_ts: time stamp of first pulse in usecs
+ * @last_ts: time stamp of last pulse in usecs
+ * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
+ */
+struct pri_sequence {
+ struct list_head head;
+ u32 pri;
+ u32 dur;
+ u32 count;
+ u32 count_falses;
+ u64 first_ts;
+ u64 last_ts;
+ u64 deadline_ts;
+};
+
+/**
* struct pri_detector - PRI detector element for a dedicated radar type
* @exit(): destructor
- * @add_pulse(): add pulse event, returns true if pattern was detected
+ * @add_pulse(): add pulse event, returns pri_sequence if pattern was detected
* @reset(): clear states and reset to given time stamp
* @rs: detector specs for this detector element
* @last_ts: last pulse time stamp considered for this element in usecs
@@ -34,7 +56,8 @@
*/
struct pri_detector {
void (*exit) (struct pri_detector *de);
- bool (*add_pulse)(struct pri_detector *de, struct pulse_event *e);
+ struct pri_sequence *
+ (*add_pulse)(struct pri_detector *de, struct pulse_event *e);
void (*reset) (struct pri_detector *de, u64 ts);
/* private: internal use only */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index d0ce1f5bba10..f13f458dd656 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -308,7 +308,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
while(skb) {
hdr = (struct ieee80211_hdr *) skb->data;
- padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
if (skb_headroom(skb) < padsize) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index 716058b67557..a47f5e05fc04 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -796,7 +796,7 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
* required version.
*/
if (priv->fw_version_major != MAJOR_VERSION_REQ ||
- priv->fw_version_minor != MINOR_VERSION_REQ) {
+ priv->fw_version_minor < MINOR_VERSION_REQ) {
dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index a8016d70088a..0743a47cef8f 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -190,7 +190,7 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
{
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_channel *channel = priv->hw->conf.channel;
+ struct ieee80211_channel *channel = priv->hw->conf.chandef.chan;
struct ath9k_hw_cal_data *caldata = NULL;
enum htc_phymode mode;
__be16 htc_mode;
@@ -250,7 +250,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_conf *conf = &common->hw->conf;
bool fastcc;
- struct ieee80211_channel *channel = hw->conf.channel;
+ struct ieee80211_channel *channel = hw->conf.chandef.chan;
struct ath9k_hw_cal_data *caldata = NULL;
enum htc_phymode mode;
__be16 htc_mode;
@@ -602,7 +602,7 @@ static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
u32 caps = 0;
int i, j;
- sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
+ sband = priv->hw->wiphy->bands[priv->hw->conf.chandef.chan->band];
for (i = 0, j = 0; i < sband->n_bitrates; i++) {
if (sta->supp_rates[sband->band] & BIT(i)) {
@@ -866,7 +866,7 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw,
hdr = (struct ieee80211_hdr *) skb->data;
/* Add the padding after the header if this is not already done */
- padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
if (skb_headroom(skb) < padsize) {
@@ -904,7 +904,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
struct ath9k_channel *init_channel;
int ret = 0;
enum htc_phymode mode;
@@ -1193,15 +1193,17 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) {
- struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&hw->conf.chandef);
int pos = curchan->hw_value;
ath_dbg(common, CONFIG, "Set channel: %d MHz\n",
curchan->center_freq);
ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
- hw->conf.channel,
- hw->conf.channel_type);
+ hw->conf.chandef.chan,
+ channel_type);
if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
ath_err(common, "Unable to set channel\n");
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index bd8251c1c749..6bd0e92ea2aa 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -490,7 +490,7 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
} else {
- if (cur_conf->channel->band == IEEE80211_BAND_5GHZ)
+ if (cur_conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
rate->idx += 4; /* No CCK rates */
}
@@ -939,7 +939,7 @@ static void ath9k_process_rate(struct ieee80211_hw *hw,
return;
}
- band = hw->conf.channel->band;
+ band = hw->conf.chandef.chan->band;
sband = hw->wiphy->bands[band];
for (i = 0; i < sband->n_bitrates; i++) {
@@ -966,7 +966,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
struct sk_buff *skb = rxbuf->skb;
struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath_htc_rx_status *rxstatus;
- int hdrlen, padpos, padsize;
+ int hdrlen, padsize;
int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc;
@@ -996,11 +996,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
fc = hdr->frame_control;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- padpos = ath9k_cmn_padpos(fc);
-
- padsize = padpos & 3;
- if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
- memmove(skb->data + padsize, skb->data, padpos);
+ padsize = hdrlen & 3;
+ if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) {
+ memmove(skb->data + padsize, skb->data, hdrlen);
skb_pull(skb, padsize);
}
@@ -1082,8 +1080,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
}
rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
- rx_status->band = hw->conf.channel->band;
- rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
rx_status->antenna = rxbuf->rxstatus.rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_END;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 07e25260c31d..7f25da8444fe 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -139,7 +139,7 @@ static void ath9k_hw_set_clockrate(struct ath_hw *ah)
clockrate = 117;
else if (!ah->curchan) /* should really check for CCK instead */
clockrate = ATH9K_CLOCK_RATE_CCK;
- else if (conf->channel->band == IEEE80211_BAND_2GHZ)
+ else if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
@@ -1100,7 +1100,8 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
}
/* As defined by IEEE 802.11-2007 17.3.8.6 */
- acktimeout = slottime + sifstime + 3 * ah->coverage_class + ack_offset;
+ slottime += 3 * ah->coverage_class;
+ acktimeout = slottime + sifstime + ack_offset;
ctstimeout = acktimeout;
/*
@@ -1110,7 +1111,8 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
* BA frames in some implementations, but it has been found to fix ACK
* timeout issues in other cases as well.
*/
- if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ &&
+ if (conf->chandef.chan &&
+ conf->chandef.chan->band == IEEE80211_BAND_2GHZ &&
!IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) {
acktimeout += 64 - sifstime - ah->slottime;
ctstimeout += 48 - sifstime - ah->slottime;
@@ -1669,6 +1671,103 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_check_alive);
+static void ath9k_hw_init_mfp(struct ath_hw *ah)
+{
+ /* Setup MFP options for CCMP */
+ if (AR_SREV_9280_20_OR_LATER(ah)) {
+ /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
+ * frames when constructing CCMP AAD. */
+ REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
+ 0xc7ff);
+ ah->sw_mgmt_crypto = false;
+ } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+ /* Disable hardware crypto for management frames */
+ REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
+ REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+ AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
+ ah->sw_mgmt_crypto = true;
+ } else {
+ ah->sw_mgmt_crypto = true;
+ }
+}
+
+static void ath9k_hw_reset_opmode(struct ath_hw *ah,
+ u32 macStaId1, u32 saveDefAntenna)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+ REG_RMW(ah, AR_STA_ID1, macStaId1
+ | AR_STA_ID1_RTS_USE_DEF
+ | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
+ | ah->sta_id1_defaults,
+ ~AR_STA_ID1_SADH_MASK);
+ ath_hw_setbssidmask(common);
+ REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
+ ath9k_hw_write_associd(ah);
+ REG_WRITE(ah, AR_ISR, ~0);
+ REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+
+ ath9k_hw_set_operating_mode(ah, ah->opmode);
+}
+
+static void ath9k_hw_init_queues(struct ath_hw *ah)
+{
+ int i;
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+ for (i = 0; i < AR_NUM_DCU; i++)
+ REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
+
+ REGWRITE_BUFFER_FLUSH(ah);
+
+ ah->intr_txqs = 0;
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ ath9k_hw_resettxqueue(ah, i);
+}
+
+/*
+ * For big endian systems turn on swapping for descriptors
+ */
+static void ath9k_hw_init_desc(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (AR_SREV_9100(ah)) {
+ u32 mask;
+ mask = REG_READ(ah, AR_CFG);
+ if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
+ ath_dbg(common, RESET, "CFG Byte Swap Set 0x%x\n",
+ mask);
+ } else {
+ mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
+ REG_WRITE(ah, AR_CFG, mask);
+ ath_dbg(common, RESET, "Setting CFG 0x%x\n",
+ REG_READ(ah, AR_CFG));
+ }
+ } else {
+ if (common->bus_ops->ath_bus_type == ATH_USB) {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ }
+#ifdef __BIG_ENDIAN
+ else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
+ AR_SREV_9550(ah))
+ REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+#endif
+ }
+}
+
/*
* Fast channel change:
* (Change synthesizer based on channel freq without resetting chip)
@@ -1746,7 +1845,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
u32 saveDefAntenna;
u32 macStaId1;
u64 tsf = 0;
- int i, r;
+ int r;
bool start_mci_reset = false;
bool save_fullsleep = ah->chip_fullsleep;
@@ -1763,10 +1862,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_getnf(ah, ah->curchan);
ah->caldata = caldata;
- if (caldata &&
- (chan->channel != caldata->channel ||
- (chan->channelFlags & ~CHANNEL_CW_INT) !=
- (caldata->channelFlags & ~CHANNEL_CW_INT))) {
+ if (caldata && (chan->channel != caldata->channel ||
+ chan->channelFlags != caldata->channelFlags)) {
/* Operating channel changed, reset channel calibration data */
memset(caldata, 0, sizeof(*caldata));
ath9k_init_nfcal_hist_buffer(ah, chan);
@@ -1853,22 +1950,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_settsf64(ah, tsf);
}
- /* Setup MFP options for CCMP */
- if (AR_SREV_9280_20_OR_LATER(ah)) {
- /* Mask Retry(b11), PwrMgt(b12), MoreData(b13) to 0 in mgmt
- * frames when constructing CCMP AAD. */
- REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT,
- 0xc7ff);
- ah->sw_mgmt_crypto = false;
- } else if (AR_SREV_9160_10_OR_LATER(ah)) {
- /* Disable hardware crypto for management frames */
- REG_CLR_BIT(ah, AR_PCU_MISC_MODE2,
- AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE);
- REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
- AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT);
- ah->sw_mgmt_crypto = true;
- } else
- ah->sw_mgmt_crypto = true;
+ ath9k_hw_init_mfp(ah);
if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
ath9k_hw_set_delta_slope(ah, chan);
@@ -1876,24 +1958,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_spur_mitigate_freq(ah, chan);
ah->eep_ops->set_board_values(ah, chan);
- ENABLE_REGWRITE_BUFFER(ah);
-
- REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
- REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
- | macStaId1
- | AR_STA_ID1_RTS_USE_DEF
- | (ah->config.
- ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
- | ah->sta_id1_defaults);
- ath_hw_setbssidmask(common);
- REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
- ath9k_hw_write_associd(ah);
- REG_WRITE(ah, AR_ISR, ~0);
- REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
-
- REGWRITE_BUFFER_FLUSH(ah);
-
- ath9k_hw_set_operating_mode(ah, ah->opmode);
+ ath9k_hw_reset_opmode(ah, macStaId1, saveDefAntenna);
r = ath9k_hw_rf_set_freq(ah, chan);
if (r)
@@ -1901,17 +1966,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_set_clockrate(ah);
- ENABLE_REGWRITE_BUFFER(ah);
-
- for (i = 0; i < AR_NUM_DCU; i++)
- REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
-
- REGWRITE_BUFFER_FLUSH(ah);
-
- ah->intr_txqs = 0;
- for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
- ath9k_hw_resettxqueue(ah, i);
-
+ ath9k_hw_init_queues(ah);
ath9k_hw_init_interrupt_masks(ah, ah->opmode);
ath9k_hw_ani_cache_ini_regs(ah);
ath9k_hw_init_qos(ah);
@@ -1966,38 +2021,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REGWRITE_BUFFER_FLUSH(ah);
- /*
- * For big endian systems turn on swapping for descriptors
- */
- if (AR_SREV_9100(ah)) {
- u32 mask;
- mask = REG_READ(ah, AR_CFG);
- if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) {
- ath_dbg(common, RESET, "CFG Byte Swap Set 0x%x\n",
- mask);
- } else {
- mask =
- INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB;
- REG_WRITE(ah, AR_CFG, mask);
- ath_dbg(common, RESET, "Setting CFG 0x%x\n",
- REG_READ(ah, AR_CFG));
- }
- } else {
- if (common->bus_ops->ath_bus_type == ATH_USB) {
- /* Configure AR9271 target WLAN */
- if (AR_SREV_9271(ah))
- REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
- else
- REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
- }
-#ifdef __BIG_ENDIAN
- else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
- AR_SREV_9550(ah))
- REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
- else
- REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
-#endif
- }
+ ath9k_hw_init_desc(ah);
if (ath9k_hw_btcoex_is_enabled(ah))
ath9k_hw_btcoex_enable(ah);
@@ -2010,7 +2034,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9300_20_OR_LATER(ah)) {
ar9003_hw_bb_watchdog_config(ah);
-
ar9003_hw_disable_phy_restart(ah);
}
@@ -2358,8 +2381,11 @@ static bool ath9k_hw_dfs_tested(struct ath_hw *ah)
{
switch (ah->hw_version.macVersion) {
+ /* for temporary testing DFS with 9280 */
+ case AR_SREV_VERSION_9280:
/* AR9580 will likely be our first target to get testing on */
case AR_SREV_VERSION_9580:
+ return true;
default:
return false;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 784e81ccb903..ae3034374bc4 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -363,7 +363,6 @@ enum ath9k_int {
ATH9K_INT_NOCARD = 0xffffffff
};
-#define CHANNEL_CW_INT 0x00002
#define CHANNEL_CCK 0x00020
#define CHANNEL_OFDM 0x00040
#define CHANNEL_2GHZ 0x00080
@@ -848,14 +847,7 @@ struct ath_hw {
struct ath_hw_ops ops;
/* Used to program the radio on non single-chip devices */
- u32 *analogBank0Data;
- u32 *analogBank1Data;
- u32 *analogBank2Data;
- u32 *analogBank3Data;
u32 *analogBank6Data;
- u32 *analogBank6TPCData;
- u32 *analogBank7Data;
- u32 *bank6Temp;
int coverage_class;
u32 slottime;
@@ -886,14 +878,8 @@ struct ath_hw {
struct ar5416IniArray iniModes;
struct ar5416IniArray iniCommon;
- struct ar5416IniArray iniBank0;
struct ar5416IniArray iniBB_RfGain;
- struct ar5416IniArray iniBank1;
- struct ar5416IniArray iniBank2;
- struct ar5416IniArray iniBank3;
struct ar5416IniArray iniBank6;
- struct ar5416IniArray iniBank6TPC;
- struct ar5416IniArray iniBank7;
struct ar5416IniArray iniAddac;
struct ar5416IniArray iniPcieSerdes;
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index af932c9444de..0237b2868961 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -319,6 +319,10 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_ps_wakeup(sc);
ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit;
+ /* synchronize DFS detector if regulatory domain changed */
+ if (sc->dfs_detector != NULL)
+ sc->dfs_detector->set_dfs_domain(sc->dfs_detector,
+ request->dfs_region);
ath9k_ps_restore(sc);
}
}
@@ -573,7 +577,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
atomic_set(&ah->intr_ref_cnt, -1);
sc->sc_ah = ah;
- sc->dfs_detector = dfs_pattern_detector_init(NL80211_DFS_UNSET);
+ sc->dfs_detector = dfs_pattern_detector_init(ah, NL80211_DFS_UNSET);
if (!pdata) {
ah->ah_flags |= AH_USE_EEPROM;
@@ -727,12 +731,28 @@ static const struct ieee80211_iface_limit if_limits[] = {
BIT(NL80211_IFTYPE_P2P_GO) },
};
-static const struct ieee80211_iface_combination if_comb = {
- .limits = if_limits,
- .n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = 2048,
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+ { .max = 1, .types = BIT(NL80211_IFTYPE_AP) },
+};
+
+static const struct ieee80211_iface_combination if_comb[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = 2048,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ },
+ {
+ .limits = if_dfs_limits,
+ .n_limits = ARRAY_SIZE(if_dfs_limits),
+ .max_interfaces = 1,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) |
+ BIT(NL80211_CHAN_HT20),
+ }
};
void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
@@ -746,7 +766,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_SPECTRUM_MGMT |
- IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_SUPPORTS_RC_TABLE;
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
@@ -763,8 +784,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->wiphy->iface_combinations = &if_comb;
- hw->wiphy->n_iface_combinations = 1;
+ hw->wiphy->iface_combinations = if_comb;
+ hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
if (AR_SREV_5416(sc->sc_ah))
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 39c84ecf6a42..849259b07370 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
- ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+ if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
+ ieee80211_queue_work(sc->hw, &sc->hw_check_work);
}
/*
@@ -213,7 +214,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
memset(tx_info, 0, sizeof(*tx_info));
- tx_info->band = hw->conf.channel->band;
+ tx_info->band = hw->conf.chandef.chan->band;
tx_info->flags |= IEEE80211_TX_CTL_NO_ACK;
tx_info->control.rates[0].idx = 0;
tx_info->control.rates[0].count = 1;
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 811007ec07a7..498fee04afa0 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -615,6 +615,14 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
rs->rs_status |= ATH9K_RXERR_DECRYPT;
else if (ads.ds_rxstatus8 & AR_MichaelErr)
rs->rs_status |= ATH9K_RXERR_MIC;
+ } else {
+ if (ads.ds_rxstatus8 &
+ (AR_CRCErr | AR_PHYErr | AR_DecryptCRCErr | AR_MichaelErr))
+ rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
+
+ /* Only up to MCS16 supported, everything above is invalid */
+ if (rs->rs_rate >= 0x90)
+ rs->rs_status |= ATH9K_RXERR_CORRUPT_DESC;
}
if (ads.ds_rxstatus8 & AR_KeyMiss)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 1ff817061ebc..5865f92998e1 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -183,6 +183,7 @@ struct ath_htc_rx_status {
#define ATH9K_RXERR_DECRYPT 0x08
#define ATH9K_RXERR_MIC 0x10
#define ATH9K_RXERR_KEYMISS 0x20
+#define ATH9K_RXERR_CORRUPT_DESC 0x40
#define ATH9K_RX_MORE 0x01
#define ATH9K_RX_MORE_AGGR 0x02
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 6e66f9c6782b..6963862a1872 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -280,6 +280,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
if (r) {
ath_err(common,
"Unable to reset channel, reset status %d\n", r);
+
+ ath9k_hw_enable_interrupts(ah);
+ ath9k_queue_reset(sc, RESET_TYPE_BB_HANG);
+
goto out;
}
@@ -585,7 +589,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
struct ath9k_channel *init_channel;
int r;
@@ -835,10 +839,14 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
struct ath9k_vif_iter_data *iter_data = data;
int i;
- if (iter_data->hw_macaddr)
+ if (iter_data->has_hw_macaddr) {
for (i = 0; i < ETH_ALEN; i++)
iter_data->mask[i] &=
~(iter_data->hw_macaddr[i] ^ mac[i]);
+ } else {
+ memcpy(iter_data->hw_macaddr, mac, ETH_ALEN);
+ iter_data->has_hw_macaddr = true;
+ }
switch (vif->type) {
case NL80211_IFTYPE_AP:
@@ -887,7 +895,6 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
* together with the BSSID mask when matching addresses.
*/
memset(iter_data, 0, sizeof(*iter_data));
- iter_data->hw_macaddr = common->macaddr;
memset(&iter_data->mask, 0xff, ETH_ALEN);
if (vif)
@@ -897,6 +904,8 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
ieee80211_iterate_active_interfaces_atomic(
sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
ath9k_vif_iter, iter_data);
+
+ memcpy(common->macaddr, iter_data->hw_macaddr, ETH_ALEN);
}
/* Called with sc->mutex held. */
@@ -1184,7 +1193,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
}
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
- struct ieee80211_channel *curchan = hw->conf.channel;
+ struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&conf->chandef);
int pos = curchan->hw_value;
int old_pos = -1;
unsigned long flags;
@@ -1193,7 +1204,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
old_pos = ah->curchan - &ah->channels[0];
ath_dbg(common, CONFIG, "Set channel: %d MHz type: %d\n",
- curchan->center_freq, conf->channel_type);
+ curchan->center_freq, channel_type);
/* update survey stats for the old channel before switching */
spin_lock_irqsave(&common->cc_lock, flags);
@@ -1208,7 +1219,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
ath9k_hw_getnf(ah, ah->curchan);
ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
- curchan, conf->channel_type);
+ curchan, channel_type);
/*
* If the operating channel changes, change the survey in-use flags
@@ -1245,10 +1256,27 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (old_pos >= 0)
ath_update_survey_nf(sc, old_pos);
- /* perform spectral scan if requested. */
- if (sc->scanning && sc->spectral_mode == SPECTRAL_CHANSCAN)
- ath9k_spectral_scan_trigger(hw);
-
+ /*
+ * Enable radar pulse detection if on a DFS channel. Spectral
+ * scanning and radar detection can not be used concurrently.
+ */
+ if (hw->conf.radar_enabled) {
+ u32 rxfilter;
+
+ /* set HW specific DFS configuration */
+ ath9k_hw_set_radar_params(ah);
+ rxfilter = ath9k_hw_getrxfilter(ah);
+ rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
+ ATH9K_RX_FILTER_PHYERR;
+ ath9k_hw_setrxfilter(ah, rxfilter);
+ ath_dbg(common, DFS, "DFS enabled at freq %d\n",
+ curchan->center_freq);
+ } else {
+ /* perform spectral scan if requested. */
+ if (sc->scanning &&
+ sc->spectral_mode == SPECTRAL_CHANSCAN)
+ ath9k_spectral_scan_trigger(hw);
+ }
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -1745,7 +1773,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
mutex_unlock(&sc->mutex);
}
-static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
+static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 96ac433ba7f6..aa4d368d8d3d 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -814,7 +814,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
* So, set fourth rate in series to be same as third one for
* above conditions.
*/
- if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) &&
+ if ((sc->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) &&
(conf_is_ht(&sc->hw->conf))) {
u8 dot11rate = rate_table->info[rix].dot11rate;
u8 phy = rate_table->info[rix].phy;
@@ -1328,7 +1328,7 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
"Operating HT Bandwidth changed to: %d\n",
- sc->hw->conf.channel_type);
+ cfg80211_get_chandef_type(&sc->hw->conf.chandef));
}
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ee156e543147..8be2b5d8c155 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -124,13 +124,13 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc,
SKB_CB_ATHBUF(skb) = bf;
ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype);
- skb_queue_tail(&rx_edma->rx_fifo, skb);
+ __skb_queue_tail(&rx_edma->rx_fifo, skb);
return true;
}
static void ath_rx_addbuffer_edma(struct ath_softc *sc,
- enum ath9k_rx_qtype qtype, int size)
+ enum ath9k_rx_qtype qtype)
{
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf, *tbf;
@@ -155,7 +155,7 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
rx_edma = &sc->rx.rx_edma[qtype];
- while ((skb = skb_dequeue(&rx_edma->rx_fifo)) != NULL) {
+ while ((skb = __skb_dequeue(&rx_edma->rx_fifo)) != NULL) {
bf = SKB_CB_ATHBUF(skb);
BUG_ON(!bf);
list_add_tail(&bf->list, &sc->rx.rxbuf);
@@ -250,15 +250,9 @@ rx_init_fail:
static void ath_edma_start_recv(struct ath_softc *sc)
{
ath9k_hw_rxena(sc->sc_ah);
-
- ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP,
- sc->rx.rx_edma[ATH9K_RX_QUEUE_HP].rx_fifo_hwsize);
-
- ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP,
- sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize);
-
+ ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP);
+ ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP);
ath_opmode_init(sc);
-
ath9k_hw_startpcureceive(sc->sc_ah, !!(sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL));
}
@@ -280,49 +274,47 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc->sc_ah->caps.rx_status_len;
- if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
return ath_rx_edma_init(sc, nbufs);
- } else {
- ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n",
- common->cachelsz, common->rx_bufsize);
- /* Initialize rx descriptors */
+ ath_dbg(common, CONFIG, "cachelsz %u rxbufsize %u\n",
+ common->cachelsz, common->rx_bufsize);
- error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
- "rx", nbufs, 1, 0);
- if (error != 0) {
- ath_err(common,
- "failed to allocate rx descriptors: %d\n",
- error);
+ /* Initialize rx descriptors */
+
+ error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
+ "rx", nbufs, 1, 0);
+ if (error != 0) {
+ ath_err(common,
+ "failed to allocate rx descriptors: %d\n",
+ error);
+ goto err;
+ }
+
+ list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+ skb = ath_rxbuf_alloc(common, common->rx_bufsize,
+ GFP_KERNEL);
+ if (skb == NULL) {
+ error = -ENOMEM;
goto err;
}
- list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = ath_rxbuf_alloc(common, common->rx_bufsize,
- GFP_KERNEL);
- if (skb == NULL) {
- error = -ENOMEM;
- goto err;
- }
-
- bf->bf_mpdu = skb;
- bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
- common->rx_bufsize,
- DMA_FROM_DEVICE);
- if (unlikely(dma_mapping_error(sc->dev,
- bf->bf_buf_addr))) {
- dev_kfree_skb_any(skb);
- bf->bf_mpdu = NULL;
- bf->bf_buf_addr = 0;
- ath_err(common,
- "dma_mapping_error() on RX init\n");
- error = -ENOMEM;
- goto err;
- }
+ bf->bf_mpdu = skb;
+ bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+ common->rx_bufsize,
+ DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(sc->dev,
+ bf->bf_buf_addr))) {
+ dev_kfree_skb_any(skb);
+ bf->bf_mpdu = NULL;
+ bf->bf_buf_addr = 0;
+ ath_err(common,
+ "dma_mapping_error() on RX init\n");
+ error = -ENOMEM;
+ goto err;
}
- sc->rx.rxlink = NULL;
}
-
+ sc->rx.rxlink = NULL;
err:
if (error)
ath_rx_cleanup(sc);
@@ -340,17 +332,17 @@ void ath_rx_cleanup(struct ath_softc *sc)
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
ath_rx_edma_cleanup(sc);
return;
- } else {
- list_for_each_entry(bf, &sc->rx.rxbuf, list) {
- skb = bf->bf_mpdu;
- if (skb) {
- dma_unmap_single(sc->dev, bf->bf_buf_addr,
- common->rx_bufsize,
- DMA_FROM_DEVICE);
- dev_kfree_skb(skb);
- bf->bf_buf_addr = 0;
- bf->bf_mpdu = NULL;
- }
+ }
+
+ list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+ skb = bf->bf_mpdu;
+ if (skb) {
+ dma_unmap_single(sc->dev, bf->bf_buf_addr,
+ common->rx_bufsize,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(skb);
+ bf->bf_buf_addr = 0;
+ bf->bf_mpdu = NULL;
}
}
}
@@ -381,6 +373,10 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
| ATH9K_RX_FILTER_MCAST;
+ /* if operating on a DFS channel, enable radar pulse detection */
+ if (sc->hw->conf.radar_enabled)
+ rfilt |= ATH9K_RX_FILTER_PHYRADAR | ATH9K_RX_FILTER_PHYERR;
+
if (sc->rx.rxfilter & FIF_PROBE_REQ)
rfilt |= ATH9K_RX_FILTER_PROBEREQ;
@@ -723,6 +719,13 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
ret = ath9k_hw_rxprocdesc(ah, tds, &trs);
if (ret == -EINPROGRESS)
return NULL;
+
+ /*
+ * mark descriptor as zero-length and set the 'more'
+ * flag to ensure that both buffers get discarded
+ */
+ rs->rs_datalen = 0;
+ rs->rs_more = true;
}
list_del(&bf->list);
@@ -859,7 +862,7 @@ static int ath9k_process_rate(struct ath_common *common,
unsigned int i = 0;
struct ath_softc __maybe_unused *sc = common->priv;
- band = hw->conf.channel->band;
+ band = hw->conf.chandef.chan->band;
sband = hw->wiphy->bands[band];
if (rx_stats->rs_rate & 0x80) {
@@ -929,14 +932,20 @@ static void ath9k_process_rssi(struct ath_common *common,
* up the frame up to let mac80211 handle the actual error case, be it no
* decryption key or real decryption error. This let us keep statistics there.
*/
-static int ath9k_rx_skb_preprocess(struct ath_common *common,
- struct ieee80211_hw *hw,
+static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
struct ieee80211_hdr *hdr,
struct ath_rx_status *rx_stats,
struct ieee80211_rx_status *rx_status,
bool *decrypt_error)
{
- struct ath_hw *ah = common->ah;
+ struct ieee80211_hw *hw = sc->hw;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ bool discard_current = sc->rx.discard_next;
+
+ sc->rx.discard_next = rx_stats->rs_more;
+ if (discard_current)
+ return -EINVAL;
/*
* everything but the rate is checked here, the rate check is done
@@ -954,14 +963,15 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
if (ath9k_process_rate(common, hw, rx_stats, rx_status))
return -EINVAL;
- rx_status->band = hw->conf.channel->band;
- rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->signal = ah->noise + rx_stats->rs_rssi;
rx_status->antenna = rx_stats->rs_antenna;
rx_status->flag |= RX_FLAG_MACTIME_END;
if (rx_stats->rs_moreaggr)
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+ sc->rx.discard_next = false;
return 0;
}
@@ -981,7 +991,7 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
hdr = (struct ieee80211_hdr *) skb->data;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
- padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padpos = ieee80211_hdrlen(fc);
/* The MAC header is padded to have 32-bit boundary if the
* packet payload is non-zero. The general calculation for
@@ -1162,6 +1172,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
u64 tsf = 0;
u32 tsf_lower = 0;
unsigned long flags;
+ dma_addr_t new_buf_addr;
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@@ -1228,6 +1239,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
unlikely(tsf_lower - rs.rs_tstamp > 0x10000000))
rxs->mactime += 0x100000000ULL;
+ if (rs.rs_phyerr == ATH9K_PHYERR_RADAR)
+ ath9k_dfs_process_phyerr(sc, hdr, &rs, rxs->mactime);
+
if (rs.rs_status & ATH9K_RXERR_PHY) {
if (ath_process_fft(sc, hdr, &rs, rxs->mactime)) {
RX_STAT_INC(rx_spectral);
@@ -1235,8 +1249,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
}
}
- retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
- rxs, &decrypt_error);
+ retval = ath9k_rx_skb_preprocess(sc, hdr, &rs, rxs,
+ &decrypt_error);
if (retval)
goto requeue_drop_frag;
@@ -1257,10 +1271,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
goto requeue_drop_frag;
}
+ /* We will now give hardware our shiny new allocated skb */
+ new_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
+ common->rx_bufsize, dma_type);
+ if (unlikely(dma_mapping_error(sc->dev, new_buf_addr))) {
+ dev_kfree_skb_any(requeue_skb);
+ goto requeue_drop_frag;
+ }
+
/* Unmap the frame */
dma_unmap_single(sc->dev, bf->bf_buf_addr,
- common->rx_bufsize,
- dma_type);
+ common->rx_bufsize, dma_type);
+
+ bf->bf_mpdu = requeue_skb;
+ bf->bf_buf_addr = new_buf_addr;
skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len);
if (ah->caps.rx_status_len)
@@ -1270,21 +1294,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ath9k_rx_skb_postprocess(common, hdr_skb, &rs,
rxs, decrypt_error);
- /* We will now give hardware our shiny new allocated skb */
- bf->bf_mpdu = requeue_skb;
- bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
- common->rx_bufsize,
- dma_type);
- if (unlikely(dma_mapping_error(sc->dev,
- bf->bf_buf_addr))) {
- dev_kfree_skb_any(requeue_skb);
- bf->bf_mpdu = NULL;
- bf->bf_buf_addr = 0;
- ath_err(common, "dma_mapping_error() on RX\n");
- ieee80211_rx(hw, skb);
- break;
- }
-
if (rs.rs_more) {
RX_STAT_INC(rx_frags);
/*
@@ -1302,6 +1311,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
sc->rx.frag = skb;
goto requeue;
}
+ if (rs.rs_status & ATH9K_RXERR_CORRUPT_DESC)
+ goto requeue_drop_frag;
if (sc->rx.frag) {
int space = skb->len - skb_tailroom(hdr_skb);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 5929850649f0..5c4ab5026dca 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1493,9 +1493,6 @@ enum {
#define AR9271_RADIO_RF_RST 0x20
#define AR9271_GATE_MAC_CTL 0x4000
-#define AR_STA_ID0 0x8000
-#define AR_STA_ID1 0x8004
-#define AR_STA_ID1_SADH_MASK 0x0000FFFF
#define AR_STA_ID1_STA_AP 0x00010000
#define AR_STA_ID1_ADHOC 0x00020000
#define AR_STA_ID1_PWR_SAV 0x00040000
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 89a64411b82e..eab0fcb7ded6 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -157,6 +157,13 @@ static void ath_send_bar(struct ath_atx_tid *tid, u16 seqno)
seqno << IEEE80211_SEQ_SEQ_SHIFT);
}
+static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ath_buf *bf)
+{
+ ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates,
+ ARRAY_SIZE(bf->rates));
+}
+
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = tid->ac->txq;
@@ -189,6 +196,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
sendbar = true;
} else {
+ ath_set_rates(tid->an->vif, tid->an->sta, bf);
ath_tx_send_normal(sc, txq, NULL, skb);
}
}
@@ -407,7 +415,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
tx_info = IEEE80211_SKB_CB(skb);
- memcpy(rates, tx_info->control.rates, sizeof(rates));
+ memcpy(rates, bf->rates, sizeof(rates));
retries = ts->ts_longretry + 1;
for (i = 0; i < ts->ts_rateindex; i++)
@@ -516,8 +524,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* not a holding desc.
*/
INIT_LIST_HEAD(&bf_head);
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
- bf_next != NULL || !bf_last->bf_stale)
+ if (bf_next != NULL || !bf_last->bf_stale)
list_move_tail(&bf->list, &bf_head);
if (!txpending || (tid->state & AGGR_CLEANUP)) {
@@ -537,8 +544,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!txfail);
} else {
/* retry the un-acked ones */
- if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
- bf->bf_next == NULL && bf_last->bf_stale) {
+ if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last);
@@ -738,8 +744,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
bool first_subfrm)
{
#define FIRST_DESC_NDELIMS 60
- struct sk_buff *skb = bf->bf_mpdu;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols;
u16 minlen;
u8 flags, rix;
@@ -780,8 +784,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
if (tid->an->mpdudensity == 0)
return ndelim;
- rix = tx_info->control.rates[0].idx;
- flags = tx_info->control.rates[0].flags;
+ rix = bf->rates[0].idx;
+ flags = bf->rates[0].flags;
width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
@@ -860,6 +864,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
bf_first = bf;
if (!rl) {
+ ath_set_rates(tid->an->vif, tid->an->sta, bf);
aggr_limit = ath_lookup_rate(sc, bf, tid);
rl = 1;
}
@@ -1000,14 +1005,14 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb);
- rates = tx_info->control.rates;
+ rates = bf->rates;
hdr = (struct ieee80211_hdr *)skb->data;
/* set dur_update_en for l-sig computation except for PS-Poll frames */
info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
info->rtscts_rate = fi->rtscts_rate;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < ARRAY_SIZE(bf->rates); i++) {
bool is_40, is_sgi, is_sp;
int phy;
@@ -1745,6 +1750,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
return;
}
+ ath_set_rates(tid->an->vif, tid->an->sta, bf);
bf->bf_state.bf_type = BUF_AMPDU;
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
@@ -1894,49 +1900,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
return bf;
}
-/* FIXME: tx power */
-static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
- struct ath_tx_control *txctl)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ath_atx_tid *tid = NULL;
- struct ath_buf *bf;
- u8 tidno;
-
- if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
- tidno = ieee80211_get_qos_ctl(hdr)[0] &
- IEEE80211_QOS_CTL_TID_MASK;
- tid = ATH_AN_2_TID(txctl->an, tidno);
-
- WARN_ON(tid->ac->txq != txctl->txq);
- }
-
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
- /*
- * Try aggregation if it's a unicast data frame
- * and the destination is HT capable.
- */
- ath_tx_send_ampdu(sc, tid, skb, txctl);
- } else {
- bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
- if (!bf) {
- if (txctl->paprd)
- dev_kfree_skb_any(skb);
- else
- ieee80211_free_txskb(sc->hw, skb);
- return;
- }
-
- bf->bf_state.bfs_paprd = txctl->paprd;
-
- if (txctl->paprd)
- bf->bf_state.bfs_paprd_timestamp = jiffies;
-
- ath_tx_send_normal(sc, txctl->txq, tid, skb);
- }
-}
-
/* Upon failure caller should free skb */
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_tx_control *txctl)
@@ -1947,8 +1910,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_vif *vif = info->control.vif;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
+ struct ath_atx_tid *tid = NULL;
+ struct ath_buf *bf;
int padpos, padsize;
int frmlen = skb->len + FCS_LEN;
+ u8 tidno;
int q;
/* NOTE: sta can be NULL according to net/mac80211.h */
@@ -1971,7 +1937,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
}
/* Add the padding after the header if this is not already done */
- padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
if (skb_headroom(skb) < padsize)
@@ -2004,8 +1970,41 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
txq->stopped = true;
}
- ath_tx_start_dma(sc, skb, txctl);
+ if (txctl->an && ieee80211_is_data_qos(hdr->frame_control)) {
+ tidno = ieee80211_get_qos_ctl(hdr)[0] &
+ IEEE80211_QOS_CTL_TID_MASK;
+ tid = ATH_AN_2_TID(txctl->an, tidno);
+
+ WARN_ON(tid->ac->txq != txctl->txq);
+ }
+
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) && tid) {
+ /*
+ * Try aggregation if it's a unicast data frame
+ * and the destination is HT capable.
+ */
+ ath_tx_send_ampdu(sc, tid, skb, txctl);
+ goto out;
+ }
+ bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+ if (!bf) {
+ if (txctl->paprd)
+ dev_kfree_skb_any(skb);
+ else
+ ieee80211_free_txskb(sc->hw, skb);
+ goto out;
+ }
+
+ bf->bf_state.bfs_paprd = txctl->paprd;
+
+ if (txctl->paprd)
+ bf->bf_state.bfs_paprd_timestamp = jiffies;
+
+ ath_set_rates(vif, sta, bf);
+ ath_tx_send_normal(sc, txctl->txq, tid, skb);
+
+out:
ath_txq_unlock(sc, txq);
return 0;
@@ -2033,7 +2032,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
- padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len>padpos+padsize) {
/*
@@ -2264,6 +2263,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
struct ath_txq *txq;
struct ath_buf *bf, *lastbf;
struct list_head bf_head;
+ struct list_head *fifo_list;
int status;
for (;;) {
@@ -2291,20 +2291,24 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
TX_STAT_INC(txq->axq_qnum, txprocdesc);
- if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+ fifo_list = &txq->txq_fifo[txq->txq_tailidx];
+ if (list_empty(fifo_list)) {
ath_txq_unlock(sc, txq);
return;
}
- bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
- struct ath_buf, list);
+ bf = list_first_entry(fifo_list, struct ath_buf, list);
+ if (bf->bf_stale) {
+ list_del(&bf->list);
+ ath_tx_return_buffer(sc, bf);
+ bf = list_first_entry(fifo_list, struct ath_buf, list);
+ }
+
lastbf = bf->bf_lastbf;
INIT_LIST_HEAD(&bf_head);
- list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
- &lastbf->list);
-
- if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+ if (list_is_last(&lastbf->list, fifo_list)) {
+ list_splice_tail_init(fifo_list, &bf_head);
INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
if (!list_empty(&txq->axq_q)) {
@@ -2315,6 +2319,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
list_splice_tail_init(&txq->axq_q, &bf_q);
ath_tx_txqaddbuf(sc, txq, &bf_q, true);
}
+ } else {
+ lastbf->bf_stale = true;
+ if (bf != lastbf)
+ list_cut_position(&bf_head, fifo_list,
+ lastbf->list.prev);
}
ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 25599741cd8a..9dce106cd6d4 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -70,12 +70,6 @@
static const u8 ar9170_qmap[__AR9170_NUM_TXQ] = { 3, 2, 1, 0 };
-enum carl9170_rf_init_mode {
- CARL9170_RFI_NONE,
- CARL9170_RFI_WARM,
- CARL9170_RFI_COLD,
-};
-
#define CARL9170_MAX_RX_BUFFER_SIZE 8192
enum carl9170_device_state {
@@ -599,7 +593,7 @@ int carl9170_led_set_state(struct ar9170 *ar, const u32 led_state);
/* PHY / RF */
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum nl80211_channel_type bw, enum carl9170_rf_init_mode rfi);
+ enum nl80211_channel_type bw);
int carl9170_get_noisefloor(struct ar9170 *ar);
/* FW */
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 93fe6003a493..3d70cd277fd7 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -654,8 +654,8 @@ static ssize_t carl9170_debugfs_bug_write(struct ar9170 *ar, const char *buf,
goto out;
case 'P':
- err = carl9170_set_channel(ar, ar->hw->conf.channel,
- ar->hw->conf.channel_type, CARL9170_RFI_COLD);
+ err = carl9170_set_channel(ar, ar->hw->conf.chandef.chan,
+ cfg80211_get_chandef_type(&ar->hw->conf.chandef));
if (err < 0)
count = err;
diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c
index 24d75ab94f0d..a2f005703c04 100644
--- a/drivers/net/wireless/ath/carl9170/mac.c
+++ b/drivers/net/wireless/ath/carl9170/mac.c
@@ -48,7 +48,7 @@ int carl9170_set_dyn_sifs_ack(struct ar9170 *ar)
if (conf_is_ht40(&ar->hw->conf))
val = 0x010a;
else {
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
val = 0x105;
else
val = 0x104;
@@ -66,7 +66,7 @@ int carl9170_set_rts_cts_rate(struct ar9170 *ar)
rts_rate = 0x1da;
cts_rate = 0x10a;
} else {
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) {
/* 11 mbit CCK */
rts_rate = 033;
cts_rate = 003;
@@ -93,7 +93,7 @@ int carl9170_set_slot_time(struct ar9170 *ar)
return 0;
}
- if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
+ if ((ar->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ) ||
vif->bss_conf.use_short_slot)
slottime = 9;
@@ -120,7 +120,7 @@ int carl9170_set_mac_rates(struct ar9170 *ar)
basic |= (vif->bss_conf.basic_rates & 0xff0) << 4;
rcu_read_unlock();
- if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
mandatory = 0xff00; /* OFDM 6/9/12/18/24/36/48/54 */
else
mandatory = 0xff0f; /* OFDM (6/9../54) + CCK (1/2/5.5/11) */
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index f293b3ff4756..e9010a481dfd 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -929,6 +929,9 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&hw->conf.chandef);
+
/* adjust slot time for 5 GHz */
err = carl9170_set_slot_time(ar);
if (err)
@@ -938,8 +941,8 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
if (err)
goto out;
- err = carl9170_set_channel(ar, hw->conf.channel,
- hw->conf.channel_type, CARL9170_RFI_NONE);
+ err = carl9170_set_channel(ar, hw->conf.chandef.chan,
+ channel_type);
if (err)
goto out;
@@ -957,7 +960,7 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- err = carl9170_set_mac_tpc(ar, ar->hw->conf.channel);
+ err = carl9170_set_mac_tpc(ar, ar->hw->conf.chandef.chan);
if (err)
goto out;
}
@@ -1703,7 +1706,7 @@ found:
return 0;
}
-static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop)
+static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct ar9170 *ar = hw->priv;
unsigned int vid;
diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c
index b72c09cf43a4..ab4ee7d39ad3 100644
--- a/drivers/net/wireless/ath/carl9170/phy.c
+++ b/drivers/net/wireless/ath/carl9170/phy.c
@@ -1331,7 +1331,7 @@ static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw)
* CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
*/
ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
- ar->hw->conf.channel->band);
+ ar->hw->conf.chandef.chan->band);
/* ctl group not found - either invalid band (NO_CTL) or ww roaming */
if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
@@ -1341,7 +1341,7 @@ static void carl9170_calc_ctl(struct ar9170 *ar, u32 freq, enum carl9170_bw bw)
/* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
return;
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) {
modes = mode_list_2ghz;
nr_modes = ARRAY_SIZE(mode_list_2ghz);
} else {
@@ -1569,16 +1569,14 @@ static enum carl9170_bw nl80211_to_carl(enum nl80211_channel_type type)
}
int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum nl80211_channel_type _bw,
- enum carl9170_rf_init_mode rfi)
+ enum nl80211_channel_type _bw)
{
const struct carl9170_phy_freq_params *freqpar;
struct carl9170_rf_init_result rf_res;
struct carl9170_rf_init rf;
- u32 cmd, tmp, offs = 0, new_ht = 0;
+ u32 tmp, offs = 0, new_ht = 0;
int err;
enum carl9170_bw bw;
- bool warm_reset;
struct ieee80211_channel *old_channel = NULL;
bw = nl80211_to_carl(_bw);
@@ -1592,51 +1590,27 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
/* may be NULL at first setup */
if (ar->channel) {
old_channel = ar->channel;
- warm_reset = (old_channel->band != channel->band) ||
- (old_channel->center_freq ==
- channel->center_freq) ||
- (ar->ht_settings != new_ht);
-
ar->channel = NULL;
- } else {
- warm_reset = true;
}
- /* HW workaround */
- if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] &&
- channel->center_freq <= 2417)
- warm_reset = true;
-
- if (rfi != CARL9170_RFI_NONE || warm_reset) {
- u32 val;
-
- if (rfi == CARL9170_RFI_COLD)
- val = AR9170_PWR_RESET_BB_COLD_RESET;
- else
- val = AR9170_PWR_RESET_BB_WARM_RESET;
-
- /* warm/cold reset BB/ADDA */
- err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, val);
- if (err)
- return err;
-
- err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
- if (err)
- return err;
+ /* cold reset BB/ADDA */
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET,
+ AR9170_PWR_RESET_BB_COLD_RESET);
+ if (err)
+ return err;
- err = carl9170_init_phy(ar, channel->band);
- if (err)
- return err;
+ err = carl9170_write_reg(ar, AR9170_PWR_REG_RESET, 0x0);
+ if (err)
+ return err;
- err = carl9170_init_rf_banks_0_7(ar,
- channel->band == IEEE80211_BAND_5GHZ);
- if (err)
- return err;
+ err = carl9170_init_phy(ar, channel->band);
+ if (err)
+ return err;
- cmd = CARL9170_CMD_RF_INIT;
- } else {
- cmd = CARL9170_CMD_FREQUENCY;
- }
+ err = carl9170_init_rf_banks_0_7(ar,
+ channel->band == IEEE80211_BAND_5GHZ);
+ if (err)
+ return err;
err = carl9170_exec_cmd(ar, CARL9170_CMD_FREQ_START, 0, NULL, 0, NULL);
if (err)
@@ -1648,8 +1622,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return err;
err = carl9170_init_rf_bank4_pwr(ar,
- channel->band == IEEE80211_BAND_5GHZ,
- channel->center_freq, bw);
+ channel->band == IEEE80211_BAND_5GHZ,
+ channel->center_freq, bw);
if (err)
return err;
@@ -1703,13 +1677,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
rf.delta_slope_coeff_man = cpu_to_le32(freqpar->coeff_man);
rf.delta_slope_coeff_exp_shgi = cpu_to_le32(freqpar->coeff_exp_shgi);
rf.delta_slope_coeff_man_shgi = cpu_to_le32(freqpar->coeff_man_shgi);
-
- if (rfi != CARL9170_RFI_NONE)
- rf.finiteLoopCount = cpu_to_le32(2000);
- else
- rf.finiteLoopCount = cpu_to_le32(1000);
-
- err = carl9170_exec_cmd(ar, cmd, sizeof(rf), &rf,
+ rf.finiteLoopCount = cpu_to_le32(2000);
+ err = carl9170_exec_cmd(ar, CARL9170_CMD_RF_INIT, sizeof(rf), &rf,
sizeof(rf_res), &rf_res);
if (err)
return err;
@@ -1724,9 +1693,8 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
old_channel->center_freq : -1, channel->center_freq,
err);
- if ((rfi == CARL9170_RFI_COLD) || (ar->chan_fail > 3)) {
- /*
- * We have tried very hard to change to _another_
+ if (ar->chan_fail > 3) {
+ /* We have tried very hard to change to _another_
* channel and we've failed to do so!
* Chances are that the PHY/RF is no longer
* operable (due to corruptions/fatal events/bugs?)
@@ -1736,8 +1704,7 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return 0;
}
- err = carl9170_set_channel(ar, channel, _bw,
- CARL9170_RFI_COLD);
+ err = carl9170_set_channel(ar, channel, _bw);
if (err)
return err;
} else {
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index 9c0b150d5b8e..c61cafa2665b 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -387,8 +387,7 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
u8 tid;
if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
- txinfo->flags & IEEE80211_TX_CTL_INJECTED ||
- (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
+ txinfo->flags & IEEE80211_TX_CTL_INJECTED)
return;
rcu_read_lock();
@@ -981,30 +980,6 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
SET_VAL(CARL9170_TX_SUPER_AMPDU_FACTOR,
txc->s.ampdu_settings, factor);
-
- for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
- txrate = &info->control.rates[i];
- if (txrate->idx >= 0) {
- txc->s.ri[i] =
- CARL9170_TX_SUPER_RI_AMPDU;
-
- if (WARN_ON(!(txrate->flags &
- IEEE80211_TX_RC_MCS))) {
- /*
- * Not sure if it's even possible
- * to aggregate non-ht rates with
- * this HW.
- */
- goto err_out;
- }
- continue;
- }
-
- txrate->idx = 0;
- txrate->count = ar->hw->max_rate_tries;
- }
-
- mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
}
/*
@@ -1012,11 +987,31 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
* taken from mac_control. For all fallback rate, the firmware
* updates the mac_control flags from the rate info field.
*/
- for (i = 1; i < CARL9170_TX_MAX_RATES; i++) {
+ for (i = 0; i < CARL9170_TX_MAX_RATES; i++) {
+ __le32 phy_set;
txrate = &info->control.rates[i];
if (txrate->idx < 0)
break;
+ phy_set = carl9170_tx_physet(ar, info, txrate);
+ if (i == 0) {
+ /* first rate - part of the hw's frame header */
+ txc->f.phy_control = phy_set;
+
+ if (ampdu && txrate->flags & IEEE80211_TX_RC_MCS)
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_AGGR);
+ if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
+ else if (carl9170_tx_cts_check(ar, txrate))
+ mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
+
+ } else {
+ /* fallback rates are stored in the firmware's
+ * retry rate set array.
+ */
+ txc->s.rr[i - 1] = phy_set;
+ }
+
SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[i],
txrate->count);
@@ -1027,21 +1022,13 @@ static int carl9170_tx_prepare(struct ar9170 *ar,
txc->s.ri[i] |= (AR9170_TX_MAC_PROT_CTS <<
CARL9170_TX_SUPER_RI_ERP_PROT_S);
- txc->s.rr[i - 1] = carl9170_tx_physet(ar, info, txrate);
+ if (ampdu && (txrate->flags & IEEE80211_TX_RC_MCS))
+ txc->s.ri[i] |= CARL9170_TX_SUPER_RI_AMPDU;
}
- txrate = &info->control.rates[0];
- SET_VAL(CARL9170_TX_SUPER_RI_TRIES, txc->s.ri[0], txrate->count);
-
- if (carl9170_tx_rts_check(ar, txrate, ampdu, no_ack))
- mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
- else if (carl9170_tx_cts_check(ar, txrate))
- mac_tmp |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
-
txc->s.len = cpu_to_le16(skb->len);
txc->f.length = cpu_to_le16(len + FCS_LEN);
txc->f.mac_control = mac_tmp;
- txc->f.phy_control = carl9170_tx_physet(ar, info, txrate);
arinfo = (void *)info->rate_driver_data;
arinfo->timeout = jiffies;
@@ -1381,9 +1368,9 @@ static void carl9170_tx(struct ar9170 *ar)
}
static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
- struct ieee80211_sta *sta, struct sk_buff *skb)
+ struct ieee80211_sta *sta, struct sk_buff *skb,
+ struct ieee80211_tx_info *txinfo)
{
- struct _carl9170_tx_superframe *super = (void *) skb->data;
struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *agg;
struct sk_buff *iter;
@@ -1450,7 +1437,7 @@ err_unlock:
err_unlock_rcu:
rcu_read_unlock();
- super->f.mac_control &= ~cpu_to_le16(AR9170_TX_MAC_AGGR);
+ txinfo->flags &= ~IEEE80211_TX_CTL_AMPDU;
carl9170_tx_status(ar, skb, false);
ar->tx_dropped++;
return false;
@@ -1492,7 +1479,7 @@ void carl9170_op_tx(struct ieee80211_hw *hw,
* sta == NULL checks are redundant in this
* special case.
*/
- run = carl9170_tx_ampdu_queue(ar, sta, skb);
+ run = carl9170_tx_ampdu_queue(ar, sta, skb, info);
if (run)
carl9170_tx_ampdu(ar);
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
index 39e8a590d7fc..eae9abf540a7 100644
--- a/drivers/net/wireless/ath/hw.c
+++ b/drivers/net/wireless/ath/hw.c
@@ -118,6 +118,12 @@
void ath_hw_setbssidmask(struct ath_common *common)
{
void *ah = common->ah;
+ u32 id1;
+
+ REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
+ id1 = REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_SADH_MASK;
+ id1 |= get_unaligned_le16(common->macaddr + 4);
+ REG_WRITE(ah, AR_STA_ID1, id1);
REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask));
REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4));
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 5c54aa43ca2d..1816b4e7dc26 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -45,7 +45,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "keyreset: keycache entry %u out of range\n",
+ entry);
return false;
}
@@ -91,7 +92,8 @@ static bool ath_hw_keysetmac(struct ath_common *common,
void *ah = common->ah;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "keysetmac: keycache entry %u out of range\n",
+ entry);
return false;
}
@@ -133,7 +135,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
u32 keyType;
if (entry >= common->keymax) {
- ath_err(common, "keycache entry %u out of range\n", entry);
+ ath_err(common, "set-entry: keycache entry %u out of range\n",
+ entry);
return false;
}
diff --git a/drivers/net/wireless/ath/reg.h b/drivers/net/wireless/ath/reg.h
index 298e53f3fa48..3ad4c774bd22 100644
--- a/drivers/net/wireless/ath/reg.h
+++ b/drivers/net/wireless/ath/reg.h
@@ -23,6 +23,10 @@
#define AR_MIBC_CMC 0x00000004
#define AR_MIBC_MCS 0x00000008
+#define AR_STA_ID0 0x8000
+#define AR_STA_ID1 0x8004
+#define AR_STA_ID1_SADH_MASK 0x0000ffff
+
/*
* BSSID mask registers. See ath_hw_set_bssid_mask()
* for detailed documentation about these registers.
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 9396dc9fe3c5..d288eea0a26a 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -9,5 +9,7 @@ wil6210-objs += wmi.o
wil6210-objs += interrupt.o
wil6210-objs += txrx.o
-subdir-ccflags-y += -Werror
+ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
+ subdir-ccflags-y += -Werror
+endif
subdir-ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9ecc1968262c..c5d4a87abaaf 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -14,16 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <net/cfg80211.h>
-
#include "wil6210.h"
#include "wmi.h"
@@ -292,7 +282,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
/* WMI_CONNECT_CMD */
memset(&conn, 0, sizeof(conn));
- switch (bss->capability & 0x03) {
+ switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
case WLAN_CAPABILITY_DMG_TYPE_AP:
conn.network_type = WMI_NETTYPE_INFRA;
break;
@@ -437,17 +427,18 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
if (rc)
return rc;
- rc = wmi_set_channel(wil, channel->hw_value);
- if (rc)
- return rc;
-
/* MAC address - pre-requisite for other commands */
wmi_set_mac_address(wil, ndev->dev_addr);
/* IE's */
/* bcon 'head IE's are not relevant for 60g band */
- wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
- bcon->beacon_ies);
+ /*
+ * FW do not form regular beacon, so bcon IE's are not set
+ * For the DMG bcon, when it will be supported, bcon IE's will
+ * be reused; add something like:
+ * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len,
+ * bcon->beacon_ies);
+ */
wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
bcon->proberesp_ies);
wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
@@ -455,7 +446,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil->secure_pcp = info->privacy;
- rc = wmi_set_bcon(wil, info->beacon_interval, wmi_nettype);
+ rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
+ channel->hw_value);
if (rc)
return rc;
@@ -472,11 +464,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
{
int rc = 0;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
- struct wireless_dev *wdev = ndev->ieee80211_ptr;
- u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
- /* To stop beaconing, set BI to 0 */
- rc = wmi_set_bcon(wil, 0, wmi_nettype);
+ rc = wmi_pcp_stop(wil);
return rc;
}
diff --git a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h b/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
deleted file mode 100644
index e5712f026c47..000000000000
--- a/drivers/net/wireless/ath/wil6210/dbg_hexdump.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef WIL_DBG_HEXDUMP_H_
-#define WIL_DBG_HEXDUMP_H_
-
-#include <linux/printk.h>
-#include <linux/dynamic_debug.h>
-
-#if defined(CONFIG_DYNAMIC_DEBUG)
-#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
- groupsize, buf, len, ascii) \
- dynamic_hex_dump(prefix_str, prefix_type, rowsize, \
- groupsize, buf, len, ascii)
-
-#else /* defined(CONFIG_DYNAMIC_DEBUG) */
-#define wil_print_hex_dump_debug(prefix_str, prefix_type, rowsize, \
- groupsize, buf, len, ascii) \
- print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \
- groupsize, buf, len, ascii)
-#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
-
-#endif /* WIL_DBG_HEXDUMP_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 76c7694518d9..727b1f53e6ad 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -312,14 +312,6 @@ static const struct file_operations fops_memread = {
.llseek = seq_lseek,
};
-static int wil_default_open(struct inode *inode, struct file *file)
-{
- if (inode->i_private)
- file->private_data = inode->i_private;
-
- return 0;
-}
-
static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -361,7 +353,7 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
static const struct file_operations fops_ioblob = {
.read = wil_read_file_ioblob,
- .open = wil_default_open,
+ .open = simple_open,
.llseek = default_llseek,
};
@@ -396,7 +388,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
- .open = wil_default_open,
+ .open = simple_open,
};
/*---------Tx descriptor------------*/
@@ -526,7 +518,50 @@ static ssize_t wil_write_file_ssid(struct file *file, const char __user *buf,
static const struct file_operations fops_ssid = {
.read = wil_read_file_ssid,
.write = wil_write_file_ssid,
- .open = wil_default_open,
+ .open = simple_open,
+};
+
+/*---------temp------------*/
+static void print_temp(struct seq_file *s, const char *prefix, u32 t)
+{
+ switch (t) {
+ case 0:
+ case ~(u32)0:
+ seq_printf(s, "%s N/A\n", prefix);
+ break;
+ default:
+ seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
+ break;
+ }
+}
+
+static int wil_temp_debugfs_show(struct seq_file *s, void *data)
+{
+ struct wil6210_priv *wil = s->private;
+ u32 t_m, t_r;
+
+ int rc = wmi_get_temperature(wil, &t_m, &t_r);
+ if (rc) {
+ seq_printf(s, "Failed\n");
+ return 0;
+ }
+
+ print_temp(s, "MAC temperature :", t_m);
+ print_temp(s, "Radio temperature :", t_r);
+
+ return 0;
+}
+
+static int wil_temp_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, wil_temp_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations fops_temp = {
+ .open = wil_temp_seq_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek,
};
/*----------------*/
@@ -563,6 +598,7 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
+ debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
wil->rgf_blob.data = (void * __force)wil->csr + 0;
wil->rgf_blob.size = 0xa000;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index dc97e7b2609c..e3c1e7684f9c 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -240,6 +240,15 @@ static void wil_notify_fw_error(struct wil6210_priv *wil)
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
+static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+{
+ /* make shadow copy of registers that should not change on run time */
+ wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
+ sizeof(struct wil6210_mbox_ctl));
+ wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
+ wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+}
+
static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
@@ -257,14 +266,19 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
wil6210_mask_irq_misc(wil);
if (isr & ISR_MISC_FW_ERROR) {
- wil_dbg_irq(wil, "IRQ: Firmware error\n");
+ wil_err(wil, "Firmware error detected\n");
clear_bit(wil_status_fwready, &wil->status);
- wil_notify_fw_error(wil);
- isr &= ~ISR_MISC_FW_ERROR;
+ /*
+ * do not clear @isr here - we do 2-nd part in thread
+ * there, user space get notified, and it should be done
+ * in non-atomic context
+ */
}
if (isr & ISR_MISC_FW_READY) {
wil_dbg_irq(wil, "IRQ: FW ready\n");
+ wil_cache_mbox_regs(wil);
+ set_bit(wil_status_reset_done, &wil->status);
/**
* Actual FW ready indicated by the
* WMI_FW_READY_EVENTID
@@ -289,6 +303,11 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
wil_dbg_irq(wil, "Thread ISR MISC 0x%08x\n", isr);
+ if (isr & ISR_MISC_FW_ERROR) {
+ wil_notify_fw_error(wil);
+ isr &= ~ISR_MISC_FW_ERROR;
+ }
+
if (isr & ISR_MISC_MBOX_EVT) {
wil_dbg_irq(wil, "MBOX event\n");
wmi_recv_cmd(wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 761c389586d4..a0478e2f6868 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -14,12 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <linux/ieee80211.h>
-#include <linux/wireless.h>
-#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <linux/if_arp.h>
@@ -109,13 +103,24 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker);
}
-static void wil_cache_mbox_regs(struct wil6210_priv *wil)
+static void wil_connect_worker(struct work_struct *work)
{
- /* make shadow copy of registers that should not change on run time */
- wil_memcpy_fromio_32(&wil->mbox_ctl, wil->csr + HOST_MBOX,
- sizeof(struct wil6210_mbox_ctl));
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.rx);
- wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
+ int rc;
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ connect_worker);
+ int cid = wil->pending_connect_cid;
+
+ if (cid < 0) {
+ wil_err(wil, "No connection pending\n");
+ return;
+ }
+
+ wil_dbg_wmi(wil, "Configure for connection CID %d\n", cid);
+
+ rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE, cid, 0);
+ wil->pending_connect_cid = -1;
+ if (rc == 0)
+ wil_link_on(wil);
}
int wil_priv_init(struct wil6210_priv *wil)
@@ -130,7 +135,7 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->pending_connect_cid = -1;
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
- INIT_WORK(&wil->wmi_connect_worker, wmi_connect_worker);
+ INIT_WORK(&wil->connect_worker, wil_connect_worker);
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
@@ -147,8 +152,6 @@ int wil_priv_init(struct wil6210_priv *wil)
return -EAGAIN;
}
- wil_cache_mbox_regs(wil);
-
return 0;
}
@@ -185,15 +188,11 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_MAC_CPU_0, BIT(1)); /* mac_cpu_man_rst */
W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
- msleep(100);
-
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FC00);
- msleep(100);
-
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
@@ -203,12 +202,6 @@ static void wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- msleep(2000);
-
- W(RGF_USER_USER_CPU_0, BIT(0)); /* user_cpu_man_de_rst */
-
- msleep(2000);
-
wil_dbg_misc(wil, "Reset completed\n");
#undef W
@@ -265,8 +258,6 @@ int wil_reset(struct wil6210_priv *wil)
wil->pending_connect_cid = -1;
INIT_COMPLETION(wil->wmi_ready);
- wil_cache_mbox_regs(wil);
-
/* TODO: release MAC reset */
wil6210_enable_irq(wil);
@@ -352,9 +343,9 @@ static int __wil_up(struct wil6210_priv *wil)
wil_err(wil, "SSID not set\n");
return -EINVAL;
}
- wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
- if (channel)
- wmi_set_channel(wil, channel->hw_value);
+ rc = wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid);
+ if (rc)
+ return rc;
break;
default:
break;
@@ -364,9 +355,12 @@ static int __wil_up(struct wil6210_priv *wil)
wmi_set_mac_address(wil, ndev->dev_addr);
/* Set up beaconing if required. */
- rc = wmi_set_bcon(wil, bi, wmi_nettype);
- if (rc)
- return rc;
+ if (bi > 0) {
+ rc = wmi_pcp_start(wil, bi, wmi_nettype,
+ (channel ? channel->hw_value : 0));
+ if (rc)
+ return rc;
+ }
/* Rx VRING. After MAC and beacon */
wil_rx_init(wil);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 8ce2e33dce20..098a8ec6b841 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -14,10 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/module.h>
-#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/slab.h>
#include "wil6210.h"
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 81c35c6e3832..eb1dc7ad80fb 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -14,10 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
#include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index d1315b442375..797024507c71 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -14,10 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/hardirq.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
#include <linux/moduleparam.h>
@@ -83,8 +80,6 @@ static int wil_vring_alloc(struct wil6210_priv *wil, struct vring *vring)
*/
vring->va = dma_alloc_coherent(dev, sz, &vring->pa, GFP_KERNEL);
if (!vring->va) {
- wil_err(wil, "vring_alloc [%d] failed to alloc DMA mem\n",
- vring->size);
kfree(vring->ctx);
vring->ctx = NULL;
return -ENOMEM;
@@ -196,8 +191,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
* - Phy info
*/
static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
- struct sk_buff *skb,
- volatile struct vring_rx_desc *d)
+ struct sk_buff *skb)
{
struct wireless_dev *wdev = wil->wdev;
struct wil6210_rtap {
@@ -221,6 +215,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil,
__le16 vendor_skip;
u8 vendor_data[0];
} __packed;
+ struct vring_rx_desc *d = wil_skb_rxdesc(skb);
struct wil6210_rtap_vendor *rtap_vendor;
int rtap_len = sizeof(struct wil6210_rtap);
int phy_length = 0; /* phy info header size, bytes */
@@ -317,6 +312,8 @@ static void wil_swap_ethaddr(void *data)
/**
* reap 1 frame from @swhead
*
+ * Rx descriptor copied to skb->cb
+ *
* Safe to call from IRQ
*/
static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
@@ -325,12 +322,15 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
struct device *dev = wil_to_dev(wil);
struct net_device *ndev = wil_to_ndev(wil);
volatile struct vring_rx_desc *d;
+ struct vring_rx_desc *d1;
struct sk_buff *skb;
dma_addr_t pa;
unsigned int sz = RX_BUF_LEN;
u8 ftype;
u8 ds_bits;
+ BUILD_BUG_ON(sizeof(struct vring_rx_desc) > sizeof(skb->cb));
+
if (wil_vring_is_empty(vring))
return NULL;
@@ -345,11 +345,14 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE);
skb_trim(skb, d->dma.length);
- wil->stats.last_mcs_rx = wil_rxdesc_mcs(d);
+ d1 = wil_skb_rxdesc(skb);
+ *d1 = *d;
+
+ wil->stats.last_mcs_rx = wil_rxdesc_mcs(d1);
/* use radiotap header only if required */
if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
- wil_rx_add_radiotap_header(wil, skb, d);
+ wil_rx_add_radiotap_header(wil, skb);
wil_dbg_txrx(wil, "Rx[%3d] : %d bytes\n", vring->swhead, d->dma.length);
wil_hex_dump_txrx("Rx ", DUMP_PREFIX_NONE, 32, 4,
@@ -365,7 +368,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* Driver should recognize it by frame type, that is found
* in Rx descriptor. If type is not data, it is 802.11 frame as is
*/
- ftype = wil_rxdesc_ftype(d) << 2;
+ ftype = wil_rxdesc_ftype(d1) << 2;
if (ftype != IEEE80211_FTYPE_DATA) {
wil_dbg_txrx(wil, "Non-data frame ftype 0x%08x\n", ftype);
/* TODO: process it */
@@ -380,7 +383,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
return NULL;
}
- ds_bits = wil_rxdesc_ds_bits(d);
+ ds_bits = wil_rxdesc_ds_bits(d1);
if (ds_bits == 1) {
/*
* HW bug - in ToDS mode, i.e. Rx on AP side,
@@ -522,6 +525,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.vring_cfg = {
.tx_sw_ring = {
.max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
+ .ring_size = cpu_to_le16(size),
},
.ringid = id,
.cidxtid = (cid & 0xf) | ((tid & 0xf) << 4),
@@ -553,14 +557,13 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
goto out;
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
- cmd.vring_cfg.tx_sw_ring.ring_size = cpu_to_le16(vring->size);
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
goto out_free;
- if (reply.cmd.status != WMI_VRING_CFG_SUCCESS) {
+ if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "Tx config failed, status 0x%02x\n",
reply.cmd.status);
rc = -EINVAL;
@@ -784,9 +787,14 @@ void wil_tx_complete(struct wil6210_priv *wil, int ringid)
wil_dbg_txrx(wil, "%s(%d)\n", __func__, ringid);
while (!wil_vring_is_empty(vring)) {
- volatile struct vring_tx_desc *d = &vring->va[vring->swtail].tx;
+ volatile struct vring_tx_desc *d1 =
+ &vring->va[vring->swtail].tx;
+ struct vring_tx_desc dd, *d = &dd;
dma_addr_t pa;
struct sk_buff *skb;
+
+ dd = *d1;
+
if (!(d->dma.status & TX_DMA_STATUS_DU))
break;
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 45a61f597c5c..adef12fb2aee 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -339,24 +339,59 @@ union vring_desc {
struct vring_rx_desc rx;
} __packed;
-static inline int wil_rxdesc_phy_length(volatile struct vring_rx_desc *d)
+static inline int wil_rxdesc_tid(struct vring_rx_desc *d)
{
- return WIL_GET_BITS(d->dma.d0, 16, 29);
+ return WIL_GET_BITS(d->mac.d0, 0, 3);
}
-static inline int wil_rxdesc_mcs(volatile struct vring_rx_desc *d)
+static inline int wil_rxdesc_cid(struct vring_rx_desc *d)
{
- return WIL_GET_BITS(d->mac.d1, 21, 24);
+ return WIL_GET_BITS(d->mac.d0, 4, 6);
}
-static inline int wil_rxdesc_ds_bits(volatile struct vring_rx_desc *d)
+static inline int wil_rxdesc_mid(struct vring_rx_desc *d)
{
- return WIL_GET_BITS(d->mac.d1, 8, 9);
+ return WIL_GET_BITS(d->mac.d0, 8, 9);
}
-static inline int wil_rxdesc_ftype(volatile struct vring_rx_desc *d)
+static inline int wil_rxdesc_ftype(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->mac.d0, 10, 11);
}
+static inline int wil_rxdesc_subtype(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d0, 12, 15);
+}
+
+static inline int wil_rxdesc_seq(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d0, 16, 27);
+}
+
+static inline int wil_rxdesc_ext_subtype(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d0, 28, 31);
+}
+
+static inline int wil_rxdesc_ds_bits(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d1, 8, 9);
+}
+
+static inline int wil_rxdesc_mcs(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d1, 21, 24);
+}
+
+static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->dma.d0, 16, 29);
+}
+
+static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
+{
+ return (void *)skb->cb;
+}
+
#endif /* WIL6210_TXRX_H */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index aea961ff8f08..8f76ecd8a7e5 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -21,8 +21,6 @@
#include <linux/wireless.h>
#include <net/cfg80211.h>
-#include "dbg_hexdump.h"
-
#define WIL_NAME "wil6210"
/**
@@ -188,6 +186,7 @@ enum { /* for wil6210_priv.status */
wil_status_fwready = 0,
wil_status_fwconnected,
wil_status_dontscan,
+ wil_status_reset_done,
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
};
@@ -210,6 +209,8 @@ struct wil6210_priv {
struct wireless_dev *wdev;
void __iomem *csr;
ulong status;
+ u32 fw_version;
+ u8 n_mids; /* number of additional MIDs as reported by FW */
/* profile */
u32 monitor_flags;
u32 secure_pcp; /* create secure PCP? */
@@ -227,7 +228,7 @@ struct wil6210_priv {
struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker;
struct workqueue_struct *wmi_wq_conn; /* for connect worker */
- struct work_struct wmi_connect_worker;
+ struct work_struct connect_worker;
struct work_struct disconnect_worker;
struct timer_list connect_timer;
int pending_connect_cid;
@@ -277,13 +278,13 @@ struct wil6210_priv {
#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
- wil_print_hex_dump_debug("DBG[TXRX]" prefix_str,\
+ print_hex_dump_debug("DBG[TXRX]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
#define wil_hex_dump_wmi(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
- wil_print_hex_dump_debug("DBG[ WMI]" prefix_str,\
+ print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
@@ -313,7 +314,6 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
void wmi_recv_cmd(struct wil6210_priv *wil);
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
u16 reply_id, void *reply, u8 reply_size, int to_msec);
-void wmi_connect_worker(struct work_struct *work);
void wmi_event_worker(struct work_struct *work);
void wmi_event_flush(struct wil6210_priv *wil);
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
@@ -328,6 +328,8 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
+int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
@@ -341,7 +343,8 @@ struct wireless_dev *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil);
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
-int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype);
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
+int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, void *bssid);
int wil_rx_init(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 0bb3b76b4b58..45b04e383f9a 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -14,9 +14,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <linux/pci.h>
-#include <linux/io.h>
-#include <linux/list.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
@@ -272,16 +269,18 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wmi_ready_event *evt = d;
- u32 ver = le32_to_cpu(evt->sw_version);
+ wil->fw_version = le32_to_cpu(evt->sw_version);
+ wil->n_mids = evt->numof_additional_mids;
- wil_dbg_wmi(wil, "FW ver. %d; MAC %pM\n", ver, evt->mac);
+ wil_dbg_wmi(wil, "FW ver. %d; MAC %pM; %d MID's\n", wil->fw_version,
+ evt->mac, wil->n_mids);
if (!is_valid_ether_addr(ndev->dev_addr)) {
memcpy(ndev->dev_addr, evt->mac, ETH_ALEN);
memcpy(ndev->perm_addr, evt->mac, ETH_ALEN);
}
snprintf(wdev->wiphy->fw_version, sizeof(wdev->wiphy->fw_version),
- "%d", ver);
+ "%d", wil->fw_version);
}
static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
@@ -324,17 +323,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) {
struct cfg80211_bss *bss;
- u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp);
- u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info);
- u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int);
- const u8 *ie_buf = rx_mgmt_frame->u.beacon.variable;
- size_t ie_len = d_len - offsetof(struct ieee80211_mgmt,
- u.beacon.variable);
- wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap);
-
- bss = cfg80211_inform_bss(wiphy, channel, rx_mgmt_frame->bssid,
- tsf, cap, bi, ie_buf, ie_len,
- signal, GFP_KERNEL);
+
+ bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame,
+ d_len, signal, GFP_KERNEL);
if (bss) {
wil_dbg_wmi(wil, "Added BSS %pM\n",
rx_mgmt_frame->bssid);
@@ -342,6 +333,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
} else {
wil_err(wil, "cfg80211_inform_bss() failed\n");
}
+ } else {
+ cfg80211_rx_mgmt(wil->wdev, freq, signal,
+ (void *)rx_mgmt_frame, d_len, GFP_KERNEL);
}
}
@@ -443,7 +437,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
memcpy(wil->dst_addr[0], evt->bssid, ETH_ALEN);
wil->pending_connect_cid = evt->cid;
- queue_work(wil->wmi_wq_conn, &wil->wmi_connect_worker);
+ queue_work(wil->wmi_wq_conn, &wil->connect_worker);
}
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -528,6 +522,37 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
}
}
+static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wmi_data_port_open_event *evt = d;
+
+ wil_dbg_wmi(wil, "Link UP for CID %d\n", evt->cid);
+
+ netif_carrier_on(ndev);
+}
+
+static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wmi_wbe_link_down_event *evt = d;
+
+ wil_dbg_wmi(wil, "Link DOWN for CID %d, reason %d\n",
+ evt->cid, le32_to_cpu(evt->reason));
+
+ netif_carrier_off(ndev);
+}
+
+static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
+ int len)
+{
+ struct wmi_vring_ba_status_event *evt = d;
+
+ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
+ evt->ringid, evt->status ? "N/A" : "OK", evt->agg_wsize,
+ __le16_to_cpu(evt->ba_timeout));
+}
+
static const struct {
int eventid;
void (*handler)(struct wil6210_priv *wil, int eventid,
@@ -541,6 +566,9 @@ static const struct {
{WMI_DISCONNECT_EVENTID, wmi_evt_disconnect},
{WMI_NOTIFY_REQ_DONE_EVENTID, wmi_evt_notify},
{WMI_EAPOL_RX_EVENTID, wmi_evt_eapol_rx},
+ {WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
+ {WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
+ {WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
};
/*
@@ -559,6 +587,11 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
void __iomem *src;
ulong flags;
+ if (!test_bit(wil_status_reset_done, &wil->status)) {
+ wil_err(wil, "Reset not completed\n");
+ return;
+ }
+
for (;;) {
u16 len;
@@ -683,18 +716,39 @@ int wmi_set_mac_address(struct wil6210_priv *wil, void *addr)
return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd));
}
-int wmi_set_bcon(struct wil6210_priv *wil, int bi, u8 wmi_nettype)
+int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
{
- struct wmi_bcon_ctrl_cmd cmd = {
+ int rc;
+
+ struct wmi_pcp_start_cmd cmd = {
.bcon_interval = cpu_to_le16(bi),
.network_type = wmi_nettype,
.disable_sec_offload = 1,
+ .channel = chan,
};
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_pcp_started_event evt;
+ } __packed reply;
if (!wil->secure_pcp)
cmd.disable_sec = 1;
- return wmi_send(wil, WMI_BCON_CTRL_CMDID, &cmd, sizeof(cmd));
+ rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd),
+ WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 100);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status != WMI_FW_STATUS_SUCCESS)
+ rc = -EINVAL;
+
+ return rc;
+}
+
+int wmi_pcp_stop(struct wil6210_priv *wil)
+{
+ return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0,
+ WMI_PCP_STOPPED_EVENTID, NULL, 0, 20);
}
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid)
@@ -765,6 +819,16 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel)
return 0;
}
+int wmi_p2p_cfg(struct wil6210_priv *wil, int channel)
+{
+ struct wmi_p2p_cfg_cmd cmd = {
+ .discovery_mode = WMI_DISCOVERY_MODE_NON_OFFLOAD,
+ .channel = channel - 1,
+ };
+
+ return wmi_send(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd));
+}
+
int wmi_tx_eapol(struct wil6210_priv *wil, struct sk_buff *skb)
{
struct wmi_eapol_tx_cmd *cmd;
@@ -843,7 +907,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie)
/* BUG: FW API define ieLen as u8. Will fix FW */
cmd->ie_len = cpu_to_le16(ie_len);
memcpy(cmd->ie_info, ie, ie_len);
- rc = wmi_send(wil, WMI_SET_APPIE_CMDID, &cmd, len);
+ rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len);
kfree(cmd);
return rc;
@@ -898,6 +962,31 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
return rc;
}
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
+{
+ int rc;
+ struct wmi_temp_sense_cmd cmd = {
+ .measure_marlon_m_en = cpu_to_le32(!!t_m),
+ .measure_marlon_r_en = cpu_to_le32(!!t_r),
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_temp_sense_done_event evt;
+ } __packed reply;
+
+ rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd),
+ WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100);
+ if (rc)
+ return rc;
+
+ if (t_m)
+ *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
+ if (t_r)
+ *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
+
+ return 0;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
@@ -997,24 +1086,3 @@ void wmi_event_worker(struct work_struct *work)
kfree(evt);
}
}
-
-void wmi_connect_worker(struct work_struct *work)
-{
- int rc;
- struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
- wmi_connect_worker);
-
- if (wil->pending_connect_cid < 0) {
- wil_err(wil, "No connection pending\n");
- return;
- }
-
- wil_dbg_wmi(wil, "Configure for connection CID %d\n",
- wil->pending_connect_cid);
-
- rc = wil_vring_init_tx(wil, 0, WIL6210_TX_RING_SIZE,
- wil->pending_connect_cid, 0);
- wil->pending_connect_cid = -1;
- if (rc == 0)
- wil_link_on(wil);
-}
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 3bbf87572b07..50b8528394f4 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -36,6 +36,7 @@
enum wmi_command_id {
WMI_CONNECT_CMDID = 0x0001,
WMI_DISCONNECT_CMDID = 0x0003,
+ WMI_DISCONNECT_STA_CMDID = 0x0004,
WMI_START_SCAN_CMDID = 0x0007,
WMI_SET_BSS_FILTER_CMDID = 0x0009,
WMI_SET_PROBED_SSID_CMDID = 0x000a,
@@ -44,7 +45,6 @@ enum wmi_command_id {
WMI_ADD_CIPHER_KEY_CMDID = 0x0016,
WMI_DELETE_CIPHER_KEY_CMDID = 0x0017,
WMI_SET_APPIE_CMDID = 0x003f,
- WMI_GET_APPIE_CMDID = 0x0040,
WMI_SET_WSC_STATUS_CMDID = 0x0041,
WMI_PXMT_RANGE_CFG_CMDID = 0x0042,
WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043,
@@ -55,11 +55,11 @@ enum wmi_command_id {
WMI_DEEP_ECHO_CMDID = 0x0804,
WMI_CONFIG_MAC_CMDID = 0x0805,
WMI_CONFIG_PHY_DEBUG_CMDID = 0x0806,
- WMI_ADD_STATION_CMDID = 0x0807,
WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x0808,
WMI_PHY_GET_STATISTICS_CMDID = 0x0809,
WMI_FS_TUNE_CMDID = 0x080a,
WMI_CORR_MEASURE_CMDID = 0x080b,
+ WMI_READ_RSSI_CMDID = 0x080c,
WMI_TEMP_SENSE_CMDID = 0x080e,
WMI_DC_CALIB_CMDID = 0x080f,
WMI_SEND_TONE_CMDID = 0x0810,
@@ -75,9 +75,9 @@ enum wmi_command_id {
MAC_IO_STATIC_PARAMS_CMDID = 0x081b,
MAC_IO_DYNAMIC_PARAMS_CMDID = 0x081c,
WMI_SILENT_RSSI_CALIB_CMDID = 0x081d,
+ WMI_RF_RX_TEST_CMDID = 0x081e,
WMI_CFG_RX_CHAIN_CMDID = 0x0820,
WMI_VRING_CFG_CMDID = 0x0821,
- WMI_RX_ON_CMDID = 0x0822,
WMI_VRING_BA_EN_CMDID = 0x0823,
WMI_VRING_BA_DIS_CMDID = 0x0824,
WMI_RCP_ADDBA_RESP_CMDID = 0x0825,
@@ -87,7 +87,6 @@ enum wmi_command_id {
WMI_SET_PCP_CHANNEL_CMDID = 0x0829,
WMI_GET_PCP_CHANNEL_CMDID = 0x082a,
WMI_SW_TX_REQ_CMDID = 0x082b,
- WMI_RX_OFF_CMDID = 0x082c,
WMI_READ_MAC_RXQ_CMDID = 0x0830,
WMI_READ_MAC_TXQ_CMDID = 0x0831,
WMI_WRITE_MAC_RXQ_CMDID = 0x0832,
@@ -112,6 +111,18 @@ enum wmi_command_id {
WMI_FLASH_READ_CMDID = 0x0902,
WMI_FLASH_WRITE_CMDID = 0x0903,
WMI_SECURITY_UNIT_TEST_CMDID = 0x0904,
+ /*P2P*/
+ WMI_P2P_CFG_CMDID = 0x0910,
+ WMI_PORT_ALLOCATE_CMDID = 0x0911,
+ WMI_PORT_DELETE_CMDID = 0x0912,
+ WMI_POWER_MGMT_CFG_CMDID = 0x0913,
+ WMI_START_LISTEN_CMDID = 0x0914,
+ WMI_START_SEARCH_CMDID = 0x0915,
+ WMI_DISCOVERY_START_CMDID = 0x0916,
+ WMI_DISCOVERY_STOP_CMDID = 0x0917,
+ WMI_PCP_START_CMDID = 0x0918,
+ WMI_PCP_STOP_CMDID = 0x0919,
+ WMI_GET_PCP_FACTOR_CMDID = 0x091b,
WMI_SET_MAC_ADDRESS_CMDID = 0xf003,
WMI_ABORT_SCAN_CMDID = 0xf007,
@@ -132,18 +143,6 @@ enum wmi_command_id {
*/
/*
- * Frame Types
- */
-enum wmi_mgmt_frame_type {
- WMI_FRAME_BEACON = 0,
- WMI_FRAME_PROBE_REQ = 1,
- WMI_FRAME_PROBE_RESP = 2,
- WMI_FRAME_ASSOC_REQ = 3,
- WMI_FRAME_ASSOC_RESP = 4,
- WMI_NUM_MGMT_FRAME,
-};
-
-/*
* WMI_CONNECT_CMDID
*/
enum wmi_network_type {
@@ -184,7 +183,7 @@ enum wmi_crypto_type {
enum wmi_connect_ctrl_flag_bits {
WMI_CONNECT_ASSOC_POLICY_USER = 0x0001,
WMI_CONNECT_SEND_REASSOC = 0x0002,
- WMI_CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004,
+ WMI_CONNECT_IGNORE_WPA_GROUP_CIPHER = 0x0004,
WMI_CONNECT_PROFILE_MATCH_DONE = 0x0008,
WMI_CONNECT_IGNORE_AAC_BEACON = 0x0010,
WMI_CONNECT_CSA_FOLLOW_BSS = 0x0020,
@@ -212,6 +211,13 @@ struct wmi_connect_cmd {
u8 reserved1[2];
} __packed;
+/*
+ * WMI_DISCONNECT_STA_CMDID
+ */
+struct wmi_disconnect_sta_cmd {
+ u8 dst_mac[WMI_MAC_LEN];
+ __le16 disconnect_reason;
+} __packed;
/*
* WMI_RECONNECT_CMDID
@@ -289,10 +295,12 @@ struct wmi_delete_cipher_key_cmd {
enum wmi_scan_type {
WMI_LONG_SCAN = 0,
WMI_SHORT_SCAN = 1,
+ WMI_PBC_SCAN = 2,
};
struct wmi_start_scan_cmd {
u8 reserved[8];
+
__le32 home_dwell_time; /* Max duration in the home channel(ms) */
__le32 force_scan_interval; /* Time interval between scans (ms)*/
u8 scan_type; /* wmi_scan_type */
@@ -309,7 +317,7 @@ struct wmi_start_scan_cmd {
/*
* WMI_SET_PROBED_SSID_CMDID
*/
-#define MAX_PROBED_SSID_INDEX (15)
+#define MAX_PROBED_SSID_INDEX (3)
enum wmi_ssid_flag {
WMI_SSID_FLAG_DISABLE = 0, /* disables entry */
@@ -328,6 +336,20 @@ struct wmi_probed_ssid_cmd {
* WMI_SET_APPIE_CMDID
* Add Application specified IE to a management frame
*/
+#define WMI_MAX_IE_LEN (1024)
+
+/*
+ * Frame Types
+ */
+enum wmi_mgmt_frame_type {
+ WMI_FRAME_BEACON = 0,
+ WMI_FRAME_PROBE_REQ = 1,
+ WMI_FRAME_PROBE_RESP = 2,
+ WMI_FRAME_ASSOC_REQ = 3,
+ WMI_FRAME_ASSOC_RESP = 4,
+ WMI_NUM_MGMT_FRAME,
+};
+
struct wmi_set_appie_cmd {
u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */
u8 reserved;
@@ -335,13 +357,18 @@ struct wmi_set_appie_cmd {
u8 ie_info[0];
} __packed;
-#define WMI_MAX_IE_LEN (1024)
+/*
+ * WMI_PXMT_RANGE_CFG_CMDID
+ */
struct wmi_pxmt_range_cfg_cmd {
u8 dst_mac[WMI_MAC_LEN];
__le16 range;
} __packed;
+/*
+ * WMI_PXMT_SNR2_RANGE_CFG_CMDID
+ */
struct wmi_pxmt_snr2_range_cfg_cmd {
s8 snr2range_arr[WMI_PROX_RANGE_NUM-1];
} __packed;
@@ -359,6 +386,23 @@ struct wmi_rf_mgmt_cmd {
__le32 rf_mgmt_type;
} __packed;
+
+/*
+ * WMI_RF_RX_TEST_CMDID
+ */
+struct wmi_rf_rx_test_cmd {
+ __le32 sector;
+} __packed;
+
+/*
+ * WMI_CORR_MEASURE_CMDID
+ */
+struct wmi_corr_measure_cmd {
+ s32 freq_mhz;
+ __le32 length_samples;
+ __le32 iterations;
+} __packed;
+
/*
* WMI_SET_SSID_CMDID
*/
@@ -388,6 +432,74 @@ struct wmi_bcon_ctrl_cmd {
u8 disable_sec;
} __packed;
+
+/******* P2P ***********/
+
+/*
+ * WMI_PORT_ALLOCATE_CMDID
+ */
+enum wmi_port_role {
+ WMI_PORT_STA = 0,
+ WMI_PORT_PCP = 1,
+ WMI_PORT_AP = 2,
+ WMI_PORT_P2P_DEV = 3,
+ WMI_PORT_P2P_CLIENT = 4,
+ WMI_PORT_P2P_GO = 5,
+};
+
+struct wmi_port_allocate_cmd {
+ u8 mac[WMI_MAC_LEN];
+ u8 port_role;
+ u8 midid;
+} __packed;
+
+/*
+ * WMI_PORT_DELETE_CMDID
+ */
+struct wmi_delete_port_cmd {
+ u8 mid;
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_P2P_CFG_CMDID
+ */
+enum wmi_discovery_mode {
+ WMI_DISCOVERY_MODE_NON_OFFLOAD = 0,
+ WMI_DISCOVERY_MODE_OFFLOAD = 1,
+};
+
+struct wmi_p2p_cfg_cmd {
+ u8 discovery_mode; /* wmi_discovery_mode */
+ u8 channel;
+ __le16 bcon_interval; /* base to listen/search duration calculation */
+} __packed;
+
+/*
+ * WMI_POWER_MGMT_CFG_CMDID
+ */
+enum wmi_power_source_type {
+ WMI_POWER_SOURCE_BATTERY = 0,
+ WMI_POWER_SOURCE_OTHER = 1,
+};
+
+struct wmi_power_mgmt_cfg_cmd {
+ u8 power_source; /* wmi_power_source_type */
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_START_CMDID
+ */
+struct wmi_pcp_start_cmd {
+ __le16 bcon_interval;
+ u8 reserved0[10];
+ u8 network_type;
+ u8 channel;
+ u8 disable_sec_offload;
+ u8 disable_sec;
+} __packed;
+
/*
* WMI_SW_TX_REQ_CMDID
*/
@@ -435,16 +547,17 @@ enum wmi_vring_cfg_schd_params_priority {
WMI_SCH_PRIO_HIGH = 1,
};
+#define CIDXTID_CID_POS (0)
+#define CIDXTID_CID_LEN (4)
+#define CIDXTID_CID_MSK (0xF)
+#define CIDXTID_TID_POS (4)
+#define CIDXTID_TID_LEN (4)
+#define CIDXTID_TID_MSK (0xF0)
+
struct wmi_vring_cfg {
struct wmi_sw_ring_cfg tx_sw_ring;
u8 ringid; /* 0-23 vrings */
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
u8 encap_trans_type;
@@ -501,8 +614,14 @@ struct wmi_vring_ba_dis_cmd {
*/
struct wmi_notify_req_cmd {
u8 cid;
- u8 reserved[3];
+ u8 year;
+ u8 month;
+ u8 day;
__le32 interval_usec;
+ u8 hour;
+ u8 minute;
+ u8 second;
+ u8 miliseconds;
} __packed;
/*
@@ -548,6 +667,11 @@ enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
WMI_NWIFI_RX_TRANS_MODE_PBSS2STA = 2,
};
+enum wmi_cfg_rx_chain_cmd_reorder_type {
+ WMI_RX_HW_REORDER = 0,
+ WMI_RX_SW_REORDER = 1,
+};
+
struct wmi_cfg_rx_chain_cmd {
__le32 action;
struct wmi_sw_ring_cfg rx_sw_ring;
@@ -596,7 +720,8 @@ struct wmi_cfg_rx_chain_cmd {
__le16 wb_thrsh;
__le32 itr_value;
__le16 host_thrsh;
- u8 reserved[2];
+ u8 reorder_type;
+ u8 reserved;
struct wmi_sniffer_cfg sniffer_cfg;
} __packed;
@@ -604,15 +729,7 @@ struct wmi_cfg_rx_chain_cmd {
* WMI_RCP_ADDBA_RESP_CMDID
*/
struct wmi_rcp_addba_resp_cmd {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 dialog_token;
__le16 status_code;
__le16 ba_param_set; /* ieee80211_ba_parameterset field to send */
@@ -623,15 +740,7 @@ struct wmi_rcp_addba_resp_cmd {
* WMI_RCP_DELBA_CMDID
*/
struct wmi_rcp_delba_cmd {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 reserved;
__le16 reason;
} __packed;
@@ -640,15 +749,7 @@ struct wmi_rcp_delba_cmd {
* WMI_RCP_ADDBA_REQ_CMDID
*/
struct wmi_rcp_addba_req_cmd {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 dialog_token;
/* ieee80211_ba_parameterset field as it received */
__le16 ba_param_set;
@@ -665,7 +766,6 @@ struct wmi_set_mac_address_cmd {
u8 reserved[2];
} __packed;
-
/*
* WMI_EAPOL_TX_CMDID
*/
@@ -692,6 +792,17 @@ struct wmi_echo_cmd {
} __packed;
/*
+ * WMI_TEMP_SENSE_CMDID
+ *
+ * Measure MAC and radio temperatures
+ */
+struct wmi_temp_sense_cmd {
+ __le32 measure_marlon_m_en;
+ __le32 measure_marlon_r_en;
+} __packed;
+
+
+/*
* WMI Events
*/
@@ -699,7 +810,6 @@ struct wmi_echo_cmd {
* List of Events (target to host)
*/
enum wmi_event_id {
- WMI_IMM_RSP_EVENTID = 0x0000,
WMI_READY_EVENTID = 0x1001,
WMI_CONNECT_EVENTID = 0x1002,
WMI_DISCONNECT_EVENTID = 0x1003,
@@ -709,13 +819,9 @@ enum wmi_event_id {
WMI_FW_READY_EVENTID = 0x1801,
WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x0200,
WMI_ECHO_RSP_EVENTID = 0x1803,
- WMI_CONFIG_MAC_DONE_EVENTID = 0x1805,
- WMI_CONFIG_PHY_DEBUG_DONE_EVENTID = 0x1806,
- WMI_ADD_STATION_DONE_EVENTID = 0x1807,
- WMI_ADD_DEBUG_TX_PCKT_DONE_EVENTID = 0x1808,
- WMI_PHY_GET_STATISTICS_EVENTID = 0x1809,
WMI_FS_TUNE_DONE_EVENTID = 0x180a,
- WMI_CORR_MEASURE_DONE_EVENTID = 0x180b,
+ WMI_CORR_MEASURE_EVENTID = 0x180b,
+ WMI_READ_RSSI_EVENTID = 0x180c,
WMI_TEMP_SENSE_DONE_EVENTID = 0x180e,
WMI_DC_CALIB_DONE_EVENTID = 0x180f,
WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811,
@@ -727,10 +833,9 @@ enum wmi_event_id {
WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819,
WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181a,
WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181d,
-
+ WMI_RF_RX_TEST_DONE_EVENTID = 0x181e,
WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820,
WMI_VRING_CFG_DONE_EVENTID = 0x1821,
- WMI_RX_ON_DONE_EVENTID = 0x1822,
WMI_BA_STATUS_EVENTID = 0x1823,
WMI_RCP_ADDBA_REQ_EVENTID = 0x1824,
WMI_ADDBA_RESP_SENT_EVENTID = 0x1825,
@@ -738,7 +843,6 @@ enum wmi_event_id {
WMI_GET_SSID_EVENTID = 0x1828,
WMI_GET_PCP_CHANNEL_EVENTID = 0x182a,
WMI_SW_TX_COMPLETE_EVENTID = 0x182b,
- WMI_RX_OFF_DONE_EVENTID = 0x182c,
WMI_READ_MAC_RXQ_EVENTID = 0x1830,
WMI_READ_MAC_TXQ_EVENTID = 0x1831,
@@ -765,7 +869,16 @@ enum wmi_event_id {
WMI_UNIT_TEST_EVENTID = 0x1900,
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
WMI_FLASH_WRITE_DONE_EVENTID = 0x1903,
-
+ /*P2P*/
+ WMI_PORT_ALLOCATED_EVENTID = 0x1911,
+ WMI_PORT_DELETED_EVENTID = 0x1912,
+ WMI_LISTEN_STARTED_EVENTID = 0x1914,
+ WMI_SEARCH_STARTED_EVENTID = 0x1915,
+ WMI_DISCOVERY_STARTED_EVENTID = 0x1916,
+ WMI_DISCOVERY_STOPPED_EVENTID = 0x1917,
+ WMI_PCP_STARTED_EVENTID = 0x1918,
+ WMI_PCP_STOPPED_EVENTID = 0x1919,
+ WMI_PCP_FACTOR_EVENTID = 0x191a,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
@@ -777,6 +890,12 @@ enum wmi_event_id {
* Events data structures
*/
+
+enum wmi_fw_status {
+ WMI_FW_STATUS_SUCCESS,
+ WMI_FW_STATUS_FAILURE,
+};
+
/*
* WMI_RF_MGMT_STATUS_EVENTID
*/
@@ -857,7 +976,7 @@ struct wmi_ready_event {
__le32 abi_version;
u8 mac[WMI_MAC_LEN];
u8 phy_capability; /* enum wmi_phy_capability */
- u8 reserved;
+ u8 numof_additional_mids;
} __packed;
/*
@@ -876,6 +995,8 @@ struct wmi_notify_req_done_event {
__le16 other_rx_sector;
__le16 other_tx_sector;
__le16 range;
+ u8 sqi;
+ u8 reserved[3];
} __packed;
/*
@@ -951,27 +1072,15 @@ struct wmi_vring_ba_status_event {
* WMI_DELBA_EVENTID
*/
struct wmi_delba_event {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 from_initiator;
__le16 reason;
} __packed;
+
/*
* WMI_VRING_CFG_DONE_EVENTID
*/
-enum wmi_vring_cfg_done_event_status {
- WMI_VRING_CFG_SUCCESS = 0,
- WMI_VRING_CFG_FAILURE = 1,
-};
-
struct wmi_vring_cfg_done_event {
u8 ringid;
u8 status;
@@ -982,21 +1091,8 @@ struct wmi_vring_cfg_done_event {
/*
* WMI_ADDBA_RESP_SENT_EVENTID
*/
-enum wmi_rcp_addba_resp_sent_event_status {
- WMI_ADDBA_SUCCESS = 0,
- WMI_ADDBA_FAIL = 1,
-};
-
struct wmi_rcp_addba_resp_sent_event {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 reserved;
__le16 status;
} __packed;
@@ -1005,15 +1101,7 @@ struct wmi_rcp_addba_resp_sent_event {
* WMI_RCP_ADDBA_REQ_EVENTID
*/
struct wmi_rcp_addba_req_event {
-
- #define CIDXTID_CID_POS (0)
- #define CIDXTID_CID_LEN (4)
- #define CIDXTID_CID_MSK (0xF)
- #define CIDXTID_TID_POS (4)
- #define CIDXTID_TID_LEN (4)
- #define CIDXTID_TID_MSK (0xF0)
u8 cidxtid;
-
u8 dialog_token;
__le16 ba_param_set; /* ieee80211_ba_parameterset as it received */
__le16 ba_timeout;
@@ -1055,6 +1143,7 @@ struct wmi_data_port_open_event {
u8 reserved[3];
} __packed;
+
/*
* WMI_GET_PCP_CHANNEL_EVENTID
*/
@@ -1063,6 +1152,54 @@ struct wmi_get_pcp_channel_event {
u8 reserved[3];
} __packed;
+
+/*
+* WMI_PORT_ALLOCATED_EVENTID
+*/
+struct wmi_port_allocated_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
+* WMI_PORT_DELETED_EVENTID
+*/
+struct wmi_port_deleted_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_LISTEN_STARTED_EVENTID
+ */
+struct wmi_listen_started_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_SEARCH_STARTED_EVENTID
+ */
+struct wmi_search_started_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_STARTED_EVENTID
+ */
+struct wmi_pcp_started_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
+ * WMI_PCP_FACTOR_EVENTID
+ */
+struct wmi_pcp_factor_event {
+ __le32 pcp_factor;
+} __packed;
+
/*
* WMI_SW_TX_COMPLETE_EVENTID
*/
@@ -1078,6 +1215,23 @@ struct wmi_sw_tx_complete_event {
} __packed;
/*
+ * WMI_CORR_MEASURE_EVENTID
+ */
+struct wmi_corr_measure_event {
+ s32 i;
+ s32 q;
+ s32 image_i;
+ s32 image_q;
+} __packed;
+
+/*
+ * WMI_READ_RSSI_EVENTID
+ */
+struct wmi_read_rssi_event {
+ __le32 ina_rssi_adc_dbm;
+} __packed;
+
+/*
* WMI_GET_SSID_EVENTID
*/
struct wmi_get_ssid_event {
@@ -1091,7 +1245,8 @@ struct wmi_get_ssid_event {
struct wmi_rx_mgmt_info {
u8 mcs;
s8 snr;
- __le16 range;
+ u8 range;
+ u8 sqi;
__le16 stype;
__le16 status;
__le32 len;
@@ -1113,4 +1268,14 @@ struct wmi_echo_event {
__le32 echoed_value;
} __packed;
+/*
+ * WMI_TEMP_SENSE_DONE_EVENTID
+ *
+ * Measure MAC and radio temperatures
+ */
+struct wmi_temp_sense_done_event {
+ __le32 marlon_m_t1000;
+ __le32 marlon_r_t1000;
+} __packed;
+
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index b42930f457c2..522572219217 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -245,16 +245,7 @@ static struct pcmcia_driver atmel_driver = {
.suspend = atmel_suspend,
.resume = atmel_resume,
};
-
-static int __init atmel_cs_init(void)
-{
- return pcmcia_register_driver(&atmel_driver);
-}
-
-static void __exit atmel_cs_cleanup(void)
-{
- pcmcia_unregister_driver(&atmel_driver);
-}
+module_pcmcia_driver(atmel_driver);
/*
This program is free software; you can redistribute it and/or
@@ -294,6 +285,3 @@ static void __exit atmel_cs_cleanup(void)
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
-
-module_init(atmel_cs_init);
-module_exit(atmel_cs_cleanup);
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 287c6b670a36..078e6f3477a9 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -131,7 +131,7 @@ config B43_PHY_LP
config B43_PHY_HT
bool "Support for HT-PHY (high throughput) devices"
- depends on B43
+ depends on B43 && B43_BCMA
---help---
Support for the HT-PHY.
@@ -166,8 +166,8 @@ config B43_DEBUG
Broadcom 43xx debugging.
This adds additional runtime sanity checks and statistics to the driver.
- These checks and statistics might me expensive and hurt runtime performance
- of your system.
+ These checks and statistics might be expensive and hurt the runtime
+ performance of your system.
This also adds the b43 debugfs interface.
Do not enable this, unless you are debugging the driver.
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 10e288d470e7..7f3d461f7e8d 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -285,7 +285,9 @@ enum {
#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
/* SHM_SHARED beacon/AP variables */
+#define B43_SHM_SH_BT_BASE0 0x0068 /* Beacon template base 0 */
#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
+#define B43_SHM_SH_BT_BASE1 0x0468 /* Beacon template base 1 */
#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
@@ -473,6 +475,12 @@ enum {
#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */
#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */
+/* See BCMA_CLKCTLST_EXTRESREQ and BCMA_CLKCTLST_EXTRESST */
+#define B43_BCMA_CLKCTLST_80211_PLL_REQ 0x00000100
+#define B43_BCMA_CLKCTLST_PHY_PLL_REQ 0x00000200
+#define B43_BCMA_CLKCTLST_80211_PLL_ST 0x01000000
+#define B43_BCMA_CLKCTLST_PHY_PLL_ST 0x02000000
+
/* BCMA 802.11 core specific IO Control (BCMA_IOCTL) flags */
#define B43_BCMA_IOCTL_PHY_CLKEN 0x00000004 /* PHY Clock Enable */
#define B43_BCMA_IOCTL_PHY_RESET 0x00000008 /* PHY Reset */
@@ -972,7 +980,7 @@ static inline int b43_is_mode(struct b43_wl *wl, int type)
*/
static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
{
- return wl->hw->conf.channel->band;
+ return wl->hw->conf.chandef.chan->band;
}
static inline int b43_bus_may_powerdown(struct b43_wldev *wldev)
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 38bc5a7997ff..523355b87659 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -419,8 +419,6 @@ static inline
static int alloc_ringmemory(struct b43_dmaring *ring)
{
- gfp_t flags = GFP_KERNEL;
-
/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
* alignment and 8K buffers for 64-bit DMA with 8K alignment.
* In practice we could use smaller buffers for the latter, but the
@@ -435,12 +433,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
ring_mem_size, &(ring->dmabase),
- flags);
- if (!ring->descbase) {
- b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+ GFP_KERNEL | __GFP_ZERO);
+ if (!ring->descbase)
return -ENOMEM;
- }
- memset(ring->descbase, 0, ring_mem_size);
return 0;
}
@@ -1487,8 +1482,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
const struct b43_dma_ops *ops;
struct b43_dmaring *ring;
struct b43_dmadesc_meta *meta;
+ static const struct b43_txstatus fake; /* filled with 0 */
+ const struct b43_txstatus *txstat;
int slot, firstused;
bool frame_succeed;
+ int skip;
+ static u8 err_out1, err_out2;
ring = parse_cookie(dev, status->cookie, &slot);
if (unlikely(!ring))
@@ -1501,13 +1500,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
firstused = ring->current_slot - ring->used_slots + 1;
if (firstused < 0)
firstused = ring->nr_slots + firstused;
+
+ skip = 0;
if (unlikely(slot != firstused)) {
/* This possibly is a firmware bug and will result in
- * malfunction, memory leaks and/or stall of DMA functionality. */
- b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
- "Expected %d, but got %d\n",
- ring->index, firstused, slot);
- return;
+ * malfunction, memory leaks and/or stall of DMA functionality.
+ */
+ if (slot == next_slot(ring, next_slot(ring, firstused))) {
+ /* If a single header/data pair was missed, skip over
+ * the first two slots in an attempt to recover.
+ */
+ slot = firstused;
+ skip = 2;
+ if (!err_out1) {
+ /* Report the error once. */
+ b43dbg(dev->wl,
+ "Skip on DMA ring %d slot %d.\n",
+ ring->index, slot);
+ err_out1 = 1;
+ }
+ } else {
+ /* More than a single header/data pair were missed.
+ * Report this error once.
+ */
+ if (!err_out2)
+ b43dbg(dev->wl,
+ "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n",
+ ring->index, firstused, slot);
+ err_out2 = 1;
+ return;
+ }
}
ops = ring->ops;
@@ -1522,11 +1544,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
slot, firstused, ring->index);
break;
}
+
if (meta->skb) {
struct b43_private_tx_info *priv_info =
- b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
+ b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
- unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
kfree(priv_info->bouncebuffer);
priv_info->bouncebuffer = NULL;
} else {
@@ -1538,8 +1562,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
struct ieee80211_tx_info *info;
if (unlikely(!meta->skb)) {
- /* This is a scatter-gather fragment of a frame, so
- * the skb pointer must not be NULL. */
+ /* This is a scatter-gather fragment of a frame,
+ * so the skb pointer must not be NULL.
+ */
b43dbg(dev->wl, "TX status unexpected NULL skb "
"at slot %d (first=%d) on ring %d\n",
slot, firstused, ring->index);
@@ -1550,9 +1575,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
/*
* Call back to inform the ieee80211 subsystem about
- * the status of the transmission.
+ * the status of the transmission. When skipping over
+ * a missed TX status report, use a status structure
+ * filled with zeros to indicate that the frame was not
+ * sent (frame_count 0) and not acknowledged
*/
- frame_succeed = b43_fill_txstatus_report(dev, info, status);
+ if (unlikely(skip))
+ txstat = &fake;
+ else
+ txstat = status;
+
+ frame_succeed = b43_fill_txstatus_report(dev, info,
+ txstat);
#ifdef CONFIG_B43_DEBUG
if (frame_succeed)
ring->nr_succeed_tx_packets++;
@@ -1580,12 +1614,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
/* Everything unmapped and free'd. So it's not used anymore. */
ring->used_slots--;
- if (meta->is_last_fragment) {
+ if (meta->is_last_fragment && !skip) {
/* This is the last scatter-gather
* fragment of the frame. We are done. */
break;
}
slot = next_slot(ring, slot);
+ if (skip > 0)
+ --skip;
}
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 05682736e466..d377f77d30b5 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1189,10 +1189,15 @@ static void b43_bcma_phy_reset(struct b43_wldev *dev)
static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
{
+ u32 req = B43_BCMA_CLKCTLST_80211_PLL_REQ |
+ B43_BCMA_CLKCTLST_PHY_PLL_REQ;
+ u32 status = B43_BCMA_CLKCTLST_80211_PLL_ST |
+ B43_BCMA_CLKCTLST_PHY_PLL_ST;
+
b43_device_enable(dev, B43_BCMA_IOCTL_PHY_CLKEN);
bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
b43_bcma_phy_reset(dev);
- bcma_core_pll_ctl(dev->dev->bdev, 0x300, 0x3000000, true);
+ bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
}
#endif
@@ -1305,17 +1310,19 @@ static u32 b43_jssi_read(struct b43_wldev *dev)
{
u32 val = 0;
- val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
+ val = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1);
val <<= 16;
- val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
+ val |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0);
return val;
}
static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
{
- b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
- b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI0,
+ (jssi & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_JSSI1,
+ (jssi & 0xFFFF0000) >> 16);
}
static void b43_generate_noise_sample(struct b43_wldev *dev)
@@ -1618,7 +1625,7 @@ static void b43_upload_beacon0(struct b43_wldev *dev)
if (wl->beacon0_uploaded)
return;
- b43_write_beacon_template(dev, 0x68, 0x18);
+ b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE0, B43_SHM_SH_BTL0);
wl->beacon0_uploaded = true;
}
@@ -1628,7 +1635,7 @@ static void b43_upload_beacon1(struct b43_wldev *dev)
if (wl->beacon1_uploaded)
return;
- b43_write_beacon_template(dev, 0x468, 0x1A);
+ b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE1, B43_SHM_SH_BTL1);
wl->beacon1_uploaded = true;
}
@@ -2775,9 +2782,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
- (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
- BCMA_CC_GPIOCTL) & ~mask) | set);
+ bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set);
break;
#endif
#ifdef CONFIG_B43_SSB
@@ -2802,8 +2807,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
- 0);
+ bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, ~0, 0);
break;
#endif
#ifdef CONFIG_B43_SSB
@@ -3111,7 +3115,7 @@ static int b43_chip_init(struct b43_wldev *dev)
/* Probe Response Timeout value */
/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
- b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 0);
/* Initially set the wireless operation mode. */
b43_adjust_opmode(dev);
@@ -3848,7 +3852,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
dev = wl->current_dev;
/* Switch the band (if necessary). This might change the active core. */
- err = b43_switch_band(wl, conf->channel);
+ err = b43_switch_band(wl, conf->chandef.chan);
if (err)
goto out_unlock_mutex;
@@ -3878,8 +3882,8 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
- if (conf->channel->hw_value != phy->channel)
- b43_switch_channel(dev, conf->channel->hw_value);
+ if (conf->chandef.chan->hw_value != phy->channel)
+ b43_switch_channel(dev, conf->chandef.chan->hw_value);
dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
@@ -5002,7 +5006,7 @@ static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = dev->stats.link_noise;
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index f2ea2ceec8a9..55f2bd7f8f74 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -130,6 +130,10 @@ static struct pcmcia_driver b43_pcmcia_driver = {
.resume = b43_pcmcia_resume,
};
+/*
+ * These are not module init/exit functions!
+ * The module_pcmcia_driver() helper cannot be used here.
+ */
int b43_pcmcia_init(void)
{
return pcmcia_register_driver(&b43_pcmcia_driver);
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c
index 7416c5e9154d..5d6833f18498 100644
--- a/drivers/net/wireless/b43/phy_ht.c
+++ b/drivers/net/wireless/b43/phy_ht.c
@@ -30,6 +30,17 @@
#include "radio_2059.h"
#include "main.h"
+/* Force values to keep compatibility with wl */
+enum ht_rssi_type {
+ HT_RSSI_W1 = 0,
+ HT_RSSI_W2 = 1,
+ HT_RSSI_NB = 2,
+ HT_RSSI_IQ = 3,
+ HT_RSSI_TSSI_2G = 4,
+ HT_RSSI_TSSI_5G = 5,
+ HT_RSSI_TBD = 6,
+};
+
/**************************************************
* Radio 2059.
**************************************************/
@@ -37,8 +48,9 @@
static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_radio2059 *e)
{
- u8 i;
- u16 routing;
+ static const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3, };
+ u16 r;
+ int core;
b43_radio_write(dev, 0x16, e->radio_syn16);
b43_radio_write(dev, 0x17, e->radio_syn17);
@@ -53,25 +65,17 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
b43_radio_write(dev, 0x41, e->radio_syn41);
b43_radio_write(dev, 0x43, e->radio_syn43);
b43_radio_write(dev, 0x47, e->radio_syn47);
- b43_radio_write(dev, 0x4a, e->radio_syn4a);
- b43_radio_write(dev, 0x58, e->radio_syn58);
- b43_radio_write(dev, 0x5a, e->radio_syn5a);
- b43_radio_write(dev, 0x6a, e->radio_syn6a);
- b43_radio_write(dev, 0x6d, e->radio_syn6d);
- b43_radio_write(dev, 0x6e, e->radio_syn6e);
- b43_radio_write(dev, 0x92, e->radio_syn92);
- b43_radio_write(dev, 0x98, e->radio_syn98);
-
- for (i = 0; i < 2; i++) {
- routing = i ? R2059_RXRX1 : R2059_TXRX0;
- b43_radio_write(dev, routing | 0x4a, e->radio_rxtx4a);
- b43_radio_write(dev, routing | 0x58, e->radio_rxtx58);
- b43_radio_write(dev, routing | 0x5a, e->radio_rxtx5a);
- b43_radio_write(dev, routing | 0x6a, e->radio_rxtx6a);
- b43_radio_write(dev, routing | 0x6d, e->radio_rxtx6d);
- b43_radio_write(dev, routing | 0x6e, e->radio_rxtx6e);
- b43_radio_write(dev, routing | 0x92, e->radio_rxtx92);
- b43_radio_write(dev, routing | 0x98, e->radio_rxtx98);
+
+ for (core = 0; core < 3; core++) {
+ r = routing[core];
+ b43_radio_write(dev, r | 0x4a, e->radio_rxtx4a);
+ b43_radio_write(dev, r | 0x58, e->radio_rxtx58);
+ b43_radio_write(dev, r | 0x5a, e->radio_rxtx5a);
+ b43_radio_write(dev, r | 0x6a, e->radio_rxtx6a);
+ b43_radio_write(dev, r | 0x6d, e->radio_rxtx6d);
+ b43_radio_write(dev, r | 0x6e, e->radio_rxtx6e);
+ b43_radio_write(dev, r | 0x92, e->radio_rxtx92);
+ b43_radio_write(dev, r | 0x98, e->radio_rxtx98);
}
udelay(50);
@@ -87,7 +91,7 @@ static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
static void b43_radio_2059_init(struct b43_wldev *dev)
{
- const u16 routing[] = { R2059_SYN, R2059_TXRX0, R2059_RXRX1 };
+ const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3 };
const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
@@ -106,17 +110,17 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
b43_radio_mask(dev, 0xc0, ~0x0080);
if (1) { /* FIXME */
- b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x1);
+ b43_radio_set(dev, R2059_C3 | 0x4, 0x1);
udelay(10);
- b43_radio_set(dev, R2059_RXRX1 | 0x0BF, 0x1);
- b43_radio_maskset(dev, R2059_RXRX1 | 0x19B, 0x3, 0x2);
+ b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
+ b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
- b43_radio_set(dev, R2059_RXRX1 | 0x4, 0x2);
+ b43_radio_set(dev, R2059_C3 | 0x4, 0x2);
udelay(100);
- b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x2);
+ b43_radio_mask(dev, R2059_C3 | 0x4, ~0x2);
for (i = 0; i < 10000; i++) {
- if (b43_radio_read(dev, R2059_RXRX1 | 0x145) & 1) {
+ if (b43_radio_read(dev, R2059_C3 | 0x145) & 1) {
i = 0;
break;
}
@@ -125,7 +129,7 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
if (i)
b43err(dev->wl, "radio 0x945 timeout\n");
- b43_radio_mask(dev, R2059_RXRX1 | 0x4, ~0x1);
+ b43_radio_mask(dev, R2059_C3 | 0x4, ~0x1);
b43_radio_set(dev, 0xa, 0x60);
for (i = 0; i < 3; i++) {
@@ -154,9 +158,84 @@ static void b43_radio_2059_init(struct b43_wldev *dev)
}
/**************************************************
+ * RF
+ **************************************************/
+
+static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
+{
+ u8 i;
+
+ u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
+
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
+ for (i = 0; i < 200; i++) {
+ if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
+ i = 0;
+ break;
+ }
+ msleep(1);
+ }
+ if (i)
+ b43err(dev->wl, "Forcing RF sequence timeout\n");
+
+ b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_pa_override(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_ht *htphy = dev->phy.ht;
+ static const u16 regs[3] = { B43_PHY_HT_RF_CTL_INT_C1,
+ B43_PHY_HT_RF_CTL_INT_C2,
+ B43_PHY_HT_RF_CTL_INT_C3 };
+ int i;
+
+ if (enable) {
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, regs[i], htphy->rf_ctl_int_save[i]);
+ } else {
+ for (i = 0; i < 3; i++)
+ htphy->rf_ctl_int_save[i] = b43_phy_read(dev, regs[i]);
+ /* TODO: Does 5GHz band use different value (not 0x0400)? */
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, regs[i], 0x0400);
+ }
+}
+
+/**************************************************
* Various PHY ops
**************************************************/
+static u16 b43_phy_ht_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+{
+ u16 tmp;
+ u16 allowed = B43_PHY_HT_CLASS_CTL_CCK_EN |
+ B43_PHY_HT_CLASS_CTL_OFDM_EN |
+ B43_PHY_HT_CLASS_CTL_WAITED_EN;
+
+ tmp = b43_phy_read(dev, B43_PHY_HT_CLASS_CTL);
+ tmp &= allowed;
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ b43_phy_maskset(dev, B43_PHY_HT_CLASS_CTL, ~allowed, tmp);
+
+ return tmp;
+}
+
+static void b43_phy_ht_reset_cca(struct b43_wldev *dev)
+{
+ u16 bbcfg;
+
+ b43_phy_force_clock(dev, true);
+ bbcfg = b43_phy_read(dev, B43_PHY_HT_BBCFG);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg | B43_PHY_HT_BBCFG_RSTCCA);
+ udelay(1);
+ b43_phy_write(dev, B43_PHY_HT_BBCFG, bbcfg & ~B43_PHY_HT_BBCFG_RSTCCA);
+ b43_phy_force_clock(dev, false);
+
+ b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
+}
+
static void b43_phy_ht_zero_extg(struct b43_wldev *dev)
{
u8 i, j;
@@ -176,10 +255,10 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
{
u8 i;
- const u16 ctl_regs[3][2] = {
- { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 },
- { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 },
- { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6},
+ static const u16 ctl_regs[3][2] = {
+ { B43_PHY_HT_AFE_C1_OVER, B43_PHY_HT_AFE_C1 },
+ { B43_PHY_HT_AFE_C2_OVER, B43_PHY_HT_AFE_C2 },
+ { B43_PHY_HT_AFE_C3_OVER, B43_PHY_HT_AFE_C3},
};
for (i = 0; i < 3; i++) {
@@ -193,27 +272,6 @@ static void b43_phy_ht_afe_unk1(struct b43_wldev *dev)
}
}
-static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq)
-{
- u8 i;
-
- u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
- b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3);
-
- b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq);
- for (i = 0; i < 200; i++) {
- if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) {
- i = 0;
- break;
- }
- msleep(1);
- }
- if (i)
- b43err(dev->wl, "Forcing RF sequence timeout\n");
-
- b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
-}
-
static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
{
clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES);
@@ -240,15 +298,456 @@ static void b43_phy_ht_bphy_init(struct b43_wldev *dev)
}
/**************************************************
+ * Samples
+ **************************************************/
+
+static void b43_phy_ht_stop_playback(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 tmp;
+ int i;
+
+ tmp = b43_phy_read(dev, B43_PHY_HT_SAMP_STAT);
+ if (tmp & 0x1)
+ b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, B43_PHY_HT_SAMP_CMD_STOP);
+ else if (tmp & 0x2)
+ b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, 0x7FFF);
+
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0x0004);
+
+ for (i = 0; i < 3; i++) {
+ if (phy_ht->bb_mult_save[i] >= 0) {
+ b43_httab_write(dev, B43_HTTAB16(13, 0x63 + i * 4),
+ phy_ht->bb_mult_save[i]);
+ b43_httab_write(dev, B43_HTTAB16(13, 0x67 + i * 4),
+ phy_ht->bb_mult_save[i]);
+ }
+ }
+}
+
+static u16 b43_phy_ht_load_samples(struct b43_wldev *dev)
+{
+ int i;
+ u16 len = 20 << 3;
+
+ b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, 0x4400);
+
+ for (i = 0; i < len; i++) {
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, 0);
+ b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, 0);
+ }
+
+ return len;
+}
+
+static void b43_phy_ht_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+ u16 wait)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 save_seq_mode;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (phy_ht->bb_mult_save[i] < 0)
+ phy_ht->bb_mult_save[i] = b43_httab_read(dev, B43_HTTAB16(13, 0x63 + i * 4));
+ }
+
+ b43_phy_write(dev, B43_PHY_HT_SAMP_DEP_CNT, samps - 1);
+ if (loops != 0xFFFF)
+ loops--;
+ b43_phy_write(dev, B43_PHY_HT_SAMP_LOOP_CNT, loops);
+ b43_phy_write(dev, B43_PHY_HT_SAMP_WAIT_CNT, wait);
+
+ save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE);
+ b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE,
+ B43_PHY_HT_RF_SEQ_MODE_CA_OVER);
+
+ /* TODO: find out mask bits! Do we need more function arguments? */
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+ b43_phy_mask(dev, B43_PHY_HT_SAMP_CMD, ~0);
+ b43_phy_mask(dev, B43_PHY_HT_IQLOCAL_CMDGCTL, ~0);
+ b43_phy_set(dev, B43_PHY_HT_SAMP_CMD, 0x1);
+
+ for (i = 0; i < 100; i++) {
+ if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & 1)) {
+ i = 0;
+ break;
+ }
+ udelay(10);
+ }
+ if (i)
+ b43err(dev->wl, "run samples timeout\n");
+
+ b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode);
+}
+
+static void b43_phy_ht_tx_tone(struct b43_wldev *dev)
+{
+ u16 samp;
+
+ samp = b43_phy_ht_load_samples(dev);
+ b43_phy_ht_run_samples(dev, samp, 0xFFFF, 0);
+}
+
+/**************************************************
+ * RSSI
+ **************************************************/
+
+static void b43_phy_ht_rssi_select(struct b43_wldev *dev, u8 core_sel,
+ enum ht_rssi_type rssi_type)
+{
+ static const u16 ctl_regs[3][2] = {
+ { B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER, },
+ { B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER, },
+ { B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER, },
+ };
+ static const u16 radio_r[] = { R2059_C1, R2059_C2, R2059_C3, };
+ int core;
+
+ if (core_sel == 0) {
+ b43err(dev->wl, "RSSI selection for core off not implemented yet\n");
+ } else {
+ for (core = 0; core < 3; core++) {
+ /* Check if caller requested a one specific core */
+ if ((core_sel == 1 && core != 0) ||
+ (core_sel == 2 && core != 1) ||
+ (core_sel == 3 && core != 2))
+ continue;
+
+ switch (rssi_type) {
+ case HT_RSSI_TSSI_2G:
+ b43_phy_set(dev, ctl_regs[core][0], 0x3 << 8);
+ b43_phy_set(dev, ctl_regs[core][0], 0x3 << 10);
+ b43_phy_set(dev, ctl_regs[core][1], 0x1 << 9);
+ b43_phy_set(dev, ctl_regs[core][1], 0x1 << 10);
+
+ b43_radio_set(dev, R2059_C3 | 0xbf, 0x1);
+ b43_radio_write(dev, radio_r[core] | 0x159,
+ 0x11);
+ break;
+ default:
+ b43err(dev->wl, "RSSI selection for type %d not implemented yet\n",
+ rssi_type);
+ }
+ }
+ }
+}
+
+static void b43_phy_ht_poll_rssi(struct b43_wldev *dev, enum ht_rssi_type type,
+ s32 *buf, u8 nsamp)
+{
+ u16 phy_regs_values[12];
+ static const u16 phy_regs_to_save[] = {
+ B43_PHY_HT_AFE_C1, B43_PHY_HT_AFE_C1_OVER,
+ 0x848, 0x841,
+ B43_PHY_HT_AFE_C2, B43_PHY_HT_AFE_C2_OVER,
+ 0x868, 0x861,
+ B43_PHY_HT_AFE_C3, B43_PHY_HT_AFE_C3_OVER,
+ 0x888, 0x881,
+ };
+ u16 tmp[3];
+ int i;
+
+ for (i = 0; i < 12; i++)
+ phy_regs_values[i] = b43_phy_read(dev, phy_regs_to_save[i]);
+
+ b43_phy_ht_rssi_select(dev, 5, type);
+
+ for (i = 0; i < 6; i++)
+ buf[i] = 0;
+
+ for (i = 0; i < nsamp; i++) {
+ tmp[0] = b43_phy_read(dev, B43_PHY_HT_RSSI_C1);
+ tmp[1] = b43_phy_read(dev, B43_PHY_HT_RSSI_C2);
+ tmp[2] = b43_phy_read(dev, B43_PHY_HT_RSSI_C3);
+
+ buf[0] += ((s8)((tmp[0] & 0x3F) << 2)) >> 2;
+ buf[1] += ((s8)(((tmp[0] >> 8) & 0x3F) << 2)) >> 2;
+ buf[2] += ((s8)((tmp[1] & 0x3F) << 2)) >> 2;
+ buf[3] += ((s8)(((tmp[1] >> 8) & 0x3F) << 2)) >> 2;
+ buf[4] += ((s8)((tmp[2] & 0x3F) << 2)) >> 2;
+ buf[5] += ((s8)(((tmp[2] >> 8) & 0x3F) << 2)) >> 2;
+ }
+
+ for (i = 0; i < 12; i++)
+ b43_phy_write(dev, phy_regs_to_save[i], phy_regs_values[i]);
+}
+
+/**************************************************
+ * Tx/Rx
+ **************************************************/
+
+static void b43_phy_ht_tx_power_fix(struct b43_wldev *dev)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ u16 mask;
+ u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+
+ if (0) /* FIXME */
+ mask = 0x2 << (i * 4);
+ else
+ mask = 0;
+ b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
+
+ b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
+ b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
+ tmp & 0xFF);
+ b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
+ tmp & 0xFF);
+ }
+}
+
+static void b43_phy_ht_tx_power_ctl(struct b43_wldev *dev, bool enable)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ u16 en_bits = B43_PHY_HT_TXPCTL_CMD_C1_COEFF |
+ B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN |
+ B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN;
+ static const u16 cmd_regs[3] = { B43_PHY_HT_TXPCTL_CMD_C1,
+ B43_PHY_HT_TXPCTL_CMD_C2,
+ B43_PHY_HT_TXPCTL_CMD_C3 };
+ static const u16 status_regs[3] = { B43_PHY_HT_TX_PCTL_STATUS_C1,
+ B43_PHY_HT_TX_PCTL_STATUS_C2,
+ B43_PHY_HT_TX_PCTL_STATUS_C3 };
+ int i;
+
+ if (!enable) {
+ if (b43_phy_read(dev, B43_PHY_HT_TXPCTL_CMD_C1) & en_bits) {
+ /* We disable enabled TX pwr ctl, save it's state */
+ for (i = 0; i < 3; i++)
+ phy_ht->tx_pwr_idx[i] =
+ b43_phy_read(dev, status_regs[i]);
+ }
+ b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1, ~en_bits);
+ } else {
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_CMD_C1, en_bits);
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+ for (i = 0; i < 3; i++)
+ b43_phy_write(dev, cmd_regs[i], 0x32);
+ }
+
+ for (i = 0; i < 3; i++)
+ if (phy_ht->tx_pwr_idx[i] <=
+ B43_PHY_HT_TXPCTL_CMD_C1_INIT)
+ b43_phy_write(dev, cmd_regs[i],
+ phy_ht->tx_pwr_idx[i]);
+ }
+
+ phy_ht->tx_pwr_ctl = enable;
+}
+
+static void b43_phy_ht_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ static const u16 base[] = { 0x840, 0x860, 0x880 };
+ u16 save_regs[3][3];
+ s32 rssi_buf[6];
+ int core;
+
+ for (core = 0; core < 3; core++) {
+ save_regs[core][1] = b43_phy_read(dev, base[core] + 6);
+ save_regs[core][2] = b43_phy_read(dev, base[core] + 7);
+ save_regs[core][0] = b43_phy_read(dev, base[core] + 0);
+
+ b43_phy_write(dev, base[core] + 6, 0);
+ b43_phy_mask(dev, base[core] + 7, ~0xF); /* 0xF? Or just 0x6? */
+ b43_phy_set(dev, base[core] + 0, 0x0400);
+ b43_phy_set(dev, base[core] + 0, 0x1000);
+ }
+
+ b43_phy_ht_tx_tone(dev);
+ udelay(20);
+ b43_phy_ht_poll_rssi(dev, HT_RSSI_TSSI_2G, rssi_buf, 1);
+ b43_phy_ht_stop_playback(dev);
+ b43_phy_ht_reset_cca(dev);
+
+ phy_ht->idle_tssi[0] = rssi_buf[0] & 0xff;
+ phy_ht->idle_tssi[1] = rssi_buf[2] & 0xff;
+ phy_ht->idle_tssi[2] = rssi_buf[4] & 0xff;
+
+ for (core = 0; core < 3; core++) {
+ b43_phy_write(dev, base[core] + 0, save_regs[core][0]);
+ b43_phy_write(dev, base[core] + 6, save_regs[core][1]);
+ b43_phy_write(dev, base[core] + 7, save_regs[core][2]);
+ }
+}
+
+static void b43_phy_ht_tssi_setup(struct b43_wldev *dev)
+{
+ static const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3, };
+ int core;
+
+ /* 0x159 is probably TX_SSI_MUX or TSSIG (by comparing to N-PHY) */
+ for (core = 0; core < 3; core++) {
+ b43_radio_set(dev, 0x8bf, 0x1);
+ b43_radio_write(dev, routing[core] | 0x0159, 0x0011);
+ }
+}
+
+static void b43_phy_ht_tx_power_ctl_setup(struct b43_wldev *dev)
+{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+
+ u8 *idle = phy_ht->idle_tssi;
+ u8 target[3];
+ s16 a1[3], b0[3], b1[3];
+
+ u16 freq = dev->phy.channel_freq;
+ int i, c;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_2g;
+ a1[c] = sprom->core_pwr_info[c].pa_2g[0];
+ b0[c] = sprom->core_pwr_info[c].pa_2g[1];
+ b1[c] = sprom->core_pwr_info[c].pa_2g[2];
+ }
+ } else if (freq >= 4900 && freq < 5100) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5gl;
+ a1[c] = sprom->core_pwr_info[c].pa_5gl[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5gl[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5gl[2];
+ }
+ } else if (freq >= 5100 && freq < 5500) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5g;
+ a1[c] = sprom->core_pwr_info[c].pa_5g[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5g[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5g[2];
+ }
+ } else if (freq >= 5500) {
+ for (c = 0; c < 3; c++) {
+ target[c] = sprom->core_pwr_info[c].maxpwr_5gh;
+ a1[c] = sprom->core_pwr_info[c].pa_5gh[0];
+ b0[c] = sprom->core_pwr_info[c].pa_5gh[1];
+ b1[c] = sprom->core_pwr_info[c].pa_5gh[2];
+ }
+ } else {
+ target[0] = target[1] = target[2] = 52;
+ a1[0] = a1[1] = a1[2] = -424;
+ b0[0] = b0[1] = b0[2] = 5612;
+ b1[0] = b1[1] = b1[2] = -1393;
+ }
+
+ b43_phy_set(dev, B43_PHY_HT_TSSIMODE, B43_PHY_HT_TSSIMODE_EN);
+ b43_phy_mask(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+ ~B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN & 0xFFFF);
+
+ /* TODO: Does it depend on sprom->fem.ghz2.tssipos? */
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI, 0x4000);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1,
+ ~B43_PHY_HT_TXPCTL_CMD_C1_INIT, 0x19);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C2,
+ ~B43_PHY_HT_TXPCTL_CMD_C2_INIT, 0x19);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C3,
+ ~B43_PHY_HT_TXPCTL_CMD_C3_INIT, 0x19);
+
+ b43_phy_set(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C1,
+ idle[0] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI_C2,
+ idle[1] << B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_IDLE_TSSI2,
+ ~B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3,
+ idle[2] << B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT);
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_TSSID,
+ 0xf0);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_N, ~B43_PHY_HT_TXPCTL_N_NPTIL2,
+ 0x3 << B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT);
+#if 0
+ /* TODO: what to mask/set? */
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x800, 0)
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_CMD_C1, 0x400, 0)
+#endif
+
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR_C1,
+ target[0] << B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR_C2 & 0xFFFF,
+ target[1] << B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT);
+ b43_phy_maskset(dev, B43_PHY_HT_TXPCTL_TARG_PWR2,
+ ~B43_PHY_HT_TXPCTL_TARG_PWR2_C3,
+ target[2] << B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT);
+
+ for (c = 0; c < 3; c++) {
+ s32 num, den, pwr;
+ u32 regval[64];
+
+ for (i = 0; i < 64; i++) {
+ num = 8 * (16 * b0[c] + b1[c] * i);
+ den = 32768 + a1[c] * i;
+ pwr = max((4 * num + den / 2) / den, -8);
+ regval[i] = pwr;
+ }
+ b43_httab_write_bulk(dev, B43_HTTAB16(26 + c, 0), 64, regval);
+ }
+}
+
+/**************************************************
* Channel switching ops.
**************************************************/
+static void b43_phy_ht_spur_avoid(struct b43_wldev *dev,
+ struct ieee80211_channel *new_channel)
+{
+ struct bcma_device *core = dev->dev->bdev;
+ int spuravoid = 0;
+ u16 tmp;
+
+ /* Check for 13 and 14 is just a guess, we don't have enough logs. */
+ if (new_channel->hw_value == 13 || new_channel->hw_value == 14)
+ spuravoid = 1;
+ bcma_core_pll_ctl(core, B43_BCMA_CLKCTLST_PHY_PLL_REQ, 0, false);
+ bcma_pmu_spuravoid_pllupdate(&core->bus->drv_cc, spuravoid);
+ bcma_core_pll_ctl(core,
+ B43_BCMA_CLKCTLST_80211_PLL_REQ |
+ B43_BCMA_CLKCTLST_PHY_PLL_REQ,
+ B43_BCMA_CLKCTLST_80211_PLL_ST |
+ B43_BCMA_CLKCTLST_PHY_PLL_ST, false);
+
+ /* Values has been taken from wlc_bmac_switch_macfreq comments */
+ switch (spuravoid) {
+ case 2: /* 126MHz */
+ tmp = 0x2082;
+ break;
+ case 1: /* 123MHz */
+ tmp = 0x5341;
+ break;
+ default: /* 120MHz */
+ tmp = 0x8889;
+ }
+
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, tmp);
+ b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+
+ /* TODO: reset PLL */
+
+ if (spuravoid)
+ b43_phy_set(dev, B43_PHY_HT_BBCFG, B43_PHY_HT_BBCFG_RSTRX);
+ else
+ b43_phy_mask(dev, B43_PHY_HT_BBCFG,
+ ~B43_PHY_HT_BBCFG_RSTRX & 0xFFFF);
+
+ b43_phy_ht_reset_cca(dev);
+}
+
static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_phy *e,
struct ieee80211_channel *new_channel)
{
bool old_band_5ghz;
- u8 i;
old_band_5ghz = b43_phy_read(dev, B43_PHY_HT_BANDCTL) & 0; /* FIXME */
if (new_channel->band == IEEE80211_BAND_5GHZ && !old_band_5ghz) {
@@ -264,25 +763,20 @@ static void b43_phy_ht_channel_setup(struct b43_wldev *dev,
b43_phy_write(dev, B43_PHY_HT_BW5, e->bw5);
b43_phy_write(dev, B43_PHY_HT_BW6, e->bw6);
- /* TODO: some ops on PHY regs 0x0B0 and 0xC0A */
-
- /* TODO: separated function? */
- for (i = 0; i < 3; i++) {
- u16 mask;
- u32 tmp = b43_httab_read(dev, B43_HTTAB32(26, 0xE8));
+ if (new_channel->hw_value == 14) {
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN, 0);
+ b43_phy_set(dev, B43_PHY_HT_TEST, 0x0800);
+ } else {
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_OFDM_EN,
+ B43_PHY_HT_CLASS_CTL_OFDM_EN);
+ if (new_channel->band == IEEE80211_BAND_2GHZ)
+ b43_phy_mask(dev, B43_PHY_HT_TEST, ~0x840);
+ }
- if (0) /* FIXME */
- mask = 0x2 << (i * 4);
- else
- mask = 0;
- b43_phy_mask(dev, B43_PHY_EXTG(0x108), mask);
+ if (1) /* TODO: On N it's for early devices only, what about HT? */
+ b43_phy_ht_tx_power_fix(dev);
- b43_httab_write(dev, B43_HTTAB16(7, 0x110 + i), tmp >> 16);
- b43_httab_write(dev, B43_HTTAB8(13, 0x63 + (i * 4)),
- tmp & 0xFF);
- b43_httab_write(dev, B43_HTTAB8(13, 0x73 + (i * 4)),
- tmp & 0xFF);
- }
+ b43_phy_ht_spur_avoid(dev, new_channel);
b43_phy_write(dev, 0x017e, 0x3830);
}
@@ -337,14 +831,29 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_ht *phy_ht = phy->ht;
+ int i;
memset(phy_ht, 0, sizeof(*phy_ht));
+
+ phy_ht->tx_pwr_ctl = true;
+ for (i = 0; i < 3; i++)
+ phy_ht->tx_pwr_idx[i] = B43_PHY_HT_TXPCTL_CMD_C1_INIT + 1;
+
+ for (i = 0; i < 3; i++)
+ phy_ht->bb_mult_save[i] = -1;
}
static int b43_phy_ht_op_init(struct b43_wldev *dev)
{
+ struct b43_phy_ht *phy_ht = dev->phy.ht;
u16 tmp;
u16 clip_state[3];
+ bool saved_tx_pwr_ctl;
+
+ if (dev->dev->bus_type != B43_BUS_BCMA) {
+ b43err(dev->wl, "HT-PHY is supported only on BCMA bus!\n");
+ return -EOPNOTSUPP;
+ }
b43_phy_ht_tables_init(dev);
@@ -357,9 +866,9 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0);
b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20);
b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20);
@@ -371,8 +880,11 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
if (0) /* TODO: condition */
; /* TODO: PHY op on reg 0x217 */
- b43_phy_read(dev, 0xb0); /* TODO: what for? */
- b43_phy_set(dev, 0xb0, 0x1);
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN, 0);
+ else
+ b43_phy_ht_classifier(dev, B43_PHY_HT_CLASS_CTL_CCK_EN,
+ B43_PHY_HT_CLASS_CTL_CCK_EN);
b43_phy_set(dev, 0xb1, 0x91);
b43_phy_write(dev, 0x32f, 0x0003);
@@ -448,12 +960,13 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_mac_phy_clock_set(dev, true);
+ b43_phy_ht_pa_override(dev, false);
b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX);
b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX);
-
- /* TODO: PHY op on reg 0xb0 */
+ b43_phy_ht_pa_override(dev, true);
/* TODO: Should we restore it? Or store it in global PHY info? */
+ b43_phy_ht_classifier(dev, 0, 0);
b43_phy_ht_read_clip_detection(dev, clip_state);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -462,6 +975,14 @@ static int b43_phy_ht_op_init(struct b43_wldev *dev)
b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0),
B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late);
+ saved_tx_pwr_ctl = phy_ht->tx_pwr_ctl;
+ b43_phy_ht_tx_power_fix(dev);
+ b43_phy_ht_tx_power_ctl(dev, false);
+ b43_phy_ht_tx_power_ctl_idle_tssi(dev);
+ b43_phy_ht_tx_power_ctl_setup(dev);
+ b43_phy_ht_tssi_setup(dev);
+ b43_phy_ht_tx_power_ctl(dev, saved_tx_pwr_ctl);
+
return 0;
}
@@ -506,27 +1027,28 @@ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev,
static void b43_phy_ht_op_switch_analog(struct b43_wldev *dev, bool on)
{
if (on) {
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x0000);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x0000);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00cd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x0000);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00cd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x0000);
} else {
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL2, 0x00fd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL4, 0x00fd);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0x07ff);
- b43_phy_write(dev, B43_PHY_HT_AFE_CTL6, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C1, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C2, 0x00fd);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3_OVER, 0x07ff);
+ b43_phy_write(dev, B43_PHY_HT_AFE_C3, 0x00fd);
}
}
static int b43_phy_ht_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
- struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
- enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
+ struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h
index 6544c4293b34..6cae370d1018 100644
--- a/drivers/net/wireless/b43/phy_ht.h
+++ b/drivers/net/wireless/b43/phy_ht.h
@@ -12,18 +12,65 @@
#define B43_PHY_HT_TABLE_ADDR 0x072 /* Table address */
#define B43_PHY_HT_TABLE_DATALO 0x073 /* Table data low */
#define B43_PHY_HT_TABLE_DATAHI 0x074 /* Table data high */
+#define B43_PHY_HT_CLASS_CTL 0x0B0 /* Classifier control */
+#define B43_PHY_HT_CLASS_CTL_CCK_EN 0x0001 /* CCK enable */
+#define B43_PHY_HT_CLASS_CTL_OFDM_EN 0x0002 /* OFDM enable */
+#define B43_PHY_HT_CLASS_CTL_WAITED_EN 0x0004 /* Waited enable */
+#define B43_PHY_HT_IQLOCAL_CMDGCTL 0x0C2 /* I/Q LO cal command G control */
+#define B43_PHY_HT_SAMP_CMD 0x0C3 /* Sample command */
+#define B43_PHY_HT_SAMP_CMD_STOP 0x0002 /* Stop */
+#define B43_PHY_HT_SAMP_LOOP_CNT 0x0C4 /* Sample loop count */
+#define B43_PHY_HT_SAMP_WAIT_CNT 0x0C5 /* Sample wait count */
+#define B43_PHY_HT_SAMP_DEP_CNT 0x0C6 /* Sample depth count */
+#define B43_PHY_HT_SAMP_STAT 0x0C7 /* Sample status */
+#define B43_PHY_HT_EST_PWR_C1 0x118
+#define B43_PHY_HT_EST_PWR_C2 0x119
+#define B43_PHY_HT_EST_PWR_C3 0x11A
+#define B43_PHY_HT_TSSIMODE 0x122 /* TSSI mode */
+#define B43_PHY_HT_TSSIMODE_EN 0x0001 /* TSSI enable */
+#define B43_PHY_HT_TSSIMODE_PDEN 0x0002 /* Power det enable */
#define B43_PHY_HT_BW1 0x1CE
#define B43_PHY_HT_BW2 0x1CF
#define B43_PHY_HT_BW3 0x1D0
#define B43_PHY_HT_BW4 0x1D1
#define B43_PHY_HT_BW5 0x1D2
#define B43_PHY_HT_BW6 0x1D3
+#define B43_PHY_HT_TXPCTL_CMD_C1 0x1E7 /* TX power control command */
+#define B43_PHY_HT_TXPCTL_CMD_C1_INIT 0x007F /* Init */
+#define B43_PHY_HT_TXPCTL_CMD_C1_COEFF 0x2000 /* Power control coefficients */
+#define B43_PHY_HT_TXPCTL_CMD_C1_HWPCTLEN 0x4000 /* Hardware TX power control enable */
+#define B43_PHY_HT_TXPCTL_CMD_C1_PCTLEN 0x8000 /* TX power control enable */
+#define B43_PHY_HT_TXPCTL_N 0x1E8 /* TX power control N num */
+#define B43_PHY_HT_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */
+#define B43_PHY_HT_TXPCTL_N_TSSID_SHIFT 0
+#define B43_PHY_HT_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */
+#define B43_PHY_HT_TXPCTL_N_NPTIL2_SHIFT 8
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI 0x1E9 /* TX power control idle TSSI */
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C1 0x003F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C1_SHIFT 0
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C2 0x3F00
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_C2_SHIFT 8
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI_BINF 0x8000 /* Raw TSSI offset bin format */
+#define B43_PHY_HT_TXPCTL_TARG_PWR 0x1EA /* TX power control target power */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C1 0x00FF /* Power 0 */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C1_SHIFT 0
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C2 0xFF00 /* Power 1 */
+#define B43_PHY_HT_TXPCTL_TARG_PWR_C2_SHIFT 8
+#define B43_PHY_HT_TX_PCTL_STATUS_C1 0x1ED
+#define B43_PHY_HT_TX_PCTL_STATUS_C2 0x1EE
+#define B43_PHY_HT_TXPCTL_CMD_C2 0x222
+#define B43_PHY_HT_TXPCTL_CMD_C2_INIT 0x007F
+#define B43_PHY_HT_RSSI_C1 0x219
+#define B43_PHY_HT_RSSI_C2 0x21A
+#define B43_PHY_HT_RSSI_C3 0x21B
#define B43_PHY_HT_C1_CLIP1THRES B43_PHY_OFDM(0x00E)
#define B43_PHY_HT_C2_CLIP1THRES B43_PHY_OFDM(0x04E)
#define B43_PHY_HT_C3_CLIP1THRES B43_PHY_OFDM(0x08E)
#define B43_PHY_HT_RF_SEQ_MODE B43_PHY_EXTG(0x000)
+#define B43_PHY_HT_RF_SEQ_MODE_CA_OVER 0x0001 /* Core active override */
+#define B43_PHY_HT_RF_SEQ_MODE_TR_OVER 0x0002 /* Trigger override */
#define B43_PHY_HT_RF_SEQ_TRIG B43_PHY_EXTG(0x003)
#define B43_PHY_HT_RF_SEQ_TRIG_RX2TX 0x0001 /* RX2TX */
#define B43_PHY_HT_RF_SEQ_TRIG_TX2RX 0x0002 /* TX2RX */
@@ -36,12 +83,28 @@
#define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010)
-#define B43_PHY_HT_AFE_CTL1 B43_PHY_EXTG(0x110)
-#define B43_PHY_HT_AFE_CTL2 B43_PHY_EXTG(0x111)
-#define B43_PHY_HT_AFE_CTL3 B43_PHY_EXTG(0x114)
-#define B43_PHY_HT_AFE_CTL4 B43_PHY_EXTG(0x115)
-#define B43_PHY_HT_AFE_CTL5 B43_PHY_EXTG(0x118)
-#define B43_PHY_HT_AFE_CTL6 B43_PHY_EXTG(0x119)
+#define B43_PHY_HT_RF_CTL_INT_C1 B43_PHY_EXTG(0x04c)
+#define B43_PHY_HT_RF_CTL_INT_C2 B43_PHY_EXTG(0x06c)
+#define B43_PHY_HT_RF_CTL_INT_C3 B43_PHY_EXTG(0x08c)
+
+#define B43_PHY_HT_AFE_C1_OVER B43_PHY_EXTG(0x110)
+#define B43_PHY_HT_AFE_C1 B43_PHY_EXTG(0x111)
+#define B43_PHY_HT_AFE_C2_OVER B43_PHY_EXTG(0x114)
+#define B43_PHY_HT_AFE_C2 B43_PHY_EXTG(0x115)
+#define B43_PHY_HT_AFE_C3_OVER B43_PHY_EXTG(0x118)
+#define B43_PHY_HT_AFE_C3 B43_PHY_EXTG(0x119)
+
+#define B43_PHY_HT_TXPCTL_CMD_C3 B43_PHY_EXTG(0x164)
+#define B43_PHY_HT_TXPCTL_CMD_C3_INIT 0x007F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2 B43_PHY_EXTG(0x165) /* TX power control idle TSSI */
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3 0x003F
+#define B43_PHY_HT_TXPCTL_IDLE_TSSI2_C3_SHIFT 0
+#define B43_PHY_HT_TXPCTL_TARG_PWR2 B43_PHY_EXTG(0x166) /* TX power control target power */
+#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3 0x00FF
+#define B43_PHY_HT_TXPCTL_TARG_PWR2_C3_SHIFT 0
+#define B43_PHY_HT_TX_PCTL_STATUS_C3 B43_PHY_EXTG(0x169)
+
+#define B43_PHY_HT_TEST B43_PHY_N_BMODE(0x00A)
/* Values for PHY registers used on channel switching */
@@ -56,6 +119,14 @@ struct b43_phy_ht_channeltab_e_phy {
struct b43_phy_ht {
+ u16 rf_ctl_int_save[3];
+
+ bool tx_pwr_ctl;
+ u8 tx_pwr_idx[3];
+
+ s32 bb_mult_save[3];
+
+ u8 idle_tssi[3];
};
diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c
index a13e28ef6246..0bafa3b17035 100644
--- a/drivers/net/wireless/b43/phy_lcn.c
+++ b/drivers/net/wireless/b43/phy_lcn.c
@@ -808,8 +808,9 @@ static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
- struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
- enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
+ struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index 3ae28561f7a4..92190dacf689 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -104,14 +104,8 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
maxpwr = sprom->maxpwr_bg;
lpphy->max_tx_pwr_med_band = maxpwr;
cckpo = sprom->cck2gpo;
- /*
- * We don't read SPROM's opo as specs say. On rev8 SPROMs
- * opo == ofdm2gpo and we don't know any SSB with LP-PHY
- * and SPROM rev below 8.
- */
- B43_WARN_ON(sprom->revision < 8);
- ofdmpo = sprom->ofdm2gpo;
if (cckpo) {
+ ofdmpo = sprom->ofdm2gpo;
for (i = 0; i < 4; i++) {
lpphy->tx_max_rate[i] =
maxpwr - (ofdmpo & 0xF) * 2;
@@ -124,11 +118,11 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
ofdmpo >>= 4;
}
} else {
- ofdmpo &= 0xFF;
+ u8 opo = sprom->opo;
for (i = 0; i < 4; i++)
lpphy->tx_max_rate[i] = maxpwr;
for (i = 4; i < 15; i++)
- lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
+ lpphy->tx_max_rate[i] = maxpwr - opo;
}
} else { /* 5GHz */
lpphy->tx_isolation_low_band = sprom->tri5gl;
@@ -287,8 +281,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
} else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
- (dev->dev->board_type == 0x048A) || ((dev->phy.rev == 0) &&
- (sprom->boardflags_lo & B43_BFL_FEM))) {
+ (dev->dev->board_type == SSB_BOARD_BU4312) ||
+ (dev->phy.rev == 0 && (sprom->boardflags_lo & B43_BFL_FEM))) {
b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 3c35382ee6c2..7c970d3ae358 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -69,14 +69,27 @@ enum b43_nphy_rf_sequence {
B43_RFSEQ_UPDATE_GAINU,
};
-enum b43_nphy_rssi_type {
- B43_NPHY_RSSI_X = 0,
- B43_NPHY_RSSI_Y,
- B43_NPHY_RSSI_Z,
- B43_NPHY_RSSI_PWRDET,
- B43_NPHY_RSSI_TSSI_I,
- B43_NPHY_RSSI_TSSI_Q,
- B43_NPHY_RSSI_TBD,
+enum n_intc_override {
+ N_INTC_OVERRIDE_OFF = 0,
+ N_INTC_OVERRIDE_TRSW = 1,
+ N_INTC_OVERRIDE_PA = 2,
+ N_INTC_OVERRIDE_EXT_LNA_PU = 3,
+ N_INTC_OVERRIDE_EXT_LNA_GAIN = 4,
+};
+
+enum n_rssi_type {
+ N_RSSI_W1 = 0,
+ N_RSSI_W2,
+ N_RSSI_NB,
+ N_RSSI_IQ,
+ N_RSSI_TSSI_2G,
+ N_RSSI_TSSI_5G,
+ N_RSSI_TBD,
+};
+
+enum n_rail_type {
+ N_RAIL_I = 0,
+ N_RAIL_Q = 1,
};
static inline bool b43_nphy_ipa(struct b43_wldev *dev)
@@ -94,7 +107,7 @@ static u8 b43_nphy_get_rx_core_state(struct b43_wldev *dev)
}
/**************************************************
- * RF (just without b43_nphy_rf_control_intc_override)
+ * RF (just without b43_nphy_rf_ctl_intc_override)
**************************************************/
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
@@ -128,9 +141,9 @@ ok:
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
-static void b43_nphy_rf_control_override_rev7(struct b43_wldev *dev, u16 field,
- u16 value, u8 core, bool off,
- u8 override)
+static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off,
+ u8 override)
{
const struct nphy_rf_control_override_rev7 *e;
u16 en_addrs[3][2] = {
@@ -168,8 +181,8 @@ static void b43_nphy_rf_control_override_rev7(struct b43_wldev *dev, u16 field,
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
-static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
- u16 value, u8 core, bool off)
+static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field,
+ u16 value, u8 core, bool off)
{
int i;
u8 index = fls(field);
@@ -244,14 +257,14 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
-static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
- u16 value, u8 core)
+static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev,
+ enum n_intc_override intc_override,
+ u16 value, u8 core)
{
u8 i, j;
u16 reg, tmp, val;
B43_WARN_ON(dev->phy.rev < 3);
- B43_WARN_ON(field > 4);
for (i = 0; i < 2; i++) {
if ((core == 1 && i == 1) || (core == 2 && !i))
@@ -261,12 +274,12 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
b43_phy_set(dev, reg, 0x400);
- switch (field) {
- case 0:
+ switch (intc_override) {
+ case N_INTC_OVERRIDE_OFF:
b43_phy_write(dev, reg, 0);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
break;
- case 1:
+ case N_INTC_OVERRIDE_TRSW:
if (!i) {
b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1,
0xFC3F, (value << 6));
@@ -307,7 +320,7 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
0xFFFE);
}
break;
- case 2:
+ case N_INTC_OVERRIDE_PA:
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
tmp = 0x0020;
val = value << 5;
@@ -317,7 +330,7 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
}
b43_phy_maskset(dev, reg, ~tmp, val);
break;
- case 3:
+ case N_INTC_OVERRIDE_EXT_LNA_PU:
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
tmp = 0x0001;
val = value;
@@ -327,7 +340,7 @@ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
}
b43_phy_maskset(dev, reg, ~tmp, val);
break;
- case 4:
+ case N_INTC_OVERRIDE_EXT_LNA_GAIN:
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
tmp = 0x0002;
val = value << 1;
@@ -1011,7 +1024,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
if (sprom->revision < 4)
workaround = (dev->dev->board_vendor != PCI_VENDOR_ID_BROADCOM
- && dev->dev->board_type == 0x46D
+ && dev->dev->board_type == SSB_BOARD_CB2_4321
&& dev->dev->board_rev >= 0x41);
else
workaround =
@@ -1207,8 +1220,9 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
- s8 offset, u8 core, u8 rail,
- enum b43_nphy_rssi_type type)
+ s8 offset, u8 core,
+ enum n_rail_type rail,
+ enum n_rssi_type rssi_type)
{
u16 tmp;
bool core1or5 = (core == 1) || (core == 5);
@@ -1217,63 +1231,74 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
offset = clamp_val(offset, -32, 31);
tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
- if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
- if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
- if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
- if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
-
- if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
- if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
- if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
- if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
-
- if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
- if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
- if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
- if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
-
- if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
- if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
- if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
- if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
-
- if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
- if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
- if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
- if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
-
- if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
- if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
-
- if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
- b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
- if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
- b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
+ switch (rssi_type) {
+ case N_RSSI_NB:
+ if (core1or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
+ if (core1or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
+ if (core2or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
+ if (core2or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
+ break;
+ case N_RSSI_W1:
+ if (core1or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
+ if (core1or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
+ if (core2or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
+ if (core2or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
+ break;
+ case N_RSSI_W2:
+ if (core1or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
+ if (core1or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
+ if (core2or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
+ if (core2or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
+ break;
+ case N_RSSI_TBD:
+ if (core1or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
+ if (core1or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
+ if (core2or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
+ if (core2or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
+ break;
+ case N_RSSI_IQ:
+ if (core1or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
+ if (core1or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
+ if (core2or5 && rail == N_RAIL_I)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
+ if (core2or5 && rail == N_RAIL_Q)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
+ break;
+ case N_RSSI_TSSI_2G:
+ if (core1or5)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
+ if (core2or5)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
+ break;
+ case N_RSSI_TSSI_5G:
+ if (core1or5)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
+ if (core2or5)
+ b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
+ break;
+ }
}
-static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code,
+ enum n_rssi_type rssi_type)
{
u8 i;
u16 reg, val;
@@ -1296,7 +1321,9 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
- if (type < 3) {
+ if (rssi_type == N_RSSI_W1 ||
+ rssi_type == N_RSSI_W2 ||
+ rssi_type == N_RSSI_NB) {
reg = (i == 0) ?
B43_NPHY_AFECTL_C1 :
B43_NPHY_AFECTL_C2;
@@ -1307,9 +1334,9 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
B43_NPHY_RFCTL_LUT_TRSW_UP2;
b43_phy_maskset(dev, reg, 0xFFC3, 0);
- if (type == 0)
+ if (rssi_type == N_RSSI_W1)
val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
- else if (type == 1)
+ else if (rssi_type == N_RSSI_W2)
val = 16;
else
val = 32;
@@ -1320,9 +1347,9 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
B43_NPHY_TXF_40CO_B32S1;
b43_phy_set(dev, reg, 0x0020);
} else {
- if (type == 6)
+ if (rssi_type == N_RSSI_TBD)
val = 0x0100;
- else if (type == 3)
+ else if (rssi_type == N_RSSI_IQ)
val = 0x0200;
else
val = 0x0300;
@@ -1334,7 +1361,8 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
b43_phy_maskset(dev, reg, 0xFCFF, val);
b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
- if (type != 3 && type != 6) {
+ if (rssi_type != N_RSSI_IQ &&
+ rssi_type != N_RSSI_TBD) {
enum ieee80211_band band =
b43_current_band(dev->wl);
@@ -1344,7 +1372,7 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
val = 0x11;
reg = (i == 0) ? 0x2000 : 0x3000;
reg |= B2055_PADDRV;
- b43_radio_write16(dev, reg, val);
+ b43_radio_write(dev, reg, val);
reg = (i == 0) ?
B43_NPHY_AFECTL_OVER1 :
@@ -1356,33 +1384,43 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
}
}
-static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code,
+ enum n_rssi_type rssi_type)
{
u16 val;
+ bool rssi_w1_w2_nb = false;
- if (type < 3)
+ switch (rssi_type) {
+ case N_RSSI_W1:
+ case N_RSSI_W2:
+ case N_RSSI_NB:
val = 0;
- else if (type == 6)
+ rssi_w1_w2_nb = true;
+ break;
+ case N_RSSI_TBD:
val = 1;
- else if (type == 3)
+ break;
+ case N_RSSI_IQ:
val = 2;
- else
+ break;
+ default:
val = 3;
+ }
val = (val << 12) | (val << 14);
b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
- if (type < 3) {
+ if (rssi_w1_w2_nb) {
b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
- (type + 1) << 4);
+ (rssi_type + 1) << 4);
b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
- (type + 1) << 4);
+ (rssi_type + 1) << 4);
}
if (code == 0) {
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
- if (type < 3) {
+ if (rssi_w1_w2_nb) {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~(B43_NPHY_RFCTL_CMD_RXEN |
B43_NPHY_RFCTL_CMD_CORESEL));
@@ -1398,7 +1436,7 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
}
} else {
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
- if (type < 3) {
+ if (rssi_w1_w2_nb) {
b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
~(B43_NPHY_RFCTL_CMD_RXEN |
B43_NPHY_RFCTL_CMD_CORESEL),
@@ -1418,7 +1456,8 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
-static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code,
+ enum n_rssi_type type)
{
if (dev->phy.rev >= 3)
b43_nphy_rev3_rssi_select(dev, code, type);
@@ -1427,11 +1466,12 @@ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
-static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
+static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev,
+ enum n_rssi_type rssi_type, u8 *buf)
{
int i;
for (i = 0; i < 2; i++) {
- if (type == 2) {
+ if (rssi_type == N_RSSI_NB) {
if (i == 0) {
b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
0xFC, buf[0]);
@@ -1455,8 +1495,8 @@ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
-static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
- u8 nsamp)
+static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type,
+ s32 *buf, u8 nsamp)
{
int i;
int out;
@@ -1487,7 +1527,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
save_regs_phy[8] = 0;
}
- b43_nphy_rssi_select(dev, 5, type);
+ b43_nphy_rssi_select(dev, 5, rssi_type);
if (dev->phy.rev < 2) {
save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL);
@@ -1564,7 +1604,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
u16 clip_off[2] = { 0xFFFF, 0xFFFF };
u8 vcm_final = 0;
- s8 offset[4];
+ s32 offset[4];
s32 results[8][4] = { };
s32 results_min[4] = { };
s32 poll_results[4] = { };
@@ -1574,7 +1614,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
u16 r; /* routing */
u8 rx_core_state;
- u8 core, i, j;
+ int core, i, j, vcm;
class = b43_nphy_classifier(dev, 0, 0);
b43_nphy_classifier(dev, 7, 4);
@@ -1586,19 +1626,19 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
for (i = 0; i < ARRAY_SIZE(regs_to_store); i++)
saved_regs_phy[i] = b43_phy_read(dev, regs_to_store[i]);
- b43_nphy_rf_control_intc_override(dev, 0, 0, 7);
- b43_nphy_rf_control_intc_override(dev, 1, 1, 7);
- b43_nphy_rf_control_override(dev, 0x1, 0, 0, false);
- b43_nphy_rf_control_override(dev, 0x2, 1, 0, false);
- b43_nphy_rf_control_override(dev, 0x80, 1, 0, false);
- b43_nphy_rf_control_override(dev, 0x40, 1, 0, false);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_OFF, 0, 7);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 1, 7);
+ b43_nphy_rf_ctl_override(dev, 0x1, 0, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x2, 1, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x80, 1, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x40, 1, 0, false);
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
- b43_nphy_rf_control_override(dev, 0x20, 0, 0, false);
- b43_nphy_rf_control_override(dev, 0x10, 1, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x20, 0, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x10, 1, 0, false);
} else {
- b43_nphy_rf_control_override(dev, 0x10, 0, 0, false);
- b43_nphy_rf_control_override(dev, 0x20, 1, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x10, 0, 0, false);
+ b43_nphy_rf_ctl_override(dev, 0x20, 1, 0, false);
}
rx_core_state = b43_nphy_get_rx_core_state(dev);
@@ -1606,35 +1646,44 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
if (!(rx_core_state & (1 << core)))
continue;
r = core ? B2056_RX1 : B2056_RX0;
- b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 0, 2);
- b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 1, 2);
- for (i = 0; i < 8; i++) {
+ b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, N_RAIL_I,
+ N_RSSI_NB);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, N_RAIL_Q,
+ N_RSSI_NB);
+
+ /* Grab RSSI results for every possible VCM */
+ for (vcm = 0; vcm < 8; vcm++) {
b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3,
- i << 2);
- b43_nphy_poll_rssi(dev, 2, results[i], 8);
+ vcm << 2);
+ b43_nphy_poll_rssi(dev, N_RSSI_NB, results[vcm], 8);
}
+
+ /* Find out which VCM got the best results */
for (i = 0; i < 4; i += 2) {
- s32 curr;
- s32 mind = 40;
+ s32 currd;
+ s32 mind = 0x100000;
s32 minpoll = 249;
u8 minvcm = 0;
if (2 * core != i)
continue;
- for (j = 0; j < 8; j++) {
- curr = results[j][i] * results[j][i] +
- results[j][i + 1] * results[j][i];
- if (curr < mind) {
- mind = curr;
- minvcm = j;
+ for (vcm = 0; vcm < 8; vcm++) {
+ currd = results[vcm][i] * results[vcm][i] +
+ results[vcm][i + 1] * results[vcm][i];
+ if (currd < mind) {
+ mind = currd;
+ minvcm = vcm;
}
- if (results[j][i] < minpoll)
- minpoll = results[j][i];
+ if (results[vcm][i] < minpoll)
+ minpoll = results[vcm][i];
}
vcm_final = minvcm;
results_min[i] = minpoll;
}
+
+ /* Select the best VCM */
b43_radio_maskset(dev, r | B2056_RX_RSSI_MISC, 0xE3,
vcm_final << 2);
+
for (i = 0; i < 4; i++) {
if (core != i / 2)
continue;
@@ -1647,16 +1696,19 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
offset[i] = -32;
b43_nphy_scale_offset_rssi(dev, 0, offset[i],
(i / 2 == 0) ? 1 : 2,
- (i % 2 == 0) ? 0 : 1,
- 2);
+ (i % 2 == 0) ? N_RAIL_I : N_RAIL_Q,
+ N_RSSI_NB);
}
}
+
for (core = 0; core < 2; core++) {
if (!(rx_core_state & (1 << core)))
continue;
for (i = 0; i < 2; i++) {
- b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 0, i);
- b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 1, i);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1,
+ N_RAIL_I, i);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1,
+ N_RAIL_Q, i);
b43_nphy_poll_rssi(dev, i, poll_results, 8);
for (j = 0; j < 4; j++) {
if (j / 2 == core) {
@@ -1696,8 +1748,13 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
rssical_radio_regs = nphy->rssical_cache.rssical_radio_regs_5G;
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
}
- rssical_radio_regs[0] = b43_radio_read(dev, 0x602B);
- rssical_radio_regs[0] = b43_radio_read(dev, 0x702B);
+ if (dev->phy.rev >= 7) {
+ } else {
+ rssical_radio_regs[0] = b43_radio_read(dev, B2056_RX0 |
+ B2056_RX_RSSI_MISC);
+ rssical_radio_regs[1] = b43_radio_read(dev, B2056_RX1 |
+ B2056_RX_RSSI_MISC);
+ }
rssical_phy_regs[0] = b43_phy_read(dev, B43_NPHY_RSSIMC_0I_RSSI_Z);
rssical_phy_regs[1] = b43_phy_read(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z);
rssical_phy_regs[2] = b43_phy_read(dev, B43_NPHY_RSSIMC_1I_RSSI_Z);
@@ -1723,16 +1780,16 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
-static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
+static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type)
{
- int i, j;
+ int i, j, vcm;
u8 state[4];
u8 code, val;
u16 class, override;
u8 regs_save_radio[2];
u16 regs_save_phy[2];
- s8 offset[4];
+ s32 offset[4];
u8 core;
u8 rail;
@@ -1743,10 +1800,10 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
s32 results[4][4] = { };
s32 miniq[4][2] = { };
- if (type == 2) {
+ if (type == N_RSSI_NB) {
code = 0;
val = 6;
- } else if (type < 2) {
+ } else if (type == N_RSSI_W1 || type == N_RSSI_W2) {
code = 25;
val = 4;
} else {
@@ -1765,63 +1822,63 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
override = 0x110;
regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
- regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
+ regs_save_radio[0] = b43_radio_read(dev, B2055_C1_PD_RXTX);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
- b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+ b43_radio_write(dev, B2055_C1_PD_RXTX, val);
regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
- regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
+ regs_save_radio[1] = b43_radio_read(dev, B2055_C2_PD_RXTX);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
- b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+ b43_radio_write(dev, B2055_C2_PD_RXTX, val);
- state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
- state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
+ state[0] = b43_radio_read(dev, B2055_C1_PD_RSSIMISC) & 0x07;
+ state[1] = b43_radio_read(dev, B2055_C2_PD_RSSIMISC) & 0x07;
b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8);
b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8);
- state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
- state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+ state[2] = b43_radio_read(dev, B2055_C1_SP_RSSI) & 0x07;
+ state[3] = b43_radio_read(dev, B2055_C2_SP_RSSI) & 0x07;
b43_nphy_rssi_select(dev, 5, type);
- b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
- b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, 5, N_RAIL_I, type);
+ b43_nphy_scale_offset_rssi(dev, 0, 0, 5, N_RAIL_Q, type);
- for (i = 0; i < 4; i++) {
+ for (vcm = 0; vcm < 4; vcm++) {
u8 tmp[4];
for (j = 0; j < 4; j++)
- tmp[j] = i;
- if (type != 1)
+ tmp[j] = vcm;
+ if (type != N_RSSI_W2)
b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
- b43_nphy_poll_rssi(dev, type, results[i], 8);
- if (type < 2)
+ b43_nphy_poll_rssi(dev, type, results[vcm], 8);
+ if (type == N_RSSI_W1 || type == N_RSSI_W2)
for (j = 0; j < 2; j++)
- miniq[i][j] = min(results[i][2 * j],
- results[i][2 * j + 1]);
+ miniq[vcm][j] = min(results[vcm][2 * j],
+ results[vcm][2 * j + 1]);
}
for (i = 0; i < 4; i++) {
- s32 mind = 40;
+ s32 mind = 0x100000;
u8 minvcm = 0;
s32 minpoll = 249;
- s32 curr;
- for (j = 0; j < 4; j++) {
- if (type == 2)
- curr = abs(results[j][i]);
+ s32 currd;
+ for (vcm = 0; vcm < 4; vcm++) {
+ if (type == N_RSSI_NB)
+ currd = abs(results[vcm][i] - code * 8);
else
- curr = abs(miniq[j][i / 2] - code * 8);
+ currd = abs(miniq[vcm][i / 2] - code * 8);
- if (curr < mind) {
- mind = curr;
- minvcm = j;
+ if (currd < mind) {
+ mind = currd;
+ minvcm = vcm;
}
- if (results[j][i] < minpoll)
- minpoll = results[j][i];
+ if (results[vcm][i] < minpoll)
+ minpoll = results[vcm][i];
}
results_min[i] = minpoll;
vcm_final[i] = minvcm;
}
- if (type != 1)
+ if (type != N_RSSI_W2)
b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
for (i = 0; i < 4; i++) {
@@ -1836,7 +1893,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
offset[i] = code - 32;
core = (i / 2) ? 2 : 1;
- rail = (i % 2) ? 1 : 0;
+ rail = (i % 2) ? N_RAIL_Q : N_RAIL_I;
b43_nphy_scale_offset_rssi(dev, 0, offset[i], core, rail,
type);
@@ -1847,37 +1904,37 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
switch (state[2]) {
case 1:
- b43_nphy_rssi_select(dev, 1, 2);
+ b43_nphy_rssi_select(dev, 1, N_RSSI_NB);
break;
case 4:
- b43_nphy_rssi_select(dev, 1, 0);
+ b43_nphy_rssi_select(dev, 1, N_RSSI_W1);
break;
case 2:
- b43_nphy_rssi_select(dev, 1, 1);
+ b43_nphy_rssi_select(dev, 1, N_RSSI_W2);
break;
default:
- b43_nphy_rssi_select(dev, 1, 1);
+ b43_nphy_rssi_select(dev, 1, N_RSSI_W2);
break;
}
switch (state[3]) {
case 1:
- b43_nphy_rssi_select(dev, 2, 2);
+ b43_nphy_rssi_select(dev, 2, N_RSSI_NB);
break;
case 4:
- b43_nphy_rssi_select(dev, 2, 0);
+ b43_nphy_rssi_select(dev, 2, N_RSSI_W1);
break;
default:
- b43_nphy_rssi_select(dev, 2, 1);
+ b43_nphy_rssi_select(dev, 2, N_RSSI_W2);
break;
}
b43_nphy_rssi_select(dev, 0, type);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
- b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
+ b43_radio_write(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
- b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+ b43_radio_write(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
b43_nphy_classifier(dev, 7, class);
b43_nphy_write_clip_detection(dev, clip_state);
@@ -1895,9 +1952,9 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev)
if (dev->phy.rev >= 3) {
b43_nphy_rev3_rssi_cal(dev);
} else {
- b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Z);
- b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_X);
- b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Y);
+ b43_nphy_rev2_rssi_cal(dev, N_RSSI_NB);
+ b43_nphy_rev2_rssi_cal(dev, N_RSSI_W1);
+ b43_nphy_rev2_rssi_cal(dev, N_RSSI_W2);
}
}
@@ -1930,10 +1987,8 @@ static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_set(dev, B43_NPHY_RXCTL, 0x0040);
/* Set Clip 2 detect */
- b43_phy_set(dev, B43_NPHY_C1_CGAINI,
- B43_NPHY_C1_CGAINI_CL2DETECT);
- b43_phy_set(dev, B43_NPHY_C2_CGAINI,
- B43_NPHY_C2_CGAINI_CL2DETECT);
+ b43_phy_set(dev, B43_NPHY_C1_CGAINI, B43_NPHY_C1_CGAINI_CL2DETECT);
+ b43_phy_set(dev, B43_NPHY_C2_CGAINI, B43_NPHY_C2_CGAINI_CL2DETECT);
b43_radio_write(dev, B2056_RX0 | B2056_RX_BIASPOLE_LNAG1_IDAC,
0x17);
@@ -1967,22 +2022,22 @@ static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
b43_ntab_write_bulk(dev, B43_NTAB8(2, 0x40), 6, lpf_bits);
b43_ntab_write_bulk(dev, B43_NTAB8(3, 0x40), 6, lpf_bits);
- b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
- b43_phy_write(dev, 0x2A7, e->init_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C1_INITGAIN_A, e->init_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C2_INITGAIN_A, e->init_gain);
+
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x106), 2,
e->rfseq_init);
- /* TODO: check defines. Do not match variables names */
- b43_phy_write(dev, B43_NPHY_C1_CLIP1_MEDGAIN, e->cliphi_gain);
- b43_phy_write(dev, 0x2A9, e->cliphi_gain);
- b43_phy_write(dev, B43_NPHY_C1_CLIP2_GAIN, e->clipmd_gain);
- b43_phy_write(dev, 0x2AB, e->clipmd_gain);
- b43_phy_write(dev, B43_NPHY_C2_CLIP1_HIGAIN, e->cliplo_gain);
- b43_phy_write(dev, 0x2AD, e->cliplo_gain);
-
- b43_phy_maskset(dev, 0x27D, 0xFF00, e->crsmin);
- b43_phy_maskset(dev, 0x280, 0xFF00, e->crsminl);
- b43_phy_maskset(dev, 0x283, 0xFF00, e->crsminu);
+ b43_phy_write(dev, B43_NPHY_REV3_C1_CLIP_HIGAIN_A, e->cliphi_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C2_CLIP_HIGAIN_A, e->cliphi_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C1_CLIP_MEDGAIN_A, e->clipmd_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C2_CLIP_MEDGAIN_A, e->clipmd_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C1_CLIP_LOGAIN_A, e->cliplo_gain);
+ b43_phy_write(dev, B43_NPHY_REV3_C2_CLIP_LOGAIN_A, e->cliplo_gain);
+
+ b43_phy_maskset(dev, B43_NPHY_CRSMINPOWER0, 0xFF00, e->crsmin);
+ b43_phy_maskset(dev, B43_NPHY_CRSMINPOWERL0, 0xFF00, e->crsminl);
+ b43_phy_maskset(dev, B43_NPHY_CRSMINPOWERU0, 0xFF00, e->crsminu);
b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, e->nbclip);
b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, e->nbclip);
b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
@@ -2164,8 +2219,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000);
}
if (phy->rev <= 8) {
- b43_phy_write(dev, 0x23F, 0x1B0);
- b43_phy_write(dev, 0x240, 0x1B0);
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x1B0);
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x1B0);
}
if (phy->rev >= 8)
b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72);
@@ -2182,8 +2237,8 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa,
rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa));
- b43_phy_maskset(dev, 0x299, 0x3FFF, 0x4000);
- b43_phy_maskset(dev, 0x29D, 0x3FFF, 0x4000);
+ b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_0, 0x3FFF, 0x4000);
+ b43_phy_maskset(dev, B43_NPHY_EPS_OVERRIDEI_1, 0x3FFF, 0x4000);
lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154);
lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
@@ -2260,11 +2315,11 @@ static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16),
rx2tx_lut_40_11n);
}
- b43_nphy_rf_control_override_rev7(dev, 16, 1, 3, false, 2);
+ b43_nphy_rf_ctl_override_rev7(dev, 16, 1, 3, false, 2);
}
b43_phy_write(dev, 0x32F, 0x3);
if (phy->radio_rev == 4 || phy->radio_rev == 6)
- b43_nphy_rf_control_override_rev7(dev, 4, 1, 3, false, 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 4, 1, 3, false, 0);
if (phy->radio_rev == 3 || phy->radio_rev == 4 || phy->radio_rev == 6) {
if (sprom->revision &&
@@ -2450,8 +2505,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
u16 tmp16;
u32 tmp32;
- b43_phy_write(dev, 0x23f, 0x1f8);
- b43_phy_write(dev, 0x240, 0x1f8);
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT0, 0x1f8);
+ b43_phy_write(dev, B43_NPHY_FORCEFRONT1, 0x1f8);
tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
tmp32 &= 0xffffff;
@@ -2464,8 +2519,8 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00CD);
b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020);
- b43_phy_write(dev, B43_NPHY_C2_CLIP1_MEDGAIN, 0x000C);
- b43_phy_write(dev, 0x2AE, 0x000C);
+ b43_phy_write(dev, B43_NPHY_REV3_C1_CLIP_LOGAIN_B, 0x000C);
+ b43_phy_write(dev, B43_NPHY_REV3_C2_CLIP_LOGAIN_B, 0x000C);
/* TX to RX */
b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays,
@@ -2490,7 +2545,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
0x2 : 0x9C40;
b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, tmp16);
- b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
+ b43_phy_maskset(dev, B43_NPHY_SGILTRNOFFSET, 0xF0FF, 0x0700);
if (!dev->phy.is_40mhz) {
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
@@ -2542,18 +2597,18 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
}
/* Dropped probably-always-true condition */
- b43_phy_write(dev, 0x224, 0x03eb);
- b43_phy_write(dev, 0x225, 0x03eb);
- b43_phy_write(dev, 0x226, 0x0341);
- b43_phy_write(dev, 0x227, 0x0341);
- b43_phy_write(dev, 0x228, 0x042b);
- b43_phy_write(dev, 0x229, 0x042b);
- b43_phy_write(dev, 0x22a, 0x0381);
- b43_phy_write(dev, 0x22b, 0x0381);
- b43_phy_write(dev, 0x22c, 0x042b);
- b43_phy_write(dev, 0x22d, 0x042b);
- b43_phy_write(dev, 0x22e, 0x0381);
- b43_phy_write(dev, 0x22f, 0x0381);
+ b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH0, 0x03eb);
+ b43_phy_write(dev, B43_NPHY_ED_CRS40ASSERTTHRESH1, 0x03eb);
+ b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341);
+ b43_phy_write(dev, B43_NPHY_ED_CRS40DEASSERTTHRESH1, 0x0341);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH0, 0x042b);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20LASSERTTHRESH1, 0x042b);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20LDEASSERTTHRESH0, 0x0381);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20LDEASSERTTHRESH1, 0x0381);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20UASSERTTHRESH0, 0x042b);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20UASSERTTHRESH1, 0x042b);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20UDEASSERTTHRESH0, 0x0381);
+ b43_phy_write(dev, B43_NPHY_ED_CRS20UDEASSERTTHRESH1, 0x0381);
if (dev->phy.rev >= 6 && sprom->boardflags2_lo & B43_BFL2_SINGLEANT_CCK)
; /* TODO: 0x0080000000000000 HF */
@@ -2572,7 +2627,7 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
- dev->dev->board_type == 0x8B) {
+ dev->dev->board_type == BCMA_BOARD_TYPE_BCM943224M93) {
delays1[0] = 0x1;
delays1[5] = 0x14;
}
@@ -2789,10 +2844,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
* Tx and Rx
**************************************************/
-void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
-{//TODO
-}
-
static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
{//TODO
}
@@ -3124,21 +3175,21 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
b43_nphy_ipa_internal_tssi_setup(dev);
if (phy->rev >= 7)
- b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, false, 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, false, 0);
else if (phy->rev >= 3)
- b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
+ b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, false);
b43_nphy_stop_playback(dev);
b43_nphy_tx_tone(dev, 0xFA0, 0, false, false);
udelay(20);
- tmp = b43_nphy_poll_rssi(dev, 4, rssi, 1);
+ tmp = b43_nphy_poll_rssi(dev, N_RSSI_TSSI_2G, rssi, 1);
b43_nphy_stop_playback(dev);
- b43_nphy_rssi_select(dev, 0, 0);
+ b43_nphy_rssi_select(dev, 0, N_RSSI_W1);
if (phy->rev >= 7)
- b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, true, 0);
+ b43_nphy_rf_ctl_override_rev7(dev, 0x2000, 0, 3, true, 0);
else if (phy->rev >= 3)
- b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
+ b43_nphy_rf_ctl_override(dev, 0x2000, 0, 3, true);
if (phy->rev >= 3) {
nphy->pwr_ctl_info[0].idle_tssi_5g = (tmp >> 24) & 0xFF;
@@ -3577,8 +3628,8 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007);
}
- b43_nphy_rf_control_intc_override(dev, 2, 0, 3);
- b43_nphy_rf_control_override(dev, 8, 0, 3, false);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, 0, 3);
+ b43_nphy_rf_ctl_override(dev, 8, 0, 3, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
if (core == 0) {
@@ -3588,8 +3639,10 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
rxval = 4;
txval = 2;
}
- b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1));
- b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core));
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, rxval,
+ core + 1);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, txval,
+ 2 - core);
}
#endif
@@ -3851,9 +3904,13 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
rssical_phy_regs = nphy->rssical_cache.rssical_phy_regs_5G;
}
- /* TODO use some definitions */
- b43_radio_maskset(dev, 0x602B, 0xE3, rssical_radio_regs[0]);
- b43_radio_maskset(dev, 0x702B, 0xE3, rssical_radio_regs[1]);
+ if (dev->phy.rev >= 7) {
+ } else {
+ b43_radio_maskset(dev, B2056_RX0 | B2056_RX_RSSI_MISC, 0xE3,
+ rssical_radio_regs[0]);
+ b43_radio_maskset(dev, B2056_RX1 | B2056_RX_RSSI_MISC, 0xE3,
+ rssical_radio_regs[1]);
+ }
b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, rssical_phy_regs[0]);
b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, rssical_phy_regs[1]);
@@ -3884,75 +3941,75 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
tmp = (i == 0) ? 0x2000 : 0x3000;
offset = i * 11;
- save[offset + 0] = b43_radio_read16(dev, B2055_CAL_RVARCTL);
- save[offset + 1] = b43_radio_read16(dev, B2055_CAL_LPOCTL);
- save[offset + 2] = b43_radio_read16(dev, B2055_CAL_TS);
- save[offset + 3] = b43_radio_read16(dev, B2055_CAL_RCCALRTS);
- save[offset + 4] = b43_radio_read16(dev, B2055_CAL_RCALRTS);
- save[offset + 5] = b43_radio_read16(dev, B2055_PADDRV);
- save[offset + 6] = b43_radio_read16(dev, B2055_XOCTL1);
- save[offset + 7] = b43_radio_read16(dev, B2055_XOCTL2);
- save[offset + 8] = b43_radio_read16(dev, B2055_XOREGUL);
- save[offset + 9] = b43_radio_read16(dev, B2055_XOMISC);
- save[offset + 10] = b43_radio_read16(dev, B2055_PLL_LFC1);
+ save[offset + 0] = b43_radio_read(dev, B2055_CAL_RVARCTL);
+ save[offset + 1] = b43_radio_read(dev, B2055_CAL_LPOCTL);
+ save[offset + 2] = b43_radio_read(dev, B2055_CAL_TS);
+ save[offset + 3] = b43_radio_read(dev, B2055_CAL_RCCALRTS);
+ save[offset + 4] = b43_radio_read(dev, B2055_CAL_RCALRTS);
+ save[offset + 5] = b43_radio_read(dev, B2055_PADDRV);
+ save[offset + 6] = b43_radio_read(dev, B2055_XOCTL1);
+ save[offset + 7] = b43_radio_read(dev, B2055_XOCTL2);
+ save[offset + 8] = b43_radio_read(dev, B2055_XOREGUL);
+ save[offset + 9] = b43_radio_read(dev, B2055_XOMISC);
+ save[offset + 10] = b43_radio_read(dev, B2055_PLL_LFC1);
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
- b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x0A);
- b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
- b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
- b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
- b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
+ b43_radio_write(dev, tmp | B2055_CAL_RVARCTL, 0x0A);
+ b43_radio_write(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+ b43_radio_write(dev, tmp | B2055_CAL_TS, 0x55);
+ b43_radio_write(dev, tmp | B2055_CAL_RCCALRTS, 0);
+ b43_radio_write(dev, tmp | B2055_CAL_RCALRTS, 0);
if (nphy->ipa5g_on) {
- b43_radio_write16(dev, tmp | B2055_PADDRV, 4);
- b43_radio_write16(dev, tmp | B2055_XOCTL1, 1);
+ b43_radio_write(dev, tmp | B2055_PADDRV, 4);
+ b43_radio_write(dev, tmp | B2055_XOCTL1, 1);
} else {
- b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
- b43_radio_write16(dev, tmp | B2055_XOCTL1, 0x2F);
+ b43_radio_write(dev, tmp | B2055_PADDRV, 0);
+ b43_radio_write(dev, tmp | B2055_XOCTL1, 0x2F);
}
- b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+ b43_radio_write(dev, tmp | B2055_XOCTL2, 0);
} else {
- b43_radio_write16(dev, tmp | B2055_CAL_RVARCTL, 0x06);
- b43_radio_write16(dev, tmp | B2055_CAL_LPOCTL, 0x40);
- b43_radio_write16(dev, tmp | B2055_CAL_TS, 0x55);
- b43_radio_write16(dev, tmp | B2055_CAL_RCCALRTS, 0);
- b43_radio_write16(dev, tmp | B2055_CAL_RCALRTS, 0);
- b43_radio_write16(dev, tmp | B2055_XOCTL1, 0);
+ b43_radio_write(dev, tmp | B2055_CAL_RVARCTL, 0x06);
+ b43_radio_write(dev, tmp | B2055_CAL_LPOCTL, 0x40);
+ b43_radio_write(dev, tmp | B2055_CAL_TS, 0x55);
+ b43_radio_write(dev, tmp | B2055_CAL_RCCALRTS, 0);
+ b43_radio_write(dev, tmp | B2055_CAL_RCALRTS, 0);
+ b43_radio_write(dev, tmp | B2055_XOCTL1, 0);
if (nphy->ipa2g_on) {
- b43_radio_write16(dev, tmp | B2055_PADDRV, 6);
- b43_radio_write16(dev, tmp | B2055_XOCTL2,
+ b43_radio_write(dev, tmp | B2055_PADDRV, 6);
+ b43_radio_write(dev, tmp | B2055_XOCTL2,
(dev->phy.rev < 5) ? 0x11 : 0x01);
} else {
- b43_radio_write16(dev, tmp | B2055_PADDRV, 0);
- b43_radio_write16(dev, tmp | B2055_XOCTL2, 0);
+ b43_radio_write(dev, tmp | B2055_PADDRV, 0);
+ b43_radio_write(dev, tmp | B2055_XOCTL2, 0);
}
}
- b43_radio_write16(dev, tmp | B2055_XOREGUL, 0);
- b43_radio_write16(dev, tmp | B2055_XOMISC, 0);
- b43_radio_write16(dev, tmp | B2055_PLL_LFC1, 0);
+ b43_radio_write(dev, tmp | B2055_XOREGUL, 0);
+ b43_radio_write(dev, tmp | B2055_XOMISC, 0);
+ b43_radio_write(dev, tmp | B2055_PLL_LFC1, 0);
}
} else {
- save[0] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL1);
- b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL1, 0x29);
+ save[0] = b43_radio_read(dev, B2055_C1_TX_RF_IQCAL1);
+ b43_radio_write(dev, B2055_C1_TX_RF_IQCAL1, 0x29);
- save[1] = b43_radio_read16(dev, B2055_C1_TX_RF_IQCAL2);
- b43_radio_write16(dev, B2055_C1_TX_RF_IQCAL2, 0x54);
+ save[1] = b43_radio_read(dev, B2055_C1_TX_RF_IQCAL2);
+ b43_radio_write(dev, B2055_C1_TX_RF_IQCAL2, 0x54);
- save[2] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL1);
- b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL1, 0x29);
+ save[2] = b43_radio_read(dev, B2055_C2_TX_RF_IQCAL1);
+ b43_radio_write(dev, B2055_C2_TX_RF_IQCAL1, 0x29);
- save[3] = b43_radio_read16(dev, B2055_C2_TX_RF_IQCAL2);
- b43_radio_write16(dev, B2055_C2_TX_RF_IQCAL2, 0x54);
+ save[3] = b43_radio_read(dev, B2055_C2_TX_RF_IQCAL2);
+ b43_radio_write(dev, B2055_C2_TX_RF_IQCAL2, 0x54);
- save[3] = b43_radio_read16(dev, B2055_C1_PWRDET_RXTX);
- save[4] = b43_radio_read16(dev, B2055_C2_PWRDET_RXTX);
+ save[3] = b43_radio_read(dev, B2055_C1_PWRDET_RXTX);
+ save[4] = b43_radio_read(dev, B2055_C2_PWRDET_RXTX);
if (!(b43_phy_read(dev, B43_NPHY_BANDCTL) &
B43_NPHY_BANDCTL_5GHZ)) {
- b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x04);
- b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x04);
+ b43_radio_write(dev, B2055_C1_PWRDET_RXTX, 0x04);
+ b43_radio_write(dev, B2055_C2_PWRDET_RXTX, 0x04);
} else {
- b43_radio_write16(dev, B2055_C1_PWRDET_RXTX, 0x20);
- b43_radio_write16(dev, B2055_C2_PWRDET_RXTX, 0x20);
+ b43_radio_write(dev, B2055_C1_PWRDET_RXTX, 0x20);
+ b43_radio_write(dev, B2055_C2_PWRDET_RXTX, 0x20);
}
if (dev->phy.rev < 2) {
@@ -4148,9 +4205,9 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev)
regs[7] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
- b43_nphy_rf_control_intc_override(dev, 2, 1, 3);
- b43_nphy_rf_control_intc_override(dev, 1, 2, 1);
- b43_nphy_rf_control_intc_override(dev, 1, 8, 2);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_PA, 1, 3);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 2, 1);
+ b43_nphy_rf_ctl_intc_override(dev, N_INTC_OVERRIDE_TRSW, 8, 2);
regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
@@ -4683,7 +4740,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
tmp[0] = ((cur_hpf2 << 8) | (cur_hpf1 << 4) |
(cur_lna << 2));
- b43_nphy_rf_control_override(dev, 0x400, tmp[0], 3,
+ b43_nphy_rf_ctl_override(dev, 0x400, tmp[0], 3,
false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
b43_nphy_stop_playback(dev);
@@ -4732,7 +4789,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev,
break;
}
- b43_nphy_rf_control_override(dev, 0x400, 0, 3, true);
+ b43_nphy_rf_ctl_override(dev, 0x400, 0, 3, true);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x110), 2, gain_save);
@@ -4801,18 +4858,6 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
* N-PHY init
**************************************************/
-/*
- * Upload the N-PHY tables.
- * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
- */
-static void b43_nphy_tables_init(struct b43_wldev *dev)
-{
- if (dev->phy.rev < 3)
- b43_nphy_rev0_1_2_tables_init(dev);
- else
- b43_nphy_rev3plus_tables_init(dev);
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble)
{
@@ -4892,7 +4937,7 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N */
-int b43_phy_initn(struct b43_wldev *dev)
+static int b43_phy_initn(struct b43_wldev *dev)
{
struct ssb_sprom *sprom = dev->dev->bus_sprom;
struct b43_phy *phy = &dev->phy;
@@ -4962,7 +5007,7 @@ int b43_phy_initn(struct b43_wldev *dev)
if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
(dev->dev->board_vendor == PCI_VENDOR_ID_APPLE &&
- dev->dev->board_type == 0x8B))
+ dev->dev->board_type == BCMA_BOARD_TYPE_BCM943224M93))
b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
else
b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
@@ -5104,68 +5149,17 @@ static void b43_chantab_phy_upload(struct b43_wldev *dev,
/* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */
static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid)
{
- struct bcma_drv_cc __maybe_unused *cc;
- u32 __maybe_unused pmu_ctl;
-
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
case B43_BUS_BCMA:
- cc = &dev->dev->bdev->bus->drv_cc;
- if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) {
- if (avoid) {
- bcma_chipco_pll_write(cc, 0x0, 0x11500010);
- bcma_chipco_pll_write(cc, 0x1, 0x000C0C06);
- bcma_chipco_pll_write(cc, 0x2, 0x0F600a08);
- bcma_chipco_pll_write(cc, 0x3, 0x00000000);
- bcma_chipco_pll_write(cc, 0x4, 0x2001E920);
- bcma_chipco_pll_write(cc, 0x5, 0x88888815);
- } else {
- bcma_chipco_pll_write(cc, 0x0, 0x11100010);
- bcma_chipco_pll_write(cc, 0x1, 0x000c0c06);
- bcma_chipco_pll_write(cc, 0x2, 0x03000a08);
- bcma_chipco_pll_write(cc, 0x3, 0x00000000);
- bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
- bcma_chipco_pll_write(cc, 0x5, 0x88888815);
- }
- pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD;
- } else if (dev->dev->chip_id == 0x4716) {
- if (avoid) {
- bcma_chipco_pll_write(cc, 0x0, 0x11500060);
- bcma_chipco_pll_write(cc, 0x1, 0x080C0C06);
- bcma_chipco_pll_write(cc, 0x2, 0x0F600000);
- bcma_chipco_pll_write(cc, 0x3, 0x00000000);
- bcma_chipco_pll_write(cc, 0x4, 0x2001E924);
- bcma_chipco_pll_write(cc, 0x5, 0x88888815);
- } else {
- bcma_chipco_pll_write(cc, 0x0, 0x11100060);
- bcma_chipco_pll_write(cc, 0x1, 0x080c0c06);
- bcma_chipco_pll_write(cc, 0x2, 0x03000000);
- bcma_chipco_pll_write(cc, 0x3, 0x00000000);
- bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
- bcma_chipco_pll_write(cc, 0x5, 0x88888815);
- }
- pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD |
- BCMA_CC_PMU_CTL_NOILPONW;
- } else if (dev->dev->chip_id == 0x4322 ||
- dev->dev->chip_id == 0x4340 ||
- dev->dev->chip_id == 0x4341) {
- bcma_chipco_pll_write(cc, 0x0, 0x11100070);
- bcma_chipco_pll_write(cc, 0x1, 0x1014140a);
- bcma_chipco_pll_write(cc, 0x5, 0x88888854);
- if (avoid)
- bcma_chipco_pll_write(cc, 0x2, 0x05201828);
- else
- bcma_chipco_pll_write(cc, 0x2, 0x05001828);
- pmu_ctl = BCMA_CC_PMU_CTL_PLL_UPD;
- } else {
- return;
- }
- bcma_cc_set32(cc, BCMA_CC_PMU_CTL, pmu_ctl);
+ bcma_pmu_spuravoid_pllupdate(&dev->dev->bdev->bus->drv_cc,
+ avoid);
break;
#endif
#ifdef CONFIG_B43_SSB
case B43_BUS_SSB:
- /* FIXME */
+ ssb_pmu_spuravoid_pllupdate(&dev->dev->sdev->bus->chipco,
+ avoid);
break;
#endif
}
@@ -5530,8 +5524,9 @@ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
static int b43_nphy_op_switch_channel(struct b43_wldev *dev,
unsigned int new_channel)
{
- struct ieee80211_channel *channel = dev->wl->hw->conf.channel;
- enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type;
+ struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if ((new_channel < 1) || (new_channel > 14))
diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h
index 092c0140c249..9a5b6bc27d24 100644
--- a/drivers/net/wireless/b43/phy_n.h
+++ b/drivers/net/wireless/b43/phy_n.h
@@ -54,10 +54,15 @@
#define B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT 7
#define B43_NPHY_C1_INITGAIN_TRRX 0x1000 /* TR RX index */
#define B43_NPHY_C1_INITGAIN_TRTX 0x2000 /* TR TX index */
+#define B43_NPHY_REV3_C1_INITGAIN_A B43_PHY_N(0x020)
#define B43_NPHY_C1_CLIP1_HIGAIN B43_PHY_N(0x021) /* Core 1 clip1 high gain code */
+#define B43_NPHY_REV3_C1_INITGAIN_B B43_PHY_N(0x021)
#define B43_NPHY_C1_CLIP1_MEDGAIN B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */
+#define B43_NPHY_REV3_C1_CLIP_HIGAIN_A B43_PHY_N(0x022)
#define B43_NPHY_C1_CLIP1_LOGAIN B43_PHY_N(0x023) /* Core 1 clip1 low gain code */
+#define B43_NPHY_REV3_C1_CLIP_HIGAIN_B B43_PHY_N(0x023)
#define B43_NPHY_C1_CLIP2_GAIN B43_PHY_N(0x024) /* Core 1 clip2 gain code */
+#define B43_NPHY_REV3_C1_CLIP_MEDGAIN_A B43_PHY_N(0x024)
#define B43_NPHY_C1_FILTERGAIN B43_PHY_N(0x025) /* Core 1 filter gain */
#define B43_NPHY_C1_LPF_QHPF_BW B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */
#define B43_NPHY_C1_CLIPWBTHRES B43_PHY_N(0x027) /* Core 1 clip wideband threshold */
@@ -107,10 +112,15 @@
#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7
#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */
#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */
+#define B43_NPHY_REV3_C1_CLIP_MEDGAIN_B B43_PHY_N(0x036)
#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */
+#define B43_NPHY_REV3_C1_CLIP_LOGAIN_A B43_PHY_N(0x037)
#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */
+#define B43_NPHY_REV3_C1_CLIP_LOGAIN_B B43_PHY_N(0x038)
#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */
+#define B43_NPHY_REV3_C1_CLIP2_GAIN_A B43_PHY_N(0x039)
#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */
+#define B43_NPHY_REV3_C1_CLIP2_GAIN_B B43_PHY_N(0x03A)
#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */
#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */
#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */
@@ -706,10 +716,146 @@
#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power control init */
#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */
#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0
+#define B43_NPHY_ED_CRSEN B43_PHY_N(0x223)
+#define B43_NPHY_ED_CRS40ASSERTTHRESH0 B43_PHY_N(0x224)
+#define B43_NPHY_ED_CRS40ASSERTTHRESH1 B43_PHY_N(0x225)
+#define B43_NPHY_ED_CRS40DEASSERTTHRESH0 B43_PHY_N(0x226)
+#define B43_NPHY_ED_CRS40DEASSERTTHRESH1 B43_PHY_N(0x227)
+#define B43_NPHY_ED_CRS20LASSERTTHRESH0 B43_PHY_N(0x228)
+#define B43_NPHY_ED_CRS20LASSERTTHRESH1 B43_PHY_N(0x229)
+#define B43_NPHY_ED_CRS20LDEASSERTTHRESH0 B43_PHY_N(0x22A)
+#define B43_NPHY_ED_CRS20LDEASSERTTHRESH1 B43_PHY_N(0x22B)
+#define B43_NPHY_ED_CRS20UASSERTTHRESH0 B43_PHY_N(0x22C)
+#define B43_NPHY_ED_CRS20UASSERTTHRESH1 B43_PHY_N(0x22D)
+#define B43_NPHY_ED_CRS20UDEASSERTTHRESH0 B43_PHY_N(0x22E)
+#define B43_NPHY_ED_CRS20UDEASSERTTHRESH1 B43_PHY_N(0x22F)
+#define B43_NPHY_ED_CRS B43_PHY_N(0x230)
+#define B43_NPHY_TIMEOUTEN B43_PHY_N(0x231)
+#define B43_NPHY_OFDMPAYDECODETIMEOUTLEN B43_PHY_N(0x232)
+#define B43_NPHY_CCKPAYDECODETIMEOUTLEN B43_PHY_N(0x233)
+#define B43_NPHY_NONPAYDECODETIMEOUTLEN B43_PHY_N(0x234)
+#define B43_NPHY_TIMEOUTSTATUS B43_PHY_N(0x235)
+#define B43_NPHY_RFCTRLCORE0GPIO0 B43_PHY_N(0x236)
+#define B43_NPHY_RFCTRLCORE0GPIO1 B43_PHY_N(0x237)
+#define B43_NPHY_RFCTRLCORE0GPIO2 B43_PHY_N(0x238)
+#define B43_NPHY_RFCTRLCORE0GPIO3 B43_PHY_N(0x239)
+#define B43_NPHY_RFCTRLCORE1GPIO0 B43_PHY_N(0x23A)
+#define B43_NPHY_RFCTRLCORE1GPIO1 B43_PHY_N(0x23B)
+#define B43_NPHY_RFCTRLCORE1GPIO2 B43_PHY_N(0x23C)
+#define B43_NPHY_RFCTRLCORE1GPIO3 B43_PHY_N(0x23D)
+#define B43_NPHY_BPHYTESTCONTROL B43_PHY_N(0x23E)
+/* REV3+ */
+#define B43_NPHY_FORCEFRONT0 B43_PHY_N(0x23F)
+#define B43_NPHY_FORCEFRONT1 B43_PHY_N(0x240)
+#define B43_NPHY_NORMVARHYSTTH B43_PHY_N(0x241)
+#define B43_NPHY_TXCCKERROR B43_PHY_N(0x242)
+#define B43_NPHY_AFESEQINITDACGAIN B43_PHY_N(0x243)
+#define B43_NPHY_TXANTSWLUT B43_PHY_N(0x244)
+#define B43_NPHY_CORECONFIG B43_PHY_N(0x245)
+#define B43_NPHY_ANTENNADIVDWELLTIME B43_PHY_N(0x246)
+#define B43_NPHY_ANTENNACCKDIVDWELLTIME B43_PHY_N(0x247)
+#define B43_NPHY_ANTENNADIVBACKOFFGAIN B43_PHY_N(0x248)
+#define B43_NPHY_ANTENNADIVMINGAIN B43_PHY_N(0x249)
+#define B43_NPHY_BRDSEL_NORMVARHYSTTH B43_PHY_N(0x24A)
+#define B43_NPHY_RXANTSWITCHCTRL B43_PHY_N(0x24B)
+#define B43_NPHY_ENERGYDROPTIMEOUTLEN2 B43_PHY_N(0x24C)
+#define B43_NPHY_ML_LOG_TXEVM0 B43_PHY_N(0x250)
+#define B43_NPHY_ML_LOG_TXEVM1 B43_PHY_N(0x251)
+#define B43_NPHY_ML_LOG_TXEVM2 B43_PHY_N(0x252)
+#define B43_NPHY_ML_LOG_TXEVM3 B43_PHY_N(0x253)
+#define B43_NPHY_ML_LOG_TXEVM4 B43_PHY_N(0x254)
+#define B43_NPHY_ML_LOG_TXEVM5 B43_PHY_N(0x255)
+#define B43_NPHY_ML_LOG_TXEVM6 B43_PHY_N(0x256)
+#define B43_NPHY_ML_LOG_TXEVM7 B43_PHY_N(0x257)
+#define B43_NPHY_ML_SCALE_TWEAK B43_PHY_N(0x258)
+#define B43_NPHY_MLUA B43_PHY_N(0x259)
+#define B43_NPHY_ZFUA B43_PHY_N(0x25A)
+#define B43_NPHY_CHANUPSYM01 B43_PHY_N(0x25B)
+#define B43_NPHY_CHANUPSYM2 B43_PHY_N(0x25C)
+#define B43_NPHY_RXSTRNFILT20NUM00 B43_PHY_N(0x25D)
+#define B43_NPHY_RXSTRNFILT20NUM01 B43_PHY_N(0x25E)
+#define B43_NPHY_RXSTRNFILT20NUM02 B43_PHY_N(0x25F)
+#define B43_NPHY_RXSTRNFILT20DEN00 B43_PHY_N(0x260)
+#define B43_NPHY_RXSTRNFILT20DEN01 B43_PHY_N(0x261)
+#define B43_NPHY_RXSTRNFILT20NUM10 B43_PHY_N(0x262)
+#define B43_NPHY_RXSTRNFILT20NUM11 B43_PHY_N(0x263)
+#define B43_NPHY_RXSTRNFILT20NUM12 B43_PHY_N(0x264)
+#define B43_NPHY_RXSTRNFILT20DEN10 B43_PHY_N(0x265)
+#define B43_NPHY_RXSTRNFILT20DEN11 B43_PHY_N(0x266)
+#define B43_NPHY_RXSTRNFILT40NUM00 B43_PHY_N(0x267)
+#define B43_NPHY_RXSTRNFILT40NUM01 B43_PHY_N(0x268)
+#define B43_NPHY_RXSTRNFILT40NUM02 B43_PHY_N(0x269)
+#define B43_NPHY_RXSTRNFILT40DEN00 B43_PHY_N(0x26A)
+#define B43_NPHY_RXSTRNFILT40DEN01 B43_PHY_N(0x26B)
+#define B43_NPHY_RXSTRNFILT40NUM10 B43_PHY_N(0x26C)
+#define B43_NPHY_RXSTRNFILT40NUM11 B43_PHY_N(0x26D)
+#define B43_NPHY_RXSTRNFILT40NUM12 B43_PHY_N(0x26E)
+#define B43_NPHY_RXSTRNFILT40DEN10 B43_PHY_N(0x26F)
+#define B43_NPHY_RXSTRNFILT40DEN11 B43_PHY_N(0x270)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD1 B43_PHY_N(0x271)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD2 B43_PHY_N(0x272)
+#define B43_NPHY_CRSHIGHLOWPOWTHRESHOLD B43_PHY_N(0x273)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD1L B43_PHY_N(0x274)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD2L B43_PHY_N(0x275)
+#define B43_NPHY_CRSHIGHLOWPOWTHRESHOLDL B43_PHY_N(0x276)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD1U B43_PHY_N(0x277)
+#define B43_NPHY_CRSHIGHPOWTHRESHOLD2U B43_PHY_N(0x278)
+#define B43_NPHY_CRSHIGHLOWPOWTHRESHOLDU B43_PHY_N(0x279)
+#define B43_NPHY_CRSACIDETECTTHRESH B43_PHY_N(0x27A)
+#define B43_NPHY_CRSACIDETECTTHRESHL B43_PHY_N(0x27B)
+#define B43_NPHY_CRSACIDETECTTHRESHU B43_PHY_N(0x27C)
+#define B43_NPHY_CRSMINPOWER0 B43_PHY_N(0x27D)
+#define B43_NPHY_CRSMINPOWER1 B43_PHY_N(0x27E)
+#define B43_NPHY_CRSMINPOWER2 B43_PHY_N(0x27F)
+#define B43_NPHY_CRSMINPOWERL0 B43_PHY_N(0x280)
+#define B43_NPHY_CRSMINPOWERL1 B43_PHY_N(0x281)
+#define B43_NPHY_CRSMINPOWERL2 B43_PHY_N(0x282)
+#define B43_NPHY_CRSMINPOWERU0 B43_PHY_N(0x283)
+#define B43_NPHY_CRSMINPOWERU1 B43_PHY_N(0x284)
+#define B43_NPHY_CRSMINPOWERU2 B43_PHY_N(0x285)
+#define B43_NPHY_STRPARAM B43_PHY_N(0x286)
+#define B43_NPHY_STRPARAML B43_PHY_N(0x287)
+#define B43_NPHY_STRPARAMU B43_PHY_N(0x288)
+#define B43_NPHY_BPHYCRSMINPOWER0 B43_PHY_N(0x289)
+#define B43_NPHY_BPHYCRSMINPOWER1 B43_PHY_N(0x28A)
+#define B43_NPHY_BPHYCRSMINPOWER2 B43_PHY_N(0x28B)
+#define B43_NPHY_BPHYFILTDEN0COEF B43_PHY_N(0x28C)
+#define B43_NPHY_BPHYFILTDEN1COEF B43_PHY_N(0x28D)
+#define B43_NPHY_BPHYFILTDEN2COEF B43_PHY_N(0x28E)
+#define B43_NPHY_BPHYFILTNUM0COEF B43_PHY_N(0x28F)
+#define B43_NPHY_BPHYFILTNUM1COEF B43_PHY_N(0x290)
+#define B43_NPHY_BPHYFILTNUM2COEF B43_PHY_N(0x291)
+#define B43_NPHY_BPHYFILTNUM01COEF2 B43_PHY_N(0x292)
+#define B43_NPHY_BPHYFILTBYPASS B43_PHY_N(0x293)
+#define B43_NPHY_SGILTRNOFFSET B43_PHY_N(0x294)
+#define B43_NPHY_RADAR_T2_MIN B43_PHY_N(0x295)
+#define B43_NPHY_TXPWRCTRLDAMPING B43_PHY_N(0x296)
#define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */
#define B43_NPHY_EPS_TABLE_ADJ0 B43_PHY_N(0x298) /* EPS Table Adj0 TBD */
+#define B43_NPHY_EPS_OVERRIDEI_0 B43_PHY_N(0x299)
+#define B43_NPHY_EPS_OVERRIDEQ_0 B43_PHY_N(0x29A)
#define B43_NPHY_PAPD_EN1 B43_PHY_N(0x29B) /* PAPD Enable1 TBD */
#define B43_NPHY_EPS_TABLE_ADJ1 B43_PHY_N(0x29C) /* EPS Table Adj1 TBD */
+#define B43_NPHY_EPS_OVERRIDEI_1 B43_PHY_N(0x29D)
+#define B43_NPHY_EPS_OVERRIDEQ_1 B43_PHY_N(0x29E)
+#define B43_NPHY_PAPD_CAL_ADDRESS B43_PHY_N(0x29F)
+#define B43_NPHY_PAPD_CAL_YREFEPSILON B43_PHY_N(0x2A0)
+#define B43_NPHY_PAPD_CAL_SETTLE B43_PHY_N(0x2A1)
+#define B43_NPHY_PAPD_CAL_CORRELATE B43_PHY_N(0x2A2)
+#define B43_NPHY_PAPD_CAL_SHIFTS0 B43_PHY_N(0x2A3)
+#define B43_NPHY_PAPD_CAL_SHIFTS1 B43_PHY_N(0x2A4)
+#define B43_NPHY_SAMPLE_START_ADDR B43_PHY_N(0x2A5)
+#define B43_NPHY_RADAR_ADC_TO_DBM B43_PHY_N(0x2A6)
+#define B43_NPHY_REV3_C2_INITGAIN_A B43_PHY_N(0x2A7)
+#define B43_NPHY_REV3_C2_INITGAIN_B B43_PHY_N(0x2A8)
+#define B43_NPHY_REV3_C2_CLIP_HIGAIN_A B43_PHY_N(0x2A9)
+#define B43_NPHY_REV3_C2_CLIP_HIGAIN_B B43_PHY_N(0x2AA)
+#define B43_NPHY_REV3_C2_CLIP_MEDGAIN_A B43_PHY_N(0x2AB)
+#define B43_NPHY_REV3_C2_CLIP_MEDGAIN_B B43_PHY_N(0x2AC)
+#define B43_NPHY_REV3_C2_CLIP_LOGAIN_A B43_PHY_N(0x2AD)
+#define B43_NPHY_REV3_C2_CLIP_LOGAIN_B B43_PHY_N(0x2AE)
+#define B43_NPHY_REV3_C2_CLIP2_GAIN_A B43_PHY_N(0x2AF)
+#define B43_NPHY_REV3_C2_CLIP2_GAIN_B B43_PHY_N(0x2B0)
#define B43_PHY_B_BBCFG B43_PHY_N_BMODE(0x001) /* BB config */
#define B43_PHY_B_TEST B43_PHY_N_BMODE(0x00A)
diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c
index ce037fb6789a..b4fd9345d673 100644
--- a/drivers/net/wireless/b43/radio_2056.c
+++ b/drivers/net/wireless/b43/radio_2056.c
@@ -2980,7 +2980,7 @@ static const struct b2056_inittab_entry b2056_inittab_rev8_rx[] = {
.rx = prefix##_rx, \
.rx_length = ARRAY_SIZE(prefix##_rx)
-struct b2056_inittabs_pts b2056_inittabs[] = {
+static const struct b2056_inittabs_pts b2056_inittabs[] = {
[3] = { INITTABSPTS(b2056_inittab_rev3) },
[4] = { INITTABSPTS(b2056_inittab_rev4) },
[5] = { INITTABSPTS(b2056_inittab_rev5) },
@@ -9035,7 +9035,7 @@ static void b2056_upload_inittab(struct b43_wldev *dev, bool ghz5,
void b2056_upload_inittabs(struct b43_wldev *dev,
bool ghz5, bool ignore_uploadflag)
{
- struct b2056_inittabs_pts *pts;
+ const struct b2056_inittabs_pts *pts;
if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
B43_WARN_ON(1);
@@ -9057,7 +9057,7 @@ void b2056_upload_inittabs(struct b43_wldev *dev,
void b2056_upload_syn_pll_cp2(struct b43_wldev *dev, bool ghz5)
{
- struct b2056_inittabs_pts *pts;
+ const struct b2056_inittabs_pts *pts;
const struct b2056_inittab_entry *e;
if (dev->phy.rev >= ARRAY_SIZE(b2056_inittabs)) {
diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c
index d4ce8a12ff9a..38e31d857e3e 100644
--- a/drivers/net/wireless/b43/radio_2059.c
+++ b/drivers/net/wireless/b43/radio_2059.c
@@ -27,7 +27,7 @@
#define RADIOREGS(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \
r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \
- r20, r21, r22, r23, r24, r25, r26, r27, r28) \
+ r20) \
.radio_syn16 = r00, \
.radio_syn17 = r01, \
.radio_syn22 = r02, \
@@ -41,22 +41,14 @@
.radio_syn41 = r10, \
.radio_syn43 = r11, \
.radio_syn47 = r12, \
- .radio_syn4a = r13, \
- .radio_syn58 = r14, \
- .radio_syn5a = r15, \
- .radio_syn6a = r16, \
- .radio_syn6d = r17, \
- .radio_syn6e = r18, \
- .radio_syn92 = r19, \
- .radio_syn98 = r20, \
- .radio_rxtx4a = r21, \
- .radio_rxtx58 = r22, \
- .radio_rxtx5a = r23, \
- .radio_rxtx6a = r24, \
- .radio_rxtx6d = r25, \
- .radio_rxtx6e = r26, \
- .radio_rxtx92 = r27, \
- .radio_rxtx98 = r28
+ .radio_rxtx4a = r13, \
+ .radio_rxtx58 = r14, \
+ .radio_rxtx5a = r15, \
+ .radio_rxtx6a = r16, \
+ .radio_rxtx6d = r17, \
+ .radio_rxtx6e = r18, \
+ .radio_rxtx92 = r19, \
+ .radio_rxtx98 = r20
#define PHYREGS(r0, r1, r2, r3, r4, r5) \
.phy_regs.bw1 = r0, \
@@ -70,91 +62,78 @@ static const struct b43_phy_ht_channeltab_e_radio2059 b43_phy_ht_channeltab_radi
{ .freq = 2412,
RADIOREGS(0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443),
},
{ .freq = 2417,
RADIOREGS(0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71,
0x09, 0x0f, 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441),
},
{ .freq = 2422,
RADIOREGS(0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f),
},
{ .freq = 2427,
RADIOREGS(0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b,
0x09, 0x0f, 0x09, 0x00, 0x09, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d),
},
{ .freq = 2432,
RADIOREGS(0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a),
},
{ .freq = 2437,
RADIOREGS(0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85,
0x09, 0x0f, 0x08, 0x00, 0x08, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438),
},
{ .freq = 2442,
RADIOREGS(0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436),
},
{ .freq = 2447,
RADIOREGS(0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434),
},
{ .freq = 2452,
RADIOREGS(0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94,
0x09, 0x0f, 0x07, 0x00, 0x07, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431),
},
{ .freq = 2457,
RADIOREGS(0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f),
},
{ .freq = 2462,
RADIOREGS(0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e,
0x09, 0x0f, 0x06, 0x00, 0x06, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d),
},
{ .freq = 2467,
RADIOREGS(0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3,
0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b),
},
{ .freq = 2472,
RADIOREGS(0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8,
0x09, 0x0f, 0x05, 0x00, 0x05, 0x00, 0x61, 0x03,
- 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x61, 0x03,
0x00, 0x00, 0x00, 0xf0, 0x00),
PHYREGS(0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429),
},
diff --git a/drivers/net/wireless/b43/radio_2059.h b/drivers/net/wireless/b43/radio_2059.h
index e4d69e55e9fe..40a82d7f510c 100644
--- a/drivers/net/wireless/b43/radio_2059.h
+++ b/drivers/net/wireless/b43/radio_2059.h
@@ -5,9 +5,9 @@
#include "phy_ht.h"
-#define R2059_SYN 0x000
-#define R2059_TXRX0 0x400
-#define R2059_RXRX1 0x800
+#define R2059_C1 0x000
+#define R2059_C2 0x400
+#define R2059_C3 0x800
#define R2059_ALL 0xC00
/* Values for various registers uploaded on channel switching */
@@ -28,14 +28,6 @@ struct b43_phy_ht_channeltab_e_radio2059 {
u8 radio_syn41;
u8 radio_syn43;
u8 radio_syn47;
- u8 radio_syn4a;
- u8 radio_syn58;
- u8 radio_syn5a;
- u8 radio_syn6a;
- u8 radio_syn6d;
- u8 radio_syn6e;
- u8 radio_syn92;
- u8 radio_syn98;
u8 radio_rxtx4a;
u8 radio_rxtx58;
u8 radio_rxtx5a;
diff --git a/drivers/net/wireless/b43/sdio.h b/drivers/net/wireless/b43/sdio.h
index fb633094403a..1e93926f388f 100644
--- a/drivers/net/wireless/b43/sdio.h
+++ b/drivers/net/wireless/b43/sdio.h
@@ -25,12 +25,12 @@ void b43_sdio_exit(void);
#else /* CONFIG_B43_SDIO */
-int b43_sdio_request_irq(struct b43_wldev *dev,
+static inline int b43_sdio_request_irq(struct b43_wldev *dev,
void (*handler)(struct b43_wldev *dev))
{
return -ENODEV;
}
-void b43_sdio_free_irq(struct b43_wldev *dev)
+static inline void b43_sdio_free_irq(struct b43_wldev *dev)
{
}
static inline int b43_sdio_init(void)
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index aaca60c6f575..94c755fdda14 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -2174,7 +2174,7 @@ static const u16 b43_ntab_loftlt1_r3[] = {
/* volatile tables, PHY revision >= 3 */
/* indexed by antswctl2g */
-static const u16 b43_ntab_antswctl2g_r3[4][32] = {
+static const u16 b43_ntab_antswctl_r3[4][32] = {
{
0x0082, 0x0082, 0x0211, 0x0222, 0x0328,
0x0000, 0x0000, 0x0000, 0x0144, 0x0000,
@@ -2800,7 +2800,7 @@ static const struct nphy_rf_control_override_rev7
{ 0x0010, 0x344, 0x345, 0x0010, 4 },
};
-struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
+static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
{ 10, 14, 19, 27 },
{ -5, 6, 10, 15 },
{ 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA },
@@ -2811,7 +2811,7 @@ struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
0x18, 0x18, 0x18,
0x01D0, 0x5,
};
-struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
+static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
{ /* 2GHz */
{ /* PHY rev 3 */
{ 7, 11, 16, 23 },
@@ -3095,9 +3095,55 @@ void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
}
#define ntab_upload(dev, offset, data) do { \
- b43_ntab_write_bulk(dev, offset, offset##_SIZE, data); \
+ b43_ntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \
} while (0)
-void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
+
+static void b43_nphy_tables_init_rev3(struct b43_wldev *dev)
+{
+ struct ssb_sprom *sprom = dev->dev->bus_sprom;
+ u8 antswlut;
+
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+ antswlut = sprom->fem.ghz5.antswlut;
+ else
+ antswlut = sprom->fem.ghz2.antswlut;
+
+ /* Static tables */
+ ntab_upload(dev, B43_NTAB_FRAMESTRUCT_R3, b43_ntab_framestruct_r3);
+ ntab_upload(dev, B43_NTAB_PILOT_R3, b43_ntab_pilot_r3);
+ ntab_upload(dev, B43_NTAB_TMAP_R3, b43_ntab_tmap_r3);
+ ntab_upload(dev, B43_NTAB_INTLEVEL_R3, b43_ntab_intlevel_r3);
+ ntab_upload(dev, B43_NTAB_TDTRN_R3, b43_ntab_tdtrn_r3);
+ ntab_upload(dev, B43_NTAB_NOISEVAR0_R3, b43_ntab_noisevar0_r3);
+ ntab_upload(dev, B43_NTAB_NOISEVAR1_R3, b43_ntab_noisevar1_r3);
+ ntab_upload(dev, B43_NTAB_MCS_R3, b43_ntab_mcs_r3);
+ ntab_upload(dev, B43_NTAB_TDI20A0_R3, b43_ntab_tdi20a0_r3);
+ ntab_upload(dev, B43_NTAB_TDI20A1_R3, b43_ntab_tdi20a1_r3);
+ ntab_upload(dev, B43_NTAB_TDI40A0_R3, b43_ntab_tdi40a0_r3);
+ ntab_upload(dev, B43_NTAB_TDI40A1_R3, b43_ntab_tdi40a1_r3);
+ ntab_upload(dev, B43_NTAB_PILOTLT_R3, b43_ntab_pilotlt_r3);
+ ntab_upload(dev, B43_NTAB_CHANEST_R3, b43_ntab_channelest_r3);
+ ntab_upload(dev, B43_NTAB_FRAMELT_R3, b43_ntab_framelookup_r3);
+ ntab_upload(dev, B43_NTAB_C0_ESTPLT_R3, b43_ntab_estimatepowerlt0_r3);
+ ntab_upload(dev, B43_NTAB_C1_ESTPLT_R3, b43_ntab_estimatepowerlt1_r3);
+ ntab_upload(dev, B43_NTAB_C0_ADJPLT_R3, b43_ntab_adjustpower0_r3);
+ ntab_upload(dev, B43_NTAB_C1_ADJPLT_R3, b43_ntab_adjustpower1_r3);
+ ntab_upload(dev, B43_NTAB_C0_GAINCTL_R3, b43_ntab_gainctl0_r3);
+ ntab_upload(dev, B43_NTAB_C1_GAINCTL_R3, b43_ntab_gainctl1_r3);
+ ntab_upload(dev, B43_NTAB_C0_IQLT_R3, b43_ntab_iqlt0_r3);
+ ntab_upload(dev, B43_NTAB_C1_IQLT_R3, b43_ntab_iqlt1_r3);
+ ntab_upload(dev, B43_NTAB_C0_LOFEEDTH_R3, b43_ntab_loftlt0_r3);
+ ntab_upload(dev, B43_NTAB_C1_LOFEEDTH_R3, b43_ntab_loftlt1_r3);
+
+ /* Volatile tables */
+ if (antswlut < ARRAY_SIZE(b43_ntab_antswctl_r3))
+ ntab_upload(dev, B43_NTAB_ANT_SW_CTL_R3,
+ b43_ntab_antswctl_r3[antswlut]);
+ else
+ B43_WARN_ON(1);
+}
+
+static void b43_nphy_tables_init_rev0(struct b43_wldev *dev)
{
/* Static tables */
ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct);
@@ -3130,48 +3176,13 @@ void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev)
ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1);
}
-#define ntab_upload_r3(dev, offset, data) do { \
- b43_ntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \
- } while (0)
-void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev)
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */
+void b43_nphy_tables_init(struct b43_wldev *dev)
{
- struct ssb_sprom *sprom = dev->dev->bus_sprom;
-
- /* Static tables */
- ntab_upload_r3(dev, B43_NTAB_FRAMESTRUCT_R3, b43_ntab_framestruct_r3);
- ntab_upload_r3(dev, B43_NTAB_PILOT_R3, b43_ntab_pilot_r3);
- ntab_upload_r3(dev, B43_NTAB_TMAP_R3, b43_ntab_tmap_r3);
- ntab_upload_r3(dev, B43_NTAB_INTLEVEL_R3, b43_ntab_intlevel_r3);
- ntab_upload_r3(dev, B43_NTAB_TDTRN_R3, b43_ntab_tdtrn_r3);
- ntab_upload_r3(dev, B43_NTAB_NOISEVAR0_R3, b43_ntab_noisevar0_r3);
- ntab_upload_r3(dev, B43_NTAB_NOISEVAR1_R3, b43_ntab_noisevar1_r3);
- ntab_upload_r3(dev, B43_NTAB_MCS_R3, b43_ntab_mcs_r3);
- ntab_upload_r3(dev, B43_NTAB_TDI20A0_R3, b43_ntab_tdi20a0_r3);
- ntab_upload_r3(dev, B43_NTAB_TDI20A1_R3, b43_ntab_tdi20a1_r3);
- ntab_upload_r3(dev, B43_NTAB_TDI40A0_R3, b43_ntab_tdi40a0_r3);
- ntab_upload_r3(dev, B43_NTAB_TDI40A1_R3, b43_ntab_tdi40a1_r3);
- ntab_upload_r3(dev, B43_NTAB_PILOTLT_R3, b43_ntab_pilotlt_r3);
- ntab_upload_r3(dev, B43_NTAB_CHANEST_R3, b43_ntab_channelest_r3);
- ntab_upload_r3(dev, B43_NTAB_FRAMELT_R3, b43_ntab_framelookup_r3);
- ntab_upload_r3(dev, B43_NTAB_C0_ESTPLT_R3,
- b43_ntab_estimatepowerlt0_r3);
- ntab_upload_r3(dev, B43_NTAB_C1_ESTPLT_R3,
- b43_ntab_estimatepowerlt1_r3);
- ntab_upload_r3(dev, B43_NTAB_C0_ADJPLT_R3, b43_ntab_adjustpower0_r3);
- ntab_upload_r3(dev, B43_NTAB_C1_ADJPLT_R3, b43_ntab_adjustpower1_r3);
- ntab_upload_r3(dev, B43_NTAB_C0_GAINCTL_R3, b43_ntab_gainctl0_r3);
- ntab_upload_r3(dev, B43_NTAB_C1_GAINCTL_R3, b43_ntab_gainctl1_r3);
- ntab_upload_r3(dev, B43_NTAB_C0_IQLT_R3, b43_ntab_iqlt0_r3);
- ntab_upload_r3(dev, B43_NTAB_C1_IQLT_R3, b43_ntab_iqlt1_r3);
- ntab_upload_r3(dev, B43_NTAB_C0_LOFEEDTH_R3, b43_ntab_loftlt0_r3);
- ntab_upload_r3(dev, B43_NTAB_C1_LOFEEDTH_R3, b43_ntab_loftlt1_r3);
-
- /* Volatile tables */
- if (sprom->fem.ghz2.antswlut < ARRAY_SIZE(b43_ntab_antswctl2g_r3))
- ntab_upload_r3(dev, B43_NTAB_ANT_SW_CTL_R3,
- b43_ntab_antswctl2g_r3[sprom->fem.ghz2.antswlut]);
+ if (dev->phy.rev >= 3)
+ b43_nphy_tables_init_rev3(dev);
else
- B43_WARN_ON(1);
+ b43_nphy_tables_init_rev0(dev);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */
diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h
index c600700ceedc..9ff33adcff89 100644
--- a/drivers/net/wireless/b43/tables_nphy.h
+++ b/drivers/net/wireless/b43/tables_nphy.h
@@ -115,22 +115,22 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
#define B43_NTAB_NOISEVAR11_SIZE 256
#define B43_NTAB_C0_ESTPLT B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */
#define B43_NTAB_C0_ESTPLT_SIZE 64
-#define B43_NTAB_C1_ESTPLT B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
-#define B43_NTAB_C1_ESTPLT_SIZE 64
#define B43_NTAB_C0_ADJPLT B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */
#define B43_NTAB_C0_ADJPLT_SIZE 128
-#define B43_NTAB_C1_ADJPLT B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
-#define B43_NTAB_C1_ADJPLT_SIZE 128
#define B43_NTAB_C0_GAINCTL B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */
#define B43_NTAB_C0_GAINCTL_SIZE 128
-#define B43_NTAB_C1_GAINCTL B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
-#define B43_NTAB_C1_GAINCTL_SIZE 128
#define B43_NTAB_C0_IQLT B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */
#define B43_NTAB_C0_IQLT_SIZE 128
-#define B43_NTAB_C1_IQLT B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
-#define B43_NTAB_C1_IQLT_SIZE 128
#define B43_NTAB_C0_LOFEEDTH B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */
#define B43_NTAB_C0_LOFEEDTH_SIZE 128
+#define B43_NTAB_C1_ESTPLT B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ESTPLT_SIZE 64
+#define B43_NTAB_C1_ADJPLT B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */
+#define B43_NTAB_C1_ADJPLT_SIZE 128
+#define B43_NTAB_C1_GAINCTL B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */
+#define B43_NTAB_C1_GAINCTL_SIZE 128
+#define B43_NTAB_C1_IQLT B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */
+#define B43_NTAB_C1_IQLT_SIZE 128
#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */
#define B43_NTAB_C1_LOFEEDTH_SIZE 128
@@ -154,15 +154,17 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
#define B43_NTAB_CHANEST_R3 B43_NTAB32(22, 0) /* channel estimate */
#define B43_NTAB_FRAMELT_R3 B43_NTAB8(24, 0) /* frame lookup */
#define B43_NTAB_C0_ESTPLT_R3 B43_NTAB8(26, 0) /* estimated power lookup 0 */
-#define B43_NTAB_C1_ESTPLT_R3 B43_NTAB8(27, 0) /* estimated power lookup 1 */
#define B43_NTAB_C0_ADJPLT_R3 B43_NTAB8(26, 64) /* adjusted power lookup 0 */
-#define B43_NTAB_C1_ADJPLT_R3 B43_NTAB8(27, 64) /* adjusted power lookup 1 */
#define B43_NTAB_C0_GAINCTL_R3 B43_NTAB32(26, 192) /* gain control lookup 0 */
-#define B43_NTAB_C1_GAINCTL_R3 B43_NTAB32(27, 192) /* gain control lookup 1 */
#define B43_NTAB_C0_IQLT_R3 B43_NTAB32(26, 320) /* I/Q lookup 0 */
-#define B43_NTAB_C1_IQLT_R3 B43_NTAB32(27, 320) /* I/Q lookup 1 */
#define B43_NTAB_C0_LOFEEDTH_R3 B43_NTAB16(26, 448) /* Local Oscillator Feed Through lookup 0 */
+#define B43_NTAB_C0_PAPD_COMP_R3 B43_NTAB16(26, 576)
+#define B43_NTAB_C1_ESTPLT_R3 B43_NTAB8(27, 0) /* estimated power lookup 1 */
+#define B43_NTAB_C1_ADJPLT_R3 B43_NTAB8(27, 64) /* adjusted power lookup 1 */
+#define B43_NTAB_C1_GAINCTL_R3 B43_NTAB32(27, 192) /* gain control lookup 1 */
+#define B43_NTAB_C1_IQLT_R3 B43_NTAB32(27, 320) /* I/Q lookup 1 */
#define B43_NTAB_C1_LOFEEDTH_R3 B43_NTAB16(27, 448) /* Local Oscillator Feed Through lookup 1 */
+#define B43_NTAB_C1_PAPD_COMP_R3 B43_NTAB16(27, 576)
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_40_SIZE 18
#define B43_NTAB_TX_IQLO_CAL_LOFT_LADDER_20_SIZE 18
@@ -182,8 +184,7 @@ void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value);
void b43_ntab_write_bulk(struct b43_wldev *dev, u32 offset,
unsigned int nr_elements, const void *_data);
-void b43_nphy_rev0_1_2_tables_init(struct b43_wldev *dev);
-void b43_nphy_rev3plus_tables_init(struct b43_wldev *dev);
+void b43_nphy_tables_init(struct b43_wldev *dev);
const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev);
diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c
index 5176363cadf2..e347b8d80ea4 100644
--- a/drivers/net/wireless/b43/tables_phy_lcn.c
+++ b/drivers/net/wireless/b43/tables_phy_lcn.c
@@ -313,7 +313,7 @@ static const u32 b43_lcntab_0x18[] = {
* TX gain.
**************************************************/
-const struct b43_lcntab_tx_gain_tbl_entry
+static const struct b43_lcntab_tx_gain_tbl_entry
b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0[B43_LCNTAB_TX_GAIN_SIZE] = {
{ 0x03, 0x00, 0x1f, 0x0, 0x48 },
{ 0x03, 0x00, 0x1f, 0x0, 0x46 },
@@ -449,7 +449,7 @@ const struct b43_lcntab_tx_gain_tbl_entry
* SW control.
**************************************************/
-const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = {
+static const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = {
0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001,
0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008,
@@ -631,7 +631,7 @@ static void b43_phy_lcn_upload_static_tables(struct b43_wldev *dev)
lcntab_upload(dev, B43_LCNTAB32(0x18, 0), b43_lcntab_0x18);
}
-void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
+static void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
const struct b43_lcntab_tx_gain_tbl_entry *gain_table)
{
u32 i;
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index 2d3c6644f82d..faeafe219c57 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -334,13 +334,9 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
B43legacy_DMA_RINGMEMSIZE,
&(ring->dmabase),
- GFP_KERNEL);
- if (!ring->descbase) {
- b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
- " failed\n");
+ GFP_KERNEL | __GFP_ZERO);
+ if (!ring->descbase)
return -ENOMEM;
- }
- memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE);
return 0;
}
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 8c3f70e1a013..572668821862 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2720,7 +2720,7 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
goto out_unlock_mutex;
/* Switch the PHY mode (if necessary). */
- switch (conf->channel->band) {
+ switch (conf->chandef.chan->band) {
case IEEE80211_BAND_2GHZ:
if (phy->type == B43legacy_PHYTYPE_B)
new_phymode = B43legacy_PHYMODE_B;
@@ -2748,8 +2748,9 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
/* Switch to the requested channel.
* The firmware takes care of races with the TX handler. */
- if (conf->channel->hw_value != phy->channel)
- b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0);
+ if (conf->chandef.chan->hw_value != phy->channel)
+ b43legacy_radio_selectchannel(dev, conf->chandef.chan->hw_value,
+ 0);
dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
@@ -3558,7 +3559,7 @@ static int b43legacy_op_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = dev->stats.link_noise;
diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig
index 1d92d874ebb6..fc8a0fa6d3b2 100644
--- a/drivers/net/wireless/brcm80211/Kconfig
+++ b/drivers/net/wireless/brcm80211/Kconfig
@@ -12,8 +12,9 @@ config BRCMSMAC
select CORDIC
---help---
This module adds support for PCIe wireless adapters based on Broadcom
- IEEE802.11n SoftMAC chipsets. If you choose to build a module, it'll
- be called brcmsmac.ko.
+ IEEE802.11n SoftMAC chipsets. It also has WLAN led support, which will
+ be available if you select BCMA_DRIVER_GPIO. If you choose to build a
+ module, the driver will be called brcmsmac.ko.
config BRCMFMAC
tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver"
@@ -36,15 +37,6 @@ config BRCMFMAC_SDIO
IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
use the driver for a SDIO wireless card.
-config BRCMFMAC_SDIO_OOB
- bool "Out of band interrupt support for SDIO interface chipset"
- depends on BRCMFMAC_SDIO
- ---help---
- This option enables out-of-band interrupt support for Broadcom
- SDIO Wifi chipset using fullmac in order to gain better
- performance and deep sleep wake up capability on certain
- platforms. Say N if you are unsure.
-
config BRCMFMAC_USB
bool "USB bus interface support for FullMAC driver"
depends on USB
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 756e19fc2795..8e9b1221b32c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -26,10 +26,12 @@ brcmfmac-objs += \
wl_cfg80211.o \
fwil.o \
fweh.o \
+ fwsignal.o \
p2p.o \
dhd_cdc.o \
dhd_common.o \
- dhd_linux.o
+ dhd_linux.o \
+ btcoex.o
brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
dhd_sdio.o \
bcmsdh.o \
@@ -39,3 +41,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
usb.o
brcmfmac-$(CONFIG_BRCMDBG) += \
dhd_dbg.o
+brcmfmac-$(CONFIG_BRCM_TRACING) += \
+ tracepoint.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 11fd1c735589..4891e3df2058 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -25,6 +25,7 @@
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
+#include <linux/platform_data/brcmfmac-sdio.h>
#include <defs.h>
#include <brcm_hw_ids.h>
@@ -37,16 +38,15 @@
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
-static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
+
+static irqreturn_t brcmf_sdio_oob_irqhandler(int irq, void *dev_id)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- brcmf_dbg(INTR, "oob intr triggered\n");
+ brcmf_dbg(INTR, "OOB intr triggered\n");
- /*
- * out-of-band interrupt is level-triggered which won't
+ /* out-of-band interrupt is level-triggered which won't
* be cleared until dpc
*/
if (sdiodev->irq_en) {
@@ -59,72 +59,12 @@ static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
-{
- int ret = 0;
- u8 data;
- unsigned long flags;
-
- brcmf_dbg(TRACE, "Entering: irq %d\n", sdiodev->irq);
-
- ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
- sdiodev->irq_flags, "brcmf_oob_intr",
- &sdiodev->func[1]->dev);
- if (ret != 0)
- return ret;
- spin_lock_init(&sdiodev->irq_en_lock);
- spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
- sdiodev->irq_en = true;
- spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
-
- ret = enable_irq_wake(sdiodev->irq);
- if (ret != 0)
- return ret;
- sdiodev->irq_wake = true;
-
- sdio_claim_host(sdiodev->func[1]);
-
- /* must configure SDIO_CCCR_IENx to enable irq */
- data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
- data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
- brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
-
- /* redirect, configure and enable io for interrupt signal */
- data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
- if (sdiodev->irq_flags & IRQF_TRIGGER_HIGH)
- data |= SDIO_SEPINT_ACT_HI;
- brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
-
- sdio_release_host(sdiodev->func[1]);
-
- return 0;
-}
-
-int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
-{
- brcmf_dbg(TRACE, "Entering\n");
-
- sdio_claim_host(sdiodev->func[1]);
- brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
- brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
- sdio_release_host(sdiodev->func[1]);
-
- if (sdiodev->irq_wake) {
- disable_irq_wake(sdiodev->irq);
- sdiodev->irq_wake = false;
- }
- free_irq(sdiodev->irq, &sdiodev->func[1]->dev);
- sdiodev->irq_en = false;
-
- return 0;
-}
-#else /* CONFIG_BRCMFMAC_SDIO_OOB */
-static void brcmf_sdio_irqhandler(struct sdio_func *func)
+static void brcmf_sdio_ib_irqhandler(struct sdio_func *func)
{
struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
- brcmf_dbg(INTR, "ib intr triggered\n");
+ brcmf_dbg(INTR, "IB intr triggered\n");
brcmf_sdbrcm_isr(sdiodev->bus);
}
@@ -136,28 +76,89 @@ static void brcmf_sdio_dummy_irqhandler(struct sdio_func *func)
int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "Entering\n");
+ int ret = 0;
+ u8 data;
+ unsigned long flags;
- sdio_claim_host(sdiodev->func[1]);
- sdio_claim_irq(sdiodev->func[1], brcmf_sdio_irqhandler);
- sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
- sdio_release_host(sdiodev->func[1]);
+ if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
+ brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
+ sdiodev->pdata->oob_irq_nr);
+ ret = request_irq(sdiodev->pdata->oob_irq_nr,
+ brcmf_sdio_oob_irqhandler,
+ sdiodev->pdata->oob_irq_flags,
+ "brcmf_oob_intr",
+ &sdiodev->func[1]->dev);
+ if (ret != 0) {
+ brcmf_err("request_irq failed %d\n", ret);
+ return ret;
+ }
+ sdiodev->oob_irq_requested = true;
+ spin_lock_init(&sdiodev->irq_en_lock);
+ spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
+ sdiodev->irq_en = true;
+ spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
+
+ ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
+ if (ret != 0) {
+ brcmf_err("enable_irq_wake failed %d\n", ret);
+ return ret;
+ }
+ sdiodev->irq_wake = true;
+
+ sdio_claim_host(sdiodev->func[1]);
+
+ /* must configure SDIO_CCCR_IENx to enable irq */
+ data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
+ data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
+
+ /* redirect, configure and enable io for interrupt signal */
+ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
+ if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
+ data |= SDIO_SEPINT_ACT_HI;
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
+
+ sdio_release_host(sdiodev->func[1]);
+ } else {
+ brcmf_dbg(SDIO, "Entering\n");
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_claim_irq(sdiodev->func[1], brcmf_sdio_ib_irqhandler);
+ sdio_claim_irq(sdiodev->func[2], brcmf_sdio_dummy_irqhandler);
+ sdio_release_host(sdiodev->func[1]);
+ }
return 0;
}
int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "Entering\n");
-
- sdio_claim_host(sdiodev->func[1]);
- sdio_release_irq(sdiodev->func[2]);
- sdio_release_irq(sdiodev->func[1]);
- sdio_release_host(sdiodev->func[1]);
+ brcmf_dbg(SDIO, "Entering\n");
+
+ if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
+ sdio_claim_host(sdiodev->func[1]);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
+ sdio_release_host(sdiodev->func[1]);
+
+ if (sdiodev->oob_irq_requested) {
+ sdiodev->oob_irq_requested = false;
+ if (sdiodev->irq_wake) {
+ disable_irq_wake(sdiodev->pdata->oob_irq_nr);
+ sdiodev->irq_wake = false;
+ }
+ free_irq(sdiodev->pdata->oob_irq_nr,
+ &sdiodev->func[1]->dev);
+ sdiodev->irq_en = false;
+ }
+ } else {
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_release_irq(sdiodev->func[2]);
+ sdio_release_irq(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
+ }
return 0;
}
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
int
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
@@ -253,9 +254,9 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u8 data;
int retval;
- brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
- brcmf_dbg(INFO, "data:0x%02x\n", data);
+ brcmf_dbg(SDIO, "data:0x%02x\n", data);
if (ret)
*ret = retval;
@@ -268,9 +269,9 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
u32 data;
int retval;
- brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
- brcmf_dbg(INFO, "data:0x%08x\n", data);
+ brcmf_dbg(SDIO, "data:0x%08x\n", data);
if (ret)
*ret = retval;
@@ -283,7 +284,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
{
int retval;
- brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
+ brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
@@ -295,7 +296,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
{
int retval;
- brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
+ brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
@@ -358,7 +359,7 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint width;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
@@ -381,7 +382,7 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint width;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pktq->qlen);
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
@@ -428,7 +429,7 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
+ brcmf_dbg(SDIO, "fun = %d, addr = 0x%x, size = %d\n",
fn, addr, pkt->len);
/* Async not implemented yet */
@@ -457,48 +458,92 @@ done:
return err;
}
-int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
- u8 *buf, uint nbytes)
+int
+brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
+ u8 *data, uint size)
{
- struct sk_buff *mypkt;
- bool write = rw ? SDIOH_WRITE : SDIOH_READ;
- int err;
+ int bcmerror = 0;
+ struct sk_buff *pkt;
+ u32 sdaddr;
+ uint dsize;
+
+ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
+ pkt = dev_alloc_skb(dsize);
+ if (!pkt) {
+ brcmf_err("dev_alloc_skb failed: len %d\n", dsize);
+ return -EIO;
+ }
+ pkt->priority = 0;
- addr &= SBSDIO_SB_OFT_ADDR_MASK;
- addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+ /* Determine initial transfer parameters */
+ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
+ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
+ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
+ else
+ dsize = size;
- mypkt = brcmu_pkt_buf_get_skb(nbytes);
- if (!mypkt) {
- brcmf_err("brcmu_pkt_buf_get_skb failed: len %d\n",
- nbytes);
- return -EIO;
+ sdio_claim_host(sdiodev->func[1]);
+
+ /* Do the transfer(s) */
+ while (size) {
+ /* Set the backplane window to include the start address */
+ bcmerror = brcmf_sdcard_set_sbaddr_window(sdiodev, address);
+ if (bcmerror)
+ break;
+
+ brcmf_dbg(SDIO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
+ write ? "write" : "read", dsize,
+ sdaddr, address & SBSDIO_SBWINDOW_MASK);
+
+ sdaddr &= SBSDIO_SB_OFT_ADDR_MASK;
+ sdaddr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+
+ skb_put(pkt, dsize);
+ if (write)
+ memcpy(pkt->data, data, dsize);
+ bcmerror = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC,
+ write, SDIO_FUNC_1,
+ sdaddr, pkt);
+ if (bcmerror) {
+ brcmf_err("membytes transfer failed\n");
+ break;
+ }
+ if (!write)
+ memcpy(data, pkt->data, dsize);
+ skb_trim(pkt, dsize);
+
+ /* Adjust for next transfer (if any) */
+ size -= dsize;
+ if (size) {
+ data += dsize;
+ address += dsize;
+ sdaddr = 0;
+ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
+ }
}
- /* For a write, copy the buffer data into the packet. */
- if (write)
- memcpy(mypkt->data, buf, nbytes);
+ dev_kfree_skb(pkt);
- err = brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, write,
- SDIO_FUNC_1, addr, mypkt);
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(sdiodev, sdiodev->sbwad))
+ brcmf_err("FAILED to set window back to 0x%x\n",
+ sdiodev->sbwad);
- /* For a read, copy the packet data back to the buffer. */
- if (!err && !write)
- memcpy(buf, mypkt->data, nbytes);
+ sdio_release_host(sdiodev->func[1]);
- brcmu_pkt_buf_free_skb(mypkt);
- return err;
+ return bcmerror;
}
int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
{
char t_func = (char)fn;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* issue abort cmd52 command through F0 */
brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
SDIO_CCCR_ABORT, &t_func);
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index d92d373733d7..44fa0cdbf97b 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -26,6 +26,7 @@
#include <linux/sched.h> /* request_irq() */
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/brcmfmac-sdio.h>
#include <net/cfg80211.h>
#include <defs.h>
@@ -40,32 +41,30 @@
#define DMA_ALIGN_MASK 0x03
+#define SDIO_DEVICE_ID_BROADCOM_43143 43143
#define SDIO_DEVICE_ID_BROADCOM_43241 0x4324
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334
+#define SDIO_DEVICE_ID_BROADCOM_4335 0x4335
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43143)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43241)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4335)},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
-static struct list_head oobirq_lh;
-struct brcmf_sdio_oobirq {
- unsigned int irq;
- unsigned long flags;
- struct list_head list;
-};
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
+static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
+
static bool
brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
@@ -139,7 +138,7 @@ int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
{
int err_ret;
- brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+ brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
if (brcmf_pm_resume_error(sdiodev))
@@ -179,7 +178,7 @@ int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
return -EINVAL;
}
- brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+ brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
rw, func, addr, nbytes);
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
@@ -252,7 +251,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
struct sk_buff *pkt;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
brcmf_pm_resume_wait(sdiodev, &sdiodev->request_chain_wait);
if (brcmf_pm_resume_error(sdiodev))
@@ -270,7 +269,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len, err_ret);
} else {
- brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ brcmf_dbg(SDIO, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pkt, SGCount, addr,
pkt_len);
}
@@ -280,7 +279,7 @@ brcmf_sdioh_request_chain(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
SGCount++;
}
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
return err_ret;
}
@@ -295,7 +294,7 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
uint pkt_len;
bool fifo = (fix_inc == SDIOH_DATA_FIX);
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
if (pkt == NULL)
return -EINVAL;
@@ -314,7 +313,7 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
brcmf_err("%s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
write ? "TX" : "RX", pkt, addr, pkt_len, status);
} else {
- brcmf_dbg(TRACE, "%s xfr'd %p, addr=0x%05x, len=%d\n",
+ brcmf_dbg(SDIO, "%s xfr'd %p, addr=0x%05x, len=%d\n",
write ? "TX" : "RX", pkt, addr, pkt_len);
}
@@ -350,12 +349,12 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
u32 fbraddr;
u8 func;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
/* Get the Card's common CIS address */
sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
SDIO_CCCR_CIS);
- brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
+ brcmf_dbg(SDIO, "Card's Common CIS Ptr = 0x%x\n",
sdiodev->func_cis_ptr[0]);
/* Get the Card's function CIS (for each function) */
@@ -363,7 +362,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
sdiodev->func_cis_ptr[func] =
brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
- brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
+ brcmf_dbg(SDIO, "Function %d CIS Ptr = 0x%x\n",
func, sdiodev->func_cis_ptr[func]);
}
@@ -382,7 +381,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
{
int err_ret = 0;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
sdiodev->num_funcs = 2;
@@ -404,13 +403,13 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
out:
sdio_release_host(sdiodev->func[1]);
- brcmf_dbg(TRACE, "Done\n");
+ brcmf_dbg(SDIO, "Done\n");
return err_ret;
}
void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
{
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
/* Disable Function 2 */
sdio_claim_host(sdiodev->func[2]);
@@ -424,33 +423,6 @@ void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
}
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
-static int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
-{
- struct brcmf_sdio_oobirq *oobirq_entry;
-
- if (list_empty(&oobirq_lh)) {
- brcmf_err("no valid oob irq resource\n");
- return -ENXIO;
- }
-
- oobirq_entry = list_first_entry(&oobirq_lh, struct brcmf_sdio_oobirq,
- list);
-
- sdiodev->irq = oobirq_entry->irq;
- sdiodev->irq_flags = oobirq_entry->flags;
- list_del(&oobirq_entry->list);
- kfree(oobirq_entry);
-
- return 0;
-}
-#else
-static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
-{
- return 0;
-}
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
-
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -458,11 +430,11 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
struct brcmf_sdio_dev *sdiodev;
struct brcmf_bus *bus_if;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(TRACE, "Class=%x\n", func->class);
- brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
- brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
- brcmf_dbg(TRACE, "Function#: %d\n", func->num);
+ brcmf_dbg(SDIO, "Enter\n");
+ brcmf_dbg(SDIO, "Class=%x\n", func->class);
+ brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+ brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+ brcmf_dbg(SDIO, "Function#: %d\n", func->num);
/* Consume func num 1 but dont do anything with it. */
if (func->num == 1)
@@ -491,23 +463,21 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
sdiodev->dev = &sdiodev->func[1]->dev;
+ sdiodev->pdata = brcmfmac_sdio_pdata;
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_byte_wait);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_chain_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
- err = brcmf_sdio_getintrcfg(sdiodev);
- if (err)
- goto fail;
- brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
+ brcmf_dbg(SDIO, "F2 found, calling brcmf_sdio_probe...\n");
err = brcmf_sdio_probe(sdiodev);
if (err) {
brcmf_err("F2 error, probe failed %d...\n", err);
goto fail;
}
- brcmf_dbg(TRACE, "F2 init completed...\n");
+ brcmf_dbg(SDIO, "F2 init completed...\n");
return 0;
fail:
@@ -523,10 +493,10 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
- brcmf_dbg(TRACE, "Enter\n");
- brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
- brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
- brcmf_dbg(TRACE, "Function: %d\n", func->num);
+ brcmf_dbg(SDIO, "Enter\n");
+ brcmf_dbg(SDIO, "sdio vendor ID: 0x%04x\n", func->vendor);
+ brcmf_dbg(SDIO, "sdio device ID: 0x%04x\n", func->device);
+ brcmf_dbg(SDIO, "Function: %d\n", func->num);
if (func->num != 1 && func->num != 2)
return;
@@ -543,7 +513,7 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
kfree(sdiodev);
}
- brcmf_dbg(TRACE, "Exit\n");
+ brcmf_dbg(SDIO, "Exit\n");
}
#ifdef CONFIG_PM_SLEEP
@@ -554,7 +524,7 @@ static int brcmf_sdio_suspend(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
int ret = 0;
- brcmf_dbg(TRACE, "\n");
+ brcmf_dbg(SDIO, "\n");
atomic_set(&sdiodev->suspend, true);
@@ -594,7 +564,7 @@ static const struct dev_pm_ops brcmf_sdio_pm_ops = {
static struct sdio_driver brcmf_sdmmc_driver = {
.probe = brcmf_ops_sdio_probe,
.remove = brcmf_ops_sdio_remove,
- .name = "brcmfmac",
+ .name = BRCMFMAC_SDIO_PDATA_NAME,
.id_table = brcmf_sdmmc_ids,
#ifdef CONFIG_PM_SLEEP
.drv = {
@@ -603,83 +573,65 @@ static struct sdio_driver brcmf_sdmmc_driver = {
#endif /* CONFIG_PM_SLEEP */
};
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static int brcmf_sdio_pd_probe(struct platform_device *pdev)
{
- struct resource *res;
- struct brcmf_sdio_oobirq *oobirq_entry;
- int i, ret;
+ int ret;
- INIT_LIST_HEAD(&oobirq_lh);
+ brcmf_dbg(SDIO, "Enter\n");
- for (i = 0; ; i++) {
- res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
- if (!res)
- break;
+ brcmfmac_sdio_pdata = pdev->dev.platform_data;
- oobirq_entry = kzalloc(sizeof(struct brcmf_sdio_oobirq),
- GFP_KERNEL);
- if (!oobirq_entry)
- return -ENOMEM;
- oobirq_entry->irq = res->start;
- oobirq_entry->flags = res->flags & IRQF_TRIGGER_MASK;
- list_add_tail(&oobirq_entry->list, &oobirq_lh);
- }
- if (i == 0)
- return -ENXIO;
+ if (brcmfmac_sdio_pdata->power_on)
+ brcmfmac_sdio_pdata->power_on();
ret = sdio_register_driver(&brcmf_sdmmc_driver);
-
if (ret)
brcmf_err("sdio_register_driver failed: %d\n", ret);
return ret;
}
-static struct platform_driver brcmf_sdio_pd = {
- .probe = brcmf_sdio_pd_probe,
- .driver = {
- .name = "brcmf_sdio_pd"
- }
-};
-
-void brcmf_sdio_exit(void)
+static int brcmf_sdio_pd_remove(struct platform_device *pdev)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
+
+ if (brcmfmac_sdio_pdata->power_off)
+ brcmfmac_sdio_pdata->power_off();
sdio_unregister_driver(&brcmf_sdmmc_driver);
- platform_driver_unregister(&brcmf_sdio_pd);
+ return 0;
}
-void brcmf_sdio_init(void)
-{
- int ret;
-
- brcmf_dbg(TRACE, "Enter\n");
-
- ret = platform_driver_register(&brcmf_sdio_pd);
+static struct platform_driver brcmf_sdio_pd = {
+ .remove = brcmf_sdio_pd_remove,
+ .driver = {
+ .name = BRCMFMAC_SDIO_PDATA_NAME
+ }
+};
- if (ret)
- brcmf_err("platform_driver_register failed: %d\n", ret);
-}
-#else
void brcmf_sdio_exit(void)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
- sdio_unregister_driver(&brcmf_sdmmc_driver);
+ if (brcmfmac_sdio_pdata)
+ platform_driver_unregister(&brcmf_sdio_pd);
+ else
+ sdio_unregister_driver(&brcmf_sdmmc_driver);
}
void brcmf_sdio_init(void)
{
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
- ret = sdio_register_driver(&brcmf_sdmmc_driver);
+ ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
+ if (ret == -ENODEV) {
+ brcmf_dbg(SDIO, "No platform data available, registering without.\n");
+ ret = sdio_register_driver(&brcmf_sdmmc_driver);
+ }
if (ret)
- brcmf_err("sdio_register_driver failed: %d\n", ret);
+ brcmf_err("driver registration failed: %d\n", ret);
}
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
new file mode 100644
index 000000000000..0cb591b050b3
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <defs.h>
+#include <dhd.h>
+#include <dhd_dbg.h>
+#include "fwil.h"
+#include "fwil_types.h"
+#include "btcoex.h"
+#include "p2p.h"
+#include "wl_cfg80211.h"
+
+/* T1 start SCO/eSCO priority suppression */
+#define BRCMF_BTCOEX_OPPR_WIN_TIME 2000
+
+/* BT registers values during DHCP */
+#define BRCMF_BT_DHCP_REG50 0x8022
+#define BRCMF_BT_DHCP_REG51 0
+#define BRCMF_BT_DHCP_REG64 0
+#define BRCMF_BT_DHCP_REG65 0
+#define BRCMF_BT_DHCP_REG71 0
+#define BRCMF_BT_DHCP_REG66 0x2710
+#define BRCMF_BT_DHCP_REG41 0x33
+#define BRCMF_BT_DHCP_REG68 0x190
+
+/* number of samples for SCO detection */
+#define BRCMF_BT_SCO_SAMPLES 12
+
+/**
+* enum brcmf_btcoex_state - BT coex DHCP state machine states
+* @BRCMF_BT_DHCP_IDLE: DCHP is idle
+* @BRCMF_BT_DHCP_START: DHCP started, wait before
+* boosting wifi priority
+* @BRCMF_BT_DHCP_OPPR_WIN: graceful DHCP opportunity ended,
+* boost wifi priority
+* @BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT: wifi priority boost end,
+* restore defaults
+*/
+enum brcmf_btcoex_state {
+ BRCMF_BT_DHCP_IDLE,
+ BRCMF_BT_DHCP_START,
+ BRCMF_BT_DHCP_OPPR_WIN,
+ BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT
+};
+
+/**
+ * struct brcmf_btcoex_info - BT coex related information
+ * @vif: interface for which request was done.
+ * @timer: timer for DHCP state machine
+ * @timeout: configured timeout.
+ * @timer_on: DHCP timer active
+ * @dhcp_done: DHCP finished before T1/T2 timer expiration
+ * @bt_state: DHCP state machine state
+ * @work: DHCP state machine work
+ * @cfg: driver private data for cfg80211 interface
+ * @reg66: saved value of btc_params 66
+ * @reg41: saved value of btc_params 41
+ * @reg68: saved value of btc_params 68
+ * @saved_regs_part1: flag indicating regs 66,41,68
+ * have been saved
+ * @reg51: saved value of btc_params 51
+ * @reg64: saved value of btc_params 64
+ * @reg65: saved value of btc_params 65
+ * @reg71: saved value of btc_params 71
+ * @saved_regs_part1: flag indicating regs 50,51,64,65,71
+ * have been saved
+ */
+struct brcmf_btcoex_info {
+ struct brcmf_cfg80211_vif *vif;
+ struct timer_list timer;
+ u16 timeout;
+ bool timer_on;
+ bool dhcp_done;
+ enum brcmf_btcoex_state bt_state;
+ struct work_struct work;
+ struct brcmf_cfg80211_info *cfg;
+ u32 reg66;
+ u32 reg41;
+ u32 reg68;
+ bool saved_regs_part1;
+ u32 reg50;
+ u32 reg51;
+ u32 reg64;
+ u32 reg65;
+ u32 reg71;
+ bool saved_regs_part2;
+};
+
+/**
+ * brcmf_btcoex_params_write() - write btc_params firmware variable
+ * @ifp: interface
+ * @addr: btc_params register number
+ * @data: data to write
+ */
+static s32 brcmf_btcoex_params_write(struct brcmf_if *ifp, u32 addr, u32 data)
+{
+ struct {
+ __le32 addr;
+ __le32 data;
+ } reg_write;
+
+ reg_write.addr = cpu_to_le32(addr);
+ reg_write.data = cpu_to_le32(data);
+ return brcmf_fil_iovar_data_set(ifp, "btc_params",
+ &reg_write, sizeof(reg_write));
+}
+
+/**
+ * brcmf_btcoex_params_read() - read btc_params firmware variable
+ * @ifp: interface
+ * @addr: btc_params register number
+ * @data: read data
+ */
+static s32 brcmf_btcoex_params_read(struct brcmf_if *ifp, u32 addr, u32 *data)
+{
+ *data = addr;
+
+ return brcmf_fil_iovar_int_get(ifp, "btc_params", data);
+}
+
+/**
+ * brcmf_btcoex_boost_wifi() - control BT SCO/eSCO parameters
+ * @btci: BT coex info
+ * @trump_sco:
+ * true - set SCO/eSCO parameters for compatibility
+ * during DHCP window
+ * false - restore saved parameter values
+ *
+ * Enhanced BT COEX settings for eSCO compatibility during DHCP window
+ */
+static void brcmf_btcoex_boost_wifi(struct brcmf_btcoex_info *btci,
+ bool trump_sco)
+{
+ struct brcmf_if *ifp = btci->cfg->pub->iflist[0];
+
+ if (trump_sco && !btci->saved_regs_part2) {
+ /* this should reduce eSCO agressive
+ * retransmit w/o breaking it
+ */
+
+ /* save current */
+ brcmf_dbg(TRACE, "new SCO/eSCO coex algo {save & override}\n");
+ brcmf_btcoex_params_read(ifp, 50, &btci->reg50);
+ brcmf_btcoex_params_read(ifp, 51, &btci->reg51);
+ brcmf_btcoex_params_read(ifp, 64, &btci->reg64);
+ brcmf_btcoex_params_read(ifp, 65, &btci->reg65);
+ brcmf_btcoex_params_read(ifp, 71, &btci->reg71);
+
+ btci->saved_regs_part2 = true;
+ brcmf_dbg(TRACE,
+ "saved bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ btci->reg50, btci->reg51, btci->reg64,
+ btci->reg65, btci->reg71);
+
+ /* pacify the eSco */
+ brcmf_btcoex_params_write(ifp, 50, BRCMF_BT_DHCP_REG50);
+ brcmf_btcoex_params_write(ifp, 51, BRCMF_BT_DHCP_REG51);
+ brcmf_btcoex_params_write(ifp, 64, BRCMF_BT_DHCP_REG64);
+ brcmf_btcoex_params_write(ifp, 65, BRCMF_BT_DHCP_REG65);
+ brcmf_btcoex_params_write(ifp, 71, BRCMF_BT_DHCP_REG71);
+
+ } else if (btci->saved_regs_part2) {
+ /* restore previously saved bt params */
+ brcmf_dbg(TRACE, "Do new SCO/eSCO coex algo {restore}\n");
+ brcmf_btcoex_params_write(ifp, 50, btci->reg50);
+ brcmf_btcoex_params_write(ifp, 51, btci->reg51);
+ brcmf_btcoex_params_write(ifp, 64, btci->reg64);
+ brcmf_btcoex_params_write(ifp, 65, btci->reg65);
+ brcmf_btcoex_params_write(ifp, 71, btci->reg71);
+
+ brcmf_dbg(TRACE,
+ "restored bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ btci->reg50, btci->reg51, btci->reg64,
+ btci->reg65, btci->reg71);
+
+ btci->saved_regs_part2 = false;
+ } else {
+ brcmf_err("attempted to restore not saved BTCOEX params\n");
+ }
+}
+
+/**
+ * brcmf_btcoex_is_sco_active() - check if SCO/eSCO is active
+ * @ifp: interface
+ *
+ * return: true if SCO/eSCO session is active
+ */
+static bool brcmf_btcoex_is_sco_active(struct brcmf_if *ifp)
+{
+ int ioc_res = 0;
+ bool res = false;
+ int sco_id_cnt = 0;
+ u32 param27;
+ int i;
+
+ for (i = 0; i < BRCMF_BT_SCO_SAMPLES; i++) {
+ ioc_res = brcmf_btcoex_params_read(ifp, 27, &param27);
+
+ if (ioc_res < 0) {
+ brcmf_err("ioc read btc params error\n");
+ break;
+ }
+
+ brcmf_dbg(TRACE, "sample[%d], btc_params 27:%x\n", i, param27);
+
+ if ((param27 & 0x6) == 2) { /* count both sco & esco */
+ sco_id_cnt++;
+ }
+
+ if (sco_id_cnt > 2) {
+ brcmf_dbg(TRACE,
+ "sco/esco detected, pkt id_cnt:%d samples:%d\n",
+ sco_id_cnt, i);
+ res = true;
+ break;
+ }
+ }
+ brcmf_dbg(TRACE, "exit: result=%d\n", res);
+ return res;
+}
+
+/**
+ * btcmf_btcoex_save_part1() - save first step parameters.
+ */
+static void btcmf_btcoex_save_part1(struct brcmf_btcoex_info *btci)
+{
+ struct brcmf_if *ifp = btci->vif->ifp;
+
+ if (!btci->saved_regs_part1) {
+ /* Retrieve and save original reg value */
+ brcmf_btcoex_params_read(ifp, 66, &btci->reg66);
+ brcmf_btcoex_params_read(ifp, 41, &btci->reg41);
+ brcmf_btcoex_params_read(ifp, 68, &btci->reg68);
+ btci->saved_regs_part1 = true;
+ brcmf_dbg(TRACE,
+ "saved btc_params regs (66,41,68) 0x%x 0x%x 0x%x\n",
+ btci->reg66, btci->reg41,
+ btci->reg68);
+ }
+}
+
+/**
+ * brcmf_btcoex_restore_part1() - restore first step parameters.
+ */
+static void brcmf_btcoex_restore_part1(struct brcmf_btcoex_info *btci)
+{
+ struct brcmf_if *ifp;
+
+ if (btci->saved_regs_part1) {
+ btci->saved_regs_part1 = false;
+ ifp = btci->vif->ifp;
+ brcmf_btcoex_params_write(ifp, 66, btci->reg66);
+ brcmf_btcoex_params_write(ifp, 41, btci->reg41);
+ brcmf_btcoex_params_write(ifp, 68, btci->reg68);
+ brcmf_dbg(TRACE,
+ "restored btc_params regs {66,41,68} 0x%x 0x%x 0x%x\n",
+ btci->reg66, btci->reg41,
+ btci->reg68);
+ }
+}
+
+/**
+ * brcmf_btcoex_timerfunc() - BT coex timer callback
+ */
+static void brcmf_btcoex_timerfunc(ulong data)
+{
+ struct brcmf_btcoex_info *bt_local = (struct brcmf_btcoex_info *)data;
+ brcmf_dbg(TRACE, "enter\n");
+
+ bt_local->timer_on = false;
+ schedule_work(&bt_local->work);
+}
+
+/**
+ * brcmf_btcoex_handler() - BT coex state machine work handler
+ * @work: work
+ */
+static void brcmf_btcoex_handler(struct work_struct *work)
+{
+ struct brcmf_btcoex_info *btci;
+ btci = container_of(work, struct brcmf_btcoex_info, work);
+ if (btci->timer_on) {
+ btci->timer_on = false;
+ del_timer_sync(&btci->timer);
+ }
+
+ switch (btci->bt_state) {
+ case BRCMF_BT_DHCP_START:
+ /* DHCP started provide OPPORTUNITY window
+ to get DHCP address
+ */
+ brcmf_dbg(TRACE, "DHCP started\n");
+ btci->bt_state = BRCMF_BT_DHCP_OPPR_WIN;
+ if (btci->timeout < BRCMF_BTCOEX_OPPR_WIN_TIME) {
+ mod_timer(&btci->timer, btci->timer.expires);
+ } else {
+ btci->timeout -= BRCMF_BTCOEX_OPPR_WIN_TIME;
+ mod_timer(&btci->timer,
+ jiffies +
+ msecs_to_jiffies(BRCMF_BTCOEX_OPPR_WIN_TIME));
+ }
+ btci->timer_on = true;
+ break;
+
+ case BRCMF_BT_DHCP_OPPR_WIN:
+ if (btci->dhcp_done) {
+ brcmf_dbg(TRACE, "DHCP done before T1 expiration\n");
+ goto idle;
+ }
+
+ /* DHCP is not over yet, start lowering BT priority */
+ brcmf_dbg(TRACE, "DHCP T1:%d expired\n",
+ BRCMF_BTCOEX_OPPR_WIN_TIME);
+ brcmf_btcoex_boost_wifi(btci, true);
+
+ btci->bt_state = BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT;
+ mod_timer(&btci->timer,
+ jiffies + msecs_to_jiffies(btci->timeout));
+ btci->timer_on = true;
+ break;
+
+ case BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT:
+ if (btci->dhcp_done)
+ brcmf_dbg(TRACE, "DHCP done before T2 expiration\n");
+ else
+ brcmf_dbg(TRACE, "DHCP T2:%d expired\n",
+ BRCMF_BT_DHCP_FLAG_FORCE_TIMEOUT);
+
+ goto idle;
+
+ default:
+ brcmf_err("invalid state=%d !!!\n", btci->bt_state);
+ goto idle;
+ }
+
+ return;
+
+idle:
+ btci->bt_state = BRCMF_BT_DHCP_IDLE;
+ btci->timer_on = false;
+ brcmf_btcoex_boost_wifi(btci, false);
+ cfg80211_crit_proto_stopped(&btci->vif->wdev, GFP_KERNEL);
+ brcmf_btcoex_restore_part1(btci);
+ btci->vif = NULL;
+}
+
+/**
+ * brcmf_btcoex_attach() - initialize BT coex data
+ * @cfg: driver private cfg80211 data
+ *
+ * return: 0 on success
+ */
+int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg)
+{
+ struct brcmf_btcoex_info *btci = NULL;
+ brcmf_dbg(TRACE, "enter\n");
+
+ btci = kmalloc(sizeof(struct brcmf_btcoex_info), GFP_KERNEL);
+ if (!btci)
+ return -ENOMEM;
+
+ btci->bt_state = BRCMF_BT_DHCP_IDLE;
+
+ /* Set up timer for BT */
+ btci->timer_on = false;
+ btci->timeout = BRCMF_BTCOEX_OPPR_WIN_TIME;
+ init_timer(&btci->timer);
+ btci->timer.data = (ulong)btci;
+ btci->timer.function = brcmf_btcoex_timerfunc;
+ btci->cfg = cfg;
+ btci->saved_regs_part1 = false;
+ btci->saved_regs_part2 = false;
+
+ INIT_WORK(&btci->work, brcmf_btcoex_handler);
+
+ cfg->btcoex = btci;
+ return 0;
+}
+
+/**
+ * brcmf_btcoex_detach - clean BT coex data
+ * @cfg: driver private cfg80211 data
+ */
+void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg)
+{
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (!cfg->btcoex)
+ return;
+
+ if (cfg->btcoex->timer_on) {
+ cfg->btcoex->timer_on = false;
+ del_timer_sync(&cfg->btcoex->timer);
+ }
+
+ cancel_work_sync(&cfg->btcoex->work);
+
+ brcmf_btcoex_boost_wifi(cfg->btcoex, false);
+ brcmf_btcoex_restore_part1(cfg->btcoex);
+
+ kfree(cfg->btcoex);
+ cfg->btcoex = NULL;
+}
+
+static void brcmf_btcoex_dhcp_start(struct brcmf_btcoex_info *btci)
+{
+ struct brcmf_if *ifp = btci->vif->ifp;
+
+ btcmf_btcoex_save_part1(btci);
+ /* set new regs values */
+ brcmf_btcoex_params_write(ifp, 66, BRCMF_BT_DHCP_REG66);
+ brcmf_btcoex_params_write(ifp, 41, BRCMF_BT_DHCP_REG41);
+ brcmf_btcoex_params_write(ifp, 68, BRCMF_BT_DHCP_REG68);
+ btci->dhcp_done = false;
+ btci->bt_state = BRCMF_BT_DHCP_START;
+ schedule_work(&btci->work);
+ brcmf_dbg(TRACE, "enable BT DHCP Timer\n");
+}
+
+static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci)
+{
+ /* Stop any bt timer because DHCP session is done */
+ btci->dhcp_done = true;
+ if (btci->timer_on) {
+ brcmf_dbg(TRACE, "disable BT DHCP Timer\n");
+ btci->timer_on = false;
+ del_timer_sync(&btci->timer);
+
+ /* schedule worker if transition to IDLE is needed */
+ if (btci->bt_state != BRCMF_BT_DHCP_IDLE) {
+ brcmf_dbg(TRACE, "bt_state:%d\n",
+ btci->bt_state);
+ schedule_work(&btci->work);
+ }
+ } else {
+ /* Restore original values */
+ brcmf_btcoex_restore_part1(btci);
+ }
+}
+
+/**
+ * brcmf_btcoex_set_mode - set BT coex mode
+ * @cfg: driver private cfg80211 data
+ * @mode: Wifi-Bluetooth coexistence mode
+ *
+ * return: 0 on success
+ */
+int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
+ enum brcmf_btcoex_mode mode, u16 duration)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy);
+ struct brcmf_btcoex_info *btci = cfg->btcoex;
+ struct brcmf_if *ifp = cfg->pub->iflist[0];
+
+ switch (mode) {
+ case BRCMF_BTCOEX_DISABLED:
+ brcmf_dbg(TRACE, "DHCP session starts\n");
+ if (btci->bt_state != BRCMF_BT_DHCP_IDLE)
+ return -EBUSY;
+ /* Start BT timer only for SCO connection */
+ if (brcmf_btcoex_is_sco_active(ifp)) {
+ btci->timeout = duration;
+ btci->vif = vif;
+ brcmf_btcoex_dhcp_start(btci);
+ }
+ break;
+
+ case BRCMF_BTCOEX_ENABLED:
+ brcmf_dbg(TRACE, "DHCP session ends\n");
+ if (btci->bt_state != BRCMF_BT_DHCP_IDLE &&
+ vif == btci->vif) {
+ brcmf_btcoex_dhcp_end(btci);
+ }
+ break;
+ default:
+ brcmf_dbg(TRACE, "Unknown mode, ignored\n");
+ }
+ return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/btcoex.h b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.h
new file mode 100644
index 000000000000..19647c68aa9e
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/btcoex.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef WL_BTCOEX_H_
+#define WL_BTCOEX_H_
+
+enum brcmf_btcoex_mode {
+ BRCMF_BTCOEX_DISABLED,
+ BRCMF_BTCOEX_ENABLED
+};
+
+int brcmf_btcoex_attach(struct brcmf_cfg80211_info *cfg);
+void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg);
+int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
+ enum brcmf_btcoex_mode mode, u16 duration);
+
+#endif /* WL_BTCOEX_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index ef6f23be6d32..28db9cf39672 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -28,6 +28,7 @@
/*******************************************************************************
* IO codes that are interpreted by dongle firmware
******************************************************************************/
+#define BRCMF_C_GET_VERSION 1
#define BRCMF_C_UP 2
#define BRCMF_C_DOWN 3
#define BRCMF_C_SET_PROMISC 10
@@ -72,6 +73,7 @@
#define BRCMF_C_SET_WSEC 134
#define BRCMF_C_GET_PHY_NOISE 135
#define BRCMF_C_GET_BSS_INFO 136
+#define BRCMF_C_GET_BANDLIST 140
#define BRCMF_C_SET_SCB_TIMEOUT 158
#define BRCMF_C_GET_PHYLIST 180
#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185
@@ -475,6 +477,11 @@ struct brcmf_sta_info_le {
__le32 rx_decrypt_failures; /* # of packet decrypted failed */
};
+struct brcmf_chanspec_list {
+ __le32 count; /* # of entries */
+ __le32 element[1]; /* variable length uint32 list */
+};
+
/*
* WLC_E_PROBRESP_MSG
* WLC_E_P2P_PROBREQ_MSG
@@ -501,6 +508,7 @@ struct brcmf_dcmd {
/* Forward decls for struct brcmf_pub (see below) */
struct brcmf_proto; /* device communication protocol info */
struct brcmf_cfg80211_dev; /* cfg80211 device info */
+struct brcmf_fws_info; /* firmware signalling info */
/* Common structure for module and instance linkage */
struct brcmf_pub {
@@ -527,6 +535,10 @@ struct brcmf_pub {
unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
struct brcmf_fweh_info fweh;
+
+ bool fw_signals;
+ struct brcmf_fws_info *fws;
+ spinlock_t fws_spinlock;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
@@ -537,10 +549,25 @@ struct brcmf_if_event {
u8 action;
u8 flags;
u8 bssidx;
+ u8 role;
};
-/* forward declaration */
+/* forward declarations */
struct brcmf_cfg80211_vif;
+struct brcmf_fws_mac_descriptor;
+
+/**
+ * enum brcmf_netif_stop_reason - reason for stopping netif queue.
+ *
+ * @BRCMF_NETIF_STOP_REASON_FWS_FC:
+ * netif stopped due to firmware signalling flow control.
+ * @BRCMF_NETIF_STOP_REASON_BLOCK_BUS:
+ * netif stopped due to bus blocking.
+ */
+enum brcmf_netif_stop_reason {
+ BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
+ BRCMF_NETIF_STOP_REASON_BLOCK_BUS = 2
+};
/**
* struct brcmf_if - interface control information.
@@ -549,9 +576,13 @@ struct brcmf_cfg80211_vif;
* @vif: points to cfg80211 specific interface information.
* @ndev: associated network device.
* @stats: interface specific network statistics.
+ * @setmacaddr_work: worker object for setting mac address.
+ * @multicast_work: worker object for multicast provisioning.
+ * @fws_desc: interface specific firmware-signalling descriptor.
* @ifidx: interface index in device firmware.
* @bssidx: index of bss associated with this interface.
* @mac_addr: assigned mac address.
+ * @netif_stop: bitmap indicates reason why netif queues are stopped.
* @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
* @pend_8021x_wait: used for signalling change in count.
*/
@@ -562,9 +593,11 @@ struct brcmf_if {
struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
+ struct brcmf_fws_mac_descriptor *fws_desc;
int ifidx;
s32 bssidx;
u8 mac_addr[ETH_ALEN];
+ u8 netif_stop;
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
};
@@ -582,13 +615,17 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
void *buf, uint len);
/* Remove any protocol-specific data header. */
-extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *rxp);
extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx,
s32 ifidx, char *name, u8 *mac_addr);
extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx);
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state);
extern u32 brcmf_get_chip_info(struct brcmf_if *ifp);
+extern void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success);
#endif /* _BRCMF_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
index ad25c3408b59..080395f49fa5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
@@ -39,10 +39,12 @@ struct brcmf_bus_dcmd {
* @txdata: send a data frame to the dongle (callee disposes skb).
* @txctl: transmit a control request message to dongle.
* @rxctl: receive a control response message from dongle.
+ * @gettxq: obtain a reference of bus transmit queue (optional).
*
* This structure provides an abstract interface towards the
* bus specific driver. For control messages to common driver
- * will assure there is only one active transaction.
+ * will assure there is only one active transaction. Unless
+ * indicated otherwise these callbacks are mandatory.
*/
struct brcmf_bus_ops {
int (*init)(struct device *dev);
@@ -50,6 +52,7 @@ struct brcmf_bus_ops {
int (*txdata)(struct device *dev, struct sk_buff *skb);
int (*txctl)(struct device *dev, unsigned char *msg, uint len);
int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
+ struct pktq * (*gettxq)(struct device *dev);
};
/**
@@ -115,6 +118,14 @@ int brcmf_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint len)
return bus->ops->rxctl(bus->dev, msg, len);
}
+static inline
+struct pktq *brcmf_bus_gettxq(struct brcmf_bus *bus)
+{
+ if (!bus->ops->gettxq)
+ return ERR_PTR(-ENOENT);
+
+ return bus->ops->gettxq(bus->dev);
+}
/*
* interface functions from common layer
*/
@@ -134,7 +145,7 @@ extern void brcmf_dev_reset(struct device *dev);
/* Indication from bus module to change flow-control state */
extern void brcmf_txflowblock(struct device *dev, bool state);
-/* Notify tx completion */
+/* Notify the bus has transferred the tx packet to firmware */
extern void brcmf_txcomplete(struct device *dev, struct sk_buff *txp,
bool success);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
index a2354d951dd7..59c77aa3b959 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
@@ -28,6 +28,7 @@
#include "dhd.h"
#include "dhd_proto.h"
#include "dhd_bus.h"
+#include "fwsignal.h"
#include "dhd_dbg.h"
struct brcmf_proto_cdc_dcmd {
@@ -71,13 +72,26 @@ struct brcmf_proto_cdc_dcmd {
((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
((idx) << BDC_FLAG2_IF_SHIFT)))
+/**
+ * struct brcmf_proto_bdc_header - BDC header format
+ *
+ * @flags: flags contain protocol and checksum info.
+ * @priority: 802.1d priority and USB flow control info (bit 4:7).
+ * @flags2: additional flags containing dongle interface index.
+ * @data_offset: start of packet data. header is following by firmware signals.
+ */
struct brcmf_proto_bdc_header {
u8 flags;
- u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */
+ u8 priority;
u8 flags2;
u8 data_offset;
};
+/*
+ * maximum length of firmware signal data between
+ * the BDC header and packet data in the tx path.
+ */
+#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 12
#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE
@@ -258,7 +272,7 @@ static void pkt_set_sum_good(struct sk_buff *skb, bool x)
skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
}
-void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
+void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
@@ -266,7 +280,6 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
brcmf_dbg(CDC, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
-
skb_push(pktbuf, BDC_HEADER_LEN);
h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
@@ -277,11 +290,11 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
h->flags2 = 0;
- h->data_offset = 0;
+ h->data_offset = offset;
BDC_SET_IF_IDX(h, ifidx);
}
-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
+int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,
struct sk_buff *pktbuf)
{
struct brcmf_proto_bdc_header *h;
@@ -290,8 +303,8 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
/* Pop BDC header used to convey priority for buses that don't */
- if (pktbuf->len < BDC_HEADER_LEN) {
- brcmf_err("rx data too short (%d < %d)\n",
+ if (pktbuf->len <= BDC_HEADER_LEN) {
+ brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",
pktbuf->len, BDC_HEADER_LEN);
return -EBADE;
}
@@ -328,7 +341,10 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx,
pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
skb_pull(pktbuf, BDC_HEADER_LEN);
- skb_pull(pktbuf, h->data_offset << 2);
+ if (do_fws)
+ brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);
+ else
+ skb_pull(pktbuf, h->data_offset << 2);
if (pktbuf->len == 0)
return -ENODATA;
@@ -350,7 +366,7 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
}
drvr->prot = cdc;
- drvr->hdrlen += BDC_HEADER_LEN;
+ drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +
sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
return 0;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
index 4544342a0428..be0787cab24f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
@@ -24,6 +24,7 @@
#include "dhd_proto.h"
#include "dhd_dbg.h"
#include "fwil.h"
+#include "tracepoint.h"
#define PKTFILTER_BUF_SIZE 128
#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
@@ -373,3 +374,35 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
done:
return err;
}
+
+#ifdef CONFIG_BRCM_TRACING
+void __brcmf_err(const char *func, const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ pr_err("%s: %pV", func, &vaf);
+ trace_brcmf_err(func, &vaf);
+ va_end(args);
+}
+#endif
+#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = fmt,
+ };
+ va_list args;
+
+ va_start(args, fmt);
+ vaf.va = &args;
+ if (brcmf_msg_level & level)
+ pr_debug("%s %pV", func, &vaf);
+ trace_brcmf_dbg(level, func, &vaf);
+ va_end(args);
+}
+#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index 57671eddf79d..202869cd0932 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -22,6 +22,7 @@
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
static struct dentry *root_folder;
@@ -123,3 +124,82 @@ void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
debugfs_create_file("counters", S_IRUGO, dentry,
sdcnt, &brcmf_debugfs_sdio_counter_ops);
}
+
+static
+ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct brcmf_fws_stats *fwstats = f->private_data;
+ char buf[650];
+ int res;
+
+ /* only allow read from start */
+ if (*ppos > 0)
+ return 0;
+
+ res = scnprintf(buf, sizeof(buf),
+ "header_pulls: %u\n"
+ "header_only_pkt: %u\n"
+ "tlv_parse_failed: %u\n"
+ "tlv_invalid_type: %u\n"
+ "mac_update_fails: %u\n"
+ "ps_update_fails: %u\n"
+ "if_update_fails: %u\n"
+ "pkt2bus: %u\n"
+ "generic_error: %u\n"
+ "rollback_success: %u\n"
+ "rollback_failed: %u\n"
+ "delayq_full: %u\n"
+ "supprq_full: %u\n"
+ "txs_indicate: %u\n"
+ "txs_discard: %u\n"
+ "txs_suppr_core: %u\n"
+ "txs_suppr_ps: %u\n"
+ "txs_tossed: %u\n"
+ "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
+ "fifo_credits_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
+ fwstats->header_pulls,
+ fwstats->header_only_pkt,
+ fwstats->tlv_parse_failed,
+ fwstats->tlv_invalid_type,
+ fwstats->mac_update_failed,
+ fwstats->mac_ps_update_failed,
+ fwstats->if_update_failed,
+ fwstats->pkt2bus,
+ fwstats->generic_error,
+ fwstats->rollback_success,
+ fwstats->rollback_failed,
+ fwstats->delayq_full_error,
+ fwstats->supprq_full_error,
+ fwstats->txs_indicate,
+ fwstats->txs_discard,
+ fwstats->txs_supp_core,
+ fwstats->txs_supp_ps,
+ fwstats->txs_tossed,
+ fwstats->send_pkts[0], fwstats->send_pkts[1],
+ fwstats->send_pkts[2], fwstats->send_pkts[3],
+ fwstats->send_pkts[4],
+ fwstats->fifo_credits_sent[0],
+ fwstats->fifo_credits_sent[1],
+ fwstats->fifo_credits_sent[2],
+ fwstats->fifo_credits_sent[3],
+ fwstats->fifo_credits_sent[4]);
+
+ return simple_read_from_buffer(data, count, ppos, buf, res);
+}
+
+static const struct file_operations brcmf_debugfs_fws_stats_ops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = brcmf_debugfs_fws_stats_read
+};
+
+void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+ struct brcmf_fws_stats *stats)
+{
+ struct dentry *dentry = drvr->dbgfs_dir;
+
+ if (!IS_ERR_OR_NULL(dentry))
+ debugfs_create_file("fws_stats", S_IRUGO, dentry,
+ stats, &brcmf_debugfs_fws_stats_ops);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index bc013cbe06f6..009c87bfd9ae 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -34,6 +34,7 @@
#define BRCMF_SCAN_VAL 0x00004000
#define BRCMF_CONN_VAL 0x00008000
#define BRCMF_CDC_VAL 0x00010000
+#define BRCMF_SDIO_VAL 0x00020000
/* set default print format */
#undef pr_fmt
@@ -43,6 +44,7 @@
* debugging is not selected. When debugging the driver error
* messages are as important as other tracing or even more so.
*/
+#ifndef CONFIG_BRCM_TRACING
#ifdef CONFIG_BRCMDBG
#define brcmf_err(fmt, ...) pr_err("%s: " fmt, __func__, ##__VA_ARGS__)
#else
@@ -52,15 +54,21 @@
pr_err("%s: " fmt, __func__, ##__VA_ARGS__); \
} while (0)
#endif
+#else
+__printf(2, 3)
+void __brcmf_err(const char *func, const char *fmt, ...);
+#define brcmf_err(fmt, ...) \
+ __brcmf_err(__func__, fmt, ##__VA_ARGS__)
+#endif
-#if defined(DEBUG)
-
+#if defined(DEBUG) || defined(CONFIG_BRCM_TRACING)
+__printf(3, 4)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...);
#define brcmf_dbg(level, fmt, ...) \
do { \
- if (brcmf_msg_level & BRCMF_##level##_VAL) \
- pr_debug("%s: " fmt, __func__, ##__VA_ARGS__); \
+ __brcmf_dbg(BRCMF_##level##_VAL, __func__, \
+ fmt, ##__VA_ARGS__); \
} while (0)
-
#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL)
#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL)
#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL)
@@ -69,7 +77,7 @@ do { \
#define BRCMF_EVENT_ON() (brcmf_msg_level & BRCMF_EVENT_VAL)
#define BRCMF_FIL_ON() (brcmf_msg_level & BRCMF_FIL_VAL)
-#else /* (defined DEBUG) || (defined DEBUG) */
+#else /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
@@ -81,10 +89,11 @@ do { \
#define BRCMF_EVENT_ON() 0
#define BRCMF_FIL_ON() 0
-#endif /* defined(DEBUG) */
+#endif /* defined(DEBUG) || defined(CONFIG_BRCM_TRACING) */
#define brcmf_dbg_hex_dump(test, data, len, fmt, ...) \
do { \
+ trace_brcmf_hexdump((void *)data, len); \
if (test) \
brcmu_dbg_hex_dump(data, len, fmt, ##__VA_ARGS__); \
} while (0)
@@ -125,6 +134,32 @@ struct brcmf_sdio_count {
ulong rx_readahead_cnt; /* packets where header read-ahead was used */
};
+struct brcmf_fws_stats {
+ u32 tlv_parse_failed;
+ u32 tlv_invalid_type;
+ u32 header_only_pkt;
+ u32 header_pulls;
+ u32 pkt2bus;
+ u32 send_pkts[5];
+ u32 fifo_credits_sent[5];
+ u32 fifo_credits_back[6];
+ u32 generic_error;
+ u32 mac_update_failed;
+ u32 mac_ps_update_failed;
+ u32 if_update_failed;
+ u32 packet_request_failed;
+ u32 credit_request_failed;
+ u32 rollback_success;
+ u32 rollback_failed;
+ u32 delayq_full_error;
+ u32 supprq_full_error;
+ u32 txs_indicate;
+ u32 txs_discard;
+ u32 txs_supp_core;
+ u32 txs_supp_ps;
+ u32 txs_tossed;
+};
+
struct brcmf_pub;
#ifdef DEBUG
void brcmf_debugfs_init(void);
@@ -134,6 +169,8 @@ void brcmf_debugfs_detach(struct brcmf_pub *drvr);
struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr,
struct brcmf_sdio_count *sdcnt);
+void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+ struct brcmf_fws_stats *stats);
#else
static inline void brcmf_debugfs_init(void)
{
@@ -148,6 +185,10 @@ static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
{
}
+static inline void brcmf_debugfs_create_fws_stats(struct brcmf_pub *drvr,
+ struct brcmf_fws_stats *stats)
+{
+}
#endif
#endif /* _BRCMF_DBG_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
index c06cea88df0d..59c25463e428 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
@@ -30,17 +30,18 @@
#include "p2p.h"
#include "wl_cfg80211.h"
#include "fwil.h"
+#include "fwsignal.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards");
MODULE_LICENSE("Dual BSD/GPL");
#define MAX_WAIT_FOR_8021X_TX 50 /* msecs */
/* Error bits */
int brcmf_msg_level;
-module_param(brcmf_msg_level, int, 0);
+module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(debug, "level of debug output");
/* P2P0 enable */
static int brcmf_p2p_enable;
@@ -222,18 +223,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done;
}
- /* handle ethernet header */
- eh = (struct ethhdr *)(skb->data);
- if (is_multicast_ether_addr(eh->h_dest))
- drvr->tx_multicast++;
- if (ntohs(eh->h_proto) == ETH_P_PAE)
- atomic_inc(&ifp->pend_8021x_cnt);
-
- /* If the protocol uses a data header, apply it */
- brcmf_proto_hdrpush(drvr, ifp->ifidx, skb);
-
- /* Use bus module to send data frame */
- ret = brcmf_bus_txdata(drvr->bus_if, skb);
+ ret = brcmf_fws_process_skb(ifp, skb);
done:
if (ret) {
@@ -247,9 +237,27 @@ done:
return NETDEV_TX_OK;
}
+void brcmf_txflowblock_if(struct brcmf_if *ifp,
+ enum brcmf_netif_stop_reason reason, bool state)
+{
+ if (!ifp)
+ return;
+
+ brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
+ ifp->bssidx, ifp->netif_stop, reason, state);
+ if (state) {
+ if (!ifp->netif_stop)
+ netif_stop_queue(ifp->ndev);
+ ifp->netif_stop |= reason;
+ } else {
+ ifp->netif_stop &= ~reason;
+ if (!ifp->netif_stop)
+ netif_wake_queue(ifp->ndev);
+ }
+}
+
void brcmf_txflowblock(struct device *dev, bool state)
{
- struct net_device *ndev;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
int i;
@@ -257,13 +265,8 @@ void brcmf_txflowblock(struct device *dev, bool state)
brcmf_dbg(TRACE, "Enter\n");
for (i = 0; i < BRCMF_MAX_IFS; i++)
- if (drvr->iflist[i]) {
- ndev = drvr->iflist[i]->ndev;
- if (state)
- netif_stop_queue(ndev);
- else
- netif_wake_queue(ndev);
- }
+ brcmf_txflowblock_if(drvr->iflist[i],
+ BRCMF_NETIF_STOP_REASON_BLOCK_BUS, state);
}
void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
@@ -283,7 +286,7 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
skb_unlink(skb, skb_list);
/* process and remove protocol-specific header */
- ret = brcmf_proto_hdrpull(drvr, &ifidx, skb);
+ ret = brcmf_proto_hdrpull(drvr, drvr->fw_signals, &ifidx, skb);
ifp = drvr->iflist[ifidx];
if (ret || !ifp || !ifp->ndev) {
@@ -320,13 +323,8 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
/* Strip header, count, deliver upward */
skb_pull(skb, ETH_HLEN);
- /* Process special event packets and then discard them */
- brcmf_fweh_process_skb(drvr, skb, &ifidx);
-
- if (drvr->iflist[ifidx]) {
- ifp = drvr->iflist[ifidx];
- ifp->ndev->last_rx = jiffies;
- }
+ /* Process special event packets */
+ brcmf_fweh_process_skb(drvr, skb);
if (!(ifp->ndev->flags & IFF_UP)) {
brcmu_pkt_buf_free_skb(skb);
@@ -349,31 +347,49 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
}
}
-void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
+ bool success)
{
- u8 ifidx;
+ struct brcmf_if *ifp;
struct ethhdr *eh;
+ u8 ifidx;
u16 type;
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_pub *drvr = bus_if->drvr;
- struct brcmf_if *ifp;
+ int res;
- brcmf_proto_hdrpull(drvr, &ifidx, txp);
+ res = brcmf_proto_hdrpull(drvr, false, &ifidx, txp);
ifp = drvr->iflist[ifidx];
if (!ifp)
- return;
+ goto done;
- eh = (struct ethhdr *)(txp->data);
- type = ntohs(eh->h_proto);
+ if (res == 0) {
+ eh = (struct ethhdr *)(txp->data);
+ type = ntohs(eh->h_proto);
- if (type == ETH_P_PAE) {
- atomic_dec(&ifp->pend_8021x_cnt);
- if (waitqueue_active(&ifp->pend_8021x_wait))
- wake_up(&ifp->pend_8021x_wait);
+ if (type == ETH_P_PAE) {
+ atomic_dec(&ifp->pend_8021x_cnt);
+ if (waitqueue_active(&ifp->pend_8021x_wait))
+ wake_up(&ifp->pend_8021x_wait);
+ }
}
if (!success)
ifp->stats.tx_errors++;
+done:
+ brcmu_pkt_buf_free_skb(txp);
+}
+
+void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_pub *drvr = bus_if->drvr;
+
+ /* await txstatus signal for firmware if active */
+ if (brcmf_fws_fc_active(drvr->fws)) {
+ if (!success)
+ brcmf_fws_bustxfail(drvr->fws, txp);
+ } else {
+ brcmf_txfinalize(drvr, txp, success);
+ }
}
static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
@@ -734,28 +750,35 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,
}
}
- /* Allocate netdev, including space for private structure */
- ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
- if (!ndev) {
- brcmf_err("OOM - alloc_netdev\n");
- return ERR_PTR(-ENOMEM);
+ if (!brcmf_p2p_enable && bssidx == 1) {
+ /* this is P2P_DEVICE interface */
+ brcmf_dbg(INFO, "allocate non-netdev interface\n");
+ ifp = kzalloc(sizeof(*ifp), GFP_KERNEL);
+ if (!ifp)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ brcmf_dbg(INFO, "allocate netdev interface\n");
+ /* Allocate netdev, including space for private structure */
+ ndev = alloc_netdev(sizeof(*ifp), name, ether_setup);
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ ifp = netdev_priv(ndev);
+ ifp->ndev = ndev;
}
- ifp = netdev_priv(ndev);
- ifp->ndev = ndev;
ifp->drvr = drvr;
drvr->iflist[bssidx] = ifp;
ifp->ifidx = ifidx;
ifp->bssidx = bssidx;
-
init_waitqueue_head(&ifp->pend_8021x_wait);
if (mac_addr != NULL)
memcpy(ifp->mac_addr, mac_addr, ETH_ALEN);
brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
- current->pid, ifp->ndev->name, ifp->mac_addr);
+ current->pid, name, ifp->mac_addr);
return ifp;
}
@@ -787,11 +810,13 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
}
unregister_netdev(ifp->ndev);
- drvr->iflist[bssidx] = NULL;
if (bssidx == 0)
brcmf_cfg80211_detach(drvr->config);
free_netdev(ifp->ndev);
+ } else {
+ kfree(ifp);
}
+ drvr->iflist[bssidx] = NULL;
}
int brcmf_attach(uint bus_hdrlen, struct device *dev)
@@ -873,6 +898,13 @@ int brcmf_bus_start(struct device *dev)
if (ret < 0)
goto fail;
+ drvr->fw_signals = true;
+ ret = brcmf_fws_init(drvr);
+ if (ret < 0)
+ goto fail;
+
+ brcmf_fws_add_interface(ifp);
+
drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev);
if (drvr->config == NULL) {
ret = -ENOMEM;
@@ -889,6 +921,10 @@ fail:
brcmf_err("failed: %d\n", ret);
if (drvr->config)
brcmf_cfg80211_detach(drvr->config);
+ if (drvr->fws) {
+ brcmf_fws_del_interface(ifp);
+ brcmf_fws_deinit(drvr);
+ }
free_netdev(ifp->ndev);
drvr->iflist[0] = NULL;
if (p2p_ifp) {
@@ -944,14 +980,18 @@ void brcmf_detach(struct device *dev)
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
- if (drvr->iflist[i])
+ if (drvr->iflist[i]) {
+ brcmf_fws_del_interface(drvr->iflist[i]);
brcmf_del_if(drvr, i);
+ }
brcmf_bus_detach(drvr);
if (drvr->prot)
brcmf_proto_detach(drvr);
+ brcmf_fws_deinit(drvr);
+
brcmf_debugfs_detach(drvr);
bus_if->drvr = NULL;
kfree(drvr);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
index 48fa70302192..ef9179883748 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
@@ -33,7 +33,7 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr);
/* Add any protocol-specific data header.
* Caller must reserve prot_hdrlen prepend space.
*/
-extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
+extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset,
struct sk_buff *txp);
/* Sets dongle media info (drv_version, mac address). */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 4469321c0eb3..d2487518bd2a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -31,6 +31,7 @@
#include <linux/bcma/bcma.h>
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
+#include <linux/platform_data/brcmfmac-sdio.h>
#include <asm/unaligned.h>
#include <defs.h>
#include <brcmu_wifi.h>
@@ -94,6 +95,7 @@ struct rte_console {
#include "dhd_bus.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#define TXQLEN 2048 /* bulk tx queue length */
#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */
@@ -323,6 +325,9 @@ MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
*/
#define BRCMF_IDLE_INTERVAL 1
+#define KSO_WAIT_US 50
+#define MAX_KSO_ATTEMPTS (PMU_MAX_TRANSITION_DLY/KSO_WAIT_US)
+
/*
* Conversion of 802.1D priority to precedence level
*/
@@ -332,95 +337,6 @@ static uint prio2prec(u32 prio)
(prio^2) : prio;
}
-/* core registers */
-struct sdpcmd_regs {
- u32 corecontrol; /* 0x00, rev8 */
- u32 corestatus; /* rev8 */
- u32 PAD[1];
- u32 biststatus; /* rev8 */
-
- /* PCMCIA access */
- u16 pcmciamesportaladdr; /* 0x010, rev8 */
- u16 PAD[1];
- u16 pcmciamesportalmask; /* rev8 */
- u16 PAD[1];
- u16 pcmciawrframebc; /* rev8 */
- u16 PAD[1];
- u16 pcmciaunderflowtimer; /* rev8 */
- u16 PAD[1];
-
- /* interrupt */
- u32 intstatus; /* 0x020, rev8 */
- u32 hostintmask; /* rev8 */
- u32 intmask; /* rev8 */
- u32 sbintstatus; /* rev8 */
- u32 sbintmask; /* rev8 */
- u32 funcintmask; /* rev4 */
- u32 PAD[2];
- u32 tosbmailbox; /* 0x040, rev8 */
- u32 tohostmailbox; /* rev8 */
- u32 tosbmailboxdata; /* rev8 */
- u32 tohostmailboxdata; /* rev8 */
-
- /* synchronized access to registers in SDIO clock domain */
- u32 sdioaccess; /* 0x050, rev8 */
- u32 PAD[3];
-
- /* PCMCIA frame control */
- u8 pcmciaframectrl; /* 0x060, rev8 */
- u8 PAD[3];
- u8 pcmciawatermark; /* rev8 */
- u8 PAD[155];
-
- /* interrupt batching control */
- u32 intrcvlazy; /* 0x100, rev8 */
- u32 PAD[3];
-
- /* counters */
- u32 cmd52rd; /* 0x110, rev8 */
- u32 cmd52wr; /* rev8 */
- u32 cmd53rd; /* rev8 */
- u32 cmd53wr; /* rev8 */
- u32 abort; /* rev8 */
- u32 datacrcerror; /* rev8 */
- u32 rdoutofsync; /* rev8 */
- u32 wroutofsync; /* rev8 */
- u32 writebusy; /* rev8 */
- u32 readwait; /* rev8 */
- u32 readterm; /* rev8 */
- u32 writeterm; /* rev8 */
- u32 PAD[40];
- u32 clockctlstatus; /* rev8 */
- u32 PAD[7];
-
- u32 PAD[128]; /* DMA engines */
-
- /* SDIO/PCMCIA CIS region */
- char cis[512]; /* 0x400-0x5ff, rev6 */
-
- /* PCMCIA function control registers */
- char pcmciafcr[256]; /* 0x600-6ff, rev6 */
- u16 PAD[55];
-
- /* PCMCIA backplane access */
- u16 backplanecsr; /* 0x76E, rev6 */
- u16 backplaneaddr0; /* rev6 */
- u16 backplaneaddr1; /* rev6 */
- u16 backplaneaddr2; /* rev6 */
- u16 backplaneaddr3; /* rev6 */
- u16 backplanedata0; /* rev6 */
- u16 backplanedata1; /* rev6 */
- u16 backplanedata2; /* rev6 */
- u16 backplanedata3; /* rev6 */
- u16 PAD[31];
-
- /* sprom "size" & "blank" info */
- u16 spromstatus; /* 0x7BE, rev2 */
- u32 PAD[464];
-
- u16 PAD[0x80];
-};
-
#ifdef DEBUG
/* Device console log buffer state */
struct brcmf_console {
@@ -587,12 +503,14 @@ struct brcmf_sdio {
bool txoff; /* Transmit flow-controlled */
struct brcmf_sdio_count sdcnt;
+ bool sr_enabled; /* SaveRestore enabled */
+ bool sleeping; /* SDIO bus sleeping */
};
/* clkstate */
#define CLK_NONE 0
#define CLK_SDONLY 1
-#define CLK_PENDING 2 /* Not used yet */
+#define CLK_PENDING 2
#define CLK_AVAIL 3
#ifdef DEBUG
@@ -600,7 +518,7 @@ static int qcount[NUMPRIO];
static int tx_packets[NUMPRIO];
#endif /* DEBUG */
-#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */
+#define DEFAULT_SDIO_DRIVE_STRENGTH 6 /* in milliamps */
#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
@@ -664,6 +582,62 @@ w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
return ret;
}
+static int
+brcmf_sdbrcm_kso_control(struct brcmf_sdio *bus, bool on)
+{
+ u8 wr_val = 0, rd_val, cmp_val, bmask;
+ int err = 0;
+ int try_cnt = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
+ /* 1st KSO write goes to AOS wake up core if device is asleep */
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ wr_val, &err);
+ if (err) {
+ brcmf_err("SDIO_AOS KSO write error: %d\n", err);
+ return err;
+ }
+
+ if (on) {
+ /* device WAKEUP through KSO:
+ * write bit 0 & read back until
+ * both bits 0 (kso bit) & 1 (dev on status) are set
+ */
+ cmp_val = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK |
+ SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK;
+ bmask = cmp_val;
+ usleep_range(2000, 3000);
+ } else {
+ /* Put device to sleep, turn off KSO */
+ cmp_val = 0;
+ /* only check for bit0, bit1(dev on status) may not
+ * get cleared right away
+ */
+ bmask = SBSDIO_FUNC1_SLEEPCSR_KSO_MASK;
+ }
+
+ do {
+ /* reliable KSO bit set/clr:
+ * the sdiod sleep write access is synced to PMU 32khz clk
+ * just one write attempt may fail,
+ * read it back until it matches written value
+ */
+ rd_val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ &err);
+ if (((rd_val & bmask) == cmp_val) && !err)
+ break;
+ brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n",
+ try_cnt, MAX_KSO_ATTEMPTS, err);
+ udelay(KSO_WAIT_US);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ wr_val, &err);
+ } while (try_cnt++ < MAX_KSO_ATTEMPTS);
+
+ return err;
+}
+
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
@@ -675,10 +649,15 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
u8 clkctl, clkreq, devctl;
unsigned long timeout;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
clkctl = 0;
+ if (bus->sr_enabled) {
+ bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY);
+ return 0;
+ }
+
if (on) {
/* Request HT Avail */
clkreq =
@@ -713,7 +692,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
- brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
+ brcmf_dbg(SDIO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
@@ -750,7 +729,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Mark clock available */
bus->clkstate = CLK_AVAIL;
- brcmf_dbg(INFO, "CLKCTL: turned ON\n");
+ brcmf_dbg(SDIO, "CLKCTL: turned ON\n");
#if defined(DEBUG)
if (!bus->alp_only) {
@@ -775,7 +754,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
bus->clkstate = CLK_SDONLY;
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
- brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
+ brcmf_dbg(SDIO, "CLKCTL: turned OFF\n");
if (err) {
brcmf_err("Failed access turning clock off: %d\n",
err);
@@ -788,7 +767,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Change idle/active SD state */
static int brcmf_sdbrcm_sdclk(struct brcmf_sdio *bus, bool on)
{
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
if (on)
bus->clkstate = CLK_SDONLY;
@@ -805,7 +784,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
uint oldstate = bus->clkstate;
#endif /* DEBUG */
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* Early exit if we're already there */
if (bus->clkstate == target) {
@@ -849,12 +828,69 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
break;
}
#ifdef DEBUG
- brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate);
+ brcmf_dbg(SDIO, "%d -> %d\n", oldstate, bus->clkstate);
#endif /* DEBUG */
return 0;
}
+static int
+brcmf_sdbrcm_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
+{
+ int err = 0;
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "request %s currently %s\n",
+ (sleep ? "SLEEP" : "WAKE"),
+ (bus->sleeping ? "SLEEP" : "WAKE"));
+
+ /* If SR is enabled control bus state with KSO */
+ if (bus->sr_enabled) {
+ /* Done if we're already in the requested state */
+ if (sleep == bus->sleeping)
+ goto end;
+
+ /* Going to sleep */
+ if (sleep) {
+ /* Don't sleep if something is pending */
+ if (atomic_read(&bus->intstatus) ||
+ atomic_read(&bus->ipend) > 0 ||
+ (!atomic_read(&bus->fcstate) &&
+ brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
+ data_ok(bus)))
+ return -EBUSY;
+ err = brcmf_sdbrcm_kso_control(bus, false);
+ /* disable watchdog */
+ if (!err)
+ brcmf_sdbrcm_wd_timer(bus, 0);
+ } else {
+ bus->idlecount = 0;
+ err = brcmf_sdbrcm_kso_control(bus, true);
+ }
+ if (!err) {
+ /* Change state */
+ bus->sleeping = sleep;
+ brcmf_dbg(SDIO, "new state %s\n",
+ (sleep ? "SLEEP" : "WAKE"));
+ } else {
+ brcmf_err("error while changing bus sleep state %d\n",
+ err);
+ return err;
+ }
+ }
+
+end:
+ /* control clocks */
+ if (sleep) {
+ if (!bus->sr_enabled)
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, pendok);
+ } else {
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, pendok);
+ }
+
+ return err;
+
+}
+
static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
{
u32 intstatus = 0;
@@ -862,7 +898,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
u8 fcbits;
int ret;
- brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(SDIO, "Enter\n");
/* Read mailbox data and ack that we did so */
ret = r_sdreg32(bus, &hmb_data,
@@ -875,7 +911,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
/* Dongle recomposed rx frames, accept them again */
if (hmb_data & HMB_DATA_NAKHANDLED) {
- brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
+ brcmf_dbg(SDIO, "Dongle reports NAK handled, expect rtx of %d\n",
bus->rx_seq);
if (!bus->rxskip)
brcmf_err("unexpected NAKHANDLED!\n");
@@ -896,7 +932,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
"expecting %d\n",
bus->sdpcm_ver, SDPCM_PROT_VERSION);
else
- brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
+ brcmf_dbg(SDIO, "Dongle ready, protocol version %d\n",
bus->sdpcm_ver);
}
@@ -970,7 +1006,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (!retries)
brcmf_err("count never zeroed: last 0x%04x\n", lastrbc);
else
- brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
+ brcmf_dbg(SDIO, "flush took %d iterations\n", 0xffff - retries);
if (rtx) {
bus->sdcnt.rxrtx++;
@@ -1173,7 +1209,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
/* If packets, issue read(s) and send up packet chain */
/* Return sequence numbers consumed? */
- brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
+ brcmf_dbg(SDIO, "start: glomd %p glom %p\n",
bus->glomd, skb_peek(&bus->glom));
/* If there's a descriptor, generate the packet chain */
@@ -1546,7 +1582,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
struct sk_buff_head pktlist; /* needed for bus interface */
u16 pad; /* Number of pad bytes to read */
uint rxleft = 0; /* Remaining number of frames allowed */
- int sdret; /* Return code from calls */
+ int ret; /* Return code from calls */
uint rxcount = 0; /* Total frames read */
struct brcmf_sdio_read *rd = &bus->cur_read, rd_new;
u8 head_read = 0;
@@ -1577,15 +1613,15 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
/* read header first for unknow frame length */
sdio_claim_host(bus->sdiodev->func[1]);
if (!rd->len) {
- sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
+ ret = brcmf_sdcard_recv_buf(bus->sdiodev,
bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC,
bus->rxhdr,
BRCMF_FIRSTREAD);
bus->sdcnt.f2rxhdrs++;
- if (sdret < 0) {
+ if (ret < 0) {
brcmf_err("RXHEADER FAILED: %d\n",
- sdret);
+ ret);
bus->sdcnt.rx_hdrfail++;
brcmf_sdbrcm_rxfail(bus, true, true);
sdio_release_host(bus->sdiodev->func[1]);
@@ -1637,14 +1673,14 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
skb_pull(pkt, head_read);
pkt_align(pkt, rd->len_left, BRCMF_SDALIGN);
- sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
+ ret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, pkt);
bus->sdcnt.f2rxdata++;
sdio_release_host(bus->sdiodev->func[1]);
- if (sdret < 0) {
+ if (ret < 0) {
brcmf_err("read %d bytes from channel %d failed: %d\n",
- rd->len, rd->channel, sdret);
+ rd->len, rd->channel, ret);
brcmu_pkt_buf_free_skb(pkt);
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdbrcm_rxfail(bus, true,
@@ -1775,13 +1811,12 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
/* Writes a HW/SW header into the packet and sends it. */
/* Assumes: (a) header space already there, (b) caller holds lock */
static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
- uint chan, bool free_pkt)
+ uint chan)
{
int ret;
u8 *frame;
u16 len, pad = 0;
u32 swheader;
- struct sk_buff *new;
int i;
brcmf_dbg(TRACE, "Enter\n");
@@ -1795,30 +1830,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
skb_headroom(pkt), pad);
bus->sdiodev->bus_if->tx_realloc++;
- new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
- if (!new) {
- brcmf_err("couldn't allocate new %d-byte packet\n",
- pkt->len + BRCMF_SDALIGN);
- ret = -ENOMEM;
+ ret = skb_cow(pkt, BRCMF_SDALIGN);
+ if (ret)
goto done;
- }
-
- pkt_align(new, pkt->len, BRCMF_SDALIGN);
- memcpy(new->data, pkt->data, pkt->len);
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
- /* free the pkt if canned one is not used */
- free_pkt = true;
- pkt = new;
- frame = (u8 *) (pkt->data);
- /* precondition: (frame % BRCMF_SDALIGN) == 0) */
- pad = 0;
- } else {
- skb_push(pkt, pad);
- frame = (u8 *) (pkt->data);
- /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
- memset(frame, 0, pad + SDPCM_HDRLEN);
+ pad = ((unsigned long)frame % BRCMF_SDALIGN);
}
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
+ memset(frame, 0, pad + SDPCM_HDRLEN);
}
/* precondition: pad < BRCMF_SDALIGN */
@@ -1833,8 +1852,8 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
(((pad +
SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+ *(((__le32 *) frame) + 1) = cpu_to_le32(swheader);
+ *(((__le32 *) frame) + 2) = 0;
#ifdef DEBUG
tx_packets[pkt->priority]++;
@@ -1900,11 +1919,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
done:
/* restore pkt buffer pointer before calling tx complete routine */
skb_pull(pkt, SDPCM_HDRLEN + pad);
- brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
-
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
-
+ brcmf_txcomplete(bus->sdiodev->dev, pkt, ret == 0);
return ret;
}
@@ -1932,7 +1947,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
spin_unlock_bh(&bus->txqlock);
datalen = pkt->len - SDPCM_HDRLEN;
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL);
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
@@ -1980,7 +1995,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
sdio_claim_host(bus->sdiodev->func[1]);
/* Enable clock for device interrupts */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_bus_sleep(bus, false, false);
/* Disable and clear interrupts at the chip level also */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
@@ -2032,23 +2047,19 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
bus->tx_seq = bus->rx_seq = 0;
}
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
{
unsigned long flags;
- spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
- if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
- enable_irq(bus->sdiodev->irq);
- bus->sdiodev->irq_en = true;
+ if (bus->sdiodev->oob_irq_requested) {
+ spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
+ if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
+ enable_irq(bus->sdiodev->pdata->oob_irq_nr);
+ bus->sdiodev->irq_en = true;
+ }
+ spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
}
- spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
-}
-#else
-static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
-{
}
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
static inline void brcmf_sdbrcm_adddpctsk(struct brcmf_sdio *bus)
{
@@ -2116,7 +2127,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
sdio_claim_host(bus->sdiodev->func[1]);
/* If waiting for HTAVAIL, check status */
- if (bus->clkstate == CLK_PENDING) {
+ if (!bus->sr_enabled && bus->clkstate == CLK_PENDING) {
u8 clkctl, devctl = 0;
#ifdef DEBUG
@@ -2138,7 +2149,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
- brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ brcmf_dbg(SDIO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
@@ -2162,7 +2173,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
}
/* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
+ brcmf_sdbrcm_bus_sleep(bus, false, true);
/* Pending interrupt indicates new device status */
if (atomic_read(&bus->ipend) > 0) {
@@ -2308,12 +2319,22 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
if ((bus->clkstate != CLK_PENDING)
&& bus->idletime == BRCMF_IDLE_IMMEDIATE) {
bus->activity = false;
+ brcmf_dbg(SDIO, "idle state\n");
sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_bus_sleep(bus, true, false);
sdio_release_host(bus->sdiodev->func[1]);
}
}
+static struct pktq *brcmf_sdbrcm_bus_gettxq(struct device *dev)
+{
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_sdio *bus = sdiodev->bus;
+
+ return &bus->txq;
+}
+
static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
{
int ret = -EBADE;
@@ -2343,7 +2364,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
skb_pull(pkt, SDPCM_HDRLEN);
brcmf_txcomplete(bus->sdiodev->dev, pkt, false);
- brcmu_pkt_buf_free_skb(pkt);
brcmf_err("out of bus->txq !!!\n");
ret = -ENOSR;
} else {
@@ -2374,69 +2394,6 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
return ret;
}
-static int
-brcmf_sdbrcm_membytes(struct brcmf_sdio *bus, bool write, u32 address, u8 *data,
- uint size)
-{
- int bcmerror = 0;
- u32 sdaddr;
- uint dsize;
-
- /* Determine initial transfer parameters */
- sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
- if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
- dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
- else
- dsize = size;
-
- sdio_claim_host(bus->sdiodev->func[1]);
-
- /* Set the backplane window to include the start address */
- bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
- if (bcmerror) {
- brcmf_err("window change failed\n");
- goto xfer_done;
- }
-
- /* Do the transfer(s) */
- while (size) {
- brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
- write ? "write" : "read", dsize,
- sdaddr, address & SBSDIO_SBWINDOW_MASK);
- bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
- sdaddr, data, dsize);
- if (bcmerror) {
- brcmf_err("membytes transfer failed\n");
- break;
- }
-
- /* Adjust for next transfer (if any) */
- size -= dsize;
- if (size) {
- data += dsize;
- address += dsize;
- bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
- address);
- if (bcmerror) {
- brcmf_err("window change failed\n");
- break;
- }
- sdaddr = 0;
- dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
- }
- }
-
-xfer_done:
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
- brcmf_err("FAILED to set window back to 0x%x\n",
- bus->sdiodev->sbwad);
-
- sdio_release_host(bus->sdiodev->func[1]);
-
- return bcmerror;
-}
-
#ifdef DEBUG
#define CONSOLE_LINE_MAX 192
@@ -2453,8 +2410,8 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
/* Read console log struct */
addr = bus->console_addr + offsetof(struct rte_console, log_le);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le,
- sizeof(c->log_le));
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&c->log_le,
+ sizeof(c->log_le));
if (rv < 0)
return rv;
@@ -2479,7 +2436,7 @@ static int brcmf_sdbrcm_readconsole(struct brcmf_sdio *bus)
/* Read the console buffer */
addr = le32_to_cpu(c->log_le.buf);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, c->buf, c->bufsize);
if (rv < 0)
return rv;
@@ -2604,7 +2561,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
/* Make sure backplane clock is on */
sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_bus_sleep(bus, false, false);
sdio_release_host(bus->sdiodev->func[1]);
/* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
@@ -2633,10 +2590,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
msecs_to_jiffies(2000));
if (!bus->ctrl_frame_stat) {
- brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
+ brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
ret = 0;
} else {
- brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
+ brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
ret = -1;
}
}
@@ -2662,6 +2619,7 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
bus->activity = false;
sdio_claim_host(bus->sdiodev->func[1]);
+ brcmf_dbg(INFO, "idle\n");
brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
sdio_release_host(bus->sdiodev->func[1]);
} else {
@@ -2691,23 +2649,22 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
struct sdpcm_shared_le sh_le;
__le32 addr_le;
- shaddr = bus->ramsize - 4;
+ shaddr = bus->ci->rambase + bus->ramsize - 4;
/*
* Read last word in socram to determine
* address of sdpcm_shared structure
*/
sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
- (u8 *)&addr_le, 4);
+ brcmf_sdbrcm_bus_sleep(bus, false, false);
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, shaddr, (u8 *)&addr_le, 4);
sdio_release_host(bus->sdiodev->func[1]);
if (rv < 0)
return rv;
addr = le32_to_cpu(addr_le);
- brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr);
+ brcmf_dbg(SDIO, "sdpcm_shared address 0x%08X\n", addr);
/*
* Check if addr is valid.
@@ -2720,8 +2677,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
}
/* Read hndrte_shared structure */
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
- sizeof(struct sdpcm_shared_le));
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr, (u8 *)&sh_le,
+ sizeof(struct sdpcm_shared_le));
if (rv < 0)
return rv;
@@ -2734,8 +2691,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
sh->console_addr = le32_to_cpu(sh_le.console_addr);
sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr);
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
- brcmf_err("sdpcm_shared version mismatch: dhd %d dongle %d\n",
+ if ((sh->flags & SDPCM_SHARED_VERSION_MASK) > SDPCM_SHARED_VERSION) {
+ brcmf_err("sdpcm shared version unsupported: dhd %d dongle %d\n",
SDPCM_SHARED_VERSION,
sh->flags & SDPCM_SHARED_VERSION_MASK);
return -EPROTO;
@@ -2757,22 +2714,22 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
/* obtain console information from device memory */
addr = sh->console_addr + offsetof(struct rte_console, log_le);
- rv = brcmf_sdbrcm_membytes(bus, false, addr,
- (u8 *)&sh_val, sizeof(u32));
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
if (rv < 0)
return rv;
console_ptr = le32_to_cpu(sh_val);
addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size);
- rv = brcmf_sdbrcm_membytes(bus, false, addr,
- (u8 *)&sh_val, sizeof(u32));
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
if (rv < 0)
return rv;
console_size = le32_to_cpu(sh_val);
addr = sh->console_addr + offsetof(struct rte_console, log_le.idx);
- rv = brcmf_sdbrcm_membytes(bus, false, addr,
- (u8 *)&sh_val, sizeof(u32));
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, addr,
+ (u8 *)&sh_val, sizeof(u32));
if (rv < 0)
return rv;
console_index = le32_to_cpu(sh_val);
@@ -2786,8 +2743,8 @@ static int brcmf_sdio_dump_console(struct brcmf_sdio *bus,
/* obtain the console data from device */
conbuf[console_size] = '\0';
- rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf,
- console_size);
+ rv = brcmf_sdio_ramrw(bus->sdiodev, false, console_ptr, (u8 *)conbuf,
+ console_size);
if (rv < 0)
goto done;
@@ -2817,21 +2774,18 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
int error, res;
char buf[350];
struct brcmf_trap_info tr;
- int nbytes;
loff_t pos = 0;
- if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
+ if ((sh->flags & SDPCM_SHARED_TRAP) == 0) {
+ brcmf_dbg(INFO, "no trap in firmware\n");
return 0;
+ }
- error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
- sizeof(struct brcmf_trap_info));
+ error = brcmf_sdio_ramrw(bus->sdiodev, false, sh->trap_addr, (u8 *)&tr,
+ sizeof(struct brcmf_trap_info));
if (error < 0)
return error;
- nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
- if (nbytes < 0)
- return nbytes;
-
res = scnprintf(buf, sizeof(buf),
"dongle trap info: type 0x%x @ epc 0x%08x\n"
" cpsr 0x%08x spsr 0x%08x sp 0x%08x\n"
@@ -2847,12 +2801,7 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
le32_to_cpu(tr.r4), le32_to_cpu(tr.r5),
le32_to_cpu(tr.r6), le32_to_cpu(tr.r7));
- error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res);
- if (error < 0)
- return error;
-
- nbytes += error;
- return nbytes;
+ return simple_read_from_buffer(data, count, &pos, buf, res);
}
static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
@@ -2876,14 +2825,14 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
sdio_claim_host(bus->sdiodev->func[1]);
if (sh->assert_file_addr != 0) {
- error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
- (u8 *)file, 80);
+ error = brcmf_sdio_ramrw(bus->sdiodev, false,
+ sh->assert_file_addr, (u8 *)file, 80);
if (error < 0)
return error;
}
if (sh->assert_exp_addr != 0) {
- error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr,
- (u8 *)expr, 80);
+ error = brcmf_sdio_ramrw(bus->sdiodev, false,
+ sh->assert_exp_addr, (u8 *)expr, 80);
if (error < 0)
return error;
}
@@ -2934,14 +2883,20 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
error = brcmf_sdio_assert_info(bus, &sh, data, count);
if (error < 0)
goto done;
-
nbytes = error;
- error = brcmf_sdio_trap_info(bus, &sh, data, count);
+
+ error = brcmf_sdio_trap_info(bus, &sh, data+nbytes, count);
if (error < 0)
goto done;
+ nbytes += error;
+
+ error = brcmf_sdio_dump_console(bus, &sh, data+nbytes, count);
+ if (error < 0)
+ goto done;
+ nbytes += error;
- error += nbytes;
- *ppos += error;
+ error = nbytes;
+ *ppos += nbytes;
done:
return error;
}
@@ -3035,84 +2990,8 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
return rxlen ? (int)rxlen : -ETIMEDOUT;
}
-static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
+static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{
- int bcmerror = 0;
- u32 varaddr;
- u32 varsizew;
- __le32 varsizew_le;
-#ifdef DEBUG
- char *nvram_ularray;
-#endif /* DEBUG */
-
- /* Even if there are no vars are to be written, we still
- need to set the ramsize. */
- varaddr = (bus->ramsize - 4) - bus->varsz;
-
- if (bus->vars) {
- /* Write the vars list */
- bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr,
- bus->vars, bus->varsz);
-#ifdef DEBUG
- /* Verify NVRAM bytes */
- brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n",
- bus->varsz);
- nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC);
- if (!nvram_ularray)
- return -ENOMEM;
-
- /* Upload image to verify downloaded contents. */
- memset(nvram_ularray, 0xaa, bus->varsz);
-
- /* Read the vars list to temp buffer for comparison */
- bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr,
- nvram_ularray, bus->varsz);
- if (bcmerror) {
- brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
- bcmerror, bus->varsz, varaddr);
- }
- /* Compare the org NVRAM with the one read from RAM */
- if (memcmp(bus->vars, nvram_ularray, bus->varsz))
- brcmf_err("Downloaded NVRAM image is corrupted\n");
- else
- brcmf_err("Download/Upload/Compare of NVRAM ok\n");
-
- kfree(nvram_ularray);
-#endif /* DEBUG */
- }
-
- /* adjust to the user specified RAM */
- brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
- brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
- varaddr, bus->varsz);
-
- /*
- * Determine the length token:
- * Varsize, converted to words, in lower 16-bits, checksum
- * in upper 16-bits.
- */
- if (bcmerror) {
- varsizew = 0;
- varsizew_le = cpu_to_le32(0);
- } else {
- varsizew = bus->varsz / 4;
- varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
- varsizew_le = cpu_to_le32(varsizew);
- }
-
- brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
- bus->varsz, varsizew);
-
- /* Write the length token to the last word */
- bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
- (u8 *)&varsizew_le, 4);
-
- return bcmerror;
-}
-
-static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
-{
- int bcmerror = 0;
struct chip_info *ci = bus->ci;
/* To enter download state, disable ARM and reset SOCRAM.
@@ -3121,41 +3000,19 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
if (enter) {
bus->alp_only = true;
- ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
-
- ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
-
- /* Clear the top bit of memory */
- if (bus->ramsize) {
- u32 zeros = 0;
- brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
- (u8 *)&zeros, 4);
- }
+ brcmf_sdio_chip_enter_download(bus->sdiodev, ci);
} else {
- if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
- brcmf_err("SOCRAM core is down after reset?\n");
- bcmerror = -EBADE;
- goto fail;
- }
-
- bcmerror = brcmf_sdbrcm_write_vars(bus);
- if (bcmerror) {
- brcmf_err("no vars written to RAM\n");
- bcmerror = 0;
- }
-
- w_sdreg32(bus, 0xFFFFFFFF,
- offsetof(struct sdpcmd_regs, intstatus));
-
- ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
+ if (!brcmf_sdio_chip_exit_download(bus->sdiodev, ci, bus->vars,
+ bus->varsz))
+ return false;
/* Allow HT Clock now that the ARM is running. */
bus->alp_only = false;
bus->sdiodev->bus_if->state = BRCMF_BUS_LOAD;
}
-fail:
- return bcmerror;
+
+ return true;
}
static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
@@ -3170,10 +3027,11 @@ static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
{
- int offset = 0;
+ int offset;
uint len;
u8 *memblock = NULL, *memptr;
int ret;
+ u8 idx;
brcmf_dbg(INFO, "Enter\n");
@@ -3194,10 +3052,15 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
memptr += (BRCMF_SDALIGN -
((u32)(unsigned long)memblock % BRCMF_SDALIGN));
+ offset = bus->ci->rambase;
+
/* Download image */
- while ((len =
- brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
- ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
+ len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus);
+ idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4);
+ if (BRCMF_MAX_CORENUM != idx)
+ memcpy(&bus->ci->rst_vec, memptr, sizeof(bus->ci->rst_vec));
+ while (len) {
+ ret = brcmf_sdio_ramrw(bus->sdiodev, true, offset, memptr, len);
if (ret) {
brcmf_err("error %d on writing %d membytes at 0x%08x\n",
ret, MEMBLOCK, offset);
@@ -3205,6 +3068,7 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
}
offset += MEMBLOCK;
+ len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus);
}
err:
@@ -3312,23 +3176,23 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
int bcmerror = -1;
/* Keep arm in reset */
- if (brcmf_sdbrcm_download_state(bus, true)) {
+ if (!brcmf_sdbrcm_download_state(bus, true)) {
brcmf_err("error placing ARM core in reset\n");
goto err;
}
- /* External image takes precedence if specified */
if (brcmf_sdbrcm_download_code_file(bus)) {
brcmf_err("dongle image file download failed\n");
goto err;
}
- /* External nvram takes precedence if specified */
- if (brcmf_sdbrcm_download_nvram(bus))
+ if (brcmf_sdbrcm_download_nvram(bus)) {
brcmf_err("dongle nvram file download failed\n");
+ goto err;
+ }
/* Take arm out of reset */
- if (brcmf_sdbrcm_download_state(bus, false)) {
+ if (!brcmf_sdbrcm_download_state(bus, false)) {
brcmf_err("error getting out of ARM core reset\n");
goto err;
}
@@ -3339,6 +3203,103 @@ err:
return bcmerror;
}
+static bool brcmf_sdbrcm_sr_capable(struct brcmf_sdio *bus)
+{
+ u32 addr, reg;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* old chips with PMU version less than 17 don't support save restore */
+ if (bus->ci->pmurev < 17)
+ return false;
+
+ /* read PMU chipcontrol register 3*/
+ addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
+ brcmf_sdio_regwl(bus->sdiodev, addr, 3, NULL);
+ addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
+ reg = brcmf_sdio_regrl(bus->sdiodev, addr, NULL);
+
+ return (bool)reg;
+}
+
+static void brcmf_sdbrcm_sr_init(struct brcmf_sdio *bus)
+{
+ int err = 0;
+ u8 val;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL,
+ &err);
+ if (err) {
+ brcmf_err("error reading SBSDIO_FUNC1_WAKEUPCTRL\n");
+ return;
+ }
+
+ val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT;
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_WAKEUPCTRL,
+ val, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_WAKEUPCTRL\n");
+ return;
+ }
+
+ /* Add CMD14 Support */
+ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_BRCM_CARDCAP,
+ (SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT |
+ SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT),
+ &err);
+ if (err) {
+ brcmf_err("error writing SDIO_CCCR_BRCM_CARDCAP\n");
+ return;
+ }
+
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_FORCE_HT, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_CHIPCLKCSR\n");
+ return;
+ }
+
+ /* set flag */
+ bus->sr_enabled = true;
+ brcmf_dbg(INFO, "SR enabled\n");
+}
+
+/* enable KSO bit */
+static int brcmf_sdbrcm_kso_init(struct brcmf_sdio *bus)
+{
+ u8 val;
+ int err = 0;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* KSO bit added in SDIO core rev 12 */
+ if (bus->ci->c_inf[1].rev < 12)
+ return 0;
+
+ val = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ &err);
+ if (err) {
+ brcmf_err("error reading SBSDIO_FUNC1_SLEEPCSR\n");
+ return err;
+ }
+
+ if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) {
+ val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN <<
+ SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
+ val, &err);
+ if (err) {
+ brcmf_err("error writing SBSDIO_FUNC1_SLEEPCSR\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
static bool
brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
{
@@ -3437,8 +3398,13 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
ret = -ENODEV;
}
- /* Restore previous clock setting */
- brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
+ if (brcmf_sdbrcm_sr_capable(bus)) {
+ brcmf_sdbrcm_sr_init(bus);
+ } else {
+ /* Restore previous clock setting */
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ saveclk, &err);
+ }
if (ret == 0) {
ret = brcmf_sdio_intr_register(bus->sdiodev);
@@ -3499,7 +3465,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
brcmf_dbg(TIMER, "Enter\n");
/* Poll period: check device if appropriate. */
- if (bus->poll && (++bus->polltick >= bus->pollrate)) {
+ if (!bus->sr_enabled &&
+ bus->poll && (++bus->polltick >= bus->pollrate)) {
u32 intstatus = 0;
/* Reset poll tick */
@@ -3550,7 +3517,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
bus->console.count -= bus->console_interval;
sdio_claim_host(bus->sdiodev->func[1]);
/* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_bus_sleep(bus, false, false);
if (brcmf_sdbrcm_readconsole(bus) < 0)
/* stop on error */
bus->console_interval = 0;
@@ -3567,8 +3534,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
bus->activity = false;
brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
} else {
+ brcmf_dbg(SDIO, "idle\n");
sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_bus_sleep(bus, true, false);
sdio_release_host(bus->sdiodev->func[1]);
}
}
@@ -3579,6 +3547,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
static bool brcmf_sdbrcm_chipmatch(u16 chipid)
{
+ if (chipid == BCM43143_CHIP_ID)
+ return true;
if (chipid == BCM43241_CHIP_ID)
return true;
if (chipid == BCM4329_CHIP_ID)
@@ -3587,6 +3557,8 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid)
return true;
if (chipid == BCM4334_CHIP_ID)
return true;
+ if (chipid == BCM4335_CHIP_ID)
+ return true;
return false;
}
@@ -3664,7 +3636,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
int err = 0;
int reg_addr;
u32 reg_val;
- u8 idx;
+ u32 drivestrength;
bus->alp_only = true;
@@ -3700,8 +3672,16 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
goto fail;
}
- brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
- SDIO_DRIVE_STRENGTH);
+ if (brcmf_sdbrcm_kso_init(bus)) {
+ brcmf_err("error enabling KSO\n");
+ goto fail;
+ }
+
+ if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
+ drivestrength = bus->sdiodev->pdata->drive_strength;
+ else
+ drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
+ brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
/* Get info on the SOCRAM cores... */
bus->ramsize = bus->ci->ramsize;
@@ -3710,12 +3690,37 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
goto fail;
}
- /* Set core control so an SDIO reset does a backplane reset */
- idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
- reg_addr = bus->ci->c_inf[idx].base +
- offsetof(struct sdpcmd_regs, corecontrol);
- reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
- brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
+ /* Set card control so an SDIO card reset does a WLAN backplane reset */
+ reg_val = brcmf_sdio_regrb(bus->sdiodev,
+ SDIO_CCCR_BRCM_CARDCTRL, &err);
+ if (err)
+ goto fail;
+
+ reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
+
+ brcmf_sdio_regwb(bus->sdiodev,
+ SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
+ if (err)
+ goto fail;
+
+ /* set PMUControl so a backplane reset does PMU state reload */
+ reg_addr = CORE_CC_REG(bus->ci->c_inf[0].base,
+ pmucontrol);
+ reg_val = brcmf_sdio_regrl(bus->sdiodev,
+ reg_addr,
+ &err);
+ if (err)
+ goto fail;
+
+ reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
+
+ brcmf_sdio_regwl(bus->sdiodev,
+ reg_addr,
+ reg_val,
+ &err);
+ if (err)
+ goto fail;
+
sdio_release_host(bus->sdiodev->func[1]);
@@ -3769,6 +3774,10 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
bus->use_rxchain = false;
bus->sd_rxchain = false;
+ /* SR state */
+ bus->sleeping = false;
+ bus->sr_enabled = false;
+
return true;
}
@@ -3856,6 +3865,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
.txdata = brcmf_sdbrcm_bus_txdata,
.txctl = brcmf_sdbrcm_bus_txctl,
.rxctl = brcmf_sdbrcm_bus_rxctl,
+ .gettxq = brcmf_sdbrcm_bus_gettxq,
};
void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
index e9d6f91a1f2b..5a64280e6485 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
@@ -20,6 +20,8 @@
#include "dhd.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
+#include "fwsignal.h"
#include "fweh.h"
#include "fwil.h"
@@ -154,7 +156,7 @@ static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
fweh = &ifp->drvr->fweh;
/* handle the event if valid interface and handler */
- if (ifp->ndev && fweh->evt_handler[code])
+ if (fweh->evt_handler[code])
err = fweh->evt_handler[code](ifp, emsg, data);
else
brcmf_err("unhandled event %d ignored\n", code);
@@ -179,9 +181,9 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
struct brcmf_if *ifp;
int err = 0;
- brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
- ifevent->action, ifevent->ifidx,
- ifevent->bssidx, ifevent->flags);
+ brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
+ ifevent->action, ifevent->ifidx, ifevent->bssidx,
+ ifevent->flags, ifevent->role);
if (ifevent->ifidx >= BRCMF_MAX_IFS) {
brcmf_err("invalid interface index: %u\n",
@@ -198,15 +200,20 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
emsg->ifname, emsg->addr);
if (IS_ERR(ifp))
return;
-
+ brcmf_fws_add_interface(ifp);
if (!drvr->fweh.evt_handler[BRCMF_E_IF])
err = brcmf_net_attach(ifp, false);
}
+ if (ifevent->action == BRCMF_E_IF_CHANGE)
+ brcmf_fws_reset_interface(ifp);
+
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
- if (ifevent->action == BRCMF_E_IF_DEL)
+ if (ifevent->action == BRCMF_E_IF_DEL) {
+ brcmf_fws_del_interface(ifp);
brcmf_del_if(drvr, ifevent->bssidx);
+ }
}
/**
@@ -400,13 +407,12 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
*
* @drvr: driver information object.
* @event_packet: event packet to process.
- * @ifidx: index of the firmware interface (may change).
*
* If the packet buffer contains a firmware event message it will
* dispatch the event to a registered handler (using worker).
*/
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- struct brcmf_event *event_packet, u8 *ifidx)
+ struct brcmf_event *event_packet)
{
enum brcmf_fweh_event_code code;
struct brcmf_fweh_info *fweh = &drvr->fweh;
@@ -418,7 +424,6 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
/* get event info */
code = get_unaligned_be32(&event_packet->msg.event_type);
datalen = get_unaligned_be32(&event_packet->msg.datalen);
- *ifidx = event_packet->msg.ifidx;
data = &event_packet[1];
if (code >= BRCMF_E_LAST)
@@ -435,7 +440,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
return;
event->code = code;
- event->ifidx = *ifidx;
+ event->ifidx = event_packet->msg.ifidx;
/* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
index 8c39b51dcccf..6ec5db9c60a5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
@@ -187,10 +187,10 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code);
int brcmf_fweh_activate_events(struct brcmf_if *ifp);
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
- struct brcmf_event *event_packet, u8 *ifidx);
+ struct brcmf_event *event_packet);
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
- struct sk_buff *skb, u8 *ifidx)
+ struct sk_buff *skb)
{
struct brcmf_event *event_packet;
u8 *data;
@@ -213,7 +213,7 @@ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return;
- brcmf_fweh_process_event(drvr, event_packet, ifidx);
+ brcmf_fweh_process_event(drvr, event_packet);
}
#endif /* FWEH_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index 8d1def935b8d..04f395930d86 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -25,6 +25,7 @@
#include "dhd.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#include "fwil.h"
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
new file mode 100644
index 000000000000..5352dc1fdf3c
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -0,0 +1,2067 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/if_ether.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/err.h>
+#include <linux/jiffies.h>
+#include <uapi/linux/nl80211.h>
+#include <net/cfg80211.h>
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include "dhd.h"
+#include "dhd_proto.h"
+#include "dhd_dbg.h"
+#include "dhd_bus.h"
+#include "fwil.h"
+#include "fwil_types.h"
+#include "fweh.h"
+#include "fwsignal.h"
+#include "p2p.h"
+#include "wl_cfg80211.h"
+
+/**
+ * DOC: Firmware Signalling
+ *
+ * Firmware can send signals to host and vice versa, which are passed in the
+ * data packets using TLV based header. This signalling layer is on top of the
+ * BDC bus protocol layer.
+ */
+
+/*
+ * single definition for firmware-driver flow control tlv's.
+ *
+ * each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length).
+ * A length value 0 indicates variable length tlv.
+ */
+#define BRCMF_FWS_TLV_DEFLIST \
+ BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \
+ BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \
+ BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \
+ BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \
+ BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \
+ BRCMF_FWS_TLV_DEF(MACDESC_ADD, 6, 8) \
+ BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \
+ BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
+ BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
+ BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
+ BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 6) \
+ BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
+ BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
+ BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
+ BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \
+ BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
+ BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
+
+/*
+ * enum brcmf_fws_tlv_type - definition of tlv identifiers.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+ BRCMF_FWS_TYPE_ ## name = id,
+enum brcmf_fws_tlv_type {
+ BRCMF_FWS_TLV_DEFLIST
+ BRCMF_FWS_TYPE_INVALID
+};
+#undef BRCMF_FWS_TLV_DEF
+
+/*
+ * enum brcmf_fws_tlv_len - definition of tlv lengths.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+ BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
+enum brcmf_fws_tlv_len {
+ BRCMF_FWS_TLV_DEFLIST
+};
+#undef BRCMF_FWS_TLV_DEF
+
+#ifdef DEBUG
+/*
+ * brcmf_fws_tlv_names - array of tlv names.
+ */
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+ { id, #name },
+static struct {
+ enum brcmf_fws_tlv_type id;
+ const char *name;
+} brcmf_fws_tlv_names[] = {
+ BRCMF_FWS_TLV_DEFLIST
+};
+#undef BRCMF_FWS_TLV_DEF
+
+static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++)
+ if (brcmf_fws_tlv_names[i].id == id)
+ return brcmf_fws_tlv_names[i].name;
+
+ return "INVALID";
+}
+#else
+static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
+{
+ return "NODEBUG";
+}
+#endif /* DEBUG */
+
+/*
+ * flags used to enable tlv signalling from firmware.
+ */
+#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
+#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
+#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
+#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
+#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
+#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
+#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
+
+#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
+#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
+
+#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
+#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
+#define BRCMF_FWS_FLOWCONTROL_HIWATER 128
+#define BRCMF_FWS_FLOWCONTROL_LOWATER 64
+
+#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
+#define BRCMF_FWS_PSQ_LEN 256
+
+#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01
+#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02
+
+#define BRCMF_FWS_RET_OK_NOSCHEDULE 0
+#define BRCMF_FWS_RET_OK_SCHEDULE 1
+
+/**
+ * enum brcmf_fws_skb_state - indicates processing state of skb.
+ *
+ * @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
+ * @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
+ * @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
+ */
+enum brcmf_fws_skb_state {
+ BRCMF_FWS_SKBSTATE_NEW,
+ BRCMF_FWS_SKBSTATE_DELAYED,
+ BRCMF_FWS_SKBSTATE_SUPPRESSED
+};
+
+/**
+ * struct brcmf_skbuff_cb - control buffer associated with skbuff.
+ *
+ * @if_flags: holds interface index and packet related flags.
+ * @htod: host to device packet identifier (used in PKTTAG tlv).
+ * @state: transmit state of the packet.
+ * @mac: descriptor related to destination for this packet.
+ *
+ * This information is stored in control buffer struct sk_buff::cb, which
+ * provides 48 bytes of storage so this structure should not exceed that.
+ */
+struct brcmf_skbuff_cb {
+ u16 if_flags;
+ u32 htod;
+ enum brcmf_fws_skb_state state;
+ struct brcmf_fws_mac_descriptor *mac;
+};
+
+/*
+ * macro casting skbuff control buffer to struct brcmf_skbuff_cb.
+ */
+#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb))
+
+/*
+ * sk_buff control if flags
+ *
+ * b[11] - packet sent upon firmware request.
+ * b[10] - packet only contains signalling data.
+ * b[9] - packet is a tx packet.
+ * b[8] - packet uses FIFO credit (non-pspoll).
+ * b[7] - interface in AP mode.
+ * b[6:4] - AC FIFO number.
+ * b[3:0] - interface index.
+ */
+#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK 0x0800
+#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT 11
+#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK 0x0400
+#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT 10
+#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK 0x0200
+#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT 9
+#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK 0x0100
+#define BRCMF_SKB_IF_FLAGS_CREDITCHECK_SHIFT 8
+#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK 0x0080
+#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT 7
+#define BRCMF_SKB_IF_FLAGS_FIFO_MASK 0x0070
+#define BRCMF_SKB_IF_FLAGS_FIFO_SHIFT 4
+#define BRCMF_SKB_IF_FLAGS_INDEX_MASK 0x000f
+#define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT 0
+
+#define brcmf_skb_if_flags_set_field(skb, field, value) \
+ brcmu_maskset16(&(brcmf_skbcb(skb)->if_flags), \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT, (value))
+#define brcmf_skb_if_flags_get_field(skb, field) \
+ brcmu_maskget16(brcmf_skbcb(skb)->if_flags, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
+ BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT)
+
+/*
+ * sk_buff control packet identifier
+ *
+ * 32-bit packet identifier used in PKTTAG tlv from host to dongle.
+ *
+ * - Generated at the host (e.g. dhd)
+ * - Seen as a generic sequence number by firmware except for the flags field.
+ *
+ * Generation : b[31] => generation number for this packet [host->fw]
+ * OR, current generation number [fw->host]
+ * Flags : b[30:27] => command, status flags
+ * FIFO-AC : b[26:24] => AC-FIFO id
+ * h-slot : b[23:8] => hanger-slot
+ * freerun : b[7:0] => A free running counter
+ */
+#define BRCMF_SKB_HTOD_TAG_GENERATION_MASK 0x80000000
+#define BRCMF_SKB_HTOD_TAG_GENERATION_SHIFT 31
+#define BRCMF_SKB_HTOD_TAG_FLAGS_MASK 0x78000000
+#define BRCMF_SKB_HTOD_TAG_FLAGS_SHIFT 27
+#define BRCMF_SKB_HTOD_TAG_FIFO_MASK 0x07000000
+#define BRCMF_SKB_HTOD_TAG_FIFO_SHIFT 24
+#define BRCMF_SKB_HTOD_TAG_HSLOT_MASK 0x00ffff00
+#define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT 8
+#define BRCMF_SKB_HTOD_TAG_FREERUN_MASK 0x000000ff
+#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT 0
+
+#define brcmf_skb_htod_tag_set_field(skb, field, value) \
+ brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT, (value))
+#define brcmf_skb_htod_tag_get_field(skb, field) \
+ brcmu_maskget32(brcmf_skbcb(skb)->htod, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
+ BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
+
+#define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000
+#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31
+#define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000
+#define BRCMF_FWS_TXSTAT_FLAGS_SHIFT 27
+#define BRCMF_FWS_TXSTAT_FIFO_MASK 0x07000000
+#define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24
+#define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00
+#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8
+#define BRCMF_FWS_TXSTAT_PKTID_MASK 0x00FFFFFF
+#define BRCMF_FWS_TXSTAT_PKTID_SHIFT 0
+
+#define brcmf_txstatus_get_field(txs, field) \
+ brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
+ BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
+
+/* How long to defer borrowing in jiffies */
+#define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
+
+/**
+ * enum brcmf_fws_fifo - fifo indices used by dongle firmware.
+ *
+ * @BRCMF_FWS_FIFO_AC_BK: fifo for background traffic.
+ * @BRCMF_FWS_FIFO_AC_BE: fifo for best-effort traffic.
+ * @BRCMF_FWS_FIFO_AC_VI: fifo for video traffic.
+ * @BRCMF_FWS_FIFO_AC_VO: fifo for voice traffic.
+ * @BRCMF_FWS_FIFO_BCMC: fifo for broadcast/multicast (AP only).
+ * @BRCMF_FWS_FIFO_ATIM: fifo for ATIM (AP only).
+ * @BRCMF_FWS_FIFO_COUNT: number of fifos.
+ */
+enum brcmf_fws_fifo {
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VO,
+ BRCMF_FWS_FIFO_BCMC,
+ BRCMF_FWS_FIFO_ATIM,
+ BRCMF_FWS_FIFO_COUNT
+};
+
+/**
+ * enum brcmf_fws_txstatus - txstatus flag values.
+ *
+ * @BRCMF_FWS_TXSTATUS_DISCARD:
+ * host is free to discard the packet.
+ * @BRCMF_FWS_TXSTATUS_CORE_SUPPRESS:
+ * 802.11 core suppressed the packet.
+ * @BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS:
+ * firmware suppress the packet as device is already in PS mode.
+ * @BRCMF_FWS_TXSTATUS_FW_TOSSED:
+ * firmware tossed the packet.
+ */
+enum brcmf_fws_txstatus {
+ BRCMF_FWS_TXSTATUS_DISCARD,
+ BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
+ BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
+ BRCMF_FWS_TXSTATUS_FW_TOSSED
+};
+
+enum brcmf_fws_fcmode {
+ BRCMF_FWS_FCMODE_NONE,
+ BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
+ BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
+};
+
+enum brcmf_fws_mac_desc_state {
+ BRCMF_FWS_STATE_OPEN = 1,
+ BRCMF_FWS_STATE_CLOSE
+};
+
+/**
+ * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
+ *
+ * @occupied: slot is in use.
+ * @mac_handle: handle for mac entry determined by firmware.
+ * @interface_id: interface index.
+ * @state: current state.
+ * @suppressed: mac entry is suppressed.
+ * @generation: generation bit.
+ * @ac_bitmap: ac queue bitmap.
+ * @requested_credit: credits requested by firmware.
+ * @ea: ethernet address.
+ * @seq: per-node free-running sequence.
+ * @psq: power-save queue.
+ * @transit_count: packet in transit to firmware.
+ */
+struct brcmf_fws_mac_descriptor {
+ u8 occupied;
+ u8 mac_handle;
+ u8 interface_id;
+ u8 state;
+ bool suppressed;
+ u8 generation;
+ u8 ac_bitmap;
+ u8 requested_credit;
+ u8 requested_packet;
+ u8 ea[ETH_ALEN];
+ u8 seq[BRCMF_FWS_FIFO_COUNT];
+ struct pktq psq;
+ int transit_count;
+ int suppress_count;
+ int suppr_transit_count;
+ bool send_tim_signal;
+ u8 traffic_pending_bmp;
+ u8 traffic_lastreported_bmp;
+};
+
+#define BRCMF_FWS_HANGER_MAXITEMS 1024
+
+/**
+ * enum brcmf_fws_hanger_item_state - state of hanger item.
+ *
+ * @BRCMF_FWS_HANGER_ITEM_STATE_FREE: item is free for use.
+ * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE: item is in use.
+ * @BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
+ */
+enum brcmf_fws_hanger_item_state {
+ BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
+ BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
+ BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
+};
+
+
+/**
+ * struct brcmf_fws_hanger_item - single entry for tx pending packet.
+ *
+ * @state: entry is either free or occupied.
+ * @gen: generation.
+ * @pkt: packet itself.
+ */
+struct brcmf_fws_hanger_item {
+ enum brcmf_fws_hanger_item_state state;
+ u8 gen;
+ struct sk_buff *pkt;
+};
+
+/**
+ * struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
+ *
+ * @pushed: packets pushed to await txstatus.
+ * @popped: packets popped upon handling txstatus.
+ * @failed_to_push: packets that could not be pushed.
+ * @failed_to_pop: packets that could not be popped.
+ * @failed_slotfind: packets for which failed to find an entry.
+ * @slot_pos: last returned item index for a free entry.
+ * @items: array of hanger items.
+ */
+struct brcmf_fws_hanger {
+ u32 pushed;
+ u32 popped;
+ u32 failed_to_push;
+ u32 failed_to_pop;
+ u32 failed_slotfind;
+ u32 slot_pos;
+ struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
+};
+
+struct brcmf_fws_macdesc_table {
+ struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
+ struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
+ struct brcmf_fws_mac_descriptor other;
+};
+
+struct brcmf_fws_info {
+ struct brcmf_pub *drvr;
+ struct brcmf_fws_stats stats;
+ struct brcmf_fws_hanger hanger;
+ enum brcmf_fws_fcmode fcmode;
+ struct brcmf_fws_macdesc_table desc;
+ struct workqueue_struct *fws_wq;
+ struct work_struct fws_dequeue_work;
+ u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
+ int fifo_credit[BRCMF_FWS_FIFO_COUNT];
+ int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
+ int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
+ u32 fifo_credit_map;
+ u32 fifo_delay_map;
+ unsigned long borrow_defer_timestamp;
+};
+
+/*
+ * brcmf_fws_prio2fifo - mapping from 802.1d priority to firmware fifo index.
+ */
+static const int brcmf_fws_prio2fifo[] = {
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BK,
+ BRCMF_FWS_FIFO_AC_BE,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VI,
+ BRCMF_FWS_FIFO_AC_VO,
+ BRCMF_FWS_FIFO_AC_VO
+};
+
+static int fcmode;
+module_param(fcmode, int, S_IRUSR);
+MODULE_PARM_DESC(fcmode, "mode of firmware signalled flow control");
+
+#define BRCMF_FWS_TLV_DEF(name, id, len) \
+ case BRCMF_FWS_TYPE_ ## name: \
+ return len;
+
+/**
+ * brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
+ *
+ * @fws: firmware-signalling information.
+ * @id: identifier of the TLV.
+ *
+ * Return: the specified length for the given TLV; Otherwise -EINVAL.
+ */
+static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
+ enum brcmf_fws_tlv_type id)
+{
+ switch (id) {
+ BRCMF_FWS_TLV_DEFLIST
+ default:
+ fws->stats.tlv_invalid_type++;
+ break;
+ }
+ return -EINVAL;
+}
+#undef BRCMF_FWS_TLV_DEF
+
+static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
+{
+ u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
+ return ifidx == *(int *)arg;
+}
+
+static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
+ int ifidx)
+{
+ bool (*matchfn)(struct sk_buff *, void *) = NULL;
+ struct sk_buff *skb;
+ int prec;
+
+ if (ifidx != -1)
+ matchfn = brcmf_fws_ifidx_match;
+ for (prec = 0; prec < q->num_prec; prec++) {
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+ while (skb) {
+ brcmu_pkt_buf_free_skb(skb);
+ skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
+ }
+ }
+}
+
+static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
+{
+ int i;
+
+ brcmf_dbg(TRACE, "enter\n");
+ memset(hanger, 0, sizeof(*hanger));
+ for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
+ hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+}
+
+static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
+{
+ u32 i;
+
+ brcmf_dbg(TRACE, "enter\n");
+ i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
+
+ while (i != h->slot_pos) {
+ if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ h->slot_pos = i;
+ goto done;
+ }
+ i++;
+ if (i == BRCMF_FWS_HANGER_MAXITEMS)
+ i = 0;
+ }
+ brcmf_err("all slots occupied\n");
+ h->failed_slotfind++;
+ i = BRCMF_FWS_HANGER_MAXITEMS;
+done:
+ brcmf_dbg(TRACE, "exit: %d\n", i);
+ return i;
+}
+
+static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
+ struct sk_buff *pkt, u32 slot_id)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("slot is not free\n");
+ h->failed_to_push++;
+ return -EINVAL;
+ }
+
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
+ h->items[slot_id].pkt = pkt;
+ h->pushed++;
+ return 0;
+}
+
+static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
+ u32 slot_id, struct sk_buff **pktout,
+ bool remove_item)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("entry not in use\n");
+ h->failed_to_pop++;
+ return -EINVAL;
+ }
+
+ *pktout = h->items[slot_id].pkt;
+ if (remove_item) {
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ h->items[slot_id].pkt = NULL;
+ h->items[slot_id].gen = 0xff;
+ h->popped++;
+ }
+ return 0;
+}
+
+static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
+ u32 slot_id, u8 gen)
+{
+ brcmf_dbg(TRACE, "enter\n");
+
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ h->items[slot_id].gen = gen;
+
+ if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_INUSE) {
+ brcmf_err("entry not in use\n");
+ return -EINVAL;
+ }
+
+ h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
+ return 0;
+}
+
+static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
+ struct sk_buff *pkt, u32 slot_id,
+ int *gen)
+{
+ brcmf_dbg(TRACE, "enter\n");
+ *gen = 0xff;
+
+ if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
+ return -ENOENT;
+
+ if (hanger->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
+ brcmf_err("slot not in use\n");
+ return -EINVAL;
+ }
+
+ *gen = hanger->items[slot_id].gen;
+ return 0;
+}
+
+static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
+ bool (*fn)(struct sk_buff *, void *),
+ int ifidx)
+{
+ struct brcmf_fws_hanger *h = &fws->hanger;
+ struct sk_buff *skb;
+ int i;
+ enum brcmf_fws_hanger_item_state s;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ for (i = 0; i < ARRAY_SIZE(h->items); i++) {
+ s = h->items[i].state;
+ if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
+ s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
+ skb = h->items[i].pkt;
+ if (fn == NULL || fn(skb, &ifidx)) {
+ /* suppress packets freed from psq */
+ if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
+ brcmu_pkt_buf_free_skb(skb);
+ h->items[i].state =
+ BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ }
+ }
+ }
+}
+
+static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
+ u8 *addr, u8 ifidx)
+{
+ brcmf_dbg(TRACE,
+ "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
+ desc->occupied = 1;
+ desc->state = BRCMF_FWS_STATE_OPEN;
+ desc->requested_credit = 0;
+ /* depending on use may need ifp->bssidx instead */
+ desc->interface_id = ifidx;
+ desc->ac_bitmap = 0xff; /* update this when handling APSD */
+ if (addr)
+ memcpy(&desc->ea[0], addr, ETH_ALEN);
+}
+
+static
+void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc)
+{
+ brcmf_dbg(TRACE,
+ "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
+ desc->occupied = 0;
+ desc->state = BRCMF_FWS_STATE_CLOSE;
+ desc->requested_credit = 0;
+}
+
+static struct brcmf_fws_mac_descriptor *
+brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ int i;
+
+ brcmf_dbg(TRACE, "enter: ea=%pM\n", ea);
+ if (ea == NULL)
+ return ERR_PTR(-EINVAL);
+
+ entry = &fws->desc.nodes[0];
+ for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
+ if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
+ return entry;
+ entry++;
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+static struct brcmf_fws_mac_descriptor*
+brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, struct brcmf_if *ifp,
+ u8 *da)
+{
+ struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
+ bool multicast;
+ enum nl80211_iftype iftype;
+
+ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
+
+ multicast = is_multicast_ether_addr(da);
+ iftype = brcmf_cfg80211_get_iftype(ifp);
+
+ /* Multicast destination and P2P clients get the interface entry.
+ * STA gets the interface entry if there is no exact match. For
+ * example, TDLS destinations have their own entry.
+ */
+ entry = NULL;
+ if ((multicast || iftype == NL80211_IFTYPE_STATION ||
+ iftype == NL80211_IFTYPE_P2P_CLIENT) && ifp->fws_desc)
+ entry = ifp->fws_desc;
+
+ if (entry != NULL && iftype != NL80211_IFTYPE_STATION)
+ goto done;
+
+ entry = brcmf_fws_mac_descriptor_lookup(fws, da);
+ if (IS_ERR(entry))
+ entry = &fws->desc.other;
+
+done:
+ brcmf_dbg(TRACE, "exit: entry=%p\n", entry);
+ return entry;
+}
+
+static bool brcmf_fws_mac_desc_closed(struct brcmf_fws_info *fws,
+ struct brcmf_fws_mac_descriptor *entry,
+ int fifo)
+{
+ struct brcmf_fws_mac_descriptor *if_entry;
+ bool closed;
+
+ /* for unique destination entries the related interface
+ * may be closed.
+ */
+ if (entry->mac_handle) {
+ if_entry = &fws->desc.iface[entry->interface_id];
+ if (if_entry->state == BRCMF_FWS_STATE_CLOSE)
+ return true;
+ }
+ /* an entry is closed when the state is closed and
+ * the firmware did not request anything.
+ */
+ closed = entry->state == BRCMF_FWS_STATE_CLOSE &&
+ !entry->requested_credit && !entry->requested_packet;
+
+ /* Or firmware does not allow traffic for given fifo */
+ return closed || !(entry->ac_bitmap & BIT(fifo));
+}
+
+static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws,
+ struct brcmf_fws_mac_descriptor *entry,
+ int ifidx)
+{
+ brcmf_dbg(TRACE, "enter: entry=(ea=%pM, ifid=%d), ifidx=%d\n",
+ entry->ea, entry->interface_id, ifidx);
+ if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
+ brcmf_dbg(TRACE, "flush psq: ifidx=%d, qlen=%d\n",
+ ifidx, entry->psq.len);
+ brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
+ entry->occupied = !!(entry->psq.len);
+ }
+}
+
+static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
+ bool (*fn)(struct sk_buff *, void *),
+ int ifidx)
+{
+ struct brcmf_fws_hanger_item *hi;
+ struct pktq *txq;
+ struct sk_buff *skb;
+ int prec;
+ u32 hslot;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ txq = brcmf_bus_gettxq(fws->drvr->bus_if);
+ if (IS_ERR(txq)) {
+ brcmf_dbg(TRACE, "no txq to clean up\n");
+ return;
+ }
+
+ for (prec = 0; prec < txq->num_prec; prec++) {
+ skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
+ while (skb) {
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+ hi = &fws->hanger.items[hslot];
+ WARN_ON(skb != hi->pkt);
+ hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
+ brcmu_pkt_buf_free_skb(skb);
+ skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
+ }
+ }
+}
+
+static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
+{
+ int i;
+ struct brcmf_fws_mac_descriptor *table;
+ bool (*matchfn)(struct sk_buff *, void *) = NULL;
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ if (fws == NULL)
+ return;
+
+ if (ifidx != -1)
+ matchfn = brcmf_fws_ifidx_match;
+
+ /* cleanup individual nodes */
+ table = &fws->desc.nodes[0];
+ for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
+ brcmf_fws_mac_desc_cleanup(fws, &table[i], ifidx);
+
+ brcmf_fws_mac_desc_cleanup(fws, &fws->desc.other, ifidx);
+ brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
+ brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
+}
+
+static void brcmf_fws_tim_update(struct brcmf_fws_info *ctx,
+ struct brcmf_fws_mac_descriptor *entry,
+ int prec)
+{
+ brcmf_dbg(TRACE, "enter: ea=%pM\n", entry->ea);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE) {
+ /* check delayedQ and suppressQ in one call using bitmap */
+ if (brcmu_pktq_mlen(&entry->psq, 3 << (prec * 2)) == 0)
+ entry->traffic_pending_bmp =
+ entry->traffic_pending_bmp & ~NBITVAL(prec);
+ else
+ entry->traffic_pending_bmp =
+ entry->traffic_pending_bmp | NBITVAL(prec);
+ }
+ /* request a TIM update to firmware at the next piggyback opportunity */
+ if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
+ entry->send_tim_signal = true;
+}
+
+static void
+brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
+ u8 if_id)
+{
+ struct brcmf_if *ifp = fws->drvr->iflist[if_id];
+
+ if (WARN_ON(!ifp))
+ return;
+
+ brcmf_dbg(TRACE,
+ "enter: bssidx=%d, ifidx=%d\n", ifp->bssidx, ifp->ifidx);
+
+ if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
+ pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
+ brcmf_txflowblock_if(ifp,
+ BRCMF_NETIF_STOP_REASON_FWS_FC, false);
+ if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
+ pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER)
+ brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
+ return;
+}
+
+static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
+{
+ brcmf_dbg(CTL, "rssi %d\n", rssi);
+ return 0;
+}
+
+static
+int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry, *existing;
+ u8 mac_handle;
+ u8 ifidx;
+ u8 *addr;
+
+ mac_handle = *data++;
+ ifidx = *data++;
+ addr = data;
+
+ entry = &fws->desc.nodes[mac_handle & 0x1F];
+ if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
+ brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
+ if (entry->occupied) {
+ brcmf_fws_mac_desc_cleanup(fws, entry, -1);
+ brcmf_fws_clear_mac_descriptor(entry);
+ } else
+ fws->stats.mac_update_failed++;
+ return 0;
+ }
+
+ brcmf_dbg(TRACE,
+ "add mac %pM handle %u idx %d\n", addr, mac_handle, ifidx);
+ existing = brcmf_fws_mac_descriptor_lookup(fws, addr);
+ if (IS_ERR(existing)) {
+ if (!entry->occupied) {
+ entry->mac_handle = mac_handle;
+ brcmf_fws_init_mac_descriptor(entry, addr, ifidx);
+ brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+ } else {
+ fws->stats.mac_update_failed++;
+ }
+ } else {
+ if (entry != existing) {
+ brcmf_dbg(TRACE, "relocate mac\n");
+ memcpy(entry, existing,
+ offsetof(struct brcmf_fws_mac_descriptor, psq));
+ entry->mac_handle = mac_handle;
+ brcmf_fws_clear_mac_descriptor(existing);
+ } else {
+ brcmf_dbg(TRACE, "use existing\n");
+ WARN_ON(entry->mac_handle != mac_handle);
+ /* TODO: what should we do here: continue, reinit, .. */
+ }
+ }
+ return 0;
+}
+
+static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 mac_handle;
+ int i;
+
+ mac_handle = data[0];
+ entry = &fws->desc.nodes[mac_handle & 0x1F];
+ if (!entry->occupied) {
+ fws->stats.mac_ps_update_failed++;
+ return -ESRCH;
+ }
+
+ /* a state update should wipe old credits? */
+ entry->requested_credit = 0;
+ if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ return BRCMF_FWS_RET_OK_SCHEDULE;
+ } else {
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ for (i = BRCMF_FWS_FIFO_AC_BE; i < NL80211_NUM_ACS; i++)
+ brcmf_fws_tim_update(fws, entry, i);
+ }
+ return BRCMF_FWS_RET_OK_NOSCHEDULE;
+}
+
+static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
+ u8 type, u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+ u8 ifidx;
+ int ret;
+
+ ifidx = data[0];
+
+ brcmf_dbg(TRACE, "enter: ifidx=%d\n", ifidx);
+ if (ifidx >= BRCMF_MAX_IFS) {
+ ret = -ERANGE;
+ goto fail;
+ }
+
+ entry = &fws->desc.iface[ifidx];
+ if (!entry->occupied) {
+ ret = -ESRCH;
+ goto fail;
+ }
+
+ switch (type) {
+ case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+ entry->state = BRCMF_FWS_STATE_OPEN;
+ return BRCMF_FWS_RET_OK_SCHEDULE;
+ case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+ entry->state = BRCMF_FWS_STATE_CLOSE;
+ return BRCMF_FWS_RET_OK_NOSCHEDULE;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+fail:
+ fws->stats.if_update_failed++;
+ return ret;
+}
+
+static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
+ u8 *data)
+{
+ struct brcmf_fws_mac_descriptor *entry;
+
+ entry = &fws->desc.nodes[data[1] & 0x1F];
+ if (!entry->occupied) {
+ if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
+ fws->stats.credit_request_failed++;
+ else
+ fws->stats.packet_request_failed++;
+ return -ESRCH;
+ }
+
+ if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
+ entry->requested_credit = data[0];
+ else
+ entry->requested_packet = data[0];
+
+ entry->ac_bitmap = data[2];
+ return BRCMF_FWS_RET_OK_SCHEDULE;
+}
+
+static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
+ u8 fifo, u8 credits)
+{
+ int lender_ac;
+ int *borrowed;
+ int *fifo_credit;
+
+ if (!credits)
+ return;
+
+ if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
+ (fws->credits_borrowed[0])) {
+ for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
+ lender_ac--) {
+ borrowed = &fws->credits_borrowed[lender_ac];
+ if (*borrowed) {
+ fws->fifo_credit_map |= (1 << lender_ac);
+ fifo_credit = &fws->fifo_credit[lender_ac];
+ if (*borrowed >= credits) {
+ *borrowed -= credits;
+ *fifo_credit += credits;
+ return;
+ } else {
+ credits -= *borrowed;
+ *fifo_credit += *borrowed;
+ *borrowed = 0;
+ }
+ }
+ }
+ }
+
+ fws->fifo_credit_map |= 1 << fifo;
+ fws->fifo_credit[fifo] += credits;
+}
+
+static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
+{
+ /* only schedule dequeue when there are credits for delayed traffic */
+ if (fws->fifo_credit_map & fws->fifo_delay_map)
+ queue_work(fws->fws_wq, &fws->fws_dequeue_work);
+}
+
+static void brcmf_skb_pick_up_credit(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *p)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(p)->mac;
+
+ if (brcmf_skbcb(p)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ if (fws->fcmode != BRCMF_FWS_FCMODE_IMPLIED_CREDIT)
+ return;
+ brcmf_fws_return_credits(fws, fifo, 1);
+ } else {
+ /*
+ * if this packet did not count against FIFO credit, it
+ * must have taken a requested_credit from the destination
+ * entry (for pspoll etc.)
+ */
+ if (!brcmf_skb_if_flags_get_field(p, REQUESTED))
+ entry->requested_credit++;
+ }
+ brcmf_fws_schedule_deq(fws);
+}
+
+static int brcmf_fws_enq(struct brcmf_fws_info *fws,
+ enum brcmf_fws_skb_state state, int fifo,
+ struct sk_buff *p)
+{
+ int prec = 2 * fifo;
+ u32 *qfull_stat = &fws->stats.delayq_full_error;
+
+ struct brcmf_fws_mac_descriptor *entry;
+
+ entry = brcmf_skbcb(p)->mac;
+ if (entry == NULL) {
+ brcmf_err("no mac descriptor found for skb %p\n", p);
+ return -ENOENT;
+ }
+
+ brcmf_dbg(TRACE, "enter: ea=%pM, qlen=%d\n", entry->ea, entry->psq.len);
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
+ prec += 1;
+ qfull_stat = &fws->stats.supprq_full_error;
+ }
+
+ if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
+ *qfull_stat += 1;
+ return -ENFILE;
+ }
+
+ /* increment total enqueued packet count */
+ fws->fifo_delay_map |= 1 << fifo;
+ fws->fifo_enqpkt[fifo]++;
+
+ /* update the sk_buff state */
+ brcmf_skbcb(p)->state = state;
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
+ entry->suppress_count++;
+
+ /*
+ * A packet has been pushed so update traffic
+ * availability bitmap, if applicable
+ */
+ brcmf_fws_tim_update(fws, entry, fifo);
+ brcmf_fws_flow_control_check(fws, &entry->psq,
+ brcmf_skb_if_flags_get_field(p, INDEX));
+ return 0;
+}
+
+static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
+{
+ struct brcmf_fws_mac_descriptor *table;
+ struct brcmf_fws_mac_descriptor *entry;
+ struct sk_buff *p;
+ int use_credit = 1;
+ int num_nodes;
+ int node_pos;
+ int prec_out;
+ int pmsk;
+ int i;
+
+ table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
+ num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
+ node_pos = fws->deq_node_pos[fifo];
+
+ for (i = 0; i < num_nodes; i++) {
+ entry = &table[(node_pos + i) % num_nodes];
+ if (!entry->occupied ||
+ brcmf_fws_mac_desc_closed(fws, entry, fifo))
+ continue;
+
+ if (entry->suppressed)
+ pmsk = 2;
+ else
+ pmsk = 3;
+ p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
+ if (p == NULL) {
+ if (entry->suppressed) {
+ if (entry->suppr_transit_count >
+ entry->suppress_count)
+ return NULL;
+ entry->suppressed = false;
+ p = brcmu_pktq_mdeq(&entry->psq,
+ 1 << (fifo * 2), &prec_out);
+ }
+ }
+ if (p == NULL)
+ continue;
+
+ /* did the packet come from suppress sub-queue? */
+ if (entry->requested_credit > 0) {
+ entry->requested_credit--;
+ /*
+ * if the packet was pulled out while destination is in
+ * closed state but had a non-zero packets requested,
+ * then this should not count against the FIFO credit.
+ * That is due to the fact that the firmware will
+ * most likely hold onto this packet until a suitable
+ * time later to push it to the appropriate AC FIFO.
+ */
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ } else if (entry->requested_packet > 0) {
+ entry->requested_packet--;
+ brcmf_skb_if_flags_set_field(p, REQUESTED, 1);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ }
+ brcmf_skb_if_flags_set_field(p, CREDITCHECK, use_credit);
+
+ /* move dequeue position to ensure fair round-robin */
+ fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
+ brcmf_fws_flow_control_check(fws, &entry->psq,
+ brcmf_skb_if_flags_get_field(p,
+ INDEX)
+ );
+ /*
+ * A packet has been picked up, update traffic
+ * availability bitmap, if applicable
+ */
+ brcmf_fws_tim_update(fws, entry, fifo);
+
+ /*
+ * decrement total enqueued fifo packets and
+ * clear delay bitmap if done.
+ */
+ fws->fifo_enqpkt[fifo]--;
+ if (fws->fifo_enqpkt[fifo] == 0)
+ fws->fifo_delay_map &= ~(1 << fifo);
+ goto done;
+ }
+ p = NULL;
+done:
+ brcmf_dbg(TRACE, "exit: fifo %d skb %p\n", fifo, p);
+ return p;
+}
+
+static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb, u32 genbit)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ u32 hslot;
+ int ret;
+
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+
+ /* this packet was suppressed */
+ if (!entry->suppressed || entry->generation != genbit) {
+ entry->suppressed = true;
+ entry->suppress_count = brcmu_pktq_mlen(&entry->psq,
+ 1 << (fifo * 2 + 1));
+ entry->suppr_transit_count = entry->transit_count;
+ }
+
+ entry->generation = genbit;
+
+ ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
+ if (ret != 0) {
+ /* suppress q is full, drop this packet */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
+ true);
+ } else {
+ /*
+ * Mark suppressed to avoid a double free during
+ * wlfc cleanup
+ */
+ brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot,
+ genbit);
+ entry->suppress_count++;
+ }
+
+ return ret;
+}
+
+static int
+brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
+ u32 genbit)
+{
+ u32 fifo;
+ int ret;
+ bool remove_from_hanger = true;
+ struct sk_buff *skb;
+ struct brcmf_fws_mac_descriptor *entry = NULL;
+
+ brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
+ flags, hslot);
+
+ if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
+ fws->stats.txs_discard++;
+ else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
+ fws->stats.txs_supp_core++;
+ remove_from_hanger = false;
+ } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
+ fws->stats.txs_supp_ps++;
+ remove_from_hanger = false;
+ } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
+ fws->stats.txs_tossed++;
+ else
+ brcmf_err("unexpected txstatus\n");
+
+ ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
+ remove_from_hanger);
+ if (ret != 0) {
+ brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
+ return ret;
+ }
+
+ entry = brcmf_skbcb(skb)->mac;
+ if (WARN_ON(!entry)) {
+ brcmu_pkt_buf_free_skb(skb);
+ return -EINVAL;
+ }
+
+ /* pick up the implicit credit from this packet */
+ fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
+ brcmf_skb_pick_up_credit(fws, fifo, skb);
+
+ if (!remove_from_hanger)
+ ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
+
+ if (remove_from_hanger || ret) {
+ entry->transit_count--;
+ if (entry->suppressed)
+ entry->suppr_transit_count--;
+
+ brcmf_txfinalize(fws->drvr, skb, true);
+ }
+ return 0;
+}
+
+static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
+ u8 *data)
+{
+ int i;
+
+ if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
+ brcmf_dbg(INFO, "ignored\n");
+ return BRCMF_FWS_RET_OK_NOSCHEDULE;
+ }
+
+ brcmf_dbg(TRACE, "enter: data %pM\n", data);
+ for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
+ brcmf_fws_return_credits(fws, i, data[i]);
+
+ brcmf_dbg(INFO, "map: credit %x delay %x\n", fws->fifo_credit_map,
+ fws->fifo_delay_map);
+ return BRCMF_FWS_RET_OK_SCHEDULE;
+}
+
+static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
+{
+ __le32 status_le;
+ u32 status;
+ u32 hslot;
+ u32 genbit;
+ u8 flags;
+
+ fws->stats.txs_indicate++;
+ memcpy(&status_le, data, sizeof(status_le));
+ status = le32_to_cpu(status_le);
+ flags = brcmf_txstatus_get_field(status, FLAGS);
+ hslot = brcmf_txstatus_get_field(status, HSLOT);
+ genbit = brcmf_txstatus_get_field(status, GENERATION);
+
+ return brcmf_fws_txstatus_process(fws, flags, hslot, genbit);
+}
+
+static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
+{
+ __le32 timestamp;
+
+ memcpy(&timestamp, &data[2], sizeof(timestamp));
+ brcmf_dbg(INFO, "received: seq %d, timestamp %d\n", data[1],
+ le32_to_cpu(timestamp));
+ return 0;
+}
+
+/* using macro so sparse checking does not complain
+ * about locking imbalance.
+ */
+#define brcmf_fws_lock(drvr, flags) \
+do { \
+ flags = 0; \
+ spin_lock_irqsave(&((drvr)->fws_spinlock), (flags)); \
+} while (0)
+
+/* using macro so sparse checking does not complain
+ * about locking imbalance.
+ */
+#define brcmf_fws_unlock(drvr, flags) \
+ spin_unlock_irqrestore(&((drvr)->fws_spinlock), (flags))
+
+static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *e,
+ void *data)
+{
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
+ int i;
+ ulong flags;
+ u8 *credits = data;
+
+ if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
+ brcmf_err("event payload too small (%d)\n", e->datalen);
+ return -EINVAL;
+ }
+
+ brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
+ brcmf_fws_lock(ifp->drvr, flags);
+ for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
+ if (*credits)
+ fws->fifo_credit_map |= 1 << i;
+ else
+ fws->fifo_credit_map &= ~(1 << i);
+ fws->fifo_credit[i] = *credits++;
+ }
+ brcmf_fws_schedule_deq(fws);
+ brcmf_fws_unlock(ifp->drvr, flags);
+ return 0;
+}
+
+int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+ struct sk_buff *skb)
+{
+ struct brcmf_fws_info *fws = drvr->fws;
+ ulong flags;
+ u8 *signal_data;
+ s16 data_len;
+ u8 type;
+ u8 len;
+ u8 *data;
+ s32 status;
+ s32 err;
+
+ brcmf_dbg(TRACE, "enter: ifidx %d, skblen %u, sig %d\n",
+ ifidx, skb->len, signal_len);
+
+ WARN_ON(signal_len > skb->len);
+
+ /* if flow control disabled, skip to packet data and leave */
+ if (!signal_len || !drvr->fw_signals) {
+ skb_pull(skb, signal_len);
+ return 0;
+ }
+
+ /* lock during tlv parsing */
+ brcmf_fws_lock(drvr, flags);
+
+ fws->stats.header_pulls++;
+ data_len = signal_len;
+ signal_data = skb->data;
+
+ status = BRCMF_FWS_RET_OK_NOSCHEDULE;
+ while (data_len > 0) {
+ /* extract tlv info */
+ type = signal_data[0];
+
+ /* FILLER type is actually not a TLV, but
+ * a single byte that can be skipped.
+ */
+ if (type == BRCMF_FWS_TYPE_FILLER) {
+ signal_data += 1;
+ data_len -= 1;
+ continue;
+ }
+ len = signal_data[1];
+ data = signal_data + 2;
+
+ brcmf_dbg(INFO, "tlv type=%d (%s), len=%d, data[0]=%d\n", type,
+ brcmf_fws_get_tlv_name(type), len, *data);
+
+ /* abort parsing when length invalid */
+ if (data_len < len + 2)
+ break;
+
+ if (len != brcmf_fws_get_tlv_len(fws, type))
+ break;
+
+ err = BRCMF_FWS_RET_OK_NOSCHEDULE;
+ switch (type) {
+ case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
+ case BRCMF_FWS_TYPE_COMP_TXSTATUS:
+ break;
+ case BRCMF_FWS_TYPE_MACDESC_ADD:
+ case BRCMF_FWS_TYPE_MACDESC_DEL:
+ brcmf_fws_macdesc_indicate(fws, type, data);
+ break;
+ case BRCMF_FWS_TYPE_MAC_OPEN:
+ case BRCMF_FWS_TYPE_MAC_CLOSE:
+ err = brcmf_fws_macdesc_state_indicate(fws, type, data);
+ break;
+ case BRCMF_FWS_TYPE_INTERFACE_OPEN:
+ case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
+ err = brcmf_fws_interface_state_indicate(fws, type,
+ data);
+ break;
+ case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
+ case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
+ err = brcmf_fws_request_indicate(fws, type, data);
+ break;
+ case BRCMF_FWS_TYPE_TXSTATUS:
+ brcmf_fws_txstatus_indicate(fws, data);
+ break;
+ case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
+ err = brcmf_fws_fifocreditback_indicate(fws, data);
+ break;
+ case BRCMF_FWS_TYPE_RSSI:
+ brcmf_fws_rssi_indicate(fws, *data);
+ break;
+ case BRCMF_FWS_TYPE_TRANS_ID:
+ brcmf_fws_dbg_seqnum_check(fws, data);
+ break;
+ case BRCMF_FWS_TYPE_PKTTAG:
+ case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
+ default:
+ fws->stats.tlv_invalid_type++;
+ break;
+ }
+ if (err == BRCMF_FWS_RET_OK_SCHEDULE)
+ status = BRCMF_FWS_RET_OK_SCHEDULE;
+ signal_data += len + 2;
+ data_len -= len + 2;
+ }
+
+ if (data_len != 0)
+ fws->stats.tlv_parse_failed++;
+
+ if (status == BRCMF_FWS_RET_OK_SCHEDULE)
+ brcmf_fws_schedule_deq(fws);
+
+ /* signalling processing result does
+ * not affect the actual ethernet packet.
+ */
+ skb_pull(skb, signal_len);
+
+ /* this may be a signal-only packet
+ */
+ if (skb->len == 0)
+ fws->stats.header_only_pkt++;
+
+ brcmf_fws_unlock(drvr, flags);
+ return 0;
+}
+
+static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ u8 *wlh;
+ u16 data_offset = 0;
+ u8 fillers;
+ __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
+
+ brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n",
+ entry->ea, entry->interface_id, le32_to_cpu(pkttag));
+ if (entry->send_tim_signal)
+ data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+
+ /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
+ data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
+ fillers = round_up(data_offset, 4) - data_offset;
+ data_offset += fillers;
+
+ skb_push(skb, data_offset);
+ wlh = skb->data;
+
+ wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
+ wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
+ memcpy(&wlh[2], &pkttag, sizeof(pkttag));
+ wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
+
+ if (entry->send_tim_signal) {
+ entry->send_tim_signal = 0;
+ wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
+ wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
+ wlh[2] = entry->mac_handle;
+ wlh[3] = entry->traffic_pending_bmp;
+ wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
+ entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
+ }
+ if (fillers)
+ memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
+
+ brcmf_proto_hdrpush(fws->drvr, brcmf_skb_if_flags_get_field(skb, INDEX),
+ data_offset >> 2, skb);
+ return 0;
+}
+
+static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *p)
+{
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
+ struct brcmf_fws_mac_descriptor *entry = skcb->mac;
+ int rc = 0;
+ bool header_needed;
+ int hslot = BRCMF_FWS_HANGER_MAXITEMS;
+ u8 free_ctr;
+ u8 ifidx;
+ u8 flags;
+
+ header_needed = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
+
+ if (header_needed) {
+ /* obtaining free slot may fail, but that will be caught
+ * by the hanger push. This assures the packet has a BDC
+ * header upon return.
+ */
+ hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
+ free_ctr = entry->seq[fifo];
+ brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
+ brcmf_skb_htod_tag_set_field(p, FREERUN, free_ctr);
+ brcmf_skb_htod_tag_set_field(p, GENERATION, 1);
+ entry->transit_count++;
+ }
+ brcmf_skb_if_flags_set_field(p, TRANSMIT, 1);
+ brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
+
+ flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
+ if (!(skcb->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)) {
+ /*
+ Indicate that this packet is being sent in response to an
+ explicit request from the firmware side.
+ */
+ flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
+ }
+ brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
+ if (header_needed) {
+ brcmf_fws_hdrpush(fws, p);
+ rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
+ if (rc)
+ brcmf_err("hanger push failed: rc=%d\n", rc);
+ } else {
+ int gen;
+
+ /* remove old header */
+ rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, p);
+ if (rc == 0) {
+ hslot = brcmf_skb_htod_tag_get_field(p, HSLOT);
+ brcmf_fws_hanger_get_genbit(&fws->hanger, p,
+ hslot, &gen);
+ brcmf_skb_htod_tag_set_field(p, GENERATION, gen);
+
+ /* push new header */
+ brcmf_fws_hdrpush(fws, p);
+ }
+ }
+
+ return rc;
+}
+
+static void
+brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ /*
+ put the packet back to the head of queue
+
+ - suppressed packet goes back to suppress sub-queue
+ - pull out the header, if new or delayed packet
+
+ Note: hslot is used only when header removal is done.
+ */
+ struct brcmf_fws_mac_descriptor *entry;
+ enum brcmf_fws_skb_state state;
+ struct sk_buff *pktout;
+ int rc = 0;
+ int fifo;
+ int hslot;
+ u8 ifidx;
+
+ fifo = brcmf_skb_if_flags_get_field(skb, FIFO);
+ state = brcmf_skbcb(skb)->state;
+ entry = brcmf_skbcb(skb)->mac;
+
+ if (entry != NULL) {
+ if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
+ /* wl-header is saved for suppressed packets */
+ pktout = brcmu_pktq_penq_head(&entry->psq, 2 * fifo + 1,
+ skb);
+ if (pktout == NULL) {
+ brcmf_err("suppress queue full\n");
+ rc = -ENOSPC;
+ }
+ } else {
+ hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
+
+ /* remove header first */
+ rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
+ if (rc) {
+ brcmf_err("header removal failed\n");
+ /* free the hanger slot */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
+ &pktout, true);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ /* delay-q packets are going to delay-q */
+ pktout = brcmu_pktq_penq_head(&entry->psq,
+ 2 * fifo, skb);
+ if (pktout == NULL) {
+ brcmf_err("delay queue full\n");
+ rc = -ENOSPC;
+ }
+
+ /* free the hanger slot */
+ brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &pktout,
+ true);
+
+ /* decrement sequence count */
+ entry->seq[fifo]--;
+ }
+ /*
+ if this packet did not count against FIFO credit, it must have
+ taken a requested_credit from the firmware (for pspoll etc.)
+ */
+ if (!(brcmf_skbcb(skb)->if_flags &
+ BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
+ entry->requested_credit++;
+ } else {
+ brcmf_err("no mac entry linked\n");
+ rc = -ENOENT;
+ }
+
+
+fail:
+ if (rc) {
+ brcmf_txfinalize(fws->drvr, skb, false);
+ fws->stats.rollback_failed++;
+ } else
+ fws->stats.rollback_success++;
+}
+
+static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
+{
+ int lender_ac;
+
+ if (time_after(fws->borrow_defer_timestamp, jiffies))
+ return -ENAVAIL;
+
+ for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
+ if (fws->fifo_credit[lender_ac]) {
+ fws->credits_borrowed[lender_ac]++;
+ fws->fifo_credit[lender_ac]--;
+ if (fws->fifo_credit[lender_ac] == 0)
+ fws->fifo_credit_map &= ~(1 << lender_ac);
+ brcmf_dbg(TRACE, "borrow credit from: %d\n", lender_ac);
+ return 0;
+ }
+ }
+ return -ENAVAIL;
+}
+
+static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb)
+{
+ struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
+ int *credit = &fws->fifo_credit[fifo];
+ int use_credit = 1;
+
+ brcmf_dbg(TRACE, "enter: ac=%d, credits=%d\n", fifo, *credit);
+
+ if (entry->requested_credit > 0) {
+ /*
+ * if the packet was pulled out while destination is in
+ * closed state but had a non-zero packets requested,
+ * then this should not count against the FIFO credit.
+ * That is due to the fact that the firmware will
+ * most likely hold onto this packet until a suitable
+ * time later to push it to the appropriate AC FIFO.
+ */
+ entry->requested_credit--;
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ } else if (entry->requested_packet > 0) {
+ entry->requested_packet--;
+ brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
+ if (entry->state == BRCMF_FWS_STATE_CLOSE)
+ use_credit = 0;
+ }
+ brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
+ if (!use_credit) {
+ brcmf_dbg(TRACE, "exit: no creditcheck set\n");
+ return 0;
+ }
+
+ if (fifo != BRCMF_FWS_FIFO_AC_BE)
+ fws->borrow_defer_timestamp = jiffies +
+ BRCMF_FWS_BORROW_DEFER_PERIOD;
+
+ if (!(*credit)) {
+ /* Try to borrow a credit from other queue */
+ if (fifo == BRCMF_FWS_FIFO_AC_BE &&
+ brcmf_fws_borrow_credit(fws) == 0)
+ return 0;
+
+ brcmf_dbg(TRACE, "exit: ac=%d, credits depleted\n", fifo);
+ return -ENAVAIL;
+ }
+ (*credit)--;
+ if (!(*credit))
+ fws->fifo_credit_map &= ~(1 << fifo);
+ brcmf_dbg(TRACE, "exit: ac=%d, credits=%d\n", fifo, *credit);
+ return 0;
+}
+
+static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
+ struct sk_buff *skb)
+{
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
+ struct brcmf_fws_mac_descriptor *entry;
+ struct brcmf_bus *bus = fws->drvr->bus_if;
+ int rc;
+
+ entry = skcb->mac;
+ if (IS_ERR(entry))
+ return PTR_ERR(entry);
+
+ rc = brcmf_fws_precommit_skb(fws, fifo, skb);
+ if (rc < 0) {
+ fws->stats.generic_error++;
+ goto rollback;
+ }
+
+ rc = brcmf_bus_txdata(bus, skb);
+ if (rc < 0)
+ goto rollback;
+
+ entry->seq[fifo]++;
+ fws->stats.pkt2bus++;
+ if (brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ fws->stats.send_pkts[fifo]++;
+ fws->stats.fifo_credits_sent[fifo]++;
+ }
+
+ return rc;
+
+rollback:
+ brcmf_fws_rollback_toq(fws, skb);
+ return rc;
+}
+
+int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct brcmf_fws_info *fws = drvr->fws;
+ struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
+ struct ethhdr *eh = (struct ethhdr *)(skb->data);
+ ulong flags;
+ int fifo = BRCMF_FWS_FIFO_BCMC;
+ bool multicast = is_multicast_ether_addr(eh->h_dest);
+
+ /* determine the priority */
+ if (!skb->priority)
+ skb->priority = cfg80211_classify8021d(skb);
+
+ drvr->tx_multicast += !!multicast;
+ if (ntohs(eh->h_proto) == ETH_P_PAE)
+ atomic_inc(&ifp->pend_8021x_cnt);
+
+ if (!brcmf_fws_fc_active(fws)) {
+ /* If the protocol uses a data header, apply it */
+ brcmf_proto_hdrpush(drvr, ifp->ifidx, 0, skb);
+
+ /* Use bus module to send data frame */
+ return brcmf_bus_txdata(drvr->bus_if, skb);
+ }
+
+ /* set control buffer information */
+ skcb->if_flags = 0;
+ skcb->mac = brcmf_fws_find_mac_desc(fws, ifp, eh->h_dest);
+ skcb->state = BRCMF_FWS_SKBSTATE_NEW;
+ brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
+ if (!multicast)
+ fifo = brcmf_fws_prio2fifo[skb->priority];
+ brcmf_skb_if_flags_set_field(skb, FIFO, fifo);
+
+ brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest,
+ multicast, fifo);
+
+ brcmf_fws_lock(drvr, flags);
+ if (skcb->mac->suppressed ||
+ brcmf_fws_mac_desc_closed(fws, skcb->mac, fifo) ||
+ brcmu_pktq_mlen(&skcb->mac->psq, 3 << (fifo * 2)) ||
+ (!multicast &&
+ brcmf_fws_consume_credit(fws, fifo, skb) < 0)) {
+ /* enqueue the packet in delayQ */
+ drvr->fws->fifo_delay_map |= 1 << fifo;
+ brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
+ } else {
+ if (brcmf_fws_commit_skb(fws, fifo, skb))
+ if (!multicast)
+ brcmf_skb_pick_up_credit(fws, fifo, skb);
+ }
+ brcmf_fws_unlock(drvr, flags);
+ return 0;
+}
+
+void brcmf_fws_reset_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+
+ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
+ if (!entry)
+ return;
+
+ brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
+}
+
+void brcmf_fws_add_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_info *fws = ifp->drvr->fws;
+ struct brcmf_fws_mac_descriptor *entry;
+
+ brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
+ ifp->bssidx, ifp->mac_addr);
+ if (!ifp->ndev || !ifp->drvr->fw_signals)
+ return;
+
+ entry = &fws->desc.iface[ifp->ifidx];
+ ifp->fws_desc = entry;
+ brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
+ brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+}
+
+void brcmf_fws_del_interface(struct brcmf_if *ifp)
+{
+ struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
+ ulong flags;
+
+ brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
+ if (!entry)
+ return;
+
+ brcmf_fws_lock(ifp->drvr, flags);
+ ifp->fws_desc = NULL;
+ brcmf_fws_clear_mac_descriptor(entry);
+ brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
+ brcmf_fws_unlock(ifp->drvr, flags);
+}
+
+static void brcmf_fws_dequeue_worker(struct work_struct *worker)
+{
+ struct brcmf_fws_info *fws;
+ struct sk_buff *skb;
+ ulong flags;
+ int fifo;
+ int credit;
+
+ fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
+
+ brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
+ brcmf_fws_lock(fws->drvr, flags);
+ for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) {
+ brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
+ fws->fifo_credit[fifo]);
+ for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
+ skb = brcmf_fws_deq(fws, fifo);
+ if (!skb || brcmf_fws_commit_skb(fws, fifo, skb))
+ break;
+ if (brcmf_skbcb(skb)->if_flags &
+ BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
+ credit++;
+ }
+ if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
+ (credit == fws->fifo_credit[fifo])) {
+ fws->fifo_credit[fifo] -= credit;
+ while (brcmf_fws_borrow_credit(fws) == 0) {
+ skb = brcmf_fws_deq(fws, fifo);
+ if (!skb) {
+ brcmf_fws_return_credits(fws, fifo, 1);
+ break;
+ }
+ if (brcmf_fws_commit_skb(fws, fifo, skb)) {
+ brcmf_fws_return_credits(fws, fifo, 1);
+ break;
+ }
+ }
+ } else {
+ fws->fifo_credit[fifo] -= credit;
+ }
+ }
+ brcmf_fws_unlock(fws->drvr, flags);
+}
+
+int brcmf_fws_init(struct brcmf_pub *drvr)
+{
+ u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
+ int rc;
+
+ if (!drvr->fw_signals)
+ return 0;
+
+ spin_lock_init(&drvr->fws_spinlock);
+
+ drvr->fws = kzalloc(sizeof(*(drvr->fws)), GFP_KERNEL);
+ if (!drvr->fws) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ /* set linkage back */
+ drvr->fws->drvr = drvr;
+ drvr->fws->fcmode = fcmode;
+
+ drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
+ if (drvr->fws->fws_wq == NULL) {
+ brcmf_err("workqueue creation failed\n");
+ rc = -EBADF;
+ goto fail;
+ }
+ INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
+
+ /* enable firmware signalling if fcmode active */
+ if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
+ tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
+ BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
+ BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE;
+
+ rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
+ brcmf_fws_notify_credit_map);
+ if (rc < 0) {
+ brcmf_err("register credit map handler failed\n");
+ goto fail;
+ }
+
+ /* setting the iovar may fail if feature is unsupported
+ * so leave the rc as is so driver initialization can
+ * continue.
+ */
+ if (brcmf_fil_iovar_int_set(drvr->iflist[0], "tlv", tlv)) {
+ brcmf_err("failed to set bdcv2 tlv signaling\n");
+ goto fail_event;
+ }
+
+ brcmf_fws_hanger_init(&drvr->fws->hanger);
+ brcmf_fws_init_mac_descriptor(&drvr->fws->desc.other, NULL, 0);
+ brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
+ BRCMF_FWS_PSQ_LEN);
+
+ /* create debugfs file for statistics */
+ brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
+
+ /* TODO: remove upon feature delivery */
+ brcmf_err("%s bdcv2 tlv signaling [%x]\n",
+ drvr->fw_signals ? "enabled" : "disabled", tlv);
+ return 0;
+
+fail_event:
+ brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
+fail:
+ brcmf_fws_deinit(drvr);
+ return rc;
+}
+
+void brcmf_fws_deinit(struct brcmf_pub *drvr)
+{
+ struct brcmf_fws_info *fws = drvr->fws;
+ ulong flags;
+
+ if (!fws)
+ return;
+
+ /* disable firmware signalling entirely
+ * to avoid using the workqueue.
+ */
+ drvr->fw_signals = false;
+
+ if (drvr->fws->fws_wq)
+ destroy_workqueue(drvr->fws->fws_wq);
+
+ /* cleanup */
+ brcmf_fws_lock(drvr, flags);
+ brcmf_fws_cleanup(fws, -1);
+ drvr->fws = NULL;
+ brcmf_fws_unlock(drvr, flags);
+
+ /* free top structure */
+ kfree(fws);
+}
+
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
+{
+ if (!fws)
+ return false;
+
+ brcmf_dbg(TRACE, "enter: mode=%d\n", fws->fcmode);
+ return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
+}
+
+void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
+{
+ ulong flags;
+
+ brcmf_fws_lock(fws->drvr, flags);
+ brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
+ brcmf_skb_htod_tag_get_field(skb, HSLOT), 0);
+ /* the packet never reached firmware so reclaim credit */
+ if (fws->fcmode == BRCMF_FWS_FCMODE_EXPLICIT_CREDIT &&
+ brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
+ brcmf_fws_return_credits(fws,
+ brcmf_skb_htod_tag_get_field(skb,
+ FIFO),
+ 1);
+ brcmf_fws_schedule_deq(fws);
+ }
+ brcmf_fws_unlock(fws->drvr, flags);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
new file mode 100644
index 000000000000..fbe483d23752
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef FWSIGNAL_H_
+#define FWSIGNAL_H_
+
+int brcmf_fws_init(struct brcmf_pub *drvr);
+void brcmf_fws_deinit(struct brcmf_pub *drvr);
+bool brcmf_fws_fc_active(struct brcmf_fws_info *fws);
+int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
+ struct sk_buff *skb);
+int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb);
+
+void brcmf_fws_reset_interface(struct brcmf_if *ifp);
+void brcmf_fws_add_interface(struct brcmf_if *ifp);
+void brcmf_fws_del_interface(struct brcmf_if *ifp);
+void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
+
+#endif /* FWSIGNAL_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
index 4166e642068b..2b90da0d85f3 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
@@ -15,6 +15,7 @@
*/
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <net/cfg80211.h>
#include <brcmu_wifi.h>
@@ -423,29 +424,6 @@ static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len)
/**
- * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec.
- *
- * @channel: channel number
- */
-static u16 brcmf_p2p_chnr_to_chspec(u16 channel)
-{
- u16 chanspec;
-
- chanspec = channel & WL_CHANSPEC_CHAN_MASK;
-
- if (channel <= CH_MAX_2G_CHANNEL)
- chanspec |= WL_CHANSPEC_BAND_2G;
- else
- chanspec |= WL_CHANSPEC_BAND_5G;
-
- chanspec |= WL_CHANSPEC_BW_20;
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-
- return chanspec;
-}
-
-
-/**
* brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
*
* @ifp: ifp to use for iovars (primary).
@@ -455,7 +433,9 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
{
s32 ret = 0;
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
brcmf_fil_iovar_int_set(ifp, "apsta", 1);
+ brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
/* In case of COB type, firmware has default mac address
* After Initializing firmware, we have to set current mac address to
@@ -473,28 +453,35 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
* brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
*
* @p2p: P2P specific data.
+ * @dev_addr: optional device address.
*
- * P2P needs mac addresses for P2P device and interface. These are
- * derived from the primary net device, ie. the permanent ethernet
- * address of the device.
+ * P2P needs mac addresses for P2P device and interface. If no device
+ * address it specified, these are derived from the primary net device, ie.
+ * the permanent ethernet address of the device.
*/
-static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
+static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
{
struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp;
+ bool local_admin = false;
+
+ if (!dev_addr || is_zero_ether_addr(dev_addr)) {
+ dev_addr = pri_ifp->mac_addr;
+ local_admin = true;
+ }
/* Generate the P2P Device Address. This consists of the device's
* primary MAC address with the locally administered bit set.
*/
- memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN);
- p2p->dev_addr[0] |= 0x02;
- memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
+ if (local_admin)
+ p2p->dev_addr[0] |= 0x02;
/* Generate the P2P Interface Address. If the discovery and connection
* BSSCFGs need to simultaneously co-exist, then this address must be
* different from the P2P Device Address, but also locally administered.
*/
memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
+ p2p->int_addr[0] |= 0x02;
p2p->int_addr[4] ^= 0x80;
}
@@ -773,7 +760,7 @@ exit:
* validates the channels in the request.
*/
static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
+ struct brcmf_if *ifp,
struct cfg80211_scan_request *request,
u16 action)
{
@@ -827,7 +814,8 @@ static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
IEEE80211_CHAN_PASSIVE_SCAN))
continue;
- chanspecs[i] = channel_to_chanspec(chan);
+ chanspecs[i] = channel_to_chanspec(&p2p->cfg->d11inf,
+ chan);
brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
num_nodfs, chan->hw_value, chanspecs[i]);
num_nodfs++;
@@ -935,8 +923,8 @@ static s32
brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
{
struct brcmf_cfg80211_vif *vif;
+ struct brcmu_chan ch;
s32 err = 0;
- u16 chanspec;
vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
if (!vif) {
@@ -951,9 +939,11 @@ brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration)
goto exit;
}
- chanspec = brcmf_p2p_chnr_to_chspec(channel);
+ ch.chnum = channel;
+ ch.bw = BRCMU_CHAN_BW_20;
+ p2p->cfg->d11inf.encchspec(&ch);
err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
- chanspec, (u16)duration);
+ ch.chspec, (u16)duration);
if (!err) {
set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status);
p2p->remain_on_channel_cookie++;
@@ -1065,6 +1055,7 @@ static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
u32 channel_cnt;
u16 *default_chan_list;
u32 i;
+ struct brcmu_chan ch;
brcmf_dbg(TRACE, "Enter\n");
@@ -1079,15 +1070,23 @@ static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel)
err = -ENOMEM;
goto exit;
}
+ ch.bw = BRCMU_CHAN_BW_20;
if (channel) {
+ ch.chnum = channel;
+ p2p->cfg->d11inf.encchspec(&ch);
/* insert same channel to the chan_list */
for (i = 0; i < channel_cnt; i++)
- default_chan_list[i] =
- brcmf_p2p_chnr_to_chspec(channel);
+ default_chan_list[i] = ch.chspec;
} else {
- default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1);
- default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2);
- default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3);
+ ch.chnum = SOCIAL_CHAN_1;
+ p2p->cfg->d11inf.encchspec(&ch);
+ default_chan_list[0] = ch.chspec;
+ ch.chnum = SOCIAL_CHAN_2;
+ p2p->cfg->d11inf.encchspec(&ch);
+ default_chan_list[1] = ch.chspec;
+ ch.chnum = SOCIAL_CHAN_3;
+ p2p->cfg->d11inf.encchspec(&ch);
+ default_chan_list[2] = ch.chspec;
}
err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list,
WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START,
@@ -1217,6 +1216,7 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
+ struct brcmu_chan ch;
u8 *ie;
s32 err;
u8 p2p_dev_addr[ETH_ALEN];
@@ -1242,8 +1242,12 @@ bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg,
p2p_dev_addr, sizeof(p2p_dev_addr));
if ((err >= 0) &&
(!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) {
- afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+ if (!bi->ctl_ch) {
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
+ bi->ctl_ch = ch.chnum;
+ }
+ afx_hdl->peer_chan = bi->ctl_ch;
brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n",
afx_hdl->tx_dst_addr, afx_hdl->peer_chan);
complete(&afx_hdl->act_frm_scan);
@@ -1261,7 +1265,7 @@ static void
brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
- struct net_device *ndev = cfg->escan_info.ndev;
+ struct brcmf_if *ifp = cfg->escan_info.ifp;
if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
(test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
@@ -1271,12 +1275,12 @@ brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
* So abort scan for off channel completion.
*/
if (p2p->af_sent_channel)
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
} else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN,
&p2p->status)) {
brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n");
/* So abort scan to cancel listen */
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
}
}
@@ -1350,12 +1354,14 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
u8 *frame = (u8 *)(rxframe + 1);
struct brcmf_p2p_pub_act_frame *act_frm;
struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm;
- u16 chanspec = be16_to_cpu(rxframe->chanspec);
+ struct brcmu_chan ch;
struct ieee80211_mgmt *mgmt_frame;
s32 freq;
u16 mgmt_type;
u8 action;
+ ch.chspec = be16_to_cpu(rxframe->chanspec);
+ cfg->d11inf.decchspec(&ch);
/* Check if wpa_supplicant has registered for this frame */
brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg);
mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4;
@@ -1374,7 +1380,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
&p2p->status) &&
(memcmp(afx_hdl->tx_dst_addr, e->addr,
ETH_ALEN) == 0)) {
- afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+ afx_hdl->peer_chan = ch.chnum;
brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n",
afx_hdl->peer_chan);
complete(&afx_hdl->act_frm_scan);
@@ -1384,7 +1390,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
/* After complete GO Negotiation, roll back to mpc mode */
if ((action == P2P_PAF_GON_CONF) ||
(action == P2P_PAF_PROVDIS_RSP))
- brcmf_set_mpc(ifp->ndev, 1);
+ brcmf_set_mpc(ifp, 1);
if (action == P2P_PAF_GON_CONF) {
brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n");
clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
@@ -1417,11 +1423,12 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
memcpy(&mgmt_frame->u, frame, mgmt_frame_len);
mgmt_frame_len += offsetof(struct ieee80211_mgmt, u);
- freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
- CHSPEC_IS2G(chanspec) ?
+ freq = ieee80211_channel_to_frequency(ch.chnum,
+ ch.band == BRCMU_CHAN_BAND_2G ?
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- wdev = ifp->ndev->ieee80211_ptr;
+
+ wdev = &ifp->vif->wdev;
cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len,
GFP_ATOMIC);
@@ -1637,6 +1644,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
struct brcmf_fil_af_params_le *af_params)
{
struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_fil_action_frame_le *action_frame;
struct brcmf_config_af_params config_af_params;
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
@@ -1725,7 +1733,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
/* To make sure to send successfully action frame, turn off mpc */
if (config_af_params.mpc_onoff == 0)
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
/* set status and destination address before sending af */
if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
@@ -1753,7 +1761,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg,
* care of current piggback algo, lets abort the scan here
* itself.
*/
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, ifp, true, true);
/* update channel */
af_params->channel = cpu_to_le32(afx_hdl->peer_chan);
@@ -1820,7 +1828,7 @@ exit:
clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status);
/* if all done, turn mpc on again */
if (config_af_params.mpc_onoff == 1)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return ack;
}
@@ -1839,10 +1847,10 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_p2p_info *p2p = &cfg->p2p;
struct afx_hdl *afx_hdl = &p2p->afx_hdl;
- struct wireless_dev *wdev;
struct brcmf_cfg80211_vif *vif = ifp->vif;
struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data;
u16 chanspec = be16_to_cpu(rxframe->chanspec);
+ struct brcmu_chan ch;
u8 *mgmt_frame;
u32 mgmt_frame_len;
s32 freq;
@@ -1851,9 +1859,12 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
e->reason);
+ ch.chspec = be16_to_cpu(rxframe->chanspec);
+ cfg->d11inf.decchspec(&ch);
+
if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) &&
(memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) {
- afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec);
+ afx_hdl->peer_chan = ch.chnum;
brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n",
afx_hdl->peer_chan);
complete(&afx_hdl->act_frm_scan);
@@ -1878,12 +1889,13 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
mgmt_frame = (u8 *)(rxframe + 1);
mgmt_frame_len = e->datalen - sizeof(*rxframe);
- freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec),
- CHSPEC_IS2G(chanspec) ?
+ freq = ieee80211_channel_to_frequency(ch.chnum,
+ ch.band == BRCMU_CHAN_BAND_2G ?
IEEE80211_BAND_2GHZ :
IEEE80211_BAND_5GHZ);
- wdev = ifp->ndev->ieee80211_ptr;
- cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
+
+ cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len,
+ GFP_ATOMIC);
brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
mgmt_frame_len, e->datalen, chanspec, freq);
@@ -1934,7 +1946,8 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
- brcmf_p2p_generate_bss_mac(p2p);
+ brcmf_p2p_generate_bss_mac(p2p, NULL);
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
/* Initialize P2P Discovery in the firmware */
@@ -2001,21 +2014,19 @@ static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p,
{
struct brcmf_if *ifp;
struct brcmf_fil_chan_info_le ci;
+ struct brcmu_chan ch;
s32 err;
ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- *chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
+ ch.chnum = 11;
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
- if (!err) {
- *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
- if (*chanspec < CH_MAX_2G_CHANNEL)
- *chanspec |= WL_CHANSPEC_BAND_2G;
- else
- *chanspec |= WL_CHANSPEC_BAND_5G;
- }
- *chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
+ if (!err)
+ ch.chnum = le32_to_cpu(ci.hw_channel);
+ ch.bw = BRCMU_CHAN_BW_20;
+ p2p->cfg->d11inf.encchspec(&ch);
+ *chanspec = ch.chspec;
}
/**
@@ -2040,13 +2051,13 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n");
return -EPERM;
}
- brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true);
+ brcmf_notify_escan_complete(cfg, vif->ifp, true, true);
vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
if (!vif) {
brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n");
return -EPERM;
}
- brcmf_set_mpc(vif->ifp->ndev, 0);
+ brcmf_set_mpc(vif->ifp, 0);
/* In concurrency case, STA may be already associated in a particular */
/* channel. so retrieve the current channel of primary interface and */
@@ -2124,13 +2135,105 @@ static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
}
/**
+ * brcmf_p2p_create_p2pdev() - create a P2P_DEVICE virtual interface.
+ *
+ * @p2p: P2P specific data.
+ * @wiphy: wiphy device of new interface.
+ * @addr: mac address for this new interface.
+ */
+static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
+ struct wiphy *wiphy,
+ u8 *addr)
+{
+ struct brcmf_cfg80211_vif *p2p_vif;
+ struct brcmf_if *p2p_ifp;
+ struct brcmf_if *pri_ifp;
+ int err;
+ u32 bssidx;
+
+ if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ return ERR_PTR(-ENOSPC);
+
+ p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE,
+ false);
+ if (IS_ERR(p2p_vif)) {
+ brcmf_err("could not create discovery vif\n");
+ return (struct wireless_dev *)p2p_vif;
+ }
+
+ pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
+ brcmf_p2p_generate_bss_mac(p2p, addr);
+ brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr);
+
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, p2p_vif);
+
+ /* Initialize P2P Discovery in the firmware */
+ err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
+ if (err < 0) {
+ brcmf_err("set p2p_disc error\n");
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+ goto fail;
+ }
+
+ /* wait for firmware event */
+ err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
+ msecs_to_jiffies(1500));
+ brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
+ if (!err) {
+ brcmf_err("timeout occurred\n");
+ err = -EIO;
+ goto fail;
+ }
+
+ /* discovery interface created */
+ p2p_ifp = p2p_vif->ifp;
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif;
+ memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN);
+ memcpy(&p2p_vif->wdev.address, p2p->dev_addr, sizeof(p2p->dev_addr));
+
+ /* verify bsscfg index for P2P discovery */
+ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
+ if (err < 0) {
+ brcmf_err("retrieving discover bsscfg index failed\n");
+ goto fail;
+ }
+
+ WARN_ON(p2p_ifp->bssidx != bssidx);
+
+ init_completion(&p2p->send_af_done);
+ INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler);
+ init_completion(&p2p->afx_hdl.act_frm_scan);
+ init_completion(&p2p->wait_next_af);
+
+ return &p2p_vif->wdev;
+
+fail:
+ brcmf_free_vif(p2p_vif);
+ return ERR_PTR(err);
+}
+
+/**
+ * brcmf_p2p_delete_p2pdev() - delete P2P_DEVICE virtual interface.
+ *
+ * @vif: virtual interface object to delete.
+ */
+static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif)
+{
+ struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p;
+
+ cfg80211_unregister_wdev(&vif->wdev);
+ p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+ brcmf_free_vif(vif);
+}
+
+/**
* brcmf_p2p_add_vif() - create a new P2P virtual interface.
*
* @wiphy: wiphy device of new interface.
* @name: name of the new interface.
* @type: nl80211 interface type.
- * @flags: TBD
- * @params: TBD
+ * @flags: not used.
+ * @params: contains mac address for P2P device.
*/
struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
enum nl80211_iftype type, u32 *flags,
@@ -2157,6 +2260,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
iftype = BRCMF_FIL_P2P_IF_GO;
mode = WL_MODE_AP;
break;
+ case NL80211_IFTYPE_P2P_DEVICE:
+ return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy,
+ params->macaddr);
default:
return ERR_PTR(-EOPNOTSUPP);
}
@@ -2244,6 +2350,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
break;
case NL80211_IFTYPE_P2P_DEVICE:
+ brcmf_p2p_delete_p2pdev(vif);
+ return 0;
default:
return -ENOTSUPP;
break;
@@ -2275,3 +2383,33 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
return err;
}
+
+int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+ int err;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ mutex_lock(&cfg->usr_sync);
+ err = brcmf_p2p_enable_discovery(p2p);
+ if (!err)
+ set_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+ mutex_unlock(&cfg->usr_sync);
+ return err;
+}
+
+void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_p2p_info *p2p = &cfg->p2p;
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+ mutex_lock(&cfg->usr_sync);
+ (void)brcmf_p2p_deinit_discovery(p2p);
+ brcmf_abort_scanning(cfg);
+ clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state);
+ mutex_unlock(&cfg->usr_sync);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
index 14be2d5530ce..ca72177388b9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
@@ -40,6 +40,15 @@
#define BCM4329_CORE_ARM_BASE 0x18002000
#define BCM4329_RAMSIZE 0x48000
+/* bcm43143 */
+/* SDIO device core */
+#define BCM43143_CORE_BUS_BASE 0x18002000
+/* internal memory core */
+#define BCM43143_CORE_SOCRAM_BASE 0x18004000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM43143_CORE_ARM_BASE 0x18003000
+#define BCM43143_RAMSIZE 0x70000
+
#define SBCOREREV(sbidh) \
((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
((sbidh) & SSB_IDHIGH_RCLO))
@@ -52,6 +61,9 @@
#define CIB_REV_MASK 0xff000000
#define CIB_REV_SHIFT 24
+/* ARM CR4 core specific control flag bits */
+#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
+
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
/* SDIO Pad drive strength to select value mappings */
struct sdiod_drive_str {
@@ -70,6 +82,14 @@ static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
{0, 0x1}
};
+/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
+static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
+ {16, 0x7},
+ {12, 0x5},
+ {8, 0x3},
+ {4, 0x1}
+};
+
u8
brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
{
@@ -149,7 +169,7 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
static void
brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid)
+ struct chip_info *ci, u16 coreid, u32 core_bits)
{
u32 regdata, base;
u8 idx;
@@ -235,7 +255,7 @@ brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
static void
brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid)
+ struct chip_info *ci, u16 coreid, u32 core_bits)
{
u8 idx;
u32 regdata;
@@ -249,19 +269,36 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
return;
- brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0, NULL);
- regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ /* ensure no pending backplane operation
+ * 300uc should be sufficient for backplane ops to be finish
+ * extra 10ms is taken into account for firmware load stage
+ * after 10300us carry on disabling the core anyway
+ */
+ SPINWAIT(brcmf_sdio_regrl(sdiodev,
+ ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
+ NULL), 10300);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
NULL);
- udelay(10);
+ if (regdata)
+ brcmf_err("disabling core 0x%x with reset status %x\n",
+ coreid, regdata);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
BCMA_RESET_CTL_RESET, NULL);
udelay(1);
+
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ core_bits, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ NULL);
+ usleep_range(10, 20);
+
}
static void
brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid)
+ struct chip_info *ci, u16 coreid, u32 core_bits)
{
u32 regdata;
u8 idx;
@@ -272,7 +309,7 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
* Must do the disable sequence first to work for
* arbitrary current core state.
*/
- brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
+ brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
/*
* Now do the initialization sequence.
@@ -325,7 +362,7 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
static void
brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid)
+ struct chip_info *ci, u16 coreid, u32 core_bits)
{
u8 idx;
u32 regdata;
@@ -333,31 +370,69 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
/* must disable first to work for arbitrary current core state */
- brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
+ brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
/* now do initialization sequence */
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
+ core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
0, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+ NULL);
udelay(1);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- BCMA_IOCTL_CLK, NULL);
+ core_bits | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(1);
}
+#ifdef DEBUG
+/* safety check for chipinfo */
+static int brcmf_sdio_chip_cichk(struct chip_info *ci)
+{
+ u8 core_idx;
+
+ /* check RAM core presence for ARM CM3 core */
+ core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
+ if (BRCMF_MAX_CORENUM != core_idx) {
+ core_idx = brcmf_sdio_chip_getinfidx(ci,
+ BCMA_CORE_INTERNAL_MEM);
+ if (BRCMF_MAX_CORENUM == core_idx) {
+ brcmf_err("RAM core not provided with ARM CM3 core\n");
+ return -ENODEV;
+ }
+ }
+
+ /* check RAM base for ARM CR4 core */
+ core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
+ if (BRCMF_MAX_CORENUM != core_idx) {
+ if (ci->rambase == 0) {
+ brcmf_err("RAM base not provided with ARM CR4 core\n");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+#else /* DEBUG */
+static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
+{
+ return 0;
+}
+#endif
+
static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u32 regs)
{
u32 regdata;
+ int ret;
- /*
- * Get CC core rev
+ /* Get CC core rev
* Chipid is assume to be at offset 0 from regs arg
* For different chiptypes or old sdio hosts w/o chipcommon,
* other ways of recognition should be added here.
@@ -375,6 +450,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
/* Address of cores for new chips should be added here */
switch (ci->chip) {
+ case BCM43143_CHIP_ID:
+ ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
+ ci->c_inf[0].cib = 0x2b000000;
+ ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+ ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
+ ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
+ ci->c_inf[1].cib = 0x18000000;
+ ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+ ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
+ ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
+ ci->c_inf[2].cib = 0x14000000;
+ ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+ ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
+ ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
+ ci->c_inf[3].cib = 0x07000000;
+ ci->ramsize = BCM43143_RAMSIZE;
+ break;
case BCM43241_CHIP_ID:
ci->c_inf[0].wrapbase = 0x18100000;
ci->c_inf[0].cib = 0x2a084411;
@@ -435,11 +527,29 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
ci->c_inf[3].cib = 0x07004211;
ci->ramsize = 0x80000;
break;
+ case BCM4335_CHIP_ID:
+ ci->c_inf[0].wrapbase = 0x18100000;
+ ci->c_inf[0].cib = 0x2b084411;
+ ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+ ci->c_inf[1].base = 0x18005000;
+ ci->c_inf[1].wrapbase = 0x18105000;
+ ci->c_inf[1].cib = 0x0f004211;
+ ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
+ ci->c_inf[2].base = 0x18002000;
+ ci->c_inf[2].wrapbase = 0x18102000;
+ ci->c_inf[2].cib = 0x01084411;
+ ci->ramsize = 0xc0000;
+ ci->rambase = 0x180000;
+ break;
default:
brcmf_err("chipid 0x%x is not supported\n", ci->chip);
return -ENODEV;
}
+ ret = brcmf_sdio_chip_cichk(ci);
+ if (ret)
+ return ret;
+
switch (ci->socitype) {
case SOCI_SB:
ci->iscoreup = brcmf_sdio_sb_iscoreup;
@@ -539,7 +649,7 @@ brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
* Make sure any on-chip ARM is off (in case strapping is wrong),
* or downloaded code was already running.
*/
- ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
+ ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
}
int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
@@ -600,21 +710,37 @@ void
brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u32 drivestrength)
{
- struct sdiod_drive_str *str_tab = NULL;
- u32 str_mask = 0;
- u32 str_shift = 0;
+ const struct sdiod_drive_str *str_tab = NULL;
+ u32 str_mask;
+ u32 str_shift;
char chn[8];
u32 base = ci->c_inf[0].base;
+ u32 i;
+ u32 drivestrength_sel = 0;
+ u32 cc_data_temp;
+ u32 addr;
if (!(ci->c_inf[0].caps & CC_CAP_PMU))
return;
switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
- str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
+ str_tab = sdiod_drvstr_tab1_1v8;
str_mask = 0x00003800;
str_shift = 11;
break;
+ case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
+ /* note: 43143 does not support tristate */
+ i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
+ if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
+ str_tab = sdiod_drvstr_tab2_3v3;
+ str_mask = 0x00000007;
+ str_shift = 0;
+ } else
+ brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
+ brcmf_sdio_chip_name(ci->chip, chn, 8),
+ drivestrength);
+ break;
default:
brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
brcmf_sdio_chip_name(ci->chip, chn, 8),
@@ -623,30 +749,207 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
}
if (str_tab != NULL) {
- u32 drivestrength_sel = 0;
- u32 cc_data_temp;
- int i;
-
for (i = 0; str_tab[i].strength != 0; i++) {
if (drivestrength >= str_tab[i].strength) {
drivestrength_sel = str_tab[i].sel;
break;
}
}
-
- brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
- 1, NULL);
- cc_data_temp =
- brcmf_sdio_regrl(sdiodev,
- CORE_CC_REG(base, chipcontrol_addr),
- NULL);
+ addr = CORE_CC_REG(base, chipcontrol_addr);
+ brcmf_sdio_regwl(sdiodev, addr, 1, NULL);
+ cc_data_temp = brcmf_sdio_regrl(sdiodev, addr, NULL);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
- brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
- cc_data_temp, NULL);
+ brcmf_sdio_regwl(sdiodev, addr, cc_data_temp, NULL);
- brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
- drivestrength, cc_data_temp);
+ brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
+ str_tab[i].strength, drivestrength, cc_data_temp);
}
}
+
+#ifdef DEBUG
+static bool
+brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
+ char *nvram_dat, uint nvram_sz)
+{
+ char *nvram_ularray;
+ int err;
+ bool ret = true;
+
+ /* read back and verify */
+ brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz);
+ nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL);
+ /* do not proceed while no memory but */
+ if (!nvram_ularray)
+ return true;
+
+ /* Upload image to verify downloaded contents. */
+ memset(nvram_ularray, 0xaa, nvram_sz);
+
+ /* Read the vars list to temp buffer for comparison */
+ err = brcmf_sdio_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
+ nvram_sz);
+ if (err) {
+ brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
+ err, nvram_sz, nvram_addr);
+ } else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) {
+ brcmf_err("Downloaded NVRAM image is corrupted\n");
+ ret = false;
+ }
+ kfree(nvram_ularray);
+
+ return ret;
+}
+#else /* DEBUG */
+static inline bool
+brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
+ char *nvram_dat, uint nvram_sz)
+{
+ return true;
+}
+#endif /* DEBUG */
+
+static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci,
+ char *nvram_dat, uint nvram_sz)
+{
+ int err;
+ u32 nvram_addr;
+ u32 token;
+ __le32 token_le;
+
+ nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
+
+ /* Write the vars list */
+ err = brcmf_sdio_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
+ if (err) {
+ brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
+ err, nvram_sz, nvram_addr);
+ return false;
+ }
+
+ if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr,
+ nvram_dat, nvram_sz))
+ return false;
+
+ /* generate token:
+ * nvram size, converted to words, in lower 16-bits, checksum
+ * in upper 16-bits.
+ */
+ token = nvram_sz / 4;
+ token = (~token << 16) | (token & 0x0000FFFF);
+ token_le = cpu_to_le32(token);
+
+ brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize);
+ brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n",
+ nvram_addr, nvram_sz, token);
+
+ /* Write the length token to the last word */
+ if (brcmf_sdio_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
+ (u8 *)&token_le, 4))
+ return false;
+
+ return true;
+}
+
+static void
+brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci)
+{
+ u32 zeros = 0;
+
+ ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
+ ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
+
+ /* clear length token */
+ brcmf_sdio_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
+}
+
+static bool
+brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+ char *nvram_dat, uint nvram_sz)
+{
+ u8 core_idx;
+ u32 reg_addr;
+
+ if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
+ brcmf_err("SOCRAM core is down after reset?\n");
+ return false;
+ }
+
+ if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
+ return false;
+
+ /* clear all interrupts */
+ core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
+ reg_addr = ci->c_inf[core_idx].base;
+ reg_addr += offsetof(struct sdpcmd_regs, intstatus);
+ brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+
+ ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
+
+ return true;
+}
+
+static inline void
+brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci)
+{
+ ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
+ ARMCR4_BCMA_IOCTL_CPUHALT);
+}
+
+static bool
+brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+ char *nvram_dat, uint nvram_sz)
+{
+ u8 core_idx;
+ u32 reg_addr;
+
+ if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
+ return false;
+
+ /* clear all interrupts */
+ core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
+ reg_addr = ci->c_inf[core_idx].base;
+ reg_addr += offsetof(struct sdpcmd_regs, intstatus);
+ brcmf_sdio_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
+
+ /* Write reset vector to address 0 */
+ brcmf_sdio_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
+ sizeof(ci->rst_vec));
+
+ /* restore ARM */
+ ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
+
+ return true;
+}
+
+void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci)
+{
+ u8 arm_core_idx;
+
+ arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
+ if (BRCMF_MAX_CORENUM != arm_core_idx) {
+ brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
+ return;
+ }
+
+ brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
+}
+
+bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci, char *nvram_dat,
+ uint nvram_sz)
+{
+ u8 arm_core_idx;
+
+ arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
+ if (BRCMF_MAX_CORENUM != arm_core_idx)
+ return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat,
+ nvram_sz);
+
+ return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, nvram_dat, nvram_sz);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
index ce974d76bd92..83c041f1bf4a 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
@@ -73,15 +73,17 @@ struct chip_info {
u32 pmurev;
u32 pmucaps;
u32 ramsize;
+ u32 rambase;
+ u32 rst_vec; /* reset vertor for ARM CR4 core */
bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
u16 coreid);
u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
u16 coreid);
void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid);
+ struct chip_info *ci, u16 coreid, u32 core_bits);
void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
- struct chip_info *ci, u16 coreid);
+ struct chip_info *ci, u16 coreid, u32 core_bits);
};
struct sbconfig {
@@ -124,6 +126,95 @@ struct sbconfig {
u32 sbidhigh; /* identification */
};
+/* sdio core registers */
+struct sdpcmd_regs {
+ u32 corecontrol; /* 0x00, rev8 */
+ u32 corestatus; /* rev8 */
+ u32 PAD[1];
+ u32 biststatus; /* rev8 */
+
+ /* PCMCIA access */
+ u16 pcmciamesportaladdr; /* 0x010, rev8 */
+ u16 PAD[1];
+ u16 pcmciamesportalmask; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciawrframebc; /* rev8 */
+ u16 PAD[1];
+ u16 pcmciaunderflowtimer; /* rev8 */
+ u16 PAD[1];
+
+ /* interrupt */
+ u32 intstatus; /* 0x020, rev8 */
+ u32 hostintmask; /* rev8 */
+ u32 intmask; /* rev8 */
+ u32 sbintstatus; /* rev8 */
+ u32 sbintmask; /* rev8 */
+ u32 funcintmask; /* rev4 */
+ u32 PAD[2];
+ u32 tosbmailbox; /* 0x040, rev8 */
+ u32 tohostmailbox; /* rev8 */
+ u32 tosbmailboxdata; /* rev8 */
+ u32 tohostmailboxdata; /* rev8 */
+
+ /* synchronized access to registers in SDIO clock domain */
+ u32 sdioaccess; /* 0x050, rev8 */
+ u32 PAD[3];
+
+ /* PCMCIA frame control */
+ u8 pcmciaframectrl; /* 0x060, rev8 */
+ u8 PAD[3];
+ u8 pcmciawatermark; /* rev8 */
+ u8 PAD[155];
+
+ /* interrupt batching control */
+ u32 intrcvlazy; /* 0x100, rev8 */
+ u32 PAD[3];
+
+ /* counters */
+ u32 cmd52rd; /* 0x110, rev8 */
+ u32 cmd52wr; /* rev8 */
+ u32 cmd53rd; /* rev8 */
+ u32 cmd53wr; /* rev8 */
+ u32 abort; /* rev8 */
+ u32 datacrcerror; /* rev8 */
+ u32 rdoutofsync; /* rev8 */
+ u32 wroutofsync; /* rev8 */
+ u32 writebusy; /* rev8 */
+ u32 readwait; /* rev8 */
+ u32 readterm; /* rev8 */
+ u32 writeterm; /* rev8 */
+ u32 PAD[40];
+ u32 clockctlstatus; /* rev8 */
+ u32 PAD[7];
+
+ u32 PAD[128]; /* DMA engines */
+
+ /* SDIO/PCMCIA CIS region */
+ char cis[512]; /* 0x400-0x5ff, rev6 */
+
+ /* PCMCIA function control registers */
+ char pcmciafcr[256]; /* 0x600-6ff, rev6 */
+ u16 PAD[55];
+
+ /* PCMCIA backplane access */
+ u16 backplanecsr; /* 0x76E, rev6 */
+ u16 backplaneaddr0; /* rev6 */
+ u16 backplaneaddr1; /* rev6 */
+ u16 backplaneaddr2; /* rev6 */
+ u16 backplaneaddr3; /* rev6 */
+ u16 backplanedata0; /* rev6 */
+ u16 backplanedata1; /* rev6 */
+ u16 backplanedata2; /* rev6 */
+ u16 backplanedata3; /* rev6 */
+ u16 PAD[31];
+
+ /* sprom "size" & "blank" info */
+ u16 spromstatus; /* 0x7BE, rev2 */
+ u32 PAD[464];
+
+ u16 PAD[0x80];
+};
+
extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
struct chip_info **ci_ptr, u32 regs);
extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
@@ -131,6 +222,10 @@ extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci,
u32 drivestrength);
extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
-
+extern void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci);
+extern bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci, char *nvram_dat,
+ uint nvram_sz);
#endif /* _BRCMFMAC_SDIO_CHIP_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
index 0d30afd8c672..7c1b6332747e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -48,7 +48,13 @@
#define SBSDIO_NUM_FUNCTION 3
/* function 0 vendor specific CCCR registers */
-#define SDIO_CCCR_BRCM_SEPINT 0xf2
+#define SDIO_CCCR_BRCM_CARDCAP 0xf0
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_SUPPORT 0x02
+#define SDIO_CCCR_BRCM_CARDCAP_CMD14_EXT 0x04
+#define SDIO_CCCR_BRCM_CARDCAP_CMD_NODEC 0x08
+#define SDIO_CCCR_BRCM_CARDCTRL 0xf1
+#define SDIO_CCCR_BRCM_CARDCTRL_WLANRESET 0x02
+#define SDIO_CCCR_BRCM_SEPINT 0xf2
#define SDIO_SEPINT_MASK 0x01
#define SDIO_SEPINT_OE 0x02
@@ -97,9 +103,23 @@
#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
/* Read Frame Byte Count High */
#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
+/* MesBusyCtl (rev 11) */
+#define SBSDIO_FUNC1_MESBUSYCTRL 0x1001D
+/* Sdio Core Rev 12 */
+#define SBSDIO_FUNC1_WAKEUPCTRL 0x1001E
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_MASK 0x1
+#define SBSDIO_FUNC1_WCTRL_ALPWAIT_SHIFT 0
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_MASK 0x2
+#define SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT 1
+#define SBSDIO_FUNC1_SLEEPCSR 0x1001F
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_MASK 0x1
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT 0
+#define SBSDIO_FUNC1_SLEEPCSR_KSO_EN 1
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK 0x2
+#define SBSDIO_FUNC1_SLEEPCSR_DEVON_SHIFT 1
#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
-#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */
+#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001F /* f1 misc register end */
/* function 1 OCP space */
@@ -154,13 +174,11 @@ struct brcmf_sdio_dev {
wait_queue_head_t request_buffer_wait;
struct device *dev;
struct brcmf_bus *bus_if;
-#ifdef CONFIG_BRCMFMAC_SDIO_OOB
- unsigned int irq; /* oob interrupt number */
- unsigned long irq_flags; /* board specific oob flags */
+ struct brcmfmac_sdio_platform_data *pdata;
+ bool oob_irq_requested;
bool irq_en; /* irq enable flags */
spinlock_t irq_en_lock;
bool irq_wake; /* irq wake enable flags */
-#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
};
/* Register/deregister interrupt handler. */
@@ -224,6 +242,8 @@ brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
*/
extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw,
u32 addr, u8 *buf, uint nbytes);
+extern int brcmf_sdio_ramrw(struct brcmf_sdio_dev *sdiodev, bool write,
+ u32 address, u8 *data, uint size);
/* Issue an abort to the specified function */
extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c
new file mode 100644
index 000000000000..b505db48c60d
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h> /* bug in tracepoint.h, it should include this */
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "tracepoint.h"
+#endif
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
new file mode 100644
index 000000000000..9df1f7a681e0
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#if !defined(BRCMF_TRACEPOINT_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define BRCMF_TRACEPOINT_H_
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#ifndef CONFIG_BRCM_TRACING
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(...)
+
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(evt_class, name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+
+#endif /* CONFIG_BRCM_TRACING */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmfmac
+
+#define MAX_MSG_LEN 100
+
+TRACE_EVENT(brcmf_err,
+ TP_PROTO(const char *func, struct va_format *vaf),
+ TP_ARGS(func, vaf),
+ TP_STRUCT__entry(
+ __string(func, func)
+ __dynamic_array(char, msg, MAX_MSG_LEN)
+ ),
+ TP_fast_assign(
+ __assign_str(func, func);
+ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+ MAX_MSG_LEN, vaf->fmt,
+ *vaf->va) >= MAX_MSG_LEN);
+ ),
+ TP_printk("%s: %s", __get_str(func), __get_str(msg))
+);
+
+TRACE_EVENT(brcmf_dbg,
+ TP_PROTO(u32 level, const char *func, struct va_format *vaf),
+ TP_ARGS(level, func, vaf),
+ TP_STRUCT__entry(
+ __field(u32, level)
+ __string(func, func)
+ __dynamic_array(char, msg, MAX_MSG_LEN)
+ ),
+ TP_fast_assign(
+ __entry->level = level;
+ __assign_str(func, func);
+ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+ MAX_MSG_LEN, vaf->fmt,
+ *vaf->va) >= MAX_MSG_LEN);
+ ),
+ TP_printk("%s: %s", __get_str(func), __get_str(msg))
+);
+
+TRACE_EVENT(brcmf_hexdump,
+ TP_PROTO(void *data, size_t len),
+ TP_ARGS(data, len),
+ TP_STRUCT__entry(
+ __field(unsigned long, len)
+ __dynamic_array(u8, hdata, len)
+ ),
+ TP_fast_assign(
+ __entry->len = len;
+ memcpy(__get_dynamic_array(hdata), data, len);
+ ),
+ TP_printk("hexdump [length=%lu]", __entry->len)
+);
+
+#ifdef CONFIG_BRCM_TRACING
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE tracepoint
+
+#include <trace/define_trace.h>
+
+#endif /* CONFIG_BRCM_TRACING */
+
+#endif /* BRCMF_TRACEPOINT_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 42289e9ea886..01aed7ad6bec 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -112,11 +112,6 @@ struct brcmf_usbdev_info {
static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
struct brcmf_usbreq *req);
-MODULE_AUTHOR("Broadcom Corporation");
-MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac usb driver.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac usb cards");
-MODULE_LICENSE("Dual BSD/GPL");
-
static struct brcmf_usbdev *brcmf_usb_get_buspub(struct device *dev)
{
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
@@ -422,8 +417,6 @@ static void brcmf_usb_tx_complete(struct urb *urb)
brcmf_usb_del_fromq(devinfo, req);
brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0);
-
- brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req, &devinfo->tx_freecount);
if (devinfo->tx_freecount > devinfo->tx_high_watermark &&
@@ -577,15 +570,17 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
int ret;
brcmf_dbg(USB, "Enter, skb=%p\n", skb);
- if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
- return -EIO;
+ if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
+ ret = -EIO;
+ goto fail;
+ }
req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
&devinfo->tx_freecount);
if (!req) {
- brcmu_pkt_buf_free_skb(skb);
brcmf_err("no req to send\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
req->skb = skb;
@@ -598,18 +593,21 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
if (ret) {
brcmf_err("brcmf_usb_tx usb_submit_urb FAILED\n");
brcmf_usb_del_fromq(devinfo, req);
- brcmu_pkt_buf_free_skb(req->skb);
req->skb = NULL;
brcmf_usb_enq(devinfo, &devinfo->tx_freeq, req,
- &devinfo->tx_freecount);
- } else {
- if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
- !devinfo->tx_flowblock) {
- brcmf_txflowblock(dev, true);
- devinfo->tx_flowblock = true;
- }
+ &devinfo->tx_freecount);
+ goto fail;
}
+ if (devinfo->tx_freecount < devinfo->tx_low_watermark &&
+ !devinfo->tx_flowblock) {
+ brcmf_txflowblock(dev, true);
+ devinfo->tx_flowblock = true;
+ }
+ return 0;
+
+fail:
+ brcmf_txcomplete(dev, skb, false);
return ret;
}
@@ -1485,6 +1483,7 @@ static struct usb_device_id brcmf_usb_devid_table[] = {
{ USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
{ }
};
+
MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index 2af9c0f0798d..6d758f285352 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -26,8 +26,10 @@
#include <brcmu_wifi.h>
#include "dhd.h"
#include "dhd_dbg.h"
+#include "tracepoint.h"
#include "fwil_types.h"
#include "p2p.h"
+#include "btcoex.h"
#include "wl_cfg80211.h"
#include "fwil.h"
@@ -182,64 +184,6 @@ static struct ieee80211_channel __wl_5ghz_a_channels[] = {
CHAN5G(216, 0),
};
-static struct ieee80211_channel __wl_5ghz_n_channels[] = {
- CHAN5G(32, 0), CHAN5G(34, 0),
- CHAN5G(36, 0), CHAN5G(38, 0),
- CHAN5G(40, 0), CHAN5G(42, 0),
- CHAN5G(44, 0), CHAN5G(46, 0),
- CHAN5G(48, 0), CHAN5G(50, 0),
- CHAN5G(52, 0), CHAN5G(54, 0),
- CHAN5G(56, 0), CHAN5G(58, 0),
- CHAN5G(60, 0), CHAN5G(62, 0),
- CHAN5G(64, 0), CHAN5G(66, 0),
- CHAN5G(68, 0), CHAN5G(70, 0),
- CHAN5G(72, 0), CHAN5G(74, 0),
- CHAN5G(76, 0), CHAN5G(78, 0),
- CHAN5G(80, 0), CHAN5G(82, 0),
- CHAN5G(84, 0), CHAN5G(86, 0),
- CHAN5G(88, 0), CHAN5G(90, 0),
- CHAN5G(92, 0), CHAN5G(94, 0),
- CHAN5G(96, 0), CHAN5G(98, 0),
- CHAN5G(100, 0), CHAN5G(102, 0),
- CHAN5G(104, 0), CHAN5G(106, 0),
- CHAN5G(108, 0), CHAN5G(110, 0),
- CHAN5G(112, 0), CHAN5G(114, 0),
- CHAN5G(116, 0), CHAN5G(118, 0),
- CHAN5G(120, 0), CHAN5G(122, 0),
- CHAN5G(124, 0), CHAN5G(126, 0),
- CHAN5G(128, 0), CHAN5G(130, 0),
- CHAN5G(132, 0), CHAN5G(134, 0),
- CHAN5G(136, 0), CHAN5G(138, 0),
- CHAN5G(140, 0), CHAN5G(142, 0),
- CHAN5G(144, 0), CHAN5G(145, 0),
- CHAN5G(146, 0), CHAN5G(147, 0),
- CHAN5G(148, 0), CHAN5G(149, 0),
- CHAN5G(150, 0), CHAN5G(151, 0),
- CHAN5G(152, 0), CHAN5G(153, 0),
- CHAN5G(154, 0), CHAN5G(155, 0),
- CHAN5G(156, 0), CHAN5G(157, 0),
- CHAN5G(158, 0), CHAN5G(159, 0),
- CHAN5G(160, 0), CHAN5G(161, 0),
- CHAN5G(162, 0), CHAN5G(163, 0),
- CHAN5G(164, 0), CHAN5G(165, 0),
- CHAN5G(166, 0), CHAN5G(168, 0),
- CHAN5G(170, 0), CHAN5G(172, 0),
- CHAN5G(174, 0), CHAN5G(176, 0),
- CHAN5G(178, 0), CHAN5G(180, 0),
- CHAN5G(182, 0), CHAN5G(184, 0),
- CHAN5G(186, 0), CHAN5G(188, 0),
- CHAN5G(190, 0), CHAN5G(192, 0),
- CHAN5G(194, 0), CHAN5G(196, 0),
- CHAN5G(198, 0), CHAN5G(200, 0),
- CHAN5G(202, 0), CHAN5G(204, 0),
- CHAN5G(206, 0), CHAN5G(208, 0),
- CHAN5G(210, 0), CHAN5G(212, 0),
- CHAN5G(214, 0), CHAN5G(216, 0),
- CHAN5G(218, 0), CHAN5G(220, 0),
- CHAN5G(222, 0), CHAN5G(224, 0),
- CHAN5G(226, 0), CHAN5G(228, 0),
-};
-
static struct ieee80211_supported_band __wl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
.channels = __wl_2ghz_channels,
@@ -256,12 +200,28 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = {
.n_bitrates = wl_a_rates_size,
};
-static struct ieee80211_supported_band __wl_band_5ghz_n = {
- .band = IEEE80211_BAND_5GHZ,
- .channels = __wl_5ghz_n_channels,
- .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels),
- .bitrates = wl_a_rates,
- .n_bitrates = wl_a_rates_size,
+/* This is to override regulatory domains defined in cfg80211 module (reg.c)
+ * By default world regulatory domain defined in reg.c puts the flags
+ * NL80211_RRF_PASSIVE_SCAN and NL80211_RRF_NO_IBSS for 5GHz channels (for
+ * 36..48 and 149..165). With respect to these flags, wpa_supplicant doesn't
+ * start p2p operations on 5GHz channels. All the changes in world regulatory
+ * domain are to be done here.
+ */
+static const struct ieee80211_regdomain brcmf_regdom = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ /* IEEE 802.11b/g, channels 1..11 */
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
+ /* If any */
+ /* IEEE 802.11 channel 14 - Only JP enables
+ * this and for 802.11b only
+ */
+ REG_RULE(2484-10, 2484+10, 20, 6, 20, 0),
+ /* IEEE 802.11a, channel 36..64 */
+ REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
+ /* IEEE 802.11a, channel 100..165 */
+ REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
};
static const u32 __wl_cipher_suites[] = {
@@ -375,22 +335,16 @@ static u8 brcmf_mw_to_qdbm(u16 mw)
return qdbm;
}
-u16 channel_to_chanspec(struct ieee80211_channel *ch)
+u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct ieee80211_channel *ch)
{
- u16 chanspec;
-
- chanspec = ieee80211_frequency_to_channel(ch->center_freq);
- chanspec &= WL_CHANSPEC_CHAN_MASK;
-
- if (ch->band == IEEE80211_BAND_2GHZ)
- chanspec |= WL_CHANSPEC_BAND_2G;
- else
- chanspec |= WL_CHANSPEC_BAND_5G;
+ struct brcmu_chan ch_inf;
- chanspec |= WL_CHANSPEC_BW_20;
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+ ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq);
+ ch_inf.bw = BRCMU_CHAN_BW_20;
+ d11inf->encchspec(&ch_inf);
- return chanspec;
+ return ch_inf.chspec;
}
/* Traverse a string of 1-byte tag/1-byte length/variable-length value
@@ -523,17 +477,16 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
return ERR_PTR(-EOPNOTSUPP);
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
return brcmf_p2p_add_vif(wiphy, name, type, flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
- case NL80211_IFTYPE_P2P_DEVICE:
default:
return ERR_PTR(-EINVAL);
}
}
-void brcmf_set_mpc(struct net_device *ndev, int mpc)
+void brcmf_set_mpc(struct brcmf_if *ifp, int mpc)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
s32 err = 0;
if (check_vif_up(ifp->vif)) {
@@ -546,10 +499,9 @@ void brcmf_set_mpc(struct net_device *ndev, int mpc)
}
}
-s32
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- bool aborted, bool fw_abort)
+s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort)
{
struct brcmf_scan_params_le params_le;
struct cfg80211_scan_request *scan_request;
@@ -580,7 +532,7 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
/* Scan is aborted by setting channel_list[0] to -1 */
params_le.channel_list[0] = cpu_to_le16(-1);
/* E-Scan (or anyother type) can be aborted by SCAN */
- err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&params_le, sizeof(params_le));
if (err)
brcmf_err("Scan abort failed\n");
@@ -594,12 +546,12 @@ brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
cfg->sched_escan = false;
if (!aborted)
cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
} else if (scan_request) {
brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
aborted ? "Aborted" : "Done");
cfg80211_scan_done(scan_request, aborted);
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
}
if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n");
@@ -619,9 +571,9 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
if (ndev) {
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
- cfg->escan_info.ndev == ndev)
- brcmf_notify_escan_complete(cfg, ndev, true,
- true);
+ cfg->escan_info.ifp == netdev_priv(ndev))
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev),
+ true, true);
brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
}
@@ -637,9 +589,9 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
return -EOPNOTSUPP;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_DEVICE:
return brcmf_p2p_del_vif(wiphy, wdev);
case NL80211_IFTYPE_UNSPECIFIED:
- case NL80211_IFTYPE_P2P_DEVICE:
default:
return -EINVAL;
}
@@ -723,7 +675,8 @@ done:
return err;
}
-static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
+static void brcmf_escan_prep(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_scan_params_le *params_le,
struct cfg80211_scan_request *request)
{
u32 n_ssids;
@@ -755,7 +708,8 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
n_channels);
if (n_channels > 0) {
for (i = 0; i < n_channels; i++) {
- chanspec = channel_to_chanspec(request->channels[i]);
+ chanspec = channel_to_chanspec(&cfg->d11inf,
+ request->channels[i]);
brcmf_dbg(SCAN, "Chan : %d, Channel spec: %x\n",
request->channels[i]->hw_value, chanspec);
params_le->channel_list[i] = cpu_to_le16(chanspec);
@@ -803,7 +757,7 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
}
static s32
-brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
+brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request, u16 action)
{
s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
@@ -827,13 +781,12 @@ brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
goto exit;
}
BUG_ON(params_size + sizeof("escan") >= BRCMF_DCMD_MEDLEN);
- brcmf_escan_prep(&params->params_le, request);
+ brcmf_escan_prep(cfg, &params->params_le, request);
params->version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
params->action = cpu_to_le16(action);
params->sync_id = cpu_to_le16(0x1234);
- err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "escan",
- params, params_size);
+ err = brcmf_fil_iovar_data_set(ifp, "escan", params, params_size);
if (err) {
if (err == -EBUSY)
brcmf_dbg(INFO, "system busy : escan canceled\n");
@@ -848,7 +801,7 @@ exit:
static s32
brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
- struct net_device *ndev, struct cfg80211_scan_request *request)
+ struct brcmf_if *ifp, struct cfg80211_scan_request *request)
{
s32 err;
u32 passive_scan;
@@ -856,35 +809,35 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
struct escan_info *escan = &cfg->escan_info;
brcmf_dbg(SCAN, "Enter\n");
- escan->ndev = ndev;
+ escan->ifp = ifp;
escan->wiphy = wiphy;
escan->escan_state = WL_ESCAN_STATE_SCANNING;
passive_scan = cfg->active_scan ? 0 : 1;
- err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN,
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
passive_scan);
if (err) {
brcmf_err("error (%d)\n", err);
return err;
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
results = (struct brcmf_scan_results *)cfg->escan_info.escan_buf;
results->version = 0;
results->count = 0;
results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE;
- err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START);
+ err = escan->run(cfg, ifp, request, WL_ESCAN_ACTION_START);
if (err)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return err;
}
static s32
-brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
+brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
struct cfg80211_scan_request *request,
struct cfg80211_ssid *this_ssid)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
+ struct brcmf_if *ifp = vif->ifp;
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct cfg80211_ssid *ssids;
struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
u32 passive_scan;
@@ -904,16 +857,19 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
cfg->scan_status);
return -EAGAIN;
}
+ if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
+ brcmf_err("Scanning suppressed: status (%lu)\n",
+ cfg->scan_status);
+ return -EAGAIN;
+ }
if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
brcmf_err("Connecting: status (%lu)\n", ifp->vif->sme_state);
return -EAGAIN;
}
/* If scan req comes for p2p0, send it over primary I/F */
- if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) {
- ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
- ndev = ifp->ndev;
- }
+ if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
+ vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
/* Arm scan timeout timer */
mod_timer(&cfg->escan_timeout, jiffies +
@@ -934,11 +890,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
if (escan_req) {
cfg->escan_info.run = brcmf_run_escan;
- err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif);
+ err = brcmf_p2p_scan_prep(wiphy, request, vif);
if (err)
goto scan_out;
- err = brcmf_do_escan(cfg, wiphy, ndev, request);
+ err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
if (err)
goto scan_out;
} else {
@@ -962,7 +918,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
goto scan_out;
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
&sr->ssid_le, sizeof(sr->ssid_le));
if (err) {
@@ -972,7 +928,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
else
brcmf_err("WLC_SCAN error (%d)\n", err);
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
goto scan_out;
}
}
@@ -990,16 +946,15 @@ scan_out:
static s32
brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
{
- struct net_device *ndev = request->wdev->netdev;
+ struct brcmf_cfg80211_vif *vif;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
-
- if (!check_vif_up(container_of(request->wdev,
- struct brcmf_cfg80211_vif, wdev)))
+ vif = container_of(request->wdev, struct brcmf_cfg80211_vif, wdev);
+ if (!check_vif_up(vif))
return -EIO;
- err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
+ err = brcmf_cfg80211_escan(wiphy, vif, request, NULL);
if (err)
brcmf_err("scan error (%d)\n", err);
@@ -1097,6 +1052,7 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
@@ -1110,6 +1066,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
+ clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+ brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
brcmf_dbg(TRACE, "Exit\n");
}
@@ -1229,7 +1187,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
params->chandef.chan->center_freq);
if (params->channel_fixed) {
/* adding chanspec */
- chanspec = channel_to_chanspec(params->chandef.chan);
+ chanspec = channel_to_chanspec(&cfg->d11inf,
+ params->chandef.chan);
join_params.params_le.chanspec_list[0] =
cpu_to_le16(chanspec);
join_params.params_le.chanspec_num = cpu_to_le32(1);
@@ -1619,7 +1578,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
if (chan) {
cfg->channel =
ieee80211_frequency_to_channel(chan->center_freq);
- chanspec = channel_to_chanspec(chan);
+ chanspec = channel_to_chanspec(&cfg->d11inf, chan);
brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n",
cfg->channel, chan->center_freq, chanspec);
} else {
@@ -1891,8 +1850,10 @@ static s32
brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
+ struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key key;
s32 err = 0;
+ u8 keybuf[8];
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -1916,8 +1877,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
memcpy(key.data, params->key, key.len);
- if (params->cipher == WLAN_CIPHER_SUITE_TKIP) {
- u8 keybuf[8];
+ if ((ifp->vif->mode != WL_MODE_AP) &&
+ (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
memcpy(&key.data[16], keybuf, sizeof(keybuf));
@@ -2013,7 +1975,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
break;
case WLAN_CIPHER_SUITE_TKIP:
if (ifp->vif->mode != WL_MODE_AP) {
- brcmf_dbg(CONN, "Swapping key\n");
+ brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
memcpy(&key.data[16], keybuf, sizeof(keybuf));
@@ -2118,8 +2080,7 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
err = -EAGAIN;
goto done;
}
- switch (wsec & ~SES_OW_ENABLED) {
- case WEP_ENABLED:
+ if (wsec & WEP_ENABLED) {
sec = &profile->sec;
if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
params.cipher = WLAN_CIPHER_SUITE_WEP40;
@@ -2128,16 +2089,13 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
params.cipher = WLAN_CIPHER_SUITE_WEP104;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
}
- break;
- case TKIP_ENABLED:
+ } else if (wsec & TKIP_ENABLED) {
params.cipher = WLAN_CIPHER_SUITE_TKIP;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
- break;
- case AES_ENABLED:
+ } else if (wsec & AES_ENABLED) {
params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
- break;
- default:
+ } else {
brcmf_err("Invalid algo (0x%x)\n", wsec);
err = -EINVAL;
goto done;
@@ -2279,6 +2237,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
struct ieee80211_channel *notify_channel;
struct cfg80211_bss *bss;
struct ieee80211_supported_band *band;
+ struct brcmu_chan ch;
s32 err = 0;
u16 channel;
u32 freq;
@@ -2293,8 +2252,12 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
return 0;
}
- channel = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+ if (!bi->ctl_ch) {
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
+ bi->ctl_ch = ch.chnum;
+ }
+ channel = bi->ctl_ch;
if (channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
@@ -2369,9 +2332,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
struct brcmf_bss_info_le *bi = NULL;
struct ieee80211_supported_band *band;
struct cfg80211_bss *bss;
+ struct brcmu_chan ch;
u8 *buf = NULL;
s32 err = 0;
- u16 channel;
u32 freq;
u16 notify_capability;
u16 notify_interval;
@@ -2398,15 +2361,15 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
bi = (struct brcmf_bss_info_le *)(buf + 4);
- channel = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
- if (channel <= CH_MAX_2G_CHANNEL)
+ if (ch.band == BRCMU_CHAN_BAND_2G)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
- freq = ieee80211_channel_to_frequency(channel, band->band);
+ freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
notify_channel = ieee80211_get_channel(wiphy, freq);
notify_capability = le16_to_cpu(bi->capability);
@@ -2415,7 +2378,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
notify_ielen = le32_to_cpu(bi->ie_length);
notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
- brcmf_dbg(CONN, "channel: %d(%d)\n", channel, freq);
+ brcmf_dbg(CONN, "channel: %d(%d)\n", ch.chnum, freq);
brcmf_dbg(CONN, "capability: %X\n", notify_capability);
brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
brcmf_dbg(CONN, "signal: %d\n", notify_signal);
@@ -2511,7 +2474,7 @@ void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
if (cfg->scan_request) {
escan->escan_state = WL_ESCAN_STATE_IDLE;
- brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
+ brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
}
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
@@ -2523,7 +2486,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
container_of(work, struct brcmf_cfg80211_info,
escan_timeout_work);
- brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true);
+ brcmf_notify_escan_complete(cfg, cfg->escan_info.ifp, true, true);
}
static void brcmf_escan_timeout(unsigned long data)
@@ -2538,12 +2501,19 @@ static void brcmf_escan_timeout(unsigned long data)
}
static s32
-brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
+brcmf_compare_update_same_bss(struct brcmf_cfg80211_info *cfg,
+ struct brcmf_bss_info_le *bss,
struct brcmf_bss_info_le *bss_info_le)
{
+ struct brcmu_chan ch_bss, ch_bss_info_le;
+
+ ch_bss.chspec = le16_to_cpu(bss->chanspec);
+ cfg->d11inf.decchspec(&ch_bss);
+ ch_bss_info_le.chspec = le16_to_cpu(bss_info_le->chanspec);
+ cfg->d11inf.decchspec(&ch_bss_info_le);
+
if (!memcmp(&bss_info_le->BSSID, &bss->BSSID, ETH_ALEN) &&
- (CHSPEC_BAND(le16_to_cpu(bss_info_le->chanspec)) ==
- CHSPEC_BAND(le16_to_cpu(bss->chanspec))) &&
+ ch_bss.band == ch_bss_info_le.band &&
bss_info_le->SSID_len == bss->SSID_len &&
!memcmp(bss_info_le->SSID, bss->SSID, bss_info_le->SSID_len)) {
if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
@@ -2574,7 +2544,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct net_device *ndev = ifp->ndev;
s32 status;
s32 err = 0;
struct brcmf_escan_result_le *escan_result_le;
@@ -2587,9 +2556,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
status = e->status;
- if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
- brcmf_err("scan not ready ndev %p drv_status %x\n", ndev,
- !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
+ if (!test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+ brcmf_err("scan not ready, bssidx=%d\n", ifp->bssidx);
return -EPERM;
}
@@ -2643,7 +2611,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
bss = bss ? (struct brcmf_bss_info_le *)
((unsigned char *)bss +
le32_to_cpu(bss->length)) : list->bss_info_le;
- if (brcmf_compare_update_same_bss(bss, bss_info_le))
+ if (brcmf_compare_update_same_bss(cfg, bss,
+ bss_info_le))
goto exit;
}
memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
@@ -2660,7 +2629,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
cfg->escan_info.escan_buf;
brcmf_inform_bss(cfg);
aborted = status != BRCMF_E_STATUS_SUCCESS;
- brcmf_notify_escan_complete(cfg, ndev, aborted,
+ brcmf_notify_escan_complete(cfg, ifp, aborted,
false);
} else
brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n",
@@ -2738,7 +2707,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
brcmf_abort_scanning(cfg);
/* Turn off watchdog timer */
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(netdev_priv(ndev), 1);
exit:
brcmf_dbg(TRACE, "Exit\n");
@@ -2896,7 +2865,6 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct net_device *ndev = ifp->ndev;
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
struct cfg80211_scan_request *request = NULL;
struct cfg80211_ssid *ssid = NULL;
@@ -2980,7 +2948,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
}
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
- err = brcmf_do_escan(cfg, wiphy, ndev, request);
+ err = brcmf_do_escan(cfg, wiphy, ifp, request);
if (err) {
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
goto out_err;
@@ -3052,16 +3020,21 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
int i;
int ret = 0;
- brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
+ brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
request->n_match_sets, request->n_ssids);
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
return -EAGAIN;
}
+ if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
+ brcmf_err("Scanning suppressed: status (%lu)\n",
+ cfg->scan_status);
+ return -EAGAIN;
+ }
- if (!request || !request->n_ssids || !request->n_match_sets) {
+ if (!request->n_ssids || !request->n_match_sets) {
brcmf_err("Invalid sched scan req!! n_ssids:%d\n",
- request ? request->n_ssids : 0);
+ request->n_ssids);
return -EINVAL;
}
@@ -3137,7 +3110,7 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
brcmf_dbg(SCAN, "enter\n");
brcmf_dev_pno_clean(ndev);
if (cfg->sched_escan)
- brcmf_notify_escan_complete(cfg, ndev, true, true);
+ brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
return 0;
}
@@ -3709,7 +3682,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
ssid_le.SSID_len = cpu_to_le32((u32)settings->ssid_len);
}
- brcmf_set_mpc(ndev, 0);
+ brcmf_set_mpc(ifp, 0);
/* find the RSN_IE */
rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
@@ -3817,15 +3790,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
exit:
if (err)
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
return err;
}
static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- s32 err = -EPERM;
+ s32 err;
struct brcmf_fil_bss_enable_le bss_enable;
+ struct brcmf_join_params join_params;
brcmf_dbg(TRACE, "Enter\n");
@@ -3833,16 +3807,21 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
/* Due to most likely deauths outstanding we sleep */
/* first to make sure they get processed by fw. */
msleep(400);
- err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
- if (err < 0) {
- brcmf_err("setting AP mode failed %d\n", err);
- goto exit;
- }
+
+ memset(&join_params, 0, sizeof(join_params));
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID,
+ &join_params, sizeof(join_params));
+ if (err < 0)
+ brcmf_err("SET SSID error (%d)\n", err);
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
- if (err < 0) {
+ if (err < 0)
brcmf_err("BRCMF_C_UP error %d\n", err);
- goto exit;
- }
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 0);
+ if (err < 0)
+ brcmf_err("setting AP mode failed %d\n", err);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 0);
+ if (err < 0)
+ brcmf_err("setting INFRA mode failed %d\n", err);
} else {
bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx);
bss_enable.enable = cpu_to_le32(0);
@@ -3851,11 +3830,10 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
if (err < 0)
brcmf_err("bss_enable config failed %d\n", err);
}
- brcmf_set_mpc(ndev, 1);
+ brcmf_set_mpc(ifp, 1);
set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
-exit:
return err;
}
@@ -3909,13 +3887,13 @@ brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
struct wireless_dev *wdev,
u16 frame_type, bool reg)
{
- struct brcmf_if *ifp = netdev_priv(wdev->netdev);
- struct brcmf_cfg80211_vif *vif = ifp->vif;
+ struct brcmf_cfg80211_vif *vif;
u16 mgmt_type;
brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg);
mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4;
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
if (reg)
vif->mgmt_rx_reg |= BIT(mgmt_type);
else
@@ -3931,7 +3909,6 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
const struct ieee80211_mgmt *mgmt;
- struct brcmf_if *ifp;
struct brcmf_cfg80211_vif *vif;
s32 err = 0;
s32 ie_offset;
@@ -3967,8 +3944,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
ie_offset = DOT11_MGMT_HDR_LEN +
DOT11_BCN_PRB_FIXED_LEN;
ie_len = len - ie_offset;
- ifp = netdev_priv(wdev->netdev);
- vif = ifp->vif;
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif)
vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
err = brcmf_vif_set_mgmt_ie(vif,
@@ -4003,7 +3979,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
*cookie, le16_to_cpu(action_frame->len),
chan->center_freq);
- ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev,
+ ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg),
af_params);
cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack,
@@ -4041,6 +4017,39 @@ exit:
return err;
}
+static int brcmf_cfg80211_crit_proto_start(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ enum nl80211_crit_proto_id proto,
+ u16 duration)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ /* only DHCP support for now */
+ if (proto != NL80211_CRIT_PROTO_DHCP)
+ return -EINVAL;
+
+ /* suppress and abort scanning */
+ set_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+ brcmf_abort_scanning(cfg);
+
+ return brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_DISABLED, duration);
+}
+
+static void brcmf_cfg80211_crit_proto_stop(struct wiphy *wiphy,
+ struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+
+ vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
+
+ brcmf_btcoex_set_mode(vif, BRCMF_BTCOEX_ENABLED, 0);
+ clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
+}
+
static struct cfg80211_ops wl_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
@@ -4075,6 +4084,10 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.mgmt_tx = brcmf_cfg80211_mgmt_tx,
.remain_on_channel = brcmf_p2p_remain_on_channel,
.cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel,
+ .start_p2p_device = brcmf_p2p_start_device,
+ .stop_p2p_device = brcmf_p2p_stop_device,
+ .crit_proto_start = brcmf_cfg80211_crit_proto_start,
+ .crit_proto_stop = brcmf_cfg80211_crit_proto_stop,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd = brcmf_cfg80211_testmode
#endif
@@ -4124,10 +4137,6 @@ static const struct ieee80211_iface_limit brcmf_iface_limits[] = {
},
{
.max = 1,
- .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
- },
- {
- .max = 1,
.types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO)
},
@@ -4162,6 +4171,11 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = {
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_DEAUTH >> 4) |
BIT(IEEE80211_STYPE_ACTION >> 4)
+ },
+ [NL80211_IFTYPE_P2P_DEVICE] = {
+ .tx = 0xffff,
+ .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+ BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
}
};
@@ -4183,18 +4197,10 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
+ BIT(NL80211_IFTYPE_P2P_GO);
wiphy->iface_combinations = brcmf_iface_combos;
wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos);
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set
- * it as 11a by default.
- * This will be updated with
- * 11n phy tables in
- * "ifconfig up"
- * if phy has 11n capability
- */
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
@@ -4204,6 +4210,9 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
brcmf_wiphy_pno_params(wiphy);
+ brcmf_dbg(INFO, "Registering custom regulatory\n");
+ wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
err = wiphy_register(wiphy);
if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err);
@@ -4387,9 +4396,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct ieee80211_channel *notify_channel = NULL;
struct ieee80211_supported_band *band;
struct brcmf_bss_info_le *bi;
+ struct brcmu_chan ch;
u32 freq;
s32 err = 0;
- u32 target_channel;
u8 *buf;
brcmf_dbg(TRACE, "Enter\n");
@@ -4413,15 +4422,15 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
goto done;
bi = (struct brcmf_bss_info_le *)(buf + 4);
- target_channel = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+ ch.chspec = le16_to_cpu(bi->chanspec);
+ cfg->d11inf.decchspec(&ch);
- if (target_channel <= CH_MAX_2G_CHANNEL)
+ if (ch.band == BRCMU_CHAN_BAND_2G)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
else
band = wiphy->bands[IEEE80211_BAND_5GHZ];
- freq = ieee80211_channel_to_frequency(target_channel, band->band);
+ freq = ieee80211_channel_to_frequency(ch.chnum, band->band);
notify_channel = ieee80211_get_channel(wiphy, freq);
done:
@@ -4622,9 +4631,11 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
ifp->vif = vif;
vif->ifp = ifp;
- vif->wdev.netdev = ifp->ndev;
- ifp->ndev->ieee80211_ptr = &vif->wdev;
- SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ if (ifp->ndev) {
+ vif->wdev.netdev = ifp->ndev;
+ ifp->ndev->ieee80211_ptr = &vif->wdev;
+ SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy));
+ }
mutex_unlock(&event->vif_event_lock);
wake_up(&event->vif_wq);
return 0;
@@ -4773,6 +4784,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
s32 err = 0;
+ s32 io_type;
if (!ndev) {
brcmf_err("ndev is invalid\n");
@@ -4813,6 +4825,21 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
brcmf_err("P2P initilisation failed (%d)\n", err);
goto cfg80211_p2p_attach_out;
}
+ err = brcmf_btcoex_attach(cfg);
+ if (err) {
+ brcmf_err("BT-coex initialisation failed (%d)\n", err);
+ brcmf_p2p_detach(&cfg->p2p);
+ goto cfg80211_p2p_attach_out;
+ }
+
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_VERSION,
+ &io_type);
+ if (err) {
+ brcmf_err("Failed to get D11 version (%d)\n", err);
+ goto cfg80211_p2p_attach_out;
+ }
+ cfg->d11inf.io_type = (u8)io_type;
+ brcmu_d11_attach(&cfg->d11inf);
return cfg;
@@ -4831,6 +4858,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
struct brcmf_cfg80211_vif *tmp;
wl_deinit_priv(cfg);
+ brcmf_btcoex_detach(cfg);
list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
brcmf_free_vif(vif);
}
@@ -4927,34 +4955,234 @@ dongle_scantime_out:
return err;
}
-static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
+
+static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
+{
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct ieee80211_channel *band_chan_arr;
+ struct brcmf_chanspec_list *list;
+ struct brcmu_chan ch;
+ s32 err;
+ u8 *pbuf;
+ u32 i, j;
+ u32 total;
+ enum ieee80211_band band;
+ u32 channel;
+ u32 *n_cnt;
+ bool ht40_allowed;
+ u32 index;
+ u32 ht40_flag;
+ bool update;
+ u32 array_size;
+
+ pbuf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
+
+ if (pbuf == NULL)
+ return -ENOMEM;
+
+ list = (struct brcmf_chanspec_list *)pbuf;
+
+ err = brcmf_fil_iovar_data_get(ifp, "chanspecs", pbuf,
+ BRCMF_DCMD_MEDLEN);
+ if (err) {
+ brcmf_err("get chanspecs error (%d)\n", err);
+ goto exit;
+ }
+
+ __wl_band_2ghz.n_channels = 0;
+ __wl_band_5ghz_a.n_channels = 0;
+
+ total = le32_to_cpu(list->count);
+ for (i = 0; i < total; i++) {
+ ch.chspec = (u16)le32_to_cpu(list->element[i]);
+ cfg->d11inf.decchspec(&ch);
+
+ if (ch.band == BRCMU_CHAN_BAND_2G) {
+ band_chan_arr = __wl_2ghz_channels;
+ array_size = ARRAY_SIZE(__wl_2ghz_channels);
+ n_cnt = &__wl_band_2ghz.n_channels;
+ band = IEEE80211_BAND_2GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
+ } else if (ch.band == BRCMU_CHAN_BAND_5G) {
+ band_chan_arr = __wl_5ghz_a_channels;
+ array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
+ n_cnt = &__wl_band_5ghz_a.n_channels;
+ band = IEEE80211_BAND_5GHZ;
+ ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
+ } else {
+ brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
+ continue;
+ }
+ if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40)
+ continue;
+ update = false;
+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+ if (band_chan_arr[j].hw_value == ch.chnum) {
+ update = true;
+ break;
+ }
+ }
+ if (update)
+ index = j;
+ else
+ index = *n_cnt;
+ if (index < array_size) {
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(ch.chnum, band);
+ band_chan_arr[index].hw_value = ch.chnum;
+
+ if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
+ /* assuming the order is HT20, HT40 Upper,
+ * HT40 lower from chanspecs
+ */
+ ht40_flag = band_chan_arr[index].flags &
+ IEEE80211_CHAN_NO_HT40;
+ if (ch.sb == BRCMU_CHAN_SB_U) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ /* It should be one of
+ * IEEE80211_CHAN_NO_HT40 or
+ * IEEE80211_CHAN_NO_HT40PLUS
+ */
+ band_chan_arr[index].flags &=
+ ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_NO_HT40MINUS;
+ }
+ } else {
+ band_chan_arr[index].flags =
+ IEEE80211_CHAN_NO_HT40;
+ ch.bw = BRCMU_CHAN_BW_20;
+ cfg->d11inf.encchspec(&ch);
+ channel = ch.chspec;
+ err = brcmf_fil_bsscfg_int_get(ifp,
+ "per_chan_info",
+ &channel);
+ if (!err) {
+ if (channel & WL_CHAN_RADAR)
+ band_chan_arr[index].flags |=
+ (IEEE80211_CHAN_RADAR |
+ IEEE80211_CHAN_NO_IBSS);
+ if (channel & WL_CHAN_PASSIVE)
+ band_chan_arr[index].flags |=
+ IEEE80211_CHAN_PASSIVE_SCAN;
+ }
+ }
+ if (!update)
+ (*n_cnt)++;
+ }
+ }
+exit:
+ kfree(pbuf);
+ return err;
+}
+
+
+static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
{
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
struct wiphy *wiphy;
s32 phy_list;
+ u32 band_list[3];
+ u32 nmode;
+ u32 bw_cap = 0;
s8 phy;
- s32 err = 0;
+ s32 err;
+ u32 nband;
+ s32 i;
+ struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
+ s32 index;
err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
&phy_list, sizeof(phy_list));
if (err) {
- brcmf_err("error (%d)\n", err);
+ brcmf_err("BRCMF_C_GET_PHYLIST error (%d)\n", err);
return err;
}
phy = ((char *)&phy_list)[0];
- brcmf_dbg(INFO, "%c phy\n", phy);
- if (phy == 'n' || phy == 'a') {
- wiphy = cfg_to_wiphy(cfg);
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ brcmf_dbg(INFO, "BRCMF_C_GET_PHYLIST reported: %c phy\n", phy);
+
+
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BANDLIST,
+ &band_list, sizeof(band_list));
+ if (err) {
+ brcmf_err("BRCMF_C_GET_BANDLIST error (%d)\n", err);
+ return err;
}
+ brcmf_dbg(INFO, "BRCMF_C_GET_BANDLIST reported: 0x%08x 0x%08x 0x%08x phy\n",
+ band_list[0], band_list[1], band_list[2]);
+
+ err = brcmf_fil_iovar_int_get(ifp, "nmode", &nmode);
+ if (err) {
+ brcmf_err("nmode error (%d)\n", err);
+ } else {
+ err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
+ if (err)
+ brcmf_err("mimo_bw_cap error (%d)\n", err);
+ }
+ brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
+
+ err = brcmf_construct_reginfo(cfg, bw_cap);
+ if (err) {
+ brcmf_err("brcmf_construct_reginfo failed (%d)\n", err);
+ return err;
+ }
+
+ nband = band_list[0];
+ memset(bands, 0, sizeof(bands));
+
+ for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
+ index = -1;
+ if ((band_list[i] == WLC_BAND_5G) &&
+ (__wl_band_5ghz_a.n_channels > 0)) {
+ index = IEEE80211_BAND_5GHZ;
+ bands[index] = &__wl_band_5ghz_a;
+ if ((bw_cap == WLC_N_BW_40ALL) ||
+ (bw_cap == WLC_N_BW_20IN2G_40IN5G))
+ bands[index]->ht_cap.cap |=
+ IEEE80211_HT_CAP_SGI_40;
+ } else if ((band_list[i] == WLC_BAND_2G) &&
+ (__wl_band_2ghz.n_channels > 0)) {
+ index = IEEE80211_BAND_2GHZ;
+ bands[index] = &__wl_band_2ghz;
+ if (bw_cap == WLC_N_BW_40ALL)
+ bands[index]->ht_cap.cap |=
+ IEEE80211_HT_CAP_SGI_40;
+ }
+
+ if ((index >= 0) && nmode) {
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+ bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+ bands[index]->ht_cap.ht_supported = true;
+ bands[index]->ht_cap.ampdu_factor =
+ IEEE80211_HT_MAX_AMPDU_64K;
+ bands[index]->ht_cap.ampdu_density =
+ IEEE80211_HT_MPDU_DENSITY_16;
+ /* An HT shall support all EQM rates for one spatial
+ * stream
+ */
+ bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+ }
+ }
+
+ wiphy = cfg_to_wiphy(cfg);
+ wiphy->bands[IEEE80211_BAND_2GHZ] = bands[IEEE80211_BAND_2GHZ];
+ wiphy->bands[IEEE80211_BAND_5GHZ] = bands[IEEE80211_BAND_5GHZ];
+ wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
return err;
}
+
static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_info *cfg)
{
- return wl_update_wiphybands(cfg);
+ return brcmf_update_wiphybands(cfg);
}
static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
@@ -5060,6 +5288,13 @@ s32 brcmf_cfg80211_down(struct net_device *ndev)
return err;
}
+enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
+{
+ struct wireless_dev *wdev = &ifp->vif->wdev;
+
+ return wdev->iftype;
+}
+
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state)
{
struct brcmf_cfg80211_vif *vif;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
index 8b5d4989906c..a71cff84cdcf 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
@@ -17,6 +17,9 @@
#ifndef _wl_cfg80211_h_
#define _wl_cfg80211_h_
+/* for brcmu_d11inf */
+#include <brcmu_d11.h>
+
#define WL_NUM_SCAN_MAX 10
#define WL_NUM_PMKIDS_MAX MAXPMKID
#define WL_TLV_INFO_MAX 1024
@@ -74,14 +77,16 @@
/**
- * enum brcmf_scan_status - dongle scan status
+ * enum brcmf_scan_status - scan engine status
*
* @BRCMF_SCAN_STATUS_BUSY: scanning in progress on dongle.
* @BRCMF_SCAN_STATUS_ABORT: scan being aborted on dongle.
+ * @BRCMF_SCAN_STATUS_SUPPRESS: scanning is suppressed in driver.
*/
enum brcmf_scan_status {
BRCMF_SCAN_STATUS_BUSY,
BRCMF_SCAN_STATUS_ABORT,
+ BRCMF_SCAN_STATUS_SUPPRESS,
};
/**
@@ -238,9 +243,8 @@ struct escan_info {
u32 escan_state;
u8 escan_buf[WL_ESCAN_BUF_SIZE];
struct wiphy *wiphy;
- struct net_device *ndev;
- s32 (*run)(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
+ struct brcmf_if *ifp;
+ s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
struct cfg80211_scan_request *request, u16 action);
};
@@ -347,6 +351,7 @@ struct brcmf_cfg80211_vif_event {
* @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration.
* @p2p: peer-to-peer specific information.
+ * @btcoex: Bluetooth coexistence information.
* @scan_request: cfg80211 scan request object.
* @usr_sync: mainly for dongle up/down synchronization.
* @bss_list: bss_list holding scanned ap information.
@@ -380,6 +385,7 @@ struct brcmf_cfg80211_info {
struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf;
struct brcmf_p2p_info p2p;
+ struct brcmf_btcoex_info *btcoex;
struct cfg80211_scan_request *scan_request;
struct mutex usr_sync;
struct brcmf_scan_results *bss_list;
@@ -409,6 +415,7 @@ struct brcmf_cfg80211_info {
u8 vif_cnt;
struct brcmf_cfg80211_vif_event vif_event;
struct completion vif_disabled;
+ struct brcmu_d11inf d11inf;
};
/**
@@ -475,6 +482,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(struct net_device *ndev);
+enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type,
@@ -485,7 +493,8 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
const u8 *vndr_ie_buf, u32 vndr_ie_len);
s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif);
struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key);
-u16 channel_to_chanspec(struct ieee80211_channel *ch);
+u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
+ struct ieee80211_channel *ch);
u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state);
void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
@@ -493,9 +502,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout);
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
- struct net_device *ndev,
- bool aborted, bool fw_abort);
-void brcmf_set_mpc(struct net_device *ndev, int mpc);
+ struct brcmf_if *ifp, bool aborted,
+ bool fw_abort);
+void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
index d3d4151c3eda..32464acccd90 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
@@ -21,7 +21,7 @@ ccflags-y := \
-Idrivers/net/wireless/brcm80211/brcmsmac/phy \
-Idrivers/net/wireless/brcm80211/include
-BRCMSMAC_OFILES := \
+brcmsmac-y := \
mac80211_if.o \
ucode_loader.o \
ampdu.o \
@@ -43,7 +43,6 @@ BRCMSMAC_OFILES := \
brcms_trace_events.o \
debug.o
-MODULEPFX := brcmsmac
+brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o
-obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o
-$(MODULEPFX)-objs = $(BRCMSMAC_OFILES)
+obj-$(CONFIG_BRCMSMAC) += brcmsmac.o
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
index f0888a9ee32e..e4fd1ee3d690 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -318,12 +318,6 @@
#define IS_SIM(chippkg) \
((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
-#ifdef DEBUG
-#define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__)
-#else
-#define SI_MSG(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif /* DEBUG */
-
#define GOODCOREADDR(x, b) \
(((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
IS_ALIGNED((x), SI_CORE_SIZE))
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 10ee314c4229..cc87926f5055 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -379,7 +379,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
u8 local_constraint_qdbm)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
- struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
+ struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
struct txpwr_limits txpwr;
brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
@@ -404,7 +404,7 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
struct txpwr_limits *txpwr)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
- struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
+ struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
uint i;
uint chan;
int maxpwr;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
index 3f659e09f1cc..9035cc4d6ff3 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/d11.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h
@@ -457,6 +457,7 @@ struct d11regs {
/*== maccontrol register ==*/
#define MCTL_GMODE (1U << 31)
#define MCTL_DISCARD_PMQ (1 << 30)
+#define MCTL_TBTTHOLD (1 << 28)
#define MCTL_WAKE (1 << 26)
#define MCTL_HPS (1 << 25)
#define MCTL_PROMISC (1 << 24)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.c b/drivers/net/wireless/brcm80211/brcmsmac/led.c
new file mode 100644
index 000000000000..74b17cecb189
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/led.c
@@ -0,0 +1,126 @@
+#include <net/mac80211.h>
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/gpio.h>
+
+#include "mac80211_if.h"
+#include "pub.h"
+#include "main.h"
+#include "led.h"
+
+ /* number of leds */
+#define BRCMS_LED_NO 4
+ /* behavior mask */
+#define BRCMS_LED_BEH_MASK 0x7f
+ /* activelow (polarity) bit */
+#define BRCMS_LED_AL_MASK 0x80
+ /* radio enabled */
+#define BRCMS_LED_RADIO 3
+
+static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state)
+{
+ if (wl->radio_led.gpio == -1)
+ return;
+
+ if (wl->radio_led.active_low)
+ state = !state;
+
+ if (state)
+ gpio_set_value(wl->radio_led.gpio, 1);
+ else
+ gpio_set_value(wl->radio_led.gpio, 0);
+}
+
+
+/* Callback from the LED subsystem. */
+static void brcms_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct brcms_info *wl = container_of(led_dev,
+ struct brcms_info, led_dev);
+ brcms_radio_led_ctrl(wl, brightness);
+}
+
+void brcms_led_unregister(struct brcms_info *wl)
+{
+ if (wl->led_dev.dev)
+ led_classdev_unregister(&wl->led_dev);
+ if (wl->radio_led.gpio != -1)
+ gpio_free(wl->radio_led.gpio);
+}
+
+int brcms_led_register(struct brcms_info *wl)
+{
+ int i, err;
+ struct brcms_led *radio_led = &wl->radio_led;
+ /* get CC core */
+ struct bcma_drv_cc *cc_drv = &wl->wlc->hw->d11core->bus->drv_cc;
+ struct gpio_chip *bcma_gpio = &cc_drv->gpio;
+ struct ssb_sprom *sprom = &wl->wlc->hw->d11core->bus->sprom;
+ u8 *leds[] = { &sprom->gpio0,
+ &sprom->gpio1,
+ &sprom->gpio2,
+ &sprom->gpio3 };
+ unsigned gpio = -1;
+ bool active_low = false;
+
+ /* none by default */
+ radio_led->gpio = -1;
+ radio_led->active_low = false;
+
+ if (!bcma_gpio || !gpio_is_valid(bcma_gpio->base))
+ return -ENODEV;
+
+ /* find radio enabled LED */
+ for (i = 0; i < BRCMS_LED_NO; i++) {
+ u8 led = *leds[i];
+ if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) {
+ gpio = bcma_gpio->base + i;
+ if (led & BRCMS_LED_AL_MASK)
+ active_low = true;
+ break;
+ }
+ }
+
+ if (gpio == -1 || !gpio_is_valid(gpio))
+ return -ENODEV;
+
+ /* request and configure LED gpio */
+ err = gpio_request_one(gpio,
+ active_low ? GPIOF_OUT_INIT_HIGH
+ : GPIOF_OUT_INIT_LOW,
+ "radio on");
+ if (err) {
+ wiphy_err(wl->wiphy, "requesting led gpio %d failed (err: %d)\n",
+ gpio, err);
+ return err;
+ }
+ err = gpio_direction_output(gpio, 1);
+ if (err) {
+ wiphy_err(wl->wiphy, "cannot set led gpio %d to output (err: %d)\n",
+ gpio, err);
+ return err;
+ }
+
+ snprintf(wl->radio_led.name, sizeof(wl->radio_led.name),
+ "brcmsmac-%s:radio", wiphy_name(wl->wiphy));
+
+ wl->led_dev.name = wl->radio_led.name;
+ wl->led_dev.default_trigger =
+ ieee80211_get_radio_led_name(wl->pub->ieee_hw);
+ wl->led_dev.brightness_set = brcms_led_brightness_set;
+ err = led_classdev_register(wiphy_dev(wl->wiphy), &wl->led_dev);
+
+ if (err) {
+ wiphy_err(wl->wiphy, "cannot register led device: %s (err: %d)\n",
+ wl->radio_led.name, err);
+ return err;
+ }
+
+ wiphy_info(wl->wiphy, "registered radio enabled led device: %s gpio: %d\n",
+ wl->radio_led.name,
+ gpio);
+ radio_led->gpio = gpio;
+ radio_led->active_low = active_low;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/led.h b/drivers/net/wireless/brcm80211/brcmsmac/led.h
new file mode 100644
index 000000000000..17a0b1f5dbcf
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmsmac/led.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BRCM_LED_H_
+#define _BRCM_LED_H_
+struct brcms_led {
+ char name[32];
+ unsigned gpio;
+ bool active_low;
+};
+
+#ifdef CONFIG_BCMA_DRIVER_GPIO
+void brcms_led_unregister(struct brcms_info *wl);
+int brcms_led_register(struct brcms_info *wl);
+#else
+static inline void brcms_led_unregister(struct brcms_info *wl) {};
+static inline int brcms_led_register(struct brcms_info *wl)
+{
+ return -ENOTSUPP;
+};
+#endif
+
+#endif /* _BRCM_LED_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index c6451c61407a..3a6544710c8a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010 Broadcom Corporation
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -34,6 +35,7 @@
#include "mac80211_if.h"
#include "main.h"
#include "debug.h"
+#include "led.h"
#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
#define BRCMS_FLUSH_TIMEOUT 500 /* msec */
@@ -274,6 +276,131 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)
}
}
+/**
+ * This function frees the WL per-device resources.
+ *
+ * This function frees resources owned by the WL device pointed to
+ * by the wl parameter.
+ *
+ * precondition: can both be called locked and unlocked
+ *
+ */
+static void brcms_free(struct brcms_info *wl)
+{
+ struct brcms_timer *t, *next;
+
+ /* free ucode data */
+ if (wl->fw.fw_cnt)
+ brcms_ucode_data_free(&wl->ucode);
+ if (wl->irq)
+ free_irq(wl->irq, wl);
+
+ /* kill dpc */
+ tasklet_kill(&wl->tasklet);
+
+ if (wl->pub) {
+ brcms_debugfs_detach(wl->pub);
+ brcms_c_module_unregister(wl->pub, "linux", wl);
+ }
+
+ /* free common resources */
+ if (wl->wlc) {
+ brcms_c_detach(wl->wlc);
+ wl->wlc = NULL;
+ wl->pub = NULL;
+ }
+
+ /* virtual interface deletion is deferred so we cannot spinwait */
+
+ /* wait for all pending callbacks to complete */
+ while (atomic_read(&wl->callbacks) > 0)
+ schedule();
+
+ /* free timers */
+ for (t = wl->timers; t; t = next) {
+ next = t->next;
+#ifdef DEBUG
+ kfree(t->name);
+#endif
+ kfree(t);
+ }
+}
+
+/*
+* called from both kernel as from this kernel module (error flow on attach)
+* precondition: perimeter lock is not acquired.
+*/
+static void brcms_remove(struct bcma_device *pdev)
+{
+ struct ieee80211_hw *hw = bcma_get_drvdata(pdev);
+ struct brcms_info *wl = hw->priv;
+
+ if (wl->wlc) {
+ brcms_led_unregister(wl);
+ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
+ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+ ieee80211_unregister_hw(hw);
+ }
+
+ brcms_free(wl);
+
+ bcma_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static void brcms_release_fw(struct brcms_info *wl)
+{
+ int i;
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ release_firmware(wl->fw.fw_bin[i]);
+ release_firmware(wl->fw.fw_hdr[i]);
+ }
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
+{
+ int status;
+ struct device *device = &pdev->dev;
+ char fw_name[100];
+ int i;
+
+ memset(&wl->fw, 0, sizeof(struct brcms_firmware));
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ if (brcms_firmwares[i] == NULL)
+ break;
+ sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ wl->fw.hdr_num_entries[i] =
+ wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
+ }
+ wl->fw.fw_cnt = i;
+ status = brcms_ucode_data_init(wl, &wl->ucode);
+ brcms_release_fw(wl);
+ return status;
+}
+
static void brcms_ops_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
@@ -306,6 +433,14 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
if (!blocked)
wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+ if (!wl->ucode.bcm43xx_bomminor) {
+ err = brcms_request_fw(wl, wl->wlc->hw->d11core);
+ if (err) {
+ brcms_remove(wl->wlc->hw->d11core);
+ return -ENOENT;
+ }
+ }
+
spin_lock_bh(&wl->lock);
/* avoid acknowledging frames before a non-monitor device is added */
wl->mute_tx = true;
@@ -355,18 +490,26 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct brcms_info *wl = hw->priv;
- /* Just STA for now */
- if (vif->type != NL80211_IFTYPE_STATION) {
+ /* Just STA, AP and ADHOC for now */
+ if (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_ADHOC) {
brcms_err(wl->wlc->hw->d11core,
- "%s: Attempt to add type %d, only STA for now\n",
+ "%s: Attempt to add type %d, only STA, AP and AdHoc for now\n",
__func__, vif->type);
return -EOPNOTSUPP;
}
spin_lock_bh(&wl->lock);
- memcpy(wl->pub->cur_etheraddr, vif->addr, sizeof(vif->addr));
wl->mute_tx = false;
brcms_c_mute(wl->wlc, false);
+ if (vif->type == NL80211_IFTYPE_STATION)
+ brcms_c_start_station(wl->wlc, vif->addr);
+ else if (vif->type == NL80211_IFTYPE_AP)
+ brcms_c_start_ap(wl->wlc, vif->addr, vif->bss_conf.bssid,
+ vif->bss_conf.ssid, vif->bss_conf.ssid_len);
+ else if (vif->type == NL80211_IFTYPE_ADHOC)
+ brcms_c_start_adhoc(wl->wlc, vif->addr);
spin_unlock_bh(&wl->lock);
return 0;
@@ -414,10 +557,10 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
new_int);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- if (conf->channel_type == NL80211_CHAN_HT20 ||
- conf->channel_type == NL80211_CHAN_NO_HT)
+ if (conf->chandef.width == NL80211_CHAN_WIDTH_20 ||
+ conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
err = brcms_c_set_channel(wl->wlc,
- conf->channel->hw_value);
+ conf->chandef.chan->hw_value);
else
err = -ENOTSUPP;
}
@@ -518,14 +661,43 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
spin_unlock_bh(&wl->lock);
}
- if (changed & BSS_CHANGED_BEACON)
+ if (changed & BSS_CHANGED_SSID) {
+ /* BSSID changed, for whatever reason (IBSS and managed mode) */
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_ssid(wl->wlc, info->ssid, info->ssid_len);
+ spin_unlock_bh(&wl->lock);
+ }
+ if (changed & BSS_CHANGED_BEACON) {
/* Beacon data changed, retrieve new beacon (beaconing modes) */
- brcms_err(core, "%s: beacon changed\n", __func__);
+ struct sk_buff *beacon;
+ u16 tim_offset = 0;
+
+ spin_lock_bh(&wl->lock);
+ beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL);
+ brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
+ info->dtim_period);
+ spin_unlock_bh(&wl->lock);
+ }
+
+ if (changed & BSS_CHANGED_AP_PROBE_RESP) {
+ struct sk_buff *probe_resp;
+
+ spin_lock_bh(&wl->lock);
+ probe_resp = ieee80211_proberesp_get(hw, vif);
+ brcms_c_set_new_probe_resp(wl->wlc, probe_resp);
+ spin_unlock_bh(&wl->lock);
+ }
if (changed & BSS_CHANGED_BEACON_ENABLED) {
/* Beaconing should be enabled/disabled (beaconing modes) */
brcms_err(core, "%s: Beacon enabled: %s\n", __func__,
info->enable_beacon ? "true" : "false");
+ if (info->enable_beacon &&
+ hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) {
+ brcms_c_enable_probe_resp(wl->wlc, true);
+ } else {
+ brcms_c_enable_probe_resp(wl->wlc, false);
+ }
}
if (changed & BSS_CHANGED_CQM) {
@@ -723,7 +895,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
return result;
}
-static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
+static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct brcms_info *wl = hw->priv;
int ret;
@@ -738,6 +910,28 @@ static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
"ret=%d\n", jiffies_to_msecs(ret));
}
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+{
+ struct brcms_info *wl = hw->priv;
+ u64 tsf;
+
+ spin_lock_bh(&wl->lock);
+ tsf = brcms_c_tsf_get(wl->wlc);
+ spin_unlock_bh(&wl->lock);
+
+ return tsf;
+}
+
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 tsf)
+{
+ struct brcms_info *wl = hw->priv;
+
+ spin_lock_bh(&wl->lock);
+ brcms_c_tsf_set(wl->wlc, tsf);
+ spin_unlock_bh(&wl->lock);
+}
+
static const struct ieee80211_ops brcms_ops = {
.tx = brcms_ops_tx,
.start = brcms_ops_start,
@@ -754,6 +948,8 @@ static const struct ieee80211_ops brcms_ops = {
.ampdu_action = brcms_ops_ampdu_action,
.rfkill_poll = brcms_ops_rfkill_poll,
.flush = brcms_ops_flush,
+ .get_tsf = brcms_ops_get_tsf,
+ .set_tsf = brcms_ops_set_tsf,
};
void brcms_dpc(unsigned long data)
@@ -793,128 +989,6 @@ void brcms_dpc(unsigned long data)
wake_up(&wl->tx_flush_wq);
}
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
-{
- int status;
- struct device *device = &pdev->dev;
- char fw_name[100];
- int i;
-
- memset(&wl->fw, 0, sizeof(struct brcms_firmware));
- for (i = 0; i < MAX_FW_IMAGES; i++) {
- if (brcms_firmwares[i] == NULL)
- break;
- sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
- UCODE_LOADER_API_VER);
- status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
- if (status) {
- wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
- KBUILD_MODNAME, fw_name);
- return status;
- }
- sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
- UCODE_LOADER_API_VER);
- status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
- if (status) {
- wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
- KBUILD_MODNAME, fw_name);
- return status;
- }
- wl->fw.hdr_num_entries[i] =
- wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
- }
- wl->fw.fw_cnt = i;
- return brcms_ucode_data_init(wl, &wl->ucode);
-}
-
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static void brcms_release_fw(struct brcms_info *wl)
-{
- int i;
- for (i = 0; i < MAX_FW_IMAGES; i++) {
- release_firmware(wl->fw.fw_bin[i]);
- release_firmware(wl->fw.fw_hdr[i]);
- }
-}
-
-/**
- * This function frees the WL per-device resources.
- *
- * This function frees resources owned by the WL device pointed to
- * by the wl parameter.
- *
- * precondition: can both be called locked and unlocked
- *
- */
-static void brcms_free(struct brcms_info *wl)
-{
- struct brcms_timer *t, *next;
-
- /* free ucode data */
- if (wl->fw.fw_cnt)
- brcms_ucode_data_free(&wl->ucode);
- if (wl->irq)
- free_irq(wl->irq, wl);
-
- /* kill dpc */
- tasklet_kill(&wl->tasklet);
-
- if (wl->pub) {
- brcms_debugfs_detach(wl->pub);
- brcms_c_module_unregister(wl->pub, "linux", wl);
- }
-
- /* free common resources */
- if (wl->wlc) {
- brcms_c_detach(wl->wlc);
- wl->wlc = NULL;
- wl->pub = NULL;
- }
-
- /* virtual interface deletion is deferred so we cannot spinwait */
-
- /* wait for all pending callbacks to complete */
- while (atomic_read(&wl->callbacks) > 0)
- schedule();
-
- /* free timers */
- for (t = wl->timers; t; t = next) {
- next = t->next;
-#ifdef DEBUG
- kfree(t->name);
-#endif
- kfree(t);
- }
-}
-
-/*
-* called from both kernel as from this kernel module (error flow on attach)
-* precondition: perimeter lock is not acquired.
-*/
-static void brcms_remove(struct bcma_device *pdev)
-{
- struct ieee80211_hw *hw = bcma_get_drvdata(pdev);
- struct brcms_info *wl = hw->priv;
-
- if (wl->wlc) {
- wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
- wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
- ieee80211_unregister_hw(hw);
- }
-
- brcms_free(wl);
-
- bcma_set_drvdata(pdev, NULL);
- ieee80211_free_hw(hw);
-}
-
static irqreturn_t brcms_isr(int irq, void *dev_id)
{
struct brcms_info *wl;
@@ -994,7 +1068,16 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
/* channel change time is dependent on chip and band */
hw->channel_change_time = 7 * 1000;
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
+ /*
+ * deactivate sending probe responses by ucude, because this will
+ * cause problems when WPS is used.
+ *
+ * hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+ */
hw->rate_control_algorithm = "minstrel_ht";
@@ -1047,18 +1130,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
spin_lock_init(&wl->lock);
spin_lock_init(&wl->isr_lock);
- /* prepare ucode */
- if (brcms_request_fw(wl, pdev) < 0) {
- wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
- "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
- brcms_release_fw(wl);
- brcms_remove(pdev);
- return NULL;
- }
-
/* common load-time initialization */
wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err);
- brcms_release_fw(wl);
if (!wl->wlc) {
wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
KBUILD_MODNAME, err);
@@ -1151,6 +1224,8 @@ static int brcms_bcma_probe(struct bcma_device *pdev)
pr_err("%s: brcms_attach failed!\n", __func__);
return -ENODEV;
}
+ brcms_led_register(wl);
+
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
index 947ccacf43e6..4090032e81a2 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
@@ -20,8 +20,10 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
+#include <linux/leds.h>
#include "ucode_loader.h"
+#include "led.h"
/*
* Starting index for 5G rates in the
* legacy rate table.
@@ -81,6 +83,8 @@ struct brcms_info {
struct wiphy *wiphy;
struct brcms_ucode ucode;
bool mute_tx;
+ struct brcms_led radio_led;
+ struct led_classdev led_dev;
};
/* misc callbacks */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 8ef02dca8f8c..28e7aeedd184 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010 Broadcom Corporation
+ * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -448,6 +449,10 @@ static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
kfree(wlc->corestate);
kfree(wlc->hw->bandstate[0]);
kfree(wlc->hw);
+ if (wlc->beacon)
+ dev_kfree_skb_any(wlc->beacon);
+ if (wlc->probe_resp)
+ dev_kfree_skb_any(wlc->probe_resp);
/* free the wlc */
kfree(wlc);
@@ -1069,7 +1074,7 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
static void brcms_c_tbtt(struct brcms_c_info *wlc)
{
- if (!wlc->bsscfg->BSS)
+ if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
/*
* DirFrmQ is now valid...defer setting until end
* of ATIM window
@@ -2163,6 +2168,32 @@ void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
}
}
+void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr)
+{
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ wlc->bsscfg->type = BRCMS_TYPE_STATION;
+}
+
+void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid,
+ u8 *ssid, size_t ssid_len)
+{
+ brcms_c_set_ssid(wlc, ssid, ssid_len);
+
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ memcpy(wlc->bsscfg->BSSID, bssid, sizeof(wlc->bsscfg->BSSID));
+ wlc->bsscfg->type = BRCMS_TYPE_AP;
+
+ brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, MCTL_AP | MCTL_INFRA);
+}
+
+void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr)
+{
+ memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));
+ wlc->bsscfg->type = BRCMS_TYPE_ADHOC;
+
+ brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, 0);
+}
+
/* Initialize GPIOs that are controlled by D11 core */
static void brcms_c_gpio_init(struct brcms_c_info *wlc)
{
@@ -3043,8 +3074,6 @@ static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
*/
static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
{
- struct brcms_bss_cfg *cfg = wlc->bsscfg;
-
/* disallow PS when one of the following global conditions meets */
if (!wlc->pub->associated)
return false;
@@ -3053,16 +3082,11 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
if (wlc->filter_flags & FIF_PROMISC_IN_BSS)
return false;
- if (cfg->associated) {
- /*
- * disallow PS when one of the following
- * bsscfg specific conditions meets
- */
- if (!cfg->BSS)
- return false;
+ if (wlc->bsscfg->type == BRCMS_TYPE_AP)
+ return false;
+ if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)
return false;
- }
return true;
}
@@ -3771,7 +3795,7 @@ static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
struct brcms_c_info *wlc = bsscfg->wlc;
/* enter the MAC addr into the RXE match registers */
- brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
+ brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, wlc->pub->cur_etheraddr);
brcms_c_ampdu_macaddr_upd(wlc);
@@ -3787,6 +3811,15 @@ static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
}
+void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len)
+{
+ u8 len = min_t(u8, sizeof(wlc->bsscfg->SSID), ssid_len);
+ memset(wlc->bsscfg->SSID, 0, sizeof(wlc->bsscfg->SSID));
+
+ memcpy(wlc->bsscfg->SSID, ssid, len);
+ wlc->bsscfg->SSID_len = len;
+}
+
static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
{
wlc_hw->shortslot = shortslot;
@@ -3821,7 +3854,7 @@ static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
if (wlc->home_chanspec != chanspec) {
wlc->home_chanspec = chanspec;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
wlc->bsscfg->current_bss->chanspec = chanspec;
}
}
@@ -4091,10 +4124,14 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
*shm_entry++);
}
- if (suspend) {
+ if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
+
+ brcms_c_update_beacon(wlc);
+ brcms_c_update_probe_resp(wlc, false);
+
+ if (suspend)
brcms_c_enable_mac(wlc);
- }
}
static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
@@ -4332,7 +4369,6 @@ static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
/* WME QoS mode is Auto by default */
wlc->pub->_ampdu = AMPDU_AGG_HOST;
- wlc->pub->bcmerror = 0;
}
static uint brcms_c_attach_module(struct brcms_c_info *wlc)
@@ -5072,8 +5108,8 @@ int brcms_c_up(struct brcms_c_info *wlc)
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
mboolset(wlc->pub->radio_disabled,
WL_RADIO_HW_DISABLE);
-
- if (bsscfg->enable && bsscfg->BSS)
+ if (bsscfg->type == BRCMS_TYPE_STATION ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)
brcms_err(wlc->hw->d11core,
"wl%d: up: rfdisable -> "
"bsscfg_disable()\n",
@@ -5099,7 +5135,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
wlc->pub->up = true;
if (wlc->bandinit_pending) {
- ch = wlc->pub->ieee_hw->conf.channel;
+ ch = wlc->pub->ieee_hw->conf.chandef.chan;
brcms_c_suspend_mac_and_wait(wlc);
brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));
wlc->bandinit_pending = false;
@@ -5434,7 +5470,7 @@ static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
u8 r;
bool war = false;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
r = wlc->bsscfg->current_bss->rateset.rates[0];
else
r = wlc->default_bss->rateset.rates[0];
@@ -5528,7 +5564,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
/* merge rateset coming in with the current mcsset */
if (wlc->pub->_n_enab & SUPPORT_11N) {
struct brcms_bss_info *mcsset_bss;
- if (wlc->bsscfg->associated)
+ if (wlc->pub->associated)
mcsset_bss = wlc->bsscfg->current_bss;
else
mcsset_bss = wlc->default_bss;
@@ -5543,12 +5579,36 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
return bcmerror;
}
+static void brcms_c_time_lock(struct brcms_c_info *wlc)
+{
+ bcma_set32(wlc->hw->d11core, D11REGOFFS(maccontrol), MCTL_TBTTHOLD);
+ /* Commit the write */
+ bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+}
+
+static void brcms_c_time_unlock(struct brcms_c_info *wlc)
+{
+ bcma_mask32(wlc->hw->d11core, D11REGOFFS(maccontrol), ~MCTL_TBTTHOLD);
+ /* Commit the write */
+ bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
+}
+
int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
{
+ u32 bcnint_us;
+
if (period == 0)
return -EINVAL;
wlc->default_bss->beacon_period = period;
+
+ bcnint_us = period << 10;
+ brcms_c_time_lock(wlc);
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfprep),
+ (bcnint_us << CFPREP_CBI_SHIFT));
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfpstart), bcnint_us);
+ brcms_c_time_unlock(wlc);
+
return 0;
}
@@ -7291,72 +7351,110 @@ brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
}
}
-/* Max buffering needed for beacon template/prb resp template is 142 bytes.
- *
- * PLCP header is 6 bytes.
- * 802.11 A3 header is 24 bytes.
- * Max beacon frame body template length is 112 bytes.
- * Max probe resp frame body template length is 110 bytes.
- *
- * *len on input contains the max length of the packet available.
- *
- * The *len value is set to the number of bytes in buf used, and starts
- * with the PLCP and included up to, but not including, the 4 byte FCS.
- */
-static void
-brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
- u32 bcn_rspec,
- struct brcms_bss_cfg *cfg, u16 *buf, int *len)
+int brcms_c_get_header_len(void)
{
- static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
- struct cck_phy_hdr *plcp;
- struct ieee80211_mgmt *h;
- int hdr_len, body_len;
-
- hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
+ return TXOFF;
+}
- /* calc buffer size provided for frame body */
- body_len = *len - hdr_len;
- /* return actual size */
- *len = hdr_len + body_len;
+static void brcms_c_beacon_write(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period, bool bcn0, bool bcn1)
+{
+ size_t len;
+ struct ieee80211_tx_info *tx_info;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;
- /* format PHY and MAC headers */
- memset(buf, 0, hdr_len);
+ /* Get tx_info */
+ tx_info = IEEE80211_SKB_CB(beacon);
- plcp = (struct cck_phy_hdr *) buf;
+ len = min_t(size_t, beacon->len, BCN_TMPL_LEN);
+ wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;
- /*
- * PLCP for Probe Response frames are filled in from
- * core's rate table
- */
- if (type == IEEE80211_STYPE_BEACON)
- /* fill in PLCP */
- brcms_c_compute_plcp(wlc, bcn_rspec,
- (DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
- (u8 *) plcp);
+ brcms_c_compute_plcp(wlc, wlc->bcn_rspec,
+ len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);
/* "Regular" and 16 MBSS but not for 4 MBSS */
/* Update the phytxctl for the beacon based on the rspec */
- brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+ brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
- h = (struct ieee80211_mgmt *)&plcp[1];
+ if (bcn0) {
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,
+ (len + 3) & ~3, beacon->data);
- /* fill in 802.11 header */
- h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
+ /* write beacon length to SCR */
+ brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
+ }
+ if (bcn1) {
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,
+ (len + 3) & ~3, beacon->data);
- /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */
- /* A1 filled in by MAC for prb resp, broadcast for bcn */
- if (type == IEEE80211_STYPE_BEACON)
- memcpy(&h->da, &ether_bcast, ETH_ALEN);
- memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN);
- memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
+ /* write beacon length to SCR */
+ brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
+ }
- /* SEQ filled in by MAC */
+ if (tim_offset != 0) {
+ brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
+ tim_offset + D11B_PHY_HDR_LEN);
+ brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);
+ } else {
+ brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
+ len + D11B_PHY_HDR_LEN);
+ brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);
+ }
}
-int brcms_c_get_header_len(void)
+static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period)
{
- return TXOFF;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct bcma_device *core = wlc_hw->d11core;
+
+ /* Hardware beaconing for this config */
+ u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
+
+ /* Check if both templates are in use, if so sched. an interrupt
+ * that will call back into this routine
+ */
+ if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)
+ /* clear any previous status */
+ bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);
+
+ if (wlc->beacon_template_virgin) {
+ wlc->beacon_template_virgin = false;
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
+ true);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
+ return;
+ }
+
+ /* Check that after scheduling the interrupt both of the
+ * templates are still busy. if not clear the int. & remask
+ */
+ if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {
+ wlc->defmacintmask |= MI_BCNTPL;
+ return;
+ }
+
+ if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
+ false);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
+ return;
+ }
+ if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {
+ brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,
+ false, true);
+ /* mark beacon0 valid */
+ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);
+ return;
+ }
+ return;
}
/*
@@ -7366,9 +7464,57 @@ void brcms_c_update_beacon(struct brcms_c_info *wlc)
{
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
- if (bsscfg->up && !bsscfg->BSS)
+ if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)) {
/* Clear the soft intmask */
wlc->defmacintmask &= ~MI_BCNTPL;
+ if (!wlc->beacon)
+ return;
+ brcms_c_update_beacon_hw(wlc, wlc->beacon,
+ wlc->beacon_tim_offset,
+ wlc->beacon_dtim_period);
+ }
+}
+
+void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,
+ u16 tim_offset, u16 dtim_period)
+{
+ if (!beacon)
+ return;
+ if (wlc->beacon)
+ dev_kfree_skb_any(wlc->beacon);
+ wlc->beacon = beacon;
+
+ /* add PLCP */
+ skb_push(wlc->beacon, D11_PHY_HDR_LEN);
+ wlc->beacon_tim_offset = tim_offset;
+ wlc->beacon_dtim_period = dtim_period;
+ brcms_c_update_beacon(wlc);
+}
+
+void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
+ struct sk_buff *probe_resp)
+{
+ if (!probe_resp)
+ return;
+ if (wlc->probe_resp)
+ dev_kfree_skb_any(wlc->probe_resp);
+ wlc->probe_resp = probe_resp;
+
+ /* add PLCP */
+ skb_push(wlc->probe_resp, D11_PHY_HDR_LEN);
+ brcms_c_update_probe_resp(wlc, false);
+}
+
+void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable)
+{
+ /*
+ * prevent ucode from sending probe responses by setting the timeout
+ * to 1, it can not send it in that time frame.
+ */
+ wlc->prb_resp_timeout = enable ? BRCMS_PRB_RESP_TIMEOUT : 1;
+ brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+ /* TODO: if (enable) => also deactivate receiving of probe request */
}
/* Write ssid into shared memory */
@@ -7390,30 +7536,19 @@ brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
static void
brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
struct brcms_bss_cfg *cfg,
+ struct sk_buff *probe_resp,
bool suspend)
{
- u16 *prb_resp;
- int len = BCN_TMPL_LEN;
-
- prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC);
- if (!prb_resp)
- return;
-
- /*
- * write the probe response to hardware, or save in
- * the config structure
- */
+ int len;
- /* create the probe response template */
- brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
- cfg, prb_resp, &len);
+ len = min_t(size_t, probe_resp->len, BCN_TMPL_LEN);
if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
/* write the probe response into the template region */
brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
- (len + 3) & ~3, prb_resp);
+ (len + 3) & ~3, probe_resp->data);
/* write the length of the probe response frame (+PLCP/-FCS) */
brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
@@ -7427,13 +7562,11 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
* PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
* by subtracting the PLCP len and adding the FCS.
*/
- len += (-D11_PHY_HDR_LEN + FCS_LEN);
- brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+ brcms_c_mod_prb_rsp_rate_table(wlc,
+ (u16)len + FCS_LEN - D11_PHY_HDR_LEN);
if (suspend)
brcms_c_enable_mac(wlc);
-
- kfree(prb_resp);
}
void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
@@ -7441,8 +7574,13 @@ void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
/* update AP or IBSS probe responses */
- if (bsscfg->up && !bsscfg->BSS)
- brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
+ if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
+ bsscfg->type == BRCMS_TYPE_ADHOC)) {
+ if (!wlc->probe_resp)
+ return;
+ brcms_c_bss_update_probe_resp(wlc, bsscfg, wlc->probe_resp,
+ suspend);
+ }
}
int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
@@ -7481,7 +7619,6 @@ void brcms_c_scan_stop(struct brcms_c_info *wlc)
void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
{
wlc->pub->associated = state;
- wlc->bsscfg->associated = state;
}
/*
@@ -7526,6 +7663,36 @@ void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
brcms_c_bcn_li_upd(wlc);
}
+u64 brcms_c_tsf_get(struct brcms_c_info *wlc)
+{
+ u32 tsf_h, tsf_l;
+ u64 tsf;
+
+ brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
+
+ tsf = tsf_h;
+ tsf <<= 32;
+ tsf |= tsf_l;
+
+ return tsf;
+}
+
+void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf)
+{
+ u32 tsf_h, tsf_l;
+
+ brcms_c_time_lock(wlc);
+
+ tsf_l = tsf;
+ tsf_h = (tsf >> 32);
+
+ /* read the tsf timer low, then high to get an atomic read */
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerlow), tsf_l);
+ bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerhigh), tsf_h);
+
+ brcms_c_time_unlock(wlc);
+}
+
int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
{
uint qdbm;
@@ -7737,6 +7904,10 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
brcms_rfkill_set_hw_state(wlc->wl);
}
+ /* BCN template is available */
+ if (macintstatus & MI_BCNTPL)
+ brcms_c_update_beacon(wlc);
+
/* it isn't done and needs to be resched if macintstatus is non-zero */
return wlc->macintstatus != 0;
@@ -7748,7 +7919,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
{
struct bcma_device *core = wlc->hw->d11core;
- struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
+ struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;
u16 chanspec;
brcms_dbg_info(core, "wl%d\n", wlc->pub->unit);
@@ -7765,7 +7936,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
brcms_c_set_bssid(wlc->bsscfg);
/* Update tsf_cfprep if associated and up */
- if (wlc->pub->associated && wlc->bsscfg->up) {
+ if (wlc->pub->associated && wlc->pub->up) {
u32 bi;
/* get beacon period and convert to uS */
@@ -7810,9 +7981,14 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
/* read the ucode version if we have not yet done so */
if (wlc->ucode_rev == 0) {
- wlc->ucode_rev =
- brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
- wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+ u16 rev;
+ u16 patch;
+
+ rev = brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR);
+ patch = brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
+ wlc->ucode_rev = (rev << NBITS(u16)) | patch;
+ snprintf(wlc->wiphy->fw_version,
+ sizeof(wlc->wiphy->fw_version), "%u.%u", rev, patch);
}
/* ..now really unleash hell (allow the MAC out of suspend) */
@@ -7868,6 +8044,7 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
pub->unit = unit;
pub->_piomode = piomode;
wlc->bandinit_pending = false;
+ wlc->beacon_template_virgin = true;
/* populate struct brcms_c_info with default values */
brcms_c_info_init(wlc, unit);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h
index fb447747c2c6..b5d7a38b53fe 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -492,6 +492,8 @@ struct brcms_c_info {
bool radio_monitor;
bool going_down;
+ bool beacon_template_virgin;
+
struct brcms_timer *wdtimer;
struct brcms_timer *radio_timer;
@@ -561,6 +563,11 @@ struct brcms_c_info {
struct wiphy *wiphy;
struct scb pri_scb;
+
+ struct sk_buff *beacon;
+ u16 beacon_tim_offset;
+ u16 beacon_dtim_period;
+ struct sk_buff *probe_resp;
};
/* antsel module specific state */
@@ -576,14 +583,17 @@ struct antsel_info {
struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */
};
+enum brcms_bss_type {
+ BRCMS_TYPE_STATION,
+ BRCMS_TYPE_AP,
+ BRCMS_TYPE_ADHOC,
+};
+
/*
* BSS configuration state
*
* wlc: wlc to which this bsscfg belongs to.
- * up: is this configuration up operational
- * enable: is this configuration enabled
- * associated: is BSS in ASSOCIATED state
- * BSS: infraustructure or adhoc
+ * type: interface type
* SSID_len: the length of SSID
* SSID: SSID string
*
@@ -599,14 +609,10 @@ struct antsel_info {
*/
struct brcms_bss_cfg {
struct brcms_c_info *wlc;
- bool up;
- bool enable;
- bool associated;
- bool BSS;
+ enum brcms_bss_type type;
u8 SSID_len;
u8 SSID[IEEE80211_MAX_SSID_LEN];
u8 BSSID[ETH_ALEN];
- u8 cur_etheraddr[ETH_ALEN];
struct brcms_bss_info *current_bss;
};
@@ -631,7 +637,6 @@ extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
struct ieee80211_sta *sta,
void (*dma_callback_fn));
-extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
index 91937c5025ce..b0fd807f2b2b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -198,8 +198,6 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
-
if ((D11REV_GE(pi->sh->corerev, 24)) ||
(D11REV_IS(pi->sh->corerev, 22)
&& (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
@@ -211,7 +209,7 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val);
}
- if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) &&
+ if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
(++pi->phy_wreg >= pi->phy_wreg_limit)) {
(void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
pi->phy_wreg = 0;
@@ -297,10 +295,8 @@ void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
if (addr == 0x72)
(void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata));
#else
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
-
bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16));
- if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) &&
+ if ((pi->d11core->bus->hosttype == BCMA_HOSTTYPE_PCI) &&
(++pi->phy_wreg >= pi->phy_wreg_limit)) {
pi->phy_wreg = 0;
(void)bcma_read16(pi->d11core, D11REGOFFS(phyversion));
@@ -374,7 +370,6 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
if (sh == NULL)
return NULL;
- sh->sih = shp->sih;
sh->physhim = shp->physhim;
sh->unit = shp->unit;
sh->corerev = shp->corerev;
@@ -2911,29 +2906,24 @@ void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2);
}
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpiocontrol),
- ~0x0, 0x0);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioout),
- 0x40, 0x40);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioouten),
- 0x40, 0x40);
+
+ bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
+ 0x0, 0x0);
+ bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x40);
+ bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x40);
} else {
mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioout),
- 0x40, 0x00);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpioouten),
- 0x40, 0x0);
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, gpiocontrol),
- ~0x0, 0x40);
+ bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x00);
+ bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc,
+ ~0x40, 0x00);
+ bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc,
+ 0x0, 0x40);
}
}
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
index af00e2c2b266..1dc767c31653 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
@@ -488,7 +488,6 @@ struct lcnphy_cal_results {
struct shared_phy {
struct brcms_phy *phy_head;
uint unit;
- struct si_pub *sih;
struct phy_shim_info *physhim;
uint corerev;
u32 machwcap;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
index 21a824232478..3d6b16ce4687 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -1137,9 +1137,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
gain0_15 = ((biq1 & 0xf) << 12) |
((tia & 0xf) << 8) |
((lna2 & 0x3) << 6) |
- ((lna2 & 0x3) << 4) |
- ((lna1 & 0x3) << 2) |
- ((lna1 & 0x3) << 0);
+ ((lna2 &
+ 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
@@ -1157,8 +1156,6 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
}
mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
- mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
- mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
}
@@ -1331,43 +1328,6 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
}
-static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
- u16 tia_gain, u16 lna2_gain)
-{
- u32 i_thresh_l, q_thresh_l;
- u32 i_thresh_h, q_thresh_h;
- struct lcnphy_iq_est iq_est_h, iq_est_l;
-
- wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
- lna2_gain, 0);
-
- wlc_lcnphy_rx_gain_override_enable(pi, true);
- wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
- udelay(500);
- write_radio_reg(pi, RADIO_2064_REG112, 0);
- if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
- return false;
-
- wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
- udelay(500);
- write_radio_reg(pi, RADIO_2064_REG112, 0);
- if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
- return false;
-
- i_thresh_l = (iq_est_l.i_pwr << 1);
- i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
-
- q_thresh_l = (iq_est_l.q_pwr << 1);
- q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
- if ((iq_est_h.i_pwr > i_thresh_l) &&
- (iq_est_h.i_pwr < i_thresh_h) &&
- (iq_est_h.q_pwr > q_thresh_l) &&
- (iq_est_h.q_pwr < q_thresh_h))
- return true;
-
- return false;
-}
-
static bool
wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
const struct lcnphy_rx_iqcomp *iqcomp,
@@ -1382,8 +1342,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
rfoverride3_old, rfoverride3val_old, rfoverride4_old,
rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
- int tia_gain, lna2_gain, biq1_gain;
- bool set_gain;
+ int tia_gain;
+ u32 received_power, rx_pwr_threshold;
u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
u16 values_to_save[11];
s16 *ptr;
@@ -1408,134 +1368,126 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
goto cal_done;
}
- WARN_ON(module != 1);
- tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
- wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
-
- for (i = 0; i < 11; i++)
- values_to_save[i] =
- read_radio_reg(pi, rxiq_cal_rf_reg[i]);
- Core1TxControl_old = read_phy_reg(pi, 0x631);
-
- or_phy_reg(pi, 0x631, 0x0015);
-
- RFOverride0_old = read_phy_reg(pi, 0x44c);
- RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
- rfoverride2_old = read_phy_reg(pi, 0x4b0);
- rfoverride2val_old = read_phy_reg(pi, 0x4b1);
- rfoverride3_old = read_phy_reg(pi, 0x4f9);
- rfoverride3val_old = read_phy_reg(pi, 0x4fa);
- rfoverride4_old = read_phy_reg(pi, 0x938);
- rfoverride4val_old = read_phy_reg(pi, 0x939);
- afectrlovr_old = read_phy_reg(pi, 0x43b);
- afectrlovrval_old = read_phy_reg(pi, 0x43c);
- old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
- old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
-
- tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
- if (tx_gain_override_old) {
- wlc_lcnphy_get_tx_gain(pi, &old_gains);
- tx_gain_index_old = pi_lcn->lcnphy_current_index;
- }
-
- wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
+ if (module == 1) {
- mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
+ tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
- mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+ for (i = 0; i < 11; i++)
+ values_to_save[i] =
+ read_radio_reg(pi, rxiq_cal_rf_reg[i]);
+ Core1TxControl_old = read_phy_reg(pi, 0x631);
+
+ or_phy_reg(pi, 0x631, 0x0015);
+
+ RFOverride0_old = read_phy_reg(pi, 0x44c);
+ RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
+ rfoverride2_old = read_phy_reg(pi, 0x4b0);
+ rfoverride2val_old = read_phy_reg(pi, 0x4b1);
+ rfoverride3_old = read_phy_reg(pi, 0x4f9);
+ rfoverride3val_old = read_phy_reg(pi, 0x4fa);
+ rfoverride4_old = read_phy_reg(pi, 0x938);
+ rfoverride4val_old = read_phy_reg(pi, 0x939);
+ afectrlovr_old = read_phy_reg(pi, 0x43b);
+ afectrlovrval_old = read_phy_reg(pi, 0x43c);
+ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+ old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
+
+ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+ if (tx_gain_override_old) {
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+ tx_gain_index_old = pi_lcn->lcnphy_current_index;
+ }
- write_radio_reg(pi, RADIO_2064_REG116, 0x06);
- write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
- write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
- write_radio_reg(pi, RADIO_2064_REG098, 0x03);
- write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
- mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
- write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
- write_radio_reg(pi, RADIO_2064_REG114, 0x01);
- write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
- write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
-
- mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
- mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
- mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
- mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
- mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
- mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
- mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
- mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
- write_phy_reg(pi, 0x6da, 0xffff);
- or_phy_reg(pi, 0x6db, 0x3);
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
- wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
- set_gain = false;
-
- lna2_gain = 3;
- while ((lna2_gain >= 0) && !set_gain) {
- tia_gain = 4;
-
- while ((tia_gain >= 0) && !set_gain) {
- biq1_gain = 6;
-
- while ((biq1_gain >= 0) && !set_gain) {
- set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
- (u16)
- biq1_gain,
- (u16)
- tia_gain,
- (u16)
- lna2_gain);
- biq1_gain -= 1;
- }
+ write_radio_reg(pi, RADIO_2064_REG116, 0x06);
+ write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
+ write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
+ write_radio_reg(pi, RADIO_2064_REG098, 0x03);
+ write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+ mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
+ write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG114, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
+ write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
+
+ mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
+ mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
+ mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+ wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
+ write_phy_reg(pi, 0x6da, 0xffff);
+ or_phy_reg(pi, 0x6db, 0x3);
+ wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
+ wlc_lcnphy_rx_gain_override_enable(pi, true);
+
+ tia_gain = 8;
+ rx_pwr_threshold = 950;
+ while (tia_gain > 0) {
tia_gain -= 1;
+ wlc_lcnphy_set_rx_gain_by_distribution(pi,
+ 0, 0, 2, 2,
+ (u16)
+ tia_gain, 1, 0);
+ udelay(500);
+
+ received_power =
+ wlc_lcnphy_measure_digital_power(pi, 2000);
+ if (received_power < rx_pwr_threshold)
+ break;
}
- lna2_gain -= 1;
- }
+ result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
- if (set_gain)
- result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
- else
- result = false;
+ wlc_lcnphy_stop_tx_tone(pi);
- wlc_lcnphy_stop_tx_tone(pi);
+ write_phy_reg(pi, 0x631, Core1TxControl_old);
- write_phy_reg(pi, 0x631, Core1TxControl_old);
-
- write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
- write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
- write_phy_reg(pi, 0x4b0, rfoverride2_old);
- write_phy_reg(pi, 0x4b1, rfoverride2val_old);
- write_phy_reg(pi, 0x4f9, rfoverride3_old);
- write_phy_reg(pi, 0x4fa, rfoverride3val_old);
- write_phy_reg(pi, 0x938, rfoverride4_old);
- write_phy_reg(pi, 0x939, rfoverride4val_old);
- write_phy_reg(pi, 0x43b, afectrlovr_old);
- write_phy_reg(pi, 0x43c, afectrlovrval_old);
- write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
- write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
+ write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x4b0, rfoverride2_old);
+ write_phy_reg(pi, 0x4b1, rfoverride2val_old);
+ write_phy_reg(pi, 0x4f9, rfoverride3_old);
+ write_phy_reg(pi, 0x4fa, rfoverride3val_old);
+ write_phy_reg(pi, 0x938, rfoverride4_old);
+ write_phy_reg(pi, 0x939, rfoverride4val_old);
+ write_phy_reg(pi, 0x43b, afectrlovr_old);
+ write_phy_reg(pi, 0x43c, afectrlovrval_old);
+ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+ write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
- wlc_lcnphy_clear_trsw_override(pi);
+ wlc_lcnphy_clear_trsw_override(pi);
- mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
- for (i = 0; i < 11; i++)
- write_radio_reg(pi, rxiq_cal_rf_reg[i],
- values_to_save[i]);
+ for (i = 0; i < 11; i++)
+ write_radio_reg(pi, rxiq_cal_rf_reg[i],
+ values_to_save[i]);
- if (tx_gain_override_old)
- wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
- else
- wlc_lcnphy_disable_tx_gain_override(pi);
+ if (tx_gain_override_old)
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
+ else
+ wlc_lcnphy_disable_tx_gain_override(pi);
- wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
- wlc_lcnphy_rx_gain_override_enable(pi, false);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
+ wlc_lcnphy_rx_gain_override_enable(pi, false);
+ }
cal_done:
kfree(ptr);
@@ -1643,11 +1595,15 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
if (channel == 1 || channel == 2 || channel == 3 ||
channel == 4 || channel == 9 ||
channel == 10 || channel == 11 || channel == 12) {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
-
- si_pmu_pllupd(pi->sh->sih);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
+ 0x03000c04);
+ bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
+ ~0x00ffffff, 0x0);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
+ 0x200005c0);
+
+ bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_PLL_UPD);
write_phy_reg(pi, 0x942, 0);
wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
pi_lcn->lcnphy_spurmod = false;
@@ -1655,11 +1611,15 @@ wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
write_phy_reg(pi, 0x425, 0x5907);
} else {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
-
- si_pmu_pllupd(pi->sh->sih);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
+ 0x03140c04);
+ bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
+ ~0x00ffffff, 0x333333);
+ bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
+ 0x202c2820);
+
+ bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_PLL_UPD);
write_phy_reg(pi, 0x942, 0);
wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
@@ -1829,17 +1789,6 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
write_radio_reg(pi, RADIO_2064_REG038, 3);
write_radio_reg(pi, RADIO_2064_REG091, 7);
}
-
- if (!(pi->sh->boardflags & BFL_FEM)) {
- u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc,
- 0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0};
-
- write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
- write_radio_reg(pi, RADIO_2064_REG091, 0x3);
- write_radio_reg(pi, RADIO_2064_REG038, 0x3);
-
- write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
- }
}
static int
@@ -2034,16 +1983,6 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
} else {
mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
- mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
- mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
- mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
- mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
- mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
- mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
- mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
- mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
- mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
- mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
}
} else {
mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
@@ -2130,14 +2069,12 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
(auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
- mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
}
static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
{
struct phytbl_info tab;
u32 rfseq, ind;
- u8 tssi_sel;
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
tab.tbl_width = 32;
@@ -2159,13 +2096,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
- if (pi->sh->boardflags & BFL_FEM) {
- tssi_sel = 0x1;
- wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
- } else {
- tssi_sel = 0xe;
- wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA);
- }
+ wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
@@ -2201,10 +2132,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
- mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
} else {
- mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
}
@@ -2251,10 +2181,6 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
- mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
- mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
- mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
-
wlc_lcnphy_pwrctrl_rssiparams(pi);
}
@@ -2873,8 +2799,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
read_radio_reg(pi, RADIO_2064_REG007) & 1;
u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
- u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
-
idleTssi = read_phy_reg(pi, 0x4ab);
suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
MCTL_EN_MAC));
@@ -2892,12 +2816,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
wlc_lcnphy_tssi_setup(pi);
-
- mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
- mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
-
- wlc_lcnphy_set_bbmult(pi, 0x0);
-
wlc_phy_do_dummy_tx(pi, true, OFF);
idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
>> 0);
@@ -2919,7 +2837,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
- wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
wlc_lcnphy_set_tx_gain(pi, &old_gains);
wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
@@ -3133,11 +3050,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
wlc_lcnphy_write_table(pi, &tab);
tab.tbl_offset++;
}
- mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
- mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
- mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
- mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
- mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
@@ -3939,6 +3851,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
target_gains.pad_gain = 21;
target_gains.dac_gain = 0;
wlc_lcnphy_set_tx_gain(pi, &target_gains);
+ wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
@@ -3949,7 +3862,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
lcnphy_recal ? LCNPHY_CAL_RECAL :
LCNPHY_CAL_FULL), false);
} else {
- wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
}
@@ -4374,22 +4286,17 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
if (CHSPEC_IS5G(pi->radio_chanspec))
pa_gain = 0x70;
else
- pa_gain = 0x60;
+ pa_gain = 0x70;
if (pi->sh->boardflags & BFL_FEM)
pa_gain = 0x10;
-
tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
tab.tbl_width = 32;
tab.tbl_len = 1;
tab.tbl_ptr = &val;
for (j = 0; j < 128; j++) {
- if (pi->sh->boardflags & BFL_FEM)
- gm_gain = gain_table[j].gm;
- else
- gm_gain = 15;
-
+ gm_gain = gain_table[j].gm;
val = (((u32) pa_gain << 24) |
(gain_table[j].pad << 16) |
(gain_table[j].pga << 8) | gm_gain);
@@ -4600,10 +4507,7 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
write_phy_reg(pi, 0x4ea, 0x4688);
- if (pi->sh->boardflags & BFL_FEM)
- mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
- else
- mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
+ mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
@@ -4614,13 +4518,6 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
wlc_lcnphy_rcal(pi);
wlc_lcnphy_rc_cal(pi);
-
- if (!(pi->sh->boardflags & BFL_FEM)) {
- write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
- write_radio_reg(pi, RADIO_2064_REG033, 0x19);
- write_radio_reg(pi, RADIO_2064_REG039, 0xe);
- }
-
}
static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
@@ -4650,20 +4547,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
wlc_lcnphy_write_table(pi, &tab);
}
- if (!(pi->sh->boardflags & BFL_FEM)) {
- tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
- tab.tbl_width = 16;
- tab.tbl_ptr = &val;
- tab.tbl_len = 1;
+ tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+ tab.tbl_width = 16;
+ tab.tbl_ptr = &val;
+ tab.tbl_len = 1;
- val = 150;
- tab.tbl_offset = 0;
- wlc_lcnphy_write_table(pi, &tab);
+ val = 114;
+ tab.tbl_offset = 0;
+ wlc_lcnphy_write_table(pi, &tab);
- val = 220;
- tab.tbl_offset = 1;
- wlc_lcnphy_write_table(pi, &tab);
- }
+ val = 130;
+ tab.tbl_offset = 1;
+ wlc_lcnphy_write_table(pi, &tab);
+
+ val = 6;
+ tab.tbl_offset = 8;
+ wlc_lcnphy_write_table(pi, &tab);
if (CHSPEC_IS2G(pi->radio_chanspec)) {
if (pi->sh->boardflags & BFL_FEM)
@@ -4864,9 +4763,10 @@ void wlc_phy_init_lcnphy(struct brcms_phy *pi)
wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
- si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
+ bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
- si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
+ bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
+ 0x03CDDDDD);
if ((pi->sh->boardflags & BFL_FEM)
&& wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
@@ -5055,7 +4955,6 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
- wlc_lcnphy_tssi_setup(pi);
}
void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
@@ -5078,7 +4977,7 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
pi->hwpwrctrl_capable = true;
}
- pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih);
+ pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
pi->pi_fptr.init = wlc_phy_init_lcnphy;
@@ -5094,7 +4993,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
return false;
- if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+ if ((pi->sh->boardflags & BFL_FEM) &&
+ (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
if (pi_lcn->lcnphy_tempsense_option == 3) {
pi->hwpwrctrl = true;
pi->hwpwrctrl_capable = true;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 65db9b7458dc..3e9f5b25be63 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -19321,14 +19321,13 @@ void wlc_phy_init_nphy(struct brcms_phy *pi)
(pi->sh->chippkg == BCMA_PKG_ID_BCM4718))) {
if ((pi->sh->boardflags & BFL_EXTLNA) &&
(CHSPEC_IS2G(pi->radio_chanspec)))
- ai_cc_reg(pi->sh->sih,
- offsetof(struct chipcregs, chipcontrol),
- 0x40, 0x40);
+ bcma_cc_set32(&pi->d11core->bus->drv_cc,
+ BCMA_CC_CHIPCTL, 0x40);
}
if ((!PHY_IPA(pi)) && (pi->sh->chip == BCMA_CHIP_ID_BCM5357))
- si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA,
- CCTRL5357_EXTPA);
+ bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 1,
+ ~CCTRL5357_EXTPA, CCTRL5357_EXTPA);
if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) &&
CHSPEC_IS40(pi->radio_chanspec)) {
@@ -21133,7 +21132,6 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
const struct nphy_sfo_cfg *ci)
{
u16 val;
- struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub);
val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
if (CHSPEC_IS5G(chanspec) && !val) {
@@ -21221,11 +21219,11 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) ||
(pi->sh->chip == BCMA_CHIP_ID_BCM43225)) {
- bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc,
+ bcma_pmu_spuravoid_pllupdate(&pi->d11core->bus->drv_cc,
spuravoid);
} else {
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false);
- bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc,
+ bcma_pmu_spuravoid_pllupdate(&pi->d11core->bus->drv_cc,
spuravoid);
wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true);
}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
index b7e95acc2084..622c01ca72c5 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
@@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
};
static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
- 0x0009,
0x000a,
- 0x0005,
- 0x0006,
0x0009,
- 0x000a,
- 0x0005,
0x0006,
- 0x0009,
- 0x000a,
0x0005,
- 0x0006,
- 0x0009,
0x000a,
- 0x0005,
- 0x0006,
0x0009,
- 0x000a,
- 0x0005,
0x0006,
- 0x0009,
- 0x000a,
0x0005,
- 0x0006,
- 0x0009,
0x000a,
- 0x0005,
- 0x0006,
0x0009,
- 0x000a,
- 0x0005,
0x0006,
- 0x0009,
- 0x000a,
0x0005,
- 0x0006,
- 0x0009,
0x000a,
- 0x0005,
- 0x0006,
0x0009,
- 0x000a,
- 0x0005,
0x0006,
- 0x0009,
- 0x000a,
0x0005,
- 0x0006,
+ 0x000a,
0x0009,
+ 0x0006,
+ 0x0005,
0x000a,
+ 0x0009,
+ 0x0006,
0x0005,
+ 0x000a,
+ 0x0009,
0x0006,
+ 0x0005,
+ 0x000a,
0x0009,
+ 0x0006,
+ 0x0005,
0x000a,
+ 0x0009,
+ 0x0006,
0x0005,
+ 0x000a,
+ 0x0009,
0x0006,
+ 0x0005,
+ 0x000a,
0x0009,
+ 0x0006,
+ 0x0005,
0x000a,
+ 0x0009,
+ 0x0006,
0x0005,
+ 0x000a,
+ 0x0009,
0x0006,
+ 0x0005,
+ 0x000a,
0x0009,
+ 0x0006,
+ 0x0005,
0x000a,
+ 0x0009,
+ 0x0006,
0x0005,
+ 0x000a,
+ 0x0009,
0x0006,
+ 0x0005,
};
static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
index 7e9df566c733..71b80381f3ad 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c
@@ -115,60 +115,6 @@ u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
return (u16) delay;
}
-/* Read/write a chipcontrol reg */
-u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol_data),
- mask, val);
-}
-
-/* Read/write a regcontrol reg */
-u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, regcontrol_data),
- mask, val);
-}
-
-/* Read/write a pllcontrol reg */
-u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_addr), ~0, reg);
- return ai_cc_reg(sih, offsetof(struct chipcregs, pllcontrol_data),
- mask, val);
-}
-
-/* PMU PLL update */
-void si_pmu_pllupd(struct si_pub *sih)
-{
- ai_cc_reg(sih, offsetof(struct chipcregs, pmucontrol),
- PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
-}
-
-/* query alp/xtal clock frequency */
-u32 si_pmu_alp_clock(struct si_pub *sih)
-{
- u32 clock = ALP_CLOCK;
-
- /* bail out with default */
- if (!(ai_get_cccaps(sih) & CC_CAP_PMU))
- return clock;
-
- switch (ai_get_chip_id(sih)) {
- case BCMA_CHIP_ID_BCM43224:
- case BCMA_CHIP_ID_BCM43225:
- case BCMA_CHIP_ID_BCM4313:
- /* always 20Mhz */
- clock = 20000 * 1000;
- break;
- default:
- break;
- }
-
- return clock;
-}
-
u32 si_pmu_measure_alpclk(struct si_pub *sih)
{
struct si_info *sii = container_of(sih, struct si_info, pub);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
index f7cff873578b..20e2012d5a3a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h
@@ -21,12 +21,6 @@
#include "types.h"
extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih);
-extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable);
-extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
-extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
-extern u32 si_pmu_alp_clock(struct si_pub *sih);
-extern void si_pmu_pllupd(struct si_pub *sih);
-extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
extern u32 si_pmu_measure_alpclk(struct si_pub *sih);
#endif /* _BRCM_PMU_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index b0f14b7b8616..d36ea5e1cc49 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -164,8 +164,6 @@ struct brcms_pub {
u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */
- int bcmerror; /* last bcm error */
-
u32 radio_disabled; /* bit vector for radio disabled reasons */
u16 boardrev; /* version # of particular board */
@@ -326,10 +324,25 @@ extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
s8 sslot_override);
extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
u8 interval);
+extern u64 brcms_c_tsf_get(struct brcms_c_info *wlc);
+extern void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf);
extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
+extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
+extern void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr,
+ const u8 *bssid, u8 *ssid, size_t ssid_len);
+extern void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr);
+extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
+extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
+ struct sk_buff *beacon, u16 tim_offset,
+ u16 dtim_period);
+extern void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,
+ struct sk_buff *probe_resp);
+extern void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable);
+extern void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid,
+ size_t ssid_len);
#endif /* _BRCM_PUB_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmutil/Makefile b/drivers/net/wireless/brcm80211/brcmutil/Makefile
index 6281c416289e..8a928184016a 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmutil/Makefile
@@ -19,10 +19,5 @@ ccflags-y := \
-Idrivers/net/wireless/brcm80211/brcmutil \
-Idrivers/net/wireless/brcm80211/include
-BRCMUTIL_OFILES := \
- utils.o
-
-MODULEPFX := brcmutil
-
-obj-$(CONFIG_BRCMUTIL) += $(MODULEPFX).o
-$(MODULEPFX)-objs = $(BRCMUTIL_OFILES)
+obj-$(CONFIG_BRCMUTIL) += brcmutil.o
+brcmutil-objs = utils.o d11.o
diff --git a/drivers/net/wireless/brcm80211/brcmutil/d11.c b/drivers/net/wireless/brcm80211/brcmutil/d11.c
new file mode 100644
index 000000000000..30e54e2c6c9b
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmutil/d11.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*********************channel spec common functions*********************/
+
+#include <linux/module.h>
+
+#include <brcmu_utils.h>
+#include <brcmu_wifi.h>
+#include <brcmu_d11.h>
+
+static void brcmu_d11n_encchspec(struct brcmu_chan *ch)
+{
+ ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK;
+
+ switch (ch->bw) {
+ case BRCMU_CHAN_BW_20:
+ ch->chspec |= BRCMU_CHSPEC_D11N_BW_20 | BRCMU_CHSPEC_D11N_SB_N;
+ break;
+ case BRCMU_CHAN_BW_40:
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ if (ch->chnum <= CH_MAX_2G_CHANNEL)
+ ch->chspec |= BRCMU_CHSPEC_D11N_BND_2G;
+ else
+ ch->chspec |= BRCMU_CHSPEC_D11N_BND_5G;
+}
+
+static void brcmu_d11ac_encchspec(struct brcmu_chan *ch)
+{
+ ch->chspec = ch->chnum & BRCMU_CHSPEC_CH_MASK;
+
+ switch (ch->bw) {
+ case BRCMU_CHAN_BW_20:
+ ch->chspec |= BRCMU_CHSPEC_D11AC_BW_20;
+ break;
+ case BRCMU_CHAN_BW_40:
+ case BRCMU_CHAN_BW_80:
+ case BRCMU_CHAN_BW_80P80:
+ case BRCMU_CHAN_BW_160:
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ if (ch->chnum <= CH_MAX_2G_CHANNEL)
+ ch->chspec |= BRCMU_CHSPEC_D11AC_BND_2G;
+ else
+ ch->chspec |= BRCMU_CHSPEC_D11AC_BND_5G;
+}
+
+static void brcmu_d11n_decchspec(struct brcmu_chan *ch)
+{
+ u16 val;
+
+ ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
+
+ switch (ch->chspec & BRCMU_CHSPEC_D11N_BW_MASK) {
+ case BRCMU_CHSPEC_D11N_BW_20:
+ ch->bw = BRCMU_CHAN_BW_20;
+ break;
+ case BRCMU_CHSPEC_D11N_BW_40:
+ ch->bw = BRCMU_CHAN_BW_40;
+ val = ch->chspec & BRCMU_CHSPEC_D11N_SB_MASK;
+ if (val == BRCMU_CHSPEC_D11N_SB_L) {
+ ch->sb = BRCMU_CHAN_SB_L;
+ ch->chnum -= CH_10MHZ_APART;
+ } else {
+ ch->sb = BRCMU_CHAN_SB_U;
+ ch->chnum += CH_10MHZ_APART;
+ }
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ switch (ch->chspec & BRCMU_CHSPEC_D11N_BND_MASK) {
+ case BRCMU_CHSPEC_D11N_BND_5G:
+ ch->band = BRCMU_CHAN_BAND_5G;
+ break;
+ case BRCMU_CHSPEC_D11N_BND_2G:
+ ch->band = BRCMU_CHAN_BAND_2G;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
+static void brcmu_d11ac_decchspec(struct brcmu_chan *ch)
+{
+ u16 val;
+
+ ch->chnum = (u8)(ch->chspec & BRCMU_CHSPEC_CH_MASK);
+
+ switch (ch->chspec & BRCMU_CHSPEC_D11AC_BW_MASK) {
+ case BRCMU_CHSPEC_D11AC_BW_20:
+ ch->bw = BRCMU_CHAN_BW_20;
+ break;
+ case BRCMU_CHSPEC_D11AC_BW_40:
+ ch->bw = BRCMU_CHAN_BW_40;
+ val = ch->chspec & BRCMU_CHSPEC_D11AC_SB_MASK;
+ if (val == BRCMU_CHSPEC_D11AC_SB_L) {
+ ch->sb = BRCMU_CHAN_SB_L;
+ ch->chnum -= CH_10MHZ_APART;
+ } else if (val == BRCMU_CHSPEC_D11AC_SB_U) {
+ ch->sb = BRCMU_CHAN_SB_U;
+ ch->chnum += CH_10MHZ_APART;
+ } else {
+ WARN_ON_ONCE(1);
+ }
+ break;
+ case BRCMU_CHSPEC_D11AC_BW_80:
+ ch->bw = BRCMU_CHAN_BW_80;
+ break;
+ case BRCMU_CHSPEC_D11AC_BW_8080:
+ case BRCMU_CHSPEC_D11AC_BW_160:
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ switch (ch->chspec & BRCMU_CHSPEC_D11AC_BND_MASK) {
+ case BRCMU_CHSPEC_D11AC_BND_5G:
+ ch->band = BRCMU_CHAN_BAND_5G;
+ break;
+ case BRCMU_CHSPEC_D11AC_BND_2G:
+ ch->band = BRCMU_CHAN_BAND_2G;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
+void brcmu_d11_attach(struct brcmu_d11inf *d11inf)
+{
+ if (d11inf->io_type == BRCMU_D11N_IOTYPE) {
+ d11inf->encchspec = brcmu_d11n_encchspec;
+ d11inf->decchspec = brcmu_d11n_decchspec;
+ } else {
+ d11inf->encchspec = brcmu_d11ac_encchspec;
+ d11inf->decchspec = brcmu_d11ac_decchspec;
+ }
+}
+EXPORT_SYMBOL(brcmu_d11_attach);
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
index 3e6405e06ac0..0f7e1c7b6f58 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -45,17 +45,9 @@ void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
{
if (!skb)
return;
+
WARN_ON(skb->next);
- if (skb->destructor)
- /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
- * destructor exists
- */
- dev_kfree_skb_any(skb);
- else
- /* can free immediately (even in_irq()) if destructor
- * does not exist
- */
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
@@ -116,6 +108,31 @@ struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
}
EXPORT_SYMBOL(brcmu_pktq_pdeq);
+/*
+ * precedence based dequeue with match function. Passing a NULL pointer
+ * for the match function parameter is considered to be a wildcard so
+ * any packet on the queue is returned. In that case it is no different
+ * from brcmu_pktq_pdeq() above.
+ */
+struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,
+ bool (*match_fn)(struct sk_buff *skb,
+ void *arg), void *arg)
+{
+ struct sk_buff_head *q;
+ struct sk_buff *p, *next;
+
+ q = &pq->q[prec].skblist;
+ skb_queue_walk_safe(q, p, next) {
+ if (match_fn == NULL || match_fn(p, arg)) {
+ skb_unlink(p, q);
+ pq->len--;
+ return p;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(brcmu_pktq_pdeq_match);
+
struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
{
struct sk_buff_head *q;
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index e8682855b73a..c1fe245bb07e 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -29,6 +29,7 @@
/* Chipcommon Core Chip IDs */
#define BCM4313_CHIP_ID 0x4313
+#define BCM43143_CHIP_ID 43143
#define BCM43224_CHIP_ID 43224
#define BCM43225_CHIP_ID 43225
#define BCM43235_CHIP_ID 43235
@@ -39,5 +40,6 @@
#define BCM4330_CHIP_ID 0x4330
#define BCM4331_CHIP_ID 0x4331
#define BCM4334_CHIP_ID 0x4334
+#define BCM4335_CHIP_ID 0x4335
#endif /* _BRCM_HW_IDS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_d11.h b/drivers/net/wireless/brcm80211/include/brcmu_d11.h
new file mode 100644
index 000000000000..92623f02b1c0
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/include/brcmu_d11.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BRCMU_D11_H_
+#define _BRCMU_D11_H_
+
+/* d11 io type */
+#define BRCMU_D11N_IOTYPE 1
+#define BRCMU_D11AC_IOTYPE 2
+
+/* A chanspec (channel specification) holds the channel number, band,
+ * bandwidth and control sideband
+ */
+
+/* chanspec binary format */
+
+#define BRCMU_CHSPEC_INVALID 255
+/* bit 0~7 channel number
+ * for 80+80 channels: bit 0~3 low channel id, bit 4~7 high channel id
+ */
+#define BRCMU_CHSPEC_CH_MASK 0x00ff
+#define BRCMU_CHSPEC_CH_SHIFT 0
+#define BRCMU_CHSPEC_CHL_MASK 0x000f
+#define BRCMU_CHSPEC_CHL_SHIFT 0
+#define BRCMU_CHSPEC_CHH_MASK 0x00f0
+#define BRCMU_CHSPEC_CHH_SHIFT 4
+
+/* bit 8~16 for dot 11n IO types
+ * bit 8~9 sideband
+ * bit 10~11 bandwidth
+ * bit 12~13 spectral band
+ * bit 14~15 not used
+ */
+#define BRCMU_CHSPEC_D11N_SB_MASK 0x0300
+#define BRCMU_CHSPEC_D11N_SB_SHIFT 8
+#define BRCMU_CHSPEC_D11N_SB_L 0x0100 /* control lower */
+#define BRCMU_CHSPEC_D11N_SB_U 0x0200 /* control upper */
+#define BRCMU_CHSPEC_D11N_SB_N 0x0300 /* none */
+#define BRCMU_CHSPEC_D11N_BW_MASK 0x0c00
+#define BRCMU_CHSPEC_D11N_BW_SHIFT 10
+#define BRCMU_CHSPEC_D11N_BW_10 0x0400
+#define BRCMU_CHSPEC_D11N_BW_20 0x0800
+#define BRCMU_CHSPEC_D11N_BW_40 0x0c00
+#define BRCMU_CHSPEC_D11N_BND_MASK 0x3000
+#define BRCMU_CHSPEC_D11N_BND_SHIFT 12
+#define BRCMU_CHSPEC_D11N_BND_5G 0x1000
+#define BRCMU_CHSPEC_D11N_BND_2G 0x2000
+
+/* bit 8~16 for dot 11ac IO types
+ * bit 8~10 sideband
+ * bit 11~13 bandwidth
+ * bit 14~15 spectral band
+ */
+#define BRCMU_CHSPEC_D11AC_SB_MASK 0x0700
+#define BRCMU_CHSPEC_D11AC_SB_SHIFT 8
+#define BRCMU_CHSPEC_D11AC_SB_LLL 0x0000
+#define BRCMU_CHSPEC_D11AC_SB_LLU 0x0100
+#define BRCMU_CHSPEC_D11AC_SB_LUL 0x0200
+#define BRCMU_CHSPEC_D11AC_SB_LUU 0x0300
+#define BRCMU_CHSPEC_D11AC_SB_ULL 0x0400
+#define BRCMU_CHSPEC_D11AC_SB_ULU 0x0500
+#define BRCMU_CHSPEC_D11AC_SB_UUL 0x0600
+#define BRCMU_CHSPEC_D11AC_SB_UUU 0x0700
+#define BRCMU_CHSPEC_D11AC_SB_LL BRCMU_CHSPEC_D11AC_SB_LLL
+#define BRCMU_CHSPEC_D11AC_SB_LU BRCMU_CHSPEC_D11AC_SB_LLU
+#define BRCMU_CHSPEC_D11AC_SB_UL BRCMU_CHSPEC_D11AC_SB_LUL
+#define BRCMU_CHSPEC_D11AC_SB_UU BRCMU_CHSPEC_D11AC_SB_LUU
+#define BRCMU_CHSPEC_D11AC_SB_L BRCMU_CHSPEC_D11AC_SB_LLL
+#define BRCMU_CHSPEC_D11AC_SB_U BRCMU_CHSPEC_D11AC_SB_LLU
+#define BRCMU_CHSPEC_D11AC_BW_MASK 0x3800
+#define BRCMU_CHSPEC_D11AC_BW_SHIFT 11
+#define BRCMU_CHSPEC_D11AC_BW_5 0x0000
+#define BRCMU_CHSPEC_D11AC_BW_10 0x0800
+#define BRCMU_CHSPEC_D11AC_BW_20 0x1000
+#define BRCMU_CHSPEC_D11AC_BW_40 0x1800
+#define BRCMU_CHSPEC_D11AC_BW_80 0x2000
+#define BRCMU_CHSPEC_D11AC_BW_160 0x2800
+#define BRCMU_CHSPEC_D11AC_BW_8080 0x3000
+#define BRCMU_CHSPEC_D11AC_BND_MASK 0xc000
+#define BRCMU_CHSPEC_D11AC_BND_SHIFT 14
+#define BRCMU_CHSPEC_D11AC_BND_2G 0x0000
+#define BRCMU_CHSPEC_D11AC_BND_3G 0x4000
+#define BRCMU_CHSPEC_D11AC_BND_4G 0x8000
+#define BRCMU_CHSPEC_D11AC_BND_5G 0xc000
+
+#define BRCMU_CHAN_BAND_2G 0
+#define BRCMU_CHAN_BAND_5G 1
+
+enum brcmu_chan_bw {
+ BRCMU_CHAN_BW_20,
+ BRCMU_CHAN_BW_40,
+ BRCMU_CHAN_BW_80,
+ BRCMU_CHAN_BW_80P80,
+ BRCMU_CHAN_BW_160,
+};
+
+enum brcmu_chan_sb {
+ BRCMU_CHAN_SB_NONE = 0,
+ BRCMU_CHAN_SB_L,
+ BRCMU_CHAN_SB_U,
+ BRCMU_CHAN_SB_LL,
+ BRCMU_CHAN_SB_LU,
+ BRCMU_CHAN_SB_UL,
+ BRCMU_CHAN_SB_UU,
+ BRCMU_CHAN_SB_LLL,
+ BRCMU_CHAN_SB_LLU,
+ BRCMU_CHAN_SB_LUL,
+ BRCMU_CHAN_SB_LUU,
+ BRCMU_CHAN_SB_ULL,
+ BRCMU_CHAN_SB_ULU,
+ BRCMU_CHAN_SB_UUL,
+ BRCMU_CHAN_SB_UUU,
+};
+
+struct brcmu_chan {
+ u16 chspec;
+ u8 chnum;
+ u8 band;
+ enum brcmu_chan_bw bw;
+ enum brcmu_chan_sb sb;
+};
+
+struct brcmu_d11inf {
+ u8 io_type;
+
+ void (*encchspec)(struct brcmu_chan *ch);
+ void (*decchspec)(struct brcmu_chan *ch);
+};
+
+extern void brcmu_d11_attach(struct brcmu_d11inf *d11inf);
+
+#endif /* _BRCMU_CHANNELS_H_ */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
index 477b92ad3d62..898cacb8d01d 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
@@ -120,6 +120,10 @@ extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
struct sk_buff *p);
extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec);
extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec);
+extern struct sk_buff *brcmu_pktq_pdeq_match(struct pktq *pq, int prec,
+ bool (*match_fn)(struct sk_buff *p,
+ void *arg),
+ void *arg);
/* packet primitives */
extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len);
@@ -173,6 +177,29 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
/* ip address */
struct ipv4_addr;
+/*
+ * bitfield macros using masking and shift
+ *
+ * remark: the mask parameter should be a shifted mask.
+ */
+static inline void brcmu_maskset32(u32 *var, u32 mask, u8 shift, u32 value)
+{
+ value = (value << shift) & mask;
+ *var = (*var & ~mask) | value;
+}
+static inline u32 brcmu_maskget32(u32 var, u32 mask, u8 shift)
+{
+ return (var & mask) >> shift;
+}
+static inline void brcmu_maskset16(u16 *var, u16 mask, u8 shift, u16 value)
+{
+ value = (value << shift) & mask;
+ *var = (*var & ~mask) | value;
+}
+static inline u16 brcmu_maskget16(u16 var, u16 mask, u8 shift)
+{
+ return (var & mask) >> shift;
+}
/* externs */
/* format/print */
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
index c11a290a1edf..0505cc065e0d 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h
@@ -32,8 +32,9 @@
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_MIN_2G_CHANNEL 1
#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
-#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */
+#define CH_MIN_5G_CHANNEL 34
/* bandstate array indices */
#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */
@@ -60,6 +61,7 @@
#define WL_CHANSPEC_BW_10 0x0400
#define WL_CHANSPEC_BW_20 0x0800
#define WL_CHANSPEC_BW_40 0x0C00
+#define WL_CHANSPEC_BW_80 0x2000
#define WL_CHANSPEC_BAND_MASK 0xf000
#define WL_CHANSPEC_BAND_SHIFT 12
@@ -67,6 +69,25 @@
#define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255
+#define WL_CHAN_VALID_HW (1 << 0) /* valid with current HW */
+#define WL_CHAN_VALID_SW (1 << 1) /* valid with country sett. */
+#define WL_CHAN_BAND_5G (1 << 2) /* 5GHz-band channel */
+#define WL_CHAN_RADAR (1 << 3) /* radar sensitive channel */
+#define WL_CHAN_INACTIVE (1 << 4) /* inactive due to radar */
+#define WL_CHAN_PASSIVE (1 << 5) /* channel in passive mode */
+#define WL_CHAN_RESTRICTED (1 << 6) /* restricted use channel */
+
+/* values for band specific 40MHz capabilities */
+#define WLC_N_BW_20ALL 0
+#define WLC_N_BW_40ALL 1
+#define WLC_N_BW_20IN2G_40IN5G 2
+
+/* band types */
+#define WLC_BAND_AUTO 0 /* auto-select */
+#define WLC_BAND_5G 1 /* 5 Ghz */
+#define WLC_BAND_2G 2 /* 2.4 Ghz */
+#define WLC_BAND_ALL 3 /* all bands */
+
#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
@@ -79,10 +100,11 @@
#define CHSPEC_IS20(chspec) \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
-#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
-#endif
+
+#define CHSPEC_IS80(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80)
#define CHSPEC_IS5G(chspec) \
(((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
diff --git a/drivers/net/wireless/brcm80211/include/chipcommon.h b/drivers/net/wireless/brcm80211/include/chipcommon.h
index f96834a7c055..d242333b7559 100644
--- a/drivers/net/wireless/brcm80211/include/chipcommon.h
+++ b/drivers/net/wireless/brcm80211/include/chipcommon.h
@@ -205,7 +205,7 @@ struct chipcregs {
u32 res_req_timer_sel;
u32 res_req_timer;
u32 res_req_mask;
- u32 PAD;
+ u32 pmucapabilities_ext; /* 0x64c, pmurev >=15 */
u32 chipcontrol_addr; /* 0x650 */
u32 chipcontrol_data; /* 0x654 */
u32 regcontrol_addr;
@@ -214,7 +214,11 @@ struct chipcregs {
u32 pllcontrol_data;
u32 pmustrapopt; /* 0x668, corerev >= 28 */
u32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */
- u32 PAD[100];
+ u32 retention_ctl; /* 0x670, pmurev >= 15 */
+ u32 PAD[3];
+ u32 retention_grpidx; /* 0x680 */
+ u32 retention_grpctl; /* 0x684 */
+ u32 PAD[94];
u16 sromotp[768];
};
@@ -276,6 +280,12 @@ struct chipcregs {
#define PCAP5_VC_SHIFT 22
#define PCAP5_CC_MASK 0xf8000000
#define PCAP5_CC_SHIFT 27
+/* pmucapabilites_ext PMU rev >= 15 */
+#define PCAPEXT_SR_SUPPORTED_MASK (1 << 1)
+/* retention_ctl PMU rev >= 15 */
+#define PMU_RCTL_MACPHY_DISABLE_MASK (1 << 26)
+#define PMU_RCTL_LOGIC_DISABLE_MASK (1 << 27)
+
/*
* Maximum delay for the PMU state transition in us.
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 89e9d3a78c3c..56cd01ca8ad0 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -709,17 +709,4 @@ static struct pcmcia_driver hostap_driver = {
.suspend = hostap_cs_suspend,
.resume = hostap_cs_resume,
};
-
-static int __init init_prism2_pccard(void)
-{
- return pcmcia_register_driver(&hostap_driver);
-}
-
-static void __exit exit_prism2_pccard(void)
-{
- pcmcia_unregister_driver(&hostap_driver);
-}
-
-
-module_init(init_prism2_pccard);
-module_exit(exit_prism2_pccard);
+module_pcmcia_driver(hostap_driver);
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index cb066f62879d..15920aaa5dd6 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -4167,17 +4167,11 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf)
static ssize_t store_debug_level(struct device_driver *d,
const char *buf, size_t count)
{
- char *p = (char *)buf;
u32 val;
+ int ret;
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- p++;
- if (p[0] == 'x' || p[0] == 'X')
- p++;
- val = simple_strtoul(p, &p, 16);
- } else
- val = simple_strtoul(p, &p, 10);
- if (p == buf)
+ ret = kstrtou32(buf, 0, &val);
+ if (ret)
IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
else
ipw2100_debug_level = val;
@@ -4238,27 +4232,15 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
{
struct ipw2100_priv *priv = dev_get_drvdata(d);
struct net_device *dev = priv->net_dev;
- char buffer[] = "00000000";
- unsigned long len =
- (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
unsigned long val;
- char *p = buffer;
+ int ret;
(void)dev; /* kill unused-var warning for debug-only code */
IPW_DEBUG_INFO("enter\n");
- strncpy(buffer, buf, len);
- buffer[len] = 0;
-
- if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') {
- p++;
- if (p[0] == 'x' || p[0] == 'X')
- p++;
- val = simple_strtoul(p, &p, 16);
- } else
- val = simple_strtoul(p, &p, 10);
- if (p == buffer) {
+ ret = kstrtoul(buf, 0, &val);
+ if (ret) {
IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
} else {
priv->ieee->scan_age = val;
@@ -4266,7 +4248,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
}
IPW_DEBUG_INFO("exit\n");
- return len;
+ return strnlen(buf, count);
}
static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age);
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index c353b5f19c8c..b37a582ccbe7 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3477,7 +3477,7 @@ static struct attribute_group il3945_attribute_group = {
.attrs = il3945_sysfs_entries,
};
-struct ieee80211_ops il3945_mac_ops = {
+static struct ieee80211_ops il3945_mac_ops __read_mostly = {
.tx = il3945_mac_tx,
.start = il3945_mac_start,
.stop = il3945_mac_stop,
diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c
index d4fd29ad90dc..c9f197d9ca1e 100644
--- a/drivers/net/wireless/iwlegacy/3945-rs.c
+++ b/drivers/net/wireless/iwlegacy/3945-rs.c
@@ -347,7 +347,7 @@ il3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
psta = (struct il3945_sta_priv *)sta->drv_priv;
rs_sta = &psta->rs_sta;
- sband = hw->wiphy->bands[conf->channel->band];
+ sband = hw->wiphy->bands[conf->chandef.chan->band];
rs_sta->il = il;
diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c
index e0b9d7fa5de0..dc1e6da9976a 100644
--- a/drivers/net/wireless/iwlegacy/3945.c
+++ b/drivers/net/wireless/iwlegacy/3945.c
@@ -2379,10 +2379,8 @@ il3945_hw_set_hw_params(struct il_priv *il)
il->_3945.shared_virt =
dma_alloc_coherent(&il->pci_dev->dev, sizeof(struct il3945_shared),
&il->_3945.shared_phys, GFP_KERNEL);
- if (!il->_3945.shared_virt) {
- IL_ERR("failed to allocate pci memory\n");
+ if (!il->_3945.shared_virt)
return -ENOMEM;
- }
il->hw_params.bcast_id = IL3945_BROADCAST_ID;
diff --git a/drivers/net/wireless/iwlegacy/3945.h b/drivers/net/wireless/iwlegacy/3945.h
index 1d45075e0d5b..9a8703def0ba 100644
--- a/drivers/net/wireless/iwlegacy/3945.h
+++ b/drivers/net/wireless/iwlegacy/3945.h
@@ -150,10 +150,6 @@ struct il3945_frame {
struct list_head list;
};
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 7941eb3a0166..b8f82e688c72 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -612,7 +612,7 @@ il4965_pass_packet_to_mac80211(struct il_priv *il, struct ieee80211_hdr *hdr,
/* Called for N_RX (legacy ABG frames), or
* N_RX_MPDU (HT high-throughput N frames). */
-void
+static void
il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
{
struct ieee80211_hdr *header;
@@ -744,7 +744,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
/* Cache phy data (Rx signal strength, etc) for HT frame (N_RX_PHY).
* This will be used later in il_hdl_rx() for N_RX_MPDU. */
-void
+static void
il4965_hdl_rx_phy(struct il_priv *il, struct il_rx_buf *rxb)
{
struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -1250,7 +1250,7 @@ il4965_dump_fh(struct il_priv *il, char **buf, bool display)
return 0;
}
-void
+static void
il4965_hdl_missed_beacon(struct il_priv *il, struct il_rx_buf *rxb)
{
struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -1357,7 +1357,7 @@ il4965_accumulative_stats(struct il_priv *il, __le32 * stats)
}
#endif
-void
+static void
il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
{
const int recalib_seconds = 60;
@@ -1399,7 +1399,7 @@ il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb)
il4965_temperature_calib(il);
}
-void
+static void
il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb)
{
struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -1921,8 +1921,8 @@ drop_unlock:
static inline int
il4965_alloc_dma_ptr(struct il_priv *il, struct il_dma_ptr *ptr, size_t size)
{
- ptr->addr =
- dma_alloc_coherent(&il->pci_dev->dev, size, &ptr->dma, GFP_KERNEL);
+ ptr->addr = dma_alloc_coherent(&il->pci_dev->dev, size, &ptr->dma,
+ GFP_KERNEL);
if (!ptr->addr)
return -ENOMEM;
ptr->size = size;
@@ -2050,7 +2050,7 @@ il4965_txq_ctx_reset(struct il_priv *il)
il_tx_queue_reset(il, txq_id);
}
-void
+static void
il4965_txq_ctx_unmap(struct il_priv *il)
{
int txq_id;
@@ -2258,7 +2258,7 @@ il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif,
spin_lock_irqsave(&il->sta_lock, flags);
tid_data = &il->stations[sta_id].tid[tid];
- *ssn = SEQ_TO_SN(tid_data->seq_number);
+ *ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
il_set_swq_id(&il->txq[txq_id], il4965_get_ac_from_tid(tid), txq_id);
spin_unlock_irqrestore(&il->sta_lock, flags);
@@ -2408,7 +2408,7 @@ il4965_txq_check_empty(struct il_priv *il, int sta_id, u8 tid, int txq_id)
/* aggregated HW queue */
if (txq_id == tid_data->agg.txq_id &&
q->read_ptr == q->write_ptr) {
- u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+ u16 ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
int tx_fifo = il4965_get_fifo_from_tid(tid);
D_HT("HW queue empty: continue DELBA flow\n");
il4965_txq_agg_disable(il, txq_id, ssn, tx_fifo);
@@ -2627,7 +2627,8 @@ il4965_get_ra_sta_id(struct il_priv *il, struct ieee80211_hdr *hdr)
static inline u32
il4965_get_scd_ssn(struct il4965_tx_resp *tx_resp)
{
- return le32_to_cpup(&tx_resp->u.status + tx_resp->frame_count) & MAX_SN;
+ return le32_to_cpup(&tx_resp->u.status +
+ tx_resp->frame_count) & IEEE80211_MAX_SN;
}
static inline u32
@@ -2717,15 +2718,15 @@ il4965_tx_status_reply_tx(struct il_priv *il, struct il_ht_agg *agg,
hdr = (struct ieee80211_hdr *) skb->data;
sc = le16_to_cpu(hdr->seq_ctrl);
- if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ if (idx != (IEEE80211_SEQ_TO_SN(sc) & 0xff)) {
IL_ERR("BUG_ON idx doesn't match seq control"
" idx=%d, seq_idx=%d, seq=%d\n", idx,
- SEQ_TO_SN(sc), hdr->seq_ctrl);
+ IEEE80211_SEQ_TO_SN(sc), hdr->seq_ctrl);
return -1;
}
D_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n", i, idx,
- SEQ_TO_SN(sc));
+ IEEE80211_SEQ_TO_SN(sc));
sh = idx - start;
if (sh > 64) {
@@ -2895,7 +2896,7 @@ il4965_hwrate_to_tx_control(struct il_priv *il, u32 rate_n_flags,
* Handles block-acknowledge notification from device, which reports success
* of frames sent via aggregation.
*/
-void
+static void
il4965_hdl_compressed_ba(struct il_priv *il, struct il_rx_buf *rxb)
{
struct il_rx_pkt *pkt = rxb_addr(rxb);
@@ -6056,7 +6057,7 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
struct il_priv *il = hw->priv;
const struct il_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_channel *channel = ch_switch->channel;
+ struct ieee80211_channel *channel = ch_switch->chandef.chan;
struct il_ht_config *ht_conf = &il->current_ht_config;
u16 ch;
@@ -6093,23 +6094,21 @@ il4965_mac_channel_switch(struct ieee80211_hw *hw,
il->current_ht_config.smps = conf->smps_mode;
/* Configure HT40 channels */
- il->ht.enabled = conf_is_ht(conf);
- if (il->ht.enabled) {
- if (conf_is_ht40_minus(conf)) {
- il->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- il->ht.is_40mhz = true;
- } else if (conf_is_ht40_plus(conf)) {
- il->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- il->ht.is_40mhz = true;
- } else {
- il->ht.extension_chan_offset =
- IEEE80211_HT_PARAM_CHA_SEC_NONE;
- il->ht.is_40mhz = false;
- }
- } else
+ switch (cfg80211_get_chandef_type(&ch_switch->chandef)) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
il->ht.is_40mhz = false;
+ il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ il->ht.is_40mhz = true;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ il->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ il->ht.is_40mhz = true;
+ break;
+ }
if ((le16_to_cpu(il->staging.channel) != ch))
il->staging.flags = 0;
@@ -6316,7 +6315,7 @@ il4965_tx_queue_set_status(struct il_priv *il, struct il_tx_queue *txq,
scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
}
-const struct ieee80211_ops il4965_mac_ops = {
+static const struct ieee80211_ops il4965_mac_ops = {
.tx = il4965_mac_tx,
.start = il4965_mac_start,
.stop = il4965_mac_stop,
diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c
index e8324b5e5bfe..1fc0b227e120 100644
--- a/drivers/net/wireless/iwlegacy/4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/4965-rs.c
@@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
int rate_idx;
int i;
u32 rate;
- u8 use_green = il4965_rs_use_green(il, sta);
+ u8 use_green;
u8 active_tbl = 0;
u8 valid_tx_ant;
struct il_station_priv *sta_priv;
@@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
if (!sta || !lq_sta)
return;
+ use_green = il4965_rs_use_green(il, sta);
sta_priv = (void *)sta->drv_priv;
i = lq_sta->last_txrate_idx;
@@ -2299,7 +2300,7 @@ il4965_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id)
sta_priv = (struct il_station_priv *)sta->drv_priv;
lq_sta = &sta_priv->lq_sta;
- sband = hw->wiphy->bands[conf->channel->band];
+ sband = hw->wiphy->bands[conf->chandef.chan->band];
lq_sta->lq.sta_id = sta_id;
diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c
index 91eb2d07fdb8..777a578294bd 100644
--- a/drivers/net/wireless/iwlegacy/4965.c
+++ b/drivers/net/wireless/iwlegacy/4965.c
@@ -1493,7 +1493,7 @@ il4965_hw_channel_switch(struct il_priv *il,
cmd.band = band;
cmd.expect_beacon = 0;
- ch = ch_switch->channel->hw_value;
+ ch = ch_switch->chandef.chan->hw_value;
cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = il->staging.flags;
cmd.rxon_filter_flags = il->staging.filter_flags;
diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c
index e006ea831320..592d0aa634a8 100644
--- a/drivers/net/wireless/iwlegacy/common.c
+++ b/drivers/net/wireless/iwlegacy/common.c
@@ -1122,7 +1122,7 @@ il_set_power(struct il_priv *il, struct il_powertable_cmd *cmd)
sizeof(struct il_powertable_cmd), cmd);
}
-int
+static int
il_power_set_mode(struct il_priv *il, struct il_powertable_cmd *cmd, bool force)
{
int ret;
@@ -2566,15 +2566,13 @@ il_rx_queue_alloc(struct il_priv *il)
INIT_LIST_HEAD(&rxq->rx_used);
/* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */
- rxq->bd =
- dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
- GFP_KERNEL);
+ rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma,
+ GFP_KERNEL);
if (!rxq->bd)
goto err_bd;
- rxq->rb_stts =
- dma_alloc_coherent(dev, sizeof(struct il_rb_status),
- &rxq->rb_stts_dma, GFP_KERNEL);
+ rxq->rb_stts = dma_alloc_coherent(dev, sizeof(struct il_rb_status),
+ &rxq->rb_stts_dma, GFP_KERNEL);
if (!rxq->rb_stts)
goto err_rb;
@@ -2941,10 +2939,9 @@ il_tx_queue_alloc(struct il_priv *il, struct il_tx_queue *txq, u32 id)
* shared with device */
txq->tfds =
dma_alloc_coherent(dev, tfd_sz, &txq->q.dma_addr, GFP_KERNEL);
- if (!txq->tfds) {
- IL_ERR("Fail to alloc TFDs\n");
+ if (!txq->tfds)
goto error;
- }
+
txq->q.id = id;
return 0;
@@ -4704,8 +4701,7 @@ out:
}
EXPORT_SYMBOL(il_mac_change_interface);
-void
-il_mac_flush(struct ieee80211_hw *hw, bool drop)
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct il_priv *il = hw->priv;
unsigned long timeout = jiffies + msecs_to_jiffies(500);
@@ -4891,7 +4887,7 @@ il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
}
EXPORT_SYMBOL(il_add_beacon_time);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int
il_pci_suspend(struct device *device)
@@ -4942,7 +4938,7 @@ il_pci_resume(struct device *device)
SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume);
EXPORT_SYMBOL(il_pm_ops);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static void
il_update_qos(struct il_priv *il)
@@ -4975,7 +4971,7 @@ il_mac_config(struct ieee80211_hw *hw, u32 changed)
struct il_priv *il = hw->priv;
const struct il_channel_info *ch_info;
struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_channel *channel = conf->channel;
+ struct ieee80211_channel *channel = conf->chandef.chan;
struct il_ht_config *ht_conf = &il->current_ht_config;
unsigned long flags = 0;
int ret = 0;
diff --git a/drivers/net/wireless/iwlegacy/common.h b/drivers/net/wireless/iwlegacy/common.h
index 96f2025d936e..f8246f2d88f9 100644
--- a/drivers/net/wireless/iwlegacy/common.h
+++ b/drivers/net/wireless/iwlegacy/common.h
@@ -541,10 +541,6 @@ struct il_frame {
struct list_head list;
};
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
-
enum {
CMD_SYNC = 0,
CMD_SIZE_NORMAL = 0,
@@ -1724,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum nl80211_iftype newtype, bool newp2p);
-void il_mac_flush(struct ieee80211_hw *hw, bool drop);
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
int il_alloc_txq_mem(struct il_priv *il);
void il_free_txq_mem(struct il_priv *il);
@@ -2235,9 +2231,8 @@ il_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
return -EINVAL;
}
- desc->v_addr =
- dma_alloc_coherent(&pci_dev->dev, desc->len, &desc->p_addr,
- GFP_KERNEL);
+ desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
+ &desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
}
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index ba319cba3f1e..56c2040a955b 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,7 +6,6 @@ config IWLWIFI
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
- select IWLDVM
---help---
Select to build the driver supporting the:
@@ -45,6 +44,7 @@ config IWLWIFI
config IWLDVM
tristate "Intel Wireless WiFi DVM Firmware support"
depends on IWLWIFI
+ default IWLWIFI
help
This is the driver supporting the DVM firmware which is
currently the only firmware available for existing devices.
@@ -58,6 +58,15 @@ config IWLMVM
Say yes if you have such a device.
+# don't call it _MODULE -- will confuse Kconfig/fixdep/...
+config IWLWIFI_OPMODE_MODULAR
+ bool
+ default y if IWLDVM=m
+ default y if IWLMVM=m
+
+comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM"
+ depends on IWLWIFI && IWLDVM=n && IWLMVM=n
+
menu "Debugging Options"
depends on IWLWIFI
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 6c7800044a04..3b5613ea458b 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -7,8 +7,7 @@ iwlwifi-objs += iwl-notif-wait.o
iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
-iwlwifi-objs += pcie/1000.o pcie/2000.o pcie/5000.o pcie/6000.o
-iwlwifi-objs += pcie/7000.o
+iwlwifi-objs += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o iwl-7000.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TESTMODE) += iwl-test.o
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
index 41ec27cb6efe..48545ab00311 100644
--- a/drivers/net/wireless/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -73,6 +73,8 @@
/* AUX (TX during scan dwell) queue */
#define IWL_AUX_QUEUE 10
+#define IWL_INVALID_STATION 255
+
/* device operations */
extern struct iwl_lib_ops iwl1000_lib;
extern struct iwl_lib_ops iwl2000_lib;
@@ -170,13 +172,13 @@ int iwl_calib_set(struct iwl_priv *priv,
const struct iwl_calib_hdr *cmd, int len);
void iwl_calib_free_results(struct iwl_priv *priv);
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
- char **buf, bool display);
+ char **buf);
int iwlagn_hw_valid_rtc_data_addr(u32 addr);
/* lib */
int iwlagn_send_tx_power(struct iwl_priv *priv);
void iwlagn_temperature(struct iwl_priv *priv);
-int iwlagn_txfifo_flush(struct iwl_priv *priv);
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk);
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv);
int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
int iwl_send_statistics_request(struct iwl_priv *priv,
@@ -210,6 +212,8 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size);
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
+int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid);
int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c
index 6468de8634b0..d6c4cf2ad7c5 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h
index 65e920cab2b7..cfddde194940 100644
--- a/drivers/net/wireless/iwlwifi/dvm/calib.h
+++ b/drivers/net/wireless/iwlwifi/dvm/calib.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h
index 84e2c0fcfef6..95ca026ecc9d 100644
--- a/drivers/net/wireless/iwlwifi/dvm/commands.h
+++ b/drivers/net/wireless/iwlwifi/dvm/commands.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -1526,6 +1526,7 @@ struct iwl_compressed_ba_resp {
__le16 scd_ssn;
u8 txed; /* number of frames sent */
u8 txed_2_done; /* number of frames acked */
+ __le16 reserved1;
} __packed;
/*
diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
index 20806cae11b7..d5329489245a 100644
--- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c
@@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -2237,15 +2237,13 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
- char *buf;
- int pos = 0;
- ssize_t ret = -ENOMEM;
+ char *buf = NULL;
+ ssize_t ret;
- ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
- if (buf) {
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- }
+ ret = iwl_dump_nic_event_log(priv, true, &buf);
+ if (ret > 0)
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
return ret;
}
@@ -2269,7 +2267,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
if (sscanf(buf, "%d", &event_log_flag) != 1)
return -EFAULT;
if (event_log_flag == 1)
- iwl_dump_nic_event_log(priv, true, NULL, false);
+ iwl_dump_nic_event_log(priv, true, NULL);
return count;
}
@@ -2324,6 +2322,28 @@ static ssize_t iwl_dbgfs_calib_disabled_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = file->private_data;
+ bool restart_fw = iwlwifi_mod_params.restart_fw;
+ int ret;
+
+ iwlwifi_mod_params.restart_fw = true;
+
+ mutex_lock(&priv->mutex);
+
+ /* take the return value to make compiler happy - it will fail anyway */
+ ret = iwl_dvm_send_cmd_pdu(priv, REPLY_ERROR, CMD_SYNC, 0, NULL);
+
+ mutex_unlock(&priv->mutex);
+
+ iwlwifi_mod_params.restart_fw = restart_fw;
+
+ return count;
+}
+
DEBUGFS_READ_FILE_OPS(ucode_rx_stats);
DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
DEBUGFS_READ_FILE_OPS(ucode_general_stats);
@@ -2343,6 +2363,7 @@ DEBUGFS_READ_FILE_OPS(bt_traffic);
DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
DEBUGFS_READ_FILE_OPS(reply_tx_error);
DEBUGFS_WRITE_FILE_OPS(echo_test);
+DEBUGFS_WRITE_FILE_OPS(fw_restart);
#ifdef CONFIG_IWLWIFI_DEBUG
DEBUGFS_READ_WRITE_FILE_OPS(log_event);
#endif
@@ -2400,6 +2421,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir)
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR);
+ DEBUGFS_ADD_FILE(fw_restart, dir_debug, S_IWUSR);
#ifdef CONFIG_IWLWIFI_DEBUG
DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR);
#endif
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 15cca2ef9294..c48907c8ab43 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -379,7 +379,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- ch = ch_switch->channel->hw_value;
+ ch = ch_switch->chandef.chan->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
ctx->active.channel, ch);
cmd.channel = cpu_to_le16(ch);
@@ -414,7 +414,8 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
}
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
cmd.switch_time);
- cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+ cmd.expect_beacon =
+ ch_switch->chandef.chan->flags & IEEE80211_CHAN_RADAR;
return iwl_dvm_send_cmd(priv, &hcmd);
}
@@ -540,7 +541,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
hcmd.data[0] = cmd;
cmd->band = priv->band == IEEE80211_BAND_2GHZ;
- ch = ch_switch->channel->hw_value;
+ ch = ch_switch->chandef.chan->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
ctx->active.channel, ch);
cmd->channel = cpu_to_le16(ch);
@@ -575,7 +576,8 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
}
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
cmd->switch_time);
- cmd->expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+ cmd->expect_beacon =
+ ch_switch->chandef.chan->flags & IEEE80211_CHAN_RADAR;
err = iwl_dvm_send_cmd(priv, &hcmd);
kfree(cmd);
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
index 86ea5f4c3939..54f553380aa8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
* 1. acquire mutex before calling
* 2. make sure rf is on and not in exit state
*/
-int iwlagn_txfifo_flush(struct iwl_priv *priv)
+int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk)
{
struct iwl_txfifo_flush_cmd flush_cmd;
struct iwl_host_cmd cmd = {
@@ -162,6 +162,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv)
if (priv->nvm_data->sku_cap_11n_enable)
flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK;
+ if (scd_q_msk)
+ flush_cmd.queue_control = cpu_to_le32(scd_q_msk);
+
IWL_DEBUG_INFO(priv, "queue control: 0x%x\n",
flush_cmd.queue_control);
flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL);
@@ -173,7 +176,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
{
mutex_lock(&priv->mutex);
ieee80211_stop_queues(priv->hw);
- if (iwlagn_txfifo_flush(priv)) {
+ if (iwlagn_txfifo_flush(priv, 0)) {
IWL_ERR(priv, "flush request fail\n");
goto done;
}
@@ -1084,7 +1087,14 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan)
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
- struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+ struct iwlagn_d3_config_cmd d3_cfg_cmd = {
+ /*
+ * Program the minimum sleep time to 10 seconds, as many
+ * platforms have issues processing a wakeup signal while
+ * still being in the process of suspending.
+ */
+ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
+ };
struct wowlan_key_data key_data = {
.ctx = ctx,
.bssid = ctx->active.bssid_addr,
@@ -1262,6 +1272,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
}
/*
+ * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag
+ * in iwl_down but cancel the workers only later.
+ */
+ if (!priv->ucode_loaded) {
+ IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id);
+ return -EIO;
+ }
+
+ /*
* Synchronous commands from this op-mode must hold
* the mutex, this ensures we don't try to send two
* (or more) synchronous commands at a time.
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index 323e4a33fcac..cab23af0be9e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -777,9 +777,12 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
IWL_DEBUG_HT(priv, "start Tx\n");
ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
break;
- case IEEE80211_AMPDU_TX_STOP_CONT:
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ IWL_DEBUG_HT(priv, "Flush Tx\n");
+ ret = iwlagn_tx_agg_flush(priv, vif, sta, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
IWL_DEBUG_HT(priv, "stop Tx\n");
ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
if ((ret == 0) && (priv->agg_tids_count > 0)) {
@@ -967,7 +970,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_channel *channel = ch_switch->channel;
+ struct ieee80211_channel *channel = ch_switch->chandef.chan;
struct iwl_ht_config *ht_conf = &priv->current_ht_config;
/*
* MULTI-FIXME
@@ -1005,11 +1008,21 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
priv->current_ht_config.smps = conf->smps_mode;
/* Configure HT40 channels */
- ctx->ht.enabled = conf_is_ht(conf);
- if (ctx->ht.enabled)
- iwlagn_config_ht40(conf, ctx);
- else
+ switch (cfg80211_get_chandef_type(&ch_switch->chandef)) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
ctx->ht.is_40mhz = false;
+ ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ break;
+ case NL80211_CHAN_HT40MINUS:
+ ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ctx->ht.is_40mhz = true;
+ break;
+ case NL80211_CHAN_HT40PLUS:
+ ctx->ht.extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ctx->ht.is_40mhz = true;
+ break;
+ }
if ((le16_to_cpu(ctx->staging.channel) != ch))
ctx->staging.flags = 0;
@@ -1100,7 +1113,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
@@ -1122,7 +1135,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
*/
if (drop) {
IWL_DEBUG_MAC80211(priv, "send flush command\n");
- if (iwlagn_txfifo_flush(priv)) {
+ if (iwlagn_txfifo_flush(priv, 0)) {
IWL_ERR(priv, "flush request fail\n");
goto done;
}
@@ -1137,7 +1150,8 @@ done:
static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *channel,
- int duration)
+ int duration,
+ enum ieee80211_roc_type type)
{
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index b9e3517652d6..74d7572e7091 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -1795,7 +1795,7 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
- char **buf, bool display)
+ char **buf)
{
u32 base; /* SRAM byte address of event log header */
u32 capacity; /* event log capacity in # entries */
@@ -1866,7 +1866,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
size);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (display) {
+ if (buf) {
if (full_log)
bufsz = capacity * 48;
else
@@ -1962,7 +1962,7 @@ static void iwl_nic_error(struct iwl_op_mode *op_mode)
priv->fw->fw_version);
iwl_dump_nic_error_log(priv);
- iwl_dump_nic_event_log(priv, false, NULL, false);
+ iwl_dump_nic_event_log(priv, false, NULL);
iwlagn_fw_error(priv, false);
}
diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c
index abe304267261..907bd6e50aad 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rs.c
@@ -2831,7 +2831,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
sta_priv = (struct iwl_station_priv *) sta->drv_priv;
lq_sta = &sta_priv->lq_sta;
- sband = hw->wiphy->bands[conf->channel->band];
+ sband = hw->wiphy->bands[conf->chandef.chan->band];
lq_sta->lq.sta_id = sta_id;
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 23be948cf162..707446fa00bd 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -78,8 +78,9 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
#endif
- ctx->staging.channel = cpu_to_le16(priv->hw->conf.channel->hw_value);
- priv->band = priv->hw->conf.channel->band;
+ ctx->staging.channel =
+ cpu_to_le16(priv->hw->conf.chandef.chan->hw_value);
+ priv->band = priv->hw->conf.chandef.chan->band;
iwl_set_flags_for_band(priv, ctx, priv->band, ctx->vif);
@@ -951,7 +952,7 @@ static void iwl_calc_basic_rates(struct iwl_priv *priv,
unsigned long basic = ctx->vif->bss_conf.basic_rates;
int i;
- sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
+ sband = priv->hw->wiphy->bands[priv->hw->conf.chandef.chan->band];
for_each_set_bit(i, &basic, BITS_PER_LONG) {
int hw = sband->bitrates[i].hw_value;
@@ -1159,7 +1160,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
}
void iwlagn_config_ht40(struct ieee80211_conf *conf,
- struct iwl_rxon_context *ctx)
+ struct iwl_rxon_context *ctx)
{
if (conf_is_ht40_minus(conf)) {
ctx->ht.extension_chan_offset =
@@ -1181,7 +1182,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
struct iwl_rxon_context *ctx;
struct ieee80211_conf *conf = &hw->conf;
- struct ieee80211_channel *channel = conf->channel;
+ struct ieee80211_channel *channel = conf->chandef.chan;
int ret = 0;
IWL_DEBUG_MAC80211(priv, "enter: changed %#x\n", changed);
@@ -1419,6 +1420,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&priv->mutex);
+ if (changes & BSS_CHANGED_IDLE && bss_conf->idle) {
+ /*
+ * If we go idle, then clearly no "passive-no-rx"
+ * workaround is needed any more, this is a reset.
+ */
+ iwlagn_lift_passive_no_rx(priv);
+ }
+
if (unlikely(!iwl_is_ready(priv))) {
IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
mutex_unlock(&priv->mutex);
@@ -1450,16 +1459,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->sync_tsf;
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
} else {
- /*
- * If we disassociate while there are pending
- * frames, just wake up the queues and let the
- * frames "escape" ... This shouldn't really
- * be happening to start with, but we should
- * not get stuck in this case either since it
- * can happen if userspace gets confused.
- */
- iwlagn_lift_passive_no_rx(priv);
-
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
if (ctx->ctxid == IWL_RXON_CTX_BSS)
diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c
index 3a4aa5239c45..d69b55866714 100644
--- a/drivers/net/wireless/iwlwifi/dvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/dvm/scan.c
@@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c
index b775769f8322..db183b44e038 100644
--- a/drivers/net/wireless/iwlwifi/dvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/dvm/sta.c
@@ -695,6 +695,7 @@ void iwl_clear_ucode_stations(struct iwl_priv *priv,
void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
struct iwl_addsta_cmd sta_cmd;
+ static const struct iwl_link_quality_cmd zero_lq = {};
struct iwl_link_quality_cmd lq;
int i;
bool found = false;
@@ -733,7 +734,9 @@ void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
else
memcpy(&lq, priv->stations[i].lq,
sizeof(struct iwl_link_quality_cmd));
- send_lq = true;
+
+ if (!memcmp(&lq, &zero_lq, sizeof(lq)))
+ send_lq = true;
}
spin_unlock_bh(&priv->sta_lock);
ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
diff --git a/drivers/net/wireless/iwlwifi/dvm/testmode.c b/drivers/net/wireless/iwlwifi/dvm/testmode.c
index dc6f965a123a..b89b9d9b9969 100644
--- a/drivers/net/wireless/iwlwifi/dvm/testmode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/testmode.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index 6aec2df3bb27..a900aaf47790 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -418,7 +418,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv,
" Tx flags = 0x%08x, agg.state = %d",
info->flags, tid_data->agg.state);
IWL_ERR(priv, "sta_id = %d, tid = %d seq_num = %d",
- sta_id, tid, SEQ_TO_SN(tid_data->seq_number));
+ sta_id, tid,
+ IEEE80211_SEQ_TO_SN(tid_data->seq_number));
goto drop_unlock_sta;
}
@@ -569,7 +570,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
return 0;
}
- tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
/* There are still packets for this RA / TID in the HW */
if (!test_bit(txq_id, priv->agg_q_alloc)) {
@@ -651,7 +652,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
spin_lock_bh(&priv->sta_lock);
tid_data = &priv->tid_data[sta_id][tid];
- tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
*ssn = tid_data->agg.ssn;
@@ -673,6 +674,51 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
return ret;
}
+int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct iwl_tid_data *tid_data;
+ enum iwl_agg_state agg_state;
+ int sta_id, txq_id;
+ sta_id = iwl_sta_id(sta);
+
+ /*
+ * First set the agg state to OFF to avoid calling
+ * ieee80211_stop_tx_ba_cb in iwlagn_check_ratid_empty.
+ */
+ spin_lock_bh(&priv->sta_lock);
+
+ tid_data = &priv->tid_data[sta_id][tid];
+ txq_id = tid_data->agg.txq_id;
+ agg_state = tid_data->agg.state;
+ IWL_DEBUG_TX_QUEUES(priv, "Flush AGG: sta %d tid %d q %d state %d\n",
+ sta_id, tid, txq_id, tid_data->agg.state);
+
+ tid_data->agg.state = IWL_AGG_OFF;
+
+ spin_unlock_bh(&priv->sta_lock);
+
+ if (iwlagn_txfifo_flush(priv, BIT(txq_id)))
+ IWL_ERR(priv, "Couldn't flush the AGG queue\n");
+
+ if (test_bit(txq_id, priv->agg_q_alloc)) {
+ /*
+ * If the transport didn't know that we wanted to start
+ * agreggation, don't tell it that we want to stop them.
+ * This can happen when we don't get the addBA response on
+ * time, or we hadn't time to drain the AC queues.
+ */
+ if (agg_state == IWL_AGG_ON)
+ iwl_trans_txq_disable(priv->trans, txq_id);
+ else
+ IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
+ agg_state);
+ iwlagn_dealloc_agg_txq(priv, txq_id);
+ }
+
+ return 0;
+}
+
int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size)
{
@@ -911,7 +957,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp)
{
return le32_to_cpup((__le32 *)&tx_resp->status +
- tx_resp->frame_count) & MAX_SN;
+ tx_resp->frame_count) & IEEE80211_MAX_SN;
}
static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
@@ -1148,7 +1194,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
if (tx_resp->frame_count == 1) {
u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
- next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
+ next_reclaimed = IEEE80211_SEQ_TO_SN(next_reclaimed + 0x10);
if (is_agg) {
/* If this is an aggregation queue, we can rely on the
@@ -1192,7 +1238,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
memset(&info->status, 0, sizeof(info->status));
if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
- iwl_is_associated_ctx(ctx) && ctx->vif &&
+ ctx->vif &&
ctx->vif->type == NL80211_IFTYPE_STATION) {
/* block and stop all queues */
priv->passive_no_rx = true;
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index 736fe9bb140e..0a1cdc5e856b 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -19,7 +19,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return -EIO;
}
+ priv->ucode_loaded = true;
+
if (ucode_type != IWL_UCODE_WOWLAN) {
/* delay a bit to give rfkill time to run */
msleep(5);
@@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
return ret;
}
- priv->ucode_loaded = true;
-
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/pcie/1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index ff3389757281..c080ae3070b2 100644
--- a/drivers/net/wireless/iwlwifi/pcie/1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -29,7 +29,6 @@
#include "iwl-config.h"
#include "iwl-csr.h"
#include "iwl-agn-hw.h"
-#include "cfg.h"
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 5
diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index e7de33128b16..a6ddd2f9fba0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -28,7 +28,6 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
-#include "cfg.h"
#include "dvm/commands.h" /* needed for BT for now */
/* Highest firmware API version supported */
diff --git a/drivers/net/wireless/iwlwifi/pcie/5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 5096f7c96ab6..403f3f224bf6 100644
--- a/drivers/net/wireless/iwlwifi/pcie/5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -29,7 +29,6 @@
#include "iwl-config.h"
#include "iwl-agn-hw.h"
#include "iwl-csr.h"
-#include "cfg.h"
/* Highest firmware API version supported */
#define IWL5000_UCODE_API_MAX 5
diff --git a/drivers/net/wireless/iwlwifi/pcie/6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 801ff49796dd..b5ab8d1bcac0 100644
--- a/drivers/net/wireless/iwlwifi/pcie/6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -28,7 +28,6 @@
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
-#include "cfg.h"
#include "dvm/commands.h" /* needed for BT for now */
/* Highest firmware API version supported */
diff --git a/drivers/net/wireless/iwlwifi/pcie/7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 6e35b2b72332..50263e87fe15 100644
--- a/drivers/net/wireless/iwlwifi/pcie/7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -1,34 +1,70 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
*
- * The full GNU General Public License is included in this distribution in the
- * file called LICENSE.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
*****************************************************************************/
#include <linux/module.h>
#include <linux/stringify.h>
#include "iwl-config.h"
#include "iwl-agn-hw.h"
-#include "cfg.h"
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 6
@@ -70,7 +106,6 @@ static const struct iwl_base_params iwl7000_base_params = {
};
static const struct iwl_ht_params iwl7000_ht_params = {
- .ht_greenfield_support = true,
.use_rts_for_aggregation = true, /* use rts/cts protection */
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index e9975c54c276..6d73f943cefa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 743b48343358..c38aa8f77554 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -275,4 +275,51 @@ struct iwl_cfg {
const bool temp_offset_v2;
};
+/*
+ * This list declares the config structures for all devices.
+ */
+extern const struct iwl_cfg iwl5300_agn_cfg;
+extern const struct iwl_cfg iwl5100_agn_cfg;
+extern const struct iwl_cfg iwl5350_agn_cfg;
+extern const struct iwl_cfg iwl5100_bgn_cfg;
+extern const struct iwl_cfg iwl5100_abg_cfg;
+extern const struct iwl_cfg iwl5150_agn_cfg;
+extern const struct iwl_cfg iwl5150_abg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_cfg;
+extern const struct iwl_cfg iwl6005_2abg_cfg;
+extern const struct iwl_cfg iwl6005_2bg_cfg;
+extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
+extern const struct iwl_cfg iwl6005_2agn_d_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
+extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
+extern const struct iwl_cfg iwl1030_bgn_cfg;
+extern const struct iwl_cfg iwl1030_bg_cfg;
+extern const struct iwl_cfg iwl6030_2agn_cfg;
+extern const struct iwl_cfg iwl6030_2abg_cfg;
+extern const struct iwl_cfg iwl6030_2bgn_cfg;
+extern const struct iwl_cfg iwl6030_2bg_cfg;
+extern const struct iwl_cfg iwl6000i_2agn_cfg;
+extern const struct iwl_cfg iwl6000i_2abg_cfg;
+extern const struct iwl_cfg iwl6000i_2bg_cfg;
+extern const struct iwl_cfg iwl6000_3agn_cfg;
+extern const struct iwl_cfg iwl6050_2agn_cfg;
+extern const struct iwl_cfg iwl6050_2abg_cfg;
+extern const struct iwl_cfg iwl6150_bgn_cfg;
+extern const struct iwl_cfg iwl6150_bg_cfg;
+extern const struct iwl_cfg iwl1000_bgn_cfg;
+extern const struct iwl_cfg iwl1000_bg_cfg;
+extern const struct iwl_cfg iwl100_bgn_cfg;
+extern const struct iwl_cfg iwl100_bg_cfg;
+extern const struct iwl_cfg iwl130_bgn_cfg;
+extern const struct iwl_cfg iwl130_bg_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_cfg;
+extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
+extern const struct iwl_cfg iwl2030_2bgn_cfg;
+extern const struct iwl_cfg iwl6035_2agn_cfg;
+extern const struct iwl_cfg iwl105_bgn_cfg;
+extern const struct iwl_cfg iwl105_bgn_d_cfg;
+extern const struct iwl_cfg iwl135_bgn_cfg;
+extern const struct iwl_cfg iwl7260_2ac_cfg;
+extern const struct iwl_cfg iwl3160_ac_cfg;
+
#endif /* __IWL_CONFIG_H__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index df3463a38704..20e845d4da04 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c
index 87535a67de76..8a44f594528d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -66,6 +66,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-debug.h"
#include "iwl-devtrace.h"
@@ -85,11 +86,11 @@ void __iwl_ ##fn(struct device *dev, const char *fmt, ...) \
}
__iwl_fn(warn)
-EXPORT_SYMBOL_GPL(__iwl_warn);
+IWL_EXPORT_SYMBOL(__iwl_warn);
__iwl_fn(info)
-EXPORT_SYMBOL_GPL(__iwl_info);
+IWL_EXPORT_SYMBOL(__iwl_info);
__iwl_fn(crit)
-EXPORT_SYMBOL_GPL(__iwl_crit);
+IWL_EXPORT_SYMBOL(__iwl_crit);
void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
const char *fmt, ...)
@@ -110,7 +111,7 @@ void __iwl_err(struct device *dev, bool rfkill_prefix, bool trace_only,
trace_iwlwifi_err(&vaf);
va_end(args);
}
-EXPORT_SYMBOL_GPL(__iwl_err);
+IWL_EXPORT_SYMBOL(__iwl_err);
#if defined(CONFIG_IWLWIFI_DEBUG) || defined(CONFIG_IWLWIFI_DEVICE_TRACING)
void __iwl_dbg(struct device *dev,
@@ -133,5 +134,5 @@ void __iwl_dbg(struct device *dev,
trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf);
va_end(args);
}
-EXPORT_SYMBOL_GPL(__iwl_dbg);
+IWL_EXPORT_SYMBOL(__iwl_dbg);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 81aa91fab5aa..4491c1c72cc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -298,7 +298,7 @@ TRACE_EVENT(iwlwifi_dbg,
MAX_MSG_LEN, vaf->fmt,
*vaf->va) >= MAX_MSG_LEN);
),
- TP_printk("%s", (char *)__get_dynamic_array(msg))
+ TP_printk("%s", __get_str(msg))
);
#undef TRACE_SYSTEM
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index fbfd2d137117..39aad9893e0b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -912,8 +912,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
}
}
- IWL_INFO(drv, "loaded firmware version %s", drv->fw.fw_version);
-
/*
* In mvm uCode there is no difference between data and instructions
* sections.
@@ -970,6 +968,9 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
else
op = &iwlwifi_opmode_table[DVM_OP_MODE];
+ IWL_INFO(drv, "loaded firmware version %s op_mode %s\n",
+ drv->fw.fw_version, op->name);
+
/* add this device to the list of devices using this op_mode */
list_add_tail(&drv->list, &op->drv);
@@ -997,8 +998,13 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
* else from proceeding if the module fails to load
* or hangs loading.
*/
- if (load_module)
- request_module("%s", op->name);
+ if (load_module) {
+ err = request_module("%s", op->name);
+ if (err)
+ IWL_ERR(drv,
+ "failed to load module %s (error %d), is dynamic loading enabled?\n",
+ op->name, err);
+ }
return;
try_again:
@@ -1102,7 +1108,7 @@ void iwl_drv_stop(struct iwl_drv *drv)
/* shared module parameters */
struct iwl_mod_params iwlwifi_mod_params = {
- .restart_fw = 1,
+ .restart_fw = true,
.plcp_check = true,
.bt_coex_active = true,
.power_level = IWL_POWER_INDEX_1,
@@ -1111,7 +1117,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
.wd_disable = true,
/* the rest are 0 by default */
};
-EXPORT_SYMBOL_GPL(iwlwifi_mod_params);
+IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
{
@@ -1135,7 +1141,7 @@ int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops)
mutex_unlock(&iwlwifi_opmode_table_mtx);
return -EIO;
}
-EXPORT_SYMBOL_GPL(iwl_opmode_register);
+IWL_EXPORT_SYMBOL(iwl_opmode_register);
void iwl_opmode_deregister(const char *name)
{
@@ -1157,7 +1163,7 @@ void iwl_opmode_deregister(const char *name)
}
mutex_unlock(&iwlwifi_opmode_table_mtx);
}
-EXPORT_SYMBOL_GPL(iwl_opmode_deregister);
+IWL_EXPORT_SYMBOL(iwl_opmode_deregister);
static int __init iwl_drv_init(void)
{
@@ -1207,8 +1213,8 @@ MODULE_PARM_DESC(11n_disable,
module_param_named(amsdu_size_8K, iwlwifi_mod_params.amsdu_size_8K,
int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0)");
-module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
+module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
+MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
int, S_IRUGO);
@@ -1266,7 +1272,3 @@ module_param_named(auto_agg, iwlwifi_mod_params.auto_agg,
bool, S_IRUGO);
MODULE_PARM_DESC(auto_agg,
"enable agg w/o check traffic load (default: enable)");
-
-module_param_named(5ghz_disable, iwlwifi_mod_params.disable_5ghz,
- bool, S_IRUGO);
-MODULE_PARM_DESC(5ghz_disable, "disable 5GHz band (default: 0 [enabled])");
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index 594a5c71b272..7d1450916308 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,8 @@
#ifndef __iwl_drv_h__
#define __iwl_drv_h__
+#include <linux/module.h>
+
/* for all modules */
#define DRV_NAME "iwlwifi"
#define IWLWIFI_VERSION "in-tree:"
@@ -123,4 +125,17 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans,
*/
void iwl_drv_stop(struct iwl_drv *drv);
+/*
+ * exported symbol management
+ *
+ * The driver can be split into multiple modules, in which case some symbols
+ * must be exported for the sub-modules. However, if it's not split and
+ * everything is built-in, then we can avoid that.
+ */
+#ifdef CONFIG_IWLWIFI_OPMODE_MODULAR
+#define IWL_EXPORT_SYMBOL(sym) EXPORT_SYMBOL_GPL(sym)
+#else
+#define IWL_EXPORT_SYMBOL(sym)
+#endif
+
#endif /* __iwl_drv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
index 034f2ff4f43d..600c9fdd7f71 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-eeprom-parse.h"
@@ -749,7 +750,7 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
}
ht_info->ht_supported = true;
- ht_info->cap = 0;
+ ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40;
if (iwlwifi_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
@@ -909,7 +910,7 @@ iwl_parse_eeprom_data(struct device *dev, const struct iwl_cfg *cfg,
kfree(data);
return NULL;
}
-EXPORT_SYMBOL_GPL(iwl_parse_eeprom_data);
+IWL_EXPORT_SYMBOL(iwl_parse_eeprom_data);
/* helper functions */
int iwl_nvm_check_version(struct iwl_nvm_data *data,
@@ -928,4 +929,4 @@ int iwl_nvm_check_version(struct iwl_nvm_data *data,
data->calib_version, trans->cfg->nvm_calib_ver);
return -EINVAL;
}
-EXPORT_SYMBOL_GPL(iwl_nvm_check_version);
+IWL_EXPORT_SYMBOL(iwl_nvm_check_version);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
index 683fe6a8c58f..37f115390b19 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
index ef4806f27cf8..e5f2e362ab0b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,7 @@
#include <linux/slab.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-debug.h"
#include "iwl-eeprom-read.h"
#include "iwl-io.h"
@@ -460,4 +461,4 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size)
return ret;
}
-EXPORT_SYMBOL_GPL(iwl_read_eeprom);
+IWL_EXPORT_SYMBOL(iwl_read_eeprom);
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
index b2588c5cbf93..8e941f8bd7d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index f5592fb3b1ed..484d318245fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 90873eca35f7..8b6c6fd95ed0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index b545178e46e3..c4c446d41eb0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -73,12 +73,14 @@
* treats good CRC threshold as a boolean
* @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
* @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
+ * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
*/
enum iwl_ucode_tlv_flag {
IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1),
IWL_UCODE_TLV_FLAGS_MFP = BIT(2),
IWL_UCODE_TLV_FLAGS_P2P = BIT(3),
+ IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
};
/* The default calibrate table size if not specified by firmware file */
@@ -152,6 +154,19 @@ struct iwl_tlv_calib_ctrl {
__le32 event_trigger;
} __packed;
+enum iwl_fw_phy_cfg {
+ FW_PHY_CFG_RADIO_TYPE_POS = 0,
+ FW_PHY_CFG_RADIO_TYPE = 0x3 << FW_PHY_CFG_RADIO_TYPE_POS,
+ FW_PHY_CFG_RADIO_STEP_POS = 2,
+ FW_PHY_CFG_RADIO_STEP = 0x3 << FW_PHY_CFG_RADIO_STEP_POS,
+ FW_PHY_CFG_RADIO_DASH_POS = 4,
+ FW_PHY_CFG_RADIO_DASH = 0x3 << FW_PHY_CFG_RADIO_DASH_POS,
+ FW_PHY_CFG_TX_CHAIN_POS = 16,
+ FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS,
+ FW_PHY_CFG_RX_CHAIN_POS = 20,
+ FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
+};
+
/**
* struct iwl_fw - variables associated with the firmware
*
@@ -188,4 +203,16 @@ struct iwl_fw {
bool mvm_fw;
};
+static inline u8 iwl_fw_valid_tx_ant(const struct iwl_fw *fw)
+{
+ return (fw->phy_config & FW_PHY_CFG_TX_CHAIN) >>
+ FW_PHY_CFG_TX_CHAIN_POS;
+}
+
+static inline u8 iwl_fw_valid_rx_ant(const struct iwl_fw *fw)
+{
+ return (fw->phy_config & FW_PHY_CFG_RX_CHAIN) >>
+ FW_PHY_CFG_RX_CHAIN_POS;
+}
+
#endif /* __iwl_fw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 276410d82de4..305c81f2c2b4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -29,6 +29,7 @@
#include <linux/device.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-io.h"
#include "iwl-csr.h"
#include "iwl-debug.h"
@@ -49,7 +50,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr,
return -ETIMEDOUT;
}
-EXPORT_SYMBOL_GPL(iwl_poll_bit);
+IWL_EXPORT_SYMBOL(iwl_poll_bit);
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
{
@@ -62,7 +63,7 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg)
return value;
}
-EXPORT_SYMBOL_GPL(iwl_read_direct32);
+IWL_EXPORT_SYMBOL(iwl_read_direct32);
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
{
@@ -73,7 +74,7 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
iwl_trans_release_nic_access(trans, &flags);
}
}
-EXPORT_SYMBOL_GPL(iwl_write_direct32);
+IWL_EXPORT_SYMBOL(iwl_write_direct32);
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
int timeout)
@@ -89,7 +90,7 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
return -ETIMEDOUT;
}
-EXPORT_SYMBOL_GPL(iwl_poll_direct_bit);
+IWL_EXPORT_SYMBOL(iwl_poll_direct_bit);
static inline u32 __iwl_read_prph(struct iwl_trans *trans, u32 ofs)
{
@@ -115,7 +116,7 @@ u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
}
return val;
}
-EXPORT_SYMBOL_GPL(iwl_read_prph);
+IWL_EXPORT_SYMBOL(iwl_read_prph);
void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
{
@@ -126,7 +127,7 @@ void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
iwl_trans_release_nic_access(trans, &flags);
}
}
-EXPORT_SYMBOL_GPL(iwl_write_prph);
+IWL_EXPORT_SYMBOL(iwl_write_prph);
void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
@@ -138,7 +139,7 @@ void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
iwl_trans_release_nic_access(trans, &flags);
}
}
-EXPORT_SYMBOL_GPL(iwl_set_bits_prph);
+IWL_EXPORT_SYMBOL(iwl_set_bits_prph);
void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
u32 bits, u32 mask)
@@ -151,7 +152,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
iwl_trans_release_nic_access(trans, &flags);
}
}
-EXPORT_SYMBOL_GPL(iwl_set_bits_mask_prph);
+IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph);
void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
{
@@ -164,4 +165,4 @@ void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
iwl_trans_release_nic_access(trans, &flags);
}
}
-EXPORT_SYMBOL_GPL(iwl_clear_bits_prph);
+IWL_EXPORT_SYMBOL(iwl_clear_bits_prph);
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 2c2a729092f5..d6f6c37c09fd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -103,13 +103,12 @@ enum iwl_power_level {
* @ant_coupling: antenna coupling in dB, default = 0
* @bt_ch_announce: BT channel inhibition, default = enable
* @auto_agg: enable agg. without check, default = true
- * @disable_5ghz: disable 5GHz capability, default = false
*/
struct iwl_mod_params {
int sw_crypto;
unsigned int disable_11n;
int amsdu_size_8K;
- int restart_fw;
+ bool restart_fw;
bool plcp_check;
int wd_disable;
bool bt_coex_active;
@@ -120,7 +119,6 @@ struct iwl_mod_params {
int ant_coupling;
bool bt_ch_announce;
bool auto_agg;
- bool disable_5ghz;
};
#endif /* #__iwl_modparams_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index c3affbc62cdf..940b8a9d5285 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -63,6 +63,7 @@
#include <linux/sched.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-notif-wait.h"
@@ -72,7 +73,7 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
INIT_LIST_HEAD(&notif_wait->notif_waits);
init_waitqueue_head(&notif_wait->notif_waitq);
}
-EXPORT_SYMBOL_GPL(iwl_notification_wait_init);
+IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
struct iwl_rx_packet *pkt)
@@ -117,7 +118,7 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
if (triggered)
wake_up_all(&notif_wait->notif_waitq);
}
-EXPORT_SYMBOL_GPL(iwl_notification_wait_notify);
+IWL_EXPORT_SYMBOL(iwl_notification_wait_notify);
void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
{
@@ -130,7 +131,7 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
wake_up_all(&notif_wait->notif_waitq);
}
-EXPORT_SYMBOL_GPL(iwl_abort_notification_waits);
+IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);
void
iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
@@ -154,7 +155,7 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
list_add(&wait_entry->list, &notif_wait->notif_waits);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
-EXPORT_SYMBOL_GPL(iwl_init_notification_wait);
+IWL_EXPORT_SYMBOL(iwl_init_notification_wait);
int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry,
@@ -178,7 +179,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
return -ETIMEDOUT;
return 0;
}
-EXPORT_SYMBOL_GPL(iwl_wait_notification);
+IWL_EXPORT_SYMBOL(iwl_wait_notification);
void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
struct iwl_notification_wait *wait_entry)
@@ -187,4 +188,4 @@ void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
list_del(&wait_entry->list);
spin_unlock_bh(&notif_wait->notif_wait_lock);
}
-EXPORT_SYMBOL_GPL(iwl_remove_notification);
+IWL_EXPORT_SYMBOL(iwl_remove_notification);
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
index c2ce764463a3..2e2f1c8c99f9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index a70213bdb83c..6199a0a597a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -62,6 +62,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-modparams.h"
#include "iwl-nvm-parse.h"
@@ -149,6 +150,8 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
* @NVM_CHANNEL_DFS: dynamic freq selection candidate
* @NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
* @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
+ * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
+ * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
*/
enum iwl_nvm_channel_flags {
NVM_CHANNEL_VALID = BIT(0),
@@ -158,6 +161,8 @@ enum iwl_nvm_channel_flags {
NVM_CHANNEL_DFS = BIT(7),
NVM_CHANNEL_WIDE = BIT(8),
NVM_CHANNEL_40MHZ = BIT(9),
+ NVM_CHANNEL_80MHZ = BIT(10),
+ NVM_CHANNEL_160MHZ = BIT(11),
};
#define CHECK_AND_PRINT_I(x) \
@@ -210,6 +215,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
else
channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
}
+ if (!(ch_flags & NVM_CHANNEL_80MHZ))
+ channel->flags |= IEEE80211_CHAN_NO_80MHZ;
+ if (!(ch_flags & NVM_CHANNEL_160MHZ))
+ channel->flags |= IEEE80211_CHAN_NO_160MHZ;
if (!(ch_flags & NVM_CHANNEL_IBSS))
channel->flags |= IEEE80211_CHAN_NO_IBSS;
@@ -245,6 +254,43 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
return n_channels;
}
+static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
+ struct iwl_nvm_data *data,
+ struct ieee80211_sta_vht_cap *vht_cap)
+{
+ /* For now, assume new devices with NVM are VHT capable */
+
+ vht_cap->vht_supported = true;
+
+ vht_cap->cap = IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_RXSTBC_1 |
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+ if (iwlwifi_mod_params.amsdu_size_8K)
+ vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
+
+ vht_cap->vht_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 |
+ IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
+
+ if (data->valid_rx_ant == 1 || cfg->rx_with_siso_diversity) {
+ vht_cap->cap |= IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+ IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+ /* this works because NOT_SUPPORTED == 3 */
+ vht_cap->vht_mcs.rx_mcs_map |=
+ cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << 2);
+ }
+
+ vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+}
+
static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
struct iwl_nvm_data *data, const __le16 *nvm_sw)
{
@@ -268,6 +314,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
n_used += iwl_init_sband_channels(data, sband, n_channels,
IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ);
+ iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap);
if (n_channels != n_used)
IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n",
@@ -343,4 +390,4 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
return data;
}
-EXPORT_SYMBOL_GPL(iwl_parse_nvm_data);
+IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
index b2692bd287fa..e57fb989661e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
index 4a680019e117..98c7aa7346da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
index 3392011a8768..25745daa0d5d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -65,6 +65,7 @@
#include <linux/string.h>
#include <linux/export.h>
+#include "iwl-drv.h"
#include "iwl-phy-db.h"
#include "iwl-debug.h"
#include "iwl-op-mode.h"
@@ -149,7 +150,7 @@ struct iwl_phy_db *iwl_phy_db_init(struct iwl_trans *trans)
/* TODO: add default values of the phy db. */
return phy_db;
}
-EXPORT_SYMBOL(iwl_phy_db_init);
+IWL_EXPORT_SYMBOL(iwl_phy_db_init);
/*
* get phy db section: returns a pointer to a phy db section specified by
@@ -215,7 +216,7 @@ void iwl_phy_db_free(struct iwl_phy_db *phy_db)
kfree(phy_db);
}
-EXPORT_SYMBOL(iwl_phy_db_free);
+IWL_EXPORT_SYMBOL(iwl_phy_db_free);
int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
gfp_t alloc_ctx)
@@ -260,7 +261,7 @@ int iwl_phy_db_set_section(struct iwl_phy_db *phy_db, struct iwl_rx_packet *pkt,
return 0;
}
-EXPORT_SYMBOL(iwl_phy_db_set_section);
+IWL_EXPORT_SYMBOL(iwl_phy_db_set_section);
static int is_valid_channel(u16 ch_id)
{
@@ -495,4 +496,4 @@ int iwl_send_phy_db_data(struct iwl_phy_db *phy_db)
"Finished sending phy db non channel data\n");
return 0;
}
-EXPORT_SYMBOL(iwl_send_phy_db_data);
+IWL_EXPORT_SYMBOL(iwl_send_phy_db_data);
diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
index d0e43d96ab38..ce983af79644 100644
--- a/drivers/net/wireless/iwlwifi/iwl-phy-db.h
+++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index f76e9cad7757..386f2a7c87cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.c b/drivers/net/wireless/iwlwifi/iwl-test.c
index ce0c67b425ee..5cfd55b86ed3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.c
+++ b/drivers/net/wireless/iwlwifi/iwl-test.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -64,6 +64,7 @@
#include <linux/export.h>
#include <net/netlink.h>
+#include "iwl-drv.h"
#include "iwl-io.h"
#include "iwl-fh.h"
#include "iwl-prph.h"
@@ -271,7 +272,7 @@ static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
reply_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
skb = iwl_test_alloc_reply(tst, reply_len + 20);
- reply_buf = kmalloc(reply_len, GFP_KERNEL);
+ reply_buf = kmemdup(&pkt->hdr, reply_len, GFP_KERNEL);
if (!skb || !reply_buf) {
kfree_skb(skb);
kfree(reply_buf);
@@ -279,7 +280,6 @@ static int iwl_test_fw_cmd(struct iwl_test *tst, struct nlattr **tb)
}
/* The reply is in a page, that we cannot send to user space. */
- memcpy(reply_buf, &(pkt->hdr), reply_len);
iwl_free_resp(&cmd);
if (nla_put_u32(skb, IWL_TM_ATTR_COMMAND,
@@ -653,7 +653,7 @@ int iwl_test_parse(struct iwl_test *tst, struct nlattr **tb,
}
return 0;
}
-EXPORT_SYMBOL_GPL(iwl_test_parse);
+IWL_EXPORT_SYMBOL(iwl_test_parse);
/*
* Handle test commands.
@@ -715,7 +715,7 @@ int iwl_test_handle_cmd(struct iwl_test *tst, struct nlattr **tb)
}
return result;
}
-EXPORT_SYMBOL_GPL(iwl_test_handle_cmd);
+IWL_EXPORT_SYMBOL(iwl_test_handle_cmd);
static int iwl_test_trace_dump(struct iwl_test *tst, struct sk_buff *skb,
struct netlink_callback *cb)
@@ -803,7 +803,7 @@ int iwl_test_dump(struct iwl_test *tst, u32 cmd, struct sk_buff *skb,
}
return result;
}
-EXPORT_SYMBOL_GPL(iwl_test_dump);
+IWL_EXPORT_SYMBOL(iwl_test_dump);
/*
* Multicast a spontaneous messages from the device to the user space.
@@ -849,4 +849,4 @@ void iwl_test_rx(struct iwl_test *tst, struct iwl_rx_cmd_buffer *rxb)
if (tst->notify)
iwl_test_send_rx(tst, rxb);
}
-EXPORT_SYMBOL_GPL(iwl_test_rx);
+IWL_EXPORT_SYMBOL(iwl_test_rx);
diff --git a/drivers/net/wireless/iwlwifi/iwl-test.h b/drivers/net/wireless/iwlwifi/iwl-test.h
index 7fbf4d717caa..8fbd21704840 100644
--- a/drivers/net/wireless/iwlwifi/iwl-test.h
+++ b/drivers/net/wireless/iwlwifi/iwl-test.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
index a963f45c6849..98f48a9afc98 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.h
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 0cac2b7af78b..7a13790b5bfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -114,9 +114,6 @@
* completely agnostic to these differences.
* The transport does provide helper functionnality (i.e. SYNC / ASYNC mode),
*/
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
#define SEQ_TO_QUEUE(s) (((s) >> 8) & 0x1f)
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
#define SEQ_TO_INDEX(s) ((s) & 0xff)
@@ -308,7 +305,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
* currently supports
*/
#define IWL_MAX_HW_QUEUES 32
-#define IWL_INVALID_STATION 255
#define IWL_MAX_TID_COUNT 8
#define IWL_FRAME_LIMIT 64
@@ -685,7 +681,7 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
int fifo)
{
- iwl_trans_txq_enable(trans, queue, fifo, IWL_INVALID_STATION,
+ iwl_trans_txq_enable(trans, queue, fifo, -1,
IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/Makefile b/drivers/net/wireless/iwlwifi/mvm/Makefile
index 807b250ec396..2acc44b40986 100644
--- a/drivers/net/wireless/iwlwifi/mvm/Makefile
+++ b/drivers/net/wireless/iwlwifi/mvm/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_IWLMVM) += iwlmvm.o
iwlmvm-y += fw.o mac80211.o nvm.o ops.o phy-ctxt.o mac-ctxt.o
iwlmvm-y += utils.o rx.o tx.o binding.o quota.o sta.o
iwlmvm-y += scan.o time-event.o rs.o
-iwlmvm-y += power.o
+iwlmvm-y += power.o bt-coex.o
iwlmvm-y += led.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
iwlmvm-$(CONFIG_PM_SLEEP) += d3.o
diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c
index 73d24aacb90a..93fd1457954b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/binding.c
+++ b/drivers/net/wireless/iwlwifi/mvm/binding.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
new file mode 100644
index 000000000000..810bfa5f6de0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c
@@ -0,0 +1,589 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * 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 version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#include <net/mac80211.h>
+
+#include "fw-api-bt-coex.h"
+#include "iwl-modparams.h"
+#include "mvm.h"
+#include "iwl-debug.h"
+
+#define EVENT_PRIO_ANT(_evt, _prio, _shrd_ant) \
+ [(_evt)] = (((_prio) << BT_COEX_PRIO_TBL_PRIO_POS) | \
+ ((_shrd_ant) << BT_COEX_PRIO_TBL_SHRD_ANT_POS))
+
+static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB1,
+ BT_COEX_PRIO_TBL_PRIO_BYPASS, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_INIT_CALIB2,
+ BT_COEX_PRIO_TBL_PRIO_BYPASS, 1),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1,
+ BT_COEX_PRIO_TBL_PRIO_LOW, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2,
+ BT_COEX_PRIO_TBL_PRIO_LOW, 1),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1,
+ BT_COEX_PRIO_TBL_PRIO_HIGH, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2,
+ BT_COEX_PRIO_TBL_PRIO_HIGH, 1),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_DTIM,
+ BT_COEX_PRIO_TBL_DISABLED, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN52,
+ BT_COEX_PRIO_TBL_PRIO_COEX_OFF, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_SCAN24,
+ BT_COEX_PRIO_TBL_PRIO_COEX_ON, 0),
+ EVENT_PRIO_ANT(BT_COEX_PRIO_TBL_EVT_IDLE,
+ BT_COEX_PRIO_TBL_PRIO_COEX_IDLE, 0),
+ 0, 0, 0, 0, 0, 0,
+};
+
+#undef EVENT_PRIO_ANT
+
+/* BT Antenna Coupling Threshold (dB) */
+#define IWL_BT_ANTENNA_COUPLING_THRESHOLD (35)
+#define IWL_BT_LOAD_FORCE_SISO_THRESHOLD (3)
+
+#define BT_ENABLE_REDUCED_TXPOWER_THRESHOLD (-62)
+#define BT_DISABLE_REDUCED_TXPOWER_THRESHOLD (-65)
+#define BT_REDUCED_TX_POWER_BIT BIT(7)
+
+static inline bool is_loose_coex(void)
+{
+ return iwlwifi_mod_params.ant_coupling >
+ IWL_BT_ANTENNA_COUPLING_THRESHOLD;
+}
+
+int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
+{
+ return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC,
+ sizeof(struct iwl_bt_coex_prio_tbl_cmd),
+ &iwl_bt_prio_tbl);
+}
+
+static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type)
+{
+ struct iwl_bt_coex_prot_env_cmd env_cmd;
+ int ret;
+
+ env_cmd.action = action;
+ env_cmd.type = type;
+ ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC,
+ sizeof(env_cmd), &env_cmd);
+ if (ret)
+ IWL_ERR(mvm, "failed to send BT env command\n");
+ return ret;
+}
+
+enum iwl_bt_kill_msk {
+ BT_KILL_MSK_DEFAULT,
+ BT_KILL_MSK_SCO_HID_A2DP,
+ BT_KILL_MSK_REDUCED_TXPOW,
+ BT_KILL_MSK_MAX,
+};
+
+static const u32 iwl_bt_ack_kill_msk[BT_KILL_MSK_MAX] = {
+ [BT_KILL_MSK_DEFAULT] = 0xffff0000,
+ [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
+ [BT_KILL_MSK_REDUCED_TXPOW] = 0,
+};
+
+static const u32 iwl_bt_cts_kill_msk[BT_KILL_MSK_MAX] = {
+ [BT_KILL_MSK_DEFAULT] = 0xffff0000,
+ [BT_KILL_MSK_SCO_HID_A2DP] = 0xffffffff,
+ [BT_KILL_MSK_REDUCED_TXPOW] = 0,
+};
+
+#define IWL_BT_DEFAULT_BOOST (0xf0f0f0f0)
+
+/* Tight Coex */
+static const __le32 iwl_tight_lookup[BT_COEX_LUT_SIZE] = {
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaeaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xcc00ff28),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0xcc00aaaa),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0xc0004000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0xf0005000),
+ cpu_to_le32(0xf0005000),
+};
+
+/* Loose Coex */
+static const __le32 iwl_loose_lookup[BT_COEX_LUT_SIZE] = {
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaeaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xcc00ff28),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0xcc00aaaa),
+ cpu_to_le32(0x0000aaaa),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0xf0005000),
+ cpu_to_le32(0xf0005000),
+};
+
+/* Full concurrency */
+static const __le32 iwl_concurrent_lookup[BT_COEX_LUT_SIZE] = {
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0xaaaaaaaa),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000),
+};
+
+int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
+{
+ struct iwl_bt_coex_cmd cmd = {
+ .max_kill = 5,
+ .bt3_time_t7_value = 1,
+ .bt3_prio_sample_time = 2,
+ .bt3_timer_t2_value = 0xc,
+ };
+ int ret;
+
+ cmd.flags = iwlwifi_mod_params.bt_coex_active ?
+ BT_COEX_NW : BT_COEX_DISABLE;
+ cmd.flags |= BT_CH_PRIMARY_EN | BT_SYNC_2_BT_DISABLE;
+
+ cmd.valid_bit_msk = cpu_to_le16(BT_VALID_ENABLE |
+ BT_VALID_BT_PRIO_BOOST |
+ BT_VALID_MAX_KILL |
+ BT_VALID_3W_TMRS |
+ BT_VALID_KILL_ACK |
+ BT_VALID_KILL_CTS |
+ BT_VALID_REDUCED_TX_POWER |
+ BT_VALID_LUT);
+
+ if (is_loose_coex())
+ memcpy(&cmd.decision_lut, iwl_loose_lookup,
+ sizeof(iwl_tight_lookup));
+ else
+ memcpy(&cmd.decision_lut, iwl_tight_lookup,
+ sizeof(iwl_tight_lookup));
+
+ cmd.bt_prio_boost = cpu_to_le32(IWL_BT_DEFAULT_BOOST);
+ cmd.kill_ack_msk =
+ cpu_to_le32(iwl_bt_ack_kill_msk[BT_KILL_MSK_DEFAULT]);
+ cmd.kill_cts_msk =
+ cpu_to_le32(iwl_bt_cts_kill_msk[BT_KILL_MSK_DEFAULT]);
+
+ memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
+
+ /* go to CALIB state in internal BT-Coex state machine */
+ ret = iwl_send_bt_env(mvm, BT_COEX_ENV_OPEN,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ if (ret)
+ return ret;
+
+ ret = iwl_send_bt_env(mvm, BT_COEX_ENV_CLOSE,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ if (ret)
+ return ret;
+
+ return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
+
+static int iwl_mvm_bt_udpate_ctrl_kill_msk(struct iwl_mvm *mvm,
+ bool reduced_tx_power)
+{
+ enum iwl_bt_kill_msk bt_kill_msk;
+ struct iwl_bt_coex_cmd cmd = {};
+ struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (reduced_tx_power) {
+ /* Reduced Tx power has precedence on the type of the profile */
+ bt_kill_msk = BT_KILL_MSK_REDUCED_TXPOW;
+ } else {
+ /* Low latency BT profile is active: give higher prio to BT */
+ if (BT_MBOX_MSG(notif, 3, SCO_STATE) ||
+ BT_MBOX_MSG(notif, 3, A2DP_STATE) ||
+ BT_MBOX_MSG(notif, 3, SNIFF_STATE))
+ bt_kill_msk = BT_KILL_MSK_SCO_HID_A2DP;
+ else
+ bt_kill_msk = BT_KILL_MSK_DEFAULT;
+ }
+
+ IWL_DEBUG_COEX(mvm,
+ "Update kill_msk: %d - SCO %sactive A2DP %sactive SNIFF %sactive\n",
+ bt_kill_msk,
+ BT_MBOX_MSG(notif, 3, SCO_STATE) ? "" : "in",
+ BT_MBOX_MSG(notif, 3, A2DP_STATE) ? "" : "in",
+ BT_MBOX_MSG(notif, 3, SNIFF_STATE) ? "" : "in");
+
+ /* Don't send HCMD if there is no update */
+ if (bt_kill_msk == mvm->bt_kill_msk)
+ return 0;
+
+ mvm->bt_kill_msk = bt_kill_msk;
+ cmd.kill_ack_msk = cpu_to_le32(iwl_bt_ack_kill_msk[bt_kill_msk]);
+ cmd.kill_cts_msk = cpu_to_le32(iwl_bt_cts_kill_msk[bt_kill_msk]);
+ cmd.valid_bit_msk = cpu_to_le16(BT_VALID_KILL_ACK | BT_VALID_KILL_CTS);
+
+ IWL_DEBUG_COEX(mvm, "bt_kill_msk = %d\n", bt_kill_msk);
+ return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_SYNC,
+ sizeof(cmd), &cmd);
+}
+
+static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id,
+ bool enable)
+{
+ struct iwl_bt_coex_cmd cmd = {
+ .valid_bit_msk = cpu_to_le16(BT_VALID_REDUCED_TX_POWER),
+ .bt_reduced_tx_power = sta_id,
+ };
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+
+ /* This can happen if the station has been removed right now */
+ if (sta_id == IWL_MVM_STATION_COUNT)
+ return 0;
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ mvmsta = (void *)sta->drv_priv;
+
+ /* nothing to do */
+ if (mvmsta->bt_reduced_txpower == enable)
+ return 0;
+
+ if (enable)
+ cmd.bt_reduced_tx_power |= BT_REDUCED_TX_POWER_BIT;
+
+ IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n",
+ enable ? "en" : "dis", sta_id);
+
+ mvmsta->bt_reduced_txpower = enable;
+
+ /* Send ASYNC since this can be sent from an atomic context */
+ return iwl_mvm_send_cmd_pdu(mvm, BT_CONFIG, CMD_ASYNC,
+ sizeof(cmd), &cmd);
+}
+
+struct iwl_bt_iterator_data {
+ struct iwl_bt_coex_profile_notif *notif;
+ struct iwl_mvm *mvm;
+ u32 num_bss_ifaces;
+ bool reduced_tx_power;
+};
+
+static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_bt_iterator_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ enum ieee80211_smps_mode smps_mode;
+ enum ieee80211_band band;
+ int ave_rssi;
+
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return;
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ if (chanctx_conf && chanctx_conf->def.chan)
+ band = chanctx_conf->def.chan->band;
+ else
+ band = -1;
+ rcu_read_unlock();
+
+ smps_mode = IEEE80211_SMPS_AUTOMATIC;
+
+ if (band != IEEE80211_BAND_2GHZ) {
+ ieee80211_request_smps(vif, smps_mode);
+ return;
+ }
+
+ if (data->notif->bt_status)
+ smps_mode = IEEE80211_SMPS_DYNAMIC;
+
+ if (data->notif->bt_traffic_load >= IWL_BT_LOAD_FORCE_SISO_THRESHOLD)
+ smps_mode = IEEE80211_SMPS_STATIC;
+
+ IWL_DEBUG_COEX(data->mvm,
+ "mac %d: bt_status %d traffic_load %d smps_req %d\n",
+ mvmvif->id, data->notif->bt_status,
+ data->notif->bt_traffic_load, smps_mode);
+
+ ieee80211_request_smps(vif, smps_mode);
+
+ /* don't reduce the Tx power if in loose scheme */
+ if (is_loose_coex())
+ return;
+
+ data->num_bss_ifaces++;
+
+ /* reduced Txpower only if there are open BT connections, so ...*/
+ if (!BT_MBOX_MSG(data->notif, 3, OPEN_CON_2)) {
+ /* ... cancel reduced Tx power ... */
+ if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
+ IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
+ data->reduced_tx_power = false;
+
+ /* ... and there is no need to get reports on RSSI any more. */
+ ieee80211_disable_rssi_reports(vif);
+ return;
+ }
+
+ ave_rssi = ieee80211_ave_rssi(vif);
+
+ /* if the RSSI isn't valid, fake it is very low */
+ if (!ave_rssi)
+ ave_rssi = -100;
+ if (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) {
+ if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true))
+ IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
+
+ /*
+ * bt_kill_msk can be BT_KILL_MSK_REDUCED_TXPOW only if all the
+ * BSS / P2P clients have rssi above threshold.
+ * We set the bt_kill_msk to BT_KILL_MSK_REDUCED_TXPOW before
+ * the iteration, if one interface's rssi isn't good enough,
+ * bt_kill_msk will be set to default values.
+ */
+ } else if (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) {
+ if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, false))
+ IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
+
+ /*
+ * One interface hasn't rssi above threshold, bt_kill_msk must
+ * be set to default values.
+ */
+ data->reduced_tx_power = false;
+ }
+
+ /* Begin to monitor the RSSI: it may influence the reduced Tx power */
+ ieee80211_enable_rssi_reports(vif, BT_DISABLE_REDUCED_TXPOWER_THRESHOLD,
+ BT_ENABLE_REDUCED_TXPOWER_THRESHOLD);
+}
+
+static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
+{
+ struct iwl_bt_iterator_data data = {
+ .mvm = mvm,
+ .notif = &mvm->last_bt_notif,
+ .reduced_tx_power = true,
+ };
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_bt_notif_iterator, &data);
+
+ /*
+ * If there are no BSS / P2P client interfaces, reduced Tx Power is
+ * irrelevant since it is based on the RSSI coming from the beacon.
+ * Use BT_KILL_MSK_DEFAULT in that case.
+ */
+ data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
+
+ if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
+ IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
+}
+
+/* upon association, the fw will send in BT Coex notification */
+int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *dev_cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data;
+
+
+ IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n");
+ IWL_DEBUG_COEX(mvm, "\tBT %salive\n", notif->bt_status ? "" : "not ");
+ IWL_DEBUG_COEX(mvm, "\tBT open conn %d\n", notif->bt_open_conn);
+ IWL_DEBUG_COEX(mvm, "\tBT traffic load %d\n", notif->bt_traffic_load);
+ IWL_DEBUG_COEX(mvm, "\tBT agg traffic load %d\n",
+ notif->bt_agg_traffic_load);
+ IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance);
+
+ /* remember this notification for future use: rssi fluctuations */
+ memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif));
+
+ iwl_mvm_bt_coex_notif_handle(mvm);
+
+ /*
+ * This is an async handler for a notification, returning anything other
+ * than 0 doesn't make sense even if HCMD failed.
+ */
+ return 0;
+}
+
+static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_bt_iterator_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvmsta;
+
+ if (vif->type != NL80211_IFTYPE_STATION ||
+ mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
+ return;
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+ lockdep_is_held(&mvm->mutex));
+ mvmsta = (void *)sta->drv_priv;
+
+ /*
+ * This interface doesn't support reduced Tx power (because of low
+ * RSSI probably), then set bt_kill_msk to default values.
+ */
+ if (!mvmsta->bt_reduced_txpower)
+ data->reduced_tx_power = false;
+ /* else - possibly leave it to BT_KILL_MSK_REDUCED_TXPOW */
+}
+
+void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum ieee80211_rssi_event rssi_event)
+{
+ struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_bt_iterator_data data = {
+ .mvm = mvm,
+ .reduced_tx_power = true,
+ };
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+
+ /* Rssi update while not associated ?! */
+ if (WARN_ON_ONCE(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT))
+ goto out_unlock;
+
+ /* No open connection - reports should be disabled */
+ if (!BT_MBOX_MSG(&mvm->last_bt_notif, 3, OPEN_CON_2))
+ goto out_unlock;
+
+ IWL_DEBUG_COEX(mvm, "RSSI for %pM is now %s\n", vif->bss_conf.bssid,
+ rssi_event == RSSI_EVENT_HIGH ? "HIGH" : "LOW");
+
+ /*
+ * Check if rssi is good enough for reduced Tx power, but not in loose
+ * scheme.
+ */
+ if (rssi_event == RSSI_EVENT_LOW || is_loose_coex())
+ ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id,
+ false);
+ else
+ ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->ap_sta_id, true);
+
+ if (ret)
+ IWL_ERR(mvm, "couldn't send BT_CONFIG HCMD upon RSSI event\n");
+
+ ieee80211_iterate_active_interfaces_atomic(
+ mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+ iwl_mvm_bt_rssi_iterator, &data);
+
+ /*
+ * If there are no BSS / P2P client interfaces, reduced Tx Power is
+ * irrelevant since it is based on the RSSI coming from the beacon.
+ * Use BT_KILL_MSK_DEFAULT in that case.
+ */
+ data.reduced_tx_power = data.reduced_tx_power && data.num_bss_ifaces;
+
+ if (iwl_mvm_bt_udpate_ctrl_kill_msk(mvm, data.reduced_tx_power))
+ IWL_ERR(mvm, "Failed to update the ctrl_kill_msk\n");
+
+ out_unlock:
+ mutex_unlock(&mvm->mutex);
+}
+
+void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ enum ieee80211_band band;
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ if (chanctx_conf && chanctx_conf->def.chan)
+ band = chanctx_conf->def.chan->band;
+ else
+ band = -1;
+ rcu_read_unlock();
+
+ /* if we are in 2GHz we will get a notification from the fw */
+ if (band == IEEE80211_BAND_2GHZ)
+ return;
+
+ /* else, we can remove all the constraints */
+ memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
+
+ iwl_mvm_bt_coex_notif_handle(mvm);
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 994c8c263dc0..16bbdcc8627a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -62,8 +62,10 @@
*****************************************************************************/
#include <linux/etherdevice.h>
+#include <linux/ip.h>
#include <net/cfg80211.h>
#include <net/ipv6.h>
+#include <net/tcp.h>
#include "iwl-modparams.h"
#include "fw-api.h"
#include "mvm.h"
@@ -402,6 +404,233 @@ static int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm,
sizeof(cmd), &cmd);
}
+enum iwl_mvm_tcp_packet_type {
+ MVM_TCP_TX_SYN,
+ MVM_TCP_RX_SYNACK,
+ MVM_TCP_TX_DATA,
+ MVM_TCP_RX_ACK,
+ MVM_TCP_RX_WAKE,
+ MVM_TCP_TX_FIN,
+};
+
+static __le16 pseudo_hdr_check(int len, __be32 saddr, __be32 daddr)
+{
+ __sum16 check = tcp_v4_check(len, saddr, daddr, 0);
+ return cpu_to_le16(be16_to_cpu((__force __be16)check));
+}
+
+static void iwl_mvm_build_tcp_packet(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_wowlan_tcp *tcp,
+ void *_pkt, u8 *mask,
+ __le16 *pseudo_hdr_csum,
+ enum iwl_mvm_tcp_packet_type ptype)
+{
+ struct {
+ struct ethhdr eth;
+ struct iphdr ip;
+ struct tcphdr tcp;
+ u8 data[];
+ } __packed *pkt = _pkt;
+ u16 ip_tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
+ int i;
+
+ pkt->eth.h_proto = cpu_to_be16(ETH_P_IP),
+ pkt->ip.version = 4;
+ pkt->ip.ihl = 5;
+ pkt->ip.protocol = IPPROTO_TCP;
+
+ switch (ptype) {
+ case MVM_TCP_TX_SYN:
+ case MVM_TCP_TX_DATA:
+ case MVM_TCP_TX_FIN:
+ memcpy(pkt->eth.h_dest, tcp->dst_mac, ETH_ALEN);
+ memcpy(pkt->eth.h_source, vif->addr, ETH_ALEN);
+ pkt->ip.ttl = 128;
+ pkt->ip.saddr = tcp->src;
+ pkt->ip.daddr = tcp->dst;
+ pkt->tcp.source = cpu_to_be16(tcp->src_port);
+ pkt->tcp.dest = cpu_to_be16(tcp->dst_port);
+ /* overwritten for TX SYN later */
+ pkt->tcp.doff = sizeof(struct tcphdr) / 4;
+ pkt->tcp.window = cpu_to_be16(65000);
+ break;
+ case MVM_TCP_RX_SYNACK:
+ case MVM_TCP_RX_ACK:
+ case MVM_TCP_RX_WAKE:
+ memcpy(pkt->eth.h_dest, vif->addr, ETH_ALEN);
+ memcpy(pkt->eth.h_source, tcp->dst_mac, ETH_ALEN);
+ pkt->ip.saddr = tcp->dst;
+ pkt->ip.daddr = tcp->src;
+ pkt->tcp.source = cpu_to_be16(tcp->dst_port);
+ pkt->tcp.dest = cpu_to_be16(tcp->src_port);
+ break;
+ default:
+ WARN_ON(1);
+ return;
+ }
+
+ switch (ptype) {
+ case MVM_TCP_TX_SYN:
+ /* firmware assumes 8 option bytes - 8 NOPs for now */
+ memset(pkt->data, 0x01, 8);
+ ip_tot_len += 8;
+ pkt->tcp.doff = (sizeof(struct tcphdr) + 8) / 4;
+ pkt->tcp.syn = 1;
+ break;
+ case MVM_TCP_TX_DATA:
+ ip_tot_len += tcp->payload_len;
+ memcpy(pkt->data, tcp->payload, tcp->payload_len);
+ pkt->tcp.psh = 1;
+ pkt->tcp.ack = 1;
+ break;
+ case MVM_TCP_TX_FIN:
+ pkt->tcp.fin = 1;
+ pkt->tcp.ack = 1;
+ break;
+ case MVM_TCP_RX_SYNACK:
+ pkt->tcp.syn = 1;
+ pkt->tcp.ack = 1;
+ break;
+ case MVM_TCP_RX_ACK:
+ pkt->tcp.ack = 1;
+ break;
+ case MVM_TCP_RX_WAKE:
+ ip_tot_len += tcp->wake_len;
+ pkt->tcp.psh = 1;
+ pkt->tcp.ack = 1;
+ memcpy(pkt->data, tcp->wake_data, tcp->wake_len);
+ break;
+ }
+
+ switch (ptype) {
+ case MVM_TCP_TX_SYN:
+ case MVM_TCP_TX_DATA:
+ case MVM_TCP_TX_FIN:
+ pkt->ip.tot_len = cpu_to_be16(ip_tot_len);
+ pkt->ip.check = ip_fast_csum(&pkt->ip, pkt->ip.ihl);
+ break;
+ case MVM_TCP_RX_WAKE:
+ for (i = 0; i < DIV_ROUND_UP(tcp->wake_len, 8); i++) {
+ u8 tmp = tcp->wake_mask[i];
+ mask[i + 6] |= tmp << 6;
+ if (i + 1 < DIV_ROUND_UP(tcp->wake_len, 8))
+ mask[i + 7] = tmp >> 2;
+ }
+ /* fall through for ethernet/IP/TCP headers mask */
+ case MVM_TCP_RX_SYNACK:
+ case MVM_TCP_RX_ACK:
+ mask[0] = 0xff; /* match ethernet */
+ /*
+ * match ethernet, ip.version, ip.ihl
+ * the ip.ihl half byte is really masked out by firmware
+ */
+ mask[1] = 0x7f;
+ mask[2] = 0x80; /* match ip.protocol */
+ mask[3] = 0xfc; /* match ip.saddr, ip.daddr */
+ mask[4] = 0x3f; /* match ip.daddr, tcp.source, tcp.dest */
+ mask[5] = 0x80; /* match tcp flags */
+ /* leave rest (0 or set for MVM_TCP_RX_WAKE) */
+ break;
+ };
+
+ *pseudo_hdr_csum = pseudo_hdr_check(ip_tot_len - sizeof(struct iphdr),
+ pkt->ip.saddr, pkt->ip.daddr);
+}
+
+static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct cfg80211_wowlan_tcp *tcp)
+{
+ struct iwl_wowlan_remote_wake_config *cfg;
+ struct iwl_host_cmd cmd = {
+ .id = REMOTE_WAKE_CONFIG_CMD,
+ .len = { sizeof(*cfg), },
+ .dataflags = { IWL_HCMD_DFL_NOCOPY, },
+ .flags = CMD_SYNC,
+ };
+ int ret;
+
+ if (!tcp)
+ return 0;
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+ cmd.data[0] = cfg;
+
+ cfg->max_syn_retries = 10;
+ cfg->max_data_retries = 10;
+ cfg->tcp_syn_ack_timeout = 1; /* seconds */
+ cfg->tcp_ack_timeout = 1; /* seconds */
+
+ /* SYN (TX) */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->syn_tx.data, NULL,
+ &cfg->syn_tx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_TX_SYN);
+ cfg->syn_tx.info.tcp_payload_length = 0;
+
+ /* SYN/ACK (RX) */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->synack_rx.data, cfg->synack_rx.rx_mask,
+ &cfg->synack_rx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_RX_SYNACK);
+ cfg->synack_rx.info.tcp_payload_length = 0;
+
+ /* KEEPALIVE/ACK (TX) */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->keepalive_tx.data, NULL,
+ &cfg->keepalive_tx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_TX_DATA);
+ cfg->keepalive_tx.info.tcp_payload_length =
+ cpu_to_le16(tcp->payload_len);
+ cfg->sequence_number_offset = tcp->payload_seq.offset;
+ /* length must be 0..4, the field is little endian */
+ cfg->sequence_number_length = tcp->payload_seq.len;
+ cfg->initial_sequence_number = cpu_to_le32(tcp->payload_seq.start);
+ cfg->keepalive_interval = cpu_to_le16(tcp->data_interval);
+ if (tcp->payload_tok.len) {
+ cfg->token_offset = tcp->payload_tok.offset;
+ cfg->token_length = tcp->payload_tok.len;
+ cfg->num_tokens =
+ cpu_to_le16(tcp->tokens_size % tcp->payload_tok.len);
+ memcpy(cfg->tokens, tcp->payload_tok.token_stream,
+ tcp->tokens_size);
+ } else {
+ /* set tokens to max value to almost never run out */
+ cfg->num_tokens = cpu_to_le16(65535);
+ }
+
+ /* ACK (RX) */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->keepalive_ack_rx.data,
+ cfg->keepalive_ack_rx.rx_mask,
+ &cfg->keepalive_ack_rx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_RX_ACK);
+ cfg->keepalive_ack_rx.info.tcp_payload_length = 0;
+
+ /* WAKEUP (RX) */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->wake_rx.data, cfg->wake_rx.rx_mask,
+ &cfg->wake_rx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_RX_WAKE);
+ cfg->wake_rx.info.tcp_payload_length =
+ cpu_to_le16(tcp->wake_len);
+
+ /* FIN */
+ iwl_mvm_build_tcp_packet(
+ mvm, vif, tcp, cfg->fin_tx.data, NULL,
+ &cfg->fin_tx.info.tcp_pseudo_header_checksum,
+ MVM_TCP_TX_FIN);
+ cfg->fin_tx.info.tcp_payload_length = 0;
+
+ ret = iwl_mvm_send_cmd(mvm, &cmd);
+ kfree(cfg);
+
+ return ret;
+}
+
struct iwl_d3_iter_data {
struct iwl_mvm *mvm;
struct ieee80211_vif *vif;
@@ -540,7 +769,14 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
- struct iwl_d3_manager_config d3_cfg_cmd = {};
+ struct iwl_d3_manager_config d3_cfg_cmd = {
+ /*
+ * Program the minimum sleep time to 10 seconds, as many
+ * platforms have issues processing a wakeup signal while
+ * still being in the process of suspending.
+ */
+ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
+ };
struct wowlan_key_data key_data = {
.use_rsc_tsc = false,
.tkip = &tkip_cmd,
@@ -637,9 +873,21 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
if (wowlan->rfkill_release)
- d3_cfg_cmd.wakeup_flags |=
+ wowlan_config_cmd.wakeup_filter |=
cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
+ if (wowlan->tcp) {
+ /*
+ * Set the "link change" (really "link lost") flag as well
+ * since that implies losing the TCP connection.
+ */
+ wowlan_config_cmd.wakeup_filter |=
+ cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
+ IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
+ IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
+ IWL_WOWLAN_WAKEUP_LINK_CHANGE);
+ }
+
iwl_mvm_cancel_scan(mvm);
iwl_trans_stop_device(mvm->trans);
@@ -755,6 +1003,10 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
if (ret)
goto out;
+ ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
+ if (ret)
+ goto out;
+
/* must be last -- this switches firmware state */
ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SYNC,
sizeof(d3_cfg_cmd), &d3_cfg_cmd);
@@ -874,6 +1126,15 @@ static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE)
wakeup.four_way_handshake = true;
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS)
+ wakeup.tcp_connlost = true;
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE)
+ wakeup.tcp_nomoretokens = true;
+
+ if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET)
+ wakeup.tcp_match = true;
+
if (status->wake_packet_bufsize) {
int pktsize = le32_to_cpu(status->wake_packet_bufsize);
int pktlen = le32_to_cpu(status->wake_packet_length);
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index c1bdb5582126..2053dccefcd6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -69,12 +69,6 @@ struct iwl_dbgfs_mvm_ctx {
struct ieee80211_vif *vif;
};
-static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
static ssize_t iwl_dbgfs_tx_flush_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
@@ -306,10 +300,191 @@ static ssize_t iwl_dbgfs_power_down_d3_allow_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->dbgfs_data;
+ u8 ap_sta_id;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ char buf[512];
+ int bufsz = sizeof(buf);
+ int pos = 0;
+ int i;
+
+ mutex_lock(&mvm->mutex);
+
+ ap_sta_id = mvmvif->ap_sta_id;
+
+ pos += scnprintf(buf+pos, bufsz-pos, "mac id/color: %d / %d\n",
+ mvmvif->id, mvmvif->color);
+ pos += scnprintf(buf+pos, bufsz-pos, "bssid: %pM\n",
+ vif->bss_conf.bssid);
+ pos += scnprintf(buf+pos, bufsz-pos, "QoS:\n");
+ for (i = 0; i < ARRAY_SIZE(mvmvif->queue_params); i++) {
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "\t%d: txop:%d - cw_min:%d - cw_max = %d - aifs = %d upasd = %d\n",
+ i, mvmvif->queue_params[i].txop,
+ mvmvif->queue_params[i].cw_min,
+ mvmvif->queue_params[i].cw_max,
+ mvmvif->queue_params[i].aifs,
+ mvmvif->queue_params[i].uapsd);
+ }
+
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ ap_sta_id != IWL_MVM_STATION_COUNT) {
+ struct ieee80211_sta *sta;
+ struct iwl_mvm_sta *mvm_sta;
+
+ sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
+ lockdep_is_held(&mvm->mutex));
+ mvm_sta = (void *)sta->drv_priv;
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "ap_sta_id %d - reduced Tx power %d\n",
+ ap_sta_id, mvm_sta->bt_reduced_txpower);
+ }
+
+ rcu_read_lock();
+ chanctx_conf = rcu_dereference(vif->chanctx_conf);
+ if (chanctx_conf) {
+ pos += scnprintf(buf+pos, bufsz-pos,
+ "idle rx chains %d, active rx chains: %d\n",
+ chanctx_conf->rx_chains_static,
+ chanctx_conf->rx_chains_dynamic);
+ }
+ rcu_read_unlock();
+
+ mutex_unlock(&mvm->mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+#define BT_MBOX_MSG(_notif, _num, _field) \
+ ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
+ >> BT_MBOX##_num##_##_field##_POS)
+
+
+#define BT_MBOX_PRINT(_num, _field, _end) \
+ pos += scnprintf(buf + pos, bufsz - pos, \
+ "\t%s: %d%s", \
+ #_field, \
+ BT_MBOX_MSG(notif, _num, _field), \
+ true ? "\n" : ", ");
+
+static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif;
+ char *buf;
+ int ret, pos = 0, bufsz = sizeof(char) * 1024;
+
+ buf = kmalloc(bufsz, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ mutex_lock(&mvm->mutex);
+
+ pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n");
+
+ BT_MBOX_PRINT(0, LE_SLAVE_LAT, false);
+ BT_MBOX_PRINT(0, LE_PROF1, false);
+ BT_MBOX_PRINT(0, LE_PROF2, false);
+ BT_MBOX_PRINT(0, LE_PROF_OTHER, false);
+ BT_MBOX_PRINT(0, CHL_SEQ_N, false);
+ BT_MBOX_PRINT(0, INBAND_S, false);
+ BT_MBOX_PRINT(0, LE_MIN_RSSI, false);
+ BT_MBOX_PRINT(0, LE_SCAN, false);
+ BT_MBOX_PRINT(0, LE_ADV, false);
+ BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false);
+ BT_MBOX_PRINT(0, OPEN_CON_1, true);
+
+ pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n");
+
+ BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false);
+ BT_MBOX_PRINT(1, IP_SR, false);
+ BT_MBOX_PRINT(1, LE_MSTR, false);
+ BT_MBOX_PRINT(1, AGGR_TRFC_LD, false);
+ BT_MBOX_PRINT(1, MSG_TYPE, false);
+ BT_MBOX_PRINT(1, SSN, true);
+
+ pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n");
+
+ BT_MBOX_PRINT(2, SNIFF_ACT, false);
+ BT_MBOX_PRINT(2, PAG, false);
+ BT_MBOX_PRINT(2, INQUIRY, false);
+ BT_MBOX_PRINT(2, CONN, false);
+ BT_MBOX_PRINT(2, SNIFF_INTERVAL, false);
+ BT_MBOX_PRINT(2, DISC, false);
+ BT_MBOX_PRINT(2, SCO_TX_ACT, false);
+ BT_MBOX_PRINT(2, SCO_RX_ACT, false);
+ BT_MBOX_PRINT(2, ESCO_RE_TX, false);
+ BT_MBOX_PRINT(2, SCO_DURATION, true);
+
+ pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n");
+
+ BT_MBOX_PRINT(3, SCO_STATE, false);
+ BT_MBOX_PRINT(3, SNIFF_STATE, false);
+ BT_MBOX_PRINT(3, A2DP_STATE, false);
+ BT_MBOX_PRINT(3, ACL_STATE, false);
+ BT_MBOX_PRINT(3, MSTR_STATE, false);
+ BT_MBOX_PRINT(3, OBX_STATE, false);
+ BT_MBOX_PRINT(3, OPEN_CON_2, false);
+ BT_MBOX_PRINT(3, TRAFFIC_LOAD, false);
+ BT_MBOX_PRINT(3, CHL_SEQN_LSB, false);
+ BT_MBOX_PRINT(3, INBAND_P, false);
+ BT_MBOX_PRINT(3, MSG_TYPE_2, false);
+ BT_MBOX_PRINT(3, SSN_2, false);
+ BT_MBOX_PRINT(3, UPDATE_REQUEST, true);
+
+ pos += scnprintf(buf+pos, bufsz-pos, "bt_status = %d\n",
+ notif->bt_status);
+ pos += scnprintf(buf+pos, bufsz-pos, "bt_open_conn = %d\n",
+ notif->bt_open_conn);
+ pos += scnprintf(buf+pos, bufsz-pos, "bt_traffic_load = %d\n",
+ notif->bt_traffic_load);
+ pos += scnprintf(buf+pos, bufsz-pos, "bt_agg_traffic_load = %d\n",
+ notif->bt_agg_traffic_load);
+ pos += scnprintf(buf+pos, bufsz-pos, "bt_ci_compliance = %d\n",
+ notif->bt_ci_compliance);
+
+ mutex_unlock(&mvm->mutex);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+
+ return ret;
+}
+#undef BT_MBOX_PRINT
+
+static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ bool restart_fw = iwlwifi_mod_params.restart_fw;
+ int ret;
+
+ iwlwifi_mod_params.restart_fw = true;
+
+ mutex_lock(&mvm->mutex);
+
+ /* take the return value to make compiler happy - it will fail anyway */
+ ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, CMD_SYNC, 0, NULL);
+
+ mutex_unlock(&mvm->mutex);
+
+ iwlwifi_mod_params.restart_fw = restart_fw;
+
+ return count;
+}
+
#define MVM_DEBUGFS_READ_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.read = iwl_dbgfs_##name##_read, \
- .open = iwl_dbgfs_open_file_generic, \
+ .open = simple_open, \
.llseek = generic_file_llseek, \
}
@@ -317,14 +492,14 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
.read = iwl_dbgfs_##name##_read, \
- .open = iwl_dbgfs_open_file_generic, \
+ .open = simple_open, \
.llseek = generic_file_llseek, \
};
#define MVM_DEBUGFS_WRITE_FILE_OPS(name) \
static const struct file_operations iwl_dbgfs_##name##_ops = { \
.write = iwl_dbgfs_##name##_write, \
- .open = iwl_dbgfs_open_file_generic, \
+ .open = simple_open, \
.llseek = generic_file_llseek, \
};
@@ -345,8 +520,13 @@ MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush);
MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram);
MVM_DEBUGFS_READ_FILE_OPS(stations);
+MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_allow);
MVM_DEBUGFS_WRITE_FILE_OPS(power_down_d3_allow);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart);
+
+/* Interface specific debugfs entries */
+MVM_DEBUGFS_READ_FILE_OPS(mac_params);
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
{
@@ -358,8 +538,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
+ MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE(power_down_allow, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(power_down_d3_allow, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR);
/*
* Create a symlink with mac80211. It will be removed when mac80211
@@ -376,3 +558,58 @@ err:
IWL_ERR(mvm, "Can't create the mvm debugfs directory\n");
return -ENOMEM;
}
+
+void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct dentry *dbgfs_dir = vif->debugfs_dir;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[100];
+
+ if (!dbgfs_dir)
+ return;
+
+ mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
+ mvmvif->dbgfs_data = mvm;
+
+ if (!mvmvif->dbgfs_dir) {
+ IWL_ERR(mvm, "Failed to create debugfs directory under %s\n",
+ dbgfs_dir->d_name.name);
+ return;
+ }
+
+ MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir,
+ S_IRUSR);
+
+ /*
+ * Create symlink for convenience pointing to interface specific
+ * debugfs entries for the driver. For example, under
+ * /sys/kernel/debug/iwlwifi/0000\:02\:00.0/iwlmvm/
+ * find
+ * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/
+ */
+ snprintf(buf, 100, "../../../%s/%s/%s/%s",
+ dbgfs_dir->d_parent->d_parent->d_name.name,
+ dbgfs_dir->d_parent->d_name.name,
+ dbgfs_dir->d_name.name,
+ mvmvif->dbgfs_dir->d_name.name);
+
+ mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name,
+ mvm->debugfs_dir, buf);
+ if (!mvmvif->dbgfs_slink)
+ IWL_ERR(mvm, "Can't create debugfs symbolic link under %s\n",
+ dbgfs_dir->d_name.name);
+ return;
+err:
+ IWL_ERR(mvm, "Can't create debugfs entity\n");
+}
+
+void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ debugfs_remove(mvmvif->dbgfs_slink);
+ mvmvif->dbgfs_slink = NULL;
+
+ debugfs_remove_recursive(mvmvif->dbgfs_dir);
+ mvmvif->dbgfs_dir = NULL;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
new file mode 100644
index 000000000000..05c61d6f384e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
@@ -0,0 +1,319 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * 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 version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __fw_api_bt_coex_h__
+#define __fw_api_bt_coex_h__
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#define BITS(nb) (BIT(nb) - 1)
+
+/**
+ * enum iwl_bt_coex_flags - flags for BT_COEX command
+ * @BT_CH_PRIMARY_EN:
+ * @BT_CH_SECONDARY_EN:
+ * @BT_NOTIF_COEX_OFF:
+ * @BT_COEX_MODE_POS:
+ * @BT_COEX_MODE_MSK:
+ * @BT_COEX_DISABLE:
+ * @BT_COEX_2W:
+ * @BT_COEX_3W:
+ * @BT_COEX_NW:
+ * @BT_USE_DEFAULTS:
+ * @BT_SYNC_2_BT_DISABLE:
+ * @BT_COEX_CORUNNING_TBL_EN:
+ */
+enum iwl_bt_coex_flags {
+ BT_CH_PRIMARY_EN = BIT(0),
+ BT_CH_SECONDARY_EN = BIT(1),
+ BT_NOTIF_COEX_OFF = BIT(2),
+ BT_COEX_MODE_POS = 3,
+ BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS,
+ BT_COEX_DISABLE = 0x0 << BT_COEX_MODE_POS,
+ BT_COEX_2W = 0x1 << BT_COEX_MODE_POS,
+ BT_COEX_3W = 0x2 << BT_COEX_MODE_POS,
+ BT_COEX_NW = 0x3 << BT_COEX_MODE_POS,
+ BT_USE_DEFAULTS = BIT(6),
+ BT_SYNC_2_BT_DISABLE = BIT(7),
+ /*
+ * For future use - when the flags will be enlarged
+ * BT_COEX_CORUNNING_TBL_EN = BIT(8),
+ */
+};
+
+/*
+ * indicates what has changed in the BT_COEX command.
+ */
+enum iwl_bt_coex_valid_bit_msk {
+ BT_VALID_ENABLE = BIT(0),
+ BT_VALID_BT_PRIO_BOOST = BIT(1),
+ BT_VALID_MAX_KILL = BIT(2),
+ BT_VALID_3W_TMRS = BIT(3),
+ BT_VALID_KILL_ACK = BIT(4),
+ BT_VALID_KILL_CTS = BIT(5),
+ BT_VALID_REDUCED_TX_POWER = BIT(6),
+ BT_VALID_LUT = BIT(7),
+ BT_VALID_WIFI_RX_SW_PRIO_BOOST = BIT(8),
+ BT_VALID_WIFI_TX_SW_PRIO_BOOST = BIT(9),
+ BT_VALID_MULTI_PRIO_LUT = BIT(10),
+ BT_VALID_TRM_KICK_FILTER = BIT(11),
+ BT_VALID_CORUN_LUT_20 = BIT(12),
+ BT_VALID_CORUN_LUT_40 = BIT(13),
+ BT_VALID_ANT_ISOLATION = BIT(14),
+ BT_VALID_ANT_ISOLATION_THRS = BIT(15),
+ /*
+ * For future use - when the valid flags will be enlarged
+ * BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
+ * BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
+ */
+};
+
+/**
+ * enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames.
+ * @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames
+ * @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames
+ *
+ * This mechanism allows to have BT and WiFi run concurrently. Since WiFi
+ * reduces its Tx power, it can work along with BT, hence reducing the amount
+ * of WiFi frames being killed by BT.
+ */
+enum iwl_bt_reduced_tx_power {
+ BT_REDUCED_TX_POWER_CTL = BIT(0),
+ BT_REDUCED_TX_POWER_DATA = BIT(1),
+};
+
+#define BT_COEX_LUT_SIZE (12)
+
+/**
+ * struct iwl_bt_coex_cmd - bt coex configuration command
+ * @flags:&enum iwl_bt_coex_flags
+ * @lead_time:
+ * @max_kill:
+ * @bt3_time_t7_value:
+ * @kill_ack_msk:
+ * @kill_cts_msk:
+ * @bt3_prio_sample_time:
+ * @bt3_timer_t2_value:
+ * @bt4_reaction_time:
+ * @decision_lut[12]:
+ * @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
+ * @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
+ * @bt_prio_boost: values for PTA boost register
+ * @wifi_tx_prio_boost: SW boost of wifi tx priority
+ * @wifi_rx_prio_boost: SW boost of wifi rx priority
+ *
+ * The structure is used for the BT_COEX command.
+ */
+struct iwl_bt_coex_cmd {
+ u8 flags;
+ u8 lead_time;
+ u8 max_kill;
+ u8 bt3_time_t7_value;
+ __le32 kill_ack_msk;
+ __le32 kill_cts_msk;
+ u8 bt3_prio_sample_time;
+ u8 bt3_timer_t2_value;
+ __le16 bt4_reaction_time;
+ __le32 decision_lut[BT_COEX_LUT_SIZE];
+ u8 bt_reduced_tx_power;
+ u8 reserved;
+ __le16 valid_bit_msk;
+ __le32 bt_prio_boost;
+ u8 reserved2;
+ u8 wifi_tx_prio_boost;
+ __le16 wifi_rx_prio_boost;
+} __packed; /* BT_COEX_CMD_API_S_VER_3 */
+
+#define BT_MBOX(n_dw, _msg, _pos, _nbits) \
+ BT_MBOX##n_dw##_##_msg##_POS = (_pos), \
+ BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS
+
+enum iwl_bt_mxbox_dw0 {
+ BT_MBOX(0, LE_SLAVE_LAT, 0, 3),
+ BT_MBOX(0, LE_PROF1, 3, 1),
+ BT_MBOX(0, LE_PROF2, 4, 1),
+ BT_MBOX(0, LE_PROF_OTHER, 5, 1),
+ BT_MBOX(0, CHL_SEQ_N, 8, 4),
+ BT_MBOX(0, INBAND_S, 13, 1),
+ BT_MBOX(0, LE_MIN_RSSI, 16, 4),
+ BT_MBOX(0, LE_SCAN, 20, 1),
+ BT_MBOX(0, LE_ADV, 21, 1),
+ BT_MBOX(0, LE_MAX_TX_POWER, 24, 4),
+ BT_MBOX(0, OPEN_CON_1, 28, 2),
+};
+
+enum iwl_bt_mxbox_dw1 {
+ BT_MBOX(1, BR_MAX_TX_POWER, 0, 4),
+ BT_MBOX(1, IP_SR, 4, 1),
+ BT_MBOX(1, LE_MSTR, 5, 1),
+ BT_MBOX(1, AGGR_TRFC_LD, 8, 6),
+ BT_MBOX(1, MSG_TYPE, 16, 3),
+ BT_MBOX(1, SSN, 19, 2),
+};
+
+enum iwl_bt_mxbox_dw2 {
+ BT_MBOX(2, SNIFF_ACT, 0, 3),
+ BT_MBOX(2, PAG, 3, 1),
+ BT_MBOX(2, INQUIRY, 4, 1),
+ BT_MBOX(2, CONN, 5, 1),
+ BT_MBOX(2, SNIFF_INTERVAL, 8, 5),
+ BT_MBOX(2, DISC, 13, 1),
+ BT_MBOX(2, SCO_TX_ACT, 16, 2),
+ BT_MBOX(2, SCO_RX_ACT, 18, 2),
+ BT_MBOX(2, ESCO_RE_TX, 20, 2),
+ BT_MBOX(2, SCO_DURATION, 24, 6),
+};
+
+enum iwl_bt_mxbox_dw3 {
+ BT_MBOX(3, SCO_STATE, 0, 1),
+ BT_MBOX(3, SNIFF_STATE, 1, 1),
+ BT_MBOX(3, A2DP_STATE, 2, 1),
+ BT_MBOX(3, ACL_STATE, 3, 1),
+ BT_MBOX(3, MSTR_STATE, 4, 1),
+ BT_MBOX(3, OBX_STATE, 5, 1),
+ BT_MBOX(3, OPEN_CON_2, 8, 2),
+ BT_MBOX(3, TRAFFIC_LOAD, 10, 2),
+ BT_MBOX(3, CHL_SEQN_LSB, 12, 1),
+ BT_MBOX(3, INBAND_P, 13, 1),
+ BT_MBOX(3, MSG_TYPE_2, 16, 3),
+ BT_MBOX(3, SSN_2, 19, 2),
+ BT_MBOX(3, UPDATE_REQUEST, 21, 1),
+};
+
+#define BT_MBOX_MSG(_notif, _num, _field) \
+ ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\
+ >> BT_MBOX##_num##_##_field##_POS)
+
+/**
+ * struct iwl_bt_coex_profile_notif - notification about BT coex
+ * @mbox_msg: message from BT to WiFi
+ * @:bt_status: 0 - off, 1 - on
+ * @:bt_open_conn: number of BT connections open
+ * @:bt_traffic_load: load of BT traffic
+ * @:bt_agg_traffic_load: aggregated load of BT traffic
+ * @:bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
+ */
+struct iwl_bt_coex_profile_notif {
+ __le32 mbox_msg[4];
+ u8 bt_status;
+ u8 bt_open_conn;
+ u8 bt_traffic_load;
+ u8 bt_agg_traffic_load;
+ u8 bt_ci_compliance;
+ u8 reserved[3];
+} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_2 */
+
+enum iwl_bt_coex_prio_table_event {
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
+ BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
+ BT_COEX_PRIO_TBL_EVT_DTIM = 6,
+ BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
+ BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
+ BT_COEX_PRIO_TBL_EVT_IDLE = 9,
+ BT_COEX_PRIO_TBL_EVT_MAX = 16,
+}; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */
+
+enum iwl_bt_coex_prio_table_prio {
+ BT_COEX_PRIO_TBL_DISABLED = 0,
+ BT_COEX_PRIO_TBL_PRIO_LOW = 1,
+ BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
+ BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
+ BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
+ BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
+ BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6,
+ BT_COEX_PRIO_TBL_MAX = 8,
+}; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */
+
+#define BT_COEX_PRIO_TBL_SHRD_ANT_POS (0)
+#define BT_COEX_PRIO_TBL_PRIO_POS (1)
+#define BT_COEX_PRIO_TBL_RESERVED_POS (4)
+
+/**
+ * struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex
+ * @prio_tbl:
+ */
+struct iwl_bt_coex_prio_tbl_cmd {
+ u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
+} __packed;
+
+enum iwl_bt_coex_env_action {
+ BT_COEX_ENV_CLOSE = 0,
+ BT_COEX_ENV_OPEN = 1,
+}; /* BT_COEX_PROT_ENV_ACTION_API_E_VER_1 */
+
+/**
+ * struct iwl_bt_coex_prot_env_cmd - BT Protection Envelope
+ * @action: enum %iwl_bt_coex_env_action
+ * @type: enum %iwl_bt_coex_prio_table_event
+ */
+struct iwl_bt_coex_prot_env_cmd {
+ u8 action; /* 0 = closed, 1 = open */
+ u8 type; /* 0 .. 15 */
+ u8 reserved[2];
+} __packed;
+
+#endif /* __fw_api_bt_coex_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
index cf6f9a02fb74..51e015d1dfb2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -258,7 +258,7 @@ enum iwl_wowlan_wakeup_reason {
IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8),
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9),
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10),
- IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11),
+ /* BIT(11) reserved */
IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12),
}; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */
@@ -277,6 +277,55 @@ struct iwl_wowlan_status {
u8 wake_packet[]; /* can be truncated from _length to _bufsize */
} __packed; /* WOWLAN_STATUSES_API_S_VER_4 */
+#define IWL_WOWLAN_TCP_MAX_PACKET_LEN 64
+#define IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN 128
+#define IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS 2048
+
+struct iwl_tcp_packet_info {
+ __le16 tcp_pseudo_header_checksum;
+ __le16 tcp_payload_length;
+} __packed; /* TCP_PACKET_INFO_API_S_VER_2 */
+
+struct iwl_tcp_packet {
+ struct iwl_tcp_packet_info info;
+ u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+ u8 data[IWL_WOWLAN_TCP_MAX_PACKET_LEN];
+} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
+
+struct iwl_remote_wake_packet {
+ struct iwl_tcp_packet_info info;
+ u8 rx_mask[IWL_WOWLAN_MAX_PATTERN_LEN / 8];
+ u8 data[IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN];
+} __packed; /* TCP_PROTOCOL_PACKET_API_S_VER_1 */
+
+struct iwl_wowlan_remote_wake_config {
+ __le32 connection_max_time; /* unused */
+ /* TCP_PROTOCOL_CONFIG_API_S_VER_1 */
+ u8 max_syn_retries;
+ u8 max_data_retries;
+ u8 tcp_syn_ack_timeout;
+ u8 tcp_ack_timeout;
+
+ struct iwl_tcp_packet syn_tx;
+ struct iwl_tcp_packet synack_rx;
+ struct iwl_tcp_packet keepalive_ack_rx;
+ struct iwl_tcp_packet fin_tx;
+
+ struct iwl_remote_wake_packet keepalive_tx;
+ struct iwl_remote_wake_packet wake_rx;
+
+ /* REMOTE_WAKE_OFFSET_INFO_API_S_VER_1 */
+ u8 sequence_number_offset;
+ u8 sequence_number_length;
+ u8 token_offset;
+ u8 token_length;
+ /* REMOTE_WAKE_PROTOCOL_PARAMS_API_S_VER_1 */
+ __le32 initial_sequence_number;
+ __le16 keepalive_interval;
+ __le16 num_tokens;
+ u8 tokens[IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS];
+} __packed; /* REMOTE_WAKE_CONFIG_API_S_VER_2 */
+
/* TODO: NetDetect API */
#endif /* __fw_api_d3_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
index ae39b7dfda7b..d68640ea41d4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index be36b7604b7f..81fe45f46be7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -68,73 +68,53 @@
/**
* enum iwl_scan_flags - masks for power table command flags
+ * @POWER_FLAGS_POWER_SAVE_ENA_MSK: '1' Allow to save power by turning off
+ * receiver and transmitter. '0' - does not allow.
* @POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK: '0' Driver disables power management,
* '1' Driver enables PM (use rest of parameters)
- * @POWER_FLAGS_SLEEP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM,
+ * @POWER_FLAGS_SKIP_OVER_DTIM_MSK: '0' PM have to walk up every DTIM,
* '1' PM could sleep over DTIM till listen Interval.
- * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
- * @POWER_FLAGS_SNOOZE_ENA_MSK: Enable snoozing only if uAPSD is enabled and all
- * access categories are both delivery and trigger enabled.
- * @POWER_FLAGS_BT_SCO_ENA: Enable BT SCO coex only if uAPSD and
- * PBW Snoozing enabled
* @POWER_FLAGS_ADVANCE_PM_ENA_MSK: Advanced PM (uAPSD) enable mask
+ * @POWER_FLAGS_LPRX_ENA_MSK: Low Power RX enable.
*/
enum iwl_power_flags {
- POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(0),
- POWER_FLAGS_SLEEP_OVER_DTIM_MSK = BIT(1),
- POWER_FLAGS_LPRX_ENA_MSK = BIT(2),
- POWER_FLAGS_SNOOZE_ENA_MSK = BIT(3),
- POWER_FLAGS_BT_SCO_ENA = BIT(4),
- POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(5)
+ POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0),
+ POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK = BIT(1),
+ POWER_FLAGS_SKIP_OVER_DTIM_MSK = BIT(2),
+ POWER_FLAGS_ADVANCE_PM_ENA_MSK = BIT(9),
+ POWER_FLAGS_LPRX_ENA_MSK = BIT(11),
};
+#define IWL_POWER_VEC_SIZE 5
+
/**
* struct iwl_powertable_cmd - Power Table Command
* POWER_TABLE_CMD = 0x77 (command, has simple generic response)
*
- * @id_and_color: MAC contex identifier
- * @action: Action on context - no action, add new,
- * modify existent, remove
* @flags: Power table command flags from POWER_FLAGS_*
* @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec.
- * Minimum allowed:- 3 * DTIM
+ * Minimum allowed:- 3 * DTIM. Keep alive period must be
+ * set regardless of power scheme or current power state.
+ * FW use this value also when PM is disabled.
* @rx_data_timeout: Minimum time (usec) from last Rx packet for AM to
* PSM transition - legacy PM
* @tx_data_timeout: Minimum time (usec) from last Tx packet for AM to
* PSM transition - legacy PM
- * @rx_data_timeout_uapsd: Minimum time (usec) from last Rx packet for AM to
- * PSM transition - uAPSD
- * @tx_data_timeout_uapsd: Minimum time (usec) from last Tx packet for AM to
- * PSM transition - uAPSD
+ * @sleep_interval: not in use
+ * @keep_alive_beacons: not in use
* @lprx_rssi_threshold: Signal strength up to which LP RX can be enabled.
* Default: 80dbm
- * @num_skip_dtim: Number of DTIMs to skip if Skip over DTIM flag is set
- * @snooze_interval: TBD
- * @snooze_window: TBD
- * @snooze_step: TBD
- * @qndp_tid: TBD
- * @uapsd_ac_flags: TBD
- * @uapsd_max_sp: TBD
*/
struct iwl_powertable_cmd {
- /* COMMON_INDEX_HDR_API_S_VER_1 */
- __le32 id_and_color;
- __le32 action;
+ /* PM_POWER_TABLE_CMD_API_S_VER_5 */
__le16 flags;
- u8 reserved;
- __le16 keep_alive_seconds;
+ u8 keep_alive_seconds;
+ u8 debug_flags;
__le32 rx_data_timeout;
__le32 tx_data_timeout;
- __le32 rx_data_timeout_uapsd;
- __le32 tx_data_timeout_uapsd;
- u8 lprx_rssi_threshold;
- u8 num_skip_dtim;
- __le16 snooze_interval;
- __le16 snooze_window;
- u8 snooze_step;
- u8 qndp_tid;
- u8 uapsd_ac_flags;
- u8 uapsd_max_sp;
+ __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+ __le32 keep_alive_beacons;
+ __le32 lprx_rssi_threshold;
} __packed;
#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
index aa3474d08231..fdd33bc0a594 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 670ac8f95e26..b60d14151721 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
index 0acb53dda22d..a30691a8a85b 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index 2677914bf0a6..007a93b25bd7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -537,6 +537,12 @@ struct iwl_mac_beacon_cmd {
struct ieee80211_hdr frame[0];
} __packed;
+struct iwl_beacon_notif {
+ struct iwl_mvm_tx_resp beacon_notify_hdr;
+ __le64 tsf;
+ __le32 ibss_mgr_status;
+} __packed;
+
/**
* enum iwl_dump_control - dump (flush) control flags
* @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 2adb61f103f4..191dcae8ba47 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -70,6 +70,7 @@
#include "fw-api-mac.h"
#include "fw-api-power.h"
#include "fw-api-d3.h"
+#include "fw-api-bt-coex.h"
/* queue and FIFO numbers by usage */
enum {
@@ -150,8 +151,10 @@ enum {
SET_CALIB_DEFAULT_CMD = 0x8e,
+ BEACON_NOTIFICATION = 0x90,
BEACON_TEMPLATE_CMD = 0x91,
TX_ANT_CONFIGURATION_CMD = 0x98,
+ BT_CONFIG = 0x9b,
STATISTICS_NOTIFICATION = 0x9d,
/* RF-KILL commands and notifications */
@@ -162,6 +165,11 @@ enum {
REPLY_RX_MPDU_CMD = 0xc1,
BA_NOTIF = 0xc5,
+ /* BT Coex */
+ BT_COEX_PRIO_TABLE = 0xcc,
+ BT_COEX_PROT_ENV = 0xcd,
+ BT_PROFILE_NOTIFICATION = 0xce,
+
REPLY_DEBUG_CMD = 0xf0,
DEBUG_LOG_MSG = 0xf7,
@@ -271,38 +279,7 @@ enum {
NVM_ACCESS_TARGET_EEPROM = 2,
};
-/**
- * struct iwl_nvm_access_cmd_ver1 - Request the device to send the NVM.
- * @op_code: 0 - read, 1 - write.
- * @target: NVM_ACCESS_TARGET_*. should be 0 for read.
- * @cache_refresh: 0 - None, 1- NVM.
- * @offset: offset in the nvm data.
- * @length: of the chunk.
- * @data: empty on read, the NVM chunk on write
- */
-struct iwl_nvm_access_cmd_ver1 {
- u8 op_code;
- u8 target;
- u8 cache_refresh;
- u8 reserved;
- __le16 offset;
- __le16 length;
- u8 data[];
-} __packed; /* NVM_ACCESS_CMD_API_S_VER_1 */
-
-/**
- * struct iwl_nvm_access_resp_ver1 - response to NVM_ACCESS_CMD
- * @offset: the offset in the nvm data
- * @length: of the chunk
- * @data: the nvm chunk on when NVM_ACCESS_CMD was read, nothing on write
- */
-struct iwl_nvm_access_resp_ver1 {
- __le16 offset;
- __le16 length;
- u8 data[];
-} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_1 */
-
-/* Section types for NVM_ACCESS_CMD version 2 */
+/* Section types for NVM_ACCESS_CMD */
enum {
NVM_SECTION_TYPE_HW = 0,
NVM_SECTION_TYPE_SW,
@@ -323,7 +300,7 @@ enum {
* @length: in bytes, to read/write
* @data: if write operation, the data to write. On read its empty
*/
-struct iwl_nvm_access_cmd_ver2 {
+struct iwl_nvm_access_cmd {
u8 op_code;
u8 target;
__le16 type;
@@ -340,7 +317,7 @@ struct iwl_nvm_access_cmd_ver2 {
* @status: 0 for success, fail otherwise
* @data: if read operation, the data returned. Empty on write.
*/
-struct iwl_nvm_access_resp_ver2 {
+struct iwl_nvm_access_resp {
__le16 offset;
__le16 length;
__le16 type;
@@ -503,15 +480,34 @@ enum {
TE_DEP_TSF = 2,
TE_EVENT_SOCIOPATHIC = 4,
}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */
-
-/* When to send Time Event notifications and to whom (internal = FW) */
+/*
+ * Supported Time event notifications configuration.
+ * A notification (both event and fragment) includes a status indicating weather
+ * the FW was able to schedule the event or not. For fragment start/end
+ * notification the status is always success. There is no start/end fragment
+ * notification for monolithic events.
+ *
+ * @TE_NOTIF_NONE: no notifications
+ * @TE_NOTIF_HOST_EVENT_START: request/receive notification on event start
+ * @TE_NOTIF_HOST_EVENT_END:request/receive notification on event end
+ * @TE_NOTIF_INTERNAL_EVENT_START: internal FW use
+ * @TE_NOTIF_INTERNAL_EVENT_END: internal FW use.
+ * @TE_NOTIF_HOST_FRAG_START: request/receive notification on frag start
+ * @TE_NOTIF_HOST_FRAG_END:request/receive notification on frag end
+ * @TE_NOTIF_INTERNAL_FRAG_START: internal FW use.
+ * @TE_NOTIF_INTERNAL_FRAG_END: internal FW use.
+ */
enum {
TE_NOTIF_NONE = 0,
- TE_NOTIF_HOST_START = 0x1,
- TE_NOTIF_HOST_END = 0x2,
- TE_NOTIF_INTERNAL_START = 0x4,
- TE_NOTIF_INTERNAL_END = 0x8
-}; /* MAC_EVENT_ACTION_API_E_VER_1 */
+ TE_NOTIF_HOST_EVENT_START = 0x1,
+ TE_NOTIF_HOST_EVENT_END = 0x2,
+ TE_NOTIF_INTERNAL_EVENT_START = 0x4,
+ TE_NOTIF_INTERNAL_EVENT_END = 0x8,
+ TE_NOTIF_HOST_FRAG_START = 0x10,
+ TE_NOTIF_HOST_FRAG_END = 0x20,
+ TE_NOTIF_INTERNAL_FRAG_START = 0x40,
+ TE_NOTIF_INTERNAL_FRAG_END = 0x80
+}; /* MAC_EVENT_ACTION_API_E_VER_2 */
/*
* @TE_FRAG_NONE: fragmentation of the time event is NOT allowed.
@@ -794,6 +790,7 @@ struct iwl_phy_context_cmd {
* @byte_count: frame's byte-count
* @frame_time: frame's time on the air, based on byte count and frame rate
* calculation
+ * @mac_active_msk: what MACs were active when the frame was received
*
* Before each Rx, the device sends this data. It contains PHY information
* about the reception of the packet.
@@ -811,7 +808,7 @@ struct iwl_rx_phy_info {
__le32 non_cfg_phy[IWL_RX_INFO_PHY_CNT];
__le32 rate_n_flags;
__le32 byte_count;
- __le16 reserved2;
+ __le16 mac_active_msk;
__le16 frame_time;
} __packed;
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index 500f818dba04..e18c92dd60ec 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -114,7 +114,7 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
.valid = cpu_to_le32(valid_tx_ant),
};
- IWL_DEBUG_HC(mvm, "select valid tx ant: %u\n", valid_tx_ant);
+ IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant);
return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, CMD_SYNC,
sizeof(tx_ant_cmd), &tx_ant_cmd);
}
@@ -134,9 +134,10 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
alive_data->scd_base_addr = le32_to_cpu(palive->scd_base_ptr);
alive_data->valid = le16_to_cpu(palive->status) == IWL_ALIVE_STATUS_OK;
- IWL_DEBUG_FW(mvm, "Alive ucode status 0x%04x revision 0x%01X 0x%01X\n",
+ IWL_DEBUG_FW(mvm,
+ "Alive ucode status 0x%04x revision 0x%01X 0x%01X flags 0x%01X\n",
le16_to_cpu(palive->status), palive->ver_type,
- palive->ver_subtype);
+ palive->ver_subtype, palive->flags);
return true;
}
@@ -309,6 +310,10 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
goto error;
}
+ ret = iwl_send_bt_prio_tbl(mvm);
+ if (ret)
+ goto error;
+
if (read_nvm) {
/* Read nvm */
ret = iwl_nvm_init(mvm);
@@ -322,16 +327,14 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
WARN_ON(ret);
/* Send TX valid antennas before triggering calibrations */
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
- /* WkP doesn't have all calibrations, need to set default values */
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- ret = iwl_set_default_calibrations(mvm);
- if (ret)
- goto error;
- }
+ /* need to set default values */
+ ret = iwl_set_default_calibrations(mvm);
+ if (ret)
+ goto error;
/*
* Send phy configurations command to init uCode
@@ -410,7 +413,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
+ if (ret)
+ goto error;
+
+ ret = iwl_send_bt_prio_tbl(mvm);
+ if (ret)
+ goto error;
+
+ ret = iwl_send_bt_init_conf(mvm);
if (ret)
goto error;
@@ -456,7 +467,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, mvm->nvm_data->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_fw_valid_tx_ant(mvm->fw));
if (ret)
goto error;
diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c
index 011906e73a05..2269a9e5cc67 100644
--- a/drivers/net/wireless/iwlwifi/mvm/led.c
+++ b/drivers/net/wireless/iwlwifi/mvm/led.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index 341dbc0237ea..e6eca4d66f6c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -196,7 +196,7 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
u32 qmask, ac;
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
- return BIT(IWL_OFFCHANNEL_QUEUE);
+ return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
qmask = (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) ?
BIT(vif->cab_queue) : 0;
@@ -553,9 +553,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
if (vif->bss_conf.qos)
cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
+ /* Don't use cts to self as the fw doesn't support it currently. */
if (vif->bss_conf.use_cts_prot)
- cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT |
- MAC_PROT_FLG_SELF_CTS_EN);
+ cmd->protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
/*
* I think that we should enable these 2 flags regardless the HT PROT
@@ -651,6 +651,13 @@ static int iwl_mvm_mac_ctxt_cmd_station(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ /* Allow beacons to pass through as long as we are not associated,or we
+ * do not have dtim period information */
+ if (!vif->bss_conf.assoc || !vif->bss_conf.dtim_period)
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
+ else
+ cmd.filter_flags &= ~cpu_to_le32(MAC_FILTER_IN_BEACON);
+
/* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.sta);
@@ -662,6 +669,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
u32 action)
{
struct iwl_mac_ctx_cmd cmd = {};
+ struct ieee80211_p2p_noa_attr *noa = &vif->bss_conf.p2p_noa_attr;
WARN_ON(vif->type != NL80211_IFTYPE_STATION || !vif->p2p);
@@ -671,7 +679,8 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_client(struct iwl_mvm *mvm,
/* Fill the data specific for station mode */
iwl_mvm_mac_ctxt_cmd_fill_sta(mvm, vif, &cmd.p2p_sta.sta);
- cmd.p2p_sta.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
+ cmd.p2p_sta.ctwin = cpu_to_le32(noa->oppps_ctwindow &
+ IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -685,7 +694,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
- /* No other data to be filled */
+
+ cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
+ MAC_FILTER_IN_CONTROL_AND_MGMT |
+ MAC_FILTER_IN_BEACON |
+ MAC_FILTER_IN_PROBE_REQUEST);
+
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -714,7 +728,9 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
- cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROMISC);
+
+ /* Override the filter flags to accept only probe requests */
+ cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
/*
* This flag should be set to true when the P2P Device is
@@ -789,7 +805,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
TX_CMD_FLG_TSF);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->mgmt_last_antenna_idx);
beacon_cmd.tx.rate_n_flags =
@@ -846,10 +862,10 @@ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
*/
static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_mac_data_ap *ctxt_ap)
+ struct iwl_mac_data_ap *ctxt_ap,
+ bool add)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- u32 curr_dev_time;
ctxt_ap->bi = cpu_to_le32(vif->bss_conf.beacon_int);
ctxt_ap->bi_reciprocal =
@@ -861,10 +877,19 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
vif->bss_conf.dtim_period));
ctxt_ap->mcast_qid = cpu_to_le32(vif->cab_queue);
- curr_dev_time = iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
- ctxt_ap->beacon_time = cpu_to_le32(curr_dev_time);
- ctxt_ap->beacon_tsf = cpu_to_le64(curr_dev_time);
+ /*
+ * Only read the system time when the MAC is being added, when we
+ * just modify the MAC then we should keep the time -- the firmware
+ * can otherwise have a "jumping" TBTT.
+ */
+ if (add)
+ mvmvif->ap_beacon_time =
+ iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+
+ ctxt_ap->beacon_time = cpu_to_le32(mvmvif->ap_beacon_time);
+
+ ctxt_ap->beacon_tsf = 0; /* unused */
/* TODO: Assume that the beacon id == mac context id */
ctxt_ap->beacon_template = cpu_to_le32(mvmvif->id);
@@ -881,8 +906,12 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
/* Fill the common data for all mac context types */
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ /* Also enable probe requests to pass */
+ cmd.filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
+
/* Fill the data specific for ap mode */
- iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap);
+ iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.ap,
+ action == FW_CTXT_ACTION_ADD);
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -892,6 +921,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
u32 action)
{
struct iwl_mac_ctx_cmd cmd = {};
+ struct ieee80211_p2p_noa_attr *noa = &vif->bss_conf.p2p_noa_attr;
WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
@@ -899,10 +929,14 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
/* Fill the data specific for GO mode */
- iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap);
+ iwl_mvm_mac_ctxt_cmd_fill_ap(mvm, vif, &cmd.go.ap,
+ action == FW_CTXT_ACTION_ADD);
- cmd.go.ctwin = cpu_to_le32(vif->bss_conf.p2p_ctwindow);
- cmd.go.opp_ps_enabled = cpu_to_le32(!!vif->bss_conf.p2p_oppps);
+ cmd.go.ctwin = cpu_to_le32(noa->oppps_ctwindow &
+ IEEE80211_P2P_OPPPS_CTWINDOW_MASK);
+ cmd.go.opp_ps_enabled =
+ cpu_to_le32(!!(noa->oppps_ctwindow &
+ IEEE80211_P2P_OPPPS_ENABLE_BIT));
return iwl_mvm_mac_ctxt_send_cmd(mvm, &cmd);
}
@@ -990,3 +1024,22 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
mvmvif->uploaded = false;
return 0;
}
+
+int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_beacon_notif *beacon = (void *)pkt->data;
+ u16 status __maybe_unused =
+ le16_to_cpu(beacon->beacon_notify_hdr.status.status);
+ u32 rate __maybe_unused =
+ le32_to_cpu(beacon->beacon_notify_hdr.initial_rate);
+
+ IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n",
+ status & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le64_to_cpu(beacon->tsf),
+ rate);
+ return 0;
+}
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 7e169b085afe..dd158ec571fb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -65,7 +65,9 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ip.h>
#include <net/mac80211.h>
+#include <net/tcp.h>
#include "iwl-op-mode.h"
#include "iwl-io.h"
@@ -102,10 +104,33 @@ static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
},
};
+#ifdef CONFIG_PM_SLEEP
+static const struct nl80211_wowlan_tcp_data_token_feature
+iwl_mvm_wowlan_tcp_token_feature = {
+ .min_len = 0,
+ .max_len = 255,
+ .bufsize = IWL_WOWLAN_REMOTE_WAKE_MAX_TOKENS,
+};
+
+static const struct wiphy_wowlan_tcp_support iwl_mvm_wowlan_tcp_support = {
+ .tok = &iwl_mvm_wowlan_tcp_token_feature,
+ .data_payload_max = IWL_WOWLAN_TCP_MAX_PACKET_LEN -
+ sizeof(struct ethhdr) -
+ sizeof(struct iphdr) -
+ sizeof(struct tcphdr),
+ .data_interval_max = 65535, /* __le16 in API */
+ .wake_payload_max = IWL_WOWLAN_REMOTE_WAKE_MAX_PACKET_LEN -
+ sizeof(struct ethhdr) -
+ sizeof(struct iphdr) -
+ sizeof(struct tcphdr),
+ .seq = true,
+};
+#endif
+
int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
{
struct ieee80211_hw *hw = mvm->hw;
- int num_mac, ret;
+ int num_mac, ret, i;
/* Tell mac80211 our characteristics */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
@@ -118,8 +143,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TIMING_BEACON_ONLY;
- hw->queues = IWL_FIRST_AMPDU_QUEUE;
- hw->offchannel_tx_hw_queue = IWL_OFFCHANNEL_QUEUE;
+ hw->queues = IWL_MVM_FIRST_AGG_QUEUE;
+ hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE;
hw->rate_control_algorithm = "iwl-mvm-rs";
/*
@@ -149,18 +174,22 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->n_iface_combinations =
ARRAY_SIZE(iwl_mvm_iface_combinations);
- hw->wiphy->max_remain_on_channel_duration = 500;
+ hw->wiphy->max_remain_on_channel_duration = 10000;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
/* Extract MAC address */
memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
hw->wiphy->addresses = mvm->addresses;
hw->wiphy->n_addresses = 1;
- num_mac = mvm->nvm_data->n_hw_addrs;
- if (num_mac > 1) {
- memcpy(mvm->addresses[1].addr, mvm->addresses[0].addr,
+
+ /* Extract additional MAC addresses if available */
+ num_mac = (mvm->nvm_data->n_hw_addrs > 1) ?
+ min(IWL_MVM_MAX_ADDRESSES, mvm->nvm_data->n_hw_addrs) : 1;
+
+ for (i = 1; i < num_mac; i++) {
+ memcpy(mvm->addresses[i].addr, mvm->addresses[i-1].addr,
ETH_ALEN);
- mvm->addresses[1].addr[5]++;
+ mvm->addresses[i].addr[5]++;
hw->wiphy->n_addresses++;
}
@@ -178,7 +207,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->hw_version = mvm->trans->hw_id;
- if (iwlwifi_mod_params.power_save)
+ if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
else
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -206,6 +235,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;
hw->wiphy->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;
hw->wiphy->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;
+ hw->wiphy->wowlan.tcp = &iwl_mvm_wowlan_tcp_support;
}
#endif
@@ -227,7 +257,7 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
goto drop;
}
- if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_OFFCHANNEL_QUEUE &&
+ if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE &&
!test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status))
goto drop;
@@ -273,12 +303,18 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
break;
case IEEE80211_AMPDU_TX_START:
+ if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_TXAGG) {
+ ret = -EINVAL;
+ break;
+ }
ret = iwl_mvm_sta_tx_agg_start(mvm, vif, sta, tid, ssn);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
+ ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+ break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- ret = iwl_mvm_sta_tx_agg_stop(mvm, vif, sta, tid);
+ ret = iwl_mvm_sta_tx_agg_flush(mvm, vif, sta, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ret = iwl_mvm_sta_tx_agg_oper(mvm, vif, sta, tid, buf_size);
@@ -466,11 +502,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
- * Iterate and disable PM on all active interfaces.
+ * If new interface added, disable PM on existing interface.
+ * P2P device is a special case, since it is handled by FW similary to
+ * scan. If P2P deviced is added, PM remains enabled on existing
+ * interface.
* Note: the method below does not count the new interface being added
* at this moment.
*/
- mvm->vif_count++;
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+ mvm->vif_count++;
if (mvm->vif_count > 1) {
IWL_DEBUG_MAC80211(mvm,
"Disable power on existing interfaces\n");
@@ -526,6 +566,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
mvm->p2p_device_vif = vif;
}
+ iwl_mvm_vif_dbgfs_register(mvm, vif);
goto out_unlock;
out_unbind:
@@ -539,10 +580,11 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
/*
* TODO: remove this temporary code.
* Currently MVM FW supports power management only on single MAC.
- * Check if only one additional interface remains after rereasing
+ * Check if only one additional interface remains after releasing
* current one. Update power mode on the remaining interface.
*/
- mvm->vif_count--;
+ if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+ mvm->vif_count--;
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
mvm->vif_count);
if (mvm->vif_count == 1) {
@@ -604,6 +646,8 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&mvm->mutex);
+ iwl_mvm_vif_dbgfs_clean(mvm, vif);
+
/*
* For AP/GO interface, the tear down of the resources allocated to the
* interface is be handled as part of the stop_ap flow.
@@ -627,7 +671,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
* Check if only one additional interface remains after removing
* current one. Update power mode on the remaining interface.
*/
- if (mvm->vif_count)
+ if (mvm->vif_count && vif->type != NL80211_IFTYPE_P2P_DEVICE)
mvm->vif_count--;
IWL_DEBUG_MAC80211(mvm, "Currently %d interfaces active\n",
mvm->vif_count);
@@ -677,6 +721,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
IWL_ERR(mvm, "failed to update quotas\n");
return;
}
+ iwl_mvm_bt_coex_vif_assoc(mvm, vif);
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
/* remove AP station now that the MAC is unassoc */
ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@@ -895,7 +940,7 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
*/
break;
case STA_NOTIFY_AWAKE:
- if (WARN_ON(mvmsta->sta_id == IWL_INVALID_STATION))
+ if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
break;
iwl_mvm_sta_modify_ps_wake(mvm, sta);
break;
@@ -1051,6 +1096,13 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
+ if (vif->type == NL80211_IFTYPE_AP && !sta) {
+ /* GTK on AP interface is a TX-only key, return 0 */
+ ret = 0;
+ key->hw_key_idx = STA_KEY_IDX_INVALID;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, false);
if (ret) {
@@ -1059,11 +1111,17 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
* can't add key for RX, but we don't need it
* in the device for TX so still return 0
*/
+ key->hw_key_idx = STA_KEY_IDX_INVALID;
ret = 0;
}
break;
case DISABLE_KEY:
+ if (key->hw_key_idx == STA_KEY_IDX_INVALID) {
+ ret = 0;
+ break;
+ }
+
IWL_DEBUG_MAC80211(mvm, "disable hwcrypto key\n");
ret = iwl_mvm_remove_sta_key(mvm, vif, sta, key);
break;
@@ -1090,7 +1148,8 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
static int iwl_mvm_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *channel,
- int duration)
+ int duration,
+ enum ieee80211_roc_type type)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
struct cfg80211_chan_def chandef;
@@ -1101,8 +1160,8 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
return -EINVAL;
}
- IWL_DEBUG_MAC80211(mvm, "enter (%d, %d)\n", channel->hw_value,
- duration);
+ IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
+ duration, type);
mutex_lock(&mvm->mutex);
@@ -1111,7 +1170,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
&chandef, 1, 1);
/* Schedule the time events */
- ret = iwl_mvm_start_p2p_roc(mvm, vif, duration);
+ ret = iwl_mvm_start_p2p_roc(mvm, vif, duration, type);
mutex_unlock(&mvm->mutex);
IWL_DEBUG_MAC80211(mvm, "leave\n");
@@ -1215,6 +1274,7 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw,
* will handle quota settings.
*/
if (vif->type == NL80211_IFTYPE_MONITOR) {
+ mvmvif->monitor_active = true;
ret = iwl_mvm_update_quotas(mvm, vif);
if (ret)
goto out_remove_binding;
@@ -1245,15 +1305,16 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (vif->type == NL80211_IFTYPE_AP)
goto out_unlock;
- iwl_mvm_binding_remove_vif(mvm, vif);
switch (vif->type) {
case NL80211_IFTYPE_MONITOR:
- iwl_mvm_update_quotas(mvm, vif);
+ mvmvif->monitor_active = false;
+ iwl_mvm_update_quotas(mvm, NULL);
break;
default:
break;
}
+ iwl_mvm_binding_remove_vif(mvm, vif);
out_unlock:
mvmvif->phy_ctxt = NULL;
mutex_unlock(&mvm->mutex);
@@ -1274,6 +1335,15 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
return iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm_sta->vif);
}
+static void iwl_mvm_mac_rssi_callback(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_rssi_event rssi_event)
+{
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+ iwl_mvm_bt_rssi_event(mvm, vif, rssi_event);
+}
+
struct ieee80211_ops iwl_mvm_hw_ops = {
.tx = iwl_mvm_mac_tx,
.ampdu_action = iwl_mvm_mac_ampdu_action,
@@ -1297,6 +1367,7 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
.update_tkip_key = iwl_mvm_mac_update_tkip_key,
.remain_on_channel = iwl_mvm_roc,
.cancel_remain_on_channel = iwl_mvm_cancel_roc,
+ .rssi_callback = iwl_mvm_mac_rssi_callback,
.add_chanctx = iwl_mvm_add_chanctx,
.remove_chanctx = iwl_mvm_remove_chanctx,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index bdae700c769e..8269bc562951 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -79,7 +79,7 @@
#include "fw-api.h"
#define IWL_INVALID_MAC80211_QUEUE 0xff
-#define IWL_MVM_MAX_ADDRESSES 2
+#define IWL_MVM_MAX_ADDRESSES 5
/* RSSI offset for WkP */
#define IWL_RSSI_OFFSET 50
@@ -90,10 +90,6 @@ enum iwl_mvm_tx_fifo {
IWL_MVM_TX_FIFO_VO,
};
-/* Placeholder */
-#define IWL_OFFCHANNEL_QUEUE 8
-#define IWL_FIRST_AMPDU_QUEUE 11
-
extern struct ieee80211_ops iwl_mvm_hw_ops;
/**
* struct iwl_mvm_mod_params - module parameters for iwlmvm
@@ -161,6 +157,8 @@ enum iwl_power_scheme {
* @uploaded: indicates the MAC context has been added to the device
* @ap_active: indicates that ap context is configured, and that the interface
* should get quota etc.
+ * @monitor_active: indicates that monitor context is configured, and that the
+ * interface should get quota etc.
* @queue_params: QoS params for this MAC
* @bcast_sta: station used for broadcast packets. Used by the following
* vifs: P2P_DEVICE, GO and AP.
@@ -173,6 +171,9 @@ struct iwl_mvm_vif {
bool uploaded;
bool ap_active;
+ bool monitor_active;
+
+ u32 ap_beacon_time;
enum iwl_tsf_id tsf_id;
@@ -211,6 +212,7 @@ struct iwl_mvm_vif {
#ifdef CONFIG_IWLWIFI_DEBUGFS
struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_slink;
void *dbgfs_data;
#endif
};
@@ -279,10 +281,7 @@ struct iwl_mvm {
atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
struct iwl_nvm_data *nvm_data;
- /* eeprom blob for debugfs/testmode */
- u8 *eeprom_blob;
- size_t eeprom_blob_size;
- /* NVM sections for 7000 family */
+ /* NVM sections */
struct iwl_nvm_section nvm_sections[NVM_NUM_OF_SECTIONS];
/* EEPROM MAC addresses */
@@ -323,6 +322,13 @@ struct iwl_mvm {
* can hold 16 keys at most. Reflect this fact.
*/
unsigned long fw_key_table[BITS_TO_LONGS(STA_KEY_MAX_NUM)];
+
+ /*
+ * This counter of created interfaces is referenced only in conjunction
+ * with FW limitation related to power management. Currently PM is
+ * supported only on a single interface.
+ * IMPORTANT: this variable counts all interfaces except P2P device.
+ */
u8 vif_count;
struct led_classdev led;
@@ -332,6 +338,10 @@ struct iwl_mvm {
#ifdef CONFIG_PM_SLEEP
int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
#endif
+
+ /* BT-Coex */
+ u8 bt_kill_msk;
+ struct iwl_bt_coex_profile_notif last_bt_notif;
};
/* Extract MVM priv from op_mode and _hw */
@@ -445,6 +455,9 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
struct ieee80211_vif *vif);
+int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* Bindings */
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
@@ -466,16 +479,22 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
/* MVM debugfs */
#ifdef CONFIG_IWLWIFI_DEBUGFS
int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir);
-int iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct dentry *dbgfs_dir);
-void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_powertable_cmd *cmd);
+void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
#else
static inline int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm,
struct dentry *dbgfs_dir)
{
return 0;
}
+static inline void
+iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+}
+static inline void
+iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+}
#endif /* CONFIG_IWLWIFI_DEBUGFS */
/* rate scaling */
@@ -485,6 +504,8 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
/* power managment */
int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_powertable_cmd *cmd);
int iwl_mvm_leds_init(struct iwl_mvm *mvm);
void iwl_mvm_leds_exit(struct iwl_mvm *mvm);
@@ -502,4 +523,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw,
void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int idx);
+/* BT Coex */
+int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm);
+int iwl_send_bt_init_conf(struct iwl_mvm *mvm);
+int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
+void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ enum ieee80211_rssi_event rssi_event);
+void iwl_mvm_bt_coex_vif_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index 20016bcbdeab..b8ec02f89acc 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -74,26 +74,11 @@ static const int nvm_to_read[] = {
NVM_SECTION_TYPE_PRODUCTION,
};
-/* used to simplify the shared operations on NCM_ACCESS_CMD versions */
-union iwl_nvm_access_cmd {
- struct iwl_nvm_access_cmd_ver1 ver1;
- struct iwl_nvm_access_cmd_ver2 ver2;
-};
-union iwl_nvm_access_resp {
- struct iwl_nvm_access_resp_ver1 ver1;
- struct iwl_nvm_access_resp_ver2 ver2;
-};
-
-static inline void iwl_nvm_fill_read_ver1(struct iwl_nvm_access_cmd_ver1 *cmd,
- u16 offset, u16 length)
-{
- cmd->offset = cpu_to_le16(offset);
- cmd->length = cpu_to_le16(length);
- cmd->cache_refresh = 1;
-}
+/* Default NVM size to read */
+#define IWL_NVM_DEFAULT_CHUNK_SIZE (2*1024);
-static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
- u16 offset, u16 length, u16 section)
+static inline void iwl_nvm_fill_read(struct iwl_nvm_access_cmd *cmd,
+ u16 offset, u16 length, u16 section)
{
cmd->offset = cpu_to_le16(offset);
cmd->length = cpu_to_le16(length);
@@ -103,8 +88,8 @@ static inline void iwl_nvm_fill_read_ver2(struct iwl_nvm_access_cmd_ver2 *cmd,
static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
u16 offset, u16 length, u8 *data)
{
- union iwl_nvm_access_cmd nvm_access_cmd;
- union iwl_nvm_access_resp *nvm_resp;
+ struct iwl_nvm_access_cmd nvm_access_cmd = {};
+ struct iwl_nvm_access_resp *nvm_resp;
struct iwl_rx_packet *pkt;
struct iwl_host_cmd cmd = {
.id = NVM_ACCESS_CMD,
@@ -114,18 +99,8 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
int ret, bytes_read, offset_read;
u8 *resp_data;
- memset(&nvm_access_cmd, 0, sizeof(nvm_access_cmd));
-
- /* TODO: not sure family should be the decider, maybe FW version? */
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- iwl_nvm_fill_read_ver2(&(nvm_access_cmd.ver2),
- offset, length, section);
- cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver2);
- } else {
- iwl_nvm_fill_read_ver1(&(nvm_access_cmd.ver1),
- offset, length);
- cmd.len[0] = sizeof(struct iwl_nvm_access_cmd_ver1);
- }
+ iwl_nvm_fill_read(&nvm_access_cmd, offset, length, section);
+ cmd.len[0] = sizeof(struct iwl_nvm_access_cmd);
ret = iwl_mvm_send_cmd(mvm, &cmd);
if (ret)
@@ -141,17 +116,10 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section,
/* Extract NVM response */
nvm_resp = (void *)pkt->data;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- ret = le16_to_cpu(nvm_resp->ver2.status);
- bytes_read = le16_to_cpu(nvm_resp->ver2.length);
- offset_read = le16_to_cpu(nvm_resp->ver2.offset);
- resp_data = nvm_resp->ver2.data;
- } else {
- ret = le16_to_cpu(nvm_resp->ver1.length) <= 0;
- bytes_read = le16_to_cpu(nvm_resp->ver1.length);
- offset_read = le16_to_cpu(nvm_resp->ver1.offset);
- resp_data = nvm_resp->ver1.data;
- }
+ ret = le16_to_cpu(nvm_resp->status);
+ bytes_read = le16_to_cpu(nvm_resp->length);
+ offset_read = le16_to_cpu(nvm_resp->offset);
+ resp_data = nvm_resp->data;
if (ret) {
IWL_ERR(mvm,
"NVM access command failed with status %d (device: %s)\n",
@@ -191,17 +159,10 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
{
u16 length, offset = 0;
int ret;
- bool old_eeprom = mvm->cfg->device_family != IWL_DEVICE_FAMILY_7000;
- length = (iwlwifi_mod_params.amsdu_size_8K ? (8 * 1024) : (4 * 1024))
- - sizeof(union iwl_nvm_access_cmd)
- - sizeof(struct iwl_rx_packet);
- /*
- * if length is greater than EEPROM size, truncate it because uCode
- * doesn't check it by itself, and exit the loop when reached.
- */
- if (old_eeprom && length > mvm->cfg->base_params->eeprom_size)
- length = mvm->cfg->base_params->eeprom_size;
+ /* Set nvm section read length */
+ length = IWL_NVM_DEFAULT_CHUNK_SIZE;
+
ret = length;
/* Read the NVM until exhausted (reading less than requested) */
@@ -214,8 +175,6 @@ static int iwl_nvm_read_section(struct iwl_mvm *mvm, u16 section,
return ret;
}
offset += ret;
- if (old_eeprom && offset == mvm->cfg->base_params->eeprom_size)
- break;
}
IWL_INFO(mvm, "NVM section %d read completed\n", section);
@@ -249,63 +208,31 @@ int iwl_nvm_init(struct iwl_mvm *mvm)
int ret, i, section;
u8 *nvm_buffer, *temp;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
- /* TODO: find correct NVM max size for a section */
- nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
- GFP_KERNEL);
- if (!nvm_buffer)
- return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
- section = nvm_to_read[i];
- /* we override the constness for initial read */
- ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
- if (ret < 0)
- break;
- temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
- if (!temp) {
- ret = -ENOMEM;
- break;
- }
- mvm->nvm_sections[section].data = temp;
- mvm->nvm_sections[section].length = ret;
- }
- kfree(nvm_buffer);
+ /* TODO: find correct NVM max size for a section */
+ nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size,
+ GFP_KERNEL);
+ if (!nvm_buffer)
+ return -ENOMEM;
+ for (i = 0; i < ARRAY_SIZE(nvm_to_read); i++) {
+ section = nvm_to_read[i];
+ /* we override the constness for initial read */
+ ret = iwl_nvm_read_section(mvm, section, nvm_buffer);
if (ret < 0)
- return ret;
- } else {
- /* allocate eeprom */
- mvm->eeprom_blob_size = mvm->cfg->base_params->eeprom_size;
- IWL_DEBUG_EEPROM(mvm->trans->dev, "NVM size = %zd\n",
- mvm->eeprom_blob_size);
- mvm->eeprom_blob = kzalloc(mvm->eeprom_blob_size, GFP_KERNEL);
- if (!mvm->eeprom_blob)
- return -ENOMEM;
-
- ret = iwl_nvm_read_section(mvm, 0, mvm->eeprom_blob);
- if (ret != mvm->eeprom_blob_size) {
- IWL_ERR(mvm, "Read partial NVM %d/%zd\n",
- ret, mvm->eeprom_blob_size);
- kfree(mvm->eeprom_blob);
- mvm->eeprom_blob = NULL;
- return -EINVAL;
+ break;
+ temp = kmemdup(nvm_buffer, ret, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ break;
}
+ mvm->nvm_sections[section].data = temp;
+ mvm->nvm_sections[section].length = ret;
}
+ kfree(nvm_buffer);
+ if (ret < 0)
+ return ret;
ret = 0;
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
- mvm->nvm_data = iwl_parse_nvm_sections(mvm);
- else
- mvm->nvm_data =
- iwl_parse_eeprom_data(mvm->trans->dev,
- mvm->cfg,
- mvm->eeprom_blob,
- mvm->eeprom_blob_size);
-
- if (!mvm->nvm_data) {
- kfree(mvm->eeprom_blob);
- mvm->eeprom_blob = NULL;
- ret = -ENOMEM;
- }
+ mvm->nvm_data = iwl_parse_nvm_sections(mvm);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index d0f9c1e0475e..fe031d304d1e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -143,21 +143,12 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
u32 reg_val = 0;
- /*
- * We can't upload the correct value to the INIT image
- * as we don't have nvm_data by that time.
- *
- * TODO: Figure out what we should do here
- */
- if (mvm->nvm_data) {
- radio_cfg_type = mvm->nvm_data->radio_cfg_type;
- radio_cfg_step = mvm->nvm_data->radio_cfg_step;
- radio_cfg_dash = mvm->nvm_data->radio_cfg_dash;
- } else {
- radio_cfg_type = 0;
- radio_cfg_step = 0;
- radio_cfg_dash = 0;
- }
+ radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >>
+ FW_PHY_CFG_RADIO_TYPE_POS;
+ radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >>
+ FW_PHY_CFG_RADIO_STEP_POS;
+ radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >>
+ FW_PHY_CFG_RADIO_DASH_POS;
/* SKU control */
reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
@@ -175,7 +166,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
/* silicon bits */
reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI;
- reg_val |= CSR_HW_IF_CONFIG_REG_BIT_MAC_SI;
iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH |
@@ -230,6 +220,9 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
+ RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true),
+ RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false),
+
RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
@@ -274,6 +267,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(WEP_KEY),
CMD(REPLY_RX_PHY_CMD),
CMD(REPLY_RX_MPDU_CMD),
+ CMD(BEACON_NOTIFICATION),
CMD(BEACON_TEMPLATE_CMD),
CMD(STATISTICS_NOTIFICATION),
CMD(TX_ANT_CONFIGURATION_CMD),
@@ -293,6 +287,11 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(NET_DETECT_PROFILES_CMD),
CMD(NET_DETECT_HOTSPOTS_CMD),
CMD(NET_DETECT_HOTSPOTS_QUERY_CMD),
+ CMD(CARD_STATE_NOTIFICATION),
+ CMD(BT_COEX_PRIO_TABLE),
+ CMD(BT_COEX_PROT_ENV),
+ CMD(BT_PROFILE_NOTIFICATION),
+ CMD(BT_CONFIG),
};
#undef CMD
@@ -312,16 +311,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
};
int err, scan_size;
- switch (cfg->device_family) {
- case IWL_DEVICE_FAMILY_6030:
- case IWL_DEVICE_FAMILY_6005:
- case IWL_DEVICE_FAMILY_7000:
- break;
- default:
- IWL_ERR(trans, "Trying to load mvm on an unsupported device\n");
- return NULL;
- }
-
/********************************
* 1. Allocating and configuring HW data
********************************/
@@ -363,8 +352,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
- /* TODO: this should really be a TLV */
- if (cfg->device_family == IWL_DEVICE_FAMILY_7000)
+ if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true;
if (!iwlwifi_mod_params.wd_disable)
@@ -438,7 +426,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
out_free:
iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd);
- kfree(mvm->eeprom_blob);
iwl_trans_stop_hw(trans, true);
ieee80211_free_hw(mvm->hw);
return NULL;
@@ -460,7 +447,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL;
- kfree(mvm->eeprom_blob);
iwl_free_nvm_data(mvm->nvm_data);
for (i = 0; i < NVM_NUM_OF_SECTIONS; i++)
kfree(mvm->nvm_sections[i].data);
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index b428448f8ddf..a28a1d1f23eb 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -142,7 +142,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
struct cfg80211_chan_def *chandef,
u8 chains_static, u8 chains_dynamic)
{
- u8 valid_rx_chains, active_cnt, idle_cnt;
+ u8 active_cnt, idle_cnt;
/* Set the channel info data */
cmd->ci.band = (chandef->chan->band == IEEE80211_BAND_2GHZ ?
@@ -153,22 +153,16 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
cmd->ci.ctrl_pos = iwl_mvm_get_ctrl_pos(chandef);
/* Set rx the chains */
-
- /* TODO:
- * Need to add on chain noise calibration limitations, and
- * BT coex considerations.
- */
- valid_rx_chains = mvm->nvm_data->valid_rx_ant;
idle_cnt = chains_static;
active_cnt = chains_dynamic;
- cmd->rxchain_info = cpu_to_le32(valid_rx_chains <<
+ cmd->rxchain_info = cpu_to_le32(iwl_fw_valid_rx_ant(mvm->fw) <<
PHY_RX_CHAIN_VALID_POS);
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
- cmd->txchain_info = cpu_to_le32(mvm->nvm_data->valid_tx_ant);
+ cmd->txchain_info = cpu_to_le32(iwl_fw_valid_tx_ant(mvm->fw));
}
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c
index 5a92a4978795..ed77e437aac4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/iwlwifi/mvm/power.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -75,23 +75,48 @@
#define POWER_KEEP_ALIVE_PERIOD_SEC 25
-static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_powertable_cmd *cmd)
+static void iwl_mvm_power_log(struct iwl_mvm *mvm,
+ struct iwl_powertable_cmd *cmd)
+{
+ IWL_DEBUG_POWER(mvm,
+ "Sending power table command for power level %d, flags = 0x%X\n",
+ iwlmvm_mod_params.power_scheme,
+ le16_to_cpu(cmd->flags));
+ IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n", cmd->keep_alive_seconds);
+
+ if (cmd->flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
+ IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
+ le32_to_cpu(cmd->rx_data_timeout));
+ IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
+ le32_to_cpu(cmd->tx_data_timeout));
+ IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
+ cmd->lprx_rssi_threshold);
+ }
+}
+
+void iwl_mvm_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct iwl_powertable_cmd *cmd)
{
struct ieee80211_hw *hw = mvm->hw;
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
int dtimper, dtimper_msec;
int keep_alive;
bool radar_detect = false;
- cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
- mvmvif->color));
- cmd->action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+ /*
+ * Regardless of power management state the driver must set
+ * keep alive period. FW will use it for sending keep alive NDPs
+ * immediately after association.
+ */
+ cmd->keep_alive_seconds = POWER_KEEP_ALIVE_PERIOD_SEC;
- if ((!vif->bss_conf.ps) ||
- (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM))
+ if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM)
+ return;
+
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
+
+ if (!vif->bss_conf.ps)
return;
cmd->flags |= cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK);
@@ -110,63 +135,29 @@ static void iwl_power_build_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* Check skip over DTIM conditions */
if (!radar_detect && (dtimper <= 10) &&
- (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP)) {
- cmd->flags |= cpu_to_le16(POWER_FLAGS_SLEEP_OVER_DTIM_MSK);
- cmd->num_skip_dtim = 2;
- }
+ (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP))
+ cmd->flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK);
/* Check that keep alive period is at least 3 * DTIM */
dtimper_msec = dtimper * vif->bss_conf.beacon_int;
keep_alive = max_t(int, 3 * dtimper_msec,
- MSEC_PER_SEC * POWER_KEEP_ALIVE_PERIOD_SEC);
+ MSEC_PER_SEC * cmd->keep_alive_seconds);
keep_alive = DIV_ROUND_UP(keep_alive, MSEC_PER_SEC);
+ cmd->keep_alive_seconds = keep_alive;
- cmd->keep_alive_seconds = cpu_to_le16(keep_alive);
-
- if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_LP) {
- /* TODO: Also for D3 (device sleep / WoWLAN) */
- cmd->rx_data_timeout = cpu_to_le32(10);
- cmd->tx_data_timeout = cpu_to_le32(10);
- } else {
- cmd->rx_data_timeout = cpu_to_le32(50);
- cmd->tx_data_timeout = cpu_to_le32(50);
- }
+ cmd->rx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
+ cmd->tx_data_timeout = cpu_to_le32(100 * USEC_PER_MSEC);
}
int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_powertable_cmd cmd = {};
- if (!iwlwifi_mod_params.power_save) {
- IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
- return 0;
- }
-
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
- iwl_power_build_cmd(mvm, vif, &cmd);
-
- IWL_DEBUG_POWER(mvm,
- "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
- cmd.id_and_color, iwlmvm_mod_params.power_scheme,
- le16_to_cpu(cmd.flags));
-
- if (cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)) {
- IWL_DEBUG_POWER(mvm, "Keep alive = %u sec\n",
- le16_to_cpu(cmd.keep_alive_seconds));
- IWL_DEBUG_POWER(mvm, "Rx timeout = %u usec\n",
- le32_to_cpu(cmd.rx_data_timeout));
- IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
- le32_to_cpu(cmd.tx_data_timeout));
- IWL_DEBUG_POWER(mvm, "Rx timeout (uAPSD) = %u usec\n",
- le32_to_cpu(cmd.rx_data_timeout_uapsd));
- IWL_DEBUG_POWER(mvm, "Tx timeout = %u usec\n",
- le32_to_cpu(cmd.tx_data_timeout_uapsd));
- IWL_DEBUG_POWER(mvm, "LP RX RSSI threshold = %u\n",
- cmd.lprx_rssi_threshold);
- IWL_DEBUG_POWER(mvm, "DTIMs to skip = %u\n", cmd.num_skip_dtim);
- }
+ iwl_mvm_power_build_cmd(mvm, vif, &cmd);
+ iwl_mvm_power_log(mvm, &cmd);
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC,
sizeof(cmd), &cmd);
@@ -175,33 +166,15 @@ int iwl_mvm_power_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
struct iwl_powertable_cmd cmd = {};
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
- if (!iwlwifi_mod_params.power_save) {
- IWL_DEBUG_POWER(mvm, "Power management is not allowed\n");
- return 0;
- }
if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
return 0;
- cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
- mvmvif->color));
- cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY);
+ if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
+ cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK);
- IWL_DEBUG_POWER(mvm,
- "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n",
- cmd.id_and_color, iwlmvm_mod_params.power_scheme,
- le16_to_cpu(cmd.flags));
+ iwl_mvm_power_log(mvm, &cmd);
return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC,
sizeof(cmd), &cmd);
}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-void iwl_power_get_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- struct iwl_powertable_cmd *cmd)
-{
- iwl_power_build_cmd(mvm, vif, cmd);
-}
-#endif /* CONFIG_IWLWIFI_DEBUGFS */
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c
index 925628468146..a1e3e923ea3e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/quota.c
+++ b/drivers/net/wireless/iwlwifi/mvm/quota.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -114,7 +114,8 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
data->n_interfaces[id]++;
break;
case NL80211_IFTYPE_MONITOR:
- data->n_interfaces[id]++;
+ if (mvmvif->monitor_active)
+ data->n_interfaces[id]++;
break;
case NL80211_IFTYPE_P2P_DEVICE:
break;
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 56b636d9ab30..55334d542e26 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -680,12 +680,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
*/
static bool rs_use_green(struct ieee80211_sta *sta)
{
- struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
-
- bool use_green = !(sta_priv->vif->bss_conf.ht_operation_mode &
- IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-
- return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && use_green;
+ /*
+ * There's a bug somewhere in this code that causes the
+ * scaling to get stuck because GF+SGI can't be combined
+ * in SISO rates. Until we find that bug, disable GF, it
+ * has only limited benefit and we still interoperate with
+ * GF APs since we can always receive GF transmissions.
+ */
+ return false;
}
/**
@@ -791,7 +793,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
if (num_of_ant(tbl->ant_type) > 1)
tbl->ant_type =
- first_antenna(mvm->nvm_data->valid_tx_ant);
+ first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
tbl->is_ht40 = 0;
tbl->is_SGI = 0;
@@ -1233,7 +1235,7 @@ static int rs_switch_to_mimo2(struct iwl_mvm *mvm,
return -1;
/* Need both Tx chains/antennas to support MIMO */
- if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 2)
+ if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 2)
return -1;
IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO2\n");
@@ -1285,7 +1287,7 @@ static int rs_switch_to_mimo3(struct iwl_mvm *mvm,
return -1;
/* Need both Tx chains/antennas to support MIMO */
- if (num_of_ant(mvm->nvm_data->valid_tx_ant) < 3)
+ if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) < 3)
return -1;
IWL_DEBUG_RATE(mvm, "LQ: try to switch to MIMO3\n");
@@ -1379,7 +1381,7 @@ static int rs_move_legacy_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant);
int ret;
u8 update_search_tbl_counter = 0;
@@ -1512,7 +1514,7 @@ static int rs_move_siso_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant);
u8 update_search_tbl_counter = 0;
int ret;
@@ -1647,7 +1649,7 @@ static int rs_move_mimo2_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant);
u8 update_search_tbl_counter = 0;
int ret;
@@ -1784,7 +1786,7 @@ static int rs_move_mimo3_to_other(struct iwl_mvm *mvm,
u32 sz = (sizeof(struct iwl_scale_tbl_info) -
(sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
u8 start_action;
- u8 valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ u8 valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
u8 tx_chains_num = num_of_ant(valid_tx_ant);
int ret;
u8 update_search_tbl_counter = 0;
@@ -2447,7 +2449,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
i = lq_sta->last_txrate_idx;
- valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
if (!lq_sta->search_better_tbl)
active_tbl = lq_sta->active_tbl;
@@ -2637,15 +2639,15 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk =
- first_antenna(mvm->nvm_data->valid_tx_ant);
+ first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
lq_sta->lq.dual_stream_ant_msk =
- mvm->nvm_data->valid_tx_ant &
- ~first_antenna(mvm->nvm_data->valid_tx_ant);
+ iwl_fw_valid_tx_ant(mvm->fw) &
+ ~first_antenna(iwl_fw_valid_tx_ant(mvm->fw));
if (!lq_sta->lq.dual_stream_ant_msk) {
lq_sta->lq.dual_stream_ant_msk = ANT_AB;
- } else if (num_of_ant(mvm->nvm_data->valid_tx_ant) == 2) {
+ } else if (num_of_ant(iwl_fw_valid_tx_ant(mvm->fw)) == 2) {
lq_sta->lq.dual_stream_ant_msk =
- mvm->nvm_data->valid_tx_ant;
+ iwl_fw_valid_tx_ant(mvm->fw);
}
/* as default allow aggregation for all tids */
@@ -2706,7 +2708,7 @@ static void rs_fill_link_cmd(struct iwl_mvm *mvm,
index++;
repeat_rate--;
if (mvm)
- valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
/* Fill rest of rate table */
while (index < LINK_QUAL_MAX_RETRY_NUM) {
@@ -2811,7 +2813,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
u8 ant_sel_tx;
mvm = lq_sta->drv;
- valid_tx_ant = mvm->nvm_data->valid_tx_ant;
+ valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
if (lq_sta->dbg_fixed_rate) {
ant_sel_tx =
((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
@@ -2882,9 +2884,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
lq_sta->dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
- (mvm->nvm_data->valid_tx_ant & ANT_A) ? "ANT_A," : "",
- (mvm->nvm_data->valid_tx_ant & ANT_B) ? "ANT_B," : "",
- (mvm->nvm_data->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+ (iwl_fw_valid_tx_ant(mvm->fw) & ANT_A) ? "ANT_A," : "",
+ (iwl_fw_valid_tx_ant(mvm->fw) & ANT_B) ? "ANT_B," : "",
+ (iwl_fw_valid_tx_ant(mvm->fw) & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n",
(is_legacy(tbl->lq_type)) ? "legacy" : "HT");
if (is_Ht(tbl->lq_type)) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index b0b190d0ec23..4dfc21a3e83e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 9b21b92aa8d1..2157b0f8ced5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -74,7 +74,7 @@
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
{
u16 rx_chain;
- u8 rx_ant = mvm->nvm_data->valid_rx_ant;
+ u8 rx_ant = iwl_fw_valid_rx_ant(mvm->fw);
rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS;
rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
@@ -115,7 +115,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
u32 tx_ant;
mvm->scan_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->scan_last_antenna_idx);
tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 274f44e2ef60..0fd96e4da461 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -101,8 +101,55 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
add_sta_cmd.add_modify = update ? 1 : 0;
- /* STA_FLG_FAT_EN_MSK ? */
- /* STA_FLG_MIMO_EN_MSK ? */
+ add_sta_cmd.station_flags_msk |= cpu_to_le32(STA_FLG_FAT_EN_MSK |
+ STA_FLG_MIMO_EN_MSK);
+
+ switch (sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_160:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_160MHZ);
+ /* fall through */
+ case IEEE80211_STA_RX_BW_80:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_80MHZ);
+ /* fall through */
+ case IEEE80211_STA_RX_BW_40:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_FAT_EN_40MHZ);
+ /* fall through */
+ case IEEE80211_STA_RX_BW_20:
+ if (sta->ht_cap.ht_supported)
+ add_sta_cmd.station_flags |=
+ cpu_to_le32(STA_FLG_FAT_EN_20MHZ);
+ break;
+ }
+
+ switch (sta->rx_nss) {
+ case 1:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
+ break;
+ case 2:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO2);
+ break;
+ case 3 ... 8:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_MIMO3);
+ break;
+ }
+
+ switch (sta->smps_mode) {
+ case IEEE80211_SMPS_AUTOMATIC:
+ case IEEE80211_SMPS_NUM_MODES:
+ WARN_ON(1);
+ break;
+ case IEEE80211_SMPS_STATIC:
+ /* override NSS */
+ add_sta_cmd.station_flags &= ~cpu_to_le32(STA_FLG_MIMO_EN_MSK);
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_MIMO_EN_SISO);
+ break;
+ case IEEE80211_SMPS_DYNAMIC:
+ add_sta_cmd.station_flags |= cpu_to_le32(STA_FLG_RTS_MIMO_PROT);
+ break;
+ case IEEE80211_SMPS_OFF:
+ /* nothing */
+ break;
+ }
if (sta->ht_cap.ht_supported) {
add_sta_cmd.station_flags_msk |=
@@ -340,6 +387,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_STATION &&
mvmvif->ap_sta_id == mvm_sta->sta_id) {
+ /* flush its queues here since we are freeing mvm_sta */
+ ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
+
/*
* Put a non-NULL since the fw station isn't removed.
* It will be removed after the MAC will be set as
@@ -348,9 +398,6 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
ERR_PTR(-EINVAL));
- /* flush its queues here since we are freeing mvm_sta */
- ret = iwl_mvm_flush_tx_path(mvm, mvm_sta->tfd_queue_msk, true);
-
/* if we are associated - we can't remove the AP STA now */
if (vif->bss_conf.assoc)
return ret;
@@ -686,7 +733,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
spin_lock_bh(&mvmsta->lock);
tid_data = &mvmsta->tid_data[tid];
- tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
tid_data->txq_id = txq_id;
*ssn = tid_data->ssn;
@@ -789,7 +836,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
switch (tid_data->state) {
case IWL_AGG_ON:
- tid_data->ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->ssn = IEEE80211_SEQ_TO_SN(tid_data->seq_number);
IWL_DEBUG_TX_QUEUES(mvm,
"ssn = %d, next_recl = %d\n",
@@ -834,6 +881,34 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return err;
}
+int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
+ struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ u16 txq_id;
+
+ /*
+ * First set the agg state to OFF to avoid calling
+ * ieee80211_stop_tx_ba_cb in iwl_mvm_check_ratid_empty.
+ */
+ spin_lock_bh(&mvmsta->lock);
+ txq_id = tid_data->txq_id;
+ IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
+ mvmsta->sta_id, tid, txq_id, tid_data->state);
+ tid_data->state = IWL_AGG_OFF;
+ spin_unlock_bh(&mvmsta->lock);
+
+ if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+ IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+ iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+ mvm->queue_to_mac80211[tid_data->txq_id] =
+ IWL_INVALID_MAC80211_QUEUE;
+
+ return 0;
+}
+
static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
{
int i;
@@ -870,7 +945,7 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
return mvmvif->ap_sta_id;
- return IWL_INVALID_STATION;
+ return IWL_MVM_STATION_COUNT;
}
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
@@ -1018,7 +1093,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
/* Get the station id from the mvm local station table */
sta_id = iwl_mvm_get_key_sta_id(vif, sta);
- if (sta_id == IWL_INVALID_STATION) {
+ if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_ERR(mvm, "Failed to find station id\n");
return -EINVAL;
}
@@ -1113,7 +1188,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
return -ENOENT;
}
- if (sta_id == IWL_INVALID_STATION) {
+ if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_DEBUG_WEP(mvm, "station non-existent, early return.\n");
return 0;
}
@@ -1179,7 +1254,7 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta;
u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
- if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+ if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
return;
rcu_read_lock();
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 896f88ac8145..12abd2d71835 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -271,6 +271,7 @@ struct iwl_mvm_tid_data {
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid.
* @max_agg_bufsize: the maximal size of the AGG buffer for this station
+ * @bt_reduced_txpower: is reduced tx power enabled for this station
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
* and from Tx response flow, it needs a spinlock.
* @pending_frames: number of frames for this STA on the shared Tx queues.
@@ -287,6 +288,7 @@ struct iwl_mvm_sta {
u32 mac_id_n_color;
u16 tid_disable_agg;
u8 max_agg_bufsize;
+ bool bt_reduced_txpower;
spinlock_t lock;
atomic_t pending_frames;
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT];
@@ -348,6 +350,8 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u8 buf_size);
int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
+int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, u16 tid);
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c
index e437e02c7149..ad9bbca99213 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -76,14 +76,12 @@
#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024))
#define MSEC_TO_TU(_msec) (_msec*1000/1024)
-/* For ROC use a TE type which has priority high enough to be scheduled when
- * there is a concurrent BSS or GO/AP. Currently, use a TE type that has
- * priority similar to the TE priority used for action scans by the FW.
- * TODO: This needs to be changed, based on the reason for the ROC, i.e., use
- * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use
- * TE_P2P_DEVICE_ACTION_SCAN
+/*
+ * For the high priority TE use a time event type that has similar priority to
+ * the FW's action scan priority.
*/
-#define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN
+#define IWL_MVM_ROC_TE_TYPE_NORMAL TE_P2P_DEVICE_DISCOVERABLE
+#define IWL_MVM_ROC_TE_TYPE_MGMT_TX TE_P2P_CLIENT_ASSOC
void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
struct iwl_mvm_time_event_data *te_data)
@@ -116,7 +114,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
* issue as it will have to complete before the next command is
* executed, and a new time event means a new command.
*/
- iwl_mvm_flush_tx_path(mvm, BIT(IWL_OFFCHANNEL_QUEUE), false);
+ iwl_mvm_flush_tx_path(mvm, BIT(IWL_MVM_OFFCHANNEL_QUEUE), false);
}
static void iwl_mvm_roc_finished(struct iwl_mvm *mvm)
@@ -168,7 +166,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
WARN_ONCE(!le32_to_cpu(notif->status),
"Failed to schedule time event\n");
- if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_END) {
+ if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) {
IWL_DEBUG_TE(mvm,
"TE ended - current time %lu, estimated end %lu\n",
jiffies, te_data->end_jiffies);
@@ -191,7 +189,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
}
iwl_mvm_te_clear_data(mvm, te_data);
- } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) {
+ } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) {
te_data->running = true;
te_data->end_jiffies = jiffies +
TU_TO_JIFFIES(te_data->duration);
@@ -370,7 +368,8 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
time_cmd.interval_reciprocal = cpu_to_le32(iwl_mvm_reciprocal(1));
time_cmd.duration = cpu_to_le32(duration);
time_cmd.repeat = cpu_to_le32(1);
- time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+ time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
+ TE_NOTIF_HOST_EVENT_END);
iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
}
@@ -438,7 +437,7 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm,
}
int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- int duration)
+ int duration, enum ieee80211_roc_type type)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@@ -459,27 +458,36 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD);
time_cmd.id_and_color =
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
- time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE);
+
+ switch (type) {
+ case IEEE80211_ROC_TYPE_NORMAL:
+ time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_NORMAL);
+ break;
+ case IEEE80211_ROC_TYPE_MGMT_TX:
+ time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE_MGMT_TX);
+ break;
+ default:
+ WARN_ONCE(1, "Got an invalid ROC type\n");
+ return -EINVAL;
+ }
time_cmd.apply_time = cpu_to_le32(0);
time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT);
time_cmd.is_present = cpu_to_le32(1);
-
time_cmd.interval = cpu_to_le32(1);
/*
- * IWL_MVM_ROC_TE_TYPE can have lower priority than other events
+ * The P2P Device TEs can have lower priority than other events
* that are being scheduled by the driver/fw, and thus it might not be
- * scheduled. To improve the chances of it being scheduled, allow it to
- * be fragmented.
- * In addition, for the same reasons, allow to delay the scheduling of
- * the time event.
+ * scheduled. To improve the chances of it being scheduled, allow them
+ * to be fragmented, and in addition allow them to be delayed.
*/
time_cmd.max_frags = cpu_to_le32(MSEC_TO_TU(duration)/20);
time_cmd.max_delay = cpu_to_le32(MSEC_TO_TU(duration/2));
time_cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
time_cmd.repeat = cpu_to_le32(1);
- time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END);
+ time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_EVENT_START |
+ TE_NOTIF_HOST_EVENT_END);
return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h
index 64fb57a5ab43..f86c51065ed3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/time-event.h
+++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -162,6 +162,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
* that the vif type is NL80211_IFTYPE_P2P_DEVICE
* @duration: the requested duration in millisecond for the fw to be on the
* channel that is bound to the vif.
+ * @type: the remain on channel request type
*
* This function can be used to issue a remain on channel session,
* which means that the fw will stay in the channel for the request %duration
@@ -172,7 +173,7 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm,
* another notification to the driver.
*/
int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- int duration);
+ int duration, enum ieee80211_roc_type type);
/**
* iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index 6645efe5c03e..479074303bd7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -205,7 +205,7 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->nvm_data->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_fw_valid_tx_ant(mvm->fw),
mvm->mgmt_last_antenna_idx);
rate_flags = BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -365,7 +365,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
if (WARN_ON_ONCE(!mvmsta))
return -1;
- if (WARN_ON_ONCE(mvmsta->sta_id == IWL_INVALID_STATION))
+ if (WARN_ON_ONCE(mvmsta->sta_id == IWL_MVM_STATION_COUNT))
return -1;
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, sta, mvmsta->sta_id);
@@ -417,7 +417,7 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
spin_unlock(&mvmsta->lock);
if (mvmsta->vif->type == NL80211_IFTYPE_AP &&
- txq_id < IWL_FIRST_AMPDU_QUEUE)
+ txq_id < IWL_MVM_FIRST_AGG_QUEUE)
atomic_inc(&mvmsta->pending_frames);
return 0;
@@ -606,7 +606,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
info);
/* Single frame failure in an AMPDU queue => send BAR */
- if (txq_id >= IWL_FIRST_AMPDU_QUEUE &&
+ if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE &&
!(info->flags & IEEE80211_TX_STAT_ACK))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
@@ -619,7 +619,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
ieee80211_tx_status_ni(mvm->hw, skb);
}
- if (txq_id >= IWL_FIRST_AMPDU_QUEUE) {
+ if (txq_id >= IWL_MVM_FIRST_AGG_QUEUE) {
/* If this is an aggregation queue, we use the ssn since:
* ssn = wifi seq_num % 256.
* The seq_ctl is the sequence control of the packet to which
@@ -637,14 +637,16 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
next_reclaimed = ssn;
} else {
/* The next packet to be reclaimed is the one after this one */
- next_reclaimed = SEQ_TO_SN(seq_ctl + 0x10);
+ next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10);
}
IWL_DEBUG_TX_REPLY(mvm,
- "TXQ %d status %s (0x%08x)\n\t\t\t\tinitial_rate 0x%x "
- "retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
- txq_id, iwl_mvm_get_tx_fail_reason(status),
- status, le32_to_cpu(tx_resp->initial_rate),
+ "TXQ %d status %s (0x%08x)\n",
+ txq_id, iwl_mvm_get_tx_fail_reason(status), status);
+
+ IWL_DEBUG_TX_REPLY(mvm,
+ "\t\t\t\tinitial_rate 0x%x retries %d, idx=%d ssn=%d next_reclaimed=0x%x seq_ctl=0x%x\n",
+ le32_to_cpu(tx_resp->initial_rate),
tx_resp->failure_frame, SEQ_TO_INDEX(sequence),
ssn, next_reclaimed, seq_ctl);
@@ -681,7 +683,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
* If there are no pending frames for this STA, notify mac80211 that
* this station can go to sleep in its STA table.
*/
- if (txq_id < IWL_FIRST_AMPDU_QUEUE && mvmsta &&
+ if (txq_id < IWL_MVM_FIRST_AGG_QUEUE && mvmsta &&
!WARN_ON(skb_freed > 1) &&
mvmsta->vif->type == NL80211_IFTYPE_AP &&
atomic_sub_and_test(skb_freed, &mvmsta->pending_frames)) {
@@ -750,7 +752,7 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm,
u16 sequence = le16_to_cpu(pkt->hdr.sequence);
struct ieee80211_sta *sta;
- if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_FIRST_AMPDU_QUEUE))
+ if (WARN_ON_ONCE(SEQ_TO_QUEUE(sequence) < IWL_MVM_FIRST_AGG_QUEUE))
return;
if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS))
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 000e842c2edd..687b34e387ac 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -253,8 +253,9 @@ int iwl_mvm_rx_fw_error(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
u8 first_antenna(u8 mask)
{
BUILD_BUG_ON(ANT_A != BIT(0)); /* using ffs is wrong if not */
- WARN_ON_ONCE(!mask); /* ffs will return 0 if mask is zeroed */
- return (u8)(BIT(ffs(mask)));
+ if (WARN_ON_ONCE(!mask)) /* ffs will return 0 if mask is zeroed */
+ return BIT(0);
+ return BIT(ffs(mask) - 1);
}
/*
@@ -462,7 +463,7 @@ int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq,
.data = { lq, },
};
- if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+ if (WARN_ON(lq->sta_id == IWL_MVM_STATION_COUNT))
return -EINVAL;
if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
diff --git a/drivers/net/wireless/iwlwifi/pcie/cfg.h b/drivers/net/wireless/iwlwifi/pcie/cfg.h
deleted file mode 100644
index c6f8e83c3551..000000000000
--- a/drivers/net/wireless/iwlwifi/pcie/cfg.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license. When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
-#ifndef __iwl_pci_h__
-#define __iwl_pci_h__
-
-
-/*
- * This file declares the config structures for all devices.
- */
-
-extern const struct iwl_cfg iwl5300_agn_cfg;
-extern const struct iwl_cfg iwl5100_agn_cfg;
-extern const struct iwl_cfg iwl5350_agn_cfg;
-extern const struct iwl_cfg iwl5100_bgn_cfg;
-extern const struct iwl_cfg iwl5100_abg_cfg;
-extern const struct iwl_cfg iwl5150_agn_cfg;
-extern const struct iwl_cfg iwl5150_abg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_cfg;
-extern const struct iwl_cfg iwl6005_2abg_cfg;
-extern const struct iwl_cfg iwl6005_2bg_cfg;
-extern const struct iwl_cfg iwl6005_2agn_sff_cfg;
-extern const struct iwl_cfg iwl6005_2agn_d_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow1_cfg;
-extern const struct iwl_cfg iwl6005_2agn_mow2_cfg;
-extern const struct iwl_cfg iwl1030_bgn_cfg;
-extern const struct iwl_cfg iwl1030_bg_cfg;
-extern const struct iwl_cfg iwl6030_2agn_cfg;
-extern const struct iwl_cfg iwl6030_2abg_cfg;
-extern const struct iwl_cfg iwl6030_2bgn_cfg;
-extern const struct iwl_cfg iwl6030_2bg_cfg;
-extern const struct iwl_cfg iwl6000i_2agn_cfg;
-extern const struct iwl_cfg iwl6000i_2abg_cfg;
-extern const struct iwl_cfg iwl6000i_2bg_cfg;
-extern const struct iwl_cfg iwl6000_3agn_cfg;
-extern const struct iwl_cfg iwl6050_2agn_cfg;
-extern const struct iwl_cfg iwl6050_2abg_cfg;
-extern const struct iwl_cfg iwl6150_bgn_cfg;
-extern const struct iwl_cfg iwl6150_bg_cfg;
-extern const struct iwl_cfg iwl1000_bgn_cfg;
-extern const struct iwl_cfg iwl1000_bg_cfg;
-extern const struct iwl_cfg iwl100_bgn_cfg;
-extern const struct iwl_cfg iwl100_bg_cfg;
-extern const struct iwl_cfg iwl130_bgn_cfg;
-extern const struct iwl_cfg iwl130_bg_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_cfg;
-extern const struct iwl_cfg iwl2000_2bgn_d_cfg;
-extern const struct iwl_cfg iwl2030_2bgn_cfg;
-extern const struct iwl_cfg iwl6035_2agn_cfg;
-extern const struct iwl_cfg iwl105_bgn_cfg;
-extern const struct iwl_cfg iwl105_bgn_d_cfg;
-extern const struct iwl_cfg iwl135_bgn_cfg;
-extern const struct iwl_cfg iwl7260_2ac_cfg;
-extern const struct iwl_cfg iwl3160_ac_cfg;
-
-#endif /* __iwl_pci_h__ */
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index 7bc0fb9128dd..8cb53ec2b77b 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -69,8 +69,6 @@
#include "iwl-trans.h"
#include "iwl-drv.h"
-
-#include "cfg.h"
#include "internal.h"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -243,6 +241,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
{IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
{IWL_PCI_DEVICE(0x088E, 0x4860, iwl6035_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x088F, 0x5260, iwl6035_2agn_cfg)},
/* 105 Series */
{IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
@@ -257,6 +256,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
/* 7000 Series */
{IWL_PCI_DEVICE(0x08B1, 0x4070, iwl7260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x08B1, 0x4062, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B1, 0xC070, iwl7260_2ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x0070, iwl3160_ac_cfg)},
{IWL_PCI_DEVICE(0x08B3, 0x8070, iwl3160_ac_cfg)},
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 17bedc50e753..50ba0a468f94 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -22,7 +22,7 @@
* USA
*
* The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
+ * in the file called COPYING.
*
* Contact Information:
* Intel Linux Wireless <ilw@linux.intel.com>
@@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* If platform's RF_KILL switch is NOT set to KILL */
hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans_pcie->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
if (hw_rfkill && !run_in_rfkill)
return -ERFKILL;
@@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
int err;
@@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
iwl_enable_rfkill_int(trans);
hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans_pcie->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
return 0;
@@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
+ if (hw_rfkill)
+ set_bit(STATUS_RFKILL, &trans_pcie->status);
+ else
+ clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}
}
@@ -715,7 +728,8 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs)
static u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg)
{
- iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR,
+ ((reg & 0x000FFFFF) | (3 << 24)));
return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT);
}
@@ -723,7 +737,7 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
u32 val)
{
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR,
- ((addr & 0x0000FFFF) | (3 << 24)));
+ ((addr & 0x000FFFFF) | (3 << 24)));
iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
}
@@ -1370,28 +1384,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
return ret;
}
-static ssize_t iwl_dbgfs_fw_restart_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_trans *trans = file->private_data;
-
- if (!trans->op_mode)
- return -EAGAIN;
-
- local_bh_disable();
- iwl_op_mode_nic_error(trans->op_mode);
- local_bh_enable();
-
- return count;
-}
-
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_FILE_OPS(rx_queue);
DEBUGFS_READ_FILE_OPS(tx_queue);
DEBUGFS_WRITE_FILE_OPS(csr);
-DEBUGFS_WRITE_FILE_OPS(fw_restart);
/*
* Create the debugfs files and directories
@@ -1405,7 +1402,6 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
- DEBUGFS_ADD_FILE(fw_restart, dir, S_IWUSR);
return 0;
err:
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 8595c16f74de..c5e30294c5ac 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -501,10 +501,8 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
* shared with device */
txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
&txq->q.dma_addr, GFP_KERNEL);
- if (!txq->tfds) {
- IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+ if (!txq->tfds)
goto error;
- }
BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs));
BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) !=
@@ -1063,7 +1061,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
/* If this queue is mapped to a certain station: it is an AGG queue */
- if (sta_id != IWL_INVALID_STATION) {
+ if (sta_id >= 0) {
u16 ra_tid = BUILD_RAxTID(sta_id, tid);
/* Map receiver-address / traffic-ID to this queue */
@@ -1264,7 +1262,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
int copy = 0;
- if (!cmd->len)
+ if (!cmd->len[i])
continue;
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
@@ -1566,8 +1564,11 @@ int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
return -EIO;
- if (test_bit(STATUS_RFKILL, &trans_pcie->status))
+ if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+ IWL_DEBUG_RF_KILL(trans, "Dropping CMD 0x%x: RF KILL\n",
+ cmd->id);
return -ERFKILL;
+ }
if (cmd->flags & CMD_ASYNC)
return iwl_pcie_send_hcmd_async(trans, cmd);
@@ -1609,7 +1610,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
* Check here that the packets are in the right place on the ring.
*/
#ifdef CONFIG_IWLWIFI_DEBUG
- wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+ wifi_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
((wifi_seq & 0xff) != q->write_ptr),
"Q: %d WiFi Seq %d tfdNum %d",
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 16beaf39dc53..c94dd6802672 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -999,7 +999,6 @@ static const struct pcmcia_device_id if_cs_ids[] = {
};
MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
-
static struct pcmcia_driver lbs_driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
@@ -1007,26 +1006,4 @@ static struct pcmcia_driver lbs_driver = {
.remove = if_cs_detach,
.id_table = if_cs_ids,
};
-
-
-static int __init if_cs_init(void)
-{
- int ret;
-
- lbs_deb_enter(LBS_DEB_CS);
- ret = pcmcia_register_driver(&lbs_driver);
- lbs_deb_leave(LBS_DEB_CS);
- return ret;
-}
-
-
-static void __exit if_cs_exit(void)
-{
- lbs_deb_enter(LBS_DEB_CS);
- pcmcia_unregister_driver(&lbs_driver);
- lbs_deb_leave(LBS_DEB_CS);
-}
-
-
-module_init(if_cs_init);
-module_exit(if_cs_exit);
+module_pcmcia_driver(lbs_driver);
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 7001856241e6..088de9d25c39 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -412,9 +412,9 @@ static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_conf *conf = &hw->conf;
lbtf_deb_enter(LBTF_DEB_MACOPS);
- if (conf->channel->center_freq != priv->cur_freq) {
- priv->cur_freq = conf->channel->center_freq;
- lbtf_set_channel(priv, conf->channel->hw_value);
+ if (conf->chandef.chan->center_freq != priv->cur_freq) {
+ priv->cur_freq = conf->chandef.chan->center_freq;
+ lbtf_set_channel(priv, conf->chandef.chan->hw_value);
}
lbtf_deb_leave(LBTF_DEB_MACOPS);
return 0;
@@ -537,7 +537,7 @@ static int lbtf_op_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = priv->noise;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index cffdf4fbf161..b878a32e7a98 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -25,6 +25,7 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/ktime.h>
@@ -52,6 +53,10 @@ static bool paged_rx = false;
module_param(paged_rx, bool, 0644);
MODULE_PARM_DESC(paged_rx, "Use paged SKBs for RX instead of linear ones");
+static bool rctbl = false;
+module_param(rctbl, bool, 0444);
+MODULE_PARM_DESC(rctbl, "Handle rate control table");
+
/**
* enum hwsim_regtest - the type of regulatory tests we offer
*
@@ -717,9 +722,17 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
rx_status.flag |= RX_FLAG_MACTIME_START;
rx_status.freq = chan->center_freq;
rx_status.band = chan->band;
- rx_status.rate_idx = info->control.rates[0].idx;
- if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
- rx_status.flag |= RX_FLAG_HT;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
+ rx_status.rate_idx =
+ ieee80211_rate_get_vht_mcs(&info->control.rates[0]);
+ rx_status.vht_nss =
+ ieee80211_rate_get_vht_nss(&info->control.rates[0]);
+ rx_status.flag |= RX_FLAG_VHT;
+ } else {
+ rx_status.rate_idx = info->control.rates[0].idx;
+ if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+ rx_status.flag |= RX_FLAG_HT;
+ }
if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
rx_status.flag |= RX_FLAG_40MHZ;
if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)
@@ -886,8 +899,12 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (control->sta)
hwsim_check_sta_magic(control->sta);
- txi->rate_driver_data[0] = channel;
+ if (rctbl)
+ ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
+ txi->control.rates,
+ ARRAY_SIZE(txi->control.rates));
+ txi->rate_driver_data[0] = channel;
mac80211_hwsim_monitor_rx(hw, skb, channel);
/* wmediumd mode check */
@@ -964,6 +981,12 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
newtype, vif->addr);
hwsim_check_magic(vif);
+ /*
+ * interface may change from non-AP to AP in
+ * which case this needs to be set up again
+ */
+ vif->cab_queue = 0;
+
return 0;
}
@@ -983,6 +1006,13 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
{
u32 _pid = ACCESS_ONCE(wmediumd_portid);
+ if (rctbl) {
+ struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
+ ieee80211_get_tx_rates(txi->control.vif, NULL, skb,
+ txi->control.rates,
+ ARRAY_SIZE(txi->control.rates));
+ }
+
mac80211_hwsim_monitor_rx(hw, skb, chan);
if (_pid)
@@ -1013,6 +1043,11 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
if (skb == NULL)
return;
info = IEEE80211_SKB_CB(skb);
+ if (rctbl)
+ ieee80211_get_tx_rates(vif, NULL, skb,
+ info->control.rates,
+ ARRAY_SIZE(info->control.rates));
+
txrate = ieee80211_get_tx_rate(hw, info);
mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1056,11 +1091,13 @@ out:
return HRTIMER_NORESTART;
}
-static const char *hwsim_chantypes[] = {
- [NL80211_CHAN_NO_HT] = "noht",
- [NL80211_CHAN_HT20] = "ht20",
- [NL80211_CHAN_HT40MINUS] = "ht40-",
- [NL80211_CHAN_HT40PLUS] = "ht40+",
+static const char * const hwsim_chanwidths[] = {
+ [NL80211_CHAN_WIDTH_20_NOHT] = "noht",
+ [NL80211_CHAN_WIDTH_20] = "ht20",
+ [NL80211_CHAN_WIDTH_40] = "ht40",
+ [NL80211_CHAN_WIDTH_80] = "vht80",
+ [NL80211_CHAN_WIDTH_80P80] = "vht80p80",
+ [NL80211_CHAN_WIDTH_160] = "vht160",
};
static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
@@ -1074,18 +1111,28 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
[IEEE80211_SMPS_DYNAMIC] = "dynamic",
};
- wiphy_debug(hw->wiphy,
- "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
- __func__,
- conf->channel ? conf->channel->center_freq : 0,
- hwsim_chantypes[conf->channel_type],
- !!(conf->flags & IEEE80211_CONF_IDLE),
- !!(conf->flags & IEEE80211_CONF_PS),
- smps_modes[conf->smps_mode]);
+ if (conf->chandef.chan)
+ wiphy_debug(hw->wiphy,
+ "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
+ __func__,
+ conf->chandef.chan->center_freq,
+ conf->chandef.center_freq1,
+ conf->chandef.center_freq2,
+ hwsim_chanwidths[conf->chandef.width],
+ !!(conf->flags & IEEE80211_CONF_IDLE),
+ !!(conf->flags & IEEE80211_CONF_PS),
+ smps_modes[conf->smps_mode]);
+ else
+ wiphy_debug(hw->wiphy,
+ "%s (freq=0 idle=%d ps=%d smps=%s)\n",
+ __func__,
+ !!(conf->flags & IEEE80211_CONF_IDLE),
+ !!(conf->flags & IEEE80211_CONF_PS),
+ smps_modes[conf->smps_mode]);
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
- data->channel = conf->channel;
+ data->channel = conf->chandef.chan;
WARN_ON(data->channel && channels > 1);
@@ -1271,7 +1318,7 @@ static int mac80211_hwsim_get_survey(
return -ENOENT;
/* Current channel */
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
/*
* Magically conjured noise level --- this is only ok for simulated hardware.
@@ -1389,7 +1436,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
return 0;
}
-static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
/* Not implemented, queues only on kernel side */
}
@@ -1535,7 +1582,8 @@ static void hw_roc_done(struct work_struct *work)
static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *chan,
- int duration)
+ int duration,
+ enum ieee80211_roc_type type)
{
struct mac80211_hwsim_data *hwsim = hw->priv;
@@ -1668,6 +1716,7 @@ static void mac80211_hwsim_free(void)
debugfs_remove(data->debugfs_ps);
debugfs_remove(data->debugfs);
ieee80211_unregister_hw(data->hw);
+ device_release_driver(data->dev);
device_unregister(data->dev);
ieee80211_free_hw(data->hw);
}
@@ -1676,7 +1725,9 @@ static void mac80211_hwsim_free(void)
static struct device_driver mac80211_hwsim_driver = {
- .name = "mac80211_hwsim"
+ .name = "mac80211_hwsim",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
};
static const struct net_device_ops hwsim_netdev_ops = {
@@ -2168,9 +2219,15 @@ static int __init init_mac80211_hwsim(void)
spin_lock_init(&hwsim_radio_lock);
INIT_LIST_HEAD(&hwsim_radios);
+ err = driver_register(&mac80211_hwsim_driver);
+ if (err)
+ return err;
+
hwsim_class = class_create(THIS_MODULE, "mac80211_hwsim");
- if (IS_ERR(hwsim_class))
- return PTR_ERR(hwsim_class);
+ if (IS_ERR(hwsim_class)) {
+ err = PTR_ERR(hwsim_class);
+ goto failed_unregister_driver;
+ }
memset(addr, 0, ETH_ALEN);
addr[0] = 0x02;
@@ -2192,12 +2249,20 @@ static int __init init_mac80211_hwsim(void)
"hwsim%d", i);
if (IS_ERR(data->dev)) {
printk(KERN_DEBUG
- "mac80211_hwsim: device_create "
- "failed (%ld)\n", PTR_ERR(data->dev));
+ "mac80211_hwsim: device_create failed (%ld)\n",
+ PTR_ERR(data->dev));
err = -ENOMEM;
goto failed_drvdata;
}
data->dev->driver = &mac80211_hwsim_driver;
+ err = device_bind_driver(data->dev);
+ if (err != 0) {
+ printk(KERN_DEBUG
+ "mac80211_hwsim: device_bind_driver failed (%d)\n",
+ err);
+ goto failed_hw;
+ }
+
skb_queue_head_init(&data->pending);
SET_IEEE80211_DEV(hw, data->dev);
@@ -2240,6 +2305,8 @@ static int __init init_mac80211_hwsim(void)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_QUEUE_CONTROL;
+ if (rctbl)
+ hw->flags |= IEEE80211_HW_SUPPORTS_RC_TABLE;
hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@@ -2291,9 +2358,6 @@ static int __init init_mac80211_hwsim(void)
hw->wiphy->bands[band] = sband;
- if (channels == 1)
- continue;
-
sband->vht_cap.vht_supported = true;
sband->vht_cap.cap =
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
@@ -2499,6 +2563,8 @@ failed_drvdata:
ieee80211_free_hw(hw);
failed:
mac80211_hwsim_free();
+failed_unregister_driver:
+ driver_unregister(&mac80211_hwsim_driver);
return err;
}
module_init(init_mac80211_hwsim);
@@ -2511,5 +2577,6 @@ static void __exit exit_mac80211_hwsim(void)
mac80211_hwsim_free();
unregister_netdev(hwsim_mon);
+ driver_unregister(&mac80211_hwsim_driver);
}
module_exit(exit_mac80211_hwsim);
diff --git a/drivers/net/wireless/mwifiex/11ac.c b/drivers/net/wireless/mwifiex/11ac.c
index cf43b3c29250..5e0eec4d71c7 100644
--- a/drivers/net/wireless/mwifiex/11ac.c
+++ b/drivers/net/wireless/mwifiex/11ac.c
@@ -200,7 +200,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
/* VHT Operation IE */
if (bss_desc->bcn_vht_oper) {
- if (priv->bss_mode == HostCmd_BSS_MODE_IBSS) {
+ if (priv->bss_mode == NL80211_IFTYPE_STATION) {
vht_op = (struct mwifiex_ie_types_vht_oper *)*buffer;
memset(vht_op, 0, sizeof(*vht_op));
vht_op->header.type =
@@ -259,3 +259,44 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
return ret_len;
}
+
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg)
+{
+ struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
+ S_DS_GEN);
+ vhtcfg->action = cpu_to_le16(cmd_action);
+ vhtcfg->band_config = cfg->band_config;
+ vhtcfg->misc_config = cfg->misc_config;
+ vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
+ vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
+ vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
+
+ return 0;
+}
+
+/* This function initializes the BlockACK setup information for given
+ * mwifiex_private structure for 11ac enabled networks.
+ */
+void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv)
+{
+ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE;
+ } else {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE;
+ }
+
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/11ac.h b/drivers/net/wireless/mwifiex/11ac.h
index 80fd1ba46200..7c2c69b5b3eb 100644
--- a/drivers/net/wireless/mwifiex/11ac.h
+++ b/drivers/net/wireless/mwifiex/11ac.h
@@ -20,7 +20,24 @@
#ifndef _MWIFIEX_11AC_H_
#define _MWIFIEX_11AC_H_
+#define VHT_CFG_2GHZ BIT(0)
+#define VHT_CFG_5GHZ BIT(1)
+
+enum vht_cfg_misc_config {
+ VHT_CAP_TX_OPERATION = 1,
+ VHT_CAP_ASSOCIATION,
+ VHT_CAP_UAP_ONLY
+};
+
+#define DEFAULT_VHT_MCS_SET 0xfffa
+#define DISABLE_VHT_MCS_SET 0xffff
+
+#define VHT_BW_80_160_80P80 BIT(2)
+
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc,
u8 **buffer);
+int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action,
+ struct mwifiex_11ac_vht_cfg *cfg);
#endif /* _MWIFIEX_11AC_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 45f19716687e..41e9d25a2d8e 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -679,3 +679,25 @@ void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
return;
}
+
+/* This function initializes the BlockACK setup information for given
+ * mwifiex_private structure.
+ */
+void mwifiex_set_ba_params(struct mwifiex_private *priv)
+{
+ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE;
+ } else {
+ priv->add_ba_param.tx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size =
+ MWIFIEX_STA_AMPDU_DEF_RXWINSIZE;
+ }
+
+ return;
+}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index af8fe6352eed..a78e0651409c 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -296,19 +296,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
break;
}
if (ret != -EBUSY) {
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
- if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
- priv->wmm.packets_out[ptrindex]++;
- priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
- }
- /* Now bss_prio_cur pointer points to next node */
- adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
- list_first_entry(
- &adapter->bss_prio_tbl[priv->bss_priority]
- .bss_prio_cur->list,
- struct mwifiex_bss_prio_node, list);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
+ mwifiex_rotate_priolists(priv, pra_list, ptrindex);
}
return 0;
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index 5e796f847088..ada809f576fe 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -447,7 +447,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
del_timer(&tbl->timer_context.timer);
mod_timer(&tbl->timer_context.timer,
- jiffies + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
+ jiffies + msecs_to_jiffies(MIN_FLUSH_TIMER_MS * win_size));
/*
* If seq_num is less then starting win then ignore and drop the
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 97b245cbafd8..ecf28464367f 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -39,6 +39,7 @@ mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o
mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
+mwifiex-y += ethtool.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index a44023a7bd57..a0cb0770d319 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1374,6 +1374,18 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
}
mwifiex_set_ht_params(priv, bss_cfg, params);
+
+ if (priv->adapter->is_hw_11ac_capable) {
+ mwifiex_set_vht_params(priv, bss_cfg, params);
+ mwifiex_set_vht_width(priv, params->chandef.width,
+ priv->ap_11ac_enabled);
+ }
+
+ if (priv->ap_11ac_enabled)
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
mwifiex_set_wmm_params(priv, bss_cfg, params);
if (params->inactivity_timeout > 0) {
@@ -1654,17 +1666,13 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- int ret = 0;
-
- if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
- wiphy_err(wiphy, "received infra assoc request "
- "when station is in ibss mode\n");
- goto done;
- }
+ int ret;
- if (priv->bss_mode == NL80211_IFTYPE_AP) {
- wiphy_err(wiphy, "skip association request for AP interface\n");
- goto done;
+ if (priv->bss_mode != NL80211_IFTYPE_STATION) {
+ wiphy_err(wiphy,
+ "%s: reject infra assoc request in non-STA mode\n",
+ dev->name);
+ return -EINVAL;
}
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
@@ -1672,7 +1680,6 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0);
-done:
if (!ret) {
cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
NULL, 0, WLAN_STATUS_SUCCESS,
@@ -1892,7 +1899,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
}
}
- for (i = 0; i < request->n_channels; i++) {
+ for (i = 0; i < min_t(u32, request->n_channels,
+ MWIFIEX_USER_SCAN_CHAN_MAX); i++) {
chan = request->channels[i];
priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
priv->user_scan_cfg->chan_list[i].radio_type = chan->band;
@@ -1932,66 +1940,10 @@ static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
- u32 vht_cap = 0, cap = adapter->hw_dot_11ac_dev_cap;
vht_info->vht_supported = true;
- switch (GET_VHTCAP_MAXMPDULEN(cap)) {
- case 0x00:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
- break;
- case 0x01:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991;
- break;
- case 0x10:
- vht_cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
- break;
- default:
- dev_err(adapter->dev, "unsupported MAX MPDU len\n");
- break;
- }
-
- if (ISSUPP_11ACVHTHTCVHT(cap))
- vht_cap |= IEEE80211_VHT_CAP_HTC_VHT;
-
- if (ISSUPP_11ACVHTTXOPPS(cap))
- vht_cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS;
-
- if (ISSUPP_11ACMURXBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
-
- if (ISSUPP_11ACMUTXBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
-
- if (ISSUPP_11ACSUBEAMFORMER(cap))
- vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
-
- if (ISSUPP_11ACSUBEAMFORMEE(cap))
- vht_cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
-
- if (ISSUPP_11ACRXSTBC(cap))
- vht_cap |= IEEE80211_VHT_CAP_RXSTBC_1;
-
- if (ISSUPP_11ACTXSTBC(cap))
- vht_cap |= IEEE80211_VHT_CAP_TXSTBC;
-
- if (ISSUPP_11ACSGI160(cap))
- vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_160;
-
- if (ISSUPP_11ACSGI80(cap))
- vht_cap |= IEEE80211_VHT_CAP_SHORT_GI_80;
-
- if (ISSUPP_11ACLDPC(cap))
- vht_cap |= IEEE80211_VHT_CAP_RXLDPC;
-
- if (ISSUPP_11ACBW8080(cap))
- vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
-
- if (ISSUPP_11ACBW160(cap))
- vht_cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-
- vht_info->cap = vht_cap;
-
+ vht_info->cap = adapter->hw_dot_11ac_dev_cap;
/* Update MCS support for VHT */
vht_info->vht_mcs.rx_mcs_map = cpu_to_le16(
adapter->hw_dot_11ac_mcs_support & 0xFFFF);
@@ -2179,10 +2131,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
/* At start-up, wpa_supplicant tries to change the interface
* to NL80211_IFTYPE_STATION if it is not managed mode.
- * So, we initialize it to STA mode.
*/
- wdev->iftype = NL80211_IFTYPE_STATION;
- priv->bss_mode = NL80211_IFTYPE_STATION;
+ wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT;
/* Setting bss_type to P2P tells firmware that this interface
* is receiving P2P peers found during find phase and doing
@@ -2196,6 +2147,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_started = 0;
priv->bss_num = 0;
+ if (mwifiex_cfg80211_init_p2p_client(priv))
+ return ERR_PTR(-EFAULT);
+
break;
default:
wiphy_err(wiphy, "type not supported\n");
@@ -2235,6 +2189,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+ dev->ethtool_ops = &mwifiex_ethtool_ops;
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
@@ -2293,6 +2248,152 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
}
EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
+#ifdef CONFIG_PM
+static bool
+mwifiex_is_pattern_supported(struct cfg80211_wowlan_trig_pkt_pattern *pat,
+ s8 *byte_seq)
+{
+ int j, k, valid_byte_cnt = 0;
+ bool dont_care_byte = false;
+
+ for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
+ for (k = 0; k < 8; k++) {
+ if (pat->mask[j] & 1 << k) {
+ memcpy(byte_seq + valid_byte_cnt,
+ &pat->pattern[j * 8 + k], 1);
+ valid_byte_cnt++;
+ if (dont_care_byte)
+ return false;
+ } else {
+ if (valid_byte_cnt)
+ dont_care_byte = true;
+ }
+
+ if (valid_byte_cnt > MAX_BYTESEQ)
+ return false;
+ }
+ }
+
+ byte_seq[MAX_BYTESEQ] = valid_byte_cnt;
+
+ return true;
+}
+
+static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_ds_mef_cfg mef_cfg;
+ struct mwifiex_mef_entry *mef_entry;
+ int i, filt_num = 0, ret;
+ bool first_pat = true;
+ u8 byte_seq[MAX_BYTESEQ + 1];
+ const u8 ipv4_mc_mac[] = {0x33, 0x33};
+ const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+ if (!wowlan) {
+ dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+ return 0;
+ }
+
+ if (!priv->media_connected) {
+ dev_warn(adapter->dev,
+ "Can not configure WOWLAN in disconnected state\n");
+ return 0;
+ }
+
+ mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
+ if (!mef_entry)
+ return -ENOMEM;
+
+ memset(&mef_cfg, 0, sizeof(mef_cfg));
+ mef_cfg.num_entries = 1;
+ mef_cfg.mef_entry = mef_entry;
+ mef_entry->mode = MEF_MODE_HOST_SLEEP;
+ mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
+
+ for (i = 0; i < wowlan->n_patterns; i++) {
+ memset(byte_seq, 0, sizeof(byte_seq));
+ if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
+ byte_seq)) {
+ wiphy_err(wiphy, "Pattern not supported\n");
+ kfree(mef_entry);
+ return -EOPNOTSUPP;
+ }
+
+ if (!wowlan->patterns[i].pkt_offset) {
+ if (!(byte_seq[0] & 0x01) &&
+ (byte_seq[MAX_BYTESEQ] == 1)) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+ continue;
+ } else if (is_broadcast_ether_addr(byte_seq)) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_BROADCAST;
+ continue;
+ } else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
+ (byte_seq[MAX_BYTESEQ] == 2)) ||
+ (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
+ (byte_seq[MAX_BYTESEQ] == 3))) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_MULTICAST;
+ continue;
+ }
+ }
+
+ mef_entry->filter[filt_num].repeat = 1;
+ mef_entry->filter[filt_num].offset =
+ wowlan->patterns[i].pkt_offset;
+ memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq,
+ sizeof(byte_seq));
+ mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+
+ if (first_pat)
+ first_pat = false;
+ else
+ mef_entry->filter[filt_num].filt_action = TYPE_AND;
+
+ filt_num++;
+ }
+
+ if (wowlan->magic_pkt) {
+ mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
+ mef_entry->filter[filt_num].repeat = 16;
+ memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
+ ETH_ALEN);
+ mef_entry->filter[filt_num].byte_seq[MAX_BYTESEQ] = ETH_ALEN;
+ mef_entry->filter[filt_num].offset = 14;
+ mef_entry->filter[filt_num].filt_type = TYPE_EQ;
+ if (filt_num)
+ mef_entry->filter[filt_num].filt_action = TYPE_OR;
+ }
+
+ if (!mef_cfg.criteria)
+ mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
+ MWIFIEX_CRITERIA_UNICAST |
+ MWIFIEX_CRITERIA_MULTICAST;
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MEF_CFG,
+ HostCmd_ACT_GEN_SET, 0,
+ &mef_cfg);
+
+ kfree(mef_entry);
+ return ret;
+}
+
+static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
+{
+ return 0;
+}
+
+static void mwifiex_cfg80211_set_wakeup(struct wiphy *wiphy,
+ bool enabled)
+{
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+
+ device_set_wakeup_enable(adapter->dev, enabled);
+}
+#endif
+
/* station cfg80211 operations */
static struct cfg80211_ops mwifiex_cfg80211_ops = {
.add_virtual_intf = mwifiex_add_virtual_intf,
@@ -2321,6 +2422,11 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.change_beacon = mwifiex_cfg80211_change_beacon,
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
.set_antenna = mwifiex_cfg80211_set_antenna,
+#ifdef CONFIG_PM
+ .suspend = mwifiex_cfg80211_suspend,
+ .resume = mwifiex_cfg80211_resume,
+ .set_wakeup = mwifiex_cfg80211_set_wakeup,
+#endif
};
/*
@@ -2379,6 +2485,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy_apply_custom_regulatory(wiphy, &mwifiex_world_regdom_custom);
+#ifdef CONFIG_PM
+ wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
+ wiphy->wowlan.n_patterns = MWIFIEX_MAX_FILTERS;
+ wiphy->wowlan.pattern_min_len = 1;
+ wiphy->wowlan.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN;
+ wiphy->wowlan.max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN;
+#endif
+
wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index b5c8b962ce12..74db0d24a579 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -153,7 +153,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
" or cmd size is 0, not sending\n");
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1;
}
@@ -167,7 +167,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
"DNLD_CMD: FW in reset state, ignore cmd %#x\n",
cmd_code);
mwifiex_complete_cmd(adapter, cmd_node);
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
return -1;
}
@@ -228,7 +228,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
adapter->cmd_sent = false;
if (cmd_node->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -250,7 +250,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
/* Setup the timer after transmit command */
mod_timer(&adapter->cmd_timer,
- jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000);
+ jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
return 0;
}
@@ -632,6 +632,20 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
}
+/* This function reuses a command node. */
+void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node)
+{
+ struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
+
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+
+ atomic_dec(&adapter->cmd_pending);
+ dev_dbg(adapter->dev, "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
+ le16_to_cpu(host_cmd->command),
+ atomic_read(&adapter->cmd_pending));
+}
+
/*
* This function queues a command to the command pending queue.
*
@@ -673,7 +687,9 @@ mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
list_add(&cmd_node->list, &adapter->cmd_pending_q);
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
- dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
+ atomic_inc(&adapter->cmd_pending);
+ dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x, cmd_pending=%d\n",
+ command, atomic_read(&adapter->cmd_pending));
}
/*
@@ -783,7 +799,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
le16_to_cpu(resp->command));
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -833,7 +849,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = -1;
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -865,8 +881,7 @@ int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd->wait_q_enabled)
adapter->cmd_wait_q.status = ret;
- /* Clean up and put current command back to cmd_free_q */
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -993,7 +1008,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
mwifiex_complete_cmd(adapter, cmd_node);
cmd_node->wait_q_enabled = false;
}
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
}
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
@@ -1040,7 +1055,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
cmd_node = adapter->curr_cmd;
cmd_node->wait_q_enabled = false;
cmd_node->cmd_flag |= CMD_F_CANCELED;
- mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ mwifiex_recycle_cmd_node(adapter, cmd_node);
mwifiex_complete_cmd(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
@@ -1149,7 +1164,7 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
phs_cfg->params.hs_config.gpio,
phs_cfg->params.hs_config.gap);
}
- if (conditions != HOST_SLEEP_CFG_CANCEL) {
+ if (conditions != HS_CFG_CANCEL) {
adapter->is_hs_configured = true;
if (adapter->iface_type == MWIFIEX_USB ||
adapter->iface_type == MWIFIEX_PCIE)
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index e8a569aaa2e8..94cc09d48444 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -41,8 +41,15 @@
#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
-#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32
-#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16
+#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 16
+#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 32
+#define MWIFIEX_UAP_AMPDU_DEF_TXWINSIZE 32
+#define MWIFIEX_UAP_AMPDU_DEF_RXWINSIZE 16
+#define MWIFIEX_11AC_STA_AMPDU_DEF_TXWINSIZE 32
+#define MWIFIEX_11AC_STA_AMPDU_DEF_RXWINSIZE 48
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_TXWINSIZE 48
+#define MWIFIEX_11AC_UAP_AMPDU_DEF_RXWINSIZE 32
+
#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
#define MWIFIEX_RATE_BITMAP_MCS0 32
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
new file mode 100644
index 000000000000..bfb39908b2c6
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -0,0 +1,70 @@
+/*
+ * Marvell Wireless LAN device driver: ethtool
+ *
+ * Copyright (C) 2013, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+
+static void mwifiex_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ u32 conditions = le32_to_cpu(priv->adapter->hs_cfg.conditions);
+
+ wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY;
+
+ if (conditions == HS_CFG_COND_DEF)
+ return;
+
+ if (conditions & HS_CFG_COND_UNICAST_DATA)
+ wol->wolopts |= WAKE_UCAST;
+ if (conditions & HS_CFG_COND_MULTICAST_DATA)
+ wol->wolopts |= WAKE_MCAST;
+ if (conditions & HS_CFG_COND_BROADCAST_DATA)
+ wol->wolopts |= WAKE_BCAST;
+ if (conditions & HS_CFG_COND_MAC_EVENT)
+ wol->wolopts |= WAKE_PHY;
+}
+
+static int mwifiex_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wol)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ u32 conditions = 0;
+
+ if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
+ return -EOPNOTSUPP;
+
+ if (wol->wolopts & WAKE_UCAST)
+ conditions |= HS_CFG_COND_UNICAST_DATA;
+ if (wol->wolopts & WAKE_MCAST)
+ conditions |= HS_CFG_COND_MULTICAST_DATA;
+ if (wol->wolopts & WAKE_BCAST)
+ conditions |= HS_CFG_COND_BROADCAST_DATA;
+ if (wol->wolopts & WAKE_PHY)
+ conditions |= HS_CFG_COND_MAC_EVENT;
+ if (wol->wolopts == 0)
+ conditions |= HS_CFG_COND_DEF;
+ priv->adapter->hs_cfg.conditions = cpu_to_le32(conditions);
+
+ return 0;
+}
+
+const struct ethtool_ops mwifiex_ethtool_ops = {
+ .get_wol = mwifiex_ethtool_get_wol,
+ .set_wol = mwifiex_ethtool_set_wol,
+};
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 25acb0682c56..1f7578d553ec 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -230,40 +230,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define ISSUPP_11ACENABLED(fw_cap_info) (fw_cap_info & (BIT(13)|BIT(14)))
-#define GET_VHTCAP_MAXMPDULEN(vht_cap_info) (vht_cap_info & 0x3)
#define GET_VHTCAP_CHWDSET(vht_cap_info) ((vht_cap_info >> 2) & 0x3)
#define GET_VHTNSSMCS(mcs_mapset, nss) ((mcs_mapset >> (2 * (nss - 1))) & 0x3)
#define SET_VHTNSSMCS(mcs_mapset, nss, value) (mcs_mapset |= (value & 0x3) << \
(2 * (nss - 1)))
#define NO_NSS_SUPPORT 0x3
-/* HW_SPEC: HTC-VHT supported */
-#define ISSUPP_11ACVHTHTCVHT(Dot11acDevCap) (Dot11acDevCap & BIT(22))
-/* HW_SPEC: VHT TXOP PS support */
-#define ISSUPP_11ACVHTTXOPPS(Dot11acDevCap) (Dot11acDevCap & BIT(21))
-/* HW_SPEC: MU RX beamformee support */
-#define ISSUPP_11ACMURXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(20))
-/* HW_SPEC: MU TX beamformee support */
-#define ISSUPP_11ACMUTXBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(19))
-/* HW_SPEC: SU Beamformee support */
-#define ISSUPP_11ACSUBEAMFORMEE(Dot11acDevCap) (Dot11acDevCap & BIT(10))
-/* HW_SPEC: SU Beamformer support */
-#define ISSUPP_11ACSUBEAMFORMER(Dot11acDevCap) (Dot11acDevCap & BIT(9))
-/* HW_SPEC: Rx STBC support */
-#define ISSUPP_11ACRXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(8))
-/* HW_SPEC: Tx STBC support */
-#define ISSUPP_11ACTXSTBC(Dot11acDevCap) (Dot11acDevCap & BIT(7))
-/* HW_SPEC: Short GI support for 160MHz BW */
-#define ISSUPP_11ACSGI160(Dot11acDevCap) (Dot11acDevCap & BIT(6))
-/* HW_SPEC: Short GI support for 80MHz BW */
-#define ISSUPP_11ACSGI80(Dot11acDevCap) (Dot11acDevCap & BIT(5))
-/* HW_SPEC: LDPC coding support */
-#define ISSUPP_11ACLDPC(Dot11acDevCap) (Dot11acDevCap & BIT(4))
-/* HW_SPEC: Channel BW 20/40/80/160/80+80 MHz support */
-#define ISSUPP_11ACBW8080(Dot11acDevCap) (Dot11acDevCap & BIT(3))
-/* HW_SPEC: Channel BW 20/40/80/160 MHz support */
-#define ISSUPP_11ACBW160(Dot11acDevCap) (Dot11acDevCap & BIT(2))
-
#define GET_DEVTXMCSMAP(dev_mcs_map) (dev_mcs_map >> 16)
#define GET_DEVRXMCSMAP(dev_mcs_map) (dev_mcs_map & 0xFFFF)
@@ -300,6 +272,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
#define HostCmd_CMD_VERSION_EXT 0x0097
+#define HostCmd_CMD_MEF_CFG 0x009a
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
@@ -322,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
+#define HostCmd_CMD_11AC_CFG 0x0112
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
@@ -376,10 +350,14 @@ enum P2P_MODES {
#define HostCmd_SCAN_RADIO_TYPE_BG 0
#define HostCmd_SCAN_RADIO_TYPE_A 1
-#define HOST_SLEEP_CFG_CANCEL 0xffffffff
-#define HOST_SLEEP_CFG_COND_DEF 0x00000000
-#define HOST_SLEEP_CFG_GPIO_DEF 0xff
-#define HOST_SLEEP_CFG_GAP_DEF 0
+#define HS_CFG_CANCEL 0xffffffff
+#define HS_CFG_COND_DEF 0x00000000
+#define HS_CFG_GPIO_DEF 0xff
+#define HS_CFG_GAP_DEF 0
+#define HS_CFG_COND_BROADCAST_DATA 0x00000001
+#define HS_CFG_COND_UNICAST_DATA 0x00000002
+#define HS_CFG_COND_MAC_EVENT 0x00000004
+#define HS_CFG_COND_MULTICAST_DATA 0x00000008
#define MWIFIEX_TIMEOUT_FOR_AP_RESP 0xfffc
#define MWIFIEX_STATUS_CODE_AUTH_TIMEOUT 2
@@ -469,6 +447,23 @@ enum P2P_MODES {
#define EVENT_GET_BSS_TYPE(event_cause) \
(((event_cause) >> 24) & 0x00ff)
+#define MWIFIEX_MAX_PATTERN_LEN 20
+#define MWIFIEX_MAX_OFFSET_LEN 50
+#define STACK_NBYTES 100
+#define TYPE_DNUM 1
+#define TYPE_BYTESEQ 2
+#define MAX_OPERAND 0x40
+#define TYPE_EQ (MAX_OPERAND+1)
+#define TYPE_EQ_DNUM (MAX_OPERAND+2)
+#define TYPE_EQ_BIT (MAX_OPERAND+3)
+#define TYPE_AND (MAX_OPERAND+4)
+#define TYPE_OR (MAX_OPERAND+5)
+#define MEF_MODE_HOST_SLEEP 1
+#define MEF_ACTION_ALLOW_AND_WAKEUP_HOST 3
+#define MWIFIEX_CRITERIA_BROADCAST BIT(0)
+#define MWIFIEX_CRITERIA_UNICAST BIT(1)
+#define MWIFIEX_CRITERIA_MULTICAST BIT(3)
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -1369,6 +1364,15 @@ struct host_cmd_ds_sys_config {
u8 tlv[0];
};
+struct host_cmd_11ac_vht_cfg {
+ __le16 action;
+ u8 band_config;
+ u8 misc_config;
+ __le32 cap_info;
+ __le32 mcs_tx_set;
+ __le32 mcs_rx_set;
+} __packed;
+
struct host_cmd_tlv_akmp {
struct host_cmd_tlv tlv;
__le16 key_mgmt;
@@ -1499,6 +1503,19 @@ struct host_cmd_ds_802_11_ibss_status {
__le16 use_g_rate_protect;
} __packed;
+struct mwifiex_fw_mef_entry {
+ u8 mode;
+ u8 action;
+ __le16 exprsize;
+ u8 expr[0];
+} __packed;
+
+struct host_cmd_ds_mef_cfg {
+ __le32 criteria;
+ __le16 num_entries;
+ struct mwifiex_fw_mef_entry mef_entry[0];
+} __packed;
+
#define CONNECTION_TYPE_INFRA 0
#define CONNECTION_TYPE_ADHOC 1
#define CONNECTION_TYPE_AP 2
@@ -1603,6 +1620,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_remain_on_chan roc_cfg;
struct host_cmd_ds_p2p_mode_cfg mode_cfg;
struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
+ struct host_cmd_ds_mef_cfg mef_cfg;
struct host_cmd_ds_mac_reg_access mac_reg;
struct host_cmd_ds_bbp_reg_access bbp_reg;
struct host_cmd_ds_rf_reg_access rf_reg;
@@ -1612,6 +1630,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
+ struct host_cmd_11ac_vht_cfg vht_cfg;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 0ff4c37ab42a..9f44fda19db9 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -44,8 +44,6 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
bss_prio->priv = priv;
INIT_LIST_HEAD(&bss_prio->list);
- if (!tbl[priv->bss_priority].bss_prio_cur)
- tbl[priv->bss_priority].bss_prio_cur = bss_prio;
spin_lock_irqsave(&tbl[priv->bss_priority].bss_prio_lock, flags);
list_add_tail(&bss_prio->list, &tbl[priv->bss_priority].bss_prio_head);
@@ -318,9 +316,9 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
adapter->is_hs_configured = false;
- adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
- adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
- adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
+ adapter->hs_cfg.conditions = cpu_to_le32(HS_CFG_COND_DEF);
+ adapter->hs_cfg.gpio = HS_CFG_GPIO_DEF;
+ adapter->hs_cfg.gap = HS_CFG_GAP_DEF;
adapter->hs_activated = false;
memset(adapter->event_body, 0, sizeof(adapter->event_body));
@@ -525,7 +523,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
for (i = 0; i < adapter->priv_num; ++i) {
INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
- adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
}
@@ -533,10 +530,8 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
if (!adapter->priv[i])
continue;
priv = adapter->priv[i];
- for (j = 0; j < MAX_NUM_TID; ++j) {
+ for (j = 0; j < MAX_NUM_TID; ++j)
INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
- spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
- }
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
INIT_LIST_HEAD(&priv->sta_list);
@@ -627,42 +622,36 @@ static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
{
int i;
struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur;
+ struct mwifiex_bss_prio_node *bssprio_node, *tmp_node;
struct list_head *head;
spinlock_t *lock; /* bss priority lock */
unsigned long flags;
for (i = 0; i < adapter->priv_num; ++i) {
head = &adapter->bss_prio_tbl[i].bss_prio_head;
- cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
dev_dbg(adapter->dev, "info: delete BSS priority table,"
" bss_type = %d, bss_num = %d, i = %d,"
- " head = %p, cur = %p\n",
- priv->bss_type, priv->bss_num, i, head, *cur);
- if (*cur) {
+ " head = %p\n",
+ priv->bss_type, priv->bss_num, i, head);
+
+ {
spin_lock_irqsave(lock, flags);
if (list_empty(head)) {
spin_unlock_irqrestore(lock, flags);
continue;
}
- bssprio_node = list_first_entry(head,
- struct mwifiex_bss_prio_node, list);
- spin_unlock_irqrestore(lock, flags);
-
list_for_each_entry_safe(bssprio_node, tmp_node, head,
list) {
if (bssprio_node->priv == priv) {
dev_dbg(adapter->dev, "info: Delete "
"node %p, next = %p\n",
bssprio_node, tmp_node);
- spin_lock_irqsave(lock, flags);
list_del(&bssprio_node->list);
- spin_unlock_irqrestore(lock, flags);
kfree(bssprio_node);
}
}
- *cur = (struct mwifiex_bss_prio_node *)head;
+ spin_unlock_irqrestore(lock, flags);
}
}
}
@@ -713,7 +702,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
if (adapter->curr_cmd) {
dev_warn(adapter->dev, "curr_cmd is still in processing\n");
del_timer(&adapter->cmd_timer);
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
adapter->curr_cmd = NULL;
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index d85e6eb1f58a..7f27e45680b5 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -272,6 +272,14 @@ struct mwifiex_ds_pm_cfg {
} param;
};
+struct mwifiex_11ac_vht_cfg {
+ u8 band_config;
+ u8 misc_config;
+ u32 cap_info;
+ u32 mcs_tx_set;
+ u32 mcs_rx_set;
+};
+
struct mwifiex_ds_11n_tx_cfg {
u16 tx_htcap;
u16 tx_htinfo;
@@ -354,6 +362,29 @@ struct mwifiex_ds_misc_subsc_evt {
struct subsc_evt_cfg bcn_h_rssi_cfg;
};
+#define MAX_BYTESEQ 6 /* non-adjustable */
+#define MWIFIEX_MAX_FILTERS 10
+
+struct mwifiex_mef_filter {
+ u16 repeat;
+ u16 offset;
+ s8 byte_seq[MAX_BYTESEQ + 1];
+ u8 filt_type;
+ u8 filt_action;
+};
+
+struct mwifiex_mef_entry {
+ u8 mode;
+ u8 action;
+ struct mwifiex_mef_filter filter[MWIFIEX_MAX_FILTERS];
+};
+
+struct mwifiex_ds_mef_cfg {
+ u32 criteria;
+ u16 num_entries;
+ struct mwifiex_mef_entry *mef_entry;
+};
+
#define MWIFIEX_MAX_VSIE_LEN (256)
#define MWIFIEX_MAX_VSIE_NUM (8)
#define MWIFIEX_VSIE_MASK_CLEAR 0x00
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 2fe0ceba4400..6bcb66e6e97c 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -1295,6 +1295,14 @@ int mwifiex_associate(struct mwifiex_private *priv,
(bss_desc->bss_mode != NL80211_IFTYPE_STATION))
return -1;
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
memcpy(&current_bssid,
&priv->curr_bss_params.bss_descriptor.mac_address,
sizeof(current_bssid));
@@ -1323,6 +1331,13 @@ mwifiex_adhoc_start(struct mwifiex_private *priv,
dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
priv->curr_bss_params.band);
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
}
@@ -1356,6 +1371,14 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
return -1;
}
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
+ !bss_desc->disable_11n && !bss_desc->disable_11ac &&
+ (priv->adapter->config_bands & BAND_GAC ||
+ priv->adapter->config_bands & BAND_AAC))
+ mwifiex_set_11ac_ba_params(priv);
+ else
+ mwifiex_set_ba_params(priv);
+
dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
priv->curr_bss_params.bss_descriptor.channel);
dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 9c802ede9c3b..121443a0f2a1 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -588,10 +588,19 @@ mwifiex_tx_timeout(struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_type-num = %d-%d\n",
- jiffies, priv->bss_type, priv->bss_num);
- mwifiex_set_trans_start(dev);
priv->num_tx_timeout++;
+ priv->tx_timeout_cnt++;
+ dev_err(priv->adapter->dev,
+ "%lu : Tx timeout(#%d), bss_type-num = %d-%d\n",
+ jiffies, priv->tx_timeout_cnt, priv->bss_type, priv->bss_num);
+ mwifiex_set_trans_start(dev);
+
+ if (priv->tx_timeout_cnt > TX_TIMEOUT_THRESHOLD &&
+ priv->adapter->if_ops.card_reset) {
+ dev_err(priv->adapter->dev,
+ "tx_timeout_cnt exceeds threshold. Triggering card reset!\n");
+ priv->adapter->if_ops.card_reset(priv->adapter);
+ }
}
/*
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 7035ade9af74..4ef67fca06d3 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -130,6 +130,9 @@ enum {
#define MWIFIEX_USB_TYPE_DATA 0xBEADC0DE
#define MWIFIEX_USB_TYPE_EVENT 0xBEEFFACE
+/* Threshold for tx_timeout_cnt before we trigger a card reset */
+#define TX_TIMEOUT_THRESHOLD 6
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -210,15 +213,11 @@ struct mwifiex_ra_list_tbl {
struct mwifiex_tid_tbl {
struct list_head ra_list;
- /* spin lock for tid table */
- spinlock_t tid_tbl_lock;
- struct mwifiex_ra_list_tbl *ra_list_curr;
};
#define WMM_HIGHEST_PRIORITY 7
#define HIGH_PRIO_TID 7
#define LOW_PRIO_TID 0
-#define NO_PKT_PRIO_TID (-1)
struct mwifiex_wmm_desc {
struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -394,6 +393,8 @@ struct mwifiex_private {
u8 curr_addr[ETH_ALEN];
u8 media_connected;
u32 num_tx_timeout;
+ /* track consecutive timeout */
+ u8 tx_timeout_cnt;
struct net_device *netdev;
struct net_device_stats stats;
u16 curr_pkt_filter;
@@ -793,6 +794,8 @@ void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node);
+void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node);
void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node,
@@ -907,12 +910,20 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
void mwifiex_set_ht_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params);
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_disable);
void
mwifiex_set_wmm_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_cfg,
struct cfg80211_ap_settings *params);
+void mwifiex_set_ba_params(struct mwifiex_private *priv);
+void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
/*
* This function checks if the queuing is RA based or not.
@@ -1098,11 +1109,15 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev);
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
+int mwifiex_add_wowlan_magic_pkt_filter(struct mwifiex_adapter *adapter);
+
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_beacon_data *data);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
+extern const struct ethtool_ops mwifiex_ethtool_ops;
+
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
void mwifiex_debugfs_remove(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 5c395e2e6a2b..20c9c4c7b0b2 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -36,8 +36,6 @@ static u8 user_rmmod;
static struct mwifiex_if_ops pcie_ops;
static struct semaphore add_remove_card_sem;
-static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter);
-static int mwifiex_pcie_resume(struct pci_dev *pdev);
static int
mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
@@ -78,6 +76,82 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
return false;
}
+#ifdef CONFIG_PM
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+ int hs_actived;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ hs_actived = mwifiex_enable_hs(adapter);
+
+ /* Indicate device suspended */
+ adapter->is_suspended = true;
+
+ return 0;
+}
+
+/*
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_pcie_resume(struct pci_dev *pdev)
+{
+ struct mwifiex_adapter *adapter;
+ struct pcie_service_card *card;
+
+ if (pdev) {
+ card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+ if (!card || !card->adapter) {
+ pr_err("Card or adapter structure is not valid\n");
+ return 0;
+ }
+ } else {
+ pr_err("PCIE device is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ if (!adapter->is_suspended) {
+ dev_warn(adapter->dev, "Device already resumed\n");
+ return 0;
+ }
+
+ adapter->is_suspended = false;
+
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_ASYNC_CMD);
+
+ return 0;
+}
+#endif
+
/*
* This function probes an mwifiex device and registers it. It allocates
* the card structure, enables PCIE function number and initiates the
@@ -159,80 +233,6 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
kfree(card);
}
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not suspended, this function allocates and sends a host
- * sleep activate request to the firmware and turns off the traffic.
- */
-static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct mwifiex_adapter *adapter;
- struct pcie_service_card *card;
- int hs_actived;
-
- if (pdev) {
- card = (struct pcie_service_card *) pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
- return 0;
- }
-
- adapter = card->adapter;
-
- hs_actived = mwifiex_enable_hs(adapter);
-
- /* Indicate device suspended */
- adapter->is_suspended = true;
-
- return 0;
-}
-
-/*
- * Kernel needs to suspend all functions separately. Therefore all
- * registered functions must have drivers with suspend and resume
- * methods. Failing that the kernel simply removes the whole card.
- *
- * If already not resumed, this function turns on the traffic and
- * sends a host sleep cancel request to the firmware.
- */
-static int mwifiex_pcie_resume(struct pci_dev *pdev)
-{
- struct mwifiex_adapter *adapter;
- struct pcie_service_card *card;
-
- if (pdev) {
- card = (struct pcie_service_card *) pci_get_drvdata(pdev);
- if (!card || !card->adapter) {
- pr_err("Card or adapter structure is not valid\n");
- return 0;
- }
- } else {
- pr_err("PCIE device is not specified\n");
- return 0;
- }
-
- adapter = card->adapter;
-
- if (!adapter->is_suspended) {
- dev_warn(adapter->dev, "Device already resumed\n");
- return 0;
- }
-
- adapter->is_suspended = false;
-
- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
- MWIFIEX_ASYNC_CMD);
-
- return 0;
-}
-
static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = {
{
PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
@@ -287,18 +287,13 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
}
/*
- * This function wakes up the card.
- *
- * A host power up command is written to the card configuration
- * register to wake up the card.
+ * This function adds delay loop to ensure FW is awake before proceeding.
*/
-static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+static void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
{
int i = 0;
- struct pcie_service_card *card = adapter->card;
- const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
- while (reg->sleep_cookie && mwifiex_pcie_ok_to_access_hw(adapter)) {
+ while (mwifiex_pcie_ok_to_access_hw(adapter)) {
i++;
usleep_range(10, 20);
/* 50ms max wait */
@@ -306,16 +301,32 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
break;
}
+ return;
+}
+
+/* This function wakes up the card by reading fw_status register. */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ u32 fw_status;
+ struct pcie_service_card *card = adapter->card;
+ const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
dev_dbg(adapter->dev, "event: Wakeup device...\n");
- /* Enable interrupts or any chip access will wakeup device */
- if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) {
- dev_warn(adapter->dev, "Enable host interrupt failed\n");
+ if (reg->sleep_cookie)
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+
+ /* Reading fw_status register will wakeup device */
+ if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status)) {
+ dev_warn(adapter->dev, "Reading fw_status register failed\n");
return -1;
}
- dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
- adapter->ps_state = PS_STATE_AWAKE;
+ if (reg->sleep_cookie) {
+ mwifiex_pcie_dev_wakeup_delay(adapter);
+ dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n");
+ adapter->ps_state = PS_STATE_AWAKE;
+ }
return 0;
}
@@ -561,7 +572,7 @@ static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
if (card->rx_buf_list[i]) {
skb = card->rx_buf_list[i];
pci_unmap_single(card->dev, desc2->paddr,
- skb->len, PCI_DMA_TODEVICE);
+ skb->len, PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
}
memset(desc2, 0, sizeof(*desc2));
@@ -570,7 +581,7 @@ static void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
if (card->rx_buf_list[i]) {
skb = card->rx_buf_list[i];
pci_unmap_single(card->dev, desc->paddr,
- skb->len, PCI_DMA_TODEVICE);
+ skb->len, PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
}
memset(desc, 0, sizeof(*desc));
@@ -850,9 +861,8 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
if (card && card->cmd_buf) {
MWIFIEX_SKB_PACB(card->cmd_buf, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_SIZE_OF_CMD_BUFFER,
+ pci_unmap_single(card->dev, buf_pa, card->cmd_buf->len,
PCI_DMA_TODEVICE);
- dev_kfree_skb_any(card->cmd_buf);
}
return 0;
}
@@ -1030,8 +1040,8 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
u32 wrindx, num_tx_buffs, rx_val;
int ret;
dma_addr_t buf_pa;
- struct mwifiex_pcie_buf_desc *desc;
- struct mwifiex_pfu_buf_desc *desc2;
+ struct mwifiex_pcie_buf_desc *desc = NULL;
+ struct mwifiex_pfu_buf_desc *desc2 = NULL;
__le16 *tmp;
if (!(skb->data && skb->len)) {
@@ -1508,6 +1518,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
}
memcpy(adapter->upld_buf, skb->data,
min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
+ skb_push(skb, INTF_HEADER_LEN);
if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
PCI_DMA_FROMDEVICE))
return -1;
@@ -1561,7 +1572,7 @@ static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
skb_tmp = card->cmd_buf;
if (skb_tmp) {
MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
- pci_unmap_single(card->dev, buf_pa, MWIFIEX_UPLD_SIZE,
+ pci_unmap_single(card->dev, buf_pa, skb_tmp->len,
PCI_DMA_FROMDEVICE);
card->cmd_buf = NULL;
}
@@ -1983,12 +1994,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
}
}
} else if (!adapter->pps_uapsd_mode &&
- adapter->ps_state == PS_STATE_SLEEP) {
+ adapter->ps_state == PS_STATE_SLEEP &&
+ mwifiex_pcie_ok_to_access_hw(adapter)) {
/* Potentially for PCIe we could get other
* interrupts like shared. Don't change power
* state until cookie is set */
- if (mwifiex_pcie_ok_to_access_hw(adapter))
- adapter->ps_state = PS_STATE_AWAKE;
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_fw_try = false;
}
}
}
@@ -2111,7 +2123,8 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
}
dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);
- mwifiex_pcie_enable_host_int(adapter);
+ if (adapter->ps_state != PS_STATE_SLEEP)
+ mwifiex_pcie_enable_host_int(adapter);
return 0;
}
@@ -2280,9 +2293,9 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
if (pdev) {
pci_iounmap(pdev, card->pci_mmap);
pci_iounmap(pdev, card->pci_mmap1);
-
- pci_release_regions(pdev);
pci_disable_device(pdev);
+ pci_release_region(pdev, 2);
+ pci_release_region(pdev, 0);
pci_set_drvdata(pdev, NULL);
}
}
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index d215b4d3c51b..9cf5d8f07df8 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1393,8 +1393,10 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
queue_work(adapter->workqueue, &adapter->main_work);
/* Perform internal scan synchronously */
- if (!priv->scan_request)
+ if (!priv->scan_request) {
+ dev_dbg(adapter->dev, "wait internal scan\n");
mwifiex_wait_queue_complete(adapter, cmd_node);
+ }
} else {
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
@@ -1498,43 +1500,22 @@ static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
if (ret)
goto done;
- /* Update current bss descriptor parameters */
spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
- priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
- priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ht_cap_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_oper = NULL;
- priv->curr_bss_params.bss_descriptor.ht_info_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = NULL;
- priv->curr_bss_params.bss_descriptor.bss_co_2040_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
- priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
- priv->curr_bss_params.bss_descriptor.beacon_buf_size = 0;
- priv->curr_bss_params.bss_descriptor.bcn_vht_cap = NULL;
- priv->curr_bss_params.bss_descriptor.vht_cap_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_vht_oper = NULL;
- priv->curr_bss_params.bss_descriptor.vht_info_offset = 0;
- priv->curr_bss_params.bss_descriptor.oper_mode = NULL;
- priv->curr_bss_params.bss_descriptor.oper_mode_offset = 0;
-
- /* Disable 11ac by default. Enable it only where there
- * exist VHT_CAP IE in AP beacon
- */
- priv->curr_bss_params.bss_descriptor.disable_11ac = true;
-
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
sizeof(priv->curr_bss_params.bss_descriptor));
+
+ /* The contents of beacon_ie will be copied to its own buffer
+ * in mwifiex_save_curr_bcn()
+ */
mwifiex_save_curr_bcn(priv);
spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
done:
+ /* beacon_ie buffer was allocated in function
+ * mwifiex_fill_new_bss_desc(). Free it now.
+ */
+ kfree(bss_desc->beacon_buf);
kfree(bss_desc);
return 0;
}
@@ -1793,7 +1774,12 @@ check_next_scan:
/* Need to indicate IOCTL complete */
if (adapter->curr_cmd->wait_q_enabled) {
adapter->cmd_wait_q.status = 0;
- mwifiex_complete_cmd(adapter, adapter->curr_cmd);
+ if (!priv->scan_request) {
+ dev_dbg(adapter->dev,
+ "complete internal scan\n");
+ mwifiex_complete_cmd(adapter,
+ adapter->curr_cmd);
+ }
}
if (priv->report_scan_result)
priv->report_scan_result = false;
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index c55c5bb93134..b193e25977d2 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -24,6 +24,7 @@
#include "main.h"
#include "wmm.h"
#include "11n.h"
+#include "11ac.h"
/*
* This function prepares command to set/get RSSI information.
@@ -334,7 +335,7 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
if (!hs_activate &&
- (hscfg_param->conditions != cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) &&
+ (hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) &&
((adapter->arp_filter_size > 0) &&
(adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
dev_dbg(adapter->dev,
@@ -1059,6 +1060,80 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
return 0;
}
+static int
+mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv,
+ struct mwifiex_mef_entry *mef_entry,
+ u8 **buffer)
+{
+ struct mwifiex_mef_filter *filter = mef_entry->filter;
+ int i, byte_len;
+ u8 *stack_ptr = *buffer;
+
+ for (i = 0; i < MWIFIEX_MAX_FILTERS; i++) {
+ filter = &mef_entry->filter[i];
+ if (!filter->filt_type)
+ break;
+ *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->repeat);
+ stack_ptr += 4;
+ *stack_ptr = TYPE_DNUM;
+ stack_ptr += 1;
+
+ byte_len = filter->byte_seq[MAX_BYTESEQ];
+ memcpy(stack_ptr, filter->byte_seq, byte_len);
+ stack_ptr += byte_len;
+ *stack_ptr = byte_len;
+ stack_ptr += 1;
+ *stack_ptr = TYPE_BYTESEQ;
+ stack_ptr += 1;
+
+ *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->offset);
+ stack_ptr += 4;
+ *stack_ptr = TYPE_DNUM;
+ stack_ptr += 1;
+
+ *stack_ptr = filter->filt_type;
+ stack_ptr += 1;
+
+ if (filter->filt_action) {
+ *stack_ptr = filter->filt_action;
+ stack_ptr += 1;
+ }
+
+ if (stack_ptr - *buffer > STACK_NBYTES)
+ return -1;
+ }
+
+ *buffer = stack_ptr;
+ return 0;
+}
+
+static int
+mwifiex_cmd_mef_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ struct mwifiex_ds_mef_cfg *mef)
+{
+ struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg;
+ u8 *pos = (u8 *)mef_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG);
+
+ mef_cfg->criteria = cpu_to_le32(mef->criteria);
+ mef_cfg->num_entries = cpu_to_le16(mef->num_entries);
+ pos += sizeof(*mef_cfg);
+ mef_cfg->mef_entry->mode = mef->mef_entry->mode;
+ mef_cfg->mef_entry->action = mef->mef_entry->action;
+ pos += sizeof(*(mef_cfg->mef_entry));
+
+ if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos))
+ return -1;
+
+ mef_cfg->mef_entry->exprsize =
+ cpu_to_le16(pos - mef_cfg->mef_entry->expr);
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN);
+
+ return 0;
+}
+
/*
* This function prepares the commands before sending them to the firmware.
*
@@ -1184,6 +1259,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
S_DS_GEN);
break;
+ case HostCmd_CMD_11AC_CFG:
+ ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
cmd_ptr->command = cpu_to_le16(cmd_no);
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
@@ -1273,6 +1351,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_MEF_CFG:
+ ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 4669f8d9389f..9f990e14966e 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -95,7 +95,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
break;
}
/* Handling errors here */
- mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ mwifiex_recycle_cmd_node(adapter, adapter->curr_cmd);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->curr_cmd = NULL;
@@ -907,6 +907,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_REMAIN_ON_CHAN:
ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf);
break;
+ case HostCmd_CMD_11AC_CFG:
+ break;
case HostCmd_CMD_P2P_MODE_CFG:
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
break;
@@ -976,6 +978,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_UAP_BSS_STOP:
priv->bss_started = 0;
break;
+ case HostCmd_CMD_MEF_CFG:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 13100f8de3db..311d0b26b81c 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -59,9 +59,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
{
int status;
- dev_dbg(adapter->dev, "cmd pending\n");
- atomic_inc(&adapter->cmd_pending);
-
/* Wait for completion */
status = wait_event_interruptible(adapter->cmd_wait_q.wait,
*(cmd_queued->condition));
@@ -143,12 +140,13 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
/*
* This function fills bss descriptor structure using provided
* information.
+ * beacon_ie buffer is allocated in this function. It is caller's
+ * responsibility to free the memory.
*/
int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
struct cfg80211_bss *bss,
struct mwifiex_bssdescriptor *bss_desc)
{
- int ret;
u8 *beacon_ie;
size_t beacon_ie_len;
struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
@@ -168,6 +166,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
bss_desc->rssi = bss->signal;
+ /* The caller of this function will free beacon_ie */
bss_desc->beacon_buf = beacon_ie;
bss_desc->beacon_buf_size = beacon_ie_len;
bss_desc->beacon_period = bss->beacon_interval;
@@ -185,10 +184,12 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
else
bss_desc->bss_mode = NL80211_IFTYPE_STATION;
- ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
+ /* Disable 11ac by default. Enable it only where there
+ * exist VHT_CAP IE in AP beacon
+ */
+ bss_desc->disable_11ac = true;
- kfree(beacon_ie);
- return ret;
+ return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
}
static int mwifiex_process_country_ie(struct mwifiex_private *priv,
@@ -352,6 +353,11 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
}
done:
+ /* beacon_ie buffer was allocated in function
+ * mwifiex_fill_new_bss_desc(). Free it now.
+ */
+ if (bss_desc)
+ kfree(bss_desc->beacon_buf);
kfree(bss_desc);
return ret;
}
@@ -382,7 +388,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
break;
}
if (hs_cfg->is_invoke_hostcmd) {
- if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
+ if (hs_cfg->conditions == HS_CFG_CANCEL) {
if (!adapter->is_hs_configured)
/* Already cancelled */
break;
@@ -397,8 +403,8 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
if (hs_cfg->gap)
adapter->hs_cfg.gap = (u8)hs_cfg->gap;
- } else if (adapter->hs_cfg.conditions
- == cpu_to_le32(HOST_SLEEP_CFG_CANCEL)) {
+ } else if (adapter->hs_cfg.conditions ==
+ cpu_to_le32(HS_CFG_CANCEL)) {
/* Return failure if no parameters for HS
enable */
status = -1;
@@ -414,7 +420,7 @@ static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
HostCmd_CMD_802_11_HS_CFG_ENH,
HostCmd_ACT_GEN_SET, 0,
&adapter->hs_cfg);
- if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
+ if (hs_cfg->conditions == HS_CFG_CANCEL)
/* Restore previous condition */
adapter->hs_cfg.conditions =
cpu_to_le32(prev_cond);
@@ -448,7 +454,7 @@ int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
{
struct mwifiex_ds_hs_cfg hscfg;
- hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.conditions = HS_CFG_CANCEL;
hscfg.is_invoke_hostcmd = true;
return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 296faec14365..8f923d0d2ba6 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -169,6 +169,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
if (!status) {
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
+ if (priv->tx_timeout_cnt)
+ priv->tx_timeout_cnt = 0;
} else {
priv->stats.tx_errors++;
}
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 6e76a15a8950..b04b1db29100 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -18,6 +18,7 @@
*/
#include "main.h"
+#include "11ac.h"
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
@@ -177,6 +178,60 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
return;
}
+/* This function updates 11ac related parameters from IE
+ * and sets them into bss_config structure.
+ */
+void mwifiex_set_vht_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_ap_settings *params)
+{
+ const u8 *vht_ie;
+
+ vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
+ params->beacon.tail_len);
+ if (vht_ie) {
+ memcpy(&bss_cfg->vht_cap, vht_ie + 2,
+ sizeof(struct ieee80211_vht_cap));
+ priv->ap_11ac_enabled = 1;
+ } else {
+ priv->ap_11ac_enabled = 0;
+ }
+
+ return;
+}
+
+/* Enable VHT only when cfg80211_ap_settings has VHT IE.
+ * Otherwise disable VHT.
+ */
+void mwifiex_set_vht_width(struct mwifiex_private *priv,
+ enum nl80211_chan_width width,
+ bool ap_11ac_enable)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_11ac_vht_cfg vht_cfg;
+
+ vht_cfg.band_config = VHT_CFG_5GHZ;
+ vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
+
+ if (!ap_11ac_enable) {
+ vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
+ } else {
+ vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
+ vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
+ }
+
+ vht_cfg.misc_config = VHT_CAP_UAP_ONLY;
+
+ if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
+ vht_cfg.misc_config |= VHT_BW_80_160_80P80;
+
+ mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
+ HostCmd_ACT_GEN_SET, 0, &vht_cfg);
+
+ return;
+}
+
/* This function finds supported rates IE from beacon parameter and sets
* these rates into bss_config structure.
*/
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 21553976b550..e57ac0dd3ab5 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -195,7 +195,7 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
skb->protocol = eth_type_trans(skb, priv->netdev);
skb->ip_summed = CHECKSUM_NONE;
- /* This is required only in case of 11n and USB as we alloc
+ /* This is required only in case of 11n and USB/PCIE as we alloc
* a buffer of 4K only if its 11N (to be able to receive 4K
* AMSDU packets). In case of SD we allocate buffers based
* on the size of packet and hence this is not needed.
@@ -212,7 +212,8 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
* fragments. Currently we fail the Filesndl-ht.scr script
* for UDP, hence this fix
*/
- if ((priv->adapter->iface_type == MWIFIEX_USB) &&
+ if ((priv->adapter->iface_type == MWIFIEX_USB ||
+ priv->adapter->iface_type == MWIFIEX_PCIE) &&
(skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);
@@ -238,7 +239,6 @@ int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb)
int mwifiex_complete_cmd(struct mwifiex_adapter *adapter,
struct cmd_ctrl_node *cmd_node)
{
- atomic_dec(&adapter->cmd_pending);
dev_dbg(adapter->dev, "cmd completed: status=%d\n",
adapter->cmd_wait_q.status);
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 32adc878041d..4be3d33ceae8 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -191,9 +191,6 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
}
list_add_tail(&ra_list->list,
&priv->wmm.tid_tbl_ptr[i].ra_list);
-
- if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
- priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
}
}
@@ -424,7 +421,6 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
- priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
}
priv->aggr_prio_tbl[6].amsdu
@@ -436,10 +432,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
= priv->aggr_prio_tbl[7].ampdu_user
= BA_STREAM_NOT_ALLOWED;
- priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
- priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
- priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
-
+ mwifiex_set_ba_params(priv);
mwifiex_reset_11n_rx_seq_num(priv);
atomic_set(&priv->wmm.tx_pkts_queued, 0);
@@ -533,8 +526,6 @@ static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
}
INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list);
-
- priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
}
}
@@ -688,13 +679,13 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
ra_list->total_pkts_size += skb->len;
ra_list->pkt_count++;
- atomic_inc(&priv->wmm.tx_pkts_queued);
-
if (atomic_read(&priv->wmm.highest_queued_prio) <
tos_to_tid_inv[tid_down])
atomic_set(&priv->wmm.highest_queued_prio,
tos_to_tid_inv[tid_down]);
+ atomic_inc(&priv->wmm.tx_pkts_queued);
+
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
}
@@ -886,128 +877,65 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
struct mwifiex_private **priv, int *tid)
{
struct mwifiex_private *priv_tmp;
- struct mwifiex_ra_list_tbl *ptr, *head;
- struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
+ struct mwifiex_ra_list_tbl *ptr;
struct mwifiex_tid_tbl *tid_ptr;
atomic_t *hqp;
- int is_list_empty;
- unsigned long flags;
+ unsigned long flags_bss, flags_ra;
int i, j;
+ /* check the BSS with highest priority first */
for (j = adapter->priv_num - 1; j >= 0; --j) {
spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
- flags);
- is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
- .bss_prio_head);
- spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
- flags);
- if (is_list_empty)
- continue;
+ flags_bss);
- if (adapter->bss_prio_tbl[j].bss_prio_cur ==
- (struct mwifiex_bss_prio_node *)
- &adapter->bss_prio_tbl[j].bss_prio_head) {
- adapter->bss_prio_tbl[j].bss_prio_cur =
- list_first_entry(&adapter->bss_prio_tbl[j]
- .bss_prio_head,
- struct mwifiex_bss_prio_node,
- list);
- }
+ /* iterate over BSS with the equal priority */
+ list_for_each_entry(adapter->bss_prio_tbl[j].bss_prio_cur,
+ &adapter->bss_prio_tbl[j].bss_prio_head,
+ list) {
- bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur;
- bssprio_head = bssprio_node;
+ priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv;
- do {
- priv_tmp = bssprio_node->priv;
- hqp = &priv_tmp->wmm.highest_queued_prio;
+ if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)
+ continue;
+ /* iterate over the WMM queues of the BSS */
+ hqp = &priv_tmp->wmm.highest_queued_prio;
for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
+ spin_lock_irqsave(&priv_tmp->wmm.
+ ra_list_spinlock, flags_ra);
+
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
- /* For non-STA ra_list_curr may be NULL */
- if (!tid_ptr->ra_list_curr)
- continue;
-
- spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
- flags);
- is_list_empty =
- list_empty(&adapter->bss_prio_tbl[j]
- .bss_prio_head);
- spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
- flags);
- if (is_list_empty)
- continue;
-
- /*
- * Always choose the next ra we transmitted
- * last time, this way we pick the ra's in
- * round robin fashion.
- */
- ptr = list_first_entry(
- &tid_ptr->ra_list_curr->list,
- struct mwifiex_ra_list_tbl,
- list);
-
- head = ptr;
- if (ptr == (struct mwifiex_ra_list_tbl *)
- &tid_ptr->ra_list) {
- /* Get next ra */
- ptr = list_first_entry(&ptr->list,
- struct mwifiex_ra_list_tbl, list);
- head = ptr;
- }
-
- do {
- is_list_empty =
- skb_queue_empty(&ptr->skb_head);
+ /* iterate over receiver addresses */
+ list_for_each_entry(ptr, &tid_ptr->ra_list,
+ list) {
- if (!is_list_empty)
+ if (!skb_queue_empty(&ptr->skb_head))
+ /* holds both locks */
goto found;
+ }
- /* Get next ra */
- ptr = list_first_entry(&ptr->list,
- struct mwifiex_ra_list_tbl,
- list);
- if (ptr ==
- (struct mwifiex_ra_list_tbl *)
- &tid_ptr->ra_list)
- ptr = list_first_entry(
- &ptr->list,
- struct mwifiex_ra_list_tbl,
- list);
- } while (ptr != head);
+ spin_unlock_irqrestore(&priv_tmp->wmm.
+ ra_list_spinlock,
+ flags_ra);
}
+ }
- /* No packet at any TID for this priv. Mark as such
- * to skip checking TIDs for this priv (until pkt is
- * added).
- */
- atomic_set(hqp, NO_PKT_PRIO_TID);
-
- /* Get next bss priority node */
- bssprio_node = list_first_entry(&bssprio_node->list,
- struct mwifiex_bss_prio_node,
- list);
-
- if (bssprio_node ==
- (struct mwifiex_bss_prio_node *)
- &adapter->bss_prio_tbl[j].bss_prio_head)
- /* Get next bss priority node */
- bssprio_node = list_first_entry(
- &bssprio_node->list,
- struct mwifiex_bss_prio_node,
- list);
- } while (bssprio_node != bssprio_head);
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags_bss);
}
+
return NULL;
found:
- spin_lock_irqsave(&priv_tmp->wmm.ra_list_spinlock, flags);
+ /* holds bss_prio_lock / ra_list_spinlock */
if (atomic_read(hqp) > i)
atomic_set(hqp, i);
- spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags);
+ spin_unlock_irqrestore(&priv_tmp->wmm.ra_list_spinlock, flags_ra);
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags_bss);
*priv = priv_tmp;
*tid = tos_to_tid[i];
@@ -1015,6 +943,42 @@ found:
return ptr;
}
+/* This functions rotates ra and bss lists so packets are picked round robin.
+ *
+ * After a packet is successfully transmitted, rotate the ra list, so the ra
+ * next to the one transmitted, will come first in the list. This way we pick
+ * the ra' in a round robin fashion. Same applies to bss nodes of equal
+ * priority.
+ *
+ * Function also increments wmm.packets_out counter.
+ */
+void mwifiex_rotate_priolists(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ra,
+ int tid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bss_prio_tbl *tbl = adapter->bss_prio_tbl;
+ struct mwifiex_tid_tbl *tid_ptr = &priv->wmm.tid_tbl_ptr[tid];
+ unsigned long flags;
+
+ spin_lock_irqsave(&tbl[priv->bss_priority].bss_prio_lock, flags);
+ /*
+ * dirty trick: we remove 'head' temporarily and reinsert it after
+ * curr bss node. imagine list to stay fixed while head is moved
+ */
+ list_move(&tbl[priv->bss_priority].bss_prio_head,
+ &tbl[priv->bss_priority].bss_prio_cur->list);
+ spin_unlock_irqrestore(&tbl[priv->bss_priority].bss_prio_lock, flags);
+
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ if (mwifiex_is_ralist_valid(priv, ra, tid)) {
+ priv->wmm.packets_out[tid]++;
+ /* same as above */
+ list_move(&tid_ptr->ra_list, &ra->list);
+ }
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
/*
* This function checks if 11n aggregation is possible.
*/
@@ -1101,20 +1065,8 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
} else {
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
- if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
- priv->wmm.packets_out[ptr_index]++;
- priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
- }
- adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
- list_first_entry(
- &adapter->bss_prio_tbl[priv->bss_priority]
- .bss_prio_cur->list,
- struct mwifiex_bss_prio_node,
- list);
+ mwifiex_rotate_priolists(priv, ptr, ptr_index);
atomic_dec(&priv->wmm.tx_pkts_queued);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
}
}
@@ -1218,20 +1170,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
break;
}
if (ret != -EBUSY) {
- spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
- if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
- priv->wmm.packets_out[ptr_index]++;
- priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
- }
- adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
- list_first_entry(
- &adapter->bss_prio_tbl[priv->bss_priority]
- .bss_prio_cur->list,
- struct mwifiex_bss_prio_node,
- list);
+ mwifiex_rotate_priolists(priv, ptr, ptr_index);
atomic_dec(&priv->wmm.tx_pkts_queued);
- spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
- ra_list_flags);
}
}
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
index b92f39d8963b..644d6e0c51cc 100644
--- a/drivers/net/wireless/mwifiex/wmm.h
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -85,6 +85,9 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)
void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
struct sk_buff *skb);
void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
+void mwifiex_rotate_priolists(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ra,
+ int tid);
int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 091d9a64080a..6820fce4016b 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -193,10 +193,10 @@ struct mwl8k_priv {
struct rxd_ops *rxd_ops;
struct ieee80211_supported_band band_24;
struct ieee80211_channel channels_24[14];
- struct ieee80211_rate rates_24[14];
+ struct ieee80211_rate rates_24[13];
struct ieee80211_supported_band band_50;
struct ieee80211_channel channels_50[4];
- struct ieee80211_rate rates_50[9];
+ struct ieee80211_rate rates_50[8];
u32 ap_macids_supported;
u32 sta_macids_supported;
@@ -232,6 +232,7 @@ struct mwl8k_priv {
u16 num_mcaddrs;
u8 hw_rev;
u32 fw_rev;
+ u32 caps;
/*
* Running count of TX packets in flight, to avoid
@@ -284,6 +285,7 @@ struct mwl8k_priv {
unsigned fw_state;
char *fw_pref;
char *fw_alt;
+ bool is_8764;
struct completion firmware_loading_complete;
/* bitmap of running BSSes */
@@ -364,7 +366,6 @@ static const struct ieee80211_rate mwl8k_rates_24[] = {
{ .bitrate = 360, .hw_value = 72, },
{ .bitrate = 480, .hw_value = 96, },
{ .bitrate = 540, .hw_value = 108, },
- { .bitrate = 720, .hw_value = 144, },
};
static const struct ieee80211_channel mwl8k_channels_50[] = {
@@ -383,7 +384,6 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
{ .bitrate = 360, .hw_value = 72, },
{ .bitrate = 480, .hw_value = 96, },
{ .bitrate = 540, .hw_value = 108, },
- { .bitrate = 720, .hw_value = 144, },
};
/* Set or get info from Firmware */
@@ -600,13 +600,18 @@ mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
loops = 1000;
do {
u32 int_code;
-
- int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
- if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
- iowrite32(0, regs + MWL8K_HIU_INT_CODE);
- break;
+ if (priv->is_8764) {
+ int_code = ioread32(regs +
+ MWL8K_HIU_H2A_INTERRUPT_STATUS);
+ if (int_code == 0)
+ break;
+ } else {
+ int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
+ if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
+ iowrite32(0, regs + MWL8K_HIU_INT_CODE);
+ break;
+ }
}
-
cond_resched();
udelay(1);
} while (--loops);
@@ -724,7 +729,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
int rc;
int loops;
- if (!memcmp(fw->data, "\x01\x00\x00\x00", 4)) {
+ if (!memcmp(fw->data, "\x01\x00\x00\x00", 4) && !priv->is_8764) {
const struct firmware *helper = priv->fw_helper;
if (helper == NULL) {
@@ -743,7 +748,10 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
} else {
- rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
+ if (priv->is_8764)
+ rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
+ else
+ rc = mwl8k_load_fw_image(priv, fw->data, fw->size);
}
if (rc) {
@@ -908,9 +916,9 @@ static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv,
}
/*
- * Packet reception for 88w8366 AP firmware.
+ * Packet reception for 88w8366/88w8764 AP firmware.
*/
-struct mwl8k_rxd_8366_ap {
+struct mwl8k_rxd_ap {
__le16 pkt_len;
__u8 sq2;
__u8 rate;
@@ -928,30 +936,30 @@ struct mwl8k_rxd_8366_ap {
__u8 rx_ctrl;
} __packed;
-#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80
-#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40
-#define MWL8K_8366_AP_RATE_INFO_RATEID(x) ((x) & 0x3f)
+#define MWL8K_AP_RATE_INFO_MCS_FORMAT 0x80
+#define MWL8K_AP_RATE_INFO_40MHZ 0x40
+#define MWL8K_AP_RATE_INFO_RATEID(x) ((x) & 0x3f)
-#define MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST 0x80
+#define MWL8K_AP_RX_CTRL_OWNED_BY_HOST 0x80
-/* 8366 AP rx_status bits */
-#define MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK 0x80
-#define MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02
-#define MWL8K_8366_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04
-#define MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08
+/* 8366/8764 AP rx_status bits */
+#define MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK 0x80
+#define MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR 0xFF
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR 0x02
+#define MWL8K_AP_RXSTAT_WEP_DECRYPT_ICV_ERR 0x04
+#define MWL8K_AP_RXSTAT_TKIP_DECRYPT_ICV_ERR 0x08
-static void mwl8k_rxd_8366_ap_init(void *_rxd, dma_addr_t next_dma_addr)
+static void mwl8k_rxd_ap_init(void *_rxd, dma_addr_t next_dma_addr)
{
- struct mwl8k_rxd_8366_ap *rxd = _rxd;
+ struct mwl8k_rxd_ap *rxd = _rxd;
rxd->next_rxd_phys_addr = cpu_to_le32(next_dma_addr);
- rxd->rx_ctrl = MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST;
+ rxd->rx_ctrl = MWL8K_AP_RX_CTRL_OWNED_BY_HOST;
}
-static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
+static void mwl8k_rxd_ap_refill(void *_rxd, dma_addr_t addr, int len)
{
- struct mwl8k_rxd_8366_ap *rxd = _rxd;
+ struct mwl8k_rxd_ap *rxd = _rxd;
rxd->pkt_len = cpu_to_le16(len);
rxd->pkt_phys_addr = cpu_to_le32(addr);
@@ -960,12 +968,12 @@ static void mwl8k_rxd_8366_ap_refill(void *_rxd, dma_addr_t addr, int len)
}
static int
-mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
- __le16 *qos, s8 *noise)
+mwl8k_rxd_ap_process(void *_rxd, struct ieee80211_rx_status *status,
+ __le16 *qos, s8 *noise)
{
- struct mwl8k_rxd_8366_ap *rxd = _rxd;
+ struct mwl8k_rxd_ap *rxd = _rxd;
- if (!(rxd->rx_ctrl & MWL8K_8366_AP_RX_CTRL_OWNED_BY_HOST))
+ if (!(rxd->rx_ctrl & MWL8K_AP_RX_CTRL_OWNED_BY_HOST))
return -1;
rmb();
@@ -974,11 +982,11 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
status->signal = -rxd->rssi;
*noise = -rxd->noise_floor;
- if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
+ if (rxd->rate & MWL8K_AP_RATE_INFO_MCS_FORMAT) {
status->flag |= RX_FLAG_HT;
- if (rxd->rate & MWL8K_8366_AP_RATE_INFO_40MHZ)
+ if (rxd->rate & MWL8K_AP_RATE_INFO_40MHZ)
status->flag |= RX_FLAG_40MHZ;
- status->rate_idx = MWL8K_8366_AP_RATE_INFO_RATEID(rxd->rate);
+ status->rate_idx = MWL8K_AP_RATE_INFO_RATEID(rxd->rate);
} else {
int i;
@@ -1002,19 +1010,19 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
*qos = rxd->qos_control;
- if ((rxd->rx_status != MWL8K_8366_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
- (rxd->rx_status & MWL8K_8366_AP_RXSTAT_DECRYPT_ERR_MASK) &&
- (rxd->rx_status & MWL8K_8366_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
+ if ((rxd->rx_status != MWL8K_AP_RXSTAT_GENERAL_DECRYPT_ERR) &&
+ (rxd->rx_status & MWL8K_AP_RXSTAT_DECRYPT_ERR_MASK) &&
+ (rxd->rx_status & MWL8K_AP_RXSTAT_TKIP_DECRYPT_MIC_ERR))
status->flag |= RX_FLAG_MMIC_ERROR;
return le16_to_cpu(rxd->pkt_len);
}
-static struct rxd_ops rxd_8366_ap_ops = {
- .rxd_size = sizeof(struct mwl8k_rxd_8366_ap),
- .rxd_init = mwl8k_rxd_8366_ap_init,
- .rxd_refill = mwl8k_rxd_8366_ap_refill,
- .rxd_process = mwl8k_rxd_8366_ap_process,
+static struct rxd_ops rxd_ap_ops = {
+ .rxd_size = sizeof(struct mwl8k_rxd_ap),
+ .rxd_init = mwl8k_rxd_ap_init,
+ .rxd_refill = mwl8k_rxd_ap_refill,
+ .rxd_process = mwl8k_rxd_ap_process,
};
/*
@@ -2401,6 +2409,9 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
{
struct mwl8k_priv *priv = hw->priv;
+ if (priv->caps)
+ return;
+
if ((caps & MWL8K_CAP_2GHZ4) || !(caps & MWL8K_CAP_BAND_MASK)) {
mwl8k_setup_2ghz_band(hw);
if (caps & MWL8K_CAP_MIMO)
@@ -2412,6 +2423,8 @@ mwl8k_set_caps(struct ieee80211_hw *hw, u32 caps)
if (caps & MWL8K_CAP_MIMO)
mwl8k_set_ht_caps(hw, &priv->band_50, caps);
}
+
+ priv->caps = caps;
}
static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
@@ -2837,7 +2850,9 @@ static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
struct ieee80211_conf *conf,
unsigned short pwr)
{
- struct ieee80211_channel *channel = conf->channel;
+ struct ieee80211_channel *channel = conf->chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&conf->chandef);
struct mwl8k_cmd_tx_power *cmd;
int rc;
int i;
@@ -2857,14 +2872,14 @@ static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
cmd->channel = cpu_to_le16(channel->hw_value);
- if (conf->channel_type == NL80211_CHAN_NO_HT ||
- conf->channel_type == NL80211_CHAN_HT20) {
+ if (channel_type == NL80211_CHAN_NO_HT ||
+ channel_type == NL80211_CHAN_HT20) {
cmd->bw = cpu_to_le16(0x2);
} else {
cmd->bw = cpu_to_le16(0x4);
- if (conf->channel_type == NL80211_CHAN_HT40MINUS)
+ if (channel_type == NL80211_CHAN_HT40MINUS)
cmd->sub_ch = cpu_to_le16(0x3);
- else if (conf->channel_type == NL80211_CHAN_HT40PLUS)
+ else if (channel_type == NL80211_CHAN_HT40PLUS)
cmd->sub_ch = cpu_to_le16(0x1);
}
@@ -3008,7 +3023,9 @@ struct mwl8k_cmd_set_rf_channel {
static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
struct ieee80211_conf *conf)
{
- struct ieee80211_channel *channel = conf->channel;
+ struct ieee80211_channel *channel = conf->chandef.chan;
+ enum nl80211_channel_type channel_type =
+ cfg80211_get_chandef_type(&conf->chandef);
struct mwl8k_cmd_set_rf_channel *cmd;
int rc;
@@ -3026,12 +3043,12 @@ static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
else if (channel->band == IEEE80211_BAND_5GHZ)
cmd->channel_flags |= cpu_to_le32(0x00000004);
- if (conf->channel_type == NL80211_CHAN_NO_HT ||
- conf->channel_type == NL80211_CHAN_HT20)
+ if (channel_type == NL80211_CHAN_NO_HT ||
+ channel_type == NL80211_CHAN_HT20)
cmd->channel_flags |= cpu_to_le32(0x00000080);
- else if (conf->channel_type == NL80211_CHAN_HT40MINUS)
+ else if (channel_type == NL80211_CHAN_HT40MINUS)
cmd->channel_flags |= cpu_to_le32(0x000001900);
- else if (conf->channel_type == NL80211_CHAN_HT40PLUS)
+ else if (channel_type == NL80211_CHAN_HT40PLUS)
cmd->channel_flags |= cpu_to_le32(0x000000900);
rc = mwl8k_post_cmd(hw, &cmd->header);
@@ -3064,11 +3081,11 @@ static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
int j;
/*
- * Clear nonstandard rates 4 and 13.
+ * Clear nonstandard rate 4.
*/
mask &= 0x1fef;
- for (i = 0, j = 0; i < 14; i++) {
+ for (i = 0, j = 0; i < 13; i++) {
if (mask & (1 << i))
rates[j++] = mwl8k_rates_24[i].hw_value;
}
@@ -3950,7 +3967,7 @@ static int mwl8k_cmd_set_new_stn_add(struct ieee80211_hw *hw,
memcpy(cmd->mac_addr, sta->addr, ETH_ALEN);
cmd->stn_id = cpu_to_le16(sta->aid);
cmd->action = cpu_to_le16(MWL8K_STA_ACTION_ADD);
- if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
else
rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
@@ -4385,7 +4402,7 @@ static int mwl8k_cmd_update_stadb_add(struct ieee80211_hw *hw,
p->ht_caps = cpu_to_le16(sta->ht_cap.cap);
p->extended_ht_caps = (sta->ht_cap.ampdu_factor & 3) |
((sta->ht_cap.ampdu_density & 7) << 2);
- if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
rates = sta->supp_rates[IEEE80211_BAND_2GHZ];
else
rates = sta->supp_rates[IEEE80211_BAND_5GHZ] << 5;
@@ -4792,16 +4809,14 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
struct mwl8k_priv *priv = hw->priv;
int rc;
- if (conf->flags & IEEE80211_CONF_IDLE) {
- mwl8k_cmd_radio_disable(hw);
- return 0;
- }
-
rc = mwl8k_fw_lock(hw);
if (rc)
return rc;
- rc = mwl8k_cmd_radio_enable(hw);
+ if (conf->flags & IEEE80211_CONF_IDLE)
+ rc = mwl8k_cmd_radio_disable(hw);
+ else
+ rc = mwl8k_cmd_radio_enable(hw);
if (rc)
goto out;
@@ -4868,7 +4883,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
- if (hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ) {
ap_legacy_rates = ap->supp_rates[IEEE80211_BAND_2GHZ];
} else {
ap_legacy_rates =
@@ -4900,7 +4915,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (idx)
idx--;
- if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
rate = mwl8k_rates_24[idx].hw_value;
else
rate = mwl8k_rates_50[idx].hw_value;
@@ -4973,7 +4988,7 @@ mwl8k_bss_info_changed_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (idx)
idx--;
- if (hw->conf.channel->band == IEEE80211_BAND_2GHZ)
+ if (hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
rate = mwl8k_rates_24[idx].hw_value;
else
rate = mwl8k_rates_50[idx].hw_value;
@@ -5246,7 +5261,7 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = priv->noise;
@@ -5429,12 +5444,17 @@ enum {
MWL8363 = 0,
MWL8687,
MWL8366,
+ MWL8764,
};
#define MWL8K_8366_AP_FW_API 3
#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
+#define MWL8K_8764_AP_FW_API 1
+#define _MWL8K_8764_AP_FW(api) "mwl8k/fmimage_8764_ap-" #api ".fw"
+#define MWL8K_8764_AP_FW(api) _MWL8K_8764_AP_FW(api)
+
static struct mwl8k_device_info mwl8k_info_tbl[] = {
[MWL8363] = {
.part_name = "88w8363",
@@ -5452,7 +5472,13 @@ static struct mwl8k_device_info mwl8k_info_tbl[] = {
.fw_image_sta = "mwl8k/fmimage_8366.fw",
.fw_image_ap = MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API),
.fw_api_ap = MWL8K_8366_AP_FW_API,
- .ap_rxd_ops = &rxd_8366_ap_ops,
+ .ap_rxd_ops = &rxd_ap_ops,
+ },
+ [MWL8764] = {
+ .part_name = "88w8764",
+ .fw_image_ap = MWL8K_8764_AP_FW(MWL8K_8764_AP_FW_API),
+ .fw_api_ap = MWL8K_8764_AP_FW_API,
+ .ap_rxd_ops = &rxd_ap_ops,
},
};
@@ -5474,6 +5500,7 @@ static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
{ PCI_VDEVICE(MARVELL, 0x2a41), .driver_data = MWL8366, },
{ PCI_VDEVICE(MARVELL, 0x2a42), .driver_data = MWL8366, },
{ PCI_VDEVICE(MARVELL, 0x2a43), .driver_data = MWL8366, },
+ { PCI_VDEVICE(MARVELL, 0x2b36), .driver_data = MWL8764, },
{ },
};
MODULE_DEVICE_TABLE(pci, mwl8k_pci_id_table);
@@ -5995,6 +6022,8 @@ static int mwl8k_probe(struct pci_dev *pdev,
priv->pdev = pdev;
priv->device_info = &mwl8k_info_tbl[id->driver_data];
+ if (id->driver_data == MWL8764)
+ priv->is_8764 = true;
priv->sram = pci_iomap(pdev, 0, 0x10000);
if (priv->sram == NULL) {
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index d7dbc00bcfbe..d21d95939316 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -338,18 +338,4 @@ static struct pcmcia_driver orinoco_driver = {
.suspend = orinoco_cs_suspend,
.resume = orinoco_cs_resume,
};
-
-static int __init
-init_orinoco_cs(void)
-{
- return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_orinoco_cs(void)
-{
- pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_orinoco_cs);
-module_exit(exit_orinoco_cs);
+module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 7744f42de1ea..1f9cb55c3360 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1584,7 +1584,7 @@ static int ezusb_probe(struct usb_interface *interface,
struct ezusb_priv *upriv = NULL;
struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *ep;
- const struct firmware *fw_entry;
+ const struct firmware *fw_entry = NULL;
int retval = 0;
int i;
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 6e28ee4e9c52..e2264bc12ebf 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -318,18 +318,4 @@ static struct pcmcia_driver orinoco_driver = {
.resume = spectrum_cs_resume,
.id_table = spectrum_cs_ids,
};
-
-static int __init
-init_spectrum_cs(void)
-{
- return pcmcia_register_driver(&orinoco_driver);
-}
-
-static void __exit
-exit_spectrum_cs(void)
-{
- pcmcia_unregister_driver(&orinoco_driver);
-}
-
-module_init(init_spectrum_cs);
-module_exit(exit_spectrum_cs);
+module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 9ba85106eec0..b3879fbf5368 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -402,7 +402,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
struct p54_rssi_db_entry *rssi_data;
unsigned int i;
void *entry;
- __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+ __le16 freq = cpu_to_le16(priv->hw->conf.chandef.chan->center_freq);
skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
2 + sizeof(*iq_autocal) + sizeof(*body) +
@@ -532,7 +532,7 @@ int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
err:
wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
ieee80211_frequency_to_channel(
- priv->hw->conf.channel->center_freq));
+ priv->hw->conf.chandef.chan->center_freq));
dev_kfree_skb_any(skb);
return -EINVAL;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index aadda99989c0..067e6f2fd050 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -340,7 +340,7 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed)
* TODO: Use the LM_SCAN_TRAP to determine the current
* operating channel.
*/
- priv->curchan = priv->hw->conf.channel;
+ priv->curchan = priv->hw->conf.chandef.chan;
p54_reset_stats(priv);
WARN_ON(p54_fetch_statistics(priv));
}
@@ -480,7 +480,7 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
p54_set_edcf(priv);
}
if (changed & BSS_CHANGED_BASIC_RATES) {
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ if (dev->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
priv->basic_rate_mask = (info->basic_rates << 4);
else
priv->basic_rate_mask = info->basic_rates;
@@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv)
return total;
}
-static void p54_flush(struct ieee80211_hw *dev, bool drop)
+static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
{
struct p54_common *priv = dev->priv;
unsigned int total, i;
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 4fd49a007b51..978e7eb26567 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -396,7 +396,7 @@ static int p54spi_rx(struct p54s_priv *priv)
static irqreturn_t p54spi_interrupt(int irq, void *config)
{
struct spi_device *spi = config;
- struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
+ struct p54s_priv *priv = spi_get_drvdata(spi);
ieee80211_queue_work(priv->hw, &priv->work);
@@ -609,7 +609,7 @@ static int p54spi_probe(struct spi_device *spi)
priv = hw->priv;
priv->hw = hw;
- dev_set_drvdata(&spi->dev, priv);
+ spi_set_drvdata(spi, priv);
priv->spi = spi;
spi->bits_per_word = 16;
@@ -685,7 +685,7 @@ err_free:
static int p54spi_remove(struct spi_device *spi)
{
- struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
+ struct p54s_priv *priv = spi_get_drvdata(spi);
p54_unregister_common(priv->hw);
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 12f0a34477f2..f95de0d16216 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -354,13 +354,13 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
if (hdr->rate & 0x10)
rx_status->flag |= RX_FLAG_SHORTPRE;
- if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ if (priv->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
else
rx_status->rate_idx = rate;
rx_status->freq = freq;
- rx_status->band = priv->hw->conf.channel->band;
+ rx_status->band = priv->hw->conf.chandef.chan->band;
rx_status->antenna = hdr->antenna;
tsf32 = le32_to_cpu(hdr->tsf32);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index a6f660c01902..9b557a1bb7f8 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -144,7 +144,7 @@ static int psm;
static char *essid;
/* Default to encapsulation unless translation requested */
-static int translate = 1;
+static bool translate = 1;
static int country = USA;
@@ -178,7 +178,7 @@ module_param(hop_dwell, int, 0);
module_param(beacon_period, int, 0);
module_param(psm, int, 0);
module_param(essid, charp, 0);
-module_param(translate, int, 0);
+module_param(translate, bool, 0);
module_param(country, int, 0);
module_param(sniffer, int, 0);
module_param(bc, int, 0);
@@ -953,7 +953,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
unsigned char *data, int len)
{
__be16 proto = ((struct ethhdr *)data)->h_proto;
- if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
+ if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */
pr_debug("ray_cs translate_frame DIX II\n");
/* Copy LLC header to card buffer */
memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
@@ -1353,7 +1353,7 @@ static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- translate = *(extra); /* Set framing mode */
+ translate = !!*(extra); /* Set framing mode */
return 0;
}
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 525fd7521dff..8169a85c4498 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2,7 +2,7 @@
* Driver for RNDIS based wireless USB devices.
*
* Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
- * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
+ * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -2839,8 +2839,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
- if (info != NULL)
- kfree(info);
+ kfree(info);
priv->connected = true;
memcpy(priv->bssid, bssid, ETH_ALEN);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 2bf4efa33186..9b915d3a44be 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -20,6 +20,7 @@ if RT2X00
config RT2400PCI
tristate "Ralink rt2400 (PCI/PCMCIA) support"
depends on PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
@@ -31,6 +32,7 @@ config RT2400PCI
config RT2500PCI
tristate "Ralink rt2500 (PCI/PCMCIA) support"
depends on PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI
select EEPROM_93CX6
---help---
@@ -43,6 +45,7 @@ config RT61PCI
tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support"
depends on PCI
select RT2X00_LIB_PCI
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_ITU_T
@@ -57,6 +60,7 @@ config RT2800PCI
tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support"
depends on PCI || SOC_RT288X || SOC_RT305X
select RT2800_LIB
+ select RT2X00_LIB_MMIO
select RT2X00_LIB_PCI if PCI
select RT2X00_LIB_SOC if SOC_RT288X || SOC_RT305X
select RT2X00_LIB_FIRMWARE
@@ -169,6 +173,13 @@ config RT2800USB_RT53XX
rt2800usb driver.
Supported chips: RT5370
+config RT2800USB_RT55XX
+ bool "rt2800usb - Include support for rt55xx devices (EXPERIMENTAL)"
+ ---help---
+ This adds support for rt55xx wireless chipset family to the
+ rt2800usb driver.
+ Supported chips: RT5572
+
config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
@@ -185,6 +196,9 @@ endif
config RT2800_LIB
tristate
+config RT2X00_LIB_MMIO
+ tristate
+
config RT2X00_LIB_PCI
tristate
select RT2X00_LIB
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 349d5b8284a4..f069d8bc5b67 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -9,6 +9,7 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 221beaaa83f1..f7143733d7e9 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -34,13 +34,14 @@
#include <linux/slab.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2400pci.h"
/*
* Register access.
* All access to the CSR registers will go through the methods
- * rt2x00pci_register_read and rt2x00pci_register_write.
+ * rt2x00mmio_register_read and rt2x00mmio_register_write.
* BBP and RF register require indirect register access,
* and use the CSR registers BBPCSR and RFCSR to achieve this.
* These indirect registers work with busy bits,
@@ -51,9 +52,9 @@
* and we will print an error.
*/
#define WAIT_FOR_BBP(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
#define WAIT_FOR_RF(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -73,7 +74,7 @@ static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg);
}
mutex_unlock(&rt2x00dev->csr_mutex);
@@ -100,7 +101,7 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg);
WAIT_FOR_BBP(rt2x00dev, &reg);
}
@@ -128,7 +129,7 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RFCSR, reg);
rt2x00_rf_write(rt2x00dev, word, value);
}
@@ -140,7 +141,7 @@ static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR21, &reg);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
@@ -162,15 +163,15 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
!!eeprom->reg_chip_select);
- rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR21, reg);
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
static const struct rt2x00debug rt2400pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2x00pci_register_read,
- .write = rt2x00pci_register_write,
+ .read = rt2x00mmio_register_read,
+ .write = rt2x00mmio_register_write,
.flags = RT2X00DEBUGFS_OFFSET,
.word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
@@ -204,7 +205,7 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_VAL0);
}
@@ -217,14 +218,14 @@ static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
unsigned int enabled = brightness != LED_OFF;
u32 reg;
- rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
+ rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, &reg);
if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC)
rt2x00_set_field32(&reg, LEDCSR_LINK, enabled);
else if (led->type == LED_TYPE_ACTIVITY)
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, enabled);
- rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
+ rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg);
}
static int rt2400pci_blink_set(struct led_classdev *led_cdev,
@@ -235,10 +236,10 @@ static int rt2400pci_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg;
- rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
+ rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, *delay_off);
- rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
+ rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg);
return 0;
}
@@ -268,7 +269,7 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
* Note that the version error will always be dropped
* since there is no filter for it at this time.
*/
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
@@ -281,7 +282,7 @@ static void rt2400pci_config_filter(struct rt2x00_dev *rt2x00dev,
!(filter_flags & FIF_PROMISC_IN_BSS) &&
!rt2x00dev->intf_ap_count);
rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
}
static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -297,25 +298,26 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev,
* Enable beacon config
*/
bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
- rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
- rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg);
/*
* Enable synchronisation.
*/
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
}
if (flags & CONFIG_UPDATE_MAC)
- rt2x00pci_register_multiwrite(rt2x00dev, CSR3,
- conf->mac, sizeof(conf->mac));
+ rt2x00mmio_register_multiwrite(rt2x00dev, CSR3,
+ conf->mac, sizeof(conf->mac));
if (flags & CONFIG_UPDATE_BSSID)
- rt2x00pci_register_multiwrite(rt2x00dev, CSR5,
- conf->bssid, sizeof(conf->bssid));
+ rt2x00mmio_register_multiwrite(rt2x00dev, CSR5,
+ conf->bssid,
+ sizeof(conf->bssid));
}
static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
@@ -331,68 +333,68 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev,
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
preamble_mask = erp->short_preamble << 3;
- rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR1, &reg);
rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x1ff);
rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0x13a);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR2, &reg);
rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 10));
- rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR3, &reg);
rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 20));
- rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR4, &reg);
rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 55));
- rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR5, &reg);
rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 110));
- rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR5, reg);
}
if (changed & BSS_CHANGED_BASIC_RATES)
- rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
if (changed & BSS_CHANGED_ERP_SLOT) {
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR18, &reg);
rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR18, reg);
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR19, &reg);
rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR19, reg);
}
if (changed & BSS_CHANGED_BEACON_INT) {
- rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR12, &reg);
rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
erp->beacon_int * 16);
rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR12, reg);
}
}
@@ -496,7 +498,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* Clear false CRC during channel switch.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1);
}
static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
@@ -509,12 +511,12 @@ static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
libconf->conf->short_frame_max_tx_count);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
}
static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
@@ -526,7 +528,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
u32 reg;
if (state == STATE_SLEEP) {
- rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
(rt2x00dev->beacon_int - 20) * 16);
rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
@@ -534,14 +536,14 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
/* We must first disable autowake before it can be enabled */
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
} else {
- rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
}
rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -567,10 +569,10 @@ static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_CWMIN, cw_min);
rt2x00_set_field32(&reg, CSR11_CWMAX, cw_max);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
}
/*
@@ -585,7 +587,7 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update FCS error count from register.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &reg);
qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
/*
@@ -640,16 +642,16 @@ static void rt2400pci_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
break;
default:
break;
@@ -663,19 +665,19 @@ static void rt2400pci_kick_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_AC_VO:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_AC_VI:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_ATIM:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
default:
break;
@@ -691,21 +693,21 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
case QID_AC_VO:
case QID_AC_VI:
case QID_ATIM:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
/*
* Wait for possibly running tbtt tasklets.
@@ -722,7 +724,7 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
*/
static bool rt2400pci_get_entry_state(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word;
if (entry->queue->qid == QID_RX) {
@@ -739,7 +741,7 @@ static bool rt2400pci_get_entry_state(struct queue_entry *entry)
static void rt2400pci_clear_entry(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
@@ -765,53 +767,53 @@ static void rt2400pci_clear_entry(struct queue_entry *entry)
static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
u32 reg;
/*
* Initialize registers.
*/
- rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR2, &reg);
rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size);
rt2x00_set_field32(&reg, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit);
rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit);
rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
- rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR3, &reg);
rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg);
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR5, &reg);
rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg);
entry_priv = rt2x00dev->atim->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR4, &reg);
rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg);
entry_priv = rt2x00dev->bcn->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR6, &reg);
rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg);
- rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR1, &reg);
rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
- rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR2, &reg);
rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg);
return 0;
}
@@ -820,23 +822,23 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
- rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
- rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20);
- rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00023f20);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002);
- rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TIMECSR, &reg);
rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
- rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg);
- rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR9, &reg);
rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
(rt2x00dev->rx->data_size / 128));
- rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR9, reg);
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
@@ -845,63 +847,63 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
- rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
+ rt2x00mmio_register_write(rt2x00dev, CNT3, 0x3f080000);
- rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR0, &reg);
rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA0, 133);
rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID0, 134);
rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA1, 136);
rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID1, 135);
- rt2x00pci_register_write(rt2x00dev, ARCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR0, reg);
- rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR3, &reg);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 3); /* Tx power.*/
rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 32); /* Signal */
rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 36); /* Rssi */
rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR3, reg);
- rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY;
- rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223);
- rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00217223);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518);
- rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MACCSR2, &reg);
rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
- rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg);
- rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RALINKCSR, &reg);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 154);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 154);
- rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RALINKCSR, reg);
- rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR1, &reg);
rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
- rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR1, &reg);
rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
- rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR1, reg);
/*
* We must clear the FCS and FIFO error count.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
- rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT4, &reg);
return 0;
}
@@ -918,7 +920,7 @@ static int rt2400pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
@@ -975,8 +977,8 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR7, reg);
}
/*
@@ -985,13 +987,13 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
@@ -1024,7 +1026,7 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable power
*/
- rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0);
}
static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1038,12 +1040,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
put_to_sleep = (state != STATE_AWAKE);
- rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, PWRCSR1, &reg);
rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
- rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg);
/*
* Device is not guaranteed to be in the requested state yet.
@@ -1051,12 +1053,12 @@ static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
* device has entered the correct state.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg2);
+ rt2x00mmio_register_read(rt2x00dev, PWRCSR1, &reg2);
bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE);
rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE);
if (bbp_state == state && rf_state == state)
return 0;
- rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg);
msleep(10);
}
@@ -1091,8 +1093,8 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -1104,7 +1106,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1181,12 +1183,12 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
if (rt2x00queue_map_txskb(entry)) {
- ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+ rt2x00_err(rt2x00dev, "Fail to map beacon, aborting\n");
goto out;
}
/*
@@ -1207,7 +1209,7 @@ out:
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
}
/*
@@ -1217,7 +1219,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word0;
u32 word2;
u32 word3;
@@ -1275,7 +1277,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx)
{
struct data_queue *queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
struct queue_entry *entry;
struct txdone_entry_desc txdesc;
u32 word;
@@ -1321,9 +1323,9 @@ static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, irq_field, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -1346,11 +1348,11 @@ static void rt2400pci_txstatus_tasklet(unsigned long data)
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -1367,7 +1369,7 @@ static void rt2400pci_tbtt_tasklet(unsigned long data)
static void rt2400pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2x00pci_rxdone(rt2x00dev))
+ if (rt2x00mmio_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
@@ -1382,8 +1384,8 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
@@ -1420,9 +1422,9 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
*/
spin_lock(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
reg |= mask;
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
@@ -1441,7 +1443,7 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
u16 word;
u8 *mac;
- rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR21, &reg);
eeprom.data = rt2x00dev;
eeprom.register_read = rt2400pci_eepromregister_read;
@@ -1462,12 +1464,12 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
if (word == 0xffff) {
- ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid EEPROM data detected\n");
return -EINVAL;
}
@@ -1489,12 +1491,12 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
- rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2460, value,
rt2x00_get_field32(reg, CSR0_REVISION));
if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
return -ENODEV;
}
@@ -1634,9 +1636,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* Enable rfkill polling by setting GPIO direction of the
* rfkill switch GPIO pin correctly.
*/
- rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, GPIOCSR, &reg);
rt2x00_set_field32(&reg, GPIOCSR_DIR0, 1);
- rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg);
/*
* Initialize hw specifications.
@@ -1696,9 +1698,9 @@ static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw,
u64 tsf;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR17, &reg);
tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
- rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR16, &reg);
tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
return tsf;
@@ -1709,7 +1711,7 @@ static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
struct rt2x00_dev *rt2x00dev = hw->priv;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR15, &reg);
return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
}
@@ -1742,8 +1744,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.tbtt_tasklet = rt2400pci_tbtt_tasklet,
.rxdone_tasklet = rt2400pci_rxdone_tasklet,
.probe_hw = rt2400pci_probe_hw,
- .initialize = rt2x00pci_initialize,
- .uninitialize = rt2x00pci_uninitialize,
+ .initialize = rt2x00mmio_initialize,
+ .uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt2400pci_get_entry_state,
.clear_entry = rt2400pci_clear_entry,
.set_device_state = rt2400pci_set_device_state,
@@ -1754,7 +1756,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.start_queue = rt2400pci_start_queue,
.kick_queue = rt2400pci_kick_queue,
.stop_queue = rt2400pci_stop_queue,
- .flush_queue = rt2x00pci_flush_queue,
+ .flush_queue = rt2x00mmio_flush_queue,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
.fill_rxdone = rt2400pci_fill_rxdone,
@@ -1769,28 +1771,28 @@ static const struct data_queue_desc rt2400pci_queue_rx = {
.entry_num = 24,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2400pci_queue_tx = {
.entry_num = 24,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2400pci_queue_bcn = {
.entry_num = 1,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2400pci_queue_atim = {
.entry_num = 8,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct rt2x00_ops rt2400pci_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 39edc59e8d03..77e45b223d15 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -34,13 +34,14 @@
#include <linux/slab.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2500pci.h"
/*
* Register access.
* All access to the CSR registers will go through the methods
- * rt2x00pci_register_read and rt2x00pci_register_write.
+ * rt2x00mmio_register_read and rt2x00mmio_register_write.
* BBP and RF register require indirect register access,
* and use the CSR registers BBPCSR and RFCSR to achieve this.
* These indirect registers work with busy bits,
@@ -51,9 +52,9 @@
* and we will print an error.
*/
#define WAIT_FOR_BBP(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg))
#define WAIT_FOR_RF(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg))
static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -73,7 +74,7 @@ static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg);
}
mutex_unlock(&rt2x00dev->csr_mutex);
@@ -100,7 +101,7 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
- rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR, reg);
WAIT_FOR_BBP(rt2x00dev, &reg);
}
@@ -128,7 +129,7 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
- rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RFCSR, reg);
rt2x00_rf_write(rt2x00dev, word, value);
}
@@ -140,7 +141,7 @@ static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR21, &reg);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
@@ -162,15 +163,15 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
!!eeprom->reg_chip_select);
- rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR21, reg);
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
static const struct rt2x00debug rt2500pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2x00pci_register_read,
- .write = rt2x00pci_register_write,
+ .read = rt2x00mmio_register_read,
+ .write = rt2x00mmio_register_write,
.flags = RT2X00DEBUGFS_OFFSET,
.word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
@@ -204,7 +205,7 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_VAL0);
}
@@ -217,14 +218,14 @@ static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
unsigned int enabled = brightness != LED_OFF;
u32 reg;
- rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
+ rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, &reg);
if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC)
rt2x00_set_field32(&reg, LEDCSR_LINK, enabled);
else if (led->type == LED_TYPE_ACTIVITY)
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, enabled);
- rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
+ rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg);
}
static int rt2500pci_blink_set(struct led_classdev *led_cdev,
@@ -235,10 +236,10 @@ static int rt2500pci_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg;
- rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
+ rt2x00mmio_register_read(led->rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, *delay_off);
- rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
+ rt2x00mmio_register_write(led->rt2x00dev, LEDCSR, reg);
return 0;
}
@@ -269,7 +270,7 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
* and broadcast frames will always be accepted since
* there is no filter for it at this time.
*/
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
@@ -285,7 +286,7 @@ static void rt2500pci_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
!(filter_flags & FIF_ALLMULTI));
rt2x00_set_field32(&reg, RXCSR0_DROP_BCAST, 0);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
}
static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -302,25 +303,25 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev,
* Enable beacon config
*/
bcn_preload = PREAMBLE + GET_DURATION(IEEE80211_HEADER, 20);
- rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCNCSR1, &reg);
rt2x00_set_field32(&reg, BCNCSR1_PRELOAD, bcn_preload);
rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN, queue->cw_min);
- rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCNCSR1, reg);
/*
* Enable synchronisation.
*/
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
}
if (flags & CONFIG_UPDATE_MAC)
- rt2x00pci_register_multiwrite(rt2x00dev, CSR3,
+ rt2x00mmio_register_multiwrite(rt2x00dev, CSR3,
conf->mac, sizeof(conf->mac));
if (flags & CONFIG_UPDATE_BSSID)
- rt2x00pci_register_multiwrite(rt2x00dev, CSR5,
+ rt2x00mmio_register_multiwrite(rt2x00dev, CSR5,
conf->bssid, sizeof(conf->bssid));
}
@@ -337,68 +338,68 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev,
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
preamble_mask = erp->short_preamble << 3;
- rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR1, &reg);
rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, 0x162);
rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, 0xa2);
rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR1, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR2, &reg);
rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00);
rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 10));
- rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR2, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR3, &reg);
rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 20));
- rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR3, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR4, &reg);
rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 55));
- rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR4, reg);
- rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARCSR5, &reg);
rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
rt2x00_set_field32(&reg, ARCSR2_LENGTH,
GET_DURATION(ACK_SIZE, 110));
- rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR5, reg);
}
if (changed & BSS_CHANGED_BASIC_RATES)
- rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
+ rt2x00mmio_register_write(rt2x00dev, ARCSR1, erp->basic_rates);
if (changed & BSS_CHANGED_ERP_SLOT) {
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
- rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR18, &reg);
rt2x00_set_field32(&reg, CSR18_SIFS, erp->sifs);
rt2x00_set_field32(&reg, CSR18_PIFS, erp->pifs);
- rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR18, reg);
- rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR19, &reg);
rt2x00_set_field32(&reg, CSR19_DIFS, erp->difs);
rt2x00_set_field32(&reg, CSR19_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR19, reg);
}
if (changed & BSS_CHANGED_BEACON_INT) {
- rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR12, &reg);
rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
erp->beacon_int * 16);
rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR12, reg);
}
}
@@ -417,7 +418,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
BUG_ON(ant->rx == ANTENNA_SW_DIVERSITY ||
ant->tx == ANTENNA_SW_DIVERSITY);
- rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BBPCSR1, &reg);
rt2500pci_bbp_read(rt2x00dev, 14, &r14);
rt2500pci_bbp_read(rt2x00dev, 2, &r2);
@@ -469,7 +470,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
}
- rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR1, reg);
rt2500pci_bbp_write(rt2x00dev, 14, r14);
rt2500pci_bbp_write(rt2x00dev, 2, r2);
}
@@ -540,7 +541,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
/*
* Clear false CRC during channel switch.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &rf->rf1);
}
static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
@@ -558,12 +559,12 @@ static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_LONG_RETRY,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, CSR11_SHORT_RETRY,
libconf->conf->short_frame_max_tx_count);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
}
static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
@@ -575,7 +576,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
u32 reg;
if (state == STATE_SLEEP) {
- rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
(rt2x00dev->beacon_int - 20) * 16);
rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
@@ -583,14 +584,14 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
/* We must first disable autowake before it can be enabled */
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
} else {
- rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
- rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR20, reg);
}
rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -624,13 +625,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update FCS error count from register.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &reg);
qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
/*
* Update False CCA count from register.
*/
- rt2x00pci_register_read(rt2x00dev, CNT3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT3, &reg);
qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
}
@@ -730,16 +731,16 @@ static void rt2500pci_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
rt2x00_set_field32(&reg, CSR14_TBCN, 1);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
break;
default:
break;
@@ -753,19 +754,19 @@ static void rt2500pci_kick_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_AC_VO:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_AC_VI:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_ATIM:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
default:
break;
@@ -781,21 +782,21 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
case QID_AC_VO:
case QID_AC_VI:
case QID_ATIM:
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR0, &reg);
rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR0, reg);
break;
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR0, &reg);
rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
/*
* Wait for possibly running tbtt tasklets.
@@ -812,7 +813,7 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
*/
static bool rt2500pci_get_entry_state(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word;
if (entry->queue->qid == QID_RX) {
@@ -829,7 +830,7 @@ static bool rt2500pci_get_entry_state(struct queue_entry *entry)
static void rt2500pci_clear_entry(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
@@ -851,53 +852,53 @@ static void rt2500pci_clear_entry(struct queue_entry *entry)
static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
u32 reg;
/*
* Initialize registers.
*/
- rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR2, &reg);
rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE, rt2x00dev->tx[0].desc_size);
rt2x00_set_field32(&reg, TXCSR2_NUM_TXD, rt2x00dev->tx[1].limit);
rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM, rt2x00dev->atim->limit);
rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO, rt2x00dev->tx[0].limit);
- rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR2, reg);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR3, &reg);
rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR3, reg);
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR5, &reg);
rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR5, reg);
entry_priv = rt2x00dev->atim->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR4, &reg);
rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR4, reg);
entry_priv = rt2x00dev->bcn->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR6, &reg);
rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR6, reg);
- rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR1, &reg);
rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->limit);
- rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR1, reg);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR2, &reg);
rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR2, reg);
return 0;
}
@@ -906,30 +907,30 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
- rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
- rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002);
- rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR2, 0x00020002);
+ rt2x00mmio_register_write(rt2x00dev, PSCSR3, 0x00000002);
- rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TIMECSR, &reg);
rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
- rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TIMECSR, reg);
- rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR9, &reg);
rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
rt2x00dev->rx->data_size / 128);
- rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR9, reg);
/*
* Always use CWmin and CWmax set in descriptor.
*/
- rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR11, &reg);
rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
- rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR11, reg);
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
rt2x00_set_field32(&reg, CSR14_TSF_SYNC, 0);
rt2x00_set_field32(&reg, CSR14_TBCN, 0);
@@ -938,11 +939,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00_set_field32(&reg, CSR14_CFP_COUNT_PRELOAD, 0);
rt2x00_set_field32(&reg, CSR14_TBCM_PRELOAD, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
- rt2x00pci_register_write(rt2x00dev, CNT3, 0);
+ rt2x00mmio_register_write(rt2x00dev, CNT3, 0);
- rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXCSR8, &reg);
rt2x00_set_field32(&reg, TXCSR8_BBP_ID0, 10);
rt2x00_set_field32(&reg, TXCSR8_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXCSR8_BBP_ID1, 11);
@@ -951,30 +952,30 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXCSR8_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXCSR8_BBP_ID3, 12);
rt2x00_set_field32(&reg, TXCSR8_BBP_ID3_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXCSR8, reg);
- rt2x00pci_register_read(rt2x00dev, ARTCSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARTCSR0, &reg);
rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_1MBS, 112);
rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_2MBS, 56);
rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_5_5MBS, 20);
rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_11MBS, 10);
- rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARTCSR0, reg);
- rt2x00pci_register_read(rt2x00dev, ARTCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARTCSR1, &reg);
rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_6MBS, 45);
rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_9MBS, 37);
rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_12MBS, 33);
rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_18MBS, 29);
- rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARTCSR1, reg);
- rt2x00pci_register_read(rt2x00dev, ARTCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, ARTCSR2, &reg);
rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_24MBS, 29);
rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_36MBS, 25);
rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_48MBS, 25);
rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_54MBS, 25);
- rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, ARTCSR2, reg);
- rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RXCSR3, &reg);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 47); /* CCK Signal */
rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 51); /* Rssi */
@@ -983,9 +984,9 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, RXCSR3_BBP_ID3, 51); /* RSSI */
rt2x00_set_field32(&reg, RXCSR3_BBP_ID3_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, RXCSR3, reg);
- rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, PCICSR, &reg);
rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
@@ -993,54 +994,54 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
- rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, PCICSR, reg);
- rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
- rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00);
- rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0);
+ rt2x00mmio_register_write(rt2x00dev, GPIOCSR, 0x0000ff00);
+ rt2x00mmio_register_write(rt2x00dev, TESTCSR, 0x000000f0);
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY;
- rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223);
- rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR0, 0x00213223);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR1, 0x00235518);
- rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MACCSR2, &reg);
rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
- rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, MACCSR2, reg);
- rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RALINKCSR, &reg);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 26);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID0, 1);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 26);
rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID1, 1);
- rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RALINKCSR, reg);
- rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200);
+ rt2x00mmio_register_write(rt2x00dev, BBPCSR1, 0x82188200);
- rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020);
+ rt2x00mmio_register_write(rt2x00dev, TXACKCSR0, 0x00000020);
- rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR1, &reg);
rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
- rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR1, &reg);
rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
- rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR1, reg);
/*
* We must clear the FCS and FIFO error count.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
*/
- rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
- rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CNT4, &reg);
return 0;
}
@@ -1057,7 +1058,7 @@ static int rt2500pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
@@ -1130,8 +1131,8 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR7, reg);
}
/*
@@ -1140,13 +1141,13 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
@@ -1178,7 +1179,7 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable power
*/
- rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR0, 0);
}
static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
@@ -1192,12 +1193,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
put_to_sleep = (state != STATE_AWAKE);
- rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, PWRCSR1, &reg);
rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
- rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg);
/*
* Device is not guaranteed to be in the requested state yet.
@@ -1205,12 +1206,12 @@ static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
* device has entered the correct state.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg2);
+ rt2x00mmio_register_read(rt2x00dev, PWRCSR1, &reg2);
bbp_state = rt2x00_get_field32(reg2, PWRCSR1_BBP_CURR_STATE);
rf_state = rt2x00_get_field32(reg2, PWRCSR1_RF_CURR_STATE);
if (bbp_state == state && rf_state == state)
return 0;
- rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, PWRCSR1, reg);
msleep(10);
}
@@ -1245,8 +1246,8 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -1258,7 +1259,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1334,12 +1335,12 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR14, &reg);
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
if (rt2x00queue_map_txskb(entry)) {
- ERROR(rt2x00dev, "Fail to map beacon, aborting\n");
+ rt2x00_err(rt2x00dev, "Fail to map beacon, aborting\n");
goto out;
}
@@ -1357,7 +1358,7 @@ out:
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR14, reg);
}
/*
@@ -1366,7 +1367,7 @@ out:
static void rt2500pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word0;
u32 word2;
@@ -1404,7 +1405,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx)
{
struct data_queue *queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx);
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
struct queue_entry *entry;
struct txdone_entry_desc txdesc;
u32 word;
@@ -1450,9 +1451,9 @@ static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, irq_field, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -1475,11 +1476,11 @@ static void rt2500pci_txstatus_tasklet(unsigned long data)
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -1496,7 +1497,7 @@ static void rt2500pci_tbtt_tasklet(unsigned long data)
static void rt2500pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2x00pci_rxdone(rt2x00dev))
+ if (rt2x00mmio_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
@@ -1511,8 +1512,8 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
- rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR7, reg);
if (!reg)
return IRQ_NONE;
@@ -1549,9 +1550,9 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
*/
spin_lock(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR8, &reg);
reg |= mask;
- rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, CSR8, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
@@ -1568,7 +1569,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
u16 word;
u8 *mac;
- rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR21, &reg);
eeprom.data = rt2x00dev;
eeprom.register_read = rt2500pci_eepromregister_read;
@@ -1589,7 +1590,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1605,7 +1606,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
- EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
@@ -1614,7 +1615,7 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
- EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
@@ -1622,7 +1623,8 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
DEFAULT_RSSI_OFFSET);
rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
- EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Calibrate offset: 0x%04x\n",
+ word);
}
return 0;
@@ -1643,7 +1645,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
- rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR0, &reg);
rt2x00_set_chip(rt2x00dev, RT2560, value,
rt2x00_get_field32(reg, CSR0_REVISION));
@@ -1653,7 +1655,7 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF2525) &&
!rt2x00_rf(rt2x00dev, RF2525E) &&
!rt2x00_rf(rt2x00dev, RF5222)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
return -ENODEV;
}
@@ -1949,9 +1951,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* Enable rfkill polling by setting GPIO direction of the
* rfkill switch GPIO pin correctly.
*/
- rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, GPIOCSR, &reg);
rt2x00_set_field32(&reg, GPIOCSR_DIR0, 1);
- rt2x00pci_register_write(rt2x00dev, GPIOCSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, GPIOCSR, reg);
/*
* Initialize hw specifications.
@@ -1985,9 +1987,9 @@ static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw,
u64 tsf;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR17, &reg);
tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
- rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR16, &reg);
tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
return tsf;
@@ -1998,7 +2000,7 @@ static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
struct rt2x00_dev *rt2x00dev = hw->priv;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CSR15, &reg);
return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
}
@@ -2031,8 +2033,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.tbtt_tasklet = rt2500pci_tbtt_tasklet,
.rxdone_tasklet = rt2500pci_rxdone_tasklet,
.probe_hw = rt2500pci_probe_hw,
- .initialize = rt2x00pci_initialize,
- .uninitialize = rt2x00pci_uninitialize,
+ .initialize = rt2x00mmio_initialize,
+ .uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt2500pci_get_entry_state,
.clear_entry = rt2500pci_clear_entry,
.set_device_state = rt2500pci_set_device_state,
@@ -2043,7 +2045,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.start_queue = rt2500pci_start_queue,
.kick_queue = rt2500pci_kick_queue,
.stop_queue = rt2500pci_stop_queue,
- .flush_queue = rt2x00pci_flush_queue,
+ .flush_queue = rt2x00mmio_flush_queue,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
.fill_rxdone = rt2500pci_fill_rxdone,
@@ -2058,28 +2060,28 @@ static const struct data_queue_desc rt2500pci_queue_rx = {
.entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2500pci_queue_tx = {
.entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2500pci_queue_bcn = {
.entry_num = 1,
.data_size = MGMT_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2500pci_queue_atim = {
.entry_num = 8,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct rt2x00_ops rt2500pci_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 6b2e1e431dd2..a7f7b365eff4 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -134,8 +134,8 @@ static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "Indirect register access failed: "
- "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ rt2x00_err(rt2x00dev, "Indirect register access failed: offset=0x%.08x, value=0x%.08x\n",
+ offset, *reg);
*reg = ~0;
return 0;
@@ -916,7 +916,7 @@ static int rt2500usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
@@ -1069,8 +1069,8 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -1353,7 +1353,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1369,7 +1369,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
- EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
@@ -1378,7 +1378,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
- EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
@@ -1386,14 +1386,15 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
DEFAULT_RSSI_OFFSET);
rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
- EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Calibrate offset: 0x%04x\n",
+ word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word);
- EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune: 0x%04x\n", word);
}
/*
@@ -1408,7 +1409,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40);
rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
- EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
} else {
rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
@@ -1419,7 +1420,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48);
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
- EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
@@ -1427,7 +1428,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40);
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word);
- EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r24: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word);
@@ -1435,7 +1436,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40);
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word);
- EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r25: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word);
@@ -1443,7 +1444,7 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60);
rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d);
rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word);
- EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "BBPtune r61: 0x%04x\n", word);
}
return 0;
@@ -1468,7 +1469,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
if (((reg & 0xfff0) != 0) || ((reg & 0x0000000f) == 0)) {
- ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RT chipset detected\n");
return -ENODEV;
}
@@ -1478,7 +1479,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF2525) &&
!rt2x00_rf(rt2x00dev, RF2525E) &&
!rt2x00_rf(rt2x00dev, RF5222)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
return -ENODEV;
}
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 4db1088a847f..a7630d5ec892 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -51,6 +51,7 @@
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
* RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5592 2.4G/5G 2T2R
* RF5360 2.4G 1T1R
* RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
@@ -68,6 +69,7 @@
#define RF3320 0x000b
#define RF3322 0x000c
#define RF3053 0x000d
+#define RF5592 0x000f
#define RF3290 0x3290
#define RF5360 0x5360
#define RF5370 0x5370
@@ -88,11 +90,8 @@
#define REV_RT3390E 0x0211
#define REV_RT5390F 0x0502
#define REV_RT5390R 0x1502
+#define REV_RT5592C 0x0221
-/*
- * Signal information.
- * Default offset is required for RSSI <-> dBm conversion.
- */
#define DEFAULT_RSSI_OFFSET 120
/*
@@ -690,6 +689,12 @@
#define GPIO_SWITCH_7 FIELD32(0x00000080)
/*
+ * FIXME: where the DEBUG_INDEX name come from?
+ */
+#define MAC_DEBUG_INDEX 0x05e8
+#define MAC_DEBUG_INDEX_XTAL FIELD32(0x80000000)
+
+/*
* MAC Control/Status Registers(CSR).
* Some values are set in TU, whereas 1 TU == 1024 us.
*/
@@ -1934,6 +1939,9 @@ struct mac_iveiv_entry {
#define BBP4_BANDWIDTH FIELD8(0x18)
#define BBP4_MAC_IF_CTRL FIELD8(0x40)
+/* BBP27 */
+#define BBP27_RX_CHAIN_SEL FIELD8(0x60)
+
/*
* BBP 47: Bandwidth
*/
@@ -1948,6 +1956,20 @@ struct mac_iveiv_entry {
#define BBP49_UPDATE_FLAG FIELD8(0x01)
/*
+ * BBP 105:
+ * - bit0: detect SIG on primary channel only (on 40MHz bandwidth)
+ * - bit1: FEQ (Feed Forward Compensation) for independend streams
+ * - bit2: MLD (Maximum Likehood Detection) for 2 streams (reserved on single
+ * stream)
+ * - bit4: channel estimation updates based on remodulation of
+ * L-SIG and HT-SIG symbols
+ */
+#define BBP105_DETECT_SIG_ON_PRIMARY FIELD8(0x01)
+#define BBP105_FEQ FIELD8(0x02)
+#define BBP105_MLD FIELD8(0x04)
+#define BBP105_SIG_REMODULATION FIELD8(0x08)
+
+/*
* BBP 109
*/
#define BBP109_TX0_POWER FIELD8(0x0f)
@@ -1967,6 +1989,11 @@ struct mac_iveiv_entry {
#define BBP152_RX_DEFAULT_ANT FIELD8(0x80)
/*
+ * BBP 254: unknown
+ */
+#define BBP254_BIT7 FIELD8(0x80)
+
+/*
* RFCSR registers
* The wordsize of the RFCSR is 8 bits.
*/
@@ -2022,9 +2049,18 @@ struct mac_iveiv_entry {
#define RFCSR7_BITS67 FIELD8(0xc0)
/*
+ * RFCSR 9:
+ */
+#define RFCSR9_K FIELD8(0x0f)
+#define RFCSR9_N FIELD8(0x10)
+#define RFCSR9_UNKNOWN FIELD8(0x60)
+#define RFCSR9_MOD FIELD8(0x80)
+
+/*
* RFCSR 11:
*/
#define RFCSR11_R FIELD8(0x03)
+#define RFCSR11_MOD FIELD8(0xc0)
/*
* RFCSR 12:
@@ -2130,11 +2166,13 @@ struct mac_iveiv_entry {
* RFCSR 49:
*/
#define RFCSR49_TX FIELD8(0x3f)
+#define RFCSR49_EP FIELD8(0xc0)
/*
* RFCSR 50:
*/
#define RFCSR50_TX FIELD8(0x3f)
+#define RFCSR50_EP FIELD8(0xc0)
/*
* RF registers
@@ -2497,6 +2535,61 @@ struct mac_iveiv_entry {
#define EEPROM_BBP_REG_ID FIELD16(0xff00)
/*
+ * EEPROM IQ Calibration, unlike other entries those are byte addresses.
+ */
+
+#define EEPROM_IQ_GAIN_CAL_TX0_2G 0x130
+#define EEPROM_IQ_PHASE_CAL_TX0_2G 0x131
+#define EEPROM_IQ_GROUPDELAY_CAL_TX0_2G 0x132
+#define EEPROM_IQ_GAIN_CAL_TX1_2G 0x133
+#define EEPROM_IQ_PHASE_CAL_TX1_2G 0x134
+#define EEPROM_IQ_GROUPDELAY_CAL_TX1_2G 0x135
+#define EEPROM_IQ_GAIN_CAL_RX0_2G 0x136
+#define EEPROM_IQ_PHASE_CAL_RX0_2G 0x137
+#define EEPROM_IQ_GROUPDELAY_CAL_RX0_2G 0x138
+#define EEPROM_IQ_GAIN_CAL_RX1_2G 0x139
+#define EEPROM_IQ_PHASE_CAL_RX1_2G 0x13A
+#define EEPROM_IQ_GROUPDELAY_CAL_RX1_2G 0x13B
+#define EEPROM_RF_IQ_COMPENSATION_CONTROL 0x13C
+#define EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CONTROL 0x13D
+#define EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5G 0x144
+#define EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5G 0x145
+#define EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5G 0X146
+#define EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5G 0x147
+#define EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5G 0x148
+#define EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5G 0x149
+#define EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5G 0x14A
+#define EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5G 0x14B
+#define EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5G 0X14C
+#define EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5G 0x14D
+#define EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5G 0x14E
+#define EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5G 0x14F
+#define EEPROM_IQ_GROUPDELAY_CAL_TX0_CH36_TO_CH64_5G 0x150
+#define EEPROM_IQ_GROUPDELAY_CAL_TX1_CH36_TO_CH64_5G 0x151
+#define EEPROM_IQ_GROUPDELAY_CAL_TX0_CH100_TO_CH138_5G 0x152
+#define EEPROM_IQ_GROUPDELAY_CAL_TX1_CH100_TO_CH138_5G 0x153
+#define EEPROM_IQ_GROUPDELAY_CAL_TX0_CH140_TO_CH165_5G 0x154
+#define EEPROM_IQ_GROUPDELAY_CAL_TX1_CH140_TO_CH165_5G 0x155
+#define EEPROM_IQ_GAIN_CAL_RX0_CH36_TO_CH64_5G 0x156
+#define EEPROM_IQ_PHASE_CAL_RX0_CH36_TO_CH64_5G 0x157
+#define EEPROM_IQ_GAIN_CAL_RX0_CH100_TO_CH138_5G 0X158
+#define EEPROM_IQ_PHASE_CAL_RX0_CH100_TO_CH138_5G 0x159
+#define EEPROM_IQ_GAIN_CAL_RX0_CH140_TO_CH165_5G 0x15A
+#define EEPROM_IQ_PHASE_CAL_RX0_CH140_TO_CH165_5G 0x15B
+#define EEPROM_IQ_GAIN_CAL_RX1_CH36_TO_CH64_5G 0x15C
+#define EEPROM_IQ_PHASE_CAL_RX1_CH36_TO_CH64_5G 0x15D
+#define EEPROM_IQ_GAIN_CAL_RX1_CH100_TO_CH138_5G 0X15E
+#define EEPROM_IQ_PHASE_CAL_RX1_CH100_TO_CH138_5G 0x15F
+#define EEPROM_IQ_GAIN_CAL_RX1_CH140_TO_CH165_5G 0x160
+#define EEPROM_IQ_PHASE_CAL_RX1_CH140_TO_CH165_5G 0x161
+#define EEPROM_IQ_GROUPDELAY_CAL_RX0_CH36_TO_CH64_5G 0x162
+#define EEPROM_IQ_GROUPDELAY_CAL_RX1_CH36_TO_CH64_5G 0x163
+#define EEPROM_IQ_GROUPDELAY_CAL_RX0_CH100_TO_CH138_5G 0x164
+#define EEPROM_IQ_GROUPDELAY_CAL_RX1_CH100_TO_CH138_5G 0x165
+#define EEPROM_IQ_GROUPDELAY_CAL_RX0_CH140_TO_CH165_5G 0x166
+#define EEPROM_IQ_GROUPDELAY_CAL_RX1_CH140_TO_CH165_5G 0x167
+
+/*
* MCU mailbox commands.
* MCU_SLEEP - go to power-save mode.
* arg1: 1: save as much power as possible, 0: save less power.
@@ -2535,6 +2628,8 @@ struct mac_iveiv_entry {
#define TXWI_DESC_SIZE (4 * sizeof(__le32))
#define RXWI_DESC_SIZE (4 * sizeof(__le32))
+#define TXWI_DESC_SIZE_5592 (5 * sizeof(__le32))
+#define RXWI_DESC_SIZE_5592 (6 * sizeof(__le32))
/*
* TX WI structure
*/
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index a658b4bc7da2..b52d70c75e1a 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -80,7 +80,7 @@ static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(rt2x00dev, RF3022))
return true;
- WARNING(rt2x00dev, "Unknown RF chipset on rt305x\n");
+ rt2x00_warn(rt2x00dev, "Unknown RF chipset on rt305x\n");
return false;
}
@@ -328,7 +328,7 @@ int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev)
msleep(1);
}
- ERROR(rt2x00dev, "Unstable hardware.\n");
+ rt2x00_err(rt2x00dev, "Unstable hardware\n");
return -EBUSY;
}
EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready);
@@ -351,7 +351,7 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
msleep(10);
}
- ERROR(rt2x00dev, "WPDMA TX/RX busy [0x%08x].\n", reg);
+ rt2x00_err(rt2x00dev, "WPDMA TX/RX busy [0x%08x]\n", reg);
return -EACCES;
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
@@ -512,7 +512,7 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
}
if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "PBF system register not ready.\n");
+ rt2x00_err(rt2x00dev, "PBF system register not ready\n");
return -EBUSY;
}
@@ -527,8 +527,10 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
*/
rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
- if (rt2x00_is_usb(rt2x00dev))
+ if (rt2x00_is_usb(rt2x00dev)) {
rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+ }
msleep(1);
return 0;
@@ -540,6 +542,7 @@ void rt2800_write_tx_data(struct queue_entry *entry,
{
__le32 *txwi = rt2800_drv_get_txwi(entry);
u32 word;
+ int i;
/*
* Initialize TX Info descriptor
@@ -582,14 +585,16 @@ void rt2800_write_tx_data(struct queue_entry *entry,
rt2x00_desc_write(txwi, 1, word);
/*
- * Always write 0 to IV/EIV fields, hardware will insert the IV
- * from the IVEIV register when TXD_W3_WIV is set to 0.
+ * Always write 0 to IV/EIV fields (word 2 and 3), hardware will insert
+ * the IV from the IVEIV register when TXD_W3_WIV is set to 0.
* When TXD_W3_WIV is set to 1 it will use the IV data
* from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
* crypto entry in the registers should be used to encrypt the frame.
+ *
+ * Nulify all remaining words as well, we don't know how to program them.
*/
- _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
- _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
+ for (i = 2; i < entry->queue->winfo_size / sizeof(__le32); i++)
+ _rt2x00_desc_write(txwi, i, 0);
}
EXPORT_SYMBOL_GPL(rt2800_write_tx_data);
@@ -674,11 +679,10 @@ void rt2800_process_rxwi(struct queue_entry *entry,
* Convert descriptor AGC value to RSSI value.
*/
rxdesc->rssi = rt2800_agc_to_rssi(entry->queue->rt2x00dev, word);
-
/*
- * Remove RXWI descriptor from start of buffer.
+ * Remove RXWI descriptor from start of the buffer.
*/
- skb_pull(entry->skb, RXWI_DESC_SIZE);
+ skb_pull(entry->skb, entry->queue->winfo_size);
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
@@ -769,6 +773,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
unsigned int beacon_base;
unsigned int padding_len;
u32 orig_reg, reg;
+ const int txwi_desc_size = entry->queue->winfo_size;
/*
* Disable beaconing while we are reloading the beacon data,
@@ -782,14 +787,14 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
/*
* Add space for the TXWI in front of the skb.
*/
- memset(skb_push(entry->skb, TXWI_DESC_SIZE), 0, TXWI_DESC_SIZE);
+ memset(skb_push(entry->skb, txwi_desc_size), 0, txwi_desc_size);
/*
* Register descriptor details in skb frame descriptor.
*/
skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = entry->skb->data;
- skbdesc->desc_len = TXWI_DESC_SIZE;
+ skbdesc->desc_len = txwi_desc_size;
/*
* Add the TXWI for the beacon to the skb.
@@ -806,7 +811,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
*/
padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
if (padding_len && skb_pad(entry->skb, padding_len)) {
- ERROR(rt2x00dev, "Failure padding beacon, aborting\n");
+ rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
@@ -835,13 +840,14 @@ static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
unsigned int beacon_base)
{
int i;
+ const int txwi_desc_size = rt2x00dev->ops->bcn->winfo_size;
/*
* For the Beacon base registers we only need to clear
* the whole TXWI which (when set to 0) will invalidate
* the entire beacon.
*/
- for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32))
+ for (i = 0; i < txwi_desc_size; i += sizeof(__le32))
rt2800_register_write(rt2x00dev, beacon_base + i, 0);
}
@@ -1988,8 +1994,21 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
}
#define POWER_BOUND 0x27
+#define POWER_BOUND_5G 0x2b
#define FREQ_OFFSET_BOUND 0x5f
+static void rt2800_adjust_freq_offset(struct rt2x00_dev *rt2x00dev)
+{
+ u8 rfcsr;
+
+ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+ if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
+ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+}
+
static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
struct rf_channel *rf,
@@ -2010,12 +2029,7 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
- rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
- if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
- else
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
- rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+ rt2800_adjust_freq_offset(rt2x00dev);
if (rf->channel <= 14) {
if (rf->channel == 6)
@@ -2056,13 +2070,7 @@ static void rt2800_config_channel_rf3322(struct rt2x00_dev *rt2x00dev,
else
rt2800_rfcsr_write(rt2x00dev, 48, info->default_power2);
- rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
- if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
- else
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
-
- rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+ rt2800_adjust_freq_offset(rt2x00dev);
rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
@@ -2127,12 +2135,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
- rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
- if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND)
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND);
- else
- rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
- rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+ rt2800_adjust_freq_offset(rt2x00dev);
if (rf->channel <= 14) {
int idx = rf->channel-1;
@@ -2184,6 +2187,382 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
}
}
+static void rt2800_config_channel_rf55xx(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf,
+ struct rf_channel *rf,
+ struct channel_info *info)
+{
+ u8 rfcsr, ep_reg;
+ u32 reg;
+ int power_bound;
+
+ /* TODO */
+ const bool is_11b = false;
+ const bool is_type_ep = false;
+
+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL,
+ (rf->channel > 14 || conf_is_ht40(conf)) ? 5 : 0);
+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+
+ /* Order of values on rf_channel entry: N, K, mod, R */
+ rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1 & 0xff);
+
+ rt2800_rfcsr_read(rt2x00dev, 9, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR9_K, rf->rf2 & 0xf);
+ rt2x00_set_field8(&rfcsr, RFCSR9_N, (rf->rf1 & 0x100) >> 8);
+ rt2x00_set_field8(&rfcsr, RFCSR9_MOD, ((rf->rf3 - 8) & 0x4) >> 2);
+ rt2800_rfcsr_write(rt2x00dev, 9, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf4 - 1);
+ rt2x00_set_field8(&rfcsr, RFCSR11_MOD, (rf->rf3 - 8) & 0x3);
+ rt2800_rfcsr_write(rt2x00dev, 11, rfcsr);
+
+ if (rf->channel <= 14) {
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x90);
+ /* FIXME: RF11 owerwrite ? */
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x4A);
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x52);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x4A);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x89);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1B);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x0D);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0x9B);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xD5);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x72);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x0E);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0xA2);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x6B);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 51, 0x3E);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x48);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0x38);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xA1);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x39);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
+
+ /* TODO RF27 <- tssi */
+
+ rfcsr = rf->channel <= 10 ? 0x07 : 0x06;
+ rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
+ rt2800_rfcsr_write(rt2x00dev, 59, rfcsr);
+
+ if (is_11b) {
+ /* CCK */
+ rt2800_rfcsr_write(rt2x00dev, 31, 0xF8);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0xC0);
+ if (is_type_ep)
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x06);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x47);
+ } else {
+ /* OFDM */
+ if (is_type_ep)
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x03);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x43);
+ }
+
+ power_bound = POWER_BOUND;
+ ep_reg = 0x2;
+ } else {
+ rt2800_rfcsr_write(rt2x00dev, 10, 0x97);
+ /* FIMXE: RF11 overwrite */
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x40);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0xBF);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 36, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 37, 0x04);
+ rt2800_rfcsr_write(rt2x00dev, 38, 0x85);
+ rt2800_rfcsr_write(rt2x00dev, 40, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 41, 0xBB);
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xD7);
+ rt2800_rfcsr_write(rt2x00dev, 45, 0x41);
+ rt2800_rfcsr_write(rt2x00dev, 48, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 57, 0x77);
+ rt2800_rfcsr_write(rt2x00dev, 60, 0x05);
+ rt2800_rfcsr_write(rt2x00dev, 61, 0x01);
+
+ /* TODO RF27 <- tssi */
+
+ if (rf->channel >= 36 && rf->channel <= 64) {
+
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x2E);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x22);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x60);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x7F);
+ if (rf->channel <= 50)
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x09);
+ else if (rf->channel >= 52)
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x07);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1C);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x5B);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0X40);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0X00);
+ rt2800_rfcsr_write(rt2x00dev, 51, 0xFE);
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x0C);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0xF8);
+ if (rf->channel <= 50) {
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x06),
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xD3);
+ } else if (rf->channel >= 52) {
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x04);
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xBB);
+ }
+
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x15);
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x7F);
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x15);
+
+ } else if (rf->channel >= 100 && rf->channel <= 165) {
+
+ rt2800_rfcsr_write(rt2x00dev, 12, 0x0E);
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x42);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x40);
+ if (rf->channel <= 153) {
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x3C);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x06);
+ } else if (rf->channel >= 155) {
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x38);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x05);
+ }
+ if (rf->channel <= 138) {
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x1A);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x3B);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x20);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0x18);
+ } else if (rf->channel >= 140) {
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x18);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x1B);
+ rt2800_rfcsr_write(rt2x00dev, 44, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 46, 0X08);
+ }
+ if (rf->channel <= 124)
+ rt2800_rfcsr_write(rt2x00dev, 51, 0xFC);
+ else if (rf->channel >= 126)
+ rt2800_rfcsr_write(rt2x00dev, 51, 0xEC);
+ if (rf->channel <= 138)
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x06);
+ else if (rf->channel >= 140)
+ rt2800_rfcsr_write(rt2x00dev, 52, 0x06);
+ rt2800_rfcsr_write(rt2x00dev, 54, 0xEB);
+ if (rf->channel <= 138)
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x01);
+ else if (rf->channel >= 140)
+ rt2800_rfcsr_write(rt2x00dev, 55, 0x00);
+ if (rf->channel <= 128)
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xBB);
+ else if (rf->channel >= 130)
+ rt2800_rfcsr_write(rt2x00dev, 56, 0xAB);
+ if (rf->channel <= 116)
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x1D);
+ else if (rf->channel >= 118)
+ rt2800_rfcsr_write(rt2x00dev, 58, 0x15);
+ if (rf->channel <= 138)
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x3F);
+ else if (rf->channel >= 140)
+ rt2800_rfcsr_write(rt2x00dev, 59, 0x7C);
+ if (rf->channel <= 116)
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x1D);
+ else if (rf->channel >= 118)
+ rt2800_rfcsr_write(rt2x00dev, 62, 0x15);
+ }
+
+ power_bound = POWER_BOUND_5G;
+ ep_reg = 0x3;
+ }
+
+ rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr);
+ if (info->default_power1 > power_bound)
+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, power_bound);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1);
+ if (is_type_ep)
+ rt2x00_set_field8(&rfcsr, RFCSR49_EP, ep_reg);
+ rt2800_rfcsr_write(rt2x00dev, 49, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr);
+ if (info->default_power1 > power_bound)
+ rt2x00_set_field8(&rfcsr, RFCSR50_TX, power_bound);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR50_TX, info->default_power2);
+ if (is_type_ep)
+ rt2x00_set_field8(&rfcsr, RFCSR50_EP, ep_reg);
+ rt2800_rfcsr_write(rt2x00dev, 50, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_PLL_PD, 1);
+
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD,
+ rt2x00dev->default_ant.tx_chain_num >= 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD,
+ rt2x00dev->default_ant.tx_chain_num == 2);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
+
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD,
+ rt2x00dev->default_ant.rx_chain_num >= 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD,
+ rt2x00dev->default_ant.rx_chain_num == 2);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
+
+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xe4);
+
+ if (conf_is_ht40(conf))
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x16);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
+
+ if (!is_11b) {
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
+ }
+
+ /* TODO proper frequency adjustment */
+ rt2800_adjust_freq_offset(rt2x00dev);
+
+ /* TODO merge with others */
+ rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR3_VCOCAL_EN, 1);
+ rt2800_rfcsr_write(rt2x00dev, 3, rfcsr);
+
+ /* BBP settings */
+ rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
+ rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
+
+ rt2800_bbp_write(rt2x00dev, 79, (rf->channel <= 14) ? 0x1C : 0x18);
+ rt2800_bbp_write(rt2x00dev, 80, (rf->channel <= 14) ? 0x0E : 0x08);
+ rt2800_bbp_write(rt2x00dev, 81, (rf->channel <= 14) ? 0x3A : 0x38);
+ rt2800_bbp_write(rt2x00dev, 82, (rf->channel <= 14) ? 0x62 : 0x92);
+
+ /* GLRT band configuration */
+ rt2800_bbp_write(rt2x00dev, 195, 128);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0xE0 : 0xF0);
+ rt2800_bbp_write(rt2x00dev, 195, 129);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x1F : 0x1E);
+ rt2800_bbp_write(rt2x00dev, 195, 130);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x38 : 0x28);
+ rt2800_bbp_write(rt2x00dev, 195, 131);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x32 : 0x20);
+ rt2800_bbp_write(rt2x00dev, 195, 133);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x28 : 0x7F);
+ rt2800_bbp_write(rt2x00dev, 195, 124);
+ rt2800_bbp_write(rt2x00dev, 196, (rf->channel <= 14) ? 0x19 : 0x7F);
+}
+
+static void rt2800_bbp_write_with_rx_chain(struct rt2x00_dev *rt2x00dev,
+ const unsigned int word,
+ const u8 value)
+{
+ u8 chain, reg;
+
+ for (chain = 0; chain < rt2x00dev->default_ant.rx_chain_num; chain++) {
+ rt2800_bbp_read(rt2x00dev, 27, &reg);
+ rt2x00_set_field8(&reg, BBP27_RX_CHAIN_SEL, chain);
+ rt2800_bbp_write(rt2x00dev, 27, reg);
+
+ rt2800_bbp_write(rt2x00dev, word, value);
+ }
+}
+
+static void rt2800_iq_calibrate(struct rt2x00_dev *rt2x00dev, int channel)
+{
+ u8 cal;
+
+ /* TX0 IQ Gain */
+ rt2800_bbp_write(rt2x00dev, 158, 0x2c);
+ if (channel <= 14)
+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_GAIN_CAL_TX0_2G);
+ else if (channel >= 36 && channel <= 64)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX0_CH36_TO_CH64_5G);
+ else if (channel >= 100 && channel <= 138)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX0_CH100_TO_CH138_5G);
+ else if (channel >= 140 && channel <= 165)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX0_CH140_TO_CH165_5G);
+ else
+ cal = 0;
+ rt2800_bbp_write(rt2x00dev, 159, cal);
+
+ /* TX0 IQ Phase */
+ rt2800_bbp_write(rt2x00dev, 158, 0x2d);
+ if (channel <= 14)
+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_PHASE_CAL_TX0_2G);
+ else if (channel >= 36 && channel <= 64)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX0_CH36_TO_CH64_5G);
+ else if (channel >= 100 && channel <= 138)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX0_CH100_TO_CH138_5G);
+ else if (channel >= 140 && channel <= 165)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX0_CH140_TO_CH165_5G);
+ else
+ cal = 0;
+ rt2800_bbp_write(rt2x00dev, 159, cal);
+
+ /* TX1 IQ Gain */
+ rt2800_bbp_write(rt2x00dev, 158, 0x4a);
+ if (channel <= 14)
+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_GAIN_CAL_TX1_2G);
+ else if (channel >= 36 && channel <= 64)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX1_CH36_TO_CH64_5G);
+ else if (channel >= 100 && channel <= 138)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX1_CH100_TO_CH138_5G);
+ else if (channel >= 140 && channel <= 165)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_GAIN_CAL_TX1_CH140_TO_CH165_5G);
+ else
+ cal = 0;
+ rt2800_bbp_write(rt2x00dev, 159, cal);
+
+ /* TX1 IQ Phase */
+ rt2800_bbp_write(rt2x00dev, 158, 0x4b);
+ if (channel <= 14)
+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_IQ_PHASE_CAL_TX1_2G);
+ else if (channel >= 36 && channel <= 64)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX1_CH36_TO_CH64_5G);
+ else if (channel >= 100 && channel <= 138)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX1_CH100_TO_CH138_5G);
+ else if (channel >= 140 && channel <= 165)
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_IQ_PHASE_CAL_TX1_CH140_TO_CH165_5G);
+ else
+ cal = 0;
+ rt2800_bbp_write(rt2x00dev, 159, cal);
+
+ /* FIXME: possible RX0, RX1 callibration ? */
+
+ /* RF IQ compensation control */
+ rt2800_bbp_write(rt2x00dev, 158, 0x04);
+ cal = rt2x00_eeprom_byte(rt2x00dev, EEPROM_RF_IQ_COMPENSATION_CONTROL);
+ rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
+
+ /* RF IQ imbalance compensation control */
+ rt2800_bbp_write(rt2x00dev, 158, 0x03);
+ cal = rt2x00_eeprom_byte(rt2x00dev,
+ EEPROM_RF_IQ_IMBALANCE_COMPENSATION_CONTROL);
+ rt2800_bbp_write(rt2x00dev, 159, cal != 0xff ? cal : 0);
+}
+
static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
struct rf_channel *rf,
@@ -2225,6 +2604,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
case RF5392:
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
break;
+ case RF5592:
+ rt2800_config_channel_rf55xx(rt2x00dev, conf, rf, info);
+ break;
default:
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
}
@@ -2326,6 +2708,17 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
if (rt2x00_rt(rt2x00dev, RT3572))
rt2800_rfcsr_write(rt2x00dev, 8, 0x80);
+ if (rt2x00_rt(rt2x00dev, RT5592)) {
+ rt2800_bbp_write(rt2x00dev, 195, 141);
+ rt2800_bbp_write(rt2x00dev, 196, conf_is_ht40(conf) ? 0x10 : 0x1a);
+
+ /* AGC init */
+ reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2 * rt2x00dev->lna_gain;
+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
+
+ rt2800_iq_calibrate(rt2x00dev, rf->channel);
+ }
+
rt2800_bbp_read(rt2x00dev, 4, &bbp);
rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
rt2800_bbp_write(rt2x00dev, 4, bbp);
@@ -2763,7 +3156,7 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
{
- rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.channel,
+ rt2800_config_txpower(rt2x00dev, rt2x00dev->hw->conf.chandef.chan,
rt2x00dev->tx_power);
}
EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
@@ -2898,11 +3291,11 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev,
if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
rt2800_config_channel(rt2x00dev, libconf->conf,
&libconf->rf, &libconf->channel);
- rt2800_config_txpower(rt2x00dev, libconf->conf->channel,
+ rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan,
libconf->conf->power_level);
}
if (flags & IEEE80211_CONF_CHANGE_POWER)
- rt2800_config_txpower(rt2x00dev, libconf->conf->channel,
+ rt2800_config_txpower(rt2x00dev, libconf->conf->chandef.chan,
libconf->conf->power_level);
if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
rt2800_config_retry_limit(rt2x00dev, libconf);
@@ -2938,13 +3331,16 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
rt2x00_rt(rt2x00dev, RT3390) ||
rt2x00_rt(rt2x00dev, RT3572) ||
rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392))
+ rt2x00_rt(rt2x00dev, RT5392) ||
+ rt2x00_rt(rt2x00dev, RT5592))
vgc = 0x1c + (2 * rt2x00dev->lna_gain);
else
vgc = 0x2e + rt2x00dev->lna_gain;
} else { /* 5GHZ band */
if (rt2x00_rt(rt2x00dev, RT3572))
vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3;
+ else if (rt2x00_rt(rt2x00dev, RT5592))
+ vgc = 0x24 + (2 * rt2x00dev->lna_gain);
else {
if (!test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
vgc = 0x32 + (rt2x00dev->lna_gain * 5) / 3;
@@ -2960,7 +3356,11 @@ static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, u8 vgc_level)
{
if (qual->vgc_level != vgc_level) {
- rt2800_bbp_write(rt2x00dev, 66, vgc_level);
+ if (rt2x00_rt(rt2x00dev, RT5592)) {
+ rt2800_bbp_write(rt2x00dev, 83, qual->rssi > -65 ? 0x4a : 0x7a);
+ rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, vgc_level);
+ } else
+ rt2800_bbp_write(rt2x00dev, 66, vgc_level);
qual->vgc_level = vgc_level;
qual->vgc_level_reg = vgc_level;
}
@@ -2975,15 +3375,23 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count)
{
+ u8 vgc;
+
if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C))
return;
-
/*
- * When RSSI is better then -80 increase VGC level with 0x10
+ * When RSSI is better then -80 increase VGC level with 0x10, except
+ * for rt5592 chip.
*/
- rt2800_set_vgc(rt2x00dev, qual,
- rt2800_get_default_vgc(rt2x00dev) +
- ((qual->rssi > -80) * 0x10));
+
+ vgc = rt2800_get_default_vgc(rt2x00dev);
+
+ if (rt2x00_rt(rt2x00dev, RT5592) && qual->rssi > -65)
+ vgc += 0x20;
+ else if (qual->rssi > -80)
+ vgc += 0x10;
+
+ rt2800_set_vgc(rt2x00dev, qual, vgc);
}
EXPORT_SYMBOL_GPL(rt2800_link_tuner);
@@ -3122,7 +3530,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
} else if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
+ rt2x00_rt(rt2x00dev, RT5392) ||
+ rt2x00_rt(rt2x00dev, RT5592)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
@@ -3302,7 +3711,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXOP_CTRL_CFG_EXT_CWMIN, 0);
rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, reg);
- rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002);
+ reg = rt2x00_rt(rt2x00dev, RT5592) ? 0x00000082 : 0x00000002;
+ rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, reg);
rt2800_register_read(rt2x00dev, TX_RTS_CFG, &reg);
rt2x00_set_field32(&reg, TX_RTS_CFG_AUTO_RTS_RETRY_LIMIT, 32);
@@ -3459,7 +3869,7 @@ static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP/RF register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP/RF register access failed, aborting\n");
return -EACCES;
}
@@ -3483,10 +3893,140 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
+static void rt2800_bbp4_mac_if_ctrl(struct rt2x00_dev *rt2x00dev)
+{
+ u8 value;
+
+ rt2800_bbp_read(rt2x00dev, 4, &value);
+ rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
+ rt2800_bbp_write(rt2x00dev, 4, value);
+}
+
+static void rt2800_init_freq_calibration(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_bbp_write(rt2x00dev, 142, 1);
+ rt2800_bbp_write(rt2x00dev, 143, 57);
+}
+
+static void rt2800_init_bbp_5592_glrt(struct rt2x00_dev *rt2x00dev)
+{
+ const u8 glrt_table[] = {
+ 0xE0, 0x1F, 0X38, 0x32, 0x08, 0x28, 0x19, 0x0A, 0xFF, 0x00, /* 128 ~ 137 */
+ 0x16, 0x10, 0x10, 0x0B, 0x36, 0x2C, 0x26, 0x24, 0x42, 0x36, /* 138 ~ 147 */
+ 0x30, 0x2D, 0x4C, 0x46, 0x3D, 0x40, 0x3E, 0x42, 0x3D, 0x40, /* 148 ~ 157 */
+ 0X3C, 0x34, 0x2C, 0x2F, 0x3C, 0x35, 0x2E, 0x2A, 0x49, 0x41, /* 158 ~ 167 */
+ 0x36, 0x31, 0x30, 0x30, 0x0E, 0x0D, 0x28, 0x21, 0x1C, 0x16, /* 168 ~ 177 */
+ 0x50, 0x4A, 0x43, 0x40, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, /* 178 ~ 187 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 188 ~ 197 */
+ 0x00, 0x00, 0x7D, 0x14, 0x32, 0x2C, 0x36, 0x4C, 0x43, 0x2C, /* 198 ~ 207 */
+ 0x2E, 0x36, 0x30, 0x6E, /* 208 ~ 211 */
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(glrt_table); i++) {
+ rt2800_bbp_write(rt2x00dev, 195, 128 + i);
+ rt2800_bbp_write(rt2x00dev, 196, glrt_table[i]);
+ }
+};
+
+static void rt2800_init_bbp_early(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_bbp_write(rt2x00dev, 65, 0x2C);
+ rt2800_bbp_write(rt2x00dev, 66, 0x38);
+ rt2800_bbp_write(rt2x00dev, 68, 0x0B);
+ rt2800_bbp_write(rt2x00dev, 69, 0x12);
+ rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+ rt2800_bbp_write(rt2x00dev, 73, 0x10);
+ rt2800_bbp_write(rt2x00dev, 81, 0x37);
+ rt2800_bbp_write(rt2x00dev, 82, 0x62);
+ rt2800_bbp_write(rt2x00dev, 83, 0x6A);
+ rt2800_bbp_write(rt2x00dev, 84, 0x99);
+ rt2800_bbp_write(rt2x00dev, 86, 0x00);
+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
+ rt2800_bbp_write(rt2x00dev, 92, 0x00);
+ rt2800_bbp_write(rt2x00dev, 103, 0x00);
+ rt2800_bbp_write(rt2x00dev, 105, 0x05);
+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
+}
+
+static void rt2800_init_bbp_5592(struct rt2x00_dev *rt2x00dev)
+{
+ int ant, div_mode;
+ u16 eeprom;
+ u8 value;
+
+ rt2800_init_bbp_early(rt2x00dev);
+
+ rt2800_bbp_read(rt2x00dev, 105, &value);
+ rt2x00_set_field8(&value, BBP105_MLD,
+ rt2x00dev->default_ant.rx_chain_num == 2);
+ rt2800_bbp_write(rt2x00dev, 105, value);
+
+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
+
+ rt2800_bbp_write(rt2x00dev, 20, 0x06);
+ rt2800_bbp_write(rt2x00dev, 31, 0x08);
+ rt2800_bbp_write(rt2x00dev, 65, 0x2C);
+ rt2800_bbp_write(rt2x00dev, 68, 0xDD);
+ rt2800_bbp_write(rt2x00dev, 69, 0x1A);
+ rt2800_bbp_write(rt2x00dev, 70, 0x05);
+ rt2800_bbp_write(rt2x00dev, 73, 0x13);
+ rt2800_bbp_write(rt2x00dev, 74, 0x0F);
+ rt2800_bbp_write(rt2x00dev, 75, 0x4F);
+ rt2800_bbp_write(rt2x00dev, 76, 0x28);
+ rt2800_bbp_write(rt2x00dev, 77, 0x59);
+ rt2800_bbp_write(rt2x00dev, 84, 0x9A);
+ rt2800_bbp_write(rt2x00dev, 86, 0x38);
+ rt2800_bbp_write(rt2x00dev, 88, 0x90);
+ rt2800_bbp_write(rt2x00dev, 91, 0x04);
+ rt2800_bbp_write(rt2x00dev, 92, 0x02);
+ rt2800_bbp_write(rt2x00dev, 95, 0x9a);
+ rt2800_bbp_write(rt2x00dev, 98, 0x12);
+ rt2800_bbp_write(rt2x00dev, 103, 0xC0);
+ rt2800_bbp_write(rt2x00dev, 104, 0x92);
+ /* FIXME BBP105 owerwrite */
+ rt2800_bbp_write(rt2x00dev, 105, 0x3C);
+ rt2800_bbp_write(rt2x00dev, 106, 0x35);
+ rt2800_bbp_write(rt2x00dev, 128, 0x12);
+ rt2800_bbp_write(rt2x00dev, 134, 0xD0);
+ rt2800_bbp_write(rt2x00dev, 135, 0xF6);
+ rt2800_bbp_write(rt2x00dev, 137, 0x0F);
+
+ /* Initialize GLRT (Generalized Likehood Radio Test) */
+ rt2800_init_bbp_5592_glrt(rt2x00dev);
+
+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ div_mode = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_ANT_DIVERSITY);
+ ant = (div_mode == 3) ? 1 : 0;
+ rt2800_bbp_read(rt2x00dev, 152, &value);
+ if (ant == 0) {
+ /* Main antenna */
+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 1);
+ } else {
+ /* Auxiliary antenna */
+ rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0);
+ }
+ rt2800_bbp_write(rt2x00dev, 152, value);
+
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C)) {
+ rt2800_bbp_read(rt2x00dev, 254, &value);
+ rt2x00_set_field8(&value, BBP254_BIT7, 1);
+ rt2800_bbp_write(rt2x00dev, 254, value);
+ }
+
+ rt2800_init_freq_calibration(rt2x00dev);
+
+ rt2800_bbp_write(rt2x00dev, 84, 0x19);
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C))
+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+}
+
static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
{
unsigned int i;
@@ -3498,6 +4038,11 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_wait_bbp_ready(rt2x00dev)))
return -EACCES;
+ if (rt2x00_rt(rt2x00dev, RT5592)) {
+ rt2800_init_bbp_5592(rt2x00dev);
+ return 0;
+ }
+
if (rt2x00_rt(rt2x00dev, RT3352)) {
rt2800_bbp_write(rt2x00dev, 3, 0x00);
rt2800_bbp_write(rt2x00dev, 4, 0x50);
@@ -3505,11 +4050,8 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT3290) ||
rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_bbp_read(rt2x00dev, 4, &value);
- rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1);
- rt2800_bbp_write(rt2x00dev, 4, value);
- }
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
if (rt2800_is_305x_soc(rt2x00dev) ||
rt2x00_rt(rt2x00dev, RT3290) ||
@@ -3783,9 +4325,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field8(&value, BBP152_RX_DEFAULT_ANT, 0);
rt2800_bbp_write(rt2x00dev, 152, value);
- /* Init frequency calibration */
- rt2800_bbp_write(rt2x00dev, 142, 1);
- rt2800_bbp_write(rt2x00dev, 143, 57);
+ rt2800_init_freq_calibration(rt2x00dev);
}
for (i = 0; i < EEPROM_BBP_SIZE; i++) {
@@ -3801,8 +4341,17 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
return 0;
}
-static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
- bool bw40, u8 rfcsr24, u8 filter_target)
+static void rt2800_led_open_drain_enable(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2800_register_read(rt2x00dev, OPT_14_CSR, &reg);
+ rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
+ rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
+}
+
+static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40,
+ u8 filter_target)
{
unsigned int i;
u8 bbp;
@@ -3810,6 +4359,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
u8 passband;
u8 stopband;
u8 overtuned = 0;
+ u8 rfcsr24 = (bw40) ? 0x27 : 0x07;
rt2800_rfcsr_write(rt2x00dev, 24, rfcsr24);
@@ -3865,8 +4415,169 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev,
return rfcsr24;
}
+static void rt2800_rf_init_calibration(struct rt2x00_dev *rt2x00dev,
+ const unsigned int rf_reg)
+{
+ u8 rfcsr;
+
+ rt2800_rfcsr_read(rt2x00dev, rf_reg, &rfcsr);
+ rt2x00_set_field8(&rfcsr, FIELD8(0x80), 1);
+ rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr);
+ msleep(1);
+ rt2x00_set_field8(&rfcsr, FIELD8(0x80), 0);
+ rt2800_rfcsr_write(rt2x00dev, rf_reg, rfcsr);
+}
+
+static void rt2800_rx_filter_calibration(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ u8 filter_tgt_bw20;
+ u8 filter_tgt_bw40;
+ u8 rfcsr, bbp;
+
+ /*
+ * TODO: sync filter_tgt values with vendor driver
+ */
+ if (rt2x00_rt(rt2x00dev, RT3070)) {
+ filter_tgt_bw20 = 0x16;
+ filter_tgt_bw40 = 0x19;
+ } else {
+ filter_tgt_bw20 = 0x13;
+ filter_tgt_bw40 = 0x15;
+ }
+
+ drv_data->calibration_bw20 =
+ rt2800_init_rx_filter(rt2x00dev, false, filter_tgt_bw20);
+ drv_data->calibration_bw40 =
+ rt2800_init_rx_filter(rt2x00dev, true, filter_tgt_bw40);
+
+ /*
+ * Save BBP 25 & 26 values for later use in channel switching (for 3052)
+ */
+ rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
+ rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
+
+ /*
+ * Set back to initial state
+ */
+ rt2800_bbp_write(rt2x00dev, 24, 0);
+
+ rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
+ rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
+
+ /*
+ * Set BBP back to BW20
+ */
+ rt2800_bbp_read(rt2x00dev, 4, &bbp);
+ rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
+ rt2800_bbp_write(rt2x00dev, 4, bbp);
+}
+
+static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev)
+{
+ struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
+ u8 min_gain, rfcsr, bbp;
+ u16 eeprom;
+
+ rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+
+ rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
+ if (rt2x00_rt(rt2x00dev, RT3070) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
+ if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
+ rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
+ }
+
+ min_gain = rt2x00_rt(rt2x00dev, RT3070) ? 1 : 2;
+ if (drv_data->txmixer_gain_24g >= min_gain) {
+ rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN,
+ drv_data->txmixer_gain_24g);
+ }
+
+ rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+
+ if (rt2x00_rt(rt2x00dev, RT3090)) {
+ /* Turn off unused DAC1 and ADC1 to reduce power consumption */
+ rt2800_bbp_read(rt2x00dev, 138, &bbp);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
+ rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
+ rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
+ rt2800_bbp_write(rt2x00dev, 138, bbp);
+ }
+
+ if (rt2x00_rt(rt2x00dev, RT3070)) {
+ rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F))
+ rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
+ else
+ rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR27_R2, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR27_R3, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR27_R4, 0);
+ rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
+ } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3090) ||
+ rt2x00_rt(rt2x00dev, RT3390)) {
+ rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+ rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+ rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+ rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 15, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
+
+ rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
+ }
+}
+
+static void rt2800_normal_mode_setup_5xxx(struct rt2x00_dev *rt2x00dev)
+{
+ u8 reg;
+ u16 eeprom;
+
+ /* Turn off unused DAC1 and ADC1 to reduce power consumption */
+ rt2800_bbp_read(rt2x00dev, 138, &reg);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
+ rt2x00_set_field8(&reg, BBP138_RX_ADC1, 0);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
+ rt2x00_set_field8(&reg, BBP138_TX_DAC1, 1);
+ rt2800_bbp_write(rt2x00dev, 138, reg);
+
+ rt2800_rfcsr_read(rt2x00dev, 38, &reg);
+ rt2x00_set_field8(&reg, RFCSR38_RX_LO1_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 38, reg);
+
+ rt2800_rfcsr_read(rt2x00dev, 39, &reg);
+ rt2x00_set_field8(&reg, RFCSR39_RX_LO2_EN, 0);
+ rt2800_rfcsr_write(rt2x00dev, 39, reg);
+
+ rt2800_bbp4_mac_if_ctrl(rt2x00dev);
+
+ rt2800_rfcsr_read(rt2x00dev, 30, &reg);
+ rt2x00_set_field8(&reg, RFCSR30_RX_VCM, 2);
+ rt2800_rfcsr_write(rt2x00dev, 30, reg);
+}
+
static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
{
+ rt2800_rf_init_calibration(rt2x00dev, 30);
+
rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
@@ -3903,6 +4614,13 @@ static void rt2800_init_rfcsr_305x_soc(struct rt2x00_dev *rt2x00dev)
static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
{
+ u8 rfcsr;
+ u16 eeprom;
+ u32 reg;
+
+ /* XXX vendor driver do this only for 3070 */
+ rt2800_rf_init_calibration(rt2x00dev, 30);
+
rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
@@ -3922,10 +4640,54 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
+
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+ } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+ rt2x00_rt(rt2x00dev, RT3090)) {
+ rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
+
+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+ else
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
+ }
+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+
+ rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+ rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
+ rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
+ }
+
+ rt2800_rx_filter_calibration(rt2x00dev);
+
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+ rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E))
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+
+ rt2800_led_open_drain_enable(rt2x00dev);
+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
}
static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
{
+ u8 rfcsr;
+
+ rt2800_rf_init_calibration(rt2x00dev, 2);
+
rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
@@ -3972,10 +4734,19 @@ static void rt2800_init_rfcsr_3290(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 59, 0x09);
rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
rt2800_rfcsr_write(rt2x00dev, 61, 0xc1);
+
+ rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3);
+ rt2800_rfcsr_write(rt2x00dev, 29, rfcsr);
+
+ rt2800_led_open_drain_enable(rt2x00dev);
+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
}
static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
{
+ rt2800_rf_init_calibration(rt2x00dev, 30);
+
rt2800_rfcsr_write(rt2x00dev, 0, 0xf0);
rt2800_rfcsr_write(rt2x00dev, 1, 0x23);
rt2800_rfcsr_write(rt2x00dev, 2, 0x50);
@@ -4039,10 +4810,18 @@ static void rt2800_init_rfcsr_3352(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 61, 0x00);
rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+
+ rt2800_rx_filter_calibration(rt2x00dev);
+ rt2800_led_open_drain_enable(rt2x00dev);
+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
}
static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
{
+ u32 reg;
+
+ rt2800_rf_init_calibration(rt2x00dev, 30);
+
rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
@@ -4075,10 +4854,27 @@ static void rt2800_init_rfcsr_3390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+
+ rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+ rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
+ rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
+
+ rt2800_rx_filter_calibration(rt2x00dev);
+
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E))
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+
+ rt2800_led_open_drain_enable(rt2x00dev);
+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
}
static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
{
+ u8 rfcsr;
+ u32 reg;
+
+ rt2800_rf_init_calibration(rt2x00dev, 30);
+
rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
@@ -4110,10 +4906,30 @@ static void rt2800_init_rfcsr_3572(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
+
+ rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+ rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
+ rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+ msleep(1);
+ rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+ rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
+ rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+ rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+
+ rt2800_rx_filter_calibration(rt2x00dev);
+ rt2800_led_open_drain_enable(rt2x00dev);
+ rt2800_normal_mode_setup_3xxx(rt2x00dev);
}
static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
{
+ rt2800_rf_init_calibration(rt2x00dev, 2);
+
rt2800_rfcsr_write(rt2x00dev, 1, 0x0f);
rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
@@ -4194,10 +5010,16 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 61, 0xdd);
rt2800_rfcsr_write(rt2x00dev, 62, 0x00);
rt2800_rfcsr_write(rt2x00dev, 63, 0x00);
+
+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
+
+ rt2800_led_open_drain_enable(rt2x00dev);
}
static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
{
+ rt2800_rf_init_calibration(rt2x00dev, 2);
+
rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
@@ -4257,53 +5079,61 @@ static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write(rt2x00dev, 61, 0x91);
rt2800_rfcsr_write(rt2x00dev, 62, 0x39);
rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
+
+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
+
+ rt2800_led_open_drain_enable(rt2x00dev);
}
-static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev)
{
- struct rt2800_drv_data *drv_data = rt2x00dev->drv_data;
- u8 rfcsr;
- u8 bbp;
- u32 reg;
- u16 eeprom;
+ rt2800_rf_init_calibration(rt2x00dev, 30);
- if (!rt2x00_rt(rt2x00dev, RT3070) &&
- !rt2x00_rt(rt2x00dev, RT3071) &&
- !rt2x00_rt(rt2x00dev, RT3090) &&
- !rt2x00_rt(rt2x00dev, RT3290) &&
- !rt2x00_rt(rt2x00dev, RT3352) &&
- !rt2x00_rt(rt2x00dev, RT3390) &&
- !rt2x00_rt(rt2x00dev, RT3572) &&
- !rt2x00_rt(rt2x00dev, RT5390) &&
- !rt2x00_rt(rt2x00dev, RT5392) &&
- !rt2800_is_305x_soc(rt2x00dev))
- return 0;
+ rt2800_rfcsr_write(rt2x00dev, 1, 0x3F);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 3, 0x08);
+ rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 6, 0xE4);
+ rt2800_rfcsr_write(rt2x00dev, 7, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 15, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x03);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x4D);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0x8D);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x82);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
+ rt2800_rfcsr_write(rt2x00dev, 33, 0xC0);
+ rt2800_rfcsr_write(rt2x00dev, 34, 0x07);
+ rt2800_rfcsr_write(rt2x00dev, 35, 0x12);
+ rt2800_rfcsr_write(rt2x00dev, 47, 0x0C);
+ rt2800_rfcsr_write(rt2x00dev, 53, 0x22);
+ rt2800_rfcsr_write(rt2x00dev, 63, 0x07);
- /*
- * Init RF calibration.
- */
+ rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
+ msleep(1);
- if (rt2x00_rt(rt2x00dev, RT3290) ||
- rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1);
- rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
- msleep(1);
- rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 2, rfcsr);
- } else {
- rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
- rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
- msleep(1);
- rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
- rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
- }
+ rt2800_adjust_freq_offset(rt2x00dev);
+
+ /* Enable DC filter */
+ if (rt2x00_rt_rev_gte(rt2x00dev, RT5592, REV_RT5592C))
+ rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+
+ rt2800_normal_mode_setup_5xxx(rt2x00dev);
+
+ if (rt2x00_rt_rev_lt(rt2x00dev, RT5592, REV_RT5592C))
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+ rt2800_led_open_drain_enable(rt2x00dev);
+}
+
+static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
+{
if (rt2800_is_305x_soc(rt2x00dev)) {
rt2800_init_rfcsr_305x_soc(rt2x00dev);
- return 0;
+ return;
}
switch (rt2x00dev->chip.rt) {
@@ -4330,198 +5160,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
case RT5392:
rt2800_init_rfcsr_5392(rt2x00dev);
break;
+ case RT5592:
+ rt2800_init_rfcsr_5592(rt2x00dev);
+ break;
}
-
- if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
- rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
- rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
- rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
- rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
- } else if (rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090)) {
- rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
-
- rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
- rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-
- rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
- rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
- if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
- rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
- else
- rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
- }
- rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
-
- rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
- rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
- rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
- } else if (rt2x00_rt(rt2x00dev, RT3390)) {
- rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
- rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
- rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
- } else if (rt2x00_rt(rt2x00dev, RT3572)) {
- rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
- rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
-
- rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
- rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
- rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
- rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
- msleep(1);
- rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
- rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
- rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
- rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
- }
-
- /*
- * Set RX Filter calibration for 20MHz and 40MHz
- */
- if (rt2x00_rt(rt2x00dev, RT3070)) {
- drv_data->calibration_bw20 =
- rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
- drv_data->calibration_bw40 =
- rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
- } else if (rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
- rt2x00_rt(rt2x00dev, RT3352) ||
- rt2x00_rt(rt2x00dev, RT3390) ||
- rt2x00_rt(rt2x00dev, RT3572)) {
- drv_data->calibration_bw20 =
- rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x13);
- drv_data->calibration_bw40 =
- rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x15);
- }
-
- /*
- * Save BBP 25 & 26 values for later use in channel switching
- */
- rt2800_bbp_read(rt2x00dev, 25, &drv_data->bbp25);
- rt2800_bbp_read(rt2x00dev, 26, &drv_data->bbp26);
-
- if (!rt2x00_rt(rt2x00dev, RT5390) &&
- !rt2x00_rt(rt2x00dev, RT5392)) {
- /*
- * Set back to initial state
- */
- rt2800_bbp_write(rt2x00dev, 24, 0);
-
- rt2800_rfcsr_read(rt2x00dev, 22, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR22_BASEBAND_LOOPBACK, 0);
- rt2800_rfcsr_write(rt2x00dev, 22, rfcsr);
-
- /*
- * Set BBP back to BW20
- */
- rt2800_bbp_read(rt2x00dev, 4, &bbp);
- rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
- rt2800_bbp_write(rt2x00dev, 4, bbp);
- }
-
- if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E))
- rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
-
- rt2800_register_read(rt2x00dev, OPT_14_CSR, &reg);
- rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
- rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
-
- if (!rt2x00_rt(rt2x00dev, RT5390) &&
- !rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
- if (rt2x00_rt(rt2x00dev, RT3070) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
- rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG,
- &rt2x00dev->cap_flags))
- rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
- }
- rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN,
- drv_data->txmixer_gain_24g);
- rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
- }
-
- if (rt2x00_rt(rt2x00dev, RT3090)) {
- rt2800_bbp_read(rt2x00dev, 138, &bbp);
-
- /* Turn off unused DAC1 and ADC1 to reduce power consumption */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
- rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
- rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
-
- rt2800_bbp_write(rt2x00dev, 138, bbp);
- }
-
- if (rt2x00_rt(rt2x00dev, RT3071) ||
- rt2x00_rt(rt2x00dev, RT3090) ||
- rt2x00_rt(rt2x00dev, RT3390)) {
- rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
- rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
- rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
- rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
- rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
- rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
-
- rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 15, rfcsr);
-
- rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
-
- rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
- }
-
- if (rt2x00_rt(rt2x00dev, RT3070)) {
- rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
- if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F))
- rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
- else
- rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
- rt2x00_set_field8(&rfcsr, RFCSR27_R2, 0);
- rt2x00_set_field8(&rfcsr, RFCSR27_R3, 0);
- rt2x00_set_field8(&rfcsr, RFCSR27_R4, 0);
- rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
- }
-
- if (rt2x00_rt(rt2x00dev, RT3290)) {
- rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3);
- rt2800_rfcsr_write(rt2x00dev, 29, rfcsr);
- }
-
- if (rt2x00_rt(rt2x00dev, RT5390) ||
- rt2x00_rt(rt2x00dev, RT5392)) {
- rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR38_RX_LO1_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 38, rfcsr);
-
- rt2800_rfcsr_read(rt2x00dev, 39, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR39_RX_LO2_EN, 0);
- rt2800_rfcsr_write(rt2x00dev, 39, rfcsr);
-
- rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
- rt2x00_set_field8(&rfcsr, RFCSR30_RX_VCM, 2);
- rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
- }
-
- return 0;
}
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -4533,15 +5175,24 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
* Initialize all registers.
*/
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
- rt2800_init_registers(rt2x00dev) ||
- rt2800_init_bbp(rt2x00dev) ||
- rt2800_init_rfcsr(rt2x00dev)))
+ rt2800_init_registers(rt2x00dev)))
return -EIO;
/*
* Send signal to firmware during boot time.
*/
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+ rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ if (rt2x00_is_usb(rt2x00dev)) {
+ rt2800_register_write(rt2x00dev, H2M_INT_SRC, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
+ }
+ msleep(1);
+
+ if (unlikely(rt2800_init_bbp(rt2x00dev)))
+ return -EIO;
+
+ rt2800_init_rfcsr(rt2x00dev);
if (rt2x00_is_usb(rt2x00dev) &&
(rt2x00_rt(rt2x00dev, RT3070) ||
@@ -4702,7 +5353,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
@@ -4711,7 +5362,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
- EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
@@ -4740,14 +5391,14 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
- EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
if ((word & 0x00ff) == 0x00ff) {
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
}
if ((word & 0xff00) == 0xff00) {
rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,
@@ -4757,7 +5408,7 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
- EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Led Mode: 0x%04x\n", word);
}
/*
@@ -4821,9 +5472,9 @@ static int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
{
- u32 reg;
u16 value;
u16 eeprom;
+ u16 rf;
/*
* Read EEPROM word for configuration.
@@ -4835,41 +5486,14 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
* RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field
* RT53xx: defined in "EEPROM_CHIP_ID" field
*/
- if (rt2x00_rt(rt2x00dev, RT3290))
- rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
- else
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
-
- if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT3290 ||
- rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 ||
- rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392)
- rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value);
+ if (rt2x00_rt(rt2x00dev, RT3290) ||
+ rt2x00_rt(rt2x00dev, RT5390) ||
+ rt2x00_rt(rt2x00dev, RT5392))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &rf);
else
- value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
+ rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
- rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
- value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
-
- switch (rt2x00dev->chip.rt) {
- case RT2860:
- case RT2872:
- case RT2883:
- case RT3070:
- case RT3071:
- case RT3090:
- case RT3290:
- case RT3352:
- case RT3390:
- case RT3572:
- case RT5390:
- case RT5392:
- break;
- default:
- ERROR(rt2x00dev, "Invalid RT chipset 0x%04x detected.\n", rt2x00dev->chip.rt);
- return -ENODEV;
- }
-
- switch (rt2x00dev->chip.rf) {
+ switch (rf) {
case RF2820:
case RF2850:
case RF2720:
@@ -4887,13 +5511,16 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
case RF5372:
case RF5390:
case RF5392:
+ case RF5592:
break;
default:
- ERROR(rt2x00dev, "Invalid RF chipset 0x%04x detected.\n",
- rt2x00dev->chip.rf);
+ rt2x00_err(rt2x00dev, "Invalid RF chipset 0x%04x detected\n",
+ rf);
return -ENODEV;
}
+ rt2x00_set_rf(rt2x00dev, rf);
+
/*
* Identify default antenna configuration.
*/
@@ -5122,6 +5749,138 @@ static const struct rf_channel rf_vals_3x[] = {
{173, 0x61, 0, 9},
};
+static const struct rf_channel rf_vals_5592_xtal20[] = {
+ /* Channel, N, K, mod, R */
+ {1, 482, 4, 10, 3},
+ {2, 483, 4, 10, 3},
+ {3, 484, 4, 10, 3},
+ {4, 485, 4, 10, 3},
+ {5, 486, 4, 10, 3},
+ {6, 487, 4, 10, 3},
+ {7, 488, 4, 10, 3},
+ {8, 489, 4, 10, 3},
+ {9, 490, 4, 10, 3},
+ {10, 491, 4, 10, 3},
+ {11, 492, 4, 10, 3},
+ {12, 493, 4, 10, 3},
+ {13, 494, 4, 10, 3},
+ {14, 496, 8, 10, 3},
+ {36, 172, 8, 12, 1},
+ {38, 173, 0, 12, 1},
+ {40, 173, 4, 12, 1},
+ {42, 173, 8, 12, 1},
+ {44, 174, 0, 12, 1},
+ {46, 174, 4, 12, 1},
+ {48, 174, 8, 12, 1},
+ {50, 175, 0, 12, 1},
+ {52, 175, 4, 12, 1},
+ {54, 175, 8, 12, 1},
+ {56, 176, 0, 12, 1},
+ {58, 176, 4, 12, 1},
+ {60, 176, 8, 12, 1},
+ {62, 177, 0, 12, 1},
+ {64, 177, 4, 12, 1},
+ {100, 183, 4, 12, 1},
+ {102, 183, 8, 12, 1},
+ {104, 184, 0, 12, 1},
+ {106, 184, 4, 12, 1},
+ {108, 184, 8, 12, 1},
+ {110, 185, 0, 12, 1},
+ {112, 185, 4, 12, 1},
+ {114, 185, 8, 12, 1},
+ {116, 186, 0, 12, 1},
+ {118, 186, 4, 12, 1},
+ {120, 186, 8, 12, 1},
+ {122, 187, 0, 12, 1},
+ {124, 187, 4, 12, 1},
+ {126, 187, 8, 12, 1},
+ {128, 188, 0, 12, 1},
+ {130, 188, 4, 12, 1},
+ {132, 188, 8, 12, 1},
+ {134, 189, 0, 12, 1},
+ {136, 189, 4, 12, 1},
+ {138, 189, 8, 12, 1},
+ {140, 190, 0, 12, 1},
+ {149, 191, 6, 12, 1},
+ {151, 191, 10, 12, 1},
+ {153, 192, 2, 12, 1},
+ {155, 192, 6, 12, 1},
+ {157, 192, 10, 12, 1},
+ {159, 193, 2, 12, 1},
+ {161, 193, 6, 12, 1},
+ {165, 194, 2, 12, 1},
+ {184, 164, 0, 12, 1},
+ {188, 164, 4, 12, 1},
+ {192, 165, 8, 12, 1},
+ {196, 166, 0, 12, 1},
+};
+
+static const struct rf_channel rf_vals_5592_xtal40[] = {
+ /* Channel, N, K, mod, R */
+ {1, 241, 2, 10, 3},
+ {2, 241, 7, 10, 3},
+ {3, 242, 2, 10, 3},
+ {4, 242, 7, 10, 3},
+ {5, 243, 2, 10, 3},
+ {6, 243, 7, 10, 3},
+ {7, 244, 2, 10, 3},
+ {8, 244, 7, 10, 3},
+ {9, 245, 2, 10, 3},
+ {10, 245, 7, 10, 3},
+ {11, 246, 2, 10, 3},
+ {12, 246, 7, 10, 3},
+ {13, 247, 2, 10, 3},
+ {14, 248, 4, 10, 3},
+ {36, 86, 4, 12, 1},
+ {38, 86, 6, 12, 1},
+ {40, 86, 8, 12, 1},
+ {42, 86, 10, 12, 1},
+ {44, 87, 0, 12, 1},
+ {46, 87, 2, 12, 1},
+ {48, 87, 4, 12, 1},
+ {50, 87, 6, 12, 1},
+ {52, 87, 8, 12, 1},
+ {54, 87, 10, 12, 1},
+ {56, 88, 0, 12, 1},
+ {58, 88, 2, 12, 1},
+ {60, 88, 4, 12, 1},
+ {62, 88, 6, 12, 1},
+ {64, 88, 8, 12, 1},
+ {100, 91, 8, 12, 1},
+ {102, 91, 10, 12, 1},
+ {104, 92, 0, 12, 1},
+ {106, 92, 2, 12, 1},
+ {108, 92, 4, 12, 1},
+ {110, 92, 6, 12, 1},
+ {112, 92, 8, 12, 1},
+ {114, 92, 10, 12, 1},
+ {116, 93, 0, 12, 1},
+ {118, 93, 2, 12, 1},
+ {120, 93, 4, 12, 1},
+ {122, 93, 6, 12, 1},
+ {124, 93, 8, 12, 1},
+ {126, 93, 10, 12, 1},
+ {128, 94, 0, 12, 1},
+ {130, 94, 2, 12, 1},
+ {132, 94, 4, 12, 1},
+ {134, 94, 6, 12, 1},
+ {136, 94, 8, 12, 1},
+ {138, 94, 10, 12, 1},
+ {140, 95, 0, 12, 1},
+ {149, 95, 9, 12, 1},
+ {151, 95, 11, 12, 1},
+ {153, 96, 1, 12, 1},
+ {155, 96, 3, 12, 1},
+ {157, 96, 5, 12, 1},
+ {159, 96, 7, 12, 1},
+ {161, 96, 9, 12, 1},
+ {165, 97, 1, 12, 1},
+ {184, 82, 0, 12, 1},
+ {188, 82, 4, 12, 1},
+ {192, 82, 8, 12, 1},
+ {196, 83, 0, 12, 1},
+};
+
static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
@@ -5130,6 +5889,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
char *default_power2;
unsigned int i;
u16 eeprom;
+ u32 reg;
/*
* Disable powersaving as default on PCI devices.
@@ -5211,8 +5971,22 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands |= SUPPORT_BAND_5GHZ;
spec->num_channels = ARRAY_SIZE(rf_vals_3x);
spec->channels = rf_vals_3x;
+ } else if (rt2x00_rf(rt2x00dev, RF5592)) {
+ spec->supported_bands |= SUPPORT_BAND_5GHZ;
+
+ rt2800_register_read(rt2x00dev, MAC_DEBUG_INDEX, &reg);
+ if (rt2x00_get_field32(reg, MAC_DEBUG_INDEX_XTAL)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal40);
+ spec->channels = rf_vals_5592_xtal40;
+ } else {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5592_xtal20);
+ spec->channels = rf_vals_5592_xtal20;
+ }
}
+ if (WARN_ON_ONCE(!spec->channels))
+ return -ENODEV;
+
/*
* Initialize HT information.
*/
@@ -5300,11 +6074,55 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
return 0;
}
+static int rt2800_probe_rt(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u32 rt;
+ u32 rev;
+
+ if (rt2x00_rt(rt2x00dev, RT3290))
+ rt2800_register_read(rt2x00dev, MAC_CSR0_3290, &reg);
+ else
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+
+ rt = rt2x00_get_field32(reg, MAC_CSR0_CHIPSET);
+ rev = rt2x00_get_field32(reg, MAC_CSR0_REVISION);
+
+ switch (rt) {
+ case RT2860:
+ case RT2872:
+ case RT2883:
+ case RT3070:
+ case RT3071:
+ case RT3090:
+ case RT3290:
+ case RT3352:
+ case RT3390:
+ case RT3572:
+ case RT5390:
+ case RT5392:
+ case RT5592:
+ break;
+ default:
+ rt2x00_err(rt2x00dev, "Invalid RT chipset 0x%04x, rev %04x detected\n",
+ rt, rev);
+ return -ENODEV;
+ }
+
+ rt2x00_set_rt(rt2x00dev, rt, rev);
+
+ return 0;
+}
+
int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
{
int retval;
u32 reg;
+ retval = rt2800_probe_rt(rt2x00dev);
+ if (retval)
+ return retval;
+
/*
* Allocate eeprom data.
*/
@@ -5546,7 +6364,8 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_OPERATIONAL:
break;
default:
- WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");
+ rt2x00_warn((struct rt2x00_dev *)hw->priv,
+ "Unknown AMPDU action\n");
}
return ret;
@@ -5563,7 +6382,7 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index ded73da4de0b..6f4a861af336 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -41,6 +41,7 @@
#include <linux/eeprom_93cx6.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt2x00soc.h"
#include "rt2800lib.h"
@@ -71,7 +72,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
return;
for (i = 0; i < 200; i++) {
- rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
+ rt2x00mmio_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
(rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
@@ -83,10 +84,10 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
}
if (i == 200)
- ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
+ rt2x00_err(rt2x00dev, "MCU request failed, no response from hardware\n");
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
#if defined(CONFIG_SOC_RT288X) || defined(CONFIG_SOC_RT305X)
@@ -115,7 +116,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
@@ -137,7 +138,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
!!eeprom->reg_chip_select);
- rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg);
}
static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
@@ -145,7 +146,7 @@ static int rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
struct eeprom_93cx6 eeprom;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom.data = rt2x00dev;
eeprom.register_read = rt2800pci_eepromregister_read;
@@ -209,20 +210,20 @@ static void rt2800pci_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
- rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg);
break;
default:
break;
@@ -240,13 +241,13 @@ static void rt2800pci_kick_queue(struct data_queue *queue)
case QID_AC_BE:
case QID_AC_BK:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
- entry->entry_idx);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
+ entry->entry_idx);
break;
case QID_MGMT:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5),
- entry->entry_idx);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX(5),
+ entry->entry_idx);
break;
default:
break;
@@ -260,20 +261,20 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
- rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_TIMER_EN, reg);
/*
* Wait for current invocation to finish. The tasklet
@@ -313,19 +314,19 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
*/
reg = 0;
rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+ rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
/*
* Write firmware to device.
*/
- rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data, len);
+ rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
+ rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
+ rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
- rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
return 0;
}
@@ -335,7 +336,7 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
*/
static bool rt2800pci_get_entry_state(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word;
if (entry->queue->qid == QID_RX) {
@@ -351,7 +352,7 @@ static bool rt2800pci_get_entry_state(struct queue_entry *entry)
static void rt2800pci_clear_entry(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 word;
@@ -369,8 +370,8 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
* Set RX IDX in register to inform hardware that we have
* handled this entry and it is available for reuse again.
*/
- rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
- entry->entry_idx);
+ rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX,
+ entry->entry_idx);
} else {
rt2x00_desc_read(entry_priv->desc, 1, &word);
rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 1);
@@ -380,60 +381,65 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
/*
* Initialize registers.
*/
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0,
- rt2x00dev->tx[0].limit);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR0,
+ entry_priv->desc_dma);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT0,
+ rt2x00dev->tx[0].limit);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX0, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX0, 0);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1,
- rt2x00dev->tx[1].limit);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR1,
+ entry_priv->desc_dma);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT1,
+ rt2x00dev->tx[1].limit);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX1, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX1, 0);
entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2,
- rt2x00dev->tx[2].limit);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR2,
+ entry_priv->desc_dma);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT2,
+ rt2x00dev->tx[2].limit);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX2, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX2, 0);
entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3,
- rt2x00dev->tx[3].limit);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0);
-
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR4, 0);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT4, 0);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX4, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX4, 0);
-
- rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR5, 0);
- rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT5, 0);
- rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX5, 0);
- rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX5, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR3,
+ entry_priv->desc_dma);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT3,
+ rt2x00dev->tx[3].limit);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX3, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX3, 0);
+
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR4, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT4, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX4, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX4, 0);
+
+ rt2x00mmio_register_write(rt2x00dev, TX_BASE_PTR5, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_MAX_CNT5, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_CTX_IDX5, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_DTX_IDX5, 0);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
- rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT,
- rt2x00dev->rx[0].limit);
- rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
- rt2x00dev->rx[0].limit - 1);
- rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
+ rt2x00mmio_register_write(rt2x00dev, RX_BASE_PTR,
+ entry_priv->desc_dma);
+ rt2x00mmio_register_write(rt2x00dev, RX_MAX_CNT,
+ rt2x00dev->rx[0].limit);
+ rt2x00mmio_register_write(rt2x00dev, RX_CRX_IDX,
+ rt2x00dev->rx[0].limit - 1);
+ rt2x00mmio_register_write(rt2x00dev, RX_DRX_IDX, 0);
rt2800_disable_wpdma(rt2x00dev);
- rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0);
+ rt2x00mmio_register_write(rt2x00dev, DELAY_INT_CFG, 0);
return 0;
}
@@ -452,8 +458,8 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
}
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
@@ -465,7 +471,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, INT_MASK_CSR_TX_FIFO_STATUS, 1);
rt2x00_set_field32(&reg, INT_MASK_CSR_AUTO_WAKEUP, 1);
}
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
if (state == STATE_RADIO_IRQ_OFF) {
@@ -487,7 +493,7 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
/*
* Reset DMA indexes
*/
- rt2x00pci_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00mmio_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
@@ -495,29 +501,29 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
- rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+ rt2x00mmio_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
- rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+ rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00mmio_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
if (rt2x00_is_pcie(rt2x00dev) &&
(rt2x00_rt(rt2x00dev, RT3572) ||
rt2x00_rt(rt2x00dev, RT5390) ||
rt2x00_rt(rt2x00dev, RT5392))) {
- rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AUX_CTRL, &reg);
rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
- rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg);
+ rt2x00mmio_register_write(rt2x00dev, AUX_CTRL, reg);
}
- rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+ rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
reg = 0;
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
- rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+ rt2x00mmio_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
return 0;
}
@@ -537,8 +543,8 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
return retval;
/* After resume MCU_BOOT_SIGNAL will trash these. */
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_RADIO_OFF, 0xff, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_RADIO_OFF);
@@ -553,8 +559,8 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00_is_soc(rt2x00dev)) {
rt2800_disable_radio(rt2x00dev);
- rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0);
- rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0);
+ rt2x00mmio_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+ rt2x00mmio_register_write(rt2x00dev, TX_PIN_CFG, 0);
}
}
@@ -566,10 +572,10 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
0, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKEUP);
} else if (state == STATE_SLEEP) {
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
- 0xffffffff);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
- 0xffffffff);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
+ 0xffffffff);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CID,
+ 0xffffffff);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, TOKEN_SLEEP,
0xff, 0x01);
}
@@ -610,8 +616,8 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -628,7 +634,7 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -682,7 +688,7 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
static void rt2800pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *rxd = entry_priv->desc;
u32 word;
@@ -742,10 +748,90 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
+static bool rt2800pci_txdone_entry_check(struct queue_entry *entry, u32 status)
+{
+ __le32 *txwi;
+ u32 word;
+ int wcid, tx_wcid;
+
+ wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
+
+ txwi = rt2800_drv_get_txwi(entry);
+ rt2x00_desc_read(txwi, 1, &word);
+ tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+
+ return (tx_wcid == wcid);
+}
+
+static bool rt2800pci_txdone_find_entry(struct queue_entry *entry, void *data)
+{
+ u32 status = *(u32 *)data;
+
+ /*
+ * rt2800pci hardware might reorder frames when exchanging traffic
+ * with multiple BA enabled STAs.
+ *
+ * For example, a tx queue
+ * [ STA1 | STA2 | STA1 | STA2 ]
+ * can result in tx status reports
+ * [ STA1 | STA1 | STA2 | STA2 ]
+ * when the hw decides to aggregate the frames for STA1 into one AMPDU.
+ *
+ * To mitigate this effect, associate the tx status to the first frame
+ * in the tx queue with a matching wcid.
+ */
+ if (rt2800pci_txdone_entry_check(entry, status) &&
+ !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
+ /*
+ * Got a matching frame, associate the tx status with
+ * the frame
+ */
+ entry->status = status;
+ set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
+ return true;
+ }
+
+ /* Check the next frame */
+ return false;
+}
+
+static bool rt2800pci_txdone_match_first(struct queue_entry *entry, void *data)
+{
+ u32 status = *(u32 *)data;
+
+ /*
+ * Find the first frame without tx status and assign this status to it
+ * regardless if it matches or not.
+ */
+ if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
+ /*
+ * Got a matching frame, associate the tx status with
+ * the frame
+ */
+ entry->status = status;
+ set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
+ return true;
+ }
+
+ /* Check the next frame */
+ return false;
+}
+static bool rt2800pci_txdone_release_entries(struct queue_entry *entry,
+ void *data)
+{
+ if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
+ rt2800_txdone_entry(entry, entry->status,
+ rt2800pci_get_txwi(entry));
+ return false;
+ }
+
+ /* No more frames to release */
+ return true;
+}
+
static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
- struct queue_entry *entry;
u32 status;
u8 qid;
int max_tx_done = 16;
@@ -757,8 +843,8 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* Unknown queue, this shouldn't happen. Just drop
* this tx status.
*/
- WARNING(rt2x00dev, "Got TX status report with "
- "unexpected pid %u, dropping\n", qid);
+ rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
+ qid);
break;
}
@@ -768,8 +854,8 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* The queue is NULL, this shouldn't happen. Stop
* processing here and drop the tx status
*/
- WARNING(rt2x00dev, "Got TX status for an unavailable "
- "queue %u, dropping\n", qid);
+ rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
+ qid);
break;
}
@@ -778,13 +864,37 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* The queue is empty. Stop processing here
* and drop the tx status.
*/
- WARNING(rt2x00dev, "Got TX status for an empty "
- "queue %u, dropping\n", qid);
+ rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
+ qid);
break;
}
- entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- rt2800_txdone_entry(entry, status, rt2800pci_get_txwi(entry));
+ /*
+ * Let's associate this tx status with the first
+ * matching frame.
+ */
+ if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
+ Q_INDEX, &status,
+ rt2800pci_txdone_find_entry)) {
+ /*
+ * We cannot match the tx status to any frame, so just
+ * use the first one.
+ */
+ if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
+ Q_INDEX, &status,
+ rt2800pci_txdone_match_first)) {
+ rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
+ qid);
+ break;
+ }
+ }
+
+ /*
+ * Release all frames with a valid tx status.
+ */
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
+ Q_INDEX, NULL,
+ rt2800pci_txdone_release_entries);
if (--max_tx_done == 0)
break;
@@ -803,9 +913,9 @@ static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
* access needs locking.
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, irq_field, 1);
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -846,15 +956,15 @@ static void rt2800pci_tbtt_tasklet(unsigned long data)
* interval every 64 beacons by 64us to mitigate this effect.
*/
if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 2)) {
- rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
(rt2x00dev->beacon_int * 16) - 1);
- rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
} else if (drv_data->tbtt_tick == (BCN_TBTT_OFFSET - 1)) {
- rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00mmio_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_INTERVAL,
(rt2x00dev->beacon_int * 16));
- rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00mmio_register_write(rt2x00dev, BCN_TIME_CFG, reg);
}
drv_data->tbtt_tick++;
drv_data->tbtt_tick %= BCN_TBTT_OFFSET;
@@ -867,7 +977,7 @@ static void rt2800pci_tbtt_tasklet(unsigned long data)
static void rt2800pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2x00pci_rxdone(rt2x00dev))
+ if (rt2x00mmio_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
@@ -905,14 +1015,13 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
* need to lock the kfifo.
*/
for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
- rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status);
+ rt2x00mmio_register_read(rt2x00dev, TX_STA_FIFO, &status);
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
if (!kfifo_put(&rt2x00dev->txstatus_fifo, &status)) {
- WARNING(rt2x00dev, "TX status FIFO overrun,"
- "drop tx status report.\n");
+ rt2x00_warn(rt2x00dev, "TX status FIFO overrun, drop tx status report\n");
break;
}
}
@@ -927,8 +1036,8 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
u32 reg, mask;
/* Read status and ACK all interrupts */
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg)
return IRQ_NONE;
@@ -968,9 +1077,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
* the tasklet will reenable the appropriate interrupts.
*/
spin_lock(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, &reg);
reg &= mask;
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
return IRQ_HANDLED;
@@ -1021,13 +1130,13 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
- .register_read = rt2x00pci_register_read,
- .register_read_lock = rt2x00pci_register_read, /* same for PCI */
- .register_write = rt2x00pci_register_write,
- .register_write_lock = rt2x00pci_register_write, /* same for PCI */
- .register_multiread = rt2x00pci_register_multiread,
- .register_multiwrite = rt2x00pci_register_multiwrite,
- .regbusy_read = rt2x00pci_regbusy_read,
+ .register_read = rt2x00mmio_register_read,
+ .register_read_lock = rt2x00mmio_register_read, /* same for PCI */
+ .register_write = rt2x00mmio_register_write,
+ .register_write_lock = rt2x00mmio_register_write, /* same for PCI */
+ .register_multiread = rt2x00mmio_register_multiread,
+ .register_multiwrite = rt2x00mmio_register_multiwrite,
+ .regbusy_read = rt2x00mmio_regbusy_read,
.read_eeprom = rt2800pci_read_eeprom,
.hwcrypt_disabled = rt2800pci_hwcrypt_disabled,
.drv_write_firmware = rt2800pci_write_firmware,
@@ -1046,8 +1155,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.get_firmware_name = rt2800pci_get_firmware_name,
.check_firmware = rt2800_check_firmware,
.load_firmware = rt2800_load_firmware,
- .initialize = rt2x00pci_initialize,
- .uninitialize = rt2x00pci_uninitialize,
+ .initialize = rt2x00mmio_initialize,
+ .uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt2800pci_get_entry_state,
.clear_entry = rt2800pci_clear_entry,
.set_device_state = rt2800pci_set_device_state,
@@ -1060,7 +1169,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.start_queue = rt2800pci_start_queue,
.kick_queue = rt2800pci_kick_queue,
.stop_queue = rt2800pci_stop_queue,
- .flush_queue = rt2x00pci_flush_queue,
+ .flush_queue = rt2x00mmio_flush_queue,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
@@ -1081,21 +1190,24 @@ static const struct data_queue_desc rt2800pci_queue_rx = {
.entry_num = 128,
.data_size = AGGREGATION_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .winfo_size = RXWI_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2800pci_queue_tx = {
.entry_num = 64,
.data_size = AGGREGATION_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .winfo_size = TXWI_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt2800pci_queue_bcn = {
.entry_num = 8,
.data_size = 0, /* No DMA required for beacons */
- .desc_size = TXWI_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .desc_size = TXD_DESC_SIZE,
+ .winfo_size = TXWI_DESC_SIZE,
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct rt2x00_ops rt2800pci_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 098613ed93fb..ac854d75bd6c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -128,9 +128,9 @@ static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry)
tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
if (unlikely(tout))
- WARNING(entry->queue->rt2x00dev,
- "TX status timeout for entry %d in queue %d\n",
- entry->entry_idx, entry->queue->qid);
+ rt2x00_warn(entry->queue->rt2x00dev,
+ "TX status timeout for entry %d in queue %d\n",
+ entry->entry_idx, entry->queue->qid);
return tout;
}
@@ -154,7 +154,8 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
bool valid;
if (urb_status) {
- WARNING(rt2x00dev, "TX status read failed %d\n", urb_status);
+ rt2x00_warn(rt2x00dev, "TX status read failed %d\n",
+ urb_status);
goto stop_reading;
}
@@ -162,7 +163,7 @@ static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
valid = rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID);
if (valid) {
if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status))
- WARNING(rt2x00dev, "TX status FIFO overrun\n");
+ rt2x00_warn(rt2x00dev, "TX status FIFO overrun\n");
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
@@ -269,7 +270,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
0, USB_MODE_FIRMWARE,
REGISTER_TIMEOUT_FIRMWARE);
if (status < 0) {
- ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
+ rt2x00_err(rt2x00dev, "Failed to write Firmware to device\n");
return status;
}
@@ -392,8 +393,8 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -408,8 +409,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
- WARNING(rt2x00dev, "TX HW queue 0 timed out,"
- " invoke forced kick\n");
+ rt2x00_warn(rt2x00dev, "TX HW queue 0 timed out, invoke forced kick\n");
rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012);
@@ -424,8 +424,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
- WARNING(rt2x00dev, "TX HW queue 1 timed out,"
- " invoke forced kick\n");
+ rt2x00_warn(rt2x00dev, "TX HW queue 1 timed out, invoke forced kick\n");
rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
@@ -485,7 +484,7 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
*/
skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txi;
- skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
+ skbdesc->desc_len = TXINFO_DESC_SIZE + entry->queue->winfo_size;
}
/*
@@ -540,9 +539,9 @@ rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
tx_pid = rt2x00_get_field32(word, TXWI_W1_PACKETID);
if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
- DEBUG(entry->queue->rt2x00dev,
- "TX status report missed for queue %d entry %d\n",
- entry->queue->qid, entry->entry_idx);
+ rt2x00_dbg(entry->queue->rt2x00dev,
+ "TX status report missed for queue %d entry %d\n",
+ entry->queue->qid, entry->entry_idx);
return TXDONE_UNKNOWN;
}
@@ -566,8 +565,8 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(rt2x00queue_empty(queue))) {
- WARNING(rt2x00dev, "Got TX status for an empty "
- "queue %u, dropping\n", qid);
+ rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
+ qid);
break;
}
@@ -575,8 +574,8 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
- WARNING(rt2x00dev, "Data pending for entry %u "
- "in queue %u\n", entry->entry_idx, qid);
+ rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
+ entry->entry_idx, qid);
break;
}
@@ -677,8 +676,8 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
*/
if (unlikely(rx_pkt_len == 0 ||
rx_pkt_len > entry->queue->data_size)) {
- ERROR(entry->queue->rt2x00dev,
- "Bad frame size %d, forcing to 0\n", rx_pkt_len);
+ rt2x00_err(entry->queue->rt2x00dev,
+ "Bad frame size %d, forcing to 0\n", rx_pkt_len);
return;
}
@@ -853,21 +852,24 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
static const struct data_queue_desc rt2800usb_queue_rx = {
.entry_num = 128,
.data_size = AGGREGATION_SIZE,
- .desc_size = RXINFO_DESC_SIZE + RXWI_DESC_SIZE,
+ .desc_size = RXINFO_DESC_SIZE,
+ .winfo_size = RXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2800usb_queue_tx = {
.entry_num = 16,
.data_size = AGGREGATION_SIZE,
- .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
+ .desc_size = TXINFO_DESC_SIZE,
+ .winfo_size = TXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
static const struct data_queue_desc rt2800usb_queue_bcn = {
.entry_num = 8,
.data_size = MGMT_FRAME_SIZE,
- .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE,
+ .desc_size = TXINFO_DESC_SIZE,
+ .winfo_size = TXWI_DESC_SIZE,
.priv_size = sizeof(struct queue_entry_priv_usb),
};
@@ -890,6 +892,50 @@ static const struct rt2x00_ops rt2800usb_ops = {
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
};
+static const struct data_queue_desc rt2800usb_queue_rx_5592 = {
+ .entry_num = 128,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = RXINFO_DESC_SIZE,
+ .winfo_size = RXWI_DESC_SIZE_5592,
+ .priv_size = sizeof(struct queue_entry_priv_usb),
+};
+
+static const struct data_queue_desc rt2800usb_queue_tx_5592 = {
+ .entry_num = 16,
+ .data_size = AGGREGATION_SIZE,
+ .desc_size = TXINFO_DESC_SIZE,
+ .winfo_size = TXWI_DESC_SIZE_5592,
+ .priv_size = sizeof(struct queue_entry_priv_usb),
+};
+
+static const struct data_queue_desc rt2800usb_queue_bcn_5592 = {
+ .entry_num = 8,
+ .data_size = MGMT_FRAME_SIZE,
+ .desc_size = TXINFO_DESC_SIZE,
+ .winfo_size = TXWI_DESC_SIZE_5592,
+ .priv_size = sizeof(struct queue_entry_priv_usb),
+};
+
+
+static const struct rt2x00_ops rt2800usb_ops_5592 = {
+ .name = KBUILD_MODNAME,
+ .drv_data_size = sizeof(struct rt2800_drv_data),
+ .max_ap_intf = 8,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .tx_queues = NUM_TX_QUEUES,
+ .extra_tx_headroom = TXINFO_DESC_SIZE + TXWI_DESC_SIZE_5592,
+ .rx = &rt2800usb_queue_rx_5592,
+ .tx = &rt2800usb_queue_tx_5592,
+ .bcn = &rt2800usb_queue_bcn_5592,
+ .lib = &rt2800usb_rt2x00_ops,
+ .drv = &rt2800usb_rt2800_ops,
+ .hw = &rt2800usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2800_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
/*
* rt2800usb module information.
*/
@@ -1200,6 +1246,18 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x148f, 0x5370) },
{ USB_DEVICE(0x148f, 0x5372) },
#endif
+#ifdef CONFIG_RT2800USB_RT55XX
+ /* Arcadyan */
+ { USB_DEVICE(0x043e, 0x7a32), .driver_info = 5592 },
+ /* AVM GmbH */
+ { USB_DEVICE(0x057c, 0x8501), .driver_info = 5592 },
+ /* D-Link DWA-160-B2 */
+ { USB_DEVICE(0x2001, 0x3c1a), .driver_info = 5592 },
+ /* Proware */
+ { USB_DEVICE(0x043e, 0x7a13), .driver_info = 5592 },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x5572), .driver_info = 5592 },
+#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
* Unclear what kind of devices these are (they aren't supported by the
@@ -1303,6 +1361,9 @@ MODULE_LICENSE("GPL");
static int rt2800usb_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
+ if (id->driver_info == 5592)
+ return rt2x00usb_probe(usb_intf, &rt2800usb_ops_5592);
+
return rt2x00usb_probe(usb_intf, &rt2800usb_ops);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 086abb403a4f..7510723a8c37 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -54,47 +54,36 @@
#define DRV_VERSION "2.3.0"
#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
-/*
- * Debug definitions.
+/* Debug definitions.
* Debug output has to be enabled during compile time.
*/
-#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \
- printk(__kernlvl "%s -> %s: %s - " __msg, \
- wiphy_name((__dev)->hw->wiphy), __func__, __lvl, ##__args)
-
-#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \
- printk(__kernlvl "%s -> %s: %s - " __msg, \
- KBUILD_MODNAME, __func__, __lvl, ##__args)
-
#ifdef CONFIG_RT2X00_DEBUG
-#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args)
-#else
-#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
- do { } while (0)
+#define DEBUG
#endif /* CONFIG_RT2X00_DEBUG */
-/*
- * Various debug levels.
- * The debug levels PANIC and ERROR both indicate serious problems,
- * for this reason they should never be ignored.
- * The special ERROR_PROBE message is for messages that are generated
- * when the rt2x00_dev is not yet initialized.
+/* Utility printing macros
+ * rt2x00_probe_err is for messages when rt2x00_dev is uninitialized
*/
-#define PANIC(__dev, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args)
-#define ERROR(__dev, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args)
-#define ERROR_PROBE(__msg, __args...) \
- DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
-#define WARNING(__dev, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, KERN_WARNING, "Warning", __msg, ##__args)
-#define INFO(__dev, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, KERN_INFO, "Info", __msg, ##__args)
-#define DEBUG(__dev, __msg, __args...) \
- DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
-#define EEPROM(__dev, __msg, __args...) \
- DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
+#define rt2x00_probe_err(fmt, ...) \
+ printk(KERN_ERR KBUILD_MODNAME ": %s: Error - " fmt, \
+ __func__, ##__VA_ARGS__)
+#define rt2x00_err(dev, fmt, ...) \
+ wiphy_err((dev)->hw->wiphy, "%s: Error - " fmt, \
+ __func__, ##__VA_ARGS__)
+#define rt2x00_warn(dev, fmt, ...) \
+ wiphy_warn((dev)->hw->wiphy, "%s: Warning - " fmt, \
+ __func__, ##__VA_ARGS__)
+#define rt2x00_info(dev, fmt, ...) \
+ wiphy_info((dev)->hw->wiphy, "%s: Info - " fmt, \
+ __func__, ##__VA_ARGS__)
+
+/* Various debug levels */
+#define rt2x00_dbg(dev, fmt, ...) \
+ wiphy_dbg((dev)->hw->wiphy, "%s: Debug - " fmt, \
+ __func__, ##__VA_ARGS__)
+#define rt2x00_eeprom_dbg(dev, fmt, ...) \
+ wiphy_dbg((dev)->hw->wiphy, "%s: EEPROM recovery - " fmt, \
+ __func__, ##__VA_ARGS__)
/*
* Duration calculations
@@ -193,6 +182,7 @@ struct rt2x00_chip {
#define RT3883 0x3883 /* WSOC */
#define RT5390 0x5390 /* 2.4GHz */
#define RT5392 0x5392 /* 2.4GHz */
+#define RT5592 0x5592
u16 rf;
u16 rev;
@@ -1064,8 +1054,7 @@ static inline void rt2x00_rf_write(struct rt2x00_dev *rt2x00dev,
}
/*
- * Generic EEPROM access.
- * The EEPROM is being accessed by word index.
+ * Generic EEPROM access. The EEPROM is being accessed by word or byte index.
*/
static inline void *rt2x00_eeprom_addr(struct rt2x00_dev *rt2x00dev,
const unsigned int word)
@@ -1085,6 +1074,12 @@ static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev,
rt2x00dev->eeprom[word] = cpu_to_le16(data);
}
+static inline u8 rt2x00_eeprom_byte(struct rt2x00_dev *rt2x00dev,
+ const unsigned int byte)
+{
+ return *(((u8 *)rt2x00dev->eeprom) + byte);
+}
+
/*
* Chipset handlers
*/
@@ -1095,9 +1090,27 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
rt2x00dev->chip.rf = rf;
rt2x00dev->chip.rev = rev;
- INFO(rt2x00dev,
- "Chipset detected - rt: %04x, rf: %04x, rev: %04x.\n",
- rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
+ rt2x00_info(rt2x00dev, "Chipset detected - rt: %04x, rf: %04x, rev: %04x\n",
+ rt2x00dev->chip.rt, rt2x00dev->chip.rf,
+ rt2x00dev->chip.rev);
+}
+
+static inline void rt2x00_set_rt(struct rt2x00_dev *rt2x00dev,
+ const u16 rt, const u16 rev)
+{
+ rt2x00dev->chip.rt = rt;
+ rt2x00dev->chip.rev = rev;
+
+ rt2x00_info(rt2x00dev, "RT chipset %04x, rev %04x detected\n",
+ rt2x00dev->chip.rt, rt2x00dev->chip.rev);
+}
+
+static inline void rt2x00_set_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
+{
+ rt2x00dev->chip.rf = rf;
+
+ rt2x00_info(rt2x00dev, "RF chipset %04x detected\n",
+ rt2x00dev->chip.rf);
}
static inline bool rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
@@ -1360,7 +1373,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 49a63e973934..8cb43f8f3efc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -184,7 +184,7 @@ static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
/*
* Initialize center channel to current channel.
*/
- center_channel = spec->channels[conf->channel->hw_value].channel;
+ center_channel = spec->channels[conf->chandef.chan->hw_value].channel;
/*
* Adjust center channel to HT40+ and HT40- operation.
@@ -199,7 +199,7 @@ static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
return i;
WARN_ON(1);
- return conf->channel->hw_value;
+ return conf->chandef.chan->hw_value;
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
@@ -227,7 +227,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
} else {
clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
- hw_value = conf->channel->hw_value;
+ hw_value = conf->chandef.chan->hw_value;
}
memcpy(&libconf.rf,
@@ -279,8 +279,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
else
clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
- rt2x00dev->curr_band = conf->channel->band;
- rt2x00dev->curr_freq = conf->channel->center_freq;
+ rt2x00dev->curr_band = conf->chandef.chan->band;
+ rt2x00dev->curr_freq = conf->chandef.chan->center_freq;
rt2x00dev->tx_power = conf->power_level;
rt2x00dev->short_retry = conf->short_frame_max_tx_count;
rt2x00dev->long_retry = conf->long_frame_max_tx_count;
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 3bb8cafbac59..fe7a7f63a9ed 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -174,7 +174,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
do_gettimeofday(&timestamp);
if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) {
- DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n");
+ rt2x00_dbg(rt2x00dev, "txrx dump queue length exceeded\n");
return;
}
@@ -185,7 +185,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,
GFP_ATOMIC);
if (!skbcopy) {
- DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
+ rt2x00_dbg(rt2x00dev, "Failed to copy skb for dump\n");
return;
}
@@ -657,7 +657,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
if (!intf) {
- ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
+ rt2x00_err(rt2x00dev, "Failed to allocate debug handler\n");
return;
}
@@ -760,7 +760,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
exit:
rt2x00debug_deregister(rt2x00dev);
- ERROR(rt2x00dev, "Failed to register debug handler.\n");
+ rt2x00_err(rt2x00dev, "Failed to register debug handler\n");
}
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 189744db65e0..90dc14336980 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -171,7 +171,7 @@ static void rt2x00lib_autowakeup(struct work_struct *work)
return;
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
- ERROR(rt2x00dev, "Device failed to wakeup.\n");
+ rt2x00_err(rt2x00dev, "Device failed to wakeup\n");
clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
}
@@ -673,9 +673,8 @@ static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
break;
}
- WARNING(rt2x00dev, "Frame received with unrecognized signal, "
- "mode=0x%.4x, signal=0x%.4x, type=%d.\n",
- rxdesc->rate_mode, signal, type);
+ rt2x00_warn(rt2x00dev, "Frame received with unrecognized signal, mode=0x%.4x, signal=0x%.4x, type=%d\n",
+ rxdesc->rate_mode, signal, type);
return 0;
}
@@ -720,8 +719,8 @@ void rt2x00lib_rxdone(struct queue_entry *entry, gfp_t gfp)
*/
if (unlikely(rxdesc.size == 0 ||
rxdesc.size > entry->queue->data_size)) {
- ERROR(rt2x00dev, "Wrong frame size %d max %d.\n",
- rxdesc.size, entry->queue->data_size);
+ rt2x00_err(rt2x00dev, "Wrong frame size %d max %d\n",
+ rxdesc.size, entry->queue->data_size);
dev_kfree_skb(entry->skb);
goto renew_skb;
}
@@ -1006,7 +1005,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
exit_free_channels:
kfree(channels);
- ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
+ rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
return -ENOMEM;
}
@@ -1337,7 +1336,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
if (retval) {
- ERROR(rt2x00dev, "Failed to allocate device.\n");
+ rt2x00_err(rt2x00dev, "Failed to allocate device\n");
goto exit;
}
@@ -1353,7 +1352,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
retval = rt2x00lib_probe_hw(rt2x00dev);
if (retval) {
- ERROR(rt2x00dev, "Failed to initialize hw.\n");
+ rt2x00_err(rt2x00dev, "Failed to initialize hw\n");
goto exit;
}
@@ -1451,7 +1450,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
#ifdef CONFIG_PM
int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
{
- DEBUG(rt2x00dev, "Going to sleep.\n");
+ rt2x00_dbg(rt2x00dev, "Going to sleep\n");
/*
* Prevent mac80211 from accessing driver while suspended.
@@ -1482,8 +1481,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
* device is as good as disabled.
*/
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP))
- WARNING(rt2x00dev, "Device failed to enter sleep state, "
- "continue suspending.\n");
+ rt2x00_warn(rt2x00dev, "Device failed to enter sleep state, continue suspending\n");
return 0;
}
@@ -1491,7 +1489,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
{
- DEBUG(rt2x00dev, "Waking up.\n");
+ rt2x00_dbg(rt2x00dev, "Waking up\n");
/*
* Restore/enable extra components.
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index f316aad30612..1b4254b4272d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -42,28 +42,28 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
*/
fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
if (!fw_name) {
- ERROR(rt2x00dev,
- "Invalid firmware filename.\n"
- "Please file bug report to %s.\n", DRV_PROJECT);
+ rt2x00_err(rt2x00dev,
+ "Invalid firmware filename\n"
+ "Please file bug report to %s\n", DRV_PROJECT);
return -EINVAL;
}
- INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
+ rt2x00_info(rt2x00dev, "Loading firmware file '%s'\n", fw_name);
retval = request_firmware(&fw, fw_name, device);
if (retval) {
- ERROR(rt2x00dev, "Failed to request Firmware.\n");
+ rt2x00_err(rt2x00dev, "Failed to request Firmware\n");
return retval;
}
if (!fw || !fw->size || !fw->data) {
- ERROR(rt2x00dev, "Failed to read Firmware.\n");
+ rt2x00_err(rt2x00dev, "Failed to read Firmware\n");
release_firmware(fw);
return -ENOENT;
}
- INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
- fw->data[fw->size - 4], fw->data[fw->size - 3]);
+ rt2x00_info(rt2x00dev, "Firmware detected - version: %d.%d\n",
+ fw->data[fw->size - 4], fw->data[fw->size - 3]);
snprintf(rt2x00dev->hw->wiphy->fw_version,
sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d",
fw->data[fw->size - 4], fw->data[fw->size - 3]);
@@ -73,15 +73,14 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
case FW_OK:
break;
case FW_BAD_CRC:
- ERROR(rt2x00dev, "Firmware checksum error.\n");
+ rt2x00_err(rt2x00dev, "Firmware checksum error\n");
goto exit;
case FW_BAD_LENGTH:
- ERROR(rt2x00dev,
- "Invalid firmware file length (len=%zu)\n", fw->size);
+ rt2x00_err(rt2x00dev, "Invalid firmware file length (len=%zu)\n",
+ fw->size);
goto exit;
case FW_BAD_VERSION:
- ERROR(rt2x00dev,
- "Current firmware does not support detected chipset.\n");
+ rt2x00_err(rt2x00dev, "Current firmware does not support detected chipset\n");
goto exit;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index 8679d781a264..997a6c89e66e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -113,7 +113,7 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
retval = led_classdev_register(device, &led->led_dev);
if (retval) {
- ERROR(rt2x00dev, "Failed to register led handler.\n");
+ rt2x00_err(rt2x00dev, "Failed to register led handler\n");
return retval;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 20c6eccce5aa..f883802f3505 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -46,7 +46,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom);
if (unlikely(!skb)) {
- WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
+ rt2x00_warn(rt2x00dev, "Failed to create RTS/CTS frame\n");
return -ENOMEM;
}
@@ -93,7 +93,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
retval = rt2x00queue_write_tx_frame(queue, skb, true);
if (retval) {
dev_kfree_skb_any(skb);
- WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
+ rt2x00_warn(rt2x00dev, "Failed to send RTS/CTS frame\n");
}
return retval;
@@ -126,9 +126,9 @@ void rt2x00mac_tx(struct ieee80211_hw *hw,
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
if (unlikely(!queue)) {
- ERROR(rt2x00dev,
- "Attempt to send packet over invalid queue %d.\n"
- "Please file bug report to %s.\n", qid, DRV_PROJECT);
+ rt2x00_err(rt2x00dev,
+ "Attempt to send packet over invalid queue %d\n"
+ "Please file bug report to %s\n", qid, DRV_PROJECT);
goto exit_free_skb;
}
@@ -731,9 +731,10 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
queue->aifs = params->aifs;
queue->txop = params->txop;
- DEBUG(rt2x00dev,
- "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d.\n",
- queue_idx, queue->cw_min, queue->cw_max, queue->aifs, queue->txop);
+ rt2x00_dbg(rt2x00dev,
+ "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d\n",
+ queue_idx, queue->cw_min, queue->cw_max, queue->aifs,
+ queue->txop);
return 0;
}
@@ -748,7 +749,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.c b/drivers/net/wireless/rt2x00/rt2x00mmio.c
new file mode 100644
index 000000000000..64b06c6abe58
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mmio.c
@@ -0,0 +1,216 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mmio
+ Abstract: rt2x00 generic mmio device routines.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "rt2x00.h"
+#include "rt2x00mmio.h"
+
+/*
+ * Register access.
+ */
+int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg)
+{
+ unsigned int i;
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00mmio_register_read(rt2x00dev, offset, reg);
+ if (!rt2x00_get_field32(*reg, field))
+ return 1;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ printk_once(KERN_ERR "%s() Indirect register access failed: "
+ "offset=0x%.08x, value=0x%.08x\n", __func__, offset, *reg);
+ *reg = ~0;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mmio_regbusy_read);
+
+bool rt2x00mmio_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue = rt2x00dev->rx;
+ struct queue_entry *entry;
+ struct queue_entry_priv_mmio *entry_priv;
+ struct skb_frame_desc *skbdesc;
+ int max_rx = 16;
+
+ while (--max_rx) {
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ entry_priv = entry->priv_data;
+
+ if (rt2x00dev->ops->lib->get_entry_state(entry))
+ break;
+
+ /*
+ * Fill in desc fields of the skb descriptor
+ */
+ skbdesc = get_skb_frame_desc(entry->skb);
+ skbdesc->desc = entry_priv->desc;
+ skbdesc->desc_len = entry->queue->desc_size;
+
+ /*
+ * DMA is already done, notify rt2x00lib that
+ * it finished successfully.
+ */
+ rt2x00lib_dmastart(entry);
+ rt2x00lib_dmadone(entry);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, GFP_ATOMIC);
+ }
+
+ return !max_rx;
+}
+EXPORT_SYMBOL_GPL(rt2x00mmio_rxdone);
+
+void rt2x00mmio_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+
+ for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
+ msleep(10);
+}
+EXPORT_SYMBOL_GPL(rt2x00mmio_flush_queue);
+
+/*
+ * Device initialization handlers.
+ */
+static int rt2x00mmio_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
+{
+ struct queue_entry_priv_mmio *entry_priv;
+ void *addr;
+ dma_addr_t dma;
+ unsigned int i;
+
+ /*
+ * Allocate DMA memory for descriptor and buffer.
+ */
+ addr = dma_alloc_coherent(rt2x00dev->dev,
+ queue->limit * queue->desc_size,
+ &dma, GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ memset(addr, 0, queue->limit * queue->desc_size);
+
+ /*
+ * Initialize all queue entries to contain valid addresses.
+ */
+ for (i = 0; i < queue->limit; i++) {
+ entry_priv = queue->entries[i].priv_data;
+ entry_priv->desc = addr + i * queue->desc_size;
+ entry_priv->desc_dma = dma + i * queue->desc_size;
+ }
+
+ return 0;
+}
+
+static void rt2x00mmio_free_queue_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_queue *queue)
+{
+ struct queue_entry_priv_mmio *entry_priv =
+ queue->entries[0].priv_data;
+
+ if (entry_priv->desc)
+ dma_free_coherent(rt2x00dev->dev,
+ queue->limit * queue->desc_size,
+ entry_priv->desc, entry_priv->desc_dma);
+ entry_priv->desc = NULL;
+}
+
+int rt2x00mmio_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ queue_for_each(rt2x00dev, queue) {
+ status = rt2x00mmio_alloc_queue_dma(rt2x00dev, queue);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * Register interrupt handler.
+ */
+ status = request_irq(rt2x00dev->irq,
+ rt2x00dev->ops->lib->irq_handler,
+ IRQF_SHARED, rt2x00dev->name, rt2x00dev);
+ if (status) {
+ rt2x00_err(rt2x00dev, "IRQ %d allocation failed (error %d)\n",
+ rt2x00dev->irq, status);
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ queue_for_each(rt2x00dev, queue)
+ rt2x00mmio_free_queue_dma(rt2x00dev, queue);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00mmio_initialize);
+
+void rt2x00mmio_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * Free irq line.
+ */
+ free_irq(rt2x00dev->irq, rt2x00dev);
+
+ /*
+ * Free DMA
+ */
+ queue_for_each(rt2x00dev, queue)
+ rt2x00mmio_free_queue_dma(rt2x00dev, queue);
+}
+EXPORT_SYMBOL_GPL(rt2x00mmio_uninitialize);
+
+/*
+ * rt2x00mmio module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 mmio library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00mmio.h b/drivers/net/wireless/rt2x00/rt2x00mmio.h
new file mode 100644
index 000000000000..cda3dbcf7ead
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mmio.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mmio
+ Abstract: Data structures for the rt2x00mmio module.
+ */
+
+#ifndef RT2X00MMIO_H
+#define RT2X00MMIO_H
+
+#include <linux/io.h>
+
+/*
+ * Register access.
+ */
+static inline void rt2x00mmio_register_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 *value)
+{
+ *value = readl(rt2x00dev->csr.base + offset);
+}
+
+static inline void rt2x00mmio_register_multiread(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
+}
+
+static inline void rt2x00mmio_register_write(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u32 value)
+{
+ writel(value, rt2x00dev->csr.base + offset);
+}
+
+static inline void rt2x00mmio_register_multiwrite(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const void *value,
+ const u32 length)
+{
+ __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
+}
+
+/**
+ * rt2x00mmio_regbusy_read - Read from register with busy check
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @field: Field to check if register is busy
+ * @reg: Pointer to where register contents should be stored
+ *
+ * This function will read the given register, and checks if the
+ * register is busy. If it is, it will sleep for a couple of
+ * microseconds before reading the register again. If the register
+ * is not read after a certain timeout, this function will return
+ * FALSE.
+ */
+int rt2x00mmio_regbusy_read(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ const struct rt2x00_field32 field,
+ u32 *reg);
+
+/**
+ * struct queue_entry_priv_mmio: Per entry PCI specific information
+ *
+ * @desc: Pointer to device descriptor
+ * @desc_dma: DMA pointer to &desc.
+ * @data: Pointer to device's entry memory.
+ * @data_dma: DMA pointer to &data.
+ */
+struct queue_entry_priv_mmio {
+ __le32 *desc;
+ dma_addr_t desc_dma;
+};
+
+/**
+ * rt2x00mmio_rxdone - Handle RX done events
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ *
+ * Returns true if there are still rx frames pending and false if all
+ * pending rx frames were processed.
+ */
+bool rt2x00mmio_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00mmio_flush_queue - Flush data queue
+ * @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
+ *
+ * This will wait for a maximum of 100ms, waiting for the queues
+ * to become empty.
+ */
+void rt2x00mmio_flush_queue(struct data_queue *queue, bool drop);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00mmio_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00mmio_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+#endif /* RT2X00MMIO_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index a0c8caef3b0a..dc49e525ae5e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -33,182 +33,6 @@
#include "rt2x00pci.h"
/*
- * Register access.
- */
-int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const struct rt2x00_field32 field,
- u32 *reg)
-{
- unsigned int i;
-
- if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
- return 0;
-
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, offset, reg);
- if (!rt2x00_get_field32(*reg, field))
- return 1;
- udelay(REGISTER_BUSY_DELAY);
- }
-
- ERROR(rt2x00dev, "Indirect register access failed: "
- "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
- *reg = ~0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
-
-bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue = rt2x00dev->rx;
- struct queue_entry *entry;
- struct queue_entry_priv_pci *entry_priv;
- struct skb_frame_desc *skbdesc;
- int max_rx = 16;
-
- while (--max_rx) {
- entry = rt2x00queue_get_entry(queue, Q_INDEX);
- entry_priv = entry->priv_data;
-
- if (rt2x00dev->ops->lib->get_entry_state(entry))
- break;
-
- /*
- * Fill in desc fields of the skb descriptor
- */
- skbdesc = get_skb_frame_desc(entry->skb);
- skbdesc->desc = entry_priv->desc;
- skbdesc->desc_len = entry->queue->desc_size;
-
- /*
- * DMA is already done, notify rt2x00lib that
- * it finished successfully.
- */
- rt2x00lib_dmastart(entry);
- rt2x00lib_dmadone(entry);
-
- /*
- * Send the frame to rt2x00lib for further processing.
- */
- rt2x00lib_rxdone(entry, GFP_ATOMIC);
- }
-
- return !max_rx;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
-
-void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
-{
- unsigned int i;
-
- for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
- msleep(10);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
-
-/*
- * Device initialization handlers.
- */
-static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
-{
- struct queue_entry_priv_pci *entry_priv;
- void *addr;
- dma_addr_t dma;
- unsigned int i;
-
- /*
- * Allocate DMA memory for descriptor and buffer.
- */
- addr = dma_alloc_coherent(rt2x00dev->dev,
- queue->limit * queue->desc_size,
- &dma, GFP_KERNEL);
- if (!addr)
- return -ENOMEM;
-
- memset(addr, 0, queue->limit * queue->desc_size);
-
- /*
- * Initialize all queue entries to contain valid addresses.
- */
- for (i = 0; i < queue->limit; i++) {
- entry_priv = queue->entries[i].priv_data;
- entry_priv->desc = addr + i * queue->desc_size;
- entry_priv->desc_dma = dma + i * queue->desc_size;
- }
-
- return 0;
-}
-
-static void rt2x00pci_free_queue_dma(struct rt2x00_dev *rt2x00dev,
- struct data_queue *queue)
-{
- struct queue_entry_priv_pci *entry_priv =
- queue->entries[0].priv_data;
-
- if (entry_priv->desc)
- dma_free_coherent(rt2x00dev->dev,
- queue->limit * queue->desc_size,
- entry_priv->desc, entry_priv->desc_dma);
- entry_priv->desc = NULL;
-}
-
-int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
- int status;
-
- /*
- * Allocate DMA
- */
- queue_for_each(rt2x00dev, queue) {
- status = rt2x00pci_alloc_queue_dma(rt2x00dev, queue);
- if (status)
- goto exit;
- }
-
- /*
- * Register interrupt handler.
- */
- status = request_irq(rt2x00dev->irq,
- rt2x00dev->ops->lib->irq_handler,
- IRQF_SHARED, rt2x00dev->name, rt2x00dev);
- if (status) {
- ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
- rt2x00dev->irq, status);
- goto exit;
- }
-
- return 0;
-
-exit:
- queue_for_each(rt2x00dev, queue)
- rt2x00pci_free_queue_dma(rt2x00dev, queue);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
-
-void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- /*
- * Free irq line.
- */
- free_irq(rt2x00dev->irq, rt2x00dev);
-
- /*
- * Free DMA
- */
- queue_for_each(rt2x00dev, queue)
- rt2x00pci_free_queue_dma(rt2x00dev, queue);
-}
-EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
-
-/*
* PCI driver handlers.
*/
static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
@@ -244,7 +68,7 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
return 0;
exit:
- ERROR_PROBE("Failed to allocate registers.\n");
+ rt2x00_probe_err("Failed to allocate registers\n");
rt2x00pci_free_reg(rt2x00dev);
@@ -260,30 +84,30 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
retval = pci_enable_device(pci_dev);
if (retval) {
- ERROR_PROBE("Enable device failed.\n");
+ rt2x00_probe_err("Enable device failed\n");
return retval;
}
retval = pci_request_regions(pci_dev, pci_name(pci_dev));
if (retval) {
- ERROR_PROBE("PCI request regions failed.\n");
+ rt2x00_probe_err("PCI request regions failed\n");
goto exit_disable_device;
}
pci_set_master(pci_dev);
if (pci_set_mwi(pci_dev))
- ERROR_PROBE("MWI not available.\n");
+ rt2x00_probe_err("MWI not available\n");
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
- ERROR_PROBE("PCI DMA not supported.\n");
+ rt2x00_probe_err("PCI DMA not supported\n");
retval = -EIO;
goto exit_release_regions;
}
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
- ERROR_PROBE("Failed to allocate hardware.\n");
+ rt2x00_probe_err("Failed to allocate hardware\n");
retval = -ENOMEM;
goto exit_release_regions;
}
@@ -383,7 +207,7 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
if (pci_set_power_state(pci_dev, PCI_D0) ||
pci_enable_device(pci_dev)) {
- ERROR(rt2x00dev, "Failed to resume device.\n");
+ rt2x00_err(rt2x00dev, "Failed to resume device\n");
return -EIO;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index e2c99f2b9a14..60d90b20f8b9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -36,94 +36,6 @@
#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
/*
- * Register access.
- */
-static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- u32 *value)
-{
- *value = readl(rt2x00dev->csr.base + offset);
-}
-
-static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- void *value, const u32 length)
-{
- memcpy_fromio(value, rt2x00dev->csr.base + offset, length);
-}
-
-static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- u32 value)
-{
- writel(value, rt2x00dev->csr.base + offset);
-}
-
-static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const void *value,
- const u32 length)
-{
- __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
-}
-
-/**
- * rt2x00pci_regbusy_read - Read from register with busy check
- * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
- * @offset: Register offset
- * @field: Field to check if register is busy
- * @reg: Pointer to where register contents should be stored
- *
- * This function will read the given register, and checks if the
- * register is busy. If it is, it will sleep for a couple of
- * microseconds before reading the register again. If the register
- * is not read after a certain timeout, this function will return
- * FALSE.
- */
-int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
- const unsigned int offset,
- const struct rt2x00_field32 field,
- u32 *reg);
-
-/**
- * struct queue_entry_priv_pci: Per entry PCI specific information
- *
- * @desc: Pointer to device descriptor
- * @desc_dma: DMA pointer to &desc.
- * @data: Pointer to device's entry memory.
- * @data_dma: DMA pointer to &data.
- */
-struct queue_entry_priv_pci {
- __le32 *desc;
- dma_addr_t desc_dma;
-};
-
-/**
- * rt2x00pci_rxdone - Handle RX done events
- * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
- *
- * Returns true if there are still rx frames pending and false if all
- * pending rx frames were processed.
- */
-bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
-
-/**
- * rt2x00pci_flush_queue - Flush data queue
- * @queue: Data queue to stop
- * @drop: True to drop all pending frames.
- *
- * This will wait for a maximum of 100ms, waiting for the queues
- * to become empty.
- */
-void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
-
-/*
- * Device initialization handlers.
- */
-int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
-void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
-
-/*
* PCI driver handlers.
*/
int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 4d91795dc6a2..2c12311467a9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -35,7 +35,8 @@
struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct data_queue *queue = entry->queue;
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
struct sk_buff *skb;
struct skb_frame_desc *skbdesc;
unsigned int frame_size;
@@ -46,7 +47,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
* The frame size includes descriptor size, because the
* hardware directly receive the frame into the skbuffer.
*/
- frame_size = entry->queue->data_size + entry->queue->desc_size;
+ frame_size = queue->data_size + queue->desc_size + queue->winfo_size;
/*
* The payload should be aligned to a 4-byte boundary,
@@ -531,10 +532,10 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
*/
if (unlikely(rt2x00dev->ops->lib->get_entry_state &&
rt2x00dev->ops->lib->get_entry_state(entry))) {
- ERROR(rt2x00dev,
- "Corrupt queue %d, accessing entry which is not ours.\n"
- "Please file bug report to %s.\n",
- entry->queue->qid, DRV_PROJECT);
+ rt2x00_err(rt2x00dev,
+ "Corrupt queue %d, accessing entry which is not ours\n"
+ "Please file bug report to %s\n",
+ entry->queue->qid, DRV_PROJECT);
return -EINVAL;
}
@@ -698,8 +699,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
spin_lock(&queue->tx_lock);
if (unlikely(rt2x00queue_full(queue))) {
- ERROR(queue->rt2x00dev,
- "Dropping frame due to full tx queue %d.\n", queue->qid);
+ rt2x00_err(queue->rt2x00dev, "Dropping frame due to full tx queue %d\n",
+ queue->qid);
ret = -ENOBUFS;
goto out;
}
@@ -708,10 +709,10 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
&entry->flags))) {
- ERROR(queue->rt2x00dev,
- "Arrived at non-free entry in the non-full queue %d.\n"
- "Please file bug report to %s.\n",
- queue->qid, DRV_PROJECT);
+ rt2x00_err(queue->rt2x00dev,
+ "Arrived at non-free entry in the non-full queue %d\n"
+ "Please file bug report to %s\n",
+ queue->qid, DRV_PROJECT);
ret = -EINVAL;
goto out;
}
@@ -832,7 +833,9 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
- bool (*fn)(struct queue_entry *entry))
+ void *data,
+ bool (*fn)(struct queue_entry *entry,
+ void *data))
{
unsigned long irqflags;
unsigned int index_start;
@@ -840,9 +843,9 @@ bool rt2x00queue_for_each_entry(struct data_queue *queue,
unsigned int i;
if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
- ERROR(queue->rt2x00dev,
- "Entry requested from invalid index range (%d - %d)\n",
- start, end);
+ rt2x00_err(queue->rt2x00dev,
+ "Entry requested from invalid index range (%d - %d)\n",
+ start, end);
return true;
}
@@ -863,17 +866,17 @@ bool rt2x00queue_for_each_entry(struct data_queue *queue,
*/
if (index_start < index_end) {
for (i = index_start; i < index_end; i++) {
- if (fn(&queue->entries[i]))
+ if (fn(&queue->entries[i], data))
return true;
}
} else {
for (i = index_start; i < queue->limit; i++) {
- if (fn(&queue->entries[i]))
+ if (fn(&queue->entries[i], data))
return true;
}
for (i = 0; i < index_end; i++) {
- if (fn(&queue->entries[i]))
+ if (fn(&queue->entries[i], data))
return true;
}
}
@@ -889,8 +892,8 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
unsigned long irqflags;
if (unlikely(index >= Q_INDEX_MAX)) {
- ERROR(queue->rt2x00dev,
- "Entry requested from invalid index type (%d)\n", index);
+ rt2x00_err(queue->rt2x00dev, "Entry requested from invalid index type (%d)\n",
+ index);
return NULL;
}
@@ -910,8 +913,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
unsigned long irqflags;
if (unlikely(index >= Q_INDEX_MAX)) {
- ERROR(queue->rt2x00dev,
- "Index change on invalid index type (%d)\n", index);
+ rt2x00_err(queue->rt2x00dev,
+ "Index change on invalid index type (%d)\n", index);
return;
}
@@ -1071,7 +1074,8 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
* The queue flush has failed...
*/
if (unlikely(!rt2x00queue_empty(queue)))
- WARNING(queue->rt2x00dev, "Queue %d failed to flush\n", queue->qid);
+ rt2x00_warn(queue->rt2x00dev, "Queue %d failed to flush\n",
+ queue->qid);
/*
* Restore the queue to the previous status
@@ -1170,6 +1174,7 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue,
queue->threshold = DIV_ROUND_UP(qdesc->entry_num, 10);
queue->data_size = qdesc->data_size;
queue->desc_size = qdesc->desc_size;
+ queue->winfo_size = qdesc->winfo_size;
/*
* Allocate all queue entries.
@@ -1260,7 +1265,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
return 0;
exit:
- ERROR(rt2x00dev, "Queue entries allocation failed.\n");
+ rt2x00_err(rt2x00dev, "Queue entries allocation failed\n");
rt2x00queue_uninitialize(rt2x00dev);
@@ -1312,7 +1317,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
queue = kcalloc(rt2x00dev->data_queues, sizeof(*queue), GFP_KERNEL);
if (!queue) {
- ERROR(rt2x00dev, "Queue allocation failed.\n");
+ rt2x00_err(rt2x00dev, "Queue allocation failed\n");
return -ENOMEM;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 9b8c10a86dee..4a7b34e9261b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -359,6 +359,7 @@ enum queue_entry_flags {
ENTRY_DATA_PENDING,
ENTRY_DATA_IO_FAILED,
ENTRY_DATA_STATUS_PENDING,
+ ENTRY_DATA_STATUS_SET,
};
/**
@@ -372,6 +373,7 @@ enum queue_entry_flags {
* @entry_idx: The entry index number.
* @priv_data: Private data belonging to this queue entry. The pointer
* points to data specific to a particular driver and queue type.
+ * @status: Device specific status
*/
struct queue_entry {
unsigned long flags;
@@ -383,6 +385,8 @@ struct queue_entry {
unsigned int entry_idx;
+ u32 status;
+
void *priv_data;
};
@@ -475,7 +479,8 @@ struct data_queue {
unsigned short cw_max;
unsigned short data_size;
- unsigned short desc_size;
+ unsigned char desc_size;
+ unsigned char winfo_size;
unsigned short usb_endpoint;
unsigned short usb_maxpacket;
@@ -495,7 +500,8 @@ struct data_queue {
struct data_queue_desc {
unsigned short entry_num;
unsigned short data_size;
- unsigned short desc_size;
+ unsigned char desc_size;
+ unsigned char winfo_size;
unsigned short priv_size;
};
@@ -584,6 +590,7 @@ struct data_queue_desc {
* @queue: Pointer to @data_queue
* @start: &enum queue_index Pointer to start index
* @end: &enum queue_index Pointer to end index
+ * @data: Data to pass to the callback function
* @fn: The function to call for each &struct queue_entry
*
* This will walk through all entries in the queue, in chronological
@@ -596,7 +603,9 @@ struct data_queue_desc {
bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
- bool (*fn)(struct queue_entry *entry));
+ void *data,
+ bool (*fn)(struct queue_entry *entry,
+ void *data));
/**
* rt2x00queue_empty - Check if the queue is empty.
diff --git a/drivers/net/wireless/rt2x00/rt2x00soc.c b/drivers/net/wireless/rt2x00/rt2x00soc.c
index 2aa5c38022f3..9271a5fce0a8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00soc.c
+++ b/drivers/net/wireless/rt2x00/rt2x00soc.c
@@ -68,7 +68,7 @@ static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev)
return 0;
exit:
- ERROR_PROBE("Failed to allocate registers.\n");
+ rt2x00_probe_err("Failed to allocate registers\n");
rt2x00soc_free_reg(rt2x00dev);
return -ENOMEM;
@@ -82,7 +82,7 @@ int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops)
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
- ERROR_PROBE("Failed to allocate hardware.\n");
+ rt2x00_probe_err("Failed to allocate hardware\n");
return -ENOMEM;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 40ea80725a96..88289873c0cf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -70,9 +70,9 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
}
}
- ERROR(rt2x00dev,
- "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n",
- request, offset, status);
+ rt2x00_err(rt2x00dev,
+ "Vendor Request 0x%02x failed for offset 0x%04x with error %d\n",
+ request, offset, status);
return status;
}
@@ -91,7 +91,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
* Check for Cache availability.
*/
if (unlikely(!rt2x00dev->csr.cache || buffer_length > CSR_CACHE_SIZE)) {
- ERROR(rt2x00dev, "CSR cache not available.\n");
+ rt2x00_err(rt2x00dev, "CSR cache not available\n");
return -ENOMEM;
}
@@ -157,8 +157,8 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "Indirect register access failed: "
- "offset=0x%.08x, value=0x%.08x\n", offset, *reg);
+ rt2x00_err(rt2x00dev, "Indirect register access failed: offset=0x%.08x, value=0x%.08x\n",
+ offset, *reg);
*reg = ~0;
return 0;
@@ -285,7 +285,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
}
-static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -307,7 +307,7 @@ static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry)
status = skb_padto(entry->skb, length);
if (unlikely(status)) {
/* TODO: report something more appropriate than IO_FAILED. */
- WARNING(rt2x00dev, "TX SKB padding error, out of memory\n");
+ rt2x00_warn(rt2x00dev, "TX SKB padding error, out of memory\n");
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
@@ -390,7 +390,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
}
-static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -427,12 +427,18 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
case QID_AC_BE:
case QID_AC_BK:
if (!rt2x00queue_empty(queue))
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00queue_for_each_entry(queue,
+ Q_INDEX_DONE,
+ Q_INDEX,
+ NULL,
rt2x00usb_kick_tx_entry);
break;
case QID_RX:
if (!rt2x00queue_full(queue))
- rt2x00queue_for_each_entry(queue, Q_INDEX, Q_INDEX_DONE,
+ rt2x00queue_for_each_entry(queue,
+ Q_INDEX,
+ Q_INDEX_DONE,
+ NULL,
rt2x00usb_kick_rx_entry);
break;
default:
@@ -441,7 +447,7 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
-static bool rt2x00usb_flush_entry(struct queue_entry *entry)
+static bool rt2x00usb_flush_entry(struct queue_entry *entry, void *data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
@@ -468,7 +474,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue, bool drop)
unsigned int i;
if (drop)
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL,
rt2x00usb_flush_entry);
/*
@@ -514,8 +520,8 @@ EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);
static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
{
- WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
- " invoke forced forced reset\n", queue->qid);
+ rt2x00_warn(queue->rt2x00dev, "TX queue %d DMA timed out, invoke forced forced reset\n",
+ queue->qid);
rt2x00queue_flush_queue(queue, true);
}
@@ -559,7 +565,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
entry->flags = 0;
if (entry->queue->qid == QID_RX)
- rt2x00usb_kick_rx_entry(entry);
+ rt2x00usb_kick_rx_entry(entry, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
@@ -616,7 +622,7 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
* At least 1 endpoint for RX and 1 endpoint for TX must be available.
*/
if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) {
- ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
+ rt2x00_err(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n");
return -EPIPE;
}
@@ -769,7 +775,7 @@ static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
return 0;
exit:
- ERROR_PROBE("Failed to allocate registers.\n");
+ rt2x00_probe_err("Failed to allocate registers\n");
rt2x00usb_free_reg(rt2x00dev);
@@ -789,7 +795,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
if (!hw) {
- ERROR_PROBE("Failed to allocate hardware.\n");
+ rt2x00_probe_err("Failed to allocate hardware\n");
retval = -ENOMEM;
goto exit_put_device;
}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index f95792cfcf89..0dc8180e251b 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -35,6 +35,7 @@
#include <linux/eeprom_93cx6.h>
#include "rt2x00.h"
+#include "rt2x00mmio.h"
#include "rt2x00pci.h"
#include "rt61pci.h"
@@ -57,12 +58,12 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
* and we will print an error.
*/
#define WAIT_FOR_BBP(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg))
#define WAIT_FOR_RF(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
+ rt2x00mmio_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg))
#define WAIT_FOR_MCU(__dev, __reg) \
- rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \
- H2M_MAILBOX_CSR_OWNER, (__reg))
+ rt2x00mmio_regbusy_read((__dev), H2M_MAILBOX_CSR, \
+ H2M_MAILBOX_CSR_OWNER, (__reg))
static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
const unsigned int word, const u8 value)
@@ -82,7 +83,7 @@ static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg);
}
mutex_unlock(&rt2x00dev->csr_mutex);
@@ -109,7 +110,7 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR3, reg);
WAIT_FOR_BBP(rt2x00dev, &reg);
}
@@ -137,7 +138,7 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR4, reg);
rt2x00_rf_write(rt2x00dev, word, value);
}
@@ -161,12 +162,12 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
- rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, reg);
}
mutex_unlock(&rt2x00dev->csr_mutex);
@@ -178,7 +179,7 @@ static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
@@ -200,15 +201,15 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
!!eeprom->reg_chip_select);
- rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, E2PROM_CSR, reg);
}
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
static const struct rt2x00debug rt61pci_rt2x00debug = {
.owner = THIS_MODULE,
.csr = {
- .read = rt2x00pci_register_read,
- .write = rt2x00pci_register_write,
+ .read = rt2x00mmio_register_read,
+ .write = rt2x00mmio_register_write,
.flags = RT2X00DEBUGFS_OFFSET,
.word_base = CSR_REG_BASE,
.word_size = sizeof(u32),
@@ -242,7 +243,7 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_VAL5);
}
@@ -293,10 +294,10 @@ static int rt61pci_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct rt2x00_led, led_dev);
u32 reg;
- rt2x00pci_register_read(led->rt2x00dev, MAC_CSR14, &reg);
+ rt2x00mmio_register_read(led->rt2x00dev, MAC_CSR14, &reg);
rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, *delay_on);
rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, *delay_off);
- rt2x00pci_register_write(led->rt2x00dev, MAC_CSR14, reg);
+ rt2x00mmio_register_write(led->rt2x00dev, MAC_CSR14, reg);
return 0;
}
@@ -338,7 +339,7 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = (0xf << crypto->bssidx);
- rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, &reg);
reg &= mask;
if (reg && reg == mask)
@@ -357,8 +358,8 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));
reg = SHARED_KEY_ENTRY(key->hw_key_idx);
- rt2x00pci_register_multiwrite(rt2x00dev, reg,
- &key_entry, sizeof(key_entry));
+ rt2x00mmio_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
/*
* The cipher types are stored over 2 registers.
@@ -371,16 +372,16 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
field.bit_offset = (3 * key->hw_key_idx);
field.bit_mask = 0x7 << field.bit_offset;
- rt2x00pci_register_read(rt2x00dev, SEC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR1, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt2x00pci_register_write(rt2x00dev, SEC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, reg);
} else {
field.bit_offset = (3 * (key->hw_key_idx - 8));
field.bit_mask = 0x7 << field.bit_offset;
- rt2x00pci_register_read(rt2x00dev, SEC_CSR5, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR5, &reg);
rt2x00_set_field32(&reg, field, crypto->cipher);
- rt2x00pci_register_write(rt2x00dev, SEC_CSR5, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, reg);
}
/*
@@ -403,12 +404,12 @@ static int rt61pci_config_shared_key(struct rt2x00_dev *rt2x00dev,
*/
mask = 1 << key->hw_key_idx;
- rt2x00pci_register_read(rt2x00dev, SEC_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR0, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt2x00pci_register_write(rt2x00dev, SEC_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, reg);
return 0;
}
@@ -432,10 +433,10 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
* When both registers are full, we drop the key.
* Otherwise, we use the first invalid entry.
*/
- rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, &reg);
if (reg && reg == ~0) {
key->hw_key_idx = 32;
- rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, &reg);
if (reg && reg == ~0)
return -ENOSPC;
}
@@ -457,21 +458,21 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
addr_entry.cipher = crypto->cipher;
reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
- rt2x00pci_register_multiwrite(rt2x00dev, reg,
- &key_entry, sizeof(key_entry));
+ rt2x00mmio_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
reg = PAIRWISE_TA_ENTRY(key->hw_key_idx);
- rt2x00pci_register_multiwrite(rt2x00dev, reg,
- &addr_entry, sizeof(addr_entry));
+ rt2x00mmio_register_multiwrite(rt2x00dev, reg,
+ &addr_entry, sizeof(addr_entry));
/*
* Enable pairwise lookup table for given BSS idx.
* Without this, received frames will not be decrypted
* by the hardware.
*/
- rt2x00pci_register_read(rt2x00dev, SEC_CSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR4, &reg);
reg |= (1 << crypto->bssidx);
- rt2x00pci_register_write(rt2x00dev, SEC_CSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR4, reg);
/*
* The driver does not support the IV/EIV generation
@@ -494,21 +495,21 @@ static int rt61pci_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
if (key->hw_key_idx < 32) {
mask = 1 << key->hw_key_idx;
- rt2x00pci_register_read(rt2x00dev, SEC_CSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR2, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt2x00pci_register_write(rt2x00dev, SEC_CSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR2, reg);
} else {
mask = 1 << (key->hw_key_idx - 32);
- rt2x00pci_register_read(rt2x00dev, SEC_CSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, SEC_CSR3, &reg);
if (crypto->cmd == SET_KEY)
reg |= mask;
else if (crypto->cmd == DISABLE_KEY)
reg &= ~mask;
- rt2x00pci_register_write(rt2x00dev, SEC_CSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR3, reg);
}
return 0;
@@ -525,7 +526,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
* and broadcast frames will always be accepted since
* there is no filter for it at this time.
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
!(filter_flags & FIF_FCSFAIL));
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
@@ -543,7 +544,7 @@ static void rt61pci_config_filter(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS,
!(filter_flags & FIF_CONTROL));
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
}
static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
@@ -557,9 +558,9 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
/*
* Enable synchronisation.
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (flags & CONFIG_UPDATE_MAC) {
@@ -567,8 +568,8 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
conf->mac[1] = cpu_to_le32(reg);
- rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2,
- conf->mac, sizeof(conf->mac));
+ rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR2,
+ conf->mac, sizeof(conf->mac));
}
if (flags & CONFIG_UPDATE_BSSID) {
@@ -576,8 +577,9 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR5_BSS_ID_MASK, 3);
conf->bssid[1] = cpu_to_le32(reg);
- rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4,
- conf->bssid, sizeof(conf->bssid));
+ rt2x00mmio_register_multiwrite(rt2x00dev, MAC_CSR4,
+ conf->bssid,
+ sizeof(conf->bssid));
}
}
@@ -587,40 +589,40 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, 0x32);
rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
!!erp->short_preamble);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg);
}
if (changed & BSS_CHANGED_BASIC_RATES)
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR5,
- erp->basic_rates);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR5,
+ erp->basic_rates);
if (changed & BSS_CHANGED_BEACON_INT) {
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
erp->beacon_int * 16);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
- rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, erp->slot_time);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR8, &reg);
rt2x00_set_field32(&reg, MAC_CSR8_SIFS, erp->sifs);
rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
rt2x00_set_field32(&reg, MAC_CSR8_EIFS, erp->eifs);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR8, reg);
}
}
@@ -713,7 +715,7 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, &reg);
rt2x00_set_field32(&reg, MAC_CSR13_DIR4, 0);
rt2x00_set_field32(&reg, MAC_CSR13_VAL4, p1);
@@ -721,7 +723,7 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MAC_CSR13_DIR3, 0);
rt2x00_set_field32(&reg, MAC_CSR13_VAL3, !p2);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg);
}
static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
@@ -820,14 +822,14 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
- rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, PHY_CSR0, &reg);
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG,
rt2x00dev->curr_band == IEEE80211_BAND_2GHZ);
rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A,
rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR0, reg);
if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325))
rt61pci_config_antenna_5x(rt2x00dev, ant);
@@ -847,7 +849,7 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
u16 eeprom;
short lna_gain = 0;
- if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+ if (libconf->conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
lna_gain += 14;
@@ -927,7 +929,7 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR4, &reg);
rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_DOWN, 1);
rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_RATE_STEP, 0);
rt2x00_set_field32(&reg, TXRX_CSR4_OFDM_TX_FALLBACK_CCK, 0);
@@ -935,7 +937,7 @@ static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev,
libconf->conf->long_frame_max_tx_count);
rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT,
libconf->conf->short_frame_max_tx_count);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR4, reg);
}
static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
@@ -947,7 +949,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
u32 reg;
if (state == STATE_SLEEP) {
- rt2x00pci_register_read(rt2x00dev, MAC_CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, &reg);
rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
rt2x00dev->beacon_int - 10);
rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
@@ -956,27 +958,29 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
/* We must first disable autowake before it can be enabled */
rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
- rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000005);
- rt2x00pci_register_write(rt2x00dev, IO_CNTL_CSR, 0x0000001c);
- rt2x00pci_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000060);
+ rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR,
+ 0x00000005);
+ rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x0000001c);
+ rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000060);
rt61pci_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 0);
} else {
- rt2x00pci_register_read(rt2x00dev, MAC_CSR11, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR11, &reg);
rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN, 0);
rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0);
rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR11, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR11, reg);
- rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
- rt2x00pci_register_write(rt2x00dev, IO_CNTL_CSR, 0x00000018);
- rt2x00pci_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000020);
+ rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR,
+ 0x00000007);
+ rt2x00mmio_register_write(rt2x00dev, IO_CNTL_CSR, 0x00000018);
+ rt2x00mmio_register_write(rt2x00dev, PCI_USEC_CSR, 0x00000020);
rt61pci_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0);
}
@@ -1012,13 +1016,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev,
/*
* Update FCS error count from register.
*/
- rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR0, &reg);
qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
/*
* Update False CCA count from register.
*/
- rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR1, &reg);
qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
}
@@ -1137,16 +1141,16 @@ static void rt61pci_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
break;
default:
break;
@@ -1160,24 +1164,24 @@ static void rt61pci_kick_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_AC_VO:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_VI:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_BE:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_BK:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
default:
break;
@@ -1191,36 +1195,36 @@ static void rt61pci_stop_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_AC_VO:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_VI:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_BE:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_AC_BK:
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_CNTL_CSR, reg);
break;
case QID_RX:
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
break;
case QID_BEACON:
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Wait for possibly running tbtt tasklets.
@@ -1298,14 +1302,14 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
* Wait for stable hardware.
*/
for (i = 0; i < 100; i++) {
- rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, &reg);
if (reg)
break;
msleep(1);
}
if (!reg) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
+ rt2x00_err(rt2x00dev, "Unstable hardware\n");
return -EBUSY;
}
@@ -1314,10 +1318,10 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
*/
reg = 0;
rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
- rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
- rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
- rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
- rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0);
+ rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+ rt2x00mmio_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00mmio_register_write(rt2x00dev, HOST_CMD_CSR, 0);
/*
* Write firmware to device.
@@ -1325,26 +1329,26 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
reg = 0;
rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 1);
- rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
- rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data, len);
+ rt2x00mmio_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 0);
- rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 0);
- rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
for (i = 0; i < 100; i++) {
- rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MCU_CNTL_CSR, &reg);
if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY))
break;
msleep(1);
}
if (i == 100) {
- ERROR(rt2x00dev, "MCU Control register not ready.\n");
+ rt2x00_err(rt2x00dev, "MCU Control register not ready\n");
return -EBUSY;
}
@@ -1359,16 +1363,16 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
reg = 0;
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
return 0;
}
@@ -1378,7 +1382,7 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev,
*/
static bool rt61pci_get_entry_state(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word;
if (entry->queue->qid == QID_RX) {
@@ -1395,7 +1399,7 @@ static bool rt61pci_get_entry_state(struct queue_entry *entry)
static void rt61pci_clear_entry(struct queue_entry *entry)
{
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
u32 word;
@@ -1418,13 +1422,13 @@ static void rt61pci_clear_entry(struct queue_entry *entry)
static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
{
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
u32 reg;
/*
* Initialize registers.
*/
- rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR0, &reg);
rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
rt2x00dev->tx[0].limit);
rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
@@ -1433,67 +1437,67 @@ static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev)
rt2x00dev->tx[2].limit);
rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
rt2x00dev->tx[3].limit);
- rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR0, reg);
- rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_RING_CSR1, &reg);
rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
rt2x00dev->tx[0].desc_size / 4);
- rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_RING_CSR1, reg);
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, AC0_BASE_CSR, reg);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, AC1_BASE_CSR, reg);
entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, AC2_BASE_CSR, reg);
entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, AC3_BASE_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RX_RING_CSR, &reg);
rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE, rt2x00dev->rx->limit);
rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
rt2x00dev->rx->desc_size / 4);
rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
- rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RX_RING_CSR, reg);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
- rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RX_BASE_CSR, &reg);
rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
entry_priv->desc_dma);
- rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RX_BASE_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC0, 2);
rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC1, 2);
rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC2, 2);
rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC3, 2);
- rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, LOAD_TX_RING_CSR, &reg);
rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1);
rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
- rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, RX_CNTL_CSR_LOAD_RXD, 1);
- rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg);
return 0;
}
@@ -1502,13 +1506,13 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR0, &reg);
rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR0, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR1, &reg);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
@@ -1517,12 +1521,12 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR1, reg);
/*
* CCK TXD BBP registers
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR2, &reg);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
@@ -1531,76 +1535,76 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR2, reg);
/*
* OFDM TXD BBP registers
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR3, &reg);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR3, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR7, &reg);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR7, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR8, &reg);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR8, reg);
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
rt2x00_set_field32(&reg, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR9, &reg);
rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR9, reg);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
return -EBUSY;
- rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
/*
* Invalidate all Shared Keys (SEC_CSR0),
* and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
*/
- rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
- rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
- rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt2x00mmio_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
- rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt2x00mmio_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
- rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
+ rt2x00mmio_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
- rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
+ rt2x00mmio_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
- rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+ rt2x00mmio_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
/*
* Clear all beacons
@@ -1608,36 +1612,36 @@ static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
* the first byte since that byte contains the VALID and OWNER
* bits which (when set to 0) will invalidate the entire beacon.
*/
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
- rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+ rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00mmio_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
/*
* We must clear the error counters.
* These registers are cleared on read,
* so we may pass a useless variable to store the value.
*/
- rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
- rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
- rt2x00pci_register_read(rt2x00dev, STA_CSR2, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR2, &reg);
/*
* Reset MAC and BBP registers.
*/
- rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR1, &reg);
rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR1, reg);
return 0;
}
@@ -1654,7 +1658,7 @@ static int rt61pci_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
@@ -1721,11 +1725,11 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+ rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
}
/*
@@ -1734,15 +1738,15 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
- rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_BEACON_DONE, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, mask);
@@ -1752,7 +1756,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_TWAKEUP, mask);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
@@ -1782,9 +1786,9 @@ static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Enable RX.
*/
- rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
rt2x00_set_field32(&reg, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
- rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, RX_CNTL_CSR, reg);
return 0;
}
@@ -1794,7 +1798,7 @@ static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Disable power
*/
- rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
}
static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
@@ -1805,10 +1809,10 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
put_to_sleep = (state != STATE_AWAKE);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, &reg);
rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg);
/*
* Device is not guaranteed to be in the requested state yet.
@@ -1816,11 +1820,11 @@ static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
* device has entered the correct state.
*/
for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg2);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR12, &reg2);
state = rt2x00_get_field32(reg2, MAC_CSR12_BBP_CURRENT_STATE);
if (state == !put_to_sleep)
return 0;
- rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR12, reg);
msleep(10);
}
@@ -1855,8 +1859,8 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -1868,7 +1872,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
__le32 *txd = entry_priv->desc;
u32 word;
@@ -1966,7 +1970,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
unsigned int beacon_base;
unsigned int padding_len;
u32 orig_reg, reg;
@@ -1975,10 +1979,10 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
orig_reg = reg;
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Write the TX descriptor for the beacon.
@@ -1995,19 +1999,19 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
*/
padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
if (padding_len && skb_pad(entry->skb, padding_len)) {
- ERROR(rt2x00dev, "Failure padding beacon, aborting\n");
+ rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
return;
}
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
- entry_priv->desc, TXINFO_SIZE);
- rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
- entry->skb->data,
- entry->skb->len + padding_len);
+ rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base,
+ entry_priv->desc, TXINFO_SIZE);
+ rt2x00mmio_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
+ entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -2015,10 +2019,10 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
* For Wi-Fi faily generated beacons between participating
* stations. Set TBTT phase adaptive adjustment step to 8us.
*/
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Clean up beacon skb.
@@ -2036,21 +2040,21 @@ static void rt61pci_clear_beacon(struct queue_entry *entry)
* Disable beaconing while we are reloading the beacon data,
* otherwise we might be sending out invalid data.
*/
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR9, &reg);
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
* Clear beacon.
*/
- rt2x00pci_register_write(rt2x00dev,
- HW_BEACON_OFFSET(entry->entry_idx), 0);
+ rt2x00mmio_register_write(rt2x00dev,
+ HW_BEACON_OFFSET(entry->entry_idx), 0);
/*
* Enable beaconing again.
*/
rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ rt2x00mmio_register_write(rt2x00dev, TXRX_CSR9, reg);
}
/*
@@ -2088,7 +2092,7 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
struct rxdone_entry_desc *rxdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
+ struct queue_entry_priv_mmio *entry_priv = entry->priv_data;
u32 word0;
u32 word1;
@@ -2154,7 +2158,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
struct queue_entry *entry;
struct queue_entry *entry_done;
- struct queue_entry_priv_pci *entry_priv;
+ struct queue_entry_priv_mmio *entry_priv;
struct txdone_entry_desc txdesc;
u32 word;
u32 reg;
@@ -2172,7 +2176,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
* tx ring size for now.
*/
for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
- rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
+ rt2x00mmio_register_read(rt2x00dev, STA_CSR4, &reg);
if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
break;
@@ -2206,9 +2210,8 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
/* Catch up.
* Just report any entries we missed as failed.
*/
- WARNING(rt2x00dev,
- "TX status report missed for entry %d\n",
- entry_done->entry_idx);
+ rt2x00_warn(rt2x00dev, "TX status report missed for entry %d\n",
+ entry_done->entry_idx);
rt2x00lib_txdone_noinfo(entry_done, TXDONE_UNKNOWN);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
@@ -2259,9 +2262,9 @@ static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, irq_field, 0);
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -2277,9 +2280,9 @@ static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev,
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, irq_field, 0);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
@@ -2303,7 +2306,7 @@ static void rt61pci_tbtt_tasklet(unsigned long data)
static void rt61pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- if (rt2x00pci_rxdone(rt2x00dev))
+ if (rt2x00mmio_rxdone(rt2x00dev))
tasklet_schedule(&rt2x00dev->rxdone_tasklet);
else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
@@ -2313,8 +2316,8 @@ static void rt61pci_autowake_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
rt61pci_wakeup(rt2x00dev);
- rt2x00pci_register_write(rt2x00dev,
- M2H_CMD_DONE_CSR, 0xffffffff);
+ rt2x00mmio_register_write(rt2x00dev,
+ M2H_CMD_DONE_CSR, 0xffffffff);
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
}
@@ -2329,11 +2332,11 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
* Get the interrupt sources & saved to local variable.
* Write register value back to clear pending interrupts.
*/
- rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
- rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+ rt2x00mmio_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+ rt2x00mmio_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
- rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg && !reg_mcu)
return IRQ_NONE;
@@ -2370,13 +2373,13 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
*/
spin_lock(&rt2x00dev->irqmask_lock);
- rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, INT_MASK_CSR, &reg);
reg |= mask;
- rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, INT_MASK_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
reg |= mask_mcu;
- rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
@@ -2394,7 +2397,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
u8 *mac;
s8 value;
- rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom.data = rt2x00dev;
eeprom.register_read = rt61pci_eepromregister_read;
@@ -2415,7 +2418,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2430,7 +2433,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
- EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
@@ -2443,7 +2446,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
- EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
@@ -2451,7 +2454,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
LED_MODE_DEFAULT);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
- EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
@@ -2459,7 +2462,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
@@ -2467,7 +2470,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
- EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
if (value < -10 || value > 10)
@@ -2483,7 +2486,7 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
- EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
if (value < -10 || value > 10)
@@ -2512,7 +2515,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify RF chipset.
*/
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
- rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
@@ -2520,7 +2523,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF5325) &&
!rt2x00_rf(rt2x00dev, RF2527) &&
!rt2x00_rf(rt2x00dev, RF2529)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
return -ENODEV;
}
@@ -2837,7 +2840,7 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Disable power saving.
*/
- rt2x00pci_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
+ rt2x00mmio_register_write(rt2x00dev, SOFT_RESET_CSR, 0x00000007);
/*
* Allocate eeprom data.
@@ -2854,9 +2857,9 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* Enable rfkill polling by setting GPIO direction of the
* rfkill switch GPIO pin correctly.
*/
- rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ rt2x00mmio_register_read(rt2x00dev, MAC_CSR13, &reg);
rt2x00_set_field32(&reg, MAC_CSR13_DIR5, 1);
- rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ rt2x00mmio_register_write(rt2x00dev, MAC_CSR13, reg);
/*
* Initialize hw specifications.
@@ -2926,25 +2929,25 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw,
field.bit_offset = (queue_idx & 1) * 16;
field.bit_mask = 0xffff << field.bit_offset;
- rt2x00pci_register_read(rt2x00dev, offset, &reg);
+ rt2x00mmio_register_read(rt2x00dev, offset, &reg);
rt2x00_set_field32(&reg, field, queue->txop);
- rt2x00pci_register_write(rt2x00dev, offset, reg);
+ rt2x00mmio_register_write(rt2x00dev, offset, reg);
/* Update WMM registers */
field.bit_offset = queue_idx * 4;
field.bit_mask = 0xf << field.bit_offset;
- rt2x00pci_register_read(rt2x00dev, AIFSN_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, AIFSN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->aifs);
- rt2x00pci_register_write(rt2x00dev, AIFSN_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, AIFSN_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, CWMIN_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CWMIN_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_min);
- rt2x00pci_register_write(rt2x00dev, CWMIN_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, CWMIN_CSR, reg);
- rt2x00pci_register_read(rt2x00dev, CWMAX_CSR, &reg);
+ rt2x00mmio_register_read(rt2x00dev, CWMAX_CSR, &reg);
rt2x00_set_field32(&reg, field, queue->cw_max);
- rt2x00pci_register_write(rt2x00dev, CWMAX_CSR, reg);
+ rt2x00mmio_register_write(rt2x00dev, CWMAX_CSR, reg);
return 0;
}
@@ -2955,9 +2958,9 @@ static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
u64 tsf;
u32 reg;
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR13, &reg);
tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ rt2x00mmio_register_read(rt2x00dev, TXRX_CSR12, &reg);
tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
return tsf;
@@ -2996,8 +2999,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.get_firmware_name = rt61pci_get_firmware_name,
.check_firmware = rt61pci_check_firmware,
.load_firmware = rt61pci_load_firmware,
- .initialize = rt2x00pci_initialize,
- .uninitialize = rt2x00pci_uninitialize,
+ .initialize = rt2x00mmio_initialize,
+ .uninitialize = rt2x00mmio_uninitialize,
.get_entry_state = rt61pci_get_entry_state,
.clear_entry = rt61pci_clear_entry,
.set_device_state = rt61pci_set_device_state,
@@ -3008,7 +3011,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.start_queue = rt61pci_start_queue,
.kick_queue = rt61pci_kick_queue,
.stop_queue = rt61pci_stop_queue,
- .flush_queue = rt2x00pci_flush_queue,
+ .flush_queue = rt2x00mmio_flush_queue,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
.clear_beacon = rt61pci_clear_beacon,
@@ -3026,21 +3029,21 @@ static const struct data_queue_desc rt61pci_queue_rx = {
.entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = RXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt61pci_queue_tx = {
.entry_num = 32,
.data_size = DATA_FRAME_SIZE,
.desc_size = TXD_DESC_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct data_queue_desc rt61pci_queue_bcn = {
.entry_num = 4,
.data_size = 0, /* No DMA required for beacons */
.desc_size = TXINFO_SIZE,
- .priv_size = sizeof(struct queue_entry_priv_pci),
+ .priv_size = sizeof(struct queue_entry_priv_mmio),
};
static const struct rt2x00_ops rt61pci_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 24eec66e9fd2..377e09bb0b81 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -739,7 +739,7 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
u16 eeprom;
short lna_gain = 0;
- if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
+ if (libconf->conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
lna_gain += 14;
@@ -1122,7 +1122,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev,
}
if (!reg) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
+ rt2x00_err(rt2x00dev, "Unstable hardware\n");
return -EBUSY;
}
@@ -1139,7 +1139,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev,
0, USB_MODE_FIRMWARE,
REGISTER_TIMEOUT_FIRMWARE);
if (status < 0) {
- ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
+ rt2x00_err(rt2x00dev, "Failed to write Firmware to device\n");
return status;
}
@@ -1305,7 +1305,7 @@ static int rt73usb_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
udelay(REGISTER_BUSY_DELAY);
}
- ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
return -EACCES;
}
@@ -1443,8 +1443,8 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
}
if (unlikely(retval))
- ERROR(rt2x00dev, "Device failed to enter state %d (%d).\n",
- state, retval);
+ rt2x00_err(rt2x00dev, "Device failed to enter state %d (%d)\n",
+ state, retval);
return retval;
}
@@ -1567,7 +1567,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
*/
padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
if (padding_len && skb_pad(entry->skb, padding_len)) {
- ERROR(rt2x00dev, "Failure padding beacon, aborting\n");
+ rt2x00_err(rt2x00dev, "Failure padding beacon, aborting\n");
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
@@ -1771,7 +1771,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
eth_random_addr(mac);
- EEPROM(rt2x00dev, "MAC: %pM\n", mac);
+ rt2x00_eeprom_dbg(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -1786,14 +1786,14 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226);
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
- EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Antenna: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
if (word == 0xffff) {
rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
- EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "NIC: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
@@ -1809,7 +1809,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
LED_MODE_DEFAULT);
rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
- EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Led: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
@@ -1817,7 +1817,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "Freq: 0x%04x\n", word);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
@@ -1825,7 +1825,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
- EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
if (value < -10 || value > 10)
@@ -1841,7 +1841,7 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
- EEPROM(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
+ rt2x00_eeprom_dbg(rt2x00dev, "RSSI OFFSET A: 0x%04x\n", word);
} else {
value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
if (value < -10 || value > 10)
@@ -1875,7 +1875,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (!rt2x00_rt(rt2x00dev, RT2573) || (rt2x00_rev(rt2x00dev) == 0)) {
- ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RT chipset detected\n");
return -ENODEV;
}
@@ -1883,7 +1883,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF2528) &&
!rt2x00_rf(rt2x00dev, RF5225) &&
!rt2x00_rf(rt2x00dev, RF2527)) {
- ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ rt2x00_err(rt2x00dev, "Invalid RF chipset detected\n");
return -ENODEV;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c
index 1b3c2843221d..91a04e2b8ece 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c
@@ -147,8 +147,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
signal = priv->rf->calc_rssi(agc, sq);
}
rx_status.signal = signal;
- rx_status.freq = dev->conf.channel->center_freq;
- rx_status.band = dev->conf.channel->band;
+ rx_status.freq = dev->conf.chandef.chan->center_freq;
+ rx_status.band = dev->conf.chandef.chan->band;
rx_status.mactime = le64_to_cpu(entry->tsft);
rx_status.flag |= RX_FLAG_MACTIME_START;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
diff --git a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c
index 5ee7589dd546..077ff92cc139 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c
@@ -82,7 +82,8 @@ static void grf5101_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int channel =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
u32 txpw = priv->channels[channel - 1].hw_value & 0xFF;
u32 chan = channel - 1;
diff --git a/drivers/net/wireless/rtl818x/rtl8180/max2820.c b/drivers/net/wireless/rtl818x/rtl8180/max2820.c
index 667b3363d437..4715000c94dd 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/max2820.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.c
@@ -95,7 +95,7 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev,
{
struct rtl8180_priv *priv = dev->priv;
int channel = conf ?
- ieee80211_frequency_to_channel(conf->channel->center_freq) : 1;
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq) : 1;
unsigned int chan_idx = channel - 1;
u32 txpw = priv->channels[chan_idx].hw_value & 0xFF;
u32 chan = max2820_chan[chan_idx];
diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
index 7c4574ba9d75..cc2a5412c1f0 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
@@ -719,7 +719,8 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int chan =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
if (priv->rf->init == rtl8225_rf_init)
rtl8225_rf_set_tx_power(dev, chan);
diff --git a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c
index 44771a6286af..b3ec40f6bd23 100644
--- a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c
+++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c
@@ -105,7 +105,8 @@ static void sa2400_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct rtl8180_priv *priv = dev->priv;
- int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int channel =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
u32 txpw = priv->channels[channel - 1].hw_value & 0xFF;
u32 chan = sa2400_chan[channel - 1];
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index 4574bd213705..f49220e234b0 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -379,8 +379,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rate = (flags >> 20) & 0xF;
skb_trim(skb, flags & 0x0FFF);
rx_status.rate_idx = rate;
- rx_status.freq = dev->conf.channel->center_freq;
- rx_status.band = dev->conf.channel->band;
+ rx_status.freq = dev->conf.chandef.chan->center_freq;
+ rx_status.band = dev->conf.chandef.chan->band;
rx_status.flag |= RX_FLAG_MACTIME_START;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
index 908903f721f5..f0bf35fedbaf 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
@@ -905,7 +905,8 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev,
struct ieee80211_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
- int chan = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ int chan =
+ ieee80211_frequency_to_channel(conf->chandef.chan->center_freq);
if (priv->rf->init == rtl8225_rf_init)
rtl8225_rf_set_tx_power(dev, chan);
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index b6aa0c40658f..7253de3d8c66 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -55,6 +55,15 @@ config RTL8723AE
If you choose to build it as a module, it will be called rtl8723ae
+config RTL8188EE
+ tristate "Realtek RTL8188EE Wireless Network Adapter"
+ depends on RTLWIFI && PCI
+ ---help---
+ This is the driver for Realtek RTL8188EE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8188ee
+
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
depends on RTLWIFI && USB
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index 3b1cbac741e3..ff02b874f8d8 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_RTL8192CU) += rtl8192cu/
obj-$(CONFIG_RTL8192SE) += rtl8192se/
obj-$(CONFIG_RTL8192DE) += rtl8192de/
obj-$(CONFIG_RTL8723AE) += rtl8723ae/
+obj-$(CONFIG_RTL8188EE) += rtl8188ee/
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 99c5cea3fe21..af59dd5718e1 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -54,7 +54,8 @@
*5) frame process functions
*6) IOT functions
*7) sysfs functions
- *8) ...
+ *8) vif functions
+ *9) ...
*/
/*********************************************************
@@ -198,34 +199,46 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
- /*
- *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ /*hw->wiphy->bands[IEEE80211_BAND_2GHZ]
*base on ant_num
*rx_mask: RX mask
- *if rx_ant =1 rx_mask[0]=0xff;==>MCS0-MCS7
- *if rx_ant =2 rx_mask[1]=0xff;==>MCS8-MCS15
- *if rx_ant >=3 rx_mask[2]=0xff;
- *if BW_40 rx_mask[4]=0x01;
+ *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
+ *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
+ *if rx_ant >= 3 rx_mask[2]= 0xff;
+ *if BW_40 rx_mask[4]= 0x01;
*highest supported RX rate
*/
- if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_2T2R) {
+ if (rtlpriv->dm.supp_phymode_switch) {
- RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T2R or 2T2R\n");
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ "Support phy mode switch\n");
ht_cap->mcs.rx_mask[0] = 0xFF;
ht_cap->mcs.rx_mask[1] = 0xFF;
ht_cap->mcs.rx_mask[4] = 0x01;
ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
- } else if (get_rf_type(rtlphy) == RF_1T1R) {
-
- RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
-
- ht_cap->mcs.rx_mask[0] = 0xFF;
- ht_cap->mcs.rx_mask[1] = 0x00;
- ht_cap->mcs.rx_mask[4] = 0x01;
-
- ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
+ } else {
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_2T2R) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "1T2R or 2T2R\n");
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0xFF;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest =
+ cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15);
+ } else if (get_rf_type(rtlphy) == RF_1T1R) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "1T1R\n");
+
+ ht_cap->mcs.rx_mask[0] = 0xFF;
+ ht_cap->mcs.rx_mask[1] = 0x00;
+ ht_cap->mcs.rx_mask[4] = 0x01;
+
+ ht_cap->mcs.rx_highest =
+ cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
+ }
}
}
@@ -311,6 +324,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_CONNECTION_MONITOR |
/* IEEE80211_HW_SUPPORTS_CQM_RSSI | */
+ IEEE80211_HW_CONNECTION_MONITOR |
+ IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
/* swlps or hwlps has been set in diff chip in init_sw_vars */
@@ -323,8 +338,12 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_MESH_POINT) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
hw->wiphy->rts_threshold = 2347;
hw->queues = AC_MAX;
@@ -354,9 +373,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
/* <1> timer */
- init_timer(&rtlpriv->works.watchdog_timer);
setup_timer(&rtlpriv->works.watchdog_timer,
rtl_watch_dog_timer_callback, (unsigned long)hw);
+ setup_timer(&rtlpriv->works.dualmac_easyconcurrent_retrytimer,
+ rtl_easy_concurrent_retrytimer_callback, (unsigned long)hw);
/* <2> work queue */
rtlpriv->works.hw = hw;
@@ -369,6 +389,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
(void *)rtl_swlps_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
(void *)rtl_swlps_rfon_wq_callback);
+ INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq,
+ (void *)rtl_fwevt_wq_callback);
}
@@ -382,6 +404,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
cancel_delayed_work(&rtlpriv->works.ps_work);
cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+ cancel_delayed_work(&rtlpriv->works.fwevt_wq);
}
void rtl_init_rfkill(struct ieee80211_hw *hw)
@@ -436,12 +459,6 @@ int rtl_init_core(struct ieee80211_hw *hw)
if (rtl_regd_init(hw, rtl_reg_notifier)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "REGD init failed\n");
return 1;
- } else {
- /* CRDA regd hint must after init CRDA */
- if (regulatory_hint(hw->wiphy, rtlpriv->regd.alpha2)) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "regulatory_hint fail\n");
- }
}
/* <4> locks */
@@ -449,15 +466,25 @@ int rtl_init_core(struct ieee80211_hw *hw)
mutex_init(&rtlpriv->locks.ps_mutex);
spin_lock_init(&rtlpriv->locks.ips_lock);
spin_lock_init(&rtlpriv->locks.irq_th_lock);
+ spin_lock_init(&rtlpriv->locks.irq_pci_lock);
+ spin_lock_init(&rtlpriv->locks.tx_lock);
spin_lock_init(&rtlpriv->locks.h2c_lock);
spin_lock_init(&rtlpriv->locks.rf_ps_lock);
spin_lock_init(&rtlpriv->locks.rf_lock);
spin_lock_init(&rtlpriv->locks.waitq_lock);
+ spin_lock_init(&rtlpriv->locks.entry_list_lock);
+ spin_lock_init(&rtlpriv->locks.fw_ps_lock);
spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
+ spin_lock_init(&rtlpriv->locks.check_sendpkt_lock);
+ spin_lock_init(&rtlpriv->locks.fw_ps_lock);
+ spin_lock_init(&rtlpriv->locks.lps_lock);
+
+ /* <5> init list */
+ INIT_LIST_HEAD(&rtlpriv->entry_list);
rtlmac->link_state = MAC80211_NOLINK;
- /* <5> init deferred work */
+ /* <6> init deferred work */
_rtl_init_deferred_work(hw);
return 0;
@@ -523,7 +550,8 @@ static void _rtl_query_shortgi(struct ieee80211_hw *hw,
if (mac->opmode == NL80211_IFTYPE_STATION)
bw_40 = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC)
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
if (bw_40 && sgi_40)
@@ -578,23 +606,26 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
if (mac->opmode == NL80211_IFTYPE_STATION) {
tcb_desc->ratr_index = 0;
- } else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ } else if (mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (tcb_desc->multicast || tcb_desc->broadcast) {
tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
tcb_desc->use_driver_rate = 1;
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
} else {
- /* TODO */
+ tcb_desc->ratr_index = ratr_index;
}
- tcb_desc->ratr_index = ratr_index;
} else if (mac->opmode == NL80211_IFTYPE_AP) {
tcb_desc->ratr_index = ratr_index;
}
}
if (rtlpriv->dm.useramask) {
- /* TODO we will differentiate adhoc and station futrue */
- if (mac->opmode == NL80211_IFTYPE_STATION) {
+ tcb_desc->ratr_index = ratr_index;
+ /* TODO we will differentiate adhoc and station future */
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
tcb_desc->mac_id = 0;
if (mac->mode == WIRELESS_MODE_N_24G)
@@ -608,7 +639,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
else if (mac->mode & WIRELESS_MODE_A)
tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
} else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
if (NULL != sta) {
if (sta->aid > 0)
tcb_desc->mac_id = sta->aid + 1;
@@ -619,7 +650,6 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
}
}
}
-
}
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
@@ -633,7 +663,8 @@ static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
if (!sta)
return;
if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
return;
} else if (mac->opmode == NL80211_IFTYPE_STATION) {
@@ -691,7 +722,7 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
int rate_idx;
if (false == isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) {
+ if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
switch (desc_rate) {
case DESC92_RATE1M:
rate_idx = 0;
@@ -834,8 +865,8 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
if (rtlpriv->dm.supp_phymode_switch &&
mac->link_state < MAC80211_LINKED &&
(ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
- if (rtlpriv->cfg->ops->check_switch_to_dmdp)
- rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
}
if (ieee80211_is_auth(fc)) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
@@ -924,6 +955,56 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(rtl_get_tcb_desc);
+static bool addbareq_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_sta *sta = NULL;
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+ struct rtl_sta_info *sta_entry = NULL;
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u16 capab = 0, tid = 0;
+ struct rtl_tid_data *tid_data;
+ struct sk_buff *skb_delba = NULL;
+ struct ieee80211_rx_status rx_status = { 0 };
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, hdr->addr3);
+ if (sta == NULL) {
+ RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_EMERG,
+ "sta is NULL\n");
+ rcu_read_unlock();
+ return true;
+ }
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ if (!sta_entry) {
+ rcu_read_unlock();
+ return true;
+ }
+ capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ tid_data = &sta_entry->tids[tid];
+ if (tid_data->agg.rx_agg_state == RTL_RX_AGG_START) {
+ skb_delba = rtl_make_del_ba(hw, hdr->addr2, hdr->addr3, tid);
+ if (skb_delba) {
+ rx_status.freq = hw->conf.chandef.chan->center_freq;
+ rx_status.band = hw->conf.chandef.chan->band;
+ rx_status.flag |= RX_FLAG_DECRYPTED;
+ rx_status.flag |= RX_FLAG_MACTIME_END;
+ rx_status.rate_idx = 0;
+ rx_status.signal = 50 + 10;
+ memcpy(IEEE80211_SKB_RXCB(skb_delba), &rx_status,
+ sizeof(rx_status));
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG,
+ "fake del\n", skb_delba->data,
+ skb_delba->len);
+ ieee80211_rx_irqsafe(hw, skb_delba);
+ }
+ }
+ rcu_read_unlock();
+ return false;
+}
+
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -948,6 +1029,11 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
"%s ACT_ADDBAREQ From :%pM\n",
is_tx ? "Tx" : "Rx", hdr->addr2);
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "req\n",
+ skb->data, skb->len);
+ if (!is_tx)
+ if (addbareq_rx(hw, skb))
+ return true;
break;
case ACT_ADDBARSP:
RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
@@ -1003,8 +1089,9 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
is_tx ? "Tx" : "Rx");
if (is_tx) {
+ rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->
- works.lps_leave_work);
+ works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies =
jiffies;
}
@@ -1014,7 +1101,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
}
} else if (ETH_P_ARP == ether_type) {
if (is_tx) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1024,7 +1112,8 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
"802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx");
if (is_tx) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
ppsc->last_delaylps_stamp_jiffies = jiffies;
}
@@ -1101,6 +1190,58 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw,
return 0;
}
+int rtl_rx_agg_start(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_tid_data *tid_data;
+ struct rtl_sta_info *sta_entry = NULL;
+
+ if (sta == NULL)
+ return -EINVAL;
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ if (!sta_entry)
+ return -ENXIO;
+ tid_data = &sta_entry->tids[tid];
+
+ RT_TRACE(rtlpriv, COMP_RECV, DBG_DMESG,
+ "on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+ tid_data->seq_number);
+
+ tid_data->agg.rx_agg_state = RTL_RX_AGG_START;
+ return 0;
+}
+
+int rtl_rx_agg_stop(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_sta_info *sta_entry = NULL;
+
+ if (sta == NULL)
+ return -EINVAL;
+
+ if (!sta->addr) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "ra = NULL\n");
+ return -EINVAL;
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ "on ra = %pM tid = %d\n", sta->addr, tid);
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ sta_entry->tids[tid].agg.rx_agg_state = RTL_RX_AGG_STOP;
+
+ return 0;
+}
+
int rtl_tx_agg_oper(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid)
{
@@ -1132,6 +1273,34 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw,
* wq & timer callback functions
*
*********************************************************/
+/* this function is used for roaming */
+void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
+ return;
+
+ if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+ return;
+
+ /* check if this really is a beacon */
+ if (!ieee80211_is_beacon(hdr->frame_control) &&
+ !ieee80211_is_probe_resp(hdr->frame_control))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (skb->len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ rtlpriv->link_info.bcn_rx_inperiod++;
+}
+
void rtl_watchdog_wq_callback(void *data)
{
struct rtl_works *rtlworks = container_of_dwork_rtl(data,
@@ -1142,6 +1311,8 @@ void rtl_watchdog_wq_callback(void *data)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
bool busytraffic = false;
+ bool tx_busy_traffic = false;
+ bool rx_busy_traffic = false;
bool higher_busytraffic = false;
bool higher_busyrxtraffic = false;
u8 idx, tid;
@@ -1151,7 +1322,6 @@ void rtl_watchdog_wq_callback(void *data)
u32 aver_tx_cnt_inperiod = 0;
u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
- bool enter_ps = false;
if (is_hal_stop(rtlhal))
return;
@@ -1191,8 +1361,13 @@ void rtl_watchdog_wq_callback(void *data)
aver_tx_cnt_inperiod = tx_cnt_inp4eriod / 4;
/* (2) check traffic busy */
- if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100)
+ if (aver_rx_cnt_inperiod > 100 || aver_tx_cnt_inperiod > 100) {
busytraffic = true;
+ if (aver_rx_cnt_inperiod > aver_tx_cnt_inperiod)
+ rx_busy_traffic = true;
+ else
+ tx_busy_traffic = false;
+ }
/* Higher Tx/Rx data. */
if (aver_rx_cnt_inperiod > 4000 ||
@@ -1228,15 +1403,12 @@ void rtl_watchdog_wq_callback(void *data)
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
(rtlpriv->link_info.num_rx_inperiod > 2))
- enter_ps = false;
+ rtlpriv->enter_ps = true;
else
- enter_ps = true;
+ rtlpriv->enter_ps = false;
/* LeisurePS only work in infra mode. */
- if (enter_ps)
- rtl_lps_enter(hw);
- else
- rtl_lps_leave(hw);
+ schedule_work(&rtlpriv->works.lps_change_work);
}
rtlpriv->link_info.num_rx_inperiod = 0;
@@ -1246,10 +1418,37 @@ void rtl_watchdog_wq_callback(void *data)
rtlpriv->link_info.busytraffic = busytraffic;
rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
+ rtlpriv->link_info.rx_busy_traffic = rx_busy_traffic;
+ rtlpriv->link_info.tx_busy_traffic = tx_busy_traffic;
rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
/* <3> DM */
rtlpriv->cfg->ops->dm_watchdog(hw);
+
+ /* <4> roaming */
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ if ((rtlpriv->link_info.bcn_rx_inperiod +
+ rtlpriv->link_info.num_rx_inperiod) == 0) {
+ rtlpriv->link_info.roam_times++;
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
+ "AP off for %d s\n",
+ (rtlpriv->link_info.roam_times * 2));
+
+ /* if we can't recv beacon for 6s, we should
+ * reconnect this AP
+ */
+ if (rtlpriv->link_info.roam_times >= 3) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "AP off, try to reconnect now\n");
+ rtlpriv->link_info.roam_times = 0;
+ ieee80211_connection_loss(rtlpriv->mac80211.vif);
+ }
+ } else {
+ rtlpriv->link_info.roam_times = 0;
+ }
+ }
+ rtlpriv->link_info.bcn_rx_inperiod = 0;
}
void rtl_watch_dog_timer_callback(unsigned long data)
@@ -1264,6 +1463,28 @@ void rtl_watch_dog_timer_callback(unsigned long data)
jiffies + MSECS(RTL_WATCH_DOG_TIME));
}
+void rtl_fwevt_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks =
+ container_of_dwork_rtl(data, struct rtl_works, fwevt_wq);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->cfg->ops->c2h_command_handle(hw);
+}
+
+void rtl_easy_concurrent_retrytimer_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_priv *buddy_priv = rtlpriv->buddy_priv;
+
+ if (buddy_priv == NULL)
+ return;
+
+ rtlpriv->cfg->ops->dualmac_easy_concurrent(hw);
+}
+
/*********************************************************
*
* frame process functions
@@ -1334,14 +1555,16 @@ static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
}
int rtl_send_smps_action(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+ struct ieee80211_sta *sta,
enum ieee80211_smps_mode smps)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
+ struct sk_buff *skb = NULL;
struct rtl_tcb_desc tcb_desc;
+ u8 bssid[ETH_ALEN] = {0};
+
memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (rtlpriv->mac80211.act_scanning)
@@ -1356,21 +1579,67 @@ int rtl_send_smps_action(struct ieee80211_hw *hw,
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP)
+ memcpy(bssid, rtlpriv->efuse.dev_addr, ETH_ALEN);
+ else
+ memcpy(bssid, rtlpriv->mac80211.bssid, ETH_ALEN);
+
+ skb = rtl_make_smps_action(hw, smps, sta->addr, bssid);
/* this is a type = mgmt * stype = action frame */
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl_sta_info *sta_entry =
(struct rtl_sta_info *) sta->drv_priv;
sta_entry->mimo_ps = smps;
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
info->control.rates[0].idx = 0;
- info->band = hw->conf.channel->band;
+ info->band = hw->conf.chandef.chan->band;
rtlpriv->intf_ops->adapter_tx(hw, sta, skb, &tcb_desc);
}
+ return 1;
+
err_free:
return 0;
}
+EXPORT_SYMBOL(rtl_send_smps_action);
+
+/* There seem to be issues in mac80211 regarding when del ba frames can be
+ * received. As a work around, we make a fake del_ba if we receive a ba_req;
+ * however, rx_agg was opened to let mac80211 release some ba related
+ * resources. This del_ba is for tx only.
+ */
+struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
+ u8 *sa, u8 *bssid, u16 tid)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *action_frame;
+ u16 params;
+
+ /* 27 = header + category + action + smps mode */
+ skb = dev_alloc_skb(34 + hw->extra_tx_headroom);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, hw->extra_tx_headroom);
+ action_frame = (void *)skb_put(skb, 34);
+ memset(action_frame, 0, 34);
+ memcpy(action_frame->sa, sa, ETH_ALEN);
+ memcpy(action_frame->da, rtlefuse->dev_addr, ETH_ALEN);
+ memcpy(action_frame->bssid, bssid, ETH_ALEN);
+ action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+ action_frame->u.action.category = WLAN_CATEGORY_BACK;
+ action_frame->u.action.u.delba.action_code = WLAN_ACTION_DELBA;
+ params = (u16)(1 << 11); /* bit 11 initiator */
+ params |= (u16)(tid << 12); /* bit 15:12 TID number */
+
+ action_frame->u.action.u.delba.params = cpu_to_le16(params);
+ action_frame->u.action.u.delba.reason_code =
+ cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
+
+ return skb;
+}
/*********************************************************
*
@@ -1587,11 +1856,17 @@ MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
+struct rtl_global_var global_var = {};
+
static int __init rtl_core_module_init(void)
{
if (rtl_rate_control_register())
pr_err("Unable to register rtl_rc, use default RC !!\n");
+ /* init some global vars */
+ INIT_LIST_HEAD(&global_var.glb_priv_list);
+ spin_lock_init(&global_var.glb_list_lock);
+
return 0;
}
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 5a8c80e259f7..8576bc34b032 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -113,6 +113,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw);
void rtl_init_rfkill(struct ieee80211_hw *hw);
void rtl_deinit_rfkill(struct ieee80211_hw *hw);
+void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
void rtl_watch_dog_timer_callback(unsigned long data);
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
@@ -126,7 +127,12 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid);
+int rtl_rx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
+int rtl_rx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
void rtl_watchdog_wq_callback(void *data);
+void rtl_fwevt_wq_callback(void *data);
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
@@ -134,14 +140,18 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
int rtl_send_smps_action(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u8 *da, u8 *bssid,
- enum ieee80211_smps_mode smps);
+ struct ieee80211_sta *sta,
+ enum ieee80211_smps_mode smps);
u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
u8 rtl_tid_to_ac(u8 tid);
extern struct attribute_group rtl_attribute_group;
+void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
+extern struct rtl_global_var global_var;
int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
bool isht, u8 desc_rate, bool first_ampdu);
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
+struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
+ u8 *sa, u8 *bssid, u16 tid);
#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index d3ce9fbef00e..ee84844be008 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -104,9 +104,12 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
if (is_hal_stop(rtlhal))
return;
+ /* here is must, because adhoc do stop and start,
+ * but stop with RFOFF may cause something wrong,
+ * like adhoc TP
+ */
if (unlikely(ppsc->rfpwr_state == ERFOFF)) {
rtl_ips_nic_on(hw);
- mdelay(1);
}
mutex_lock(&rtlpriv->locks.conf_mutex);
@@ -167,7 +170,11 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
- switch (vif->type) {
+
+ switch (ieee80211_vif_type_p2p(vif)) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ mac->p2p = P2P_ROLE_CLIENT;
+ /*fall through*/
case NL80211_IFTYPE_STATION:
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -192,6 +199,9 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
(u8 *) (&mac->basic_rates));
break;
+ case NL80211_IFTYPE_P2P_GO:
+ mac->p2p = P2P_ROLE_GO;
+ /*fall through*/
case NL80211_IFTYPE_AP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
"NL80211_IFTYPE_AP\n");
@@ -205,6 +215,19 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *) (&mac->basic_rates));
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "NL80211_IFTYPE_MESH_POINT\n");
+
+ mac->link_state = MAC80211_LINKED;
+ rtlpriv->cfg->ops->set_bcn_reg(hw);
+ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+ mac->basic_rates = 0xfff;
+ else
+ mac->basic_rates = 0xff0;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *)(&mac->basic_rates));
+ break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"operation mode %d is not supported!\n", vif->type);
@@ -212,6 +235,13 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ if (mac->p2p) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "p2p role %x\n", vif->type);
+ mac->basic_rates = 0xff0;/*disable cck rate for p2p*/
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *)(&mac->basic_rates));
+ }
mac->vif = vif;
mac->opmode = vif->type;
rtlpriv->cfg->ops->set_network_type(hw, vif->type);
@@ -232,9 +262,9 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&rtlpriv->locks.conf_mutex);
/* Free beacon resources */
- if ((mac->opmode == NL80211_IFTYPE_AP) ||
- (mac->opmode == NL80211_IFTYPE_ADHOC) ||
- (mac->opmode == NL80211_IFTYPE_MESH_POINT)) {
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) {
if (mac->beacon_enabled == 1) {
mac->beacon_enabled = 0;
rtlpriv->cfg->ops->update_interrupt_mask(hw, 0,
@@ -247,6 +277,7 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
*Note: We assume NL80211_IFTYPE_UNSPECIFIED as
*NO LINK for our hardware.
*/
+ mac->p2p = 0;
mac->vif = NULL;
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
@@ -256,6 +287,22 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
+static int rtl_op_change_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum nl80211_iftype new_type, bool p2p)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int ret;
+ rtl_op_remove_interface(hw, vif);
+
+ vif->type = new_type;
+ vif->p2p = p2p;
+ ret = rtl_op_add_interface(hw, vif);
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
+ "p2p %x\n", p2p);
+ return ret;
+}
+
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -264,6 +311,9 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct ieee80211_conf *conf = &hw->conf;
+ if (mac->skip_scan)
+ return 1;
+
mutex_lock(&rtlpriv->locks.conf_mutex);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { /*BIT(2)*/
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
@@ -320,9 +370,19 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- struct ieee80211_channel *channel = hw->conf.channel;
+ struct ieee80211_channel *channel = hw->conf.chandef.chan;
u8 wide_chan = (u8) channel->hw_value;
+ if (mac->act_scanning)
+ mac->n_channels++;
+
+ if (rtlpriv->dm.supp_phymode_switch &&
+ mac->link_state < MAC80211_LINKED &&
+ !mac->act_scanning) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
+
/*
*because we should back channel to
*current_network.chan in in scanning,
@@ -332,7 +392,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
*info for cisco1253 bw20, so we modify
*it here based on UPPER & LOWER
*/
- switch (hw->conf.channel_type) {
+ switch (cfg80211_get_chandef_type(&hw->conf.chandef)) {
case NL80211_CHAN_HT20:
case NL80211_CHAN_NO_HT:
/* SC */
@@ -373,13 +433,13 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
if (wide_chan <= 0)
wide_chan = 1;
- /* In scanning, before we go offchannel we may send a ps=1 null
- * to AP, and then we may send a ps = 0 null to AP quickly, but
- * first null may have caused AP to put lots of packet to hw tx
- * buffer. These packets must be tx'd before we go off channel
- * so we must delay more time to let AP flush these packets
- * before going offchannel, or dis-association or delete BA will
- * happen by AP
+ /* In scanning, before we go offchannel we may send a ps = 1
+ * null to AP, and then we may send a ps = 0 null to AP quickly,
+ * but first null may have caused AP to put lots of packet to
+ * hw tx buffer. These packets must be tx'd before we go off
+ * channel so we must delay more time to let AP flush these
+ * packets before going offchannel, or dis-association or
+ * delete BA will be caused by AP
*/
if (rtlpriv->mac80211.offchan_delay) {
rtlpriv->mac80211.offchan_delay = false;
@@ -390,7 +450,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
rtlpriv->cfg->ops->switch_channel(hw);
rtlpriv->cfg->ops->set_channel_access(hw);
rtlpriv->cfg->ops->set_bw_mode(hw,
- hw->conf.channel_type);
+ cfg80211_get_chandef_type(&hw->conf.chandef));
}
mutex_unlock(&rtlpriv->locks.conf_mutex);
@@ -441,7 +501,8 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
* and nolink check bssid is set in set network_type */
if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
(mac->link_state >= MAC80211_LINKED)) {
- if (mac->opmode != NL80211_IFTYPE_AP) {
+ if (mac->opmode != NL80211_IFTYPE_AP &&
+ mac->opmode != NL80211_IFTYPE_MESH_POINT) {
if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
rtlpriv->cfg->ops->set_chk_bssid(hw, false);
} else {
@@ -481,32 +542,43 @@ static int rtl_op_sta_add(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_sta_info *sta_entry;
if (sta) {
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_add_tail(&sta_entry->list, &rtlpriv->entry_list);
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
if (rtlhal->current_bandtype == BAND_ON_2_4G) {
sta_entry->wireless_mode = WIRELESS_MODE_G;
if (sta->supp_rates[0] <= 0xf)
sta_entry->wireless_mode = WIRELESS_MODE_B;
- if (sta->ht_cap.ht_supported)
+ if (sta->ht_cap.ht_supported == true)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ sta_entry->wireless_mode = WIRELESS_MODE_G;
} else if (rtlhal->current_bandtype == BAND_ON_5G) {
sta_entry->wireless_mode = WIRELESS_MODE_A;
- if (sta->ht_cap.ht_supported)
+ if (sta->ht_cap.ht_supported == true)
sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
- }
- /* I found some times mac80211 give wrong supp_rates for adhoc*/
- if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
- sta_entry->wireless_mode = WIRELESS_MODE_G;
+ if (vif->type == NL80211_IFTYPE_ADHOC)
+ sta_entry->wireless_mode = WIRELESS_MODE_A;
+ }
+ /*disable cck rate for p2p*/
+ if (mac->p2p)
+ sta->supp_rates[0] &= 0xfffffff0;
+ memcpy(sta_entry->mac_addr, sta->addr, ETH_ALEN);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"Add sta addr is %pM\n", sta->addr);
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
}
return 0;
}
+
static int rtl_op_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -519,9 +591,14 @@ static int rtl_op_sta_remove(struct ieee80211_hw *hw,
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
sta_entry->wireless_mode = 0;
sta_entry->ratr_index = 0;
+
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_del(&sta_entry->list);
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
}
return 0;
}
+
static int _rtl_get_hal_qnum(u16 queue)
{
int qnum;
@@ -547,8 +624,8 @@ static int _rtl_get_hal_qnum(u16 queue)
}
/*
- *for mac80211 VO=0, VI=1, BE=2, BK=3
- *for rtl819x BE=0, BK=1, VI=2, VO=3
+ *for mac80211 VO = 0, VI = 1, BE = 2, BK = 3
+ *for rtl819x BE = 0, BK = 1, VI = 2, VO = 3
*/
static int rtl_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, u16 queue,
@@ -630,6 +707,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
/*TODO: reference to enum ieee80211_bss_change */
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
+ struct ieee80211_sta *sta = NULL;
/* we should reset all sec info & cam
* before set cam after linked, we should not
* reset in disassoc, that will cause tkip->wep
@@ -647,23 +725,39 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
- if (mac->opmode == NL80211_IFTYPE_STATION && sta)
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, (u8 *)bss_conf->bssid);
+
+ if (vif->type == NL80211_IFTYPE_STATION && sta)
rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+ RT_TRACE(rtlpriv, COMP_EASY_CONCURRENT, DBG_LOUD,
+ "send PS STATIC frame\n");
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (sta->ht_cap.ht_supported)
+ rtl_send_smps_action(hw, sta,
+ IEEE80211_SMPS_STATIC);
+ }
+ rcu_read_unlock();
+
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_ASSOC\n");
} else {
- if (mac->link_state == MAC80211_LINKED)
- rtl_lps_leave(hw);
+ if (mac->link_state == MAC80211_LINKED) {
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
+ }
+ if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
-
- /* reset sec info */
- rtl_cam_reset_sec_info(hw);
-
- rtl_cam_reset_all_entry(hw);
mac->vendor = PEER_UNKNOWN;
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
+
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
"BSS_CHANGED_UN_ASSOC\n");
}
@@ -778,7 +872,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BASIC_RATES) {
- /* for 5G must << RATE_6M_INDEX=4,
+ /* for 5G must << RATE_6M_INDEX = 4,
* because 5G have no cck rate*/
if (rtlhal->current_bandtype == BAND_ON_5G)
basic_rates = sta->supp_rates[1] << 4;
@@ -815,6 +909,9 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
ppsc->report_linked = false;
}
}
+ if (rtlpriv->cfg->ops->bt_wifi_media_status_notify)
+ rtlpriv->cfg->ops->bt_wifi_media_status_notify(hw,
+ ppsc->report_linked);
}
out:
@@ -885,7 +982,6 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid);
return rtl_tx_agg_stop(hw, sta, tid);
- break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid);
@@ -894,11 +990,11 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_START:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_START:TID:%d\n", tid);
- break;
+ return rtl_rx_agg_start(hw, sta, tid);
case IEEE80211_AMPDU_RX_STOP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
"IEEE80211_AMPDU_RX_STOP:TID:%d\n", tid);
- break;
+ return rtl_rx_agg_stop(hw, sta, tid);
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"IEEE80211_AMPDU_ERR!!!!:\n");
@@ -912,12 +1008,20 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- mac->act_scanning = true;
-
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
+ mac->act_scanning = true;
+ if (rtlpriv->link_info.higher_busytraffic) {
+ mac->skip_scan = true;
+ return;
+ }
+ if (rtlpriv->dm.supp_phymode_switch) {
+ if (rtlpriv->cfg->ops->chk_switch_dmdp)
+ rtlpriv->cfg->ops->chk_switch_dmdp(hw);
+ }
if (mac->link_state == MAC80211_LINKED) {
- rtl_lps_leave(hw);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
mac->link_state = MAC80211_LINKED_SCANNING;
} else {
rtl_ips_nic_on(hw);
@@ -937,6 +1041,16 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, "\n");
mac->act_scanning = false;
+ mac->skip_scan = false;
+ if (rtlpriv->link_info.higher_busytraffic)
+ return;
+
+ /*p2p will use 1/6/11 to scan */
+ if (mac->n_channels == 3)
+ mac->p2p_in_use = true;
+ else
+ mac->p2p_in_use = false;
+ mac->n_channels = 0;
/* Dual mac */
rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
@@ -970,6 +1084,11 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
"not open hw encryption\n");
return -ENOSPC; /*User disabled HW-crypto */
}
+ /* To support IBSS, use sw-crypto for GTK */
+ if (((vif->type == NL80211_IFTYPE_ADHOC) ||
+ (vif->type == NL80211_IFTYPE_MESH_POINT)) &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -ENOSPC;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"%s hardware based encryption for keyidx: %d, mac: %pM\n",
cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
@@ -996,6 +1115,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key_type = AESCCMP_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CCMP\n");
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /*HW doesn't support CMAC encryption, use software CMAC */
+ key_type = AESCMAC_ENCRYPTION;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "alg:CMAC\n");
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "HW don't support CMAC encryption, use software CMAC\n");
+ err = -EOPNOTSUPP;
+ goto out_unlock;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "alg_err:%x!!!!\n",
key->cipher);
@@ -1017,13 +1144,14 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* 1) wep only: is just for wep enc, in this condition
* rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
* will be true & enable_hw_sec will be set when wep
- * ke setting.
+ * key setting.
* 2) wep(group) + AES(pairwise): some AP like cisco
* may use it, in this condition enable_hw_sec will not
* be set when wep key setting */
/* we must reset sec_info after lingked before set key,
* or some flag will be wrong*/
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) {
if (!group_key || key_type == WEP40_ENCRYPTION ||
key_type == WEP104_ENCRYPTION) {
if (group_key)
@@ -1098,12 +1226,16 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
key->hw_key_idx = key_idx;
if (key_type == TKIP_ENCRYPTION)
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ /*use software CCMP encryption for management frames (MFP) */
+ if (key_type == AESCCMP_ENCRYPTION)
+ key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
break;
case DISABLE_KEY:
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"disable key delete one entry\n");
/*set local buf about wep key. */
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) {
if (sta)
rtl_cam_del_entry(hw, sta->addr);
}
@@ -1163,10 +1295,10 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
}
/* this function is called by mac80211 to flush tx buffer
- * before switch channle or power save, or tx buffer packet
+ * before switch channel or power save, or tx buffer packet
* maybe send after offchannel or rf sleep, this may cause
* dis-association by AP */
-static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1180,6 +1312,7 @@ const struct ieee80211_ops rtl_ops = {
.tx = rtl_op_tx,
.add_interface = rtl_op_add_interface,
.remove_interface = rtl_op_remove_interface,
+ .change_interface = rtl_op_change_interface,
.config = rtl_op_config,
.configure_filter = rtl_op_configure_filter,
.sta_add = rtl_op_sta_add,
diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c
index bdda9b2fffe1..7d52d3d7769f 100644
--- a/drivers/net/wireless/rtlwifi/debug.c
+++ b/drivers/net/wireless/rtlwifi/debug.c
@@ -41,7 +41,10 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
COMP_BEACON | COMP_RATE | COMP_RXDESC | COMP_DIG | COMP_TXAGC |
COMP_POWER | COMP_POWER_TRACKING | COMP_BB_POWERSAVING | COMP_SWAS |
COMP_RF | COMP_TURBO | COMP_RATR | COMP_CMD |
- COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN;
+ COMP_EFUSE | COMP_QOS | COMP_MAC80211 | COMP_REGD | COMP_CHAN |
+ COMP_EASY_CONCURRENT | COMP_EFUSE | COMP_QOS | COMP_MAC80211 |
+ COMP_REGD | COMP_CHAN | COMP_BT_COEXIST;
+
for (i = 0; i < DBGP_TYPE_MAX; i++)
rtlpriv->dbg.dbgp_type[i] = 0;
diff --git a/drivers/net/wireless/rtlwifi/debug.h b/drivers/net/wireless/rtlwifi/debug.h
index fd3269f47685..6d669364e3d9 100644
--- a/drivers/net/wireless/rtlwifi/debug.h
+++ b/drivers/net/wireless/rtlwifi/debug.h
@@ -115,11 +115,11 @@
/* Define EEPROM and EFUSE check module bit*/
#define EEPROM_W BIT(0)
#define EFUSE_PG BIT(1)
-#define EFUSE_READ_ALL BIT(2)
+#define EFUSE_READ_ALL BIT(2)
/* Define init check for module bit*/
#define INIT_EEPROM BIT(0)
-#define INIT_TxPower BIT(1)
+#define INIT_TXPOWER BIT(1)
#define INIT_IQK BIT(2)
#define INIT_RF BIT(3)
@@ -135,6 +135,15 @@
#define PHY_TXPWR BIT(8)
#define PHY_PWRDIFF BIT(9)
+/* Define Dynamic Mechanism check module bit --> FDM */
+#define WA_IOT BIT(0)
+#define DM_PWDB BIT(1)
+#define DM_MONITOR BIT(2)
+#define DM_DIG BIT(3)
+#define DM_EDCA_TURBO BIT(4)
+
+#define DM_PWDB BIT(1)
+
enum dbgp_flag_e {
FQOS = 0,
FTX = 1,
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 8e2f9afb125a..9e3894178e77 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -35,8 +35,6 @@ static const u8 MAX_PGPKT_SIZE = 9;
static const u8 PGPKT_DATA_SIZE = 8;
static const int EFUSE_MAX_SIZE = 512;
-static const u8 EFUSE_OOB_PROTECT_BYTES = 15;
-
static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
{0, 0, 0, 2},
{0, 1, 0, 2},
@@ -240,6 +238,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
u8 rtemp8[1];
u16 efuse_addr = 0;
u8 offset, wren;
+ u8 u1temp = 0;
u16 i;
u16 j;
const u16 efuse_max_section =
@@ -285,10 +284,31 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
}
while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {
- offset = ((*rtemp8 >> 4) & 0x0f);
+ /* Check PG header for section num. */
+ if ((*rtemp8 & 0x1F) == 0x0F) {/* extended header */
+ u1temp = ((*rtemp8 & 0xE0) >> 5);
+ read_efuse_byte(hw, efuse_addr, rtemp8);
- if (offset < efuse_max_section) {
+ if ((*rtemp8 & 0x0F) == 0x0F) {
+ efuse_addr++;
+ read_efuse_byte(hw, efuse_addr, rtemp8);
+
+ if (*rtemp8 != 0xFF &&
+ (efuse_addr < efuse_len)) {
+ efuse_addr++;
+ }
+ continue;
+ } else {
+ offset = ((*rtemp8 & 0xF0) >> 1) | u1temp;
+ wren = (*rtemp8 & 0x0F);
+ efuse_addr++;
+ }
+ } else {
+ offset = ((*rtemp8 >> 4) & 0x0f);
wren = (*rtemp8 & 0x0f);
+ }
+
+ if (offset < efuse_max_section) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
"offset-%d Worden=%x\n", offset, wren);
@@ -391,7 +411,8 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
efuse_used = rtlefuse->efuse_usedbytes;
if ((totalbytes + efuse_used) >=
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
+ (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))
result = false;
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
@@ -932,8 +953,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
u8 badworden = 0x0F;
static int repeat_times;
- if (efuse_get_current_size(hw) >=
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ if (efuse_get_current_size(hw) >= (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
"efuse_pg_packet_write error\n");
return false;
@@ -949,8 +970,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse Power ON\n");
- while (continual && (efuse_addr <
- (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
+ while (continual && (efuse_addr < (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) {
if (write_state == PG_STATE_HEADER) {
badworden = 0x0F;
@@ -1003,7 +1024,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
}
}
- if (efuse_addr >= (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES)) {
+ if (efuse_addr >= (EFUSE_MAX_SIZE -
+ rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN])) {
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
"efuse_addr(%#x) Out of size!!\n", efuse_addr);
}
@@ -1102,8 +1124,11 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
u8 tempval;
u16 tmpV16;
- if (pwrstate && (rtlhal->hw_type !=
- HARDWARE_TYPE_RTL8192SE)) {
+ if (pwrstate && (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)) {
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS],
+ 0x69);
+
tmpV16 = rtl_read_word(rtlpriv,
rtlpriv->cfg->maps[SYS_ISO_CTRL]);
if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
@@ -1153,6 +1178,10 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
}
} else {
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8188EE)
+ rtl_write_byte(rtlpriv,
+ rtlpriv->cfg->maps[EFUSE_ACCESS], 0);
+
if (write) {
tempval = rtl_read_byte(rtlpriv,
rtlpriv->cfg->maps[EFUSE_TEST] +
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
index 2bdea9a8699e..395a326acfb4 100644
--- a/drivers/net/wireless/rtlwifi/efuse.h
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -32,7 +32,6 @@
#define EFUSE_IC_ID_OFFSET 506
-#define EFUSE_REAL_CONTENT_LEN 512
#define EFUSE_MAP_LEN 128
#define EFUSE_MAX_WORD_UNIT 4
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 4261e8ecc4c3..999ffc12578b 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -59,7 +59,7 @@ static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
if (unlikely(ieee80211_is_beacon(fc)))
return BEACON_QUEUE;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return MGNT_QUEUE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
if (ieee80211_is_nullfunc(fc))
@@ -271,9 +271,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
- u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
- u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
@@ -302,8 +299,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
u_pcibridge_aspmsetting);
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
- "PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
- pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
+ "PlatformEnableASPM(): Write reg[%x] = %x\n",
(pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
u_pcibridge_aspmsetting);
@@ -349,6 +345,49 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
return status;
}
+static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
+ struct rtl_priv **buddy_priv)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ bool find_buddy_priv = false;
+ struct rtl_priv *tpriv = NULL;
+ struct rtl_pci_priv *tpcipriv = NULL;
+
+ if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) {
+ list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list,
+ list) {
+ if (tpriv) {
+ tpcipriv = (struct rtl_pci_priv *)tpriv->priv;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "pcipriv->ndis_adapter.funcnumber %x\n",
+ pcipriv->ndis_adapter.funcnumber);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "tpcipriv->ndis_adapter.funcnumber %x\n",
+ tpcipriv->ndis_adapter.funcnumber);
+
+ if ((pcipriv->ndis_adapter.busnumber ==
+ tpcipriv->ndis_adapter.busnumber) &&
+ (pcipriv->ndis_adapter.devnumber ==
+ tpcipriv->ndis_adapter.devnumber) &&
+ (pcipriv->ndis_adapter.funcnumber !=
+ tpcipriv->ndis_adapter.funcnumber)) {
+ find_buddy_priv = true;
+ break;
+ }
+ }
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "find_buddy_priv %d\n", find_buddy_priv);
+
+ if (find_buddy_priv)
+ *buddy_priv = tpriv;
+
+ return find_buddy_priv;
+}
+
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -420,17 +459,14 @@ static void _rtl_pci_io_handler_init(struct device *dev,
}
-static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
-{
-}
-
static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u8 additionlen = FCS_LEN;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct sk_buff *next_skb;
+ u8 additionlen = FCS_LEN;
/* here open is 4, wep/tkip is 8, aes is 12*/
if (info->control.hw_key)
@@ -455,7 +491,7 @@ static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
next_skb))
break;
- if (tcb_desc->empkt_num >= 5)
+ if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num)
break;
}
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -471,11 +507,17 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct sk_buff *skb = NULL;
struct ieee80211_tx_info *info = NULL;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
int tid;
if (!rtlpriv->rtlhal.earlymode_enable)
return;
+ if (rtlpriv->dm.supp_phymode_switch &&
+ (rtlpriv->easy_concurrent_ctl.switch_in_process ||
+ (rtlpriv->buddy_priv &&
+ rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process)))
+ return;
/* we juse use em for BE/BK/VI/VO */
for (tid = 7; tid >= 0; tid--) {
u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)];
@@ -487,7 +529,8 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
spin_lock_bh(&rtlpriv->locks.waitq_lock);
if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
- (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+ (ring->entries - skb_queue_len(&ring->queue) >
+ rtlhal->max_earlymode_num)) {
skb = skb_dequeue(&mac->skb_waitq[tid]);
} else {
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -525,9 +568,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
HW_DESC_OWN);
- /*
- *beacon packet will only use the first
- *descriptor defautly,and the own may not
+ /*beacon packet will only use the first
+ *descriptor by defaut, and the own may not
*be cleared by the hardware
*/
if (own)
@@ -558,8 +600,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
}
/* for sw LPS, just after NULL skb send out, we can
- * sure AP kown we are sleeped, our we should not let
- * rf to sleep*/
+ * sure AP knows we are sleeping, we should not let
+ * rf sleep
+ */
fc = rtl_get_fc(skb);
if (ieee80211_is_nullfunc(fc)) {
if (ieee80211_has_pm(fc)) {
@@ -569,6 +612,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
rtlpriv->psc.state_inap = false;
}
}
+ if (ieee80211_is_action(fc)) {
+ struct ieee80211_mgmt *action_frame =
+ (struct ieee80211_mgmt *)skb->data;
+ if (action_frame->u.action.u.ht_smps.action ==
+ WLAN_HT_ACTION_SMPS) {
+ dev_kfree_skb(skb);
+ goto tx_status_ok;
+ }
+ }
/* update tid tx pkt num */
tid = rtl_get_tid(skb);
@@ -602,7 +654,8 @@ tx_status_ok:
if (((rtlpriv->link_info.num_rx_inperiod +
rtlpriv->link_info.num_tx_inperiod) > 8) ||
(rtlpriv->link_info.num_rx_inperiod > 2)) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
}
@@ -637,6 +690,10 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->link_info.num_rx_inperiod++;
}
+ /* static bcn for roaming */
+ rtl_beacon_statistic(hw, skb);
+ rtl_p2p_info(hw, (void *)skb->data, skb->len);
+
/* for sw lps */
rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
rtl_recognize_peer(hw, (void *)skb->data, skb->len);
@@ -727,9 +784,10 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
_rtl_receive_one(hw, skb, rx_status);
if (((rtlpriv->link_info.num_rx_inperiod +
- rtlpriv->link_info.num_tx_inperiod) > 8) ||
- (rtlpriv->link_info.num_rx_inperiod > 2)) {
- schedule_work(&rtlpriv->works.lps_leave_work);
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2)) {
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
dev_kfree_skb_any(skb);
@@ -803,7 +861,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n");
}
- if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_BCNINT]) {
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
"prepare beacon for interrupt!\n");
tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
@@ -884,6 +942,16 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
_rtl_pci_rx_interrupt(hw);
}
+ /*fw related*/
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ "firmware interrupt!\n");
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.fwevt_wq, 0);
+ }
+ }
+
if (rtlpriv->rtlhal.earlymode_enable)
tasklet_schedule(&rtlpriv->works.irq_tasklet);
@@ -939,13 +1007,17 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
return;
}
-static void rtl_lps_leave_work_callback(struct work_struct *work)
+static void rtl_lps_change_work_callback(struct work_struct *work)
{
struct rtl_works *rtlworks =
- container_of(work, struct rtl_works, lps_leave_work);
+ container_of(work, struct rtl_works, lps_change_work);
struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
- rtl_lps_leave(hw);
+ if (rtlpriv->enter_ps)
+ rtl_lps_enter(hw);
+ else
+ rtl_lps_leave(hw);
}
static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
@@ -1009,7 +1081,8 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
(void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
(unsigned long)hw);
- INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback);
+ INIT_WORK(&rtlpriv->works.lps_change_work,
+ rtl_lps_change_work_callback);
}
static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1458,10 +1531,14 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 i = 0;
int queue_id;
struct rtl8192_tx_ring *ring;
+ if (mac->skip_scan)
+ return;
+
for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
u32 queue_len;
ring = &pcipriv->dev.tx_ring[queue_id];
@@ -1491,7 +1568,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
tasklet_kill(&rtlpriv->works.irq_tasklet);
- cancel_work_sync(&rtlpriv->works.lps_leave_work);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
flush_workqueue(rtlpriv->works.rtl_wq);
destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1566,7 +1643,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
set_hal_stop(rtlhal);
rtlpriv->cfg->ops->disable_interrupt(hw);
- cancel_work_sync(&rtlpriv->works.lps_leave_work);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
while (ppsc->rfchange_inprogress) {
@@ -1673,6 +1750,10 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"8192D PCI-E is found - vid/did=%x/%x\n",
venderid, deviceid);
+ } else if (deviceid == RTL_PCI_8188EE_DID) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Find adapter, Hardware type is 8188EE\n");
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"Err: Unknown device - vid/did=%x/%x\n",
@@ -1704,6 +1785,9 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
+ /* some ARM have no bridge_pdev and will crash here
+ * so we should check if bridge_pdev is NULL
+ */
if (bridge_pdev) {
/*find bridge info if available */
pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
@@ -1758,6 +1842,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pcipriv->ndis_adapter.amd_l1_patch);
rtl_pci_parse_configuration(pdev, hw);
+ list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list);
return true;
}
@@ -1804,6 +1889,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, hw);
rtlpriv = hw->priv;
+ rtlpriv->hw = hw;
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
init_completion(&rtlpriv->firmware_loading_complete);
@@ -1812,6 +1898,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
rtlpriv->rtlhal.interface = INTF_PCI;
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
+ rtlpriv->glb_var = &global_var;
/*
*init dbgp flags before all
@@ -1916,7 +2003,6 @@ int rtl_pci_probe(struct pci_dev *pdev,
fail3:
rtl_deinit_core(hw);
- _rtl_pci_io_handler_release(hw);
if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
@@ -1965,14 +2051,15 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtl_pci_deinit(hw);
rtl_deinit_core(hw);
- _rtl_pci_io_handler_release(hw);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
if (rtlpci->irq_alloc) {
+ synchronize_irq(rtlpci->pdev->irq);
free_irq(rtlpci->pdev->irq, hw);
rtlpci->irq_alloc = 0;
}
+ list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
pci_release_regions(pdev);
@@ -2034,6 +2121,7 @@ struct rtl_intf_ops rtl_pci_ops = {
.read_efuse_byte = read_efuse_byte,
.adapter_start = rtl_pci_start,
.adapter_stop = rtl_pci_stop,
+ .check_buddy_priv = rtl_pci_check_buddy_priv,
.adapter_tx = rtl_pci_tx,
.flush = rtl_pci_flush,
.reset_trx_ring = rtl_pci_reset_trx_ring,
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 65b08f50022e..d3262ec45d23 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -94,6 +94,7 @@
#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */
#define RTL_PCI_8192DE_DID 0x8193 /*8192de */
#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/
+#define RTL_PCI_8188EE_DID 0x8179 /*8188ee*/
/*8192 support 16 pages of IO registers*/
#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000
@@ -175,6 +176,7 @@ struct rtl_pci {
/*irq */
u8 irq_alloc;
u32 irq_mask[2];
+ u32 sys_irq_mask;
/*Bcn control register setting */
u32 reg_bcn_ctrl_val;
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 13ad33e85577..884bceae38a9 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -180,6 +180,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
return;
}
+ if (mac->p2p_in_use)
+ return;
+
if (mac->link_state > MAC80211_NOLINK)
return;
@@ -189,6 +192,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
if (rtlpriv->sec.being_setkey)
return;
+ if (rtlpriv->cfg->ops->bt_coex_off_before_lps)
+ rtlpriv->cfg->ops->bt_coex_off_before_lps(hw);
+
if (ppsc->inactiveps) {
rtstate = ppsc->rfpwr_state;
@@ -231,6 +237,9 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
&rtlpriv->works.ips_nic_off_wq, MSECS(100));
}
+/* NOTICE: any opmode should exc nic_on, or disable without
+ * nic_on may something wrong, like adhoc TP
+ */
void rtl_ips_nic_on(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -299,7 +308,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- u8 rpwm_val, fw_pwrmode;
+ bool enter_fwlps;
if (mac->opmode == NL80211_IFTYPE_ADHOC)
return;
@@ -324,43 +333,31 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
*/
if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
- bool fw_current_inps;
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS leave ps_mode:%x\n",
FW_PS_ACTIVE_MODE);
-
- rpwm_val = 0x0C; /* RF on */
- fw_pwrmode = FW_PS_ACTIVE_MODE;
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
- &rpwm_val);
+ enter_fwlps = false;
+ ppsc->pwr_mode = FW_PS_ACTIVE_MODE;
+ ppsc->smart_ps = 0;
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- &fw_pwrmode);
- fw_current_inps = false;
-
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_FW_PSMODE_STATUS,
- (u8 *) (&fw_current_inps));
+ HW_VAR_FW_LPS_ACTION,
+ (u8 *)(&enter_fwlps));
+ if (ppsc->p2p_ps_info.opp_ps)
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
} else {
if (rtl_get_fwlps_doze(hw)) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
"FW LPS enter ps_mode:%x\n",
ppsc->fwctrl_psmode);
-
- rpwm_val = 0x02; /* RF off */
- fw_current_inps = true;
+ enter_fwlps = true;
+ ppsc->pwr_mode = ppsc->fwctrl_psmode;
+ ppsc->smart_ps = 2;
rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_FW_PSMODE_STATUS,
- (u8 *) (&fw_current_inps));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_H2C_FW_PWRMODE,
- &ppsc->fwctrl_psmode);
+ HW_VAR_FW_LPS_ACTION,
+ (u8 *)(&enter_fwlps));
- rtlpriv->cfg->ops->set_hw_reg(hw,
- HW_VAR_SET_RPWM,
- &rpwm_val);
} else {
/* Reset the power save related parameters. */
ppsc->dot11_psmode = EACTIVE;
@@ -642,3 +639,286 @@ void rtl_swlps_wq_callback(void *data)
rtlpriv->psc.state = ps;
}
}
+
+static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data,
+ unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+ u8 *pos, *end, *ie;
+ u16 noa_len;
+ static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+ u8 noa_num, index, i, noa_index = 0;
+ bool find_p2p_ie = false , find_p2p_ps_ie = false;
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ ie = NULL;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ return;
+
+ if (pos[0] == 221 && pos[1] > 4) {
+ if (memcmp(&pos[2], p2p_oui_ie_type, 4) == 0) {
+ ie = pos + 2+4;
+ break;
+ }
+ }
+ pos += 2 + pos[1];
+ }
+
+ if (ie == NULL)
+ return;
+ find_p2p_ie = true;
+ /*to find noa ie*/
+ while (ie + 1 < end) {
+ noa_len = READEF2BYTE(&ie[1]);
+ if (ie + 3 + ie[1] > end)
+ return;
+
+ if (ie[0] == 12) {
+ find_p2p_ps_ie = true;
+ if ((noa_len - 2) % 13 != 0) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "P2P notice of absence: invalid length.%d\n",
+ noa_len);
+ return;
+ } else {
+ noa_num = (noa_len - 2) / 13;
+ }
+ noa_index = ie[3];
+ if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+ P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "update NOA ie.\n");
+ p2pinfo->noa_index = noa_index;
+ p2pinfo->opp_ps = (ie[4] >> 7);
+ p2pinfo->ctwindow = ie[4] & 0x7F;
+ p2pinfo->noa_num = noa_num;
+ index = 5;
+ for (i = 0; i < noa_num; i++) {
+ p2pinfo->noa_count_type[i] =
+ READEF1BYTE(ie+index);
+ index += 1;
+ p2pinfo->noa_duration[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_interval[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_start_time[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ }
+
+ if (p2pinfo->opp_ps == 1) {
+ p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+ /* Driver should wait LPS entering
+ * CTWindow
+ */
+ if (rtlpriv->psc.fw_current_inpsmode)
+ rtl_p2p_ps_cmd(hw,
+ P2P_PS_ENABLE);
+ } else if (p2pinfo->noa_num > 0) {
+ p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+ } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+ }
+ break;
+ }
+ ie += 3 + noa_len;
+ }
+
+ if (find_p2p_ie == true) {
+ if ((p2pinfo->p2p_ps_mode > P2P_PS_NONE) &&
+ (find_p2p_ps_ie == false))
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+}
+
+static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data,
+ unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+ u8 noa_num, index, i, noa_index = 0;
+ u8 *pos, *end, *ie;
+ u16 noa_len;
+ static u8 p2p_oui_ie_type[4] = {0x50, 0x6f, 0x9a, 0x09};
+
+ pos = (u8 *)&mgmt->u.action.category;
+ end = data + len;
+ ie = NULL;
+
+ if (pos[0] == 0x7f) {
+ if (memcmp(&pos[1], p2p_oui_ie_type, 4) == 0)
+ ie = pos + 3+4;
+ }
+
+ if (ie == NULL)
+ return;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "action frame find P2P IE.\n");
+ /*to find noa ie*/
+ while (ie + 1 < end) {
+ noa_len = READEF2BYTE(&ie[1]);
+ if (ie + 3 + ie[1] > end)
+ return;
+
+ if (ie[0] == 12) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "find NOA IE.\n");
+ RT_PRINT_DATA(rtlpriv, COMP_FW, DBG_LOUD, "noa ie ",
+ ie, noa_len);
+ if ((noa_len - 2) % 13 != 0) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "P2P notice of absence: invalid length.%d\n",
+ noa_len);
+ return;
+ } else {
+ noa_num = (noa_len - 2) / 13;
+ }
+ noa_index = ie[3];
+ if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode ==
+ P2P_PS_NONE || noa_index != p2pinfo->noa_index) {
+ p2pinfo->noa_index = noa_index;
+ p2pinfo->opp_ps = (ie[4] >> 7);
+ p2pinfo->ctwindow = ie[4] & 0x7F;
+ p2pinfo->noa_num = noa_num;
+ index = 5;
+ for (i = 0; i < noa_num; i++) {
+ p2pinfo->noa_count_type[i] =
+ READEF1BYTE(ie+index);
+ index += 1;
+ p2pinfo->noa_duration[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_interval[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ p2pinfo->noa_start_time[i] =
+ READEF4BYTE(ie+index);
+ index += 4;
+ }
+
+ if (p2pinfo->opp_ps == 1) {
+ p2pinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+ /* Driver should wait LPS entering
+ * CTWindow
+ */
+ if (rtlpriv->psc.fw_current_inpsmode)
+ rtl_p2p_ps_cmd(hw,
+ P2P_PS_ENABLE);
+ } else if (p2pinfo->noa_num > 0) {
+ p2pinfo->p2p_ps_mode = P2P_PS_NOA;
+ rtl_p2p_ps_cmd(hw, P2P_PS_ENABLE);
+ } else if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
+ }
+ }
+ break;
+ }
+ ie += 3 + noa_len;
+ }
+}
+
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlpriv->psc.p2p_ps_info);
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, " p2p state %x\n", p2p_ps_state);
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+
+ p2pinfo->noa_index = 0;
+ p2pinfo->ctwindow = 0;
+ p2pinfo->opp_ps = 0;
+ p2pinfo->noa_num = 0;
+ p2pinfo->p2p_ps_mode = P2P_PS_NONE;
+ if (rtlps->fw_current_inpsmode == true) {
+ if (rtlps->smart_ps == 0) {
+ rtlps->smart_ps = 2;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&rtlps->pwr_mode));
+ }
+ }
+ break;
+ case P2P_PS_ENABLE:
+ if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+
+ if (p2pinfo->ctwindow > 0) {
+ if (rtlps->smart_ps != 0) {
+ rtlps->smart_ps = 0;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&rtlps->pwr_mode));
+ }
+ }
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+ }
+ break;
+ case P2P_PS_SCAN:
+ case P2P_PS_SCAN_DONE:
+ case P2P_PS_ALLSTASLEEP:
+ if (p2pinfo->p2p_ps_mode > P2P_PS_NONE) {
+ p2pinfo->p2p_ps_state = p2p_ps_state;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+ (u8 *)(&p2p_ps_state));
+ }
+ break;
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "ctwindow %x oppps %x\n", p2pinfo->ctwindow, p2pinfo->opp_ps);
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
+ "count %x duration %x index %x interval %x start time %x noa num %x\n",
+ p2pinfo->noa_count_type[0], p2pinfo->noa_duration[0],
+ p2pinfo->noa_index, p2pinfo->noa_interval[0],
+ p2pinfo->noa_start_time[0], p2pinfo->noa_num);
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "end\n");
+}
+
+void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (void *)data;
+
+ if (!mac->p2p)
+ return;
+ if (mac->link_state != MAC80211_LINKED)
+ return;
+ /* min. beacon length + FCS_LEN */
+ if (len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ /* check if this really is a beacon */
+ if (!(ieee80211_is_beacon(hdr->frame_control) ||
+ ieee80211_is_probe_resp(hdr->frame_control) ||
+ ieee80211_is_action(hdr->frame_control)))
+ return;
+
+ if (ieee80211_is_action(hdr->frame_control))
+ rtl_p2p_action_ie(hw, data, len - FCS_LEN);
+ else
+ rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
+}
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index 1357856998c2..4d682b753f50 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -47,5 +47,7 @@ void rtl_swlps_wq_callback(void *data);
void rtl_swlps_rfon_wq_callback(void *data);
void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
+void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
new file mode 100644
index 000000000000..5b194e97f4b3
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/Makefile
@@ -0,0 +1,16 @@
+rtl8188ee-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ pwrseq.o \
+ pwrseqcmd.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o
+
+obj-$(CONFIG_RTL8188EE) += rtl8188ee.o
+
+ccflags-y += -Idrivers/net/wireless/rtlwifi -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/def.h b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
new file mode 100644
index 000000000000..c764fff9ebe6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/def.h
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_DEF_H__
+#define __RTL92C_DEF_H__
+
+#define HAL_RETRY_LIMIT_INFRA 48
+#define HAL_RETRY_LIMIT_AP_ADHOC 7
+
+#define RESET_DELAY_8185 20
+
+#define RT_IBSS_INT_MASKS (IMR_BCNINT | IMR_TBDOK | IMR_TBDER)
+#define RT_AC_INT_MASKS (IMR_VIDOK | IMR_VODOK | IMR_BEDOK|IMR_BKDOK)
+
+#define NUM_OF_FIRMWARE_QUEUE 10
+#define NUM_OF_PAGES_IN_FW 0x100
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO 0x07
+#define NUM_OF_PAGE_IN_FW_QUEUE_HCCA 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_CMD 0x0
+#define NUM_OF_PAGE_IN_FW_QUEUE_MGNT 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_HIGH 0x02
+#define NUM_OF_PAGE_IN_FW_QUEUE_BCN 0x2
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB 0xA1
+
+#define NUM_OF_PAGE_IN_FW_QUEUE_BK_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_BE_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VI_DTM 0x048
+#define NUM_OF_PAGE_IN_FW_QUEUE_VO_DTM 0x026
+#define NUM_OF_PAGE_IN_FW_QUEUE_PUB_DTM 0x00
+
+#define MAX_LINES_HWCONFIG_TXT 1000
+#define MAX_BYTES_LINE_HWCONFIG_TXT 256
+
+#define SW_THREE_WIRE 0
+#define HW_THREE_WIRE 2
+
+#define BT_DEMO_BOARD 0
+#define BT_QA_BOARD 1
+#define BT_FPGA 2
+
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE 0
+#define HAL_PRIME_CHNL_OFFSET_LOWER 1
+#define HAL_PRIME_CHNL_OFFSET_UPPER 2
+
+#define MAX_H2C_QUEUE_NUM 10
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+#define AC2QUEUEID(_AC) (_AC)
+
+#define C2H_RX_CMD_HDR_LEN 8
+#define GET_C2H_CMD_CMD_LEN(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 0, 16)
+#define GET_C2H_CMD_ELEMENT_ID(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 16, 8)
+#define GET_C2H_CMD_CMD_SEQ(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 24, 7)
+#define GET_C2H_CMD_CONTINUE(__prxhdr) \
+ LE_BITS_TO_4BYTE((__prxhdr), 31, 1)
+#define GET_C2H_CMD_CONTENT(__prxhdr) \
+ ((u8 *)(__prxhdr) + C2H_RX_CMD_HDR_LEN)
+
+#define GET_C2H_CMD_FEEDBACK_ELEMENT_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 0, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_LEN(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 8, 8)
+#define GET_C2H_CMD_FEEDBACK_CCX_CMD_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE((__pcmdfbhdr), 16, 16)
+#define GET_C2H_CMD_FEEDBACK_CCX_MAC_ID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 0, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_VALID(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 7, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_RETRY_CNT(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 8, 5)
+#define GET_C2H_CMD_FEEDBACK_CCX_TOK(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 15, 1)
+#define GET_C2H_CMD_FEEDBACK_CCX_QSEL(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 16, 4)
+#define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \
+ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12)
+
+#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3)
+
+
+/* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3
+ * [7] Manufacturer: TSMC=0, UMC=1
+ * [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2
+ * [3] Chip type: TEST=0, NORMAL=1
+ * [2:0] IC type: 81xxC=0, 8723=1, 92D=2
+ */
+#define CHIP_8723 BIT(0)
+#define CHIP_92D BIT(1)
+#define NORMAL_CHIP BIT(3)
+#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6)))
+#define RF_TYPE_1T2R BIT(4)
+#define RF_TYPE_2T2R BIT(5)
+#define CHIP_VENDOR_UMC BIT(7)
+#define B_CUT_VERSION BIT(12)
+#define C_CUT_VERSION BIT(13)
+#define D_CUT_VERSION ((BIT(12)|BIT(13)))
+#define E_CUT_VERSION BIT(14)
+
+
+/* MASK */
+#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK BIT(3)
+#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK BIT(7)
+#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK)
+#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK)
+#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK)
+#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK)
+#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK)
+
+
+#define IS_81XXC(version) \
+ ((GET_CVID_IC_TYPE(version) == 0) ? true : false)
+#define IS_8723_SERIES(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_8723) ? true : false)
+#define IS_92D(version) \
+ ((GET_CVID_IC_TYPE(version) == CHIP_92D) ? true : false)
+
+#define IS_NORMAL_CHIP(version) \
+ ((GET_CVID_CHIP_TYPE(version)) ? true : false)
+#define IS_NORMAL_CHIP92D(version) \
+ ((GET_CVID_CHIP_TYPE(version)) ? true : false)
+
+#define IS_1T1R(version) \
+ ((GET_CVID_RF_TYPE(version)) ? false : true)
+#define IS_1T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version) \
+ ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version) \
+ ((GET_CVID_MANUFACTUER(version)) ? true : false)
+
+#define IS_92C_SERIAL(version) \
+ ((IS_81XXC(version) && IS_2T2R(version)) ? true : false)
+#define IS_81xxC_VENDOR_UMC_A_CUT(version) \
+ (IS_81XXC(version) ? ((IS_CHIP_VENDOR_UMC(version)) ? \
+ ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version) \
+ (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ? \
+ ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true \
+ : false) : false) : false)
+
+enum version_8188e {
+ VERSION_TEST_CHIP_88E = 0x00,
+ VERSION_NORMAL_CHIP_88E = 0x01,
+ VERSION_UNKNOWN = 0xFF,
+};
+
+enum rx_packet_type {
+ NORMAL_RX,
+ TX_REPORT1,
+ TX_REPORT2,
+ HIS_REPORT,
+};
+
+enum rtl819x_loopback_e {
+ RTL819X_NO_LOOPBACK = 0,
+ RTL819X_MAC_LOOPBACK = 1,
+ RTL819X_DMA_LOOPBACK = 2,
+ RTL819X_CCK_LOOPBACK = 3,
+};
+
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum rf_power_state {
+ RF_ON,
+ RF_OFF,
+ RF_SLEEP,
+ RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+ POWER_SAVE_MODE_ACTIVE,
+ POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+ POWERCFG_MAX_POWER_SAVINGS,
+ POWERCFG_GLOBAL_POWER_SAVINGS,
+ POWERCFG_LOCAL_POWER_SAVINGS,
+ POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+ INTF_SEL1_MINICARD,
+ INTF_SEL0_PCIE,
+ INTF_SEL2_RSV,
+ INTF_SEL3_RSV,
+};
+
+enum hal_fw_c2h_cmd_id {
+ HAL_FW_C2H_CMD_Read_MACREG,
+ HAL_FW_C2H_CMD_Read_BBREG,
+ HAL_FW_C2H_CMD_Read_RFREG,
+ HAL_FW_C2H_CMD_Read_EEPROM,
+ HAL_FW_C2H_CMD_Read_EFUSE,
+ HAL_FW_C2H_CMD_Read_CAM,
+ HAL_FW_C2H_CMD_Get_BasicRate,
+ HAL_FW_C2H_CMD_Get_DataRate,
+ HAL_FW_C2H_CMD_Survey,
+ HAL_FW_C2H_CMD_SurveyDone,
+ HAL_FW_C2H_CMD_JoinBss,
+ HAL_FW_C2H_CMD_AddSTA,
+ HAL_FW_C2H_CMD_DelSTA,
+ HAL_FW_C2H_CMD_AtimDone,
+ HAL_FW_C2H_CMD_TX_Report,
+ HAL_FW_C2H_CMD_CCX_Report,
+ HAL_FW_C2H_CMD_DTM_Report,
+ HAL_FW_C2H_CMD_TX_Rate_Statistics,
+ HAL_FW_C2H_CMD_C2HLBK,
+ HAL_FW_C2H_CMD_C2HDBG,
+ HAL_FW_C2H_CMD_C2HFEEDBACK,
+ HAL_FW_C2H_CMD_MAX
+};
+
+enum wake_on_wlan_mode {
+ ewowlandisable,
+ ewakeonmagicpacketonly,
+ ewakeonpatternmatchonly,
+ ewakeonbothtypepacket
+};
+
+enum rtl_desc_qsel {
+ QSLT_BK = 0x2,
+ QSLT_BE = 0x0,
+ QSLT_VI = 0x5,
+ QSLT_VO = 0x7,
+ QSLT_BEACON = 0x10,
+ QSLT_HIGH = 0x11,
+ QSLT_MGNT = 0x12,
+ QSLT_CMD = 0x13,
+};
+
+enum rtl_desc92c_rate {
+ DESC92C_RATE1M = 0x00,
+ DESC92C_RATE2M = 0x01,
+ DESC92C_RATE5_5M = 0x02,
+ DESC92C_RATE11M = 0x03,
+
+ DESC92C_RATE6M = 0x04,
+ DESC92C_RATE9M = 0x05,
+ DESC92C_RATE12M = 0x06,
+ DESC92C_RATE18M = 0x07,
+ DESC92C_RATE24M = 0x08,
+ DESC92C_RATE36M = 0x09,
+ DESC92C_RATE48M = 0x0a,
+ DESC92C_RATE54M = 0x0b,
+
+ DESC92C_RATEMCS0 = 0x0c,
+ DESC92C_RATEMCS1 = 0x0d,
+ DESC92C_RATEMCS2 = 0x0e,
+ DESC92C_RATEMCS3 = 0x0f,
+ DESC92C_RATEMCS4 = 0x10,
+ DESC92C_RATEMCS5 = 0x11,
+ DESC92C_RATEMCS6 = 0x12,
+ DESC92C_RATEMCS7 = 0x13,
+ DESC92C_RATEMCS8 = 0x14,
+ DESC92C_RATEMCS9 = 0x15,
+ DESC92C_RATEMCS10 = 0x16,
+ DESC92C_RATEMCS11 = 0x17,
+ DESC92C_RATEMCS12 = 0x18,
+ DESC92C_RATEMCS13 = 0x19,
+ DESC92C_RATEMCS14 = 0x1a,
+ DESC92C_RATEMCS15 = 0x1b,
+ DESC92C_RATEMCS15_SG = 0x1c,
+ DESC92C_RATEMCS32 = 0x20,
+};
+
+struct phy_sts_cck_8192s_t {
+ u8 adc_pwdb_X[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8192c {
+ u8 element_id;
+ u32 cmd_len;
+ u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
new file mode 100644
index 000000000000..21a5cf060677
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -0,0 +1,1794 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "trx.h"
+
+static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
+ 0x7f8001fe, /* 0, +6.0dB */
+ 0x788001e2, /* 1, +5.5dB */
+ 0x71c001c7, /* 2, +5.0dB */
+ 0x6b8001ae, /* 3, +4.5dB */
+ 0x65400195, /* 4, +4.0dB */
+ 0x5fc0017f, /* 5, +3.5dB */
+ 0x5a400169, /* 6, +3.0dB */
+ 0x55400155, /* 7, +2.5dB */
+ 0x50800142, /* 8, +2.0dB */
+ 0x4c000130, /* 9, +1.5dB */
+ 0x47c0011f, /* 10, +1.0dB */
+ 0x43c0010f, /* 11, +0.5dB */
+ 0x40000100, /* 12, +0dB */
+ 0x3c8000f2, /* 13, -0.5dB */
+ 0x390000e4, /* 14, -1.0dB */
+ 0x35c000d7, /* 15, -1.5dB */
+ 0x32c000cb, /* 16, -2.0dB */
+ 0x300000c0, /* 17, -2.5dB */
+ 0x2d4000b5, /* 18, -3.0dB */
+ 0x2ac000ab, /* 19, -3.5dB */
+ 0x288000a2, /* 20, -4.0dB */
+ 0x26000098, /* 21, -4.5dB */
+ 0x24000090, /* 22, -5.0dB */
+ 0x22000088, /* 23, -5.5dB */
+ 0x20000080, /* 24, -6.0dB */
+ 0x1e400079, /* 25, -6.5dB */
+ 0x1c800072, /* 26, -7.0dB */
+ 0x1b00006c, /* 27. -7.5dB */
+ 0x19800066, /* 28, -8.0dB */
+ 0x18000060, /* 29, -8.5dB */
+ 0x16c0005b, /* 30, -9.0dB */
+ 0x15800056, /* 31, -9.5dB */
+ 0x14400051, /* 32, -10.0dB */
+ 0x1300004c, /* 33, -10.5dB */
+ 0x12000048, /* 34, -11.0dB */
+ 0x11000044, /* 35, -11.5dB */
+ 0x10000040, /* 36, -12.0dB */
+ 0x0f00003c, /* 37, -12.5dB */
+ 0x0e400039, /* 38, -13.0dB */
+ 0x0d800036, /* 39, -13.5dB */
+ 0x0cc00033, /* 40, -14.0dB */
+ 0x0c000030, /* 41, -14.5dB */
+ 0x0b40002d, /* 42, -15.0dB */
+};
+
+static const u8 cck_tbl_ch1_13[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 20, -10.0dB*/
+ {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 21, -10.5dB*/
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /* 22, -11.0dB*/
+ {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /* 23, -11.5dB*/
+ {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /* 24, -12.0dB*/
+ {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /* 25, -12.5dB*/
+ {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /* 26, -13.0dB*/
+ {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 27, -13.5dB*/
+ {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /* 28, -14.0dB*/
+ {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 29, -14.5dB*/
+ {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /* 30, -15.0dB*/
+ {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /* 31, -15.5dB*/
+ {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01} /* 32, -16.0dB*/
+};
+
+static const u8 cck_tbl_ch14[CCK_TABLE_SIZE][8] = {
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0dB */
+ {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /* 1, -0.5dB */
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 2, -1.0dB */
+ {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /* 3, -1.5dB */
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 4, -2.0dB */
+ {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /* 5, -2.5dB */
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 6, -3.0dB */
+ {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /* 7, -3.5dB */
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 8, -4.0dB */
+ {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /* 9, -4.5dB */
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 10, -5.0dB */
+ {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 11, -5.5dB */
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 12, -6.0dB */
+ {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /* 13, -6.5dB */
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 14, -7.0dB */
+ {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 15, -7.5dB */
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 16, -8.0dB */
+ {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 17, -8.5dB */
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 18, -9.0dB */
+ {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 19, -9.5dB */
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 20, -10.0dB*/
+ {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 21, -10.5dB*/
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /* 22, -11.0dB*/
+ {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 23, -11.5dB*/
+ {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /* 24, -12.0dB*/
+ {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 25, -12.5dB*/
+ {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 26, -13.0dB*/
+ {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /* 27, -13.5dB*/
+ {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 28, -14.0dB*/
+ {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 29, -14.5dB*/
+ {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 30, -15.0dB*/
+ {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /* 31, -15.5dB*/
+ {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB*/
+};
+
+#define CAL_SWING_OFF(_off, _dir, _size, _del) \
+ do { \
+ for (_off = 0; _off < _size; _off++) { \
+ if (_del < thermal_threshold[_dir][_off]) { \
+ if (_off != 0) \
+ _off--; \
+ break; \
+ } \
+ } \
+ if (_off >= _size) \
+ _off = _size - 1; \
+ } while (0)
+
+static void rtl88e_set_iqk_matrix(struct ieee80211_hw *hw,
+ u8 ofdm_index, u8 rfpath,
+ long iqk_result_x, long iqk_result_y)
+{
+ long ele_a = 0, ele_d, ele_c = 0, value32;
+
+ ele_d = (ofdmswing_table[ofdm_index] & 0xFFC00000)>>22;
+
+ if (iqk_result_x != 0) {
+ if ((iqk_result_x & 0x00000200) != 0)
+ iqk_result_x = iqk_result_x | 0xFFFFFC00;
+ ele_a = ((iqk_result_x * ele_d)>>8)&0x000003FF;
+
+ if ((iqk_result_y & 0x00000200) != 0)
+ iqk_result_y = iqk_result_y | 0xFFFFFC00;
+ ele_c = ((iqk_result_y * ele_d)>>8)&0x000003FF;
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
+ value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, value32);
+ value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), value32);
+ break;
+ case RF90_PATH_B:
+ value32 = (ele_d << 22)|((ele_c & 0x3F)<<16) | ele_a;
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL,
+ MASKDWORD, value32);
+ value32 = (ele_c & 0x000003C0) >> 6;
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, value32);
+ value32 = ((iqk_result_x * ele_d) >> 7) & 0x01;
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), value32);
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD,
+ ofdmswing_table[ofdm_index]);
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(24), 0x00);
+ break;
+ case RF90_PATH_B:
+ rtl_set_bbreg(hw, ROFDM0_XBTXIQIMBAL, MASKDWORD,
+ ofdmswing_table[ofdm_index]);
+ rtl_set_bbreg(hw, ROFDM0_XDTXAFE, MASKH4BITS, 0x00);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(28), 0x00);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+ u8 type, u8 *pdirection, u32 *poutwrite_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ u8 pwr_val = 0;
+ u8 cck_base = rtldm->swing_idx_cck_base;
+ u8 cck_val = rtldm->swing_idx_cck;
+ u8 ofdm_base = rtldm->swing_idx_ofdm_base;
+ u8 ofdm_val = rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A];
+
+ if (type == 0) {
+ if (ofdm_val <= ofdm_base) {
+ *pdirection = 1;
+ pwr_val = ofdm_base - ofdm_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = ofdm_val - ofdm_base;
+ }
+ } else if (type == 1) {
+ if (cck_val <= cck_base) {
+ *pdirection = 1;
+ pwr_val = cck_base - cck_val;
+ } else {
+ *pdirection = 2;
+ pwr_val = cck_val - cck_base;
+ }
+ }
+
+ if (pwr_val >= TXPWRTRACK_MAX_IDX && (*pdirection == 1))
+ pwr_val = TXPWRTRACK_MAX_IDX;
+
+ *poutwrite_val = pwr_val | (pwr_val << 8) | (pwr_val << 16) |
+ (pwr_val << 24);
+}
+
+
+static void rtl88e_chk_tx_track(struct ieee80211_hw *hw,
+ enum pwr_track_control_method method,
+ u8 rfpath, u8 index)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ int jj = rtldm->swing_idx_cck;
+ int i;
+
+ if (method == TXAGC) {
+ if (rtldm->swing_flag_ofdm == true ||
+ rtldm->swing_flag_cck == true) {
+ u8 chan = rtlphy->current_channel;
+ rtl88e_phy_set_txpower_level(hw, chan);
+ rtldm->swing_flag_ofdm = false;
+ rtldm->swing_flag_cck = false;
+ }
+ } else if (method == BBSWING) {
+ if (!rtldm->cck_inch14) {
+ for (i = 0; i < 8; i++)
+ rtl_write_byte(rtlpriv, 0xa22 + i,
+ cck_tbl_ch1_13[jj][i]);
+ } else {
+ for (i = 0; i < 8; i++)
+ rtl_write_byte(rtlpriv, 0xa22 + i,
+ cck_tbl_ch14[jj][i]);
+ }
+
+ if (rfpath == RF90_PATH_A) {
+ long x = rtlphy->iqk_matrix[index].value[0][0];
+ long y = rtlphy->iqk_matrix[index].value[0][1];
+ u8 indx = rtldm->swing_idx_ofdm[rfpath];
+ rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+ } else if (rfpath == RF90_PATH_B) {
+ u8 indx = rtldm->swing_idx_ofdm[rfpath];
+ long x = rtlphy->iqk_matrix[indx].value[0][4];
+ long y = rtlphy->iqk_matrix[indx].value[0][5];
+ rtl88e_set_iqk_matrix(hw, indx, rfpath, x, y);
+ }
+ } else {
+ return;
+ }
+}
+
+static void rtl88e_dm_diginit(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+ dm_dig->dig_enable_flag = true;
+ dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
+ dm_dig->pre_igvalue = 0;
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+ dm_dig->presta_cstate = DIG_STA_DISCONNECT;
+ dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
+ dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
+ dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH;
+ dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+ dm_dig->rx_gain_max = DM_DIG_MAX;
+ dm_dig->rx_gain_min = DM_DIG_MIN;
+ dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_dig->back_range_max = DM_DIG_BACKOFF_MAX;
+ dm_dig->back_range_min = DM_DIG_BACKOFF_MIN;
+ dm_dig->pre_cck_cca_thres = 0xff;
+ dm_dig->cur_cck_cca_thres = 0x83;
+ dm_dig->forbidden_igi = DM_DIG_MIN;
+ dm_dig->large_fa_hit = 0;
+ dm_dig->recover_cnt = 0;
+ dm_dig->dig_min_0 = 0x25;
+ dm_dig->dig_min_1 = 0x25;
+ dm_dig->media_connect_0 = false;
+ dm_dig->media_connect_1 = false;
+ rtlpriv->dm.dm_initialgain_enable = true;
+}
+
+static u8 rtl88e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ long rssi_val_min = 0;
+
+ if ((dm_dig->curmultista_cstate == DIG_MULTISTA_CONNECT) &&
+ (dm_dig->cursta_cstate == DIG_STA_CONNECT)) {
+ if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)
+ rssi_val_min =
+ (rtlpriv->dm.entry_min_undec_sm_pwdb >
+ rtlpriv->dm.undec_sm_pwdb) ?
+ rtlpriv->dm.undec_sm_pwdb :
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ else
+ rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+ } else if (dm_dig->cursta_cstate == DIG_STA_CONNECT ||
+ dm_dig->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
+ rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+ } else if (dm_dig->curmultista_cstate ==
+ DIG_MULTISTA_CONNECT) {
+ rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
+ }
+ return (u8)rssi_val_min;
+}
+
+static void rtl88e_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ u32 ret_value;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *alm_cnt = &(rtlpriv->falsealm_cnt);
+
+ rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 1);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 1);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM0_FRAMESYNC, MASKDWORD);
+ alm_cnt->cnt_fast_fsync_fail = (ret_value&0xffff);
+ alm_cnt->cnt_sb_search_fail = ((ret_value&0xffff0000)>>16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+ alm_cnt->cnt_ofdm_cca = (ret_value&0xffff);
+ alm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+ alm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+ alm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+ alm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+ alm_cnt->cnt_ofdm_fail = alm_cnt->cnt_parity_fail +
+ alm_cnt->cnt_rate_illegal +
+ alm_cnt->cnt_crc8_fail +
+ alm_cnt->cnt_mcs_fail +
+ alm_cnt->cnt_fast_fsync_fail +
+ alm_cnt->cnt_sb_search_fail;
+
+ ret_value = rtl_get_bbreg(hw, REG_SC_CNT, MASKDWORD);
+ alm_cnt->cnt_bw_lsc = (ret_value & 0xffff);
+ alm_cnt->cnt_bw_usc = ((ret_value & 0xffff0000) >> 16);
+
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(12), 1);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
+ alm_cnt->cnt_cck_fail = ret_value;
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
+ alm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+
+ ret_value = rtl_get_bbreg(hw, RCCK0_CCA_CNT, MASKDWORD);
+ alm_cnt->cnt_cck_cca = ((ret_value & 0xff) << 8) |
+ ((ret_value&0xFF00)>>8);
+
+ alm_cnt->cnt_all = alm_cnt->cnt_fast_fsync_fail +
+ alm_cnt->cnt_sb_search_fail +
+ alm_cnt->cnt_parity_fail +
+ alm_cnt->cnt_rate_illegal +
+ alm_cnt->cnt_crc8_fail +
+ alm_cnt->cnt_mcs_fail +
+ alm_cnt->cnt_cck_fail;
+ alm_cnt->cnt_cca_all = alm_cnt->cnt_ofdm_cca + alm_cnt->cnt_cck_cca;
+
+ rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 1);
+ rtl_set_bbreg(hw, ROFDM0_TRSWISOLATION, BIT(31), 0);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(27), 1);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(27), 0);
+ rtl_set_bbreg(hw, ROFDM0_LSTF, BIT(31), 0);
+ rtl_set_bbreg(hw, ROFDM1_LSTF, BIT(31), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(13)|BIT(12), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(13)|BIT(12), 2);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(15)|BIT(14), 0);
+ rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(15)|BIT(14), 2);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+ "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+ alm_cnt->cnt_parity_fail,
+ alm_cnt->cnt_rate_illegal,
+ alm_cnt->cnt_crc8_fail, alm_cnt->cnt_mcs_fail);
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
+ alm_cnt->cnt_ofdm_fail,
+ alm_cnt->cnt_cck_fail, alm_cnt->cnt_all);
+}
+
+static void rtl88e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ u8 cur_cck_cca_thresh;
+
+ if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+ dm_dig->rssi_val_min = rtl88e_dm_initial_gain_min_pwdb(hw);
+ if (dm_dig->rssi_val_min > 25) {
+ cur_cck_cca_thresh = 0xcd;
+ } else if ((dm_dig->rssi_val_min <= 25) &&
+ (dm_dig->rssi_val_min > 10)) {
+ cur_cck_cca_thresh = 0x83;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_cck_fail > 1000)
+ cur_cck_cca_thresh = 0x83;
+ else
+ cur_cck_cca_thresh = 0x40;
+ }
+
+ if (dm_dig->cur_cck_cca_thres != cur_cck_cca_thresh)
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, cur_cck_cca_thresh);
+
+ dm_dig->cur_cck_cca_thres = cur_cck_cca_thresh;
+ dm_dig->pre_cck_cca_thres = dm_dig->cur_cck_cca_thres;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+ "CCK cca thresh hold =%x\n", dm_dig->cur_cck_cca_thres);
+}
+
+static void rtl88e_dm_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 dig_min, dig_maxofmin;
+ bool bfirstconnect;
+ u8 dm_dig_max, dm_dig_min;
+ u8 current_igi = dm_dig->cur_igvalue;
+
+ if (rtlpriv->dm.dm_initialgain_enable == false)
+ return;
+ if (dm_dig->dig_enable_flag == false)
+ return;
+ if (mac->act_scanning == true)
+ return;
+
+ if (mac->link_state >= MAC80211_LINKED)
+ dm_dig->cursta_cstate = DIG_STA_CONNECT;
+ else
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+ dm_dig->cursta_cstate = DIG_STA_DISCONNECT;
+
+ dm_dig_max = DM_DIG_MAX;
+ dm_dig_min = DM_DIG_MIN;
+ dig_maxofmin = DM_DIG_MAX_AP;
+ dig_min = dm_dig->dig_min_0;
+ bfirstconnect = ((mac->link_state >= MAC80211_LINKED) ? true : false) &&
+ (dm_dig->media_connect_0 == false);
+
+ dm_dig->rssi_val_min =
+ rtl88e_dm_initial_gain_min_pwdb(hw);
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if ((dm_dig->rssi_val_min + 20) > dm_dig_max)
+ dm_dig->rx_gain_max = dm_dig_max;
+ else if ((dm_dig->rssi_val_min + 20) < dm_dig_min)
+ dm_dig->rx_gain_max = dm_dig_min;
+ else
+ dm_dig->rx_gain_max = dm_dig->rssi_val_min + 20;
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ dig_min = dm_dig->antdiv_rssi_max;
+ } else {
+ if (dm_dig->rssi_val_min < dm_dig_min)
+ dig_min = dm_dig_min;
+ else if (dm_dig->rssi_val_min < dig_maxofmin)
+ dig_min = dig_maxofmin;
+ else
+ dig_min = dm_dig->rssi_val_min;
+ }
+ } else {
+ dm_dig->rx_gain_max = dm_dig_max;
+ dig_min = dm_dig_min;
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
+ }
+
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000) {
+ dm_dig->large_fa_hit++;
+ if (dm_dig->forbidden_igi < current_igi) {
+ dm_dig->forbidden_igi = current_igi;
+ dm_dig->large_fa_hit = 1;
+ }
+
+ if (dm_dig->large_fa_hit >= 3) {
+ if ((dm_dig->forbidden_igi + 1) > dm_dig->rx_gain_max)
+ dm_dig->rx_gain_min = dm_dig->rx_gain_max;
+ else
+ dm_dig->rx_gain_min = dm_dig->forbidden_igi + 1;
+ dm_dig->recover_cnt = 3600;
+ }
+ } else {
+ if (dm_dig->recover_cnt != 0) {
+ dm_dig->recover_cnt--;
+ } else {
+ if (dm_dig->large_fa_hit == 0) {
+ if ((dm_dig->forbidden_igi - 1) < dig_min) {
+ dm_dig->forbidden_igi = dig_min;
+ dm_dig->rx_gain_min = dig_min;
+ } else {
+ dm_dig->forbidden_igi--;
+ dm_dig->rx_gain_min =
+ dm_dig->forbidden_igi + 1;
+ }
+ } else if (dm_dig->large_fa_hit == 3) {
+ dm_dig->large_fa_hit = 0;
+ }
+ }
+ }
+
+ if (dm_dig->cursta_cstate == DIG_STA_CONNECT) {
+ if (bfirstconnect) {
+ current_igi = dm_dig->rssi_val_min;
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH2)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all > DM_DIG_FA_TH1)
+ current_igi++;
+ else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+ current_igi--;
+ }
+ } else {
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ current_igi += 2;
+ else if (rtlpriv->falsealm_cnt.cnt_all > 8000)
+ current_igi++;
+ else if (rtlpriv->falsealm_cnt.cnt_all < 500)
+ current_igi--;
+ }
+
+ if (current_igi > DM_DIG_FA_UPPER)
+ current_igi = DM_DIG_FA_UPPER;
+ else if (current_igi < DM_DIG_FA_LOWER)
+ current_igi = DM_DIG_FA_LOWER;
+
+ if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+ current_igi = DM_DIG_FA_UPPER;
+
+ dm_dig->cur_igvalue = current_igi;
+ rtl88e_dm_write_dig(hw);
+ dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ?
+ true : false);
+ dm_dig->dig_min_0 = dig_min;
+
+ rtl88e_dm_cck_packet_detection_thresh(hw);
+}
+
+static void rtl88e_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+
+static void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undec_sm_pwdb;
+
+ if (!rtlpriv->dm.dynamic_txpower_enable)
+ return;
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ "Not connected\n");
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undec_sm_pwdb =
+ rtlpriv->dm.entry_min_undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "AP Client PWDB = 0x%lx\n",
+ undec_sm_pwdb);
+ } else {
+ undec_sm_pwdb =
+ rtlpriv->dm.undec_sm_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "STA Default Port PWDB = 0x%lx\n",
+ undec_sm_pwdb);
+ }
+ } else {
+ undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "AP Ext Port PWDB = 0x%lx\n", undec_sm_pwdb);
+ }
+
+ if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x0)\n");
+ } else if ((undec_sm_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+ (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_LEVEL1 (TxPwr = 0x10)\n");
+ } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "TXHIGHPWRLEVEL_NORMAL\n");
+ }
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "PHY_SetTxPowerLevel8192S() Channel = %d\n",
+ rtlphy->current_channel);
+ rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
+ }
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+void rtl88e_dm_write_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "cur_igvalue = 0x%x, "
+ "pre_igvalue = 0x%x, back_val = %d\n",
+ dm_dig->cur_igvalue, dm_dig->pre_igvalue,
+ dm_dig->back_val);
+
+ if (dm_dig->cur_igvalue > 0x3f)
+ dm_dig->cur_igvalue = 0x3f;
+ if (dm_dig->pre_igvalue != dm_dig->cur_igvalue) {
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
+ dm_dig->cur_igvalue);
+
+ dm_dig->pre_igvalue = dm_dig->cur_igvalue;
+ }
+}
+
+static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ static u64 last_txok;
+ static u64 last_rx;
+ long tmp_entry_max_pwdb = 0, tmp_entry_min_pwdb = 0xff;
+
+ if (rtlhal->oem_id == RT_CID_819x_HP) {
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rx;
+ last_txok = cur_txok_cnt;
+ last_rx = cur_rxok_cnt;
+
+ if (cur_rxok_cnt > (cur_txok_cnt * 6))
+ rtl_write_dword(rtlpriv, REG_ARFR0, 0x8f015);
+ else
+ rtl_write_dword(rtlpriv, REG_ARFR0, 0xff015);
+ }
+
+ /* AP & ADHOC & MESH */
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ if (drv_priv->rssi_stat.undec_sm_pwdb < tmp_entry_min_pwdb)
+ tmp_entry_min_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+ if (drv_priv->rssi_stat.undec_sm_pwdb > tmp_entry_max_pwdb)
+ tmp_entry_max_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+
+ /* If associated entry is found */
+ if (tmp_entry_max_pwdb != 0) {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = tmp_entry_max_pwdb;
+ RTPRINT(rtlpriv, FDM, DM_PWDB, "EntryMaxPWDB = 0x%lx(%ld)\n",
+ tmp_entry_max_pwdb, tmp_entry_max_pwdb);
+ } else {
+ rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
+ }
+ /* If associated entry is found */
+ if (tmp_entry_min_pwdb != 0xff) {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = tmp_entry_min_pwdb;
+ RTPRINT(rtlpriv, FDM, DM_PWDB, "EntryMinPWDB = 0x%lx(%ld)\n",
+ tmp_entry_min_pwdb, tmp_entry_min_pwdb);
+ } else {
+ rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
+ }
+ /* Indicate Rx signal strength to FW. */
+ if (!rtlpriv->dm.useramask)
+ rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb);
+}
+
+void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.current_turbo_edca = false;
+ rtlpriv->dm.is_any_nonbepkts = false;
+ rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+static void rtl88e_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ static u32 last_bt_edca_ul;
+ static u32 last_bt_edca_dl;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+ u32 edca_be_ul = 0x5ea42b;
+ u32 edca_be_dl = 0x5ea42b;
+ bool change_edca = false;
+
+ if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+ (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+ rtlpriv->dm.current_turbo_edca = false;
+ last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ change_edca = true;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+ change_edca = true;
+ }
+
+ if (mac->link_state != MAC80211_LINKED) {
+ rtlpriv->dm.current_turbo_edca = false;
+ return;
+ }
+
+ if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
+ if (!(edca_be_ul & 0xffff0000))
+ edca_be_ul |= 0x005e0000;
+
+ if (!(edca_be_dl & 0xffff0000))
+ edca_be_dl |= 0x005e0000;
+ }
+
+ if ((change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting))) {
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+ if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ } else {
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv,
+ REG_EDCA_BE_PARAM,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ } else {
+ if (rtlpriv->dm.current_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *)(&tmp));
+ rtlpriv->dm.current_turbo_edca = false;
+ }
+ }
+
+ rtlpriv->dm.is_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl88e_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
+ *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 thermalvalue = 0, delta, delta_lck, delta_iqk, off;
+ u8 th_avg_cnt = 0;
+ u32 thermalvalue_avg = 0;
+ long ele_d, temp_cck;
+ char ofdm_index[2], cck_index = 0, ofdm_old[2] = {0, 0}, cck_old = 0;
+ int i = 0;
+ bool is2t = false;
+
+ u8 ofdm_min_index = 6, rf = (is2t) ? 2 : 1;
+ u8 index_for_channel;
+ enum _dec_inc {dec, power_inc};
+
+ /* 0.1 the following TWO tables decide the final index of
+ * OFDM/CCK swing table
+ */
+ char del_tbl_idx[2][15] = {
+ {0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11},
+ {0, 0, -1, -2, -3, -4, -4, -4, -4, -5, -7, -8, -9, -9, -10}
+ };
+ u8 thermal_threshold[2][15] = {
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 27},
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 25, 25, 25}
+ };
+
+ /*Initilization (7 steps in total) */
+ rtlpriv->dm.txpower_trackinginit = true;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "rtl88e_dm_txpower_tracking_callback_thermalmeter\n");
+
+ thermalvalue = (u8) rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0xfc00);
+ if (!thermalvalue)
+ return;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x eeprom_thermalmeter 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter);
+
+ /*1. Query OFDM Default Setting: Path A*/
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL, MASKDWORD) & MASKOFDM_D;
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_old[0] = (u8) i;
+ rtldm->swing_idx_ofdm_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial pathA ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
+ ROFDM0_XATXIQIMBAL,
+ ele_d, ofdm_old[0]);
+ break;
+ }
+ }
+
+ if (is2t) {
+ ele_d = rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBAL,
+ MASKDWORD) & MASKOFDM_D;
+ for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
+ if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) {
+ ofdm_old[1] = (u8)i;
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
+ DBG_LOUD,
+ "Initial pathB ele_d reg0x%x = 0x%lx, ofdm_index = 0x%x\n",
+ ROFDM0_XBTXIQIMBAL, ele_d,
+ ofdm_old[1]);
+ break;
+ }
+ }
+ }
+ /*2.Query CCK default setting From 0xa24*/
+ temp_cck = rtl_get_bbreg(hw, RCCK0_TXFILTER2, MASKDWORD) & MASKCCK;
+ for (i = 0; i < CCK_TABLE_LENGTH; i++) {
+ if (rtlpriv->dm.cck_inch14) {
+ if (memcmp(&temp_cck, &cck_tbl_ch14[i][2], 4) == 0) {
+ cck_old = (u8)i;
+ rtldm->swing_idx_cck_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch 14 %d\n",
+ RCCK0_TXFILTER2, temp_cck, cck_old,
+ rtlpriv->dm.cck_inch14);
+ break;
+ }
+ } else {
+ if (memcmp(&temp_cck, &cck_tbl_ch1_13[i][2], 4) == 0) {
+ cck_old = (u8)i;
+ rtldm->swing_idx_cck_base = (u8)i;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Initial reg0x%x = 0x%lx, cck_index = 0x%x, ch14 %d\n",
+ RCCK0_TXFILTER2, temp_cck, cck_old,
+ rtlpriv->dm.cck_inch14);
+ break;
+ }
+ }
+ }
+
+ /*3 Initialize ThermalValues of RFCalibrateInfo*/
+ if (!rtldm->thermalvalue) {
+ rtlpriv->dm.thermalvalue = rtlefuse->eeprom_thermalmeter;
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ for (i = 0; i < rf; i++)
+ rtlpriv->dm.ofdm_index[i] = ofdm_old[i];
+ rtlpriv->dm.cck_index = cck_old;
+ }
+
+ /*4 Calculate average thermal meter*/
+ rtldm->thermalvalue_avg[rtldm->thermalvalue_avg_index] = thermalvalue;
+ rtldm->thermalvalue_avg_index++;
+ if (rtldm->thermalvalue_avg_index == AVG_THERMAL_NUM_88E)
+ rtldm->thermalvalue_avg_index = 0;
+
+ for (i = 0; i < AVG_THERMAL_NUM_88E; i++) {
+ if (rtldm->thermalvalue_avg[i]) {
+ thermalvalue_avg += rtldm->thermalvalue_avg[i];
+ th_avg_cnt++;
+ }
+ }
+
+ if (th_avg_cnt)
+ thermalvalue = (u8)(thermalvalue_avg / th_avg_cnt);
+
+ /* 5 Calculate delta, delta_LCK, delta_IQK.*/
+ if (rtlhal->reloadtxpowerindex) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ rtlhal->reloadtxpowerindex = false;
+ rtlpriv->dm.done_txpower = false;
+ } else if (rtlpriv->dm.done_txpower) {
+ delta = (thermalvalue > rtlpriv->dm.thermalvalue) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue) :
+ (rtlpriv->dm.thermalvalue - thermalvalue);
+ } else {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+ }
+ delta_lck = (thermalvalue > rtlpriv->dm.thermalvalue_lck) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_lck) :
+ (rtlpriv->dm.thermalvalue_lck - thermalvalue);
+ delta_iqk = (thermalvalue > rtlpriv->dm.thermalvalue_iqk) ?
+ (thermalvalue - rtlpriv->dm.thermalvalue_iqk) :
+ (rtlpriv->dm.thermalvalue_iqk - thermalvalue);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x delta 0x%x "
+ "delta_lck 0x%x delta_iqk 0x%x\n",
+ thermalvalue, rtlpriv->dm.thermalvalue,
+ rtlefuse->eeprom_thermalmeter, delta, delta_lck,
+ delta_iqk);
+ /* 6 If necessary, do LCK.*/
+ if (delta_lck >= 8) {
+ rtlpriv->dm.thermalvalue_lck = thermalvalue;
+ rtl88e_phy_lc_calibrate(hw);
+ }
+
+ /* 7 If necessary, move the index of swing table to adjust Tx power. */
+ if (delta > 0 && rtlpriv->dm.txpower_track_control) {
+ delta = (thermalvalue > rtlefuse->eeprom_thermalmeter) ?
+ (thermalvalue - rtlefuse->eeprom_thermalmeter) :
+ (rtlefuse->eeprom_thermalmeter - thermalvalue);
+
+ /* 7.1 Get the final CCK_index and OFDM_index for each
+ * swing table.
+ */
+ if (thermalvalue > rtlefuse->eeprom_thermalmeter) {
+ CAL_SWING_OFF(off, power_inc, IDX_MAP, delta);
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] = rtldm->ofdm_index[i] +
+ del_tbl_idx[power_inc][off];
+ cck_index = rtldm->cck_index +
+ del_tbl_idx[power_inc][off];
+ } else {
+ CAL_SWING_OFF(off, dec, IDX_MAP, delta);
+ for (i = 0; i < rf; i++)
+ ofdm_index[i] = rtldm->ofdm_index[i] +
+ del_tbl_idx[dec][off];
+ cck_index = rtldm->cck_index + del_tbl_idx[dec][off];
+ }
+
+ /* 7.2 Handle boundary conditions of index.*/
+ for (i = 0; i < rf; i++) {
+ if (ofdm_index[i] > OFDM_TABLE_SIZE-1)
+ ofdm_index[i] = OFDM_TABLE_SIZE-1;
+ else if (rtldm->ofdm_index[i] < ofdm_min_index)
+ ofdm_index[i] = ofdm_min_index;
+ }
+
+ if (cck_index > CCK_TABLE_SIZE - 1)
+ cck_index = CCK_TABLE_SIZE - 1;
+ else if (cck_index < 0)
+ cck_index = 0;
+
+ /*7.3Configure the Swing Table to adjust Tx Power.*/
+ if (rtlpriv->dm.txpower_track_control) {
+ rtldm->done_txpower = true;
+ rtldm->swing_idx_ofdm[RF90_PATH_A] =
+ (u8)ofdm_index[RF90_PATH_A];
+ if (is2t)
+ rtldm->swing_idx_ofdm[RF90_PATH_B] =
+ (u8)ofdm_index[RF90_PATH_B];
+ rtldm->swing_idx_cck = cck_index;
+ if (rtldm->swing_idx_ofdm_cur !=
+ rtldm->swing_idx_ofdm[0]) {
+ rtldm->swing_idx_ofdm_cur =
+ rtldm->swing_idx_ofdm[0];
+ rtldm->swing_flag_ofdm = true;
+ }
+
+ if (rtldm->swing_idx_cck != rtldm->swing_idx_cck) {
+ rtldm->swing_idx_cck_cur = rtldm->swing_idx_cck;
+ rtldm->swing_flag_cck = true;
+ }
+
+ rtl88e_chk_tx_track(hw, TXAGC, 0, 0);
+
+ if (is2t)
+ rtl88e_chk_tx_track(hw, BBSWING,
+ RF90_PATH_B,
+ index_for_channel);
+ }
+ }
+
+ if (delta_iqk >= 8) {
+ rtlpriv->dm.thermalvalue_iqk = thermalvalue;
+ rtl88e_phy_iq_calibrate(hw, false);
+ }
+
+ if (rtldm->txpower_track_control)
+ rtldm->thermalvalue = thermalvalue;
+ rtldm->txpowercount = 0;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, "end\n");
+}
+
+static void rtl88e_dm_init_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.txpower_tracking = true;
+ rtlpriv->dm.txpower_trackinginit = false;
+ rtlpriv->dm.txpowercount = 0;
+ rtlpriv->dm.txpower_track_control = true;
+
+ rtlpriv->dm.swing_idx_ofdm[RF90_PATH_A] = 12;
+ rtlpriv->dm.swing_idx_ofdm_cur = 12;
+ rtlpriv->dm.swing_flag_ofdm = false;
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ " rtlpriv->dm.txpower_tracking = %d\n",
+ rtlpriv->dm.txpower_tracking);
+}
+
+void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ static u8 tm_trigger;
+
+ if (!rtlpriv->dm.txpower_tracking)
+ return;
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER, BIT(17)|BIT(16),
+ 0x03);
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Trigger 88E Thermal Meter!!\n");
+ tm_trigger = 1;
+ return;
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Schedule TxPowerTracking !!\n");
+ rtl88e_dm_txpower_tracking_callback_thermalmeter(hw);
+ tm_trigger = 0;
+ }
+}
+
+void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+
+ p_ra->ratr_state = DM_RATR_STA_INIT;
+ p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.useramask = true;
+ else
+ rtlpriv->dm.useramask = false;
+}
+
+static void rtl88e_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+ struct ieee80211_sta *sta = NULL;
+ u32 low_rssi, hi_rssi;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver is going to unload\n");
+ return;
+ }
+
+ if (!rtlpriv->dm.useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "driver does not control rate adaptive mask\n");
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ switch (p_ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ hi_rssi = 50;
+ low_rssi = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ hi_rssi = 55;
+ low_rssi = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ hi_rssi = 50;
+ low_rssi = 25;
+ break;
+ default:
+ hi_rssi = 50;
+ low_rssi = 20;
+ break;
+ }
+
+ if (rtlpriv->dm.undec_sm_pwdb > (long)hi_rssi)
+ p_ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi)
+ p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ p_ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI = %ld\n",
+ rtlpriv->dm.undec_sm_pwdb);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI_LEVEL = %d\n", p_ra->ratr_state);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "PreState = %d, CurState = %d\n",
+ p_ra->pre_ratr_state, p_ra->ratr_state);
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ p_ra->ratr_state);
+ rcu_read_unlock();
+
+ p_ra->pre_ratr_state = p_ra->ratr_state;
+ }
+ }
+}
+
+static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
+
+ dm_pstable->pre_ccastate = CCA_MAX;
+ dm_pstable->cur_ccasate = CCA_MAX;
+ dm_pstable->pre_rfstate = RF_MAX;
+ dm_pstable->cur_rfstate = RF_MAX;
+ dm_pstable->rssi_val_min = 0;
+}
+
+static void rtl88e_dm_update_rx_idle_ant(struct ieee80211_hw *hw, u8 ant)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 def_ant, opt_ant;
+
+ if (fat_tbl->rx_idle_ant != ant) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "need to update rx idle ant\n");
+ if (ant == MAIN_ANT) {
+ def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ } else {
+ def_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ AUX_ANT_CG_TRX : AUX_ANT_CGCS_RX;
+ opt_ant = (fat_tbl->rx_idle_ant == CG_TRX_HW_ANTDIV) ?
+ MAIN_ANT_CG_TRX : MAIN_ANT_CGCS_RX;
+ }
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
+ BIT(4) | BIT(3), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), opt_ant);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_CTRL_11N, BIT(14) |
+ BIT(13) | BIT(12), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RESP_TX_11N, BIT(6) | BIT(7),
+ def_ant);
+ } else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) |
+ BIT(4) | BIT(3), def_ant);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), opt_ant);
+ }
+ }
+ fat_tbl->rx_idle_ant = ant;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RxIdleAnt %s\n",
+ ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+}
+
+static void rtl88e_dm_update_tx_ant(struct ieee80211_hw *hw,
+ u8 ant, u32 mac_id)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u8 target_ant;
+
+ if (ant == MAIN_ANT)
+ target_ant = MAIN_ANT_CG_TRX;
+ else
+ target_ant = AUX_ANT_CG_TRX;
+
+ fat_tbl->antsel_a[mac_id] = target_ant & BIT(0);
+ fat_tbl->antsel_b[mac_id] = (target_ant & BIT(1)) >> 1;
+ fat_tbl->antsel_c[mac_id] = (target_ant & BIT(2)) >> 2;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "txfrominfo target ant %s\n",
+ ((ant == MAIN_ANT) ? ("MAIN_ANT") : ("AUX_ANT")));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "antsel_tr_mux = 3'b%d%d%d\n",
+ fat_tbl->antsel_c[mac_id],
+ fat_tbl->antsel_b[mac_id], fat_tbl->antsel_a[mac_id]);
+}
+
+static void rtl88e_dm_rx_hw_antena_div_init(struct ieee80211_hw *hw)
+{
+ u32 value32;
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
+ (BIT(23) | BIT(25)));
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 1);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*CCK Setting*/
+ rtl_set_bbreg(hw, DM_REG_BB_PWR_SAV4_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1);
+ rtl88e_dm_update_rx_idle_ant(hw, MAIN_ANT);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKLWORD, 0x0201);
+}
+
+static void rtl88e_dm_trx_hw_antenna_div_init(struct ieee80211_hw *hw)
+{
+ u32 value32;
+
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 |
+ (BIT(23) | BIT(25)));
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*CCK Setting*/
+ rtl_set_bbreg(hw, DM_REG_BB_PWR_SAV4_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA2_11N, BIT(4), 1);
+ /*TX Setting*/
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 0);
+ rtl88e_dm_update_rx_idle_ant(hw, MAIN_ANT);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKLWORD, 0x0201);
+}
+
+static void rtl88e_dm_fast_training_init(struct ieee80211_hw *hw)
+{
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 ant_combo = 2;
+ u32 value32, i;
+
+ for (i = 0; i < 6; i++) {
+ fat_tbl->bssid[i] = 0;
+ fat_tbl->ant_sum[i] = 0;
+ fat_tbl->ant_cnt[i] = 0;
+ fat_tbl->ant_ave[i] = 0;
+ }
+ fat_tbl->train_idx = 0;
+ fat_tbl->fat_state = FAT_NORMAL_STATE;
+
+ /*MAC Setting*/
+ value32 = rtl_get_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANTSEL_PIN_11N, MASKDWORD, value32 | (BIT(23) |
+ BIT(25)));
+ value32 = rtl_get_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD);
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKDWORD, value32 | (BIT(16) |
+ BIT(17)));
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2, MASKLWORD, 0);
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1, MASKDWORD, 0);
+
+ /*Pin Setting*/
+ rtl_set_bbreg(hw, DM_REG_PIN_CTRL_11N, BIT(9) | BIT(8), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(10), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(22), 0);
+ rtl_set_bbreg(hw, DM_REG_LNA_SWITCH_11N, BIT(31), 1);
+
+ /*OFDM Setting*/
+ rtl_set_bbreg(hw, DM_REG_ANTDIV_PARA1_11N, MASKDWORD, 0x000000a0);
+ /*antenna mapping table*/
+ if (ant_combo == 2) {
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
+ } else if (ant_combo == 7) {
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE0, 1);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE1, 2);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE2, 2);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING1_11N, MASKBYTE3, 3);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE0, 4);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE1, 5);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE2, 6);
+ rtl_set_bbreg(hw, DM_REG_ANT_MAPPING2_11N, MASKBYTE3, 7);
+ }
+
+ /*TX Setting*/
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(5) | BIT(4) | BIT(3), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) | BIT(7) | BIT(6), 1);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(2) | BIT(1) | BIT(0),
+ (ant_combo - 1));
+
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+}
+
+static void rtl88e_dm_antenna_div_init(struct ieee80211_hw *hw)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl88e_dm_rx_hw_antena_div_init(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_trx_hw_antenna_div_init(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)
+ rtl88e_dm_fast_training_init(hw);
+}
+
+void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+ u8 *pdesc, u32 mac_id)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)) {
+ SET_TX_DESC_ANTSEL_A(pdesc, fat_tbl->antsel_a[mac_id]);
+ SET_TX_DESC_ANTSEL_B(pdesc, fat_tbl->antsel_b[mac_id]);
+ SET_TX_DESC_ANTSEL_C(pdesc, fat_tbl->antsel_c[mac_id]);
+ }
+}
+
+void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw,
+ u8 antsel_tr_mux, u32 mac_id, u32 rx_pwdb_all)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CG_TRX) {
+ fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->main_ant_cnt[mac_id]++;
+ } else {
+ fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->aux_ant_cnt[mac_id]++;
+ }
+ } else if (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) {
+ if (antsel_tr_mux == MAIN_ANT_CGCS_RX) {
+ fat_tbl->main_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->main_ant_cnt[mac_id]++;
+ } else {
+ fat_tbl->aux_ant_sum[mac_id] += rx_pwdb_all;
+ fat_tbl->aux_ant_cnt[mac_id]++;
+ }
+ }
+}
+
+static void rtl88e_dm_hw_ant_div(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_dig = &rtlpriv->dm_digtable;
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 i, min_rssi = 0xff, ant_div_max_rssi = 0, max_rssi = 0;
+ u32 local_min_rssi, local_max_rssi;
+ u32 main_rssi, aux_rssi;
+ u8 rx_idle_ant = 0, target_ant = 7;
+
+ i = 0;
+ main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
+ (fat_tbl->main_ant_sum[i] /
+ fat_tbl->main_ant_cnt[i]) : 0;
+ aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
+ (fat_tbl->aux_ant_sum[i] / fat_tbl->aux_ant_cnt[i]) : 0;
+ target_ant = (main_rssi == aux_rssi) ?
+ fat_tbl->rx_idle_ant : ((main_rssi >= aux_rssi) ?
+ MAIN_ANT : AUX_ANT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "main_ant_sum %d main_ant_cnt %d\n",
+ fat_tbl->main_ant_sum[i], fat_tbl->main_ant_cnt[i]);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "aux_ant_sum %d aux_ant_cnt %d\n",
+ fat_tbl->aux_ant_sum[i],
+ fat_tbl->aux_ant_cnt[i]);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "main_rssi %d aux_rssi%d\n", main_rssi, aux_rssi);
+ local_max_rssi = (main_rssi > aux_rssi) ? main_rssi : aux_rssi;
+ if ((local_max_rssi > ant_div_max_rssi) && (local_max_rssi < 40))
+ ant_div_max_rssi = local_max_rssi;
+ if (local_max_rssi > max_rssi)
+ max_rssi = local_max_rssi;
+
+ if ((fat_tbl->rx_idle_ant == MAIN_ANT) && (main_rssi == 0))
+ main_rssi = aux_rssi;
+ else if ((fat_tbl->rx_idle_ant == AUX_ANT) && (aux_rssi == 0))
+ aux_rssi = main_rssi;
+
+ local_min_rssi = (main_rssi > aux_rssi) ? aux_rssi : main_rssi;
+ if (local_min_rssi < min_rssi) {
+ min_rssi = local_min_rssi;
+ rx_idle_ant = target_ant;
+ }
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_update_tx_ant(hw, target_ant, i);
+
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) {
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv, &rtlpriv->entry_list, list) {
+ i++;
+ main_rssi = (fat_tbl->main_ant_cnt[i] != 0) ?
+ (fat_tbl->main_ant_sum[i] /
+ fat_tbl->main_ant_cnt[i]) : 0;
+ aux_rssi = (fat_tbl->aux_ant_cnt[i] != 0) ?
+ (fat_tbl->aux_ant_sum[i] /
+ fat_tbl->aux_ant_cnt[i]) : 0;
+ target_ant = (main_rssi == aux_rssi) ?
+ fat_tbl->rx_idle_ant : ((main_rssi >=
+ aux_rssi) ? MAIN_ANT : AUX_ANT);
+
+
+ local_max_rssi = max_t(u32, main_rssi, aux_rssi);
+ if ((local_max_rssi > ant_div_max_rssi) &&
+ (local_max_rssi < 40))
+ ant_div_max_rssi = local_max_rssi;
+ if (local_max_rssi > max_rssi)
+ max_rssi = local_max_rssi;
+
+ if ((fat_tbl->rx_idle_ant == MAIN_ANT) && !main_rssi)
+ main_rssi = aux_rssi;
+ else if ((fat_tbl->rx_idle_ant == AUX_ANT) &&
+ (aux_rssi == 0))
+ aux_rssi = main_rssi;
+
+ local_min_rssi = (main_rssi > aux_rssi) ?
+ aux_rssi : main_rssi;
+ if (local_min_rssi < min_rssi) {
+ min_rssi = local_min_rssi;
+ rx_idle_ant = target_ant;
+ }
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl88e_dm_update_tx_ant(hw, target_ant, i);
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+ }
+
+ for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
+ fat_tbl->main_ant_sum[i] = 0;
+ fat_tbl->aux_ant_sum[i] = 0;
+ fat_tbl->main_ant_cnt[i] = 0;
+ fat_tbl->aux_ant_cnt[i] = 0;
+ }
+
+ rtl88e_dm_update_rx_idle_ant(hw, rx_idle_ant);
+
+ dm_dig->antdiv_rssi_max = ant_div_max_rssi;
+ dm_dig->rssi_max = max_rssi;
+}
+
+static void rtl88e_set_next_mac_address_target(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_sta_info *drv_priv;
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 value32, i, j = 0;
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ for (i = 0; i < ASSOCIATE_ENTRY_NUM; i++) {
+ if ((fat_tbl->train_idx + 1) == ASSOCIATE_ENTRY_NUM)
+ fat_tbl->train_idx = 0;
+ else
+ fat_tbl->train_idx++;
+
+ if (fat_tbl->train_idx == 0) {
+ value32 = (mac->mac_addr[5] << 8) |
+ mac->mac_addr[4];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+ MASKLWORD, value32);
+
+ value32 = (mac->mac_addr[3] << 24) |
+ (mac->mac_addr[2] << 16) |
+ (mac->mac_addr[1] << 8) |
+ mac->mac_addr[0];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+ MASKDWORD, value32);
+ break;
+ }
+
+ if (rtlpriv->mac80211.opmode !=
+ NL80211_IFTYPE_STATION) {
+ spin_lock_bh(&rtlpriv->locks.entry_list_lock);
+ list_for_each_entry(drv_priv,
+ &rtlpriv->entry_list,
+ list) {
+ j++;
+ if (j != fat_tbl->train_idx)
+ continue;
+
+ value32 = (drv_priv->mac_addr[5] << 8) |
+ drv_priv->mac_addr[4];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_2,
+ MASKLWORD, value32);
+
+ value32 = (drv_priv->mac_addr[3]<<24) |
+ (drv_priv->mac_addr[2]<<16) |
+ (drv_priv->mac_addr[1]<<8) |
+ drv_priv->mac_addr[0];
+ rtl_set_bbreg(hw, DM_REG_ANT_TRAIN_1,
+ MASKDWORD, value32);
+ break;
+ }
+ spin_unlock_bh(&rtlpriv->locks.entry_list_lock);
+ /*find entry, break*/
+ if (j == fat_tbl->train_idx)
+ break;
+ }
+ }
+ }
+}
+
+static void rtl88e_dm_fast_ant_training(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+ u32 i, max_rssi = 0;
+ u8 target_ant = 2;
+ bool bpkt_filter_match = false;
+
+ if (fat_tbl->fat_state == FAT_TRAINING_STATE) {
+ for (i = 0; i < 7; i++) {
+ if (fat_tbl->ant_cnt[i] == 0) {
+ fat_tbl->ant_ave[i] = 0;
+ } else {
+ fat_tbl->ant_ave[i] = fat_tbl->ant_sum[i] /
+ fat_tbl->ant_cnt[i];
+ bpkt_filter_match = true;
+ }
+
+ if (fat_tbl->ant_ave[i] > max_rssi) {
+ max_rssi = fat_tbl->ant_ave[i];
+ target_ant = (u8) i;
+ }
+ }
+
+ if (bpkt_filter_match == false) {
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N,
+ BIT(16), 0);
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ } else {
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N,
+ BIT(16), 0);
+ rtl_set_bbreg(hw, DM_REG_RX_ANT_CTRL_11N, BIT(8) |
+ BIT(7) | BIT(6), target_ant);
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N, BIT(21), 1);
+
+ fat_tbl->antsel_a[fat_tbl->train_idx] =
+ target_ant & BIT(0);
+ fat_tbl->antsel_b[fat_tbl->train_idx] =
+ (target_ant & BIT(1)) >> 1;
+ fat_tbl->antsel_c[fat_tbl->train_idx] =
+ (target_ant & BIT(2)) >> 2;
+
+ if (target_ant == 0)
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ }
+
+ for (i = 0; i < 7; i++) {
+ fat_tbl->ant_sum[i] = 0;
+ fat_tbl->ant_cnt[i] = 0;
+ }
+
+ fat_tbl->fat_state = FAT_NORMAL_STATE;
+ return;
+ }
+
+ if (fat_tbl->fat_state == FAT_NORMAL_STATE) {
+ rtl88e_set_next_mac_address_target(hw);
+
+ fat_tbl->fat_state = FAT_TRAINING_STATE;
+ rtl_set_bbreg(hw, DM_REG_TXAGC_A_1_MCS32_11N, BIT(16), 1);
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+
+ mod_timer(&rtlpriv->works.fast_antenna_training_timer,
+ jiffies + MSECS(RTL_WATCH_DOG_TIME));
+ }
+}
+
+void rtl88e_dm_fast_antenna_training_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+
+ rtl88e_dm_fast_ant_training(hw);
+}
+
+static void rtl88e_dm_antenna_diversity(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct fast_ant_training *fat_tbl = &(rtldm->fat_table);
+
+ if (mac->link_state < MAC80211_LINKED) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "No Link\n");
+ if (fat_tbl->becomelinked == true) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "need to turn off HW AntDiv\n");
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 0);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA1_11N,
+ BIT(15), 0);
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
+ BIT(21), 0);
+ fat_tbl->becomelinked =
+ (mac->link_state == MAC80211_LINKED) ? true : false;
+ }
+ return;
+ } else {
+ if (fat_tbl->becomelinked == false) {
+ RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+ "Need to turn on HW AntDiv\n");
+ rtl_set_bbreg(hw, DM_REG_IGI_A_11N, BIT(7), 1);
+ rtl_set_bbreg(hw, DM_REG_CCK_ANTDIV_PARA1_11N,
+ BIT(15), 1);
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV)
+ rtl_set_bbreg(hw, DM_REG_TX_ANT_CTRL_11N,
+ BIT(21), 1);
+ fat_tbl->becomelinked =
+ (mac->link_state >= MAC80211_LINKED) ? true : false;
+ }
+ }
+
+ if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV))
+ rtl88e_dm_hw_ant_div(hw);
+ else if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV)
+ rtl88e_dm_fast_ant_training(hw);
+}
+
+void rtl88e_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtl88e_dm_diginit(hw);
+ rtl88e_dm_init_dynamic_txpower(hw);
+ rtl88e_dm_init_edca_turbo(hw);
+ rtl88e_dm_init_rate_adaptive_mask(hw);
+ rtl88e_dm_init_txpower_tracking(hw);
+ rtl92c_dm_init_dynamic_bb_powersaving(hw);
+ rtl88e_dm_antenna_div_init(hw);
+}
+
+void rtl88e_dm_watchdog(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool fw_current_inpsmode = false;
+ bool fw_ps_awake = true;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inpsmode));
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+ (u8 *)(&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
+ if ((ppsc->rfpwr_state == ERFON) &&
+ ((!fw_current_inpsmode) && fw_ps_awake) &&
+ (!ppsc->rfchange_inprogress)) {
+ rtl88e_dm_pwdb_monitor(hw);
+ rtl88e_dm_dig(hw);
+ rtl88e_dm_false_alarm_counter_statistics(hw);
+ rtl92c_dm_dynamic_txpower(hw);
+ rtl88e_dm_check_txpower_tracking(hw);
+ rtl88e_dm_refresh_rate_adaptive_mask(hw);
+ rtl88e_dm_check_edca_turbo(hw);
+ rtl88e_dm_antenna_diversity(hw);
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
new file mode 100644
index 000000000000..0e07f72ea158
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
@@ -0,0 +1,326 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL88E_DM_H__
+#define __RTL88E_DM_H__
+
+#define MAIN_ANT 0
+#define AUX_ANT 1
+#define MAIN_ANT_CG_TRX 1
+#define AUX_ANT_CG_TRX 0
+#define MAIN_ANT_CGCS_RX 0
+#define AUX_ANT_CGCS_RX 1
+
+/*RF REG LIST*/
+#define DM_REG_RF_MODE_11N 0x00
+#define DM_REG_RF_0B_11N 0x0B
+#define DM_REG_CHNBW_11N 0x18
+#define DM_REG_T_METER_11N 0x24
+#define DM_REG_RF_25_11N 0x25
+#define DM_REG_RF_26_11N 0x26
+#define DM_REG_RF_27_11N 0x27
+#define DM_REG_RF_2B_11N 0x2B
+#define DM_REG_RF_2C_11N 0x2C
+#define DM_REG_RXRF_A3_11N 0x3C
+#define DM_REG_T_METER_92D_11N 0x42
+#define DM_REG_T_METER_88E_11N 0x42
+
+/*BB REG LIST*/
+/*PAGE 8 */
+#define DM_REG_BB_CTRL_11N 0x800
+#define DM_REG_RF_PIN_11N 0x804
+#define DM_REG_PSD_CTRL_11N 0x808
+#define DM_REG_TX_ANT_CTRL_11N 0x80C
+#define DM_REG_BB_PWR_SAV5_11N 0x818
+#define DM_REG_CCK_RPT_FORMAT_11N 0x824
+#define DM_REG_RX_DEFAULT_A_11N 0x858
+#define DM_REG_RX_DEFAULT_B_11N 0x85A
+#define DM_REG_BB_PWR_SAV3_11N 0x85C
+#define DM_REG_ANTSEL_CTRL_11N 0x860
+#define DM_REG_RX_ANT_CTRL_11N 0x864
+#define DM_REG_PIN_CTRL_11N 0x870
+#define DM_REG_BB_PWR_SAV1_11N 0x874
+#define DM_REG_ANTSEL_PATH_11N 0x878
+#define DM_REG_BB_3WIRE_11N 0x88C
+#define DM_REG_SC_CNT_11N 0x8C4
+#define DM_REG_PSD_DATA_11N 0x8B4
+/*PAGE 9*/
+#define DM_REG_ANT_MAPPING1_11N 0x914
+#define DM_REG_ANT_MAPPING2_11N 0x918
+/*PAGE A*/
+#define DM_REG_CCK_ANTDIV_PARA1_11N 0xA00
+#define DM_REG_CCK_CCA_11N 0xA0A
+#define DM_REG_CCK_ANTDIV_PARA2_11N 0xA0C
+#define DM_REG_CCK_ANTDIV_PARA3_11N 0xA10
+#define DM_REG_CCK_ANTDIV_PARA4_11N 0xA14
+#define DM_REG_CCK_FILTER_PARA1_11N 0xA22
+#define DM_REG_CCK_FILTER_PARA2_11N 0xA23
+#define DM_REG_CCK_FILTER_PARA3_11N 0xA24
+#define DM_REG_CCK_FILTER_PARA4_11N 0xA25
+#define DM_REG_CCK_FILTER_PARA5_11N 0xA26
+#define DM_REG_CCK_FILTER_PARA6_11N 0xA27
+#define DM_REG_CCK_FILTER_PARA7_11N 0xA28
+#define DM_REG_CCK_FILTER_PARA8_11N 0xA29
+#define DM_REG_CCK_FA_RST_11N 0xA2C
+#define DM_REG_CCK_FA_MSB_11N 0xA58
+#define DM_REG_CCK_FA_LSB_11N 0xA5C
+#define DM_REG_CCK_CCA_CNT_11N 0xA60
+#define DM_REG_BB_PWR_SAV4_11N 0xA74
+/*PAGE B */
+#define DM_REG_LNA_SWITCH_11N 0xB2C
+#define DM_REG_PATH_SWITCH_11N 0xB30
+#define DM_REG_RSSI_CTRL_11N 0xB38
+#define DM_REG_CONFIG_ANTA_11N 0xB68
+#define DM_REG_RSSI_BT_11N 0xB9C
+/*PAGE C */
+#define DM_REG_OFDM_FA_HOLDC_11N 0xC00
+#define DM_REG_RX_PATH_11N 0xC04
+#define DM_REG_TRMUX_11N 0xC08
+#define DM_REG_OFDM_FA_RSTC_11N 0xC0C
+#define DM_REG_RXIQI_MATRIX_11N 0xC14
+#define DM_REG_TXIQK_MATRIX_LSB1_11N 0xC4C
+#define DM_REG_IGI_A_11N 0xC50
+#define DM_REG_ANTDIV_PARA2_11N 0xC54
+#define DM_REG_IGI_B_11N 0xC58
+#define DM_REG_ANTDIV_PARA3_11N 0xC5C
+#define DM_REG_BB_PWR_SAV2_11N 0xC70
+#define DM_REG_RX_OFF_11N 0xC7C
+#define DM_REG_TXIQK_MATRIXA_11N 0xC80
+#define DM_REG_TXIQK_MATRIXB_11N 0xC88
+#define DM_REG_TXIQK_MATRIXA_LSB2_11N 0xC94
+#define DM_REG_TXIQK_MATRIXB_LSB2_11N 0xC9C
+#define DM_REG_RXIQK_MATRIX_LSB_11N 0xCA0
+#define DM_REG_ANTDIV_PARA1_11N 0xCA4
+#define DM_REG_OFDM_FA_TYPE1_11N 0xCF0
+/*PAGE D */
+#define DM_REG_OFDM_FA_RSTD_11N 0xD00
+#define DM_REG_OFDM_FA_TYPE2_11N 0xDA0
+#define DM_REG_OFDM_FA_TYPE3_11N 0xDA4
+#define DM_REG_OFDM_FA_TYPE4_11N 0xDA8
+/*PAGE E */
+#define DM_REG_TXAGC_A_6_18_11N 0xE00
+#define DM_REG_TXAGC_A_24_54_11N 0xE04
+#define DM_REG_TXAGC_A_1_MCS32_11N 0xE08
+#define DM_REG_TXAGC_A_MCS0_3_11N 0xE10
+#define DM_REG_TXAGC_A_MCS4_7_11N 0xE14
+#define DM_REG_TXAGC_A_MCS8_11_11N 0xE18
+#define DM_REG_TXAGC_A_MCS12_15_11N 0xE1C
+#define DM_REG_FPGA0_IQK_11N 0xE28
+#define DM_REG_TXIQK_TONE_A_11N 0xE30
+#define DM_REG_RXIQK_TONE_A_11N 0xE34
+#define DM_REG_TXIQK_PI_A_11N 0xE38
+#define DM_REG_RXIQK_PI_A_11N 0xE3C
+#define DM_REG_TXIQK_11N 0xE40
+#define DM_REG_RXIQK_11N 0xE44
+#define DM_REG_IQK_AGC_PTS_11N 0xE48
+#define DM_REG_IQK_AGC_RSP_11N 0xE4C
+#define DM_REG_BLUETOOTH_11N 0xE6C
+#define DM_REG_RX_WAIT_CCA_11N 0xE70
+#define DM_REG_TX_CCK_RFON_11N 0xE74
+#define DM_REG_TX_CCK_BBON_11N 0xE78
+#define DM_REG_OFDM_RFON_11N 0xE7C
+#define DM_REG_OFDM_BBON_11N 0xE80
+#define DM_REG_TX2RX_11N 0xE84
+#define DM_REG_TX2TX_11N 0xE88
+#define DM_REG_RX_CCK_11N 0xE8C
+#define DM_REG_RX_OFDM_11N 0xED0
+#define DM_REG_RX_WAIT_RIFS_11N 0xED4
+#define DM_REG_RX2RX_11N 0xED8
+#define DM_REG_STANDBY_11N 0xEDC
+#define DM_REG_SLEEP_11N 0xEE0
+#define DM_REG_PMPD_ANAEN_11N 0xEEC
+
+
+/*MAC REG LIST*/
+#define DM_REG_BB_RST_11N 0x02
+#define DM_REG_ANTSEL_PIN_11N 0x4C
+#define DM_REG_EARLY_MODE_11N 0x4D0
+#define DM_REG_RSSI_MONITOR_11N 0x4FE
+#define DM_REG_EDCA_VO_11N 0x500
+#define DM_REG_EDCA_VI_11N 0x504
+#define DM_REG_EDCA_BE_11N 0x508
+#define DM_REG_EDCA_BK_11N 0x50C
+#define DM_REG_TXPAUSE_11N 0x522
+#define DM_REG_RESP_TX_11N 0x6D8
+#define DM_REG_ANT_TRAIN_1 0x7b0
+#define DM_REG_ANT_TRAIN_2 0x7b4
+
+/*DIG Related*/
+#define DM_BIT_IGI_11N 0x0000007F
+
+#define HAL_DM_DIG_DISABLE BIT(0)
+#define HAL_DM_HIPWR_DISABLE BIT(1)
+
+#define OFDM_TABLE_LENGTH 43
+#define CCK_TABLE_LENGTH 33
+
+#define OFDM_TABLE_SIZE 43
+#define CCK_TABLE_SIZE 33
+
+#define BW_AUTO_SWITCH_HIGH_LOW 25
+#define BW_AUTO_SWITCH_LOW_HIGH 30
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+
+#define DM_FALSEALARM_THRESH_LOW 400
+#define DM_FALSEALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1e
+
+#define DM_DIG_MAX_AP 0x32
+#define DM_DIG_MIN_AP 0x20
+
+#define DM_DIG_FA_UPPER 0x3e
+#define DM_DIG_FA_LOWER 0x1e
+#define DM_DIG_FA_TH0 0x200
+#define DM_DIG_FA_TH1 0x300
+#define DM_DIG_FA_TH2 0x400
+
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+#define RXPATHSELECTION_SS_TH_LOW 30
+#define RXPATHSELECTION_DIFF_TH 18
+
+#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
+
+#define CTS2SELF_THVAL 30
+#define REGC38_TH 20
+
+#define WAIOTTHVAL 25
+
+#define TXHIGHPWRLEVEL_NORMAL 0
+#define TXHIGHPWRLEVEL_LEVEL1 1
+#define TXHIGHPWRLEVEL_LEVEL2 2
+#define TXHIGHPWRLEVEL_BT1 3
+#define TXHIGHPWRLEVEL_BT2 4
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+#define TXPWRTRACK_MAX_IDX 6
+
+struct swat_t {
+ u8 failure_cnt;
+ u8 try_flag;
+ u8 stop_trying;
+ long pre_rssi;
+ long trying_threshold;
+ u8 cur_antenna;
+ u8 pre_antenna;
+};
+
+enum FAT_STATE {
+ FAT_NORMAL_STATE = 0,
+ FAT_TRAINING_STATE = 1,
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+ DIG_TYPE_THRESH_HIGH = 0,
+ DIG_TYPE_THRESH_LOW = 1,
+ DIG_TYPE_BACKOFF = 2,
+ DIG_TYPE_RX_GAIN_MIN = 3,
+ DIG_TYPE_RX_GAIN_MAX = 4,
+ DIG_TYPE_ENABLE = 5,
+ DIG_TYPE_DISABLE = 6,
+ DIG_OP_TYPE_MAX
+};
+
+enum tag_cck_packet_detection_threshold_type_definition {
+ CCK_PD_STAGE_LOWRSSI = 0,
+ CCK_PD_STAGE_HIGHRSSI = 1,
+ CCK_FA_STAGE_LOW = 2,
+ CCK_FA_STAGE_HIGH = 3,
+ CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_1r_cca_e {
+ CCA_1R = 0,
+ CCA_2R = 1,
+ CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+ RF_SAVE = 0,
+ RF_NORMAL = 1,
+ RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+ ANS_ANTENNA_B = 1,
+ ANS_ANTENNA_A = 2,
+ ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_MULTISTA_DISCONNECT = 3,
+ DIG_MULTISTA_CONNECT = 4,
+ DIG_CONNECT_MAX
+};
+
+enum pwr_track_control_method {
+ BBSWING,
+ TXAGC
+};
+
+void rtl88e_dm_set_tx_ant_by_tx_info(struct ieee80211_hw *hw,
+ u8 *pdesc, u32 mac_id);
+void rtl88e_dm_ant_sel_statistics(struct ieee80211_hw *hw, u8 antsel_tr_mux,
+ u32 mac_id, u32 rx_pwdb_all);
+void rtl88e_dm_fast_antenna_training_callback(unsigned long data);
+void rtl88e_dm_init(struct ieee80211_hw *hw);
+void rtl88e_dm_watchdog(struct ieee80211_hw *hw);
+void rtl88e_dm_write_dig(struct ieee80211_hw *hw);
+void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl88e_dm_check_txpower_tracking(struct ieee80211_hw *hw);
+void rtl88e_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl88e_dm_txpower_track_adjust(struct ieee80211_hw *hw,
+ u8 type, u8 *pdirection,
+ u32 *poutwrite_val);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
new file mode 100644
index 000000000000..57e4cc5833a9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.c
@@ -0,0 +1,830 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+
+#include <linux/kmemleak.h>
+
+static void _rtl88e_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp;
+
+ if (enable) {
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+ } else {
+ tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+ rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+ }
+}
+
+static void _rtl88e_fw_block_write(struct ieee80211_hw *hw,
+ const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 blk_sz = sizeof(u32);
+ u8 *buf_ptr = (u8 *)buffer;
+ u32 *pu4BytePtr = (u32 *)buffer;
+ u32 i, offset, blk_cnt, remain;
+
+ blk_cnt = size / blk_sz;
+ remain = size % blk_sz;
+
+ for (i = 0; i < blk_cnt; i++) {
+ offset = i * blk_sz;
+ rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+ *(pu4BytePtr + i));
+ }
+
+ if (remain) {
+ offset = blk_cnt * blk_sz;
+ buf_ptr += offset;
+ for (i = 0; i < remain; i++) {
+ rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
+ offset + i), *(buf_ptr + i));
+ }
+ }
+}
+
+static void _rtl88e_fw_page_write(struct ieee80211_hw *hw,
+ u32 page, const u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 value8;
+ u8 u8page = (u8) (page & 0x07);
+
+ value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+ rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+ _rtl88e_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl88e_fill_dummy(u8 *pfwbuf, u32 *pfwlen)
+{
+ u32 fwlen = *pfwlen;
+ u8 remain = (u8) (fwlen % 4);
+
+ remain = (remain == 0) ? 0 : (4 - remain);
+
+ while (remain > 0) {
+ pfwbuf[fwlen] = 0;
+ fwlen++;
+ remain--;
+ }
+
+ *pfwlen = fwlen;
+}
+
+static void _rtl88e_write_fw(struct ieee80211_hw *hw,
+ enum version_8188e version, u8 *buffer, u32 size)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 *buf_ptr = (u8 *)buffer;
+ u32 page_no, remain;
+ u32 page, offset;
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "FW size is %d bytes,\n", size);
+
+ _rtl88e_fill_dummy(buf_ptr, &size);
+
+ page_no = size / FW_8192C_PAGE_SIZE;
+ remain = size % FW_8192C_PAGE_SIZE;
+
+ if (page_no > 8) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Page numbers should not greater then 8\n");
+ }
+
+ for (page = 0; page < page_no; page++) {
+ offset = page * FW_8192C_PAGE_SIZE;
+ _rtl88e_fw_page_write(hw, page, (buf_ptr + offset),
+ FW_8192C_PAGE_SIZE);
+ }
+
+ if (remain) {
+ offset = page_no * FW_8192C_PAGE_SIZE;
+ page = page_no;
+ _rtl88e_fw_page_write(hw, page, (buf_ptr + offset), remain);
+ }
+}
+
+static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int err = -EIO;
+ u32 counter = 0;
+ u32 value32;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+ (!(value32 & FWDL_CHKSUM_RPT)));
+
+ if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+ value32);
+ goto exit;
+ }
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ value32 |= MCUFWDL_RDY;
+ value32 &= ~WINTINI_RDY;
+ rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+ rtl88e_firmware_selfreset(hw);
+ counter = 0;
+
+ do {
+ value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+ if (value32 & WINTINI_RDY) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+ "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
+ value32);
+ err = 0;
+ goto exit;
+ }
+
+ udelay(FW_8192C_POLLING_DELAY);
+
+ } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+
+exit:
+ return err;
+}
+
+int rtl88e_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl92c_firmware_header *pfwheader;
+ u8 *pfwdata;
+ u32 fwsize;
+ int err;
+ enum version_8188e version = rtlhal->version;
+
+ if (!rtlhal->pfirmware)
+ return 1;
+
+ pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
+ pfwdata = (u8 *)rtlhal->pfirmware;
+ fwsize = rtlhal->fwsize;
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "normal Firmware SIZE %d\n", fwsize);
+
+ if (IS_FW_HEADER_EXIST(pfwheader)) {
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "Firmware Version(%d), Signature(%#x), Size(%d)\n",
+ pfwheader->version, pfwheader->signature,
+ (int)sizeof(struct rtl92c_firmware_header));
+
+ pfwdata = pfwdata + sizeof(struct rtl92c_firmware_header);
+ fwsize = fwsize - sizeof(struct rtl92c_firmware_header);
+ }
+
+ if (rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0);
+ rtl88e_firmware_selfreset(hw);
+ }
+ _rtl88e_enable_fw_download(hw, true);
+ _rtl88e_write_fw(hw, version, pfwdata, fwsize);
+ _rtl88e_enable_fw_download(hw, false);
+
+ err = _rtl88e_fw_free_to_go(hw);
+
+ RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+ "Firmware is%s ready to run!\n", err ? " not" : "");
+ return 0;
+}
+
+static bool _rtl88e_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 val_hmetfr;
+
+ val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+ if (((val_hmetfr >> boxnum) & BIT(0)) == 0)
+ return true;
+ return false;
+}
+
+static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len,
+ u8 *cmd_b)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 boxnum;
+ u16 box_reg = 0, box_extreg = 0;
+ u8 u1b_tmp;
+ bool isfw_read = false;
+ u8 buf_index = 0;
+ bool write_sucess = false;
+ u8 wait_h2c_limit = 100;
+ u8 wait_writeh2c_limit = 100;
+ u8 boxc[4], boxext[2];
+ u32 h2c_waitcounter = 0;
+ unsigned long flag;
+ u8 idx;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+ while (true) {
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ if (rtlhal->h2c_setinprogress) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C set in progress! Wait to set..element_id(%d).\n",
+ element_id);
+
+ while (rtlhal->h2c_setinprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+ flag);
+ h2c_waitcounter++;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wait 100 us (%d times)...\n",
+ h2c_waitcounter);
+ udelay(100);
+
+ if (h2c_waitcounter > 1000)
+ return;
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+ flag);
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ } else {
+ rtlhal->h2c_setinprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+ break;
+ }
+ }
+
+ while (!write_sucess) {
+ wait_writeh2c_limit--;
+ if (wait_writeh2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Write H2C fail because no trigger for FW INT!\n");
+ break;
+ }
+
+ boxnum = rtlhal->last_hmeboxnum;
+ switch (boxnum) {
+ case 0:
+ box_reg = REG_HMEBOX_0;
+ box_extreg = REG_HMEBOX_EXT_0;
+ break;
+ case 1:
+ box_reg = REG_HMEBOX_1;
+ box_extreg = REG_HMEBOX_EXT_1;
+ break;
+ case 2:
+ box_reg = REG_HMEBOX_2;
+ box_extreg = REG_HMEBOX_EXT_2;
+ break;
+ case 3:
+ box_reg = REG_HMEBOX_3;
+ box_extreg = REG_HMEBOX_EXT_3;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
+ while (!isfw_read) {
+ wait_h2c_limit--;
+ if (wait_h2c_limit == 0) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating too long for FW read "
+ "clear HMEBox(%d)!\n", boxnum);
+ break;
+ }
+
+ udelay(10);
+
+ isfw_read = _rtl88e_check_fw_read_last_h2c(hw, boxnum);
+ u1b_tmp = rtl_read_byte(rtlpriv, 0x130);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Wating for FW read clear HMEBox(%d)!!! "
+ "0x130 = %2x\n", boxnum, u1b_tmp);
+ }
+
+ if (!isfw_read) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write H2C register BOX[%d] fail!!!!! "
+ "Fw do not read.\n", boxnum);
+ break;
+ }
+
+ memset(boxc, 0, sizeof(boxc));
+ memset(boxext, 0, sizeof(boxext));
+ boxc[0] = element_id;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "Write element_id box_reg(%4x) = %2x\n",
+ box_reg, element_id);
+
+ switch (cmd_len) {
+ case 1:
+ case 2:
+ case 3:
+ /*boxc[0] &= ~(BIT(7));*/
+ memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, cmd_len);
+
+ for (idx = 0; idx < 4; idx++)
+ rtl_write_byte(rtlpriv, box_reg+idx, boxc[idx]);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /*boxc[0] |= (BIT(7));*/
+ memcpy((u8 *)(boxext), cmd_b + buf_index+3, cmd_len-3);
+ memcpy((u8 *)(boxc) + 1, cmd_b + buf_index, 3);
+
+ for (idx = 0; idx < 2; idx++) {
+ rtl_write_byte(rtlpriv, box_extreg + idx,
+ boxext[idx]);
+ }
+
+ for (idx = 0; idx < 4; idx++) {
+ rtl_write_byte(rtlpriv, box_reg + idx,
+ boxc[idx]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ write_sucess = true;
+
+ rtlhal->last_hmeboxnum = boxnum + 1;
+ if (rtlhal->last_hmeboxnum == 4)
+ rtlhal->last_hmeboxnum = 0;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ "pHalData->last_hmeboxnum = %d\n",
+ rtlhal->last_hmeboxnum);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+ rtlhal->h2c_setinprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw,
+ u8 element_id, u32 cmd_len, u8 *cmd_b)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 tmp_cmdbuf[2];
+
+ if (rtlhal->fw_ready == false) {
+ RT_ASSERT(false, "fail H2C cmd - Fw download fail!!!\n");
+ return;
+ }
+
+ memset(tmp_cmdbuf, 0, 8);
+ memcpy(tmp_cmdbuf, cmd_b, cmd_len);
+ _rtl88e_fill_h2c_command(hw, element_id, cmd_len, (u8 *)&tmp_cmdbuf);
+
+ return;
+}
+
+void rtl88e_firmware_selfreset(struct ieee80211_hw *hw)
+{
+ u8 u1b_tmp;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp & (~BIT(2))));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1b_tmp | BIT(2)));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "8051Reset88E(): 8051 reset success.\n");
+}
+
+void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1_h2c_set_pwrmode[H2C_88E_PWEMODE_LENGTH] = { 0 };
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 power_state = 0;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+ SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, ((mode) ? 1 : 0));
+ SET_H2CCMD_PWRMODE_PARM_RLBM(u1_h2c_set_pwrmode, 0);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
+ SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(u1_h2c_set_pwrmode,
+ ppsc->reg_max_lps_awakeintvl);
+ SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(u1_h2c_set_pwrmode, 0);
+ if (mode == FW_PS_ACTIVE_MODE)
+ power_state |= FW_PWR_STATE_ACTIVE;
+ else
+ power_state |= FW_PWR_STATE_RF_OFF;
+ SET_H2CCMD_PWRMODE_PARM_PWR_STATE(u1_h2c_set_pwrmode, power_state);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl92c_set_fw_pwrmode(): u1_h2c_set_pwrmode\n",
+ u1_h2c_set_pwrmode, H2C_88E_PWEMODE_LENGTH);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_SETPWRMODE, H2C_88E_PWEMODE_LENGTH,
+ u1_h2c_set_pwrmode);
+}
+
+void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+ u8 u1_joinbssrpt_parm[1] = { 0 };
+
+ SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_JOINBSSRPT, 1, u1_joinbssrpt_parm);
+}
+
+void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw,
+ u8 ap_offload_enable)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 u1_apoffload_parm[H2C_88E_AP_OFFLOAD_LENGTH] = { 0 };
+
+ SET_H2CCMD_AP_OFFLOAD_ON(u1_apoffload_parm, ap_offload_enable);
+ SET_H2CCMD_AP_OFFLOAD_HIDDEN(u1_apoffload_parm, mac->hiddenssid);
+ SET_H2CCMD_AP_OFFLOAD_DENYANY(u1_apoffload_parm, 0);
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_AP_OFFLOAD, H2C_88E_AP_OFFLOAD_LENGTH,
+ u1_apoffload_parm);
+}
+
+static bool _rtl88e_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ struct sk_buff *pskb = NULL;
+ unsigned long flags;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+
+#define BEACON_PG 0 /* ->1 */
+#define PSPOLL_PG 2
+#define NULL_PG 3
+#define PROBERSP_PG 4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN 768
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+ /* page 0 beacon */
+ 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 1 beacon */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 2 ps-poll */
+ 0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 3 null */
+ 0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 4 probe_resp */
+ 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+ 0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+ 0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+ 0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+ 0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+ 0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+ 0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+ 0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+ 0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+ 0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+ 0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ /* page 5 probe_resp */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct sk_buff *skb = NULL;
+
+ u32 totalpacketlen;
+ u8 u1RsvdPageLoc[5] = { 0 };
+
+ u8 *beacon;
+ u8 *pspoll;
+ u8 *nullfunc;
+ u8 *probersp;
+ /*---------------------------------------------------------
+ * (1) beacon
+ *---------------------------------------------------------
+ */
+ beacon = &reserved_page_packet[BEACON_PG * 128];
+ SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+ /*-------------------------------------------------------
+ * (2) ps-poll
+ *--------------------------------------------------------
+ */
+ pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+ SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
+ SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
+ SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+ /*--------------------------------------------------------
+ * (3) null data
+ *---------------------------------------------------------
+ */
+ nullfunc = &reserved_page_packet[NULL_PG * 128];
+ SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+ SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+ /*---------------------------------------------------------
+ * (4) probe response
+ *----------------------------------------------------------
+ */
+ probersp = &reserved_page_packet[PROBERSP_PG * 128];
+ SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
+ SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
+
+ SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+
+ totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ &reserved_page_packet[0], totalpacketlen);
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "rtl88e_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+ u1RsvdPageLoc, 3);
+
+ skb = dev_alloc_skb(totalpacketlen);
+ if (!skb)
+ return;
+ kmemleak_not_leak(skb);
+ memcpy(skb_put(skb, totalpacketlen),
+ &reserved_page_packet, totalpacketlen);
+
+ if (_rtl88e_cmd_send_packet(hw, skb)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Set RSVD page location to Fw.\n");
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+ "H2C_RSVDPAGE:\n", u1RsvdPageLoc, 3);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_RSVDPAGE,
+ sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+ } else
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set RSVD page location to Fw FAIL!!!!!!.\n");
+}
+
+/*Shoud check FW support p2p or not.*/
+static void rtl88e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl88e_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low + (50 * 1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_P2P_PS_OFFLOAD, 1,
+ (u8 *)p2p_ps_offload);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
new file mode 100644
index 000000000000..854a9875cd5f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/fw.h
@@ -0,0 +1,301 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C__FW__H__
+#define __RTL92C__FW__H__
+
+#define FW_8192C_SIZE 0x8000
+#define FW_8192C_START_ADDRESS 0x1000
+#define FW_8192C_END_ADDRESS 0x5FFF
+#define FW_8192C_PAGE_SIZE 4096
+#define FW_8192C_POLLING_DELAY 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT 3000
+
+#define IS_FW_HEADER_EXIST(_pfwhdr) \
+ ((_pfwhdr->signature&0xFFFF) == 0x88E1)
+#define USE_OLD_WOWLAN_DEBUG_FW 0
+
+#define H2C_88E_RSVDPAGE_LOC_LEN 5
+#define H2C_88E_PWEMODE_LENGTH 5
+#define H2C_88E_JOINBSSRPT_LENGTH 1
+#define H2C_88E_AP_OFFLOAD_LENGTH 3
+#define H2C_88E_WOWLAN_LENGTH 3
+#define H2C_88E_KEEP_ALIVE_CTRL_LENGTH 3
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define H2C_88E_REMOTE_WAKE_CTRL_LEN 1
+#else
+#define H2C_88E_REMOTE_WAKE_CTRL_LEN 3
+#endif
+#define H2C_88E_AOAC_GLOBAL_INFO_LEN 2
+#define H2C_88E_AOAC_RSVDPAGE_LOC_LEN 7
+
+/* Fw PS state for RPWM.
+ * BIT[2:0] = HW state
+ * BIT[3] = Protocol PS state, 1: register active state, 0: register sleep state
+ * BIT[4] = sub-state
+ */
+#define FW_PS_GO_ON BIT(0)
+#define FW_PS_TX_NULL BIT(1)
+#define FW_PS_RF_ON BIT(2)
+#define FW_PS_REGISTER_ACTIVE BIT(3)
+
+#define FW_PS_DPS BIT(0)
+#define FW_PS_LCLK (FW_PS_DPS)
+#define FW_PS_RF_OFF BIT(1)
+#define FW_PS_ALL_ON BIT(2)
+#define FW_PS_ST_ACTIVE BIT(3)
+#define FW_PS_ISR_ENABLE BIT(4)
+#define FW_PS_IMR_ENABLE BIT(5)
+
+
+#define FW_PS_ACK BIT(6)
+#define FW_PS_TOGGLE BIT(7)
+
+ /* 88E RPWM value*/
+ /* BIT[0] = 1: 32k, 0: 40M*/
+#define FW_PS_CLOCK_OFF BIT(0) /* 32k*/
+#define FW_PS_CLOCK_ON 0 /*40M*/
+
+#define FW_PS_STATE_MASK (0x0F)
+#define FW_PS_STATE_HW_MASK (0x07)
+/*ISR_ENABLE, IMR_ENABLE, and PS mode should be inherited.*/
+#define FW_PS_STATE_INT_MASK (0x3F)
+
+#define FW_PS_STATE(x) (FW_PS_STATE_MASK & (x))
+#define FW_PS_STATE_HW(x) (FW_PS_STATE_HW_MASK & (x))
+#define FW_PS_STATE_INT(x) (FW_PS_STATE_INT_MASK & (x))
+#define FW_PS_ISR_VAL(x) ((x) & 0x70)
+#define FW_PS_IMR_MASK(x) ((x) & 0xDF)
+#define FW_PS_KEEP_IMR(x) ((x) & 0x20)
+
+#define FW_PS_STATE_S0 (FW_PS_DPS)
+#define FW_PS_STATE_S1 (FW_PS_LCLK)
+#define FW_PS_STATE_S2 (FW_PS_RF_OFF)
+#define FW_PS_STATE_S3 (FW_PS_ALL_ON)
+#define FW_PS_STATE_S4 ((FW_PS_ST_ACTIVE) | (FW_PS_ALL_ON))
+
+#define FW_PS_STATE_ALL_ON_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_ON_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_OFF_88E (FW_PS_CLOCK_ON)
+#define FW_PS_STATE_RF_OFF_LOW_PWR_88E (FW_PS_CLOCK_OFF)
+
+#define FW_PS_STATE_ALL_ON_92C (FW_PS_STATE_S4)
+#define FW_PS_STATE_RF_ON_92C (FW_PS_STATE_S3)
+#define FW_PS_STATE_RF_OFF_92C (FW_PS_STATE_S2)
+#define FW_PS_STATE_RF_OFF_LOW_PWR_92C (FW_PS_STATE_S1)
+
+/* For 88E H2C PwrMode Cmd ID 5.*/
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+#define FW_PS_IS_ACK(x) ((x) & FW_PS_ACK)
+#define FW_PS_IS_CLK_ON(x) ((x) & (FW_PS_RF_OFF | FW_PS_ALL_ON))
+#define FW_PS_IS_RF_ON(x) ((x) & (FW_PS_ALL_ON))
+#define FW_PS_IS_ACTIVE(x) ((x) & (FW_PS_ST_ACTIVE))
+#define FW_PS_IS_CPWM_INT(x) ((x) & 0x40)
+
+#define FW_CLR_PS_STATE(x) ((x) = ((x) & (0xF0)))
+
+#define IS_IN_LOW_POWER_STATE_88E(fwpsstate) \
+ (FW_PS_STATE(fwpsstate) == FW_PS_CLOCK_OFF)
+
+#define FW_PWR_STATE_ACTIVE ((FW_PS_RF_ON) | (FW_PS_REGISTER_ACTIVE))
+#define FW_PWR_STATE_RF_OFF 0
+
+struct rtl92c_firmware_header {
+ u16 signature;
+ u8 category;
+ u8 function;
+ u16 version;
+ u8 subversion;
+ u8 rsvd1;
+ u8 month;
+ u8 date;
+ u8 hour;
+ u8 minute;
+ u16 ramcodesize;
+ u16 rsvd2;
+ u32 svnindex;
+ u32 rsvd3;
+ u32 rsvd4;
+ u32 rsvd5;
+};
+
+enum rtl8192c_h2c_cmd {
+ H2C_88E_RSVDPAGE = 0,
+ H2C_88E_JOINBSSRPT = 1,
+ H2C_88E_SCAN = 2,
+ H2C_88E_KEEP_ALIVE_CTRL = 3,
+ H2C_88E_DISCONNECT_DECISION = 4,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+ H2C_88E_WO_WLAN = 5,
+#endif
+ H2C_88E_INIT_OFFLOAD = 6,
+#if (USE_OLD_WOWLAN_DEBUG_FW == 1)
+ H2C_88E_REMOTE_WAKE_CTRL = 7,
+#endif
+ H2C_88E_AP_OFFLOAD = 8,
+ H2C_88E_BCN_RSVDPAGE = 9,
+ H2C_88E_PROBERSP_RSVDPAGE = 10,
+
+ H2C_88E_SETPWRMODE = 0x20,
+ H2C_88E_PS_TUNING_PARA = 0x21,
+ H2C_88E_PS_TUNING_PARA2 = 0x22,
+ H2C_88E_PS_LPS_PARA = 0x23,
+ H2C_88E_P2P_PS_OFFLOAD = 024,
+
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+ H2C_88E_WO_WLAN = 0x80,
+ H2C_88E_REMOTE_WAKE_CTRL = 0x81,
+ H2C_88E_AOAC_GLOBAL_INFO = 0x82,
+ H2C_88E_AOAC_RSVDPAGE = 0x83,
+#endif
+ /* Not defined in new 88E H2C CMD Format */
+ H2C_88E_RA_MASK,
+ H2C_88E_SELECTIVE_SUSPEND_ROF_CMD,
+ H2C_88E_P2P_PS_MODE,
+ H2C_88E_PSD_RESULT,
+ /*Not defined CTW CMD for P2P yet*/
+ H2C_88E_P2P_PS_CTW_CMD,
+ MAX_88E_H2CCMD
+};
+
+#define pagenum_128(_len) (u32)(((_len)>>7) + ((_len)&0x7F ? 1 : 0))
+
+#define SET_88E_H2CCMD_WOWLAN_FUNC_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_PATTERN_MATCH_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_MAGIC_PKT_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_UNICAST_PKT_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_ALL_PKT_DROP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 4, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_ACTIVE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 5, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_REKEY_WAKE_UP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 6, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_DISCONNECT_WAKE_UP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 7, 1, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIONUM(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_WOWLAN_GPIO_DURATION(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_RLBM(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 4, 4, __value)
+#define SET_H2CCMD_PWRMODE_PARM_AWAKE_INTERVAL(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_ALL_QUEUE_UAPSD(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_H2CCMD_PWRMODE_PARM_PWR_STATE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+#define GET_88E_H2CCMD_PWRMODE_PARM_MODE(__cmd) \
+ LE_BITS_TO_1BYTE(__cmd, 0, 8)
+
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val) \
+ SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+/* AP_OFFLOAD */
+#define SET_H2CCMD_AP_OFFLOAD_ON(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_HIDDEN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_DENYANY(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_H2CCMD_AP_OFFLOAD_WAKEUP_EVT_RPT(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+
+/* Keep Alive Control*/
+#define SET_88E_H2CCMD_KEEP_ALIVE_ENABLE(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#define SET_88E_H2CCMD_KEEP_ALIVE_ACCPEPT_USER_DEFINED(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_KEEP_ALIVE_PERIOD(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/*REMOTE_WAKE_CTRL */
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 1, __value)
+#if (USE_OLD_WOWLAN_DEBUG_FW == 0)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_ARP_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 1, 1, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_NDP_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 2, 1, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GTK_OFFLOAD_EN(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 3, 1, __value)
+#else
+#define SET_88E_H2_REM_WAKE_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_REMOTE_WAKE_CTRL_GROUP_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#endif
+
+/* GTK_OFFLOAD */
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_PAIRWISE_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE(__cmd, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_GLOBAL_INFO_GROUP_ENC_ALG(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+
+/* AOAC_RSVDPAGE_LOC */
+#define SET_88E_H2CCMD_AOAC_RSVD_LOC_REM_WAKE_CTRL_INFO(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd), 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_ARP_RSP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+1, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_NEIGHBOR_ADV(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+2, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_RSP(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+3, 0, 8, __value)
+#define SET_88E_H2CCMD_AOAC_RSVDPAGE_LOC_GTK_INFO(__cmd, __value) \
+ SET_BITS_TO_LE_1BYTE((__cmd)+4, 0, 8, __value)
+
+int rtl88e_download_fw(struct ieee80211_hw *hw,
+ bool buse_wake_on_wlan_fw);
+void rtl88e_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+ u32 cmd_len, u8 *p_cmdbuffer);
+void rtl88e_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl88e_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl88e_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus);
+void rtl88e_set_fw_ap_off_load_cmd(struct ieee80211_hw *hw, u8 enable);
+void rtl88e_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl88e_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
new file mode 100644
index 000000000000..b68cae3024fc
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
@@ -0,0 +1,2530 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+#define LLT_CONFIG 5
+
+static void _rtl88ee_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+ u8 set_bits, u8 clear_bits)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpci->reg_bcn_ctrl_val |= set_bits;
+ rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl88ee_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl88ee_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 tmp1byte;
+
+ tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+ tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+ tmp1byte |= BIT(0);
+ rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl88ee_enable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl88ee_return_beacon_queue_skb(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ while (skb_queue_len(&ring->queue)) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ struct sk_buff *skb = __skb_dequeue(&ring->queue);
+
+ pci_unmap_single(rtlpci->pdev,
+ rtlpriv->cfg->ops->get_desc(
+ (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
+ skb->len, PCI_DMA_TODEVICE);
+ kfree_skb(skb);
+ ring->idx = (ring->idx + 1) % ring->entries;
+ }
+}
+
+static void _rtl88ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
+{
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
+ u8 rpwm_val, bool need_turn_off_ckk)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool support_remote_wake_up;
+ u32 count = 0, isr_regaddr, content;
+ bool schedule_timer = need_turn_off_ckk;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HAL_DEF_WOWLAN,
+ (u8 *)(&support_remote_wake_up));
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+
+ while (1) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (rtlhal->fw_clk_change_in_progress) {
+ while (rtlhal->fw_clk_change_in_progress) {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ udelay(100);
+ if (++count > 1000)
+ return;
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+ }
+
+ if (IS_IN_LOW_POWER_STATE_88E(rtlhal->fw_ps_state)) {
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ if (FW_PS_IS_ACK(rpwm_val)) {
+ isr_regaddr = REG_HISR;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ while (!(content & IMR_CPWM) && (count < 500)) {
+ udelay(50);
+ count++;
+ content = rtl_read_dword(rtlpriv, isr_regaddr);
+ }
+
+ if (content & IMR_CPWM) {
+ rtl_write_word(rtlpriv, isr_regaddr, 0x0100);
+ rtlhal->fw_ps_state = FW_PS_STATE_RF_ON_88E;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ "Receive CPWM INT!!! Set pHalData->FwPSState = %X\n",
+ rtlhal->fw_ps_state);
+ }
+ }
+
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ } else {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ }
+}
+
+static void _rtl88ee_set_fw_clock_off(struct ieee80211_hw *hw,
+ u8 rpwm_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ enum rf_pwrstate rtstate;
+ bool schedule_timer = false;
+ u8 queue;
+
+ if (!rtlhal->fw_ready)
+ return;
+ if (!rtlpriv->psc.fw_current_inpsmode)
+ return;
+ if (!rtlhal->allow_sw_to_change_hwclc)
+ return;
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE, (u8 *)(&rtstate));
+ if (rtstate == ERFOFF || rtlpriv->psc.inactive_pwrstate == ERFOFF)
+ return;
+
+ for (queue = 0; queue < RTL_PCI_MAX_TX_QUEUE_COUNT; queue++) {
+ ring = &rtlpci->tx_ring[queue];
+ if (skb_queue_len(&ring->queue)) {
+ schedule_timer = true;
+ break;
+ }
+ }
+
+ if (schedule_timer) {
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ return;
+ }
+
+ if (FW_PS_STATE(rtlhal->fw_ps_state) !=
+ FW_PS_STATE_RF_OFF_LOW_PWR_88E) {
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ if (!rtlhal->fw_clk_change_in_progress) {
+ rtlhal->fw_clk_change_in_progress = true;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_ps_state = FW_PS_STATE(rpwm_val);
+ rtl_write_word(rtlpriv, REG_HISR, 0x0100);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ spin_lock_bh(&rtlpriv->locks.fw_ps_lock);
+ rtlhal->fw_clk_change_in_progress = false;
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ } else {
+ spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+ mod_timer(&rtlpriv->works.fw_clockoff_timer,
+ jiffies + MSECS(10));
+ }
+ }
+}
+
+static void _rtl88ee_set_fw_ps_rf_on(struct ieee80211_hw *hw)
+{
+ u8 rpwm_val = 0;
+
+ rpwm_val |= (FW_PS_STATE_RF_OFF_88E | FW_PS_ACK);
+ _rtl88ee_set_fw_clock_on(hw, rpwm_val, true);
+}
+
+static void _rtl88ee_set_fw_ps_rf_off_low_power(struct ieee80211_hw *hw)
+{
+ u8 rpwm_val = 0;
+
+ rpwm_val |= FW_PS_STATE_RF_OFF_LOW_PWR_88E;
+ _rtl88ee_set_fw_clock_off(hw, rpwm_val);
+}
+
+void rtl88ee_fw_clk_off_timer_callback(unsigned long data)
+{
+ struct ieee80211_hw *hw = (struct ieee80211_hw *)data;
+
+ _rtl88ee_set_fw_ps_rf_off_low_power(hw);
+}
+
+static void _rtl88ee_fwlps_leave(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = false;
+ u8 rpwm_val = 0, fw_pwrmode = FW_PS_ACTIVE_MODE;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = (FW_PS_STATE_ALL_ON_88E|FW_PS_ACK);/* RF on */
+ _rtl88ee_set_fw_clock_on(hw, rpwm_val, false);
+ rtlhal->allow_sw_to_change_hwclc = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ } else {
+ rpwm_val = FW_PS_STATE_ALL_ON_88E; /* RF on */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+}
+
+static void _rtl88ee_fwlps_enter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool fw_current_inps = true;
+ u8 rpwm_val;
+
+ if (ppsc->low_power_enable) {
+ rpwm_val = FW_PS_STATE_RF_OFF_LOW_PWR_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+ rtlhal->allow_sw_to_change_hwclc = true;
+ _rtl88ee_set_fw_clock_off(hw, rpwm_val);
+ } else {
+ rpwm_val = FW_PS_STATE_RF_OFF_88E; /* RF off */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ }
+}
+
+void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR:
+ *((u32 *)(val)) = rtlpci->receive_config;
+ break;
+ case HW_VAR_RF_STATE:
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ case HW_VAR_FWLPS_RF_ON:{
+ enum rf_pwrstate rfstate;
+ u32 val_rcr;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RF_STATE,
+ (u8 *)(&rfstate));
+ if (rfstate == ERFOFF) {
+ *((bool *)(val)) = true;
+ } else {
+ val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+ val_rcr &= 0x00070000;
+ if (val_rcr)
+ *((bool *)(val)) = false;
+ else
+ *((bool *)(val)) = true;
+ }
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS:
+ *((bool *)(val)) = ppsc->fw_current_inpsmode;
+ break;
+ case HW_VAR_CORRECT_TSF:{
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ *((u64 *)(val)) = tsf;
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n", variable);
+ break;
+ }
+}
+
+void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 idx;
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_MACID + idx), val[idx]);
+ break;
+ case HW_VAR_BASIC_RATE:{
+ u16 rate_cfg = ((u16 *)val)[0];
+ u8 rate_index = 0;
+ rate_cfg = rate_cfg & 0x15f;
+ rate_cfg |= 0x01;
+ rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, REG_RRSR + 1, (rate_cfg >> 8) & 0xff);
+ while (rate_cfg > 0x1) {
+ rate_cfg = (rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, rate_index);
+ break; }
+ case HW_VAR_BSSID:
+ for (idx = 0; idx < ETH_ALEN; idx++)
+ rtl_write_byte(rtlpriv, (REG_BSSID + idx), val[idx]);
+ break;
+ case HW_VAR_SIFS:
+ rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+ rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+ rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+ if (!mac->ht_enable)
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM, 0x0e0e);
+ else
+ rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+ *((u16 *)val));
+ break;
+ case HW_VAR_SLOT_TIME:{
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+ rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ (u8 *)(&e_aci));
+ }
+ break; }
+ case HW_VAR_ACK_PREAMBLE:{
+ u8 reg_tmp;
+ u8 short_preamble = (bool) (*(u8 *)val);
+ reg_tmp = rtl_read_byte(rtlpriv, REG_TRXPTCL_CTL+2);
+ if (short_preamble) {
+ reg_tmp |= 0x02;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ } else {
+ reg_tmp |= 0xFD;
+ rtl_write_byte(rtlpriv, REG_TRXPTCL_CTL + 2, reg_tmp);
+ }
+ break; }
+ case HW_VAR_WPA_CONFIG:
+ rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *)val));
+ break;
+ case HW_VAR_AMPDU_MIN_SPACE:{
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *((u8 *)val);
+ if (min_spacing_to_set <= 7) {
+ sec_min_space = 0;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+
+ mac->min_space_cfg = ((mac->min_space_cfg &
+ 0xf8) | min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break; }
+ case HW_VAR_SHORTGI_DENSITY:{
+ u8 density_to_set;
+
+ density_to_set = *((u8 *)val);
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg);
+
+ rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ break; }
+ case HW_VAR_AMPDU_FACTOR:{
+ u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+ u8 factor;
+ u8 *reg = NULL;
+ u8 id = 0;
+
+ reg = regtoset_normal;
+
+ factor = *((u8 *)val);
+ if (factor <= 3) {
+ factor = (1 << (factor + 2));
+ if (factor > 0xf)
+ factor = 0xf;
+
+ for (id = 0; id < 4; id++) {
+ if ((reg[id] & 0xf0) > (factor << 4))
+ reg[id] = (reg[id] & 0x0f) |
+ (factor << 4);
+
+ if ((reg[id] & 0x0f) > factor)
+ reg[id] = (reg[id] & 0xf0) | (factor);
+
+ rtl_write_byte(rtlpriv, (REG_AGGLEN_LMT + id),
+ reg[id]);
+ }
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ "Set HW_VAR_AMPDU_FACTOR: %#x\n", factor);
+ }
+ break; }
+ case HW_VAR_AC_PARAM:{
+ u8 e_aci = *((u8 *)val);
+ rtl88e_dm_init_edca_turbo(hw);
+
+ if (rtlpci->acm_method != eAcmWay2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ACM_CTRL,
+ (u8 *)(&e_aci));
+ break; }
+ case HW_VAR_ACM_CTRL:{
+ u8 e_aci = *((u8 *)val);
+ union aci_aifsn *p_aci_aifsn =
+ (union aci_aifsn *)(&(mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+ acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= ACMHW_BEQEN;
+ break;
+ case AC2_VI:
+ acm_ctrl |= ACMHW_VIQEN;
+ break;
+ case AC3_VO:
+ acm_ctrl |= ACMHW_VOQEN;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+ acm);
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~ACMHW_VIQEN);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~ACMHW_BEQEN);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process\n");
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+ acm_ctrl);
+ rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+ break; }
+ case HW_VAR_RCR:
+ rtl_write_dword(rtlpriv, REG_RCR, ((u32 *)(val))[0]);
+ rtlpci->receive_config = ((u32 *)(val))[0];
+ break;
+ case HW_VAR_RETRY_LIMIT:{
+ u8 retry_limit = ((u8 *)(val))[0];
+
+ rtl_write_word(rtlpriv, REG_RL,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break; }
+ case HW_VAR_DUAL_TSF_RST:
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+ break;
+ case HW_VAR_EFUSE_BYTES:
+ rtlefuse->efuse_usedbytes = *((u16 *)val);
+ break;
+ case HW_VAR_EFUSE_USAGE:
+ rtlefuse->efuse_usedpercentage = *((u8 *)val);
+ break;
+ case HW_VAR_IO_CMD:
+ rtl88e_phy_set_io_cmd(hw, (*(enum io_type *)val));
+ break;
+ case HW_VAR_SET_RPWM:{
+ u8 rpwm_val;
+
+ rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+ udelay(1);
+
+ if (rpwm_val & BIT(7)) {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ (*(u8 *)val));
+ } else {
+ rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+ ((*(u8 *)val) | BIT(7)));
+ }
+ break; }
+ case HW_VAR_H2C_FW_PWRMODE:
+ rtl88e_set_fw_pwrmode_cmd(hw, (*(u8 *)val));
+ break;
+ case HW_VAR_FW_PSMODE_STATUS:
+ ppsc->fw_current_inpsmode = *((bool *)val);
+ break;
+ case HW_VAR_RESUME_CLK_ON:
+ _rtl88ee_set_fw_ps_rf_on(hw);
+ break;
+ case HW_VAR_FW_LPS_ACTION:{
+ bool enter_fwlps = *((bool *)val);
+
+ if (enter_fwlps)
+ _rtl88ee_fwlps_enter(hw);
+ else
+ _rtl88ee_fwlps_leave(hw);
+ break; }
+ case HW_VAR_H2C_FW_JOINBSSRPT:{
+ u8 mstatus = (*(u8 *)val);
+ u8 tmp, tmp_reg422, uval;
+ u8 count = 0, dlbcn_count = 0;
+ bool recover = false;
+
+ if (mstatus == RT_MEDIA_CONNECT) {
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+
+ tmp = rtl_read_byte(rtlpriv, REG_CR + 1);
+ rtl_write_byte(rtlpriv, REG_CR + 1, (tmp | BIT(0)));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+ tmp_reg422 = rtl_read_byte(rtlpriv,
+ REG_FWHW_TXQ_CTRL + 2);
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422 & (~BIT(6)));
+ if (tmp_reg422 & BIT(6))
+ recover = true;
+
+ do {
+ uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+ rtl_write_byte(rtlpriv, REG_TDECTRL+2,
+ (uval | BIT(0)));
+ _rtl88ee_return_beacon_queue_skb(hw);
+
+ rtl88e_set_fw_rsvdpagepkt(hw, 0);
+ uval = rtl_read_byte(rtlpriv, REG_TDECTRL+2);
+ count = 0;
+ while (!(uval & BIT(0)) && count < 20) {
+ count++;
+ udelay(10);
+ uval = rtl_read_byte(rtlpriv,
+ REG_TDECTRL+2);
+ }
+ dlbcn_count++;
+ } while (!(uval & BIT(0)) && dlbcn_count < 5);
+
+ if (uval & BIT(0))
+ rtl_write_byte(rtlpriv, REG_TDECTRL+2, BIT(0));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+ if (recover) {
+ rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+ tmp_reg422);
+ }
+ rtl_write_byte(rtlpriv, REG_CR + 1, (tmp & ~(BIT(0))));
+ }
+ rtl88e_set_fw_joinbss_report_cmd(hw, (*(u8 *)val));
+ break; }
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl88e_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
+ case HW_VAR_AID:{
+ u16 u2btmp;
+ u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+ u2btmp &= 0xC000;
+ rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
+ mac->assoc_id));
+ break; }
+ case HW_VAR_CORRECT_TSF:{
+ u8 btype_ibss = ((u8 *)(val))[0];
+
+ if (btype_ibss == true)
+ _rtl88ee_stop_tx_beacon(hw);
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+ rtl_write_dword(rtlpriv, REG_TSFTR,
+ (u32) (mac->tsf & 0xffffffff));
+ rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+ (u32) ((mac->tsf >> 32) & 0xffffffff));
+
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+ if (btype_ibss == true)
+ _rtl88ee_resume_tx_beacon(hw);
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not process %x\n", variable);
+ break;
+ }
+}
+
+static bool _rtl88ee_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool status = true;
+ long count = 0;
+ u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+ _LLT_OP(_LLT_WRITE_ACCESS);
+
+ rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+ do {
+ value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+ if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+ break;
+
+ if (count > POLLING_LLT_THRESHOLD) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to polling write LLT done at address %d!\n",
+ address);
+ status = false;
+ break;
+ }
+ } while (++count);
+
+ return status;
+}
+
+static bool _rtl88ee_llt_table_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ unsigned short i;
+ u8 txpktbuf_bndy;
+ u8 maxpage;
+ bool status;
+
+ maxpage = 0xAF;
+ txpktbuf_bndy = 0xAB;
+
+ rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x01);
+ rtl_write_dword(rtlpriv, REG_RQPN, 0x80730d29);
+
+
+ rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x25FF0000 | txpktbuf_bndy));
+ rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+ rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+ rtl_write_byte(rtlpriv, REG_PBP, 0x11);
+ rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+ for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+ status = _rtl88ee_llt_write(hw, i, i + 1);
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl88ee_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+ if (true != status)
+ return status;
+
+ for (i = txpktbuf_bndy; i < maxpage; i++) {
+ status = _rtl88ee_llt_write(hw, i, (i + 1));
+ if (true != status)
+ return status;
+ }
+
+ status = _rtl88ee_llt_write(hw, maxpage, txpktbuf_bndy);
+ if (true != status)
+ return status;
+
+ return true;
+}
+
+static void _rtl88ee_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpriv->rtlhal.up_first_time)
+ return;
+
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl88ee_sw_led_on(hw, pLed0);
+ else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+ rtl88ee_sw_led_on(hw, pLed0);
+ else
+ rtl88ee_sw_led_off(hw, pLed0);
+}
+
+static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 bytetmp;
+ u16 wordtmp;
+
+ /*Disable XTAL OUTPUT for power saving. YJ, add, 111206. */
+ bytetmp = rtl_read_byte(rtlpriv, REG_XCK_OUT_CTRL) & (~BIT(0));
+ rtl_write_byte(rtlpriv, REG_XCK_OUT_CTRL, bytetmp);
+ /*Auto Power Down to CHIP-off State*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) & (~BIT(7));
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, bytetmp);
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+ /* HW Power on sequence */
+ if (!rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK,
+ PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_ENABLE_FLOW)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "init MAC Fail as rtl88_hal_pwrseqcmdparsing\n");
+ return false;
+ }
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO) | BIT(4);
+ rtl_write_byte(rtlpriv, REG_APS_FSMCO, bytetmp);
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+2);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+2, bytetmp|BIT(2));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_WATCH_DOG+1);
+ rtl_write_byte(rtlpriv, REG_WATCH_DOG+1, bytetmp|BIT(7));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL_EXT+1);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL_EXT+1, bytetmp|BIT(1));
+
+ bytetmp = rtl_read_byte(rtlpriv, REG_TX_RPT_CTRL);
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL, bytetmp|BIT(1)|BIT(0));
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL+1, 2);
+ rtl_write_word(rtlpriv, REG_TX_RPT_TIME, 0xcdf0);
+
+ /*Add for wake up online*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_SYS_CLKR);
+
+ rtl_write_byte(rtlpriv, REG_SYS_CLKR, bytetmp|BIT(3));
+ bytetmp = rtl_read_byte(rtlpriv, REG_GPIO_MUXCFG+1);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG+1, (bytetmp & (~BIT(4))));
+ rtl_write_byte(rtlpriv, 0x367, 0x80);
+
+ rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+ rtl_write_byte(rtlpriv, REG_CR+1, 0x06);
+ rtl_write_byte(rtlpriv, REG_CR+2, 0x00);
+
+ if (!rtlhal->mac_func_enable) {
+ if (_rtl88ee_llt_table_init(hw) == false) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "LLT table init fail\n");
+ return false;
+ }
+ }
+
+
+ rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+ rtl_write_dword(rtlpriv, REG_HISRE, 0xffffffff);
+
+ wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL);
+ wordtmp &= 0xf;
+ wordtmp |= 0xE771;
+ rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+ rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xffff);
+ rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+ rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+ ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+ (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+ (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+ (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+ (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+ (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_HQ_DESA,
+ (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+ DMA_BIT_MASK(32));
+ rtl_write_dword(rtlpriv, REG_RX_DESA,
+ (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+ DMA_BIT_MASK(32));
+
+ /* if we want to support 64 bit DMA, we should set it here,
+ * but at the moment we do not support 64 bit DMA
+ */
+
+ rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+ rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0);/*Enable RX DMA */
+
+ if (rtlhal->earlymode_enable) {/*Early mode enable*/
+ bytetmp = rtl_read_byte(rtlpriv, REG_EARLY_MODE_CONTROL);
+ bytetmp |= 0x1f;
+ rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL, bytetmp);
+ rtl_write_byte(rtlpriv, REG_EARLY_MODE_CONTROL+3, 0x81);
+ }
+ _rtl88ee_gen_refresh_led_state(hw);
+ return true;
+}
+
+static void _rtl88ee_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 reg_prsr;
+
+ reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+ rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+}
+
+static void _rtl88ee_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 tmp1byte = 0;
+ u32 tmp4Byte = 0, count;
+
+ rtl_write_word(rtlpriv, 0x354, 0x8104);
+ rtl_write_word(rtlpriv, 0x358, 0x24);
+
+ rtl_write_word(rtlpriv, 0x350, 0x70c);
+ rtl_write_byte(rtlpriv, 0x352, 0x2);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+ if (0 == tmp1byte) {
+ tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
+ rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(31));
+ rtl_write_word(rtlpriv, 0x350, 0xf70c);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+ }
+
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+
+ rtl_write_word(rtlpriv, 0x350, 0x718);
+ rtl_write_byte(rtlpriv, 0x352, 0x2);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+ if (ppsc->support_backdoor || (0 == tmp1byte)) {
+ tmp4Byte = rtl_read_dword(rtlpriv, 0x34c);
+ rtl_write_dword(rtlpriv, 0x348, tmp4Byte|BIT(11)|BIT(12));
+ rtl_write_word(rtlpriv, 0x350, 0xf718);
+ rtl_write_byte(rtlpriv, 0x352, 0x1);
+ }
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count = 0;
+ while (tmp1byte && count < 20) {
+ udelay(10);
+ tmp1byte = rtl_read_byte(rtlpriv, 0x352);
+ count++;
+ }
+}
+
+void rtl88ee_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm);
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "not open hw encryption\n");
+ return;
+ }
+ sec_reg_value = SCR_TXENCENABLE | SCR_RXDECENABLE;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TXUSEDK;
+ sec_reg_value |= SCR_RXUSEDK;
+ }
+
+ sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+ rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "The SECR-value %x\n", sec_reg_value);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+}
+
+int rtl88ee_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus = true;
+ int err = 0;
+ u8 tmp_u1b, u1byte;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Rtl8188EE hw init\n");
+ rtlpriv->rtlhal.being_init_adapter = true;
+ rtlpriv->intf_ops->disable_aspm(hw);
+
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_SYS_CLKR+1);
+ u1byte = rtl_read_byte(rtlpriv, REG_CR);
+ if ((tmp_u1b & BIT(3)) && (u1byte != 0 && u1byte != 0xEA)) {
+ rtlhal->mac_func_enable = true;
+ } else {
+ rtlhal->mac_func_enable = false;
+ rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_88E;
+ }
+
+ rtstatus = _rtl88ee_init_mac(hw);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+ err = 1;
+ return err;
+ }
+
+ err = rtl88e_download_fw(hw, false);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Failed to download FW. Init HW without FW now..\n");
+ err = 1;
+ rtlhal->fw_ready = false;
+ return err;
+ } else {
+ rtlhal->fw_ready = true;
+ }
+ /*fw related variable initialize */
+ rtlhal->last_hmeboxnum = 0;
+ rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_88E;
+ rtlhal->fw_clk_change_in_progress = false;
+ rtlhal->allow_sw_to_change_hwclc = false;
+ ppsc->fw_current_inpsmode = false;
+
+ rtl88e_phy_mac_config(hw);
+ /* because last function modifies RCR, we update
+ * rcr var here, or TP will be unstable for receive_config
+ * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
+ * RCR_APP_ICV will cause mac80211 disassoc for cisco 1252
+ */
+ rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ rtl88e_phy_bb_config(hw);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+ rtl88e_phy_rf_config(hw);
+
+ rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+ RF_CHNLBW, RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[0] = rtlphy->rfreg_chnlval[0] & 0xfff00fff;
+
+ _rtl88ee_hw_configure(hw);
+ rtl_cam_reset_all_entry(hw);
+ rtl88ee_enable_hw_security_config(hw);
+
+ rtlhal->mac_func_enable = true;
+ ppsc->rfpwr_state = ERFON;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+ _rtl88ee_enable_aspm_back_door(hw);
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ if (ppsc->rfpwr_state == ERFON) {
+ if ((rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV) ||
+ ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) &&
+ (rtlhal->oem_id == RT_CID_819x_HP))) {
+ rtl88e_phy_set_rfpath_switch(hw, true);
+ rtlpriv->dm.fat_table.rx_idle_ant = MAIN_ANT;
+ } else {
+ rtl88e_phy_set_rfpath_switch(hw, false);
+ rtlpriv->dm.fat_table.rx_idle_ant = AUX_ANT;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "rx idle ant %s\n",
+ (rtlpriv->dm.fat_table.rx_idle_ant == MAIN_ANT) ?
+ ("MAIN_ANT") : ("AUX_ANT"));
+
+ if (rtlphy->iqk_initialized) {
+ rtl88e_phy_iq_calibrate(hw, true);
+ } else {
+ rtl88e_phy_iq_calibrate(hw, false);
+ rtlphy->iqk_initialized = true;
+ }
+ rtl88e_dm_check_txpower_tracking(hw);
+ rtl88e_phy_lc_calibrate(hw);
+ }
+
+ tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+ if (!(tmp_u1b & BIT(0))) {
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "PA BIAS path A\n");
+ }
+
+ if (!(tmp_u1b & BIT(4))) {
+ tmp_u1b = rtl_read_byte(rtlpriv, 0x16);
+ tmp_u1b &= 0x0F;
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+ udelay(10);
+ rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "under 1.5V\n");
+ }
+ rtl_write_byte(rtlpriv, REG_NAV_CTRL+2, ((30000+127)/128));
+ rtl88e_dm_init(hw);
+ rtlpriv->rtlhal.being_init_adapter = false;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "end of Rtl8188EE hw init %x\n",
+ err);
+ return 0;
+}
+
+static enum version_8188e _rtl88ee_read_chip_version(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ enum version_8188e version = VERSION_UNKNOWN;
+ u32 value32;
+
+ value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+ if (value32 & TRP_VAUX_EN) {
+ version = (enum version_8188e) VERSION_TEST_CHIP_88E;
+ } else {
+ version = NORMAL_CHIP;
+ version = version | ((value32 & TYPE_ID) ? RF_TYPE_2T2R : 0);
+ version = version | ((value32 & VENDOR_ID) ?
+ CHIP_VENDOR_UMC : 0);
+ }
+
+ rtlphy->rf_type = RF_1T1R;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Chip RF Type: %s\n", (rtlphy->rf_type == RF_2T2R) ?
+ "RF_2T2R" : "RF_1T1R");
+
+ return version;
+}
+
+static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+ bt_msr &= 0xfc;
+
+ if (type == NL80211_IFTYPE_UNSPECIFIED ||
+ type == NL80211_IFTYPE_STATION) {
+ _rtl88ee_stop_tx_beacon(hw);
+ _rtl88ee_enable_bcn_sub_func(hw);
+ } else if (type == NL80211_IFTYPE_ADHOC ||
+ type == NL80211_IFTYPE_AP ||
+ type == NL80211_IFTYPE_MESH_POINT) {
+ _rtl88ee_resume_tx_beacon(hw);
+ _rtl88ee_disable_bcn_sub_func(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+ type);
+ }
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= MSR_NOLINK;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to NO LINK!\n");
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Ad Hoc!\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= MSR_INFRA;
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to STA!\n");
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= MSR_AP;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to AP!\n");
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Mesh Point!\n");
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Network type %d not support!\n", type);
+ return 1;
+ }
+
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+ rtlpriv->cfg->ops->led_control(hw, ledaction);
+ if ((bt_msr & 0xfc) == MSR_AP)
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+ else
+ rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+ return 0;
+}
+
+void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 reg_rcr = rtlpci->receive_config;
+
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (check_bssid == true) {
+ reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+ (u8 *)(&reg_rcr));
+ _rtl88ee_set_bcn_ctrl_reg(hw, 0, BIT(4));
+ } else if (check_bssid == false) {
+ reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(4), 0);
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_RCR, (u8 *)(&reg_rcr));
+ }
+}
+
+int rtl88ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (_rtl88ee_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP &&
+ type != NL80211_IFTYPE_MESH_POINT)
+ rtl88ee_set_check_bssid(hw, true);
+ } else {
+ rtl88ee_set_check_bssid(hw, false);
+ }
+
+ return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl88e_dm_init_edca_turbo(hw);
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+ break;
+ case AC0_BE:
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+ break;
+ default:
+ RT_ASSERT(false, "invalid aci: %d !\n", aci);
+ break;
+ }
+}
+
+void rtl88ee_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+ rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+ rtlpci->irq_enabled = true;
+ /* there are some C2H CMDs have been sent before system interrupt
+ * is enabled, e.g., C2H, CPWM.
+ * So we need to clear all C2H events that FW has notified, otherwise
+ * FW won't schedule any commands anymore.
+ */
+ rtl_write_byte(rtlpriv, REG_C2HEVT_CLEAR, 0);
+ /*enable system interrupt*/
+ rtl_write_dword(rtlpriv, REG_HSIMR, rtlpci->sys_irq_mask & 0xFFFFFFFF);
+}
+
+void rtl88ee_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, REG_HIMR, IMR_DISABLED);
+ rtl_write_dword(rtlpriv, REG_HIMRE, IMR_DISABLED);
+ rtlpci->irq_enabled = false;
+ synchronize_irq(rtlpci->pdev->irq);
+}
+
+static void _rtl88ee_poweroff_adapter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 u1b_tmp;
+ u32 count = 0;
+ rtlhal->mac_func_enable = false;
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "POWER OFF adapter\n");
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_TX_RPT_CTRL);
+ rtl_write_byte(rtlpriv, REG_TX_RPT_CTRL, u1b_tmp & (~BIT(1)));
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ while (!(u1b_tmp & BIT(1)) && (count++ < 100)) {
+ udelay(10);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ count++;
+ }
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+1, 0xFF);
+
+ rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK,
+ Rtl8188E_NIC_LPS_ENTER_FLOW);
+
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+
+ if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+ rtl88e_firmware_selfreset(hw);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, (u1b_tmp & (~BIT(2))));
+ rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_32K_CTRL);
+ rtl_write_byte(rtlpriv, REG_32K_CTRL, (u1b_tmp & (~BIT(0))));
+
+ rtl88_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+ PWR_INTF_PCI_MSK, Rtl8188E_NIC_DISABLE_FLOW);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp & (~BIT(3))));
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL+1);
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL+1, (u1b_tmp | BIT(3)));
+
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0E);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, GPIO_IN);
+ rtl_write_byte(rtlpriv, GPIO_OUT, u1b_tmp);
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, 0x7F);
+
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL);
+ rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL, (u1b_tmp << 4) | u1b_tmp);
+ u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL+1);
+ rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL+1, u1b_tmp | 0x0F);
+
+ rtl_write_dword(rtlpriv, REG_GPIO_IO_SEL_2+2, 0x00080808);
+}
+
+void rtl88ee_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "RTL8188ee card disable\n");
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+
+ _rtl88ee_set_media_status(hw, opmode);
+
+ if (rtlpriv->rtlhal.driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ _rtl88ee_poweroff_adapter(hw);
+
+ /* after power off we should do iqk again */
+ rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl88ee_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ *p_intb = rtl_read_dword(rtlpriv, REG_HISRE) & rtlpci->irq_mask[1];
+ rtl_write_dword(rtlpriv, REG_HISRE, *p_intb);
+}
+
+void rtl88ee_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u16 bcn_interval, atim_window;
+
+ bcn_interval = mac->beacon_interval;
+ atim_window = 2; /*FIX MERGE */
+ rtl88ee_disable_interrupt(hw);
+ rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+ rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+ rtl_write_byte(rtlpriv, 0x606, 0x30);
+ rtlpci->reg_bcn_ctrl_val |= BIT(3);
+ rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+ /*rtl88ee_enable_interrupt(hw);*/
+}
+
+void rtl88ee_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+ "beacon_interval:%d\n", bcn_interval);
+ /*rtl88ee_disable_interrupt(hw);*/
+ rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+ /*rtl88ee_enable_interrupt(hw);*/
+}
+
+void rtl88ee_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+ rtl88ee_disable_interrupt(hw);
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+ rtl88ee_enable_interrupt(hw);
+}
+
+static inline u8 get_chnl_group(u8 chnl)
+{
+ u8 group;
+
+ group = chnl / 3;
+ if (chnl == 14)
+ group = 5;
+
+ return group;
+}
+
+static void set_diff0_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ pwr2g->bw40_diff[path][i] = 0;
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw20_diff[path][i] = 0x02;
+ } else {
+ pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ /*bit sign number to 8 bit sign number*/
+ if (pwr2g->bw20_diff[path][i] & BIT(3))
+ pwr2g->bw20_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->ofdm_diff[path][i] = 0x04;
+ } else {
+ pwr2g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ /*bit sign number to 8 bit sign number*/
+ if (pwr2g->ofdm_diff[path][i] & BIT(3))
+ pwr2g->ofdm_diff[path][i] |= 0xF0;
+ }
+ pwr2g->cck_diff[path][i] = 0;
+}
+
+static void set_diff0_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ pwr5g->bw40_diff[path][i] = 0;
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw20_diff[path][i] = 0;
+ } else {
+ pwr5g->bw20_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ /*bit sign number to 8 bit sign number*/
+ if (pwr5g->bw20_diff[path][i] & BIT(3))
+ pwr5g->bw20_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->ofdm_diff[path][i] = 0x04;
+ } else {
+ pwr5g->ofdm_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ /*bit sign number to 8 bit sign number*/
+ if (pwr5g->ofdm_diff[path][i] & BIT(3))
+ pwr5g->ofdm_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff1_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw40_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr2g->bw40_diff[path][i] & BIT(3))
+ pwr2g->bw40_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->bw20_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->bw20_diff[path][i] = (hwinfo[eadr]&0x0f);
+ if (pwr2g->bw20_diff[path][i] & BIT(3))
+ pwr2g->bw20_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff1_5g(struct txpower_info_5g *pwr5g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw40_diff[path][i] = 0xFE;
+ } else {
+ pwr5g->bw40_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr5g->bw40_diff[path][i] & BIT(3))
+ pwr5g->bw40_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->bw20_diff[path][i] = 0xFE;
+ } else {
+ pwr5g->bw20_diff[path][i] = (hwinfo[eadr] & 0x0f);
+ if (pwr5g->bw20_diff[path][i] & BIT(3))
+ pwr5g->bw20_diff[path][i] |= 0xF0;
+ }
+}
+
+static void set_diff2_2g(struct txpower_info_2g *pwr2g, u8 *hwinfo, u32 path,
+ u32 i, u32 eadr)
+{
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->ofdm_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->ofdm_diff[path][i] = (hwinfo[eadr]&0xf0)>>4;
+ if (pwr2g->ofdm_diff[path][i] & BIT(3))
+ pwr2g->ofdm_diff[path][i] |= 0xF0;
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr2g->cck_diff[path][i] = 0xFE;
+ } else {
+ pwr2g->cck_diff[path][i] = (hwinfo[eadr]&0x0f);
+ if (pwr2g->cck_diff[path][i] & BIT(3))
+ pwr2g->cck_diff[path][i] |= 0xF0;
+ }
+}
+
+static void _rtl8188e_read_power_value_fromprom(struct ieee80211_hw *hw,
+ struct txpower_info_2g *pwr2g,
+ struct txpower_info_5g *pwr5g,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 path, eadr = EEPROM_TX_PWR_INX, i;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "hal_ReadPowerValueFromPROM88E(): PROMContent[0x%x]= 0x%x\n",
+ (eadr+1), hwinfo[eadr+1]);
+ if (0xFF == hwinfo[eadr+1])
+ autoload_fail = true;
+
+ if (autoload_fail) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "auto load fail : Use Default value!\n");
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /* 2.4G default value */
+ for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
+ pwr2g->index_cck_base[path][i] = 0x2D;
+ pwr2g->index_bw40_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ pwr2g->bw20_diff[path][0] = 0x02;
+ pwr2g->ofdm_diff[path][0] = 0x04;
+ } else {
+ pwr2g->bw20_diff[path][i] = 0xFE;
+ pwr2g->bw40_diff[path][i] = 0xFE;
+ pwr2g->cck_diff[path][i] = 0xFE;
+ pwr2g->ofdm_diff[path][i] = 0xFE;
+ }
+ }
+ }
+ return;
+ }
+
+ for (path = 0; path < MAX_RF_PATH; path++) {
+ /*2.4G default value*/
+ for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
+ pwr2g->index_cck_base[path][i] = hwinfo[eadr++];
+ if (pwr2g->index_cck_base[path][i] == 0xFF)
+ pwr2g->index_cck_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_CHNL_GROUP_24G; i++) {
+ pwr2g->index_bw40_base[path][i] = hwinfo[eadr++];
+ if (pwr2g->index_bw40_base[path][i] == 0xFF)
+ pwr2g->index_bw40_base[path][i] = 0x2D;
+ }
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ set_diff0_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+ } else {
+ set_diff1_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+
+ set_diff2_2g(pwr2g, hwinfo, path, i, eadr);
+ eadr++;
+ }
+ }
+
+ /*5G default value*/
+ for (i = 0; i < MAX_CHNL_GROUP_5G; i++) {
+ pwr5g->index_bw40_base[path][i] = hwinfo[eadr++];
+ if (pwr5g->index_bw40_base[path][i] == 0xFF)
+ pwr5g->index_bw40_base[path][i] = 0xFE;
+ }
+
+ for (i = 0; i < MAX_TX_COUNT; i++) {
+ if (i == 0) {
+ set_diff0_5g(pwr5g, hwinfo, path, i, eadr);
+ eadr++;
+ } else {
+ set_diff1_5g(pwr5g, hwinfo, path, i, eadr);
+ eadr++;
+ }
+ }
+
+ if (hwinfo[eadr] == 0xFF) {
+ pwr5g->ofdm_diff[path][1] = 0xFE;
+ pwr5g->ofdm_diff[path][2] = 0xFE;
+ } else {
+ pwr5g->ofdm_diff[path][1] = (hwinfo[eadr] & 0xf0) >> 4;
+ pwr5g->ofdm_diff[path][2] = (hwinfo[eadr] & 0x0f);
+ }
+ eadr++;
+
+ if (hwinfo[eadr] == 0xFF)
+ pwr5g->ofdm_diff[path][3] = 0xFE;
+ else
+ pwr5g->ofdm_diff[path][3] = (hwinfo[eadr]&0x0f);
+ eadr++;
+
+ for (i = 1; i < MAX_TX_COUNT; i++) {
+ if (pwr5g->ofdm_diff[path][i] == 0xFF)
+ pwr5g->ofdm_diff[path][i] = 0xFE;
+ else if (pwr5g->ofdm_diff[path][i] & BIT(3))
+ pwr5g->ofdm_diff[path][i] |= 0xF0;
+ }
+ }
+}
+
+static void _rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail,
+ u8 *hwinfo)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct txpower_info_2g pwrinfo24g;
+ struct txpower_info_5g pwrinfo5g;
+ u8 rf_path, index;
+ u8 i;
+ int jj = EEPROM_RF_BOARD_OPTION_88E;
+ int kk = EEPROM_THERMAL_METER_88E;
+
+ _rtl8188e_read_power_value_fromprom(hw, &pwrinfo24g, &pwrinfo5g,
+ autoload_fail, hwinfo);
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 14; i++) {
+ index = get_chnl_group(i+1);
+
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ pwrinfo24g.index_cck_base[rf_path][index];
+ if (i == 13)
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ pwrinfo24g.index_bw40_base[rf_path][4];
+ else
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ pwrinfo24g.index_bw40_base[rf_path][index];
+ rtlefuse->txpwr_ht20diff[rf_path][i] =
+ pwrinfo24g.bw20_diff[rf_path][0];
+ rtlefuse->txpwr_legacyhtdiff[rf_path][i] =
+ pwrinfo24g.ofdm_diff[rf_path][0];
+ }
+
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "RF(%d)-Ch(%d) [CCK / HT40_1S ] = "
+ "[0x%x / 0x%x ]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i]);
+ }
+ }
+
+ if (!autoload_fail)
+ rtlefuse->eeprom_thermalmeter = hwinfo[kk];
+ else
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+
+ if (rtlefuse->eeprom_thermalmeter == 0xff || autoload_fail) {
+ rtlefuse->apk_thermalmeterignore = true;
+ rtlefuse->eeprom_thermalmeter = EEPROM_DEFAULT_THERMALMETER;
+ }
+
+ rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+
+ if (!autoload_fail) {
+ rtlefuse->eeprom_regulatory = hwinfo[jj] & 0x07;/*bit0~2*/
+ if (hwinfo[jj] == 0xFF)
+ rtlefuse->eeprom_regulatory = 0;
+ } else {
+ rtlefuse->eeprom_regulatory = 0;
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
+ "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+}
+
+static void _rtl88ee_read_adapter_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ u16 i, usvalue;
+ u8 hwinfo[HWSET_MAX_SIZE];
+ u16 eeprom_id;
+ int jj = EEPROM_RF_BOARD_OPTION_88E;
+ int kk = EEPROM_RF_FEATURE_OPTION_88E;
+
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE);
+ } else if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "RTL819X Not boot from eeprom, check it !!");
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8188E_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ }
+
+ if (rtlefuse->autoload_failflag == true)
+ return;
+ /*VID DID SVID SDID*/
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROMId = 0x%4x\n", eeprom_id);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+ /*customer ID*/
+ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+ if (rtlefuse->eeprom_oemid == 0xFF)
+ rtlefuse->eeprom_oemid = 0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+ /*EEPROM version*/
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+ /*mac address*/
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "dev_addr: %pM\n", rtlefuse->dev_addr);
+ /*channel plan */
+ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ /* set channel paln to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+ /*tx power*/
+ _rtl88ee_read_txpower_info_from_hwpg(hw, rtlefuse->autoload_failflag,
+ hwinfo);
+ rtlefuse->txpwr_fromeprom = true;
+
+ rtl8188ee_read_bt_coexist_info_from_hwpg(hw,
+ rtlefuse->autoload_failflag,
+ hwinfo);
+ /*board type*/
+ rtlefuse->board_type = (((*(u8 *)&hwinfo[jj]) & 0xE0) >> 5);
+ /*Wake on wlan*/
+ rtlefuse->wowlan_enable = ((hwinfo[kk] & 0x40) >> 6);
+ /*parse xtal*/
+ rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_88E];
+ if (hwinfo[EEPROM_XTAL_88E])
+ rtlefuse->crystalcap = 0x20;
+ /*antenna diversity*/
+ rtlefuse->antenna_div_cfg = (hwinfo[jj] & 0x18) >> 3;
+ if (hwinfo[jj] == 0xFF)
+ rtlefuse->antenna_div_cfg = 0;
+ if (rppriv->bt_coexist.eeprom_bt_coexist != 0 &&
+ rppriv->bt_coexist.eeprom_bt_ant_num == ANT_X1)
+ rtlefuse->antenna_div_cfg = 0;
+
+ rtlefuse->antenna_div_type = hwinfo[EEPROM_RF_ANTENNA_OPT_88E];
+ if (rtlefuse->antenna_div_type == 0xFF)
+ rtlefuse->antenna_div_type = 0x01;
+ if (rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV ||
+ rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtlefuse->antenna_div_cfg = 1;
+
+ if (rtlhal->oem_id == RT_CID_DEFAULT) {
+ switch (rtlefuse->eeprom_oemid) {
+ case EEPROM_CID_DEFAULT:
+ if (rtlefuse->eeprom_did == 0x8179) {
+ if (rtlefuse->eeprom_svid == 0x1025) {
+ rtlhal->oem_id = RT_CID_819x_Acer;
+ } else if ((rtlefuse->eeprom_svid == 0x10EC &&
+ rtlefuse->eeprom_smid == 0x0179) ||
+ (rtlefuse->eeprom_svid == 0x17AA &&
+ rtlefuse->eeprom_smid == 0x0179)) {
+ rtlhal->oem_id = RT_CID_819x_Lenovo;
+ } else if (rtlefuse->eeprom_svid == 0x103c &&
+ rtlefuse->eeprom_smid == 0x197d) {
+ rtlhal->oem_id = RT_CID_819x_HP;
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ } else {
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ }
+ break;
+ case EEPROM_CID_TOSHIBA:
+ rtlhal->oem_id = RT_CID_TOSHIBA;
+ break;
+ case EEPROM_CID_QMI:
+ rtlhal->oem_id = RT_CID_819x_QMI;
+ break;
+ case EEPROM_CID_WHQL:
+ default:
+ rtlhal->oem_id = RT_CID_DEFAULT;
+ break;
+ }
+ }
+}
+
+static void _rtl88ee_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ pcipriv->ledctl.led_opendrain = true;
+
+ switch (rtlhal->oem_id) {
+ case RT_CID_819x_HP:
+ pcipriv->ledctl.led_opendrain = true;
+ break;
+ case RT_CID_819x_Lenovo:
+ case RT_CID_DEFAULT:
+ case RT_CID_TOSHIBA:
+ case RT_CID_CCX:
+ case RT_CID_819x_Acer:
+ case RT_CID_WHQL:
+ default:
+ break;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_u1b;
+
+ rtlhal->version = _rtl88ee_read_chip_version(hw);
+ if (get_rf_type(rtlphy) == RF_1T1R) {
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] = true;
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+ rtlhal->version);
+ tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+ rtlefuse->autoload_failflag = false;
+ _rtl88ee_read_adapter_info(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+ }
+ _rtl88ee_hal_customized_behavior(hw);
+}
+
+static void rtl88ee_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
+ u8 ratr_index = 0;
+ u8 nmode = mac->ht_enable;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate;
+ u32 tmp_ratr_value;
+ u8 ctx40 = mac->bw_40;
+ u16 cap = sta->ht_cap.cap;
+ u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+ u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ if (ratr_value & 0x0000000c)
+ ratr_value &= 0x0000000d;
+ else
+ ratr_value &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ nmode = 1;
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
+
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+
+ break;
+ }
+
+ if ((rppriv->bt_coexist.bt_coexistence) &&
+ (rppriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
+ (rppriv->bt_coexist.bt_cur_state) &&
+ (rppriv->bt_coexist.bt_ant_isolation) &&
+ ((rppriv->bt_coexist.bt_service == BT_SCO) ||
+ (rppriv->bt_coexist.bt_service == BT_BUSY)))
+ ratr_value &= 0x0fffcfc0;
+ else
+ ratr_value &= 0x0FFFFFFF;
+
+ if (nmode && ((ctx40 && short40) ||
+ (!ctx40 && short20))) {
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ }
+
+ rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static void rtl88ee_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index;
+ u16 cap = sta->ht_cap.cap;
+ u8 ctx40 = (cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+ u8 short40 = (cap & IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
+ u8 short20 = (cap & IEEE80211_HT_CAP_SGI_20) ? 1 : 0;
+ enum wireless_mode wirelessmode = 0;
+ bool shortgi = false;
+ u8 rate_mask[5];
+ u8 macid = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ ctx40 = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (ctx40) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff015;
+ } else {
+ if (rssi == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (ctx40) {
+ if (rssi == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff015;
+ } else {
+ if (rssi == 1)
+ ratr_bitmap &= 0x0f8f0000;
+ else if (rssi == 2)
+ ratr_bitmap &= 0x0f8ff000;
+ else
+ ratr_bitmap &= 0x0f8ff005;
+ }
+ }
+ }
+
+ if ((ctx40 && short40) || (!ctx40 && short20)) {
+ if (macid == 0)
+ shortgi = true;
+ else if (macid == 1)
+ shortgi = false;
+ }
+ break;
+ default:
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f0ff0ff;
+ break;
+ }
+ sta_entry->ratr_index = ratr_index;
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "ratr_bitmap :%x\n", ratr_bitmap);
+ *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28);
+ rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ "Rate_index:%x, ratr_val:%x, %x:%x:%x:%x:%x\n",
+ ratr_index, ratr_bitmap, rate_mask[0], rate_mask[1],
+ rate_mask[2], rate_mask[3], rate_mask[4]);
+ rtl88e_fill_h2c_cmd(hw, H2C_88E_RA_MASK, 5, rate_mask);
+ _rtl88ee_set_bcn_ctrl_reg(hw, BIT(3), 0);
+}
+
+void rtl88ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl88ee_update_hal_rate_mask(hw, sta, rssi);
+ else
+ rtl88ee_update_hal_rate_table(hw, sta);
+}
+
+void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *)&mac->slot_time);
+ if (!mac->ht_enable)
+ sifs_timer = 0x0a0a;
+ else
+ sifs_timer = 0x0e0e;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl88ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum rf_pwrstate state_toset;
+ u32 u4tmp;
+ bool actuallyset = false;
+
+ if (rtlpriv->rtlhal.being_init_adapter)
+ return false;
+
+ if (ppsc->swrf_processing)
+ return false;
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+
+ u4tmp = rtl_read_dword(rtlpriv, REG_GPIO_OUTPUT);
+ state_toset = (u4tmp & BIT(31)) ? ERFON : ERFOFF;
+
+
+ if ((ppsc->hwradiooff == true) && (state_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio ON, RF ON\n");
+
+ state_toset = ERFON;
+ ppsc->hwradiooff = false;
+ actuallyset = true;
+ } else if ((ppsc->hwradiooff == false) && (state_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "GPIOChangeRF - HW Radio OFF, RF OFF\n");
+
+ state_toset = ERFOFF;
+ ppsc->hwradiooff = true;
+ actuallyset = true;
+ }
+
+ if (actuallyset) {
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ } else {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+ spin_lock(&rtlpriv->locks.rf_ps_lock);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock(&rtlpriv->locks.rf_ps_lock);
+ }
+
+ *valid = 1;
+ return !ppsc->hwradiooff;
+}
+
+static void add_one_key(struct ieee80211_hw *hw, u8 *macaddr,
+ struct rtl_mac *mac, u32 key, u32 id,
+ u8 enc_algo, bool is_pairwise)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "add one entry\n");
+ if (is_pairwise) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set Pairwise key\n");
+
+ rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[key]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "set group key\n");
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw, rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[id]);
+ }
+
+ rtl_cam_add_one_entry(hw, macaddr, key, id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[id]);
+ }
+}
+
+void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key,
+ u8 *mac_ad, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 *macaddr = mac_ad;
+ u32 id = 0;
+ bool is_pairwise = false;
+
+ static u8 cam_const_addr[4][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+ };
+ static u8 cam_const_broad[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key];
+ id = key;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ id = key;
+ } else {
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
+ id = rtl_cam_get_free_entry(hw, mac_ad);
+ if (id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv, COMP_SEC,
+ DBG_EMERG,
+ "Can not find free hw security cam entry\n");
+ return;
+ }
+ } else {
+ id = CAM_PAIRWISE_KEY_POSITION;
+ }
+
+ key = PAIRWISE_KEYIDX;
+ is_pairwise = true;
+ }
+ }
+
+ if (rtlpriv->sec.key_len[key] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ "delete one entry, id is %d\n", id);
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
+ rtl_cam_del_entry(hw, mac_ad);
+ rtl_cam_delete_one_entry(hw, mac_ad, id);
+ } else {
+ add_one_key(hw, macaddr, mac, key, id, enc_algo,
+ is_pairwise);
+ }
+ }
+}
+
+static void rtl8188ee_bt_var_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct bt_coexist_info coexist = rppriv->bt_coexist;
+
+ coexist.bt_coexistence = rppriv->bt_coexist.eeprom_bt_coexist;
+ coexist.bt_ant_num = coexist.eeprom_bt_ant_num;
+ coexist.bt_coexist_type = coexist.eeprom_bt_type;
+
+ if (coexist.reg_bt_iso == 2)
+ coexist.bt_ant_isolation = coexist.eeprom_bt_ant_isol;
+ else
+ coexist.bt_ant_isolation = coexist.reg_bt_iso;
+
+ coexist.bt_radio_shared_type = coexist.eeprom_bt_radio_shared;
+
+ if (coexist.bt_coexistence) {
+ if (coexist.reg_bt_sco == 1)
+ coexist.bt_service = BT_OTHER_ACTION;
+ else if (coexist.reg_bt_sco == 2)
+ coexist.bt_service = BT_SCO;
+ else if (coexist.reg_bt_sco == 4)
+ coexist.bt_service = BT_BUSY;
+ else if (coexist.reg_bt_sco == 5)
+ coexist.bt_service = BT_OTHERBUSY;
+ else
+ coexist.bt_service = BT_IDLE;
+
+ coexist.bt_edca_ul = 0;
+ coexist.bt_edca_dl = 0;
+ coexist.bt_rssi_state = 0xff;
+ }
+}
+
+void rtl8188ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool auto_load_fail, u8 *hwinfo)
+{
+ rtl8188ee_bt_var_init(hw);
+}
+
+void rtl8188ee_bt_reg_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+
+ /* 0:Low, 1:High, 2:From Efuse. */
+ rppriv->bt_coexist.reg_bt_iso = 2;
+ /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+ rppriv->bt_coexist.reg_bt_sco = 3;
+ /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+ rppriv->bt_coexist.reg_bt_sco = 0;
+}
+
+void rtl8188ee_bt_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci_priv *rppriv = rtl_pcipriv(hw);
+ struct bt_coexist_info coexist = rppriv->bt_coexist;
+ u8 u1_tmp;
+
+ if (coexist.bt_coexistence &&
+ ((coexist.bt_coexist_type == BT_CSR_BC4) ||
+ coexist.bt_coexist_type == BT_CSR_BC8)) {
+ if (coexist.bt_ant_isolation)
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+
+ u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) &
+ BIT_OFFSET_LEN_MASK_32(0, 1);
+ u1_tmp = u1_tmp | ((coexist.bt_ant_isolation == 1) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+ ((coexist.bt_service == BT_SCO) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+ rtl_write_byte(rtlpriv, 0x4fd, u1_tmp);
+
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010);
+
+ /* Config to 1T1R. */
+ if (rtlphy->rf_type == RF_1T1R) {
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp);
+
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp);
+ }
+ }
+}
+
+void rtl88ee_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl88ee_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl88ee_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) /* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ else /* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config = 0x%08X, write_into_reg =%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h
new file mode 100644
index 000000000000..b4460a41bd01
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/hw.h
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_HW_H__
+#define __RTL92CE_HW_H__
+
+void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl88ee_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *p_inta, u32 *p_intb);
+int rtl88ee_hw_init(struct ieee80211_hw *hw);
+void rtl88ee_card_disable(struct ieee80211_hw *hw);
+void rtl88ee_enable_interrupt(struct ieee80211_hw *hw);
+void rtl88ee_disable_interrupt(struct ieee80211_hw *hw);
+int rtl88ee_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl88ee_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl88ee_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl88ee_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl88ee_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl88ee_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl88ee_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
+void rtl88ee_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl88ee_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl88ee_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
+ u8 *p_macaddr, bool is_group, u8 enc_algo,
+ bool is_wepkey, bool clear_all);
+
+void rtl8188ee_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail, u8 *hwinfo);
+void rtl8188ee_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8188ee_bt_hw_init(struct ieee80211_hw *hw);
+void rtl88ee_suspend(struct ieee80211_hw *hw);
+void rtl88ee_resume(struct ieee80211_hw *hw);
+void rtl88ee_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
+void rtl88ee_fw_clk_off_timer_callback(unsigned long data);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.c b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
new file mode 100644
index 000000000000..c81a9cb6894c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.c
@@ -0,0 +1,157 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void rtl88ee_init_led(struct ieee80211_hw *hw,
+ struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
+void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+ rtl_write_byte(rtlpriv, REG_LEDCFG2,
+ (ledcfg & 0xf0) | BIT(5) | BIT(6));
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, ledcfg & 0x10);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ pled->ledon = true;
+}
+
+void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+ u8 val;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ "LedAddr:%X ledpin =%d\n", REG_LEDCFG2, pled->ledpin);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+ ledcfg &= 0xf0;
+ val = ledcfg | BIT(3) | BIT(5) | BIT(6);
+ if (pcipriv->ledctl.led_opendrain == true) {
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
+ ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+ val = ledcfg & 0xFE;
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, val);
+ } else {
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, val);
+ }
+ break;
+ case LED_PIN_LED1:
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1);
+ ledcfg &= 0x10;
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ pled->ledon = false;
+}
+
+void rtl88ee_init_sw_leds(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+ rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ rtl88ee_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+static void rtl88ee_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl88ee_sw_led_on(hw, pLed0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl88ee_sw_led_off(hw, pLed0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl88ee_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+ (ledaction == LED_CTL_TX ||
+ ledaction == LED_CTL_RX ||
+ ledaction == LED_CTL_SITE_SURVEY ||
+ ledaction == LED_CTL_LINK ||
+ ledaction == LED_CTL_NO_LINK ||
+ ledaction == LED_CTL_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_TRACE, "ledaction %d,\n",
+ ledaction);
+ rtl88ee_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/led.h b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
new file mode 100644
index 000000000000..4073f6f847b2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/led.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_LED_H__
+#define __RTL92CE_LED_H__
+
+void rtl88ee_init_sw_leds(struct ieee80211_hw *hw);
+void rtl88ee_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl88ee_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl88ee_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
new file mode 100644
index 000000000000..e655c0473225
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
@@ -0,0 +1,2202 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+
+static void set_baseband_phy_config(struct ieee80211_hw *hw);
+static void set_baseband_agc_config(struct ieee80211_hw *hw);
+static void store_pwrindex_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data);
+static bool check_cond(struct ieee80211_hw *hw, const u32 condition);
+
+static u32 rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 ret;
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ offset &= 0xff;
+ newoffset = offset;
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+ return 0xFFFFFFFF;
+ }
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+ if (rfpath == jj)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, phreg->rfhssi_para2, MASKDWORD);
+ tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+ (newoffset << 23) | BLSSIREADEDGE;
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSIREADEDGE));
+ mdelay(1);
+ rtl_set_bbreg(hw, phreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(2);
+ if (rfpath == jj)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == kk)
+ rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+ if (rfpi_enable)
+ ret = rtl_get_bbreg(hw, phreg->rf_rbpi, BLSSIREADBACKDATA);
+ else
+ ret = rtl_get_bbreg(hw, phreg->rf_rb, BLSSIREADBACKDATA);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]= 0x%x\n",
+ rfpath, phreg->rf_rb, ret);
+ return ret;
+}
+
+static void rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ u32 data_and_addr;
+ u32 newoffset;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *phreg = &rtlphy->phyreg_def[rfpath];
+
+ if (RT_CANNOT_IO(hw)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+ return;
+ }
+ offset &= 0xff;
+ newoffset = offset;
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, phreg->rf3wire_offset, MASKDWORD, data_and_addr);
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]= 0x%x\n",
+ rfpath, phreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 cal_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+ return i;
+}
+
+static bool config_bb_with_header(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ if (configtype == BASEBAND_CONFIG_PHY_REG)
+ set_baseband_phy_config(hw);
+ else if (configtype == BASEBAND_CONFIG_AGC_TAB)
+ set_baseband_agc_config(hw);
+ return true;
+}
+
+static bool config_bb_with_pgheader(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int i;
+ u32 *table_pg;
+ u16 tbl_page_len;
+ u32 v1 = 0, v2 = 0;
+
+ tbl_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN;
+ table_pg = RTL8188EEPHY_REG_ARRAY_PG;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < tbl_page_len; i = i + 3) {
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+
+ if (v1 < 0xcdcdcdcd) {
+ if (table_pg[i] == 0xfe)
+ mdelay(50);
+ else if (table_pg[i] == 0xfd)
+ mdelay(5);
+ else if (table_pg[i] == 0xfc)
+ mdelay(1);
+ else if (table_pg[i] == 0xfb)
+ udelay(50);
+ else if (table_pg[i] == 0xfa)
+ udelay(5);
+ else if (table_pg[i] == 0xf9)
+ udelay(1);
+
+ store_pwrindex_offset(hw, table_pg[i],
+ table_pg[i + 1],
+ table_pg[i + 2]);
+ continue;
+ } else {
+ if (!check_cond(hw, table_pg[i])) {
+ /*don't need the hw_body*/
+ i += 2; /* skip the pair of expression*/
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+ while (v2 != 0xDEAD) {
+ i += 3;
+ v1 = table_pg[i];
+ v2 = table_pg[i + 1];
+ }
+ }
+ }
+ }
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "configtype != BaseBand_Config_PHY_REG\n");
+ }
+ return true;
+}
+
+static bool config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus;
+
+ rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_PHY_REG);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+ return false;
+ }
+
+ if (fuse->autoload_failflag == false) {
+ rtlphy->pwrgroup_cnt = 0;
+ rtstatus = config_bb_with_pgheader(hw, BASEBAND_CONFIG_PHY_REG);
+ }
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+ return false;
+ }
+ rtstatus = config_bb_with_header(hw, BASEBAND_CONFIG_AGC_TAB);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+ return false;
+ }
+ rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2, 0x200));
+
+ return true;
+}
+
+static void rtl88e_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ rtlphy->phyreg_def[jj].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[kk].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ rtlphy->phyreg_def[jj].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[kk].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ rtlphy->phyreg_def[jj].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[kk].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[jj].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[kk].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+ rtlphy->phyreg_def[jj].rf3wire_offset = RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[kk].rf3wire_offset = RFPGA0_XB_LSSIPARAMETER;
+
+ rtlphy->phyreg_def[jj].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[kk].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+ rtlphy->phyreg_def[jj].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[kk].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ rtlphy->phyreg_def[jj].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[kk].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+ rtlphy->phyreg_def[jj].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[kk].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+ rtlphy->phyreg_def[jj].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[kk].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+
+ rtlphy->phyreg_def[jj].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[kk].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ rtlphy->phyreg_def[jj].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[kk].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ rtlphy->phyreg_def[jj].rfrxiq_imbal = ROFDM0_XARXIQIMBAL;
+ rtlphy->phyreg_def[kk].rfrxiq_imbal = ROFDM0_XBRXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBAL;
+
+ rtlphy->phyreg_def[jj].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[kk].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ rtlphy->phyreg_def[jj].rftxiq_imbal = ROFDM0_XATXIQIMBAL;
+ rtlphy->phyreg_def[kk].rftxiq_imbal = ROFDM0_XBTXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBAL;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBAL;
+
+ rtlphy->phyreg_def[jj].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[kk].rftx_afe = ROFDM0_XBTXAFE;
+
+ rtlphy->phyreg_def[jj].rf_rb = RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[kk].rf_rb = RFPGA0_XB_LSSIREADBACK;
+
+ rtlphy->phyreg_def[jj].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+ rtlphy->phyreg_def[kk].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+
+static bool rtl88e_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+ return true;
+}
+
+static bool chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT,
+ CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+ rtl88e_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+ postcommoncmdcnt = 0;
+
+ rtl88e_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ "illegal channel for Zebra: %d\n", channel);
+
+ rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ rtl88e_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0,
+ 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl88e_phy_set_txpower_level(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16) currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8) currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+static long rtl88e_pwr_idx_dbm(struct ieee80211_hw *hw,
+ enum wireless_mode wirelessmode,
+ u8 txpwridx)
+{
+ long offset;
+ long pwrout_dbm;
+
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ offset = -7;
+ break;
+ case WIRELESS_MODE_G:
+ case WIRELESS_MODE_N_24G:
+ offset = -8;
+ break;
+ default:
+ offset = -8;
+ break;
+ }
+ pwrout_dbm = txpwridx / 2 + offset;
+ return pwrout_dbm;
+}
+
+static void rtl88e_phy_set_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "--->Cmd(%#x), set_io_inprogress(%d)\n",
+ rtlphy->current_io_type, rtlphy->set_io_inprogress);
+ switch (rtlphy->current_io_type) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+ /*rtl92c_dm_write_dig(hw);*/
+ rtl88e_phy_set_txpower_level(hw, rtlphy->current_channel);
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x83);
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+ dm_digtable->cur_igvalue = 0x17;
+ rtl_set_bbreg(hw, RCCK0_CCA, 0xff0000, 0x40);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ rtlphy->set_io_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "(%#x)\n", rtlphy->current_io_type);
+}
+
+u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "BBR MASK = 0x%x Addr[0x%x]= 0x%x\n", bitmask,
+ regaddr, originalvalue);
+
+ return returnvalue;
+}
+
+void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x),data(%#x)\n",
+ regaddr, bitmask, data);
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+ regaddr, bitmask, data);
+}
+
+u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+ regaddr, rfpath, bitmask);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+
+ original_value = rf_serial_read(hw, rfpath, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
+ regaddr, rfpath, bitmask, original_value);
+
+ return readback_value;
+}
+
+void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, rfpath);
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = rf_serial_read(hw, rfpath, regaddr);
+ bitshift = cal_bit_shift(bitmask);
+ data = ((original_value & (~bitmask)) |
+ (data << bitshift));
+ }
+
+ rf_serial_write(hw, rfpath, regaddr, data);
+
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+ regaddr, bitmask, data, rfpath);
+}
+
+static bool config_mac_with_header(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptrarray;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl8188EMACPHY_Array\n");
+ arraylength = RTL8188EEMAC_1T_ARRAYLEN;
+ ptrarray = RTL8188EEMAC_1T_ARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Img:RTL8188EEMAC_1T_ARRAY LEN %d\n", arraylength);
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+ return true;
+}
+
+bool rtl88e_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool rtstatus = config_mac_with_header(hw);
+
+ rtl_write_byte(rtlpriv, 0x04CA, 0x0B);
+ return rtstatus;
+}
+
+bool rtl88e_phy_bb_config(struct ieee80211_hw *hw)
+{
+ bool rtstatus = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regval;
+ u8 reg_hwparafile = 1;
+ u32 tmp;
+ rtl88e_phy_init_bb_rf_register_definition(hw);
+ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+ regval | BIT(13) | BIT(0) | BIT(1));
+
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+ FEN_BB_GLB_RSTN | FEN_BBRSTB);
+ tmp = rtl_read_dword(rtlpriv, 0x4c);
+ rtl_write_dword(rtlpriv, 0x4c, tmp | BIT(23));
+ if (reg_hwparafile == 1)
+ rtstatus = config_parafile(hw);
+ return rtstatus;
+}
+
+bool rtl88e_phy_rf_config(struct ieee80211_hw *hw)
+{
+ return rtl88e_phy_rf6052_config(hw);
+}
+
+static bool check_cond(struct ieee80211_hw *hw,
+ const u32 condition)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u32 _board = fuse->board_type; /*need efuse define*/
+ u32 _interface = rtlhal->interface;
+ u32 _platform = 0x08;/*SupportPlatform */
+ u32 cond = condition;
+
+ if (condition == 0xCDCDCDCD)
+ return true;
+
+ cond = condition & 0xFF;
+ if ((_board & cond) == 0 && cond != 0x1F)
+ return false;
+
+ cond = condition & 0xFF00;
+ cond = cond >> 8;
+ if ((_interface & cond) == 0 && cond != 0x07)
+ return false;
+
+ cond = condition & 0xFF0000;
+ cond = cond >> 16;
+ if ((_platform & cond) == 0 && cond != 0x0F)
+ return false;
+ return true;
+}
+
+static void _rtl8188e_config_rf_reg(struct ieee80211_hw *hw,
+ u32 addr, u32 data, enum radio_path rfpath,
+ u32 regaddr)
+{
+ if (addr == 0xffe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_rfreg(hw, rfpath, regaddr,
+ RFREG_OFFSET_MASK,
+ data);
+ udelay(1);
+ }
+}
+
+static void rtl88_config_s(struct ieee80211_hw *hw,
+ u32 addr, u32 data)
+{
+ u32 content = 0x1000; /*RF Content: radio_a_txt*/
+ u32 maskforphyset = (u32)(content & 0xE000);
+
+ _rtl8188e_config_rf_reg(hw, addr, data, RF90_PATH_A,
+ addr | maskforphyset);
+}
+
+static void _rtl8188e_config_bb_reg(struct ieee80211_hw *hw,
+ u32 addr, u32 data)
+{
+ if (addr == 0xfe) {
+ mdelay(50);
+ } else if (addr == 0xfd) {
+ mdelay(5);
+ } else if (addr == 0xfc) {
+ mdelay(1);
+ } else if (addr == 0xfb) {
+ udelay(50);
+ } else if (addr == 0xfa) {
+ udelay(5);
+ } else if (addr == 0xf9) {
+ udelay(1);
+ } else {
+ rtl_set_bbreg(hw, addr, MASKDWORD, data);
+ udelay(1);
+ }
+}
+
+
+#define NEXT_PAIR(v1, v2, i) \
+ do { \
+ i += 2; v1 = array_table[i]; \
+ v2 = array_table[i + 1]; \
+ } while (0)
+
+static void set_baseband_agc_config(struct ieee80211_hw *hw)
+{
+ int i;
+ u32 *array_table;
+ u16 arraylen;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 v1 = 0, v2 = 0;
+
+ arraylen = RTL8188EEAGCTAB_1TARRAYLEN;
+ array_table = RTL8188EEAGCTAB_1TARRAY;
+
+ for (i = 0; i < arraylen; i += 2) {
+ v1 = array_table[i];
+ v2 = array_table[i + 1];
+ if (v1 < 0xCDCDCDCD) {
+ rtl_set_bbreg(hw, array_table[i], MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ continue;
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, array_table[i])) {
+ /*Discard the following (offset, data) pairs*/
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ NEXT_PAIR(v1, v2, i);
+ }
+ i -= 2; /* compensate for loop's += 2*/
+ } else {
+ /* Configure matched pairs and skip to end */
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ rtl_set_bbreg(hw, array_table[i],
+ MASKDWORD,
+ array_table[i + 1]);
+ udelay(1);
+ NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n",
+ array_table[i],
+ array_table[i + 1]);
+ }
+}
+
+static void set_baseband_phy_config(struct ieee80211_hw *hw)
+{
+ int i;
+ u32 *array_table;
+ u16 arraylen;
+ u32 v1 = 0, v2 = 0;
+
+ arraylen = RTL8188EEPHY_REG_1TARRAYLEN;
+ array_table = RTL8188EEPHY_REG_1TARRAY;
+
+ for (i = 0; i < arraylen; i += 2) {
+ v1 = array_table[i];
+ v2 = array_table[i + 1];
+ if (v1 < 0xcdcdcdcd) {
+ _rtl8188e_config_bb_reg(hw, v1, v2);
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, array_table[i])) {
+ /*Discard the following (offset, data) pairs*/
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2*/
+ } else {
+ /* Configure matched pairs and skip to end */
+ NEXT_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD &&
+ v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < arraylen - 2) {
+ _rtl8188e_config_bb_reg(hw, v1, v2);
+ NEXT_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < arraylen - 2)
+ NEXT_PAIR(v1, v2, i);
+ }
+ }
+ }
+}
+
+static void store_pwrindex_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (regaddr == RTXAGC_A_RATE18_06) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]);
+ }
+ if (regaddr == RTXAGC_A_RATE54_24) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]);
+ }
+ if (regaddr == RTXAGC_A_CCK1_MCS32) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]);
+ }
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0xffffff00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]);
+ }
+ if (regaddr == RTXAGC_A_MCS03_MCS00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]);
+ }
+ if (regaddr == RTXAGC_A_MCS07_MCS04) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]);
+ }
+ if (regaddr == RTXAGC_A_MCS11_MCS08) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]);
+ }
+ if (regaddr == RTXAGC_A_MCS15_MCS12) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data;
+ if (get_rf_type(rtlphy) == RF_1T1R)
+ rtlphy->pwrgroup_cnt++;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]);
+ }
+ if (regaddr == RTXAGC_B_RATE18_06) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]);
+ }
+ if (regaddr == RTXAGC_B_RATE54_24) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]);
+ }
+ if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]);
+ }
+ if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]);
+ }
+ if (regaddr == RTXAGC_B_MCS03_MCS00) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]);
+ }
+ if (regaddr == RTXAGC_B_MCS07_MCS04) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]);
+ }
+ if (regaddr == RTXAGC_B_MCS11_MCS08) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]);
+ }
+ if (regaddr == RTXAGC_B_MCS15_MCS12) {
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+ rtlphy->pwrgroup_cnt,
+ rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]);
+ if (get_rf_type(rtlphy) != RF_1T1R)
+ rtlphy->pwrgroup_cnt++;
+ }
+}
+
+#define READ_NEXT_RF_PAIR(v1, v2, i) \
+ do { \
+ i += 2; v1 = a_table[i]; \
+ v2 = a_table[i + 1]; \
+ } while (0)
+
+bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ int i;
+ u32 *a_table;
+ u16 a_len;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 v1 = 0, v2 = 0;
+
+ a_len = RTL8188EE_RADIOA_1TARRAYLEN;
+ a_table = RTL8188EE_RADIOA_1TARRAY;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", a_len);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath);
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < a_len; i = i + 2) {
+ v1 = a_table[i];
+ v2 = a_table[i + 1];
+ if (v1 < 0xcdcdcdcd) {
+ rtl88_config_s(hw, v1, v2);
+ } else {/*This line is the start line of branch.*/
+ if (!check_cond(hw, a_table[i])) {
+ /* Discard the following (offset, data)
+ * pairs
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < a_len - 2)
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ i -= 2; /* prevent from for-loop += 2*/
+ } else {
+ /* Configure matched pairs and skip to
+ * end of if-else.
+ */
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ while (v2 != 0xDEAD && v2 != 0xCDEF &&
+ v2 != 0xCDCD && i < a_len - 2) {
+ rtl88_config_s(hw, v1, v2);
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+
+ while (v2 != 0xDEAD && i < a_len - 2)
+ READ_NEXT_RF_PAIR(v1, v2, i);
+ }
+ }
+ }
+
+ if (rtlhal->oem_id == RT_CID_819x_HP)
+ rtl88_config_s(hw, 0x52, 0x7E4BD);
+
+ break;
+
+ case RF90_PATH_B:
+ case RF90_PATH_C:
+ case RF90_PATH_D:
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ return true;
+}
+
+void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->default_initialgain[0] = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[1] = rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[2] = rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1,
+ MASKBYTE0);
+ rtlphy->default_initialgain[3] = rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1,
+ MASKBYTE0);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default initial gain (c50 = 0x%x, c58 = 0x%x, c60 = 0x%x, c68 = 0x%x\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]);
+
+ rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3,
+ MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+ MASKDWORD);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 level;
+ long dbm;
+
+ level = rtlphy->cur_cck_txpwridx;
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_B, level);
+ level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level) > dbm)
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_G, level);
+ level = rtlphy->cur_ofdm24g_txpwridx;
+ if (rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level) > dbm)
+ dbm = rtl88e_pwr_idx_dbm(hw, WIRELESS_MODE_N_24G, level);
+ *powerlevel = dbm;
+}
+
+static void _rtl88e_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+ u8 *cckpower, u8 *ofdm, u8 *bw20_pwr,
+ u8 *bw40_pwr)
+{
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u8 i = (channel - 1);
+ u8 rf_path = 0;
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ if (rf_path == jj) {
+ cckpower[jj] = fuse->txpwrlevel_cck[jj][i];
+ if (fuse->txpwr_ht20diff[jj][i] > 0x0f) /*-8~7 */
+ bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
+ (~(fuse->txpwr_ht20diff[jj][i]) + 1);
+ else
+ bw20_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
+ fuse->txpwr_ht20diff[jj][i];
+ if (fuse->txpwr_legacyhtdiff[jj][i] > 0xf)
+ ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] -
+ (~(fuse->txpwr_legacyhtdiff[jj][i])+1);
+ else
+ ofdm[jj] = fuse->txpwrlevel_ht40_1s[jj][i] +
+ fuse->txpwr_legacyhtdiff[jj][i];
+ bw40_pwr[jj] = fuse->txpwrlevel_ht40_1s[jj][i];
+
+ } else if (rf_path == kk) {
+ cckpower[kk] = fuse->txpwrlevel_cck[kk][i];
+ bw20_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
+ fuse->txpwr_ht20diff[kk][i];
+ ofdm[kk] = fuse->txpwrlevel_ht40_1s[kk][i] +
+ fuse->txpwr_legacyhtdiff[kk][i];
+ bw40_pwr[kk] = fuse->txpwrlevel_ht40_1s[kk][i];
+ }
+ }
+}
+
+static void _rtl88e_ccxpower_index_check(struct ieee80211_hw *hw,
+ u8 channel, u8 *cckpower,
+ u8 *ofdm, u8 *bw20_pwr,
+ u8 *bw40_pwr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->cur_cck_txpwridx = cckpower[0];
+ rtlphy->cur_ofdm24g_txpwridx = ofdm[0];
+ rtlphy->cur_bw20_txpwridx = bw20_pwr[0];
+ rtlphy->cur_bw40_txpwridx = bw40_pwr[0];
+}
+
+void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ u8 cckpower[MAX_TX_COUNT] = {0}, ofdm[MAX_TX_COUNT] = {0};
+ u8 bw20_pwr[MAX_TX_COUNT] = {0}, bw40_pwr[MAX_TX_COUNT] = {0};
+
+ if (fuse->txpwr_fromeprom == false)
+ return;
+ _rtl88e_get_txpower_index(hw, channel, &cckpower[0], &ofdm[0],
+ &bw20_pwr[0], &bw40_pwr[0]);
+ _rtl88e_ccxpower_index_check(hw, channel, &cckpower[0], &ofdm[0],
+ &bw20_pwr[0], &bw40_pwr[0]);
+ rtl88e_phy_rf6052_set_cck_txpower(hw, &cckpower[0]);
+ rtl88e_phy_rf6052_set_ofdm_txpower(hw, &ofdm[0], &bw20_pwr[0],
+ &bw40_pwr[0], channel);
+}
+
+void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ enum io_type iotype;
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ case SCAN_OPT_RESTORE:
+ iotype = IO_CMD_RESUME_DM_BY_SCAN;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_IO_CMD,
+ (u8 *)&iotype);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Unknown Scan Backup operation.\n");
+ break;
+ }
+ }
+}
+
+void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz");
+
+ if (is_hal_stop(rtlhal)) {
+ rtlphy->set_bwmode_inprogress = false;
+ return;
+ }
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+ reg_prsr_rsc =
+ (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+ rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+ /* rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);*/
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+ /*rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);*/
+
+ rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+ (mac->cur_40_prime_sc ==
+ HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+ break;
+ }
+ rtl88e_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "\n");
+}
+
+void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp_bw = rtlphy->current_chan_bw;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ rtlphy->set_bwmode_inprogress = true;
+ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl88e_phy_set_bw_mode_callback(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "FALSE driver sleep or unload\n");
+ rtlphy->set_bwmode_inprogress = false;
+ rtlphy->current_chan_bw = tmp_bw;
+ }
+}
+
+void rtl88e_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ "switch to channel%d\n", rtlphy->current_channel);
+ if (is_hal_stop(rtlhal))
+ return;
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+ if (!chnl_step_by_step(hw, rtlphy->current_channel,
+ &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step, &delay)) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else {
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ break;
+ } while (true);
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "\n");
+}
+
+u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+ RT_ASSERT((rtlphy->current_channel <= 14),
+ "WIRELESS_MODE_G but channel>14");
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+ if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+ rtl88e_phy_sw_chnl_callback(hw);
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false schdule workitem current channel %d\n",
+ rtlphy->current_channel);
+ rtlphy->sw_chnl_inprogress = false;
+ } else {
+ RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+ "sw_chnl_inprogress false driver sleep or unload\n");
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ return 1;
+}
+
+static u8 _rtl88e_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x8214032a);
+ rtl_set_bbreg(hw, 0xe3c, MASKDWORD, 0x28160000);
+
+ rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x00462911);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ return result;
+}
+
+static u8 _rtl88e_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+ u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+ u8 result = 0x00;
+
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+ rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
+ mdelay(IQK_DELAY_TIME);
+ reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+ reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
+ reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
+ reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
+ reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+
+ if (!(reg_eac & BIT(31)) &&
+ (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+ if (!(reg_eac & BIT(30)) &&
+ (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static u8 _rtl88e_phy_path_a_rx_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+ u32 reg_eac, reg_e94, reg_e9c, reg_ea4, u32temp;
+ u8 result = 0x00;
+ int jj = RF90_PATH_A;
+
+ /*Get TXIMR Setting*/
+ /*Modify RX IQK mode table*/
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+ rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+ rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf117b);
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+ /*IQK Setting*/
+ rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x81004800);
+
+ /*path a IQK setting*/
+ rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160804);
+ rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160000);
+
+ /*LO calibration Setting*/
+ rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+ /*one shot, path A LOK & iqk*/
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+
+
+ if (!(reg_eac & BIT(28)) &&
+ (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+ (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+ result |= 0x01;
+ else
+ return result;
+
+ u32temp = 0x80007C00 | (reg_e94&0x3FF0000) |
+ ((reg_e9c&0x3FF0000) >> 16);
+ rtl_set_bbreg(hw, RTX_IQK, MASKDWORD, u32temp);
+ /*RX IQK*/
+ /*Modify RX IQK mode table*/
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x00000000);
+ rtl_set_rfreg(hw, jj, RF_WE_LUT, RFREG_OFFSET_MASK, 0x800a0);
+ rtl_set_rfreg(hw, jj, RF_RCK_OS, RFREG_OFFSET_MASK, 0x30000);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G1, RFREG_OFFSET_MASK, 0x0000f);
+ rtl_set_rfreg(hw, jj, RF_TXPA_G2, RFREG_OFFSET_MASK, 0xf7ffa);
+ rtl_set_bbreg(hw, RFPGA0_IQK, MASKDWORD, 0x80800000);
+
+ /*IQK Setting*/
+ rtl_set_bbreg(hw, RRX_IQK, MASKDWORD, 0x01004800);
+
+ /*path a IQK setting*/
+ rtl_set_bbreg(hw, RTX_IQK_TONE_A, MASKDWORD, 0x30008c1c);
+ rtl_set_bbreg(hw, RRX_IQK_TONE_A, MASKDWORD, 0x10008c1c);
+ rtl_set_bbreg(hw, RTX_IQK_PI_A, MASKDWORD, 0x82160c05);
+ rtl_set_bbreg(hw, RRX_IQK_PI_A, MASKDWORD, 0x28160c05);
+
+ /*LO calibration Setting*/
+ rtl_set_bbreg(hw, RIQK_AGC_RSP, MASKDWORD, 0x0046a911);
+ /*one shot, path A LOK & iqk*/
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf9000000);
+ rtl_set_bbreg(hw, RIQK_AGC_PTS, MASKDWORD, 0xf8000000);
+
+ mdelay(IQK_DELAY_TIME);
+
+ reg_eac = rtl_get_bbreg(hw, RRX_POWER_AFTER_IQK_A_2, MASKDWORD);
+ reg_e94 = rtl_get_bbreg(hw, RTX_POWER_BEFORE_IQK_A, MASKDWORD);
+ reg_e9c = rtl_get_bbreg(hw, RTX_POWER_AFTER_IQK_A, MASKDWORD);
+ reg_ea4 = rtl_get_bbreg(hw, RRX_POWER_BEFORE_IQK_A_2, MASKDWORD);
+
+ if (!(reg_eac & BIT(27)) &&
+ (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+ (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+ result |= 0x02;
+ return result;
+}
+
+static void fill_iqk(struct ieee80211_hw *hw, bool iqk_ok, long result[][8],
+ u8 final, bool btxonly)
+{
+ u32 oldval_0, x, tx0_a, reg;
+ long y, tx0_c;
+
+ if (final == 0xFF) {
+ return;
+ } else if (iqk_ok) {
+ oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBAL,
+ MASKDWORD) >> 22) & 0x3FF;
+ x = result[final][0];
+ if ((x & 0x00000200) != 0)
+ x = x | 0xFFFFFC00;
+ tx0_a = (x * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x3FF, tx0_a);
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(31),
+ ((x * oldval_0 >> 7) & 0x1));
+ y = result[final][1];
+ if ((y & 0x00000200) != 0)
+ y |= 0xFFFFFC00;
+ tx0_c = (y * oldval_0) >> 8;
+ rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+ ((tx0_c & 0x3C0) >> 6));
+ rtl_set_bbreg(hw, ROFDM0_XATXIQIMBAL, 0x003F0000,
+ (tx0_c & 0x3F));
+ rtl_set_bbreg(hw, ROFDM0_ECCATHRES, BIT(29),
+ ((y * oldval_0 >> 7) & 0x1));
+ if (btxonly)
+ return;
+ reg = result[final][2];
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0x3FF, reg);
+ reg = result[final][3] & 0x3F;
+ rtl_set_bbreg(hw, ROFDM0_XARXIQIMBAL, 0xFC00, reg);
+ reg = (result[final][3] >> 6) & 0xF;
+ rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+ }
+}
+
+static void save_adda_reg(struct ieee80211_hw *hw,
+ const u32 *addareg, u32 *backup,
+ u32 registernum)
+{
+ u32 i;
+
+ for (i = 0; i < registernum; i++)
+ backup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+
+static void save_mac_reg(struct ieee80211_hw *hw, const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+ macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+
+static void reload_adda(struct ieee80211_hw *hw, const u32 *addareg,
+ u32 *backup, u32 reg_num)
+{
+ u32 i;
+
+ for (i = 0; i < reg_num; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, backup[i]);
+}
+
+static void reload_mac(struct ieee80211_hw *hw, const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+
+ for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+ rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+
+static void _rtl88e_phy_path_adda_on(struct ieee80211_hw *hw,
+ const u32 *addareg, bool is_patha_on,
+ bool is2t)
+{
+ u32 pathon;
+ u32 i;
+
+ pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+ if (false == is2t) {
+ pathon = 0x0bdb25a0;
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+ } else {
+ rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathon);
+ }
+
+ for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+ rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathon);
+}
+
+static void _rtl88e_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+ const u32 *macreg,
+ u32 *macbackup)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i = 0;
+
+ rtl_write_byte(rtlpriv, macreg[i], 0x3F);
+
+ for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+ rtl_write_byte(rtlpriv, macreg[i],
+ (u8) (macbackup[i] & (~BIT(3))));
+ rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+
+static void _rtl88e_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+
+static void _rtl88e_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+ u32 mode;
+
+ mode = pi_mode ? 0x01000100 : 0x01000000;
+ rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+ rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+
+static bool sim_comp(struct ieee80211_hw *hw, long result[][8], u8 c1, u8 c2)
+{
+ u32 i, j, diff, bitmap, bound;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 final[2] = {0xFF, 0xFF};
+ bool bresult = true, is2t = IS_92C_SERIAL(rtlhal->version);
+
+ if (is2t)
+ bound = 8;
+ else
+ bound = 4;
+
+ bitmap = 0;
+
+ for (i = 0; i < bound; i++) {
+ diff = (result[c1][i] > result[c2][i]) ?
+ (result[c1][i] - result[c2][i]) :
+ (result[c2][i] - result[c1][i]);
+
+ if (diff > MAX_TOLERANCE) {
+ if ((i == 2 || i == 6) && !bitmap) {
+ if (result[c1][i] + result[c1][i + 1] == 0)
+ final[(i / 4)] = c2;
+ else if (result[c2][i] + result[c2][i + 1] == 0)
+ final[(i / 4)] = c1;
+ else
+ bitmap = bitmap | (1 << i);
+ } else {
+ bitmap = bitmap | (1 << i);
+ }
+ }
+ }
+
+ if (bitmap == 0) {
+ for (i = 0; i < (bound / 4); i++) {
+ if (final[i] != 0xFF) {
+ for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+ result[3][j] = result[final[i]][j];
+ bresult = false;
+ }
+ }
+ return bresult;
+ } else if (!(bitmap & 0x0F)) {
+ for (i = 0; i < 4; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else if (!(bitmap & 0xF0) && is2t) {
+ for (i = 4; i < 8; i++)
+ result[3][i] = result[c1][i];
+ return false;
+ } else {
+ return false;
+ }
+}
+
+static void _rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw,
+ long result[][8], u8 t, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 i;
+ u8 patha_ok, pathb_ok;
+ const u32 adda_reg[IQK_ADDA_REG_NUM] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+ const u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+ 0x522, 0x550, 0x551, 0x040
+ };
+ const u32 iqk_bb_reg[IQK_BB_REG_NUM] = {
+ ROFDM0_TRXPATHENABLE, ROFDM0_TRMUXPAR, RFPGA0_XCD_RFINTERFACESW,
+ 0xb68, 0xb6c, 0x870, 0x860, 0x864, 0x800
+ };
+ const u32 retrycount = 2;
+
+ if (t == 0) {
+ save_adda_reg(hw, adda_reg, rtlphy->adda_backup, 16);
+ save_mac_reg(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+ }
+ _rtl88e_phy_path_adda_on(hw, adda_reg, true, is2t);
+ if (t == 0) {
+ rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER1, BIT(8));
+ }
+
+ if (!rtlphy->rfpi_enable)
+ _rtl88e_phy_pi_mode_switch(hw, true);
+ /*BB Setting*/
+ rtl_set_bbreg(hw, 0x800, BIT(24), 0x00);
+ rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+ rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+ rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+
+ rtl_set_bbreg(hw, 0x870, BIT(10), 0x01);
+ rtl_set_bbreg(hw, 0x870, BIT(26), 0x01);
+ rtl_set_bbreg(hw, 0x860, BIT(10), 0x00);
+ rtl_set_bbreg(hw, 0x864, BIT(10), 0x00);
+
+ if (is2t) {
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
+ }
+ _rtl88e_phy_mac_setting_calibration(hw, iqk_mac_reg,
+ rtlphy->iqk_mac_backup);
+ rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x0f600000);
+ if (is2t)
+ rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x0f600000);
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+ rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+ rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x81004800);
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl88e_phy_path_a_iqk(hw, is2t);
+ if (patha_ok == 0x01) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A Tx IQK Success!!\n");
+ result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ }
+ }
+
+ for (i = 0; i < retrycount; i++) {
+ patha_ok = _rtl88e_phy_path_a_rx_iqk(hw, is2t);
+ if (patha_ok == 0x03) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A Rx IQK Success!!\n");
+ result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path a RX iqk fail!!!\n");
+ }
+ }
+
+ if (0 == patha_ok) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Path A IQK Success!!\n");
+ }
+ if (is2t) {
+ _rtl88e_phy_path_a_standby(hw);
+ _rtl88e_phy_path_adda_on(hw, adda_reg, false, is2t);
+ for (i = 0; i < retrycount; i++) {
+ pathb_ok = _rtl88e_phy_path_b_iqk(hw);
+ if (pathb_ok == 0x03) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][5] =
+ (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][6] =
+ (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ result[t][7] =
+ (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ break;
+ } else if (i == (retrycount - 1) && pathb_ok == 0x01) {
+ result[t][4] = (rtl_get_bbreg(hw,
+ 0xeb4, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+ 0x3FF0000) >> 16;
+ }
+ }
+
+ rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+
+ if (t != 0) {
+ if (!rtlphy->rfpi_enable)
+ _rtl88e_phy_pi_mode_switch(hw, false);
+ reload_adda(hw, adda_reg, rtlphy->adda_backup, 16);
+ reload_mac(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+ reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup,
+ IQK_BB_REG_NUM);
+
+ rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+ if (is2t)
+ rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+ rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x01008c00);
+ rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x01008c00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "88ee IQK Finish!!\n");
+}
+
+static void _rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+ u8 tmpreg;
+ u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int jj = RF90_PATH_A;
+ int kk = RF90_PATH_B;
+
+ tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+ if ((tmpreg & 0x70) != 0)
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+ else
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+ if ((tmpreg & 0x70) != 0) {
+ rf_a_mode = rtl_get_rfreg(hw, jj, 0x00, MASK12BITS);
+
+ if (is2t)
+ rf_b_mode = rtl_get_rfreg(hw, kk, 0x00,
+ MASK12BITS);
+
+ rtl_set_rfreg(hw, jj, 0x00, MASK12BITS,
+ (rf_a_mode & 0x8FFFF) | 0x10000);
+
+ if (is2t)
+ rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+ (rf_b_mode & 0x8FFFF) | 0x10000);
+ }
+ lc_cal = rtl_get_rfreg(hw, jj, 0x18, MASK12BITS);
+
+ rtl_set_rfreg(hw, jj, 0x18, MASK12BITS, lc_cal | 0x08000);
+
+ mdelay(100);
+
+ if ((tmpreg & 0x70) != 0) {
+ rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+ rtl_set_rfreg(hw, jj, 0x00, MASK12BITS, rf_a_mode);
+
+ if (is2t)
+ rtl_set_rfreg(hw, kk, 0x00, MASK12BITS,
+ rf_b_mode);
+ } else {
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ }
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+}
+
+static void rfpath_switch(struct ieee80211_hw *hw,
+ bool bmain, bool is2t)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *fuse = rtl_efuse(rtl_priv(hw));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "\n");
+
+ if (is_hal_stop(rtlhal)) {
+ u8 u1btmp;
+ u1btmp = rtl_read_byte(rtlpriv, REG_LEDCFG0);
+ rtl_write_byte(rtlpriv, REG_LEDCFG0, u1btmp | BIT(7));
+ rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+ }
+ if (is2t) {
+ if (bmain)
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x1);
+ else
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+ BIT(5) | BIT(6), 0x2);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XAB_RFINTERFACESW, BIT(8) | BIT(9), 0);
+ rtl_set_bbreg(hw, 0x914, MASKLWORD, 0x0201);
+
+ /* We use the RF definition of MAIN and AUX, left antenna and
+ * right antenna repectively.
+ * Default output at AUX.
+ */
+ if (bmain) {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
+ BIT(13) | BIT(12), 0);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
+ BIT(4) | BIT(3), 0);
+ if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 0);
+ } else {
+ rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, BIT(14) |
+ BIT(13) | BIT(12), 1);
+ rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE, BIT(5) |
+ BIT(4) | BIT(3), 1);
+ if (fuse->antenna_div_type == CGCS_RX_HW_ANTDIV)
+ rtl_set_bbreg(hw, RCONFIG_RAM64X16, BIT(31), 1);
+ }
+ }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ long result[4][8];
+ u8 i, final;
+ bool patha_ok;
+ long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_tmp = 0;
+ bool is12simular, is13simular, is23simular;
+ u32 iqk_bb_reg[9] = {
+ ROFDM0_XARXIQIMBAL,
+ ROFDM0_XBRXIQIMBAL,
+ ROFDM0_ECCATHRES,
+ ROFDM0_AGCRSSITABLE,
+ ROFDM0_XATXIQIMBAL,
+ ROFDM0_XBTXIQIMBAL,
+ ROFDM0_XCTXAFE,
+ ROFDM0_XDTXAFE,
+ ROFDM0_RXIQEXTANTA
+ };
+
+ if (recovery) {
+ reload_adda(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+ return;
+ }
+
+ memset(result, 0, 32 * sizeof(long));
+ final = 0xff;
+ patha_ok = false;
+ is12simular = false;
+ is23simular = false;
+ is13simular = false;
+ for (i = 0; i < 3; i++) {
+ if (get_rf_type(rtlphy) == RF_2T2R)
+ _rtl88e_phy_iq_calibrate(hw, result, i, true);
+ else
+ _rtl88e_phy_iq_calibrate(hw, result, i, false);
+ if (i == 1) {
+ is12simular = sim_comp(hw, result, 0, 1);
+ if (is12simular) {
+ final = 0;
+ break;
+ }
+ }
+ if (i == 2) {
+ is13simular = sim_comp(hw, result, 0, 2);
+ if (is13simular) {
+ final = 0;
+ break;
+ }
+ is23simular = sim_comp(hw, result, 1, 2);
+ if (is23simular) {
+ final = 1;
+ } else {
+ for (i = 0; i < 8; i++)
+ reg_tmp += result[3][i];
+
+ if (reg_tmp != 0)
+ final = 3;
+ else
+ final = 0xFF;
+ }
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ reg_e94 = result[i][0];
+ reg_e9c = result[i][1];
+ reg_ea4 = result[i][2];
+ reg_eb4 = result[i][4];
+ reg_ebc = result[i][5];
+ }
+ if (final != 0xff) {
+ reg_e94 = result[final][0];
+ rtlphy->reg_e94 = reg_e94;
+ reg_e9c = result[final][1];
+ rtlphy->reg_e9c = reg_e9c;
+ reg_ea4 = result[final][2];
+ reg_eb4 = result[final][4];
+ rtlphy->reg_eb4 = reg_eb4;
+ reg_ebc = result[final][5];
+ rtlphy->reg_ebc = reg_ebc;
+ patha_ok = true;
+ } else {
+ rtlphy->reg_e94 = 0x100;
+ rtlphy->reg_eb4 = 0x100;
+ rtlphy->reg_ebc = 0x0;
+ rtlphy->reg_e9c = 0x0;
+ }
+ if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+ fill_iqk(hw, patha_ok, result, final, (reg_ea4 == 0));
+ if (final != 0xFF) {
+ for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
+ rtlphy->iqk_matrix[0].value[0][i] = result[final][i];
+ rtlphy->iqk_matrix[0].iqk_done = true;
+ }
+ save_adda_reg(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 9);
+}
+
+void rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = &(rtlpriv->rtlhal);
+ bool start_conttx = false, singletone = false;
+ u32 timeout = 2000, timecount = 0;
+
+ if (start_conttx || singletone)
+ return;
+
+ while (rtlpriv->mac80211.act_scanning && timecount < timeout) {
+ udelay(50);
+ timecount += 50;
+ }
+
+ rtlphy->lck_inprogress = true;
+ RTPRINT(rtlpriv, FINIT, INIT_IQK,
+ "LCK:Start!!! currentband %x delay %d ms\n",
+ rtlhal->current_bandtype, timecount);
+
+ _rtl88e_phy_lc_calibrate(hw, false);
+
+ rtlphy->lck_inprogress = false;
+}
+
+void rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+ rfpath_switch(hw, bmain, false);
+}
+
+bool rtl88e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool postprocessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+ iotype, rtlphy->set_io_inprogress);
+ do {
+ switch (iotype) {
+ case IO_CMD_RESUME_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Resume DM after scan.\n");
+ postprocessing = true;
+ break;
+ case IO_CMD_PAUSE_DM_BY_SCAN:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+ "[IO CMD] Pause DM before scan.\n");
+ postprocessing = true;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ break;
+ }
+ } while (false);
+ if (postprocessing && !rtlphy->set_io_inprogress) {
+ rtlphy->set_io_inprogress = true;
+ rtlphy->current_io_type = iotype;
+ } else {
+ return false;
+ }
+ rtl88e_phy_set_io(hw);
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "IO Type(%#x)\n", iotype);
+ return true;
+}
+
+static void rtl88ee_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ /*rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);*/
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl88ee_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int jj = RF90_PATH_A;
+
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, jj, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl88ee_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl8192_tx_ring *ring = NULL;
+ bool bresult = true;
+ u8 i, queue_id;
+
+ switch (rfpwr_state) {
+ case ERFON:{
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ bool rtstatus;
+ u32 init = 0;
+ do {
+ init++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic enable\n");
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while ((rtstatus != true) && (init < 10));
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFON sleeped:%d ms\n",
+ jiffies_to_msecs(jiffies - ppsc->
+ last_sleep_jiffies));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl88ee_phy_set_rf_on(hw);
+ }
+ if (mac->link_state == MAC80211_LINKED)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_NO_LINK);
+ break; }
+ case ERFOFF:{
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "IPS Set eRf nic disable\n");
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ } else {
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ }
+ break; }
+ case ERFSLEEP:{
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue));
+
+ udelay(10);
+ i++;
+ }
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue));
+ break;
+ }
+ }
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ "Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl88ee_phy_set_rf_sleep(hw);
+ break; }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "switch case not processed\n");
+ bresult = false;
+ break;
+ }
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+ return bresult;
+}
+
+bool rtl88e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return false;
+ bresult = _rtl88ee_phy_set_rf_power_state(hw, rfpwr_state);
+ return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
new file mode 100644
index 000000000000..f1acd6d27e44
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_PHY_H__
+#define __RTL92C_PHY_H__
+
+/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/
+#define MAX_TX_COUNT 4
+
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+#define RT_CANNOT_IO(hw) false
+#define HIGHPOWER_RADIOA_ARRAYLEN 22
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_BB_REG_NUM 9
+#define MAX_TOLERANCE 5
+#define IQK_DELAY_TIME 10
+#define IDX_MAP 15
+
+#define APK_BB_REG_NUM 5
+#define APK_AFE_REG_NUM 16
+#define APK_CURVE_REG_NUM 4
+#define PATH_NUM 2
+
+#define LOOP_LIMIT 5
+#define MAX_STALL_TIME 50
+#define ANTENNADIVERSITYVALUE 0x80
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define RESET_CNT_LIMIT 3
+
+#define IQK_ADDA_REG_NUM 16
+#define IQK_MAC_REG_NUM 4
+
+#define RF6052_MAX_PATH 2
+
+#define CT_OFFSET_MAC_ADDR 0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX 0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX 0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF 0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF 0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF 0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET 0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET 0x72
+
+#define CT_OFFSET_CHANNEL_PLAH 0x75
+#define CT_OFFSET_THERMAL_METER 0x78
+#define CT_OFFSET_RF_OPTION 0x79
+#define CT_OFFSET_VERSION 0x7E
+#define CT_OFFSET_CUSTOMER_ID 0x7F
+
+#define RTL92C_MAX_PATH_NUM 2
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+enum hw90_block_e {
+ HW90_BLOCK_MAC = 0,
+ HW90_BLOCK_PHY0 = 1,
+ HW90_BLOCK_PHY1 = 2,
+ HW90_BLOCK_RF = 3,
+ HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+ BASEBAND_CONFIG_PHY_REG = 0,
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+ RA_OFFSET_LEGACY_OFDM1,
+ RA_OFFSET_LEGACY_OFDM2,
+ RA_OFFSET_HT_OFDM1,
+ RA_OFFSET_HT_OFDM2,
+ RA_OFFSET_HT_OFDM3,
+ RA_OFFSET_HT_OFDM4,
+ RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+ ANTENNA_NONE,
+ ANTENNA_D,
+ ANTENNA_C,
+ ANTENNA_CD,
+ ANTENNA_B,
+ ANTENNA_BD,
+ ANTENNA_BC,
+ ANTENNA_BCD,
+ ANTENNA_A,
+ ANTENNA_AD,
+ ANTENNA_AC,
+ ANTENNA_ACD,
+ ANTENNA_AB,
+ ANTENNA_ABD,
+ ANTENNA_ABC,
+ ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+ u32 r_tx_antenna:4;
+ u32 r_ant_l:4;
+ u32 r_ant_non_ht:4;
+ u32 r_ant_ht1:4;
+ u32 r_ant_ht2:4;
+ u32 r_ant_ht_s1:4;
+ u32 r_ant_non_ht_s1:4;
+ u32 ofdm_txsc:2;
+ u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+ u8 r_cckrx_enable_2:2;
+ u8 r_cckrx_enable:2;
+ u8 r_ccktx_enable:4;
+};
+
+
+struct efuse_contents {
+ u8 mac_addr[ETH_ALEN];
+ u8 cck_tx_power_idx[6];
+ u8 ht40_1s_tx_power_idx[6];
+ u8 ht40_2s_tx_power_idx_diff[3];
+ u8 ht20_tx_power_idx_diff[3];
+ u8 ofdm_tx_power_idx_diff[3];
+ u8 ht40_max_power_offset[3];
+ u8 ht20_max_power_offset[3];
+ u8 channel_plan;
+ u8 thermal_meter;
+ u8 rf_option[5];
+ u8 version;
+ u8 oem_id;
+ u8 regulatory;
+};
+
+struct tx_power_struct {
+ u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 legacy_ht_txpowerdiff;
+ u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+ u8 pwrgroup_cnt;
+ u32 mcs_original_offset[4][16];
+};
+
+enum _ANT_DIV_TYPE {
+ NO_ANTDIV = 0xFF,
+ CG_TRX_HW_ANTDIV = 0x01,
+ CGCS_RX_HW_ANTDIV = 0x02,
+ FIXED_HW_ANTDIV = 0x03,
+ CG_TRX_SMART_ANTDIV = 0x04,
+ CGCS_RX_SW_ANTDIV = 0x05,
+};
+
+extern u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask);
+extern void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask, u32 data);
+extern u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask);
+extern void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask, u32 data);
+extern bool rtl88e_phy_mac_config(struct ieee80211_hw *hw);
+extern bool rtl88e_phy_bb_config(struct ieee80211_hw *hw);
+extern bool rtl88e_phy_rf_config(struct ieee80211_hw *hw);
+extern void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+extern void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw,
+ long *powerlevel);
+extern void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+extern void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation);
+extern void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+extern void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+extern void rtl88e_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+extern u8 rtl88e_phy_sw_chnl(struct ieee80211_hw *hw);
+extern void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl88e_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl88e_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+ enum radio_path rfpath);
+bool rtl88e_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+extern bool rtl88e_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
new file mode 100644
index 000000000000..6dc4e3a954f6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.c
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+/* drivers should parse below arrays and do the corresponding actions */
+/*3 Power on Array*/
+struct wlan_pwr_cfg rtl8188e_power_on_flow[RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8188e_radio_off_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg rtl8188e_card_disable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_CARDDIS
+ RTL8188E_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8188e_card_enable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_CARDDIS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8188e_suspend_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_SUS
+ RTL8188E_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8188e_resume_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_SUS_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_ACT
+ RTL8188E_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8188e_hwpdn_flow[RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS
+ + RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ RTL8188E_TRANS_ACT_TO_CARDEMU
+ RTL8188E_TRANS_CARDEMU_TO_PDN
+ RTL8188E_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8188e_enter_lps_flow[RTL8188E_TRANS_ACT_TO_LPS_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8188E_TRANS_ACT_TO_LPS
+ RTL8188E_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8188e_leave_lps_flow[RTL8188E_TRANS_LPS_TO_ACT_STEPS
+ + RTL8188E_TRANS_END_STEPS] = {
+ /*FW behavior*/
+ RTL8188E_TRANS_LPS_TO_ACT
+ RTL8188E_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
new file mode 100644
index 000000000000..028ec6dd52b4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseq.h
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQ_H__
+#define __RTL8723E_PWRSEQ_H__
+
+#include "pwrseqcmd.h"
+/*
+ Check document WM-20110607-Paul-RTL8188E_Power_Architecture-R02.vsd
+ There are 6 HW Power States:
+ 0: POFF--Power Off
+ 1: PDN--Power Down
+ 2: CARDEMU--Card Emulation
+ 3: ACT--Active Mode
+ 4: LPS--Low Power State
+ 5: SUS--Suspend
+
+ The transision from different states are defined below
+ TRANS_CARDEMU_TO_ACT
+ TRANS_ACT_TO_CARDEMU
+ TRANS_CARDEMU_TO_SUS
+ TRANS_SUS_TO_CARDEMU
+ TRANS_CARDEMU_TO_PDN
+ TRANS_ACT_TO_LPS
+ TRANS_LPS_TO_ACT
+
+ TRANS_END
+ PWR SEQ Version: rtl8188e_PwrSeq_V09.h
+*/
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS 10
+#define RTL8188E_TRANS_SUS_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS 10
+#define RTL8188E_TRANS_PDN_TO_CARDEMU_STEPS 10
+#define RTL8188E_TRANS_ACT_TO_LPS_STEPS 15
+#define RTL8188E_TRANS_LPS_TO_ACT_STEPS 15
+#define RTL8188E_TRANS_END_STEPS 1
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* wait till 0x04[17] = 1 power ready*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* 0x02[1:0] = 0 reset BB*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0)|BIT(1), 0}, \
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x24[23] = 2b'01 schmit trigger */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /* 0x04[15] = 0 disable HWPDN (control by DRV)*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[12:11] = 2b'00 disable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), 0}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[8] = 1 polling until return 0*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*wait till 0x04[8] = 0*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}, \
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*LDO normal mode*/\
+ {0x0074, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*SDIO Driving*/\
+
+#define RTL8188E_TRANS_ACT_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/\
+ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*LDO Sleep mode*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[9] = 1 turn off MAC by HW state machine*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, \
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_SUS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ /*0x04[12:11] = 2b'11enable WL suspend for PCIe*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},\
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, BIT(7)}, \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Set USB suspend enable local register 0xfe10[4]= 1 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*wait power state to suspend*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0},
+
+#define RTL8188E_TRANS_SUS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*wait power state to suspend*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},
+
+#define RTL8188E_TRANS_CARDEMU_TO_CARDDIS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*0x24[23] = 2b'01 schmit trigger */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}, \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*0x04[12:11] = 2b'01 enable WL suspend*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /* 0x04[31:30] = 2b'10 enable enable bandgap mbias in suspend */\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, \
+ {0x0041, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \
+ PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, \
+ /*Clear SIC_EN register 0x40[12] = 1'b0 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0xfe10, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ /*Set USB suspend enable local register 0xfe10[4]= 1 */ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ /*Set SDIO suspend local register*/ \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+
+#define RTL8188E_TRANS_CARDDIS_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO,\
+ PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ \
+ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO,\
+ PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, \
+ PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \
+ /*0x04[12:11] = 2b'01enable WL suspend*/
+
+
+#define RTL8188E_TRANS_CARDEMU_TO_PDN \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/ \
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
+
+
+#define RTL8188E_TRANS_PDN_TO_CARDEMU \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
+
+
+#define RTL8188E_TRANS_ACT_TO_LPS \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},/*Tx Pause*/ \
+ {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*zero if no pkt is tx*/\
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Should be zero if no packet is transmitting*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*CCK and OFDM are disabled, and clock are gated*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/\
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},/*Reset MAC TRX*/ \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*check if removed later*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0}, \
+ {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Respond TxOK to scheduler*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, \
+
+
+#define RTL8188E_TRANS_LPS_TO_ACT \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+ {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \
+ PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/ \
+ {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/ \
+ {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/ \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/ \
+ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x08[4] = 0 switch TSF to 40M*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \
+ {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*Polling 0x109[7]= 0 TSF in 40M*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, \
+ {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x29[7:6] = 2b'00 enable BB clock*/ \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0}, \
+ {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x101[1] = 1*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, \
+ {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x100[7:0] = 0xFF enable WMAC TRX*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, \
+ {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \
+ /*. 0x02[1:0] = 2b'11 enable BB macro*/\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0), BIT(1)|BIT(0)}, \
+ {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*. 0x522 = 0*/
+
+
+#define RTL8188E_TRANS_END \
+ /* format */ \
+ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },*/\
+ {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
+ 0, PWR_CMD_END, 0, 0}
+
+extern struct wlan_pwr_cfg rtl8188e_power_on_flow
+ [RTL8188E_TRANS_CARDEMU_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_radio_off_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_card_disable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_card_enable_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_suspend_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_resume_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_SUS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_hwpdn_flow
+ [RTL8188E_TRANS_ACT_TO_CARDEMU_STEPS +
+ RTL8188E_TRANS_CARDEMU_TO_PDN_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_enter_lps_flow
+ [RTL8188E_TRANS_ACT_TO_LPS_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8188e_leave_lps_flow
+ [RTL8188E_TRANS_LPS_TO_ACT_STEPS +
+ RTL8188E_TRANS_END_STEPS];
+
+/* RTL8723 Power Configuration CMDs for PCIe interface */
+#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188e_power_on_flow
+#define Rtl8188E_NIC_RF_OFF_FLOW rtl8188e_radio_off_flow
+#define Rtl8188E_NIC_DISABLE_FLOW rtl8188e_card_disable_flow
+#define Rtl8188E_NIC_ENABLE_FLOW rtl8188e_card_enable_flow
+#define Rtl8188E_NIC_SUSPEND_FLOW rtl8188e_suspend_flow
+#define Rtl8188E_NIC_RESUME_FLOW rtl8188e_resume_flow
+#define Rtl8188E_NIC_PDN_FLOW rtl8188e_hwpdn_flow
+#define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188e_enter_lps_flow
+#define Rtl8188E_NIC_LPS_LEAVE_FLOW rtl8188e_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
new file mode 100644
index 000000000000..a9cfa13be3a8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+
+/* Description:
+ * This routine deal with the Power Configuration CMDs
+ * parsing for RTL8723/RTL8188E Series IC.
+ * Assumption:
+ * We should follow specific format which was released from HW SD.
+ *
+ * 2011.07.07, added by Roger.
+ */
+
+bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[])
+{
+ struct wlan_pwr_cfg cmd = {0};
+ bool polling_bit = false;
+ u32 ary_idx = 0;
+ u8 val = 0;
+ u32 offset = 0;
+ u32 polling_count = 0;
+ u32 max_polling_cnt = 5000;
+
+ do {
+ cmd = pwrcfgcmd[ary_idx];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): offset(%#x), cut_msk(%#x), fab_msk(%#x),"
+ "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), val(%#x)\n",
+ GET_PWR_CFG_OFFSET(cmd),
+ GET_PWR_CFG_CUT_MASK(cmd),
+ GET_PWR_CFG_FAB_MASK(cmd),
+ GET_PWR_CFG_INTF_MASK(cmd),
+ GET_PWR_CFG_BASE(cmd),
+ GET_PWR_CFG_CMD(cmd),
+ GET_PWR_CFG_MASK(cmd),
+ GET_PWR_CFG_VALUE(cmd));
+
+ if ((GET_PWR_CFG_FAB_MASK(cmd) & fab_version) &&
+ (GET_PWR_CFG_CUT_MASK(cmd) & cut_version) &&
+ (GET_PWR_CFG_INTF_MASK(cmd) & interface_type)) {
+ switch (GET_PWR_CFG_CMD(cmd)) {
+ case PWR_CMD_READ:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+ break;
+ case PWR_CMD_WRITE: {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+ offset = GET_PWR_CFG_OFFSET(cmd);
+
+ /*Read the val from system register*/
+ val = rtl_read_byte(rtlpriv, offset);
+ val &= (~(GET_PWR_CFG_MASK(cmd)));
+ val |= (GET_PWR_CFG_VALUE(cmd) &
+ GET_PWR_CFG_MASK(cmd));
+
+ /*Write the val back to sytem register*/
+ rtl_write_byte(rtlpriv, offset, val);
+ }
+ break;
+ case PWR_CMD_POLLING:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+ polling_bit = false;
+ offset = GET_PWR_CFG_OFFSET(cmd);
+
+ do {
+ val = rtl_read_byte(rtlpriv, offset);
+
+ val = val & GET_PWR_CFG_MASK(cmd);
+ if (val == (GET_PWR_CFG_VALUE(cmd) &
+ GET_PWR_CFG_MASK(cmd)))
+ polling_bit = true;
+ else
+ udelay(10);
+
+ if (polling_count++ > max_polling_cnt) {
+ RT_TRACE(rtlpriv, COMP_INIT,
+ DBG_LOUD,
+ "polling fail in pwrseqcmd\n");
+ return false;
+ }
+ } while (!polling_bit);
+
+ break;
+ case PWR_CMD_DELAY:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+ if (GET_PWR_CFG_VALUE(cmd) == PWRSEQ_DELAY_US)
+ udelay(GET_PWR_CFG_OFFSET(cmd));
+ else
+ mdelay(GET_PWR_CFG_OFFSET(cmd));
+ break;
+ case PWR_CMD_END:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "rtl88_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+ return true;
+ break;
+ default:
+ RT_ASSERT(false,
+ "rtl88_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+ break;
+ }
+ }
+
+ ary_idx++;
+ } while (1);
+
+ return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
new file mode 100644
index 000000000000..d9ae280bb1a2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/pwrseqcmd.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQCMD_H__
+#define __RTL8723E_PWRSEQCMD_H__
+
+#include "../wifi.h"
+/*---------------------------------------------*/
+/* The value of cmd: 4 bits */
+/*---------------------------------------------*/
+#define PWR_CMD_READ 0x00
+#define PWR_CMD_WRITE 0x01
+#define PWR_CMD_POLLING 0x02
+#define PWR_CMD_DELAY 0x03
+#define PWR_CMD_END 0x04
+
+/* define the base address of each block */
+#define PWR_BASEADDR_MAC 0x00
+#define PWR_BASEADDR_USB 0x01
+#define PWR_BASEADDR_PCIE 0x02
+#define PWR_BASEADDR_SDIO 0x03
+
+#define PWR_INTF_SDIO_MSK BIT(0)
+#define PWR_INTF_USB_MSK BIT(1)
+#define PWR_INTF_PCI_MSK BIT(2)
+#define PWR_INTF_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define PWR_FAB_TSMC_MSK BIT(0)
+#define PWR_FAB_UMC_MSK BIT(1)
+#define PWR_FAB_ALL_MSK (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define PWR_CUT_TESTCHIP_MSK BIT(0)
+#define PWR_CUT_A_MSK BIT(1)
+#define PWR_CUT_B_MSK BIT(2)
+#define PWR_CUT_C_MSK BIT(3)
+#define PWR_CUT_D_MSK BIT(4)
+#define PWR_CUT_E_MSK BIT(5)
+#define PWR_CUT_F_MSK BIT(6)
+#define PWR_CUT_G_MSK BIT(7)
+#define PWR_CUT_ALL_MSK 0xFF
+
+enum pwrseq_delay_unit {
+ PWRSEQ_DELAY_US,
+ PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+ u16 offset;
+ u8 cut_msk;
+ u8 fab_msk:4;
+ u8 interface_msk:4;
+ u8 base:4;
+ u8 cmd:4;
+ u8 msk;
+ u8 value;
+};
+
+#define GET_PWR_CFG_OFFSET(__PWR) (__PWR.offset)
+#define GET_PWR_CFG_CUT_MASK(__PWR) (__PWR.cut_msk)
+#define GET_PWR_CFG_FAB_MASK(__PWR) (__PWR.fab_msk)
+#define GET_PWR_CFG_INTF_MASK(__PWR) (__PWR.interface_msk)
+#define GET_PWR_CFG_BASE(__PWR) (__PWR.base)
+#define GET_PWR_CFG_CMD(__PWR) (__PWR.cmd)
+#define GET_PWR_CFG_MASK(__PWR) (__PWR.msk)
+#define GET_PWR_CFG_VALUE(__PWR) (__PWR.value)
+
+bool rtl88_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+ u8 fab_version, u8 interface_type,
+ struct wlan_pwr_cfg pwrcfgcmd[]);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
new file mode 100644
index 000000000000..d849abf7d94a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/reg.h
@@ -0,0 +1,2258 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_REG_H__
+#define __RTL92C_REG_H__
+
+#define TXPKT_BUF_SELECT 0x69
+#define RXPKT_BUF_SELECT 0xA5
+#define DISABLE_TRXPKT_BUF_ACCESS 0x0
+
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define REG_APS_FSMCO 0x0004
+#define REG_SYS_CLKR 0x0008
+#define REG_9346CR 0x000A
+#define REG_EE_VPD 0x000C
+#define REG_AFE_MISC 0x0010
+#define REG_SPS0_CTRL 0x0011
+#define REG_SPS_OCP_CFG 0x0018
+#define REG_RSV_CTRL 0x001C
+#define REG_RF_CTRL 0x001F
+#define REG_LDOA15_CTRL 0x0020
+#define REG_LDOV12D_CTRL 0x0021
+#define REG_LDOHCI12_CTRL 0x0022
+#define REG_LPLDO_CTRL 0x0023
+#define REG_AFE_XTAL_CTRL 0x0024
+#define REG_AFE_LDO_CTRL 0x0027 /* 1.5v for 8188EE test
+ * chip, 1.4v for MP chip
+ */
+#define REG_AFE_PLL_CTRL 0x0028
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define REG_PWR_DATA 0x0038
+#define REG_CAL_TIMER 0x003C
+#define REG_ACLK_MON 0x003E
+#define REG_GPIO_MUXCFG 0x0040
+#define REG_GPIO_IO_SEL 0x0042
+#define REG_MAC_PINMUX_CFG 0x0043
+#define REG_GPIO_PIN_CTRL 0x0044
+#define REG_GPIO_INTM 0x0048
+#define REG_LEDCFG0 0x004C
+#define REG_LEDCFG1 0x004D
+#define REG_LEDCFG2 0x004E
+#define REG_LEDCFG3 0x004F
+#define REG_FSIMR 0x0050
+#define REG_FSISR 0x0054
+#define REG_HSIMR 0x0058
+#define REG_HSISR 0x005c
+#define REG_GPIO_PIN_CTRL_2 0x0060
+#define REG_GPIO_IO_SEL_2 0x0062
+#define REG_GPIO_OUTPUT 0x006c
+#define REG_AFE_XTAL_CTRL_EXT 0x0078
+#define REG_XCK_OUT_CTRL 0x007c
+#define REG_MCUFWDL 0x0080
+#define REG_WOL_EVENT 0x0081
+#define REG_MCUTSTCFG 0x0084
+
+
+#define REG_HIMR 0x00B0
+#define REG_HISR 0x00B4
+#define REG_HIMRE 0x00B8
+#define REG_HISRE 0x00BC
+
+#define REG_EFUSE_ACCESS 0x00CF
+
+#define REG_BIST_SCAN 0x00D0
+#define REG_BIST_RPT 0x00D4
+#define REG_BIST_ROM_RPT 0x00D8
+#define REG_USB_SIE_INTF 0x00E0
+#define REG_PCIE_MIO_INTF 0x00E4
+#define REG_PCIE_MIO_INTD 0x00E8
+#define REG_HPON_FSM 0x00EC
+#define REG_SYS_CFG 0x00F0
+
+#define REG_CR 0x0100
+#define REG_PBP 0x0104
+#define REG_PKT_BUFF_ACCESS_CTRL 0x0106
+#define REG_TRXDMA_CTRL 0x010C
+#define REG_TRXFF_BNDY 0x0114
+#define REG_TRXFF_STATUS 0x0118
+#define REG_RXFF_PTR 0x011C
+
+#define REG_CPWM 0x012F
+#define REG_FWIMR 0x0130
+#define REG_FWISR 0x0134
+#define REG_PKTBUF_DBG_CTRL 0x0140
+#define REG_PKTBUF_DBG_DATA_L 0x0144
+#define REG_PKTBUF_DBG_DATA_H 0x0148
+#define REG_RXPKTBUF_CTRL (REG_PKTBUF_DBG_CTRL+2)
+
+#define REG_TC0_CTRL 0x0150
+#define REG_TC1_CTRL 0x0154
+#define REG_TC2_CTRL 0x0158
+#define REG_TC3_CTRL 0x015C
+#define REG_TC4_CTRL 0x0160
+#define REG_TCUNIT_BASE 0x0164
+#define REG_MBIST_START 0x0174
+#define REG_MBIST_DONE 0x0178
+#define REG_MBIST_FAIL 0x017C
+#define REG_32K_CTRL 0x0194
+#define REG_C2HEVT_MSG_NORMAL 0x01A0
+#define REG_C2HEVT_CLEAR 0x01AF
+#define REG_C2HEVT_MSG_TEST 0x01B8
+#define REG_MCUTST_1 0x01c0
+#define REG_FMETHR 0x01C8
+#define REG_HMETFR 0x01CC
+#define REG_HMEBOX_0 0x01D0
+#define REG_HMEBOX_1 0x01D4
+#define REG_HMEBOX_2 0x01D8
+#define REG_HMEBOX_3 0x01DC
+
+#define REG_LLT_INIT 0x01E0
+#define REG_BB_ACCEESS_CTRL 0x01E8
+#define REG_BB_ACCESS_DATA 0x01EC
+
+#define REG_HMEBOX_EXT_0 0x01F0
+#define REG_HMEBOX_EXT_1 0x01F4
+#define REG_HMEBOX_EXT_2 0x01F8
+#define REG_HMEBOX_EXT_3 0x01FC
+
+#define REG_RQPN 0x0200
+#define REG_FIFOPAGE 0x0204
+#define REG_TDECTRL 0x0208
+#define REG_TXDMA_OFFSET_CHK 0x020C
+#define REG_TXDMA_STATUS 0x0210
+#define REG_RQPN_NPQ 0x0214
+
+#define REG_RXDMA_AGG_PG_TH 0x0280
+#define REG_FW_UPD_RDPTR 0x0284 /* FW shall update this
+ * register before FW * write
+ * RXPKT_RELEASE_POLL to 1
+ */
+#define REG_RXDMA_CONTROL 0x0286 /* Control the RX DMA.*/
+#define REG_RXPKT_NUM 0x0287 /* The number of packets
+ * in RXPKTBUF.
+ */
+#define REG_PCIE_CTRL_REG 0x0300
+#define REG_INT_MIG 0x0304
+#define REG_BCNQ_DESA 0x0308
+#define REG_HQ_DESA 0x0310
+#define REG_MGQ_DESA 0x0318
+#define REG_VOQ_DESA 0x0320
+#define REG_VIQ_DESA 0x0328
+#define REG_BEQ_DESA 0x0330
+#define REG_BKQ_DESA 0x0338
+#define REG_RX_DESA 0x0340
+
+#define REG_DBI 0x0348
+#define REG_MDIO 0x0354
+#define REG_DBG_SEL 0x0360
+#define REG_PCIE_HRPWM 0x0361
+#define REG_PCIE_HCPWM 0x0363
+#define REG_UART_CTRL 0x0364
+#define REG_WATCH_DOG 0x0368
+#define REG_UART_TX_DESA 0x0370
+#define REG_UART_RX_DESA 0x0378
+
+
+#define REG_HDAQ_DESA_NODEF 0x0000
+#define REG_CMDQ_DESA_NODEF 0x0000
+
+#define REG_VOQ_INFORMATION 0x0400
+#define REG_VIQ_INFORMATION 0x0404
+#define REG_BEQ_INFORMATION 0x0408
+#define REG_BKQ_INFORMATION 0x040C
+#define REG_MGQ_INFORMATION 0x0410
+#define REG_HGQ_INFORMATION 0x0414
+#define REG_BCNQ_INFORMATION 0x0418
+#define REG_TXPKT_EMPTY 0x041A
+
+
+#define REG_CPU_MGQ_INFORMATION 0x041C
+#define REG_FWHW_TXQ_CTRL 0x0420
+#define REG_HWSEQ_CTRL 0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY 0x0425
+#define REG_MULTI_BCNQ_EN 0x0426
+#define REG_MULTI_BCNQ_OFFSET 0x0427
+#define REG_SPEC_SIFS 0x0428
+#define REG_RL 0x042A
+#define REG_DARFRC 0x0430
+#define REG_RARFRC 0x0438
+#define REG_RRSR 0x0440
+#define REG_ARFR0 0x0444
+#define REG_ARFR1 0x0448
+#define REG_ARFR2 0x044C
+#define REG_ARFR3 0x0450
+#define REG_AGGLEN_LMT 0x0458
+#define REG_AMPDU_MIN_SPACE 0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD 0x045D
+#define REG_FAST_EDCA_CTRL 0x0460
+#define REG_RD_RESP_PKT_TH 0x0463
+#define REG_INIRTS_RATE_SEL 0x0480
+#define REG_INIDATA_RATE_SEL 0x0484
+#define REG_POWER_STATUS 0x04A4
+#define REG_POWER_STAGE1 0x04B4
+#define REG_POWER_STAGE2 0x04B8
+#define REG_PKT_LIFE_TIME 0x04C0
+#define REG_STBC_SETTING 0x04C4
+#define REG_PROT_MODE_CTRL 0x04C8
+#define REG_BAR_MODE_CTRL 0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT 0x04CF
+#define REG_EARLY_MODE_CONTROL 0x04D0
+#define REG_NQOS_SEQ 0x04DC
+#define REG_QOS_SEQ 0x04DE
+#define REG_NEED_CPU_HANDLE 0x04E0
+#define REG_PKT_LOSE_RPT 0x04E1
+#define REG_PTCL_ERR_STATUS 0x04E2
+#define REG_TX_RPT_CTRL 0x04EC
+#define REG_TX_RPT_TIME 0x04F0
+#define REG_DUMMY 0x04FC
+
+#define REG_EDCA_VO_PARAM 0x0500
+#define REG_EDCA_VI_PARAM 0x0504
+#define REG_EDCA_BE_PARAM 0x0508
+#define REG_EDCA_BK_PARAM 0x050C
+#define REG_BCNTCFG 0x0510
+#define REG_PIFS 0x0512
+#define REG_RDG_PIFS 0x0513
+#define REG_SIFS_CTX 0x0514
+#define REG_SIFS_TRX 0x0516
+#define REG_AGGR_BREAK_TIME 0x051A
+#define REG_SLOT 0x051B
+#define REG_TX_PTCL_CTRL 0x0520
+#define REG_TXPAUSE 0x0522
+#define REG_DIS_TXREQ_CLR 0x0523
+#define REG_RD_CTRL 0x0524
+#define REG_TBTT_PROHIBIT 0x0540
+#define REG_RD_NAV_NXT 0x0544
+#define REG_NAV_PROT_LEN 0x0546
+#define REG_BCN_CTRL 0x0550
+#define REG_USTIME_TSF 0x0551
+#define REG_MBID_NUM 0x0552
+#define REG_DUAL_TSF_RST 0x0553
+#define REG_BCN_INTERVAL 0x0554
+#define REG_MBSSID_BCN_SPACE 0x0554
+#define REG_DRVERLYINT 0x0558
+#define REG_BCNDMATIM 0x0559
+#define REG_ATIMWND 0x055A
+#define REG_BCN_MAX_ERR 0x055D
+#define REG_RXTSF_OFFSET_CCK 0x055E
+#define REG_RXTSF_OFFSET_OFDM 0x055F
+#define REG_TSFTR 0x0560
+#define REG_INIT_TSFTR 0x0564
+#define REG_PSTIMER 0x0580
+#define REG_TIMER0 0x0584
+#define REG_TIMER1 0x0588
+#define REG_ACMHWCTRL 0x05C0
+#define REG_ACMRSTCTRL 0x05C1
+#define REG_ACMAVG 0x05C2
+#define REG_VO_ADMTIME 0x05C4
+#define REG_VI_ADMTIME 0x05C6
+#define REG_BE_ADMTIME 0x05C8
+#define REG_EDCA_RANDOM_GEN 0x05CC
+#define REG_SCH_TXCMD 0x05D0
+
+#define REG_APSD_CTRL 0x0600
+#define REG_BWOPMODE 0x0603
+#define REG_TCR 0x0604
+#define REG_RCR 0x0608
+#define REG_RX_PKT_LIMIT 0x060C
+#define REG_RX_DLK_TIME 0x060D
+#define REG_RX_DRVINFO_SZ 0x060F
+
+#define REG_MACID 0x0610
+#define REG_BSSID 0x0618
+#define REG_MAR 0x0620
+#define REG_MBIDCAMCFG 0x0628
+
+#define REG_USTIME_EDCA 0x0638
+#define REG_MAC_SPEC_SIFS 0x063A
+#define REG_RESP_SIFS_CCK 0x063C
+#define REG_RESP_SIFS_OFDM 0x063E
+#define REG_ACKTO 0x0640
+#define REG_CTS2TO 0x0641
+#define REG_EIFS 0x0642
+
+#define REG_NAV_CTRL 0x0650
+#define REG_BACAMCMD 0x0654
+#define REG_BACAMCONTENT 0x0658
+#define REG_LBDLY 0x0660
+#define REG_FWDLY 0x0661
+#define REG_RXERR_RPT 0x0664
+#define REG_TRXPTCL_CTL 0x0668
+
+#define REG_CAMCMD 0x0670
+#define REG_CAMWRITE 0x0674
+#define REG_CAMREAD 0x0678
+#define REG_CAMDBG 0x067C
+#define REG_SECCFG 0x0680
+
+#define REG_WOW_CTRL 0x0690
+#define REG_PSSTATUS 0x0691
+#define REG_PS_RX_INFO 0x0692
+#define REG_UAPSD_TID 0x0693
+#define REG_LPNAV_CTRL 0x0694
+#define REG_WKFMCAM_NUM 0x0698
+#define REG_WKFMCAM_RWD 0x069C
+#define REG_RXFLTMAP0 0x06A0
+#define REG_RXFLTMAP1 0x06A2
+#define REG_RXFLTMAP2 0x06A4
+#define REG_BCN_PSR_RPT 0x06A8
+#define REG_CALB32K_CTRL 0x06AC
+#define REG_PKT_MON_CTRL 0x06B4
+#define REG_BT_COEX_TABLE 0x06C0
+#define REG_WMAC_RESP_TXINFO 0x06D8
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_TEST_USB_TXQS 0xFE48
+#define REG_TEST_SIE_VID 0xFE60
+#define REG_TEST_SIE_PID 0xFE62
+#define REG_TEST_SIE_OPTIONAL 0xFE64
+#define REG_TEST_SIE_CHIRP_K 0xFE65
+#define REG_TEST_SIE_PHY 0xFE66
+#define REG_TEST_SIE_MAC_ADDR 0xFE70
+#define REG_TEST_SIE_STRING 0xFE80
+
+#define REG_NORMAL_SIE_VID 0xFE60
+#define REG_NORMAL_SIE_PID 0xFE62
+#define REG_NORMAL_SIE_OPTIONAL 0xFE64
+#define REG_NORMAL_SIE_EP 0xFE65
+#define REG_NORMAL_SIE_PHY 0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR 0xFE70
+#define REG_NORMAL_SIE_STRING 0xFE80
+
+#define CR9346 REG_9346CR
+#define MSR (REG_CR + 2)
+#define ISR REG_HISR
+#define TSFR REG_TSFTR
+
+#define MACIDR0 REG_MACID
+#define MACIDR4 (REG_MACID + 4)
+
+#define PBP REG_PBP
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+#define UNUSED_REGISTER 0x1BF
+#define DCAM UNUSED_REGISTER
+#define PSR UNUSED_REGISTER
+#define BBADDR UNUSED_REGISTER
+#define PHYDATAR UNUSED_REGISTER
+
+#define INVALID_BBRF_VALUE 0x12345678
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define CMDEEPROM_EN BIT(5)
+#define CMDEEPROM_SEL BIT(4)
+#define CMD9346CR_9356SEL BIT(4)
+#define AUTOLOAD_EEPROM (CMDEEPROM_EN|CMDEEPROM_SEL)
+#define AUTOLOAD_EFUSE CMDEEPROM_EN
+
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_ENBT BIT(5)
+
+#define GPIO_IN REG_GPIO_PIN_CTRL
+#define GPIO_OUT (REG_GPIO_PIN_CTRL+1)
+#define GPIO_IO_SEL (REG_GPIO_PIN_CTRL+2)
+#define GPIO_MOD (REG_GPIO_PIN_CTRL+3)
+
+/* 8723/8188E Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define HSIMR_GPIO12_0_INT_EN BIT(0)
+#define HSIMR_SPS_OCP_INT_EN BIT(5)
+#define HSIMR_RON_INT_EN BIT(6)
+#define HSIMR_PDN_INT_EN BIT(7)
+#define HSIMR_GPIO9_INT_EN BIT(25)
+
+
+/* 8723/8188E Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define HSISR_GPIO12_0_INT BIT(0)
+#define HSISR_SPS_OCP_INT BIT(5)
+#define HSISR_RON_INT_EN BIT(6)
+#define HSISR_PDNINT BIT(7)
+#define HSISR_GPIO9_INT BIT(25)
+
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_ACKSHORTPMB BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+#define RATE_1M BIT(0)
+#define RATE_2M BIT(1)
+#define RATE_5_5M BIT(2)
+#define RATE_11M BIT(3)
+#define RATE_6M BIT(4)
+#define RATE_9M BIT(5)
+#define RATE_12M BIT(6)
+#define RATE_18M BIT(7)
+#define RATE_24M BIT(8)
+#define RATE_36M BIT(9)
+#define RATE_48M BIT(10)
+#define RATE_54M BIT(11)
+#define RATE_MCS0 BIT(12)
+#define RATE_MCS1 BIT(13)
+#define RATE_MCS2 BIT(14)
+#define RATE_MCS3 BIT(15)
+#define RATE_MCS4 BIT(16)
+#define RATE_MCS5 BIT(17)
+#define RATE_MCS6 BIT(18)
+#define RATE_MCS7 BIT(19)
+#define RATE_MCS8 BIT(20)
+#define RATE_MCS9 BIT(21)
+#define RATE_MCS10 BIT(22)
+#define RATE_MCS11 BIT(23)
+#define RATE_MCS12 BIT(24)
+#define RATE_MCS13 BIT(25)
+#define RATE_MCS14 BIT(26)
+#define RATE_MCS15 BIT(27)
+
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | RATR_12M | RATR_18M | \
+ RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | \
+ RATR_MCS3 | RATR_MCS4 | RATR_MCS5 | \
+ RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | \
+ RATR_MCS11 | RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define SCR_USEDK 0x01
+#define SCR_TXSEC_ENABLE 0x02
+#define SCR_RXSEC_ENABLE 0x04
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+/*********************************************
+* 8188 IMR/ISR bits
+**********************************************/
+#define IMR_DISABLED 0x0
+/* IMR DW0(0x0060-0063) Bit 0-31 */
+#define IMR_TXCCK BIT(30) /* TXRPT interrupt when CCX bit of
+ * the packet is set
+ */
+#define IMR_PSTIMEOUT BIT(29) /* Power Save Time Out Interrupt */
+#define IMR_GTINT4 BIT(28) /* When GTIMER4 expires,
+ * this bit is set to 1
+ */
+#define IMR_GTINT3 BIT(27) /* When GTIMER3 expires,
+ * this bit is set to 1
+ */
+#define IMR_TBDER BIT(26) /* Transmit Beacon0 Error */
+#define IMR_TBDOK BIT(25) /* Transmit Beacon0 OK */
+#define IMR_TSF_BIT32_TOGGLE BIT(24) /* TSF Timer BIT32 toggle ind int */
+#define IMR_BCNDMAINT0 BIT(20) /* Beacon DMA Interrupt 0 */
+#define IMR_BCNDOK0 BIT(16) /* Beacon Queue DMA OK0 */
+#define IMR_HSISR_IND_ON_INT BIT(15) /* HSISR Indicator (HSIMR & HSISR is
+ * true, this bit is set to 1)
+ */
+#define IMR_BCNDMAINT_E BIT(14) /* Beacon DMA Int Extension for Win7 */
+#define IMR_ATIMEND BIT(12) /* CTWidnow End or ATIM Window End */
+#define IMR_HISR1_IND_INT BIT(11) /* HISR1 Indicator (HISR1 & HIMR1 is
+ * true, this bit is set to 1)
+ */
+#define IMR_C2HCMD BIT(10) /* CPU to Host Command INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM2 BIT(9) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_CPWM BIT(8) /* CPU power Mode exchange INT Status,
+ * Write 1 clear
+ */
+#define IMR_HIGHDOK BIT(7) /* High Queue DMA OK */
+#define IMR_MGNTDOK BIT(6) /* Management Queue DMA OK */
+#define IMR_BKDOK BIT(5) /* AC_BK DMA OK */
+#define IMR_BEDOK BIT(4) /* AC_BE DMA OK */
+#define IMR_VIDOK BIT(3) /* AC_VI DMA OK */
+#define IMR_VODOK BIT(2) /* AC_VO DMA OK */
+#define IMR_RDU BIT(1) /* Rx Descriptor Unavailable */
+#define IMR_ROK BIT(0) /* Receive DMA OK */
+
+/* IMR DW1(0x00B4-00B7) Bit 0-31 */
+#define IMR_BCNDMAINT7 BIT(27) /* Beacon DMA Interrupt 7 */
+#define IMR_BCNDMAINT6 BIT(26) /* Beacon DMA Interrupt 6 */
+#define IMR_BCNDMAINT5 BIT(25) /* Beacon DMA Interrupt 5 */
+#define IMR_BCNDMAINT4 BIT(24) /* Beacon DMA Interrupt 4 */
+#define IMR_BCNDMAINT3 BIT(23) /* Beacon DMA Interrupt 3 */
+#define IMR_BCNDMAINT2 BIT(22) /* Beacon DMA Interrupt 2 */
+#define IMR_BCNDMAINT1 BIT(21) /* Beacon DMA Interrupt 1 */
+#define IMR_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrup 7 */
+#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrup 6 */
+#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrup 5 */
+#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrup 4 */
+#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrup 3 */
+#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrup 2 */
+#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrup 1 */
+#define IMR_ATIMEND_E BIT(13) /* ATIM Window End Extension for Win7 */
+#define IMR_TXERR BIT(11) /* Tx Err Flag Int Status,
+ * write 1 clear.
+ */
+#define IMR_RXERR BIT(10) /* Rx Err Flag INT Status,
+ * Write 1 clear
+ */
+#define IMR_TXFOVW BIT(9) /* Transmit FIFO Overflow */
+#define IMR_RXFOVW BIT(8) /* Receive FIFO Overflow */
+
+
+#define HWSET_MAX_SIZE 512
+#define EFUSE_MAX_SECTION 64
+#define EFUSE_REAL_CONTENT_LEN 256
+#define EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header,
+ * dummy 7 bytes frome CP
+ * test and reserved 1byte.
+ */
+
+#define EEPROM_DEFAULT_TSSI 0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_BOARDTYPE 0x02
+#define EEPROM_DEFAULT_TXPOWER 0x1010
+#define EEPROM_DEFAULT_HT2T_TXPWR 0x10
+
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_THERMALMETER 0x18
+#define EEPROM_DEFAULT_ANTTXPOWERDIFF 0x0
+#define EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP 0x5
+#define EEPROM_DEFAULT_TXPOWERLEVEL 0x22
+#define EEPROM_DEFAULT_HT40_2SDIFF 0x0
+#define EEPROM_DEFAULT_HT20_DIFF 2
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET 0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET 0
+
+#define RF_OPTION1 0x79
+#define RF_OPTION2 0x7A
+#define RF_OPTION3 0x7B
+#define RF_OPTION4 0x7C
+
+#define EEPROM_DEFAULT_PID 0x1234
+#define EEPROM_DEFAULT_VID 0x5678
+#define EEPROM_DEFAULT_CUSTOMERID 0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID 0xCD
+#define EEPROM_DEFAULT_VERSION 0
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define EEPROM_CID_DEFAULT 0x0
+#define EEPROM_CID_TOSHIBA 0x4
+#define EEPROM_CID_CCX 0x10
+#define EEPROM_CID_QMI 0x0D
+#define EEPROM_CID_WHQL 0xFE
+
+#define RTL8188E_EEPROM_ID 0x8129
+
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+#define EEPROM_TXPOWERCCK 0x10
+#define EEPROM_TXPOWERHT40_1S 0x16
+#define EEPROM_TXPOWERHT20DIFF 0x1B
+#define EEPROM_TXPOWER_OFDMDIFF 0x1B
+
+#define EEPROM_TX_PWR_INX 0x10
+
+#define EEPROM_CHANNELPLAN 0xB8
+#define EEPROM_XTAL_88E 0xB9
+#define EEPROM_THERMAL_METER_88E 0xBA
+#define EEPROM_IQK_LCK_88E 0xBB
+
+#define EEPROM_RF_BOARD_OPTION_88E 0xC1
+#define EEPROM_RF_FEATURE_OPTION_88E 0xC2
+#define EEPROM_RF_BT_SETTING_88E 0xC3
+#define EEPROM_VERSION 0xC4
+#define EEPROM_CUSTOMER_ID 0xC5
+#define EEPROM_RF_ANTENNA_OPT_88E 0xC9
+
+#define EEPROM_MAC_ADDR 0xD0
+#define EEPROM_VID 0xD6
+#define EEPROM_DID 0xD8
+#define EEPROM_SVID 0xDA
+#define EEPROM_SMID 0xDC
+
+#define STOPBECON BIT(6)
+#define STOPHIGHT BIT(5)
+#define STOPMGT BIT(4)
+#define STOPVO BIT(3)
+#define STOPVI BIT(2)
+#define STOPBE BIT(1)
+#define STOPBK BIT(0)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_APP_MIC BIT(30)
+#define RCR_APP_ICV BIT(29)
+#define RCR_APP_PHYST_RXFF BIT(28)
+#define RCR_APP_BA_SSN BIT(27)
+#define RCR_ENMBID BIT(24)
+#define RCR_LSIGEN BIT(23)
+#define RCR_MFBEN BIT(22)
+#define RCR_HTC_LOC_CTRL BIT(14)
+#define RCR_AMF BIT(13)
+#define RCR_ACF BIT(12)
+#define RCR_ADF BIT(11)
+#define RCR_AICV BIT(9)
+#define RCR_ACRC32 BIT(8)
+#define RCR_CBSSID_BCN BIT(7)
+#define RCR_CBSSID_DATA BIT(6)
+#define RCR_CBSSID RCR_CBSSID_DATA
+#define RCR_APWRMGT BIT(5)
+#define RCR_ADD3 BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+#define RSV_CTRL 0x001C
+#define RD_CTRL 0x0524
+
+#define REG_USB_INFO 0xFE17
+#define REG_USB_SPECIAL_OPTION 0xFE55
+#define REG_USB_DMA_AGG_TO 0xFE5B
+#define REG_USB_AGG_TO 0xFE5C
+#define REG_USB_AGG_TH 0xFE5D
+
+#define REG_USB_VID 0xFE60
+#define REG_USB_PID 0xFE62
+#define REG_USB_OPTIONAL 0xFE64
+#define REG_USB_CHIRP_K 0xFE65
+#define REG_USB_PHY 0xFE66
+#define REG_USB_MAC_ADDR 0xFE70
+#define REG_USB_HRPWM 0xFE58
+#define REG_USB_HCPWM 0xFE57
+
+#define SW18_FPWM BIT(3)
+
+#define ISO_MD2PP BIT(0)
+#define ISO_UA2USB BIT(1)
+#define ISO_UD2CORE BIT(2)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PD2CORE BIT(4)
+#define ISO_IP2MAC BIT(5)
+#define ISO_DIOP BIT(6)
+#define ISO_DIOE BIT(7)
+#define ISO_EB2CORE BIT(8)
+#define ISO_DIOR BIT(9)
+
+#define PWC_EV25V BIT(14)
+#define PWC_EV12V BIT(15)
+
+#define FEN_BBRSTB BIT(0)
+#define FEN_BB_GLB_RSTN BIT(1)
+#define FEN_USBA BIT(2)
+#define FEN_UPLL BIT(3)
+#define FEN_USBD BIT(4)
+#define FEN_DIO_PCIE BIT(5)
+#define FEN_PCIEA BIT(6)
+#define FEN_PPLL BIT(7)
+#define FEN_PCIED BIT(8)
+#define FEN_DIOE BIT(9)
+#define FEN_CPUEN BIT(10)
+#define FEN_DCORE BIT(11)
+#define FEN_ELDR BIT(12)
+#define FEN_DIO_RF BIT(13)
+#define FEN_HWPDN BIT(14)
+#define FEN_MREGEN BIT(15)
+
+#define PFM_LDALL BIT(0)
+#define PFM_ALDN BIT(1)
+#define PFM_LDKP BIT(2)
+#define PFM_WOWL BIT(3)
+#define ENPDN BIT(4)
+#define PDN_PL BIT(5)
+#define APFM_ONMAC BIT(8)
+#define APFM_OFF BIT(9)
+#define APFM_RSM BIT(10)
+#define AFSM_HSUS BIT(11)
+#define AFSM_PCIE BIT(12)
+#define APDM_MAC BIT(13)
+#define APDM_HOST BIT(14)
+#define APDM_HPDN BIT(15)
+#define RDY_MACON BIT(16)
+#define SUS_HOST BIT(17)
+#define ROP_ALD BIT(20)
+#define ROP_PWR BIT(21)
+#define ROP_SPS BIT(22)
+#define SOP_MRST BIT(25)
+#define SOP_FUSE BIT(26)
+#define SOP_ABG BIT(27)
+#define SOP_AMB BIT(28)
+#define SOP_RCK BIT(29)
+#define SOP_A8M BIT(30)
+#define XOP_BTCK BIT(31)
+
+#define ANAD16V_EN BIT(0)
+#define ANA8M BIT(1)
+#define MACSLP BIT(4)
+#define LOADER_CLK_EN BIT(5)
+#define _80M_SSC_DIS BIT(7)
+#define _80M_SSC_EN_HO BIT(8)
+#define PHY_SSC_RSTB BIT(9)
+#define SEC_CLK_EN BIT(10)
+#define MAC_CLK_EN BIT(11)
+#define SYS_CLK_EN BIT(12)
+#define RING_CLK_EN BIT(13)
+
+#define BOOT_FROM_EEPROM BIT(4)
+#define EEPROM_EN BIT(5)
+
+#define AFE_BGEN BIT(0)
+#define AFE_MBEN BIT(1)
+#define MAC_ID_EN BIT(7)
+
+#define WLOCK_ALL BIT(0)
+#define WLOCK_00 BIT(1)
+#define WLOCK_04 BIT(2)
+#define WLOCK_08 BIT(3)
+#define WLOCK_40 BIT(4)
+#define R_DIS_PRST_0 BIT(5)
+#define R_DIS_PRST_1 BIT(6)
+#define LOCK_ALL_EN BIT(7)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+#define LDA15_STBY BIT(1)
+#define LDA15_OBUF BIT(2)
+#define LDA15_REG_VOS BIT(3)
+#define _LDA15_VOADJ(x) (((x) & 0x7) << 4)
+
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+#define LPLDO_HSM BIT(2)
+#define LPLDO_LSM_DIS BIT(3)
+#define _LDV12_VADJ(x) (((x) & 0xF) << 4)
+
+#define XTAL_EN BIT(0)
+#define XTAL_BSEL BIT(1)
+#define _XTAL_BOSC(x) (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x) (((x) & 0xF) << 4)
+#define XTAL_GATE_USB BIT(8)
+#define _XTAL_USB_DRV(x) (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE BIT(11)
+#define _XTAL_AFE_DRV(x) (((x) & 0x3) << 12)
+#define XTAL_RF_GATE BIT(14)
+#define _XTAL_RF_DRV(x) (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG BIT(17)
+#define _XTAL_DIG_DRV(x) (((x) & 0x3) << 18)
+#define XTAL_BT_GATE BIT(20)
+#define _XTAL_BT_DRV(x) (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x) (((x) & 0x7) << 23)
+
+#define CKDLY_AFE BIT(26)
+#define CKDLY_USB BIT(27)
+#define CKDLY_DIG BIT(28)
+#define CKDLY_BT BIT(29)
+
+#define APLL_EN BIT(0)
+#define APLL_320_EN BIT(1)
+#define APLL_FREF_SEL BIT(2)
+#define APLL_EDGE_SEL BIT(3)
+#define APLL_WDOGB BIT(4)
+#define APLL_LPFEN BIT(5)
+
+#define APLL_REF_CLK_13MHZ 0x1
+#define APLL_REF_CLK_19_2MHZ 0x2
+#define APLL_REF_CLK_20MHZ 0x3
+#define APLL_REF_CLK_25MHZ 0x4
+#define APLL_REF_CLK_26MHZ 0x5
+#define APLL_REF_CLK_38_4MHZ 0x6
+#define APLL_REF_CLK_40MHZ 0x7
+
+#define APLL_320EN BIT(14)
+#define APLL_80EN BIT(15)
+#define APLL_1MEN BIT(24)
+
+#define ALD_EN BIT(18)
+#define EF_PD BIT(19)
+#define EF_FLAG BIT(31)
+
+#define EF_TRPT BIT(7)
+#define LDOE25_EN BIT(31)
+
+#define RSM_EN BIT(0)
+#define TIMER_EN BIT(4)
+
+#define TRSW0EN BIT(2)
+#define TRSW1EN BIT(3)
+#define EROM_EN BIT(4)
+#define ENBT BIT(5)
+#define ENUART BIT(8)
+#define UART_910 BIT(9)
+#define ENPMAC BIT(10)
+#define SIC_SWRST BIT(11)
+#define ENSIC BIT(12)
+#define SIC_23 BIT(13)
+#define ENHDP BIT(14)
+#define SIC_LBK BIT(15)
+
+#define LED0PL BIT(4)
+#define LED1PL BIT(12)
+#define LED0DIS BIT(7)
+
+#define MCUFWDL_EN BIT(0)
+#define MCUFWDL_RDY BIT(1)
+#define FWDL_CHKSUM_RPT BIT(2)
+#define MACINI_RDY BIT(3)
+#define BBINI_RDY BIT(4)
+#define RFINI_RDY BIT(5)
+#define WINTINI_RDY BIT(6)
+#define CPRST BIT(23)
+
+#define XCLK_VLD BIT(0)
+#define ACLK_VLD BIT(1)
+#define UCLK_VLD BIT(2)
+#define PCLK_VLD BIT(3)
+#define PCIRSTB BIT(4)
+#define V15_VLD BIT(5)
+#define TRP_B15V_EN BIT(7)
+#define SIC_IDLE BIT(8)
+#define BD_MAC2 BIT(9)
+#define BD_MAC1 BIT(10)
+#define IC_MACPHY_MODE BIT(11)
+#define VENDOR_ID BIT(19)
+#define PAD_HWPD_IDN BIT(22)
+#define TRP_VAUX_EN BIT(23)
+#define TRP_BT_EN BIT(24)
+#define BD_PKG_SEL BIT(25)
+#define BD_HCI_SEL BIT(26)
+#define TYPE_ID BIT(27)
+
+#define CHIP_VER_RTL_MASK 0xF000
+#define CHIP_VER_RTL_SHIFT 12
+
+#define REG_LBMODE (REG_CR + 3)
+
+#define HCI_TXDMA_EN BIT(0)
+#define HCI_RXDMA_EN BIT(1)
+#define TXDMA_EN BIT(2)
+#define RXDMA_EN BIT(3)
+#define PROTOCOL_EN BIT(4)
+#define SCHEDULE_EN BIT(5)
+#define MACTXEN BIT(6)
+#define MACRXEN BIT(7)
+#define ENSWBCN BIT(8)
+#define ENSEC BIT(9)
+
+#define _NETTYPE(x) (((x) & 0x3) << 16)
+#define MASK_NETTYPE 0x30000
+#define NT_NO_LINK 0x0
+#define NT_LINK_AD_HOC 0x1
+#define NT_LINK_AP 0x2
+#define NT_AS_AP 0x3
+
+#define _LBMODE(x) (((x) & 0xF) << 24)
+#define MASK_LBMODE 0xF000000
+#define LOOPBACK_NORMAL 0x0
+#define LOOPBACK_IMMEDIATELY 0xB
+#define LOOPBACK_MAC_DELAY 0x3
+#define LOOPBACK_PHY 0x1
+#define LOOPBACK_DMA 0x7
+
+#define GET_RX_PAGE_SIZE(value) ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value) (((value) & 0xF0) >> 4)
+#define _PSRX_MASK 0xF
+#define _PSTX_MASK 0xF0
+#define _PSRX(x) (x)
+#define _PSTX(x) ((x) << 4)
+
+#define PBP_64 0x0
+#define PBP_128 0x1
+#define PBP_256 0x2
+#define PBP_512 0x3
+#define PBP_1024 0x4
+
+#define RXDMA_ARBBW_EN BIT(0)
+#define RXSHFT_EN BIT(1)
+#define RXDMA_AGG_EN BIT(2)
+#define QS_VO_QUEUE BIT(8)
+#define QS_VI_QUEUE BIT(9)
+#define QS_BE_QUEUE BIT(10)
+#define QS_BK_QUEUE BIT(11)
+#define QS_MANAGER_QUEUE BIT(12)
+#define QS_HIGH_QUEUE BIT(13)
+
+#define HQSEL_VOQ BIT(0)
+#define HQSEL_VIQ BIT(1)
+#define HQSEL_BEQ BIT(2)
+#define HQSEL_BKQ BIT(3)
+#define HQSEL_MGTQ BIT(4)
+#define HQSEL_HIQ BIT(5)
+
+#define _TXDMA_HIQ_MAP(x) (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x) (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x) (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x) (((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x) (((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x) (((x)&0x3) << 4)
+
+#define QUEUE_LOW 1
+#define QUEUE_NORMAL 2
+#define QUEUE_HIGH 3
+
+#define _LLT_NO_ACTIVE 0x0
+#define _LLT_WRITE_ACCESS 0x1
+#define _LLT_READ_ACCESS 0x2
+
+#define _LLT_INIT_DATA(x) ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x) (((x) & 0xFF) << 8)
+#define _LLT_OP(x) (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x) (((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK (BIT(31) | BIT(30))
+#define BB_WRITE_EN BIT(30)
+#define BB_READ_EN BIT(31)
+
+#define _HPQ(x) ((x) & 0xFF)
+#define _LPQ(x) (((x) & 0xFF) << 8)
+#define _PUBQ(x) (((x) & 0xFF) << 16)
+#define _NPQ(x) ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS BIT(24)
+#define LPQ_PUBLIC_DIS BIT(25)
+#define LD_RQPN BIT(31)
+
+#define BCN_VALID BIT(16)
+#define BCN_HEAD(x) (((x) & 0xFF) << 8)
+#define BCN_HEAD_MASK 0xFF00
+
+#define BLK_DESC_NUM_SHIFT 4
+#define BLK_DESC_NUM_MASK 0xF
+
+#define DROP_DATA_EN BIT(9)
+
+#define EN_AMPDU_RTY_NEW BIT(7)
+
+#define _INIRTSMCS_SEL(x) ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x) ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x) (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL 0xFFFFF
+
+#define _RRSC_BITMAP(x) ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x) (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED 0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL 0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL 0x2
+#define RRSR_RSC_DUPLICATE_MODE 0x3
+
+#define USE_SHORT_G1 BIT(20)
+
+#define _AGGLMT_MCS0(x) ((x) & 0xF)
+#define _AGGLMT_MCS1(x) (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x) (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x) (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x) (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x) (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x) (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x) (((x) & 0xF) << 28)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define _DARF_RC1(x) ((x) & 0x1F)
+#define _DARF_RC2(x) (((x) & 0x1F) << 8)
+#define _DARF_RC3(x) (((x) & 0x1F) << 16)
+#define _DARF_RC4(x) (((x) & 0x1F) << 24)
+#define _DARF_RC5(x) ((x) & 0x1F)
+#define _DARF_RC6(x) (((x) & 0x1F) << 8)
+#define _DARF_RC7(x) (((x) & 0x1F) << 16)
+#define _DARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x) ((x) & 0x1F)
+#define _RARF_RC2(x) (((x) & 0x1F) << 8)
+#define _RARF_RC3(x) (((x) & 0x1F) << 16)
+#define _RARF_RC4(x) (((x) & 0x1F) << 24)
+#define _RARF_RC5(x) ((x) & 0x1F)
+#define _RARF_RC6(x) (((x) & 0x1F) << 8)
+#define _RARF_RC7(x) (((x) & 0x1F) << 16)
+#define _RARF_RC8(x) (((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define _AIFS(x) (x)
+#define _ECW_MAX_MIN(x) ((x) << 8)
+#define _TXOP_LIMIT(x) ((x) << 16)
+
+#define _BCNIFS(x) ((x) & 0xFF)
+#define _BCNECW(x) ((((x) & 0xF)) << 8)
+
+#define _LRL(x) ((x) & 0x3F)
+#define _SRL(x) (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x) ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x) (((x) & 0xFF) << 8);
+
+#define _SIFS_OFDM_CTX(x) ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x) (((x) & 0xFF) << 8);
+
+#define _TBTT_PROHIBIT_HOLD(x) (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN BIT(11)
+
+#define EN_MBSSID BIT(1)
+#define EN_TXBCN_RPT BIT(2)
+#define EN_BCN_FUNCTION BIT(3)
+
+#define TSFTR_RST BIT(0)
+#define TSFTR1_RST BIT(1)
+
+#define STOP_BCNQ BIT(6)
+
+#define DIS_TSF_UDT0_NORMAL_CHIP BIT(4)
+#define DIS_TSF_UDT0_TEST_CHIP BIT(5)
+
+#define ACMHW_HWEN BIT(0)
+#define ACMHW_BEQEN BIT(1)
+#define ACMHW_VIQEN BIT(2)
+#define ACMHW_VOQEN BIT(3)
+#define ACMHW_BEQSTATUS BIT(4)
+#define ACMHW_VIQSTATUS BIT(5)
+#define ACMHW_VOQSTATUS BIT(6)
+
+#define APSDOFF BIT(6)
+#define APSDOFF_STATUS BIT(7)
+
+#define BW_20MHZ BIT(2)
+
+#define RATE_BITMAP_ALL 0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M 0xFFFF1
+
+#define TSFRST BIT(0)
+#define DIS_GCLK BIT(1)
+#define PAD_SEL BIT(2)
+#define PWR_ST BIT(6)
+#define PWRBIT_OW_EN BIT(7)
+#define ACRC BIT(8)
+#define CFENDFORM BIT(9)
+#define ICV BIT(10)
+
+#define AAP BIT(0)
+#define APM BIT(1)
+#define AM BIT(2)
+#define AB BIT(3)
+#define ADD3 BIT(4)
+#define APWRMGT BIT(5)
+#define CBSSID BIT(6)
+#define CBSSID_DATA BIT(6)
+#define CBSSID_BCN BIT(7)
+#define ACRC32 BIT(8)
+#define AICV BIT(9)
+#define ADF BIT(11)
+#define ACF BIT(12)
+#define AMF BIT(13)
+#define HTC_LOC_CTRL BIT(14)
+#define UC_DATA_EN BIT(16)
+#define BM_DATA_EN BIT(17)
+#define MFBEN BIT(22)
+#define LSIGEN BIT(23)
+#define ENMBID BIT(24)
+#define APP_BASSN BIT(27)
+#define APP_PHYSTS BIT(28)
+#define APP_ICV BIT(29)
+#define APP_MIC BIT(30)
+#define APP_FCS BIT(31)
+
+#define _MIN_SPACE(x) ((x) & 0x7)
+#define _SHORT_GI_PADDING(x) (((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU 0
+#define RXERR_TYPE_OFDM_FALSE_ALARM 1
+#define RXERR_TYPE_OFDM_MPDU_OK 2
+#define RXERR_TYPE_OFDM_MPDU_FAIL 3
+#define RXERR_TYPE_CCK_PPDU 4
+#define RXERR_TYPE_CCK_FALSE_ALARM 5
+#define RXERR_TYPE_CCK_MPDU_OK 6
+#define RXERR_TYPE_CCK_MPDU_FAIL 7
+#define RXERR_TYPE_HT_PPDU 8
+#define RXERR_TYPE_HT_FALSE_ALARM 9
+#define RXERR_TYPE_HT_MPDU_TOTAL 10
+#define RXERR_TYPE_HT_MPDU_OK 11
+#define RXERR_TYPE_HT_MPDU_FAIL 12
+#define RXERR_TYPE_RX_FULL_DROP 15
+
+#define RXERR_COUNTER_MASK 0xFFFFF
+#define RXERR_RPT_RST BIT(27)
+#define _RXERR_RPT_SEL(type) ((type) << 28)
+
+#define SCR_TXUSEDK BIT(0)
+#define SCR_RXUSEDK BIT(1)
+#define SCR_TXENCENABLE BIT(2)
+#define SCR_RXDECENABLE BIT(3)
+#define SCR_SKBYA2 BIT(4)
+#define SCR_NOSKMC BIT(5)
+#define SCR_TXBCUSEDK BIT(6)
+#define SCR_RXBCUSEDK BIT(7)
+
+#define USB_IS_HIGH_SPEED 0
+#define USB_IS_FULL_SPEED 1
+#define USB_SPEED_MASK BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK 0xF
+#define USB_NORMAL_SIE_EP_SHIFT 4
+
+#define USB_TEST_EP_MASK 0x30
+#define USB_TEST_EP_SHIFT 4
+
+#define USB_AGG_EN BIT(3)
+
+#define MAC_ADDR_LEN 6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER 175/*255 88e*/
+
+#define POLLING_LLT_THRESHOLD 20
+#define POLLING_READY_TIMEOUT_COUNT 3000
+
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG 0x3
+#define EPROM_CMD_LOAD 1
+
+#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
+
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
+
+#define RPMAC_RESET 0x100
+#define RPMAC_TXSTART 0x104
+#define RPMAC_TXLEGACYSIG 0x108
+#define RPMAC_TXHTSIG1 0x10c
+#define RPMAC_TXHTSIG2 0x110
+#define RPMAC_PHYDEBUG 0x114
+#define RPMAC_TXPACKETNUM 0x118
+#define RPMAC_TXIDLE 0x11c
+#define RPMAC_TXMACHEADER0 0x120
+#define RPMAC_TXMACHEADER1 0x124
+#define RPMAC_TXMACHEADER2 0x128
+#define RPMAC_TXMACHEADER3 0x12c
+#define RPMAC_TXMACHEADER4 0x130
+#define RPMAC_TXMACHEADER5 0x134
+#define RPMAC_TXDADATYPE 0x138
+#define RPMAC_TXRANDOMSEED 0x13c
+#define RPMAC_CCKPLCPPREAMBLE 0x140
+#define RPMAC_CCKPLCPHEADER 0x144
+#define RPMAC_CCKCRC16 0x148
+#define RPMAC_OFDMRXCRC32OK 0x170
+#define RPMAC_OFDMRXCRC32Er 0x174
+#define RPMAC_OFDMRXPARITYER 0x178
+#define RPMAC_OFDMRXCRC8ER 0x17c
+#define RPMAC_CCKCRXRC16ER 0x180
+#define RPMAC_CCKCRXRC32ER 0x184
+#define RPMAC_CCKCRXRC32OK 0x188
+#define RPMAC_TXSTATUS 0x18c
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#define RFPGA0_XA_HSSIPARAMETER2 0x824
+#define RFPGA0_XB_HSSIPARAMETER1 0x828
+#define RFPGA0_XB_HSSIPARAMETER2 0x82c
+
+#define RFPGA0_XA_LSSIPARAMETER 0x840
+#define RFPGA0_XB_LSSIPARAMETER 0x844
+
+#define RFPGA0_RFWAKEUPPARAMETER 0x850
+#define RFPGA0_RFSLEEPUPPARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define rFPGA0_XAB_RFPARAMETER 0x878
+#define rFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVEA_HSPI_READBACK 0x8b8
+#define TRANSCEIVEB_HSPI_READBACK 0x8bc
+#define REG_SC_CNT 0x8c4
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+#define RCCK0_CCA_CNT 0xa60
+
+
+/* PageB(0xB00) */
+#define RPDP_ANTA 0xb00
+#define RPDP_ANTA_4 0xb04
+#define RPDP_ANTA_8 0xb08
+#define RPDP_ANTA_C 0xb0c
+#define RPDP_ANTA_10 0xb10
+#define RPDP_ANTA_14 0xb14
+#define RPDP_ANTA_18 0xb18
+#define RPDP_ANTA_1C 0xb1c
+#define RPDP_ANTA_20 0xb20
+#define RPDP_ANTA_24 0xb24
+
+#define RCONFIG_PMPD_ANTA 0xb28
+#define RCONFIG_RAM64X16 0xb2c
+
+#define RBNDA 0xb30
+#define RHSSIPAR 0xb34
+
+#define RCONFIG_ANTA 0xb68
+#define RCONFIG_ANTB 0xb6c
+
+#define RPDP_ANTB 0xb70
+#define RPDP_ANTB_4 0xb74
+#define RPDP_ANTB_8 0xb78
+#define RPDP_ANTB_C 0xb7c
+#define RPDP_ANTB_10 0xb80
+#define RPDP_ANTB_14 0xb84
+#define RPDP_ANTB_18 0xb88
+#define RPDP_ANTB_1C 0xb8c
+#define RPDP_ANTB_20 0xb90
+#define RPDP_ANTB_24 0xb94
+
+#define RCONFIG_PMPD_ANTB 0xb98
+
+#define RBNDB 0xba0
+
+#define RAPK 0xbd8
+#define rPm_Rx0_AntA 0xbdc
+#define rPm_Rx1_AntA 0xbe0
+#define rPm_Rx2_AntA 0xbe4
+#define rPm_Rx3_AntA 0xbe8
+#define rPm_Rx0_AntB 0xbec
+#define rPm_Rx1_AntB 0xbf0
+#define rPm_Rx2_AntB 0xbf4
+#define rPm_Rx3_AntB 0xbf8
+
+/*Page C*/
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBAL 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBAL 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBAL 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBAL 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFOANDDAGC 0xc44
+#define ROFDM0_CCADROPTHRES 0xc48
+#define ROFDM0_ECCATHRES 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#define ROFDM0_XAAGCCORE2 0xc54
+#define ROFDM0_XBAGCCORE1 0xc58
+#define ROFDM0_XBAGCCORE2 0xc5c
+#define ROFDM0_XCAGCCORE1 0xc60
+#define ROFDM0_XCAGCCORE2 0xc64
+#define ROFDM0_XDAGCCORE1 0xc68
+#define ROFDM0_XDAGCCORE2 0xc6c
+
+#define ROFDM0_AGCPARAMETER1 0xc70
+#define ROFDM0_AGCPARAMETER2 0xc74
+#define ROFDM0_AGCRSSITABLE 0xc78
+#define ROFDM0_HTSTFAGC 0xc7c
+
+#define ROFDM0_XATXIQIMBAL 0xc80
+#define ROFDM0_XATXAFE 0xc84
+#define ROFDM0_XBTXIQIMBAL 0xc88
+#define ROFDM0_XBTXAFE 0xc8c
+#define ROFDM0_XCTXIQIMBAL 0xc90
+#define ROFDM0_XCTXAFE 0xc94
+#define ROFDM0_XDTXIQIMBAL 0xc98
+#define ROFDM0_XDTXAFE 0xc9c
+
+#define ROFDM0_RXIQEXTANTA 0xca0
+#define ROFDM0_TXCOEFF1 0xca4
+#define ROFDM0_TXCOEFF2 0xca8
+#define ROFDM0_TXCOEFF3 0xcac
+#define ROFDM0_TXCOEFF4 0xcb0
+#define ROFDM0_TXCOEFF5 0xcb4
+#define ROFDM0_TXCOEFF6 0xcb8
+
+#define ROFDM0_RXHPPARAMETER 0xce0
+#define ROFDM0_TXPSEUDONOISEWGT 0xce4
+#define ROFDM0_FRAMESYNC 0xcf0
+#define ROFDM0_DFSREPORT 0xcf4
+
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CF0 0xd08
+#define ROFDM1_CSI1 0xd10
+#define ROFDM1_SBD 0xd14
+#define ROFDM1_CSI2 0xd18
+#define ROFDM1_CFOTRACKING 0xd2c
+#define ROFDM1_TRXMESAURE1 0xd34
+#define ROFDM1_INTFDET 0xd3c
+#define ROFDM1_PSEUDONOISESTATEAB 0xd50
+#define ROFDM1_PSEUDONOISESTATECD 0xd54
+#define ROFDM1_RXPSEUDONOISEWGT 0xd58
+
+#define ROFDM_PHYCOUNTER1 0xda0
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORTCFOAB 0xdac
+#define ROFDM_SHORTCFOCD 0xdb0
+#define ROFDM_LONGCFOAB 0xdb4
+#define ROFDM_LONGCFOCD 0xdb8
+#define ROFDM_TAILCF0AB 0xdbc
+#define ROFDM_TAILCF0CD 0xdc0
+#define ROFDM_PWMEASURE1 0xdc4
+#define ROFDM_PWMEASURE2 0xdc8
+#define ROFDM_BWREPORT 0xdcc
+#define ROFDM_AGCREPORT 0xdd0
+#define ROFDM_RXSNR 0xdd4
+#define ROFDM_RXEVMCSI 0xdd8
+#define ROFDM_SIGREPORT 0xddc
+
+#define RTXAGC_A_RATE18_06 0xe00
+#define RTXAGC_A_RATE54_24 0xe04
+#define RTXAGC_A_CCK1_MCS32 0xe08
+#define RTXAGC_A_MCS03_MCS00 0xe10
+#define RTXAGC_A_MCS07_MCS04 0xe14
+#define RTXAGC_A_MCS11_MCS08 0xe18
+#define RTXAGC_A_MCS15_MCS12 0xe1c
+
+#define RTXAGC_B_RATE18_06 0x830
+#define RTXAGC_B_RATE54_24 0x834
+#define RTXAGC_B_CCK1_55_MCS32 0x838
+#define RTXAGC_B_MCS03_MCS00 0x83c
+#define RTXAGC_B_MCS07_MCS04 0x848
+#define RTXAGC_B_MCS11_MCS08 0x84c
+#define RTXAGC_B_MCS15_MCS12 0x868
+#define RTXAGC_B_CCK11_A_CCK2_11 0x86c
+
+#define RFPGA0_IQK 0xe28
+#define RTX_IQK_TONE_A 0xe30
+#define RRX_IQK_TONE_A 0xe34
+#define RTX_IQK_PI_A 0xe38
+#define RRX_IQK_PI_A 0xe3c
+
+#define RTX_IQK 0xe40
+#define RRX_IQK 0xe44
+#define RIQK_AGC_PTS 0xe48
+#define RIQK_AGC_RSP 0xe4c
+#define RTX_IQK_TONE_B 0xe50
+#define RRX_IQK_TONE_B 0xe54
+#define RTX_IQK_PI_B 0xe58
+#define RRX_IQK_PI_B 0xe5c
+#define RIQK_AGC_CONT 0xe60
+
+#define RBLUE_TOOTH 0xe6c
+#define RRX_WAIT_CCA 0xe70
+#define RTX_CCK_RFON 0xe74
+#define RTX_CCK_BBON 0xe78
+#define RTX_OFDM_RFON 0xe7c
+#define RTX_OFDM_BBON 0xe80
+#define RTX_TO_RX 0xe84
+#define RTX_TO_TX 0xe88
+#define RRX_CCK 0xe8c
+
+#define RTX_POWER_BEFORE_IQK_A 0xe94
+#define RTX_POWER_AFTER_IQK_A 0xe9c
+
+#define RRX_POWER_BEFORE_IQK_A 0xea0
+#define RRX_POWER_BEFORE_IQK_A_2 0xea4
+#define RRX_POWER_AFTER_IQK_A 0xea8
+#define RRX_POWER_AFTER_IQK_A_2 0xeac
+
+#define RTX_POWER_BEFORE_IQK_B 0xeb4
+#define RTX_POWER_AFTER_IQK_B 0xebc
+
+#define RRX_POWER_BEFORE_IQK_B 0xec0
+#define RRX_POWER_BEFORE_IQK_B_2 0xec4
+#define RRX_POWER_AFTER_IQK_B 0xec8
+#define RRX_POWER_AFTER_IQK_B_2 0xecc
+
+#define RRX_OFDM 0xed0
+#define RRX_WAIT_RIFS 0xed4
+#define RRX_TO_RX 0xed8
+#define RSTANDBY 0xedc
+#define RSLEEP 0xee0
+#define RPMPD_ANAEN 0xeec
+
+#define RZEBRA1_HSSIENABLE 0x0
+#define RZEBRA1_TRXENABLE1 0x1
+#define RZEBRA1_TRXENABLE2 0x2
+#define RZEBRA1_AGC 0x4
+#define RZEBRA1_CHARGEPUMP 0x5
+#define RZEBRA1_CHANNEL 0x7
+
+#define RZEBRA1_TXGAIN 0x8
+#define RZEBRA1_TXLPF 0x9
+#define RZEBRA1_RXLPF 0xb
+#define RZEBRA1_RXHPFCORNER 0xc
+
+#define RGLOBALCTRL 0
+#define RRTL8256_TXLPF 19
+#define RRTL8256_RXLPF 11
+#define RRTL8258_TXLPF 0x11
+#define RRTL8258_RXLPF 0x13
+#define RRTL8258_RSSILPF 0xa
+
+#define RF_AC 0x00
+
+#define RF_IQADJ_G1 0x01
+#define RF_IQADJ_G2 0x02
+#define RF_POW_TRSW 0x05
+
+#define RF_GAIN_RX 0x06
+#define RF_GAIN_TX 0x07
+
+#define RF_TXM_IDAC 0x08
+#define RF_BS_IQGEN 0x0F
+
+#define RF_MODE1 0x10
+#define RF_MODE2 0x11
+
+#define RF_RX_AGC_HP 0x12
+#define RF_TX_AGC 0x13
+#define RF_BIAS 0x14
+#define RF_IPA 0x15
+#define RF_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RRFCHANNEL 0x18
+#define RF_CHNLBW 0x18
+#define RF_TOP 0x19
+
+#define RF_RX_G1 0x1A
+#define RF_RX_G2 0x1B
+
+#define RF_RX_BB2 0x1C
+#define RF_RX_BB1 0x1D
+
+#define RF_RCK1 0x1E
+#define RF_RCK2 0x1F
+
+#define RF_TX_G1 0x20
+#define RF_TX_G2 0x21
+#define RF_TX_G3 0x22
+
+#define RF_TX_BB1 0x23
+#define RF_T_METER 0x42
+
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#define RF_TX_BIAS_A 0x35
+#define RF_TX_BIAS_D 0x36
+#define RF_LOBF_9 0x38
+#define RF_RXRF_A3 0x3C
+#define RF_TRSW 0x3F
+
+#define RF_TXRF_A2 0x41
+#define RF_TXPA_G4 0x46
+#define RF_TXPA_A4 0x4B
+
+#define RF_WE_LUT 0xEF
+
+#define BBBRESETB 0x100
+#define BGLOBALRESETB 0x200
+#define BOFDMTXSTART 0x4
+#define BCCKTXSTART 0x8
+#define BCRC32DEBUG 0x100
+#define BPMACLOOPBACK 0x10
+#define BTXLSIG 0xffffff
+#define BOFDMTXRATE 0xf
+#define BOFDMTXRESERVED 0x10
+#define BOFDMTXLENGTH 0x1ffe0
+#define BOFDMTXPARITY 0x20000
+#define BTXHTSIG1 0xffffff
+#define BTXHTMCSRATE 0x7f
+#define BTXHTBW 0x80
+#define BTXHTLENGTH 0xffff00
+#define BTXHTSIG2 0xffffff
+#define BTXHTSMOOTHING 0x1
+#define BTXHTSOUNDING 0x2
+#define BTXHTRESERVED 0x4
+#define BTXHTAGGREATION 0x8
+#define BTXHTSTBC 0x30
+#define BTXHTADVANCECODING 0x40
+#define BTXHTSHORTGI 0x80
+#define BTXHTNUMBERHT_LTF 0x300
+#define BTXHTCRC8 0x3fc00
+#define BCOUNTERRESET 0x10000
+#define BNUMOFOFDMTX 0xffff
+#define BNUMOFCCKTX 0xffff0000
+#define BTXIDLEINTERVAL 0xffff
+#define BOFDMSERVICE 0xffff0000
+#define BTXMACHEADER 0xffffffff
+#define BTXDATAINIT 0xff
+#define BTXHTMODE 0x100
+#define BTXDATATYPE 0x30000
+#define BTXRANDOMSEED 0xffffffff
+#define BCCKTXPREAMBLE 0x1
+#define BCCKTXSFD 0xffff0000
+#define BCCKTXSIG 0xff
+#define BCCKTXSERVICE 0xff00
+#define BCCKLENGTHEXT 0x8000
+#define BCCKTXLENGHT 0xffff0000
+#define BCCKTXCRC16 0xffff
+#define BCCKTXSTATUS 0x1
+#define BOFDMTXSTATUS 0x2
+#define IS_BB_REG_OFFSET_92S(_offset) \
+ ((_offset >= 0x800) && (_offset <= 0xfff))
+
+#define BRFMOD 0x1
+#define BJAPANMODE 0x2
+#define BCCKTXSC 0x30
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BOFDMRXADCPHASE 0x10000
+#define BOFDMTXDACPHASE 0x40000
+#define BXATXAGC 0x3f
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define BPASTART 0xf0000000
+#define BTRSTART 0x00f00000
+#define BRFSTART 0x0000f000
+#define BBBSTART 0x000000f0
+#define BBBCCKSTART 0x0000000f
+#define BPAEND 0xf
+#define BTREND 0x0f000000
+#define BRFEND 0x000f0000
+#define BCCAMASK 0x000000f0
+#define BR2RCCAMASK 0x00000f00
+#define BHSSI_R2TDELAY 0xf8000000
+#define BHSSI_T2RDELAY 0xf80000
+#define BCONTXHSSI 0x400
+#define BIGFROMCCK 0x200
+#define BAGCADDRESS 0x3f
+#define BRXHPTX 0x7000
+#define BRXHP2RX 0x38000
+#define BRXHPCCKINI 0xc0000
+#define BAGCTXCODE 0xc00000
+#define BAGCRXCODE 0x300000
+
+#define B3WIREDATALENGTH 0x800
+#define B3WIREADDREAALENGTH 0x400
+
+#define B3WIRERFPOWERDOWN 0x1
+#define B5GPAPEPOLARITY 0x40000000
+#define B2GPAPEPOLARITY 0x80000000
+#define BRFSW_TXDEFAULTANT 0x3
+#define BRFSW_TXOPTIONANT 0x30
+#define BRFSW_RXDEFAULTANT 0x300
+#define BRFSW_RXOPTIONANT 0x3000
+#define BRFSI_3WIREDATA 0x1
+#define BRFSI_3WIRECLOCK 0x2
+#define BRFSI_3WIRELOAD 0x4
+#define BRFSI_3WIRERW 0x8
+#define BRFSI_3WIRE 0xf
+
+#define BRFSI_RFENV 0x10
+
+#define BRFSI_TRSW 0x20
+#define BRFSI_TRSWB 0x40
+#define BRFSI_ANTSW 0x100
+#define BRFSI_ANTSWB 0x200
+#define BRFSI_PAPE 0x400
+#define BRFSI_PAPE5G 0x800
+#define BBANDSELECT 0x1
+#define BHTSIG2_GI 0x80
+#define BHTSIG2_SMOOTHING 0x01
+#define BHTSIG2_SOUNDING 0x02
+#define BHTSIG2_AGGREATON 0x08
+#define BHTSIG2_STBC 0x30
+#define BHTSIG2_ADVCODING 0x40
+#define BHTSIG2_NUMOFHTLTF 0x300
+#define BHTSIG2_CRC8 0x3fc
+#define BHTSIG1_MCS 0x7f
+#define BHTSIG1_BANDWIDTH 0x80
+#define BHTSIG1_HTLENGTH 0xffff
+#define BLSIG_RATE 0xf
+#define BLSIG_RESERVED 0x10
+#define BLSIG_LENGTH 0x1fffe
+#define BLSIG_PARITY 0x20
+#define BCCKRXPHASE 0x4
+
+#define BLSSIREADADDRESS 0x7f800000
+#define BLSSIREADEDGE 0x80000000
+
+#define BLSSIREADBACKDATA 0xfffff
+
+#define BLSSIREADOKFLAG 0x1000
+#define BCCKSAMPLERATE 0x8
+#define BREGULATOR0STANDBY 0x1
+#define BREGULATORPLLSTANDBY 0x2
+#define BREGULATOR1STANDBY 0x4
+#define BPLLPOWERUP 0x8
+#define BDPLLPOWERUP 0x10
+#define BDA10POWERUP 0x20
+#define BAD7POWERUP 0x200
+#define BDA6POWERUP 0x2000
+#define BXTALPOWERUP 0x4000
+#define B40MDCLKPOWERUP 0x8000
+#define BDA6DEBUGMODE 0x20000
+#define BDA6SWING 0x380000
+
+#define BADCLKPHASE 0x4000000
+#define B80MCLKDELAY 0x18000000
+#define BAFEWATCHDOGENABLE 0x20000000
+
+#define BXTALCAP01 0xc0000000
+#define BXTALCAP23 0x3
+#define BXTALCAP92X 0x0f000000
+#define BXTALCAP 0x0f000000
+
+#define BINTDIFCLKENABLE 0x400
+#define BEXTSIGCLKENABLE 0x800
+#define BBANDGAP_MBIAS_POWERUP 0x10000
+#define BAD11SH_GAIN 0xc0000
+#define BAD11NPUT_RANGE 0x700000
+#define BAD110P_CURRENT 0x3800000
+#define BLPATH_LOOPBACK 0x4000000
+#define BQPATH_LOOPBACK 0x8000000
+#define BAFE_LOOPBACK 0x10000000
+#define BDA10_SWING 0x7e0
+#define BDA10_REVERSE 0x800
+#define BDA_CLK_SOURCE 0x1000
+#define BDA7INPUT_RANGE 0x6000
+#define BDA7_GAIN 0x38000
+#define BDA7OUTPUT_CM_MODE 0x40000
+#define BDA7INPUT_CM_MODE 0x380000
+#define BDA7CURRENT 0xc00000
+#define BREGULATOR_ADJUST 0x7000000
+#define BAD11POWERUP_ATTX 0x1
+#define BDA10PS_ATTX 0x10
+#define BAD11POWERUP_ATRX 0x100
+#define BDA10PS_ATRX 0x1000
+#define BCCKRX_AGC_FORMAT 0x200
+#define BPSDFFT_SAMPLE_POINT 0xc000
+#define BPSD_AVERAGE_NUM 0x3000
+#define BIQPATH_CONTROL 0xc00
+#define BPSD_FREQ 0x3ff
+#define BPSD_ANTENNA_PATH 0x30
+#define BPSD_IQ_SWITCH 0x40
+#define BPSD_RX_TRIGGER 0x400000
+#define BPSD_TX_TRIGGERCW 0x80000000
+#define BPSD_SINE_TONE_SCALE 0x7f000000
+#define BPSD_REPORT 0xffff
+
+#define BOFDM_TXSC 0x30000000
+#define BCCK_TXON 0x1
+#define BOFDM_TXON 0x2
+#define BDEBUG_PAGE 0xfff
+#define BDEBUG_ITEM 0xff
+#define BANTL 0x10
+#define BANT_NONHT 0x100
+#define BANT_HT1 0x1000
+#define BANT_HT2 0x10000
+#define BANT_HT1S1 0x100000
+#define BANT_NONHTS1 0x1000000
+
+#define BCCK_BBMODE 0x3
+#define BCCK_TXPOWERSAVING 0x80
+#define BCCK_RXPOWERSAVING 0x40
+
+#define BCCK_SIDEBAND 0x10
+
+#define BCCK_SCRAMBLE 0x8
+#define BCCK_ANTDIVERSITY 0x8000
+#define BCCK_CARRIER_RECOVERY 0x4000
+#define BCCK_TXRATE 0x3000
+#define BCCK_DCCANCEL 0x0800
+#define BCCK_ISICANCEL 0x0400
+#define BCCK_MATCH_FILTER 0x0200
+#define BCCK_EQUALIZER 0x0100
+#define BCCK_PREAMBLE_DETECT 0x800000
+#define BCCK_FAST_FALSECCA 0x400000
+#define BCCK_CH_ESTSTART 0x300000
+#define BCCK_CCA_COUNT 0x080000
+#define BCCK_CS_LIM 0x070000
+#define BCCK_BIST_MODE 0x80000000
+#define BCCK_CCAMASK 0x40000000
+#define BCCK_TX_DAC_PHASE 0x4
+#define BCCK_RX_ADC_PHASE 0x20000000
+#define BCCKR_CP_MODE 0x0100
+#define BCCK_TXDC_OFFSET 0xf0
+#define BCCK_RXDC_OFFSET 0xf
+#define BCCK_CCA_MODE 0xc000
+#define BCCK_FALSECS_LIM 0x3f00
+#define BCCK_CS_RATIO 0xc00000
+#define BCCK_CORGBIT_SEL 0x300000
+#define BCCK_PD_LIM 0x0f0000
+#define BCCK_NEWCCA 0x80000000
+#define BCCK_RXHP_OF_IG 0x8000
+#define BCCK_RXIG 0x7f00
+#define BCCK_LNA_POLARITY 0x800000
+#define BCCK_RX1ST_BAIN 0x7f0000
+#define BCCK_RF_EXTEND 0x20000000
+#define BCCK_RXAGC_SATLEVEL 0x1f000000
+#define BCCK_RXAGC_SATCOUNT 0xe0
+#define BCCKRXRFSETTLE 0x1f
+#define BCCK_FIXED_RXAGC 0x8000
+#define BCCK_ANTENNA_POLARITY 0x2000
+#define BCCK_TXFILTER_TYPE 0x0c00
+#define BCCK_RXAGC_REPORTTYPE 0x0300
+#define BCCK_RXDAGC_EN 0x80000000
+#define BCCK_RXDAGC_PERIOD 0x20000000
+#define BCCK_RXDAGC_SATLEVEL 0x1f000000
+#define BCCK_TIMING_RECOVERY 0x800000
+#define BCCK_TXC0 0x3f0000
+#define BCCK_TXC1 0x3f000000
+#define BCCK_TXC2 0x3f
+#define BCCK_TXC3 0x3f00
+#define BCCK_TXC4 0x3f0000
+#define BCCK_TXC5 0x3f000000
+#define BCCK_TXC6 0x3f
+#define BCCK_TXC7 0x3f00
+#define BCCK_DEBUGPORT 0xff0000
+#define BCCK_DAC_DEBUG 0x0f000000
+#define BCCK_FALSEALARM_ENABLE 0x8000
+#define BCCK_FALSEALARM_READ 0x4000
+#define BCCK_TRSSI 0x7f
+#define BCCK_RXAGC_REPORT 0xfe
+#define BCCK_RXREPORT_ANTSEL 0x80000000
+#define BCCK_RXREPORT_MFOFF 0x40000000
+#define BCCK_RXREPORT_SQLOSS 0x20000000
+#define BCCK_RXREPORT_PKTLOSS 0x10000000
+#define BCCK_RXREPORT_LOCKEDBIT 0x08000000
+#define BCCK_RXREPORT_RATEERROR 0x04000000
+#define BCCK_RXREPORT_RXRATE 0x03000000
+#define BCCK_RXFA_COUNTER_LOWER 0xff
+#define BCCK_RXFA_COUNTER_UPPER 0xff000000
+#define BCCK_RXHPAGC_START 0xe000
+#define BCCK_RXHPAGC_FINAL 0x1c00
+#define BCCK_RXFALSEALARM_ENABLE 0x8000
+#define BCCK_FACOUNTER_FREEZE 0x4000
+#define BCCK_TXPATH_SEL 0x10000000
+#define BCCK_DEFAULT_RXPATH 0xc000000
+#define BCCK_OPTION_RXPATH 0x3000000
+
+#define BNUM_OFSTF 0x3
+#define BSHIFT_L 0xc0
+#define BGI_TH 0xc
+#define BRXPATH_A 0x1
+#define BRXPATH_B 0x2
+#define BRXPATH_C 0x4
+#define BRXPATH_D 0x8
+#define BTXPATH_A 0x1
+#define BTXPATH_B 0x2
+#define BTXPATH_C 0x4
+#define BTXPATH_D 0x8
+#define BTRSSI_FREQ 0x200
+#define BADC_BACKOFF 0x3000
+#define BDFIR_BACKOFF 0xc000
+#define BTRSSI_LATCH_PHASE 0x10000
+#define BRX_LDC_OFFSET 0xff
+#define BRX_QDC_OFFSET 0xff00
+#define BRX_DFIR_MODE 0x1800000
+#define BRX_DCNF_TYPE 0xe000000
+#define BRXIQIMB_A 0x3ff
+#define BRXIQIMB_B 0xfc00
+#define BRXIQIMB_C 0x3f0000
+#define BRXIQIMB_D 0xffc00000
+#define BDC_DC_NOTCH 0x60000
+#define BRXNB_NOTCH 0x1f000000
+#define BPD_TH 0xf
+#define BPD_TH_OPT2 0xc000
+#define BPWED_TH 0x700
+#define BIFMF_WIN_L 0x800
+#define BPD_OPTION 0x1000
+#define BMF_WIN_L 0xe000
+#define BBW_SEARCH_L 0x30000
+#define BWIN_ENH_L 0xc0000
+#define BBW_TH 0x700000
+#define BED_TH2 0x3800000
+#define BBW_OPTION 0x4000000
+#define BRADIO_TH 0x18000000
+#define BWINDOW_L 0xe0000000
+#define BSBD_OPTION 0x1
+#define BFRAME_TH 0x1c
+#define BFS_OPTION 0x60
+#define BDC_SLOPE_CHECK 0x80
+#define BFGUARD_COUNTER_DC_L 0xe00
+#define BFRAME_WEIGHT_SHORT 0x7000
+#define BSUB_TUNE 0xe00000
+#define BFRAME_DC_LENGTH 0xe000000
+#define BSBD_START_OFFSET 0x30000000
+#define BFRAME_TH_2 0x7
+#define BFRAME_GI2_TH 0x38
+#define BGI2_SYNC_EN 0x40
+#define BSARCH_SHORT_EARLY 0x300
+#define BSARCH_SHORT_LATE 0xc00
+#define BSARCH_GI2_LATE 0x70000
+#define BCFOANTSUM 0x1
+#define BCFOACC 0x2
+#define BCFOSTARTOFFSET 0xc
+#define BCFOLOOPBACK 0x70
+#define BCFOSUMWEIGHT 0x80
+#define BDAGCENABLE 0x10000
+#define BTXIQIMB_A 0x3ff
+#define BTXIQIMB_B 0xfc00
+#define BTXIQIMB_C 0x3f0000
+#define BTXIQIMB_D 0xffc00000
+#define BTXIDCOFFSET 0xff
+#define BTXIQDCOFFSET 0xff00
+#define BTXDFIRMODE 0x10000
+#define BTXPESUDO_NOISEON 0x4000000
+#define BTXPESUDO_NOISE_A 0xff
+#define BTXPESUDO_NOISE_B 0xff00
+#define BTXPESUDO_NOISE_C 0xff0000
+#define BTXPESUDO_NOISE_D 0xff000000
+#define BCCA_DROPOPTION 0x20000
+#define BCCA_DROPTHRES 0xfff00000
+#define BEDCCA_H 0xf
+#define BEDCCA_L 0xf0
+#define BLAMBDA_ED 0x300
+#define BRX_INITIALGAIN 0x7f
+#define BRX_ANTDIV_EN 0x80
+#define BRX_AGC_ADDRESS_FOR_LNA 0x7f00
+#define BRX_HIGHPOWER_FLOW 0x8000
+#define BRX_AGC_FREEZE_THRES 0xc0000
+#define BRX_FREEZESTEP_AGC1 0x300000
+#define BRX_FREEZESTEP_AGC2 0xc00000
+#define BRX_FREEZESTEP_AGC3 0x3000000
+#define BRX_FREEZESTEP_AGC0 0xc000000
+#define BRXRSSI_CMP_EN 0x10000000
+#define BRXQUICK_AGCEN 0x20000000
+#define BRXAGC_FREEZE_THRES_MODE 0x40000000
+#define BRX_OVERFLOW_CHECKTYPE 0x80000000
+#define BRX_AGCSHIFT 0x7f
+#define BTRSW_TRI_ONLY 0x80
+#define BPOWER_THRES 0x300
+#define BRXAGC_EN 0x1
+#define BRXAGC_TOGETHER_EN 0x2
+#define BRXAGC_MIN 0x4
+#define BRXHP_INI 0x7
+#define BRXHP_TRLNA 0x70
+#define BRXHP_RSSI 0x700
+#define BRXHP_BBP1 0x7000
+#define BRXHP_BBP2 0x70000
+#define BRXHP_BBP3 0x700000
+#define BRSSI_H 0x7f0000
+#define BRSSI_GEN 0x7f000000
+#define BRXSETTLE_TRSW 0x7
+#define BRXSETTLE_LNA 0x38
+#define BRXSETTLE_RSSI 0x1c0
+#define BRXSETTLE_BBP 0xe00
+#define BRXSETTLE_RXHP 0x7000
+#define BRXSETTLE_ANTSW_RSSI 0x38000
+#define BRXSETTLE_ANTSW 0xc0000
+#define BRXPROCESS_TIME_DAGC 0x300000
+#define BRXSETTLE_HSSI 0x400000
+#define BRXPROCESS_TIME_BBPPW 0x800000
+#define BRXANTENNA_POWER_SHIFT 0x3000000
+#define BRSSI_TABLE_SELECT 0xc000000
+#define BRXHP_FINAL 0x7000000
+#define BRXHPSETTLE_BBP 0x7
+#define BRXHTSETTLE_HSSI 0x8
+#define BRXHTSETTLE_RXHP 0x70
+#define BRXHTSETTLE_BBPPW 0x80
+#define BRXHTSETTLE_IDLE 0x300
+#define BRXHTSETTLE_RESERVED 0x1c00
+#define BRXHT_RXHP_EN 0x8000
+#define BRXAGC_FREEZE_THRES 0x30000
+#define BRXAGC_TOGETHEREN 0x40000
+#define BRXHTAGC_MIN 0x80000
+#define BRXHTAGC_EN 0x100000
+#define BRXHTDAGC_EN 0x200000
+#define BRXHT_RXHP_BBP 0x1c00000
+#define BRXHT_RXHP_FINAL 0xe0000000
+#define BRXPW_RADIO_TH 0x3
+#define BRXPW_RADIO_EN 0x4
+#define BRXMF_HOLD 0x3800
+#define BRXPD_DELAY_TH1 0x38
+#define BRXPD_DELAY_TH2 0x1c0
+#define BRXPD_DC_COUNT_MAX 0x600
+#define BRXPD_DELAY_TH 0x8000
+#define BRXPROCESS_DELAY 0xf0000
+#define BRXSEARCHRANGE_GI2_EARLY 0x700000
+#define BRXFRAME_FUARD_COUNTER_L 0x3800000
+#define BRXSGI_GUARD_L 0xc000000
+#define BRXSGI_SEARCH_L 0x30000000
+#define BRXSGI_TH 0xc0000000
+#define BDFSCNT0 0xff
+#define BDFSCNT1 0xff00
+#define BDFSFLAG 0xf0000
+#define BMF_WEIGHT_SUM 0x300000
+#define BMINIDX_TH 0x7f000000
+#define BDAFORMAT 0x40000
+#define BTXCH_EMU_ENABLE 0x01000000
+#define BTRSW_ISOLATION_A 0x7f
+#define BTRSW_ISOLATION_B 0x7f00
+#define BTRSW_ISOLATION_C 0x7f0000
+#define BTRSW_ISOLATION_D 0x7f000000
+#define BEXT_LNA_GAIN 0x7c00
+
+#define BSTBC_EN 0x4
+#define BANTENNA_MAPPING 0x10
+#define BNSS 0x20
+#define BCFO_ANTSUM_ID 0x200
+#define BPHY_COUNTER_RESET 0x8000000
+#define BCFO_REPORT_GET 0x4000000
+#define BOFDM_CONTINUE_TX 0x10000000
+#define BOFDM_SINGLE_CARRIER 0x20000000
+#define BOFDM_SINGLE_TONE 0x40000000
+#define BHT_DETECT 0x100
+#define BCFOEN 0x10000
+#define BCFOVALUE 0xfff00000
+#define BSIGTONE_RE 0x3f
+#define BSIGTONE_IM 0x7f00
+#define BCOUNTER_CCA 0xffff
+#define BCOUNTER_PARITYFAIL 0xffff0000
+#define BCOUNTER_RATEILLEGAL 0xffff
+#define BCOUNTER_CRC8FAIL 0xffff0000
+#define BCOUNTER_MCSNOSUPPORT 0xffff
+#define BCOUNTER_FASTSYNC 0xffff
+#define BSHORTCFO 0xfff
+#define BSHORTCFOT_LENGTH 12
+#define BSHORTCFOF_LENGTH 11
+#define BLONGCFO 0x7ff
+#define BLONGCFOT_LENGTH 11
+#define BLONGCFOF_LENGTH 11
+#define BTAILCFO 0x1fff
+#define BTAILCFOT_LENGTH 13
+#define BTAILCFOF_LENGTH 12
+#define BNOISE_EN_PWDB 0xffff
+#define BCC_POWER_DB 0xffff0000
+#define BMOISE_PWDB 0xffff
+#define BPOWERMEAST_LENGTH 10
+#define BPOWERMEASF_LENGTH 3
+#define BRX_HT_BW 0x1
+#define BRXSC 0x6
+#define BRX_HT 0x8
+#define BNB_INTF_DET_ON 0x1
+#define BINTF_WIN_LEN_CFG 0x30
+#define BNB_INTF_TH_CFG 0x1c0
+#define BRFGAIN 0x3f
+#define BTABLESEL 0x40
+#define BTRSW 0x80
+#define BRXSNR_A 0xff
+#define BRXSNR_B 0xff00
+#define BRXSNR_C 0xff0000
+#define BRXSNR_D 0xff000000
+#define BSNR_EVMT_LENGTH 8
+#define BSNR_EVMF_LENGTH 1
+#define BCSI1ST 0xff
+#define BCSI2ND 0xff00
+#define BRXEVM1ST 0xff0000
+#define BRXEVM2ND 0xff000000
+#define BSIGEVM 0xff
+#define BPWDB 0xff00
+#define BSGIEN 0x10000
+
+#define BSFACTOR_QMA1 0xf
+#define BSFACTOR_QMA2 0xf0
+#define BSFACTOR_QMA3 0xf00
+#define BSFACTOR_QMA4 0xf000
+#define BSFACTOR_QMA5 0xf0000
+#define BSFACTOR_QMA6 0xf0000
+#define BSFACTOR_QMA7 0xf00000
+#define BSFACTOR_QMA8 0xf000000
+#define BSFACTOR_QMA9 0xf0000000
+#define BCSI_SCHEME 0x100000
+
+#define BNOISE_LVL_TOP_SET 0x3
+#define BCHSMOOTH 0x4
+#define BCHSMOOTH_CFG1 0x38
+#define BCHSMOOTH_CFG2 0x1c0
+#define BCHSMOOTH_CFG3 0xe00
+#define BCHSMOOTH_CFG4 0x7000
+#define BMRCMODE 0x800000
+#define BTHEVMCFG 0x7000000
+
+#define BLOOP_FIT_TYPE 0x1
+#define BUPD_CFO 0x40
+#define BUPD_CFO_OFFDATA 0x80
+#define BADV_UPD_CFO 0x100
+#define BADV_TIME_CTRL 0x800
+#define BUPD_CLKO 0x1000
+#define BFC 0x6000
+#define BTRACKING_MODE 0x8000
+#define BPHCMP_ENABLE 0x10000
+#define BUPD_CLKO_LTF 0x20000
+#define BCOM_CH_CFO 0x40000
+#define BCSI_ESTI_MODE 0x80000
+#define BADV_UPD_EQZ 0x100000
+#define BUCHCFG 0x7000000
+#define BUPDEQZ 0x8000000
+
+#define BRX_PESUDO_NOISE_ON 0x20000000
+#define BRX_PESUDO_NOISE_A 0xff
+#define BRX_PESUDO_NOISE_B 0xff00
+#define BRX_PESUDO_NOISE_C 0xff0000
+#define BRX_PESUDO_NOISE_D 0xff000000
+#define BRX_PESUDO_NOISESTATE_A 0xffff
+#define BRX_PESUDO_NOISESTATE_B 0xffff0000
+#define BRX_PESUDO_NOISESTATE_C 0xffff
+#define BRX_PESUDO_NOISESTATE_D 0xffff0000
+
+#define BZEBRA1_HSSIENABLE 0x8
+#define BZEBRA1_TRXCONTROL 0xc00
+#define BZEBRA1_TRXGAINSETTING 0x07f
+#define BZEBRA1_RXCOUNTER 0xc00
+#define BZEBRA1_TXCHANGEPUMP 0x38
+#define BZEBRA1_RXCHANGEPUMP 0x7
+#define BZEBRA1_CHANNEL_NUM 0xf80
+#define BZEBRA1_TXLPFBW 0x400
+#define BZEBRA1_RXLPFBW 0x600
+
+#define BRTL8256REG_MODE_CTRL1 0x100
+#define BRTL8256REG_MODE_CTRL0 0x40
+#define BRTL8256REG_TXLPFBW 0x18
+#define BRTL8256REG_RXLPFBW 0x600
+
+#define BRTL8258_TXLPFBW 0xc
+#define BRTL8258_RXLPFBW 0xc00
+#define BRTL8258_RSSILPFBW 0xc0
+
+#define BBYTE0 0x1
+#define BBYTE1 0x2
+#define BBYTE2 0x4
+#define BBYTE3 0x8
+#define BWORD0 0x3
+#define BWORD1 0xc
+#define BWORD 0xf
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+#define MASK12BITS 0xfff
+#define MASKH4BITS 0xf0000000
+#define MASKOFDM_D 0xffc00000
+#define MASKCCK 0x3f3f3f3f
+
+#define MASK4BITS 0x0f
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#define BENABLE 0x1
+#define BDISABLE 0x0
+
+#define LEFT_ANTENNA 0x0
+#define RIGHT_ANTENNA 0x1
+
+#define TCHECK_TXSTATUS 500
+#define TUPDATE_RXCOUNTER 100
+
+#define REG_UN_USED_REGISTER 0x01bf
+
+/* WOL bit information */
+#define HAL92C_WOL_PTK_UPDATE_EVENT BIT(0)
+#define HAL92C_WOL_GTK_UPDATE_EVENT BIT(1)
+#define HAL92C_WOL_DISASSOC_EVENT BIT(2)
+#define HAL92C_WOL_DEAUTH_EVENT BIT(3)
+#define HAL92C_WOL_FW_DISCONNECT_EVENT BIT(4)
+
+#define WOL_REASON_PTK_UPDATE BIT(0)
+#define WOL_REASON_GTK_UPDATE BIT(1)
+#define WOL_REASON_DISASSOC BIT(2)
+#define WOL_REASON_DEAUTH BIT(3)
+#define WOL_REASON_FW_DISCONNECT BIT(4)
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
new file mode 100644
index 000000000000..4faafdbab9c6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.c
@@ -0,0 +1,467 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10) | BIT(11));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | BIT(10));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "unknown bandwidth: %#X\n", bandwidth);
+ break;
+ }
+}
+
+void rtl88e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *plevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 tx_agc[2] = {0, 0}, tmpval;
+ bool turbo_scanoff = false;
+ u8 idx1, idx2;
+ u8 *ptr;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ if (rtlefuse->eeprom_regulatory != 0)
+ turbo_scanoff = true;
+
+ if (mac->act_scanning == true) {
+ tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+ tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+ if (turbo_scanoff) {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = plevel[idx1] |
+ (plevel[idx1] << 8) |
+ (plevel[idx1] << 16) |
+ (plevel[idx1] << 24);
+ }
+ }
+ } else {
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ tx_agc[idx1] = plevel[idx1] | (plevel[idx1] << 8) |
+ (plevel[idx1] << 16) |
+ (plevel[idx1] << 24);
+ }
+
+ if (rtlefuse->eeprom_regulatory == 0) {
+ tmpval = (rtlphy->mcs_offset[0][6]) +
+ (rtlphy->mcs_offset[0][7] << 8);
+ tx_agc[RF90_PATH_A] += tmpval;
+
+ tmpval = (rtlphy->mcs_offset[0][14]) +
+ (rtlphy->mcs_offset[0][15] << 24);
+ tx_agc[RF90_PATH_B] += tmpval;
+ }
+ }
+
+ for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+ ptr = (u8 *)(&(tx_agc[idx1]));
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if (*ptr > RF6052_MAX_TX_PWR)
+ *ptr = RF6052_MAX_TX_PWR;
+ ptr++;
+ }
+ }
+ rtl88e_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+ if (direction == 1) {
+ tx_agc[0] += pwrtrac_value;
+ tx_agc[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ tx_agc[0] -= pwrtrac_value;
+ tx_agc[1] -= pwrtrac_value;
+ }
+ tmpval = tx_agc[RF90_PATH_A] & 0xff;
+ rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_A_CCK1_MCS32);
+
+ tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] >> 24;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK11_A_CCK2_11);
+
+ tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+ rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+ RTXAGC_B_CCK1_55_MCS32);
+}
+
+static void rtl88e_phy_get_power_base(struct ieee80211_hw *hw,
+ u8 *pwrlvlofdm, u8 *pwrlvlbw20,
+ u8 *pwrlvlbw40, u8 channel,
+ u32 *ofdmbase, u32 *mcsbase)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 base0, base1;
+ u8 i, powerlevel[2];
+
+ for (i = 0; i < 2; i++) {
+ base0 = pwrlvlofdm[i];
+
+ base0 = (base0 << 24) | (base0 << 16) |
+ (base0 << 8) | base0;
+ *(ofdmbase + i) = base0;
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "[OFDM power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+ }
+
+ for (i = 0; i < 2; i++) {
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+ powerlevel[i] = pwrlvlbw20[i];
+ else
+ powerlevel[i] = pwrlvlbw40[i];
+ base1 = powerlevel[i];
+ base1 = (base1 << 24) |
+ (base1 << 16) | (base1 << 8) | base1;
+
+ *(mcsbase + i) = base1;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "[MCS power base index rf(%c) = 0x%x]\n",
+ ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+ }
+}
+
+static void get_txpwr_by_reg(struct ieee80211_hw *hw, u8 chan, u8 index,
+ u32 *base0, u32 *base1, u32 *outval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chg = 0, pwr_lim[4], pwr_diff = 0, cust_pwr_dif;
+ u32 writeval, cust_lim, rf, tmp;
+ u8 ch = chan - 1;
+ u8 j;
+
+ for (rf = 0; rf < 2; rf++) {
+ j = index + (rf ? 8 : 0);
+ tmp = ((index < 2) ? base0[rf] : base1[rf]);
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ chg = 0;
+
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "RTK better performance, "
+ "writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 1:
+ if (rtlphy->pwrgroup_cnt == 1) {
+ chg = 0;
+ } else {
+ chg = chan / 3;
+ if (chan == 14)
+ chg = 5;
+ }
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Realtek regulatory, 20MHz, writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 2:
+ writeval = ((index < 2) ? base0[rf] : base1[rf]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Better regulatory, writeval(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ case 3:
+ chg = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "customer's limit, 40MHz rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht40[rf][ch]);
+ } else {
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "customer's limit, 20MHz rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'),
+ rtlefuse->pwrgroup_ht20[rf][ch]);
+ }
+
+ if (index < 2)
+ pwr_diff = rtlefuse->txpwr_legacyhtdiff[rf][ch];
+ else if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20)
+ pwr_diff = rtlefuse->txpwr_ht20diff[rf][ch];
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+ cust_pwr_dif = rtlefuse->pwrgroup_ht40[rf][ch];
+ else
+ cust_pwr_dif = rtlefuse->pwrgroup_ht20[rf][ch];
+
+ if (pwr_diff > cust_pwr_dif)
+ pwr_diff = 0;
+ else
+ pwr_diff = cust_pwr_dif - pwr_diff;
+
+ for (i = 0; i < 4; i++) {
+ pwr_lim[i] = (u8)((rtlphy->mcs_offset[chg][j] &
+ (0x7f << (i * 8))) >> (i * 8));
+
+ if (pwr_lim[i] > pwr_diff)
+ pwr_lim[i] = pwr_diff;
+ }
+
+ cust_lim = (pwr_lim[3] << 24) | (pwr_lim[2] << 16) |
+ (pwr_lim[1] << 8) | (pwr_lim[0]);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Customer's limit rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), cust_lim);
+
+ writeval = cust_lim + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Customer, writeval rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ default:
+ chg = 0;
+ writeval = rtlphy->mcs_offset[chg][j] + tmp;
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "RTK better performance, writeval "
+ "rf(%c) = 0x%x\n",
+ ((rf == 0) ? 'A' : 'B'), writeval);
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+ writeval = writeval - 0x06060606;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TXHIGHPWRLEVEL_BT2)
+ writeval -= 0x0c0c0c0c;
+ *(outval + rf) = writeval;
+ }
+}
+
+static void write_ofdm_pwr(struct ieee80211_hw *hw, u8 index, u32 *pvalue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regoffset_a[6] = {
+ RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
+ RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+ RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+ };
+ u16 regoffset_b[6] = {
+ RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
+ RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+ RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+ };
+ u8 i, rf, pwr_val[4];
+ u32 writeval;
+ u16 regoffset;
+
+ for (rf = 0; rf < 2; rf++) {
+ writeval = pvalue[rf];
+ for (i = 0; i < 4; i++) {
+ pwr_val[i] = (u8) ((writeval & (0x7f <<
+ (i * 8))) >> (i * 8));
+
+ if (pwr_val[i] > RF6052_MAX_TX_PWR)
+ pwr_val[i] = RF6052_MAX_TX_PWR;
+ }
+ writeval = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+ (pwr_val[1] << 8) | pwr_val[0];
+
+ if (rf == 0)
+ regoffset = regoffset_a[index];
+ else
+ regoffset = regoffset_b[index];
+ rtl_set_bbreg(hw, regoffset, MASKDWORD, writeval);
+
+ RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+ "Set 0x%x = %08x\n", regoffset, writeval);
+ }
+}
+
+void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *pwrlvlofdm,
+ u8 *pwrlvlbw20,
+ u8 *pwrlvlbw40, u8 chan)
+{
+ u32 writeval[2], base0[2], base1[2];
+ u8 index;
+ u8 direction;
+ u32 pwrtrac_value;
+
+ rtl88e_phy_get_power_base(hw, pwrlvlofdm, pwrlvlbw20,
+ pwrlvlbw40, chan, &base0[0],
+ &base1[0]);
+
+ rtl88e_dm_txpower_track_adjust(hw, 1, &direction, &pwrtrac_value);
+
+ for (index = 0; index < 6; index++) {
+ get_txpwr_by_reg(hw, chan, index, &base0[0], &base1[0],
+ &writeval[0]);
+ if (direction == 1) {
+ writeval[0] += pwrtrac_value;
+ writeval[1] += pwrtrac_value;
+ } else if (direction == 2) {
+ writeval[0] -= pwrtrac_value;
+ writeval[1] -= pwrtrac_value;
+ }
+ write_ofdm_pwr(hw, index, &writeval[0]);
+ }
+}
+
+static bool rf6052_conf_para(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 u4val = 0;
+ u8 rfpath;
+ bool rtstatus = true;
+ struct bb_reg_def *pphyreg;
+
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4val = rtl_get_bbreg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+ B3WIREADDREAALENGTH, 0x0);
+ udelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+ udelay(1);
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl88e_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV, u4val);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl_set_bbreg(hw, pphyreg->rfintfs, BRFSI_RFENV << 16,
+ u4val);
+ break;
+ }
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Radio[%d] Fail!!", rfpath);
+ return false;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
+ return rtstatus;
+}
+
+bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ return rf6052_conf_para(hw);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
new file mode 100644
index 000000000000..a39a2a3dbcc9
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/rf.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_RF_H__
+#define __RTL92C_RF_H__
+
+#define RF6052_MAX_TX_PWR 0x3F
+#define RF6052_MAX_REG 0x3F
+
+void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+void rtl88e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+void rtl88e_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel_ofdm,
+ u8 *ppowerlevel_bw20,
+ u8 *ppowerlevel_bw40, u8 channel);
+bool rtl88e_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
new file mode 100644
index 000000000000..c254693a1e6a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
@@ -0,0 +1,400 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /* ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ */
+ rtlpci->const_pci_aspm = 3;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /* In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 0;
+
+ /* This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
+{
+ int err = 0;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 tid;
+
+ rtl8188ee_bt_reg_init(hw);
+
+ rtlpriv->dm.dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.disable_framebursting = 0;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpci->transmit_config = CFENDFORM | BIT(15);
+
+ /* compatible 5G band 88ce just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->receive_config = (RCR_APPFCS |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_APP_PHYST_RXFF |
+ RCR_HTC_LOC_CTRL |
+ RCR_AMF |
+ RCR_ACF |
+ RCR_ADF |
+ RCR_AICV |
+ RCR_ACRC32 |
+ RCR_AB |
+ RCR_AM |
+ RCR_APM |
+ 0);
+
+ rtlpci->irq_mask[0] =
+ (u32) (IMR_PSTIMEOUT |
+ IMR_HSISR_IND_ON_INT |
+ IMR_C2HCMD |
+ IMR_HIGHDOK |
+ IMR_MGNTDOK |
+ IMR_BKDOK |
+ IMR_BEDOK |
+ IMR_VIDOK |
+ IMR_VODOK |
+ IMR_RDU |
+ IMR_ROK |
+ 0);
+ rtlpci->irq_mask[1] = (u32) (IMR_RXFOVW | 0);
+ rtlpci->sys_irq_mask = (u32) (HSIMR_PDN_INT_EN | HSIMR_RON_INT_EN);
+
+ /* for debug level */
+ rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ if (!rtlpriv->psc.inactiveps)
+ pr_info("rtl8188ee: Power Save off (module option)\n");
+ if (!rtlpriv->psc.fwctrl_lps)
+ pr_info("rtl8188ee: FW Power Save off (module option)\n");
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0
+ */
+ rtl88e_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vmalloc(0x8000);
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Can't alloc buffer for fw.\n");
+ return 1;
+ }
+
+ rtlpriv->cfg->fw_name = "rtlwifi/rtl8188efw.bin";
+ rtlpriv->max_fw_size = 0x8000;
+ pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+ err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev, GFP_KERNEL, hw,
+ rtl_fw_cb);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to request firmware!\n");
+ return 1;
+ }
+
+ /* for early mode */
+ rtlpriv->rtlhal.earlymode_enable = false;
+ rtlpriv->rtlhal.max_earlymode_num = 10;
+ for (tid = 0; tid < 8; tid++)
+ skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
+
+ /*low power */
+ rtlpriv->psc.low_power_enable = false;
+ if (rtlpriv->psc.low_power_enable) {
+ init_timer(&rtlpriv->works.fw_clockoff_timer);
+ setup_timer(&rtlpriv->works.fw_clockoff_timer,
+ rtl88ee_fw_clk_off_timer_callback,
+ (unsigned long)hw);
+ }
+
+ init_timer(&rtlpriv->works.fast_antenna_training_timer);
+ setup_timer(&rtlpriv->works.fast_antenna_training_timer,
+ rtl88e_dm_fast_antenna_training_callback,
+ (unsigned long)hw);
+ return err;
+}
+
+void rtl88e_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+
+ if (rtlpriv->psc.low_power_enable)
+ del_timer_sync(&rtlpriv->works.fw_clockoff_timer);
+
+ del_timer_sync(&rtlpriv->works.fast_antenna_training_timer);
+}
+
+static struct rtl_hal_ops rtl8188ee_hal_ops = {
+ .init_sw_vars = rtl88e_init_sw_vars,
+ .deinit_sw_vars = rtl88e_deinit_sw_vars,
+ .read_eeprom_info = rtl88ee_read_eeprom_info,
+ .interrupt_recognized = rtl88ee_interrupt_recognized,/*need check*/
+ .hw_init = rtl88ee_hw_init,
+ .hw_disable = rtl88ee_card_disable,
+ .hw_suspend = rtl88ee_suspend,
+ .hw_resume = rtl88ee_resume,
+ .enable_interrupt = rtl88ee_enable_interrupt,
+ .disable_interrupt = rtl88ee_disable_interrupt,
+ .set_network_type = rtl88ee_set_network_type,
+ .set_chk_bssid = rtl88ee_set_check_bssid,
+ .set_qos = rtl88ee_set_qos,
+ .set_bcn_reg = rtl88ee_set_beacon_related_registers,
+ .set_bcn_intv = rtl88ee_set_beacon_interval,
+ .update_interrupt_mask = rtl88ee_update_interrupt_mask,
+ .get_hw_reg = rtl88ee_get_hw_reg,
+ .set_hw_reg = rtl88ee_set_hw_reg,
+ .update_rate_tbl = rtl88ee_update_hal_rate_tbl,
+ .fill_tx_desc = rtl88ee_tx_fill_desc,
+ .fill_tx_cmddesc = rtl88ee_tx_fill_cmddesc,
+ .query_rx_desc = rtl88ee_rx_query_desc,
+ .set_channel_access = rtl88ee_update_channel_access_setting,
+ .radio_onoff_checking = rtl88ee_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl88e_phy_set_bw_mode,
+ .switch_channel = rtl88e_phy_sw_chnl,
+ .dm_watchdog = rtl88e_dm_watchdog,
+ .scan_operation_backup = rtl88e_phy_scan_operation_backup,
+ .set_rf_power_state = rtl88e_phy_set_rf_power_state,
+ .led_control = rtl88ee_led_control,
+ .set_desc = rtl88ee_set_desc,
+ .get_desc = rtl88ee_get_desc,
+ .tx_polling = rtl88ee_tx_polling,
+ .enable_hw_sec = rtl88ee_enable_hw_security_config,
+ .set_key = rtl88ee_set_key,
+ .init_sw_leds = rtl88ee_init_sw_leds,
+ .allow_all_destaddr = rtl88ee_allow_all_destaddr,
+ .get_bbreg = rtl88e_phy_query_bb_reg,
+ .set_bbreg = rtl88e_phy_set_bb_reg,
+ .get_rfreg = rtl88e_phy_query_rf_reg,
+ .set_rfreg = rtl88e_phy_set_rf_reg,
+};
+
+static struct rtl_mod_params rtl88ee_mod_params = {
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = false,
+ .fwctrl_lps = true,
+ .debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl88ee_hal_cfg = {
+ .bar_id = 2,
+ .write_readback = true,
+ .name = "rtl88e_pci",
+ .ops = &rtl8188ee_hal_ops,
+ .mod_params = &rtl88ee_mod_params,
+
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = REG_SYS_CLKR,
+ .maps[MAC_RCR_AM] = AM,
+ .maps[MAC_RCR_AB] = AB,
+ .maps[MAC_RCR_ACRC32] = ACRC32,
+ .maps[MAC_RCR_ACF] = ACF,
+ .maps[MAC_RCR_AAP] = AAP,
+
+ .maps[EFUSE_ACCESS] = REG_EFUSE_ACCESS,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = 0,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+ .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+ .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+ .maps[EFUSE_ANA8M] = ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+ .maps[RWCAM] = REG_CAMCMD,
+ .maps[WCAMI] = REG_CAMWRITE,
+ .maps[RCAMO] = REG_CAMREAD,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECCFG,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+/* .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8, */ /*need check*/
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+/* .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,*/
+/* .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,*/
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNDMAINT0,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BCNDOK0,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNDMAINT0 | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(rtl88ee_pci_ids) = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8179, rtl88ee_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl88ee_pci_ids);
+
+MODULE_AUTHOR("zhiyuan_yang <zhiyuan_yang@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8188E 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8188efw.bin");
+
+module_param_named(swenc, rtl88ee_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl88ee_mod_params.debug, int, 0444);
+module_param_named(ips, rtl88ee_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl88ee_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl88ee_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
+
+static struct pci_driver rtl88ee_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl88ee_pci_ids,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+ .driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl88ee_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
new file mode 100644
index 000000000000..85e02b3bdff8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/sw.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_SW_H__
+#define __RTL92CE_SW_H__
+
+int rtl88e_init_sw_vars(struct ieee80211_hw *hw);
+void rtl88e_deinit_sw_vars(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.c b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
new file mode 100644
index 000000000000..fad373f97b2c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.c
@@ -0,0 +1,643 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+
+u32 RTL8188EEPHY_REG_1TARRAY[] = {
+ 0x800, 0x80040000,
+ 0x804, 0x00000003,
+ 0x808, 0x0000FC00,
+ 0x80C, 0x0000000A,
+ 0x810, 0x10001331,
+ 0x814, 0x020C3D10,
+ 0x818, 0x02200385,
+ 0x81C, 0x00000000,
+ 0x820, 0x01000100,
+ 0x824, 0x00390204,
+ 0x828, 0x00000000,
+ 0x82C, 0x00000000,
+ 0x830, 0x00000000,
+ 0x834, 0x00000000,
+ 0x838, 0x00000000,
+ 0x83C, 0x00000000,
+ 0x840, 0x00010000,
+ 0x844, 0x00000000,
+ 0x848, 0x00000000,
+ 0x84C, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x569A11A9,
+ 0x85C, 0x01000014,
+ 0x860, 0x66F60110,
+ 0x864, 0x061F0649,
+ 0x868, 0x00000000,
+ 0x86C, 0x27272700,
+ 0x870, 0x07000760,
+ 0x874, 0x25004000,
+ 0x878, 0x00000808,
+ 0x87C, 0x00000000,
+ 0x880, 0xB0000C1C,
+ 0x884, 0x00000001,
+ 0x888, 0x00000000,
+ 0x88C, 0xCCC000C0,
+ 0x890, 0x00000800,
+ 0x894, 0xFFFFFFFE,
+ 0x898, 0x40302010,
+ 0x89C, 0x00706050,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90C, 0x81121111,
+ 0x910, 0x00000002,
+ 0x914, 0x00000201,
+ 0xA00, 0x00D047C8,
+ 0xA04, 0x80FF000C,
+ 0xA08, 0x8C838300,
+ 0xA0C, 0x2E7F120F,
+ 0xA10, 0x9500BB78,
+ 0xA14, 0x1114D028,
+ 0xA18, 0x00881117,
+ 0xA1C, 0x89140F00,
+ 0xA20, 0x1A1B0000,
+ 0xA24, 0x090E1317,
+ 0xA28, 0x00000204,
+ 0xA2C, 0x00D30000,
+ 0xA70, 0x101FBF00,
+ 0xA74, 0x00000007,
+ 0xA78, 0x00000900,
+ 0xA7C, 0x225B0606,
+ 0xA80, 0x218075B1,
+ 0xB2C, 0x80000000,
+ 0xC00, 0x48071D40,
+ 0xC04, 0x03A05611,
+ 0xC08, 0x000000E4,
+ 0xC0C, 0x6C6C6C6C,
+ 0xC10, 0x08800000,
+ 0xC14, 0x40000100,
+ 0xC18, 0x08800000,
+ 0xC1C, 0x40000100,
+ 0xC20, 0x00000000,
+ 0xC24, 0x00000000,
+ 0xC28, 0x00000000,
+ 0xC2C, 0x00000000,
+ 0xC30, 0x69E9AC47,
+ 0xC34, 0x469652AF,
+ 0xC38, 0x49795994,
+ 0xC3C, 0x0A97971C,
+ 0xC40, 0x1F7C403F,
+ 0xC44, 0x000100B7,
+ 0xC48, 0xEC020107,
+ 0xC4C, 0x007F037F,
+ 0xC50, 0x69553420,
+ 0xC54, 0x43BC0094,
+ 0xC58, 0x00013169,
+ 0xC5C, 0x00250492,
+ 0xC60, 0x00000000,
+ 0xC64, 0x7112848B,
+ 0xC68, 0x47C00BFF,
+ 0xC6C, 0x00000036,
+ 0xC70, 0x2C7F000D,
+ 0xC74, 0x020610DB,
+ 0xC78, 0x0000001F,
+ 0xC7C, 0x00B91612,
+ 0xC80, 0x390000E4,
+ 0xC84, 0x20F60000,
+ 0xC88, 0x40000100,
+ 0xC8C, 0x20200000,
+ 0xC90, 0x00091521,
+ 0xC94, 0x00000000,
+ 0xC98, 0x00121820,
+ 0xC9C, 0x00007F7F,
+ 0xCA0, 0x00000000,
+ 0xCA4, 0x000300A0,
+ 0xCA8, 0x00000000,
+ 0xCAC, 0x00000000,
+ 0xCB0, 0x00000000,
+ 0xCB4, 0x00000000,
+ 0xCB8, 0x00000000,
+ 0xCBC, 0x28000000,
+ 0xCC0, 0x00000000,
+ 0xCC4, 0x00000000,
+ 0xCC8, 0x00000000,
+ 0xCCC, 0x00000000,
+ 0xCD0, 0x00000000,
+ 0xCD4, 0x00000000,
+ 0xCD8, 0x64B22427,
+ 0xCDC, 0x00766932,
+ 0xCE0, 0x00222222,
+ 0xCE4, 0x00000000,
+ 0xCE8, 0x37644302,
+ 0xCEC, 0x2F97D40C,
+ 0xD00, 0x00000740,
+ 0xD04, 0x00020401,
+ 0xD08, 0x0000907F,
+ 0xD0C, 0x20010201,
+ 0xD10, 0xA0633333,
+ 0xD14, 0x3333BC43,
+ 0xD18, 0x7A8F5B6F,
+ 0xD2C, 0xCC979975,
+ 0xD30, 0x00000000,
+ 0xD34, 0x80608000,
+ 0xD38, 0x00000000,
+ 0xD3C, 0x00127353,
+ 0xD40, 0x00000000,
+ 0xD44, 0x00000000,
+ 0xD48, 0x00000000,
+ 0xD4C, 0x00000000,
+ 0xD50, 0x6437140A,
+ 0xD54, 0x00000000,
+ 0xD58, 0x00000282,
+ 0xD5C, 0x30032064,
+ 0xD60, 0x4653DE68,
+ 0xD64, 0x04518A3C,
+ 0xD68, 0x00002101,
+ 0xD6C, 0x2A201C16,
+ 0xD70, 0x1812362E,
+ 0xD74, 0x322C2220,
+ 0xD78, 0x000E3C24,
+ 0xE00, 0x2D2D2D2D,
+ 0xE04, 0x2D2D2D2D,
+ 0xE08, 0x0390272D,
+ 0xE10, 0x2D2D2D2D,
+ 0xE14, 0x2D2D2D2D,
+ 0xE18, 0x2D2D2D2D,
+ 0xE1C, 0x2D2D2D2D,
+ 0xE28, 0x00000000,
+ 0xE30, 0x1000DC1F,
+ 0xE34, 0x10008C1F,
+ 0xE38, 0x02140102,
+ 0xE3C, 0x681604C2,
+ 0xE40, 0x01007C00,
+ 0xE44, 0x01004800,
+ 0xE48, 0xFB000000,
+ 0xE4C, 0x000028D1,
+ 0xE50, 0x1000DC1F,
+ 0xE54, 0x10008C1F,
+ 0xE58, 0x02140102,
+ 0xE5C, 0x28160D05,
+ 0xE60, 0x00000008,
+ 0xE68, 0x001B25A4,
+ 0xE6C, 0x00C00014,
+ 0xE70, 0x00C00014,
+ 0xE74, 0x01000014,
+ 0xE78, 0x01000014,
+ 0xE7C, 0x01000014,
+ 0xE80, 0x01000014,
+ 0xE84, 0x00C00014,
+ 0xE88, 0x01000014,
+ 0xE8C, 0x00C00014,
+ 0xED0, 0x00C00014,
+ 0xED4, 0x00C00014,
+ 0xED8, 0x00C00014,
+ 0xEDC, 0x00000014,
+ 0xEE0, 0x00000014,
+ 0xEEC, 0x01C00014,
+ 0xF14, 0x00000003,
+ 0xF4C, 0x00000000,
+ 0xF00, 0x00000300,
+
+};
+
+u32 RTL8188EEPHY_REG_ARRAY_PG[] = {
+ 0xE00, 0xFFFFFFFF, 0x06070809,
+ 0xE04, 0xFFFFFFFF, 0x02020405,
+ 0xE08, 0x0000FF00, 0x00000006,
+ 0x86C, 0xFFFFFF00, 0x00020400,
+ 0xE10, 0xFFFFFFFF, 0x08090A0B,
+ 0xE14, 0xFFFFFFFF, 0x01030607,
+ 0xE18, 0xFFFFFFFF, 0x08090A0B,
+ 0xE1C, 0xFFFFFFFF, 0x01030607,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x02020202,
+ 0xE04, 0xFFFFFFFF, 0x00020202,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x04040404,
+ 0xE14, 0xFFFFFFFF, 0x00020404,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+ 0xE00, 0xFFFFFFFF, 0x00000000,
+ 0xE04, 0xFFFFFFFF, 0x00000000,
+ 0xE08, 0x0000FF00, 0x00000000,
+ 0x86C, 0xFFFFFF00, 0x00000000,
+ 0xE10, 0xFFFFFFFF, 0x00000000,
+ 0xE14, 0xFFFFFFFF, 0x00000000,
+ 0xE18, 0xFFFFFFFF, 0x00000000,
+ 0xE1C, 0xFFFFFFFF, 0x00000000,
+
+};
+
+u32 RTL8188EE_RADIOA_1TARRAY[] = {
+ 0x000, 0x00030000,
+ 0x008, 0x00084000,
+ 0x018, 0x00000407,
+ 0x019, 0x00000012,
+ 0x01E, 0x00080009,
+ 0x01F, 0x00000880,
+ 0x02F, 0x0001A060,
+ 0x03F, 0x00000000,
+ 0x042, 0x000060C0,
+ 0x057, 0x000D0000,
+ 0x058, 0x000BE180,
+ 0x067, 0x00001552,
+ 0x083, 0x00000000,
+ 0x0B0, 0x000FF8FC,
+ 0x0B1, 0x00054400,
+ 0x0B2, 0x000CCC19,
+ 0x0B4, 0x00043003,
+ 0x0B6, 0x0004953E,
+ 0x0B7, 0x0001C718,
+ 0x0B8, 0x000060FF,
+ 0x0B9, 0x00080001,
+ 0x0BA, 0x00040000,
+ 0x0BB, 0x00000400,
+ 0x0BF, 0x000C0000,
+ 0x0C2, 0x00002400,
+ 0x0C3, 0x00000009,
+ 0x0C4, 0x00040C91,
+ 0x0C5, 0x00099999,
+ 0x0C6, 0x000000A3,
+ 0x0C7, 0x00088820,
+ 0x0C8, 0x00076C06,
+ 0x0C9, 0x00000000,
+ 0x0CA, 0x00080000,
+ 0x0DF, 0x00000180,
+ 0x0EF, 0x000001A0,
+ 0x051, 0x0006B27D,
+ 0x052, 0x0007E49D,
+ 0x053, 0x00000073,
+ 0x056, 0x00051FF3,
+ 0x035, 0x00000086,
+ 0x035, 0x00000186,
+ 0x035, 0x00000286,
+ 0x036, 0x00001C25,
+ 0x036, 0x00009C25,
+ 0x036, 0x00011C25,
+ 0x036, 0x00019C25,
+ 0x0B6, 0x00048538,
+ 0x018, 0x00000C07,
+ 0x05A, 0x0004BD00,
+ 0x019, 0x000739D0,
+ 0x034, 0x0000ADF3,
+ 0x034, 0x00009DF0,
+ 0x034, 0x00008DED,
+ 0x034, 0x00007DEA,
+ 0x034, 0x00006DE7,
+ 0x034, 0x000054EE,
+ 0x034, 0x000044EB,
+ 0x034, 0x000034E8,
+ 0x034, 0x0000246B,
+ 0x034, 0x00001468,
+ 0x034, 0x0000006D,
+ 0x000, 0x00030159,
+ 0x084, 0x00068200,
+ 0x086, 0x000000CE,
+ 0x087, 0x00048A00,
+ 0x08E, 0x00065540,
+ 0x08F, 0x00088000,
+ 0x0EF, 0x000020A0,
+ 0x03B, 0x000F02B0,
+ 0x03B, 0x000EF7B0,
+ 0x03B, 0x000D4FB0,
+ 0x03B, 0x000CF060,
+ 0x03B, 0x000B0090,
+ 0x03B, 0x000A0080,
+ 0x03B, 0x00090080,
+ 0x03B, 0x0008F780,
+ 0x03B, 0x000722B0,
+ 0x03B, 0x0006F7B0,
+ 0x03B, 0x00054FB0,
+ 0x03B, 0x0004F060,
+ 0x03B, 0x00030090,
+ 0x03B, 0x00020080,
+ 0x03B, 0x00010080,
+ 0x03B, 0x0000F780,
+ 0x0EF, 0x000000A0,
+ 0x000, 0x00010159,
+ 0x018, 0x0000F407,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01F, 0x00080003,
+ 0xFFE, 0x00000000,
+ 0xFFE, 0x00000000,
+ 0x01E, 0x00000001,
+ 0x01F, 0x00080000,
+ 0x000, 0x00033E60,
+
+};
+
+u32 RTL8188EEMAC_1T_ARRAY[] = {
+ 0x026, 0x00000041,
+ 0x027, 0x00000035,
+ 0x428, 0x0000000A,
+ 0x429, 0x00000010,
+ 0x430, 0x00000000,
+ 0x431, 0x00000001,
+ 0x432, 0x00000002,
+ 0x433, 0x00000004,
+ 0x434, 0x00000005,
+ 0x435, 0x00000006,
+ 0x436, 0x00000007,
+ 0x437, 0x00000008,
+ 0x438, 0x00000000,
+ 0x439, 0x00000000,
+ 0x43A, 0x00000001,
+ 0x43B, 0x00000002,
+ 0x43C, 0x00000004,
+ 0x43D, 0x00000005,
+ 0x43E, 0x00000006,
+ 0x43F, 0x00000007,
+ 0x440, 0x0000005D,
+ 0x441, 0x00000001,
+ 0x442, 0x00000000,
+ 0x444, 0x00000015,
+ 0x445, 0x000000F0,
+ 0x446, 0x0000000F,
+ 0x447, 0x00000000,
+ 0x458, 0x00000041,
+ 0x459, 0x000000A8,
+ 0x45A, 0x00000072,
+ 0x45B, 0x000000B9,
+ 0x460, 0x00000066,
+ 0x461, 0x00000066,
+ 0x480, 0x00000008,
+ 0x4C8, 0x000000FF,
+ 0x4C9, 0x00000008,
+ 0x4CC, 0x000000FF,
+ 0x4CD, 0x000000FF,
+ 0x4CE, 0x00000001,
+ 0x4D3, 0x00000001,
+ 0x500, 0x00000026,
+ 0x501, 0x000000A2,
+ 0x502, 0x0000002F,
+ 0x503, 0x00000000,
+ 0x504, 0x00000028,
+ 0x505, 0x000000A3,
+ 0x506, 0x0000005E,
+ 0x507, 0x00000000,
+ 0x508, 0x0000002B,
+ 0x509, 0x000000A4,
+ 0x50A, 0x0000005E,
+ 0x50B, 0x00000000,
+ 0x50C, 0x0000004F,
+ 0x50D, 0x000000A4,
+ 0x50E, 0x00000000,
+ 0x50F, 0x00000000,
+ 0x512, 0x0000001C,
+ 0x514, 0x0000000A,
+ 0x516, 0x0000000A,
+ 0x525, 0x0000004F,
+ 0x550, 0x00000010,
+ 0x551, 0x00000010,
+ 0x559, 0x00000002,
+ 0x55D, 0x000000FF,
+ 0x605, 0x00000030,
+ 0x608, 0x0000000E,
+ 0x609, 0x0000002A,
+ 0x620, 0x000000FF,
+ 0x621, 0x000000FF,
+ 0x622, 0x000000FF,
+ 0x623, 0x000000FF,
+ 0x624, 0x000000FF,
+ 0x625, 0x000000FF,
+ 0x626, 0x000000FF,
+ 0x627, 0x000000FF,
+ 0x652, 0x00000020,
+ 0x63C, 0x0000000A,
+ 0x63D, 0x0000000A,
+ 0x63E, 0x0000000E,
+ 0x63F, 0x0000000E,
+ 0x640, 0x00000040,
+ 0x66E, 0x00000005,
+ 0x700, 0x00000021,
+ 0x701, 0x00000043,
+ 0x702, 0x00000065,
+ 0x703, 0x00000087,
+ 0x708, 0x00000021,
+ 0x709, 0x00000043,
+ 0x70A, 0x00000065,
+ 0x70B, 0x00000087,
+
+};
+
+u32 RTL8188EEAGCTAB_1TARRAY[] = {
+ 0xC78, 0xFB000001,
+ 0xC78, 0xFB010001,
+ 0xC78, 0xFB020001,
+ 0xC78, 0xFB030001,
+ 0xC78, 0xFB040001,
+ 0xC78, 0xFB050001,
+ 0xC78, 0xFA060001,
+ 0xC78, 0xF9070001,
+ 0xC78, 0xF8080001,
+ 0xC78, 0xF7090001,
+ 0xC78, 0xF60A0001,
+ 0xC78, 0xF50B0001,
+ 0xC78, 0xF40C0001,
+ 0xC78, 0xF30D0001,
+ 0xC78, 0xF20E0001,
+ 0xC78, 0xF10F0001,
+ 0xC78, 0xF0100001,
+ 0xC78, 0xEF110001,
+ 0xC78, 0xEE120001,
+ 0xC78, 0xED130001,
+ 0xC78, 0xEC140001,
+ 0xC78, 0xEB150001,
+ 0xC78, 0xEA160001,
+ 0xC78, 0xE9170001,
+ 0xC78, 0xE8180001,
+ 0xC78, 0xE7190001,
+ 0xC78, 0xE61A0001,
+ 0xC78, 0xE51B0001,
+ 0xC78, 0xE41C0001,
+ 0xC78, 0xE31D0001,
+ 0xC78, 0xE21E0001,
+ 0xC78, 0xE11F0001,
+ 0xC78, 0x8A200001,
+ 0xC78, 0x89210001,
+ 0xC78, 0x88220001,
+ 0xC78, 0x87230001,
+ 0xC78, 0x86240001,
+ 0xC78, 0x85250001,
+ 0xC78, 0x84260001,
+ 0xC78, 0x83270001,
+ 0xC78, 0x82280001,
+ 0xC78, 0x6B290001,
+ 0xC78, 0x6A2A0001,
+ 0xC78, 0x692B0001,
+ 0xC78, 0x682C0001,
+ 0xC78, 0x672D0001,
+ 0xC78, 0x662E0001,
+ 0xC78, 0x652F0001,
+ 0xC78, 0x64300001,
+ 0xC78, 0x63310001,
+ 0xC78, 0x62320001,
+ 0xC78, 0x61330001,
+ 0xC78, 0x46340001,
+ 0xC78, 0x45350001,
+ 0xC78, 0x44360001,
+ 0xC78, 0x43370001,
+ 0xC78, 0x42380001,
+ 0xC78, 0x41390001,
+ 0xC78, 0x403A0001,
+ 0xC78, 0x403B0001,
+ 0xC78, 0x403C0001,
+ 0xC78, 0x403D0001,
+ 0xC78, 0x403E0001,
+ 0xC78, 0x403F0001,
+ 0xC78, 0xFB400001,
+ 0xC78, 0xFB410001,
+ 0xC78, 0xFB420001,
+ 0xC78, 0xFB430001,
+ 0xC78, 0xFB440001,
+ 0xC78, 0xFB450001,
+ 0xC78, 0xFB460001,
+ 0xC78, 0xFB470001,
+ 0xC78, 0xFB480001,
+ 0xC78, 0xFA490001,
+ 0xC78, 0xF94A0001,
+ 0xC78, 0xF84B0001,
+ 0xC78, 0xF74C0001,
+ 0xC78, 0xF64D0001,
+ 0xC78, 0xF54E0001,
+ 0xC78, 0xF44F0001,
+ 0xC78, 0xF3500001,
+ 0xC78, 0xF2510001,
+ 0xC78, 0xF1520001,
+ 0xC78, 0xF0530001,
+ 0xC78, 0xEF540001,
+ 0xC78, 0xEE550001,
+ 0xC78, 0xED560001,
+ 0xC78, 0xEC570001,
+ 0xC78, 0xEB580001,
+ 0xC78, 0xEA590001,
+ 0xC78, 0xE95A0001,
+ 0xC78, 0xE85B0001,
+ 0xC78, 0xE75C0001,
+ 0xC78, 0xE65D0001,
+ 0xC78, 0xE55E0001,
+ 0xC78, 0xE45F0001,
+ 0xC78, 0xE3600001,
+ 0xC78, 0xE2610001,
+ 0xC78, 0xC3620001,
+ 0xC78, 0xC2630001,
+ 0xC78, 0xC1640001,
+ 0xC78, 0x8B650001,
+ 0xC78, 0x8A660001,
+ 0xC78, 0x89670001,
+ 0xC78, 0x88680001,
+ 0xC78, 0x87690001,
+ 0xC78, 0x866A0001,
+ 0xC78, 0x856B0001,
+ 0xC78, 0x846C0001,
+ 0xC78, 0x676D0001,
+ 0xC78, 0x666E0001,
+ 0xC78, 0x656F0001,
+ 0xC78, 0x64700001,
+ 0xC78, 0x63710001,
+ 0xC78, 0x62720001,
+ 0xC78, 0x61730001,
+ 0xC78, 0x60740001,
+ 0xC78, 0x46750001,
+ 0xC78, 0x45760001,
+ 0xC78, 0x44770001,
+ 0xC78, 0x43780001,
+ 0xC78, 0x42790001,
+ 0xC78, 0x417A0001,
+ 0xC78, 0x407B0001,
+ 0xC78, 0x407C0001,
+ 0xC78, 0x407D0001,
+ 0xC78, 0x407E0001,
+ 0xC78, 0x407F0001,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/table.h b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
new file mode 100644
index 000000000000..c1218e835129
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/table.h
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on 2010/ 5/18, 1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TABLE__H_
+#define __RTL92CE_TABLE__H_
+
+#include <linux/types.h>
+#define RTL8188EEPHY_REG_1TARRAYLEN 382
+extern u32 RTL8188EEPHY_REG_1TARRAY[];
+#define RTL8188EEPHY_REG_ARRAY_PGLEN 264
+extern u32 RTL8188EEPHY_REG_ARRAY_PG[];
+#define RTL8188EE_RADIOA_1TARRAYLEN 190
+extern u32 RTL8188EE_RADIOA_1TARRAY[];
+#define RTL8188EEMAC_1T_ARRAYLEN 180
+extern u32 RTL8188EEMAC_1T_ARRAY[];
+#define RTL8188EEAGCTAB_1TARRAYLEN 256
+extern u32 RTL8188EEAGCTAB_1TARRAY[];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
new file mode 100644
index 000000000000..a8871d66d56a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -0,0 +1,817 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+#include "dm.h"
+
+static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+ __le16 fc = rtl_get_fc(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+ return QSLT_MGNT;
+
+ return skb->priority;
+}
+
+static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstatus, u8 *pdesc,
+ struct rx_fwinfo_88e *p_drvinfo,
+ bool bpacket_match_bssid,
+ bool bpacket_toself, bool packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+ struct phy_sts_cck_8192s_t *cck_buf;
+ struct phy_status_rpt *phystrpt = (struct phy_status_rpt *)p_drvinfo;
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ char rx_pwr_all = 0, rx_pwr[4];
+ u8 rf_rx_num = 0, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi = 0;
+ bool is_cck = pstatus->is_cck;
+ u8 lan_idx, vga_idx;
+
+ /* Record it for next packet processing */
+ pstatus->packet_matchbssid = bpacket_match_bssid;
+ pstatus->packet_toself = bpacket_toself;
+ pstatus->packet_beacon = packet_beacon;
+ pstatus->rx_mimo_sig_qual[0] = -1;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+
+ if (is_cck) {
+ u8 cck_hipwr;
+ u8 cck_agc_rpt;
+ /* CCK Driver info Structure is not the same as OFDM packet. */
+ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
+ cck_agc_rpt = cck_buf->cck_agc_rpt;
+
+ /* (1)Hardware does not provide RSSI for CCK
+ * (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
+ if (ppsc->rfpwr_state == ERFON)
+ cck_hipwr = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2,
+ BIT(9));
+ else
+ cck_hipwr = false;
+
+ lan_idx = ((cck_agc_rpt & 0xE0) >> 5);
+ vga_idx = (cck_agc_rpt & 0x1f);
+ switch (lan_idx) {
+ case 7:
+ if (vga_idx <= 27)
+ rx_pwr_all = -100 + 2 * (27 - vga_idx);
+ else
+ rx_pwr_all = -100;
+ break;
+ case 6:
+ rx_pwr_all = -48 + 2 * (2 - vga_idx); /*VGA_idx = 2~0*/
+ break;
+ case 5:
+ rx_pwr_all = -42 + 2 * (7 - vga_idx); /*VGA_idx = 7~5*/
+ break;
+ case 4:
+ rx_pwr_all = -36 + 2 * (7 - vga_idx); /*VGA_idx = 7~4*/
+ break;
+ case 3:
+ rx_pwr_all = -24 + 2 * (7 - vga_idx); /*VGA_idx = 7~0*/
+ break;
+ case 2:
+ if (cck_hipwr)
+ rx_pwr_all = -12 + 2 * (5 - vga_idx);
+ else
+ rx_pwr_all = -6 + 2 * (5 - vga_idx);
+ break;
+ case 1:
+ rx_pwr_all = 8 - 2 * vga_idx;
+ break;
+ case 0:
+ rx_pwr_all = 14 - 2 * vga_idx;
+ break;
+ default:
+ break;
+ }
+ rx_pwr_all += 6;
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ /* CCK gain is smaller than OFDM/MCS gain,
+ * so we add gain diff by experiences,
+ * the val is 6
+ */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same
+ * gain index with OFDM.
+ */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+ if (cck_hipwr == false) {
+ if (pwdb_all >= 80)
+ pwdb_all = ((pwdb_all - 80)<<1) +
+ ((pwdb_all - 80)>>1) + 80;
+ else if ((pwdb_all <= 78) && (pwdb_all >= 20))
+ pwdb_all += 3;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ }
+
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3) Get Signal Quality (EVM) */
+ if (bpacket_match_bssid) {
+ u8 sq;
+
+ if (pstatus->rx_pwdb_all > 40) {
+ sq = 100;
+ } else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstatus->signalquality = sq;
+ pstatus->rx_mimo_sig_qual[0] = sq;
+ pstatus->rx_mimo_sig_qual[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] =
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+
+ /* (1)Get RSSI for HT rate */
+ for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+ /* we will judge RF RX path now. */
+ if (rtlpriv->dm.rfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f) * 2)-110;
+
+ /* Translate DBM to percentage. */
+ rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+
+ /* Get Rx snr value in DB */
+ rtlpriv->stats.rx_snr_db[i] = p_drvinfo->rxsnr[i] / 2;
+
+ /* Record Signal Strength for next packet */
+ if (bpacket_match_bssid)
+ pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ /* (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ pstatus->rx_pwdb_all = pwdb_all;
+ pstatus->rxpower = rx_pwr_all;
+ pstatus->recvsignalpower = rx_pwr_all;
+
+ /* (3)EVM of HT rate */
+ if (pstatus->is_ht && pstatus->rate >= DESC92C_RATEMCS8 &&
+ pstatus->rate <= DESC92C_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (bpacket_match_bssid) {
+ /* Fill value in RFD, Get the first
+ * spatial stream only
+ */
+ if (i == 0)
+ pstatus->signalquality = evm & 0xff;
+ pstatus->rx_mimo_sig_qual[i] = evm & 0xff;
+ }
+ }
+ }
+
+ /* UI BSS List signal strength(in percentage),
+ * make it good looking, from 0~100.
+ */
+ if (is_cck)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ pwdb_all));
+ else if (rf_rx_num != 0)
+ pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+ total_rssi /= rf_rx_num));
+ /*HW antenna diversity*/
+ rtldm->fat_table.antsel_rx_keep_0 = phystrpt->ant_sel;
+ rtldm->fat_table.antsel_rx_keep_1 = phystrpt->ant_sel_b;
+ rtldm->fat_table.antsel_rx_keep_2 = phystrpt->antsel_rx_keep_2;
+}
+
+static void _rtl88ee_smart_antenna(struct ieee80211_hw *hw,
+ struct rtl_stats *pstatus)
+{
+ struct rtl_dm *rtldm = rtl_dm(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 ant_mux;
+ struct fast_ant_training *pfat = &(rtldm->fat_table);
+
+ if (rtlefuse->antenna_div_type == CG_TRX_SMART_ANTDIV) {
+ if (pfat->fat_state == FAT_TRAINING_STATE) {
+ if (pstatus->packet_toself) {
+ ant_mux = (pfat->antsel_rx_keep_2 << 2) |
+ (pfat->antsel_rx_keep_1 << 1) |
+ pfat->antsel_rx_keep_0;
+ pfat->ant_sum[ant_mux] += pstatus->rx_pwdb_all;
+ pfat->ant_cnt[ant_mux]++;
+ }
+ }
+ } else if ((rtlefuse->antenna_div_type == CG_TRX_HW_ANTDIV) ||
+ (rtlefuse->antenna_div_type == CGCS_RX_HW_ANTDIV)) {
+ if (pstatus->packet_toself || pstatus->packet_matchbssid) {
+ ant_mux = (pfat->antsel_rx_keep_2 << 2) |
+ (pfat->antsel_rx_keep_1 << 1) |
+ pfat->antsel_rx_keep_0;
+ rtl88e_dm_ant_sel_statistics(hw, ant_mux, 0,
+ pstatus->rx_pwdb_all);
+ }
+ }
+}
+
+static void _rtl88ee_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct rtl_stats *pstatus,
+ u8 *pdesc, struct rx_fwinfo_88e *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ __le16 fc;
+ u16 type, ufc;
+ bool match_bssid, packet_toself, packet_beacon, addr;
+
+ tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = hdr->frame_control;
+ ufc = le16_to_cpu(fc);
+ type = WLAN_FC_GET_TYPE(fc);
+ praddr = hdr->addr1;
+ psaddr = ieee80211_get_SA(hdr);
+ memcpy(pstatus->psaddr, psaddr, ETH_ALEN);
+
+ addr = (!compare_ether_addr(mac->bssid, (ufc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (ufc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3));
+ match_bssid = ((IEEE80211_FTYPE_CTL != type) && (!pstatus->hwerror) &&
+ (!pstatus->crc) && (!pstatus->icv)) && addr;
+
+ addr = (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+ packet_toself = match_bssid && addr;
+
+ if (ieee80211_is_beacon(fc))
+ packet_beacon = true;
+
+ _rtl88ee_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+ match_bssid, packet_toself, packet_beacon);
+ _rtl88ee_smart_antenna(hw, pstatus);
+ rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+static void insert_em(struct rtl_tcb_desc *ptcb_desc, u8 *virtualaddress)
+{
+ u32 dwtmp = 0;
+
+ memset(virtualaddress, 0, 8);
+
+ SET_EARLYMODE_PKTNUM(virtualaddress, ptcb_desc->empkt_num);
+ if (ptcb_desc->empkt_num == 1) {
+ dwtmp = ptcb_desc->empkt_len[0];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[0];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[1];
+ }
+ SET_EARLYMODE_LEN0(virtualaddress, dwtmp);
+
+ if (ptcb_desc->empkt_num <= 3) {
+ dwtmp = ptcb_desc->empkt_len[2];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[2];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[3];
+ }
+ SET_EARLYMODE_LEN1(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 5) {
+ dwtmp = ptcb_desc->empkt_len[4];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[4];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[5];
+ }
+ SET_EARLYMODE_LEN2_1(virtualaddress, dwtmp & 0xF);
+ SET_EARLYMODE_LEN2_2(virtualaddress, dwtmp >> 4);
+ if (ptcb_desc->empkt_num <= 7) {
+ dwtmp = ptcb_desc->empkt_len[6];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[6];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[7];
+ }
+ SET_EARLYMODE_LEN3(virtualaddress, dwtmp);
+ if (ptcb_desc->empkt_num <= 9) {
+ dwtmp = ptcb_desc->empkt_len[8];
+ } else {
+ dwtmp = ptcb_desc->empkt_len[8];
+ dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4;
+ dwtmp += ptcb_desc->empkt_len[9];
+ }
+ SET_EARLYMODE_LEN4(virtualaddress, dwtmp);
+}
+
+bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rx_fwinfo_88e *p_drvinfo;
+ struct ieee80211_hdr *hdr;
+
+ u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ status->packet_report_type = (u8)GET_RX_STATUS_DESC_RPT_SEL(pdesc);
+ if (status->packet_report_type == TX_REPORT2)
+ status->length = (u16) GET_RX_RPT2_DESC_PKT_LEN(pdesc);
+ else
+ status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+ status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+ RX_DRV_INFO_SIZE_UNIT;
+ status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+ status->icv = (u16) GET_RX_DESC_ICV(pdesc);
+ status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+ status->hwerror = (status->crc | status->icv);
+ status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+ status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+ status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+ status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+ status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1) &&
+ (GET_RX_DESC_FAGGR(pdesc) == 1));
+ if (status->packet_report_type == NORMAL_RX)
+ status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+ status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+ status->is_cck = RTL8188_RX_HAL_IS_CCK_RATE(status->rate);
+
+ status->macid = GET_RX_DESC_MACID(pdesc);
+ if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(2);
+ else if (GET_RX_STATUS_DESC_MAGIC_MATCH(pdesc))
+ status->wake_match = BIT(1);
+ else if (GET_RX_STATUS_DESC_UNICAST_MATCH(pdesc))
+ status->wake_match = BIT(0);
+ else
+ status->wake_match = 0;
+ if (status->wake_match)
+ RT_TRACE(rtlpriv, COMP_RXDESC, DBG_LOUD,
+ "Get Wakeup Packet!! WakeMatch =%d\n",
+ status->wake_match);
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
+
+ if (status->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (status->rx_is40Mhzpacket)
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (status->is_ht)
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_MACTIME_START;
+
+ /* hw will set status->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame.
+ * So hw will not decryption robust managment frame
+ * for IEEE80211w but still set status->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it
+ */
+ if (status->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ status->rx_drvinfo_size + status->rx_bufshift);
+
+ if (!hdr) {
+ /* During testing, hdr was NULL */
+ return false;
+ }
+ if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+
+ /* rate_idx: index of data rate into band's
+ * supported rates or MCS index if HT rates
+ * are use (RX_FLAG_HT)
+ * Notice: this is diff with windows define
+ */
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ status->rate, false);
+
+ rx_status->mactime = status->timestamp_low;
+ if (phystatus == true) {
+ p_drvinfo = (struct rx_fwinfo_88e *)(skb->data +
+ status->rx_bufshift);
+
+ _rtl88ee_translate_rx_signal_stuff(hw, skb, status, pdesc,
+ p_drvinfo);
+ }
+
+ /*rx_status->qual = status->signal; */
+ rx_status->signal = status->recvsignalpower + 10;
+ /*rx_status->noise = -status->noise; */
+ if (status->packet_report_type == TX_REPORT2) {
+ status->macid_valid_entry[0] =
+ GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
+ status->macid_valid_entry[1] =
+ GET_RX_RPT2_DESC_MACID_VALID_2(pdesc);
+ }
+ return true;
+}
+
+void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ u8 *pdesc = (u8 *)pdesc_tx;
+ u16 seq_number;
+ __le16 fc = hdr->frame_control;
+ unsigned int buf_len = 0;
+ unsigned int skb_len = skb->len;
+ u8 fw_qsel = _rtl88ee_map_hwqueue_to_fwqueue(skb, hw_queue);
+ bool firstseg = ((hdr->seq_ctrl &
+ cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+ bool lastseg = ((hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+ dma_addr_t mapping;
+ u8 bw_40 = 0;
+ u8 short_gi = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+ /* reserve 8 byte for AMPDU early mode */
+ if (rtlhal->earlymode_enable) {
+ skb_push(skb, EM_HDR_LEN);
+ memset(skb->data, 0, EM_HDR_LEN);
+ }
+ buf_len = skb->len;
+ mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_88e));
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
+ if (firstseg) {
+ if (rtlhal->earlymode_enable) {
+ SET_TX_DESC_PKT_OFFSET(pdesc, 1);
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN +
+ EM_HDR_LEN);
+ if (ptcb_desc->empkt_num) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Insert 8 byte.pTcb->EMPktNum:%d\n",
+ ptcb_desc->empkt_num);
+ insert_em(ptcb_desc, (u8 *)(skb->data));
+ }
+ } else {
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+ }
+
+ ptcb_desc->use_driver_rate = true;
+ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+ if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+ short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
+ else
+ short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
+ SET_TX_DESC_DATA_SHORTGI(pdesc, short_gi);
+
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+ SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+ }
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ !ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_HW_RTS_ENABLE(pdesc, 0);
+ SET_TX_DESC_CTS2SELF(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+ SET_TX_DESC_RTS_BW(pdesc, 0);
+ SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc,
+ ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
+ (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+ if (ptcb_desc->btx_enable_sw_calc_duration)
+ SET_TX_DESC_NAV_USE_HDR(pdesc, 1);
+
+ if (bw_40) {
+ if (ptcb_desc->packet_bw) {
+ SET_TX_DESC_DATA_BW(pdesc, 1);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
+ }
+ } else {
+ SET_TX_DESC_DATA_BW(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb_len);
+ if (sta) {
+ u8 ampdu_density = sta->ht_cap.ampdu_density;
+ SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+ }
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf;
+ keyconf = info->control.hw_key;
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+ }
+ }
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+ SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+ SET_TX_DESC_DISABLE_FB(pdesc, ptcb_desc->disable_ratefallback ?
+ 1 : 0);
+ SET_TX_DESC_USE_RATE(pdesc, ptcb_desc->use_driver_rate ? 1 : 0);
+
+ /* Set TxRate and RTSRate in TxDesc */
+ /* This prevent Tx initial rate of new-coming packets */
+ /* from being overwritten by retried packet rate.*/
+ if (!ptcb_desc->use_driver_rate) {
+ /*SET_TX_DESC_RTS_RATE(pdesc, 0x08); */
+ /* SET_TX_DESC_TX_RATE(pdesc, 0x0b); */
+ }
+ if (ieee80211_is_data_qos(fc)) {
+ if (mac->rdg_en) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "Enable RDG function.\n");
+ SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+ SET_TX_DESC_HTC(pdesc, 1);
+ }
+ }
+ }
+
+ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) buf_len);
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+ if (rtlpriv->dm.useramask) {
+ SET_TX_DESC_RATE_ID(pdesc, ptcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ } else {
+ SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->ratr_index);
+ }
+ if (ieee80211_is_data_qos(fc))
+ SET_TX_DESC_QOS(pdesc, 1);
+
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+ SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+ if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+ is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+ SET_TX_DESC_BMC(pdesc, 1);
+
+ rtl88e_dm_set_tx_ant_by_tx_info(hw, pdesc, ptcb_desc->mac_id);
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
+ u8 *pdesc, bool firstseg,
+ bool lastseg, struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 fw_queue = QSLT_BEACON;
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+ skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ __le16 fc = hdr->frame_control;
+
+ if (pci_dma_mapping_error(rtlpci->pdev, mapping)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+ "DMA mapping error");
+ return;
+ }
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+ if (firstseg)
+ SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+ SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+
+ SET_TX_DESC_SEQ(pdesc, 0);
+
+ SET_TX_DESC_LINIP(pdesc, 0);
+
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+ SET_TX_DESC_RATE_ID(pdesc, 7);
+ SET_TX_DESC_MACID(pdesc, 0);
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ SET_TX_DESC_PKT_SIZE((u8 *)pdesc, (u16)(skb->len));
+
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+ SET_TX_DESC_USE_RATE(pdesc, 1);
+
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_HWSEQ_EN(pdesc, 1);
+
+ RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+ "H2C Tx Cmd Content\n",
+ pdesc, TX_DESC_SIZE);
+}
+
+void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *)val);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_DESC_PKT_LEN(pdesc, *(u32 *)val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ }
+}
+
+u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR txdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_DESC_OWN(pdesc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_DESC_PKT_LEN(pdesc);
+ break;
+ default:
+ RT_ASSERT(false, "ERR rxdesc :%d not processed\n",
+ desc_name);
+ break;
+ }
+ }
+ return ret;
+}
+
+void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ if (hw_queue == BEACON_QUEUE) {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+ } else {
+ rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+ BIT(0) << (hw_queue));
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
new file mode 100644
index 000000000000..d3a02e73f53a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.h
@@ -0,0 +1,795 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2013 Realtek Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_TRX_H__
+#define __RTL92CE_TRX_H__
+
+#define TX_DESC_SIZE 64
+#define TX_DESC_AGGR_SUBFRAME_SIZE 32
+
+#define RX_DESC_SIZE 32
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+#define TX_DESC_NEXT_DESC_OFFSET 40
+#define USB_HWDESC_HEADER_LEN 32
+#define CRCLENGTH 4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 6, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 26, 5, __val)
+#define SET_TX_DESC_PADDING_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
+
+#define GET_TX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_TX_DESC_AGG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
+#define GET_TX_DESC_AGG_BREAK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
+#define GET_TX_DESC_RDG_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
+#define GET_TX_DESC_QUEUE_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_TX_DESC_PIFS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_TX_DESC_RATE_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_TX_DESC_EN_DESC_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_TX_DESC_SEC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
+#define GET_TX_DESC_PKT_OFFSET(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 8)
+
+#define SET_TX_DESC_RTS_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val)
+#define SET_TX_DESC_DATA_RC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 12, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 13, 1, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 16, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_CCX(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_BT_INT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 23, 1, __val)
+#define SET_TX_DESC_ANTSEL_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val)
+#define SET_TX_DESC_ANTSEL_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val)
+#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val)
+#define SET_TX_DESC_TX_ANTL(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val)
+#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 6)
+#define GET_TX_DESC_DATA_RC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 6, 6)
+#define GET_TX_DESC_BAR_RTY_TH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 14, 2)
+#define GET_TX_DESC_MORE_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 17, 1)
+#define GET_TX_DESC_RAW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 18, 1)
+#define GET_TX_DESC_CCX(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 19, 1)
+#define GET_TX_DESC_AMPDU_DENSITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 20, 3)
+#define GET_TX_DESC_ANTSEL_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 24, 1)
+#define GET_TX_DESC_ANTSEL_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 25, 1)
+#define GET_TX_DESC_TX_ANT_CCK(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 26, 2)
+#define GET_TX_DESC_TX_ANTL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 2)
+#define GET_TX_DESC_TX_ANT_HT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 30, 2)
+
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val)
+#define SET_TX_DESC_CPU_HANDLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 1, __val)
+#define SET_TX_DESC_TAG1(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 29, 1, __val)
+#define SET_TX_DESC_TRIGGER_INT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 30, 1, __val)
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val)
+
+
+#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
+#define GET_TX_DESC_TAIL_PAGE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 8)
+#define GET_TX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
+
+
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
+#define SET_TX_DESC_AP_DCFE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val)
+#define SET_TX_DESC_QOS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val)
+#define SET_TX_DESC_HWSEQ_SSN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val)
+#define SET_TX_DESC_PORT_ID(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val)
+#define SET_TX_DESC_PWR_STATUS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 15, 3, __val)
+#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val)
+#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val)
+#define SET_TX_DESC_DATA_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val)
+#define SET_TX_DESC_RTS_BW(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 5)
+#define GET_TX_DESC_AP_DCFE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 5, 1)
+#define GET_TX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 6, 1)
+#define GET_TX_DESC_HWSEQ_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 7, 1)
+#define GET_TX_DESC_USE_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 8, 1)
+#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 9, 1)
+#define GET_TX_DESC_DISABLE_FB(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 10, 1)
+#define GET_TX_DESC_CTS2SELF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 11, 1)
+#define GET_TX_DESC_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 12, 1)
+#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 13, 1)
+#define GET_TX_DESC_PORT_ID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 14, 1)
+#define GET_TX_DESC_WAIT_DCTS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 18, 1)
+#define GET_TX_DESC_CTS2AP_EN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 19, 1)
+#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 20, 2)
+#define GET_TX_DESC_TX_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 22, 2)
+#define GET_TX_DESC_DATA_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 24, 1)
+#define GET_TX_DESC_DATA_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 25, 1)
+#define GET_TX_DESC_RTS_SHORT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 26, 1)
+#define GET_TX_DESC_RTS_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 27, 1)
+#define GET_TX_DESC_RTS_SC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 28, 2)
+#define GET_TX_DESC_RTS_STBC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 30, 2)
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val)
+#define SET_TX_DESC_CCX_TAG(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val)
+#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val)
+
+#define GET_TX_DESC_TX_RATE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 6)
+#define GET_TX_DESC_DATA_SHORTGI(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 6, 1)
+#define GET_TX_DESC_CCX_TAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 7, 1)
+#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 8, 5)
+#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 13, 4)
+#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 17, 1)
+#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 18, 6)
+#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 24, 8)
+
+#define SET_TX_DESC_TXAGC_A(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val)
+#define SET_TX_DESC_TXAGC_B(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val)
+#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val)
+#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val)
+#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val)
+#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val)
+
+#define GET_TX_DESC_TXAGC_A(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 5)
+#define GET_TX_DESC_TXAGC_B(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 5, 5)
+#define GET_TX_DESC_USE_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 10, 1)
+#define GET_TX_DESC_MAX_AGG_NUM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 11, 5)
+#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 16, 4)
+#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 20, 4)
+#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 24, 4)
+#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+#define SET_TX_DESC_SW_OFFSET30(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 8, __val)
+#define SET_TX_DESC_SW_OFFSET31(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val)
+#define SET_TX_DESC_ANTSEL_C(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 29, 1, __val)
+#define SET_TX_DESC_NULL_0(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 30, 1, __val)
+#define SET_TX_DESC_NULL_1(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 30, 1, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val)
+#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+32, 0, 32)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+36, 0, 32)
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+44, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 0, 6)
+#define GET_RX_DESC_PAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_FAGGR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_A2_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 20, 4)
+#define GET_RX_DESC_PAM(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+#define GET_RX_DESC_SEQ(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+
+#define GET_RX_DESC_RXMCS(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 0, 6)
+#define GET_RX_DESC_RXHT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_STATUS_DESC_RX_GF(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 7, 1)
+#define GET_RX_DESC_SPLCP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 8, 1)
+#define GET_RX_DESC_BW(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 9, 1)
+#define GET_RX_DESC_HTC(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_STATUS_DESC_EOSP(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 11, 1)
+#define GET_RX_STATUS_DESC_BSSID_FIT(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 12, 2)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 14, 2)
+
+#define GET_RX_STATUS_DESC_PATTERN_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 29, 1)
+#define GET_RX_STATUS_DESC_UNICAST_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 30, 1)
+#define GET_RX_STATUS_DESC_MAGIC_MATCH(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+12, 31, 1)
+
+#define GET_RX_DESC_IV1(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+16, 0, 32)
+#define GET_RX_DESC_TSFL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val) \
+ SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+/* TX report 2 format in Rx desc*/
+
+#define GET_RX_RPT2_DESC_PKT_LEN(__status) \
+ LE_BITS_TO_4BYTE(__status, 0, 9)
+#define GET_RX_RPT2_DESC_MACID_VALID_1(__status) \
+ LE_BITS_TO_4BYTE(__status+16, 0, 32)
+#define GET_RX_RPT2_DESC_MACID_VALID_2(__status) \
+ LE_BITS_TO_4BYTE(__status+20, 0, 32)
+
+#define SET_EARLYMODE_PKTNUM(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 0, 4, __value)
+#define SET_EARLYMODE_LEN0(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 4, 12, __value)
+#define SET_EARLYMODE_LEN1(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 16, 12, __value)
+#define SET_EARLYMODE_LEN2_1(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr, 28, 4, __value)
+#define SET_EARLYMODE_LEN2_2(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 0, 8, __value)
+#define SET_EARLYMODE_LEN3(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 8, 12, __value)
+#define SET_EARLYMODE_LEN4(__paddr, __value) \
+ SET_BITS_TO_LE_4BYTE(__paddr+4, 20, 12, __value)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset(__pdesc, 0, _size); \
+} while (0)
+
+#define RTL8188_RX_HAL_IS_CCK_RATE(rxmcs)\
+ (rxmcs == DESC92C_RATE1M ||\
+ rxmcs == DESC92C_RATE2M ||\
+ rxmcs == DESC92C_RATE5_5M ||\
+ rxmcs == DESC92C_RATE11M)
+
+struct phy_rx_agc_info_t {
+ #if __LITTLE_ENDIAN
+ u8 gain:7, trsw:1;
+ #else
+ u8 trsw:1, gain:7;
+ #endif
+};
+struct phy_status_rpt {
+ struct phy_rx_agc_info_t path_agc[2];
+ u8 ch_corr[2];
+ u8 cck_sig_qual_ofdm_pwdb_all;
+ u8 cck_agc_rpt_ofdm_cfosho_a;
+ u8 cck_rpt_b_ofdm_cfosho_b;
+ u8 rsvd_1;
+ u8 noise_power_db_msb;
+ u8 path_cfotail[2];
+ u8 pcts_mask[2];
+ u8 stream_rxevm[2];
+ u8 path_rxsnr[2];
+ u8 noise_power_db_lsb;
+ u8 rsvd_2[3];
+ u8 stream_csi[2];
+ u8 stream_target_csi[2];
+ u8 sig_evm;
+ u8 rsvd_3;
+#if __LITTLE_ENDIAN
+ u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 idle_long:1;
+ u8 r_ant_train_en:1;
+ u8 ant_sel_b:1;
+ u8 ant_sel:1;
+#else /* _BIG_ENDIAN_ */
+ u8 ant_sel:1;
+ u8 ant_sel_b:1;
+ u8 r_ant_train_en:1;
+ u8 idle_long:1;
+ u8 rxsc:2;
+ u8 sgi_en:1;
+ u8 antsel_rx_keep_2:1; /*ex_intf_flg:1;*/
+#endif
+} __packed;
+
+struct rx_fwinfo_88e {
+ u8 gain_trsw[4];
+ u8 pwdb_all;
+ u8 cfosho[4];
+ u8 cfotail[4];
+ char rxevm[2];
+ char rxsnr[4];
+ u8 pdsnr[2];
+ u8 csi_current[2];
+ u8 csi_target[2];
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+} __packed;
+
+struct tx_desc_88e {
+ u32 pktsize:16;
+ u32 offset:8;
+ u32 bmc:1;
+ u32 htc:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 linip:1;
+ u32 noacm:1;
+ u32 gf:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 rsvd0:2;
+ u32 queuesel:5;
+ u32 rd_nav_ext:1;
+ u32 lsig_txop_en:1;
+ u32 pifs:1;
+ u32 rateid:4;
+ u32 nav_usehdr:1;
+ u32 en_descid:1;
+ u32 sectype:2;
+ u32 pktoffset:8;
+
+ u32 rts_rc:6;
+ u32 data_rc:6;
+ u32 agg_en:1;
+ u32 rdg_en:1;
+ u32 bar_retryht:2;
+ u32 agg_break:1;
+ u32 morefrag:1;
+ u32 raw:1;
+ u32 ccx:1;
+ u32 ampdudensity:3;
+ u32 bt_int:1;
+ u32 ant_sela:1;
+ u32 ant_selb:1;
+ u32 txant_cck:2;
+ u32 txant_l:2;
+ u32 txant_ht:2;
+
+ u32 nextheadpage:8;
+ u32 tailpage:8;
+ u32 seq:12;
+ u32 cpu_handle:1;
+ u32 tag1:1;
+ u32 trigger_int:1;
+ u32 hwseq_en:1;
+
+ u32 rtsrate:5;
+ u32 apdcfe:1;
+ u32 qos:1;
+ u32 hwseq_ssn:1;
+ u32 userrate:1;
+ u32 dis_rtsfb:1;
+ u32 dis_datafb:1;
+ u32 cts2self:1;
+ u32 rts_en:1;
+ u32 hwrts_en:1;
+ u32 portid:1;
+ u32 pwr_status:3;
+ u32 waitdcts:1;
+ u32 cts2ap_en:1;
+ u32 txsc:2;
+ u32 stbc:2;
+ u32 txshort:1;
+ u32 txbw:1;
+ u32 rtsshort:1;
+ u32 rtsbw:1;
+ u32 rtssc:2;
+ u32 rtsstbc:2;
+
+ u32 txrate:6;
+ u32 shortgi:1;
+ u32 ccxt:1;
+ u32 txrate_fb_lmt:5;
+ u32 rtsrate_fb_lmt:4;
+ u32 retrylmt_en:1;
+ u32 txretrylmt:6;
+ u32 usb_txaggnum:8;
+
+ u32 txagca:5;
+ u32 txagcb:5;
+ u32 usemaxlen:1;
+ u32 maxaggnum:5;
+ u32 mcsg1maxlen:4;
+ u32 mcsg2maxlen:4;
+ u32 mcsg3maxlen:4;
+ u32 mcs7sgimaxlen:4;
+
+ u32 txbuffersize:16;
+ u32 sw_offset30:8;
+ u32 sw_offset31:4;
+ u32 rsvd1:1;
+ u32 antsel_c:1;
+ u32 null_0:1;
+ u32 null_1:1;
+
+ u32 txbuffaddr;
+ u32 txbufferaddr64;
+ u32 nextdescaddress;
+ u32 nextdescaddress64;
+
+ u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_88e {
+ u32 length:14;
+ u32 crc32:1;
+ u32 icverror:1;
+ u32 drv_infosize:4;
+ u32 security:3;
+ u32 qos:1;
+ u32 shift:2;
+ u32 phystatus:1;
+ u32 swdec:1;
+ u32 lastseg:1;
+ u32 firstseg:1;
+ u32 eor:1;
+ u32 own:1;
+
+ u32 macid:6;
+ u32 tid:4;
+ u32 hwrsvd:5;
+ u32 paggr:1;
+ u32 faggr:1;
+ u32 a1_fit:4;
+ u32 a2_fit:4;
+ u32 pam:1;
+ u32 pwr:1;
+ u32 moredata:1;
+ u32 morefrag:1;
+ u32 type:2;
+ u32 mc:1;
+ u32 bc:1;
+
+ u32 seq:12;
+ u32 frag:4;
+ u32 nextpktlen:14;
+ u32 nextind:1;
+ u32 rsvd:1;
+
+ u32 rxmcs:6;
+ u32 rxht:1;
+ u32 amsdu:1;
+ u32 splcp:1;
+ u32 bandwidth:1;
+ u32 htc:1;
+ u32 tcpchk_rpt:1;
+ u32 ipcchk_rpt:1;
+ u32 tcpchk_valid:1;
+ u32 hwpcerr:1;
+ u32 hwpcind:1;
+ u32 iv0:16;
+
+ u32 iv1;
+
+ u32 tsfl;
+
+ u32 bufferaddress;
+ u32 bufferaddress64;
+
+} __packed;
+
+void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc);
+bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
+ struct rtl_stats *status,
+ struct ieee80211_rx_status *rx_status,
+ u8 *pdesc, struct sk_buff *skb);
+void rtl88ee_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl88ee_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl88ee_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl88ee_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool b_firstseg, bool b_lastseg,
+ struct sk_buff *skb);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index b793a659a465..d2d57a27a7c1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -174,8 +174,8 @@ static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_range_max = DM_DIG_MAX;
- dm_digtable->rx_gain_range_min = DM_DIG_MIN;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -300,11 +300,11 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
}
if ((digtable->rssi_val_min + 10 - digtable->back_val) >
- digtable->rx_gain_range_max)
- digtable->cur_igvalue = digtable->rx_gain_range_max;
+ digtable->rx_gain_max)
+ digtable->cur_igvalue = digtable->rx_gain_max;
else if ((digtable->rssi_val_min + 10 -
- digtable->back_val) < digtable->rx_gain_range_min)
- digtable->cur_igvalue = digtable->rx_gain_range_min;
+ digtable->back_val) < digtable->rx_gain_min)
+ digtable->cur_igvalue = digtable->rx_gain_min;
else
digtable->cur_igvalue = digtable->rssi_val_min + 10 -
digtable->back_val;
@@ -669,7 +669,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
u8 thermalvalue, delta, delta_lck, delta_iqk;
long ele_a, ele_d, temp_cck, val_x, value32;
long val_y, ele_c = 0;
- u8 ofdm_index[2], ofdm_index_old[2], cck_index_old = 0;
+ u8 ofdm_index[2], ofdm_index_old[2] = {0, 0}, cck_index_old = 0;
s8 cck_index = 0;
int i;
bool is2t = IS_92C_SERIAL(rtlhal->version);
@@ -717,7 +717,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
if (ele_d == (ofdmswing_table[i] &
MASKOFDM_D)) {
-
+ ofdm_index_old[1] = (u8) i;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
DBG_LOUD,
"Initial pathB ele_d reg0x%x = 0x%lx, ofdm_index=0x%x\n",
@@ -1147,75 +1147,6 @@ void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(rtl92c_dm_init_rate_adaptive_mask);
-static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct rate_adaptive *p_ra = &(rtlpriv->ra);
- u32 low_rssi_thresh, high_rssi_thresh;
- struct ieee80211_sta *sta = NULL;
-
- if (is_hal_stop(rtlhal)) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "<---- driver is going to unload\n");
- return;
- }
-
- if (!rtlpriv->dm.useramask) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "<---- driver does not control rate adaptive mask\n");
- return;
- }
-
- if (mac->link_state == MAC80211_LINKED &&
- mac->opmode == NL80211_IFTYPE_STATION) {
- switch (p_ra->pre_ratr_state) {
- case DM_RATR_STA_HIGH:
- high_rssi_thresh = 50;
- low_rssi_thresh = 20;
- break;
- case DM_RATR_STA_MIDDLE:
- high_rssi_thresh = 55;
- low_rssi_thresh = 20;
- break;
- case DM_RATR_STA_LOW:
- high_rssi_thresh = 50;
- low_rssi_thresh = 25;
- break;
- default:
- high_rssi_thresh = 50;
- low_rssi_thresh = 20;
- break;
- }
-
- if (rtlpriv->dm.undec_sm_pwdb > (long)high_rssi_thresh)
- p_ra->ratr_state = DM_RATR_STA_HIGH;
- else if (rtlpriv->dm.undec_sm_pwdb > (long)low_rssi_thresh)
- p_ra->ratr_state = DM_RATR_STA_MIDDLE;
- else
- p_ra->ratr_state = DM_RATR_STA_LOW;
-
- if (p_ra->pre_ratr_state != p_ra->ratr_state) {
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, "RSSI = %ld\n",
- rtlpriv->dm.undec_sm_pwdb);
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "RSSI_LEVEL = %d\n", p_ra->ratr_state);
- RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
- "PreState = %d, CurState = %d\n",
- p_ra->pre_ratr_state, p_ra->ratr_state);
-
- rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
- p_ra->ratr_state);
-
- p_ra->pre_ratr_state = p_ra->ratr_state;
- rcu_read_unlock();
- }
- }
-}
-
static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1437,6 +1368,9 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
(u8 *) (&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
if ((ppsc->rfpwr_state == ERFON) && ((!fw_current_inpsmode) &&
fw_ps_awake)
&& (!ppsc->rfchange_inprogress)) {
@@ -1446,7 +1380,7 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
rtl92c_dm_dynamic_bb_powersaving(hw);
rtl92c_dm_dynamic_txpower(hw);
rtl92c_dm_check_txpower_tracking(hw);
- rtl92c_dm_refresh_rate_adaptive_mask(hw);
+ /* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
rtl92c_dm_bt_coexist(hw);
rtl92c_dm_check_edca_turbo(hw);
}
@@ -1651,7 +1585,7 @@ static void rtl92c_bt_set_normal(struct ieee80211_hw *hw)
}
}
-static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
+static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw, u8 tmp1byte)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
@@ -1673,9 +1607,9 @@ static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
BT_RSSI_STATE_SPECIAL_LOW)) {
rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
} else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
} else {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
}
}
@@ -1726,12 +1660,17 @@ static void rtl92c_check_bt_change(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 tmp1byte = 0;
+ if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version) &&
+ rtlpcipriv->bt_coexist.bt_coexistence)
+ tmp1byte |= BIT(5);
if (rtlpcipriv->bt_coexist.bt_cur_state) {
if (rtlpcipriv->bt_coexist.bt_ant_isolation)
- rtl92c_bt_ant_isolation(hw);
+ rtl92c_bt_ant_isolation(hw, tmp1byte);
} else {
- rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte);
rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0,
rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 883f23ae9519..04a41628ceed 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -552,7 +552,9 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
ppsc->reg_max_lps_awakeintvl);
@@ -808,3 +810,98 @@ void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
rtl92c_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
}
EXPORT_SYMBOL(rtl92c_set_fw_joinbss_report_cmd);
+
+static void rtl92c_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl92c_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low+(50*1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+
+ rtl92c_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+}
+EXPORT_SYMBOL_GPL(rtl92c_set_p2p_ps_offload_cmd);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index 780ea5b1e24c..15b2055e6212 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -67,6 +67,9 @@ enum rtl8192c_h2c_cmd {
H2C_RSVDPAGE = 3,
H2C_RSSI_REPORT = 5,
H2C_RA_MASK = 6,
+ H2C_MACID_PS_MODE = 7,
+ H2C_P2P_PS_OFFLOAD = 8,
+ H2C_P2P_PS_CTW_CMD = 32,
MAX_H2CCMD
};
@@ -95,5 +98,6 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
void usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, void *data, u16 len);
+void rtl92c_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 1b65db7fd651..a82b30a1996c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -475,6 +475,9 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl92c_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
case HW_VAR_AID:{
u16 u2btmp;
u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
@@ -505,6 +508,40 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -1105,7 +1142,8 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
type == NL80211_IFTYPE_STATION) {
_rtl92ce_stop_tx_beacon(hw);
_rtl92ce_enable_bcn_sub_func(hw);
- } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP) {
+ } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP ||
+ type == NL80211_IFTYPE_MESH_POINT) {
_rtl92ce_resume_tx_beacon(hw);
_rtl92ce_disable_bcn_sub_func(hw);
} else {
@@ -1137,6 +1175,11 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to AP!\n");
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ bt_msr |= MSR_ADHOC;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ "Set Network type to Mesh Point!\n");
+ break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"Network type %d not supported!\n", type);
@@ -1184,7 +1227,8 @@ int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
return -EOPNOTSUPP;
if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
- if (type != NL80211_IFTYPE_AP)
+ if (type != NL80211_IFTYPE_AP &&
+ type != NL80211_IFTYPE_MESH_POINT)
rtl92ce_set_check_bssid(hw, true);
} else {
rtl92ce_set_check_bssid(hw, false);
@@ -1459,7 +1503,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n",
rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1500,11 +1544,11 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
& 0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -1545,19 +1589,19 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
@@ -1565,7 +1609,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
@@ -1575,7 +1619,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1589,7 +1633,7 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
@@ -1629,6 +1673,21 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
if (rtlefuse->autoload_failflag)
return;
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROMId = 0x%4x\n", eeprom_id);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
for (i = 0; i < 6; i += 2) {
usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
*((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
@@ -1766,6 +1825,9 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value = sta->supp_rates[1] << 4;
else
ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
+
ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -1860,7 +1922,8 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
wirelessmode = sta_entry->wireless_mode;
- if (mac->opmode == NL80211_IFTYPE_STATION)
+ if (mac->opmode == NL80211_IFTYPE_STATION ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
curtxbw_40mhz = mac->bw_40;
else if (mac->opmode == NL80211_IFTYPE_AP ||
mac->opmode == NL80211_IFTYPE_ADHOC)
@@ -1870,6 +1933,8 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap = sta->supp_rates[1] << 4;
else
ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2135,7 +2200,8 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
macaddr = cam_const_broad;
entry_id = key_index;
} else {
- if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
entry_id = rtl_cam_get_free_entry(hw,
p_macaddr);
if (entry_id >= TOTAL_CAM_ENTRY) {
@@ -2157,7 +2223,8 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"delete one entry, entry_id is %d\n",
entry_id);
- if (mac->opmode == NL80211_IFTYPE_AP)
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT)
rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else {
@@ -2338,3 +2405,24 @@ void rtl92ce_suspend(struct ieee80211_hw *hw)
void rtl92ce_resume(struct ieee80211_hw *hw)
{
}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl92ce_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) {/* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ } else {/* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+ }
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config=0x%08X, write_into_reg=%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
index 52a3aea9b3de..2d063b0c7760 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -61,6 +61,8 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u8 rssi_level);
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw);
bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw);
@@ -74,5 +76,7 @@ void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw);
void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw);
void rtl92ce_suspend(struct ieee80211_hw *hw);
void rtl92ce_resume(struct ieee80211_hw *hw);
+void rtl92ce_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
index e4d738f6166d..bd4aef74c056 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -544,6 +544,7 @@
#define IMR_WLANOFF BIT(0)
#define EFUSE_REAL_CONTENT_LEN 512
+#define EFUSE_OOB_PROTECT_BYTES 15
#define EEPROM_DEFAULT_TSSI 0x0
#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index 49f663bd93ff..14203561b6ee 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -228,6 +228,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
.enable_hw_sec = rtl92ce_enable_hw_security_config,
.set_key = rtl92ce_set_key,
.init_sw_leds = rtl92ce_init_sw_leds,
+ .allow_all_destaddr = rtl92ce_allow_all_destaddr,
.get_bbreg = rtl92c_phy_query_bb_reg,
.set_bbreg = rtl92c_phy_set_bb_reg,
.set_rfreg = rtl92ce_phy_set_rf_reg,
@@ -278,6 +279,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
.maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
.maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+ .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
.maps[RWCAM] = REG_CAMCMD,
.maps[WCAMI] = REG_CAMWRITE,
@@ -309,7 +311,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index b9b1a6e0b16e..6ad23b413eb3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
+#include "../stats.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -42,7 +43,7 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
if (unlikely(ieee80211_is_beacon(fc)))
return QSLT_BEACON;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return QSLT_MGNT;
return skb->priority;
@@ -78,16 +79,6 @@ static u8 _rtl92c_evm_db_to_percentage(char value)
return ret_val;
}
-static long _rtl92ce_translate_todbm(struct ieee80211_hw *hw,
- u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
- return signal_power;
-}
-
static long _rtl92ce_signal_scale_mapping(struct ieee80211_hw *hw,
long currsig)
{
@@ -139,7 +130,6 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
pstats->packet_toself = packet_toself;
pstats->is_cck = is_cck_rate;
pstats->packet_beacon = packet_beacon;
- pstats->is_cck = is_cck_rate;
pstats->rx_mimo_sig_qual[0] = -1;
pstats->rx_mimo_sig_qual[1] = -1;
@@ -192,10 +182,30 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
}
}
- pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+ /* CCK gain is smaller than OFDM/MCS gain,
+ * so we add gain diff by experiences,
+ * the val is 6
+ */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same
+ * gain index with OFDM.
+ */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+
pstats->rx_pwdb_all = pwdb_all;
pstats->recvsignalpower = rx_pwr_all;
+ /* (3) Get Signal Quality (EVM) */
if (packet_match_bssid) {
u8 sq;
if (pstats->rx_pwdb_all > 40)
@@ -217,29 +227,38 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
} else {
rtlpriv->dm.rfpath_rxenable[0] =
rtlpriv->dm.rfpath_rxenable[1] = true;
+ /* (1)Get RSSI for HT rate */
for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ /* we will judge RF RX path now. */
if (rtlpriv->dm.rfpath_rxenable[i])
rf_rx_num++;
rx_pwr[i] =
((p_drvinfo->gain_trsw[i] & 0x3f) * 2) - 110;
+ /* Translate DBM to percentage. */
rssi = _rtl92c_query_rxpwrpercentage(rx_pwr[i]);
total_rssi += rssi;
+ /* Get Rx snr value in DB */
rtlpriv->stats.rx_snr_db[i] =
(long)(p_drvinfo->rxsnr[i] / 2);
+ /* Record Signal Strength for next packet */
if (packet_match_bssid)
pstats->rx_mimo_signalstrength[i] = (u8) rssi;
}
+ /* (2)PWDB, Average PWDB cacluated by
+ * hardware (for rate adaptive)
+ */
rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
pwdb_all = _rtl92c_query_rxpwrpercentage(rx_pwr_all);
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
- pdesc->rxmcs <= DESC92_RATEMCS15)
+ /* (3)EVM of HT rate */
+ if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 &&
+ pstats->rate <= DESC92_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -248,6 +267,9 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
evm = _rtl92c_evm_db_to_percentage(p_drvinfo->rxevm[i]);
if (packet_match_bssid) {
+ /* Fill value in RFD, Get the first
+ * spatial stream only
+ */
if (i == 0)
pstats->signalquality =
(u8) (evm & 0xff);
@@ -256,6 +278,9 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
}
}
+ /* UI BSS List signal strength(in percentage),
+ * make it good looking, from 0~100.
+ */
if (is_cck_rate)
pstats->signalstrength =
(u8) (_rtl92ce_signal_scale_mapping(hw, pwdb_all));
@@ -265,215 +290,6 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
(hw, total_rssi /= rf_rx_num));
}
-static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- u8 rfpath;
- u32 last_rssi, tmpval;
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- rtlpriv->stats.rssi_calculate_cnt++;
-
- if (rtlpriv->stats.ui_rssi.total_num++ >=
- PHY_RSSI_SLID_WIN_MAX) {
-
- rtlpriv->stats.ui_rssi.total_num =
- PHY_RSSI_SLID_WIN_MAX;
- last_rssi =
- rtlpriv->stats.ui_rssi.elements[rtlpriv->
- stats.ui_rssi.index];
- rtlpriv->stats.ui_rssi.total_val -= last_rssi;
- }
-
- rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
- rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.
- index++] =
- pstats->signalstrength;
-
- if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
- rtlpriv->stats.ui_rssi.index = 0;
-
- tmpval = rtlpriv->stats.ui_rssi.total_val /
- rtlpriv->stats.ui_rssi.total_num;
- rtlpriv->stats.signal_strength =
- _rtl92ce_translate_todbm(hw, (u8) tmpval);
- pstats->rssi = rtlpriv->stats.signal_strength;
- }
-
- if (!pstats->is_cck && pstats->packet_toself) {
- for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
- rfpath++) {
- if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- pstats->rx_mimo_signalstrength[rfpath];
-
- }
-
- if (pstats->rx_mimo_signalstrength[rfpath] >
- rtlpriv->stats.rx_rssi_percentage[rfpath]) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.
- rx_rssi_percentage[rfpath] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
-
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- rtlpriv->stats.rx_rssi_percentage[rfpath] +
- 1;
- } else {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.
- rx_rssi_percentage[rfpath] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
- }
-
- }
- }
-}
-
-static void _rtl92ce_update_rxsignalstatistics(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int weighting = 0;
-
- if (rtlpriv->stats.recv_signal_power == 0)
- rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
-
- if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
- weighting = 5;
-
- else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
- weighting = (-5);
-
- rtlpriv->stats.recv_signal_power =
- (rtlpriv->stats.recv_signal_power * 5 +
- pstats->recvsignalpower + weighting) / 6;
-}
-
-static void _rtl92ce_process_pwdb(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- long undec_sm_pwdb;
-
- if (mac->opmode == NL80211_IFTYPE_ADHOC) {
- return;
- } else {
- undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
- }
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- if (undec_sm_pwdb < 0)
- undec_sm_pwdb = pstats->rx_pwdb_all;
-
- if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-
- undec_sm_pwdb += 1;
- } else {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
- }
-
- rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
- _rtl92ce_update_rxsignalstatistics(hw, pstats);
- }
-}
-
-static void _rtl92ce_process_ui_link_quality(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 last_evm, n_spatialstream, tmpval;
-
- if (pstats->signalquality != 0) {
- if (pstats->packet_toself || pstats->packet_beacon) {
-
- if (rtlpriv->stats.ui_link_quality.total_num++ >=
- PHY_LINKQUALITY_SLID_WIN_MAX) {
- rtlpriv->stats.ui_link_quality.total_num =
- PHY_LINKQUALITY_SLID_WIN_MAX;
- last_evm =
- rtlpriv->stats.
- ui_link_quality.elements[rtlpriv->
- stats.ui_link_quality.
- index];
- rtlpriv->stats.ui_link_quality.total_val -=
- last_evm;
- }
-
- rtlpriv->stats.ui_link_quality.total_val +=
- pstats->signalquality;
- rtlpriv->stats.ui_link_quality.elements[rtlpriv->stats.
- ui_link_quality.
- index++] =
- pstats->signalquality;
-
- if (rtlpriv->stats.ui_link_quality.index >=
- PHY_LINKQUALITY_SLID_WIN_MAX)
- rtlpriv->stats.ui_link_quality.index = 0;
-
- tmpval = rtlpriv->stats.ui_link_quality.total_val /
- rtlpriv->stats.ui_link_quality.total_num;
- rtlpriv->stats.signal_quality = tmpval;
-
- rtlpriv->stats.last_sigstrength_inpercent = tmpval;
-
- for (n_spatialstream = 0; n_spatialstream < 2;
- n_spatialstream++) {
- if (pstats->
- rx_mimo_sig_qual[n_spatialstream] != -1) {
- if (rtlpriv->stats.
- rx_evm_percentage[n_spatialstream]
- == 0) {
- rtlpriv->stats.
- rx_evm_percentage
- [n_spatialstream] =
- pstats->rx_mimo_sig_qual
- [n_spatialstream];
- }
-
- rtlpriv->stats.
- rx_evm_percentage[n_spatialstream] =
- ((rtlpriv->
- stats.rx_evm_percentage
- [n_spatialstream] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_sig_qual
- [n_spatialstream] * 1)) /
- (RX_SMOOTH_FACTOR);
- }
- }
- }
- } else {
- ;
- }
-}
-
-static void _rtl92ce_process_phyinfo(struct ieee80211_hw *hw,
- u8 *buffer,
- struct rtl_stats *pcurrent_stats)
-{
-
- if (!pcurrent_stats->packet_matchbssid &&
- !pcurrent_stats->packet_beacon)
- return;
-
- _rtl92ce_process_ui_rssi(hw, pcurrent_stats);
- _rtl92ce_process_pwdb(hw, pcurrent_stats);
- _rtl92ce_process_ui_link_quality(hw, pcurrent_stats);
-}
-
static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct sk_buff *skb,
struct rtl_stats *pstats,
@@ -516,7 +332,7 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
packet_matchbssid, packet_toself,
packet_beacon);
- _rtl92ce_process_phyinfo(hw, tmp_buf, pstats);
+ rtl_process_phyinfo(hw, tmp_buf, pstats);
}
bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
@@ -526,7 +342,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
{
struct rx_fwinfo_92c *p_drvinfo;
struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc;
-
+ struct ieee80211_hdr *hdr;
u32 phystatus = GET_RX_DESC_PHYST(pdesc);
stats->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
stats->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
@@ -539,37 +355,60 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
stats->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
stats->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
stats->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
- stats->isampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+ stats->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
+ stats->is_cck = RX_HAL_IS_CCK_RATE(pdesc);
- if (GET_RX_DESC_CRC32(pdesc))
- rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
- if (!GET_RX_DESC_SWDEC(pdesc))
- rx_status->flag |= RX_FLAG_DECRYPTED;
+ hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size
+ + stats->rx_bufshift);
+
+ if (stats->crc)
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (GET_RX_DESC_BW(pdesc))
+ if (stats->rx_is40Mhzpacket)
rx_status->flag |= RX_FLAG_40MHZ;
- if (GET_RX_DESC_RXHT(pdesc))
+ if (stats->is_ht)
rx_status->flag |= RX_FLAG_HT;
rx_status->flag |= RX_FLAG_MACTIME_START;
- if (stats->decrypted)
- rx_status->flag |= RX_FLAG_DECRYPTED;
-
+ /* hw will set stats->decrypted true, if it finds the
+ * frame is open data frame or mgmt frame.
+ * So hw will not decryption robust managment frame
+ * for IEEE80211w but still set status->decrypted
+ * true, so here we should set it back to undecrypted
+ * for IEEE80211w frame, and mac80211 sw will help
+ * to decrypt it
+ */
+ if (stats->decrypted) {
+ if (!hdr) {
+ /* In testing, hdr was NULL here */
+ return false;
+ }
+ if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+ (ieee80211_has_protected(hdr->frame_control)))
+ rx_status->flag &= ~RX_FLAG_DECRYPTED;
+ else
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ }
+ /* rate_idx: index of data rate into band's
+ * supported rates or MCS index if HT rates
+ * are use (RX_FLAG_HT)
+ * Notice: this is diff with windows define
+ */
rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- (bool)GET_RX_DESC_RXHT(pdesc),
- (u8)GET_RX_DESC_RXMCS(pdesc),
- (bool)GET_RX_DESC_PAGGR(pdesc));
+ stats->is_ht, stats->rate,
+ stats->isfirst_ampdu);
- rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
+ rx_status->mactime = stats->timestamp_low;
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
stats->rx_bufshift);
@@ -580,7 +419,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
}
/*rx_status->qual = stats->signal; */
- rx_status->signal = stats->rssi + 10;
+ rx_status->signal = stats->recvsignalpower + 10;
/*rx_status->noise = -stats->noise; */
return true;
@@ -624,7 +463,8 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
if (mac->opmode == NL80211_IFTYPE_STATION) {
bw_40 = mac->bw_40;
} else if (mac->opmode == NL80211_IFTYPE_AP ||
- mac->opmode == NL80211_IFTYPE_ADHOC) {
+ mac->opmode == NL80211_IFTYPE_ADHOC ||
+ mac->opmode == NL80211_IFTYPE_MESH_POINT) {
if (sta)
bw_40 = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index c08d0f4c5f3d..3d0498e69c8c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -202,7 +202,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n", rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
@@ -238,11 +238,11 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
((rtlefuse->eeprom_pwrlimit_ht40[index]
& 0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -273,26 +273,26 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->legacy_ht_txpowerdiff =
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
if (!autoload_fail)
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail) {
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
@@ -301,7 +301,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
rtlefuse->eeprom_tssi[RF90_PATH_B] = EEPROM_DEFAULT_TSSI;
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -316,7 +316,7 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail)
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index a73a17bc56dd..23d640a4debd 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -223,7 +223,7 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index b6222eedb835..763cf1defab5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -324,8 +324,8 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
if (GET_RX_DESC_CRC32(pdesc))
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (!GET_RX_DESC_SWDEC(pdesc))
@@ -395,8 +395,8 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
stats.rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(rxdesc);
/* TODO: is center_freq changed when doing scan? */
/* TODO: Shall we add protection or just skip those two step? */
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
if (GET_RX_DESC_CRC32(rxdesc))
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (!GET_RX_DESC_SWDEC(rxdesc))
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
(u32)hdr->addr1[2], (u32)hdr->addr1[3],
(u32)hdr->addr1[4], (u32)hdr->addr1[5]);
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
- ieee80211_rx_irqsafe(hw, skb);
+ ieee80211_rx(hw, skb);
}
void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index 5251fb8a111e..19a765532603 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -171,8 +171,8 @@ static void rtl92d_dm_diginit(struct ieee80211_hw *hw)
de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- de_digtable->rx_gain_range_max = DM_DIG_FA_UPPER;
- de_digtable->rx_gain_range_min = DM_DIG_FA_LOWER;
+ de_digtable->rx_gain_max = DM_DIG_FA_UPPER;
+ de_digtable->rx_gain_min = DM_DIG_FA_LOWER;
de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
de_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
de_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -444,8 +444,8 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
"dm_DIG() Before: large_fa_hit=%d, forbidden_igi=%x\n",
de_digtable->large_fa_hit, de_digtable->forbidden_igi);
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
- "dm_DIG() Before: Recover_cnt=%d, rx_gain_range_min=%x\n",
- de_digtable->recover_cnt, de_digtable->rx_gain_range_min);
+ "dm_DIG() Before: Recover_cnt=%d, rx_gain_min=%x\n",
+ de_digtable->recover_cnt, de_digtable->rx_gain_min);
/* deal with abnorally large false alarm */
if (falsealm_cnt->cnt_all > 10000) {
@@ -459,9 +459,9 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
}
if (de_digtable->large_fa_hit >= 3) {
if ((de_digtable->forbidden_igi + 1) > DM_DIG_MAX)
- de_digtable->rx_gain_range_min = DM_DIG_MAX;
+ de_digtable->rx_gain_min = DM_DIG_MAX;
else
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
(de_digtable->forbidden_igi + 1);
de_digtable->recover_cnt = 3600; /* 3600=2hr */
}
@@ -475,12 +475,12 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
DM_DIG_FA_LOWER) {
de_digtable->forbidden_igi =
DM_DIG_FA_LOWER;
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
DM_DIG_FA_LOWER;
} else {
de_digtable->forbidden_igi--;
- de_digtable->rx_gain_range_min =
+ de_digtable->rx_gain_min =
(de_digtable->forbidden_igi + 1);
}
} else if (de_digtable->large_fa_hit == 3) {
@@ -492,13 +492,13 @@ static void rtl92d_dm_dig(struct ieee80211_hw *hw)
"dm_DIG() After: large_fa_hit=%d, forbidden_igi=%x\n",
de_digtable->large_fa_hit, de_digtable->forbidden_igi);
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
- "dm_DIG() After: recover_cnt=%d, rx_gain_range_min=%x\n",
- de_digtable->recover_cnt, de_digtable->rx_gain_range_min);
+ "dm_DIG() After: recover_cnt=%d, rx_gain_min=%x\n",
+ de_digtable->recover_cnt, de_digtable->rx_gain_min);
if (value_igi > DM_DIG_MAX)
value_igi = DM_DIG_MAX;
- else if (value_igi < de_digtable->rx_gain_range_min)
- value_igi = de_digtable->rx_gain_range_min;
+ else if (value_igi < de_digtable->rx_gain_min)
+ value_igi = de_digtable->rx_gain_min;
de_digtable->cur_igvalue = value_igi;
rtl92d_dm_write_dig(hw);
if (rtlpriv->rtlhal.current_bandtype != BAND_ON_5G)
@@ -1071,9 +1071,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
}
ele_d = (ofdmswing_table[(u8) ofdm_index[0]] &
0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix_regsetting
+ val_x = rtlphy->iqk_matrix
[indexforchannel].value[0][0];
- val_y = rtlphy->iqk_matrix_regsetting
+ val_y = rtlphy->iqk_matrix
[indexforchannel].value[0][1];
if (val_x != 0) {
if ((val_x & 0x00000200) != 0)
@@ -1175,9 +1175,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
if (is2t) {
ele_d = (ofdmswing_table[(u8) ofdm_index[1]] &
0xFFC00000) >> 22;
- val_x = rtlphy->iqk_matrix_regsetting
+ val_x = rtlphy->iqk_matrix
[indexforchannel].value[0][4];
- val_y = rtlphy->iqk_matrix_regsetting
+ val_y = rtlphy->iqk_matrix
[indexforchannel].value[0][5];
if (val_x != 0) {
if ((val_x & 0x00000200) != 0)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index aa5b42521bb4..7dd8f6de0550 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -1183,7 +1183,7 @@ void rtl92d_linked_set_reg(struct ieee80211_hw *hw)
u8 channel = rtlphy->current_channel;
indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel);
- if (!rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done) {
+ if (!rtlphy->iqk_matrix[indexforchannel].iqk_done) {
RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_DMESG,
"Do IQK for channel:%d\n", channel);
rtl92d_phy_iq_calibrate(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
index 33041bd4da81..840bac5fa2f8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c
@@ -2479,9 +2479,9 @@ void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw)
rtlphy->current_channel);
for (i = 0; i < IQK_MATRIX_REG_NUM; i++)
- rtlphy->iqk_matrix_regsetting[indexforchannel].
+ rtlphy->iqk_matrix[indexforchannel].
value[0][i] = result[final_candidate][i];
- rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done =
+ rtlphy->iqk_matrix[indexforchannel].iqk_done =
true;
RT_TRACE(rtlpriv, COMP_SCAN | COMP_MLME, DBG_LOUD,
@@ -2501,8 +2501,8 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)
indexforchannel = rtl92d_get_rightchnlplace_for_iqk(channel);
RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "indexforchannel %d done %d\n",
indexforchannel,
- rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done);
- if (0 && !rtlphy->iqk_matrix_regsetting[indexforchannel].iqk_done &&
+ rtlphy->iqk_matrix[indexforchannel].iqk_done);
+ if (0 && !rtlphy->iqk_matrix[indexforchannel].iqk_done &&
rtlphy->need_iqk) {
/* Re Do IQK. */
RT_TRACE(rtlpriv, COMP_SCAN | COMP_INIT, DBG_LOUD,
@@ -2516,23 +2516,23 @@ void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel)
RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD,
"Just Read IQK Matrix reg for channel:%d....\n",
channel);
- if ((rtlphy->iqk_matrix_regsetting[indexforchannel].
+ if ((rtlphy->iqk_matrix[indexforchannel].
value[0] != NULL)
/*&&(regea4 != 0) */)
_rtl92d_phy_patha_fill_iqk_matrix(hw, true,
- rtlphy->iqk_matrix_regsetting[
+ rtlphy->iqk_matrix[
indexforchannel].value, 0,
- (rtlphy->iqk_matrix_regsetting[
+ (rtlphy->iqk_matrix[
indexforchannel].value[0][2] == 0));
if (IS_92D_SINGLEPHY(rtlhal->version)) {
- if ((rtlphy->iqk_matrix_regsetting[
+ if ((rtlphy->iqk_matrix[
indexforchannel].value[0][4] != 0)
/*&&(regec4 != 0) */)
_rtl92d_phy_pathb_fill_iqk_matrix(hw,
true,
- rtlphy->iqk_matrix_regsetting[
+ rtlphy->iqk_matrix[
indexforchannel].value, 0,
- (rtlphy->iqk_matrix_regsetting[
+ (rtlphy->iqk_matrix[
indexforchannel].value[0][6]
== 0));
}
@@ -2830,20 +2830,20 @@ void rtl92d_phy_reset_iqk_result(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
"settings regs %d default regs %d\n",
- (int)(sizeof(rtlphy->iqk_matrix_regsetting) /
+ (int)(sizeof(rtlphy->iqk_matrix) /
sizeof(struct iqk_matrix_regs)),
IQK_MATRIX_REG_NUM);
/* 0xe94, 0xe9c, 0xea4, 0xeac, 0xeb4, 0xebc, 0xec4, 0xecc */
for (i = 0; i < IQK_MATRIX_SETTINGS_NUM; i++) {
- rtlphy->iqk_matrix_regsetting[i].value[0][0] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][2] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][4] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][6] = 0x100;
- rtlphy->iqk_matrix_regsetting[i].value[0][1] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][3] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][5] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].value[0][7] = 0x0;
- rtlphy->iqk_matrix_regsetting[i].iqk_done = false;
+ rtlphy->iqk_matrix[i].value[0][0] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][2] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][4] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][6] = 0x100;
+ rtlphy->iqk_matrix[i].value[0][1] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][3] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][5] = 0x0;
+ rtlphy->iqk_matrix[i].value[0][7] = 0x0;
+ rtlphy->iqk_matrix[i].iqk_done = false;
}
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
index ebb1d5f5e7b5..b7498c5bafc5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/reg.h
@@ -543,7 +543,7 @@
#define IMR_TIMEOUT1 BIT(16)
#define IMR_TXFOVW BIT(15)
#define IMR_PSTIMEOUT BIT(14)
-#define IMR_BcnInt BIT(13)
+#define IMR_BCNINT BIT(13)
#define IMR_RXFOVW BIT(12)
#define IMR_RDU BIT(11)
#define IMR_ATIMEND BIT(10)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
index 03c6d18b2e07..c18c04bf0c13 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
@@ -166,7 +166,7 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
/* for early mode */
- rtlpriv->rtlhal.earlymode_enable = true;
+ rtlpriv->rtlhal.earlymode_enable = false;
for (tid = 0; tid < 8; tid++)
skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]);
@@ -319,7 +319,7 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BcnInt,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
@@ -333,7 +333,7 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_VIDOK] = IMR_VIDOK,
.maps[RTL_IMR_VODOK] = IMR_VODOK,
.maps[RTL_IMR_ROK] = IMR_ROK,
- .maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER),
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
.maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
.maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index 941080e03c06..b8ec718a0fab 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -499,8 +499,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
if (GET_RX_DESC_CRC32(pdesc))
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
if (!GET_RX_DESC_SWDEC(pdesc))
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
index 2d255e02d795..83c98674bfd3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -36,9 +36,6 @@
#define SHORT_SLOT_TIME 9
#define NON_SHORT_SLOT_TIME 20
-/* Rx smooth factor */
-#define RX_SMOOTH_FACTOR 20
-
/* Queue Select Value in TxDesc */
#define QSLT_BK 0x2
#define QSLT_BE 0x0
@@ -49,10 +46,6 @@
#define QSLT_MGNT 0x12
#define QSLT_CMD 0x13
-#define PHY_RSSI_SLID_WIN_MAX 100
-#define PHY_LINKQUALITY_SLID_WIN_MAX 20
-#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
-
/* Tx Desc */
#define TX_DESC_SIZE_RTL8192S (16 * 4)
#define TX_CMDDESC_SIZE_RTL8192S (16 * 4)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index e551fe5f9ccd..b3a2d5ec59e6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -163,6 +163,7 @@ static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 thermalvalue = 0;
+ u32 fw_cmd = 0;
rtlpriv->dm.txpower_trackinginit = true;
@@ -175,7 +176,19 @@ static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
if (thermalvalue) {
rtlpriv->dm.thermalvalue = thermalvalue;
- rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ } else {
+ fw_cmd = (FW_TXPWR_TRACK_THERMAL |
+ (rtlpriv->efuse.thermalmeter[0] << 8) |
+ (thermalvalue << 16));
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ "Write to FW Thermal Val = 0x%x\n", fw_cmd);
+
+ rtl_write_dword(rtlpriv, WFM5, fw_cmd);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ }
}
rtlpriv->dm.txpowercount = 0;
@@ -217,11 +230,10 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rate_adaptive *ra = &(rtlpriv->ra);
-
+ struct ieee80211_sta *sta = NULL;
u32 low_rssi_thresh = 0;
u32 middle_rssi_thresh = 0;
u32 high_rssi_thresh = 0;
- struct ieee80211_sta *sta = NULL;
if (is_hal_stop(rtlhal))
return;
@@ -229,14 +241,12 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
if (!rtlpriv->dm.useramask)
return;
- if (!rtlpriv->dm.inform_fw_driverctrldm) {
+ if (hal_get_firmwareversion(rtlpriv) >= 61 &&
+ !rtlpriv->dm.inform_fw_driverctrldm) {
rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER);
rtlpriv->dm.inform_fw_driverctrldm = true;
}
- rcu_read_lock();
- if (mac->opmode == NL80211_IFTYPE_STATION)
- sta = get_sta(hw, mac->vif, mac->bssid);
if ((mac->link_state == MAC80211_LINKED) &&
(mac->opmode == NL80211_IFTYPE_STATION)) {
switch (ra->pre_ratr_state) {
@@ -285,12 +295,16 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
rtlpriv->dm.undec_sm_pwdb, ra->ratr_state,
ra->pre_ratr_state, ra->ratr_state);
- rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
ra->ratr_state);
+ rcu_read_unlock();
+
ra->pre_ratr_state = ra->ratr_state;
}
}
- rcu_read_unlock();
}
static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
@@ -370,7 +384,8 @@ static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
ra->ratr_state = DM_RATR_STA_MAX;
ra->pre_ratr_state = DM_RATR_STA_MAX;
- if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER &&
+ hal_get_firmwareversion(rtlpriv) >= 60)
rtlpriv->dm.useramask = true;
else
rtlpriv->dm.useramask = false;
@@ -457,13 +472,13 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
digtable->back_val = DM_DIG_BACKOFF;
if ((digtable->rssi_val + 10 - digtable->back_val) >
- digtable->rx_gain_range_max)
+ digtable->rx_gain_max)
digtable->cur_igvalue =
- digtable->rx_gain_range_max;
+ digtable->rx_gain_max;
else if ((digtable->rssi_val + 10 - digtable->back_val)
- < digtable->rx_gain_range_min)
+ < digtable->rx_gain_min)
digtable->cur_igvalue =
- digtable->rx_gain_range_min;
+ digtable->rx_gain_min;
else
digtable->cur_igvalue = digtable->rssi_val + 10
- digtable->back_val;
@@ -475,7 +490,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
if (falsealm_cnt->cnt_all > 16000)
digtable->cur_igvalue =
- digtable->rx_gain_range_max;
+ digtable->rx_gain_max;
/* connected -> connected or disconnected -> disconnected */
} else {
/* Firmware control DIG, do nothing in driver dm */
@@ -677,9 +692,9 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
/* for dig debug rssi value */
digtable->rssi_val = 50;
digtable->back_val = DM_DIG_BACKOFF;
- digtable->rx_gain_range_max = DM_DIG_MAX;
+ digtable->rx_gain_max = DM_DIG_MAX;
- digtable->rx_gain_range_min = DM_DIG_MIN;
+ digtable->rx_gain_min = DM_DIG_MIN;
digtable->backoffval_range_max = DM_DIG_BACKOFF_MAX;
digtable->backoffval_range_min = DM_DIG_BACKOFF_MIN;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
index 084e7773bce2..4f461786a7eb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -400,6 +400,39 @@ void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -438,7 +471,7 @@ void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw)
}
-static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data)
+static u8 _rtl92se_halset_sysclk(struct ieee80211_hw *hw, u8 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 waitcount = 100;
@@ -547,7 +580,7 @@ static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
tmpu1b &= ~(BIT(6) | BIT(7));
/* Set failed, return to prevent hang. */
- if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ if (!_rtl92se_halset_sysclk(hw, tmpu1b))
return;
}
@@ -650,7 +683,7 @@ static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
- if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ if (!_rtl92se_halset_sysclk(hw, tmpu1b))
return; /* Set failed, return to prevent hang. */
rtl_write_word(rtlpriv, CMDR, 0x07FC);
@@ -967,6 +1000,15 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
return rtstatus;
}
+ /* because last function modify RCR, so we update
+ * rcr var here, or TP will unstable for receive_config
+ * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx
+ * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+ */
+ rtlpci->receive_config = rtl_read_dword(rtlpriv, RCR);
+ rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
/* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */
/* We must set flag avoid BB/RF config period later!! */
rtl_write_dword(rtlpriv, CMDR, 0x37FC);
@@ -982,25 +1024,6 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
- /* RF Power Save */
-#if 0
- /* H/W or S/W RF OFF before sleep. */
- if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) {
- u32 rfoffreason = rtlpriv->psc.rfoff_reason;
-
- rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT;
- rtlpriv->psc.rfpwr_state = ERFON;
- /* FIXME: check spinlocks if this block is uncommented */
- rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason);
- } else {
- /* gpio radio on/off is out of adapter start */
- if (rtlpriv->psc.hwradiooff == false) {
- rtlpriv->psc.rfpwr_state = ERFON;
- rtlpriv->psc.rfoff_reason = 0;
- }
- }
-#endif
-
/* Before RF-R/W we must execute the IO from Scott's suggestion. */
rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB);
if (rtlhal->version == VERSION_8192S_ACUT)
@@ -1058,7 +1081,22 @@ int rtl92se_hw_init(struct ieee80211_hw *hw)
/* We enable high power and RA related mechanism after NIC
* initialized. */
- rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ /* Fw v.53 and later. */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+ } else if (hal_get_firmwareversion(rtlpriv) == 0x34) {
+ /* Fw v.52. */
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_INIT);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ } else {
+ /* Compatible earlier FW version. */
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ }
/* Add to prevent ASPM bug. */
/* Always enable hst and NIC clock request. */
@@ -1229,7 +1267,6 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
synchronize_irq(rtlpci->pdev->irq);
}
-
static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1754,7 +1791,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = [0x%x / 0x%x / 0x%x]\n",
rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1791,11 +1828,11 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
((rtlefuse->eeprom_pwrgroup[rf_path][index] &
0xf0) >> 4);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n",
rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
@@ -1850,27 +1887,27 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->eeprom_regulatory =
(hwinfo[EEPROM_REGULATORY] & 0x1);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n",
i, rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TxPwrSafetyFlag = %d\n", rtlefuse->txpwr_safetyflag);
/* Read RF-indication and Tx Power gain
@@ -1880,7 +1917,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->legacy_httxpowerdiff =
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0];
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TxPowerDiff = %#x\n", rtlefuse->eeprom_txpowerdiff);
/* Get TSSI value for each path. */
@@ -1889,7 +1926,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
usvalue = hwinfo[EEPROM_TSSI_B];
rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1897,7 +1934,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
/* and read ThermalMeter from EEPROM */
tempval = hwinfo[EEPROM_THERMALMETER];
rtlefuse->eeprom_thermalmeter = tempval;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
/* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */
@@ -1914,7 +1951,7 @@ static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
/* Version ID, Channel plan */
rtlefuse->eeprom_channelplan = hwinfo[EEPROM_CHANNELPLAN];
rtlefuse->txpwr_fromeprom = true;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"EEPROM ChannelPlan = 0x%4x\n", rtlefuse->eeprom_channelplan);
/* Read Customer ID or Board Type!!! */
@@ -1999,6 +2036,8 @@ static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw,
ratr_value = sta->supp_rates[1] << 4;
else
ratr_value = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_value = 0xfff;
ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2112,6 +2151,8 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap = sta->supp_rates[1] << 4;
else
ratr_bitmap = sta->supp_rates[0];
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ ratr_bitmap = 0xfff;
ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
@@ -2200,6 +2241,7 @@ static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
ratr_bitmap &= 0x0f8ff0ff;
break;
}
+ sta_entry->ratr_index = ratr_index;
if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
ratr_bitmap &= 0x0FFFFFFF;
@@ -2438,23 +2480,9 @@ void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr,
rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else {
- RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
- "The insert KEY length is %d\n",
- rtlpriv->sec.key_len[PAIRWISE_KEYIDX]);
- RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
- "The insert KEY is %x %x\n",
- rtlpriv->sec.key_buf[0][0],
- rtlpriv->sec.key_buf[0][1]);
-
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"add one entry\n");
if (is_pairwise) {
- RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD,
- "Pairwise Key content",
- rtlpriv->sec.pairwise_key,
- rtlpriv->sec.
- key_len[PAIRWISE_KEYIDX]);
-
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
"set Pairwise key\n");
@@ -2502,3 +2530,23 @@ void rtl92se_resume(struct ieee80211_hw *hw)
pci_write_config_dword(rtlpci->pdev, 0x40,
val & 0xffff00ff);
}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl92se_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ if (allow_all_da) /* Set BIT0 */
+ rtlpci->receive_config |= RCR_AAP;
+ else /* Clear BIT0 */
+ rtlpci->receive_config &= ~RCR_AAP;
+
+ if (write_into_reg)
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
+ RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+ "receive_config=0x%08X, write_into_reg=%d\n",
+ rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
index a8e068c76e47..da48aa8cbe6f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
@@ -74,6 +74,7 @@ void rtl92se_set_key(struct ieee80211_hw *hw,
u8 enc_algo, bool is_wepkey, bool clear_all);
void rtl92se_suspend(struct ieee80211_hw *hw);
void rtl92se_resume(struct ieee80211_hw *hw);
+void rtl92se_allow_all_destaddr(struct ieee80211_hw *hw,
+ bool allow_all_da, bool write_into_reg);
#endif
-
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
index 67404975e00b..9c092e6eb3fe 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -1307,6 +1307,8 @@ static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
if (is_hal_stop(rtlhal))
return;
+ if (hal_get_firmwareversion(rtlpriv) < 0x34)
+ goto skip;
/* We re-map RA related CMD IO to combinational ones */
/* if FW version is v.52 or later. */
switch (rtlhal->current_fwcmd_io) {
@@ -1320,6 +1322,7 @@ static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
break;
}
+skip:
switch (rtlhal->current_fwcmd_io) {
case FW_CMD_RA_RESET:
RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG, "FW_CMD_RA_RESET\n");
@@ -1440,7 +1443,7 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv);
u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv);
- bool bPostProcessing = false;
+ bool postprocessing = false;
RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
"Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n",
@@ -1449,15 +1452,24 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
do {
/* We re-map to combined FW CMD ones if firmware version */
/* is v.53 or later. */
- switch (fw_cmdio) {
- case FW_CMD_RA_REFRESH_N:
- fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
- break;
- case FW_CMD_RA_REFRESH_BG:
- fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
- break;
- default:
- break;
+ if (hal_get_firmwareversion(rtlpriv) >= 0x35) {
+ switch (fw_cmdio) {
+ case FW_CMD_RA_REFRESH_N:
+ fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+ } else {
+ if ((fw_cmdio == FW_CMD_IQK_ENABLE) ||
+ (fw_cmdio == FW_CMD_RA_REFRESH_N) ||
+ (fw_cmdio == FW_CMD_RA_REFRESH_BG)) {
+ postprocessing = true;
+ break;
+ }
}
/* If firmware version is v.62 or later,
@@ -1588,19 +1600,19 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_PAUSE_DM_BY_SCAN:
fw_cmdmap &= ~(FW_DIG_ENABLE_CTL |
FW_HIGH_PWR_ENABLE_CTL |
FW_SS_CTL);
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_HIGH_PWR_DISABLE:
fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
break;
case FW_CMD_HIGH_PWR_ENABLE:
if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) &&
@@ -1608,7 +1620,7 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL |
FW_SS_CTL);
FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
- bPostProcessing = true;
+ postprocessing = true;
}
break;
case FW_CMD_DIG_MODE_FA:
@@ -1629,14 +1641,15 @@ bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
default:
/* Pass to original FW CMD processing callback
* routine. */
- bPostProcessing = true;
+ postprocessing = true;
break;
}
} while (false);
/* We shall post processing these FW CMD if
- * variable bPostProcessing is set. */
- if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) {
+ * variable postprocessing is set.
+ */
+ if (postprocessing && !rtlhal->set_fwcmd_inprogress) {
rtlhal->set_fwcmd_inprogress = true;
/* Update current FW Cmd for callback use. */
rtlhal->current_fwcmd_io = fw_cmdio;
@@ -1697,8 +1710,18 @@ void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw)
}
-void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval)
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8));
+ u32 new_bcn_num = 0;
+
+ if (hal_get_firmwareversion(rtlpriv) >= 0x33) {
+ /* Fw v.51 and later. */
+ rtl_write_dword(rtlpriv, WFM5, 0xF1000000 |
+ (beaconinterval << 8));
+ } else {
+ new_bcn_num = beaconinterval * 32 - 64;
+ rtl_write_dword(rtlpriv, WFM3 + 4, new_bcn_num);
+ rtl_write_dword(rtlpriv, WFM3, 0xB026007C);
+ }
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
index ac0387770630..8acf4765a7a6 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
@@ -39,6 +39,7 @@
#define MAX_POSTCMD_CNT 16
#define RF90_PATH_MAX 4
+#define RF6052_MAX_PATH 2
enum version_8192s {
VERSION_8192S_ACUT,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index cecc377e9e61..2e8e6f8d2d51 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -290,6 +290,7 @@ static struct rtl_hal_ops rtl8192se_hal_ops = {
.enable_hw_sec = rtl92se_enable_hw_security_config,
.set_key = rtl92se_set_key,
.init_sw_leds = rtl92se_init_sw_leds,
+ .allow_all_destaddr = rtl92se_allow_all_destaddr,
.get_bbreg = rtl92s_phy_query_bb_reg,
.set_bbreg = rtl92s_phy_set_bb_reg,
.get_rfreg = rtl92s_phy_query_rf_reg,
@@ -366,7 +367,7 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_BCNINT] = IMR_BCNINT,
.maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
.maps[RTL_IMR_RDU] = IMR_RDU,
.maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 7b0a2e75b8b8..c7095118de6e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../pci.h"
#include "../base.h"
+#include "../stats.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -43,7 +44,7 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
if (unlikely(ieee80211_is_beacon(fc)))
return QSLT_BEACON;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return QSLT_MGNT;
if (ieee80211_is_nullfunc(fc))
return QSLT_HIGH;
@@ -51,65 +52,6 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
return skb->priority;
}
-static u8 _rtl92s_query_rxpwrpercentage(char antpower)
-{
- if ((antpower <= -100) || (antpower >= 20))
- return 0;
- else if (antpower >= 0)
- return 100;
- else
- return 100 + antpower;
-}
-
-static u8 _rtl92s_evm_db_to_percentage(char value)
-{
- char ret_val;
- ret_val = value;
-
- if (ret_val >= 0)
- ret_val = 0;
-
- if (ret_val <= -33)
- ret_val = -33;
-
- ret_val = 0 - ret_val;
- ret_val *= 3;
-
- if (ret_val == 99)
- ret_val = 100;
-
- return ret_val;
-}
-
-static long _rtl92se_translate_todbm(struct ieee80211_hw *hw,
- u8 signal_strength_index)
-{
- long signal_power;
-
- signal_power = (long)((signal_strength_index + 1) >> 1);
- signal_power -= 95;
- return signal_power;
-}
-
-static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw,
- long currsig)
-{
- long retsig = 0;
-
- /* Step 1. Scale mapping. */
- if (currsig > 47)
- retsig = 100;
- else if (currsig > 14 && currsig <= 47)
- retsig = 100 - ((47 - currsig) * 3) / 2;
- else if (currsig > 2 && currsig <= 14)
- retsig = 48 - ((14 - currsig) * 15) / 7;
- else if (currsig >= 0)
- retsig = currsig * 9 + 1;
-
- return retsig;
-}
-
-
static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstats, u8 *pdesc,
struct rx_fwinfo *p_drvinfo,
@@ -119,11 +61,11 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct phy_sts_cck_8192s_t *cck_buf;
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
s8 rx_pwr_all = 0, rx_pwr[4];
u8 rf_rx_num = 0, evm, pwdb_all;
u8 i, max_spatial_stream;
u32 rssi, total_rssi = 0;
- bool in_powersavemode = false;
bool is_cck = pstats->is_cck;
pstats->packet_matchbssid = packet_match_bssid;
@@ -136,7 +78,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
u8 report, cck_highpwr;
cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
- if (!in_powersavemode)
+ if (ppsc->rfpwr_state == ERFON)
cck_highpwr = (u8) rtl_get_bbreg(hw,
RFPGA0_XA_HSSIPARAMETER2,
0x200);
@@ -181,7 +123,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
}
- pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
/* CCK gain is smaller than OFDM/MCS gain, */
/* so we add gain diff by experiences, the val is 6 */
@@ -222,13 +164,13 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
} else {
rtlpriv->dm.rfpath_rxenable[0] =
rtlpriv->dm.rfpath_rxenable[1] = true;
- for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
if (rtlpriv->dm.rfpath_rxenable[i])
rf_rx_num++;
rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
0x3f) * 2) - 110;
- rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]);
+ rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
total_rssi += rssi;
rtlpriv->stats.rx_snr_db[i] =
(long)(p_drvinfo->rxsnr[i] / 2);
@@ -238,7 +180,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
- pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
@@ -250,7 +192,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
max_spatial_stream = 1;
for (i = 0; i < max_spatial_stream; i++) {
- evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+ evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
if (packet_match_bssid) {
if (i == 0)
@@ -262,212 +204,13 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
}
if (is_cck)
- pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw,
+ pstats->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
pwdb_all));
else if (rf_rx_num != 0)
- pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw,
+ pstats->signalstrength = (u8) (rtl_signal_scale_mapping(hw,
total_rssi /= rf_rx_num));
}
-static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
- u8 rfpath;
- u32 last_rssi, tmpval;
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- rtlpriv->stats.rssi_calculate_cnt++;
-
- if (rtlpriv->stats.ui_rssi.total_num++ >=
- PHY_RSSI_SLID_WIN_MAX) {
- rtlpriv->stats.ui_rssi.total_num =
- PHY_RSSI_SLID_WIN_MAX;
- last_rssi = rtlpriv->stats.ui_rssi.elements[
- rtlpriv->stats.ui_rssi.index];
- rtlpriv->stats.ui_rssi.total_val -= last_rssi;
- }
-
- rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
- rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++]
- = pstats->signalstrength;
-
- if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
- rtlpriv->stats.ui_rssi.index = 0;
-
- tmpval = rtlpriv->stats.ui_rssi.total_val /
- rtlpriv->stats.ui_rssi.total_num;
- rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw,
- (u8) tmpval);
- pstats->rssi = rtlpriv->stats.signal_strength;
- }
-
- if (!pstats->is_cck && pstats->packet_toself) {
- for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
- rfpath++) {
- if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- pstats->rx_mimo_signalstrength[rfpath];
-
- }
-
- if (pstats->rx_mimo_signalstrength[rfpath] >
- rtlpriv->stats.rx_rssi_percentage[rfpath]) {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.rx_rssi_percentage[rfpath]
- * (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
-
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- rtlpriv->stats.rx_rssi_percentage[rfpath]
- + 1;
- } else {
- rtlpriv->stats.rx_rssi_percentage[rfpath] =
- ((rtlpriv->stats.rx_rssi_percentage[rfpath]
- * (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_signalstrength[rfpath])) /
- (RX_SMOOTH_FACTOR);
- }
-
- }
- }
-}
-
-static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- int weighting = 0;
-
- if (rtlpriv->stats.recv_signal_power == 0)
- rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
-
- if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
- weighting = 5;
- else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
- weighting = (-5);
-
- rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5
- + pstats->recvsignalpower +
- weighting) / 6;
-}
-
-static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- long undec_sm_pwdb = 0;
-
- if (mac->opmode == NL80211_IFTYPE_ADHOC) {
- return;
- } else {
- undec_sm_pwdb =
- rtlpriv->dm.undec_sm_pwdb;
- }
-
- if (pstats->packet_toself || pstats->packet_beacon) {
- if (undec_sm_pwdb < 0)
- undec_sm_pwdb = pstats->rx_pwdb_all;
-
- if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
- undec_sm_pwdb =
- (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-
- undec_sm_pwdb = undec_sm_pwdb + 1;
- } else {
- undec_sm_pwdb = (((undec_sm_pwdb) *
- (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) /
- (RX_SMOOTH_FACTOR);
- }
-
- rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
- _rtl92se_update_rxsignalstatistics(hw, pstats);
- }
-}
-
-static void rtl_92s_process_streams(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 stream;
-
- for (stream = 0; stream < 2; stream++) {
- if (pstats->rx_mimo_sig_qual[stream] != -1) {
- if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
- rtlpriv->stats.rx_evm_percentage[stream] =
- pstats->rx_mimo_sig_qual[stream];
- }
-
- rtlpriv->stats.rx_evm_percentage[stream] =
- ((rtlpriv->stats.rx_evm_percentage[stream] *
- (RX_SMOOTH_FACTOR - 1)) +
- (pstats->rx_mimo_sig_qual[stream] *
- 1)) / (RX_SMOOTH_FACTOR);
- }
- }
-}
-
-static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw,
- struct rtl_stats *pstats)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u32 last_evm = 0, tmpval;
-
- if (pstats->signalquality != 0) {
- if (pstats->packet_toself || pstats->packet_beacon) {
-
- if (rtlpriv->stats.ui_link_quality.total_num++ >=
- PHY_LINKQUALITY_SLID_WIN_MAX) {
- rtlpriv->stats.ui_link_quality.total_num =
- PHY_LINKQUALITY_SLID_WIN_MAX;
- last_evm =
- rtlpriv->stats.ui_link_quality.elements[
- rtlpriv->stats.ui_link_quality.index];
- rtlpriv->stats.ui_link_quality.total_val -=
- last_evm;
- }
-
- rtlpriv->stats.ui_link_quality.total_val +=
- pstats->signalquality;
- rtlpriv->stats.ui_link_quality.elements[
- rtlpriv->stats.ui_link_quality.index++] =
- pstats->signalquality;
-
- if (rtlpriv->stats.ui_link_quality.index >=
- PHY_LINKQUALITY_SLID_WIN_MAX)
- rtlpriv->stats.ui_link_quality.index = 0;
-
- tmpval = rtlpriv->stats.ui_link_quality.total_val /
- rtlpriv->stats.ui_link_quality.total_num;
- rtlpriv->stats.signal_quality = tmpval;
-
- rtlpriv->stats.last_sigstrength_inpercent = tmpval;
-
- rtl_92s_process_streams(hw, pstats);
-
- }
- }
-}
-
-static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw,
- u8 *buffer,
- struct rtl_stats *pcurrent_stats)
-{
-
- if (!pcurrent_stats->packet_matchbssid &&
- !pcurrent_stats->packet_beacon)
- return;
-
- _rtl92se_process_ui_rssi(hw, pcurrent_stats);
- _rtl92se_process_pwdb(hw, pcurrent_stats);
- _rtl92se_process_ui_link_quality(hw, pcurrent_stats);
-}
-
static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_stats *pstats,
u8 *pdesc, struct rx_fwinfo *p_drvinfo)
@@ -505,7 +248,7 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
_rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
packet_matchbssid, packet_toself, packet_beacon);
- _rtl92se_process_phyinfo(hw, tmp_buf, pstats);
+ rtl_process_phyinfo(hw, tmp_buf, pstats);
}
bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
@@ -538,11 +281,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
if (stats->hwerror)
return false;
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
-
- hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size
- + stats->rx_bufshift);
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
if (stats->crc)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -563,6 +303,13 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
* for IEEE80211w frame, and mac80211 sw will help
* to decrypt it */
if (stats->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ stats->rx_drvinfo_size + stats->rx_bufshift);
+
+ if (!hdr) {
+ /* during testing, hdr was NULL here */
+ return false;
+ }
if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
@@ -630,6 +377,11 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S);
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
+
if (firstseg) {
if (rtlpriv->dm.useramask) {
/* set txdesc macId */
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
index 12e2a3cb0701..a36eee28f9e7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
@@ -166,8 +166,8 @@ static void rtl8723ae_dm_diginit(struct ieee80211_hw *hw)
dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_range_max = DM_DIG_MAX;
- dm_digtable->rx_gain_range_min = DM_DIG_MIN;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
@@ -291,11 +291,11 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
}
if ((dgtbl->rssi_val_min + 10 - dgtbl->back_val) >
- dgtbl->rx_gain_range_max)
- dgtbl->cur_igvalue = dgtbl->rx_gain_range_max;
+ dgtbl->rx_gain_max)
+ dgtbl->cur_igvalue = dgtbl->rx_gain_max;
else if ((dgtbl->rssi_val_min + 10 -
- dgtbl->back_val) < dgtbl->rx_gain_range_min)
- dgtbl->cur_igvalue = dgtbl->rx_gain_range_min;
+ dgtbl->back_val) < dgtbl->rx_gain_min)
+ dgtbl->cur_igvalue = dgtbl->rx_gain_min;
else
dgtbl->cur_igvalue = dgtbl->rssi_val_min + 10 - dgtbl->back_val;
@@ -707,6 +707,77 @@ void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
rtlpriv->dm.useramask = false;
}
+static void rtl8723ae_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *p_ra = &(rtlpriv->ra);
+ u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+ struct ieee80211_sta *sta = NULL;
+
+ if (is_hal_stop(rtlhal)) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ " driver is going to unload\n");
+ return;
+ }
+
+ if (!rtlpriv->dm.useramask) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ " driver does not control rate adaptive mask\n");
+ return;
+ }
+
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
+ switch (p_ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ high_rssithresh_for_ra = 55;
+ low_rssithresh_for_ra = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 25;
+ break;
+ default:
+ high_rssithresh_for_ra = 50;
+ low_rssithresh_for_ra = 20;
+ break;
+ }
+
+ if (rtlpriv->dm.undec_sm_pwdb > high_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_HIGH;
+ else if (rtlpriv->dm.undec_sm_pwdb > low_rssithresh_for_ra)
+ p_ra->ratr_state = DM_RATR_STA_MIDDLE;
+ else
+ p_ra->ratr_state = DM_RATR_STA_LOW;
+
+ if (p_ra->pre_ratr_state != p_ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI = %ld\n",
+ rtlpriv->dm.undec_sm_pwdb);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "RSSI_LEVEL = %d\n", p_ra->ratr_state);
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
+ "PreState = %d, CurState = %d\n",
+ p_ra->pre_ratr_state, p_ra->ratr_state);
+
+ rcu_read_lock();
+ sta = rtl_find_sta(hw, mac->bssid);
+ if (sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ p_ra->ratr_state);
+ rcu_read_unlock();
+
+ p_ra->pre_ratr_state = p_ra->ratr_state;
+ }
+ }
+}
+
static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -853,6 +924,9 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
(u8 *) (&fw_ps_awake));
+ if (ppsc->p2p_ps_info.p2p_ps_mode)
+ fw_ps_awake = false;
+
if ((ppsc->rfpwr_state == ERFON) &&
((!fw_current_inpsmode) && fw_ps_awake) &&
(!ppsc->rfchange_inprogress)) {
@@ -861,7 +935,7 @@ void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
rtl8723ae_dm_false_alarm_counter_statistics(hw);
rtl8723ae_dm_dynamic_bpowersaving(hw);
rtl8723ae_dm_dynamic_txpower(hw);
- /* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
+ rtl8723ae_dm_refresh_rate_adaptive_mask(hw);
rtl8723ae_dm_bt_coexist(hw);
rtl8723ae_dm_check_edca_turbo(hw);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
index 39d246196247..a372b0204456 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
@@ -55,7 +55,13 @@
#define DM_DIG_BACKOFF_MIN -4
#define DM_DIG_BACKOFF_DEFAULT 10
+#define RXPATHSELECTION_SS_TH_LOW 30
+#define RXPATHSELECTION_DIFF_TH 18
+
#define DM_RATR_STA_INIT 0
+#define DM_RATR_STA_HIGH 1
+#define DM_RATR_STA_MIDDLE 2
+#define DM_RATR_STA_LOW 3
#define TXHIGHPWRLEVEL_NORMAL 0
#define TXHIGHPWRLEVEL_LEVEL1 1
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
index 35cb8f83eed4..dedfa1ed3e02 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
@@ -494,7 +494,9 @@ void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+ SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode,
+ (rtlpriv->mac80211.p2p) ?
+ ppsc->smart_ps : 1);
SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
ppsc->reg_max_lps_awakeintvl);
@@ -741,3 +743,96 @@ void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
}
+
+static void rtl8723e_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw,
+ u8 ctwindow)
+{
+ u8 u1_ctwindow_period[1] = {ctwindow};
+
+ rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_CTW_CMD, 1, u1_ctwindow_period);
+}
+
+void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *rtlps = rtl_psc(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_p2p_ps_info *p2pinfo = &(rtlps->p2p_ps_info);
+ struct p2p_ps_offload_t *p2p_ps_offload = &rtlhal->p2p_ps_offload;
+ u8 i;
+ u16 ctwindow;
+ u32 start_time, tsf_low;
+
+ switch (p2p_ps_state) {
+ case P2P_PS_DISABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_DISABLE\n");
+ memset(p2p_ps_offload, 0, sizeof(struct p2p_ps_offload_t));
+ break;
+ case P2P_PS_ENABLE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_ENABLE\n");
+ /* update CTWindow value. */
+ if (p2pinfo->ctwindow > 0) {
+ p2p_ps_offload->ctwindow_en = 1;
+ ctwindow = p2pinfo->ctwindow;
+ rtl8723e_set_p2p_ctw_period_cmd(hw, ctwindow);
+ }
+
+ /* hw only support 2 set of NoA */
+ for (i = 0; i < p2pinfo->noa_num; i++) {
+ /* To control the register setting for which NOA*/
+ rtl_write_byte(rtlpriv, 0x5cf, (i << 4));
+ if (i == 0)
+ p2p_ps_offload->noa0_en = 1;
+ else
+ p2p_ps_offload->noa1_en = 1;
+
+ /* config P2P NoA Descriptor Register */
+ rtl_write_dword(rtlpriv, 0x5E0,
+ p2pinfo->noa_duration[i]);
+ rtl_write_dword(rtlpriv, 0x5E4,
+ p2pinfo->noa_interval[i]);
+
+ /*Get Current TSF value */
+ tsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+ start_time = p2pinfo->noa_start_time[i];
+ if (p2pinfo->noa_count_type[i] != 1) {
+ while (start_time <= (tsf_low+(50*1024))) {
+ start_time += p2pinfo->noa_interval[i];
+ if (p2pinfo->noa_count_type[i] != 255)
+ p2pinfo->noa_count_type[i]--;
+ }
+ }
+ rtl_write_dword(rtlpriv, 0x5E8, start_time);
+ rtl_write_dword(rtlpriv, 0x5EC,
+ p2pinfo->noa_count_type[i]);
+ }
+ if ((p2pinfo->opp_ps == 1) || (p2pinfo->noa_num > 0)) {
+ /* rst p2p circuit */
+ rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, BIT(4));
+
+ p2p_ps_offload->offload_en = 1;
+
+ if (P2P_ROLE_GO == rtlpriv->mac80211.p2p) {
+ p2p_ps_offload->role = 1;
+ p2p_ps_offload->allstasleep = 0;
+ } else {
+ p2p_ps_offload->role = 0;
+ }
+ p2p_ps_offload->discovery = 0;
+ }
+ break;
+ case P2P_PS_SCAN:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN\n");
+ p2p_ps_offload->discovery = 1;
+ break;
+ case P2P_PS_SCAN_DONE:
+ RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "P2P_PS_SCAN_DONE\n");
+ p2p_ps_offload->discovery = 0;
+ p2pinfo->p2p_ps_state = P2P_PS_ENABLE;
+ break;
+ default:
+ break;
+ }
+ rtl8723ae_fill_h2c_cmd(hw, H2C_P2P_PS_OFFLOAD, 1, (u8 *)p2p_ps_offload);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
index 89994e16dc83..ed3b795e6980 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
@@ -70,8 +70,10 @@ enum rtl8192c_h2c_cmd {
H2C_SETPWRMODE = 1,
H2C_JOINBSSRPT = 2,
H2C_RSVDPAGE = 3,
- H2C_RSSI_REPORT = 5,
- H2C_RA_MASK = 6,
+ H2C_RSSI_REPORT = 4,
+ H2C_P2P_PS_CTW_CMD = 5,
+ H2C_P2P_PS_OFFLOAD = 6,
+ H2C_RA_MASK = 7,
MAX_H2CCMD
};
@@ -97,5 +99,6 @@ void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+void rtl8723ae_set_p2p_ps_offload_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
index 9a0c71c2e15e..c333dfd116b8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
@@ -449,6 +449,9 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
break; }
+ case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+ rtl8723ae_set_p2p_ps_offload_cmd(hw, (*(u8 *)val));
+ break;
case HW_VAR_AID:{
u16 u2btmp;
u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
@@ -474,6 +477,39 @@ void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
if (btype_ibss == true)
_rtl8723ae_resume_tx_beacon(hw);
break; }
+ case HW_VAR_FW_LPS_ACTION: {
+ bool enter_fwlps = *((bool *)val);
+ u8 rpwm_val, fw_pwrmode;
+ bool fw_current_inps;
+
+ if (enter_fwlps) {
+ rpwm_val = 0x02; /* RF off */
+ fw_current_inps = true;
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&ppsc->fwctrl_psmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ } else {
+ rpwm_val = 0x0C; /* RF on */
+ fw_pwrmode = FW_PS_ACTIVE_MODE;
+ fw_current_inps = false;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SET_RPWM,
+ (u8 *)(&rpwm_val));
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_H2C_FW_PWRMODE,
+ (u8 *)(&fw_pwrmode));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_FW_PSMODE_STATUS,
+ (u8 *)(&fw_current_inps));
+ }
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case not processed\n");
@@ -1379,7 +1415,7 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
}
for (i = 0; i < 14; i++) {
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
"[0x%x / 0x%x / 0x%x]\n", rf_path, i,
rtlefuse->txpwrlevel_cck[rf_path][i],
@@ -1420,10 +1456,10 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
0xf0) >> 4);
}
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht20[%d] = 0x%x\n", rf_path, i,
rtlefuse->pwrgroup_ht20[rf_path][i]);
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-%d pwrgroup_ht40[%d] = 0x%x\n", rf_path, i,
rtlefuse->pwrgroup_ht40[rf_path][i]);
}
@@ -1463,19 +1499,19 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
for (i = 0; i < 14; i++)
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
@@ -1483,14 +1519,14 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
else
rtlefuse->eeprom_regulatory = 0;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
if (!autoload_fail)
rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
else
rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"TSSI_A = 0x%x, TSSI_B = 0x%x\n",
rtlefuse->eeprom_tssi[RF90_PATH_A],
rtlefuse->eeprom_tssi[RF90_PATH_B]);
@@ -1505,7 +1541,7 @@ static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
rtlefuse->apk_thermalmeterignore = true;
rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
- RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ RTPRINT(rtlpriv, FINIT, INIT_TXPOWER,
"thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
}
@@ -1713,19 +1749,7 @@ static void _rtl8723ae_hal_customized_behavior(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- switch (rtlhal->oem_id) {
- case RT_CID_819x_HP:
- pcipriv->ledctl.led_opendrain = true;
- break;
- case RT_CID_819x_Lenovo:
- case RT_CID_DEFAULT:
- case RT_CID_TOSHIBA:
- case RT_CID_CCX:
- case RT_CID_819x_Acer:
- case RT_CID_WHQL:
- default:
- break;
- }
+ pcipriv->ledctl.led_opendrain = true;
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"RT Customized ID: 0x%02X\n", rtlhal->oem_id);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
index 9c4e1d811187..061526fe6e2d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
@@ -54,8 +54,9 @@ void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
case LED_PIN_GPIO0:
break;
case LED_PIN_LED0:
+ ledcfg &= ~BIT(6);
rtl_write_byte(rtlpriv,
- REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6));
+ REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5));
break;
case LED_PIN_LED1:
rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5));
@@ -84,16 +85,21 @@ void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
break;
case LED_PIN_LED0:
ledcfg &= 0xf0;
- if (pcipriv->ledctl.led_opendrain)
+ if (pcipriv->ledctl.led_opendrain) {
+ ledcfg &= 0x90;
+ rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg|BIT(3)));
+ ledcfg = rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG);
+ ledcfg &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, ledcfg);
+ } else {
+ ledcfg &= ~BIT(6);
rtl_write_byte(rtlpriv, REG_LEDCFG2,
- (ledcfg | BIT(1) | BIT(5) | BIT(6)));
- else
- rtl_write_byte(rtlpriv, REG_LEDCFG2,
- (ledcfg | BIT(3) | BIT(5) | BIT(6)));
+ (ledcfg | BIT(3) | BIT(5)));
+ }
break;
case LED_PIN_LED1:
- ledcfg &= 0x0f;
- rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3)));
+ ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG1) & 0x10;
+ rtl_write_byte(rtlpriv, REG_LEDCFG1, (ledcfg | BIT(3)));
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
index bb7cc90bafb2..e4c4cdc3eb67 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
@@ -305,7 +305,7 @@ static struct rtl_hal_cfg rtl8723ae_hal_cfg = {
.maps[RTL_IMR_TXFOVW] = PHIMR_TXFOVW,
.maps[RTL_IMR_PSTIMEOUT] = PHIMR_PSTIMEOUT,
- .maps[RTL_IMR_BcnInt] = PHIMR_BCNDMAINT0,
+ .maps[RTL_IMR_BCNINT] = PHIMR_BCNDMAINT0,
.maps[RTL_IMR_RXFOVW] = PHIMR_RXFOVW,
.maps[RTL_IMR_RDU] = PHIMR_RDU,
.maps[RTL_IMR_ATIMEND] = PHIMR_ATIMEND_E,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index ac081297db50..c72758d8f4ed 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -304,11 +304,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->band = hw->conf.channel->band;
-
- hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size
- + status->rx_bufshift);
+ rx_status->freq = hw->conf.chandef.chan->center_freq;
+ rx_status->band = hw->conf.chandef.chan->band;
if (status->crc)
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
@@ -330,6 +327,13 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
* to decrypt it
*/
if (status->decrypted) {
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ status->rx_drvinfo_size + status->rx_bufshift);
+
+ if (!hdr) {
+ /* during testing, hdr could be NULL here */
+ return false;
+ }
if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
(ieee80211_has_protected(hdr->frame_control)))
rx_status->flag &= ~RX_FLAG_DECRYPTED;
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 5847d6d0881e..76732b0cd221 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -224,10 +224,9 @@ static void _usb_writeN_sync(struct rtl_priv *rtlpriv, u32 addr, void *data,
u8 *buffer;
wvalue = (u16)(addr & 0x0000ffff);
- buffer = kmalloc(len, GFP_ATOMIC);
+ buffer = kmemdup(data, len, GFP_ATOMIC);
if (!buffer)
return;
- memcpy(buffer, data, len);
usb_control_msg(udev, pipe, request, reqtype, wvalue,
index, buffer, len, 50);
@@ -309,6 +308,8 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw)
return 0;
}
+static void _rtl_rx_work(unsigned long param);
+
static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -325,6 +326,12 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n",
rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep);
init_usb_anchor(&rtlusb->rx_submitted);
+ init_usb_anchor(&rtlusb->rx_cleanup_urbs);
+
+ skb_queue_head_init(&rtlusb->rx_queue);
+ rtlusb->rx_work_tasklet.func = _rtl_rx_work;
+ rtlusb->rx_work_tasklet.data = (unsigned long)rtlusb;
+
return 0;
}
@@ -406,40 +413,30 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
rtlusb->disableHWSM = true;
}
-#define __RADIO_TAP_SIZE_RSV 32
-
static void _rtl_rx_completed(struct urb *urb);
-static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw,
- struct rtl_usb *rtlusb,
- struct urb *urb,
- gfp_t gfp_mask)
+static int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb,
+ struct urb *urb, gfp_t gfp_mask)
{
- struct sk_buff *skb;
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ void *buf;
- skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV),
- gfp_mask);
- if (!skb) {
+ buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask,
+ &urb->transfer_dma);
+ if (!buf) {
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
- "Failed to __dev_alloc_skb!!\n");
- return ERR_PTR(-ENOMEM);
+ "Failed to usb_alloc_coherent!!\n");
+ return -ENOMEM;
}
- /* reserve some space for mac80211's radiotap */
- skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
usb_fill_bulk_urb(urb, rtlusb->udev,
usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep),
- skb->data, min(skb_tailroom(skb),
- (int)rtlusb->rx_max_size),
- _rtl_rx_completed, skb);
+ buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
- return skb;
+ return 0;
}
-#undef __RADIO_TAP_SIZE_RSV
-
static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
@@ -523,22 +520,14 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
if (unicast)
rtlpriv->link_info.num_rx_inperiod++;
}
- if (likely(rtl_action_proc(hw, skb, false))) {
- struct sk_buff *uskb = NULL;
- u8 *pdata;
-
- uskb = dev_alloc_skb(skb->len + 128);
- if (uskb) { /* drop packet on allocation failure */
- memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
- sizeof(rx_status));
- pdata = (u8 *)skb_put(uskb, skb->len);
- memcpy(pdata, skb->data, skb->len);
- ieee80211_rx_irqsafe(hw, uskb);
- }
- dev_kfree_skb_any(skb);
- } else {
+
+ /* static bcn for roaming */
+ rtl_beacon_statistic(hw, skb);
+
+ if (likely(rtl_action_proc(hw, skb, false)))
+ ieee80211_rx(hw, skb);
+ else
dev_kfree_skb_any(skb);
- }
}
}
@@ -555,15 +544,70 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
while (!skb_queue_empty(&rx_queue)) {
_skb = skb_dequeue(&rx_queue);
_rtl_usb_rx_process_agg(hw, _skb);
- ieee80211_rx_irqsafe(hw, _skb);
+ ieee80211_rx(hw, _skb);
+ }
+}
+
+#define __RX_SKB_MAX_QUEUED 32
+
+static void _rtl_rx_work(unsigned long param)
+{
+ struct rtl_usb *rtlusb = (struct rtl_usb *)param;
+ struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&rtlusb->rx_queue))) {
+ if (unlikely(IS_USB_STOP(rtlusb))) {
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (likely(!rtlusb->usb_rx_segregate_hdl)) {
+ _rtl_usb_rx_process_noagg(hw, skb);
+ } else {
+ /* TO DO */
+ _rtl_rx_pre_process(hw, skb);
+ pr_err("rx agg not supported\n");
+ }
+ }
+}
+
+static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
+ unsigned int len)
+{
+ unsigned int padding = 0;
+
+ /* make function no-op when possible */
+ if (NET_IP_ALIGN == 0 || len < sizeof(*hdr))
+ return 0;
+
+ /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */
+ /* TODO: deduplicate common code, define helper function instead? */
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+ padding ^= NET_IP_ALIGN;
+
+ /* Input might be invalid, avoid accessing memory outside
+ * the buffer.
+ */
+ if ((unsigned long)qc - (unsigned long)hdr < len &&
+ *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
+ padding ^= NET_IP_ALIGN;
}
+
+ if (ieee80211_has_a4(hdr->frame_control))
+ padding ^= NET_IP_ALIGN;
+
+ return padding;
}
+#define __RADIO_TAP_SIZE_RSV 32
+
static void _rtl_rx_completed(struct urb *_urb)
{
- struct sk_buff *skb = (struct sk_buff *)_urb->context;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0];
+ struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context;
struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
struct rtl_priv *rtlpriv = rtl_priv(hw);
int err = 0;
@@ -572,28 +616,50 @@ static void _rtl_rx_completed(struct urb *_urb)
goto free;
if (likely(0 == _urb->status)) {
- /* If this code were moved to work queue, would CPU
- * utilization be improved? NOTE: We shall allocate another skb
- * and reuse the original one.
- */
- skb_put(skb, _urb->actual_length);
+ unsigned int padding;
+ struct sk_buff *skb;
+ unsigned int qlen;
+ unsigned int size = _urb->actual_length;
+ struct ieee80211_hdr *hdr;
- if (likely(!rtlusb->usb_rx_segregate_hdl)) {
- struct sk_buff *_skb;
- _rtl_usb_rx_process_noagg(hw, skb);
- _skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC);
- if (IS_ERR(_skb)) {
- err = PTR_ERR(_skb);
- RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
- "Can't allocate skb for bulk IN!\n");
- return;
- }
- skb = _skb;
- } else{
- /* TO DO */
- _rtl_rx_pre_process(hw, skb);
- pr_err("rx agg not supported\n");
+ if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Too short packet from bulk IN! (len: %d)\n",
+ size);
+ goto resubmit;
+ }
+
+ qlen = skb_queue_len(&rtlusb->rx_queue);
+ if (qlen >= __RX_SKB_MAX_QUEUED) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Pending RX skbuff queue full! (qlen: %d)\n",
+ qlen);
+ goto resubmit;
}
+
+ hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE);
+ padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE);
+
+ skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding);
+ if (!skb) {
+ RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
+ "Can't allocate skb for bulk IN!\n");
+ goto resubmit;
+ }
+
+ _rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
+
+ /* Make sure the payload data is 4 byte aligned. */
+ skb_reserve(skb, padding);
+
+ /* reserve some space for mac80211's radiotap */
+ skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
+
+ memcpy(skb_put(skb, size), _urb->transfer_buffer, size);
+
+ skb_queue_tail(&rtlusb->rx_queue, skb);
+ tasklet_schedule(&rtlusb->rx_work_tasklet);
+
goto resubmit;
}
@@ -609,9 +675,6 @@ static void _rtl_rx_completed(struct urb *_urb)
}
resubmit:
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
-
usb_anchor_urb(_urb, &rtlusb->rx_submitted);
err = usb_submit_urb(_urb, GFP_ATOMIC);
if (unlikely(err)) {
@@ -621,13 +684,34 @@ resubmit:
return;
free:
- dev_kfree_skb_irq(skb);
+ /* On some architectures, usb_free_coherent must not be called from
+ * hardirq context. Queue urb to cleanup list.
+ */
+ usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs);
+}
+
+#undef __RADIO_TAP_SIZE_RSV
+
+static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw)
+{
+ struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
+ struct urb *urb;
+
+ usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+
+ tasklet_kill(&rtlusb->rx_work_tasklet);
+ skb_queue_purge(&rtlusb->rx_queue);
+
+ while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ }
}
static int _rtl_usb_receive(struct ieee80211_hw *hw)
{
struct urb *urb;
- struct sk_buff *skb;
int err;
int i;
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -646,11 +730,10 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
goto err_out;
}
- skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
- if (IS_ERR(skb)) {
+ err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
+ if (err < 0) {
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
"Failed to prep_rx_urb!!\n");
- err = PTR_ERR(skb);
usb_free_urb(urb);
goto err_out;
}
@@ -665,6 +748,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
err_out:
usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+ _rtl_usb_cleanup_rx(hw);
return err;
}
@@ -706,7 +790,7 @@ static void rtl_usb_cleanup(struct ieee80211_hw *hw)
SET_USB_STOP(rtlusb);
/* clean up rx stuff. */
- usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+ _rtl_usb_cleanup_rx(hw);
/* clean up tx stuff */
for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) {
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index fb986f98d1df..685273ca9561 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -136,11 +136,14 @@ struct rtl_usb {
void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *);
/* Rx */
- u8 in_ep_nums ;
+ u8 in_ep_nums;
u32 in_ep; /* Bulk IN endpoint number */
u32 rx_max_size; /* Bulk IN max buffer size */
u32 rx_urb_num; /* How many Bulk INs are submitted to host. */
struct usb_anchor rx_submitted;
+ struct usb_anchor rx_cleanup_urbs;
+ struct tasklet_struct rx_work_tasklet;
+ struct sk_buff_head rx_queue;
void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *,
struct sk_buff_head *);
void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *);
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index f13258a8d995..44328baa6389 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -99,11 +99,36 @@
#define CHANNEL_GROUP_MAX_5G 9
#define CHANNEL_MAX_NUMBER_2G 14
#define AVG_THERMAL_NUM 8
+#define AVG_THERMAL_NUM_88E 4
#define MAX_TID_COUNT 9
/* for early mode */
#define FCS_LEN 4
#define EM_HDR_LEN 8
+
+#define MAX_TX_COUNT 4
+#define MAX_RF_PATH 4
+#define MAX_CHNL_GROUP_24G 6
+#define MAX_CHNL_GROUP_5G 14
+
+struct txpower_info_2g {
+ u8 index_cck_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+ u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
+ /*If only one tx, only BW20 and OFDM are used.*/
+ u8 cck_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
+struct txpower_info_5g {
+ u8 index_bw40_base[MAX_RF_PATH][MAX_CHNL_GROUP_5G];
+ /*If only one tx, only BW20, OFDM, BW80 and BW160 are used.*/
+ u8 ofdm_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw20_diff[MAX_RF_PATH][MAX_TX_COUNT];
+ u8 bw40_diff[MAX_RF_PATH][MAX_TX_COUNT];
+};
+
enum intf_type {
INTF_PCI = 0,
INTF_USB = 1,
@@ -137,6 +162,7 @@ enum hardware_type {
HARDWARE_TYPE_RTL8192DU,
HARDWARE_TYPE_RTL8723AE,
HARDWARE_TYPE_RTL8723U,
+ HARDWARE_TYPE_RTL8188EE,
/* keep it last */
HARDWARE_TYPE_NUM
@@ -263,7 +289,7 @@ enum hw_variables {
HW_VAR_RATR_0,
HW_VAR_RRSR,
HW_VAR_CPU_RST,
- HW_VAR_CECHK_BSSID,
+ HW_VAR_CHECK_BSSID,
HW_VAR_LBK_MODE,
HW_VAR_AES_11N_FIX,
HW_VAR_USB_RX_AGGR,
@@ -278,7 +304,10 @@ enum hw_variables {
HW_VAR_SET_RPWM,
HW_VAR_H2C_FW_PWRMODE,
HW_VAR_H2C_FW_JOINBSSRPT,
+ HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
HW_VAR_FW_PSMODE_STATUS,
+ HW_VAR_RESUME_CLK_ON,
+ HW_VAR_FW_LPS_ACTION,
HW_VAR_1X1_RECV_COMBINE,
HW_VAR_STOP_SEND_BEACON,
HW_VAR_TSF_TIMER,
@@ -305,6 +334,7 @@ enum hw_variables {
HW_VAR_INT_AC,
HW_VAR_RF_TIMING,
+ HAL_DEF_WOWLAN,
HW_VAR_MRC,
HW_VAR_MGT_FILTER,
@@ -461,6 +491,7 @@ enum rtl_var_map {
EFUSE_MAX_SECTION_MAP,
EFUSE_REAL_CONTENT_SIZE,
EFUSE_OOB_PROTECT_BYTES_LEN,
+ EFUSE_ACCESS,
/*CAM map */
RWCAM,
@@ -493,7 +524,7 @@ enum rtl_var_map {
RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */
RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */
RTL_IMR_PSTIMEOUT, /*Power save time out interrupt */
- RTL_IMR_BcnInt, /*Beacon DMA Interrupt 0 */
+ RTL_IMR_BCNINT, /*Beacon DMA Interrupt 0 */
RTL_IMR_RXFOVW, /*Receive FIFO Overflow */
RTL_IMR_RDU, /*Receive Descriptor Unavailable */
RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */
@@ -508,7 +539,7 @@ enum rtl_var_map {
RTL_IMR_VIDOK, /*AC_VI DMA OK Interrupt */
RTL_IMR_VODOK, /*AC_VO DMA Interrupt */
RTL_IMR_ROK, /*Receive DMA OK Interrupt */
- RTL_IBSS_INT_MASKS, /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK |
+ RTL_IBSS_INT_MASKS, /*(RTL_IMR_BCNINT | RTL_IMR_TBDOK |
* RTL_IMR_TBDER) */
RTL_IMR_C2HCMD, /*fw interrupt*/
@@ -742,6 +773,11 @@ struct false_alarm_statistics {
u32 cnt_ofdm_fail;
u32 cnt_cck_fail;
u32 cnt_all;
+ u32 cnt_ofdm_cca;
+ u32 cnt_cck_cca;
+ u32 cnt_cca_all;
+ u32 cnt_bw_usc;
+ u32 cnt_bw_lsc;
};
struct init_gain {
@@ -826,8 +862,67 @@ struct rtl_rfkill {
bool rfkill_state; /*0 is off, 1 is on */
};
+/*for P2P PS**/
+#define P2P_MAX_NOA_NUM 2
+
+enum p2p_role {
+ P2P_ROLE_DISABLE = 0,
+ P2P_ROLE_DEVICE = 1,
+ P2P_ROLE_CLIENT = 2,
+ P2P_ROLE_GO = 3
+};
+
+enum p2p_ps_state {
+ P2P_PS_DISABLE = 0,
+ P2P_PS_ENABLE = 1,
+ P2P_PS_SCAN = 2,
+ P2P_PS_SCAN_DONE = 3,
+ P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
+};
+
+enum p2p_ps_mode {
+ P2P_PS_NONE = 0,
+ P2P_PS_CTWINDOW = 1,
+ P2P_PS_NOA = 2,
+ P2P_PS_MIX = 3, /* CTWindow and NoA */
+};
+
+struct rtl_p2p_ps_info {
+ enum p2p_ps_mode p2p_ps_mode; /* indicate p2p ps mode */
+ enum p2p_ps_state p2p_ps_state; /* indicate p2p ps state */
+ u8 noa_index; /* Identifies instance of Notice of Absence timing. */
+ /* Client traffic window. A period of time in TU after TBTT. */
+ u8 ctwindow;
+ u8 opp_ps; /* opportunistic power save. */
+ u8 noa_num; /* number of NoA descriptor in P2P IE. */
+ /* Count for owner, Type of client. */
+ u8 noa_count_type[P2P_MAX_NOA_NUM];
+ /* Max duration for owner, preferred or min acceptable duration
+ * for client.
+ */
+ u32 noa_duration[P2P_MAX_NOA_NUM];
+ /* Length of interval for owner, preferred or max acceptable intervali
+ * of client.
+ */
+ u32 noa_interval[P2P_MAX_NOA_NUM];
+ /* schedule in terms of the lower 4 bytes of the TSF timer. */
+ u32 noa_start_time[P2P_MAX_NOA_NUM];
+};
+
+struct p2p_ps_offload_t {
+ u8 offload_en:1;
+ u8 role:1; /* 1: Owner, 0: Client */
+ u8 ctwindow_en:1;
+ u8 noa0_en:1;
+ u8 noa1_en:1;
+ u8 allstasleep:1;
+ u8 discovery:1;
+ u8 reserved:1;
+};
+
#define IQK_MATRIX_REG_NUM 8
#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21)
+
struct iqk_matrix_regs {
bool iqk_done;
long value[1][IQK_MATRIX_REG_NUM];
@@ -889,7 +984,7 @@ struct rtl_phy {
/* Dual mac */
bool need_iqk;
- struct iqk_matrix_regs iqk_matrix_regsetting[IQK_MATRIX_SETTINGS_NUM];
+ struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM];
bool rfpi_enable;
@@ -902,6 +997,8 @@ struct rtl_phy {
/* the current Tx power level */
u8 cur_cck_txpwridx;
u8 cur_ofdm24g_txpwridx;
+ u8 cur_bw20_txpwridx;
+ u8 cur_bw40_txpwridx;
u32 rfreg_chnlval[2];
bool apk_done;
@@ -940,20 +1037,21 @@ struct rtl_ht_agg {
u8 rx_agg_state;
};
+struct rssi_sta {
+ long undec_sm_pwdb;
+};
+
struct rtl_tid_data {
u16 seq_number;
struct rtl_ht_agg agg;
};
-struct rssi_sta {
- long undec_sm_pwdb;
-};
-
struct rtl_sta_info {
struct list_head list;
u8 ratr_index;
u8 wireless_mode;
u8 mimo_ps;
+ u8 mac_addr[ETH_ALEN];
struct rtl_tid_data tids[MAX_TID_COUNT];
/* just used for ap adhoc or mesh*/
@@ -1005,6 +1103,8 @@ struct rtl_mac {
int n_bitrates;
bool offchan_delay;
+ u8 p2p; /*using p2p role*/
+ bool p2p_in_use;
/*filters */
u32 rx_conf;
@@ -1014,11 +1114,11 @@ struct rtl_mac {
bool act_scanning;
u8 cnt_after_linked;
+ bool skip_scan;
/* early mode */
/* skb wait queue */
struct sk_buff_head skb_waitq[MAX_TID_COUNT];
- u8 earlymode_threshold;
/*RDG*/
bool rdg_en;
@@ -1042,6 +1142,7 @@ struct rtl_mac {
u8 retry_short;
u8 retry_long;
u16 assoc_id;
+ bool hiddenssid;
/*IBSS*/
int beacon_interval;
@@ -1111,10 +1212,13 @@ struct bt_coexist_8723 {
struct rtl_hal {
struct ieee80211_hw *hw;
- struct bt_coexist_8723 hal_coex_8723;
+ bool driver_is_goingto_unload;
bool up_first_time;
+ bool first_init;
bool being_init_adapter;
bool bbrf_ready;
+ bool mac_func_enable;
+ struct bt_coexist_8723 hal_coex_8723;
enum intf_type interface;
u16 hw_type; /*92c or 92d or 92s and so on */
@@ -1122,6 +1226,7 @@ struct rtl_hal {
u8 oem_id;
u32 version; /*version of chip */
u8 state; /*stop 0, start 1 */
+ u8 board_type;
/*firmware */
u32 fwsize;
@@ -1141,6 +1246,10 @@ struct rtl_hal {
bool set_fwcmd_inprogress;
u8 current_fwcmd_io;
+ struct p2p_ps_offload_t p2p_ps_offload;
+ bool fw_clk_change_in_progress;
+ bool allow_sw_to_change_hwclc;
+ u8 fw_ps_state;
/**/
bool driver_going2unload;
@@ -1157,6 +1266,7 @@ struct rtl_hal {
/* just for DualMac S3S4 */
u8 macphyctl_reg;
bool earlymode_enable;
+ u8 max_earlymode_num;
/* Dual mac*/
bool during_mac0init_radiob;
bool during_mac1init_radioa;
@@ -1193,6 +1303,29 @@ struct rtl_security {
u8 *pairwise_key;
};
+#define ASSOCIATE_ENTRY_NUM 33
+
+struct fast_ant_training {
+ u8 bssid[6];
+ u8 antsel_rx_keep_0;
+ u8 antsel_rx_keep_1;
+ u8 antsel_rx_keep_2;
+ u32 ant_sum[7];
+ u32 ant_cnt[7];
+ u32 ant_ave[7];
+ u8 fat_state;
+ u32 train_idx;
+ u8 antsel_a[ASSOCIATE_ENTRY_NUM];
+ u8 antsel_b[ASSOCIATE_ENTRY_NUM];
+ u8 antsel_c[ASSOCIATE_ENTRY_NUM];
+ u32 main_ant_sum[ASSOCIATE_ENTRY_NUM];
+ u32 aux_ant_sum[ASSOCIATE_ENTRY_NUM];
+ u32 main_ant_cnt[ASSOCIATE_ENTRY_NUM];
+ u32 aux_ant_cnt[ASSOCIATE_ENTRY_NUM];
+ u8 rx_idle_ant;
+ bool becomelinked;
+};
+
struct rtl_dm {
/*PHY status for Dynamic Management */
long entry_min_undec_sm_pwdb;
@@ -1229,9 +1362,24 @@ struct rtl_dm {
bool disable_tx_int;
char ofdm_index[2];
char cck_index;
+ char delta_power_index;
+ char delta_power_index_last;
+ char power_index_offset;
+
+ /*88e tx power tracking*/
+ u8 swing_idx_ofdm[2];
+ u8 swing_idx_ofdm_cur;
+ u8 swing_idx_ofdm_base;
+ bool swing_flag_ofdm;
+ u8 swing_idx_cck;
+ u8 swing_idx_cck_cur;
+ u8 swing_idx_cck_base;
+ bool swing_flag_cck;
/* DMSP */
bool supp_phymode_switch;
+
+ struct fast_ant_training fat_table;
};
#define EFUSE_MAX_LOGICAL_SIZE 256
@@ -1264,6 +1412,9 @@ struct rtl_efuse {
u8 external_pa;
u8 dev_addr[6];
+ u8 wowlan_enable;
+ u8 antenna_div_cfg;
+ u8 antenna_div_type;
bool txpwr_fromeprom;
u8 eeprom_crystalcap;
@@ -1319,14 +1470,12 @@ struct rtl_ps_ctl {
bool rfchange_inprogress;
bool swrf_processing;
bool hwradiooff;
-
/*
* just for PCIE ASPM
* If it supports ASPM, Offset[560h] = 0x40,
* otherwise Offset[560h] = 0x00.
* */
bool support_aspm;
-
bool support_backdoor;
/*for LPS */
@@ -1341,6 +1490,7 @@ struct rtl_ps_ctl {
bool fw_current_inpsmode;
u8 reg_max_lps_awakeintvl;
bool report_linked;
+ bool low_power_enable;/*for 32k*/
/*for IPS */
bool inactiveps;
@@ -1373,6 +1523,11 @@ struct rtl_ps_ctl {
unsigned long last_beacon;
unsigned long last_action;
unsigned long last_slept;
+
+ /*For P2P PS */
+ struct rtl_p2p_ps_info p2p_ps_info;
+ u8 pwr_mode;
+ u8 smart_ps;
};
struct rtl_stats {
@@ -1381,7 +1536,7 @@ struct rtl_stats {
s8 rssi;
u8 signal;
u8 noise;
- u16 rate; /*in 100 kbps */
+ u8 rate; /* hw desc rate */
u8 received_channel;
u8 control;
u8 mask;
@@ -1423,8 +1578,16 @@ struct rtl_stats {
bool packet_toself;
bool packet_beacon; /*for rssi */
char cck_adc_pwdb[4]; /*for rx path selection */
+
+ u8 packet_report_type;
+
+ u32 macid;
+ u8 wake_match;
+ u32 bt_rx_rssi_percentage;
+ u32 macid_valid_entry[2];
};
+
struct rt_link_detect {
/* count for roaming */
u32 bcn_rx_inperiod;
@@ -1477,7 +1640,8 @@ struct rtl_tcb_desc {
/* early mode */
u8 empkt_num;
/* The max value by HW */
- u32 empkt_len[5];
+ u32 empkt_len[10];
+ bool btx_enable_sw_calc_duration;
};
struct rtl_hal_ops {
@@ -1553,7 +1717,7 @@ struct rtl_hal_ops {
void (*allow_all_destaddr)(struct ieee80211_hw *hw,
bool allow_all_da, bool write_into_reg);
void (*linked_set_reg) (struct ieee80211_hw *hw);
- void (*check_switch_to_dmdp) (struct ieee80211_hw *hw);
+ void (*chk_switch_dmdp) (struct ieee80211_hw *hw);
void (*dualmac_easy_concurrent) (struct ieee80211_hw *hw);
void (*dualmac_switch_to_dmdp) (struct ieee80211_hw *hw);
bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
@@ -1662,6 +1826,8 @@ struct rtl_locks {
/*spin lock */
spinlock_t ips_lock;
spinlock_t irq_th_lock;
+ spinlock_t irq_pci_lock;
+ spinlock_t tx_lock;
spinlock_t h2c_lock;
spinlock_t rf_ps_lock;
spinlock_t rf_lock;
@@ -1670,6 +1836,9 @@ struct rtl_locks {
spinlock_t entry_list_lock;
spinlock_t usb_lock;
+ /*FW clock change */
+ spinlock_t fw_ps_lock;
+
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;
@@ -1683,7 +1852,8 @@ struct rtl_works {
/*timer */
struct timer_list watchdog_timer;
struct timer_list dualmac_easyconcurrent_retrytimer;
-
+ struct timer_list fw_clockoff_timer;
+ struct timer_list fast_antenna_training_timer;
/*task */
struct tasklet_struct irq_tasklet;
struct tasklet_struct irq_prepare_bcn_tasklet;
@@ -1696,8 +1866,9 @@ struct rtl_works {
/* For SW LPS */
struct delayed_work ps_work;
struct delayed_work ps_rfon_wq;
+ struct delayed_work fwevt_wq;
- struct work_struct lps_leave_work;
+ struct work_struct lps_change_work;
};
struct rtl_debug {
@@ -1767,10 +1938,12 @@ struct dig_t {
char back_val;
char back_range_max;
char back_range_min;
- u8 rx_gain_range_max;
- u8 rx_gain_range_min;
+ u8 rx_gain_max;
+ u8 rx_gain_min;
u8 min_undec_pwdb_for_dm;
u8 rssi_val_min;
+ u8 pre_cck_cca_thres;
+ u8 cur_cck_cca_thres;
u8 pre_cck_pd_state;
u8 cur_cck_pd_state;
u8 pre_cck_fa_state;
@@ -1792,6 +1965,13 @@ struct dig_t {
u8 backoff_enable_flag;
char backoffval_range_max;
char backoffval_range_min;
+ u8 dig_min_0;
+ u8 dig_min_1;
+ bool media_connect_0;
+ bool media_connect_1;
+
+ u32 antdiv_rssi_max;
+ u32 rssi_max;
};
struct rtl_global_var {
@@ -1802,6 +1982,7 @@ struct rtl_global_var {
};
struct rtl_priv {
+ struct ieee80211_hw *hw;
struct completion firmware_loading_complete;
struct list_head list;
struct rtl_priv *buddy_priv;
@@ -1866,6 +2047,7 @@ struct rtl_priv {
bool bt_operation_on;
};
};
+ bool enter_ps; /* true when entering PS */
/*This must be the last item so
that it points to the data allocated
@@ -2127,9 +2309,7 @@ value to host byte ordering.*/
#define WLAN_FC_GET_TYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE)
#define WLAN_FC_GET_STYPE(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE)
#define WLAN_FC_MORE_DATA(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_MOREDATA)
-#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
-#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+#define rtl_dm(rtlpriv) (&((rtlpriv)->dm))
#define RT_RF_OFF_LEVL_ASPM BIT(0) /*PCI ASPM */
#define RT_RF_OFF_LEVL_CLK_REQ BIT(1) /*PCI clock request */
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index bbbf68cf50a7..3291ffa95273 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -572,7 +572,8 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_conf *conf = &hw->conf;
int channel, ret = 0;
- channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
+ channel = ieee80211_frequency_to_channel(
+ conf->chandef.chan->center_freq);
wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
channel,
@@ -1223,7 +1224,7 @@ static int wl1251_op_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = SURVEY_INFO_NOISE_DBM;
survey->noise = wl->noise;
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index e57ee48edff6..e2b3d9c541e8 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
wl->set_power(true);
ret = pm_runtime_get_sync(&func->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_sync(&func->dev);
goto out;
+ }
sdio_claim_host(func);
sdio_enable_func(func);
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 3b266d3231a3..4c67c2f9ea71 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -257,7 +257,7 @@ static int wl1251_spi_probe(struct spi_device *spi)
wl = hw->priv;
SET_IEEE80211_DEV(hw, &spi->dev);
- dev_set_drvdata(&spi->dev, wl);
+ spi_set_drvdata(spi, wl);
wl->if_priv = spi;
wl->if_ops = &wl1251_spi_ops;
@@ -311,7 +311,7 @@ static int wl1251_spi_probe(struct spi_device *spi)
static int wl1251_spi_remove(struct spi_device *spi)
{
- struct wl1251 *wl = dev_get_drvdata(&spi->dev);
+ struct wl1251 *wl = spi_get_drvdata(spi);
free_irq(wl->irq, wl);
wl1251_free_hw(wl);
diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c
index 7dc9f965037d..7485dbae8c4b 100644
--- a/drivers/net/wireless/ti/wl12xx/cmd.c
+++ b/drivers/net/wireless/ti/wl12xx/cmd.c
@@ -301,7 +301,7 @@ int wl12xx_cmd_channel_switch(struct wl1271 *wl,
}
cmd->role_id = wlvif->role_id;
- cmd->channel = ch_switch->channel->hw_value;
+ cmd->channel = ch_switch->chandef.chan->hw_value;
cmd->switch_time = ch_switch->count;
cmd->stop_tx = ch_switch->block_tx;
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index 09694e39bb14..1c627da85083 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
+ wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS;
out:
return ret;
}
diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h
index d4552857480c..222d03540200 100644
--- a/drivers/net/wireless/ti/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h
@@ -63,6 +63,8 @@
#define WL12XX_NUM_MAC_ADDRESSES 2
+#define WL12XX_RX_BA_MAX_SESSIONS 3
+
struct wl127x_rx_mem_pool_addr {
u32 addr;
u32 addr_extra;
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 1d1f6cc7a50a..7649c75cd68d 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -42,11 +42,11 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
}
cmd->role_id = wlvif->role_id;
- cmd->channel = ch_switch->channel->hw_value;
+ cmd->channel = ch_switch->chandef.chan->hw_value;
cmd->switch_time = ch_switch->count;
cmd->stop_tx = ch_switch->block_tx;
- switch (ch_switch->channel->band) {
+ switch (ch_switch->chandef.chan->band) {
case IEEE80211_BAND_2GHZ:
cmd->band = WLCORE_BAND_2_4GHZ;
break;
@@ -55,7 +55,7 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
break;
default:
wl1271_error("invalid channel switch band: %d",
- ch_switch->channel->band);
+ ch_switch->chandef.chan->band);
ret = -EINVAL;
goto out_free;
}
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index da3ef1b10a9c..9fa692d11025 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
+ wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
out:
return ret;
}
@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
{
u32 fuse;
+ s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
int ret;
ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
if (ret < 0)
goto out;
+ pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+ rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
+
+ if (rom <= 0xE)
+ metal = (fuse & WL18XX_METAL_VER_MASK) >>
+ WL18XX_METAL_VER_OFFSET;
+ else
+ metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
+ WL18XX_NEW_METAL_VER_OFFSET;
+
+ ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
+ if (ret < 0)
+ goto out;
+
+ rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
+ if (rdl_ver > RDL_MAX)
+ rdl_ver = RDL_NONE;
+
+ wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)",
+ rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom);
+
if (ver)
- *ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
+ *ver = pg_ver;
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
diff --git a/drivers/net/wireless/ti/wl18xx/reg.h b/drivers/net/wireless/ti/wl18xx/reg.h
index 937b71d8783f..6306e04cd258 100644
--- a/drivers/net/wireless/ti/wl18xx/reg.h
+++ b/drivers/net/wireless/ti/wl18xx/reg.h
@@ -131,6 +131,16 @@
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
#define WL18XX_PG_VER_MASK 0x70
#define WL18XX_PG_VER_OFFSET 4
+#define WL18XX_ROM_VER_MASK 0x3
+#define WL18XX_ROM_VER_OFFSET 0
+#define WL18XX_METAL_VER_MASK 0xC
+#define WL18XX_METAL_VER_OFFSET 2
+#define WL18XX_NEW_METAL_VER_MASK 0x180
+#define WL18XX_NEW_METAL_VER_OFFSET 7
+
+#define WL18XX_REG_FUSE_DATA_2_3 0xA02614
+#define WL18XX_RDL_VER_MASK 0x1f00
+#define WL18XX_RDL_VER_OFFSET 8
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
@@ -188,4 +198,23 @@ enum {
NUM_BOARD_TYPES,
};
+enum {
+ RDL_NONE = 0,
+ RDL_1_HP = 1,
+ RDL_2_SP = 2,
+ RDL_3_HP = 3,
+ RDL_4_SP = 4,
+
+ _RDL_LAST,
+ RDL_MAX = _RDL_LAST - 1,
+};
+
+static const char * const rdl_names[] = {
+ [RDL_NONE] = "",
+ [RDL_1_HP] = "1853 SISO",
+ [RDL_2_SP] = "1857 MIMO",
+ [RDL_3_HP] = "1893 SISO",
+ [RDL_4_SP] = "1897 MIMO",
+};
+
#endif /* __REG_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index b6739e79efcf..9204e07ee432 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -29,7 +29,7 @@
#define WL18XX_IFTYPE_VER 5
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
-#define WL18XX_MINOR_VER 28
+#define WL18XX_MINOR_VER 39
#define WL18XX_CMD_MAX_SIZE 740
@@ -40,6 +40,8 @@
#define WL18XX_NUM_MAC_ADDRESSES 3
+#define WL18XX_RX_BA_MAX_SESSIONS 5
+
struct wl18xx_priv {
/* buffer for sending commands to FW */
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index c79654323396..7a970cd9c555 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1736,6 +1736,35 @@ out:
}
+int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ s8 *avg_rssi)
+{
+ struct acx_roaming_stats *acx;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_ACX, "acx roaming statistics");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->role_id = wlvif->role_id;
+ ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx roaming statistics failed: %d", ret);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ *avg_rssi = acx->rssi_beacon;
+out:
+ kfree(acx);
+ return ret;
+}
+
#ifdef CONFIG_PM
/* Set the global behaviour of RX filters - On/Off + default action */
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index 126536c6a393..6dcfad9b0472 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information {
u8 padding[2];
} __packed;
-#define RX_BA_MAX_SESSIONS 3
-
struct wl1271_acx_ba_initiator_policy {
struct acx_header header;
@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg {
u8 fields[0];
} __packed;
+struct acx_roaming_stats {
+ struct acx_header header;
+
+ u8 role_id;
+ u8 pad[3];
+ u32 missed_beacons;
+ u8 snr_data;
+ u8 snr_bacon;
+ s8 rssi_data;
+ s8 rssi_beacon;
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001,
@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
+int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ s8 *avg_rssi);
#ifdef CONFIG_PM
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 6331f9e1cb39..c9e060795d13 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl->links[link].prev_freed_pkts =
wl->fw_status_2->counters.tx_lnk_free_pkts[link];
wl->links[link].wlvif = wlvif;
+
+ /*
+ * Take saved value for total freed packets from wlvif, in case this is
+ * recovery/resume
+ */
+ if (wlvif->bss_type != BSS_TYPE_AP_BSS)
+ wl->links[link].total_freed_pkts = wlvif->total_freed_pkts;
+
*hlid = link;
wl->active_link_count++;
@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
wl1271_tx_reset_link_queues(wl, *hlid);
wl->links[*hlid].wlvif = NULL;
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
+ (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ *hlid == wlvif->ap.bcast_hlid)) {
+ /*
+ * save the total freed packets in the wlvif, in case this is
+ * recovery or suspend
+ */
+ wlvif->total_freed_pkts = wl->links[*hlid].total_freed_pkts;
+
+ /*
+ * increment the initial seq number on recovery to account for
+ * transmitted packets that we haven't yet got in the FW status
+ */
+ if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+ wlvif->total_freed_pkts +=
+ WL1271_TX_SQN_POST_RECOVERY_PADDING;
+ }
+
+ wl->links[*hlid].total_freed_pkts = 0;
+
*hlid = WL12XX_INVALID_LINK_ID;
wl->active_link_count--;
WARN_ON_ONCE(wl->active_link_count < 0);
@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0)
goto out_free_global;
+ /* use the previous security seq, if this is a recovery/resume */
+ wl->links[wlvif->ap.bcast_hlid].total_freed_pkts =
+ wlvif->total_freed_pkts;
+
cmd->role_id = wlvif->role_id;
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
diff --git a/drivers/net/wireless/ti/wlcore/debug.h b/drivers/net/wireless/ti/wlcore/debug.h
index db4bf5a68ce2..0420bd45e4ee 100644
--- a/drivers/net/wireless/ti/wlcore/debug.h
+++ b/drivers/net/wireless/ti/wlcore/debug.h
@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level;
} while (0)
#endif
-/* TODO: use pr_debug_hex_dump when it becomes available */
-#define wl1271_dump(level, prefix, buf, len) \
- do { \
- if (level & wl12xx_debug_level) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- 0); \
+#define wl1271_dump(level, prefix, buf, len) \
+ do { \
+ if (level & wl12xx_debug_level) \
+ print_hex_dump_debug(DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
} while (0)
-#define wl1271_dump_ascii(level, prefix, buf, len) \
- do { \
- if (level & wl12xx_debug_level) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- true); \
+#define wl1271_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & wl12xx_debug_level) \
+ print_hex_dump_debug(DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
} while (0)
#endif /* __DEBUG_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index e70a7c864865..c3e1f79c7856 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
VIF_STATE_PRINT_INT(last_rssi_event);
VIF_STATE_PRINT_INT(ba_support);
VIF_STATE_PRINT_INT(ba_allowed);
- VIF_STATE_PRINT_LLHEX(tx_security_seq);
- VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
+ VIF_STATE_PRINT_LLHEX(total_freed_pkts);
}
#undef VIF_STATE_PRINT_INT
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 70f289aa1bc6..67f61689b49e 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
!test_bit(wlvif->role_id , &roles_bitmap))
continue;
+ vif = wl12xx_wlvif_to_vif(wlvif);
+
+ /* don't attempt roaming in case of p2p */
+ if (wlvif->p2p) {
+ ieee80211_connection_loss(vif);
+ continue;
+ }
+
/*
* if the work is already queued, it should take place.
* We don't want to delay the connection loss
@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
&wlvif->connection_loss_work,
msecs_to_jiffies(delay));
- vif = wl12xx_wlvif_to_vif(wlvif);
ieee80211_cqm_rssi_notify(
vif,
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 2c2ff3e1f849..953111a502ee 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -108,8 +108,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
}
- if (likely(wl->state == WLCORE_STATE_ON))
- wlcore_regdomain_config(wl);
+ wlcore_regdomain_config(wl);
}
static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
@@ -332,10 +331,9 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid, u8 tx_pkts)
{
- bool fw_ps, single_link;
+ bool fw_ps;
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
- single_link = (wl->active_link_count == 1);
/*
* Wake up from high level PS if the STA is asleep with too little
@@ -348,8 +346,13 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
* Start high-level PS if the STA is asleep with enough blocks in FW.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
+ * Note that a single connected STA means 3 active links, since we must
+ * account for the global and broadcast AP links. The "fw_ps" check
+ * assures us the third link is a STA connected to the AP. Otherwise
+ * the FW would not set the PSM bit.
*/
- else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ else if (wl->active_link_count > 3 && fw_ps &&
+ tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -414,13 +417,21 @@ static int wlcore_fw_status(struct wl1271 *wl,
for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
+ u8 diff;
lnk = &wl->links[i];
+
/* prevent wrap-around in freed-packets counter */
- lnk->allocated_pkts -=
- (status_2->counters.tx_lnk_free_pkts[i] -
- lnk->prev_freed_pkts) & 0xff;
+ diff = (status_2->counters.tx_lnk_free_pkts[i] -
+ lnk->prev_freed_pkts) & 0xff;
+
+ if (diff == 0)
+ continue;
+ lnk->allocated_pkts -= diff;
lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
+
+ /* accumulate the prev_freed_pkts counter */
+ lnk->total_freed_pkts += diff;
}
/* prevent wrap-around in total blocks counter */
@@ -640,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie)
unsigned long flags;
struct wl1271 *wl = cookie;
+ /* complete the ELP completion */
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
+ if (wl->elp_compl) {
+ complete(wl->elp_compl);
+ wl->elp_compl = NULL;
+ }
+
+ if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
+ /* don't enqueue a work right now. mark it as pending */
+ set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
+ wl1271_debug(DEBUG_IRQ, "should not enqueue work");
+ disable_irq_nosync(wl->irq);
+ pm_wakeup_event(wl->dev, 0);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
/* TX might be handled here, avoid redundant work */
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
@@ -919,18 +949,6 @@ static void wl1271_recovery_work(struct work_struct *work)
goto out_unlock;
}
- /*
- * Advance security sequence number to overcome potential progress
- * in the firmware during recovery. This doens't hurt if the network is
- * not encrypted.
- */
- wl12xx_for_each_wlvif(wl, wlvif) {
- if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
- test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
- wlvif->tx_security_seq +=
- WL1271_TX_SQN_POST_RECOVERY_PADDING;
- }
-
/* Prevent spurious TX during FW restart */
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
@@ -2523,6 +2541,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
wl1271_ps_elp_sleep(wl);
}
deinit:
+ wl12xx_tx_reset_wlvif(wl, wlvif);
+
/* clear all hlids (except system_hlid) */
wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
@@ -2546,7 +2566,6 @@ deinit:
dev_kfree_skb(wlvif->probereq);
wlvif->probereq = NULL;
- wl12xx_tx_reset_wlvif(wl, wlvif);
if (wl->last_wlvif == wlvif)
wl->last_wlvif = NULL;
list_del(&wlvif->list);
@@ -2860,10 +2879,6 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
wlvif->sta.klv_template_id,
ACX_KEEP_ALIVE_TPL_INVALID);
- /* reset TX security counters on a clean disconnect */
- wlvif->tx_security_last_seq_lsb = 0;
- wlvif->tx_security_seq = 0;
-
return 0;
}
@@ -3262,6 +3277,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
u32 tx_seq_32 = 0;
u16 tx_seq_16 = 0;
u8 key_type;
+ u8 hlid;
wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
@@ -3271,6 +3287,22 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
key_conf->keylen, key_conf->flags);
wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS)
+ if (sta) {
+ struct wl1271_station *wl_sta = (void *)sta->drv_priv;
+ hlid = wl_sta->hlid;
+ } else {
+ hlid = wlvif->ap.bcast_hlid;
+ }
+ else
+ hlid = wlvif->sta.hlid;
+
+ if (hlid != WL12XX_INVALID_LINK_ID) {
+ u64 tx_seq = wl->links[hlid].total_freed_pkts;
+ tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq);
+ tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq);
+ }
+
switch (key_conf->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -3280,22 +3312,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
break;
case WLAN_CIPHER_SUITE_TKIP:
key_type = KEY_TKIP;
-
key_conf->hw_key_idx = key_conf->keyidx;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
case WLAN_CIPHER_SUITE_CCMP:
key_type = KEY_AES;
-
key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
case WL1271_CIPHER_SUITE_GEM:
key_type = KEY_GEM;
- tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
- tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
break;
default:
wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
@@ -3358,6 +3382,10 @@ void wlcore_regdomain_config(struct wl1271 *wl)
return;
mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
@@ -4474,7 +4502,7 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx,
if (idx != 0)
return -ENOENT;
- survey->channel = conf->channel;
+ survey->channel = conf->chandef.chan;
survey->filled = 0;
return 0;
}
@@ -4499,6 +4527,9 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
return -EBUSY;
}
+ /* use the previous security seq, if this is a recovery/resume */
+ wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts;
+
set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
wl->active_sta_count++;
@@ -4507,12 +4538,37 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
{
+ struct wl1271_station *wl_sta;
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
return;
clear_bit(hlid, wlvif->ap.sta_hlid_map);
__clear_bit(hlid, &wl->ap_ps_map);
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+
+ /*
+ * save the last used PN in the private part of iee80211_sta,
+ * in case of recovery/suspend
+ */
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
+ if (sta) {
+ wl_sta = (void *)sta->drv_priv;
+ wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
+
+ /*
+ * increment the initial seq number on recovery to account for
+ * transmitted packets that we haven't yet got in the FW status
+ */
+ if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+ wl_sta->total_freed_pkts +=
+ WL1271_TX_SQN_POST_RECOVERY_PADDING;
+ }
+ rcu_read_unlock();
+
wl12xx_free_link(wl, wlvif, &hlid);
wl->active_sta_count--;
@@ -4616,13 +4672,11 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
enum ieee80211_sta_state new_state)
{
struct wl1271_station *wl_sta;
- u8 hlid;
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
int ret;
wl_sta = (struct wl1271_station *)sta->drv_priv;
- hlid = wl_sta->hlid;
/* Add station (AP mode) */
if (is_ap &&
@@ -4648,12 +4702,12 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
/* Authorize station (AP mode) */
if (is_ap &&
new_state == IEEE80211_STA_AUTHORIZED) {
- ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid);
+ ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid);
if (ret < 0)
return ret;
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
- hlid);
+ wl_sta->hlid);
if (ret)
return ret;
@@ -4784,7 +4838,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
break;
}
- if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
+ if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) {
ret = -EBUSY;
wl1271_error("exceeded max RX BA sessions");
break;
@@ -4946,7 +5000,7 @@ out:
mutex_unlock(&wl->mutex);
}
-static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
+static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
{
struct wl1271 *wl = hw->priv;
@@ -4956,7 +5010,8 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *chan,
- int duration)
+ int duration,
+ enum ieee80211_roc_type type)
{
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
struct wl1271 *wl = hw->priv;
@@ -5091,6 +5146,39 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
}
+static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ s8 *rssi_dbm)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
{
struct wl1271 *wl = hw->priv;
@@ -5290,6 +5378,7 @@ static const struct ieee80211_ops wl1271_ops = {
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
+ .get_rssi = wlcore_op_get_rssi,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -5929,35 +6018,6 @@ int wlcore_free_hw(struct wl1271 *wl)
}
EXPORT_SYMBOL_GPL(wlcore_free_hw);
-static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
-{
- struct wl1271 *wl = cookie;
- unsigned long flags;
-
- wl1271_debug(DEBUG_IRQ, "IRQ");
-
- /* complete the ELP completion */
- spin_lock_irqsave(&wl->wl_lock, flags);
- set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
- if (wl->elp_compl) {
- complete(wl->elp_compl);
- wl->elp_compl = NULL;
- }
-
- if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
- /* don't enqueue a work right now. mark it as pending */
- set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
- wl1271_debug(DEBUG_IRQ, "should not enqueue work");
- disable_irq_nosync(wl->irq);
- pm_wakeup_event(wl->dev, 0);
- spin_unlock_irqrestore(&wl->wl_lock, flags);
- return IRQ_HANDLED;
- }
- spin_unlock_irqrestore(&wl->wl_lock, flags);
-
- return IRQ_WAKE_THREAD;
-}
-
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
{
struct wl1271 *wl = context;
@@ -5999,9 +6059,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
else
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
- ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq,
- irqflags,
- pdev->name, wl);
+ ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
+ irqflags, pdev->name, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
goto out_free_nvs;
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index 9b7b6e2e4fbc..9654577efd01 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -29,6 +29,7 @@
#define WL1271_WAKEUP_TIMEOUT 500
#define ELP_ENTRY_DELAY 30
+#define ELP_ENTRY_DELAY_FORCE_PS 5
void wl1271_elp_work(struct work_struct *work)
{
@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return;
}
- timeout = ELP_ENTRY_DELAY;
+ timeout = wl->conf.conn.forced_ps ?
+ ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY;
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(timeout));
}
diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c
index ece392c54d9c..004d02e71f01 100644
--- a/drivers/net/wireless/ti/wlcore/tx.c
+++ b/drivers/net/wireless/ti/wlcore/tx.c
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
#include "wlcore.h"
#include "debug.h"
@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
u8 hlid)
{
- bool fw_ps, single_link;
+ bool fw_ps;
u8 tx_pkts;
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
tx_pkts = wl->links[hlid].allocated_pkts;
- single_link = (wl->active_link_count == 1);
/*
* if in FW PS and there is enough data in FW we can put the link
* into high-level PS and clean out its TX queues.
* Make an exception if this is the only connected link. In this
* case FW-memory congestion is less of a problem.
+ * Note that a single connected STA means 3 active links, since we must
+ * account for the global and broadcast AP links. The "fw_ps" check
+ * assures us the third link is a STA connected to the AP. Otherwise
+ * the FW would not set the PSM bit.
*/
- if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+ if (wl->active_link_count > 3 && fw_ps &&
+ tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
wl12xx_ps_link_start(wl, wlvif, hlid, true);
}
@@ -639,6 +644,7 @@ next:
}
+out:
if (!skb &&
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
int q;
@@ -652,7 +658,6 @@ next:
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
-out:
return skb;
}
@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
wl->stats.retry_count += result->ack_failures;
- /*
- * update sequence number only when relevant, i.e. only in
- * sessions of TKIP, AES and GEM (not in open or WEP sessions)
- */
- if (info->control.hw_key &&
- (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
- info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
- info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
- u8 fw_lsb = result->tx_security_sequence_number_lsb;
- u8 cur_lsb = wlvif->tx_security_last_seq_lsb;
-
- /*
- * update security sequence number, taking care of potential
- * wrap-around
- */
- wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
- wlvif->tx_security_last_seq_lsb = fw_lsb;
- }
-
/* remove private header from packet */
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* TX failure */
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
+ if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
/* this calls wl12xx_free_link */
wl1271_free_sta(wl, wlvif, i);
} else {
@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
{
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
- WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ assert_spin_locked(&wl->wl_lock);
return test_bit(reason, &wl->queue_stop_reasons[hwq]);
}
@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
{
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
- WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
+ assert_spin_locked(&wl->wl_lock);
return !!wl->queue_stop_reasons[hwq];
}
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index af9fecaefc30..0034979e97cb 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -390,6 +390,9 @@ struct wl1271 {
/* number of currently active RX BA sessions */
int ba_rx_session_count;
+ /* Maximum number of supported RX BA sessions */
+ int ba_rx_session_count_max;
+
/* AP-mode - number of currently connected stations */
int active_sta_count;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 508f5b0f8a70..e5e146435fe7 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -274,6 +274,13 @@ struct wl1271_link {
/* The wlvif this link belongs to. Might be null for global links */
struct wl12xx_vif *wlvif;
+
+ /*
+ * total freed FW packets on the link - used for tracking the
+ * AES/TKIP PN across recoveries. Re-initialized each time
+ * from the wl1271_station structure.
+ */
+ u64 total_freed_pkts;
};
#define WL1271_MAX_RX_FILTERS 5
@@ -318,6 +325,13 @@ struct wl12xx_rx_filter {
struct wl1271_station {
u8 hlid;
bool in_connection;
+
+ /*
+ * total freed FW packets on the link to the STA - used for tracking the
+ * AES/TKIP PN across recoveries. Re-initialized each time from the
+ * wl1271_station structure.
+ */
+ u64 total_freed_pkts;
};
struct wl12xx_vif {
@@ -449,16 +463,15 @@ struct wl12xx_vif {
*/
struct {
u8 persistent[0];
+
/*
- * Security sequence number
- * bits 0-15: lower 16 bits part of sequence number
- * bits 16-47: higher 32 bits part of sequence number
- * bits 48-63: not in use
+ * total freed FW packets on the link - used for
+ * storing the AES/TKIP PN during recovery, as this
+ * structure is not zeroed out.
+ * For STA this holds the PN of the link to the AP.
+ * For AP this holds the PN of the broadcast link.
*/
- u64 tx_security_seq;
-
- /* 8 bits of the last sequence number in use */
- u8 tx_security_last_seq_lsb;
+ u64 total_freed_pkts;
};
};
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 730186d0449b..38d2089f338a 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -2013,19 +2013,7 @@ static struct pcmcia_driver wl3501_driver = {
.suspend = wl3501_suspend,
.resume = wl3501_resume,
};
-
-static int __init wl3501_init_module(void)
-{
- return pcmcia_register_driver(&wl3501_driver);
-}
-
-static void __exit wl3501_exit_module(void)
-{
- pcmcia_unregister_driver(&wl3501_driver);
-}
-
-module_init(wl3501_init_module);
-module_exit(wl3501_exit_module);
+module_pcmcia_driver(wl3501_driver);
MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "
"Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 114364b5d466..c6208a7988e4 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -1156,10 +1156,10 @@ static int zd_op_config(struct ieee80211_hw *hw, u32 changed)
struct ieee80211_conf *conf = &hw->conf;
spin_lock_irq(&mac->lock);
- mac->channel = conf->channel->hw_value;
+ mac->channel = conf->chandef.chan->hw_value;
spin_unlock_irq(&mac->lock);
- return zd_chip_set_channel(&mac->chip, conf->channel->hw_value);
+ return zd_chip_set_channel(&mac->chip, conf->chandef.chan->hw_value);
}
static void zd_beacon_done(struct zd_mac *mac)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index cd49ba949636..a2865f17c667 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -47,11 +47,25 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/page.h>
+/*
+ * This is the maximum slots a skb can have. If a guest sends a skb
+ * which exceeds this limit it is considered malicious.
+ */
+#define MAX_SKB_SLOTS_DEFAULT 20
+static unsigned int max_skb_slots = MAX_SKB_SLOTS_DEFAULT;
+module_param(max_skb_slots, uint, 0444);
+
+typedef unsigned int pending_ring_idx_t;
+#define INVALID_PENDING_RING_IDX (~0U)
+
struct pending_tx_info {
- struct xen_netif_tx_request req;
+ struct xen_netif_tx_request req; /* coalesced tx request */
struct xenvif *vif;
+ pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX
+ * if it is head of one or more tx
+ * reqs
+ */
};
-typedef unsigned int pending_ring_idx_t;
struct netbk_rx_meta {
int id;
@@ -102,7 +116,11 @@ struct xen_netbk {
atomic_t netfront_count;
struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
- struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
+ /* Coalescing tx requests before copying makes number of grant
+ * copy ops greater or equal to number of slots required. In
+ * worst case a tx request consumes 2 gnttab_copy.
+ */
+ struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS];
u16 pending_ring[MAX_PENDING_REQS];
@@ -118,6 +136,16 @@ struct xen_netbk {
static struct xen_netbk *xen_netbk;
static int xen_netbk_group_nr;
+/*
+ * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of
+ * one or more merged tx requests, otherwise it is the continuation of
+ * previous tx request.
+ */
+static inline int pending_tx_is_head(struct xen_netbk *netbk, RING_IDX idx)
+{
+ return netbk->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
+}
+
void xen_netbk_add_xenvif(struct xenvif *vif)
{
int i;
@@ -250,6 +278,7 @@ static int max_required_rx_slots(struct xenvif *vif)
{
int max = DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE);
+ /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */
if (vif->can_sg || vif->gso || vif->gso_prefix)
max += MAX_SKB_FRAGS + 1; /* extra_info + frags */
@@ -657,6 +686,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
__skb_queue_tail(&rxq, skb);
/* Filled the batch queue? */
+ /* XXX FIXME: RX path dependent on MAX_SKB_FRAGS */
if (count + MAX_SKB_FRAGS >= XEN_NETIF_RX_RING_SIZE)
break;
}
@@ -898,51 +928,91 @@ static void netbk_fatal_tx_err(struct xenvif *vif)
static int netbk_count_requests(struct xenvif *vif,
struct xen_netif_tx_request *first,
+ RING_IDX first_idx,
struct xen_netif_tx_request *txp,
int work_to_do)
{
RING_IDX cons = vif->tx.req_cons;
- int frags = 0;
+ int slots = 0;
+ int drop_err = 0;
if (!(first->flags & XEN_NETTXF_more_data))
return 0;
do {
- if (frags >= work_to_do) {
- netdev_err(vif->dev, "Need more frags\n");
+ if (slots >= work_to_do) {
+ netdev_err(vif->dev,
+ "Asked for %d slots but exceeds this limit\n",
+ work_to_do);
netbk_fatal_tx_err(vif);
return -ENODATA;
}
- if (unlikely(frags >= MAX_SKB_FRAGS)) {
- netdev_err(vif->dev, "Too many frags\n");
+ /* This guest is really using too many slots and
+ * considered malicious.
+ */
+ if (unlikely(slots >= max_skb_slots)) {
+ netdev_err(vif->dev,
+ "Malicious frontend using %d slots, threshold %u\n",
+ slots, max_skb_slots);
netbk_fatal_tx_err(vif);
return -E2BIG;
}
- memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + frags),
+ /* Xen network protocol had implicit dependency on
+ * MAX_SKB_FRAGS. XEN_NETIF_NR_SLOTS_MIN is set to the
+ * historical MAX_SKB_FRAGS value 18 to honor the same
+ * behavior as before. Any packet using more than 18
+ * slots but less than max_skb_slots slots is dropped
+ */
+ if (!drop_err && slots >= XEN_NETIF_NR_SLOTS_MIN) {
+ if (net_ratelimit())
+ netdev_dbg(vif->dev,
+ "Too many slots (%d) exceeding limit (%d), dropping packet\n",
+ slots, XEN_NETIF_NR_SLOTS_MIN);
+ drop_err = -E2BIG;
+ }
+
+ memcpy(txp, RING_GET_REQUEST(&vif->tx, cons + slots),
sizeof(*txp));
- if (txp->size > first->size) {
- netdev_err(vif->dev, "Frag is bigger than frame.\n");
- netbk_fatal_tx_err(vif);
- return -EIO;
+
+ /* If the guest submitted a frame >= 64 KiB then
+ * first->size overflowed and following slots will
+ * appear to be larger than the frame.
+ *
+ * This cannot be fatal error as there are buggy
+ * frontends that do this.
+ *
+ * Consume all slots and drop the packet.
+ */
+ if (!drop_err && txp->size > first->size) {
+ if (net_ratelimit())
+ netdev_dbg(vif->dev,
+ "Invalid tx request, slot size %u > remaining size %u\n",
+ txp->size, first->size);
+ drop_err = -EIO;
}
first->size -= txp->size;
- frags++;
+ slots++;
if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
- netdev_err(vif->dev, "txp->offset: %x, size: %u\n",
+ netdev_err(vif->dev, "Cross page boundary, txp->offset: %x, size: %u\n",
txp->offset, txp->size);
netbk_fatal_tx_err(vif);
return -EINVAL;
}
} while ((txp++)->flags & XEN_NETTXF_more_data);
- return frags;
+
+ if (drop_err) {
+ netbk_tx_err(vif, first, first_idx + slots);
+ return drop_err;
+ }
+
+ return slots;
}
static struct page *xen_netbk_alloc_page(struct xen_netbk *netbk,
- struct sk_buff *skb,
u16 pending_idx)
{
struct page *page;
@@ -963,48 +1033,114 @@ static struct gnttab_copy *xen_netbk_get_requests(struct xen_netbk *netbk,
struct skb_shared_info *shinfo = skb_shinfo(skb);
skb_frag_t *frags = shinfo->frags;
u16 pending_idx = *((u16 *)skb->data);
- int i, start;
+ u16 head_idx = 0;
+ int slot, start;
+ struct page *page;
+ pending_ring_idx_t index, start_idx = 0;
+ uint16_t dst_offset;
+ unsigned int nr_slots;
+ struct pending_tx_info *first = NULL;
+
+ /* At this point shinfo->nr_frags is in fact the number of
+ * slots, which can be as large as XEN_NETIF_NR_SLOTS_MIN.
+ */
+ nr_slots = shinfo->nr_frags;
/* Skip first skb fragment if it is on same page as header fragment. */
start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
- for (i = start; i < shinfo->nr_frags; i++, txp++) {
- struct page *page;
- pending_ring_idx_t index;
+ /* Coalesce tx requests, at this point the packet passed in
+ * should be <= 64K. Any packets larger than 64K have been
+ * handled in netbk_count_requests().
+ */
+ for (shinfo->nr_frags = slot = start; slot < nr_slots;
+ shinfo->nr_frags++) {
struct pending_tx_info *pending_tx_info =
netbk->pending_tx_info;
- index = pending_index(netbk->pending_cons++);
- pending_idx = netbk->pending_ring[index];
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
+ page = alloc_page(GFP_KERNEL|__GFP_COLD);
if (!page)
goto err;
- gop->source.u.ref = txp->gref;
- gop->source.domid = vif->domid;
- gop->source.offset = txp->offset;
-
- gop->dest.u.gmfn = virt_to_mfn(page_address(page));
- gop->dest.domid = DOMID_SELF;
- gop->dest.offset = txp->offset;
-
- gop->len = txp->size;
- gop->flags = GNTCOPY_source_gref;
+ dst_offset = 0;
+ first = NULL;
+ while (dst_offset < PAGE_SIZE && slot < nr_slots) {
+ gop->flags = GNTCOPY_source_gref;
+
+ gop->source.u.ref = txp->gref;
+ gop->source.domid = vif->domid;
+ gop->source.offset = txp->offset;
+
+ gop->dest.domid = DOMID_SELF;
+
+ gop->dest.offset = dst_offset;
+ gop->dest.u.gmfn = virt_to_mfn(page_address(page));
+
+ if (dst_offset + txp->size > PAGE_SIZE) {
+ /* This page can only merge a portion
+ * of tx request. Do not increment any
+ * pointer / counter here. The txp
+ * will be dealt with in future
+ * rounds, eventually hitting the
+ * `else` branch.
+ */
+ gop->len = PAGE_SIZE - dst_offset;
+ txp->offset += gop->len;
+ txp->size -= gop->len;
+ dst_offset += gop->len; /* quit loop */
+ } else {
+ /* This tx request can be merged in the page */
+ gop->len = txp->size;
+ dst_offset += gop->len;
+
+ index = pending_index(netbk->pending_cons++);
+
+ pending_idx = netbk->pending_ring[index];
+
+ memcpy(&pending_tx_info[pending_idx].req, txp,
+ sizeof(*txp));
+ xenvif_get(vif);
+
+ pending_tx_info[pending_idx].vif = vif;
+
+ /* Poison these fields, corresponding
+ * fields for head tx req will be set
+ * to correct values after the loop.
+ */
+ netbk->mmap_pages[pending_idx] = (void *)(~0UL);
+ pending_tx_info[pending_idx].head =
+ INVALID_PENDING_RING_IDX;
+
+ if (!first) {
+ first = &pending_tx_info[pending_idx];
+ start_idx = index;
+ head_idx = pending_idx;
+ }
+
+ txp++;
+ slot++;
+ }
- gop++;
+ gop++;
+ }
- memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
- xenvif_get(vif);
- pending_tx_info[pending_idx].vif = vif;
- frag_set_pending_idx(&frags[i], pending_idx);
+ first->req.offset = 0;
+ first->req.size = dst_offset;
+ first->head = start_idx;
+ set_page_ext(page, netbk, head_idx);
+ netbk->mmap_pages[head_idx] = page;
+ frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
}
+ BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS);
+
return gop;
err:
/* Unwind, freeing all pages and sending error responses. */
- while (i-- > start) {
- xen_netbk_idx_release(netbk, frag_get_pending_idx(&frags[i]),
- XEN_NETIF_RSP_ERROR);
+ while (shinfo->nr_frags-- > start) {
+ xen_netbk_idx_release(netbk,
+ frag_get_pending_idx(&frags[shinfo->nr_frags]),
+ XEN_NETIF_RSP_ERROR);
}
/* The head too, if necessary. */
if (start)
@@ -1020,8 +1156,10 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
struct gnttab_copy *gop = *gopp;
u16 pending_idx = *((u16 *)skb->data);
struct skb_shared_info *shinfo = skb_shinfo(skb);
+ struct pending_tx_info *tx_info;
int nr_frags = shinfo->nr_frags;
int i, err, start;
+ u16 peek; /* peek into next tx request */
/* Check status of header. */
err = gop->status;
@@ -1033,11 +1171,20 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk,
for (i = start; i < nr_frags; i++) {
int j, newerr;
+ pending_ring_idx_t head;
pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
+ tx_info = &netbk->pending_tx_info[pending_idx];
+ head = tx_info->head;
/* Check error status: if okay then remember grant handle. */
- newerr = (++gop)->status;
+ do {
+ newerr = (++gop)->status;
+ if (newerr)
+ break;
+ peek = netbk->pending_ring[pending_index(++head)];
+ } while (!pending_tx_is_head(netbk, peek));
+
if (likely(!newerr)) {
/* Had a previous error? Invalidate this fragment. */
if (unlikely(err))
@@ -1157,7 +1304,6 @@ static int netbk_set_skb_gso(struct xenvif *vif,
static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
{
struct iphdr *iph;
- unsigned char *th;
int err = -EPROTO;
int recalculate_partial_csum = 0;
@@ -1181,27 +1327,26 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
goto out;
iph = (void *)skb->data;
- th = skb->data + 4 * iph->ihl;
- if (th >= skb_tail_pointer(skb))
- goto out;
-
- skb->csum_start = th - skb->head;
switch (iph->protocol) {
case IPPROTO_TCP:
- skb->csum_offset = offsetof(struct tcphdr, check);
+ if (!skb_partial_csum_set(skb, 4 * iph->ihl,
+ offsetof(struct tcphdr, check)))
+ goto out;
if (recalculate_partial_csum) {
- struct tcphdr *tcph = (struct tcphdr *)th;
+ struct tcphdr *tcph = tcp_hdr(skb);
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
skb->len - iph->ihl*4,
IPPROTO_TCP, 0);
}
break;
case IPPROTO_UDP:
- skb->csum_offset = offsetof(struct udphdr, check);
+ if (!skb_partial_csum_set(skb, 4 * iph->ihl,
+ offsetof(struct udphdr, check)))
+ goto out;
if (recalculate_partial_csum) {
- struct udphdr *udph = (struct udphdr *)th;
+ struct udphdr *udph = udp_hdr(skb);
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
skb->len - iph->ihl*4,
IPPROTO_UDP, 0);
@@ -1215,9 +1360,6 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
goto out;
}
- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
- goto out;
-
err = 0;
out:
@@ -1262,11 +1404,12 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
struct sk_buff *skb;
int ret;
- while (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
+ while ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN
+ < MAX_PENDING_REQS) &&
!list_empty(&netbk->net_schedule_list)) {
struct xenvif *vif;
struct xen_netif_tx_request txreq;
- struct xen_netif_tx_request txfrags[MAX_SKB_FRAGS];
+ struct xen_netif_tx_request txfrags[max_skb_slots];
struct page *page;
struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
u16 pending_idx;
@@ -1327,7 +1470,8 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
continue;
}
- ret = netbk_count_requests(vif, &txreq, txfrags, work_to_do);
+ ret = netbk_count_requests(vif, &txreq, idx,
+ txfrags, work_to_do);
if (unlikely(ret < 0))
continue;
@@ -1354,7 +1498,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
pending_idx = netbk->pending_ring[index];
data_len = (txreq.size > PKT_PROT_LEN &&
- ret < MAX_SKB_FRAGS) ?
+ ret < XEN_NETIF_NR_SLOTS_MIN) ?
PKT_PROT_LEN : txreq.size;
skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
@@ -1381,7 +1525,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
}
/* XXX could copy straight to head */
- page = xen_netbk_alloc_page(netbk, skb, pending_idx);
+ page = xen_netbk_alloc_page(netbk, pending_idx);
if (!page) {
kfree_skb(skb);
netbk_tx_err(vif, &txreq, idx);
@@ -1404,6 +1548,7 @@ static unsigned xen_netbk_tx_build_gops(struct xen_netbk *netbk)
memcpy(&netbk->pending_tx_info[pending_idx].req,
&txreq, sizeof(txreq));
netbk->pending_tx_info[pending_idx].vif = vif;
+ netbk->pending_tx_info[pending_idx].head = index;
*((u16 *)skb->data) = pending_idx;
__skb_put(skb, data_len);
@@ -1496,6 +1641,7 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
skb->dev = vif->dev;
skb->protocol = eth_type_trans(skb, skb->dev);
+ skb_reset_network_header(skb);
if (checksum_setup(vif, skb)) {
netdev_dbg(vif->dev,
@@ -1504,6 +1650,8 @@ static void xen_netbk_tx_submit(struct xen_netbk *netbk)
continue;
}
+ skb_probe_transport_header(skb, 0);
+
vif->dev->stats.rx_bytes += skb->len;
vif->dev->stats.rx_packets++;
@@ -1531,7 +1679,10 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
{
struct xenvif *vif;
struct pending_tx_info *pending_tx_info;
- pending_ring_idx_t index;
+ pending_ring_idx_t head;
+ u16 peek; /* peek into next tx request */
+
+ BUG_ON(netbk->mmap_pages[pending_idx] == (void *)(~0UL));
/* Already complete? */
if (netbk->mmap_pages[pending_idx] == NULL)
@@ -1540,19 +1691,40 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx,
pending_tx_info = &netbk->pending_tx_info[pending_idx];
vif = pending_tx_info->vif;
+ head = pending_tx_info->head;
+
+ BUG_ON(!pending_tx_is_head(netbk, head));
+ BUG_ON(netbk->pending_ring[pending_index(head)] != pending_idx);
+
+ do {
+ pending_ring_idx_t index;
+ pending_ring_idx_t idx = pending_index(head);
+ u16 info_idx = netbk->pending_ring[idx];
- make_tx_response(vif, &pending_tx_info->req, status);
+ pending_tx_info = &netbk->pending_tx_info[info_idx];
+ make_tx_response(vif, &pending_tx_info->req, status);
- index = pending_index(netbk->pending_prod++);
- netbk->pending_ring[index] = pending_idx;
+ /* Setting any number other than
+ * INVALID_PENDING_RING_IDX indicates this slot is
+ * starting a new packet / ending a previous packet.
+ */
+ pending_tx_info->head = 0;
- xenvif_put(vif);
+ index = pending_index(netbk->pending_prod++);
+ netbk->pending_ring[index] = netbk->pending_ring[info_idx];
+
+ xenvif_put(vif);
+
+ peek = netbk->pending_ring[pending_index(++head)];
+
+ } while (!pending_tx_is_head(netbk, peek));
netbk->mmap_pages[pending_idx]->mapping = 0;
put_page(netbk->mmap_pages[pending_idx]);
netbk->mmap_pages[pending_idx] = NULL;
}
+
static void make_tx_response(struct xenvif *vif,
struct xen_netif_tx_request *txp,
s8 st)
@@ -1605,8 +1777,9 @@ static inline int rx_work_todo(struct xen_netbk *netbk)
static inline int tx_work_todo(struct xen_netbk *netbk)
{
- if (((nr_pending_reqs(netbk) + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
- !list_empty(&netbk->net_schedule_list))
+ if ((nr_pending_reqs(netbk) + XEN_NETIF_NR_SLOTS_MIN
+ < MAX_PENDING_REQS) &&
+ !list_empty(&netbk->net_schedule_list))
return 1;
return 0;
@@ -1689,6 +1862,13 @@ static int __init netback_init(void)
if (!xen_domain())
return -ENODEV;
+ if (max_skb_slots < XEN_NETIF_NR_SLOTS_MIN) {
+ printk(KERN_INFO
+ "xen-netback: max_skb_slots too small (%d), bump it to XEN_NETIF_NR_SLOTS_MIN (%d)\n",
+ max_skb_slots, XEN_NETIF_NR_SLOTS_MIN);
+ max_skb_slots = XEN_NETIF_NR_SLOTS_MIN;
+ }
+
xen_netbk_group_nr = num_online_cpus();
xen_netbk = vzalloc(sizeof(struct xen_netbk) * xen_netbk_group_nr);
if (!xen_netbk)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 7ffa43bd7cf9..1db101415069 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -36,7 +36,7 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/if_ether.h>
-#include <linux/tcp.h>
+#include <net/tcp.h>
#include <linux/udp.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
@@ -537,7 +537,6 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct netfront_info *np = netdev_priv(dev);
struct netfront_stats *stats = this_cpu_ptr(np->stats);
struct xen_netif_tx_request *tx;
- struct xen_netif_extra_info *extra;
char *data = skb->data;
RING_IDX i;
grant_ref_t ref;
@@ -548,6 +547,16 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int len = skb_headlen(skb);
unsigned long flags;
+ /* If skb->len is too big for wire format, drop skb and alert
+ * user about misconfiguration.
+ */
+ if (unlikely(skb->len > XEN_NETIF_MAX_TX_SIZE)) {
+ net_alert_ratelimited(
+ "xennet: skb->len = %u, too big for wire format\n",
+ skb->len);
+ goto drop;
+ }
+
slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) +
xennet_count_skb_frag_slots(skb);
if (unlikely(slots > MAX_SKB_FRAGS + 1)) {
@@ -581,7 +590,6 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
tx->gref = np->grant_tx_ref[id] = ref;
tx->offset = offset;
tx->size = len;
- extra = NULL;
tx->flags = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -597,10 +605,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
gso = (struct xen_netif_extra_info *)
RING_GET_REQUEST(&np->tx, ++i);
- if (extra)
- extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
- else
- tx->flags |= XEN_NETTXF_extra_info;
+ tx->flags |= XEN_NETTXF_extra_info;
gso->u.gso.size = skb_shinfo(skb)->gso_size;
gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
@@ -609,7 +614,6 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
gso->flags = 0;
- extra = gso;
}
np->tx.req_prod_pvt = i + 1;
@@ -718,7 +722,7 @@ static int xennet_get_responses(struct netfront_info *np,
struct sk_buff *skb = xennet_get_rx_skb(np, cons);
grant_ref_t ref = xennet_get_rx_ref(np, cons);
int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
- int frags = 1;
+ int slots = 1;
int err = 0;
unsigned long ret;
@@ -741,7 +745,7 @@ static int xennet_get_responses(struct netfront_info *np,
/*
* This definitely indicates a bug, either in this driver or in
* the backend driver. In future this should flag the bad
- * situation to the system controller to reboot the backed.
+ * situation to the system controller to reboot the backend.
*/
if (ref == GRANT_INVALID_REF) {
if (net_ratelimit())
@@ -762,27 +766,27 @@ next:
if (!(rx->flags & XEN_NETRXF_more_data))
break;
- if (cons + frags == rp) {
+ if (cons + slots == rp) {
if (net_ratelimit())
- dev_warn(dev, "Need more frags\n");
+ dev_warn(dev, "Need more slots\n");
err = -ENOENT;
break;
}
- rx = RING_GET_RESPONSE(&np->rx, cons + frags);
- skb = xennet_get_rx_skb(np, cons + frags);
- ref = xennet_get_rx_ref(np, cons + frags);
- frags++;
+ rx = RING_GET_RESPONSE(&np->rx, cons + slots);
+ skb = xennet_get_rx_skb(np, cons + slots);
+ ref = xennet_get_rx_ref(np, cons + slots);
+ slots++;
}
- if (unlikely(frags > max)) {
+ if (unlikely(slots > max)) {
if (net_ratelimit())
- dev_warn(dev, "Too many frags\n");
+ dev_warn(dev, "Too many slots\n");
err = -E2BIG;
}
if (unlikely(err))
- np->rx.rsp_cons = cons + frags;
+ np->rx.rsp_cons = cons + slots;
return err;
}
@@ -1064,7 +1068,8 @@ err:
static int xennet_change_mtu(struct net_device *dev, int mtu)
{
- int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+ int max = xennet_can_sg(dev) ?
+ XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER : ETH_DATA_LEN;
if (mtu > max)
return -EINVAL;
@@ -1368,6 +1373,8 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
SET_NETDEV_DEV(netdev, &dev->dev);
+ netif_set_gso_max_size(netdev, XEN_NETIF_MAX_TX_SIZE - MAX_TCP_HEADER);
+
np->netdev = netdev;
netif_carrier_off(netdev);
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index e57034971ccc..4775d4e61b88 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -26,6 +26,16 @@ config NFC_WILINK
Say Y here to compile support for Texas Instrument's NFC WiLink driver
into the kernel or say M to compile it as module.
+config NFC_MEI_PHY
+ tristate "MEI bus NFC device support"
+ depends on INTEL_MEI_BUS_NFC && NFC_HCI
+ help
+ This adds support to use an mei bus nfc device. Select this if you
+ will use an HCI NFC driver for an NFC chip connected behind an
+ Intel's Management Engine chip.
+
+ If unsure, say N.
+
source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index a189ada0926a..aa6bd657ef40 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544) += pn544/
obj-$(CONFIG_NFC_MICROREAD) += microread/
obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
+obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
new file mode 100644
index 000000000000..b8f8abc422f0
--- /dev/null
+++ b/drivers/nfc/mei_phy.c
@@ -0,0 +1,164 @@
+/*
+ * MEI Library for mei bus nfc device access
+ *
+ * Copyright (C) 2013 Intel Corporation. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/nfc.h>
+
+#include "mei_phy.h"
+
+struct mei_nfc_hdr {
+ u8 cmd;
+ u8 status;
+ u16 req_id;
+ u32 reserved;
+ u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+#define MEI_DUMP_SKB_IN(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET, \
+ 16, 1, (skb)->data, (skb)->len, false); \
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb) \
+do { \
+ pr_debug("%s:\n", info); \
+ print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET, \
+ 16, 1, (skb)->data, (skb)->len, false); \
+} while (0)
+
+int nfc_mei_phy_enable(void *phy_id)
+{
+ int r;
+ struct nfc_mei_phy *phy = phy_id;
+
+ pr_info("%s\n", __func__);
+
+ if (phy->powered == 1)
+ return 0;
+
+ r = mei_cl_enable_device(phy->device);
+ if (r < 0) {
+ pr_err("MEI_PHY: Could not enable device\n");
+ return r;
+ }
+
+ phy->powered = 1;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
+
+void nfc_mei_phy_disable(void *phy_id)
+{
+ struct nfc_mei_phy *phy = phy_id;
+
+ pr_info("%s\n", __func__);
+
+ mei_cl_disable_device(phy->device);
+
+ phy->powered = 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
+{
+ struct nfc_mei_phy *phy = phy_id;
+ int r;
+
+ MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+ r = mei_cl_send(phy->device, skb->data, skb->len);
+ if (r > 0)
+ r = 0;
+
+ return r;
+}
+
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
+{
+ struct nfc_mei_phy *phy = context;
+
+ if (phy->hard_fault != 0)
+ return;
+
+ if (events & BIT(MEI_CL_EVENT_RX)) {
+ struct sk_buff *skb;
+ int reply_size;
+
+ skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
+ if (reply_size < MEI_NFC_HEADER_SIZE) {
+ kfree(skb);
+ return;
+ }
+
+ skb_put(skb, reply_size);
+ skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+ MEI_DUMP_SKB_IN("mei frame read", skb);
+
+ nfc_hci_recv_frame(phy->hdev, skb);
+ }
+}
+EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
+
+struct nfc_phy_ops mei_phy_ops = {
+ .write = nfc_mei_phy_write,
+ .enable = nfc_mei_phy_enable,
+ .disable = nfc_mei_phy_disable,
+};
+EXPORT_SYMBOL_GPL(mei_phy_ops);
+
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
+{
+ struct nfc_mei_phy *phy;
+
+ phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
+ if (!phy)
+ return NULL;
+
+ phy->device = device;
+ mei_cl_set_drvdata(device, phy);
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
+
+void nfc_mei_phy_free(struct nfc_mei_phy *phy)
+{
+ kfree(phy);
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("mei bus NFC device interface");
diff --git a/drivers/nfc/mei_phy.h b/drivers/nfc/mei_phy.h
new file mode 100644
index 000000000000..d669900f8278
--- /dev/null
+++ b/drivers/nfc/mei_phy.h
@@ -0,0 +1,30 @@
+#ifndef __LOCAL_MEI_PHY_H_
+#define __LOCAL_MEI_PHY_H_
+
+#include <linux/mei_cl_bus.h>
+#include <net/nfc/hci.h>
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+
+struct nfc_mei_phy {
+ struct mei_cl_device *device;
+ struct nfc_hci_dev *hdev;
+
+ int powered;
+
+ int hard_fault; /*
+ * < 0 if hardware error occured
+ * and prevents normal operation.
+ */
+};
+
+extern struct nfc_phy_ops mei_phy_ops;
+
+int nfc_mei_phy_enable(void *phy_id);
+void nfc_mei_phy_disable(void *phy_id);
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
+void nfc_mei_phy_free(struct nfc_mei_phy *phy);
+
+#endif /* __LOCAL_MEI_PHY_H_ */
diff --git a/drivers/nfc/microread/Kconfig b/drivers/nfc/microread/Kconfig
index 572305be6e37..951d5542f6bc 100644
--- a/drivers/nfc/microread/Kconfig
+++ b/drivers/nfc/microread/Kconfig
@@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C
config NFC_MICROREAD_MEI
tristate "NFC Microread MEI support"
- depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+ depends on NFC_MICROREAD && NFC_MEI_PHY
---help---
This module adds support for the mei interface of adapters using
Inside microread chipsets. Select this if your microread chipset
diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
index eef38cfd812e..1ad044dce7b6 100644
--- a/drivers/nfc/microread/mei.c
+++ b/drivers/nfc/microread/mei.c
@@ -19,154 +19,31 @@
*/
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mei_bus.h>
-
+#include <linux/mod_devicetable.h>
#include <linux/nfc.h>
#include <net/nfc/hci.h>
#include <net/nfc/llc.h>
+#include "../mei_phy.h"
#include "microread.h"
#define MICROREAD_DRIVER_NAME "microread"
-#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
- 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
-
-struct mei_nfc_hdr {
- u8 cmd;
- u8 status;
- u16 req_id;
- u32 reserved;
- u16 data_size;
-} __attribute__((packed));
-
-#define MEI_NFC_HEADER_SIZE 10
-#define MEI_NFC_MAX_HCI_PAYLOAD 300
-#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
-
-struct microread_mei_phy {
- struct mei_device *mei_device;
- struct nfc_hci_dev *hdev;
-
- int powered;
-
- int hard_fault; /*
- * < 0 if hardware error occured (e.g. i2c err)
- * and prevents normal operation.
- */
-};
-
-#define MEI_DUMP_SKB_IN(info, skb) \
-do { \
- pr_debug("%s:\n", info); \
- print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET, \
- 16, 1, (skb)->data, (skb)->len, 0); \
-} while (0)
-
-#define MEI_DUMP_SKB_OUT(info, skb) \
-do { \
- pr_debug("%s:\n", info); \
- print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET, \
- 16, 1, (skb)->data, (skb)->len, 0); \
-} while (0)
-
-static int microread_mei_enable(void *phy_id)
+static int microread_mei_probe(struct mei_cl_device *device,
+ const struct mei_cl_device_id *id)
{
- struct microread_mei_phy *phy = phy_id;
-
- pr_info(DRIVER_DESC ": %s\n", __func__);
-
- phy->powered = 1;
-
- return 0;
-}
-
-static void microread_mei_disable(void *phy_id)
-{
- struct microread_mei_phy *phy = phy_id;
-
- pr_info(DRIVER_DESC ": %s\n", __func__);
-
- phy->powered = 0;
-}
-
-/*
- * Writing a frame must not return the number of written bytes.
- * It must return either zero for success, or <0 for error.
- * In addition, it must not alter the skb
- */
-static int microread_mei_write(void *phy_id, struct sk_buff *skb)
-{
- struct microread_mei_phy *phy = phy_id;
- int r;
-
- MEI_DUMP_SKB_OUT("mei frame sent", skb);
-
- r = mei_send(phy->device, skb->data, skb->len);
- if (r > 0)
- r = 0;
-
- return r;
-}
-
-static void microread_event_cb(struct mei_device *device, u32 events,
- void *context)
-{
- struct microread_mei_phy *phy = context;
-
- if (phy->hard_fault != 0)
- return;
-
- if (events & BIT(MEI_EVENT_RX)) {
- struct sk_buff *skb;
- int reply_size;
-
- skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
- if (!skb)
- return;
-
- reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
- if (reply_size < MEI_NFC_HEADER_SIZE) {
- kfree(skb);
- return;
- }
-
- skb_put(skb, reply_size);
- skb_pull(skb, MEI_NFC_HEADER_SIZE);
-
- MEI_DUMP_SKB_IN("mei frame read", skb);
-
- nfc_hci_recv_frame(phy->hdev, skb);
- }
-}
-
-static struct nfc_phy_ops mei_phy_ops = {
- .write = microread_mei_write,
- .enable = microread_mei_enable,
- .disable = microread_mei_disable,
-};
-
-static int microread_mei_probe(struct mei_device *device,
- const struct mei_id *id)
-{
- struct microread_mei_phy *phy;
+ struct nfc_mei_phy *phy;
int r;
pr_info("Probing NFC microread\n");
- phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+ phy = nfc_mei_phy_alloc(device);
if (!phy) {
pr_err("Cannot allocate memory for microread mei phy.\n");
return -ENOMEM;
}
- phy->device = device;
- mei_set_clientdata(device, phy);
-
- r = mei_register_event_cb(device, microread_event_cb, phy);
+ r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
if (r) {
pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
goto err_out;
@@ -181,37 +58,35 @@ static int microread_mei_probe(struct mei_device *device,
return 0;
err_out:
- kfree(phy);
+ nfc_mei_phy_free(phy);
return r;
}
-static int microread_mei_remove(struct mei_device *device)
+static int microread_mei_remove(struct mei_cl_device *device)
{
- struct microread_mei_phy *phy = mei_get_clientdata(device);
+ struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
pr_info("Removing microread\n");
microread_remove(phy->hdev);
- if (phy->powered)
- microread_mei_disable(phy);
+ nfc_mei_phy_disable(phy);
- kfree(phy);
+ nfc_mei_phy_free(phy);
return 0;
}
-static struct mei_id microread_mei_tbl[] = {
- { MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+static struct mei_cl_device_id microread_mei_tbl[] = {
+ { MICROREAD_DRIVER_NAME },
/* required last entry */
{ }
};
-
MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
-static struct mei_driver microread_driver = {
+static struct mei_cl_driver microread_driver = {
.id_table = microread_mei_tbl,
.name = MICROREAD_DRIVER_NAME,
@@ -225,7 +100,7 @@ static int microread_mei_init(void)
pr_debug(DRIVER_DESC ": %s\n", __func__);
- r = mei_driver_register(&microread_driver);
+ r = mei_cl_driver_register(&microread_driver);
if (r) {
pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
return r;
@@ -236,7 +111,7 @@ static int microread_mei_init(void)
static void microread_mei_exit(void)
{
- mei_driver_unregister(&microread_driver);
+ mei_cl_driver_unregister(&microread_driver);
}
module_init(microread_mei_init);
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index f0f6763d67ae..8f6f2baa930d 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1,9 +1,6 @@
/*
* Copyright (C) 2011 Instituto Nokia de Tecnologia
- *
- * Authors:
- * Lauro Ramos Venancio <lauro.venancio@openbossa.org>
- * Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ * Copyright (C) 2012-2013 Tieto Poland
*
* 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
@@ -30,7 +27,7 @@
#include <linux/netdevice.h>
#include <net/nfc/nfc.h>
-#define VERSION "0.1"
+#define VERSION "0.2"
#define PN533_VENDOR_ID 0x4CC
#define PN533_PRODUCT_ID 0x2533
@@ -41,8 +38,12 @@
#define SONY_VENDOR_ID 0x054c
#define PASORI_PRODUCT_ID 0x02e1
-#define PN533_DEVICE_STD 0x1
-#define PN533_DEVICE_PASORI 0x2
+#define ACS_VENDOR_ID 0x072f
+#define ACR122U_PRODUCT_ID 0x2200
+
+#define PN533_DEVICE_STD 0x1
+#define PN533_DEVICE_PASORI 0x2
+#define PN533_DEVICE_ACR122U 0x3
#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
@@ -71,6 +72,11 @@ static const struct usb_device_id pn533_table[] = {
.idProduct = PASORI_PRODUCT_ID,
.driver_info = PN533_DEVICE_PASORI,
},
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = ACS_VENDOR_ID,
+ .idProduct = ACR122U_PRODUCT_ID,
+ .driver_info = PN533_DEVICE_ACR122U,
+ },
{ }
};
MODULE_DEVICE_TABLE(usb, pn533_table);
@@ -78,32 +84,47 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
/* How much time we spend listening for initiators */
#define PN533_LISTEN_TIME 2
-/* frame definitions */
-#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+/* Standard pn533 frame definitions */
+#define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \
+ 2) /* data[0] TFI, data[1] CC */
-#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
+#define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
/*
* Max extended frame payload len, excluding TFI and CC
* which are already in PN533_FRAME_HEADER_LEN.
*/
-#define PN533_FRAME_MAX_PAYLOAD_LEN 263
+#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263
-#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+#define PN533_STD_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
Postamble (1) */
-#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
-#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
+#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
+#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
/* start of frame */
-#define PN533_SOF 0x00FF
+#define PN533_STD_FRAME_SOF 0x00FF
+
+/* standard frame identifier: in/out/error */
+#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */
+#define PN533_STD_FRAME_DIR_OUT 0xD4
+#define PN533_STD_FRAME_DIR_IN 0xD5
+
+/* ACS ACR122 pn533 frame definitions */
+#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \
+ + 2)
+#define PN533_ACR122_TX_FRAME_TAIL_LEN 0
+#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \
+ + 2)
+#define PN533_ACR122_RX_FRAME_TAIL_LEN 2
+#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN
+
+/* CCID messages types */
+#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62
+#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B
-/* frame identifier: in/out/error */
-#define PN533_FRAME_IDENTIFIER(f) (f->data[0])
-#define PN533_DIR_OUT 0xD4
-#define PN533_DIR_IN 0xD5
+#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
/* PN533 Commands */
-#define PN533_FRAME_CMD(f) (f->data[1])
+#define PN533_STD_FRAME_CMD(f) (f->data[1])
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
#define PN533_CMD_RF_CONFIGURATION 0x32
@@ -128,8 +149,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
struct pn533;
-typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
-
typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
struct sk_buff *resp);
@@ -144,9 +163,13 @@ struct pn533_fw_version {
};
/* PN533_CMD_RF_CONFIGURATION */
-#define PN533_CFGITEM_TIMING 0x02
+#define PN533_CFGITEM_RF_FIELD 0x01
+#define PN533_CFGITEM_TIMING 0x02
#define PN533_CFGITEM_MAX_RETRIES 0x05
-#define PN533_CFGITEM_PASORI 0x82
+#define PN533_CFGITEM_PASORI 0x82
+
+#define PN533_CFGITEM_RF_FIELD_ON 0x1
+#define PN533_CFGITEM_RF_FIELD_OFF 0x0
#define PN533_CONFIG_TIMING_102 0xb
#define PN533_CONFIG_TIMING_204 0xc
@@ -313,10 +336,17 @@ struct pn533_cmd_jump_dep_response {
#define PN533_INIT_TARGET_RESP_ACTIVE 0x1
#define PN533_INIT_TARGET_RESP_DEP 0x4
+enum pn533_protocol_type {
+ PN533_PROTO_REQ_ACK_RESP = 0,
+ PN533_PROTO_REQ_RESP
+};
+
struct pn533 {
struct usb_device *udev;
struct usb_interface *interface;
struct nfc_dev *nfc_dev;
+ u32 device_type;
+ enum pn533_protocol_type protocol_type;
struct urb *out_urb;
struct urb *in_urb;
@@ -329,21 +359,21 @@ struct pn533 {
struct work_struct poll_work;
struct work_struct mi_work;
struct work_struct tg_work;
- struct timer_list listen_timer;
- int wq_in_error;
- int cancel_listen;
- pn533_cmd_complete_t cmd_complete;
- void *cmd_complete_arg;
+ struct list_head cmd_queue;
+ struct pn533_cmd *cmd;
+ u8 cmd_pending;
+ struct mutex cmd_lock; /* protects cmd queue */
+
void *cmd_complete_mi_arg;
- struct mutex cmd_lock;
- u8 cmd;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
u8 poll_mod_count;
u8 poll_mod_curr;
u32 poll_protocols;
u32 listen_protocols;
+ struct timer_list listen_timer;
+ int cancel_listen;
u8 *gb;
size_t gb_len;
@@ -352,24 +382,21 @@ struct pn533 {
u8 tgt_active_prot;
u8 tgt_mode;
- u32 device_type;
-
- struct list_head cmd_queue;
- u8 cmd_pending;
-
struct pn533_frame_ops *ops;
};
struct pn533_cmd {
struct list_head queue;
- u8 cmd_code;
+ u8 code;
+ int status;
struct sk_buff *req;
struct sk_buff *resp;
int resp_len;
- void *arg;
+ pn533_send_async_complete_t complete_cb;
+ void *complete_cb_context;
};
-struct pn533_frame {
+struct pn533_std_frame {
u8 preamble;
__be16 start_frame;
u8 datalen;
@@ -393,14 +420,124 @@ struct pn533_frame_ops {
u8 (*get_cmd_code)(void *frame);
};
+struct pn533_acr122_ccid_hdr {
+ u8 type;
+ u32 datalen;
+ u8 slot;
+ u8 seq;
+ u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific
+ byte for reposnse msg */
+ u8 data[]; /* payload */
+} __packed;
+
+struct pn533_acr122_apdu_hdr {
+ u8 class;
+ u8 ins;
+ u8 p1;
+ u8 p2;
+} __packed;
+
+struct pn533_acr122_tx_frame {
+ struct pn533_acr122_ccid_hdr ccid;
+ struct pn533_acr122_apdu_hdr apdu;
+ u8 datalen;
+ u8 data[]; /* pn533 frame: TFI ... */
+} __packed;
+
+struct pn533_acr122_rx_frame {
+ struct pn533_acr122_ccid_hdr ccid;
+ u8 data[]; /* pn533 frame : TFI ... */
+} __packed;
+
+static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code)
+{
+ struct pn533_acr122_tx_frame *frame = _frame;
+
+ frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE;
+ frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) +
+ sizeof(datalen) */
+ frame->ccid.slot = 0;
+ frame->ccid.seq = 0;
+ frame->ccid.params[0] = 0;
+ frame->ccid.params[1] = 0;
+ frame->ccid.params[2] = 0;
+
+ frame->data[0] = PN533_STD_FRAME_DIR_OUT;
+ frame->data[1] = cmd_code;
+ frame->datalen = 2; /* data[0] + data[1] */
+
+ frame->apdu.class = 0xFF;
+ frame->apdu.ins = 0;
+ frame->apdu.p1 = 0;
+ frame->apdu.p2 = 0;
+}
+
+static void pn533_acr122_tx_frame_finish(void *_frame)
+{
+ struct pn533_acr122_tx_frame *frame = _frame;
+
+ frame->ccid.datalen += frame->datalen;
+}
+
+static void pn533_acr122_tx_update_payload_len(void *_frame, int len)
+{
+ struct pn533_acr122_tx_frame *frame = _frame;
+
+ frame->datalen += len;
+}
+
+static bool pn533_acr122_is_rx_frame_valid(void *_frame)
+{
+ struct pn533_acr122_rx_frame *frame = _frame;
+
+ if (frame->ccid.type != 0x83)
+ return false;
+
+ if (frame->data[frame->ccid.datalen - 2] == 0x63)
+ return false;
+
+ return true;
+}
+
+static int pn533_acr122_rx_frame_size(void *frame)
+{
+ struct pn533_acr122_rx_frame *f = frame;
+
+ /* f->ccid.datalen already includes tail length */
+ return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen;
+}
+
+static u8 pn533_acr122_get_cmd_code(void *frame)
+{
+ struct pn533_acr122_rx_frame *f = frame;
+
+ return PN533_STD_FRAME_CMD(f);
+}
+
+static struct pn533_frame_ops pn533_acr122_frame_ops = {
+ .tx_frame_init = pn533_acr122_tx_frame_init,
+ .tx_frame_finish = pn533_acr122_tx_frame_finish,
+ .tx_update_payload_len = pn533_acr122_tx_update_payload_len,
+ .tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN,
+ .tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN,
+
+ .rx_is_frame_valid = pn533_acr122_is_rx_frame_valid,
+ .rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN,
+ .rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN,
+ .rx_frame_size = pn533_acr122_rx_frame_size,
+
+ .max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN,
+ .get_cmd_code = pn533_acr122_get_cmd_code,
+};
+
/* The rule: value + checksum = 0 */
-static inline u8 pn533_checksum(u8 value)
+static inline u8 pn533_std_checksum(u8 value)
{
return ~value + 1;
}
/* The rule: sum(data elements) + checksum = 0 */
-static u8 pn533_data_checksum(u8 *data, int datalen)
+static u8 pn533_std_data_checksum(u8 *data, int datalen)
{
u8 sum = 0;
int i;
@@ -408,61 +545,61 @@ static u8 pn533_data_checksum(u8 *data, int datalen)
for (i = 0; i < datalen; i++)
sum += data[i];
- return pn533_checksum(sum);
+ return pn533_std_checksum(sum);
}
-static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
+static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code)
{
- struct pn533_frame *frame = _frame;
+ struct pn533_std_frame *frame = _frame;
frame->preamble = 0;
- frame->start_frame = cpu_to_be16(PN533_SOF);
- PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
- PN533_FRAME_CMD(frame) = cmd_code;
+ frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF);
+ PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT;
+ PN533_STD_FRAME_CMD(frame) = cmd_code;
frame->datalen = 2;
}
-static void pn533_tx_frame_finish(void *_frame)
+static void pn533_std_tx_frame_finish(void *_frame)
{
- struct pn533_frame *frame = _frame;
+ struct pn533_std_frame *frame = _frame;
- frame->datalen_checksum = pn533_checksum(frame->datalen);
+ frame->datalen_checksum = pn533_std_checksum(frame->datalen);
- PN533_FRAME_CHECKSUM(frame) =
- pn533_data_checksum(frame->data, frame->datalen);
+ PN533_STD_FRAME_CHECKSUM(frame) =
+ pn533_std_data_checksum(frame->data, frame->datalen);
- PN533_FRAME_POSTAMBLE(frame) = 0;
+ PN533_STD_FRAME_POSTAMBLE(frame) = 0;
}
-static void pn533_tx_update_payload_len(void *_frame, int len)
+static void pn533_std_tx_update_payload_len(void *_frame, int len)
{
- struct pn533_frame *frame = _frame;
+ struct pn533_std_frame *frame = _frame;
frame->datalen += len;
}
-static bool pn533_rx_frame_is_valid(void *_frame)
+static bool pn533_std_rx_frame_is_valid(void *_frame)
{
u8 checksum;
- struct pn533_frame *frame = _frame;
+ struct pn533_std_frame *frame = _frame;
- if (frame->start_frame != cpu_to_be16(PN533_SOF))
+ if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
return false;
- checksum = pn533_checksum(frame->datalen);
+ checksum = pn533_std_checksum(frame->datalen);
if (checksum != frame->datalen_checksum)
return false;
- checksum = pn533_data_checksum(frame->data, frame->datalen);
- if (checksum != PN533_FRAME_CHECKSUM(frame))
+ checksum = pn533_std_data_checksum(frame->data, frame->datalen);
+ if (checksum != PN533_STD_FRAME_CHECKSUM(frame))
return false;
return true;
}
-static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
+static bool pn533_std_rx_frame_is_ack(struct pn533_std_frame *frame)
{
- if (frame->start_frame != cpu_to_be16(PN533_SOF))
+ if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
return false;
if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
@@ -471,57 +608,51 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
return true;
}
-static inline int pn533_rx_frame_size(void *frame)
+static inline int pn533_std_rx_frame_size(void *frame)
{
- struct pn533_frame *f = frame;
+ struct pn533_std_frame *f = frame;
- return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+ return sizeof(struct pn533_std_frame) + f->datalen +
+ PN533_STD_FRAME_TAIL_LEN;
}
-static u8 pn533_get_cmd_code(void *frame)
+static u8 pn533_std_get_cmd_code(void *frame)
{
- struct pn533_frame *f = frame;
+ struct pn533_std_frame *f = frame;
- return PN533_FRAME_CMD(f);
+ return PN533_STD_FRAME_CMD(f);
}
static struct pn533_frame_ops pn533_std_frame_ops = {
- .tx_frame_init = pn533_tx_frame_init,
- .tx_frame_finish = pn533_tx_frame_finish,
- .tx_update_payload_len = pn533_tx_update_payload_len,
- .tx_header_len = PN533_FRAME_HEADER_LEN,
- .tx_tail_len = PN533_FRAME_TAIL_LEN,
-
- .rx_is_frame_valid = pn533_rx_frame_is_valid,
- .rx_frame_size = pn533_rx_frame_size,
- .rx_header_len = PN533_FRAME_HEADER_LEN,
- .rx_tail_len = PN533_FRAME_TAIL_LEN,
-
- .max_payload_len = PN533_FRAME_MAX_PAYLOAD_LEN,
- .get_cmd_code = pn533_get_cmd_code,
+ .tx_frame_init = pn533_std_tx_frame_init,
+ .tx_frame_finish = pn533_std_tx_frame_finish,
+ .tx_update_payload_len = pn533_std_tx_update_payload_len,
+ .tx_header_len = PN533_STD_FRAME_HEADER_LEN,
+ .tx_tail_len = PN533_STD_FRAME_TAIL_LEN,
+
+ .rx_is_frame_valid = pn533_std_rx_frame_is_valid,
+ .rx_frame_size = pn533_std_rx_frame_size,
+ .rx_header_len = PN533_STD_FRAME_HEADER_LEN,
+ .rx_tail_len = PN533_STD_FRAME_TAIL_LEN,
+
+ .max_payload_len = PN533_STD_FRAME_MAX_PAYLOAD_LEN,
+ .get_cmd_code = pn533_std_get_cmd_code,
};
static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
{
- return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
-}
-
-
-static void pn533_wq_cmd_complete(struct work_struct *work)
-{
- struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
- int rc;
-
- rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
- if (rc != -EINPROGRESS)
- queue_work(dev->wq, &dev->cmd_work);
+ return (dev->ops->get_cmd_code(frame) ==
+ PN533_CMD_RESPONSE(dev->cmd->code));
}
static void pn533_recv_response(struct urb *urb)
{
struct pn533 *dev = urb->context;
+ struct pn533_cmd *cmd = dev->cmd;
u8 *in_frame;
+ cmd->status = urb->status;
+
switch (urb->status) {
case 0:
break; /* success */
@@ -530,37 +661,33 @@ static void pn533_recv_response(struct urb *urb)
nfc_dev_dbg(&dev->interface->dev,
"The urb has been canceled (status %d)",
urb->status);
- dev->wq_in_error = urb->status;
goto sched_wq;
case -ESHUTDOWN:
default:
nfc_dev_err(&dev->interface->dev,
"Urb failure (status %d)", urb->status);
- dev->wq_in_error = urb->status;
goto sched_wq;
}
in_frame = dev->in_urb->transfer_buffer;
nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
- print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
- in_frame, dev->ops->rx_frame_size(in_frame), false);
+ print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame,
+ dev->ops->rx_frame_size(in_frame), false);
if (!dev->ops->rx_is_frame_valid(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
- dev->wq_in_error = -EIO;
+ cmd->status = -EIO;
goto sched_wq;
}
if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
nfc_dev_err(&dev->interface->dev,
"It it not the response to the last command");
- dev->wq_in_error = -EIO;
+ cmd->status = -EIO;
goto sched_wq;
}
- dev->wq_in_error = 0;
-
sched_wq:
queue_work(dev->wq, &dev->cmd_complete_work);
}
@@ -575,9 +702,12 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
static void pn533_recv_ack(struct urb *urb)
{
struct pn533 *dev = urb->context;
- struct pn533_frame *in_frame;
+ struct pn533_cmd *cmd = dev->cmd;
+ struct pn533_std_frame *in_frame;
int rc;
+ cmd->status = urb->status;
+
switch (urb->status) {
case 0:
break; /* success */
@@ -586,21 +716,19 @@ static void pn533_recv_ack(struct urb *urb)
nfc_dev_dbg(&dev->interface->dev,
"The urb has been stopped (status %d)",
urb->status);
- dev->wq_in_error = urb->status;
goto sched_wq;
case -ESHUTDOWN:
default:
nfc_dev_err(&dev->interface->dev,
"Urb failure (status %d)", urb->status);
- dev->wq_in_error = urb->status;
goto sched_wq;
}
in_frame = dev->in_urb->transfer_buffer;
- if (!pn533_rx_frame_is_ack(in_frame)) {
+ if (!pn533_std_rx_frame_is_ack(in_frame)) {
nfc_dev_err(&dev->interface->dev, "Received an invalid ack");
- dev->wq_in_error = -EIO;
+ cmd->status = -EIO;
goto sched_wq;
}
@@ -608,7 +736,7 @@ static void pn533_recv_ack(struct urb *urb)
if (rc) {
nfc_dev_err(&dev->interface->dev,
"usb_submit_urb failed with result %d", rc);
- dev->wq_in_error = rc;
+ cmd->status = rc;
goto sched_wq;
}
@@ -627,7 +755,7 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
{
- u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+ u8 ack[PN533_STD_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
/* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
int rc;
@@ -643,32 +771,34 @@ static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
static int __pn533_send_frame_async(struct pn533 *dev,
struct sk_buff *out,
struct sk_buff *in,
- int in_len,
- pn533_cmd_complete_t cmd_complete,
- void *arg)
+ int in_len)
{
int rc;
- dev->cmd = dev->ops->get_cmd_code(out->data);
- dev->cmd_complete = cmd_complete;
- dev->cmd_complete_arg = arg;
-
dev->out_urb->transfer_buffer = out->data;
dev->out_urb->transfer_buffer_length = out->len;
dev->in_urb->transfer_buffer = in->data;
dev->in_urb->transfer_buffer_length = in_len;
- print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
- out->data, out->len, false);
+ print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+ out->data, out->len, false);
rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
if (rc)
return rc;
- rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
- if (rc)
- goto error;
+ if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
+ /* request for response for sent packet directly */
+ rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
+ if (rc)
+ goto error;
+ } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) {
+ /* request for ACK if that's the case */
+ rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
+ if (rc)
+ goto error;
+ }
return 0;
@@ -693,39 +823,34 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
ops->tx_frame_finish(skb->data);
}
-struct pn533_send_async_complete_arg {
- pn533_send_async_complete_t complete_cb;
- void *complete_cb_context;
- struct sk_buff *resp;
- struct sk_buff *req;
-};
-
-static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
+static int pn533_send_async_complete(struct pn533 *dev)
{
- struct pn533_send_async_complete_arg *arg = _arg;
+ struct pn533_cmd *cmd = dev->cmd;
+ int status = cmd->status;
- struct sk_buff *req = arg->req;
- struct sk_buff *resp = arg->resp;
+ struct sk_buff *req = cmd->req;
+ struct sk_buff *resp = cmd->resp;
int rc;
dev_kfree_skb(req);
if (status < 0) {
- arg->complete_cb(dev, arg->complete_cb_context,
- ERR_PTR(status));
+ rc = cmd->complete_cb(dev, cmd->complete_cb_context,
+ ERR_PTR(status));
dev_kfree_skb(resp);
- kfree(arg);
- return status;
+ goto done;
}
skb_put(resp, dev->ops->rx_frame_size(resp->data));
skb_pull(resp, dev->ops->rx_header_len);
skb_trim(resp, resp->len - dev->ops->rx_tail_len);
- rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+ rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp);
- kfree(arg);
+done:
+ kfree(cmd);
+ dev->cmd = NULL;
return rc;
}
@@ -736,56 +861,45 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
void *complete_cb_context)
{
struct pn533_cmd *cmd;
- struct pn533_send_async_complete_arg *arg;
int rc = 0;
nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
- arg = kzalloc(sizeof(*arg), GFP_KERNEL);
- if (!arg)
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
return -ENOMEM;
- arg->complete_cb = complete_cb;
- arg->complete_cb_context = complete_cb_context;
- arg->resp = resp;
- arg->req = req;
+ cmd->code = cmd_code;
+ cmd->req = req;
+ cmd->resp = resp;
+ cmd->resp_len = resp_len;
+ cmd->complete_cb = complete_cb;
+ cmd->complete_cb_context = complete_cb_context;
pn533_build_cmd_frame(dev, cmd_code, req);
mutex_lock(&dev->cmd_lock);
if (!dev->cmd_pending) {
- rc = __pn533_send_frame_async(dev, req, resp, resp_len,
- pn533_send_async_complete, arg);
+ rc = __pn533_send_frame_async(dev, req, resp, resp_len);
if (rc)
goto error;
dev->cmd_pending = 1;
+ dev->cmd = cmd;
goto unlock;
}
nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
cmd_code);
- cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
- if (!cmd) {
- rc = -ENOMEM;
- goto error;
- }
-
INIT_LIST_HEAD(&cmd->queue);
- cmd->cmd_code = cmd_code;
- cmd->req = req;
- cmd->resp = resp;
- cmd->resp_len = resp_len;
- cmd->arg = arg;
-
list_add_tail(&cmd->queue, &dev->cmd_queue);
goto unlock;
error:
- kfree(arg);
+ kfree(cmd);
unlock:
mutex_unlock(&dev->cmd_lock);
return rc;
@@ -850,8 +964,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
pn533_send_async_complete_t complete_cb,
void *complete_cb_context)
{
- struct pn533_send_async_complete_arg *arg;
struct sk_buff *resp;
+ struct pn533_cmd *cmd;
int rc;
int resp_len = dev->ops->rx_header_len +
dev->ops->max_payload_len +
@@ -861,33 +975,47 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
if (!resp)
return -ENOMEM;
- arg = kzalloc(sizeof(*arg), GFP_KERNEL);
- if (!arg) {
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
dev_kfree_skb(resp);
return -ENOMEM;
}
- arg->complete_cb = complete_cb;
- arg->complete_cb_context = complete_cb_context;
- arg->resp = resp;
- arg->req = req;
+ cmd->code = cmd_code;
+ cmd->req = req;
+ cmd->resp = resp;
+ cmd->resp_len = resp_len;
+ cmd->complete_cb = complete_cb;
+ cmd->complete_cb_context = complete_cb_context;
pn533_build_cmd_frame(dev, cmd_code, req);
- rc = __pn533_send_frame_async(dev, req, resp, resp_len,
- pn533_send_async_complete, arg);
+ rc = __pn533_send_frame_async(dev, req, resp, resp_len);
if (rc < 0) {
dev_kfree_skb(resp);
- kfree(arg);
+ kfree(cmd);
+ } else {
+ dev->cmd = cmd;
}
return rc;
}
+static void pn533_wq_cmd_complete(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
+ int rc;
+
+ rc = pn533_send_async_complete(dev);
+ if (rc != -EINPROGRESS)
+ queue_work(dev->wq, &dev->cmd_work);
+}
+
static void pn533_wq_cmd(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, cmd_work);
struct pn533_cmd *cmd;
+ int rc;
mutex_lock(&dev->cmd_lock);
@@ -903,10 +1031,15 @@ static void pn533_wq_cmd(struct work_struct *work)
mutex_unlock(&dev->cmd_lock);
- __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
- pn533_send_async_complete, cmd->arg);
+ rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len);
+ if (rc < 0) {
+ dev_kfree_skb(cmd->req);
+ dev_kfree_skb(cmd->resp);
+ kfree(cmd);
+ return;
+ }
- kfree(cmd);
+ dev->cmd = cmd;
}
struct pn533_sync_cmd_response {
@@ -982,6 +1115,23 @@ static void pn533_send_complete(struct urb *urb)
}
}
+static void pn533_abort_cmd(struct pn533 *dev, gfp_t flags)
+{
+ /* ACR122U does not support any command which aborts last
+ * issued command i.e. as ACK for standard PN533. Additionally,
+ * it behaves stange, sending broken or incorrect responses,
+ * when we cancel urb before the chip will send response.
+ */
+ if (dev->device_type == PN533_DEVICE_ACR122U)
+ return;
+
+ /* An ack will cancel the last issued command */
+ pn533_send_ack(dev, flags);
+
+ /* cancel the urb request */
+ usb_kill_urb(dev->in_urb);
+}
+
static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
{
struct sk_buff *skb;
@@ -1500,9 +1650,6 @@ static void pn533_listen_mode_timer(unsigned long data)
nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
- /* An ack will cancel the last issued command (poll) */
- pn533_send_ack(dev, GFP_ATOMIC);
-
dev->cancel_listen = 1;
pn533_poll_next_mod(dev);
@@ -1549,6 +1696,11 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
if (!rc)
goto done;
+ if (!dev->poll_mod_count) {
+ nfc_dev_dbg(&dev->interface->dev, "Polling has been stoped.");
+ goto done;
+ }
+
pn533_poll_next_mod(dev);
queue_work(dev->wq, &dev->poll_work);
@@ -1627,7 +1779,7 @@ static void pn533_wq_poll(struct work_struct *work)
if (dev->cancel_listen == 1) {
dev->cancel_listen = 0;
- usb_kill_urb(dev->in_urb);
+ pn533_abort_cmd(dev, GFP_ATOMIC);
}
rc = pn533_send_poll_frame(dev);
@@ -1689,12 +1841,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
return;
}
- /* An ack will cancel the last issued command (poll) */
- pn533_send_ack(dev, GFP_KERNEL);
-
- /* prevent pn533_start_poll_complete to issue a new poll meanwhile */
- usb_kill_urb(dev->in_urb);
-
+ pn533_abort_cmd(dev, GFP_KERNEL);
pn533_poll_reset_mod_list(dev);
}
@@ -1723,6 +1870,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
rsp = (struct pn533_cmd_activate_response *)resp->data;
rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) {
+ nfc_dev_err(&dev->interface->dev,
+ "Target activation failed (error 0x%x)", rc);
dev_kfree_skb(resp);
return -EIO;
}
@@ -1850,7 +1999,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
rc = rsp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev,
- "Bringing DEP link up failed %d", rc);
+ "Bringing DEP link up failed (error 0x%x)", rc);
goto error;
}
@@ -1985,10 +2134,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
pn533_poll_reset_mod_list(dev);
- if (dev->tgt_mode || dev->tgt_active_prot) {
- pn533_send_ack(dev, GFP_KERNEL);
- usb_kill_urb(dev->in_urb);
- }
+ if (dev->tgt_mode || dev->tgt_active_prot)
+ pn533_abort_cmd(dev, GFP_KERNEL);
dev->tgt_active_prot = 0;
dev->tgt_mode = 0;
@@ -2064,8 +2211,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
if (ret != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev,
- "PN533 reported error %d when exchanging data",
- ret);
+ "Exchanging data failed (error 0x%x)", ret);
rc = -EIO;
goto error;
}
@@ -2253,7 +2399,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
"Error %d when trying to perform data_exchange", rc);
dev_kfree_skb(skb);
- kfree(dev->cmd_complete_arg);
+ kfree(dev->cmd_complete_mi_arg);
error:
pn533_send_ack(dev, GFP_KERNEL);
@@ -2310,7 +2456,7 @@ static int pn533_get_firmware_version(struct pn533 *dev,
return 0;
}
-static int pn533_fw_reset(struct pn533 *dev)
+static int pn533_pasori_fw_reset(struct pn533 *dev)
{
struct sk_buff *skb;
struct sk_buff *resp;
@@ -2332,9 +2478,102 @@ static int pn533_fw_reset(struct pn533 *dev)
return 0;
}
+struct pn533_acr122_poweron_rdr_arg {
+ int rc;
+ struct completion done;
+};
+
+static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
+{
+ struct pn533_acr122_poweron_rdr_arg *arg = urb->context;
+
+ nfc_dev_dbg(&urb->dev->dev, "%s", __func__);
+
+ print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
+ urb->transfer_buffer, urb->transfer_buffer_length,
+ false);
+
+ arg->rc = urb->status;
+ complete(&arg->done);
+}
+
+static int pn533_acr122_poweron_rdr(struct pn533 *dev)
+{
+ /* Power on th reader (CCID cmd) */
+ u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON,
+ 0, 0, 0, 0, 0, 0, 3, 0, 0};
+ u8 buf[255];
+ int rc;
+ void *cntx;
+ struct pn533_acr122_poweron_rdr_arg arg;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ init_completion(&arg.done);
+ cntx = dev->in_urb->context; /* backup context */
+
+ dev->in_urb->transfer_buffer = buf;
+ dev->in_urb->transfer_buffer_length = 255;
+ dev->in_urb->complete = pn533_acr122_poweron_rdr_resp;
+ dev->in_urb->context = &arg;
+
+ dev->out_urb->transfer_buffer = cmd;
+ dev->out_urb->transfer_buffer_length = sizeof(cmd);
+
+ print_hex_dump(KERN_ERR, "ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
+ cmd, sizeof(cmd), false);
+
+ rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Reader power on cmd error %d", rc);
+ return rc;
+ }
+
+ rc = usb_submit_urb(dev->in_urb, GFP_KERNEL);
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Can't submit for reader power on cmd response %d",
+ rc);
+ return rc;
+ }
+
+ wait_for_completion(&arg.done);
+ dev->in_urb->context = cntx; /* restore context */
+
+ return arg.rc;
+}
+
+static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf)
+{
+ struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+ u8 rf_field = !!rf;
+ int rc;
+
+ rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD,
+ (u8 *)&rf_field, 1);
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error on setting RF field");
+ return rc;
+ }
+
+ return rc;
+}
+
+int pn533_dev_up(struct nfc_dev *nfc_dev)
+{
+ return pn533_rf_field(nfc_dev, 1);
+}
+
+int pn533_dev_down(struct nfc_dev *nfc_dev)
+{
+ return pn533_rf_field(nfc_dev, 0);
+}
+
static struct nfc_ops pn533_nfc_ops = {
- .dev_up = NULL,
- .dev_down = NULL,
+ .dev_up = pn533_dev_up,
+ .dev_down = pn533_dev_down,
.dep_link_up = pn533_dep_link_up,
.dep_link_down = pn533_dep_link_down,
.start_poll = pn533_start_poll,
@@ -2366,6 +2605,7 @@ static int pn533_setup(struct pn533 *dev)
break;
case PN533_DEVICE_PASORI:
+ case PN533_DEVICE_ACR122U:
max_retries.mx_rty_atr = 0x2;
max_retries.mx_rty_psl = 0x1;
max_retries.mx_rty_passive_act =
@@ -2405,7 +2645,7 @@ static int pn533_setup(struct pn533 *dev)
break;
case PN533_DEVICE_PASORI:
- pn533_fw_reset(dev);
+ pn533_pasori_fw_reset(dev);
rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI,
pasori_cfg, 3);
@@ -2415,7 +2655,7 @@ static int pn533_setup(struct pn533 *dev)
return rc;
}
- pn533_fw_reset(dev);
+ pn533_pasori_fw_reset(dev);
break;
}
@@ -2496,6 +2736,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->ops = &pn533_std_frame_ops;
+ dev->protocol_type = PN533_PROTO_REQ_ACK_RESP;
dev->device_type = id->driver_info;
switch (dev->device_type) {
case PN533_DEVICE_STD:
@@ -2506,6 +2747,20 @@ static int pn533_probe(struct usb_interface *interface,
protocols = PN533_NO_TYPE_B_PROTOCOLS;
break;
+ case PN533_DEVICE_ACR122U:
+ protocols = PN533_NO_TYPE_B_PROTOCOLS;
+ dev->ops = &pn533_acr122_frame_ops;
+ dev->protocol_type = PN533_PROTO_REQ_RESP,
+
+ rc = pn533_acr122_poweron_rdr(dev);
+ if (rc < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Couldn't poweron the reader (error %d)",
+ rc);
+ goto destroy_wq;
+ }
+ break;
+
default:
nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n",
dev->device_type);
@@ -2555,6 +2810,7 @@ destroy_wq:
error:
usb_free_urb(dev->in_urb);
usb_free_urb(dev->out_urb);
+ usb_put_dev(dev->udev);
kfree(dev);
return rc;
}
@@ -2600,8 +2856,9 @@ static struct usb_driver pn533_driver = {
module_usb_driver(pn533_driver);
-MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>,"
- " Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
+MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
+MODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
+MODULE_AUTHOR("Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>");
MODULE_DESCRIPTION("PN533 usb driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/nfc/pn544/Kconfig b/drivers/nfc/pn544/Kconfig
index c277790ac71c..ccf06f5f6ebb 100644
--- a/drivers/nfc/pn544/Kconfig
+++ b/drivers/nfc/pn544/Kconfig
@@ -20,4 +20,15 @@ config NFC_PN544_I2C
Select this if your platform is using the i2c bus.
If you choose to build a module, it'll be called pn544_i2c.
- Say N if unsure. \ No newline at end of file
+ Say N if unsure.
+
+config NFC_PN544_MEI
+ tristate "NFC PN544 MEI support"
+ depends on NFC_PN544 && NFC_MEI_PHY
+ ---help---
+ This module adds support for the mei interface of adapters using
+ NXP pn544 chipsets. Select this if your pn544 chipset
+ is handled by Intel's Management Engine Interface on your platform.
+
+ If you choose to build a module, it'll be called pn544_mei.
+ Say N if unsure.
diff --git a/drivers/nfc/pn544/Makefile b/drivers/nfc/pn544/Makefile
index ac076793687d..29fb5a174036 100644
--- a/drivers/nfc/pn544/Makefile
+++ b/drivers/nfc/pn544/Makefile
@@ -3,6 +3,8 @@
#
pn544_i2c-objs = i2c.o
+pn544_mei-objs = mei.o
obj-$(CONFIG_NFC_PN544) += pn544.o
obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
+obj-$(CONFIG_NFC_PN544_MEI) += pn544_mei.o
diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c
new file mode 100644
index 000000000000..1eb48848a35a
--- /dev/null
+++ b/drivers/nfc/pn544/mei.c
@@ -0,0 +1,121 @@
+/*
+ * HCI based Driver for NXP pn544 NFC Chip
+ *
+ * Copyright (C) 2013 Intel Corporation. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "../mei_phy.h"
+#include "pn544.h"
+
+#define PN544_DRIVER_NAME "pn544"
+
+static int pn544_mei_probe(struct mei_cl_device *device,
+ const struct mei_cl_device_id *id)
+{
+ struct nfc_mei_phy *phy;
+ int r;
+
+ pr_info("Probing NFC pn544\n");
+
+ phy = nfc_mei_phy_alloc(device);
+ if (!phy) {
+ pr_err("Cannot allocate memory for pn544 mei phy.\n");
+ return -ENOMEM;
+ }
+
+ r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
+ if (r) {
+ pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
+ goto err_out;
+ }
+
+ r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
+ MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
+ &phy->hdev);
+ if (r < 0)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ nfc_mei_phy_free(phy);
+
+ return r;
+}
+
+static int pn544_mei_remove(struct mei_cl_device *device)
+{
+ struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
+
+ pr_info("Removing pn544\n");
+
+ pn544_hci_remove(phy->hdev);
+
+ nfc_mei_phy_disable(phy);
+
+ nfc_mei_phy_free(phy);
+
+ return 0;
+}
+
+static struct mei_cl_device_id pn544_mei_tbl[] = {
+ { PN544_DRIVER_NAME },
+
+ /* required last entry */
+ { }
+};
+MODULE_DEVICE_TABLE(mei, pn544_mei_tbl);
+
+static struct mei_cl_driver pn544_driver = {
+ .id_table = pn544_mei_tbl,
+ .name = PN544_DRIVER_NAME,
+
+ .probe = pn544_mei_probe,
+ .remove = pn544_mei_remove,
+};
+
+static int pn544_mei_init(void)
+{
+ int r;
+
+ pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+ r = mei_cl_driver_register(&pn544_driver);
+ if (r) {
+ pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void pn544_mei_exit(void)
+{
+ mei_cl_driver_unregister(&pn544_driver);
+}
+
+module_init(pn544_mei_init);
+module_exit(pn544_mei_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 9c704369eda8..0a2bdd106b23 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -382,6 +382,7 @@ struct device_node *of_get_next_parent(struct device_node *node)
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return parent;
}
+EXPORT_SYMBOL(of_get_next_parent);
/**
* of_get_next_child - Iterate a node childs
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index e3a8b22ef9dd..23049aeca662 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -34,7 +34,10 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
{
struct phy_device *phy;
struct device_node *child;
- int rc, i;
+ const __be32 *paddr;
+ u32 addr;
+ bool is_c45, scanphys = false;
+ int rc, i, len;
/* Mask out all PHYs from auto probing. Instead the PHYs listed in
* the device tree are populated after the bus has been registered */
@@ -54,14 +57,10 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* Loop over the child nodes and register a phy_device for each one */
for_each_available_child_of_node(np, child) {
- const __be32 *paddr;
- u32 addr;
- int len;
- bool is_c45;
-
/* A PHY must have a reg property in the range [0-31] */
paddr = of_get_property(child, "reg", &len);
if (!paddr || len < sizeof(*paddr)) {
+ scanphys = true;
dev_err(&mdio->dev, "%s has invalid PHY address\n",
child->full_name);
continue;
@@ -111,6 +110,59 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
child->name, addr);
}
+ if (!scanphys)
+ return 0;
+
+ /* auto scan for PHYs with empty reg property */
+ for_each_available_child_of_node(np, child) {
+ /* Skip PHYs with reg property set */
+ paddr = of_get_property(child, "reg", &len);
+ if (paddr)
+ continue;
+
+ is_c45 = of_device_is_compatible(child,
+ "ethernet-phy-ieee802.3-c45");
+
+ for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
+ /* skip already registered PHYs */
+ if (mdio->phy_map[addr])
+ continue;
+
+ /* be noisy to encourage people to set reg property */
+ dev_info(&mdio->dev, "scan phy %s at address %i\n",
+ child->name, addr);
+
+ phy = get_phy_device(mdio, addr, is_c45);
+ if (!phy || IS_ERR(phy))
+ continue;
+
+ if (mdio->irq) {
+ mdio->irq[addr] =
+ irq_of_parse_and_map(child, 0);
+ if (!mdio->irq[addr])
+ mdio->irq[addr] = PHY_POLL;
+ }
+
+ /* Associate the OF node with the device structure so it
+ * can be looked up later */
+ of_node_get(child);
+ phy->dev.of_node = child;
+
+ /* All data is now stored in the phy struct;
+ * register it */
+ rc = phy_device_register(phy);
+ if (rc) {
+ phy_device_free(phy);
+ of_node_put(child);
+ continue;
+ }
+
+ dev_info(&mdio->dev, "registered phy %s at address %i\n",
+ child->name, addr);
+ break;
+ }
+ }
+
return 0;
}
EXPORT_SYMBOL(of_mdiobus_register);
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index ee78e0ee6e05..09503b8d12e6 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -244,20 +244,7 @@ static struct platform_driver amiga_parallel_driver = {
},
};
-static int __init amiga_parallel_init(void)
-{
- return platform_driver_probe(&amiga_parallel_driver,
- amiga_parallel_probe);
-}
-
-module_init(amiga_parallel_init);
-
-static void __exit amiga_parallel_exit(void)
-{
- platform_driver_unregister(&amiga_parallel_driver);
-}
-
-module_exit(amiga_parallel_exit);
+module_platform_driver_probe(amiga_parallel_driver, amiga_parallel_probe);
MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
MODULE_DESCRIPTION("Parport Driver for Amiga builtin Port");
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 067ad517c1f5..e9b52e4a4648 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -193,16 +193,4 @@ static struct pcmcia_driver parport_cs_driver = {
.remove = parport_detach,
.id_table = parport_ids,
};
-
-static int __init init_parport_cs(void)
-{
- return pcmcia_register_driver(&parport_cs_driver);
-}
-
-static void __exit exit_parport_cs(void)
-{
- pcmcia_unregister_driver(&parport_cs_driver);
-}
-
-module_init(init_parport_cs);
-module_exit(exit_parport_cs);
+module_pcmcia_driver(parport_cs_driver);
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 050773c36823..a5251cb5fb0c 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -246,14 +246,14 @@ struct parport *parport_gsc_probe_port(unsigned long base,
printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
return NULL;
}
- ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+ ops = kmemdup(&parport_gsc_ops, sizeof(struct parport_operations),
+ GFP_KERNEL);
if (!ops) {
printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
base);
kfree (priv);
return NULL;
}
- memcpy (ops, &parport_gsc_ops, sizeof (struct parport_operations));
priv->ctr = 0xc;
priv->ctr_writable = 0xff;
priv->dma_buf = 0;
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 5c4b6a1db6ca..dffd6d0bd15b 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -284,12 +284,11 @@ static int bpp_probe(struct platform_device *op)
size = resource_size(&op->resource[0]);
dma = PARPORT_DMA_NONE;
- ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
+ ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations),
+ GFP_KERNEL);
if (!ops)
goto out_unmap;
- memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
-
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
goto out_free_ops;
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 3f56bc086cb5..92ed045a5f93 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -476,10 +476,9 @@ int parport_proc_register(struct parport *port)
struct parport_sysctl_table *t;
int i;
- t = kmalloc(sizeof(*t), GFP_KERNEL);
+ t = kmemdup(&parport_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
- memcpy(t, &parport_sysctl_template, sizeof(*t));
t->device_dir[0].extra1 = port;
@@ -523,10 +522,9 @@ int parport_device_proc_register(struct pardevice *device)
struct parport_device_sysctl_table *t;
struct parport * port = device->port;
- t = kmalloc(sizeof(*t), GFP_KERNEL);
+ t = kmemdup(&parport_device_sysctl_template, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return -ENOMEM;
- memcpy(t, &parport_device_sysctl_template, sizeof(*t));
t->dev_dir[0].child = t->parport_dir;
t->parport_dir[0].child = t->port_dir;
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 8647dc6f52d0..748f8f3e9ff5 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -202,20 +202,16 @@ void pci_bus_add_devices(const struct pci_bus *bus)
if (dev->is_added)
continue;
retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "Error adding device (%d)\n",
+ retval);
}
list_for_each_entry(dev, &bus->devices, bus_list) {
BUG_ON(!dev->is_added);
-
child = dev->subordinate;
-
- if (!child)
- continue;
- pci_bus_add_devices(child);
-
- if (child->is_added)
- continue;
- child->is_added = 1;
+ if (child)
+ pci_bus_add_devices(child);
}
}
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 13e9e63a7266..9fcb87f353d4 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -52,15 +52,12 @@ config HOTPLUG_PCI_IBM
When in doubt, say N.
config HOTPLUG_PCI_ACPI
- tristate "ACPI PCI Hotplug driver"
- depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
+ bool "ACPI PCI Hotplug driver"
+ depends on HOTPLUG_PCI=y && ((!ACPI_DOCK && ACPI) || (ACPI_DOCK))
help
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
- To compile this driver as a module, choose M here: the
- module will be called acpiphp.
-
When in doubt, say N.
config HOTPLUG_PCI_ACPI_IBM
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index b70ac00a117e..6fdd49c6f0b9 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -73,8 +73,9 @@ static inline const char *slot_name(struct slot *slot)
*/
struct acpiphp_bridge {
struct list_head list;
+ struct list_head slots;
+ struct kref ref;
acpi_handle handle;
- struct acpiphp_slot *slots;
/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
struct acpiphp_func *func;
@@ -97,7 +98,7 @@ struct acpiphp_bridge {
* PCI slot information for each *physical* PCI slot
*/
struct acpiphp_slot {
- struct acpiphp_slot *next;
+ struct list_head node;
struct acpiphp_bridge *bridge; /* parent */
struct list_head funcs; /* one slot may have different
objects (i.e. for each function) */
@@ -119,7 +120,6 @@ struct acpiphp_slot {
*/
struct acpiphp_func {
struct acpiphp_slot *slot; /* parent */
- struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */
struct list_head sibling;
struct notifier_block nb;
@@ -146,10 +146,6 @@ struct acpiphp_attention_info
#define ACPI_PCI_HOST_HID "PNP0A03"
/* ACPI _STA method value (ignore bit 4; battery present) */
-#define ACPI_STA_PRESENT (0x00000001)
-#define ACPI_STA_ENABLED (0x00000002)
-#define ACPI_STA_SHOW_IN_UI (0x00000004)
-#define ACPI_STA_FUNCTIONING (0x00000008)
#define ACPI_STA_ALL (0x0000000f)
/* bridge flags */
@@ -174,25 +170,24 @@ struct acpiphp_attention_info
/* function prototypes */
/* acpiphp_core.c */
-extern int acpiphp_register_attention(struct acpiphp_attention_info*info);
-extern int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
-extern int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
-extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
+int acpiphp_register_attention(struct acpiphp_attention_info*info);
+int acpiphp_unregister_attention(struct acpiphp_attention_info *info);
+int acpiphp_register_hotplug_slot(struct acpiphp_slot *slot);
+void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
/* acpiphp_glue.c */
-extern int acpiphp_glue_init (void);
-extern void acpiphp_glue_exit (void);
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
-extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
-extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
-extern int acpiphp_eject_slot (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
-extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+int acpiphp_enable_slot(struct acpiphp_slot *slot);
+int acpiphp_disable_slot(struct acpiphp_slot *slot);
+int acpiphp_eject_slot(struct acpiphp_slot *slot);
+u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);
+u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot);
/* variables */
extern bool acpiphp_debug;
+extern bool acpiphp_disabled;
#endif /* _ACPIPHP_H */
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index c2fd3095701f..ca8127950fcd 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
@@ -48,6 +49,7 @@
#define SLOT_NAME_SIZE 21 /* {_SUN} */
bool acpiphp_debug;
+bool acpiphp_disabled;
/* local variables */
static struct acpiphp_attention_info *attention_info;
@@ -60,7 +62,9 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(disable, "disable acpiphp driver");
module_param_named(debug, acpiphp_debug, bool, 0644);
+module_param_named(disable, acpiphp_disabled, bool, 0444);
/* export the attention callback registration methods */
EXPORT_SYMBOL_GPL(acpiphp_register_attention);
@@ -351,27 +355,9 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
}
-static int __init acpiphp_init(void)
+void __init acpiphp_init(void)
{
- info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
- if (acpi_pci_disabled)
- return 0;
-
- /* read all the ACPI info from the system */
- /* initialize internal data structure etc. */
- return acpiphp_glue_init();
-}
-
-
-static void __exit acpiphp_exit(void)
-{
- if (acpi_pci_disabled)
- return;
-
- /* deallocate internal data structures etc. */
- acpiphp_glue_exit();
+ info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
+ acpiphp_disabled ? ", disabled by user; please report a bug"
+ : "");
}
-
-module_init(acpiphp_init);
-module_exit(acpiphp_exit);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 270fdbadc19c..96fed19c6d90 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -54,6 +54,7 @@
#include "acpiphp.h"
static LIST_HEAD(bridge_list);
+static DEFINE_MUTEX(bridge_mutex);
#define MY_NAME "acpiphp_glue"
@@ -61,6 +62,7 @@ static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
+static void free_bridge(struct kref *kref);
/* callback routine to check for the existence of a pci dock device */
static acpi_status
@@ -76,6 +78,39 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
}
}
+static inline void get_bridge(struct acpiphp_bridge *bridge)
+{
+ kref_get(&bridge->ref);
+}
+
+static inline void put_bridge(struct acpiphp_bridge *bridge)
+{
+ kref_put(&bridge->ref, free_bridge);
+}
+
+static void free_bridge(struct kref *kref)
+{
+ struct acpiphp_bridge *bridge;
+ struct acpiphp_slot *slot, *next;
+ struct acpiphp_func *func, *tmp;
+
+ bridge = container_of(kref, struct acpiphp_bridge, ref);
+
+ list_for_each_entry_safe(slot, next, &bridge->slots, node) {
+ list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+ kfree(func);
+ }
+ kfree(slot);
+ }
+
+ /* Release reference acquired by acpiphp_bridge_handle_to_function() */
+ if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)
+ put_bridge(bridge->func->slot->bridge);
+ put_device(&bridge->pci_bus->dev);
+ pci_dev_put(bridge->pci_dev);
+ kfree(bridge);
+}
+
/*
* the _DCK method can do funny things... and sometimes not
* hah-hah funny.
@@ -154,9 +189,10 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_handle tmp;
acpi_status status = AE_OK;
unsigned long long adr, sun;
- int device, function, retval;
+ int device, function, retval, found = 0;
struct pci_bus *pbus = bridge->pci_bus;
struct pci_dev *pdev;
+ u32 val;
if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
@@ -170,7 +206,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
- pdev = pbus->self;
+ pdev = bridge->pci_dev;
if (pdev && device_is_managed_by_native_pciehp(pdev))
return AE_OK;
@@ -178,7 +214,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
if (!newfunc)
return AE_NO_MEMORY;
- INIT_LIST_HEAD(&newfunc->sibling);
newfunc->handle = handle;
newfunc->function = function;
@@ -207,14 +242,15 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
}
/* search for objects that share the same slot */
- for (slot = bridge->slots; slot; slot = slot->next)
+ list_for_each_entry(slot, &bridge->slots, node)
if (slot->device == device) {
if (slot->sun != sun)
warn("sibling found, but _SUN doesn't match!\n");
+ found = 1;
break;
}
- if (!slot) {
+ if (!found) {
slot = kzalloc(sizeof(struct acpiphp_slot), GFP_KERNEL);
if (!slot) {
kfree(newfunc);
@@ -227,9 +263,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
INIT_LIST_HEAD(&slot->funcs);
mutex_init(&slot->crit_sect);
- slot->next = bridge->slots;
- bridge->slots = slot;
-
+ mutex_lock(&bridge_mutex);
+ list_add_tail(&slot->node, &bridge->slots);
+ mutex_unlock(&bridge_mutex);
bridge->nr_slots++;
dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
@@ -247,13 +283,13 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
}
newfunc->slot = slot;
+ mutex_lock(&bridge_mutex);
list_add_tail(&newfunc->sibling, &slot->funcs);
+ mutex_unlock(&bridge_mutex);
- pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
- if (pdev) {
+ if (pci_bus_read_dev_vendor_id(pbus, PCI_DEVFN(device, function),
+ &val, 60*1000))
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
- pci_dev_put(pdev);
- }
if (is_dock_device(handle)) {
/* we don't want to call this device's _EJ0
@@ -290,7 +326,9 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
err_exit:
bridge->nr_slots--;
- bridge->slots = slot->next;
+ mutex_lock(&bridge_mutex);
+ list_del(&slot->node);
+ mutex_unlock(&bridge_mutex);
kfree(slot);
kfree(newfunc);
@@ -315,13 +353,17 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
acpi_status status;
/* must be added to the list prior to calling register_slot */
+ mutex_lock(&bridge_mutex);
list_add(&bridge->list, &bridge_list);
+ mutex_unlock(&bridge_mutex);
/* register all slot objects under this bridge */
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
register_slot, NULL, bridge, NULL);
if (ACPI_FAILURE(status)) {
+ mutex_lock(&bridge_mutex);
list_del(&bridge->list);
+ mutex_unlock(&bridge_mutex);
return;
}
@@ -351,178 +393,46 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle
{
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot;
- struct acpiphp_func *func;
+ struct acpiphp_func *func = NULL;
+ mutex_lock(&bridge_mutex);
list_for_each_entry(bridge, &bridge_list, list) {
- for (slot = bridge->slots; slot; slot = slot->next) {
+ list_for_each_entry(slot, &bridge->slots, node) {
list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->handle == handle)
+ if (func->handle == handle) {
+ get_bridge(func->slot->bridge);
+ mutex_unlock(&bridge_mutex);
return func;
+ }
}
}
}
+ mutex_unlock(&bridge_mutex);
return NULL;
}
-static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
-{
- acpi_handle dummy_handle;
- struct acpiphp_func *func;
-
- if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
- "_EJ0", &dummy_handle))) {
- bridge->flags |= BRIDGE_HAS_EJ0;
-
- dbg("found ejectable p2p bridge\n");
-
- /* make link between PCI bridge and PCI function */
- func = acpiphp_bridge_handle_to_function(bridge->handle);
- if (!func)
- return;
- bridge->func = func;
- func->bridge = bridge;
- }
-}
-
-
-/* allocate and initialize host bridge data structure */
-static void add_host_bridge(struct acpi_pci_root *root)
-{
- struct acpiphp_bridge *bridge;
- acpi_handle handle = root->device->handle;
-
- bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
- if (bridge == NULL)
- return;
-
- bridge->handle = handle;
-
- bridge->pci_bus = root->bus;
-
- init_bridge_misc(bridge);
-}
-
-
-/* allocate and initialize PCI-to-PCI bridge data structure */
-static void add_p2p_bridge(acpi_handle *handle)
-{
- struct acpiphp_bridge *bridge;
-
- bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
- if (bridge == NULL) {
- err("out of memory\n");
- return;
- }
-
- bridge->handle = handle;
- config_p2p_bridge_flags(bridge);
-
- bridge->pci_dev = acpi_get_pci_dev(handle);
- bridge->pci_bus = bridge->pci_dev->subordinate;
- if (!bridge->pci_bus) {
- err("This is not a PCI-to-PCI bridge!\n");
- goto err;
- }
-
- /*
- * Grab a ref to the subordinate PCI bus in case the bus is
- * removed via PCI core logical hotplug. The ref pins the bus
- * (which we access during module unload).
- */
- get_device(&bridge->pci_bus->dev);
-
- init_bridge_misc(bridge);
- return;
- err:
- pci_dev_put(bridge->pci_dev);
- kfree(bridge);
- return;
-}
-
-
-/* callback routine to find P2P bridges */
-static acpi_status
-find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- acpi_status status;
- struct pci_dev *dev;
-
- dev = acpi_get_pci_dev(handle);
- if (!dev || !dev->subordinate)
- goto out;
-
- /* check if this bridge has ejectable slots */
- if ((detect_ejectable_slots(handle) > 0)) {
- dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
- add_p2p_bridge(handle);
- }
-
- /* search P2P bridges under this p2p bridge */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- find_p2p_bridge, NULL, NULL, NULL);
- if (ACPI_FAILURE(status))
- warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
- out:
- pci_dev_put(dev);
- return AE_OK;
-}
-
-
-/* find hot-pluggable slots, and then find P2P bridge */
-static int add_bridge(struct acpi_pci_root *root)
-{
- acpi_status status;
- unsigned long long tmp;
- acpi_handle dummy_handle;
- acpi_handle handle = root->device->handle;
-
- /* if the bridge doesn't have _STA, we assume it is always there */
- status = acpi_get_handle(handle, "_STA", &dummy_handle);
- if (ACPI_SUCCESS(status)) {
- status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
- if (ACPI_FAILURE(status)) {
- dbg("%s: _STA evaluation failure\n", __func__);
- return 0;
- }
- if ((tmp & ACPI_STA_FUNCTIONING) == 0)
- /* don't register this object */
- return 0;
- }
-
- /* check if this bridge has ejectable slots */
- if (detect_ejectable_slots(handle) > 0) {
- dbg("found PCI host-bus bridge with hot-pluggable slots\n");
- add_host_bridge(root);
- }
-
- /* search P2P bridges under this host bridge */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- find_p2p_bridge, NULL, NULL, NULL);
-
- if (ACPI_FAILURE(status))
- warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
-
- return 0;
-}
-
static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
{
struct acpiphp_bridge *bridge;
+ mutex_lock(&bridge_mutex);
list_for_each_entry(bridge, &bridge_list, list)
- if (bridge->handle == handle)
+ if (bridge->handle == handle) {
+ get_bridge(bridge);
+ mutex_unlock(&bridge_mutex);
return bridge;
+ }
+ mutex_unlock(&bridge_mutex);
return NULL;
}
static void cleanup_bridge(struct acpiphp_bridge *bridge)
{
- struct acpiphp_slot *slot, *next;
- struct acpiphp_func *func, *tmp;
+ struct acpiphp_slot *slot;
+ struct acpiphp_func *func;
acpi_status status;
acpi_handle handle = bridge->handle;
@@ -543,10 +453,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
err("failed to install interrupt notify handler\n");
}
- slot = bridge->slots;
- while (slot) {
- next = slot->next;
- list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
+ list_for_each_entry(slot, &bridge->slots, node) {
+ list_for_each_entry(func, &slot->funcs, sibling) {
if (is_dock_device(func->handle)) {
unregister_hotplug_dock_device(func->handle);
unregister_dock_notifier(&func->nb);
@@ -558,63 +466,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
- list_del(&func->sibling);
- kfree(func);
}
acpiphp_unregister_hotplug_slot(slot);
- list_del(&slot->funcs);
- kfree(slot);
- slot = next;
}
- /*
- * Only P2P bridges have a pci_dev
- */
- if (bridge->pci_dev)
- put_device(&bridge->pci_bus->dev);
-
- pci_dev_put(bridge->pci_dev);
+ mutex_lock(&bridge_mutex);
list_del(&bridge->list);
- kfree(bridge);
-}
-
-static acpi_status
-cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- struct acpiphp_bridge *bridge;
-
- /* cleanup p2p bridges under this P2P bridge
- in a depth-first manner */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- cleanup_p2p_bridge, NULL, NULL, NULL);
-
- bridge = acpiphp_handle_to_bridge(handle);
- if (bridge)
- cleanup_bridge(bridge);
-
- return AE_OK;
-}
-
-static void remove_bridge(struct acpi_pci_root *root)
-{
- struct acpiphp_bridge *bridge;
- acpi_handle handle = root->device->handle;
-
- /* cleanup p2p bridges under this host bridge
- in a depth-first manner */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
- (u32)1, cleanup_p2p_bridge, NULL, NULL, NULL);
-
- /*
- * On root bridges with hotplug slots directly underneath (ie,
- * no p2p bridge between), we call cleanup_bridge().
- *
- * The else clause cleans up root bridges that either had no
- * hotplug slots at all, or had a p2p bridge underneath.
- */
- bridge = acpiphp_handle_to_bridge(handle);
- if (bridge)
- cleanup_bridge(bridge);
+ mutex_unlock(&bridge_mutex);
}
static int power_on_slot(struct acpiphp_slot *slot)
@@ -798,6 +656,7 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
}
}
}
+
/**
* enable_device - enable, configure a slot
* @slot: slot to be enabled
@@ -810,9 +669,7 @@ static int __ref enable_device(struct acpiphp_slot *slot)
struct pci_dev *dev;
struct pci_bus *bus = slot->bridge->pci_bus;
struct acpiphp_func *func;
- int retval = 0;
int num, max, pass;
- acpi_status status;
if (slot->flags & SLOT_ENABLED)
goto err_exit;
@@ -867,23 +724,11 @@ static int __ref enable_device(struct acpiphp_slot *slot)
slot->flags &= (~SLOT_ENABLED);
continue;
}
-
- if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
- dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) {
- pci_dev_put(dev);
- continue;
- }
-
- status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
- if (ACPI_FAILURE(status))
- warn("find_p2p_bridge failed (error code = 0x%x)\n",
- status);
- pci_dev_put(dev);
}
err_exit:
- return retval;
+ return 0;
}
/* return first device in slot, acquiring a reference on it */
@@ -912,23 +757,6 @@ static int disable_device(struct acpiphp_slot *slot)
{
struct acpiphp_func *func;
struct pci_dev *pdev;
- struct pci_bus *bus = slot->bridge->pci_bus;
-
- /* The slot will be enabled when func 0 is added, so check
- func 0 before disable the slot. */
- pdev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
- if (!pdev)
- goto err_exit;
- pci_dev_put(pdev);
-
- list_for_each_entry(func, &slot->funcs, sibling) {
- if (func->bridge) {
- /* cleanup p2p bridges under this P2P bridge */
- cleanup_p2p_bridge(func->bridge->handle,
- (u32)1, NULL, NULL);
- func->bridge = NULL;
- }
- }
/*
* enable_device() enumerates all functions in this device via
@@ -947,7 +775,6 @@ static int disable_device(struct acpiphp_slot *slot)
slot->flags &= (~SLOT_ENABLED);
-err_exit:
return 0;
}
@@ -1037,7 +864,7 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
enabled = disabled = 0;
- for (slot = bridge->slots; slot; slot = slot->next) {
+ list_for_each_entry(slot, &bridge->slots, node) {
unsigned int status = get_slot_status(slot);
if (slot->flags & SLOT_ENABLED) {
if (status == ACPI_STA_ALL)
@@ -1082,11 +909,11 @@ static void acpiphp_set_hpp_values(struct pci_bus *bus)
*/
static void acpiphp_sanitize_bus(struct pci_bus *bus)
{
- struct pci_dev *dev;
+ struct pci_dev *dev, *tmp;
int i;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
- list_for_each_entry(dev, &bus->devices, bus_list) {
+ list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
struct resource *res = &dev->resource[i];
if ((res->flags & type_mask) && !res->start &&
@@ -1118,6 +945,7 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
dbg("%s: re-enumerating slots under %s\n",
__func__, objname);
acpiphp_check_bridge(bridge);
+ put_bridge(bridge);
}
return AE_OK ;
}
@@ -1195,6 +1023,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
+ put_bridge(bridge);
}
/**
@@ -1208,6 +1037,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work)
static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
void *context)
{
+ struct acpiphp_bridge *bridge = context;
+
/*
* Currently the code adds all hotplug events to the kacpid_wq
* queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1216,6 +1047,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type,
* For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions.
*/
+ get_bridge(bridge);
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge);
}
@@ -1270,6 +1102,7 @@ static void _handle_hotplug_event_func(struct work_struct *work)
acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_func */
+ put_bridge(func->slot->bridge);
}
/**
@@ -1283,6 +1116,8 @@ static void _handle_hotplug_event_func(struct work_struct *work)
static void handle_hotplug_event_func(acpi_handle handle, u32 type,
void *context)
{
+ struct acpiphp_func *func = context;
+
/*
* Currently the code adds all hotplug events to the kacpid_wq
* queue when it should add hotplug events to the kacpi_hotplug_wq.
@@ -1291,33 +1126,69 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type,
* For now just re-add this work to the kacpi_hotplug_wq so we
* don't deadlock on hotplug actions.
*/
+ get_bridge(func->slot->bridge);
alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func);
}
-static struct acpi_pci_driver acpi_pci_hp_driver = {
- .add = add_bridge,
- .remove = remove_bridge,
-};
-
-/**
- * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures
+/*
+ * Create hotplug slots for the PCI bus.
+ * It should always return 0 to avoid skipping following notifiers.
*/
-int __init acpiphp_glue_init(void)
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle)
{
- acpi_pci_register_driver(&acpi_pci_hp_driver);
+ acpi_handle dummy_handle;
+ struct acpiphp_bridge *bridge;
- return 0;
-}
+ if (acpiphp_disabled)
+ return;
+ if (detect_ejectable_slots(handle) <= 0)
+ return;
-/**
- * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures
- *
- * This function frees all data allocated in acpiphp_glue_init().
- */
-void acpiphp_glue_exit(void)
+ bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
+ if (bridge == NULL) {
+ err("out of memory\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&bridge->slots);
+ kref_init(&bridge->ref);
+ bridge->handle = handle;
+ bridge->pci_dev = pci_dev_get(bus->self);
+ bridge->pci_bus = bus;
+
+ /*
+ * Grab a ref to the subordinate PCI bus in case the bus is
+ * removed via PCI core logical hotplug. The ref pins the bus
+ * (which we access during module unload).
+ */
+ get_device(&bus->dev);
+
+ if (!pci_is_root_bus(bridge->pci_bus) &&
+ ACPI_SUCCESS(acpi_get_handle(bridge->handle,
+ "_EJ0", &dummy_handle))) {
+ dbg("found ejectable p2p bridge\n");
+ bridge->flags |= BRIDGE_HAS_EJ0;
+ bridge->func = acpiphp_bridge_handle_to_function(handle);
+ }
+
+ init_bridge_misc(bridge);
+}
+
+/* Destroy hotplug slots associated with the PCI bus */
+void acpiphp_remove_slots(struct pci_bus *bus)
{
- acpi_pci_unregister_driver(&acpi_pci_hp_driver);
+ struct acpiphp_bridge *bridge, *tmp;
+
+ if (acpiphp_disabled)
+ return;
+
+ list_for_each_entry_safe(bridge, tmp, &bridge_list, list)
+ if (bridge->pci_bus == bus) {
+ cleanup_bridge(bridge);
+ put_bridge(bridge);
+ break;
+ }
}
/**
@@ -1396,7 +1267,7 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
sta = get_slot_status(slot);
- return (sta & ACPI_STA_SHOW_IN_UI) ? 0 : 1;
+ return (sta & ACPI_STA_DEVICE_UI) ? 0 : 1;
}
diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h
index 9fff878cf026..1356211431d0 100644
--- a/drivers/pci/hotplug/cpci_hotplug.h
+++ b/drivers/pci/hotplug/cpci_hotplug.h
@@ -75,28 +75,36 @@ static inline const char *slot_name(struct slot *slot)
return hotplug_slot_name(slot->hotplug_slot);
}
-extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
-extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
-extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
-extern int cpci_hp_unregister_bus(struct pci_bus *bus);
-extern int cpci_hp_start(void);
-extern int cpci_hp_stop(void);
+int cpci_hp_register_controller(struct cpci_hp_controller *controller);
+int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
+int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
+int cpci_hp_unregister_bus(struct pci_bus *bus);
+int cpci_hp_start(void);
+int cpci_hp_stop(void);
/*
* Internal function prototypes, these functions should not be used by
* board/chassis drivers.
*/
-extern u8 cpci_get_attention_status(struct slot *slot);
-extern u8 cpci_get_latch_status(struct slot *slot);
-extern u8 cpci_get_adapter_status(struct slot *slot);
-extern u16 cpci_get_hs_csr(struct slot * slot);
-extern int cpci_set_attention_status(struct slot *slot, int status);
-extern int cpci_check_and_clear_ins(struct slot * slot);
-extern int cpci_check_ext(struct slot * slot);
-extern int cpci_clear_ext(struct slot * slot);
-extern int cpci_led_on(struct slot * slot);
-extern int cpci_led_off(struct slot * slot);
-extern int cpci_configure_slot(struct slot *slot);
-extern int cpci_unconfigure_slot(struct slot *slot);
+u8 cpci_get_attention_status(struct slot *slot);
+u8 cpci_get_latch_status(struct slot *slot);
+u8 cpci_get_adapter_status(struct slot *slot);
+u16 cpci_get_hs_csr(struct slot * slot);
+int cpci_set_attention_status(struct slot *slot, int status);
+int cpci_check_and_clear_ins(struct slot * slot);
+int cpci_check_ext(struct slot * slot);
+int cpci_clear_ext(struct slot * slot);
+int cpci_led_on(struct slot * slot);
+int cpci_led_off(struct slot * slot);
+int cpci_configure_slot(struct slot *slot);
+int cpci_unconfigure_slot(struct slot *slot);
+
+#ifdef CONFIG_HOTPLUG_PCI_CPCI
+int cpci_hotplug_init(int debug);
+void cpci_hotplug_exit(void);
+#else
+static inline int cpci_hotplug_init(int debug) { return 0; }
+static inline void cpci_hotplug_exit(void) { }
+#endif
#endif /* _CPCI_HOTPLUG_H */
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index d8ffc7366801..516b87738b6e 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -404,50 +404,44 @@ struct resource_lists {
/* debugfs functions for the hotplug controller info */
-extern void cpqhp_initialize_debugfs(void);
-extern void cpqhp_shutdown_debugfs(void);
-extern void cpqhp_create_debugfs_files(struct controller *ctrl);
-extern void cpqhp_remove_debugfs_files(struct controller *ctrl);
+void cpqhp_initialize_debugfs(void);
+void cpqhp_shutdown_debugfs(void);
+void cpqhp_create_debugfs_files(struct controller *ctrl);
+void cpqhp_remove_debugfs_files(struct controller *ctrl);
/* controller functions */
-extern void cpqhp_pushbutton_thread(unsigned long event_pointer);
-extern irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
-extern int cpqhp_find_available_resources(struct controller *ctrl,
- void __iomem *rom_start);
-extern int cpqhp_event_start_thread(void);
-extern void cpqhp_event_stop_thread(void);
-extern struct pci_func *cpqhp_slot_create(unsigned char busnumber);
-extern struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
- unsigned char index);
-extern int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func);
-extern int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func);
-extern int cpqhp_hardware_test(struct controller *ctrl, int test_num);
+void cpqhp_pushbutton_thread(unsigned long event_pointer);
+irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data);
+int cpqhp_find_available_resources(struct controller *ctrl,
+ void __iomem *rom_start);
+int cpqhp_event_start_thread(void);
+void cpqhp_event_stop_thread(void);
+struct pci_func *cpqhp_slot_create(unsigned char busnumber);
+struct pci_func *cpqhp_slot_find(unsigned char bus, unsigned char device,
+ unsigned char index);
+int cpqhp_process_SI(struct controller *ctrl, struct pci_func *func);
+int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func);
+int cpqhp_hardware_test(struct controller *ctrl, int test_num);
/* resource functions */
-extern int cpqhp_resource_sort_and_combine (struct pci_resource **head);
+int cpqhp_resource_sort_and_combine (struct pci_resource **head);
/* pci functions */
-extern int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
-extern int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num,
- u8 slot);
-extern int cpqhp_save_config(struct controller *ctrl, int busnumber,
- int is_hot_plug);
-extern int cpqhp_save_base_addr_length(struct controller *ctrl,
- struct pci_func *func);
-extern int cpqhp_save_used_resources(struct controller *ctrl,
- struct pci_func *func);
-extern int cpqhp_configure_board(struct controller *ctrl,
- struct pci_func *func);
-extern int cpqhp_save_slot_config(struct controller *ctrl,
- struct pci_func *new_slot);
-extern int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func);
-extern void cpqhp_destroy_board_resources(struct pci_func *func);
-extern int cpqhp_return_board_resources (struct pci_func *func,
- struct resource_lists *resources);
-extern void cpqhp_destroy_resource_list(struct resource_lists *resources);
-extern int cpqhp_configure_device(struct controller *ctrl,
- struct pci_func *func);
-extern int cpqhp_unconfigure_device(struct pci_func *func);
+int cpqhp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+int cpqhp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num,
+ u8 slot);
+int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug);
+int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func);
+int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func);
+int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func);
+int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot);
+int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func);
+void cpqhp_destroy_board_resources(struct pci_func *func);
+int cpqhp_return_board_resources(struct pci_func *func,
+ struct resource_lists *resources);
+void cpqhp_destroy_resource_list(struct resource_lists *resources);
+int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func);
+int cpqhp_unconfigure_device(struct pci_func *func);
/* Global variables */
extern int cpqhp_debug;
diff --git a/drivers/pci/hotplug/cpqphp_nvram.h b/drivers/pci/hotplug/cpqphp_nvram.h
index e89c0702119d..34e4e54fcf15 100644
--- a/drivers/pci/hotplug/cpqphp_nvram.h
+++ b/drivers/pci/hotplug/cpqphp_nvram.h
@@ -30,26 +30,26 @@
#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM
-static inline void compaq_nvram_init (void __iomem *rom_start)
+static inline void compaq_nvram_init(void __iomem *rom_start)
{
return;
}
-static inline int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
+static inline int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
{
return 0;
}
-static inline int compaq_nvram_store (void __iomem *rom_start)
+static inline int compaq_nvram_store(void __iomem *rom_start)
{
return 0;
}
#else
-extern void compaq_nvram_init (void __iomem *rom_start);
-extern int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl);
-extern int compaq_nvram_store (void __iomem *rom_start);
+void compaq_nvram_init(void __iomem *rom_start);
+int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl);
+int compaq_nvram_store(void __iomem *rom_start);
#endif
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
index a8d391a4957d..8c5b25871d02 100644
--- a/drivers/pci/hotplug/ibmphp.h
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -275,17 +275,17 @@ extern struct list_head ibmphp_slot_head;
* FUNCTION PROTOTYPES *
***********************************************************/
-extern void ibmphp_free_ebda_hpc_queue (void);
-extern int ibmphp_access_ebda (void);
-extern struct slot *ibmphp_get_slot_from_physical_num (u8);
-extern int ibmphp_get_total_hp_slots (void);
-extern void ibmphp_free_ibm_slot (struct slot *);
-extern void ibmphp_free_bus_info_queue (void);
-extern void ibmphp_free_ebda_pci_rsrc_queue (void);
-extern struct bus_info *ibmphp_find_same_bus_num (u32);
-extern int ibmphp_get_bus_index (u8);
-extern u16 ibmphp_get_total_controllers (void);
-extern int ibmphp_register_pci (void);
+void ibmphp_free_ebda_hpc_queue(void);
+int ibmphp_access_ebda(void);
+struct slot *ibmphp_get_slot_from_physical_num(u8);
+int ibmphp_get_total_hp_slots(void);
+void ibmphp_free_ibm_slot(struct slot *);
+void ibmphp_free_bus_info_queue(void);
+void ibmphp_free_ebda_pci_rsrc_queue(void);
+struct bus_info *ibmphp_find_same_bus_num(u32);
+int ibmphp_get_bus_index(u8);
+u16 ibmphp_get_total_controllers(void);
+int ibmphp_register_pci(void);
/* passed parameters */
#define MEM 0
@@ -381,24 +381,24 @@ struct res_needed {
/* functions */
-extern int ibmphp_rsrc_init (void);
-extern int ibmphp_add_resource (struct resource_node *);
-extern int ibmphp_remove_resource (struct resource_node *);
-extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int);
-extern int ibmphp_check_resource (struct resource_node *, u8);
-extern int ibmphp_remove_bus (struct bus_node *, u8);
-extern void ibmphp_free_resources (void);
-extern int ibmphp_add_pfmem_from_mem (struct resource_node *);
-extern struct bus_node *ibmphp_find_res_bus (u8);
-extern void ibmphp_print_test (void); /* for debugging purposes */
+int ibmphp_rsrc_init(void);
+int ibmphp_add_resource(struct resource_node *);
+int ibmphp_remove_resource(struct resource_node *);
+int ibmphp_find_resource(struct bus_node *, u32, struct resource_node **, int);
+int ibmphp_check_resource(struct resource_node *, u8);
+int ibmphp_remove_bus(struct bus_node *, u8);
+void ibmphp_free_resources(void);
+int ibmphp_add_pfmem_from_mem(struct resource_node *);
+struct bus_node *ibmphp_find_res_bus(u8);
+void ibmphp_print_test(void); /* for debugging purposes */
-extern void ibmphp_hpc_initvars (void);
-extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *);
-extern int ibmphp_hpc_writeslot (struct slot *, u8);
-extern void ibmphp_lock_operations (void);
-extern void ibmphp_unlock_operations (void);
-extern int ibmphp_hpc_start_poll_thread (void);
-extern void ibmphp_hpc_stop_poll_thread (void);
+void ibmphp_hpc_initvars(void);
+int ibmphp_hpc_readslot(struct slot *, u8, u8 *);
+int ibmphp_hpc_writeslot(struct slot *, u8);
+void ibmphp_lock_operations(void);
+void ibmphp_unlock_operations(void);
+int ibmphp_hpc_start_poll_thread(void);
+void ibmphp_hpc_stop_poll_thread(void);
//----------------------------------------------------------------------------
@@ -749,11 +749,11 @@ struct controller {
/* Functions */
-extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */
-extern int ibmphp_do_disable_slot (struct slot *slot_cur);
-extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */
-extern int ibmphp_configure_card (struct pci_func *, u8);
-extern int ibmphp_unconfigure_card (struct slot **, int);
+int ibmphp_init_devno(struct slot **); /* This function is called from EBDA, so we need it not be static */
+int ibmphp_do_disable_slot(struct slot *slot_cur);
+int ibmphp_update_slot_info(struct slot *); /* This function is called from HPC, so we need it to not be be static */
+int ibmphp_configure_card(struct pci_func *, u8);
+int ibmphp_unconfigure_card(struct slot **, int);
extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
#endif //__IBMPHP_H
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index 202f4a969eb5..ec20f74c8981 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -41,6 +41,7 @@
#include <linux/pci_hotplug.h>
#include <asm/uaccess.h>
#include "../pci.h"
+#include "cpci_hotplug.h"
#define MY_NAME "pci_hotplug"
@@ -63,14 +64,6 @@ static bool debug;
static LIST_HEAD(pci_hotplug_slot_list);
static DEFINE_MUTEX(pci_hp_mutex);
-#ifdef CONFIG_HOTPLUG_PCI_CPCI
-extern int cpci_hotplug_init(int debug);
-extern void cpci_hotplug_exit(void);
-#else
-static inline int cpci_hotplug_init(int debug) { return 0; }
-static inline void cpci_hotplug_exit(void) { }
-#endif
-
/* Weee, fun with macros... */
#define GET_STATUS(name,type) \
static int get_##name (struct hotplug_slot *slot, type *value) \
@@ -524,13 +517,11 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)
*
* Returns 0 if successful, anything else for an error.
*/
-int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
- struct hotplug_slot_info *info)
+int pci_hp_change_slot_info(struct hotplug_slot *hotplug,
+ struct hotplug_slot_info *info)
{
- struct pci_slot *slot;
if (!hotplug || !info)
return -ENODEV;
- slot = hotplug->pci_slot;
memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 2c113de94323..7fb326983ed6 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -127,15 +127,15 @@ struct controller {
#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS)
#define PSN(ctrl) ((ctrl)->slot_cap >> 19)
-extern int pciehp_sysfs_enable_slot(struct slot *slot);
-extern int pciehp_sysfs_disable_slot(struct slot *slot);
-extern u8 pciehp_handle_attention_button(struct slot *p_slot);
-extern u8 pciehp_handle_switch_change(struct slot *p_slot);
-extern u8 pciehp_handle_presence_change(struct slot *p_slot);
-extern u8 pciehp_handle_power_fault(struct slot *p_slot);
-extern int pciehp_configure_device(struct slot *p_slot);
-extern int pciehp_unconfigure_device(struct slot *p_slot);
-extern void pciehp_queue_pushbutton_work(struct work_struct *work);
+int pciehp_sysfs_enable_slot(struct slot *slot);
+int pciehp_sysfs_disable_slot(struct slot *slot);
+u8 pciehp_handle_attention_button(struct slot *p_slot);
+u8 pciehp_handle_switch_change(struct slot *p_slot);
+u8 pciehp_handle_presence_change(struct slot *p_slot);
+u8 pciehp_handle_power_fault(struct slot *p_slot);
+int pciehp_configure_device(struct slot *p_slot);
+int pciehp_unconfigure_device(struct slot *p_slot);
+void pciehp_queue_pushbutton_work(struct work_struct *work);
struct controller *pcie_init(struct pcie_device *dev);
int pcie_init_notification(struct controller *ctrl);
int pciehp_enable_slot(struct slot *p_slot);
@@ -166,8 +166,8 @@ static inline const char *slot_name(struct slot *slot)
#include <acpi/acpi_bus.h>
#include <linux/pci-acpi.h>
-extern void __init pciehp_acpi_slot_detection_init(void);
-extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
+void __init pciehp_acpi_slot_detection_init(void);
+int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
static inline void pciehp_firmware_init(void)
{
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index 24d709b7388c..ead7c534095e 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -90,7 +90,7 @@ static int __init dummy_probe(struct pcie_device *dev)
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
return -ENOMEM;
- slot->number = slot_cap >> 19;
+ slot->number = (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19;
list_for_each_entry(tmp, &dummy_slots, list) {
if (tmp->number == slot->number)
dup_slot_id++;
diff --git a/drivers/pci/hotplug/rpadlpar.h b/drivers/pci/hotplug/rpadlpar.h
index 4a0a59b82eae..81df93931ad0 100644
--- a/drivers/pci/hotplug/rpadlpar.h
+++ b/drivers/pci/hotplug/rpadlpar.h
@@ -15,10 +15,10 @@
#ifndef _RPADLPAR_IO_H_
#define _RPADLPAR_IO_H_
-extern int dlpar_sysfs_init(void);
-extern void dlpar_sysfs_exit(void);
+int dlpar_sysfs_init(void);
+void dlpar_sysfs_exit(void);
-extern int dlpar_add_slot(char *drc_name);
-extern int dlpar_remove_slot(char *drc_name);
+int dlpar_add_slot(char *drc_name);
+int dlpar_remove_slot(char *drc_name);
#endif
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index df5677440a08..3135856e5e1c 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -86,18 +86,18 @@ extern struct list_head rpaphp_slot_head;
/* function prototypes */
/* rpaphp_pci.c */
-extern int rpaphp_enable_slot(struct slot *slot);
-extern int rpaphp_get_sensor_state(struct slot *slot, int *state);
+int rpaphp_enable_slot(struct slot *slot);
+int rpaphp_get_sensor_state(struct slot *slot, int *state);
/* rpaphp_core.c */
-extern int rpaphp_add_slot(struct device_node *dn);
-extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
+int rpaphp_add_slot(struct device_node *dn);
+int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
char **drc_name, char **drc_type, int *drc_power_domain);
/* rpaphp_slot.c */
-extern void dealloc_slot_struct(struct slot *slot);
-extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
-extern int rpaphp_register_slot(struct slot *slot);
-extern int rpaphp_deregister_slot(struct slot *slot);
+void dealloc_slot_struct(struct slot *slot);
+struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
+int rpaphp_register_slot(struct slot *slot);
+int rpaphp_deregister_slot(struct slot *slot);
#endif /* _PPC64PHP_H */
diff --git a/drivers/pci/hotplug/s390_pci_hpc.c b/drivers/pci/hotplug/s390_pci_hpc.c
index 7db249a25016..46a7b738f61f 100644
--- a/drivers/pci/hotplug/s390_pci_hpc.c
+++ b/drivers/pci/hotplug/s390_pci_hpc.c
@@ -16,6 +16,7 @@
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/init.h>
+#include <asm/pci_debug.h>
#include <asm/sclp.h>
#define SLOT_NAME_SIZE 10
@@ -49,6 +50,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return -EIO;
rc = sclp_pci_configure(slot->zdev->fid);
+ zpci_dbg(3, "conf fid:%x, rc:%d\n", slot->zdev->fid, rc);
if (!rc) {
slot->zdev->state = ZPCI_FN_STATE_CONFIGURED;
/* automatically scan the device after is was configured */
@@ -66,16 +68,16 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
if (!zpci_fn_configured(slot->zdev->state))
return -EIO;
+ rc = zpci_disable_device(slot->zdev);
+ if (rc)
+ return rc;
/* TODO: we rely on the user to unbind/remove the device, is that plausible
* or do we need to trigger that here?
*/
rc = sclp_pci_deconfigure(slot->zdev->fid);
- if (!rc) {
- /* Fixme: better call List-PCI to find the disabled FH
- for the FID since the FH should be opaque... */
- slot->zdev->fh &= 0x7fffffff;
+ zpci_dbg(3, "deconf fid:%x, rc:%d\n", slot->zdev->fid, rc);
+ if (!rc)
slot->zdev->state = ZPCI_FN_STATE_STANDBY;
- }
return rc;
}
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index b849f995075a..e260f207a90e 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -168,19 +168,19 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
-extern void shpchp_remove_ctrl_files(struct controller *ctrl);
-extern int shpchp_sysfs_enable_slot(struct slot *slot);
-extern int shpchp_sysfs_disable_slot(struct slot *slot);
-extern u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
-extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
-extern int shpchp_configure_device(struct slot *p_slot);
-extern int shpchp_unconfigure_device(struct slot *p_slot);
-extern void cleanup_slots(struct controller *ctrl);
-extern void shpchp_queue_pushbutton_work(struct work_struct *work);
-extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
+int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
+void shpchp_remove_ctrl_files(struct controller *ctrl);
+int shpchp_sysfs_enable_slot(struct slot *slot);
+int shpchp_sysfs_disable_slot(struct slot *slot);
+u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+int shpchp_configure_device(struct slot *p_slot);
+int shpchp_unconfigure_device(struct slot *p_slot);
+void cleanup_slots(struct controller *ctrl);
+void shpchp_queue_pushbutton_work(struct work_struct *work);
+int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
static inline const char *slot_name(struct slot *slot)
{
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index eeb23ceae4a8..e8c31fe20566 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -85,7 +85,7 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
-int __must_check shpchp_create_ctrl_files (struct controller *ctrl)
+int shpchp_create_ctrl_files (struct controller *ctrl)
{
return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
}
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index ee599f274f05..c93071d428f5 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -729,6 +729,47 @@ int pci_num_vf(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_num_vf);
/**
+ * pci_vfs_assigned - returns number of VFs are assigned to a guest
+ * @dev: the PCI device
+ *
+ * Returns number of VFs belonging to this device that are assigned to a guest.
+ * If device is not a physical function returns -ENODEV.
+ */
+int pci_vfs_assigned(struct pci_dev *dev)
+{
+ struct pci_dev *vfdev;
+ unsigned int vfs_assigned = 0;
+ unsigned short dev_id;
+
+ /* only search if we are a PF */
+ if (!dev->is_physfn)
+ return 0;
+
+ /*
+ * determine the device ID for the VFs, the vendor ID will be the
+ * same as the PF so there is no need to check for that one
+ */
+ pci_read_config_word(dev, dev->sriov->pos + PCI_SRIOV_VF_DID, &dev_id);
+
+ /* loop through all the VFs to see if we own any that are assigned */
+ vfdev = pci_get_device(dev->vendor, dev_id, NULL);
+ while (vfdev) {
+ /*
+ * It is considered assigned if it is a virtual function with
+ * our dev as the physical function and the assigned bit is set
+ */
+ if (vfdev->is_virtfn && (vfdev->physfn == dev) &&
+ (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED))
+ vfs_assigned++;
+
+ vfdev = pci_get_device(dev->vendor, dev_id, vfdev);
+ }
+
+ return vfs_assigned;
+}
+EXPORT_SYMBOL_GPL(pci_vfs_assigned);
+
+/**
* pci_sriov_set_totalvfs -- reduce the TotalVFs available
* @dev: the PCI PF device
* @numvfs: number that should be used for TotalVFs supported
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 00cc78c7aa04..d40bed726769 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -22,10 +22,12 @@
#include <linux/slab.h>
#include "pci.h"
-#include "msi.h"
static int pci_msi_enable = 1;
+#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
+
+
/* Arch hooks */
#ifndef arch_msi_check_device
@@ -111,32 +113,26 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq)
}
#endif
-static void msi_set_enable(struct pci_dev *dev, int pos, int enable)
+static void msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
- BUG_ON(!pos);
-
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
- pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static void msix_set_enable(struct pci_dev *dev, int enable)
{
- int pos;
u16 control;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos) {
- pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
- control &= ~PCI_MSIX_FLAGS_ENABLE;
- if (enable)
- control |= PCI_MSIX_FLAGS_ENABLE;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
- }
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+ control &= ~PCI_MSIX_FLAGS_ENABLE;
+ if (enable)
+ control |= PCI_MSIX_FLAGS_ENABLE;
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
}
static inline __attribute_const__ u32 msi_mask(unsigned x)
@@ -247,18 +243,18 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
msg->data = readl(base + PCI_MSIX_ENTRY_DATA);
} else {
struct pci_dev *dev = entry->dev;
- int pos = entry->msi_attrib.pos;
+ int pos = dev->msi_cap;
u16 data;
- pci_read_config_dword(dev, msi_lower_address_reg(pos),
- &msg->address_lo);
+ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+ &msg->address_lo);
if (entry->msi_attrib.is_64) {
- pci_read_config_dword(dev, msi_upper_address_reg(pos),
- &msg->address_hi);
- pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+ &msg->address_hi);
+ pci_read_config_word(dev, pos + PCI_MSI_DATA_64, &data);
} else {
msg->address_hi = 0;
- pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
+ pci_read_config_word(dev, pos + PCI_MSI_DATA_32, &data);
}
msg->data = data;
}
@@ -302,24 +298,24 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
writel(msg->data, base + PCI_MSIX_ENTRY_DATA);
} else {
struct pci_dev *dev = entry->dev;
- int pos = entry->msi_attrib.pos;
+ int pos = dev->msi_cap;
u16 msgctl;
- pci_read_config_word(dev, msi_control_reg(pos), &msgctl);
+ pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
msgctl &= ~PCI_MSI_FLAGS_QSIZE;
msgctl |= entry->msi_attrib.multiple << 4;
- pci_write_config_word(dev, msi_control_reg(pos), msgctl);
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
- pci_write_config_dword(dev, msi_lower_address_reg(pos),
- msg->address_lo);
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+ msg->address_lo);
if (entry->msi_attrib.is_64) {
- pci_write_config_dword(dev, msi_upper_address_reg(pos),
- msg->address_hi);
- pci_write_config_word(dev, msi_data_reg(pos, 1),
- msg->data);
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+ msg->address_hi);
+ pci_write_config_word(dev, pos + PCI_MSI_DATA_64,
+ msg->data);
} else {
- pci_write_config_word(dev, msi_data_reg(pos, 0),
- msg->data);
+ pci_write_config_word(dev, pos + PCI_MSI_DATA_32,
+ msg->data);
}
}
entry->msg = *msg;
@@ -391,7 +387,6 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
static void __pci_restore_msi_state(struct pci_dev *dev)
{
- int pos;
u16 control;
struct msi_desc *entry;
@@ -399,22 +394,20 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
return;
entry = irq_get_msi_desc(dev->irq);
- pos = entry->msi_attrib.pos;
pci_intx_for_msi(dev, 0);
- msi_set_enable(dev, pos, 0);
+ msi_set_enable(dev, 0);
arch_restore_msi_irqs(dev, dev->irq);
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
control &= ~PCI_MSI_FLAGS_QSIZE;
control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
- pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static void __pci_restore_msix_state(struct pci_dev *dev)
{
- int pos;
struct msi_desc *entry;
u16 control;
@@ -422,13 +415,12 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
return;
BUG_ON(list_empty(&dev->msi_list));
entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
- pos = entry->msi_attrib.pos;
- pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
/* route the table */
pci_intx_for_msi(dev, 0);
control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
list_for_each_entry(entry, &dev->msi_list, list) {
arch_restore_msi_irqs(dev, entry->irq);
@@ -436,7 +428,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
}
control &= ~PCI_MSIX_FLAGS_MASKALL;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
}
void pci_restore_msi_state(struct pci_dev *dev)
@@ -484,12 +476,12 @@ static struct msi_attribute mode_attribute =
__ATTR(mode, S_IRUGO, show_msi_mode, NULL);
-struct attribute *msi_irq_default_attrs[] = {
+static struct attribute *msi_irq_default_attrs[] = {
&mode_attribute.attr,
NULL
};
-void msi_kobj_release(struct kobject *kobj)
+static void msi_kobj_release(struct kobject *kobj)
{
struct msi_desc *entry = to_msi_desc(kobj);
@@ -552,27 +544,27 @@ out_unroll:
static int msi_capability_init(struct pci_dev *dev, int nvec)
{
struct msi_desc *entry;
- int pos, ret;
+ int ret;
u16 control;
unsigned mask;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- msi_set_enable(dev, pos, 0); /* Disable MSI during set up */
+ msi_set_enable(dev, 0); /* Disable MSI during set up */
- pci_read_config_word(dev, msi_control_reg(pos), &control);
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
/* MSI Entry Initialization */
entry = alloc_msi_entry(dev);
if (!entry)
return -ENOMEM;
entry->msi_attrib.is_msix = 0;
- entry->msi_attrib.is_64 = is_64bit_address(control);
+ entry->msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
entry->msi_attrib.entry_nr = 0;
- entry->msi_attrib.maskbit = is_mask_bit_support(control);
+ entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT);
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
- entry->msi_attrib.pos = pos;
+ entry->msi_attrib.pos = dev->msi_cap;
- entry->mask_pos = msi_mask_reg(pos, entry->msi_attrib.is_64);
+ entry->mask_pos = dev->msi_cap + (control & PCI_MSI_FLAGS_64BIT) ?
+ PCI_MSI_MASK_64 : PCI_MSI_MASK_32;
/* All MSIs are unmasked by default, Mask them all */
if (entry->msi_attrib.maskbit)
pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
@@ -598,31 +590,30 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
/* Set MSI enabled bits */
pci_intx_for_msi(dev, 0);
- msi_set_enable(dev, pos, 1);
+ msi_set_enable(dev, 1);
dev->msi_enabled = 1;
dev->irq = entry->irq;
return 0;
}
-static void __iomem *msix_map_region(struct pci_dev *dev, unsigned pos,
- unsigned nr_entries)
+static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
{
resource_size_t phys_addr;
u32 table_offset;
u8 bir;
- pci_read_config_dword(dev, msix_table_offset_reg(pos), &table_offset);
- bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK);
- table_offset &= ~PCI_MSIX_FLAGS_BIRMASK;
+ pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
+ &table_offset);
+ bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
+ table_offset &= PCI_MSIX_TABLE_OFFSET;
phys_addr = pci_resource_start(dev, bir) + table_offset;
return ioremap_nocache(phys_addr, nr_entries * PCI_MSIX_ENTRY_SIZE);
}
-static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
- void __iomem *base, struct msix_entry *entries,
- int nvec)
+static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
+ struct msix_entry *entries, int nvec)
{
struct msi_desc *entry;
int i;
@@ -642,7 +633,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = entries[i].entry;
entry->msi_attrib.default_irq = dev->irq;
- entry->msi_attrib.pos = pos;
+ entry->msi_attrib.pos = dev->msix_cap;
entry->mask_base = base;
list_add_tail(&entry->list, &dev->msi_list);
@@ -652,7 +643,7 @@ static int msix_setup_entries(struct pci_dev *dev, unsigned pos,
}
static void msix_program_entries(struct pci_dev *dev,
- struct msix_entry *entries)
+ struct msix_entry *entries)
{
struct msi_desc *entry;
int i = 0;
@@ -682,23 +673,22 @@ static void msix_program_entries(struct pci_dev *dev,
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- int pos, ret;
+ int ret;
u16 control;
void __iomem *base;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
/* Ensure MSI-X is disabled while it is set up */
control &= ~PCI_MSIX_FLAGS_ENABLE;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
/* Request & Map MSI-X table region */
- base = msix_map_region(dev, pos, multi_msix_capable(control));
+ base = msix_map_region(dev, msix_table_size(control));
if (!base)
return -ENOMEM;
- ret = msix_setup_entries(dev, pos, base, entries, nvec);
+ ret = msix_setup_entries(dev, base, entries, nvec);
if (ret)
return ret;
@@ -712,7 +702,7 @@ static int msix_capability_init(struct pci_dev *dev,
* interrupts coming in before they're fully set up.
*/
control |= PCI_MSIX_FLAGS_MASKALL | PCI_MSIX_FLAGS_ENABLE;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
msix_program_entries(dev, entries);
@@ -727,7 +717,7 @@ static int msix_capability_init(struct pci_dev *dev,
dev->msix_enabled = 1;
control &= ~PCI_MSIX_FLAGS_MASKALL;
- pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
+ pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
return 0;
@@ -795,9 +785,6 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
if (ret)
return ret;
- if (!pci_find_capability(dev, type))
- return -EINVAL;
-
return 0;
}
@@ -816,13 +803,13 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
*/
int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
{
- int status, pos, maxvec;
+ int status, maxvec;
u16 msgctl;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (!pos)
+ if (!dev->msi_cap)
return -EINVAL;
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
if (nvec > maxvec)
return maxvec;
@@ -847,14 +834,13 @@ EXPORT_SYMBOL(pci_enable_msi_block);
int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
{
- int ret, pos, nvec;
+ int ret, nvec;
u16 msgctl;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (!pos)
+ if (!dev->msi_cap)
return -EINVAL;
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
if (maxvec)
@@ -876,21 +862,19 @@ void pci_msi_shutdown(struct pci_dev *dev)
struct msi_desc *desc;
u32 mask;
u16 ctrl;
- unsigned pos;
if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
BUG_ON(list_empty(&dev->msi_list));
desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
- pos = desc->msi_attrib.pos;
- msi_set_enable(dev, pos, 0);
+ msi_set_enable(dev, 0);
pci_intx_for_msi(dev, 1);
dev->msi_enabled = 0;
/* Return the device with MSI unmasked as initial states */
- pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &ctrl);
+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
mask = msi_capable_mask(ctrl);
/* Keep cached state to be restored */
__msi_mask_irq(desc, mask, ~mask);
@@ -917,15 +901,13 @@ EXPORT_SYMBOL(pci_disable_msi);
*/
int pci_msix_table_size(struct pci_dev *dev)
{
- int pos;
u16 control;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (!pos)
+ if (!dev->msix_cap)
return 0;
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- return multi_msix_capable(control);
+ pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
+ return msix_table_size(control);
}
/**
@@ -948,7 +930,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
int status, nr_entries;
int i, j;
- if (!entries)
+ if (!entries || !dev->msix_cap)
return -EINVAL;
status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
@@ -1048,15 +1030,17 @@ EXPORT_SYMBOL(pci_msi_enabled);
void pci_msi_init_pci_dev(struct pci_dev *dev)
{
- int pos;
INIT_LIST_HEAD(&dev->msi_list);
/* Disable the msi hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos)
- msi_set_enable(dev, pos, 0);
- msix_set_enable(dev, 0);
+ dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
+ if (dev->msi_cap)
+ msi_set_enable(dev, 0);
+
+ dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
+ if (dev->msix_cap)
+ msix_set_enable(dev, 0);
}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
deleted file mode 100644
index 65c42f80f23e..000000000000
--- a/drivers/pci/msi.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef MSI_H
-#define MSI_H
-
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
-#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
-#define msi_data_reg(base, is64bit) \
- (base + ((is64bit == 1) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32))
-#define msi_mask_reg(base, is64bit) \
- (base + ((is64bit == 1) ? PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
-#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
-#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
-
-#define msix_table_offset_reg(base) (base + PCI_MSIX_TABLE)
-#define msix_pba_offset_reg(base) (base + PCI_MSIX_PBA)
-#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1)
-#define multi_msix_capable(control) msix_table_size((control))
-
-#endif /* MSI_H */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index dee5dddaa292..e4b1fb2c0f5d 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -53,14 +53,15 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
return;
}
- if (!pci_dev->pm_cap || !pci_dev->pme_support
- || pci_check_pme_status(pci_dev)) {
- if (pci_dev->pme_poll)
- pci_dev->pme_poll = false;
+ /* Clear PME Status if set. */
+ if (pci_dev->pme_support)
+ pci_check_pme_status(pci_dev);
- pci_wakeup_event(pci_dev);
- pm_runtime_resume(&pci_dev->dev);
- }
+ if (pci_dev->pme_poll)
+ pci_dev->pme_poll = false;
+
+ pci_wakeup_event(pci_dev);
+ pm_runtime_resume(&pci_dev->dev);
if (pci_dev->subordinate)
pci_pme_wakeup_bus(pci_dev->subordinate);
@@ -287,6 +288,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
.run_wake = acpi_pci_run_wake,
};
+void acpi_pci_add_bus(struct pci_bus *bus)
+{
+ acpi_handle handle = NULL;
+
+ if (bus->bridge)
+ handle = ACPI_HANDLE(bus->bridge);
+ if (acpi_pci_disabled || handle == NULL)
+ return;
+
+ acpi_pci_slot_enumerate(bus, handle);
+ acpiphp_enumerate_slots(bus, handle);
+}
+
+void acpi_pci_remove_bus(struct pci_bus *bus)
+{
+ /*
+ * bus->bridge->acpi_node.handle has already been reset to NULL
+ * when acpi_pci_remove_bus() is called, so don't check ACPI handle.
+ */
+ if (acpi_pci_disabled)
+ return;
+
+ acpiphp_remove_slots(bus);
+ acpi_pci_slot_remove(bus);
+}
+
/* ACPI bus type */
static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
{
@@ -361,7 +388,11 @@ static int __init acpi_pci_init(void)
ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
+
pci_set_platform_pm(&acpi_pci_platform_pm);
+ acpi_pci_slot_init();
+ acpiphp_init();
+
return 0;
}
arch_initcall(acpi_pci_init);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 1fa1e482a999..79277fb36c6b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -390,9 +390,10 @@ static void pci_device_shutdown(struct device *dev)
/*
* Turn off Bus Master bit on the device to tell it to not
- * continue to do DMA
+ * continue to do DMA. Don't touch devices in D3cold or unknown states.
*/
- pci_clear_master(pci_dev);
+ if (pci_dev->current_state <= PCI_D3hot)
+ pci_clear_master(pci_dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9c6e9bb674ec..5b4a9d9cd200 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -897,7 +897,7 @@ int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
if (pci_resource_len(pdev, resno) == 0)
return 0;
- nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ nr = vma_pages(vma);
start = vma->vm_pgoff;
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
pci_start = (mmap_api == PCI_MMAP_PROCFS) ?
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b099e0025d2b..a899d8bb190d 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -646,15 +646,11 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
error = platform_pci_set_power_state(dev, state);
if (!error)
pci_update_current_state(dev, state);
- /* Fall back to PCI_D0 if native PM is not supported */
- if (!dev->pm_cap)
- dev->current_state = PCI_D0;
- } else {
+ } else
error = -ENODEV;
- /* Fall back to PCI_D0 if native PM is not supported */
- if (!dev->pm_cap)
- dev->current_state = PCI_D0;
- }
+
+ if (error && !dev->pm_cap) /* Fall back to PCI_D0 */
+ dev->current_state = PCI_D0;
return error;
}
@@ -1575,7 +1571,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
{
u16 pmcsr;
- if (!dev->pm_cap)
+ if (!dev->pme_support)
return;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
@@ -1924,6 +1920,7 @@ void pci_pm_init(struct pci_dev *dev)
dev->wakeup_prepared = false;
dev->pm_cap = 0;
+ dev->pme_support = 0;
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -1975,8 +1972,6 @@ void pci_pm_init(struct pci_dev *dev)
device_set_wakeup_capable(&dev->dev, true);
/* Disable the PME# generation functionality */
pci_pme_active(dev, false);
- } else {
- dev->pme_support = 0;
}
}
@@ -2619,7 +2614,7 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars)
pci_release_region(pdev, i);
}
-int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
+static int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
const char *res_name, int excl)
{
int i;
@@ -3699,7 +3694,7 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
* RETURNS: Resource alignment if it is specified.
* Zero if it is not specified.
*/
-resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
+static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev)
{
int seg, bus, slot, func, align_order, count;
resource_size_t align = 0;
@@ -3812,7 +3807,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
}
}
-ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
+static ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
{
if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1)
count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1;
@@ -3823,7 +3818,7 @@ ssize_t pci_set_resource_alignment_param(const char *buf, size_t count)
return count;
}
-ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
+static ssize_t pci_get_resource_alignment_param(char *buf, size_t size)
{
size_t count;
spin_lock(&resource_alignment_lock);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 7346ee68f47d..68678ed76b0d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -8,26 +8,25 @@
/* Functions internal to the PCI core code */
-extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
-extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
+int pci_create_sysfs_dev_files(struct pci_dev *pdev);
+void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
#if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI)
static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
{ return; }
static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)
{ return; }
#else
-extern void pci_create_firmware_label_files(struct pci_dev *pdev);
-extern void pci_remove_firmware_label_files(struct pci_dev *pdev);
+void pci_create_firmware_label_files(struct pci_dev *pdev);
+void pci_remove_firmware_label_files(struct pci_dev *pdev);
#endif
-extern void pci_cleanup_rom(struct pci_dev *dev);
+void pci_cleanup_rom(struct pci_dev *dev);
#ifdef HAVE_PCI_MMAP
enum pci_mmap_api {
PCI_MMAP_SYSFS, /* mmap on /sys/bus/pci/devices/<BDF>/resource<N> */
PCI_MMAP_PROCFS /* mmap on /proc/bus/pci/<BDF> */
};
-extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
- struct vm_area_struct *vmai,
- enum pci_mmap_api mmap_api);
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vmai,
+ enum pci_mmap_api mmap_api);
#endif
int pci_probe_reset_function(struct pci_dev *dev);
@@ -60,17 +59,17 @@ struct pci_platform_pm_ops {
int (*run_wake)(struct pci_dev *dev, bool enable);
};
-extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
-extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
-extern void pci_power_up(struct pci_dev *dev);
-extern void pci_disable_enabled_device(struct pci_dev *dev);
-extern int pci_finish_runtime_suspend(struct pci_dev *dev);
-extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
-extern void pci_wakeup_bus(struct pci_bus *bus);
-extern void pci_config_pm_runtime_get(struct pci_dev *dev);
-extern void pci_config_pm_runtime_put(struct pci_dev *dev);
-extern void pci_pm_init(struct pci_dev *dev);
-extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
+int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
+void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
+void pci_power_up(struct pci_dev *dev);
+void pci_disable_enabled_device(struct pci_dev *dev);
+int pci_finish_runtime_suspend(struct pci_dev *dev);
+int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+void pci_wakeup_bus(struct pci_bus *bus);
+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_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
static inline void pci_wakeup_event(struct pci_dev *dev)
@@ -96,7 +95,7 @@ struct pci_vpd {
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
};
-extern int pci_vpd_pci22_init(struct pci_dev *dev);
+int pci_vpd_pci22_init(struct pci_dev *dev);
static inline void pci_vpd_release(struct pci_dev *dev)
{
if (dev->vpd)
@@ -105,9 +104,9 @@ static inline void pci_vpd_release(struct pci_dev *dev)
/* PCI /proc functions */
#ifdef CONFIG_PROC_FS
-extern int pci_proc_attach_device(struct pci_dev *dev);
-extern int pci_proc_detach_device(struct pci_dev *dev);
-extern int pci_proc_detach_bus(struct pci_bus *bus);
+int pci_proc_attach_device(struct pci_dev *dev);
+int pci_proc_detach_device(struct pci_dev *dev);
+int pci_proc_detach_bus(struct pci_bus *bus);
#else
static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; }
static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; }
@@ -118,8 +117,8 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
int pci_hp_add_bridge(struct pci_dev *dev);
#ifdef HAVE_PCI_LEGACY
-extern void pci_create_legacy_files(struct pci_bus *bus);
-extern void pci_remove_legacy_files(struct pci_bus *bus);
+void pci_create_legacy_files(struct pci_bus *bus);
+void pci_remove_legacy_files(struct pci_bus *bus);
#else
static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }
@@ -134,7 +133,7 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
-extern void pci_msi_init_pci_dev(struct pci_dev *dev);
+void pci_msi_init_pci_dev(struct pci_dev *dev);
#else
static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
@@ -198,12 +197,11 @@ enum pci_bar_type {
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
int crs_timeout);
-extern int pci_setup_device(struct pci_dev *dev);
-extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
- struct resource *res, unsigned int reg);
-extern int pci_resource_bar(struct pci_dev *dev, int resno,
- enum pci_bar_type *type);
-extern void pci_configure_ari(struct pci_dev *dev);
+int pci_setup_device(struct pci_dev *dev);
+int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+ struct resource *res, unsigned int reg);
+int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type);
+void pci_configure_ari(struct pci_dev *dev);
/**
* pci_ari_enabled - query ARI forwarding status
@@ -217,7 +215,7 @@ static inline int pci_ari_enabled(struct pci_bus *bus)
}
void pci_reassigndev_resource_alignment(struct pci_dev *dev);
-extern void pci_disable_bridge_window(struct pci_dev *dev);
+void pci_disable_bridge_window(struct pci_dev *dev);
/* Single Root I/O Virtualization */
struct pci_sriov {
@@ -241,7 +239,7 @@ struct pci_sriov {
};
#ifdef CONFIG_PCI_ATS
-extern void pci_restore_ats_state(struct pci_dev *dev);
+void pci_restore_ats_state(struct pci_dev *dev);
#else
static inline void pci_restore_ats_state(struct pci_dev *dev)
{
@@ -249,14 +247,13 @@ static inline void pci_restore_ats_state(struct pci_dev *dev)
#endif /* CONFIG_PCI_ATS */
#ifdef CONFIG_PCI_IOV
-extern int pci_iov_init(struct pci_dev *dev);
-extern void pci_iov_release(struct pci_dev *dev);
-extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
- enum pci_bar_type *type);
-extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
- int resno);
-extern void pci_restore_iov_state(struct pci_dev *dev);
-extern int pci_iov_bus_range(struct pci_bus *bus);
+int pci_iov_init(struct pci_dev *dev);
+void pci_iov_release(struct pci_dev *dev);
+int pci_iov_resource_bar(struct pci_dev *dev, int resno,
+ enum pci_bar_type *type);
+resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
+void pci_restore_iov_state(struct pci_dev *dev);
+int pci_iov_bus_range(struct pci_bus *bus);
#else
static inline int pci_iov_init(struct pci_dev *dev)
@@ -282,10 +279,10 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
#endif /* CONFIG_PCI_IOV */
-extern unsigned long pci_cardbus_resource_alignment(struct resource *);
+unsigned long pci_cardbus_resource_alignment(struct resource *);
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
- struct resource *res)
+ struct resource *res)
{
#ifdef CONFIG_PCI_IOV
int resno = res - dev->resource;
@@ -298,7 +295,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
return resource_alignment(res);
}
-extern void pci_enable_acs(struct pci_dev *dev);
+void pci_enable_acs(struct pci_dev *dev);
struct pci_dev_reset_methods {
u16 vendor;
@@ -307,7 +304,7 @@ struct pci_dev_reset_methods {
};
#ifdef CONFIG_PCI_QUIRKS
-extern int pci_dev_specific_reset(struct pci_dev *dev, int probe);
+int pci_dev_specific_reset(struct pci_dev *dev, int probe);
#else
static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
{
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index fde4a32a0295..569f82fc9e22 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -82,4 +82,4 @@ endchoice
config PCIE_PME
def_bool y
- depends on PCIEPORTBUS && PM_RUNTIME && ACPI
+ depends on PCIEPORTBUS && PM_RUNTIME
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index 4e24cb8a94ae..587e7e853107 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -212,8 +212,8 @@ out:
return ops->read(bus, devfn, where, size, val);
}
-int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
- u32 val)
+static int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 val)
{
u32 *sim;
struct aer_error *err;
@@ -334,13 +334,13 @@ static int aer_inject(struct aer_error_inj *einj)
return -ENODEV;
rpdev = pcie_find_root_port(dev);
if (!rpdev) {
- ret = -ENOTTY;
+ ret = -ENODEV;
goto out_put;
}
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos_cap_err) {
- ret = -ENOTTY;
+ ret = -EPERM;
goto out_put;
}
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
@@ -350,7 +350,7 @@ static int aer_inject(struct aer_error_inj *einj)
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) {
- ret = -ENOTTY;
+ ret = -EPERM;
goto out_put;
}
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 22f840f4dda1..d12c77cd6991 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -110,15 +110,15 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
}
extern struct bus_type pcie_port_bus_type;
-extern void aer_do_secondary_bus_reset(struct pci_dev *dev);
-extern int aer_init(struct pcie_device *dev);
-extern void aer_isr(struct work_struct *work);
-extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
-extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
-extern irqreturn_t aer_irq(int irq, void *context);
+void aer_do_secondary_bus_reset(struct pci_dev *dev);
+int aer_init(struct pcie_device *dev);
+void aer_isr(struct work_struct *work);
+void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
+void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
+irqreturn_t aer_irq(int irq, void *context);
#ifdef CONFIG_ACPI_APEI
-extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
+int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
#else
static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
{
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 564d97f94b6c..8ec8b4f48560 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -89,8 +89,6 @@ static int add_error_device(struct aer_err_info *e_info, struct pci_dev *dev)
return -ENOSPC;
}
-#define PCI_BUS(x) (((x) >> 8) & 0xff)
-
/**
* is_error_source - check whether the device is source of reported error
* @dev: pointer to pci_dev to be checked
@@ -106,7 +104,7 @@ static bool is_error_source(struct pci_dev *dev, struct aer_err_info *e_info)
* When bus id is equal to 0, it might be a bad id
* reported by root port.
*/
- if (!nosourceid && (PCI_BUS(e_info->id) != 0)) {
+ if (!nosourceid && (PCI_BUS_NUM(e_info->id) != 0)) {
/* Device ID match? */
if (e_info->id == ((dev->bus->number << 8) | dev->devfn))
return true;
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 9ca0dc9ffd84..795db1f9d50c 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -19,8 +19,6 @@
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/pcieport_if.h>
-#include <linux/acpi.h>
-#include <linux/pci-acpi.h>
#include <linux/pm_runtime.h>
#include "../pci.h"
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index eea2ca2375e6..d2eb80aab569 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -21,18 +21,18 @@
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
extern struct bus_type pcie_port_bus_type;
-extern int pcie_port_device_register(struct pci_dev *dev);
+int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM
-extern int pcie_port_device_suspend(struct device *dev);
-extern int pcie_port_device_resume(struct device *dev);
+int pcie_port_device_suspend(struct device *dev);
+int pcie_port_device_resume(struct device *dev);
#endif
-extern void pcie_port_device_remove(struct pci_dev *dev);
-extern int __must_check pcie_port_bus_register(void);
-extern void pcie_port_bus_unregister(void);
+void pcie_port_device_remove(struct pci_dev *dev);
+int __must_check pcie_port_bus_register(void);
+void pcie_port_bus_unregister(void);
struct pci_dev;
-extern void pcie_clear_root_pme_status(struct pci_dev *dev);
+void pcie_clear_root_pme_status(struct pci_dev *dev);
#ifdef CONFIG_HOTPLUG_PCI_PCIE
extern bool pciehp_msi_disabled;
@@ -59,7 +59,7 @@ static inline bool pcie_pme_no_msi(void)
return pcie_pme_msi_disabled;
}
-extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
+void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
#else /* !CONFIG_PCIE_PME */
static inline void pcie_pme_disable_msi(void) {}
static inline bool pcie_pme_no_msi(void) { return false; }
@@ -67,7 +67,7 @@ static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
#endif /* !CONFIG_PCIE_PME */
#ifdef CONFIG_ACPI
-extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
+int pcie_port_acpi_setup(struct pci_dev *port, int *mask);
static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
{
diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c
index a86b56e5f2f2..b4d2894ee3fc 100644
--- a/drivers/pci/pcie/portdrv_acpi.c
+++ b/drivers/pci/pcie/portdrv_acpi.c
@@ -17,6 +17,7 @@
#include "aer/aerdrv.h"
#include "../pci.h"
+#include "portdrv.h"
/**
* pcie_port_acpi_setup - Request the BIOS to release control of PCIe services.
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 08c243ab034e..696caed5fdf5 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -185,14 +185,6 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
#endif /* !PM */
/*
- * PCIe port runtime suspend is broken for some chipsets, so use a
- * black list to disable runtime PM for these chipsets.
- */
-static const struct pci_device_id port_runtime_pm_black_list[] = {
- { /* end: all zeroes */ }
-};
-
-/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
*
@@ -225,16 +217,11 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
* it by default.
*/
dev->d3cold_allowed = false;
- if (!pci_match_id(port_runtime_pm_black_list, dev))
- pm_runtime_put_noidle(&dev->dev);
-
return 0;
}
static void pcie_portdrv_remove(struct pci_dev *dev)
{
- if (!pci_match_id(port_runtime_pm_black_list, dev))
- pm_runtime_get_noresume(&dev->dev);
pcie_port_device_remove(dev);
pci_disable_device(dev);
}
@@ -272,11 +259,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
enum pci_channel_state error)
{
struct aer_broadcast_data data = {error, PCI_ERS_RESULT_CAN_RECOVER};
- int ret;
-
- /* can not fail */
- ret = device_for_each_child(&dev->dev, &data, error_detected_iter);
+ /* get true return value from &data */
+ device_for_each_child(&dev->dev, &data, error_detected_iter);
return data.result;
}
@@ -308,10 +293,9 @@ static int mmio_enabled_iter(struct device *device, void *data)
static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
{
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
- int retval;
/* get true return value from &status */
- retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
+ device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
return status;
}
@@ -343,7 +327,6 @@ static int slot_reset_iter(struct device *device, void *data)
static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
{
pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
- int retval;
/* If fatal, restore cfg space for possible link reset at upstream */
if (dev->error_state == pci_channel_io_frozen) {
@@ -354,8 +337,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
}
/* get true return value from &status */
- retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
-
+ device_for_each_child(&dev->dev, &status, slot_reset_iter);
return status;
}
@@ -381,9 +363,7 @@ static int resume_iter(struct device *device, void *data)
static void pcie_portdrv_err_resume(struct pci_dev *dev)
{
- int retval;
- /* nothing to do with error value, if it ever happens */
- retval = device_for_each_child(&dev->dev, NULL, resume_iter);
+ device_for_each_child(&dev->dev, NULL, resume_iter);
}
/*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b494066ef32f..43ece5d41d36 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -673,6 +673,8 @@ add_dev:
ret = device_register(&child->dev);
WARN_ON(ret < 0);
+ pcibios_add_bus(child);
+
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(child);
@@ -1627,8 +1629,7 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
if (!bus->is_added) {
dev_dbg(&bus->dev, "fixups for bus\n");
pcibios_fixup_bus(bus);
- if (pci_is_root_bus(bus))
- bus->is_added = 1;
+ bus->is_added = 1;
}
for (pass=0; pass < 2; pass++)
@@ -1661,6 +1662,14 @@ int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
return 0;
}
+void __weak pcibios_add_bus(struct pci_bus *bus)
+{
+}
+
+void __weak pcibios_remove_bus(struct pci_bus *bus)
+{
+}
+
struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
@@ -1715,6 +1724,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
if (error)
goto class_dev_reg_err;
+ pcibios_add_bus(b);
+
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(b);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0369fb6fc1da..7d68aeebf56b 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -324,29 +324,30 @@ static void quirk_cs5536_vsa(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);
-static void quirk_io_region(struct pci_dev *dev, unsigned region,
- unsigned size, int nr, const char *name)
+static void quirk_io_region(struct pci_dev *dev, int port,
+ unsigned size, int nr, const char *name)
{
- region &= ~(size-1);
- if (region) {
- struct pci_bus_region bus_region;
- struct resource *res = dev->resource + nr;
+ u16 region;
+ struct pci_bus_region bus_region;
+ struct resource *res = dev->resource + nr;
- res->name = pci_name(dev);
- res->start = region;
- res->end = region + size - 1;
- res->flags = IORESOURCE_IO;
+ pci_read_config_word(dev, port, &region);
+ region &= ~(size - 1);
- /* Convert from PCI bus to resource space. */
- bus_region.start = res->start;
- bus_region.end = res->end;
- pcibios_bus_to_resource(dev, res, &bus_region);
+ if (!region)
+ return;
- if (pci_claim_resource(dev, nr) == 0)
- dev_info(&dev->dev, "quirk: %pR claimed by %s\n",
- res, name);
- }
-}
+ res->name = pci_name(dev);
+ res->flags = IORESOURCE_IO;
+
+ /* Convert from PCI bus to resource space */
+ bus_region.start = region;
+ bus_region.end = region + size - 1;
+ pcibios_bus_to_resource(dev, res, &bus_region);
+
+ if (!pci_claim_resource(dev, nr))
+ dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
+}
/*
* ATI Northbridge setups MCE the processor if you even
@@ -374,12 +375,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
*/
static void quirk_ali7101_acpi(struct pci_dev *dev)
{
- u16 region;
-
- pci_read_config_word(dev, 0xE0, &region);
- quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
- pci_read_config_word(dev, 0xE2, &region);
- quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
+ quirk_io_region(dev, 0xE0, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
+ quirk_io_region(dev, 0xE2, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
@@ -442,12 +439,10 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
*/
static void quirk_piix4_acpi(struct pci_dev *dev)
{
- u32 region, res_a;
+ u32 res_a;
- pci_read_config_dword(dev, 0x40, &region);
- quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
- pci_read_config_dword(dev, 0x90, &region);
- quirk_io_region(dev, region, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
+ quirk_io_region(dev, 0x40, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
+ quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
/* Device resource A has enables for some of the other ones */
pci_read_config_dword(dev, 0x5c, &res_a);
@@ -491,7 +486,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui
*/
static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
{
- u32 region;
u8 enable;
/*
@@ -503,22 +497,14 @@ static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
*/
pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
- if (enable & ICH4_ACPI_EN) {
- pci_read_config_dword(dev, ICH_PMBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
- "ICH4 ACPI/GPIO/TCO");
- }
+ if (enable & ICH4_ACPI_EN)
+ quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+ "ICH4 ACPI/GPIO/TCO");
pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
- if (enable & ICH4_GPIO_EN) {
- pci_read_config_dword(dev, ICH4_GPIOBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 64,
- PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO");
- }
+ if (enable & ICH4_GPIO_EN)
+ quirk_io_region(dev, ICH4_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+ "ICH4 GPIO");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
@@ -533,26 +519,17 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, qui
static void ich6_lpc_acpi_gpio(struct pci_dev *dev)
{
- u32 region;
u8 enable;
pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
- if (enable & ICH6_ACPI_EN) {
- pci_read_config_dword(dev, ICH_PMBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
- "ICH6 ACPI/GPIO/TCO");
- }
+ if (enable & ICH6_ACPI_EN)
+ quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+ "ICH6 ACPI/GPIO/TCO");
pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
- if (enable & ICH6_GPIO_EN) {
- pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 64,
- PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO");
- }
+ if (enable & ICH6_GPIO_EN)
+ quirk_io_region(dev, ICH6_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+ "ICH6 GPIO");
}
static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
@@ -650,13 +627,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, qui
*/
static void quirk_vt82c586_acpi(struct pci_dev *dev)
{
- u32 region;
-
- if (dev->revision & 0x10) {
- pci_read_config_dword(dev, 0x48, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
- }
+ if (dev->revision & 0x10)
+ quirk_io_region(dev, 0x48, 256, PCI_BRIDGE_RESOURCES,
+ "vt82c586 ACPI");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi);
@@ -668,18 +641,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt
*/
static void quirk_vt82c686_acpi(struct pci_dev *dev)
{
- u16 hm;
- u32 smb;
-
quirk_vt82c586_acpi(dev);
- pci_read_config_word(dev, 0x70, &hm);
- hm &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c686 HW-mon");
+ quirk_io_region(dev, 0x70, 128, PCI_BRIDGE_RESOURCES+1,
+ "vt82c686 HW-mon");
- pci_read_config_dword(dev, 0x90, &smb);
- smb &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
+ quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+2, "vt82c686 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi);
@@ -690,15 +657,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt
*/
static void quirk_vt8235_acpi(struct pci_dev *dev)
{
- u16 pm, smb;
-
- pci_read_config_word(dev, 0x88, &pm);
- pm &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
-
- pci_read_config_word(dev, 0xd0, &smb);
- smb &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1, "vt8235 SMB");
+ quirk_io_region(dev, 0x88, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
+ quirk_io_region(dev, 0xd0, 16, PCI_BRIDGE_RESOURCES+1, "vt8235 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);
@@ -2594,6 +2554,14 @@ static void quirk_msi_intx_disable_ati_bug(struct pci_dev *dev)
dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
pci_dev_put(p);
}
+static void quirk_msi_intx_disable_qca_bug(struct pci_dev *dev)
+{
+ /* AR816X/AR817X/E210X MSI is fixed at HW level from revision 0x18 */
+ if (dev->revision < 0x18) {
+ dev_info(&dev->dev, "set MSI_INTX_DISABLE_BUG flag\n");
+ dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+ }
+}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
PCI_DEVICE_ID_TIGON3_5780,
quirk_msi_intx_disable_bug);
@@ -2643,6 +2611,16 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1073,
quirk_msi_intx_disable_bug);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083,
quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1090,
+ quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1091,
+ quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x10a0,
+ quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x10a1,
+ quirk_msi_intx_disable_qca_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0xe091,
+ quirk_msi_intx_disable_qca_bug);
#endif /* CONFIG_PCI_MSI */
/* Allow manual resource allocation for PCI hotplug bridges
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index cc875e6ed159..8fc54b7327bc 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -50,10 +50,8 @@ void pci_remove_bus(struct pci_bus *bus)
list_del(&bus->node);
pci_bus_release_busn_res(bus);
up_write(&pci_bus_sem);
- if (!bus->is_added)
- return;
-
pci_remove_legacy_files(bus);
+ pcibios_remove_bus(bus);
device_unregister(&bus->dev);
}
EXPORT_SYMBOL(pci_remove_bus);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index b41ac7756a4b..c5d0a08a8747 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -100,27 +100,6 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
return min((size_t)(image - rom), size);
}
-static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size)
-{
- struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
- loff_t start;
-
- /* assign the ROM an address if it doesn't have one */
- if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE))
- return 0;
- start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
- *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
-
- if (*size == 0)
- return 0;
-
- /* Enable ROM space decodes */
- if (pci_enable_rom(pdev))
- return 0;
-
- return start;
-}
-
/**
* pci_map_rom - map a PCI ROM to kernel space
* @pdev: pointer to pci device struct
@@ -135,7 +114,7 @@ static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size)
void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
- loff_t start = 0;
+ loff_t start;
void __iomem *rom;
/*
@@ -154,21 +133,21 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
return (void __iomem *)(unsigned long)
pci_resource_start(pdev, PCI_ROM_RESOURCE);
} else {
- start = pci_find_rom(pdev, size);
- }
- }
+ /* assign the ROM an address if it doesn't have one */
+ if (res->parent == NULL &&
+ pci_assign_resource(pdev,PCI_ROM_RESOURCE))
+ return NULL;
+ start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
+ *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+ if (*size == 0)
+ return NULL;
- /*
- * Some devices may provide ROMs via a source other than the BAR
- */
- if (!start && pdev->rom && pdev->romlen) {
- *size = pdev->romlen;
- return phys_to_virt(pdev->rom);
+ /* Enable ROM space decodes */
+ if (pci_enable_rom(pdev))
+ return NULL;
+ }
}
- if (!start)
- return NULL;
-
rom = ioremap(start, *size);
if (!rom) {
/* restore enable if ioremap fails */
@@ -202,8 +181,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
return;
- if (!pdev->rom || !pdev->romlen)
- iounmap(rom);
+ iounmap(rom);
/* Disable again before continuing, leave enabled if pci=rom */
if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
@@ -227,7 +205,24 @@ void pci_cleanup_rom(struct pci_dev *pdev)
}
}
+/**
+ * pci_platform_rom - provides a pointer to any ROM image provided by the
+ * platform
+ * @pdev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ */
+void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size)
+{
+ if (pdev->rom && pdev->romlen) {
+ *size = pdev->romlen;
+ return phys_to_virt((phys_addr_t)pdev->rom);
+ }
+
+ return NULL;
+}
+
EXPORT_SYMBOL(pci_map_rom);
EXPORT_SYMBOL(pci_unmap_rom);
EXPORT_SYMBOL_GPL(pci_enable_rom);
EXPORT_SYMBOL_GPL(pci_disable_rom);
+EXPORT_SYMBOL(pci_platform_rom);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 7e8739e25b9e..16abaaa1f83c 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1044,7 +1044,7 @@ handle_done:
;
}
-void __ref __pci_bus_size_bridges(struct pci_bus *bus,
+static void __ref __pci_bus_size_bridges(struct pci_bus *bus,
struct list_head *realloc_head)
{
struct pci_dev *dev;
@@ -1545,6 +1545,8 @@ again:
enable_all:
retval = pci_reenable_device(bridge);
+ if (retval)
+ dev_err(&bridge->dev, "Error reenabling bridge (%d)\n", retval);
pci_set_master(bridge);
pci_enable_bridges(parent);
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 81b88bda7930..07f2eddc09ce 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -261,7 +261,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct resource *res = dev->resource + resno;
resource_size_t align, size;
- struct pci_bus *bus;
int ret;
align = pci_resource_alignment(dev, res);
@@ -271,7 +270,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
return -EINVAL;
}
- bus = dev->bus;
size = resource_size(res);
ret = _pci_assign_resource(dev, resno, size, align);
diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
index ac6412fb8d6f..c1e9284a677b 100644
--- a/drivers/pci/slot.c
+++ b/drivers/pci/slot.c
@@ -377,14 +377,17 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
{
struct hotplug_slot *slot = pci_slot->hotplug;
struct kobject *kobj = NULL;
- int no_warn;
+ int ret;
if (!slot || !slot->ops)
return;
kobj = kset_find_obj(module_kset, slot->ops->mod_name);
if (!kobj)
return;
- no_warn = sysfs_create_link(&pci_slot->kobj, kobj, "module");
+ ret = sysfs_create_link(&pci_slot->kobj, kobj, "module");
+ if (ret)
+ dev_err(&pci_slot->bus->dev, "Error creating sysfs link (%d)\n",
+ ret);
kobject_put(kobj);
}
EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 34f51d2d90d2..f910962baaa7 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -106,20 +106,11 @@ config PINCTRL_LANTIQ
select PINMUX
select PINCONF
-config PINCTRL_PXA3xx
- bool
- select PINMUX
-
config PINCTRL_FALCON
bool
depends on SOC_FALCON
depends on PINCTRL_LANTIQ
-config PINCTRL_MMP2
- bool "MMP2 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
config PINCTRL_MXS
bool
select PINMUX
@@ -151,21 +142,12 @@ config PINCTRL_DB8540
bool "DB8540 pin controller driver"
depends on PINCTRL_NOMADIK && ARCH_U8500
-config PINCTRL_PXA168
- bool "PXA168 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
-config PINCTRL_PXA910
- bool "PXA910 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
select PINMUX
select PINCONF
+ select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
@@ -226,6 +208,11 @@ config PINCTRL_EXYNOS5440
select PINMUX
select PINCONF
+config PINCTRL_S3C64XX
+ bool "Samsung S3C64XX SoC pinctrl driver"
+ depends on ARCH_S3C64XX
+ select PINCTRL_SAMSUNG
+
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/sh-pfc/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f82cc5baf767..988279ae23cd 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -21,9 +21,7 @@ obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o
obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o
obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o
-obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
-obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o
@@ -31,8 +29,6 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o
obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o
obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o
-obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
-obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o
@@ -45,6 +41,7 @@ obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
+obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index b0de6e7f1fdb..c3d222ed39a2 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -27,6 +27,11 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/machine.h>
+
+#ifdef CONFIG_GPIOLIB
+#include <asm-generic/gpio.h>
+#endif
+
#include "core.h"
#include "devicetree.h"
#include "pinmux.h"
@@ -35,11 +40,17 @@
static bool pinctrl_dummy_state;
-/* Mutex taken by all entry points */
-DEFINE_MUTEX(pinctrl_mutex);
+/* Mutex taken to protect pinctrl_list */
+DEFINE_MUTEX(pinctrl_list_mutex);
+
+/* Mutex taken to protect pinctrl_maps */
+DEFINE_MUTEX(pinctrl_maps_mutex);
+
+/* Mutex taken to protect pinctrldev_list */
+DEFINE_MUTEX(pinctrldev_list_mutex);
/* Global list of pin control devices (struct pinctrl_dev) */
-LIST_HEAD(pinctrldev_list);
+static LIST_HEAD(pinctrldev_list);
/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
@@ -106,6 +117,23 @@ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
return found ? pctldev : NULL;
}
+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
+{
+ struct pinctrl_dev *pctldev;
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ list_for_each_entry(pctldev, &pinctrldev_list, node)
+ if (pctldev->dev->of_node == np) {
+ mutex_unlock(&pinctrldev_list_mutex);
+ return pctldev;
+ }
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ return NULL;
+}
+
/**
* pin_get_from_name() - look up a pin number from a name
* @pctldev: the pin control device to lookup the pin on
@@ -165,9 +193,9 @@ bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
if (pin < 0)
return false;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
pindesc = pin_desc_get(pctldev, pin);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return pindesc != NULL;
}
@@ -264,19 +292,58 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
{
struct pinctrl_gpio_range *range = NULL;
+ mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (gpio >= range->base &&
gpio < range->base + range->npins) {
+ mutex_unlock(&pctldev->mutex);
return range;
}
}
-
+ mutex_unlock(&pctldev->mutex);
return NULL;
}
/**
+ * pinctrl_ready_for_gpio_range() - check if other GPIO pins of
+ * the same GPIO chip are in range
+ * @gpio: gpio pin to check taken from the global GPIO pin space
+ *
+ * This function is complement of pinctrl_match_gpio_range(). If the return
+ * value of pinctrl_match_gpio_range() is NULL, this function could be used
+ * to check whether pinctrl device is ready or not. Maybe some GPIO pins
+ * of the same GPIO chip don't have back-end pinctrl interface.
+ * If the return value is true, it means that pinctrl device is ready & the
+ * certain GPIO pin doesn't have back-end pinctrl device. If the return value
+ * is false, it means that pinctrl device may not be ready.
+ */
+#ifdef CONFIG_GPIOLIB
+static bool pinctrl_ready_for_gpio_range(unsigned gpio)
+{
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_gpio_range *range = NULL;
+ struct gpio_chip *chip = gpio_to_chip(gpio);
+
+ /* Loop over the pin controllers */
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ /* Loop over the ranges */
+ list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+ /* Check if any gpio range overlapped with gpio chip */
+ if (range->base + range->npins - 1 < chip->base ||
+ range->base > chip->base + chip->ngpio - 1)
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+#else
+static bool pinctrl_ready_for_gpio_range(unsigned gpio) { return true; }
+#endif
+
+/**
* pinctrl_get_device_gpio_range() - find device for GPIO range
* @gpio: the pin to locate the pin controller for
* @outdev: the pin control device if found
@@ -319,9 +386,9 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
list_add_tail(&range->node, &pctldev->gpio_ranges);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
@@ -339,17 +406,25 @@ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
struct pinctrl_gpio_range *range)
{
- struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
+ struct pinctrl_dev *pctldev;
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ pctldev = get_pinctrl_dev_from_devname(devname);
/*
* If we can't find this device, let's assume that is because
* it has not probed yet, so the driver trying to register this
* range need to defer probing.
*/
- if (!pctldev)
+ if (!pctldev) {
+ mutex_unlock(&pinctrldev_list_mutex);
return ERR_PTR(-EPROBE_DEFER);
-
+ }
pinctrl_add_gpio_range(pctldev, range);
+
+ mutex_unlock(&pinctrldev_list_mutex);
+
return pctldev;
}
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@@ -365,14 +440,17 @@ pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
{
struct pinctrl_gpio_range *range = NULL;
+ mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (pin >= range->pin_base &&
pin < range->pin_base + range->npins) {
+ mutex_unlock(&pctldev->mutex);
return range;
}
}
+ mutex_unlock(&pctldev->mutex);
return NULL;
}
@@ -386,9 +464,9 @@ EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
list_del(&range->node);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
@@ -439,11 +517,13 @@ int pinctrl_request_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrl_mutex);
+ if (pinctrl_ready_for_gpio_range(gpio))
+ ret = 0;
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
@@ -452,7 +532,7 @@ int pinctrl_request_gpio(unsigned gpio)
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -472,20 +552,22 @@ void pinctrl_free_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
return;
}
+ mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
pinmux_free_gpio(pctldev, pin, range);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
@@ -496,14 +578,24 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
int ret;
int pin;
+ mutex_lock(&pinctrldev_list_mutex);
+
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
- if (ret)
+ if (ret) {
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
+ }
+
+ mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
+ ret = pinmux_gpio_direction(pctldev, range, pin, input);
+
+ mutex_unlock(&pctldev->mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
- return pinmux_gpio_direction(pctldev, range, pin, input);
+ return ret;
}
/**
@@ -516,11 +608,7 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
*/
int pinctrl_gpio_direction_input(unsigned gpio)
{
- int ret;
- mutex_lock(&pinctrl_mutex);
- ret = pinctrl_gpio_direction(gpio, true);
- mutex_unlock(&pinctrl_mutex);
- return ret;
+ return pinctrl_gpio_direction(gpio, true);
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
@@ -534,11 +622,7 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
*/
int pinctrl_gpio_direction_output(unsigned gpio)
{
- int ret;
- mutex_lock(&pinctrl_mutex);
- ret = pinctrl_gpio_direction(gpio, false);
- mutex_unlock(&pinctrl_mutex);
- return ret;
+ return pinctrl_gpio_direction(gpio, false);
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
@@ -641,14 +725,18 @@ static struct pinctrl *find_pinctrl(struct device *dev)
{
struct pinctrl *p;
+ mutex_lock(&pinctrl_list_mutex);
list_for_each_entry(p, &pinctrl_list, node)
- if (p->dev == dev)
+ if (p->dev == dev) {
+ mutex_unlock(&pinctrl_list_mutex);
return p;
+ }
+ mutex_unlock(&pinctrl_list_mutex);
return NULL;
}
-static void pinctrl_put_locked(struct pinctrl *p, bool inlist);
+static void pinctrl_free(struct pinctrl *p, bool inlist);
static struct pinctrl *create_pinctrl(struct device *dev)
{
@@ -681,6 +769,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
devname = dev_name(dev);
+ mutex_lock(&pinctrl_maps_mutex);
/* Iterate over the pin control maps to locate the right ones */
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
@@ -702,13 +791,16 @@ static struct pinctrl *create_pinctrl(struct device *dev)
* an -EPROBE_DEFER later, as that is the worst case.
*/
if (ret == -EPROBE_DEFER) {
- pinctrl_put_locked(p, false);
+ pinctrl_free(p, false);
+ mutex_unlock(&pinctrl_maps_mutex);
return ERR_PTR(ret);
}
}
+ mutex_unlock(&pinctrl_maps_mutex);
+
if (ret < 0) {
/* If some other error than deferral occured, return here */
- pinctrl_put_locked(p, false);
+ pinctrl_free(p, false);
return ERR_PTR(ret);
}
@@ -720,7 +812,11 @@ static struct pinctrl *create_pinctrl(struct device *dev)
return p;
}
-static struct pinctrl *pinctrl_get_locked(struct device *dev)
+/**
+ * pinctrl_get() - retrieves the pinctrl handle for a device
+ * @dev: the device to obtain the handle for
+ */
+struct pinctrl *pinctrl_get(struct device *dev)
{
struct pinctrl *p;
@@ -741,43 +837,35 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev)
return create_pinctrl(dev);
}
+EXPORT_SYMBOL_GPL(pinctrl_get);
-/**
- * pinctrl_get() - retrieves the pinctrl handle for a device
- * @dev: the device to obtain the handle for
- */
-struct pinctrl *pinctrl_get(struct device *dev)
+static void pinctrl_free_setting(bool disable_setting,
+ struct pinctrl_setting *setting)
{
- struct pinctrl *p;
-
- mutex_lock(&pinctrl_mutex);
- p = pinctrl_get_locked(dev);
- mutex_unlock(&pinctrl_mutex);
-
- return p;
+ switch (setting->type) {
+ case PIN_MAP_TYPE_MUX_GROUP:
+ if (disable_setting)
+ pinmux_disable_setting(setting);
+ pinmux_free_setting(setting);
+ break;
+ case PIN_MAP_TYPE_CONFIGS_PIN:
+ case PIN_MAP_TYPE_CONFIGS_GROUP:
+ pinconf_free_setting(setting);
+ break;
+ default:
+ break;
+ }
}
-EXPORT_SYMBOL_GPL(pinctrl_get);
-static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
+static void pinctrl_free(struct pinctrl *p, bool inlist)
{
struct pinctrl_state *state, *n1;
struct pinctrl_setting *setting, *n2;
+ mutex_lock(&pinctrl_list_mutex);
list_for_each_entry_safe(state, n1, &p->states, node) {
list_for_each_entry_safe(setting, n2, &state->settings, node) {
- switch (setting->type) {
- case PIN_MAP_TYPE_MUX_GROUP:
- if (state == p->state)
- pinmux_disable_setting(setting);
- pinmux_free_setting(setting);
- break;
- case PIN_MAP_TYPE_CONFIGS_PIN:
- case PIN_MAP_TYPE_CONFIGS_GROUP:
- pinconf_free_setting(setting);
- break;
- default:
- break;
- }
+ pinctrl_free_setting(state == p->state, setting);
list_del(&setting->node);
kfree(setting);
}
@@ -790,6 +878,7 @@ static void pinctrl_put_locked(struct pinctrl *p, bool inlist)
if (inlist)
list_del(&p->node);
kfree(p);
+ mutex_unlock(&pinctrl_list_mutex);
}
/**
@@ -800,7 +889,7 @@ static void pinctrl_release(struct kref *kref)
{
struct pinctrl *p = container_of(kref, struct pinctrl, users);
- pinctrl_put_locked(p, true);
+ pinctrl_free(p, true);
}
/**
@@ -809,14 +898,17 @@ static void pinctrl_release(struct kref *kref)
*/
void pinctrl_put(struct pinctrl *p)
{
- mutex_lock(&pinctrl_mutex);
kref_put(&p->users, pinctrl_release);
- mutex_unlock(&pinctrl_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_put);
-static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
- const char *name)
+/**
+ * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
+ * @p: the pinctrl handle to retrieve the state from
+ * @name: the state name to retrieve
+ */
+struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
+ const char *name)
{
struct pinctrl_state *state;
@@ -833,28 +925,17 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
return state;
}
+EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
/**
- * pinctrl_lookup_state() - retrieves a state handle from a pinctrl handle
- * @p: the pinctrl handle to retrieve the state from
- * @name: the state name to retrieve
+ * pinctrl_select_state() - select/activate/program a pinctrl state to HW
+ * @p: the pinctrl handle for the device that requests configuration
+ * @state: the state handle to select/activate/program
*/
-struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name)
-{
- struct pinctrl_state *s;
-
- mutex_lock(&pinctrl_mutex);
- s = pinctrl_lookup_state_locked(p, name);
- mutex_unlock(&pinctrl_mutex);
-
- return s;
-}
-EXPORT_SYMBOL_GPL(pinctrl_lookup_state);
-
-static int pinctrl_select_state_locked(struct pinctrl *p,
- struct pinctrl_state *state)
+int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
struct pinctrl_setting *setting, *setting2;
+ struct pinctrl_state *old_state = p->state;
int ret;
if (p->state == state)
@@ -888,7 +969,7 @@ static int pinctrl_select_state_locked(struct pinctrl *p,
}
}
- p->state = state;
+ p->state = NULL;
/* Apply all the settings for the new state */
list_for_each_entry(setting, &state->settings, node) {
@@ -904,27 +985,36 @@ static int pinctrl_select_state_locked(struct pinctrl *p,
ret = -EINVAL;
break;
}
+
if (ret < 0) {
- /* FIXME: Difficult to return to prev state */
- return ret;
+ goto unapply_new_state;
}
}
+ p->state = state;
+
return 0;
-}
-/**
- * pinctrl_select() - select/activate/program a pinctrl state to HW
- * @p: the pinctrl handle for the device that requests configuratio
- * @state: the state handle to select/activate/program
- */
-int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
-{
- int ret;
+unapply_new_state:
+ dev_err(p->dev, "Error applying setting, reverse things back\n");
- mutex_lock(&pinctrl_mutex);
- ret = pinctrl_select_state_locked(p, state);
- mutex_unlock(&pinctrl_mutex);
+ list_for_each_entry(setting2, &state->settings, node) {
+ if (&setting2->node == &setting->node)
+ break;
+ /*
+ * All we can do here is pinmux_disable_setting.
+ * That means that some pins are muxed differently now
+ * than they were before applying the setting (We can't
+ * "unmux a pin"!), but it's not a big deal since the pins
+ * are free to be muxed by another apply_setting.
+ */
+ if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
+ pinmux_disable_setting(setting2);
+ }
+
+ /* There's no infinite recursive loop here because p->state is NULL */
+ if (old_state)
+ pinctrl_select_state(p, old_state);
return ret;
}
@@ -979,9 +1069,8 @@ static int devm_pinctrl_match(struct device *dev, void *res, void *data)
*/
void devm_pinctrl_put(struct pinctrl *p)
{
- WARN_ON(devres_destroy(p->dev, devm_pinctrl_release,
+ WARN_ON(devres_release(p->dev, devm_pinctrl_release,
devm_pinctrl_match, p));
- pinctrl_put(p);
}
EXPORT_SYMBOL_GPL(devm_pinctrl_put);
@@ -1055,10 +1144,10 @@ int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
}
if (!locked)
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps);
if (!locked)
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
@@ -1080,12 +1169,15 @@ void pinctrl_unregister_map(struct pinctrl_map const *map)
{
struct pinctrl_maps *maps_node;
+ mutex_lock(&pinctrl_maps_mutex);
list_for_each_entry(maps_node, &pinctrl_maps, node) {
if (maps_node->maps == map) {
list_del(&maps_node->node);
+ mutex_unlock(&pinctrl_maps_mutex);
return;
}
}
+ mutex_unlock(&pinctrl_maps_mutex);
}
/**
@@ -1122,7 +1214,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
seq_printf(s, "registered pins: %d\n", pctldev->desc->npins);
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
@@ -1144,7 +1236,7 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
seq_puts(s, "\n");
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
@@ -1155,8 +1247,9 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
unsigned ngroups, selector = 0;
+ mutex_lock(&pctldev->mutex);
+
ngroups = ops->get_groups_count(pctldev);
- mutex_lock(&pinctrl_mutex);
seq_puts(s, "registered pin groups:\n");
while (selector < ngroups) {
@@ -1177,7 +1270,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
for (i = 0; i < num_pins; i++) {
pname = pin_get_name(pctldev, pins[i]);
if (WARN_ON(!pname)) {
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return -EINVAL;
}
seq_printf(s, "pin %d (%s)\n", pins[i], pname);
@@ -1187,7 +1280,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
selector++;
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
@@ -1199,7 +1292,7 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
seq_puts(s, "GPIO ranges handled:\n");
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
@@ -1210,7 +1303,7 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
(range->pin_base + range->npins - 1));
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
@@ -1221,7 +1314,7 @@ static int pinctrl_devices_show(struct seq_file *s, void *what)
seq_puts(s, "name [pinmux] [pinconf]\n");
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrldev_list_mutex);
list_for_each_entry(pctldev, &pinctrldev_list, node) {
seq_printf(s, "%s ", pctldev->desc->name);
@@ -1236,7 +1329,7 @@ static int pinctrl_devices_show(struct seq_file *s, void *what)
seq_puts(s, "\n");
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
return 0;
}
@@ -1265,8 +1358,7 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
seq_puts(s, "Pinctrl maps:\n");
- mutex_lock(&pinctrl_mutex);
-
+ mutex_lock(&pinctrl_maps_mutex);
for_each_maps(maps_node, i, map) {
seq_printf(s, "device %s\nstate %s\ntype %s (%d)\n",
map->dev_name, map->name, map_type(map->type),
@@ -1290,8 +1382,7 @@ static int pinctrl_maps_show(struct seq_file *s, void *what)
seq_printf(s, "\n");
}
-
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
@@ -1304,7 +1395,7 @@ static int pinctrl_show(struct seq_file *s, void *what)
seq_puts(s, "Requested pin control handlers their pinmux maps:\n");
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrl_list_mutex);
list_for_each_entry(p, &pinctrl_list, node) {
seq_printf(s, "device: %s current state: %s\n",
@@ -1336,7 +1427,7 @@ static int pinctrl_show(struct seq_file *s, void *what)
}
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrl_list_mutex);
return 0;
}
@@ -1522,6 +1613,7 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
pctldev->dev = dev;
+ mutex_init(&pctldev->mutex);
/* check core ops for sanity */
if (pinctrl_check_ops(pctldev)) {
@@ -1551,38 +1643,37 @@ struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
goto out_err;
}
- mutex_lock(&pinctrl_mutex);
-
+ mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
+ mutex_unlock(&pinctrldev_list_mutex);
+
+ pctldev->p = pinctrl_get(pctldev->dev);
- pctldev->p = pinctrl_get_locked(pctldev->dev);
if (!IS_ERR(pctldev->p)) {
pctldev->hog_default =
- pinctrl_lookup_state_locked(pctldev->p,
- PINCTRL_STATE_DEFAULT);
+ pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
if (IS_ERR(pctldev->hog_default)) {
dev_dbg(dev, "failed to lookup the default state\n");
} else {
- if (pinctrl_select_state_locked(pctldev->p,
+ if (pinctrl_select_state(pctldev->p,
pctldev->hog_default))
dev_err(dev,
"failed to select default state\n");
}
pctldev->hog_sleep =
- pinctrl_lookup_state_locked(pctldev->p,
+ pinctrl_lookup_state(pctldev->p,
PINCTRL_STATE_SLEEP);
if (IS_ERR(pctldev->hog_sleep))
dev_dbg(dev, "failed to lookup the sleep state\n");
}
- mutex_unlock(&pinctrl_mutex);
-
pinctrl_init_device_debugfs(pctldev);
return pctldev;
out_err:
+ mutex_destroy(&pctldev->mutex);
kfree(pctldev);
return NULL;
}
@@ -1600,12 +1691,13 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
if (pctldev == NULL)
return;
- pinctrl_remove_device_debugfs(pctldev);
+ mutex_lock(&pinctrldev_list_mutex);
+ mutex_lock(&pctldev->mutex);
- mutex_lock(&pinctrl_mutex);
+ pinctrl_remove_device_debugfs(pctldev);
if (!IS_ERR(pctldev->p))
- pinctrl_put_locked(pctldev->p, true);
+ pinctrl_put(pctldev->p);
/* TODO: check that no pinmuxes are still active? */
list_del(&pctldev->node);
@@ -1616,9 +1708,10 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
list_for_each_entry_safe(range, n, &pctldev->gpio_ranges, node)
list_del(&range->node);
+ mutex_unlock(&pctldev->mutex);
+ mutex_destroy(&pctldev->mutex);
kfree(pctldev);
-
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_unregister);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index ee72f1f6d862..75476b3d87da 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -33,6 +33,7 @@ struct pinctrl_gpio_range;
* @p: result of pinctrl_get() for this device
* @hog_default: default state for pins hogged by this device
* @hog_sleep: sleep state for pins hogged by this device
+ * @mutex: mutex taken on each pin controller specific action
* @device_root: debugfs root for this device
*/
struct pinctrl_dev {
@@ -46,6 +47,7 @@ struct pinctrl_dev {
struct pinctrl *p;
struct pinctrl_state *hog_default;
struct pinctrl_state *hog_sleep;
+ struct mutex mutex;
#ifdef CONFIG_DEBUG_FS
struct dentry *device_root;
#endif
@@ -72,7 +74,7 @@ struct pinctrl {
/**
* struct pinctrl_state - a pinctrl state for a device
- * @node: list not for struct pinctrl's @states field
+ * @node: list node for struct pinctrl's @states field
* @name: the name of this state
* @settings: a list of settings for this state
*/
@@ -168,6 +170,7 @@ struct pinctrl_maps {
};
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
@@ -186,8 +189,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map);
extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
-extern struct mutex pinctrl_mutex;
-extern struct list_head pinctrldev_list;
+extern struct mutex pinctrl_maps_mutex;
extern struct list_head pinctrl_maps;
#define for_each_maps(_maps_node_, _i_, _map_) \
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fd40a11ad645..340fb4e6c600 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -41,7 +41,7 @@ static void dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
if (pctldev) {
- struct pinctrl_ops *ops = pctldev->desc->pctlops;
+ const struct pinctrl_ops *ops = pctldev->desc->pctlops;
ops->dt_free_map(pctldev, map, num_maps);
} else {
/* There is no pctldev for PIN_MAP_TYPE_DUMMY_STATE */
@@ -95,22 +95,11 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
return pinctrl_register_map(map, num_maps, false, true);
}
-static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
-{
- struct pinctrl_dev *pctldev;
-
- list_for_each_entry(pctldev, &pinctrldev_list, node)
- if (pctldev->dev->of_node == np)
- return pctldev;
-
- return NULL;
-}
-
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
{
struct pinctrl_dev *pctldev;
- pctldev = find_pinctrl_by_of_node(np);
+ pctldev = get_pinctrl_dev_from_of_node(np);
if (!pctldev)
return NULL;
@@ -122,7 +111,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
{
struct device_node *np_pctldev;
struct pinctrl_dev *pctldev;
- struct pinctrl_ops *ops;
+ const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
unsigned num_maps;
@@ -138,7 +127,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
/* OK let's just assume this will appear later then */
return -EPROBE_DEFER;
}
- pctldev = find_pinctrl_by_of_node(np_pctldev);
+ pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
break;
/* Do not defer probing of hogs (circular loop) */
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 2d2f0a43d36b..bb7ddb1bc89f 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -263,7 +263,7 @@ static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
return;
}
-static struct pinconf_ops mvebu_pinconf_ops = {
+static const struct pinconf_ops mvebu_pinconf_ops = {
.pin_config_group_get = mvebu_pinconf_group_get,
.pin_config_group_set = mvebu_pinconf_group_set,
.pin_config_group_dbg_show = mvebu_pinconf_group_dbg_show,
@@ -369,7 +369,7 @@ static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
return -ENOTSUPP;
}
-static struct pinmux_ops mvebu_pinmux_ops = {
+static const struct pinmux_ops mvebu_pinmux_ops = {
.get_functions_count = mvebu_pinmux_get_funcs_count,
.get_function_name = mvebu_pinmux_get_func_name,
.get_function_groups = mvebu_pinmux_get_groups,
@@ -470,7 +470,7 @@ static void mvebu_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops mvebu_pinctrl_ops = {
+static const struct pinctrl_ops mvebu_pinctrl_ops = {
.get_groups_count = mvebu_pinctrl_get_groups_count,
.get_group_name = mvebu_pinctrl_get_group_name,
.get_group_pins = mvebu_pinctrl_get_group_pins,
@@ -478,8 +478,12 @@ static struct pinctrl_ops mvebu_pinctrl_ops = {
.dt_free_map = mvebu_pinctrl_dt_free_map,
};
-static int _add_function(struct mvebu_pinctrl_function *funcs, const char *name)
+static int _add_function(struct mvebu_pinctrl_function *funcs, int *funcsize,
+ const char *name)
{
+ if (*funcsize <= 0)
+ return -EOVERFLOW;
+
while (funcs->num_groups) {
/* function already there */
if (strcmp(funcs->name, name) == 0) {
@@ -488,8 +492,12 @@ static int _add_function(struct mvebu_pinctrl_function *funcs, const char *name)
}
funcs++;
}
+
+ /* append new unique function */
funcs->name = name;
funcs->num_groups = 1;
+ (*funcsize)--;
+
return 0;
}
@@ -497,12 +505,12 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
struct mvebu_pinctrl *pctl)
{
struct mvebu_pinctrl_function *funcs;
- int num = 0;
+ int num = 0, funcsize = pctl->desc.npins;
int n, s;
/* we allocate functions for number of pins and hope
- * there are less unique functions than pins available */
- funcs = devm_kzalloc(&pdev->dev, pctl->desc.npins *
+ * there are fewer unique functions than pins available */
+ funcs = devm_kzalloc(&pdev->dev, funcsize *
sizeof(struct mvebu_pinctrl_function), GFP_KERNEL);
if (!funcs)
return -ENOMEM;
@@ -510,26 +518,27 @@ static int mvebu_pinctrl_build_functions(struct platform_device *pdev,
for (n = 0; n < pctl->num_groups; n++) {
struct mvebu_pinctrl_group *grp = &pctl->groups[n];
for (s = 0; s < grp->num_settings; s++) {
+ int ret;
+
/* skip unsupported settings on this variant */
if (pctl->variant &&
!(pctl->variant & grp->settings[s].variant))
continue;
/* check for unique functions and count groups */
- if (_add_function(funcs, grp->settings[s].name))
+ ret = _add_function(funcs, &funcsize,
+ grp->settings[s].name);
+ if (ret == -EOVERFLOW)
+ dev_err(&pdev->dev,
+ "More functions than pins(%d)\n",
+ pctl->desc.npins);
+ if (ret < 0)
continue;
num++;
}
}
- /* with the number of unique functions and it's groups known,
- reallocate functions and assign group names */
- funcs = krealloc(funcs, num * sizeof(struct mvebu_pinctrl_function),
- GFP_KERNEL);
- if (!funcs)
- return -ENOMEM;
-
pctl->num_functions = num;
pctl->functions = funcs;
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 06c304ac6f7d..2ad5a8d337b5 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -12,6 +12,7 @@
#define pr_fmt(fmt) "generic pinconfig core: " fmt
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
@@ -33,7 +34,7 @@ struct pin_config_item {
#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c }
-struct pin_config_item conf_items[] = {
+static struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
@@ -59,7 +60,7 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
if (!ops->is_generic)
return;
- for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+ for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
unsigned long config;
int ret;
@@ -94,7 +95,7 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
if (!ops->is_generic)
return;
- for(i = 0; i < ARRAY_SIZE(conf_items); i++) {
+ for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
unsigned long config;
int ret;
@@ -120,4 +121,17 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
}
}
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned long config)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
+ if (pinconf_to_config_param(config) != conf_items[i].param)
+ continue;
+ seq_printf(s, "%s: 0x%x", conf_items[i].display,
+ pinconf_to_config_argument(config));
+ }
+}
+EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
#endif
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index d611ecfcbf70..c67c37e23dd7 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <linux/uaccess.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
@@ -88,14 +89,14 @@ int pin_config_get(const char *dev_name, const char *name,
struct pinctrl_dev *pctldev;
int pin;
- mutex_lock(&pinctrl_mutex);
-
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
pin = -EINVAL;
- goto unlock;
+ return pin;
}
+ mutex_lock(&pctldev->mutex);
+
pin = pin_get_from_name(pctldev, name);
if (pin < 0)
goto unlock;
@@ -103,7 +104,7 @@ int pin_config_get(const char *dev_name, const char *name,
pin = pin_config_get_for_pin(pctldev, pin, config);
unlock:
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return pin;
}
EXPORT_SYMBOL(pin_config_get);
@@ -144,14 +145,14 @@ int pin_config_set(const char *dev_name, const char *name,
struct pinctrl_dev *pctldev;
int pin, ret;
- mutex_lock(&pinctrl_mutex);
-
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
ret = -EINVAL;
- goto unlock;
+ return ret;
}
+ mutex_lock(&pctldev->mutex);
+
pin = pin_get_from_name(pctldev, name);
if (pin < 0) {
ret = pin;
@@ -161,7 +162,7 @@ int pin_config_set(const char *dev_name, const char *name,
ret = pin_config_set_for_pin(pctldev, pin, config);
unlock:
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return ret;
}
EXPORT_SYMBOL(pin_config_set);
@@ -173,13 +174,14 @@ int pin_config_group_get(const char *dev_name, const char *pin_group,
const struct pinconf_ops *ops;
int selector, ret;
- mutex_lock(&pinctrl_mutex);
-
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
ret = -EINVAL;
- goto unlock;
+ return ret;
}
+
+ mutex_lock(&pctldev->mutex);
+
ops = pctldev->desc->confops;
if (!ops || !ops->pin_config_group_get) {
@@ -199,7 +201,7 @@ int pin_config_group_get(const char *dev_name, const char *pin_group,
ret = ops->pin_config_group_get(pctldev, selector, config);
unlock:
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return ret;
}
EXPORT_SYMBOL(pin_config_group_get);
@@ -216,13 +218,14 @@ int pin_config_group_set(const char *dev_name, const char *pin_group,
int ret;
int i;
- mutex_lock(&pinctrl_mutex);
-
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
ret = -EINVAL;
- goto unlock;
+ return ret;
}
+
+ mutex_lock(&pctldev->mutex);
+
ops = pctldev->desc->confops;
pctlops = pctldev->desc->pctlops;
@@ -278,7 +281,7 @@ int pin_config_group_set(const char *dev_name, const char *pin_group,
ret = 0;
unlock:
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return ret;
}
@@ -486,7 +489,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
seq_puts(s, "Pin config settings per pin\n");
seq_puts(s, "Format: pin (name): configs\n");
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
@@ -506,7 +509,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
seq_printf(s, "\n");
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
@@ -574,122 +577,58 @@ static const struct file_operations pinconf_groups_ops = {
.release = single_release,
};
-/* 32bit read/write ressources */
-#define MAX_NAME_LEN 16
-char dbg_pinname[MAX_NAME_LEN]; /* shared: name of the state of the pin*/
-char dbg_state_name[MAX_NAME_LEN]; /* shared: state of the pin*/
-static u32 dbg_config; /* shared: config to be read/set for the pin & state*/
-
-static int pinconf_dbg_pinname_print(struct seq_file *s, void *d)
-{
- if (strlen(dbg_pinname))
- seq_printf(s, "%s\n", dbg_pinname);
- else
- seq_printf(s, "No pin name set\n");
- return 0;
-}
-
-static int pinconf_dbg_pinname_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pinconf_dbg_pinname_print, inode->i_private);
-}
-
-static int pinconf_dbg_pinname_write(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- int err;
-
- if (count > MAX_NAME_LEN)
- return -EINVAL;
-
- err = sscanf(user_buf, "%15s", dbg_pinname);
-
- if (err != 1)
- return -EINVAL;
-
- return count;
-}
+#define MAX_NAME_LEN 15
-static const struct file_operations pinconf_dbg_pinname_fops = {
- .open = pinconf_dbg_pinname_open,
- .write = pinconf_dbg_pinname_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
+struct dbg_cfg {
+ enum pinctrl_map_type map_type;
+ char dev_name[MAX_NAME_LEN+1];
+ char state_name[MAX_NAME_LEN+1];
+ char pin_name[MAX_NAME_LEN+1];
};
-static int pinconf_dbg_state_print(struct seq_file *s, void *d)
-{
- if (strlen(dbg_state_name))
- seq_printf(s, "%s\n", dbg_state_name);
- else
- seq_printf(s, "No pin state set\n");
- return 0;
-}
-
-static int pinconf_dbg_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pinconf_dbg_state_print, inode->i_private);
-}
-
-static int pinconf_dbg_state_write(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- int err;
-
- if (count > MAX_NAME_LEN)
- return -EINVAL;
-
- err = sscanf(user_buf, "%15s", dbg_state_name);
-
- if (err != 1)
- return -EINVAL;
-
- return count;
-}
-
-static const struct file_operations pinconf_dbg_pinstate_fops = {
- .open = pinconf_dbg_state_open,
- .write = pinconf_dbg_state_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
+/*
+ * Goal is to keep this structure as global in order to simply read the
+ * pinconf-config file after a write to check config is as expected
+ */
+static struct dbg_cfg pinconf_dbg_conf;
/**
* pinconf_dbg_config_print() - display the pinctrl config from the pinctrl
- * map, of a pin/state pair based on pinname and state that have been
- * selected with the debugfs entries pinconf-name and pinconf-state
- * @s: contains the 32bits config to be written
+ * map, of the dev/pin/state that was last written to pinconf-config file.
+ * @s: string filled in with config description
* @d: not used
*/
static int pinconf_dbg_config_print(struct seq_file *s, void *d)
{
struct pinctrl_maps *maps_node;
- struct pinctrl_map const *map;
+ const struct pinctrl_map *map;
struct pinctrl_dev *pctldev = NULL;
- struct pinconf_ops *confops = NULL;
+ const struct pinconf_ops *confops = NULL;
+ const struct pinctrl_map_configs *configs;
+ struct dbg_cfg *dbg = &pinconf_dbg_conf;
int i, j;
bool found = false;
+ unsigned long config;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
/* Parse the pinctrl map and look for the elected pin/state */
for_each_maps(maps_node, i, map) {
- if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+ if (map->type != dbg->map_type)
continue;
-
- if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+ if (strcmp(map->dev_name, dbg->dev_name))
+ continue;
+ if (strcmp(map->name, dbg->state_name))
continue;
for (j = 0; j < map->data.configs.num_configs; j++) {
- if (0 == strncmp(map->data.configs.group_or_pin,
- dbg_pinname, MAX_NAME_LEN)) {
- /* We found the right pin / state, read the
- * config and store the pctldev */
- dbg_config = map->data.configs.configs[j];
+ if (!strcmp(map->data.configs.group_or_pin,
+ dbg->pin_name)) {
+ /*
+ * We found the right pin / state, read the
+ * config and he pctldev for later use
+ */
+ configs = &map->data.configs;
pctldev = get_pinctrl_dev_from_devname
(map->ctrl_dev_name);
found = true;
@@ -698,74 +637,166 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d)
}
}
- mutex_unlock(&pinctrl_mutex);
+ if (!found) {
+ seq_printf(s, "No config found for dev/state/pin, expected:\n");
+ seq_printf(s, "Searched dev:%s\n", dbg->dev_name);
+ seq_printf(s, "Searched state:%s\n", dbg->state_name);
+ seq_printf(s, "Searched pin:%s\n", dbg->pin_name);
+ seq_printf(s, "Use: modify config_pin <devname> "\
+ "<state> <pinname> <value>\n");
+ goto exit;
+ }
- if (found) {
- seq_printf(s, "Config of %s in state %s: 0x%08X\n", dbg_pinname,
- dbg_state_name, dbg_config);
+ config = *(configs->configs);
+ seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n",
+ dbg->dev_name, dbg->pin_name,
+ dbg->state_name, config);
- if (pctldev)
- confops = pctldev->desc->confops;
+ if (pctldev)
+ confops = pctldev->desc->confops;
- if (confops && confops->pin_config_config_dbg_show)
- confops->pin_config_config_dbg_show(pctldev,
- s, dbg_config);
- } else {
- seq_printf(s, "No pin found for defined name/state\n");
- }
+ if (confops && confops->pin_config_config_dbg_show)
+ confops->pin_config_config_dbg_show(pctldev, s, config);
- return 0;
-}
+exit:
+ mutex_unlock(&pctldev->mutex);
-static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pinconf_dbg_config_print, inode->i_private);
+ return 0;
}
/**
- * pinconf_dbg_config_write() - overwrite the pinctrl config in thepinctrl
- * map, of a pin/state pair based on pinname and state that have been
- * selected with the debugfs entries pinconf-name and pinconf-state
+ * pinconf_dbg_config_write() - modify the pinctrl config in the pinctrl
+ * map, of a dev/pin/state entry based on user entries to pinconf-config
+ * @user_buf: contains the modification request with expected format:
+ * modify config_pin <devicename> <state> <pinname> <newvalue>
+ * modify is literal string, alternatives like add/delete not supported yet
+ * config_pin is literal, alternatives like config_mux not supported yet
+ * <devicename> <state> <pinname> are values that should match the pinctrl-maps
+ * <newvalue> reflects the new config and is driver dependant
*/
static int pinconf_dbg_config_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
- int err;
- unsigned long config;
struct pinctrl_maps *maps_node;
- struct pinctrl_map const *map;
- int i, j;
+ const struct pinctrl_map *map;
+ struct pinctrl_dev *pctldev = NULL;
+ const struct pinconf_ops *confops = NULL;
+ struct dbg_cfg *dbg = &pinconf_dbg_conf;
+ const struct pinctrl_map_configs *configs;
+ char config[MAX_NAME_LEN+1];
+ bool found = false;
+ char buf[128];
+ char *b = &buf[0];
+ int buf_size;
+ char *token;
+ int i;
+
+ /* Get userspace string and assure termination */
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = 0;
+
+ /*
+ * need to parse entry and extract parameters:
+ * modify configs_pin devicename state pinname newvalue
+ */
+
+ /* Get arg: 'modify' */
+ token = strsep(&b, " ");
+ if (!token)
+ return -EINVAL;
+ if (strcmp(token, "modify"))
+ return -EINVAL;
- err = kstrtoul_from_user(user_buf, count, 0, &config);
+ /* Get arg type: "config_pin" type supported so far */
+ token = strsep(&b, " ");
+ if (!token)
+ return -EINVAL;
+ if (strcmp(token, "config_pin"))
+ return -EINVAL;
+ dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN;
- if (err)
- return err;
+ /* get arg 'device_name' */
+ token = strsep(&b, " ");
+ if (token == NULL)
+ return -EINVAL;
+ if (strlen(token) >= MAX_NAME_LEN)
+ return -EINVAL;
+ strncpy(dbg->dev_name, token, MAX_NAME_LEN);
- dbg_config = config;
+ /* get arg 'state_name' */
+ token = strsep(&b, " ");
+ if (token == NULL)
+ return -EINVAL;
+ if (strlen(token) >= MAX_NAME_LEN)
+ return -EINVAL;
+ strncpy(dbg->state_name, token, MAX_NAME_LEN);
- mutex_lock(&pinctrl_mutex);
+ /* get arg 'pin_name' */
+ token = strsep(&b, " ");
+ if (token == NULL)
+ return -EINVAL;
+ if (strlen(token) >= MAX_NAME_LEN)
+ return -EINVAL;
+ strncpy(dbg->pin_name, token, MAX_NAME_LEN);
- /* Parse the pinctrl map and look for the selected pin/state */
+ /* get new_value of config' */
+ token = strsep(&b, " ");
+ if (token == NULL)
+ return -EINVAL;
+ if (strlen(token) >= MAX_NAME_LEN)
+ return -EINVAL;
+ strncpy(config, token, MAX_NAME_LEN);
+
+ mutex_lock(&pinctrl_maps_mutex);
+
+ /* Parse the pinctrl map and look for the selected dev/state/pin */
for_each_maps(maps_node, i, map) {
- if (map->type != PIN_MAP_TYPE_CONFIGS_PIN)
+ if (strcmp(map->dev_name, dbg->dev_name))
continue;
-
- if (strncmp(map->name, dbg_state_name, MAX_NAME_LEN) > 0)
+ if (map->type != dbg->map_type)
+ continue;
+ if (strcmp(map->name, dbg->state_name))
continue;
/* we found the right pin / state, so overwrite config */
- for (j = 0; j < map->data.configs.num_configs; j++) {
- if (strncmp(map->data.configs.group_or_pin, dbg_pinname,
- MAX_NAME_LEN) == 0)
- map->data.configs.configs[j] = dbg_config;
+ if (!strcmp(map->data.configs.group_or_pin, dbg->pin_name)) {
+ found = true;
+ pctldev = get_pinctrl_dev_from_devname(
+ map->ctrl_dev_name);
+ configs = &map->data.configs;
+ break;
}
}
- mutex_unlock(&pinctrl_mutex);
+ if (!found) {
+ count = -EINVAL;
+ goto exit;
+ }
+
+ if (pctldev)
+ confops = pctldev->desc->confops;
+
+ if (confops && confops->pin_config_dbg_parse_modify) {
+ for (i = 0; i < configs->num_configs; i++) {
+ confops->pin_config_dbg_parse_modify(pctldev,
+ config,
+ &configs->configs[i]);
+ }
+ }
+
+exit:
+ mutex_unlock(&pinctrl_maps_mutex);
return count;
}
+static int pinconf_dbg_config_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pinconf_dbg_config_print, inode->i_private);
+}
+
static const struct file_operations pinconf_dbg_pinconfig_fops = {
.open = pinconf_dbg_config_open,
.write = pinconf_dbg_config_write,
@@ -782,10 +813,6 @@ void pinconf_init_device_debugfs(struct dentry *devroot,
devroot, pctldev, &pinconf_pins_ops);
debugfs_create_file("pinconf-groups", S_IFREG | S_IRUGO,
devroot, pctldev, &pinconf_groups_ops);
- debugfs_create_file("pinconf-name", (S_IRUGO | S_IWUSR | S_IWGRP),
- devroot, pctldev, &pinconf_dbg_pinname_fops);
- debugfs_create_file("pinconf-state", (S_IRUGO | S_IWUSR | S_IWGRP),
- devroot, pctldev, &pinconf_dbg_pinstate_fops);
debugfs_create_file("pinconf-config", (S_IRUGO | S_IWUSR | S_IWGRP),
devroot, pctldev, &pinconf_dbg_pinconfig_fops);
}
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index bfda73d64eed..92c7267244d2 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -98,6 +98,8 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
struct seq_file *s, const char *gname);
+void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned long config);
#else
static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
@@ -114,4 +116,10 @@ static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
return;
}
+static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ unsigned long config)
+{
+ return;
+}
#endif
diff --git a/drivers/pinctrl/pinctrl-ab8500.c b/drivers/pinctrl/pinctrl-ab8500.c
index 3b471d87c211..2ac2d0ad3025 100644
--- a/drivers/pinctrl/pinctrl-ab8500.c
+++ b/drivers/pinctrl/pinctrl-ab8500.c
@@ -389,7 +389,8 @@ static const struct abx500_function ab8500_functions[] = {
* alt_A | 1 | 0 | 0
*/
-struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1] = {
ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
@@ -455,7 +456,7 @@ struct alternate_functions ab8500_alternate_functions[AB8500_GPIO_MAX_NUMBER + 1
* GPIO24 and GPIO25
* GPIO36 to GPIO41
*/
-struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8500_gpio_irq_cluster[] = {
GPIO_IRQ_CLUSTER(6, 13, AB8500_INT_GPIO6R),
GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
GPIO_IRQ_CLUSTER(36, 41, AB8500_INT_GPIO36R),
diff --git a/drivers/pinctrl/pinctrl-ab8505.c b/drivers/pinctrl/pinctrl-ab8505.c
index 3a4238e879e3..bf0ef4ac376f 100644
--- a/drivers/pinctrl/pinctrl-ab8505.c
+++ b/drivers/pinctrl/pinctrl-ab8505.c
@@ -271,7 +271,8 @@ static const struct abx500_function ab8505_functions[] = {
* alt_A | 1 | 0 | 0
*/
-struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1] = {
ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
ALTERNATE_FUNCTIONS(2, 1, UNUSED, UNUSED, 0, 0, 0), /* GPIO2, altA controlled by bit 1 */
@@ -284,7 +285,7 @@ struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1
ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9, bit 0 reserved */
ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
- ALTERNATE_FUNCTIONS(11, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
+ ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 2 */
ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12, bit3 reseved */
ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
@@ -348,7 +349,7 @@ struct alternate_functions ab8505_alternate_functions[AB8505_GPIO_MAX_NUMBER + 1
* GPIO50
* GPIO52 to GPIO53
*/
-struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8505_gpio_irq_cluster[] = {
GPIO_IRQ_CLUSTER(10, 11, AB8500_INT_GPIO10R),
GPIO_IRQ_CLUSTER(13, 13, AB8500_INT_GPIO13R),
GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
diff --git a/drivers/pinctrl/pinctrl-ab8540.c b/drivers/pinctrl/pinctrl-ab8540.c
index 8ee1e8d95f65..9867535d49c1 100644
--- a/drivers/pinctrl/pinctrl-ab8540.c
+++ b/drivers/pinctrl/pinctrl-ab8540.c
@@ -299,7 +299,8 @@ static const struct abx500_function ab8540_functions[] = {
*
*/
-struct alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab8540_alternate_functions[AB8540_GPIO_MAX_NUMBER + 1] = {
/* GPIOSEL1 - bit 4-7 reserved */
ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
@@ -376,7 +377,7 @@ static struct pullud ab8540_pullud = {
* GPIO43 to GPIO44
* GPIO51 to GPIO54
*/
-struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab8540_gpio_irq_cluster[] = {
GPIO_IRQ_CLUSTER(43, 43, AB8540_INT_GPIO43F),
GPIO_IRQ_CLUSTER(44, 44, AB8540_INT_GPIO44F),
GPIO_IRQ_CLUSTER(51, 54, AB9540_INT_GPIO51R),
diff --git a/drivers/pinctrl/pinctrl-ab9540.c b/drivers/pinctrl/pinctrl-ab9540.c
index 7610bd012b98..1a281ca95dac 100644
--- a/drivers/pinctrl/pinctrl-ab9540.c
+++ b/drivers/pinctrl/pinctrl-ab9540.c
@@ -379,7 +379,8 @@ static const struct abx500_function ab9540_functions[] = {
* alt_A | 1 | 0 | 0
*/
-struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
+static struct
+alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1] = {
/* GPIOSEL1 - bits 4-7 are reserved */
ALTERNATE_FUNCTIONS(0, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO0 */
ALTERNATE_FUNCTIONS(1, 0, UNUSED, UNUSED, 0, 0, 0), /* GPIO1, altA controlled by bit 0 */
@@ -393,7 +394,7 @@ struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1]
/* GPIOSEL2 - bits 0 and 3 are reserved */
ALTERNATE_FUNCTIONS(9, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO9 */
ALTERNATE_FUNCTIONS(10, 1, 0, UNUSED, 1, 0, 0), /* GPIO10, altA and altB controlled by bit 0 */
- ALTERNATE_FUNCTIONS(11, 2, UNUSED, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
+ ALTERNATE_FUNCTIONS(11, 2, 1, UNUSED, 0, 0, 0), /* GPIO11, altA controlled by bit 1 */
ALTERNATE_FUNCTIONS(12, UNUSED, UNUSED, UNUSED, 0, 0, 0), /* no GPIO12 */
ALTERNATE_FUNCTIONS(13, 4, 3, 4, 1, 0, 2), /* GPIO13, altA altB and altC controlled by bit 3 and 4 */
ALTERNATE_FUNCTIONS(14, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO14, altA controlled by bit 5 */
@@ -454,7 +455,7 @@ struct alternate_functions ab9540alternate_functions[AB9540_GPIO_MAX_NUMBER + 1]
ALTERNATE_FUNCTIONS(54, 5, UNUSED, UNUSED, 0, 0, 0), /* GPIO54 = GPIO60, altA controlled by bit 5 */
};
-struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
+static struct abx500_gpio_irq_cluster ab9540_gpio_irq_cluster[] = {
GPIO_IRQ_CLUSTER(10, 13, AB8500_INT_GPIO10R),
GPIO_IRQ_CLUSTER(24, 25, AB8500_INT_GPIO24R),
GPIO_IRQ_CLUSTER(40, 41, AB8500_INT_GPIO40R),
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
index c542a97c82f3..aa17f7580f61 100644
--- a/drivers/pinctrl/pinctrl-abx500.c
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -517,14 +517,14 @@ static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
#define abx500_gpio_dbg_show NULL
#endif
-int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
{
int gpio = chip->base + offset;
return pinctrl_request_gpio(gpio);
}
-void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
{
int gpio = chip->base + offset;
@@ -611,7 +611,7 @@ static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
}
-int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset)
{
@@ -656,7 +656,7 @@ static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
{
}
-static struct pinmux_ops abx500_pinmux_ops = {
+static const struct pinmux_ops abx500_pinmux_ops = {
.get_functions_count = abx500_pmx_get_funcs_cnt,
.get_function_name = abx500_pmx_get_func_name,
.get_function_groups = abx500_pmx_get_func_groups,
@@ -704,21 +704,21 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
chip->base + offset - 1);
}
-static struct pinctrl_ops abx500_pinctrl_ops = {
+static const struct pinctrl_ops abx500_pinctrl_ops = {
.get_groups_count = abx500_get_groups_cnt,
.get_group_name = abx500_get_group_name,
.get_group_pins = abx500_get_group_pins,
.pin_dbg_show = abx500_pin_dbg_show,
};
-int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *config)
{
return -ENOSYS;
}
-int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long config)
{
@@ -778,7 +778,7 @@ int abx500_pin_config_set(struct pinctrl_dev *pctldev,
return ret;
}
-static struct pinconf_ops abx500_pinconf_ops = {
+static const struct pinconf_ops abx500_pinconf_ops = {
.pin_config_get = abx500_pin_config_get,
.pin_config_set = abx500_pin_config_set,
};
@@ -834,6 +834,7 @@ static const struct of_device_id abx500_gpio_match[] = {
{ .compatible = "stericsson,ab8505-gpio", .data = (void *)PINCTRL_AB8505, },
{ .compatible = "stericsson,ab8540-gpio", .data = (void *)PINCTRL_AB8540, },
{ .compatible = "stericsson,ab9540-gpio", .data = (void *)PINCTRL_AB9540, },
+ { }
};
static int abx500_gpio_probe(struct platform_device *pdev)
@@ -879,7 +880,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
pct->parent = dev_get_drvdata(pdev->dev.parent);
pct->chip = abx500gpio_chip;
pct->chip.dev = &pdev->dev;
- pct->chip.base = pdata->gpio_base;
pct->chip.base = (np) ? -1 : pdata->gpio_base;
/* initialize the lock */
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index efb7f10e902a..4d7f531e945d 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -294,7 +294,7 @@ static void at91_dt_free_map(struct pinctrl_dev *pctldev,
{
}
-static struct pinctrl_ops at91_pctrl_ops = {
+static const struct pinctrl_ops at91_pctrl_ops = {
.get_groups_count = at91_get_groups_count,
.get_group_name = at91_get_group_name,
.get_group_pins = at91_get_group_pins,
@@ -303,7 +303,7 @@ static struct pinctrl_ops at91_pctrl_ops = {
.dt_free_map = at91_dt_free_map,
};
-static void __iomem * pin_to_controller(struct at91_pinctrl *info,
+static void __iomem *pin_to_controller(struct at91_pinctrl *info,
unsigned int bank)
{
return gpio_chips[bank]->regbase;
@@ -501,7 +501,7 @@ static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pi
}
}
-static int pin_check_config(struct at91_pinctrl *info, const char* name,
+static int pin_check_config(struct at91_pinctrl *info, const char *name,
int index, const struct at91_pmx_pin *pin)
{
int mux;
@@ -579,7 +579,7 @@ static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
pio = pin_to_controller(info, pin->bank);
mask = pin_to_mask(pin->pin);
at91_mux_disable_interrupt(pio, mask);
- switch(pin->mux) {
+ switch (pin->mux) {
case AT91_MUX_GPIO:
at91_mux_gpio_enable(pio, mask, 1);
break;
@@ -696,7 +696,7 @@ static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
/* Set the pin to some default state, GPIO is usually default */
}
-static struct pinmux_ops at91_pmx_ops = {
+static const struct pinmux_ops at91_pmx_ops = {
.get_functions_count = at91_pmx_get_funcs_count,
.get_function_name = at91_pmx_get_func_name,
.get_function_groups = at91_pmx_get_groups,
@@ -776,7 +776,7 @@ static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
{
}
-static struct pinconf_ops at91_pinconf_ops = {
+static const struct pinconf_ops at91_pinconf_ops = {
.pin_config_get = at91_pinconf_get,
.pin_config_set = at91_pinconf_set,
.pin_config_dbg_show = at91_pinconf_dbg_show,
@@ -812,7 +812,7 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info,
{
int ret = 0;
int size;
- const const __be32 *list;
+ const __be32 *list;
list = of_get_property(np, "atmel,mux-mask", &size);
if (!list) {
@@ -846,7 +846,7 @@ static int at91_pinctrl_parse_groups(struct device_node *np,
{
struct at91_pmx_pin *pin;
int size;
- const const __be32 *list;
+ const __be32 *list;
int i, j;
dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
@@ -944,7 +944,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
return -ENODEV;
info->dev = &pdev->dev;
- info->ops = (struct at91_pinctrl_mux_ops*)
+ info->ops = (struct at91_pinctrl_mux_ops *)
of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
at91_pinctrl_child_count(info, np);
@@ -1002,7 +1002,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
{
struct at91_pinctrl *info;
struct pinctrl_pin_desc *pdesc;
- int ret, i, j ,k;
+ int ret, i, j, k;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -1568,7 +1568,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
goto err;
}
- at91_chip->ops = (struct at91_pinctrl_mux_ops*)
+ at91_chip->ops = (struct at91_pinctrl_mux_ops *)
of_match_device(at91_gpio_of_match, &pdev->dev)->data;
at91_chip->pioc_virq = irq;
at91_chip->pioc_idx = alias_idx;
@@ -1605,7 +1605,8 @@ static int at91_gpio_probe(struct platform_device *pdev)
chip->ngpio = ngpio;
}
- names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL);
+ names = devm_kzalloc(&pdev->dev, sizeof(char *) * chip->ngpio,
+ GFP_KERNEL);
if (!names) {
ret = -ENOMEM;
@@ -1615,7 +1616,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
for (i = 0; i < chip->ngpio; i++)
names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i);
- chip->names = (const char*const*)names;
+ chip->names = (const char *const *)names;
range = &at91_chip->range;
range->name = chip->label;
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index 4eb6d2c4e4df..f28d4b08771a 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -795,7 +795,7 @@ out:
return err;
}
-static struct pinctrl_ops bcm2835_pctl_ops = {
+static const struct pinctrl_ops bcm2835_pctl_ops = {
.get_groups_count = bcm2835_pctl_get_groups_count,
.get_group_name = bcm2835_pctl_get_group_name,
.get_group_pins = bcm2835_pctl_get_group_pins,
@@ -872,7 +872,7 @@ static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinmux_ops bcm2835_pmx_ops = {
+static const struct pinmux_ops bcm2835_pmx_ops = {
.get_functions_count = bcm2835_pmx_get_functions_count,
.get_function_name = bcm2835_pmx_get_function_name,
.get_function_groups = bcm2835_pmx_get_function_groups,
@@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinconf_ops bcm2835_pinconf_ops = {
+static const struct pinconf_ops bcm2835_pinconf_ops = {
.pin_config_get = bcm2835_pinconf_get,
.pin_config_set = bcm2835_pinconf_set,
};
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index 8b7e7bc2226b..edde3acc4186 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -318,13 +318,16 @@ static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
struct u300_gpio_port *port = NULL;
struct list_head *p;
int retirq;
+ bool found = false;
list_for_each(p, &gpio->port_list) {
port = list_entry(p, struct u300_gpio_port, node);
- if (port->number == portno)
+ if (port->number == portno) {
+ found = true;
break;
+ }
}
- if (port == NULL) {
+ if (!found) {
dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
offset);
return -EINVAL;
@@ -359,7 +362,7 @@ int u300_gpio_config_get(struct gpio_chip *chip,
drmode &= (U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1));
drmode >>= ((offset & 0x07) << 1);
- switch(param) {
+ switch (param) {
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
*config = 0;
if (biasmode)
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 538b9ddaadf7..8b10b1ac9071 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -26,6 +26,7 @@
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/err.h>
#include <asm/mach/irq.h>
@@ -33,6 +34,17 @@
#include "pinctrl-samsung.h"
#include "pinctrl-exynos.h"
+
+static struct samsung_pin_bank_type bank_type_off = {
+ .fld_width = { 4, 1, 2, 2, 2, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_alive = {
+ .fld_width = { 4, 1, 2, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
+};
+
/* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = {
{ .compatible = "samsung,exynos4210-wakeup-eint", },
@@ -75,12 +87,14 @@ static void exynos_gpio_irq_ack(struct irq_data *irqd)
static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pin_bank_type *bank_type = bank->type;
struct samsung_pinctrl_drv_data *d = bank->drvdata;
struct samsung_pin_ctrl *ctrl = d->ctrl;
unsigned int pin = irqd->hwirq;
unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
unsigned int con, trig_type;
unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
+ unsigned long flags;
unsigned int mask;
switch (type) {
@@ -114,15 +128,19 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
con |= trig_type << shift;
writel(con, d->virt_base + reg_con);
- reg_con = bank->pctl_offset;
- shift = pin * bank->func_width;
- mask = (1 << bank->func_width) - 1;
+ reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+ shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+ mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+ spin_lock_irqsave(&bank->slock, flags);
con = readl(d->virt_base + reg_con);
con &= ~(mask << shift);
con |= EXYNOS_EINT_FUNC << shift;
writel(con, d->virt_base + reg_con);
+ spin_unlock_irqrestore(&bank->slock, flags);
+
return 0;
}
@@ -253,11 +271,13 @@ static void exynos_wkup_irq_ack(struct irq_data *irqd)
static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pin_bank_type *bank_type = bank->type;
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned int pin = irqd->hwirq;
unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset;
unsigned long shift = EXYNOS_EINT_CON_LEN * pin;
unsigned long con, trig_type;
+ unsigned long flags;
unsigned int mask;
switch (type) {
@@ -291,15 +311,19 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
con |= trig_type << shift;
writel(con, d->virt_base + reg_con);
- reg_con = bank->pctl_offset;
- shift = pin * bank->func_width;
- mask = (1 << bank->func_width) - 1;
+ reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+ shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+ mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+ spin_lock_irqsave(&bank->slock, flags);
con = readl(d->virt_base + reg_con);
con &= ~(mask << shift);
con |= EXYNOS_EINT_FUNC << shift;
writel(con, d->virt_base + reg_con);
+ spin_unlock_irqrestore(&bank->slock, flags);
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 0a708890d8b4..9b1f77a5bf0f 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -48,26 +48,18 @@
#define EXYNOS_PIN_BANK_EINTN(pins, reg, id) \
{ \
+ .type = &bank_type_off, \
.pctl_offset = reg, \
.nr_pins = pins, \
- .func_width = 4, \
- .pud_width = 2, \
- .drv_width = 2, \
- .conpdn_width = 2, \
- .pudpdn_width = 2, \
.eint_type = EINT_TYPE_NONE, \
.name = id \
}
#define EXYNOS_PIN_BANK_EINTG(pins, reg, id, offs) \
{ \
+ .type = &bank_type_off, \
.pctl_offset = reg, \
.nr_pins = pins, \
- .func_width = 4, \
- .pud_width = 2, \
- .drv_width = 2, \
- .conpdn_width = 2, \
- .pudpdn_width = 2, \
.eint_type = EINT_TYPE_GPIO, \
.eint_offset = offs, \
.name = id \
@@ -75,11 +67,9 @@
#define EXYNOS_PIN_BANK_EINTW(pins, reg, id, offs) \
{ \
+ .type = &bank_type_alive, \
.pctl_offset = reg, \
.nr_pins = pins, \
- .func_width = 4, \
- .pud_width = 2, \
- .drv_width = 2, \
.eint_type = EINT_TYPE_WKUP, \
.eint_offset = offs, \
.name = id \
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
index 1376eb7305db..6038503ed929 100644
--- a/drivers/pinctrl/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/pinctrl-exynos5440.c
@@ -20,6 +20,9 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
#include "core.h"
/* EXYNOS5440 GPIO and Pinctrl register offsets */
@@ -37,6 +40,7 @@
#define GPIO_DS1 0x2C
#define EXYNOS5440_MAX_PINS 23
+#define EXYNOS5440_MAX_GPIO_INT 8
#define PIN_NAME_LENGTH 10
#define GROUP_SUFFIX "-grp"
@@ -109,6 +113,7 @@ struct exynos5440_pmx_func {
struct exynos5440_pinctrl_priv_data {
void __iomem *reg_base;
struct gpio_chip *gc;
+ struct irq_domain *irq_domain;
const struct exynos5440_pin_group *pin_groups;
unsigned int nr_groups;
@@ -116,6 +121,16 @@ struct exynos5440_pinctrl_priv_data {
unsigned int nr_functions;
};
+/**
+ * struct exynos5440_gpio_intr_data: private data for gpio interrupts.
+ * @priv: driver's private runtime data.
+ * @gpio_int: gpio interrupt number.
+ */
+struct exynos5440_gpio_intr_data {
+ struct exynos5440_pinctrl_priv_data *priv;
+ unsigned int gpio_int;
+};
+
/* list of all possible config options supported */
static struct pin_config {
char *prop_cfg;
@@ -286,7 +301,7 @@ static void exynos5440_dt_free_map(struct pinctrl_dev *pctldev,
}
/* list of pinctrl callbacks for the pinctrl core */
-static struct pinctrl_ops exynos5440_pctrl_ops = {
+static const struct pinctrl_ops exynos5440_pctrl_ops = {
.get_groups_count = exynos5440_get_group_count,
.get_group_name = exynos5440_get_group_name,
.get_group_pins = exynos5440_get_group_pins,
@@ -374,7 +389,7 @@ static int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
}
/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static struct pinmux_ops exynos5440_pinmux_ops = {
+static const struct pinmux_ops exynos5440_pinmux_ops = {
.get_functions_count = exynos5440_get_functions_count,
.get_function_name = exynos5440_pinmux_get_fname,
.get_function_groups = exynos5440_pinmux_get_groups,
@@ -523,7 +538,7 @@ static int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev,
}
/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static struct pinconf_ops exynos5440_pinconf_ops = {
+static const struct pinconf_ops exynos5440_pinconf_ops = {
.pin_config_get = exynos5440_pinconf_get,
.pin_config_set = exynos5440_pinconf_set,
.pin_config_group_get = exynos5440_pinconf_group_get,
@@ -598,6 +613,22 @@ static int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offse
return 0;
}
+/* gpiolib gpio_to_irq callback function */
+static int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev);
+ unsigned int virq;
+
+ if (offset < 16 || offset > 23)
+ return -ENXIO;
+
+ if (!priv->irq_domain)
+ return -ENXIO;
+
+ virq = irq_create_mapping(priv->irq_domain, offset - 16);
+ return virq ? : -ENXIO;
+}
+
/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */
static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev,
struct device_node *cfg_np, unsigned int **pin_list,
@@ -670,8 +701,10 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np,
&pin_list, &npins);
- if (ret)
- return ret;
+ if (ret) {
+ gname = NULL;
+ goto skip_to_pin_function;
+ }
/* derive pin group name from the node name */
gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN,
@@ -687,6 +720,7 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
grp->num_pins = npins;
grp++;
+skip_to_pin_function:
ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function",
&function);
if (ret)
@@ -709,7 +743,7 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
return -ENOMEM;
}
func->groups[0] = gname;
- func->num_groups = 1;
+ func->num_groups = gname ? 1 : 0;
func->function = function;
func++;
func_idx++;
@@ -818,6 +852,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
gc->get = exynos5440_gpio_get;
gc->direction_input = exynos5440_gpio_direction_input;
gc->direction_output = exynos5440_gpio_direction_output;
+ gc->to_irq = exynos5440_gpio_to_irq;
gc->label = "gpiolib-exynos5440";
gc->owner = THIS_MODULE;
ret = gpiochip_add(gc);
@@ -842,6 +877,110 @@ static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
return 0;
}
+static void exynos5440_gpio_irq_unmask(struct irq_data *irqd)
+{
+ struct exynos5440_pinctrl_priv_data *d;
+ unsigned long gpio_int;
+
+ d = irq_data_get_irq_chip_data(irqd);
+ gpio_int = readl(d->reg_base + GPIO_INT);
+ gpio_int |= 1 << irqd->hwirq;
+ writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+static void exynos5440_gpio_irq_mask(struct irq_data *irqd)
+{
+ struct exynos5440_pinctrl_priv_data *d;
+ unsigned long gpio_int;
+
+ d = irq_data_get_irq_chip_data(irqd);
+ gpio_int = readl(d->reg_base + GPIO_INT);
+ gpio_int &= ~(1 << irqd->hwirq);
+ writel(gpio_int, d->reg_base + GPIO_INT);
+}
+
+/* irq_chip for gpio interrupts */
+static struct irq_chip exynos5440_gpio_irq_chip = {
+ .name = "exynos5440_gpio_irq_chip",
+ .irq_unmask = exynos5440_gpio_irq_unmask,
+ .irq_mask = exynos5440_gpio_irq_mask,
+};
+
+/* interrupt handler for GPIO interrupts 0..7 */
+static irqreturn_t exynos5440_gpio_irq(int irq, void *data)
+{
+ struct exynos5440_gpio_intr_data *intd = data;
+ struct exynos5440_pinctrl_priv_data *d = intd->priv;
+ int virq;
+
+ virq = irq_linear_revmap(d->irq_domain, intd->gpio_int);
+ if (!virq)
+ return IRQ_NONE;
+ generic_handle_irq(virq);
+ return IRQ_HANDLED;
+}
+
+static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct exynos5440_pinctrl_priv_data *d = h->host_data;
+
+ irq_set_chip_data(virq, d);
+ irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip,
+ handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID);
+ return 0;
+}
+
+/* irq domain callbacks for gpio interrupt controller */
+static const struct irq_domain_ops exynos5440_gpio_irqd_ops = {
+ .map = exynos5440_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+/* setup handling of gpio interrupts */
+static int exynos5440_gpio_irq_init(struct platform_device *pdev,
+ struct exynos5440_pinctrl_priv_data *priv)
+{
+ struct device *dev = &pdev->dev;
+ struct exynos5440_gpio_intr_data *intd;
+ int i, irq, ret;
+
+ intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT,
+ GFP_KERNEL);
+ if (!intd) {
+ dev_err(dev, "failed to allocate memory for gpio intr data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) {
+ irq = irq_of_parse_and_map(dev->of_node, i);
+ if (irq <= 0) {
+ dev_err(dev, "irq parsing failed\n");
+ return -EINVAL;
+ }
+
+ intd->gpio_int = i;
+ intd->priv = priv;
+ ret = devm_request_irq(dev, irq, exynos5440_gpio_irq,
+ 0, dev_name(dev), intd++);
+ if (ret) {
+ dev_err(dev, "irq request failed\n");
+ return -ENXIO;
+ }
+ }
+
+ priv->irq_domain = irq_domain_add_linear(dev->of_node,
+ EXYNOS5440_MAX_GPIO_INT,
+ &exynos5440_gpio_irqd_ops, priv);
+ if (!priv->irq_domain) {
+ dev_err(dev, "failed to create irq domain\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
static int exynos5440_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -854,7 +993,7 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
return -ENODEV;
}
- priv = devm_kzalloc(dev, sizeof(priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(dev, "could not allocate memory for private data\n");
return -ENOMEM;
@@ -880,6 +1019,12 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
return ret;
}
+ ret = exynos5440_gpio_irq_init(pdev, priv);
+ if (ret) {
+ dev_err(dev, "failed to setup gpio interrupts\n");
+ return ret;
+ }
+
platform_set_drvdata(pdev, priv);
dev_info(dev, "EXYNOS5440 pinctrl driver registered\n");
return 0;
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index af97a1f90007..f9b2a1d4854f 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -353,7 +353,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
{
}
-static struct pinconf_ops falcon_pinconf_ops = {
+static const struct pinconf_ops falcon_pinconf_ops = {
.pin_config_get = falcon_pinconf_get,
.pin_config_set = falcon_pinconf_set,
.pin_config_group_get = falcon_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c
index 4cebb9c6c5c5..0ef190449eab 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -207,7 +207,7 @@ static void imx_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops imx_pctrl_ops = {
+static const struct pinctrl_ops imx_pctrl_ops = {
.get_groups_count = imx_get_groups_count,
.get_group_name = imx_get_group_name,
.get_group_pins = imx_get_group_pins,
@@ -299,7 +299,7 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static struct pinmux_ops imx_pmx_ops = {
+static const struct pinmux_ops imx_pmx_ops = {
.get_functions_count = imx_pmx_get_funcs_count,
.get_function_name = imx_pmx_get_func_name,
.get_function_groups = imx_pmx_get_groups,
@@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
}
}
-static struct pinconf_ops imx_pinconf_ops = {
+static const struct pinconf_ops imx_pinconf_ops = {
.pin_config_get = imx_pinconf_get,
.pin_config_set = imx_pinconf_set,
.pin_config_dbg_show = imx_pinconf_dbg_show,
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index a70384611351..615c5002b757 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -169,7 +169,7 @@ static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops ltq_pctrl_ops = {
+static const struct pinctrl_ops ltq_pctrl_ops = {
.get_groups_count = ltq_get_group_count,
.get_group_name = ltq_get_group_name,
.get_group_pins = ltq_get_group_pins,
@@ -311,7 +311,7 @@ static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
return info->apply_mux(pctrldev, mfp, pin_func);
}
-static struct pinmux_ops ltq_pmx_ops = {
+static const struct pinmux_ops ltq_pmx_ops = {
.get_functions_count = ltq_pmx_func_count,
.get_function_name = ltq_pmx_func_name,
.get_function_groups = ltq_pmx_get_groups,
diff --git a/drivers/pinctrl/pinctrl-mmp2.c b/drivers/pinctrl/pinctrl-mmp2.c
deleted file mode 100644
index 4afa56a3a51d..000000000000
--- a/drivers/pinctrl/pinctrl-mmp2.c
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- * linux/drivers/pinctrl/pinmux-mmp2.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- *
- * Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define MMP2_DS_MASK 0x1800
-#define MMP2_DS_SHIFT 11
-#define MMP2_SLEEP_MASK 0x38
-#define MMP2_SLEEP_SELECT (1 << 9)
-#define MMP2_SLEEP_DATA (1 << 8)
-#define MMP2_SLEEP_DIR (1 << 7)
-
-#define MFPR_MMP2(a, r, f0, f1, f2, f3, f4, f5, f6, f7) \
- { \
- .name = #a, \
- .pin = a, \
- .mfpr = r, \
- .func = { \
- MMP2_MUX_##f0, \
- MMP2_MUX_##f1, \
- MMP2_MUX_##f2, \
- MMP2_MUX_##f3, \
- MMP2_MUX_##f4, \
- MMP2_MUX_##f5, \
- MMP2_MUX_##f6, \
- MMP2_MUX_##f7, \
- }, \
- }
-
-#define GRP_MMP2(a, m, p) \
- { .name = a, .mux = MMP2_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 174 pins */
-enum mmp2_pin_list {
- /* 0~168: GPIO0~GPIO168 */
- TWSI4_SCL = 169,
- TWSI4_SDA, /* 170 */
- G_CLKREQ,
- VCXO_REQ,
- VCXO_OUT,
-};
-
-enum mmp2_mux {
- /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
- MMP2_MUX_GPIO = 0,
- MMP2_MUX_G_CLKREQ,
- MMP2_MUX_VCXO_REQ,
- MMP2_MUX_VCXO_OUT,
- MMP2_MUX_KP_MK,
- MMP2_MUX_KP_DK,
- MMP2_MUX_CCIC1,
- MMP2_MUX_CCIC2,
- MMP2_MUX_SPI,
- MMP2_MUX_SSPA2,
- MMP2_MUX_ROT,
- MMP2_MUX_I2S,
- MMP2_MUX_TB,
- MMP2_MUX_CAM2,
- MMP2_MUX_HDMI,
- MMP2_MUX_TWSI2,
- MMP2_MUX_TWSI3,
- MMP2_MUX_TWSI4,
- MMP2_MUX_TWSI5,
- MMP2_MUX_TWSI6,
- MMP2_MUX_UART1,
- MMP2_MUX_UART2,
- MMP2_MUX_UART3,
- MMP2_MUX_UART4,
- MMP2_MUX_SSP1_RX,
- MMP2_MUX_SSP1_FRM,
- MMP2_MUX_SSP1_TXRX,
- MMP2_MUX_SSP2_RX,
- MMP2_MUX_SSP2_FRM,
- MMP2_MUX_SSP1,
- MMP2_MUX_SSP2,
- MMP2_MUX_SSP3,
- MMP2_MUX_SSP4,
- MMP2_MUX_MMC1,
- MMP2_MUX_MMC2,
- MMP2_MUX_MMC3,
- MMP2_MUX_MMC4,
- MMP2_MUX_ULPI,
- MMP2_MUX_AC,
- MMP2_MUX_CA,
- MMP2_MUX_PWM,
- MMP2_MUX_USIM,
- MMP2_MUX_TIPU,
- MMP2_MUX_PLL,
- MMP2_MUX_NAND,
- MMP2_MUX_FSIC,
- MMP2_MUX_SLEEP_IND,
- MMP2_MUX_EXT_DMA,
- MMP2_MUX_ONE_WIRE,
- MMP2_MUX_LCD,
- MMP2_MUX_SMC,
- MMP2_MUX_SMC_INT,
- MMP2_MUX_MSP,
- MMP2_MUX_G_CLKOUT,
- MMP2_MUX_32K_CLKOUT,
- MMP2_MUX_PRI_JTAG,
- MMP2_MUX_AAS_JTAG,
- MMP2_MUX_AAS_GPIO,
- MMP2_MUX_AAS_SPI,
- MMP2_MUX_AAS_TWSI,
- MMP2_MUX_AAS_DEU_EX,
- MMP2_MUX_NONE = 0xffff,
-};
-
-static struct pinctrl_pin_desc mmp2_pads[] = {
- /*
- * The name indicates function 0 of this pin.
- * After reset, function 0 is the default function of pin.
- */
- PINCTRL_PIN(GPIO0, "GPIO0"),
- PINCTRL_PIN(GPIO1, "GPIO1"),
- PINCTRL_PIN(GPIO2, "GPIO2"),
- PINCTRL_PIN(GPIO3, "GPIO3"),
- PINCTRL_PIN(GPIO4, "GPIO4"),
- PINCTRL_PIN(GPIO5, "GPIO5"),
- PINCTRL_PIN(GPIO6, "GPIO6"),
- PINCTRL_PIN(GPIO7, "GPIO7"),
- PINCTRL_PIN(GPIO8, "GPIO8"),
- PINCTRL_PIN(GPIO9, "GPIO9"),
- PINCTRL_PIN(GPIO10, "GPIO10"),
- PINCTRL_PIN(GPIO11, "GPIO11"),
- PINCTRL_PIN(GPIO12, "GPIO12"),
- PINCTRL_PIN(GPIO13, "GPIO13"),
- PINCTRL_PIN(GPIO14, "GPIO14"),
- PINCTRL_PIN(GPIO15, "GPIO15"),
- PINCTRL_PIN(GPIO16, "GPIO16"),
- PINCTRL_PIN(GPIO17, "GPIO17"),
- PINCTRL_PIN(GPIO18, "GPIO18"),
- PINCTRL_PIN(GPIO19, "GPIO19"),
- PINCTRL_PIN(GPIO20, "GPIO20"),
- PINCTRL_PIN(GPIO21, "GPIO21"),
- PINCTRL_PIN(GPIO22, "GPIO22"),
- PINCTRL_PIN(GPIO23, "GPIO23"),
- PINCTRL_PIN(GPIO24, "GPIO24"),
- PINCTRL_PIN(GPIO25, "GPIO25"),
- PINCTRL_PIN(GPIO26, "GPIO26"),
- PINCTRL_PIN(GPIO27, "GPIO27"),
- PINCTRL_PIN(GPIO28, "GPIO28"),
- PINCTRL_PIN(GPIO29, "GPIO29"),
- PINCTRL_PIN(GPIO30, "GPIO30"),
- PINCTRL_PIN(GPIO31, "GPIO31"),
- PINCTRL_PIN(GPIO32, "GPIO32"),
- PINCTRL_PIN(GPIO33, "GPIO33"),
- PINCTRL_PIN(GPIO34, "GPIO34"),
- PINCTRL_PIN(GPIO35, "GPIO35"),
- PINCTRL_PIN(GPIO36, "GPIO36"),
- PINCTRL_PIN(GPIO37, "GPIO37"),
- PINCTRL_PIN(GPIO38, "GPIO38"),
- PINCTRL_PIN(GPIO39, "GPIO39"),
- PINCTRL_PIN(GPIO40, "GPIO40"),
- PINCTRL_PIN(GPIO41, "GPIO41"),
- PINCTRL_PIN(GPIO42, "GPIO42"),
- PINCTRL_PIN(GPIO43, "GPIO43"),
- PINCTRL_PIN(GPIO44, "GPIO44"),
- PINCTRL_PIN(GPIO45, "GPIO45"),
- PINCTRL_PIN(GPIO46, "GPIO46"),
- PINCTRL_PIN(GPIO47, "GPIO47"),
- PINCTRL_PIN(GPIO48, "GPIO48"),
- PINCTRL_PIN(GPIO49, "GPIO49"),
- PINCTRL_PIN(GPIO50, "GPIO50"),
- PINCTRL_PIN(GPIO51, "GPIO51"),
- PINCTRL_PIN(GPIO52, "GPIO52"),
- PINCTRL_PIN(GPIO53, "GPIO53"),
- PINCTRL_PIN(GPIO54, "GPIO54"),
- PINCTRL_PIN(GPIO55, "GPIO55"),
- PINCTRL_PIN(GPIO56, "GPIO56"),
- PINCTRL_PIN(GPIO57, "GPIO57"),
- PINCTRL_PIN(GPIO58, "GPIO58"),
- PINCTRL_PIN(GPIO59, "GPIO59"),
- PINCTRL_PIN(GPIO60, "GPIO60"),
- PINCTRL_PIN(GPIO61, "GPIO61"),
- PINCTRL_PIN(GPIO62, "GPIO62"),
- PINCTRL_PIN(GPIO63, "GPIO63"),
- PINCTRL_PIN(GPIO64, "GPIO64"),
- PINCTRL_PIN(GPIO65, "GPIO65"),
- PINCTRL_PIN(GPIO66, "GPIO66"),
- PINCTRL_PIN(GPIO67, "GPIO67"),
- PINCTRL_PIN(GPIO68, "GPIO68"),
- PINCTRL_PIN(GPIO69, "GPIO69"),
- PINCTRL_PIN(GPIO70, "GPIO70"),
- PINCTRL_PIN(GPIO71, "GPIO71"),
- PINCTRL_PIN(GPIO72, "GPIO72"),
- PINCTRL_PIN(GPIO73, "GPIO73"),
- PINCTRL_PIN(GPIO74, "GPIO74"),
- PINCTRL_PIN(GPIO75, "GPIO75"),
- PINCTRL_PIN(GPIO76, "GPIO76"),
- PINCTRL_PIN(GPIO77, "GPIO77"),
- PINCTRL_PIN(GPIO78, "GPIO78"),
- PINCTRL_PIN(GPIO79, "GPIO79"),
- PINCTRL_PIN(GPIO80, "GPIO80"),
- PINCTRL_PIN(GPIO81, "GPIO81"),
- PINCTRL_PIN(GPIO82, "GPIO82"),
- PINCTRL_PIN(GPIO83, "GPIO83"),
- PINCTRL_PIN(GPIO84, "GPIO84"),
- PINCTRL_PIN(GPIO85, "GPIO85"),
- PINCTRL_PIN(GPIO86, "GPIO86"),
- PINCTRL_PIN(GPIO87, "GPIO87"),
- PINCTRL_PIN(GPIO88, "GPIO88"),
- PINCTRL_PIN(GPIO89, "GPIO89"),
- PINCTRL_PIN(GPIO90, "GPIO90"),
- PINCTRL_PIN(GPIO91, "GPIO91"),
- PINCTRL_PIN(GPIO92, "GPIO92"),
- PINCTRL_PIN(GPIO93, "GPIO93"),
- PINCTRL_PIN(GPIO94, "GPIO94"),
- PINCTRL_PIN(GPIO95, "GPIO95"),
- PINCTRL_PIN(GPIO96, "GPIO96"),
- PINCTRL_PIN(GPIO97, "GPIO97"),
- PINCTRL_PIN(GPIO98, "GPIO98"),
- PINCTRL_PIN(GPIO99, "GPIO99"),
- PINCTRL_PIN(GPIO100, "GPIO100"),
- PINCTRL_PIN(GPIO101, "GPIO101"),
- PINCTRL_PIN(GPIO102, "GPIO102"),
- PINCTRL_PIN(GPIO103, "GPIO103"),
- PINCTRL_PIN(GPIO104, "GPIO104"),
- PINCTRL_PIN(GPIO105, "GPIO105"),
- PINCTRL_PIN(GPIO106, "GPIO106"),
- PINCTRL_PIN(GPIO107, "GPIO107"),
- PINCTRL_PIN(GPIO108, "GPIO108"),
- PINCTRL_PIN(GPIO109, "GPIO109"),
- PINCTRL_PIN(GPIO110, "GPIO110"),
- PINCTRL_PIN(GPIO111, "GPIO111"),
- PINCTRL_PIN(GPIO112, "GPIO112"),
- PINCTRL_PIN(GPIO113, "GPIO113"),
- PINCTRL_PIN(GPIO114, "GPIO114"),
- PINCTRL_PIN(GPIO115, "GPIO115"),
- PINCTRL_PIN(GPIO116, "GPIO116"),
- PINCTRL_PIN(GPIO117, "GPIO117"),
- PINCTRL_PIN(GPIO118, "GPIO118"),
- PINCTRL_PIN(GPIO119, "GPIO119"),
- PINCTRL_PIN(GPIO120, "GPIO120"),
- PINCTRL_PIN(GPIO121, "GPIO121"),
- PINCTRL_PIN(GPIO122, "GPIO122"),
- PINCTRL_PIN(GPIO123, "GPIO123"),
- PINCTRL_PIN(GPIO124, "GPIO124"),
- PINCTRL_PIN(GPIO125, "GPIO125"),
- PINCTRL_PIN(GPIO126, "GPIO126"),
- PINCTRL_PIN(GPIO127, "GPIO127"),
- PINCTRL_PIN(GPIO128, "GPIO128"),
- PINCTRL_PIN(GPIO129, "GPIO129"),
- PINCTRL_PIN(GPIO130, "GPIO130"),
- PINCTRL_PIN(GPIO131, "GPIO131"),
- PINCTRL_PIN(GPIO132, "GPIO132"),
- PINCTRL_PIN(GPIO133, "GPIO133"),
- PINCTRL_PIN(GPIO134, "GPIO134"),
- PINCTRL_PIN(GPIO135, "GPIO135"),
- PINCTRL_PIN(GPIO136, "GPIO136"),
- PINCTRL_PIN(GPIO137, "GPIO137"),
- PINCTRL_PIN(GPIO138, "GPIO138"),
- PINCTRL_PIN(GPIO139, "GPIO139"),
- PINCTRL_PIN(GPIO140, "GPIO140"),
- PINCTRL_PIN(GPIO141, "GPIO141"),
- PINCTRL_PIN(GPIO142, "GPIO142"),
- PINCTRL_PIN(GPIO143, "GPIO143"),
- PINCTRL_PIN(GPIO144, "GPIO144"),
- PINCTRL_PIN(GPIO145, "GPIO145"),
- PINCTRL_PIN(GPIO146, "GPIO146"),
- PINCTRL_PIN(GPIO147, "GPIO147"),
- PINCTRL_PIN(GPIO148, "GPIO148"),
- PINCTRL_PIN(GPIO149, "GPIO149"),
- PINCTRL_PIN(GPIO150, "GPIO150"),
- PINCTRL_PIN(GPIO151, "GPIO151"),
- PINCTRL_PIN(GPIO152, "GPIO152"),
- PINCTRL_PIN(GPIO153, "GPIO153"),
- PINCTRL_PIN(GPIO154, "GPIO154"),
- PINCTRL_PIN(GPIO155, "GPIO155"),
- PINCTRL_PIN(GPIO156, "GPIO156"),
- PINCTRL_PIN(GPIO157, "GPIO157"),
- PINCTRL_PIN(GPIO158, "GPIO158"),
- PINCTRL_PIN(GPIO159, "GPIO159"),
- PINCTRL_PIN(GPIO160, "GPIO160"),
- PINCTRL_PIN(GPIO161, "GPIO161"),
- PINCTRL_PIN(GPIO162, "GPIO162"),
- PINCTRL_PIN(GPIO163, "GPIO163"),
- PINCTRL_PIN(GPIO164, "GPIO164"),
- PINCTRL_PIN(GPIO165, "GPIO165"),
- PINCTRL_PIN(GPIO166, "GPIO166"),
- PINCTRL_PIN(GPIO167, "GPIO167"),
- PINCTRL_PIN(GPIO168, "GPIO168"),
- PINCTRL_PIN(TWSI4_SCL, "TWSI4_SCL"),
- PINCTRL_PIN(TWSI4_SDA, "TWSI4_SDA"),
- PINCTRL_PIN(G_CLKREQ, "G_CLKREQ"),
- PINCTRL_PIN(VCXO_REQ, "VCXO_REQ"),
- PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
-};
-
-struct pxa3xx_mfp_pin mmp2_mfp[] = {
- /* pin offs f0 f1 f2 f3 f4 f5 f6 f7 */
- MFPR_MMP2(GPIO0, 0x054, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO1, 0x058, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO2, 0x05C, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO3, 0x060, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO4, 0x064, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO5, 0x068, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO6, 0x06C, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO7, 0x070, GPIO, KP_MK, NONE, SPI, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO8, 0x074, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO9, 0x078, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO10, 0x07C, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO11, 0x080, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO12, 0x084, GPIO, KP_MK, NONE, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO13, 0x088, GPIO, KP_MK, NONE, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO14, 0x08C, GPIO, KP_MK, NONE, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO15, 0x090, GPIO, KP_MK, KP_DK, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO16, 0x094, GPIO, KP_DK, ROT, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO17, 0x098, GPIO, KP_DK, ROT, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO18, 0x09C, GPIO, KP_DK, ROT, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO19, 0x0A0, GPIO, KP_DK, ROT, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO20, 0x0A4, GPIO, KP_DK, TB, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO21, 0x0A8, GPIO, KP_DK, TB, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO22, 0x0AC, GPIO, KP_DK, TB, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO23, 0x0B0, GPIO, KP_DK, TB, CCIC1, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO24, 0x0B4, GPIO, I2S, VCXO_OUT, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO25, 0x0B8, GPIO, I2S, HDMI, SSPA2, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO26, 0x0BC, GPIO, I2S, HDMI, SSPA2, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO27, 0x0C0, GPIO, I2S, HDMI, SSPA2, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO28, 0x0C4, GPIO, I2S, NONE, SSPA2, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO29, 0x0C8, GPIO, UART1, KP_MK, NONE, NONE, NONE, AAS_SPI, NONE),
- MFPR_MMP2(GPIO30, 0x0CC, GPIO, UART1, KP_MK, NONE, NONE, NONE, AAS_SPI, NONE),
- MFPR_MMP2(GPIO31, 0x0D0, GPIO, UART1, KP_MK, NONE, NONE, NONE, AAS_SPI, NONE),
- MFPR_MMP2(GPIO32, 0x0D4, GPIO, UART1, KP_MK, NONE, NONE, NONE, AAS_SPI, NONE),
- MFPR_MMP2(GPIO33, 0x0D8, GPIO, SSPA2, I2S, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO34, 0x0DC, GPIO, SSPA2, I2S, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO35, 0x0E0, GPIO, SSPA2, I2S, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO36, 0x0E4, GPIO, SSPA2, I2S, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO37, 0x0E8, GPIO, MMC2, SSP1, TWSI2, UART2, UART3, AAS_SPI, AAS_TWSI),
- MFPR_MMP2(GPIO38, 0x0EC, GPIO, MMC2, SSP1, TWSI2, UART2, UART3, AAS_SPI, AAS_TWSI),
- MFPR_MMP2(GPIO39, 0x0F0, GPIO, MMC2, SSP1, TWSI2, UART2, UART3, AAS_SPI, AAS_TWSI),
- MFPR_MMP2(GPIO40, 0x0F4, GPIO, MMC2, SSP1, TWSI2, UART2, UART3, AAS_SPI, AAS_TWSI),
- MFPR_MMP2(GPIO41, 0x0F8, GPIO, MMC2, TWSI5, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO42, 0x0FC, GPIO, MMC2, TWSI5, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO43, 0x100, GPIO, TWSI2, UART4, SSP1, UART2, UART3, NONE, AAS_TWSI),
- MFPR_MMP2(GPIO44, 0x104, GPIO, TWSI2, UART4, SSP1, UART2, UART3, NONE, AAS_TWSI),
- MFPR_MMP2(GPIO45, 0x108, GPIO, UART1, UART4, SSP1, UART2, UART3, NONE, NONE),
- MFPR_MMP2(GPIO46, 0x10C, GPIO, UART1, UART4, SSP1, UART2, UART3, NONE, NONE),
- MFPR_MMP2(GPIO47, 0x110, GPIO, UART2, SSP2, TWSI6, CAM2, AAS_SPI, AAS_GPIO, NONE),
- MFPR_MMP2(GPIO48, 0x114, GPIO, UART2, SSP2, TWSI6, CAM2, AAS_SPI, AAS_GPIO, NONE),
- MFPR_MMP2(GPIO49, 0x118, GPIO, UART2, SSP2, PWM, CCIC2, AAS_SPI, NONE, NONE),
- MFPR_MMP2(GPIO50, 0x11C, GPIO, UART2, SSP2, PWM, CCIC2, AAS_SPI, NONE, NONE),
- MFPR_MMP2(GPIO51, 0x120, GPIO, UART3, ROT, AAS_GPIO, PWM, NONE, NONE, NONE),
- MFPR_MMP2(GPIO52, 0x124, GPIO, UART3, ROT, AAS_GPIO, PWM, NONE, NONE, NONE),
- MFPR_MMP2(GPIO53, 0x128, GPIO, UART3, TWSI2, VCXO_REQ, NONE, PWM, NONE, AAS_TWSI),
- MFPR_MMP2(GPIO54, 0x12C, GPIO, UART3, TWSI2, VCXO_OUT, HDMI, PWM, NONE, AAS_TWSI),
- MFPR_MMP2(GPIO55, 0x130, GPIO, SSP2, SSP1, UART2, ROT, TWSI2, SSP3, AAS_TWSI),
- MFPR_MMP2(GPIO56, 0x134, GPIO, SSP2, SSP1, UART2, ROT, TWSI2, KP_DK, AAS_TWSI),
- MFPR_MMP2(GPIO57, 0x138, GPIO, SSP2_RX, SSP1_TXRX, SSP2_FRM, SSP1_RX, VCXO_REQ, KP_DK, NONE),
- MFPR_MMP2(GPIO58, 0x13C, GPIO, SSP2, SSP1_RX, SSP1_FRM, SSP1_TXRX, VCXO_REQ, KP_DK, NONE),
- MFPR_MMP2(GPIO59, 0x280, GPIO, CCIC1, ULPI, MMC3, CCIC2, UART3, UART4, NONE),
- MFPR_MMP2(GPIO60, 0x284, GPIO, CCIC1, ULPI, MMC3, CCIC2, UART3, UART4, NONE),
- MFPR_MMP2(GPIO61, 0x288, GPIO, CCIC1, ULPI, MMC3, CCIC2, UART3, HDMI, NONE),
- MFPR_MMP2(GPIO62, 0x28C, GPIO, CCIC1, ULPI, MMC3, CCIC2, UART3, NONE, NONE),
- MFPR_MMP2(GPIO63, 0x290, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, UART4, NONE),
- MFPR_MMP2(GPIO64, 0x294, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, UART4, NONE),
- MFPR_MMP2(GPIO65, 0x298, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, UART4, NONE),
- MFPR_MMP2(GPIO66, 0x29C, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, UART4, NONE),
- MFPR_MMP2(GPIO67, 0x2A0, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, NONE, NONE),
- MFPR_MMP2(GPIO68, 0x2A4, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, LCD, NONE),
- MFPR_MMP2(GPIO69, 0x2A8, GPIO, CCIC1, ULPI, MMC3, CCIC2, NONE, LCD, NONE),
- MFPR_MMP2(GPIO70, 0x2AC, GPIO, CCIC1, ULPI, MMC3, CCIC2, MSP, LCD, NONE),
- MFPR_MMP2(GPIO71, 0x2B0, GPIO, TWSI3, NONE, PWM, NONE, NONE, LCD, AAS_TWSI),
- MFPR_MMP2(GPIO72, 0x2B4, GPIO, TWSI3, HDMI, PWM, NONE, NONE, LCD, AAS_TWSI),
- MFPR_MMP2(GPIO73, 0x2B8, GPIO, VCXO_REQ, 32K_CLKOUT, PWM, VCXO_OUT, NONE, LCD, NONE),
- MFPR_MMP2(GPIO74, 0x170, GPIO, LCD, SMC, MMC4, SSP3, UART2, UART4, TIPU),
- MFPR_MMP2(GPIO75, 0x174, GPIO, LCD, SMC, MMC4, SSP3, UART2, UART4, TIPU),
- MFPR_MMP2(GPIO76, 0x178, GPIO, LCD, SMC, MMC4, SSP3, UART2, UART4, TIPU),
- MFPR_MMP2(GPIO77, 0x17C, GPIO, LCD, SMC, MMC4, SSP3, UART2, UART4, TIPU),
- MFPR_MMP2(GPIO78, 0x180, GPIO, LCD, HDMI, MMC4, NONE, SSP4, AAS_SPI, TIPU),
- MFPR_MMP2(GPIO79, 0x184, GPIO, LCD, AAS_GPIO, MMC4, NONE, SSP4, AAS_SPI, TIPU),
- MFPR_MMP2(GPIO80, 0x188, GPIO, LCD, AAS_GPIO, MMC4, NONE, SSP4, AAS_SPI, TIPU),
- MFPR_MMP2(GPIO81, 0x18C, GPIO, LCD, AAS_GPIO, MMC4, NONE, SSP4, AAS_SPI, TIPU),
- MFPR_MMP2(GPIO82, 0x190, GPIO, LCD, NONE, MMC4, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO83, 0x194, GPIO, LCD, NONE, MMC4, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO84, 0x198, GPIO, LCD, SMC, MMC2, NONE, TWSI5, AAS_TWSI, TIPU),
- MFPR_MMP2(GPIO85, 0x19C, GPIO, LCD, SMC, MMC2, NONE, TWSI5, AAS_TWSI, TIPU),
- MFPR_MMP2(GPIO86, 0x1A0, GPIO, LCD, SMC, MMC2, NONE, TWSI6, CCIC2, TIPU),
- MFPR_MMP2(GPIO87, 0x1A4, GPIO, LCD, SMC, MMC2, NONE, TWSI6, CCIC2, TIPU),
- MFPR_MMP2(GPIO88, 0x1A8, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO89, 0x1AC, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO90, 0x1B0, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO91, 0x1B4, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO92, 0x1B8, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO93, 0x1BC, GPIO, LCD, AAS_GPIO, MMC2, NONE, NONE, CCIC2, TIPU),
- MFPR_MMP2(GPIO94, 0x1C0, GPIO, LCD, AAS_GPIO, SPI, NONE, AAS_SPI, CCIC2, TIPU),
- MFPR_MMP2(GPIO95, 0x1C4, GPIO, LCD, TWSI3, SPI, AAS_DEU_EX, AAS_SPI, CCIC2, TIPU),
- MFPR_MMP2(GPIO96, 0x1C8, GPIO, LCD, TWSI3, SPI, AAS_DEU_EX, AAS_SPI, NONE, TIPU),
- MFPR_MMP2(GPIO97, 0x1CC, GPIO, LCD, TWSI6, SPI, AAS_DEU_EX, AAS_SPI, NONE, TIPU),
- MFPR_MMP2(GPIO98, 0x1D0, GPIO, LCD, TWSI6, SPI, ONE_WIRE, NONE, NONE, TIPU),
- MFPR_MMP2(GPIO99, 0x1D4, GPIO, LCD, SMC, SPI, TWSI5, NONE, NONE, TIPU),
- MFPR_MMP2(GPIO100, 0x1D8, GPIO, LCD, SMC, SPI, TWSI5, NONE, NONE, TIPU),
- MFPR_MMP2(GPIO101, 0x1DC, GPIO, LCD, SMC, SPI, NONE, NONE, NONE, TIPU),
- MFPR_MMP2(GPIO102, 0x000, USIM, GPIO, FSIC, KP_DK, LCD, NONE, NONE, NONE),
- MFPR_MMP2(GPIO103, 0x004, USIM, GPIO, FSIC, KP_DK, LCD, NONE, NONE, NONE),
- MFPR_MMP2(GPIO104, 0x1FC, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO105, 0x1F8, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO106, 0x1F4, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO107, 0x1F0, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO108, 0x21C, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO109, 0x218, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO110, 0x214, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO111, 0x200, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO112, 0x244, NAND, GPIO, MMC3, SMC, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO113, 0x25C, SMC, GPIO, EXT_DMA, MMC3, SMC, HDMI, NONE, NONE),
- MFPR_MMP2(GPIO114, 0x164, G_CLKOUT, 32K_CLKOUT, HDMI, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO115, 0x260, GPIO, NONE, AC, UART4, UART3, SSP1, NONE, NONE),
- MFPR_MMP2(GPIO116, 0x264, GPIO, NONE, AC, UART4, UART3, SSP1, NONE, NONE),
- MFPR_MMP2(GPIO117, 0x268, GPIO, NONE, AC, UART4, UART3, SSP1, NONE, NONE),
- MFPR_MMP2(GPIO118, 0x26C, GPIO, NONE, AC, UART4, UART3, SSP1, NONE, NONE),
- MFPR_MMP2(GPIO119, 0x270, GPIO, NONE, CA, SSP3, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO120, 0x274, GPIO, NONE, CA, SSP3, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO121, 0x278, GPIO, NONE, CA, SSP3, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO122, 0x27C, GPIO, NONE, CA, SSP3, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO123, 0x148, GPIO, SLEEP_IND, ONE_WIRE, 32K_CLKOUT, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO124, 0x00C, GPIO, MMC1, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO125, 0x010, GPIO, MMC1, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO126, 0x014, GPIO, MMC1, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO127, 0x018, GPIO, NONE, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO128, 0x01C, GPIO, NONE, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO129, 0x020, GPIO, MMC1, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO130, 0x024, GPIO, MMC1, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO131, 0x028, GPIO, MMC1, NONE, MSP, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO132, 0x02C, GPIO, MMC1, PRI_JTAG, MSP, SSP3, AAS_JTAG, NONE, NONE),
- MFPR_MMP2(GPIO133, 0x030, GPIO, MMC1, PRI_JTAG, MSP, SSP3, AAS_JTAG, NONE, NONE),
- MFPR_MMP2(GPIO134, 0x034, GPIO, MMC1, PRI_JTAG, MSP, SSP3, AAS_JTAG, NONE, NONE),
- MFPR_MMP2(GPIO135, 0x038, GPIO, NONE, LCD, MMC3, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO136, 0x03C, GPIO, MMC1, PRI_JTAG, MSP, SSP3, AAS_JTAG, NONE, NONE),
- MFPR_MMP2(GPIO137, 0x040, GPIO, HDMI, LCD, MSP, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO138, 0x044, GPIO, NONE, LCD, MMC3, SMC, NONE, NONE, NONE),
- MFPR_MMP2(GPIO139, 0x048, GPIO, MMC1, PRI_JTAG, MSP, NONE, AAS_JTAG, NONE, NONE),
- MFPR_MMP2(GPIO140, 0x04C, GPIO, MMC1, LCD, NONE, NONE, UART2, UART1, NONE),
- MFPR_MMP2(GPIO141, 0x050, GPIO, MMC1, LCD, NONE, NONE, UART2, UART1, NONE),
- MFPR_MMP2(GPIO142, 0x008, USIM, GPIO, FSIC, KP_DK, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO143, 0x220, NAND, GPIO, SMC, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO144, 0x224, NAND, GPIO, SMC_INT, SMC, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO145, 0x228, SMC, GPIO, NONE, NONE, SMC, NONE, NONE, NONE),
- MFPR_MMP2(GPIO146, 0x22C, SMC, GPIO, NONE, NONE, SMC, NONE, NONE, NONE),
- MFPR_MMP2(GPIO147, 0x230, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO148, 0x234, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO149, 0x238, NAND, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO150, 0x23C, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO151, 0x240, SMC, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO152, 0x248, SMC, GPIO, NONE, NONE, SMC, NONE, NONE, NONE),
- MFPR_MMP2(GPIO153, 0x24C, SMC, GPIO, NONE, NONE, SMC, NONE, NONE, NONE),
- MFPR_MMP2(GPIO154, 0x254, SMC_INT, GPIO, SMC, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO155, 0x258, EXT_DMA, GPIO, SMC, NONE, EXT_DMA, NONE, NONE, NONE),
- MFPR_MMP2(GPIO156, 0x14C, PRI_JTAG, GPIO, PWM, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO157, 0x150, PRI_JTAG, GPIO, PWM, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO158, 0x154, PRI_JTAG, GPIO, PWM, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO159, 0x158, PRI_JTAG, GPIO, PWM, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO160, 0x250, NAND, GPIO, SMC, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO161, 0x210, NAND, GPIO, NONE, NONE, NAND, NONE, NONE, NONE),
- MFPR_MMP2(GPIO162, 0x20C, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO163, 0x208, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO164, 0x204, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO165, 0x1EC, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO166, 0x1E8, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO167, 0x1E4, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(GPIO168, 0x1E0, NAND, GPIO, MMC3, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(TWSI4_SCL, 0x2BC, TWSI4, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(TWSI4_SDA, 0x2C0, TWSI4, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(G_CLKREQ, 0x160, G_CLKREQ, ONE_WIRE, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(VCXO_REQ, 0x168, VCXO_REQ, ONE_WIRE, PLL, NONE, NONE, NONE, NONE, NONE),
- MFPR_MMP2(VCXO_OUT, 0x16C, VCXO_OUT, 32K_CLKOUT, NONE, NONE, NONE, NONE, NONE, NONE),
-};
-
-static const unsigned mmp2_uart1_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned mmp2_uart1_pin2[] = {GPIO45, GPIO46};
-static const unsigned mmp2_uart1_pin3[] = {GPIO140, GPIO141};
-static const unsigned mmp2_uart2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_uart2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned mmp2_uart2_pin4[] = {GPIO74, GPIO75, GPIO76, GPIO77};
-static const unsigned mmp2_uart2_pin5[] = {GPIO55, GPIO56};
-static const unsigned mmp2_uart2_pin6[] = {GPIO140, GPIO141};
-static const unsigned mmp2_uart3_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_uart3_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart3_pin3[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned mmp2_uart3_pin4[] = {GPIO59, GPIO60, GPIO61, GPIO62};
-static const unsigned mmp2_uart3_pin5[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_uart3_pin6[] = {GPIO51, GPIO52};
-static const unsigned mmp2_uart4_pin1[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_uart4_pin2[] = {GPIO63, GPIO64, GPIO65, GPIO66};
-static const unsigned mmp2_uart4_pin3[] = {GPIO74, GPIO75, GPIO76, GPIO77};
-static const unsigned mmp2_uart4_pin4[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_uart4_pin5[] = {GPIO59, GPIO60};
-static const unsigned mmp2_kpdk_pin1[] = {GPIO16, GPIO17, GPIO18, GPIO19};
-static const unsigned mmp2_kpdk_pin2[] = {GPIO16, GPIO17};
-static const unsigned mmp2_twsi2_pin1[] = {GPIO37, GPIO38};
-static const unsigned mmp2_twsi2_pin2[] = {GPIO39, GPIO40};
-static const unsigned mmp2_twsi2_pin3[] = {GPIO43, GPIO44};
-static const unsigned mmp2_twsi2_pin4[] = {GPIO53, GPIO54};
-static const unsigned mmp2_twsi2_pin5[] = {GPIO55, GPIO56};
-static const unsigned mmp2_twsi3_pin1[] = {GPIO71, GPIO72};
-static const unsigned mmp2_twsi3_pin2[] = {GPIO95, GPIO96};
-static const unsigned mmp2_twsi4_pin1[] = {TWSI4_SCL, TWSI4_SDA};
-static const unsigned mmp2_twsi5_pin1[] = {GPIO41, GPIO42};
-static const unsigned mmp2_twsi5_pin2[] = {GPIO84, GPIO85};
-static const unsigned mmp2_twsi5_pin3[] = {GPIO99, GPIO100};
-static const unsigned mmp2_twsi6_pin1[] = {GPIO47, GPIO48};
-static const unsigned mmp2_twsi6_pin2[] = {GPIO86, GPIO87};
-static const unsigned mmp2_twsi6_pin3[] = {GPIO97, GPIO98};
-static const unsigned mmp2_ccic1_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
- GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23};
-static const unsigned mmp2_ccic1_pin2[] = {GPIO59, GPIO60, GPIO61, GPIO62,
- GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ccic2_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
- GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ccic2_pin2[] = {GPIO82, GPIO83, GPIO86, GPIO87,
- GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94, GPIO95};
-static const unsigned mmp2_ulpi_pin1[] = {GPIO59, GPIO60, GPIO61, GPIO62,
- GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70};
-static const unsigned mmp2_ro_pin1[] = {GPIO16, GPIO17};
-static const unsigned mmp2_ro_pin2[] = {GPIO18, GPIO19};
-static const unsigned mmp2_ro_pin3[] = {GPIO51, GPIO52};
-static const unsigned mmp2_ro_pin4[] = {GPIO55, GPIO56};
-static const unsigned mmp2_i2s_pin1[] = {GPIO24, GPIO25, GPIO26, GPIO27,
- GPIO28};
-static const unsigned mmp2_i2s_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned mmp2_ssp1_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40};
-static const unsigned mmp2_ssp1_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned mmp2_ssp1_pin3[] = {GPIO115, GPIO116, GPIO117, GPIO118};
-static const unsigned mmp2_ssp2_pin1[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned mmp2_ssp3_pin1[] = {GPIO119, GPIO120, GPIO121, GPIO122};
-static const unsigned mmp2_ssp3_pin2[] = {GPIO132, GPIO133, GPIO133, GPIO136};
-static const unsigned mmp2_sspa2_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
-static const unsigned mmp2_sspa2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned mmp2_mmc1_pin1[] = {GPIO131, GPIO132, GPIO133, GPIO134,
- GPIO136, GPIO139, GPIO140, GPIO141};
-static const unsigned mmp2_mmc2_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
- GPIO41, GPIO42};
-static const unsigned mmp2_mmc3_pin1[] = {GPIO111, GPIO112, GPIO151, GPIO162,
- GPIO163, GPIO164, GPIO165, GPIO166, GPIO167, GPIO168};
-
-static struct pxa3xx_pin_group mmp2_grps[] = {
- GRP_MMP2("uart1 4p1", UART1, mmp2_uart1_pin1),
- GRP_MMP2("uart1 2p2", UART1, mmp2_uart1_pin2),
- GRP_MMP2("uart1 2p3", UART1, mmp2_uart1_pin3),
- GRP_MMP2("uart2 4p1", UART2, mmp2_uart2_pin1),
- GRP_MMP2("uart2 4p2", UART2, mmp2_uart2_pin2),
- GRP_MMP2("uart2 4p3", UART2, mmp2_uart2_pin3),
- GRP_MMP2("uart2 4p4", UART2, mmp2_uart2_pin4),
- GRP_MMP2("uart2 2p5", UART2, mmp2_uart2_pin5),
- GRP_MMP2("uart2 2p6", UART2, mmp2_uart2_pin6),
- GRP_MMP2("uart3 4p1", UART3, mmp2_uart3_pin1),
- GRP_MMP2("uart3 4p2", UART3, mmp2_uart3_pin2),
- GRP_MMP2("uart3 4p3", UART3, mmp2_uart3_pin3),
- GRP_MMP2("uart3 4p4", UART3, mmp2_uart3_pin4),
- GRP_MMP2("uart3 4p5", UART3, mmp2_uart3_pin5),
- GRP_MMP2("uart3 2p6", UART3, mmp2_uart3_pin6),
- GRP_MMP2("uart4 4p1", UART4, mmp2_uart4_pin1),
- GRP_MMP2("uart4 4p2", UART4, mmp2_uart4_pin2),
- GRP_MMP2("uart4 4p3", UART4, mmp2_uart4_pin3),
- GRP_MMP2("uart4 4p4", UART4, mmp2_uart4_pin4),
- GRP_MMP2("uart4 2p5", UART4, mmp2_uart4_pin5),
- GRP_MMP2("kpdk 4p1", KP_DK, mmp2_kpdk_pin1),
- GRP_MMP2("kpdk 4p2", KP_DK, mmp2_kpdk_pin2),
- GRP_MMP2("twsi2-1", TWSI2, mmp2_twsi2_pin1),
- GRP_MMP2("twsi2-2", TWSI2, mmp2_twsi2_pin2),
- GRP_MMP2("twsi2-3", TWSI2, mmp2_twsi2_pin3),
- GRP_MMP2("twsi2-4", TWSI2, mmp2_twsi2_pin4),
- GRP_MMP2("twsi2-5", TWSI2, mmp2_twsi2_pin5),
- GRP_MMP2("twsi3-1", TWSI3, mmp2_twsi3_pin1),
- GRP_MMP2("twsi3-2", TWSI3, mmp2_twsi3_pin2),
- GRP_MMP2("twsi4", TWSI4, mmp2_twsi4_pin1),
- GRP_MMP2("twsi5-1", TWSI5, mmp2_twsi5_pin1),
- GRP_MMP2("twsi5-2", TWSI5, mmp2_twsi5_pin2),
- GRP_MMP2("twsi5-3", TWSI5, mmp2_twsi5_pin3),
- GRP_MMP2("twsi6-1", TWSI6, mmp2_twsi6_pin1),
- GRP_MMP2("twsi6-2", TWSI6, mmp2_twsi6_pin2),
- GRP_MMP2("twsi6-3", TWSI6, mmp2_twsi6_pin3),
- GRP_MMP2("ccic1-1", CCIC1, mmp2_ccic1_pin1),
- GRP_MMP2("ccic1-2", CCIC1, mmp2_ccic1_pin2),
- GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin1),
- GRP_MMP2("ccic2-1", CCIC2, mmp2_ccic2_pin2),
- GRP_MMP2("ulpi", ULPI, mmp2_ulpi_pin1),
- GRP_MMP2("ro-1", ROT, mmp2_ro_pin1),
- GRP_MMP2("ro-2", ROT, mmp2_ro_pin2),
- GRP_MMP2("ro-3", ROT, mmp2_ro_pin3),
- GRP_MMP2("ro-4", ROT, mmp2_ro_pin4),
- GRP_MMP2("i2s 5p1", I2S, mmp2_i2s_pin1),
- GRP_MMP2("i2s 4p2", I2S, mmp2_i2s_pin2),
- GRP_MMP2("ssp1 4p1", SSP1, mmp2_ssp1_pin1),
- GRP_MMP2("ssp1 4p2", SSP1, mmp2_ssp1_pin2),
- GRP_MMP2("ssp1 4p3", SSP1, mmp2_ssp1_pin3),
- GRP_MMP2("ssp2 4p1", SSP2, mmp2_ssp2_pin1),
- GRP_MMP2("ssp3 4p1", SSP3, mmp2_ssp3_pin1),
- GRP_MMP2("ssp3 4p2", SSP3, mmp2_ssp3_pin2),
- GRP_MMP2("sspa2 4p1", SSPA2, mmp2_sspa2_pin1),
- GRP_MMP2("sspa2 4p2", SSPA2, mmp2_sspa2_pin2),
- GRP_MMP2("mmc1 8p1", MMC1, mmp2_mmc1_pin1),
- GRP_MMP2("mmc2 6p1", MMC2, mmp2_mmc2_pin1),
- GRP_MMP2("mmc3 10p1", MMC3, mmp2_mmc3_pin1),
-};
-
-static const char * const mmp2_uart1_grps[] = {"uart1 4p1", "uart1 2p2",
- "uart1 2p3"};
-static const char * const mmp2_uart2_grps[] = {"uart2 4p1", "uart2 4p2",
- "uart2 4p3", "uart2 4p4", "uart2 4p5", "uart2 4p6"};
-static const char * const mmp2_uart3_grps[] = {"uart3 4p1", "uart3 4p2",
- "uart3 4p3", "uart3 4p4", "uart3 4p5", "uart3 2p6"};
-static const char * const mmp2_uart4_grps[] = {"uart4 4p1", "uart4 4p2",
- "uart4 4p3", "uart4 4p4", "uart4 2p5"};
-static const char * const mmp2_kpdk_grps[] = {"kpdk 4p1", "kpdk 4p2"};
-static const char * const mmp2_twsi2_grps[] = {"twsi2-1", "twsi2-2",
- "twsi2-3", "twsi2-4", "twsi2-5"};
-static const char * const mmp2_twsi3_grps[] = {"twsi3-1", "twsi3-2"};
-static const char * const mmp2_twsi4_grps[] = {"twsi4"};
-static const char * const mmp2_twsi5_grps[] = {"twsi5-1", "twsi5-2",
- "twsi5-3"};
-static const char * const mmp2_twsi6_grps[] = {"twsi6-1", "twsi6-2",
- "twsi6-3"};
-static const char * const mmp2_ccic1_grps[] = {"ccic1-1", "ccic1-2"};
-static const char * const mmp2_ccic2_grps[] = {"ccic2-1", "ccic2-2"};
-static const char * const mmp2_ulpi_grps[] = {"ulpi"};
-static const char * const mmp2_ro_grps[] = {"ro-1", "ro-2", "ro-3", "ro-4"};
-static const char * const mmp2_i2s_grps[] = {"i2s 5p1", "i2s 4p2"};
-static const char * const mmp2_ssp1_grps[] = {"ssp1 4p1", "ssp1 4p2",
- "ssp1 4p3"};
-static const char * const mmp2_ssp2_grps[] = {"ssp2 4p1"};
-static const char * const mmp2_ssp3_grps[] = {"ssp3 4p1", "ssp3 4p2"};
-static const char * const mmp2_sspa2_grps[] = {"sspa2 4p1", "sspa2 4p2"};
-static const char * const mmp2_mmc1_grps[] = {"mmc1 8p1"};
-static const char * const mmp2_mmc2_grps[] = {"mmc2 6p1"};
-static const char * const mmp2_mmc3_grps[] = {"mmc3 10p1"};
-
-static struct pxa3xx_pmx_func mmp2_funcs[] = {
- {"uart1", ARRAY_AND_SIZE(mmp2_uart1_grps)},
- {"uart2", ARRAY_AND_SIZE(mmp2_uart2_grps)},
- {"uart3", ARRAY_AND_SIZE(mmp2_uart3_grps)},
- {"uart4", ARRAY_AND_SIZE(mmp2_uart4_grps)},
- {"kpdk", ARRAY_AND_SIZE(mmp2_kpdk_grps)},
- {"twsi2", ARRAY_AND_SIZE(mmp2_twsi2_grps)},
- {"twsi3", ARRAY_AND_SIZE(mmp2_twsi3_grps)},
- {"twsi4", ARRAY_AND_SIZE(mmp2_twsi4_grps)},
- {"twsi5", ARRAY_AND_SIZE(mmp2_twsi5_grps)},
- {"twsi6", ARRAY_AND_SIZE(mmp2_twsi6_grps)},
- {"ccic1", ARRAY_AND_SIZE(mmp2_ccic1_grps)},
- {"ccic2", ARRAY_AND_SIZE(mmp2_ccic2_grps)},
- {"ulpi", ARRAY_AND_SIZE(mmp2_ulpi_grps)},
- {"ro", ARRAY_AND_SIZE(mmp2_ro_grps)},
- {"i2s", ARRAY_AND_SIZE(mmp2_i2s_grps)},
- {"ssp1", ARRAY_AND_SIZE(mmp2_ssp1_grps)},
- {"ssp2", ARRAY_AND_SIZE(mmp2_ssp2_grps)},
- {"ssp3", ARRAY_AND_SIZE(mmp2_ssp3_grps)},
- {"sspa2", ARRAY_AND_SIZE(mmp2_sspa2_grps)},
- {"mmc1", ARRAY_AND_SIZE(mmp2_mmc1_grps)},
- {"mmc2", ARRAY_AND_SIZE(mmp2_mmc2_grps)},
- {"mmc3", ARRAY_AND_SIZE(mmp2_mmc3_grps)},
-};
-
-static struct pinctrl_desc mmp2_pctrl_desc = {
- .name = "mmp2-pinctrl",
- .owner = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info mmp2_info = {
- .mfp = mmp2_mfp,
- .num_mfp = ARRAY_SIZE(mmp2_mfp),
- .grps = mmp2_grps,
- .num_grps = ARRAY_SIZE(mmp2_grps),
- .funcs = mmp2_funcs,
- .num_funcs = ARRAY_SIZE(mmp2_funcs),
- .num_gpio = 169,
- .desc = &mmp2_pctrl_desc,
- .pads = mmp2_pads,
- .num_pads = ARRAY_SIZE(mmp2_pads),
-
- .cputype = PINCTRL_MMP2,
- .ds_mask = MMP2_DS_MASK,
- .ds_shift = MMP2_DS_SHIFT,
-};
-
-static int mmp2_pinmux_probe(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_register(pdev, &mmp2_info);
-}
-
-static int mmp2_pinmux_remove(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver mmp2_pinmux_driver = {
- .driver = {
- .name = "mmp2-pinmux",
- .owner = THIS_MODULE,
- },
- .probe = mmp2_pinmux_probe,
- .remove = mmp2_pinmux_remove,
-};
-
-static int __init mmp2_pinmux_init(void)
-{
- return platform_driver_register(&mmp2_pinmux_driver);
-}
-core_initcall_sync(mmp2_pinmux_init);
-
-static void __exit mmp2_pinmux_exit(void)
-{
- platform_driver_unregister(&mmp2_pinmux_driver);
-}
-module_exit(mmp2_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
index 23af9f1f9c35..b45c4eb35798 100644
--- a/drivers/pinctrl/pinctrl-mxs.c
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -158,7 +158,7 @@ static void mxs_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops mxs_pinctrl_ops = {
+static const struct pinctrl_ops mxs_pinctrl_ops = {
.get_groups_count = mxs_get_groups_count,
.get_group_name = mxs_get_group_name,
.get_group_pins = mxs_get_group_pins,
@@ -219,7 +219,7 @@ static int mxs_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static struct pinmux_ops mxs_pinmux_ops = {
+static const struct pinmux_ops mxs_pinmux_ops = {
.get_functions_count = mxs_pinctrl_get_funcs_count,
.get_function_name = mxs_pinctrl_get_func_name,
.get_function_groups = mxs_pinctrl_get_func_groups,
@@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, "0x%lx", config);
}
-static struct pinconf_ops mxs_pinconf_ops = {
+static const struct pinconf_ops mxs_pinconf_ops = {
.pin_config_get = mxs_pinconf_get,
.pin_config_set = mxs_pinconf_set,
.pin_config_group_get = mxs_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c
index 30b4da91ef7e..c74840729648 100644
--- a/drivers/pinctrl/pinctrl-nomadik-db8500.c
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -466,7 +466,7 @@ static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15,
DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,
DB8500_PIN_AH15 };
static const unsigned mc1_a_2_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AJ15,
- DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,DB8500_PIN_AH15 };
+ DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13, DB8500_PIN_AH15 };
static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
DB8500_PIN_AH12, DB8500_PIN_AH11 };
static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10,
@@ -663,7 +663,7 @@ static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
-#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \
+#define DB8500_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
static const struct nmk_pingroup nmk_db8500_groups[] = {
diff --git a/drivers/pinctrl/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/pinctrl-nomadik-stn8815.c
index 924a3393fa82..ed39dcafd4f8 100644
--- a/drivers/pinctrl/pinctrl-nomadik-stn8815.c
+++ b/drivers/pinctrl/pinctrl-nomadik-stn8815.c
@@ -299,7 +299,7 @@ static const unsigned i2c0_a_1_pins[] = { STN8815_PIN_D3, STN8815_PIN_D2 };
static const unsigned u1_b_1_pins[] = { STN8815_PIN_B16, STN8815_PIN_A16 };
static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 };
-#define STN8815_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \
+#define STN8815_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins, \
.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
static const struct nmk_pingroup nmk_stn8815_groups[] = {
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 36d20293de5c..435bf3078d2c 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -1565,8 +1565,8 @@ static int nmk_dt_add_map_configs(struct pinctrl_map **map,
return 0;
}
-#define NMK_CONFIG_PIN(x,y) { .property = x, .config = y, }
-#define NMK_CONFIG_PIN_ARRAY(x,y) { .property = x, .choice = y, \
+#define NMK_CONFIG_PIN(x, y) { .property = x, .config = y, }
+#define NMK_CONFIG_PIN_ARRAY(x, y) { .property = x, .choice = y, \
.size = ARRAY_SIZE(y), }
static const unsigned long nmk_pin_input_modes[] = {
@@ -1764,7 +1764,7 @@ int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops nmk_pinctrl_ops = {
+static const struct pinctrl_ops nmk_pinctrl_ops = {
.get_groups_count = nmk_get_groups_cnt,
.get_group_name = nmk_get_group_name,
.get_group_pins = nmk_get_group_pins,
@@ -1975,7 +1975,7 @@ static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
/* Set the pin to some default state, GPIO is usually default */
}
-static struct pinmux_ops nmk_pinmux_ops = {
+static const struct pinmux_ops nmk_pinmux_ops = {
.get_functions_count = nmk_pmx_get_funcs_cnt,
.get_function_name = nmk_pmx_get_func_name,
.get_function_groups = nmk_pmx_get_func_groups,
@@ -2068,7 +2068,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
pin, cfg, pullnames[pull], slpmnames[slpm],
output ? "output " : "input",
output ? (val ? "high" : "low") : "",
- lowemi ? "on" : "off" );
+ lowemi ? "on" : "off");
clk_enable(nmk_chip->clk);
bit = pin % NMK_GPIO_PER_CHIP;
@@ -2089,7 +2089,7 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
return 0;
}
-static struct pinconf_ops nmk_pinconf_ops = {
+static const struct pinconf_ops nmk_pinconf_ops = {
.pin_config_get = nmk_pin_config_get,
.pin_config_set = nmk_pin_config_set,
};
@@ -2111,6 +2111,10 @@ static const struct of_device_id nmk_pinctrl_match[] = {
.compatible = "stericsson,nmk-pinctrl",
.data = (void *)PINCTRL_NMK_DB8500,
},
+ {
+ .compatible = "stericsson,nmk-pinctrl-db8540",
+ .data = (void *)PINCTRL_NMK_DB8540,
+ },
{},
};
diff --git a/drivers/pinctrl/pinctrl-pxa168.c b/drivers/pinctrl/pinctrl-pxa168.c
deleted file mode 100644
index d9cd2b457484..000000000000
--- a/drivers/pinctrl/pinctrl-pxa168.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * linux/drivers/pinctrl/pinmux-pxa168.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- *
- * Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define PXA168_DS_MASK 0x1800
-#define PXA168_DS_SHIFT 11
-#define PXA168_SLEEP_MASK 0x38
-#define PXA168_SLEEP_SELECT (1 << 9)
-#define PXA168_SLEEP_DATA (1 << 8)
-#define PXA168_SLEEP_DIR (1 << 7)
-
-#define MFPR_168(a, r, f0, f1, f2, f3, f4, f5, f6, f7) \
- { \
- .name = #a, \
- .pin = a, \
- .mfpr = r, \
- .func = { \
- PXA168_MUX_##f0, \
- PXA168_MUX_##f1, \
- PXA168_MUX_##f2, \
- PXA168_MUX_##f3, \
- PXA168_MUX_##f4, \
- PXA168_MUX_##f5, \
- PXA168_MUX_##f6, \
- PXA168_MUX_##f7, \
- }, \
- }
-
-#define GRP_168(a, m, p) \
- { .name = a, .mux = PXA168_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 131 pins */
-enum pxa168_pin_list {
- /* 0~122: GPIO0~GPIO122 */
- PWR_SCL = 123,
- PWR_SDA,
- TDI,
- TMS,
- TCK,
- TDO,
- TRST,
- WAKEUP = 130,
-};
-
-enum pxa168_mux {
- /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
- PXA168_MUX_GPIO = 0,
- PXA168_MUX_DFIO,
- PXA168_MUX_NAND,
- PXA168_MUX_SMC,
- PXA168_MUX_SMC_CS0,
- PXA168_MUX_SMC_CS1,
- PXA168_MUX_SMC_INT,
- PXA168_MUX_SMC_RDY,
- PXA168_MUX_MMC1,
- PXA168_MUX_MMC2,
- PXA168_MUX_MMC2_CMD,
- PXA168_MUX_MMC2_CLK,
- PXA168_MUX_MMC3,
- PXA168_MUX_MMC3_CMD,
- PXA168_MUX_MMC3_CLK,
- PXA168_MUX_MMC4,
- PXA168_MUX_MSP,
- PXA168_MUX_MSP_DAT3,
- PXA168_MUX_MSP_INS,
- PXA168_MUX_I2C,
- PXA168_MUX_PWRI2C,
- PXA168_MUX_AC97,
- PXA168_MUX_AC97_SYSCLK,
- PXA168_MUX_PWM,
- PXA168_MUX_PWM1,
- PXA168_MUX_XD,
- PXA168_MUX_XP,
- PXA168_MUX_LCD,
- PXA168_MUX_CCIC,
- PXA168_MUX_CF,
- PXA168_MUX_CF_RDY,
- PXA168_MUX_CF_nINPACK,
- PXA168_MUX_CF_nWAIT,
- PXA168_MUX_KP_MKOUT,
- PXA168_MUX_KP_MKIN,
- PXA168_MUX_KP_DK,
- PXA168_MUX_ETH,
- PXA168_MUX_ETH_TX,
- PXA168_MUX_ETH_RX,
- PXA168_MUX_ONE_WIRE,
- PXA168_MUX_UART1,
- PXA168_MUX_UART1_TX,
- PXA168_MUX_UART1_CTS,
- PXA168_MUX_UART1_nRI,
- PXA168_MUX_UART1_DTR,
- PXA168_MUX_UART2,
- PXA168_MUX_UART2_TX,
- PXA168_MUX_UART3,
- PXA168_MUX_UART3_TX,
- PXA168_MUX_UART3_CTS,
- PXA168_MUX_SSP1,
- PXA168_MUX_SSP1_TX,
- PXA168_MUX_SSP2,
- PXA168_MUX_SSP2_TX,
- PXA168_MUX_SSP3,
- PXA168_MUX_SSP3_TX,
- PXA168_MUX_SSP4,
- PXA168_MUX_SSP4_TX,
- PXA168_MUX_SSP5,
- PXA168_MUX_SSP5_TX,
- PXA168_MUX_USB,
- PXA168_MUX_JTAG,
- PXA168_MUX_RESET,
- PXA168_MUX_WAKEUP,
- PXA168_MUX_EXT_32K_IN,
- PXA168_MUX_NONE = 0xffff,
-};
-
-static struct pinctrl_pin_desc pxa168_pads[] = {
- PINCTRL_PIN(GPIO0, "GPIO0"),
- PINCTRL_PIN(GPIO1, "GPIO1"),
- PINCTRL_PIN(GPIO2, "GPIO2"),
- PINCTRL_PIN(GPIO3, "GPIO3"),
- PINCTRL_PIN(GPIO4, "GPIO4"),
- PINCTRL_PIN(GPIO5, "GPIO5"),
- PINCTRL_PIN(GPIO6, "GPIO6"),
- PINCTRL_PIN(GPIO7, "GPIO7"),
- PINCTRL_PIN(GPIO8, "GPIO8"),
- PINCTRL_PIN(GPIO9, "GPIO9"),
- PINCTRL_PIN(GPIO10, "GPIO10"),
- PINCTRL_PIN(GPIO11, "GPIO11"),
- PINCTRL_PIN(GPIO12, "GPIO12"),
- PINCTRL_PIN(GPIO13, "GPIO13"),
- PINCTRL_PIN(GPIO14, "GPIO14"),
- PINCTRL_PIN(GPIO15, "GPIO15"),
- PINCTRL_PIN(GPIO16, "GPIO16"),
- PINCTRL_PIN(GPIO17, "GPIO17"),
- PINCTRL_PIN(GPIO18, "GPIO18"),
- PINCTRL_PIN(GPIO19, "GPIO19"),
- PINCTRL_PIN(GPIO20, "GPIO20"),
- PINCTRL_PIN(GPIO21, "GPIO21"),
- PINCTRL_PIN(GPIO22, "GPIO22"),
- PINCTRL_PIN(GPIO23, "GPIO23"),
- PINCTRL_PIN(GPIO24, "GPIO24"),
- PINCTRL_PIN(GPIO25, "GPIO25"),
- PINCTRL_PIN(GPIO26, "GPIO26"),
- PINCTRL_PIN(GPIO27, "GPIO27"),
- PINCTRL_PIN(GPIO28, "GPIO28"),
- PINCTRL_PIN(GPIO29, "GPIO29"),
- PINCTRL_PIN(GPIO30, "GPIO30"),
- PINCTRL_PIN(GPIO31, "GPIO31"),
- PINCTRL_PIN(GPIO32, "GPIO32"),
- PINCTRL_PIN(GPIO33, "GPIO33"),
- PINCTRL_PIN(GPIO34, "GPIO34"),
- PINCTRL_PIN(GPIO35, "GPIO35"),
- PINCTRL_PIN(GPIO36, "GPIO36"),
- PINCTRL_PIN(GPIO37, "GPIO37"),
- PINCTRL_PIN(GPIO38, "GPIO38"),
- PINCTRL_PIN(GPIO39, "GPIO39"),
- PINCTRL_PIN(GPIO40, "GPIO40"),
- PINCTRL_PIN(GPIO41, "GPIO41"),
- PINCTRL_PIN(GPIO42, "GPIO42"),
- PINCTRL_PIN(GPIO43, "GPIO43"),
- PINCTRL_PIN(GPIO44, "GPIO44"),
- PINCTRL_PIN(GPIO45, "GPIO45"),
- PINCTRL_PIN(GPIO46, "GPIO46"),
- PINCTRL_PIN(GPIO47, "GPIO47"),
- PINCTRL_PIN(GPIO48, "GPIO48"),
- PINCTRL_PIN(GPIO49, "GPIO49"),
- PINCTRL_PIN(GPIO50, "GPIO50"),
- PINCTRL_PIN(GPIO51, "GPIO51"),
- PINCTRL_PIN(GPIO52, "GPIO52"),
- PINCTRL_PIN(GPIO53, "GPIO53"),
- PINCTRL_PIN(GPIO54, "GPIO54"),
- PINCTRL_PIN(GPIO55, "GPIO55"),
- PINCTRL_PIN(GPIO56, "GPIO56"),
- PINCTRL_PIN(GPIO57, "GPIO57"),
- PINCTRL_PIN(GPIO58, "GPIO58"),
- PINCTRL_PIN(GPIO59, "GPIO59"),
- PINCTRL_PIN(GPIO60, "GPIO60"),
- PINCTRL_PIN(GPIO61, "GPIO61"),
- PINCTRL_PIN(GPIO62, "GPIO62"),
- PINCTRL_PIN(GPIO63, "GPIO63"),
- PINCTRL_PIN(GPIO64, "GPIO64"),
- PINCTRL_PIN(GPIO65, "GPIO65"),
- PINCTRL_PIN(GPIO66, "GPIO66"),
- PINCTRL_PIN(GPIO67, "GPIO67"),
- PINCTRL_PIN(GPIO68, "GPIO68"),
- PINCTRL_PIN(GPIO69, "GPIO69"),
- PINCTRL_PIN(GPIO70, "GPIO70"),
- PINCTRL_PIN(GPIO71, "GPIO71"),
- PINCTRL_PIN(GPIO72, "GPIO72"),
- PINCTRL_PIN(GPIO73, "GPIO73"),
- PINCTRL_PIN(GPIO74, "GPIO74"),
- PINCTRL_PIN(GPIO75, "GPIO75"),
- PINCTRL_PIN(GPIO76, "GPIO76"),
- PINCTRL_PIN(GPIO77, "GPIO77"),
- PINCTRL_PIN(GPIO78, "GPIO78"),
- PINCTRL_PIN(GPIO79, "GPIO79"),
- PINCTRL_PIN(GPIO80, "GPIO80"),
- PINCTRL_PIN(GPIO81, "GPIO81"),
- PINCTRL_PIN(GPIO82, "GPIO82"),
- PINCTRL_PIN(GPIO83, "GPIO83"),
- PINCTRL_PIN(GPIO84, "GPIO84"),
- PINCTRL_PIN(GPIO85, "GPIO85"),
- PINCTRL_PIN(GPIO86, "GPIO86"),
- PINCTRL_PIN(GPIO87, "GPIO87"),
- PINCTRL_PIN(GPIO88, "GPIO88"),
- PINCTRL_PIN(GPIO89, "GPIO89"),
- PINCTRL_PIN(GPIO90, "GPIO90"),
- PINCTRL_PIN(GPIO91, "GPIO91"),
- PINCTRL_PIN(GPIO92, "GPIO92"),
- PINCTRL_PIN(GPIO93, "GPIO93"),
- PINCTRL_PIN(GPIO94, "GPIO94"),
- PINCTRL_PIN(GPIO95, "GPIO95"),
- PINCTRL_PIN(GPIO96, "GPIO96"),
- PINCTRL_PIN(GPIO97, "GPIO97"),
- PINCTRL_PIN(GPIO98, "GPIO98"),
- PINCTRL_PIN(GPIO99, "GPIO99"),
- PINCTRL_PIN(GPIO100, "GPIO100"),
- PINCTRL_PIN(GPIO101, "GPIO101"),
- PINCTRL_PIN(GPIO102, "GPIO102"),
- PINCTRL_PIN(GPIO103, "GPIO103"),
- PINCTRL_PIN(GPIO104, "GPIO104"),
- PINCTRL_PIN(GPIO105, "GPIO105"),
- PINCTRL_PIN(GPIO106, "GPIO106"),
- PINCTRL_PIN(GPIO107, "GPIO107"),
- PINCTRL_PIN(GPIO108, "GPIO108"),
- PINCTRL_PIN(GPIO109, "GPIO109"),
- PINCTRL_PIN(GPIO110, "GPIO110"),
- PINCTRL_PIN(GPIO111, "GPIO111"),
- PINCTRL_PIN(GPIO112, "GPIO112"),
- PINCTRL_PIN(GPIO113, "GPIO113"),
- PINCTRL_PIN(GPIO114, "GPIO114"),
- PINCTRL_PIN(GPIO115, "GPIO115"),
- PINCTRL_PIN(GPIO116, "GPIO116"),
- PINCTRL_PIN(GPIO117, "GPIO117"),
- PINCTRL_PIN(GPIO118, "GPIO118"),
- PINCTRL_PIN(GPIO119, "GPIO119"),
- PINCTRL_PIN(GPIO120, "GPIO120"),
- PINCTRL_PIN(GPIO121, "GPIO121"),
- PINCTRL_PIN(GPIO122, "GPIO122"),
- PINCTRL_PIN(PWR_SCL, "PWR_SCL"),
- PINCTRL_PIN(PWR_SDA, "PWR_SDA"),
- PINCTRL_PIN(TDI, "TDI"),
- PINCTRL_PIN(TMS, "TMS"),
- PINCTRL_PIN(TCK, "TCK"),
- PINCTRL_PIN(TDO, "TDO"),
- PINCTRL_PIN(TRST, "TRST"),
- PINCTRL_PIN(WAKEUP, "WAKEUP"),
-};
-
-struct pxa3xx_mfp_pin pxa168_mfp[] = {
- /* pin offs f0 f1 f2 f3 f4 f5 f6 f7 */
- MFPR_168(GPIO0, 0x04C, DFIO, NONE, NONE, MSP, MMC3_CMD, GPIO, MMC3, NONE),
- MFPR_168(GPIO1, 0x050, DFIO, NONE, NONE, MSP, MMC3_CLK, GPIO, MMC3, NONE),
- MFPR_168(GPIO2, 0x054, DFIO, NONE, NONE, MSP, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO3, 0x058, DFIO, NONE, NONE, NONE, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO4, 0x05C, DFIO, NONE, NONE, MSP_DAT3, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO5, 0x060, DFIO, NONE, NONE, MSP, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO6, 0x064, DFIO, NONE, NONE, MSP, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO7, 0x068, DFIO, NONE, NONE, MSP, NONE, GPIO, MMC3, NONE),
- MFPR_168(GPIO8, 0x06C, DFIO, MMC2, UART3_TX, NONE, MMC2_CMD, GPIO, MMC3_CLK, NONE),
- MFPR_168(GPIO9, 0x070, DFIO, MMC2, UART3, NONE, MMC2_CLK, GPIO, MMC3_CMD, NONE),
- MFPR_168(GPIO10, 0x074, DFIO, MMC2, UART3, NONE, NONE, GPIO, MSP_DAT3, NONE),
- MFPR_168(GPIO11, 0x078, DFIO, MMC2, UART3, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO12, 0x07C, DFIO, MMC2, UART3, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO13, 0x080, DFIO, MMC2, UART3, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO14, 0x084, DFIO, MMC2, NONE, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO15, 0x088, DFIO, MMC2, NONE, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO16, 0x08C, GPIO, NAND, SMC_CS0, SMC_CS1, NONE, NONE, MMC3, NONE),
- MFPR_168(GPIO17, 0x090, NAND, NONE, NONE, NONE, NONE, GPIO, MSP, NONE),
- MFPR_168(GPIO18, 0x094, GPIO, NAND, SMC_CS1, SMC_CS0, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO19, 0x098, SMC_CS0, NONE, NONE, CF, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO20, 0x09C, GPIO, NONE, SMC_CS1, CF, CF_RDY, NONE, NONE, NONE),
- MFPR_168(GPIO21, 0x0A0, NAND, MMC2_CLK, NONE, NONE, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO22, 0x0A4, NAND, MMC2_CMD, NONE, NONE, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO23, 0x0A8, SMC, NAND, NONE, CF, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO24, 0x0AC, NAND, NONE, NONE, NONE, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO25, 0x0B0, SMC, NAND, NONE, CF, NONE, GPIO, NONE, NONE),
- MFPR_168(GPIO26, 0x0B4, GPIO, NAND, NONE, NONE, CF, NONE, NONE, NONE),
- MFPR_168(GPIO27, 0x0B8, SMC_INT, NAND, SMC, NONE, SMC_RDY, GPIO, NONE, NONE),
- MFPR_168(GPIO28, 0x0BC, SMC_RDY, MMC4, SMC, CF_RDY, NONE, GPIO, MMC2_CMD, NONE),
- MFPR_168(GPIO29, 0x0C0, SMC, MMC4, NONE, CF, NONE, GPIO, MMC2_CLK, KP_DK),
- MFPR_168(GPIO30, 0x0C4, SMC, MMC4, UART3_TX, CF, NONE, GPIO, MMC2, KP_DK),
- MFPR_168(GPIO31, 0x0C8, SMC, MMC4, UART3, CF, NONE, GPIO, MMC2, KP_DK),
- MFPR_168(GPIO32, 0x0CC, SMC, MMC4, UART3, CF, NONE, GPIO, MMC2, KP_DK),
- MFPR_168(GPIO33, 0x0D0, SMC, MMC4, UART3, CF, CF_nINPACK, GPIO, MMC2, KP_DK),
- MFPR_168(GPIO34, 0x0D4, GPIO, NONE, SMC_CS1, CF, CF_nWAIT, NONE, MMC3, KP_DK),
- MFPR_168(GPIO35, 0x0D8, GPIO, NONE, SMC, CF_nINPACK, NONE, NONE, MMC3_CMD, KP_DK),
- MFPR_168(GPIO36, 0x0DC, GPIO, NONE, SMC, CF_nWAIT, NONE, NONE, MMC3_CLK, KP_DK),
- MFPR_168(GPIO37, 0x000, GPIO, MMC1, NONE, KP_MKOUT, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO38, 0x004, GPIO, MMC1, NONE, KP_MKOUT, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO39, 0x008, GPIO, NONE, NONE, KP_MKOUT, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO40, 0x00C, GPIO, MMC1, MSP, KP_MKOUT, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO41, 0x010, GPIO, MMC1, MSP, NONE, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO42, 0x014, GPIO, I2C, NONE, MSP, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO43, 0x018, GPIO, MMC1, MSP, MSP_INS, NONE, NONE, KP_MKIN, KP_DK),
- MFPR_168(GPIO44, 0x01C, GPIO, MMC1, MSP_DAT3, MSP, CCIC, XP, KP_MKIN, KP_DK),
- MFPR_168(GPIO45, 0x020, GPIO, NONE, NONE, MSP, CCIC, XP, NONE, KP_DK),
- MFPR_168(GPIO46, 0x024, GPIO, MMC1, MSP_INS, MSP, CCIC, NONE, KP_MKOUT, KP_DK),
- MFPR_168(GPIO47, 0x028, GPIO, NONE, NONE, MSP_INS, NONE, XP, NONE, KP_DK),
- MFPR_168(GPIO48, 0x02C, GPIO, MMC1, NONE, MSP_DAT3, CCIC, NONE, NONE, KP_DK),
- MFPR_168(GPIO49, 0x030, GPIO, MMC1, NONE, MSP, NONE, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO50, 0x034, GPIO, I2C, NONE, MSP, CCIC, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO51, 0x038, GPIO, MMC1, NONE, MSP, NONE, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO52, 0x03C, GPIO, MMC1, NONE, MSP, NONE, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO53, 0x040, GPIO, MMC1, NONE, NONE, NONE, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO54, 0x044, GPIO, MMC1, NONE, NONE, CCIC, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO55, 0x048, GPIO, NONE, NONE, MSP, CCIC, XD, KP_MKOUT, NONE),
- MFPR_168(GPIO56, 0x0E0, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO57, 0x0E4, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO58, 0x0E8, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO59, 0x0EC, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO60, 0x0F0, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO61, 0x0F4, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO62, 0x0F8, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO63, 0x0FC, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO64, 0x100, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO65, 0x104, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO66, 0x108, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO67, 0x10C, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO68, 0x110, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO69, 0x114, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO70, 0x118, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO71, 0x11C, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO72, 0x120, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO73, 0x124, GPIO, LCD, NONE, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO74, 0x128, GPIO, LCD, PWM, XD, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO75, 0x12C, GPIO, LCD, PWM, XD, ONE_WIRE, NONE, NONE, NONE),
- MFPR_168(GPIO76, 0x130, GPIO, LCD, PWM, I2C, NONE, NONE, MSP_INS, NONE),
- MFPR_168(GPIO77, 0x134, GPIO, LCD, PWM1, I2C, ONE_WIRE, NONE, XD, NONE),
- MFPR_168(GPIO78, 0x138, GPIO, LCD, NONE, NONE, NONE, MMC4, NONE, NONE),
- MFPR_168(GPIO79, 0x13C, GPIO, LCD, NONE, NONE, ONE_WIRE, MMC4, NONE, NONE),
- MFPR_168(GPIO80, 0x140, GPIO, LCD, NONE, I2C, NONE, MMC4, NONE, NONE),
- MFPR_168(GPIO81, 0x144, GPIO, LCD, NONE, I2C, ONE_WIRE, MMC4, NONE, NONE),
- MFPR_168(GPIO82, 0x148, GPIO, LCD, PWM, NONE, NONE, MMC4, NONE, NONE),
- MFPR_168(GPIO83, 0x14C, GPIO, LCD, PWM, NONE, RESET, MMC4, NONE, NONE),
- MFPR_168(GPIO84, 0x150, GPIO, NONE, PWM, ONE_WIRE, PWM1, NONE, NONE, EXT_32K_IN),
- MFPR_168(GPIO85, 0x154, GPIO, NONE, PWM1, NONE, NONE, NONE, NONE, USB),
- MFPR_168(GPIO86, 0x158, GPIO, MMC2, UART2, NONE, JTAG, ETH_TX, SSP5_TX, SSP5),
- MFPR_168(GPIO87, 0x15C, GPIO, MMC2, UART2, NONE, JTAG, ETH_TX, SSP5, SSP5_TX),
- MFPR_168(GPIO88, 0x160, GPIO, MMC2, UART2, UART2_TX, JTAG, ETH_TX, ETH_RX, SSP5),
- MFPR_168(GPIO89, 0x164, GPIO, MMC2, UART2_TX, UART2, JTAG, ETH_TX, ETH_RX, SSP5),
- MFPR_168(GPIO90, 0x168, GPIO, MMC2, NONE, SSP3, JTAG, ETH_TX, ETH_RX, NONE),
- MFPR_168(GPIO91, 0x16C, GPIO, MMC2, NONE, SSP3, SSP4, ETH_TX, ETH_RX, NONE),
- MFPR_168(GPIO92, 0x170, GPIO, MMC2, NONE, SSP3, SSP3_TX, ETH, NONE, NONE),
- MFPR_168(GPIO93, 0x174, GPIO, MMC2, NONE, SSP3_TX, SSP3, ETH, NONE, NONE),
- MFPR_168(GPIO94, 0x178, GPIO, MMC2_CMD, SSP3, AC97_SYSCLK, AC97, ETH, NONE, NONE),
- MFPR_168(GPIO95, 0x17C, GPIO, MMC2_CLK, NONE, NONE, AC97, ETH, NONE, NONE),
- MFPR_168(GPIO96, 0x180, GPIO, PWM, NONE, MMC2, NONE, ETH_RX, ETH_TX, NONE),
- MFPR_168(GPIO97, 0x184, GPIO, PWM, ONE_WIRE, NONE, NONE, ETH_RX, ETH_TX, NONE),
- MFPR_168(GPIO98, 0x188, GPIO, PWM1, UART3_TX, UART3, NONE, ETH_RX, ETH_TX, NONE),
- MFPR_168(GPIO99, 0x18C, GPIO, ONE_WIRE, UART3, UART3_TX, NONE, ETH_RX, ETH_TX, NONE),
- MFPR_168(GPIO100, 0x190, GPIO, NONE, UART3_CTS, UART3, NONE, ETH, NONE, NONE),
- MFPR_168(GPIO101, 0x194, GPIO, NONE, UART3, UART3_CTS, NONE, ETH, NONE, NONE),
- MFPR_168(GPIO102, 0x198, GPIO, I2C, UART3, SSP4, NONE, NONE, NONE, NONE),
- MFPR_168(GPIO103, 0x19C, GPIO, I2C, UART3, SSP4, SSP2, ETH, NONE, NONE),
- MFPR_168(GPIO104, 0x1A0, GPIO, PWM, UART1, SSP4, SSP4_TX, AC97, KP_MKOUT, NONE),
- MFPR_168(GPIO105, 0x1A4, GPIO, I2C, UART1, SSP4_TX, SSP4, AC97, KP_MKOUT, NONE),
- MFPR_168(GPIO106, 0x1A8, GPIO, I2C, PWM1, AC97_SYSCLK, MMC2, NONE, KP_MKOUT, NONE),
- MFPR_168(GPIO107, 0x1AC, GPIO, UART1_TX, UART1, NONE, SSP2, MSP_DAT3, NONE, KP_MKIN),
- MFPR_168(GPIO108, 0x1B0, GPIO, UART1, UART1_TX, NONE, SSP2_TX, MSP, NONE, KP_MKIN),
- MFPR_168(GPIO109, 0x1B4, GPIO, UART1_CTS, UART1, NONE, AC97_SYSCLK, MSP, NONE, KP_MKIN),
- MFPR_168(GPIO110, 0x1B8, GPIO, UART1, UART1_CTS, NONE, SMC_RDY, MSP, NONE, KP_MKIN),
- MFPR_168(GPIO111, 0x1BC, GPIO, UART1_nRI, UART1, SSP3, SSP2, MSP, XD, KP_MKOUT),
- MFPR_168(GPIO112, 0x1C0, GPIO, UART1_DTR, UART1, ONE_WIRE, SSP2, MSP, XD, KP_MKOUT),
- MFPR_168(GPIO113, 0x1C4, GPIO, NONE, NONE, NONE, NONE, NONE, AC97_SYSCLK, NONE),
- MFPR_168(GPIO114, 0x1C8, GPIO, SSP1, NONE, NONE, NONE, NONE, AC97, NONE),
- MFPR_168(GPIO115, 0x1CC, GPIO, SSP1, NONE, NONE, NONE, NONE, AC97, NONE),
- MFPR_168(GPIO116, 0x1D0, GPIO, SSP1_TX, SSP1, NONE, NONE, NONE, AC97, NONE),
- MFPR_168(GPIO117, 0x1D4, GPIO, SSP1, SSP1_TX, NONE, MMC2_CMD, NONE, AC97, NONE),
- MFPR_168(GPIO118, 0x1D8, GPIO, SSP2, NONE, NONE, MMC2_CLK, NONE, AC97, KP_MKIN),
- MFPR_168(GPIO119, 0x1DC, GPIO, SSP2, NONE, NONE, MMC2, NONE, AC97, KP_MKIN),
- MFPR_168(GPIO120, 0x1E0, GPIO, SSP2, SSP2_TX, NONE, MMC2, NONE, NONE, KP_MKIN),
- MFPR_168(GPIO121, 0x1E4, GPIO, SSP2_TX, SSP2, NONE, MMC2, NONE, NONE, KP_MKIN),
- MFPR_168(GPIO122, 0x1E8, GPIO, AC97_SYSCLK, SSP2, PWM, MMC2, NONE, NONE, NONE),
- MFPR_168(PWR_SCL, 0x1EC, PWRI2C, NONE, NONE, NONE, NONE, NONE, GPIO, MMC4),
- MFPR_168(PWR_SDA, 0x1F0, PWRI2C, NONE, NONE, NONE, NONE, NONE, GPIO, NONE),
- MFPR_168(TDI, 0x1F4, JTAG, PWM1, UART2, MMC4, SSP5, NONE, XD, MMC4),
- MFPR_168(TMS, 0x1F8, JTAG, PWM, UART2, NONE, SSP5, NONE, XD, MMC4),
- MFPR_168(TCK, 0x1FC, JTAG, PWM, UART2, UART2_TX, SSP5, NONE, XD, MMC4),
- MFPR_168(TDO, 0x200, JTAG, PWM, UART2_TX, UART2, SSP5_TX, NONE, XD, MMC4),
- MFPR_168(TRST, 0x204, JTAG, ONE_WIRE, SSP2, SSP3, AC97_SYSCLK, NONE, XD, MMC4),
- MFPR_168(WAKEUP, 0x208, WAKEUP, ONE_WIRE, PWM1, PWM, SSP2, NONE, GPIO, MMC4),
-};
-
-static const unsigned p168_jtag_pin1[] = {TDI, TMS, TCK, TDO, TRST};
-static const unsigned p168_wakeup_pin1[] = {WAKEUP};
-static const unsigned p168_ssp1rx_pin1[] = {GPIO114, GPIO115, GPIO116};
-static const unsigned p168_ssp1tx_pin1[] = {GPIO117};
-static const unsigned p168_ssp4rx_pin1[] = {GPIO102, GPIO103, GPIO104};
-static const unsigned p168_ssp4tx_pin1[] = {GPIO105};
-static const unsigned p168_ssp5rx_pin1[] = {GPIO86, GPIO88, GPIO89};
-static const unsigned p168_ssp5tx_pin1[] = {GPIO87};
-static const unsigned p168_i2c_pin1[] = {GPIO105, GPIO106};
-static const unsigned p168_pwri2c_pin1[] = {PWR_SCL, PWR_SDA};
-static const unsigned p168_mmc1_pin1[] = {GPIO40, GPIO41, GPIO43, GPIO46,
- GPIO49, GPIO51, GPIO52, GPIO53};
-static const unsigned p168_mmc2_data_pin1[] = {GPIO90, GPIO91, GPIO92, GPIO93};
-static const unsigned p168_mmc2_cmd_pin1[] = {GPIO94};
-static const unsigned p168_mmc2_clk_pin1[] = {GPIO95};
-static const unsigned p168_mmc3_data_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
- GPIO4, GPIO5, GPIO6, GPIO7};
-static const unsigned p168_mmc3_cmd_pin1[] = {GPIO9};
-static const unsigned p168_mmc3_clk_pin1[] = {GPIO8};
-static const unsigned p168_eth_pin1[] = {GPIO92, GPIO93, GPIO100, GPIO101,
- GPIO103};
-static const unsigned p168_ethtx_pin1[] = {GPIO86, GPIO87, GPIO88, GPIO89,
- GPIO90, GPIO91};
-static const unsigned p168_ethrx_pin1[] = {GPIO94, GPIO95, GPIO96, GPIO97,
- GPIO98, GPIO99};
-static const unsigned p168_uart1rx_pin1[] = {GPIO107};
-static const unsigned p168_uart1tx_pin1[] = {GPIO108};
-static const unsigned p168_uart3rx_pin1[] = {GPIO98, GPIO100, GPIO101};
-static const unsigned p168_uart3tx_pin1[] = {GPIO99};
-static const unsigned p168_msp_pin1[] = {GPIO40, GPIO41, GPIO42, GPIO43,
- GPIO44, GPIO50};
-static const unsigned p168_ccic_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
- GPIO41, GPIO42, GPIO44, GPIO45, GPIO46, GPIO48, GPIO54, GPIO55};
-static const unsigned p168_xd_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
- GPIO41, GPIO42, GPIO44, GPIO45, GPIO47, GPIO48, GPIO49, GPIO50,
- GPIO51, GPIO52};
-static const unsigned p168_lcd_pin1[] = {GPIO56, GPIO57, GPIO58, GPIO59,
- GPIO60, GPIO61, GPIO62, GPIO63, GPIO64, GPIO65, GPIO66, GPIO67,
- GPIO68, GPIO69, GPIO70, GPIO71, GPIO72, GPIO73, GPIO74, GPIO75,
- GPIO76, GPIO77, GPIO78, GPIO79, GPIO80, GPIO81, GPIO82, GPIO83};
-static const unsigned p168_dfio_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3,
- GPIO4, GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12,
- GPIO13, GPIO14, GPIO15};
-static const unsigned p168_nand_pin1[] = {GPIO16, GPIO17, GPIO21, GPIO22,
- GPIO24, GPIO26};
-static const unsigned p168_smc_pin1[] = {GPIO23, GPIO25, GPIO29, GPIO35,
- GPIO36};
-static const unsigned p168_smccs0_pin1[] = {GPIO18};
-static const unsigned p168_smccs1_pin1[] = {GPIO34};
-static const unsigned p168_smcrdy_pin1[] = {GPIO28};
-static const unsigned p168_ac97sysclk_pin1[] = {GPIO113};
-static const unsigned p168_ac97_pin1[] = {GPIO114, GPIO115, GPIO117, GPIO118,
- GPIO119};
-static const unsigned p168_cf_pin1[] = {GPIO19, GPIO20, GPIO23, GPIO25,
- GPIO28, GPIO29, GPIO30, GPIO31, GPIO32, GPIO33, GPIO34, GPIO35,
- GPIO36};
-static const unsigned p168_kpmkin_pin1[] = {GPIO109, GPIO110, GPIO121};
-static const unsigned p168_kpmkout_pin1[] = {GPIO111, GPIO112};
-static const unsigned p168_gpio86_pin1[] = {WAKEUP};
-static const unsigned p168_gpio86_pin2[] = {GPIO86};
-static const unsigned p168_gpio87_pin1[] = {GPIO87};
-static const unsigned p168_gpio87_pin2[] = {PWR_SDA};
-static const unsigned p168_gpio88_pin1[] = {GPIO88};
-static const unsigned p168_gpio88_pin2[] = {PWR_SCL};
-
-static struct pxa3xx_pin_group pxa168_grps[] = {
- GRP_168("uart1rx-1", UART1, p168_uart1rx_pin1),
- GRP_168("uart1tx-1", UART1_TX, p168_uart1tx_pin1),
- GRP_168("uart3rx-1", UART3, p168_uart3rx_pin1),
- GRP_168("uart3tx-1", UART3_TX, p168_uart3tx_pin1),
- GRP_168("ssp1rx-1", SSP1, p168_ssp1rx_pin1),
- GRP_168("ssp1tx-1", SSP1_TX, p168_ssp1tx_pin1),
- GRP_168("ssp4rx-1", SSP4, p168_ssp4rx_pin1),
- GRP_168("ssp4tx-1", SSP4_TX, p168_ssp4tx_pin1),
- GRP_168("ssp5rx-1", SSP5, p168_ssp5rx_pin1),
- GRP_168("ssp5tx-1", SSP5_TX, p168_ssp5tx_pin1),
- GRP_168("jtag", JTAG, p168_jtag_pin1),
- GRP_168("wakeup", WAKEUP, p168_wakeup_pin1),
- GRP_168("i2c", I2C, p168_i2c_pin1),
- GRP_168("pwri2c", PWRI2C, p168_pwri2c_pin1),
- GRP_168("mmc1 8p1", MMC1, p168_mmc1_pin1),
- GRP_168("mmc2 4p1", MMC2, p168_mmc2_data_pin1),
- GRP_168("mmc2 cmd1", MMC2_CMD, p168_mmc2_cmd_pin1),
- GRP_168("mmc2 clk1", MMC2_CLK, p168_mmc2_clk_pin1),
- GRP_168("mmc3 8p1", MMC3, p168_mmc3_data_pin1),
- GRP_168("mmc3 cmd1", MMC3_CMD, p168_mmc3_cmd_pin1),
- GRP_168("mmc3 clk1", MMC3_CLK, p168_mmc3_clk_pin1),
- GRP_168("eth", ETH, p168_eth_pin1),
- GRP_168("eth rx", ETH_RX, p168_ethrx_pin1),
- GRP_168("eth tx", ETH_TX, p168_ethtx_pin1),
- GRP_168("msp", MSP, p168_msp_pin1),
- GRP_168("ccic", CCIC, p168_ccic_pin1),
- GRP_168("xd", XD, p168_xd_pin1),
- GRP_168("lcd", LCD, p168_lcd_pin1),
- GRP_168("dfio", DFIO, p168_dfio_pin1),
- GRP_168("nand", NAND, p168_nand_pin1),
- GRP_168("smc", SMC, p168_smc_pin1),
- GRP_168("smc cs0", SMC_CS0, p168_smccs0_pin1),
- GRP_168("smc cs1", SMC_CS1, p168_smccs1_pin1),
- GRP_168("smc rdy", SMC_RDY, p168_smcrdy_pin1),
- GRP_168("ac97 sysclk", AC97_SYSCLK, p168_ac97sysclk_pin1),
- GRP_168("ac97", AC97, p168_ac97_pin1),
- GRP_168("cf", CF, p168_cf_pin1),
- GRP_168("kp mkin 3p1", KP_MKIN, p168_kpmkin_pin1),
- GRP_168("kp mkout 2p1", KP_MKOUT, p168_kpmkout_pin1),
- GRP_168("gpio86-1", GPIO, p168_gpio86_pin1),
- GRP_168("gpio86-2", GPIO, p168_gpio86_pin2),
- GRP_168("gpio87-1", GPIO, p168_gpio87_pin1),
- GRP_168("gpio87-2", GPIO, p168_gpio87_pin2),
- GRP_168("gpio88-1", GPIO, p168_gpio88_pin1),
- GRP_168("gpio88-2", GPIO, p168_gpio88_pin2),
-};
-
-static const char * const p168_uart1rx_grps[] = {"uart1rx-1"};
-static const char * const p168_uart1tx_grps[] = {"uart1tx-1"};
-static const char * const p168_uart3rx_grps[] = {"uart3rx-1"};
-static const char * const p168_uart3tx_grps[] = {"uart3tx-1"};
-static const char * const p168_ssp1rx_grps[] = {"ssp1rx-1"};
-static const char * const p168_ssp1tx_grps[] = {"ssp1tx-1"};
-static const char * const p168_ssp4rx_grps[] = {"ssp4rx-1"};
-static const char * const p168_ssp4tx_grps[] = {"ssp4tx-1"};
-static const char * const p168_ssp5rx_grps[] = {"ssp5rx-1"};
-static const char * const p168_ssp5tx_grps[] = {"ssp5tx-1"};
-static const char * const p168_i2c_grps[] = {"i2c"};
-static const char * const p168_pwri2c_grps[] = {"pwri2c"};
-static const char * const p168_mmc1_grps[] = {"mmc1 8p1"};
-static const char * const p168_mmc2_data_grps[] = {"mmc2 4p1"};
-static const char * const p168_mmc2_cmd_grps[] = {"mmc2 cmd1"};
-static const char * const p168_mmc2_clk_grps[] = {"mmc2 clk1"};
-static const char * const p168_mmc3_data_grps[] = {"mmc3 8p1"};
-static const char * const p168_mmc3_cmd_grps[] = {"mmc3 cmd1"};
-static const char * const p168_mmc3_clk_grps[] = {"mmc3 clk1"};
-static const char * const p168_eth_grps[] = {"eth"};
-static const char * const p168_ethrx_grps[] = {"eth rx"};
-static const char * const p168_ethtx_grps[] = {"eth tx"};
-static const char * const p168_msp_grps[] = {"msp"};
-static const char * const p168_ccic_grps[] = {"ccic"};
-static const char * const p168_xd_grps[] = {"xd"};
-static const char * const p168_lcd_grps[] = {"lcd"};
-static const char * const p168_dfio_grps[] = {"dfio"};
-static const char * const p168_nand_grps[] = {"nand"};
-static const char * const p168_smc_grps[] = {"smc"};
-static const char * const p168_smccs0_grps[] = {"smc cs0"};
-static const char * const p168_smccs1_grps[] = {"smc cs1"};
-static const char * const p168_smcrdy_grps[] = {"smc rdy"};
-static const char * const p168_ac97sysclk_grps[] = {"ac97 sysclk"};
-static const char * const p168_ac97_grps[] = {"ac97"};
-static const char * const p168_cf_grps[] = {"cf"};
-static const char * const p168_kpmkin_grps[] = {"kp mkin 3p1"};
-static const char * const p168_kpmkout_grps[] = {"kp mkout 2p1"};
-static const char * const p168_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
-static const char * const p168_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
-static const char * const p168_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
-
-static struct pxa3xx_pmx_func pxa168_funcs[] = {
- {"uart1 rx", ARRAY_AND_SIZE(p168_uart1rx_grps)},
- {"uart1 tx", ARRAY_AND_SIZE(p168_uart1tx_grps)},
- {"uart3 rx", ARRAY_AND_SIZE(p168_uart3rx_grps)},
- {"uart3 tx", ARRAY_AND_SIZE(p168_uart3tx_grps)},
- {"ssp1 rx", ARRAY_AND_SIZE(p168_ssp1rx_grps)},
- {"ssp1 tx", ARRAY_AND_SIZE(p168_ssp1tx_grps)},
- {"ssp4 rx", ARRAY_AND_SIZE(p168_ssp4rx_grps)},
- {"ssp4 tx", ARRAY_AND_SIZE(p168_ssp4tx_grps)},
- {"ssp5 rx", ARRAY_AND_SIZE(p168_ssp5rx_grps)},
- {"ssp5 tx", ARRAY_AND_SIZE(p168_ssp5tx_grps)},
- {"i2c", ARRAY_AND_SIZE(p168_i2c_grps)},
- {"pwri2c", ARRAY_AND_SIZE(p168_pwri2c_grps)},
- {"mmc1", ARRAY_AND_SIZE(p168_mmc1_grps)},
- {"mmc2", ARRAY_AND_SIZE(p168_mmc2_data_grps)},
- {"mmc2 cmd", ARRAY_AND_SIZE(p168_mmc2_cmd_grps)},
- {"mmc2 clk", ARRAY_AND_SIZE(p168_mmc2_clk_grps)},
- {"mmc3", ARRAY_AND_SIZE(p168_mmc3_data_grps)},
- {"mmc3 cmd", ARRAY_AND_SIZE(p168_mmc3_cmd_grps)},
- {"mmc3 clk", ARRAY_AND_SIZE(p168_mmc3_clk_grps)},
- {"eth", ARRAY_AND_SIZE(p168_eth_grps)},
- {"eth rx", ARRAY_AND_SIZE(p168_ethrx_grps)},
- {"eth tx", ARRAY_AND_SIZE(p168_ethtx_grps)},
- {"msp", ARRAY_AND_SIZE(p168_msp_grps)},
- {"ccic", ARRAY_AND_SIZE(p168_ccic_grps)},
- {"xd", ARRAY_AND_SIZE(p168_xd_grps)},
- {"lcd", ARRAY_AND_SIZE(p168_lcd_grps)},
- {"dfio", ARRAY_AND_SIZE(p168_dfio_grps)},
- {"nand", ARRAY_AND_SIZE(p168_nand_grps)},
- {"smc", ARRAY_AND_SIZE(p168_smc_grps)},
- {"smc cs0", ARRAY_AND_SIZE(p168_smccs0_grps)},
- {"smc cs1", ARRAY_AND_SIZE(p168_smccs1_grps)},
- {"smc rdy", ARRAY_AND_SIZE(p168_smcrdy_grps)},
- {"ac97", ARRAY_AND_SIZE(p168_ac97_grps)},
- {"ac97 sysclk", ARRAY_AND_SIZE(p168_ac97sysclk_grps)},
- {"cf", ARRAY_AND_SIZE(p168_cf_grps)},
- {"kpmkin", ARRAY_AND_SIZE(p168_kpmkin_grps)},
- {"kpmkout", ARRAY_AND_SIZE(p168_kpmkout_grps)},
- {"gpio86", ARRAY_AND_SIZE(p168_gpio86_grps)},
- {"gpio87", ARRAY_AND_SIZE(p168_gpio87_grps)},
- {"gpio88", ARRAY_AND_SIZE(p168_gpio88_grps)},
-};
-
-static struct pinctrl_desc pxa168_pctrl_desc = {
- .name = "pxa168-pinctrl",
- .owner = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info pxa168_info = {
- .mfp = pxa168_mfp,
- .num_mfp = ARRAY_SIZE(pxa168_mfp),
- .grps = pxa168_grps,
- .num_grps = ARRAY_SIZE(pxa168_grps),
- .funcs = pxa168_funcs,
- .num_funcs = ARRAY_SIZE(pxa168_funcs),
- .num_gpio = 128,
- .desc = &pxa168_pctrl_desc,
- .pads = pxa168_pads,
- .num_pads = ARRAY_SIZE(pxa168_pads),
-
- .cputype = PINCTRL_PXA168,
- .ds_mask = PXA168_DS_MASK,
- .ds_shift = PXA168_DS_SHIFT,
-};
-
-static int pxa168_pinmux_probe(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_register(pdev, &pxa168_info);
-}
-
-static int pxa168_pinmux_remove(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver pxa168_pinmux_driver = {
- .driver = {
- .name = "pxa168-pinmux",
- .owner = THIS_MODULE,
- },
- .probe = pxa168_pinmux_probe,
- .remove = pxa168_pinmux_remove,
-};
-
-static int __init pxa168_pinmux_init(void)
-{
- return platform_driver_register(&pxa168_pinmux_driver);
-}
-core_initcall_sync(pxa168_pinmux_init);
-
-static void __exit pxa168_pinmux_exit(void)
-{
- platform_driver_unregister(&pxa168_pinmux_driver);
-}
-module_exit(pxa168_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
deleted file mode 100644
index 1f49bb02a6af..000000000000
--- a/drivers/pinctrl/pinctrl-pxa3xx.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * linux/drivers/pinctrl/pinctrl-pxa3xx.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- *
- * Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include "pinctrl-pxa3xx.h"
-
-static struct pinctrl_gpio_range pxa3xx_pinctrl_gpio_range = {
- .name = "PXA3xx GPIO",
- .id = 0,
- .base = 0,
- .pin_base = 0,
-};
-
-static int pxa3xx_get_groups_count(struct pinctrl_dev *pctrldev)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
- return info->num_grps;
-}
-
-static const char *pxa3xx_get_group_name(struct pinctrl_dev *pctrldev,
- unsigned selector)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
- return info->grps[selector].name;
-}
-
-static int pxa3xx_get_group_pins(struct pinctrl_dev *pctrldev,
- unsigned selector,
- const unsigned **pins,
- unsigned *num_pins)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
- *pins = info->grps[selector].pins;
- *num_pins = info->grps[selector].npins;
- return 0;
-}
-
-static struct pinctrl_ops pxa3xx_pctrl_ops = {
- .get_groups_count = pxa3xx_get_groups_count,
- .get_group_name = pxa3xx_get_group_name,
- .get_group_pins = pxa3xx_get_group_pins,
-};
-
-static int pxa3xx_pmx_get_funcs_count(struct pinctrl_dev *pctrldev)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
-
- return info->num_funcs;
-}
-
-static const char *pxa3xx_pmx_get_func_name(struct pinctrl_dev *pctrldev,
- unsigned func)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- return info->funcs[func].name;
-}
-
-static int pxa3xx_pmx_get_groups(struct pinctrl_dev *pctrldev, unsigned func,
- const char * const **groups,
- unsigned * const num_groups)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- *groups = info->funcs[func].groups;
- *num_groups = info->funcs[func].num_groups;
- return 0;
-}
-
-/* Return function number. If failure, return negative value. */
-static int match_mux(struct pxa3xx_mfp_pin *mfp, unsigned mux)
-{
- int i;
- for (i = 0; i < PXA3xx_MAX_MUX; i++) {
- if (mfp->func[i] == mux)
- break;
- }
- if (i >= PXA3xx_MAX_MUX)
- return -EINVAL;
- return i;
-}
-
-/* check whether current pin configuration is valid. Negative for failure */
-static int match_group_mux(struct pxa3xx_pin_group *grp,
- struct pxa3xx_pinmux_info *info,
- unsigned mux)
-{
- int i, pin, ret = 0;
- for (i = 0; i < grp->npins; i++) {
- pin = grp->pins[i];
- ret = match_mux(&info->mfp[pin], mux);
- if (ret < 0) {
- dev_err(info->dev, "Can't find mux %d on pin%d\n",
- mux, pin);
- break;
- }
- }
- return ret;
-}
-
-static int pxa3xx_pmx_enable(struct pinctrl_dev *pctrldev, unsigned func,
- unsigned group)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- struct pxa3xx_pin_group *pin_grp = &info->grps[group];
- unsigned int data;
- int i, mfpr, pin, pin_func;
-
- if (!pin_grp->npins ||
- (match_group_mux(pin_grp, info, pin_grp->mux) < 0)) {
- dev_err(info->dev, "Failed to set the pin group: %d\n", group);
- return -EINVAL;
- }
- for (i = 0; i < pin_grp->npins; i++) {
- pin = pin_grp->pins[i];
- pin_func = match_mux(&info->mfp[pin], pin_grp->mux);
- mfpr = info->mfp[pin].mfpr;
- data = readl_relaxed(info->virt_base + mfpr);
- data &= ~MFPR_FUNC_MASK;
- data |= pin_func;
- writel_relaxed(data, info->virt_base + mfpr);
- }
- return 0;
-}
-
-static int pxa3xx_pmx_request_gpio(struct pinctrl_dev *pctrldev,
- struct pinctrl_gpio_range *range,
- unsigned pin)
-{
- struct pxa3xx_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
- unsigned int data;
- int pin_func, mfpr;
-
- pin_func = match_mux(&info->mfp[pin], PXA3xx_MUX_GPIO);
- if (pin_func < 0) {
- dev_err(info->dev, "No GPIO function on pin%d (%s)\n",
- pin, info->pads[pin].name);
- return -EINVAL;
- }
- mfpr = info->mfp[pin].mfpr;
- /* write gpio function into mfpr register */
- data = readl_relaxed(info->virt_base + mfpr) & ~MFPR_FUNC_MASK;
- data |= pin_func;
- writel_relaxed(data, info->virt_base + mfpr);
- return 0;
-}
-
-static struct pinmux_ops pxa3xx_pmx_ops = {
- .get_functions_count = pxa3xx_pmx_get_funcs_count,
- .get_function_name = pxa3xx_pmx_get_func_name,
- .get_function_groups = pxa3xx_pmx_get_groups,
- .enable = pxa3xx_pmx_enable,
- .gpio_request_enable = pxa3xx_pmx_request_gpio,
-};
-
-int pxa3xx_pinctrl_register(struct platform_device *pdev,
- struct pxa3xx_pinmux_info *info)
-{
- struct pinctrl_desc *desc;
- struct resource *res;
-
- if (!info || !info->cputype)
- return -EINVAL;
- desc = info->desc;
- desc->pins = info->pads;
- desc->npins = info->num_pads;
- desc->pctlops = &pxa3xx_pctrl_ops;
- desc->pmxops = &pxa3xx_pmx_ops;
- info->dev = &pdev->dev;
- pxa3xx_pinctrl_gpio_range.npins = info->num_gpio;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOENT;
- info->virt_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(info->virt_base))
- return PTR_ERR(info->virt_base);
- info->pctrl = pinctrl_register(desc, &pdev->dev, info);
- if (!info->pctrl) {
- dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
- return -EINVAL;
- }
- pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range);
- platform_set_drvdata(pdev, info);
- return 0;
-}
-
-int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
-{
- struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev);
-
- pinctrl_unregister(info->pctrl);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-static int __init pxa3xx_pinctrl_init(void)
-{
- pr_info("pxa3xx-pinctrl: PXA3xx pinctrl driver initializing\n");
- return 0;
-}
-core_initcall_sync(pxa3xx_pinctrl_init);
-
-static void __exit pxa3xx_pinctrl_exit(void)
-{
-}
-module_exit(pxa3xx_pinctrl_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h
deleted file mode 100644
index 92fad0880834..000000000000
--- a/drivers/pinctrl/pinctrl-pxa3xx.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * linux/drivers/pinctrl/pinctrl-pxa3xx.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- *
- * Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#ifndef __PINCTRL_PXA3XX_H
-
-#include <linux/pinctrl/pinctrl.h>
-#include <linux/pinctrl/pinmux.h>
-
-#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
-
-#define PXA3xx_MUX_GPIO 0
-
-#define PXA3xx_MAX_MUX 8
-#define MFPR_FUNC_MASK 0x7
-
-enum pxa_cpu_type {
- PINCTRL_INVALID = 0,
- PINCTRL_PXA300,
- PINCTRL_PXA310,
- PINCTRL_PXA320,
- PINCTRL_PXA168,
- PINCTRL_PXA910,
- PINCTRL_PXA930,
- PINCTRL_PXA955,
- PINCTRL_MMP2,
- PINCTRL_MAX,
-};
-
-struct pxa3xx_mfp_pin {
- const char *name;
- const unsigned int pin;
- const unsigned int mfpr; /* register offset */
- const unsigned short func[8];
-};
-
-struct pxa3xx_pin_group {
- const char *name;
- const unsigned mux;
- const unsigned *pins;
- const unsigned npins;
-};
-
-struct pxa3xx_pmx_func {
- const char *name;
- const char * const * groups;
- const unsigned num_groups;
-};
-
-struct pxa3xx_pinmux_info {
- struct device *dev;
- struct pinctrl_dev *pctrl;
- enum pxa_cpu_type cputype;
- void __iomem *virt_base;
-
- struct pxa3xx_mfp_pin *mfp;
- unsigned int num_mfp;
- struct pxa3xx_pin_group *grps;
- unsigned int num_grps;
- struct pxa3xx_pmx_func *funcs;
- unsigned int num_funcs;
- unsigned int num_gpio;
- struct pinctrl_desc *desc;
- struct pinctrl_pin_desc *pads;
- unsigned int num_pads;
-
- unsigned ds_mask; /* drive strength mask */
- unsigned ds_shift; /* drive strength shift */
- unsigned slp_mask; /* sleep mask */
- unsigned slp_input_low;
- unsigned slp_input_high;
- unsigned slp_output_low;
- unsigned slp_output_high;
- unsigned slp_float;
-};
-
-enum pxa3xx_pin_list {
- GPIO0 = 0,
- GPIO1,
- GPIO2,
- GPIO3,
- GPIO4,
- GPIO5,
- GPIO6,
- GPIO7,
- GPIO8,
- GPIO9,
- GPIO10, /* 10 */
- GPIO11,
- GPIO12,
- GPIO13,
- GPIO14,
- GPIO15,
- GPIO16,
- GPIO17,
- GPIO18,
- GPIO19,
- GPIO20, /* 20 */
- GPIO21,
- GPIO22,
- GPIO23,
- GPIO24,
- GPIO25,
- GPIO26,
- GPIO27,
- GPIO28,
- GPIO29,
- GPIO30, /* 30 */
- GPIO31,
- GPIO32,
- GPIO33,
- GPIO34,
- GPIO35,
- GPIO36,
- GPIO37,
- GPIO38,
- GPIO39,
- GPIO40, /* 40 */
- GPIO41,
- GPIO42,
- GPIO43,
- GPIO44,
- GPIO45,
- GPIO46,
- GPIO47,
- GPIO48,
- GPIO49,
- GPIO50, /* 50 */
- GPIO51,
- GPIO52,
- GPIO53,
- GPIO54,
- GPIO55,
- GPIO56,
- GPIO57,
- GPIO58,
- GPIO59,
- GPIO60, /* 60 */
- GPIO61,
- GPIO62,
- GPIO63,
- GPIO64,
- GPIO65,
- GPIO66,
- GPIO67,
- GPIO68,
- GPIO69,
- GPIO70, /* 70 */
- GPIO71,
- GPIO72,
- GPIO73,
- GPIO74,
- GPIO75,
- GPIO76,
- GPIO77,
- GPIO78,
- GPIO79,
- GPIO80, /* 80 */
- GPIO81,
- GPIO82,
- GPIO83,
- GPIO84,
- GPIO85,
- GPIO86,
- GPIO87,
- GPIO88,
- GPIO89,
- GPIO90, /* 90 */
- GPIO91,
- GPIO92,
- GPIO93,
- GPIO94,
- GPIO95,
- GPIO96,
- GPIO97,
- GPIO98,
- GPIO99,
- GPIO100, /* 100 */
- GPIO101,
- GPIO102,
- GPIO103,
- GPIO104,
- GPIO105,
- GPIO106,
- GPIO107,
- GPIO108,
- GPIO109,
- GPIO110, /* 110 */
- GPIO111,
- GPIO112,
- GPIO113,
- GPIO114,
- GPIO115,
- GPIO116,
- GPIO117,
- GPIO118,
- GPIO119,
- GPIO120, /* 120 */
- GPIO121,
- GPIO122,
- GPIO123,
- GPIO124,
- GPIO125,
- GPIO126,
- GPIO127,
- GPIO128,
- GPIO129,
- GPIO130, /* 130 */
- GPIO131,
- GPIO132,
- GPIO133,
- GPIO134,
- GPIO135,
- GPIO136,
- GPIO137,
- GPIO138,
- GPIO139,
- GPIO140, /* 140 */
- GPIO141,
- GPIO142,
- GPIO143,
- GPIO144,
- GPIO145,
- GPIO146,
- GPIO147,
- GPIO148,
- GPIO149,
- GPIO150, /* 150 */
- GPIO151,
- GPIO152,
- GPIO153,
- GPIO154,
- GPIO155,
- GPIO156,
- GPIO157,
- GPIO158,
- GPIO159,
- GPIO160, /* 160 */
- GPIO161,
- GPIO162,
- GPIO163,
- GPIO164,
- GPIO165,
- GPIO166,
- GPIO167,
- GPIO168,
- GPIO169,
-};
-
-extern int pxa3xx_pinctrl_register(struct platform_device *pdev,
- struct pxa3xx_pinmux_info *info);
-extern int pxa3xx_pinctrl_unregister(struct platform_device *pdev);
-#endif /* __PINCTRL_PXA3XX_H */
diff --git a/drivers/pinctrl/pinctrl-pxa910.c b/drivers/pinctrl/pinctrl-pxa910.c
deleted file mode 100644
index a2f917b847fb..000000000000
--- a/drivers/pinctrl/pinctrl-pxa910.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * linux/drivers/pinctrl/pinmux-pxa910.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * publishhed by the Free Software Foundation.
- *
- * Copyright (C) 2011, Marvell Technology Group Ltd.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include "pinctrl-pxa3xx.h"
-
-#define PXA910_DS_MASK 0x1800
-#define PXA910_DS_SHIFT 11
-#define PXA910_SLEEP_MASK 0x38
-#define PXA910_SLEEP_SELECT (1 << 9)
-#define PXA910_SLEEP_DATA (1 << 8)
-#define PXA910_SLEEP_DIR (1 << 7)
-
-#define MFPR_910(a, r, f0, f1, f2, f3, f4, f5, f6, f7) \
- { \
- .name = #a, \
- .pin = a, \
- .mfpr = r, \
- .func = { \
- PXA910_MUX_##f0, \
- PXA910_MUX_##f1, \
- PXA910_MUX_##f2, \
- PXA910_MUX_##f3, \
- PXA910_MUX_##f4, \
- PXA910_MUX_##f5, \
- PXA910_MUX_##f6, \
- PXA910_MUX_##f7, \
- }, \
- }
-
-#define GRP_910(a, m, p) \
- { .name = a, .mux = PXA910_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), }
-
-/* 170 pins */
-enum pxa910_pin_list {
- /* 0~127: GPIO0~GPIO127 */
- ND_IO15 = 128,
- ND_IO14,
- ND_IO13, /* 130 */
- ND_IO12,
- ND_IO11,
- ND_IO10,
- ND_IO9,
- ND_IO8,
- ND_IO7,
- ND_IO6,
- ND_IO5,
- ND_IO4,
- ND_IO3, /* 140 */
- ND_IO2,
- ND_IO1,
- ND_IO0,
- ND_NCS0,
- ND_NCS1,
- SM_NCS0,
- SM_NCS1,
- ND_NWE,
- ND_NRE,
- ND_CLE, /* 150 */
- ND_ALE,
- SM_SCLK,
- ND_RDY0,
- SM_ADV,
- ND_RDY1,
- SM_ADVMUX,
- SM_RDY,
- MMC1_DAT7,
- MMC1_DAT6,
- MMC1_DAT5, /* 160 */
- MMC1_DAT4,
- MMC1_DAT3,
- MMC1_DAT2,
- MMC1_DAT1,
- MMC1_DAT0,
- MMC1_CMD,
- MMC1_CLK,
- MMC1_CD,
- VCXO_OUT,
-};
-
-enum pxa910_mux {
- /* PXA3xx_MUX_GPIO = 0 (predefined in pinctrl-pxa3xx.h) */
- PXA910_MUX_GPIO = 0,
- PXA910_MUX_NAND,
- PXA910_MUX_USIM2,
- PXA910_MUX_EXT_DMA,
- PXA910_MUX_EXT_INT,
- PXA910_MUX_MMC1,
- PXA910_MUX_MMC2,
- PXA910_MUX_MMC3,
- PXA910_MUX_SM_INT,
- PXA910_MUX_PRI_JTAG,
- PXA910_MUX_SEC1_JTAG,
- PXA910_MUX_SEC2_JTAG,
- PXA910_MUX_RESET, /* SLAVE RESET OUT */
- PXA910_MUX_CLK_REQ,
- PXA910_MUX_VCXO_REQ,
- PXA910_MUX_VCXO_OUT,
- PXA910_MUX_VCXO_REQ2,
- PXA910_MUX_VCXO_OUT2,
- PXA910_MUX_SPI,
- PXA910_MUX_SPI2,
- PXA910_MUX_GSSP,
- PXA910_MUX_SSP0,
- PXA910_MUX_SSP1,
- PXA910_MUX_SSP2,
- PXA910_MUX_DSSP2,
- PXA910_MUX_DSSP3,
- PXA910_MUX_UART0,
- PXA910_MUX_UART1,
- PXA910_MUX_UART2,
- PXA910_MUX_TWSI,
- PXA910_MUX_CCIC,
- PXA910_MUX_PWM0,
- PXA910_MUX_PWM1,
- PXA910_MUX_PWM2,
- PXA910_MUX_PWM3,
- PXA910_MUX_HSL,
- PXA910_MUX_ONE_WIRE,
- PXA910_MUX_LCD,
- PXA910_MUX_DAC_ST23,
- PXA910_MUX_ULPI,
- PXA910_MUX_TB,
- PXA910_MUX_KP_MK,
- PXA910_MUX_KP_DK,
- PXA910_MUX_TCU_GPOA,
- PXA910_MUX_TCU_GPOB,
- PXA910_MUX_ROT,
- PXA910_MUX_TDS,
- PXA910_MUX_32K_CLK, /* 32KHz CLK OUT */
- PXA910_MUX_MN_CLK, /* MN CLK OUT */
- PXA910_MUX_SMC,
- PXA910_MUX_SM_ADDR18,
- PXA910_MUX_SM_ADDR19,
- PXA910_MUX_SM_ADDR20,
- PXA910_MUX_NONE = 0xffff,
-};
-
-
-static struct pinctrl_pin_desc pxa910_pads[] = {
- PINCTRL_PIN(GPIO0, "GPIO0"),
- PINCTRL_PIN(GPIO1, "GPIO1"),
- PINCTRL_PIN(GPIO2, "GPIO2"),
- PINCTRL_PIN(GPIO3, "GPIO3"),
- PINCTRL_PIN(GPIO4, "GPIO4"),
- PINCTRL_PIN(GPIO5, "GPIO5"),
- PINCTRL_PIN(GPIO6, "GPIO6"),
- PINCTRL_PIN(GPIO7, "GPIO7"),
- PINCTRL_PIN(GPIO8, "GPIO8"),
- PINCTRL_PIN(GPIO9, "GPIO9"),
- PINCTRL_PIN(GPIO10, "GPIO10"),
- PINCTRL_PIN(GPIO11, "GPIO11"),
- PINCTRL_PIN(GPIO12, "GPIO12"),
- PINCTRL_PIN(GPIO13, "GPIO13"),
- PINCTRL_PIN(GPIO14, "GPIO14"),
- PINCTRL_PIN(GPIO15, "GPIO15"),
- PINCTRL_PIN(GPIO16, "GPIO16"),
- PINCTRL_PIN(GPIO17, "GPIO17"),
- PINCTRL_PIN(GPIO18, "GPIO18"),
- PINCTRL_PIN(GPIO19, "GPIO19"),
- PINCTRL_PIN(GPIO20, "GPIO20"),
- PINCTRL_PIN(GPIO21, "GPIO21"),
- PINCTRL_PIN(GPIO22, "GPIO22"),
- PINCTRL_PIN(GPIO23, "GPIO23"),
- PINCTRL_PIN(GPIO24, "GPIO24"),
- PINCTRL_PIN(GPIO25, "GPIO25"),
- PINCTRL_PIN(GPIO26, "GPIO26"),
- PINCTRL_PIN(GPIO27, "GPIO27"),
- PINCTRL_PIN(GPIO28, "GPIO28"),
- PINCTRL_PIN(GPIO29, "GPIO29"),
- PINCTRL_PIN(GPIO30, "GPIO30"),
- PINCTRL_PIN(GPIO31, "GPIO31"),
- PINCTRL_PIN(GPIO32, "GPIO32"),
- PINCTRL_PIN(GPIO33, "GPIO33"),
- PINCTRL_PIN(GPIO34, "GPIO34"),
- PINCTRL_PIN(GPIO35, "GPIO35"),
- PINCTRL_PIN(GPIO36, "GPIO36"),
- PINCTRL_PIN(GPIO37, "GPIO37"),
- PINCTRL_PIN(GPIO38, "GPIO38"),
- PINCTRL_PIN(GPIO39, "GPIO39"),
- PINCTRL_PIN(GPIO40, "GPIO40"),
- PINCTRL_PIN(GPIO41, "GPIO41"),
- PINCTRL_PIN(GPIO42, "GPIO42"),
- PINCTRL_PIN(GPIO43, "GPIO43"),
- PINCTRL_PIN(GPIO44, "GPIO44"),
- PINCTRL_PIN(GPIO45, "GPIO45"),
- PINCTRL_PIN(GPIO46, "GPIO46"),
- PINCTRL_PIN(GPIO47, "GPIO47"),
- PINCTRL_PIN(GPIO48, "GPIO48"),
- PINCTRL_PIN(GPIO49, "GPIO49"),
- PINCTRL_PIN(GPIO50, "GPIO50"),
- PINCTRL_PIN(GPIO51, "GPIO51"),
- PINCTRL_PIN(GPIO52, "GPIO52"),
- PINCTRL_PIN(GPIO53, "GPIO53"),
- PINCTRL_PIN(GPIO54, "GPIO54"),
- PINCTRL_PIN(GPIO55, "GPIO55"),
- PINCTRL_PIN(GPIO56, "GPIO56"),
- PINCTRL_PIN(GPIO57, "GPIO57"),
- PINCTRL_PIN(GPIO58, "GPIO58"),
- PINCTRL_PIN(GPIO59, "GPIO59"),
- PINCTRL_PIN(GPIO60, "GPIO60"),
- PINCTRL_PIN(GPIO61, "GPIO61"),
- PINCTRL_PIN(GPIO62, "GPIO62"),
- PINCTRL_PIN(GPIO63, "GPIO63"),
- PINCTRL_PIN(GPIO64, "GPIO64"),
- PINCTRL_PIN(GPIO65, "GPIO65"),
- PINCTRL_PIN(GPIO66, "GPIO66"),
- PINCTRL_PIN(GPIO67, "GPIO67"),
- PINCTRL_PIN(GPIO68, "GPIO68"),
- PINCTRL_PIN(GPIO69, "GPIO69"),
- PINCTRL_PIN(GPIO70, "GPIO70"),
- PINCTRL_PIN(GPIO71, "GPIO71"),
- PINCTRL_PIN(GPIO72, "GPIO72"),
- PINCTRL_PIN(GPIO73, "GPIO73"),
- PINCTRL_PIN(GPIO74, "GPIO74"),
- PINCTRL_PIN(GPIO75, "GPIO75"),
- PINCTRL_PIN(GPIO76, "GPIO76"),
- PINCTRL_PIN(GPIO77, "GPIO77"),
- PINCTRL_PIN(GPIO78, "GPIO78"),
- PINCTRL_PIN(GPIO79, "GPIO79"),
- PINCTRL_PIN(GPIO80, "GPIO80"),
- PINCTRL_PIN(GPIO81, "GPIO81"),
- PINCTRL_PIN(GPIO82, "GPIO82"),
- PINCTRL_PIN(GPIO83, "GPIO83"),
- PINCTRL_PIN(GPIO84, "GPIO84"),
- PINCTRL_PIN(GPIO85, "GPIO85"),
- PINCTRL_PIN(GPIO86, "GPIO86"),
- PINCTRL_PIN(GPIO87, "GPIO87"),
- PINCTRL_PIN(GPIO88, "GPIO88"),
- PINCTRL_PIN(GPIO89, "GPIO89"),
- PINCTRL_PIN(GPIO90, "GPIO90"),
- PINCTRL_PIN(GPIO91, "GPIO91"),
- PINCTRL_PIN(GPIO92, "GPIO92"),
- PINCTRL_PIN(GPIO93, "GPIO93"),
- PINCTRL_PIN(GPIO94, "GPIO94"),
- PINCTRL_PIN(GPIO95, "GPIO95"),
- PINCTRL_PIN(GPIO96, "GPIO96"),
- PINCTRL_PIN(GPIO97, "GPIO97"),
- PINCTRL_PIN(GPIO98, "GPIO98"),
- PINCTRL_PIN(GPIO99, "GPIO99"),
- PINCTRL_PIN(GPIO100, "GPIO100"),
- PINCTRL_PIN(GPIO101, "GPIO101"),
- PINCTRL_PIN(GPIO102, "GPIO102"),
- PINCTRL_PIN(GPIO103, "GPIO103"),
- PINCTRL_PIN(GPIO104, "GPIO104"),
- PINCTRL_PIN(GPIO105, "GPIO105"),
- PINCTRL_PIN(GPIO106, "GPIO106"),
- PINCTRL_PIN(GPIO107, "GPIO107"),
- PINCTRL_PIN(GPIO108, "GPIO108"),
- PINCTRL_PIN(GPIO109, "GPIO109"),
- PINCTRL_PIN(GPIO110, "GPIO110"),
- PINCTRL_PIN(GPIO111, "GPIO111"),
- PINCTRL_PIN(GPIO112, "GPIO112"),
- PINCTRL_PIN(GPIO113, "GPIO113"),
- PINCTRL_PIN(GPIO114, "GPIO114"),
- PINCTRL_PIN(GPIO115, "GPIO115"),
- PINCTRL_PIN(GPIO116, "GPIO116"),
- PINCTRL_PIN(GPIO117, "GPIO117"),
- PINCTRL_PIN(GPIO118, "GPIO118"),
- PINCTRL_PIN(GPIO119, "GPIO119"),
- PINCTRL_PIN(GPIO120, "GPIO120"),
- PINCTRL_PIN(GPIO121, "GPIO121"),
- PINCTRL_PIN(GPIO122, "GPIO122"),
- PINCTRL_PIN(GPIO123, "GPIO123"),
- PINCTRL_PIN(GPIO124, "GPIO124"),
- PINCTRL_PIN(GPIO125, "GPIO125"),
- PINCTRL_PIN(GPIO126, "GPIO126"),
- PINCTRL_PIN(GPIO127, "GPIO127"),
- PINCTRL_PIN(ND_IO15, "ND_IO15"),
- PINCTRL_PIN(ND_IO14, "ND_IO14"),
- PINCTRL_PIN(ND_IO13, "ND_IO13"),
- PINCTRL_PIN(ND_IO12, "ND_IO12"),
- PINCTRL_PIN(ND_IO11, "ND_IO11"),
- PINCTRL_PIN(ND_IO10, "ND_IO10"),
- PINCTRL_PIN(ND_IO9, "ND_IO9"),
- PINCTRL_PIN(ND_IO8, "ND_IO8"),
- PINCTRL_PIN(ND_IO7, "ND_IO7"),
- PINCTRL_PIN(ND_IO6, "ND_IO6"),
- PINCTRL_PIN(ND_IO5, "ND_IO5"),
- PINCTRL_PIN(ND_IO4, "ND_IO4"),
- PINCTRL_PIN(ND_IO3, "ND_IO3"),
- PINCTRL_PIN(ND_IO2, "ND_IO2"),
- PINCTRL_PIN(ND_IO1, "ND_IO1"),
- PINCTRL_PIN(ND_IO0, "ND_IO0"),
- PINCTRL_PIN(ND_NCS0, "ND_NCS0_SM_NCS2"),
- PINCTRL_PIN(ND_NCS1, "ND_NCS1_SM_NCS3"),
- PINCTRL_PIN(SM_NCS0, "SM_NCS0"),
- PINCTRL_PIN(SM_NCS1, "SM_NCS1"),
- PINCTRL_PIN(ND_NWE, "ND_NWE"),
- PINCTRL_PIN(ND_NRE, "ND_NRE"),
- PINCTRL_PIN(ND_CLE, "ND_CLE_SM_NOE"),
- PINCTRL_PIN(ND_ALE, "ND_ALE_SM_NWE"),
- PINCTRL_PIN(SM_SCLK, "SM_SCLK"),
- PINCTRL_PIN(ND_RDY0, "ND_RDY0"),
- PINCTRL_PIN(SM_ADV, "SM_ADV"),
- PINCTRL_PIN(ND_RDY1, "ND_RDY1"),
- PINCTRL_PIN(SM_RDY, "SM_RDY"),
- PINCTRL_PIN(MMC1_DAT7, "MMC1_DAT7"),
- PINCTRL_PIN(MMC1_DAT6, "MMC1_DAT6"),
- PINCTRL_PIN(MMC1_DAT5, "MMC1_DAT5"),
- PINCTRL_PIN(MMC1_DAT4, "MMC1_DAT4"),
- PINCTRL_PIN(MMC1_DAT3, "MMC1_DAT3"),
- PINCTRL_PIN(MMC1_DAT2, "MMC1_DAT2"),
- PINCTRL_PIN(MMC1_DAT1, "MMC1_DAT1"),
- PINCTRL_PIN(MMC1_DAT0, "MMC1_DAT0"),
- PINCTRL_PIN(MMC1_CMD, "MMC1 CMD"),
- PINCTRL_PIN(MMC1_CLK, "MMC1 CLK"),
- PINCTRL_PIN(MMC1_CD, "MMC1 CD"),
- PINCTRL_PIN(VCXO_OUT, "VCXO_OUT"),
-};
-
-struct pxa3xx_mfp_pin pxa910_mfp[] = {
- /* pin offs f0 f1 f2 f3 f4 f5 f6 f7 */
- MFPR_910(GPIO0, 0x0DC, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO1, 0x0E0, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO2, 0x0E4, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO3, 0x0E8, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO4, 0x0EC, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO5, 0x0F0, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO6, 0x0F4, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO7, 0x0F8, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO8, 0x0FC, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO9, 0x100, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO10, 0x104, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO11, 0x108, GPIO, KP_MK, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO12, 0x10C, GPIO, KP_MK, NONE, NONE, KP_DK, NONE, NONE, NONE),
- MFPR_910(GPIO13, 0x110, GPIO, KP_MK, NONE, NONE, KP_DK, NONE, NONE, NONE),
- MFPR_910(GPIO14, 0x114, GPIO, KP_MK, NONE, NONE, KP_DK, TB, NONE, NONE),
- MFPR_910(GPIO15, 0x118, GPIO, KP_MK, NONE, NONE, KP_DK, TB, NONE, NONE),
- MFPR_910(GPIO16, 0x11C, GPIO, KP_DK, NONE, NONE, NONE, TB, NONE, NONE),
- MFPR_910(GPIO17, 0x120, GPIO, KP_DK, NONE, NONE, NONE, TB, NONE, NONE),
- MFPR_910(GPIO18, 0x124, GPIO, KP_DK, NONE, NONE, ROT, NONE, NONE, NONE),
- MFPR_910(GPIO19, 0x128, GPIO, KP_DK, NONE, NONE, ROT, NONE, NONE, NONE),
- MFPR_910(GPIO20, 0x12C, GPIO, SSP1, NONE, NONE, VCXO_OUT, NONE, NONE, NONE),
- MFPR_910(GPIO21, 0x130, GPIO, SSP1, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO22, 0x134, GPIO, SSP1, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO23, 0x138, GPIO, SSP1, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO24, 0x13C, GPIO, SSP1, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO25, 0x140, GPIO, GSSP, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO26, 0x144, GPIO, GSSP, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO27, 0x148, GPIO, GSSP, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO28, 0x14C, GPIO, GSSP, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO29, 0x150, GPIO, UART0, NONE, NONE, UART1, NONE, NONE, NONE),
- MFPR_910(GPIO30, 0x154, GPIO, UART0, NONE, NONE, UART1, NONE, NONE, NONE),
- MFPR_910(GPIO31, 0x158, GPIO, UART0, NONE, NONE, UART1, NONE, NONE, NONE),
- MFPR_910(GPIO32, 0x15C, GPIO, UART0, DAC_ST23, NONE, UART1, NONE, NONE, NONE),
- MFPR_910(GPIO33, 0x160, GPIO, MMC2, SSP0, SSP2, NONE, SPI, NONE, MMC3),
- MFPR_910(GPIO34, 0x164, GPIO, MMC2, SSP0, SSP2, NONE, SPI, NONE, MMC3),
- MFPR_910(GPIO35, 0x168, GPIO, MMC2, SSP0, SSP2, NONE, SPI, NONE, MMC3),
- MFPR_910(GPIO36, 0x16C, GPIO, MMC2, SSP0, SSP2, NONE, SPI, NONE, MMC3),
- MFPR_910(GPIO37, 0x170, GPIO, MMC2, NONE, NONE, NONE, SPI, HSL, NONE),
- MFPR_910(GPIO38, 0x174, GPIO, MMC2, NONE, NONE, NONE, NONE, HSL, NONE),
- MFPR_910(GPIO39, 0x178, GPIO, MMC2, NONE, NONE, NONE, NONE, HSL, NONE),
- MFPR_910(GPIO40, 0x17C, GPIO, MMC2, NONE, NONE, NONE, NONE, HSL, NONE),
- MFPR_910(GPIO41, 0x180, GPIO, MMC2, NONE, NONE, NONE, NONE, HSL, NONE),
- MFPR_910(GPIO42, 0x184, GPIO, MMC2, NONE, NONE, NONE, NONE, HSL, NONE),
- MFPR_910(GPIO43, 0x188, GPIO, UART1, NONE, DAC_ST23, NONE, DSSP2, SPI, UART2),
- MFPR_910(GPIO44, 0x18C, GPIO, UART1, NONE, EXT_INT, NONE, DSSP2, SPI, UART2),
- MFPR_910(GPIO45, 0x190, GPIO, UART1, NONE, EXT_INT, NONE, DSSP2, SPI, UART2),
- MFPR_910(GPIO46, 0x194, GPIO, UART1, NONE, EXT_INT, NONE, DSSP2, SPI, UART2),
- MFPR_910(GPIO47, 0x198, GPIO, SSP0, NONE, NONE, NONE, SSP2, UART1, NONE),
- MFPR_910(GPIO48, 0x19C, GPIO, SSP0, NONE, NONE, NONE, SSP2, UART1, NONE),
- MFPR_910(GPIO49, 0x1A0, GPIO, SSP0, UART0, VCXO_REQ, NONE, SSP2, NONE, MMC3),
- MFPR_910(GPIO50, 0x1A4, GPIO, SSP0, UART0, VCXO_OUT, NONE, SSP2, NONE, MMC3),
- MFPR_910(GPIO51, 0x1A8, GPIO, UART2, PWM1, TWSI, SSP0, NONE, DSSP3, NONE),
- MFPR_910(GPIO52, 0x1AC, GPIO, UART2, DAC_ST23, TWSI, SSP0, NONE, DSSP3, NONE),
- MFPR_910(GPIO53, 0x1B0, GPIO, UART2, TWSI, NONE, SSP0, NONE, DSSP3, NONE),
- MFPR_910(GPIO54, 0x1B4, GPIO, UART2, TWSI, SSP0, NONE, NONE, DSSP3, NONE),
- MFPR_910(GPIO55, 0x2F0, TDS, GPIO, TB, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO56, 0x2F4, TDS, GPIO, TB, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO57, 0x2F8, TDS, GPIO, TB, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO58, 0x2FC, TDS, GPIO, TB, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO59, 0x300, TDS, GPIO, TCU_GPOA, TCU_GPOB, ONE_WIRE, NONE, NONE, NONE),
- MFPR_910(GPIO60, 0x304, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO61, 0x308, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, HSL),
- MFPR_910(GPIO62, 0x30C, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, HSL),
- MFPR_910(GPIO63, 0x310, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, HSL),
- MFPR_910(GPIO64, 0x314, GPIO, SPI2, NONE, NONE, NONE, NONE, NONE, HSL),
- MFPR_910(GPIO65, 0x318, GPIO, SPI2, NONE, NONE, NONE, NONE, ONE_WIRE, HSL),
- MFPR_910(GPIO66, 0x31C, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, HSL),
- MFPR_910(GPIO67, 0x1B8, GPIO, CCIC, SPI, NONE, NONE, ULPI, NONE, USIM2),
- MFPR_910(GPIO68, 0x1BC, GPIO, CCIC, SPI, NONE, NONE, ULPI, NONE, USIM2),
- MFPR_910(GPIO69, 0x1C0, GPIO, CCIC, SPI, NONE, NONE, ULPI, NONE, USIM2),
- MFPR_910(GPIO70, 0x1C4, GPIO, CCIC, SPI, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO71, 0x1C8, GPIO, CCIC, SPI, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO72, 0x1CC, GPIO, CCIC, EXT_DMA, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO73, 0x1D0, GPIO, CCIC, EXT_DMA, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO74, 0x1D4, GPIO, CCIC, EXT_DMA, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO75, 0x1D8, GPIO, CCIC, NONE, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO76, 0x1DC, GPIO, CCIC, NONE, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO77, 0x1E0, GPIO, CCIC, NONE, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO78, 0x1E4, GPIO, CCIC, NONE, NONE, NONE, ULPI, NONE, NONE),
- MFPR_910(GPIO79, 0x1E8, GPIO, TWSI, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO80, 0x1EC, GPIO, TWSI, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO81, 0x1F0, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO82, 0x1F4, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO83, 0x1F8, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO84, 0x1FC, GPIO, LCD, VCXO_REQ2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO85, 0x200, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO86, 0x204, GPIO, LCD, VCXO_OUT2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO87, 0x208, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO88, 0x20C, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO89, 0x210, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO90, 0x214, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO91, 0x218, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO92, 0x21C, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO93, 0x220, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO94, 0x224, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO95, 0x228, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO96, 0x22C, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO97, 0x230, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO98, 0x234, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO99, 0x0B0, MMC1, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO100, 0x238, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO101, 0x23C, GPIO, LCD, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO102, 0x240, GPIO, LCD, DSSP2, SPI, NONE, NONE, NONE, SPI2),
- MFPR_910(GPIO103, 0x244, GPIO, LCD, DSSP2, SPI, NONE, NONE, NONE, SPI2),
- MFPR_910(GPIO104, 0x248, GPIO, LCD, DSSP2, SPI, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO105, 0x24C, GPIO, LCD, DSSP2, SPI, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO106, 0x250, GPIO, LCD, DSSP3, ONE_WIRE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO107, 0x254, GPIO, LCD, DSSP3, SPI, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO108, 0x258, GPIO, LCD, DSSP3, SPI, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO109, 0x25C, GPIO, LCD, DSSP3, SPI, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO110, 0x298, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO111, 0x29C, GPIO, NONE, DSSP2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO112, 0x2A0, GPIO, NONE, DSSP2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO113, 0x2A4, GPIO, NONE, DSSP2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO114, 0x2A8, GPIO, NONE, DSSP3, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO115, 0x2AC, GPIO, NONE, DSSP3, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO116, 0x2B0, GPIO, NONE, DSSP3, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO117, 0x0B4, PRI_JTAG, GPIO, PWM0, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO118, 0x0B8, PRI_JTAG, GPIO, PWM1, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO119, 0x0BC, PRI_JTAG, GPIO, PWM2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO120, 0x0C0, PRI_JTAG, GPIO, PWM3, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO121, 0x32C, GPIO, NONE, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO122, 0x0C8, RESET, GPIO, 32K_CLK, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO123, 0x0CC, CLK_REQ, GPIO, ONE_WIRE, EXT_DMA, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO124, 0x0D0, GPIO, MN_CLK, DAC_ST23, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO125, 0x0D4, VCXO_REQ, GPIO, NONE, EXT_INT, NONE, NONE, NONE, NONE),
- MFPR_910(GPIO126, 0x06C, GPIO, SMC, NONE, SM_ADDR18, NONE, EXT_DMA, NONE, NONE),
- MFPR_910(GPIO127, 0x070, GPIO, SMC, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO15, 0x004, NAND, GPIO, USIM2, EXT_DMA, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO14, 0x008, NAND, GPIO, USIM2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO13, 0x00C, NAND, GPIO, USIM2, EXT_INT, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO12, 0x010, NAND, GPIO, SSP2, EXT_INT, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO11, 0x014, NAND, GPIO, SSP2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO10, 0x018, NAND, GPIO, SSP2, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO9, 0x01C, NAND, GPIO, SSP2, NONE, VCXO_OUT2, NONE, NONE, NONE),
- MFPR_910(ND_IO8, 0x020, NAND, GPIO, NONE, NONE, PWM3, NONE, NONE, NONE),
- MFPR_910(ND_IO7, 0x024, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO6, 0x028, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO5, 0x02C, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO4, 0x030, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO3, 0x034, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO2, 0x038, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO1, 0x03C, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_IO0, 0x040, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_NCS0, 0x044, NAND, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_NCS1, 0x048, NAND, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(SM_NCS0, 0x04C, SMC, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(SM_NCS1, 0x050, SMC, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_NWE, 0x054, GPIO, NAND, NONE, SM_ADDR20, NONE, SMC, NONE, NONE),
- MFPR_910(ND_NRE, 0x058, GPIO, NAND, NONE, SMC, NONE, EXT_DMA, NONE, NONE),
- MFPR_910(ND_CLE, 0x05C, NAND, MMC3, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_ALE, 0x060, GPIO, NAND, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(SM_SCLK, 0x064, MMC3, NONE, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_RDY0, 0x068, NAND, GPIO, NONE, SMC, NONE, NONE, NONE, NONE),
- MFPR_910(SM_ADV, 0x074, SMC, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(ND_RDY1, 0x078, NAND, GPIO, NONE, SMC, NONE, NONE, NONE, NONE),
- MFPR_910(SM_ADVMUX, 0x07C, SMC, GPIO, NONE, SM_ADDR19, NONE, NONE, NONE, NONE),
- MFPR_910(SM_RDY, 0x080, SMC, GPIO, NONE, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT7, 0x084, MMC1, GPIO, SEC1_JTAG, TB, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT6, 0x088, MMC1, GPIO, SEC1_JTAG, TB, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT5, 0x08C, MMC1, GPIO, SEC1_JTAG, TB, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT4, 0x090, MMC1, GPIO, NONE, TB, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT3, 0x094, MMC1, HSL, SEC2_JTAG, SSP0, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT2, 0x098, MMC1, HSL, SEC2_JTAG, SSP2, SSP0, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT1, 0x09C, MMC1, HSL, SEC2_JTAG, SSP2, SSP0, NONE, NONE, NONE),
- MFPR_910(MMC1_DAT0, 0x0A0, MMC1, HSL, SEC2_JTAG, SSP2, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_CMD, 0x0A4, MMC1, HSL, SEC1_JTAG, SSP2, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_CLK, 0x0A8, MMC1, HSL, SEC2_JTAG, SSP0, NONE, NONE, NONE, NONE),
- MFPR_910(MMC1_CD, 0x0AC, MMC1, GPIO, SEC1_JTAG, NONE, NONE, NONE, NONE, NONE),
- MFPR_910(VCXO_OUT, 0x0D8, VCXO_OUT, PWM3, NONE, NONE, NONE, NONE, NONE, NONE),
-};
-
-
-static const unsigned p910_usim2_pin1[] = {GPIO67, GPIO68, GPIO69};
-static const unsigned p910_usim2_pin2[] = {ND_IO15, ND_IO14, ND_IO13};
-static const unsigned p910_mmc1_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
- MMC1_DAT4, MMC1_DAT3, MMC1_DAT2, MMC1_DAT1, MMC1_DAT0, MMC1_CMD,
- MMC1_CLK, MMC1_CD, GPIO99};
-static const unsigned p910_mmc2_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
- GPIO37, GPIO38, GPIO39, GPIO40, GPIO41, GPIO42};
-static const unsigned p910_mmc3_pin1[] = {GPIO33, GPIO34, GPIO35, GPIO36,
- GPIO49, GPIO50};
-static const unsigned p910_mmc3_pin2[] = {ND_IO7, ND_IO6, ND_IO5, ND_IO4,
- ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_CLE, SM_SCLK};
-static const unsigned p910_uart0_pin1[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned p910_uart1_pin1[] = {GPIO47, GPIO48};
-static const unsigned p910_uart1_pin2[] = {GPIO31, GPIO32};
-static const unsigned p910_uart1_pin3[] = {GPIO45, GPIO46};
-static const unsigned p910_uart1_pin4[] = {GPIO29, GPIO30, GPIO31, GPIO32};
-static const unsigned p910_uart1_pin5[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_uart2_pin1[] = {GPIO43, GPIO44};
-static const unsigned p910_uart2_pin2[] = {GPIO51, GPIO52};
-static const unsigned p910_uart2_pin3[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_uart2_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_twsi_pin1[] = {GPIO51, GPIO52};
-static const unsigned p910_twsi_pin2[] = {GPIO53, GPIO54};
-static const unsigned p910_twsi_pin3[] = {GPIO79, GPIO80};
-static const unsigned p910_ccic_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
- GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
-static const unsigned p910_lcd_pin1[] = {GPIO81, GPIO82, GPIO83, GPIO84,
- GPIO85, GPIO86, GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92,
- GPIO93, GPIO94, GPIO95, GPIO96, GPIO97, GPIO98, GPIO100, GPIO101,
- GPIO102, GPIO103};
-static const unsigned p910_spi_pin1[] = {GPIO104, GPIO105, GPIO107, GPIO108};
-static const unsigned p910_spi_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_spi_pin3[] = {GPIO33, GPIO34, GPIO35, GPIO36,
- GPIO37};
-static const unsigned p910_spi_pin4[] = {GPIO67, GPIO68, GPIO69, GPIO70,
- GPIO71};
-static const unsigned p910_spi2_pin1[] = {GPIO64, GPIO65};
-static const unsigned p910_spi2_pin2[] = {GPIO102, GPIO103};
-static const unsigned p910_dssp2_pin1[] = {GPIO102, GPIO103, GPIO104, GPIO105};
-static const unsigned p910_dssp2_pin2[] = {GPIO43, GPIO44, GPIO45, GPIO46};
-static const unsigned p910_dssp2_pin3[] = {GPIO111, GPIO112, GPIO113};
-static const unsigned p910_dssp3_pin1[] = {GPIO106, GPIO107, GPIO108, GPIO109};
-static const unsigned p910_dssp3_pin2[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_dssp3_pin3[] = {GPIO114, GPIO115, GPIO116};
-static const unsigned p910_ssp0_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
- MMC1_CLK};
-static const unsigned p910_ssp0_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned p910_ssp0_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned p910_ssp0_pin4[] = {GPIO51, GPIO52, GPIO53, GPIO54};
-static const unsigned p910_ssp1_pin1[] = {GPIO21, GPIO22, GPIO23, GPIO24};
-static const unsigned p910_ssp1_pin2[] = {GPIO20, GPIO21, GPIO22, GPIO23,
- GPIO24};
-static const unsigned p910_ssp2_pin1[] = {MMC1_DAT2, MMC1_DAT1, MMC1_DAT0,
- MMC1_CMD};
-static const unsigned p910_ssp2_pin2[] = {GPIO33, GPIO34, GPIO35, GPIO36};
-static const unsigned p910_ssp2_pin3[] = {GPIO47, GPIO48, GPIO49, GPIO50};
-static const unsigned p910_ssp2_pin4[] = {ND_IO12, ND_IO11, ND_IO10, ND_IO9};
-static const unsigned p910_gssp_pin1[] = {GPIO25, GPIO26, GPIO27, GPIO28};
-static const unsigned p910_pwm0_pin1[] = {GPIO117};
-static const unsigned p910_pwm1_pin1[] = {GPIO118};
-static const unsigned p910_pwm1_pin2[] = {GPIO51};
-static const unsigned p910_pwm2_pin1[] = {GPIO119};
-static const unsigned p910_pwm3_pin1[] = {GPIO120};
-static const unsigned p910_pwm3_pin2[] = {ND_IO8};
-static const unsigned p910_pwm3_pin3[] = {VCXO_OUT};
-static const unsigned p910_pri_jtag_pin1[] = {GPIO117, GPIO118, GPIO119,
- GPIO120};
-static const unsigned p910_sec1_jtag_pin1[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
- MMC1_CMD, MMC1_CD};
-static const unsigned p910_sec2_jtag_pin1[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
- MMC1_DAT0, MMC1_CLK};
-static const unsigned p910_hsl_pin1[] = {GPIO37, GPIO38, GPIO39, GPIO40,
- GPIO41, GPIO42};
-static const unsigned p910_hsl_pin2[] = {GPIO61, GPIO62, GPIO63, GPIO64,
- GPIO65, GPIO66};
-static const unsigned p910_hsl_pin3[] = {MMC1_DAT3, MMC1_DAT2, MMC1_DAT1,
- MMC1_DAT0, MMC1_CMD, MMC1_CLK};
-static const unsigned p910_w1_pin1[] = {GPIO59};
-static const unsigned p910_w1_pin2[] = {GPIO65};
-static const unsigned p910_w1_pin3[] = {GPIO106};
-static const unsigned p910_w1_pin4[] = {GPIO123};
-static const unsigned p910_kpmk_pin1[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
- GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13,
- GPIO14, GPIO15};
-static const unsigned p910_kpmk_pin2[] = {GPIO0, GPIO1, GPIO2, GPIO3, GPIO4,
- GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO12};
-static const unsigned p910_kpdk_pin1[] = {GPIO12, GPIO13, GPIO14, GPIO15,
- GPIO16, GPIO17, GPIO18, GPIO19};
-static const unsigned p910_tds_pin1[] = {GPIO55, GPIO56, GPIO57, GPIO58,
- GPIO59};
-static const unsigned p910_tds_pin2[] = {GPIO55, GPIO57, GPIO58, GPIO59};
-static const unsigned p910_tb_pin1[] = {GPIO14, GPIO15, GPIO16, GPIO17};
-static const unsigned p910_tb_pin2[] = {GPIO55, GPIO56, GPIO57, GPIO58};
-static const unsigned p910_tb_pin3[] = {MMC1_DAT7, MMC1_DAT6, MMC1_DAT5,
- MMC1_DAT4};
-static const unsigned p910_ext_dma0_pin1[] = {GPIO72};
-static const unsigned p910_ext_dma0_pin2[] = {ND_IO15};
-static const unsigned p910_ext_dma0_pin3[] = {ND_NRE};
-static const unsigned p910_ext_dma1_pin1[] = {GPIO73};
-static const unsigned p910_ext_dma1_pin2[] = {GPIO123};
-static const unsigned p910_ext_dma1_pin3[] = {GPIO126};
-static const unsigned p910_ext_dma2_pin1[] = {GPIO74};
-static const unsigned p910_ext0_int_pin1[] = {GPIO44};
-static const unsigned p910_ext0_int_pin2[] = {ND_IO13};
-static const unsigned p910_ext1_int_pin1[] = {GPIO45};
-static const unsigned p910_ext1_int_pin2[] = {ND_IO12};
-static const unsigned p910_ext2_int_pin1[] = {GPIO46};
-static const unsigned p910_ext2_int_pin2[] = {GPIO125};
-static const unsigned p910_dac_st23_pin1[] = {GPIO32};
-static const unsigned p910_dac_st23_pin2[] = {GPIO43};
-static const unsigned p910_dac_st23_pin3[] = {GPIO52};
-static const unsigned p910_dac_st23_pin4[] = {GPIO124};
-static const unsigned p910_vcxo_out_pin1[] = {GPIO50};
-static const unsigned p910_vcxo_out_pin2[] = {VCXO_OUT};
-static const unsigned p910_vcxo_out_pin3[] = {GPIO20};
-static const unsigned p910_vcxo_req_pin1[] = {GPIO49};
-static const unsigned p910_vcxo_req_pin2[] = {GPIO125};
-static const unsigned p910_vcxo_out2_pin1[] = {GPIO86};
-static const unsigned p910_vcxo_out2_pin2[] = {ND_IO9};
-static const unsigned p910_vcxo_req2_pin1[] = {GPIO84};
-static const unsigned p910_ulpi_pin1[] = {GPIO67, GPIO68, GPIO69, GPIO70,
- GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78};
-static const unsigned p910_nand_pin1[] = {ND_IO15, ND_IO14, ND_IO13, ND_IO12,
- ND_IO11, ND_IO10, ND_IO9, ND_IO8, ND_IO7, ND_IO6, ND_IO5, ND_IO4,
- ND_IO3, ND_IO2, ND_IO1, ND_IO0, ND_NCS0, ND_NWE, ND_NRE, ND_CLE,
- ND_ALE, ND_RDY0};
-static const unsigned p910_gpio0_pin1[] = {GPIO0};
-static const unsigned p910_gpio0_pin2[] = {SM_ADV};
-static const unsigned p910_gpio1_pin1[] = {GPIO1};
-static const unsigned p910_gpio1_pin2[] = {ND_RDY1};
-static const unsigned p910_gpio2_pin1[] = {GPIO2};
-static const unsigned p910_gpio2_pin2[] = {SM_ADVMUX};
-static const unsigned p910_gpio3_pin1[] = {GPIO3};
-static const unsigned p910_gpio3_pin2[] = {SM_RDY};
-static const unsigned p910_gpio20_pin1[] = {GPIO20};
-static const unsigned p910_gpio20_pin2[] = {ND_IO15};
-static const unsigned p910_gpio20_pin3[] = {MMC1_DAT6};
-static const unsigned p910_gpio21_pin1[] = {GPIO21};
-static const unsigned p910_gpio21_pin2[] = {ND_IO14};
-static const unsigned p910_gpio21_pin3[] = {MMC1_DAT5};
-static const unsigned p910_gpio22_pin1[] = {GPIO22};
-static const unsigned p910_gpio22_pin2[] = {ND_IO13};
-static const unsigned p910_gpio22_pin3[] = {MMC1_DAT4};
-static const unsigned p910_gpio23_pin1[] = {GPIO23};
-static const unsigned p910_gpio23_pin2[] = {ND_IO12};
-static const unsigned p910_gpio23_pin3[] = {MMC1_CD};
-static const unsigned p910_gpio24_pin1[] = {GPIO24};
-static const unsigned p910_gpio24_pin2[] = {ND_IO11};
-static const unsigned p910_gpio24_pin3[] = {MMC1_DAT7};
-static const unsigned p910_gpio25_pin1[] = {GPIO25};
-static const unsigned p910_gpio25_pin2[] = {ND_IO10};
-static const unsigned p910_gpio26_pin1[] = {GPIO26};
-static const unsigned p910_gpio26_pin2[] = {ND_IO9};
-static const unsigned p910_gpio27_pin1[] = {GPIO27};
-static const unsigned p910_gpio27_pin2[] = {ND_IO8};
-static const unsigned p910_gpio85_pin1[] = {GPIO85};
-static const unsigned p910_gpio85_pin2[] = {ND_NCS0};
-static const unsigned p910_gpio86_pin1[] = {GPIO86};
-static const unsigned p910_gpio86_pin2[] = {ND_NCS1};
-static const unsigned p910_gpio87_pin1[] = {GPIO87};
-static const unsigned p910_gpio87_pin2[] = {SM_NCS0};
-static const unsigned p910_gpio88_pin1[] = {GPIO88};
-static const unsigned p910_gpio88_pin2[] = {SM_NCS1};
-static const unsigned p910_gpio89_pin1[] = {GPIO89};
-static const unsigned p910_gpio89_pin2[] = {ND_NWE};
-static const unsigned p910_gpio90_pin1[] = {GPIO90};
-static const unsigned p910_gpio90_pin2[] = {ND_NRE};
-static const unsigned p910_gpio91_pin1[] = {GPIO91};
-static const unsigned p910_gpio91_pin2[] = {ND_ALE};
-static const unsigned p910_gpio92_pin1[] = {GPIO92};
-static const unsigned p910_gpio92_pin2[] = {ND_RDY0};
-
-static struct pxa3xx_pin_group pxa910_grps[] = {
- GRP_910("usim2 3p1", USIM2, p910_usim2_pin1),
- GRP_910("usim2 3p2", USIM2, p910_usim2_pin2),
- GRP_910("mmc1 12p", MMC1, p910_mmc1_pin1),
- GRP_910("mmc2 10p", MMC2, p910_mmc2_pin1),
- GRP_910("mmc3 6p", MMC3, p910_mmc3_pin1),
- GRP_910("mmc3 10p", MMC3, p910_mmc3_pin2),
- GRP_910("uart0 4p", UART0, p910_uart0_pin1),
- GRP_910("uart1 2p1", UART1, p910_uart1_pin1),
- GRP_910("uart1 2p2", UART1, p910_uart1_pin2),
- GRP_910("uart1 2p3", UART1, p910_uart1_pin3),
- GRP_910("uart1 4p4", UART1, p910_uart1_pin4),
- GRP_910("uart1 4p5", UART1, p910_uart1_pin5),
- GRP_910("uart2 2p1", UART2, p910_uart2_pin1),
- GRP_910("uart2 2p2", UART2, p910_uart2_pin2),
- GRP_910("uart2 4p3", UART2, p910_uart2_pin3),
- GRP_910("uart2 4p4", UART2, p910_uart2_pin4),
- GRP_910("twsi 2p1", TWSI, p910_twsi_pin1),
- GRP_910("twsi 2p2", TWSI, p910_twsi_pin2),
- GRP_910("twsi 2p3", TWSI, p910_twsi_pin3),
- GRP_910("ccic", CCIC, p910_ccic_pin1),
- GRP_910("lcd", LCD, p910_lcd_pin1),
- GRP_910("spi 4p1", SPI, p910_spi_pin1),
- GRP_910("spi 4p2", SPI, p910_spi_pin2),
- GRP_910("spi 5p3", SPI, p910_spi_pin3),
- GRP_910("spi 5p4", SPI, p910_spi_pin4),
- GRP_910("dssp2 4p1", DSSP2, p910_dssp2_pin1),
- GRP_910("dssp2 4p2", DSSP2, p910_dssp2_pin2),
- GRP_910("dssp2 3p3", DSSP2, p910_dssp2_pin3),
- GRP_910("dssp3 4p1", DSSP3, p910_dssp3_pin1),
- GRP_910("dssp3 4p2", DSSP3, p910_dssp3_pin2),
- GRP_910("dssp3 3p3", DSSP3, p910_dssp3_pin3),
- GRP_910("ssp0 4p1", SSP0, p910_ssp0_pin1),
- GRP_910("ssp0 4p2", SSP0, p910_ssp0_pin2),
- GRP_910("ssp0 4p3", SSP0, p910_ssp0_pin3),
- GRP_910("ssp0 4p4", SSP0, p910_ssp0_pin4),
- GRP_910("ssp1 4p1", SSP1, p910_ssp1_pin1),
- GRP_910("ssp1 5p2", SSP1, p910_ssp1_pin2),
- GRP_910("ssp2 4p1", SSP2, p910_ssp2_pin1),
- GRP_910("ssp2 4p2", SSP2, p910_ssp2_pin2),
- GRP_910("ssp2 4p3", SSP2, p910_ssp2_pin3),
- GRP_910("ssp2 4p4", SSP2, p910_ssp2_pin4),
- GRP_910("gssp", GSSP, p910_gssp_pin1),
- GRP_910("pwm0", PWM0, p910_pwm0_pin1),
- GRP_910("pwm1-1", PWM1, p910_pwm1_pin1),
- GRP_910("pwm1-2", PWM1, p910_pwm1_pin2),
- GRP_910("pwm2", PWM2, p910_pwm2_pin1),
- GRP_910("pwm3-1", PWM3, p910_pwm3_pin1),
- GRP_910("pwm3-2", PWM3, p910_pwm3_pin2),
- GRP_910("pwm3-3", PWM3, p910_pwm3_pin3),
- GRP_910("pri jtag", PRI_JTAG, p910_pri_jtag_pin1),
- GRP_910("sec1 jtag", SEC1_JTAG, p910_sec1_jtag_pin1),
- GRP_910("sec2 jtag", SEC2_JTAG, p910_sec2_jtag_pin1),
- GRP_910("hsl 6p1", HSL, p910_hsl_pin1),
- GRP_910("hsl 6p2", HSL, p910_hsl_pin2),
- GRP_910("hsl 6p3", HSL, p910_hsl_pin3),
- GRP_910("w1-1", ONE_WIRE, p910_w1_pin1),
- GRP_910("w1-2", ONE_WIRE, p910_w1_pin2),
- GRP_910("w1-3", ONE_WIRE, p910_w1_pin3),
- GRP_910("w1-4", ONE_WIRE, p910_w1_pin4),
- GRP_910("kpmk 16p1", KP_MK, p910_kpmk_pin1),
- GRP_910("kpmk 11p2", KP_MK, p910_kpmk_pin2),
- GRP_910("kpdk 8p1", KP_DK, p910_kpdk_pin1),
- GRP_910("tds 5p1", TDS, p910_tds_pin1),
- GRP_910("tds 4p2", TDS, p910_tds_pin2),
- GRP_910("tb 4p1", TB, p910_tb_pin1),
- GRP_910("tb 4p2", TB, p910_tb_pin2),
- GRP_910("tb 4p3", TB, p910_tb_pin3),
- GRP_910("ext dma0-1", EXT_DMA, p910_ext_dma0_pin1),
- GRP_910("ext dma0-2", EXT_DMA, p910_ext_dma0_pin2),
- GRP_910("ext dma0-3", EXT_DMA, p910_ext_dma0_pin3),
- GRP_910("ext dma1-1", EXT_DMA, p910_ext_dma1_pin1),
- GRP_910("ext dma1-2", EXT_DMA, p910_ext_dma1_pin2),
- GRP_910("ext dma1-3", EXT_DMA, p910_ext_dma1_pin3),
- GRP_910("ext dma2", EXT_DMA, p910_ext_dma2_pin1),
- GRP_910("ext0 int-1", EXT_INT, p910_ext0_int_pin1),
- GRP_910("ext0 int-2", EXT_INT, p910_ext0_int_pin2),
- GRP_910("ext1 int-1", EXT_INT, p910_ext1_int_pin1),
- GRP_910("ext1 int-2", EXT_INT, p910_ext1_int_pin2),
- GRP_910("ext2 int-1", EXT_INT, p910_ext2_int_pin1),
- GRP_910("ext2 int-2", EXT_INT, p910_ext2_int_pin2),
- GRP_910("dac st23-1", DAC_ST23, p910_dac_st23_pin1),
- GRP_910("dac st23-2", DAC_ST23, p910_dac_st23_pin2),
- GRP_910("dac st23-3", DAC_ST23, p910_dac_st23_pin3),
- GRP_910("dac st23-4", DAC_ST23, p910_dac_st23_pin4),
- GRP_910("vcxo out-1", VCXO_OUT, p910_vcxo_out_pin1),
- GRP_910("vcxo out-2", VCXO_OUT, p910_vcxo_out_pin2),
- GRP_910("vcxo out-3", VCXO_OUT, p910_vcxo_out_pin3),
- GRP_910("vcxo req-1", VCXO_REQ, p910_vcxo_req_pin1),
- GRP_910("vcxo req-2", VCXO_REQ, p910_vcxo_req_pin2),
- GRP_910("vcxo out2-1", VCXO_OUT2, p910_vcxo_out2_pin1),
- GRP_910("vcxo out2-2", VCXO_OUT2, p910_vcxo_out2_pin2),
- GRP_910("vcxo req2", VCXO_REQ2, p910_vcxo_req2_pin1),
- GRP_910("ulpi", ULPI, p910_ulpi_pin1),
- GRP_910("nand", NAND, p910_nand_pin1),
- GRP_910("gpio0-1", GPIO, p910_gpio0_pin1),
- GRP_910("gpio0-2", GPIO, p910_gpio0_pin2),
- GRP_910("gpio1-1", GPIO, p910_gpio1_pin1),
- GRP_910("gpio1-2", GPIO, p910_gpio1_pin2),
- GRP_910("gpio2-1", GPIO, p910_gpio2_pin1),
- GRP_910("gpio2-2", GPIO, p910_gpio2_pin2),
- GRP_910("gpio3-1", GPIO, p910_gpio3_pin1),
- GRP_910("gpio3-2", GPIO, p910_gpio3_pin2),
- GRP_910("gpio20-1", GPIO, p910_gpio20_pin1),
- GRP_910("gpio20-2", GPIO, p910_gpio20_pin2),
- GRP_910("gpio21-1", GPIO, p910_gpio21_pin1),
- GRP_910("gpio21-2", GPIO, p910_gpio21_pin2),
- GRP_910("gpio22-1", GPIO, p910_gpio22_pin1),
- GRP_910("gpio22-2", GPIO, p910_gpio22_pin2),
- GRP_910("gpio23-1", GPIO, p910_gpio23_pin1),
- GRP_910("gpio23-2", GPIO, p910_gpio23_pin2),
- GRP_910("gpio24-1", GPIO, p910_gpio24_pin1),
- GRP_910("gpio24-2", GPIO, p910_gpio24_pin2),
- GRP_910("gpio25-1", GPIO, p910_gpio25_pin1),
- GRP_910("gpio25-2", GPIO, p910_gpio25_pin2),
- GRP_910("gpio26-1", GPIO, p910_gpio26_pin1),
- GRP_910("gpio26-2", GPIO, p910_gpio26_pin2),
- GRP_910("gpio27-1", GPIO, p910_gpio27_pin1),
- GRP_910("gpio27-2", GPIO, p910_gpio27_pin2),
- GRP_910("gpio85-1", GPIO, p910_gpio85_pin1),
- GRP_910("gpio85-2", GPIO, p910_gpio85_pin2),
- GRP_910("gpio86-1", GPIO, p910_gpio86_pin1),
- GRP_910("gpio86-2", GPIO, p910_gpio86_pin2),
- GRP_910("gpio87-1", GPIO, p910_gpio87_pin1),
- GRP_910("gpio87-2", GPIO, p910_gpio87_pin2),
- GRP_910("gpio88-1", GPIO, p910_gpio88_pin1),
- GRP_910("gpio88-2", GPIO, p910_gpio88_pin2),
- GRP_910("gpio89-1", GPIO, p910_gpio89_pin1),
- GRP_910("gpio89-2", GPIO, p910_gpio89_pin2),
- GRP_910("gpio90-1", GPIO, p910_gpio90_pin1),
- GRP_910("gpio90-2", GPIO, p910_gpio90_pin2),
- GRP_910("gpio91-1", GPIO, p910_gpio91_pin1),
- GRP_910("gpio91-2", GPIO, p910_gpio91_pin2),
- GRP_910("gpio92-1", GPIO, p910_gpio92_pin1),
- GRP_910("gpio92-2", GPIO, p910_gpio92_pin2),
-};
-
-static const char * const p910_usim2_grps[] = {"usim2 3p1", "usim2 3p2"};
-static const char * const p910_mmc1_grps[] = {"mmc1 12p"};
-static const char * const p910_mmc2_grps[] = {"mmc2 10p"};
-static const char * const p910_mmc3_grps[] = {"mmc3 6p", "mmc3 10p"};
-static const char * const p910_uart0_grps[] = {"uart0 4p"};
-static const char * const p910_uart1_grps[] = {"uart1 2p1", "uart1 2p2",
- "uart1 2p3", "uart1 4p4", "uart1 4p5"};
-static const char * const p910_uart2_grps[] = {"uart2 2p1", "uart2 2p2",
- "uart2 4p3", "uart2 4p4"};
-static const char * const p910_twsi_grps[] = {"twsi 2p1", "twsi 2p2",
- "twsi 2p3"};
-static const char * const p910_ccic_grps[] = {"ccic"};
-static const char * const p910_lcd_grps[] = {"lcd"};
-static const char * const p910_spi_grps[] = {"spi 4p1", "spi 4p2", "spi 5p3",
- "spi 5p4"};
-static const char * const p910_dssp2_grps[] = {"dssp2 4p1", "dssp2 4p2",
- "dssp2 3p3"};
-static const char * const p910_dssp3_grps[] = {"dssp3 4p1", "dssp3 4p2",
- "dssp3 3p3"};
-static const char * const p910_ssp0_grps[] = {"ssp0 4p1", "ssp0 4p2",
- "ssp0 4p3", "ssp0 4p4"};
-static const char * const p910_ssp1_grps[] = {"ssp1 4p1", "ssp1 5p2"};
-static const char * const p910_ssp2_grps[] = {"ssp2 4p1", "ssp2 4p2",
- "ssp2 4p3", "ssp2 4p4"};
-static const char * const p910_gssp_grps[] = {"gssp"};
-static const char * const p910_pwm0_grps[] = {"pwm0"};
-static const char * const p910_pwm1_grps[] = {"pwm1-1", "pwm1-2"};
-static const char * const p910_pwm2_grps[] = {"pwm2"};
-static const char * const p910_pwm3_grps[] = {"pwm3-1", "pwm3-2", "pwm3-3"};
-static const char * const p910_pri_jtag_grps[] = {"pri jtag"};
-static const char * const p910_sec1_jtag_grps[] = {"sec1 jtag"};
-static const char * const p910_sec2_jtag_grps[] = {"sec2 jtag"};
-static const char * const p910_hsl_grps[] = {"hsl 6p1", "hsl 6p2", "hsl 6p3"};
-static const char * const p910_w1_grps[] = {"w1-1", "w1-2", "w1-3", "w1-4"};
-static const char * const p910_kpmk_grps[] = {"kpmk 16p1", "kpmk 11p2"};
-static const char * const p910_kpdk_grps[] = {"kpdk 8p1"};
-static const char * const p910_tds_grps[] = {"tds 5p1", "tds 4p2"};
-static const char * const p910_tb_grps[] = {"tb 4p1", "tb 4p2", "tb 4p3"};
-static const char * const p910_dma0_grps[] = {"ext dma0-1", "ext dma0-2",
- "ext dma0-3"};
-static const char * const p910_dma1_grps[] = {"ext dma1-1", "ext dma1-2",
- "ext dma1-3"};
-static const char * const p910_dma2_grps[] = {"ext dma2"};
-static const char * const p910_int0_grps[] = {"ext0 int-1", "ext0 int-2"};
-static const char * const p910_int1_grps[] = {"ext1 int-1", "ext1 int-2"};
-static const char * const p910_int2_grps[] = {"ext2 int-1", "ext2 int-2"};
-static const char * const p910_dac_st23_grps[] = {"dac st23-1", "dac st23-2",
- "dac st23-3", "dac st23-4"};
-static const char * const p910_vcxo_out_grps[] = {"vcxo out-1", "vcxo out-2",
- "vcxo out-3"};
-static const char * const p910_vcxo_req_grps[] = {"vcxo req-1", "vcxo req-2"};
-static const char * const p910_vcxo_out2_grps[] = {"vcxo out2-1",
- "vcxo out2-2"};
-static const char * const p910_vcxo_req2_grps[] = {"vcxo req2"};
-static const char * const p910_ulpi_grps[] = {"ulpi"};
-static const char * const p910_nand_grps[] = {"nand"};
-static const char * const p910_gpio0_grps[] = {"gpio0-1", "gpio0-2"};
-static const char * const p910_gpio1_grps[] = {"gpio1-1", "gpio1-2"};
-static const char * const p910_gpio2_grps[] = {"gpio2-1", "gpio2-2"};
-static const char * const p910_gpio3_grps[] = {"gpio3-1", "gpio3-2"};
-static const char * const p910_gpio20_grps[] = {"gpio20-1", "gpio20-2"};
-static const char * const p910_gpio21_grps[] = {"gpio21-1", "gpio21-2"};
-static const char * const p910_gpio22_grps[] = {"gpio22-1", "gpio22-2"};
-static const char * const p910_gpio23_grps[] = {"gpio23-1", "gpio23-2"};
-static const char * const p910_gpio24_grps[] = {"gpio24-1", "gpio24-2"};
-static const char * const p910_gpio25_grps[] = {"gpio25-1", "gpio25-2"};
-static const char * const p910_gpio26_grps[] = {"gpio26-1", "gpio26-2"};
-static const char * const p910_gpio27_grps[] = {"gpio27-1", "gpio27-2"};
-static const char * const p910_gpio85_grps[] = {"gpio85-1", "gpio85-2"};
-static const char * const p910_gpio86_grps[] = {"gpio86-1", "gpio86-2"};
-static const char * const p910_gpio87_grps[] = {"gpio87-1", "gpio87-2"};
-static const char * const p910_gpio88_grps[] = {"gpio88-1", "gpio88-2"};
-static const char * const p910_gpio89_grps[] = {"gpio89-1", "gpio89-2"};
-static const char * const p910_gpio90_grps[] = {"gpio90-1", "gpio90-2"};
-static const char * const p910_gpio91_grps[] = {"gpio91-1", "gpio91-2"};
-static const char * const p910_gpio92_grps[] = {"gpio92-1", "gpio92-2"};
-
-static struct pxa3xx_pmx_func pxa910_funcs[] = {
- {"usim2", ARRAY_AND_SIZE(p910_usim2_grps)},
- {"mmc1", ARRAY_AND_SIZE(p910_mmc1_grps)},
- {"mmc2", ARRAY_AND_SIZE(p910_mmc2_grps)},
- {"mmc3", ARRAY_AND_SIZE(p910_mmc3_grps)},
- {"uart0", ARRAY_AND_SIZE(p910_uart0_grps)},
- {"uart1", ARRAY_AND_SIZE(p910_uart1_grps)},
- {"uart2", ARRAY_AND_SIZE(p910_uart2_grps)},
- {"twsi", ARRAY_AND_SIZE(p910_twsi_grps)},
- {"ccic", ARRAY_AND_SIZE(p910_ccic_grps)},
- {"lcd", ARRAY_AND_SIZE(p910_lcd_grps)},
- {"spi", ARRAY_AND_SIZE(p910_spi_grps)},
- {"dssp2", ARRAY_AND_SIZE(p910_dssp2_grps)},
- {"dssp3", ARRAY_AND_SIZE(p910_dssp3_grps)},
- {"ssp0", ARRAY_AND_SIZE(p910_ssp0_grps)},
- {"ssp1", ARRAY_AND_SIZE(p910_ssp1_grps)},
- {"ssp2", ARRAY_AND_SIZE(p910_ssp2_grps)},
- {"gssp", ARRAY_AND_SIZE(p910_gssp_grps)},
- {"pwm0", ARRAY_AND_SIZE(p910_pwm0_grps)},
- {"pwm1", ARRAY_AND_SIZE(p910_pwm1_grps)},
- {"pwm2", ARRAY_AND_SIZE(p910_pwm2_grps)},
- {"pwm3", ARRAY_AND_SIZE(p910_pwm3_grps)},
- {"pri_jtag", ARRAY_AND_SIZE(p910_pri_jtag_grps)},
- {"sec1_jtag", ARRAY_AND_SIZE(p910_sec1_jtag_grps)},
- {"sec2_jtag", ARRAY_AND_SIZE(p910_sec2_jtag_grps)},
- {"hsl", ARRAY_AND_SIZE(p910_hsl_grps)},
- {"w1", ARRAY_AND_SIZE(p910_w1_grps)},
- {"kpmk", ARRAY_AND_SIZE(p910_kpmk_grps)},
- {"kpdk", ARRAY_AND_SIZE(p910_kpdk_grps)},
- {"tds", ARRAY_AND_SIZE(p910_tds_grps)},
- {"tb", ARRAY_AND_SIZE(p910_tb_grps)},
- {"dma0", ARRAY_AND_SIZE(p910_dma0_grps)},
- {"dma1", ARRAY_AND_SIZE(p910_dma1_grps)},
- {"dma2", ARRAY_AND_SIZE(p910_dma2_grps)},
- {"int0", ARRAY_AND_SIZE(p910_int0_grps)},
- {"int1", ARRAY_AND_SIZE(p910_int1_grps)},
- {"int2", ARRAY_AND_SIZE(p910_int2_grps)},
- {"dac_st23", ARRAY_AND_SIZE(p910_dac_st23_grps)},
- {"vcxo_out", ARRAY_AND_SIZE(p910_vcxo_out_grps)},
- {"vcxo_req", ARRAY_AND_SIZE(p910_vcxo_req_grps)},
- {"vcxo_out2", ARRAY_AND_SIZE(p910_vcxo_out2_grps)},
- {"vcxo_req2", ARRAY_AND_SIZE(p910_vcxo_req2_grps)},
- {"ulpi", ARRAY_AND_SIZE(p910_ulpi_grps)},
- {"nand", ARRAY_AND_SIZE(p910_nand_grps)},
- {"gpio0", ARRAY_AND_SIZE(p910_gpio0_grps)},
- {"gpio1", ARRAY_AND_SIZE(p910_gpio1_grps)},
- {"gpio2", ARRAY_AND_SIZE(p910_gpio2_grps)},
- {"gpio3", ARRAY_AND_SIZE(p910_gpio3_grps)},
- {"gpio20", ARRAY_AND_SIZE(p910_gpio20_grps)},
- {"gpio21", ARRAY_AND_SIZE(p910_gpio21_grps)},
- {"gpio22", ARRAY_AND_SIZE(p910_gpio22_grps)},
- {"gpio23", ARRAY_AND_SIZE(p910_gpio23_grps)},
- {"gpio24", ARRAY_AND_SIZE(p910_gpio24_grps)},
- {"gpio25", ARRAY_AND_SIZE(p910_gpio25_grps)},
- {"gpio26", ARRAY_AND_SIZE(p910_gpio26_grps)},
- {"gpio27", ARRAY_AND_SIZE(p910_gpio27_grps)},
- {"gpio85", ARRAY_AND_SIZE(p910_gpio85_grps)},
- {"gpio86", ARRAY_AND_SIZE(p910_gpio86_grps)},
- {"gpio87", ARRAY_AND_SIZE(p910_gpio87_grps)},
- {"gpio88", ARRAY_AND_SIZE(p910_gpio88_grps)},
- {"gpio89", ARRAY_AND_SIZE(p910_gpio89_grps)},
- {"gpio90", ARRAY_AND_SIZE(p910_gpio90_grps)},
- {"gpio91", ARRAY_AND_SIZE(p910_gpio91_grps)},
- {"gpio92", ARRAY_AND_SIZE(p910_gpio92_grps)},
-};
-
-static struct pinctrl_desc pxa910_pctrl_desc = {
- .name = "pxa910-pinctrl",
- .owner = THIS_MODULE,
-};
-
-static struct pxa3xx_pinmux_info pxa910_info = {
- .mfp = pxa910_mfp,
- .num_mfp = ARRAY_SIZE(pxa910_mfp),
- .grps = pxa910_grps,
- .num_grps = ARRAY_SIZE(pxa910_grps),
- .funcs = pxa910_funcs,
- .num_funcs = ARRAY_SIZE(pxa910_funcs),
- .num_gpio = 128,
- .desc = &pxa910_pctrl_desc,
- .pads = pxa910_pads,
- .num_pads = ARRAY_SIZE(pxa910_pads),
-
- .cputype = PINCTRL_PXA910,
- .ds_mask = PXA910_DS_MASK,
- .ds_shift = PXA910_DS_SHIFT,
-};
-
-static int pxa910_pinmux_probe(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_register(pdev, &pxa910_info);
-}
-
-static int pxa910_pinmux_remove(struct platform_device *pdev)
-{
- return pxa3xx_pinctrl_unregister(pdev);
-}
-
-static struct platform_driver pxa910_pinmux_driver = {
- .driver = {
- .name = "pxa910-pinmux",
- .owner = THIS_MODULE,
- },
- .probe = pxa910_pinmux_probe,
- .remove = pxa910_pinmux_remove,
-};
-
-static int __init pxa910_pinmux_init(void)
-{
- return platform_driver_register(&pxa910_pinmux_driver);
-}
-core_initcall_sync(pxa910_pinmux_init);
-
-static void __exit pxa910_pinmux_exit(void)
-{
- platform_driver_unregister(&pxa910_pinmux_driver);
-}
-module_exit(pxa910_pinmux_exit);
-
-MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
-MODULE_DESCRIPTION("PXA3xx pin control driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-s3c64xx.c b/drivers/pinctrl/pinctrl-s3c64xx.c
new file mode 100644
index 000000000000..89143c903000
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-s3c64xx.c
@@ -0,0 +1,816 @@
+/*
+ * S3C64xx specific support for pinctrl-samsung driver.
+ *
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
+ *
+ * Based on pinctrl-exynos.c, please see the file for original copyrights.
+ *
+ * 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 file contains the Samsung S3C64xx specific information required by the
+ * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
+ * external gpio and wakeup interrupt support.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "pinctrl-samsung.h"
+
+#define NUM_EINT0 28
+#define NUM_EINT0_IRQ 4
+#define EINT_MAX_PER_REG 16
+#define EINT_MAX_PER_GROUP 16
+
+/* External GPIO and wakeup interrupt related definitions */
+#define SVC_GROUP_SHIFT 4
+#define SVC_GROUP_MASK 0xf
+#define SVC_NUM_MASK 0xf
+#define SVC_GROUP(x) ((x >> SVC_GROUP_SHIFT) & \
+ SVC_GROUP_MASK)
+
+#define EINT12CON_REG 0x200
+#define EINT12MASK_REG 0x240
+#define EINT12PEND_REG 0x260
+
+#define EINT_OFFS(i) ((i) % (2 * EINT_MAX_PER_GROUP))
+#define EINT_GROUP(i) ((i) / EINT_MAX_PER_GROUP)
+#define EINT_REG(g) (4 * ((g) / 2))
+
+#define EINTCON_REG(i) (EINT12CON_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTMASK_REG(i) (EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))
+#define EINTPEND_REG(i) (EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))
+
+#define SERVICE_REG 0x284
+#define SERVICEPEND_REG 0x288
+
+#define EINT0CON0_REG 0x900
+#define EINT0MASK_REG 0x920
+#define EINT0PEND_REG 0x924
+
+/* S3C64xx specific external interrupt trigger types */
+#define EINT_LEVEL_LOW 0
+#define EINT_LEVEL_HIGH 1
+#define EINT_EDGE_FALLING 2
+#define EINT_EDGE_RISING 4
+#define EINT_EDGE_BOTH 6
+#define EINT_CON_MASK 0xF
+#define EINT_CON_LEN 4
+
+static struct samsung_pin_bank_type bank_type_4bit_off = {
+ .fld_width = { 4, 1, 2, 0, 2, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit_alive = {
+ .fld_width = { 4, 1, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_off = {
+ .fld_width = { 4, 1, 2, 0, 2, 2, },
+ .reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
+};
+
+static struct samsung_pin_bank_type bank_type_4bit2_alive = {
+ .fld_width = { 4, 1, 2, },
+ .reg_offset = { 0x00, 0x08, 0x0c, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_off = {
+ .fld_width = { 2, 1, 2, 0, 2, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
+};
+
+static struct samsung_pin_bank_type bank_type_2bit_alive = {
+ .fld_width = { 2, 1, 2, },
+ .reg_offset = { 0x00, 0x04, 0x08, },
+};
+
+#define PIN_BANK_4BIT(pins, reg, id) \
+ { \
+ .type = &bank_type_4bit_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_NONE, \
+ .name = id \
+ }
+
+#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs) \
+ { \
+ .type = &bank_type_4bit_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_GPIO, \
+ .eint_func = 7, \
+ .eint_mask = (1 << (pins)) - 1, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
+ { \
+ .type = &bank_type_4bit_alive,\
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_WKUP, \
+ .eint_func = 3, \
+ .eint_mask = emask, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs) \
+ { \
+ .type = &bank_type_4bit2_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_GPIO, \
+ .eint_func = 7, \
+ .eint_mask = (1 << (pins)) - 1, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
+ { \
+ .type = &bank_type_4bit2_alive,\
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_WKUP, \
+ .eint_func = 3, \
+ .eint_mask = emask, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+#define PIN_BANK_4BIT2_ALIVE(pins, reg, id) \
+ { \
+ .type = &bank_type_4bit2_alive,\
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_NONE, \
+ .name = id \
+ }
+
+#define PIN_BANK_2BIT(pins, reg, id) \
+ { \
+ .type = &bank_type_2bit_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_NONE, \
+ .name = id \
+ }
+
+#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
+ { \
+ .type = &bank_type_2bit_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_GPIO, \
+ .eint_func = 3, \
+ .eint_mask = emask, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs) \
+ { \
+ .type = &bank_type_2bit_alive,\
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_WKUP, \
+ .eint_func = 2, \
+ .eint_mask = (1 << (pins)) - 1, \
+ .eint_offset = eoffs, \
+ .name = id \
+ }
+
+/**
+ * struct s3c64xx_eint0_data: EINT0 common data
+ * @drvdata: pin controller driver data
+ * @domains: IRQ domains of particular EINT0 interrupts
+ * @pins: pin offsets inside of banks of particular EINT0 interrupts
+ */
+struct s3c64xx_eint0_data {
+ struct samsung_pinctrl_drv_data *drvdata;
+ struct irq_domain *domains[NUM_EINT0];
+ u8 pins[NUM_EINT0];
+};
+
+/**
+ * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
+ * @bank: pin bank related to the domain
+ * @eints: EINT0 interrupts related to the domain
+ */
+struct s3c64xx_eint0_domain_data {
+ struct samsung_pin_bank *bank;
+ u8 eints[];
+};
+
+/**
+ * struct s3c64xx_eint_gpio_data: GPIO EINT data
+ * @drvdata: pin controller driver data
+ * @domains: array of domains related to EINT interrupt groups
+ */
+struct s3c64xx_eint_gpio_data {
+ struct samsung_pinctrl_drv_data *drvdata;
+ struct irq_domain *domains[];
+};
+
+/*
+ * Common functions for S3C64xx EINT configuration
+ */
+
+static int s3c64xx_irq_get_trigger(unsigned int type)
+{
+ int trigger;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = EINT_EDGE_RISING;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = EINT_EDGE_FALLING;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = EINT_EDGE_BOTH;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = EINT_LEVEL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = EINT_LEVEL_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return trigger;
+}
+
+static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
+{
+ /* Edge- and level-triggered interrupts need different handlers */
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(irq, handle_edge_irq);
+ else
+ __irq_set_handler_locked(irq, handle_level_irq);
+}
+
+static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
+ struct samsung_pin_bank *bank, int pin)
+{
+ struct samsung_pin_bank_type *bank_type = bank->type;
+ unsigned long flags;
+ void __iomem *reg;
+ u8 shift;
+ u32 mask;
+ u32 val;
+
+ /* Make sure that pin is configured as interrupt */
+ reg = d->virt_base + bank->pctl_offset;
+ shift = pin;
+ if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) {
+ /* 4-bit bank type with 2 con regs */
+ reg += 4;
+ shift -= 8;
+ }
+
+ shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC];
+ mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+ spin_lock_irqsave(&bank->slock, flags);
+
+ val = readl(reg);
+ val &= ~(mask << shift);
+ val |= bank->eint_func << shift;
+ writel(val, reg);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+/*
+ * Functions for EINT GPIO configuration (EINT groups 1-9)
+ */
+
+static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+ void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset);
+ u32 val;
+
+ val = readl(reg);
+ if (mask)
+ val |= 1 << index;
+ else
+ val &= ~(1 << index);
+ writel(val, reg);
+}
+
+static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd)
+{
+ s3c64xx_gpio_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_gpio_irq_mask(struct irq_data *irqd)
+{
+ s3c64xx_gpio_irq_set_mask(irqd, true);
+}
+
+static void s3c64xx_gpio_irq_ack(struct irq_data *irqd)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+ void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset);
+
+ writel(1 << index, reg);
+}
+
+static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ void __iomem *reg;
+ int trigger;
+ u8 shift;
+ u32 val;
+
+ trigger = s3c64xx_irq_get_trigger(type);
+ if (trigger < 0) {
+ pr_err("unsupported external interrupt type\n");
+ return -EINVAL;
+ }
+
+ s3c64xx_irq_set_handler(irqd->irq, type);
+
+ /* Set up interrupt trigger */
+ reg = d->virt_base + EINTCON_REG(bank->eint_offset);
+ shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq;
+ shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */
+
+ val = readl(reg);
+ val &= ~(EINT_CON_MASK << shift);
+ val |= trigger << shift;
+ writel(val, reg);
+
+ s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+ return 0;
+}
+
+/*
+ * irq_chip for gpio interrupts.
+ */
+static struct irq_chip s3c64xx_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_unmask = s3c64xx_gpio_irq_unmask,
+ .irq_mask = s3c64xx_gpio_irq_mask,
+ .irq_ack = s3c64xx_gpio_irq_ack,
+ .irq_set_type = s3c64xx_gpio_irq_set_type,
+};
+
+static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct samsung_pin_bank *bank = h->host_data;
+
+ if (!(bank->eint_mask & (1 << hw)))
+ return -EINVAL;
+
+ irq_set_chip_and_handler(virq,
+ &s3c64xx_gpio_irq_chip, handle_level_irq);
+ irq_set_chip_data(virq, bank);
+ set_irq_flags(virq, IRQF_VALID);
+
+ return 0;
+}
+
+/*
+ * irq domain callbacks for external gpio interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = {
+ .map = s3c64xx_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq);
+ struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
+
+ chained_irq_enter(chip, desc);
+
+ do {
+ unsigned int svc;
+ unsigned int group;
+ unsigned int pin;
+ unsigned int virq;
+
+ svc = readl(drvdata->virt_base + SERVICE_REG);
+ group = SVC_GROUP(svc);
+ pin = svc & SVC_NUM_MASK;
+
+ if (!group)
+ break;
+
+ /* Group 1 is used for two pin banks */
+ if (group == 1) {
+ if (pin < 8)
+ group = 0;
+ else
+ pin -= 8;
+ }
+
+ virq = irq_linear_revmap(data->domains[group], pin);
+ /*
+ * Something must be really wrong if an unmapped EINT
+ * was unmasked...
+ */
+ BUG_ON(!virq);
+
+ generic_handle_irq(virq);
+ } while (1);
+
+ chained_irq_exit(chip, desc);
+}
+
+/**
+ * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
+{
+ struct s3c64xx_eint_gpio_data *data;
+ struct samsung_pin_bank *bank;
+ struct device *dev = d->dev;
+ unsigned int nr_domains;
+ unsigned int i;
+
+ if (!d->irq) {
+ dev_err(dev, "irq number not available\n");
+ return -EINVAL;
+ }
+
+ nr_domains = 0;
+ bank = d->ctrl->pin_banks;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ unsigned int nr_eints;
+ unsigned int mask;
+
+ if (bank->eint_type != EINT_TYPE_GPIO)
+ continue;
+
+ mask = bank->eint_mask;
+ nr_eints = fls(mask);
+
+ bank->irq_domain = irq_domain_add_linear(bank->of_node,
+ nr_eints, &s3c64xx_gpio_irqd_ops, bank);
+ if (!bank->irq_domain) {
+ dev_err(dev, "gpio irq domain add failed\n");
+ return -ENXIO;
+ }
+
+ ++nr_domains;
+ }
+
+ data = devm_kzalloc(dev, sizeof(*data)
+ + nr_domains * sizeof(*data->domains), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "failed to allocate handler data\n");
+ return -ENOMEM;
+ }
+ data->drvdata = d;
+
+ bank = d->ctrl->pin_banks;
+ nr_domains = 0;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ if (bank->eint_type != EINT_TYPE_GPIO)
+ continue;
+
+ data->domains[nr_domains++] = bank->irq_domain;
+ }
+
+ irq_set_chained_handler(d->irq, s3c64xx_eint_gpio_irq);
+ irq_set_handler_data(d->irq, data);
+
+ return 0;
+}
+
+/*
+ * Functions for configuration of EINT0 wake-up interrupts
+ */
+
+static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask)
+{
+ struct s3c64xx_eint0_domain_data *ddata =
+ irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
+ u32 val;
+
+ val = readl(d->virt_base + EINT0MASK_REG);
+ if (mask)
+ val |= 1 << ddata->eints[irqd->hwirq];
+ else
+ val &= ~(1 << ddata->eints[irqd->hwirq]);
+ writel(val, d->virt_base + EINT0MASK_REG);
+}
+
+static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd)
+{
+ s3c64xx_eint0_irq_set_mask(irqd, false);
+}
+
+static void s3c64xx_eint0_irq_mask(struct irq_data *irqd)
+{
+ s3c64xx_eint0_irq_set_mask(irqd, true);
+}
+
+static void s3c64xx_eint0_irq_ack(struct irq_data *irqd)
+{
+ struct s3c64xx_eint0_domain_data *ddata =
+ irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata;
+
+ writel(1 << ddata->eints[irqd->hwirq],
+ d->virt_base + EINT0PEND_REG);
+}
+
+static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+ struct s3c64xx_eint0_domain_data *ddata =
+ irq_data_get_irq_chip_data(irqd);
+ struct samsung_pin_bank *bank = ddata->bank;
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ void __iomem *reg;
+ int trigger;
+ u8 shift;
+ u32 val;
+
+ trigger = s3c64xx_irq_get_trigger(type);
+ if (trigger < 0) {
+ pr_err("unsupported external interrupt type\n");
+ return -EINVAL;
+ }
+
+ s3c64xx_irq_set_handler(irqd->irq, type);
+
+ /* Set up interrupt trigger */
+ reg = d->virt_base + EINT0CON0_REG;
+ shift = ddata->eints[irqd->hwirq];
+ if (shift >= EINT_MAX_PER_REG) {
+ reg += 4;
+ shift -= EINT_MAX_PER_REG;
+ }
+ shift = EINT_CON_LEN * (shift / 2);
+
+ val = readl(reg);
+ val &= ~(EINT_CON_MASK << shift);
+ val |= trigger << shift;
+ writel(val, reg);
+
+ s3c64xx_irq_set_function(d, bank, irqd->hwirq);
+
+ return 0;
+}
+
+/*
+ * irq_chip for wakeup interrupts
+ */
+static struct irq_chip s3c64xx_eint0_irq_chip = {
+ .name = "EINT0",
+ .irq_unmask = s3c64xx_eint0_irq_unmask,
+ .irq_mask = s3c64xx_eint0_irq_mask,
+ .irq_ack = s3c64xx_eint0_irq_ack,
+ .irq_set_type = s3c64xx_eint0_irq_set_type,
+};
+
+static inline void s3c64xx_irq_demux_eint(unsigned int irq,
+ struct irq_desc *desc, u32 range)
+{
+ struct irq_chip *chip = irq_get_chip(irq);
+ struct s3c64xx_eint0_data *data = irq_get_handler_data(irq);
+ struct samsung_pinctrl_drv_data *drvdata = data->drvdata;
+ unsigned int pend, mask;
+
+ chained_irq_enter(chip, desc);
+
+ pend = readl(drvdata->virt_base + EINT0PEND_REG);
+ mask = readl(drvdata->virt_base + EINT0MASK_REG);
+
+ pend = pend & range & ~mask;
+ pend &= range;
+
+ while (pend) {
+ unsigned int virq;
+
+ irq = fls(pend) - 1;
+ pend &= ~(1 << irq);
+
+ virq = irq_linear_revmap(data->domains[irq], data->pins[irq]);
+ /*
+ * Something must be really wrong if an unmapped EINT
+ * was unmasked...
+ */
+ BUG_ON(!virq);
+
+ generic_handle_irq(virq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc)
+{
+ s3c64xx_irq_demux_eint(irq, desc, 0xf);
+}
+
+static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc)
+{
+ s3c64xx_irq_demux_eint(irq, desc, 0xff0);
+}
+
+static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc)
+{
+ s3c64xx_irq_demux_eint(irq, desc, 0xff000);
+}
+
+static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc)
+{
+ s3c64xx_irq_demux_eint(irq, desc, 0xff00000);
+}
+
+static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = {
+ s3c64xx_demux_eint0_3,
+ s3c64xx_demux_eint4_11,
+ s3c64xx_demux_eint12_19,
+ s3c64xx_demux_eint20_27,
+};
+
+static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct s3c64xx_eint0_domain_data *ddata = h->host_data;
+ struct samsung_pin_bank *bank = ddata->bank;
+
+ if (!(bank->eint_mask & (1 << hw)))
+ return -EINVAL;
+
+ irq_set_chip_and_handler(virq,
+ &s3c64xx_eint0_irq_chip, handle_level_irq);
+ irq_set_chip_data(virq, ddata);
+ set_irq_flags(virq, IRQF_VALID);
+
+ return 0;
+}
+
+/*
+ * irq domain callbacks for external wakeup interrupt controller.
+ */
+static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = {
+ .map = s3c64xx_eint0_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+/* list of external wakeup controllers supported */
+static const struct of_device_id s3c64xx_eint0_irq_ids[] = {
+ { .compatible = "samsung,s3c64xx-wakeup-eint", },
+ { }
+};
+
+/**
+ * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts.
+ * @d: driver data of samsung pinctrl driver.
+ */
+static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
+{
+ struct device *dev = d->dev;
+ struct device_node *eint0_np = NULL;
+ struct device_node *np;
+ struct samsung_pin_bank *bank;
+ struct s3c64xx_eint0_data *data;
+ unsigned int i;
+
+ for_each_child_of_node(dev->of_node, np) {
+ if (of_match_node(s3c64xx_eint0_irq_ids, np)) {
+ eint0_np = np;
+ break;
+ }
+ }
+ if (!eint0_np)
+ return -ENODEV;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "could not allocate memory for wkup eint data\n");
+ return -ENOMEM;
+ }
+ data->drvdata = d;
+
+ for (i = 0; i < NUM_EINT0_IRQ; ++i) {
+ unsigned int irq;
+
+ irq = irq_of_parse_and_map(eint0_np, i);
+ if (!irq) {
+ dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i);
+ return -ENXIO;
+ }
+
+ irq_set_chained_handler(irq, s3c64xx_eint0_handlers[i]);
+ irq_set_handler_data(irq, data);
+ }
+
+ bank = d->ctrl->pin_banks;
+ for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ struct s3c64xx_eint0_domain_data *ddata;
+ unsigned int nr_eints;
+ unsigned int mask;
+ unsigned int irq;
+ unsigned int pin;
+
+ if (bank->eint_type != EINT_TYPE_WKUP)
+ continue;
+
+ mask = bank->eint_mask;
+ nr_eints = fls(mask);
+
+ ddata = devm_kzalloc(dev,
+ sizeof(*ddata) + nr_eints, GFP_KERNEL);
+ if (!ddata) {
+ dev_err(dev, "failed to allocate domain data\n");
+ return -ENOMEM;
+ }
+ ddata->bank = bank;
+
+ bank->irq_domain = irq_domain_add_linear(bank->of_node,
+ nr_eints, &s3c64xx_eint0_irqd_ops, ddata);
+ if (!bank->irq_domain) {
+ dev_err(dev, "wkup irq domain add failed\n");
+ return -ENXIO;
+ }
+
+ irq = bank->eint_offset;
+ mask = bank->eint_mask;
+ for (pin = 0; mask; ++pin, mask >>= 1) {
+ if (!(mask & 1))
+ continue;
+ data->domains[irq] = bank->irq_domain;
+ data->pins[irq] = pin;
+ ddata->eints[pin] = irq;
+ ++irq;
+ }
+ }
+
+ return 0;
+}
+
+/* pin banks of s3c64xx pin-controller 0 */
+static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
+ PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
+ PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
+ PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
+ PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32),
+ PIN_BANK_4BIT(5, 0x080, "gpe"),
+ PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff),
+ PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64),
+ PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80),
+ PIN_BANK_2BIT(16, 0x100, "gpi"),
+ PIN_BANK_2BIT(12, 0x120, "gpj"),
+ PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"),
+ PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00),
+ PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f),
+ PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0),
+ PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff),
+ PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff),
+ PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff),
+};
+
+/*
+ * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
+ * one gpio/pin-mux/pinconfig controller.
+ */
+struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
+ {
+ /* pin-controller instance 1 data */
+ .pin_banks = s3c64xx_pin_banks0,
+ .nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0),
+ .eint_gpio_init = s3c64xx_eint_gpio_init,
+ .eint_wkup_init = s3c64xx_eint_eint0_init,
+ .label = "S3C64xx-GPIO",
+ },
+};
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index f206df175656..4f54faf2971f 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -27,6 +27,7 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
+#include <linux/spinlock.h>
#include "core.h"
#include "pinctrl-samsung.h"
@@ -214,7 +215,7 @@ static void samsung_dt_free_map(struct pinctrl_dev *pctldev,
}
/* list of pinctrl callbacks for the pinctrl core */
-static struct pinctrl_ops samsung_pctrl_ops = {
+static const struct pinctrl_ops samsung_pctrl_ops = {
.get_groups_count = samsung_get_group_count,
.get_group_name = samsung_get_group_name,
.get_group_pins = samsung_get_group_pins,
@@ -274,10 +275,6 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
*offset = pin - b->pin_base;
if (bank)
*bank = b;
-
- /* some banks have two config registers in a single bank */
- if (*offset * b->func_width > BITS_PER_LONG)
- *reg += 4;
}
/* enable or disable a pinmux function */
@@ -289,6 +286,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
struct samsung_pin_bank *bank;
void __iomem *reg;
u32 mask, shift, data, pin_offset, cnt;
+ unsigned long flags;
drvdata = pinctrl_dev_get_drvdata(pctldev);
pins = drvdata->pin_groups[group].pins;
@@ -298,16 +296,28 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
* pin function number in the config register.
*/
for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) {
+ struct samsung_pin_bank_type *type;
+
pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base,
&reg, &pin_offset, &bank);
- mask = (1 << bank->func_width) - 1;
- shift = pin_offset * bank->func_width;
+ type = bank->type;
+ mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+ shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
+ if (shift >= 32) {
+ /* Some banks have two config registers */
+ shift -= 32;
+ reg += 4;
+ }
+
+ spin_lock_irqsave(&bank->slock, flags);
- data = readl(reg);
+ data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]);
data &= ~(mask << shift);
if (enable)
data |= drvdata->pin_groups[group].func << shift;
- writel(data, reg);
+ writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
}
}
@@ -334,30 +344,44 @@ static void samsung_pinmux_disable(struct pinctrl_dev *pctldev,
static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range, unsigned offset, bool input)
{
+ struct samsung_pin_bank_type *type;
struct samsung_pin_bank *bank;
struct samsung_pinctrl_drv_data *drvdata;
void __iomem *reg;
u32 data, pin_offset, mask, shift;
+ unsigned long flags;
bank = gc_to_pin_bank(range->gc);
+ type = bank->type;
drvdata = pinctrl_dev_get_drvdata(pctldev);
pin_offset = offset - bank->pin_base;
- reg = drvdata->virt_base + bank->pctl_offset;
+ reg = drvdata->virt_base + bank->pctl_offset +
+ type->reg_offset[PINCFG_TYPE_FUNC];
+
+ mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+ shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC];
+ if (shift >= 32) {
+ /* Some banks have two config registers */
+ shift -= 32;
+ reg += 4;
+ }
- mask = (1 << bank->func_width) - 1;
- shift = pin_offset * bank->func_width;
+ spin_lock_irqsave(&bank->slock, flags);
data = readl(reg);
data &= ~(mask << shift);
if (!input)
data |= FUNC_OUTPUT << shift;
writel(data, reg);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
+
return 0;
}
/* list of pinmux callbacks for the pinmux vertical in pinctrl core */
-static struct pinmux_ops samsung_pinmux_ops = {
+static const struct pinmux_ops samsung_pinmux_ops = {
.get_functions_count = samsung_get_functions_count,
.get_function_name = samsung_pinmux_get_fname,
.get_function_groups = samsung_pinmux_get_groups,
@@ -371,40 +395,26 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config, bool set)
{
struct samsung_pinctrl_drv_data *drvdata;
+ struct samsung_pin_bank_type *type;
struct samsung_pin_bank *bank;
void __iomem *reg_base;
enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
u32 data, width, pin_offset, mask, shift;
u32 cfg_value, cfg_reg;
+ unsigned long flags;
drvdata = pinctrl_dev_get_drvdata(pctldev);
pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
&pin_offset, &bank);
+ type = bank->type;
- switch (cfg_type) {
- case PINCFG_TYPE_PUD:
- width = bank->pud_width;
- cfg_reg = PUD_REG;
- break;
- case PINCFG_TYPE_DRV:
- width = bank->drv_width;
- cfg_reg = DRV_REG;
- break;
- case PINCFG_TYPE_CON_PDN:
- width = bank->conpdn_width;
- cfg_reg = CONPDN_REG;
- break;
- case PINCFG_TYPE_PUD_PDN:
- width = bank->pudpdn_width;
- cfg_reg = PUDPDN_REG;
- break;
- default:
- WARN_ON(1);
+ if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type])
return -EINVAL;
- }
- if (!width)
- return -EINVAL;
+ width = type->fld_width[cfg_type];
+ cfg_reg = type->reg_offset[cfg_type];
+
+ spin_lock_irqsave(&bank->slock, flags);
mask = (1 << width) - 1;
shift = pin_offset * width;
@@ -420,6 +430,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
data &= mask;
*config = PINCFG_PACK(cfg_type, data);
}
+
+ spin_unlock_irqrestore(&bank->slock, flags);
+
return 0;
}
@@ -468,7 +481,7 @@ static int samsung_pinconf_group_get(struct pinctrl_dev *pctldev,
}
/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */
-static struct pinconf_ops samsung_pinconf_ops = {
+static const struct pinconf_ops samsung_pinconf_ops = {
.pin_config_get = samsung_pinconf_get,
.pin_config_set = samsung_pinconf_set,
.pin_config_group_get = samsung_pinconf_group_get,
@@ -479,16 +492,22 @@ static struct pinconf_ops samsung_pinconf_ops = {
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+ struct samsung_pin_bank_type *type = bank->type;
+ unsigned long flags;
void __iomem *reg;
u32 data;
reg = bank->drvdata->virt_base + bank->pctl_offset;
- data = readl(reg + DAT_REG);
+ spin_lock_irqsave(&bank->slock, flags);
+
+ data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
data &= ~(1 << offset);
if (value)
data |= 1 << offset;
- writel(data, reg + DAT_REG);
+ writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
}
/* gpiolib gpio_get callback function */
@@ -497,10 +516,11 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
void __iomem *reg;
u32 data;
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
+ struct samsung_pin_bank_type *type = bank->type;
reg = bank->drvdata->virt_base + bank->pctl_offset;
- data = readl(reg + DAT_REG);
+ data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]);
data >>= offset;
data &= 1;
return data;
@@ -859,6 +879,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
bank = ctrl->pin_banks;
for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+ spin_lock_init(&bank->slock);
bank->drvdata = d;
bank->pin_base = ctrl->nr_pins;
ctrl->nr_pins += bank->nr_pins;
@@ -944,10 +965,16 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
}
static const struct of_device_id samsung_pinctrl_dt_match[] = {
+#ifdef CONFIG_PINCTRL_EXYNOS
{ .compatible = "samsung,exynos4210-pinctrl",
.data = (void *)exynos4210_pin_ctrl },
{ .compatible = "samsung,exynos4x12-pinctrl",
.data = (void *)exynos4x12_pin_ctrl },
+#endif
+#ifdef CONFIG_PINCTRL_S3C64XX
+ { .compatible = "samsung,s3c64xx-pinctrl",
+ .data = s3c64xx_pin_ctrl },
+#endif
{},
};
MODULE_DEVICE_TABLE(of, samsung_pinctrl_dt_match);
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index e2d4e67f7e88..45f27b41e30c 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -25,28 +25,27 @@
#include <linux/gpio.h>
-/* register offsets within a pin bank */
-#define DAT_REG 0x4
-#define PUD_REG 0x8
-#define DRV_REG 0xC
-#define CONPDN_REG 0x10
-#define PUDPDN_REG 0x14
-
/* pinmux function number for pin as gpio output line */
#define FUNC_OUTPUT 0x1
/**
* enum pincfg_type - possible pin configuration types supported.
+ * @PINCFG_TYPE_FUNC: Function configuration.
+ * @PINCFG_TYPE_DAT: Pin value configuration.
* @PINCFG_TYPE_PUD: Pull up/down configuration.
* @PINCFG_TYPE_DRV: Drive strength configuration.
* @PINCFG_TYPE_CON_PDN: Pin function in power down mode.
* @PINCFG_TYPE_PUD_PDN: Pull up/down configuration in power down mode.
*/
enum pincfg_type {
+ PINCFG_TYPE_FUNC,
+ PINCFG_TYPE_DAT,
PINCFG_TYPE_PUD,
PINCFG_TYPE_DRV,
PINCFG_TYPE_CON_PDN,
PINCFG_TYPE_PUD_PDN,
+
+ PINCFG_TYPE_NUM
};
/*
@@ -103,33 +102,40 @@ enum eint_type {
struct samsung_pinctrl_drv_data;
/**
+ * struct samsung_pin_bank_type: pin bank type description
+ * @fld_width: widths of configuration bitfields (0 if unavailable)
+ * @reg_offset: offsets of configuration registers (don't care of width is 0)
+ */
+struct samsung_pin_bank_type {
+ u8 fld_width[PINCFG_TYPE_NUM];
+ u8 reg_offset[PINCFG_TYPE_NUM];
+};
+
+/**
* struct samsung_pin_bank: represent a controller pin-bank.
+ * @type: type of the bank (register offsets and bitfield widths)
* @pctl_offset: starting offset of the pin-bank registers.
* @pin_base: starting pin number of the bank.
* @nr_pins: number of pins included in this bank.
- * @func_width: width of the function selector bit field.
- * @pud_width: width of the pin pull up/down selector bit field.
- * @drv_width: width of the pin driver strength selector bit field.
- * @conpdn_width: width of the sleep mode function selector bin field.
- * @pudpdn_width: width of the sleep mode pull up/down selector bit field.
+ * @eint_func: function to set in CON register to configure pin as EINT.
* @eint_type: type of the external interrupt supported by the bank.
+ * @eint_mask: bit mask of pins which support EINT function.
* @name: name to be prefixed for each pin in this pin bank.
* @of_node: OF node of the bank.
* @drvdata: link to controller driver data
* @irq_domain: IRQ domain of the bank.
* @gpio_chip: GPIO chip of the bank.
* @grange: linux gpio pin range supported by this bank.
+ * @slock: spinlock protecting bank registers
*/
struct samsung_pin_bank {
+ struct samsung_pin_bank_type *type;
u32 pctl_offset;
u32 pin_base;
u8 nr_pins;
- u8 func_width;
- u8 pud_width;
- u8 drv_width;
- u8 conpdn_width;
- u8 pudpdn_width;
+ u8 eint_func;
enum eint_type eint_type;
+ u32 eint_mask;
u32 eint_offset;
char *name;
struct device_node *of_node;
@@ -137,6 +143,7 @@ struct samsung_pin_bank {
struct irq_domain *irq_domain;
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range grange;
+ spinlock_t slock;
};
/**
@@ -237,5 +244,6 @@ struct samsung_pmx_func {
/* list of all exported SoC specific data */
extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
+extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
#endif /* __PINCTRL_SAMSUNG_H */
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 5c32e880bcb2..5f2d2bfd356e 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -22,8 +22,10 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include "core.h"
+#include "pinconf.h"
#define DRIVER_NAME "pinctrl-single"
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
@@ -59,6 +61,33 @@ struct pcs_func_vals {
};
/**
+ * struct pcs_conf_vals - pinconf parameter, pinconf register offset
+ * and value, enable, disable, mask
+ * @param: config parameter
+ * @val: user input bits in the pinconf register
+ * @enable: enable bits in the pinconf register
+ * @disable: disable bits in the pinconf register
+ * @mask: mask bits in the register value
+ */
+struct pcs_conf_vals {
+ enum pin_config_param param;
+ unsigned val;
+ unsigned enable;
+ unsigned disable;
+ unsigned mask;
+};
+
+/**
+ * struct pcs_conf_type - pinconf property name, pinconf param pair
+ * @name: property name in DTS file
+ * @param: config parameter
+ */
+struct pcs_conf_type {
+ const char *name;
+ enum pin_config_param param;
+};
+
+/**
* struct pcs_function - pinctrl function
* @name: pinctrl function name
* @vals: register and vals array
@@ -73,6 +102,22 @@ struct pcs_function {
unsigned nvals;
const char **pgnames;
int npgnames;
+ struct pcs_conf_vals *conf;
+ int nconfs;
+ struct list_head node;
+};
+
+/**
+ * struct pcs_gpiofunc_range - pin ranges with same mux value of gpio function
+ * @offset: offset base of pins
+ * @npins: number pins with the same mux value of gpio function
+ * @gpiofunc: mux value of gpio function
+ * @node: list node
+ */
+struct pcs_gpiofunc_range {
+ unsigned offset;
+ unsigned npins;
+ unsigned gpiofunc;
struct list_head node;
};
@@ -117,12 +162,14 @@ struct pcs_name {
* @fshift: function register shift
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
+ * @is_pinconf: whether supports pinconf
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
* @ftree: function index radix tree
* @pingroups: list of pingroups
* @functions: list of functions
+ * @gpiofuncs: list of gpio functions
* @ngroups: number of pingroups
* @nfuncs: number of functions
* @desc: pin controller descriptor
@@ -142,12 +189,14 @@ struct pcs_device {
unsigned foff;
unsigned fmax;
bool bits_per_mux;
+ bool is_pinconf;
struct pcs_name *names;
struct pcs_data pins;
struct radix_tree_root pgtree;
struct radix_tree_root ftree;
struct list_head pingroups;
struct list_head functions;
+ struct list_head gpiofuncs;
unsigned ngroups;
unsigned nfuncs;
struct pinctrl_desc desc;
@@ -155,6 +204,16 @@ struct pcs_device {
void (*write)(unsigned val, void __iomem *reg);
};
+static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config);
+static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config);
+
+static enum pin_config_param pcs_bias[] = {
+ PIN_CONFIG_BIAS_PULL_DOWN,
+ PIN_CONFIG_BIAS_PULL_UP,
+};
+
/*
* REVISIT: Reads and writes could eventually use regmap or something
* generic. But at least on omaps, some mux registers are performance
@@ -270,7 +329,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps);
-static struct pinctrl_ops pcs_pinctrl_ops = {
+static const struct pinctrl_ops pcs_pinctrl_ops = {
.get_groups_count = pcs_get_groups_count,
.get_group_name = pcs_get_group_name,
.get_group_pins = pcs_get_group_pins,
@@ -326,6 +385,28 @@ static int pcs_get_function_groups(struct pinctrl_dev *pctldev,
return 0;
}
+static int pcs_get_function(struct pinctrl_dev *pctldev, unsigned pin,
+ struct pcs_function **func)
+{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pin_desc *pdesc = pin_desc_get(pctldev, pin);
+ const struct pinctrl_setting_mux *setting;
+ unsigned fselector;
+
+ /* If pin is not described in DTS & enabled, mux_setting is NULL. */
+ setting = pdesc->mux_setting;
+ if (!setting)
+ return -ENOTSUPP;
+ fselector = setting->func;
+ *func = radix_tree_lookup(&pcs->ftree, fselector);
+ if (!(*func)) {
+ dev_err(pcs->dev, "%s could not find function%i\n",
+ __func__, fselector);
+ return -ENOTSUPP;
+ }
+ return 0;
+}
+
static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
unsigned group)
{
@@ -334,6 +415,9 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
int i;
pcs = pinctrl_dev_get_drvdata(pctldev);
+ /* If function mask is null, needn't enable it. */
+ if (!pcs->fmask)
+ return 0;
func = radix_tree_lookup(&pcs->ftree, fselector);
if (!func)
return -EINVAL;
@@ -368,6 +452,10 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
int i;
pcs = pinctrl_dev_get_drvdata(pctldev);
+ /* If function mask is null, needn't disable it. */
+ if (!pcs->fmask)
+ return;
+
func = radix_tree_lookup(&pcs->ftree, fselector);
if (!func) {
dev_err(pcs->dev, "%s could not find function%i\n",
@@ -403,12 +491,33 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
}
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
+ struct pinctrl_gpio_range *range, unsigned pin)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_gpiofunc_range *frange = NULL;
+ struct list_head *pos, *tmp;
+ int mux_bytes = 0;
+ unsigned data;
+
+ /* If function mask is null, return directly. */
+ if (!pcs->fmask)
+ return -ENOTSUPP;
+
+ list_for_each_safe(pos, tmp, &pcs->gpiofuncs) {
+ frange = list_entry(pos, struct pcs_gpiofunc_range, node);
+ if (pin >= frange->offset + frange->npins
+ || pin < frange->offset)
+ continue;
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+ data |= frange->gpiofunc;
+ pcs->write(data, pcs->base + pin * mux_bytes);
+ break;
+ }
+ return 0;
}
-static struct pinmux_ops pcs_pinmux_ops = {
+static const struct pinmux_ops pcs_pinmux_ops = {
.get_functions_count = pcs_get_functions_count,
.get_function_name = pcs_get_function_name,
.get_function_groups = pcs_get_function_groups,
@@ -417,32 +526,190 @@ static struct pinmux_ops pcs_pinmux_ops = {
.gpio_request_enable = pcs_request_gpio,
};
+/* Clear BIAS value */
+static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin)
+{
+ unsigned long config;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+ config = pinconf_to_config_packed(pcs_bias[i], 0);
+ pcs_pinconf_set(pctldev, pin, config);
+ }
+}
+
+/*
+ * Check whether PIN_CONFIG_BIAS_DISABLE is valid.
+ * It's depend on that PULL_DOWN & PULL_UP configs are all invalid.
+ */
+static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin)
+{
+ unsigned long config;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+ config = pinconf_to_config_packed(pcs_bias[i], 0);
+ if (!pcs_pinconf_get(pctldev, pin, &config))
+ goto out;
+ }
+ return true;
+out:
+ return false;
+}
+
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_function *func;
+ enum pin_config_param param;
+ unsigned offset = 0, data = 0, i, j, ret;
+
+ ret = pcs_get_function(pctldev, pin, &func);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < func->nconfs; i++) {
+ param = pinconf_to_config_param(*config);
+ if (param == PIN_CONFIG_BIAS_DISABLE) {
+ if (pcs_pinconf_bias_disable(pctldev, pin)) {
+ *config = 0;
+ return 0;
+ } else {
+ return -ENOTSUPP;
+ }
+ } else if (param != func->conf[i].param) {
+ continue;
+ }
+
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ data = pcs->read(pcs->base + offset) & func->conf[i].mask;
+ switch (func->conf[i].param) {
+ /* 4 parameters */
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if ((data != func->conf[i].enable) ||
+ (data == func->conf[i].disable))
+ return -ENOTSUPP;
+ *config = 0;
+ break;
+ /* 2 parameters */
+ case PIN_CONFIG_INPUT_SCHMITT:
+ for (j = 0; j < func->nconfs; j++) {
+ switch (func->conf[j].param) {
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (data != func->conf[j].enable)
+ return -ENOTSUPP;
+ break;
+ default:
+ break;
+ }
+ }
+ *config = data;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ case PIN_CONFIG_SLEW_RATE:
+ default:
+ *config = data;
+ break;
+ }
+ return 0;
+ }
return -ENOTSUPP;
}
static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_function *func;
+ unsigned offset = 0, shift = 0, i, data, ret;
+ u16 arg;
+
+ ret = pcs_get_function(pctldev, pin, &func);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < func->nconfs; i++) {
+ if (pinconf_to_config_param(config) == func->conf[i].param) {
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ data = pcs->read(pcs->base + offset);
+ arg = pinconf_to_config_argument(config);
+ switch (func->conf[i].param) {
+ /* 2 parameters */
+ case PIN_CONFIG_INPUT_SCHMITT:
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ case PIN_CONFIG_SLEW_RATE:
+ shift = ffs(func->conf[i].mask) - 1;
+ data &= ~func->conf[i].mask;
+ data |= (arg << shift) & func->conf[i].mask;
+ break;
+ /* 4 parameters */
+ case PIN_CONFIG_BIAS_DISABLE:
+ pcs_pinconf_clear_bias(pctldev, pin);
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg)
+ pcs_pinconf_clear_bias(pctldev, pin);
+ /* fall through */
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ data &= ~func->conf[i].mask;
+ if (arg)
+ data |= func->conf[i].enable;
+ else
+ data |= func->conf[i].disable;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ pcs->write(data, pcs->base + offset);
+ return 0;
+ }
+ }
return -ENOTSUPP;
}
static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned group, unsigned long *config)
{
- return -ENOTSUPP;
+ const unsigned *pins;
+ unsigned npins, old = 0;
+ int i, ret;
+
+ ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+ for (i = 0; i < npins; i++) {
+ if (pcs_pinconf_get(pctldev, pins[i], config))
+ return -ENOTSUPP;
+ /* configs do not match between two pins */
+ if (i && (old != *config))
+ return -ENOTSUPP;
+ old = *config;
+ }
+ return 0;
}
static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config)
{
- return -ENOTSUPP;
+ const unsigned *pins;
+ unsigned npins;
+ int i, ret;
+
+ ret = pcs_get_group_pins(pctldev, group, &pins, &npins);
+ if (ret)
+ return ret;
+ for (i = 0; i < npins; i++) {
+ if (pcs_pinconf_set(pctldev, pins[i], config))
+ return -ENOTSUPP;
+ }
+ return 0;
}
static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned offset)
+ struct seq_file *s, unsigned pin)
{
}
@@ -451,13 +718,22 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
{
}
-static struct pinconf_ops pcs_pinconf_ops = {
+static void pcs_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ unsigned long config)
+{
+ pinconf_generic_dump_config(pctldev, s, config);
+}
+
+static const struct pinconf_ops pcs_pinconf_ops = {
.pin_config_get = pcs_pinconf_get,
.pin_config_set = pcs_pinconf_set,
.pin_config_group_get = pcs_pinconf_group_get,
.pin_config_group_set = pcs_pinconf_group_set,
.pin_config_dbg_show = pcs_pinconf_dbg_show,
.pin_config_group_dbg_show = pcs_pinconf_group_dbg_show,
+ .pin_config_config_dbg_show = pcs_pinconf_config_dbg_show,
+ .is_generic = true,
};
/**
@@ -648,11 +924,158 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
return index;
}
+/*
+ * check whether data matches enable bits or disable bits
+ * Return value: 1 for matching enable bits, 0 for matching disable bits,
+ * and negative value for matching failure.
+ */
+static int pcs_config_match(unsigned data, unsigned enable, unsigned disable)
+{
+ int ret = -EINVAL;
+
+ if (data == enable)
+ ret = 1;
+ else if (data == disable)
+ ret = 0;
+ return ret;
+}
+
+static void add_config(struct pcs_conf_vals **conf, enum pin_config_param param,
+ unsigned value, unsigned enable, unsigned disable,
+ unsigned mask)
+{
+ (*conf)->param = param;
+ (*conf)->val = value;
+ (*conf)->enable = enable;
+ (*conf)->disable = disable;
+ (*conf)->mask = mask;
+ (*conf)++;
+}
+
+static void add_setting(unsigned long **setting, enum pin_config_param param,
+ unsigned arg)
+{
+ **setting = pinconf_to_config_packed(param, arg);
+ (*setting)++;
+}
+
+/* add pinconf setting with 2 parameters */
+static void pcs_add_conf2(struct pcs_device *pcs, struct device_node *np,
+ const char *name, enum pin_config_param param,
+ struct pcs_conf_vals **conf, unsigned long **settings)
+{
+ unsigned value[2], shift;
+ int ret;
+
+ ret = of_property_read_u32_array(np, name, value, 2);
+ if (ret)
+ return;
+ /* set value & mask */
+ value[0] &= value[1];
+ shift = ffs(value[1]) - 1;
+ /* skip enable & disable */
+ add_config(conf, param, value[0], 0, 0, value[1]);
+ add_setting(settings, param, value[0] >> shift);
+}
+
+/* add pinconf setting with 4 parameters */
+static void pcs_add_conf4(struct pcs_device *pcs, struct device_node *np,
+ const char *name, enum pin_config_param param,
+ struct pcs_conf_vals **conf, unsigned long **settings)
+{
+ unsigned value[4];
+ int ret;
+
+ /* value to set, enable, disable, mask */
+ ret = of_property_read_u32_array(np, name, value, 4);
+ if (ret)
+ return;
+ if (!value[3]) {
+ dev_err(pcs->dev, "mask field of the property can't be 0\n");
+ return;
+ }
+ value[0] &= value[3];
+ value[1] &= value[3];
+ value[2] &= value[3];
+ ret = pcs_config_match(value[0], value[1], value[2]);
+ if (ret < 0)
+ dev_dbg(pcs->dev, "failed to match enable or disable bits\n");
+ add_config(conf, param, value[0], value[1], value[2], value[3]);
+ add_setting(settings, param, ret);
+}
+
+static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
+ struct pcs_function *func,
+ struct pinctrl_map **map)
+
+{
+ struct pinctrl_map *m = *map;
+ int i = 0, nconfs = 0;
+ unsigned long *settings = NULL, *s = NULL;
+ struct pcs_conf_vals *conf = NULL;
+ struct pcs_conf_type prop2[] = {
+ { "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
+ { "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
+ { "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
+ };
+ struct pcs_conf_type prop4[] = {
+ { "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
+ { "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
+ { "pinctrl-single,input-schmitt-enable",
+ PIN_CONFIG_INPUT_SCHMITT_ENABLE, },
+ };
+
+ /* If pinconf isn't supported, don't parse properties in below. */
+ if (!pcs->is_pinconf)
+ return 0;
+
+ /* cacluate how much properties are supported in current node */
+ for (i = 0; i < ARRAY_SIZE(prop2); i++) {
+ if (of_find_property(np, prop2[i].name, NULL))
+ nconfs++;
+ }
+ for (i = 0; i < ARRAY_SIZE(prop4); i++) {
+ if (of_find_property(np, prop4[i].name, NULL))
+ nconfs++;
+ }
+ if (!nconfs)
+ return 0;
+
+ func->conf = devm_kzalloc(pcs->dev,
+ sizeof(struct pcs_conf_vals) * nconfs,
+ GFP_KERNEL);
+ if (!func->conf)
+ return -ENOMEM;
+ func->nconfs = nconfs;
+ conf = &(func->conf[0]);
+ m++;
+ settings = devm_kzalloc(pcs->dev, sizeof(unsigned long) * nconfs,
+ GFP_KERNEL);
+ if (!settings)
+ return -ENOMEM;
+ s = &settings[0];
+
+ for (i = 0; i < ARRAY_SIZE(prop2); i++)
+ pcs_add_conf2(pcs, np, prop2[i].name, prop2[i].param,
+ &conf, &s);
+ for (i = 0; i < ARRAY_SIZE(prop4); i++)
+ pcs_add_conf4(pcs, np, prop4[i].name, prop4[i].param,
+ &conf, &s);
+ m->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ m->data.configs.group_or_pin = np->name;
+ m->data.configs.configs = settings;
+ m->data.configs.num_configs = nconfs;
+ return 0;
+}
+
+static void pcs_free_pingroups(struct pcs_device *pcs);
+
/**
* smux_parse_one_pinctrl_entry() - parses a device tree mux entry
* @pcs: pinctrl driver instance
* @np: device node of the mux entry
* @map: map entry
+ * @num_maps: number of map
* @pgnames: pingroup names
*
* Note that this binding currently supports only sets of one register + value.
@@ -669,6 +1092,7 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
struct device_node *np,
struct pinctrl_map **map,
+ unsigned *num_maps,
const char **pgnames)
{
struct pcs_func_vals *vals;
@@ -741,8 +1165,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
(*map)->data.mux.group = np->name;
(*map)->data.mux.function = np->name;
+ if (pcs->is_pinconf) {
+ if (pcs_parse_pinconf(pcs, np, function, map))
+ goto free_pingroups;
+ *num_maps = 2;
+ } else {
+ *num_maps = 1;
+ }
return 0;
+free_pingroups:
+ pcs_free_pingroups(pcs);
+ *num_maps = 1;
free_function:
pcs_remove_function(pcs, function);
@@ -771,7 +1205,8 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
pcs = pinctrl_dev_get_drvdata(pctldev);
- *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
+ /* create 2 maps. One is for pinmux, and the other is for pinconf. */
+ *map = devm_kzalloc(pcs->dev, sizeof(**map) * 2, GFP_KERNEL);
if (!*map)
return -ENOMEM;
@@ -783,13 +1218,13 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
goto free_map;
}
- ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
+ pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
}
- *num_maps = 1;
return 0;
@@ -879,6 +1314,37 @@ static void pcs_free_resources(struct pcs_device *pcs)
static struct of_device_id pcs_of_match[];
+static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
+{
+ const char *propname = "pinctrl-single,gpio-range";
+ const char *cellname = "#pinctrl-single,gpio-range-cells";
+ struct of_phandle_args gpiospec;
+ struct pcs_gpiofunc_range *range;
+ int ret, i;
+
+ for (i = 0; ; i++) {
+ ret = of_parse_phandle_with_args(node, propname, cellname,
+ i, &gpiospec);
+ /* Do not treat it as error. Only treat it as end condition. */
+ if (ret) {
+ ret = 0;
+ break;
+ }
+ range = devm_kzalloc(pcs->dev, sizeof(*range), GFP_KERNEL);
+ if (!range) {
+ ret = -ENOMEM;
+ break;
+ }
+ range->offset = gpiospec.args[0];
+ range->npins = gpiospec.args[1];
+ range->gpiofunc = gpiospec.args[2];
+ mutex_lock(&pcs->mutex);
+ list_add_tail(&range->node, &pcs->gpiofuncs);
+ mutex_unlock(&pcs->mutex);
+ }
+ return ret;
+}
+
static int pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -900,14 +1366,23 @@ static int pcs_probe(struct platform_device *pdev)
mutex_init(&pcs->mutex);
INIT_LIST_HEAD(&pcs->pingroups);
INIT_LIST_HEAD(&pcs->functions);
+ INIT_LIST_HEAD(&pcs->gpiofuncs);
+ pcs->is_pinconf = match->data;
PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
"register width not specified\n");
- PCS_GET_PROP_U32("pinctrl-single,function-mask", &pcs->fmask,
- "function register mask not specified\n");
- pcs->fshift = ffs(pcs->fmask) - 1;
- pcs->fmax = pcs->fmask >> pcs->fshift;
+ ret = of_property_read_u32(np, "pinctrl-single,function-mask",
+ &pcs->fmask);
+ if (!ret) {
+ pcs->fshift = ffs(pcs->fmask) - 1;
+ pcs->fmax = pcs->fmask >> pcs->fshift;
+ } else {
+ /* If mask property doesn't exist, function mux is invalid. */
+ pcs->fmask = 0;
+ pcs->fshift = 0;
+ pcs->fmax = 0;
+ }
ret = of_property_read_u32(np, "pinctrl-single,function-off",
&pcs->foff);
@@ -961,7 +1436,8 @@ static int pcs_probe(struct platform_device *pdev)
pcs->desc.name = DRIVER_NAME;
pcs->desc.pctlops = &pcs_pinctrl_ops;
pcs->desc.pmxops = &pcs_pinmux_ops;
- pcs->desc.confops = &pcs_pinconf_ops;
+ if (pcs->is_pinconf)
+ pcs->desc.confops = &pcs_pinconf_ops;
pcs->desc.owner = THIS_MODULE;
ret = pcs_allocate_pin_table(pcs);
@@ -975,6 +1451,10 @@ static int pcs_probe(struct platform_device *pdev)
goto free;
}
+ ret = pcs_add_gpio_func(np, pcs);
+ if (ret < 0)
+ goto free;
+
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
pcs->desc.npins, pcs->base, pcs->size);
@@ -999,7 +1479,8 @@ static int pcs_remove(struct platform_device *pdev)
}
static struct of_device_id pcs_of_match[] = {
- { .compatible = DRIVER_NAME, },
+ { .compatible = "pinctrl-single", .data = (void *)false },
+ { .compatible = "pinconf-single", .data = (void *)true },
{ },
};
MODULE_DEVICE_TABLE(of, pcs_of_match);
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index d02498b30c6e..fb9062570745 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -979,7 +979,7 @@ static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops sirfsoc_pctrl_ops = {
+static const struct pinctrl_ops sirfsoc_pctrl_ops = {
.get_groups_count = sirfsoc_get_groups_count,
.get_group_name = sirfsoc_get_group_name,
.get_group_pins = sirfsoc_get_group_pins,
@@ -1181,7 +1181,7 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
return 0;
}
-static struct pinmux_ops sirfsoc_pinmux_ops = {
+static const struct pinmux_ops sirfsoc_pinmux_ops = {
.enable = sirfsoc_pinmux_enable,
.disable = sirfsoc_pinmux_disable,
.get_functions_count = sirfsoc_pinmux_get_funcs_count,
@@ -1685,15 +1685,12 @@ static void sirfsoc_gpio_set_pullup(const u32 *pullups)
const unsigned long *p = (const unsigned long *)pullups;
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
- n = find_first_bit(p + i, BITS_PER_LONG);
- while (n < BITS_PER_LONG) {
+ for_each_set_bit(n, p + i, BITS_PER_LONG) {
u32 offset = SIRFSOC_GPIO_CTRL(i, n);
u32 val = readl(sgpio_bank[i].chip.regs + offset);
val |= SIRFSOC_GPIO_CTL_PULL_MASK;
val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
writel(val, sgpio_bank[i].chip.regs + offset);
-
- n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
}
}
}
@@ -1704,15 +1701,12 @@ static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
const unsigned long *p = (const unsigned long *)pulldowns;
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
- n = find_first_bit(p + i, BITS_PER_LONG);
- while (n < BITS_PER_LONG) {
+ for_each_set_bit(n, p + i, BITS_PER_LONG) {
u32 offset = SIRFSOC_GPIO_CTRL(i, n);
u32 val = readl(sgpio_bank[i].chip.regs + offset);
val |= SIRFSOC_GPIO_CTL_PULL_MASK;
val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
writel(val, sgpio_bank[i].chip.regs + offset);
-
- n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
}
}
}
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index 80b11e3415bc..c52fc2c08732 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -11,6 +11,7 @@
*/
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -30,482 +31,856 @@
static const struct sunxi_desc_pin sun4i_a10_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXD3 */
+ SUNXI_FUNCTION(0x3, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x4, "uart2")), /* RTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXD2 */
+ SUNXI_FUNCTION(0x3, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x4, "uart2")), /* CTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXD1 */
+ SUNXI_FUNCTION(0x3, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x4, "uart2")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXD0 */
+ SUNXI_FUNCTION(0x3, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x4, "uart2")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXD3 */
+ SUNXI_FUNCTION(0x3, "spi1")), /* CS1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXD2 */
+ SUNXI_FUNCTION(0x3, "spi3")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXD1 */
+ SUNXI_FUNCTION(0x3, "spi3")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXD0 */
+ SUNXI_FUNCTION(0x3, "spi3")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXCK */
+ SUNXI_FUNCTION(0x3, "spi3")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXERR */
+ SUNXI_FUNCTION(0x3, "spi3")), /* CS1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA10,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ERXDV */
SUNXI_FUNCTION(0x4, "uart1")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA11,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* EMDC */
SUNXI_FUNCTION(0x4, "uart1")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA12,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* EMDIO */
+ SUNXI_FUNCTION(0x3, "uart6"), /* TX */
SUNXI_FUNCTION(0x4, "uart1")), /* RTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA13,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXEN */
+ SUNXI_FUNCTION(0x3, "uart6"), /* RX */
SUNXI_FUNCTION(0x4, "uart1")), /* CTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA14,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXCK */
+ SUNXI_FUNCTION(0x3, "uart7"), /* TX */
SUNXI_FUNCTION(0x4, "uart1")), /* DTR */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA15,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ECRS */
+ SUNXI_FUNCTION(0x3, "uart7"), /* RX */
SUNXI_FUNCTION(0x4, "uart1")), /* DSR */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA16,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ECOL */
+ SUNXI_FUNCTION(0x3, "can"), /* TX */
SUNXI_FUNCTION(0x4, "uart1")), /* DCD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PA17,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac"), /* ETXERR */
+ SUNXI_FUNCTION(0x3, "can"), /* RX */
SUNXI_FUNCTION(0x4, "uart1")), /* RING */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm")), /* PWM0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ir0")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ir0")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "ac97")), /* MCLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "ac97")), /* BCLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s"), /* LRCK */
+ SUNXI_FUNCTION(0x3, "ac97")), /* SYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s"), /* DO0 */
+ SUNXI_FUNCTION(0x3, "ac97")), /* DO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s")), /* DO1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s")), /* DO2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s")), /* DO3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s"), /* DI */
+ SUNXI_FUNCTION(0x3, "ac97")), /* DI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2")), /* CS1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* MS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* CLK */
+ SUNXI_FUNCTION(0x3, "jtag")), /* CK0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DO0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* MISO */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DI0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB22,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x2, "uart0")), /* TX */
+ SUNXI_FUNCTION(0x2, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x3, "ir1")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB23,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x2, "uart0")), /* RX */
+ SUNXI_FUNCTION(0x2, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x3, "ir1")), /* RX */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NWE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NRE# */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NDQ4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NDQ5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NDQ6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NDQ7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NWP */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE4 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE5 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE6 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC22,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE7 */
+ SUNXI_FUNCTION(0x3, "spi2")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC23,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC24,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NDQS */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VM3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VPC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D20 */
+ SUNXI_FUNCTION(0x3, "csi1")), /* MCLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D21 */
+ SUNXI_FUNCTION(0x3, "sim")), /* VPPEN */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D22 */
+ SUNXI_FUNCTION(0x3, "sim")), /* VPPPP */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D23 */
+ SUNXI_FUNCTION(0x3, "sim")), /* DET */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "sim")), /* VCCEN */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* DE */
+ SUNXI_FUNCTION(0x3, "sim")), /* RST */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "sim")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "sim")), /* SDA */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "csi0")), /* PCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* ERR */
+ SUNXI_FUNCTION(0x3, "csi0")), /* CK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "csi0")), /* HSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* DVLD */
+ SUNXI_FUNCTION(0x3, "csi0")), /* VSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "csi0"), /* D1 */
+ SUNXI_FUNCTION(0x4, "sim")), /* VPPEN */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "csi0")), /* D7 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* MSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
SUNXI_FUNCTION(0x4, "uart0")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x4, "jtag")), /* DO1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
SUNXI_FUNCTION(0x4, "uart0")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "csi1"), /* PCK */
+ SUNXI_FUNCTION(0x4, "mmc1")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* ERR */
+ SUNXI_FUNCTION(0x3, "csi1"), /* CK */
+ SUNXI_FUNCTION(0x4, "mmc1")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "csi1"), /* HSYNC */
+ SUNXI_FUNCTION(0x4, "mmc1")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* DVLD */
+ SUNXI_FUNCTION(0x3, "csi1"), /* VSYNC */
+ SUNXI_FUNCTION(0x4, "mmc1")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D0 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D0 */
+ SUNXI_FUNCTION(0x4, "mmc1"), /* D2 */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D1 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D1 */
+ SUNXI_FUNCTION(0x4, "mmc1"), /* D3 */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D2 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D2 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D3 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D3 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D4 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D4 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* RTS */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D12 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D5 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D5 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* CTS */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D13 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D6 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D6 */
+ SUNXI_FUNCTION(0x4, "uart4"), /* TX */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D14 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ts1"), /* D7 */
+ SUNXI_FUNCTION(0x3, "csi1"), /* D7 */
+ SUNXI_FUNCTION(0x4, "uart4"), /* RX */
+ SUNXI_FUNCTION(0x5, "csi0")), /* D15 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D0 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAA0 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D1 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAA1 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D2 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAA2 */
+ SUNXI_FUNCTION(0x4, "uart3"), /* RTS */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D3 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAIRQ */
+ SUNXI_FUNCTION(0x4, "uart3"), /* CTS */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D4 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD0 */
+ SUNXI_FUNCTION(0x4, "uart4"), /* TX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D5 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD1 */
+ SUNXI_FUNCTION(0x4, "uart4"), /* RX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D6 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD2 */
+ SUNXI_FUNCTION(0x4, "uart5"), /* TX */
+ SUNXI_FUNCTION(0x5, "ms"), /* BS */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D7 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD3 */
+ SUNXI_FUNCTION(0x4, "uart5"), /* RX */
+ SUNXI_FUNCTION(0x5, "ms"), /* CLK */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D7 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D8 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD4 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN0 */
+ SUNXI_FUNCTION(0x5, "ms"), /* D0 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D8 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D9 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD5 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN1 */
+ SUNXI_FUNCTION(0x5, "ms"), /* D1 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D9 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D10 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD6 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN2 */
+ SUNXI_FUNCTION(0x5, "ms"), /* D2 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D11 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD7 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN3 */
+ SUNXI_FUNCTION(0x5, "ms"), /* D3 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D12 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD8 */
+ SUNXI_FUNCTION(0x4, "ps2"), /* SCK1 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D12 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D13 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD9 */
+ SUNXI_FUNCTION(0x4, "ps2"), /* SDA1 */
+ SUNXI_FUNCTION(0x5, "sim"), /* RST */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D13 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D14 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD10 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN4 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VPPEN */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D14 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D15 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD11 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN5 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VPPPP */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D15 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D16 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD12 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN6 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D16 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D17 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD13 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* IN7 */
+ SUNXI_FUNCTION(0x5, "sim"), /* VCCEN */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D17 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D18 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD14 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT0 */
+ SUNXI_FUNCTION(0x5, "sim"), /* SCK */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D18 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D19 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAD15 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT1 */
+ SUNXI_FUNCTION(0x5, "sim"), /* SDA */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D19 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D20 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAOE */
+ SUNXI_FUNCTION(0x4, "can"), /* TX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D20 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D21 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATADREQ */
+ SUNXI_FUNCTION(0x4, "can"), /* RX */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D21 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH22,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D22 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATADACK */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT2 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* CMD */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D22 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH23,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* D23 */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATACS0 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT3 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* CLK */
+ SUNXI_FUNCTION(0x7, "csi1")), /* D23 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH24,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATACS1 */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT4 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* D0 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* PCLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH25,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* DE */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAIORDY */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT5 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* D1 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* FIELD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH26,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAIOR */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT6 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* D2 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* HSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PH27,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd1"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "pata"), /* ATAIOW */
+ SUNXI_FUNCTION(0x4, "keypad"), /* OUT7 */
+ SUNXI_FUNCTION(0x5, "mmc1"), /* D3 */
+ SUNXI_FUNCTION(0x7, "csi1")), /* VSYNC */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI0,
SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -518,277 +893,401 @@ static const struct sunxi_desc_pin sun4i_a10_pins[] = {
SUNXI_FUNCTION(0x1, "gpio_out")),
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm")), /* PWM1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc3")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "uart5")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart5")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "uart6")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* MISO */
+ SUNXI_FUNCTION(0x3, "uart6")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi0"), /* CS1 */
+ SUNXI_FUNCTION(0x3, "ps2"), /* SCK1 */
+ SUNXI_FUNCTION(0x4, "timer4")), /* TCLKIN0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CS1 */
+ SUNXI_FUNCTION(0x3, "ps2"), /* SDA1 */
+ SUNXI_FUNCTION(0x4, "timer5")), /* TCLKIN1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "uart2")), /* RTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart2")), /* CTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "uart2")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x3, "uart2")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ps2"), /* SCK0 */
+ SUNXI_FUNCTION(0x3, "uart7"), /* TX */
+ SUNXI_FUNCTION(0x4, "hdmi")), /* HSCL */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PI21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ps2"), /* SDA0 */
+ SUNXI_FUNCTION(0x3, "uart7"), /* RX */
+ SUNXI_FUNCTION(0x4, "hdmi")), /* HSDA */
};
static const struct sunxi_desc_pin sun5i_a13_pins[] = {
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm")),
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ir0")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "ir0")), /* RX */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2")), /* CS1 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB16,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB17,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PB18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NWE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NCE1 */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NCE0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* NRE */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NRB1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PC19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* NDQS */
+ SUNXI_FUNCTION(0x4, "uart3")), /* RTS */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D4 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D5 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D6 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D7 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D10 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD13,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD14,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD15,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD18,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD19,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD20,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD21,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD22,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD23,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD24,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD25,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* DE */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD26,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PD27,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x3, "csi0"), /* PCLK */
+ SUNXI_FUNCTION(0x4, "spi2")), /* CS0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x3, "csi0"), /* MCLK */
+ SUNXI_FUNCTION(0x4, "spi2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x3, "csi0"), /* HSYNC */
+ SUNXI_FUNCTION(0x4, "spi2")), /* MOSI */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* VSYNC */
+ SUNXI_FUNCTION(0x4, "spi2")), /* MISO */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D0 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D1 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE6,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D2 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* D2 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE7,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D3 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE8,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D4 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D5 */
+ SUNXI_FUNCTION(0x4, "mmc2")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE10,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D6 */
SUNXI_FUNCTION(0x4, "uart1")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PE11,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "csi0"), /* D7 */
SUNXI_FUNCTION(0x4, "uart1")), /* RX */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */
/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -802,24 +1301,34 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG3,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
SUNXI_FUNCTION(0x4, "uart1")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG4,
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
SUNXI_FUNCTION(0x4, "uart1")), /* RX */
- /* Hole */
+/* Hole */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG9,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "uart3")), /* TX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG10,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RX */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG11,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "uart3")), /* CTS */
SUNXI_PIN(SUNXI_PINCTRL_PIN_PG12,
SUNXI_FUNCTION(0x0, "gpio_in"),
- SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x3, "uart3")), /* RTS */
};
static const struct sunxi_pinctrl_desc sun4i_a10_pinctrl_data = {
@@ -1029,7 +1538,7 @@ static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops sunxi_pctrl_ops = {
+static const struct pinctrl_ops sunxi_pctrl_ops = {
.dt_node_to_map = sunxi_pctrl_dt_node_to_map,
.dt_free_map = sunxi_pctrl_dt_free_map,
.get_groups_count = sunxi_pctrl_get_groups_count,
@@ -1098,7 +1607,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinconf_ops sunxi_pconf_ops = {
+static const struct pinconf_ops sunxi_pconf_ops = {
.pin_config_group_get = sunxi_pconf_group_get,
.pin_config_group_set = sunxi_pconf_group_set,
};
@@ -1204,7 +1713,7 @@ error:
return ret;
}
-static struct pinmux_ops sunxi_pmx_ops = {
+static const struct pinmux_ops sunxi_pmx_ops = {
.get_functions_count = sunxi_pmx_get_funcs_cnt,
.get_function_name = sunxi_pmx_get_func_name,
.get_function_groups = sunxi_pmx_get_func_groups,
@@ -1409,6 +1918,7 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
struct pinctrl_pin_desc *pins;
struct sunxi_pinctrl *pctl;
int i, ret, last_pin;
+ struct clk *clk;
pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
if (!pctl)
@@ -1479,6 +1989,12 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
goto gpiochip_error;
}
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ goto gpiochip_error;
+
+ clk_prepare_enable(clk);
+
dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
return 0;
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index f195d77a3572..2fa9bc6cd7ab 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -316,7 +316,7 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
}
-static struct pinctrl_ops tegra_pinctrl_ops = {
+static const struct pinctrl_ops tegra_pinctrl_ops = {
.get_groups_count = tegra_pinctrl_get_groups_count,
.get_group_name = tegra_pinctrl_get_group_name,
.get_group_pins = tegra_pinctrl_get_group_pins,
@@ -401,7 +401,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
pmx_writel(pmx, val, g->mux_bank, g->mux_reg);
}
-static struct pinmux_ops tegra_pinmux_ops = {
+static const struct pinmux_ops tegra_pinmux_ops = {
.get_functions_count = tegra_pinctrl_get_funcs_count,
.get_function_name = tegra_pinctrl_get_func_name,
.get_function_groups = tegra_pinctrl_get_func_groups,
@@ -676,7 +676,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
}
#endif
-static struct pinconf_ops tegra_pinconf_ops = {
+static const struct pinconf_ops tegra_pinconf_ops = {
.pin_config_get = tegra_pinconf_get,
.pin_config_set = tegra_pinconf_set,
.pin_config_group_get = tegra_pinconf_group_get,
diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c
index 2b5772550836..6a3a7503e6a0 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -860,7 +860,7 @@ static void u300_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
seq_printf(s, " " DRIVER_NAME);
}
-static struct pinctrl_ops u300_pctrl_ops = {
+static const struct pinctrl_ops u300_pctrl_ops = {
.get_groups_count = u300_get_groups_count,
.get_group_name = u300_get_group_name,
.get_group_pins = u300_get_group_pins,
@@ -1003,7 +1003,7 @@ static int u300_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
-static struct pinmux_ops u300_pmx_ops = {
+static const struct pinmux_ops u300_pmx_ops = {
.get_functions_count = u300_pmx_get_funcs_count,
.get_function_name = u300_pmx_get_func_name,
.get_function_groups = u300_pmx_get_groups,
@@ -1046,7 +1046,7 @@ static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
return 0;
}
-static struct pinconf_ops u300_pconf_ops = {
+static const struct pinconf_ops u300_pconf_ops = {
.is_generic = true,
.pin_config_get = u300_pin_config_get,
.pin_config_set = u300_pin_config_set,
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 068224efa6fa..f2977cff8366 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -553,7 +553,7 @@ int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
return ret;
}
-static struct pinconf_ops xway_pinconf_ops = {
+static const struct pinconf_ops xway_pinconf_ops = {
.pin_config_get = xway_pinconf_get,
.pin_config_set = xway_pinconf_set,
.pin_config_group_set = xway_pinconf_group_set,
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index bd83c8b01cd1..88cc5095d0c9 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -506,7 +506,7 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
if (!pmxops)
return 0;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
nfuncs = pmxops->get_functions_count(pctldev);
while (func_selector < nfuncs) {
const char *func = pmxops->get_function_name(pctldev,
@@ -530,7 +530,7 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
func_selector++;
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
@@ -548,7 +548,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
seq_puts(s, "Pinmux settings per pin\n");
seq_puts(s, "Format: pin (name): mux_owner gpio_owner hog?\n");
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
@@ -583,7 +583,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
seq_printf(s, "\n");
}
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return 0;
}
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index 6a7dae70db08..116da0412c4b 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -198,7 +198,7 @@ static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
kfree(map);
}
-static struct pinctrl_ops spear_pinctrl_ops = {
+static const struct pinctrl_ops spear_pinctrl_ops = {
.get_groups_count = spear_pinctrl_get_groups_cnt,
.get_group_name = spear_pinctrl_get_group_name,
.get_group_pins = spear_pinctrl_get_group_pins,
@@ -340,7 +340,7 @@ static void gpio_disable_free(struct pinctrl_dev *pctldev,
gpio_request_endisable(pctldev, range, offset, false);
}
-static struct pinmux_ops spear_pinmux_ops = {
+static const struct pinmux_ops spear_pinmux_ops = {
.get_functions_count = spear_pinctrl_get_funcs_count,
.get_function_name = spear_pinctrl_get_func_name,
.get_function_groups = spear_pinctrl_get_func_groups,
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 45cacf79f3a7..1a779bbfb87d 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -134,7 +134,6 @@ static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x2142, { KEY_MEDIA } },
{ KE_KEY, 0x213b, { KEY_INFO } },
{ KE_KEY, 0x2169, { KEY_DIRECTION } },
- { KE_KEY, 0x216a, { KEY_SETUP } },
{ KE_KEY, 0x231b, { KEY_HELP } },
{ KE_END, 0 }
};
@@ -925,9 +924,6 @@ static int __init hp_wmi_init(void)
err = hp_wmi_input_setup();
if (err)
return err;
-
- //Enable magic for hotkeys that run on the SMBus
- ec_write(0xe6,0x6e);
}
if (bios_capable) {
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 14d4dced1def..d544e3aaf761 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -4121,7 +4121,7 @@ static int sony_pic_enable(struct acpi_device *device,
resource->res3.data.irq.sharable = ACPI_SHARED;
resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
-
+ resource->res4.length = sizeof(struct acpi_resource);
}
/* setup Type 2/3 resources */
else {
@@ -4140,6 +4140,7 @@ static int sony_pic_enable(struct acpi_device *device,
resource->res2.data.irq.sharable = ACPI_SHARED;
resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
+ resource->res3.length = sizeof(struct acpi_resource);
}
/* Attempt to set the resource */
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 05272e676a28..54d31c0a9840 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -1964,9 +1964,6 @@ struct tp_nvram_state {
/* kthread for the hotkey poller */
static struct task_struct *tpacpi_hotkey_task;
-/* Acquired while the poller kthread is running, use to sync start/stop */
-static struct mutex hotkey_thread_mutex;
-
/*
* Acquire mutex to write poller control variables as an
* atomic block.
@@ -2462,8 +2459,6 @@ static int hotkey_kthread(void *data)
unsigned int poll_freq;
bool was_frozen;
- mutex_lock(&hotkey_thread_mutex);
-
if (tpacpi_lifecycle == TPACPI_LIFE_EXITING)
goto exit;
@@ -2523,7 +2518,6 @@ static int hotkey_kthread(void *data)
}
exit:
- mutex_unlock(&hotkey_thread_mutex);
return 0;
}
@@ -2533,9 +2527,6 @@ static void hotkey_poll_stop_sync(void)
if (tpacpi_hotkey_task) {
kthread_stop(tpacpi_hotkey_task);
tpacpi_hotkey_task = NULL;
- mutex_lock(&hotkey_thread_mutex);
- /* at this point, the thread did exit */
- mutex_unlock(&hotkey_thread_mutex);
}
}
@@ -3234,7 +3225,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
mutex_init(&hotkey_mutex);
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
- mutex_init(&hotkey_thread_mutex);
mutex_init(&hotkey_thread_data_mutex);
#endif
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 918d5f044865..cf88f9b62445 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -379,10 +379,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
*type = (tag >> 3) & 0x0f;
*size = tag & 0x07;
}
-#if 0
- printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type,
- *size);
-#endif
if (*type == 0xff && *size == 0xffff) /* probably invalid data */
return -1;
return 0;
@@ -813,13 +809,6 @@ static int __init isapnp_build_device_list(void)
if (!card)
continue;
-#if 0
- dev_info(&card->dev,
- "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- header[0], header[1], header[2], header[3], header[4],
- header[5], header[6], header[7], header[8]);
- dev_info(&card->dev, "checksum = %#x\n", checksum);
-#endif
INIT_LIST_HEAD(&card->devices);
card->serial =
(header[7] << 24) | (header[6] << 16) | (header[5] << 8) |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index b8f4ea7b27fc..9847ab163829 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -634,6 +634,7 @@ int pnpacpi_build_resource_template(struct pnp_dev *dev,
}
/* resource will pointer the end resource now */
resource->type = ACPI_RESOURCE_TYPE_END_TAG;
+ resource->length = sizeof(struct acpi_resource);
return 0;
}
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 8dafd65d4758..c212db0fc65d 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -185,10 +185,9 @@ static int pnp_devices_proc_show(struct seq_file *m, void *v)
if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node))
break;
- seq_printf(m, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
+ seq_printf(m, "%02x\t%08x\t%3phC\t%04x\n",
node->handle, node->eisa_id,
- node->type_code[0], node->type_code[1],
- node->type_code[2], node->flags);
+ node->type_code, node->flags);
if (nodenum <= thisnodenum) {
printk(KERN_ERR
"%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c
index 4b37a5af8deb..36fb4b5a4b0d 100644
--- a/drivers/power/88pm860x_charger.c
+++ b/drivers/power/88pm860x_charger.c
@@ -714,7 +714,6 @@ out_irq:
while (--i >= 0)
free_irq(info->irq[i], info);
out:
- kfree(info);
return ret;
}
@@ -728,7 +727,6 @@ static int pm860x_charger_remove(struct platform_device *pdev)
free_irq(info->irq[0], info);
for (i = 0; i < info->irq_nums; i++)
free_irq(info->irq[i], info);
- kfree(info);
return 0;
}
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 9e00c389e777..0d0b5d7d19d0 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -254,7 +254,7 @@ config BATTERY_RX51
config CHARGER_ISP1704
tristate "ISP1704 USB Charger Detection"
- depends on USB_OTG_UTILS
+ depends on USB_PHY
help
Say Y to enable support for USB Charger Detection with
ISP1707/ISP1704 USB transceivers.
@@ -340,6 +340,13 @@ config CHARGER_SMB347
Say Y to include support for Summit Microelectronics SMB347
Battery Charger.
+config CHARGER_TPS65090
+ tristate "TPS65090 battery charger driver"
+ depends on MFD_TPS65090
+ help
+ Say Y here to enable support for battery charging with TPS65090
+ PMIC chips.
+
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC
@@ -353,13 +360,6 @@ config BATTERY_GOLDFISH
Say Y to enable support for the battery and AC power in the
Goldfish emulator.
-config CHARGER_PM2301
- bool "PM2301 Battery Charger Driver"
- depends on AB8500_BM
- help
- Say Y to include support for PM2301 charger driver.
- Depends on AB8500 battery management core.
-
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 3f66436af45c..653bf6ceff30 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
-obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
+obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
@@ -47,10 +47,10 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
-obj-$(CONFIG_CHARGER_PM2301) += pm2301_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
+obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_POWER_RESET) += reset/
diff --git a/drivers/power/ab8500_bmdata.c b/drivers/power/ab8500_bmdata.c
index 7a96c0650fbb..d29864533093 100644
--- a/drivers/power/ab8500_bmdata.c
+++ b/drivers/power/ab8500_bmdata.c
@@ -11,7 +11,7 @@
* Note that the res_to_temp table must be strictly sorted by falling resistance
* values to work.
*/
-static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
+const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
{-5, 53407},
{ 0, 48594},
{ 5, 43804},
@@ -28,8 +28,12 @@ static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
{60, 13437},
{65, 12500},
};
+EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor);
-static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
+const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor);
+EXPORT_SYMBOL(ab8500_temp_tbl_a_size);
+
+const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
{-5, 200000},
{ 0, 159024},
{ 5, 151921},
@@ -46,8 +50,12 @@ static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
{60, 85461},
{65, 82869},
};
+EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor);
+
+const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor);
+EXPORT_SYMBOL(ab8500_temp_tbl_b_size);
-static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
+static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = {
{4171, 100},
{4114, 95},
{4009, 83},
@@ -70,7 +78,7 @@ static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
{3247, 0},
};
-static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
+static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = {
{4161, 100},
{4124, 98},
{4044, 90},
@@ -93,7 +101,7 @@ static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
{3250, 0},
};
-static struct abx500_v_to_cap cap_tbl[] = {
+static const struct abx500_v_to_cap cap_tbl[] = {
{4186, 100},
{4163, 99},
{4114, 95},
@@ -124,7 +132,7 @@ static struct abx500_v_to_cap cap_tbl[] = {
* Note that the res_to_temp table must be strictly sorted by falling
* resistance values to work.
*/
-static struct abx500_res_to_temp temp_tbl[] = {
+static const struct abx500_res_to_temp temp_tbl[] = {
{-5, 214834},
{ 0, 162943},
{ 5, 124820},
@@ -146,7 +154,7 @@ static struct abx500_res_to_temp temp_tbl[] = {
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work.
*/
-static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
+static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
{ 40, 120},
{ 30, 135},
{ 20, 165},
@@ -160,7 +168,7 @@ static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work.
*/
-static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
+static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
{ 60, 300},
{ 30, 300},
{ 20, 300},
@@ -171,7 +179,7 @@ static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
};
/* battery resistance table for LI ION 9100 battery */
-static struct batres_vs_temp temp_to_batres_tbl_9100[] = {
+static const struct batres_vs_temp temp_to_batres_tbl_9100[] = {
{ 60, 180},
{ 30, 180},
{ 20, 180},
@@ -230,10 +238,10 @@ static struct abx500_battery_type bat_type_thermistor[] = {
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
- .r_to_t_tbl = temp_tbl_A_thermistor,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
- .v_to_cap_tbl = cap_tbl_A_thermistor,
+ .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor),
+ .r_to_t_tbl = ab8500_temp_tbl_a_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor),
+ .v_to_cap_tbl = cap_tbl_a_thermistor,
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
.batres_tbl = temp_to_batres_tbl_thermistor,
@@ -258,10 +266,10 @@ static struct abx500_battery_type bat_type_thermistor[] = {
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
- .n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
- .r_to_t_tbl = temp_tbl_B_thermistor,
- .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
- .v_to_cap_tbl = cap_tbl_B_thermistor,
+ .n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor),
+ .r_to_t_tbl = ab8500_temp_tbl_b_thermistor,
+ .n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor),
+ .v_to_cap_tbl = cap_tbl_b_thermistor,
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
.batres_tbl = temp_to_batres_tbl_thermistor,
},
@@ -407,15 +415,27 @@ static const struct abx500_fg_parameters fg = {
.battok_raising_th_sel1 = 2860,
.maint_thres = 95,
.user_cap_limit = 15,
+ .pcut_enable = 1,
+ .pcut_max_time = 127,
+ .pcut_flag_time = 112,
+ .pcut_max_restart = 15,
+ .pcut_debounce_time = 2,
};
-static const struct abx500_maxim_parameters maxi_params = {
+static const struct abx500_maxim_parameters ab8500_maxi_params = {
.ena_maxi = true,
.chg_curr = 910,
.wait_cycles = 10,
.charger_curr_step = 100,
};
+static const struct abx500_maxim_parameters abx540_maxi_params = {
+ .ena_maxi = true,
+ .chg_curr = 3000,
+ .wait_cycles = 10,
+ .charger_curr_step = 200,
+};
+
static const struct abx500_bm_charger_parameters chg = {
.usb_volt_max = 5500,
.usb_curr_max = 1500,
@@ -423,6 +443,46 @@ static const struct abx500_bm_charger_parameters chg = {
.ac_curr_max = 1500,
};
+/*
+ * This array maps the raw hex value to charger output current used by the
+ * AB8500 values
+ */
+static int ab8500_charge_output_curr_map[] = {
+ 100, 200, 300, 400, 500, 600, 700, 800,
+ 900, 1000, 1100, 1200, 1300, 1400, 1500, 1500,
+};
+
+static int ab8540_charge_output_curr_map[] = {
+ 0, 0, 0, 75, 100, 125, 150, 175,
+ 200, 225, 250, 275, 300, 325, 350, 375,
+ 400, 425, 450, 475, 500, 525, 550, 575,
+ 600, 625, 650, 675, 700, 725, 750, 775,
+ 800, 825, 850, 875, 900, 925, 950, 975,
+ 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
+ 1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375,
+ 1400, 1425, 1450, 1500, 1600, 1700, 1900, 2000,
+};
+
+/*
+ * This array maps the raw hex value to charger input current used by the
+ * AB8500 values
+ */
+static int ab8500_charge_input_curr_map[] = {
+ 50, 98, 193, 290, 380, 450, 500, 600,
+ 700, 800, 900, 1000, 1100, 1300, 1400, 1500,
+};
+
+static int ab8540_charge_input_curr_map[] = {
+ 25, 50, 75, 100, 125, 150, 175, 200,
+ 225, 250, 275, 300, 325, 350, 375, 400,
+ 425, 450, 475, 500, 525, 550, 575, 600,
+ 625, 650, 675, 700, 725, 750, 775, 800,
+ 825, 850, 875, 900, 925, 950, 975, 1000,
+ 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200,
+ 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400,
+ 1425, 1450, 1475, 1500, 1500, 1500, 1500, 1500,
+};
+
struct abx500_bm_data ab8500_bm_data = {
.temp_under = 3,
.temp_low = 8,
@@ -442,22 +502,60 @@ struct abx500_bm_data ab8500_bm_data = {
.fg_res = 100,
.cap_levels = &cap_levels,
.bat_type = bat_type_thermistor,
- .n_btypes = 3,
+ .n_btypes = ARRAY_SIZE(bat_type_thermistor),
.batt_id = 0,
.interval_charging = 5,
.interval_not_charging = 120,
.temp_hysteresis = 3,
.gnd_lift_resistance = 34,
- .maxi = &maxi_params,
+ .chg_output_curr = ab8500_charge_output_curr_map,
+ .n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map),
+ .maxi = &ab8500_maxi_params,
.chg_params = &chg,
.fg_params = &fg,
+ .chg_input_curr = ab8500_charge_input_curr_map,
+ .n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map),
+};
+
+struct abx500_bm_data ab8540_bm_data = {
+ .temp_under = 3,
+ .temp_low = 8,
+ .temp_high = 43,
+ .temp_over = 48,
+ .main_safety_tmr_h = 4,
+ .temp_interval_chg = 20,
+ .temp_interval_nochg = 120,
+ .usb_safety_tmr_h = 4,
+ .bkup_bat_v = BUP_VCH_SEL_2P6V,
+ .bkup_bat_i = BUP_ICH_SEL_150UA,
+ .no_maintenance = false,
+ .capacity_scaling = false,
+ .adc_therm = ABx500_ADC_THERM_BATCTRL,
+ .chg_unknown_bat = false,
+ .enable_overshoot = false,
+ .fg_res = 100,
+ .cap_levels = &cap_levels,
+ .bat_type = bat_type_thermistor,
+ .n_btypes = ARRAY_SIZE(bat_type_thermistor),
+ .batt_id = 0,
+ .interval_charging = 5,
+ .interval_not_charging = 120,
+ .temp_hysteresis = 3,
+ .gnd_lift_resistance = 0,
+ .maxi = &abx540_maxi_params,
+ .chg_params = &chg,
+ .fg_params = &fg,
+ .chg_output_curr = ab8540_charge_output_curr_map,
+ .n_chg_out_curr = ARRAY_SIZE(ab8540_charge_output_curr_map),
+ .chg_input_curr = ab8540_charge_input_curr_map,
+ .n_chg_in_curr = ARRAY_SIZE(ab8540_charge_input_curr_map),
};
int ab8500_bm_of_probe(struct device *dev,
struct device_node *np,
struct abx500_bm_data *bm)
{
- struct batres_vs_temp *tmp_batres_tbl;
+ const struct batres_vs_temp *tmp_batres_tbl;
struct device_node *battery_node;
const char *btech;
int i;
diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c
index 07689064996e..d412d34bf3df 100644
--- a/drivers/power/ab8500_btemp.c
+++ b/drivers/power/ab8500_btemp.c
@@ -42,6 +42,9 @@
#define BTEMP_BATCTRL_CURR_SRC_16UA 16
#define BTEMP_BATCTRL_CURR_SRC_18UA 18
+#define BTEMP_BATCTRL_CURR_SRC_60UA 60
+#define BTEMP_BATCTRL_CURR_SRC_120UA 120
+
#define to_ab8500_btemp_device_info(x) container_of((x), \
struct ab8500_btemp, btemp_psy);
@@ -76,8 +79,8 @@ struct ab8500_btemp_ranges {
* @dev: Pointer to the structure device
* @node: List of AB8500 BTEMPs, hence prepared for reentrance
* @curr_source: What current source we use, in uA
- * @bat_temp: Battery temperature in degree Celcius
- * @prev_bat_temp Last dispatched battery temperature
+ * @bat_temp: Dispatched battery temperature in degree Celcius
+ * @prev_bat_temp Last measured battery temperature in degree Celcius
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
* @fg: Pointer to the struct fg
@@ -128,6 +131,7 @@ struct ab8500_btemp *ab8500_btemp_get(void)
return btemp;
}
+EXPORT_SYMBOL(ab8500_btemp_get);
/**
* ab8500_btemp_batctrl_volt_to_res() - convert batctrl voltage to resistance
@@ -155,7 +159,7 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) {
/*
* If the battery has internal NTC, we use the current
- * source to calculate the resistance, 7uA or 20uA
+ * source to calculate the resistance.
*/
rbs = (v_batctrl * 1000
- di->bm->gnd_lift_resistance * inst_curr)
@@ -216,7 +220,12 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
/* Only do this for batteries with internal NTC */
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
- if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ if (is_ab8540(di->parent)) {
+ if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_60UA)
+ curr = BAT_CTRL_60U_ENA;
+ else
+ curr = BAT_CTRL_120U_ENA;
+ } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_16UA)
curr = BAT_CTRL_16U_ENA;
else
@@ -257,7 +266,14 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
} else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
dev_dbg(di->dev, "Disable BATCTRL curr source\n");
- if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ if (is_ab8540(di->parent)) {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(
+ di->dev,
+ AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+ BAT_CTRL_60U_ENA | BAT_CTRL_120U_ENA,
+ ~(BAT_CTRL_60U_ENA | BAT_CTRL_120U_ENA));
+ } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
/* Write 0 to the curr bits */
ret = abx500_mask_and_set_register_interruptible(
di->dev,
@@ -314,7 +330,13 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
* if we got an error above
*/
disable_curr_source:
- if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ if (is_ab8540(di->parent)) {
+ /* Write 0 to the curr bits */
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
+ BAT_CTRL_60U_ENA | BAT_CTRL_120U_ENA,
+ ~(BAT_CTRL_60U_ENA | BAT_CTRL_120U_ENA));
+ } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
/* Write 0 to the curr bits */
ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_CHARGER, AB8500_BAT_CTRL_CURRENT_SOURCE,
@@ -541,7 +563,9 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
{
int res;
u8 i;
- if (is_ab9540(di->parent) || is_ab8505(di->parent))
+ if (is_ab8540(di->parent))
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_60UA;
+ else if (is_ab9540(di->parent) || is_ab8505(di->parent))
di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
else
di->curr_source = BTEMP_BATCTRL_CURR_SRC_7UA;
@@ -579,12 +603,17 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
/*
* We only have to change current source if the
- * detected type is Type 1, else we use the 7uA source
+ * detected type is Type 1.
*/
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
- di->bm->batt_id == 1) {
- if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
- dev_dbg(di->dev, "Set BATCTRL current source to 16uA\n");
+ di->bm->batt_id == 1) {
+ if (is_ab8540(di->parent)) {
+ dev_dbg(di->dev,
+ "Set BATCTRL current source to 60uA\n");
+ di->curr_source = BTEMP_BATCTRL_CURR_SRC_60UA;
+ } else if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ dev_dbg(di->dev,
+ "Set BATCTRL current source to 16uA\n");
di->curr_source = BTEMP_BATCTRL_CURR_SRC_16UA;
} else {
dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
@@ -604,22 +633,37 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
static void ab8500_btemp_periodic_work(struct work_struct *work)
{
int interval;
+ int bat_temp;
struct ab8500_btemp *di = container_of(work,
struct ab8500_btemp, btemp_periodic_work.work);
if (!di->initialized) {
- di->initialized = true;
/* Identify the battery */
if (ab8500_btemp_id(di) < 0)
dev_warn(di->dev, "failed to identify the battery\n");
}
- di->bat_temp = ab8500_btemp_measure_temp(di);
-
- if (di->bat_temp != di->prev_bat_temp) {
- di->prev_bat_temp = di->bat_temp;
+ bat_temp = ab8500_btemp_measure_temp(di);
+ /*
+ * Filter battery temperature.
+ * Allow direct updates on temperature only if two samples result in
+ * same temperature. Else only allow 1 degree change from previous
+ * reported value in the direction of the new measurement.
+ */
+ if ((bat_temp == di->prev_bat_temp) || !di->initialized) {
+ if ((di->bat_temp != di->prev_bat_temp) || !di->initialized) {
+ di->initialized = true;
+ di->bat_temp = bat_temp;
+ power_supply_changed(&di->btemp_psy);
+ }
+ } else if (bat_temp < di->prev_bat_temp) {
+ di->bat_temp--;
+ power_supply_changed(&di->btemp_psy);
+ } else if (bat_temp > di->prev_bat_temp) {
+ di->bat_temp++;
power_supply_changed(&di->btemp_psy);
}
+ di->prev_bat_temp = bat_temp;
if (di->events.ac_conn || di->events.usb_conn)
interval = di->bm->temp_interval_chg;
@@ -772,7 +816,7 @@ static void ab8500_btemp_periodic(struct ab8500_btemp *di,
*
* Returns battery temperature
*/
-static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
+int ab8500_btemp_get_temp(struct ab8500_btemp *di)
{
int temp = 0;
@@ -808,6 +852,7 @@ static int ab8500_btemp_get_temp(struct ab8500_btemp *di)
}
return temp;
}
+EXPORT_SYMBOL(ab8500_btemp_get_temp);
/**
* ab8500_btemp_get_batctrl_temp() - get the temperature
@@ -819,6 +864,7 @@ int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp)
{
return btemp->bat_temp * 1000;
}
+EXPORT_SYMBOL(ab8500_btemp_get_batctrl_temp);
/**
* ab8500_btemp_get_property() - get the btemp properties
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index 24b30b7ea5ca..a558318b169c 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
@@ -52,10 +53,15 @@
#define VBUS_DET_DBNC100 0x02
#define VBUS_DET_DBNC1 0x01
#define OTP_ENABLE_WD 0x01
+#define DROP_COUNT_RESET 0x01
+#define USB_CH_DET 0x01
#define MAIN_CH_INPUT_CURR_SHIFT 4
#define VBUS_IN_CURR_LIM_SHIFT 4
+#define AB8540_VBUS_IN_CURR_LIM_SHIFT 2
#define AUTO_VBUS_IN_CURR_LIM_SHIFT 4
+#define AB8540_AUTO_VBUS_IN_CURR_MASK 0x3F
+#define VBUS_IN_CURR_LIM_RETRY_SET_TIME 30 /* seconds */
#define LED_INDICATOR_PWM_ENA 0x01
#define LED_INDICATOR_PWM_DIS 0x00
@@ -77,7 +83,9 @@
/* UsbLineStatus register bit masks */
#define AB8500_USB_LINK_STATUS 0x78
+#define AB8505_USB_LINK_STATUS 0xF8
#define AB8500_STD_HOST_SUSP 0x18
+#define USB_LINK_STATUS_SHIFT 3
/* Watchdog timeout constant */
#define WD_TIMER 0x30 /* 4min */
@@ -96,6 +104,10 @@
#define AB8500_SW_CONTROL_FALLBACK 0x03
/* Wait for enumeration before charing in us */
#define WAIT_ACA_RID_ENUMERATION (5 * 1000)
+/*External charger control*/
+#define AB8500_SYS_CHARGER_CONTROL_REG 0x52
+#define EXTERNAL_CHARGER_DISABLE_REG_VAL 0x03
+#define EXTERNAL_CHARGER_ENABLE_REG_VAL 0x07
/* UsbLineStatus register - usb types */
enum ab8500_charger_link_status {
@@ -196,10 +208,15 @@ struct ab8500_charger_usb_state {
spinlock_t usb_lock;
};
+struct ab8500_charger_max_usb_in_curr {
+ int usb_type_max;
+ int set_max;
+ int calculated_max;
+};
+
/**
* struct ab8500_charger - ab8500 Charger device information
* @dev: Pointer to the structure device
- * @max_usb_in_curr: Max USB charger input current
* @vbus_detected: VBUS detected
* @vbus_detected_start:
* VBUS detected during startup
@@ -214,7 +231,6 @@ struct ab8500_charger_usb_state {
* @autopower Indicate if we should have automatic pwron after pwrloss
* @autopower_cfg platform specific power config support for "pwron after pwrloss"
* @invalid_charger_detect_state State when forcing AB to use invalid charger
- * @is_usb_host: Indicate if last detected USB type is host
* @is_aca_rid: Incicate if accessory is ACA type
* @current_stepping_sessions:
* Counter for current stepping sessions
@@ -223,6 +239,7 @@ struct ab8500_charger_usb_state {
* @bm: Platform specific battery management information
* @flags: Structure for information about events triggered
* @usb_state: Structure for usb stack information
+ * @max_usb_in_curr: Max USB charger input current
* @ac_chg: AC charger power supply
* @usb_chg: USB charger power supply
* @ac: Structure that holds the AC charger properties
@@ -254,7 +271,6 @@ struct ab8500_charger_usb_state {
*/
struct ab8500_charger {
struct device *dev;
- int max_usb_in_curr;
bool vbus_detected;
bool vbus_detected_start;
bool ac_conn;
@@ -266,7 +282,6 @@ struct ab8500_charger {
bool autopower;
bool autopower_cfg;
int invalid_charger_detect_state;
- bool is_usb_host;
int is_aca_rid;
atomic_t current_stepping_sessions;
struct ab8500 *parent;
@@ -274,6 +289,7 @@ struct ab8500_charger {
struct abx500_bm_data *bm;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
+ struct ab8500_charger_max_usb_in_curr max_usb_in_curr;
struct ux500_charger ac_chg;
struct ux500_charger usb_chg;
struct ab8500_charger_info ac;
@@ -415,13 +431,18 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
if (connected != di->usb.charger_connected) {
dev_dbg(di->dev, "USB connected:%i\n", connected);
di->usb.charger_connected = connected;
+
+ if (!connected)
+ di->flags.vbus_drop_end = false;
+
sysfs_notify(&di->usb_chg.psy.dev->kobj, NULL, "present");
if (connected) {
mutex_lock(&di->charger_attached_mutex);
mutex_unlock(&di->charger_attached_mutex);
- queue_delayed_work(di->charger_wq,
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
&di->usb_charger_attached_work,
HZ);
} else {
@@ -668,23 +689,19 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
case USB_STAT_STD_HOST_C_S:
dev_dbg(di->dev, "USB Type - Standard host is "
"detected through USB driver\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
- di->is_usb_host = true;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS_CHIRP:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
- di->is_usb_host = true;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_HOST_CHG_HS:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
- di->is_usb_host = true;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_C_HS:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P9;
- di->is_usb_host = false;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P9;
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_A:
@@ -693,8 +710,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
* can consume (900mA). Closest level is 500mA
*/
dev_dbg(di->dev, "USB_STAT_ACA_RID_A detected\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
- di->is_usb_host = false;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 1;
break;
case USB_STAT_ACA_RID_B:
@@ -702,38 +718,35 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
* Dedicated charger level minus 120mA (20mA for ACA and
* 100mA for potential accessory). Closest level is 1300mA
*/
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P3;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P3;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
- di->max_usb_in_curr);
- di->is_usb_host = false;
+ di->max_usb_in_curr.usb_type_max);
di->is_aca_rid = 1;
break;
case USB_STAT_HOST_CHG_NM:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
- di->is_usb_host = true;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
di->is_aca_rid = 0;
break;
case USB_STAT_DEDICATED_CHG:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
- di->is_usb_host = false;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5;
di->is_aca_rid = 0;
break;
case USB_STAT_ACA_RID_C_HS_CHIRP:
case USB_STAT_ACA_RID_C_NM:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
- di->is_usb_host = false;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_1P5;
di->is_aca_rid = 1;
break;
case USB_STAT_NOT_CONFIGURED:
if (di->vbus_detected) {
di->usb_device_is_unrecognised = true;
dev_dbg(di->dev, "USB Type - Legacy charger.\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_1P5;
+ di->max_usb_in_curr.usb_type_max =
+ USB_CH_IP_CUR_LVL_1P5;
break;
}
case USB_STAT_HM_IDGND:
dev_err(di->dev, "USB Type - Charging not allowed\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
ret = -ENXIO;
break;
case USB_STAT_RESERVED:
@@ -743,12 +756,13 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
"VBUS has collapsed\n");
ret = -ENXIO;
break;
- }
- if (is_ab9540(di->parent) || is_ab8505(di->parent)) {
+ } else {
dev_dbg(di->dev, "USB Type - Charging not allowed\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+ di->max_usb_in_curr.usb_type_max =
+ USB_CH_IP_CUR_LVL_0P05;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
- link_status, di->max_usb_in_curr);
+ link_status,
+ di->max_usb_in_curr.usb_type_max);
ret = -ENXIO;
break;
}
@@ -757,23 +771,24 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
case USB_STAT_CARKIT_2:
case USB_STAT_ACA_DOCK_CHARGER:
case USB_STAT_CHARGER_LINE_1:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
- di->max_usb_in_curr);
+ di->max_usb_in_curr.usb_type_max);
case USB_STAT_NOT_VALID_LINK:
dev_err(di->dev, "USB Type invalid - try charging anyway\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
break;
default:
dev_err(di->dev, "USB Type - Unknown\n");
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
ret = -ENXIO;
break;
};
+ di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max;
dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d",
- link_status, di->max_usb_in_curr);
+ link_status, di->max_usb_in_curr.set_max);
return ret;
}
@@ -796,21 +811,22 @@ static int ab8500_charger_read_usb_type(struct ab8500_charger *di)
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
- if (is_ab8500(di->parent)) {
+ if (is_ab8500(di->parent))
ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
- AB8500_USB_LINE_STAT_REG, &val);
- } else {
- if (is_ab9540(di->parent) || is_ab8505(di->parent))
- ret = abx500_get_register_interruptible(di->dev,
- AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
- }
+ AB8500_USB_LINE_STAT_REG, &val);
+ else
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINK1_STAT_REG, &val);
if (ret < 0) {
dev_err(di->dev, "%s ab8500 read failed\n", __func__);
return ret;
}
/* get the USB type */
- val = (val & AB8500_USB_LINK_STATUS) >> 3;
+ if (is_ab8500(di->parent))
+ val = (val & AB8500_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
+ else
+ val = (val & AB8505_USB_LINK_STATUS) >> USB_LINK_STATUS_SHIFT;
ret = ab8500_charger_max_usb_curr(di,
(enum ab8500_charger_link_status) val);
@@ -865,7 +881,12 @@ static int ab8500_charger_detect_usb_type(struct ab8500_charger *di)
*/
/* get the USB type */
- val = (val & AB8500_USB_LINK_STATUS) >> 3;
+ if (is_ab8500(di->parent))
+ val = (val & AB8500_USB_LINK_STATUS) >>
+ USB_LINK_STATUS_SHIFT;
+ else
+ val = (val & AB8505_USB_LINK_STATUS) >>
+ USB_LINK_STATUS_SHIFT;
if (val)
break;
}
@@ -960,51 +981,6 @@ static int ab8500_charger_voltage_map[] = {
4600 ,
};
-/*
- * This array maps the raw hex value to charger current used by the AB8500
- * Values taken from the UM0836
- */
-static int ab8500_charger_current_map[] = {
- 100 ,
- 200 ,
- 300 ,
- 400 ,
- 500 ,
- 600 ,
- 700 ,
- 800 ,
- 900 ,
- 1000 ,
- 1100 ,
- 1200 ,
- 1300 ,
- 1400 ,
- 1500 ,
-};
-
-/*
- * This array maps the raw hex value to VBUS input current used by the AB8500
- * Values taken from the UM0836
- */
-static int ab8500_charger_vbus_in_curr_map[] = {
- USB_CH_IP_CUR_LVL_0P05,
- USB_CH_IP_CUR_LVL_0P09,
- USB_CH_IP_CUR_LVL_0P19,
- USB_CH_IP_CUR_LVL_0P29,
- USB_CH_IP_CUR_LVL_0P38,
- USB_CH_IP_CUR_LVL_0P45,
- USB_CH_IP_CUR_LVL_0P5,
- USB_CH_IP_CUR_LVL_0P6,
- USB_CH_IP_CUR_LVL_0P7,
- USB_CH_IP_CUR_LVL_0P8,
- USB_CH_IP_CUR_LVL_0P9,
- USB_CH_IP_CUR_LVL_1P0,
- USB_CH_IP_CUR_LVL_1P1,
- USB_CH_IP_CUR_LVL_1P3,
- USB_CH_IP_CUR_LVL_1P4,
- USB_CH_IP_CUR_LVL_1P5,
-};
-
static int ab8500_voltage_to_regval(int voltage)
{
int i;
@@ -1026,41 +1002,41 @@ static int ab8500_voltage_to_regval(int voltage)
return -1;
}
-static int ab8500_current_to_regval(int curr)
+static int ab8500_current_to_regval(struct ab8500_charger *di, int curr)
{
int i;
- if (curr < ab8500_charger_current_map[0])
+ if (curr < di->bm->chg_output_curr[0])
return 0;
- for (i = 0; i < ARRAY_SIZE(ab8500_charger_current_map); i++) {
- if (curr < ab8500_charger_current_map[i])
+ for (i = 0; i < di->bm->n_chg_out_curr; i++) {
+ if (curr < di->bm->chg_output_curr[i])
return i - 1;
}
/* If not last element, return error */
- i = ARRAY_SIZE(ab8500_charger_current_map) - 1;
- if (curr == ab8500_charger_current_map[i])
+ i = di->bm->n_chg_out_curr - 1;
+ if (curr == di->bm->chg_output_curr[i])
return i;
else
return -1;
}
-static int ab8500_vbus_in_curr_to_regval(int curr)
+static int ab8500_vbus_in_curr_to_regval(struct ab8500_charger *di, int curr)
{
int i;
- if (curr < ab8500_charger_vbus_in_curr_map[0])
+ if (curr < di->bm->chg_input_curr[0])
return 0;
- for (i = 0; i < ARRAY_SIZE(ab8500_charger_vbus_in_curr_map); i++) {
- if (curr < ab8500_charger_vbus_in_curr_map[i])
+ for (i = 0; i < di->bm->n_chg_in_curr; i++) {
+ if (curr < di->bm->chg_input_curr[i])
return i - 1;
}
/* If not last element, return error */
- i = ARRAY_SIZE(ab8500_charger_vbus_in_curr_map) - 1;
- if (curr == ab8500_charger_vbus_in_curr_map[i])
+ i = di->bm->n_chg_in_curr - 1;
+ if (curr == di->bm->chg_input_curr[i])
return i;
else
return -1;
@@ -1077,28 +1053,48 @@ static int ab8500_vbus_in_curr_to_regval(int curr)
*/
static int ab8500_charger_get_usb_cur(struct ab8500_charger *di)
{
+ int ret = 0;
switch (di->usb_state.usb_current) {
case 100:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P09;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P09;
break;
case 200:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P19;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P19;
break;
case 300:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P29;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P29;
break;
case 400:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P38;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P38;
break;
case 500:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P5;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
break;
default:
- di->max_usb_in_curr = USB_CH_IP_CUR_LVL_0P05;
- return -1;
+ di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P05;
+ ret = -EPERM;
break;
};
- return 0;
+ di->max_usb_in_curr.set_max = di->max_usb_in_curr.usb_type_max;
+ return ret;
+}
+
+/**
+ * ab8500_charger_check_continue_stepping() - Check to allow stepping
+ * @di: pointer to the ab8500_charger structure
+ * @reg: select what charger register to check
+ *
+ * Check if current stepping should be allowed to continue.
+ * Checks if charger source has not collapsed. If it has, further stepping
+ * is not allowed.
+ */
+static bool ab8500_charger_check_continue_stepping(struct ab8500_charger *di,
+ int reg)
+{
+ if (reg == AB8500_USBCH_IPT_CRNTLVL_REG)
+ return !di->flags.vbus_drop_end;
+ else
+ return true;
}
/**
@@ -1118,7 +1114,7 @@ static int ab8500_charger_set_current(struct ab8500_charger *di,
int ich, int reg)
{
int ret = 0;
- int auto_curr_index, curr_index, prev_curr_index, shift_value, i;
+ int curr_index, prev_curr_index, shift_value, i;
u8 reg_value;
u32 step_udelay;
bool no_stepping = false;
@@ -1136,39 +1132,27 @@ static int ab8500_charger_set_current(struct ab8500_charger *di,
case AB8500_MCH_IPT_CURLVL_REG:
shift_value = MAIN_CH_INPUT_CURR_SHIFT;
prev_curr_index = (reg_value >> shift_value);
- curr_index = ab8500_current_to_regval(ich);
+ curr_index = ab8500_current_to_regval(di, ich);
step_udelay = STEP_UDELAY;
if (!di->ac.charger_connected)
no_stepping = true;
break;
case AB8500_USBCH_IPT_CRNTLVL_REG:
- shift_value = VBUS_IN_CURR_LIM_SHIFT;
+ if (is_ab8540(di->parent))
+ shift_value = AB8540_VBUS_IN_CURR_LIM_SHIFT;
+ else
+ shift_value = VBUS_IN_CURR_LIM_SHIFT;
prev_curr_index = (reg_value >> shift_value);
- curr_index = ab8500_vbus_in_curr_to_regval(ich);
+ curr_index = ab8500_vbus_in_curr_to_regval(di, ich);
step_udelay = STEP_UDELAY * 100;
- ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CH_USBCH_STAT2_REG, &reg_value);
- if (ret < 0) {
- dev_err(di->dev, "%s read failed\n", __func__);
- goto exit_set_current;
- }
- auto_curr_index =
- reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT;
-
- dev_dbg(di->dev, "%s Auto VBUS curr is %d mA\n",
- __func__,
- ab8500_charger_vbus_in_curr_map[auto_curr_index]);
-
- prev_curr_index = min(prev_curr_index, auto_curr_index);
-
if (!di->usb.charger_connected)
no_stepping = true;
break;
case AB8500_CH_OPT_CRNTLVL_REG:
shift_value = 0;
prev_curr_index = (reg_value >> shift_value);
- curr_index = ab8500_current_to_regval(ich);
+ curr_index = ab8500_current_to_regval(di, ich);
step_udelay = STEP_UDELAY;
if (curr_index && (curr_index - prev_curr_index) > 1)
step_udelay *= 100;
@@ -1219,7 +1203,8 @@ static int ab8500_charger_set_current(struct ab8500_charger *di,
usleep_range(step_udelay, step_udelay * 2);
}
} else {
- for (i = prev_curr_index + 1; i <= curr_index; i++) {
+ bool allow = true;
+ for (i = prev_curr_index + 1; i <= curr_index && allow; i++) {
dev_dbg(di->dev, "curr change_2 to: %x for 0x%02x\n",
(u8)i << shift_value, reg);
ret = abx500_set_register_interruptible(di->dev,
@@ -1230,6 +1215,8 @@ static int ab8500_charger_set_current(struct ab8500_charger *di,
}
if (i != curr_index)
usleep_range(step_udelay, step_udelay * 2);
+
+ allow = ab8500_charger_check_continue_stepping(di, reg);
}
}
@@ -1255,6 +1242,11 @@ static int ab8500_charger_set_vbus_in_curr(struct ab8500_charger *di,
/* We should always use to lowest current limit */
min_value = min(di->bm->chg_params->usb_curr_max, ich_in);
+ if (di->max_usb_in_curr.set_max > 0)
+ min_value = min(di->max_usb_in_curr.set_max, min_value);
+
+ if (di->usb_state.usb_current >= 0)
+ min_value = min(di->usb_state.usb_current, min_value);
switch (min_value) {
case 100:
@@ -1400,8 +1392,8 @@ static int ab8500_charger_ac_en(struct ux500_charger *charger,
/* Check if the requested voltage or current is valid */
volt_index = ab8500_voltage_to_regval(vset);
- curr_index = ab8500_current_to_regval(iset);
- input_curr_index = ab8500_current_to_regval(
+ curr_index = ab8500_current_to_regval(di, iset);
+ input_curr_index = ab8500_current_to_regval(di,
di->bm->chg_params->ac_curr_max);
if (volt_index < 0 || curr_index < 0 || input_curr_index < 0) {
dev_err(di->dev,
@@ -1572,7 +1564,7 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
/* Check if the requested voltage or current is valid */
volt_index = ab8500_voltage_to_regval(vset);
- curr_index = ab8500_current_to_regval(ich_out);
+ curr_index = ab8500_current_to_regval(di, ich_out);
if (volt_index < 0 || curr_index < 0) {
dev_err(di->dev,
"Charger voltage or current too high, "
@@ -1609,7 +1601,8 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
di->usb.charger_online = 1;
/* USBChInputCurr: current that can be drawn from the usb */
- ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ ret = ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr.usb_type_max);
if (ret) {
dev_err(di->dev, "setting USBChInputCurr failed\n");
return ret;
@@ -1668,8 +1661,7 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
/* Cancel any pending Vbat check work */
- if (delayed_work_pending(&di->check_vbat_work))
- cancel_delayed_work(&di->check_vbat_work);
+ cancel_delayed_work(&di->check_vbat_work);
}
ab8500_power_supply_changed(di, &di->usb_chg.psy);
@@ -1677,6 +1669,128 @@ static int ab8500_charger_usb_en(struct ux500_charger *charger,
return ret;
}
+static int ab8500_external_charger_prepare(struct notifier_block *charger_nb,
+ unsigned long event, void *data)
+{
+ int ret;
+ struct device *dev = data;
+ /*Toggle External charger control pin*/
+ ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
+ AB8500_SYS_CHARGER_CONTROL_REG,
+ EXTERNAL_CHARGER_DISABLE_REG_VAL);
+ if (ret < 0) {
+ dev_err(dev, "write reg failed %d\n", ret);
+ goto out;
+ }
+ ret = abx500_set_register_interruptible(dev, AB8500_SYS_CTRL1_BLOCK,
+ AB8500_SYS_CHARGER_CONTROL_REG,
+ EXTERNAL_CHARGER_ENABLE_REG_VAL);
+ if (ret < 0)
+ dev_err(dev, "Write reg failed %d\n", ret);
+
+out:
+ return ret;
+}
+
+/**
+ * ab8500_charger_usb_check_enable() - enable usb charging
+ * @charger: pointer to the ux500_charger structure
+ * @vset: charging voltage
+ * @iset: charger output current
+ *
+ * Check if the VBUS charger has been disconnected and reconnected without
+ * AB8500 rising an interrupt. Returns 0 on success.
+ */
+static int ab8500_charger_usb_check_enable(struct ux500_charger *charger,
+ int vset, int iset)
+{
+ u8 usbch_ctrl1 = 0;
+ int ret = 0;
+
+ struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);
+
+ if (!di->usb.charger_connected)
+ return ret;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_USBCH_CTRL1_REG, &usbch_ctrl1);
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+ return ret;
+ }
+ dev_dbg(di->dev, "USB charger ctrl: 0x%02x\n", usbch_ctrl1);
+
+ if (!(usbch_ctrl1 & USB_CH_ENA)) {
+ dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
+
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CHARGER_CTRL,
+ DROP_COUNT_RESET, DROP_COUNT_RESET);
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
+ return ret;
+ }
+
+ ret = ab8500_charger_usb_en(&di->usb_chg, true, vset, iset);
+ if (ret < 0) {
+ dev_err(di->dev, "Failed to enable VBUS charger %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+/**
+ * ab8500_charger_ac_check_enable() - enable usb charging
+ * @charger: pointer to the ux500_charger structure
+ * @vset: charging voltage
+ * @iset: charger output current
+ *
+ * Check if the AC charger has been disconnected and reconnected without
+ * AB8500 rising an interrupt. Returns 0 on success.
+ */
+static int ab8500_charger_ac_check_enable(struct ux500_charger *charger,
+ int vset, int iset)
+{
+ u8 mainch_ctrl1 = 0;
+ int ret = 0;
+
+ struct ab8500_charger *di = to_ab8500_charger_ac_device_info(charger);
+
+ if (!di->ac.charger_connected)
+ return ret;
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_MCH_CTRL1, &mainch_ctrl1);
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 read failed %d\n", __LINE__);
+ return ret;
+ }
+ dev_dbg(di->dev, "AC charger ctrl: 0x%02x\n", mainch_ctrl1);
+
+ if (!(mainch_ctrl1 & MAIN_CH_ENA)) {
+ dev_info(di->dev, "Charging has been disabled abnormally and will be re-enabled\n");
+
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CHARGER_CTRL,
+ DROP_COUNT_RESET, DROP_COUNT_RESET);
+
+ if (ret < 0) {
+ dev_err(di->dev, "ab8500 write failed %d\n", __LINE__);
+ return ret;
+ }
+
+ ret = ab8500_charger_ac_en(&di->usb_chg, true, vset, iset);
+ if (ret < 0) {
+ dev_err(di->dev, "failed to enable AC charger %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+ return ret;
+}
+
/**
* ab8500_charger_watchdog_kick() - kick charger watchdog
* @di: pointer to the ab8500_charger structure
@@ -1734,8 +1848,68 @@ static int ab8500_charger_update_charger_current(struct ux500_charger *charger,
/* Reset the main and usb drop input current measurement counter */
ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CHARGER_CTRL,
- 0x1);
+ AB8500_CHARGER_CTRL, DROP_COUNT_RESET);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * ab8540_charger_power_path_enable() - enable usb power path mode
+ * @charger: pointer to the ux500_charger structure
+ * @enable: enable/disable flag
+ *
+ * Enable or disable the power path for usb mode
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8540_charger_power_path_enable(struct ux500_charger *charger,
+ bool enable)
+{
+ int ret;
+ struct ab8500_charger *di;
+
+ if (charger->psy.type == POWER_SUPPLY_TYPE_USB)
+ di = to_ab8500_charger_usb_device_info(charger);
+ else
+ return -ENXIO;
+
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8540_USB_PP_MODE_REG,
+ BUS_POWER_PATH_MODE_ENA, enable);
+ if (ret) {
+ dev_err(di->dev, "%s write failed\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+
+/**
+ * ab8540_charger_usb_pre_chg_enable() - enable usb pre change
+ * @charger: pointer to the ux500_charger structure
+ * @enable: enable/disable flag
+ *
+ * Enable or disable the pre-chage for usb mode
+ * Returns error code in case of failure else 0(on success)
+ */
+static int ab8540_charger_usb_pre_chg_enable(struct ux500_charger *charger,
+ bool enable)
+{
+ int ret;
+ struct ab8500_charger *di;
+
+ if (charger->psy.type == POWER_SUPPLY_TYPE_USB)
+ di = to_ab8500_charger_usb_device_info(charger);
+ else
+ return -ENXIO;
+
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8540_USB_PP_CHR_REG,
+ BUS_POWER_PATH_PRECHG_ENA, enable);
if (ret) {
dev_err(di->dev, "%s write failed\n", __func__);
return ret;
@@ -1823,9 +1997,10 @@ static void ab8500_charger_check_vbat_work(struct work_struct *work)
di->vbat > VBAT_TRESH_IP_CUR_RED))) {
dev_dbg(di->dev, "Vbat did cross threshold, curr: %d, new: %d,"
- " old: %d\n", di->max_usb_in_curr, di->vbat,
- di->old_vbat);
- ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ " old: %d\n", di->max_usb_in_curr.usb_type_max,
+ di->vbat, di->old_vbat);
+ ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr.usb_type_max);
power_supply_changed(&di->usb_chg.psy);
}
@@ -2105,7 +2280,8 @@ static void ab8500_charger_usb_link_attach_work(struct work_struct *work)
/* Update maximum input current if USB enumeration is not detected */
if (!di->usb.charger_online) {
- ret = ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ ret = ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr.usb_type_max);
if (ret)
return;
}
@@ -2125,6 +2301,7 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
int detected_chargers;
int ret;
u8 val;
+ u8 link_status;
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, usb_link_status_work);
@@ -2144,38 +2321,61 @@ static void ab8500_charger_usb_link_status_work(struct work_struct *work)
* to start the charging process. but by jumping
* thru a few hoops it can be forced to start.
*/
- ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
- AB8500_USB_LINE_STAT_REG, &val);
+ if (is_ab8500(di->parent))
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINE_STAT_REG, &val);
+ else
+ ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
+ AB8500_USB_LINK1_STAT_REG, &val);
+
if (ret >= 0)
dev_dbg(di->dev, "UsbLineStatus register = 0x%02x\n", val);
else
dev_dbg(di->dev, "Error reading USB link status\n");
+ if (is_ab8500(di->parent))
+ link_status = AB8500_USB_LINK_STATUS;
+ else
+ link_status = AB8505_USB_LINK_STATUS;
+
if (detected_chargers & USB_PW_CONN) {
- if (((val & AB8500_USB_LINK_STATUS) >> 3) == USB_STAT_NOT_VALID_LINK &&
+ if (((val & link_status) >> USB_LINK_STATUS_SHIFT) ==
+ USB_STAT_NOT_VALID_LINK &&
di->invalid_charger_detect_state == 0) {
- dev_dbg(di->dev, "Invalid charger detected, state= 0\n");
+ dev_dbg(di->dev,
+ "Invalid charger detected, state= 0\n");
/*Enable charger*/
abx500_mask_and_set_register_interruptible(di->dev,
- AB8500_CHARGER, AB8500_USBCH_CTRL1_REG, 0x01, 0x01);
+ AB8500_CHARGER, AB8500_USBCH_CTRL1_REG,
+ USB_CH_ENA, USB_CH_ENA);
/*Enable charger detection*/
- abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
- AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x01);
+ abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
+ USB_CH_DET, USB_CH_DET);
di->invalid_charger_detect_state = 1;
/*exit and wait for new link status interrupt.*/
return;
}
if (di->invalid_charger_detect_state == 1) {
- dev_dbg(di->dev, "Invalid charger detected, state= 1\n");
+ dev_dbg(di->dev,
+ "Invalid charger detected, state= 1\n");
/*Stop charger detection*/
- abx500_mask_and_set_register_interruptible(di->dev, AB8500_USB,
- AB8500_MCH_IPT_CURLVL_REG, 0x01, 0x00);
+ abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINE_CTRL2_REG,
+ USB_CH_DET, 0x00);
/*Check link status*/
- ret = abx500_get_register_interruptible(di->dev, AB8500_USB,
- AB8500_USB_LINE_STAT_REG, &val);
+ if (is_ab8500(di->parent))
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG,
+ &val);
+ else
+ ret = abx500_get_register_interruptible(di->dev,
+ AB8500_USB, AB8500_USB_LINK1_STAT_REG,
+ &val);
+
dev_dbg(di->dev, "USB link status= 0x%02x\n",
- (val & AB8500_USB_LINK_STATUS) >> 3);
+ (val & link_status) >> USB_LINK_STATUS_SHIFT);
di->invalid_charger_detect_state = 2;
}
} else {
@@ -2273,7 +2473,7 @@ static void ab8500_charger_usb_state_changed_work(struct work_struct *work)
if (!ab8500_charger_get_usb_cur(di)) {
/* Update maximum input current */
ret = ab8500_charger_set_vbus_in_curr(di,
- di->max_usb_in_curr);
+ di->max_usb_in_curr.usb_type_max);
if (ret)
return;
@@ -2422,7 +2622,9 @@ static irqreturn_t ab8500_charger_mainchplugdet_handler(int irq, void *_di)
mutex_lock(&di->charger_attached_mutex);
mutex_unlock(&di->charger_attached_mutex);
- queue_delayed_work(di->charger_wq,
+
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
&di->ac_charger_attached_work,
HZ);
return IRQ_HANDLED;
@@ -2491,6 +2693,8 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work)
{
struct ab8500_charger *di = container_of(work,
struct ab8500_charger, vbus_drop_end_work.work);
+ int ret, curr;
+ u8 reg_value;
di->flags.vbus_drop_end = false;
@@ -2498,8 +2702,45 @@ static void ab8500_charger_vbus_drop_end_work(struct work_struct *work)
abx500_set_register_interruptible(di->dev,
AB8500_CHARGER, AB8500_CHARGER_CTRL, 0x01);
+ if (is_ab8540(di->parent))
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8540_CH_USBCH_STAT3_REG, &reg_value);
+ else
+ ret = abx500_get_register_interruptible(di->dev, AB8500_CHARGER,
+ AB8500_CH_USBCH_STAT2_REG, &reg_value);
+ if (ret < 0) {
+ dev_err(di->dev, "%s read failed\n", __func__);
+ return;
+ }
+
+ if (is_ab8540(di->parent))
+ curr = di->bm->chg_input_curr[
+ reg_value & AB8540_AUTO_VBUS_IN_CURR_MASK];
+ else
+ curr = di->bm->chg_input_curr[
+ reg_value >> AUTO_VBUS_IN_CURR_LIM_SHIFT];
+
+ if (di->max_usb_in_curr.calculated_max != curr) {
+ /* USB source is collapsing */
+ di->max_usb_in_curr.calculated_max = curr;
+ dev_dbg(di->dev,
+ "VBUS input current limiting to %d mA\n",
+ di->max_usb_in_curr.calculated_max);
+ } else {
+ /*
+ * USB source can not give more than this amount.
+ * Taking more will collapse the source.
+ */
+ di->max_usb_in_curr.set_max =
+ di->max_usb_in_curr.calculated_max;
+ dev_dbg(di->dev,
+ "VBUS input current limited to %d mA\n",
+ di->max_usb_in_curr.set_max);
+ }
+
if (di->usb.charger_connected)
- ab8500_charger_set_vbus_in_curr(di, di->max_usb_in_curr);
+ ab8500_charger_set_vbus_in_curr(di,
+ di->max_usb_in_curr.usb_type_max);
}
/**
@@ -2654,8 +2895,13 @@ static irqreturn_t ab8500_charger_vbuschdropend_handler(int irq, void *_di)
dev_dbg(di->dev, "VBUS charger drop ended\n");
di->flags.vbus_drop_end = true;
+
+ /*
+ * VBUS might have dropped due to bad connection.
+ * Schedule a new input limit set to the value SW requests.
+ */
queue_delayed_work(di->charger_wq, &di->vbus_drop_end_work,
- round_jiffies(30 * HZ));
+ round_jiffies(VBUS_IN_CURR_LIM_RETRY_SET_TIME * HZ));
return IRQ_HANDLED;
}
@@ -2836,6 +3082,7 @@ static int ab8500_charger_usb_get_property(struct power_supply *psy,
static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
{
int ret = 0;
+ u8 bup_vch_range = 0, vbup33_vrtcn = 0;
/* Setup maximum charger current and voltage for ABB cut2.0 */
if (!is_ab8500_1p1_or_earlier(di->parent)) {
@@ -2848,9 +3095,14 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
goto out;
}
- ret = abx500_set_register_interruptible(di->dev,
- AB8500_CHARGER,
- AB8500_CH_OPT_CRNTLVL_MAX_REG, CH_OP_CUR_LVL_1P6);
+ if (is_ab8540(di->parent))
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG,
+ CH_OP_CUR_LVL_2P);
+ else
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8500_CH_OPT_CRNTLVL_MAX_REG,
+ CH_OP_CUR_LVL_1P6);
if (ret) {
dev_err(di->dev,
"failed to set CH_OPT_CRNTLVL_MAX_REG\n");
@@ -2858,7 +3110,8 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
}
}
- if (is_ab9540_2p0(di->parent) || is_ab8505_2p0(di->parent))
+ if (is_ab9540_2p0(di->parent) || is_ab9540_3p0(di->parent)
+ || is_ab8505_2p0(di->parent) || is_ab8540(di->parent))
ret = abx500_mask_and_set_register_interruptible(di->dev,
AB8500_CHARGER,
AB8500_USBCH_CTRL2_REG,
@@ -2930,14 +3183,6 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
goto out;
}
- /* Set charger watchdog timeout */
- ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
- AB8500_CH_WD_TIMER_REG, WD_TIMER);
- if (ret) {
- dev_err(di->dev, "failed to set charger watchdog timeout\n");
- goto out;
- }
-
ret = ab8500_charger_led_en(di, false);
if (ret < 0) {
dev_err(di->dev, "failed to disable LED\n");
@@ -2945,15 +3190,30 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
}
/* Backup battery voltage and current */
+ if (di->bm->bkup_bat_v > BUP_VCH_SEL_3P1V)
+ bup_vch_range = BUP_VCH_RANGE;
+ if (di->bm->bkup_bat_v == BUP_VCH_SEL_3P3V)
+ vbup33_vrtcn = VBUP33_VRTCN;
+
ret = abx500_set_register_interruptible(di->dev,
AB8500_RTC,
AB8500_RTC_BACKUP_CHG_REG,
- di->bm->bkup_bat_v |
- di->bm->bkup_bat_i);
+ (di->bm->bkup_bat_v & 0x3) | di->bm->bkup_bat_i);
if (ret) {
dev_err(di->dev, "failed to setup backup battery charging\n");
goto out;
}
+ if (is_ab8540(di->parent)) {
+ ret = abx500_set_register_interruptible(di->dev,
+ AB8500_RTC,
+ AB8500_RTC_CTRL1_REG,
+ bup_vch_range | vbup33_vrtcn);
+ if (ret) {
+ dev_err(di->dev,
+ "failed to setup backup battery charging\n");
+ goto out;
+ }
+ }
/* Enable backup battery charging */
abx500_mask_and_set_register_interruptible(di->dev,
@@ -2962,6 +3222,25 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di)
if (ret < 0)
dev_err(di->dev, "%s mask and set failed\n", __func__);
+ if (is_ab8540(di->parent)) {
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8540_USB_PP_MODE_REG,
+ BUS_VSYS_VOL_SELECT_MASK, BUS_VSYS_VOL_SELECT_3P6V);
+ if (ret) {
+ dev_err(di->dev,
+ "failed to setup usb power path vsys voltage\n");
+ goto out;
+ }
+ ret = abx500_mask_and_set_register_interruptible(di->dev,
+ AB8500_CHARGER, AB8540_USB_PP_CHR_REG,
+ BUS_PP_PRECHG_CURRENT_MASK, 0);
+ if (ret) {
+ dev_err(di->dev,
+ "failed to setup usb power path prechage current\n");
+ goto out;
+ }
+ }
+
out:
return ret;
}
@@ -3055,11 +3334,8 @@ static int ab8500_charger_resume(struct platform_device *pdev)
dev_err(di->dev, "Failed to kick WD!\n");
/* If not already pending start a new timer */
- if (!delayed_work_pending(
- &di->kick_wd_work)) {
- queue_delayed_work(di->charger_wq, &di->kick_wd_work,
- round_jiffies(WD_KICK_INTERVAL));
- }
+ queue_delayed_work(di->charger_wq, &di->kick_wd_work,
+ round_jiffies(WD_KICK_INTERVAL));
}
/* If we still have a HW failure, schedule a new check */
@@ -3079,12 +3355,9 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
{
struct ab8500_charger *di = platform_get_drvdata(pdev);
- /* Cancel any pending HW failure check */
- if (delayed_work_pending(&di->check_hw_failure_work))
- cancel_delayed_work(&di->check_hw_failure_work);
-
- if (delayed_work_pending(&di->vbus_drop_end_work))
- cancel_delayed_work(&di->vbus_drop_end_work);
+ /* Cancel any pending jobs */
+ cancel_delayed_work(&di->check_hw_failure_work);
+ cancel_delayed_work(&di->vbus_drop_end_work);
flush_delayed_work(&di->attach_work);
flush_delayed_work(&di->usb_charger_attached_work);
@@ -3107,6 +3380,10 @@ static int ab8500_charger_suspend(struct platform_device *pdev,
#define ab8500_charger_resume NULL
#endif
+static struct notifier_block charger_nb = {
+ .notifier_call = ab8500_external_charger_prepare,
+};
+
static int ab8500_charger_remove(struct platform_device *pdev)
{
struct ab8500_charger *di = platform_get_drvdata(pdev);
@@ -3136,13 +3413,18 @@ static int ab8500_charger_remove(struct platform_device *pdev)
/* Delete the work queue */
destroy_workqueue(di->charger_wq);
+ /* Unregister external charger enable notifier */
+ if (!di->ac_chg.enabled)
+ blocking_notifier_chain_unregister(
+ &charger_notifier_list, &charger_nb);
+
flush_scheduled_work();
- if(di->usb_chg.enabled)
+ if (di->usb_chg.enabled)
power_supply_unregister(&di->usb_chg.psy);
-#if !defined(CONFIG_CHARGER_PM2301)
- if(di->ac_chg.enabled)
+
+ if (di->ac_chg.enabled && !di->ac_chg.external)
power_supply_unregister(&di->ac_chg.psy);
-#endif
+
platform_set_drvdata(pdev, NULL);
return 0;
@@ -3206,16 +3488,22 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->ac_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
/* ux500_charger sub-class */
di->ac_chg.ops.enable = &ab8500_charger_ac_en;
+ di->ac_chg.ops.check_enable = &ab8500_charger_ac_check_enable;
di->ac_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
di->ac_chg.ops.update_curr = &ab8500_charger_update_charger_current;
di->ac_chg.max_out_volt = ab8500_charger_voltage_map[
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
- di->ac_chg.max_out_curr = ab8500_charger_current_map[
- ARRAY_SIZE(ab8500_charger_current_map) - 1];
+ di->ac_chg.max_out_curr =
+ di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
di->ac_chg.wdt_refresh = CHG_WD_INTERVAL;
di->ac_chg.enabled = di->bm->ac_enabled;
di->ac_chg.external = false;
+ /*notifier for external charger enabling*/
+ if (!di->ac_chg.enabled)
+ blocking_notifier_chain_register(
+ &charger_notifier_list, &charger_nb);
+
/* USB supply */
/* power_supply base class */
di->usb_chg.psy.name = "ab8500_usb";
@@ -3227,15 +3515,20 @@ static int ab8500_charger_probe(struct platform_device *pdev)
di->usb_chg.psy.num_supplicants = ARRAY_SIZE(supply_interface),
/* ux500_charger sub-class */
di->usb_chg.ops.enable = &ab8500_charger_usb_en;
+ di->usb_chg.ops.check_enable = &ab8500_charger_usb_check_enable;
di->usb_chg.ops.kick_wd = &ab8500_charger_watchdog_kick;
di->usb_chg.ops.update_curr = &ab8500_charger_update_charger_current;
+ di->usb_chg.ops.pp_enable = &ab8540_charger_power_path_enable;
+ di->usb_chg.ops.pre_chg_enable = &ab8540_charger_usb_pre_chg_enable;
di->usb_chg.max_out_volt = ab8500_charger_voltage_map[
ARRAY_SIZE(ab8500_charger_voltage_map) - 1];
- di->usb_chg.max_out_curr = ab8500_charger_current_map[
- ARRAY_SIZE(ab8500_charger_current_map) - 1];
+ di->usb_chg.max_out_curr =
+ di->bm->chg_output_curr[di->bm->n_chg_out_curr - 1];
di->usb_chg.wdt_refresh = CHG_WD_INTERVAL;
di->usb_chg.enabled = di->bm->usb_enabled;
di->usb_chg.external = false;
+ di->usb_chg.power_path = di->bm->usb_power_path;
+ di->usb_state.usb_current = -1;
/* Create a work queue for the charger */
di->charger_wq =
@@ -3316,7 +3609,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
}
/* Register AC charger class */
- if(di->ac_chg.enabled) {
+ if (di->ac_chg.enabled) {
ret = power_supply_register(di->dev, &di->ac_chg.psy);
if (ret) {
dev_err(di->dev, "failed to register AC charger\n");
@@ -3325,7 +3618,7 @@ static int ab8500_charger_probe(struct platform_device *pdev)
}
/* Register USB charger class */
- if(di->usb_chg.enabled) {
+ if (di->usb_chg.enabled) {
ret = power_supply_register(di->dev, &di->usb_chg.psy);
if (ret) {
dev_err(di->dev, "failed to register USB charger\n");
@@ -3385,14 +3678,16 @@ static int ab8500_charger_probe(struct platform_device *pdev)
ch_stat = ab8500_charger_detect_chargers(di, false);
if ((ch_stat & AC_PW_CONN) == AC_PW_CONN) {
- queue_delayed_work(di->charger_wq,
- &di->ac_charger_attached_work,
- HZ);
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
+ &di->ac_charger_attached_work,
+ HZ);
}
if ((ch_stat & USB_PW_CONN) == USB_PW_CONN) {
- queue_delayed_work(di->charger_wq,
- &di->usb_charger_attached_work,
- HZ);
+ if (is_ab8500(di->parent))
+ queue_delayed_work(di->charger_wq,
+ &di->usb_charger_attached_work,
+ HZ);
}
mutex_unlock(&di->charger_attached_mutex);
@@ -3410,10 +3705,10 @@ free_irq:
put_usb_phy:
usb_put_phy(di->usb_phy);
free_usb:
- if(di->usb_chg.enabled)
+ if (di->usb_chg.enabled)
power_supply_unregister(&di->usb_chg.psy);
free_ac:
- if(di->ac_chg.enabled)
+ if (di->ac_chg.enabled)
power_supply_unregister(&di->ac_chg.psy);
free_charger_wq:
destroy_workqueue(di->charger_wq);
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 25dae4c4b0ef..c5391f5c372d 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -36,7 +36,7 @@
#define MILLI_TO_MICRO 1000
#define FG_LSB_IN_MA 1627
-#define QLSB_NANO_AMP_HOURS_X10 1129
+#define QLSB_NANO_AMP_HOURS_X10 1071
#define INS_CURR_TIMEOUT (3 * HZ)
#define SEC_TO_SAMPLE(S) (S * 4)
@@ -672,11 +672,11 @@ int ab8500_fg_inst_curr_finalize(struct ab8500_fg *di, int *res)
/*
* Convert to unit value in mA
* Full scale input voltage is
- * 66.660mV => LSB = 66.660mV/(4096*res) = 1.627mA
+ * 63.160mV => LSB = 63.160mV/(4096*res) = 1.542mA
* Given a 250ms conversion cycle time the LSB corresponds
- * to 112.9 nAh. Convert to current by dividing by the conversion
+ * to 107.1 nAh. Convert to current by dividing by the conversion
* time in hours (250ms = 1 / (3600 * 4)h)
- * 112.9nAh assumes 10mOhm, but fg_res is in 0.1mOhm
+ * 107.1nAh assumes 10mOhm, but fg_res is in 0.1mOhm
*/
val = (val * QLSB_NANO_AMP_HOURS_X10 * 36 * 4) /
(1000 * di->bm->fg_res);
@@ -863,7 +863,7 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
{
int i, tbl_size;
- struct abx500_v_to_cap *tbl;
+ const struct abx500_v_to_cap *tbl;
int cap = 0;
tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl,
@@ -915,7 +915,7 @@ static int ab8500_fg_uncomp_volt_to_capacity(struct ab8500_fg *di)
static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
{
int i, tbl_size;
- struct batres_vs_temp *tbl;
+ const struct batres_vs_temp *tbl;
int resist = 0;
tbl = di->bm->bat_type[di->bm->batt_id].batres_tbl;
@@ -1354,9 +1354,6 @@ static void ab8500_fg_check_capacity_limits(struct ab8500_fg *di, bool init)
* algorithm says.
*/
di->bat_cap.prev_percent = 1;
- di->bat_cap.permille = 1;
- di->bat_cap.prev_mah = 1;
- di->bat_cap.mah = 1;
percent = 1;
changed = true;
@@ -1683,7 +1680,6 @@ static void ab8500_fg_algorithm_discharging(struct ab8500_fg *di)
break;
case AB8500_FG_DISCHARGE_WAKEUP:
- ab8500_fg_coulomb_counter(di, true);
ab8500_fg_calc_cap_discharge_voltage(di, true);
di->fg_samples = SEC_TO_SAMPLE(
@@ -1768,9 +1764,10 @@ static void ab8500_fg_algorithm(struct ab8500_fg *di)
ab8500_fg_algorithm_discharging(di);
}
- dev_dbg(di->dev, "[FG_DATA] %d %d %d %d %d %d %d %d %d "
+ dev_dbg(di->dev, "[FG_DATA] %d %d %d %d %d %d %d %d %d %d "
"%d %d %d %d %d %d %d\n",
di->bat_cap.max_mah_design,
+ di->bat_cap.max_mah,
di->bat_cap.mah,
di->bat_cap.permille,
di->bat_cap.level,
@@ -1982,7 +1979,7 @@ static void ab8500_fg_instant_work(struct work_struct *work)
}
/**
- * ab8500_fg_cc_data_end_handler() - isr to get battery avg current.
+ * ab8500_fg_cc_data_end_handler() - end of data conversion isr.
* @irq: interrupt number
* @_di: pointer to the ab8500_fg structure
*
@@ -2002,7 +1999,7 @@ static irqreturn_t ab8500_fg_cc_data_end_handler(int irq, void *_di)
}
/**
- * ab8500_fg_cc_convend_handler() - isr to get battery avg current.
+ * ab8500_fg_cc_int_calib_handler () - end of calibration isr.
* @irq: interrupt number
* @_di: pointer to the ab8500_fg structure
*
@@ -2153,9 +2150,7 @@ static int ab8500_fg_get_property(struct power_supply *psy,
val->intval = di->bat_cap.prev_mah;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- if (di->bm->capacity_scaling)
- val->intval = di->bat_cap.cap_scale.scaled_cap;
- else if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
+ if (di->flags.batt_unknown && !di->bm->chg_unknown_bat &&
di->flags.batt_id_received)
val->intval = 100;
else
@@ -2344,6 +2339,50 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
dev_err(di->dev, "BattOk init write failed.\n");
goto out;
}
+
+ if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+ abx500_get_chip_id(di->dev) >= AB8500_CUT2P0)
+ || is_ab8540(di->parent)) {
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_MAX_TIME_REG, di->bm->fg_params->pcut_max_time);
+
+ if (ret) {
+ dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_MAX_TIME_REG\n", __func__);
+ goto out;
+ };
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_FLAG_TIME_REG, di->bm->fg_params->pcut_flag_time);
+
+ if (ret) {
+ dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_FLAG_TIME_REG\n", __func__);
+ goto out;
+ };
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_RESTART_REG, di->bm->fg_params->pcut_max_restart);
+
+ if (ret) {
+ dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_RESTART_REG\n", __func__);
+ goto out;
+ };
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_DEBOUNCE_REG, di->bm->fg_params->pcut_debounce_time);
+
+ if (ret) {
+ dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_DEBOUNCE_REG\n", __func__);
+ goto out;
+ };
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_CTL_STATUS_REG, di->bm->fg_params->pcut_enable);
+
+ if (ret) {
+ dev_err(di->dev, "%s write failed AB8505_RTC_PCUT_CTL_STATUS_REG\n", __func__);
+ goto out;
+ };
+ }
out:
return ret;
}
@@ -2546,6 +2585,428 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di)
return ret;
}
+
+static ssize_t ab8505_powercut_flagtime_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_FLAG_TIME_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_FLAG_TIME_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_flagtime_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ long unsigned reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ reg_value = simple_strtoul(buf, NULL, 10);
+
+ if (reg_value > 0x7F) {
+ dev_err(dev, "Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime\n");
+ goto fail;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_FLAG_TIME_REG, (u8)reg_value);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to set AB8505_RTC_PCUT_FLAG_TIME_REG\n");
+
+fail:
+ return count;
+}
+
+static ssize_t ab8505_powercut_maxtime_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_MAX_TIME_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_MAX_TIME_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+ return ret;
+
+}
+
+static ssize_t ab8505_powercut_maxtime_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ int reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ reg_value = simple_strtoul(buf, NULL, 10);
+ if (reg_value > 0x7F) {
+ dev_err(dev, "Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime\n");
+ goto fail;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_MAX_TIME_REG, (u8)reg_value);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to set AB8505_RTC_PCUT_MAX_TIME_REG\n");
+
+fail:
+ return count;
+}
+
+static ssize_t ab8505_powercut_restart_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_RESTART_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_RESTART_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_restart_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ int reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ reg_value = simple_strtoul(buf, NULL, 10);
+ if (reg_value > 0xF) {
+ dev_err(dev, "Incorrect parameter, echo 0 - 15 for number of restart\n");
+ goto fail;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_RESTART_REG, (u8)reg_value);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to set AB8505_RTC_PCUT_RESTART_REG\n");
+
+fail:
+ return count;
+
+}
+
+static ssize_t ab8505_powercut_timer_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_TIME_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_TIME_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7F));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_restart_counter_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_RESTART_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_RESTART_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0xF0) >> 4);
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_CTL_STATUS_REG, &reg_value);
+
+ if (ret < 0)
+ goto fail;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x1));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ int reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ reg_value = simple_strtoul(buf, NULL, 10);
+ if (reg_value > 0x1) {
+ dev_err(dev, "Incorrect parameter, echo 0/1 to disable/enable Pcut feature\n");
+ goto fail;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_CTL_STATUS_REG, (u8)reg_value);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to set AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+
+fail:
+ return count;
+}
+
+static ssize_t ab8505_powercut_flag_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_CTL_STATUS_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x10) >> 4));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_debounce_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_DEBOUNCE_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_DEBOUNCE_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (reg_value & 0x7));
+
+fail:
+ return ret;
+}
+
+static ssize_t ab8505_powercut_debounce_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ int reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ reg_value = simple_strtoul(buf, NULL, 10);
+ if (reg_value > 0x7) {
+ dev_err(dev, "Incorrect parameter, echo 0 to 7 for debounce setting\n");
+ goto fail;
+ }
+
+ ret = abx500_set_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_DEBOUNCE_REG, (u8)reg_value);
+
+ if (ret < 0)
+ dev_err(dev, "Failed to set AB8505_RTC_PCUT_DEBOUNCE_REG\n");
+
+fail:
+ return count;
+}
+
+static ssize_t ab8505_powercut_enable_status_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 reg_value;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ ret = abx500_get_register_interruptible(di->dev, AB8500_RTC,
+ AB8505_RTC_PCUT_CTL_STATUS_REG, &reg_value);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG\n");
+ goto fail;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", ((reg_value & 0x20) >> 5));
+
+fail:
+ return ret;
+}
+
+static struct device_attribute ab8505_fg_sysfs_psy_attrs[] = {
+ __ATTR(powercut_flagtime, (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8505_powercut_flagtime_read, ab8505_powercut_flagtime_write),
+ __ATTR(powercut_maxtime, (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8505_powercut_maxtime_read, ab8505_powercut_maxtime_write),
+ __ATTR(powercut_restart_max, (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8505_powercut_restart_read, ab8505_powercut_restart_write),
+ __ATTR(powercut_timer, S_IRUGO, ab8505_powercut_timer_read, NULL),
+ __ATTR(powercut_restart_counter, S_IRUGO,
+ ab8505_powercut_restart_counter_read, NULL),
+ __ATTR(powercut_enable, (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8505_powercut_read, ab8505_powercut_write),
+ __ATTR(powercut_flag, S_IRUGO, ab8505_powercut_flag_read, NULL),
+ __ATTR(powercut_debounce_time, (S_IRUGO | S_IWUSR | S_IWGRP),
+ ab8505_powercut_debounce_read, ab8505_powercut_debounce_write),
+ __ATTR(powercut_enable_status, S_IRUGO,
+ ab8505_powercut_enable_status_read, NULL),
+};
+
+static int ab8500_fg_sysfs_psy_create_attrs(struct device *dev)
+{
+ unsigned int i, j;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+ abx500_get_chip_id(dev->parent) >= AB8500_CUT2P0)
+ || is_ab8540(di->parent)) {
+ for (j = 0; j < ARRAY_SIZE(ab8505_fg_sysfs_psy_attrs); j++)
+ if (device_create_file(dev, &ab8505_fg_sysfs_psy_attrs[j]))
+ goto sysfs_psy_create_attrs_failed_ab8505;
+ }
+ return 0;
+sysfs_psy_create_attrs_failed_ab8505:
+ dev_err(dev, "Failed creating sysfs psy attrs for ab8505.\n");
+ while (j--)
+ device_remove_file(dev, &ab8505_fg_sysfs_psy_attrs[i]);
+
+ return -EIO;
+}
+
+static void ab8500_fg_sysfs_psy_remove_attrs(struct device *dev)
+{
+ unsigned int i;
+ struct power_supply *psy = dev_get_drvdata(dev);
+ struct ab8500_fg *di;
+
+ di = to_ab8500_fg_device_info(psy);
+
+ if (((is_ab8505(di->parent) || is_ab9540(di->parent)) &&
+ abx500_get_chip_id(dev->parent) >= AB8500_CUT2P0)
+ || is_ab8540(di->parent)) {
+ for (i = 0; i < ARRAY_SIZE(ab8505_fg_sysfs_psy_attrs); i++)
+ (void)device_remove_file(dev, &ab8505_fg_sysfs_psy_attrs[i]);
+ }
+}
+
/* Exposure to the sysfs interface <<END>> */
#if defined(CONFIG_PM)
@@ -2607,6 +3068,7 @@ static int ab8500_fg_remove(struct platform_device *pdev)
ab8500_fg_sysfs_exit(di);
flush_scheduled_work();
+ ab8500_fg_sysfs_psy_remove_attrs(di->fg_psy.dev);
power_supply_unregister(&di->fg_psy);
platform_set_drvdata(pdev, NULL);
return ret;
@@ -2772,6 +3234,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
goto free_irq;
}
+ ret = ab8500_fg_sysfs_psy_create_attrs(di->fg_psy.dev);
+ if (ret) {
+ dev_err(di->dev, "failed to create FG psy\n");
+ ab8500_fg_sysfs_exit(di);
+ goto free_irq;
+ }
+
/* Calibrate the fg first time */
di->flags.calibrate = true;
di->calib_state = AB8500_FG_CALIB_INIT;
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index f043c0851a76..9863e423602c 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) ST-Ericsson SA 2012
+ * Copyright (c) 2012 Sony Mobile Communications AB
*
* Charging algorithm driver for abx500 variants
*
@@ -8,11 +9,13 @@
* Johan Palsson <johan.palsson@stericsson.com>
* Karl Komierowski <karl.komierowski@stericsson.com>
* Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Imre Sunyi <imre.sunyi@sonymobile.com>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/hrtimer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -24,8 +27,10 @@
#include <linux/of.h>
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
#include <linux/mfd/abx500/ab8500-bm.h>
+#include <linux/notifier.h>
/* Watchdog kick interval */
#define CHG_WD_INTERVAL (6 * HZ)
@@ -33,6 +38,18 @@
/* End-of-charge criteria counter */
#define EOC_COND_CNT 10
+/* One hour expressed in seconds */
+#define ONE_HOUR_IN_SECONDS 3600
+
+/* Five minutes expressed in seconds */
+#define FIVE_MINUTES_IN_SECONDS 300
+
+/* Plus margin for the low battery threshold */
+#define BAT_PLUS_MARGIN (100)
+
+#define CHARGALG_CURR_STEP_LOW 0
+#define CHARGALG_CURR_STEP_HIGH 100
+
#define to_abx500_chargalg_device_info(x) container_of((x), \
struct abx500_chargalg, chargalg_psy);
@@ -66,6 +83,11 @@ struct abx500_chargalg_suspension_status {
bool usb_suspended;
};
+struct abx500_chargalg_current_step_status {
+ bool curr_step_change;
+ int curr_step;
+};
+
struct abx500_chargalg_battery_data {
int temp;
int volt;
@@ -82,6 +104,7 @@ enum abx500_chargalg_states {
STATE_HW_TEMP_PROTECT_INIT,
STATE_HW_TEMP_PROTECT,
STATE_NORMAL_INIT,
+ STATE_USB_PP_PRE_CHARGE,
STATE_NORMAL,
STATE_WAIT_FOR_RECHARGE_INIT,
STATE_WAIT_FOR_RECHARGE,
@@ -113,6 +136,7 @@ static const char *states[] = {
"HW_TEMP_PROTECT_INIT",
"HW_TEMP_PROTECT",
"NORMAL_INIT",
+ "USB_PP_PRE_CHARGE",
"NORMAL",
"WAIT_FOR_RECHARGE_INIT",
"WAIT_FOR_RECHARGE",
@@ -204,6 +228,8 @@ enum maxim_ret {
* @batt_data: data of the battery
* @susp_status: current charger suspension status
* @bm: Platform specific battery management information
+ * @curr_status: Current step status for over-current protection
+ * @parent: pointer to the struct abx500
* @chargalg_psy: structure that holds the battery properties exposed by
* the charging algorithm
* @events: structure for information about events triggered
@@ -227,6 +253,8 @@ struct abx500_chargalg {
struct abx500_chargalg_charger_info chg_info;
struct abx500_chargalg_battery_data batt_data;
struct abx500_chargalg_suspension_status susp_status;
+ struct ab8500 *parent;
+ struct abx500_chargalg_current_step_status curr_status;
struct abx500_bm_data *bm;
struct power_supply chargalg_psy;
struct ux500_charger *ac_chg;
@@ -236,51 +264,69 @@ struct abx500_chargalg {
struct delayed_work chargalg_periodic_work;
struct delayed_work chargalg_wd_work;
struct work_struct chargalg_work;
- struct timer_list safety_timer;
- struct timer_list maintenance_timer;
+ struct hrtimer safety_timer;
+ struct hrtimer maintenance_timer;
struct kobject chargalg_kobject;
};
+/*External charger prepare notifier*/
+BLOCKING_NOTIFIER_HEAD(charger_notifier_list);
+
/* Main battery properties */
static enum power_supply_property abx500_chargalg_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_HEALTH,
};
+struct abx500_chargalg_sysfs_entry {
+ struct attribute attr;
+ ssize_t (*show)(struct abx500_chargalg *, char *);
+ ssize_t (*store)(struct abx500_chargalg *, const char *, size_t);
+};
+
/**
* abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
- * @data: pointer to the abx500_chargalg structure
+ * @timer: pointer to the hrtimer structure
*
* This function gets called when the safety timer for the charger
* expires
*/
-static void abx500_chargalg_safety_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_safety_timer_expired(struct hrtimer *timer)
{
- struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+ struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+ safety_timer);
dev_err(di->dev, "Safety timer expired\n");
di->events.safety_timer_expired = true;
/* Trigger execution of the algorithm instantly */
queue_work(di->chargalg_wq, &di->chargalg_work);
+
+ return HRTIMER_NORESTART;
}
/**
* abx500_chargalg_maintenance_timer_expired() - Expiration of
* the maintenance timer
- * @i: pointer to the abx500_chargalg structure
+ * @timer: pointer to the timer structure
*
* This function gets called when the maintenence timer
* expires
*/
-static void abx500_chargalg_maintenance_timer_expired(unsigned long data)
+static enum hrtimer_restart
+abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer)
{
- struct abx500_chargalg *di = (struct abx500_chargalg *) data;
+ struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg,
+ maintenance_timer);
+
dev_dbg(di->dev, "Maintenance timer expired\n");
di->events.maintenance_timer_expired = true;
/* Trigger execution of the algorithm instantly */
queue_work(di->chargalg_wq, &di->chargalg_work);
+
+ return HRTIMER_NORESTART;
}
/**
@@ -303,6 +349,30 @@ static void abx500_chargalg_state_to(struct abx500_chargalg *di,
di->charge_state = state;
}
+static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di)
+{
+ switch (di->charge_state) {
+ case STATE_NORMAL:
+ case STATE_MAINTENANCE_A:
+ case STATE_MAINTENANCE_B:
+ break;
+ default:
+ return 0;
+ }
+
+ if (di->chg_info.charger_type & USB_CHG) {
+ return di->usb_chg->ops.check_enable(di->usb_chg,
+ di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
+ } else if ((di->chg_info.charger_type & AC_CHG) &&
+ !(di->ac_chg->external)) {
+ return di->ac_chg->ops.check_enable(di->ac_chg,
+ di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
+ di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
+ }
+ return 0;
+}
+
/**
* abx500_chargalg_check_charger_connection() - Check charger connection change
* @di: pointer to the abx500_chargalg structure
@@ -348,6 +418,22 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
}
/**
+ * abx500_chargalg_check_current_step_status() - Check charging current
+ * step status.
+ * @di: pointer to the abx500_chargalg structure
+ *
+ * This function will check if there is a change in the charging current step
+ * and change charge state accordingly.
+ */
+static void abx500_chargalg_check_current_step_status
+ (struct abx500_chargalg *di)
+{
+ if (di->curr_status.curr_step_change)
+ abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+ di->curr_status.curr_step_change = false;
+}
+
+/**
* abx500_chargalg_start_safety_timer() - Start charging safety timer
* @di: pointer to the abx500_chargalg structure
*
@@ -356,19 +442,16 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
*/
static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
{
- unsigned long timer_expiration = 0;
+ /* Charger-dependent expiration time in hours*/
+ int timer_expiration = 0;
switch (di->chg_info.charger_type) {
case AC_CHG:
- timer_expiration =
- round_jiffies(jiffies +
- (di->bm->main_safety_tmr_h * 3600 * HZ));
+ timer_expiration = di->bm->main_safety_tmr_h;
break;
case USB_CHG:
- timer_expiration =
- round_jiffies(jiffies +
- (di->bm->usb_safety_tmr_h * 3600 * HZ));
+ timer_expiration = di->bm->usb_safety_tmr_h;
break;
default:
@@ -377,11 +460,10 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
}
di->events.safety_timer_expired = false;
- di->safety_timer.expires = timer_expiration;
- if (!timer_pending(&di->safety_timer))
- add_timer(&di->safety_timer);
- else
- mod_timer(&di->safety_timer, timer_expiration);
+ hrtimer_set_expires_range(&di->safety_timer,
+ ktime_set(timer_expiration * ONE_HOUR_IN_SECONDS, 0),
+ ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
+ hrtimer_start_expires(&di->safety_timer, HRTIMER_MODE_REL);
}
/**
@@ -392,8 +474,8 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di)
*/
static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
{
- di->events.safety_timer_expired = false;
- del_timer(&di->safety_timer);
+ if (hrtimer_try_to_cancel(&di->safety_timer) >= 0)
+ di->events.safety_timer_expired = false;
}
/**
@@ -408,17 +490,11 @@ static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di)
static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
int duration)
{
- unsigned long timer_expiration;
-
- /* Convert from hours to jiffies */
- timer_expiration = round_jiffies(jiffies + (duration * 3600 * HZ));
-
+ hrtimer_set_expires_range(&di->maintenance_timer,
+ ktime_set(duration * ONE_HOUR_IN_SECONDS, 0),
+ ktime_set(FIVE_MINUTES_IN_SECONDS, 0));
di->events.maintenance_timer_expired = false;
- di->maintenance_timer.expires = timer_expiration;
- if (!timer_pending(&di->maintenance_timer))
- add_timer(&di->maintenance_timer);
- else
- mod_timer(&di->maintenance_timer, timer_expiration);
+ hrtimer_start_expires(&di->maintenance_timer, HRTIMER_MODE_REL);
}
/**
@@ -430,8 +506,8 @@ static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di,
*/
static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di)
{
- di->events.maintenance_timer_expired = false;
- del_timer(&di->maintenance_timer);
+ if (hrtimer_try_to_cancel(&di->maintenance_timer) >= 0)
+ di->events.maintenance_timer_expired = false;
}
/**
@@ -477,6 +553,8 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di)
static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
int vset, int iset)
{
+ static int abx500_chargalg_ex_ac_enable_toggle;
+
if (!di->ac_chg || !di->ac_chg->ops.enable)
return -ENXIO;
@@ -489,6 +567,14 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable,
di->chg_info.ac_iset = iset;
di->chg_info.ac_vset = vset;
+ /* Enable external charger */
+ if (enable && di->ac_chg->external &&
+ !abx500_chargalg_ex_ac_enable_toggle) {
+ blocking_notifier_call_chain(&charger_notifier_list,
+ 0, di->dev);
+ abx500_chargalg_ex_ac_enable_toggle++;
+ }
+
return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset);
}
@@ -520,6 +606,37 @@ static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable,
return di->usb_chg->ops.enable(di->usb_chg, enable, vset, iset);
}
+ /**
+ * ab8540_chargalg_usb_pp_en() - Enable/ disable USB power path
+ * @di: pointer to the abx500_chargalg structure
+ * @enable: power path enable/disable
+ *
+ * The USB power path will be enable/ disable
+ */
+static int ab8540_chargalg_usb_pp_en(struct abx500_chargalg *di, bool enable)
+{
+ if (!di->usb_chg || !di->usb_chg->ops.pp_enable)
+ return -ENXIO;
+
+ return di->usb_chg->ops.pp_enable(di->usb_chg, enable);
+}
+
+/**
+ * ab8540_chargalg_usb_pre_chg_en() - Enable/ disable USB pre-charge
+ * @di: pointer to the abx500_chargalg structure
+ * @enable: USB pre-charge enable/disable
+ *
+ * The USB USB pre-charge will be enable/ disable
+ */
+static int ab8540_chargalg_usb_pre_chg_en(struct abx500_chargalg *di,
+ bool enable)
+{
+ if (!di->usb_chg || !di->usb_chg->ops.pre_chg_enable)
+ return -ENXIO;
+
+ return di->usb_chg->ops.pre_chg_enable(di->usb_chg, enable);
+}
+
/**
* abx500_chargalg_update_chg_curr() - Update charger current
* @di: pointer to the abx500_chargalg structure
@@ -613,8 +730,6 @@ static void abx500_chargalg_hold_charging(struct abx500_chargalg *di)
static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
int vset, int iset)
{
- bool start_chargalg_wd = true;
-
switch (di->chg_info.charger_type) {
case AC_CHG:
dev_dbg(di->dev,
@@ -632,12 +747,8 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di,
default:
dev_err(di->dev, "Unknown charger to charge from\n");
- start_chargalg_wd = false;
break;
}
-
- if (start_chargalg_wd && !delayed_work_pending(&di->chargalg_wd_work))
- queue_delayed_work(di->chargalg_wq, &di->chargalg_wd_work, 0);
}
/**
@@ -725,6 +836,9 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di)
di->batt_data.avg_curr > 0) {
if (++di->eoc_cnt >= EOC_COND_CNT) {
di->eoc_cnt = 0;
+ if ((di->chg_info.charger_type & USB_CHG) &&
+ (di->usb_chg->power_path))
+ ab8540_chargalg_usb_pp_en(di, true);
di->charge_status = POWER_SUPPLY_STATUS_FULL;
di->maintenance_chg = true;
dev_dbg(di->dev, "EOC reached!\n");
@@ -1217,6 +1331,8 @@ static void abx500_chargalg_external_power_changed(struct power_supply *psy)
static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
{
int charger_status;
+ int ret;
+ int curr_step_lvl;
/* Collect data from all power_supply class devices */
class_for_each_device(power_supply_class, NULL,
@@ -1227,6 +1343,15 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
abx500_chargalg_check_charger_voltage(di);
charger_status = abx500_chargalg_check_charger_connection(di);
+ abx500_chargalg_check_current_step_status(di);
+
+ if (is_ab8500(di->parent)) {
+ ret = abx500_chargalg_check_charger_enable(di);
+ if (ret < 0)
+ dev_err(di->dev, "Checking charger is enabled error"
+ ": Returned Value %d\n", ret);
+ }
+
/*
* First check if we have a charger connected.
* Also we don't allow charging of unknown batteries if configured
@@ -1416,9 +1541,34 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
break;
case STATE_NORMAL_INIT:
- abx500_chargalg_start_charging(di,
- di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
- di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
+ if ((di->chg_info.charger_type & USB_CHG) &&
+ di->usb_chg->power_path) {
+ if (di->batt_data.volt >
+ (di->bm->fg_params->lowbat_threshold +
+ BAT_PLUS_MARGIN)) {
+ ab8540_chargalg_usb_pre_chg_en(di, false);
+ ab8540_chargalg_usb_pp_en(di, false);
+ } else {
+ ab8540_chargalg_usb_pp_en(di, true);
+ ab8540_chargalg_usb_pre_chg_en(di, true);
+ abx500_chargalg_state_to(di,
+ STATE_USB_PP_PRE_CHARGE);
+ break;
+ }
+ }
+
+ if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW)
+ abx500_chargalg_stop_charging(di);
+ else {
+ curr_step_lvl = di->bm->bat_type[
+ di->bm->batt_id].normal_cur_lvl
+ * di->curr_status.curr_step
+ / CHARGALG_CURR_STEP_HIGH;
+ abx500_chargalg_start_charging(di,
+ di->bm->bat_type[di->bm->batt_id]
+ .normal_vol_lvl, curr_step_lvl);
+ }
+
abx500_chargalg_state_to(di, STATE_NORMAL);
abx500_chargalg_start_safety_timer(di);
abx500_chargalg_stop_maintenance_timer(di);
@@ -1430,6 +1580,13 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
break;
+ case STATE_USB_PP_PRE_CHARGE:
+ if (di->batt_data.volt >
+ (di->bm->fg_params->lowbat_threshold +
+ BAT_PLUS_MARGIN))
+ abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
+ break;
+
case STATE_NORMAL:
handle_maxim_chg_curr(di);
if (di->charge_status == POWER_SUPPLY_STATUS_FULL &&
@@ -1653,99 +1810,134 @@ static int abx500_chargalg_get_property(struct power_supply *psy,
/* Exposure to the sysfs interface */
-/**
- * abx500_chargalg_sysfs_show() - sysfs show operations
- * @kobj: pointer to the struct kobject
- * @attr: pointer to the struct attribute
- * @buf: buffer that holds the parameter to send to userspace
- *
- * Returns a buffer to be displayed in user space
- */
-static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+static ssize_t abx500_chargalg_curr_step_show(struct abx500_chargalg *di,
+ char *buf)
{
- struct abx500_chargalg *di = container_of(kobj,
- struct abx500_chargalg, chargalg_kobject);
+ return sprintf(buf, "%d\n", di->curr_status.curr_step);
+}
+
+static ssize_t abx500_chargalg_curr_step_store(struct abx500_chargalg *di,
+ const char *buf, size_t length)
+{
+ long int param;
+ int ret;
+
+ ret = kstrtol(buf, 10, &param);
+ if (ret < 0)
+ return ret;
+
+ di->curr_status.curr_step = param;
+ if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW &&
+ di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) {
+ di->curr_status.curr_step_change = true;
+ queue_work(di->chargalg_wq, &di->chargalg_work);
+ } else
+ dev_info(di->dev, "Wrong current step\n"
+ "Enter 0. Disable AC/USB Charging\n"
+ "1--100. Set AC/USB charging current step\n"
+ "100. Enable AC/USB Charging\n");
+
+ return strlen(buf);
+}
+
+static ssize_t abx500_chargalg_en_show(struct abx500_chargalg *di,
+ char *buf)
+{
return sprintf(buf, "%d\n",
di->susp_status.ac_suspended &&
di->susp_status.usb_suspended);
}
-/**
- * abx500_chargalg_sysfs_charger() - sysfs store operations
- * @kobj: pointer to the struct kobject
- * @attr: pointer to the struct attribute
- * @buf: buffer that holds the parameter passed from userspace
- * @length: length of the parameter passed
- *
- * Returns length of the buffer(input taken from user space) on success
- * else error code on failure
- * The operation to be performed on passing the parameters from the user space.
- */
-static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t length)
+static ssize_t abx500_chargalg_en_store(struct abx500_chargalg *di,
+ const char *buf, size_t length)
{
- struct abx500_chargalg *di = container_of(kobj,
- struct abx500_chargalg, chargalg_kobject);
long int param;
int ac_usb;
int ret;
- char entry = *attr->name;
- switch (entry) {
- case 'c':
- ret = strict_strtol(buf, 10, &param);
- if (ret < 0)
- return ret;
-
- ac_usb = param;
- switch (ac_usb) {
- case 0:
- /* Disable charging */
- di->susp_status.ac_suspended = true;
- di->susp_status.usb_suspended = true;
- di->susp_status.suspended_change = true;
- /* Trigger a state change */
- queue_work(di->chargalg_wq,
- &di->chargalg_work);
- break;
- case 1:
- /* Enable AC Charging */
- di->susp_status.ac_suspended = false;
- di->susp_status.suspended_change = true;
- /* Trigger a state change */
- queue_work(di->chargalg_wq,
- &di->chargalg_work);
- break;
- case 2:
- /* Enable USB charging */
- di->susp_status.usb_suspended = false;
- di->susp_status.suspended_change = true;
- /* Trigger a state change */
- queue_work(di->chargalg_wq,
- &di->chargalg_work);
- break;
- default:
- dev_info(di->dev, "Wrong input\n"
- "Enter 0. Disable AC/USB Charging\n"
- "1. Enable AC charging\n"
- "2. Enable USB Charging\n");
- };
+ ret = kstrtol(buf, 10, &param);
+ if (ret < 0)
+ return ret;
+
+ ac_usb = param;
+ switch (ac_usb) {
+ case 0:
+ /* Disable charging */
+ di->susp_status.ac_suspended = true;
+ di->susp_status.usb_suspended = true;
+ di->susp_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->chargalg_wq,
+ &di->chargalg_work);
+ break;
+ case 1:
+ /* Enable AC Charging */
+ di->susp_status.ac_suspended = false;
+ di->susp_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->chargalg_wq,
+ &di->chargalg_work);
+ break;
+ case 2:
+ /* Enable USB charging */
+ di->susp_status.usb_suspended = false;
+ di->susp_status.suspended_change = true;
+ /* Trigger a state change */
+ queue_work(di->chargalg_wq,
+ &di->chargalg_work);
break;
+ default:
+ dev_info(di->dev, "Wrong input\n"
+ "Enter 0. Disable AC/USB Charging\n"
+ "1. Enable AC charging\n"
+ "2. Enable USB Charging\n");
};
return strlen(buf);
}
-static struct attribute abx500_chargalg_en_charger = \
+static struct abx500_chargalg_sysfs_entry abx500_chargalg_en_charger =
+ __ATTR(chargalg, 0644, abx500_chargalg_en_show,
+ abx500_chargalg_en_store);
+
+static struct abx500_chargalg_sysfs_entry abx500_chargalg_curr_step =
+ __ATTR(chargalg_curr_step, 0644, abx500_chargalg_curr_step_show,
+ abx500_chargalg_curr_step_store);
+
+static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
{
- .name = "chargalg",
- .mode = S_IRUGO | S_IWUSR,
-};
+ struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
+ struct abx500_chargalg_sysfs_entry, attr);
+
+ struct abx500_chargalg *di = container_of(kobj,
+ struct abx500_chargalg, chargalg_kobject);
+
+ if (!entry->show)
+ return -EIO;
+
+ return entry->show(di, buf);
+}
+
+static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t length)
+{
+ struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
+ struct abx500_chargalg_sysfs_entry, attr);
+
+ struct abx500_chargalg *di = container_of(kobj,
+ struct abx500_chargalg, chargalg_kobject);
+
+ if (!entry->store)
+ return -EIO;
+
+ return entry->store(di, buf, length);
+}
static struct attribute *abx500_chargalg_chg[] = {
- &abx500_chargalg_en_charger,
- NULL
+ &abx500_chargalg_en_charger.attr,
+ &abx500_chargalg_curr_step.attr,
+ NULL,
};
static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
@@ -1832,10 +2024,16 @@ static int abx500_chargalg_remove(struct platform_device *pdev)
/* sysfs interface to enable/disbale charging from user space */
abx500_chargalg_sysfs_exit(di);
+ hrtimer_cancel(&di->safety_timer);
+ hrtimer_cancel(&di->maintenance_timer);
+
+ cancel_delayed_work_sync(&di->chargalg_periodic_work);
+ cancel_delayed_work_sync(&di->chargalg_wd_work);
+ cancel_work_sync(&di->chargalg_work);
+
/* Delete the work queue */
destroy_workqueue(di->chargalg_wq);
- flush_scheduled_work();
power_supply_unregister(&di->chargalg_psy);
platform_set_drvdata(pdev, NULL);
@@ -1873,8 +2071,9 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
}
}
- /* get device struct */
+ /* get device struct and parent */
di->dev = &pdev->dev;
+ di->parent = dev_get_drvdata(pdev->dev.parent);
/* chargalg supply */
di->chargalg_psy.name = "abx500_chargalg";
@@ -1888,15 +2087,13 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
abx500_chargalg_external_power_changed;
/* Initilialize safety timer */
- init_timer(&di->safety_timer);
+ hrtimer_init(&di->safety_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
di->safety_timer.function = abx500_chargalg_safety_timer_expired;
- di->safety_timer.data = (unsigned long) di;
/* Initilialize maintenance timer */
- init_timer(&di->maintenance_timer);
+ hrtimer_init(&di->maintenance_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
di->maintenance_timer.function =
abx500_chargalg_maintenance_timer_expired;
- di->maintenance_timer.data = (unsigned long) di;
/* Create a work queue for the chargalg */
di->chargalg_wq =
@@ -1933,6 +2130,7 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
dev_err(di->dev, "failed to create sysfs entry\n");
goto free_psy;
}
+ di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
/* Run the charging algorithm */
queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
@@ -1964,18 +2162,7 @@ static struct platform_driver abx500_chargalg_driver = {
},
};
-static int __init abx500_chargalg_init(void)
-{
- return platform_driver_register(&abx500_chargalg_driver);
-}
-
-static void __exit abx500_chargalg_exit(void)
-{
- platform_driver_unregister(&abx500_chargalg_driver);
-}
-
-module_init(abx500_chargalg_init);
-module_exit(abx500_chargalg_exit);
+module_platform_driver(abx500_chargalg_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Johan Palsson, Karl Komierowski");
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 8acc3f8d303c..fefc39fe42be 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -1485,13 +1485,12 @@ static int charger_manager_probe(struct platform_device *pdev)
/* Basic Values. Unspecified are Null or 0 */
cm->dev = &pdev->dev;
- cm->desc = kzalloc(sizeof(struct charger_desc), GFP_KERNEL);
+ cm->desc = kmemdup(desc, sizeof(struct charger_desc), GFP_KERNEL);
if (!cm->desc) {
dev_err(&pdev->dev, "Cannot allocate memory.\n");
ret = -ENOMEM;
goto err_alloc_desc;
}
- memcpy(cm->desc, desc, sizeof(struct charger_desc));
cm->last_temp_mC = INT_MIN; /* denotes "unmeasured, yet" */
/*
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
index e8c5a391a498..ae6c41835ee6 100644
--- a/drivers/power/da9030_battery.c
+++ b/drivers/power/da9030_battery.c
@@ -505,7 +505,7 @@ static int da9030_battery_probe(struct platform_device *pdev)
pdata->charge_millivolt > 4350)
return -EINVAL;
- charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+ charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
if (charger == NULL)
return -ENOMEM;
@@ -557,8 +557,6 @@ err_notifier:
cancel_delayed_work(&charger->work);
err_charger_init:
- kfree(charger);
-
return ret;
}
@@ -575,8 +573,6 @@ static int da9030_battery_remove(struct platform_device *dev)
da9030_set_charge(charger, 0);
power_supply_unregister(&charger->psy);
- kfree(charger);
-
return 0;
}
diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c
index 08193feb3b08..f8f4c0f7c17d 100644
--- a/drivers/power/da9052-battery.c
+++ b/drivers/power/da9052-battery.c
@@ -594,7 +594,8 @@ static s32 da9052_bat_probe(struct platform_device *pdev)
int ret;
int i;
- bat = kzalloc(sizeof(struct da9052_battery), GFP_KERNEL);
+ bat = devm_kzalloc(&pdev->dev, sizeof(struct da9052_battery),
+ GFP_KERNEL);
if (!bat)
return -ENOMEM;
@@ -635,7 +636,6 @@ err:
while (--i >= 0)
da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat);
- kfree(bat);
return ret;
}
static int da9052_bat_remove(struct platform_device *pdev)
@@ -647,7 +647,6 @@ static int da9052_bat_remove(struct platform_device *pdev)
da9052_free_irq(bat->da9052, da9052_bat_irq_bits[i], bat);
power_supply_unregister(&bat->psy);
- kfree(bat);
return 0;
}
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index 704e652072be..85b4e6eca0b1 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -512,7 +512,7 @@ static int ds2760_battery_probe(struct platform_device *pdev)
int retval = 0;
struct ds2760_device_info *di;
- di = kzalloc(sizeof(*di), GFP_KERNEL);
+ di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
if (!di) {
retval = -ENOMEM;
goto di_alloc_failed;
@@ -576,7 +576,6 @@ static int ds2760_battery_probe(struct platform_device *pdev)
workqueue_failed:
power_supply_unregister(&di->bat);
batt_failed:
- kfree(di);
di_alloc_failed:
success:
return retval;
@@ -590,7 +589,6 @@ static int ds2760_battery_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&di->set_charged_work);
destroy_workqueue(di->monitor_wqueue);
power_supply_unregister(&di->bat);
- kfree(di);
return 0;
}
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
index 8b6c4539e7f4..9f418fa879e5 100644
--- a/drivers/power/ds2780_battery.c
+++ b/drivers/power/ds2780_battery.c
@@ -760,7 +760,7 @@ static int ds2780_battery_probe(struct platform_device *pdev)
int ret = 0;
struct ds2780_device_info *dev_info;
- dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
+ dev_info = devm_kzalloc(&pdev->dev, sizeof(*dev_info), GFP_KERNEL);
if (!dev_info) {
ret = -ENOMEM;
goto fail;
@@ -779,7 +779,7 @@ static int ds2780_battery_probe(struct platform_device *pdev)
ret = power_supply_register(&pdev->dev, &dev_info->bat);
if (ret) {
dev_err(dev_info->dev, "failed to register battery\n");
- goto fail_free_info;
+ goto fail;
}
ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
@@ -813,8 +813,6 @@ fail_remove_group:
sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
fail_unregister:
power_supply_unregister(&dev_info->bat);
-fail_free_info:
- kfree(dev_info);
fail:
return ret;
}
@@ -828,7 +826,6 @@ static int ds2780_battery_remove(struct platform_device *pdev)
power_supply_unregister(&dev_info->bat);
- kfree(dev_info);
return 0;
}
diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c
index c09e7726c96c..563174891c90 100644
--- a/drivers/power/ds2782_battery.c
+++ b/drivers/power/ds2782_battery.c
@@ -332,32 +332,32 @@ static int ds278x_battery_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int ds278x_suspend(struct i2c_client *client,
- pm_message_t state)
+static int ds278x_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ds278x_info *info = i2c_get_clientdata(client);
cancel_delayed_work(&info->bat_work);
return 0;
}
-static int ds278x_resume(struct i2c_client *client)
+static int ds278x_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct ds278x_info *info = i2c_get_clientdata(client);
schedule_delayed_work(&info->bat_work, DS278x_DELAY);
return 0;
}
-#else
-
-#define ds278x_suspend NULL
-#define ds278x_resume NULL
-
-#endif /* CONFIG_PM */
+static SIMPLE_DEV_PM_OPS(ds278x_battery_pm_ops, ds278x_suspend, ds278x_resume);
+#define DS278X_BATTERY_PM_OPS (&ds278x_battery_pm_ops)
+#else
+#define DS278X_BATTERY_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
enum ds278x_num_id {
DS2782 = 0,
@@ -460,11 +460,10 @@ MODULE_DEVICE_TABLE(i2c, ds278x_id);
static struct i2c_driver ds278x_battery_driver = {
.driver = {
.name = "ds2782-battery",
+ .pm = DS278X_BATTERY_PM_OPS,
},
.probe = ds278x_battery_probe,
.remove = ds278x_battery_remove,
- .suspend = ds278x_suspend,
- .resume = ds278x_resume,
.id_table = ds278x_id,
};
module_i2c_driver(ds278x_battery_driver);
diff --git a/drivers/power/goldfish_battery.c b/drivers/power/goldfish_battery.c
index c10f460f986f..29eba88a2963 100644
--- a/drivers/power/goldfish_battery.c
+++ b/drivers/power/goldfish_battery.c
@@ -178,7 +178,7 @@ static int goldfish_battery_probe(struct platform_device *pdev)
return -ENODEV;
}
- data->reg_base = devm_ioremap(&pdev->dev, r->start, r->end - r->start + 1);
+ data->reg_base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (data->reg_base == NULL) {
dev_err(&pdev->dev, "unable to remap MMIO\n");
return -ENOMEM;
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
index e3e40a9f3af2..e9883eeeee76 100644
--- a/drivers/power/gpio-charger.c
+++ b/drivers/power/gpio-charger.c
@@ -86,7 +86,8 @@ static int gpio_charger_probe(struct platform_device *pdev)
return -EINVAL;
}
- gpio_charger = kzalloc(sizeof(*gpio_charger), GFP_KERNEL);
+ gpio_charger = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger),
+ GFP_KERNEL);
if (!gpio_charger) {
dev_err(&pdev->dev, "Failed to alloc driver structure\n");
return -ENOMEM;
@@ -140,7 +141,6 @@ static int gpio_charger_probe(struct platform_device *pdev)
err_gpio_free:
gpio_free(pdata->gpio);
err_free:
- kfree(gpio_charger);
return ret;
}
@@ -156,7 +156,6 @@ static int gpio_charger_remove(struct platform_device *pdev)
gpio_free(gpio_charger->pdata->gpio);
platform_set_drvdata(pdev, NULL);
- kfree(gpio_charger);
return 0;
}
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 176ad59d99f5..fc04d191579b 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -411,7 +411,7 @@ static int isp1704_charger_probe(struct platform_device *pdev)
struct isp1704_charger *isp;
int ret = -ENODEV;
- isp = kzalloc(sizeof *isp, GFP_KERNEL);
+ isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL);
if (!isp)
return -ENOMEM;
@@ -477,8 +477,6 @@ fail1:
isp1704_charger_set_power(isp, 0);
usb_put_phy(isp->phy);
fail0:
- kfree(isp);
-
dev_err(&pdev->dev, "failed to register isp1704 with error %d\n", ret);
return ret;
@@ -492,7 +490,6 @@ static int isp1704_charger_remove(struct platform_device *pdev)
power_supply_unregister(&isp->psy);
usb_put_phy(isp->phy);
isp1704_charger_set_power(isp, 0);
- kfree(isp);
return 0;
}
diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c
index 6d1f452810b8..ed49b50b220b 100644
--- a/drivers/power/lp8788-charger.c
+++ b/drivers/power/lp8788-charger.c
@@ -49,7 +49,6 @@
#define LP8788_CHG_START 0x11
#define LP8788_CHG_END 0x1C
-#define LP8788_BUF_SIZE 40
#define LP8788_ISEL_MAX 23
#define LP8788_ISEL_STEP 50
#define LP8788_VTERM_MIN 4100
@@ -633,7 +632,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev,
lp8788_read_byte(pchg->lp, LP8788_CHG_STATUS, &data);
state = (data & LP8788_CHG_STATE_M) >> LP8788_CHG_STATE_S;
- return scnprintf(buf, LP8788_BUF_SIZE, "%s\n", desc[state]);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", desc[state]);
}
static ssize_t lp8788_show_eoc_time(struct device *dev,
@@ -647,7 +646,7 @@ static ssize_t lp8788_show_eoc_time(struct device *dev,
lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
val = (val & LP8788_CHG_EOC_TIME_M) >> LP8788_CHG_EOC_TIME_S;
- return scnprintf(buf, LP8788_BUF_SIZE, "End Of Charge Time: %s\n",
+ return scnprintf(buf, PAGE_SIZE, "End Of Charge Time: %s\n",
stime[val]);
}
@@ -667,8 +666,7 @@ static ssize_t lp8788_show_eoc_level(struct device *dev,
val = (val & LP8788_CHG_EOC_LEVEL_M) >> LP8788_CHG_EOC_LEVEL_S;
level = mode ? abs_level[val] : relative_level[val];
- return scnprintf(buf, LP8788_BUF_SIZE, "End Of Charge Level: %s\n",
- level);
+ return scnprintf(buf, PAGE_SIZE, "End Of Charge Level: %s\n", level);
}
static DEVICE_ATTR(charger_status, S_IRUSR, lp8788_show_charger_status, NULL);
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index 74a0bd9bc162..c7ff6d67f158 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -246,31 +246,34 @@ static int max17040_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int max17040_suspend(struct i2c_client *client,
- pm_message_t state)
+static int max17040_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct max17040_chip *chip = i2c_get_clientdata(client);
cancel_delayed_work(&chip->work);
return 0;
}
-static int max17040_resume(struct i2c_client *client)
+static int max17040_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct max17040_chip *chip = i2c_get_clientdata(client);
schedule_delayed_work(&chip->work, MAX17040_DELAY);
return 0;
}
+static SIMPLE_DEV_PM_OPS(max17040_pm_ops, max17040_suspend, max17040_resume);
+#define MAX17040_PM_OPS (&max17040_pm_ops)
+
#else
-#define max17040_suspend NULL
-#define max17040_resume NULL
+#define MAX17040_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static const struct i2c_device_id max17040_id[] = {
{ "max17040", 0 },
@@ -281,11 +284,10 @@ MODULE_DEVICE_TABLE(i2c, max17040_id);
static struct i2c_driver max17040_i2c_driver = {
.driver = {
.name = "max17040",
+ .pm = MAX17040_PM_OPS,
},
.probe = max17040_probe,
.remove = max17040_remove,
- .suspend = max17040_suspend,
- .resume = max17040_resume,
.id_table = max17040_id,
};
module_i2c_driver(max17040_i2c_driver);
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c
index 14e2b96d93b0..08f0d7909b6b 100644
--- a/drivers/power/max8903_charger.c
+++ b/drivers/power/max8903_charger.c
@@ -189,7 +189,7 @@ static int max8903_probe(struct platform_device *pdev)
int ta_in = 0;
int usb_in = 0;
- data = kzalloc(sizeof(struct max8903_data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(struct max8903_data), GFP_KERNEL);
if (data == NULL) {
dev_err(dev, "Cannot allocate memory.\n");
return -ENOMEM;
@@ -341,7 +341,6 @@ err_dc_irq:
err_psy:
power_supply_unregister(&data->psy);
err:
- kfree(data);
return ret;
}
@@ -359,7 +358,6 @@ static int max8903_remove(struct platform_device *pdev)
if (pdata->dc_valid)
free_irq(gpio_to_irq(pdata->dok), data);
power_supply_unregister(&data->psy);
- kfree(data);
}
return 0;
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
index 665cdc76c265..0ee1e14f76e9 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/max8925_power.c
@@ -489,7 +489,8 @@ static int max8925_power_probe(struct platform_device *pdev)
return -EINVAL;
}
- info = kzalloc(sizeof(struct max8925_power_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_power_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
info->chip = chip;
@@ -546,7 +547,6 @@ out_battery:
out_usb:
power_supply_unregister(&info->ac);
out:
- kfree(info);
return ret;
}
@@ -559,7 +559,6 @@ static int max8925_power_remove(struct platform_device *pdev)
power_supply_unregister(&info->usb);
power_supply_unregister(&info->battery);
max8925_deinit_charger(info);
- kfree(info);
}
return 0;
}
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c
index e757885b620c..4bdedfed936d 100644
--- a/drivers/power/max8997_charger.c
+++ b/drivers/power/max8997_charger.c
@@ -138,7 +138,8 @@ static int max8997_battery_probe(struct platform_device *pdev)
return ret;
}
- charger = kzalloc(sizeof(struct charger_data), GFP_KERNEL);
+ charger = devm_kzalloc(&pdev->dev, sizeof(struct charger_data),
+ GFP_KERNEL);
if (charger == NULL) {
dev_err(&pdev->dev, "Cannot allocate memory.\n");
return -ENOMEM;
@@ -158,13 +159,10 @@ static int max8997_battery_probe(struct platform_device *pdev)
ret = power_supply_register(&pdev->dev, &charger->battery);
if (ret) {
dev_err(&pdev->dev, "failed: power supply register\n");
- goto err;
+ return ret;
}
return 0;
-err:
- kfree(charger);
- return ret;
}
static int max8997_battery_remove(struct platform_device *pdev)
@@ -172,7 +170,6 @@ static int max8997_battery_remove(struct platform_device *pdev)
struct charger_data *charger = platform_get_drvdata(pdev);
power_supply_unregister(&charger->battery);
- kfree(charger);
return 0;
}
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
index bf677e3daec9..5017470c2fc9 100644
--- a/drivers/power/max8998_charger.c
+++ b/drivers/power/max8998_charger.c
@@ -88,7 +88,8 @@ static int max8998_battery_probe(struct platform_device *pdev)
return -ENODEV;
}
- max8998 = kzalloc(sizeof(struct max8998_battery_data), GFP_KERNEL);
+ max8998 = devm_kzalloc(&pdev->dev, sizeof(struct max8998_battery_data),
+ GFP_KERNEL);
if (!max8998)
return -ENOMEM;
@@ -174,7 +175,6 @@ static int max8998_battery_probe(struct platform_device *pdev)
return 0;
err:
- kfree(max8998);
return ret;
}
@@ -183,7 +183,6 @@ static int max8998_battery_remove(struct platform_device *pdev)
struct max8998_battery_data *max8998 = platform_get_drvdata(pdev);
power_supply_unregister(&max8998->battery);
- kfree(max8998);
return 0;
}
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
index c2122a7ad065..17fd77f24b2a 100644
--- a/drivers/power/pcf50633-charger.c
+++ b/drivers/power/pcf50633-charger.c
@@ -373,7 +373,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
int i;
u8 mbcs1;
- mbc = kzalloc(sizeof(*mbc), GFP_KERNEL);
+ mbc = devm_kzalloc(&pdev->dev, sizeof(*mbc), GFP_KERNEL);
if (!mbc)
return -ENOMEM;
@@ -413,7 +413,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
ret = power_supply_register(&pdev->dev, &mbc->adapter);
if (ret) {
dev_err(mbc->pcf->dev, "failed to register adapter\n");
- kfree(mbc);
return ret;
}
@@ -421,7 +420,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
if (ret) {
dev_err(mbc->pcf->dev, "failed to register usb\n");
power_supply_unregister(&mbc->adapter);
- kfree(mbc);
return ret;
}
@@ -430,7 +428,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev)
dev_err(mbc->pcf->dev, "failed to register ac\n");
power_supply_unregister(&mbc->adapter);
power_supply_unregister(&mbc->usb);
- kfree(mbc);
return ret;
}
@@ -461,8 +458,6 @@ static int pcf50633_mbc_remove(struct platform_device *pdev)
power_supply_unregister(&mbc->adapter);
power_supply_unregister(&mbc->ac);
- kfree(mbc);
-
return 0;
}
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index 7df7c5facc10..0c52e2a0d90c 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -35,7 +35,7 @@ static struct timer_list supply_timer;
static struct timer_list polling_timer;
static int polling;
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
static struct usb_phy *transceiver;
static struct notifier_block otg_nb;
#endif
@@ -218,7 +218,7 @@ static void polling_timer_func(unsigned long unused)
jiffies + msecs_to_jiffies(pdata->polling_interval));
}
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
static int otg_is_usb_online(void)
{
return (transceiver->last_event == USB_EVENT_VBUS ||
@@ -315,7 +315,7 @@ static int pda_power_probe(struct platform_device *pdev)
pda_psy_usb.num_supplicants = pdata->num_supplicants;
}
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(transceiver)) {
if (!pdata->is_usb_online)
@@ -367,7 +367,7 @@ static int pda_power_probe(struct platform_device *pdev)
}
}
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver) && pdata->use_otg_notifier) {
otg_nb.notifier_call = otg_handle_notification;
ret = usb_register_notifier(transceiver, &otg_nb);
@@ -391,7 +391,7 @@ static int pda_power_probe(struct platform_device *pdev)
return 0;
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
otg_reg_notifier_failed:
if (pdata->is_usb_online && usb_irq)
free_irq(usb_irq->start, &pda_psy_usb);
@@ -402,7 +402,7 @@ usb_irq_failed:
usb_supply_failed:
if (pdata->is_ac_online && ac_irq)
free_irq(ac_irq->start, &pda_psy_ac);
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver))
usb_put_phy(transceiver);
#endif
@@ -437,7 +437,7 @@ static int pda_power_remove(struct platform_device *pdev)
power_supply_unregister(&pda_psy_usb);
if (pdata->is_ac_online)
power_supply_unregister(&pda_psy_ac);
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
if (!IS_ERR_OR_NULL(transceiver))
usb_put_phy(transceiver);
#endif
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
index ed48d75bb786..a44175139bbf 100644
--- a/drivers/power/pm2301_charger.c
+++ b/drivers/power/pm2301_charger.c
@@ -16,24 +16,25 @@
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
-#include <linux/completion.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
-#include <linux/kobject.h>
-#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
-#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
#include <linux/pm2301_charger.h>
#include <linux/gpio.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm.h>
#include "pm2301_charger.h"
#define to_pm2xxx_charger_ac_device_info(x) container_of((x), \
struct pm2xxx_charger, ac_chg)
+#define SLEEP_MIN 50
+#define SLEEP_MAX 100
+#define PM2XXX_AUTOSUSPEND_DELAY 500
static int pm2xxx_interrupt_registers[] = {
PM2XXX_REG_INT1,
@@ -113,33 +114,24 @@ static const struct i2c_device_id pm2xxx_ident[] = {
static void set_lpn_pin(struct pm2xxx_charger *pm2)
{
- if (pm2->ac.charger_connected)
- return;
- gpio_set_value(pm2->lpn_pin, 1);
-
- return;
+ if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin)) {
+ gpio_set_value(pm2->lpn_pin, 1);
+ usleep_range(SLEEP_MIN, SLEEP_MAX);
+ }
}
static void clear_lpn_pin(struct pm2xxx_charger *pm2)
{
- if (pm2->ac.charger_connected)
- return;
- gpio_set_value(pm2->lpn_pin, 0);
-
- return;
+ if (!pm2->ac.charger_connected && gpio_is_valid(pm2->lpn_pin))
+ gpio_set_value(pm2->lpn_pin, 0);
}
static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
{
int ret;
- /*
- * When AC adaptor is unplugged, the host
- * must put LPN high to be able to
- * communicate by I2C with PM2301
- * and receive I2C "acknowledge" from PM2301.
- */
- mutex_lock(&pm2->lock);
- set_lpn_pin(pm2);
+
+ /* wake up the device */
+ pm_runtime_get_sync(pm2->dev);
ret = i2c_smbus_read_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
1, val);
@@ -147,8 +139,8 @@ static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
dev_err(pm2->dev, "Error reading register at 0x%x\n", reg);
else
ret = 0;
- clear_lpn_pin(pm2);
- mutex_unlock(&pm2->lock);
+
+ pm_runtime_put_sync(pm2->dev);
return ret;
}
@@ -156,14 +148,9 @@ static int pm2xxx_reg_read(struct pm2xxx_charger *pm2, int reg, u8 *val)
static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
{
int ret;
- /*
- * When AC adaptor is unplugged, the host
- * must put LPN high to be able to
- * communicate by I2C with PM2301
- * and receive I2C "acknowledge" from PM2301.
- */
- mutex_lock(&pm2->lock);
- set_lpn_pin(pm2);
+
+ /* wake up the device */
+ pm_runtime_get_sync(pm2->dev);
ret = i2c_smbus_write_i2c_block_data(pm2->config.pm2xxx_i2c, reg,
1, &val);
@@ -171,8 +158,8 @@ static int pm2xxx_reg_write(struct pm2xxx_charger *pm2, int reg, u8 val)
dev_err(pm2->dev, "Error writing register at 0x%x\n", reg);
else
ret = 0;
- clear_lpn_pin(pm2);
- mutex_unlock(&pm2->lock);
+
+ pm_runtime_put_sync(pm2->dev);
return ret;
}
@@ -192,11 +179,22 @@ static int pm2xxx_charging_disable_mngt(struct pm2xxx_charger *pm2)
{
int ret;
+ /* Disable SW EOC ctrl */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG, PM2XXX_SWCTRL_HW);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ return ret;
+ }
+
/* Disable charging */
ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG2,
(PM2XXX_CH_AUTO_RESUME_DIS | PM2XXX_CHARGER_DIS));
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ return ret;
+ }
- return ret;
+ return 0;
}
static int pm2xxx_charger_batt_therm_mngt(struct pm2xxx_charger *pm2, int val)
@@ -216,26 +214,19 @@ int pm2xxx_charger_die_therm_mngt(struct pm2xxx_charger *pm2, int val)
static int pm2xxx_charger_ovv_mngt(struct pm2xxx_charger *pm2, int val)
{
- int ret = 0;
+ dev_err(pm2->dev, "Overvoltage detected\n");
+ pm2->flags.ovv = true;
+ power_supply_changed(&pm2->ac_chg.psy);
- pm2->failure_input_ovv++;
- if (pm2->failure_input_ovv < 4) {
- ret = pm2xxx_charging_enable_mngt(pm2);
- goto out;
- } else {
- pm2->failure_input_ovv = 0;
- dev_err(pm2->dev, "Overvoltage detected\n");
- pm2->flags.ovv = true;
- power_supply_changed(&pm2->ac_chg.psy);
- }
+ /* Schedule a new HW failure check */
+ queue_delayed_work(pm2->charger_wq, &pm2->check_hw_failure_work, 0);
-out:
- return ret;
+ return 0;
}
static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
{
- dev_dbg(pm2->dev , "20 minutes watchdog occured\n");
+ dev_dbg(pm2->dev , "20 minutes watchdog expired\n");
pm2->ac.wd_expired = true;
power_supply_changed(&pm2->ac_chg.psy);
@@ -245,13 +236,29 @@ static int pm2xxx_charger_wd_exp_mngt(struct pm2xxx_charger *pm2, int val)
static int pm2xxx_charger_vbat_lsig_mngt(struct pm2xxx_charger *pm2, int val)
{
+ int ret;
+
switch (val) {
case PM2XXX_INT1_ITVBATLOWR:
dev_dbg(pm2->dev, "VBAT grows above VBAT_LOW level\n");
+ /* Enable SW EOC ctrl */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
+ PM2XXX_SWCTRL_SW);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ return ret;
+ }
break;
case PM2XXX_INT1_ITVBATLOWF:
dev_dbg(pm2->dev, "VBAT drops below VBAT_LOW level\n");
+ /* Disable SW EOC ctrl */
+ ret = pm2xxx_reg_write(pm2, PM2XXX_SW_CTRL_REG,
+ PM2XXX_SWCTRL_HW);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
+ return ret;
+ }
break;
default:
@@ -322,16 +329,27 @@ static int pm2_int_reg0(void *pm2_data, int val)
struct pm2xxx_charger *pm2 = pm2_data;
int ret = 0;
- if (val & (PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF)) {
- ret = pm2xxx_charger_vbat_lsig_mngt(pm2, val &
- (PM2XXX_INT1_ITVBATLOWR | PM2XXX_INT1_ITVBATLOWF));
+ if (val & PM2XXX_INT1_ITVBATLOWR) {
+ ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
+ PM2XXX_INT1_ITVBATLOWR);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (val & PM2XXX_INT1_ITVBATLOWF) {
+ ret = pm2xxx_charger_vbat_lsig_mngt(pm2,
+ PM2XXX_INT1_ITVBATLOWF);
+ if (ret < 0)
+ goto out;
}
if (val & PM2XXX_INT1_ITVBATDISCONNECT) {
ret = pm2xxx_charger_bat_disc_mngt(pm2,
PM2XXX_INT1_ITVBATDISCONNECT);
+ if (ret < 0)
+ goto out;
}
-
+out:
return ret;
}
@@ -447,7 +465,6 @@ static int pm2_int_reg5(void *pm2_data, int val)
struct pm2xxx_charger *pm2 = pm2_data;
int ret = 0;
-
if (val & (PM2XXX_INT6_ITVPWR2DROP | PM2XXX_INT6_ITVPWR1DROP)) {
dev_dbg(pm2->dev, "VMPWR drop to VBAT level\n");
}
@@ -468,14 +485,22 @@ static irqreturn_t pm2xxx_irq_int(int irq, void *data)
struct pm2xxx_interrupts *interrupt = pm2->pm2_int;
int i;
- for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
- pm2xxx_reg_read(pm2,
+ /* wake up the device */
+ pm_runtime_get_sync(pm2->dev);
+
+ do {
+ for (i = 0; i < PM2XXX_NUM_INT_REG; i++) {
+ pm2xxx_reg_read(pm2,
pm2xxx_interrupt_registers[i],
&(interrupt->reg[i]));
- if (interrupt->reg[i] > 0)
- interrupt->handler[i](pm2, interrupt->reg[i]);
- }
+ if (interrupt->reg[i] > 0)
+ interrupt->handler[i](pm2, interrupt->reg[i]);
+ }
+ } while (gpio_get_value(pm2->pdata->gpio_irq_number) == 0);
+
+ pm_runtime_mark_last_busy(pm2->dev);
+ pm_runtime_put_autosuspend(pm2->dev);
return IRQ_HANDLED;
}
@@ -592,6 +617,8 @@ static int pm2xxx_charger_ac_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_HEALTH_DEAD;
else if (pm2->flags.main_thermal_prot)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (pm2->flags.ovv)
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
else
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
@@ -674,10 +701,6 @@ static int pm2xxx_charging_init(struct pm2xxx_charger *pm2)
ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_LOW_LEV_COMP_REG,
PM2XXX_VBAT_LOW_MONITORING_ENA);
- /* Disable LED */
- ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG,
- PM2XXX_LED_SELECT_DIS);
-
return ret;
}
@@ -822,10 +845,54 @@ static void pm2xxx_charger_ac_work(struct work_struct *work)
sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
};
+static void pm2xxx_charger_check_hw_failure_work(struct work_struct *work)
+{
+ u8 reg_value;
+
+ struct pm2xxx_charger *pm2 = container_of(work,
+ struct pm2xxx_charger, check_hw_failure_work.work);
+
+ if (pm2->flags.ovv) {
+ pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT4, &reg_value);
+
+ if (!(reg_value & (PM2XXX_INT4_S_ITVPWR1OVV |
+ PM2XXX_INT4_S_ITVPWR2OVV))) {
+ pm2->flags.ovv = false;
+ power_supply_changed(&pm2->ac_chg.psy);
+ }
+ }
+
+ /* If we still have a failure, schedule a new check */
+ if (pm2->flags.ovv) {
+ queue_delayed_work(pm2->charger_wq,
+ &pm2->check_hw_failure_work, round_jiffies(HZ));
+ }
+}
+
static void pm2xxx_charger_check_main_thermal_prot_work(
struct work_struct *work)
{
-};
+ int ret;
+ u8 val;
+
+ struct pm2xxx_charger *pm2 = container_of(work, struct pm2xxx_charger,
+ check_main_thermal_prot_work);
+
+ /* Check if die temp warning is still active */
+ ret = pm2xxx_reg_read(pm2, PM2XXX_SRCE_REG_INT5, &val);
+ if (ret < 0) {
+ dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
+ return;
+ }
+ if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGRISE
+ | PM2XXX_INT5_S_ITTHERMALSHUTDOWNRISE))
+ pm2->flags.main_thermal_prot = true;
+ else if (val & (PM2XXX_INT5_S_ITTHERMALWARNINGFALL
+ | PM2XXX_INT5_S_ITTHERMALSHUTDOWNFALL))
+ pm2->flags.main_thermal_prot = false;
+
+ power_supply_changed(&pm2->ac_chg.psy);
+}
static struct pm2xxx_interrupts pm2xxx_int = {
.handler[0] = pm2_int_reg0,
@@ -840,24 +907,105 @@ static struct pm2xxx_irq pm2xxx_charger_irq[] = {
{"PM2XXX_IRQ_INT", pm2xxx_irq_int},
};
-static int pm2xxx_wall_charger_resume(struct i2c_client *i2c_client)
+#ifdef CONFIG_PM
+
+#ifdef CONFIG_PM_SLEEP
+
+static int pm2xxx_wall_charger_resume(struct device *dev)
{
+ struct i2c_client *i2c_client = to_i2c_client(dev);
+ struct pm2xxx_charger *pm2;
+
+ pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
+ set_lpn_pin(pm2);
+
+ /* If we still have a HW failure, schedule a new check */
+ if (pm2->flags.ovv)
+ queue_delayed_work(pm2->charger_wq,
+ &pm2->check_hw_failure_work, 0);
+
return 0;
}
-static int pm2xxx_wall_charger_suspend(struct i2c_client *i2c_client,
- pm_message_t state)
+static int pm2xxx_wall_charger_suspend(struct device *dev)
{
+ struct i2c_client *i2c_client = to_i2c_client(dev);
+ struct pm2xxx_charger *pm2;
+
+ pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(i2c_client);
+ clear_lpn_pin(pm2);
+
+ /* Cancel any pending HW failure check */
+ if (delayed_work_pending(&pm2->check_hw_failure_work))
+ cancel_delayed_work(&pm2->check_hw_failure_work);
+
+ flush_work(&pm2->ac_work);
+ flush_work(&pm2->check_main_thermal_prot_work);
+
return 0;
}
-static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int pm2xxx_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
+ struct pm2xxx_charger *pm2;
+ int ret = 0;
+
+ pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
+ if (!pm2) {
+ dev_err(pm2->dev, "no pm2xxx_charger data supplied\n");
+ ret = -EINVAL;
+ return ret;
+ }
+
+ clear_lpn_pin(pm2);
+
+ return ret;
+}
+
+static int pm2xxx_runtime_resume(struct device *dev)
+{
+ struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
+ struct pm2xxx_charger *pm2;
+ int ret = 0;
+
+ pm2 = (struct pm2xxx_charger *)i2c_get_clientdata(pm2xxx_i2c_client);
+ if (!pm2) {
+ dev_err(pm2->dev, "no pm2xxx_charger data supplied\n");
+ ret = -EINVAL;
+ return ret;
+ }
+
+ if (gpio_is_valid(pm2->lpn_pin) && gpio_get_value(pm2->lpn_pin) == 0)
+ set_lpn_pin(pm2);
+
+ return ret;
+}
+
+#endif
+
+static const struct dev_pm_ops pm2xxx_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend,
+ pm2xxx_wall_charger_resume)
+ SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL)
+};
+#define PM2XXX_PM_OPS (&pm2xxx_pm_ops)
+#else
+#define PM2XXX_PM_OPS NULL
+#endif
+
+static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
struct pm2xxx_charger *pm2;
int ret = 0;
u8 val;
+ int i;
pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
if (!pm2) {
@@ -867,7 +1015,6 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
/* get parent data */
pm2->dev = &i2c_client->dev;
- pm2->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
pm2->pm2_int = &pm2xxx_int;
@@ -889,14 +1036,6 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
pm2->bat = pl_data->battery;
- /*get lpn GPIO from platform data*/
- if (!pm2->pdata->lpn_gpio) {
- dev_err(pm2->dev, "no lpn gpio data supplied\n");
- ret = -EINVAL;
- goto free_device_info;
- }
- pm2->lpn_pin = pm2->pdata->lpn_gpio;
-
if (!i2c_check_functionality(i2c_client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA)) {
@@ -945,6 +1084,10 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
INIT_WORK(&pm2->check_main_thermal_prot_work,
pm2xxx_charger_check_main_thermal_prot_work);
+ /* Init work for HW failure check */
+ INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work,
+ pm2xxx_charger_check_hw_failure_work);
+
/*
* VDD ADC supply needs to be enabled from this driver when there
* is a charger connected to avoid erroneous BTEMP_HIGH/LOW
@@ -965,40 +1108,72 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
}
/* Register interrupts */
- ret = request_threaded_irq(pm2->pdata->irq_number, NULL,
+ ret = request_threaded_irq(gpio_to_irq(pm2->pdata->gpio_irq_number),
+ NULL,
pm2xxx_charger_irq[0].isr,
pm2->pdata->irq_type,
pm2xxx_charger_irq[0].name, pm2);
if (ret != 0) {
dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
- pm2xxx_charger_irq[0].name, pm2->pdata->irq_number, ret);
+ pm2xxx_charger_irq[0].name,
+ gpio_to_irq(pm2->pdata->gpio_irq_number), ret);
goto unregister_pm2xxx_charger;
}
- /*Initialize lock*/
- mutex_init(&pm2->lock);
+ ret = pm_runtime_set_active(pm2->dev);
+ if (ret)
+ dev_err(pm2->dev, "set active Error\n");
- /*
- * Charger detection mechanism requires pulling up the LPN pin
- * while i2c communication if Charger is not connected
- * LPN pin of PM2301 is GPIO60 of AB9540
- */
- ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
- if (ret < 0) {
- dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
- goto unregister_pm2xxx_charger;
+ pm_runtime_enable(pm2->dev);
+ pm_runtime_set_autosuspend_delay(pm2->dev, PM2XXX_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(pm2->dev);
+ pm_runtime_resume(pm2->dev);
+
+ /* pm interrupt can wake up system */
+ ret = enable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
+ if (ret) {
+ dev_err(pm2->dev, "failed to set irq wake\n");
+ goto unregister_pm2xxx_interrupt;
}
- ret = gpio_direction_output(pm2->lpn_pin, 0);
- if (ret < 0) {
- dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
- goto free_gpio;
+
+ mutex_init(&pm2->lock);
+
+ if (gpio_is_valid(pm2->pdata->lpn_gpio)) {
+ /* get lpn GPIO from platform data */
+ pm2->lpn_pin = pm2->pdata->lpn_gpio;
+
+ /*
+ * Charger detection mechanism requires pulling up the LPN pin
+ * while i2c communication if Charger is not connected
+ * LPN pin of PM2301 is GPIO60 of AB9540
+ */
+ ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");
+
+ if (ret < 0) {
+ dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
+ goto disable_pm2_irq_wake;
+ }
+ ret = gpio_direction_output(pm2->lpn_pin, 0);
+ if (ret < 0) {
+ dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
+ goto free_gpio;
+ }
+ set_lpn_pin(pm2);
}
+ /* read interrupt registers */
+ for (i = 0; i < PM2XXX_NUM_INT_REG; i++)
+ pm2xxx_reg_read(pm2,
+ pm2xxx_interrupt_registers[i],
+ &val);
+
ret = pm2xxx_charger_detection(pm2, &val);
if ((ret == 0) && val) {
pm2->ac.charger_connected = 1;
+ ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
+ AB8500_MAIN_CH_DET);
pm2->ac_conn = true;
power_supply_changed(&pm2->ac_chg.psy);
sysfs_notify(&pm2->ac_chg.psy.dev->kobj, NULL, "present");
@@ -1007,7 +1182,13 @@ static int __devinit pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
return 0;
free_gpio:
- gpio_free(pm2->lpn_pin);
+ if (gpio_is_valid(pm2->lpn_pin))
+ gpio_free(pm2->lpn_pin);
+disable_pm2_irq_wake:
+ disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
+unregister_pm2xxx_interrupt:
+ /* disable interrupt */
+ free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
unregister_pm2xxx_charger:
/* unregister power supply */
power_supply_unregister(&pm2->ac_chg.psy);
@@ -1018,18 +1199,24 @@ free_charger_wq:
destroy_workqueue(pm2->charger_wq);
free_device_info:
kfree(pm2);
+
return ret;
}
-static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
+static int pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
{
struct pm2xxx_charger *pm2 = i2c_get_clientdata(i2c_client);
+ /* Disable pm_runtime */
+ pm_runtime_disable(pm2->dev);
/* Disable AC charging */
pm2xxx_charger_ac_en(&pm2->ac_chg, false, 0, 0);
+ /* Disable wake by pm interrupt */
+ disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
+
/* Disable interrupts */
- free_irq(pm2->pdata->irq_number, pm2);
+ free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
/* Delete the work queue */
destroy_workqueue(pm2->charger_wq);
@@ -1041,8 +1228,8 @@ static int __devexit pm2xxx_wall_charger_remove(struct i2c_client *i2c_client)
power_supply_unregister(&pm2->ac_chg.psy);
- /*Free GPIO60*/
- gpio_free(pm2->lpn_pin);
+ if (gpio_is_valid(pm2->lpn_pin))
+ gpio_free(pm2->lpn_pin);
kfree(pm2);
@@ -1058,12 +1245,11 @@ MODULE_DEVICE_TABLE(i2c, pm2xxx_id);
static struct i2c_driver pm2xxx_charger_driver = {
.probe = pm2xxx_wall_charger_probe,
- .remove = __devexit_p(pm2xxx_wall_charger_remove),
- .suspend = pm2xxx_wall_charger_suspend,
- .resume = pm2xxx_wall_charger_resume,
+ .remove = pm2xxx_wall_charger_remove,
.driver = {
.name = "pm2xxx-wall_charger",
.owner = THIS_MODULE,
+ .pm = PM2XXX_PM_OPS,
},
.id_table = pm2xxx_id,
};
@@ -1078,11 +1264,10 @@ static void __exit pm2xxx_charger_exit(void)
i2c_del_driver(&pm2xxx_charger_driver);
}
-subsys_initcall_sync(pm2xxx_charger_init);
+device_initcall_sync(pm2xxx_charger_init);
module_exit(pm2xxx_charger_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
MODULE_ALIAS("platform:pm2xxx-charger");
MODULE_DESCRIPTION("PM2xxx charger management driver");
-
diff --git a/drivers/power/pm2301_charger.h b/drivers/power/pm2301_charger.h
index e6319cdbc94f..8ce3cc0195df 100644
--- a/drivers/power/pm2301_charger.h
+++ b/drivers/power/pm2301_charger.h
@@ -9,27 +9,6 @@
#ifndef PM2301_CHARGER_H
#define PM2301_CHARGER_H
-#define MAIN_WDOG_ENA 0x01
-#define MAIN_WDOG_KICK 0x02
-#define MAIN_WDOG_DIS 0x00
-#define CHARG_WD_KICK 0x01
-#define MAIN_CH_ENA 0x01
-#define MAIN_CH_NO_OVERSHOOT_ENA_N 0x02
-#define MAIN_CH_DET 0x01
-#define MAIN_CH_CV_ON 0x04
-#define OTP_ENABLE_WD 0x01
-
-#define MAIN_CH_INPUT_CURR_SHIFT 4
-
-#define LED_INDICATOR_PWM_ENA 0x01
-#define LED_INDICATOR_PWM_DIS 0x00
-#define LED_IND_CUR_5MA 0x04
-#define LED_INDICATOR_PWM_DUTY_252_256 0xBF
-
-/* HW failure constants */
-#define MAIN_CH_TH_PROT 0x02
-#define MAIN_CH_NOK 0x01
-
/* Watchdog timeout constant */
#define WD_TIMER 0x30 /* 4min */
#define WD_KICK_INTERVAL (30 * HZ)
@@ -495,7 +474,6 @@ struct pm2xxx_charger {
int failure_input_ovv;
unsigned int lpn_pin;
struct pm2xxx_interrupts *pm2_int;
- struct ab8500_gpadc *gpadc;
struct regulator *regu;
struct pm2xxx_bm_data *bat;
struct mutex lock;
@@ -506,6 +484,7 @@ struct pm2xxx_charger {
struct delayed_work check_vbat_work;
struct work_struct ac_work;
struct work_struct check_main_thermal_prot_work;
+ struct delayed_work check_hw_failure_work;
struct ux500_charger ac_chg;
struct pm2xxx_charger_event_flags flags;
};
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 5deac432e2ae..1c517c34e4be 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -26,17 +26,42 @@ EXPORT_SYMBOL_GPL(power_supply_class);
static struct device_type power_supply_dev_type;
+static bool __power_supply_is_supplied_by(struct power_supply *supplier,
+ struct power_supply *supply)
+{
+ int i;
+
+ if (!supply->supplied_from && !supplier->supplied_to)
+ return false;
+
+ /* Support both supplied_to and supplied_from modes */
+ if (supply->supplied_from) {
+ if (!supplier->name)
+ return false;
+ for (i = 0; i < supply->num_supplies; i++)
+ if (!strcmp(supplier->name, supply->supplied_from[i]))
+ return true;
+ } else {
+ if (!supply->name)
+ return false;
+ for (i = 0; i < supplier->num_supplicants; i++)
+ if (!strcmp(supplier->supplied_to[i], supply->name))
+ return true;
+ }
+
+ return false;
+}
+
static int __power_supply_changed_work(struct device *dev, void *data)
{
struct power_supply *psy = (struct power_supply *)data;
struct power_supply *pst = dev_get_drvdata(dev);
- int i;
- for (i = 0; i < psy->num_supplicants; i++)
- if (!strcmp(psy->supplied_to[i], pst->name)) {
- if (pst->external_power_changed)
- pst->external_power_changed(pst);
- }
+ if (__power_supply_is_supplied_by(psy, pst)) {
+ if (pst->external_power_changed)
+ pst->external_power_changed(pst);
+ }
+
return 0;
}
@@ -63,22 +88,151 @@ void power_supply_changed(struct power_supply *psy)
}
EXPORT_SYMBOL_GPL(power_supply_changed);
+#ifdef CONFIG_OF
+#include <linux/of.h>
+
+static int __power_supply_populate_supplied_from(struct device *dev,
+ void *data)
+{
+ struct power_supply *psy = (struct power_supply *)data;
+ struct power_supply *epsy = dev_get_drvdata(dev);
+ struct device_node *np;
+ int i = 0;
+
+ do {
+ np = of_parse_phandle(psy->of_node, "power-supplies", i++);
+ if (!np)
+ continue;
+
+ if (np == epsy->of_node) {
+ dev_info(psy->dev, "%s: Found supply : %s\n",
+ psy->name, epsy->name);
+ psy->supplied_from[i-1] = (char *)epsy->name;
+ psy->num_supplies++;
+ break;
+ }
+ } while (np);
+
+ return 0;
+}
+
+static int power_supply_populate_supplied_from(struct power_supply *psy)
+{
+ int error;
+
+ error = class_for_each_device(power_supply_class, NULL, psy,
+ __power_supply_populate_supplied_from);
+
+ dev_dbg(psy->dev, "%s %d\n", __func__, error);
+
+ return error;
+}
+
+static int __power_supply_find_supply_from_node(struct device *dev,
+ void *data)
+{
+ struct device_node *np = (struct device_node *)data;
+ struct power_supply *epsy = dev_get_drvdata(dev);
+
+ /* return error breaks out of class_for_each_device loop */
+ if (epsy->of_node == np)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int power_supply_find_supply_from_node(struct device_node *supply_node)
+{
+ int error;
+ struct device *dev;
+ struct class_dev_iter iter;
+
+ /*
+ * Use iterator to see if any other device is registered.
+ * This is required since class_for_each_device returns 0
+ * if there are no devices registered.
+ */
+ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
+ dev = class_dev_iter_next(&iter);
+
+ if (!dev)
+ return -EPROBE_DEFER;
+
+ /*
+ * We have to treat the return value as inverted, because if
+ * we return error on not found, then it won't continue looking.
+ * So we trick it by returning error on success to stop looking
+ * once the matching device is found.
+ */
+ error = class_for_each_device(power_supply_class, NULL, supply_node,
+ __power_supply_find_supply_from_node);
+
+ return error ? 0 : -EPROBE_DEFER;
+}
+
+static int power_supply_check_supplies(struct power_supply *psy)
+{
+ struct device_node *np;
+ int cnt = 0;
+
+ /* If there is already a list honor it */
+ if (psy->supplied_from && psy->num_supplies > 0)
+ return 0;
+
+ /* No device node found, nothing to do */
+ if (!psy->of_node)
+ return 0;
+
+ do {
+ int ret;
+
+ np = of_parse_phandle(psy->of_node, "power-supplies", cnt++);
+ if (!np)
+ continue;
+
+ ret = power_supply_find_supply_from_node(np);
+ if (ret) {
+ dev_dbg(psy->dev, "Failed to find supply, defer!\n");
+ return -EPROBE_DEFER;
+ }
+ } while (np);
+
+ /* All supplies found, allocate char ** array for filling */
+ psy->supplied_from = devm_kzalloc(psy->dev, sizeof(psy->supplied_from),
+ GFP_KERNEL);
+ if (!psy->supplied_from) {
+ dev_err(psy->dev, "Couldn't allocate memory for supply list\n");
+ return -ENOMEM;
+ }
+
+ *psy->supplied_from = devm_kzalloc(psy->dev, sizeof(char *) * cnt,
+ GFP_KERNEL);
+ if (!*psy->supplied_from) {
+ dev_err(psy->dev, "Couldn't allocate memory for supply list\n");
+ return -ENOMEM;
+ }
+
+ return power_supply_populate_supplied_from(psy);
+}
+#else
+static inline int power_supply_check_supplies(struct power_supply *psy)
+{
+ return 0;
+}
+#endif
+
static int __power_supply_am_i_supplied(struct device *dev, void *data)
{
union power_supply_propval ret = {0,};
struct power_supply *psy = (struct power_supply *)data;
struct power_supply *epsy = dev_get_drvdata(dev);
- int i;
- for (i = 0; i < epsy->num_supplicants; i++) {
- if (!strcmp(epsy->supplied_to[i], psy->name)) {
- if (epsy->get_property(epsy,
- POWER_SUPPLY_PROP_ONLINE, &ret))
- continue;
+ if (__power_supply_is_supplied_by(epsy, psy))
+ if (!epsy->get_property(epsy, POWER_SUPPLY_PROP_ONLINE, &ret)) {
if (ret.intval)
return ret.intval;
}
- }
+
return 0;
}
@@ -336,6 +490,12 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
INIT_WORK(&psy->changed_work, power_supply_changed_work);
+ rc = power_supply_check_supplies(psy);
+ if (rc) {
+ dev_info(dev, "Not all required supplies found, defer probe\n");
+ goto check_supplies_failed;
+ }
+
rc = kobject_set_name(&dev->kobj, "%s", psy->name);
if (rc)
goto kobject_set_name_failed;
@@ -368,6 +528,7 @@ register_thermal_failed:
device_del(dev);
kobject_set_name_failed:
device_add_failed:
+check_supplies_failed:
put_device(dev);
success:
return rc;
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 1ae65b822864..349e9ae8090a 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -30,3 +30,10 @@ config POWER_RESET_RESTART
Some boards don't actually have the ability to power off.
Instead they restart, and u-boot holds the SoC until the
user presses a key. u-boot then boots into Linux.
+
+config POWER_RESET_VEXPRESS
+ bool
+ depends on POWER_RESET
+ help
+ Power off and reset support for the ARM Ltd. Versatile
+ Express boards.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 0f317f50c56f..372807fd83f7 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
-obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o \ No newline at end of file
+obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
+obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
diff --git a/arch/arm/mach-vexpress/reset.c b/drivers/power/reset/vexpress-poweroff.c
index 465923aa3819..469e6962b2cf 100644
--- a/arch/arm/mach-vexpress/reset.c
+++ b/drivers/power/reset/vexpress-poweroff.c
@@ -18,6 +18,8 @@
#include <linux/stat.h>
#include <linux/vexpress.h>
+#include <asm/system_misc.h>
+
static void vexpress_reset_do(struct device *dev, const char *what)
{
int err = -ENOENT;
@@ -39,14 +41,14 @@ static void vexpress_reset_do(struct device *dev, const char *what)
static struct device *vexpress_power_off_device;
-void vexpress_power_off(void)
+static void vexpress_power_off(void)
{
vexpress_reset_do(vexpress_power_off_device, "power off");
}
static struct device *vexpress_restart_device;
-void vexpress_restart(char str, const char *cmd)
+static void vexpress_restart(char str, const char *cmd)
{
vexpress_reset_do(vexpress_restart_device, "restart");
}
@@ -103,14 +105,17 @@ static int vexpress_reset_probe(struct platform_device *pdev)
switch (func) {
case FUNC_SHUTDOWN:
vexpress_power_off_device = &pdev->dev;
+ pm_power_off = vexpress_power_off;
break;
case FUNC_RESET:
if (!vexpress_restart_device)
vexpress_restart_device = &pdev->dev;
+ arm_pm_restart = vexpress_restart;
device_create_file(&pdev->dev, &dev_attr_active);
break;
case FUNC_REBOOT:
vexpress_restart_device = &pdev->dev;
+ arm_pm_restart = vexpress_restart;
device_create_file(&pdev->dev, &dev_attr_active);
break;
};
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c
index 8208888b844e..1a1dcb831a17 100644
--- a/drivers/power/rx51_battery.c
+++ b/drivers/power/rx51_battery.c
@@ -119,7 +119,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
/* First check for temperature in first direct table */
if (raw < ARRAY_SIZE(rx51_temp_table1))
- return rx51_temp_table1[raw] * 100;
+ return rx51_temp_table1[raw] * 10;
/* Binary search RAW value in second inverse table */
while (max - min > 1) {
@@ -132,7 +132,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
break;
}
- return (rx51_temp_table2_first - min) * 100;
+ return (rx51_temp_table2_first - min) * 10;
}
/*
@@ -202,7 +202,7 @@ static int rx51_battery_probe(struct platform_device *pdev)
struct rx51_device_info *di;
int ret;
- di = kzalloc(sizeof(*di), GFP_KERNEL);
+ di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
if (!di)
return -ENOMEM;
@@ -217,7 +217,6 @@ static int rx51_battery_probe(struct platform_device *pdev)
ret = power_supply_register(di->dev, &di->bat);
if (ret) {
platform_set_drvdata(pdev, NULL);
- kfree(di);
return ret;
}
@@ -230,7 +229,6 @@ static int rx51_battery_remove(struct platform_device *pdev)
power_supply_unregister(&di->bat);
platform_set_drvdata(pdev, NULL);
- kfree(di);
return 0;
}
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index d2ca989dcbdc..5948ce058bdd 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -145,14 +145,17 @@ static int s3c_adc_bat_get_property(struct power_supply *psy,
int new_level;
int full_volt;
- const struct s3c_adc_bat_thresh *lut = bat->pdata->lut_noac;
- unsigned int lut_size = bat->pdata->lut_noac_cnt;
+ const struct s3c_adc_bat_thresh *lut;
+ unsigned int lut_size;
if (!bat) {
dev_err(psy->dev, "no battery infos ?!\n");
return -EINVAL;
}
+ lut = bat->pdata->lut_noac;
+ lut_size = bat->pdata->lut_noac_cnt;
+
if (bat->volt_value < 0 || bat->cur_value < 0 ||
jiffies_to_msecs(jiffies - bat->timestamp) >
BAT_POLL_INTERVAL) {
diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c
index 3960f0b2afe9..c8c78a74e75a 100644
--- a/drivers/power/sbs-battery.c
+++ b/drivers/power/sbs-battery.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
+#include <linux/of.h>
#include <linux/power/sbs-battery.h>
@@ -667,7 +668,6 @@ of_out:
return pdata;
}
#else
-#define sbs_dt_ids NULL
static struct sbs_platform_data *sbs_of_populate_pdata(
struct i2c_client *client)
{
@@ -820,10 +820,11 @@ static int sbs_remove(struct i2c_client *client)
return 0;
}
-#if defined CONFIG_PM
-static int sbs_suspend(struct i2c_client *client,
- pm_message_t state)
+#if defined CONFIG_PM_SLEEP
+
+static int sbs_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct sbs_info *chip = i2c_get_clientdata(client);
s32 ret;
@@ -838,11 +839,13 @@ static int sbs_suspend(struct i2c_client *client,
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(sbs_pm_ops, sbs_suspend, NULL);
+#define SBS_PM_OPS (&sbs_pm_ops)
+
#else
-#define sbs_suspend NULL
+#define SBS_PM_OPS NULL
#endif
-/* any smbus transaction will wake up sbs */
-#define sbs_resume NULL
static const struct i2c_device_id sbs_id[] = {
{ "bq20z75", 0 },
@@ -854,12 +857,11 @@ MODULE_DEVICE_TABLE(i2c, sbs_id);
static struct i2c_driver sbs_battery_driver = {
.probe = sbs_probe,
.remove = sbs_remove,
- .suspend = sbs_suspend,
- .resume = sbs_resume,
.id_table = sbs_id,
.driver = {
.name = "sbs-battery",
- .of_match_table = sbs_dt_ids,
+ .of_match_table = of_match_ptr(sbs_dt_ids),
+ .pm = SBS_PM_OPS,
},
};
module_i2c_driver(sbs_battery_driver);
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
index b99a452a4fda..0152f35dca5c 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/test_power.c
@@ -30,6 +30,8 @@ static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION;
static int battery_capacity = 50;
static int battery_voltage = 3300;
+static bool module_initialized;
+
static int test_power_get_ac_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -185,6 +187,7 @@ static int __init test_power_init(void)
}
}
+ module_initialized = true;
return 0;
failed:
while (--i >= 0)
@@ -209,6 +212,8 @@ static void __exit test_power_exit(void)
for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
power_supply_unregister(&test_power_supplies[i]);
+
+ module_initialized = false;
}
module_exit(test_power_exit);
@@ -221,8 +226,8 @@ struct battery_property_map {
};
static struct battery_property_map map_ac_online[] = {
- { 0, "on" },
- { 1, "off" },
+ { 0, "off" },
+ { 1, "on" },
{ -1, NULL },
};
@@ -295,10 +300,16 @@ static const char *map_get_key(struct battery_property_map *map, int value,
return def_key;
}
+static inline void signal_power_supply_changed(struct power_supply *psy)
+{
+ if (module_initialized)
+ power_supply_changed(psy);
+}
+
static int param_set_ac_online(const char *key, const struct kernel_param *kp)
{
ac_online = map_get_value(map_ac_online, key, ac_online);
- power_supply_changed(&test_power_supplies[0]);
+ signal_power_supply_changed(&test_power_supplies[0]);
return 0;
}
@@ -311,7 +322,7 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
static int param_set_usb_online(const char *key, const struct kernel_param *kp)
{
usb_online = map_get_value(map_ac_online, key, usb_online);
- power_supply_changed(&test_power_supplies[2]);
+ signal_power_supply_changed(&test_power_supplies[2]);
return 0;
}
@@ -325,7 +336,7 @@ static int param_set_battery_status(const char *key,
const struct kernel_param *kp)
{
battery_status = map_get_value(map_status, key, battery_status);
- power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[1]);
return 0;
}
@@ -339,7 +350,7 @@ static int param_set_battery_health(const char *key,
const struct kernel_param *kp)
{
battery_health = map_get_value(map_health, key, battery_health);
- power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[1]);
return 0;
}
@@ -353,7 +364,7 @@ static int param_set_battery_present(const char *key,
const struct kernel_param *kp)
{
battery_present = map_get_value(map_present, key, battery_present);
- power_supply_changed(&test_power_supplies[0]);
+ signal_power_supply_changed(&test_power_supplies[0]);
return 0;
}
@@ -369,7 +380,7 @@ static int param_set_battery_technology(const char *key,
{
battery_technology = map_get_value(map_technology, key,
battery_technology);
- power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[1]);
return 0;
}
@@ -390,7 +401,7 @@ static int param_set_battery_capacity(const char *key,
return -EINVAL;
battery_capacity = tmp;
- power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[1]);
return 0;
}
@@ -405,7 +416,7 @@ static int param_set_battery_voltage(const char *key,
return -EINVAL;
battery_voltage = tmp;
- power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[1]);
return 0;
}
diff --git a/drivers/power/tps65090-charger.c b/drivers/power/tps65090-charger.c
new file mode 100644
index 000000000000..9fbca310a2ad
--- /dev/null
+++ b/drivers/power/tps65090-charger.c
@@ -0,0 +1,320 @@
+/*
+ * Battery charger driver for TI's tps65090
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION. 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/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/tps65090.h>
+
+#define TPS65090_REG_INTR_STS 0x00
+#define TPS65090_REG_CG_CTRL0 0x04
+#define TPS65090_REG_CG_CTRL1 0x05
+#define TPS65090_REG_CG_CTRL2 0x06
+#define TPS65090_REG_CG_CTRL3 0x07
+#define TPS65090_REG_CG_CTRL4 0x08
+#define TPS65090_REG_CG_CTRL5 0x09
+#define TPS65090_REG_CG_STATUS1 0x0a
+#define TPS65090_REG_CG_STATUS2 0x0b
+
+#define TPS65090_CHARGER_ENABLE BIT(0)
+#define TPS65090_VACG BIT(1)
+#define TPS65090_NOITERM BIT(5)
+
+struct tps65090_charger {
+ struct device *dev;
+ int ac_online;
+ int prev_ac_online;
+ int irq;
+ struct power_supply ac;
+ struct tps65090_platform_data *pdata;
+};
+
+static enum power_supply_property tps65090_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static int tps65090_low_chrg_current(struct tps65090_charger *charger)
+{
+ int ret;
+
+ ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5,
+ TPS65090_NOITERM);
+ if (ret < 0) {
+ dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
+ __func__, TPS65090_REG_CG_CTRL5);
+ return ret;
+ }
+ return 0;
+}
+
+static int tps65090_enable_charging(struct tps65090_charger *charger,
+ uint8_t enable)
+{
+ int ret;
+ uint8_t ctrl0 = 0;
+
+ ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0,
+ &ctrl0);
+ if (ret < 0) {
+ dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
+ __func__, TPS65090_REG_CG_CTRL0);
+ return ret;
+ }
+
+ ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL0,
+ (ctrl0 | TPS65090_CHARGER_ENABLE));
+ if (ret < 0) {
+ dev_err(charger->dev, "%s(): error reading in register 0x%x\n",
+ __func__, TPS65090_REG_CG_CTRL0);
+ return ret;
+ }
+ return 0;
+}
+
+static int tps65090_config_charger(struct tps65090_charger *charger)
+{
+ int ret;
+
+ if (charger->pdata->enable_low_current_chrg) {
+ ret = tps65090_low_chrg_current(charger);
+ if (ret < 0) {
+ dev_err(charger->dev,
+ "error configuring low charge current\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int tps65090_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct tps65090_charger *charger = container_of(psy,
+ struct tps65090_charger, ac);
+
+ if (psp == POWER_SUPPLY_PROP_ONLINE) {
+ val->intval = charger->ac_online;
+ charger->prev_ac_online = charger->ac_online;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static irqreturn_t tps65090_charger_isr(int irq, void *dev_id)
+{
+ struct tps65090_charger *charger = dev_id;
+ int ret;
+ uint8_t status1 = 0;
+ uint8_t intrsts = 0;
+
+ ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_STATUS1,
+ &status1);
+ if (ret < 0) {
+ dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n",
+ __func__, TPS65090_REG_CG_STATUS1);
+ return IRQ_HANDLED;
+ }
+ msleep(75);
+ ret = tps65090_read(charger->dev->parent, TPS65090_REG_INTR_STS,
+ &intrsts);
+ if (ret < 0) {
+ dev_err(charger->dev, "%s(): Error in reading reg 0x%x\n",
+ __func__, TPS65090_REG_INTR_STS);
+ return IRQ_HANDLED;
+ }
+
+ if (intrsts & TPS65090_VACG) {
+ ret = tps65090_enable_charging(charger, 1);
+ if (ret < 0)
+ return IRQ_HANDLED;
+ charger->ac_online = 1;
+ } else {
+ charger->ac_online = 0;
+ }
+
+ if (charger->prev_ac_online != charger->ac_online)
+ power_supply_changed(&charger->ac);
+
+ return IRQ_HANDLED;
+}
+
+#if defined(CONFIG_OF)
+
+#include <linux/of_device.h>
+
+static struct tps65090_platform_data *
+ tps65090_parse_dt_charger_data(struct platform_device *pdev)
+{
+ struct tps65090_platform_data *pdata;
+ struct device_node *np = pdev->dev.of_node;
+ unsigned int prop;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n");
+ return NULL;
+ }
+
+ prop = of_property_read_bool(np, "ti,enable-low-current-chrg");
+ pdata->enable_low_current_chrg = prop;
+
+ pdata->irq_base = -1;
+
+ return pdata;
+
+}
+#else
+static struct tps65090_platform_data *
+ tps65090_parse_dt_charger_data(struct platform_device *pdev)
+{
+ return NULL;
+}
+#endif
+
+static int tps65090_charger_probe(struct platform_device *pdev)
+{
+ struct tps65090_charger *cdata;
+ struct tps65090_platform_data *pdata;
+ uint8_t status1 = 0;
+ int ret;
+ int irq;
+
+ pdata = dev_get_platdata(pdev->dev.parent);
+
+ if (!pdata && pdev->dev.of_node)
+ pdata = tps65090_parse_dt_charger_data(pdev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "%s():no platform data available\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ cdata = devm_kzalloc(&pdev->dev, sizeof(*cdata), GFP_KERNEL);
+ if (!cdata) {
+ dev_err(&pdev->dev, "failed to allocate memory status\n");
+ return -ENOMEM;
+ }
+
+ dev_set_drvdata(&pdev->dev, cdata);
+
+ cdata->dev = &pdev->dev;
+ cdata->pdata = pdata;
+
+ cdata->ac.name = "tps65090-ac";
+ cdata->ac.type = POWER_SUPPLY_TYPE_MAINS;
+ cdata->ac.get_property = tps65090_ac_get_property;
+ cdata->ac.properties = tps65090_ac_props;
+ cdata->ac.num_properties = ARRAY_SIZE(tps65090_ac_props);
+ cdata->ac.supplied_to = pdata->supplied_to;
+ cdata->ac.num_supplicants = pdata->num_supplicants;
+
+ ret = power_supply_register(&pdev->dev, &cdata->ac);
+ if (ret) {
+ dev_err(&pdev->dev, "failed: power supply register\n");
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_warn(&pdev->dev, "Unable to get charger irq = %d\n", irq);
+ ret = irq;
+ goto fail_unregister_supply;
+ }
+
+ cdata->irq = irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ tps65090_charger_isr, 0, "tps65090-charger", cdata);
+ if (ret) {
+ dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq,
+ ret);
+ goto fail_free_irq;
+ }
+
+ ret = tps65090_config_charger(cdata);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
+ goto fail_free_irq;
+ }
+
+ /* Check for charger presence */
+ ret = tps65090_read(cdata->dev->parent, TPS65090_REG_CG_STATUS1,
+ &status1);
+ if (ret < 0) {
+ dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__,
+ TPS65090_REG_CG_STATUS1);
+ goto fail_free_irq;
+ }
+
+ if (status1 != 0) {
+ ret = tps65090_enable_charging(cdata, 1);
+ if (ret < 0) {
+ dev_err(cdata->dev, "error enabling charger\n");
+ goto fail_free_irq;
+ }
+ cdata->ac_online = 1;
+ power_supply_changed(&cdata->ac);
+ }
+
+ return 0;
+
+fail_free_irq:
+ devm_free_irq(cdata->dev, irq, cdata);
+fail_unregister_supply:
+ power_supply_unregister(&cdata->ac);
+
+ return ret;
+}
+
+static int tps65090_charger_remove(struct platform_device *pdev)
+{
+ struct tps65090_charger *cdata = dev_get_drvdata(&pdev->dev);
+
+ devm_free_irq(cdata->dev, cdata->irq, cdata);
+ power_supply_unregister(&cdata->ac);
+
+ return 0;
+}
+
+static struct of_device_id of_tps65090_charger_match[] = {
+ { .compatible = "ti,tps65090-charger", },
+ { /* end */ }
+};
+
+static struct platform_driver tps65090_charger_driver = {
+ .driver = {
+ .name = "tps65090-charger",
+ .of_match_table = of_tps65090_charger_match,
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65090_charger_probe,
+ .remove = tps65090_charger_remove,
+};
+module_platform_driver(tps65090_charger_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Syed Rafiuddin <srafiuddin@nvidia.com>");
+MODULE_DESCRIPTION("tps65090 battery charger driver");
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index a69d0d11b540..bed458172dd2 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -636,17 +636,7 @@ static struct platform_driver twl4030_bci_driver = {
.remove = __exit_p(twl4030_bci_remove),
};
-static int __init twl4030_bci_init(void)
-{
- return platform_driver_probe(&twl4030_bci_driver, twl4030_bci_probe);
-}
-module_init(twl4030_bci_init);
-
-static void __exit twl4030_bci_exit(void)
-{
- platform_driver_unregister(&twl4030_bci_driver);
-}
-module_exit(twl4030_bci_exit);
+module_platform_driver_probe(twl4030_bci_driver, twl4030_bci_probe);
MODULE_AUTHOR("Gražvydas Ignotas");
MODULE_DESCRIPTION("TWL4030 Battery Charger Interface driver");
diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c
index d9cc169f1424..58cbb009b74f 100644
--- a/drivers/power/wm831x_backup.c
+++ b/drivers/power/wm831x_backup.c
@@ -169,7 +169,8 @@ static int wm831x_backup_probe(struct platform_device *pdev)
struct power_supply *backup;
int ret;
- devdata = kzalloc(sizeof(struct wm831x_backup), GFP_KERNEL);
+ devdata = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_backup),
+ GFP_KERNEL);
if (devdata == NULL)
return -ENOMEM;
@@ -197,14 +198,8 @@ static int wm831x_backup_probe(struct platform_device *pdev)
backup->num_properties = ARRAY_SIZE(wm831x_backup_props);
backup->get_property = wm831x_backup_get_prop;
ret = power_supply_register(&pdev->dev, backup);
- if (ret)
- goto err_kmalloc;
return ret;
-
-err_kmalloc:
- kfree(devdata);
- return ret;
}
static int wm831x_backup_remove(struct platform_device *pdev)
@@ -213,7 +208,6 @@ static int wm831x_backup_remove(struct platform_device *pdev)
power_supply_unregister(&devdata->backup);
kfree(devdata->backup.name);
- kfree(devdata);
return 0;
}
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 982d16b5a846..7512e98e9311 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -20,10 +20,10 @@ config PPS
To compile this driver as a module, choose M here: the module
will be called pps_core.ko.
+if PPS
config PPS_DEBUG
bool "PPS debugging messages"
- depends on PPS
help
Say Y here if you want the PPS support to produce a bunch of debug
messages to the system log. Select this if you are having a
@@ -31,13 +31,15 @@ config PPS_DEBUG
config NTP_PPS
bool "PPS kernel consumer support"
- depends on PPS && !NO_HZ
+ depends on !NO_HZ
help
This option adds support for direct in-kernel time
synchronization using an external PPS signal.
It doesn't work on tickless systems at the moment.
+endif
+
source drivers/pps/clients/Kconfig
source drivers/pps/generators/Kconfig
diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c
index 079e930b1938..e219db1f1c84 100644
--- a/drivers/pps/kc.c
+++ b/drivers/pps/kc.c
@@ -34,10 +34,10 @@
*/
/* state variables to bind kernel consumer */
-DEFINE_SPINLOCK(pps_kc_hardpps_lock);
+static DEFINE_SPINLOCK(pps_kc_hardpps_lock);
/* PPS API (RFC 2783): current source and mode for kernel consumer */
-struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */
-int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
+static struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */
+static int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
/* pps_kc_bind - control PPS kernel consumer binding
* @pps: the PPS source
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 79f4bce061bd..4a8c388364ca 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/bitops.h>
+#include <linux/idr.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -32,7 +32,6 @@
#include "ptp_private.h"
#define PTP_MAX_ALARMS 4
-#define PTP_MAX_CLOCKS 8
#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
#define PTP_PPS_EVENT PPS_CAPTUREASSERT
#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
@@ -42,8 +41,7 @@
static dev_t ptp_devt;
static struct class *ptp_class;
-static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS);
-static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
+static DEFINE_IDA(ptp_clocks_map);
/* time stamp event queue operations */
@@ -171,12 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc)
struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
mutex_destroy(&ptp->tsevq_mux);
-
- /* Remove the clock from the bit map. */
- mutex_lock(&ptp_clocks_mutex);
- clear_bit(ptp->index, ptp_clocks_map);
- mutex_unlock(&ptp_clocks_mutex);
-
+ ida_simple_remove(&ptp_clocks_map, ptp->index);
kfree(ptp);
}
@@ -191,21 +184,18 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
if (info->n_alarm > PTP_MAX_ALARMS)
return ERR_PTR(-EINVAL);
- /* Find a free clock slot and reserve it. */
- err = -EBUSY;
- mutex_lock(&ptp_clocks_mutex);
- index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
- if (index < PTP_MAX_CLOCKS)
- set_bit(index, ptp_clocks_map);
- else
- goto no_slot;
-
/* Initialize a clock structure. */
err = -ENOMEM;
ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
if (ptp == NULL)
goto no_memory;
+ index = ida_simple_get(&ptp_clocks_map, 0, MINORMASK + 1, GFP_KERNEL);
+ if (index < 0) {
+ err = index;
+ goto no_slot;
+ }
+
ptp->clock.ops = ptp_clock_ops;
ptp->clock.release = delete_ptp_clock;
ptp->info = info;
@@ -248,7 +238,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
goto no_clock;
}
- mutex_unlock(&ptp_clocks_mutex);
return ptp;
no_clock:
@@ -260,11 +249,9 @@ no_sysfs:
device_destroy(ptp_class, ptp->devid);
no_device:
mutex_destroy(&ptp->tsevq_mux);
+no_slot:
kfree(ptp);
no_memory:
- clear_bit(index, ptp_clocks_map);
-no_slot:
- mutex_unlock(&ptp_clocks_mutex);
return ERR_PTR(err);
}
EXPORT_SYMBOL(ptp_clock_register);
@@ -323,7 +310,8 @@ EXPORT_SYMBOL(ptp_clock_index);
static void __exit ptp_exit(void)
{
class_destroy(ptp_class);
- unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+ unregister_chrdev_region(ptp_devt, MINORMASK + 1);
+ ida_destroy(&ptp_clocks_map);
}
static int __init ptp_init(void)
@@ -336,7 +324,7 @@ static int __init ptp_init(void)
return PTR_ERR(ptp_class);
}
- err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+ err = alloc_chrdev_region(&ptp_devt, 0, MINORMASK + 1, "ptp");
if (err < 0) {
pr_err("ptp: failed to allocate device region\n");
goto no_region;
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
index 1367655eee39..bea94510ad2d 100644
--- a/drivers/ptp/ptp_pch.c
+++ b/drivers/ptp/ptp_pch.c
@@ -118,7 +118,7 @@ struct pch_ts_regs {
* struct pch_dev - Driver private data
*/
struct pch_dev {
- struct pch_ts_regs *regs;
+ struct pch_ts_regs __iomem *regs;
struct ptp_clock *ptp_clock;
struct ptp_clock_info caps;
int exts0_enabled;
@@ -154,7 +154,7 @@ static inline void pch_eth_enable_set(struct pch_dev *chip)
iowrite32(val, (&chip->regs->ts_sel));
}
-static u64 pch_systime_read(struct pch_ts_regs *regs)
+static u64 pch_systime_read(struct pch_ts_regs __iomem *regs)
{
u64 ns;
u32 lo, hi;
@@ -169,7 +169,7 @@ static u64 pch_systime_read(struct pch_ts_regs *regs)
return ns;
}
-static void pch_systime_write(struct pch_ts_regs *regs, u64 ns)
+static void pch_systime_write(struct pch_ts_regs __iomem *regs, u64 ns)
{
u32 hi, lo;
@@ -315,7 +315,7 @@ int pch_set_station_address(u8 *addr, struct pci_dev *pdev)
struct pch_dev *chip = pci_get_drvdata(pdev);
/* Verify the parameter */
- if ((chip->regs == 0) || addr == (u8 *)NULL) {
+ if ((chip->regs == NULL) || addr == (u8 *)NULL) {
dev_err(&pdev->dev,
"invalid params returning PCH_INVALIDPARAM\n");
return PCH_INVALIDPARAM;
@@ -361,7 +361,7 @@ EXPORT_SYMBOL(pch_set_station_address);
static irqreturn_t isr(int irq, void *priv)
{
struct pch_dev *pch_dev = priv;
- struct pch_ts_regs *regs = pch_dev->regs;
+ struct pch_ts_regs __iomem *regs = pch_dev->regs;
struct ptp_clock_event event;
u32 ack = 0, lo, hi, val;
@@ -415,7 +415,7 @@ static int ptp_pch_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
u32 diff, addend;
int neg_adj = 0;
struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
- struct pch_ts_regs *regs = pch_dev->regs;
+ struct pch_ts_regs __iomem *regs = pch_dev->regs;
if (ppb < 0) {
neg_adj = 1;
@@ -438,7 +438,7 @@ static int ptp_pch_adjtime(struct ptp_clock_info *ptp, s64 delta)
s64 now;
unsigned long flags;
struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
- struct pch_ts_regs *regs = pch_dev->regs;
+ struct pch_ts_regs __iomem *regs = pch_dev->regs;
spin_lock_irqsave(&pch_dev->register_lock, flags);
now = pch_systime_read(regs);
@@ -455,7 +455,7 @@ static int ptp_pch_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
u32 remainder;
unsigned long flags;
struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
- struct pch_ts_regs *regs = pch_dev->regs;
+ struct pch_ts_regs __iomem *regs = pch_dev->regs;
spin_lock_irqsave(&pch_dev->register_lock, flags);
ns = pch_systime_read(regs);
@@ -472,7 +472,7 @@ static int ptp_pch_settime(struct ptp_clock_info *ptp,
u64 ns;
unsigned long flags;
struct pch_dev *pch_dev = container_of(ptp, struct pch_dev, caps);
- struct pch_ts_regs *regs = pch_dev->regs;
+ struct pch_ts_regs __iomem *regs = pch_dev->regs;
ns = ts->tv_sec * 1000000000ULL;
ns += ts->tv_nsec;
@@ -567,9 +567,9 @@ static void pch_remove(struct pci_dev *pdev)
free_irq(pdev->irq, chip);
/* unmap the virtual IO memory space */
- if (chip->regs != 0) {
+ if (chip->regs != NULL) {
iounmap(chip->regs);
- chip->regs = 0;
+ chip->regs = NULL;
}
/* release the reserved IO memory space */
if (chip->mem_base != 0) {
@@ -670,7 +670,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_req_irq:
ptp_clock_unregister(chip->ptp_clock);
iounmap(chip->regs);
- chip->regs = 0;
+ chip->regs = NULL;
err_ioremap:
release_mem_region(chip->mem_base, chip->mem_size);
@@ -723,9 +723,10 @@ static s32 __init ptp_pch_init(void)
module_init(ptp_pch_init);
module_exit(ptp_pch_exit);
-module_param_string(station, pch_param.station, sizeof pch_param.station, 0444);
+module_param_string(station,
+ pch_param.station, sizeof(pch_param.station), 0444);
MODULE_PARM_DESC(station,
- "IEEE 1588 station address to use - column separated hex values");
+ "IEEE 1588 station address to use - colon separated hex values");
MODULE_AUTHOR("LAPIS SEMICONDUCTOR, <tshimizu818@gmail.com>");
MODULE_DESCRIPTION("PTP clock using the EG20T timer");
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index c79ab843333e..493948a38fca 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -220,35 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
return ret;
}
-static int pm8606_preg_enable(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-
- return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
- 1 << rdev->desc->enable_mask, 0);
-}
-
-static int pm8606_preg_disable(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
-
- return pm860x_set_bits(info->i2c, rdev->desc->enable_reg,
- 1 << rdev->desc->enable_mask,
- 1 << rdev->desc->enable_mask);
-}
-
-static int pm8606_preg_is_enabled(struct regulator_dev *rdev)
-{
- struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
-
- ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg);
- if (ret < 0)
- return ret;
-
- return !((unsigned char)ret & (1 << rdev->desc->enable_mask));
-}
-
static struct regulator_ops pm8607_regulator_ops = {
.list_voltage = pm8607_list_voltage,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -259,9 +230,9 @@ static struct regulator_ops pm8607_regulator_ops = {
};
static struct regulator_ops pm8606_preg_ops = {
- .enable = pm8606_preg_enable,
- .disable = pm8606_preg_disable,
- .is_enabled = pm8606_preg_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
};
#define PM8606_PREG(ereg, ebit) \
@@ -274,6 +245,7 @@ static struct regulator_ops pm8606_preg_ops = {
.owner = THIS_MODULE, \
.enable_reg = PM8606_##ereg, \
.enable_mask = (ebit), \
+ .enable_is_inverted = true, \
}, \
}
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 6e8250382def..47a34ff88f98 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
-obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index 111ec69a3e94..3be9e46594a1 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -17,6 +17,8 @@
#include <linux/regulator/driver.h>
#include <linux/mfd/ab3100.h>
#include <linux/mfd/abx500.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
/* LDO registers and some handy masking definitions for AB3100 */
#define AB3100_LDO_A 0x40
@@ -345,7 +347,11 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
{
struct ab3100_regulator *abreg = rdev_get_drvdata(reg);
- return abreg->plfdata->external_voltage;
+ if (abreg->plfdata)
+ return abreg->plfdata->external_voltage;
+ else
+ /* TODO: encode external voltage into device tree */
+ return 0;
}
static struct regulator_ops regulator_ops_fixed = {
@@ -488,16 +494,174 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
},
};
+static int ab3100_regulator_register(struct platform_device *pdev,
+ struct ab3100_platform_data *plfdata,
+ struct regulator_init_data *init_data,
+ struct device_node *np,
+ int id)
+{
+ struct regulator_desc *desc;
+ struct ab3100_regulator *reg;
+ struct regulator_dev *rdev;
+ struct regulator_config config = { };
+ int err, i;
+
+ for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
+ desc = &ab3100_regulator_desc[i];
+ if (desc->id == id)
+ break;
+ }
+ if (desc->id != id)
+ return -ENODEV;
+
+ /* Same index used for this array */
+ reg = &ab3100_regulators[i];
+
+ /*
+ * Initialize per-regulator struct.
+ * Inherit platform data, this comes down from the
+ * i2c boarddata, from the machine. So if you want to
+ * see what it looks like for a certain machine, go
+ * into the machine I2C setup.
+ */
+ reg->dev = &pdev->dev;
+ if (plfdata) {
+ reg->plfdata = plfdata;
+ config.init_data = &plfdata->reg_constraints[i];
+ } else if (np) {
+ config.of_node = np;
+ config.init_data = init_data;
+ }
+ config.dev = &pdev->dev;
+ config.driver_data = reg;
+
+ rdev = regulator_register(desc, &config);
+ if (IS_ERR(rdev)) {
+ err = PTR_ERR(rdev);
+ dev_err(&pdev->dev,
+ "%s: failed to register regulator %s err %d\n",
+ __func__, desc->name,
+ err);
+ return err;
+ }
+
+ /* Then set a pointer back to the registered regulator */
+ reg->rdev = rdev;
+ return 0;
+}
+
+static struct of_regulator_match ab3100_regulator_matches[] = {
+ { .name = "ab3100_ldo_a", .driver_data = (void *) AB3100_LDO_A, },
+ { .name = "ab3100_ldo_c", .driver_data = (void *) AB3100_LDO_C, },
+ { .name = "ab3100_ldo_d", .driver_data = (void *) AB3100_LDO_D, },
+ { .name = "ab3100_ldo_e", .driver_data = (void *) AB3100_LDO_E, },
+ { .name = "ab3100_ldo_f", .driver_data = (void *) AB3100_LDO_F },
+ { .name = "ab3100_ldo_g", .driver_data = (void *) AB3100_LDO_G },
+ { .name = "ab3100_ldo_h", .driver_data = (void *) AB3100_LDO_H },
+ { .name = "ab3100_ldo_k", .driver_data = (void *) AB3100_LDO_K },
+ { .name = "ab3100_ext", .driver_data = (void *) AB3100_LDO_EXT },
+ { .name = "ab3100_buck", .driver_data = (void *) AB3100_BUCK },
+};
+
/*
- * NOTE: the following functions are regulators pluralis - it is the
- * binding to the AB3100 core driver and the parent platform device
- * for all the different regulators.
+ * Initial settings of ab3100 registers.
+ * Common for below LDO regulator settings are that
+ * bit 7-5 controls voltage. Bit 4 turns regulator ON(1) or OFF(0).
+ * Bit 3-2 controls sleep enable and bit 1-0 controls sleep mode.
*/
+/* LDO_A 0x16: 2.75V, ON, SLEEP_A, SLEEP OFF GND */
+#define LDO_A_SETTING 0x16
+/* LDO_C 0x10: 2.65V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_C_SETTING 0x10
+/* LDO_D 0x10: 2.65V, ON, sleep mode not used */
+#define LDO_D_SETTING 0x10
+/* LDO_E 0x10: 1.8V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_E_SETTING 0x10
+/* LDO_E SLEEP 0x00: 1.8V, not used, SLEEP_A or B, not used */
+#define LDO_E_SLEEP_SETTING 0x00
+/* LDO_F 0xD0: 2.5V, ON, SLEEP_A or B, SLEEP full power */
+#define LDO_F_SETTING 0xD0
+/* LDO_G 0x00: 2.85V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_G_SETTING 0x00
+/* LDO_H 0x18: 2.75V, ON, SLEEP_B, SLEEP full power */
+#define LDO_H_SETTING 0x18
+/* LDO_K 0x00: 2.75V, OFF, SLEEP_A or B, SLEEP full power */
+#define LDO_K_SETTING 0x00
+/* LDO_EXT 0x00: Voltage not set, OFF, not used, not used */
+#define LDO_EXT_SETTING 0x00
+/* BUCK 0x7D: 1.2V, ON, SLEEP_A and B, SLEEP low power */
+#define BUCK_SETTING 0x7D
+/* BUCK SLEEP 0xAC: 1.05V, Not used, SLEEP_A and B, Not used */
+#define BUCK_SLEEP_SETTING 0xAC
+
+static const u8 ab3100_reg_initvals[] = {
+ LDO_A_SETTING,
+ LDO_C_SETTING,
+ LDO_E_SETTING,
+ LDO_E_SLEEP_SETTING,
+ LDO_F_SETTING,
+ LDO_G_SETTING,
+ LDO_H_SETTING,
+ LDO_K_SETTING,
+ LDO_EXT_SETTING,
+ BUCK_SETTING,
+ BUCK_SLEEP_SETTING,
+ LDO_D_SETTING,
+};
+
+static int ab3100_regulators_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
+ struct ab3100_regulator *reg = &ab3100_regulators[i];
+
+ regulator_unregister(reg->rdev);
+ reg->rdev = NULL;
+ }
+ return 0;
+}
+
+static int
+ab3100_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
+{
+ int err, i;
+
+ /*
+ * Set up the regulator registers, as was previously done with
+ * platform data.
+ */
+ /* Set up regulators */
+ for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
+ err = abx500_set_register_interruptible(&pdev->dev, 0,
+ ab3100_reg_init_order[i],
+ ab3100_reg_initvals[i]);
+ if (err) {
+ dev_err(&pdev->dev, "regulator initialization failed with error %d\n",
+ err);
+ return err;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ab3100_regulator_matches); i++) {
+ err = ab3100_regulator_register(
+ pdev, NULL, ab3100_regulator_matches[i].init_data,
+ ab3100_regulator_matches[i].of_node,
+ (int) ab3100_regulator_matches[i].driver_data);
+ if (err) {
+ ab3100_regulators_remove(pdev);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int ab3100_regulators_probe(struct platform_device *pdev)
{
struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
- struct regulator_config config = { };
+ struct device_node *np = pdev->dev.of_node;
int err = 0;
u8 data;
int i;
@@ -516,6 +680,18 @@ static int ab3100_regulators_probe(struct platform_device *pdev)
dev_notice(&pdev->dev,
"chip is in inactive mode (Cold start)\n");
+ if (np) {
+ err = of_regulator_match(&pdev->dev, np,
+ ab3100_regulator_matches,
+ ARRAY_SIZE(ab3100_regulator_matches));
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Error parsing regulator init data: %d\n", err);
+ return err;
+ }
+ return ab3100_regulator_of_probe(pdev, np);
+ }
+
/* Set up regulators */
for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) {
err = abx500_set_register_interruptible(&pdev->dev, 0,
@@ -530,59 +706,19 @@ static int ab3100_regulators_probe(struct platform_device *pdev)
/* Register the regulators */
for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
- struct ab3100_regulator *reg = &ab3100_regulators[i];
- struct regulator_dev *rdev;
-
- /*
- * Initialize per-regulator struct.
- * Inherit platform data, this comes down from the
- * i2c boarddata, from the machine. So if you want to
- * see what it looks like for a certain machine, go
- * into the machine I2C setup.
- */
- reg->dev = &pdev->dev;
- reg->plfdata = plfdata;
+ struct regulator_desc *desc = &ab3100_regulator_desc[i];
- config.dev = &pdev->dev;
- config.driver_data = reg;
- config.init_data = &plfdata->reg_constraints[i];
-
- /*
- * Register the regulator, pass around
- * the ab3100_regulator struct
- */
- rdev = regulator_register(&ab3100_regulator_desc[i], &config);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- dev_err(&pdev->dev,
- "%s: failed to register regulator %s err %d\n",
- __func__, ab3100_regulator_desc[i].name,
- err);
- /* remove the already registered regulators */
- while (--i >= 0)
- regulator_unregister(ab3100_regulators[i].rdev);
+ err = ab3100_regulator_register(pdev, plfdata, NULL, NULL,
+ desc->id);
+ if (err) {
+ ab3100_regulators_remove(pdev);
return err;
}
-
- /* Then set a pointer back to the registered regulator */
- reg->rdev = rdev;
}
return 0;
}
-static int ab3100_regulators_remove(struct platform_device *pdev)
-{
- int i;
-
- for (i = 0; i < AB3100_NUM_REGULATORS; i++) {
- struct ab3100_regulator *reg = &ab3100_regulators[i];
-
- regulator_unregister(reg->rdev);
- }
- return 0;
-}
-
static struct platform_driver ab3100_regulators_driver = {
.driver = {
.name = "ab3100-regulators",
diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c
new file mode 100644
index 000000000000..b4d45472aae6
--- /dev/null
+++ b/drivers/regulator/ab8500-ext.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
+ *
+ * This file is based on drivers/regulator/ab8500.c
+ *
+ * AB8500 external regulators
+ *
+ * ab8500-ext supports the following regulators:
+ * - VextSupply3
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/regulator/ab8500.h>
+
+/**
+ * struct ab8500_ext_regulator_info - ab8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device
+ * @cfg: regulator configuration (extension of regulator FW configuration)
+ * @update_bank: bank to control on/off
+ * @update_reg: register to control on/off
+ * @update_mask: mask to enable/disable and set mode of regulator
+ * @update_val: bits holding the regulator current mode
+ * @update_val_hp: bits to set EN pin active (LPn pin deactive)
+ * normally this means high power mode
+ * @update_val_lp: bits to set EN pin active and LPn pin active
+ * normally this means low power mode
+ * @update_val_hw: bits to set regulator pins in HW control
+ * SysClkReq pins and logic will choose mode
+ */
+struct ab8500_ext_regulator_info {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct ab8500_ext_regulator_cfg *cfg;
+ u8 update_bank;
+ u8 update_reg;
+ u8 update_mask;
+ u8 update_val;
+ u8 update_val_hp;
+ u8 update_val_lp;
+ u8 update_val_hw;
+};
+
+static int ab8500_ext_regulator_enable(struct regulator_dev *rdev)
+{
+ int ret;
+ struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ /*
+ * To satisfy both HW high power request and SW request, the regulator
+ * must be on in high power.
+ */
+ if (info->cfg && info->cfg->hwreq)
+ regval = info->update_val_hp;
+ else
+ regval = info->update_val;
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ info->update_mask, regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(info->rdev),
+ "couldn't set enable bits for regulator\n");
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev),
+ "%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, regval);
+
+ return 0;
+}
+
+static int ab8500_ext_regulator_disable(struct regulator_dev *rdev)
+{
+ int ret;
+ struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Set the regulator in HW request mode if configured
+ */
+ if (info->cfg && info->cfg->hwreq)
+ regval = info->update_val_hw;
+ else
+ regval = 0;
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ info->update_mask, regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(info->rdev),
+ "couldn't set disable bits for regulator\n");
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):"
+ " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, regval);
+
+ return 0;
+}
+
+static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ int ret;
+ struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->update_bank, info->update_reg, &regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read 0x%x register\n", info->update_reg);
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):"
+ " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, regval);
+
+ if (((regval & info->update_mask) == info->update_val_lp) ||
+ ((regval & info->update_mask) == info->update_val_hp))
+ return 1;
+ else
+ return 0;
+}
+
+static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ int ret = 0;
+ struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ regval = info->update_val_hp;
+ break;
+ case REGULATOR_MODE_IDLE:
+ regval = info->update_val_lp;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* If regulator is enabled and info->cfg->hwreq is set, the regulator
+ must be on in high power, so we don't need to write the register with
+ the same value.
+ */
+ if (ab8500_ext_regulator_is_enabled(rdev) &&
+ !(info->cfg && info->cfg->hwreq)) {
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->update_bank, info->update_reg,
+ info->update_mask, regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "Could not set regulator mode.\n");
+ return ret;
+ }
+
+ dev_dbg(rdev_get_dev(rdev),
+ "%s-set_mode (bank, reg, mask, value): "
+ "0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->update_bank, info->update_reg,
+ info->update_mask, regval);
+ }
+
+ info->update_val = regval;
+
+ return 0;
+}
+
+static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ if (info->update_val == info->update_val_hp)
+ ret = REGULATOR_MODE_NORMAL;
+ else if (info->update_val == info->update_val_lp)
+ ret = REGULATOR_MODE_IDLE;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int ab8500_ext_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct regulation_constraints *regu_constraints = rdev->constraints;
+
+ if (regu_constraints == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n");
+ return -EINVAL;
+ }
+ /* return the uV for the fixed regulators */
+ if (regu_constraints->min_uV && regu_constraints->max_uV) {
+ if (regu_constraints->min_uV == regu_constraints->max_uV)
+ return regu_constraints->min_uV;
+ }
+ return -EINVAL;
+}
+
+static struct regulator_ops ab8500_ext_regulator_ops = {
+ .enable = ab8500_ext_regulator_enable,
+ .disable = ab8500_ext_regulator_disable,
+ .is_enabled = ab8500_ext_regulator_is_enabled,
+ .set_mode = ab8500_ext_regulator_set_mode,
+ .get_mode = ab8500_ext_regulator_get_mode,
+ .list_voltage = ab8500_ext_list_voltage,
+};
+
+static struct ab8500_ext_regulator_info
+ ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = {
+ [AB8500_EXT_SUPPLY1] = {
+ .desc = {
+ .name = "VEXTSUPPLY1",
+ .ops = &ab8500_ext_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_EXT_SUPPLY1,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .update_bank = 0x04,
+ .update_reg = 0x08,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_hp = 0x01,
+ .update_val_lp = 0x03,
+ .update_val_hw = 0x02,
+ },
+ [AB8500_EXT_SUPPLY2] = {
+ .desc = {
+ .name = "VEXTSUPPLY2",
+ .ops = &ab8500_ext_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_EXT_SUPPLY2,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .update_bank = 0x04,
+ .update_reg = 0x08,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_hp = 0x04,
+ .update_val_lp = 0x0c,
+ .update_val_hw = 0x08,
+ },
+ [AB8500_EXT_SUPPLY3] = {
+ .desc = {
+ .name = "VEXTSUPPLY3",
+ .ops = &ab8500_ext_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_EXT_SUPPLY3,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ },
+ .update_bank = 0x04,
+ .update_reg = 0x08,
+ .update_mask = 0x30,
+ .update_val = 0x10,
+ .update_val_hp = 0x10,
+ .update_val_lp = 0x30,
+ .update_val_hw = 0x20,
+ },
+};
+
+int ab8500_ext_regulator_init(struct platform_device *pdev)
+{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
+ struct ab8500_platform_data *ppdata;
+ struct ab8500_regulator_platform_data *pdata;
+ struct regulator_config config = { };
+ int i, err;
+
+ if (!ab8500) {
+ dev_err(&pdev->dev, "null mfd parent\n");
+ return -EINVAL;
+ }
+ ppdata = dev_get_platdata(ab8500->dev);
+ if (!ppdata) {
+ dev_err(&pdev->dev, "null parent pdata\n");
+ return -EINVAL;
+ }
+
+ pdata = ppdata->regulator;
+ if (!pdata) {
+ dev_err(&pdev->dev, "null pdata\n");
+ return -EINVAL;
+ }
+
+ /* make sure the platform data has the correct size */
+ if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
+ dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
+ return -EINVAL;
+ }
+
+ /* check for AB8500 2.x */
+ if (is_ab8500_2p0_or_earlier(ab8500)) {
+ struct ab8500_ext_regulator_info *info;
+
+ /* VextSupply3LPn is inverted on AB8500 2.x */
+ info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3];
+ info->update_val = 0x30;
+ info->update_val_hp = 0x30;
+ info->update_val_lp = 0x10;
+ }
+
+ /* register all regulators */
+ for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
+ struct ab8500_ext_regulator_info *info = NULL;
+
+ /* assign per-regulator data */
+ info = &ab8500_ext_regulator_info[i];
+ info->dev = &pdev->dev;
+ info->cfg = (struct ab8500_ext_regulator_cfg *)
+ pdata->ext_regulator[i].driver_data;
+
+ config.dev = &pdev->dev;
+ config.init_data = &pdata->ext_regulator[i];
+ config.driver_data = info;
+
+ /* register regulator with framework */
+ info->rdev = regulator_register(&info->desc, &config);
+ if (IS_ERR(info->rdev)) {
+ err = PTR_ERR(info->rdev);
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ info->desc.name);
+ /* when we fail, un-register all earlier regulators */
+ while (--i >= 0) {
+ info = &ab8500_ext_regulator_info[i];
+ regulator_unregister(info->rdev);
+ }
+ return err;
+ }
+
+ dev_dbg(rdev_get_dev(info->rdev),
+ "%s-probed\n", info->desc.name);
+ }
+
+ return 0;
+}
+
+void ab8500_ext_regulator_exit(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
+ struct ab8500_ext_regulator_info *info = NULL;
+ info = &ab8500_ext_regulator_info[i];
+
+ dev_vdbg(rdev_get_dev(info->rdev),
+ "%s-remove\n", info->desc.name);
+
+ regulator_unregister(info->rdev);
+ }
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
+MODULE_DESCRIPTION("AB8500 external regulator driver");
+MODULE_ALIAS("platform:ab8500-ext-regulator");
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 09014f38a948..f6656b8c28b6 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -5,11 +5,15 @@
*
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ * Daniel Willerud <daniel.willerud@stericsson.com> for ST-Ericsson
*
* AB8500 peripheral regulators
*
* AB8500 supports the following regulators:
* VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA
+ *
+ * AB8505 supports the following regulators:
+ * VAUX1/2/3/4/5/6, VINTCORE, VADC, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA
*/
#include <linux/init.h>
#include <linux/kernel.h>
@@ -26,33 +30,64 @@
#include <linux/slab.h>
/**
+ * struct ab8500_shared_mode - is used when mode is shared between
+ * two regulators.
+ * @shared_regulator: pointer to the other sharing regulator
+ * @lp_mode_req: low power mode requested by this regulator
+ */
+struct ab8500_shared_mode {
+ struct ab8500_regulator_info *shared_regulator;
+ bool lp_mode_req;
+};
+
+/**
* struct ab8500_regulator_info - ab8500 regulator information
* @dev: device pointer
* @desc: regulator description
* @regulator_dev: regulator device
+ * @shared_mode: used when mode is shared between two regulators
+ * @load_lp_uA: maximum load in idle (low power) mode
* @update_bank: bank to control on/off
* @update_reg: register to control on/off
- * @update_mask: mask to enable/disable regulator
- * @update_val_enable: bits to enable the regulator in normal (high power) mode
+ * @update_mask: mask to enable/disable and set mode of regulator
+ * @update_val: bits holding the regulator current mode
+ * @update_val_idle: bits to enable the regulator in idle (low power) mode
+ * @update_val_normal: bits to enable the regulator in normal (high power) mode
+ * @mode_bank: bank with location of mode register
+ * @mode_reg: mode register
+ * @mode_mask: mask for setting mode
+ * @mode_val_idle: mode setting for low power
+ * @mode_val_normal: mode setting for normal power
* @voltage_bank: bank to control regulator voltage
* @voltage_reg: register to control regulator voltage
* @voltage_mask: mask to control regulator voltage
- * @voltage_shift: shift to control regulator voltage
- * @delay: startup/set voltage delay in us
*/
struct ab8500_regulator_info {
struct device *dev;
struct regulator_desc desc;
struct regulator_dev *regulator;
+ struct ab8500_shared_mode *shared_mode;
+ int load_lp_uA;
u8 update_bank;
u8 update_reg;
u8 update_mask;
- u8 update_val_enable;
+ u8 update_val;
+ u8 update_val_idle;
+ u8 update_val_normal;
+ u8 mode_bank;
+ u8 mode_reg;
+ u8 mode_mask;
+ u8 mode_val_idle;
+ u8 mode_val_normal;
u8 voltage_bank;
u8 voltage_reg;
u8 voltage_mask;
- u8 voltage_shift;
- unsigned int delay;
+ struct {
+ u8 voltage_limit;
+ u8 voltage_bank;
+ u8 voltage_reg;
+ u8 voltage_mask;
+ } expand_register;
};
/* voltage tables for the vauxn/vintcore supplies */
@@ -86,6 +121,44 @@ static const unsigned int ldo_vaux3_voltages[] = {
2910000,
};
+static const unsigned int ldo_vaux56_voltages[] = {
+ 1800000,
+ 1050000,
+ 1100000,
+ 1200000,
+ 1500000,
+ 2200000,
+ 2500000,
+ 2790000,
+};
+
+static const unsigned int ldo_vaux3_ab8540_voltages[] = {
+ 1200000,
+ 1500000,
+ 1800000,
+ 2100000,
+ 2500000,
+ 2750000,
+ 2790000,
+ 2910000,
+ 3050000,
+};
+
+static const unsigned int ldo_vaux56_ab8540_voltages[] = {
+ 750000, 760000, 770000, 780000, 790000, 800000,
+ 810000, 820000, 830000, 840000, 850000, 860000,
+ 870000, 880000, 890000, 900000, 910000, 920000,
+ 930000, 940000, 950000, 960000, 970000, 980000,
+ 990000, 1000000, 1010000, 1020000, 1030000,
+ 1040000, 1050000, 1060000, 1070000, 1080000,
+ 1090000, 1100000, 1110000, 1120000, 1130000,
+ 1140000, 1150000, 1160000, 1170000, 1180000,
+ 1190000, 1200000, 1210000, 1220000, 1230000,
+ 1240000, 1250000, 1260000, 1270000, 1280000,
+ 1290000, 1300000, 1310000, 1320000, 1330000,
+ 1340000, 1350000, 1360000, 1800000, 2790000,
+};
+
static const unsigned int ldo_vintcore_voltages[] = {
1200000,
1225000,
@@ -96,6 +169,72 @@ static const unsigned int ldo_vintcore_voltages[] = {
1350000,
};
+static const unsigned int ldo_sdio_voltages[] = {
+ 1160000,
+ 1050000,
+ 1100000,
+ 1500000,
+ 1800000,
+ 2200000,
+ 2910000,
+ 3050000,
+};
+
+static const unsigned int fixed_1200000_voltage[] = {
+ 1200000,
+};
+
+static const unsigned int fixed_1800000_voltage[] = {
+ 1800000,
+};
+
+static const unsigned int fixed_2000000_voltage[] = {
+ 2000000,
+};
+
+static const unsigned int fixed_2050000_voltage[] = {
+ 2050000,
+};
+
+static const unsigned int fixed_3300000_voltage[] = {
+ 3300000,
+};
+
+static const unsigned int ldo_vana_voltages[] = {
+ 1050000,
+ 1075000,
+ 1100000,
+ 1125000,
+ 1150000,
+ 1175000,
+ 1200000,
+ 1225000,
+};
+
+static const unsigned int ldo_vaudio_voltages[] = {
+ 2000000,
+ 2100000,
+ 2200000,
+ 2300000,
+ 2400000,
+ 2500000,
+ 2600000,
+ 2600000, /* Duplicated in Vaudio and IsoUicc Control register. */
+};
+
+static const unsigned int ldo_vdmic_voltages[] = {
+ 1800000,
+ 1900000,
+ 2000000,
+ 2850000,
+};
+
+static DEFINE_MUTEX(shared_mode_mutex);
+static struct ab8500_shared_mode ldo_anamic1_shared;
+static struct ab8500_shared_mode ldo_anamic2_shared;
+static struct ab8500_shared_mode ab8540_ldo_anamic1_shared;
+static struct ab8500_shared_mode ab8540_ldo_anamic2_shared;
+
static int ab8500_regulator_enable(struct regulator_dev *rdev)
{
int ret;
@@ -108,15 +247,17 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev)
ret = abx500_mask_and_set_register_interruptible(info->dev,
info->update_bank, info->update_reg,
- info->update_mask, info->update_val_enable);
- if (ret < 0)
+ info->update_mask, info->update_val);
+ if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't set enable bits for regulator\n");
+ return ret;
+ }
dev_vdbg(rdev_get_dev(rdev),
"%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
info->desc.name, info->update_bank, info->update_reg,
- info->update_mask, info->update_val_enable);
+ info->update_mask, info->update_val);
return ret;
}
@@ -134,9 +275,11 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev)
ret = abx500_mask_and_set_register_interruptible(info->dev,
info->update_bank, info->update_reg,
info->update_mask, 0x0);
- if (ret < 0)
+ if (ret < 0) {
dev_err(rdev_get_dev(rdev),
"couldn't set disable bits for regulator\n");
+ return ret;
+ }
dev_vdbg(rdev_get_dev(rdev),
"%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
@@ -172,14 +315,170 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
info->update_mask, regval);
if (regval & info->update_mask)
- return true;
+ return 1;
+ else
+ return 0;
+}
+
+static unsigned int ab8500_regulator_get_optimum_mode(
+ struct regulator_dev *rdev, int input_uV,
+ int output_uV, int load_uA)
+{
+ unsigned int mode;
+
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ if (load_uA <= info->load_lp_uA)
+ mode = REGULATOR_MODE_IDLE;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+
+ return mode;
+}
+
+static int ab8500_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ int ret = 0;
+ u8 bank, reg, mask, val;
+ bool lp_mode_req = false;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ if (info->mode_mask) {
+ bank = info->mode_bank;
+ reg = info->mode_reg;
+ mask = info->mode_mask;
+ } else {
+ bank = info->update_bank;
+ reg = info->update_reg;
+ mask = info->update_mask;
+ }
+
+ if (info->shared_mode)
+ mutex_lock(&shared_mode_mutex);
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ if (info->shared_mode)
+ lp_mode_req = false;
+
+ if (info->mode_mask)
+ val = info->mode_val_normal;
+ else
+ val = info->update_val_normal;
+ break;
+ case REGULATOR_MODE_IDLE:
+ if (info->shared_mode) {
+ struct ab8500_regulator_info *shared_regulator;
+
+ shared_regulator = info->shared_mode->shared_regulator;
+ if (!shared_regulator->shared_mode->lp_mode_req) {
+ /* Other regulator prevent LP mode */
+ info->shared_mode->lp_mode_req = true;
+ goto out_unlock;
+ }
+
+ lp_mode_req = true;
+ }
+
+ if (info->mode_mask)
+ val = info->mode_val_idle;
+ else
+ val = info->update_val_idle;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (info->mode_mask || ab8500_regulator_is_enabled(rdev)) {
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ bank, reg, mask, val);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set regulator mode\n");
+ goto out_unlock;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_mode (bank, reg, mask, value): "
+ "0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, bank, reg,
+ mask, val);
+ }
+
+ if (!info->mode_mask)
+ info->update_val = val;
+
+ if (info->shared_mode)
+ info->shared_mode->lp_mode_req = lp_mode_req;
+
+out_unlock:
+ if (info->shared_mode)
+ mutex_unlock(&shared_mode_mutex);
+
+ return ret;
+}
+
+static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+ u8 val;
+ u8 val_normal;
+ u8 val_idle;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ /* Need special handling for shared mode */
+ if (info->shared_mode) {
+ if (info->shared_mode->lp_mode_req)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+ }
+
+ if (info->mode_mask) {
+ /* Dedicated register for handling mode */
+ ret = abx500_get_register_interruptible(info->dev,
+ info->mode_bank, info->mode_reg, &val);
+ val = val & info->mode_mask;
+
+ val_normal = info->mode_val_normal;
+ val_idle = info->mode_val_idle;
+ } else {
+ /* Mode register same as enable register */
+ val = info->update_val;
+ val_normal = info->update_val_normal;
+ val_idle = info->update_val_idle;
+ }
+
+ if (val == val_normal)
+ ret = REGULATOR_MODE_NORMAL;
+ else if (val == val_idle)
+ ret = REGULATOR_MODE_IDLE;
else
- return false;
+ ret = -EINVAL;
+
+ return ret;
}
static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
- int ret, val;
+ int ret, voltage_shift;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
u8 regval;
@@ -188,6 +487,8 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
return -EINVAL;
}
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
ret = abx500_get_register_interruptible(info->dev,
info->voltage_bank, info->voltage_reg, &regval);
if (ret < 0) {
@@ -201,16 +502,62 @@ static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
"0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
info->desc.name, info->voltage_bank,
info->voltage_reg, info->voltage_mask,
- info->voltage_shift, regval);
+ voltage_shift, regval);
- val = regval & info->voltage_mask;
- return val >> info->voltage_shift;
+ return (regval & info->voltage_mask) >> voltage_shift;
+}
+
+static int ab8540_aux3_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+ int ret, voltage_shift;
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval, regval_expand;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg, &regval_expand);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read voltage expand reg for regulator\n");
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-get_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg,
+ info->expand_register.voltage_mask, regval_expand);
+
+ if (regval_expand & info->expand_register.voltage_mask)
+ return info->expand_register.voltage_limit;
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg, &regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read voltage reg for regulator\n");
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-get_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
+ return (regval & info->voltage_mask) >> voltage_shift;
}
static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
- int ret;
+ int ret, voltage_shift;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
u8 regval;
@@ -219,8 +566,10 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
return -EINVAL;
}
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
/* set the registers for the request */
- regval = (u8)selector << info->voltage_shift;
+ regval = (u8)selector << voltage_shift;
ret = abx500_mask_and_set_register_interruptible(info->dev,
info->voltage_bank, info->voltage_reg,
info->voltage_mask, regval);
@@ -237,32 +586,121 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
return ret;
}
-static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
- unsigned int old_sel,
- unsigned int new_sel)
+static int ab8540_aux3_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
{
+ int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ u8 regval, regval_expand;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ if (selector < info->expand_register.voltage_limit) {
+ int voltage_shift = ffs(info->voltage_mask) - 1;
+
+ regval = (u8)selector << voltage_shift;
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set voltage reg for regulator\n");
+ return ret;
+ }
- return info->delay;
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
+ regval_expand = 0;
+ } else {
+ regval_expand = info->expand_register.voltage_mask;
+ }
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg,
+ info->expand_register.voltage_mask,
+ regval_expand);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set expand voltage reg for regulator\n");
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg,
+ info->expand_register.voltage_mask, regval_expand);
+
+ return 0;
}
-static struct regulator_ops ab8500_regulator_ops = {
+static struct regulator_ops ab8500_regulator_volt_mode_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_optimum_mode = ab8500_regulator_get_optimum_mode,
+ .set_mode = ab8500_regulator_set_mode,
+ .get_mode = ab8500_regulator_get_mode,
+ .get_voltage_sel = ab8500_regulator_get_voltage_sel,
+ .set_voltage_sel = ab8500_regulator_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_table,
+};
+
+static struct regulator_ops ab8540_aux3_regulator_volt_mode_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .get_optimum_mode = ab8500_regulator_get_optimum_mode,
+ .set_mode = ab8500_regulator_set_mode,
+ .get_mode = ab8500_regulator_get_mode,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_voltage_sel = ab8540_aux3_regulator_get_voltage_sel,
+ .set_voltage_sel = ab8540_aux3_regulator_set_voltage_sel,
+ .list_voltage = regulator_list_voltage_table,
+};
+
+static struct regulator_ops ab8500_regulator_volt_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage_sel = ab8500_regulator_get_voltage_sel,
.set_voltage_sel = ab8500_regulator_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
- .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
};
-static struct regulator_ops ab8500_regulator_fixed_ops = {
+static struct regulator_ops ab8500_regulator_mode_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .get_optimum_mode = ab8500_regulator_get_optimum_mode,
+ .set_mode = ab8500_regulator_set_mode,
+ .get_mode = ab8500_regulator_get_mode,
+ .list_voltage = regulator_list_voltage_table,
+};
+
+static struct regulator_ops ab8500_regulator_ops = {
+ .enable = ab8500_regulator_enable,
+ .disable = ab8500_regulator_disable,
+ .is_enabled = ab8500_regulator_is_enabled,
+ .list_voltage = regulator_list_voltage_table,
+};
+
+static struct regulator_ops ab8500_regulator_anamic_mode_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
.is_enabled = ab8500_regulator_is_enabled,
- .list_voltage = regulator_list_voltage_linear,
+ .set_mode = ab8500_regulator_set_mode,
+ .get_mode = ab8500_regulator_get_mode,
+ .list_voltage = regulator_list_voltage_table,
};
+/* AB8500 regulator information */
static struct ab8500_regulator_info
ab8500_regulator_info[AB8500_NUM_REGULATORS] = {
/*
@@ -274,17 +712,21 @@ static struct ab8500_regulator_info
[AB8500_LDO_AUX1] = {
.desc = {
.name = "LDO-AUX1",
- .ops = &ab8500_regulator_ops,
+ .ops = &ab8500_regulator_volt_mode_ops,
.type = REGULATOR_VOLTAGE,
.id = AB8500_LDO_AUX1,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
.volt_table = ldo_vauxn_voltages,
+ .enable_time = 200,
},
+ .load_lp_uA = 5000,
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x03,
- .update_val_enable = 0x01,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
.voltage_bank = 0x04,
.voltage_reg = 0x1f,
.voltage_mask = 0x0f,
@@ -292,17 +734,21 @@ static struct ab8500_regulator_info
[AB8500_LDO_AUX2] = {
.desc = {
.name = "LDO-AUX2",
- .ops = &ab8500_regulator_ops,
+ .ops = &ab8500_regulator_volt_mode_ops,
.type = REGULATOR_VOLTAGE,
.id = AB8500_LDO_AUX2,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
.volt_table = ldo_vauxn_voltages,
+ .enable_time = 200,
},
+ .load_lp_uA = 5000,
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x0c,
- .update_val_enable = 0x04,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
.voltage_bank = 0x04,
.voltage_reg = 0x20,
.voltage_mask = 0x0f,
@@ -310,17 +756,21 @@ static struct ab8500_regulator_info
[AB8500_LDO_AUX3] = {
.desc = {
.name = "LDO-AUX3",
- .ops = &ab8500_regulator_ops,
+ .ops = &ab8500_regulator_volt_mode_ops,
.type = REGULATOR_VOLTAGE,
.id = AB8500_LDO_AUX3,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vaux3_voltages),
.volt_table = ldo_vaux3_voltages,
+ .enable_time = 450,
},
+ .load_lp_uA = 5000,
.update_bank = 0x04,
.update_reg = 0x0a,
.update_mask = 0x03,
- .update_val_enable = 0x01,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
.voltage_bank = 0x04,
.voltage_reg = 0x21,
.voltage_mask = 0x07,
@@ -328,21 +778,24 @@ static struct ab8500_regulator_info
[AB8500_LDO_INTCORE] = {
.desc = {
.name = "LDO-INTCORE",
- .ops = &ab8500_regulator_ops,
+ .ops = &ab8500_regulator_volt_mode_ops,
.type = REGULATOR_VOLTAGE,
.id = AB8500_LDO_INTCORE,
.owner = THIS_MODULE,
.n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
.volt_table = ldo_vintcore_voltages,
+ .enable_time = 750,
},
+ .load_lp_uA = 5000,
.update_bank = 0x03,
.update_reg = 0x80,
.update_mask = 0x44,
- .update_val_enable = 0x04,
+ .update_val = 0x44,
+ .update_val_idle = 0x44,
+ .update_val_normal = 0x04,
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltage_shift = 3,
},
/*
@@ -353,112 +806,984 @@ static struct ab8500_regulator_info
[AB8500_LDO_TVOUT] = {
.desc = {
.name = "LDO-TVOUT",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_mode_ops,
.type = REGULATOR_VOLTAGE,
.id = AB8500_LDO_TVOUT,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 2000000,
+ .volt_table = fixed_2000000_voltage,
+ .enable_time = 500,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x82,
+ .update_val = 0x02,
+ .update_val_idle = 0x82,
+ .update_val_normal = 0x02,
+ },
+ [AB8500_LDO_AUDIO] = {
+ .desc = {
+ .name = "LDO-AUDIO",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_AUDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .enable_time = 140,
+ .volt_table = fixed_2000000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x02,
+ .update_val = 0x02,
+ },
+ [AB8500_LDO_ANAMIC1] = {
+ .desc = {
+ .name = "LDO-ANAMIC1",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANAMIC1,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .enable_time = 500,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x08,
+ .update_val = 0x08,
+ },
+ [AB8500_LDO_ANAMIC2] = {
+ .desc = {
+ .name = "LDO-ANAMIC2",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANAMIC2,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .enable_time = 500,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x10,
+ .update_val = 0x10,
+ },
+ [AB8500_LDO_DMIC] = {
+ .desc = {
+ .name = "LDO-DMIC",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_DMIC,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .enable_time = 420,
+ .volt_table = fixed_1800000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x04,
+ .update_val = 0x04,
+ },
+
+ /*
+ * Regulators with fixed voltage and normal/idle modes
+ */
+ [AB8500_LDO_ANA] = {
+ .desc = {
+ .name = "LDO-ANA",
+ .ops = &ab8500_regulator_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8500_LDO_ANA,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .enable_time = 140,
+ .volt_table = fixed_1200000_voltage,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x04,
+ .update_reg = 0x06,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ },
+};
+
+/* AB8505 regulator information */
+static struct ab8500_regulator_info
+ ab8505_regulator_info[AB8505_NUM_REGULATORS] = {
+ /*
+ * Variable Voltage Regulators
+ * name, min mV, max mV,
+ * update bank, reg, mask, enable val
+ * volt bank, reg, mask
+ */
+ [AB8505_LDO_AUX1] = {
+ .desc = {
+ .name = "LDO-AUX1",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX1,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x1f,
+ .voltage_mask = 0x0f,
+ },
+ [AB8505_LDO_AUX2] = {
+ .desc = {
+ .name = "LDO-AUX2",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX2,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x20,
+ .voltage_mask = 0x0f,
+ },
+ [AB8505_LDO_AUX3] = {
+ .desc = {
+ .name = "LDO-AUX3",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX3,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages),
+ .volt_table = ldo_vaux3_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x0a,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x21,
+ .voltage_mask = 0x07,
+ },
+ [AB8505_LDO_AUX4] = {
+ .desc = {
+ .name = "LDO-AUX4",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX4,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ /* values for Vaux4Regu register */
+ .update_bank = 0x04,
+ .update_reg = 0x2e,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ /* values for Vaux4SEL register */
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x2f,
+ .voltage_mask = 0x0f,
+ },
+ [AB8505_LDO_AUX5] = {
+ .desc = {
+ .name = "LDO-AUX5",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX5,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages),
+ .volt_table = ldo_vaux56_voltages,
+ },
+ .load_lp_uA = 2000,
+ /* values for CtrlVaux5 register */
+ .update_bank = 0x01,
+ .update_reg = 0x55,
+ .update_mask = 0x18,
+ .update_val = 0x10,
+ .update_val_idle = 0x18,
+ .update_val_normal = 0x10,
+ .voltage_bank = 0x01,
+ .voltage_reg = 0x55,
+ .voltage_mask = 0x07,
+ },
+ [AB8505_LDO_AUX6] = {
+ .desc = {
+ .name = "LDO-AUX6",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX6,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux56_voltages),
+ .volt_table = ldo_vaux56_voltages,
+ },
+ .load_lp_uA = 2000,
+ /* values for CtrlVaux6 register */
+ .update_bank = 0x01,
+ .update_reg = 0x56,
+ .update_mask = 0x18,
+ .update_val = 0x10,
+ .update_val_idle = 0x18,
+ .update_val_normal = 0x10,
+ .voltage_bank = 0x01,
+ .voltage_reg = 0x56,
+ .voltage_mask = 0x07,
+ },
+ [AB8505_LDO_INTCORE] = {
+ .desc = {
+ .name = "LDO-INTCORE",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_INTCORE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
+ .volt_table = ldo_vintcore_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x44,
+ .update_val = 0x04,
+ .update_val_idle = 0x44,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x80,
+ .voltage_mask = 0x38,
+ },
+
+ /*
+ * Fixed Voltage Regulators
+ * name, fixed mV,
+ * update bank, reg, mask, enable val
+ */
+ [AB8505_LDO_ADC] = {
+ .desc = {
+ .name = "LDO-ADC",
+ .ops = &ab8500_regulator_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_ADC,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2000000_voltage,
.enable_time = 10000,
},
- .delay = 10000,
+ .load_lp_uA = 1000,
.update_bank = 0x03,
.update_reg = 0x80,
.update_mask = 0x82,
- .update_val_enable = 0x02,
+ .update_val = 0x02,
+ .update_val_idle = 0x82,
+ .update_val_normal = 0x02,
},
- [AB8500_LDO_USB] = {
+ [AB8505_LDO_USB] = {
.desc = {
.name = "LDO-USB",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_mode_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_USB,
+ .id = AB8505_LDO_USB,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 3300000,
+ .volt_table = fixed_3300000_voltage,
},
.update_bank = 0x03,
.update_reg = 0x82,
.update_mask = 0x03,
- .update_val_enable = 0x01,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
},
- [AB8500_LDO_AUDIO] = {
+ [AB8505_LDO_AUDIO] = {
.desc = {
.name = "LDO-AUDIO",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_volt_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_AUDIO,
+ .id = AB8505_LDO_AUDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaudio_voltages),
+ .volt_table = ldo_vaudio_voltages,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x02,
+ .update_val = 0x02,
+ .voltage_bank = 0x01,
+ .voltage_reg = 0x57,
+ .voltage_mask = 0x70,
+ },
+ [AB8505_LDO_ANAMIC1] = {
+ .desc = {
+ .name = "LDO-ANAMIC1",
+ .ops = &ab8500_regulator_anamic_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_ANAMIC1,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .shared_mode = &ldo_anamic1_shared,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x08,
+ .update_val = 0x08,
+ .mode_bank = 0x01,
+ .mode_reg = 0x54,
+ .mode_mask = 0x04,
+ .mode_val_idle = 0x04,
+ .mode_val_normal = 0x00,
+ },
+ [AB8505_LDO_ANAMIC2] = {
+ .desc = {
+ .name = "LDO-ANAMIC2",
+ .ops = &ab8500_regulator_anamic_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_ANAMIC2,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 2000000,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .shared_mode = &ldo_anamic2_shared,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x10,
+ .update_val = 0x10,
+ .mode_bank = 0x01,
+ .mode_reg = 0x54,
+ .mode_mask = 0x04,
+ .mode_val_idle = 0x04,
+ .mode_val_normal = 0x00,
+ },
+ [AB8505_LDO_AUX8] = {
+ .desc = {
+ .name = "LDO-AUX8",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_AUX8,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_1800000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x04,
+ .update_val = 0x04,
+ },
+ /*
+ * Regulators with fixed voltage and normal/idle modes
+ */
+ [AB8505_LDO_ANA] = {
+ .desc = {
+ .name = "LDO-ANA",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8505_LDO_ANA,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vana_voltages),
+ .volt_table = ldo_vana_voltages,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x04,
+ .update_reg = 0x06,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x29,
+ .voltage_mask = 0x7,
+ },
+};
+
+/* AB9540 regulator information */
+static struct ab8500_regulator_info
+ ab9540_regulator_info[AB9540_NUM_REGULATORS] = {
+ /*
+ * Variable Voltage Regulators
+ * name, min mV, max mV,
+ * update bank, reg, mask, enable val
+ * volt bank, reg, mask
+ */
+ [AB9540_LDO_AUX1] = {
+ .desc = {
+ .name = "LDO-AUX1",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_AUX1,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x1f,
+ .voltage_mask = 0x0f,
+ },
+ [AB9540_LDO_AUX2] = {
+ .desc = {
+ .name = "LDO-AUX2",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_AUX2,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x20,
+ .voltage_mask = 0x0f,
+ },
+ [AB9540_LDO_AUX3] = {
+ .desc = {
+ .name = "LDO-AUX3",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_AUX3,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages),
+ .volt_table = ldo_vaux3_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x0a,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x21,
+ .voltage_mask = 0x07,
+ },
+ [AB9540_LDO_AUX4] = {
+ .desc = {
+ .name = "LDO-AUX4",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_AUX4,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ /* values for Vaux4Regu register */
+ .update_bank = 0x04,
+ .update_reg = 0x2e,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ /* values for Vaux4SEL register */
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x2f,
+ .voltage_mask = 0x0f,
+ },
+ [AB9540_LDO_INTCORE] = {
+ .desc = {
+ .name = "LDO-INTCORE",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_INTCORE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
+ .volt_table = ldo_vintcore_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x44,
+ .update_val = 0x44,
+ .update_val_idle = 0x44,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x80,
+ .voltage_mask = 0x38,
+ },
+
+ /*
+ * Fixed Voltage Regulators
+ * name, fixed mV,
+ * update bank, reg, mask, enable val
+ */
+ [AB9540_LDO_TVOUT] = {
+ .desc = {
+ .name = "LDO-TVOUT",
+ .ops = &ab8500_regulator_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_TVOUT,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2000000_voltage,
+ .enable_time = 10000,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x82,
+ .update_val = 0x02,
+ .update_val_idle = 0x82,
+ .update_val_normal = 0x02,
+ },
+ [AB9540_LDO_USB] = {
+ .desc = {
+ .name = "LDO-USB",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_USB,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_3300000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x82,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ },
+ [AB9540_LDO_AUDIO] = {
+ .desc = {
+ .name = "LDO-AUDIO",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB9540_LDO_AUDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2000000_voltage,
},
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x02,
- .update_val_enable = 0x02,
+ .update_val = 0x02,
},
- [AB8500_LDO_ANAMIC1] = {
+ [AB9540_LDO_ANAMIC1] = {
.desc = {
.name = "LDO-ANAMIC1",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_ANAMIC1,
+ .id = AB9540_LDO_ANAMIC1,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 2050000,
+ .volt_table = fixed_2050000_voltage,
},
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x08,
- .update_val_enable = 0x08,
+ .update_val = 0x08,
},
- [AB8500_LDO_ANAMIC2] = {
+ [AB9540_LDO_ANAMIC2] = {
.desc = {
.name = "LDO-ANAMIC2",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_ANAMIC2,
+ .id = AB9540_LDO_ANAMIC2,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 2050000,
+ .volt_table = fixed_2050000_voltage,
},
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x10,
- .update_val_enable = 0x10,
+ .update_val = 0x10,
},
- [AB8500_LDO_DMIC] = {
+ [AB9540_LDO_DMIC] = {
.desc = {
.name = "LDO-DMIC",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_DMIC,
+ .id = AB9540_LDO_DMIC,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 1800000,
+ .volt_table = fixed_1800000_voltage,
},
.update_bank = 0x03,
.update_reg = 0x83,
.update_mask = 0x04,
- .update_val_enable = 0x04,
+ .update_val = 0x04,
},
- [AB8500_LDO_ANA] = {
+
+ /*
+ * Regulators with fixed voltage and normal/idle modes
+ */
+ [AB9540_LDO_ANA] = {
.desc = {
.name = "LDO-ANA",
- .ops = &ab8500_regulator_fixed_ops,
+ .ops = &ab8500_regulator_mode_ops,
.type = REGULATOR_VOLTAGE,
- .id = AB8500_LDO_ANA,
+ .id = AB9540_LDO_ANA,
.owner = THIS_MODULE,
.n_voltages = 1,
- .min_uV = 1200000,
+ .volt_table = fixed_1200000_voltage,
},
+ .load_lp_uA = 1000,
.update_bank = 0x04,
.update_reg = 0x06,
.update_mask = 0x0c,
- .update_val_enable = 0x04,
+ .update_val = 0x08,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x08,
},
+};
+/* AB8540 regulator information */
+static struct ab8500_regulator_info
+ ab8540_regulator_info[AB8540_NUM_REGULATORS] = {
+ /*
+ * Variable Voltage Regulators
+ * name, min mV, max mV,
+ * update bank, reg, mask, enable val
+ * volt bank, reg, mask
+ */
+ [AB8540_LDO_AUX1] = {
+ .desc = {
+ .name = "LDO-AUX1",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX1,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x1f,
+ .voltage_mask = 0x0f,
+ },
+ [AB8540_LDO_AUX2] = {
+ .desc = {
+ .name = "LDO-AUX2",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX2,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x09,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x20,
+ .voltage_mask = 0x0f,
+ },
+ [AB8540_LDO_AUX3] = {
+ .desc = {
+ .name = "LDO-AUX3",
+ .ops = &ab8540_aux3_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX3,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux3_ab8540_voltages),
+ .volt_table = ldo_vaux3_ab8540_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x04,
+ .update_reg = 0x0a,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x21,
+ .voltage_mask = 0x07,
+ .expand_register = {
+ .voltage_limit = 8,
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x01,
+ .voltage_mask = 0x10,
+ }
+ },
+ [AB8540_LDO_AUX4] = {
+ .desc = {
+ .name = "LDO-AUX4",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX4,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages),
+ .volt_table = ldo_vauxn_voltages,
+ },
+ .load_lp_uA = 5000,
+ /* values for Vaux4Regu register */
+ .update_bank = 0x04,
+ .update_reg = 0x2e,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ /* values for Vaux4SEL register */
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x2f,
+ .voltage_mask = 0x0f,
+ },
+ [AB8540_LDO_AUX5] = {
+ .desc = {
+ .name = "LDO-AUX5",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX5,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages),
+ .volt_table = ldo_vaux56_ab8540_voltages,
+ },
+ .load_lp_uA = 20000,
+ /* values for Vaux5Regu register */
+ .update_bank = 0x04,
+ .update_reg = 0x32,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ /* values for Vaux5SEL register */
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x33,
+ .voltage_mask = 0x3f,
+ },
+ [AB8540_LDO_AUX6] = {
+ .desc = {
+ .name = "LDO-AUX6",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUX6,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vaux56_ab8540_voltages),
+ .volt_table = ldo_vaux56_ab8540_voltages,
+ },
+ .load_lp_uA = 20000,
+ /* values for Vaux6Regu register */
+ .update_bank = 0x04,
+ .update_reg = 0x35,
+ .update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
+ .update_val_normal = 0x01,
+ /* values for Vaux6SEL register */
+ .voltage_bank = 0x04,
+ .voltage_reg = 0x36,
+ .voltage_mask = 0x3f,
+ },
+ [AB8540_LDO_INTCORE] = {
+ .desc = {
+ .name = "LDO-INTCORE",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_INTCORE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages),
+ .volt_table = ldo_vintcore_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x44,
+ .update_val = 0x44,
+ .update_val_idle = 0x44,
+ .update_val_normal = 0x04,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x80,
+ .voltage_mask = 0x38,
+ },
+ /*
+ * Fixed Voltage Regulators
+ * name, fixed mV,
+ * update bank, reg, mask, enable val
+ */
+ [AB8540_LDO_TVOUT] = {
+ .desc = {
+ .name = "LDO-TVOUT",
+ .ops = &ab8500_regulator_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_TVOUT,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2000000_voltage,
+ .enable_time = 10000,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x03,
+ .update_reg = 0x80,
+ .update_mask = 0x82,
+ .update_val = 0x02,
+ .update_val_idle = 0x82,
+ .update_val_normal = 0x02,
+ },
+ [AB8540_LDO_AUDIO] = {
+ .desc = {
+ .name = "LDO-AUDIO",
+ .ops = &ab8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_AUDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2000000_voltage,
+ },
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x02,
+ .update_val = 0x02,
+ },
+ [AB8540_LDO_ANAMIC1] = {
+ .desc = {
+ .name = "LDO-ANAMIC1",
+ .ops = &ab8500_regulator_anamic_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_ANAMIC1,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .shared_mode = &ab8540_ldo_anamic1_shared,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x08,
+ .update_val = 0x08,
+ .mode_bank = 0x03,
+ .mode_reg = 0x83,
+ .mode_mask = 0x20,
+ .mode_val_idle = 0x20,
+ .mode_val_normal = 0x00,
+ },
+ [AB8540_LDO_ANAMIC2] = {
+ .desc = {
+ .name = "LDO-ANAMIC2",
+ .ops = &ab8500_regulator_anamic_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_ANAMIC2,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_2050000_voltage,
+ },
+ .shared_mode = &ab8540_ldo_anamic2_shared,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x10,
+ .update_val = 0x10,
+ .mode_bank = 0x03,
+ .mode_reg = 0x83,
+ .mode_mask = 0x20,
+ .mode_val_idle = 0x20,
+ .mode_val_normal = 0x00,
+ },
+ [AB8540_LDO_DMIC] = {
+ .desc = {
+ .name = "LDO-DMIC",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_DMIC,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_vdmic_voltages),
+ .volt_table = ldo_vdmic_voltages,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x03,
+ .update_reg = 0x83,
+ .update_mask = 0x04,
+ .update_val = 0x04,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x83,
+ .voltage_mask = 0xc0,
+ },
+
+ /*
+ * Regulators with fixed voltage and normal/idle modes
+ */
+ [AB8540_LDO_ANA] = {
+ .desc = {
+ .name = "LDO-ANA",
+ .ops = &ab8500_regulator_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_ANA,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .volt_table = fixed_1200000_voltage,
+ },
+ .load_lp_uA = 1000,
+ .update_bank = 0x04,
+ .update_reg = 0x06,
+ .update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
+ .update_val_normal = 0x04,
+ },
+ [AB8540_LDO_SDIO] = {
+ .desc = {
+ .name = "LDO-SDIO",
+ .ops = &ab8500_regulator_volt_mode_ops,
+ .type = REGULATOR_VOLTAGE,
+ .id = AB8540_LDO_SDIO,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(ldo_sdio_voltages),
+ .volt_table = ldo_sdio_voltages,
+ },
+ .load_lp_uA = 5000,
+ .update_bank = 0x03,
+ .update_reg = 0x88,
+ .update_mask = 0x30,
+ .update_val = 0x10,
+ .update_val_idle = 0x30,
+ .update_val_normal = 0x10,
+ .voltage_bank = 0x03,
+ .voltage_reg = 0x88,
+ .voltage_mask = 0x07,
+ },
+};
+
+static struct ab8500_shared_mode ldo_anamic1_shared = {
+ .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC2],
+};
+
+static struct ab8500_shared_mode ldo_anamic2_shared = {
+ .shared_regulator = &ab8505_regulator_info[AB8505_LDO_ANAMIC1],
+};
+
+static struct ab8500_shared_mode ab8540_ldo_anamic1_shared = {
+ .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC2],
+};
+
+static struct ab8500_shared_mode ab8540_ldo_anamic2_shared = {
+ .shared_regulator = &ab8540_regulator_info[AB8540_LDO_ANAMIC1],
};
struct ab8500_reg_init {
@@ -474,13 +1799,13 @@ struct ab8500_reg_init {
.mask = _mask, \
}
+/* AB8500 register init */
static struct ab8500_reg_init ab8500_reg_init[] = {
/*
* 0x30, VanaRequestCtrl
- * 0x0C, VpllRequestCtrl
* 0xc0, VextSupply1RequestCtrl
*/
- REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc),
+ REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xf0),
/*
* 0x03, VextSupply2RequestCtrl
* 0x0c, VextSupply3RequestCtrl
@@ -547,13 +1872,21 @@ static struct ab8500_reg_init ab8500_reg_init[] = {
REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f),
/*
* 0x02, SysClkReq2Valid1
- * ...
+ * 0x04, SysClkReq3Valid1
+ * 0x08, SysClkReq4Valid1
+ * 0x10, SysClkReq5Valid1
+ * 0x20, SysClkReq6Valid1
+ * 0x40, SysClkReq7Valid1
* 0x80, SysClkReq8Valid1
*/
REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe),
/*
* 0x02, SysClkReq2Valid2
- * ...
+ * 0x04, SysClkReq3Valid2
+ * 0x08, SysClkReq4Valid2
+ * 0x10, SysClkReq5Valid2
+ * 0x20, SysClkReq6Valid2
+ * 0x40, SysClkReq7Valid2
* 0x80, SysClkReq8Valid2
*/
REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe),
@@ -578,8 +1911,8 @@ static struct ab8500_reg_init ab8500_reg_init[] = {
*/
REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03),
/*
+ * 0x03, VpllRegu (NOTE! PRCMU register bits)
* 0x0c, VanaRegu
- * 0x03, VpllRegu
*/
REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f),
/*
@@ -605,10 +1938,6 @@ static struct ab8500_reg_init ab8500_reg_init[] = {
*/
REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03),
/*
- * 0x3f, Vsmps1Sel1
- */
- REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f),
- /*
* 0x0f, Vaux1Sel
*/
REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f),
@@ -641,52 +1970,1073 @@ static struct ab8500_reg_init ab8500_reg_init[] = {
REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16),
};
-static int
-ab8500_regulator_init_registers(struct platform_device *pdev, int id, int value)
+/* AB8505 register init */
+static struct ab8500_reg_init ab8505_reg_init[] = {
+ /*
+ * 0x03, VarmRequestCtrl
+ * 0x0c, VsmpsCRequestCtrl
+ * 0x30, VsmpsARequestCtrl
+ * 0xc0, VsmpsBRequestCtrl
+ */
+ REG_INIT(AB8505_REGUREQUESTCTRL1, 0x03, 0x03, 0xff),
+ /*
+ * 0x03, VsafeRequestCtrl
+ * 0x0c, VpllRequestCtrl
+ * 0x30, VanaRequestCtrl
+ */
+ REG_INIT(AB8505_REGUREQUESTCTRL2, 0x03, 0x04, 0x3f),
+ /*
+ * 0x30, Vaux1RequestCtrl
+ * 0xc0, Vaux2RequestCtrl
+ */
+ REG_INIT(AB8505_REGUREQUESTCTRL3, 0x03, 0x05, 0xf0),
+ /*
+ * 0x03, Vaux3RequestCtrl
+ * 0x04, SwHPReq
+ */
+ REG_INIT(AB8505_REGUREQUESTCTRL4, 0x03, 0x06, 0x07),
+ /*
+ * 0x01, VsmpsASysClkReq1HPValid
+ * 0x02, VsmpsBSysClkReq1HPValid
+ * 0x04, VsafeSysClkReq1HPValid
+ * 0x08, VanaSysClkReq1HPValid
+ * 0x10, VpllSysClkReq1HPValid
+ * 0x20, Vaux1SysClkReq1HPValid
+ * 0x40, Vaux2SysClkReq1HPValid
+ * 0x80, Vaux3SysClkReq1HPValid
+ */
+ REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff),
+ /*
+ * 0x01, VsmpsCSysClkReq1HPValid
+ * 0x02, VarmSysClkReq1HPValid
+ * 0x04, VbbSysClkReq1HPValid
+ * 0x08, VsmpsMSysClkReq1HPValid
+ */
+ REG_INIT(AB8505_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x0f),
+ /*
+ * 0x01, VsmpsAHwHPReq1Valid
+ * 0x02, VsmpsBHwHPReq1Valid
+ * 0x04, VsafeHwHPReq1Valid
+ * 0x08, VanaHwHPReq1Valid
+ * 0x10, VpllHwHPReq1Valid
+ * 0x20, Vaux1HwHPReq1Valid
+ * 0x40, Vaux2HwHPReq1Valid
+ * 0x80, Vaux3HwHPReq1Valid
+ */
+ REG_INIT(AB8505_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff),
+ /*
+ * 0x08, VsmpsMHwHPReq1Valid
+ */
+ REG_INIT(AB8505_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x08),
+ /*
+ * 0x01, VsmpsAHwHPReq2Valid
+ * 0x02, VsmpsBHwHPReq2Valid
+ * 0x04, VsafeHwHPReq2Valid
+ * 0x08, VanaHwHPReq2Valid
+ * 0x10, VpllHwHPReq2Valid
+ * 0x20, Vaux1HwHPReq2Valid
+ * 0x40, Vaux2HwHPReq2Valid
+ * 0x80, Vaux3HwHPReq2Valid
+ */
+ REG_INIT(AB8505_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff),
+ /*
+ * 0x08, VsmpsMHwHPReq2Valid
+ */
+ REG_INIT(AB8505_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x08),
+ /*
+ * 0x01, VsmpsCSwHPReqValid
+ * 0x02, VarmSwHPReqValid
+ * 0x04, VsmpsASwHPReqValid
+ * 0x08, VsmpsBSwHPReqValid
+ * 0x10, VsafeSwHPReqValid
+ * 0x20, VanaSwHPReqValid
+ * 0x40, VpllSwHPReqValid
+ * 0x80, Vaux1SwHPReqValid
+ */
+ REG_INIT(AB8505_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff),
+ /*
+ * 0x01, Vaux2SwHPReqValid
+ * 0x02, Vaux3SwHPReqValid
+ * 0x20, VsmpsMSwHPReqValid
+ */
+ REG_INIT(AB8505_REGUSWHPREQVALID2, 0x03, 0x0e, 0x23),
+ /*
+ * 0x02, SysClkReq2Valid1
+ * 0x04, SysClkReq3Valid1
+ * 0x08, SysClkReq4Valid1
+ */
+ REG_INIT(AB8505_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0x0e),
+ /*
+ * 0x02, SysClkReq2Valid2
+ * 0x04, SysClkReq3Valid2
+ * 0x08, SysClkReq4Valid2
+ */
+ REG_INIT(AB8505_REGUSYSCLKREQVALID2, 0x03, 0x10, 0x0e),
+ /*
+ * 0x01, Vaux4SwHPReqValid
+ * 0x02, Vaux4HwHPReq2Valid
+ * 0x04, Vaux4HwHPReq1Valid
+ * 0x08, Vaux4SysClkReq1HPValid
+ */
+ REG_INIT(AB8505_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f),
+ /*
+ * 0x02, VadcEna
+ * 0x04, VintCore12Ena
+ * 0x38, VintCore12Sel
+ * 0x40, VintCore12LP
+ * 0x80, VadcLP
+ */
+ REG_INIT(AB8505_REGUMISC1, 0x03, 0x80, 0xfe),
+ /*
+ * 0x02, VaudioEna
+ * 0x04, VdmicEna
+ * 0x08, Vamic1Ena
+ * 0x10, Vamic2Ena
+ */
+ REG_INIT(AB8505_VAUDIOSUPPLY, 0x03, 0x83, 0x1e),
+ /*
+ * 0x01, Vamic1_dzout
+ * 0x02, Vamic2_dzout
+ */
+ REG_INIT(AB8505_REGUCTRL1VAMIC, 0x03, 0x84, 0x03),
+ /*
+ * 0x03, VsmpsARegu
+ * 0x0c, VsmpsASelCtrl
+ * 0x10, VsmpsAAutoMode
+ * 0x20, VsmpsAPWMMode
+ */
+ REG_INIT(AB8505_VSMPSAREGU, 0x04, 0x03, 0x3f),
+ /*
+ * 0x03, VsmpsBRegu
+ * 0x0c, VsmpsBSelCtrl
+ * 0x10, VsmpsBAutoMode
+ * 0x20, VsmpsBPWMMode
+ */
+ REG_INIT(AB8505_VSMPSBREGU, 0x04, 0x04, 0x3f),
+ /*
+ * 0x03, VsafeRegu
+ * 0x0c, VsafeSelCtrl
+ * 0x10, VsafeAutoMode
+ * 0x20, VsafePWMMode
+ */
+ REG_INIT(AB8505_VSAFEREGU, 0x04, 0x05, 0x3f),
+ /*
+ * 0x03, VpllRegu (NOTE! PRCMU register bits)
+ * 0x0c, VanaRegu
+ */
+ REG_INIT(AB8505_VPLLVANAREGU, 0x04, 0x06, 0x0f),
+ /*
+ * 0x03, VextSupply1Regu
+ * 0x0c, VextSupply2Regu
+ * 0x30, VextSupply3Regu
+ * 0x40, ExtSupply2Bypass
+ * 0x80, ExtSupply3Bypass
+ */
+ REG_INIT(AB8505_EXTSUPPLYREGU, 0x04, 0x08, 0xff),
+ /*
+ * 0x03, Vaux1Regu
+ * 0x0c, Vaux2Regu
+ */
+ REG_INIT(AB8505_VAUX12REGU, 0x04, 0x09, 0x0f),
+ /*
+ * 0x0f, Vaux3Regu
+ */
+ REG_INIT(AB8505_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f),
+ /*
+ * 0x3f, VsmpsASel1
+ */
+ REG_INIT(AB8505_VSMPSASEL1, 0x04, 0x13, 0x3f),
+ /*
+ * 0x3f, VsmpsASel2
+ */
+ REG_INIT(AB8505_VSMPSASEL2, 0x04, 0x14, 0x3f),
+ /*
+ * 0x3f, VsmpsASel3
+ */
+ REG_INIT(AB8505_VSMPSASEL3, 0x04, 0x15, 0x3f),
+ /*
+ * 0x3f, VsmpsBSel1
+ */
+ REG_INIT(AB8505_VSMPSBSEL1, 0x04, 0x17, 0x3f),
+ /*
+ * 0x3f, VsmpsBSel2
+ */
+ REG_INIT(AB8505_VSMPSBSEL2, 0x04, 0x18, 0x3f),
+ /*
+ * 0x3f, VsmpsBSel3
+ */
+ REG_INIT(AB8505_VSMPSBSEL3, 0x04, 0x19, 0x3f),
+ /*
+ * 0x7f, VsafeSel1
+ */
+ REG_INIT(AB8505_VSAFESEL1, 0x04, 0x1b, 0x7f),
+ /*
+ * 0x3f, VsafeSel2
+ */
+ REG_INIT(AB8505_VSAFESEL2, 0x04, 0x1c, 0x7f),
+ /*
+ * 0x3f, VsafeSel3
+ */
+ REG_INIT(AB8505_VSAFESEL3, 0x04, 0x1d, 0x7f),
+ /*
+ * 0x0f, Vaux1Sel
+ */
+ REG_INIT(AB8505_VAUX1SEL, 0x04, 0x1f, 0x0f),
+ /*
+ * 0x0f, Vaux2Sel
+ */
+ REG_INIT(AB8505_VAUX2SEL, 0x04, 0x20, 0x0f),
+ /*
+ * 0x07, Vaux3Sel
+ * 0x30, VRF1Sel
+ */
+ REG_INIT(AB8505_VRF1VAUX3SEL, 0x04, 0x21, 0x37),
+ /*
+ * 0x03, Vaux4RequestCtrl
+ */
+ REG_INIT(AB8505_VAUX4REQCTRL, 0x04, 0x2d, 0x03),
+ /*
+ * 0x03, Vaux4Regu
+ */
+ REG_INIT(AB8505_VAUX4REGU, 0x04, 0x2e, 0x03),
+ /*
+ * 0x0f, Vaux4Sel
+ */
+ REG_INIT(AB8505_VAUX4SEL, 0x04, 0x2f, 0x0f),
+ /*
+ * 0x04, Vaux1Disch
+ * 0x08, Vaux2Disch
+ * 0x10, Vaux3Disch
+ * 0x20, Vintcore12Disch
+ * 0x40, VTVoutDisch
+ * 0x80, VaudioDisch
+ */
+ REG_INIT(AB8505_REGUCTRLDISCH, 0x04, 0x43, 0xfc),
+ /*
+ * 0x02, VanaDisch
+ * 0x04, VdmicPullDownEna
+ * 0x10, VdmicDisch
+ */
+ REG_INIT(AB8505_REGUCTRLDISCH2, 0x04, 0x44, 0x16),
+ /*
+ * 0x01, Vaux4Disch
+ */
+ REG_INIT(AB8505_REGUCTRLDISCH3, 0x04, 0x48, 0x01),
+ /*
+ * 0x07, Vaux5Sel
+ * 0x08, Vaux5LP
+ * 0x10, Vaux5Ena
+ * 0x20, Vaux5Disch
+ * 0x40, Vaux5DisSfst
+ * 0x80, Vaux5DisPulld
+ */
+ REG_INIT(AB8505_CTRLVAUX5, 0x01, 0x55, 0xff),
+ /*
+ * 0x07, Vaux6Sel
+ * 0x08, Vaux6LP
+ * 0x10, Vaux6Ena
+ * 0x80, Vaux6DisPulld
+ */
+ REG_INIT(AB8505_CTRLVAUX6, 0x01, 0x56, 0x9f),
+};
+
+/* AB9540 register init */
+static struct ab8500_reg_init ab9540_reg_init[] = {
+ /*
+ * 0x03, VarmRequestCtrl
+ * 0x0c, VapeRequestCtrl
+ * 0x30, Vsmps1RequestCtrl
+ * 0xc0, Vsmps2RequestCtrl
+ */
+ REG_INIT(AB9540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff),
+ /*
+ * 0x03, Vsmps3RequestCtrl
+ * 0x0c, VpllRequestCtrl
+ * 0x30, VanaRequestCtrl
+ * 0xc0, VextSupply1RequestCtrl
+ */
+ REG_INIT(AB9540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff),
+ /*
+ * 0x03, VextSupply2RequestCtrl
+ * 0x0c, VextSupply3RequestCtrl
+ * 0x30, Vaux1RequestCtrl
+ * 0xc0, Vaux2RequestCtrl
+ */
+ REG_INIT(AB9540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff),
+ /*
+ * 0x03, Vaux3RequestCtrl
+ * 0x04, SwHPReq
+ */
+ REG_INIT(AB9540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07),
+ /*
+ * 0x01, Vsmps1SysClkReq1HPValid
+ * 0x02, Vsmps2SysClkReq1HPValid
+ * 0x04, Vsmps3SysClkReq1HPValid
+ * 0x08, VanaSysClkReq1HPValid
+ * 0x10, VpllSysClkReq1HPValid
+ * 0x20, Vaux1SysClkReq1HPValid
+ * 0x40, Vaux2SysClkReq1HPValid
+ * 0x80, Vaux3SysClkReq1HPValid
+ */
+ REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff),
+ /*
+ * 0x01, VapeSysClkReq1HPValid
+ * 0x02, VarmSysClkReq1HPValid
+ * 0x04, VbbSysClkReq1HPValid
+ * 0x08, VmodSysClkReq1HPValid
+ * 0x10, VextSupply1SysClkReq1HPValid
+ * 0x20, VextSupply2SysClkReq1HPValid
+ * 0x40, VextSupply3SysClkReq1HPValid
+ */
+ REG_INIT(AB9540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f),
+ /*
+ * 0x01, Vsmps1HwHPReq1Valid
+ * 0x02, Vsmps2HwHPReq1Valid
+ * 0x04, Vsmps3HwHPReq1Valid
+ * 0x08, VanaHwHPReq1Valid
+ * 0x10, VpllHwHPReq1Valid
+ * 0x20, Vaux1HwHPReq1Valid
+ * 0x40, Vaux2HwHPReq1Valid
+ * 0x80, Vaux3HwHPReq1Valid
+ */
+ REG_INIT(AB9540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff),
+ /*
+ * 0x01, VextSupply1HwHPReq1Valid
+ * 0x02, VextSupply2HwHPReq1Valid
+ * 0x04, VextSupply3HwHPReq1Valid
+ * 0x08, VmodHwHPReq1Valid
+ */
+ REG_INIT(AB9540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f),
+ /*
+ * 0x01, Vsmps1HwHPReq2Valid
+ * 0x02, Vsmps2HwHPReq2Valid
+ * 0x03, Vsmps3HwHPReq2Valid
+ * 0x08, VanaHwHPReq2Valid
+ * 0x10, VpllHwHPReq2Valid
+ * 0x20, Vaux1HwHPReq2Valid
+ * 0x40, Vaux2HwHPReq2Valid
+ * 0x80, Vaux3HwHPReq2Valid
+ */
+ REG_INIT(AB9540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff),
+ /*
+ * 0x01, VextSupply1HwHPReq2Valid
+ * 0x02, VextSupply2HwHPReq2Valid
+ * 0x04, VextSupply3HwHPReq2Valid
+ * 0x08, VmodHwHPReq2Valid
+ */
+ REG_INIT(AB9540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f),
+ /*
+ * 0x01, VapeSwHPReqValid
+ * 0x02, VarmSwHPReqValid
+ * 0x04, Vsmps1SwHPReqValid
+ * 0x08, Vsmps2SwHPReqValid
+ * 0x10, Vsmps3SwHPReqValid
+ * 0x20, VanaSwHPReqValid
+ * 0x40, VpllSwHPReqValid
+ * 0x80, Vaux1SwHPReqValid
+ */
+ REG_INIT(AB9540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff),
+ /*
+ * 0x01, Vaux2SwHPReqValid
+ * 0x02, Vaux3SwHPReqValid
+ * 0x04, VextSupply1SwHPReqValid
+ * 0x08, VextSupply2SwHPReqValid
+ * 0x10, VextSupply3SwHPReqValid
+ * 0x20, VmodSwHPReqValid
+ */
+ REG_INIT(AB9540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f),
+ /*
+ * 0x02, SysClkReq2Valid1
+ * ...
+ * 0x80, SysClkReq8Valid1
+ */
+ REG_INIT(AB9540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe),
+ /*
+ * 0x02, SysClkReq2Valid2
+ * ...
+ * 0x80, SysClkReq8Valid2
+ */
+ REG_INIT(AB9540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe),
+ /*
+ * 0x01, Vaux4SwHPReqValid
+ * 0x02, Vaux4HwHPReq2Valid
+ * 0x04, Vaux4HwHPReq1Valid
+ * 0x08, Vaux4SysClkReq1HPValid
+ */
+ REG_INIT(AB9540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f),
+ /*
+ * 0x02, VTVoutEna
+ * 0x04, Vintcore12Ena
+ * 0x38, Vintcore12Sel
+ * 0x40, Vintcore12LP
+ * 0x80, VTVoutLP
+ */
+ REG_INIT(AB9540_REGUMISC1, 0x03, 0x80, 0xfe),
+ /*
+ * 0x02, VaudioEna
+ * 0x04, VdmicEna
+ * 0x08, Vamic1Ena
+ * 0x10, Vamic2Ena
+ */
+ REG_INIT(AB9540_VAUDIOSUPPLY, 0x03, 0x83, 0x1e),
+ /*
+ * 0x01, Vamic1_dzout
+ * 0x02, Vamic2_dzout
+ */
+ REG_INIT(AB9540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03),
+ /*
+ * 0x03, Vsmps1Regu
+ * 0x0c, Vsmps1SelCtrl
+ * 0x10, Vsmps1AutoMode
+ * 0x20, Vsmps1PWMMode
+ */
+ REG_INIT(AB9540_VSMPS1REGU, 0x04, 0x03, 0x3f),
+ /*
+ * 0x03, Vsmps2Regu
+ * 0x0c, Vsmps2SelCtrl
+ * 0x10, Vsmps2AutoMode
+ * 0x20, Vsmps2PWMMode
+ */
+ REG_INIT(AB9540_VSMPS2REGU, 0x04, 0x04, 0x3f),
+ /*
+ * 0x03, Vsmps3Regu
+ * 0x0c, Vsmps3SelCtrl
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB9540_VSMPS3REGU, 0x04, 0x05, 0x0f),
+ /*
+ * 0x03, VpllRegu
+ * 0x0c, VanaRegu
+ */
+ REG_INIT(AB9540_VPLLVANAREGU, 0x04, 0x06, 0x0f),
+ /*
+ * 0x03, VextSupply1Regu
+ * 0x0c, VextSupply2Regu
+ * 0x30, VextSupply3Regu
+ * 0x40, ExtSupply2Bypass
+ * 0x80, ExtSupply3Bypass
+ */
+ REG_INIT(AB9540_EXTSUPPLYREGU, 0x04, 0x08, 0xff),
+ /*
+ * 0x03, Vaux1Regu
+ * 0x0c, Vaux2Regu
+ */
+ REG_INIT(AB9540_VAUX12REGU, 0x04, 0x09, 0x0f),
+ /*
+ * 0x0c, Vrf1Regu
+ * 0x03, Vaux3Regu
+ */
+ REG_INIT(AB9540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f),
+ /*
+ * 0x3f, Vsmps1Sel1
+ */
+ REG_INIT(AB9540_VSMPS1SEL1, 0x04, 0x13, 0x3f),
+ /*
+ * 0x3f, Vsmps1Sel2
+ */
+ REG_INIT(AB9540_VSMPS1SEL2, 0x04, 0x14, 0x3f),
+ /*
+ * 0x3f, Vsmps1Sel3
+ */
+ REG_INIT(AB9540_VSMPS1SEL3, 0x04, 0x15, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel1
+ */
+ REG_INIT(AB9540_VSMPS2SEL1, 0x04, 0x17, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel2
+ */
+ REG_INIT(AB9540_VSMPS2SEL2, 0x04, 0x18, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel3
+ */
+ REG_INIT(AB9540_VSMPS2SEL3, 0x04, 0x19, 0x3f),
+ /*
+ * 0x7f, Vsmps3Sel1
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB9540_VSMPS3SEL1, 0x04, 0x1b, 0x7f),
+ /*
+ * 0x7f, Vsmps3Sel2
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB9540_VSMPS3SEL2, 0x04, 0x1c, 0x7f),
+ /*
+ * 0x0f, Vaux1Sel
+ */
+ REG_INIT(AB9540_VAUX1SEL, 0x04, 0x1f, 0x0f),
+ /*
+ * 0x0f, Vaux2Sel
+ */
+ REG_INIT(AB9540_VAUX2SEL, 0x04, 0x20, 0x0f),
+ /*
+ * 0x07, Vaux3Sel
+ * 0x30, Vrf1Sel
+ */
+ REG_INIT(AB9540_VRF1VAUX3SEL, 0x04, 0x21, 0x37),
+ /*
+ * 0x01, VextSupply12LP
+ */
+ REG_INIT(AB9540_REGUCTRL2SPARE, 0x04, 0x22, 0x01),
+ /*
+ * 0x03, Vaux4RequestCtrl
+ */
+ REG_INIT(AB9540_VAUX4REQCTRL, 0x04, 0x2d, 0x03),
+ /*
+ * 0x03, Vaux4Regu
+ */
+ REG_INIT(AB9540_VAUX4REGU, 0x04, 0x2e, 0x03),
+ /*
+ * 0x08, Vaux4Sel
+ */
+ REG_INIT(AB9540_VAUX4SEL, 0x04, 0x2f, 0x0f),
+ /*
+ * 0x01, VpllDisch
+ * 0x02, Vrf1Disch
+ * 0x04, Vaux1Disch
+ * 0x08, Vaux2Disch
+ * 0x10, Vaux3Disch
+ * 0x20, Vintcore12Disch
+ * 0x40, VTVoutDisch
+ * 0x80, VaudioDisch
+ */
+ REG_INIT(AB9540_REGUCTRLDISCH, 0x04, 0x43, 0xff),
+ /*
+ * 0x01, VsimDisch
+ * 0x02, VanaDisch
+ * 0x04, VdmicPullDownEna
+ * 0x08, VpllPullDownEna
+ * 0x10, VdmicDisch
+ */
+ REG_INIT(AB9540_REGUCTRLDISCH2, 0x04, 0x44, 0x1f),
+ /*
+ * 0x01, Vaux4Disch
+ */
+ REG_INIT(AB9540_REGUCTRLDISCH3, 0x04, 0x48, 0x01),
+};
+
+/* AB8540 register init */
+static struct ab8500_reg_init ab8540_reg_init[] = {
+ /*
+ * 0x01, VSimSycClkReq1Valid
+ * 0x02, VSimSycClkReq2Valid
+ * 0x04, VSimSycClkReq3Valid
+ * 0x08, VSimSycClkReq4Valid
+ * 0x10, VSimSycClkReq5Valid
+ * 0x20, VSimSycClkReq6Valid
+ * 0x40, VSimSycClkReq7Valid
+ * 0x80, VSimSycClkReq8Valid
+ */
+ REG_INIT(AB8540_VSIMSYSCLKCTRL, 0x02, 0x33, 0xff),
+ /*
+ * 0x03, VarmRequestCtrl
+ * 0x0c, VapeRequestCtrl
+ * 0x30, Vsmps1RequestCtrl
+ * 0xc0, Vsmps2RequestCtrl
+ */
+ REG_INIT(AB8540_REGUREQUESTCTRL1, 0x03, 0x03, 0xff),
+ /*
+ * 0x03, Vsmps3RequestCtrl
+ * 0x0c, VpllRequestCtrl
+ * 0x30, VanaRequestCtrl
+ * 0xc0, VextSupply1RequestCtrl
+ */
+ REG_INIT(AB8540_REGUREQUESTCTRL2, 0x03, 0x04, 0xff),
+ /*
+ * 0x03, VextSupply2RequestCtrl
+ * 0x0c, VextSupply3RequestCtrl
+ * 0x30, Vaux1RequestCtrl
+ * 0xc0, Vaux2RequestCtrl
+ */
+ REG_INIT(AB8540_REGUREQUESTCTRL3, 0x03, 0x05, 0xff),
+ /*
+ * 0x03, Vaux3RequestCtrl
+ * 0x04, SwHPReq
+ */
+ REG_INIT(AB8540_REGUREQUESTCTRL4, 0x03, 0x06, 0x07),
+ /*
+ * 0x01, Vsmps1SysClkReq1HPValid
+ * 0x02, Vsmps2SysClkReq1HPValid
+ * 0x04, Vsmps3SysClkReq1HPValid
+ * 0x08, VanaSysClkReq1HPValid
+ * 0x10, VpllSysClkReq1HPValid
+ * 0x20, Vaux1SysClkReq1HPValid
+ * 0x40, Vaux2SysClkReq1HPValid
+ * 0x80, Vaux3SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff),
+ /*
+ * 0x01, VapeSysClkReq1HPValid
+ * 0x02, VarmSysClkReq1HPValid
+ * 0x04, VbbSysClkReq1HPValid
+ * 0x10, VextSupply1SysClkReq1HPValid
+ * 0x20, VextSupply2SysClkReq1HPValid
+ * 0x40, VextSupply3SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x77),
+ /*
+ * 0x01, Vsmps1HwHPReq1Valid
+ * 0x02, Vsmps2HwHPReq1Valid
+ * 0x04, Vsmps3HwHPReq1Valid
+ * 0x08, VanaHwHPReq1Valid
+ * 0x10, VpllHwHPReq1Valid
+ * 0x20, Vaux1HwHPReq1Valid
+ * 0x40, Vaux2HwHPReq1Valid
+ * 0x80, Vaux3HwHPReq1Valid
+ */
+ REG_INIT(AB8540_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff),
+ /*
+ * 0x01, VextSupply1HwHPReq1Valid
+ * 0x02, VextSupply2HwHPReq1Valid
+ * 0x04, VextSupply3HwHPReq1Valid
+ */
+ REG_INIT(AB8540_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07),
+ /*
+ * 0x01, Vsmps1HwHPReq2Valid
+ * 0x02, Vsmps2HwHPReq2Valid
+ * 0x03, Vsmps3HwHPReq2Valid
+ * 0x08, VanaHwHPReq2Valid
+ * 0x10, VpllHwHPReq2Valid
+ * 0x20, Vaux1HwHPReq2Valid
+ * 0x40, Vaux2HwHPReq2Valid
+ * 0x80, Vaux3HwHPReq2Valid
+ */
+ REG_INIT(AB8540_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff),
+ /*
+ * 0x01, VextSupply1HwHPReq2Valid
+ * 0x02, VextSupply2HwHPReq2Valid
+ * 0x04, VextSupply3HwHPReq2Valid
+ */
+ REG_INIT(AB8540_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07),
+ /*
+ * 0x01, VapeSwHPReqValid
+ * 0x02, VarmSwHPReqValid
+ * 0x04, Vsmps1SwHPReqValid
+ * 0x08, Vsmps2SwHPReqValid
+ * 0x10, Vsmps3SwHPReqValid
+ * 0x20, VanaSwHPReqValid
+ * 0x40, VpllSwHPReqValid
+ * 0x80, Vaux1SwHPReqValid
+ */
+ REG_INIT(AB8540_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff),
+ /*
+ * 0x01, Vaux2SwHPReqValid
+ * 0x02, Vaux3SwHPReqValid
+ * 0x04, VextSupply1SwHPReqValid
+ * 0x08, VextSupply2SwHPReqValid
+ * 0x10, VextSupply3SwHPReqValid
+ */
+ REG_INIT(AB8540_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f),
+ /*
+ * 0x02, SysClkReq2Valid1
+ * ...
+ * 0x80, SysClkReq8Valid1
+ */
+ REG_INIT(AB8540_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xff),
+ /*
+ * 0x02, SysClkReq2Valid2
+ * ...
+ * 0x80, SysClkReq8Valid2
+ */
+ REG_INIT(AB8540_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xff),
+ /*
+ * 0x01, Vaux4SwHPReqValid
+ * 0x02, Vaux4HwHPReq2Valid
+ * 0x04, Vaux4HwHPReq1Valid
+ * 0x08, Vaux4SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUVAUX4REQVALID, 0x03, 0x11, 0x0f),
+ /*
+ * 0x01, Vaux5SwHPReqValid
+ * 0x02, Vaux5HwHPReq2Valid
+ * 0x04, Vaux5HwHPReq1Valid
+ * 0x08, Vaux5SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUVAUX5REQVALID, 0x03, 0x12, 0x0f),
+ /*
+ * 0x01, Vaux6SwHPReqValid
+ * 0x02, Vaux6HwHPReq2Valid
+ * 0x04, Vaux6HwHPReq1Valid
+ * 0x08, Vaux6SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUVAUX6REQVALID, 0x03, 0x13, 0x0f),
+ /*
+ * 0x01, VclkbSwHPReqValid
+ * 0x02, VclkbHwHPReq2Valid
+ * 0x04, VclkbHwHPReq1Valid
+ * 0x08, VclkbSysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUVCLKBREQVALID, 0x03, 0x14, 0x0f),
+ /*
+ * 0x01, Vrf1SwHPReqValid
+ * 0x02, Vrf1HwHPReq2Valid
+ * 0x04, Vrf1HwHPReq1Valid
+ * 0x08, Vrf1SysClkReq1HPValid
+ */
+ REG_INIT(AB8540_REGUVRF1REQVALID, 0x03, 0x15, 0x0f),
+ /*
+ * 0x02, VTVoutEna
+ * 0x04, Vintcore12Ena
+ * 0x38, Vintcore12Sel
+ * 0x40, Vintcore12LP
+ * 0x80, VTVoutLP
+ */
+ REG_INIT(AB8540_REGUMISC1, 0x03, 0x80, 0xfe),
+ /*
+ * 0x02, VaudioEna
+ * 0x04, VdmicEna
+ * 0x08, Vamic1Ena
+ * 0x10, Vamic2Ena
+ * 0x20, Vamic12LP
+ * 0xC0, VdmicSel
+ */
+ REG_INIT(AB8540_VAUDIOSUPPLY, 0x03, 0x83, 0xfe),
+ /*
+ * 0x01, Vamic1_dzout
+ * 0x02, Vamic2_dzout
+ */
+ REG_INIT(AB8540_REGUCTRL1VAMIC, 0x03, 0x84, 0x03),
+ /*
+ * 0x07, VHSICSel
+ * 0x08, VHSICOffState
+ * 0x10, VHSIEna
+ * 0x20, VHSICLP
+ */
+ REG_INIT(AB8540_VHSIC, 0x03, 0x87, 0x3f),
+ /*
+ * 0x07, VSDIOSel
+ * 0x08, VSDIOOffState
+ * 0x10, VSDIOEna
+ * 0x20, VSDIOLP
+ */
+ REG_INIT(AB8540_VSDIO, 0x03, 0x88, 0x3f),
+ /*
+ * 0x03, Vsmps1Regu
+ * 0x0c, Vsmps1SelCtrl
+ * 0x10, Vsmps1AutoMode
+ * 0x20, Vsmps1PWMMode
+ */
+ REG_INIT(AB8540_VSMPS1REGU, 0x04, 0x03, 0x3f),
+ /*
+ * 0x03, Vsmps2Regu
+ * 0x0c, Vsmps2SelCtrl
+ * 0x10, Vsmps2AutoMode
+ * 0x20, Vsmps2PWMMode
+ */
+ REG_INIT(AB8540_VSMPS2REGU, 0x04, 0x04, 0x3f),
+ /*
+ * 0x03, Vsmps3Regu
+ * 0x0c, Vsmps3SelCtrl
+ * 0x10, Vsmps3AutoMode
+ * 0x20, Vsmps3PWMMode
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB8540_VSMPS3REGU, 0x04, 0x05, 0x0f),
+ /*
+ * 0x03, VpllRegu
+ * 0x0c, VanaRegu
+ */
+ REG_INIT(AB8540_VPLLVANAREGU, 0x04, 0x06, 0x0f),
+ /*
+ * 0x03, VextSupply1Regu
+ * 0x0c, VextSupply2Regu
+ * 0x30, VextSupply3Regu
+ * 0x40, ExtSupply2Bypass
+ * 0x80, ExtSupply3Bypass
+ */
+ REG_INIT(AB8540_EXTSUPPLYREGU, 0x04, 0x08, 0xff),
+ /*
+ * 0x03, Vaux1Regu
+ * 0x0c, Vaux2Regu
+ */
+ REG_INIT(AB8540_VAUX12REGU, 0x04, 0x09, 0x0f),
+ /*
+ * 0x0c, VRF1Regu
+ * 0x03, Vaux3Regu
+ */
+ REG_INIT(AB8540_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f),
+ /*
+ * 0x3f, Vsmps1Sel1
+ */
+ REG_INIT(AB8540_VSMPS1SEL1, 0x04, 0x13, 0x3f),
+ /*
+ * 0x3f, Vsmps1Sel2
+ */
+ REG_INIT(AB8540_VSMPS1SEL2, 0x04, 0x14, 0x3f),
+ /*
+ * 0x3f, Vsmps1Sel3
+ */
+ REG_INIT(AB8540_VSMPS1SEL3, 0x04, 0x15, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel1
+ */
+ REG_INIT(AB8540_VSMPS2SEL1, 0x04, 0x17, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel2
+ */
+ REG_INIT(AB8540_VSMPS2SEL2, 0x04, 0x18, 0x3f),
+ /*
+ * 0x3f, Vsmps2Sel3
+ */
+ REG_INIT(AB8540_VSMPS2SEL3, 0x04, 0x19, 0x3f),
+ /*
+ * 0x7f, Vsmps3Sel1
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB8540_VSMPS3SEL1, 0x04, 0x1b, 0x7f),
+ /*
+ * 0x7f, Vsmps3Sel2
+ * NOTE! PRCMU register
+ */
+ REG_INIT(AB8540_VSMPS3SEL2, 0x04, 0x1c, 0x7f),
+ /*
+ * 0x0f, Vaux1Sel
+ */
+ REG_INIT(AB8540_VAUX1SEL, 0x04, 0x1f, 0x0f),
+ /*
+ * 0x0f, Vaux2Sel
+ */
+ REG_INIT(AB8540_VAUX2SEL, 0x04, 0x20, 0x0f),
+ /*
+ * 0x07, Vaux3Sel
+ * 0x70, Vrf1Sel
+ */
+ REG_INIT(AB8540_VRF1VAUX3SEL, 0x04, 0x21, 0x77),
+ /*
+ * 0x01, VextSupply12LP
+ */
+ REG_INIT(AB8540_REGUCTRL2SPARE, 0x04, 0x22, 0x01),
+ /*
+ * 0x07, Vanasel
+ * 0x30, Vpllsel
+ */
+ REG_INIT(AB8540_VANAVPLLSEL, 0x04, 0x29, 0x37),
+ /*
+ * 0x03, Vaux4RequestCtrl
+ */
+ REG_INIT(AB8540_VAUX4REQCTRL, 0x04, 0x2d, 0x03),
+ /*
+ * 0x03, Vaux4Regu
+ */
+ REG_INIT(AB8540_VAUX4REGU, 0x04, 0x2e, 0x03),
+ /*
+ * 0x0f, Vaux4Sel
+ */
+ REG_INIT(AB8540_VAUX4SEL, 0x04, 0x2f, 0x0f),
+ /*
+ * 0x03, Vaux5RequestCtrl
+ */
+ REG_INIT(AB8540_VAUX5REQCTRL, 0x04, 0x31, 0x03),
+ /*
+ * 0x03, Vaux5Regu
+ */
+ REG_INIT(AB8540_VAUX5REGU, 0x04, 0x32, 0x03),
+ /*
+ * 0x3f, Vaux5Sel
+ */
+ REG_INIT(AB8540_VAUX5SEL, 0x04, 0x33, 0x3f),
+ /*
+ * 0x03, Vaux6RequestCtrl
+ */
+ REG_INIT(AB8540_VAUX6REQCTRL, 0x04, 0x34, 0x03),
+ /*
+ * 0x03, Vaux6Regu
+ */
+ REG_INIT(AB8540_VAUX6REGU, 0x04, 0x35, 0x03),
+ /*
+ * 0x3f, Vaux6Sel
+ */
+ REG_INIT(AB8540_VAUX6SEL, 0x04, 0x36, 0x3f),
+ /*
+ * 0x03, VCLKBRequestCtrl
+ */
+ REG_INIT(AB8540_VCLKBREQCTRL, 0x04, 0x37, 0x03),
+ /*
+ * 0x03, VCLKBRegu
+ */
+ REG_INIT(AB8540_VCLKBREGU, 0x04, 0x38, 0x03),
+ /*
+ * 0x07, VCLKBSel
+ */
+ REG_INIT(AB8540_VCLKBSEL, 0x04, 0x39, 0x07),
+ /*
+ * 0x03, Vrf1RequestCtrl
+ */
+ REG_INIT(AB8540_VRF1REQCTRL, 0x04, 0x3a, 0x03),
+ /*
+ * 0x01, VpllDisch
+ * 0x02, Vrf1Disch
+ * 0x04, Vaux1Disch
+ * 0x08, Vaux2Disch
+ * 0x10, Vaux3Disch
+ * 0x20, Vintcore12Disch
+ * 0x40, VTVoutDisch
+ * 0x80, VaudioDisch
+ */
+ REG_INIT(AB8540_REGUCTRLDISCH, 0x04, 0x43, 0xff),
+ /*
+ * 0x02, VanaDisch
+ * 0x04, VdmicPullDownEna
+ * 0x08, VpllPullDownEna
+ * 0x10, VdmicDisch
+ */
+ REG_INIT(AB8540_REGUCTRLDISCH2, 0x04, 0x44, 0x1e),
+ /*
+ * 0x01, Vaux4Disch
+ */
+ REG_INIT(AB8540_REGUCTRLDISCH3, 0x04, 0x48, 0x01),
+ /*
+ * 0x01, Vaux5Disch
+ * 0x02, Vaux6Disch
+ * 0x04, VCLKBDisch
+ */
+ REG_INIT(AB8540_REGUCTRLDISCH4, 0x04, 0x49, 0x07),
+};
+
+static struct of_regulator_match ab8500_regulator_match[] = {
+ { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8500_LDO_AUX1, },
+ { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8500_LDO_AUX2, },
+ { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8500_LDO_AUX3, },
+ { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8500_LDO_INTCORE, },
+ { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8500_LDO_TVOUT, },
+ { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8500_LDO_AUDIO, },
+ { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8500_LDO_ANAMIC1, },
+ { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, },
+ { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8500_LDO_DMIC, },
+ { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, },
+};
+
+static struct of_regulator_match ab8505_regulator_match[] = {
+ { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8505_LDO_AUX1, },
+ { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8505_LDO_AUX2, },
+ { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8505_LDO_AUX3, },
+ { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8505_LDO_AUX4, },
+ { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8505_LDO_AUX5, },
+ { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8505_LDO_AUX6, },
+ { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8505_LDO_INTCORE, },
+ { .name = "ab8500_ldo_adc", .driver_data = (void *) AB8505_LDO_ADC, },
+ { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8505_LDO_AUDIO, },
+ { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8505_LDO_ANAMIC1, },
+ { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8505_LDO_ANAMIC2, },
+ { .name = "ab8500_ldo_aux8", .driver_data = (void *) AB8505_LDO_AUX8, },
+ { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8505_LDO_ANA, },
+};
+
+static struct of_regulator_match ab8540_regulator_match[] = {
+ { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8540_LDO_AUX1, },
+ { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8540_LDO_AUX2, },
+ { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8540_LDO_AUX3, },
+ { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB8540_LDO_AUX4, },
+ { .name = "ab8500_ldo_aux5", .driver_data = (void *) AB8540_LDO_AUX5, },
+ { .name = "ab8500_ldo_aux6", .driver_data = (void *) AB8540_LDO_AUX6, },
+ { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8540_LDO_INTCORE, },
+ { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8540_LDO_TVOUT, },
+ { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8540_LDO_AUDIO, },
+ { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8540_LDO_ANAMIC1, },
+ { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8540_LDO_ANAMIC2, },
+ { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8540_LDO_DMIC, },
+ { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8540_LDO_ANA, },
+ { .name = "ab8500_ldo_sdio", .driver_data = (void *) AB8540_LDO_SDIO, },
+};
+
+static struct of_regulator_match ab9540_regulator_match[] = {
+ { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB9540_LDO_AUX1, },
+ { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB9540_LDO_AUX2, },
+ { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB9540_LDO_AUX3, },
+ { .name = "ab8500_ldo_aux4", .driver_data = (void *) AB9540_LDO_AUX4, },
+ { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB9540_LDO_INTCORE, },
+ { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB9540_LDO_TVOUT, },
+ { .name = "ab8500_ldo_audio", .driver_data = (void *) AB9540_LDO_AUDIO, },
+ { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB9540_LDO_ANAMIC1, },
+ { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB9540_LDO_ANAMIC2, },
+ { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB9540_LDO_DMIC, },
+ { .name = "ab8500_ldo_ana", .driver_data = (void *) AB9540_LDO_ANA, },
+};
+
+static struct {
+ struct ab8500_regulator_info *info;
+ int info_size;
+ struct ab8500_reg_init *init;
+ int init_size;
+ struct of_regulator_match *match;
+ int match_size;
+} abx500_regulator;
+
+static void abx500_get_regulator_info(struct ab8500 *ab8500)
+{
+ if (is_ab9540(ab8500)) {
+ abx500_regulator.info = ab9540_regulator_info;
+ abx500_regulator.info_size = ARRAY_SIZE(ab9540_regulator_info);
+ abx500_regulator.init = ab9540_reg_init;
+ abx500_regulator.init_size = AB9540_NUM_REGULATOR_REGISTERS;
+ abx500_regulator.match = ab9540_regulator_match;
+ abx500_regulator.match_size = ARRAY_SIZE(ab9540_regulator_match);
+ } else if (is_ab8505(ab8500)) {
+ abx500_regulator.info = ab8505_regulator_info;
+ abx500_regulator.info_size = ARRAY_SIZE(ab8505_regulator_info);
+ abx500_regulator.init = ab8505_reg_init;
+ abx500_regulator.init_size = AB8505_NUM_REGULATOR_REGISTERS;
+ abx500_regulator.match = ab8505_regulator_match;
+ abx500_regulator.match_size = ARRAY_SIZE(ab8505_regulator_match);
+ } else if (is_ab8540(ab8500)) {
+ abx500_regulator.info = ab8540_regulator_info;
+ abx500_regulator.info_size = ARRAY_SIZE(ab8540_regulator_info);
+ abx500_regulator.init = ab8540_reg_init;
+ abx500_regulator.init_size = AB8540_NUM_REGULATOR_REGISTERS;
+ abx500_regulator.match = ab8540_regulator_match;
+ abx500_regulator.match_size = ARRAY_SIZE(ab8540_regulator_match);
+ } else {
+ abx500_regulator.info = ab8500_regulator_info;
+ abx500_regulator.info_size = ARRAY_SIZE(ab8500_regulator_info);
+ abx500_regulator.init = ab8500_reg_init;
+ abx500_regulator.init_size = AB8500_NUM_REGULATOR_REGISTERS;
+ abx500_regulator.match = ab8500_regulator_match;
+ abx500_regulator.match_size = ARRAY_SIZE(ab8500_regulator_match);
+ }
+}
+
+static int ab8500_regulator_init_registers(struct platform_device *pdev,
+ int id, int mask, int value)
{
+ struct ab8500_reg_init *reg_init = abx500_regulator.init;
int err;
- if (value & ~ab8500_reg_init[id].mask) {
- dev_err(&pdev->dev,
- "Configuration error: value outside mask.\n");
- return -EINVAL;
- }
+ BUG_ON(value & ~mask);
+ BUG_ON(mask & ~reg_init[id].mask);
+ /* initialize register */
err = abx500_mask_and_set_register_interruptible(
&pdev->dev,
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr,
- ab8500_reg_init[id].mask,
- value);
+ reg_init[id].bank,
+ reg_init[id].addr,
+ mask, value);
if (err < 0) {
dev_err(&pdev->dev,
"Failed to initialize 0x%02x, 0x%02x.\n",
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr);
+ reg_init[id].bank,
+ reg_init[id].addr);
return err;
}
-
dev_vdbg(&pdev->dev,
- "init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
- ab8500_reg_init[id].bank,
- ab8500_reg_init[id].addr,
- ab8500_reg_init[id].mask,
- value);
+ " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
+ reg_init[id].bank,
+ reg_init[id].addr,
+ mask, value);
return 0;
}
static int ab8500_regulator_register(struct platform_device *pdev,
- struct regulator_init_data *init_data,
- int id,
- struct device_node *np)
+ struct regulator_init_data *init_data,
+ int id, struct device_node *np)
{
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_regulator_info *info = NULL;
struct regulator_config config = { };
int err;
/* assign per-regulator data */
- info = &ab8500_regulator_info[id];
+ info = &abx500_regulator.info[id];
info->dev = &pdev->dev;
config.dev = &pdev->dev;
@@ -695,7 +3045,7 @@ static int ab8500_regulator_register(struct platform_device *pdev,
config.of_node = np;
/* fix for hardware before ab8500v2.0 */
- if (abx500_get_chip_id(info->dev) < 0x20) {
+ if (is_ab8500_1p1_or_earlier(ab8500)) {
if (info->desc.id == AB8500_LDO_AUX3) {
info->desc.n_voltages =
ARRAY_SIZE(ldo_vauxn_voltages);
@@ -712,7 +3062,7 @@ static int ab8500_regulator_register(struct platform_device *pdev,
info->desc.name);
/* when we fail, un-register all earlier regulators */
while (--id >= 0) {
- info = &ab8500_regulator_info[id];
+ info = &abx500_regulator.info[id];
regulator_unregister(info->regulator);
}
return err;
@@ -721,29 +3071,16 @@ static int ab8500_regulator_register(struct platform_device *pdev,
return 0;
}
-static struct of_regulator_match ab8500_regulator_matches[] = {
- { .name = "ab8500_ldo_aux1", .driver_data = (void *) AB8500_LDO_AUX1, },
- { .name = "ab8500_ldo_aux2", .driver_data = (void *) AB8500_LDO_AUX2, },
- { .name = "ab8500_ldo_aux3", .driver_data = (void *) AB8500_LDO_AUX3, },
- { .name = "ab8500_ldo_intcore", .driver_data = (void *) AB8500_LDO_INTCORE, },
- { .name = "ab8500_ldo_tvout", .driver_data = (void *) AB8500_LDO_TVOUT, },
- { .name = "ab8500_ldo_usb", .driver_data = (void *) AB8500_LDO_USB, },
- { .name = "ab8500_ldo_audio", .driver_data = (void *) AB8500_LDO_AUDIO, },
- { .name = "ab8500_ldo_anamic1", .driver_data = (void *) AB8500_LDO_ANAMIC1, },
- { .name = "ab8500_ldo_amamic2", .driver_data = (void *) AB8500_LDO_ANAMIC2, },
- { .name = "ab8500_ldo_dmic", .driver_data = (void *) AB8500_LDO_DMIC, },
- { .name = "ab8500_ldo_ana", .driver_data = (void *) AB8500_LDO_ANA, },
-};
-
static int
-ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
+ab8500_regulator_of_probe(struct platform_device *pdev,
+ struct device_node *np)
{
+ struct of_regulator_match *match = abx500_regulator.match;
int err, i;
- for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ for (i = 0; i < abx500_regulator.info_size; i++) {
err = ab8500_regulator_register(
- pdev, ab8500_regulator_matches[i].init_data,
- i, ab8500_regulator_matches[i].of_node);
+ pdev, match[i].init_data, i, match[i].of_node);
if (err)
return err;
}
@@ -754,14 +3091,22 @@ ab8500_regulator_of_probe(struct platform_device *pdev, struct device_node *np)
static int ab8500_regulator_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- struct ab8500_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
+ struct ab8500_platform_data *ppdata;
+ struct ab8500_regulator_platform_data *pdata;
int i, err;
+ if (!ab8500) {
+ dev_err(&pdev->dev, "null mfd parent\n");
+ return -EINVAL;
+ }
+
+ abx500_get_regulator_info(ab8500);
+
if (np) {
err = of_regulator_match(&pdev->dev, np,
- ab8500_regulator_matches,
- ARRAY_SIZE(ab8500_regulator_matches));
+ abx500_regulator.match,
+ abx500_regulator.match_size);
if (err < 0) {
dev_err(&pdev->dev,
"Error parsing regulator init data: %d\n", err);
@@ -772,46 +3117,61 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
return err;
}
- if (!ab8500) {
- dev_err(&pdev->dev, "null mfd parent\n");
+ ppdata = dev_get_platdata(ab8500->dev);
+ if (!ppdata) {
+ dev_err(&pdev->dev, "null parent pdata\n");
return -EINVAL;
}
- pdata = dev_get_platdata(ab8500->dev);
+
+ pdata = ppdata->regulator;
if (!pdata) {
dev_err(&pdev->dev, "null pdata\n");
return -EINVAL;
}
/* make sure the platform data has the correct size */
- if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) {
+ if (pdata->num_regulator != abx500_regulator.info_size) {
dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
return -EINVAL;
}
+ /* initialize debug (initial state is recorded with this call) */
+ err = ab8500_regulator_debug_init(pdev);
+ if (err)
+ return err;
+
/* initialize registers */
- for (i = 0; i < pdata->num_regulator_reg_init; i++) {
- int id, value;
+ for (i = 0; i < pdata->num_reg_init; i++) {
+ int id, mask, value;
- id = pdata->regulator_reg_init[i].id;
- value = pdata->regulator_reg_init[i].value;
+ id = pdata->reg_init[i].id;
+ mask = pdata->reg_init[i].mask;
+ value = pdata->reg_init[i].value;
/* check for configuration errors */
- if (id >= AB8500_NUM_REGULATOR_REGISTERS) {
- dev_err(&pdev->dev,
- "Configuration error: id outside range.\n");
- return -EINVAL;
- }
+ BUG_ON(id >= abx500_regulator.init_size);
- err = ab8500_regulator_init_registers(pdev, id, value);
+ err = ab8500_regulator_init_registers(pdev, id, mask, value);
if (err < 0)
return err;
}
+ if (!is_ab8505(ab8500)) {
+ /* register external regulators (before Vaux1, 2 and 3) */
+ err = ab8500_ext_regulator_init(pdev);
+ if (err)
+ return err;
+ }
+
/* register all regulators */
- for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
- err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL);
- if (err < 0)
+ for (i = 0; i < abx500_regulator.info_size; i++) {
+ err = ab8500_regulator_register(pdev, &pdata->regulator[i],
+ i, NULL);
+ if (err < 0) {
+ if (!is_ab8505(ab8500))
+ ab8500_ext_regulator_exit(pdev);
return err;
+ }
}
return 0;
@@ -819,11 +3179,12 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
static int ab8500_regulator_remove(struct platform_device *pdev)
{
- int i;
+ int i, err;
+ struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
- for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
+ for (i = 0; i < abx500_regulator.info_size; i++) {
struct ab8500_regulator_info *info = NULL;
- info = &ab8500_regulator_info[i];
+ info = &abx500_regulator.info[i];
dev_vdbg(rdev_get_dev(info->regulator),
"%s-remove\n", info->desc.name);
@@ -831,6 +3192,15 @@ static int ab8500_regulator_remove(struct platform_device *pdev)
regulator_unregister(info->regulator);
}
+ /* remove external regulators (after Vaux1, 2 and 3) */
+ if (!is_ab8505(ab8500))
+ ab8500_ext_regulator_exit(pdev);
+
+ /* remove regulator debug */
+ err = ab8500_regulator_debug_exit(pdev);
+ if (err)
+ return err;
+
return 0;
}
@@ -863,5 +3233,7 @@ module_exit(ab8500_regulator_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>");
+MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
+MODULE_AUTHOR("Daniel Willerud <daniel.willerud@stericsson.com>");
MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC");
MODULE_ALIAS("platform:ab8500-regulator");
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index ed7beec53af8..81d8681c3195 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -131,7 +131,7 @@ static const struct regulator_desc arizona_ldo1_hc = {
.min_uV = 900000,
.uV_step = 50000,
.n_voltages = 8,
- .enable_time = 500,
+ .enable_time = 1500,
.owner = THIS_MODULE,
};
diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c
index f0ba8c4eefa9..3da6bd6950cf 100644
--- a/drivers/regulator/as3711-regulator.c
+++ b/drivers/regulator/as3711-regulator.c
@@ -13,9 +13,11 @@
#include <linux/init.h>
#include <linux/mfd/as3711.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
struct as3711_regulator_info {
@@ -276,6 +278,53 @@ static struct as3711_regulator_info as3711_reg_info[] = {
#define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info)
+static struct of_regulator_match
+as3711_regulator_matches[AS3711_REGULATOR_NUM] = {
+ [AS3711_REGULATOR_SD_1] = { .name = "sd1" },
+ [AS3711_REGULATOR_SD_2] = { .name = "sd2" },
+ [AS3711_REGULATOR_SD_3] = { .name = "sd3" },
+ [AS3711_REGULATOR_SD_4] = { .name = "sd4" },
+ [AS3711_REGULATOR_LDO_1] = { .name = "ldo1" },
+ [AS3711_REGULATOR_LDO_2] = { .name = "ldo2" },
+ [AS3711_REGULATOR_LDO_3] = { .name = "ldo3" },
+ [AS3711_REGULATOR_LDO_4] = { .name = "ldo4" },
+ [AS3711_REGULATOR_LDO_5] = { .name = "ldo5" },
+ [AS3711_REGULATOR_LDO_6] = { .name = "ldo6" },
+ [AS3711_REGULATOR_LDO_7] = { .name = "ldo7" },
+ [AS3711_REGULATOR_LDO_8] = { .name = "ldo8" },
+};
+
+static int as3711_regulator_parse_dt(struct device *dev,
+ struct device_node **of_node, const int count)
+{
+ struct as3711_regulator_pdata *pdata = dev_get_platdata(dev);
+ struct device_node *regulators =
+ of_find_node_by_name(dev->parent->of_node, "regulators");
+ struct of_regulator_match *match;
+ int ret, i;
+
+ if (!regulators) {
+ dev_err(dev, "regulator node not found\n");
+ return -ENODEV;
+ }
+
+ ret = of_regulator_match(dev->parent, regulators,
+ as3711_regulator_matches, count);
+ of_node_put(regulators);
+ if (ret < 0) {
+ dev_err(dev, "Error parsing regulator init data: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0, match = as3711_regulator_matches; i < count; i++, match++)
+ if (match->of_node) {
+ pdata->init_data[i] = match->init_data;
+ of_node[i] = match->of_node;
+ }
+
+ return 0;
+}
+
static int as3711_regulator_probe(struct platform_device *pdev)
{
struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -284,13 +333,24 @@ static int as3711_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {.dev = &pdev->dev,};
struct as3711_regulator *reg = NULL;
struct as3711_regulator *regs;
+ struct device_node *of_node[AS3711_REGULATOR_NUM] = {};
struct regulator_dev *rdev;
struct as3711_regulator_info *ri;
int ret;
int id;
- if (!pdata)
- dev_dbg(&pdev->dev, "No platform data...\n");
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data...\n");
+ return -ENODEV;
+ }
+
+ if (pdev->dev.parent->of_node) {
+ ret = as3711_regulator_parse_dt(&pdev->dev, of_node, AS3711_REGULATOR_NUM);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+ return ret;
+ }
+ }
regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM *
sizeof(struct as3711_regulator), GFP_KERNEL);
@@ -300,7 +360,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
}
for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) {
- reg_data = pdata ? pdata->init_data[id] : NULL;
+ reg_data = pdata->init_data[id];
/* No need to register if there is no regulator data */
if (!reg_data)
@@ -312,6 +372,7 @@ static int as3711_regulator_probe(struct platform_device *pdev)
config.init_data = reg_data;
config.driver_data = reg;
config.regmap = as3711->regmap;
+ config.of_node = of_node[id];
rdev = regulator_register(&ri->desc, &config);
if (IS_ERR(rdev)) {
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e3661c20cf38..6e5017841582 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -51,6 +51,7 @@
static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
+static LIST_HEAD(regulator_ena_gpio_list);
static bool has_full_constraints;
static bool board_wants_dummy_regulator;
@@ -69,6 +70,19 @@ struct regulator_map {
};
/*
+ * struct regulator_enable_gpio
+ *
+ * Management for shared enable GPIO pin
+ */
+struct regulator_enable_gpio {
+ struct list_head list;
+ int gpio;
+ u32 enable_count; /* a number of enabled shared GPIO */
+ u32 request_count; /* a number of requested shared GPIO */
+ unsigned int ena_gpio_invert:1;
+};
+
+/*
* struct regulator
*
* One for each consumer device.
@@ -116,7 +130,7 @@ static const char *rdev_get_name(struct regulator_dev *rdev)
* @supply: regulator supply name
*
* Extract the regulator device node corresponding to the supply name.
- * retruns the device node corresponding to the regulator if found, else
+ * returns the device node corresponding to the regulator if found, else
* returns NULL.
*/
static struct device_node *of_get_regulator(struct device *dev, const char *supply)
@@ -1229,7 +1243,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
struct regulator_dev *rdev;
struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
const char *devname = NULL;
- int ret;
+ int ret = 0;
if (id == NULL) {
pr_err("get() with no identifier\n");
@@ -1245,6 +1259,15 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
if (rdev)
goto found;
+ /*
+ * If we have return value from dev_lookup fail, we do not expect to
+ * succeed, so, quit with appropriate error value
+ */
+ if (ret) {
+ regulator = ERR_PTR(ret);
+ goto out;
+ }
+
if (board_wants_dummy_regulator) {
rdev = dummy_regulator_rdev;
goto found;
@@ -1456,6 +1479,101 @@ void devm_regulator_put(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(devm_regulator_put);
+/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */
+static int regulator_ena_gpio_request(struct regulator_dev *rdev,
+ const struct regulator_config *config)
+{
+ struct regulator_enable_gpio *pin;
+ int ret;
+
+ list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
+ if (pin->gpio == config->ena_gpio) {
+ rdev_dbg(rdev, "GPIO %d is already used\n",
+ config->ena_gpio);
+ goto update_ena_gpio_to_rdev;
+ }
+ }
+
+ ret = gpio_request_one(config->ena_gpio,
+ GPIOF_DIR_OUT | config->ena_gpio_flags,
+ rdev_get_name(rdev));
+ if (ret)
+ return ret;
+
+ pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
+ if (pin == NULL) {
+ gpio_free(config->ena_gpio);
+ return -ENOMEM;
+ }
+
+ pin->gpio = config->ena_gpio;
+ pin->ena_gpio_invert = config->ena_gpio_invert;
+ list_add(&pin->list, &regulator_ena_gpio_list);
+
+update_ena_gpio_to_rdev:
+ pin->request_count++;
+ rdev->ena_pin = pin;
+ return 0;
+}
+
+static void regulator_ena_gpio_free(struct regulator_dev *rdev)
+{
+ struct regulator_enable_gpio *pin, *n;
+
+ if (!rdev->ena_pin)
+ return;
+
+ /* Free the GPIO only in case of no use */
+ list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
+ if (pin->gpio == rdev->ena_pin->gpio) {
+ if (pin->request_count <= 1) {
+ pin->request_count = 0;
+ gpio_free(pin->gpio);
+ list_del(&pin->list);
+ kfree(pin);
+ } else {
+ pin->request_count--;
+ }
+ }
+ }
+}
+
+/**
+ * Balance enable_count of each GPIO and actual GPIO pin control.
+ * GPIO is enabled in case of initial use. (enable_count is 0)
+ * GPIO is disabled when it is not shared any more. (enable_count <= 1)
+ */
+static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
+{
+ struct regulator_enable_gpio *pin = rdev->ena_pin;
+
+ if (!pin)
+ return -EINVAL;
+
+ if (enable) {
+ /* Enable GPIO at initial use */
+ if (pin->enable_count == 0)
+ gpio_set_value_cansleep(pin->gpio,
+ !pin->ena_gpio_invert);
+
+ pin->enable_count++;
+ } else {
+ if (pin->enable_count > 1) {
+ pin->enable_count--;
+ return 0;
+ }
+
+ /* Disable GPIO if not used */
+ if (pin->enable_count <= 1) {
+ gpio_set_value_cansleep(pin->gpio,
+ pin->ena_gpio_invert);
+ pin->enable_count = 0;
+ }
+ }
+
+ return 0;
+}
+
static int _regulator_do_enable(struct regulator_dev *rdev)
{
int ret, delay;
@@ -1471,9 +1589,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable(rdev_get_name(rdev));
- if (rdev->ena_gpio) {
- gpio_set_value_cansleep(rdev->ena_gpio,
- !rdev->ena_gpio_invert);
+ if (rdev->ena_pin) {
+ ret = regulator_ena_gpio_ctrl(rdev, true);
+ if (ret < 0)
+ return ret;
rdev->ena_gpio_state = 1;
} else if (rdev->desc->ops->enable) {
ret = rdev->desc->ops->enable(rdev);
@@ -1575,9 +1694,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable(rdev_get_name(rdev));
- if (rdev->ena_gpio) {
- gpio_set_value_cansleep(rdev->ena_gpio,
- rdev->ena_gpio_invert);
+ if (rdev->ena_pin) {
+ ret = regulator_ena_gpio_ctrl(rdev, false);
+ if (ret < 0)
+ return ret;
rdev->ena_gpio_state = 0;
} else if (rdev->desc->ops->disable) {
@@ -1794,7 +1914,10 @@ int regulator_is_enabled_regmap(struct regulator_dev *rdev)
if (ret != 0)
return ret;
- return (val & rdev->desc->enable_mask) != 0;
+ if (rdev->desc->enable_is_inverted)
+ return (val & rdev->desc->enable_mask) == 0;
+ else
+ return (val & rdev->desc->enable_mask) != 0;
}
EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
@@ -1809,9 +1932,15 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled_regmap);
*/
int regulator_enable_regmap(struct regulator_dev *rdev)
{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted)
+ val = 0;
+ else
+ val = rdev->desc->enable_mask;
+
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask,
- rdev->desc->enable_mask);
+ rdev->desc->enable_mask, val);
}
EXPORT_SYMBOL_GPL(regulator_enable_regmap);
@@ -1826,15 +1955,22 @@ EXPORT_SYMBOL_GPL(regulator_enable_regmap);
*/
int regulator_disable_regmap(struct regulator_dev *rdev)
{
+ unsigned int val;
+
+ if (rdev->desc->enable_is_inverted)
+ val = rdev->desc->enable_mask;
+ else
+ val = 0;
+
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, 0);
+ rdev->desc->enable_mask, val);
}
EXPORT_SYMBOL_GPL(regulator_disable_regmap);
static int _regulator_is_enabled(struct regulator_dev *rdev)
{
/* A GPIO control always takes precedence */
- if (rdev->ena_gpio)
+ if (rdev->ena_pin)
return rdev->ena_gpio_state;
/* If we don't know then assume that the regulator is always on */
@@ -2138,6 +2274,37 @@ int regulator_map_voltage_iterate(struct regulator_dev *rdev,
EXPORT_SYMBOL_GPL(regulator_map_voltage_iterate);
/**
+ * regulator_map_voltage_ascend - map_voltage() for ascendant voltage list
+ *
+ * @rdev: Regulator to operate on
+ * @min_uV: Lower bound for voltage
+ * @max_uV: Upper bound for voltage
+ *
+ * Drivers that have ascendant voltage list can use this as their
+ * map_voltage() operation.
+ */
+int regulator_map_voltage_ascend(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ int i, ret;
+
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ ret = rdev->desc->ops->list_voltage(rdev, i);
+ if (ret < 0)
+ continue;
+
+ if (ret > max_uV)
+ break;
+
+ if (ret >= min_uV && ret <= max_uV)
+ return i;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(regulator_map_voltage_ascend);
+
+/**
* regulator_map_voltage_linear - map_voltage() for simple linear mappings
*
* @rdev: Regulator to operate on
@@ -3237,7 +3404,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0)
return status;
}
- if (rdev->ena_gpio || ops->is_enabled) {
+ if (rdev->ena_pin || ops->is_enabled) {
status = device_create_file(dev, &dev_attr_state);
if (status < 0)
return status;
@@ -3439,22 +3606,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
dev_set_drvdata(&rdev->dev, rdev);
if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
- ret = gpio_request_one(config->ena_gpio,
- GPIOF_DIR_OUT | config->ena_gpio_flags,
- rdev_get_name(rdev));
+ ret = regulator_ena_gpio_request(rdev, config);
if (ret != 0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
config->ena_gpio, ret);
goto wash;
}
- rdev->ena_gpio = config->ena_gpio;
- rdev->ena_gpio_invert = config->ena_gpio_invert;
-
if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
rdev->ena_gpio_state = 1;
- if (rdev->ena_gpio_invert)
+ if (config->ena_gpio_invert)
rdev->ena_gpio_state = !rdev->ena_gpio_state;
}
@@ -3481,7 +3643,14 @@ regulator_register(const struct regulator_desc *regulator_desc,
r = regulator_dev_lookup(dev, supply, &ret);
- if (!r) {
+ if (ret == -ENODEV) {
+ /*
+ * No supply was specified for this regulator and
+ * there will never be one.
+ */
+ ret = 0;
+ goto add_dev;
+ } else if (!r) {
dev_err(dev, "Failed to find supply %s\n", supply);
ret = -EPROBE_DEFER;
goto scrub;
@@ -3499,6 +3668,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
}
}
+add_dev:
/* add consumers devices */
if (init_data) {
for (i = 0; i < init_data->num_consumer_supplies; i++) {
@@ -3526,8 +3696,7 @@ unset_supplies:
scrub:
if (rdev->supply)
_regulator_put(rdev->supply);
- if (rdev->ena_gpio)
- gpio_free(rdev->ena_gpio);
+ regulator_ena_gpio_free(rdev);
kfree(rdev->constraints);
wash:
device_unregister(&rdev->dev);
@@ -3562,8 +3731,7 @@ void regulator_unregister(struct regulator_dev *rdev)
unset_regulator_supplies(rdev);
list_del(&rdev->list);
kfree(rdev->constraints);
- if (rdev->ena_gpio)
- gpio_free(rdev->ena_gpio);
+ regulator_ena_gpio_free(rdev);
device_unregister(&rdev->dev);
mutex_unlock(&regulator_list_mutex);
}
diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h
index e763883a44f4..c8e51ace9f06 100644
--- a/drivers/regulator/dbx500-prcmu.h
+++ b/drivers/regulator/dbx500-prcmu.h
@@ -21,7 +21,6 @@
* @is_enabled: status of the regulator
* @epod_id: id for EPOD (power domain)
* @is_ramret: RAM retention switch for EPOD (power domain)
- * @operating_point: operating point (only for vape, to be removed)
*
*/
struct dbx500_regulator_info {
@@ -32,7 +31,6 @@ struct dbx500_regulator_info {
u16 epod_id;
bool is_ramret;
bool exclude_from_power_state;
- unsigned int operating_point;
};
void power_state_active_enable(void);
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 9165b0c40ed3..f0e1ae52bb05 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -219,9 +219,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
rdesc->owner = THIS_MODULE;
di->rdev = regulator_register(&di->desc, config);
- if (IS_ERR(di->rdev))
- return PTR_ERR(di->rdev);
- return 0;
+ return PTR_RET(di->rdev);
}
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 9cb2c0f34515..d8af9e773310 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -163,6 +163,7 @@ static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev,
static struct regulator_ops lp3971_ldo_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.is_enabled = lp3971_ldo_is_enabled,
.enable = lp3971_ldo_enable,
.disable = lp3971_ldo_disable,
@@ -236,6 +237,7 @@ static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev,
static struct regulator_ops lp3971_dcdc_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.is_enabled = lp3971_dcdc_is_enabled,
.enable = lp3971_dcdc_enable,
.disable = lp3971_dcdc_disable,
diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c
index 0baabcfb578a..61e4cf9edf6e 100644
--- a/drivers/regulator/lp3972.c
+++ b/drivers/regulator/lp3972.c
@@ -309,6 +309,7 @@ static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev,
static struct regulator_ops lp3972_ldo_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.is_enabled = lp3972_ldo_is_enabled,
.enable = lp3972_ldo_enable,
.disable = lp3972_ldo_disable,
@@ -389,6 +390,7 @@ static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev,
static struct regulator_ops lp3972_dcdc_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.is_enabled = lp3972_dcdc_is_enabled,
.enable = lp3972_dcdc_enable,
.disable = lp3972_dcdc_disable,
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 8e3c7ae0047f..f5fc4a142cdf 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -478,6 +478,7 @@ static unsigned int lp872x_buck_get_mode(struct regulator_dev *rdev)
static struct regulator_ops lp872x_ldo_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
@@ -488,6 +489,7 @@ static struct regulator_ops lp872x_ldo_ops = {
static struct regulator_ops lp8720_buck_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = lp872x_buck_set_voltage_sel,
.get_voltage_sel = lp872x_buck_get_voltage_sel,
.enable = regulator_enable_regmap,
@@ -500,6 +502,7 @@ static struct regulator_ops lp8720_buck_ops = {
static struct regulator_ops lp8725_buck_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = lp872x_buck_set_voltage_sel,
.get_voltage_sel = lp872x_buck_get_voltage_sel,
.enable = regulator_enable_regmap,
diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c
index 97891a7ea7b2..eb1e1e88ae51 100644
--- a/drivers/regulator/lp8788-buck.c
+++ b/drivers/regulator/lp8788-buck.c
@@ -346,6 +346,7 @@ static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
static struct regulator_ops lp8788_buck12_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = lp8788_buck12_set_voltage_sel,
.get_voltage_sel = lp8788_buck12_get_voltage_sel,
.enable = regulator_enable_regmap,
@@ -358,6 +359,7 @@ static struct regulator_ops lp8788_buck12_ops = {
static struct regulator_ops lp8788_buck34_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = regulator_enable_regmap,
diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c
index cd5a14ad9263..0ce2c4c194b3 100644
--- a/drivers/regulator/lp8788-ldo.c
+++ b/drivers/regulator/lp8788-ldo.c
@@ -156,68 +156,6 @@ static const int lp8788_aldo7_vtbl[] = {
1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1800000,
};
-static enum lp8788_ldo_id lp8788_dldo_id[] = {
- DLDO1,
- DLDO2,
- DLDO3,
- DLDO4,
- DLDO5,
- DLDO6,
- DLDO7,
- DLDO8,
- DLDO9,
- DLDO10,
- DLDO11,
- DLDO12,
-};
-
-static enum lp8788_ldo_id lp8788_aldo_id[] = {
- ALDO1,
- ALDO2,
- ALDO3,
- ALDO4,
- ALDO5,
- ALDO6,
- ALDO7,
- ALDO8,
- ALDO9,
- ALDO10,
-};
-
-static int lp8788_ldo_enable(struct regulator_dev *rdev)
-{
- struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
- if (ldo->en_pin) {
- gpio_set_value(ldo->en_pin->gpio, ENABLE);
- return 0;
- } else {
- return regulator_enable_regmap(rdev);
- }
-}
-
-static int lp8788_ldo_disable(struct regulator_dev *rdev)
-{
- struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
- if (ldo->en_pin) {
- gpio_set_value(ldo->en_pin->gpio, DISABLE);
- return 0;
- } else {
- return regulator_disable_regmap(rdev);
- }
-}
-
-static int lp8788_ldo_is_enabled(struct regulator_dev *rdev)
-{
- struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
-
- if (ldo->en_pin)
- return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0;
- else
- return regulator_is_enabled_regmap(rdev);
-}
-
static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
{
struct lp8788_ldo *ldo = rdev_get_drvdata(rdev);
@@ -232,38 +170,21 @@ static int lp8788_ldo_enable_time(struct regulator_dev *rdev)
return ENABLE_TIME_USEC * val;
}
-static int lp8788_ldo_fixed_get_voltage(struct regulator_dev *rdev)
-{
- enum lp8788_ldo_id id = rdev_get_id(rdev);
-
- switch (id) {
- case ALDO2 ... ALDO5:
- return 2850000;
- case DLDO12:
- case ALDO8 ... ALDO9:
- return 2500000;
- case ALDO10:
- return 1100000;
- default:
- return -EINVAL;
- }
-}
-
static struct regulator_ops lp8788_ldo_voltage_table_ops = {
.list_voltage = regulator_list_voltage_table,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
- .enable = lp8788_ldo_enable,
- .disable = lp8788_ldo_disable,
- .is_enabled = lp8788_ldo_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.enable_time = lp8788_ldo_enable_time,
};
static struct regulator_ops lp8788_ldo_voltage_fixed_ops = {
- .get_voltage = lp8788_ldo_fixed_get_voltage,
- .enable = lp8788_ldo_enable,
- .disable = lp8788_ldo_disable,
- .is_enabled = lp8788_ldo_is_enabled,
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.enable_time = lp8788_ldo_enable_time,
};
@@ -420,6 +341,7 @@ static struct regulator_desc lp8788_dldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_B,
.enable_mask = LP8788_EN_DLDO12_M,
+ .min_uV = 2500000,
},
};
@@ -446,6 +368,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_B,
.enable_mask = LP8788_EN_ALDO2_M,
+ .min_uV = 2850000,
},
{
.name = "aldo3",
@@ -456,6 +379,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_B,
.enable_mask = LP8788_EN_ALDO3_M,
+ .min_uV = 2850000,
},
{
.name = "aldo4",
@@ -466,6 +390,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_B,
.enable_mask = LP8788_EN_ALDO4_M,
+ .min_uV = 2850000,
},
{
.name = "aldo5",
@@ -476,6 +401,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_C,
.enable_mask = LP8788_EN_ALDO5_M,
+ .min_uV = 2850000,
},
{
.name = "aldo6",
@@ -512,6 +438,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_C,
.enable_mask = LP8788_EN_ALDO8_M,
+ .min_uV = 2500000,
},
{
.name = "aldo9",
@@ -522,6 +449,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_C,
.enable_mask = LP8788_EN_ALDO9_M,
+ .min_uV = 2500000,
},
{
.name = "aldo10",
@@ -532,46 +460,14 @@ static struct regulator_desc lp8788_aldo_desc[] = {
.owner = THIS_MODULE,
.enable_reg = LP8788_EN_LDO_C,
.enable_mask = LP8788_EN_ALDO10_M,
+ .min_uV = 1100000,
},
};
-static int lp8788_gpio_request_ldo_en(struct platform_device *pdev,
- struct lp8788_ldo *ldo,
- enum lp8788_ext_ldo_en_id id)
-{
- struct device *dev = &pdev->dev;
- struct lp8788_ldo_enable_pin *pin = ldo->en_pin;
- int ret, gpio, pinstate;
- char *name[] = {
- [EN_ALDO1] = "LP8788_EN_ALDO1",
- [EN_ALDO234] = "LP8788_EN_ALDO234",
- [EN_ALDO5] = "LP8788_EN_ALDO5",
- [EN_ALDO7] = "LP8788_EN_ALDO7",
- [EN_DLDO7] = "LP8788_EN_DLDO7",
- [EN_DLDO911] = "LP8788_EN_DLDO911",
- };
-
- gpio = pin->gpio;
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "invalid gpio: %d\n", gpio);
- return -EINVAL;
- }
-
- pinstate = pin->init_state;
- ret = devm_gpio_request_one(dev, gpio, pinstate, name[id]);
- if (ret == -EBUSY) {
- dev_warn(dev, "gpio%d already used\n", gpio);
- return 0;
- }
-
- return ret;
-}
-
static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
struct lp8788_ldo *ldo,
enum lp8788_ldo_id id)
{
- int ret;
struct lp8788 *lp = ldo->lp;
struct lp8788_platform_data *pdata = lp->pdata;
enum lp8788_ext_ldo_en_id enable_id;
@@ -613,14 +509,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev,
goto set_default_ldo_enable_mode;
ldo->en_pin = pdata->ldo_pin[enable_id];
-
- ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id);
- if (ret) {
- ldo->en_pin = NULL;
- goto set_default_ldo_enable_mode;
- }
-
- return ret;
+ return 0;
set_default_ldo_enable_mode:
return lp8788_update_bits(lp, LP8788_EN_SEL, en_mask[enable_id], 0);
@@ -640,10 +529,15 @@ static int lp8788_dldo_probe(struct platform_device *pdev)
return -ENOMEM;
ldo->lp = lp;
- ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]);
+ ret = lp8788_config_ldo_enable_mode(pdev, ldo, id);
if (ret)
return ret;
+ if (ldo->en_pin) {
+ cfg.ena_gpio = ldo->en_pin->gpio;
+ cfg.ena_gpio_flags = ldo->en_pin->init_state;
+ }
+
cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL;
cfg.driver_data = ldo;
@@ -696,10 +590,15 @@ static int lp8788_aldo_probe(struct platform_device *pdev)
return -ENOMEM;
ldo->lp = lp;
- ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]);
+ ret = lp8788_config_ldo_enable_mode(pdev, ldo, id + ALDO1);
if (ret)
return ret;
+ if (ldo->en_pin) {
+ cfg.ena_gpio = ldo->en_pin->gpio;
+ cfg.ena_gpio_flags = ldo->en_pin->init_state;
+ }
+
cfg.dev = pdev->dev.parent;
cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL;
cfg.driver_data = ldo;
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index 8c5a54f541b5..54af61015814 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -56,7 +56,7 @@ struct max1586_data {
* set V6 to either 0V, 1.8V, 2.5V, 3V depending on (x & 0x3)
* As regulator framework doesn't accept voltages to be 0V, we use 1uV.
*/
-static int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
+static const unsigned int v6_voltages_uv[] = { 1, 1800000, 2500000, 3000000 };
/*
* V3 voltage
@@ -232,8 +232,7 @@ static int max1586_pmic_remove(struct i2c_client *client)
int i;
for (i = 0; i <= MAX1586_V6; i++)
- if (max1586->rdev[i])
- regulator_unregister(max1586->rdev[i]);
+ regulator_unregister(max1586->rdev[i]);
return 0;
}
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index e4586ee8858d..20935b1a6ed4 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -75,17 +75,20 @@ static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev)
{
unsigned int val;
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
+ int ret, id = rdev_get_id(rdev);
if (id == MAX77686_BUCK1)
val = 0x1;
else
val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+ if (ret)
+ return ret;
+
max77686->opmode[id] = val;
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask,
- val);
+ return 0;
}
/* Some LDOs supports [LPM/Normal]ON mode during suspend state */
@@ -94,7 +97,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
{
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
unsigned int val;
- int id = rdev_get_id(rdev);
+ int ret, id = rdev_get_id(rdev);
/* BUCK[5-9] doesn't support this feature */
if (id >= MAX77686_BUCK5)
@@ -113,10 +116,13 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
return -EINVAL;
}
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+ if (ret)
+ return ret;
+
max77686->opmode[id] = val;
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask,
- val);
+ return 0;
}
/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */
@@ -125,6 +131,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
{
unsigned int val;
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
+ int ret;
switch (mode) {
case REGULATOR_MODE_STANDBY: /* switch off */
@@ -142,10 +149,13 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
return -EINVAL;
}
+ ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, val);
+ if (ret)
+ return ret;
+
max77686->opmode[rdev_get_id(rdev)] = val;
- return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask,
- val);
+ return 0;
}
static int max77686_enable(struct regulator_dev *rdev)
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index 3ca14380f22d..db6c9be10f3f 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -60,36 +60,6 @@ struct max8649_regulator_info {
unsigned ramp_down:1;
};
-/* EN_PD means pulldown on EN input */
-static int max8649_enable(struct regulator_dev *rdev)
-{
- struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
- return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0);
-}
-
-/*
- * Applied internal pulldown resistor on EN input pin.
- * If pulldown EN pin outside, it would be better.
- */
-static int max8649_disable(struct regulator_dev *rdev)
-{
- struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
- return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD,
- MAX8649_EN_PD);
-}
-
-static int max8649_is_enabled(struct regulator_dev *rdev)
-{
- struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
- unsigned int val;
- int ret;
-
- ret = regmap_read(info->regmap, MAX8649_CONTROL, &val);
- if (ret != 0)
- return ret;
- return !((unsigned char)val & MAX8649_EN_PD);
-}
-
static int max8649_enable_time(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
@@ -151,9 +121,9 @@ static struct regulator_ops max8649_dcdc_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
- .enable = max8649_enable,
- .disable = max8649_disable,
- .is_enabled = max8649_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.enable_time = max8649_enable_time,
.set_mode = max8649_set_mode,
.get_mode = max8649_get_mode,
@@ -169,6 +139,9 @@ static struct regulator_desc dcdc_desc = {
.vsel_mask = MAX8649_VOL_MASK,
.min_uV = MAX8649_DCDC_VMIN,
.uV_step = MAX8649_DCDC_STEP,
+ .enable_reg = MAX8649_CONTROL,
+ .enable_mask = MAX8649_EN_PD,
+ .enable_is_inverted = true,
};
static struct regmap_config max8649_regmap_config = {
@@ -275,10 +248,8 @@ static int max8649_regulator_remove(struct i2c_client *client)
{
struct max8649_regulator_info *info = i2c_get_clientdata(client);
- if (info) {
- if (info->regulator)
- regulator_unregister(info->regulator);
- }
+ if (info)
+ regulator_unregister(info->regulator);
return 0;
}
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 4d7c635c36c2..d428ef9a626f 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -426,8 +426,7 @@ static int max8660_remove(struct i2c_client *client)
int i;
for (i = 0; i < MAX8660_V_END; i++)
- if (max8660->rdev[i])
- regulator_unregister(max8660->rdev[i]);
+ regulator_unregister(max8660->rdev[i]);
return 0;
}
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 0d5f64a805a0..3597da8f0dca 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -246,7 +246,6 @@ static struct max8925_regulator_info max8925_regulator_info[] = {
#ifdef CONFIG_OF
static int max8925_regulator_dt_init(struct platform_device *pdev,
- struct max8925_regulator_info *info,
struct regulator_config *config,
int ridx)
{
@@ -272,7 +271,7 @@ static int max8925_regulator_dt_init(struct platform_device *pdev,
return 0;
}
#else
-#define max8925_regulator_dt_init(w, x, y, z) (-1)
+#define max8925_regulator_dt_init(x, y, z) (-1)
#endif
static int max8925_regulator_probe(struct platform_device *pdev)
@@ -309,7 +308,7 @@ static int max8925_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.driver_data = ri;
- if (max8925_regulator_dt_init(pdev, ri, &config, regulator_idx))
+ if (max8925_regulator_dt_init(pdev, &config, regulator_idx))
if (pdata)
config.init_data = pdata;
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index fc7935a19e3a..5259c2fea90a 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -28,6 +28,9 @@
#include <linux/regulator/max8952.h>
#include <linux/gpio.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/slab.h>
/* Registers */
@@ -126,6 +129,69 @@ static const struct regulator_desc regulator = {
.owner = THIS_MODULE,
};
+#ifdef CONFIG_OF
+static struct of_device_id max8952_dt_match[] = {
+ { .compatible = "maxim,max8952" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, max8952_dt_match);
+
+static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
+{
+ struct max8952_platform_data *pd;
+ struct device_node *np = dev->of_node;
+ int ret;
+ int i;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ dev_err(dev, "Failed to allocate platform data\n");
+ return NULL;
+ }
+
+ pd->gpio_vid0 = of_get_named_gpio(np, "max8952,vid-gpios", 0);
+ pd->gpio_vid1 = of_get_named_gpio(np, "max8952,vid-gpios", 1);
+ pd->gpio_en = of_get_named_gpio(np, "max8952,en-gpio", 0);
+
+ if (of_property_read_u32(np, "max8952,default-mode", &pd->default_mode))
+ dev_warn(dev, "Default mode not specified, assuming 0\n");
+
+ ret = of_property_read_u32_array(np, "max8952,dvs-mode-microvolt",
+ pd->dvs_mode, ARRAY_SIZE(pd->dvs_mode));
+ if (ret) {
+ dev_err(dev, "max8952,dvs-mode-microvolt property not specified");
+ return NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pd->dvs_mode); ++i) {
+ if (pd->dvs_mode[i] < 770000 || pd->dvs_mode[i] > 1400000) {
+ dev_err(dev, "DVS voltage %d out of range\n", i);
+ return NULL;
+ }
+ pd->dvs_mode[i] = (pd->dvs_mode[i] - 770000) / 10000;
+ }
+
+ if (of_property_read_u32(np, "max8952,sync-freq", &pd->sync_freq))
+ dev_warn(dev, "max8952,sync-freq property not specified, defaulting to 26MHz\n");
+
+ if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed))
+ dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n");
+
+ pd->reg_data = of_get_regulator_init_data(dev, np);
+ if (!pd->reg_data) {
+ dev_err(dev, "Failed to parse regulator init data\n");
+ return NULL;
+ }
+
+ return pd;
+}
+#else
+static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
+{
+ return NULL;
+}
+#endif
+
static int max8952_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
@@ -136,6 +202,9 @@ static int max8952_pmic_probe(struct i2c_client *client,
int ret = 0, err = 0;
+ if (client->dev.of_node)
+ pdata = max8952_parse_dt(&client->dev);
+
if (!pdata) {
dev_err(&client->dev, "Require the platform data\n");
return -EINVAL;
@@ -154,11 +223,12 @@ static int max8952_pmic_probe(struct i2c_client *client,
max8952->pdata = pdata;
config.dev = max8952->dev;
- config.init_data = &pdata->reg_data;
+ config.init_data = pdata->reg_data;
config.driver_data = max8952;
+ config.of_node = client->dev.of_node;
config.ena_gpio = pdata->gpio_en;
- if (pdata->reg_data.constraints.boot_on)
+ if (pdata->reg_data->constraints.boot_on)
config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
max8952->rdev = regulator_register(&regulator, &config);
@@ -271,6 +341,7 @@ static struct i2c_driver max8952_pmic_driver = {
.remove = max8952_pmic_remove,
.driver = {
.name = "max8952",
+ .of_match_table = of_match_ptr(max8952_dt_match),
},
.id_table = max8952_ids,
};
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index 9a8ea9163005..adb1414e5e37 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -274,15 +274,15 @@ static int max8973_init_dcdc(struct max8973_chip *max,
if (pdata->reg_init_data &&
pdata->reg_init_data->constraints.ramp_delay) {
if (pdata->reg_init_data->constraints.ramp_delay < 25000)
- control1 = MAX8973_RAMP_12mV_PER_US;
+ control1 |= MAX8973_RAMP_12mV_PER_US;
else if (pdata->reg_init_data->constraints.ramp_delay < 50000)
- control1 = MAX8973_RAMP_25mV_PER_US;
+ control1 |= MAX8973_RAMP_25mV_PER_US;
else if (pdata->reg_init_data->constraints.ramp_delay < 200000)
- control1 = MAX8973_RAMP_50mV_PER_US;
+ control1 |= MAX8973_RAMP_50mV_PER_US;
else
- control1 = MAX8973_RAMP_200mV_PER_US;
+ control1 |= MAX8973_RAMP_200mV_PER_US;
} else {
- control1 = MAX8973_RAMP_12mV_PER_US;
+ control1 |= MAX8973_RAMP_12mV_PER_US;
max->desc.ramp_delay = 12500;
}
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 0ac7a87519b4..df20069f0537 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -1035,8 +1035,8 @@ static int max8997_pmic_probe(struct platform_device *pdev)
int i, ret, size, nr_dvs;
u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0;
- if (IS_ERR_OR_NULL(pdata)) {
- dev_err(pdev->dev.parent, "No platform init data supplied.\n");
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform init data supplied.\n");
return -ENODEV;
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index b588f07c7cad..a57a1b15cdba 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -665,14 +665,16 @@ static int max8998_pmic_probe(struct platform_device *pdev)
gpio_is_valid(pdata->buck1_set2)) {
/* Check if SET1 is not equal to 0 */
if (!pdata->buck1_set1) {
- printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
+ dev_err(&pdev->dev,
+ "MAX8998 SET1 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set1);
ret = -EIO;
goto err_out;
}
/* Check if SET2 is not equal to 0 */
if (!pdata->buck1_set2) {
- printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
+ dev_err(&pdev->dev,
+ "MAX8998 SET2 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set2);
ret = -EIO;
goto err_out;
@@ -738,7 +740,8 @@ static int max8998_pmic_probe(struct platform_device *pdev)
if (gpio_is_valid(pdata->buck2_set3)) {
/* Check if SET3 is not equal to 0 */
if (!pdata->buck2_set3) {
- printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
+ dev_err(&pdev->dev,
+ "MAX8998 SET3 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck2_set3);
ret = -EIO;
goto err_out;
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index c46c6705cd74..fdf7f0a09090 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -398,33 +398,51 @@ static int mc13783_regulator_probe(struct platform_device *pdev)
struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
struct mc13xxx_regulator_platform_data *pdata =
dev_get_platdata(&pdev->dev);
- struct mc13xxx_regulator_init_data *init_data;
+ struct mc13xxx_regulator_init_data *mc13xxx_data;
struct regulator_config config = { };
- int i, ret;
+ int i, ret, num_regulators;
- dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id);
+ num_regulators = mc13xxx_get_num_regulators_dt(pdev);
- if (!pdata)
+ if (num_regulators <= 0 && pdata)
+ num_regulators = pdata->num_regulators;
+ if (num_regulators <= 0)
return -EINVAL;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
- pdata->num_regulators * sizeof(priv->regulators[0]),
+ num_regulators * sizeof(priv->regulators[0]),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->num_regulators = num_regulators;
priv->mc13xxx_regulators = mc13783_regulators;
priv->mc13xxx = mc13783;
+ platform_set_drvdata(pdev, priv);
- for (i = 0; i < pdata->num_regulators; i++) {
- struct regulator_desc *desc;
+ mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13783_regulators,
+ ARRAY_SIZE(mc13783_regulators));
- init_data = &pdata->regulators[i];
- desc = &mc13783_regulators[init_data->id].desc;
+ for (i = 0; i < priv->num_regulators; i++) {
+ struct regulator_init_data *init_data;
+ struct regulator_desc *desc;
+ struct device_node *node = NULL;
+ int id;
+
+ if (mc13xxx_data) {
+ id = mc13xxx_data[i].id;
+ init_data = mc13xxx_data[i].init_data;
+ node = mc13xxx_data[i].node;
+ } else {
+ id = pdata->regulators[i].id;
+ init_data = pdata->regulators[i].init_data;
+ }
+ desc = &mc13783_regulators[id].desc;
config.dev = &pdev->dev;
- config.init_data = init_data->init_data;
+ config.init_data = init_data;
config.driver_data = priv;
+ config.of_node = node;
priv->regulators[i] = regulator_register(desc, &config);
if (IS_ERR(priv->regulators[i])) {
@@ -435,8 +453,6 @@ static int mc13783_regulator_probe(struct platform_device *pdev)
}
}
- platform_set_drvdata(pdev, priv);
-
return 0;
err:
while (--i >= 0)
@@ -448,13 +464,11 @@ err:
static int mc13783_regulator_remove(struct platform_device *pdev)
{
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
- struct mc13xxx_regulator_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
int i;
platform_set_drvdata(pdev, NULL);
- for (i = 0; i < pdata->num_regulators; i++)
+ for (i = 0; i < priv->num_regulators; i++)
regulator_unregister(priv->regulators[i]);
return 0;
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 9891aec47b57..b716283a8760 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -465,13 +465,13 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
*/
if (mc13892_regulators[id].vsel_reg != MC13892_SWITCHERS0) {
+ mask |= MC13892_SWITCHERS0_SWxHI;
+
if (volt > 1375000) {
reg_value -= MC13892_SWxHI_SEL_OFFSET;
reg_value |= MC13892_SWITCHERS0_SWxHI;
- mask |= MC13892_SWITCHERS0_SWxHI;
- } else if (volt < 1100000) {
+ } else {
reg_value &= ~MC13892_SWITCHERS0_SWxHI;
- mask |= MC13892_SWITCHERS0_SWxHI;
}
}
@@ -485,6 +485,7 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
static struct regulator_ops mc13892_sw_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
.get_voltage_sel = mc13892_sw_regulator_get_voltage_sel,
};
@@ -535,7 +536,7 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
struct mc13xxx_regulator_init_data *mc13xxx_data;
struct regulator_config config = { };
int i, ret;
- int num_regulators = 0, num_parsed;
+ int num_regulators = 0;
u32 val;
num_regulators = mc13xxx_get_num_regulators_dt(pdev);
@@ -545,8 +546,6 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
if (num_regulators <= 0)
return -EINVAL;
- num_parsed = num_regulators;
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
num_regulators * sizeof(priv->regulators[0]),
GFP_KERNEL);
@@ -589,40 +588,9 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
= mc13892_vcam_get_mode;
mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
- ARRAY_SIZE(mc13892_regulators),
- &num_parsed);
-
- /*
- * Perform a little sanity check on the regulator tree - if we found
- * a number of regulators from mc13xxx_get_num_regulators_dt and
- * then parsed a smaller number in mc13xxx_parse_regulators_dt then
- * there is a regulator defined in the regulators node which has
- * not matched any usable regulator in the driver. In this case,
- * there is one missing and what will happen is the first regulator
- * will get registered again.
- *
- * Fix this by basically making our number of registerable regulators
- * equal to the number of regulators we parsed. We are allocating
- * too much memory for priv, but this is unavoidable at this point.
- *
- * As an example of how this can happen, try making a typo in your
- * regulators node (vviohi {} instead of viohi {}) so that the name
- * does not match..
- *
- * The check will basically pass for platform data (non-DT) because
- * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
- *
- */
- if (num_parsed != num_regulators) {
- dev_warn(&pdev->dev,
- "parsed %d != regulators %d - check your device tree!\n",
- num_parsed, num_regulators);
-
- num_regulators = num_parsed;
- priv->num_regulators = num_regulators;
- }
+ ARRAY_SIZE(mc13892_regulators));
- for (i = 0; i < num_regulators; i++) {
+ for (i = 0; i < priv->num_regulators; i++) {
struct regulator_init_data *init_data;
struct regulator_desc *desc;
struct device_node *node = NULL;
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 23cf9f9c383b..da4859282302 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -180,15 +180,13 @@ EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators, int *num_parsed)
+ int num_regulators)
{
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
struct mc13xxx_regulator_init_data *data, *p;
struct device_node *parent, *child;
int i, parsed = 0;
- *num_parsed = 0;
-
of_node_get(pdev->dev.parent->of_node);
parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
if (!parent)
@@ -204,10 +202,13 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
p = data;
for_each_child_of_node(parent, child) {
+ int found = 0;
+
for (i = 0; i < num_regulators; i++) {
+ if (!regulators[i].desc.name)
+ continue;
if (!of_node_cmp(child->name,
regulators[i].desc.name)) {
-
p->id = i;
p->init_data = of_get_regulator_init_data(
&pdev->dev, child);
@@ -215,13 +216,19 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
p++;
parsed++;
+ found = 1;
break;
}
}
+
+ if (!found)
+ dev_warn(&pdev->dev,
+ "Unknown regulator: %s\n", child->name);
}
of_node_put(parent);
- *num_parsed = parsed;
+ priv->num_regulators = parsed;
+
return data;
}
EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index 007f83387fd6..06c8903f182a 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators, int *num_parsed);
+ int num_regulators);
#else
static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
{
@@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
struct platform_device *pdev, struct mc13xxx_regulator *regulators,
- int num_regulators, int *num_parsed)
+ int num_regulators)
{
return NULL;
}
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 39cf14606784..92ceed0fc65e 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -1,7 +1,7 @@
/*
* Driver for Regulator part of Palmas PMIC Chips
*
- * Copyright 2011-2012 Texas Instruments Inc.
+ * Copyright 2011-2013 Texas Instruments Inc.
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
* Author: Ian Lartey <ian@slimlogic.co.uk>
@@ -29,6 +29,7 @@
struct regs_info {
char *name;
+ char *sname;
u8 vsel_addr;
u8 ctrl_addr;
u8 tstep_addr;
@@ -37,115 +38,159 @@ struct regs_info {
static const struct regs_info palmas_regs_info[] = {
{
.name = "SMPS12",
+ .sname = "smps1-in",
.vsel_addr = PALMAS_SMPS12_VOLTAGE,
.ctrl_addr = PALMAS_SMPS12_CTRL,
.tstep_addr = PALMAS_SMPS12_TSTEP,
},
{
.name = "SMPS123",
+ .sname = "smps1-in",
.vsel_addr = PALMAS_SMPS12_VOLTAGE,
.ctrl_addr = PALMAS_SMPS12_CTRL,
.tstep_addr = PALMAS_SMPS12_TSTEP,
},
{
.name = "SMPS3",
+ .sname = "smps3-in",
.vsel_addr = PALMAS_SMPS3_VOLTAGE,
.ctrl_addr = PALMAS_SMPS3_CTRL,
},
{
.name = "SMPS45",
+ .sname = "smps4-in",
.vsel_addr = PALMAS_SMPS45_VOLTAGE,
.ctrl_addr = PALMAS_SMPS45_CTRL,
.tstep_addr = PALMAS_SMPS45_TSTEP,
},
{
.name = "SMPS457",
+ .sname = "smps4-in",
.vsel_addr = PALMAS_SMPS45_VOLTAGE,
.ctrl_addr = PALMAS_SMPS45_CTRL,
.tstep_addr = PALMAS_SMPS45_TSTEP,
},
{
.name = "SMPS6",
+ .sname = "smps6-in",
.vsel_addr = PALMAS_SMPS6_VOLTAGE,
.ctrl_addr = PALMAS_SMPS6_CTRL,
.tstep_addr = PALMAS_SMPS6_TSTEP,
},
{
.name = "SMPS7",
+ .sname = "smps7-in",
.vsel_addr = PALMAS_SMPS7_VOLTAGE,
.ctrl_addr = PALMAS_SMPS7_CTRL,
},
{
.name = "SMPS8",
+ .sname = "smps8-in",
.vsel_addr = PALMAS_SMPS8_VOLTAGE,
.ctrl_addr = PALMAS_SMPS8_CTRL,
.tstep_addr = PALMAS_SMPS8_TSTEP,
},
{
.name = "SMPS9",
+ .sname = "smps9-in",
.vsel_addr = PALMAS_SMPS9_VOLTAGE,
.ctrl_addr = PALMAS_SMPS9_CTRL,
},
{
.name = "SMPS10",
+ .sname = "smps10-in",
+ .ctrl_addr = PALMAS_SMPS10_CTRL,
},
{
.name = "LDO1",
+ .sname = "ldo1-in",
.vsel_addr = PALMAS_LDO1_VOLTAGE,
.ctrl_addr = PALMAS_LDO1_CTRL,
},
{
.name = "LDO2",
+ .sname = "ldo2-in",
.vsel_addr = PALMAS_LDO2_VOLTAGE,
.ctrl_addr = PALMAS_LDO2_CTRL,
},
{
.name = "LDO3",
+ .sname = "ldo3-in",
.vsel_addr = PALMAS_LDO3_VOLTAGE,
.ctrl_addr = PALMAS_LDO3_CTRL,
},
{
.name = "LDO4",
+ .sname = "ldo4-in",
.vsel_addr = PALMAS_LDO4_VOLTAGE,
.ctrl_addr = PALMAS_LDO4_CTRL,
},
{
.name = "LDO5",
+ .sname = "ldo5-in",
.vsel_addr = PALMAS_LDO5_VOLTAGE,
.ctrl_addr = PALMAS_LDO5_CTRL,
},
{
.name = "LDO6",
+ .sname = "ldo6-in",
.vsel_addr = PALMAS_LDO6_VOLTAGE,
.ctrl_addr = PALMAS_LDO6_CTRL,
},
{
.name = "LDO7",
+ .sname = "ldo7-in",
.vsel_addr = PALMAS_LDO7_VOLTAGE,
.ctrl_addr = PALMAS_LDO7_CTRL,
},
{
.name = "LDO8",
+ .sname = "ldo8-in",
.vsel_addr = PALMAS_LDO8_VOLTAGE,
.ctrl_addr = PALMAS_LDO8_CTRL,
},
{
.name = "LDO9",
+ .sname = "ldo9-in",
.vsel_addr = PALMAS_LDO9_VOLTAGE,
.ctrl_addr = PALMAS_LDO9_CTRL,
},
{
.name = "LDOLN",
+ .sname = "ldoln-in",
.vsel_addr = PALMAS_LDOLN_VOLTAGE,
.ctrl_addr = PALMAS_LDOLN_CTRL,
},
{
.name = "LDOUSB",
+ .sname = "ldousb-in",
.vsel_addr = PALMAS_LDOUSB_VOLTAGE,
.ctrl_addr = PALMAS_LDOUSB_CTRL,
},
+ {
+ .name = "REGEN1",
+ .ctrl_addr = PALMAS_REGEN1_CTRL,
+ },
+ {
+ .name = "REGEN2",
+ .ctrl_addr = PALMAS_REGEN2_CTRL,
+ },
+ {
+ .name = "REGEN3",
+ .ctrl_addr = PALMAS_REGEN3_CTRL,
+ },
+ {
+ .name = "SYSEN1",
+ .ctrl_addr = PALMAS_SYSEN1_CTRL,
+ },
+ {
+ .name = "SYSEN2",
+ .ctrl_addr = PALMAS_SYSEN2_CTRL,
+ },
};
+static unsigned int palmas_smps_ramp_delay[4] = {0, 10000, 5000, 2500};
+
#define SMPS_CTRL_MODE_OFF 0x00
#define SMPS_CTRL_MODE_ON 0x01
#define SMPS_CTRL_MODE_ECO 0x02
@@ -231,7 +276,10 @@ static int palmas_enable_smps(struct regulator_dev *dev)
palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
- reg |= SMPS_CTRL_MODE_ON;
+ if (pmic->current_reg_mode[id])
+ reg |= pmic->current_reg_mode[id];
+ else
+ reg |= SMPS_CTRL_MODE_ON;
palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
@@ -253,16 +301,19 @@ static int palmas_disable_smps(struct regulator_dev *dev)
return 0;
}
-
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
{
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
int id = rdev_get_id(dev);
unsigned int reg;
+ bool rail_enable = true;
palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
+ if (reg == SMPS_CTRL_MODE_OFF)
+ rail_enable = false;
+
switch (mode) {
case REGULATOR_MODE_NORMAL:
reg |= SMPS_CTRL_MODE_ON;
@@ -276,8 +327,11 @@ static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
default:
return -EINVAL;
}
- palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
+ pmic->current_reg_mode[id] = reg & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
+ if (rail_enable)
+ palmas_smps_write(pmic->palmas,
+ palmas_regs_info[id].ctrl_addr, reg);
return 0;
}
@@ -287,9 +341,7 @@ static unsigned int palmas_get_mode_smps(struct regulator_dev *dev)
int id = rdev_get_id(dev);
unsigned int reg;
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, &reg);
- reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
- reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
+ reg = pmic->current_reg_mode[id] & PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
switch (reg) {
case SMPS_CTRL_MODE_ON:
@@ -356,6 +408,63 @@ static int palmas_map_voltage_smps(struct regulator_dev *rdev,
return ret;
}
+static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ int old_uv, new_uv;
+ unsigned int ramp_delay = pmic->ramp_delay[id];
+
+ if (!ramp_delay)
+ return 0;
+
+ old_uv = palmas_list_voltage_smps(rdev, old_selector);
+ if (old_uv < 0)
+ return old_uv;
+
+ new_uv = palmas_list_voltage_smps(rdev, new_selector);
+ if (new_uv < 0)
+ return new_uv;
+
+ return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay);
+}
+
+static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
+ int ramp_delay)
+{
+ struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+ unsigned int reg = 0;
+ unsigned int addr = palmas_regs_info[id].tstep_addr;
+ int ret;
+
+ /* SMPS3 and SMPS7 do not have tstep_addr setting */
+ switch (id) {
+ case PALMAS_REG_SMPS3:
+ case PALMAS_REG_SMPS7:
+ return 0;
+ }
+
+ if (ramp_delay <= 0)
+ reg = 0;
+ else if (ramp_delay <= 2500)
+ reg = 3;
+ else if (ramp_delay <= 5000)
+ reg = 2;
+ else
+ reg = 1;
+
+ ret = palmas_smps_write(pmic->palmas, addr, reg);
+ if (ret < 0) {
+ dev_err(pmic->palmas->dev, "TSTEP write failed: %d\n", ret);
+ return ret;
+ }
+
+ pmic->ramp_delay[id] = palmas_smps_ramp_delay[reg];
+ return ret;
+}
+
static struct regulator_ops palmas_ops_smps = {
.is_enabled = palmas_is_enabled_smps,
.enable = palmas_enable_smps,
@@ -366,6 +475,8 @@ static struct regulator_ops palmas_ops_smps = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = palmas_list_voltage_smps,
.map_voltage = palmas_map_voltage_smps,
+ .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel,
+ .set_ramp_delay = palmas_smps_set_ramp_delay,
};
static struct regulator_ops palmas_ops_smps10 = {
@@ -401,6 +512,12 @@ static struct regulator_ops palmas_ops_ldo = {
.map_voltage = regulator_map_voltage_linear,
};
+static struct regulator_ops palmas_ops_extreg = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+};
+
/*
* setup the hardware based sleep configuration of the SMPS/LDO regulators
* from the platform data. This is different to the software based control
@@ -422,40 +539,32 @@ static int palmas_smps_init(struct palmas *palmas, int id,
switch (id) {
case PALMAS_REG_SMPS10:
- if (reg_init->mode_sleep) {
- reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+ reg &= ~PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK;
+ if (reg_init->mode_sleep)
reg |= reg_init->mode_sleep <<
PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT;
- }
break;
default:
if (reg_init->warm_reset)
reg |= PALMAS_SMPS12_CTRL_WR_S;
+ else
+ reg &= ~PALMAS_SMPS12_CTRL_WR_S;
if (reg_init->roof_floor)
reg |= PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
+ else
+ reg &= ~PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN;
- if (reg_init->mode_sleep) {
- reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
+ reg &= ~PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK;
+ if (reg_init->mode_sleep)
reg |= reg_init->mode_sleep <<
PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT;
- }
}
ret = palmas_smps_write(palmas, addr, reg);
if (ret)
return ret;
- if (palmas_regs_info[id].tstep_addr && reg_init->tstep) {
- addr = palmas_regs_info[id].tstep_addr;
-
- reg = reg_init->tstep & PALMAS_SMPS12_TSTEP_TSTEP_MASK;
-
- ret = palmas_smps_write(palmas, addr, reg);
- if (ret)
- return ret;
- }
-
if (palmas_regs_info[id].vsel_addr && reg_init->vsel) {
addr = palmas_regs_info[id].vsel_addr;
@@ -485,9 +594,13 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
if (reg_init->warm_reset)
reg |= PALMAS_LDO1_CTRL_WR_S;
+ else
+ reg &= ~PALMAS_LDO1_CTRL_WR_S;
if (reg_init->mode_sleep)
reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
+ else
+ reg &= ~PALMAS_LDO1_CTRL_MODE_SLEEP;
ret = palmas_ldo_write(palmas, addr, reg);
if (ret)
@@ -496,6 +609,68 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
return 0;
}
+static int palmas_extreg_init(struct palmas *palmas, int id,
+ struct palmas_reg_init *reg_init)
+{
+ unsigned int addr;
+ int ret;
+ unsigned int val = 0;
+
+ addr = palmas_regs_info[id].ctrl_addr;
+
+ if (reg_init->mode_sleep)
+ val = PALMAS_REGEN1_CTRL_MODE_SLEEP;
+
+ ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
+ addr, PALMAS_REGEN1_CTRL_MODE_SLEEP, val);
+ if (ret < 0) {
+ dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
+ addr, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void palmas_enable_ldo8_track(struct palmas *palmas)
+{
+ unsigned int reg;
+ unsigned int addr;
+ int ret;
+
+ addr = palmas_regs_info[PALMAS_REG_LDO8].ctrl_addr;
+
+ ret = palmas_ldo_read(palmas, addr, &reg);
+ if (ret) {
+ dev_err(palmas->dev, "Error in reading ldo8 control reg\n");
+ return;
+ }
+
+ reg |= PALMAS_LDO8_CTRL_LDO_TRACKING_EN;
+ ret = palmas_ldo_write(palmas, addr, reg);
+ if (ret < 0) {
+ dev_err(palmas->dev, "Error in enabling tracking mode\n");
+ return;
+ }
+ /*
+ * When SMPS45 is set to off and LDO8 tracking is enabled, the LDO8
+ * output is defined by the LDO8_VOLTAGE.VSEL register divided by two,
+ * and can be set from 0.45 to 1.65 V.
+ */
+ addr = palmas_regs_info[PALMAS_REG_LDO8].vsel_addr;
+ ret = palmas_ldo_read(palmas, addr, &reg);
+ if (ret) {
+ dev_err(palmas->dev, "Error in reading ldo8 voltage reg\n");
+ return;
+ }
+
+ reg = (reg << 1) & PALMAS_LDO8_VOLTAGE_VSEL_MASK;
+ ret = palmas_ldo_write(palmas, addr, reg);
+ if (ret < 0)
+ dev_err(palmas->dev, "Error in setting ldo8 voltage reg\n");
+
+ return;
+}
+
static struct of_regulator_match palmas_matches[] = {
{ .name = "smps12", },
{ .name = "smps123", },
@@ -518,6 +693,11 @@ static struct of_regulator_match palmas_matches[] = {
{ .name = "ldo9", },
{ .name = "ldoln", },
{ .name = "ldousb", },
+ { .name = "regen1", },
+ { .name = "regen2", },
+ { .name = "regen3", },
+ { .name = "sysen1", },
+ { .name = "sysen2", },
};
static void palmas_dt_to_pdata(struct device *dev,
@@ -553,39 +733,36 @@ static void palmas_dt_to_pdata(struct device *dev,
pdata->reg_init[idx] = devm_kzalloc(dev,
sizeof(struct palmas_reg_init), GFP_KERNEL);
- ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,warm_reset", &prop);
- if (!ret)
- pdata->reg_init[idx]->warm_reset = prop;
+ pdata->reg_init[idx]->warm_reset =
+ of_property_read_bool(palmas_matches[idx].of_node,
+ "ti,warm-reset");
- ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,roof_floor", &prop);
- if (!ret)
- pdata->reg_init[idx]->roof_floor = prop;
+ pdata->reg_init[idx]->roof_floor =
+ of_property_read_bool(palmas_matches[idx].of_node,
+ "ti,roof-floor");
ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,mode_sleep", &prop);
+ "ti,mode-sleep", &prop);
if (!ret)
pdata->reg_init[idx]->mode_sleep = prop;
- ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,tstep", &prop);
- if (!ret)
- pdata->reg_init[idx]->tstep = prop;
+ ret = of_property_read_bool(palmas_matches[idx].of_node,
+ "ti,smps-range");
+ if (ret)
+ pdata->reg_init[idx]->vsel =
+ PALMAS_SMPS12_VOLTAGE_RANGE;
- ret = of_property_read_u32(palmas_matches[idx].of_node,
- "ti,vsel", &prop);
- if (!ret)
- pdata->reg_init[idx]->vsel = prop;
+ if (idx == PALMAS_REG_LDO8)
+ pdata->enable_ldo8_tracking = of_property_read_bool(
+ palmas_matches[idx].of_node,
+ "ti,enable-ldo8-tracking");
}
- ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop);
- if (!ret)
- pdata->ldo6_vibrator = prop;
+ pdata->ldo6_vibrator = of_property_read_bool(node, "ti,ldo6-vibrator");
}
-static int palmas_probe(struct platform_device *pdev)
+static int palmas_regulators_probe(struct platform_device *pdev)
{
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data;
@@ -630,6 +807,7 @@ static int palmas_probe(struct platform_device *pdev)
config.driver_data = pmic;
for (id = 0; id < PALMAS_REG_LDO1; id++) {
+ bool ramp_delay_support = false;
/*
* Miss out regulators which are not available due
@@ -640,19 +818,42 @@ static int palmas_probe(struct platform_device *pdev)
case PALMAS_REG_SMPS3:
if (pmic->smps123)
continue;
+ if (id == PALMAS_REG_SMPS12)
+ ramp_delay_support = true;
break;
case PALMAS_REG_SMPS123:
if (!pmic->smps123)
continue;
+ ramp_delay_support = true;
break;
case PALMAS_REG_SMPS45:
case PALMAS_REG_SMPS7:
if (pmic->smps457)
continue;
+ if (id == PALMAS_REG_SMPS45)
+ ramp_delay_support = true;
break;
case PALMAS_REG_SMPS457:
if (!pmic->smps457)
continue;
+ ramp_delay_support = true;
+ break;
+ }
+
+ if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8))
+ ramp_delay_support = true;
+
+ if (ramp_delay_support) {
+ addr = palmas_regs_info[id].tstep_addr;
+ ret = palmas_smps_read(pmic->palmas, addr, &reg);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "reading TSTEP reg failed: %d\n", ret);
+ goto err_unregister_regulator;
+ }
+ pmic->desc[id].ramp_delay =
+ palmas_smps_ramp_delay[reg & 0x3];
+ pmic->ramp_delay[id] = pmic->desc[id].ramp_delay;
}
/* Initialise sleep/init values from platform data */
@@ -686,7 +887,8 @@ static int palmas_probe(struct platform_device *pdev)
/*
* Read and store the RANGE bit for later use
* This must be done before regulator is probed,
- * otherwise we error in probe with unsupportable ranges.
+ * otherwise we error in probe with unsupportable
+ * ranges. Read the current smps mode for later use.
*/
addr = palmas_regs_info[id].vsel_addr;
@@ -703,6 +905,14 @@ static int palmas_probe(struct platform_device *pdev)
palmas_regs_info[id].vsel_addr);
pmic->desc[id].vsel_mask =
PALMAS_SMPS12_VOLTAGE_VSEL_MASK;
+
+ /* Read the smps mode for later use. */
+ addr = palmas_regs_info[id].ctrl_addr;
+ ret = palmas_smps_read(pmic->palmas, addr, &reg);
+ if (ret)
+ goto err_unregister_regulator;
+ pmic->current_reg_mode[id] = reg &
+ PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
}
pmic->desc[id].type = REGULATOR_VOLTAGE;
@@ -713,6 +923,7 @@ static int palmas_probe(struct platform_device *pdev)
else
config.init_data = NULL;
+ pmic->desc[id].supply_name = palmas_regs_info[id].sname;
config.of_node = palmas_matches[id].of_node;
rdev = regulator_register(&pmic->desc[id], &config);
@@ -738,27 +949,49 @@ static int palmas_probe(struct platform_device *pdev)
/* Register the regulators */
pmic->desc[id].name = palmas_regs_info[id].name;
pmic->desc[id].id = id;
- pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
-
- pmic->desc[id].ops = &palmas_ops_ldo;
-
pmic->desc[id].type = REGULATOR_VOLTAGE;
pmic->desc[id].owner = THIS_MODULE;
- pmic->desc[id].min_uV = 900000;
- pmic->desc[id].uV_step = 50000;
- pmic->desc[id].linear_min_sel = 1;
- pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+
+ if (id < PALMAS_REG_REGEN1) {
+ pmic->desc[id].n_voltages = PALMAS_LDO_NUM_VOLTAGES;
+ pmic->desc[id].ops = &palmas_ops_ldo;
+ pmic->desc[id].min_uV = 900000;
+ pmic->desc[id].uV_step = 50000;
+ pmic->desc[id].linear_min_sel = 1;
+ pmic->desc[id].vsel_reg =
+ PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
palmas_regs_info[id].vsel_addr);
- pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
- pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+ pmic->desc[id].vsel_mask =
+ PALMAS_LDO1_VOLTAGE_VSEL_MASK;
+ pmic->desc[id].enable_reg =
+ PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+ palmas_regs_info[id].ctrl_addr);
+ pmic->desc[id].enable_mask =
+ PALMAS_LDO1_CTRL_MODE_ACTIVE;
+
+ /* Check if LDO8 is in tracking mode or not */
+ if (pdata && (id == PALMAS_REG_LDO8) &&
+ pdata->enable_ldo8_tracking) {
+ palmas_enable_ldo8_track(palmas);
+ pmic->desc[id].min_uV = 450000;
+ pmic->desc[id].uV_step = 25000;
+ }
+ } else {
+ pmic->desc[id].n_voltages = 1;
+ pmic->desc[id].ops = &palmas_ops_extreg;
+ pmic->desc[id].enable_reg =
+ PALMAS_BASE_TO_REG(PALMAS_RESOURCE_BASE,
palmas_regs_info[id].ctrl_addr);
- pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
+ pmic->desc[id].enable_mask =
+ PALMAS_REGEN1_CTRL_MODE_ACTIVE;
+ }
if (pdata)
config.init_data = pdata->reg_data[id];
else
config.init_data = NULL;
+ pmic->desc[id].supply_name = palmas_regs_info[id].sname;
config.of_node = palmas_matches[id].of_node;
rdev = regulator_register(&pmic->desc[id], &config);
@@ -777,7 +1010,12 @@ static int palmas_probe(struct platform_device *pdev)
if (pdata) {
reg_init = pdata->reg_init[id];
if (reg_init) {
- ret = palmas_ldo_init(palmas, id, reg_init);
+ if (id < PALMAS_REG_REGEN1)
+ ret = palmas_ldo_init(palmas,
+ id, reg_init);
+ else
+ ret = palmas_extreg_init(palmas,
+ id, reg_init);
if (ret) {
regulator_unregister(pmic->rdev[id]);
goto err_unregister_regulator;
@@ -786,6 +1024,7 @@ static int palmas_probe(struct platform_device *pdev)
}
}
+
return 0;
err_unregister_regulator:
@@ -794,7 +1033,7 @@ err_unregister_regulator:
return ret;
}
-static int palmas_remove(struct platform_device *pdev)
+static int palmas_regulators_remove(struct platform_device *pdev)
{
struct palmas_pmic *pmic = platform_get_drvdata(pdev);
int id;
@@ -806,6 +1045,12 @@ static int palmas_remove(struct platform_device *pdev)
static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-pmic", },
+ { .compatible = "ti,twl6035-pmic", },
+ { .compatible = "ti,twl6036-pmic", },
+ { .compatible = "ti,twl6037-pmic", },
+ { .compatible = "ti,tps65913-pmic", },
+ { .compatible = "ti,tps65914-pmic", },
+ { .compatible = "ti,tps80036-pmic", },
{ /* end */ }
};
@@ -815,8 +1060,8 @@ static struct platform_driver palmas_driver = {
.of_match_table = of_palmas_match_tbl,
.owner = THIS_MODULE,
},
- .probe = palmas_probe,
- .remove = palmas_remove,
+ .probe = palmas_regulators_probe,
+ .remove = palmas_regulators_remove,
};
static int __init palmas_init(void)
diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c
index 9e6f78694bf1..5885b4504596 100644
--- a/drivers/regulator/rc5t583-regulator.c
+++ b/drivers/regulator/rc5t583-regulator.c
@@ -49,10 +49,6 @@ struct rc5t583_regulator_info {
struct rc5t583_regulator {
struct rc5t583_regulator_info *reg_info;
-
- /* Devices */
- struct device *dev;
- struct rc5t583 *mfd;
struct regulator_dev *rdev;
};
@@ -155,8 +151,6 @@ static int rc5t583_regulator_probe(struct platform_device *pdev)
reg = &regs[id];
ri = &rc5t583_reg_info[id];
reg->reg_info = ri;
- reg->mfd = rc5t583;
- reg->dev = &pdev->dev;
if (ri->deepsleep_id == RC5T583_DS_NONE)
goto skip_ext_pwr_config;
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 8a831947c351..c24448bc43cf 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -549,7 +549,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rmode = devm_kzalloc(&pdev->dev, sizeof(*rmode) *
pdata->num_regulators, GFP_KERNEL);
- if (!rdata) {
+ if (!rmode) {
dev_err(iodev->dev,
"could not allocate memory for regulator mode\n");
return -ENOMEM;
@@ -923,8 +923,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
return 0;
err:
for (i = 0; i < s5m8767->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
+ regulator_unregister(rdev[i]);
return ret;
}
@@ -936,8 +935,7 @@ static int s5m8767_pmic_remove(struct platform_device *pdev)
int i;
for (i = 0; i < s5m8767->num_regulators; i++)
- if (rdev[i])
- regulator_unregister(rdev[i]);
+ regulator_unregister(rdev[i]);
return 0;
}
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index acbd63fde415..612919c3081c 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -278,7 +278,7 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps,
__func__, REG_RAMPCTRL, ret);
return ret;
}
- ramp_ctrl = (ramp_ctrl >> 4) & 0x7;
+ ramp_ctrl = (ramp_ctrl >> 5) & 0x7;
/* ramp mV/us = 32/(2^ramp_ctrl) */
tps->desc.ramp_delay = DIV_ROUND_UP(32000, BIT(ramp_ctrl));
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 9b9af6d889c8..9d053e23e9eb 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -107,12 +107,7 @@ static const unsigned int DCDC_FIXED_1800000_VSEL_table[] = {
};
/* Supported voltage values for LDO regulators for tps65020 */
-static const unsigned int TPS65020_LDO1_VSEL_table[] = {
- 1000000, 1050000, 1100000, 1300000,
- 1800000, 2500000, 3000000, 3300000,
-};
-
-static const unsigned int TPS65020_LDO2_VSEL_table[] = {
+static const unsigned int TPS65020_LDO_VSEL_table[] = {
1000000, 1050000, 1100000, 1300000,
1800000, 2500000, 3000000, 3300000,
};
@@ -154,20 +149,15 @@ struct tps_driver_data {
static int tps65023_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
- int ret;
- int data, dcdc = rdev_get_id(dev);
+ int dcdc = rdev_get_id(dev);
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL;
- if (dcdc == tps->core_regulator) {
- ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data);
- if (ret != 0)
- return ret;
- data &= (tps->info[dcdc]->table_len - 1);
- return data;
- } else
+ if (dcdc != tps->core_regulator)
return 0;
+
+ return regulator_get_voltage_sel_regmap(dev);
}
static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
@@ -175,23 +165,11 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
{
struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev);
- int ret;
if (dcdc != tps->core_regulator)
return -EINVAL;
- ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector);
- if (ret)
- goto out;
-
- /* Tell the chip that we have changed the value in DEFCORE
- * and its time to update the core voltage
- */
- ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
- TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
-
-out:
- return ret;
+ return regulator_set_voltage_sel_regmap(dev, selector);
}
/* Operations permitted on VDCDCx */
@@ -202,6 +180,7 @@ static struct regulator_ops tps65023_dcdc_ops = {
.get_voltage_sel = tps65023_dcdc_get_voltage_sel,
.set_voltage_sel = tps65023_dcdc_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
/* Operations permitted on LDOx */
@@ -212,6 +191,7 @@ static struct regulator_ops tps65023_ldo_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
static struct regmap_config tps65023_regmap_config = {
@@ -285,6 +265,10 @@ static int tps_65023_probe(struct i2c_client *client,
default: /* DCDCx */
tps->desc[i].enable_mask =
1 << (TPS65023_NUM_REGULATOR - i);
+ tps->desc[i].vsel_reg = TPS65023_REG_DEF_CORE;
+ tps->desc[i].vsel_mask = info->table_len - 1;
+ tps->desc[i].apply_reg = TPS65023_REG_CON_CTRL2;
+ tps->desc[i].apply_bit = TPS65023_REG_CTRL2_GO;
}
config.dev = &client->dev;
@@ -347,13 +331,13 @@ static const struct tps_info tps65020_regs[] = {
},
{
.name = "LDO1",
- .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
- .table = TPS65020_LDO1_VSEL_table,
+ .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
+ .table = TPS65020_LDO_VSEL_table,
},
{
.name = "LDO2",
- .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
- .table = TPS65020_LDO2_VSEL_table,
+ .table_len = ARRAY_SIZE(TPS65020_LDO_VSEL_table),
+ .table = TPS65020_LDO_VSEL_table,
},
};
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 54aa2da7283b..4117ff52dba1 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -356,6 +356,7 @@ static struct regulator_ops tps6507x_pmic_ops = {
.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
#ifdef CONFIG_OF
diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c
index 843ee0a9bb92..1094393155ed 100644
--- a/drivers/regulator/tps6524x-regulator.c
+++ b/drivers/regulator/tps6524x-regulator.c
@@ -572,6 +572,7 @@ static struct regulator_ops regulator_ops = {
.get_voltage_sel = get_voltage_sel,
.set_voltage_sel = set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.set_current_limit = set_current_limit,
.get_current_limit = get_current_limit,
};
@@ -584,8 +585,7 @@ static int pmic_remove(struct spi_device *spi)
if (!hw)
return 0;
for (i = 0; i < N_REGULATORS; i++) {
- if (hw->rdev[i])
- regulator_unregister(hw->rdev[i]);
+ regulator_unregister(hw->rdev[i]);
hw->rdev[i] = NULL;
}
spi_set_drvdata(spi, NULL);
diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c
index e68382d0e1ea..d8fa37d5c734 100644
--- a/drivers/regulator/tps6586x-regulator.c
+++ b/drivers/regulator/tps6586x-regulator.c
@@ -70,6 +70,7 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev)
static struct regulator_ops tps6586x_regulator_ops = {
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
@@ -245,7 +246,7 @@ static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev,
reg = TPS6586X_SM1SL;
break;
default:
- dev_warn(&pdev->dev, "Only SM0/SM1 can set slew rate\n");
+ dev_err(&pdev->dev, "Only SM0/SM1 can set slew rate\n");
return -EINVAL;
}
@@ -304,14 +305,12 @@ static struct tps6586x_platform_data *tps6586x_parse_regulator_dt(
}
err = of_regulator_match(&pdev->dev, regs, tps6586x_matches, num);
+ of_node_put(regs);
if (err < 0) {
dev_err(&pdev->dev, "Regulator match failed, e %d\n", err);
- of_node_put(regs);
return NULL;
}
- of_node_put(regs);
-
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev, "Memory alloction failed\n");
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 6ba6931ac855..45c16447744b 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -748,6 +748,7 @@ static struct regulator_ops tps65910_ops_dcdc = {
.set_voltage_sel = tps65910_set_voltage_dcdc_sel,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.list_voltage = tps65910_list_voltage_dcdc,
+ .map_voltage = regulator_map_voltage_ascend,
};
static struct regulator_ops tps65910_ops_vdd3 = {
@@ -758,6 +759,7 @@ static struct regulator_ops tps65910_ops_vdd3 = {
.get_mode = tps65910_get_mode,
.get_voltage = tps65910_get_voltage_vdd3,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
static struct regulator_ops tps65910_ops = {
@@ -769,6 +771,7 @@ static struct regulator_ops tps65910_ops = {
.get_voltage_sel = tps65910_get_voltage_sel,
.set_voltage_sel = tps65910_set_voltage_sel,
.list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_ascend,
};
static struct regulator_ops tps65911_ops = {
@@ -780,6 +783,7 @@ static struct regulator_ops tps65911_ops = {
.get_voltage_sel = tps65911_get_voltage_sel,
.set_voltage_sel = tps65911_set_voltage_sel,
.list_voltage = tps65911_list_voltage,
+ .map_voltage = regulator_map_voltage_ascend,
};
static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c
index 9019d0e7ecb6..6511d0bfd896 100644
--- a/drivers/regulator/tps80031-regulator.c
+++ b/drivers/regulator/tps80031-regulator.c
@@ -238,12 +238,11 @@ static int tps80031_dcdc_get_voltage_sel(struct regulator_dev *rdev)
return vsel & SMPS_VSEL_MASK;
}
-static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev,
- unsigned sel)
+static int tps80031_ldo_list_voltage(struct regulator_dev *rdev,
+ unsigned int sel)
{
struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps80031_dev(rdev);
- int ret;
/* Check for valid setting for TPS80031 or TPS80032-ES1.0 */
if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) &&
@@ -260,28 +259,27 @@ static int tps80031_ldo_set_voltage_sel(struct regulator_dev *rdev,
}
}
- ret = tps80031_write(parent, ri->rinfo->volt_id,
- ri->rinfo->volt_reg, sel);
- if (ret < 0)
- dev_err(ri->dev, "Error in writing reg 0x%02x, e = %d\n",
- ri->rinfo->volt_reg, ret);
- return ret;
+ return regulator_list_voltage_linear(rdev, sel);
}
-static int tps80031_ldo_get_voltage_sel(struct regulator_dev *rdev)
+static int tps80031_ldo_map_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
{
struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps80031_dev(rdev);
- uint8_t vsel;
- int ret;
- ret = tps80031_read(parent, ri->rinfo->volt_id,
- ri->rinfo->volt_reg, &vsel);
- if (ret < 0) {
- dev_err(ri->dev, "Error in writing the Voltage register\n");
- return ret;
+ /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */
+ if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) &&
+ (ri->device_flags & TRACK_MODE_ENABLE)) {
+ if (((tps80031_get_chip_info(parent) == TPS80031) ||
+ ((tps80031_get_chip_info(parent) == TPS80032) &&
+ (tps80031_get_pmu_version(parent) == 0x0)))) {
+ return regulator_map_voltage_iterate(rdev, min_uV,
+ max_uV);
+ }
}
- return vsel & rdev->desc->vsel_mask;
+
+ return regulator_map_voltage_linear(rdev, min_uV, max_uV);
}
static int tps80031_vbus_is_enabled(struct regulator_dev *rdev)
@@ -390,9 +388,10 @@ static struct regulator_ops tps80031_dcdc_ops = {
};
static struct regulator_ops tps80031_ldo_ops = {
- .list_voltage = regulator_list_voltage_linear,
- .set_voltage_sel = tps80031_ldo_set_voltage_sel,
- .get_voltage_sel = tps80031_ldo_get_voltage_sel,
+ .list_voltage = tps80031_ldo_list_voltage,
+ .map_voltage = tps80031_ldo_map_voltage,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
.enable = tps80031_reg_enable,
.disable = tps80031_reg_disable,
.is_enabled = tps80031_reg_is_enabled,
@@ -459,6 +458,7 @@ static struct regulator_ops tps80031_ext_reg_ops = {
.uV_step = 100000, \
.linear_min_sel = 1, \
.n_voltages = 25, \
+ .vsel_reg = TPS80031_##_id##_CFG_VOLTAGE, \
.vsel_mask = LDO_VSEL_MASK, \
.enable_time = 500, \
}, \
@@ -680,6 +680,7 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
struct tps80031_regulator *pmic;
struct regulator_dev *rdev;
struct regulator_config config = { };
+ struct tps80031 *tps80031_mfd = dev_get_drvdata(pdev->dev.parent);
int ret;
int num;
@@ -707,6 +708,8 @@ static int tps80031_regulator_probe(struct platform_device *pdev)
config.dev = &pdev->dev;
config.init_data = NULL;
config.driver_data = ri;
+ config.regmap = tps80031_mfd->regmap[ri->rinfo->volt_id];
+
if (tps_pdata) {
config.init_data = tps_pdata->reg_init_data;
ri->config_flags = tps_pdata->config_flags;
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index f705d25b437c..fb6e67d74ffb 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -441,12 +441,6 @@ static const u16 VSIM_VSEL_table[] = {
static const u16 VDAC_VSEL_table[] = {
1200, 1300, 1800, 1800,
};
-static const u16 VDD1_VSEL_table[] = {
- 800, 1450,
-};
-static const u16 VDD2_VSEL_table[] = {
- 800, 1450, 1500,
-};
static const u16 VIO_VSEL_table[] = {
1800, 1850,
};
@@ -615,18 +609,8 @@ static struct regulator_ops twl6030ldo_ops = {
/*----------------------------------------------------------------------*/
-/*
- * Fixed voltage LDOs don't have a VSEL field to update.
- */
-static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index)
-{
- struct twlreg_info *info = rdev_get_drvdata(rdev);
-
- return info->min_mV * 1000;
-}
-
static struct regulator_ops twl4030fixed_ops = {
- .list_voltage = twlfixed_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
.enable = twl4030reg_enable,
.disable = twl4030reg_disable,
@@ -638,7 +622,7 @@ static struct regulator_ops twl4030fixed_ops = {
};
static struct regulator_ops twl6030fixed_ops = {
- .list_voltage = twlfixed_list_voltage,
+ .list_voltage = regulator_list_voltage_linear,
.enable = twl6030reg_enable,
.disable = twl6030reg_disable,
@@ -944,19 +928,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \
.ops = &operations, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
- .enable_time = turnon_delay, \
- }, \
- }
-
-#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
-static struct twlreg_info TWLRES_INFO_##label = { \
- .base = offset, \
- .desc = { \
- .name = #label, \
- .id = TWL6030_REG_##label, \
- .ops = &twl6030_fixed_resource, \
- .type = REGULATOR_VOLTAGE, \
- .owner = THIS_MODULE, \
+ .min_uV = mVolts * 1000, \
.enable_time = turnon_delay, \
}, \
}
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 6ff872342648..a612c356a697 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -18,6 +18,7 @@
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -28,6 +29,8 @@
struct wm8994_ldo {
struct regulator_dev *regulator;
struct wm8994 *wm8994;
+ struct regulator_consumer_supply supply;
+ struct regulator_init_data init_data;
};
#define WM8994_LDO1_MAX_SELECTOR 0x7
@@ -99,6 +102,26 @@ static const struct regulator_desc wm8994_ldo_desc[] = {
},
};
+static const struct regulator_consumer_supply wm8994_ldo_consumer[] = {
+ { .supply = "AVDD1" },
+ { .supply = "DCVDD" },
+};
+
+static const struct regulator_init_data wm8994_ldo_default[] = {
+ {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ },
+ {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ },
+};
+
static int wm8994_ldo_probe(struct platform_device *pdev)
{
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
@@ -117,13 +140,29 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
}
ldo->wm8994 = wm8994;
+ ldo->supply = wm8994_ldo_consumer[id];
+ ldo->supply.dev_name = dev_name(wm8994->dev);
config.dev = wm8994->dev;
config.driver_data = ldo;
config.regmap = wm8994->regmap;
- if (pdata) {
- config.init_data = pdata->ldo[id].init_data;
+ config.init_data = &ldo->init_data;
+ if (pdata)
config.ena_gpio = pdata->ldo[id].enable;
+ else if (wm8994->dev->of_node)
+ config.ena_gpio = wm8994->pdata.ldo[id].enable;
+
+ /* Use default constraints if none set up */
+ if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) {
+ dev_dbg(wm8994->dev, "Using default init data, supply %s %s\n",
+ ldo->supply.dev_name, ldo->supply.supply);
+
+ ldo->init_data = wm8994_ldo_default[id];
+ ldo->init_data.consumer_supplies = &ldo->supply;
+ if (!config.ena_gpio)
+ ldo->init_data.constraints.valid_ops_mask = 0;
+ } else {
+ ldo->init_data = *pdata->ldo[id].init_data;
}
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config);
@@ -162,23 +201,7 @@ static struct platform_driver wm8994_ldo_driver = {
},
};
-static int __init wm8994_ldo_init(void)
-{
- int ret;
-
- ret = platform_driver_register(&wm8994_ldo_driver);
- if (ret != 0)
- pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret);
-
- return ret;
-}
-subsys_initcall(wm8994_ldo_init);
-
-static void __exit wm8994_ldo_exit(void)
-{
- platform_driver_unregister(&wm8994_ldo_driver);
-}
-module_exit(wm8994_ldo_exit);
+module_platform_driver(wm8994_ldo_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index cc1f7bf53fd0..c6d77e20622c 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -4,7 +4,7 @@ menu "Remoteproc drivers"
config REMOTEPROC
tristate
depends on HAS_DMA
- select FW_CONFIG
+ select FW_LOADER
select VIRTIO
config OMAP_REMOTEPROC
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 29387df4bfc9..814af5ab8a72 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -59,7 +59,7 @@ static const char *rproc_crash_to_string(enum rproc_crash_type type)
{
if (type < ARRAY_SIZE(rproc_crash_names))
return rproc_crash_names[type];
- return "unkown";
+ return "unknown";
}
/*
@@ -217,7 +217,7 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
* TODO: support predefined notifyids (via resource table)
*/
ret = idr_alloc(&rproc->notifyids, rvring, 0, 0, GFP_KERNEL);
- if (ret) {
+ if (ret < 0) {
dev_err(dev, "idr_alloc failed: %d\n", ret);
dma_free_coherent(dev->parent, size, va, dma);
return ret;
@@ -366,10 +366,12 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc,
/* it is now safe to add the virtio device */
ret = rproc_add_virtio_dev(rvdev, rsc->id);
if (ret)
- goto free_rvdev;
+ goto remove_rvdev;
return 0;
+remove_rvdev:
+ list_del(&rvdev->node);
free_rvdev:
kfree(rvdev);
return ret;
diff --git a/drivers/remoteproc/ste_modem_rproc.c b/drivers/remoteproc/ste_modem_rproc.c
index a7743c069339..fb95c4220052 100644
--- a/drivers/remoteproc/ste_modem_rproc.c
+++ b/drivers/remoteproc/ste_modem_rproc.c
@@ -240,6 +240,8 @@ static int sproc_drv_remove(struct platform_device *pdev)
/* Unregister as remoteproc device */
rproc_del(sproc->rproc);
+ dma_free_coherent(sproc->rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
rproc_put(sproc->rproc);
mdev->drv_data = NULL;
@@ -297,10 +299,13 @@ static int sproc_probe(struct platform_device *pdev)
/* Register as a remoteproc device */
err = rproc_add(rproc);
if (err)
- goto free_rproc;
+ goto free_mem;
return 0;
+free_mem:
+ dma_free_coherent(rproc->dev.parent, SPROC_FW_SIZE,
+ sproc->fw_addr, sproc->fw_dma_addr);
free_rproc:
/* Reset device data upon error */
mdev->drv_data = NULL;
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index a59684b5fc68..7861f1119b7d 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -951,8 +951,10 @@ static int rpmsg_probe(struct virtio_device *vdev)
bufs_va = dma_alloc_coherent(vdev->dev.parent->parent,
RPMSG_TOTAL_BUF_SPACE,
&vrp->bufs_dma, GFP_KERNEL);
- if (!bufs_va)
+ if (!bufs_va) {
+ err = -ENOMEM;
goto vqs_del;
+ }
dev_dbg(&vdev->dev, "buffers: va %p, dma 0x%llx\n", bufs_va,
(unsigned long long)vrp->bufs_dma);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 79fbe3832dfc..0c81915b1997 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -402,7 +402,7 @@ config RTC_DRV_TPS6586X
tristate "TI TPS6586X RTC driver"
depends on MFD_TPS6586X
help
- TI Power Managment IC TPS6586X supports RTC functionality
+ TI Power Management IC TPS6586X supports RTC functionality
along with alarm. This driver supports the RTC driver for
the TPS6586X RTC module.
@@ -420,7 +420,7 @@ config RTC_DRV_TPS80031
tristate "TI TPS80031/TPS80032 RTC driver"
depends on MFD_TPS80031
help
- TI Power Managment IC TPS80031 supports RTC functionality
+ TI Power Management IC TPS80031 supports RTC functionality
along with alarm. This driver supports the RTC driver for
the TPS80031 RTC module.
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 9b742d3ffb94..66385402d20e 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -259,6 +259,76 @@ void rtc_device_unregister(struct rtc_device *rtc)
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
+static void devm_rtc_device_release(struct device *dev, void *res)
+{
+ struct rtc_device *rtc = *(struct rtc_device **)res;
+
+ rtc_device_unregister(rtc);
+}
+
+static int devm_rtc_device_match(struct device *dev, void *res, void *data)
+{
+ struct rtc **r = res;
+
+ return *r == data;
+}
+
+/**
+ * devm_rtc_device_register - resource managed rtc_device_register()
+ * @dev: the device to register
+ * @name: the name of the device
+ * @ops: the rtc operations structure
+ * @owner: the module owner
+ *
+ * @return a struct rtc on success, or an ERR_PTR on error
+ *
+ * Managed rtc_device_register(). The rtc_device returned from this function
+ * are automatically freed on driver detach. See rtc_device_register()
+ * for more information.
+ */
+
+struct rtc_device *devm_rtc_device_register(struct device *dev,
+ const char *name,
+ const struct rtc_class_ops *ops,
+ struct module *owner)
+{
+ struct rtc_device **ptr, *rtc;
+
+ ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ rtc = rtc_device_register(name, dev, ops, owner);
+ if (!IS_ERR(rtc)) {
+ *ptr = rtc;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return rtc;
+}
+EXPORT_SYMBOL_GPL(devm_rtc_device_register);
+
+/**
+ * devm_rtc_device_unregister - resource managed devm_rtc_device_unregister()
+ * @dev: the device to unregister
+ * @rtc: the RTC class device to unregister
+ *
+ * Deallocated a rtc allocated with devm_rtc_device_register(). Normally this
+ * function will not need to be called and the resource management code will
+ * ensure that the resource is freed.
+ */
+void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_rtc_device_release,
+ devm_rtc_device_match, rtc);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_rtc_device_unregister);
+
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
index 63b17ebe90e8..f3742f364eb8 100644
--- a/drivers/rtc/rtc-88pm80x.c
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -234,7 +234,7 @@ static const struct rtc_class_ops pm80x_rtc_ops = {
.alarm_irq_enable = pm80x_rtc_alarm_irq_enable,
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int pm80x_rtc_suspend(struct device *dev)
{
return pm80x_dev_suspend(dev);
@@ -312,7 +312,7 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
}
rtc_tm_to_time(&tm, &ticks);
- info->rtc_dev = rtc_device_register("88pm80x-rtc", &pdev->dev,
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm80x-rtc",
&pm80x_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
ret = PTR_ERR(info->rtc_dev);
@@ -346,7 +346,6 @@ static int pm80x_rtc_remove(struct platform_device *pdev)
{
struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(info->rtc_dev);
pm80x_free_irq(info->chip, info->irq, info);
return 0;
}
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index f663746f4603..0f2b91bfee37 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -318,14 +318,14 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
- info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
- ret = -EINVAL;
- goto out;
+ return info->irq;
}
info->chip = chip;
@@ -333,12 +333,13 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, info);
- ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
- IRQF_ONESHOT, "rtc", info);
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+ rtc_update_handler, IRQF_ONESHOT, "rtc",
+ info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq, ret);
- goto out;
+ return ret;
}
/* set addresses of 32-bit base value for RTC time */
@@ -350,7 +351,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
ret = pm860x_rtc_read_time(&pdev->dev, &tm);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read initial time.\n");
- goto out_rtc;
+ return ret;
}
if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
tm.tm_year = 70;
@@ -362,7 +363,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
ret = pm860x_rtc_set_time(&pdev->dev, &tm);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to set initial time.\n");
- goto out_rtc;
+ return ret;
}
}
rtc_tm_to_time(&tm, &ticks);
@@ -373,12 +374,12 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
}
}
- info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm860x-rtc",
&pm860x_rtc_ops, THIS_MODULE);
ret = PTR_ERR(info->rtc_dev);
if (IS_ERR(info->rtc_dev)) {
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- goto out_rtc;
+ return ret;
}
/*
@@ -405,11 +406,6 @@ static int pm860x_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
return 0;
-out_rtc:
- free_irq(info->irq, info);
-out:
- kfree(info);
- return ret;
}
static int pm860x_rtc_remove(struct platform_device *pdev)
@@ -423,9 +419,6 @@ static int pm860x_rtc_remove(struct platform_device *pdev)
#endif /* VRTC_CALIBRATION */
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(info->rtc_dev);
- free_irq(info->irq, info);
- kfree(info);
return 0;
}
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index 261a07e0fb24..47a4f2c4d30e 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -229,8 +229,8 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
/* Ignore any error on this write */
}
- rtc = rtc_device_register("ab3100-rtc", &pdev->dev, &ab3100_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, "ab3100-rtc",
+ &ab3100_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
return err;
@@ -242,9 +242,6 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
static int __exit ab3100_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -257,19 +254,7 @@ static struct platform_driver ab3100_rtc_driver = {
.remove = __exit_p(ab3100_rtc_remove),
};
-static int __init ab3100_rtc_init(void)
-{
- return platform_driver_probe(&ab3100_rtc_driver,
- ab3100_rtc_probe);
-}
-
-static void __exit ab3100_rtc_exit(void)
-{
- platform_driver_unregister(&ab3100_rtc_driver);
-}
-
-module_init(ab3100_rtc_init);
-module_exit(ab3100_rtc_exit);
+module_platform_driver_probe(ab3100_rtc_driver, ab3100_rtc_probe);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("AB3100 RTC Driver");
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 57cde2b061e6..63cfa314a39f 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -422,20 +422,19 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, true);
- rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc",
+ &ab8500_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "Registration failed\n");
err = PTR_ERR(rtc);
return err;
}
- err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
- IRQF_NO_SUSPEND | IRQF_ONESHOT, "ab8500-rtc", rtc);
- if (err < 0) {
- rtc_device_unregister(rtc);
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ rtc_alarm_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ "ab8500-rtc", rtc);
+ if (err < 0)
return err;
- }
platform_set_drvdata(pdev, rtc);
@@ -450,13 +449,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
static int ab8500_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
- int irq = platform_get_irq_byname(pdev, "ALARM");
-
ab8500_sysfs_rtc_unregister(&pdev->dev);
- free_irq(irq, rtc);
- rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 8dd08305aae1..f47fbb5eee8b 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -202,7 +202,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
int irq;
int ret;
- rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL);
+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x),
+ GFP_KERNEL);
if (!rtc) {
dev_dbg(&pdev->dev, "out of memory\n");
return -ENOMEM;
@@ -223,7 +224,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
}
rtc->irq = irq;
- rtc->regs = ioremap(regs->start, resource_size(regs));
+ rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
if (!rtc->regs) {
ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
@@ -244,20 +245,21 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
| RTC_BIT(CTRL_EN));
}
- ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc);
+ ret = devm_request_irq(&pdev->dev, irq, at32_rtc_interrupt, IRQF_SHARED,
+ "rtc", rtc);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
- goto out_iounmap;
+ goto out;
}
platform_set_drvdata(pdev, rtc);
- rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&at32_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
dev_dbg(&pdev->dev, "could not register rtc device\n");
ret = PTR_ERR(rtc->rtc);
- goto out_free_irq;
+ goto out;
}
device_init_wakeup(&pdev->dev, 1);
@@ -267,26 +269,15 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
return 0;
-out_free_irq:
- platform_set_drvdata(pdev, NULL);
- free_irq(irq, rtc);
-out_iounmap:
- iounmap(rtc->regs);
out:
- kfree(rtc);
+ platform_set_drvdata(pdev, NULL);
return ret;
}
static int __exit at32_rtc_remove(struct platform_device *pdev)
{
- struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
-
device_init_wakeup(&pdev->dev, 0);
- free_irq(rtc->irq, rtc);
- iounmap(rtc->regs);
- rtc_device_unregister(rtc->rtc);
- kfree(rtc);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -302,17 +293,7 @@ static struct platform_driver at32_rtc_driver = {
},
};
-static int __init at32_rtc_init(void)
-{
- return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe);
-}
-module_init(at32_rtc_init);
-
-static void __exit at32_rtc_exit(void)
-{
- platform_driver_unregister(&at32_rtc_driver);
-}
-module_exit(at32_rtc_exit);
+module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 0a9f27e094ea..0eab77b22340 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -28,6 +28,8 @@
#include <linux/ioctl.h>
#include <linux/completion.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/uaccess.h>
@@ -44,7 +46,6 @@ static DECLARE_COMPLETION(at91_rtc_updated);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
-static u32 at91_rtc_imr;
/*
* Decode time/date into rtc_time structure
@@ -109,11 +110,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
cr = at91_rtc_read(AT91_RTC_CR);
at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
- at91_rtc_imr |= AT91_RTC_ACKUPD;
at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
- at91_rtc_imr &= ~AT91_RTC_ACKUPD;
at91_rtc_write(AT91_RTC_TIMR,
bin2bcd(tm->tm_sec) << 0
@@ -145,7 +144,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
- alrm->enabled = (at91_rtc_imr & AT91_RTC_ALARM)
+ alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
? 1 : 0;
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
@@ -171,7 +170,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm.tm_sec = alrm->time.tm_sec;
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
- at91_rtc_imr &= ~AT91_RTC_ALARM;
at91_rtc_write(AT91_RTC_TIMALR,
bin2bcd(tm.tm_sec) << 0
| bin2bcd(tm.tm_min) << 8
@@ -184,7 +182,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (alrm->enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_imr |= AT91_RTC_ALARM;
at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
}
@@ -201,12 +198,9 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_imr |= AT91_RTC_ALARM;
at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
- } else {
+ } else
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
- at91_rtc_imr &= ~AT91_RTC_ALARM;
- }
return 0;
}
@@ -215,10 +209,12 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
*/
static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
{
+ unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
+
seq_printf(seq, "update_IRQ\t: %s\n",
- (at91_rtc_imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+ (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
seq_printf(seq, "periodic_IRQ\t: %s\n",
- (at91_rtc_imr & AT91_RTC_SECEV) ? "yes" : "no");
+ (imr & AT91_RTC_SECEV) ? "yes" : "no");
return 0;
}
@@ -233,7 +229,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
unsigned int rtsr;
unsigned long events = 0;
- rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_imr;
+ rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
if (rtsr) { /* this interrupt is shared! Is it ours? */
if (rtsr & AT91_RTC_ALARM)
events |= (RTC_AF | RTC_IRQF);
@@ -297,14 +293,13 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
- at91_rtc_imr = 0;
ret = request_irq(irq, at91_rtc_interrupt,
IRQF_SHARED,
"at91_rtc", pdev);
if (ret) {
dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
- return ret;
+ goto err_unmap;
}
/* cpu init code should really have flagged this device as
@@ -316,13 +311,20 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
rtc = rtc_device_register(pdev->name, &pdev->dev,
&at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
- free_irq(irq, pdev);
- return PTR_ERR(rtc);
+ ret = PTR_ERR(rtc);
+ goto err_free_irq;
}
platform_set_drvdata(pdev, rtc);
dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
return 0;
+
+err_free_irq:
+ free_irq(irq, pdev);
+err_unmap:
+ iounmap(at91_rtc_regs);
+
+ return ret;
}
/*
@@ -336,84 +338,68 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
- at91_rtc_imr = 0;
free_irq(irq, pdev);
rtc_device_unregister(rtc);
+ iounmap(at91_rtc_regs);
platform_set_drvdata(pdev, NULL);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* AT91RM9200 RTC Power management control */
-static u32 at91_rtc_bkpimr;
-
+static u32 at91_rtc_imr;
static int at91_rtc_suspend(struct device *dev)
{
/* this IRQ is shared with DBGU and other hardware which isn't
* necessarily doing PM like we are...
*/
- at91_rtc_bkpimr = at91_rtc_imr & (AT91_RTC_ALARM|AT91_RTC_SECEV);
- if (at91_rtc_bkpimr) {
- if (device_may_wakeup(dev)) {
+ at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
+ & (AT91_RTC_ALARM|AT91_RTC_SECEV);
+ if (at91_rtc_imr) {
+ if (device_may_wakeup(dev))
enable_irq_wake(irq);
- } else {
- at91_rtc_write(AT91_RTC_IDR, at91_rtc_bkpimr);
- at91_rtc_imr &= ~at91_rtc_bkpimr;
- }
-}
+ else
+ at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
+ }
return 0;
}
static int at91_rtc_resume(struct device *dev)
{
- if (at91_rtc_bkpimr) {
- if (device_may_wakeup(dev)) {
+ if (at91_rtc_imr) {
+ if (device_may_wakeup(dev))
disable_irq_wake(irq);
- } else {
- at91_rtc_imr |= at91_rtc_bkpimr;
- at91_rtc_write(AT91_RTC_IER, at91_rtc_bkpimr);
- }
+ else
+ at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
}
return 0;
}
+#endif
-static const struct dev_pm_ops at91_rtc_pm = {
- .suspend = at91_rtc_suspend,
- .resume = at91_rtc_resume,
-};
-
-#define at91_rtc_pm_ptr &at91_rtc_pm
+static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
-#else
-#define at91_rtc_pm_ptr NULL
-#endif
+static const struct of_device_id at91_rtc_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-rtc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
.driver = {
.name = "at91_rtc",
.owner = THIS_MODULE,
- .pm = at91_rtc_pm_ptr,
+ .pm = &at91_rtc_pm_ops,
+ .of_match_table = of_match_ptr(at91_rtc_dt_ids),
},
};
-static int __init at91_rtc_init(void)
-{
- return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
-}
-
-static void __exit at91_rtc_exit(void)
-{
- platform_driver_unregister(&at91_rtc_driver);
-}
-
-module_init(at91_rtc_init);
-module_exit(at91_rtc_exit);
+module_platform_driver_probe(at91_rtc_driver, at91_rtc_probe);
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h
index 5f940b6844cb..da1945e5f714 100644
--- a/drivers/rtc/rtc-at91rm9200.h
+++ b/drivers/rtc/rtc-at91rm9200.h
@@ -64,6 +64,7 @@
#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
#define AT91_RTC_VER 0x2c /* Valid Entry Register */
#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 39cfd2ee0042..b60a34cb145a 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -20,6 +20,7 @@
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/platform_data/atmel.h>
+#include <linux/io.h>
#include <mach/at91_rtt.h>
#include <mach/cpu.h>
@@ -309,7 +310,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
return irq;
}
- rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
@@ -320,18 +321,19 @@ static int at91_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, rtc);
- rtc->rtt = ioremap(r->start, resource_size(r));
+ rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!rtc->rtt) {
dev_err(&pdev->dev, "failed to map registers, aborting.\n");
ret = -ENOMEM;
goto fail;
}
- rtc->gpbr = ioremap(r_gpbr->start, resource_size(r_gpbr));
+ rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start,
+ resource_size(r_gpbr));
if (!rtc->gpbr) {
dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
ret = -ENOMEM;
- goto fail_gpbr;
+ goto fail;
}
mr = rtt_readl(rtc, MR);
@@ -346,20 +348,19 @@ static int at91_rtc_probe(struct platform_device *pdev)
mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
rtt_writel(rtc, MR, mr);
- rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
- &at91_rtc_ops, THIS_MODULE);
+ rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtcdev)) {
ret = PTR_ERR(rtc->rtcdev);
- goto fail_register;
+ goto fail;
}
/* register irq handler after we know what name we'll use */
- ret = request_irq(rtc->irq, at91_rtc_interrupt, IRQF_SHARED,
- dev_name(&rtc->rtcdev->dev), rtc);
+ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
+ IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
if (ret) {
dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
- rtc_device_unregister(rtc->rtcdev);
- goto fail_register;
+ goto fail;
}
/* NOTE: sam9260 rev A silicon has a ROM bug which resets the
@@ -374,13 +375,8 @@ static int at91_rtc_probe(struct platform_device *pdev)
return 0;
-fail_register:
- iounmap(rtc->gpbr);
-fail_gpbr:
- iounmap(rtc->rtt);
fail:
platform_set_drvdata(pdev, NULL);
- kfree(rtc);
return ret;
}
@@ -394,14 +390,8 @@ static int at91_rtc_remove(struct platform_device *pdev)
/* disable all interrupts */
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
- free_irq(rtc->irq, rtc);
-
- rtc_device_unregister(rtc->rtcdev);
- iounmap(rtc->gpbr);
- iounmap(rtc->rtt);
platform_set_drvdata(pdev, NULL);
- kfree(rtc);
return 0;
}
@@ -414,14 +404,13 @@ static void at91_rtc_shutdown(struct platform_device *pdev)
rtt_writel(rtc, MR, mr & ~rtc->imr);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* AT91SAM9 RTC Power management control */
-static int at91_rtc_suspend(struct platform_device *pdev,
- pm_message_t state)
+static int at91_rtc_suspend(struct device *dev)
{
- struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
u32 mr = rtt_readl(rtc, MR);
/*
@@ -430,7 +419,7 @@ static int at91_rtc_suspend(struct platform_device *pdev,
*/
rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
if (rtc->imr) {
- if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
+ if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) {
enable_irq_wake(rtc->irq);
/* don't let RTTINC cause wakeups */
if (mr & AT91_RTT_RTTINCIEN)
@@ -442,13 +431,13 @@ static int at91_rtc_suspend(struct platform_device *pdev,
return 0;
}
-static int at91_rtc_resume(struct platform_device *pdev)
+static int at91_rtc_resume(struct device *dev)
{
- struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
u32 mr;
if (rtc->imr) {
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
disable_irq_wake(rtc->irq);
mr = rtt_readl(rtc, MR);
rtt_writel(rtc, MR, mr | rtc->imr);
@@ -456,20 +445,18 @@ static int at91_rtc_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define at91_rtc_suspend NULL
-#define at91_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
+
static struct platform_driver at91_rtc_driver = {
.probe = at91_rtc_probe,
.remove = at91_rtc_remove,
.shutdown = at91_rtc_shutdown,
- .suspend = at91_rtc_suspend,
- .resume = at91_rtc_resume,
.driver = {
.name = "rtc-at91sam9",
.owner = THIS_MODULE,
+ .pm = &at91_rtc_pm_ops,
},
};
diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c
index b309da4ec745..7995abc391fc 100644
--- a/drivers/rtc/rtc-au1xxx.c
+++ b/drivers/rtc/rtc-au1xxx.c
@@ -101,7 +101,7 @@ static int au1xtoy_rtc_probe(struct platform_device *pdev)
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S)
msleep(1);
- rtcdev = rtc_device_register("rtc-au1xxx", &pdev->dev,
+ rtcdev = devm_rtc_device_register(&pdev->dev, "rtc-au1xxx",
&au1xtoy_rtc_ops, THIS_MODULE);
if (IS_ERR(rtcdev)) {
ret = PTR_ERR(rtcdev);
@@ -118,9 +118,6 @@ out_err:
static int au1xtoy_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtcdev = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtcdev);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -134,18 +131,7 @@ static struct platform_driver au1xrtc_driver = {
.remove = au1xtoy_rtc_remove,
};
-static int __init au1xtoy_rtc_init(void)
-{
- return platform_driver_probe(&au1xrtc_driver, au1xtoy_rtc_probe);
-}
-
-static void __exit au1xtoy_rtc_exit(void)
-{
- platform_driver_unregister(&au1xrtc_driver);
-}
-
-module_init(au1xtoy_rtc_init);
-module_exit(au1xtoy_rtc_exit);
+module_platform_driver_probe(au1xrtc_driver, au1xtoy_rtc_probe);
MODULE_DESCRIPTION("Au1xxx TOY-counter-based RTC driver");
MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>");
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 4ec614b0954d..ad44ec5dc29a 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -352,14 +352,14 @@ static int bfin_rtc_probe(struct platform_device *pdev)
dev_dbg_stamp(dev);
/* Allocate memory for our RTC struct */
- rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
device_init_wakeup(dev, 1);
/* Register our RTC with the RTC framework */
- rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops,
+ rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,
THIS_MODULE);
if (unlikely(IS_ERR(rtc->rtc_dev))) {
ret = PTR_ERR(rtc->rtc_dev);
@@ -367,9 +367,10 @@ static int bfin_rtc_probe(struct platform_device *pdev)
}
/* Grab the IRQ and init the hardware */
- ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, 0, pdev->name, dev);
+ ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0,
+ pdev->name, dev);
if (unlikely(ret))
- goto err_reg;
+ goto err;
/* sometimes the bootloader touched things, but the write complete was not
* enabled, so let's just do a quick timeout here since the IRQ will not fire ...
*/
@@ -381,32 +382,23 @@ static int bfin_rtc_probe(struct platform_device *pdev)
return 0;
-err_reg:
- rtc_device_unregister(rtc->rtc_dev);
err:
- kfree(rtc);
return ret;
}
static int bfin_rtc_remove(struct platform_device *pdev)
{
- struct bfin_rtc *rtc = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
bfin_rtc_reset(dev, 0);
- free_irq(IRQ_RTC, dev);
- rtc_device_unregister(rtc->rtc_dev);
platform_set_drvdata(pdev, NULL);
- kfree(rtc);
return 0;
}
-#ifdef CONFIG_PM
-static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int bfin_rtc_suspend(struct device *dev)
{
- struct device *dev = &pdev->dev;
-
dev_dbg_stamp(dev);
if (device_may_wakeup(dev)) {
@@ -418,10 +410,8 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int bfin_rtc_resume(struct platform_device *pdev)
+static int bfin_rtc_resume(struct device *dev)
{
- struct device *dev = &pdev->dev;
-
dev_dbg_stamp(dev);
if (device_may_wakeup(dev))
@@ -440,20 +430,18 @@ static int bfin_rtc_resume(struct platform_device *pdev)
return 0;
}
-#else
-# define bfin_rtc_suspend NULL
-# define bfin_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(bfin_rtc_pm_ops, bfin_rtc_suspend, bfin_rtc_resume);
+
static struct platform_driver bfin_rtc_driver = {
.driver = {
.name = "rtc-bfin",
.owner = THIS_MODULE,
+ .pm = &bfin_rtc_pm_ops,
},
.probe = bfin_rtc_probe,
.remove = bfin_rtc_remove,
- .suspend = bfin_rtc_suspend,
- .resume = bfin_rtc_resume,
};
module_platform_driver(bfin_rtc_driver);
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index 036cb89f8188..fea78bc713ca 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -153,7 +153,7 @@ static int bq32k_probe(struct i2c_client *client,
if (error)
return error;
- rtc = rtc_device_register(bq32k_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
&bq32k_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -165,9 +165,6 @@ static int bq32k_probe(struct i2c_client *client,
static int bq32k_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- rtc_device_unregister(rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
index 693be71b5b18..af2886784a7b 100644
--- a/drivers/rtc/rtc-bq4802.c
+++ b/drivers/rtc/rtc-bq4802.c
@@ -142,7 +142,7 @@ static const struct rtc_class_ops bq4802_ops = {
static int bq4802_probe(struct platform_device *pdev)
{
- struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct bq4802 *p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
int err = -ENOMEM;
if (!p)
@@ -155,54 +155,41 @@ static int bq4802_probe(struct platform_device *pdev)
p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
err = -EINVAL;
if (!p->r)
- goto out_free;
+ goto out;
}
if (p->r->flags & IORESOURCE_IO) {
p->ioport = p->r->start;
p->read = bq4802_read_io;
p->write = bq4802_write_io;
} else if (p->r->flags & IORESOURCE_MEM) {
- p->regs = ioremap(p->r->start, resource_size(p->r));
+ p->regs = devm_ioremap(&pdev->dev, p->r->start,
+ resource_size(p->r));
p->read = bq4802_read_mem;
p->write = bq4802_write_mem;
} else {
err = -EINVAL;
- goto out_free;
+ goto out;
}
platform_set_drvdata(pdev, p);
- p->rtc = rtc_device_register("bq4802", &pdev->dev,
- &bq4802_ops, THIS_MODULE);
+ p->rtc = devm_rtc_device_register(&pdev->dev, "bq4802",
+ &bq4802_ops, THIS_MODULE);
if (IS_ERR(p->rtc)) {
err = PTR_ERR(p->rtc);
- goto out_iounmap;
+ goto out;
}
err = 0;
out:
return err;
-out_iounmap:
- if (p->r->flags & IORESOURCE_MEM)
- iounmap(p->regs);
-out_free:
- kfree(p);
- goto out;
}
static int bq4802_remove(struct platform_device *pdev)
{
- struct bq4802 *p = platform_get_drvdata(pdev);
-
- rtc_device_unregister(p->rtc);
- if (p->r->flags & IORESOURCE_MEM)
- iounmap(p->regs);
-
platform_set_drvdata(pdev, NULL);
- kfree(p);
-
return 0;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index af97c94e8a3a..cc5bea9c4b1c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -804,9 +804,8 @@ static int cmos_suspend(struct device *dev)
mask = RTC_IRQMASK;
tmp &= ~mask;
CMOS_WRITE(tmp, RTC_CONTROL);
+ hpet_mask_rtc_irq_bit(mask);
- /* shut down hpet emulation - we don't need it for alarm */
- hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
cmos_checkintr(cmos, tmp);
}
spin_unlock_irq(&rtc_lock);
@@ -870,6 +869,7 @@ static int cmos_resume(struct device *dev)
rtc_update_irq(cmos->rtc, 1, mask);
tmp &= ~RTC_AIE;
hpet_mask_rtc_irq_bit(RTC_AIE);
+ hpet_rtc_timer_init();
} while (mask & RTC_AIE);
spin_unlock_irq(&rtc_lock);
}
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 2d28ec1aa1cd..93c06588ddca 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -47,7 +47,7 @@ struct coh901331_port {
u32 physize;
void __iomem *virtbase;
int irq;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 irqmaskstore;
#endif
};
@@ -155,7 +155,6 @@ static int __exit coh901331_remove(struct platform_device *pdev)
struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
if (rtap) {
- rtc_device_unregister(rtap->rtc);
clk_unprepare(rtap->clk);
platform_set_drvdata(pdev, NULL);
}
@@ -211,8 +210,8 @@ static int __init coh901331_probe(struct platform_device *pdev)
clk_disable(rtap->clk);
platform_set_drvdata(pdev, rtap);
- rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops,
- THIS_MODULE);
+ rtap->rtc = devm_rtc_device_register(&pdev->dev, "coh901331",
+ &coh901331_ops, THIS_MODULE);
if (IS_ERR(rtap->rtc)) {
ret = PTR_ERR(rtap->rtc);
goto out_no_rtc;
@@ -226,17 +225,17 @@ static int __init coh901331_probe(struct platform_device *pdev)
return ret;
}
-#ifdef CONFIG_PM
-static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int coh901331_suspend(struct device *dev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+ struct coh901331_port *rtap = dev_get_drvdata(dev);
/*
* If this RTC alarm will be used for waking the system up,
* don't disable it of course. Else we just disable the alarm
* and await suspension.
*/
- if (device_may_wakeup(&pdev->dev)) {
+ if (device_may_wakeup(dev)) {
enable_irq_wake(rtap->irq);
} else {
clk_enable(rtap->clk);
@@ -248,12 +247,12 @@ static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int coh901331_resume(struct platform_device *pdev)
+static int coh901331_resume(struct device *dev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+ struct coh901331_port *rtap = dev_get_drvdata(dev);
clk_prepare(rtap->clk);
- if (device_may_wakeup(&pdev->dev)) {
+ if (device_may_wakeup(dev)) {
disable_irq_wake(rtap->irq);
} else {
clk_enable(rtap->clk);
@@ -262,11 +261,10 @@ static int coh901331_resume(struct platform_device *pdev)
}
return 0;
}
-#else
-#define coh901331_suspend NULL
-#define coh901331_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(coh901331_pm_ops, coh901331_suspend, coh901331_resume);
+
static void coh901331_shutdown(struct platform_device *pdev)
{
struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
@@ -280,25 +278,13 @@ static struct platform_driver coh901331_driver = {
.driver = {
.name = "rtc-coh901331",
.owner = THIS_MODULE,
+ .pm = &coh901331_pm_ops,
},
.remove = __exit_p(coh901331_remove),
- .suspend = coh901331_suspend,
- .resume = coh901331_resume,
.shutdown = coh901331_shutdown,
};
-static int __init coh901331_init(void)
-{
- return platform_driver_probe(&coh901331_driver, coh901331_probe);
-}
-
-static void __exit coh901331_exit(void)
-{
- platform_driver_unregister(&coh901331_driver);
-}
-
-module_init(coh901331_init);
-module_exit(coh901331_exit);
+module_platform_driver_probe(coh901331_driver, coh901331_probe);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("ST-Ericsson AB COH 901 331 RTC Driver");
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
index 969abbad7fe3..7286b279cf2d 100644
--- a/drivers/rtc/rtc-da9052.c
+++ b/drivers/rtc/rtc-da9052.c
@@ -247,7 +247,7 @@ static int da9052_rtc_probe(struct platform_device *pdev)
return ret;
}
- rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&da9052_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc))
return PTR_ERR(rtc->rtc);
@@ -257,9 +257,6 @@ static int da9052_rtc_probe(struct platform_device *pdev)
static int da9052_rtc_remove(struct platform_device *pdev)
{
- struct da9052_rtc *rtc = pdev->dev.platform_data;
-
- rtc_device_unregister(rtc->rtc);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
index 8f0dcfedb83c..73858ca9709a 100644
--- a/drivers/rtc/rtc-da9055.c
+++ b/drivers/rtc/rtc-da9055.c
@@ -294,7 +294,7 @@ static int da9055_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&da9055_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
ret = PTR_ERR(rtc->rtc);
@@ -317,9 +317,6 @@ err_rtc:
static int da9055_rtc_remove(struct platform_device *pdev)
{
- struct da9055_rtc *rtc = pdev->dev.platform_data;
-
- rtc_device_unregister(rtc->rtc);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 56b73089bb29..a55048c3e26f 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -523,7 +523,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, davinci_rtc);
- davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&davinci_rtc_ops, THIS_MODULE);
if (IS_ERR(davinci_rtc->rtc)) {
ret = PTR_ERR(davinci_rtc->rtc);
@@ -543,7 +543,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
0, "davinci_rtc", davinci_rtc);
if (ret < 0) {
dev_err(dev, "unable to register davinci RTC interrupt\n");
- goto fail2;
+ goto fail1;
}
/* Enable interrupts */
@@ -557,14 +557,12 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
return 0;
-fail2:
- rtc_device_unregister(davinci_rtc->rtc);
fail1:
platform_set_drvdata(pdev, NULL);
return ret;
}
-static int davinci_rtc_remove(struct platform_device *pdev)
+static int __exit davinci_rtc_remove(struct platform_device *pdev)
{
struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev);
@@ -572,8 +570,6 @@ static int davinci_rtc_remove(struct platform_device *pdev)
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
- rtc_device_unregister(davinci_rtc->rtc);
-
platform_set_drvdata(pdev, NULL);
return 0;
@@ -581,24 +577,14 @@ static int davinci_rtc_remove(struct platform_device *pdev)
static struct platform_driver davinci_rtc_driver = {
.probe = davinci_rtc_probe,
- .remove = davinci_rtc_remove,
+ .remove = __exit_p(davinci_rtc_remove),
.driver = {
.name = "rtc_davinci",
.owner = THIS_MODULE,
},
};
-static int __init rtc_init(void)
-{
- return platform_driver_probe(&davinci_rtc_driver, davinci_rtc_probe);
-}
-module_init(rtc_init);
-
-static void __exit rtc_exit(void)
-{
- platform_driver_unregister(&davinci_rtc_driver);
-}
-module_exit(rtc_exit);
+module_platform_driver_probe(davinci_rtc_driver, davinci_rtc_probe);
MODULE_AUTHOR("Miguel Aguilar <miguel.aguilar@ridgerun.com>");
MODULE_DESCRIPTION("Texas Instruments DaVinci PRTC Driver");
diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c
index b2ed2c94b081..1e1ca63d58a9 100644
--- a/drivers/rtc/rtc-dm355evm.c
+++ b/drivers/rtc/rtc-dm355evm.c
@@ -127,8 +127,8 @@ static int dm355evm_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register(pdev->name,
- &pdev->dev, &dm355evm_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &dm355evm_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc));
@@ -141,9 +141,6 @@ static int dm355evm_rtc_probe(struct platform_device *pdev)
static int dm355evm_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
index 45cd8c9f5a39..c7702b7269f7 100644
--- a/drivers/rtc/rtc-ds1216.c
+++ b/drivers/rtc/rtc-ds1216.c
@@ -30,8 +30,6 @@ struct ds1216_regs {
struct ds1216_priv {
struct rtc_device *rtc;
void __iomem *ioaddr;
- size_t size;
- unsigned long baseaddr;
};
static const u8 magic[] = {
@@ -144,57 +142,33 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct ds1216_priv *priv;
- int ret = 0;
u8 dummy[8];
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof *priv, GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
- priv->size = resource_size(res);
- if (!request_mem_region(res->start, priv->size, pdev->name)) {
- ret = -EBUSY;
- goto out;
- }
- priv->baseaddr = res->start;
- priv->ioaddr = ioremap(priv->baseaddr, priv->size);
- if (!priv->ioaddr) {
- ret = -ENOMEM;
- goto out;
- }
- priv->rtc = rtc_device_register("ds1216", &pdev->dev,
- &ds1216_rtc_ops, THIS_MODULE);
- if (IS_ERR(priv->rtc)) {
- ret = PTR_ERR(priv->rtc);
- goto out;
- }
+ priv->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->ioaddr))
+ return PTR_ERR(priv->ioaddr);
+
+ priv->rtc = devm_rtc_device_register(&pdev->dev, "ds1216",
+ &ds1216_rtc_ops, THIS_MODULE);
+ if (IS_ERR(priv->rtc))
+ return PTR_ERR(priv->rtc);
/* dummy read to get clock into a known state */
ds1216_read(priv->ioaddr, dummy);
return 0;
-
-out:
- if (priv->ioaddr)
- iounmap(priv->ioaddr);
- if (priv->baseaddr)
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return ret;
}
static int __exit ds1216_rtc_remove(struct platform_device *pdev)
{
- struct ds1216_priv *priv = platform_get_drvdata(pdev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->ioaddr);
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
return 0;
}
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
index d989412a348a..398c96a98fc4 100644
--- a/drivers/rtc/rtc-ds1286.c
+++ b/drivers/rtc/rtc-ds1286.c
@@ -25,8 +25,6 @@
struct ds1286_priv {
struct rtc_device *rtc;
u32 __iomem *rtcregs;
- size_t size;
- unsigned long baseaddr;
spinlock_t lock;
};
@@ -270,7 +268,6 @@ static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
- unsigned char cmd;
unsigned long flags;
/*
@@ -281,7 +278,7 @@ static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f;
alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07;
- cmd = ds1286_rtc_read(priv, RTC_CMD);
+ ds1286_rtc_read(priv, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
alm->time.tm_min = bcd2bin(alm->time.tm_min);
@@ -334,56 +331,30 @@ static int ds1286_probe(struct platform_device *pdev)
struct rtc_device *rtc;
struct resource *res;
struct ds1286_priv *priv;
- int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->size = resource_size(res);
- if (!request_mem_region(res->start, priv->size, pdev->name)) {
- ret = -EBUSY;
- goto out;
- }
- priv->baseaddr = res->start;
- priv->rtcregs = ioremap(priv->baseaddr, priv->size);
- if (!priv->rtcregs) {
- ret = -ENOMEM;
- goto out;
- }
+ priv->rtcregs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->rtcregs))
+ return PTR_ERR(priv->rtcregs);
+
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
- rtc = rtc_device_register("ds1286", &pdev->dev,
- &ds1286_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- ret = PTR_ERR(rtc);
- goto out;
- }
+ rtc = devm_rtc_device_register(&pdev->dev, "ds1286", &ds1286_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
priv->rtc = rtc;
return 0;
-
-out:
- if (priv->rtc)
- rtc_device_unregister(priv->rtc);
- if (priv->rtcregs)
- iounmap(priv->rtcregs);
- if (priv->baseaddr)
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return ret;
}
static int ds1286_remove(struct platform_device *pdev)
{
- struct ds1286_priv *priv = platform_get_drvdata(pdev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->rtcregs);
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
return 0;
}
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index fdbcdb289d60..d13954346286 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -224,7 +224,7 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
return -ENODEV;
}
- rtc = rtc_device_register("ds1302", &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, "ds1302",
&ds1302_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -234,11 +234,8 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int ds1302_rtc_remove(struct platform_device *pdev)
+static int __exit ds1302_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -249,21 +246,10 @@ static struct platform_driver ds1302_platform_driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .remove = ds1302_rtc_remove,
+ .remove = __exit_p(ds1302_rtc_remove),
};
-static int __init ds1302_rtc_init(void)
-{
- return platform_driver_probe(&ds1302_platform_driver, ds1302_rtc_probe);
-}
-
-static void __exit ds1302_rtc_exit(void)
-{
- platform_driver_unregister(&ds1302_platform_driver);
-}
-
-module_init(ds1302_rtc_init);
-module_exit(ds1302_rtc_exit);
+module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe);
MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index b05a6dc96405..bb5f13f63630 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -619,7 +619,7 @@ static int ds1305_probe(struct spi_device *spi)
return -EINVAL;
/* set up driver data */
- ds1305 = kzalloc(sizeof *ds1305, GFP_KERNEL);
+ ds1305 = devm_kzalloc(&spi->dev, sizeof(*ds1305), GFP_KERNEL);
if (!ds1305)
return -ENOMEM;
ds1305->spi = spi;
@@ -632,7 +632,7 @@ static int ds1305_probe(struct spi_device *spi)
if (status < 0) {
dev_dbg(&spi->dev, "can't %s, %d\n",
"read", status);
- goto fail0;
+ return status;
}
dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
@@ -644,8 +644,7 @@ static int ds1305_probe(struct spi_device *spi)
*/
if ((ds1305->ctrl[0] & 0x38) != 0 || (ds1305->ctrl[1] & 0xfc) != 0) {
dev_dbg(&spi->dev, "RTC chip is not present\n");
- status = -ENODEV;
- goto fail0;
+ return -ENODEV;
}
if (ds1305->ctrl[2] == 0)
dev_dbg(&spi->dev, "chip may not be present\n");
@@ -664,7 +663,7 @@ static int ds1305_probe(struct spi_device *spi)
dev_dbg(&spi->dev, "clear WP --> %d\n", status);
if (status < 0)
- goto fail0;
+ return status;
}
/* on DS1305, maybe start oscillator; like most low power
@@ -718,7 +717,7 @@ static int ds1305_probe(struct spi_device *spi)
if (status < 0) {
dev_dbg(&spi->dev, "can't %s, %d\n",
"write", status);
- goto fail0;
+ return status;
}
dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
@@ -730,7 +729,7 @@ static int ds1305_probe(struct spi_device *spi)
&value, sizeof value);
if (status < 0) {
dev_dbg(&spi->dev, "read HOUR --> %d\n", status);
- goto fail0;
+ return status;
}
ds1305->hr12 = (DS1305_HR_12 & value) != 0;
@@ -738,12 +737,12 @@ static int ds1305_probe(struct spi_device *spi)
dev_dbg(&spi->dev, "AM/PM\n");
/* register RTC ... from here on, ds1305->ctrl needs locking */
- ds1305->rtc = rtc_device_register("ds1305", &spi->dev,
+ ds1305->rtc = devm_rtc_device_register(&spi->dev, "ds1305",
&ds1305_ops, THIS_MODULE);
if (IS_ERR(ds1305->rtc)) {
status = PTR_ERR(ds1305->rtc);
dev_dbg(&spi->dev, "register rtc --> %d\n", status);
- goto fail0;
+ return status;
}
/* Maybe set up alarm IRQ; be ready to handle it triggering right
@@ -754,12 +753,12 @@ static int ds1305_probe(struct spi_device *spi)
*/
if (spi->irq) {
INIT_WORK(&ds1305->work, ds1305_work);
- status = request_irq(spi->irq, ds1305_irq,
+ status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,
0, dev_name(&ds1305->rtc->dev), ds1305);
if (status < 0) {
dev_dbg(&spi->dev, "request_irq %d --> %d\n",
spi->irq, status);
- goto fail1;
+ return status;
}
device_set_wakeup_capable(&spi->dev, 1);
@@ -769,18 +768,10 @@ static int ds1305_probe(struct spi_device *spi)
status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
if (status < 0) {
dev_dbg(&spi->dev, "register nvram --> %d\n", status);
- goto fail2;
+ return status;
}
return 0;
-
-fail2:
- free_irq(spi->irq, ds1305);
-fail1:
- rtc_device_unregister(ds1305->rtc);
-fail0:
- kfree(ds1305);
- return status;
}
static int ds1305_remove(struct spi_device *spi)
@@ -792,13 +783,11 @@ static int ds1305_remove(struct spi_device *spi)
/* carefully shut down irq and workqueue, if present */
if (spi->irq) {
set_bit(FLAG_EXITING, &ds1305->flags);
- free_irq(spi->irq, ds1305);
+ devm_free_irq(&spi->dev, spi->irq, ds1305);
cancel_work_sync(&ds1305->work);
}
- rtc_device_unregister(ds1305->rtc);
spi_set_drvdata(spi, NULL);
- kfree(ds1305);
return 0;
}
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 970a236b147a..b53992ab3090 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -4,6 +4,7 @@
* Copyright (C) 2005 James Chapman (ds1337 core)
* Copyright (C) 2006 David Brownell
* Copyright (C) 2009 Matthias Fuchs (rx8025 support)
+ * Copyright (C) 2012 Bertrand Achard (nvram access fixes)
*
* 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
@@ -196,7 +197,7 @@ static s32 ds1307_read_block_data_once(const struct i2c_client *client,
static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
u8 length, u8 *values)
{
- u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 oldvalues[255];
s32 ret;
int tries = 0;
@@ -222,7 +223,7 @@ static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
- u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 currvalues[255];
int tries = 0;
dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
@@ -250,6 +251,57 @@ static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
/*----------------------------------------------------------------------*/
+/* These RTC devices are not designed to be connected to a SMbus adapter.
+ SMbus limits block operations length to 32 bytes, whereas it's not
+ limited on I2C buses. As a result, accesses may exceed 32 bytes;
+ in that case, split them into smaller blocks */
+
+static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
+ u8 command, u8 length, const u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_write_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_write_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
+ u8 command, u8 length, u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_read_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_read_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+/*----------------------------------------------------------------------*/
+
/*
* The IRQ logic includes a "real" handler running in IRQ context just
* long enough to schedule this workqueue entry. We need a task context
@@ -646,8 +698,8 @@ static int ds1307_probe(struct i2c_client *client,
buf = ds1307->regs;
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
- ds1307->read_block_data = i2c_smbus_read_i2c_block_data;
- ds1307->write_block_data = i2c_smbus_write_i2c_block_data;
+ ds1307->read_block_data = ds1307_native_smbus_read_block_data;
+ ds1307->write_block_data = ds1307_native_smbus_write_block_data;
} else {
ds1307->read_block_data = ds1307_read_block_data;
ds1307->write_block_data = ds1307_write_block_data;
@@ -661,7 +713,7 @@ static int ds1307_probe(struct i2c_client *client,
tmp = ds1307->read_block_data(ds1307->client,
DS1337_REG_CONTROL, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -700,7 +752,7 @@ static int ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -744,7 +796,7 @@ static int ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -772,7 +824,7 @@ read_rtc:
/* read RTC registers */
tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
if (tmp != 8) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -814,7 +866,7 @@ read_rtc:
tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
if (tmp < 0) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -908,8 +960,8 @@ read_rtc:
ds1307->nvram->attr.name = "nvram";
ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
sysfs_bin_attr_init(ds1307->nvram);
- ds1307->nvram->read = ds1307_nvram_read,
- ds1307->nvram->write = ds1307_nvram_write,
+ ds1307->nvram->read = ds1307_nvram_read;
+ ds1307->nvram->write = ds1307_nvram_write;
ds1307->nvram->size = chip->nvram_size;
ds1307->nvram_offset = chip->nvram_offset;
err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram);
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index fef76868aae0..94366e12f40f 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -347,7 +347,7 @@ static int ds1374_probe(struct i2c_client *client,
struct ds1374 *ds1374;
int ret;
- ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL);
+ ds1374 = devm_kzalloc(&client->dev, sizeof(struct ds1374), GFP_KERNEL);
if (!ds1374)
return -ENOMEM;
@@ -359,36 +359,27 @@ static int ds1374_probe(struct i2c_client *client,
ret = ds1374_check_rtc_status(client);
if (ret)
- goto out_free;
+ return ret;
if (client->irq > 0) {
- ret = request_irq(client->irq, ds1374_irq, 0,
+ ret = devm_request_irq(&client->dev, client->irq, ds1374_irq, 0,
"ds1374", client);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
- goto out_free;
+ return ret;
}
device_set_wakeup_capable(&client->dev, 1);
}
- ds1374->rtc = rtc_device_register(client->name, &client->dev,
+ ds1374->rtc = devm_rtc_device_register(&client->dev, client->name,
&ds1374_rtc_ops, THIS_MODULE);
if (IS_ERR(ds1374->rtc)) {
- ret = PTR_ERR(ds1374->rtc);
dev_err(&client->dev, "unable to register the class device\n");
- goto out_irq;
+ return PTR_ERR(ds1374->rtc);
}
return 0;
-
-out_irq:
- if (client->irq > 0)
- free_irq(client->irq, client);
-
-out_free:
- kfree(ds1374);
- return ret;
}
static int ds1374_remove(struct i2c_client *client)
@@ -400,16 +391,14 @@ static int ds1374_remove(struct i2c_client *client)
ds1374->exiting = 1;
mutex_unlock(&ds1374->mutex);
- free_irq(client->irq, client);
+ devm_free_irq(&client->dev, client->irq, client);
cancel_work_sync(&ds1374->work);
}
- rtc_device_unregister(ds1374->rtc);
- kfree(ds1374);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ds1374_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -427,19 +416,15 @@ static int ds1374_resume(struct device *dev)
disable_irq_wake(client->irq);
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
-#define DS1374_PM (&ds1374_pm)
-#else
-#define DS1374_PM NULL
-#endif
-
static struct i2c_driver ds1374_driver = {
.driver = {
.name = "rtc-ds1374",
.owner = THIS_MODULE,
- .pm = DS1374_PM,
+ .pm = &ds1374_pm,
},
.probe = ds1374_probe,
.remove = ds1374_remove,
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index f994257981a0..289af419dff4 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -131,26 +131,24 @@ static int ds1390_probe(struct spi_device *spi)
spi->bits_per_word = 8;
spi_setup(spi);
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
if (!chip) {
dev_err(&spi->dev, "unable to allocate device memory\n");
return -ENOMEM;
}
- dev_set_drvdata(&spi->dev, chip);
+ spi_set_drvdata(spi, chip);
res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp);
if (res != 0) {
dev_err(&spi->dev, "unable to read device\n");
- kfree(chip);
return res;
}
- chip->rtc = rtc_device_register("ds1390",
- &spi->dev, &ds1390_rtc_ops, THIS_MODULE);
+ chip->rtc = devm_rtc_device_register(&spi->dev, "ds1390",
+ &ds1390_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
dev_err(&spi->dev, "unable to register device\n");
res = PTR_ERR(chip->rtc);
- kfree(chip);
}
return res;
@@ -158,11 +156,6 @@ static int ds1390_probe(struct spi_device *spi)
static int ds1390_remove(struct spi_device *spi)
{
- struct ds1390 *chip = spi_get_drvdata(spi);
-
- rtc_device_unregister(chip->rtc);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 6a3fcfe3b0e7..6ce8a997cf51 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -538,15 +538,14 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
}
}
- rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &ds1511_rtc_ops,
+ THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
pdata->rtc = rtc;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
- if (ret)
- rtc_device_unregister(pdata->rtc);
+
return ret;
}
@@ -555,7 +554,6 @@ static int ds1511_rtc_remove(struct platform_device *pdev)
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
- rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0) {
/*
* disable the alarm interrupt
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 25ce0621ade9..8c6c952e90b1 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -326,15 +326,14 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
}
}
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&ds1553_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
pdata->rtc = rtc;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
- if (ret)
- rtc_device_unregister(rtc);
+
return ret;
}
@@ -343,7 +342,6 @@ static int ds1553_rtc_remove(struct platform_device *pdev)
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
- rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0)
writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
return 0;
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 45d65c0b3a85..3fc2a4738027 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -155,11 +155,6 @@ static const struct rtc_class_ops ds1672_rtc_ops = {
static int ds1672_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
return 0;
}
@@ -177,7 +172,7 @@ static int ds1672_probe(struct i2c_client *client,
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, ds1672_driver.driver.name,
&ds1672_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -202,7 +197,6 @@ static int ds1672_probe(struct i2c_client *client,
return 0;
exit_devreg:
- rtc_device_unregister(rtc);
return err;
}
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 609c870e2cc5..eccdc62ae1c0 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -208,17 +208,14 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&ds1742_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
pdata->rtc = rtc;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
- if (ret) {
- dev_err(&pdev->dev, "creating nvram file in sysfs failed\n");
- rtc_device_unregister(rtc);
- }
+
return ret;
}
@@ -227,7 +224,6 @@ static int ds1742_rtc_remove(struct platform_device *pdev)
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
- rtc_device_unregister(pdata->rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index b04fc4272fb3..2ca5a23aba8a 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -228,7 +228,7 @@ static int rtc_probe(struct platform_device *pdev)
struct ds2404 *chip;
int retval = -EBUSY;
- chip = kzalloc(sizeof(struct ds2404), GFP_KERNEL);
+ chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -244,8 +244,8 @@ static int rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chip);
- chip->rtc = rtc_device_register("ds2404",
- &pdev->dev, &ds2404_rtc_ops, THIS_MODULE);
+ chip->rtc = devm_rtc_device_register(&pdev->dev, "ds2404",
+ &ds2404_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
retval = PTR_ERR(chip->rtc);
goto err_io;
@@ -257,20 +257,14 @@ static int rtc_probe(struct platform_device *pdev)
err_io:
chip->ops->unmap_io(chip);
err_chip:
- kfree(chip);
return retval;
}
static int rtc_remove(struct platform_device *dev)
{
struct ds2404 *chip = platform_get_drvdata(dev);
- struct rtc_device *rtc = chip->rtc;
-
- if (rtc)
- rtc_device_unregister(rtc);
chip->ops->unmap_io(chip);
- kfree(chip);
return 0;
}
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index db0ca08db315..b83bb5a527f8 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -397,7 +397,7 @@ static int ds3232_probe(struct i2c_client *client,
struct ds3232 *ds3232;
int ret;
- ds3232 = kzalloc(sizeof(struct ds3232), GFP_KERNEL);
+ ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL);
if (!ds3232)
return -ENOMEM;
@@ -409,34 +409,25 @@ static int ds3232_probe(struct i2c_client *client,
ret = ds3232_check_rtc_status(client);
if (ret)
- goto out_free;
+ return ret;
- ds3232->rtc = rtc_device_register(client->name, &client->dev,
+ ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
&ds3232_rtc_ops, THIS_MODULE);
if (IS_ERR(ds3232->rtc)) {
- ret = PTR_ERR(ds3232->rtc);
dev_err(&client->dev, "unable to register the class device\n");
- goto out_irq;
+ return PTR_ERR(ds3232->rtc);
}
if (client->irq >= 0) {
- ret = request_irq(client->irq, ds3232_irq, 0,
+ ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0,
"ds3232", client);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
- goto out_free;
+ return ret;
}
}
return 0;
-
-out_irq:
- if (client->irq >= 0)
- free_irq(client->irq, client);
-
-out_free:
- kfree(ds3232);
- return ret;
}
static int ds3232_remove(struct i2c_client *client)
@@ -448,12 +439,10 @@ static int ds3232_remove(struct i2c_client *client)
ds3232->exiting = 1;
mutex_unlock(&ds3232->mutex);
- free_irq(client->irq, client);
+ devm_free_irq(&client->dev, client->irq, client);
cancel_work_sync(&ds3232->work);
}
- rtc_device_unregister(ds3232->rtc);
- kfree(ds3232);
return 0;
}
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
index 7a4495ef1c39..ba98c0e9580d 100644
--- a/drivers/rtc/rtc-ds3234.c
+++ b/drivers/rtc/rtc-ds3234.c
@@ -146,21 +146,18 @@ static int ds3234_probe(struct spi_device *spi)
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
- rtc = rtc_device_register("ds3234",
- &spi->dev, &ds3234_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, "ds3234",
+ &ds3234_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
static int ds3234_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = spi_get_drvdata(spi);
-
- rtc_device_unregister(rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 1a0c37c9152b..b3c8c0b1709d 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -191,7 +191,7 @@ static int __init efi_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -203,10 +203,6 @@ static int __init efi_rtc_probe(struct platform_device *dev)
static int __exit efi_rtc_remove(struct platform_device *dev)
{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
- rtc_device_unregister(rtc);
-
return 0;
}
@@ -218,18 +214,7 @@ static struct platform_driver efi_rtc_driver = {
.remove = __exit_p(efi_rtc_remove),
};
-static int __init efi_rtc_init(void)
-{
- return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
-}
-
-static void __exit efi_rtc_exit(void)
-{
- platform_driver_unregister(&efi_rtc_driver);
-}
-
-module_init(efi_rtc_init);
-module_exit(efi_rtc_exit);
+module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
MODULE_AUTHOR("dann frazier <dannf@hp.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index f6c24ce35d36..3f9eb57d0486 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -121,7 +121,7 @@ static int em3027_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- rtc = rtc_device_register(em3027_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, em3027_driver.driver.name,
&em3027_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -133,11 +133,6 @@ static int em3027_probe(struct i2c_client *client,
static int em3027_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 1a4e5e4a70cd..5807b77c444a 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -153,8 +153,8 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
pdev->dev.platform_data = ep93xx_rtc;
platform_set_drvdata(pdev, ep93xx_rtc);
- ep93xx_rtc->rtc = rtc_device_register(pdev->name,
- &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+ ep93xx_rtc->rtc = devm_rtc_device_register(&pdev->dev,
+ pdev->name, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(ep93xx_rtc->rtc)) {
err = PTR_ERR(ep93xx_rtc->rtc);
goto exit;
@@ -162,12 +162,10 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
if (err)
- goto fail;
+ goto exit;
return 0;
-fail:
- rtc_device_unregister(ep93xx_rtc->rtc);
exit:
platform_set_drvdata(pdev, NULL);
pdev->dev.platform_data = NULL;
@@ -176,11 +174,8 @@ exit:
static int ep93xx_rtc_remove(struct platform_device *pdev)
{
- struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
-
sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(ep93xx_rtc->rtc);
pdev->dev.platform_data = NULL;
return 0;
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index bff3cdc5140e..2835fb6c1965 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -358,7 +358,7 @@ static int fm3130_probe(struct i2c_client *client,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
- fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
+ fm3130 = devm_kzalloc(&client->dev, sizeof(struct fm3130), GFP_KERNEL);
if (!fm3130)
return -ENOMEM;
@@ -395,7 +395,7 @@ static int fm3130_probe(struct i2c_client *client,
tmp = i2c_transfer(adapter, fm3130->msg, 4);
if (tmp != 4) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -507,7 +507,7 @@ bad_clock:
/* We won't bail out here because we just got invalid data.
Time setting from u-boot doesn't work anyway */
- fm3130->rtc = rtc_device_register(client->name, &client->dev,
+ fm3130->rtc = devm_rtc_device_register(&client->dev, client->name,
&fm3130_rtc_ops, THIS_MODULE);
if (IS_ERR(fm3130->rtc)) {
err = PTR_ERR(fm3130->rtc);
@@ -517,16 +517,11 @@ bad_clock:
}
return 0;
exit_free:
- kfree(fm3130);
return err;
}
static int fm3130_remove(struct i2c_client *client)
{
- struct fm3130 *fm3130 = i2c_get_clientdata(client);
-
- rtc_device_unregister(fm3130->rtc);
- kfree(fm3130);
return 0;
}
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c
index 98322004ad2e..06279ce6bff2 100644
--- a/drivers/rtc/rtc-generic.c
+++ b/drivers/rtc/rtc-generic.c
@@ -38,8 +38,8 @@ static int __init generic_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register("rtc-generic", &dev->dev, &generic_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
+ &generic_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -50,10 +50,6 @@ static int __init generic_rtc_probe(struct platform_device *dev)
static int __exit generic_rtc_remove(struct platform_device *dev)
{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
- rtc_device_unregister(rtc);
-
return 0;
}
@@ -65,18 +61,7 @@ static struct platform_driver generic_rtc_driver = {
.remove = __exit_p(generic_rtc_remove),
};
-static int __init generic_rtc_init(void)
-{
- return platform_driver_probe(&generic_rtc_driver, generic_rtc_probe);
-}
-
-static void __exit generic_rtc_fini(void)
-{
- platform_driver_unregister(&generic_rtc_driver);
-}
-
-module_init(generic_rtc_init);
-module_exit(generic_rtc_fini);
+module_platform_driver_probe(generic_rtc_driver, generic_rtc_probe);
MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c
index 31c5728ef629..63024505dddc 100644
--- a/drivers/rtc/rtc-hid-sensor-time.c
+++ b/drivers/rtc/rtc-hid-sensor-time.c
@@ -255,8 +255,9 @@ static int hid_time_probe(struct platform_device *pdev)
return ret;
}
- time_state->rtc = rtc_device_register("hid-sensor-time",
- &pdev->dev, &hid_time_rtc_ops, THIS_MODULE);
+ time_state->rtc = devm_rtc_device_register(&pdev->dev,
+ "hid-sensor-time", &hid_time_rtc_ops,
+ THIS_MODULE);
if (IS_ERR(time_state->rtc)) {
dev_err(&pdev->dev, "rtc device register failed!\n");
@@ -269,9 +270,7 @@ static int hid_time_probe(struct platform_device *pdev)
static int hid_time_remove(struct platform_device *pdev)
{
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
- struct hid_time_state *time_state = platform_get_drvdata(pdev);
- rtc_device_unregister(time_state->rtc);
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);
return 0;
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 82aad695979e..d3a8c8e255de 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -369,7 +369,7 @@ static void dryice_work(struct work_struct *work)
/*
* probe for dryice rtc device
*/
-static int dryice_rtc_probe(struct platform_device *pdev)
+static int __init dryice_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct imxdi_dev *imxdi;
@@ -464,7 +464,7 @@ static int dryice_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, imxdi);
- imxdi->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&dryice_rtc_ops, THIS_MODULE);
if (IS_ERR(imxdi->rtc)) {
rc = PTR_ERR(imxdi->rtc);
@@ -479,7 +479,7 @@ err:
return rc;
}
-static int dryice_rtc_remove(struct platform_device *pdev)
+static int __exit dryice_rtc_remove(struct platform_device *pdev)
{
struct imxdi_dev *imxdi = platform_get_drvdata(pdev);
@@ -488,8 +488,6 @@ static int dryice_rtc_remove(struct platform_device *pdev)
/* mask all interrupts */
__raw_writel(0, imxdi->ioaddr + DIER);
- rtc_device_unregister(imxdi->rtc);
-
clk_disable_unprepare(imxdi->clk);
return 0;
@@ -510,21 +508,10 @@ static struct platform_driver dryice_rtc_driver = {
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(dryice_dt_ids),
},
- .remove = dryice_rtc_remove,
+ .remove = __exit_p(dryice_rtc_remove),
};
-static int __init dryice_rtc_init(void)
-{
- return platform_driver_probe(&dryice_rtc_driver, dryice_rtc_probe);
-}
-
-static void __exit dryice_rtc_exit(void)
-{
- platform_driver_unregister(&dryice_rtc_driver);
-}
-
-module_init(dryice_rtc_init);
-module_exit(dryice_rtc_exit);
+module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 6b4298ea683d..a1bbbb8de029 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -252,12 +252,11 @@ static int isl12022_probe(struct i2c_client *client,
{
struct isl12022 *isl12022;
- int ret = 0;
-
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- isl12022 = kzalloc(sizeof(struct isl12022), GFP_KERNEL);
+ isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
+ GFP_KERNEL);
if (!isl12022)
return -ENOMEM;
@@ -265,37 +264,22 @@ static int isl12022_probe(struct i2c_client *client,
i2c_set_clientdata(client, isl12022);
- isl12022->rtc = rtc_device_register(isl12022_driver.driver.name,
- &client->dev,
- &isl12022_rtc_ops,
- THIS_MODULE);
-
- if (IS_ERR(isl12022->rtc)) {
- ret = PTR_ERR(isl12022->rtc);
- goto exit_kfree;
- }
+ isl12022->rtc = devm_rtc_device_register(&client->dev,
+ isl12022_driver.driver.name,
+ &isl12022_rtc_ops, THIS_MODULE);
+ if (IS_ERR(isl12022->rtc))
+ return PTR_ERR(isl12022->rtc);
return 0;
-
-exit_kfree:
- kfree(isl12022);
-
- return ret;
}
static int isl12022_remove(struct i2c_client *client)
{
- struct isl12022 *isl12022 = i2c_get_clientdata(client);
-
- rtc_device_unregister(isl12022->rtc);
- kfree(isl12022);
-
return 0;
}
static const struct i2c_device_id isl12022_id[] = {
{ "isl12022", 0 },
- { "rtc8564", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl12022_id);
diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c
index 9a4631218f41..9853ac15b296 100644
--- a/drivers/rtc/rtc-lp8788.c
+++ b/drivers/rtc/rtc-lp8788.c
@@ -299,7 +299,7 @@ static int lp8788_rtc_probe(struct platform_device *pdev)
device_init_wakeup(dev, 1);
- rtc->rdev = rtc_device_register("lp8788_rtc", dev,
+ rtc->rdev = devm_rtc_device_register(dev, "lp8788_rtc",
&lp8788_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rdev)) {
dev_err(dev, "can not register rtc device\n");
@@ -314,9 +314,6 @@ static int lp8788_rtc_probe(struct platform_device *pdev)
static int lp8788_rtc_remove(struct platform_device *pdev)
{
- struct lp8788_rtc *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc->rdev);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index 40a598332bac..787550d756e9 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -273,8 +273,8 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
- rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops,
- THIS_MODULE);
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, RTC_NAME,
+ &lpc32xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
dev_err(&pdev->dev, "Can't get RTC\n");
platform_set_drvdata(pdev, NULL);
@@ -307,7 +307,6 @@ static int lpc32xx_rtc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(rtc->rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c
index f59b6349551a..db82f91f4562 100644
--- a/drivers/rtc/rtc-ls1x.c
+++ b/drivers/rtc/rtc-ls1x.c
@@ -172,7 +172,7 @@ static int ls1x_rtc_probe(struct platform_device *pdev)
while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS)
usleep_range(1000, 3000);
- rtcdev = rtc_device_register("ls1x-rtc", &pdev->dev,
+ rtcdev = devm_rtc_device_register(&pdev->dev, "ls1x-rtc",
&ls1x_rtc_ops , THIS_MODULE);
if (IS_ERR(rtcdev)) {
ret = PTR_ERR(rtcdev);
@@ -187,9 +187,6 @@ err:
static int ls1x_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtcdev = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtcdev);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index b885bcd08908..89674b5e6efd 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -637,7 +637,8 @@ static int m41t80_probe(struct i2c_client *client,
dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
- clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
+ clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata),
+ GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
goto exit;
@@ -646,8 +647,8 @@ static int m41t80_probe(struct i2c_client *client,
clientdata->features = id->driver_data;
i2c_set_clientdata(client, clientdata);
- rtc = rtc_device_register(client->name, &client->dev,
- &m41t80_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev, client->name,
+ &m41t80_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
rc = PTR_ERR(rtc);
rtc = NULL;
@@ -718,26 +719,19 @@ ht_err:
goto exit;
exit:
- if (rtc)
- rtc_device_unregister(rtc);
- kfree(clientdata);
return rc;
}
static int m41t80_remove(struct i2c_client *client)
{
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
struct m41t80_data *clientdata = i2c_get_clientdata(client);
- struct rtc_device *rtc = clientdata->rtc;
-#ifdef CONFIG_RTC_DRV_M41T80_WDT
if (clientdata->features & M41T80_FEATURE_HT) {
misc_deregister(&wdt_dev);
unregister_reboot_notifier(&wdt_notifier);
}
#endif
- if (rtc)
- rtc_device_unregister(rtc);
- kfree(clientdata);
return 0;
}
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 49169680786e..9707d36e8b15 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -184,12 +184,12 @@ static int m41t93_probe(struct spi_device *spi)
return -ENODEV;
}
- rtc = rtc_device_register(m41t93_driver.driver.name,
- &spi->dev, &m41t93_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
+ &m41t93_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
@@ -197,11 +197,6 @@ static int m41t93_probe(struct spi_device *spi)
static int m41t93_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = spi_get_drvdata(spi);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-m41t94.c b/drivers/rtc/rtc-m41t94.c
index 89266c6764bc..7454ef0a4cfa 100644
--- a/drivers/rtc/rtc-m41t94.c
+++ b/drivers/rtc/rtc-m41t94.c
@@ -124,23 +124,18 @@ static int m41t94_probe(struct spi_device *spi)
return res;
}
- rtc = rtc_device_register(m41t94_driver.driver.name,
- &spi->dev, &m41t94_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, m41t94_driver.driver.name,
+ &m41t94_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
static int m41t94_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = spi_get_drvdata(spi);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 31c9190a1fcb..37444246e5e4 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -145,12 +145,11 @@ static int m48t35_probe(struct platform_device *pdev)
{
struct resource *res;
struct m48t35_priv *priv;
- int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof(struct m48t35_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct m48t35_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -160,50 +159,29 @@ static int m48t35_probe(struct platform_device *pdev)
* conflicts are resolved
*/
#ifndef CONFIG_SGI_IP27
- if (!request_mem_region(res->start, priv->size, pdev->name)) {
- ret = -EBUSY;
- goto out;
- }
+ if (!devm_request_mem_region(&pdev->dev, res->start, priv->size,
+ pdev->name))
+ return -EBUSY;
#endif
priv->baseaddr = res->start;
- priv->reg = ioremap(priv->baseaddr, priv->size);
- if (!priv->reg) {
- ret = -ENOMEM;
- goto out;
- }
+ priv->reg = devm_ioremap(&pdev->dev, priv->baseaddr, priv->size);
+ if (!priv->reg)
+ return -ENOMEM;
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
- priv->rtc = rtc_device_register("m48t35", &pdev->dev,
+ priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35",
&m48t35_ops, THIS_MODULE);
- if (IS_ERR(priv->rtc)) {
- ret = PTR_ERR(priv->rtc);
- goto out;
- }
+ if (IS_ERR(priv->rtc))
+ return PTR_ERR(priv->rtc);
return 0;
-
-out:
- if (priv->reg)
- iounmap(priv->reg);
- if (priv->baseaddr)
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return ret;
}
static int m48t35_remove(struct platform_device *pdev)
{
- struct m48t35_priv *priv = platform_get_drvdata(pdev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->reg);
-#ifndef CONFIG_SGI_IP27
- release_mem_region(priv->baseaddr, priv->size);
-#endif
- kfree(priv);
return 0;
}
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index 2ffbcacd2439..33a91c484533 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -148,8 +148,10 @@ static int m48t86_rtc_probe(struct platform_device *dev)
{
unsigned char reg;
struct m48t86_ops *ops = dev->dev.platform_data;
- struct rtc_device *rtc = rtc_device_register("m48t86",
- &dev->dev, &m48t86_rtc_ops, THIS_MODULE);
+ struct rtc_device *rtc;
+
+ rtc = devm_rtc_device_register(&dev->dev, "m48t86",
+ &m48t86_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -166,11 +168,6 @@ static int m48t86_rtc_probe(struct platform_device *dev)
static int m48t86_rtc_remove(struct platform_device *dev)
{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
platform_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index a00e33204b91..8669d6d09a00 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -214,11 +214,6 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int max6900_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
return 0;
}
@@ -237,8 +232,8 @@ max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(max6900_driver.driver.name,
- &client->dev, &max6900_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev, max6900_driver.driver.name,
+ &max6900_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 7d0bf698b79e..e3aea00c3145 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -93,24 +93,24 @@ static int max6902_set_time(struct device *dev, struct rtc_time *dt)
dt->tm_year = dt->tm_year + 1900;
/* Remove write protection */
- max6902_set_reg(dev, 0xF, 0);
+ max6902_set_reg(dev, MAX6902_REG_CONTROL, 0);
- max6902_set_reg(dev, 0x01, bin2bcd(dt->tm_sec));
- max6902_set_reg(dev, 0x03, bin2bcd(dt->tm_min));
- max6902_set_reg(dev, 0x05, bin2bcd(dt->tm_hour));
+ max6902_set_reg(dev, MAX6902_REG_SECONDS, bin2bcd(dt->tm_sec));
+ max6902_set_reg(dev, MAX6902_REG_MINUTES, bin2bcd(dt->tm_min));
+ max6902_set_reg(dev, MAX6902_REG_HOURS, bin2bcd(dt->tm_hour));
- max6902_set_reg(dev, 0x07, bin2bcd(dt->tm_mday));
- max6902_set_reg(dev, 0x09, bin2bcd(dt->tm_mon + 1));
- max6902_set_reg(dev, 0x0B, bin2bcd(dt->tm_wday));
- max6902_set_reg(dev, 0x0D, bin2bcd(dt->tm_year % 100));
- max6902_set_reg(dev, 0x13, bin2bcd(dt->tm_year / 100));
+ max6902_set_reg(dev, MAX6902_REG_DATE, bin2bcd(dt->tm_mday));
+ max6902_set_reg(dev, MAX6902_REG_MONTH, bin2bcd(dt->tm_mon + 1));
+ max6902_set_reg(dev, MAX6902_REG_DAY, bin2bcd(dt->tm_wday));
+ max6902_set_reg(dev, MAX6902_REG_YEAR, bin2bcd(dt->tm_year % 100));
+ max6902_set_reg(dev, MAX6902_REG_CENTURY, bin2bcd(dt->tm_year / 100));
/* Compulab used a delay here. However, the datasheet
* does not mention a delay being required anywhere... */
/* delay(2000); */
/* Write protect */
- max6902_set_reg(dev, 0xF, 0x80);
+ max6902_set_reg(dev, MAX6902_REG_CONTROL, 0x80);
return 0;
}
@@ -134,20 +134,17 @@ static int max6902_probe(struct spi_device *spi)
if (res != 0)
return res;
- rtc = rtc_device_register("max6902",
- &spi->dev, &max6902_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, "max6902",
+ &max6902_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
static int max6902_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
-
- rtc_device_unregister(rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 6b1337f9baf4..771812d62e6b 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -24,7 +24,7 @@
/* RTC Control Register */
#define BCD_EN_SHIFT 0
-#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
+#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
#define MODEL24_SHIFT 1
#define MODEL24_MASK (1 << MODEL24_SHIFT)
/* RTC Update Register1 */
@@ -33,12 +33,12 @@
#define RTC_RBUDR_SHIFT 4
#define RTC_RBUDR_MASK (1 << RTC_RBUDR_SHIFT)
/* WTSR and SMPL Register */
-#define WTSRT_SHIFT 0
-#define SMPLT_SHIFT 2
+#define WTSRT_SHIFT 0
+#define SMPLT_SHIFT 2
#define WTSR_EN_SHIFT 6
#define SMPL_EN_SHIFT 7
-#define WTSRT_MASK (3 << WTSRT_SHIFT)
-#define SMPLT_MASK (3 << SMPLT_SHIFT)
+#define WTSRT_MASK (3 << WTSRT_SHIFT)
+#define SMPLT_MASK (3 << SMPLT_SHIFT)
#define WTSR_EN_MASK (1 << WTSR_EN_SHIFT)
#define SMPL_EN_MASK (1 << SMPL_EN_SHIFT)
/* RTC Hour register */
@@ -466,7 +466,7 @@ static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable
val = 0;
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
- pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
+ dev_info(info->dev, "%s: WTSR_SMPL(0x%02x)\n", __func__, val);
}
#endif /* MAX77686_RTC_WTSR_SMPL */
@@ -505,7 +505,8 @@ static int max77686_rtc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s\n", __func__);
- info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct max77686_rtc_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -513,13 +514,12 @@ static int max77686_rtc_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
info->max77686 = max77686;
info->rtc = max77686->rtc;
- info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc,
+ info->max77686->rtc_regmap = devm_regmap_init_i2c(info->max77686->rtc,
&max77686_rtc_regmap_config);
if (IS_ERR(info->max77686->rtc_regmap)) {
ret = PTR_ERR(info->max77686->rtc_regmap);
dev_err(info->max77686->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(info);
return ret;
}
platform_set_drvdata(pdev, info);
@@ -538,8 +538,8 @@ static int max77686_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev,
- &max77686_rtc_ops, THIS_MODULE);
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max77686-rtc",
+ &max77686_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
dev_info(&pdev->dev, "%s: fail\n", __func__);
@@ -551,36 +551,24 @@ static int max77686_rtc_probe(struct platform_device *pdev)
goto err_rtc;
}
virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1);
- if (!virq)
+ if (!virq) {
+ ret = -ENXIO;
goto err_rtc;
+ }
info->virq = virq;
- ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0,
- "rtc-alarm0", info);
- if (ret < 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+ max77686_rtc_alarm_irq, 0, "rtc-alarm0", info);
+ if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->virq, ret);
- goto err_rtc;
- }
- goto out;
err_rtc:
- kfree(info);
- return ret;
-out:
return ret;
}
static int max77686_rtc_remove(struct platform_device *pdev)
{
- struct max77686_rtc_info *info = platform_get_drvdata(pdev);
-
- if (info) {
- free_irq(info->virq, info);
- rtc_device_unregister(info->rtc_dev);
- kfree(info);
- }
-
return 0;
}
@@ -594,11 +582,14 @@ static void max77686_rtc_shutdown(struct platform_device *pdev)
for (i = 0; i < 3; i++) {
max77686_rtc_enable_wtsr(info, false);
regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
- pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);
- if (val & WTSR_EN_MASK)
- pr_emerg("%s: fail to disable WTSR\n", __func__);
- else {
- pr_info("%s: success to disable WTSR\n", __func__);
+ dev_info(info->dev, "%s: WTSR_SMPL reg(0x%02x)\n", __func__,
+ val);
+ if (val & WTSR_EN_MASK) {
+ dev_emerg(info->dev, "%s: fail to disable WTSR\n",
+ __func__);
+ } else {
+ dev_info(info->dev, "%s: success to disable WTSR\n",
+ __func__);
break;
}
}
@@ -624,18 +615,8 @@ static struct platform_driver max77686_rtc_driver = {
.id_table = rtc_id,
};
-static int __init max77686_rtc_init(void)
-{
- return platform_driver_register(&max77686_rtc_driver);
-}
-module_init(max77686_rtc_init);
-
-static void __exit max77686_rtc_exit(void)
-{
- platform_driver_unregister(&max77686_rtc_driver);
-}
-module_exit(max77686_rtc_exit);
+module_platform_driver(max77686_rtc_driver);
MODULE_DESCRIPTION("Maxim MAX77686 RTC driver");
-MODULE_AUTHOR("<woong.byun@samsung.com>");
+MODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c
index 31ca8faf9f05..86afb797125d 100644
--- a/drivers/rtc/rtc-max8907.c
+++ b/drivers/rtc/rtc-max8907.c
@@ -190,7 +190,7 @@ static int max8907_rtc_probe(struct platform_device *pdev)
rtc->max8907 = max8907;
rtc->regmap = max8907->regmap_rtc;
- rtc->rtc_dev = rtc_device_register("max8907-rtc", &pdev->dev,
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8907-rtc",
&max8907_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc_dev)) {
ret = PTR_ERR(rtc->rtc_dev);
@@ -200,33 +200,21 @@ static int max8907_rtc_probe(struct platform_device *pdev)
rtc->irq = regmap_irq_get_virq(max8907->irqc_rtc,
MAX8907_IRQ_RTC_ALARM0);
- if (rtc->irq < 0) {
- ret = rtc->irq;
- goto err_unregister;
- }
+ if (rtc->irq < 0)
+ return rtc->irq;
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
max8907_irq_handler,
IRQF_ONESHOT, "max8907-alarm0", rtc);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
rtc->irq, ret);
- goto err_unregister;
- }
- return 0;
-
-err_unregister:
- rtc_device_unregister(rtc->rtc_dev);
return ret;
}
static int max8907_rtc_remove(struct platform_device *pdev)
{
- struct max8907_rtc *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc->rtc_dev);
-
return 0;
}
diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c
index a0c8265646d2..7c90f4e45e27 100644
--- a/drivers/rtc/rtc-max8925.c
+++ b/drivers/rtc/rtc-max8925.c
@@ -253,7 +253,8 @@ static int max8925_rtc_probe(struct platform_device *pdev)
struct max8925_rtc_info *info;
int ret;
- info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct max8925_rtc_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
info->chip = chip;
@@ -261,12 +262,13 @@ static int max8925_rtc_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
info->irq = platform_get_irq(pdev, 0);
- ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
- IRQF_ONESHOT, "rtc-alarm0", info);
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+ rtc_update_handler, IRQF_ONESHOT,
+ "rtc-alarm0", info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq, ret);
- goto out_irq;
+ goto err;
}
dev_set_drvdata(&pdev->dev, info);
@@ -275,32 +277,22 @@ static int max8925_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8925-rtc",
&max8925_rtc_ops, THIS_MODULE);
ret = PTR_ERR(info->rtc_dev);
if (IS_ERR(info->rtc_dev)) {
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- goto out_rtc;
+ goto err;
}
return 0;
-out_rtc:
+err:
platform_set_drvdata(pdev, NULL);
- free_irq(info->irq, info);
-out_irq:
- kfree(info);
return ret;
}
static int max8925_rtc_remove(struct platform_device *pdev)
{
- struct max8925_rtc_info *info = platform_get_drvdata(pdev);
-
- if (info) {
- free_irq(info->irq, info);
- rtc_device_unregister(info->rtc_dev);
- kfree(info);
- }
return 0;
}
diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c
index 00e505b6bee3..dacf48db7925 100644
--- a/drivers/rtc/rtc-max8997.c
+++ b/drivers/rtc/rtc-max8997.c
@@ -24,7 +24,7 @@
/* Module parameter for WTSR function control */
static int wtsr_en = 1;
module_param(wtsr_en, int, 0444);
-MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)");
+MODULE_PARM_DESC(wtsr_en, "Watchdog Timeout & Software Reset (default=on)");
/* Module parameter for SMPL function control */
static int smpl_en = 1;
module_param(smpl_en, int, 0444);
@@ -479,8 +479,8 @@ static int max8997_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev,
- &max8997_rtc_ops, THIS_MODULE);
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8997-rtc",
+ &max8997_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
ret = PTR_ERR(info->rtc_dev);
@@ -491,6 +491,7 @@ static int max8997_rtc_probe(struct platform_device *pdev)
virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1);
if (!virq) {
dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n");
+ ret = -ENXIO;
goto err_out;
}
info->virq = virq;
@@ -498,26 +499,16 @@ static int max8997_rtc_probe(struct platform_device *pdev)
ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
max8997_rtc_alarm_irq, 0,
"rtc-alarm0", info);
- if (ret < 0) {
+ if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
info->virq, ret);
- goto err_out;
- }
-
- return ret;
err_out:
- rtc_device_unregister(info->rtc_dev);
return ret;
}
static int max8997_rtc_remove(struct platform_device *pdev)
{
- struct max8997_rtc_info *info = platform_get_drvdata(pdev);
-
- if (info)
- rtc_device_unregister(info->rtc_dev);
-
return 0;
}
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index 8f234a075e8f..48b6612fae7f 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -256,7 +256,8 @@ static int max8998_rtc_probe(struct platform_device *pdev)
struct max8998_rtc_info *info;
int ret;
- info = kzalloc(sizeof(struct max8998_rtc_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct max8998_rtc_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -267,7 +268,7 @@ static int max8998_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
- info->rtc_dev = rtc_device_register("max8998-rtc", &pdev->dev,
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "max8998-rtc",
&max8998_rtc_ops, THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
@@ -276,8 +277,8 @@ static int max8998_rtc_probe(struct platform_device *pdev)
goto out_rtc;
}
- ret = request_threaded_irq(info->irq, NULL, max8998_rtc_alarm_irq, 0,
- "rtc-alarm0", info);
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+ max8998_rtc_alarm_irq, 0, "rtc-alarm0", info);
if (ret < 0)
dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
@@ -294,20 +295,11 @@ static int max8998_rtc_probe(struct platform_device *pdev)
out_rtc:
platform_set_drvdata(pdev, NULL);
- kfree(info);
return ret;
}
static int max8998_rtc_remove(struct platform_device *pdev)
{
- struct max8998_rtc_info *info = platform_get_drvdata(pdev);
-
- if (info) {
- free_irq(info->irq, info);
- rtc_device_unregister(info->rtc_dev);
- kfree(info);
- }
-
return 0;
}
diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c
index 2643d8874925..7a8ed27a5f2e 100644
--- a/drivers/rtc/rtc-mc13xxx.c
+++ b/drivers/rtc/rtc-mc13xxx.c
@@ -316,7 +316,7 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
struct mc13xxx *mc13xxx;
int rtcrst_pending;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -351,8 +351,8 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
mc13xxx_unlock(mc13xxx);
- priv->rtc = rtc_device_register(pdev->name,
- &pdev->dev, &mc13xxx_rtc_ops, THIS_MODULE);
+ priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &mc13xxx_rtc_ops, THIS_MODULE);
if (IS_ERR(priv->rtc)) {
ret = PTR_ERR(priv->rtc);
@@ -372,7 +372,6 @@ err_reset_irq_request:
mc13xxx_unlock(mc13xxx);
platform_set_drvdata(pdev, NULL);
- kfree(priv);
}
return ret;
@@ -384,8 +383,6 @@ static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
mc13xxx_lock(priv->mc13xxx);
- rtc_device_unregister(priv->rtc);
-
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv);
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv);
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
@@ -394,8 +391,6 @@ static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
- kfree(priv);
-
return 0;
}
@@ -420,17 +415,7 @@ static struct platform_driver mc13xxx_rtc_driver = {
},
};
-static int __init mc13xxx_rtc_init(void)
-{
- return platform_driver_probe(&mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
-}
-module_init(mc13xxx_rtc_init);
-
-static void __exit mc13xxx_rtc_exit(void)
-{
- platform_driver_unregister(&mc13xxx_rtc_driver);
-}
-module_exit(mc13xxx_rtc_exit);
+module_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");
diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c
index fcb113c11122..771f86a05d14 100644
--- a/drivers/rtc/rtc-msm6242.c
+++ b/drivers/rtc/rtc-msm6242.c
@@ -194,30 +194,28 @@ static const struct rtc_class_ops msm6242_rtc_ops = {
.set_time = msm6242_set_time,
};
-static int __init msm6242_rtc_probe(struct platform_device *dev)
+static int __init msm6242_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct msm6242_priv *priv;
struct rtc_device *rtc;
int error;
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->regs = ioremap(res->start, resource_size(res));
- if (!priv->regs) {
- error = -ENOMEM;
- goto out_free_priv;
- }
- platform_set_drvdata(dev, priv);
+ priv->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!priv->regs)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
- rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, "rtc-msm6242",
+ &msm6242_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
error = PTR_ERR(rtc);
goto out_unmap;
@@ -227,20 +225,12 @@ static int __init msm6242_rtc_probe(struct platform_device *dev)
return 0;
out_unmap:
- platform_set_drvdata(dev, NULL);
- iounmap(priv->regs);
-out_free_priv:
- kfree(priv);
+ platform_set_drvdata(pdev, NULL);
return error;
}
-static int __exit msm6242_rtc_remove(struct platform_device *dev)
+static int __exit msm6242_rtc_remove(struct platform_device *pdev)
{
- struct msm6242_priv *priv = platform_get_drvdata(dev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->regs);
- kfree(priv);
return 0;
}
@@ -252,18 +242,7 @@ static struct platform_driver msm6242_rtc_driver = {
.remove = __exit_p(msm6242_rtc_remove),
};
-static int __init msm6242_rtc_init(void)
-{
- return platform_driver_probe(&msm6242_rtc_driver, msm6242_rtc_probe);
-}
-
-static void __exit msm6242_rtc_fini(void)
-{
- platform_driver_unregister(&msm6242_rtc_driver);
-}
-
-module_init(msm6242_rtc_init);
-module_exit(msm6242_rtc_fini);
+module_platform_driver_probe(msm6242_rtc_driver, msm6242_rtc_probe);
MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index 8f87fec27ce7..baab802f2153 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -217,7 +217,7 @@ static const struct rtc_class_ops mv_rtc_alarm_ops = {
.alarm_irq_enable = mv_rtc_alarm_irq_enable,
};
-static int mv_rtc_probe(struct platform_device *pdev)
+static int __init mv_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct rtc_plat_data *pdata;
@@ -272,12 +272,13 @@ static int mv_rtc_probe(struct platform_device *pdev)
if (pdata->irq >= 0) {
device_init_wakeup(&pdev->dev, 1);
- pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&mv_rtc_alarm_ops,
THIS_MODULE);
- } else
- pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ } else {
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&mv_rtc_ops, THIS_MODULE);
+ }
if (IS_ERR(pdata->rtc)) {
ret = PTR_ERR(pdata->rtc);
goto out;
@@ -308,7 +309,6 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
if (pdata->irq >= 0)
device_init_wakeup(&pdev->dev, 0);
- rtc_device_unregister(pdata->rtc);
if (!IS_ERR(pdata->clk))
clk_disable_unprepare(pdata->clk);
@@ -331,18 +331,7 @@ static struct platform_driver mv_rtc_driver = {
},
};
-static __init int mv_init(void)
-{
- return platform_driver_probe(&mv_rtc_driver, mv_rtc_probe);
-}
-
-static __exit void mv_exit(void)
-{
- platform_driver_unregister(&mv_rtc_driver);
-}
-
-module_init(mv_init);
-module_exit(mv_exit);
+module_platform_driver_probe(mv_rtc_driver, mv_rtc_probe);
MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>");
MODULE_DESCRIPTION("Marvell RTC driver");
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index 1c3ef7289565..9a3895bc4f4d 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -439,7 +439,7 @@ static int mxc_rtc_probe(struct platform_device *pdev)
if (pdata->irq >=0)
device_init_wakeup(&pdev->dev, 1);
- rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
@@ -464,15 +464,13 @@ static int mxc_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
- rtc_device_unregister(pdata->rtc);
-
clk_disable_unprepare(pdata->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mxc_rtc_suspend(struct device *dev)
{
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
@@ -492,19 +490,14 @@ static int mxc_rtc_resume(struct device *dev)
return 0;
}
-
-static struct dev_pm_ops mxc_rtc_pm_ops = {
- .suspend = mxc_rtc_suspend,
- .resume = mxc_rtc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(mxc_rtc_pm_ops, mxc_rtc_suspend, mxc_rtc_resume);
+
static struct platform_driver mxc_rtc_driver = {
.driver = {
.name = "mxc_rtc",
-#ifdef CONFIG_PM
.pm = &mxc_rtc_pm_ops,
-#endif
.owner = THIS_MODULE,
},
.id_table = imx_rtc_devtype,
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index a63680850fef..f5dfb6e5e7d9 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -222,13 +222,13 @@ static struct rtc_class_ops nuc900_rtc_ops = {
.alarm_irq_enable = nuc900_alarm_irq_enable,
};
-static int nuc900_rtc_probe(struct platform_device *pdev)
+static int __init nuc900_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct nuc900_rtc *nuc900_rtc;
- int err = 0;
- nuc900_rtc = kzalloc(sizeof(struct nuc900_rtc), GFP_KERNEL);
+ nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc),
+ GFP_KERNEL);
if (!nuc900_rtc) {
dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n");
return -ENOMEM;
@@ -236,93 +236,51 @@ static int nuc900_rtc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "platform_get_resource failed\n");
- err = -ENXIO;
- goto fail1;
+ return -ENXIO;
}
- if (!request_mem_region(res->start, resource_size(res),
- pdev->name)) {
- dev_err(&pdev->dev, "request_mem_region failed\n");
- err = -EBUSY;
- goto fail1;
- }
-
- nuc900_rtc->rtc_reg = ioremap(res->start, resource_size(res));
- if (!nuc900_rtc->rtc_reg) {
- dev_err(&pdev->dev, "ioremap rtc_reg failed\n");
- err = -ENOMEM;
- goto fail2;
- }
+ nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(nuc900_rtc->rtc_reg))
+ return PTR_ERR(nuc900_rtc->rtc_reg);
platform_set_drvdata(pdev, nuc900_rtc);
- nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
+ nuc900_rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
&nuc900_rtc_ops, THIS_MODULE);
if (IS_ERR(nuc900_rtc->rtcdev)) {
dev_err(&pdev->dev, "rtc device register failed\n");
- err = PTR_ERR(nuc900_rtc->rtcdev);
- goto fail3;
+ return PTR_ERR(nuc900_rtc->rtcdev);
}
__raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24,
nuc900_rtc->rtc_reg + REG_RTC_TSSR);
nuc900_rtc->irq_num = platform_get_irq(pdev, 0);
- if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt,
- 0, "nuc900rtc", nuc900_rtc)) {
+ if (devm_request_irq(&pdev->dev, nuc900_rtc->irq_num,
+ nuc900_rtc_interrupt, 0, "nuc900rtc", nuc900_rtc)) {
dev_err(&pdev->dev, "NUC900 RTC request irq failed\n");
- err = -EBUSY;
- goto fail4;
+ return -EBUSY;
}
return 0;
-
-fail4: rtc_device_unregister(nuc900_rtc->rtcdev);
-fail3: iounmap(nuc900_rtc->rtc_reg);
-fail2: release_mem_region(res->start, resource_size(res));
-fail1: kfree(nuc900_rtc);
- return err;
}
-static int nuc900_rtc_remove(struct platform_device *pdev)
+static int __exit nuc900_rtc_remove(struct platform_device *pdev)
{
- struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev);
- struct resource *res;
-
- free_irq(nuc900_rtc->irq_num, nuc900_rtc);
- rtc_device_unregister(nuc900_rtc->rtcdev);
- iounmap(nuc900_rtc->rtc_reg);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(nuc900_rtc);
-
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver nuc900_rtc_driver = {
- .remove = nuc900_rtc_remove,
+ .remove = __exit_p(nuc900_rtc_remove),
.driver = {
.name = "nuc900-rtc",
.owner = THIS_MODULE,
},
};
-static int __init nuc900_rtc_init(void)
-{
- return platform_driver_probe(&nuc900_rtc_driver, nuc900_rtc_probe);
-}
-
-static void __exit nuc900_rtc_exit(void)
-{
- platform_driver_unregister(&nuc900_rtc_driver);
-}
-
-module_init(nuc900_rtc_init);
-module_exit(nuc900_rtc_exit);
+module_platform_driver_probe(nuc900_rtc_driver, nuc900_rtc_probe);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("nuc910/nuc920 RTC driver");
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 600971407aac..4e1bdb832e37 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -324,7 +324,7 @@ MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
static int __init omap_rtc_probe(struct platform_device *pdev)
{
- struct resource *res, *mem;
+ struct resource *res;
struct rtc_device *rtc;
u8 reg, new_ctrl;
const struct platform_device_id *id_entry;
@@ -352,18 +352,9 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
return -ENOENT;
}
- mem = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!mem) {
- pr_debug("%s: RTC registers at %08x are not free\n",
- pdev->name, res->start);
- return -EBUSY;
- }
-
- rtc_base = ioremap(res->start, resource_size(res));
- if (!rtc_base) {
- pr_debug("%s: RTC registers can't be mapped\n", pdev->name);
- goto fail;
- }
+ rtc_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc_base))
+ return PTR_ERR(rtc_base);
/* Enable the clock/module so that we can access the registers */
pm_runtime_enable(&pdev->dev);
@@ -375,7 +366,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);
}
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&omap_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
pr_debug("%s: can't register RTC device, err %ld\n",
@@ -383,7 +374,6 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
goto fail0;
}
platform_set_drvdata(pdev, rtc);
- dev_set_drvdata(&rtc->dev, mem);
/* clear pending irqs, and set 1/second periodic,
* which we'll use instead of update irqs
@@ -401,18 +391,18 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
/* handle periodic and alarm irqs */
- if (request_irq(omap_rtc_timer, rtc_irq, 0,
+ if (devm_request_irq(&pdev->dev, omap_rtc_timer, rtc_irq, 0,
dev_name(&rtc->dev), rtc)) {
pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_timer);
- goto fail1;
+ goto fail0;
}
if ((omap_rtc_timer != omap_rtc_alarm) &&
- (request_irq(omap_rtc_alarm, rtc_irq, 0,
+ (devm_request_irq(&pdev->dev, omap_rtc_alarm, rtc_irq, 0,
dev_name(&rtc->dev), rtc))) {
pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_alarm);
- goto fail2;
+ goto fail0;
}
/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
@@ -446,25 +436,16 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
return 0;
-fail2:
- free_irq(omap_rtc_timer, rtc);
-fail1:
- rtc_device_unregister(rtc);
fail0:
if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
rtc_writel(0, OMAP_RTC_KICK0_REG);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- iounmap(rtc_base);
-fail:
- release_mem_region(mem->start, resource_size(mem));
return -EIO;
}
static int __exit omap_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
- struct resource *mem = dev_get_drvdata(&rtc->dev);
const struct platform_device_id *id_entry =
platform_get_device_id(pdev);
@@ -473,12 +454,6 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
/* leave rtc running, but disable irqs */
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
- free_irq(omap_rtc_timer, rtc);
-
- if (omap_rtc_timer != omap_rtc_alarm)
- free_irq(omap_rtc_alarm, rtc);
-
- rtc_device_unregister(rtc);
if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER))
rtc_writel(0, OMAP_RTC_KICK0_REG);
@@ -486,16 +461,13 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- iounmap(rtc_base);
- release_mem_region(mem->start, resource_size(mem));
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static u8 irqstat;
-static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int omap_rtc_suspend(struct device *dev)
{
irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
@@ -503,34 +475,32 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
* source, and in fact this enable() call is just saving a flag
* that's never used...
*/
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
enable_irq_wake(omap_rtc_alarm);
else
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
/* Disable the clock/module */
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_sync(dev);
return 0;
}
-static int omap_rtc_resume(struct platform_device *pdev)
+static int omap_rtc_resume(struct device *dev)
{
/* Enable the clock/module so that we can access the registers */
- pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_get_sync(dev);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(dev))
disable_irq_wake(omap_rtc_alarm);
else
rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
return 0;
}
-
-#else
-#define omap_rtc_suspend NULL
-#define omap_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume);
+
static void omap_rtc_shutdown(struct platform_device *pdev)
{
rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
@@ -539,28 +509,17 @@ static void omap_rtc_shutdown(struct platform_device *pdev)
MODULE_ALIAS("platform:omap_rtc");
static struct platform_driver omap_rtc_driver = {
.remove = __exit_p(omap_rtc_remove),
- .suspend = omap_rtc_suspend,
- .resume = omap_rtc_resume,
.shutdown = omap_rtc_shutdown,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .pm = &omap_rtc_pm_ops,
.of_match_table = of_match_ptr(omap_rtc_of_match),
},
.id_table = omap_rtc_devtype,
};
-static int __init rtc_init(void)
-{
- return platform_driver_probe(&omap_rtc_driver, omap_rtc_probe);
-}
-module_init(rtc_init);
-
-static void __exit rtc_exit(void)
-{
- platform_driver_unregister(&omap_rtc_driver);
-}
-module_exit(rtc_exit);
+module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe);
MODULE_AUTHOR("George G. Davis (and others)");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c
index 59c42986254e..50204d474eb7 100644
--- a/drivers/rtc/rtc-palmas.c
+++ b/drivers/rtc/rtc-palmas.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/mfd/palmas.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/types.h>
#include <linux/platform_device.h>
@@ -264,7 +265,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
palmas_rtc->irq = platform_get_irq(pdev, 0);
- palmas_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ palmas_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&palmas_rtc_ops, THIS_MODULE);
if (IS_ERR(palmas_rtc->rtc)) {
ret = PTR_ERR(palmas_rtc->rtc);
@@ -272,14 +273,13 @@ static int palmas_rtc_probe(struct platform_device *pdev)
return ret;
}
- ret = request_threaded_irq(palmas_rtc->irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, palmas_rtc->irq, NULL,
palmas_rtc_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT |
IRQF_EARLY_RESUME,
dev_name(&pdev->dev), palmas_rtc);
if (ret < 0) {
dev_err(&pdev->dev, "IRQ request failed, err = %d\n", ret);
- rtc_device_unregister(palmas_rtc->rtc);
return ret;
}
@@ -289,11 +289,7 @@ static int palmas_rtc_probe(struct platform_device *pdev)
static int palmas_rtc_remove(struct platform_device *pdev)
{
- struct palmas_rtc *palmas_rtc = platform_get_drvdata(pdev);
-
palmas_rtc_alarm_irq_enable(&pdev->dev, 0);
- free_irq(palmas_rtc->irq, palmas_rtc);
- rtc_device_unregister(palmas_rtc->rtc);
return 0;
}
@@ -321,6 +317,14 @@ static const struct dev_pm_ops palmas_rtc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume)
};
+#ifdef CONFIG_OF
+static struct of_device_id of_palmas_rtc_match[] = {
+ { .compatible = "ti,palmas-rtc"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_palmas_rtc_match);
+#endif
+
static struct platform_driver palmas_rtc_driver = {
.probe = palmas_rtc_probe,
.remove = palmas_rtc_remove,
@@ -328,6 +332,7 @@ static struct platform_driver palmas_rtc_driver = {
.owner = THIS_MODULE,
.name = "palmas-rtc",
.pm = &palmas_rtc_pm_ops,
+ .of_match_table = of_match_ptr(of_palmas_rtc_match),
},
};
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
index e0019cd0bf71..539a90b98bc5 100644
--- a/drivers/rtc/rtc-pcap.c
+++ b/drivers/rtc/rtc-pcap.c
@@ -139,13 +139,14 @@ static const struct rtc_class_ops pcap_rtc_ops = {
.alarm_irq_enable = pcap_rtc_alarm_irq_enable,
};
-static int pcap_rtc_probe(struct platform_device *pdev)
+static int __init pcap_rtc_probe(struct platform_device *pdev)
{
struct pcap_rtc *pcap_rtc;
int timer_irq, alarm_irq;
int err = -ENOMEM;
- pcap_rtc = kmalloc(sizeof(struct pcap_rtc), GFP_KERNEL);
+ pcap_rtc = devm_kzalloc(&pdev->dev, sizeof(struct pcap_rtc),
+ GFP_KERNEL);
if (!pcap_rtc)
return err;
@@ -153,68 +154,46 @@ static int pcap_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcap_rtc);
- pcap_rtc->rtc = rtc_device_register("pcap", &pdev->dev,
- &pcap_rtc_ops, THIS_MODULE);
+ pcap_rtc->rtc = devm_rtc_device_register(&pdev->dev, "pcap",
+ &pcap_rtc_ops, THIS_MODULE);
if (IS_ERR(pcap_rtc->rtc)) {
err = PTR_ERR(pcap_rtc->rtc);
- goto fail_rtc;
+ goto fail;
}
-
timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ);
alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA);
- err = request_irq(timer_irq, pcap_rtc_irq, 0, "RTC Timer", pcap_rtc);
+ err = devm_request_irq(&pdev->dev, timer_irq, pcap_rtc_irq, 0,
+ "RTC Timer", pcap_rtc);
if (err)
- goto fail_timer;
+ goto fail;
- err = request_irq(alarm_irq, pcap_rtc_irq, 0, "RTC Alarm", pcap_rtc);
+ err = devm_request_irq(&pdev->dev, alarm_irq, pcap_rtc_irq, 0,
+ "RTC Alarm", pcap_rtc);
if (err)
- goto fail_alarm;
+ goto fail;
return 0;
-fail_alarm:
- free_irq(timer_irq, pcap_rtc);
-fail_timer:
- rtc_device_unregister(pcap_rtc->rtc);
-fail_rtc:
+fail:
platform_set_drvdata(pdev, NULL);
- kfree(pcap_rtc);
return err;
}
-static int pcap_rtc_remove(struct platform_device *pdev)
+static int __exit pcap_rtc_remove(struct platform_device *pdev)
{
- struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
-
- free_irq(pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ), pcap_rtc);
- free_irq(pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA), pcap_rtc);
- rtc_device_unregister(pcap_rtc->rtc);
- kfree(pcap_rtc);
-
return 0;
}
static struct platform_driver pcap_rtc_driver = {
- .remove = pcap_rtc_remove,
+ .remove = __exit_p(pcap_rtc_remove),
.driver = {
.name = "pcap-rtc",
.owner = THIS_MODULE,
},
};
-static int __init rtc_pcap_init(void)
-{
- return platform_driver_probe(&pcap_rtc_driver, pcap_rtc_probe);
-}
-
-static void __exit rtc_pcap_exit(void)
-{
- platform_driver_unregister(&pcap_rtc_driver);
-}
-
-module_init(rtc_pcap_init);
-module_exit(rtc_pcap_exit);
+module_platform_driver_probe(pcap_rtc_driver, pcap_rtc_probe);
MODULE_DESCRIPTION("Motorola pcap rtc driver");
MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>");
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 02b742afa761..796a6c5067dd 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -226,7 +226,8 @@ static int pcf2123_probe(struct spi_device *spi)
u8 txbuf[2], rxbuf[2];
int ret, i;
- pdata = kzalloc(sizeof(struct pcf2123_plat_data), GFP_KERNEL);
+ pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
+ GFP_KERNEL);
if (!pdata)
return -ENOMEM;
spi->dev.platform_data = pdata;
@@ -265,6 +266,7 @@ static int pcf2123_probe(struct spi_device *spi)
if (!(rxbuf[0] & 0x20)) {
dev_err(&spi->dev, "chip not found\n");
+ ret = -ENODEV;
goto kfree_exit;
}
@@ -281,7 +283,7 @@ static int pcf2123_probe(struct spi_device *spi)
pcf2123_delay_trec();
/* Finalize the initialization */
- rtc = rtc_device_register(pcf2123_driver.driver.name, &spi->dev,
+ rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
&pcf2123_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -314,7 +316,6 @@ sysfs_exit:
device_remove_file(&spi->dev, &pdata->regs[i].attr);
kfree_exit:
- kfree(pdata);
spi->dev.platform_data = NULL;
return ret;
}
@@ -325,15 +326,10 @@ static int pcf2123_remove(struct spi_device *spi)
int i;
if (pdata) {
- struct rtc_device *rtc = pdata->rtc;
-
- if (rtc)
- rtc_device_unregister(rtc);
for (i = 0; i < 16; i++)
if (pdata->regs[i].name[0])
device_remove_file(&spi->dev,
&pdata->regs[i].attr);
- kfree(pdata);
}
return 0;
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
index e9f3135d305f..e6b6911c8e05 100644
--- a/drivers/rtc/rtc-pcf50633.c
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -252,20 +252,17 @@ static int pcf50633_rtc_probe(struct platform_device *pdev)
{
struct pcf50633_rtc *rtc;
- rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->pcf = dev_to_pcf50633(pdev->dev.parent);
platform_set_drvdata(pdev, rtc);
- rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev,
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, "pcf50633-rtc",
&pcf50633_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc_dev)) {
- int ret = PTR_ERR(rtc->rtc_dev);
- kfree(rtc);
- return ret;
- }
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
pcf50633_rtc_irq, rtc);
@@ -277,12 +274,8 @@ static int pcf50633_rtc_remove(struct platform_device *pdev)
struct pcf50633_rtc *rtc;
rtc = platform_get_drvdata(pdev);
-
pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
- rtc_device_unregister(rtc->rtc_dev);
- kfree(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 889e3160e701..305c9515e5bb 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -307,7 +307,7 @@ static int pcf8523_probe(struct i2c_client *client,
if (err < 0)
return err;
- pcf->rtc = rtc_device_register(DRIVER_NAME, &client->dev,
+ pcf->rtc = devm_rtc_device_register(&client->dev, DRIVER_NAME,
&pcf8523_rtc_ops, THIS_MODULE);
if (IS_ERR(pcf->rtc))
return PTR_ERR(pcf->rtc);
@@ -319,10 +319,6 @@ static int pcf8523_probe(struct i2c_client *client,
static int pcf8523_remove(struct i2c_client *client)
{
- struct pcf8523 *pcf = i2c_get_clientdata(client);
-
- rtc_device_unregister(pcf->rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index f7daf18a112e..97b354a26a44 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -245,14 +245,13 @@ static int pcf8563_probe(struct i2c_client *client,
{
struct pcf8563 *pcf8563;
- int err = 0;
-
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- pcf8563 = kzalloc(sizeof(struct pcf8563), GFP_KERNEL);
+ pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563),
+ GFP_KERNEL);
if (!pcf8563)
return -ENOMEM;
@@ -260,31 +259,18 @@ static int pcf8563_probe(struct i2c_client *client,
i2c_set_clientdata(client, pcf8563);
- pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
- &client->dev, &pcf8563_rtc_ops, THIS_MODULE);
+ pcf8563->rtc = devm_rtc_device_register(&client->dev,
+ pcf8563_driver.driver.name,
+ &pcf8563_rtc_ops, THIS_MODULE);
- if (IS_ERR(pcf8563->rtc)) {
- err = PTR_ERR(pcf8563->rtc);
- goto exit_kfree;
- }
+ if (IS_ERR(pcf8563->rtc))
+ return PTR_ERR(pcf8563->rtc);
return 0;
-
-exit_kfree:
- kfree(pcf8563);
-
- return err;
}
static int pcf8563_remove(struct i2c_client *client)
{
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
-
- if (pcf8563->rtc)
- rtc_device_unregister(pcf8563->rtc);
-
- kfree(pcf8563);
-
return 0;
}
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 5f97c61247d5..95886dcf4a39 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -268,39 +268,29 @@ static int pcf8583_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pcf8583 *pcf8583;
- int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- pcf8583 = kzalloc(sizeof(struct pcf8583), GFP_KERNEL);
+ pcf8583 = devm_kzalloc(&client->dev, sizeof(struct pcf8583),
+ GFP_KERNEL);
if (!pcf8583)
return -ENOMEM;
i2c_set_clientdata(client, pcf8583);
- pcf8583->rtc = rtc_device_register(pcf8583_driver.driver.name,
- &client->dev, &pcf8583_rtc_ops, THIS_MODULE);
+ pcf8583->rtc = devm_rtc_device_register(&client->dev,
+ pcf8583_driver.driver.name,
+ &pcf8583_rtc_ops, THIS_MODULE);
- if (IS_ERR(pcf8583->rtc)) {
- err = PTR_ERR(pcf8583->rtc);
- goto exit_kfree;
- }
+ if (IS_ERR(pcf8583->rtc))
+ return PTR_ERR(pcf8583->rtc);
return 0;
-
-exit_kfree:
- kfree(pcf8583);
- return err;
}
static int pcf8583_remove(struct i2c_client *client)
{
- struct pcf8583 *pcf8583 = i2c_get_clientdata(client);
-
- if (pcf8583->rtc)
- rtc_device_unregister(pcf8583->rtc);
- kfree(pcf8583);
return 0;
}
diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c
index 968133ce1ee8..4bb825bb5804 100644
--- a/drivers/rtc/rtc-ps3.c
+++ b/drivers/rtc/rtc-ps3.c
@@ -62,7 +62,7 @@ static int __init ps3_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register("rtc-ps3", &dev->dev, &ps3_rtc_ops,
+ rtc = devm_rtc_device_register(&dev->dev, "rtc-ps3", &ps3_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -73,7 +73,6 @@ static int __init ps3_rtc_probe(struct platform_device *dev)
static int __exit ps3_rtc_remove(struct platform_device *dev)
{
- rtc_device_unregister(platform_get_drvdata(dev));
return 0;
}
@@ -85,18 +84,7 @@ static struct platform_driver ps3_rtc_driver = {
.remove = __exit_p(ps3_rtc_remove),
};
-static int __init ps3_rtc_init(void)
-{
- return platform_driver_probe(&ps3_rtc_driver, ps3_rtc_probe);
-}
-
-static void __exit ps3_rtc_fini(void)
-{
- platform_driver_unregister(&ps3_rtc_driver);
-}
-
-module_init(ps3_rtc_init);
-module_exit(ps3_rtc_fini);
+module_platform_driver_probe(ps3_rtc_driver, ps3_rtc_probe);
MODULE_AUTHOR("Sony Corporation");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c
index 0407e13d4de4..72f437170d2e 100644
--- a/drivers/rtc/rtc-puv3.c
+++ b/drivers/rtc/rtc-puv3.c
@@ -207,14 +207,14 @@ static const struct rtc_class_ops puv3_rtcops = {
.proc = puv3_rtc_proc,
};
-static void puv3_rtc_enable(struct platform_device *pdev, int en)
+static void puv3_rtc_enable(struct device *dev, int en)
{
if (!en) {
writel(readl(RTC_RTSR) & ~RTC_RTSR_HZE, RTC_RTSR);
} else {
/* re-enable the device, and check it is ok */
if ((readl(RTC_RTSR) & RTC_RTSR_HZE) == 0) {
- dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
+ dev_info(dev, "rtc disabled, re-enabling\n");
writel(readl(RTC_RTSR) | RTC_RTSR_HZE, RTC_RTSR);
}
}
@@ -276,7 +276,7 @@ static int puv3_rtc_probe(struct platform_device *pdev)
goto err_nores;
}
- puv3_rtc_enable(pdev, 1);
+ puv3_rtc_enable(&pdev->dev, 1);
/* register RTC and exit */
rtc = rtc_device_register("pkunity", &pdev->dev, &puv3_rtcops,
@@ -296,44 +296,41 @@ static int puv3_rtc_probe(struct platform_device *pdev)
return 0;
err_nortc:
- puv3_rtc_enable(pdev, 0);
+ puv3_rtc_enable(&pdev->dev, 0);
release_resource(puv3_rtc_mem);
err_nores:
return ret;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int ticnt_save;
-static int puv3_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int puv3_rtc_suspend(struct device *dev)
{
/* save RTAR for anyone using periodic interrupts */
ticnt_save = readl(RTC_RTAR);
- puv3_rtc_enable(pdev, 0);
+ puv3_rtc_enable(dev, 0);
return 0;
}
-static int puv3_rtc_resume(struct platform_device *pdev)
+static int puv3_rtc_resume(struct device *dev)
{
- puv3_rtc_enable(pdev, 1);
+ puv3_rtc_enable(dev, 1);
writel(ticnt_save, RTC_RTAR);
return 0;
}
-#else
-#define puv3_rtc_suspend NULL
-#define puv3_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(puv3_rtc_pm_ops, puv3_rtc_suspend, puv3_rtc_resume);
+
static struct platform_driver puv3_rtc_driver = {
.probe = puv3_rtc_probe,
.remove = puv3_rtc_remove,
- .suspend = puv3_rtc_suspend,
- .resume = puv3_rtc_resume,
.driver = {
.name = "PKUnity-v3-RTC",
.owner = THIS_MODULE,
+ .pm = &puv3_rtc_pm_ops,
}
};
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index 03c85ee719a7..ed037ae91c5f 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -416,7 +416,7 @@ static struct of_device_id pxa_rtc_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids);
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int pxa_rtc_suspend(struct device *dev)
{
struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev);
@@ -434,36 +434,20 @@ static int pxa_rtc_resume(struct device *dev)
disable_irq_wake(pxa_rtc->irq_Alrm);
return 0;
}
-
-static const struct dev_pm_ops pxa_rtc_pm_ops = {
- .suspend = pxa_rtc_suspend,
- .resume = pxa_rtc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume);
+
static struct platform_driver pxa_rtc_driver = {
.remove = __exit_p(pxa_rtc_remove),
.driver = {
.name = "pxa-rtc",
.of_match_table = of_match_ptr(pxa_rtc_dt_ids),
-#ifdef CONFIG_PM
.pm = &pxa_rtc_pm_ops,
-#endif
},
};
-static int __init pxa_rtc_init(void)
-{
- return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
-}
-
-static void __exit pxa_rtc_exit(void)
-{
- platform_driver_unregister(&pxa_rtc_driver);
-}
-
-module_init(pxa_rtc_init);
-module_exit(pxa_rtc_exit);
+module_platform_driver_probe(pxa_rtc_driver, pxa_rtc_probe);
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
MODULE_DESCRIPTION("PXA27x/PXA3xx Realtime Clock Driver (RTC)");
diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c
index 7726f4a4f2d0..feeedbd82000 100644
--- a/drivers/rtc/rtc-r9701.c
+++ b/drivers/rtc/rtc-r9701.c
@@ -154,21 +154,18 @@ static int r9701_probe(struct spi_device *spi)
}
}
- rtc = rtc_device_register("r9701",
- &spi->dev, &r9701_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, "r9701",
+ &r9701_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
static int r9701_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
-
- rtc_device_unregister(rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c
index eb3194d664a8..8eabcf51b35a 100644
--- a/drivers/rtc/rtc-rc5t583.c
+++ b/drivers/rtc/rtc-rc5t583.c
@@ -256,7 +256,7 @@ static int rc5t583_rtc_probe(struct platform_device *pdev)
}
device_init_wakeup(&pdev->dev, 1);
- ricoh_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ ricoh_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&rc5t583_rtc_ops, THIS_MODULE);
if (IS_ERR(ricoh_rtc->rtc)) {
ret = PTR_ERR(ricoh_rtc->rtc);
@@ -276,13 +276,10 @@ static int rc5t583_rtc_remove(struct platform_device *pdev)
struct rc5t583_rtc *rc5t583_rtc = dev_get_drvdata(&pdev->dev);
rc5t583_rtc_alarm_irq_enable(&rc5t583_rtc->rtc->dev, 0);
-
- rtc_device_unregister(rc5t583_rtc->rtc);
return 0;
}
#ifdef CONFIG_PM_SLEEP
-
static int rc5t583_rtc_suspend(struct device *dev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(dev->parent);
@@ -304,24 +301,18 @@ static int rc5t583_rtc_resume(struct device *dev)
return regmap_write(rc5t583->regmap, RC5T583_RTC_CTL1,
rc5t583_rtc->irqen);
}
-
-static const struct dev_pm_ops rc5t583_rtc_pm_ops = {
- .suspend = rc5t583_rtc_suspend,
- .resume = rc5t583_rtc_resume,
-};
-
-#define DEV_PM_OPS (&rc5t583_rtc_pm_ops)
-#else
-#define DEV_PM_OPS NULL
#endif
+static SIMPLE_DEV_PM_OPS(rc5t583_rtc_pm_ops, rc5t583_rtc_suspend,
+ rc5t583_rtc_resume);
+
static struct platform_driver rc5t583_rtc_driver = {
.probe = rc5t583_rtc_probe,
.remove = rc5t583_rtc_remove,
.driver = {
.owner = THIS_MODULE,
.name = "rtc-rc5t583",
- .pm = DEV_PM_OPS,
+ .pm = &rc5t583_rtc_pm_ops,
},
};
diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c
index 359da6d020b9..873c689f01c3 100644
--- a/drivers/rtc/rtc-rp5c01.c
+++ b/drivers/rtc/rtc-rp5c01.c
@@ -230,15 +230,13 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->regs = ioremap(res->start, resource_size(res));
- if (!priv->regs) {
- error = -ENOMEM;
- goto out_free_priv;
- }
+ priv->regs = devm_ioremap(&dev->dev, res->start, resource_size(res));
+ if (!priv->regs)
+ return -ENOMEM;
sysfs_bin_attr_init(&priv->nvram_attr);
priv->nvram_attr.attr.name = "nvram";
@@ -251,27 +249,22 @@ static int __init rp5c01_rtc_probe(struct platform_device *dev)
platform_set_drvdata(dev, priv);
- rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops,
+ rtc = devm_rtc_device_register(&dev->dev, "rtc-rp5c01", &rp5c01_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc)) {
error = PTR_ERR(rtc);
- goto out_unmap;
+ goto out;
}
priv->rtc = rtc;
error = sysfs_create_bin_file(&dev->dev.kobj, &priv->nvram_attr);
if (error)
- goto out_unregister;
+ goto out;
return 0;
-out_unregister:
- rtc_device_unregister(rtc);
-out_unmap:
+out:
platform_set_drvdata(dev, NULL);
- iounmap(priv->regs);
-out_free_priv:
- kfree(priv);
return error;
}
@@ -280,9 +273,6 @@ static int __exit rp5c01_rtc_remove(struct platform_device *dev)
struct rp5c01_priv *priv = platform_get_drvdata(dev);
sysfs_remove_bin_file(&dev->dev.kobj, &priv->nvram_attr);
- rtc_device_unregister(priv->rtc);
- iounmap(priv->regs);
- kfree(priv);
return 0;
}
@@ -294,18 +284,7 @@ static struct platform_driver rp5c01_rtc_driver = {
.remove = __exit_p(rp5c01_rtc_remove),
};
-static int __init rp5c01_rtc_init(void)
-{
- return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe);
-}
-
-static void __exit rp5c01_rtc_fini(void)
-{
- platform_driver_unregister(&rp5c01_rtc_driver);
-}
-
-module_init(rp5c01_rtc_init);
-module_exit(rp5c01_rtc_fini);
+module_platform_driver_probe(rp5c01_rtc_driver, rp5c01_rtc_probe);
MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index d98ea5b759c8..8089fc63e403 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -367,7 +367,7 @@ static const struct rtc_class_ops rs5c313_rtc_ops = {
static int rs5c313_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc = rtc_device_register("rs5c313", &pdev->dev,
+ struct rtc_device *rtc = devm_rtc_device_register(&pdev->dev, "rs5c313",
&rs5c313_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -380,10 +380,6 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
static int rs5c313_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata( pdev );
-
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 72ef10be8662..2c37df3586c7 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -158,7 +158,8 @@ static int rs5c348_probe(struct spi_device *spi)
struct rtc_device *rtc;
struct rs5c348_plat_data *pdata;
- pdata = kzalloc(sizeof(struct rs5c348_plat_data), GFP_KERNEL);
+ pdata = devm_kzalloc(&spi->dev, sizeof(struct rs5c348_plat_data),
+ GFP_KERNEL);
if (!pdata)
return -ENOMEM;
spi->dev.platform_data = pdata;
@@ -202,7 +203,7 @@ static int rs5c348_probe(struct spi_device *spi)
if (ret & RS5C348_BIT_24H)
pdata->rtc_24h = 1;
- rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev,
+ rtc = devm_rtc_device_register(&spi->dev, rs5c348_driver.driver.name,
&rs5c348_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -214,18 +215,11 @@ static int rs5c348_probe(struct spi_device *spi)
return 0;
kfree_exit:
- kfree(pdata);
return ret;
}
static int rs5c348_remove(struct spi_device *spi)
{
- struct rs5c348_plat_data *pdata = spi->dev.platform_data;
- struct rtc_device *rtc = pdata->rtc;
-
- if (rtc)
- rtc_device_unregister(rtc);
- kfree(pdata);
return 0;
}
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 581739f40097..224d634322b4 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -579,7 +579,9 @@ static int rs5c372_probe(struct i2c_client *client,
}
}
- if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
+ rs5c372 = devm_kzalloc(&client->dev, sizeof(struct rs5c372),
+ GFP_KERNEL);
+ if (!rs5c372) {
err = -ENOMEM;
goto exit;
}
@@ -594,7 +596,7 @@ static int rs5c372_probe(struct i2c_client *client,
err = rs5c_get_regs(rs5c372);
if (err < 0)
- goto exit_kfree;
+ goto exit;
/* clock may be set for am/pm or 24 hr time */
switch (rs5c372->type) {
@@ -617,7 +619,7 @@ static int rs5c372_probe(struct i2c_client *client,
break;
default:
dev_err(&client->dev, "unknown RTC type\n");
- goto exit_kfree;
+ goto exit;
}
/* if the oscillator lost power and no other software (like
@@ -629,7 +631,7 @@ static int rs5c372_probe(struct i2c_client *client,
err = rs5c_oscillator_setup(rs5c372);
if (unlikely(err < 0)) {
dev_err(&client->dev, "setup error\n");
- goto exit_kfree;
+ goto exit;
}
if (rs5c372_get_datetime(client, &tm) < 0)
@@ -648,38 +650,28 @@ static int rs5c372_probe(struct i2c_client *client,
);
/* REVISIT use client->irq to register alarm irq ... */
-
- rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name,
- &client->dev, &rs5c372_rtc_ops, THIS_MODULE);
+ rs5c372->rtc = devm_rtc_device_register(&client->dev,
+ rs5c372_driver.driver.name,
+ &rs5c372_rtc_ops, THIS_MODULE);
if (IS_ERR(rs5c372->rtc)) {
err = PTR_ERR(rs5c372->rtc);
- goto exit_kfree;
+ goto exit;
}
err = rs5c_sysfs_register(&client->dev);
if (err)
- goto exit_devreg;
+ goto exit;
return 0;
-exit_devreg:
- rtc_device_unregister(rs5c372->rtc);
-
-exit_kfree:
- kfree(rs5c372);
-
exit:
return err;
}
static int rs5c372_remove(struct i2c_client *client)
{
- struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
-
- rtc_device_unregister(rs5c372->rtc);
rs5c_sysfs_unregister(&client->dev);
- kfree(rs5c372);
return 0;
}
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index f8ee8ad7825e..5032c24ec159 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -395,9 +395,8 @@ static int rv3029c2_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
return -ENODEV;
- rtc = rtc_device_register(client->name,
- &client->dev, &rv3029c2_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev, client->name,
+ &rv3029c2_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -407,23 +406,14 @@ static int rv3029c2_probe(struct i2c_client *client,
rc = rv3029c2_i2c_get_sr(client, buf);
if (rc < 0) {
dev_err(&client->dev, "reading status failed\n");
- goto exit_unregister;
+ return rc;
}
return 0;
-
-exit_unregister:
- rtc_device_unregister(rtc);
-
- return rc;
}
static int rv3029c2_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c
index 599ec73ec886..84eb08d65d30 100644
--- a/drivers/rtc/rtc-rx4581.c
+++ b/drivers/rtc/rtc-rx4581.c
@@ -273,20 +273,17 @@ static int rx4581_probe(struct spi_device *spi)
if (res != 0)
return res;
- rtc = rtc_device_register("rx4581",
- &spi->dev, &rx4581_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, "rx4581",
+ &rx4581_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
static int rx4581_remove(struct spi_device *spi)
{
- struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
-
- rtc_device_unregister(rtc);
return 0;
}
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index b0c272658fa2..07f3037b18f4 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -240,8 +240,8 @@ static int rx8581_probe(struct i2c_client *client,
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(rx8581_driver.driver.name,
- &client->dev, &rx8581_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev, rx8581_driver.driver.name,
+ &rx8581_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -253,10 +253,6 @@ static int rx8581_probe(struct i2c_client *client,
static int rx8581_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- rtc_device_unregister(rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index 8a092325188d..f40afdd0e5f5 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -338,7 +338,8 @@ static int s35390a_probe(struct i2c_client *client,
goto exit;
}
- s35390a = kzalloc(sizeof(struct s35390a), GFP_KERNEL);
+ s35390a = devm_kzalloc(&client->dev, sizeof(struct s35390a),
+ GFP_KERNEL);
if (!s35390a) {
err = -ENOMEM;
goto exit;
@@ -386,8 +387,9 @@ static int s35390a_probe(struct i2c_client *client,
device_set_wakeup_capable(&client->dev, 1);
- s35390a->rtc = rtc_device_register(s35390a_driver.driver.name,
- &client->dev, &s35390a_rtc_ops, THIS_MODULE);
+ s35390a->rtc = devm_rtc_device_register(&client->dev,
+ s35390a_driver.driver.name,
+ &s35390a_rtc_ops, THIS_MODULE);
if (IS_ERR(s35390a->rtc)) {
err = PTR_ERR(s35390a->rtc);
@@ -399,7 +401,6 @@ exit_dummy:
for (i = 1; i < 8; ++i)
if (s35390a->client[i])
i2c_unregister_device(s35390a->client[i]);
- kfree(s35390a);
exit:
return err;
@@ -408,15 +409,12 @@ exit:
static int s35390a_remove(struct i2c_client *client)
{
unsigned int i;
-
struct s35390a *s35390a = i2c_get_clientdata(client);
+
for (i = 1; i < 8; ++i)
if (s35390a->client[i])
i2c_unregister_device(s35390a->client[i]);
- rtc_device_unregister(s35390a->rtc);
- kfree(s35390a);
-
return 0;
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index fb994e9ddc15..8e96c00936be 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -51,7 +51,6 @@ static struct clk *rtc_clk;
static void __iomem *s3c_rtc_base;
static int s3c_rtc_alarmno = NO_IRQ;
static int s3c_rtc_tickno = NO_IRQ;
-static bool wake_en;
static enum s3c_cpu_type s3c_rtc_cpu_type;
static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
@@ -423,13 +422,11 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
static int s3c_rtc_remove(struct platform_device *dev)
{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
platform_set_drvdata(dev, NULL);
- rtc_device_unregister(rtc);
s3c_rtc_setaie(&dev->dev, 0);
+ clk_unprepare(rtc_clk);
rtc_clk = NULL;
return 0;
@@ -498,7 +495,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
return ret;
}
- clk_enable(rtc_clk);
+ clk_prepare_enable(rtc_clk);
/* check to see if everything is setup correctly */
@@ -511,7 +508,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
/* register RTC and exit */
- rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
+ rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
THIS_MODULE);
if (IS_ERR(rtc)) {
@@ -574,23 +571,24 @@ static int s3c_rtc_probe(struct platform_device *pdev)
err_alarm_irq:
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(rtc);
err_nortc:
s3c_rtc_enable(pdev, 0);
- clk_disable(rtc_clk);
+ clk_disable_unprepare(rtc_clk);
return ret;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
/* RTC Power management control */
static int ticnt_save, ticnt_en_save;
+static bool wake_en;
-static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int s3c_rtc_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
+
clk_enable(rtc_clk);
/* save TICNT for anyone using periodic interrupts */
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
@@ -600,19 +598,20 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
}
s3c_rtc_enable(pdev, 0);
- if (device_may_wakeup(&pdev->dev) && !wake_en) {
+ if (device_may_wakeup(dev) && !wake_en) {
if (enable_irq_wake(s3c_rtc_alarmno) == 0)
wake_en = true;
else
- dev_err(&pdev->dev, "enable_irq_wake failed\n");
+ dev_err(dev, "enable_irq_wake failed\n");
}
clk_disable(rtc_clk);
return 0;
}
-static int s3c_rtc_resume(struct platform_device *pdev)
+static int s3c_rtc_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
unsigned int tmp;
clk_enable(rtc_clk);
@@ -623,7 +622,7 @@ static int s3c_rtc_resume(struct platform_device *pdev)
writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
}
- if (device_may_wakeup(&pdev->dev) && wake_en) {
+ if (device_may_wakeup(dev) && wake_en) {
disable_irq_wake(s3c_rtc_alarmno);
wake_en = false;
}
@@ -631,11 +630,10 @@ static int s3c_rtc_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define s3c_rtc_suspend NULL
-#define s3c_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
+
#ifdef CONFIG_OF
static struct s3c_rtc_drv_data s3c_rtc_drv_data_array[] = {
[TYPE_S3C2410] = { TYPE_S3C2410 },
@@ -685,12 +683,11 @@ MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = s3c_rtc_remove,
- .suspend = s3c_rtc_suspend,
- .resume = s3c_rtc_resume,
.id_table = s3c_rtc_driver_ids,
.driver = {
.name = "s3c-rtc",
.owner = THIS_MODULE,
+ .pm = &s3c_rtc_pm_ops,
.of_match_table = of_match_ptr(s3c_rtc_dt_match),
},
};
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 5ec5036df0bc..00605601dbf7 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -234,14 +234,13 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
if (irq_1hz < 0 || irq_alarm < 0)
return -ENODEV;
- info = kzalloc(sizeof(struct sa1100_rtc), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL);
if (!info)
return -ENOMEM;
- info->clk = clk_get(&pdev->dev, NULL);
+ info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to find rtc clock source\n");
- ret = PTR_ERR(info->clk);
- goto err_clk;
+ return PTR_ERR(info->clk);
}
info->irq_1hz = irq_1hz;
info->irq_alarm = irq_alarm;
@@ -268,8 +267,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops,
+ THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
@@ -306,9 +305,6 @@ err_dev:
clk_disable_unprepare(info->clk);
err_enable_clk:
platform_set_drvdata(pdev, NULL);
- clk_put(info->clk);
-err_clk:
- kfree(info);
return ret;
}
@@ -317,17 +313,14 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
struct sa1100_rtc *info = platform_get_drvdata(pdev);
if (info) {
- rtc_device_unregister(info->rtc);
clk_disable_unprepare(info->clk);
- clk_put(info->clk);
platform_set_drvdata(pdev, NULL);
- kfree(info);
}
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sa1100_rtc_suspend(struct device *dev)
{
struct sa1100_rtc *info = dev_get_drvdata(dev);
@@ -343,13 +336,11 @@ static int sa1100_rtc_resume(struct device *dev)
disable_irq_wake(info->irq_alarm);
return 0;
}
-
-static const struct dev_pm_ops sa1100_rtc_pm_ops = {
- .suspend = sa1100_rtc_suspend,
- .resume = sa1100_rtc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend,
+ sa1100_rtc_resume);
+
#ifdef CONFIG_OF
static struct of_device_id sa1100_rtc_dt_ids[] = {
{ .compatible = "mrvl,sa1100-rtc", },
@@ -364,9 +355,7 @@ static struct platform_driver sa1100_rtc_driver = {
.remove = sa1100_rtc_remove,
.driver = {
.name = "sa1100-rtc",
-#ifdef CONFIG_PM
.pm = &sa1100_rtc_pm_ops,
-#endif
.of_match_table = of_match_ptr(sa1100_rtc_dt_ids),
},
};
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index e55a7635ae5f..8d5bd2e36776 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -790,6 +790,7 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
}
}
+#ifdef CONFIG_PM_SLEEP
static int sh_rtc_suspend(struct device *dev)
{
if (device_may_wakeup(dev))
@@ -805,33 +806,20 @@ static int sh_rtc_resume(struct device *dev)
return 0;
}
+#endif
-static const struct dev_pm_ops sh_rtc_dev_pm_ops = {
- .suspend = sh_rtc_suspend,
- .resume = sh_rtc_resume,
-};
+static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
static struct platform_driver sh_rtc_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .pm = &sh_rtc_dev_pm_ops,
+ .pm = &sh_rtc_pm_ops,
},
.remove = __exit_p(sh_rtc_remove),
};
-static int __init sh_rtc_init(void)
-{
- return platform_driver_probe(&sh_rtc_platform_driver, sh_rtc_probe);
-}
-
-static void __exit sh_rtc_exit(void)
-{
- platform_driver_unregister(&sh_rtc_platform_driver);
-}
-
-module_init(sh_rtc_init);
-module_exit(sh_rtc_exit);
+module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
MODULE_DESCRIPTION("SuperH on-chip RTC driver");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index f7d90703db5e..b04f09a1df2a 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -283,7 +283,7 @@ static int snvs_rtc_probe(struct platform_device *pdev)
return ret;
}
- data->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&snvs_rtc_ops, THIS_MODULE);
if (IS_ERR(data->rtc)) {
ret = PTR_ERR(data->rtc);
@@ -296,10 +296,6 @@ static int snvs_rtc_probe(struct platform_device *pdev)
static int snvs_rtc_remove(struct platform_device *pdev)
{
- struct snvs_rtc_data *data = platform_get_drvdata(pdev);
-
- rtc_device_unregister(data->rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index a18c3192ed40..574359c48f65 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -400,8 +400,8 @@ static int spear_rtc_probe(struct platform_device *pdev)
spin_lock_init(&config->lock);
platform_set_drvdata(pdev, config);
- config->rtc = rtc_device_register(pdev->name, &pdev->dev,
- &spear_rtc_ops, THIS_MODULE);
+ config->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &spear_rtc_ops, THIS_MODULE);
if (IS_ERR(config->rtc)) {
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(config->rtc));
@@ -427,7 +427,6 @@ static int spear_rtc_remove(struct platform_device *pdev)
{
struct spear_rtc_config *config = platform_get_drvdata(pdev);
- rtc_device_unregister(config->rtc);
spear_rtc_disable_interrupt(config);
clk_disable_unprepare(config->clk);
device_init_wakeup(&pdev->dev, 0);
@@ -435,10 +434,10 @@ static int spear_rtc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
-static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int spear_rtc_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct spear_rtc_config *config = platform_get_drvdata(pdev);
int irq;
@@ -454,8 +453,9 @@ static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int spear_rtc_resume(struct platform_device *pdev)
+static int spear_rtc_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct spear_rtc_config *config = platform_get_drvdata(pdev);
int irq;
@@ -473,12 +473,10 @@ static int spear_rtc_resume(struct platform_device *pdev)
return 0;
}
-
-#else
-#define spear_rtc_suspend NULL
-#define spear_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(spear_rtc_pm_ops, spear_rtc_suspend, spear_rtc_resume);
+
static void spear_rtc_shutdown(struct platform_device *pdev)
{
struct spear_rtc_config *config = platform_get_drvdata(pdev);
@@ -498,11 +496,10 @@ MODULE_DEVICE_TABLE(of, spear_rtc_id_table);
static struct platform_driver spear_rtc_driver = {
.probe = spear_rtc_probe,
.remove = spear_rtc_remove,
- .suspend = spear_rtc_suspend,
- .resume = spear_rtc_resume,
.shutdown = spear_rtc_shutdown,
.driver = {
.name = "rtc-spear",
+ .pm = &spear_rtc_pm_ops,
.of_match_table = of_match_ptr(spear_rtc_id_table),
},
};
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
index 5be98bfd7ed3..987b5ec0ae56 100644
--- a/drivers/rtc/rtc-starfire.c
+++ b/drivers/rtc/rtc-starfire.c
@@ -39,8 +39,10 @@ static const struct rtc_class_ops starfire_rtc_ops = {
static int __init starfire_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc = rtc_device_register("starfire", &pdev->dev,
- &starfire_rtc_ops, THIS_MODULE);
+ struct rtc_device *rtc;
+
+ rtc = devm_rtc_device_register(&pdev->dev, "starfire",
+ &starfire_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -51,10 +53,6 @@ static int __init starfire_rtc_probe(struct platform_device *pdev)
static int __exit starfire_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
-
return 0;
}
@@ -66,15 +64,4 @@ static struct platform_driver starfire_rtc_driver = {
.remove = __exit_p(starfire_rtc_remove),
};
-static int __init starfire_rtc_init(void)
-{
- return platform_driver_probe(&starfire_rtc_driver, starfire_rtc_probe);
-}
-
-static void __exit starfire_rtc_exit(void)
-{
- platform_driver_unregister(&starfire_rtc_driver);
-}
-
-module_init(starfire_rtc_init);
-module_exit(starfire_rtc_exit);
+module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 7e4a6f65cb91..af5e97e3f272 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -336,14 +336,13 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev)
}
}
- pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&stk17ta8_rtc_ops, THIS_MODULE);
if (IS_ERR(pdata->rtc))
return PTR_ERR(pdata->rtc);
ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
- if (ret)
- rtc_device_unregister(pdata->rtc);
+
return ret;
}
@@ -352,7 +351,6 @@ static int stk17ta8_rtc_remove(struct platform_device *pdev)
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
- rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0)
writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
return 0;
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index 98f0d3c30738..a9cd26a26dc0 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -227,11 +227,7 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev)
writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
- free_irq(rtc_data->irq_alarm, &pdev->dev);
- rtc_device_unregister(rtc_data->rtc);
platform_set_drvdata(pdev, NULL);
- iounmap(rtc_data->io);
- kfree(rtc_data);
return 0;
}
@@ -242,22 +238,20 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
struct resource *r;
int err;
- rtc_data = kzalloc(sizeof *rtc_data, GFP_KERNEL);
+ rtc_data = devm_kzalloc(&pdev->dev, sizeof(*rtc_data), GFP_KERNEL);
if (!rtc_data)
return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "failed to get resource\n");
- err = -ENXIO;
- goto out_free;
+ return -ENXIO;
}
- rtc_data->io = ioremap(r->start, resource_size(r));
+ rtc_data->io = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!rtc_data->io) {
dev_err(&pdev->dev, "ioremap failed\n");
- err = -EIO;
- goto out_free;
+ return -EIO;
}
rtc_data->irq_alarm = platform_get_irq(pdev, 0);
@@ -265,8 +259,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
if (!(readl(STMP3XXX_RTC_STAT + rtc_data->io) &
STMP3XXX_RTC_STAT_RTC_PRESENT)) {
dev_err(&pdev->dev, "no device onboard\n");
- err = -ENODEV;
- goto out_remap;
+ return -ENODEV;
}
platform_set_drvdata(pdev, rtc_data);
@@ -281,43 +274,38 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
STMP3XXX_RTC_CTRL_ALARM_IRQ_EN,
rtc_data->io + STMP3XXX_RTC_CTRL_CLR);
- rtc_data->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc_data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&stmp3xxx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc_data->rtc)) {
err = PTR_ERR(rtc_data->rtc);
- goto out_remap;
+ goto out;
}
- err = request_irq(rtc_data->irq_alarm, stmp3xxx_rtc_interrupt, 0,
- "RTC alarm", &pdev->dev);
+ err = devm_request_irq(&pdev->dev, rtc_data->irq_alarm,
+ stmp3xxx_rtc_interrupt, 0, "RTC alarm", &pdev->dev);
if (err) {
dev_err(&pdev->dev, "Cannot claim IRQ%d\n",
rtc_data->irq_alarm);
- goto out_irq_alarm;
+ goto out;
}
stmp3xxx_wdt_register(pdev);
return 0;
-out_irq_alarm:
- rtc_device_unregister(rtc_data->rtc);
-out_remap:
+out:
platform_set_drvdata(pdev, NULL);
- iounmap(rtc_data->io);
-out_free:
- kfree(rtc_data);
return err;
}
-#ifdef CONFIG_PM
-static int stmp3xxx_rtc_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int stmp3xxx_rtc_suspend(struct device *dev)
{
return 0;
}
-static int stmp3xxx_rtc_resume(struct platform_device *dev)
+static int stmp3xxx_rtc_resume(struct device *dev)
{
- struct stmp3xxx_rtc_data *rtc_data = platform_get_drvdata(dev);
+ struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
mxs_reset_block(rtc_data->io);
writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN |
@@ -326,11 +314,11 @@ static int stmp3xxx_rtc_resume(struct platform_device *dev)
rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR);
return 0;
}
-#else
-#define stmp3xxx_rtc_suspend NULL
-#define stmp3xxx_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(stmp3xxx_rtc_pm_ops, stmp3xxx_rtc_suspend,
+ stmp3xxx_rtc_resume);
+
static const struct of_device_id rtc_dt_ids[] = {
{ .compatible = "fsl,stmp3xxx-rtc", },
{ /* sentinel */ }
@@ -340,11 +328,10 @@ MODULE_DEVICE_TABLE(of, rtc_dt_ids);
static struct platform_driver stmp3xxx_rtcdrv = {
.probe = stmp3xxx_rtc_probe,
.remove = stmp3xxx_rtc_remove,
- .suspend = stmp3xxx_rtc_suspend,
- .resume = stmp3xxx_rtc_resume,
.driver = {
.name = "stmp3xxx-rtc",
.owner = THIS_MODULE,
+ .pm = &stmp3xxx_rtc_pm_ops,
.of_match_table = of_match_ptr(rtc_dt_ids),
},
};
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
index 59b5c2dcb58c..ce42e5fa9e09 100644
--- a/drivers/rtc/rtc-sun4v.c
+++ b/drivers/rtc/rtc-sun4v.c
@@ -81,8 +81,10 @@ static const struct rtc_class_ops sun4v_rtc_ops = {
static int __init sun4v_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc = rtc_device_register("sun4v", &pdev->dev,
- &sun4v_rtc_ops, THIS_MODULE);
+ struct rtc_device *rtc;
+
+ rtc = devm_rtc_device_register(&pdev->dev, "sun4v",
+ &sun4v_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -92,9 +94,6 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev)
static int __exit sun4v_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
return 0;
}
@@ -106,18 +105,7 @@ static struct platform_driver sun4v_rtc_driver = {
.remove = __exit_p(sun4v_rtc_remove),
};
-static int __init sun4v_rtc_init(void)
-{
- return platform_driver_probe(&sun4v_rtc_driver, sun4v_rtc_probe);
-}
-
-static void __exit sun4v_rtc_exit(void)
-{
- platform_driver_unregister(&sun4v_rtc_driver);
-}
-
-module_init(sun4v_rtc_init);
-module_exit(sun4v_rtc_exit);
+module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe);
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("SUN4V RTC driver");
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 7c033756d6b5..a34315d25478 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
#define TEGRA_RTC_REG_BUSY 0x004
@@ -309,7 +310,7 @@ static const struct of_device_id tegra_rtc_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_rtc_dt_match);
-static int tegra_rtc_probe(struct platform_device *pdev)
+static int __init tegra_rtc_probe(struct platform_device *pdev)
{
struct tegra_rtc_info *info;
struct resource *res;
@@ -348,53 +349,35 @@ static int tegra_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- info->rtc_dev = rtc_device_register(
- pdev->name, &pdev->dev, &tegra_rtc_ops, THIS_MODULE);
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev,
+ dev_name(&pdev->dev), &tegra_rtc_ops,
+ THIS_MODULE);
if (IS_ERR(info->rtc_dev)) {
ret = PTR_ERR(info->rtc_dev);
- info->rtc_dev = NULL;
- dev_err(&pdev->dev,
- "Unable to register device (err=%d).\n",
+ dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
ret);
return ret;
}
ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
tegra_rtc_irq_handler, IRQF_TRIGGER_HIGH,
- "rtc alarm", &pdev->dev);
+ dev_name(&pdev->dev), &pdev->dev);
if (ret) {
dev_err(&pdev->dev,
"Unable to request interrupt for device (err=%d).\n",
ret);
- goto err_dev_unreg;
+ return ret;
}
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
return 0;
-
-err_dev_unreg:
- rtc_device_unregister(info->rtc_dev);
-
- return ret;
}
-static int tegra_rtc_remove(struct platform_device *pdev)
+#ifdef CONFIG_PM_SLEEP
+static int tegra_rtc_suspend(struct device *dev)
{
- struct tegra_rtc_info *info = platform_get_drvdata(pdev);
-
- rtc_device_unregister(info->rtc_dev);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct device *dev = &pdev->dev;
- struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+ struct tegra_rtc_info *info = dev_get_drvdata(dev);
tegra_rtc_wait_while_busy(dev);
@@ -416,10 +399,9 @@ static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int tegra_rtc_resume(struct platform_device *pdev)
+static int tegra_rtc_resume(struct device *dev)
{
- struct device *dev = &pdev->dev;
- struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+ struct tegra_rtc_info *info = dev_get_drvdata(dev);
dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n",
device_may_wakeup(dev));
@@ -431,6 +413,8 @@ static int tegra_rtc_resume(struct platform_device *pdev)
}
#endif
+static SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume);
+
static void tegra_rtc_shutdown(struct platform_device *pdev)
{
dev_vdbg(&pdev->dev, "disabling interrupts.\n");
@@ -439,30 +423,16 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
MODULE_ALIAS("platform:tegra_rtc");
static struct platform_driver tegra_rtc_driver = {
- .remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
.owner = THIS_MODULE,
.of_match_table = tegra_rtc_dt_match,
+ .pm = &tegra_rtc_pm_ops,
},
-#ifdef CONFIG_PM
- .suspend = tegra_rtc_suspend,
- .resume = tegra_rtc_resume,
-#endif
};
-static int __init tegra_rtc_init(void)
-{
- return platform_driver_probe(&tegra_rtc_driver, tegra_rtc_probe);
-}
-module_init(tegra_rtc_init);
-
-static void __exit tegra_rtc_exit(void)
-{
- platform_driver_unregister(&tegra_rtc_driver);
-}
-module_exit(tegra_rtc_exit);
+module_platform_driver_probe(tegra_rtc_driver, tegra_rtc_probe);
MODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>");
MODULE_DESCRIPTION("driver for Tegra internal RTC");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index b92e0f6383e6..7746e65b93f2 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -99,8 +99,10 @@ static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
static int test_probe(struct platform_device *plat_dev)
{
int err;
- struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev,
- &test_rtc_ops, THIS_MODULE);
+ struct rtc_device *rtc;
+
+ rtc = devm_rtc_device_register(&plat_dev->dev, "test",
+ &test_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
return err;
@@ -115,15 +117,11 @@ static int test_probe(struct platform_device *plat_dev)
return 0;
err:
- rtc_device_unregister(rtc);
return err;
}
static int test_remove(struct platform_device *plat_dev)
{
- struct rtc_device *rtc = platform_get_drvdata(plat_dev);
-
- rtc_device_unregister(rtc);
device_remove_file(&plat_dev->dev, &dev_attr_irq);
return 0;
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c
index 62db4841078b..249b6531f119 100644
--- a/drivers/rtc/rtc-tile.c
+++ b/drivers/rtc/rtc-tile.c
@@ -80,8 +80,8 @@ static int tile_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register("tile",
- &dev->dev, &tile_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&dev->dev, "tile",
+ &tile_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -96,11 +96,6 @@ static int tile_rtc_probe(struct platform_device *dev)
*/
static int tile_rtc_remove(struct platform_device *dev)
{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
platform_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index aab4e8c93622..459c2ffc95a6 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -274,7 +274,7 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rtc);
- rtc->rtc = rtc_device_register(dev_name(&pdev->dev), &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev),
&tps6586x_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
ret = PTR_ERR(rtc->rtc);
@@ -289,15 +289,12 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ(%d) failed with ret %d\n",
rtc->irq, ret);
- goto fail_req_irq;
+ goto fail_rtc_register;
}
disable_irq(rtc->irq);
device_set_wakeup_capable(&pdev->dev, 1);
return 0;
-fail_req_irq:
- rtc_device_unregister(rtc->rtc);
-
fail_rtc_register:
tps6586x_update(tps_dev, RTC_CTRL, 0,
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
@@ -306,12 +303,10 @@ fail_rtc_register:
static int tps6586x_rtc_remove(struct platform_device *pdev)
{
- struct tps6586x_rtc *rtc = platform_get_drvdata(pdev);
struct device *tps_dev = to_tps6586x_dev(&pdev->dev);
tps6586x_update(tps_dev, RTC_CTRL, 0,
RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
- rtc_device_unregister(rtc->rtc);
return 0;
}
@@ -335,9 +330,8 @@ static int tps6586x_rtc_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops tps6586x_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tps6586x_rtc_suspend, tps6586x_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_rtc_suspend,
+ tps6586x_rtc_resume);
static struct platform_driver tps6586x_rtc_driver = {
.driver = {
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 8bd8115329b5..a9caf043b0ce 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -263,7 +263,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
if (irq <= 0) {
dev_warn(&pdev->dev, "Wake up is not possible as irq = %d\n",
irq);
- return ret;
+ return -ENXIO;
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
@@ -276,7 +276,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
tps_rtc->irq = irq;
device_set_wakeup_capable(&pdev->dev, 1);
- tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ tps_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&tps65910_rtc_ops, THIS_MODULE);
if (IS_ERR(tps_rtc->rtc)) {
ret = PTR_ERR(tps_rtc->rtc);
@@ -295,12 +295,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
*/
static int tps65910_rtc_remove(struct platform_device *pdev)
{
- /* leave rtc running, but disable irqs */
- struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev);
-
tps65910_rtc_alarm_irq_enable(&pdev->dev, 0);
- rtc_device_unregister(tps_rtc->rtc);
return 0;
}
@@ -324,9 +320,8 @@ static int tps65910_rtc_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops tps65910_rtc_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(tps65910_rtc_pm_ops, tps65910_rtc_suspend,
+ tps65910_rtc_resume);
static struct platform_driver tps65910_rtc_driver = {
.probe = tps65910_rtc_probe,
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index 9aaf8aaebae9..72662eafb938 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -277,7 +277,7 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
return ret;
}
- rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&tps80031_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
ret = PTR_ERR(rtc->rtc);
@@ -292,7 +292,6 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",
rtc->irq, ret);
- rtc_device_unregister(rtc->rtc);
return ret;
}
device_set_wakeup_capable(&pdev->dev, 1);
@@ -301,9 +300,6 @@ static int tps80031_rtc_probe(struct platform_device *pdev)
static int tps80031_rtc_remove(struct platform_device *pdev)
{
- struct tps80031_rtc *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc->rtc);
return 0;
}
@@ -327,9 +323,8 @@ static int tps80031_rtc_resume(struct device *dev)
};
#endif
-static const struct dev_pm_ops tps80031_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume)
-};
+static SIMPLE_DEV_PM_OPS(tps80031_pm_ops, tps80031_rtc_suspend,
+ tps80031_rtc_resume);
static struct platform_driver tps80031_rtc_driver = {
.driver = {
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 8bc6c80b184c..8751a5240c99 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -566,11 +566,10 @@ static void twl_rtc_shutdown(struct platform_device *pdev)
mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static unsigned char irqstat;
-static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+static int twl_rtc_suspend(struct device *dev)
{
irqstat = rtc_irq_bits;
@@ -578,17 +577,15 @@ static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int twl_rtc_resume(struct platform_device *pdev)
+static int twl_rtc_resume(struct device *dev)
{
set_rtc_irq_bit(irqstat);
return 0;
}
-
-#else
-#define twl_rtc_suspend NULL
-#define twl_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
+
#ifdef CONFIG_OF
static const struct of_device_id twl_rtc_of_match[] = {
{.compatible = "ti,twl4030-rtc", },
@@ -603,11 +600,10 @@ static struct platform_driver twl4030rtc_driver = {
.probe = twl_rtc_probe,
.remove = twl_rtc_remove,
.shutdown = twl_rtc_shutdown,
- .suspend = twl_rtc_suspend,
- .resume = twl_rtc_resume,
.driver = {
.owner = THIS_MODULE,
.name = "twl_rtc",
+ .pm = &twl_rtc_pm_ops,
.of_match_table = of_match_ptr(twl_rtc_of_match),
},
};
diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c
index a12bfac49d36..f9a0677e4e3b 100644
--- a/drivers/rtc/rtc-tx4939.c
+++ b/drivers/rtc/rtc-tx4939.c
@@ -268,14 +268,13 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
0, pdev->name, &pdev->dev) < 0)
return -EBUSY;
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&tx4939_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
pdata->rtc = rtc;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
- if (ret)
- rtc_device_unregister(rtc);
+
return ret;
}
@@ -284,7 +283,6 @@ static int __exit tx4939_rtc_remove(struct platform_device *pdev)
struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
- rtc_device_unregister(pdata->rtc);
spin_lock_irq(&pdata->lock);
tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
spin_unlock_irq(&pdata->lock);
@@ -299,18 +297,7 @@ static struct platform_driver tx4939_rtc_driver = {
},
};
-static int __init tx4939rtc_init(void)
-{
- return platform_driver_probe(&tx4939_rtc_driver, tx4939_rtc_probe);
-}
-
-static void __exit tx4939rtc_exit(void)
-{
- platform_driver_unregister(&tx4939_rtc_driver);
-}
-
-module_init(tx4939rtc_init);
-module_exit(tx4939rtc_exit);
+module_platform_driver_probe(tx4939_rtc_driver, tx4939_rtc_probe);
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
MODULE_DESCRIPTION("TX4939 internal RTC driver");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index bca5d677bc85..6e0cba8f47d5 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -309,7 +309,7 @@ static int rtc_probe(struct platform_device *pdev)
int i;
int temp;
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -353,8 +353,8 @@ static int rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, chip);
- chip->rtc = rtc_device_register("v3020",
- &pdev->dev, &v3020_rtc_ops, THIS_MODULE);
+ chip->rtc = devm_rtc_device_register(&pdev->dev, "v3020",
+ &v3020_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
retval = PTR_ERR(chip->rtc);
goto err_io;
@@ -365,21 +365,14 @@ static int rtc_probe(struct platform_device *pdev)
err_io:
chip->ops->unmap_io(chip);
err_chip:
- kfree(chip);
-
return retval;
}
static int rtc_remove(struct platform_device *dev)
{
struct v3020 *chip = platform_get_drvdata(dev);
- struct rtc_device *rtc = chip->rtc;
-
- if (rtc)
- rtc_device_unregister(rtc);
chip->ops->unmap_io(chip);
- kfree(chip);
return 0;
}
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
index a000bc0a8bff..d89efee6d29e 100644
--- a/drivers/rtc/rtc-vt8500.c
+++ b/drivers/rtc/rtc-vt8500.c
@@ -252,7 +252,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
writel(VT8500_RTC_CR_ENABLE,
vt8500_rtc->regbase + VT8500_RTC_CR);
- vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
+ vt8500_rtc->rtc = devm_rtc_device_register(&pdev->dev, "vt8500-rtc",
&vt8500_rtc_ops, THIS_MODULE);
if (IS_ERR(vt8500_rtc->rtc)) {
ret = PTR_ERR(vt8500_rtc->rtc);
@@ -266,13 +266,11 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "can't get irq %i, err %d\n",
vt8500_rtc->irq_alarm, ret);
- goto err_unreg;
+ goto err_return;
}
return 0;
-err_unreg:
- rtc_device_unregister(vt8500_rtc->rtc);
err_return:
return ret;
}
@@ -281,8 +279,6 @@ static int vt8500_rtc_remove(struct platform_device *pdev)
{
struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
- rtc_device_unregister(vt8500_rtc->rtc);
-
/* Disable alarm matching */
writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c
index 2f0ac7b30a0c..8d65b94e5a7e 100644
--- a/drivers/rtc/rtc-wm831x.c
+++ b/drivers/rtc/rtc-wm831x.c
@@ -436,7 +436,7 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- wm831x_rtc->rtc = rtc_device_register("wm831x", &pdev->dev,
+ wm831x_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm831x",
&wm831x_rtc_ops, THIS_MODULE);
if (IS_ERR(wm831x_rtc->rtc)) {
ret = PTR_ERR(wm831x_rtc->rtc);
@@ -462,10 +462,6 @@ err:
static int wm831x_rtc_remove(struct platform_device *pdev)
{
- struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(wm831x_rtc->rtc);
-
return 0;
}
diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c
index 8ad86ae0d30f..fa247deb9cf4 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -339,7 +339,7 @@ static const struct rtc_class_ops wm8350_rtc_ops = {
.alarm_irq_enable = wm8350_rtc_alarm_irq_enable,
};
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int wm8350_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -375,10 +375,6 @@ static int wm8350_rtc_resume(struct device *dev)
return 0;
}
-
-#else
-#define wm8350_rtc_suspend NULL
-#define wm8350_rtc_resume NULL
#endif
static int wm8350_rtc_probe(struct platform_device *pdev)
@@ -439,8 +435,8 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
- wm_rtc->rtc = rtc_device_register("wm8350", &pdev->dev,
- &wm8350_rtc_ops, THIS_MODULE);
+ wm_rtc->rtc = devm_rtc_device_register(&pdev->dev, "wm8350",
+ &wm8350_rtc_ops, THIS_MODULE);
if (IS_ERR(wm_rtc->rtc)) {
ret = PTR_ERR(wm_rtc->rtc);
dev_err(&pdev->dev, "failed to register RTC: %d\n", ret);
@@ -462,20 +458,15 @@ static int wm8350_rtc_probe(struct platform_device *pdev)
static int wm8350_rtc_remove(struct platform_device *pdev)
{
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
- struct wm8350_rtc *wm_rtc = &wm8350->rtc;
wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC, wm8350);
wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM, wm8350);
- rtc_device_unregister(wm_rtc->rtc);
-
return 0;
}
-static struct dev_pm_ops wm8350_rtc_pm_ops = {
- .suspend = wm8350_rtc_suspend,
- .resume = wm8350_rtc_resume,
-};
+static SIMPLE_DEV_PM_OPS(wm8350_rtc_pm_ops, wm8350_rtc_suspend,
+ wm8350_rtc_resume);
static struct platform_driver wm8350_rtc_driver = {
.probe = wm8350_rtc_probe,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index f36e59c6bc01..fa9b0679fb60 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -630,8 +630,8 @@ static int x1205_probe(struct i2c_client *client,
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
- &x1205_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&client->dev, x1205_driver.driver.name,
+ &x1205_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -653,21 +653,13 @@ static int x1205_probe(struct i2c_client *client,
err = x1205_sysfs_register(&client->dev);
if (err)
- goto exit_devreg;
+ return err;
return 0;
-
-exit_devreg:
- rtc_device_unregister(rtc);
-
- return err;
}
static int x1205_remove(struct i2c_client *client)
{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- rtc_device_unregister(rtc);
x1205_sysfs_unregister(&client->dev);
return 0;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index f1b7fdc58a5f..82758cbb220b 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -246,7 +246,7 @@ static struct dentry *dasd_debugfs_setup(const char *name,
static int dasd_state_known_to_basic(struct dasd_device *device)
{
struct dasd_block *block = device->block;
- int rc;
+ int rc = 0;
/* Allocate and register gendisk structure. */
if (block) {
@@ -273,7 +273,8 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
device->state = DASD_STATE_BASIC;
- return 0;
+
+ return rc;
}
/*
@@ -282,6 +283,7 @@ static int dasd_state_known_to_basic(struct dasd_device *device)
static int dasd_state_basic_to_known(struct dasd_device *device)
{
int rc;
+
if (device->block) {
dasd_profile_exit(&device->block->profile);
if (device->block->debugfs_dentry)
@@ -332,8 +334,10 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
if (block->base->discipline->do_analysis != NULL)
rc = block->base->discipline->do_analysis(block);
if (rc) {
- if (rc != -EAGAIN)
+ if (rc != -EAGAIN) {
device->state = DASD_STATE_UNFMT;
+ goto out;
+ }
return rc;
}
dasd_setup_queue(block);
@@ -341,11 +345,16 @@ static int dasd_state_basic_to_ready(struct dasd_device *device)
block->blocks << block->s2b_shift);
device->state = DASD_STATE_READY;
rc = dasd_scan_partitions(block);
- if (rc)
+ if (rc) {
device->state = DASD_STATE_BASIC;
+ return rc;
+ }
} else {
device->state = DASD_STATE_READY;
}
+out:
+ if (device->discipline->basic_to_ready)
+ rc = device->discipline->basic_to_ready(device);
return rc;
}
@@ -368,6 +377,11 @@ static int dasd_state_ready_to_basic(struct dasd_device *device)
{
int rc;
+ if (device->discipline->ready_to_basic) {
+ rc = device->discipline->ready_to_basic(device);
+ if (rc)
+ return rc;
+ }
device->state = DASD_STATE_BASIC;
if (device->block) {
struct dasd_block *block = device->block;
@@ -402,16 +416,10 @@ static int dasd_state_unfmt_to_basic(struct dasd_device *device)
static int
dasd_state_ready_to_online(struct dasd_device * device)
{
- int rc;
struct gendisk *disk;
struct disk_part_iter piter;
struct hd_struct *part;
- if (device->discipline->ready_to_online) {
- rc = device->discipline->ready_to_online(device);
- if (rc)
- return rc;
- }
device->state = DASD_STATE_ONLINE;
if (device->block) {
dasd_schedule_block_bh(device->block);
@@ -444,6 +452,7 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
if (rc)
return rc;
}
+
device->state = DASD_STATE_READY;
if (device->block && !(device->features & DASD_FEATURE_USERAW)) {
disk = device->block->bdev->bd_disk;
@@ -2223,6 +2232,77 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
return rc;
}
+static inline int _wait_for_wakeup_queue(struct list_head *ccw_queue)
+{
+ struct dasd_ccw_req *cqr;
+
+ list_for_each_entry(cqr, ccw_queue, blocklist) {
+ if (cqr->callback_data != DASD_SLEEPON_END_TAG)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
+{
+ struct dasd_device *device;
+ int rc;
+ struct dasd_ccw_req *cqr, *n;
+
+retry:
+ list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+ device = cqr->startdev;
+ if (cqr->status != DASD_CQR_FILLED) /*could be failed*/
+ continue;
+
+ if (test_bit(DASD_FLAG_LOCK_STOLEN, &device->flags) &&
+ !test_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags)) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = -EPERM;
+ continue;
+ }
+ /*Non-temporary stop condition will trigger fail fast*/
+ if (device->stopped & ~DASD_STOPPED_PENDING &&
+ test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+ !dasd_eer_enabled(device)) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = -EAGAIN;
+ continue;
+ }
+
+ /*Don't try to start requests if device is stopped*/
+ if (interruptible) {
+ rc = wait_event_interruptible(
+ generic_waitq, !device->stopped);
+ if (rc == -ERESTARTSYS) {
+ cqr->status = DASD_CQR_FAILED;
+ cqr->intrc = rc;
+ continue;
+ }
+ } else
+ wait_event(generic_waitq, !(device->stopped));
+
+ if (!cqr->callback)
+ cqr->callback = dasd_wakeup_cb;
+ cqr->callback_data = DASD_SLEEPON_START_TAG;
+ dasd_add_request_tail(cqr);
+ }
+
+ wait_event(generic_waitq, _wait_for_wakeup_queue(ccw_queue));
+
+ rc = 0;
+ list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
+ if (__dasd_sleep_on_erp(cqr))
+ rc = 1;
+ }
+ if (rc)
+ goto retry;
+
+
+ return 0;
+}
+
/*
* Queue a request to the tail of the device ccw_queue and wait for
* it's completion.
@@ -2233,6 +2313,15 @@ int dasd_sleep_on(struct dasd_ccw_req *cqr)
}
/*
+ * Start requests from a ccw_queue and wait for their completion.
+ */
+int dasd_sleep_on_queue(struct list_head *ccw_queue)
+{
+ return _dasd_sleep_on_queue(ccw_queue, 0);
+}
+EXPORT_SYMBOL(dasd_sleep_on_queue);
+
+/*
* Queue a request to the tail of the device ccw_queue and wait
* interruptible for it's completion.
*/
@@ -2663,6 +2752,26 @@ static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data)
}
/*
+ * Requeue a request back to the block request queue
+ * only works for block requests
+ */
+static int _dasd_requeue_request(struct dasd_ccw_req *cqr)
+{
+ struct dasd_block *block = cqr->block;
+ struct request *req;
+ unsigned long flags;
+
+ if (!block)
+ return -EINVAL;
+ spin_lock_irqsave(&block->queue_lock, flags);
+ req = (struct request *) cqr->callback_data;
+ blk_requeue_request(block->request_queue, req);
+ spin_unlock_irqrestore(&block->queue_lock, flags);
+
+ return 0;
+}
+
+/*
* Go through all request on the dasd_block request queue, cancel them
* on the respective dasd_device, and return them to the generic
* block layer.
@@ -3380,10 +3489,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_verify_path);
int dasd_generic_pm_freeze(struct ccw_device *cdev)
{
+ struct dasd_device *device = dasd_device_from_cdev(cdev);
+ struct list_head freeze_queue;
struct dasd_ccw_req *cqr, *n;
+ struct dasd_ccw_req *refers;
int rc;
- struct list_head freeze_queue;
- struct dasd_device *device = dasd_device_from_cdev(cdev);
if (IS_ERR(device))
return PTR_ERR(device);
@@ -3396,7 +3506,8 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
/* disallow new I/O */
dasd_device_set_stop_bits(device, DASD_STOPPED_PM);
- /* clear active requests */
+
+ /* clear active requests and requeue them to block layer if possible */
INIT_LIST_HEAD(&freeze_queue);
spin_lock_irq(get_ccwdev_lock(cdev));
rc = 0;
@@ -3416,7 +3527,6 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
}
list_move_tail(&cqr->devlist, &freeze_queue);
}
-
spin_unlock_irq(get_ccwdev_lock(cdev));
list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
@@ -3424,12 +3534,38 @@ int dasd_generic_pm_freeze(struct ccw_device *cdev)
(cqr->status != DASD_CQR_CLEAR_PENDING));
if (cqr->status == DASD_CQR_CLEARED)
cqr->status = DASD_CQR_QUEUED;
+
+ /* requeue requests to blocklayer will only work for
+ block device requests */
+ if (_dasd_requeue_request(cqr))
+ continue;
+
+ /* remove requests from device and block queue */
+ list_del_init(&cqr->devlist);
+ while (cqr->refers != NULL) {
+ refers = cqr->refers;
+ /* remove the request from the block queue */
+ list_del(&cqr->blocklist);
+ /* free the finished erp request */
+ dasd_free_erp_request(cqr, cqr->memdev);
+ cqr = refers;
+ }
+ if (cqr->block)
+ list_del_init(&cqr->blocklist);
+ cqr->block->base->discipline->free_cp(
+ cqr, (struct request *) cqr->callback_data);
}
- /* move freeze_queue to start of the ccw_queue */
- spin_lock_irq(get_ccwdev_lock(cdev));
- list_splice_tail(&freeze_queue, &device->ccw_queue);
- spin_unlock_irq(get_ccwdev_lock(cdev));
+ /*
+ * if requests remain then they are internal request
+ * and go back to the device queue
+ */
+ if (!list_empty(&freeze_queue)) {
+ /* move freeze_queue to start of the ccw_queue */
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ list_splice_tail(&freeze_queue, &device->ccw_queue);
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+ }
dasd_put_device(device);
return rc;
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index c196827c228f..a71bb8aaca1d 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -410,8 +410,7 @@ dasd_add_busid(const char *bus_id, int features)
struct dasd_devmap *devmap, *new, *tmp;
int hash;
- new = (struct dasd_devmap *)
- kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+ new = kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
if (!new)
return ERR_PTR(-ENOMEM);
spin_lock(&dasd_devmap_lock);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 6999fd919e94..6a44b27623ed 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -2022,7 +2022,7 @@ static int dasd_eckd_do_analysis(struct dasd_block *block)
return dasd_eckd_end_analysis(block);
}
-static int dasd_eckd_ready_to_online(struct dasd_device *device)
+static int dasd_eckd_basic_to_ready(struct dasd_device *device)
{
return dasd_alias_add_device(device);
};
@@ -2031,6 +2031,11 @@ static int dasd_eckd_online_to_ready(struct dasd_device *device)
{
cancel_work_sync(&device->reload_device);
cancel_work_sync(&device->kick_validate);
+ return 0;
+};
+
+static int dasd_eckd_ready_to_basic(struct dasd_device *device)
+{
return dasd_alias_remove_device(device);
};
@@ -2050,45 +2055,34 @@ dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo)
}
static struct dasd_ccw_req *
-dasd_eckd_format_device(struct dasd_device * device,
- struct format_data_t * fdata)
+dasd_eckd_build_format(struct dasd_device *base,
+ struct format_data_t *fdata)
{
- struct dasd_eckd_private *private;
+ struct dasd_eckd_private *base_priv;
+ struct dasd_eckd_private *start_priv;
+ struct dasd_device *startdev;
struct dasd_ccw_req *fcp;
struct eckd_count *ect;
+ struct ch_t address;
struct ccw1 *ccw;
void *data;
int rpt;
- struct ch_t address;
int cplength, datasize;
- int i;
+ int i, j;
int intensity = 0;
int r0_perm;
+ int nr_tracks;
- private = (struct dasd_eckd_private *) device->private;
- rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize);
- set_ch_t(&address,
- fdata->start_unit / private->rdc_data.trk_per_cyl,
- fdata->start_unit % private->rdc_data.trk_per_cyl);
+ startdev = dasd_alias_get_start_dev(base);
+ if (!startdev)
+ startdev = base;
- /* Sanity checks. */
- if (fdata->start_unit >=
- (private->real_cyl * private->rdc_data.trk_per_cyl)) {
- dev_warn(&device->cdev->dev, "Start track number %d used in "
- "formatting is too big\n", fdata->start_unit);
- return ERR_PTR(-EINVAL);
- }
- if (fdata->start_unit > fdata->stop_unit) {
- dev_warn(&device->cdev->dev, "Start track %d used in "
- "formatting exceeds end track\n", fdata->start_unit);
- return ERR_PTR(-EINVAL);
- }
- if (dasd_check_blocksize(fdata->blksize) != 0) {
- dev_warn(&device->cdev->dev,
- "The DASD cannot be formatted with block size %d\n",
- fdata->blksize);
- return ERR_PTR(-EINVAL);
- }
+ start_priv = (struct dasd_eckd_private *) startdev->private;
+ base_priv = (struct dasd_eckd_private *) base->private;
+
+ rpt = recs_per_track(&base_priv->rdc_data, 0, fdata->blksize);
+
+ nr_tracks = fdata->stop_unit - fdata->start_unit + 1;
/*
* fdata->intensity is a bit string that tells us what to do:
@@ -2106,149 +2100,282 @@ dasd_eckd_format_device(struct dasd_device * device,
r0_perm = 1;
intensity = fdata->intensity;
}
+
switch (intensity) {
case 0x00: /* Normal format */
case 0x08: /* Normal format, use cdl. */
- cplength = 2 + rpt;
- datasize = sizeof(struct DE_eckd_data) +
+ cplength = 2 + (rpt*nr_tracks);
+ datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
- rpt * sizeof(struct eckd_count);
+ rpt * nr_tracks * sizeof(struct eckd_count);
break;
case 0x01: /* Write record zero and format track. */
case 0x09: /* Write record zero and format track, use cdl. */
- cplength = 3 + rpt;
- datasize = sizeof(struct DE_eckd_data) +
+ cplength = 2 + rpt * nr_tracks;
+ datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count) +
- rpt * sizeof(struct eckd_count);
+ rpt * nr_tracks * sizeof(struct eckd_count);
break;
case 0x04: /* Invalidate track. */
case 0x0c: /* Invalidate track, use cdl. */
cplength = 3;
- datasize = sizeof(struct DE_eckd_data) +
+ datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count);
break;
default:
- dev_warn(&device->cdev->dev, "An I/O control call used "
- "incorrect flags 0x%x\n", fdata->intensity);
+ dev_warn(&startdev->cdev->dev,
+ "An I/O control call used incorrect flags 0x%x\n",
+ fdata->intensity);
return ERR_PTR(-EINVAL);
}
/* Allocate the format ccw request. */
- fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize, device);
+ fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
+ datasize, startdev);
if (IS_ERR(fcp))
return fcp;
+ start_priv->count++;
data = fcp->data;
ccw = fcp->cpaddr;
switch (intensity & ~0x08) {
case 0x00: /* Normal format. */
- define_extent(ccw++, (struct DE_eckd_data *) data,
- fdata->start_unit, fdata->start_unit,
- DASD_ECKD_CCW_WRITE_CKD, device);
+ prefix(ccw++, (struct PFX_eckd_data *) data,
+ fdata->start_unit, fdata->stop_unit,
+ DASD_ECKD_CCW_WRITE_CKD, base, startdev);
/* grant subsystem permission to format R0 */
if (r0_perm)
- ((struct DE_eckd_data *)data)->ga_extended |= 0x04;
- data += sizeof(struct DE_eckd_data);
+ ((struct PFX_eckd_data *)data)
+ ->define_extent.ga_extended |= 0x04;
+ data += sizeof(struct PFX_eckd_data);
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data,
- fdata->start_unit, 0, rpt,
- DASD_ECKD_CCW_WRITE_CKD, device,
+ fdata->start_unit, 0, rpt*nr_tracks,
+ DASD_ECKD_CCW_WRITE_CKD, base,
fdata->blksize);
data += sizeof(struct LO_eckd_data);
break;
case 0x01: /* Write record zero + format track. */
- define_extent(ccw++, (struct DE_eckd_data *) data,
- fdata->start_unit, fdata->start_unit,
- DASD_ECKD_CCW_WRITE_RECORD_ZERO,
- device);
- data += sizeof(struct DE_eckd_data);
+ prefix(ccw++, (struct PFX_eckd_data *) data,
+ fdata->start_unit, fdata->stop_unit,
+ DASD_ECKD_CCW_WRITE_RECORD_ZERO,
+ base, startdev);
+ data += sizeof(struct PFX_eckd_data);
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data,
- fdata->start_unit, 0, rpt + 1,
- DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
- device->block->bp_block);
+ fdata->start_unit, 0, rpt * nr_tracks + 1,
+ DASD_ECKD_CCW_WRITE_RECORD_ZERO, base,
+ base->block->bp_block);
data += sizeof(struct LO_eckd_data);
break;
case 0x04: /* Invalidate track. */
- define_extent(ccw++, (struct DE_eckd_data *) data,
- fdata->start_unit, fdata->start_unit,
- DASD_ECKD_CCW_WRITE_CKD, device);
- data += sizeof(struct DE_eckd_data);
+ prefix(ccw++, (struct PFX_eckd_data *) data,
+ fdata->start_unit, fdata->stop_unit,
+ DASD_ECKD_CCW_WRITE_CKD, base, startdev);
+ data += sizeof(struct PFX_eckd_data);
ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, 1,
- DASD_ECKD_CCW_WRITE_CKD, device, 8);
+ DASD_ECKD_CCW_WRITE_CKD, base, 8);
data += sizeof(struct LO_eckd_data);
break;
}
- if (intensity & 0x01) { /* write record zero */
- ect = (struct eckd_count *) data;
- data += sizeof(struct eckd_count);
- ect->cyl = address.cyl;
- ect->head = address.head;
- ect->record = 0;
- ect->kl = 0;
- ect->dl = 8;
- ccw[-1].flags |= CCW_FLAG_CC;
- ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
- ccw->flags = CCW_FLAG_SLI;
- ccw->count = 8;
- ccw->cda = (__u32)(addr_t) ect;
- ccw++;
- }
- if ((intensity & ~0x08) & 0x04) { /* erase track */
- ect = (struct eckd_count *) data;
- data += sizeof(struct eckd_count);
- ect->cyl = address.cyl;
- ect->head = address.head;
- ect->record = 1;
- ect->kl = 0;
- ect->dl = 0;
- ccw[-1].flags |= CCW_FLAG_CC;
- ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
- ccw->flags = CCW_FLAG_SLI;
- ccw->count = 8;
- ccw->cda = (__u32)(addr_t) ect;
- } else { /* write remaining records */
- for (i = 0; i < rpt; i++) {
+
+ for (j = 0; j < nr_tracks; j++) {
+ /* calculate cylinder and head for the current track */
+ set_ch_t(&address,
+ (fdata->start_unit + j) /
+ base_priv->rdc_data.trk_per_cyl,
+ (fdata->start_unit + j) %
+ base_priv->rdc_data.trk_per_cyl);
+ if (intensity & 0x01) { /* write record zero */
ect = (struct eckd_count *) data;
data += sizeof(struct eckd_count);
ect->cyl = address.cyl;
ect->head = address.head;
- ect->record = i + 1;
+ ect->record = 0;
ect->kl = 0;
- ect->dl = fdata->blksize;
- /* Check for special tracks 0-1 when formatting CDL */
- if ((intensity & 0x08) &&
- fdata->start_unit == 0) {
- if (i < 3) {
- ect->kl = 4;
- ect->dl = sizes_trk0[i] - 4;
- }
- }
- if ((intensity & 0x08) &&
- fdata->start_unit == 1) {
- ect->kl = 44;
- ect->dl = LABEL_SIZE - 44;
- }
+ ect->dl = 8;
ccw[-1].flags |= CCW_FLAG_CC;
- ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+ ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
ccw->flags = CCW_FLAG_SLI;
ccw->count = 8;
ccw->cda = (__u32)(addr_t) ect;
ccw++;
}
+ if ((intensity & ~0x08) & 0x04) { /* erase track */
+ ect = (struct eckd_count *) data;
+ data += sizeof(struct eckd_count);
+ ect->cyl = address.cyl;
+ ect->head = address.head;
+ ect->record = 1;
+ ect->kl = 0;
+ ect->dl = 0;
+ ccw[-1].flags |= CCW_FLAG_CC;
+ ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+ ccw->flags = CCW_FLAG_SLI;
+ ccw->count = 8;
+ ccw->cda = (__u32)(addr_t) ect;
+ } else { /* write remaining records */
+ for (i = 0; i < rpt; i++) {
+ ect = (struct eckd_count *) data;
+ data += sizeof(struct eckd_count);
+ ect->cyl = address.cyl;
+ ect->head = address.head;
+ ect->record = i + 1;
+ ect->kl = 0;
+ ect->dl = fdata->blksize;
+ /*
+ * Check for special tracks 0-1
+ * when formatting CDL
+ */
+ if ((intensity & 0x08) &&
+ fdata->start_unit == 0) {
+ if (i < 3) {
+ ect->kl = 4;
+ ect->dl = sizes_trk0[i] - 4;
+ }
+ }
+ if ((intensity & 0x08) &&
+ fdata->start_unit == 1) {
+ ect->kl = 44;
+ ect->dl = LABEL_SIZE - 44;
+ }
+ ccw[-1].flags |= CCW_FLAG_CC;
+ if (i != 0 || j == 0)
+ ccw->cmd_code =
+ DASD_ECKD_CCW_WRITE_CKD;
+ else
+ ccw->cmd_code =
+ DASD_ECKD_CCW_WRITE_CKD_MT;
+ ccw->flags = CCW_FLAG_SLI;
+ ccw->count = 8;
+ ccw->cda = (__u32)(addr_t) ect;
+ ccw++;
+ }
+ }
}
- fcp->startdev = device;
- fcp->memdev = device;
+
+ fcp->startdev = startdev;
+ fcp->memdev = startdev;
fcp->retries = 256;
+ fcp->expires = startdev->default_expires * HZ;
fcp->buildclk = get_tod_clock();
fcp->status = DASD_CQR_FILLED;
+
return fcp;
}
+static int
+dasd_eckd_format_device(struct dasd_device *base,
+ struct format_data_t *fdata)
+{
+ struct dasd_ccw_req *cqr, *n;
+ struct dasd_block *block;
+ struct dasd_eckd_private *private;
+ struct list_head format_queue;
+ struct dasd_device *device;
+ int old_stop, format_step;
+ int step, rc = 0;
+
+ block = base->block;
+ private = (struct dasd_eckd_private *) base->private;
+
+ /* Sanity checks. */
+ if (fdata->start_unit >=
+ (private->real_cyl * private->rdc_data.trk_per_cyl)) {
+ dev_warn(&base->cdev->dev,
+ "Start track number %u used in formatting is too big\n",
+ fdata->start_unit);
+ return -EINVAL;
+ }
+ if (fdata->stop_unit >=
+ (private->real_cyl * private->rdc_data.trk_per_cyl)) {
+ dev_warn(&base->cdev->dev,
+ "Stop track number %u used in formatting is too big\n",
+ fdata->stop_unit);
+ return -EINVAL;
+ }
+ if (fdata->start_unit > fdata->stop_unit) {
+ dev_warn(&base->cdev->dev,
+ "Start track %u used in formatting exceeds end track\n",
+ fdata->start_unit);
+ return -EINVAL;
+ }
+ if (dasd_check_blocksize(fdata->blksize) != 0) {
+ dev_warn(&base->cdev->dev,
+ "The DASD cannot be formatted with block size %u\n",
+ fdata->blksize);
+ return -EINVAL;
+ }
+
+ INIT_LIST_HEAD(&format_queue);
+ old_stop = fdata->stop_unit;
+
+ while (fdata->start_unit <= 1) {
+ fdata->stop_unit = fdata->start_unit;
+ cqr = dasd_eckd_build_format(base, fdata);
+ list_add(&cqr->blocklist, &format_queue);
+
+ fdata->stop_unit = old_stop;
+ fdata->start_unit++;
+
+ if (fdata->start_unit > fdata->stop_unit)
+ goto sleep;
+ }
+
+retry:
+ format_step = 255 / recs_per_track(&private->rdc_data, 0,
+ fdata->blksize);
+ while (fdata->start_unit <= old_stop) {
+ step = fdata->stop_unit - fdata->start_unit + 1;
+ if (step > format_step)
+ fdata->stop_unit = fdata->start_unit + format_step - 1;
+
+ cqr = dasd_eckd_build_format(base, fdata);
+ if (IS_ERR(cqr)) {
+ if (PTR_ERR(cqr) == -ENOMEM) {
+ /*
+ * not enough memory available
+ * go to out and start requests
+ * retry after first requests were finished
+ */
+ fdata->stop_unit = old_stop;
+ goto sleep;
+ } else
+ return PTR_ERR(cqr);
+ }
+ list_add(&cqr->blocklist, &format_queue);
+
+ fdata->start_unit = fdata->stop_unit + 1;
+ fdata->stop_unit = old_stop;
+ }
+
+sleep:
+ dasd_sleep_on_queue(&format_queue);
+
+ list_for_each_entry_safe(cqr, n, &format_queue, blocklist) {
+ device = cqr->startdev;
+ private = (struct dasd_eckd_private *) device->private;
+ if (cqr->status == DASD_CQR_FAILED)
+ rc = -EIO;
+ list_del_init(&cqr->blocklist);
+ dasd_sfree_request(cqr, device);
+ private->count--;
+ }
+
+ /*
+ * in case of ENOMEM we need to retry after
+ * first requests are finished
+ */
+ if (fdata->start_unit <= fdata->stop_unit)
+ goto retry;
+
+ return rc;
+}
+
static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr)
{
cqr->status = DASD_CQR_FILLED;
@@ -4305,8 +4432,9 @@ static struct dasd_discipline dasd_eckd_discipline = {
.uncheck_device = dasd_eckd_uncheck_device,
.do_analysis = dasd_eckd_do_analysis,
.verify_path = dasd_eckd_verify_path,
- .ready_to_online = dasd_eckd_ready_to_online,
+ .basic_to_ready = dasd_eckd_basic_to_ready,
.online_to_ready = dasd_eckd_online_to_ready,
+ .ready_to_basic = dasd_eckd_ready_to_basic,
.fill_geometry = dasd_eckd_fill_geometry,
.start_IO = dasd_start_IO,
.term_IO = dasd_term_IO,
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 899e3f5a56e5..0785bd9bd5b6 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -300,10 +300,11 @@ struct dasd_discipline {
* Last things to do when a device is set online, and first things
* when it is set offline.
*/
- int (*ready_to_online) (struct dasd_device *);
+ int (*basic_to_ready) (struct dasd_device *);
int (*online_to_ready) (struct dasd_device *);
+ int (*ready_to_basic) (struct dasd_device *);
- /*
+ /* (struct dasd_device *);
* Device operation functions. build_cp creates a ccw chain for
* a block device request, start_io starts the request and
* term_IO cancels it (e.g. in case of a timeout). format_device
@@ -317,8 +318,8 @@ struct dasd_discipline {
int (*start_IO) (struct dasd_ccw_req *);
int (*term_IO) (struct dasd_ccw_req *);
void (*handle_terminated_request) (struct dasd_ccw_req *);
- struct dasd_ccw_req *(*format_device) (struct dasd_device *,
- struct format_data_t *);
+ int (*format_device) (struct dasd_device *,
+ struct format_data_t *);
int (*free_cp) (struct dasd_ccw_req *, struct request *);
/*
@@ -672,6 +673,7 @@ int dasd_term_IO(struct dasd_ccw_req *);
void dasd_schedule_device_bh(struct dasd_device *);
void dasd_schedule_block_bh(struct dasd_block *);
int dasd_sleep_on(struct dasd_ccw_req *);
+int dasd_sleep_on_queue(struct list_head *);
int dasd_sleep_on_immediatly(struct dasd_ccw_req *);
int dasd_sleep_on_interruptible(struct dasd_ccw_req *);
void dasd_device_set_timer(struct dasd_device *, int);
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 03c0e0444553..8be1b51e9311 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -143,12 +143,12 @@ static int dasd_ioctl_resume(struct dasd_block *block)
/*
* performs formatting of _device_ according to _fdata_
* Note: The discipline's format_function is assumed to deliver formatting
- * commands to format a single unit of the device. In terms of the ECKD
- * devices this means CCWs are generated to format a single track.
+ * commands to format multiple units of the device. In terms of the ECKD
+ * devices this means CCWs are generated to format multiple tracks.
*/
-static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
+static int
+dasd_format(struct dasd_block *block, struct format_data_t *fdata)
{
- struct dasd_ccw_req *cqr;
struct dasd_device *base;
int rc;
@@ -157,8 +157,8 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
return -EPERM;
if (base->state != DASD_STATE_BASIC) {
- pr_warning("%s: The DASD cannot be formatted while it is "
- "enabled\n", dev_name(&base->cdev->dev));
+ pr_warn("%s: The DASD cannot be formatted while it is enabled\n",
+ dev_name(&base->cdev->dev));
return -EBUSY;
}
@@ -178,21 +178,10 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata)
bdput(bdev);
}
- while (fdata->start_unit <= fdata->stop_unit) {
- cqr = base->discipline->format_device(base, fdata);
- if (IS_ERR(cqr))
- return PTR_ERR(cqr);
- rc = dasd_sleep_on_interruptible(cqr);
- dasd_sfree_request(cqr, cqr->memdev);
- if (rc) {
- if (rc != -ERESTARTSYS)
- pr_err("%s: Formatting unit %d failed with "
- "rc=%d\n", dev_name(&base->cdev->dev),
- fdata->start_unit, rc);
- return rc;
- }
- fdata->start_unit++;
- }
+ rc = base->discipline->format_device(base, fdata);
+ if (rc)
+ return rc;
+
return 0;
}
diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c
index 5ac9c935c151..b303cab76a7f 100644
--- a/drivers/s390/block/scm_blk.c
+++ b/drivers/s390/block/scm_blk.c
@@ -307,7 +307,7 @@ static void scm_blk_handle_error(struct scm_request *scmrq)
case EQC_WR_PROHIBIT:
spin_lock_irqsave(&bdev->lock, flags);
if (bdev->state != SCM_WR_PROHIBIT)
- pr_info("%lu: Write access to the SCM increment is suspended\n",
+ pr_info("%lx: Write access to the SCM increment is suspended\n",
(unsigned long) bdev->scmdev->address);
bdev->state = SCM_WR_PROHIBIT;
spin_unlock_irqrestore(&bdev->lock, flags);
@@ -445,7 +445,7 @@ void scm_blk_set_available(struct scm_blk_dev *bdev)
spin_lock_irqsave(&bdev->lock, flags);
if (bdev->state == SCM_WR_PROHIBIT)
- pr_info("%lu: Write access to the SCM increment is restored\n",
+ pr_info("%lx: Write access to the SCM increment is restored\n",
(unsigned long) bdev->scmdev->address);
bdev->state = SCM_OPER;
spin_unlock_irqrestore(&bdev->lock, flags);
@@ -463,12 +463,15 @@ static int __init scm_blk_init(void)
goto out;
scm_major = ret;
- if (scm_alloc_rqs(nr_requests))
- goto out_unreg;
+ ret = scm_alloc_rqs(nr_requests);
+ if (ret)
+ goto out_free;
scm_debug = debug_register("scm_log", 16, 1, 16);
- if (!scm_debug)
+ if (!scm_debug) {
+ ret = -ENOMEM;
goto out_free;
+ }
debug_register_view(scm_debug, &debug_hex_ascii_view);
debug_set_level(scm_debug, 2);
@@ -483,7 +486,6 @@ out_dbf:
debug_unregister(scm_debug);
out_free:
scm_free_rqs();
-out_unreg:
unregister_blkdev(scm_major, "scm");
out:
return ret;
diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c
index f4bb61b0cea1..c0d102e3a48b 100644
--- a/drivers/s390/block/scm_blk_cluster.c
+++ b/drivers/s390/block/scm_blk_cluster.c
@@ -223,6 +223,8 @@ void scm_cluster_request_irq(struct scm_request *scmrq)
bool scm_cluster_size_valid(void)
{
- return write_cluster_size == 0 || write_cluster_size == 32 ||
- write_cluster_size == 64 || write_cluster_size == 128;
+ if (write_cluster_size == 1 || write_cluster_size > 128)
+ return false;
+
+ return !(write_cluster_size & (write_cluster_size - 1));
}
diff --git a/drivers/s390/block/scm_drv.c b/drivers/s390/block/scm_drv.c
index 5f6180d6ff08..c98cf52d78d1 100644
--- a/drivers/s390/block/scm_drv.c
+++ b/drivers/s390/block/scm_drv.c
@@ -19,7 +19,7 @@ static void scm_notify(struct scm_device *scmdev, enum scm_event event)
switch (event) {
case SCM_CHANGE:
- pr_info("%lu: The capabilities of the SCM increment changed\n",
+ pr_info("%lx: The capabilities of the SCM increment changed\n",
(unsigned long) scmdev->address);
SCM_LOG(2, "State changed");
SCM_LOG_STATE(2, scmdev);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 7b00fa634d40..eb5d22795c47 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -502,7 +502,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
raw3215_try_io(raw);
raw->flags &= ~RAW3215_FLUSHING;
#ifdef CONFIG_TN3215_CONSOLE
- wait_cons_dev();
+ ccw_device_wait_idle(raw->cdev);
#endif
/* Enough room freed up ? */
if (RAW3215_BUFFER_SIZE - raw->count >= length)
@@ -858,7 +858,7 @@ static void con3215_flush(void)
raw = raw3215[0]; /* console 3215 is the first one */
if (raw->port.flags & ASYNC_SUSPENDED)
/* The console is still frozen for suspend. */
- if (ccw_device_force_console())
+ if (ccw_device_force_console(raw->cdev))
/* Forcing didn't work, no panic message .. */
return;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index f4ff515db251..0da3ae3cd63b 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -174,8 +174,7 @@ static void mon_free_mem(struct mon_private *monpriv)
int i;
for (i = 0; i < MON_MSGLIM; i++)
- if (monpriv->msg_array[i])
- kfree(monpriv->msg_array[i]);
+ kfree(monpriv->msg_array[i]);
kfree(monpriv);
}
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 4c9030a5b9f2..24a08e8f19e1 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -796,7 +796,7 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
do {
__raw3270_reset_device(rp);
while (!raw3270_state_final(rp)) {
- wait_cons_dev();
+ ccw_device_wait_idle(rp->cdev);
barrier();
}
} while (rp->state != RAW3270_STATE_READY);
@@ -810,7 +810,7 @@ raw3270_wait_cons_dev(struct raw3270 *rp)
unsigned long flags;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
- wait_cons_dev();
+ ccw_device_wait_idle(rp->cdev);
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
}
@@ -1274,7 +1274,7 @@ void raw3270_pm_unfreeze(struct raw3270_view *view)
rp = view->dev;
if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
- ccw_device_force_console();
+ ccw_device_force_console(rp->cdev);
#endif
}
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index cd798386b622..178836ec252b 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -561,6 +561,8 @@ static void __init sclp_add_standby_memory(void)
add_memory_merged(0);
}
+#define MEM_SCT_SIZE (1UL << SECTION_SIZE_BITS)
+
static void __init insert_increment(u16 rn, int standby, int assigned)
{
struct memory_increment *incr, *new_incr;
@@ -573,7 +575,7 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
new_incr->rn = rn;
new_incr->standby = standby;
if (!standby)
- new_incr->usecount = 1;
+ new_incr->usecount = rzm > MEM_SCT_SIZE ? rzm/MEM_SCT_SIZE : 1;
last_rn = 0;
prev = &sclp_mem_list;
list_for_each_entry(incr, &sclp_mem_list, list) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 14b4cb8abcc8..7ed7a5987816 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -107,7 +107,6 @@ sclp_tty_write_room (struct tty_struct *tty)
static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{
- struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -125,12 +124,8 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
struct sclp_buffer, list);
spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
- /* check if the tty needs a wake up call */
- tty = tty_port_tty_get(&sclp_port);
- if (tty != NULL) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+
+ tty_port_tty_wakeup(&sclp_port);
}
static inline void
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 6c92f62623be..5aaaa2ec8df4 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -114,7 +114,6 @@ static struct sclp_register sclp_vt220_register = {
static void
sclp_vt220_process_queue(struct sclp_vt220_request *request)
{
- struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -139,12 +138,7 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
} while (__sclp_vt220_emit(request));
if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
- /* Check if the tty needs a wake up call */
- tty = tty_port_tty_get(&sclp_vt220_port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&sclp_vt220_port);
}
#define SCLP_BUFFER_MAX_RETRY 1
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index b907dba24025..cee69dac3e18 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -915,7 +915,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
int i, rc;
/* Check if the tty3270 is already there. */
- view = raw3270_find_view(&tty3270_fn, tty->index);
+ view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
if (!IS_ERR(view)) {
tp = container_of(view, struct tty3270, view);
tty->driver_data = tp;
@@ -927,15 +927,16 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
tp->inattr = TF_INPUT;
return tty_port_install(&tp->port, driver, tty);
}
- if (tty3270_max_index < tty->index)
- tty3270_max_index = tty->index;
+ if (tty3270_max_index < tty->index + 1)
+ tty3270_max_index = tty->index + 1;
/* Allocate tty3270 structure on first open. */
tp = tty3270_alloc_view();
if (IS_ERR(tp))
return PTR_ERR(tp);
- rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
+ rc = raw3270_add_view(&tp->view, &tty3270_fn,
+ tty->index + RAW3270_FIRSTMINOR);
if (rc) {
tty3270_free_view(tp);
return rc;
@@ -1846,12 +1847,12 @@ static const struct tty_operations tty3270_ops = {
void tty3270_create_cb(int minor)
{
- tty_register_device(tty3270_driver, minor, NULL);
+ tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
}
void tty3270_destroy_cb(int minor)
{
- tty_unregister_device(tty3270_driver, minor);
+ tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
}
struct raw3270_notifier tty3270_notifier =
@@ -1884,7 +1885,8 @@ static int __init tty3270_init(void)
driver->driver_name = "tty3270";
driver->name = "3270/tty";
driver->major = IBM_TTY3270_MAJOR;
- driver->minor_start = 0;
+ driver->minor_start = RAW3270_FIRSTMINOR;
+ driver->name_base = RAW3270_FIRSTMINOR;
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 1d61a01576d2..22820610022c 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -127,7 +127,7 @@ static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
}
if (mode == TO_USER) {
if (copy_to_user((__force __user void*) dest + offs, buf,
- PAGE_SIZE))
+ count - offs))
return -EFAULT;
} else
memcpy(dest + offs, buf, count - offs);
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 50ad5fdd815d..21fabc6d5a9c 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -377,6 +377,26 @@ static void chp_release(struct device *dev)
}
/**
+ * chp_update_desc - update channel-path description
+ * @chp - channel-path
+ *
+ * Update the channel-path description of the specified channel-path.
+ * Return zero on success, non-zero otherwise.
+ */
+int chp_update_desc(struct channel_path *chp)
+{
+ int rc;
+
+ rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc);
+ if (rc)
+ return rc;
+
+ rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1);
+
+ return rc;
+}
+
+/**
* chp_new - register a new channel-path
* @chpid - channel-path ID
*
@@ -403,7 +423,7 @@ int chp_new(struct chp_id chpid)
mutex_init(&chp->lock);
/* Obtain channel path description and fill it in. */
- ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ ret = chp_update_desc(chp);
if (ret)
goto out_free;
if ((chp->desc.flags & 0x80) == 0) {
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h
index e1399dbee834..9284b785a06f 100644
--- a/drivers/s390/cio/chp.h
+++ b/drivers/s390/cio/chp.h
@@ -44,6 +44,7 @@ struct channel_path {
struct mutex lock; /* Serialize access to below members. */
int state;
struct channel_path_desc desc;
+ struct channel_path_desc_fmt1 desc_fmt1;
/* Channel-measurement related stuff: */
int cmg;
int shared;
@@ -62,6 +63,7 @@ int chp_is_registered(struct chp_id chpid);
void *chp_get_chp_desc(struct chp_id chpid);
void chp_remove_cmg_attr(struct channel_path *chp);
int chp_add_cmg_attr(struct channel_path *chp);
+int chp_update_desc(struct channel_path *chp);
int chp_new(struct chp_id chpid);
void chp_cfg_schedule(struct chp_id chpid, int configure);
void chp_cfg_cancel_deconfigure(struct chp_id chpid);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index e16c553f6556..8ea7d9b2c671 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -376,7 +376,7 @@ static void chsc_process_sei_chp_avail(struct chsc_sei_nt0_area *sei_area)
continue;
}
mutex_lock(&chp->lock);
- chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ chp_update_desc(chp);
mutex_unlock(&chp->lock);
}
}
@@ -631,8 +631,8 @@ int chsc_chp_vary(struct chp_id chpid, int on)
* Redo PathVerification on the devices the chpid connects to
*/
if (on) {
- /* Try to update the channel path descritor. */
- chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ /* Try to update the channel path description. */
+ chp_update_desc(chp);
for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
__s390_vary_chpid_on, &chpid);
} else
@@ -825,9 +825,10 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
{
struct chsc_response_struct *chsc_resp;
struct chsc_scpd *scpd_area;
+ unsigned long flags;
int ret;
- spin_lock_irq(&chsc_page_lock);
+ spin_lock_irqsave(&chsc_page_lock, flags);
scpd_area = chsc_page;
ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area);
if (ret)
@@ -835,7 +836,7 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid,
chsc_resp = (void *)&scpd_area->response;
memcpy(desc, &chsc_resp->data, sizeof(*desc));
out:
- spin_unlock_irq(&chsc_page_lock);
+ spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 986ef6a92a41..935d80b4e9ce 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -471,15 +471,6 @@ int cio_disable_subchannel(struct subchannel *sch)
}
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
-int cio_create_sch_lock(struct subchannel *sch)
-{
- sch->lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
- if (!sch->lock)
- return -ENOMEM;
- spin_lock_init(sch->lock);
- return 0;
-}
-
static int cio_check_devno_blacklisted(struct subchannel *sch)
{
if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
@@ -536,32 +527,19 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
sprintf(dbf_txt, "valsch%x", schid.sch_no);
CIO_TRACE_EVENT(4, dbf_txt);
- /* Nuke all fields. */
- memset(sch, 0, sizeof(struct subchannel));
-
- sch->schid = schid;
- if (cio_is_console(schid)) {
- sch->lock = cio_get_console_lock();
- } else {
- err = cio_create_sch_lock(sch);
- if (err)
- goto out;
- }
- mutex_init(&sch->reg_mutex);
-
/*
* The first subchannel that is not-operational (ccode==3)
- * indicates that there aren't any more devices available.
+ * indicates that there aren't any more devices available.
* If stsch gets an exception, it means the current subchannel set
- * is not valid.
+ * is not valid.
*/
- ccode = stsch_err (schid, &sch->schib);
+ ccode = stsch_err(schid, &sch->schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
}
- /* Copy subchannel type from path management control word. */
sch->st = sch->schib.pmcw.st;
+ sch->schid = schid;
switch (sch->st) {
case SUBCHANNEL_TYPE_IO:
@@ -578,11 +556,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
sch->schid.ssid, sch->schid.sch_no, sch->st);
- return 0;
out:
- if (!cio_is_console(schid))
- kfree(sch->lock);
- sch->lock = NULL;
return err;
}
@@ -650,15 +624,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
}
#ifdef CONFIG_CCW_CONSOLE
-static struct subchannel console_subchannel;
-static struct io_subchannel_private console_priv;
-static int console_subchannel_in_use;
+static struct subchannel *console_sch;
/*
* Use cio_tsch to update the subchannel status and call the interrupt handler
- * if status had been pending. Called with the console_subchannel lock.
+ * if status had been pending. Called with the subchannel's lock held.
*/
-static void cio_tsch(struct subchannel *sch)
+void cio_tsch(struct subchannel *sch)
{
struct irb *irb;
int irq_context;
@@ -675,6 +647,7 @@ static void cio_tsch(struct subchannel *sch)
local_bh_disable();
irq_enter();
}
+ kstat_incr_irqs_this_cpu(IO_INTERRUPT, NULL);
if (sch->driver && sch->driver->irq)
sch->driver->irq(sch);
else
@@ -685,135 +658,90 @@ static void cio_tsch(struct subchannel *sch)
}
}
-void *cio_get_console_priv(void)
-{
- return &console_priv;
-}
-
-/*
- * busy wait for the next interrupt on the console
- */
-void wait_cons_dev(void)
+static int cio_test_for_console(struct subchannel_id schid, void *data)
{
- if (!console_subchannel_in_use)
- return;
-
- while (1) {
- cio_tsch(&console_subchannel);
- if (console_subchannel.schib.scsw.cmd.actl == 0)
- break;
- udelay_simple(100);
- }
-}
+ struct schib schib;
-static int
-cio_test_for_console(struct subchannel_id schid, void *data)
-{
- if (stsch_err(schid, &console_subchannel.schib) != 0)
+ if (stsch_err(schid, &schib) != 0)
return -ENXIO;
- if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) &&
- console_subchannel.schib.pmcw.dnv &&
- (console_subchannel.schib.pmcw.dev == console_devno)) {
+ if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
+ (schib.pmcw.dev == console_devno)) {
console_irq = schid.sch_no;
return 1; /* found */
}
return 0;
}
-
-static int
-cio_get_console_sch_no(void)
+static int cio_get_console_sch_no(void)
{
struct subchannel_id schid;
-
+ struct schib schib;
+
init_subchannel_id(&schid);
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
schid.sch_no = console_irq;
- if (stsch_err(schid, &console_subchannel.schib) != 0 ||
- (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
- !console_subchannel.schib.pmcw.dnv)
+ if (stsch_err(schid, &schib) != 0 ||
+ (schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
return -1;
- console_devno = console_subchannel.schib.pmcw.dev;
+ console_devno = schib.pmcw.dev;
} else if (console_devno != -1) {
/* At least the console device number is known. */
for_each_subchannel(cio_test_for_console, NULL);
- if (console_irq == -1)
- return -1;
- } else {
- /* unlike in 2.4, we cannot autoprobe here, since
- * the channel subsystem is not fully initialized.
- * With some luck, the HWC console can take over */
- return -1;
}
return console_irq;
}
-struct subchannel *
-cio_probe_console(void)
+struct subchannel *cio_probe_console(void)
{
- int sch_no, ret;
struct subchannel_id schid;
+ struct subchannel *sch;
+ int sch_no, ret;
- if (xchg(&console_subchannel_in_use, 1) != 0)
- return ERR_PTR(-EBUSY);
sch_no = cio_get_console_sch_no();
if (sch_no == -1) {
- console_subchannel_in_use = 0;
pr_warning("No CCW console was found\n");
return ERR_PTR(-ENODEV);
}
- memset(&console_subchannel, 0, sizeof(struct subchannel));
init_subchannel_id(&schid);
schid.sch_no = sch_no;
- ret = cio_validate_subchannel(&console_subchannel, schid);
- if (ret) {
- console_subchannel_in_use = 0;
- return ERR_PTR(-ENODEV);
- }
+ sch = css_alloc_subchannel(schid);
+ if (IS_ERR(sch))
+ return sch;
- /*
- * enable console I/O-interrupt subclass
- */
isc_register(CONSOLE_ISC);
- console_subchannel.config.isc = CONSOLE_ISC;
- console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel;
- ret = cio_commit_config(&console_subchannel);
+ sch->config.isc = CONSOLE_ISC;
+ sch->config.intparm = (u32)(addr_t)sch;
+ ret = cio_commit_config(sch);
if (ret) {
isc_unregister(CONSOLE_ISC);
- console_subchannel_in_use = 0;
+ put_device(&sch->dev);
return ERR_PTR(ret);
}
- return &console_subchannel;
-}
-
-void
-cio_release_console(void)
-{
- console_subchannel.config.intparm = 0;
- cio_commit_config(&console_subchannel);
- isc_unregister(CONSOLE_ISC);
- console_subchannel_in_use = 0;
+ console_sch = sch;
+ return sch;
}
-/* Bah... hack to catch console special sausages. */
-int
-cio_is_console(struct subchannel_id schid)
+int cio_is_console(struct subchannel_id schid)
{
- if (!console_subchannel_in_use)
+ if (!console_sch)
return 0;
- return schid_equal(&schid, &console_subchannel.schid);
+ return schid_equal(&schid, &console_sch->schid);
}
-struct subchannel *
-cio_get_console_subchannel(void)
+void cio_register_early_subchannels(void)
{
- if (!console_subchannel_in_use)
- return NULL;
- return &console_subchannel;
+ int ret;
+
+ if (!console_sch)
+ return;
+
+ ret = css_register_subchannel(console_sch);
+ if (ret)
+ put_device(&console_sch->dev);
}
+#endif /* CONFIG_CCW_CONSOLE */
-#endif
static int
__disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
{
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 4a1ff5c2eb88..d62f5e7f3cf1 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -121,23 +121,18 @@ extern int cio_commit_config(struct subchannel *sch);
int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
int cio_tm_intrg(struct subchannel *sch);
-int cio_create_sch_lock(struct subchannel *);
void do_adapter_IO(u8 isc);
void do_IRQ(struct pt_regs *);
/* Use with care. */
#ifdef CONFIG_CCW_CONSOLE
extern struct subchannel *cio_probe_console(void);
-extern void cio_release_console(void);
extern int cio_is_console(struct subchannel_id);
-extern struct subchannel *cio_get_console_subchannel(void);
-extern spinlock_t * cio_get_console_lock(void);
-extern void *cio_get_console_priv(void);
+extern void cio_register_early_subchannels(void);
+extern void cio_tsch(struct subchannel *sch);
#else
#define cio_is_console(schid) 0
-#define cio_get_console_subchannel() NULL
-#define cio_get_console_lock() NULL
-#define cio_get_console_priv() NULL
+static inline void cio_register_early_subchannels(void) {}
#endif
#endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index a239237d43f3..1ebe5d3ddebb 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -137,37 +137,53 @@ out:
static void css_sch_todo(struct work_struct *work);
-static struct subchannel *
-css_alloc_subchannel(struct subchannel_id schid)
+static int css_sch_create_locks(struct subchannel *sch)
+{
+ sch->lock = kmalloc(sizeof(*sch->lock), GFP_KERNEL);
+ if (!sch->lock)
+ return -ENOMEM;
+
+ spin_lock_init(sch->lock);
+ mutex_init(&sch->reg_mutex);
+
+ return 0;
+}
+
+static void css_subchannel_release(struct device *dev)
+{
+ struct subchannel *sch = to_subchannel(dev);
+
+ sch->config.intparm = 0;
+ cio_commit_config(sch);
+ kfree(sch->lock);
+ kfree(sch);
+}
+
+struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
{
struct subchannel *sch;
int ret;
- sch = kmalloc (sizeof (*sch), GFP_KERNEL | GFP_DMA);
- if (sch == NULL)
+ sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
+ if (!sch)
return ERR_PTR(-ENOMEM);
- ret = cio_validate_subchannel (sch, schid);
- if (ret < 0) {
- kfree(sch);
- return ERR_PTR(ret);
- }
+
+ ret = cio_validate_subchannel(sch, schid);
+ if (ret < 0)
+ goto err;
+
+ ret = css_sch_create_locks(sch);
+ if (ret)
+ goto err;
+
INIT_WORK(&sch->todo_work, css_sch_todo);
+ sch->dev.release = &css_subchannel_release;
+ device_initialize(&sch->dev);
return sch;
-}
-
-static void
-css_subchannel_release(struct device *dev)
-{
- struct subchannel *sch;
- sch = to_subchannel(dev);
- if (!cio_is_console(sch->schid)) {
- /* Reset intparm to zeroes. */
- sch->config.intparm = 0;
- cio_commit_config(sch);
- kfree(sch->lock);
- kfree(sch);
- }
+err:
+ kfree(sch);
+ return ERR_PTR(ret);
}
static int css_sch_device_register(struct subchannel *sch)
@@ -177,7 +193,7 @@ static int css_sch_device_register(struct subchannel *sch)
mutex_lock(&sch->reg_mutex);
dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid,
sch->schid.sch_no);
- ret = device_register(&sch->dev);
+ ret = device_add(&sch->dev);
mutex_unlock(&sch->reg_mutex);
return ret;
}
@@ -228,16 +244,11 @@ void css_update_ssd_info(struct subchannel *sch)
{
int ret;
- if (cio_is_console(sch->schid)) {
- /* Console is initialized too early for functions requiring
- * memory allocation. */
+ ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
+ if (ret)
ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
- } else {
- ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
- if (ret)
- ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
- ssd_register_chpids(&sch->ssd_info);
- }
+
+ ssd_register_chpids(&sch->ssd_info);
}
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
@@ -275,14 +286,13 @@ static const struct attribute_group *default_subch_attr_groups[] = {
NULL,
};
-static int css_register_subchannel(struct subchannel *sch)
+int css_register_subchannel(struct subchannel *sch)
{
int ret;
/* Initialize the subchannel structure */
sch->dev.parent = &channel_subsystems[0]->device;
sch->dev.bus = &css_bus_type;
- sch->dev.release = &css_subchannel_release;
sch->dev.groups = default_subch_attr_groups;
/*
* We don't want to generate uevents for I/O subchannels that don't
@@ -314,23 +324,19 @@ static int css_register_subchannel(struct subchannel *sch)
return ret;
}
-int css_probe_device(struct subchannel_id schid)
+static int css_probe_device(struct subchannel_id schid)
{
- int ret;
struct subchannel *sch;
+ int ret;
+
+ sch = css_alloc_subchannel(schid);
+ if (IS_ERR(sch))
+ return PTR_ERR(sch);
- if (cio_is_console(schid))
- sch = cio_get_console_subchannel();
- else {
- sch = css_alloc_subchannel(schid);
- if (IS_ERR(sch))
- return PTR_ERR(sch);
- }
ret = css_register_subchannel(sch);
- if (ret) {
- if (!cio_is_console(schid))
- put_device(&sch->dev);
- }
+ if (ret)
+ put_device(&sch->dev);
+
return ret;
}
@@ -770,7 +776,7 @@ static int __init setup_css(int nr)
css->pseudo_subchannel->dev.release = css_subchannel_release;
dev_set_name(&css->pseudo_subchannel->dev, "defunct");
mutex_init(&css->pseudo_subchannel->reg_mutex);
- ret = cio_create_sch_lock(css->pseudo_subchannel);
+ ret = css_sch_create_locks(css->pseudo_subchannel);
if (ret) {
kfree(css->pseudo_subchannel);
return ret;
@@ -870,8 +876,7 @@ static struct notifier_block css_power_notifier = {
/*
* Now that the driver core is running, we can setup our channel subsystem.
- * The struct subchannel's are created during probing (except for the
- * static console subchannel).
+ * The struct subchannel's are created during probing.
*/
static int __init css_bus_init(void)
{
@@ -1050,6 +1055,8 @@ int css_complete_work(void)
*/
static int __init channel_subsystem_init_sync(void)
{
+ /* Register subchannels which are already in use. */
+ cio_register_early_subchannels();
/* Start initial subchannel evaluation. */
css_schedule_eval_all();
css_complete_work();
@@ -1065,9 +1072,8 @@ void channel_subsystem_reinit(void)
chsc_enable_facility(CHSC_SDA_OC_MSS);
chp_id_for_each(&chpid) {
chp = chpid_to_chp(chpid);
- if (!chp)
- continue;
- chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ if (chp)
+ chp_update_desc(chp);
}
}
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 4af3dfe70ef5..b1de60335238 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -101,7 +101,8 @@ extern int css_driver_register(struct css_driver *);
extern void css_driver_unregister(struct css_driver *);
extern void css_sch_device_unregister(struct subchannel *);
-extern int css_probe_device(struct subchannel_id);
+extern int css_register_subchannel(struct subchannel *);
+extern struct subchannel *css_alloc_subchannel(struct subchannel_id);
extern struct subchannel *get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int max_ssid;
@@ -109,7 +110,6 @@ int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
int (*fn_unknown)(struct subchannel_id,
void *), void *data);
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
-extern void css_reiterate_subchannels(void);
void css_update_ssd_info(struct subchannel *sch);
struct channel_subsystem {
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index c6767f5a58b2..1ab5f6c36d9b 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -19,6 +19,7 @@
#include <linux/list.h>
#include <linux/device.h>
#include <linux/workqueue.h>
+#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/kernel_stat.h>
@@ -43,6 +44,10 @@ static DEFINE_SPINLOCK(recovery_lock);
static int recovery_phase;
static const unsigned long recovery_delay[] = { 3, 30, 300 };
+static atomic_t ccw_device_init_count = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(ccw_device_init_wq);
+static struct bus_type ccw_bus_type;
+
/******************* bus type handling ***********************/
/* The Linux driver model distinguishes between a bus type and
@@ -127,8 +132,6 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
return ret;
}
-static struct bus_type ccw_bus_type;
-
static void io_subchannel_irq(struct subchannel *);
static int io_subchannel_probe(struct subchannel *);
static int io_subchannel_remove(struct subchannel *);
@@ -137,8 +140,6 @@ static int io_subchannel_sch_event(struct subchannel *, int);
static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
int);
static void recovery_func(unsigned long data);
-wait_queue_head_t ccw_device_init_wq;
-atomic_t ccw_device_init_count;
static struct css_device_id io_subchannel_ids[] = {
{ .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
@@ -191,10 +192,7 @@ int __init io_subchannel_init(void)
{
int ret;
- init_waitqueue_head(&ccw_device_init_wq);
- atomic_set(&ccw_device_init_count, 0);
setup_timer(&recovery_timer, recovery_func, 0);
-
ret = bus_register(&ccw_bus_type);
if (ret)
return ret;
@@ -1086,19 +1084,14 @@ static int io_subchannel_probe(struct subchannel *sch)
dev_set_uevent_suppress(&sch->dev, 0);
kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
cdev = sch_get_cdev(sch);
- cdev->dev.groups = ccwdev_attr_groups;
- device_initialize(&cdev->dev);
- cdev->private->flags.initialized = 1;
- ccw_device_register(cdev);
- /*
- * Check if the device is already online. If it is
- * the reference count needs to be corrected since we
- * didn't obtain a reference in ccw_device_set_online.
- */
- if (cdev->private->state != DEV_STATE_NOT_OPER &&
- cdev->private->state != DEV_STATE_OFFLINE &&
- cdev->private->state != DEV_STATE_BOXED)
- get_device(&cdev->dev);
+ rc = ccw_device_register(cdev);
+ if (rc) {
+ /* Release online reference. */
+ put_device(&cdev->dev);
+ goto out_schedule;
+ }
+ if (atomic_dec_and_test(&ccw_device_init_count))
+ wake_up(&ccw_device_init_wq);
return 0;
}
io_subchannel_init_fields(sch);
@@ -1580,88 +1573,102 @@ out:
}
#ifdef CONFIG_CCW_CONSOLE
-static struct ccw_device console_cdev;
-static struct ccw_device_private console_private;
-static int console_cdev_in_use;
-
-static DEFINE_SPINLOCK(ccw_console_lock);
-
-spinlock_t * cio_get_console_lock(void)
-{
- return &ccw_console_lock;
-}
-
static int ccw_device_console_enable(struct ccw_device *cdev,
struct subchannel *sch)
{
- struct io_subchannel_private *io_priv = cio_get_console_priv();
int rc;
- /* Attach subchannel private data. */
- memset(io_priv, 0, sizeof(*io_priv));
- set_io_private(sch, io_priv);
io_subchannel_init_fields(sch);
rc = cio_commit_config(sch);
if (rc)
return rc;
sch->driver = &io_subchannel_driver;
- /* Initialize the ccw_device structure. */
- cdev->dev.parent= &sch->dev;
sch_set_cdev(sch, cdev);
io_subchannel_recog(cdev, sch);
/* Now wait for the async. recognition to come to an end. */
spin_lock_irq(cdev->ccwlock);
while (!dev_fsm_final_state(cdev))
- wait_cons_dev();
- rc = -EIO;
- if (cdev->private->state != DEV_STATE_OFFLINE)
+ ccw_device_wait_idle(cdev);
+
+ /* Hold on to an extra reference while device is online. */
+ get_device(&cdev->dev);
+ rc = ccw_device_online(cdev);
+ if (rc)
goto out_unlock;
- ccw_device_online(cdev);
+
while (!dev_fsm_final_state(cdev))
- wait_cons_dev();
- if (cdev->private->state != DEV_STATE_ONLINE)
- goto out_unlock;
- rc = 0;
+ ccw_device_wait_idle(cdev);
+
+ if (cdev->private->state == DEV_STATE_ONLINE)
+ cdev->online = 1;
+ else
+ rc = -EIO;
out_unlock:
spin_unlock_irq(cdev->ccwlock);
+ if (rc) /* Give up online reference since onlining failed. */
+ put_device(&cdev->dev);
return rc;
}
-struct ccw_device *
-ccw_device_probe_console(void)
+struct ccw_device *ccw_device_probe_console(void)
{
+ struct io_subchannel_private *io_priv;
+ struct ccw_device *cdev;
struct subchannel *sch;
int ret;
- if (xchg(&console_cdev_in_use, 1) != 0)
- return ERR_PTR(-EBUSY);
sch = cio_probe_console();
- if (IS_ERR(sch)) {
- console_cdev_in_use = 0;
- return (void *) sch;
+ if (IS_ERR(sch))
+ return ERR_CAST(sch);
+
+ io_priv = kzalloc(sizeof(*io_priv), GFP_KERNEL | GFP_DMA);
+ if (!io_priv) {
+ put_device(&sch->dev);
+ return ERR_PTR(-ENOMEM);
}
- memset(&console_cdev, 0, sizeof(struct ccw_device));
- memset(&console_private, 0, sizeof(struct ccw_device_private));
- console_cdev.private = &console_private;
- console_private.cdev = &console_cdev;
- console_private.int_class = IRQIO_CIO;
- ret = ccw_device_console_enable(&console_cdev, sch);
+ cdev = io_subchannel_create_ccwdev(sch);
+ if (IS_ERR(cdev)) {
+ put_device(&sch->dev);
+ kfree(io_priv);
+ return cdev;
+ }
+ set_io_private(sch, io_priv);
+ ret = ccw_device_console_enable(cdev, sch);
if (ret) {
- cio_release_console();
- console_cdev_in_use = 0;
+ set_io_private(sch, NULL);
+ put_device(&sch->dev);
+ put_device(&cdev->dev);
+ kfree(io_priv);
return ERR_PTR(ret);
}
- console_cdev.online = 1;
- return &console_cdev;
+ return cdev;
+}
+
+/**
+ * ccw_device_wait_idle() - busy wait for device to become idle
+ * @cdev: ccw device
+ *
+ * Poll until activity control is zero, that is, no function or data
+ * transfer is pending/active.
+ * Called with device lock being held.
+ */
+void ccw_device_wait_idle(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ while (1) {
+ cio_tsch(sch);
+ if (sch->schib.scsw.cmd.actl == 0)
+ break;
+ udelay_simple(100);
+ }
}
static int ccw_device_pm_restore(struct device *dev);
-int ccw_device_force_console(void)
+int ccw_device_force_console(struct ccw_device *cdev)
{
- if (!console_cdev_in_use)
- return -ENODEV;
- return ccw_device_pm_restore(&console_cdev.dev);
+ return ccw_device_pm_restore(&cdev->dev);
}
EXPORT_SYMBOL_GPL(ccw_device_force_console);
#endif
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 7d4ecb65db00..8d1d29873172 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -81,8 +81,6 @@ dev_fsm_final_state(struct ccw_device *cdev)
cdev->private->state == DEV_STATE_BOXED);
}
-extern wait_queue_head_t ccw_device_init_wq;
-extern atomic_t ccw_device_init_count;
int __init io_subchannel_init(void);
void io_subchannel_recog_done(struct ccw_device *cdev);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index c77b6e06bf64..4845d64f2842 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -704,9 +704,9 @@ EXPORT_SYMBOL(ccw_device_tm_start_timeout);
int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
{
struct subchannel *sch = to_subchannel(cdev->dev.parent);
- struct channel_path_desc_fmt1 desc;
+ struct channel_path *chp;
struct chp_id chpid;
- int mdc = 0, ret, i;
+ int mdc = 0, i;
/* Adjust requested path mask to excluded varied off paths. */
if (mask)
@@ -719,14 +719,20 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
if (!(mask & (0x80 >> i)))
continue;
chpid.id = sch->schib.pmcw.chpid[i];
- ret = chsc_determine_fmt1_channel_path_desc(chpid, &desc);
- if (ret)
- return ret;
- if (!desc.f)
+ chp = chpid_to_chp(chpid);
+ if (!chp)
+ continue;
+
+ mutex_lock(&chp->lock);
+ if (!chp->desc_fmt1.f) {
+ mutex_unlock(&chp->lock);
return 0;
- if (!desc.r)
+ }
+ if (!chp->desc_fmt1.r)
mdc = 1;
- mdc = mdc ? min(mdc, (int)desc.mdc) : desc.mdc;
+ mdc = mdc ? min_t(int, mdc, chp->desc_fmt1.mdc) :
+ chp->desc_fmt1.mdc;
+ mutex_unlock(&chp->lock);
}
return mdc;
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
index 65d13e38803f..5a999084a229 100644
--- a/drivers/s390/cio/idset.c
+++ b/drivers/s390/cio/idset.c
@@ -17,7 +17,7 @@ struct idset {
static inline unsigned long bitmap_size(int num_ssid, int num_id)
{
- return __BITOPS_WORDS(num_ssid * num_id) * sizeof(unsigned long);
+ return BITS_TO_LONGS(num_ssid * num_id) * sizeof(unsigned long);
}
static struct idset *idset_new(int num_ssid, int num_id)
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index 2029b6caa595..fb877b59ec57 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -166,7 +166,7 @@ static void virtio_ccw_kvm_notify(struct virtqueue *vq)
vcdev = to_vc_device(info->vq->vdev);
ccw_device_get_schid(vcdev->cdev, &schid);
- do_kvm_notify(schid, virtqueue_get_queue_index(vq));
+ do_kvm_notify(schid, vq->index);
}
static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev,
@@ -188,7 +188,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
unsigned long flags;
unsigned long size;
int ret;
- unsigned int index = virtqueue_get_queue_index(vq);
+ unsigned int index = vq->index;
/* Remove from our list. */
spin_lock_irqsave(&vcdev->lock, flags);
@@ -610,7 +610,7 @@ static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev,
vq = NULL;
spin_lock_irqsave(&vcdev->lock, flags);
list_for_each_entry(info, &vcdev->virtqueues, node) {
- if (virtqueue_get_queue_index(info->vq) == index) {
+ if (info->vq->index == index) {
vq = info->vq;
break;
}
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 8c0622399fcd..c4f392d5db4c 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -769,6 +769,7 @@ struct qeth_card {
unsigned long thread_start_mask;
unsigned long thread_allowed_mask;
unsigned long thread_running_mask;
+ struct task_struct *recovery_task;
spinlock_t ip_lock;
struct list_head ip_list;
struct list_head *ip_tbd_list;
@@ -862,6 +863,8 @@ extern struct qeth_card_list_struct qeth_core_card_list;
extern struct kmem_cache *qeth_core_header_cache;
extern struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS];
+void qeth_set_recovery_task(struct qeth_card *);
+void qeth_clear_recovery_task(struct qeth_card *);
void qeth_set_allowed_threads(struct qeth_card *, unsigned long , int);
int qeth_threads_running(struct qeth_card *, unsigned long);
int qeth_wait_for_threads(struct qeth_card *, unsigned long);
@@ -915,7 +918,7 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
void *reply_param);
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
-int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
+int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int);
int qeth_get_elements_for_frags(struct sk_buff *);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int, int, int);
@@ -929,7 +932,7 @@ void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
void qeth_dbf_longtext(debug_info_t *id, int level, char *text, ...);
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
int qeth_set_access_ctrl_online(struct qeth_card *card, int fallback);
-int qeth_hdr_chk_and_bounce(struct sk_buff *, int);
+int qeth_hdr_chk_and_bounce(struct sk_buff *, struct qeth_hdr **, int);
int qeth_configure_cq(struct qeth_card *, enum qeth_cq);
int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 0d73a999983d..6cd0fc1b203a 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -177,6 +177,23 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
return "n/a";
}
+void qeth_set_recovery_task(struct qeth_card *card)
+{
+ card->recovery_task = current;
+}
+EXPORT_SYMBOL_GPL(qeth_set_recovery_task);
+
+void qeth_clear_recovery_task(struct qeth_card *card)
+{
+ card->recovery_task = NULL;
+}
+EXPORT_SYMBOL_GPL(qeth_clear_recovery_task);
+
+static bool qeth_is_recovery_task(const struct qeth_card *card)
+{
+ return card->recovery_task == current;
+}
+
void qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
int clear_start_mask)
{
@@ -205,6 +222,8 @@ EXPORT_SYMBOL_GPL(qeth_threads_running);
int qeth_wait_for_threads(struct qeth_card *card, unsigned long threads)
{
+ if (qeth_is_recovery_task(card))
+ return 0;
return wait_event_interruptible(card->wait_q,
qeth_threads_running(card, threads) == 0);
}
@@ -316,7 +335,7 @@ static inline int qeth_alloc_cq(struct qeth_card *card)
card->qdio.no_in_queues = 2;
- card->qdio.out_bufstates = (struct qdio_outbuf_state *)
+ card->qdio.out_bufstates =
kzalloc(card->qdio.no_out_queues *
QDIO_MAX_BUFFERS_PER_Q *
sizeof(struct qdio_outbuf_state), GFP_KERNEL);
@@ -3698,7 +3717,7 @@ int qeth_get_elements_for_frags(struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
-int qeth_get_elements_no(struct qeth_card *card, void *hdr,
+int qeth_get_elements_no(struct qeth_card *card,
struct sk_buff *skb, int elems)
{
int dlen = skb->len - skb->data_len;
@@ -3717,7 +3736,7 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
-int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
+int qeth_hdr_chk_and_bounce(struct sk_buff *skb, struct qeth_hdr **hdr, int len)
{
int hroom, inpage, rest;
@@ -3730,6 +3749,8 @@ int qeth_hdr_chk_and_bounce(struct sk_buff *skb, int len)
return 1;
memmove(skb->data - rest, skb->data, skb->len - skb->data_len);
skb->data -= rest;
+ skb->tail -= rest;
+ *hdr = (struct qeth_hdr *)skb->data;
QETH_DBF_MESSAGE(2, "skb bounce len: %d rest: %d\n", len, rest);
}
return 0;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index d690166efeaf..ec8ccdae7aba 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -302,7 +302,8 @@ static void qeth_l2_process_vlans(struct qeth_card *card)
spin_unlock_bh(&card->vlanlock);
}
-static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct qeth_card *card = dev->ml_priv;
struct qeth_vlan_vid *id;
@@ -331,7 +332,8 @@ static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct qeth_vlan_vid *id, *tmpid = NULL;
struct qeth_card *card = dev->ml_priv;
@@ -771,8 +773,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- elements = qeth_get_elements_no(card, (void *)hdr, new_skb,
- elements_needed);
+ elements = qeth_get_elements_no(card, new_skb, elements_needed);
if (!elements) {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
@@ -780,7 +781,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (card->info.type != QETH_CARD_TYPE_IQD) {
- if (qeth_hdr_chk_and_bounce(new_skb,
+ if (qeth_hdr_chk_and_bounce(new_skb, &hdr,
sizeof(struct qeth_hdr_layer2)))
goto tx_drop;
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
@@ -959,7 +960,7 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops);
else
SET_ETHTOOL_OPS(card->dev, &qeth_l2_osn_ops);
- card->dev->features |= NETIF_F_HW_VLAN_FILTER;
+ card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
card->info.broadcast_capable = 1;
qeth_l2_request_initial_mac(card);
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
@@ -1143,6 +1144,7 @@ static int qeth_l2_recover(void *ptr)
QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n");
+ qeth_set_recovery_task(card);
__qeth_l2_set_offline(card->gdev, 1);
rc = __qeth_l2_set_online(card->gdev, 1);
if (!rc)
@@ -1153,6 +1155,7 @@ static int qeth_l2_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
+ qeth_clear_recovery_task(card);
qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
return 0;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 8710337dab3e..c1b0b2761f8d 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1659,7 +1659,8 @@ static void qeth_l3_add_vlan_mc(struct qeth_card *card)
for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
struct net_device *netdev;
- netdev = __vlan_find_dev_deep(card->dev, vid);
+ netdev = __vlan_find_dev_deep(card->dev, htons(ETH_P_8021Q),
+ vid);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
continue;
@@ -1720,7 +1721,8 @@ static void qeth_l3_add_vlan_mc6(struct qeth_card *card)
for_each_set_bit(vid, card->active_vlans, VLAN_N_VID) {
struct net_device *netdev;
- netdev = __vlan_find_dev_deep(card->dev, vid);
+ netdev = __vlan_find_dev_deep(card->dev, htons(ETH_P_8021Q),
+ vid);
if (netdev == NULL ||
!(netdev->flags & IFF_UP))
continue;
@@ -1764,7 +1766,7 @@ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "frvaddr4");
- netdev = __vlan_find_dev_deep(card->dev, vid);
+ netdev = __vlan_find_dev_deep(card->dev, htons(ETH_P_8021Q), vid);
if (!netdev)
return;
in_dev = in_dev_get(netdev);
@@ -1794,7 +1796,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "frvaddr6");
- netdev = __vlan_find_dev_deep(card->dev, vid);
+ netdev = __vlan_find_dev_deep(card->dev, htons(ETH_P_8021Q), vid);
if (!netdev)
return;
in6_dev = in6_dev_get(netdev);
@@ -1824,7 +1826,8 @@ static void qeth_l3_free_vlan_addresses(struct qeth_card *card,
rcu_read_unlock();
}
-static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int qeth_l3_vlan_rx_add_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct qeth_card *card = dev->ml_priv;
@@ -1832,7 +1835,8 @@ static int qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
return 0;
}
-static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev,
+ __be16 proto, u16 vid)
{
struct qeth_card *card = dev->ml_priv;
unsigned long flags;
@@ -1975,7 +1979,8 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card,
&vlan_tag);
len = skb->len;
if (is_vlan && !card->options.sniffer)
- __vlan_hwaccel_put_tag(skb, vlan_tag);
+ __vlan_hwaccel_put_tag(skb,
+ htons(ETH_P_8021Q), vlan_tag);
napi_gro_receive(&card->napi, skb);
}
break;
@@ -2084,7 +2089,8 @@ static int qeth_l3_verify_vlan_dev(struct net_device *dev,
struct net_device *netdev;
rcu_read_lock();
- netdev = __vlan_find_dev_deep(card->dev, vid);
+ netdev = __vlan_find_dev_deep(card->dev, htons(ETH_P_8021Q),
+ vid);
rcu_read_unlock();
if (netdev == dev) {
rc = QETH_VLAN_CARD;
@@ -3031,8 +3037,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
qeth_l3_hdr_csum(card, hdr, new_skb);
}
- elems = qeth_get_elements_no(card, (void *)hdr, new_skb,
- elements_needed);
+ elems = qeth_get_elements_no(card, new_skb, elements_needed);
if (!elems) {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
@@ -3050,7 +3055,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
else
len = sizeof(struct qeth_hdr_layer3);
- if (qeth_hdr_chk_and_bounce(new_skb, len))
+ if (qeth_hdr_chk_and_bounce(new_skb, &hdr, len))
goto tx_drop;
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed);
@@ -3294,9 +3299,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
card->dev->mtu = card->info.initial_mtu;
SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops);
- card->dev->features |= NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ card->dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_CTAG_FILTER;
card->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
card->dev->gso_max_size = 15 * PAGE_SIZE;
@@ -3515,6 +3520,7 @@ static int qeth_l3_recover(void *ptr)
QETH_CARD_TEXT(card, 2, "recover2");
dev_warn(&card->gdev->dev,
"A recovery process has been started for the device\n");
+ qeth_set_recovery_task(card);
__qeth_l3_set_offline(card->gdev, 1);
rc = __qeth_l3_set_online(card->gdev, 1);
if (!rc)
@@ -3525,6 +3531,7 @@ static int qeth_l3_recover(void *ptr)
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
+ qeth_clear_recovery_task(card);
qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD);
return 0;
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 1a9d1e3ce64c..c1441ed282eb 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -282,7 +282,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
+static void reset_one_i2c(struct bbc_i2c_bus *bp)
{
writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
writeb(bp->own, bp->i2c_control_regs + 0x1);
@@ -291,7 +291,7 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
}
-static struct bbc_i2c_bus * __init attach_one_i2c(struct platform_device *op, int index)
+static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index)
{
struct bbc_i2c_bus *bp;
struct device_node *dp;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index a6f7190c09a4..9323d058706b 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 30000
+# define AAC_DRIVER_BUILD 30200
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -1918,6 +1918,10 @@ extern struct aac_common aac_config;
#define MONITOR_PANIC 0x00000020
#define KERNEL_UP_AND_RUNNING 0x00000080
#define KERNEL_PANIC 0x00000100
+#define FLASH_UPD_PENDING 0x00002000
+#define FLASH_UPD_SUCCESS 0x00004000
+#define FLASH_UPD_FAILED 0x00008000
+#define FWUPD_TIMEOUT (5 * 60)
/*
* Doorbell bit defines
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 3f759957f4b4..177b094c7792 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -214,7 +214,7 @@ int aac_send_shutdown(struct aac_dev * dev)
cmd = (struct aac_close *) fib_data(fibctx);
cmd->command = cpu_to_le32(VM_CloseAll);
- cmd->cid = cpu_to_le32(0xffffffff);
+ cmd->cid = cpu_to_le32(0xfffffffe);
status = aac_fib_send(ContainerCommand,
fibctx,
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index e2e349204e7d..0f56d8d7524f 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -703,6 +703,28 @@ int aac_srcv_init(struct aac_dev *dev)
!aac_src_restart_adapter(dev, 0))
++restart;
/*
+ * Check to see if flash update is running.
+ * Wait for the adapter to be up and running. Wait up to 5 minutes
+ */
+ status = src_readl(dev, MUnit.OMR);
+ if (status & FLASH_UPD_PENDING) {
+ start = jiffies;
+ do {
+ status = src_readl(dev, MUnit.OMR);
+ if (time_after(jiffies, start+HZ*FWUPD_TIMEOUT)) {
+ printk(KERN_ERR "%s%d: adapter flash update failed.\n",
+ dev->name, instance);
+ goto error_iounmap;
+ }
+ } while (!(status & FLASH_UPD_SUCCESS) &&
+ !(status & FLASH_UPD_FAILED));
+ /* Delay 10 seconds.
+ * Because right now FW is doing a soft reset,
+ * do not read scratch pad register at this time
+ */
+ ssleep(10);
+ }
+ /*
* Check to see if the board panic'd while booting.
*/
status = src_readl(dev, MUnit.OMR);
@@ -730,7 +752,9 @@ int aac_srcv_init(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
*/
- while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) {
+ while (!((status = src_readl(dev, MUnit.OMR)) &
+ KERNEL_UP_AND_RUNNING) ||
+ status == 0xffffffff) {
if ((restart &&
(status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
time_after(jiffies, start+HZ*startup_timeout)) {
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 214d691adb53..9014690fe841 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -369,7 +369,7 @@ beiscsi_set_vlan_tag(struct Scsi_Host *shost,
break;
default:
beiscsi_log(phba, KERN_WARNING, BEISCSI_LOG_CONFIG,
- "BS_%d : Unkown Param Type : %d\n",
+ "BS_%d : Unknown Param Type : %d\n",
iface_param->param);
return -ENOSYS;
}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index a6c2fe4b4d65..55cc9902263d 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1292,7 +1292,7 @@ beiscsi_adap_family_disp(struct device *dev, struct device_attribute *attr,
break;
default:
return snprintf(buf, PAGE_SIZE,
- "Unkown Adapter Family: 0x%x\n", dev_id);
+ "Unknown Adapter Family: 0x%x\n", dev_id);
break;
}
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 50fcd018d14b..11596b2c4702 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -88,9 +88,6 @@
#define BNX2FC_MAX_NPIV 256
-#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048
-#define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS
-#define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE
#define BNX2FC_MIN_PAYLOAD 256
#define BNX2FC_MAX_PAYLOAD 2048
#define BNX2FC_MFS \
@@ -108,11 +105,8 @@
#define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe))
#define BNX2FC_5771X_DB_PAGE_SIZE 128
-#define BNX2FC_MAX_TASKS \
- (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS)
#define BNX2FC_TASK_SIZE 128
#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE)
-#define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE)
#define BNX2FC_MAX_ROWS_IN_HASH_TBL 8
#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024)
@@ -125,12 +119,9 @@
#define BNX2FC_WRITE (1 << 0)
#define BNX2FC_MIN_XID 0
-#define BNX2FC_MAX_XID \
- (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1)
#define FCOE_MAX_NUM_XIDS 0x2000
-#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1)
-#define FCOE_MAX_XID (FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1)
-#define FCOE_XIDS_PER_CPU (FCOE_MIN_XID + (512 * nr_cpu_ids) - 1)
+#define FCOE_MAX_XID_OFFSET (FCOE_MAX_NUM_XIDS - 1)
+#define FCOE_XIDS_PER_CPU_OFFSET ((512 * nr_cpu_ids) - 1)
#define BNX2FC_MAX_LUN 0xFFFF
#define BNX2FC_MAX_FCP_TGT 256
#define BNX2FC_MAX_CMD_LEN 16
@@ -206,6 +197,13 @@ struct bnx2fc_hba {
#define BNX2FC_FLAG_FW_INIT_DONE 0
#define BNX2FC_FLAG_DESTROY_CMPL 1
u32 next_conn_id;
+
+ /* xid resources */
+ u16 max_xid;
+ u32 max_tasks;
+ u32 max_outstanding_cmds;
+ u32 elstm_xids;
+
struct fcoe_task_ctx_entry **task_ctx;
dma_addr_t *task_ctx_dma;
struct regpair *task_ctx_bd_tbl;
@@ -504,8 +502,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba);
void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba);
int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba);
void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba);
-struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
- u16 min_xid, u16 max_xid);
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba);
void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr);
void bnx2fc_get_link_state(struct bnx2fc_hba *hba);
char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 2daf4b0da434..7dffec1e5715 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -71,7 +71,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb);
static void bnx2fc_start_disc(struct bnx2fc_interface *interface);
static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev);
static int bnx2fc_lport_config(struct fc_lport *lport);
-static int bnx2fc_em_config(struct fc_lport *lport);
+static int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba);
static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba);
static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba);
static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba);
@@ -940,19 +940,21 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
fc_exch_init(lport);
fc_rport_init(lport);
fc_disc_init(lport);
+ fc_disc_config(lport, lport);
return 0;
}
-static int bnx2fc_em_config(struct fc_lport *lport)
+static int bnx2fc_em_config(struct fc_lport *lport, struct bnx2fc_hba *hba)
{
- int max_xid;
+ int fcoe_min_xid, fcoe_max_xid;
+ fcoe_min_xid = hba->max_xid + 1;
if (nr_cpu_ids <= 2)
- max_xid = FCOE_XIDS_PER_CPU;
+ fcoe_max_xid = hba->max_xid + FCOE_XIDS_PER_CPU_OFFSET;
else
- max_xid = FCOE_MAX_XID;
- if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID,
- max_xid, NULL)) {
+ fcoe_max_xid = hba->max_xid + FCOE_MAX_XID_OFFSET;
+ if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, fcoe_min_xid,
+ fcoe_max_xid, NULL)) {
printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n");
return -ENOMEM;
}
@@ -1299,6 +1301,12 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
mutex_init(&hba->hba_mutex);
hba->cnic = cnic;
+
+ hba->max_tasks = cnic->max_fcoe_exchanges;
+ hba->elstm_xids = (hba->max_tasks / 2);
+ hba->max_outstanding_cmds = hba->elstm_xids;
+ hba->max_xid = (hba->max_tasks - 1);
+
rc = bnx2fc_bind_pcidev(hba);
if (rc) {
printk(KERN_ERR PFX "create_adapter: bind error\n");
@@ -1317,8 +1325,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
hba->num_ofld_sess = 0;
- hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID,
- BNX2FC_MAX_XID);
+ hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba);
if (!hba->cmd_mgr) {
printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n");
goto cmgr_err;
@@ -1329,13 +1336,13 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic)
FCOE_IOS_PER_CONNECTION_SHIFT;
fcoe_cap->capability1 |= BNX2FC_NUM_MAX_SESS <<
FCOE_LOGINS_PER_PORT_SHIFT;
- fcoe_cap->capability2 = BNX2FC_MAX_OUTSTANDING_CMNDS <<
+ fcoe_cap->capability2 = hba->max_outstanding_cmds <<
FCOE_NUMBER_OF_EXCHANGES_SHIFT;
fcoe_cap->capability2 |= BNX2FC_MAX_NPIV <<
FCOE_NPIV_WWN_PER_PORT_SHIFT;
fcoe_cap->capability3 = BNX2FC_NUM_MAX_SESS <<
FCOE_TARGETS_SUPPORTED_SHIFT;
- fcoe_cap->capability3 |= BNX2FC_MAX_OUTSTANDING_CMNDS <<
+ fcoe_cap->capability3 |= hba->max_outstanding_cmds <<
FCOE_OUTSTANDING_COMMANDS_SHIFT;
fcoe_cap->capability4 = FCOE_CAPABILITY4_STATEFUL;
@@ -1415,7 +1422,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
struct Scsi_Host *shost;
struct fc_vport *vport = dev_to_vport(parent);
struct bnx2fc_lport *blport;
- struct bnx2fc_hba *hba;
+ struct bnx2fc_hba *hba = interface->hba;
int rc = 0;
blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
@@ -1425,6 +1432,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
}
/* Allocate Scsi_Host structure */
+ bnx2fc_shost_template.can_queue = hba->max_outstanding_cmds;
if (!npiv)
lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
else
@@ -1476,7 +1484,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
/* Allocate exchange manager */
if (!npiv)
- rc = bnx2fc_em_config(lport);
+ rc = bnx2fc_em_config(lport, hba);
else {
shost = vport_to_shost(vport);
n_port = shost_priv(shost);
@@ -1490,7 +1498,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
bnx2fc_interface_get(interface);
- hba = interface->hba;
spin_lock_bh(&hba->hba_lock);
blport->lport = lport;
list_add_tail(&blport->list, &hba->vports);
@@ -2133,6 +2140,7 @@ static int _bnx2fc_create(struct net_device *netdev,
}
ctlr = bnx2fc_to_ctlr(interface);
+ cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
interface->vlan_id = vlan_id;
interface->timer_work_queue =
@@ -2143,7 +2151,7 @@ static int _bnx2fc_create(struct net_device *netdev,
goto ifput_err;
}
- lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0);
+ lport = bnx2fc_if_create(interface, &cdev->dev, 0);
if (!lport) {
printk(KERN_ERR PFX "Failed to create interface (%s)\n",
netdev->name);
@@ -2159,8 +2167,6 @@ static int _bnx2fc_create(struct net_device *netdev,
/* Make this master N_port */
ctlr->lp = lport;
- cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
-
if (link_state == BNX2FC_CREATE_LINK_UP)
cdev->enabled = FCOE_CTLR_ENABLED;
else
@@ -2706,7 +2712,6 @@ static struct scsi_host_template bnx2fc_shost_template = {
.change_queue_type = fc_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
- .can_queue = BNX2FC_CAN_QUEUE,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
.max_sectors = 1024,
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 85ea98a80f40..50510ffe1bf5 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -77,7 +77,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba)
fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
- fcoe_init1.num_tasks = BNX2FC_MAX_TASKS;
+ fcoe_init1.num_tasks = hba->max_tasks;
fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX;
fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX;
fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ;
@@ -697,7 +697,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
- if (xid > BNX2FC_MAX_XID) {
+ if (xid > hba->max_xid) {
BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
xid);
goto ret_err_rqe;
@@ -815,7 +815,7 @@ ret_err_rqe:
BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
- if (xid > BNX2FC_MAX_XID) {
+ if (xid > hba->max_xid) {
BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid);
goto ret_warn_rqe;
}
@@ -880,7 +880,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe)
spin_lock_bh(&tgt->tgt_lock);
xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID;
- if (xid >= BNX2FC_MAX_TASKS) {
+ if (xid >= hba->max_tasks) {
printk(KERN_ERR PFX "ERROR:xid out of range\n");
spin_unlock_bh(&tgt->tgt_lock);
return;
@@ -1842,6 +1842,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
int rc = 0;
struct regpair *task_ctx_bdt;
dma_addr_t addr;
+ int task_ctx_arr_sz;
int i;
/*
@@ -1865,7 +1866,8 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
* Allocate task_ctx which is an array of pointers pointing to
* a page containing 32 task contexts
*/
- hba->task_ctx = kzalloc((BNX2FC_TASK_CTX_ARR_SZ * sizeof(void *)),
+ task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE);
+ hba->task_ctx = kzalloc((task_ctx_arr_sz * sizeof(void *)),
GFP_KERNEL);
if (!hba->task_ctx) {
printk(KERN_ERR PFX "unable to allocate task context array\n");
@@ -1876,7 +1878,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
/*
* Allocate task_ctx_dma which is an array of dma addresses
*/
- hba->task_ctx_dma = kmalloc((BNX2FC_TASK_CTX_ARR_SZ *
+ hba->task_ctx_dma = kmalloc((task_ctx_arr_sz *
sizeof(dma_addr_t)), GFP_KERNEL);
if (!hba->task_ctx_dma) {
printk(KERN_ERR PFX "unable to alloc context mapping array\n");
@@ -1885,7 +1887,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
}
task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl;
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev,
PAGE_SIZE,
@@ -1905,7 +1907,7 @@ int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba)
return 0;
out3:
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
if (hba->task_ctx[i]) {
dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
@@ -1929,6 +1931,7 @@ out:
void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba)
{
+ int task_ctx_arr_sz;
int i;
if (hba->task_ctx_bd_tbl) {
@@ -1938,8 +1941,9 @@ void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba)
hba->task_ctx_bd_tbl = NULL;
}
+ task_ctx_arr_sz = (hba->max_tasks / BNX2FC_TASKS_PER_PAGE);
if (hba->task_ctx) {
- for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) {
+ for (i = 0; i < task_ctx_arr_sz; i++) {
if (hba->task_ctx[i]) {
dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
hba->task_ctx[i],
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 60798e829de6..723a9a8ba5ee 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -239,8 +239,7 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code)
sc_cmd->scsi_done(sc_cmd);
}
-struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
- u16 min_xid, u16 max_xid)
+struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba)
{
struct bnx2fc_cmd_mgr *cmgr;
struct io_bdt *bdt_info;
@@ -252,6 +251,8 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
int num_ios, num_pri_ios;
size_t bd_tbl_sz;
int arr_sz = num_possible_cpus() + 1;
+ u16 min_xid = BNX2FC_MIN_XID;
+ u16 max_xid = hba->max_xid;
if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) {
printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \
@@ -298,7 +299,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba,
* of slow path requests.
*/
xid = BNX2FC_MIN_XID;
- num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS;
+ num_pri_ios = num_ios - hba->elstm_xids;
for (i = 0; i < num_ios; i++) {
io_req = kzalloc(sizeof(*io_req), GFP_KERNEL);
@@ -367,7 +368,7 @@ void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr)
struct bnx2fc_hba *hba = cmgr->hba;
size_t bd_tbl_sz;
u16 min_xid = BNX2FC_MIN_XID;
- u16 max_xid = BNX2FC_MAX_XID;
+ u16 max_xid = hba->max_xid;
int num_ios;
int i;
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index b44d04e41b0d..f109e3b073c3 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -580,8 +580,8 @@ struct bnx2i_5771x_dbell {
* @sq_mem_size: SQ size
* @sq_prod_qe: SQ producer entry pointer
* @sq_cons_qe: SQ consumer entry pointer
- * @sq_first_qe: virtaul address of first entry in SQ
- * @sq_last_qe: virtaul address of last entry in SQ
+ * @sq_first_qe: virtual address of first entry in SQ
+ * @sq_last_qe: virtual address of last entry in SQ
* @sq_prod_idx: SQ producer index
* @sq_cons_idx: SQ consumer index
* @sqe_left: number sq entry left
@@ -593,8 +593,8 @@ struct bnx2i_5771x_dbell {
* @cq_mem_size: CQ size
* @cq_prod_qe: CQ producer entry pointer
* @cq_cons_qe: CQ consumer entry pointer
- * @cq_first_qe: virtaul address of first entry in CQ
- * @cq_last_qe: virtaul address of last entry in CQ
+ * @cq_first_qe: virtual address of first entry in CQ
+ * @cq_last_qe: virtual address of last entry in CQ
* @cq_prod_idx: CQ producer index
* @cq_cons_idx: CQ consumer index
* @cqe_left: number cq entry left
@@ -608,8 +608,8 @@ struct bnx2i_5771x_dbell {
* @rq_mem_size: RQ size
* @rq_prod_qe: RQ producer entry pointer
* @rq_cons_qe: RQ consumer entry pointer
- * @rq_first_qe: virtaul address of first entry in RQ
- * @rq_last_qe: virtaul address of last entry in RQ
+ * @rq_first_qe: virtual address of first entry in RQ
+ * @rq_last_qe: virtual address of last entry in RQ
* @rq_prod_idx: RQ producer index
* @rq_cons_idx: RQ consumer index
* @rqe_left: number rq entry left
diff --git a/drivers/scsi/csiostor/Makefile b/drivers/scsi/csiostor/Makefile
index b581966c88f9..913b9a92fb06 100644
--- a/drivers/scsi/csiostor/Makefile
+++ b/drivers/scsi/csiostor/Makefile
@@ -8,4 +8,5 @@ ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor.o
csiostor-objs := csio_attr.o csio_init.o csio_lnode.o csio_scsi.o \
- csio_hw.o csio_isr.o csio_mb.o csio_rnode.o csio_wr.o
+ csio_hw.o csio_hw_t4.o csio_hw_t5.o csio_isr.o \
+ csio_mb.o csio_rnode.o csio_wr.o
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index bdd78fb4fc70..193605519361 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -61,7 +61,7 @@ int csio_msi = 2;
static int dev_num;
/* FCoE Adapter types & its description */
-static const struct csio_adap_desc csio_fcoe_adapters[] = {
+static const struct csio_adap_desc csio_t4_fcoe_adapters[] = {
{"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"},
{"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"},
{"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"},
@@ -77,7 +77,38 @@ static const struct csio_adap_desc csio_fcoe_adapters[] = {
{"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"},
{"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"},
{"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"},
- {"T4 FPGA", "Chelsio T4 FPGA [FCoE]"}
+ {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"},
+ {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"},
+ {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"},
+ {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"},
+ {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"},
+ {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"},
+ {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"},
+ {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"},
+ {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"}
+};
+
+static const struct csio_adap_desc csio_t5_fcoe_adapters[] = {
+ {"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"},
+ {"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"},
+ {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"},
+ {"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"},
+ {"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"},
+ {"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"},
+ {"T540-CH 10G", "Chelsio T540-CH 10G [FCoE]"},
+ {"T520-SO 10G", "Chelsio T520-SO 10G [FCoE]"},
+ {"T520-CX4 10G", "Chelsio T520-CX4 10G [FCoE]"},
+ {"T520-BT 10G", "Chelsio T520-BT 10G [FCoE]"},
+ {"T504-BT 1G", "Chelsio T504-BT 1G [FCoE]"},
+ {"B520-SR 10G", "Chelsio B520-SR 10G [FCoE]"},
+ {"B504-BT 1G", "Chelsio B504-BT 1G [FCoE]"},
+ {"T580-CR 10G", "Chelsio T580-CR 10G [FCoE]"},
+ {"T540-LP-CR 10G", "Chelsio T540-LP-CR 10G [FCoE]"},
+ {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"},
+ {"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"},
+ {"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"},
+ {"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"},
+ {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"}
};
static void csio_mgmtm_cleanup(struct csio_mgmtm *);
@@ -124,7 +155,7 @@ int csio_is_hw_removing(struct csio_hw *hw)
* at the time it indicated completion is stored there. Returns 0 if the
* operation completes and -EAGAIN otherwise.
*/
-static int
+int
csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask,
int polarity, int attempts, int delay, uint32_t *valp)
{
@@ -145,6 +176,24 @@ csio_hw_wait_op_done_val(struct csio_hw *hw, int reg, uint32_t mask,
}
}
+/*
+ * csio_hw_tp_wr_bits_indirect - set/clear bits in an indirect TP register
+ * @hw: the adapter
+ * @addr: the indirect TP register address
+ * @mask: specifies the field within the register to modify
+ * @val: new value for the field
+ *
+ * Sets a field of an indirect TP register to the given value.
+ */
+void
+csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr,
+ unsigned int mask, unsigned int val)
+{
+ csio_wr_reg32(hw, addr, TP_PIO_ADDR);
+ val |= csio_rd_reg32(hw, TP_PIO_DATA) & ~mask;
+ csio_wr_reg32(hw, val, TP_PIO_DATA);
+}
+
void
csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask,
uint32_t value)
@@ -157,242 +206,22 @@ csio_set_reg_field(struct csio_hw *hw, uint32_t reg, uint32_t mask,
}
-/*
- * csio_hw_mc_read - read from MC through backdoor accesses
- * @hw: the hw module
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from MC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int
-csio_hw_mc_read(struct csio_hw *hw, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
- csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
- csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
- csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
- MC_BIST_CMD);
- i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, MC_DATA(16));
-#undef MC_DATA
- return 0;
-}
-
-/*
- * csio_hw_edc_read - read from EDC through backdoor accesses
- * @hw: the hw module
- * @idx: which EDC to access
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-int
-csio_hw_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- idx *= EDC_STRIDE;
- if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
- csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
- csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
- csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
- EDC_BIST_CMD + idx);
- i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, EDC_DATA(16));
-#undef EDC_DATA
- return 0;
-}
-
-/*
- * csio_mem_win_rw - read/write memory through PCIE memory window
- * @hw: the adapter
- * @addr: address of first byte requested
- * @data: MEMWIN0_APERTURE bytes of data containing the requested address
- * @dir: direction of transfer 1 => read, 0 => write
- *
- * Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
- * MEMWIN0_APERTURE-byte-aligned address that covers the requested
- * address @addr.
- */
-static int
-csio_mem_win_rw(struct csio_hw *hw, u32 addr, u32 *data, int dir)
-{
- int i;
-
- /*
- * Setup offset into PCIE memory window. Address must be a
- * MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to
- * ensure that changes propagate before we attempt to use the new
- * values.)
- */
- csio_wr_reg32(hw, addr & ~(MEMWIN0_APERTURE - 1),
- PCIE_MEM_ACCESS_OFFSET);
- csio_rd_reg32(hw, PCIE_MEM_ACCESS_OFFSET);
-
- /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
- for (i = 0; i < MEMWIN0_APERTURE; i = i + sizeof(__be32)) {
- if (dir)
- *data++ = csio_rd_reg32(hw, (MEMWIN0_BASE + i));
- else
- csio_wr_reg32(hw, *data++, (MEMWIN0_BASE + i));
- }
-
- return 0;
-}
-
-/*
- * csio_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
- * @hw: the csio_hw
- * @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
- * @addr: address within indicated memory type
- * @len: amount of memory to transfer
- * @buf: host memory buffer
- * @dir: direction of transfer 1 => read, 0 => write
- *
- * Reads/writes an [almost] arbitrary memory region in the firmware: the
- * firmware memory address, length and host buffer must be aligned on
- * 32-bit boudaries. The memory is transferred as a raw byte sequence
- * from/to the firmware's memory. If this memory contains data
- * structures which contain multi-byte integers, it's the callers
- * responsibility to perform appropriate byte order conversions.
- */
-static int
-csio_memory_rw(struct csio_hw *hw, int mtype, u32 addr, u32 len,
- uint32_t *buf, int dir)
-{
- uint32_t pos, start, end, offset, memoffset;
- int ret;
- uint32_t *data;
-
- /*
- * Argument sanity checks ...
- */
- if ((addr & 0x3) || (len & 0x3))
- return -EINVAL;
-
- data = kzalloc(MEMWIN0_APERTURE, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- /* Offset into the region of memory which is being accessed
- * MEM_EDC0 = 0
- * MEM_EDC1 = 1
- * MEM_MC = 2
- */
- memoffset = (mtype * (5 * 1024 * 1024));
-
- /* Determine the PCIE_MEM_ACCESS_OFFSET */
- addr = addr + memoffset;
-
- /*
- * The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
- * at a time so we need to round down the start and round up the end.
- * We'll start copying out of the first line at (addr - start) a word
- * at a time.
- */
- start = addr & ~(MEMWIN0_APERTURE-1);
- end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
- offset = (addr - start)/sizeof(__be32);
-
- for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
- /*
- * If we're writing, copy the data from the caller's memory
- * buffer
- */
- if (!dir) {
- /*
- * If we're doing a partial write, then we need to do
- * a read-modify-write ...
- */
- if (offset || len < MEMWIN0_APERTURE) {
- ret = csio_mem_win_rw(hw, pos, data, 1);
- if (ret) {
- kfree(data);
- return ret;
- }
- }
- while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
- len > 0) {
- data[offset++] = *buf++;
- len -= sizeof(__be32);
- }
- }
-
- /*
- * Transfer a block of memory and bail if there's an error.
- */
- ret = csio_mem_win_rw(hw, pos, data, dir);
- if (ret) {
- kfree(data);
- return ret;
- }
-
- /*
- * If we're reading, copy the data into the caller's memory
- * buffer.
- */
- if (dir)
- while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
- len > 0) {
- *buf++ = data[offset++];
- len -= sizeof(__be32);
- }
- }
-
- kfree(data);
-
- return 0;
-}
-
static int
csio_memory_write(struct csio_hw *hw, int mtype, u32 addr, u32 len, u32 *buf)
{
- return csio_memory_rw(hw, mtype, addr, len, buf, 0);
+ return hw->chip_ops->chip_memory_rw(hw, MEMWIN_CSIOSTOR, mtype,
+ addr, len, buf, 0);
}
/*
* EEPROM reads take a few tens of us while writes can take a bit over 5 ms.
*/
-#define EEPROM_MAX_RD_POLL 40
-#define EEPROM_MAX_WR_POLL 6
-#define EEPROM_STAT_ADDR 0x7bfc
-#define VPD_BASE 0x400
-#define VPD_BASE_OLD 0
-#define VPD_LEN 512
+#define EEPROM_MAX_RD_POLL 40
+#define EEPROM_MAX_WR_POLL 6
+#define EEPROM_STAT_ADDR 0x7bfc
+#define VPD_BASE 0x400
+#define VPD_BASE_OLD 0
+#define VPD_LEN 1024
#define VPD_INFO_FLD_HDR_SIZE 3
/*
@@ -817,23 +646,6 @@ out:
return 0;
}
-/*
- * csio_hw_flash_cfg_addr - return the address of the flash
- * configuration file
- * @hw: the HW module
- *
- * Return the address within the flash where the Firmware Configuration
- * File is stored.
- */
-static unsigned int
-csio_hw_flash_cfg_addr(struct csio_hw *hw)
-{
- if (hw->params.sf_size == 0x100000)
- return FPGA_FLASH_CFG_OFFSET;
- else
- return FLASH_CFG_OFFSET;
-}
-
static void
csio_hw_print_fw_version(struct csio_hw *hw, char *str)
{
@@ -898,13 +710,13 @@ csio_hw_check_fw_version(struct csio_hw *hw)
minor = FW_HDR_FW_VER_MINOR_GET(hw->fwrev);
micro = FW_HDR_FW_VER_MICRO_GET(hw->fwrev);
- if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */
+ if (major != FW_VERSION_MAJOR(hw)) { /* major mismatch - fail */
csio_err(hw, "card FW has major version %u, driver wants %u\n",
- major, FW_VERSION_MAJOR);
+ major, FW_VERSION_MAJOR(hw));
return -EINVAL;
}
- if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO)
+ if (minor == FW_VERSION_MINOR(hw) && micro == FW_VERSION_MICRO(hw))
return 0; /* perfect match */
/* Minor/micro version mismatch */
@@ -1044,7 +856,7 @@ static void
csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
{
uint16_t val;
- uint32_t pcie_cap;
+ int pcie_cap;
if (!csio_pci_capability(hw->pdev, PCI_CAP_ID_EXP, &pcie_cap)) {
pci_read_config_word(hw->pdev,
@@ -1056,84 +868,6 @@ csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
}
}
-
-/*
- * Return the specified PCI-E Configuration Space register from our Physical
- * Function. We try first via a Firmware LDST Command since we prefer to let
- * the firmware own all of these registers, but if that fails we go for it
- * directly ourselves.
- */
-static uint32_t
-csio_read_pcie_cfg4(struct csio_hw *hw, int reg)
-{
- u32 val = 0;
- struct csio_mb *mbp;
- int rv;
- struct fw_ldst_cmd *ldst_cmd;
-
- mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
- if (!mbp) {
- CSIO_INC_STATS(hw, n_err_nomem);
- pci_read_config_dword(hw->pdev, reg, &val);
- return val;
- }
-
- csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
-
- rv = csio_mb_issue(hw, mbp);
-
- /*
- * If the LDST Command suucceeded, exctract the returned register
- * value. Otherwise read it directly ourself.
- */
- if (rv == 0) {
- ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
- val = ntohl(ldst_cmd->u.pcie.data[0]);
- } else
- pci_read_config_dword(hw->pdev, reg, &val);
-
- mempool_free(mbp, hw->mb_mempool);
-
- return val;
-} /* csio_read_pcie_cfg4 */
-
-static int
-csio_hw_set_mem_win(struct csio_hw *hw)
-{
- u32 bar0;
-
- /*
- * Truncation intentional: we only read the bottom 32-bits of the
- * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
- * read BAR0 instead of using pci_resource_start() because we could be
- * operating from within a Virtual Machine which is trapping our
- * accesses to our Configuration Space and we need to set up the PCI-E
- * Memory Window decoders with the actual addresses which will be
- * coming across the PCI-E link.
- */
- bar0 = csio_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
- bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
-
- /*
- * Set up memory window for accessing adapter memory ranges. (Read
- * back MA register to ensure that changes propagate before we attempt
- * to use the new values.)
- */
- csio_wr_reg32(hw, (bar0 + MEMWIN0_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN0_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0));
- csio_wr_reg32(hw, (bar0 + MEMWIN1_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN1_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1));
- csio_wr_reg32(hw, (bar0 + MEMWIN2_BASE) | BIR(0) |
- WINDOW(ilog2(MEMWIN2_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
- csio_rd_reg32(hw, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
- return 0;
-} /* csio_hw_set_mem_win */
-
-
-
/*****************************************************************************/
/* HW State machine assists */
/*****************************************************************************/
@@ -1234,7 +968,9 @@ retry:
for (;;) {
uint32_t pcie_fw;
+ spin_unlock_irq(&hw->lock);
msleep(50);
+ spin_lock_irq(&hw->lock);
waiting -= 50;
/*
@@ -2121,9 +1857,9 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
uint32_t *cfg_data;
int value_to_add = 0;
- if (request_firmware(&cf, CSIO_CF_FNAME, dev) < 0) {
- csio_err(hw, "could not find config file " CSIO_CF_FNAME
- ",err: %d\n", ret);
+ if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) {
+ csio_err(hw, "could not find config file %s, err: %d\n",
+ CSIO_CF_FNAME(hw), ret);
return -ENOENT;
}
@@ -2147,9 +1883,24 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
ret = csio_memory_write(hw, mtype, maddr,
cf->size + value_to_add, cfg_data);
+
+ if ((ret == 0) && (value_to_add != 0)) {
+ union {
+ u32 word;
+ char buf[4];
+ } last;
+ size_t size = cf->size & ~0x3;
+ int i;
+
+ last.word = cfg_data[size >> 2];
+ for (i = value_to_add; i < 4; i++)
+ last.buf[i] = 0;
+ ret = csio_memory_write(hw, mtype, maddr + size, 4, &last.word);
+ }
if (ret == 0) {
- csio_info(hw, "config file upgraded to " CSIO_CF_FNAME "\n");
- strncpy(path, "/lib/firmware/" CSIO_CF_FNAME, 64);
+ csio_info(hw, "config file upgraded to %s\n",
+ CSIO_CF_FNAME(hw));
+ snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw));
}
leave:
@@ -2179,7 +1930,7 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
{
unsigned int mtype, maddr;
int rv;
- uint32_t finiver, finicsum, cfcsum;
+ uint32_t finiver = 0, finicsum = 0, cfcsum = 0;
int using_flash;
char path[64];
@@ -2207,7 +1958,7 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
* config file from flash.
*/
mtype = FW_MEMTYPE_CF_FLASH;
- maddr = csio_hw_flash_cfg_addr(hw);
+ maddr = hw->chip_ops->chip_flash_cfg_addr(hw);
using_flash = 1;
} else {
/*
@@ -2346,30 +2097,32 @@ csio_hw_flash_fw(struct csio_hw *hw)
struct pci_dev *pci_dev = hw->pdev;
struct device *dev = &pci_dev->dev ;
- if (request_firmware(&fw, CSIO_FW_FNAME, dev) < 0) {
- csio_err(hw, "could not find firmware image " CSIO_FW_FNAME
- ",err: %d\n", ret);
+ if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) {
+ csio_err(hw, "could not find firmware image %s, err: %d\n",
+ CSIO_FW_FNAME(hw), ret);
return -EINVAL;
}
hdr = (const struct fw_hdr *)fw->data;
fw_ver = ntohl(hdr->fw_ver);
- if (FW_HDR_FW_VER_MAJOR_GET(fw_ver) != FW_VERSION_MAJOR)
+ if (FW_HDR_FW_VER_MAJOR_GET(fw_ver) != FW_VERSION_MAJOR(hw))
return -EINVAL; /* wrong major version, won't do */
/*
* If the flash FW is unusable or we found something newer, load it.
*/
- if (FW_HDR_FW_VER_MAJOR_GET(hw->fwrev) != FW_VERSION_MAJOR ||
+ if (FW_HDR_FW_VER_MAJOR_GET(hw->fwrev) != FW_VERSION_MAJOR(hw) ||
fw_ver > hw->fwrev) {
ret = csio_hw_fw_upgrade(hw, hw->pfn, fw->data, fw->size,
/*force=*/false);
if (!ret)
- csio_info(hw, "firmware upgraded to version %pI4 from "
- CSIO_FW_FNAME "\n", &hdr->fw_ver);
+ csio_info(hw,
+ "firmware upgraded to version %pI4 from %s\n",
+ &hdr->fw_ver, CSIO_FW_FNAME(hw));
else
csio_err(hw, "firmware upgrade failed! err=%d\n", ret);
- }
+ } else
+ ret = -EINVAL;
release_firmware(fw);
@@ -2410,7 +2163,7 @@ csio_hw_configure(struct csio_hw *hw)
/* Set pci completion timeout value to 4 seconds. */
csio_set_pcie_completion_timeout(hw, 0xd);
- csio_hw_set_mem_win(hw);
+ hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR);
rv = csio_hw_get_fw_version(hw, &hw->fwrev);
if (rv != 0)
@@ -2478,6 +2231,8 @@ csio_hw_configure(struct csio_hw *hw)
} else {
if (hw->fw_state == CSIO_DEV_STATE_INIT) {
+ hw->flags |= CSIO_HWF_USING_SOFT_PARAMS;
+
/* device parameters */
rv = csio_get_device_params(hw);
if (rv != 0)
@@ -2651,7 +2406,7 @@ csio_hw_intr_disable(struct csio_hw *hw)
}
-static void
+void
csio_hw_fatal_err(struct csio_hw *hw)
{
csio_set_reg_field(hw, SGE_CONTROL, GLOBALENABLE, 0);
@@ -2990,14 +2745,6 @@ csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt)
/* END: HW SM */
/*****************************************************************************/
-/* Slow path handlers */
-struct intr_info {
- unsigned int mask; /* bits to check in interrupt status */
- const char *msg; /* message to print or NULL */
- short stat_idx; /* stat counter to increment or -1 */
- unsigned short fatal; /* whether the condition reported is fatal */
-};
-
/*
* csio_handle_intr_status - table driven interrupt handler
* @hw: HW instance
@@ -3011,7 +2758,7 @@ struct intr_info {
* by an entry specifying mask 0. Returns the number of fatal interrupt
* conditions.
*/
-static int
+int
csio_handle_intr_status(struct csio_hw *hw, unsigned int reg,
const struct intr_info *acts)
{
@@ -3038,80 +2785,6 @@ csio_handle_intr_status(struct csio_hw *hw, unsigned int reg,
}
/*
- * Interrupt handler for the PCIE module.
- */
-static void
-csio_pcie_intr_handler(struct csio_hw *hw)
-{
- static struct intr_info sysbus_intr_info[] = {
- { RNPP, "RXNP array parity error", -1, 1 },
- { RPCP, "RXPC array parity error", -1, 1 },
- { RCIP, "RXCIF array parity error", -1, 1 },
- { RCCP, "Rx completions control array parity error", -1, 1 },
- { RFTP, "RXFT array parity error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_port_intr_info[] = {
- { TPCP, "TXPC array parity error", -1, 1 },
- { TNPP, "TXNP array parity error", -1, 1 },
- { TFTP, "TXFT array parity error", -1, 1 },
- { TCAP, "TXCA array parity error", -1, 1 },
- { TCIP, "TXCIF array parity error", -1, 1 },
- { RCAP, "RXCA array parity error", -1, 1 },
- { OTDD, "outbound request TLP discarded", -1, 1 },
- { RDPE, "Rx data parity error", -1, 1 },
- { TDUE, "Tx uncorrectable data error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_intr_info[] = {
- { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
- { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
- { MSIDATAPERR, "MSI data parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
- { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
- { MATAGPERR, "PCI MA tag parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
- { RXWRPERR, "PCI Rx write parity error", -1, 1 },
- { RPLPERR, "PCI replay buffer parity error", -1, 1 },
- { PCIESINT, "PCI core secondary fault", -1, 1 },
- { PCIEPINT, "PCI core primary fault", -1, 1 },
- { UNXSPLCPLERR, "PCI unexpected split completion error", -1,
- 0 },
- { 0, NULL, 0, 0 }
- };
-
- int fat;
-
- fat = csio_handle_intr_status(hw,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
- sysbus_intr_info) +
- csio_handle_intr_status(hw,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
- pcie_port_intr_info) +
- csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
- if (fat)
- csio_hw_fatal_err(hw);
-}
-
-/*
* TP interrupt handler.
*/
static void csio_tp_intr_handler(struct csio_hw *hw)
@@ -3517,7 +3190,7 @@ static void csio_ncsi_intr_handler(struct csio_hw *hw)
*/
static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
{
- uint32_t v = csio_rd_reg32(hw, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
+ uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port));
v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
if (!v)
@@ -3527,7 +3200,7 @@ static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port);
if (v & RXFIFO_PRTY_ERR)
csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port);
- csio_wr_reg32(hw, v, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
+ csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port));
csio_hw_fatal_err(hw);
}
@@ -3596,7 +3269,7 @@ csio_hw_slow_intr_handler(struct csio_hw *hw)
csio_xgmac_intr_handler(hw, 3);
if (cause & PCIE)
- csio_pcie_intr_handler(hw);
+ hw->chip_ops->chip_pcie_intr_handler(hw);
if (cause & MC)
csio_mem_intr_handler(hw, MEM_MC);
@@ -3892,7 +3565,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
struct csio_fl_dma_buf *flb, void *priv)
{
__u8 op;
- __be64 *data;
void *msg = NULL;
uint32_t msg_len = 0;
bool msg_sg = 0;
@@ -3908,8 +3580,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
msg = (void *) flb;
msg_len = flb->totlen;
msg_sg = 1;
-
- data = (__be64 *) msg;
} else if (op == CPL_FW6_MSG || op == CPL_FW4_MSG) {
CSIO_INC_STATS(hw, n_cpl_fw6_msg);
@@ -3917,8 +3587,6 @@ csio_process_fwevtq_entry(struct csio_hw *hw, void *wr, uint32_t len,
msg = (void *)((uintptr_t)wr + sizeof(__be64));
msg_len = (op == CPL_FW6_MSG) ? sizeof(struct cpl_fw6_msg) :
sizeof(struct cpl_fw4_msg);
-
- data = (__be64 *) msg;
} else {
csio_warn(hw, "unexpected CPL %#x on FW event queue\n", op);
CSIO_INC_STATS(hw, n_cpl_unexp);
@@ -4262,6 +3930,7 @@ csio_hw_get_device_id(struct csio_hw *hw)
&hw->params.pci.device_id);
csio_dev_id_cached(hw);
+ hw->chip_id = (hw->params.pci.device_id & CSIO_HW_CHIP_MASK);
} /* csio_hw_get_device_id */
@@ -4280,19 +3949,21 @@ csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id)
prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK);
adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK);
- if (prot_type == CSIO_FPGA) {
+ if (prot_type == CSIO_T4_FCOE_ASIC) {
+ memcpy(hw->hw_ver,
+ csio_t4_fcoe_adapters[adap_type].model_no, 16);
memcpy(hw->model_desc,
- csio_fcoe_adapters[13].description, 32);
- } else if (prot_type == CSIO_T4_FCOE_ASIC) {
+ csio_t4_fcoe_adapters[adap_type].description,
+ 32);
+ } else if (prot_type == CSIO_T5_FCOE_ASIC) {
memcpy(hw->hw_ver,
- csio_fcoe_adapters[adap_type].model_no, 16);
+ csio_t5_fcoe_adapters[adap_type].model_no, 16);
memcpy(hw->model_desc,
- csio_fcoe_adapters[adap_type].description, 32);
+ csio_t5_fcoe_adapters[adap_type].description,
+ 32);
} else {
char tempName[32] = "Chelsio FCoE Controller";
memcpy(hw->model_desc, tempName, 32);
-
- CSIO_DB_ASSERT(0);
}
}
} /* csio_hw_set_description */
@@ -4321,6 +3992,9 @@ csio_hw_init(struct csio_hw *hw)
strcpy(hw->name, CSIO_HW_NAME);
+ /* Initialize the HW chip ops with T4/T5 specific ops */
+ hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops;
+
/* Set the model & its description */
ven_id = hw->params.pci.vendor_id;
diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h
index 9edcca4c71af..489fc095cb03 100644
--- a/drivers/scsi/csiostor/csio_hw.h
+++ b/drivers/scsi/csiostor/csio_hw.h
@@ -48,6 +48,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_fc.h>
+#include "csio_hw_chip.h"
#include "csio_wr.h"
#include "csio_mb.h"
#include "csio_scsi.h"
@@ -60,13 +61,6 @@
*/
#define FW_HOSTERROR 255
-#define CSIO_FW_FNAME "cxgb4/t4fw.bin"
-#define CSIO_CF_FNAME "cxgb4/t4-config.txt"
-
-#define FW_VERSION_MAJOR 1
-#define FW_VERSION_MINOR 2
-#define FW_VERSION_MICRO 8
-
#define CSIO_HW_NAME "Chelsio FCoE Adapter"
#define CSIO_MAX_PFN 8
#define CSIO_MAX_PPORTS 4
@@ -123,8 +117,6 @@ extern int csio_msi;
#define CSIO_VENDOR_ID 0x1425
#define CSIO_ASIC_DEVID_PROTO_MASK 0xFF00
#define CSIO_ASIC_DEVID_TYPE_MASK 0x00FF
-#define CSIO_FPGA 0xA000
-#define CSIO_T4_FCOE_ASIC 0x4600
#define CSIO_GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
EDC1 | LE | TP | MA | PM_TX | PM_RX | \
@@ -207,17 +199,6 @@ enum {
SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */
};
-enum { MEM_EDC0, MEM_EDC1, MEM_MC };
-
-enum {
- MEMWIN0_APERTURE = 2048,
- MEMWIN0_BASE = 0x1b800,
- MEMWIN1_APERTURE = 32768,
- MEMWIN1_BASE = 0x28000,
- MEMWIN2_APERTURE = 65536,
- MEMWIN2_BASE = 0x30000,
-};
-
/* serial flash and firmware constants */
enum {
SF_ATTEMPTS = 10, /* max retries for SF operations */
@@ -239,9 +220,6 @@ enum {
FLASH_CFG_MAX_SIZE = 0x10000 , /* max size of the flash config file*/
FLASH_CFG_OFFSET = 0x1f0000,
FLASH_CFG_START_SEC = FLASH_CFG_OFFSET / SF_SEC_SIZE,
- FPGA_FLASH_CFG_OFFSET = 0xf0000 , /* if FPGA mode, then cfg file is
- * at 1MB - 64KB */
- FPGA_FLASH_CFG_START_SEC = FPGA_FLASH_CFG_OFFSET / SF_SEC_SIZE,
};
/*
@@ -259,6 +237,8 @@ enum {
FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
+ /* Location of Firmware Configuration File in FLASH. */
+ FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC),
};
#undef FLASH_START
@@ -310,7 +290,7 @@ struct csio_adap_desc {
struct pci_params {
uint16_t vendor_id;
uint16_t device_id;
- uint32_t vpd_cap_addr;
+ int vpd_cap_addr;
uint16_t speed;
uint8_t width;
};
@@ -513,6 +493,7 @@ struct csio_hw {
uint32_t fwrev;
uint32_t tp_vers;
char chip_ver;
+ uint16_t chip_id; /* Tells T4/T5 chip */
uint32_t cfg_finiver;
uint32_t cfg_finicsum;
uint32_t cfg_cfcsum;
@@ -556,6 +537,9 @@ struct csio_hw {
*/
struct csio_fcoe_res_info fres_info; /* Fcoe resource info */
+ struct csio_hw_chip_ops *chip_ops; /* T4/T5 Chip specific
+ * Operations
+ */
/* MSIX vectors */
struct csio_msix_entries msix_entries[CSIO_MAX_MSIX_VECS];
@@ -636,9 +620,16 @@ csio_us_to_core_ticks(struct csio_hw *hw, uint32_t us)
#define csio_dbg(__hw, __fmt, ...)
#endif
+int csio_hw_wait_op_done_val(struct csio_hw *, int, uint32_t, int,
+ int, int, uint32_t *);
+void csio_hw_tp_wr_bits_indirect(struct csio_hw *, unsigned int,
+ unsigned int, unsigned int);
int csio_mgmt_req_lookup(struct csio_mgmtm *, struct csio_ioreq *);
void csio_hw_intr_disable(struct csio_hw *);
-int csio_hw_slow_intr_handler(struct csio_hw *hw);
+int csio_hw_slow_intr_handler(struct csio_hw *);
+int csio_handle_intr_status(struct csio_hw *, unsigned int,
+ const struct intr_info *);
+
int csio_hw_start(struct csio_hw *);
int csio_hw_stop(struct csio_hw *);
int csio_hw_reset(struct csio_hw *);
@@ -647,19 +638,17 @@ int csio_is_hw_removing(struct csio_hw *);
int csio_fwevtq_handler(struct csio_hw *);
void csio_evtq_worker(struct work_struct *);
-int csio_enqueue_evt(struct csio_hw *hw, enum csio_evt type,
- void *evt_msg, uint16_t len);
+int csio_enqueue_evt(struct csio_hw *, enum csio_evt, void *, uint16_t);
void csio_evtq_flush(struct csio_hw *hw);
int csio_request_irqs(struct csio_hw *);
void csio_intr_enable(struct csio_hw *);
void csio_intr_disable(struct csio_hw *, bool);
+void csio_hw_fatal_err(struct csio_hw *);
struct csio_lnode *csio_lnode_alloc(struct csio_hw *);
int csio_config_queues(struct csio_hw *);
-int csio_hw_mc_read(struct csio_hw *, uint32_t, __be32 *, uint64_t *);
-int csio_hw_edc_read(struct csio_hw *, int, uint32_t, __be32 *, uint64_t *);
int csio_hw_init(struct csio_hw *);
void csio_hw_exit(struct csio_hw *);
#endif /* ifndef __CSIO_HW_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw_chip.h b/drivers/scsi/csiostor/csio_hw_chip.h
new file mode 100644
index 000000000000..bca0de61ae80
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_chip.h
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 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
+ * 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 __CSIO_HW_CHIP_H__
+#define __CSIO_HW_CHIP_H__
+
+#include "csio_defs.h"
+
+/* FCoE device IDs for T4 */
+#define CSIO_DEVID_T440DBG_FCOE 0x4600
+#define CSIO_DEVID_T420CR_FCOE 0x4601
+#define CSIO_DEVID_T422CR_FCOE 0x4602
+#define CSIO_DEVID_T440CR_FCOE 0x4603
+#define CSIO_DEVID_T420BCH_FCOE 0x4604
+#define CSIO_DEVID_T440BCH_FCOE 0x4605
+#define CSIO_DEVID_T440CH_FCOE 0x4606
+#define CSIO_DEVID_T420SO_FCOE 0x4607
+#define CSIO_DEVID_T420CX_FCOE 0x4608
+#define CSIO_DEVID_T420BT_FCOE 0x4609
+#define CSIO_DEVID_T404BT_FCOE 0x460A
+#define CSIO_DEVID_B420_FCOE 0x460B
+#define CSIO_DEVID_B404_FCOE 0x460C
+#define CSIO_DEVID_T480CR_FCOE 0x460D
+#define CSIO_DEVID_T440LPCR_FCOE 0x460E
+#define CSIO_DEVID_AMSTERDAM_T4_FCOE 0x460F
+#define CSIO_DEVID_HUAWEI_T480_FCOE 0x4680
+#define CSIO_DEVID_HUAWEI_T440_FCOE 0x4681
+#define CSIO_DEVID_HUAWEI_STG310_FCOE 0x4682
+#define CSIO_DEVID_ACROMAG_XMC_XAUI 0x4683
+#define CSIO_DEVID_ACROMAG_XMC_SFP_FCOE 0x4684
+#define CSIO_DEVID_QUANTA_MEZZ_SFP_FCOE 0x4685
+#define CSIO_DEVID_HUAWEI_10GT_FCOE 0x4686
+#define CSIO_DEVID_HUAWEI_T440_TOE_FCOE 0x4687
+
+/* FCoE device IDs for T5 */
+#define CSIO_DEVID_T580DBG_FCOE 0x5600
+#define CSIO_DEVID_T520CR_FCOE 0x5601
+#define CSIO_DEVID_T522CR_FCOE 0x5602
+#define CSIO_DEVID_T540CR_FCOE 0x5603
+#define CSIO_DEVID_T520BCH_FCOE 0x5604
+#define CSIO_DEVID_T540BCH_FCOE 0x5605
+#define CSIO_DEVID_T540CH_FCOE 0x5606
+#define CSIO_DEVID_T520SO_FCOE 0x5607
+#define CSIO_DEVID_T520CX_FCOE 0x5608
+#define CSIO_DEVID_T520BT_FCOE 0x5609
+#define CSIO_DEVID_T504BT_FCOE 0x560A
+#define CSIO_DEVID_B520_FCOE 0x560B
+#define CSIO_DEVID_B504_FCOE 0x560C
+#define CSIO_DEVID_T580CR2_FCOE 0x560D
+#define CSIO_DEVID_T540LPCR_FCOE 0x560E
+#define CSIO_DEVID_AMSTERDAM_T5_FCOE 0x560F
+#define CSIO_DEVID_T580LPCR_FCOE 0x5610
+#define CSIO_DEVID_T520LLCR_FCOE 0x5611
+#define CSIO_DEVID_T560CR_FCOE 0x5612
+#define CSIO_DEVID_T580CR_FCOE 0x5613
+
+/* Define MACRO values */
+#define CSIO_HW_T4 0x4000
+#define CSIO_T4_FCOE_ASIC 0x4600
+#define CSIO_HW_T5 0x5000
+#define CSIO_T5_FCOE_ASIC 0x5600
+#define CSIO_HW_CHIP_MASK 0xF000
+#define T4_REGMAP_SIZE (160 * 1024)
+#define T5_REGMAP_SIZE (332 * 1024)
+#define FW_FNAME_T4 "cxgb4/t4fw.bin"
+#define FW_FNAME_T5 "cxgb4/t5fw.bin"
+#define FW_CFG_NAME_T4 "cxgb4/t4-config.txt"
+#define FW_CFG_NAME_T5 "cxgb4/t5-config.txt"
+
+/* Define static functions */
+static inline int csio_is_t4(uint16_t chip)
+{
+ return (chip == CSIO_HW_T4);
+}
+
+static inline int csio_is_t5(uint16_t chip)
+{
+ return (chip == CSIO_HW_T5);
+}
+
+/* Define MACRO DEFINITIONS */
+#define CSIO_DEVICE(devid, idx) \
+ { PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
+
+#define CSIO_HW_PIDX(hw, index) \
+ (csio_is_t4(hw->chip_id) ? (PIDX(index)) : \
+ (PIDX_T5(index) | DBTYPE(1U)))
+
+#define CSIO_HW_LP_INT_THRESH(hw, val) \
+ (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH(val)) : \
+ (V_LP_INT_THRESH_T5(val)))
+
+#define CSIO_HW_M_LP_INT_THRESH(hw) \
+ (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH_MASK) : (M_LP_INT_THRESH_T5))
+
+#define CSIO_MAC_INT_CAUSE_REG(hw, port) \
+ (csio_is_t4(hw->chip_id) ? (PORT_REG(port, XGMAC_PORT_INT_CAUSE)) : \
+ (T5_PORT_REG(port, MAC_PORT_INT_CAUSE)))
+
+#define FW_VERSION_MAJOR(hw) (csio_is_t4(hw->chip_id) ? 1 : 0)
+#define FW_VERSION_MINOR(hw) (csio_is_t4(hw->chip_id) ? 2 : 0)
+#define FW_VERSION_MICRO(hw) (csio_is_t4(hw->chip_id) ? 8 : 0)
+
+#define CSIO_FW_FNAME(hw) \
+ (csio_is_t4(hw->chip_id) ? FW_FNAME_T4 : FW_FNAME_T5)
+
+#define CSIO_CF_FNAME(hw) \
+ (csio_is_t4(hw->chip_id) ? FW_CFG_NAME_T4 : FW_CFG_NAME_T5)
+
+/* Declare ENUMS */
+enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 };
+
+enum {
+ MEMWIN_APERTURE = 2048,
+ MEMWIN_BASE = 0x1b800,
+ MEMWIN_CSIOSTOR = 6, /* PCI-e Memory Window access */
+};
+
+/* Slow path handlers */
+struct intr_info {
+ unsigned int mask; /* bits to check in interrupt status */
+ const char *msg; /* message to print or NULL */
+ short stat_idx; /* stat counter to increment or -1 */
+ unsigned short fatal; /* whether the condition reported is fatal */
+};
+
+/* T4/T5 Chip specific ops */
+struct csio_hw;
+struct csio_hw_chip_ops {
+ int (*chip_set_mem_win)(struct csio_hw *, uint32_t);
+ void (*chip_pcie_intr_handler)(struct csio_hw *);
+ uint32_t (*chip_flash_cfg_addr)(struct csio_hw *);
+ int (*chip_mc_read)(struct csio_hw *, int, uint32_t,
+ __be32 *, uint64_t *);
+ int (*chip_edc_read)(struct csio_hw *, int, uint32_t,
+ __be32 *, uint64_t *);
+ int (*chip_memory_rw)(struct csio_hw *, u32, int, u32,
+ u32, uint32_t *, int);
+ void (*chip_dfs_create_ext_mem)(struct csio_hw *);
+};
+
+extern struct csio_hw_chip_ops t4_ops;
+extern struct csio_hw_chip_ops t5_ops;
+
+#endif /* #ifndef __CSIO_HW_CHIP_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw_t4.c b/drivers/scsi/csiostor/csio_hw_t4.c
new file mode 100644
index 000000000000..89ecbac5478f
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_t4.c
@@ -0,0 +1,403 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 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
+ * 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
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "csio_hw.h"
+#include "csio_init.h"
+
+/*
+ * Return the specified PCI-E Configuration Space register from our Physical
+ * Function. We try first via a Firmware LDST Command since we prefer to let
+ * the firmware own all of these registers, but if that fails we go for it
+ * directly ourselves.
+ */
+static uint32_t
+csio_t4_read_pcie_cfg4(struct csio_hw *hw, int reg)
+{
+ u32 val = 0;
+ struct csio_mb *mbp;
+ int rv;
+ struct fw_ldst_cmd *ldst_cmd;
+
+ mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+ if (!mbp) {
+ CSIO_INC_STATS(hw, n_err_nomem);
+ pci_read_config_dword(hw->pdev, reg, &val);
+ return val;
+ }
+
+ csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
+ rv = csio_mb_issue(hw, mbp);
+
+ /*
+ * If the LDST Command suucceeded, exctract the returned register
+ * value. Otherwise read it directly ourself.
+ */
+ if (rv == 0) {
+ ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
+ val = ntohl(ldst_cmd->u.pcie.data[0]);
+ } else
+ pci_read_config_dword(hw->pdev, reg, &val);
+
+ mempool_free(mbp, hw->mb_mempool);
+
+ return val;
+}
+
+static int
+csio_t4_set_mem_win(struct csio_hw *hw, uint32_t win)
+{
+ u32 bar0;
+ u32 mem_win_base;
+
+ /*
+ * Truncation intentional: we only read the bottom 32-bits of the
+ * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
+ * read BAR0 instead of using pci_resource_start() because we could be
+ * operating from within a Virtual Machine which is trapping our
+ * accesses to our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will be
+ * coming across the PCI-E link.
+ */
+ bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
+ bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ mem_win_base = bar0 + MEMWIN_BASE;
+
+ /*
+ * Set up memory window for accessing adapter memory ranges. (Read
+ * back MA register to ensure that changes propagate before we attempt
+ * to use the new values.)
+ */
+ csio_wr_reg32(hw, mem_win_base | BIR(0) |
+ WINDOW(ilog2(MEMWIN_APERTURE) - 10),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ return 0;
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void
+csio_t4_pcie_intr_handler(struct csio_hw *hw)
+{
+ static struct intr_info sysbus_intr_info[] = {
+ { RNPP, "RXNP array parity error", -1, 1 },
+ { RPCP, "RXPC array parity error", -1, 1 },
+ { RCIP, "RXCIF array parity error", -1, 1 },
+ { RCCP, "Rx completions control array parity error", -1, 1 },
+ { RFTP, "RXFT array parity error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+ static struct intr_info pcie_port_intr_info[] = {
+ { TPCP, "TXPC array parity error", -1, 1 },
+ { TNPP, "TXNP array parity error", -1, 1 },
+ { TFTP, "TXFT array parity error", -1, 1 },
+ { TCAP, "TXCA array parity error", -1, 1 },
+ { TCIP, "TXCIF array parity error", -1, 1 },
+ { RCAP, "RXCA array parity error", -1, 1 },
+ { OTDD, "outbound request TLP discarded", -1, 1 },
+ { RDPE, "Rx data parity error", -1, 1 },
+ { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+
+ static struct intr_info pcie_intr_info[] = {
+ { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
+ { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
+ { MSIDATAPERR, "MSI data parity error", -1, 1 },
+ { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
+ { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
+ { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
+ { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
+ { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
+ { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
+ { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR, "PCI FID parity error", -1, 1 },
+ { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
+ { MATAGPERR, "PCI MA tag parity error", -1, 1 },
+ { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
+ { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
+ { RXWRPERR, "PCI Rx write parity error", -1, 1 },
+ { RPLPERR, "PCI replay buffer parity error", -1, 1 },
+ { PCIESINT, "PCI core secondary fault", -1, 1 },
+ { PCIEPINT, "PCI core primary fault", -1, 1 },
+ { UNXSPLCPLERR, "PCI unexpected split completion error", -1,
+ 0 },
+ { 0, NULL, 0, 0 }
+ };
+
+ int fat;
+ fat = csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+ sysbus_intr_info) +
+ csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+ pcie_port_intr_info) +
+ csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
+ if (fat)
+ csio_hw_fatal_err(hw);
+}
+
+/*
+ * csio_t4_flash_cfg_addr - return the address of the flash configuration file
+ * @hw: the HW module
+ *
+ * Return the address within the flash where the Firmware Configuration
+ * File is stored.
+ */
+static unsigned int
+csio_t4_flash_cfg_addr(struct csio_hw *hw)
+{
+ return FLASH_CFG_OFFSET;
+}
+
+/*
+ * csio_t4_mc_read - read from MC through backdoor accesses
+ * @hw: the hw module
+ * @idx: not used for T4 adapter
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from MC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t4_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+
+ if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
+ csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
+ csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ MC_BIST_CMD);
+ i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, MC_DATA(16));
+#undef MC_DATA
+ return 0;
+}
+
+/*
+ * csio_t4_edc_read - read from EDC through backdoor accesses
+ * @hw: the hw module
+ * @idx: which EDC to access
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t4_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+
+ idx *= EDC_STRIDE;
+ if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
+ csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
+ csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
+ EDC_BIST_CMD + idx);
+ i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, EDC_DATA(16));
+#undef EDC_DATA
+ return 0;
+}
+
+/*
+ * csio_t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ * @hw: the csio_hw
+ * @win: PCI-E memory Window to use
+ * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
+ * @addr: address within indicated memory type
+ * @len: amount of memory to transfer
+ * @buf: host memory buffer
+ * @dir: direction of transfer 1 => read, 0 => write
+ *
+ * Reads/writes an [almost] arbitrary memory region in the firmware: the
+ * firmware memory address, length and host buffer must be aligned on
+ * 32-bit boudaries. The memory is transferred as a raw byte sequence
+ * from/to the firmware's memory. If this memory contains data
+ * structures which contain multi-byte integers, it's the callers
+ * responsibility to perform appropriate byte order conversions.
+ */
+static int
+csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
+ u32 len, uint32_t *buf, int dir)
+{
+ u32 pos, start, offset, memoffset, bar0;
+ u32 edc_size, mc_size, mem_reg, mem_aperture, mem_base;
+
+ /*
+ * Argument sanity checks ...
+ */
+ if ((addr & 0x3) || (len & 0x3))
+ return -EINVAL;
+
+ /* Offset into the region of memory which is being accessed
+ * MEM_EDC0 = 0
+ * MEM_EDC1 = 1
+ * MEM_MC = 2 -- T4
+ */
+ edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ if (mtype != MEM_MC1)
+ memoffset = (mtype * (edc_size * 1024 * 1024));
+ else {
+ mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR));
+ memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+ }
+
+ /* Determine the PCIE_MEM_ACCESS_OFFSET */
+ addr = addr + memoffset;
+
+ /*
+ * Each PCI-E Memory Window is programmed with a window size -- or
+ * "aperture" -- which controls the granularity of its mapping onto
+ * adapter memory. We need to grab that aperture in order to know
+ * how to use the specified window. The window is also programmed
+ * with the base address of the Memory Window in BAR0's address
+ * space. For T4 this is an absolute PCI-E Bus Address. For T5
+ * the address is relative to BAR0.
+ */
+ mem_reg = csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ mem_aperture = 1 << (WINDOW(mem_reg) + 10);
+ mem_base = GET_PCIEOFST(mem_reg) << 10;
+
+ bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
+ bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
+ mem_base -= bar0;
+
+ start = addr & ~(mem_aperture-1);
+ offset = addr - start;
+
+ csio_dbg(hw, "csio_t4_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
+ mem_reg, mem_aperture);
+ csio_dbg(hw, "csio_t4_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
+ mem_base, memoffset);
+ csio_dbg(hw, "csio_t4_memory_rw: bar0: 0x%x, start:0x%x, offset:0x%x\n",
+ bar0, start, offset);
+ csio_dbg(hw, "csio_t4_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
+ mtype, addr, len);
+
+ for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
+ /*
+ * Move PCI-E Memory Window to our current transfer
+ * position. Read it back to ensure that changes propagate
+ * before we attempt to use the new value.
+ */
+ csio_wr_reg32(hw, pos,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+
+ while (offset < mem_aperture && len > 0) {
+ if (dir)
+ *buf++ = csio_rd_reg32(hw, mem_base + offset);
+ else
+ csio_wr_reg32(hw, *buf++, mem_base + offset);
+
+ offset += sizeof(__be32);
+ len -= sizeof(__be32);
+ }
+ }
+ return 0;
+}
+
+/*
+ * csio_t4_dfs_create_ext_mem - setup debugfs for MC to read the values
+ * @hw: the csio_hw
+ *
+ * This function creates files in the debugfs with external memory region MC.
+ */
+static void
+csio_t4_dfs_create_ext_mem(struct csio_hw *hw)
+{
+ u32 size;
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
+ if (i & EXT_MEM_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ csio_add_debugfs_mem(hw, "mc", MEM_MC,
+ EXT_MEM_SIZE_GET(size));
+ }
+}
+
+/* T4 adapter specific function */
+struct csio_hw_chip_ops t4_ops = {
+ .chip_set_mem_win = csio_t4_set_mem_win,
+ .chip_pcie_intr_handler = csio_t4_pcie_intr_handler,
+ .chip_flash_cfg_addr = csio_t4_flash_cfg_addr,
+ .chip_mc_read = csio_t4_mc_read,
+ .chip_edc_read = csio_t4_edc_read,
+ .chip_memory_rw = csio_t4_memory_rw,
+ .chip_dfs_create_ext_mem = csio_t4_dfs_create_ext_mem,
+};
diff --git a/drivers/scsi/csiostor/csio_hw_t5.c b/drivers/scsi/csiostor/csio_hw_t5.c
new file mode 100644
index 000000000000..27745c170c24
--- /dev/null
+++ b/drivers/scsi/csiostor/csio_hw_t5.c
@@ -0,0 +1,397 @@
+/*
+ * This file is part of the Chelsio FCoE driver for Linux.
+ *
+ * Copyright (c) 2008-2013 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
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "csio_hw.h"
+#include "csio_init.h"
+
+static int
+csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win)
+{
+ u32 mem_win_base;
+ /*
+ * Truncation intentional: we only read the bottom 32-bits of the
+ * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
+ * read BAR0 instead of using pci_resource_start() because we could be
+ * operating from within a Virtual Machine which is trapping our
+ * accesses to our Configuration Space and we need to set up the PCI-E
+ * Memory Window decoders with the actual addresses which will be
+ * coming across the PCI-E link.
+ */
+
+ /* For T5, only relative offset inside the PCIe BAR is passed */
+ mem_win_base = MEMWIN_BASE;
+
+ /*
+ * Set up memory window for accessing adapter memory ranges. (Read
+ * back MA register to ensure that changes propagate before we attempt
+ * to use the new values.)
+ */
+ csio_wr_reg32(hw, mem_win_base | BIR(0) |
+ WINDOW(ilog2(MEMWIN_APERTURE) - 10),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+
+ return 0;
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void
+csio_t5_pcie_intr_handler(struct csio_hw *hw)
+{
+ static struct intr_info sysbus_intr_info[] = {
+ { RNPP, "RXNP array parity error", -1, 1 },
+ { RPCP, "RXPC array parity error", -1, 1 },
+ { RCIP, "RXCIF array parity error", -1, 1 },
+ { RCCP, "Rx completions control array parity error", -1, 1 },
+ { RFTP, "RXFT array parity error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+ static struct intr_info pcie_port_intr_info[] = {
+ { TPCP, "TXPC array parity error", -1, 1 },
+ { TNPP, "TXNP array parity error", -1, 1 },
+ { TFTP, "TXFT array parity error", -1, 1 },
+ { TCAP, "TXCA array parity error", -1, 1 },
+ { TCIP, "TXCIF array parity error", -1, 1 },
+ { RCAP, "RXCA array parity error", -1, 1 },
+ { OTDD, "outbound request TLP discarded", -1, 1 },
+ { RDPE, "Rx data parity error", -1, 1 },
+ { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { 0, NULL, 0, 0 }
+ };
+
+ static struct intr_info pcie_intr_info[] = {
+ { MSTGRPPERR, "Master Response Read Queue parity error",
+ -1, 1 },
+ { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
+ { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
+ { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
+ -1, 1 },
+ { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
+ -1, 1 },
+ { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
+ { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
+ { DREQWRPERR, "PCI DMA channel write request parity error",
+ -1, 1 },
+ { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
+ { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR, "PCI FID parity error", -1, 1 },
+ { VFIDPERR, "PCI INTx clear parity error", -1, 1 },
+ { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
+ { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
+ { IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
+ -1, 1 },
+ { IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
+ -1, 1 },
+ { RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
+ { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
+ { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
+ { READRSPERR, "Outbound read error", -1, 0 },
+ { 0, NULL, 0, 0 }
+ };
+
+ int fat;
+ fat = csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+ sysbus_intr_info) +
+ csio_handle_intr_status(hw,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+ pcie_port_intr_info) +
+ csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
+ if (fat)
+ csio_hw_fatal_err(hw);
+}
+
+/*
+ * csio_t5_flash_cfg_addr - return the address of the flash configuration file
+ * @hw: the HW module
+ *
+ * Return the address within the flash where the Firmware Configuration
+ * File is stored.
+ */
+static unsigned int
+csio_t5_flash_cfg_addr(struct csio_hw *hw)
+{
+ return FLASH_CFG_START;
+}
+
+/*
+ * csio_t5_mc_read - read from MC through backdoor accesses
+ * @hw: the hw module
+ * @idx: index to the register
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from MC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t5_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+ uint32_t mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg;
+ uint32_t mc_bist_status_rdata_reg, mc_bist_data_pattern_reg;
+
+ mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD, idx);
+ mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR, idx);
+ mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN, idx);
+ mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA, idx);
+ mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN, idx);
+
+ if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, mc_bist_cmd_addr_reg);
+ csio_wr_reg32(hw, 64, mc_bist_cmd_len_reg);
+ csio_wr_reg32(hw, 0xc, mc_bist_data_pattern_reg);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ mc_bist_cmd_reg);
+ i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, MC_DATA(16));
+#undef MC_DATA
+ return 0;
+}
+
+/*
+ * csio_t5_edc_read - read from EDC through backdoor accesses
+ * @hw: the hw module
+ * @idx: which EDC to access
+ * @addr: address of first byte requested
+ * @data: 64 bytes of data containing the requested address
+ * @ecc: where to store the corresponding 64-bit ECC word
+ *
+ * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
+ * that covers the requested address @addr. If @parity is not %NULL it
+ * is assigned the 64-bit ECC word for the read data.
+ */
+static int
+csio_t5_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
+ uint64_t *ecc)
+{
+ int i;
+ uint32_t edc_bist_cmd_reg, edc_bist_cmd_addr_reg, edc_bist_cmd_len_reg;
+ uint32_t edc_bist_cmd_data_pattern, edc_bist_status_rdata_reg;
+
+/*
+ * These macro are missing in t4_regs.h file.
+ */
+#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
+#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
+
+ edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD, idx);
+ edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx);
+ edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx);
+ edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx);
+ edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx);
+#undef EDC_REG_T5
+#undef EDC_STRIDE_T5
+
+ if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST)
+ return -EBUSY;
+ csio_wr_reg32(hw, addr & ~0x3fU, edc_bist_cmd_addr_reg);
+ csio_wr_reg32(hw, 64, edc_bist_cmd_len_reg);
+ csio_wr_reg32(hw, 0xc, edc_bist_cmd_data_pattern);
+ csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ edc_bist_cmd_reg);
+ i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST,
+ 0, 10, 1, NULL);
+ if (i)
+ return i;
+
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+
+ for (i = 15; i >= 0; i--)
+ *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
+ if (ecc)
+ *ecc = csio_rd_reg64(hw, EDC_DATA(16));
+#undef EDC_DATA
+ return 0;
+}
+
+/*
+ * csio_t5_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
+ * @hw: the csio_hw
+ * @win: PCI-E memory Window to use
+ * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
+ * @addr: address within indicated memory type
+ * @len: amount of memory to transfer
+ * @buf: host memory buffer
+ * @dir: direction of transfer 1 => read, 0 => write
+ *
+ * Reads/writes an [almost] arbitrary memory region in the firmware: the
+ * firmware memory address, length and host buffer must be aligned on
+ * 32-bit boudaries. The memory is transferred as a raw byte sequence
+ * from/to the firmware's memory. If this memory contains data
+ * structures which contain multi-byte integers, it's the callers
+ * responsibility to perform appropriate byte order conversions.
+ */
+static int
+csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
+ u32 len, uint32_t *buf, int dir)
+{
+ u32 pos, start, offset, memoffset;
+ u32 edc_size, mc_size, win_pf, mem_reg, mem_aperture, mem_base;
+
+ /*
+ * Argument sanity checks ...
+ */
+ if ((addr & 0x3) || (len & 0x3))
+ return -EINVAL;
+
+ /* Offset into the region of memory which is being accessed
+ * MEM_EDC0 = 0
+ * MEM_EDC1 = 1
+ * MEM_MC = 2 -- T4
+ * MEM_MC0 = 2 -- For T5
+ * MEM_MC1 = 3 -- For T5
+ */
+ edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+ if (mtype != MEM_MC1)
+ memoffset = (mtype * (edc_size * 1024 * 1024));
+ else {
+ mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
+ MA_EXT_MEMORY_BAR));
+ memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
+ }
+
+ /* Determine the PCIE_MEM_ACCESS_OFFSET */
+ addr = addr + memoffset;
+
+ /*
+ * Each PCI-E Memory Window is programmed with a window size -- or
+ * "aperture" -- which controls the granularity of its mapping onto
+ * adapter memory. We need to grab that aperture in order to know
+ * how to use the specified window. The window is also programmed
+ * with the base address of the Memory Window in BAR0's address
+ * space. For T4 this is an absolute PCI-E Bus Address. For T5
+ * the address is relative to BAR0.
+ */
+ mem_reg = csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ mem_aperture = 1 << (WINDOW(mem_reg) + 10);
+ mem_base = GET_PCIEOFST(mem_reg) << 10;
+
+ start = addr & ~(mem_aperture-1);
+ offset = addr - start;
+ win_pf = V_PFNUM(hw->pfn);
+
+ csio_dbg(hw, "csio_t5_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
+ mem_reg, mem_aperture);
+ csio_dbg(hw, "csio_t5_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
+ mem_base, memoffset);
+ csio_dbg(hw, "csio_t5_memory_rw: start:0x%x, offset:0x%x, win_pf:%d\n",
+ start, offset, win_pf);
+ csio_dbg(hw, "csio_t5_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
+ mtype, addr, len);
+
+ for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
+ /*
+ * Move PCI-E Memory Window to our current transfer
+ * position. Read it back to ensure that changes propagate
+ * before we attempt to use the new value.
+ */
+ csio_wr_reg32(hw, pos | win_pf,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ csio_rd_reg32(hw,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+
+ while (offset < mem_aperture && len > 0) {
+ if (dir)
+ *buf++ = csio_rd_reg32(hw, mem_base + offset);
+ else
+ csio_wr_reg32(hw, *buf++, mem_base + offset);
+
+ offset += sizeof(__be32);
+ len -= sizeof(__be32);
+ }
+ }
+ return 0;
+}
+
+/*
+ * csio_t5_dfs_create_ext_mem - setup debugfs for MC0 or MC1 to read the values
+ * @hw: the csio_hw
+ *
+ * This function creates files in the debugfs with external memory region
+ * MC0 & MC1.
+ */
+static void
+csio_t5_dfs_create_ext_mem(struct csio_hw *hw)
+{
+ u32 size;
+ int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
+ if (i & EXT_MEM_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+ csio_add_debugfs_mem(hw, "mc0", MEM_MC0,
+ EXT_MEM_SIZE_GET(size));
+ }
+ if (i & EXT_MEM1_ENABLE) {
+ size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR);
+ csio_add_debugfs_mem(hw, "mc1", MEM_MC1,
+ EXT_MEM_SIZE_GET(size));
+ }
+}
+
+/* T5 adapter specific function */
+struct csio_hw_chip_ops t5_ops = {
+ .chip_set_mem_win = csio_t5_set_mem_win,
+ .chip_pcie_intr_handler = csio_t5_pcie_intr_handler,
+ .chip_flash_cfg_addr = csio_t5_flash_cfg_addr,
+ .chip_mc_read = csio_t5_mc_read,
+ .chip_edc_read = csio_t5_edc_read,
+ .chip_memory_rw = csio_t5_memory_rw,
+ .chip_dfs_create_ext_mem = csio_t5_dfs_create_ext_mem,
+};
diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c
index 0604b5ff3638..00346fe939d5 100644
--- a/drivers/scsi/csiostor/csio_init.c
+++ b/drivers/scsi/csiostor/csio_init.c
@@ -81,9 +81,11 @@ csio_mem_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
__be32 data[16];
if (mem == MEM_MC)
- ret = csio_hw_mc_read(hw, pos, data, NULL);
+ ret = hw->chip_ops->chip_mc_read(hw, 0, pos,
+ data, NULL);
else
- ret = csio_hw_edc_read(hw, mem, pos, data, NULL);
+ ret = hw->chip_ops->chip_edc_read(hw, mem, pos,
+ data, NULL);
if (ret)
return ret;
@@ -108,7 +110,7 @@ static const struct file_operations csio_mem_debugfs_fops = {
.llseek = default_llseek,
};
-static void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
+void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
unsigned int idx, unsigned int size_mb)
{
struct dentry *de;
@@ -131,9 +133,8 @@ static int csio_setup_debugfs(struct csio_hw *hw)
csio_add_debugfs_mem(hw, "edc0", MEM_EDC0, 5);
if (i & EDRAM1_ENABLE)
csio_add_debugfs_mem(hw, "edc1", MEM_EDC1, 5);
- if (i & EXT_MEM_ENABLE)
- csio_add_debugfs_mem(hw, "mc", MEM_MC,
- EXT_MEM_SIZE_GET(csio_rd_reg32(hw, MA_EXT_MEMORY_BAR)));
+
+ hw->chip_ops->chip_dfs_create_ext_mem(hw);
return 0;
}
@@ -1169,7 +1170,7 @@ static struct pci_error_handlers csio_err_handler = {
};
static DEFINE_PCI_DEVICE_TABLE(csio_pci_tbl) = {
- CSIO_DEVICE(CSIO_DEVID_T440DBG_FCOE, 0), /* T440DBG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T440DBG_FCOE, 0), /* T4 DEBUG FCOE */
CSIO_DEVICE(CSIO_DEVID_T420CR_FCOE, 0), /* T420CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T422CR_FCOE, 0), /* T422CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T440CR_FCOE, 0), /* T440CR FCOE */
@@ -1184,8 +1185,34 @@ static DEFINE_PCI_DEVICE_TABLE(csio_pci_tbl) = {
CSIO_DEVICE(CSIO_DEVID_B404_FCOE, 0), /* B404 FCOE */
CSIO_DEVICE(CSIO_DEVID_T480CR_FCOE, 0), /* T480 CR FCOE */
CSIO_DEVICE(CSIO_DEVID_T440LPCR_FCOE, 0), /* T440 LP-CR FCOE */
- CSIO_DEVICE(CSIO_DEVID_PE10K, 0), /* PE10K FCOE */
- CSIO_DEVICE(CSIO_DEVID_PE10K_PF1, 0), /* PE10K FCOE on PF1 */
+ CSIO_DEVICE(CSIO_DEVID_AMSTERDAM_T4_FCOE, 0), /* AMSTERDAM T4 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T480_FCOE, 0), /* HUAWEI T480 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T440_FCOE, 0), /* HUAWEI T440 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_STG310_FCOE, 0), /* HUAWEI STG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_ACROMAG_XMC_XAUI, 0), /* ACROMAG XAUI FCOE */
+ CSIO_DEVICE(CSIO_DEVID_QUANTA_MEZZ_SFP_FCOE, 0),/* QUANTA MEZZ FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_10GT_FCOE, 0), /* HUAWEI 10GT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_HUAWEI_T440_TOE_FCOE, 0),/* HUAWEI T4 TOE FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580DBG_FCOE, 0), /* T5 DEBUG FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520CR_FCOE, 0), /* T520CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T522CR_FCOE, 0), /* T522CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540CR_FCOE, 0), /* T540CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520BCH_FCOE, 0), /* T520BCH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540BCH_FCOE, 0), /* T540BCH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540CH_FCOE, 0), /* T540CH FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520SO_FCOE, 0), /* T520SO FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520CX_FCOE, 0), /* T520CX FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520BT_FCOE, 0), /* T520BT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T504BT_FCOE, 0), /* T504BT FCOE */
+ CSIO_DEVICE(CSIO_DEVID_B520_FCOE, 0), /* B520 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_B504_FCOE, 0), /* B504 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580CR2_FCOE, 0), /* T580 CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T540LPCR_FCOE, 0), /* T540 LP-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_AMSTERDAM_T5_FCOE, 0), /* AMSTERDAM T5 FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580LPCR_FCOE, 0), /* T580 LP-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T520LLCR_FCOE, 0), /* T520 LL-CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T560CR_FCOE, 0), /* T560 CR FCOE */
+ CSIO_DEVICE(CSIO_DEVID_T580CR_FCOE, 0), /* T580 CR FCOE */
{ 0, 0, 0, 0, 0, 0, 0 }
};
@@ -1259,4 +1286,5 @@ MODULE_DESCRIPTION(CSIO_DRV_DESC);
MODULE_LICENSE(CSIO_DRV_LICENSE);
MODULE_DEVICE_TABLE(pci, csio_pci_tbl);
MODULE_VERSION(CSIO_DRV_VERSION);
-MODULE_FIRMWARE(CSIO_FW_FNAME);
+MODULE_FIRMWARE(FW_FNAME_T4);
+MODULE_FIRMWARE(FW_FNAME_T5);
diff --git a/drivers/scsi/csiostor/csio_init.h b/drivers/scsi/csiostor/csio_init.h
index 0838fd7ec9c7..5cc5d317a442 100644
--- a/drivers/scsi/csiostor/csio_init.h
+++ b/drivers/scsi/csiostor/csio_init.h
@@ -52,31 +52,6 @@
#define CSIO_DRV_DESC "Chelsio FCoE driver"
#define CSIO_DRV_VERSION "1.0.0"
-#define CSIO_DEVICE(devid, idx) \
-{ PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
-
-#define CSIO_IS_T4_FPGA(_dev) (((_dev) == CSIO_DEVID_PE10K) ||\
- ((_dev) == CSIO_DEVID_PE10K_PF1))
-
-/* FCoE device IDs */
-#define CSIO_DEVID_PE10K 0xA000
-#define CSIO_DEVID_PE10K_PF1 0xA001
-#define CSIO_DEVID_T440DBG_FCOE 0x4600
-#define CSIO_DEVID_T420CR_FCOE 0x4601
-#define CSIO_DEVID_T422CR_FCOE 0x4602
-#define CSIO_DEVID_T440CR_FCOE 0x4603
-#define CSIO_DEVID_T420BCH_FCOE 0x4604
-#define CSIO_DEVID_T440BCH_FCOE 0x4605
-#define CSIO_DEVID_T440CH_FCOE 0x4606
-#define CSIO_DEVID_T420SO_FCOE 0x4607
-#define CSIO_DEVID_T420CX_FCOE 0x4608
-#define CSIO_DEVID_T420BT_FCOE 0x4609
-#define CSIO_DEVID_T404BT_FCOE 0x460A
-#define CSIO_DEVID_B420_FCOE 0x460B
-#define CSIO_DEVID_B404_FCOE 0x460C
-#define CSIO_DEVID_T480CR_FCOE 0x460D
-#define CSIO_DEVID_T440LPCR_FCOE 0x460E
-
extern struct fc_function_template csio_fc_transport_funcs;
extern struct fc_function_template csio_fc_transport_vport_funcs;
@@ -100,6 +75,10 @@ struct csio_lnode *csio_shost_init(struct csio_hw *, struct device *, bool,
void csio_shost_exit(struct csio_lnode *);
void csio_lnodes_exit(struct csio_hw *, bool);
+/* DebugFS helper routines */
+void csio_add_debugfs_mem(struct csio_hw *, const char *,
+ unsigned int, unsigned int);
+
static inline struct Scsi_Host *
csio_ln_to_shost(struct csio_lnode *ln)
{
diff --git a/drivers/scsi/csiostor/csio_lnode.h b/drivers/scsi/csiostor/csio_lnode.h
index 8d84988ab06d..0f9c04175b11 100644
--- a/drivers/scsi/csiostor/csio_lnode.h
+++ b/drivers/scsi/csiostor/csio_lnode.h
@@ -114,7 +114,7 @@ struct csio_lnode_stats {
uint32_t n_rnode_match; /* matched rnode */
uint32_t n_dev_loss_tmo; /* Device loss timeout */
uint32_t n_fdmi_err; /* fdmi err */
- uint32_t n_evt_fw[RSCN_DEV_LOST]; /* fw events */
+ uint32_t n_evt_fw[PROTO_ERR_IMPL_LOGO]; /* fw events */
enum csio_ln_ev n_evt_sm[CSIO_LNE_MAX_EVENT]; /* State m/c events */
uint32_t n_rnode_alloc; /* rnode allocated */
uint32_t n_rnode_free; /* rnode freed */
diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c
index 5b27c48f6836..f5d9ee1fda62 100644
--- a/drivers/scsi/csiostor/csio_mb.c
+++ b/drivers/scsi/csiostor/csio_mb.c
@@ -182,7 +182,7 @@ csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
* @tmo: Command timeout.
* @pf: PF number.
* @vf: VF number.
- * @nparams: Number of paramters
+ * @nparams: Number of parameters
* @params: Parameter mnemonic array.
* @val: Parameter value array.
* @wr: Write/Read PARAMS.
@@ -721,7 +721,7 @@ csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @mbp: Mailbox structure to initialize
* @priv: Private data
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -752,7 +752,7 @@ csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @priv: Private data
* @mb_tmo: Mailbox time-out period (in ms).
* @cascaded_req: TRUE - if this request is cascased with Eq-alloc request.
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -817,7 +817,7 @@ csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
* @mbp: Mailbox structure to initialize
* @priv: Private data.
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
* @cbfn: The call-back function
*
*
@@ -840,7 +840,7 @@ csio_mb_eq_ofld_alloc_write(struct csio_hw *hw, struct csio_mb *mbp,
* @hw: The HW structure.
* @mbp: Mailbox structure to initialize.
* @retval: Firmware return value.
- * @eq_ofld_params: (Offload) Egress queue paramters.
+ * @eq_ofld_params: (Offload) Egress queue parameters.
*
*/
void
@@ -870,7 +870,7 @@ csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
* @mbp: Mailbox structure to initialize
* @priv: Private data area.
* @mb_tmo: Mailbox time-out period (in ms).
- * @eq_ofld_params: (Offload) Egress queue paramters, that is to be freed.
+ * @eq_ofld_params: (Offload) Egress queue parameters, that is to be freed.
* @cbfn: The call-back function
*
*
diff --git a/drivers/scsi/csiostor/csio_rnode.c b/drivers/scsi/csiostor/csio_rnode.c
index 51c6a388de2b..e9c3b045f587 100644
--- a/drivers/scsi/csiostor/csio_rnode.c
+++ b/drivers/scsi/csiostor/csio_rnode.c
@@ -302,7 +302,7 @@ csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
{
uint8_t rport_type;
struct csio_rnode *rn, *match_rn;
- uint32_t vnp_flowid;
+ uint32_t vnp_flowid = 0;
__be32 *port_id;
port_id = (__be32 *)&rdevp->r_id[0];
@@ -350,6 +350,14 @@ csio_confirm_rnode(struct csio_lnode *ln, uint32_t rdev_flowid,
* Else, go ahead and alloc a new rnode.
*/
if (!memcmp(csio_rn_wwpn(match_rn), rdevp->wwpn, 8)) {
+ if (rn == match_rn)
+ goto found_rnode;
+ csio_ln_dbg(ln,
+ "nport_id:x%x and wwpn:%llx"
+ " match for ssni:x%x\n",
+ rn->nport_id,
+ wwn_to_u64(rdevp->wwpn),
+ rdev_flowid);
if (csio_is_rnode_ready(rn)) {
csio_ln_warn(ln,
"rnode is already"
diff --git a/drivers/scsi/csiostor/csio_rnode.h b/drivers/scsi/csiostor/csio_rnode.h
index a3b434c801da..65940096a80d 100644
--- a/drivers/scsi/csiostor/csio_rnode.h
+++ b/drivers/scsi/csiostor/csio_rnode.h
@@ -63,7 +63,7 @@ struct csio_rnode_stats {
uint32_t n_err_nomem; /* error nomem */
uint32_t n_evt_unexp; /* unexpected event */
uint32_t n_evt_drop; /* unexpected event */
- uint32_t n_evt_fw[RSCN_DEV_LOST]; /* fw events */
+ uint32_t n_evt_fw[PROTO_ERR_IMPL_LOGO]; /* fw events */
enum csio_rn_ev n_evt_sm[CSIO_RNFE_MAX_EVENT]; /* State m/c events */
uint32_t n_lun_rst; /* Number of resets of
* of LUNs under this
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index c32df1bdaa97..4255ce264abf 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -85,8 +85,8 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq)
*/
if (flq->inc_idx >= 8) {
csio_wr_reg32(hw, DBPRIO(1) | QID(flq->un.fl.flid) |
- PIDX(flq->inc_idx / 8),
- MYPF_REG(SGE_PF_KDOORBELL));
+ CSIO_HW_PIDX(hw, flq->inc_idx / 8),
+ MYPF_REG(SGE_PF_KDOORBELL));
flq->inc_idx &= 7;
}
}
@@ -989,7 +989,8 @@ csio_wr_issue(struct csio_hw *hw, int qidx, bool prio)
wmb();
/* Ring SGE Doorbell writing q->pidx into it */
csio_wr_reg32(hw, DBPRIO(prio) | QID(q->un.eq.physeqid) |
- PIDX(q->inc_idx), MYPF_REG(SGE_PF_KDOORBELL));
+ CSIO_HW_PIDX(hw, q->inc_idx),
+ MYPF_REG(SGE_PF_KDOORBELL));
q->inc_idx = 0;
return 0;
@@ -1331,20 +1332,30 @@ csio_wr_fixup_host_params(struct csio_hw *hw)
/* FL BUFFER SIZE#0 is Page size i,e already aligned to cache line */
csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0);
- csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) +
- sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE2);
- csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) +
- sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE3);
+
+ /*
+ * If using hard params, the following will get set correctly
+ * in csio_wr_set_sge().
+ */
+ if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) {
+ csio_wr_reg32(hw,
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) +
+ sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
+ SGE_FL_BUFFER_SIZE2);
+ csio_wr_reg32(hw,
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) +
+ sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
+ SGE_FL_BUFFER_SIZE3);
+ }
csio_wr_reg32(hw, HPZ0(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ);
/* default value of rx_dma_offset of the NIC driver */
csio_set_reg_field(hw, SGE_CONTROL, PKTSHIFT_MASK,
PKTSHIFT(CSIO_SGE_RX_DMA_OFFSET));
+
+ csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG,
+ CSUM_HAS_PSEUDO_HDR, 0);
}
static void
@@ -1460,18 +1471,21 @@ csio_wr_set_sge(struct csio_hw *hw)
* and generate an interrupt when this occurs so we can recover.
*/
csio_set_reg_field(hw, SGE_DBFIFO_STATUS,
- HP_INT_THRESH(HP_INT_THRESH_MASK) |
- LP_INT_THRESH(LP_INT_THRESH_MASK),
- HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) |
- LP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH));
+ HP_INT_THRESH(HP_INT_THRESH_MASK) |
+ CSIO_HW_LP_INT_THRESH(hw, CSIO_HW_M_LP_INT_THRESH(hw)),
+ HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) |
+ CSIO_HW_LP_INT_THRESH(hw, CSIO_SGE_DBFIFO_INT_THRESH));
+
csio_set_reg_field(hw, SGE_DOORBELL_CONTROL, ENABLE_DROP,
ENABLE_DROP);
/* SGE_FL_BUFFER_SIZE0 is set up by csio_wr_fixup_host_params(). */
CSIO_SET_FLBUF_SIZE(hw, 1, CSIO_SGE_FLBUF_SIZE1);
- CSIO_SET_FLBUF_SIZE(hw, 2, CSIO_SGE_FLBUF_SIZE2);
- CSIO_SET_FLBUF_SIZE(hw, 3, CSIO_SGE_FLBUF_SIZE3);
+ csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE2 + sge->csio_fl_align - 1)
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2);
+ csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE3 + sge->csio_fl_align - 1)
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3);
CSIO_SET_FLBUF_SIZE(hw, 4, CSIO_SGE_FLBUF_SIZE4);
CSIO_SET_FLBUF_SIZE(hw, 5, CSIO_SGE_FLBUF_SIZE5);
CSIO_SET_FLBUF_SIZE(hw, 6, CSIO_SGE_FLBUF_SIZE6);
@@ -1522,22 +1536,24 @@ void
csio_wr_sge_init(struct csio_hw *hw)
{
/*
- * If we are master:
+ * If we are master and chip is not initialized:
* - If we plan to use the config file, we need to fixup some
* host specific registers, and read the rest of the SGE
* configuration.
* - If we dont plan to use the config file, we need to initialize
* SGE entirely, including fixing the host specific registers.
+ * If we are master and chip is initialized, just read and work off of
+ * the already initialized SGE values.
* If we arent the master, we are only allowed to read and work off of
* the already initialized SGE values.
*
* Therefore, before calling this function, we assume that the master-
- * ship of the card, and whether to use config file or not, have
- * already been decided. In other words, CSIO_HWF_USING_SOFT_PARAMS and
- * CSIO_HWF_MASTER should be set/unset.
+ * ship of the card, state and whether to use config file or not, have
+ * already been decided.
*/
if (csio_is_hw_master(hw)) {
- csio_wr_fixup_host_params(hw);
+ if (hw->fw_state != CSIO_DEV_STATE_INIT)
+ csio_wr_fixup_host_params(hw);
if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS)
csio_wr_get_sge(hw);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 6f4d8e6f32f1..68adb8955d2d 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -232,13 +232,13 @@ static void stpg_endio(struct request *req, int error)
struct scsi_sense_hdr sense_hdr;
unsigned err = SCSI_DH_OK;
- if (error || host_byte(req->errors) != DID_OK ||
- msg_byte(req->errors) != COMMAND_COMPLETE) {
+ if (host_byte(req->errors) != DID_OK ||
+ msg_byte(req->errors) != COMMAND_COMPLETE) {
err = SCSI_DH_IO;
goto done;
}
- if (h->senselen > 0) {
+ if (req->sense_len > 0) {
err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE,
&sense_hdr);
if (!err) {
@@ -255,7 +255,9 @@ static void stpg_endio(struct request *req, int error)
ALUA_DH_NAME, sense_hdr.sense_key,
sense_hdr.asc, sense_hdr.ascq);
err = SCSI_DH_IO;
- }
+ } else if (error)
+ err = SCSI_DH_IO;
+
if (err == SCSI_DH_OK) {
h->state = TPGS_STATE_OPTIMIZED;
sdev_printk(KERN_INFO, h->sdev,
@@ -710,6 +712,10 @@ static int alua_set_params(struct scsi_device *sdev, const char *params)
return result;
}
+static uint optimize_stpg;
+module_param(optimize_stpg, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than sending a STPG, when implicit TPGS is supported (0=No,1=Yes). Default is 0.");
+
/*
* alua_activate - activate a path
* @sdev: device on the path to be activated
@@ -731,6 +737,9 @@ static int alua_activate(struct scsi_device *sdev,
if (err != SCSI_DH_OK)
goto out;
+ if (optimize_stpg)
+ h->flags |= ALUA_OPTIMIZE_STPG;
+
if (h->tpgs & TPGS_MODE_EXPLICIT) {
switch (h->state) {
case TPGS_STATE_NONOPTIMIZED:
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index b5d92fc93c70..292b24f9bf93 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -490,7 +490,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
{
struct net_device *netdev = fcoe->netdev;
struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
- struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
rtnl_lock();
if (!fcoe->removed)
@@ -501,7 +500,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
/* tear-down the FCoE controller */
fcoe_ctlr_destroy(fip);
scsi_host_put(fip->lp->host);
- fcoe_ctlr_device_delete(ctlr_dev);
dev_put(netdev);
module_put(THIS_MODULE);
}
@@ -1657,7 +1655,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
skb->priority = fcoe->priority;
if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN &&
- fcoe->realdev->features & NETIF_F_HW_VLAN_TX) {
+ fcoe->realdev->features & NETIF_F_HW_VLAN_CTAG_TX) {
skb->vlan_tci = VLAN_TAG_PRESENT |
vlan_dev_vlan_id(fcoe->netdev);
skb->dev = fcoe->realdev;
@@ -2194,6 +2192,8 @@ out_nodev:
*/
static void fcoe_destroy_work(struct work_struct *work)
{
+ struct fcoe_ctlr_device *cdev;
+ struct fcoe_ctlr *ctlr;
struct fcoe_port *port;
struct fcoe_interface *fcoe;
struct Scsi_Host *shost;
@@ -2224,10 +2224,15 @@ static void fcoe_destroy_work(struct work_struct *work)
mutex_lock(&fcoe_config_mutex);
fcoe = port->priv;
+ ctlr = fcoe_to_ctlr(fcoe);
+ cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
+
fcoe_if_destroy(port->lport);
fcoe_interface_cleanup(fcoe);
mutex_unlock(&fcoe_config_mutex);
+
+ fcoe_ctlr_device_delete(cdev);
}
/**
@@ -2335,7 +2340,9 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
rc = -EIO;
rtnl_unlock();
fcoe_interface_cleanup(fcoe);
- goto out_nortnl;
+ mutex_unlock(&fcoe_config_mutex);
+ fcoe_ctlr_device_delete(ctlr_dev);
+ goto out;
}
/* Make this the "master" N_Port */
@@ -2375,8 +2382,8 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
out_nodev:
rtnl_unlock();
-out_nortnl:
mutex_unlock(&fcoe_config_mutex);
+out:
return rc;
}
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 08c3bc398da2..cd743c545ce9 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2161,7 +2161,7 @@ static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip)
if (fip->probe_tries < FIP_VN_RLIM_COUNT) {
fip->probe_tries++;
- wait = random32() % FIP_VN_PROBE_WAIT;
+ wait = prandom_u32() % FIP_VN_PROBE_WAIT;
} else
wait = FIP_VN_RLIM_INT;
mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait));
@@ -2794,7 +2794,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
fcoe_all_vn2vn, 0);
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_BEACON_INT +
- (random32() % FIP_VN_BEACON_FUZZ));
+ (prandom_u32() % FIP_VN_BEACON_FUZZ));
}
if (time_before(fip->port_ka_time, next_time))
next_time = fip->port_ka_time;
@@ -2815,6 +2815,47 @@ unlock:
}
/**
+ * fcoe_ctlr_mode_set() - Set or reset the ctlr's mode
+ * @lport: The local port to be (re)configured
+ * @fip: The FCoE controller whose mode is changing
+ * @fip_mode: The new fip mode
+ *
+ * Note that the we shouldn't be changing the libfc discovery settings
+ * (fc_disc_config) while an lport is going through the libfc state
+ * machine. The mode can only be changed when a fcoe_ctlr device is
+ * disabled, so that should ensure that this routine is only called
+ * when nothing is happening.
+ */
+void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
+ enum fip_state fip_mode)
+{
+ void *priv;
+
+ WARN_ON(lport->state != LPORT_ST_RESET &&
+ lport->state != LPORT_ST_DISABLED);
+
+ if (fip_mode == FIP_MODE_VN2VN) {
+ lport->rport_priv_size = sizeof(struct fcoe_rport);
+ lport->point_to_multipoint = 1;
+ lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
+ lport->tt.disc_start = fcoe_ctlr_disc_start;
+ lport->tt.disc_stop = fcoe_ctlr_disc_stop;
+ lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
+ priv = fip;
+ } else {
+ lport->rport_priv_size = 0;
+ lport->point_to_multipoint = 0;
+ lport->tt.disc_recv_req = NULL;
+ lport->tt.disc_start = NULL;
+ lport->tt.disc_stop = NULL;
+ lport->tt.disc_stop_final = NULL;
+ priv = lport;
+ }
+
+ fc_disc_config(lport, priv);
+}
+
+/**
* fcoe_libfc_config() - Sets up libfc related properties for local port
* @lport: The local port to configure libfc for
* @fip: The FCoE controller in use by the local port
@@ -2833,21 +2874,9 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
fc_exch_init(lport);
fc_elsct_init(lport);
fc_lport_init(lport);
- if (fip->mode == FIP_MODE_VN2VN)
- lport->rport_priv_size = sizeof(struct fcoe_rport);
fc_rport_init(lport);
- if (fip->mode == FIP_MODE_VN2VN) {
- lport->point_to_multipoint = 1;
- lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
- lport->tt.disc_start = fcoe_ctlr_disc_start;
- lport->tt.disc_stop = fcoe_ctlr_disc_stop;
- lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
- mutex_init(&lport->disc.disc_mutex);
- INIT_LIST_HEAD(&lport->disc.rports);
- lport->disc.priv = fip;
- } else {
- fc_disc_init(lport);
- }
+ fc_disc_init(lport);
+ fcoe_ctlr_mode_set(lport, fip, fip->mode);
return 0;
}
EXPORT_SYMBOL_GPL(fcoe_libfc_config);
@@ -2875,6 +2904,7 @@ EXPORT_SYMBOL(fcoe_fcf_get_selected);
void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
{
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+ struct fc_lport *lport = ctlr->lp;
mutex_lock(&ctlr->ctlr_mutex);
switch (ctlr_dev->mode) {
@@ -2888,5 +2918,7 @@ void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
}
mutex_unlock(&ctlr->ctlr_mutex);
+
+ fcoe_ctlr_mode_set(lport, ctlr, ctlr->mode);
}
EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index a044f593e8b9..d0fa4b6c551f 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1899,8 +1899,8 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
sdev->allow_restart = 1;
blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
}
- scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
spin_unlock_irqrestore(shost->host_lock, lock_flags);
+ scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
return 0;
}
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f328089a1060..2197b57fb225 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -5148,7 +5148,7 @@ static int ipr_cancel_op(struct scsi_cmnd *scsi_cmd)
ipr_trace;
}
- list_add_tail(&ipr_cmd->queue, &hrrq->hrrq_free_q);
+ list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
if (!ipr_is_naca_model(res))
res->needs_sync_complete = 1;
@@ -9349,7 +9349,10 @@ static int ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, struct pci_dev *pdev)
int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
+ if (ioa_cfg->intr_flag == IPR_USE_MSIX)
+ rc = request_irq(ioa_cfg->vectors_info[0].vec, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
+ else
+ rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg);
if (rc) {
dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq);
return rc;
@@ -9371,7 +9374,10 @@ static int ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, struct pci_dev *pdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- free_irq(pdev->irq, ioa_cfg);
+ if (ioa_cfg->intr_flag == IPR_USE_MSIX)
+ free_irq(ioa_cfg->vectors_info[0].vec, ioa_cfg);
+ else
+ free_irq(pdev->irq, ioa_cfg);
LEAVE;
@@ -9722,6 +9728,7 @@ static void __ipr_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
flush_work(&ioa_cfg->work_q);
+ INIT_LIST_HEAD(&ioa_cfg->used_res_q);
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
spin_lock(&ipr_driver_lock);
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 2839baa82a5a..d25d0d859f05 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -721,7 +721,7 @@ static void isci_pci_remove(struct pci_dev *pdev)
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int isci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -770,18 +770,16 @@ static int isci_resume(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume);
-#endif
static struct pci_driver isci_pci_driver = {
.name = DRV_NAME,
.id_table = isci_id_table,
.probe = isci_pci_probe,
.remove = isci_pci_remove,
-#ifdef CONFIG_PM
.driver.pm = &isci_pm_ops,
-#endif
};
static __init int isci_init(void)
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 1b91ca0dc1e3..9e2588a6881c 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -370,17 +370,24 @@ static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn)
static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task)
{
struct iscsi_conn *conn = task->conn;
- int rc;
+ unsigned long pflags = current->flags;
+ int rc = 0;
+
+ current->flags |= PF_MEMALLOC;
while (iscsi_sw_tcp_xmit_qlen(conn)) {
rc = iscsi_sw_tcp_xmit(conn);
- if (rc == 0)
- return -EAGAIN;
+ if (rc == 0) {
+ rc = -EAGAIN;
+ break;
+ }
if (rc < 0)
- return rc;
+ break;
+ rc = 0;
}
- return 0;
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
+ return rc;
}
/*
@@ -665,6 +672,7 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session,
sk->sk_reuse = SK_CAN_REUSE;
sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
sk->sk_allocation = GFP_ATOMIC;
+ sk_set_memalloc(sk);
iscsi_sw_tcp_conn_set_callbacks(conn);
tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage;
diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c
index 8e561e6a557c..880a9068ca12 100644
--- a/drivers/scsi/libfc/fc_disc.c
+++ b/drivers/scsi/libfc/fc_disc.c
@@ -712,12 +712,13 @@ static void fc_disc_stop_final(struct fc_lport *lport)
}
/**
- * fc_disc_init() - Initialize the discovery layer for a local port
- * @lport: The local port that needs the discovery layer to be initialized
+ * fc_disc_config() - Configure the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be configured
+ * @priv: Private data structre for users of the discovery layer
*/
-int fc_disc_init(struct fc_lport *lport)
+void fc_disc_config(struct fc_lport *lport, void *priv)
{
- struct fc_disc *disc;
+ struct fc_disc *disc = &lport->disc;
if (!lport->tt.disc_start)
lport->tt.disc_start = fc_disc_start;
@@ -732,12 +733,21 @@ int fc_disc_init(struct fc_lport *lport)
lport->tt.disc_recv_req = fc_disc_recv_req;
disc = &lport->disc;
+
+ disc->priv = priv;
+}
+EXPORT_SYMBOL(fc_disc_config);
+
+/**
+ * fc_disc_init() - Initialize the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be initialized
+ */
+void fc_disc_init(struct fc_lport *lport)
+{
+ struct fc_disc *disc = &lport->disc;
+
INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
mutex_init(&disc->disc_mutex);
INIT_LIST_HEAD(&disc->rports);
-
- disc->priv = lport;
-
- return 0;
}
EXPORT_SYMBOL(fc_disc_init);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 82c3fd4bc938..5de946984500 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -507,7 +507,6 @@ static void iscsi_free_task(struct iscsi_task *task)
kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*));
if (sc) {
- task->sc = NULL;
/* SCSI eh reuses commands to verify us */
sc->SCp.ptr = NULL;
/*
@@ -3142,7 +3141,7 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
-static int iscsi_switch_str_param(char **param, char *new_val_buf)
+int iscsi_switch_str_param(char **param, char *new_val_buf)
{
char *new_val;
@@ -3159,6 +3158,7 @@ static int iscsi_switch_str_param(char **param, char *new_val_buf)
*param = new_val;
return 0;
}
+EXPORT_SYMBOL_GPL(iscsi_switch_str_param);
int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf, int buflen)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index aec2e0da5016..55cbd0180159 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -235,6 +235,17 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
linkrate = phy->linkrate;
memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+ /* Handle vacant phy - rest of dr data is not valid so skip it */
+ if (phy->phy_state == PHY_VACANT) {
+ memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ phy->attached_dev_type = NO_DEVICE;
+ if (!test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
+ phy->phy_id = phy_id;
+ goto skip;
+ } else
+ goto out;
+ }
+
phy->attached_dev_type = to_dev_type(dr);
if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))
goto out;
@@ -272,6 +283,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
phy->phy->maximum_linkrate = dr->pmax_linkrate;
phy->phy->negotiated_linkrate = phy->linkrate;
+ skip:
if (new_phy)
if (sas_phy_add(phy->phy)) {
sas_phy_free(phy->phy);
@@ -388,7 +400,7 @@ int sas_ex_phy_discover(struct domain_device *dev, int single)
if (!disc_req)
return -ENOMEM;
- disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
if (!disc_resp) {
kfree(disc_req);
return -ENOMEM;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index a364cae9e984..9290713af253 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -692,7 +692,7 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
*/
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- while (pring->txcmplq_cnt) {
+ while (!list_empty(&pring->txcmplq)) {
msleep(10);
if (cnt++ > 500) { /* 5 secs */
lpfc_printf_log(phba,
@@ -2302,11 +2302,17 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2,
"FCF Fast failover=1 Priority failover=2");
-int lpfc_enable_rrq;
+int lpfc_enable_rrq = 2;
module_param(lpfc_enable_rrq, int, S_IRUGO);
MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality");
lpfc_param_show(enable_rrq);
-lpfc_param_init(enable_rrq, 0, 0, 1);
+/*
+# lpfc_enable_rrq: Track XRI/OXID reuse after IO failures
+# 0x0 = disabled, XRI/OXID use not tracked.
+# 0x1 = XRI/OXID reuse is timed with ratov, RRQ sent.
+# 0x2 = XRI/OXID reuse is timed with ratov, No RRQ sent.
+*/
+lpfc_param_init(enable_rrq, 2, 0, 2);
static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL);
/*
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 32d5683e6181..888666892004 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -64,18 +64,14 @@ struct lpfc_bsg_event {
struct list_head events_to_get;
struct list_head events_to_see;
- /* job waiting for this event to finish */
- struct fc_bsg_job *set_job;
+ /* driver data associated with the job */
+ void *dd_data;
};
struct lpfc_bsg_iocb {
struct lpfc_iocbq *cmdiocbq;
- struct lpfc_iocbq *rspiocbq;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *rmp;
struct lpfc_nodelist *ndlp;
-
- /* job waiting for this iocb to finish */
- struct fc_bsg_job *set_job;
};
struct lpfc_bsg_mbox {
@@ -86,20 +82,13 @@ struct lpfc_bsg_mbox {
uint32_t mbOffset; /* from app */
uint32_t inExtWLen; /* from app */
uint32_t outExtWLen; /* from app */
-
- /* job waiting for this mbox command to finish */
- struct fc_bsg_job *set_job;
};
#define MENLO_DID 0x0000FC0E
struct lpfc_bsg_menlo {
struct lpfc_iocbq *cmdiocbq;
- struct lpfc_iocbq *rspiocbq;
- struct lpfc_dmabuf *bmp;
-
- /* job waiting for this iocb to finish */
- struct fc_bsg_job *set_job;
+ struct lpfc_dmabuf *rmp;
};
#define TYPE_EVT 1
@@ -108,6 +97,7 @@ struct lpfc_bsg_menlo {
#define TYPE_MENLO 4
struct bsg_job_data {
uint32_t type;
+ struct fc_bsg_job *set_job; /* job waiting for this iocb to finish */
union {
struct lpfc_bsg_event *evt;
struct lpfc_bsg_iocb iocb;
@@ -141,6 +131,138 @@ struct lpfc_dmabufext {
uint32_t flag;
};
+static void
+lpfc_free_bsg_buffers(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
+{
+ struct lpfc_dmabuf *mlast, *next_mlast;
+
+ if (mlist) {
+ list_for_each_entry_safe(mlast, next_mlast, &mlist->list,
+ list) {
+ lpfc_mbuf_free(phba, mlast->virt, mlast->phys);
+ list_del(&mlast->list);
+ kfree(mlast);
+ }
+ lpfc_mbuf_free(phba, mlist->virt, mlist->phys);
+ kfree(mlist);
+ }
+ return;
+}
+
+static struct lpfc_dmabuf *
+lpfc_alloc_bsg_buffers(struct lpfc_hba *phba, unsigned int size,
+ int outbound_buffers, struct ulp_bde64 *bpl,
+ int *bpl_entries)
+{
+ struct lpfc_dmabuf *mlist = NULL;
+ struct lpfc_dmabuf *mp;
+ unsigned int bytes_left = size;
+
+ /* Verify we can support the size specified */
+ if (!size || (size > (*bpl_entries * LPFC_BPL_SIZE)))
+ return NULL;
+
+ /* Determine the number of dma buffers to allocate */
+ *bpl_entries = (size % LPFC_BPL_SIZE ? size/LPFC_BPL_SIZE + 1 :
+ size/LPFC_BPL_SIZE);
+
+ /* Allocate dma buffer and place in BPL passed */
+ while (bytes_left) {
+ /* Allocate dma buffer */
+ mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!mp) {
+ if (mlist)
+ lpfc_free_bsg_buffers(phba, mlist);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&mp->list);
+ mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
+
+ if (!mp->virt) {
+ kfree(mp);
+ if (mlist)
+ lpfc_free_bsg_buffers(phba, mlist);
+ return NULL;
+ }
+
+ /* Queue it to a linked list */
+ if (!mlist)
+ mlist = mp;
+ else
+ list_add_tail(&mp->list, &mlist->list);
+
+ /* Add buffer to buffer pointer list */
+ if (outbound_buffers)
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+ else
+ bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys));
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys));
+ bpl->tus.f.bdeSize = (uint16_t)
+ (bytes_left >= LPFC_BPL_SIZE ? LPFC_BPL_SIZE :
+ bytes_left);
+ bytes_left -= bpl->tus.f.bdeSize;
+ bpl->tus.w = le32_to_cpu(bpl->tus.w);
+ bpl++;
+ }
+ return mlist;
+}
+
+static unsigned int
+lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers,
+ struct fc_bsg_buffer *bsg_buffers,
+ unsigned int bytes_to_transfer, int to_buffers)
+{
+
+ struct lpfc_dmabuf *mp;
+ unsigned int transfer_bytes, bytes_copied = 0;
+ unsigned int sg_offset, dma_offset;
+ unsigned char *dma_address, *sg_address;
+ struct scatterlist *sgel;
+ LIST_HEAD(temp_list);
+
+
+ list_splice_init(&dma_buffers->list, &temp_list);
+ list_add(&dma_buffers->list, &temp_list);
+ sg_offset = 0;
+ sgel = bsg_buffers->sg_list;
+ list_for_each_entry(mp, &temp_list, list) {
+ dma_offset = 0;
+ while (bytes_to_transfer && sgel &&
+ (dma_offset < LPFC_BPL_SIZE)) {
+ dma_address = mp->virt + dma_offset;
+ if (sg_offset) {
+ /* Continue previous partial transfer of sg */
+ sg_address = sg_virt(sgel) + sg_offset;
+ transfer_bytes = sgel->length - sg_offset;
+ } else {
+ sg_address = sg_virt(sgel);
+ transfer_bytes = sgel->length;
+ }
+ if (bytes_to_transfer < transfer_bytes)
+ transfer_bytes = bytes_to_transfer;
+ if (transfer_bytes > (LPFC_BPL_SIZE - dma_offset))
+ transfer_bytes = LPFC_BPL_SIZE - dma_offset;
+ if (to_buffers)
+ memcpy(dma_address, sg_address, transfer_bytes);
+ else
+ memcpy(sg_address, dma_address, transfer_bytes);
+ dma_offset += transfer_bytes;
+ sg_offset += transfer_bytes;
+ bytes_to_transfer -= transfer_bytes;
+ bytes_copied += transfer_bytes;
+ if (sg_offset >= sgel->length) {
+ sg_offset = 0;
+ sgel = sg_next(sgel);
+ }
+ }
+ }
+ list_del_init(&dma_buffers->list);
+ list_splice(&temp_list, &dma_buffers->list);
+ return bytes_copied;
+}
+
/**
* lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler
* @phba: Pointer to HBA context object.
@@ -166,62 +288,72 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp, *rmp;
struct lpfc_nodelist *ndlp;
struct lpfc_bsg_iocb *iocb;
unsigned long flags;
+ unsigned int rsp_size;
int rc = 0;
+ dd_data = cmdiocbq->context1;
+
+ /* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context2;
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- lpfc_sli_release_iocbq(phba, cmdiocbq);
- return;
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
iocb = &dd_data->context_un.iocb;
- job = iocb->set_job;
- job->dd_data = NULL; /* so timeout handler does not reply */
-
- bmp = iocb->bmp;
+ ndlp = iocb->ndlp;
+ rmp = iocb->rmp;
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
rsp = &rspiocbq->iocb;
- ndlp = cmdiocbq->context1;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Copy the completed data or set the error status */
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ rsp_size = rsp->un.genreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ lpfc_bsg_copy_data(rmp, &job->reply_payload,
+ rsp_size, 0);
+ }
+ }
+ lpfc_free_bsg_buffers(phba, cmp);
+ lpfc_free_bsg_buffers(phba, rmp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ kfree(bmp);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
- kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -240,12 +372,9 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
uint32_t timeout;
struct lpfc_iocbq *cmdiocbq = NULL;
IOCB_t *cmd;
- struct lpfc_dmabuf *bmp = NULL;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
int request_nseg;
int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
uint32_t creg_val;
int rc = 0;
@@ -268,54 +397,50 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
goto no_ndlp;
}
- bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!bmp) {
- rc = -ENOMEM;
- goto free_ndlp;
- }
-
if (ndlp->nlp_flag & NLP_ELS_SND_MASK) {
rc = -ENODEV;
- goto free_bmp;
+ goto free_ndlp;
}
cmdiocbq = lpfc_sli_get_iocbq(phba);
if (!cmdiocbq) {
rc = -ENOMEM;
- goto free_bmp;
+ goto free_ndlp;
}
cmd = &cmdiocbq->iocb;
+
+ bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
+ if (!bmp) {
+ rc = -ENOMEM;
+ goto free_cmdiocbq;
+ }
bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
if (!bmp->virt) {
rc = -ENOMEM;
- goto free_cmdiocbq;
+ goto free_bmp;
}
INIT_LIST_HEAD(&bmp->list);
+
bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &request_nseg);
+ if (!cmp) {
+ rc = -ENOMEM;
+ goto free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl += request_nseg;
+ reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
+ rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
+ bpl, &reply_nseg);
+ if (!rmp) {
+ rc = -ENOMEM;
+ goto free_cmp;
}
cmd->un.genreq64.bdl.ulpIoTag32 = 0;
@@ -343,17 +468,20 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
cmd->ulpTimeout = timeout;
cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
- cmdiocbq->context1 = ndlp;
- cmdiocbq->context2 = dd_data;
+ cmdiocbq->context1 = dd_data;
+ cmdiocbq->context2 = cmp;
+ cmdiocbq->context3 = bmp;
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = bmp;
+ dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = rmp;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
rc = -EIO ;
- goto free_cmdiocbq;
+ goto free_rmp;
}
creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
writel(creg_val, phba->HCregaddr);
@@ -368,19 +496,18 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
else
rc = -EIO;
-
/* iocb failed so cleanup */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-
-free_cmdiocbq:
- lpfc_sli_release_iocbq(phba, cmdiocbq);
+free_rmp:
+ lpfc_free_bsg_buffers(phba, rmp);
+free_cmp:
+ lpfc_free_bsg_buffers(phba, cmp);
free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
+free_cmdiocbq:
+ lpfc_sli_release_iocbq(phba, cmdiocbq);
free_ndlp:
lpfc_nlp_put(ndlp);
no_ndlp:
@@ -418,67 +545,68 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
struct fc_bsg_job *job;
IOCB_t *rsp;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *pbuflist = NULL;
+ struct lpfc_dmabuf *pcmd = NULL, *prsp = NULL;
struct fc_bsg_ctels_reply *els_reply;
uint8_t *rjt_data;
unsigned long flags;
+ unsigned int rsp_size;
int rc = 0;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = cmdiocbq->context1;
- /* normal completion and timeout crossed paths, already done */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
+ ndlp = dd_data->context_un.iocb.ndlp;
+ cmdiocbq->context1 = ndlp;
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = dd_data->context_un.iocb.set_job;
- cmdiocbq = dd_data->context_un.iocb.cmdiocbq;
- rspiocbq = dd_data->context_un.iocb.rspiocbq;
rsp = &rspiocbq->iocb;
- ndlp = dd_data->context_un.iocb.ndlp;
+ pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
+ prsp = (struct lpfc_dmabuf *)pcmd->list.next;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Copy the completed job data or determine the job status if job is
+ * still active
+ */
- if (job->reply->result == -EAGAIN)
- rc = -EAGAIN;
- else if (rsp->ulpStatus == IOSTAT_SUCCESS)
- job->reply->reply_payload_rcv_len =
- rsp->un.elsreq64.bdl.bdeSize;
- else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
- job->reply->reply_payload_rcv_len =
- sizeof(struct fc_bsg_ctels_reply);
- /* LS_RJT data returned in word 4 */
- rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
- els_reply = &job->reply->reply_data.ctels_reply;
- els_reply->status = FC_CTELS_STATUS_REJECT;
- els_reply->rjt_data.action = rjt_data[3];
- els_reply->rjt_data.reason_code = rjt_data[2];
- els_reply->rjt_data.reason_explanation = rjt_data[1];
- els_reply->rjt_data.vendor_unique = rjt_data[0];
- } else
- rc = -EIO;
+ if (job) {
+ if (rsp->ulpStatus == IOSTAT_SUCCESS) {
+ rsp_size = rsp->un.elsreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ prsp->virt,
+ rsp_size);
+ } else if (rsp->ulpStatus == IOSTAT_LS_RJT) {
+ job->reply->reply_payload_rcv_len =
+ sizeof(struct fc_bsg_ctels_reply);
+ /* LS_RJT data returned in word 4 */
+ rjt_data = (uint8_t *)&rsp->un.ulpWord[4];
+ els_reply = &job->reply->reply_data.ctels_reply;
+ els_reply->status = FC_CTELS_STATUS_REJECT;
+ els_reply->rjt_data.action = rjt_data[3];
+ els_reply->rjt_data.reason_code = rjt_data[2];
+ els_reply->rjt_data.reason_explanation = rjt_data[1];
+ els_reply->rjt_data.vendor_unique = rjt_data[0];
+ } else {
+ rc = -EIO;
+ }
+ }
- pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
- lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
- lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
+ lpfc_els_free_iocb(phba, cmdiocbq);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- job->dd_data = NULL;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -496,19 +624,8 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
uint32_t elscmd;
uint32_t cmdsize;
uint32_t rspsize;
- struct lpfc_iocbq *rspiocbq;
struct lpfc_iocbq *cmdiocbq;
- IOCB_t *rsp;
uint16_t rpi = 0;
- struct lpfc_dmabuf *pcmd;
- struct lpfc_dmabuf *prsp;
- struct lpfc_dmabuf *pbuflist = NULL;
- struct ulp_bde64 *bpl;
- int request_nseg;
- int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
uint32_t creg_val;
int rc = 0;
@@ -516,6 +633,15 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
+ /* verify the els command is not greater than the
+ * maximum ELS transfer size.
+ */
+
+ if (job->request_payload.payload_len > FCELSSIZE) {
+ rc = -EINVAL;
+ goto no_dd_data;
+ }
+
/* allocate our bsg tracking structure */
dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
if (!dd_data) {
@@ -525,88 +651,51 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
goto no_dd_data;
}
- if (!lpfc_nlp_get(ndlp)) {
- rc = -ENODEV;
- goto free_dd_data;
- }
-
elscmd = job->request->rqst_data.r_els.els_code;
cmdsize = job->request_payload.payload_len;
rspsize = job->reply_payload.payload_len;
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- lpfc_nlp_put(ndlp);
- rc = -ENOMEM;
+
+ if (!lpfc_nlp_get(ndlp)) {
+ rc = -ENODEV;
goto free_dd_data;
}
- rsp = &rspiocbq->iocb;
- rpi = ndlp->nlp_rpi;
+ /* We will use the allocated dma buffers by prep els iocb for command
+ * and response to ensure if the job times out and the request is freed,
+ * we won't be dma into memory that is no longer allocated to for the
+ * request.
+ */
cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp,
ndlp->nlp_DID, elscmd);
if (!cmdiocbq) {
rc = -EIO;
- goto free_rspiocbq;
+ goto release_ndlp;
}
- /* prep els iocb set context1 to the ndlp, context2 to the command
- * dmabuf, context3 holds the data dmabuf
- */
- pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2;
- prsp = (struct lpfc_dmabuf *) pcmd->list.next;
- lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
- kfree(pcmd);
- lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
- kfree(prsp);
- cmdiocbq->context2 = NULL;
-
- pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3;
- bpl = (struct ulp_bde64 *) pbuflist->virt;
-
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
- }
+ rpi = ndlp->nlp_rpi;
+
+ /* Transfer the request payload to allocated command dma buffer */
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt,
+ cmdsize);
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
- }
- cmdiocbq->iocb.un.elsreq64.bdl.bdeSize =
- (request_nseg + reply_nseg) * sizeof(struct ulp_bde64);
if (phba->sli_rev == LPFC_SLI_REV4)
cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi];
else
cmdiocbq->iocb.ulpContext = rpi;
cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC;
- cmdiocbq->context1 = NULL;
- cmdiocbq->context2 = NULL;
-
- cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
cmdiocbq->context1 = dd_data;
cmdiocbq->context_un.ndlp = ndlp;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp;
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
- dd_data->context_un.iocb.rspiocbq = rspiocbq;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = NULL;
dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = NULL;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
@@ -617,8 +706,9 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
writel(creg_val, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
+
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
- lpfc_nlp_put(ndlp);
+
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
else if (rc == IOCB_BUSY)
@@ -627,17 +717,12 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
rc = -EIO;
linkdown_err:
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys);
-
- lpfc_sli_release_iocbq(phba, cmdiocbq);
+ cmdiocbq->context1 = ndlp;
+ lpfc_els_free_iocb(phba, cmdiocbq);
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
+release_ndlp:
+ lpfc_nlp_put(ndlp);
free_dd_data:
kfree(dd_data);
@@ -680,6 +765,7 @@ lpfc_bsg_event_free(struct kref *kref)
kfree(ed);
}
+ kfree(evt->dd_data);
kfree(evt);
}
@@ -723,6 +809,7 @@ lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id)
evt->req_id = ev_req_id;
evt->reg_id = ev_reg_id;
evt->wait_time_stamp = jiffies;
+ evt->dd_data = NULL;
init_waitqueue_head(&evt->wq);
kref_init(&evt->kref);
return evt;
@@ -790,6 +877,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_hbq_entry *hbqe;
struct lpfc_sli_ct_request *ct_req;
struct fc_bsg_job *job = NULL;
+ struct bsg_job_data *dd_data = NULL;
unsigned long flags;
int size = 0;
@@ -986,10 +1074,11 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
list_move(evt->events_to_see.prev, &evt->events_to_get);
- lpfc_bsg_event_unref(evt);
- job = evt->set_job;
- evt->set_job = NULL;
+ dd_data = (struct bsg_job_data *)evt->dd_data;
+ job = dd_data->set_job;
+ dd_data->set_job = NULL;
+ lpfc_bsg_event_unref(evt);
if (job) {
job->reply->reply_payload_rcv_len = size;
/* make error code available to userspace */
@@ -1078,14 +1167,6 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
goto job_error;
}
- dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
- if (dd_data == NULL) {
- lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
- "2734 Failed allocation of dd_data\n");
- rc = -ENOMEM;
- goto job_error;
- }
-
event_req = (struct set_ct_event *)
job->request->rqst_data.h_vendor.vendor_cmd;
ev_mask = ((uint32_t)(unsigned long)event_req->type_mask &
@@ -1095,6 +1176,7 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
if (evt->reg_id == event_req->ev_reg_id) {
lpfc_bsg_event_ref(evt);
evt->wait_time_stamp = jiffies;
+ dd_data = (struct bsg_job_data *)evt->dd_data;
break;
}
}
@@ -1102,6 +1184,13 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
if (&evt->node == &phba->ct_ev_waiters) {
/* no event waiting struct yet - first call */
+ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL);
+ if (dd_data == NULL) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC,
+ "2734 Failed allocation of dd_data\n");
+ rc = -ENOMEM;
+ goto job_error;
+ }
evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id,
event_req->ev_req_id);
if (!evt) {
@@ -1111,7 +1200,10 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
rc = -ENOMEM;
goto job_error;
}
-
+ dd_data->type = TYPE_EVT;
+ dd_data->set_job = NULL;
+ dd_data->context_un.evt = evt;
+ evt->dd_data = (void *)dd_data;
spin_lock_irqsave(&phba->ct_ev_lock, flags);
list_add(&evt->node, &phba->ct_ev_waiters);
lpfc_bsg_event_ref(evt);
@@ -1121,9 +1213,7 @@ lpfc_bsg_hba_set_event(struct fc_bsg_job *job)
spin_lock_irqsave(&phba->ct_ev_lock, flags);
evt->waiting = 1;
- dd_data->type = TYPE_EVT;
- dd_data->context_un.evt = evt;
- evt->set_job = job; /* for unsolicited command */
+ dd_data->set_job = job; /* for unsolicited command */
job->dd_data = dd_data; /* for fc transport timeout callback*/
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
return 0; /* call job done later */
@@ -1252,57 +1342,64 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp;
struct lpfc_nodelist *ndlp;
unsigned long flags;
int rc = 0;
+ dd_data = cmdiocbq->context1;
+
+ /* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
- dd_data = cmdiocbq->context2;
- /* normal completion and timeout crossed paths, already done */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = dd_data->context_un.iocb.set_job;
- bmp = dd_data->context_un.iocb.bmp;
- rsp = &rspiocbq->iocb;
ndlp = dd_data->context_un.iocb.ndlp;
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
+ rsp = &rspiocbq->iocb;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ /* Copy the completed job data or set the error status */
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ job->reply->reply_payload_rcv_len = 0;
+ }
+ }
+ lpfc_free_bsg_buffers(phba, cmp);
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+ kfree(bmp);
lpfc_sli_release_iocbq(phba, cmdiocbq);
lpfc_nlp_put(ndlp);
- kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- job->dd_data = NULL;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if the job is still active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
return;
}
@@ -1316,7 +1413,8 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
**/
static int
lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
- struct lpfc_dmabuf *bmp, int num_entry)
+ struct lpfc_dmabuf *cmp, struct lpfc_dmabuf *bmp,
+ int num_entry)
{
IOCB_t *icmd;
struct lpfc_iocbq *ctiocb = NULL;
@@ -1377,7 +1475,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
/* Check if the ndlp is active */
if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) {
- rc = -IOCB_ERROR;
+ rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
@@ -1385,7 +1483,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
* we respond
*/
if (!lpfc_nlp_get(ndlp)) {
- rc = -IOCB_ERROR;
+ rc = IOCB_ERROR;
goto issue_ct_rsp_exit;
}
@@ -1407,17 +1505,17 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
ctiocb->iocb_cmpl = NULL;
ctiocb->iocb_flag |= LPFC_IO_LIBDFC;
ctiocb->vport = phba->pport;
+ ctiocb->context1 = dd_data;
+ ctiocb->context2 = cmp;
ctiocb->context3 = bmp;
-
ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
- ctiocb->context2 = dd_data;
- ctiocb->context1 = ndlp;
+
dd_data->type = TYPE_IOCB;
+ dd_data->set_job = job;
dd_data->context_un.iocb.cmdiocbq = ctiocb;
- dd_data->context_un.iocb.rspiocbq = NULL;
- dd_data->context_un.iocb.set_job = job;
- dd_data->context_un.iocb.bmp = bmp;
dd_data->context_un.iocb.ndlp = ndlp;
+ dd_data->context_un.iocb.rmp = NULL;
+ job->dd_data = dd_data;
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
if (lpfc_readl(phba->HCregaddr, &creg_val)) {
@@ -1454,11 +1552,8 @@ lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job)
struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *)
job->request->rqst_data.h_vendor.vendor_cmd;
struct ulp_bde64 *bpl;
- struct lpfc_dmabuf *bmp = NULL;
- struct scatterlist *sgel = NULL;
- int request_nseg;
- int numbde;
- dma_addr_t busaddr;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL;
+ int bpl_entries;
uint32_t tag = mgmt_resp->tag;
unsigned long reqbfrcnt =
(unsigned long)job->request_payload.payload_len;
@@ -1486,30 +1581,28 @@ lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job)
INIT_LIST_HEAD(&bmp->list);
bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl_entries = (LPFC_BPL_SIZE/sizeof(struct ulp_bde64));
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &bpl_entries);
+ if (!cmp) {
+ rc = -ENOMEM;
+ goto send_mgmt_rsp_free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg);
+ rc = lpfc_issue_ct_rsp(phba, job, tag, cmp, bmp, bpl_entries);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
- /* TBD need to handle a timeout */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
rc = -EACCES;
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
+
+ lpfc_free_bsg_buffers(phba, cmp);
send_mgmt_rsp_free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
send_mgmt_rsp_exit:
/* make error code available to userspace */
@@ -1559,7 +1652,7 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
scsi_block_requests(shost);
}
- while (pring->txcmplq_cnt) {
+ while (!list_empty(&pring->txcmplq)) {
if (i++ > 500) /* wait up to 5 seconds */
break;
msleep(10);
@@ -3193,13 +3286,7 @@ lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
unsigned long flags;
uint8_t *pmb, *pmb_buf;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = pmboxq->context1;
- /* job already timed out? */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
/*
* The outgoing buffer is readily referred from the dma buffer,
@@ -3209,29 +3296,33 @@ lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
memcpy(pmb_buf, pmb, sizeof(MAILBOX_t));
- job = dd_data->context_un.mbox.set_job;
+ /* Determine if job has been aborted */
+
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Copy the mailbox data to the job if it is still active */
+
if (job) {
size = job->reply_payload.payload_len;
job->reply->reply_payload_rcv_len =
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
pmb_buf, size);
- /* need to hold the lock until we set job->dd_data to NULL
- * to hold off the timeout handler returning to the mid-layer
- * while we are still processing the job.
- */
- job->dd_data = NULL;
- dd_data->context_un.mbox.set_job = NULL;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- } else {
- dd_data->context_un.mbox.set_job = NULL;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
}
+ dd_data->set_job = NULL;
mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool);
lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers);
kfree(dd_data);
+ /* Complete the job if the job is still active */
+
if (job) {
job->reply->result = 0;
job->job_done(job);
@@ -3377,19 +3468,22 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
struct lpfc_sli_config_mbox *sli_cfg_mbx;
uint8_t *pmbx;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = pmboxq->context1;
- /* has the job already timed out? */
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job = NULL;
- goto job_done_out;
+
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
}
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
/*
* The outgoing buffer is readily referred from the dma buffer,
* just need to get header part from mailboxq structure.
*/
+
pmb = (uint8_t *)&pmboxq->u.mb;
pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb;
/* Copy the byte swapped response mailbox back to the user */
@@ -3406,21 +3500,18 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len);
}
- job = dd_data->context_un.mbox.set_job;
+ /* Complete the job if the job is still active */
+
if (job) {
size = job->reply_payload.payload_len;
job->reply->reply_payload_rcv_len =
sg_copy_from_buffer(job->reply_payload.sg_list,
job->reply_payload.sg_cnt,
pmb_buf, size);
+
/* result for successful */
job->reply->result = 0;
- job->dd_data = NULL;
- /* need to hold the lock util we set job->dd_data to NULL
- * to hold off the timeout handler from midlayer to take
- * any action.
- */
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"2937 SLI_CONFIG ext-buffer maibox command "
"(x%x/x%x) complete bsg job done, bsize:%d\n",
@@ -3431,20 +3522,18 @@ lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
phba->mbox_ext_buf_ctx.mboxType,
dma_ebuf, sta_pos_addr,
phba->mbox_ext_buf_ctx.mbx_dmabuf, 0);
- } else
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
-
-job_done_out:
- if (!job)
+ } else {
lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC,
"2938 SLI_CONFIG ext-buffer maibox "
"command (x%x/x%x) failure, rc:x%x\n",
phba->mbox_ext_buf_ctx.nembType,
phba->mbox_ext_buf_ctx.mboxType, rc);
+ }
+
+
/* state change */
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE;
kfree(dd_data);
-
return job;
}
@@ -3461,8 +3550,10 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
struct fc_bsg_job *job;
+ job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
+
/* handle the BSG job with mailbox command */
- if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+ if (!job)
pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3470,15 +3561,13 @@ lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
"complete, ctxState:x%x, mbxStatus:x%x\n",
phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
- job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
-
if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1)
lpfc_bsg_mbox_ext_session_reset(phba);
/* free base driver mailbox structure memory */
mempool_free(pmboxq, phba->mbox_mem_pool);
- /* complete the bsg job if we have it */
+ /* if the job is still active, call job done */
if (job)
job->job_done(job);
@@ -3498,8 +3587,10 @@ lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
struct fc_bsg_job *job;
+ job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
+
/* handle the BSG job with the mailbox command */
- if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS)
+ if (!job)
pmboxq->u.mb.mbxStatus = MBXERR_ERROR;
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3507,13 +3598,11 @@ lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
"complete, ctxState:x%x, mbxStatus:x%x\n",
phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus);
- job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq);
-
/* free all memory, including dma buffers */
mempool_free(pmboxq, phba->mbox_mem_pool);
lpfc_bsg_mbox_ext_session_reset(phba);
- /* complete the bsg job if we have it */
+ /* if the job is still active, call job done */
if (job)
job->job_done(job);
@@ -3759,9 +3848,9 @@ lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
@@ -3928,14 +4017,14 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
- phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
+ phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT;
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) {
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
@@ -3951,6 +4040,7 @@ lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job,
}
/* wait for additoinal external buffers */
+
job->reply->result = 0;
job->job_done(job);
return SLI_CONFIG_HANDLED;
@@ -4268,9 +4358,9 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* context fields to callback function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf;
- dd_data->context_un.mbox.set_job = job;
job->dd_data = dd_data;
/* state change */
@@ -4455,7 +4545,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
uint8_t *from;
uint32_t size;
-
/* in case no data is transferred */
job->reply->reply_payload_rcv_len = 0;
@@ -4681,9 +4770,9 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
/* setup context field to pass wait_queue pointer to wake function */
pmboxq->context1 = dd_data;
dd_data->type = TYPE_MBOX;
+ dd_data->set_job = job;
dd_data->context_un.mbox.pmboxq = pmboxq;
dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx;
- dd_data->context_un.mbox.set_job = job;
dd_data->context_un.mbox.ext = ext;
dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset;
dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen;
@@ -4741,7 +4830,7 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job)
if (job->request_len <
sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) {
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
- "2737 Mix-and-match backward compability "
+ "2737 Mix-and-match backward compatibility "
"between MBOX_REQ old size:%d and "
"new request size:%d\n",
(int)(job->request_len -
@@ -4797,75 +4886,79 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
struct bsg_job_data *dd_data;
struct fc_bsg_job *job;
IOCB_t *rsp;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_dmabuf *bmp, *cmp, *rmp;
struct lpfc_bsg_menlo *menlo;
unsigned long flags;
struct menlo_response *menlo_resp;
+ unsigned int rsp_size;
int rc = 0;
- spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = cmdiocbq->context1;
- if (!dd_data) {
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return;
- }
-
+ cmp = cmdiocbq->context2;
+ bmp = cmdiocbq->context3;
menlo = &dd_data->context_un.menlo;
- job = menlo->set_job;
- job->dd_data = NULL; /* so timeout handler does not reply */
-
- spin_lock(&phba->hbalock);
- cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
- &rspiocbq->iocb, sizeof(IOCB_t));
- spin_unlock(&phba->hbalock);
-
- bmp = menlo->bmp;
- rspiocbq = menlo->rspiocbq;
+ rmp = menlo->rmp;
rsp = &rspiocbq->iocb;
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ /* Determine if job has been aborted */
+ spin_lock_irqsave(&phba->ct_ev_lock, flags);
+ job = dd_data->set_job;
+ if (job) {
+ /* Prevent timeout handling from trying to abort job */
+ job->dd_data = NULL;
+ }
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Copy the job data or set the failing status for the job */
- /* always return the xri, this would be used in the case
- * of a menlo download to allow the data to be sent as a continuation
- * of the exchange.
- */
- menlo_resp = (struct menlo_response *)
- job->reply->reply_data.vendor_reply.vendor_rsp;
- menlo_resp->xri = rsp->ulpContext;
- if (rsp->ulpStatus) {
- if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
- switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
- case IOERR_SEQUENCE_TIMEOUT:
- rc = -ETIMEDOUT;
- break;
- case IOERR_INVALID_RPI:
- rc = -EFAULT;
- break;
- default:
+ if (job) {
+ /* always return the xri, this would be used in the case
+ * of a menlo download to allow the data to be sent as a
+ * continuation of the exchange.
+ */
+
+ menlo_resp = (struct menlo_response *)
+ job->reply->reply_data.vendor_reply.vendor_rsp;
+ menlo_resp->xri = rsp->ulpContext;
+ if (rsp->ulpStatus) {
+ if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) {
+ switch (rsp->un.ulpWord[4] & IOERR_PARAM_MASK) {
+ case IOERR_SEQUENCE_TIMEOUT:
+ rc = -ETIMEDOUT;
+ break;
+ case IOERR_INVALID_RPI:
+ rc = -EFAULT;
+ break;
+ default:
+ rc = -EACCES;
+ break;
+ }
+ } else {
rc = -EACCES;
- break;
}
- } else
- rc = -EACCES;
- } else
- job->reply->reply_payload_rcv_len =
- rsp->un.genreq64.bdl.bdeSize;
+ } else {
+ rsp_size = rsp->un.genreq64.bdl.bdeSize;
+ job->reply->reply_payload_rcv_len =
+ lpfc_bsg_copy_data(rmp, &job->reply_payload,
+ rsp_size, 0);
+ }
+
+ }
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- lpfc_sli_release_iocbq(phba, rspiocbq);
lpfc_sli_release_iocbq(phba, cmdiocbq);
+ lpfc_free_bsg_buffers(phba, cmp);
+ lpfc_free_bsg_buffers(phba, rmp);
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
kfree(dd_data);
- /* make error code available to userspace */
- job->reply->result = rc;
- /* complete the job back to userspace */
- job->job_done(job);
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+ /* Complete the job if active */
+
+ if (job) {
+ job->reply->result = rc;
+ job->job_done(job);
+ }
+
return;
}
@@ -4883,17 +4976,14 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
{
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
- struct lpfc_iocbq *cmdiocbq, *rspiocbq;
- IOCB_t *cmd, *rsp;
+ struct lpfc_iocbq *cmdiocbq;
+ IOCB_t *cmd;
int rc = 0;
struct menlo_command *menlo_cmd;
struct menlo_response *menlo_resp;
- struct lpfc_dmabuf *bmp = NULL;
+ struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL;
int request_nseg;
int reply_nseg;
- struct scatterlist *sgel = NULL;
- int numbde;
- dma_addr_t busaddr;
struct bsg_job_data *dd_data;
struct ulp_bde64 *bpl = NULL;
@@ -4948,50 +5038,38 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
goto free_dd;
}
- cmdiocbq = lpfc_sli_get_iocbq(phba);
- if (!cmdiocbq) {
+ bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
+ if (!bmp->virt) {
rc = -ENOMEM;
goto free_bmp;
}
- rspiocbq = lpfc_sli_get_iocbq(phba);
- if (!rspiocbq) {
- rc = -ENOMEM;
- goto free_cmdiocbq;
- }
-
- rsp = &rspiocbq->iocb;
+ INIT_LIST_HEAD(&bmp->list);
- bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys);
- if (!bmp->virt) {
+ bpl = (struct ulp_bde64 *)bmp->virt;
+ request_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64);
+ cmp = lpfc_alloc_bsg_buffers(phba, job->request_payload.payload_len,
+ 1, bpl, &request_nseg);
+ if (!cmp) {
rc = -ENOMEM;
- goto free_rspiocbq;
+ goto free_bmp;
}
+ lpfc_bsg_copy_data(cmp, &job->request_payload,
+ job->request_payload.payload_len, 1);
- INIT_LIST_HEAD(&bmp->list);
- bpl = (struct ulp_bde64 *) bmp->virt;
- request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ bpl += request_nseg;
+ reply_nseg = LPFC_BPL_SIZE/sizeof(struct ulp_bde64) - request_nseg;
+ rmp = lpfc_alloc_bsg_buffers(phba, job->reply_payload.payload_len, 0,
+ bpl, &reply_nseg);
+ if (!rmp) {
+ rc = -ENOMEM;
+ goto free_cmp;
}
- reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
- for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) {
- busaddr = sg_dma_address(sgel);
- bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
- bpl->tus.f.bdeSize = sg_dma_len(sgel);
- bpl->tus.w = cpu_to_le32(bpl->tus.w);
- bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr));
- bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr));
- bpl++;
+ cmdiocbq = lpfc_sli_get_iocbq(phba);
+ if (!cmdiocbq) {
+ rc = -ENOMEM;
+ goto free_rmp;
}
cmd = &cmdiocbq->iocb;
@@ -5013,11 +5091,10 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
cmdiocbq->vport = phba->pport;
/* We want the firmware to timeout before we do */
cmd->ulpTimeout = MENLO_TIMEOUT - 5;
- cmdiocbq->context3 = bmp;
- cmdiocbq->context2 = rspiocbq;
cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp;
cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = rspiocbq;
+ cmdiocbq->context2 = cmp;
+ cmdiocbq->context3 = bmp;
if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) {
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->ulpPU = MENLO_PU; /* 3 */
@@ -5031,29 +5108,25 @@ lpfc_menlo_cmd(struct fc_bsg_job *job)
}
dd_data->type = TYPE_MENLO;
+ dd_data->set_job = job;
dd_data->context_un.menlo.cmdiocbq = cmdiocbq;
- dd_data->context_un.menlo.rspiocbq = rspiocbq;
- dd_data->context_un.menlo.set_job = job;
- dd_data->context_un.menlo.bmp = bmp;
+ dd_data->context_un.menlo.rmp = rmp;
+ job->dd_data = dd_data;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq,
MENLO_TIMEOUT - 5);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
- /* iocb failed so cleanup */
- pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
- job->request_payload.sg_cnt, DMA_TO_DEVICE);
- pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list,
- job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
-
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
-
-free_rspiocbq:
- lpfc_sli_release_iocbq(phba, rspiocbq);
-free_cmdiocbq:
lpfc_sli_release_iocbq(phba, cmdiocbq);
+
+free_rmp:
+ lpfc_free_bsg_buffers(phba, rmp);
+free_cmp:
+ lpfc_free_bsg_buffers(phba, cmp);
free_bmp:
+ if (bmp->virt)
+ lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
free_dd:
kfree(dd_data);
@@ -5162,70 +5235,94 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata;
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
- struct lpfc_bsg_event *evt;
- struct lpfc_bsg_iocb *iocb;
- struct lpfc_bsg_mbox *mbox;
- struct lpfc_bsg_menlo *menlo;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct bsg_job_data *dd_data;
unsigned long flags;
+ int rc = 0;
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *check_iocb, *next_iocb;
+
+ /* if job's driver data is NULL, the command completed or is in the
+ * the process of completing. In this case, return status to request
+ * so the timeout is retried. This avoids double completion issues
+ * and the request will be pulled off the timer queue when the
+ * command's completion handler executes. Otherwise, prevent the
+ * command's completion handler from executing the job done callback
+ * and continue processing to abort the outstanding the command.
+ */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
dd_data = (struct bsg_job_data *)job->dd_data;
- /* timeout and completion crossed paths if no dd_data */
- if (!dd_data) {
+ if (dd_data) {
+ dd_data->set_job = NULL;
+ job->dd_data = NULL;
+ } else {
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- return 0;
+ return -EAGAIN;
}
switch (dd_data->type) {
case TYPE_IOCB:
- iocb = &dd_data->context_un.iocb;
- cmdiocb = iocb->cmdiocbq;
- /* hint to completion handler that the job timed out */
- job->reply->result = -EAGAIN;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- /* this will call our completion handler */
+ /* Check to see if IOCB was issued to the port or not. If not,
+ * remove it from the txq queue and call cancel iocbs.
+ * Otherwise, call abort iotag
+ */
+
+ cmdiocb = dd_data->context_un.iocb.cmdiocbq;
spin_lock_irq(&phba->hbalock);
- lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+ list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
+ list) {
+ if (check_iocb == cmdiocb) {
+ list_move_tail(&check_iocb->list, &completions);
+ break;
+ }
+ }
+ if (list_empty(&completions))
+ lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ if (!list_empty(&completions)) {
+ lpfc_sli_cancel_iocbs(phba, &completions,
+ IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+ }
break;
+
case TYPE_EVT:
- evt = dd_data->context_un.evt;
- /* this event has no job anymore */
- evt->set_job = NULL;
- job->dd_data = NULL;
- job->reply->reply_payload_rcv_len = 0;
- /* Return -EAGAIN which is our way of signallying the
- * app to retry.
- */
- job->reply->result = -EAGAIN;
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job->job_done(job);
break;
+
case TYPE_MBOX:
- mbox = &dd_data->context_un.mbox;
- /* this mbox has no job anymore */
- mbox->set_job = NULL;
- job->dd_data = NULL;
- job->reply->reply_payload_rcv_len = 0;
- job->reply->result = -EAGAIN;
- /* the mbox completion handler can now be run */
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- job->job_done(job);
+ /* Update the ext buf ctx state if needed */
+
if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT)
phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS;
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
break;
case TYPE_MENLO:
- menlo = &dd_data->context_un.menlo;
- cmdiocb = menlo->cmdiocbq;
- /* hint to completion handler that the job timed out */
- job->reply->result = -EAGAIN;
- spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
- /* this will call our completion handler */
+ /* Check to see if IOCB was issued to the port or not. If not,
+ * remove it from the txq queue and call cancel iocbs.
+ * Otherwise, call abort iotag.
+ */
+
+ cmdiocb = dd_data->context_un.menlo.cmdiocbq;
spin_lock_irq(&phba->hbalock);
- lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
+ list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
+ list) {
+ if (check_iocb == cmdiocb) {
+ list_move_tail(&check_iocb->list, &completions);
+ break;
+ }
+ }
+ if (list_empty(&completions))
+ lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
spin_unlock_irq(&phba->hbalock);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+ if (!list_empty(&completions)) {
+ lpfc_sli_cancel_iocbs(phba, &completions,
+ IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+ }
break;
default:
spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
@@ -5236,5 +5333,5 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
* otherwise an error message will be displayed on the console
* so always return success (zero)
*/
- return 0;
+ return rc;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 76ca65dae781..7631893ae005 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -106,6 +106,7 @@ void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_cleanup(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
+int lpfc_unregister_fcf_prep(struct lpfc_hba *);
struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
void lpfc_worker_wake_up(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 08d156a9094f..bbed8471bf0b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -484,6 +484,7 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
vport->port_state = LPFC_FABRIC_CFG_LINK;
memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam));
lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
+
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
mboxq->context1 = dmabuf;
@@ -700,6 +701,20 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
}
}
+ /*
+ * For FC we need to do some special processing because of the SLI
+ * Port's default settings of the Common Service Parameters.
+ */
+ if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) {
+ /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */
+ if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed)
+ lpfc_unregister_fcf_prep(phba);
+
+ /* This should just update the VFI CSPs*/
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ lpfc_issue_reg_vfi(vport);
+ }
+
if (fabric_param_changed &&
!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
@@ -6225,7 +6240,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
spin_unlock_irq(&phba->hbalock);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ if (!list_empty(&phba->sli.ring[LPFC_ELS_RING].txcmplq))
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
}
@@ -6279,7 +6294,6 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
continue;
list_move_tail(&piocb->list, &completions);
- pring->txq_cnt--;
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -6339,7 +6353,6 @@ lpfc_els_flush_all_cmd(struct lpfc_hba *phba)
cmd->ulpCommand == CMD_ABORT_XRI_CN)
continue;
list_move_tail(&piocb->list, &completions);
- pring->txq_cnt--;
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
if (piocb->iocb_flag & LPFC_IO_LIBDFC)
@@ -8065,7 +8078,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba,
rxid, 1);
/* Check if TXQ queue needs to be serviced */
- if (pring->txq_cnt)
+ if (!(list_empty(&pring->txq)))
lpfc_worker_wake_up(phba);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index d7096ad94d3f..326e05a65a73 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -691,12 +691,15 @@ lpfc_work_done(struct lpfc_hba *phba)
/* Set the lpfc data pending flag */
set_bit(LPFC_DATA_READY, &phba->data_flags);
} else {
- pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
- lpfc_sli_handle_slow_ring_event(phba, pring,
- (status &
- HA_RXMASK));
+ if (phba->link_state >= LPFC_LINK_UP) {
+ pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+ lpfc_sli_handle_slow_ring_event(phba, pring,
+ (status &
+ HA_RXMASK));
+ }
}
- if ((phba->sli_rev == LPFC_SLI_REV4) && pring->txq_cnt)
+ if ((phba->sli_rev == LPFC_SLI_REV4) &
+ (!list_empty(&pring->txq)))
lpfc_drain_txq(phba);
/*
* Turn on Ring interrupts
@@ -1732,7 +1735,7 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* use through a sequence of @fcf_cnt eligible FCF records with equal
* probability. To perform integer manunipulation of random numbers with
* size unit32_t, the lower 16 bits of the 32-bit random number returned
- * from random32() are taken as the random random number generated.
+ * from prandom_u32() are taken as the random random number generated.
*
* Returns true when outcome is for the newly read FCF record should be
* chosen; otherwise, return false when outcome is for keeping the previously
@@ -1744,7 +1747,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt)
uint32_t rand_num;
/* Get 16-bit uniform random number */
- rand_num = (0xFFFF & random32());
+ rand_num = 0xFFFF & prandom_u32();
/* Decision with probability 1/fcf_cnt */
if ((fcf_cnt * rand_num) < 0xFFFF)
@@ -1792,6 +1795,8 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
virt_addr = mboxq->sge_array->addr[0];
shdr = (union lpfc_sli4_cfg_shdr *)virt_addr;
+ lpfc_sli_pcimem_bcopy(shdr, shdr,
+ sizeof(union lpfc_sli4_cfg_shdr));
shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response);
shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response);
if (shdr_status || shdr_add_status) {
@@ -2380,7 +2385,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.eligible_fcf_cnt = 1;
/* Seeding the random number generator for random selection */
seed = (uint32_t)(0xFFFFFFFF & jiffies);
- srandom32(seed);
+ prandom_seed(seed);
}
spin_unlock_irq(&phba->hbalock);
goto read_next_fcf;
@@ -2888,6 +2893,11 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
goto out_free_mem;
}
+
+ /* If the VFI is already registered, there is nothing else to do */
+ if (vport->fc_flag & FC_VFI_REGISTERED)
+ goto out_free_mem;
+
/* The VPI is implicitly registered when the VFI is registered */
spin_lock_irq(shost->host_lock);
vport->vpi_state |= LPFC_VPI_REGISTERED;
@@ -2980,6 +2990,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
struct lpfc_dmabuf *mp;
int rc;
struct fcf_record *fcf_record;
+ uint32_t fc_flags = 0;
spin_lock_irq(&phba->hbalock);
switch (bf_get(lpfc_mbx_read_top_link_spd, la)) {
@@ -3011,11 +3022,8 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
"1309 Link Up Event npiv not supported in loop "
"topology\n");
/* Get Loop Map information */
- if (bf_get(lpfc_mbx_read_top_il, la)) {
- spin_lock(shost->host_lock);
- vport->fc_flag |= FC_LBIT;
- spin_unlock(shost->host_lock);
- }
+ if (bf_get(lpfc_mbx_read_top_il, la))
+ fc_flags |= FC_LBIT;
vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la);
i = la->lilpBde64.tus.f.bdeSize;
@@ -3064,12 +3072,16 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
}
vport->fc_myDID = phba->fc_pref_DID;
- spin_lock(shost->host_lock);
- vport->fc_flag |= FC_LBIT;
- spin_unlock(shost->host_lock);
+ fc_flags |= FC_LBIT;
}
spin_unlock_irq(&phba->hbalock);
+ if (fc_flags) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= fc_flags;
+ spin_unlock_irq(shost->host_lock);
+ }
+
lpfc_linkup(phba);
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!sparam_mbox)
@@ -3237,8 +3249,7 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
vport->fc_flag &= ~FC_BYPASSED_MODE;
spin_unlock_irq(shost->host_lock);
- if ((phba->fc_eventTag < la->eventTag) ||
- (phba->fc_eventTag == la->eventTag)) {
+ if (phba->fc_eventTag <= la->eventTag) {
phba->fc_stat.LinkMultiEvent++;
if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)
if (phba->fc_eventTag != 0)
@@ -3246,16 +3257,18 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
phba->fc_eventTag = la->eventTag;
- spin_lock_irq(&phba->hbalock);
- if (bf_get(lpfc_mbx_read_top_mm, la))
- phba->sli.sli_flag |= LPFC_MENLO_MAINT;
- else
- phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
- spin_unlock_irq(&phba->hbalock);
+ if (phba->sli_rev < LPFC_SLI_REV4) {
+ spin_lock_irq(&phba->hbalock);
+ if (bf_get(lpfc_mbx_read_top_mm, la))
+ phba->sli.sli_flag |= LPFC_MENLO_MAINT;
+ else
+ phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
+ spin_unlock_irq(&phba->hbalock);
+ }
phba->link_events++;
if ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) &&
- (!bf_get(lpfc_mbx_read_top_mm, la))) {
+ !(phba->sli.sli_flag & LPFC_MENLO_MAINT)) {
phba->fc_stat.LinkUp++;
if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -3300,8 +3313,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
bf_get(lpfc_mbx_read_top_fa, la));
lpfc_mbx_issue_link_down(phba);
}
- if ((bf_get(lpfc_mbx_read_top_mm, la)) &&
- (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)) {
+ if ((phba->sli.sli_flag & LPFC_MENLO_MAINT) &&
+ ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP))) {
if (phba->link_state != LPFC_LINK_DOWN) {
phba->fc_stat.LinkDown++;
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
@@ -3329,8 +3342,9 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
}
- if (bf_get(lpfc_mbx_read_top_fa, la)) {
- if (bf_get(lpfc_mbx_read_top_mm, la))
+ if ((phba->sli_rev < LPFC_SLI_REV4) &&
+ bf_get(lpfc_mbx_read_top_fa, la)) {
+ if (phba->sli.sli_flag & LPFC_MENLO_MAINT)
lpfc_issue_clear_la(phba, vport);
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"1311 fa %d\n",
@@ -4354,7 +4368,6 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
with an error */
list_move_tail(&iocb->list,
&completions);
- pring->txq_cnt--;
}
}
spin_unlock_irq(&phba->hbalock);
@@ -5055,7 +5068,6 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
(icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 6e93b886cd4d..1dd2f6f0a127 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1958,6 +1958,9 @@ struct lpfc_mbx_init_vfi {
struct lpfc_mbx_reg_vfi {
uint32_t word1;
+#define lpfc_reg_vfi_upd_SHIFT 29
+#define lpfc_reg_vfi_upd_MASK 0x00000001
+#define lpfc_reg_vfi_upd_WORD word1
#define lpfc_reg_vfi_vp_SHIFT 28
#define lpfc_reg_vfi_vp_MASK 0x00000001
#define lpfc_reg_vfi_vp_WORD word1
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 8b9c191a7019..90b8b0515e23 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -839,7 +839,6 @@ lpfc_hba_down_post_s3(struct lpfc_hba *phba)
* way, nothing should be on txcmplq as it will NEVER complete.
*/
list_splice_init(&pring->txcmplq, &completions);
- pring->txcmplq_cnt = 0;
spin_unlock_irq(&phba->hbalock);
/* Cancel all the IOCBs from the completions list */
@@ -2915,9 +2914,9 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
sglq_entry->state = SGL_FREED;
list_add_tail(&sglq_entry->list, &els_sgl_list);
}
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
} else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) {
/* els xri-sgl shrinked */
xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt;
@@ -3015,9 +3014,9 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
psb->cur_iocbq.sli4_lxritag = lxri;
psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
}
- spin_lock(&phba->scsi_buf_list_lock);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list);
- spin_unlock(&phba->scsi_buf_list_lock);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
return 0;
@@ -4004,6 +4003,52 @@ lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba)
}
/**
+ * lpfc_sli4_perform_inuse_fcf_recovery - Perform inuse fcf recovery
+ * @vport: pointer to lpfc hba data structure.
+ *
+ * This routine is to perform FCF recovery when the in-use FCF either dead or
+ * got modified.
+ **/
+static void
+lpfc_sli4_perform_inuse_fcf_recovery(struct lpfc_hba *phba,
+ struct lpfc_acqe_fip *acqe_fip)
+{
+ int rc;
+
+ spin_lock_irq(&phba->hbalock);
+ /* Mark the fast failover process in progress */
+ phba->fcf.fcf_flag |= FCF_DEAD_DISC;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+ "2771 Start FCF fast failover process due to in-use "
+ "FCF DEAD/MODIFIED event: evt_tag:x%x, index:x%x\n",
+ acqe_fip->event_tag, acqe_fip->index);
+ rc = lpfc_sli4_redisc_fcf_table(phba);
+ if (rc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY,
+ "2772 Issue FCF rediscover mabilbox command "
+ "failed, fail through to FCF dead event\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
+ spin_unlock_irq(&phba->hbalock);
+ /*
+ * Last resort will fail over by treating this as a link
+ * down to FCF registration.
+ */
+ lpfc_sli4_fcf_dead_failthrough(phba);
+ } else {
+ /* Reset FCF roundrobin bmask for new discovery */
+ lpfc_sli4_clear_fcf_rr_bmask(phba);
+ /*
+ * Handling fast FCF failover to a DEAD FCF event is
+ * considered equalivant to receiving CVL to all vports.
+ */
+ lpfc_sli4_perform_all_vport_cvl(phba);
+ }
+}
+
+/**
* lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event
* @phba: pointer to lpfc hba data structure.
* @acqe_link: pointer to the async fcoe completion queue entry.
@@ -4068,9 +4113,22 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
break;
}
- /* If the FCF has been in discovered state, do nothing. */
- if (phba->fcf.fcf_flag & FCF_SCAN_DONE) {
+ /* If FCF has been in discovered state, perform rediscovery
+ * only if the FCF with the same index of the in-use FCF got
+ * modified during normal operation. Otherwise, do nothing.
+ */
+ if (phba->pport->port_state > LPFC_FLOGI) {
spin_unlock_irq(&phba->hbalock);
+ if (phba->fcf.current_rec.fcf_indx ==
+ acqe_fip->index) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
+ "3300 In-use FCF (%d) "
+ "modified, perform FCF "
+ "rediscovery\n",
+ acqe_fip->index);
+ lpfc_sli4_perform_inuse_fcf_recovery(phba,
+ acqe_fip);
+ }
break;
}
spin_unlock_irq(&phba->hbalock);
@@ -4123,39 +4181,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba,
* is no longer valid as we are not in the middle of FCF
* failover process already.
*/
- spin_lock_irq(&phba->hbalock);
- /* Mark the fast failover process in progress */
- phba->fcf.fcf_flag |= FCF_DEAD_DISC;
- spin_unlock_irq(&phba->hbalock);
-
- lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
- "2771 Start FCF fast failover process due to "
- "FCF DEAD event: evt_tag:x%x, fcf_index:x%x "
- "\n", acqe_fip->event_tag, acqe_fip->index);
- rc = lpfc_sli4_redisc_fcf_table(phba);
- if (rc) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FIP |
- LOG_DISCOVERY,
- "2772 Issue FCF rediscover mabilbox "
- "command failed, fail through to FCF "
- "dead event\n");
- spin_lock_irq(&phba->hbalock);
- phba->fcf.fcf_flag &= ~FCF_DEAD_DISC;
- spin_unlock_irq(&phba->hbalock);
- /*
- * Last resort will fail over by treating this
- * as a link down to FCF registration.
- */
- lpfc_sli4_fcf_dead_failthrough(phba);
- } else {
- /* Reset FCF roundrobin bmask for new discovery */
- lpfc_sli4_clear_fcf_rr_bmask(phba);
- /*
- * Handling fast FCF failover to a DEAD FCF event is
- * considered equalivant to receiving CVL to all vports.
- */
- lpfc_sli4_perform_all_vport_cvl(phba);
- }
+ lpfc_sli4_perform_inuse_fcf_recovery(phba, acqe_fip);
break;
case LPFC_FIP_EVENT_TYPE_CVL:
phba->fcoe_cvl_eventtag = acqe_fip->event_tag;
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index efc9cd9def8b..a7a9fa468308 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -2126,32 +2126,40 @@ void
lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys)
{
struct lpfc_mbx_reg_vfi *reg_vfi;
+ struct lpfc_hba *phba = vport->phba;
memset(mbox, 0, sizeof(*mbox));
reg_vfi = &mbox->u.mqe.un.reg_vfi;
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI);
bf_set(lpfc_reg_vfi_vp, reg_vfi, 1);
bf_set(lpfc_reg_vfi_vfi, reg_vfi,
- vport->phba->sli4_hba.vfi_ids[vport->vfi]);
- bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi);
- bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->phba->vpi_ids[vport->vpi]);
+ phba->sli4_hba.vfi_ids[vport->vfi]);
+ bf_set(lpfc_reg_vfi_fcfi, reg_vfi, phba->fcf.fcfi);
+ bf_set(lpfc_reg_vfi_vpi, reg_vfi, phba->vpi_ids[vport->vpi]);
memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name));
reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]);
reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]);
- reg_vfi->e_d_tov = vport->phba->fc_edtov;
- reg_vfi->r_a_tov = vport->phba->fc_ratov;
+ reg_vfi->e_d_tov = phba->fc_edtov;
+ reg_vfi->r_a_tov = phba->fc_ratov;
reg_vfi->bde.addrHigh = putPaddrHigh(phys);
reg_vfi->bde.addrLow = putPaddrLow(phys);
reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam);
reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID);
+
+ /* Only FC supports upd bit */
+ if ((phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) &&
+ (vport->fc_flag & FC_VFI_REGISTERED)) {
+ bf_set(lpfc_reg_vfi_vp, reg_vfi, 0);
+ bf_set(lpfc_reg_vfi_upd, reg_vfi, 1);
+ }
lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX,
"3134 Register VFI, mydid:x%x, fcfi:%d, "
" vfi:%d, vpi:%d, fc_pname:%x%x\n",
vport->fc_myDID,
- vport->phba->fcf.fcfi,
- vport->phba->sli4_hba.vfi_ids[vport->vfi],
- vport->phba->vpi_ids[vport->vpi],
+ phba->fcf.fcfi,
+ phba->sli4_hba.vfi_ids[vport->vfi],
+ phba->vpi_ids[vport->vpi],
reg_vfi->wwn[0], reg_vfi->wwn[1]);
}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 46128c679202..82f4d3542289 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -226,7 +226,6 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
/* It matches, so deque and call compl with anp error */
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 98af07c6e300..74b8710e1e90 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -732,7 +732,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba,
psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
psb->exch_busy = 0;
spin_unlock_irqrestore(&phba->hbalock, iflag);
- if (pring->txq_cnt)
+ if (!list_empty(&pring->txq))
lpfc_worker_wake_up(phba);
return;
@@ -885,9 +885,9 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
int num_posted, rc = 0;
/* get all SCSI buffers need to repost to a local list */
- spin_lock(&phba->scsi_buf_list_lock);
+ spin_lock_irq(&phba->scsi_buf_list_lock);
list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist);
- spin_unlock(&phba->scsi_buf_list_lock);
+ spin_unlock_irq(&phba->scsi_buf_list_lock);
/* post the list of scsi buffer sgls to port if available */
if (!list_empty(&post_sblist)) {
@@ -4246,7 +4246,7 @@ static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba)
unsigned long poll_tmo_expires =
(jiffies + msecs_to_jiffies(phba->cfg_poll_tmo));
- if (phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt)
+ if (!list_empty(&phba->sli.ring[LPFC_FCP_RING].txcmplq))
mod_timer(&phba->fcp_poll_timer,
poll_tmo_expires);
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 74b67d98e952..35dd17eb0f27 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -438,11 +438,12 @@ lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq,
struct lpfc_rqe *temp_hrqe;
struct lpfc_rqe *temp_drqe;
struct lpfc_register doorbell;
- int put_index = hq->host_index;
+ int put_index;
/* sanity check on queue memory */
if (unlikely(!hq) || unlikely(!dq))
return -ENOMEM;
+ put_index = hq->host_index;
temp_hrqe = hq->qe[hq->host_index].rqe;
temp_drqe = dq->qe[dq->host_index].rqe;
@@ -872,14 +873,16 @@ lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
xritag, rxid, ndlp->nlp_DID, send_rrq);
return -EINVAL;
}
- rrq->send_rrq = send_rrq;
+ if (phba->cfg_enable_rrq == 1)
+ rrq->send_rrq = send_rrq;
+ else
+ rrq->send_rrq = 0;
rrq->xritag = xritag;
rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1);
rrq->ndlp = ndlp;
rrq->nlp_DID = ndlp->nlp_DID;
rrq->vport = ndlp->vport;
rrq->rxid = rxid;
- rrq->send_rrq = send_rrq;
spin_lock_irqsave(&phba->hbalock, iflags);
empty = list_empty(&phba->active_rrq_list);
list_add_tail(&rrq->list, &phba->active_rrq_list);
@@ -1008,6 +1011,18 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
else
sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag);
+ /*
+ ** This should have been removed from the txcmplq before calling
+ ** iocbq_release. The normal completion
+ ** path should have already done the list_del_init.
+ */
+ if (unlikely(!list_empty(&iocbq->list))) {
+ if (iocbq->iocb_flag & LPFC_IO_ON_TXCMPLQ)
+ iocbq->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
+ list_del_init(&iocbq->list);
+ }
+
+
if (sglq) {
if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) &&
(sglq->state != SGL_XRI_ABORTED)) {
@@ -1024,7 +1039,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
&phba->sli4_hba.lpfc_sgl_list);
/* Check if TXQ queue needs to be serviced */
- if (pring->txq_cnt)
+ if (!list_empty(&pring->txq))
lpfc_worker_wake_up(phba);
}
}
@@ -1056,6 +1071,14 @@ __lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
/*
+ ** This should have been removed from the txcmplq before calling
+ ** iocbq_release. The normal completion
+ ** path should have already done the list_del_init.
+ */
+ if (unlikely(!list_empty(&iocbq->list)))
+ list_del_init(&iocbq->list);
+
+ /*
* Clean all volatile data fields, preserve iotag and node struct.
*/
memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean);
@@ -1121,7 +1144,6 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist,
while (!list_empty(iocblist)) {
list_remove_head(iocblist, piocb, struct lpfc_iocbq, list);
-
if (!piocb->iocb_cmpl)
lpfc_sli_release_iocbq(phba, piocb);
else {
@@ -1309,9 +1331,6 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
list_add_tail(&piocb->list, &pring->txcmplq);
piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ;
- pring->txcmplq_cnt++;
- if (pring->txcmplq_cnt > pring->txcmplq_max)
- pring->txcmplq_max = pring->txcmplq_cnt;
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
@@ -1343,8 +1362,6 @@ lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
struct lpfc_iocbq *cmd_iocb;
list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
- if (cmd_iocb != NULL)
- pring->txq_cnt--;
return cmd_iocb;
}
@@ -1613,8 +1630,9 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* (c) link attention events can be processed (fcp ring only)
* (d) IOCB processing is not blocked by the outstanding mbox command.
*/
- if (pring->txq_cnt &&
- lpfc_is_link_up(phba) &&
+
+ if (lpfc_is_link_up(phba) &&
+ (!list_empty(&pring->txq)) &&
(pring->ringno != phba->sli.fcp_ring ||
phba->sli.sli_flag & LPFC_PROCESS_LA)) {
@@ -2611,7 +2629,6 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) {
- pring->txcmplq_cnt--;
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
}
return cmd_iocb;
@@ -2649,7 +2666,6 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
/* remove from txcmpl queue list */
list_del_init(&cmd_iocb->list);
cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ;
- pring->txcmplq_cnt--;
return cmd_iocb;
}
}
@@ -3498,7 +3514,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
*/
spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txq, &completions);
- pring->txq_cnt = 0;
/* Next issue ABTS for everything on the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
@@ -3535,11 +3550,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
/* Retrieve everything on txq */
list_splice_init(&pring->txq, &txq);
- pring->txq_cnt = 0;
/* Retrieve everything on the txcmplq */
list_splice_init(&pring->txcmplq, &txcmplq);
- pring->txcmplq_cnt = 0;
/* Indicate the I/O queues are flushed */
phba->hba_flag |= HBA_FCP_IOQ_FLUSH;
@@ -5987,9 +6000,9 @@ lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
LIST_HEAD(post_sgl_list);
LIST_HEAD(free_sgl_list);
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
list_for_each_entry_safe(sglq_entry, sglq_entry_next,
&allc_sgl_list, list) {
@@ -6090,10 +6103,10 @@ lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba)
/* push els sgls posted to the availble list */
if (!list_empty(&post_sgl_list)) {
- spin_lock(&phba->hbalock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&post_sgl_list,
&phba->sli4_hba.lpfc_sgl_list);
- spin_unlock(&phba->hbalock);
+ spin_unlock_irq(&phba->hbalock);
} else {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3161 Failure to post els sgl to port.\n");
@@ -7614,7 +7627,6 @@ __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
{
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
- pring->txq_cnt++;
}
/**
@@ -8386,7 +8398,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
- if (pring->txq_cnt) {
+ if (!list_empty(&pring->txq)) {
if (!(flag & SLI_IOCB_RET_IOCB)) {
__lpfc_sli_ringtx_put(phba,
pring, piocb);
@@ -9054,7 +9066,6 @@ lpfc_sli_host_down(struct lpfc_vport *vport)
if (iocb->vport != vport)
continue;
list_move_tail(&iocb->list, &completions);
- pring->txq_cnt--;
}
/* Next issue ABTS for everything on the txcmplq */
@@ -9123,8 +9134,6 @@ lpfc_sli_hba_down(struct lpfc_hba *phba)
* given to the FW yet.
*/
list_splice_init(&pring->txq, &completions);
- pring->txq_cnt = 0;
-
}
spin_unlock_irqrestore(&phba->hbalock, flags);
@@ -9965,6 +9974,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
+ struct lpfc_iocbq *iocb;
+ int txq_cnt = 0;
+ int txcmplq_cnt = 0;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
/*
* If the caller has provided a response iocbq buffer, then context2
@@ -10012,9 +10024,17 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
retval = IOCB_TIMEDOUT;
}
} else if (retval == IOCB_BUSY) {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
- phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+ if (phba->cfg_log_verbose & LOG_SLI) {
+ list_for_each_entry(iocb, &pring->txq, list) {
+ txq_cnt++;
+ }
+ list_for_each_entry(iocb, &pring->txcmplq, list) {
+ txcmplq_cnt++;
+ }
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+ phba->iocb_cnt, txq_cnt, txcmplq_cnt);
+ }
return retval;
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -11297,16 +11317,25 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
struct lpfc_sli_ring *pring = cq->pring;
+ int txq_cnt = 0;
+ int txcmplq_cnt = 0;
+ int fcp_txcmplq_cnt = 0;
/* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
+ if (!list_empty(&pring->txq))
+ txq_cnt++;
+ if (!list_empty(&pring->txcmplq))
+ txcmplq_cnt++;
+ if (!list_empty(&phba->sli.ring[LPFC_FCP_RING].txcmplq))
+ fcp_txcmplq_cnt++;
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
"fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
- pring->txq_cnt, phba->iocb_cnt,
- phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
- phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
+ txq_cnt, phba->iocb_cnt,
+ fcp_txcmplq_cnt,
+ txcmplq_cnt);
return false;
}
@@ -15481,11 +15510,18 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba)
LPFC_SLI4_FCF_TBL_INDX_MAX);
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"3060 Last IDX %d\n", last_index);
- if (list_empty(&phba->fcf.fcf_pri_list)) {
+
+ /* Verify the priority list has 2 or more entries */
+ spin_lock_irq(&phba->hbalock);
+ if (list_empty(&phba->fcf.fcf_pri_list) ||
+ list_is_singular(&phba->fcf.fcf_pri_list)) {
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
"3061 Last IDX %d\n", last_index);
return 0; /* Empty rr list */
}
+ spin_unlock_irq(&phba->hbalock);
+
next_fcf_pri = 0;
/*
* Clear the rr_bmask and set all of the bits that are at this
@@ -16244,14 +16280,19 @@ lpfc_drain_txq(struct lpfc_hba *phba)
char *fail_msg = NULL;
struct lpfc_sglq *sglq;
union lpfc_wqe wqe;
+ int txq_cnt = 0;
spin_lock_irqsave(&phba->hbalock, iflags);
- if (pring->txq_cnt > pring->txq_max)
- pring->txq_max = pring->txq_cnt;
+ list_for_each_entry(piocbq, &pring->txq, list) {
+ txq_cnt++;
+ }
+
+ if (txq_cnt > pring->txq_max)
+ pring->txq_max = txq_cnt;
spin_unlock_irqrestore(&phba->hbalock, iflags);
- while (pring->txq_cnt) {
+ while (!list_empty(&pring->txq)) {
spin_lock_irqsave(&phba->hbalock, iflags);
piocbq = lpfc_sli_ringtx_get(phba, pring);
@@ -16259,7 +16300,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
spin_unlock_irqrestore(&phba->hbalock, iflags);
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"2823 txq empty and txq_cnt is %d\n ",
- pring->txq_cnt);
+ txq_cnt);
break;
}
sglq = __lpfc_sli_get_sglq(phba, piocbq);
@@ -16268,6 +16309,7 @@ lpfc_drain_txq(struct lpfc_hba *phba)
spin_unlock_irqrestore(&phba->hbalock, iflags);
break;
}
+ txq_cnt--;
/* The xri and iocb resources secured,
* attempt to issue request
@@ -16299,5 +16341,5 @@ lpfc_drain_txq(struct lpfc_hba *phba)
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
- return pring->txq_cnt;
+ return txq_cnt;
}
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index f3b7795a296b..664cd04f7cd8 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.37"
+#define LPFC_DRIVER_VERSION "8.3.38"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 408d2548a748..684cc343cf09 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1488,7 +1488,4 @@ struct megasas_mgmt_info {
int max_index;
};
-#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 9d53540207ec..7c90d57b867e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -3984,12 +3984,12 @@ static int megasas_probe_one(struct pci_dev *pdev,
if (reset_devices) {
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
if (pos) {
- pci_read_config_word(pdev, msi_control_reg(pos),
+ pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS,
&control);
if (control & PCI_MSIX_FLAGS_ENABLE) {
dev_info(&pdev->dev, "resetting MSI-X\n");
pci_write_config_word(pdev,
- msi_control_reg(pos),
+ pos + PCI_MSIX_FLAGS,
control &
~PCI_MSIX_FLAGS_ENABLE);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 1df9ed4f371d..4db0c7a18bd8 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -148,7 +148,7 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
desc = "raid_config";
break;
case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
- desc = "driver_mappping";
+ desc = "driver_mapping";
break;
}
break;
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index ce90d0546cdd..74550922ad55 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -703,7 +703,7 @@ static struct pci_device_id mvs_pci_table[] = {
{ PCI_VDEVICE(TTI, 0x2744), chip_9480 },
{ PCI_VDEVICE(TTI, 0x2760), chip_9480 },
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9480,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
@@ -712,7 +712,7 @@ static struct pci_device_id mvs_pci_table[] = {
.driver_data = chip_9480,
},
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9445,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
@@ -721,7 +721,7 @@ static struct pci_device_id mvs_pci_table[] = {
.driver_data = chip_9445,
},
{
- .vendor = 0x1b4b,
+ .vendor = PCI_VENDOR_ID_MARVELL_EXT,
.device = 0x9485,
.subvendor = PCI_ANY_ID,
.subdevice = 0x9480,
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 4594ccaaf49b..c3601b57a80c 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -49,8 +49,8 @@ MODULE_AUTHOR("jyli@marvell.com");
MODULE_DESCRIPTION("Marvell UMI Driver");
static DEFINE_PCI_DEVICE_TABLE(mvumi_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9143) },
- { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9580) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9143) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, PCI_DEVICE_ID_MARVELL_MV9580) },
{ 0 }
};
diff --git a/drivers/scsi/mvumi.h b/drivers/scsi/mvumi.h
index e360135fd1bd..41f168702ac7 100644
--- a/drivers/scsi/mvumi.h
+++ b/drivers/scsi/mvumi.h
@@ -32,7 +32,6 @@
#define VER_BUILD 1500
#define MV_DRIVER_NAME "mvumi"
-#define PCI_VENDOR_ID_MARVELL_2 0x1b4b
#define PCI_DEVICE_ID_MARVELL_MV9143 0x9143
#define PCI_DEVICE_ID_MARVELL_MV9580 0x9580
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index d8293f25ca33..aa66361ed44b 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -1049,7 +1049,7 @@ static struct bio *_create_sg_bios(struct osd_request *or,
bio = bio_kmalloc(GFP_KERNEL, numentries);
if (unlikely(!bio)) {
- OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries);
+ OSD_DEBUG("Failed to allocate BIO size=%u\n", numentries);
return ERR_PTR(-ENOMEM);
}
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index dce7d788cdc9..c37b244cf8ae 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,6 +1,6 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
- qla_nx.o qla_target.o
+ qla_nx.o qla_mr.o qla_target.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
obj-$(CONFIG_TCM_QLA2XXX) += tcm_qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 1d82eef4e1eb..bf60c631abb5 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -888,7 +888,10 @@ qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
struct qla_hw_data *ha = vha->hw;
uint32_t sn;
- if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(vha->hw)) {
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.serial_num);
+ } else if (IS_FWI2_CAPABLE(ha)) {
qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE);
return snprintf(buf, PAGE_SIZE, "%s\n", buf);
}
@@ -912,6 +915,11 @@ qla2x00_isp_id_show(struct device *dev, struct device_attribute *attr,
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
struct qla_hw_data *ha = vha->hw;
+
+ if (IS_QLAFX00(vha->hw))
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.hw_version);
+
return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
@@ -922,6 +930,11 @@ qla2x00_model_name_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+
+ if (IS_QLAFX00(vha->hw))
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ vha->hw->mr.product_name);
+
return snprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number);
}
@@ -1304,6 +1317,12 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
int rval = QLA_FUNCTION_FAILED;
uint16_t state[5];
+ uint32_t pstate;
+
+ if (IS_QLAFX00(vha->hw)) {
+ pstate = qlafx00_fw_state_show(dev, attr, buf);
+ return snprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
+ }
if (qla2x00_reset_active(vha))
ql_log(ql_log_warn, vha, 0x707c,
@@ -1454,6 +1473,11 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
(shost_priv(shost)))->hw;
u32 speed = FC_PORTSPEED_UNKNOWN;
+ if (IS_QLAFX00(ha)) {
+ qlafx00_get_host_speed(shost);
+ return;
+ }
+
switch (ha->link_data_rate) {
case PORT_SPEED_1GB:
speed = FC_PORTSPEED_1GBIT;
@@ -1637,6 +1661,9 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
{
scsi_qla_host_t *vha = shost_priv(shost);
+ if (IS_QLAFX00(vha->hw))
+ return 0;
+
qla2x00_loop_reset(vha);
return 0;
}
@@ -1655,6 +1682,9 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat = &vha->fc_host_stat;
memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
+ if (IS_QLAFX00(vha->hw))
+ goto done;
+
if (test_bit(UNLOADING, &vha->dpc_flags))
goto done;
@@ -1938,11 +1968,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
"Timer for the VP[%d] has stopped\n", vha->vp_idx);
}
- /* No pending activities shall be there on the vha now */
- if (ql2xextended_error_logging & ql_dbg_user)
- msleep(random32()%10); /* Just to see if something falls on
- * the net we have placed below */
-
BUG_ON(atomic_read(&vha->vref_count));
qla2x00_free_fcports(vha);
@@ -2092,6 +2117,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
FC_PORTSPEED_1GBIT;
else if (IS_QLA23XX(ha))
speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
+ else if (IS_QLAFX00(ha))
+ speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
+ FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
else
speed = FC_PORTSPEED_1GBIT;
fc_host_supported_speeds(vha->host) = speed;
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index ad54099cb805..39719f892488 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -30,14 +30,31 @@ qla2x00_bsg_sp_free(void *data, void *ptr)
struct scsi_qla_host *vha = sp->fcport->vha;
struct fc_bsg_job *bsg_job = sp->u.bsg_job;
struct qla_hw_data *ha = vha->hw;
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
- dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
- bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (sp->type == SRB_FXIOCB_BCMD) {
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
- dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
- bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+ dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ }
if (sp->type == SRB_CT_CMD ||
+ sp->type == SRB_FXIOCB_BCMD ||
sp->type == SRB_ELS_CMD_HST)
kfree(sp->fcport);
qla2x00_rel_sp(vha, sp);
@@ -751,6 +768,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
elreq.transfer_size = req_data_len;
elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+ elreq.iteration_count =
+ bsg_job->request->rqst_data.h_vendor.vendor_cmd[2];
if (atomic_read(&vha->loop_state) == LOOP_READY &&
(ha->current_topology == ISP_CFG_F ||
@@ -1883,6 +1902,128 @@ done:
}
static int
+qlafx00_mgmt_cmd(struct fc_bsg_job *bsg_job)
+{
+ struct Scsi_Host *host = bsg_job->shost;
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct qla_hw_data *ha = vha->hw;
+ int rval = (DRIVER_ERROR << 16);
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
+ srb_t *sp;
+ int req_sg_cnt = 0, rsp_sg_cnt = 0;
+ struct fc_port *fcport;
+ char *type = "FC_BSG_HST_FX_MGMT";
+
+ /* Copy the IOCB specific information */
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+ /* Dump the vendor information */
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose , vha, 0x70cf,
+ (uint8_t *)piocb_rqst, sizeof(struct qla_mt_iocb_rqst_fx00));
+
+ if (!vha->flags.online) {
+ ql_log(ql_log_warn, vha, 0x70d0,
+ "Host is not online.\n");
+ rval = -EIO;
+ goto done;
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
+ req_sg_cnt = dma_map_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+ if (!req_sg_cnt) {
+ ql_log(ql_log_warn, vha, 0x70c7,
+ "dma_map_sg return %d for request\n", req_sg_cnt);
+ rval = -ENOMEM;
+ goto done;
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
+ rsp_sg_cnt = dma_map_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+ if (!rsp_sg_cnt) {
+ ql_log(ql_log_warn, vha, 0x70c8,
+ "dma_map_sg return %d for reply\n", rsp_sg_cnt);
+ rval = -ENOMEM;
+ goto done_unmap_req_sg;
+ }
+ }
+
+ ql_dbg(ql_dbg_user, vha, 0x70c9,
+ "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x "
+ "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt,
+ req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt);
+
+ /* Allocate a dummy fcport structure, since functions preparing the
+ * IOCB and mailbox command retrieves port specific information
+ * from fcport structure. For Host based ELS commands there will be
+ * no fcport structure allocated
+ */
+ fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (!fcport) {
+ ql_log(ql_log_warn, vha, 0x70ca,
+ "Failed to allocate fcport.\n");
+ rval = -ENOMEM;
+ goto done_unmap_rsp_sg;
+ }
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ ql_log(ql_log_warn, vha, 0x70cb,
+ "qla2x00_get_sp failed.\n");
+ rval = -ENOMEM;
+ goto done_free_fcport;
+ }
+
+ /* Initialize all required fields of fcport */
+ fcport->vha = vha;
+ fcport->loop_id = piocb_rqst->dataword;
+
+ sp->type = SRB_FXIOCB_BCMD;
+ sp->name = "bsg_fx_mgmt";
+ sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt);
+ sp->u.bsg_job = bsg_job;
+ sp->free = qla2x00_bsg_sp_free;
+ sp->done = qla2x00_bsg_job_done;
+
+ ql_dbg(ql_dbg_user, vha, 0x70cc,
+ "bsg rqst type: %s fx_mgmt_type: %x id=%x\n",
+ type, piocb_rqst->func_type, fcport->loop_id);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x70cd,
+ "qla2x00_start_sp failed=%d.\n", rval);
+ mempool_free(sp, ha->srb_mempool);
+ rval = -EIO;
+ goto done_free_fcport;
+ }
+ return rval;
+
+done_free_fcport:
+ kfree(fcport);
+
+done_unmap_rsp_sg:
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done_unmap_req_sg:
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID)
+ dma_unmap_sg(&ha->pdev->dev,
+ bsg_job->request_payload.sg_list,
+ bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+done:
+ return rval;
+}
+
+static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -1928,6 +2069,8 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_DIAG_IO_CMD:
return qla24xx_process_bidir_cmd(bsg_job);
+ case QL_VND_FX00_MGMT_CMD:
+ return qlafx00_mgmt_cmd(bsg_job);
default:
return -ENOSYS;
}
@@ -2007,7 +2150,8 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job)
sp = req->outstanding_cmds[cnt];
if (sp) {
if (((sp->type == SRB_CT_CMD) ||
- (sp->type == SRB_ELS_CMD_HST))
+ (sp->type == SRB_ELS_CMD_HST) ||
+ (sp->type == SRB_FXIOCB_BCMD))
&& (sp->u.bsg_job == bsg_job)) {
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index e9f6b9bbf29a..04f770332c2b 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -22,6 +22,7 @@
#define QL_VND_DIAG_IO_CMD 0x0A
#define QL_VND_WRITE_I2C 0x10
#define QL_VND_READ_I2C 0x11
+#define QL_VND_FX00_MGMT_CMD 0x12
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 1626de52e32a..cfa2a20dee97 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -11,27 +11,31 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
- * | Module Init and Probe | 0x0126 | 0x4b,0xba,0xfa |
- * | Mailbox commands | 0x115b | 0x111a-0x111b |
- * | | | 0x112c-0x112e |
- * | | | 0x113a |
- * | Device Discovery | 0x2087 | 0x2020-0x2022, |
+ * | Module Init and Probe | 0x014f | 0x4b,0xba,0xfa |
+ * | Mailbox commands | 0x1179 | 0x111a-0x111b |
+ * | | | 0x1155-0x1158 |
+ * | Device Discovery | 0x2095 | 0x2020-0x2022, |
* | | | 0x2016 |
- * | Queue Command and IO tracing | 0x3031 | 0x3006-0x300b |
+ * | Queue Command and IO tracing | 0x3058 | 0x3006-0x300b |
* | | | 0x3027-0x3028 |
- * | | | 0x302d-0x302e |
- * | DPC Thread | 0x401d | 0x4002,0x4013 |
- * | Async Events | 0x5071 | 0x502b-0x502f |
+ * | | | 0x303d-0x3041 |
+ * | | | 0x302d,0x3033 |
+ * | | | 0x3036,0x3038 |
+ * | | | 0x303a |
+ * | DPC Thread | 0x4022 | 0x4002,0x4013 |
+ * | Async Events | 0x5081 | 0x502b-0x502f |
* | | | 0x5047,0x5052 |
+ * | | | 0x5040,0x5075 |
* | Timer Routines | 0x6011 | |
- * | User Space Interactions | 0x70c4 | 0x7018,0x702e, |
+ * | User Space Interactions | 0x70dd | 0x7018,0x702e, |
* | | | 0x7020,0x7024, |
* | | | 0x7039,0x7045, |
* | | | 0x7073-0x7075, |
- * | | | 0x708c, |
+ * | | | 0x707b,0x708c, |
* | | | 0x70a5,0x70a6, |
* | | | 0x70a8,0x70ab, |
- * | | | 0x70ad-0x70ae |
+ * | | | 0x70ad-0x70ae, |
+ * | | | 0x70d1-0x70da |
* | Task Management | 0x803c | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
@@ -401,7 +405,7 @@ qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr,
void *ring;
} aq, *aqp;
- if (!ha->tgt.atio_q_length)
+ if (!ha->tgt.atio_ring)
return ptr;
num_queues = 1;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c6509911772b..c32efc753229 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -245,7 +245,6 @@
#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */
#include "qla_fw.h"
-
/*
* Timeout timer counts in seconds
*/
@@ -265,6 +264,7 @@
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
+#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
struct req_que;
@@ -284,6 +284,7 @@ struct sd_dif_tuple {
struct srb_cmd {
struct scsi_cmnd *cmd; /* Linux SCSI command pkt */
uint32_t request_sense_length;
+ uint32_t fw_sense_length;
uint8_t *request_sense_ptr;
void *ctx;
};
@@ -321,7 +322,39 @@ struct srb_iocb {
uint32_t flags;
uint32_t lun;
uint32_t data;
+ struct completion comp;
+ uint32_t comp_status;
} tmf;
+ struct {
+#define SRB_FXDISC_REQ_DMA_VALID BIT_0
+#define SRB_FXDISC_RESP_DMA_VALID BIT_1
+#define SRB_FXDISC_REQ_DWRD_VALID BIT_2
+#define SRB_FXDISC_RSP_DWRD_VALID BIT_3
+#define FXDISC_TIMEOUT 20
+ uint8_t flags;
+ uint32_t req_len;
+ uint32_t rsp_len;
+ void *req_addr;
+ void *rsp_addr;
+ dma_addr_t req_dma_handle;
+ dma_addr_t rsp_dma_handle;
+ uint32_t adapter_id;
+ uint32_t adapter_id_hi;
+ uint32_t req_func_type;
+ uint32_t req_data;
+ uint32_t req_data_extra;
+ uint32_t result;
+ uint32_t seq_number;
+ uint32_t fw_flags;
+ struct completion fxiocb_comp;
+ uint32_t reserved_0;
+ uint8_t reserved_1;
+ } fxiocb;
+ struct {
+ uint32_t cmd_hndl;
+ uint32_t comp_status;
+ struct completion comp;
+ } abt;
} u;
struct timer_list timer;
@@ -338,6 +371,10 @@ struct srb_iocb {
#define SRB_TM_CMD 7
#define SRB_SCSI_CMD 8
#define SRB_BIDI_CMD 9
+#define SRB_FXIOCB_DCMD 10
+#define SRB_FXIOCB_BCMD 11
+#define SRB_ABT_CMD 12
+
typedef struct srb {
atomic_t ref_count;
@@ -368,6 +405,10 @@ typedef struct srb {
(sp->u.scmd.request_sense_ptr)
#define SET_CMD_SENSE_PTR(sp, ptr) \
(sp->u.scmd.request_sense_ptr = ptr)
+#define GET_FW_SENSE_LEN(sp) \
+ (sp->u.scmd.fw_sense_length)
+#define SET_FW_SENSE_LEN(sp, len) \
+ (sp->u.scmd.fw_sense_length = len)
struct msg_echo_lb {
dma_addr_t send_dma;
@@ -376,6 +417,7 @@ struct msg_echo_lb {
uint16_t rsp_sg_cnt;
uint16_t options;
uint32_t transfer_size;
+ uint32_t iteration_count;
};
/*
@@ -542,11 +584,74 @@ struct device_reg_25xxmq {
uint32_t atio_q_out;
};
+
+struct device_reg_fx00 {
+ uint32_t mailbox0; /* 00 */
+ uint32_t mailbox1; /* 04 */
+ uint32_t mailbox2; /* 08 */
+ uint32_t mailbox3; /* 0C */
+ uint32_t mailbox4; /* 10 */
+ uint32_t mailbox5; /* 14 */
+ uint32_t mailbox6; /* 18 */
+ uint32_t mailbox7; /* 1C */
+ uint32_t mailbox8; /* 20 */
+ uint32_t mailbox9; /* 24 */
+ uint32_t mailbox10; /* 28 */
+ uint32_t mailbox11;
+ uint32_t mailbox12;
+ uint32_t mailbox13;
+ uint32_t mailbox14;
+ uint32_t mailbox15;
+ uint32_t mailbox16;
+ uint32_t mailbox17;
+ uint32_t mailbox18;
+ uint32_t mailbox19;
+ uint32_t mailbox20;
+ uint32_t mailbox21;
+ uint32_t mailbox22;
+ uint32_t mailbox23;
+ uint32_t mailbox24;
+ uint32_t mailbox25;
+ uint32_t mailbox26;
+ uint32_t mailbox27;
+ uint32_t mailbox28;
+ uint32_t mailbox29;
+ uint32_t mailbox30;
+ uint32_t mailbox31;
+ uint32_t aenmailbox0;
+ uint32_t aenmailbox1;
+ uint32_t aenmailbox2;
+ uint32_t aenmailbox3;
+ uint32_t aenmailbox4;
+ uint32_t aenmailbox5;
+ uint32_t aenmailbox6;
+ uint32_t aenmailbox7;
+ /* Request Queue. */
+ uint32_t req_q_in; /* A0 - Request Queue In-Pointer */
+ uint32_t req_q_out; /* A4 - Request Queue Out-Pointer */
+ /* Response Queue. */
+ uint32_t rsp_q_in; /* A8 - Response Queue In-Pointer */
+ uint32_t rsp_q_out; /* AC - Response Queue Out-Pointer */
+ /* Init values shadowed on FW Up Event */
+ uint32_t initval0; /* B0 */
+ uint32_t initval1; /* B4 */
+ uint32_t initval2; /* B8 */
+ uint32_t initval3; /* BC */
+ uint32_t initval4; /* C0 */
+ uint32_t initval5; /* C4 */
+ uint32_t initval6; /* C8 */
+ uint32_t initval7; /* CC */
+ uint32_t fwheartbeat; /* D0 */
+};
+
+
+
typedef union {
struct device_reg_2xxx isp;
struct device_reg_24xx isp24;
struct device_reg_25xxmq isp25mq;
struct device_reg_82xx isp82;
+ struct device_reg_fx00 ispfx00;
} device_reg_t;
#define ISP_REQ_Q_IN(ha, reg) \
@@ -602,6 +707,20 @@ typedef struct {
#define IOCTL_CMD BIT_2
} mbx_cmd_t;
+struct mbx_cmd_32 {
+ uint32_t out_mb; /* outbound from driver */
+ uint32_t in_mb; /* Incoming from RISC */
+ uint32_t mb[MAILBOX_REGISTER_COUNT];
+ long buf_size;
+ void *bufp;
+ uint32_t tov;
+ uint8_t flags;
+#define MBX_DMA_IN BIT_0
+#define MBX_DMA_OUT BIT_1
+#define IOCTL_CMD BIT_2
+};
+
+
#define MBX_TOV_SECONDS 30
/*
@@ -677,6 +796,15 @@ typedef struct {
#define MBA_BYPASS_NOTIFICATION 0x8043 /* Auto bypass notification. */
#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */
#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */
+#define MBA_FW_NOT_STARTED 0x8050 /* Firmware not started */
+#define MBA_FW_STARTING 0x8051 /* Firmware starting */
+#define MBA_FW_RESTART_CMPLT 0x8060 /* Firmware restart complete */
+#define MBA_INIT_REQUIRED 0x8061 /* Initialization required */
+#define MBA_SHUTDOWN_REQUESTED 0x8062 /* Shutdown Requested */
+#define MBA_FW_INIT_FAILURE 0x8401 /* Firmware initialization failure */
+#define MBA_MIRROR_LUN_CHANGE 0x8402 /* Mirror LUN State Change
+ Notification */
+#define MBA_FW_POLL_STATE 0x8600 /* Firmware in poll diagnostic state */
/* 83XX FCoE specific */
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
@@ -798,6 +926,12 @@ typedef struct {
#define MBC_LUN_RESET 0x7E /* Send LUN reset */
/*
+ * all the Mt. Rainier mailbox command codes that clash with FC/FCoE ones
+ * should be defined with MBC_MR_*
+ */
+#define MBC_MR_DRV_SHUTDOWN 0x6A
+
+/*
* ISP24xx mailbox commands
*/
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
@@ -863,7 +997,6 @@ typedef struct {
#define MBX_1 BIT_1
#define MBX_0 BIT_0
-#define RNID_TYPE_SET_VERSION 0x9
#define RNID_TYPE_ASIC_TEMP 0xC
/*
@@ -1059,6 +1192,30 @@ typedef struct {
uint8_t reserved_3[26];
} init_cb_t;
+
+struct init_cb_fx {
+ uint16_t version;
+ uint16_t reserved_1[13];
+ uint16_t request_q_outpointer;
+ uint16_t response_q_inpointer;
+ uint16_t reserved_2[2];
+ uint16_t response_q_length;
+ uint16_t request_q_length;
+ uint16_t reserved_3[2];
+ uint32_t request_q_address[2];
+ uint32_t response_q_address[2];
+ uint16_t reserved_4[4];
+ uint8_t response_q_msivec;
+ uint8_t reserved_5[19];
+ uint16_t interrupt_delay_timer;
+ uint16_t reserved_6;
+ uint32_t fwoptions1;
+ uint32_t fwoptions2;
+ uint32_t fwoptions3;
+ uint8_t reserved_7[24];
+};
+
+
/*
* Get Link Status mailbox command return buffer.
*/
@@ -1832,6 +1989,9 @@ typedef struct fc_port {
uint16_t loop_id;
uint16_t old_loop_id;
+ uint16_t tgt_id;
+ uint16_t old_tgt_id;
+
uint8_t fcp_prio;
uint8_t fabric_port_name[WWN_SIZE];
@@ -1849,8 +2009,15 @@ typedef struct fc_port {
uint8_t fc4_type;
uint8_t scan_state;
+
+ unsigned long last_queue_full;
+ unsigned long last_ramp_up;
+
+ uint16_t port_id;
} fc_port_t;
+#include "qla_mr.h"
+
/*
* Fibre channel port/lun states.
*/
@@ -2392,6 +2559,7 @@ struct isp_operations {
int (*start_scsi) (srb_t *);
int (*abort_isp) (struct scsi_qla_host *);
int (*iospace_config)(struct qla_hw_data*);
+ int (*initialize_adapter)(struct scsi_qla_host *);
};
/* MSI-X Support *************************************************************/
@@ -2430,6 +2598,7 @@ enum qla_work_type {
QLA_EVT_ASYNC_ADISC,
QLA_EVT_ASYNC_ADISC_DONE,
QLA_EVT_UEVENT,
+ QLA_EVT_AENFX,
};
@@ -2457,7 +2626,15 @@ struct qla_work_evt {
u32 code;
#define QLA_UEVENT_CODE_FW_DUMP 0
} uevent;
- } u;
+ struct {
+ uint32_t evtcode;
+ uint32_t mbx[8];
+ uint32_t count;
+ } aenfx;
+ struct {
+ srb_t *sp;
+ } iosb;
+ } u;
};
struct qla_chip_state_84xx {
@@ -2521,6 +2698,11 @@ struct rsp_que {
struct req_que *req;
srb_t *status_srb; /* status continuation entry */
struct work_struct q_work;
+
+ dma_addr_t dma_fx00;
+ response_t *ring_fx00;
+ uint16_t length_fx00;
+ uint8_t rsp_pkt[REQUEST_ENTRY_SIZE];
};
/* Request queue data structure */
@@ -2545,6 +2727,11 @@ struct req_que {
uint16_t num_outstanding_cmds;
#define MAX_Q_DEPTH 32
int max_q_depth;
+
+ dma_addr_t dma_fx00;
+ request_t *ring_fx00;
+ uint16_t length_fx00;
+ uint8_t req_pkt[REQUEST_ENTRY_SIZE];
};
/* Place holder for FW buffer parameters */
@@ -2634,7 +2821,10 @@ struct qla_hw_data {
uint32_t isp82xx_no_md_cap:1;
uint32_t host_shutting_down:1;
uint32_t idc_compl_status:1;
- /* 32 bits */
+
+ uint32_t mr_reset_hdlr_active:1;
+ uint32_t mr_intr_valid:1;
+ /* 34 bits */
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2651,7 +2841,21 @@ struct qla_hw_data {
resource_size_t pio_address;
#define MIN_IOBASE_LEN 0x100
-/* Multi queue data structs */
+ dma_addr_t bar0_hdl;
+
+ void __iomem *cregbase;
+ dma_addr_t bar2_hdl;
+#define BAR0_LEN_FX00 (1024 * 1024)
+#define BAR2_LEN_FX00 (128 * 1024)
+
+ uint32_t rqstq_intr_code;
+ uint32_t mbx_intr_code;
+ uint32_t req_que_len;
+ uint32_t rsp_que_len;
+ uint32_t req_que_off;
+ uint32_t rsp_que_off;
+
+ /* Multi queue data structs */
device_reg_t __iomem *mqiobase;
device_reg_t __iomem *msixbase;
uint16_t msix_count;
@@ -2730,7 +2934,8 @@ struct qla_hw_data {
#define DT_ISP8021 BIT_14
#define DT_ISP2031 BIT_15
#define DT_ISP8031 BIT_16
-#define DT_ISP_LAST (DT_ISP8031 << 1)
+#define DT_ISPFX00 BIT_17
+#define DT_ISP_LAST (DT_ISPFX00 << 1)
#define DT_T10_PI BIT_25
#define DT_IIDMA BIT_26
@@ -2758,6 +2963,7 @@ struct qla_hw_data {
#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031)
#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031)
+#define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2822,6 +3028,7 @@ struct qla_hw_data {
uint16_t r_a_tov;
int port_down_retry_count;
uint8_t mbx_count;
+ uint8_t aen_mbx_count;
uint32_t login_retry_count;
/* SNS command interfaces. */
@@ -2869,9 +3076,13 @@ struct qla_hw_data {
void *swl;
/* These are used by mailbox operations. */
- volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+ uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+ uint32_t mailbox_out32[MAILBOX_REGISTER_COUNT];
+ uint32_t aenmb[AEN_MAILBOX_REGISTER_COUNT_FX00];
mbx_cmd_t *mcp;
+ struct mbx_cmd_32 *mcp32;
+
unsigned long mbx_cmd_flags;
#define MBX_INTERRUPT 1
#define MBX_INTR_WAIT 2
@@ -3015,6 +3226,7 @@ struct qla_hw_data {
int cur_vport_count;
struct qla_chip_state_84xx *cs84xx;
+ struct qla_statistics qla_stats;
struct isp_operations *isp_ops;
struct workqueue_struct *wq;
struct qlfc_fw fw_buf;
@@ -3081,6 +3293,8 @@ struct qla_hw_data {
unsigned long host_last_rampup_time;
int cfg_lun_q_depth;
+ struct mr_data_fx00 mr;
+
struct qlt_hw_data tgt;
uint16_t thermal_support;
#define THERMAL_SUPPORT_I2C BIT_0
@@ -3110,6 +3324,8 @@ typedef struct scsi_qla_host {
uint32_t process_response_queue :1;
uint32_t difdix_supported:1;
uint32_t delete_progress:1;
+
+ uint32_t fw_tgt_reported:1;
} flags;
atomic_t loop_state;
@@ -3145,6 +3361,9 @@ typedef struct scsi_qla_host {
#define SCR_PENDING 21 /* SCR in target mode */
#define HOST_RAMP_DOWN_QUEUE_DEPTH 22
#define HOST_RAMP_UP_QUEUE_DEPTH 23
+#define PORT_UPDATE_NEEDED 24
+#define FX00_RESET_RECOVERY 25
+#define FX00_TARGET_SCAN 26
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
@@ -3235,6 +3454,10 @@ struct qla_tgt_vp_map {
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
atomic_read(&ha->loop_state) == LOOP_DOWN)
+#define STATE_TRANSITION(ha) \
+ (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \
+ test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+
#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \
atomic_inc(&__vha->vref_count); \
mb(); \
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index eb3ca21a7f17..026bfde33e67 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -86,6 +86,7 @@ extern int qla2xxx_mctp_dump(scsi_qla_host_t *);
extern int
qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *);
+extern int qla2x00_init_rings(scsi_qla_host_t *);
/*
* Global Data in qla_os.c source file.
@@ -134,7 +135,6 @@ extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
-extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
@@ -158,6 +158,7 @@ extern int qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_set_drv_presence(scsi_qla_host_t *vha);
extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
+extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32);
/*
* Global Functions in qla_mid.c source file.
@@ -211,8 +212,6 @@ extern int qla24xx_start_scsi(srb_t *sp);
int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
-extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t);
-extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
extern int qla24xx_dif_start_scsi(srb_t *);
extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t);
extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *);
@@ -358,9 +357,6 @@ extern int
qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
extern int
-qla2x00_set_driver_version(scsi_qla_host_t *, char *);
-
-extern int
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *,
uint16_t, uint16_t, uint16_t, uint16_t);
@@ -427,6 +423,12 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *);
extern int qla2x00_get_data_rate(scsi_qla_host_t *);
extern const char *qla2x00_get_link_speed_str(struct qla_hw_data *, uint16_t);
+extern srb_t *
+qla2x00_get_sp_from_handle(scsi_qla_host_t *, const char *, struct req_que *,
+ void *);
+extern void
+qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *,
+ uint32_t);
/*
* Global Function Prototypes in qla_sup.c source file.
@@ -564,6 +566,42 @@ extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+/* qlafx00 related functions */
+extern int qlafx00_pci_config(struct scsi_qla_host *);
+extern int qlafx00_initialize_adapter(struct scsi_qla_host *);
+extern void qlafx00_soft_reset(scsi_qla_host_t *);
+extern int qlafx00_chip_diag(scsi_qla_host_t *);
+extern void qlafx00_config_rings(struct scsi_qla_host *);
+extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *);
+extern char *qlafx00_fw_version_str(struct scsi_qla_host *, char *);
+extern irqreturn_t qlafx00_intr_handler(int, void *);
+extern void qlafx00_enable_intrs(struct qla_hw_data *);
+extern void qlafx00_disable_intrs(struct qla_hw_data *);
+extern int qlafx00_abort_command(srb_t *);
+extern int qlafx00_abort_target(fc_port_t *, unsigned int, int);
+extern int qlafx00_lun_reset(fc_port_t *, unsigned int, int);
+extern int qlafx00_start_scsi(srb_t *);
+extern int qlafx00_abort_isp(scsi_qla_host_t *);
+extern int qlafx00_iospace_config(struct qla_hw_data *);
+extern int qlafx00_init_firmware(scsi_qla_host_t *, uint16_t);
+extern int qlafx00_fw_ready(scsi_qla_host_t *);
+extern int qlafx00_configure_devices(scsi_qla_host_t *);
+extern int qlafx00_reset_initialize(scsi_qla_host_t *);
+extern int qlafx00_fx_disc(scsi_qla_host_t *, fc_port_t *, uint8_t);
+extern int qlafx00_process_aen(struct scsi_qla_host *, struct qla_work_evt *);
+extern int qlafx00_post_aenfx_work(struct scsi_qla_host *, uint32_t,
+ uint32_t *, int);
+extern uint32_t qlafx00_fw_state_show(struct device *,
+ struct device_attribute *, char *);
+extern void qlafx00_get_host_speed(struct Scsi_Host *);
+extern void qlafx00_init_response_q_entries(struct rsp_que *);
+
+extern void qlafx00_tm_iocb(srb_t *, struct tsk_mgmt_entry_fx00 *);
+extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
+extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
+extern void qlafx00_timer_routine(scsi_qla_host_t *);
+extern int qlafx00_rescan_isp(scsi_qla_host_t *);
+
/* qla82xx related functions */
/* PCI related functions */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 9b455250c101..d0ea8b921177 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -639,9 +639,14 @@ void
qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn)
{
struct qla_hw_data *ha = vha->hw;
- sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
- ha->fw_major_version, ha->fw_minor_version,
- ha->fw_subminor_version, qla2x00_version_str);
+
+ if (IS_QLAFX00(ha))
+ sprintf(snn, "%s FW:v%s DVR:v%s", ha->model_number,
+ ha->mr.fw_version, qla2x00_version_str);
+ else
+ sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s", ha->model_number,
+ ha->fw_major_version, ha->fw_minor_version,
+ ha->fw_subminor_version, qla2x00_version_str);
}
/**
@@ -923,7 +928,7 @@ qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
sns_cmd->p.gpn_data[9] != 0x02) {
ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e,
"GPN_ID failed, rejected request, gpn_rsp:\n");
- ql_dump_buffer(ql_dbg_disc, vha, 0x207f,
+ ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207f,
sns_cmd->p.gpn_data, 16);
rval = QLA_FUNCTION_FAILED;
} else {
@@ -1718,7 +1723,8 @@ qla2x00_fdmi_register(scsi_qla_host_t *vha)
int rval;
struct qla_hw_data *ha = vha->hw;
- if (IS_QLA2100(ha) || IS_QLA2200(ha))
+ if (IS_QLA2100(ha) || IS_QLA2200(ha) ||
+ IS_QLAFX00(ha))
return QLA_FUNCTION_FAILED;
rval = qla2x00_mgmt_svr_login(vha);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index edf4d14a1335..3565dfd8f370 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -25,7 +25,6 @@
*/
static int qla2x00_isp_firmware(scsi_qla_host_t *);
static int qla2x00_setup_chip(scsi_qla_host_t *);
-static int qla2x00_init_rings(scsi_qla_host_t *);
static int qla2x00_fw_ready(scsi_qla_host_t *);
static int qla2x00_configure_hba(scsi_qla_host_t *);
static int qla2x00_configure_loop(scsi_qla_host_t *);
@@ -83,7 +82,9 @@ qla2x00_get_async_timeout(struct scsi_qla_host *vha)
/* Firmware should use switch negotiated r_a_tov for timeout. */
tmo = ha->r_a_tov / 10 * 2;
- if (!IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(ha)) {
+ tmo = FX00_DEF_RATOV * 2;
+ } else if (!IS_FWI2_CAPABLE(ha)) {
/*
* Except for earlier ISPs where the timeout is seeded from the
* initialization control block.
@@ -619,8 +620,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
qla24xx_read_fcp_prio_cfg(vha);
- qla2x00_set_driver_version(vha, QLA2XXX_VERSION);
-
return (rval);
}
@@ -1399,7 +1398,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mq_size += ha->max_rsp_queues *
(rsp->length * sizeof(response_t));
}
- if (ha->tgt.atio_q_length)
+ if (ha->tgt.atio_ring)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
@@ -1979,7 +1978,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
*
* Returns 0 on success.
*/
-static int
+int
qla2x00_init_rings(scsi_qla_host_t *vha)
{
int rval;
@@ -2014,7 +2013,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
if (!rsp)
continue;
/* Initialize response queue entries */
- qla2x00_init_response_q_entries(rsp);
+ if (IS_QLAFX00(ha))
+ qlafx00_init_response_q_entries(rsp);
+ else
+ qla2x00_init_response_q_entries(rsp);
}
ha->tgt.atio_ring_ptr = ha->tgt.atio_ring;
@@ -2026,11 +2028,16 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
+
+ if (IS_QLAFX00(ha)) {
+ rval = qlafx00_init_firmware(vha, ha->init_cb_size);
+ goto next_check;
+ }
+
/* Update any ISP specific firmware options before initialization. */
ha->isp_ops->update_fw_options(vha);
- ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n");
-
if (ha->flags.npiv_supported) {
if (ha->operating_mode == LOOP && !IS_CNA_CAPABLE(ha))
ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
@@ -2044,6 +2051,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
}
rval = qla2x00_init_firmware(vha, ha->init_cb_size);
+next_check:
if (rval) {
ql_log(ql_log_fatal, vha, 0x00d2,
"Init Firmware **** FAILED ****.\n");
@@ -2071,6 +2079,9 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
uint16_t state[5];
struct qla_hw_data *ha = vha->hw;
+ if (IS_QLAFX00(vha->hw))
+ return qlafx00_fw_ready(vha);
+
rval = QLA_SUCCESS;
/* 20 seconds for loop down. */
@@ -3136,6 +3147,12 @@ void
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
{
fcport->vha = vha;
+
+ if (IS_QLAFX00(vha->hw)) {
+ qla2x00_set_fcport_state(fcport, FCS_ONLINE);
+ qla2x00_reg_remote_port(vha, fcport);
+ return;
+ }
fcport->login_retry = 0;
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
@@ -3896,15 +3913,24 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
- /* Issue a marker after FW becomes ready. */
- qla2x00_marker(vha, req, rsp, 0, 0,
- MK_SYNC_ALL);
- vha->marker_needed = 0;
+ if (!IS_QLAFX00(vha->hw)) {
+ /*
+ * Issue a marker after FW becomes
+ * ready.
+ */
+ qla2x00_marker(vha, req, rsp, 0, 0,
+ MK_SYNC_ALL);
+ vha->marker_needed = 0;
+ }
/* Remap devices on Loop. */
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
- qla2x00_configure_loop(vha);
+ if (IS_QLAFX00(vha->hw))
+ qlafx00_configure_devices(vha);
+ else
+ qla2x00_configure_loop(vha);
+
wait_time--;
} while (!atomic_read(&vha->loop_down_timer) &&
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
@@ -3970,9 +3996,7 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
if (fcport->drport &&
atomic_read(&fcport->state) != FCS_UNCONFIGURED) {
spin_unlock_irqrestore(&ha->vport_slock, flags);
-
qla2x00_rport_del(fcport);
-
spin_lock_irqsave(&ha->vport_slock, flags);
}
}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 68e2c4afc134..98ab921070d2 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -5,6 +5,28 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
+/**
+ * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
+ * Continuation Type 1 IOCBs to allocate.
+ *
+ * @dsds: number of data segment decriptors needed
+ *
+ * Returns the number of IOCB entries needed to store @dsds.
+ */
+static inline uint16_t
+qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
+{
+ uint16_t iocbs;
+
+ iocbs = 1;
+ if (dsds > 1) {
+ iocbs += (dsds - 1) / 5;
+ if ((dsds - 1) % 5)
+ iocbs++;
+ }
+ return iocbs;
+}
+
/*
* qla2x00_debounce_register
* Debounce register.
@@ -58,6 +80,17 @@ host_to_fcp_swap(uint8_t *fcp, uint32_t bsize)
}
static inline void
+host_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize)
+{
+ uint32_t *isrc = (uint32_t *) src;
+ uint32_t *odest = (uint32_t *) dst;
+ uint32_t iter = bsize >> 2;
+
+ for (; iter ; iter--)
+ *odest++ = cpu_to_le32(*isrc++);
+}
+
+static inline void
qla2x00_set_reserved_loop_ids(struct qla_hw_data *ha)
{
int i;
@@ -213,12 +246,18 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout;
add_timer(&sp->u.iocb_cmd.timer);
sp->free = qla2x00_sp_free;
+ if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
+ (sp->type == SRB_FXIOCB_DCMD))
+ init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
}
static inline int
qla2x00_gid_list_size(struct qla_hw_data *ha)
{
- return sizeof(struct gid_list_info) * ha->max_fibre_devices;
+ if (IS_QLAFX00(ha))
+ return sizeof(uint32_t) * 32;
+ else
+ return sizeof(struct gid_list_info) * ha->max_fibre_devices;
}
static inline void
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index d2630317cce8..15e4080b347c 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -135,7 +135,8 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req)
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
/* Load packet defaults. */
- *((uint32_t *)(&cont_pkt->entry_type)) =
+ *((uint32_t *)(&cont_pkt->entry_type)) = IS_QLAFX00(vha->hw) ?
+ __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00) :
__constant_cpu_to_le32(CONTINUE_A64_TYPE);
return (cont_pkt);
@@ -486,6 +487,10 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
if (ha->mqenable || IS_QLA83XX(ha)) {
WRT_REG_DWORD(req->req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr);
+ } else if (IS_QLAFX00(ha)) {
+ WRT_REG_DWORD(&reg->ispfx00.req_q_in, req->ring_index);
+ RD_REG_DWORD_RELAXED(&reg->ispfx00.req_q_in);
+ QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
@@ -514,11 +519,12 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
uint16_t lun, uint8_t type)
{
mrk_entry_t *mrk;
- struct mrk_entry_24xx *mrk24;
+ struct mrk_entry_24xx *mrk24 = NULL;
+ struct mrk_entry_fx00 *mrkfx = NULL;
+
struct qla_hw_data *ha = vha->hw;
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
- mrk24 = NULL;
req = ha->req_q_map[0];
mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, NULL);
if (mrk == NULL) {
@@ -531,7 +537,15 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_FWI2_CAPABLE(ha)) {
+ if (IS_QLAFX00(ha)) {
+ mrkfx = (struct mrk_entry_fx00 *) mrk;
+ mrkfx->handle = MAKE_HANDLE(req->id, mrkfx->handle);
+ mrkfx->handle_hi = 0;
+ mrkfx->tgt_id = cpu_to_le16(loop_id);
+ mrkfx->lun[1] = LSB(lun);
+ mrkfx->lun[2] = MSB(lun);
+ host_to_fcp_swap(mrkfx->lun, sizeof(mrkfx->lun));
+ } else if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
@@ -589,28 +603,6 @@ int qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked)
return QLA_SUCCESS;
}
-/**
- * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
- * Continuation Type 1 IOCBs to allocate.
- *
- * @dsds: number of data segment decriptors needed
- *
- * Returns the number of IOCB entries needed to store @dsds.
- */
-inline uint16_t
-qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds)
-{
- uint16_t iocbs;
-
- iocbs = 1;
- if (dsds > 1) {
- iocbs += (dsds - 1) / 5;
- if ((dsds - 1) % 5)
- iocbs++;
- }
- return iocbs;
-}
-
static inline int
qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt,
uint16_t tot_dsds)
@@ -1583,7 +1575,6 @@ queuing_error:
return QLA_FUNCTION_FAILED;
}
-
/**
* qla24xx_dif_start_scsi() - Send a SCSI command to the ISP
* @sp: command to send to the ISP
@@ -1852,6 +1843,8 @@ skip_cmd_array:
cnt = RD_REG_DWORD(&reg->isp82.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
+ else if (IS_QLAFX00(ha))
+ cnt = RD_REG_DWORD(&reg->ispfx00.req_q_out);
else
cnt = qla2x00_debounce_register(
ISP_REQ_Q_OUT(ha, &reg->isp));
@@ -1869,8 +1862,13 @@ skip_cmd_array:
req->cnt -= req_cnt;
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
- pkt->entry_count = req_cnt;
- pkt->handle = handle;
+ if (IS_QLAFX00(ha)) {
+ WRT_REG_BYTE(&pkt->entry_count, req_cnt);
+ WRT_REG_WORD(&pkt->handle, handle);
+ } else {
+ pkt->entry_count = req_cnt;
+ pkt->handle = handle;
+ }
queuing_error:
return pkt;
@@ -2625,7 +2623,16 @@ qla2x00_start_sp(srb_t *sp)
qla2x00_adisc_iocb(sp, pkt);
break;
case SRB_TM_CMD:
- qla24xx_tm_iocb(sp, pkt);
+ IS_QLAFX00(ha) ?
+ qlafx00_tm_iocb(sp, pkt) :
+ qla24xx_tm_iocb(sp, pkt);
+ break;
+ case SRB_FXIOCB_DCMD:
+ case SRB_FXIOCB_BCMD:
+ qlafx00_fxdisc_iocb(sp, pkt);
+ break;
+ case SRB_ABT_CMD:
+ qlafx00_abort_iocb(sp, pkt);
break;
default:
break;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index e9dbd74c20d3..259d9205d876 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -13,11 +13,7 @@
#include <scsi/scsi_bsg_fc.h>
#include <scsi/scsi_eh.h>
-#include "qla_target.h"
-
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_process_completed_request(struct scsi_qla_host *,
- struct req_que *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
@@ -1065,9 +1061,9 @@ skip_rio:
* @ha: SCSI driver HA context
* @index: SRB index
*/
-static void
+void
qla2x00_process_completed_request(struct scsi_qla_host *vha,
- struct req_que *req, uint32_t index)
+ struct req_que *req, uint32_t index)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
@@ -1101,7 +1097,7 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
}
}
-static srb_t *
+srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
struct req_que *req, void *iocb)
{
@@ -1994,7 +1990,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
return;
}
- lscsi_status = scsi_status & STATUS_MASK;
+ lscsi_status = scsi_status & STATUS_MASK;
fcport = sp->fcport;
@@ -2939,7 +2935,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
/* If possible, enable MSI-X. */
if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
+ !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha))
goto skip_msi;
if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
@@ -2972,7 +2968,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
skip_msix:
if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
- !IS_QLA8001(ha) && !IS_QLA82XX(ha))
+ !IS_QLA8001(ha) && !IS_QLA82XX(ha) && !IS_QLAFX00(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
@@ -2998,9 +2994,11 @@ skip_msi:
"Failed to reserve interrupt %d already in use.\n",
ha->pdev->irq);
goto fail;
- } else if (!ha->flags.msi_enabled)
+ } else if (!ha->flags.msi_enabled) {
ql_dbg(ql_dbg_init, vha, 0x0125,
"INTa mode: Enabled.\n");
+ ha->flags.mr_intr_valid = 1;
+ }
clear_risc_ints:
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 186dd59ce4fa..9e5d89db7272 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -3866,64 +3866,6 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
return rval;
}
-int
-qla2x00_set_driver_version(scsi_qla_host_t *vha, char *version)
-{
- int rval;
- mbx_cmd_t mc;
- mbx_cmd_t *mcp = &mc;
- int len;
- uint16_t dwlen;
- uint8_t *str;
- dma_addr_t str_dma;
- struct qla_hw_data *ha = vha->hw;
-
- if (!IS_FWI2_CAPABLE(ha) || IS_QLA82XX(ha))
- return QLA_FUNCTION_FAILED;
-
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1155,
- "Entered %s.\n", __func__);
-
- str = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &str_dma);
- if (!str) {
- ql_log(ql_log_warn, vha, 0x1156,
- "Failed to allocate driver version param.\n");
- return QLA_MEMORY_ALLOC_FAILED;
- }
-
- memcpy(str, "\x7\x3\x11\x0", 4);
- dwlen = str[0];
- len = dwlen * sizeof(uint32_t) - 4;
- memset(str + 4, 0, len);
- if (len > strlen(version))
- len = strlen(version);
- memcpy(str + 4, version, len);
-
- mcp->mb[0] = MBC_SET_RNID_PARAMS;
- mcp->mb[1] = RNID_TYPE_SET_VERSION << 8 | dwlen;
- mcp->mb[2] = MSW(LSD(str_dma));
- mcp->mb[3] = LSW(LSD(str_dma));
- mcp->mb[6] = MSW(MSD(str_dma));
- mcp->mb[7] = LSW(MSD(str_dma));
- mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
- mcp->in_mb = MBX_0;
- mcp->tov = MBX_TOV_SECONDS;
- mcp->flags = 0;
- rval = qla2x00_mailbox_command(vha, mcp);
-
- if (rval != QLA_SUCCESS) {
- ql_dbg(ql_dbg_mbx, vha, 0x1157,
- "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
- } else {
- ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1158,
- "Done %s.\n", __func__);
- }
-
- dma_pool_free(ha->s_dma_pool, str, str_dma);
-
- return rval;
-}
-
static int
qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp)
{
@@ -4171,7 +4113,6 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
int rval;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- uint32_t iter_cnt = 0x1;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10f7,
"Entered %s.\n", __func__);
@@ -4197,8 +4138,8 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
mcp->mb[7] = MSW(MSD(mreq->rcv_dma));
/* Iteration count */
- mcp->mb[18] = LSW(iter_cnt);
- mcp->mb[19] = MSW(iter_cnt);
+ mcp->mb[18] = LSW(mreq->iteration_count);
+ mcp->mb[19] = MSW(mreq->iteration_count);
mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15|
MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0;
@@ -4576,7 +4517,8 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
goto done;
ql_log(ql_log_warn, vha, 0x10c9,
- "Thermal not supported by I2C.\n");
+ "Thermal not supported through I2C bus, trying alternate "
+ "method (ISP access).\n");
ha->thermal_support &= ~THERMAL_SUPPORT_I2C;
}
@@ -4586,7 +4528,7 @@ qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp)
goto done;
ql_log(ql_log_warn, vha, 0x1019,
- "Thermal not supported by ISP.\n");
+ "Thermal not supported through ISP.\n");
ha->thermal_support &= ~THERMAL_SUPPORT_ISP;
}
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
new file mode 100644
index 000000000000..729b74389f83
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -0,0 +1,3476 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#include "qla_def.h"
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
+#include <scsi/scsi_tcq.h>
+#include <linux/utsname.h>
+
+
+/* QLAFX00 specific Mailbox implementation functions */
+
+/*
+ * qlafx00_mailbox_command
+ * Issue mailbox command and waits for completion.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * mcp = driver internal mbx struct pointer.
+ *
+ * Output:
+ * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data.
+ *
+ * Returns:
+ * 0 : QLA_SUCCESS = cmd performed success
+ * 1 : QLA_FUNCTION_FAILED (error encountered)
+ * 6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered)
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp)
+
+{
+ int rval;
+ unsigned long flags = 0;
+ device_reg_t __iomem *reg;
+ uint8_t abort_active;
+ uint8_t io_lock_on;
+ uint16_t command = 0;
+ uint32_t *iptr;
+ uint32_t __iomem *optr;
+ uint32_t cnt;
+ uint32_t mboxes;
+ unsigned long wait_time;
+ struct qla_hw_data *ha = vha->hw;
+ scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+ if (ha->pdev->error_state > pci_channel_io_frozen) {
+ ql_log(ql_log_warn, vha, 0x115c,
+ "error_state is greater than pci_channel_io_frozen, "
+ "exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (vha->device_flags & DFLG_DEV_FAILED) {
+ ql_log(ql_log_warn, vha, 0x115f,
+ "Device in failed state, exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ reg = ha->iobase;
+ io_lock_on = base_vha->flags.init_done;
+
+ rval = QLA_SUCCESS;
+ abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
+
+ if (ha->flags.pci_channel_io_perm_failure) {
+ ql_log(ql_log_warn, vha, 0x1175,
+ "Perm failure on EEH timeout MBX, exiting.\n");
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (ha->flags.isp82xx_fw_hung) {
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ ql_log(ql_log_warn, vha, 0x1176,
+ "FW hung = %d.\n", ha->flags.isp82xx_fw_hung);
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
+ /*
+ * Wait for active mailbox commands to finish by waiting at most tov
+ * seconds. This is to serialize actual issuing of mailbox cmds during
+ * non ISP abort time.
+ */
+ if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) {
+ /* Timeout occurred. Return error. */
+ ql_log(ql_log_warn, vha, 0x1177,
+ "Cmd access timeout, cmd=0x%x, Exiting.\n",
+ mcp->mb[0]);
+ return QLA_FUNCTION_TIMEOUT;
+ }
+
+ ha->flags.mbox_busy = 1;
+ /* Save mailbox command for debug */
+ ha->mcp32 = mcp;
+
+ ql_dbg(ql_dbg_mbx, vha, 0x1178,
+ "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Load mailbox registers. */
+ optr = (uint32_t __iomem *)&reg->ispfx00.mailbox0;
+
+ iptr = mcp->mb;
+ command = mcp->mb[0];
+ mboxes = mcp->out_mb;
+
+ for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ if (mboxes & BIT_0)
+ WRT_REG_DWORD(optr, *iptr);
+
+ mboxes >>= 1;
+ optr++;
+ iptr++;
+ }
+
+ /* Issue set host interrupt command to send cmd out. */
+ ha->flags.mbox_int = 0;
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1172,
+ (uint8_t *)mcp->mb, 16);
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1173,
+ ((uint8_t *)mcp->mb + 0x10), 16);
+ ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1174,
+ ((uint8_t *)mcp->mb + 0x20), 8);
+
+ /* Unlock mbx registers and wait for interrupt */
+ ql_dbg(ql_dbg_mbx, vha, 0x1179,
+ "Going to unlock irq & waiting for interrupts. "
+ "jiffies=%lx.\n", jiffies);
+
+ /* Wait for mbx cmd completion until timeout */
+ if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
+ set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+ QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ);
+
+ clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+ } else {
+ ql_dbg(ql_dbg_mbx, vha, 0x112c,
+ "Cmd=%x Polling Mode.\n", command);
+
+ QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
+ while (!ha->flags.mbox_int) {
+ if (time_after(jiffies, wait_time))
+ break;
+
+ /* Check for pending interrupts. */
+ qla2x00_poll(ha->rsp_q_map[0]);
+
+ if (!ha->flags.mbox_int &&
+ !(IS_QLA2200(ha) &&
+ command == MBC_LOAD_RISC_RAM_EXTENDED))
+ usleep_range(10000, 11000);
+ } /* while */
+ ql_dbg(ql_dbg_mbx, vha, 0x112d,
+ "Waited %d sec.\n",
+ (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ));
+ }
+
+ /* Check whether we timed out */
+ if (ha->flags.mbox_int) {
+ uint32_t *iptr2;
+
+ ql_dbg(ql_dbg_mbx, vha, 0x112e,
+ "Cmd=%x completed.\n", command);
+
+ /* Got interrupt. Clear the flag. */
+ ha->flags.mbox_int = 0;
+ clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+ if (ha->mailbox_out32[0] != MBS_COMMAND_COMPLETE)
+ rval = QLA_FUNCTION_FAILED;
+
+ /* Load return mailbox registers. */
+ iptr2 = mcp->mb;
+ iptr = (uint32_t *)&ha->mailbox_out32[0];
+ mboxes = mcp->in_mb;
+ for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+ if (mboxes & BIT_0)
+ *iptr2 = *iptr;
+
+ mboxes >>= 1;
+ iptr2++;
+ iptr++;
+ }
+ } else {
+
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ ha->flags.mbox_busy = 0;
+
+ /* Clean up */
+ ha->mcp32 = NULL;
+
+ if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
+ ql_dbg(ql_dbg_mbx, vha, 0x113a,
+ "checking for additional resp interrupt.\n");
+
+ /* polling mode for non isp_abort commands. */
+ qla2x00_poll(ha->rsp_q_map[0]);
+ }
+
+ if (rval == QLA_FUNCTION_TIMEOUT &&
+ mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) {
+ if (!io_lock_on || (mcp->flags & IOCTL_CMD) ||
+ ha->flags.eeh_busy) {
+ /* not in dpc. schedule it for dpc to take over. */
+ ql_dbg(ql_dbg_mbx, vha, 0x115d,
+ "Timeout, schedule isp_abort_needed.\n");
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ ql_log(ql_log_info, base_vha, 0x115e,
+ "Mailbox cmd timeout occurred, cmd=0x%x, "
+ "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP "
+ "abort.\n", command, mcp->mb[0],
+ ha->flags.eeh_busy);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
+ } else if (!abort_active) {
+ /* call abort directly since we are in the DPC thread */
+ ql_dbg(ql_dbg_mbx, vha, 0x1160,
+ "Timeout, calling abort_isp.\n");
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ ql_log(ql_log_info, base_vha, 0x1161,
+ "Mailbox cmd timeout occurred, cmd=0x%x, "
+ "mb[0]=0x%x. Scheduling ISP abort ",
+ command, mcp->mb[0]);
+
+ set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ if (ha->isp_ops->abort_isp(vha)) {
+ /* Failed. retry later. */
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ }
+ clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ ql_dbg(ql_dbg_mbx, vha, 0x1162,
+ "Finished abort_isp.\n");
+ }
+ }
+ }
+
+premature_exit:
+ /* Allow next mbx cmd to come in. */
+ complete(&ha->mbx_cmd_comp);
+
+ if (rval) {
+ ql_log(ql_log_warn, base_vha, 0x1163,
+ "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, "
+ "mb[3]=%x, cmd=%x ****.\n",
+ mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command);
+ } else {
+ ql_dbg(ql_dbg_mbx, base_vha, 0x1164, "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_driver_shutdown
+ * Indicate a driver shutdown to firmware.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_driver_shutdown(scsi_qla_host_t *vha, int tmo)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1166,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_MR_DRV_SHUTDOWN;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_0;
+ if (tmo)
+ mcp->tov = tmo;
+ else
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1167,
+ "Failed=%x.\n", rval);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1168,
+ "Done %s.\n", __func__);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_get_firmware_state
+ * Get adapter firmware state.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ * qla7xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+static int
+qlafx00_get_firmware_state(scsi_qla_host_t *vha, uint32_t *states)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1169,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ /* Return firmware states. */
+ states[0] = mcp->mb[1];
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x116a,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116b,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/*
+ * qlafx00_init_firmware
+ * Initialize adapter firmware.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * dptr = Initialization control block pointer.
+ * size = size of initialization control block.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ * qlafx00 local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qlafx00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116c,
+ "Entered %s.\n", __func__);
+
+ mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+
+ mcp->mb[1] = 0;
+ mcp->mb[2] = MSD(ha->init_cb_dma);
+ mcp->mb[3] = LSD(ha->init_cb_dma);
+
+ mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qlafx00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x116d,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116e,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/*
+ * qlafx00_mbx_reg_test
+ */
+static int
+qlafx00_mbx_reg_test(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct mbx_cmd_32 mc;
+ struct mbx_cmd_32 *mcp = &mc;
+
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x116f,
+ "Entered %s.\n", __func__);
+
+
+ mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
+ mcp->mb[1] = 0xAAAA;
+ mcp->mb[2] = 0x5555;
+ mcp->mb[3] = 0xAA55;
+ mcp->mb[4] = 0x55AA;
+ mcp->mb[5] = 0xA5A5;
+ mcp->mb[6] = 0x5A5A;
+ mcp->mb[7] = 0x2525;
+ mcp->mb[8] = 0xBBBB;
+ mcp->mb[9] = 0x6666;
+ mcp->mb[10] = 0xBB66;
+ mcp->mb[11] = 0x66BB;
+ mcp->mb[12] = 0xB6B6;
+ mcp->mb[13] = 0x6B6B;
+ mcp->mb[14] = 0x3636;
+ mcp->mb[15] = 0xCCCC;
+
+
+ mcp->out_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
+ MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_15|MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|
+ MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->buf_size = 0;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qlafx00_mailbox_command(vha, mcp);
+ if (rval == QLA_SUCCESS) {
+ if (mcp->mb[17] != 0xAAAA || mcp->mb[18] != 0x5555 ||
+ mcp->mb[19] != 0xAA55 || mcp->mb[20] != 0x55AA)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[21] != 0xA5A5 || mcp->mb[22] != 0x5A5A ||
+ mcp->mb[23] != 0x2525 || mcp->mb[24] != 0xBBBB)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[25] != 0x6666 || mcp->mb[26] != 0xBB66 ||
+ mcp->mb[27] != 0x66BB || mcp->mb[28] != 0xB6B6)
+ rval = QLA_FUNCTION_FAILED;
+ if (mcp->mb[29] != 0x6B6B || mcp->mb[30] != 0x3636 ||
+ mcp->mb[31] != 0xCCCC)
+ rval = QLA_FUNCTION_FAILED;
+ }
+
+ if (rval != QLA_SUCCESS) {
+ ql_dbg(ql_dbg_mbx, vha, 0x1170,
+ "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
+ } else {
+ ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1171,
+ "Done %s.\n", __func__);
+ }
+ return rval;
+}
+
+/**
+ * qlafx00_pci_config() - Setup ISPFx00 PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_pci_config(scsi_qla_host_t *vha)
+{
+ uint16_t w;
+ struct qla_hw_data *ha = vha->hw;
+
+ pci_set_master(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
+
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+ /* PCIe -- adjust Maximum Read Request Size (2048). */
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
+
+ ha->chip_revision = ha->pdev->revision;
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qlafx00_warm_reset() - Perform warm reset of iSA(CPUs being reset on SOC).
+ * @ha: HA context
+ *
+ */
+static inline void
+qlafx00_soc_cpu_reset(scsi_qla_host_t *vha)
+{
+ unsigned long flags = 0;
+ struct qla_hw_data *ha = vha->hw;
+ int i, core;
+ uint32_t cnt;
+
+ /* Set all 4 cores in reset */
+ for (i = 0; i < 4; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_SW_RST_CONTROL_REG_CORE0 + 8*i), (0xF01));
+ }
+
+ /* Set all 4 core Clock gating control */
+ for (i = 0; i < 4; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_SW_RST_CONTROL_REG_CORE0 + 4 + 8*i), (0x01010101));
+ }
+
+ /* Reset all units in Fabric */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x11F0101));
+
+ /* Reset all interrupt control registers */
+ for (i = 0; i < 115; i++) {
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_INTERRUPT_SOURCE_I_CONTROL_REG + 4*i), (0x0));
+ }
+
+ /* Reset Timers control registers. per core */
+ for (core = 0; core < 4; core++)
+ for (i = 0; i < 8; i++)
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_CORE_TIMER_REG + 0x100*core + 4*i), (0x0));
+
+ /* Reset per core IRQ ack register */
+ for (core = 0; core < 4; core++)
+ QLAFX00_SET_HBA_SOC_REG(ha,
+ (SOC_IRQ_ACK_REG + 0x100*core), (0x3FF));
+
+ /* Set Fabric control and config to defaults */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONTROL_REG, (0x2));
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_CONFIG_REG, (0x3));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Kick in Fabric units */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_FABRIC_RST_CONTROL_REG, (0x0));
+
+ /* Kick in Core0 to start boot process */
+ QLAFX00_SET_HBA_SOC_REG(ha, SOC_SW_RST_CONTROL_REG_CORE0, (0xF00));
+
+ /* Wait 10secs for soft-reset to complete. */
+ for (cnt = 10; cnt; cnt--) {
+ msleep(1000);
+ barrier();
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qlafx00_soft_reset() - Soft Reset ISPFx00.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+void
+qlafx00_soft_reset(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (unlikely(pci_channel_offline(ha->pdev) &&
+ ha->flags.pci_channel_io_perm_failure))
+ return;
+
+ ha->isp_ops->disable_intrs(ha);
+ qlafx00_soc_cpu_reset(vha);
+ ha->isp_ops->enable_intrs(ha);
+}
+
+/**
+ * qlafx00_chip_diag() - Test ISPFx00 for proper operation.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_chip_diag(scsi_qla_host_t *vha)
+{
+ int rval = 0;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+
+ ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
+
+ rval = qlafx00_mbx_reg_test(vha);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x1165,
+ "Failed mailbox send register test\n");
+ } else {
+ /* Flag a successful rval */
+ rval = QLA_SUCCESS;
+ }
+ return rval;
+}
+
+void
+qlafx00_config_rings(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ struct init_cb_fx *icb;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+
+ /* Setup ring parameters in initialization control block. */
+ icb = (struct init_cb_fx *)ha->init_cb;
+ icb->request_q_outpointer = __constant_cpu_to_le16(0);
+ icb->response_q_inpointer = __constant_cpu_to_le16(0);
+ icb->request_q_length = cpu_to_le16(req->length);
+ icb->response_q_length = cpu_to_le16(rsp->length);
+ icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
+ icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
+ icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
+ icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
+
+ WRT_REG_DWORD(&reg->req_q_in, 0);
+ WRT_REG_DWORD(&reg->req_q_out, 0);
+
+ WRT_REG_DWORD(&reg->rsp_q_in, 0);
+ WRT_REG_DWORD(&reg->rsp_q_out, 0);
+
+ /* PCI posting */
+ RD_REG_DWORD(&reg->rsp_q_out);
+}
+
+char *
+qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str)
+{
+ struct qla_hw_data *ha = vha->hw;
+ int pcie_reg;
+
+ pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
+ if (pcie_reg) {
+ strcpy(str, "PCIe iSA");
+ return str;
+ }
+ return str;
+}
+
+char *
+qlafx00_fw_version_str(struct scsi_qla_host *vha, char *str)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ sprintf(str, "%s", ha->mr.fw_version);
+ return str;
+}
+
+void
+qlafx00_enable_intrs(struct qla_hw_data *ha)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ QLAFX00_ENABLE_ICNTRL_REG(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void
+qlafx00_disable_intrs(struct qla_hw_data *ha)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ QLAFX00_DISABLE_ICNTRL_REG(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qlafx00_tmf_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
+ tmf->u.tmf.comp_status = CS_TIMEOUT;
+ complete(&tmf->u.tmf.comp);
+}
+
+static void
+qlafx00_tmf_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
+ complete(&tmf->u.tmf.comp);
+}
+
+static int
+qlafx00_async_tm_cmd(fc_port_t *fcport, uint32_t flags,
+ uint32_t lun, uint32_t tag)
+{
+ scsi_qla_host_t *vha = fcport->vha;
+ struct srb_iocb *tm_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ tm_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_TM_CMD;
+ sp->name = "tmf";
+ qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha));
+ tm_iocb->u.tmf.flags = flags;
+ tm_iocb->u.tmf.lun = lun;
+ tm_iocb->u.tmf.data = tag;
+ sp->done = qlafx00_tmf_sp_done;
+ tm_iocb->timeout = qlafx00_tmf_iocb_timeout;
+ init_completion(&tm_iocb->u.tmf.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507b,
+ "Task management command issued target_id=%x\n",
+ fcport->tgt_id);
+
+ wait_for_completion(&tm_iocb->u.tmf.comp);
+
+ rval = tm_iocb->u.tmf.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+int
+qlafx00_abort_target(fc_port_t *fcport, unsigned int l, int tag)
+{
+ return qlafx00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+}
+
+int
+qlafx00_lun_reset(fc_port_t *fcport, unsigned int l, int tag)
+{
+ return qlafx00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+}
+
+int
+qlafx00_iospace_config(struct qla_hw_data *ha)
+{
+ if (pci_request_selected_regions(ha->pdev, ha->bars,
+ QLA2XXX_DRIVER_NAME)) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x014e,
+ "Failed to reserve PIO/MMIO regions (%s), aborting.\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ /* Use MMIO operations for all accesses. */
+ if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x014f,
+ "Invalid pci I/O region size (%s).\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+ if (pci_resource_len(ha->pdev, 0) < BAR0_LEN_FX00) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x0127,
+ "Invalid PCI mem BAR0 region size (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ ha->cregbase =
+ ioremap_nocache(pci_resource_start(ha->pdev, 0), BAR0_LEN_FX00);
+ if (!ha->cregbase) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x0128,
+ "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ if (!(pci_resource_flags(ha->pdev, 2) & IORESOURCE_MEM)) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x0129,
+ "region #2 not an MMIO resource (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+ if (pci_resource_len(ha->pdev, 2) < BAR2_LEN_FX00) {
+ ql_log_pci(ql_log_warn, ha->pdev, 0x012a,
+ "Invalid PCI mem BAR2 region size (%s), aborting\n",
+ pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ ha->iobase =
+ ioremap_nocache(pci_resource_start(ha->pdev, 2), BAR2_LEN_FX00);
+ if (!ha->iobase) {
+ ql_log_pci(ql_log_fatal, ha->pdev, 0x012b,
+ "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+ goto iospace_error_exit;
+ }
+
+ /* Determine queue resources */
+ ha->max_req_queues = ha->max_rsp_queues = 1;
+
+ ql_log_pci(ql_log_info, ha->pdev, 0x012c,
+ "Bars 0x%x, iobase0 0x%p, iobase2 0x%p\n",
+ ha->bars, ha->cregbase, ha->iobase);
+
+ return 0;
+
+iospace_error_exit:
+ return -ENOMEM;
+}
+
+static void
+qlafx00_save_queue_ptrs(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+
+ req->length_fx00 = req->length;
+ req->ring_fx00 = req->ring;
+ req->dma_fx00 = req->dma;
+
+ rsp->length_fx00 = rsp->length;
+ rsp->ring_fx00 = rsp->ring;
+ rsp->dma_fx00 = rsp->dma;
+
+ ql_dbg(ql_dbg_init, vha, 0x012d,
+ "req: %p, ring_fx00: %p, length_fx00: 0x%x,"
+ "req->dma_fx00: 0x%llx\n", req, req->ring_fx00,
+ req->length_fx00, (u64)req->dma_fx00);
+
+ ql_dbg(ql_dbg_init, vha, 0x012e,
+ "rsp: %p, ring_fx00: %p, length_fx00: 0x%x,"
+ "rsp->dma_fx00: 0x%llx\n", rsp, rsp->ring_fx00,
+ rsp->length_fx00, (u64)rsp->dma_fx00);
+}
+
+static int
+qlafx00_config_queues(struct scsi_qla_host *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = ha->req_q_map[0];
+ struct rsp_que *rsp = ha->rsp_q_map[0];
+ dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2);
+
+ req->length = ha->req_que_len;
+ req->ring = (void *)ha->iobase + ha->req_que_off;
+ req->dma = bar2_hdl + ha->req_que_off;
+ if ((!req->ring) || (req->length == 0)) {
+ ql_log_pci(ql_log_info, ha->pdev, 0x012f,
+ "Unable to allocate memory for req_ring\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x0130,
+ "req: %p req_ring pointer %p req len 0x%x "
+ "req off 0x%x\n, req->dma: 0x%llx",
+ req, req->ring, req->length,
+ ha->req_que_off, (u64)req->dma);
+
+ rsp->length = ha->rsp_que_len;
+ rsp->ring = (void *)ha->iobase + ha->rsp_que_off;
+ rsp->dma = bar2_hdl + ha->rsp_que_off;
+ if ((!rsp->ring) || (rsp->length == 0)) {
+ ql_log_pci(ql_log_info, ha->pdev, 0x0131,
+ "Unable to allocate memory for rsp_ring\n");
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_init, vha, 0x0132,
+ "rsp: %p rsp_ring pointer %p rsp len 0x%x "
+ "rsp off 0x%x, rsp->dma: 0x%llx\n",
+ rsp, rsp->ring, rsp->length,
+ ha->rsp_que_off, (u64)rsp->dma);
+
+ return QLA_SUCCESS;
+}
+
+static int
+qlafx00_init_fw_ready(scsi_qla_host_t *vha)
+{
+ int rval = 0;
+ unsigned long wtime;
+ uint16_t wait_time; /* Wait time */
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ uint32_t aenmbx, aenmbx7 = 0;
+ uint32_t state[5];
+ bool done = false;
+
+ /* 30 seconds wait - Adjust if required */
+ wait_time = 30;
+
+ /* wait time before firmware ready */
+ wtime = jiffies + (wait_time * HZ);
+ do {
+ aenmbx = RD_REG_DWORD(&reg->aenmailbox0);
+ barrier();
+ ql_dbg(ql_dbg_mbx, vha, 0x0133,
+ "aenmbx: 0x%x\n", aenmbx);
+
+ switch (aenmbx) {
+ case MBA_FW_NOT_STARTED:
+ case MBA_FW_STARTING:
+ break;
+
+ case MBA_SYSTEM_ERR:
+ case MBA_REQ_TRANSFER_ERR:
+ case MBA_RSP_TRANSFER_ERR:
+ case MBA_FW_INIT_FAILURE:
+ qlafx00_soft_reset(vha);
+ break;
+
+ case MBA_FW_RESTART_CMPLT:
+ /* Set the mbx and rqstq intr code */
+ aenmbx7 = RD_REG_DWORD(&reg->aenmailbox7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->aenmailbox3);
+ ha->req_que_len = RD_REG_DWORD(&reg->aenmailbox5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->aenmailbox6);
+ WRT_REG_DWORD(&reg->aenmailbox0, 0);
+ RD_REG_DWORD_RELAXED(&reg->aenmailbox0);
+ ql_dbg(ql_dbg_init, vha, 0x0134,
+ "f/w returned mbx_intr_code: 0x%x, "
+ "rqstq_intr_code: 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code);
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+ rval = QLA_SUCCESS;
+ done = true;
+ break;
+
+ default:
+ /* If fw is apparently not ready. In order to continue,
+ * we might need to issue Mbox cmd, but the problem is
+ * that the DoorBell vector values that come with the
+ * 8060 AEN are most likely gone by now (and thus no
+ * bell would be rung on the fw side when mbox cmd is
+ * issued). We have to therefore grab the 8060 AEN
+ * shadow regs (filled in by FW when the last 8060
+ * AEN was being posted).
+ * Do the following to determine what is needed in
+ * order to get the FW ready:
+ * 1. reload the 8060 AEN values from the shadow regs
+ * 2. clear int status to get rid of possible pending
+ * interrupts
+ * 3. issue Get FW State Mbox cmd to determine fw state
+ * Set the mbx and rqstq intr code from Shadow Regs
+ */
+ aenmbx7 = RD_REG_DWORD(&reg->initval7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->initval1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->initval3);
+ ha->req_que_len = RD_REG_DWORD(&reg->initval5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->initval6);
+ ql_dbg(ql_dbg_init, vha, 0x0135,
+ "f/w returned mbx_intr_code: 0x%x, "
+ "rqstq_intr_code: 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code);
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ /* Get the FW state */
+ rval = qlafx00_get_firmware_state(vha, state);
+ if (rval != QLA_SUCCESS) {
+ /* Retry if timer has not expired */
+ break;
+ }
+
+ if (state[0] == FSTATE_FX00_CONFIG_WAIT) {
+ /* Firmware is waiting to be
+ * initialized by driver
+ */
+ rval = QLA_SUCCESS;
+ done = true;
+ break;
+ }
+
+ /* Issue driver shutdown and wait until f/w recovers.
+ * Driver should continue to poll until 8060 AEN is
+ * received indicating firmware recovery.
+ */
+ ql_dbg(ql_dbg_init, vha, 0x0136,
+ "Sending Driver shutdown fw_state 0x%x\n",
+ state[0]);
+
+ rval = qlafx00_driver_shutdown(vha, 10);
+ if (rval != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ break;
+ }
+ msleep(500);
+
+ wtime = jiffies + (wait_time * HZ);
+ break;
+ }
+
+ if (!done) {
+ if (time_after_eq(jiffies, wtime)) {
+ ql_dbg(ql_dbg_init, vha, 0x0137,
+ "Init f/w failed: aen[7]: 0x%x\n",
+ RD_REG_DWORD(&reg->aenmailbox7));
+ rval = QLA_FUNCTION_FAILED;
+ done = true;
+ break;
+ }
+ /* Delay for a while */
+ msleep(500);
+ }
+ } while (!done);
+
+ if (rval)
+ ql_dbg(ql_dbg_init, vha, 0x0138,
+ "%s **** FAILED ****.\n", __func__);
+ else
+ ql_dbg(ql_dbg_init, vha, 0x0139,
+ "%s **** SUCCESS ****.\n", __func__);
+
+ return rval;
+}
+
+/*
+ * qlafx00_fw_ready() - Waits for firmware ready.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qlafx00_fw_ready(scsi_qla_host_t *vha)
+{
+ int rval;
+ unsigned long wtime;
+ uint16_t wait_time; /* Wait time if loop is coming ready */
+ uint32_t state[5];
+
+ rval = QLA_SUCCESS;
+
+ wait_time = 10;
+
+ /* wait time before firmware ready */
+ wtime = jiffies + (wait_time * HZ);
+
+ /* Wait for ISP to finish init */
+ if (!vha->flags.init_done)
+ ql_dbg(ql_dbg_init, vha, 0x013a,
+ "Waiting for init to complete...\n");
+
+ do {
+ rval = qlafx00_get_firmware_state(vha, state);
+
+ if (rval == QLA_SUCCESS) {
+ if (state[0] == FSTATE_FX00_INITIALIZED) {
+ ql_dbg(ql_dbg_init, vha, 0x013b,
+ "fw_state=%x\n", state[0]);
+ rval = QLA_SUCCESS;
+ break;
+ }
+ }
+ rval = QLA_FUNCTION_FAILED;
+
+ if (time_after_eq(jiffies, wtime))
+ break;
+
+ /* Delay for a while */
+ msleep(500);
+
+ ql_dbg(ql_dbg_init, vha, 0x013c,
+ "fw_state=%x curr time=%lx.\n", state[0], jiffies);
+ } while (1);
+
+
+ if (rval)
+ ql_dbg(ql_dbg_init, vha, 0x013d,
+ "Firmware ready **** FAILED ****.\n");
+ else
+ ql_dbg(ql_dbg_init, vha, 0x013e,
+ "Firmware ready **** SUCCESS ****.\n");
+
+ return rval;
+}
+
+static int
+qlafx00_find_all_targets(scsi_qla_host_t *vha,
+ struct list_head *new_fcports)
+{
+ int rval;
+ uint16_t tgt_id;
+ fc_port_t *fcport, *new_fcport;
+ int found;
+ struct qla_hw_data *ha = vha->hw;
+
+ rval = QLA_SUCCESS;
+
+ if (!test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
+ return QLA_FUNCTION_FAILED;
+
+ if ((atomic_read(&vha->loop_down_timer) ||
+ STATE_TRANSITION(vha))) {
+ atomic_set(&vha->loop_down_timer, 0);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x2088,
+ "Listing Target bit map...\n");
+ ql_dump_buffer(ql_dbg_disc + ql_dbg_init, vha,
+ 0x2089, (uint8_t *)ha->gid_list, 32);
+
+ /* Allocate temporary rmtport for any new rmtports discovered. */
+ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (new_fcport == NULL)
+ return QLA_MEMORY_ALLOC_FAILED;
+
+ for_each_set_bit(tgt_id, (void *)ha->gid_list,
+ QLAFX00_TGT_NODE_LIST_SIZE) {
+
+ /* Send get target node info */
+ new_fcport->tgt_id = tgt_id;
+ rval = qlafx00_fx_disc(vha, new_fcport,
+ FXDISC_GET_TGT_NODE_INFO);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x208a,
+ "Target info scan failed -- assuming zero-entry "
+ "result...\n");
+ continue;
+ }
+
+ /* Locate matching device in database. */
+ found = 0;
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (memcmp(new_fcport->port_name,
+ fcport->port_name, WWN_SIZE))
+ continue;
+
+ found++;
+
+ /*
+ * If tgt_id is same and state FCS_ONLINE, nothing
+ * changed.
+ */
+ if (fcport->tgt_id == new_fcport->tgt_id &&
+ atomic_read(&fcport->state) == FCS_ONLINE)
+ break;
+
+ /*
+ * Tgt ID changed or device was marked to be updated.
+ */
+ ql_dbg(ql_dbg_disc + ql_dbg_init, vha, 0x208b,
+ "TGT-ID Change(%s): Present tgt id: "
+ "0x%x state: 0x%x "
+ "wwnn = %llx wwpn = %llx.\n",
+ __func__, fcport->tgt_id,
+ atomic_read(&fcport->state),
+ (unsigned long long)wwn_to_u64(fcport->node_name),
+ (unsigned long long)wwn_to_u64(fcport->port_name));
+
+ ql_log(ql_log_info, vha, 0x208c,
+ "TGT-ID Announce(%s): Discovered tgt "
+ "id 0x%x wwnn = %llx "
+ "wwpn = %llx.\n", __func__, new_fcport->tgt_id,
+ (unsigned long long)
+ wwn_to_u64(new_fcport->node_name),
+ (unsigned long long)
+ wwn_to_u64(new_fcport->port_name));
+
+ if (atomic_read(&fcport->state) != FCS_ONLINE) {
+ fcport->old_tgt_id = fcport->tgt_id;
+ fcport->tgt_id = new_fcport->tgt_id;
+ ql_log(ql_log_info, vha, 0x208d,
+ "TGT-ID: New fcport Added: %p\n", fcport);
+ qla2x00_update_fcport(vha, fcport);
+ } else {
+ ql_log(ql_log_info, vha, 0x208e,
+ " Existing TGT-ID %x did not get "
+ " offline event from firmware.\n",
+ fcport->old_tgt_id);
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ kfree(new_fcport);
+ return rval;
+ }
+ break;
+ }
+
+ if (found)
+ continue;
+
+ /* If device was not in our fcports list, then add it. */
+ list_add_tail(&new_fcport->list, new_fcports);
+
+ /* Allocate a new replacement fcport. */
+ new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
+ if (new_fcport == NULL)
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+
+ kfree(new_fcport);
+ return rval;
+}
+
+/*
+ * qlafx00_configure_all_targets
+ * Setup target devices with node ID's.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ * BIT_0 = error
+ */
+static int
+qlafx00_configure_all_targets(scsi_qla_host_t *vha)
+{
+ int rval;
+ fc_port_t *fcport, *rmptemp;
+ LIST_HEAD(new_fcports);
+
+ rval = qlafx00_fx_disc(vha, &vha->hw->mr.fcport,
+ FXDISC_GET_TGT_NODE_LIST);
+ if (rval != QLA_SUCCESS) {
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return rval;
+ }
+
+ rval = qlafx00_find_all_targets(vha, &new_fcports);
+ if (rval != QLA_SUCCESS) {
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return rval;
+ }
+
+ /*
+ * Delete all previous devices marked lost.
+ */
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+ break;
+
+ if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+ if (fcport->port_type != FCT_INITIATOR)
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ }
+ }
+
+ /*
+ * Add the new devices to our devices list.
+ */
+ list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
+ break;
+
+ qla2x00_update_fcport(vha, fcport);
+ list_move_tail(&fcport->list, &vha->vp_fcports);
+ ql_log(ql_log_info, vha, 0x208f,
+ "Attach new target id 0x%x wwnn = %llx "
+ "wwpn = %llx.\n",
+ fcport->tgt_id,
+ (unsigned long long)wwn_to_u64(fcport->node_name),
+ (unsigned long long)wwn_to_u64(fcport->port_name));
+ }
+
+ /* Free all new device structures not processed. */
+ list_for_each_entry_safe(fcport, rmptemp, &new_fcports, list) {
+ list_del(&fcport->list);
+ kfree(fcport);
+ }
+
+ return rval;
+}
+
+/*
+ * qlafx00_configure_devices
+ * Updates Fibre Channel Device Database with what is actually on loop.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success.
+ * 1 = error.
+ * 2 = database was full and device was not configured.
+ */
+int
+qlafx00_configure_devices(scsi_qla_host_t *vha)
+{
+ int rval;
+ unsigned long flags, save_flags;
+ rval = QLA_SUCCESS;
+
+ save_flags = flags = vha->dpc_flags;
+
+ ql_dbg(ql_dbg_disc, vha, 0x2090,
+ "Configure devices -- dpc flags =0x%lx\n", flags);
+
+ rval = qlafx00_configure_all_targets(vha);
+
+ if (rval == QLA_SUCCESS) {
+ if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ atomic_set(&vha->loop_state, LOOP_READY);
+ ql_log(ql_log_info, vha, 0x2091,
+ "Device Ready\n");
+ }
+ }
+
+ if (rval) {
+ ql_dbg(ql_dbg_disc, vha, 0x2092,
+ "%s *** FAILED ***.\n", __func__);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0x2093,
+ "%s: exiting normally.\n", __func__);
+ }
+ return rval;
+}
+
+static void
+qlafx00_abort_isp_cleanup(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ fc_port_t *fcport;
+
+ vha->flags.online = 0;
+ ha->flags.chip_reset_done = 0;
+ ha->mr.fw_hbt_en = 0;
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ vha->qla_stats.total_isp_aborts++;
+
+ ql_log(ql_log_info, vha, 0x013f,
+ "Performing ISP error recovery - ha = %p.\n", ha);
+
+ ha->isp_ops->reset_chip(vha);
+
+ if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer,
+ QLAFX00_LOOP_DOWN_TIME);
+ } else {
+ if (!atomic_read(&vha->loop_down_timer))
+ atomic_set(&vha->loop_down_timer,
+ QLAFX00_LOOP_DOWN_TIME);
+ }
+
+ /* Clear all async request states across all VPs. */
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ fcport->flags = 0;
+ if (atomic_read(&fcport->state) == FCS_ONLINE)
+ qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
+ }
+
+ if (!ha->flags.eeh_busy) {
+ /* Requeue all commands in outstanding command list. */
+ qla2x00_abort_all_cmds(vha, DID_RESET << 16);
+ }
+
+ qla2x00_free_irqs(vha);
+ set_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+
+ /* Clear the Interrupts */
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ ql_log(ql_log_info, vha, 0x0140,
+ "%s Done done - ha=%p.\n", __func__, ha);
+}
+
+/**
+ * qlafx00_init_response_q_entries() - Initializes response queue entries.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ *
+ * Returns 0 on success.
+ */
+void
+qlafx00_init_response_q_entries(struct rsp_que *rsp)
+{
+ uint16_t cnt;
+ response_t *pkt;
+
+ rsp->ring_ptr = rsp->ring;
+ rsp->ring_index = 0;
+ rsp->status_srb = NULL;
+ pkt = rsp->ring_ptr;
+ for (cnt = 0; cnt < rsp->length; cnt++) {
+ pkt->signature = RESPONSE_PROCESSED;
+ WRT_REG_DWORD(&pkt->signature, RESPONSE_PROCESSED);
+ pkt++;
+ }
+}
+
+int
+qlafx00_rescan_isp(scsi_qla_host_t *vha)
+{
+ uint32_t status = QLA_FUNCTION_FAILED;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+ uint32_t aenmbx7;
+
+ qla2x00_request_irqs(ha, ha->rsp_q_map[0]);
+
+ aenmbx7 = RD_REG_DWORD(&reg->aenmailbox7);
+ ha->mbx_intr_code = MSW(aenmbx7);
+ ha->rqstq_intr_code = LSW(aenmbx7);
+ ha->req_que_off = RD_REG_DWORD(&reg->aenmailbox1);
+ ha->rsp_que_off = RD_REG_DWORD(&reg->aenmailbox3);
+ ha->req_que_len = RD_REG_DWORD(&reg->aenmailbox5);
+ ha->rsp_que_len = RD_REG_DWORD(&reg->aenmailbox6);
+
+ ql_dbg(ql_dbg_disc, vha, 0x2094,
+ "fw returned mbx_intr_code: 0x%x, rqstq_intr_code: 0x%x "
+ " Req que offset 0x%x Rsp que offset 0x%x\n",
+ ha->mbx_intr_code, ha->rqstq_intr_code,
+ ha->req_que_off, ha->rsp_que_len);
+
+ /* Clear the Interrupts */
+ QLAFX00_CLR_INTR_REG(ha, QLAFX00_HST_INT_STS_BITS);
+
+ status = qla2x00_init_rings(vha);
+ if (!status) {
+ vha->flags.online = 1;
+
+ /* if no cable then assume it's good */
+ if ((vha->device_flags & DFLG_NO_CABLE))
+ status = 0;
+ /* Register system information */
+ if (qlafx00_fx_disc(vha,
+ &vha->hw->mr.fcport, FXDISC_REG_HOST_INFO))
+ ql_dbg(ql_dbg_disc, vha, 0x2095,
+ "failed to register host info\n");
+ }
+ scsi_unblock_requests(vha->host);
+ return status;
+}
+
+void
+qlafx00_timer_routine(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t fw_heart_beat;
+ uint32_t aenmbx0;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+
+ /* Check firmware health */
+ if (ha->mr.fw_hbt_cnt)
+ ha->mr.fw_hbt_cnt--;
+ else {
+ if ((!ha->flags.mr_reset_hdlr_active) &&
+ (!test_bit(UNLOADING, &vha->dpc_flags)) &&
+ (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
+ (ha->mr.fw_hbt_en)) {
+ fw_heart_beat = RD_REG_DWORD(&reg->fwheartbeat);
+ if (fw_heart_beat != ha->mr.old_fw_hbt_cnt) {
+ ha->mr.old_fw_hbt_cnt = fw_heart_beat;
+ ha->mr.fw_hbt_miss_cnt = 0;
+ } else {
+ ha->mr.fw_hbt_miss_cnt++;
+ if (ha->mr.fw_hbt_miss_cnt ==
+ QLAFX00_HEARTBEAT_MISS_CNT) {
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_hbt_miss_cnt = 0;
+ }
+ }
+ }
+ ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
+ }
+
+ if (test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags)) {
+ /* Reset recovery to be performed in timer routine */
+ aenmbx0 = RD_REG_DWORD(&reg->aenmailbox0);
+ if (ha->mr.fw_reset_timer_exp) {
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_reset_timer_exp = 0;
+ } else if (aenmbx0 == MBA_FW_RESTART_CMPLT) {
+ /* Wake up DPC to rescan the targets */
+ set_bit(FX00_TARGET_SCAN, &vha->dpc_flags);
+ clear_bit(FX00_RESET_RECOVERY, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ } else if ((aenmbx0 == MBA_FW_STARTING) &&
+ (!ha->mr.fw_hbt_en)) {
+ ha->mr.fw_hbt_en = 1;
+ } else if (!ha->mr.fw_reset_timer_tick) {
+ if (aenmbx0 == ha->mr.old_aenmbx0_state)
+ ha->mr.fw_reset_timer_exp = 1;
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ } else if (aenmbx0 == 0xFFFFFFFF) {
+ uint32_t data0, data1;
+
+ data0 = QLAFX00_RD_REG(ha,
+ QLAFX00_BAR1_BASE_ADDR_REG);
+ data1 = QLAFX00_RD_REG(ha,
+ QLAFX00_PEX0_WIN0_BASE_ADDR_REG);
+
+ data0 &= 0xffff0000;
+ data1 &= 0x0000ffff;
+
+ QLAFX00_WR_REG(ha,
+ QLAFX00_PEX0_WIN0_BASE_ADDR_REG,
+ (data0 | data1));
+ } else if ((aenmbx0 & 0xFF00) == MBA_FW_POLL_STATE) {
+ ha->mr.fw_reset_timer_tick =
+ QLAFX00_MAX_RESET_INTERVAL;
+ }
+ ha->mr.old_aenmbx0_state = aenmbx0;
+ ha->mr.fw_reset_timer_tick--;
+ }
+}
+
+/*
+ * qlfx00a_reset_initialize
+ * Re-initialize after a iSA device reset.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_reset_initialize(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->device_flags & DFLG_DEV_FAILED) {
+ ql_dbg(ql_dbg_init, vha, 0x0142,
+ "Device in failed state\n");
+ return QLA_SUCCESS;
+ }
+
+ ha->flags.mr_reset_hdlr_active = 1;
+
+ if (vha->flags.online) {
+ scsi_block_requests(vha->host);
+ qlafx00_abort_isp_cleanup(vha);
+ }
+
+ ql_log(ql_log_info, vha, 0x0143,
+ "(%s): succeeded.\n", __func__);
+ ha->flags.mr_reset_hdlr_active = 0;
+ return QLA_SUCCESS;
+}
+
+/*
+ * qlafx00_abort_isp
+ * Resets ISP and aborts all outstanding commands.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_abort_isp(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+
+ if (vha->flags.online) {
+ if (unlikely(pci_channel_offline(ha->pdev) &&
+ ha->flags.pci_channel_io_perm_failure)) {
+ clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
+ return QLA_SUCCESS;
+ }
+
+ scsi_block_requests(vha->host);
+ qlafx00_abort_isp_cleanup(vha);
+ }
+
+ ql_log(ql_log_info, vha, 0x0145,
+ "(%s): succeeded.\n", __func__);
+
+ return QLA_SUCCESS;
+}
+
+static inline fc_port_t*
+qlafx00_get_fcport(struct scsi_qla_host *vha, int tgt_id)
+{
+ fc_port_t *fcport;
+
+ /* Check for matching device in remote port list. */
+ fcport = NULL;
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (fcport->tgt_id == tgt_id) {
+ ql_dbg(ql_dbg_async, vha, 0x5072,
+ "Matching fcport(%p) found with TGT-ID: 0x%x "
+ "and Remote TGT_ID: 0x%x\n",
+ fcport, fcport->tgt_id, tgt_id);
+ break;
+ }
+ }
+ return fcport;
+}
+
+static void
+qlafx00_tgt_detach(struct scsi_qla_host *vha, int tgt_id)
+{
+ fc_port_t *fcport;
+
+ ql_log(ql_log_info, vha, 0x5073,
+ "Detach TGT-ID: 0x%x\n", tgt_id);
+
+ fcport = qlafx00_get_fcport(vha, tgt_id);
+ if (!fcport)
+ return;
+
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+
+ return;
+}
+
+int
+qlafx00_process_aen(struct scsi_qla_host *vha, struct qla_work_evt *evt)
+{
+ int rval = 0;
+ uint32_t aen_code, aen_data;
+
+ aen_code = FCH_EVT_VENDOR_UNIQUE;
+ aen_data = evt->u.aenfx.evtcode;
+
+ switch (evt->u.aenfx.evtcode) {
+ case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
+ if (evt->u.aenfx.mbx[1] == 0) {
+ if (evt->u.aenfx.mbx[2] == 1) {
+ if (!vha->flags.fw_tgt_reported)
+ vha->flags.fw_tgt_reported = 1;
+ atomic_set(&vha->loop_down_timer, 0);
+ atomic_set(&vha->loop_state, LOOP_UP);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ } else if (evt->u.aenfx.mbx[2] == 2) {
+ qlafx00_tgt_detach(vha, evt->u.aenfx.mbx[3]);
+ }
+ } else if (evt->u.aenfx.mbx[1] == 0xffff) {
+ if (evt->u.aenfx.mbx[2] == 1) {
+ if (!vha->flags.fw_tgt_reported)
+ vha->flags.fw_tgt_reported = 1;
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ } else if (evt->u.aenfx.mbx[2] == 2) {
+ vha->device_flags |= DFLG_NO_CABLE;
+ qla2x00_mark_all_devices_lost(vha, 1);
+ }
+ }
+ break;
+ case QLAFX00_MBA_LINK_UP:
+ aen_code = FCH_EVT_LINKUP;
+ aen_data = 0;
+ break;
+ case QLAFX00_MBA_LINK_DOWN:
+ aen_code = FCH_EVT_LINKDOWN;
+ aen_data = 0;
+ break;
+ }
+
+ fc_host_post_event(vha->host, fc_get_event_number(),
+ aen_code, aen_data);
+
+ return rval;
+}
+
+static void
+qlafx00_update_host_attr(scsi_qla_host_t *vha, struct port_info_data *pinfo)
+{
+ u64 port_name = 0, node_name = 0;
+
+ port_name = (unsigned long long)wwn_to_u64(pinfo->port_name);
+ node_name = (unsigned long long)wwn_to_u64(pinfo->node_name);
+
+ fc_host_node_name(vha->host) = node_name;
+ fc_host_port_name(vha->host) = port_name;
+ if (!pinfo->port_type)
+ vha->hw->current_topology = ISP_CFG_F;
+ if (pinfo->link_status == QLAFX00_LINK_STATUS_UP)
+ atomic_set(&vha->loop_state, LOOP_READY);
+ else if (pinfo->link_status == QLAFX00_LINK_STATUS_DOWN)
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->hw->link_data_rate = (uint16_t)pinfo->link_config;
+}
+
+static void
+qla2x00_fxdisc_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+
+ complete(&lio->u.fxiocb.fxiocb_comp);
+}
+
+static void
+qla2x00_fxdisc_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+
+ complete(&lio->u.fxiocb.fxiocb_comp);
+}
+
+int
+qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t fx_type)
+{
+ srb_t *sp;
+ struct srb_iocb *fdisc;
+ int rval = QLA_FUNCTION_FAILED;
+ struct qla_hw_data *ha = vha->hw;
+ struct host_system_info *phost_info;
+ struct register_host_info *preg_hsi;
+ struct new_utsname *p_sysid = NULL;
+ struct timeval tv;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ fdisc = &sp->u.iocb_cmd;
+ switch (fx_type) {
+ case FXDISC_GET_CONFIG_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID;
+ fdisc->u.fxiocb.rsp_len = sizeof(struct config_info_data);
+ break;
+ case FXDISC_GET_PORT_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_PORT_DATA_INFO;
+ fdisc->u.fxiocb.req_data = fcport->port_id;
+ break;
+ case FXDISC_GET_TGT_NODE_INFO:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_INFO;
+ fdisc->u.fxiocb.req_data = fcport->tgt_id;
+ break;
+ case FXDISC_GET_TGT_NODE_LIST:
+ fdisc->u.fxiocb.flags =
+ SRB_FXDISC_RESP_DMA_VALID | SRB_FXDISC_REQ_DWRD_VALID;
+ fdisc->u.fxiocb.rsp_len = QLAFX00_TGT_NODE_LIST_SIZE;
+ break;
+ case FXDISC_REG_HOST_INFO:
+ fdisc->u.fxiocb.flags = SRB_FXDISC_REQ_DMA_VALID;
+ fdisc->u.fxiocb.req_len = sizeof(struct register_host_info);
+ p_sysid = utsname();
+ if (!p_sysid) {
+ ql_log(ql_log_warn, vha, 0x303c,
+ "Not able to get the system informtion\n");
+ goto done_free_sp;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (fdisc->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
+ fdisc->u.fxiocb.req_addr = dma_alloc_coherent(&ha->pdev->dev,
+ fdisc->u.fxiocb.req_len,
+ &fdisc->u.fxiocb.req_dma_handle, GFP_KERNEL);
+ if (!fdisc->u.fxiocb.req_addr)
+ goto done_free_sp;
+
+ if (fx_type == FXDISC_REG_HOST_INFO) {
+ preg_hsi = (struct register_host_info *)
+ fdisc->u.fxiocb.req_addr;
+ phost_info = &preg_hsi->hsi;
+ memset(preg_hsi, 0, sizeof(struct register_host_info));
+ phost_info->os_type = OS_TYPE_LINUX;
+ strncpy(phost_info->sysname,
+ p_sysid->sysname, SYSNAME_LENGTH);
+ strncpy(phost_info->nodename,
+ p_sysid->nodename, NODENAME_LENGTH);
+ strncpy(phost_info->release,
+ p_sysid->release, RELEASE_LENGTH);
+ strncpy(phost_info->version,
+ p_sysid->version, VERSION_LENGTH);
+ strncpy(phost_info->machine,
+ p_sysid->machine, MACHINE_LENGTH);
+ strncpy(phost_info->domainname,
+ p_sysid->domainname, DOMNAME_LENGTH);
+ strncpy(phost_info->hostdriver,
+ QLA2XXX_VERSION, VERSION_LENGTH);
+ do_gettimeofday(&tv);
+ preg_hsi->utc = (uint64_t)tv.tv_sec;
+ ql_dbg(ql_dbg_init, vha, 0x0149,
+ "ISP%04X: Host registration with firmware\n",
+ ha->pdev->device);
+ ql_dbg(ql_dbg_init, vha, 0x014a,
+ "os_type = '%d', sysname = '%s', nodname = '%s'\n",
+ phost_info->os_type,
+ phost_info->sysname,
+ phost_info->nodename);
+ ql_dbg(ql_dbg_init, vha, 0x014b,
+ "release = '%s', version = '%s'\n",
+ phost_info->release,
+ phost_info->version);
+ ql_dbg(ql_dbg_init, vha, 0x014c,
+ "machine = '%s' "
+ "domainname = '%s', hostdriver = '%s'\n",
+ phost_info->machine,
+ phost_info->domainname,
+ phost_info->hostdriver);
+ ql_dump_buffer(ql_dbg_init + ql_dbg_disc, vha, 0x014d,
+ (uint8_t *)phost_info,
+ sizeof(struct host_system_info));
+ }
+ }
+
+ if (fdisc->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
+ fdisc->u.fxiocb.rsp_addr = dma_alloc_coherent(&ha->pdev->dev,
+ fdisc->u.fxiocb.rsp_len,
+ &fdisc->u.fxiocb.rsp_dma_handle, GFP_KERNEL);
+ if (!fdisc->u.fxiocb.rsp_addr)
+ goto done_unmap_req;
+ }
+
+ sp->type = SRB_FXIOCB_DCMD;
+ sp->name = "fxdisc";
+ qla2x00_init_timer(sp, FXDISC_TIMEOUT);
+ fdisc->timeout = qla2x00_fxdisc_iocb_timeout;
+ fdisc->u.fxiocb.req_func_type = fx_type;
+ sp->done = qla2x00_fxdisc_sp_done;
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_unmap_dma;
+
+ wait_for_completion(&fdisc->u.fxiocb.fxiocb_comp);
+
+ if (fx_type == FXDISC_GET_CONFIG_INFO) {
+ struct config_info_data *pinfo =
+ (struct config_info_data *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(&vha->hw->mr.product_name, pinfo->product_name,
+ sizeof(vha->hw->mr.product_name));
+ memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name,
+ sizeof(vha->hw->mr.symbolic_name));
+ memcpy(&vha->hw->mr.serial_num, pinfo->serial_num,
+ sizeof(vha->hw->mr.serial_num));
+ memcpy(&vha->hw->mr.hw_version, pinfo->hw_version,
+ sizeof(vha->hw->mr.hw_version));
+ memcpy(&vha->hw->mr.fw_version, pinfo->fw_version,
+ sizeof(vha->hw->mr.fw_version));
+ strim(vha->hw->mr.fw_version);
+ memcpy(&vha->hw->mr.uboot_version, pinfo->uboot_version,
+ sizeof(vha->hw->mr.uboot_version));
+ memcpy(&vha->hw->mr.fru_serial_num, pinfo->fru_serial_num,
+ sizeof(vha->hw->mr.fru_serial_num));
+ } else if (fx_type == FXDISC_GET_PORT_INFO) {
+ struct port_info_data *pinfo =
+ (struct port_info_data *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(vha->node_name, pinfo->node_name, WWN_SIZE);
+ memcpy(vha->port_name, pinfo->port_name, WWN_SIZE);
+ vha->d_id.b.domain = pinfo->port_id[0];
+ vha->d_id.b.area = pinfo->port_id[1];
+ vha->d_id.b.al_pa = pinfo->port_id[2];
+ qlafx00_update_host_attr(vha, pinfo);
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0141,
+ (uint8_t *)pinfo, 16);
+ } else if (fx_type == FXDISC_GET_TGT_NODE_INFO) {
+ struct qlafx00_tgt_node_info *pinfo =
+ (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
+ memcpy(fcport->node_name, pinfo->tgt_node_wwnn, WWN_SIZE);
+ memcpy(fcport->port_name, pinfo->tgt_node_wwpn, WWN_SIZE);
+ fcport->port_type = FCT_TARGET;
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0144,
+ (uint8_t *)pinfo, 16);
+ } else if (fx_type == FXDISC_GET_TGT_NODE_LIST) {
+ struct qlafx00_tgt_node_info *pinfo =
+ (struct qlafx00_tgt_node_info *) fdisc->u.fxiocb.rsp_addr;
+ ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0146,
+ (uint8_t *)pinfo, 16);
+ memcpy(vha->hw->gid_list, pinfo, QLAFX00_TGT_NODE_LIST_SIZE);
+ }
+ rval = fdisc->u.fxiocb.result;
+
+done_unmap_dma:
+ if (fdisc->u.fxiocb.rsp_addr)
+ dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.rsp_len,
+ fdisc->u.fxiocb.rsp_addr, fdisc->u.fxiocb.rsp_dma_handle);
+
+done_unmap_req:
+ if (fdisc->u.fxiocb.req_addr)
+ dma_free_coherent(&ha->pdev->dev, fdisc->u.fxiocb.req_len,
+ fdisc->u.fxiocb.req_addr, fdisc->u.fxiocb.req_dma_handle);
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+static void
+qlafx00_abort_iocb_timeout(void *data)
+{
+ srb_t *sp = (srb_t *)data;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ abt->u.abt.comp_status = CS_TIMEOUT;
+ complete(&abt->u.abt.comp);
+}
+
+static void
+qlafx00_abort_sp_done(void *data, void *ptr, int res)
+{
+ srb_t *sp = (srb_t *)ptr;
+ struct srb_iocb *abt = &sp->u.iocb_cmd;
+
+ complete(&abt->u.abt.comp);
+}
+
+static int
+qlafx00_async_abt_cmd(srb_t *cmd_sp)
+{
+ scsi_qla_host_t *vha = cmd_sp->fcport->vha;
+ fc_port_t *fcport = cmd_sp->fcport;
+ struct srb_iocb *abt_iocb;
+ srb_t *sp;
+ int rval = QLA_FUNCTION_FAILED;
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+ abt_iocb = &sp->u.iocb_cmd;
+ sp->type = SRB_ABT_CMD;
+ sp->name = "abort";
+ qla2x00_init_timer(sp, FXDISC_TIMEOUT);
+ abt_iocb->u.abt.cmd_hndl = cmd_sp->handle;
+ sp->done = qlafx00_abort_sp_done;
+ abt_iocb->timeout = qlafx00_abort_iocb_timeout;
+ init_completion(&abt_iocb->u.abt.comp);
+
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+
+ ql_dbg(ql_dbg_async, vha, 0x507c,
+ "Abort command issued - hdl=%x, target_id=%x\n",
+ cmd_sp->handle, fcport->tgt_id);
+
+ wait_for_completion(&abt_iocb->u.abt.comp);
+
+ rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ?
+ QLA_SUCCESS : QLA_FUNCTION_FAILED;
+
+done_free_sp:
+ sp->free(vha, sp);
+done:
+ return rval;
+}
+
+int
+qlafx00_abort_command(srb_t *sp)
+{
+ unsigned long flags = 0;
+
+ uint32_t handle;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct req_que *req = vha->req;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (handle = 1; handle < DEFAULT_OUTSTANDING_COMMANDS; handle++) {
+ if (req->outstanding_cmds[handle] == sp)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (handle == DEFAULT_OUTSTANDING_COMMANDS) {
+ /* Command not found. */
+ return QLA_FUNCTION_FAILED;
+ }
+ return qlafx00_async_abt_cmd(sp);
+}
+
+/*
+ * qlafx00_initialize_adapter
+ * Initialize board.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ *
+ * Returns:
+ * 0 = success
+ */
+int
+qlafx00_initialize_adapter(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Clear adapter flags. */
+ vha->flags.online = 0;
+ ha->flags.chip_reset_done = 0;
+ vha->flags.reset_active = 0;
+ ha->flags.pci_channel_io_perm_failure = 0;
+ ha->flags.eeh_busy = 0;
+ ha->thermal_support = 0;
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->device_flags = DFLG_NO_CABLE;
+ vha->dpc_flags = 0;
+ vha->flags.management_server_logged_in = 0;
+ vha->marker_needed = 0;
+ ha->isp_abort_cnt = 0;
+ ha->beacon_blink_led = 0;
+
+ set_bit(0, ha->req_qid_map);
+ set_bit(0, ha->rsp_qid_map);
+
+ ql_dbg(ql_dbg_init, vha, 0x0147,
+ "Configuring PCI space...\n");
+
+ rval = ha->isp_ops->pci_config(vha);
+ if (rval) {
+ ql_log(ql_log_warn, vha, 0x0148,
+ "Unable to configure PCI space.\n");
+ return rval;
+ }
+
+ rval = qlafx00_init_fw_ready(vha);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ qlafx00_save_queue_ptrs(vha);
+
+ rval = qlafx00_config_queues(vha);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ /*
+ * Allocate the array of outstanding commands
+ * now that we know the firmware resources.
+ */
+ rval = qla2x00_alloc_outstanding_cmds(ha, vha->req);
+ if (rval != QLA_SUCCESS)
+ return rval;
+
+ rval = qla2x00_init_rings(vha);
+ ha->flags.chip_reset_done = 1;
+
+ return rval;
+}
+
+uint32_t
+qlafx00_fw_state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ int rval = QLA_FUNCTION_FAILED;
+ uint32_t state[1];
+
+ if (qla2x00_reset_active(vha))
+ ql_log(ql_log_warn, vha, 0x70ce,
+ "ISP reset active.\n");
+ else if (!vha->hw->flags.eeh_busy) {
+ rval = qlafx00_get_firmware_state(vha, state);
+ }
+ if (rval != QLA_SUCCESS)
+ memset(state, -1, sizeof(state));
+
+ return state[0];
+}
+
+void
+qlafx00_get_host_speed(struct Scsi_Host *shost)
+{
+ struct qla_hw_data *ha = ((struct scsi_qla_host *)
+ (shost_priv(shost)))->hw;
+ u32 speed = FC_PORTSPEED_UNKNOWN;
+
+ switch (ha->link_data_rate) {
+ case QLAFX00_PORT_SPEED_2G:
+ speed = FC_PORTSPEED_2GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_4G:
+ speed = FC_PORTSPEED_4GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_8G:
+ speed = FC_PORTSPEED_8GBIT;
+ break;
+ case QLAFX00_PORT_SPEED_10G:
+ speed = FC_PORTSPEED_10GBIT;
+ break;
+ }
+ fc_host_speed(shost) = speed;
+}
+
+/** QLAFX00 specific ISR implementation functions */
+
+static inline void
+qlafx00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
+ uint32_t sense_len, struct rsp_que *rsp, int res)
+{
+ struct scsi_qla_host *vha = sp->fcport->vha;
+ struct scsi_cmnd *cp = GET_CMD_SP(sp);
+ uint32_t track_sense_len;
+
+ SET_FW_SENSE_LEN(sp, sense_len);
+
+ if (sense_len >= SCSI_SENSE_BUFFERSIZE)
+ sense_len = SCSI_SENSE_BUFFERSIZE;
+
+ SET_CMD_SENSE_LEN(sp, sense_len);
+ SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
+ track_sense_len = sense_len;
+
+ if (sense_len > par_sense_len)
+ sense_len = par_sense_len;
+
+ memcpy(cp->sense_buffer, sense_data, sense_len);
+
+ SET_FW_SENSE_LEN(sp, GET_FW_SENSE_LEN(sp) - sense_len);
+
+ SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
+ track_sense_len -= sense_len;
+ SET_CMD_SENSE_LEN(sp, track_sense_len);
+
+ ql_dbg(ql_dbg_io, vha, 0x304d,
+ "sense_len=0x%x par_sense_len=0x%x track_sense_len=0x%x.\n",
+ sense_len, par_sense_len, track_sense_len);
+ if (GET_FW_SENSE_LEN(sp) > 0) {
+ rsp->status_srb = sp;
+ cp->result = res;
+ }
+
+ if (sense_len) {
+ ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3039,
+ "Check condition Sense data, nexus%ld:%d:%d cmd=%p.\n",
+ sp->fcport->vha->host_no, cp->device->id, cp->device->lun,
+ cp);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3049,
+ cp->sense_buffer, sense_len);
+ }
+}
+
+static void
+qlafx00_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct tsk_mgmt_entry_fx00 *pkt, srb_t *sp,
+ uint16_t sstatus, uint16_t cpstatus)
+{
+ struct srb_iocb *tmf;
+
+ tmf = &sp->u.iocb_cmd;
+ if (cpstatus != CS_COMPLETE ||
+ (sstatus & SS_RESPONSE_INFO_LEN_VALID))
+ cpstatus = CS_INCOMPLETE;
+ tmf->u.tmf.comp_status = cpstatus;
+ sp->done(vha, sp, 0);
+}
+
+static void
+qlafx00_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct abort_iocb_entry_fx00 *pkt)
+{
+ const char func[] = "ABT_IOCB";
+ srb_t *sp;
+ struct srb_iocb *abt;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ abt = &sp->u.iocb_cmd;
+ abt->u.abt.comp_status = le32_to_cpu(pkt->tgt_id_sts);
+ sp->done(vha, sp, 0);
+}
+
+static void
+qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req,
+ struct ioctl_iocb_entry_fx00 *pkt)
+{
+ const char func[] = "IOSB_IOCB";
+ srb_t *sp;
+ struct fc_bsg_job *bsg_job;
+ struct srb_iocb *iocb_job;
+ int res;
+ struct qla_mt_iocb_rsp_fx00 fstatus;
+ uint8_t *fw_sts_ptr;
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (!sp)
+ return;
+
+ if (sp->type == SRB_FXIOCB_DCMD) {
+ iocb_job = &sp->u.iocb_cmd;
+ iocb_job->u.fxiocb.seq_number = le32_to_cpu(pkt->seq_no);
+ iocb_job->u.fxiocb.fw_flags = le32_to_cpu(pkt->fw_iotcl_flags);
+ iocb_job->u.fxiocb.result = le32_to_cpu(pkt->status);
+ if (iocb_job->u.fxiocb.flags & SRB_FXDISC_RSP_DWRD_VALID)
+ iocb_job->u.fxiocb.req_data =
+ le32_to_cpu(pkt->dataword_r);
+ } else {
+ bsg_job = sp->u.bsg_job;
+
+ memset(&fstatus, 0, sizeof(struct qla_mt_iocb_rsp_fx00));
+
+ fstatus.reserved_1 = pkt->reserved_0;
+ fstatus.func_type = pkt->comp_func_num;
+ fstatus.ioctl_flags = pkt->fw_iotcl_flags;
+ fstatus.ioctl_data = pkt->dataword_r;
+ fstatus.adapid = pkt->adapid;
+ fstatus.adapid_hi = pkt->adapid_hi;
+ fstatus.reserved_2 = pkt->reserved_1;
+ fstatus.res_count = pkt->residuallen;
+ fstatus.status = pkt->status;
+ fstatus.seq_number = pkt->seq_no;
+ memcpy(fstatus.reserved_3,
+ pkt->reserved_2, 20 * sizeof(uint8_t));
+
+ fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) +
+ sizeof(struct fc_bsg_reply);
+
+ memcpy(fw_sts_ptr, (uint8_t *)&fstatus,
+ sizeof(struct qla_mt_iocb_rsp_fx00));
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
+ sizeof(struct qla_mt_iocb_rsp_fx00) + sizeof(uint8_t);
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x5080,
+ (uint8_t *)pkt, sizeof(struct ioctl_iocb_entry_fx00));
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x5074,
+ (uint8_t *)fw_sts_ptr, sizeof(struct qla_mt_iocb_rsp_fx00));
+
+ res = bsg_job->reply->result = DID_OK << 16;
+ bsg_job->reply->reply_payload_rcv_len =
+ bsg_job->reply_payload.payload_len;
+ }
+ sp->done(vha, sp, res);
+}
+
+/**
+ * qlafx00_status_entry() - Process a Status IOCB entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
+{
+ srb_t *sp;
+ fc_port_t *fcport;
+ struct scsi_cmnd *cp;
+ struct sts_entry_fx00 *sts;
+ uint16_t comp_status;
+ uint16_t scsi_status;
+ uint16_t ox_id;
+ uint8_t lscsi_status;
+ int32_t resid;
+ uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
+ fw_resid_len;
+ uint8_t *rsp_info = NULL, *sense_data = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t hindex, handle;
+ uint16_t que;
+ struct req_que *req;
+ int logit = 1;
+ int res = 0;
+
+ sts = (struct sts_entry_fx00 *) pkt;
+
+ comp_status = le16_to_cpu(sts->comp_status);
+ scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
+ hindex = sts->handle;
+ handle = LSW(hindex);
+
+ que = MSW(hindex);
+ req = ha->req_q_map[que];
+
+ /* Validate handle. */
+ if (handle < req->num_outstanding_cmds)
+ sp = req->outstanding_cmds[handle];
+ else
+ sp = NULL;
+
+ if (sp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3034,
+ "Invalid status handle (0x%x).\n", handle);
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+
+ if (sp->type == SRB_TM_CMD) {
+ req->outstanding_cmds[handle] = NULL;
+ qlafx00_tm_iocb_entry(vha, req, pkt, sp,
+ scsi_status, comp_status);
+ return;
+ }
+
+ /* Fast path completion. */
+ if (comp_status == CS_COMPLETE && scsi_status == 0) {
+ qla2x00_do_host_ramp_up(vha);
+ qla2x00_process_completed_request(vha, req, handle);
+ return;
+ }
+
+ req->outstanding_cmds[handle] = NULL;
+ cp = GET_CMD_SP(sp);
+ if (cp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3048,
+ "Command already returned (0x%x/%p).\n",
+ handle, sp);
+
+ return;
+ }
+
+ lscsi_status = scsi_status & STATUS_MASK;
+
+ fcport = sp->fcport;
+
+ ox_id = 0;
+ sense_len = par_sense_len = rsp_info_len = resid_len =
+ fw_resid_len = 0;
+ if (scsi_status & SS_SENSE_LEN_VALID)
+ sense_len = le32_to_cpu(sts->sense_len);
+ if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
+ resid_len = le32_to_cpu(sts->residual_len);
+ if (comp_status == CS_DATA_UNDERRUN)
+ fw_resid_len = le32_to_cpu(sts->residual_len);
+ rsp_info = sense_data = sts->data;
+ par_sense_len = sizeof(sts->data);
+
+ /* Check for overrun. */
+ if (comp_status == CS_COMPLETE &&
+ scsi_status & SS_RESIDUAL_OVER)
+ comp_status = CS_DATA_OVERRUN;
+
+ /*
+ * Based on Host and scsi status generate status code for Linux
+ */
+ switch (comp_status) {
+ case CS_COMPLETE:
+ case CS_QUEUE_FULL:
+ if (scsi_status == 0) {
+ res = DID_OK << 16;
+ break;
+ }
+ if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
+ resid = resid_len;
+ scsi_set_resid(cp, resid);
+
+ if (!lscsi_status &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3050,
+ "Mid-layer underflow "
+ "detected (0x%x of 0x%x bytes).\n",
+ resid, scsi_bufflen(cp));
+
+ res = DID_ERROR << 16;
+ break;
+ }
+ }
+ res = DID_OK << 16 | lscsi_status;
+
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3051,
+ "QUEUE FULL detected.\n");
+ break;
+ }
+ logit = 0;
+ if (lscsi_status != SS_CHECK_CONDITION)
+ break;
+
+ memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ if (!(scsi_status & SS_SENSE_LEN_VALID))
+ break;
+
+ qlafx00_handle_sense(sp, sense_data, par_sense_len, sense_len,
+ rsp, res);
+ break;
+
+ case CS_DATA_UNDERRUN:
+ /* Use F/W calculated residual length. */
+ if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
+ resid = fw_resid_len;
+ else
+ resid = resid_len;
+ scsi_set_resid(cp, resid);
+ if (scsi_status & SS_RESIDUAL_UNDER) {
+ if ((IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
+ && fw_resid_len != resid_len) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3052,
+ "Dropped frame(s) detected "
+ "(0x%x of 0x%x bytes).\n",
+ resid, scsi_bufflen(cp));
+
+ res = DID_ERROR << 16 | lscsi_status;
+ goto check_scsi_status;
+ }
+
+ if (!lscsi_status &&
+ ((unsigned)(scsi_bufflen(cp) - resid) <
+ cp->underflow)) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3053,
+ "Mid-layer underflow "
+ "detected (0x%x of 0x%x bytes, "
+ "cp->underflow: 0x%x).\n",
+ resid, scsi_bufflen(cp), cp->underflow);
+
+ res = DID_ERROR << 16;
+ break;
+ }
+ } else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
+ lscsi_status != SAM_STAT_BUSY) {
+ /*
+ * scsi status of task set and busy are considered
+ * to be task not completed.
+ */
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3054,
+ "Dropped frame(s) detected (0x%x "
+ "of 0x%x bytes).\n", resid,
+ scsi_bufflen(cp));
+
+ res = DID_ERROR << 16 | lscsi_status;
+ goto check_scsi_status;
+ } else {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3055,
+ "scsi_status: 0x%x, lscsi_status: 0x%x\n",
+ scsi_status, lscsi_status);
+ }
+
+ res = DID_OK << 16 | lscsi_status;
+ logit = 0;
+
+check_scsi_status:
+ /*
+ * Check to see if SCSI Status is non zero. If so report SCSI
+ * Status.
+ */
+ if (lscsi_status != 0) {
+ if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3056,
+ "QUEUE FULL detected.\n");
+ logit = 1;
+ break;
+ }
+ if (lscsi_status != SS_CHECK_CONDITION)
+ break;
+
+ memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ if (!(scsi_status & SS_SENSE_LEN_VALID))
+ break;
+
+ qlafx00_handle_sense(sp, sense_data, par_sense_len,
+ sense_len, rsp, res);
+ }
+ break;
+
+ case CS_PORT_LOGGED_OUT:
+ case CS_PORT_CONFIG_CHG:
+ case CS_PORT_BUSY:
+ case CS_INCOMPLETE:
+ case CS_PORT_UNAVAILABLE:
+ case CS_TIMEOUT:
+ case CS_RESET:
+
+ /*
+ * We are going to have the fc class block the rport
+ * while we try to recover so instruct the mid layer
+ * to requeue until the class decides how to handle this.
+ */
+ res = DID_TRANSPORT_DISRUPTED << 16;
+
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3057,
+ "Port down status: port-state=0x%x.\n",
+ atomic_read(&fcport->state));
+
+ if (atomic_read(&fcport->state) == FCS_ONLINE)
+ qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
+ break;
+
+ case CS_ABORTED:
+ res = DID_RESET << 16;
+ break;
+
+ default:
+ res = DID_ERROR << 16;
+ break;
+ }
+
+ if (logit)
+ ql_dbg(ql_dbg_io, fcport->vha, 0x3058,
+ "FCP command status: 0x%x-0x%x (0x%x) "
+ "nexus=%ld:%d:%d tgt_id: 0x%x lscsi_status: 0x%x"
+ "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
+ "rsp_info=0x%x resid=0x%x fw_resid=0x%x "
+ "sense_len=0x%x, par_sense_len=0x%x, rsp_info_len=0x%x\n",
+ comp_status, scsi_status, res, vha->host_no,
+ cp->device->id, cp->device->lun, fcport->tgt_id,
+ lscsi_status, cp->cmnd[0], cp->cmnd[1], cp->cmnd[2],
+ cp->cmnd[3], cp->cmnd[4], cp->cmnd[5], cp->cmnd[6],
+ cp->cmnd[7], cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp),
+ rsp_info_len, resid_len, fw_resid_len, sense_len,
+ par_sense_len, rsp_info_len);
+
+ if (!res)
+ qla2x00_do_host_ramp_up(vha);
+
+ if (rsp->status_srb == NULL)
+ sp->done(ha, sp, res);
+}
+
+/**
+ * qlafx00_status_cont_entry() - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
+{
+ uint8_t sense_sz = 0;
+ struct qla_hw_data *ha = rsp->hw;
+ struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
+ srb_t *sp = rsp->status_srb;
+ struct scsi_cmnd *cp;
+ uint32_t sense_len;
+ uint8_t *sense_ptr;
+
+ if (!sp) {
+ ql_dbg(ql_dbg_io, vha, 0x3037,
+ "no SP, sp = %p\n", sp);
+ return;
+ }
+
+ if (!GET_FW_SENSE_LEN(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x304b,
+ "no fw sense data, sp = %p\n", sp);
+ return;
+ }
+ cp = GET_CMD_SP(sp);
+ if (cp == NULL) {
+ ql_log(ql_log_warn, vha, 0x303b,
+ "cmd is NULL: already returned to OS (sp=%p).\n", sp);
+
+ rsp->status_srb = NULL;
+ return;
+ }
+
+ if (!GET_CMD_SENSE_LEN(sp)) {
+ ql_dbg(ql_dbg_io, vha, 0x304c,
+ "no sense data, sp = %p\n", sp);
+ } else {
+ sense_len = GET_CMD_SENSE_LEN(sp);
+ sense_ptr = GET_CMD_SENSE_PTR(sp);
+ ql_dbg(ql_dbg_io, vha, 0x304f,
+ "sp=%p sense_len=0x%x sense_ptr=%p.\n",
+ sp, sense_len, sense_ptr);
+
+ if (sense_len > sizeof(pkt->data))
+ sense_sz = sizeof(pkt->data);
+ else
+ sense_sz = sense_len;
+
+ /* Move sense data. */
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304e,
+ (uint8_t *)pkt, sizeof(sts_cont_entry_t));
+ memcpy(sense_ptr, pkt->data, sense_sz);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x304a,
+ sense_ptr, sense_sz);
+
+ sense_len -= sense_sz;
+ sense_ptr += sense_sz;
+
+ SET_CMD_SENSE_PTR(sp, sense_ptr);
+ SET_CMD_SENSE_LEN(sp, sense_len);
+ }
+ sense_len = GET_FW_SENSE_LEN(sp);
+ sense_len = (sense_len > sizeof(pkt->data)) ?
+ (sense_len - sizeof(pkt->data)) : 0;
+ SET_FW_SENSE_LEN(sp, sense_len);
+
+ /* Place command on done queue. */
+ if (sense_len == 0) {
+ rsp->status_srb = NULL;
+ sp->done(ha, sp, cp->result);
+ }
+}
+
+/**
+ * qlafx00_multistatus_entry() - Process Multi response queue entries.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_multistatus_entry(struct scsi_qla_host *vha,
+ struct rsp_que *rsp, void *pkt)
+{
+ srb_t *sp;
+ struct multi_sts_entry_fx00 *stsmfx;
+ struct qla_hw_data *ha = vha->hw;
+ uint32_t handle, hindex, handle_count, i;
+ uint16_t que;
+ struct req_que *req;
+ uint32_t *handle_ptr;
+
+ stsmfx = (struct multi_sts_entry_fx00 *) pkt;
+
+ handle_count = stsmfx->handle_count;
+
+ if (handle_count > MAX_HANDLE_COUNT) {
+ ql_dbg(ql_dbg_io, vha, 0x3035,
+ "Invalid handle count (0x%x).\n", handle_count);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+
+ handle_ptr = (uint32_t *) &stsmfx->handles[0];
+
+ for (i = 0; i < handle_count; i++) {
+ hindex = le32_to_cpu(*handle_ptr);
+ handle = LSW(hindex);
+ que = MSW(hindex);
+ req = ha->req_q_map[que];
+
+ /* Validate handle. */
+ if (handle < req->num_outstanding_cmds)
+ sp = req->outstanding_cmds[handle];
+ else
+ sp = NULL;
+
+ if (sp == NULL) {
+ ql_dbg(ql_dbg_io, vha, 0x3044,
+ "Invalid status handle (0x%x).\n", handle);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ return;
+ }
+ qla2x00_process_completed_request(vha, req, handle);
+ handle_ptr++;
+ }
+}
+
+/**
+ * qlafx00_error_entry() - Process an error entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp,
+ struct sts_entry_fx00 *pkt, uint8_t estatus, uint8_t etype)
+{
+ srb_t *sp;
+ struct qla_hw_data *ha = vha->hw;
+ const char func[] = "ERROR-IOCB";
+ uint16_t que = MSW(pkt->handle);
+ struct req_que *req = NULL;
+ int res = DID_ERROR << 16;
+
+ ql_dbg(ql_dbg_async, vha, 0x507f,
+ "type of error status in response: 0x%x\n", estatus);
+
+ req = ha->req_q_map[que];
+
+ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
+ if (sp) {
+ sp->done(ha, sp, res);
+ return;
+ }
+
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+}
+
+/**
+ * qlafx00_process_response_queue() - Process response queue entries.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_process_response_queue(struct scsi_qla_host *vha,
+ struct rsp_que *rsp)
+{
+ struct sts_entry_fx00 *pkt;
+ response_t *lptr;
+
+ if (!vha->flags.online)
+ return;
+
+ while (RD_REG_DWORD(&(rsp->ring_ptr->signature)) !=
+ RESPONSE_PROCESSED) {
+ lptr = rsp->ring_ptr;
+ memcpy_fromio(rsp->rsp_pkt, lptr, sizeof(rsp->rsp_pkt));
+ pkt = (struct sts_entry_fx00 *)rsp->rsp_pkt;
+
+ rsp->ring_index++;
+ if (rsp->ring_index == rsp->length) {
+ rsp->ring_index = 0;
+ rsp->ring_ptr = rsp->ring;
+ } else {
+ rsp->ring_ptr++;
+ }
+
+ if (pkt->entry_status != 0 &&
+ pkt->entry_type != IOCTL_IOSB_TYPE_FX00) {
+ qlafx00_error_entry(vha, rsp,
+ (struct sts_entry_fx00 *)pkt, pkt->entry_status,
+ pkt->entry_type);
+ goto next_iter;
+ continue;
+ }
+
+ switch (pkt->entry_type) {
+ case STATUS_TYPE_FX00:
+ qlafx00_status_entry(vha, rsp, pkt);
+ break;
+
+ case STATUS_CONT_TYPE_FX00:
+ qlafx00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
+ break;
+
+ case MULTI_STATUS_TYPE_FX00:
+ qlafx00_multistatus_entry(vha, rsp, pkt);
+ break;
+
+ case ABORT_IOCB_TYPE_FX00:
+ qlafx00_abort_iocb_entry(vha, rsp->req,
+ (struct abort_iocb_entry_fx00 *)pkt);
+ break;
+
+ case IOCTL_IOSB_TYPE_FX00:
+ qlafx00_ioctl_iosb_entry(vha, rsp->req,
+ (struct ioctl_iocb_entry_fx00 *)pkt);
+ break;
+ default:
+ /* Type Not Supported. */
+ ql_dbg(ql_dbg_async, vha, 0x5081,
+ "Received unknown response pkt type %x "
+ "entry status=%x.\n",
+ pkt->entry_type, pkt->entry_status);
+ break;
+ }
+next_iter:
+ WRT_REG_DWORD(&lptr->signature, RESPONSE_PROCESSED);
+ wmb();
+ }
+
+ /* Adjust ring index */
+ WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
+}
+
+/**
+ * qlafx00_async_event() - Process aynchronous events.
+ * @ha: SCSI driver HA context
+ */
+static void
+qlafx00_async_event(scsi_qla_host_t *vha)
+{
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg;
+ int data_size = 1;
+
+ reg = &ha->iobase->ispfx00;
+ /* Setup to process RIO completion. */
+ switch (ha->aenmb[0]) {
+ case QLAFX00_MBA_SYSTEM_ERR: /* System Error */
+ ql_log(ql_log_warn, vha, 0x5079,
+ "ISP System Error - mbx1=%x\n", ha->aenmb[0]);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ break;
+
+ case QLAFX00_MBA_SHUTDOWN_RQSTD: /* Shutdown requested */
+ ql_dbg(ql_dbg_async, vha, 0x5076,
+ "Asynchronous FW shutdown requested.\n");
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ break;
+
+ case QLAFX00_MBA_PORT_UPDATE: /* Port database update */
+ ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ql_dbg(ql_dbg_async, vha, 0x5077,
+ "Asynchronous port Update received "
+ "aenmb[0]: %x, aenmb[1]: %x, aenmb[2]: %x, aenmb[3]: %x\n",
+ ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3]);
+ data_size = 4;
+ break;
+ default:
+ ha->aenmb[1] = RD_REG_WORD(&reg->aenmailbox1);
+ ha->aenmb[2] = RD_REG_WORD(&reg->aenmailbox2);
+ ha->aenmb[3] = RD_REG_WORD(&reg->aenmailbox3);
+ ha->aenmb[4] = RD_REG_WORD(&reg->aenmailbox4);
+ ha->aenmb[5] = RD_REG_WORD(&reg->aenmailbox5);
+ ha->aenmb[6] = RD_REG_WORD(&reg->aenmailbox6);
+ ha->aenmb[7] = RD_REG_WORD(&reg->aenmailbox7);
+ ql_dbg(ql_dbg_async, vha, 0x5078,
+ "AEN:%04x %04x %04x %04x :%04x %04x %04x %04x\n",
+ ha->aenmb[0], ha->aenmb[1], ha->aenmb[2], ha->aenmb[3],
+ ha->aenmb[4], ha->aenmb[5], ha->aenmb[6], ha->aenmb[7]);
+ break;
+ }
+ qlafx00_post_aenfx_work(vha, ha->aenmb[0],
+ (uint32_t *)ha->aenmb, data_size);
+}
+
+/**
+ *
+ * qlafx00x_mbx_completion() - Process mailbox command completions.
+ * @ha: SCSI driver HA context
+ * @mb16: Mailbox16 register
+ */
+static void
+qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0)
+{
+ uint16_t cnt;
+ uint16_t __iomem *wptr;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_fx00 __iomem *reg = &ha->iobase->ispfx00;
+
+ if (!ha->mcp32)
+ ql_dbg(ql_dbg_async, vha, 0x507e, "MBX pointer ERROR.\n");
+
+ /* Load return mailbox registers. */
+ ha->flags.mbox_int = 1;
+ ha->mailbox_out32[0] = mb0;
+ wptr = (uint16_t __iomem *)&reg->mailbox17;
+
+ for (cnt = 1; cnt < ha->mbx_count; cnt++) {
+ ha->mailbox_out32[cnt] = RD_REG_WORD(wptr);
+ wptr++;
+ }
+}
+
+/**
+ * qlafx00_intr_handler() - Process interrupts for the ISPFX00.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qlafx00_intr_handler(int irq, void *dev_id)
+{
+ scsi_qla_host_t *vha;
+ struct qla_hw_data *ha;
+ struct device_reg_fx00 __iomem *reg;
+ int status;
+ unsigned long iter;
+ uint32_t stat;
+ uint32_t mb[8];
+ struct rsp_que *rsp;
+ unsigned long flags;
+ uint32_t clr_intr = 0;
+
+ rsp = (struct rsp_que *) dev_id;
+ if (!rsp) {
+ ql_log(ql_log_info, NULL, 0x507d,
+ "%s: NULL response queue pointer.\n", __func__);
+ return IRQ_NONE;
+ }
+
+ ha = rsp->hw;
+ reg = &ha->iobase->ispfx00;
+ status = 0;
+
+ if (unlikely(pci_channel_offline(ha->pdev)))
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ vha = pci_get_drvdata(ha->pdev);
+ for (iter = 50; iter--; clr_intr = 0) {
+ stat = QLAFX00_RD_INTR_REG(ha);
+ if ((stat & QLAFX00_HST_INT_STS_BITS) == 0)
+ break;
+
+ switch (stat & QLAFX00_HST_INT_STS_BITS) {
+ case QLAFX00_INTR_MB_CMPLT:
+ case QLAFX00_INTR_MB_RSP_CMPLT:
+ case QLAFX00_INTR_MB_ASYNC_CMPLT:
+ case QLAFX00_INTR_ALL_CMPLT:
+ mb[0] = RD_REG_WORD(&reg->mailbox16);
+ qlafx00_mbx_completion(vha, mb[0]);
+ status |= MBX_INTERRUPT;
+ clr_intr |= QLAFX00_INTR_MB_CMPLT;
+ break;
+ case QLAFX00_INTR_ASYNC_CMPLT:
+ case QLAFX00_INTR_RSP_ASYNC_CMPLT:
+ ha->aenmb[0] = RD_REG_WORD(&reg->aenmailbox0);
+ qlafx00_async_event(vha);
+ clr_intr |= QLAFX00_INTR_ASYNC_CMPLT;
+ break;
+ case QLAFX00_INTR_RSP_CMPLT:
+ qlafx00_process_response_queue(vha, rsp);
+ clr_intr |= QLAFX00_INTR_RSP_CMPLT;
+ break;
+ default:
+ ql_dbg(ql_dbg_async, vha, 0x507a,
+ "Unrecognized interrupt type (%d).\n", stat);
+ break;
+ }
+ QLAFX00_CLR_INTR_REG(ha, clr_intr);
+ QLAFX00_RD_INTR_REG(ha);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+ (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+ set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ complete(&ha->mbx_intr_comp);
+ }
+ return IRQ_HANDLED;
+}
+
+/** QLAFX00 specific IOCB implementation functions */
+
+static inline cont_a64_entry_t *
+qlafx00_prep_cont_type1_iocb(struct req_que *req,
+ cont_a64_entry_t *lcont_pkt)
+{
+ cont_a64_entry_t *cont_pkt;
+
+ /* Adjust ring index. */
+ req->ring_index++;
+ if (req->ring_index == req->length) {
+ req->ring_index = 0;
+ req->ring_ptr = req->ring;
+ } else {
+ req->ring_ptr++;
+ }
+
+ cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
+
+ /* Load packet defaults. */
+ *((uint32_t *)(&lcont_pkt->entry_type)) =
+ __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00);
+
+ return cont_pkt;
+}
+
+static inline void
+qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt,
+ uint16_t tot_dsds, struct cmd_type_7_fx00 *lcmd_pkt)
+{
+ uint16_t avail_dsds;
+ uint32_t *cur_dsd;
+ scsi_qla_host_t *vha;
+ struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i, cont;
+ struct req_que *req;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt;
+
+ vha = sp->fcport->vha;
+ req = vha->req;
+
+ cmd = GET_CMD_SP(sp);
+ cont = 0;
+ cont_pkt = NULL;
+
+ /* Update entry type to indicate Command Type 3 IOCB */
+ *((uint32_t *)(&lcmd_pkt->entry_type)) =
+ __constant_cpu_to_le32(FX00_COMMAND_TYPE_7);
+
+ /* No data transfer */
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
+ lcmd_pkt->byte_count = __constant_cpu_to_le32(0);
+ return;
+ }
+
+ /* Set transfer direction */
+ if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+ lcmd_pkt->cntrl_flags =
+ __constant_cpu_to_le16(TMF_WRITE_DATA);
+ vha->qla_stats.output_bytes += scsi_bufflen(cmd);
+ } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ lcmd_pkt->cntrl_flags =
+ __constant_cpu_to_le16(TMF_READ_DATA);
+ vha->qla_stats.input_bytes += scsi_bufflen(cmd);
+ }
+
+ /* One DSD is available in the Command Type 3 IOCB */
+ avail_dsds = 1;
+ cur_dsd = (uint32_t *)&lcmd_pkt->dseg_0_address;
+
+ /* Load data segments */
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0, REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(req, &lcont_pkt);
+ cur_dsd = (uint32_t *)lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt, &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+}
+
+/**
+ * qlafx00_start_scsi() - Send a SCSI command to the ISP
+ * @sp: command to send to the ISP
+ *
+ * Returns non-zero if a failure occurred, else zero.
+ */
+int
+qlafx00_start_scsi(srb_t *sp)
+{
+ int ret, nseg;
+ unsigned long flags;
+ uint32_t index;
+ uint32_t handle;
+ uint16_t cnt;
+ uint16_t req_cnt;
+ uint16_t tot_dsds;
+ struct req_que *req = NULL;
+ struct rsp_que *rsp = NULL;
+ struct scsi_cmnd *cmd = GET_CMD_SP(sp);
+ struct scsi_qla_host *vha = sp->fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct cmd_type_7_fx00 *cmd_pkt;
+ struct cmd_type_7_fx00 lcmd_pkt;
+ struct scsi_lun llun;
+ char tag[2];
+
+ /* Setup device pointers. */
+ ret = 0;
+
+ rsp = ha->rsp_q_map[0];
+ req = vha->req;
+
+ /* So we know we haven't pci_map'ed anything yet */
+ tot_dsds = 0;
+
+ /* Forcing marker needed for now */
+ vha->marker_needed = 0;
+
+ /* Send marker if required */
+ if (vha->marker_needed != 0) {
+ if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) !=
+ QLA_SUCCESS)
+ return QLA_FUNCTION_FAILED;
+ vha->marker_needed = 0;
+ }
+
+ /* Acquire ring specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Check for room in outstanding command list. */
+ handle = req->current_outstanding_cmd;
+ for (index = 1; index < req->num_outstanding_cmds; index++) {
+ handle++;
+ if (handle == req->num_outstanding_cmds)
+ handle = 1;
+ if (!req->outstanding_cmds[handle])
+ break;
+ }
+ if (index == req->num_outstanding_cmds)
+ goto queuing_error;
+
+ /* Map the sg table so we have an accurate count of sg entries needed */
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
+ goto queuing_error;
+ } else
+ nseg = 0;
+
+ tot_dsds = nseg;
+ req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
+ if (req->cnt < (req_cnt + 2)) {
+ cnt = RD_REG_DWORD_RELAXED(req->req_q_out);
+
+ if (req->ring_index < cnt)
+ req->cnt = cnt - req->ring_index;
+ else
+ req->cnt = req->length -
+ (req->ring_index - cnt);
+ if (req->cnt < (req_cnt + 2))
+ goto queuing_error;
+ }
+
+ /* Build command packet. */
+ req->current_outstanding_cmd = handle;
+ req->outstanding_cmds[handle] = sp;
+ sp->handle = handle;
+ cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+ req->cnt -= req_cnt;
+
+ cmd_pkt = (struct cmd_type_7_fx00 *)req->ring_ptr;
+
+ memset(&lcmd_pkt, 0, REQUEST_ENTRY_SIZE);
+
+ lcmd_pkt.handle = MAKE_HANDLE(req->id, sp->handle);
+ lcmd_pkt.handle_hi = 0;
+ lcmd_pkt.dseg_count = cpu_to_le16(tot_dsds);
+ lcmd_pkt.tgt_idx = cpu_to_le16(sp->fcport->tgt_id);
+
+ int_to_scsilun(cmd->device->lun, &llun);
+ host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun,
+ sizeof(lcmd_pkt.lun));
+
+ /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
+ if (scsi_populate_tag_msg(cmd, tag)) {
+ switch (tag[0]) {
+ case HEAD_OF_QUEUE_TAG:
+ lcmd_pkt.task = TSK_HEAD_OF_QUEUE;
+ break;
+ case ORDERED_QUEUE_TAG:
+ lcmd_pkt.task = TSK_ORDERED;
+ break;
+ }
+ }
+
+ /* Load SCSI command packet. */
+ host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb));
+ lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
+
+ /* Build IOCB segments */
+ qlafx00_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, &lcmd_pkt);
+
+ /* Set total data segment count. */
+ lcmd_pkt.entry_count = (uint8_t)req_cnt;
+
+ /* Specify response queue number where completion should happen */
+ lcmd_pkt.entry_status = (uint8_t) rsp->id;
+
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302e,
+ (uint8_t *)cmd->cmnd, cmd->cmd_len);
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x3032,
+ (uint8_t *)&lcmd_pkt, REQUEST_ENTRY_SIZE);
+
+ memcpy_toio((void __iomem *)cmd_pkt, &lcmd_pkt, REQUEST_ENTRY_SIZE);
+ wmb();
+
+ /* Adjust ring index. */
+ req->ring_index++;
+ if (req->ring_index == req->length) {
+ req->ring_index = 0;
+ req->ring_ptr = req->ring;
+ } else
+ req->ring_ptr++;
+
+ sp->flags |= SRB_DMA_VALID;
+
+ /* Set chip new ring index. */
+ WRT_REG_DWORD(req->req_q_in, req->ring_index);
+ QLAFX00_SET_HST_INTR(ha, ha->rqstq_intr_code);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return QLA_SUCCESS;
+
+queuing_error:
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_FUNCTION_FAILED;
+}
+
+void
+qlafx00_tm_iocb(srb_t *sp, struct tsk_mgmt_entry_fx00 *ptm_iocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+ struct tsk_mgmt_entry_fx00 tm_iocb;
+ struct scsi_lun llun;
+
+ memset(&tm_iocb, 0, sizeof(struct tsk_mgmt_entry_fx00));
+ tm_iocb.entry_type = TSK_MGMT_IOCB_TYPE_FX00;
+ tm_iocb.entry_count = 1;
+ tm_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ tm_iocb.handle_hi = 0;
+ tm_iocb.timeout = cpu_to_le16(qla2x00_get_async_timeout(vha) + 2);
+ tm_iocb.tgt_id = cpu_to_le16(sp->fcport->tgt_id);
+ tm_iocb.control_flags = cpu_to_le32(fxio->u.tmf.flags);
+ if (tm_iocb.control_flags == TCF_LUN_RESET) {
+ int_to_scsilun(fxio->u.tmf.lun, &llun);
+ host_to_adap((uint8_t *)&llun, (uint8_t *)&tm_iocb.lun,
+ sizeof(struct scsi_lun));
+ }
+
+ memcpy((void __iomem *)ptm_iocb, &tm_iocb,
+ sizeof(struct tsk_mgmt_entry_fx00));
+ wmb();
+}
+
+void
+qlafx00_abort_iocb(srb_t *sp, struct abort_iocb_entry_fx00 *pabt_iocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ scsi_qla_host_t *vha = sp->fcport->vha;
+ struct req_que *req = vha->req;
+ struct abort_iocb_entry_fx00 abt_iocb;
+
+ memset(&abt_iocb, 0, sizeof(struct abort_iocb_entry_fx00));
+ abt_iocb.entry_type = ABORT_IOCB_TYPE_FX00;
+ abt_iocb.entry_count = 1;
+ abt_iocb.handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
+ abt_iocb.abort_handle =
+ cpu_to_le32(MAKE_HANDLE(req->id, fxio->u.abt.cmd_hndl));
+ abt_iocb.tgt_id_sts = cpu_to_le16(sp->fcport->tgt_id);
+ abt_iocb.req_que_no = cpu_to_le16(req->id);
+
+ memcpy((void __iomem *)pabt_iocb, &abt_iocb,
+ sizeof(struct abort_iocb_entry_fx00));
+ wmb();
+}
+
+void
+qlafx00_fxdisc_iocb(srb_t *sp, struct fxdisc_entry_fx00 *pfxiocb)
+{
+ struct srb_iocb *fxio = &sp->u.iocb_cmd;
+ struct qla_mt_iocb_rqst_fx00 *piocb_rqst;
+ struct fc_bsg_job *bsg_job;
+ struct fxdisc_entry_fx00 fx_iocb;
+ uint8_t entry_cnt = 1;
+
+ memset(&fx_iocb, 0, sizeof(struct fxdisc_entry_fx00));
+ fx_iocb.entry_type = FX00_IOCB_TYPE;
+ fx_iocb.handle = cpu_to_le32(sp->handle);
+ fx_iocb.entry_count = entry_cnt;
+
+ if (sp->type == SRB_FXIOCB_DCMD) {
+ fx_iocb.func_num =
+ cpu_to_le16(sp->u.iocb_cmd.u.fxiocb.req_func_type);
+ fx_iocb.adapid = cpu_to_le32(fxio->u.fxiocb.adapter_id);
+ fx_iocb.adapid_hi = cpu_to_le32(fxio->u.fxiocb.adapter_id_hi);
+ fx_iocb.reserved_0 = cpu_to_le32(fxio->u.fxiocb.reserved_0);
+ fx_iocb.reserved_1 = cpu_to_le32(fxio->u.fxiocb.reserved_1);
+ fx_iocb.dataword_extra =
+ cpu_to_le32(fxio->u.fxiocb.req_data_extra);
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DMA_VALID) {
+ fx_iocb.req_dsdcnt = cpu_to_le16(1);
+ fx_iocb.req_xfrcnt =
+ cpu_to_le16(fxio->u.fxiocb.req_len);
+ fx_iocb.dseg_rq_address[0] =
+ cpu_to_le32(LSD(fxio->u.fxiocb.req_dma_handle));
+ fx_iocb.dseg_rq_address[1] =
+ cpu_to_le32(MSD(fxio->u.fxiocb.req_dma_handle));
+ fx_iocb.dseg_rq_len =
+ cpu_to_le32(fxio->u.fxiocb.req_len);
+ }
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_RESP_DMA_VALID) {
+ fx_iocb.rsp_dsdcnt = cpu_to_le16(1);
+ fx_iocb.rsp_xfrcnt =
+ cpu_to_le16(fxio->u.fxiocb.rsp_len);
+ fx_iocb.dseg_rsp_address[0] =
+ cpu_to_le32(LSD(fxio->u.fxiocb.rsp_dma_handle));
+ fx_iocb.dseg_rsp_address[1] =
+ cpu_to_le32(MSD(fxio->u.fxiocb.rsp_dma_handle));
+ fx_iocb.dseg_rsp_len =
+ cpu_to_le32(fxio->u.fxiocb.rsp_len);
+ }
+
+ if (fxio->u.fxiocb.flags & SRB_FXDISC_REQ_DWRD_VALID) {
+ fx_iocb.dataword =
+ cpu_to_le32(fxio->u.fxiocb.req_data);
+ }
+ fx_iocb.flags = fxio->u.fxiocb.flags;
+ } else {
+ struct scatterlist *sg;
+ bsg_job = sp->u.bsg_job;
+ piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
+ &bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
+
+ fx_iocb.func_num = piocb_rqst->func_type;
+ fx_iocb.adapid = piocb_rqst->adapid;
+ fx_iocb.adapid_hi = piocb_rqst->adapid_hi;
+ fx_iocb.reserved_0 = piocb_rqst->reserved_0;
+ fx_iocb.reserved_1 = piocb_rqst->reserved_1;
+ fx_iocb.dataword_extra = piocb_rqst->dataword_extra;
+ fx_iocb.dataword = piocb_rqst->dataword;
+ fx_iocb.req_xfrcnt = cpu_to_le16(piocb_rqst->req_len);
+ fx_iocb.rsp_xfrcnt = cpu_to_le16(piocb_rqst->rsp_len);
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DMA_VALID) {
+ int avail_dsds, tot_dsds;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt = NULL;
+ uint32_t *cur_dsd;
+ int index = 0, cont = 0;
+
+ fx_iocb.req_dsdcnt =
+ cpu_to_le16(bsg_job->request_payload.sg_cnt);
+ tot_dsds =
+ cpu_to_le32(bsg_job->request_payload.sg_cnt);
+ cur_dsd = (uint32_t *)&fx_iocb.dseg_rq_address[0];
+ avail_dsds = 1;
+ for_each_sg(bsg_job->request_payload.sg_list, sg,
+ tot_dsds, index) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0,
+ REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(
+ sp->fcport->vha->req,
+ &lcont_pkt);
+ cur_dsd = (uint32_t *)
+ lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ entry_cnt++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio(
+ (void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(
+ ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3042,
+ (uint8_t *)&lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3043,
+ (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_RESP_DMA_VALID) {
+ int avail_dsds, tot_dsds;
+ cont_a64_entry_t lcont_pkt;
+ cont_a64_entry_t *cont_pkt = NULL;
+ uint32_t *cur_dsd;
+ int index = 0, cont = 0;
+
+ fx_iocb.rsp_dsdcnt =
+ cpu_to_le16(bsg_job->reply_payload.sg_cnt);
+ tot_dsds = cpu_to_le32(bsg_job->reply_payload.sg_cnt);
+ cur_dsd = (uint32_t *)&fx_iocb.dseg_rsp_address[0];
+ avail_dsds = 1;
+
+ for_each_sg(bsg_job->reply_payload.sg_list, sg,
+ tot_dsds, index) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Cont.
+ * Type 1 IOCB.
+ */
+ memset(&lcont_pkt, 0,
+ REQUEST_ENTRY_SIZE);
+ cont_pkt =
+ qlafx00_prep_cont_type1_iocb(
+ sp->fcport->vha->req,
+ &lcont_pkt);
+ cur_dsd = (uint32_t *)
+ lcont_pkt.dseg_0_address;
+ avail_dsds = 5;
+ cont = 1;
+ entry_cnt++;
+ }
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ if (avail_dsds == 0 && cont == 1) {
+ cont = 0;
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(
+ ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3045,
+ (uint8_t *)&lcont_pkt,
+ REQUEST_ENTRY_SIZE);
+ }
+ }
+ if (avail_dsds != 0 && cont == 1) {
+ memcpy_toio((void __iomem *)cont_pkt,
+ &lcont_pkt, REQUEST_ENTRY_SIZE);
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3046,
+ (uint8_t *)&lcont_pkt, REQUEST_ENTRY_SIZE);
+ }
+ }
+
+ if (piocb_rqst->flags & SRB_FXDISC_REQ_DWRD_VALID)
+ fx_iocb.dataword = cpu_to_le32(piocb_rqst->dataword);
+ fx_iocb.flags = piocb_rqst->flags;
+ fx_iocb.entry_count = entry_cnt;
+ }
+
+ ql_dump_buffer(ql_dbg_user + ql_dbg_verbose,
+ sp->fcport->vha, 0x3047,
+ (uint8_t *)&fx_iocb, sizeof(struct fxdisc_entry_fx00));
+
+ memcpy((void __iomem *)pfxiocb, &fx_iocb,
+ sizeof(struct fxdisc_entry_fx00));
+ wmb();
+}
diff --git a/drivers/scsi/qla2xxx/qla_mr.h b/drivers/scsi/qla2xxx/qla_mr.h
new file mode 100644
index 000000000000..cc327dc2fd10
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mr.h
@@ -0,0 +1,510 @@
+/*
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c) 2003-2013 QLogic Corporation
+ *
+ * See LICENSE.qla2xxx for copyright and licensing details.
+ */
+#ifndef __QLA_MR_H
+#define __QLA_MR_H
+
+/*
+ * The PCI VendorID and DeviceID for our board.
+ */
+#define PCI_DEVICE_ID_QLOGIC_ISPF001 0xF001
+
+/* FX00 specific definitions */
+
+#define FX00_COMMAND_TYPE_7 0x07 /* Command Type 7 entry for 7XXX */
+struct cmd_type_7_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi;
+
+ uint16_t tgt_idx; /* Target Idx. */
+ uint16_t timeout; /* Command timeout. */
+
+ uint16_t dseg_count; /* Data segment count. */
+ uint16_t scsi_rsp_dsd_len;
+
+ struct scsi_lun lun; /* LUN (LE). */
+
+ uint8_t cntrl_flags;
+
+ uint8_t task_mgmt_flags; /* Task management flags. */
+
+ uint8_t task;
+
+ uint8_t crn;
+
+ uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
+ uint32_t byte_count; /* Total byte count. */
+
+ uint32_t dseg_0_address[2]; /* Data segment 0 address. */
+ uint32_t dseg_0_len; /* Data segment 0 length. */
+};
+
+/*
+ * ISP queue - marker entry structure definition.
+ */
+struct mrk_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t handle_count; /* Handle count. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id; /* Target ID. */
+
+ uint8_t modifier; /* Modifier (7-0). */
+ uint8_t reserved_1;
+
+ uint8_t reserved_2[5];
+
+ uint8_t lun[8]; /* FCP LUN (BE). */
+ uint8_t reserved_3[36];
+};
+
+
+#define STATUS_TYPE_FX00 0x01 /* Status entry. */
+struct sts_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t comp_status; /* Completion status. */
+ uint16_t reserved_0; /* OX_ID used by the firmware. */
+
+ uint32_t residual_len; /* FW calc residual transfer length. */
+
+ uint16_t reserved_1;
+ uint16_t state_flags; /* State flags. */
+
+ uint16_t reserved_2;
+ uint16_t scsi_status; /* SCSI status. */
+
+ uint32_t sense_len; /* FCP SENSE length. */
+ uint8_t data[32]; /* FCP response/sense information. */
+};
+
+
+#define MAX_HANDLE_COUNT 15
+#define MULTI_STATUS_TYPE_FX00 0x0D
+
+struct multi_sts_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t handle_count;
+ uint8_t entry_status;
+
+ uint32_t handles[MAX_HANDLE_COUNT];
+};
+
+#define TSK_MGMT_IOCB_TYPE_FX00 0x05
+struct tsk_mgmt_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define;
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id; /* Target Idx. */
+
+ uint16_t reserved_1;
+
+ uint16_t delay; /* Activity delay in seconds. */
+
+ uint16_t timeout; /* Command timeout. */
+
+ struct scsi_lun lun; /* LUN (LE). */
+
+ uint32_t control_flags; /* Control Flags. */
+
+ uint8_t reserved_2[32];
+};
+
+
+#define ABORT_IOCB_TYPE_FX00 0x08 /* Abort IOCB status. */
+struct abort_iocb_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t handle_hi; /* System handle. */
+
+ uint16_t tgt_id_sts; /* Completion status. */
+ uint16_t options;
+
+ uint32_t abort_handle; /* System handle. */
+ uint32_t abort_handle_hi; /* System handle. */
+
+ uint16_t req_que_no;
+ uint8_t reserved_1[38];
+};
+
+#define IOCTL_IOSB_TYPE_FX00 0x0C
+struct ioctl_iocb_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t reserved_0; /* System handle. */
+
+ uint16_t comp_func_num;
+ uint16_t fw_iotcl_flags;
+
+ uint32_t dataword_r; /* Data word returned */
+ uint32_t adapid; /* Adapter ID */
+ uint32_t adapid_hi; /* Adapter ID high */
+ uint32_t reserved_1;
+
+ uint32_t seq_no;
+ uint8_t reserved_2[20];
+ uint32_t residuallen;
+ uint32_t status;
+};
+
+#define STATUS_CONT_TYPE_FX00 0x04
+
+#define FX00_IOCB_TYPE 0x0B
+struct fxdisc_entry_fx00 {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System Defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint32_t reserved_0; /* System handle. */
+
+ uint16_t func_num;
+ uint16_t req_xfrcnt;
+ uint16_t req_dsdcnt;
+ uint16_t rsp_xfrcnt;
+ uint16_t rsp_dsdcnt;
+ uint8_t flags;
+ uint8_t reserved_1;
+
+ uint32_t dseg_rq_address[2]; /* Data segment 0 address. */
+ uint32_t dseg_rq_len; /* Data segment 0 length. */
+ uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */
+ uint32_t dseg_rsp_len; /* Data segment 1 length. */
+
+ uint32_t dataword;
+ uint32_t adapid;
+ uint32_t adapid_hi;
+ uint32_t dataword_extra;
+};
+
+struct qlafx00_tgt_node_info {
+ uint8_t tgt_node_wwpn[WWN_SIZE];
+ uint8_t tgt_node_wwnn[WWN_SIZE];
+ uint32_t tgt_node_state;
+ uint8_t reserved[128];
+ uint32_t reserved_1[8];
+ uint64_t reserved_2[4];
+} __packed;
+
+#define QLAFX00_TGT_NODE_INFO sizeof(struct qlafx00_tgt_node_info)
+
+#define QLAFX00_LINK_STATUS_DOWN 0x10
+#define QLAFX00_LINK_STATUS_UP 0x11
+
+#define QLAFX00_PORT_SPEED_2G 0x2
+#define QLAFX00_PORT_SPEED_4G 0x4
+#define QLAFX00_PORT_SPEED_8G 0x8
+#define QLAFX00_PORT_SPEED_10G 0xa
+struct port_info_data {
+ uint8_t port_state;
+ uint8_t port_type;
+ uint16_t port_identifier;
+ uint32_t up_port_state;
+ uint8_t fw_ver_num[32];
+ uint8_t portal_attrib;
+ uint16_t host_option;
+ uint8_t reset_delay;
+ uint8_t pdwn_retry_cnt;
+ uint16_t max_luns2tgt;
+ uint8_t risc_ver;
+ uint8_t pconn_option;
+ uint16_t risc_option;
+ uint16_t max_frame_len;
+ uint16_t max_iocb_alloc;
+ uint16_t exec_throttle;
+ uint8_t retry_cnt;
+ uint8_t retry_delay;
+ uint8_t port_name[8];
+ uint8_t port_id[3];
+ uint8_t link_status;
+ uint8_t plink_rate;
+ uint32_t link_config;
+ uint16_t adap_haddr;
+ uint8_t tgt_disc;
+ uint8_t log_tout;
+ uint8_t node_name[8];
+ uint16_t erisc_opt1;
+ uint8_t resp_acc_tmr;
+ uint8_t intr_del_tmr;
+ uint8_t erisc_opt2;
+ uint8_t alt_port_name[8];
+ uint8_t alt_node_name[8];
+ uint8_t link_down_tout;
+ uint8_t conn_type;
+ uint8_t fc_fw_mode;
+ uint32_t uiReserved[48];
+} __packed;
+
+/* OS Type Designations */
+#define OS_TYPE_UNKNOWN 0
+#define OS_TYPE_LINUX 2
+
+/* Linux Info */
+#define SYSNAME_LENGTH 128
+#define NODENAME_LENGTH 64
+#define RELEASE_LENGTH 64
+#define VERSION_LENGTH 64
+#define MACHINE_LENGTH 64
+#define DOMNAME_LENGTH 64
+
+struct host_system_info {
+ uint32_t os_type;
+ char sysname[SYSNAME_LENGTH];
+ char nodename[NODENAME_LENGTH];
+ char release[RELEASE_LENGTH];
+ char version[VERSION_LENGTH];
+ char machine[MACHINE_LENGTH];
+ char domainname[DOMNAME_LENGTH];
+ char hostdriver[VERSION_LENGTH];
+ uint32_t reserved[64];
+} __packed;
+
+struct register_host_info {
+ struct host_system_info hsi; /* host system info */
+ uint64_t utc; /* UTC (system time) */
+ uint32_t reserved[64]; /* future additions */
+} __packed;
+
+
+#define QLAFX00_PORT_DATA_INFO (sizeof(struct port_info_data))
+#define QLAFX00_TGT_NODE_LIST_SIZE (sizeof(uint32_t) * 32)
+
+struct config_info_data {
+ uint8_t product_name[256];
+ uint8_t symbolic_name[64];
+ uint8_t serial_num[32];
+ uint8_t hw_version[16];
+ uint8_t fw_version[16];
+ uint8_t uboot_version[16];
+ uint8_t fru_serial_num[32];
+
+ uint8_t fc_port_count;
+ uint8_t iscsi_port_count;
+ uint8_t reserved1[2];
+
+ uint8_t mode;
+ uint8_t log_level;
+ uint8_t reserved2[2];
+
+ uint32_t log_size;
+
+ uint8_t tgt_pres_mode;
+ uint8_t iqn_flags;
+ uint8_t lun_mapping;
+
+ uint64_t adapter_id;
+
+ uint32_t cluster_key_len;
+ uint8_t cluster_key[10];
+
+ uint64_t cluster_master_id;
+ uint64_t cluster_slave_id;
+ uint8_t cluster_flags;
+} __packed;
+
+#define FXDISC_GET_CONFIG_INFO 0x01
+#define FXDISC_GET_PORT_INFO 0x02
+#define FXDISC_GET_TGT_NODE_INFO 0x80
+#define FXDISC_GET_TGT_NODE_LIST 0x81
+#define FXDISC_REG_HOST_INFO 0x99
+
+#define QLAFX00_HBA_ICNTRL_REG 0x21B08
+#define QLAFX00_ICR_ENB_MASK 0x80000000
+#define QLAFX00_ICR_DIS_MASK 0x7fffffff
+#define QLAFX00_HST_RST_REG 0x18264
+#define QLAFX00_HST_TO_HBA_REG 0x20A04
+#define QLAFX00_HBA_TO_HOST_REG 0x21B70
+#define QLAFX00_HST_INT_STS_BITS 0x7
+#define QLAFX00_BAR1_BASE_ADDR_REG 0x40018
+#define QLAFX00_PEX0_WIN0_BASE_ADDR_REG 0x41824
+
+#define QLAFX00_INTR_MB_CMPLT 0x1
+#define QLAFX00_INTR_RSP_CMPLT 0x2
+#define QLAFX00_INTR_MB_RSP_CMPLT 0x3
+#define QLAFX00_INTR_ASYNC_CMPLT 0x4
+#define QLAFX00_INTR_MB_ASYNC_CMPLT 0x5
+#define QLAFX00_INTR_RSP_ASYNC_CMPLT 0x6
+#define QLAFX00_INTR_ALL_CMPLT 0x7
+
+#define QLAFX00_MBA_SYSTEM_ERR 0x8002
+#define QLAFX00_MBA_LINK_UP 0x8011
+#define QLAFX00_MBA_LINK_DOWN 0x8012
+#define QLAFX00_MBA_PORT_UPDATE 0x8014
+#define QLAFX00_MBA_SHUTDOWN_RQSTD 0x8062
+
+#define SOC_SW_RST_CONTROL_REG_CORE0 0x0020800
+#define SOC_FABRIC_RST_CONTROL_REG 0x0020840
+#define SOC_FABRIC_CONTROL_REG 0x0020200
+#define SOC_FABRIC_CONFIG_REG 0x0020204
+
+#define SOC_INTERRUPT_SOURCE_I_CONTROL_REG 0x0020B00
+#define SOC_CORE_TIMER_REG 0x0021850
+#define SOC_IRQ_ACK_REG 0x00218b4
+
+#define CONTINUE_A64_TYPE_FX00 0x03 /* Continuation entry. */
+
+#define QLAFX00_SET_HST_INTR(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HST_TO_HBA_REG, \
+ value)
+
+#define QLAFX00_CLR_HST_INTR(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG, \
+ ~value)
+
+#define QLAFX00_RD_INTR_REG(ha) \
+ RD_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG)
+
+#define QLAFX00_CLR_INTR_REG(ha, value) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_TO_HOST_REG, \
+ ~value)
+
+#define QLAFX00_SET_HBA_SOC_REG(ha, off, val)\
+ WRT_REG_DWORD((ha)->cregbase + off, val)
+
+#define QLAFX00_GET_HBA_SOC_REG(ha, off)\
+ RD_REG_DWORD((ha)->cregbase + off)
+
+#define QLAFX00_HBA_RST_REG(ha, val)\
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HST_RST_REG, val)
+
+#define QLAFX00_RD_ICNTRL_REG(ha) \
+ RD_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG)
+
+#define QLAFX00_ENABLE_ICNTRL_REG(ha) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG, \
+ (QLAFX00_GET_HBA_SOC_REG(ha, QLAFX00_HBA_ICNTRL_REG) | \
+ QLAFX00_ICR_ENB_MASK))
+
+#define QLAFX00_DISABLE_ICNTRL_REG(ha) \
+ WRT_REG_DWORD((ha)->cregbase + QLAFX00_HBA_ICNTRL_REG, \
+ (QLAFX00_GET_HBA_SOC_REG(ha, QLAFX00_HBA_ICNTRL_REG) & \
+ QLAFX00_ICR_DIS_MASK))
+
+#define QLAFX00_RD_REG(ha, off) \
+ RD_REG_DWORD((ha)->cregbase + off)
+
+#define QLAFX00_WR_REG(ha, off, val) \
+ WRT_REG_DWORD((ha)->cregbase + off, val)
+
+struct qla_mt_iocb_rqst_fx00 {
+ uint32_t reserved_0;
+
+ uint16_t func_type;
+ uint8_t flags;
+ uint8_t reserved_1;
+
+ uint32_t dataword;
+
+ uint32_t adapid;
+ uint32_t adapid_hi;
+
+ uint32_t dataword_extra;
+
+ uint32_t req_len;
+
+ uint32_t rsp_len;
+};
+
+struct qla_mt_iocb_rsp_fx00 {
+ uint32_t reserved_1;
+
+ uint16_t func_type;
+ uint16_t ioctl_flags;
+
+ uint32_t ioctl_data;
+
+ uint32_t adapid;
+ uint32_t adapid_hi;
+
+ uint32_t reserved_2;
+ uint32_t seq_number;
+
+ uint8_t reserved_3[20];
+
+ int32_t res_count;
+
+ uint32_t status;
+};
+
+
+#define MAILBOX_REGISTER_COUNT_FX00 16
+#define AEN_MAILBOX_REGISTER_COUNT_FX00 8
+#define MAX_FIBRE_DEVICES_FX00 512
+#define MAX_LUNS_FX00 0x1024
+#define MAX_TARGETS_FX00 MAX_ISA_DEVICES
+#define REQUEST_ENTRY_CNT_FX00 512 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_FX00 256 /* Number of response entries.*/
+
+/*
+ * Firmware state codes for QLAFX00 adapters
+ */
+#define FSTATE_FX00_CONFIG_WAIT 0x0000 /* Waiting for driver to issue
+ * Initialize FW Mbox cmd
+ */
+#define FSTATE_FX00_INITIALIZED 0x1000 /* FW has been initialized by
+ * the driver
+ */
+
+#define FX00_DEF_RATOV 10
+
+struct mr_data_fx00 {
+ uint8_t product_name[256];
+ uint8_t symbolic_name[64];
+ uint8_t serial_num[32];
+ uint8_t hw_version[16];
+ uint8_t fw_version[16];
+ uint8_t uboot_version[16];
+ uint8_t fru_serial_num[32];
+ fc_port_t fcport; /* fcport used for requests
+ * that are not linked
+ * to a particular target
+ */
+ uint8_t fw_hbt_en;
+ uint8_t fw_hbt_cnt;
+ uint8_t fw_hbt_miss_cnt;
+ uint32_t old_fw_hbt_cnt;
+ uint16_t fw_reset_timer_tick;
+ uint8_t fw_reset_timer_exp;
+ uint32_t old_aenmbx0_state;
+};
+
+#define QLAFX00_LOOP_DOWN_TIME 615 /* 600 */
+#define QLAFX00_HEARTBEAT_INTERVAL 6 /* number of seconds */
+#define QLAFX00_HEARTBEAT_MISS_CNT 3 /* number of miss */
+#define QLAFX00_RESET_INTERVAL 120 /* number of seconds */
+#define QLAFX00_MAX_RESET_INTERVAL 600 /* number of seconds */
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ccb5e6404d09..5307bf86d5e0 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -47,6 +47,7 @@ MODULE_PARM_DESC(ql2xenableclass2,
"Specify if Class 2 operations are supported from the very "
"beginning. Default is 0 - class 2 not supported.");
+
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO);
MODULE_PARM_DESC(ql2xlogintimeout,
@@ -354,7 +355,12 @@ fail_req_map:
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
{
- if (req && req->ring)
+ if (IS_QLAFX00(ha)) {
+ if (req && req->ring_fx00)
+ dma_free_coherent(&ha->pdev->dev,
+ (req->length_fx00 + 1) * sizeof(request_t),
+ req->ring_fx00, req->dma_fx00);
+ } else if (req && req->ring)
dma_free_coherent(&ha->pdev->dev,
(req->length + 1) * sizeof(request_t),
req->ring, req->dma);
@@ -368,11 +374,16 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
{
- if (rsp && rsp->ring)
+ if (IS_QLAFX00(ha)) {
+ if (rsp && rsp->ring)
+ dma_free_coherent(&ha->pdev->dev,
+ (rsp->length_fx00 + 1) * sizeof(request_t),
+ rsp->ring_fx00, rsp->dma_fx00);
+ } else if (rsp && rsp->ring) {
dma_free_coherent(&ha->pdev->dev,
(rsp->length + 1) * sizeof(response_t),
rsp->ring, rsp->dma);
-
+ }
kfree(rsp);
rsp = NULL;
}
@@ -633,7 +644,7 @@ qla2x00_sp_free_dma(void *vha, void *ptr)
qla2x00_rel_sp(sp->fcport->vha, sp);
}
-static void
+void
qla2x00_sp_compl(void *data, void *ptr, int res)
{
struct qla_hw_data *ha = (struct qla_hw_data *)data;
@@ -657,6 +668,9 @@ qla2x00_sp_compl(void *data, void *ptr, int res)
cmd->scsi_done(cmd);
}
+/* If we are SP1 here, we need to still take and release the host_lock as SP1
+ * does not have the changes necessary to avoid taking host->host_lock.
+ */
static int
qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
@@ -1304,6 +1318,9 @@ qla2x00_loop_reset(scsi_qla_host_t *vha)
}
}
+ if (IS_QLAFX00(ha))
+ return QLA_SUCCESS;
+
if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
@@ -1858,6 +1875,7 @@ static struct isp_operations qla2100_isp_ops = {
.start_scsi = qla2x00_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla2300_isp_ops = {
@@ -1895,6 +1913,7 @@ static struct isp_operations qla2300_isp_ops = {
.start_scsi = qla2x00_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla24xx_isp_ops = {
@@ -1932,6 +1951,7 @@ static struct isp_operations qla24xx_isp_ops = {
.start_scsi = qla24xx_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla25xx_isp_ops = {
@@ -1969,6 +1989,7 @@ static struct isp_operations qla25xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla81xx_isp_ops = {
@@ -2006,6 +2027,7 @@ static struct isp_operations qla81xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla2x00_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla82xx_isp_ops = {
@@ -2043,6 +2065,7 @@ static struct isp_operations qla82xx_isp_ops = {
.start_scsi = qla82xx_start_scsi,
.abort_isp = qla82xx_abort_isp,
.iospace_config = qla82xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
};
static struct isp_operations qla83xx_isp_ops = {
@@ -2080,6 +2103,45 @@ static struct isp_operations qla83xx_isp_ops = {
.start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
.iospace_config = qla83xx_iospace_config,
+ .initialize_adapter = qla2x00_initialize_adapter,
+};
+
+static struct isp_operations qlafx00_isp_ops = {
+ .pci_config = qlafx00_pci_config,
+ .reset_chip = qlafx00_soft_reset,
+ .chip_diag = qlafx00_chip_diag,
+ .config_rings = qlafx00_config_rings,
+ .reset_adapter = qlafx00_soft_reset,
+ .nvram_config = NULL,
+ .update_fw_options = NULL,
+ .load_risc = NULL,
+ .pci_info_str = qlafx00_pci_info_str,
+ .fw_version_str = qlafx00_fw_version_str,
+ .intr_handler = qlafx00_intr_handler,
+ .enable_intrs = qlafx00_enable_intrs,
+ .disable_intrs = qlafx00_disable_intrs,
+ .abort_command = qlafx00_abort_command,
+ .target_reset = qlafx00_abort_target,
+ .lun_reset = qlafx00_lun_reset,
+ .fabric_login = NULL,
+ .fabric_logout = NULL,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla24xx_read_nvram_data,
+ .write_nvram = qla24xx_write_nvram_data,
+ .fw_dump = NULL,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = NULL,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+ .start_scsi = qlafx00_start_scsi,
+ .abort_isp = qlafx00_abort_isp,
+ .iospace_config = qlafx00_iospace_config,
+ .initialize_adapter = qlafx00_initialize_adapter,
};
static inline void
@@ -2192,6 +2254,9 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_T10_PI;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISPF001:
+ ha->device_type |= DT_ISPFX00;
+ break;
}
if (IS_QLA82XX(ha))
@@ -2265,7 +2330,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
mem_only = 1;
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
@@ -2436,6 +2502,18 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
ha->nvram_conf_off = ~0;
ha->nvram_data_off = ~0;
+ } else if (IS_QLAFX00(ha)) {
+ ha->max_fibre_devices = MAX_FIBRE_DEVICES_FX00;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT_FX00;
+ ha->aen_mbx_count = AEN_MAILBOX_REGISTER_COUNT_FX00;
+ req_length = REQUEST_ENTRY_CNT_FX00;
+ rsp_length = RESPONSE_ENTRY_CNT_FX00;
+ ha->init_cb_size = sizeof(struct init_cb_fx);
+ ha->isp_ops = &qlafx00_isp_ops;
+ ha->port_down_retry_count = 30; /* default value */
+ ha->mr.fw_hbt_cnt = QLAFX00_HEARTBEAT_INTERVAL;
+ ha->mr.fw_reset_timer_tick = QLAFX00_RESET_INTERVAL;
+ ha->mr.fw_hbt_en = 1;
}
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
@@ -2500,13 +2578,24 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host = base_vha->host;
base_vha->req = req;
- host->can_queue = req->length + 128;
+ if (IS_QLAFX00(ha))
+ host->can_queue = 1024;
+ else
+ host->can_queue = req->length + 128;
if (IS_QLA2XXX_MIDTYPE(ha))
base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx;
else
base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
base_vha->vp_idx;
+ /* Setup fcport template structure. */
+ ha->mr.fcport.vha = base_vha;
+ ha->mr.fcport.port_type = FCT_UNKNOWN;
+ ha->mr.fcport.loop_id = FC_NO_LOOP_ID;
+ qla2x00_set_fcport_state(&ha->mr.fcport, FCS_UNCONFIGURED);
+ ha->mr.fcport.supported_classes = FC_COS_UNSPECIFIED;
+ ha->mr.fcport.scan_state = 1;
+
/* Set the SG table size based on ISP type */
if (!IS_FWI2_CAPABLE(ha)) {
if (IS_QLA2100(ha))
@@ -2562,6 +2651,13 @@ que_init:
rsp->req = req;
req->rsp = rsp;
+ if (IS_QLAFX00(ha)) {
+ ha->rsp_q_map[0] = rsp;
+ ha->req_q_map[0] = req;
+ set_bit(0, ha->req_qid_map);
+ set_bit(0, ha->rsp_qid_map);
+ }
+
/* FWI2-capable only. */
req->req_q_in = &ha->iobase->isp24.req_q_in;
req->req_q_out = &ha->iobase->isp24.req_q_out;
@@ -2574,6 +2670,13 @@ que_init:
rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out;
}
+ if (IS_QLAFX00(ha)) {
+ req->req_q_in = &ha->iobase->ispfx00.req_q_in;
+ req->req_q_out = &ha->iobase->ispfx00.req_q_out;
+ rsp->rsp_q_in = &ha->iobase->ispfx00.rsp_q_in;
+ rsp->rsp_q_out = &ha->iobase->ispfx00.rsp_q_out;
+ }
+
if (IS_QLA82XX(ha)) {
req->req_q_out = &ha->iobase->isp82.req_q_out[0];
rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0];
@@ -2595,7 +2698,7 @@ que_init:
"req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n",
req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out);
- if (qla2x00_initialize_adapter(base_vha)) {
+ if (ha->isp_ops->initialize_adapter(base_vha)) {
ql_log(ql_log_fatal, base_vha, 0x00d6,
"Failed to initialize adapter - Adapter flags %x.\n",
base_vha->device_flags);
@@ -2720,6 +2823,18 @@ skip_dpc:
qla2x00_alloc_sysfs_attr(base_vha);
+ if (IS_QLAFX00(ha)) {
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_GET_CONFIG_INFO);
+
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_GET_PORT_INFO);
+
+ /* Register system information */
+ ret = qlafx00_fx_disc(base_vha,
+ &base_vha->hw->mr.fcport, FXDISC_REG_HOST_INFO);
+ }
+
qla2x00_init_host_attr(base_vha);
qla2x00_dfs_setup(base_vha);
@@ -2777,6 +2892,8 @@ iospace_config_failed:
} else {
if (ha->iobase)
iounmap(ha->iobase);
+ if (ha->cregbase)
+ iounmap(ha->cregbase);
}
pci_release_selected_regions(ha->pdev, ha->bars);
kfree(ha);
@@ -2960,6 +3077,9 @@ qla2x00_remove_one(struct pci_dev *pdev)
if (ha->iobase)
iounmap(ha->iobase);
+ if (ha->cregbase)
+ iounmap(ha->cregbase);
+
if (ha->mqiobase)
iounmap(ha->mqiobase);
@@ -3068,6 +3188,12 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport,
int do_login, int defer)
{
+ if (IS_QLAFX00(vha->hw)) {
+ qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
+ qla2x00_schedule_rport_del(vha, fcport, defer);
+ return;
+ }
+
if (atomic_read(&fcport->state) == FCS_ONLINE &&
vha->vp_idx == fcport->vha->vp_idx) {
qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST);
@@ -3710,6 +3836,22 @@ qla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code)
kobject_uevent_env(&vha->hw->pdev->dev.kobj, KOBJ_CHANGE, envp);
}
+int
+qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode,
+ uint32_t *data, int cnt)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(vha, QLA_EVT_AENFX);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.aenfx.evtcode = evtcode;
+ e->u.aenfx.count = cnt;
+ memcpy(e->u.aenfx.mbx, data, sizeof(*data) * cnt);
+ return qla2x00_post_work(vha, e);
+}
+
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
@@ -3758,6 +3900,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_UEVENT:
qla2x00_uevent_emit(vha, e->u.uevent.code);
break;
+ case QLA_EVT_AENFX:
+ qlafx00_process_aen(vha, e);
+ break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
@@ -4592,6 +4737,38 @@ qla2x00_do_dpc(void *data)
ql_dbg(ql_dbg_dpc, base_vha, 0x4006,
"FCoE context reset end.\n");
}
+ } else if (IS_QLAFX00(ha)) {
+ if (test_and_clear_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags)) {
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4020,
+ "Firmware Reset Recovery\n");
+ if (qlafx00_reset_initialize(base_vha)) {
+ /* Failed. Abort isp later. */
+ if (!test_bit(UNLOADING,
+ &base_vha->dpc_flags))
+ set_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags);
+ ql_dbg(ql_dbg_dpc, base_vha,
+ 0x4021,
+ "Reset Recovery Failed\n");
+ }
+ }
+
+ if (test_and_clear_bit(FX00_TARGET_SCAN,
+ &base_vha->dpc_flags)) {
+ ql_dbg(ql_dbg_dpc, base_vha, 0x4022,
+ "ISPFx00 Target Scan scheduled\n");
+ if (qlafx00_rescan_isp(base_vha)) {
+ if (!test_bit(UNLOADING,
+ &base_vha->dpc_flags))
+ set_bit(ISP_UNRECOVERABLE,
+ &base_vha->dpc_flags);
+ ql_dbg(ql_dbg_dpc, base_vha, 0x401e,
+ "ISPFx00 Target Scan Failed\n");
+ }
+ ql_dbg(ql_dbg_dpc, base_vha, 0x401f,
+ "ISPFx00 Target Scan End\n");
+ }
}
if (test_and_clear_bit(ISP_ABORT_NEEDED,
@@ -4630,6 +4807,9 @@ qla2x00_do_dpc(void *data)
clear_bit(SCR_PENDING, &base_vha->dpc_flags);
}
+ if (IS_QLAFX00(ha))
+ goto loop_resync_check;
+
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n");
@@ -4654,7 +4834,7 @@ qla2x00_do_dpc(void *data)
}
if (test_and_clear_bit(RESET_MARKER_NEEDED,
- &base_vha->dpc_flags) &&
+ &base_vha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) {
ql_dbg(ql_dbg_dpc, base_vha, 0x400b,
@@ -4677,9 +4857,9 @@ qla2x00_do_dpc(void *data)
ql_dbg(ql_dbg_dpc, base_vha, 0x400e,
"Relogin end.\n");
}
-
+loop_resync_check:
if (test_and_clear_bit(LOOP_RESYNC_NEEDED,
- &base_vha->dpc_flags)) {
+ &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x400f,
"Loop resync scheduled.\n");
@@ -4697,6 +4877,9 @@ qla2x00_do_dpc(void *data)
"Loop resync end.\n");
}
+ if (IS_QLAFX00(ha))
+ goto intr_on_check;
+
if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) &&
atomic_read(&base_vha->loop_state) == LOOP_READY) {
clear_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags);
@@ -4714,7 +4897,7 @@ qla2x00_do_dpc(void *data)
if (test_and_clear_bit(HOST_RAMP_UP_QUEUE_DEPTH,
&base_vha->dpc_flags))
qla2x00_host_ramp_up_queuedepth(base_vha);
-
+intr_on_check:
if (!ha->interrupts_on)
ha->isp_ops->enable_intrs(ha);
@@ -4722,7 +4905,8 @@ qla2x00_do_dpc(void *data)
&base_vha->dpc_flags))
ha->isp_ops->beacon_blink(base_vha);
- qla2x00_do_dpc_all_vps(base_vha);
+ if (!IS_QLAFX00(ha))
+ qla2x00_do_dpc_all_vps(base_vha);
ha->dpc_active = 0;
end_loop:
@@ -4818,6 +5002,9 @@ qla2x00_timer(scsi_qla_host_t *vha)
qla82xx_watchdog(vha);
}
+ if (!vha->vp_idx && IS_QLAFX00(ha))
+ qlafx00_timer_routine(vha);
+
/* Loop down handler. */
if (atomic_read(&vha->loop_down_timer) > 0 &&
!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) &&
@@ -5335,6 +5522,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8031) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISPF001) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 61b5d8c2b5da..fcdc22306cab 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -2585,25 +2585,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle,
ha->tgt.tgt_ops->free_cmd(cmd);
}
-/* ha->hardware_lock supposed to be held on entry */
-/* called via callback from qla2xxx */
-void qlt_ctio_completion(struct scsi_qla_host *vha, uint32_t handle)
-{
- struct qla_hw_data *ha = vha->hw;
- struct qla_tgt *tgt = ha->tgt.qla_tgt;
-
- if (likely(tgt == NULL)) {
- ql_dbg(ql_dbg_tgt, vha, 0xe021,
- "CTIO, but target mode not enabled"
- " (ha %d %p handle %#x)", vha->vp_idx, ha, handle);
- return;
- }
-
- tgt->irq_cmd_count++;
- qlt_do_ctio_completion(vha, handle, CTIO_SUCCESS, NULL);
- tgt->irq_cmd_count--;
-}
-
static inline int qlt_get_fcp_task_attr(struct scsi_qla_host *vha,
uint8_t task_codes)
{
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index ff9ccb9fd036..b33e411f28a0 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -980,7 +980,6 @@ extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
-extern void qlt_ctio_completion(struct scsi_qla_host *, uint32_t);
extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *);
extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 2b6e478d9e33..6c66d22eb1b1 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.04.00.08-k"
+#define QLA2XXX_VERSION "8.05.00.03-k"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 4
+#define QLA_DRIVER_MINOR_VER 5
#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.c b/drivers/scsi/qla4xxx/ql4_83xx.c
index 5d8fe4f75650..d607eb8e24cb 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.c
+++ b/drivers/scsi/qla4xxx/ql4_83xx.c
@@ -1629,9 +1629,37 @@ static void __qla4_83xx_disable_pause(struct scsi_qla_host *ha)
ql4_printk(KERN_INFO, ha, "Disabled pause frames successfully.\n");
}
+/**
+ * qla4_83xx_eport_init - Initialize EPort.
+ * @ha: Pointer to host adapter structure.
+ *
+ * If EPort hardware is in reset state before disabling pause, there would be
+ * serious hardware wedging issues. To prevent this perform eport init everytime
+ * before disabling pause frames.
+ **/
+static void qla4_83xx_eport_init(struct scsi_qla_host *ha)
+{
+ /* Clear the 8 registers */
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_REG, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT0, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT1, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT2, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_PORT3, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_SRE_SHIM, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_EPG_SHIM, 0x0);
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_ETHER_PCS, 0x0);
+
+ /* Write any value to Reset Control register */
+ qla4_83xx_wr_reg_indirect(ha, QLA83XX_RESET_CONTROL, 0xFF);
+
+ ql4_printk(KERN_INFO, ha, "EPORT is out of reset.\n");
+}
+
void qla4_83xx_disable_pause(struct scsi_qla_host *ha)
{
ha->isp_ops->idc_lock(ha);
+ /* Before disabling pause frames, ensure that eport is not in reset */
+ qla4_83xx_eport_init(ha);
qla4_83xx_dump_pause_control_regs(ha);
__qla4_83xx_disable_pause(ha);
ha->isp_ops->idc_unlock(ha);
diff --git a/drivers/scsi/qla4xxx/ql4_83xx.h b/drivers/scsi/qla4xxx/ql4_83xx.h
index 6a00f903f2a6..fab237fa32cc 100644
--- a/drivers/scsi/qla4xxx/ql4_83xx.h
+++ b/drivers/scsi/qla4xxx/ql4_83xx.h
@@ -55,6 +55,16 @@
#define QLA83XX_SET_PAUSE_VAL 0x0
#define QLA83XX_SET_TC_MAX_CELL_VAL 0x03FF03FF
+#define QLA83XX_RESET_CONTROL 0x28084E50
+#define QLA83XX_RESET_REG 0x28084E60
+#define QLA83XX_RESET_PORT0 0x28084E70
+#define QLA83XX_RESET_PORT1 0x28084E80
+#define QLA83XX_RESET_PORT2 0x28084E90
+#define QLA83XX_RESET_PORT3 0x28084EA0
+#define QLA83XX_RESET_SRE_SHIM 0x28084EB0
+#define QLA83XX_RESET_EPG_SHIM 0x28084EC0
+#define QLA83XX_RESET_ETHER_PCS 0x28084ED0
+
/* qla_83xx_reg_tbl registers */
#define QLA83XX_PEG_HALT_STATUS1 0x34A8
#define QLA83XX_PEG_HALT_STATUS2 0x34AC
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
index 5b0afc18ef18..51c365bcf912 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.h
+++ b/drivers/scsi/qla4xxx/ql4_dbg.h
@@ -12,6 +12,7 @@
/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
/* #define QL_DEBUG_LEVEL_4 */
/* #define QL_DEBUG_LEVEL_5 */
+/* #define QL_DEBUG_LEVEL_7 */
/* #define QL_DEBUG_LEVEL_9 */
#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
@@ -48,6 +49,12 @@
#define DEBUG5(x) do {} while (0);
#endif /* */
+#if defined(QL_DEBUG_LEVEL_7)
+#define DEBUG7(x) do {x; } while (0)
+#else /* */
+#define DEBUG7(x) do {} while (0)
+#endif /* */
+
#if defined(QL_DEBUG_LEVEL_9)
#define DEBUG9(x) do {x;} while (0);
#else /* */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 129f5dd02822..ddf16a86bbf5 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -159,6 +159,22 @@
#define LSDW(x) ((u32)((u64)(x)))
#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
+#define DEV_DB_NON_PERSISTENT 0
+#define DEV_DB_PERSISTENT 1
+
+#define COPY_ISID(dst_isid, src_isid) { \
+ int i, j; \
+ for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;) \
+ dst_isid[i++] = src_isid[j--]; \
+}
+
+#define SET_BITVAL(o, n, v) { \
+ if (o) \
+ n |= v; \
+ else \
+ n &= ~v; \
+}
+
/*
* Retry & Timeout Values
*/
@@ -363,6 +379,8 @@ struct ql82xx_hw_data {
uint32_t flt_iscsi_param;
uint32_t flt_region_chap;
uint32_t flt_chap_size;
+ uint32_t flt_region_ddb;
+ uint32_t flt_ddb_size;
};
struct qla4_8xxx_legacy_intr_set {
@@ -501,6 +519,7 @@ struct scsi_qla_host {
#define AF_INIT_DONE 1 /* 0x00000002 */
#define AF_MBOX_COMMAND 2 /* 0x00000004 */
#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_ST_DISCOVERY_IN_PROGRESS 4 /* 0x00000010 */
#define AF_INTERRUPTS_ON 6 /* 0x00000040 */
#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
#define AF_LINK_UP 8 /* 0x00000100 */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index ad9d2e2d370f..c7b8892b5a83 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -288,6 +288,8 @@ union external_hw_config_reg {
#define FA_GOLD_RISC_CODE_ADDR_82 0x80000
#define FA_FLASH_ISCSI_CHAP 0x540000
#define FA_FLASH_CHAP_SIZE 0xC0000
+#define FA_FLASH_ISCSI_DDB 0x420000
+#define FA_FLASH_DDB_SIZE 0x080000
/* Flash Description Table */
struct qla_fdt_layout {
@@ -348,6 +350,7 @@ struct qla_flt_header {
#define FLT_REG_BOOT_CODE_82 0x78
#define FLT_REG_ISCSI_PARAM 0x65
#define FLT_REG_ISCSI_CHAP 0x63
+#define FLT_REG_ISCSI_DDB 0x6A
struct qla_flt_region {
uint32_t code;
@@ -490,12 +493,16 @@ struct qla_flt_region {
#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
+#define MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED 0x802A
#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
+#define MBOX_ASTS_INITIALIZATION_FAILED 0x8031
+#define MBOX_ASTS_SYSTEM_WARNING_EVENT 0x8036
#define MBOX_ASTS_IDC_COMPLETE 0x8100
#define MBOX_ASTS_IDC_REQUEST_NOTIFICATION 0x8101
+#define MBOX_ASTS_DCBX_CONF_CHANGE 0x8110
#define MBOX_ASTS_TXSCVR_INSERTED 0x8130
#define MBOX_ASTS_TXSCVR_REMOVED 0x8131
@@ -779,12 +786,41 @@ struct dev_db_entry {
#define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */
#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */
+#define OPT_IS_FW_ASSIGNED_IPV6 11
+#define OPT_IPV6_DEVICE 8
+#define OPT_AUTO_SENDTGTS_DISABLE 6
+#define OPT_DISC_SESSION 4
+#define OPT_ENTRY_STATE 3
uint16_t exec_throttle; /* 02-03 */
uint16_t exec_count; /* 04-05 */
uint16_t res0; /* 06-07 */
uint16_t iscsi_options; /* 08-09 */
+#define ISCSIOPT_HEADER_DIGEST_EN 13
+#define ISCSIOPT_DATA_DIGEST_EN 12
+#define ISCSIOPT_IMMEDIATE_DATA_EN 11
+#define ISCSIOPT_INITIAL_R2T_EN 10
+#define ISCSIOPT_DATA_SEQ_IN_ORDER 9
+#define ISCSIOPT_DATA_PDU_IN_ORDER 8
+#define ISCSIOPT_CHAP_AUTH_EN 7
+#define ISCSIOPT_SNACK_REQ_EN 6
+#define ISCSIOPT_DISCOVERY_LOGOUT_EN 5
+#define ISCSIOPT_BIDI_CHAP_EN 4
+#define ISCSIOPT_DISCOVERY_AUTH_OPTIONAL 3
+#define ISCSIOPT_ERL1 1
+#define ISCSIOPT_ERL0 0
+
uint16_t tcp_options; /* 0A-0B */
+#define TCPOPT_TIMESTAMP_STAT 6
+#define TCPOPT_NAGLE_DISABLE 5
+#define TCPOPT_WSF_DISABLE 4
+#define TCPOPT_TIMER_SCALE3 3
+#define TCPOPT_TIMER_SCALE2 2
+#define TCPOPT_TIMER_SCALE1 1
+#define TCPOPT_TIMESTAMP_EN 0
+
uint16_t ip_options; /* 0C-0D */
+#define IPOPT_FRAGMENT_DISABLE 4
+
uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */
#define BYTE_UNITS 512
uint32_t res1; /* 10-13 */
@@ -816,6 +852,8 @@ struct dev_db_entry {
* much RAM */
uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */
uint8_t res5[0x10]; /* 1B0-1BF */
+#define DDB_NO_LINK 0xFFFF
+#define DDB_ISNS 0xFFFD
uint16_t ddb_link; /* 1C0-1C1 */
uint16_t chap_tbl_idx; /* 1C2-1C3 */
uint16_t tgt_portal_grp; /* 1C4-1C5 */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 982293edf02c..4a428009f699 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -191,6 +191,9 @@ int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options,
int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha,
uint32_t status, uint32_t pid,
uint32_t data_size, uint8_t *data);
+int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index);
/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
@@ -224,8 +227,6 @@ void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha,
int qla4_83xx_isp_reset(struct scsi_qla_host *ha);
void qla4_83xx_queue_iocb(struct scsi_qla_host *ha);
void qla4_83xx_complete_iocb(struct scsi_qla_host *ha);
-uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha);
-uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha);
uint32_t qla4_83xx_rd_reg(struct scsi_qla_host *ha, ulong addr);
void qla4_83xx_wr_reg(struct scsi_qla_host *ha, ulong addr, uint32_t val);
int qla4_83xx_rd_reg_indirect(struct scsi_qla_host *ha, uint32_t addr,
@@ -261,6 +262,10 @@ int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha);
void qla4_83xx_disable_pause(struct scsi_qla_host *ha);
void qla4_83xx_enable_mbox_intrs(struct scsi_qla_host *ha);
int qla4_83xx_can_perform_reset(struct scsi_qla_host *ha);
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
+ dma_addr_t dma_addr);
+int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
+ char *password, uint16_t chap_index);
extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 1b83dc283d2e..482287f4005f 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -396,7 +396,6 @@ static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,
task_data = task->dd_data;
memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status));
- ha->req_q_count += task_data->iocb_req_cnt;
ha->iocb_cnt -= task_data->iocb_req_cnt;
queue_work(ha->task_wq, &task_data->task_work);
}
@@ -416,7 +415,6 @@ static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha,
return mrb;
/* update counters */
- ha->req_q_count += mrb->iocb_cnt;
ha->iocb_cnt -= mrb->iocb_cnt;
return mrb;
@@ -877,6 +875,43 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
}
break;
+ case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x Received IPv6 default router changed notification\n",
+ ha->host_no, mbox_sts[0]));
+ break;
+
+ case MBOX_ASTS_INITIALIZATION_FAILED:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",
+ ha->host_no, mbox_sts[0],
+ mbox_sts[3]));
+ break;
+
+ case MBOX_ASTS_SYSTEM_WARNING_EVENT:
+ DEBUG2(ql4_printk(KERN_WARNING, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ break;
+
+ case MBOX_ASTS_DCBX_CONF_CHANGE:
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
+ ha->host_no, mbox_sts[0], mbox_sts[1],
+ mbox_sts[2], mbox_sts[3], mbox_sts[4],
+ mbox_sts[5]));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "scsi%ld: AEN %04x Received DCBX configuration changed notification\n",
+ ha->host_no, mbox_sts[0]));
+ break;
+
default:
DEBUG2(printk(KERN_WARNING
"scsi%ld: AEN %04x UNKNOWN\n",
@@ -1099,8 +1134,8 @@ irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id)
status = qla4_82xx_rd_32(ha, ISR_INT_STATE_REG);
if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) {
- DEBUG2(ql4_printk(KERN_INFO, ha,
- "%s legacy Int not triggered\n", __func__));
+ DEBUG7(ql4_printk(KERN_INFO, ha,
+ "%s legacy Int not triggered\n", __func__));
return IRQ_NONE;
}
@@ -1158,7 +1193,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)
/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
if (!(leg_int_ptr & LEG_INT_PTR_B31)) {
- DEBUG2(ql4_printk(KERN_ERR, ha,
+ DEBUG7(ql4_printk(KERN_ERR, ha,
"%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n",
__func__));
return IRQ_NONE;
@@ -1166,7 +1201,7 @@ irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)
/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) {
- DEBUG2(ql4_printk(KERN_ERR, ha,
+ DEBUG7(ql4_printk(KERN_ERR, ha,
"%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n",
__func__, (leg_int_ptr & PF_BITS_MASK),
ha->pf_bit));
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 160d33697216..a501beab3ffe 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1129,6 +1129,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
+ uint32_t scsi_lun[2];
int status = QLA_SUCCESS;
DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
@@ -1140,10 +1141,16 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
*/
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+ int_to_scsilun(lun, (struct scsi_lun *) scsi_lun);
mbox_cmd[0] = MBOX_CMD_LUN_RESET;
mbox_cmd[1] = ddb_entry->fw_ddb_index;
- mbox_cmd[2] = lun << 8;
+ /* FW expects LUN bytes 0-3 in Incoming Mailbox 2
+ * (LUN byte 0 is LSByte, byte 3 is MSByte) */
+ mbox_cmd[2] = cpu_to_le32(scsi_lun[0]);
+ /* FW expects LUN bytes 4-7 in Incoming Mailbox 3
+ * (LUN byte 4 is LSByte, byte 7 is MSByte) */
+ mbox_cmd[3] = cpu_to_le32(scsi_lun[1]);
mbox_cmd[5] = 0x01; /* Immediate Command Enable */
qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
@@ -1281,8 +1288,8 @@ exit_about_fw:
return status;
}
-static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
- dma_addr_t dma_addr)
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
+ dma_addr_t dma_addr)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -1410,6 +1417,55 @@ exit_bootdb_failed:
return status;
}
+int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index)
+{
+ uint32_t dev_db_start_offset;
+ uint32_t dev_db_end_offset;
+ int status = QLA_ERROR;
+
+ memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
+
+ if (is_qla40XX(ha)) {
+ dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ dev_db_end_offset = FLASH_OFFSET_DB_END;
+ } else {
+ dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
+ (ha->hw.flt_region_ddb << 2);
+ /* flt_ddb_size is DDB table size for both ports
+ * so divide it by 2 to calculate the offset for second port
+ */
+ if (ha->port_num == 1)
+ dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
+
+ dev_db_end_offset = dev_db_start_offset +
+ (ha->hw.flt_ddb_size / 2);
+ }
+
+ dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry));
+
+ if (dev_db_start_offset > dev_db_end_offset) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s:Invalid DDB index %d", __func__,
+ ddb_index));
+ goto exit_fdb_failed;
+ }
+
+ if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ sizeof(*fw_ddb_entry)) != QLA_SUCCESS) {
+ ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash failed\n",
+ ha->host_no, __func__);
+ goto exit_fdb_failed;
+ }
+
+ if (fw_ddb_entry->cookie == DDB_VALID_COOKIE)
+ status = QLA_SUCCESS;
+
+exit_fdb_failed:
+ return status;
+}
+
int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
uint16_t idx)
{
@@ -1503,6 +1559,62 @@ exit_set_chap:
return ret;
}
+
+int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
+ char *password, uint16_t chap_index)
+{
+ int rval = QLA_ERROR;
+ struct ql4_chap_table *chap_table = NULL;
+ int max_chap_entries;
+
+ if (!ha->chap_list) {
+ ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ if (!username || !password) {
+ ql4_printk(KERN_ERR, ha, "No memory for username & secret\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ if (is_qla80XX(ha))
+ max_chap_entries = (ha->hw.flt_chap_size / 2) /
+ sizeof(struct ql4_chap_table);
+ else
+ max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+ if (chap_index > max_chap_entries) {
+ ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
+ rval = QLA_ERROR;
+ goto exit_uni_chap;
+ }
+
+ mutex_lock(&ha->chap_sem);
+ chap_table = (struct ql4_chap_table *)ha->chap_list + chap_index;
+ if (chap_table->cookie != __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
+ rval = QLA_ERROR;
+ goto exit_unlock_uni_chap;
+ }
+
+ if (!(chap_table->flags & BIT_6)) {
+ ql4_printk(KERN_ERR, ha, "Unidirectional entry not set\n");
+ rval = QLA_ERROR;
+ goto exit_unlock_uni_chap;
+ }
+
+ strncpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
+ strncpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
+
+ rval = QLA_SUCCESS;
+
+exit_unlock_uni_chap:
+ mutex_unlock(&ha->chap_sem);
+exit_uni_chap:
+ return rval;
+}
+
/**
* qla4xxx_get_chap_index - Get chap index given username and secret
* @ha: pointer to adapter structure
@@ -1524,7 +1636,7 @@ int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
int max_chap_entries = 0;
struct ql4_chap_table *chap_table;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c
index 71d3d234f526..eaf00c162eb2 100644
--- a/drivers/scsi/qla4xxx/ql4_nx.c
+++ b/drivers/scsi/qla4xxx/ql4_nx.c
@@ -2089,7 +2089,7 @@ static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
if (r_addr & 0xf) {
DEBUG2(ql4_printk(KERN_INFO, ha,
- "[%s]: Read addr 0x%x not 16 bytes alligned\n",
+ "[%s]: Read addr 0x%x not 16 bytes aligned\n",
__func__, r_addr));
return QLA_ERROR;
}
@@ -3154,6 +3154,10 @@ qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
hw->flt_region_chap = start;
hw->flt_chap_size = le32_to_cpu(region->size);
break;
+ case FLT_REG_ISCSI_DDB:
+ hw->flt_region_ddb = start;
+ hw->flt_ddb_size = le32_to_cpu(region->size);
+ break;
}
}
goto done;
@@ -3166,14 +3170,19 @@ no_flash_data:
hw->flt_region_boot = FA_BOOT_CODE_ADDR_82;
hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
hw->flt_region_fw = FA_RISC_CODE_ADDR_82;
- hw->flt_region_chap = FA_FLASH_ISCSI_CHAP;
+ hw->flt_region_chap = FA_FLASH_ISCSI_CHAP >> 2;
hw->flt_chap_size = FA_FLASH_CHAP_SIZE;
+ hw->flt_region_ddb = FA_FLASH_ISCSI_DDB >> 2;
+ hw->flt_ddb_size = FA_FLASH_DDB_SIZE;
done:
- DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x "
- "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt,
- hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload,
- hw->flt_region_fw));
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x chap_size=0x%x ddb=0x%x ddb_size=0x%x\n",
+ loc, hw->flt_region_flt, hw->flt_region_fdt,
+ hw->flt_region_boot, hw->flt_region_bootload,
+ hw->flt_region_fw, hw->flt_region_chap,
+ hw->flt_chap_size, hw->flt_region_ddb,
+ hw->flt_ddb_size));
}
static void
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 6142729167f4..a47f99957ba8 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -166,6 +166,26 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
int reason);
+/*
+ * iSCSI Flash DDB sysfs entry points
+ */
+static int
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len);
+static int
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf);
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
+ int len);
+static int
+qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess);
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess);
+
static struct qla4_8xxx_legacy_intr_set legacy_intr[] =
QLA82XX_LEGACY_INTR_CONFIG;
@@ -232,6 +252,13 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
.send_ping = qla4xxx_send_ping,
.get_chap = qla4xxx_get_chap_list,
.delete_chap = qla4xxx_delete_chap,
+ .get_flashnode_param = qla4xxx_sysfs_ddb_get_param,
+ .set_flashnode_param = qla4xxx_sysfs_ddb_set_param,
+ .new_flashnode = qla4xxx_sysfs_ddb_add,
+ .del_flashnode = qla4xxx_sysfs_ddb_delete,
+ .login_flashnode = qla4xxx_sysfs_ddb_login,
+ .logout_flashnode = qla4xxx_sysfs_ddb_logout,
+ .logout_flashnode_sid = qla4xxx_sysfs_ddb_logout_sid,
};
static struct scsi_transport_template *qla4xxx_scsi_transport;
@@ -376,6 +403,68 @@ static umode_t qla4_attr_is_visible(int param_type, int param)
default:
return 0;
}
+ case ISCSI_FLASHNODE_PARAM:
+ switch (param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ case ISCSI_FLASHNODE_ERL:
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ case ISCSI_FLASHNODE_MAX_R2T:
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ case ISCSI_FLASHNODE_ISID:
+ case ISCSI_FLASHNODE_TSID:
+ case ISCSI_FLASHNODE_PORT:
+ case ISCSI_FLASHNODE_MAX_BURST:
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ case ISCSI_FLASHNODE_IPADDR:
+ case ISCSI_FLASHNODE_ALIAS:
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ case ISCSI_FLASHNODE_IPV6_TC:
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ case ISCSI_FLASHNODE_NAME:
+ case ISCSI_FLASHNODE_TPGT:
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
+ case ISCSI_FLASHNODE_USERNAME:
+ case ISCSI_FLASHNODE_PASSWORD:
+ case ISCSI_FLASHNODE_STATSN:
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
+ return S_IRUGO;
+ default:
+ return 0;
+ }
}
return 0;
@@ -391,7 +480,7 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
int valid_chap_entries = 0;
int ret = 0, i;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -495,7 +584,7 @@ static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx)
memset(chap_table, 0, sizeof(struct ql4_chap_table));
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -1922,6 +2011,252 @@ static int qla4xxx_task_xmit(struct iscsi_task *task)
return -ENOSYS;
}
+static int qla4xxx_copy_from_fwddb_param(struct iscsi_bus_flash_session *sess,
+ struct iscsi_bus_flash_conn *conn,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ unsigned long options = 0;
+ int rc = 0;
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ conn->is_fw_assigned_ipv6 = test_bit(OPT_IS_FW_ASSIGNED_IPV6, &options);
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
+ rc = iscsi_switch_str_param(&sess->portal_type,
+ PORTAL_TYPE_IPV6);
+ if (rc)
+ goto exit_copy;
+ } else {
+ rc = iscsi_switch_str_param(&sess->portal_type,
+ PORTAL_TYPE_IPV4);
+ if (rc)
+ goto exit_copy;
+ }
+
+ sess->auto_snd_tgt_disable = test_bit(OPT_AUTO_SENDTGTS_DISABLE,
+ &options);
+ sess->discovery_sess = test_bit(OPT_DISC_SESSION, &options);
+ sess->entry_state = test_bit(OPT_ENTRY_STATE, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+ conn->hdrdgst_en = test_bit(ISCSIOPT_HEADER_DIGEST_EN, &options);
+ conn->datadgst_en = test_bit(ISCSIOPT_DATA_DIGEST_EN, &options);
+ sess->imm_data_en = test_bit(ISCSIOPT_IMMEDIATE_DATA_EN, &options);
+ sess->initial_r2t_en = test_bit(ISCSIOPT_INITIAL_R2T_EN, &options);
+ sess->dataseq_inorder_en = test_bit(ISCSIOPT_DATA_SEQ_IN_ORDER,
+ &options);
+ sess->pdu_inorder_en = test_bit(ISCSIOPT_DATA_PDU_IN_ORDER, &options);
+ sess->chap_auth_en = test_bit(ISCSIOPT_CHAP_AUTH_EN, &options);
+ conn->snack_req_en = test_bit(ISCSIOPT_SNACK_REQ_EN, &options);
+ sess->discovery_logout_en = test_bit(ISCSIOPT_DISCOVERY_LOGOUT_EN,
+ &options);
+ sess->bidi_chap_en = test_bit(ISCSIOPT_BIDI_CHAP_EN, &options);
+ sess->discovery_auth_optional =
+ test_bit(ISCSIOPT_DISCOVERY_AUTH_OPTIONAL, &options);
+ if (test_bit(ISCSIOPT_ERL1, &options))
+ sess->erl |= BIT_1;
+ if (test_bit(ISCSIOPT_ERL0, &options))
+ sess->erl |= BIT_0;
+
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
+ conn->tcp_timestamp_stat = test_bit(TCPOPT_TIMESTAMP_STAT, &options);
+ conn->tcp_nagle_disable = test_bit(TCPOPT_NAGLE_DISABLE, &options);
+ conn->tcp_wsf_disable = test_bit(TCPOPT_WSF_DISABLE, &options);
+ if (test_bit(TCPOPT_TIMER_SCALE3, &options))
+ conn->tcp_timer_scale |= BIT_3;
+ if (test_bit(TCPOPT_TIMER_SCALE2, &options))
+ conn->tcp_timer_scale |= BIT_2;
+ if (test_bit(TCPOPT_TIMER_SCALE1, &options))
+ conn->tcp_timer_scale |= BIT_1;
+
+ conn->tcp_timer_scale >>= 1;
+ conn->tcp_timestamp_en = test_bit(TCPOPT_TIMESTAMP_EN, &options);
+
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
+ conn->fragment_disable = test_bit(IPOPT_FRAGMENT_DISABLE, &options);
+
+ conn->max_recv_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len);
+ conn->max_xmit_dlength = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len);
+ sess->first_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len);
+ sess->max_burst = BYTE_UNITS *
+ le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len);
+ sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t);
+ sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
+ sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain);
+ sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ conn->max_segment_size = le16_to_cpu(fw_ddb_entry->mss);
+ conn->tcp_xmit_wsf = fw_ddb_entry->tcp_xmt_wsf;
+ conn->tcp_recv_wsf = fw_ddb_entry->tcp_rcv_wsf;
+ conn->ipv6_flow_label = le16_to_cpu(fw_ddb_entry->ipv6_flow_lbl);
+ conn->keepalive_timeout = le16_to_cpu(fw_ddb_entry->ka_timeout);
+ conn->local_port = le16_to_cpu(fw_ddb_entry->lcl_port);
+ conn->statsn = le32_to_cpu(fw_ddb_entry->stat_sn);
+ conn->exp_statsn = le32_to_cpu(fw_ddb_entry->exp_stat_sn);
+ sess->discovery_parent_idx = le16_to_cpu(fw_ddb_entry->ddb_link);
+ sess->discovery_parent_type = le16_to_cpu(fw_ddb_entry->ddb_link);
+ sess->chap_out_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx);
+ sess->tsid = le16_to_cpu(fw_ddb_entry->tsid);
+
+ sess->default_taskmgmt_timeout =
+ le16_to_cpu(fw_ddb_entry->def_timeout);
+ conn->port = le16_to_cpu(fw_ddb_entry->port);
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ conn->ipaddress = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->ipaddress) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ conn->redirect_ipaddr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->redirect_ipaddr) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ memcpy(conn->ipaddress, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN);
+ memcpy(conn->redirect_ipaddr, fw_ddb_entry->tgt_addr, IPv6_ADDR_LEN);
+
+ if (test_bit(OPT_IPV6_DEVICE, &options)) {
+ conn->ipv6_traffic_class = fw_ddb_entry->ipv4_tos;
+
+ conn->link_local_ipv6_addr = kzalloc(IPv6_ADDR_LEN, GFP_KERNEL);
+ if (!conn->link_local_ipv6_addr) {
+ rc = -ENOMEM;
+ goto exit_copy;
+ }
+
+ memcpy(conn->link_local_ipv6_addr,
+ fw_ddb_entry->link_local_ipv6_addr, IPv6_ADDR_LEN);
+ } else {
+ conn->ipv4_tos = fw_ddb_entry->ipv4_tos;
+ }
+
+ if (fw_ddb_entry->iscsi_name[0]) {
+ rc = iscsi_switch_str_param(&sess->targetname,
+ (char *)fw_ddb_entry->iscsi_name);
+ if (rc)
+ goto exit_copy;
+ }
+
+ if (fw_ddb_entry->iscsi_alias[0]) {
+ rc = iscsi_switch_str_param(&sess->targetalias,
+ (char *)fw_ddb_entry->iscsi_alias);
+ if (rc)
+ goto exit_copy;
+ }
+
+ COPY_ISID(sess->isid, fw_ddb_entry->isid);
+
+exit_copy:
+ return rc;
+}
+
+static int qla4xxx_copy_to_fwddb_param(struct iscsi_bus_flash_session *sess,
+ struct iscsi_bus_flash_conn *conn,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ uint16_t options;
+ int rc = 0;
+
+ options = le16_to_cpu(fw_ddb_entry->options);
+ SET_BITVAL(conn->is_fw_assigned_ipv6, options, BIT_11);
+ if (!strncmp(sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= BIT_8;
+ else
+ options &= ~BIT_8;
+
+ SET_BITVAL(sess->auto_snd_tgt_disable, options, BIT_6);
+ SET_BITVAL(sess->discovery_sess, options, BIT_4);
+ SET_BITVAL(sess->entry_state, options, BIT_3);
+ fw_ddb_entry->options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->iscsi_options);
+ SET_BITVAL(conn->hdrdgst_en, options, BIT_13);
+ SET_BITVAL(conn->datadgst_en, options, BIT_12);
+ SET_BITVAL(sess->imm_data_en, options, BIT_11);
+ SET_BITVAL(sess->initial_r2t_en, options, BIT_10);
+ SET_BITVAL(sess->dataseq_inorder_en, options, BIT_9);
+ SET_BITVAL(sess->pdu_inorder_en, options, BIT_8);
+ SET_BITVAL(sess->chap_auth_en, options, BIT_7);
+ SET_BITVAL(conn->snack_req_en, options, BIT_6);
+ SET_BITVAL(sess->discovery_logout_en, options, BIT_5);
+ SET_BITVAL(sess->bidi_chap_en, options, BIT_4);
+ SET_BITVAL(sess->discovery_auth_optional, options, BIT_3);
+ SET_BITVAL(sess->erl & BIT_1, options, BIT_1);
+ SET_BITVAL(sess->erl & BIT_0, options, BIT_0);
+ fw_ddb_entry->iscsi_options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->tcp_options);
+ SET_BITVAL(conn->tcp_timestamp_stat, options, BIT_6);
+ SET_BITVAL(conn->tcp_nagle_disable, options, BIT_5);
+ SET_BITVAL(conn->tcp_wsf_disable, options, BIT_4);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_2, options, BIT_3);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_1, options, BIT_2);
+ SET_BITVAL(conn->tcp_timer_scale & BIT_0, options, BIT_1);
+ SET_BITVAL(conn->tcp_timestamp_en, options, BIT_0);
+ fw_ddb_entry->tcp_options = cpu_to_le16(options);
+
+ options = le16_to_cpu(fw_ddb_entry->ip_options);
+ SET_BITVAL(conn->fragment_disable, options, BIT_4);
+ fw_ddb_entry->ip_options = cpu_to_le16(options);
+
+ fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
+ fw_ddb_entry->iscsi_max_rcv_data_seg_len =
+ cpu_to_le16(conn->max_recv_dlength / BYTE_UNITS);
+ fw_ddb_entry->iscsi_max_snd_data_seg_len =
+ cpu_to_le16(conn->max_xmit_dlength / BYTE_UNITS);
+ fw_ddb_entry->iscsi_first_burst_len =
+ cpu_to_le16(sess->first_burst / BYTE_UNITS);
+ fw_ddb_entry->iscsi_max_burst_len = cpu_to_le16(sess->max_burst /
+ BYTE_UNITS);
+ fw_ddb_entry->iscsi_def_time2wait = cpu_to_le16(sess->time2wait);
+ fw_ddb_entry->iscsi_def_time2retain = cpu_to_le16(sess->time2retain);
+ fw_ddb_entry->tgt_portal_grp = cpu_to_le16(sess->tpgt);
+ fw_ddb_entry->mss = cpu_to_le16(conn->max_segment_size);
+ fw_ddb_entry->tcp_xmt_wsf = cpu_to_le16(conn->tcp_xmit_wsf);
+ fw_ddb_entry->tcp_rcv_wsf = cpu_to_le16(conn->tcp_recv_wsf);
+ fw_ddb_entry->ipv4_tos = conn->ipv4_tos;
+ fw_ddb_entry->ipv6_flow_lbl = cpu_to_le16(conn->ipv6_flow_label);
+ fw_ddb_entry->ka_timeout = cpu_to_le16(conn->keepalive_timeout);
+ fw_ddb_entry->lcl_port = cpu_to_le16(conn->local_port);
+ fw_ddb_entry->stat_sn = cpu_to_le16(conn->statsn);
+ fw_ddb_entry->exp_stat_sn = cpu_to_le16(conn->exp_statsn);
+ fw_ddb_entry->ddb_link = cpu_to_le16(sess->discovery_parent_type);
+ fw_ddb_entry->chap_tbl_idx = cpu_to_le16(sess->chap_out_idx);
+ fw_ddb_entry->tsid = cpu_to_le16(sess->tsid);
+ fw_ddb_entry->port = cpu_to_le16(conn->port);
+ fw_ddb_entry->def_timeout =
+ cpu_to_le16(sess->default_taskmgmt_timeout);
+
+ if (conn->ipaddress)
+ memcpy(fw_ddb_entry->ip_addr, conn->ipaddress,
+ sizeof(fw_ddb_entry->ip_addr));
+
+ if (conn->redirect_ipaddr)
+ memcpy(fw_ddb_entry->tgt_addr, conn->redirect_ipaddr,
+ sizeof(fw_ddb_entry->tgt_addr));
+
+ if (conn->link_local_ipv6_addr)
+ memcpy(fw_ddb_entry->link_local_ipv6_addr,
+ conn->link_local_ipv6_addr,
+ sizeof(fw_ddb_entry->link_local_ipv6_addr));
+
+ if (sess->targetname)
+ memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
+ sizeof(fw_ddb_entry->iscsi_name));
+
+ if (sess->targetalias)
+ memcpy(fw_ddb_entry->iscsi_alias, sess->targetalias,
+ sizeof(fw_ddb_entry->iscsi_alias));
+
+ COPY_ISID(fw_ddb_entry->isid, sess->isid);
+
+ return rc;
+}
+
static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha,
struct dev_db_entry *fw_ddb_entry,
struct iscsi_cls_session *cls_sess,
@@ -2543,6 +2878,7 @@ static void qla4_8xxx_process_fw_error(struct scsi_qla_host *ha)
void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
{
uint32_t dev_state;
+ uint32_t idc_ctrl;
/* don't poll if reset is going on */
if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) ||
@@ -2561,10 +2897,23 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha)
qla4xxx_wake_dpc(ha);
} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
!test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+
+ ql4_printk(KERN_INFO, ha, "%s: HW State: NEED RESET!\n",
+ __func__);
+
+ if (is_qla8032(ha)) {
+ idc_ctrl = qla4_83xx_rd_reg(ha,
+ QLA83XX_IDC_DRV_CTRL);
+ if (!(idc_ctrl & GRACEFUL_RESET_BIT1)) {
+ ql4_printk(KERN_INFO, ha, "%s: Graceful reset bit is not set\n",
+ __func__);
+ qla4xxx_mailbox_premature_completion(
+ ha);
+ }
+ }
+
if (is_qla8032(ha) ||
(is_qla8022(ha) && !ql4xdontresethba)) {
- ql4_printk(KERN_INFO, ha, "%s: HW State: "
- "NEED RESET!\n", __func__);
set_bit(DPC_RESET_HA, &ha->dpc_flags);
qla4xxx_wake_dpc(ha);
}
@@ -3737,8 +4086,8 @@ static struct isp_operations qla4_83xx_isp_ops = {
.reset_firmware = qla4_8xxx_stop_firmware,
.queue_iocb = qla4_83xx_queue_iocb,
.complete_iocb = qla4_83xx_complete_iocb,
- .rd_shdw_req_q_out = qla4_83xx_rd_shdw_req_q_out,
- .rd_shdw_rsp_q_in = qla4_83xx_rd_shdw_rsp_q_in,
+ .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out,
+ .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in,
.get_sys_info = qla4_8xxx_get_sys_info,
.rd_reg_direct = qla4_83xx_rd_reg,
.wr_reg_direct = qla4_83xx_wr_reg,
@@ -3761,11 +4110,6 @@ uint16_t qla4_82xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->req_q_out));
}
-uint16_t qla4_83xx_rd_shdw_req_q_out(struct scsi_qla_host *ha)
-{
- return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->req_q_out));
-}
-
uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
{
return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in);
@@ -3776,11 +4120,6 @@ uint16_t qla4_82xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
return (uint16_t)le32_to_cpu(readl(&ha->qla4_82xx_reg->rsp_q_in));
}
-uint16_t qla4_83xx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha)
-{
- return (uint16_t)le32_to_cpu(readl(&ha->qla4_83xx_reg->rsp_q_in));
-}
-
static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf)
{
struct scsi_qla_host *ha = data;
@@ -4005,7 +4344,7 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
if (val & BIT_7)
ddb_index[1] = (val & 0x7f);
- } else if (is_qla8022(ha)) {
+ } else if (is_qla80XX(ha)) {
buf = dma_alloc_coherent(&ha->pdev->dev, size,
&buf_dma, GFP_KERNEL);
if (!buf) {
@@ -4083,7 +4422,7 @@ static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
int max_chap_entries = 0;
struct ql4_chap_table *chap_table;
- if (is_qla8022(ha))
+ if (is_qla80XX(ha))
max_chap_entries = (ha->hw.flt_chap_size / 2) /
sizeof(struct ql4_chap_table);
else
@@ -5058,6 +5397,1342 @@ exit_nt_list:
dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
}
+static void qla4xxx_build_new_nt_list(struct scsi_qla_host *ha,
+ struct list_head *list_nt)
+{
+ struct dev_db_entry *fw_ddb_entry;
+ dma_addr_t fw_ddb_dma;
+ int max_ddbs;
+ int fw_idx_size;
+ int ret;
+ uint32_t idx = 0, next_idx = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t conn_id = 0;
+ struct qla_ddb_index *nt_ddb_idx;
+
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
+ &fw_ddb_dma);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n"));
+ goto exit_new_nt_list;
+ }
+ max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX :
+ MAX_DEV_DB_ENTRIES;
+ fw_idx_size = sizeof(struct qla_ddb_index);
+
+ for (idx = 0; idx < max_ddbs; idx = next_idx) {
+ ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma,
+ NULL, &next_idx, &state,
+ &conn_err, NULL, &conn_id);
+ if (ret == QLA_ERROR)
+ break;
+
+ /* Check if NT, then add it to list */
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
+ goto continue_next_new_nt;
+
+ if (!(state == DDB_DS_NO_CONNECTION_ACTIVE))
+ goto continue_next_new_nt;
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Adding DDB to session = 0x%x\n", idx));
+
+ nt_ddb_idx = vmalloc(fw_idx_size);
+ if (!nt_ddb_idx)
+ break;
+
+ nt_ddb_idx->fw_ddb_idx = idx;
+
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
+ if (ret == QLA_SUCCESS) {
+ /* free nt_ddb_idx and do not add to list_nt */
+ vfree(nt_ddb_idx);
+ goto continue_next_new_nt;
+ }
+
+ list_add_tail(&nt_ddb_idx->list, list_nt);
+
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
+ idx);
+ if (ret == QLA_ERROR)
+ goto exit_new_nt_list;
+
+continue_next_new_nt:
+ if (next_idx == 0)
+ break;
+ }
+
+exit_new_nt_list:
+ if (fw_ddb_entry)
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+}
+
+/**
+ * qla4xxx_sysfs_ddb_is_non_persistent - check for non-persistence of ddb entry
+ * @dev: dev associated with the sysfs entry
+ * @data: pointer to flashnode session object
+ *
+ * Returns:
+ * 1: if flashnode entry is non-persistent
+ * 0: if flashnode entry is persistent
+ **/
+static int qla4xxx_sysfs_ddb_is_non_persistent(struct device *dev, void *data)
+{
+ struct iscsi_bus_flash_session *fnode_sess;
+
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ return 0;
+
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+
+ return (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT);
+}
+
+/**
+ * qla4xxx_sysfs_ddb_tgt_create - Create sysfs entry for target
+ * @ha: pointer to host
+ * @fw_ddb_entry: flash ddb data
+ * @idx: target index
+ * @user: if set then this call is made from userland else from kernel
+ *
+ * Returns:
+ * On sucess: QLA_SUCCESS
+ * On failure: QLA_ERROR
+ *
+ * This create separate sysfs entries for session and connection attributes of
+ * the given fw ddb entry.
+ * If this is invoked as a result of a userspace call then the entry is marked
+ * as nonpersistent using flash_state field.
+ **/
+int qla4xxx_sysfs_ddb_tgt_create(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t *idx, int user)
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ struct iscsi_bus_flash_conn *fnode_conn = NULL;
+ int rc = QLA_ERROR;
+
+ fnode_sess = iscsi_create_flashnode_sess(ha->host, *idx,
+ &qla4xxx_iscsi_transport, 0);
+ if (!fnode_sess) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to create session sysfs entry for flashnode %d of host%lu\n",
+ __func__, *idx, ha->host_no);
+ goto exit_tgt_create;
+ }
+
+ fnode_conn = iscsi_create_flashnode_conn(ha->host, fnode_sess,
+ &qla4xxx_iscsi_transport, 0);
+ if (!fnode_conn) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to create conn sysfs entry for flashnode %d of host%lu\n",
+ __func__, *idx, ha->host_no);
+ goto free_sess;
+ }
+
+ if (user) {
+ fnode_sess->flash_state = DEV_DB_NON_PERSISTENT;
+ } else {
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
+
+ if (*idx == ha->pri_ddb_idx || *idx == ha->sec_ddb_idx)
+ fnode_sess->is_boot_target = 1;
+ else
+ fnode_sess->is_boot_target = 0;
+ }
+
+ rc = qla4xxx_copy_from_fwddb_param(fnode_sess, fnode_conn,
+ fw_ddb_entry);
+
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
+ __func__, fnode_sess->dev.kobj.name);
+
+ ql4_printk(KERN_INFO, ha, "%s: sysfs entry %s created\n",
+ __func__, fnode_conn->dev.kobj.name);
+
+ return QLA_SUCCESS;
+
+free_sess:
+ iscsi_destroy_flashnode_sess(fnode_sess);
+
+exit_tgt_create:
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_add - Add new ddb entry in flash
+ * @shost: pointer to host
+ * @buf: type of ddb entry (ipv4/ipv6)
+ * @len: length of buf
+ *
+ * This creates new ddb entry in the flash by finding first free index and
+ * storing default ddb there. And then create sysfs entry for the new ddb entry.
+ **/
+static int qla4xxx_sysfs_ddb_add(struct Scsi_Host *shost, const char *buf,
+ int len)
+{
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ struct device *dev;
+ uint16_t idx = 0;
+ uint16_t max_ddbs = 0;
+ uint32_t options = 0;
+ uint32_t rval = QLA_ERROR;
+
+ if (strncasecmp(PORTAL_TYPE_IPV4, buf, 4) &&
+ strncasecmp(PORTAL_TYPE_IPV6, buf, 4)) {
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Invalid portal type\n",
+ __func__));
+ goto exit_ddb_add;
+ }
+
+ max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
+ MAX_DEV_DB_ENTRIES;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ goto exit_ddb_add;
+ }
+
+ dev = iscsi_find_flashnode_sess(ha->host, NULL,
+ qla4xxx_sysfs_ddb_is_non_persistent);
+ if (dev) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: A non-persistent entry %s found\n",
+ __func__, dev->kobj.name);
+ goto exit_ddb_add;
+ }
+
+ for (idx = 0; idx < max_ddbs; idx++) {
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry,
+ fw_ddb_entry_dma, idx))
+ break;
+ }
+
+ if (idx == max_ddbs)
+ goto exit_ddb_add;
+
+ if (!strncasecmp("ipv6", buf, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (rval == QLA_ERROR)
+ goto exit_ddb_add;
+
+ rval = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 1);
+
+exit_ddb_add:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ if (rval == QLA_SUCCESS)
+ return idx;
+ else
+ return -EIO;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_apply - write the target ddb contents to Flash
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This writes the contents of target ddb buffer to Flash with a valid cookie
+ * value in order to make the ddb entry persistent.
+ **/
+static int qla4xxx_sysfs_ddb_apply(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t options = 0;
+ int rval = 0;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ rval = -ENOMEM;
+ goto exit_ddb_apply;
+ }
+
+ if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ rval = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (rval == QLA_ERROR)
+ goto exit_ddb_apply;
+
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
+
+ rval = qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ sizeof(*fw_ddb_entry), FLASH_OPT_RMW_COMMIT);
+
+ if (rval == QLA_SUCCESS) {
+ fnode_sess->flash_state = DEV_DB_PERSISTENT;
+ ql4_printk(KERN_INFO, ha,
+ "%s: flash node %u of host %lu written to flash\n",
+ __func__, fnode_sess->target_id, ha->host_no);
+ } else {
+ rval = -EIO;
+ ql4_printk(KERN_ERR, ha,
+ "%s: Error while writing flash node %u of host %lu to flash\n",
+ __func__, fnode_sess->target_id, ha->host_no);
+ }
+
+exit_ddb_apply:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return rval;
+}
+
+static ssize_t qla4xxx_sysfs_ddb_conn_open(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t idx)
+{
+ struct dev_db_entry *ddb_entry = NULL;
+ dma_addr_t ddb_entry_dma;
+ unsigned long wtime;
+ uint32_t mbx_sts = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t tmo = 0;
+ int ret = 0;
+
+ ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
+ &ddb_entry_dma, GFP_KERNEL);
+ if (!ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ return QLA_ERROR;
+ }
+
+ memcpy(ddb_entry, fw_ddb_entry, sizeof(*ddb_entry));
+
+ ret = qla4xxx_set_ddb_entry(ha, idx, ddb_entry_dma, &mbx_sts);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to set ddb entry for index %d\n",
+ __func__, idx));
+ goto exit_ddb_conn_open;
+ }
+
+ qla4xxx_conn_open(ha, idx);
+
+ /* To ensure that sendtargets is done, wait for at least 12 secs */
+ tmo = ((ha->def_timeout > LOGIN_TOV) &&
+ (ha->def_timeout < LOGIN_TOV * 10) ?
+ ha->def_timeout : LOGIN_TOV);
+
+ DEBUG2(ql4_printk(KERN_INFO, ha,
+ "Default time to wait for login to ddb %d\n", tmo));
+
+ wtime = jiffies + (HZ * tmo);
+ do {
+ ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL,
+ NULL, &state, &conn_err, NULL,
+ NULL);
+ if (ret == QLA_ERROR)
+ continue;
+
+ if (state == DDB_DS_NO_CONNECTION_ACTIVE ||
+ state == DDB_DS_SESSION_FAILED)
+ break;
+
+ schedule_timeout_uninterruptible(HZ / 10);
+ } while (time_after(wtime, jiffies));
+
+exit_ddb_conn_open:
+ if (ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*ddb_entry),
+ ddb_entry, ddb_entry_dma);
+ return ret;
+}
+
+static int qla4xxx_ddb_login_st(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry)
+{
+ struct qla_ddb_index *ddb_idx, *ddb_idx_tmp;
+ struct list_head list_nt;
+ uint16_t ddb_index;
+ int ret = 0;
+
+ if (test_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s: A discovery already in progress!\n", __func__);
+ return QLA_ERROR;
+ }
+
+ INIT_LIST_HEAD(&list_nt);
+
+ set_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
+
+ ret = qla4xxx_get_ddb_index(ha, &ddb_index);
+ if (ret == QLA_ERROR)
+ goto exit_login_st_clr_bit;
+
+ ret = qla4xxx_sysfs_ddb_conn_open(ha, fw_ddb_entry, ddb_index);
+ if (ret == QLA_ERROR)
+ goto exit_login_st;
+
+ qla4xxx_build_new_nt_list(ha, &list_nt);
+
+ list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, &list_nt, list) {
+ list_del_init(&ddb_idx->list);
+ qla4xxx_clear_ddb_entry(ha, ddb_idx->fw_ddb_idx);
+ vfree(ddb_idx);
+ }
+
+exit_login_st:
+ if (qla4xxx_clear_ddb_entry(ha, ddb_index) == QLA_ERROR) {
+ ql4_printk(KERN_ERR, ha,
+ "Unable to clear DDB index = 0x%x\n", ddb_index);
+ }
+
+ clear_bit(ddb_index, ha->ddb_idx_map);
+
+exit_login_st_clr_bit:
+ clear_bit(AF_ST_DISCOVERY_IN_PROGRESS, &ha->flags);
+ return ret;
+}
+
+static int qla4xxx_ddb_login_nt(struct scsi_qla_host *ha,
+ struct dev_db_entry *fw_ddb_entry,
+ uint16_t idx)
+{
+ int ret = QLA_ERROR;
+
+ ret = qla4xxx_is_session_exists(ha, fw_ddb_entry);
+ if (ret != QLA_SUCCESS)
+ ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, RESET_ADAPTER,
+ idx);
+ else
+ ret = -EPERM;
+
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_login - Login to the specified target
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This logs in to the specified target
+ **/
+static int qla4xxx_sysfs_ddb_login(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t options = 0;
+ int ret = 0;
+
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Target info is not persistent\n", __func__);
+ ret = -EIO;
+ goto exit_ddb_login;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ ret = -ENOMEM;
+ goto exit_ddb_login;
+ }
+
+ if (!strncasecmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ options |= IPV6_DEFAULT_DDB_ENTRY;
+
+ ret = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
+ if (ret == QLA_ERROR)
+ goto exit_ddb_login;
+
+ qla4xxx_copy_to_fwddb_param(fnode_sess, fnode_conn, fw_ddb_entry);
+ fw_ddb_entry->cookie = DDB_VALID_COOKIE;
+
+ if (strlen((char *)fw_ddb_entry->iscsi_name) == 0)
+ ret = qla4xxx_ddb_login_st(ha, fw_ddb_entry);
+ else
+ ret = qla4xxx_ddb_login_nt(ha, fw_ddb_entry,
+ fnode_sess->target_id);
+
+ if (ret > 0)
+ ret = -EIO;
+
+exit_ddb_login:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_logout_sid - Logout session for the specified target
+ * @cls_sess: pointer to session to be logged out
+ *
+ * This performs session log out from the specified target
+ **/
+static int qla4xxx_sysfs_ddb_logout_sid(struct iscsi_cls_session *cls_sess)
+{
+ struct iscsi_session *sess;
+ struct ddb_entry *ddb_entry = NULL;
+ struct scsi_qla_host *ha;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ unsigned long flags;
+ unsigned long wtime;
+ uint32_t ddb_state;
+ int options;
+ int ret = 0;
+
+ sess = cls_sess->dd_data;
+ ddb_entry = sess->dd_data;
+ ha = ddb_entry->ha;
+
+ if (ddb_entry->ddb_type != FLASH_DDB) {
+ ql4_printk(KERN_ERR, ha, "%s: Not a flash node session\n",
+ __func__);
+ ret = -ENXIO;
+ goto exit_ddb_logout;
+ }
+
+ if (test_bit(DF_BOOT_TGT, &ddb_entry->flags)) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Logout from boot target entry is not permitted.\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ options = LOGOUT_OPTION_CLOSE_SESSION;
+ if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) {
+ ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
+ ret = -EIO;
+ goto exit_ddb_logout;
+ }
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ wtime = jiffies + (HZ * LOGOUT_TOV);
+ do {
+ ret = qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index,
+ fw_ddb_entry, fw_ddb_entry_dma,
+ NULL, NULL, &ddb_state, NULL,
+ NULL, NULL);
+ if (ret == QLA_ERROR)
+ goto ddb_logout_clr_sess;
+
+ if ((ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) ||
+ (ddb_state == DDB_DS_SESSION_FAILED))
+ goto ddb_logout_clr_sess;
+
+ schedule_timeout_uninterruptible(HZ);
+ } while ((time_after(wtime, jiffies)));
+
+ddb_logout_clr_sess:
+ qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+ /*
+ * we have decremented the reference count of the driver
+ * when we setup the session to have the driver unload
+ * to be seamless without actually destroying the
+ * session
+ **/
+ try_module_get(qla4xxx_iscsi_transport.owner);
+ iscsi_destroy_endpoint(ddb_entry->conn->ep);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ qla4xxx_free_ddb(ha, ddb_entry);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ iscsi_session_teardown(ddb_entry->sess);
+
+ ret = QLA_SUCCESS;
+
+exit_ddb_logout:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_logout - Logout from the specified target
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ *
+ * This performs log out from the specified target
+ **/
+static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct ql4_tuple_ddb *flash_tddb = NULL;
+ struct ql4_tuple_ddb *tmp_tddb = NULL;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ struct ddb_entry *ddb_entry = NULL;
+ dma_addr_t fw_ddb_dma;
+ uint32_t next_idx = 0;
+ uint32_t state = 0, conn_err = 0;
+ uint16_t conn_id = 0;
+ int idx, index;
+ int status, ret = 0;
+
+ fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL,
+ &fw_ddb_dma);
+ if (fw_ddb_entry == NULL) {
+ ql4_printk(KERN_ERR, ha, "%s:Out of memory\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ flash_tddb = vzalloc(sizeof(*flash_tddb));
+ if (!flash_tddb) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s:Memory Allocation failed.\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ tmp_tddb = vzalloc(sizeof(*tmp_tddb));
+ if (!tmp_tddb) {
+ ql4_printk(KERN_WARNING, ha,
+ "%s:Memory Allocation failed.\n", __func__);
+ ret = -ENOMEM;
+ goto exit_ddb_logout;
+ }
+
+ if (!fnode_sess->targetname) {
+ ql4_printk(KERN_ERR, ha,
+ "%s:Cannot logout from SendTarget entry\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ if (fnode_sess->is_boot_target) {
+ ql4_printk(KERN_ERR, ha,
+ "%s: Logout from boot target entry is not permitted.\n",
+ __func__);
+ ret = -EPERM;
+ goto exit_ddb_logout;
+ }
+
+ strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
+ ISCSI_NAME_SIZE);
+
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ sprintf(flash_tddb->ip_addr, "%pI6", fnode_conn->ipaddress);
+ else
+ sprintf(flash_tddb->ip_addr, "%pI4", fnode_conn->ipaddress);
+
+ flash_tddb->tpgt = fnode_sess->tpgt;
+ flash_tddb->port = fnode_conn->port;
+
+ COPY_ISID(flash_tddb->isid, fnode_sess->isid);
+
+ for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) {
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx);
+ if (ddb_entry == NULL)
+ continue;
+
+ if (ddb_entry->ddb_type != FLASH_DDB)
+ continue;
+
+ index = ddb_entry->sess->target_id;
+ status = qla4xxx_get_fwddb_entry(ha, index, fw_ddb_entry,
+ fw_ddb_dma, NULL, &next_idx,
+ &state, &conn_err, NULL,
+ &conn_id);
+ if (status == QLA_ERROR) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ qla4xxx_convert_param_ddb(fw_ddb_entry, tmp_tddb, NULL);
+
+ status = qla4xxx_compare_tuple_ddb(ha, flash_tddb, tmp_tddb,
+ true);
+ if (status == QLA_SUCCESS) {
+ ret = qla4xxx_sysfs_ddb_logout_sid(ddb_entry->sess);
+ break;
+ }
+ }
+
+ if (idx == MAX_DDB_ENTRIES)
+ ret = -ESRCH;
+
+exit_ddb_logout:
+ if (flash_tddb)
+ vfree(flash_tddb);
+ if (tmp_tddb)
+ vfree(tmp_tddb);
+ if (fw_ddb_entry)
+ dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma);
+
+ return ret;
+}
+
+static int
+qla4xxx_sysfs_ddb_get_param(struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct ql4_chap_table chap_tbl;
+ struct device *dev;
+ int parent_type, parent_index = 0xffff;
+ int rc = 0;
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev)
+ return -EIO;
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ switch (param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ rc = sprintf(buf, "%u\n", fnode_conn->is_fw_assigned_ipv6);
+ break;
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ rc = sprintf(buf, "%s\n", fnode_sess->portal_type);
+ break;
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_sess->auto_snd_tgt_disable);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_sess);
+ break;
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->entry_state);
+ break;
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->hdrdgst_en);
+ break;
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->datadgst_en);
+ break;
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->imm_data_en);
+ break;
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->initial_r2t_en);
+ break;
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ rc = sprintf(buf, "%u\n", fnode_sess->dataseq_inorder_en);
+ break;
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ rc = sprintf(buf, "%u\n", fnode_sess->pdu_inorder_en);
+ break;
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_auth_en);
+ break;
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->snack_req_en);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_logout_en);
+ break;
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ rc = sprintf(buf, "%u\n", fnode_sess->bidi_chap_en);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ rc = sprintf(buf, "%u\n", fnode_sess->discovery_auth_optional);
+ break;
+ case ISCSI_FLASHNODE_ERL:
+ rc = sprintf(buf, "%u\n", fnode_sess->erl);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_stat);
+ break;
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_nagle_disable);
+ break;
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_wsf_disable);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timer_scale);
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_timestamp_en);
+ break;
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ rc = sprintf(buf, "%u\n", fnode_conn->fragment_disable);
+ break;
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_recv_dlength);
+ break;
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_xmit_dlength);
+ break;
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ rc = sprintf(buf, "%u\n", fnode_sess->first_burst);
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ rc = sprintf(buf, "%u\n", fnode_sess->time2wait);
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ rc = sprintf(buf, "%u\n", fnode_sess->time2retain);
+ break;
+ case ISCSI_FLASHNODE_MAX_R2T:
+ rc = sprintf(buf, "%u\n", fnode_sess->max_r2t);
+ break;
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ rc = sprintf(buf, "%u\n", fnode_conn->keepalive_timeout);
+ break;
+ case ISCSI_FLASHNODE_ISID:
+ rc = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+ fnode_sess->isid[0], fnode_sess->isid[1],
+ fnode_sess->isid[2], fnode_sess->isid[3],
+ fnode_sess->isid[4], fnode_sess->isid[5]);
+ break;
+ case ISCSI_FLASHNODE_TSID:
+ rc = sprintf(buf, "%u\n", fnode_sess->tsid);
+ break;
+ case ISCSI_FLASHNODE_PORT:
+ rc = sprintf(buf, "%d\n", fnode_conn->port);
+ break;
+ case ISCSI_FLASHNODE_MAX_BURST:
+ rc = sprintf(buf, "%u\n", fnode_sess->max_burst);
+ break;
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ rc = sprintf(buf, "%u\n",
+ fnode_sess->default_taskmgmt_timeout);
+ break;
+ case ISCSI_FLASHNODE_IPADDR:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n", fnode_conn->ipaddress);
+ else
+ rc = sprintf(buf, "%pI4\n", fnode_conn->ipaddress);
+ break;
+ case ISCSI_FLASHNODE_ALIAS:
+ if (fnode_sess->targetalias)
+ rc = sprintf(buf, "%s\n", fnode_sess->targetalias);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n",
+ fnode_conn->redirect_ipaddr);
+ else
+ rc = sprintf(buf, "%pI4\n",
+ fnode_conn->redirect_ipaddr);
+ break;
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ rc = sprintf(buf, "%u\n", fnode_conn->max_segment_size);
+ break;
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ rc = sprintf(buf, "%u\n", fnode_conn->local_port);
+ break;
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv4_tos);
+ break;
+ case ISCSI_FLASHNODE_IPV6_TC:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%u\n",
+ fnode_conn->ipv6_traffic_class);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ rc = sprintf(buf, "%u\n", fnode_conn->ipv6_flow_label);
+ break;
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
+ rc = sprintf(buf, "%pI6\n",
+ fnode_conn->link_local_ipv6_addr);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX:
+ if ((fnode_sess->discovery_parent_idx) >= 0 &&
+ (fnode_sess->discovery_parent_idx < MAX_DDB_ENTRIES))
+ parent_index = fnode_sess->discovery_parent_idx;
+
+ rc = sprintf(buf, "%u\n", parent_index);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ if (fnode_sess->discovery_parent_type == DDB_ISNS)
+ parent_type = ISCSI_DISC_PARENT_ISNS;
+ else if (fnode_sess->discovery_parent_type == DDB_NO_LINK)
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
+ else if (fnode_sess->discovery_parent_type >= 0 &&
+ fnode_sess->discovery_parent_type < MAX_DDB_ENTRIES)
+ parent_type = ISCSI_DISC_PARENT_SENDTGT;
+ else
+ parent_type = ISCSI_DISC_PARENT_UNKNOWN;
+
+ rc = sprintf(buf, "%s\n",
+ iscsi_get_discovery_parent_name(parent_type));
+ break;
+ case ISCSI_FLASHNODE_NAME:
+ if (fnode_sess->targetname)
+ rc = sprintf(buf, "%s\n", fnode_sess->targetname);
+ else
+ rc = sprintf(buf, "\n");
+ break;
+ case ISCSI_FLASHNODE_TPGT:
+ rc = sprintf(buf, "%u\n", fnode_sess->tpgt);
+ break;
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_xmit_wsf);
+ break;
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ rc = sprintf(buf, "%u\n", fnode_conn->tcp_recv_wsf);
+ break;
+ case ISCSI_FLASHNODE_CHAP_OUT_IDX:
+ rc = sprintf(buf, "%u\n", fnode_sess->chap_out_idx);
+ break;
+ case ISCSI_FLASHNODE_USERNAME:
+ if (fnode_sess->chap_auth_en) {
+ qla4xxx_get_uni_chap_at_index(ha,
+ chap_tbl.name,
+ chap_tbl.secret,
+ fnode_sess->chap_out_idx);
+ rc = sprintf(buf, "%s\n", chap_tbl.name);
+ } else {
+ rc = sprintf(buf, "\n");
+ }
+ break;
+ case ISCSI_FLASHNODE_PASSWORD:
+ if (fnode_sess->chap_auth_en) {
+ qla4xxx_get_uni_chap_at_index(ha,
+ chap_tbl.name,
+ chap_tbl.secret,
+ fnode_sess->chap_out_idx);
+ rc = sprintf(buf, "%s\n", chap_tbl.secret);
+ } else {
+ rc = sprintf(buf, "\n");
+ }
+ break;
+ case ISCSI_FLASHNODE_STATSN:
+ rc = sprintf(buf, "%u\n", fnode_conn->statsn);
+ break;
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ rc = sprintf(buf, "%u\n", fnode_conn->exp_statsn);
+ break;
+ case ISCSI_FLASHNODE_IS_BOOT_TGT:
+ rc = sprintf(buf, "%u\n", fnode_sess->is_boot_target);
+ break;
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_set_param - Set parameter for firmware DDB entry
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ * @fnode_conn: pointer to connection attrs of flash ddb entry
+ * @data: Parameters and their values to update
+ * @len: len of data
+ *
+ * This sets the parameter of flash ddb entry and writes them to flash
+ **/
+static int
+qla4xxx_sysfs_ddb_set_param(struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ struct iscsi_flashnode_param_info *fnode_param;
+ struct nlattr *attr;
+ int rc = QLA_ERROR;
+ uint32_t rem = len;
+
+ fw_ddb_entry = kzalloc(sizeof(*fw_ddb_entry), GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate ddb buffer\n",
+ __func__));
+ return -ENOMEM;
+ }
+
+ nla_for_each_attr(attr, data, len, rem) {
+ fnode_param = nla_data(attr);
+
+ switch (fnode_param->param) {
+ case ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6:
+ fnode_conn->is_fw_assigned_ipv6 = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_PORTAL_TYPE:
+ memcpy(fnode_sess->portal_type, fnode_param->value,
+ strlen(fnode_sess->portal_type));
+ break;
+ case ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE:
+ fnode_sess->auto_snd_tgt_disable =
+ fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_SESS:
+ fnode_sess->discovery_sess = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_ENTRY_EN:
+ fnode_sess->entry_state = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_HDR_DGST_EN:
+ fnode_conn->hdrdgst_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DATA_DGST_EN:
+ fnode_conn->datadgst_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IMM_DATA_EN:
+ fnode_sess->imm_data_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_INITIAL_R2T_EN:
+ fnode_sess->initial_r2t_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DATASEQ_INORDER:
+ fnode_sess->dataseq_inorder_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_PDU_INORDER:
+ fnode_sess->pdu_inorder_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_CHAP_AUTH_EN:
+ fnode_sess->chap_auth_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_SNACK_REQ_EN:
+ fnode_conn->snack_req_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN:
+ fnode_sess->discovery_logout_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_BIDI_CHAP_EN:
+ fnode_sess->bidi_chap_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL:
+ fnode_sess->discovery_auth_optional =
+ fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_ERL:
+ fnode_sess->erl = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT:
+ fnode_conn->tcp_timestamp_stat = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_NAGLE_DISABLE:
+ fnode_conn->tcp_nagle_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_WSF_DISABLE:
+ fnode_conn->tcp_wsf_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMER_SCALE:
+ fnode_conn->tcp_timer_scale = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_TCP_TIMESTAMP_EN:
+ fnode_conn->tcp_timestamp_en = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IP_FRAG_DISABLE:
+ fnode_conn->fragment_disable = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_MAX_RECV_DLENGTH:
+ fnode_conn->max_recv_dlength =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_XMIT_DLENGTH:
+ fnode_conn->max_xmit_dlength =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_FIRST_BURST:
+ fnode_sess->first_burst =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2WAIT:
+ fnode_sess->time2wait = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TIME2RETAIN:
+ fnode_sess->time2retain =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_R2T:
+ fnode_sess->max_r2t =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_KEEPALIVE_TMO:
+ fnode_conn->keepalive_timeout =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_ISID:
+ memcpy(fnode_sess->isid, fnode_param->value,
+ sizeof(fnode_sess->isid));
+ break;
+ case ISCSI_FLASHNODE_TSID:
+ fnode_sess->tsid = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_PORT:
+ fnode_conn->port = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_MAX_BURST:
+ fnode_sess->max_burst = *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_DEF_TASKMGMT_TMO:
+ fnode_sess->default_taskmgmt_timeout =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_IPADDR:
+ memcpy(fnode_conn->ipaddress, fnode_param->value,
+ IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_ALIAS:
+ rc = iscsi_switch_str_param(&fnode_sess->targetalias,
+ (char *)fnode_param->value);
+ break;
+ case ISCSI_FLASHNODE_REDIRECT_IPADDR:
+ memcpy(fnode_conn->redirect_ipaddr, fnode_param->value,
+ IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_MAX_SEGMENT_SIZE:
+ fnode_conn->max_segment_size =
+ *(unsigned *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_LOCAL_PORT:
+ fnode_conn->local_port =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_IPV4_TOS:
+ fnode_conn->ipv4_tos = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IPV6_TC:
+ fnode_conn->ipv6_traffic_class = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_IPV6_FLOW_LABEL:
+ fnode_conn->ipv6_flow_label = fnode_param->value[0];
+ break;
+ case ISCSI_FLASHNODE_NAME:
+ rc = iscsi_switch_str_param(&fnode_sess->targetname,
+ (char *)fnode_param->value);
+ break;
+ case ISCSI_FLASHNODE_TPGT:
+ fnode_sess->tpgt = *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_LINK_LOCAL_IPV6:
+ memcpy(fnode_conn->link_local_ipv6_addr,
+ fnode_param->value, IPv6_ADDR_LEN);
+ break;
+ case ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE:
+ fnode_sess->discovery_parent_type =
+ *(uint16_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_TCP_XMIT_WSF:
+ fnode_conn->tcp_xmit_wsf =
+ *(uint8_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_TCP_RECV_WSF:
+ fnode_conn->tcp_recv_wsf =
+ *(uint8_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_STATSN:
+ fnode_conn->statsn = *(uint32_t *)fnode_param->value;
+ break;
+ case ISCSI_FLASHNODE_EXP_STATSN:
+ fnode_conn->exp_statsn =
+ *(uint32_t *)fnode_param->value;
+ break;
+ default:
+ ql4_printk(KERN_ERR, ha,
+ "%s: No such sysfs attribute\n", __func__);
+ rc = -ENOSYS;
+ goto exit_set_param;
+ }
+ }
+
+ rc = qla4xxx_sysfs_ddb_apply(fnode_sess, fnode_conn);
+
+exit_set_param:
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_delete - Delete firmware DDB entry
+ * @fnode_sess: pointer to session attrs of flash ddb entry
+ *
+ * This invalidates the flash ddb entry at the given index
+ **/
+static int qla4xxx_sysfs_ddb_delete(struct iscsi_bus_flash_session *fnode_sess)
+{
+ struct Scsi_Host *shost = iscsi_flash_session_to_shost(fnode_sess);
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ uint32_t dev_db_start_offset;
+ uint32_t dev_db_end_offset;
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint16_t *ddb_cookie = NULL;
+ size_t ddb_size;
+ void *pddb = NULL;
+ int target_id;
+ int rc = 0;
+
+ if (!fnode_sess) {
+ rc = -EINVAL;
+ goto exit_ddb_del;
+ }
+
+ if (fnode_sess->is_boot_target) {
+ rc = -EPERM;
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Deletion of boot target entry is not permitted.\n",
+ __func__));
+ goto exit_ddb_del;
+ }
+
+ if (fnode_sess->flash_state == DEV_DB_NON_PERSISTENT)
+ goto sysfs_ddb_del;
+
+ if (is_qla40XX(ha)) {
+ dev_db_start_offset = FLASH_OFFSET_DB_INFO;
+ dev_db_end_offset = FLASH_OFFSET_DB_END;
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+ ddb_size = sizeof(*fw_ddb_entry);
+ } else {
+ dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
+ (ha->hw.flt_region_ddb << 2);
+ /* flt_ddb_size is DDB table size for both ports
+ * so divide it by 2 to calculate the offset for second port
+ */
+ if (ha->port_num == 1)
+ dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
+
+ dev_db_end_offset = dev_db_start_offset +
+ (ha->hw.flt_ddb_size / 2);
+
+ dev_db_start_offset += (fnode_sess->target_id *
+ sizeof(*fw_ddb_entry));
+ dev_db_start_offset += (void *)&(fw_ddb_entry->cookie) -
+ (void *)fw_ddb_entry;
+
+ ddb_size = sizeof(*ddb_cookie);
+ }
+
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s: start offset=%u, end offset=%u\n",
+ __func__, dev_db_start_offset, dev_db_end_offset));
+
+ if (dev_db_start_offset > dev_db_end_offset) {
+ rc = -EIO;
+ DEBUG2(ql4_printk(KERN_ERR, ha, "%s:Invalid DDB index %u\n",
+ __func__, fnode_sess->target_id));
+ goto exit_ddb_del;
+ }
+
+ pddb = dma_alloc_coherent(&ha->pdev->dev, ddb_size,
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!pddb) {
+ rc = -ENOMEM;
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ goto exit_ddb_del;
+ }
+
+ if (is_qla40XX(ha)) {
+ fw_ddb_entry = pddb;
+ memset(fw_ddb_entry, 0, ddb_size);
+ ddb_cookie = &fw_ddb_entry->cookie;
+ } else {
+ ddb_cookie = pddb;
+ }
+
+ /* invalidate the cookie */
+ *ddb_cookie = 0xFFEE;
+ qla4xxx_set_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
+ ddb_size, FLASH_OPT_RMW_COMMIT);
+
+sysfs_ddb_del:
+ target_id = fnode_sess->target_id;
+ iscsi_destroy_flashnode_sess(fnode_sess);
+ ql4_printk(KERN_INFO, ha,
+ "%s: session and conn entries for flashnode %u of host %lu deleted\n",
+ __func__, target_id, ha->host_no);
+exit_ddb_del:
+ if (pddb)
+ dma_free_coherent(&ha->pdev->dev, ddb_size, pddb,
+ fw_ddb_entry_dma);
+ return rc;
+}
+
+/**
+ * qla4xxx_sysfs_ddb_export - Create sysfs entries for firmware DDBs
+ * @ha: pointer to adapter structure
+ *
+ * Export the firmware DDB for all send targets and normal targets to sysfs.
+ **/
+static int qla4xxx_sysfs_ddb_export(struct scsi_qla_host *ha)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ uint16_t max_ddbs;
+ uint16_t idx = 0;
+ int ret = QLA_SUCCESS;
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(ql4_printk(KERN_ERR, ha,
+ "%s: Unable to allocate dma buffer\n",
+ __func__));
+ return -ENOMEM;
+ }
+
+ max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES :
+ MAX_DEV_DB_ENTRIES;
+
+ for (idx = 0; idx < max_ddbs; idx++) {
+ if (qla4xxx_flashdb_by_index(ha, fw_ddb_entry, fw_ddb_entry_dma,
+ idx))
+ continue;
+
+ ret = qla4xxx_sysfs_ddb_tgt_create(ha, fw_ddb_entry, &idx, 0);
+ if (ret) {
+ ret = -EIO;
+ break;
+ }
+ }
+
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+ fw_ddb_entry_dma);
+
+ return ret;
+}
+
+static void qla4xxx_sysfs_ddb_remove(struct scsi_qla_host *ha)
+{
+ iscsi_destroy_all_flashnode(ha->host);
+}
+
/**
* qla4xxx_build_ddb_list - Build ddb list and setup sessions
* @ha: pointer to adapter structure
@@ -5341,8 +7016,11 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER);
/* Dont retry adapter initialization if IRQ allocation failed */
- if (!test_bit(AF_IRQ_ATTACHED, &ha->flags))
+ if (is_qla80XX(ha) && !test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
+ ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization\n",
+ __func__);
goto skip_retry_init;
+ }
while ((!test_bit(AF_ONLINE, &ha->flags)) &&
init_retry_count++ < MAX_INIT_RETRIES) {
@@ -5445,6 +7123,10 @@ skip_retry_init:
ql4_printk(KERN_ERR, ha,
"%s: No iSCSI boot target configured\n", __func__);
+ if (qla4xxx_sysfs_ddb_export(ha))
+ ql4_printk(KERN_ERR, ha,
+ "%s: Error exporting ddb to sysfs\n", __func__);
+
/* Perform the build ddb list and login to each */
qla4xxx_build_ddb_list(ha, INIT_ADAPTER);
iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb);
@@ -5570,6 +7252,7 @@ static void qla4xxx_remove_adapter(struct pci_dev *pdev)
qla4xxx_destroy_fw_ddb_session(ha);
qla4_8xxx_free_sysfs_attr(ha);
+ qla4xxx_sysfs_ddb_remove(ha);
scsi_remove_host(ha->host);
qla4xxx_free_adapter(ha);
@@ -5669,7 +7352,6 @@ struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
/* update counters */
if (srb->flags & SRB_DMA_VALID) {
- ha->req_q_count += srb->iocb_cnt;
ha->iocb_cnt -= srb->iocb_cnt;
if (srb->cmd)
srb->cmd->host_scribble =
@@ -6081,6 +7763,7 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
{
struct scsi_qla_host *ha = to_qla_host(shost);
int rval = QLA_SUCCESS;
+ uint32_t idc_ctrl;
if (ql4xdontresethba) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n",
@@ -6111,6 +7794,14 @@ static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type)
}
recover_adapter:
+ /* For ISP83XX set graceful reset bit in IDC_DRV_CTRL if
+ * reset is issued by application */
+ if (is_qla8032(ha) && test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ idc_ctrl = qla4_83xx_rd_reg(ha, QLA83XX_IDC_DRV_CTRL);
+ qla4_83xx_wr_reg(ha, QLA83XX_IDC_DRV_CTRL,
+ (idc_ctrl | GRACEFUL_RESET_BIT1));
+ }
+
rval = qla4xxx_recover_adapter(ha);
if (rval != QLA_SUCCESS) {
DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n",
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index 6775a45af315..83e0fec35d56 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,4 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.03.00-k4"
+#define QLA4XXX_DRIVER_VERSION "5.03.00-k8"
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 65123a21b97e..fe30ea94ffe6 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -50,7 +50,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
u32 rlen;
int err, tport;
- while (skb->len >= NLMSG_SPACE(0)) {
+ while (skb->len >= NLMSG_HDRLEN) {
err = 0;
nlh = nlmsg_hdr(skb);
@@ -70,7 +70,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
goto next_msg;
}
- hdr = NLMSG_DATA(nlh);
+ hdr = nlmsg_data(nlh);
if ((hdr->version != SCSI_NL_VERSION) ||
(hdr->magic != SCSI_NL_MAGIC)) {
err = -EPROTOTYPE;
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index e894ca7b54c0..e106c276aa00 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -35,7 +35,6 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
-#include <linux/netlink.h>
#include <net/netlink.h>
#include <scsi/scsi_netlink_fc.h>
#include <scsi/scsi_bsg_fc.h>
@@ -534,7 +533,7 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
struct nlmsghdr *nlh;
struct fc_nl_event *event;
const char *name;
- u32 len, skblen;
+ u32 len;
int err;
if (!scsi_nl_sock) {
@@ -543,21 +542,19 @@ fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
}
len = FC_NL_MSGALIGN(sizeof(*event));
- skblen = NLMSG_SPACE(len);
- skb = alloc_skb(skblen, GFP_KERNEL);
+ skb = nlmsg_new(len, GFP_KERNEL);
if (!skb) {
err = -ENOBUFS;
goto send_fail;
}
- nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
- skblen - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0);
if (!nlh) {
err = -ENOBUFS;
goto send_fail_skb;
}
- event = NLMSG_DATA(nlh);
+ event = nlmsg_data(nlh);
INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
FC_NL_ASYNC_EVENT, len);
@@ -604,7 +601,7 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct fc_nl_event *event;
- u32 len, skblen;
+ u32 len;
int err;
if (!scsi_nl_sock) {
@@ -613,21 +610,19 @@ fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
}
len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
- skblen = NLMSG_SPACE(len);
- skb = alloc_skb(skblen, GFP_KERNEL);
+ skb = nlmsg_new(len, GFP_KERNEL);
if (!skb) {
err = -ENOBUFS;
goto send_vendor_fail;
}
- nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
- skblen - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0);
if (!nlh) {
err = -ENOBUFS;
goto send_vendor_fail_skb;
}
- event = NLMSG_DATA(nlh);
+ event = nlmsg_data(nlh);
INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
FC_NL_ASYNC_EVENT, len);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 0a74b975efdf..47799a33d6ca 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/bsg-lib.h>
#include <linux/idr.h>
+#include <linux/list.h>
#include <net/tcp.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
@@ -460,6 +461,689 @@ void iscsi_destroy_iface(struct iscsi_iface *iface)
EXPORT_SYMBOL_GPL(iscsi_destroy_iface);
/*
+ * Interface to display flash node params to sysfs
+ */
+
+#define ISCSI_FLASHNODE_ATTR(_prefix, _name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_prefix##_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+/* flash node session attrs show */
+#define iscsi_flashnode_sess_attr_show(type, name, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct iscsi_bus_flash_session *fnode_sess = \
+ iscsi_dev_to_flash_session(dev);\
+ struct iscsi_transport *t = fnode_sess->transport; \
+ return t->get_flashnode_param(fnode_sess, param, buf); \
+} \
+
+
+#define iscsi_flashnode_sess_attr(type, name, param) \
+ iscsi_flashnode_sess_attr_show(type, name, param) \
+static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
+ show_##type##_##name, NULL);
+
+/* Flash node session attributes */
+
+iscsi_flashnode_sess_attr(fnode, auto_snd_tgt_disable,
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE);
+iscsi_flashnode_sess_attr(fnode, discovery_session,
+ ISCSI_FLASHNODE_DISCOVERY_SESS);
+iscsi_flashnode_sess_attr(fnode, portal_type, ISCSI_FLASHNODE_PORTAL_TYPE);
+iscsi_flashnode_sess_attr(fnode, entry_enable, ISCSI_FLASHNODE_ENTRY_EN);
+iscsi_flashnode_sess_attr(fnode, immediate_data, ISCSI_FLASHNODE_IMM_DATA_EN);
+iscsi_flashnode_sess_attr(fnode, initial_r2t, ISCSI_FLASHNODE_INITIAL_R2T_EN);
+iscsi_flashnode_sess_attr(fnode, data_seq_in_order,
+ ISCSI_FLASHNODE_DATASEQ_INORDER);
+iscsi_flashnode_sess_attr(fnode, data_pdu_in_order,
+ ISCSI_FLASHNODE_PDU_INORDER);
+iscsi_flashnode_sess_attr(fnode, chap_auth, ISCSI_FLASHNODE_CHAP_AUTH_EN);
+iscsi_flashnode_sess_attr(fnode, discovery_logout,
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN);
+iscsi_flashnode_sess_attr(fnode, bidi_chap, ISCSI_FLASHNODE_BIDI_CHAP_EN);
+iscsi_flashnode_sess_attr(fnode, discovery_auth_optional,
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL);
+iscsi_flashnode_sess_attr(fnode, erl, ISCSI_FLASHNODE_ERL);
+iscsi_flashnode_sess_attr(fnode, first_burst_len, ISCSI_FLASHNODE_FIRST_BURST);
+iscsi_flashnode_sess_attr(fnode, def_time2wait, ISCSI_FLASHNODE_DEF_TIME2WAIT);
+iscsi_flashnode_sess_attr(fnode, def_time2retain,
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN);
+iscsi_flashnode_sess_attr(fnode, max_outstanding_r2t, ISCSI_FLASHNODE_MAX_R2T);
+iscsi_flashnode_sess_attr(fnode, isid, ISCSI_FLASHNODE_ISID);
+iscsi_flashnode_sess_attr(fnode, tsid, ISCSI_FLASHNODE_TSID);
+iscsi_flashnode_sess_attr(fnode, max_burst_len, ISCSI_FLASHNODE_MAX_BURST);
+iscsi_flashnode_sess_attr(fnode, def_taskmgmt_tmo,
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO);
+iscsi_flashnode_sess_attr(fnode, targetalias, ISCSI_FLASHNODE_ALIAS);
+iscsi_flashnode_sess_attr(fnode, targetname, ISCSI_FLASHNODE_NAME);
+iscsi_flashnode_sess_attr(fnode, tpgt, ISCSI_FLASHNODE_TPGT);
+iscsi_flashnode_sess_attr(fnode, discovery_parent_idx,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX);
+iscsi_flashnode_sess_attr(fnode, discovery_parent_type,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE);
+iscsi_flashnode_sess_attr(fnode, chap_in_idx, ISCSI_FLASHNODE_CHAP_IN_IDX);
+iscsi_flashnode_sess_attr(fnode, chap_out_idx, ISCSI_FLASHNODE_CHAP_OUT_IDX);
+iscsi_flashnode_sess_attr(fnode, username, ISCSI_FLASHNODE_USERNAME);
+iscsi_flashnode_sess_attr(fnode, username_in, ISCSI_FLASHNODE_USERNAME_IN);
+iscsi_flashnode_sess_attr(fnode, password, ISCSI_FLASHNODE_PASSWORD);
+iscsi_flashnode_sess_attr(fnode, password_in, ISCSI_FLASHNODE_PASSWORD_IN);
+iscsi_flashnode_sess_attr(fnode, is_boot_target, ISCSI_FLASHNODE_IS_BOOT_TGT);
+
+static struct attribute *iscsi_flashnode_sess_attrs[] = {
+ &dev_attr_fnode_auto_snd_tgt_disable.attr,
+ &dev_attr_fnode_discovery_session.attr,
+ &dev_attr_fnode_portal_type.attr,
+ &dev_attr_fnode_entry_enable.attr,
+ &dev_attr_fnode_immediate_data.attr,
+ &dev_attr_fnode_initial_r2t.attr,
+ &dev_attr_fnode_data_seq_in_order.attr,
+ &dev_attr_fnode_data_pdu_in_order.attr,
+ &dev_attr_fnode_chap_auth.attr,
+ &dev_attr_fnode_discovery_logout.attr,
+ &dev_attr_fnode_bidi_chap.attr,
+ &dev_attr_fnode_discovery_auth_optional.attr,
+ &dev_attr_fnode_erl.attr,
+ &dev_attr_fnode_first_burst_len.attr,
+ &dev_attr_fnode_def_time2wait.attr,
+ &dev_attr_fnode_def_time2retain.attr,
+ &dev_attr_fnode_max_outstanding_r2t.attr,
+ &dev_attr_fnode_isid.attr,
+ &dev_attr_fnode_tsid.attr,
+ &dev_attr_fnode_max_burst_len.attr,
+ &dev_attr_fnode_def_taskmgmt_tmo.attr,
+ &dev_attr_fnode_targetalias.attr,
+ &dev_attr_fnode_targetname.attr,
+ &dev_attr_fnode_tpgt.attr,
+ &dev_attr_fnode_discovery_parent_idx.attr,
+ &dev_attr_fnode_discovery_parent_type.attr,
+ &dev_attr_fnode_chap_in_idx.attr,
+ &dev_attr_fnode_chap_out_idx.attr,
+ &dev_attr_fnode_username.attr,
+ &dev_attr_fnode_username_in.attr,
+ &dev_attr_fnode_password.attr,
+ &dev_attr_fnode_password_in.attr,
+ &dev_attr_fnode_is_boot_target.attr,
+ NULL,
+};
+
+static umode_t iscsi_flashnode_sess_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_bus_flash_session *fnode_sess =
+ iscsi_dev_to_flash_session(dev);
+ struct iscsi_transport *t = fnode_sess->transport;
+ int param;
+
+ if (attr == &dev_attr_fnode_auto_snd_tgt_disable.attr) {
+ param = ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE;
+ } else if (attr == &dev_attr_fnode_discovery_session.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_SESS;
+ } else if (attr == &dev_attr_fnode_portal_type.attr) {
+ param = ISCSI_FLASHNODE_PORTAL_TYPE;
+ } else if (attr == &dev_attr_fnode_entry_enable.attr) {
+ param = ISCSI_FLASHNODE_ENTRY_EN;
+ } else if (attr == &dev_attr_fnode_immediate_data.attr) {
+ param = ISCSI_FLASHNODE_IMM_DATA_EN;
+ } else if (attr == &dev_attr_fnode_initial_r2t.attr) {
+ param = ISCSI_FLASHNODE_INITIAL_R2T_EN;
+ } else if (attr == &dev_attr_fnode_data_seq_in_order.attr) {
+ param = ISCSI_FLASHNODE_DATASEQ_INORDER;
+ } else if (attr == &dev_attr_fnode_data_pdu_in_order.attr) {
+ param = ISCSI_FLASHNODE_PDU_INORDER;
+ } else if (attr == &dev_attr_fnode_chap_auth.attr) {
+ param = ISCSI_FLASHNODE_CHAP_AUTH_EN;
+ } else if (attr == &dev_attr_fnode_discovery_logout.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN;
+ } else if (attr == &dev_attr_fnode_bidi_chap.attr) {
+ param = ISCSI_FLASHNODE_BIDI_CHAP_EN;
+ } else if (attr == &dev_attr_fnode_discovery_auth_optional.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL;
+ } else if (attr == &dev_attr_fnode_erl.attr) {
+ param = ISCSI_FLASHNODE_ERL;
+ } else if (attr == &dev_attr_fnode_first_burst_len.attr) {
+ param = ISCSI_FLASHNODE_FIRST_BURST;
+ } else if (attr == &dev_attr_fnode_def_time2wait.attr) {
+ param = ISCSI_FLASHNODE_DEF_TIME2WAIT;
+ } else if (attr == &dev_attr_fnode_def_time2retain.attr) {
+ param = ISCSI_FLASHNODE_DEF_TIME2RETAIN;
+ } else if (attr == &dev_attr_fnode_max_outstanding_r2t.attr) {
+ param = ISCSI_FLASHNODE_MAX_R2T;
+ } else if (attr == &dev_attr_fnode_isid.attr) {
+ param = ISCSI_FLASHNODE_ISID;
+ } else if (attr == &dev_attr_fnode_tsid.attr) {
+ param = ISCSI_FLASHNODE_TSID;
+ } else if (attr == &dev_attr_fnode_max_burst_len.attr) {
+ param = ISCSI_FLASHNODE_MAX_BURST;
+ } else if (attr == &dev_attr_fnode_def_taskmgmt_tmo.attr) {
+ param = ISCSI_FLASHNODE_DEF_TASKMGMT_TMO;
+ } else if (attr == &dev_attr_fnode_targetalias.attr) {
+ param = ISCSI_FLASHNODE_ALIAS;
+ } else if (attr == &dev_attr_fnode_targetname.attr) {
+ param = ISCSI_FLASHNODE_NAME;
+ } else if (attr == &dev_attr_fnode_tpgt.attr) {
+ param = ISCSI_FLASHNODE_TPGT;
+ } else if (attr == &dev_attr_fnode_discovery_parent_idx.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX;
+ } else if (attr == &dev_attr_fnode_discovery_parent_type.attr) {
+ param = ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE;
+ } else if (attr == &dev_attr_fnode_chap_in_idx.attr) {
+ param = ISCSI_FLASHNODE_CHAP_IN_IDX;
+ } else if (attr == &dev_attr_fnode_chap_out_idx.attr) {
+ param = ISCSI_FLASHNODE_CHAP_OUT_IDX;
+ } else if (attr == &dev_attr_fnode_username.attr) {
+ param = ISCSI_FLASHNODE_USERNAME;
+ } else if (attr == &dev_attr_fnode_username_in.attr) {
+ param = ISCSI_FLASHNODE_USERNAME_IN;
+ } else if (attr == &dev_attr_fnode_password.attr) {
+ param = ISCSI_FLASHNODE_PASSWORD;
+ } else if (attr == &dev_attr_fnode_password_in.attr) {
+ param = ISCSI_FLASHNODE_PASSWORD_IN;
+ } else if (attr == &dev_attr_fnode_is_boot_target.attr) {
+ param = ISCSI_FLASHNODE_IS_BOOT_TGT;
+ } else {
+ WARN_ONCE(1, "Invalid flashnode session attr");
+ return 0;
+ }
+
+ return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
+}
+
+static struct attribute_group iscsi_flashnode_sess_attr_group = {
+ .attrs = iscsi_flashnode_sess_attrs,
+ .is_visible = iscsi_flashnode_sess_attr_is_visible,
+};
+
+static const struct attribute_group *iscsi_flashnode_sess_attr_groups[] = {
+ &iscsi_flashnode_sess_attr_group,
+ NULL,
+};
+
+static void iscsi_flashnode_sess_release(struct device *dev)
+{
+ struct iscsi_bus_flash_session *fnode_sess =
+ iscsi_dev_to_flash_session(dev);
+
+ kfree(fnode_sess->targetname);
+ kfree(fnode_sess->targetalias);
+ kfree(fnode_sess->portal_type);
+ kfree(fnode_sess);
+}
+
+struct device_type iscsi_flashnode_sess_dev_type = {
+ .name = "iscsi_flashnode_sess_dev_type",
+ .groups = iscsi_flashnode_sess_attr_groups,
+ .release = iscsi_flashnode_sess_release,
+};
+
+/* flash node connection attrs show */
+#define iscsi_flashnode_conn_attr_show(type, name, param) \
+static ssize_t \
+show_##type##_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);\
+ struct iscsi_bus_flash_session *fnode_sess = \
+ iscsi_flash_conn_to_flash_session(fnode_conn);\
+ struct iscsi_transport *t = fnode_conn->transport; \
+ return t->get_flashnode_param(fnode_sess, param, buf); \
+} \
+
+
+#define iscsi_flashnode_conn_attr(type, name, param) \
+ iscsi_flashnode_conn_attr_show(type, name, param) \
+static ISCSI_FLASHNODE_ATTR(type, name, S_IRUGO, \
+ show_##type##_##name, NULL);
+
+/* Flash node connection attributes */
+
+iscsi_flashnode_conn_attr(fnode, is_fw_assigned_ipv6,
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6);
+iscsi_flashnode_conn_attr(fnode, header_digest, ISCSI_FLASHNODE_HDR_DGST_EN);
+iscsi_flashnode_conn_attr(fnode, data_digest, ISCSI_FLASHNODE_DATA_DGST_EN);
+iscsi_flashnode_conn_attr(fnode, snack_req, ISCSI_FLASHNODE_SNACK_REQ_EN);
+iscsi_flashnode_conn_attr(fnode, tcp_timestamp_stat,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT);
+iscsi_flashnode_conn_attr(fnode, tcp_nagle_disable,
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE);
+iscsi_flashnode_conn_attr(fnode, tcp_wsf_disable,
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE);
+iscsi_flashnode_conn_attr(fnode, tcp_timer_scale,
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE);
+iscsi_flashnode_conn_attr(fnode, tcp_timestamp_enable,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN);
+iscsi_flashnode_conn_attr(fnode, fragment_disable,
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE);
+iscsi_flashnode_conn_attr(fnode, keepalive_tmo, ISCSI_FLASHNODE_KEEPALIVE_TMO);
+iscsi_flashnode_conn_attr(fnode, port, ISCSI_FLASHNODE_PORT);
+iscsi_flashnode_conn_attr(fnode, ipaddress, ISCSI_FLASHNODE_IPADDR);
+iscsi_flashnode_conn_attr(fnode, max_recv_dlength,
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH);
+iscsi_flashnode_conn_attr(fnode, max_xmit_dlength,
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH);
+iscsi_flashnode_conn_attr(fnode, local_port, ISCSI_FLASHNODE_LOCAL_PORT);
+iscsi_flashnode_conn_attr(fnode, ipv4_tos, ISCSI_FLASHNODE_IPV4_TOS);
+iscsi_flashnode_conn_attr(fnode, ipv6_traffic_class, ISCSI_FLASHNODE_IPV6_TC);
+iscsi_flashnode_conn_attr(fnode, ipv6_flow_label,
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL);
+iscsi_flashnode_conn_attr(fnode, redirect_ipaddr,
+ ISCSI_FLASHNODE_REDIRECT_IPADDR);
+iscsi_flashnode_conn_attr(fnode, max_segment_size,
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE);
+iscsi_flashnode_conn_attr(fnode, link_local_ipv6,
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6);
+iscsi_flashnode_conn_attr(fnode, tcp_xmit_wsf, ISCSI_FLASHNODE_TCP_XMIT_WSF);
+iscsi_flashnode_conn_attr(fnode, tcp_recv_wsf, ISCSI_FLASHNODE_TCP_RECV_WSF);
+iscsi_flashnode_conn_attr(fnode, statsn, ISCSI_FLASHNODE_STATSN);
+iscsi_flashnode_conn_attr(fnode, exp_statsn, ISCSI_FLASHNODE_EXP_STATSN);
+
+static struct attribute *iscsi_flashnode_conn_attrs[] = {
+ &dev_attr_fnode_is_fw_assigned_ipv6.attr,
+ &dev_attr_fnode_header_digest.attr,
+ &dev_attr_fnode_data_digest.attr,
+ &dev_attr_fnode_snack_req.attr,
+ &dev_attr_fnode_tcp_timestamp_stat.attr,
+ &dev_attr_fnode_tcp_nagle_disable.attr,
+ &dev_attr_fnode_tcp_wsf_disable.attr,
+ &dev_attr_fnode_tcp_timer_scale.attr,
+ &dev_attr_fnode_tcp_timestamp_enable.attr,
+ &dev_attr_fnode_fragment_disable.attr,
+ &dev_attr_fnode_max_recv_dlength.attr,
+ &dev_attr_fnode_max_xmit_dlength.attr,
+ &dev_attr_fnode_keepalive_tmo.attr,
+ &dev_attr_fnode_port.attr,
+ &dev_attr_fnode_ipaddress.attr,
+ &dev_attr_fnode_redirect_ipaddr.attr,
+ &dev_attr_fnode_max_segment_size.attr,
+ &dev_attr_fnode_local_port.attr,
+ &dev_attr_fnode_ipv4_tos.attr,
+ &dev_attr_fnode_ipv6_traffic_class.attr,
+ &dev_attr_fnode_ipv6_flow_label.attr,
+ &dev_attr_fnode_link_local_ipv6.attr,
+ &dev_attr_fnode_tcp_xmit_wsf.attr,
+ &dev_attr_fnode_tcp_recv_wsf.attr,
+ &dev_attr_fnode_statsn.attr,
+ &dev_attr_fnode_exp_statsn.attr,
+ NULL,
+};
+
+static umode_t iscsi_flashnode_conn_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr,
+ int i)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
+ struct iscsi_transport *t = fnode_conn->transport;
+ int param;
+
+ if (attr == &dev_attr_fnode_is_fw_assigned_ipv6.attr) {
+ param = ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6;
+ } else if (attr == &dev_attr_fnode_header_digest.attr) {
+ param = ISCSI_FLASHNODE_HDR_DGST_EN;
+ } else if (attr == &dev_attr_fnode_data_digest.attr) {
+ param = ISCSI_FLASHNODE_DATA_DGST_EN;
+ } else if (attr == &dev_attr_fnode_snack_req.attr) {
+ param = ISCSI_FLASHNODE_SNACK_REQ_EN;
+ } else if (attr == &dev_attr_fnode_tcp_timestamp_stat.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT;
+ } else if (attr == &dev_attr_fnode_tcp_nagle_disable.attr) {
+ param = ISCSI_FLASHNODE_TCP_NAGLE_DISABLE;
+ } else if (attr == &dev_attr_fnode_tcp_wsf_disable.attr) {
+ param = ISCSI_FLASHNODE_TCP_WSF_DISABLE;
+ } else if (attr == &dev_attr_fnode_tcp_timer_scale.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMER_SCALE;
+ } else if (attr == &dev_attr_fnode_tcp_timestamp_enable.attr) {
+ param = ISCSI_FLASHNODE_TCP_TIMESTAMP_EN;
+ } else if (attr == &dev_attr_fnode_fragment_disable.attr) {
+ param = ISCSI_FLASHNODE_IP_FRAG_DISABLE;
+ } else if (attr == &dev_attr_fnode_max_recv_dlength.attr) {
+ param = ISCSI_FLASHNODE_MAX_RECV_DLENGTH;
+ } else if (attr == &dev_attr_fnode_max_xmit_dlength.attr) {
+ param = ISCSI_FLASHNODE_MAX_XMIT_DLENGTH;
+ } else if (attr == &dev_attr_fnode_keepalive_tmo.attr) {
+ param = ISCSI_FLASHNODE_KEEPALIVE_TMO;
+ } else if (attr == &dev_attr_fnode_port.attr) {
+ param = ISCSI_FLASHNODE_PORT;
+ } else if (attr == &dev_attr_fnode_ipaddress.attr) {
+ param = ISCSI_FLASHNODE_IPADDR;
+ } else if (attr == &dev_attr_fnode_redirect_ipaddr.attr) {
+ param = ISCSI_FLASHNODE_REDIRECT_IPADDR;
+ } else if (attr == &dev_attr_fnode_max_segment_size.attr) {
+ param = ISCSI_FLASHNODE_MAX_SEGMENT_SIZE;
+ } else if (attr == &dev_attr_fnode_local_port.attr) {
+ param = ISCSI_FLASHNODE_LOCAL_PORT;
+ } else if (attr == &dev_attr_fnode_ipv4_tos.attr) {
+ param = ISCSI_FLASHNODE_IPV4_TOS;
+ } else if (attr == &dev_attr_fnode_ipv6_traffic_class.attr) {
+ param = ISCSI_FLASHNODE_IPV6_TC;
+ } else if (attr == &dev_attr_fnode_ipv6_flow_label.attr) {
+ param = ISCSI_FLASHNODE_IPV6_FLOW_LABEL;
+ } else if (attr == &dev_attr_fnode_link_local_ipv6.attr) {
+ param = ISCSI_FLASHNODE_LINK_LOCAL_IPV6;
+ } else if (attr == &dev_attr_fnode_tcp_xmit_wsf.attr) {
+ param = ISCSI_FLASHNODE_TCP_XMIT_WSF;
+ } else if (attr == &dev_attr_fnode_tcp_recv_wsf.attr) {
+ param = ISCSI_FLASHNODE_TCP_RECV_WSF;
+ } else if (attr == &dev_attr_fnode_statsn.attr) {
+ param = ISCSI_FLASHNODE_STATSN;
+ } else if (attr == &dev_attr_fnode_exp_statsn.attr) {
+ param = ISCSI_FLASHNODE_EXP_STATSN;
+ } else {
+ WARN_ONCE(1, "Invalid flashnode connection attr");
+ return 0;
+ }
+
+ return t->attr_is_visible(ISCSI_FLASHNODE_PARAM, param);
+}
+
+static struct attribute_group iscsi_flashnode_conn_attr_group = {
+ .attrs = iscsi_flashnode_conn_attrs,
+ .is_visible = iscsi_flashnode_conn_attr_is_visible,
+};
+
+static const struct attribute_group *iscsi_flashnode_conn_attr_groups[] = {
+ &iscsi_flashnode_conn_attr_group,
+ NULL,
+};
+
+static void iscsi_flashnode_conn_release(struct device *dev)
+{
+ struct iscsi_bus_flash_conn *fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ kfree(fnode_conn->ipaddress);
+ kfree(fnode_conn->redirect_ipaddr);
+ kfree(fnode_conn->link_local_ipv6_addr);
+ kfree(fnode_conn);
+}
+
+struct device_type iscsi_flashnode_conn_dev_type = {
+ .name = "iscsi_flashnode_conn_dev_type",
+ .groups = iscsi_flashnode_conn_attr_groups,
+ .release = iscsi_flashnode_conn_release,
+};
+
+struct bus_type iscsi_flashnode_bus;
+
+int iscsi_flashnode_bus_match(struct device *dev,
+ struct device_driver *drv)
+{
+ if (dev->bus == &iscsi_flashnode_bus)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_flashnode_bus_match);
+
+struct bus_type iscsi_flashnode_bus = {
+ .name = "iscsi_flashnode",
+ .match = &iscsi_flashnode_bus_match,
+};
+
+/**
+ * iscsi_create_flashnode_sess - Add flashnode session entry in sysfs
+ * @shost: pointer to host data
+ * @index: index of flashnode to add in sysfs
+ * @transport: pointer to transport data
+ * @dd_size: total size to allocate
+ *
+ * Adds a sysfs entry for the flashnode session attributes
+ *
+ * Returns:
+ * pointer to allocated flashnode sess on sucess
+ * %NULL on failure
+ */
+struct iscsi_bus_flash_session *
+iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
+ struct iscsi_transport *transport,
+ int dd_size)
+{
+ struct iscsi_bus_flash_session *fnode_sess;
+ int err;
+
+ fnode_sess = kzalloc(sizeof(*fnode_sess) + dd_size, GFP_KERNEL);
+ if (!fnode_sess)
+ return NULL;
+
+ fnode_sess->transport = transport;
+ fnode_sess->target_id = index;
+ fnode_sess->dev.type = &iscsi_flashnode_sess_dev_type;
+ fnode_sess->dev.bus = &iscsi_flashnode_bus;
+ fnode_sess->dev.parent = &shost->shost_gendev;
+ dev_set_name(&fnode_sess->dev, "flashnode_sess-%u:%u",
+ shost->host_no, index);
+
+ err = device_register(&fnode_sess->dev);
+ if (err)
+ goto free_fnode_sess;
+
+ if (dd_size)
+ fnode_sess->dd_data = &fnode_sess[1];
+
+ return fnode_sess;
+
+free_fnode_sess:
+ kfree(fnode_sess);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_flashnode_sess);
+
+/**
+ * iscsi_create_flashnode_conn - Add flashnode conn entry in sysfs
+ * @shost: pointer to host data
+ * @fnode_sess: pointer to the parent flashnode session entry
+ * @transport: pointer to transport data
+ * @dd_size: total size to allocate
+ *
+ * Adds a sysfs entry for the flashnode connection attributes
+ *
+ * Returns:
+ * pointer to allocated flashnode conn on success
+ * %NULL on failure
+ */
+struct iscsi_bus_flash_conn *
+iscsi_create_flashnode_conn(struct Scsi_Host *shost,
+ struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_transport *transport,
+ int dd_size)
+{
+ struct iscsi_bus_flash_conn *fnode_conn;
+ int err;
+
+ fnode_conn = kzalloc(sizeof(*fnode_conn) + dd_size, GFP_KERNEL);
+ if (!fnode_conn)
+ return NULL;
+
+ fnode_conn->transport = transport;
+ fnode_conn->dev.type = &iscsi_flashnode_conn_dev_type;
+ fnode_conn->dev.bus = &iscsi_flashnode_bus;
+ fnode_conn->dev.parent = &fnode_sess->dev;
+ dev_set_name(&fnode_conn->dev, "flashnode_conn-%u:%u:0",
+ shost->host_no, fnode_sess->target_id);
+
+ err = device_register(&fnode_conn->dev);
+ if (err)
+ goto free_fnode_conn;
+
+ if (dd_size)
+ fnode_conn->dd_data = &fnode_conn[1];
+
+ return fnode_conn;
+
+free_fnode_conn:
+ kfree(fnode_conn);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_flashnode_conn);
+
+/**
+ * iscsi_is_flashnode_conn_dev - verify passed device is to be flashnode conn
+ * @dev: device to verify
+ * @data: pointer to data containing value to use for verification
+ *
+ * Verifies if the passed device is flashnode conn device
+ *
+ * Returns:
+ * 1 on success
+ * 0 on failure
+ */
+int iscsi_is_flashnode_conn_dev(struct device *dev, void *data)
+{
+ return dev->bus == &iscsi_flashnode_bus;
+}
+EXPORT_SYMBOL_GPL(iscsi_is_flashnode_conn_dev);
+
+static int iscsi_destroy_flashnode_conn(struct iscsi_bus_flash_conn *fnode_conn)
+{
+ device_unregister(&fnode_conn->dev);
+ return 0;
+}
+
+static int flashnode_match_index(struct device *dev, void *data)
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ int ret = 0;
+
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ goto exit_match_index;
+
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+ ret = (fnode_sess->target_id == *((int *)data)) ? 1 : 0;
+
+exit_match_index:
+ return ret;
+}
+
+/**
+ * iscsi_get_flashnode_by_index -finds flashnode session entry by index
+ * @shost: pointer to host data
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode session object for the passed index
+ *
+ * Returns:
+ * pointer to found flashnode session object on success
+ * %NULL on failure
+ */
+static struct iscsi_bus_flash_session *
+iscsi_get_flashnode_by_index(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct iscsi_bus_flash_session *fnode_sess = NULL;
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ if (dev)
+ fnode_sess = iscsi_dev_to_flash_session(dev);
+
+ return fnode_sess;
+}
+
+/**
+ * iscsi_find_flashnode_sess - finds flashnode session entry
+ * @shost: pointer to host data
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode session object comparing the data passed using logic
+ * defined in passed function pointer
+ *
+ * Returns:
+ * pointer to found flashnode session device object on success
+ * %NULL on failure
+ */
+struct device *
+iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+
+ dev = device_find_child(&shost->shost_gendev, data, fn);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(iscsi_find_flashnode_sess);
+
+/**
+ * iscsi_find_flashnode_conn - finds flashnode connection entry
+ * @fnode_sess: pointer to parent flashnode session entry
+ * @data: pointer to data containing value to use for comparison
+ * @fn: function pointer that does actual comparison
+ *
+ * Finds the flashnode connection object comparing the data passed using logic
+ * defined in passed function pointer
+ *
+ * Returns:
+ * pointer to found flashnode connection device object on success
+ * %NULL on failure
+ */
+struct device *
+iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess,
+ void *data,
+ int (*fn)(struct device *dev, void *data))
+{
+ struct device *dev;
+
+ dev = device_find_child(&fnode_sess->dev, data, fn);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(iscsi_find_flashnode_conn);
+
+static int iscsi_iter_destroy_flashnode_conn_fn(struct device *dev, void *data)
+{
+ if (!iscsi_is_flashnode_conn_dev(dev, NULL))
+ return 0;
+
+ return iscsi_destroy_flashnode_conn(iscsi_dev_to_flash_conn(dev));
+}
+
+/**
+ * iscsi_destroy_flashnode_sess - destory flashnode session entry
+ * @fnode_sess: pointer to flashnode session entry to be destroyed
+ *
+ * Deletes the flashnode session entry and all children flashnode connection
+ * entries from sysfs
+ */
+void iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess)
+{
+ int err;
+
+ err = device_for_each_child(&fnode_sess->dev, NULL,
+ iscsi_iter_destroy_flashnode_conn_fn);
+ if (err)
+ pr_err("Could not delete all connections for %s. Error %d.\n",
+ fnode_sess->dev.kobj.name, err);
+
+ device_unregister(&fnode_sess->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_flashnode_sess);
+
+static int iscsi_iter_destroy_flashnode_fn(struct device *dev, void *data)
+{
+ if (!iscsi_flashnode_bus_match(dev, NULL))
+ return 0;
+
+ iscsi_destroy_flashnode_sess(iscsi_dev_to_flash_session(dev));
+ return 0;
+}
+
+/**
+ * iscsi_destroy_all_flashnode - destory all flashnode session entries
+ * @shost: pointer to host data
+ *
+ * Destroys all the flashnode session entries and all corresponding children
+ * flashnode connection entries from sysfs
+ */
+void iscsi_destroy_all_flashnode(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL,
+ iscsi_iter_destroy_flashnode_fn);
+}
+EXPORT_SYMBOL_GPL(iscsi_destroy_all_flashnode);
+
+/*
* BSG support
*/
/**
@@ -1344,8 +2028,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_uevent *ev;
char *pdu;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
- data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + sizeof(struct iscsi_hdr) +
+ data_size);
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1360,7 +2044,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
memset(ev, 0, sizeof(*ev));
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_RECV_PDU;
@@ -1381,7 +2065,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_ATOMIC);
if (!skb) {
@@ -1390,7 +2074,7 @@ int iscsi_offload_mesg(struct Scsi_Host *shost,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
memset(ev, 0, sizeof(*ev));
ev->type = type;
ev->transport_handle = iscsi_handle(transport);
@@ -1415,7 +2099,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
struct sk_buff *skb;
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev));
+ int len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1429,7 +2113,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_CONN_ERROR;
ev->r.connerror.error = error;
@@ -1450,7 +2134,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
struct sk_buff *skb;
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev));
+ int len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -1464,7 +2148,7 @@ void iscsi_conn_login_event(struct iscsi_cls_conn *conn,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(conn->transport);
ev->type = ISCSI_KEVENT_CONN_LOGIN_STATE;
ev->r.conn_login.state = state;
@@ -1484,7 +2168,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_NOIO);
if (!skb) {
@@ -1494,7 +2178,7 @@ void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(transport);
ev->type = ISCSI_KEVENT_HOST_EVENT;
ev->r.host_event.host_no = host_no;
@@ -1515,7 +2199,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
struct nlmsghdr *nlh;
struct sk_buff *skb;
struct iscsi_uevent *ev;
- int len = NLMSG_SPACE(sizeof(*ev) + data_size);
+ int len = nlmsg_total_size(sizeof(*ev) + data_size);
skb = alloc_skb(len, GFP_NOIO);
if (!skb) {
@@ -1524,7 +2208,7 @@ void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(transport);
ev->type = ISCSI_KEVENT_PING_COMP;
ev->r.ping_comp.host_no = host_no;
@@ -1543,7 +2227,7 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
- int len = NLMSG_SPACE(size);
+ int len = nlmsg_total_size(size);
int flags = multi ? NLM_F_MULTI : 0;
int t = done ? NLMSG_DONE : type;
@@ -1555,24 +2239,24 @@ iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
nlh->nlmsg_flags = flags;
- memcpy(NLMSG_DATA(nlh), payload, size);
+ memcpy(nlmsg_data(nlh), payload, size);
return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
}
static int
iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
{
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct iscsi_stats *stats;
struct sk_buff *skbstat;
struct iscsi_cls_conn *conn;
struct nlmsghdr *nlhstat;
struct iscsi_uevent *evstat;
struct iscsi_internal *priv;
- int len = NLMSG_SPACE(sizeof(*ev) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- ISCSI_STATS_CUSTOM_MAX);
+ int len = nlmsg_total_size(sizeof(*ev) +
+ sizeof(struct iscsi_stats) +
+ sizeof(struct iscsi_stats_custom) *
+ ISCSI_STATS_CUSTOM_MAX);
int err = 0;
priv = iscsi_if_transport_lookup(transport);
@@ -1595,7 +2279,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
(len - sizeof(*nlhstat)), 0);
- evstat = NLMSG_DATA(nlhstat);
+ evstat = nlmsg_data(nlhstat);
memset(evstat, 0, sizeof(*evstat));
evstat->transport_handle = iscsi_handle(conn->transport);
evstat->type = nlh->nlmsg_type;
@@ -1608,12 +2292,12 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
memset(stats, 0, sizeof(*stats));
transport->get_stats(conn, stats);
- actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
- sizeof(struct iscsi_stats) +
- sizeof(struct iscsi_stats_custom) *
- stats->custom_length);
+ actual_size = nlmsg_total_size(sizeof(struct iscsi_uevent) +
+ sizeof(struct iscsi_stats) +
+ sizeof(struct iscsi_stats_custom) *
+ stats->custom_length);
actual_size -= sizeof(*nlhstat);
- actual_size = NLMSG_LENGTH(actual_size);
+ actual_size = nlmsg_msg_size(actual_size);
skb_trim(skbstat, NLMSG_ALIGN(actual_size));
nlhstat->nlmsg_len = actual_size;
@@ -1637,7 +2321,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
struct iscsi_uevent *ev;
struct sk_buff *skb;
struct nlmsghdr *nlh;
- int rc, len = NLMSG_SPACE(sizeof(*ev));
+ int rc, len = nlmsg_total_size(sizeof(*ev));
priv = iscsi_if_transport_lookup(session->transport);
if (!priv)
@@ -1653,7 +2337,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,
}
nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
ev->transport_handle = iscsi_handle(session->transport);
ev->type = event;
@@ -2005,7 +2689,7 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev)
static int
iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
{
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct Scsi_Host *shost = NULL;
struct iscsi_chap_rec *chap_rec;
struct iscsi_internal *priv;
@@ -2024,7 +2708,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
return -EINVAL;
chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
- len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+ len = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
shost = scsi_host_lookup(ev->u.get_chap.host_no);
if (!shost) {
@@ -2045,7 +2729,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
(len - sizeof(*nlhchap)), 0);
- evchap = NLMSG_DATA(nlhchap);
+ evchap = nlmsg_data(nlhchap);
memset(evchap, 0, sizeof(*evchap));
evchap->transport_handle = iscsi_handle(transport);
evchap->type = nlh->nlmsg_type;
@@ -2058,7 +2742,7 @@ iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
&evchap->u.get_chap.num_entries, buf);
- actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size);
+ actual_size = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
skb_trim(skbchap, NLMSG_ALIGN(actual_size));
nlhchap->nlmsg_len = actual_size;
@@ -2092,11 +2776,299 @@ static int iscsi_delete_chap(struct iscsi_transport *transport,
return err;
}
+static const struct {
+ enum iscsi_discovery_parent_type value;
+ char *name;
+} iscsi_discovery_parent_names[] = {
+ {ISCSI_DISC_PARENT_UNKNOWN, "Unknown" },
+ {ISCSI_DISC_PARENT_SENDTGT, "Sendtarget" },
+ {ISCSI_DISC_PARENT_ISNS, "isns" },
+};
+
+char *iscsi_get_discovery_parent_name(int parent_type)
+{
+ int i;
+ char *state = "Unknown!";
+
+ for (i = 0; i < ARRAY_SIZE(iscsi_discovery_parent_names); i++) {
+ if (iscsi_discovery_parent_names[i].value & parent_type) {
+ state = iscsi_discovery_parent_names[i].name;
+ break;
+ }
+ }
+ return state;
+}
+EXPORT_SYMBOL_GPL(iscsi_get_discovery_parent_name);
+
+static int iscsi_set_flashnode_param(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->set_flashnode_param) {
+ err = -ENOSYS;
+ goto exit_set_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.set_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.set_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.set_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.set_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+ err = transport->set_flashnode_param(fnode_sess, fnode_conn, data, len);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_set_fnode:
+ return err;
+}
+
+static int iscsi_new_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev, uint32_t len)
+{
+ char *data = (char *)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ int index;
+ int err = 0;
+
+ if (!transport->new_flashnode) {
+ err = -ENOSYS;
+ goto exit_new_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.new_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.new_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ index = transport->new_flashnode(shost, data, len);
+
+ if (index >= 0)
+ ev->r.new_flashnode_ret.flashnode_idx = index;
+ else
+ err = -EIO;
+
+put_host:
+ scsi_host_put(shost);
+
+exit_new_fnode:
+ return err;
+}
+
+static int iscsi_del_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->del_flashnode) {
+ err = -ENOSYS;
+ goto exit_del_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.del_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.del_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.del_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.del_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ err = transport->del_flashnode(fnode_sess);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_del_fnode:
+ return err;
+}
+
+static int iscsi_login_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->login_flashnode) {
+ err = -ENOSYS;
+ goto exit_login_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.login_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.login_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.login_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.login_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+ err = transport->login_flashnode(fnode_sess, fnode_conn);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_login_fnode:
+ return err;
+}
+
+static int iscsi_logout_flashnode(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_bus_flash_session *fnode_sess;
+ struct iscsi_bus_flash_conn *fnode_conn;
+ struct device *dev;
+ uint32_t *idx;
+ int err = 0;
+
+ if (!transport->logout_flashnode) {
+ err = -ENOSYS;
+ goto exit_logout_fnode;
+ }
+
+ shost = scsi_host_lookup(ev->u.logout_flashnode.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ idx = &ev->u.logout_flashnode.flashnode_idx;
+ fnode_sess = iscsi_get_flashnode_by_index(shost, idx,
+ flashnode_match_index);
+ if (!fnode_sess) {
+ pr_err("%s could not find flashnode %u for host no %u\n",
+ __func__, *idx, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ dev = iscsi_find_flashnode_conn(fnode_sess, NULL,
+ iscsi_is_flashnode_conn_dev);
+ if (!dev) {
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ fnode_conn = iscsi_dev_to_flash_conn(dev);
+
+ err = transport->logout_flashnode(fnode_sess, fnode_conn);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_logout_fnode:
+ return err;
+}
+
+static int iscsi_logout_flashnode_sid(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct Scsi_Host *shost;
+ struct iscsi_cls_session *session;
+ int err = 0;
+
+ if (!transport->logout_flashnode_sid) {
+ err = -ENOSYS;
+ goto exit_logout_sid;
+ }
+
+ shost = scsi_host_lookup(ev->u.logout_flashnode_sid.host_no);
+ if (!shost) {
+ pr_err("%s could not find host no %u\n",
+ __func__, ev->u.logout_flashnode.host_no);
+ err = -ENODEV;
+ goto put_host;
+ }
+
+ session = iscsi_session_lookup(ev->u.logout_flashnode_sid.sid);
+ if (!session) {
+ pr_err("%s could not find session id %u\n",
+ __func__, ev->u.logout_flashnode_sid.sid);
+ err = -EINVAL;
+ goto put_host;
+ }
+
+ err = transport->logout_flashnode_sid(session);
+
+put_host:
+ scsi_host_put(shost);
+
+exit_logout_sid:
+ return err;
+}
+
static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
{
int err = 0;
- struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+ struct iscsi_uevent *ev = nlmsg_data(nlh);
struct iscsi_transport *transport = NULL;
struct iscsi_internal *priv;
struct iscsi_cls_session *session;
@@ -2246,6 +3218,27 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
case ISCSI_UEVENT_DELETE_CHAP:
err = iscsi_delete_chap(transport, ev);
break;
+ case ISCSI_UEVENT_SET_FLASHNODE_PARAMS:
+ err = iscsi_set_flashnode_param(transport, ev,
+ nlmsg_attrlen(nlh,
+ sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_NEW_FLASHNODE:
+ err = iscsi_new_flashnode(transport, ev,
+ nlmsg_attrlen(nlh, sizeof(*ev)));
+ break;
+ case ISCSI_UEVENT_DEL_FLASHNODE:
+ err = iscsi_del_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGIN_FLASHNODE:
+ err = iscsi_login_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGOUT_FLASHNODE:
+ err = iscsi_logout_flashnode(transport, ev);
+ break;
+ case ISCSI_UEVENT_LOGOUT_FLASHNODE_SID:
+ err = iscsi_logout_flashnode_sid(transport, ev);
+ break;
default:
err = -ENOSYS;
break;
@@ -2263,7 +3256,7 @@ static void
iscsi_if_rx(struct sk_buff *skb)
{
mutex_lock(&rx_queue_mutex);
- while (skb->len >= NLMSG_SPACE(0)) {
+ while (skb->len >= NLMSG_HDRLEN) {
int err;
uint32_t rlen;
struct nlmsghdr *nlh;
@@ -2276,7 +3269,7 @@ iscsi_if_rx(struct sk_buff *skb)
break;
}
- ev = NLMSG_DATA(nlh);
+ ev = nlmsg_data(nlh);
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
if (rlen > skb->len)
rlen = skb->len;
@@ -2981,10 +3974,14 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
+ err = bus_register(&iscsi_flashnode_bus);
+ if (err)
+ goto unregister_session_class;
+
nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, &cfg);
if (!nls) {
err = -ENOBUFS;
- goto unregister_session_class;
+ goto unregister_flashnode_bus;
}
iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
@@ -2995,6 +3992,8 @@ static __init int iscsi_transport_init(void)
release_nls:
netlink_kernel_release(nls);
+unregister_flashnode_bus:
+ bus_unregister(&iscsi_flashnode_bus);
unregister_session_class:
transport_class_unregister(&iscsi_session_class);
unregister_conn_class:
@@ -3014,6 +4013,7 @@ static void __exit iscsi_transport_exit(void)
{
destroy_workqueue(iscsi_eh_timer_workq);
netlink_kernel_release(nls);
+ bus_unregister(&iscsi_flashnode_bus);
transport_class_unregister(&iscsi_connection_class);
transport_class_unregister(&iscsi_session_class);
transport_class_unregister(&iscsi_host_class);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 86974471af68..2a32036a9404 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4112,6 +4112,10 @@ static int st_probe(struct device *dev)
tpnt->disk = disk;
disk->private_data = &tpnt->driver;
disk->queue = SDp->request_queue;
+ /* SCSI tape doesn't register this gendisk via add_disk(). Manually
+ * take queue reference that release_disk() expects. */
+ if (!blk_get_queue(disk->queue))
+ goto out_put_disk;
tpnt->driver = &st_template;
tpnt->device = SDp;
@@ -4185,7 +4189,7 @@ static int st_probe(struct device *dev)
idr_preload_end();
if (error < 0) {
pr_warn("st: idr allocation failed: %d\n", error);
- goto out_put_disk;
+ goto out_put_queue;
}
tpnt->index = error;
sprintf(disk->disk_name, "st%d", tpnt->index);
@@ -4211,6 +4215,8 @@ out_remove_devs:
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, tpnt->index);
spin_unlock(&st_index_lock);
+out_put_queue:
+ blk_put_queue(disk->queue);
out_put_disk:
put_disk(disk);
kfree(tpnt);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f80eee74a311..141d8c10b764 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -55,6 +55,7 @@ comment "SPI Master Controller Drivers"
config SPI_ALTERA
tristate "Altera SPI Controller"
+ depends on GENERIC_HARDIRQS
select SPI_BITBANG
help
This is the driver for the Altera SPI Controller.
@@ -74,6 +75,17 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
+config SPI_BCM2835
+ tristate "BCM2835 SPI controller"
+ depends on ARCH_BCM2835
+ help
+ This selects a driver for the Broadcom BCM2835 SPI master.
+
+ The BCM2835 contains two types of SPI master controller; the
+ "universal SPI master", and the regular SPI controller. This driver
+ is for the regular SPI controller. Slave mode operation is not also
+ not supported.
+
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN
@@ -218,16 +230,23 @@ config SPI_MPC512x_PSC
config SPI_FSL_LIB
tristate
+ depends on OF
+
+config SPI_FSL_CPM
+ tristate
depends on FSL_SOC
config SPI_FSL_SPI
- bool "Freescale SPI controller"
- depends on FSL_SOC
+ bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
+ depends on OF
select SPI_FSL_LIB
+ select SPI_FSL_CPM if FSL_SOC
help
This enables using the Freescale SPI controllers in master mode.
MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
+ This also enables using the Aeroflex Gaisler GRLIB SPI controller in
+ master mode.
config SPI_FSL_ESPI
bool "Freescale eSPI controller"
@@ -310,7 +329,7 @@ config SPI_PXA2XX_DMA
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on ARCH_PXA || PCI || ACPI
+ depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS
select PXA_SSP if ARCH_PXA
help
This enables using a PXA2xx or Sodaville SSP port as a SPI master
@@ -397,6 +416,14 @@ config SPI_MXS
help
SPI driver for Freescale MXS devices.
+config SPI_TEGRA114
+ tristate "NVIDIA Tegra114 SPI Controller"
+ depends on ARCH_TEGRA && TEGRA20_APB_DMA
+ help
+ SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
+ is different than the older SoCs SPI controller and also register interface
+ get changed with this controller.
+
config SPI_TEGRA20_SFLASH
tristate "Nvidia Tegra20 Serial flash Controller"
depends on ARCH_TEGRA
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e53c30941340..33f9c09561e7 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
+obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
@@ -28,6 +29,7 @@ obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
+obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
@@ -63,6 +65,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 656d137db253..787bd2c22bca 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -15,16 +15,17 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/platform_data/atmel.h>
+#include <linux/platform_data/dma-atmel.h>
#include <linux/of.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <mach/cpu.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -39,6 +40,7 @@
#define SPI_CSR1 0x0034
#define SPI_CSR2 0x0038
#define SPI_CSR3 0x003c
+#define SPI_VERSION 0x00fc
#define SPI_RPR 0x0100
#define SPI_RCR 0x0104
#define SPI_TPR 0x0108
@@ -71,6 +73,8 @@
#define SPI_FDIV_SIZE 1
#define SPI_MODFDIS_OFFSET 4
#define SPI_MODFDIS_SIZE 1
+#define SPI_WDRBT_OFFSET 5
+#define SPI_WDRBT_SIZE 1
#define SPI_LLB_OFFSET 7
#define SPI_LLB_SIZE 1
#define SPI_PCS_OFFSET 16
@@ -180,6 +184,27 @@
#define spi_writel(port,reg,value) \
__raw_writel((value), (port)->regs + SPI_##reg)
+/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
+ * cache operations; better heuristics consider wordsize and bitrate.
+ */
+#define DMA_MIN_BYTES 16
+
+struct atmel_spi_dma {
+ struct dma_chan *chan_rx;
+ struct dma_chan *chan_tx;
+ struct scatterlist sgrx;
+ struct scatterlist sgtx;
+ struct dma_async_tx_descriptor *data_desc_rx;
+ struct dma_async_tx_descriptor *data_desc_tx;
+
+ struct at_dma_slave dma_slave;
+};
+
+struct atmel_spi_caps {
+ bool is_spi2;
+ bool has_wdrbt;
+ bool has_dma_support;
+};
/*
* The core SPI transfer engine just talks to a register bank to set up
@@ -188,7 +213,9 @@
*/
struct atmel_spi {
spinlock_t lock;
+ unsigned long flags;
+ phys_addr_t phybase;
void __iomem *regs;
int irq;
struct clk *clk;
@@ -197,13 +224,23 @@ struct atmel_spi {
u8 stopping;
struct list_head queue;
+ struct tasklet_struct tasklet;
struct spi_transfer *current_transfer;
unsigned long current_remaining_bytes;
struct spi_transfer *next_transfer;
unsigned long next_remaining_bytes;
+ int done_status;
+ /* scratch buffer */
void *buffer;
dma_addr_t buffer_dma;
+
+ struct atmel_spi_caps caps;
+
+ bool use_dma;
+ bool use_pdc;
+ /* dmaengine data */
+ struct atmel_spi_dma dma;
};
/* Controller-specific per-slave state */
@@ -222,14 +259,10 @@ struct atmel_spi_device {
* - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
* - SPI_CSRx.CSAAT
* - SPI_CSRx.SBCR allows faster clocking
- *
- * We can determine the controller version by reading the VERSION
- * register, but I haven't checked that it exists on all chips, and
- * this is cheaper anyway.
*/
-static bool atmel_spi_is_v2(void)
+static bool atmel_spi_is_v2(struct atmel_spi *as)
{
- return !cpu_is_at91rm9200();
+ return as->caps.is_spi2;
}
/*
@@ -250,11 +283,6 @@ static bool atmel_spi_is_v2(void)
* Master on Chip Select 0.") No workaround exists for that ... so for
* nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
* and (c) will trigger that first erratum in some cases.
- *
- * TODO: Test if the atmel_spi_is_v2() branch below works on
- * AT91RM9200 if we use some other register than CSR0. However, don't
- * do this unconditionally since AP7000 has an errata where the BITS
- * field in CSR0 overrides all other CSRs.
*/
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
@@ -263,15 +291,25 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
unsigned active = spi->mode & SPI_CS_HIGH;
u32 mr;
- if (atmel_spi_is_v2()) {
- /*
- * Always use CSR0. This ensures that the clock
- * switches to the correct idle polarity before we
- * toggle the CS.
+ if (atmel_spi_is_v2(as)) {
+ spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr);
+ /* For the low SPI version, there is a issue that PDC transfer
+ * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
*/
spi_writel(as, CSR0, asd->csr);
- spi_writel(as, MR, SPI_BF(PCS, 0x0e) | SPI_BIT(MODFDIS)
- | SPI_BIT(MSTR));
+ if (as->caps.has_wdrbt) {
+ spi_writel(as, MR,
+ SPI_BF(PCS, ~(0x01 << spi->chip_select))
+ | SPI_BIT(WDRBT)
+ | SPI_BIT(MODFDIS)
+ | SPI_BIT(MSTR));
+ } else {
+ spi_writel(as, MR,
+ SPI_BF(PCS, ~(0x01 << spi->chip_select))
+ | SPI_BIT(MODFDIS)
+ | SPI_BIT(MSTR));
+ }
+
mr = spi_readl(as, MR);
gpio_set_value(asd->npcs_pin, active);
} else {
@@ -318,10 +356,26 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
asd->npcs_pin, active ? " (low)" : "",
mr);
- if (atmel_spi_is_v2() || spi->chip_select != 0)
+ if (atmel_spi_is_v2(as) || spi->chip_select != 0)
gpio_set_value(asd->npcs_pin, !active);
}
+static void atmel_spi_lock(struct atmel_spi *as)
+{
+ spin_lock_irqsave(&as->lock, as->flags);
+}
+
+static void atmel_spi_unlock(struct atmel_spi *as)
+{
+ spin_unlock_irqrestore(&as->lock, as->flags);
+}
+
+static inline bool atmel_spi_use_dma(struct atmel_spi *as,
+ struct spi_transfer *xfer)
+{
+ return as->use_dma && xfer->len >= DMA_MIN_BYTES;
+}
+
static inline int atmel_spi_xfer_is_last(struct spi_message *msg,
struct spi_transfer *xfer)
{
@@ -333,6 +387,265 @@ static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer)
return xfer->delay_usecs == 0 && !xfer->cs_change;
}
+static int atmel_spi_dma_slave_config(struct atmel_spi *as,
+ struct dma_slave_config *slave_config,
+ u8 bits_per_word)
+{
+ int err = 0;
+
+ if (bits_per_word > 8) {
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ } else {
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
+
+ slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
+ slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
+ slave_config->src_maxburst = 1;
+ slave_config->dst_maxburst = 1;
+ slave_config->device_fc = false;
+
+ slave_config->direction = DMA_MEM_TO_DEV;
+ if (dmaengine_slave_config(as->dma.chan_tx, slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure tx dma channel\n");
+ err = -EINVAL;
+ }
+
+ slave_config->direction = DMA_DEV_TO_MEM;
+ if (dmaengine_slave_config(as->dma.chan_rx, slave_config)) {
+ dev_err(&as->pdev->dev,
+ "failed to configure rx dma channel\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct at_dma_slave *sl = slave;
+
+ if (sl->dma_dev == chan->device->dev) {
+ chan->private = sl;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+static int atmel_spi_configure_dma(struct atmel_spi *as)
+{
+ struct at_dma_slave *sdata = &as->dma.dma_slave;
+ struct dma_slave_config slave_config;
+ int err;
+
+ if (sdata && sdata->dma_dev) {
+ dma_cap_mask_t mask;
+
+ /* Try to grab two DMA channels */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ as->dma.chan_tx = dma_request_channel(mask, filter, sdata);
+ if (as->dma.chan_tx)
+ as->dma.chan_rx =
+ dma_request_channel(mask, filter, sdata);
+ }
+ if (!as->dma.chan_rx || !as->dma.chan_tx) {
+ dev_err(&as->pdev->dev,
+ "DMA channel not available, SPI unable to use DMA\n");
+ err = -EBUSY;
+ goto error;
+ }
+
+ err = atmel_spi_dma_slave_config(as, &slave_config, 8);
+ if (err)
+ goto error;
+
+ dev_info(&as->pdev->dev,
+ "Using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(as->dma.chan_tx),
+ dma_chan_name(as->dma.chan_rx));
+ return 0;
+error:
+ if (as->dma.chan_rx)
+ dma_release_channel(as->dma.chan_rx);
+ if (as->dma.chan_tx)
+ dma_release_channel(as->dma.chan_tx);
+ return err;
+}
+
+static void atmel_spi_stop_dma(struct atmel_spi *as)
+{
+ if (as->dma.chan_rx)
+ as->dma.chan_rx->device->device_control(as->dma.chan_rx,
+ DMA_TERMINATE_ALL, 0);
+ if (as->dma.chan_tx)
+ as->dma.chan_tx->device->device_control(as->dma.chan_tx,
+ DMA_TERMINATE_ALL, 0);
+}
+
+static void atmel_spi_release_dma(struct atmel_spi *as)
+{
+ if (as->dma.chan_rx)
+ dma_release_channel(as->dma.chan_rx);
+ if (as->dma.chan_tx)
+ dma_release_channel(as->dma.chan_tx);
+}
+
+/* This function is called by the DMA driver from tasklet context */
+static void dma_callback(void *data)
+{
+ struct spi_master *master = data;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ /* trigger SPI tasklet */
+ tasklet_schedule(&as->tasklet);
+}
+
+/*
+ * Next transfer using PIO.
+ * lock is held, spi tasklet is blocked
+ */
+static void atmel_spi_next_xfer_pio(struct spi_master *master,
+ struct spi_transfer *xfer)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n");
+
+ as->current_remaining_bytes = xfer->len;
+
+ /* Make sure data is not remaining in RDR */
+ spi_readl(as, RDR);
+ while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
+ spi_readl(as, RDR);
+ cpu_relax();
+ }
+
+ if (xfer->tx_buf)
+ spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
+ else
+ spi_writel(as, TDR, 0);
+
+ dev_dbg(master->dev.parent,
+ " start pio xfer %p: len %u tx %p rx %p\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf);
+
+ /* Enable relevant interrupts */
+ spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
+}
+
+/*
+ * Submit next transfer for DMA.
+ * lock is held, spi tasklet is blocked
+ */
+static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
+ struct spi_transfer *xfer,
+ u32 *plen)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct dma_chan *rxchan = as->dma.chan_rx;
+ struct dma_chan *txchan = as->dma.chan_tx;
+ struct dma_async_tx_descriptor *rxdesc;
+ struct dma_async_tx_descriptor *txdesc;
+ struct dma_slave_config slave_config;
+ dma_cookie_t cookie;
+ u32 len = *plen;
+
+ dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
+
+ /* Check that the channels are available */
+ if (!rxchan || !txchan)
+ return -ENODEV;
+
+ /* release lock for DMA operations */
+ atmel_spi_unlock(as);
+
+ /* prepare the RX dma transfer */
+ sg_init_table(&as->dma.sgrx, 1);
+ if (xfer->rx_buf) {
+ as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;
+ } else {
+ as->dma.sgrx.dma_address = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ }
+
+ /* prepare the TX dma transfer */
+ sg_init_table(&as->dma.sgtx, 1);
+ if (xfer->tx_buf) {
+ as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen;
+ } else {
+ as->dma.sgtx.dma_address = as->buffer_dma;
+ if (len > BUFFER_SIZE)
+ len = BUFFER_SIZE;
+ memset(as->buffer, 0, len);
+ }
+
+ sg_dma_len(&as->dma.sgtx) = len;
+ sg_dma_len(&as->dma.sgrx) = len;
+
+ *plen = len;
+
+ if (atmel_spi_dma_slave_config(as, &slave_config, 8))
+ goto err_exit;
+
+ /* Send both scatterlists */
+ rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+ &as->dma.sgrx,
+ 1,
+ DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+ NULL);
+ if (!rxdesc)
+ goto err_dma;
+
+ txdesc = txchan->device->device_prep_slave_sg(txchan,
+ &as->dma.sgtx,
+ 1,
+ DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK,
+ NULL);
+ if (!txdesc)
+ goto err_dma;
+
+ dev_dbg(master->dev.parent,
+ " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+ xfer->rx_buf, xfer->rx_dma);
+
+ /* Enable relevant interrupts */
+ spi_writel(as, IER, SPI_BIT(OVRES));
+
+ /* Put the callback on the RX transfer only, that should finish last */
+ rxdesc->callback = dma_callback;
+ rxdesc->callback_param = master;
+
+ /* Submit and fire RX and TX with TX last so we're ready to read! */
+ cookie = rxdesc->tx_submit(rxdesc);
+ if (dma_submit_error(cookie))
+ goto err_dma;
+ cookie = txdesc->tx_submit(txdesc);
+ if (dma_submit_error(cookie))
+ goto err_dma;
+ rxchan->device->device_issue_pending(rxchan);
+ txchan->device->device_issue_pending(txchan);
+
+ /* take back lock */
+ atmel_spi_lock(as);
+ return 0;
+
+err_dma:
+ spi_writel(as, IDR, SPI_BIT(OVRES));
+ atmel_spi_stop_dma(as);
+err_exit:
+ atmel_spi_lock(as);
+ return -ENOMEM;
+}
+
static void atmel_spi_next_xfer_data(struct spi_master *master,
struct spi_transfer *xfer,
dma_addr_t *tx_dma,
@@ -350,6 +663,7 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
if (len > BUFFER_SIZE)
len = BUFFER_SIZE;
}
+
if (xfer->tx_buf)
*tx_dma = xfer->tx_dma + xfer->len - *plen;
else {
@@ -365,10 +679,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
}
/*
- * Submit next transfer for DMA.
+ * Submit next transfer for PDC.
* lock is held, spi irq is blocked
*/
-static void atmel_spi_next_xfer(struct spi_master *master,
+static void atmel_spi_pdc_next_xfer(struct spi_master *master,
struct spi_message *msg)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -465,6 +779,48 @@ static void atmel_spi_next_xfer(struct spi_master *master,
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
}
+/*
+ * Choose way to submit next transfer and start it.
+ * lock is held, spi tasklet is blocked
+ */
+static void atmel_spi_dma_next_xfer(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ u32 remaining, len;
+
+ remaining = as->current_remaining_bytes;
+ if (remaining) {
+ xfer = as->current_transfer;
+ len = remaining;
+ } else {
+ if (!as->current_transfer)
+ xfer = list_entry(msg->transfers.next,
+ struct spi_transfer, transfer_list);
+ else
+ xfer = list_entry(
+ as->current_transfer->transfer_list.next,
+ struct spi_transfer, transfer_list);
+
+ as->current_transfer = xfer;
+ len = xfer->len;
+ }
+
+ if (atmel_spi_use_dma(as, xfer)) {
+ u32 total = len;
+ if (!atmel_spi_next_xfer_dma_submit(master, xfer, &len)) {
+ as->current_remaining_bytes = total - len;
+ return;
+ } else {
+ dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n");
+ }
+ }
+
+ /* use PIO if error appened using DMA */
+ atmel_spi_next_xfer_pio(master, xfer);
+}
+
static void atmel_spi_next_message(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -489,7 +845,10 @@ static void atmel_spi_next_message(struct spi_master *master)
} else
cs_activate(as, spi);
- atmel_spi_next_xfer(master, msg);
+ if (as->use_pdc)
+ atmel_spi_pdc_next_xfer(master, msg);
+ else
+ atmel_spi_dma_next_xfer(master, msg);
}
/*
@@ -542,38 +901,213 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
xfer->len, DMA_FROM_DEVICE);
}
+static void atmel_spi_disable_pdc_transfer(struct atmel_spi *as)
+{
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+}
+
static void
atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
- struct spi_message *msg, int status, int stay)
+ struct spi_message *msg, int stay)
{
- if (!stay || status < 0)
+ if (!stay || as->done_status < 0)
cs_deactivate(as, msg->spi);
else
as->stay = msg->spi;
list_del(&msg->queue);
- msg->status = status;
+ msg->status = as->done_status;
dev_dbg(master->dev.parent,
"xfer complete: %u bytes transferred\n",
msg->actual_length);
- spin_unlock(&as->lock);
+ atmel_spi_unlock(as);
msg->complete(msg->context);
- spin_lock(&as->lock);
+ atmel_spi_lock(as);
as->current_transfer = NULL;
as->next_transfer = NULL;
+ as->done_status = 0;
/* continue if needed */
- if (list_empty(&as->queue) || as->stopping)
- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
- else
+ if (list_empty(&as->queue) || as->stopping) {
+ if (as->use_pdc)
+ atmel_spi_disable_pdc_transfer(as);
+ } else {
atmel_spi_next_message(master);
+ }
+}
+
+/* Called from IRQ
+ * lock is held
+ *
+ * Must update "current_remaining_bytes" to keep track of data
+ * to transfer.
+ */
+static void
+atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
+{
+ u8 *txp;
+ u8 *rxp;
+ unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
+
+ if (xfer->rx_buf) {
+ rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
+ *rxp = spi_readl(as, RDR);
+ } else {
+ spi_readl(as, RDR);
+ }
+
+ as->current_remaining_bytes--;
+
+ if (as->current_remaining_bytes) {
+ if (xfer->tx_buf) {
+ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
+ spi_writel(as, TDR, *txp);
+ } else {
+ spi_writel(as, TDR, 0);
+ }
+ }
+}
+
+/* Tasklet
+ * Called from DMA callback + pio transfer and overrun IRQ.
+ */
+static void atmel_spi_tasklet_func(unsigned long data)
+{
+ struct spi_master *master = (struct spi_master *)data;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+
+ dev_vdbg(master->dev.parent, "atmel_spi_tasklet_func\n");
+
+ atmel_spi_lock(as);
+
+ xfer = as->current_transfer;
+
+ if (xfer == NULL)
+ /* already been there */
+ goto tasklet_out;
+
+ msg = list_entry(as->queue.next, struct spi_message, queue);
+
+ if (as->current_remaining_bytes == 0) {
+ if (as->done_status < 0) {
+ /* error happened (overrun) */
+ if (atmel_spi_use_dma(as, xfer))
+ atmel_spi_stop_dma(as);
+ } else {
+ /* only update length if no error */
+ msg->actual_length += xfer->len;
+ }
+
+ if (atmel_spi_use_dma(as, xfer))
+ if (!msg->is_dma_mapped)
+ atmel_spi_dma_unmap_xfer(master, xfer);
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (atmel_spi_xfer_is_last(msg, xfer) || as->done_status < 0) {
+ /* report completed (or erroneous) message */
+ atmel_spi_msg_done(master, as, msg, xfer->cs_change);
+ } else {
+ if (xfer->cs_change) {
+ cs_deactivate(as, msg->spi);
+ udelay(1);
+ cs_activate(as, msg->spi);
+ }
+
+ /*
+ * Not done yet. Submit the next transfer.
+ *
+ * FIXME handle protocol options for xfer
+ */
+ atmel_spi_dma_next_xfer(master, msg);
+ }
+ } else {
+ /*
+ * Keep going, we still have data to send in
+ * the current transfer.
+ */
+ atmel_spi_dma_next_xfer(master, msg);
+ }
+
+tasklet_out:
+ atmel_spi_unlock(as);
}
+/* Interrupt
+ *
+ * No need for locking in this Interrupt handler: done_status is the
+ * only information modified. What we need is the update of this field
+ * before tasklet runs. This is ensured by using barrier.
+ */
static irqreturn_t
-atmel_spi_interrupt(int irq, void *dev_id)
+atmel_spi_pio_interrupt(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct atmel_spi *as = spi_master_get_devdata(master);
+ u32 status, pending, imr;
+ struct spi_transfer *xfer;
+ int ret = IRQ_NONE;
+
+ imr = spi_readl(as, IMR);
+ status = spi_readl(as, SR);
+ pending = status & imr;
+
+ if (pending & SPI_BIT(OVRES)) {
+ ret = IRQ_HANDLED;
+ spi_writel(as, IDR, SPI_BIT(OVRES));
+ dev_warn(master->dev.parent, "overrun\n");
+
+ /*
+ * When we get an overrun, we disregard the current
+ * transfer. Data will not be copied back from any
+ * bounce buffer and msg->actual_len will not be
+ * updated with the last xfer.
+ *
+ * We will also not process any remaning transfers in
+ * the message.
+ *
+ * All actions are done in tasklet with done_status indication
+ */
+ as->done_status = -EIO;
+ smp_wmb();
+
+ /* Clear any overrun happening while cleaning up */
+ spi_readl(as, SR);
+
+ tasklet_schedule(&as->tasklet);
+
+ } else if (pending & SPI_BIT(RDRF)) {
+ atmel_spi_lock(as);
+
+ if (as->current_remaining_bytes) {
+ ret = IRQ_HANDLED;
+ xfer = as->current_transfer;
+ atmel_spi_pump_pio_data(as, xfer);
+ if (!as->current_remaining_bytes) {
+ /* no more data to xfer, kick tasklet */
+ spi_writel(as, IDR, pending);
+ tasklet_schedule(&as->tasklet);
+ }
+ }
+
+ atmel_spi_unlock(as);
+ } else {
+ WARN_ONCE(pending, "IRQ not handled, pending = %x\n", pending);
+ ret = IRQ_HANDLED;
+ spi_writel(as, IDR, pending);
+ }
+
+ return ret;
+}
+
+static irqreturn_t
+atmel_spi_pdc_interrupt(int irq, void *dev_id)
{
struct spi_master *master = dev_id;
struct atmel_spi *as = spi_master_get_devdata(master);
@@ -582,7 +1116,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
u32 status, pending, imr;
int ret = IRQ_NONE;
- spin_lock(&as->lock);
+ atmel_spi_lock(as);
xfer = as->current_transfer;
msg = list_entry(as->queue.next, struct spi_message, queue);
@@ -641,7 +1175,8 @@ atmel_spi_interrupt(int irq, void *dev_id)
/* Clear any overrun happening while cleaning up */
spi_readl(as, SR);
- atmel_spi_msg_done(master, as, msg, -EIO, 0);
+ as->done_status = -EIO;
+ atmel_spi_msg_done(master, as, msg, 0);
} else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
ret = IRQ_HANDLED;
@@ -659,7 +1194,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (atmel_spi_xfer_is_last(msg, xfer)) {
/* report completed message */
- atmel_spi_msg_done(master, as, msg, 0,
+ atmel_spi_msg_done(master, as, msg,
xfer->cs_change);
} else {
if (xfer->cs_change) {
@@ -673,18 +1208,18 @@ atmel_spi_interrupt(int irq, void *dev_id)
*
* FIXME handle protocol options for xfer
*/
- atmel_spi_next_xfer(master, msg);
+ atmel_spi_pdc_next_xfer(master, msg);
}
} else {
/*
* Keep going, we still have data to send in
* the current transfer.
*/
- atmel_spi_next_xfer(master, msg);
+ atmel_spi_pdc_next_xfer(master, msg);
}
}
- spin_unlock(&as->lock);
+ atmel_spi_unlock(as);
return ret;
}
@@ -719,7 +1254,7 @@ static int atmel_spi_setup(struct spi_device *spi)
}
/* see notes above re chipselect */
- if (!atmel_spi_is_v2()
+ if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
&& (spi->mode & SPI_CS_HIGH)) {
dev_dbg(&spi->dev, "setup: can't be active-high\n");
@@ -728,7 +1263,7 @@ static int atmel_spi_setup(struct spi_device *spi)
/* v1 chips start out at half the peripheral bus speed. */
bus_hz = clk_get_rate(as->clk);
- if (!atmel_spi_is_v2())
+ if (!atmel_spi_is_v2(as))
bus_hz /= 2;
if (spi->max_speed_hz) {
@@ -789,13 +1324,11 @@ static int atmel_spi_setup(struct spi_device *spi)
spi->controller_state = asd;
gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
} else {
- unsigned long flags;
-
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
if (as->stay == spi)
as->stay = NULL;
cs_deactivate(as, spi);
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
}
asd->csr = csr;
@@ -804,7 +1337,7 @@ static int atmel_spi_setup(struct spi_device *spi)
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
- if (!atmel_spi_is_v2())
+ if (!atmel_spi_is_v2(as))
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
return 0;
@@ -814,7 +1347,6 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct atmel_spi *as;
struct spi_transfer *xfer;
- unsigned long flags;
struct device *controller = spi->master->dev.parent;
u8 bits;
struct atmel_spi_device *asd;
@@ -854,13 +1386,10 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
/*
* DMA map early, for performance (empties dcache ASAP) and
- * better fault reporting. This is a DMA-only driver.
- *
- * NOTE that if dma_unmap_single() ever starts to do work on
- * platforms supported by this driver, we would need to clean
- * up mappings for previously-mapped transfers.
+ * better fault reporting.
*/
- if (!msg->is_dma_mapped) {
+ if ((!msg->is_dma_mapped) && (atmel_spi_use_dma(as, xfer)
+ || as->use_pdc)) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
@@ -879,11 +1408,11 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
msg->status = -EINPROGRESS;
msg->actual_length = 0;
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
list_add_tail(&msg->queue, &as->queue);
if (!as->current_transfer)
atmel_spi_next_message(spi->master);
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
return 0;
}
@@ -893,23 +1422,39 @@ static void atmel_spi_cleanup(struct spi_device *spi)
struct atmel_spi *as = spi_master_get_devdata(spi->master);
struct atmel_spi_device *asd = spi->controller_state;
unsigned gpio = (unsigned) spi->controller_data;
- unsigned long flags;
if (!asd)
return;
- spin_lock_irqsave(&as->lock, flags);
+ atmel_spi_lock(as);
if (as->stay == spi) {
as->stay = NULL;
cs_deactivate(as, spi);
}
- spin_unlock_irqrestore(&as->lock, flags);
+ atmel_spi_unlock(as);
spi->controller_state = NULL;
gpio_free(gpio);
kfree(asd);
}
+static inline unsigned int atmel_get_version(struct atmel_spi *as)
+{
+ return spi_readl(as, VERSION) & 0x00000fff;
+}
+
+static void atmel_get_caps(struct atmel_spi *as)
+{
+ unsigned int version;
+
+ version = atmel_get_version(as);
+ dev_info(&as->pdev->dev, "version: 0x%x\n", version);
+
+ as->caps.is_spi2 = version > 0x121;
+ as->caps.has_wdrbt = version >= 0x210;
+ as->caps.has_dma_support = version >= 0x212;
+}
+
/*-------------------------------------------------------------------------*/
static int atmel_spi_probe(struct platform_device *pdev)
@@ -963,15 +1508,39 @@ static int atmel_spi_probe(struct platform_device *pdev)
spin_lock_init(&as->lock);
INIT_LIST_HEAD(&as->queue);
+
as->pdev = pdev;
as->regs = ioremap(regs->start, resource_size(regs));
if (!as->regs)
goto out_free_buffer;
+ as->phybase = regs->start;
as->irq = irq;
as->clk = clk;
- ret = request_irq(irq, atmel_spi_interrupt, 0,
- dev_name(&pdev->dev), master);
+ atmel_get_caps(as);
+
+ as->use_dma = false;
+ as->use_pdc = false;
+ if (as->caps.has_dma_support) {
+ if (atmel_spi_configure_dma(as) == 0)
+ as->use_dma = true;
+ } else {
+ as->use_pdc = true;
+ }
+
+ if (as->caps.has_dma_support && !as->use_dma)
+ dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n");
+
+ if (as->use_pdc) {
+ ret = request_irq(irq, atmel_spi_pdc_interrupt, 0,
+ dev_name(&pdev->dev), master);
+ } else {
+ tasklet_init(&as->tasklet, atmel_spi_tasklet_func,
+ (unsigned long)master);
+
+ ret = request_irq(irq, atmel_spi_pio_interrupt, 0,
+ dev_name(&pdev->dev), master);
+ }
if (ret)
goto out_unmap_regs;
@@ -979,8 +1548,15 @@ static int atmel_spi_probe(struct platform_device *pdev)
clk_enable(clk);
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
- spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
- spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+ if (as->caps.has_wdrbt) {
+ spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
+ | SPI_BIT(MSTR));
+ } else {
+ spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
+ }
+
+ if (as->use_pdc)
+ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
spi_writel(as, CR, SPI_BIT(SPIEN));
/* go! */
@@ -989,11 +1565,14 @@ static int atmel_spi_probe(struct platform_device *pdev)
ret = spi_register_master(master);
if (ret)
- goto out_reset_hw;
+ goto out_free_dma;
return 0;
-out_reset_hw:
+out_free_dma:
+ if (as->use_dma)
+ atmel_spi_release_dma(as);
+
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
clk_disable(clk);
@@ -1001,6 +1580,8 @@ out_reset_hw:
out_unmap_regs:
iounmap(as->regs);
out_free_buffer:
+ if (!as->use_pdc)
+ tasklet_kill(&as->tasklet);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
out_free:
@@ -1014,10 +1595,16 @@ static int atmel_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
+ struct spi_transfer *xfer;
/* reset the hardware and block queue progress */
spin_lock_irq(&as->lock);
as->stopping = 1;
+ if (as->use_dma) {
+ atmel_spi_stop_dma(as);
+ atmel_spi_release_dma(as);
+ }
+
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
spi_readl(as, SR);
@@ -1025,13 +1612,18 @@ static int atmel_spi_remove(struct platform_device *pdev)
/* Terminate remaining queued transfers */
list_for_each_entry(msg, &as->queue, queue) {
- /* REVISIT unmapping the dma is a NOP on ARM and AVR32
- * but we shouldn't depend on that...
- */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!msg->is_dma_mapped
+ && (atmel_spi_use_dma(as, xfer)
+ || as->use_pdc))
+ atmel_spi_dma_unmap_xfer(master, xfer);
+ }
msg->status = -ESHUTDOWN;
msg->complete(msg->context);
}
+ if (!as->use_pdc)
+ tasklet_kill(&as->tasklet);
dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
as->buffer_dma);
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
new file mode 100644
index 000000000000..89c0b5033114
--- /dev/null
+++ b/drivers/spi/spi-bcm2835.c
@@ -0,0 +1,422 @@
+/*
+ * Driver for Broadcom BCM2835 SPI Controllers
+ *
+ * Copyright (C) 2012 Chris Boot
+ * Copyright (C) 2013 Stephen Warren
+ *
+ * This driver is inspired by:
+ * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+/* SPI register offsets */
+#define BCM2835_SPI_CS 0x00
+#define BCM2835_SPI_FIFO 0x04
+#define BCM2835_SPI_CLK 0x08
+#define BCM2835_SPI_DLEN 0x0c
+#define BCM2835_SPI_LTOH 0x10
+#define BCM2835_SPI_DC 0x14
+
+/* Bitfields in CS */
+#define BCM2835_SPI_CS_LEN_LONG 0x02000000
+#define BCM2835_SPI_CS_DMA_LEN 0x01000000
+#define BCM2835_SPI_CS_CSPOL2 0x00800000
+#define BCM2835_SPI_CS_CSPOL1 0x00400000
+#define BCM2835_SPI_CS_CSPOL0 0x00200000
+#define BCM2835_SPI_CS_RXF 0x00100000
+#define BCM2835_SPI_CS_RXR 0x00080000
+#define BCM2835_SPI_CS_TXD 0x00040000
+#define BCM2835_SPI_CS_RXD 0x00020000
+#define BCM2835_SPI_CS_DONE 0x00010000
+#define BCM2835_SPI_CS_LEN 0x00002000
+#define BCM2835_SPI_CS_REN 0x00001000
+#define BCM2835_SPI_CS_ADCS 0x00000800
+#define BCM2835_SPI_CS_INTR 0x00000400
+#define BCM2835_SPI_CS_INTD 0x00000200
+#define BCM2835_SPI_CS_DMAEN 0x00000100
+#define BCM2835_SPI_CS_TA 0x00000080
+#define BCM2835_SPI_CS_CSPOL 0x00000040
+#define BCM2835_SPI_CS_CLEAR_RX 0x00000020
+#define BCM2835_SPI_CS_CLEAR_TX 0x00000010
+#define BCM2835_SPI_CS_CPOL 0x00000008
+#define BCM2835_SPI_CS_CPHA 0x00000004
+#define BCM2835_SPI_CS_CS_10 0x00000002
+#define BCM2835_SPI_CS_CS_01 0x00000001
+
+#define BCM2835_SPI_TIMEOUT_MS 30000
+#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS)
+
+#define DRV_NAME "spi-bcm2835"
+
+struct bcm2835_spi {
+ void __iomem *regs;
+ struct clk *clk;
+ int irq;
+ struct completion done;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg)
+{
+ return readl(bs->regs + reg);
+}
+
+static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned reg, u32 val)
+{
+ writel(val, bs->regs + reg);
+}
+
+static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs, int len)
+{
+ u8 byte;
+
+ while (len--) {
+ byte = bcm2835_rd(bs, BCM2835_SPI_FIFO);
+ if (bs->rx_buf)
+ *bs->rx_buf++ = byte;
+ }
+}
+
+static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs, int len)
+{
+ u8 byte;
+
+ if (len > bs->len)
+ len = bs->len;
+
+ while (len--) {
+ byte = bs->tx_buf ? *bs->tx_buf++ : 0;
+ bcm2835_wr(bs, BCM2835_SPI_FIFO, byte);
+ bs->len--;
+ }
+}
+
+static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+ /*
+ * RXR - RX needs Reading. This means 12 (or more) bytes have been
+ * transmitted and hence 12 (or more) bytes have been received.
+ *
+ * The FIFO is 16-bytes deep. We check for this interrupt to keep the
+ * FIFO full; we have a 4-byte-time buffer for IRQ latency. We check
+ * this before DONE (TX empty) just in case we delayed processing this
+ * interrupt for some reason.
+ *
+ * We only check for this case if we have more bytes to TX; at the end
+ * of the transfer, we ignore this pipelining optimization, and let
+ * bcm2835_spi_finish_transfer() drain the RX FIFO.
+ */
+ if (bs->len && (cs & BCM2835_SPI_CS_RXR)) {
+ /* Read 12 bytes of data */
+ bcm2835_rd_fifo(bs, 12);
+
+ /* Write up to 12 bytes */
+ bcm2835_wr_fifo(bs, 12);
+
+ /*
+ * We must have written something to the TX FIFO due to the
+ * bs->len check above, so cannot be DONE. Hence, return
+ * early. Note that DONE could also be set if we serviced an
+ * RXR interrupt really late.
+ */
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * DONE - TX empty. This occurs when we first enable the transfer
+ * since we do not pre-fill the TX FIFO. At any other time, given that
+ * we refill the TX FIFO above based on RXR, and hence ignore DONE if
+ * RXR is set, DONE really does mean end-of-transfer.
+ */
+ if (cs & BCM2835_SPI_CS_DONE) {
+ if (bs->len) { /* First interrupt in a transfer */
+ bcm2835_wr_fifo(bs, 16);
+ } else { /* Transfer complete */
+ /* Disable SPI interrupts */
+ cs &= ~(BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD);
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+
+ /*
+ * Wake up bcm2835_spi_transfer_one(), which will call
+ * bcm2835_spi_finish_transfer(), to drain the RX FIFO.
+ */
+ complete(&bs->done);
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int bcm2835_spi_start_transfer(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct bcm2835_spi *bs = spi_master_get_devdata(spi->master);
+ unsigned long spi_hz, clk_hz, cdiv;
+ u32 cs = BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA;
+
+ spi_hz = tfr->speed_hz;
+ clk_hz = clk_get_rate(bs->clk);
+
+ if (spi_hz >= clk_hz / 2) {
+ cdiv = 2; /* clk_hz/2 is the fastest we can go */
+ } else if (spi_hz) {
+ /* CDIV must be a power of two */
+ cdiv = roundup_pow_of_two(DIV_ROUND_UP(clk_hz, spi_hz));
+
+ if (cdiv >= 65536)
+ cdiv = 0; /* 0 is the slowest we can go */
+ } else
+ cdiv = 0; /* 0 is the slowest we can go */
+
+ if (spi->mode & SPI_CPOL)
+ cs |= BCM2835_SPI_CS_CPOL;
+ if (spi->mode & SPI_CPHA)
+ cs |= BCM2835_SPI_CS_CPHA;
+
+ if (!(spi->mode & SPI_NO_CS)) {
+ if (spi->mode & SPI_CS_HIGH) {
+ cs |= BCM2835_SPI_CS_CSPOL;
+ cs |= BCM2835_SPI_CS_CSPOL0 << spi->chip_select;
+ }
+
+ cs |= spi->chip_select;
+ }
+
+ INIT_COMPLETION(bs->done);
+ bs->tx_buf = tfr->tx_buf;
+ bs->rx_buf = tfr->rx_buf;
+ bs->len = tfr->len;
+
+ bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
+ /*
+ * Enable the HW block. This will immediately trigger a DONE (TX
+ * empty) interrupt, upon which we will fill the TX FIFO with the
+ * first TX bytes. Pre-filling the TX FIFO here to avoid the
+ * interrupt doesn't work:-(
+ */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+
+ return 0;
+}
+
+static int bcm2835_spi_finish_transfer(struct spi_device *spi,
+ struct spi_transfer *tfr, bool cs_change)
+{
+ struct bcm2835_spi *bs = spi_master_get_devdata(spi->master);
+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+ /* Drain RX FIFO */
+ while (cs & BCM2835_SPI_CS_RXD) {
+ bcm2835_rd_fifo(bs, 1);
+ cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+ }
+
+ if (tfr->delay_usecs)
+ udelay(tfr->delay_usecs);
+
+ if (cs_change)
+ /* Clear TA flag */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs & ~BCM2835_SPI_CS_TA);
+
+ return 0;
+}
+
+static int bcm2835_spi_transfer_one(struct spi_master *master,
+ struct spi_message *mesg)
+{
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+ struct spi_transfer *tfr;
+ struct spi_device *spi = mesg->spi;
+ int err = 0;
+ unsigned int timeout;
+ bool cs_change;
+
+ list_for_each_entry(tfr, &mesg->transfers, transfer_list) {
+ err = bcm2835_spi_start_transfer(spi, tfr);
+ if (err)
+ goto out;
+
+ timeout = wait_for_completion_timeout(&bs->done,
+ msecs_to_jiffies(BCM2835_SPI_TIMEOUT_MS));
+ if (!timeout) {
+ err = -ETIMEDOUT;
+ goto out;
+ }
+
+ cs_change = tfr->cs_change ||
+ list_is_last(&tfr->transfer_list, &mesg->transfers);
+
+ err = bcm2835_spi_finish_transfer(spi, tfr, cs_change);
+ if (err)
+ goto out;
+
+ mesg->actual_length += (tfr->len - bs->len);
+ }
+
+out:
+ /* Clear FIFOs, and disable the HW block */
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+ mesg->status = err;
+ spi_finalize_current_message(master);
+
+ return 0;
+}
+
+static int bcm2835_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct bcm2835_spi *bs;
+ struct resource *res;
+ int err;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ if (!master) {
+ dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, master);
+
+ master->mode_bits = BCM2835_SPI_MODE_BITS;
+ master->bits_per_word_mask = BIT(8 - 1);
+ master->bus_num = -1;
+ master->num_chipselect = 3;
+ master->transfer_one_message = bcm2835_spi_transfer_one;
+ master->dev.of_node = pdev->dev.of_node;
+
+ bs = spi_master_get_devdata(master);
+
+ init_completion(&bs->done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "could not get memory resource\n");
+ err = -ENODEV;
+ goto out_master_put;
+ }
+
+ bs->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!bs->regs) {
+ dev_err(&pdev->dev, "could not request/map memory region\n");
+ err = -ENODEV;
+ goto out_master_put;
+ }
+
+ bs->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(bs->clk)) {
+ err = PTR_ERR(bs->clk);
+ dev_err(&pdev->dev, "could not get clk: %d\n", err);
+ goto out_master_put;
+ }
+
+ bs->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (bs->irq <= 0) {
+ dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
+ err = bs->irq ? bs->irq : -ENODEV;
+ goto out_master_put;
+ }
+
+ clk_prepare_enable(bs->clk);
+
+ err = request_irq(bs->irq, bcm2835_spi_interrupt, 0,
+ dev_name(&pdev->dev), master);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+ goto out_clk_disable;
+ }
+
+ /* initialise the hardware */
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+
+ err = spi_register_master(master);
+ if (err) {
+ dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
+ goto out_free_irq;
+ }
+
+ return 0;
+
+out_free_irq:
+ free_irq(bs->irq, master);
+out_clk_disable:
+ clk_disable_unprepare(bs->clk);
+out_master_put:
+ spi_master_put(master);
+ return err;
+}
+
+static int bcm2835_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcm2835_spi *bs = spi_master_get_devdata(master);
+
+ free_irq(bs->irq, master);
+ spi_unregister_master(master);
+
+ /* Clear FIFOs, and disable the HW block */
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+
+ clk_disable_unprepare(bs->clk);
+ spi_master_put(master);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_spi_match[] = {
+ { .compatible = "brcm,bcm2835-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
+
+static struct platform_driver bcm2835_spi_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_spi_match,
+ },
+ .probe = bcm2835_spi_probe,
+ .remove = bcm2835_spi_remove,
+};
+module_platform_driver(bcm2835_spi_driver);
+
+MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 9578af782a77..a4ec5f4ec817 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -46,7 +46,6 @@ struct bcm63xx_spi {
int irq;
/* Platform data */
- u32 speed_hz;
unsigned fifo_size;
unsigned int msg_type_shift;
unsigned int msg_ctl_width;
@@ -93,40 +92,16 @@ static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
{ 391000, SPI_CLK_0_391MHZ }
};
-static int bcm63xx_spi_check_transfer(struct spi_device *spi,
- struct spi_transfer *t)
-{
- u8 bits_per_word;
-
- bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
- if (bits_per_word != 8) {
- dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
- __func__, bits_per_word);
- return -EINVAL;
- }
-
- if (spi->chip_select > spi->master->num_chipselect) {
- dev_err(&spi->dev, "%s, unsupported slave %d\n",
- __func__, spi->chip_select);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
- u32 hz;
u8 clk_cfg, reg;
int i;
- hz = (t) ? t->speed_hz : spi->max_speed_hz;
-
/* Find the closest clock configuration */
for (i = 0; i < SPI_CLK_MASK; i++) {
- if (hz >= bcm63xx_spi_freq_table[i][0]) {
+ if (t->speed_hz >= bcm63xx_spi_freq_table[i][0]) {
clk_cfg = bcm63xx_spi_freq_table[i][1];
break;
}
@@ -143,7 +118,7 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
- clk_cfg, hz);
+ clk_cfg, t->speed_hz);
}
/* the spi->mode bits understood by this driver: */
@@ -151,23 +126,12 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
static int bcm63xx_spi_setup(struct spi_device *spi)
{
- struct bcm63xx_spi *bs;
- int ret;
-
- bs = spi_master_get_devdata(spi->master);
-
- if (!spi->bits_per_word)
- spi->bits_per_word = 8;
-
- if (spi->mode & ~MODEBITS) {
- dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
- __func__, spi->mode & ~MODEBITS);
+ if (spi->bits_per_word != 8) {
+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+ __func__, spi->bits_per_word);
return -EINVAL;
}
- dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
- __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
-
return 0;
}
@@ -313,9 +277,12 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
* full-duplex transfers.
*/
list_for_each_entry(t, &m->transfers, transfer_list) {
- status = bcm63xx_spi_check_transfer(spi, t);
- if (status < 0)
+ if (t->bits_per_word != 8) {
+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
+ __func__, t->bits_per_word);
+ status = -EINVAL;
goto exit;
+ }
if (!first)
first = t;
@@ -444,18 +411,9 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
- if (!devm_request_mem_region(&pdev->dev, r->start,
- resource_size(r), PFX)) {
- dev_err(dev, "iomem request failed\n");
- ret = -ENXIO;
- goto out_err;
- }
-
- bs->regs = devm_ioremap_nocache(&pdev->dev, r->start,
- resource_size(r));
- if (!bs->regs) {
- dev_err(dev, "unable to ioremap regs\n");
- ret = -ENOMEM;
+ bs->regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(bs->regs)) {
+ ret = PTR_ERR(bs->regs);
goto out_err;
}
@@ -477,7 +435,6 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
master->transfer_one_message = bcm63xx_spi_transfer_one;
master->mode_bits = MODEBITS;
- bs->speed_hz = pdata->speed_hz;
bs->msg_type_shift = pdata->msg_type_shift;
bs->msg_ctl_width = pdata->msg_ctl_width;
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
@@ -490,11 +447,11 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
default:
dev_err(dev, "unsupported MSG_CTL width: %d\n",
bs->msg_ctl_width);
- goto out_clk_disable;
+ goto out_err;
}
/* Initialize hardware */
- clk_enable(bs->clk);
+ clk_prepare_enable(bs->clk);
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
/* register and we are done */
@@ -510,7 +467,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return 0;
out_clk_disable:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
out_err:
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
@@ -531,7 +488,7 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
/* HW shutdown */
- clk_disable(bs->clk);
+ clk_disable_unprepare(bs->clk);
clk_put(bs->clk);
platform_set_drvdata(pdev, 0);
@@ -550,7 +507,7 @@ static int bcm63xx_spi_suspend(struct device *dev)
spi_master_suspend(master);
- clk_disable(bs->clk);
+ clk_disable_unprepare(bs->clk);
return 0;
}
@@ -561,7 +518,7 @@ static int bcm63xx_spi_resume(struct device *dev)
platform_get_drvdata(to_platform_device(dev));
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
- clk_enable(bs->clk);
+ clk_prepare_enable(bs->clk);
spi_master_resume(master);
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
new file mode 100644
index 000000000000..07971e3fe58b
--- /dev/null
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -0,0 +1,387 @@
+/*
+ * Freescale SPI controller driver cpm functions.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <asm/cpm.h>
+#include <asm/qe.h>
+
+#include "spi-fsl-lib.h"
+#include "spi-fsl-cpm.h"
+#include "spi-fsl-spi.h"
+
+/* CPM1 and CPM2 are mutually exclusive. */
+#ifdef CONFIG_CPM1
+#include <asm/cpm1.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
+#else
+#include <asm/cpm2.h>
+#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
+#endif
+
+#define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */
+#define SPIE_RXB 0x00000100 /* Last char is written to rx buf */
+
+/* SPCOM register values */
+#define SPCOM_STR (1 << 23) /* Start transmit */
+
+#define SPI_PRAM_SIZE 0x100
+#define SPI_MRBLR ((unsigned int)PAGE_SIZE)
+
+static void *fsl_dummy_rx;
+static DEFINE_MUTEX(fsl_dummy_rx_lock);
+static int fsl_dummy_rx_refcnt;
+
+void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
+{
+ if (mspi->flags & SPI_QE) {
+ qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+ } else {
+ cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
+ if (mspi->flags & SPI_CPM1) {
+ out_be16(&mspi->pram->rbptr,
+ in_be16(&mspi->pram->rbase));
+ out_be16(&mspi->pram->tbptr,
+ in_be16(&mspi->pram->tbase));
+ }
+ }
+}
+
+static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
+{
+ struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
+ struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
+ unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
+ unsigned int xfer_ofs;
+ struct fsl_spi_reg *reg_base = mspi->reg_base;
+
+ xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
+
+ if (mspi->rx_dma == mspi->dma_dummy_rx)
+ out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
+ else
+ out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
+ out_be16(&rx_bd->cbd_datlen, 0);
+ out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+
+ if (mspi->tx_dma == mspi->dma_dummy_tx)
+ out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
+ else
+ out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
+ out_be16(&tx_bd->cbd_datlen, xfer_len);
+ out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
+ BD_SC_LAST);
+
+ /* start transfer */
+ mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
+}
+
+int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+ struct spi_transfer *t, bool is_dma_mapped)
+{
+ struct device *dev = mspi->dev;
+ struct fsl_spi_reg *reg_base = mspi->reg_base;
+
+ if (is_dma_mapped) {
+ mspi->map_tx_dma = 0;
+ mspi->map_rx_dma = 0;
+ } else {
+ mspi->map_tx_dma = 1;
+ mspi->map_rx_dma = 1;
+ }
+
+ if (!t->tx_buf) {
+ mspi->tx_dma = mspi->dma_dummy_tx;
+ mspi->map_tx_dma = 0;
+ }
+
+ if (!t->rx_buf) {
+ mspi->rx_dma = mspi->dma_dummy_rx;
+ mspi->map_rx_dma = 0;
+ }
+
+ if (mspi->map_tx_dma) {
+ void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
+
+ mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, mspi->tx_dma)) {
+ dev_err(dev, "unable to map tx dma\n");
+ return -ENOMEM;
+ }
+ } else if (t->tx_buf) {
+ mspi->tx_dma = t->tx_dma;
+ }
+
+ if (mspi->map_rx_dma) {
+ mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, mspi->rx_dma)) {
+ dev_err(dev, "unable to map rx dma\n");
+ goto err_rx_dma;
+ }
+ } else if (t->rx_buf) {
+ mspi->rx_dma = t->rx_dma;
+ }
+
+ /* enable rx ints */
+ mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
+
+ mspi->xfer_in_progress = t;
+ mspi->count = t->len;
+
+ /* start CPM transfers */
+ fsl_spi_cpm_bufs_start(mspi);
+
+ return 0;
+
+err_rx_dma:
+ if (mspi->map_tx_dma)
+ dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+ return -ENOMEM;
+}
+
+void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
+{
+ struct device *dev = mspi->dev;
+ struct spi_transfer *t = mspi->xfer_in_progress;
+
+ if (mspi->map_tx_dma)
+ dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
+ if (mspi->map_rx_dma)
+ dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
+ mspi->xfer_in_progress = NULL;
+}
+
+void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+ u16 len;
+ struct fsl_spi_reg *reg_base = mspi->reg_base;
+
+ dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
+ in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+
+ len = in_be16(&mspi->rx_bd->cbd_datlen);
+ if (len > mspi->count) {
+ WARN_ON(1);
+ len = mspi->count;
+ }
+
+ /* Clear the events */
+ mpc8xxx_spi_write_reg(&reg_base->event, events);
+
+ mspi->count -= len;
+ if (mspi->count)
+ fsl_spi_cpm_bufs_start(mspi);
+ else
+ complete(&mspi->done);
+}
+
+static void *fsl_spi_alloc_dummy_rx(void)
+{
+ mutex_lock(&fsl_dummy_rx_lock);
+
+ if (!fsl_dummy_rx)
+ fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+ if (fsl_dummy_rx)
+ fsl_dummy_rx_refcnt++;
+
+ mutex_unlock(&fsl_dummy_rx_lock);
+
+ return fsl_dummy_rx;
+}
+
+static void fsl_spi_free_dummy_rx(void)
+{
+ mutex_lock(&fsl_dummy_rx_lock);
+
+ switch (fsl_dummy_rx_refcnt) {
+ case 0:
+ WARN_ON(1);
+ break;
+ case 1:
+ kfree(fsl_dummy_rx);
+ fsl_dummy_rx = NULL;
+ /* fall through */
+ default:
+ fsl_dummy_rx_refcnt--;
+ break;
+ }
+
+ mutex_unlock(&fsl_dummy_rx_lock);
+}
+
+static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+{
+ struct device *dev = mspi->dev;
+ struct device_node *np = dev->of_node;
+ const u32 *iprop;
+ int size;
+ void __iomem *spi_base;
+ unsigned long pram_ofs = -ENOMEM;
+
+ /* Can't use of_address_to_resource(), QE muram isn't at 0. */
+ iprop = of_get_property(np, "reg", &size);
+
+ /* QE with a fixed pram location? */
+ if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
+ return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
+
+ /* QE but with a dynamic pram location? */
+ if (mspi->flags & SPI_QE) {
+ pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
+ QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
+ return pram_ofs;
+ }
+
+ spi_base = of_iomap(np, 1);
+ if (spi_base == NULL)
+ return -EINVAL;
+
+ if (mspi->flags & SPI_CPM2) {
+ pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+ out_be16(spi_base, pram_ofs);
+ } else {
+ struct spi_pram __iomem *pram = spi_base;
+ u16 rpbase = in_be16(&pram->rpbase);
+
+ /* Microcode relocation patch applied? */
+ if (rpbase) {
+ pram_ofs = rpbase;
+ } else {
+ pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
+ out_be16(spi_base, pram_ofs);
+ }
+ }
+
+ iounmap(spi_base);
+ return pram_ofs;
+}
+
+int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
+{
+ struct device *dev = mspi->dev;
+ struct device_node *np = dev->of_node;
+ const u32 *iprop;
+ int size;
+ unsigned long pram_ofs;
+ unsigned long bds_ofs;
+
+ if (!(mspi->flags & SPI_CPM_MODE))
+ return 0;
+
+ if (!fsl_spi_alloc_dummy_rx())
+ return -ENOMEM;
+
+ if (mspi->flags & SPI_QE) {
+ iprop = of_get_property(np, "cell-index", &size);
+ if (iprop && size == sizeof(*iprop))
+ mspi->subblock = *iprop;
+
+ switch (mspi->subblock) {
+ default:
+ dev_warn(dev, "cell-index unspecified, assuming SPI1");
+ /* fall through */
+ case 0:
+ mspi->subblock = QE_CR_SUBBLOCK_SPI1;
+ break;
+ case 1:
+ mspi->subblock = QE_CR_SUBBLOCK_SPI2;
+ break;
+ }
+ }
+
+ pram_ofs = fsl_spi_cpm_get_pram(mspi);
+ if (IS_ERR_VALUE(pram_ofs)) {
+ dev_err(dev, "can't allocate spi parameter ram\n");
+ goto err_pram;
+ }
+
+ bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
+ sizeof(*mspi->rx_bd), 8);
+ if (IS_ERR_VALUE(bds_ofs)) {
+ dev_err(dev, "can't allocate bds\n");
+ goto err_bds;
+ }
+
+ mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
+ dev_err(dev, "unable to map dummy tx buffer\n");
+ goto err_dummy_tx;
+ }
+
+ mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
+ dev_err(dev, "unable to map dummy rx buffer\n");
+ goto err_dummy_rx;
+ }
+
+ mspi->pram = cpm_muram_addr(pram_ofs);
+
+ mspi->tx_bd = cpm_muram_addr(bds_ofs);
+ mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
+
+ /* Initialize parameter ram. */
+ out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
+ out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
+ out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
+ out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
+ out_be16(&mspi->pram->mrblr, SPI_MRBLR);
+ out_be32(&mspi->pram->rstate, 0);
+ out_be32(&mspi->pram->rdp, 0);
+ out_be16(&mspi->pram->rbptr, 0);
+ out_be16(&mspi->pram->rbc, 0);
+ out_be32(&mspi->pram->rxtmp, 0);
+ out_be32(&mspi->pram->tstate, 0);
+ out_be32(&mspi->pram->tdp, 0);
+ out_be16(&mspi->pram->tbptr, 0);
+ out_be16(&mspi->pram->tbc, 0);
+ out_be32(&mspi->pram->txtmp, 0);
+
+ return 0;
+
+err_dummy_rx:
+ dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+err_dummy_tx:
+ cpm_muram_free(bds_ofs);
+err_bds:
+ cpm_muram_free(pram_ofs);
+err_pram:
+ fsl_spi_free_dummy_rx();
+ return -ENOMEM;
+}
+
+void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
+{
+ struct device *dev = mspi->dev;
+
+ if (!(mspi->flags & SPI_CPM_MODE))
+ return;
+
+ dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
+ dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
+ cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
+ cpm_muram_free(cpm_muram_offset(mspi->pram));
+ fsl_spi_free_dummy_rx();
+}
diff --git a/drivers/spi/spi-fsl-cpm.h b/drivers/spi/spi-fsl-cpm.h
new file mode 100644
index 000000000000..c71115805485
--- /dev/null
+++ b/drivers/spi/spi-fsl-cpm.h
@@ -0,0 +1,43 @@
+/*
+ * Freescale SPI controller driver cpm functions.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __SPI_FSL_CPM_H__
+#define __SPI_FSL_CPM_H__
+
+#include "spi-fsl-lib.h"
+
+#ifdef CONFIG_FSL_SOC
+extern void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi);
+extern int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+ struct spi_transfer *t, bool is_dma_mapped);
+extern void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi);
+extern void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events);
+extern int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi);
+extern void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi);
+#else
+static inline void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) { }
+static inline int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+ struct spi_transfer *t,
+ bool is_dma_mapped) { return 0; }
+static inline void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { }
+static inline void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { }
+static inline int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { return 0; }
+static inline void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) { }
+#endif
+
+#endif /* __SPI_FSL_CPM_H__ */
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 8ade675a04f1..a91db0e57b23 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -23,7 +23,9 @@
#include <linux/mm.h>
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
+#ifdef CONFIG_FSL_SOC
#include <sysdev/fsl_soc.h>
+#endif
#include "spi-fsl-lib.h"
@@ -208,6 +210,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
/* Allocate bus num dynamically. */
pdata->bus_num = -1;
+#ifdef CONFIG_FSL_SOC
/* SPI controller is either clocked from QE or SoC clock. */
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
@@ -217,6 +220,11 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
goto err;
}
}
+#else
+ ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
+ if (ret)
+ goto err;
+#endif
prop = of_get_property(np, "mode", NULL);
if (prop && !strcmp(prop, "cpu-qe"))
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index cbe881b9ea76..52db6936778e 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -34,8 +34,10 @@ struct mpc8xxx_spi {
int subblock;
struct spi_pram __iomem *pram;
+#ifdef CONFIG_FSL_SOC
struct cpm_buf_desc __iomem *tx_bd;
struct cpm_buf_desc __iomem *rx_bd;
+#endif
struct spi_transfer *xfer_in_progress;
@@ -67,6 +69,15 @@ struct mpc8xxx_spi {
unsigned int flags;
+#ifdef CONFIG_SPI_FSL_SPI
+ int type;
+ int native_chipselects;
+ u8 max_bits_per_word;
+
+ void (*set_shifts)(u32 *rx_shift, u32 *tx_shift,
+ int bits_per_word, int msb_first);
+#endif
+
struct workqueue_struct *workqueue;
struct work_struct work;
@@ -87,12 +98,12 @@ struct spi_mpc8xxx_cs {
static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
{
- out_be32(reg, val);
+ iowrite32be(val, reg);
}
static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
{
- return in_be32(reg);
+ return ioread32be(reg);
}
struct mpc8xxx_spi_probe_info {
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 086a9eef2e05..14e202ee7036 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -10,6 +10,10 @@
* Copyright (c) 2009 MontaVista Software, Inc.
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
*
+ * GRLIB support:
+ * Copyright (c) 2012 Aeroflex Gaisler AB.
+ * Author: Andreas Larsson <andreas@gaisler.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
@@ -30,75 +34,54 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
-#include <sysdev/fsl_soc.h>
-#include <asm/cpm.h>
-#include <asm/qe.h>
-
#include "spi-fsl-lib.h"
+#include "spi-fsl-cpm.h"
+#include "spi-fsl-spi.h"
-/* CPM1 and CPM2 are mutually exclusive. */
-#ifdef CONFIG_CPM1
-#include <asm/cpm1.h>
-#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_CH_SPI, 0)
-#else
-#include <asm/cpm2.h>
-#define CPM_SPI_CMD mk_cr_cmd(CPM_CR_SPI_PAGE, CPM_CR_SPI_SBLOCK, 0, 0)
-#endif
-
-/* SPI Controller registers */
-struct fsl_spi_reg {
- u8 res1[0x20];
- __be32 mode;
- __be32 event;
- __be32 mask;
- __be32 command;
- __be32 transmit;
- __be32 receive;
-};
-
-/* SPI Controller mode register definitions */
-#define SPMODE_LOOP (1 << 30)
-#define SPMODE_CI_INACTIVEHIGH (1 << 29)
-#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
-#define SPMODE_DIV16 (1 << 27)
-#define SPMODE_REV (1 << 26)
-#define SPMODE_MS (1 << 25)
-#define SPMODE_ENABLE (1 << 24)
-#define SPMODE_LEN(x) ((x) << 20)
-#define SPMODE_PM(x) ((x) << 16)
-#define SPMODE_OP (1 << 14)
-#define SPMODE_CG(x) ((x) << 7)
+#define TYPE_FSL 0
+#define TYPE_GRLIB 1
-/*
- * Default for SPI Mode:
- * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
- */
-#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
- SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
-
-/* SPIE register values */
-#define SPIE_NE 0x00000200 /* Not empty */
-#define SPIE_NF 0x00000100 /* Not full */
+struct fsl_spi_match_data {
+ int type;
+};
-/* SPIM register values */
-#define SPIM_NE 0x00000200 /* Not empty */
-#define SPIM_NF 0x00000100 /* Not full */
+static struct fsl_spi_match_data of_fsl_spi_fsl_config = {
+ .type = TYPE_FSL,
+};
-#define SPIE_TXB 0x00000200 /* Last char is written to tx fifo */
-#define SPIE_RXB 0x00000100 /* Last char is written to rx buf */
+static struct fsl_spi_match_data of_fsl_spi_grlib_config = {
+ .type = TYPE_GRLIB,
+};
-/* SPCOM register values */
-#define SPCOM_STR (1 << 23) /* Start transmit */
+static struct of_device_id of_fsl_spi_match[] = {
+ {
+ .compatible = "fsl,spi",
+ .data = &of_fsl_spi_fsl_config,
+ },
+ {
+ .compatible = "aeroflexgaisler,spictrl",
+ .data = &of_fsl_spi_grlib_config,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
-#define SPI_PRAM_SIZE 0x100
-#define SPI_MRBLR ((unsigned int)PAGE_SIZE)
+static int fsl_spi_get_type(struct device *dev)
+{
+ const struct of_device_id *match;
-static void *fsl_dummy_rx;
-static DEFINE_MUTEX(fsl_dummy_rx_lock);
-static int fsl_dummy_rx_refcnt;
+ if (dev->of_node) {
+ match = of_match_node(of_fsl_spi_match, dev->of_node);
+ if (match && match->data)
+ return ((struct fsl_spi_match_data *)match->data)->type;
+ }
+ return TYPE_FSL;
+}
static void fsl_spi_change_mode(struct spi_device *spi)
{
@@ -119,18 +102,7 @@ static void fsl_spi_change_mode(struct spi_device *spi)
/* When in CPM mode, we need to reinit tx and rx. */
if (mspi->flags & SPI_CPM_MODE) {
- if (mspi->flags & SPI_QE) {
- qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, 0);
- } else {
- cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
- if (mspi->flags & SPI_CPM1) {
- out_be16(&mspi->pram->rbptr,
- in_be16(&mspi->pram->rbase));
- out_be16(&mspi->pram->tbptr,
- in_be16(&mspi->pram->tbase));
- }
- }
+ fsl_spi_cpm_reinit_txrx(mspi);
}
mpc8xxx_spi_write_reg(mode, cs->hw_mode);
local_irq_restore(flags);
@@ -163,6 +135,40 @@ static void fsl_spi_chipselect(struct spi_device *spi, int value)
}
}
+static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift,
+ int bits_per_word, int msb_first)
+{
+ *rx_shift = 0;
+ *tx_shift = 0;
+ if (msb_first) {
+ if (bits_per_word <= 8) {
+ *rx_shift = 16;
+ *tx_shift = 24;
+ } else if (bits_per_word <= 16) {
+ *rx_shift = 16;
+ *tx_shift = 16;
+ }
+ } else {
+ if (bits_per_word <= 8)
+ *rx_shift = 8;
+ }
+}
+
+static void fsl_spi_grlib_set_shifts(u32 *rx_shift, u32 *tx_shift,
+ int bits_per_word, int msb_first)
+{
+ *rx_shift = 0;
+ *tx_shift = 0;
+ if (bits_per_word <= 16) {
+ if (msb_first) {
+ *rx_shift = 16; /* LSB in bit 16 */
+ *tx_shift = 32 - bits_per_word; /* MSB in bit 31 */
+ } else {
+ *rx_shift = 16 - bits_per_word; /* MSB in bit 15 */
+ }
+ }
+}
+
static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
struct spi_device *spi,
struct mpc8xxx_spi *mpc8xxx_spi,
@@ -173,31 +179,20 @@ static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
if (bits_per_word <= 8) {
cs->get_rx = mpc8xxx_spi_rx_buf_u8;
cs->get_tx = mpc8xxx_spi_tx_buf_u8;
- if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
- cs->rx_shift = 16;
- cs->tx_shift = 24;
- }
} else if (bits_per_word <= 16) {
cs->get_rx = mpc8xxx_spi_rx_buf_u16;
cs->get_tx = mpc8xxx_spi_tx_buf_u16;
- if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
- cs->rx_shift = 16;
- cs->tx_shift = 16;
- }
} else if (bits_per_word <= 32) {
cs->get_rx = mpc8xxx_spi_rx_buf_u32;
cs->get_tx = mpc8xxx_spi_tx_buf_u32;
} else
return -EINVAL;
- if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
- spi->mode & SPI_LSB_FIRST) {
- cs->tx_shift = 0;
- if (bits_per_word <= 8)
- cs->rx_shift = 8;
- else
- cs->rx_shift = 0;
- }
+ if (mpc8xxx_spi->set_shifts)
+ mpc8xxx_spi->set_shifts(&cs->rx_shift, &cs->tx_shift,
+ bits_per_word,
+ !(spi->mode & SPI_LSB_FIRST));
+
mpc8xxx_spi->rx_shift = cs->rx_shift;
mpc8xxx_spi->tx_shift = cs->tx_shift;
mpc8xxx_spi->get_rx = cs->get_rx;
@@ -246,7 +241,8 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
- || ((bits_per_word > 16) && (bits_per_word != 32)))
+ || ((bits_per_word > 16) && (bits_per_word != 32))
+ || (bits_per_word > mpc8xxx_spi->max_bits_per_word))
return -EINVAL;
if (!hz)
@@ -295,112 +291,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
return 0;
}
-static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
-{
- struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
- struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
- unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
- unsigned int xfer_ofs;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
-
- xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
-
- if (mspi->rx_dma == mspi->dma_dummy_rx)
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
- else
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
- out_be16(&rx_bd->cbd_datlen, 0);
- out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
-
- if (mspi->tx_dma == mspi->dma_dummy_tx)
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
- else
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
- out_be16(&tx_bd->cbd_datlen, xfer_len);
- out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
- BD_SC_LAST);
-
- /* start transfer */
- mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
-}
-
-static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, bool is_dma_mapped)
-{
- struct device *dev = mspi->dev;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
-
- if (is_dma_mapped) {
- mspi->map_tx_dma = 0;
- mspi->map_rx_dma = 0;
- } else {
- mspi->map_tx_dma = 1;
- mspi->map_rx_dma = 1;
- }
-
- if (!t->tx_buf) {
- mspi->tx_dma = mspi->dma_dummy_tx;
- mspi->map_tx_dma = 0;
- }
-
- if (!t->rx_buf) {
- mspi->rx_dma = mspi->dma_dummy_rx;
- mspi->map_rx_dma = 0;
- }
-
- if (mspi->map_tx_dma) {
- void *nonconst_tx = (void *)mspi->tx; /* shut up gcc */
-
- mspi->tx_dma = dma_map_single(dev, nonconst_tx, t->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, mspi->tx_dma)) {
- dev_err(dev, "unable to map tx dma\n");
- return -ENOMEM;
- }
- } else if (t->tx_buf) {
- mspi->tx_dma = t->tx_dma;
- }
-
- if (mspi->map_rx_dma) {
- mspi->rx_dma = dma_map_single(dev, mspi->rx, t->len,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, mspi->rx_dma)) {
- dev_err(dev, "unable to map rx dma\n");
- goto err_rx_dma;
- }
- } else if (t->rx_buf) {
- mspi->rx_dma = t->rx_dma;
- }
-
- /* enable rx ints */
- mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
-
- mspi->xfer_in_progress = t;
- mspi->count = t->len;
-
- /* start CPM transfers */
- fsl_spi_cpm_bufs_start(mspi);
-
- return 0;
-
-err_rx_dma:
- if (mspi->map_tx_dma)
- dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
- return -ENOMEM;
-}
-
-static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
-{
- struct device *dev = mspi->dev;
- struct spi_transfer *t = mspi->xfer_in_progress;
-
- if (mspi->map_tx_dma)
- dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
- if (mspi->map_rx_dma)
- dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
- mspi->xfer_in_progress = NULL;
-}
-
static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, unsigned int len)
{
@@ -565,31 +455,45 @@ static int fsl_spi_setup(struct spi_device *spi)
cs->hw_mode = hw_mode; /* Restore settings */
return retval;
}
- return 0;
-}
-static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
-{
- u16 len;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ if (mpc8xxx_spi->type == TYPE_GRLIB) {
+ if (gpio_is_valid(spi->cs_gpio)) {
+ int desel;
- dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
- in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+ retval = gpio_request(spi->cs_gpio,
+ dev_name(&spi->dev));
+ if (retval)
+ return retval;
- len = in_be16(&mspi->rx_bd->cbd_datlen);
- if (len > mspi->count) {
- WARN_ON(1);
- len = mspi->count;
+ desel = !(spi->mode & SPI_CS_HIGH);
+ retval = gpio_direction_output(spi->cs_gpio, desel);
+ if (retval) {
+ gpio_free(spi->cs_gpio);
+ return retval;
+ }
+ } else if (spi->cs_gpio != -ENOENT) {
+ if (spi->cs_gpio < 0)
+ return spi->cs_gpio;
+ return -EINVAL;
+ }
+ /* When spi->cs_gpio == -ENOENT, a hole in the phandle list
+ * indicates to use native chipselect if present, or allow for
+ * an always selected chip
+ */
}
- /* Clear the events */
- mpc8xxx_spi_write_reg(&reg_base->event, events);
+ /* Initialize chipselect - might be active for SPI_CS_HIGH mode */
+ fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- mspi->count -= len;
- if (mspi->count)
- fsl_spi_cpm_bufs_start(mspi);
- else
- complete(&mspi->done);
+ return 0;
+}
+
+static void fsl_spi_cleanup(struct spi_device *spi)
+{
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+
+ if (mpc8xxx_spi->type == TYPE_GRLIB && gpio_is_valid(spi->cs_gpio))
+ gpio_free(spi->cs_gpio);
}
static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
@@ -646,201 +550,51 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
return ret;
}
-static void *fsl_spi_alloc_dummy_rx(void)
-{
- mutex_lock(&fsl_dummy_rx_lock);
-
- if (!fsl_dummy_rx)
- fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
- if (fsl_dummy_rx)
- fsl_dummy_rx_refcnt++;
-
- mutex_unlock(&fsl_dummy_rx_lock);
-
- return fsl_dummy_rx;
-}
-
-static void fsl_spi_free_dummy_rx(void)
+static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
{
- mutex_lock(&fsl_dummy_rx_lock);
-
- switch (fsl_dummy_rx_refcnt) {
- case 0:
- WARN_ON(1);
- break;
- case 1:
- kfree(fsl_dummy_rx);
- fsl_dummy_rx = NULL;
- /* fall through */
- default:
- fsl_dummy_rx_refcnt--;
- break;
- }
-
- mutex_unlock(&fsl_dummy_rx_lock);
+ iounmap(mspi->reg_base);
+ fsl_spi_cpm_free(mspi);
}
-static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
{
- struct device *dev = mspi->dev;
- struct device_node *np = dev->of_node;
- const u32 *iprop;
- int size;
- void __iomem *spi_base;
- unsigned long pram_ofs = -ENOMEM;
-
- /* Can't use of_address_to_resource(), QE muram isn't at 0. */
- iprop = of_get_property(np, "reg", &size);
-
- /* QE with a fixed pram location? */
- if (mspi->flags & SPI_QE && iprop && size == sizeof(*iprop) * 4)
- return cpm_muram_alloc_fixed(iprop[2], SPI_PRAM_SIZE);
-
- /* QE but with a dynamic pram location? */
- if (mspi->flags & SPI_QE) {
- pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
- qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, mspi->subblock,
- QE_CR_PROTOCOL_UNSPECIFIED, pram_ofs);
- return pram_ofs;
- }
-
- spi_base = of_iomap(np, 1);
- if (spi_base == NULL)
- return -EINVAL;
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
+ u32 slvsel;
+ u16 cs = spi->chip_select;
- if (mspi->flags & SPI_CPM2) {
- pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
- out_be16(spi_base, pram_ofs);
- } else {
- struct spi_pram __iomem *pram = spi_base;
- u16 rpbase = in_be16(&pram->rpbase);
-
- /* Microcode relocation patch applied? */
- if (rpbase)
- pram_ofs = rpbase;
- else {
- pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
- out_be16(spi_base, pram_ofs);
- }
+ if (gpio_is_valid(spi->cs_gpio)) {
+ gpio_set_value(spi->cs_gpio, on);
+ } else if (cs < mpc8xxx_spi->native_chipselects) {
+ slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel);
+ slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs));
+ mpc8xxx_spi_write_reg(&reg_base->slvsel, slvsel);
}
-
- iounmap(spi_base);
- return pram_ofs;
}
-static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
+static void fsl_spi_grlib_probe(struct device *dev)
{
- struct device *dev = mspi->dev;
- struct device_node *np = dev->of_node;
- const u32 *iprop;
- int size;
- unsigned long pram_ofs;
- unsigned long bds_ofs;
-
- if (!(mspi->flags & SPI_CPM_MODE))
- return 0;
-
- if (!fsl_spi_alloc_dummy_rx())
- return -ENOMEM;
-
- if (mspi->flags & SPI_QE) {
- iprop = of_get_property(np, "cell-index", &size);
- if (iprop && size == sizeof(*iprop))
- mspi->subblock = *iprop;
-
- switch (mspi->subblock) {
- default:
- dev_warn(dev, "cell-index unspecified, assuming SPI1");
- /* fall through */
- case 0:
- mspi->subblock = QE_CR_SUBBLOCK_SPI1;
- break;
- case 1:
- mspi->subblock = QE_CR_SUBBLOCK_SPI2;
- break;
- }
- }
-
- pram_ofs = fsl_spi_cpm_get_pram(mspi);
- if (IS_ERR_VALUE(pram_ofs)) {
- dev_err(dev, "can't allocate spi parameter ram\n");
- goto err_pram;
- }
+ struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base;
+ int mbits;
+ u32 capabilities;
- bds_ofs = cpm_muram_alloc(sizeof(*mspi->tx_bd) +
- sizeof(*mspi->rx_bd), 8);
- if (IS_ERR_VALUE(bds_ofs)) {
- dev_err(dev, "can't allocate bds\n");
- goto err_bds;
- }
+ capabilities = mpc8xxx_spi_read_reg(&reg_base->cap);
- mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
- dev_err(dev, "unable to map dummy tx buffer\n");
- goto err_dummy_tx;
- }
+ mpc8xxx_spi->set_shifts = fsl_spi_grlib_set_shifts;
+ mbits = SPCAP_MAXWLEN(capabilities);
+ if (mbits)
+ mpc8xxx_spi->max_bits_per_word = mbits + 1;
- mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
- DMA_FROM_DEVICE);
- if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
- dev_err(dev, "unable to map dummy rx buffer\n");
- goto err_dummy_rx;
+ mpc8xxx_spi->native_chipselects = 0;
+ if (SPCAP_SSEN(capabilities)) {
+ mpc8xxx_spi->native_chipselects = SPCAP_SSSZ(capabilities);
+ mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
-
- mspi->pram = cpm_muram_addr(pram_ofs);
-
- mspi->tx_bd = cpm_muram_addr(bds_ofs);
- mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
-
- /* Initialize parameter ram. */
- out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
- out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
- out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
- out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
- out_be16(&mspi->pram->mrblr, SPI_MRBLR);
- out_be32(&mspi->pram->rstate, 0);
- out_be32(&mspi->pram->rdp, 0);
- out_be16(&mspi->pram->rbptr, 0);
- out_be16(&mspi->pram->rbc, 0);
- out_be32(&mspi->pram->rxtmp, 0);
- out_be32(&mspi->pram->tstate, 0);
- out_be32(&mspi->pram->tdp, 0);
- out_be16(&mspi->pram->tbptr, 0);
- out_be16(&mspi->pram->tbc, 0);
- out_be32(&mspi->pram->txtmp, 0);
-
- return 0;
-
-err_dummy_rx:
- dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
-err_dummy_tx:
- cpm_muram_free(bds_ofs);
-err_bds:
- cpm_muram_free(pram_ofs);
-err_pram:
- fsl_spi_free_dummy_rx();
- return -ENOMEM;
-}
-
-static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
-{
- struct device *dev = mspi->dev;
-
- if (!(mspi->flags & SPI_CPM_MODE))
- return;
-
- dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
- dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
- cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
- cpm_muram_free(cpm_muram_offset(mspi->pram));
- fsl_spi_free_dummy_rx();
-}
-
-static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
-{
- iounmap(mspi->reg_base);
- fsl_spi_cpm_free(mspi);
+ master->num_chipselect = mpc8xxx_spi->native_chipselects;
+ pdata->cs_control = fsl_spi_grlib_cs_control;
}
static struct spi_master * fsl_spi_probe(struct device *dev,
@@ -866,27 +620,35 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
goto err_probe;
master->setup = fsl_spi_setup;
+ master->cleanup = fsl_spi_cleanup;
mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
mpc8xxx_spi->spi_remove = fsl_spi_remove;
-
+ mpc8xxx_spi->max_bits_per_word = 32;
+ mpc8xxx_spi->type = fsl_spi_get_type(dev);
ret = fsl_spi_cpm_init(mpc8xxx_spi);
if (ret)
goto err_cpm_init;
- if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
- mpc8xxx_spi->rx_shift = 16;
- mpc8xxx_spi->tx_shift = 24;
- }
-
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
if (mpc8xxx_spi->reg_base == NULL) {
ret = -ENOMEM;
goto err_ioremap;
}
+ if (mpc8xxx_spi->type == TYPE_GRLIB)
+ fsl_spi_grlib_probe(dev);
+
+ if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
+ mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
+
+ if (mpc8xxx_spi->set_shifts)
+ /* 8 bits per word and MSB first */
+ mpc8xxx_spi->set_shifts(&mpc8xxx_spi->rx_shift,
+ &mpc8xxx_spi->tx_shift, 8, 1);
+
/* Register for SPI Interrupt */
ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
0, "fsl_spi", mpc8xxx_spi);
@@ -904,6 +666,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+ if (mpc8xxx_spi->max_bits_per_word < 8) {
+ regval &= ~SPMODE_LEN(0xF);
+ regval |= SPMODE_LEN(mpc8xxx_spi->max_bits_per_word - 1);
+ }
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
regval |= SPMODE_OP;
@@ -1047,28 +813,31 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
struct device_node *np = ofdev->dev.of_node;
struct spi_master *master;
struct resource mem;
- struct resource irq;
+ int irq, type;
int ret = -ENOMEM;
ret = of_mpc8xxx_spi_probe(ofdev);
if (ret)
return ret;
- ret = of_fsl_spi_get_chipselects(dev);
- if (ret)
- goto err;
+ type = fsl_spi_get_type(&ofdev->dev);
+ if (type == TYPE_FSL) {
+ ret = of_fsl_spi_get_chipselects(dev);
+ if (ret)
+ goto err;
+ }
ret = of_address_to_resource(np, 0, &mem);
if (ret)
goto err;
- ret = of_irq_to_resource(np, 0, &irq);
- if (!ret) {
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
ret = -EINVAL;
goto err;
}
- master = fsl_spi_probe(dev, &mem, irq.start);
+ master = fsl_spi_probe(dev, &mem, irq);
if (IS_ERR(master)) {
ret = PTR_ERR(master);
goto err;
@@ -1077,27 +846,25 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
return 0;
err:
- of_fsl_spi_free_chipselects(dev);
+ if (type == TYPE_FSL)
+ of_fsl_spi_free_chipselects(dev);
return ret;
}
static int of_fsl_spi_remove(struct platform_device *ofdev)
{
+ struct spi_master *master = dev_get_drvdata(&ofdev->dev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
int ret;
ret = mpc8xxx_spi_remove(&ofdev->dev);
if (ret)
return ret;
- of_fsl_spi_free_chipselects(&ofdev->dev);
+ if (mpc8xxx_spi->type == TYPE_FSL)
+ of_fsl_spi_free_chipselects(&ofdev->dev);
return 0;
}
-static const struct of_device_id of_fsl_spi_match[] = {
- { .compatible = "fsl,spi" },
- {}
-};
-MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
-
static struct platform_driver of_fsl_spi_driver = {
.driver = {
.name = "fsl_spi",
@@ -1134,9 +901,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return -EINVAL;
master = fsl_spi_probe(&pdev->dev, mem, irq);
- if (IS_ERR(master))
- return PTR_ERR(master);
- return 0;
+ return PTR_RET(master);
}
static int plat_mpc8xxx_spi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi-fsl-spi.h b/drivers/spi/spi-fsl-spi.h
new file mode 100644
index 000000000000..9a6dae00e3f3
--- /dev/null
+++ b/drivers/spi/spi-fsl-spi.h
@@ -0,0 +1,72 @@
+/*
+ * Freescale SPI controller driver.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * GRLIB support:
+ * Copyright (c) 2012 Aeroflex Gaisler AB.
+ * Author: Andreas Larsson <andreas@gaisler.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 __SPI_FSL_SPI_H__
+#define __SPI_FSL_SPI_H__
+
+/* SPI Controller registers */
+struct fsl_spi_reg {
+ __be32 cap; /* TYPE_GRLIB specific */
+ u8 res1[0x1C];
+ __be32 mode;
+ __be32 event;
+ __be32 mask;
+ __be32 command;
+ __be32 transmit;
+ __be32 receive;
+ __be32 slvsel; /* TYPE_GRLIB specific */
+};
+
+/* SPI Controller mode register definitions */
+#define SPMODE_LOOP (1 << 30)
+#define SPMODE_CI_INACTIVEHIGH (1 << 29)
+#define SPMODE_CP_BEGIN_EDGECLK (1 << 28)
+#define SPMODE_DIV16 (1 << 27)
+#define SPMODE_REV (1 << 26)
+#define SPMODE_MS (1 << 25)
+#define SPMODE_ENABLE (1 << 24)
+#define SPMODE_LEN(x) ((x) << 20)
+#define SPMODE_PM(x) ((x) << 16)
+#define SPMODE_OP (1 << 14)
+#define SPMODE_CG(x) ((x) << 7)
+
+/* TYPE_GRLIB SPI Controller capability register definitions */
+#define SPCAP_SSEN(x) (((x) >> 16) & 0x1)
+#define SPCAP_SSSZ(x) (((x) >> 24) & 0xff)
+#define SPCAP_MAXWLEN(x) (((x) >> 20) & 0xf)
+
+/*
+ * Default for SPI Mode:
+ * SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
+ */
+#define SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
+ SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
+
+/* SPIE register values */
+#define SPIE_NE 0x00000200 /* Not empty */
+#define SPIE_NF 0x00000100 /* Not full */
+
+/* SPIM register values */
+#define SPIM_NE 0x00000200 /* Not empty */
+#define SPIM_NF 0x00000100 /* Not full */
+
+#endif /* __SPI_FSL_SPI_H__ */
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 9ddef55a7165..0021fc4c45bc 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -265,9 +265,9 @@ static int spi_gpio_setup(struct spi_device *spi)
}
}
if (!status) {
- status = spi_bitbang_setup(spi);
/* in case it was initialized from static board data */
spi_gpio->cs_gpios[spi->chip_select] = cs;
+ status = spi_bitbang_setup(spi);
}
if (status) {
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 89480b281d74..dfddf336912d 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -28,6 +28,7 @@
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
+#include <linux/gpio.h>
#include <asm/mpc52xx_psc.h>
struct mpc512x_psc_spi {
@@ -113,7 +114,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
out_be32(&psc->ccr, ccr);
mps->bits_per_word = cs->bits_per_word;
- if (mps->cs_control)
+ if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
}
@@ -121,7 +122,7 @@ static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
- if (mps->cs_control)
+ if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
}
@@ -148,6 +149,9 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
in_8(&psc->mode);
out_8(&psc->mode, 0x0);
+ /* enable transmiter/receiver */
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+
while (len) {
int count;
int i;
@@ -164,7 +168,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
for (i = count; i > 0; i--) {
data = tx_buf ? *tx_buf++ : 0;
- if (len == EOFBYTE)
+ if (len == EOFBYTE && t->cs_change)
setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
out_8(&fifo->txdata_8, data);
len--;
@@ -176,10 +180,6 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
- /* enable transmiter/receiver */
- out_8(&psc->command,
- MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
-
wait_for_completion(&mps->done);
mdelay(1);
@@ -204,9 +204,6 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
while (in_be32(&fifo->rxcnt)) {
in_8(&fifo->rxdata_8);
}
-
- out_8(&psc->command,
- MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
}
/* disable transmiter/receiver and fifo interrupt */
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
@@ -278,6 +275,7 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
unsigned long flags;
+ int ret;
if (spi->bits_per_word % 8)
return -EINVAL;
@@ -286,6 +284,19 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
+
+ if (gpio_is_valid(spi->cs_gpio)) {
+ ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
+ if (ret) {
+ dev_err(&spi->dev, "can't get CS gpio: %d\n",
+ ret);
+ kfree(cs);
+ return ret;
+ }
+ gpio_direction_output(spi->cs_gpio,
+ spi->mode & SPI_CS_HIGH ? 0 : 1);
+ }
+
spi->controller_state = cs;
}
@@ -319,6 +330,8 @@ static int mpc512x_psc_spi_transfer(struct spi_device *spi,
static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
{
+ if (gpio_is_valid(spi->cs_gpio))
+ gpio_free(spi->cs_gpio);
kfree(spi->controller_state);
}
@@ -405,6 +418,11 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
return IRQ_NONE;
}
+static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
+{
+ gpio_set_value(spi->cs_gpio, onoff);
+}
+
/* bus_num is used only for the case dev->platform_data == NULL */
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq,
@@ -425,12 +443,9 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
mps->irq = irq;
if (pdata == NULL) {
- dev_err(dev, "probe called without platform data, no "
- "cs_control function will be called\n");
- mps->cs_control = NULL;
+ mps->cs_control = mpc512x_spi_cs_control;
mps->sysclk = 0;
master->bus_num = bus_num;
- master->num_chipselect = 255;
} else {
mps->cs_control = pdata->cs_control;
mps->sysclk = pdata->sysclk;
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 22a0af0147fb..a1d5778e2bbb 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -612,6 +612,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
ssp->dmach = dma_request_channel(mask, mxs_ssp_dma_filter, ssp);
if (!ssp->dmach) {
dev_err(ssp->dev, "Failed to request DMA\n");
+ ret = -ENODEV;
goto out_master_free;
}
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index cb2e284bd814..e60a776ed2d4 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -393,8 +393,6 @@ static const struct of_device_id tiny_spi_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, tiny_spi_match);
-#else /* CONFIG_OF */
-#define tiny_spi_match NULL
#endif /* CONFIG_OF */
static struct platform_driver tiny_spi_driver = {
@@ -404,7 +402,7 @@ static struct platform_driver tiny_spi_driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = NULL,
- .of_match_table = tiny_spi_match,
+ .of_match_table = of_match_ptr(tiny_spi_match),
},
};
module_platform_driver(tiny_spi_driver);
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 893c3d78e426..86d2158946bb 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -285,8 +285,12 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
timeout = jiffies + msecs_to_jiffies(1000);
while (!(__raw_readl(reg) & bit)) {
- if (time_after(jiffies, timeout))
- return -1;
+ if (time_after(jiffies, timeout)) {
+ if (!(__raw_readl(reg) & bit))
+ return -ETIMEDOUT;
+ else
+ return 0;
+ }
cpu_relax();
}
return 0;
@@ -805,6 +809,10 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
return 0;
}
+/*
+ * Note that we currently allow DMA only if we get a channel
+ * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
+ */
static int omap2_mcspi_request_dma(struct spi_device *spi)
{
struct spi_master *master = spi->master;
@@ -823,21 +831,22 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
dma_cap_set(DMA_SLAVE, mask);
sig = mcspi_dma->dma_rx_sync_dev;
mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
- if (!mcspi_dma->dma_rx) {
- dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
- return -EAGAIN;
- }
+ if (!mcspi_dma->dma_rx)
+ goto no_dma;
sig = mcspi_dma->dma_tx_sync_dev;
mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
if (!mcspi_dma->dma_tx) {
- dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n");
dma_release_channel(mcspi_dma->dma_rx);
mcspi_dma->dma_rx = NULL;
- return -EAGAIN;
+ goto no_dma;
}
return 0;
+
+no_dma:
+ dev_warn(&spi->dev, "not using DMA for McSPI\n");
+ return -EAGAIN;
}
static int omap2_mcspi_setup(struct spi_device *spi)
@@ -870,7 +879,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
ret = omap2_mcspi_request_dma(spi);
- if (ret < 0)
+ if (ret < 0 && ret != -EAGAIN)
return ret;
}
@@ -928,6 +937,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
struct spi_device *spi;
struct spi_transfer *t = NULL;
struct spi_master *master;
+ struct omap2_mcspi_dma *mcspi_dma;
int cs_active = 0;
struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd;
@@ -937,6 +947,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
spi = m->spi;
master = spi->master;
+ mcspi_dma = mcspi->dma_channels + spi->chip_select;
cs = spi->controller_state;
cd = spi->controller_data;
@@ -993,7 +1004,8 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
__raw_writel(0, cs->base
+ OMAP2_MCSPI_TX0);
- if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
+ if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+ (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
count = omap2_mcspi_txrx_dma(spi, t);
else
count = omap2_mcspi_txrx_pio(spi, t);
@@ -1040,10 +1052,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
static int omap2_mcspi_transfer_one_message(struct spi_master *master,
struct spi_message *m)
{
+ struct spi_device *spi;
struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
struct spi_transfer *t;
+ spi = m->spi;
mcspi = spi_master_get_devdata(master);
+ mcspi_dma = mcspi->dma_channels + spi->chip_select;
m->actual_length = 0;
m->status = 0;
@@ -1078,7 +1094,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
- if (tx_buf != NULL) {
+ if (mcspi_dma->dma_tx && tx_buf != NULL) {
t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
len, DMA_TO_DEVICE);
if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
@@ -1087,7 +1103,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
return -EINVAL;
}
}
- if (rx_buf != NULL) {
+ if (mcspi_dma->dma_rx && rx_buf != NULL) {
t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
@@ -1277,7 +1293,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);
- if (status || omap2_mcspi_master_setup(mcspi) < 0)
+ status = omap2_mcspi_master_setup(mcspi);
+ if (status < 0)
goto disable_pm;
status = spi_register_master(master);
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 364964d2ed04..74bc18775658 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -22,7 +22,7 @@ static int ce4100_spi_probe(struct pci_dev *dev,
return ret;
ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
- if (!ret)
+ if (ret)
return ret;
memset(&spi_pdata, 0, sizeof(spi_pdata));
@@ -47,8 +47,8 @@ static int ce4100_spi_probe(struct pci_dev *dev,
pi.size_data = sizeof(spi_pdata);
pdev = platform_device_register_full(&pi);
- if (!pdev)
- return -ENOMEM;
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
pci_set_drvdata(dev, pdev);
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 90b27a3508a6..f5d84d6f8222 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h>
@@ -68,6 +69,7 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_TX_HITHRESH_DFLT 224
/* Offset from drv_data->lpss_base */
+#define SSP_REG 0x0c
#define SPI_CS_CONTROL 0x18
#define SPI_CS_CONTROL_SW_MODE BIT(0)
#define SPI_CS_CONTROL_CS_HIGH BIT(1)
@@ -138,6 +140,10 @@ detection_done:
/* Enable software chip select control */
value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
+
+ /* Enable multiblock DMA transfers */
+ if (drv_data->master_info->enable_dma)
+ __lpss_ssp_write_priv(drv_data, SSP_REG, 1);
}
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
@@ -1083,11 +1089,9 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
ssp = &pdata->ssp;
ssp->phys_base = res->start;
- ssp->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!ssp->mmio_base) {
- dev_err(&pdev->dev, "failed to ioremap mmio_base\n");
- return NULL;
- }
+ ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ssp->mmio_base))
+ return PTR_ERR(ssp->mmio_base);
ssp->clk = devm_clk_get(&pdev->dev, NULL);
ssp->irq = platform_get_irq(pdev, 0);
@@ -1168,7 +1172,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master->dev.parent = &pdev->dev;
master->dev.of_node = pdev->dev.of_node;
- ACPI_HANDLE_SET(&master->dev, ACPI_HANDLE(&pdev->dev));
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index e862ab8853aa..5000586cb98d 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -31,9 +32,12 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <mach/dma.h>
#include <linux/platform_data/spi-s3c64xx.h>
+#ifdef CONFIG_S3C_DMA
+#include <mach/dma.h>
+#endif
+
#define MAX_SPI_PORTS 3
/* Registers and bit-fields */
@@ -131,9 +135,9 @@
#define TXBUSY (1<<3)
struct s3c64xx_spi_dma_data {
- unsigned ch;
+ struct dma_chan *ch;
enum dma_transfer_direction direction;
- enum dma_ch dmach;
+ unsigned int dmach;
};
/**
@@ -195,16 +199,14 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
+#ifdef CONFIG_S3C_DMA
struct samsung_dma_ops *ops;
+#endif
struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id;
unsigned long gpios[4];
};
-static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
- .name = "samsung-spi-dma",
-};
-
static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
{
void __iomem *regs = sdd->regs;
@@ -281,6 +283,13 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags);
}
+#ifdef CONFIG_S3C_DMA
+/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
+
+static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
+ .name = "samsung-spi-dma",
+};
+
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
unsigned len, dma_addr_t buf)
{
@@ -294,14 +303,14 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
config.direction = sdd->rx_dma.direction;
config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
config.width = sdd->cur_bpw / 8;
- sdd->ops->config(sdd->rx_dma.ch, &config);
+ sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
} else {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, tx_dma);
config.direction = sdd->tx_dma.direction;
config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
config.width = sdd->cur_bpw / 8;
- sdd->ops->config(sdd->tx_dma.ch, &config);
+ sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
}
info.cap = DMA_SLAVE;
@@ -311,8 +320,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
info.direction = dma->direction;
info.buf = buf;
- sdd->ops->prepare(dma->ch, &info);
- sdd->ops->trigger(dma->ch);
+ sdd->ops->prepare((enum dma_ch)dma->ch, &info);
+ sdd->ops->trigger((enum dma_ch)dma->ch);
}
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
@@ -325,12 +334,150 @@ static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
req.cap = DMA_SLAVE;
req.client = &s3c64xx_spi_dma_client;
- sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
- sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
+ sdd->rx_dma.ch = (void *)sdd->ops->request(sdd->rx_dma.dmach, &req, dev, "rx");
+ sdd->tx_dma.ch = (void *)sdd->ops->request(sdd->tx_dma.dmach, &req, dev, "tx");
return 1;
}
+static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
+{
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+
+ /* Acquire DMA channels */
+ while (!acquire_dma(sdd))
+ usleep_range(10000, 11000);
+
+ pm_runtime_get_sync(&sdd->pdev->dev);
+
+ return 0;
+}
+
+static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
+{
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+
+ /* Free DMA channels */
+ sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
+ sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
+
+ pm_runtime_put(&sdd->pdev->dev);
+
+ return 0;
+}
+
+static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
+ struct s3c64xx_spi_dma_data *dma)
+{
+ sdd->ops->stop((enum dma_ch)dma->ch);
+}
+#else
+
+static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
+ unsigned len, dma_addr_t buf)
+{
+ struct s3c64xx_spi_driver_data *sdd;
+ struct dma_slave_config config;
+ struct scatterlist sg;
+ struct dma_async_tx_descriptor *desc;
+
+ if (dma->direction == DMA_DEV_TO_MEM) {
+ sdd = container_of((void *)dma,
+ struct s3c64xx_spi_driver_data, rx_dma);
+ config.direction = dma->direction;
+ config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+ config.src_addr_width = sdd->cur_bpw / 8;
+ config.src_maxburst = 1;
+ dmaengine_slave_config(dma->ch, &config);
+ } else {
+ sdd = container_of((void *)dma,
+ struct s3c64xx_spi_driver_data, tx_dma);
+ config.direction = dma->direction;
+ config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+ config.dst_addr_width = sdd->cur_bpw / 8;
+ config.dst_maxburst = 1;
+ dmaengine_slave_config(dma->ch, &config);
+ }
+
+ sg_init_table(&sg, 1);
+ sg_dma_len(&sg) = len;
+ sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
+ len, offset_in_page(buf));
+ sg_dma_address(&sg) = buf;
+
+ desc = dmaengine_prep_slave_sg(dma->ch,
+ &sg, 1, dma->direction, DMA_PREP_INTERRUPT);
+
+ desc->callback = s3c64xx_spi_dmacb;
+ desc->callback_param = dma;
+
+ dmaengine_submit(desc);
+ dma_async_issue_pending(dma->ch);
+}
+
+static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
+{
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+ dma_filter_fn filter = sdd->cntrlr_info->filter;
+ struct device *dev = &sdd->pdev->dev;
+ dma_cap_mask_t mask;
+ int ret;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /* Acquire DMA channels */
+ sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ (void*)sdd->rx_dma.dmach, dev, "rx");
+ if (!sdd->rx_dma.ch) {
+ dev_err(dev, "Failed to get RX DMA channel\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
+ (void*)sdd->tx_dma.dmach, dev, "tx");
+ if (!sdd->tx_dma.ch) {
+ dev_err(dev, "Failed to get TX DMA channel\n");
+ ret = -EBUSY;
+ goto out_rx;
+ }
+
+ ret = pm_runtime_get_sync(&sdd->pdev->dev);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable device: %d\n", ret);
+ goto out_tx;
+ }
+
+ return 0;
+
+out_tx:
+ dma_release_channel(sdd->tx_dma.ch);
+out_rx:
+ dma_release_channel(sdd->rx_dma.ch);
+out:
+ return ret;
+}
+
+static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
+{
+ struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+
+ /* Free DMA channels */
+ dma_release_channel(sdd->rx_dma.ch);
+ dma_release_channel(sdd->tx_dma.ch);
+
+ pm_runtime_put(&sdd->pdev->dev);
+ return 0;
+}
+
+static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
+ struct s3c64xx_spi_dma_data *dma)
+{
+ dmaengine_terminate_all(dma->ch);
+}
+#endif
+
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi,
struct spi_transfer *xfer, int dma_mode)
@@ -713,9 +860,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
}
/* Polling method for xfers not bigger than FIFO capacity */
- if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
- use_dma = 0;
- else
+ use_dma = 0;
+ if (sdd->rx_dma.ch && sdd->tx_dma.ch &&
+ (xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))
use_dma = 1;
spin_lock_irqsave(&sdd->lock, flags);
@@ -750,10 +897,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
if (use_dma) {
if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY))
- sdd->ops->stop(sdd->tx_dma.ch);
+ s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY))
- sdd->ops->stop(sdd->rx_dma.ch);
+ s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
}
goto out;
@@ -790,34 +937,7 @@ out:
return 0;
}
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /* Acquire DMA channels */
- while (!acquire_dma(sdd))
- usleep_range(10000, 11000);
-
- pm_runtime_get_sync(&sdd->pdev->dev);
-
- return 0;
-}
-
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
-{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
-
- /* Free DMA channels */
- sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
- sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
-
- pm_runtime_put(&sdd->pdev->dev);
-
- return 0;
-}
-
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
- struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs;
@@ -874,7 +994,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
sdd = spi_master_get_devdata(spi->master);
if (!cs && spi->dev.of_node) {
- cs = s3c64xx_get_slave_ctrldata(sdd, spi);
+ cs = s3c64xx_get_slave_ctrldata(spi);
spi->controller_data = cs;
}
@@ -912,15 +1032,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
spin_unlock_irqrestore(&sdd->lock, flags);
- if (spi->bits_per_word != 8
- && spi->bits_per_word != 16
- && spi->bits_per_word != 32) {
- dev_err(&spi->dev, "setup: %dbits/wrd not supported!\n",
- spi->bits_per_word);
- err = -EINVAL;
- goto setup_exit;
- }
-
pm_runtime_get_sync(&sdd->pdev->dev);
/* Check if we can provide the requested rate */
@@ -994,25 +1105,30 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
{
struct s3c64xx_spi_driver_data *sdd = data;
struct spi_master *spi = sdd->master;
- unsigned int val;
-
- val = readl(sdd->regs + S3C64XX_SPI_PENDING_CLR);
+ unsigned int val, clr = 0;
- val &= S3C64XX_SPI_PND_RX_OVERRUN_CLR |
- S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
- S3C64XX_SPI_PND_TX_OVERRUN_CLR |
- S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
+ val = readl(sdd->regs + S3C64XX_SPI_STATUS);
- writel(val, sdd->regs + S3C64XX_SPI_PENDING_CLR);
-
- if (val & S3C64XX_SPI_PND_RX_OVERRUN_CLR)
+ if (val & S3C64XX_SPI_ST_RX_OVERRUN_ERR) {
+ clr = S3C64XX_SPI_PND_RX_OVERRUN_CLR;
dev_err(&spi->dev, "RX overrun\n");
- if (val & S3C64XX_SPI_PND_RX_UNDERRUN_CLR)
+ }
+ if (val & S3C64XX_SPI_ST_RX_UNDERRUN_ERR) {
+ clr |= S3C64XX_SPI_PND_RX_UNDERRUN_CLR;
dev_err(&spi->dev, "RX underrun\n");
- if (val & S3C64XX_SPI_PND_TX_OVERRUN_CLR)
+ }
+ if (val & S3C64XX_SPI_ST_TX_OVERRUN_ERR) {
+ clr |= S3C64XX_SPI_PND_TX_OVERRUN_CLR;
dev_err(&spi->dev, "TX overrun\n");
- if (val & S3C64XX_SPI_PND_TX_UNDERRUN_CLR)
+ }
+ if (val & S3C64XX_SPI_ST_TX_UNDERRUN_ERR) {
+ clr |= S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
dev_err(&spi->dev, "TX underrun\n");
+ }
+
+ /* Clear the pending irq by setting and then clearing it */
+ writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR);
+ writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR);
return IRQ_HANDLED;
}
@@ -1036,9 +1152,13 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
writel(0, regs + S3C64XX_SPI_MODE_CFG);
writel(0, regs + S3C64XX_SPI_PACKET_CNT);
- /* Clear any irq pending bits */
- writel(readl(regs + S3C64XX_SPI_PENDING_CLR),
- regs + S3C64XX_SPI_PENDING_CLR);
+ /* Clear any irq pending bits, should set and clear the bits */
+ val = S3C64XX_SPI_PND_RX_OVERRUN_CLR |
+ S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
+ S3C64XX_SPI_PND_TX_OVERRUN_CLR |
+ S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
+ writel(val, regs + S3C64XX_SPI_PENDING_CLR);
+ writel(0, regs + S3C64XX_SPI_PENDING_CLR);
writel(0, regs + S3C64XX_SPI_SWAP_CFG);
@@ -1052,41 +1172,6 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
}
#ifdef CONFIG_OF
-static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
-{
- struct device *dev = &sdd->pdev->dev;
- int idx, gpio, ret;
-
- /* find gpios for mosi, miso and clock lines */
- for (idx = 0; idx < 3; idx++) {
- gpio = of_get_gpio(dev->of_node, idx);
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
- goto free_gpio;
- }
- sdd->gpios[idx] = gpio;
- ret = gpio_request(gpio, "spi-bus");
- if (ret) {
- dev_err(dev, "gpio [%d] request failed: %d\n",
- gpio, ret);
- goto free_gpio;
- }
- }
- return 0;
-
-free_gpio:
- while (--idx >= 0)
- gpio_free(sdd->gpios[idx]);
- return -EINVAL;
-}
-
-static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
-{
- unsigned int idx;
- for (idx = 0; idx < 3; idx++)
- gpio_free(sdd->gpios[idx]);
-}
-
static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
{
struct s3c64xx_spi_info *sci;
@@ -1119,15 +1204,6 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
{
return dev->platform_data;
}
-
-static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd)
-{
- return -EINVAL;
-}
-
-static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd)
-{
-}
#endif
static const struct of_device_id s3c64xx_spi_dt_match[];
@@ -1238,6 +1314,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
+ master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
@@ -1247,10 +1324,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
goto err0;
}
- if (!sci->cfg_gpio && pdev->dev.of_node) {
- if (s3c64xx_spi_parse_dt_gpio(sdd))
- return -EBUSY;
- } else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) {
+ if (sci->cfg_gpio && sci->cfg_gpio()) {
dev_err(&pdev->dev, "Unable to config gpio\n");
ret = -EBUSY;
goto err0;
@@ -1261,13 +1335,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(sdd->clk)) {
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
ret = PTR_ERR(sdd->clk);
- goto err1;
+ goto err0;
}
if (clk_prepare_enable(sdd->clk)) {
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
ret = -EBUSY;
- goto err1;
+ goto err0;
}
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
@@ -1324,9 +1398,6 @@ err3:
clk_disable_unprepare(sdd->src_clk);
err2:
clk_disable_unprepare(sdd->clk);
-err1:
- if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
- s3c64xx_spi_dt_gpio_free(sdd);
err0:
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
@@ -1349,16 +1420,13 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(sdd->clk);
- if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node)
- s3c64xx_spi_dt_gpio_free(sdd);
-
platform_set_drvdata(pdev, NULL);
spi_master_put(master);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int s3c64xx_spi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
@@ -1370,9 +1438,6 @@ static int s3c64xx_spi_suspend(struct device *dev)
clk_disable_unprepare(sdd->src_clk);
clk_disable_unprepare(sdd->clk);
- if (!sdd->cntrlr_info->cfg_gpio && dev->of_node)
- s3c64xx_spi_dt_gpio_free(sdd);
-
sdd->cur_speed = 0; /* Output Clock is stopped */
return 0;
@@ -1384,9 +1449,7 @@ static int s3c64xx_spi_resume(struct device *dev)
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
- if (!sci->cfg_gpio && dev->of_node)
- s3c64xx_spi_parse_dt_gpio(sdd);
- else
+ if (sci->cfg_gpio)
sci->cfg_gpio();
/* Enable the clock */
@@ -1399,7 +1462,7 @@ static int s3c64xx_spi_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
static int s3c64xx_spi_runtime_suspend(struct device *dev)
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 8b40d0884f8b..2bc5a6b86300 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -764,8 +764,6 @@ static const struct of_device_id sh_msiof_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
-#else
-#define sh_msiof_match NULL
#endif
static struct dev_pm_ops sh_msiof_spi_dev_pm_ops = {
@@ -780,7 +778,7 @@ static struct platform_driver sh_msiof_spi_drv = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,
.pm = &sh_msiof_spi_dev_pm_ops,
- .of_match_table = sh_msiof_match,
+ .of_match_table = of_match_ptr(sh_msiof_match),
},
};
module_platform_driver(sh_msiof_spi_drv);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index f59d4177b419..0808cd56bf8d 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -660,7 +660,7 @@ static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,marco-spi", },
{}
};
-MODULE_DEVICE_TABLE(of, sirfsoc_spi_of_match);
+MODULE_DEVICE_TABLE(of, spi_sirfsoc_of_match);
static struct platform_driver spi_sirfsoc_driver = {
.driver = {
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
new file mode 100644
index 000000000000..598eb45e8008
--- /dev/null
+++ b/drivers/spi/spi-tegra114.c
@@ -0,0 +1,1246 @@
+/*
+ * SPI driver for NVIDIA's Tegra114 SPI Controller.
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION. 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/clk.h>
+#include <linux/clk/tegra.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+#define SPI_COMMAND1 0x000
+#define SPI_BIT_LENGTH(x) (((x) & 0x1f) << 0)
+#define SPI_PACKED (1 << 5)
+#define SPI_TX_EN (1 << 11)
+#define SPI_RX_EN (1 << 12)
+#define SPI_BOTH_EN_BYTE (1 << 13)
+#define SPI_BOTH_EN_BIT (1 << 14)
+#define SPI_LSBYTE_FE (1 << 15)
+#define SPI_LSBIT_FE (1 << 16)
+#define SPI_BIDIROE (1 << 17)
+#define SPI_IDLE_SDA_DRIVE_LOW (0 << 18)
+#define SPI_IDLE_SDA_DRIVE_HIGH (1 << 18)
+#define SPI_IDLE_SDA_PULL_LOW (2 << 18)
+#define SPI_IDLE_SDA_PULL_HIGH (3 << 18)
+#define SPI_IDLE_SDA_MASK (3 << 18)
+#define SPI_CS_SS_VAL (1 << 20)
+#define SPI_CS_SW_HW (1 << 21)
+/* SPI_CS_POL_INACTIVE bits are default high */
+#define SPI_CS_POL_INACTIVE 22
+#define SPI_CS_POL_INACTIVE_0 (1 << 22)
+#define SPI_CS_POL_INACTIVE_1 (1 << 23)
+#define SPI_CS_POL_INACTIVE_2 (1 << 24)
+#define SPI_CS_POL_INACTIVE_3 (1 << 25)
+#define SPI_CS_POL_INACTIVE_MASK (0xF << 22)
+
+#define SPI_CS_SEL_0 (0 << 26)
+#define SPI_CS_SEL_1 (1 << 26)
+#define SPI_CS_SEL_2 (2 << 26)
+#define SPI_CS_SEL_3 (3 << 26)
+#define SPI_CS_SEL_MASK (3 << 26)
+#define SPI_CS_SEL(x) (((x) & 0x3) << 26)
+#define SPI_CONTROL_MODE_0 (0 << 28)
+#define SPI_CONTROL_MODE_1 (1 << 28)
+#define SPI_CONTROL_MODE_2 (2 << 28)
+#define SPI_CONTROL_MODE_3 (3 << 28)
+#define SPI_CONTROL_MODE_MASK (3 << 28)
+#define SPI_MODE_SEL(x) (((x) & 0x3) << 28)
+#define SPI_M_S (1 << 30)
+#define SPI_PIO (1 << 31)
+
+#define SPI_COMMAND2 0x004
+#define SPI_TX_TAP_DELAY(x) (((x) & 0x3F) << 6)
+#define SPI_RX_TAP_DELAY(x) (((x) & 0x3F) << 0)
+
+#define SPI_CS_TIMING1 0x008
+#define SPI_SETUP_HOLD(setup, hold) (((setup) << 4) | (hold))
+#define SPI_CS_SETUP_HOLD(reg, cs, val) \
+ ((((val) & 0xFFu) << ((cs) * 8)) | \
+ ((reg) & ~(0xFFu << ((cs) * 8))))
+
+#define SPI_CS_TIMING2 0x00C
+#define CYCLES_BETWEEN_PACKETS_0(x) (((x) & 0x1F) << 0)
+#define CS_ACTIVE_BETWEEN_PACKETS_0 (1 << 5)
+#define CYCLES_BETWEEN_PACKETS_1(x) (((x) & 0x1F) << 8)
+#define CS_ACTIVE_BETWEEN_PACKETS_1 (1 << 13)
+#define CYCLES_BETWEEN_PACKETS_2(x) (((x) & 0x1F) << 16)
+#define CS_ACTIVE_BETWEEN_PACKETS_2 (1 << 21)
+#define CYCLES_BETWEEN_PACKETS_3(x) (((x) & 0x1F) << 24)
+#define CS_ACTIVE_BETWEEN_PACKETS_3 (1 << 29)
+#define SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(reg, cs, val) \
+ (reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \
+ ((reg) & ~(1 << ((cs) * 8 + 5))))
+#define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \
+ (reg = (((val) & 0xF) << ((cs) * 8)) | \
+ ((reg) & ~(0xF << ((cs) * 8))))
+
+#define SPI_TRANS_STATUS 0x010
+#define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF)
+#define SPI_SLV_IDLE_COUNT(val) (((val) >> 16) & 0xFF)
+#define SPI_RDY (1 << 30)
+
+#define SPI_FIFO_STATUS 0x014
+#define SPI_RX_FIFO_EMPTY (1 << 0)
+#define SPI_RX_FIFO_FULL (1 << 1)
+#define SPI_TX_FIFO_EMPTY (1 << 2)
+#define SPI_TX_FIFO_FULL (1 << 3)
+#define SPI_RX_FIFO_UNF (1 << 4)
+#define SPI_RX_FIFO_OVF (1 << 5)
+#define SPI_TX_FIFO_UNF (1 << 6)
+#define SPI_TX_FIFO_OVF (1 << 7)
+#define SPI_ERR (1 << 8)
+#define SPI_TX_FIFO_FLUSH (1 << 14)
+#define SPI_RX_FIFO_FLUSH (1 << 15)
+#define SPI_TX_FIFO_EMPTY_COUNT(val) (((val) >> 16) & 0x7F)
+#define SPI_RX_FIFO_FULL_COUNT(val) (((val) >> 23) & 0x7F)
+#define SPI_FRAME_END (1 << 30)
+#define SPI_CS_INACTIVE (1 << 31)
+
+#define SPI_FIFO_ERROR (SPI_RX_FIFO_UNF | \
+ SPI_RX_FIFO_OVF | SPI_TX_FIFO_UNF | SPI_TX_FIFO_OVF)
+#define SPI_FIFO_EMPTY (SPI_RX_FIFO_EMPTY | SPI_TX_FIFO_EMPTY)
+
+#define SPI_TX_DATA 0x018
+#define SPI_RX_DATA 0x01C
+
+#define SPI_DMA_CTL 0x020
+#define SPI_TX_TRIG_1 (0 << 15)
+#define SPI_TX_TRIG_4 (1 << 15)
+#define SPI_TX_TRIG_8 (2 << 15)
+#define SPI_TX_TRIG_16 (3 << 15)
+#define SPI_TX_TRIG_MASK (3 << 15)
+#define SPI_RX_TRIG_1 (0 << 19)
+#define SPI_RX_TRIG_4 (1 << 19)
+#define SPI_RX_TRIG_8 (2 << 19)
+#define SPI_RX_TRIG_16 (3 << 19)
+#define SPI_RX_TRIG_MASK (3 << 19)
+#define SPI_IE_TX (1 << 28)
+#define SPI_IE_RX (1 << 29)
+#define SPI_CONT (1 << 30)
+#define SPI_DMA (1 << 31)
+#define SPI_DMA_EN SPI_DMA
+
+#define SPI_DMA_BLK 0x024
+#define SPI_DMA_BLK_SET(x) (((x) & 0xFFFF) << 0)
+
+#define SPI_TX_FIFO 0x108
+#define SPI_RX_FIFO 0x188
+#define MAX_CHIP_SELECT 4
+#define SPI_FIFO_DEPTH 64
+#define DATA_DIR_TX (1 << 0)
+#define DATA_DIR_RX (1 << 1)
+
+#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
+#define DEFAULT_SPI_DMA_BUF_LEN (16*1024)
+#define TX_FIFO_EMPTY_COUNT_MAX SPI_TX_FIFO_EMPTY_COUNT(0x40)
+#define RX_FIFO_FULL_COUNT_ZERO SPI_RX_FIFO_FULL_COUNT(0)
+#define MAX_HOLD_CYCLES 16
+#define SPI_DEFAULT_SPEED 25000000
+
+#define MAX_CHIP_SELECT 4
+#define SPI_FIFO_DEPTH 64
+
+struct tegra_spi_data {
+ struct device *dev;
+ struct spi_master *master;
+ spinlock_t lock;
+
+ struct clk *clk;
+ void __iomem *base;
+ phys_addr_t phys;
+ unsigned irq;
+ int dma_req_sel;
+ u32 spi_max_frequency;
+ u32 cur_speed;
+
+ struct spi_device *cur_spi;
+ unsigned cur_pos;
+ unsigned cur_len;
+ unsigned words_per_32bit;
+ unsigned bytes_per_word;
+ unsigned curr_dma_words;
+ unsigned cur_direction;
+
+ unsigned cur_rx_pos;
+ unsigned cur_tx_pos;
+
+ unsigned dma_buf_size;
+ unsigned max_buf_size;
+ bool is_curr_dma_xfer;
+
+ struct completion rx_dma_complete;
+ struct completion tx_dma_complete;
+
+ u32 tx_status;
+ u32 rx_status;
+ u32 status_reg;
+ bool is_packed;
+ unsigned long packed_size;
+
+ u32 command1_reg;
+ u32 dma_control_reg;
+ u32 def_command1_reg;
+ u32 spi_cs_timing;
+
+ struct completion xfer_completion;
+ struct spi_transfer *curr_xfer;
+ struct dma_chan *rx_dma_chan;
+ u32 *rx_dma_buf;
+ dma_addr_t rx_dma_phys;
+ struct dma_async_tx_descriptor *rx_dma_desc;
+
+ struct dma_chan *tx_dma_chan;
+ u32 *tx_dma_buf;
+ dma_addr_t tx_dma_phys;
+ struct dma_async_tx_descriptor *tx_dma_desc;
+};
+
+static int tegra_spi_runtime_suspend(struct device *dev);
+static int tegra_spi_runtime_resume(struct device *dev);
+
+static inline unsigned long tegra_spi_readl(struct tegra_spi_data *tspi,
+ unsigned long reg)
+{
+ return readl(tspi->base + reg);
+}
+
+static inline void tegra_spi_writel(struct tegra_spi_data *tspi,
+ unsigned long val, unsigned long reg)
+{
+ writel(val, tspi->base + reg);
+
+ /* Read back register to make sure that register writes completed */
+ if (reg != SPI_TX_FIFO)
+ readl(tspi->base + SPI_COMMAND1);
+}
+
+static void tegra_spi_clear_status(struct tegra_spi_data *tspi)
+{
+ unsigned long val;
+
+ /* Write 1 to clear status register */
+ val = tegra_spi_readl(tspi, SPI_TRANS_STATUS);
+ tegra_spi_writel(tspi, val, SPI_TRANS_STATUS);
+
+ /* Clear fifo status error if any */
+ val = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ if (val & SPI_ERR)
+ tegra_spi_writel(tspi, SPI_ERR | SPI_FIFO_ERROR,
+ SPI_FIFO_STATUS);
+}
+
+static unsigned tegra_spi_calculate_curr_xfer_param(
+ struct spi_device *spi, struct tegra_spi_data *tspi,
+ struct spi_transfer *t)
+{
+ unsigned remain_len = t->len - tspi->cur_pos;
+ unsigned max_word;
+ unsigned bits_per_word = t->bits_per_word;
+ unsigned max_len;
+ unsigned total_fifo_words;
+
+ tspi->bytes_per_word = (bits_per_word - 1) / 8 + 1;
+
+ if (bits_per_word == 8 || bits_per_word == 16) {
+ tspi->is_packed = 1;
+ tspi->words_per_32bit = 32/bits_per_word;
+ } else {
+ tspi->is_packed = 0;
+ tspi->words_per_32bit = 1;
+ }
+
+ if (tspi->is_packed) {
+ max_len = min(remain_len, tspi->max_buf_size);
+ tspi->curr_dma_words = max_len/tspi->bytes_per_word;
+ total_fifo_words = (max_len + 3) / 4;
+ } else {
+ max_word = (remain_len - 1) / tspi->bytes_per_word + 1;
+ max_word = min(max_word, tspi->max_buf_size/4);
+ tspi->curr_dma_words = max_word;
+ total_fifo_words = max_word;
+ }
+ return total_fifo_words;
+}
+
+static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned nbytes;
+ unsigned tx_empty_count;
+ unsigned long fifo_status;
+ unsigned max_n_32bit;
+ unsigned i, count;
+ unsigned long x;
+ unsigned int written_words;
+ unsigned fifo_words_left;
+ u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
+
+ fifo_status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ tx_empty_count = SPI_TX_FIFO_EMPTY_COUNT(fifo_status);
+
+ if (tspi->is_packed) {
+ fifo_words_left = tx_empty_count * tspi->words_per_32bit;
+ written_words = min(fifo_words_left, tspi->curr_dma_words);
+ nbytes = written_words * tspi->bytes_per_word;
+ max_n_32bit = DIV_ROUND_UP(nbytes, 4);
+ for (count = 0; count < max_n_32bit; count++) {
+ x = 0;
+ for (i = 0; (i < 4) && nbytes; i++, nbytes--)
+ x |= (*tx_buf++) << (i*8);
+ tegra_spi_writel(tspi, x, SPI_TX_FIFO);
+ }
+ } else {
+ max_n_32bit = min(tspi->curr_dma_words, tx_empty_count);
+ written_words = max_n_32bit;
+ nbytes = written_words * tspi->bytes_per_word;
+ for (count = 0; count < max_n_32bit; count++) {
+ x = 0;
+ for (i = 0; nbytes && (i < tspi->bytes_per_word);
+ i++, nbytes--)
+ x |= ((*tx_buf++) << i*8);
+ tegra_spi_writel(tspi, x, SPI_TX_FIFO);
+ }
+ }
+ tspi->cur_tx_pos += written_words * tspi->bytes_per_word;
+ return written_words;
+}
+
+static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned rx_full_count;
+ unsigned long fifo_status;
+ unsigned i, count;
+ unsigned long x;
+ unsigned int read_words = 0;
+ unsigned len;
+ u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos;
+
+ fifo_status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ rx_full_count = SPI_RX_FIFO_FULL_COUNT(fifo_status);
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ for (count = 0; count < rx_full_count; count++) {
+ x = tegra_spi_readl(tspi, SPI_RX_FIFO);
+ for (i = 0; len && (i < 4); i++, len--)
+ *rx_buf++ = (x >> i*8) & 0xFF;
+ }
+ tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+ read_words += tspi->curr_dma_words;
+ } else {
+ unsigned int rx_mask;
+ unsigned int bits_per_word = t->bits_per_word;
+
+ rx_mask = (1 << bits_per_word) - 1;
+ for (count = 0; count < rx_full_count; count++) {
+ x = tegra_spi_readl(tspi, SPI_RX_FIFO);
+ x &= rx_mask;
+ for (i = 0; (i < tspi->bytes_per_word); i++)
+ *rx_buf++ = (x >> (i*8)) & 0xFF;
+ }
+ tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word;
+ read_words += rx_full_count;
+ }
+ return read_words;
+}
+
+static void tegra_spi_copy_client_txbuf_to_spi_txbuf(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned len;
+
+ /* Make the dma buffer to read by cpu */
+ dma_sync_single_for_cpu(tspi->dev, tspi->tx_dma_phys,
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len);
+ } else {
+ unsigned int i;
+ unsigned int count;
+ u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos;
+ unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word;
+ unsigned int x;
+
+ for (count = 0; count < tspi->curr_dma_words; count++) {
+ x = 0;
+ for (i = 0; consume && (i < tspi->bytes_per_word);
+ i++, consume--)
+ x |= ((*tx_buf++) << i * 8);
+ tspi->tx_dma_buf[count] = x;
+ }
+ }
+ tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys,
+ tspi->dma_buf_size, DMA_TO_DEVICE);
+}
+
+static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned len;
+
+ /* Make the dma buffer to read by cpu */
+ dma_sync_single_for_cpu(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
+ if (tspi->is_packed) {
+ len = tspi->curr_dma_words * tspi->bytes_per_word;
+ memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len);
+ } else {
+ unsigned int i;
+ unsigned int count;
+ unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos;
+ unsigned int x;
+ unsigned int rx_mask;
+ unsigned int bits_per_word = t->bits_per_word;
+
+ rx_mask = (1 << bits_per_word) - 1;
+ for (count = 0; count < tspi->curr_dma_words; count++) {
+ x = tspi->rx_dma_buf[count];
+ x &= rx_mask;
+ for (i = 0; (i < tspi->bytes_per_word); i++)
+ *rx_buf++ = (x >> (i*8)) & 0xFF;
+ }
+ }
+ tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
+
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+}
+
+static void tegra_spi_dma_complete(void *args)
+{
+ struct completion *dma_complete = args;
+
+ complete(dma_complete);
+}
+
+static int tegra_spi_start_tx_dma(struct tegra_spi_data *tspi, int len)
+{
+ INIT_COMPLETION(tspi->tx_dma_complete);
+ tspi->tx_dma_desc = dmaengine_prep_slave_single(tspi->tx_dma_chan,
+ tspi->tx_dma_phys, len, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tspi->tx_dma_desc) {
+ dev_err(tspi->dev, "Not able to get desc for Tx\n");
+ return -EIO;
+ }
+
+ tspi->tx_dma_desc->callback = tegra_spi_dma_complete;
+ tspi->tx_dma_desc->callback_param = &tspi->tx_dma_complete;
+
+ dmaengine_submit(tspi->tx_dma_desc);
+ dma_async_issue_pending(tspi->tx_dma_chan);
+ return 0;
+}
+
+static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len)
+{
+ INIT_COMPLETION(tspi->rx_dma_complete);
+ tspi->rx_dma_desc = dmaengine_prep_slave_single(tspi->rx_dma_chan,
+ tspi->rx_dma_phys, len, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tspi->rx_dma_desc) {
+ dev_err(tspi->dev, "Not able to get desc for Rx\n");
+ return -EIO;
+ }
+
+ tspi->rx_dma_desc->callback = tegra_spi_dma_complete;
+ tspi->rx_dma_desc->callback_param = &tspi->rx_dma_complete;
+
+ dmaengine_submit(tspi->rx_dma_desc);
+ dma_async_issue_pending(tspi->rx_dma_chan);
+ return 0;
+}
+
+static int tegra_spi_start_dma_based_transfer(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned long val;
+ unsigned int len;
+ int ret = 0;
+ unsigned long status;
+
+ /* Make sure that Rx and Tx fifo are empty */
+ status = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) {
+ dev_err(tspi->dev,
+ "Rx/Tx fifo are not empty status 0x%08lx\n", status);
+ return -EIO;
+ }
+
+ val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1);
+ tegra_spi_writel(tspi, val, SPI_DMA_BLK);
+
+ if (tspi->is_packed)
+ len = DIV_ROUND_UP(tspi->curr_dma_words * tspi->bytes_per_word,
+ 4) * 4;
+ else
+ len = tspi->curr_dma_words * 4;
+
+ /* Set attention level based on length of transfer */
+ if (len & 0xF)
+ val |= SPI_TX_TRIG_1 | SPI_RX_TRIG_1;
+ else if (((len) >> 4) & 0x1)
+ val |= SPI_TX_TRIG_4 | SPI_RX_TRIG_4;
+ else
+ val |= SPI_TX_TRIG_8 | SPI_RX_TRIG_8;
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SPI_IE_TX;
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SPI_IE_RX;
+
+ tegra_spi_writel(tspi, val, SPI_DMA_CTL);
+ tspi->dma_control_reg = val;
+
+ if (tspi->cur_direction & DATA_DIR_TX) {
+ tegra_spi_copy_client_txbuf_to_spi_txbuf(tspi, t);
+ ret = tegra_spi_start_tx_dma(tspi, len);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "Starting tx dma failed, err %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX) {
+ /* Make the dma buffer to read by dma */
+ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys,
+ tspi->dma_buf_size, DMA_FROM_DEVICE);
+
+ ret = tegra_spi_start_rx_dma(tspi, len);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "Starting rx dma failed, err %d\n", ret);
+ if (tspi->cur_direction & DATA_DIR_TX)
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ return ret;
+ }
+ }
+ tspi->is_curr_dma_xfer = true;
+ tspi->dma_control_reg = val;
+
+ val |= SPI_DMA_EN;
+ tegra_spi_writel(tspi, val, SPI_DMA_CTL);
+ return ret;
+}
+
+static int tegra_spi_start_cpu_based_transfer(
+ struct tegra_spi_data *tspi, struct spi_transfer *t)
+{
+ unsigned long val;
+ unsigned cur_words;
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ cur_words = tegra_spi_fill_tx_fifo_from_client_txbuf(tspi, t);
+ else
+ cur_words = tspi->curr_dma_words;
+
+ val = SPI_DMA_BLK_SET(cur_words - 1);
+ tegra_spi_writel(tspi, val, SPI_DMA_BLK);
+
+ val = 0;
+ if (tspi->cur_direction & DATA_DIR_TX)
+ val |= SPI_IE_TX;
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ val |= SPI_IE_RX;
+
+ tegra_spi_writel(tspi, val, SPI_DMA_CTL);
+ tspi->dma_control_reg = val;
+
+ tspi->is_curr_dma_xfer = false;
+
+ val |= SPI_DMA_EN;
+ tegra_spi_writel(tspi, val, SPI_DMA_CTL);
+ return 0;
+}
+
+static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
+ bool dma_to_memory)
+{
+ struct dma_chan *dma_chan;
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+ int ret;
+ struct dma_slave_config dma_sconfig;
+ dma_cap_mask_t mask;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_chan = dma_request_channel(mask, NULL, NULL);
+ if (!dma_chan) {
+ dev_err(tspi->dev,
+ "Dma channel is not available, will try later\n");
+ return -EPROBE_DEFER;
+ }
+
+ dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size,
+ &dma_phys, GFP_KERNEL);
+ if (!dma_buf) {
+ dev_err(tspi->dev, " Not able to allocate the dma buffer\n");
+ dma_release_channel(dma_chan);
+ return -ENOMEM;
+ }
+
+ dma_sconfig.slave_id = tspi->dma_req_sel;
+ if (dma_to_memory) {
+ dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.src_maxburst = 0;
+ } else {
+ dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO;
+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.dst_maxburst = 0;
+ }
+
+ ret = dmaengine_slave_config(dma_chan, &dma_sconfig);
+ if (ret)
+ goto scrub;
+ if (dma_to_memory) {
+ tspi->rx_dma_chan = dma_chan;
+ tspi->rx_dma_buf = dma_buf;
+ tspi->rx_dma_phys = dma_phys;
+ } else {
+ tspi->tx_dma_chan = dma_chan;
+ tspi->tx_dma_buf = dma_buf;
+ tspi->tx_dma_phys = dma_phys;
+ }
+ return 0;
+
+scrub:
+ dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys);
+ dma_release_channel(dma_chan);
+ return ret;
+}
+
+static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
+ bool dma_to_memory)
+{
+ u32 *dma_buf;
+ dma_addr_t dma_phys;
+ struct dma_chan *dma_chan;
+
+ if (dma_to_memory) {
+ dma_buf = tspi->rx_dma_buf;
+ dma_chan = tspi->rx_dma_chan;
+ dma_phys = tspi->rx_dma_phys;
+ tspi->rx_dma_chan = NULL;
+ tspi->rx_dma_buf = NULL;
+ } else {
+ dma_buf = tspi->tx_dma_buf;
+ dma_chan = tspi->tx_dma_chan;
+ dma_phys = tspi->tx_dma_phys;
+ tspi->tx_dma_buf = NULL;
+ tspi->tx_dma_chan = NULL;
+ }
+ if (!dma_chan)
+ return;
+
+ dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys);
+ dma_release_channel(dma_chan);
+}
+
+static int tegra_spi_start_transfer_one(struct spi_device *spi,
+ struct spi_transfer *t, bool is_first_of_msg,
+ bool is_single_xfer)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ u32 speed = t->speed_hz;
+ u8 bits_per_word = t->bits_per_word;
+ unsigned total_fifo_words;
+ int ret;
+ unsigned long command1;
+ int req_mode;
+
+ if (speed != tspi->cur_speed) {
+ clk_set_rate(tspi->clk, speed);
+ tspi->cur_speed = speed;
+ }
+
+ tspi->cur_spi = spi;
+ tspi->cur_pos = 0;
+ tspi->cur_rx_pos = 0;
+ tspi->cur_tx_pos = 0;
+ tspi->curr_xfer = t;
+ total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t);
+
+ if (is_first_of_msg) {
+ tegra_spi_clear_status(tspi);
+
+ command1 = tspi->def_command1_reg;
+ command1 |= SPI_BIT_LENGTH(bits_per_word - 1);
+
+ command1 &= ~SPI_CONTROL_MODE_MASK;
+ req_mode = spi->mode & 0x3;
+ if (req_mode == SPI_MODE_0)
+ command1 |= SPI_CONTROL_MODE_0;
+ else if (req_mode == SPI_MODE_1)
+ command1 |= SPI_CONTROL_MODE_1;
+ else if (req_mode == SPI_MODE_2)
+ command1 |= SPI_CONTROL_MODE_2;
+ else if (req_mode == SPI_MODE_3)
+ command1 |= SPI_CONTROL_MODE_3;
+
+ tegra_spi_writel(tspi, command1, SPI_COMMAND1);
+
+ command1 |= SPI_CS_SW_HW;
+ if (spi->mode & SPI_CS_HIGH)
+ command1 |= SPI_CS_SS_VAL;
+ else
+ command1 &= ~SPI_CS_SS_VAL;
+
+ tegra_spi_writel(tspi, 0, SPI_COMMAND2);
+ } else {
+ command1 = tspi->command1_reg;
+ command1 &= ~SPI_BIT_LENGTH(~0);
+ command1 |= SPI_BIT_LENGTH(bits_per_word - 1);
+ }
+
+ if (tspi->is_packed)
+ command1 |= SPI_PACKED;
+
+ command1 &= ~(SPI_CS_SEL_MASK | SPI_TX_EN | SPI_RX_EN);
+ tspi->cur_direction = 0;
+ if (t->rx_buf) {
+ command1 |= SPI_RX_EN;
+ tspi->cur_direction |= DATA_DIR_RX;
+ }
+ if (t->tx_buf) {
+ command1 |= SPI_TX_EN;
+ tspi->cur_direction |= DATA_DIR_TX;
+ }
+ command1 |= SPI_CS_SEL(spi->chip_select);
+ tegra_spi_writel(tspi, command1, SPI_COMMAND1);
+ tspi->command1_reg = command1;
+
+ dev_dbg(tspi->dev, "The def 0x%x and written 0x%lx\n",
+ tspi->def_command1_reg, command1);
+
+ if (total_fifo_words > SPI_FIFO_DEPTH)
+ ret = tegra_spi_start_dma_based_transfer(tspi, t);
+ else
+ ret = tegra_spi_start_cpu_based_transfer(tspi, t);
+ return ret;
+}
+
+static int tegra_spi_setup(struct spi_device *spi)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ unsigned long val;
+ unsigned long flags;
+ int ret;
+ unsigned int cs_pol_bit[MAX_CHIP_SELECT] = {
+ SPI_CS_POL_INACTIVE_0,
+ SPI_CS_POL_INACTIVE_1,
+ SPI_CS_POL_INACTIVE_2,
+ SPI_CS_POL_INACTIVE_3,
+ };
+
+ dev_dbg(&spi->dev, "setup %d bpw, %scpol, %scpha, %dHz\n",
+ spi->bits_per_word,
+ spi->mode & SPI_CPOL ? "" : "~",
+ spi->mode & SPI_CPHA ? "" : "~",
+ spi->max_speed_hz);
+
+ BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
+
+ /* Set speed to the spi max fequency if spi device has not set */
+ spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
+
+ ret = pm_runtime_get_sync(tspi->dev);
+ if (ret < 0) {
+ dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+ return ret;
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ val = tspi->def_command1_reg;
+ if (spi->mode & SPI_CS_HIGH)
+ val &= ~cs_pol_bit[spi->chip_select];
+ else
+ val |= cs_pol_bit[spi->chip_select];
+ tspi->def_command1_reg = val;
+ tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+ spin_unlock_irqrestore(&tspi->lock, flags);
+
+ pm_runtime_put(tspi->dev);
+ return 0;
+}
+
+static int tegra_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
+{
+ bool is_first_msg = true;
+ int single_xfer;
+ struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct spi_transfer *xfer;
+ struct spi_device *spi = msg->spi;
+ int ret;
+
+ msg->status = 0;
+ msg->actual_length = 0;
+
+ ret = pm_runtime_get_sync(tspi->dev);
+ if (ret < 0) {
+ dev_err(tspi->dev, "runtime PM get failed: %d\n", ret);
+ msg->status = ret;
+ spi_finalize_current_message(master);
+ return ret;
+ }
+
+ single_xfer = list_is_singular(&msg->transfers);
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ INIT_COMPLETION(tspi->xfer_completion);
+ ret = tegra_spi_start_transfer_one(spi, xfer,
+ is_first_msg, single_xfer);
+ if (ret < 0) {
+ dev_err(tspi->dev,
+ "spi can not start transfer, err %d\n", ret);
+ goto exit;
+ }
+ is_first_msg = false;
+ ret = wait_for_completion_timeout(&tspi->xfer_completion,
+ SPI_DMA_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(tspi->dev,
+ "spi trasfer timeout, err %d\n", ret);
+ ret = -EIO;
+ goto exit;
+ }
+
+ if (tspi->tx_status || tspi->rx_status) {
+ dev_err(tspi->dev, "Error in Transfer\n");
+ ret = -EIO;
+ goto exit;
+ }
+ msg->actual_length += xfer->len;
+ if (xfer->cs_change && xfer->delay_usecs) {
+ tegra_spi_writel(tspi, tspi->def_command1_reg,
+ SPI_COMMAND1);
+ udelay(xfer->delay_usecs);
+ }
+ }
+ ret = 0;
+exit:
+ tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+ pm_runtime_put(tspi->dev);
+ msg->status = ret;
+ spi_finalize_current_message(master);
+ return ret;
+}
+
+static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
+{
+ struct spi_transfer *t = tspi->curr_xfer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ if (tspi->tx_status || tspi->rx_status) {
+ dev_err(tspi->dev, "CpuXfer ERROR bit set 0x%x\n",
+ tspi->status_reg);
+ dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n",
+ tspi->command1_reg, tspi->dma_control_reg);
+ tegra_periph_reset_assert(tspi->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tspi->clk);
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tegra_spi_read_rx_fifo_to_client_rxbuf(tspi, t);
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->cur_pos = tspi->cur_tx_pos;
+ else
+ tspi->cur_pos = tspi->cur_rx_pos;
+
+ if (tspi->cur_pos == t->len) {
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ tegra_spi_calculate_curr_xfer_param(tspi->cur_spi, tspi, t);
+ tegra_spi_start_cpu_based_transfer(tspi, t);
+exit:
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
+{
+ struct spi_transfer *t = tspi->curr_xfer;
+ long wait_status;
+ int err = 0;
+ unsigned total_fifo_words;
+ unsigned long flags;
+
+ /* Abort dmas if any error */
+ if (tspi->cur_direction & DATA_DIR_TX) {
+ if (tspi->tx_status) {
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ err += 1;
+ } else {
+ wait_status = wait_for_completion_interruptible_timeout(
+ &tspi->tx_dma_complete, SPI_DMA_TIMEOUT);
+ if (wait_status <= 0) {
+ dmaengine_terminate_all(tspi->tx_dma_chan);
+ dev_err(tspi->dev, "TxDma Xfer failed\n");
+ err += 1;
+ }
+ }
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX) {
+ if (tspi->rx_status) {
+ dmaengine_terminate_all(tspi->rx_dma_chan);
+ err += 2;
+ } else {
+ wait_status = wait_for_completion_interruptible_timeout(
+ &tspi->rx_dma_complete, SPI_DMA_TIMEOUT);
+ if (wait_status <= 0) {
+ dmaengine_terminate_all(tspi->rx_dma_chan);
+ dev_err(tspi->dev, "RxDma Xfer failed\n");
+ err += 2;
+ }
+ }
+ }
+
+ spin_lock_irqsave(&tspi->lock, flags);
+ if (err) {
+ dev_err(tspi->dev, "DmaXfer: ERROR bit set 0x%x\n",
+ tspi->status_reg);
+ dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n",
+ tspi->command1_reg, tspi->dma_control_reg);
+ tegra_periph_reset_assert(tspi->clk);
+ udelay(2);
+ tegra_periph_reset_deassert(tspi->clk);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tegra_spi_copy_spi_rxbuf_to_client_rxbuf(tspi, t);
+
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->cur_pos = tspi->cur_tx_pos;
+ else
+ tspi->cur_pos = tspi->cur_rx_pos;
+
+ if (tspi->cur_pos == t->len) {
+ complete(&tspi->xfer_completion);
+ goto exit;
+ }
+
+ /* Continue transfer in current message */
+ total_fifo_words = tegra_spi_calculate_curr_xfer_param(tspi->cur_spi,
+ tspi, t);
+ if (total_fifo_words > SPI_FIFO_DEPTH)
+ err = tegra_spi_start_dma_based_transfer(tspi, t);
+ else
+ err = tegra_spi_start_cpu_based_transfer(tspi, t);
+
+exit:
+ spin_unlock_irqrestore(&tspi->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tegra_spi_isr_thread(int irq, void *context_data)
+{
+ struct tegra_spi_data *tspi = context_data;
+
+ if (!tspi->is_curr_dma_xfer)
+ return handle_cpu_based_xfer(tspi);
+ return handle_dma_based_xfer(tspi);
+}
+
+static irqreturn_t tegra_spi_isr(int irq, void *context_data)
+{
+ struct tegra_spi_data *tspi = context_data;
+
+ tspi->status_reg = tegra_spi_readl(tspi, SPI_FIFO_STATUS);
+ if (tspi->cur_direction & DATA_DIR_TX)
+ tspi->tx_status = tspi->status_reg &
+ (SPI_TX_FIFO_UNF | SPI_TX_FIFO_OVF);
+
+ if (tspi->cur_direction & DATA_DIR_RX)
+ tspi->rx_status = tspi->status_reg &
+ (SPI_RX_FIFO_OVF | SPI_RX_FIFO_UNF);
+ tegra_spi_clear_status(tspi);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static void tegra_spi_parse_dt(struct platform_device *pdev,
+ struct tegra_spi_data *tspi)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 of_dma[2];
+
+ if (of_property_read_u32_array(np, "nvidia,dma-request-selector",
+ of_dma, 2) >= 0)
+ tspi->dma_req_sel = of_dma[1];
+
+ if (of_property_read_u32(np, "spi-max-frequency",
+ &tspi->spi_max_frequency))
+ tspi->spi_max_frequency = 25000000; /* 25MHz */
+}
+
+static struct of_device_id tegra_spi_of_match[] = {
+ { .compatible = "nvidia,tegra114-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_spi_of_match);
+
+static int tegra_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct tegra_spi_data *tspi;
+ struct resource *r;
+ int ret, spi_irq;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
+ if (!master) {
+ dev_err(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(&pdev->dev, master);
+ tspi = spi_master_get_devdata(master);
+
+ /* Parse DT */
+ tegra_spi_parse_dt(pdev, tspi);
+
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->setup = tegra_spi_setup;
+ master->transfer_one_message = tegra_spi_transfer_one_message;
+ master->num_chipselect = MAX_CHIP_SELECT;
+ master->bus_num = -1;
+
+ tspi->master = master;
+ tspi->dev = &pdev->dev;
+ spin_lock_init(&tspi->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "No IO memory resource\n");
+ ret = -ENODEV;
+ goto exit_free_master;
+ }
+ tspi->phys = r->start;
+ tspi->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(tspi->base)) {
+ ret = PTR_ERR(tspi->base);
+ dev_err(&pdev->dev, "ioremap failed: err = %d\n", ret);
+ goto exit_free_master;
+ }
+
+ spi_irq = platform_get_irq(pdev, 0);
+ tspi->irq = spi_irq;
+ ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
+ tegra_spi_isr_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), tspi);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
+ tspi->irq);
+ goto exit_free_master;
+ }
+
+ tspi->clk = devm_clk_get(&pdev->dev, "spi");
+ if (IS_ERR(tspi->clk)) {
+ dev_err(&pdev->dev, "can not get clock\n");
+ ret = PTR_ERR(tspi->clk);
+ goto exit_free_irq;
+ }
+
+ tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
+ tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN;
+
+ if (tspi->dma_req_sel) {
+ ret = tegra_spi_init_dma_param(tspi, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "RxDma Init failed, err %d\n", ret);
+ goto exit_free_irq;
+ }
+
+ ret = tegra_spi_init_dma_param(tspi, false);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "TxDma Init failed, err %d\n", ret);
+ goto exit_rx_dma_free;
+ }
+ tspi->max_buf_size = tspi->dma_buf_size;
+ init_completion(&tspi->tx_dma_complete);
+ init_completion(&tspi->rx_dma_complete);
+ }
+
+ init_completion(&tspi->xfer_completion);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra_spi_runtime_resume(&pdev->dev);
+ if (ret)
+ goto exit_pm_disable;
+ }
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
+ goto exit_pm_disable;
+ }
+ tspi->def_command1_reg = SPI_M_S;
+ tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+ pm_runtime_put(&pdev->dev);
+
+ master->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_master(master);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ goto exit_pm_disable;
+ }
+ return ret;
+
+exit_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_spi_runtime_suspend(&pdev->dev);
+ tegra_spi_deinit_dma_param(tspi, false);
+exit_rx_dma_free:
+ tegra_spi_deinit_dma_param(tspi, true);
+exit_free_irq:
+ free_irq(spi_irq, tspi);
+exit_free_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int tegra_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = dev_get_drvdata(&pdev->dev);
+ struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+
+ free_irq(tspi->irq, tspi);
+ spi_unregister_master(master);
+
+ if (tspi->tx_dma_chan)
+ tegra_spi_deinit_dma_param(tspi, false);
+
+ if (tspi->rx_dma_chan)
+ tegra_spi_deinit_dma_param(tspi, true);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra_spi_runtime_suspend(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_spi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+
+ return spi_master_suspend(master);
+}
+
+static int tegra_spi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm runtime failed, e = %d\n", ret);
+ return ret;
+ }
+ tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ pm_runtime_put(dev);
+
+ return spi_master_resume(master);
+}
+#endif
+
+static int tegra_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+
+ /* Flush all write which are in PPSB queue by reading back */
+ tegra_spi_readl(tspi, SPI_COMMAND1);
+
+ clk_disable_unprepare(tspi->clk);
+ return 0;
+}
+
+static int tegra_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(tspi->clk);
+ if (ret < 0) {
+ dev_err(tspi->dev, "clk_prepare failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops tegra_spi_pm_ops = {
+ SET_RUNTIME_PM_OPS(tegra_spi_runtime_suspend,
+ tegra_spi_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_spi_suspend, tegra_spi_resume)
+};
+static struct platform_driver tegra_spi_driver = {
+ .driver = {
+ .name = "spi-tegra114",
+ .owner = THIS_MODULE,
+ .pm = &tegra_spi_pm_ops,
+ .of_match_table = tegra_spi_of_match,
+ },
+ .probe = tegra_spi_probe,
+ .remove = tegra_spi_remove,
+};
+module_platform_driver(tegra_spi_driver);
+
+MODULE_ALIAS("platform:spi-tegra114");
+MODULE_DESCRIPTION("NVIDIA Tegra114 SPI Controller Driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 3d6a12b2af04..d65c000efe35 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -33,7 +33,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi-tegra.h>
#include <linux/clk/tegra.h>
#define SPI_COMMAND 0x000
@@ -439,23 +438,13 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
return handle_cpu_based_xfer(tsd);
}
-static struct tegra_spi_platform_data *tegra_sflash_parse_dt(
- struct platform_device *pdev)
+static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
{
- struct tegra_spi_platform_data *pdata;
- struct device_node *np = pdev->dev.of_node;
- u32 max_freq;
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "Memory alloc for pdata failed\n");
- return NULL;
- }
-
- if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
- pdata->spi_max_frequency = max_freq;
+ struct device_node *np = tsd->dev->of_node;
- return pdata;
+ if (of_property_read_u32(np, "spi-max-frequency",
+ &tsd->spi_max_frequency))
+ tsd->spi_max_frequency = 25000000; /* 25MHz */
}
static struct of_device_id tegra_sflash_of_match[] = {
@@ -469,28 +458,15 @@ static int tegra_sflash_probe(struct platform_device *pdev)
struct spi_master *master;
struct tegra_sflash_data *tsd;
struct resource *r;
- struct tegra_spi_platform_data *pdata = pdev->dev.platform_data;
int ret;
const struct of_device_id *match;
- match = of_match_device(of_match_ptr(tegra_sflash_of_match),
- &pdev->dev);
+ match = of_match_device(tegra_sflash_of_match, &pdev->dev);
if (!match) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
- if (!pdata && pdev->dev.of_node)
- pdata = tegra_sflash_parse_dt(pdev);
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data, exiting\n");
- return -ENODEV;
- }
-
- if (!pdata->spi_max_frequency)
- pdata->spi_max_frequency = 25000000; /* 25MHz */
-
master = spi_alloc_master(&pdev->dev, sizeof(*tsd));
if (!master) {
dev_err(&pdev->dev, "master allocation failed\n");
@@ -510,6 +486,8 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
+ tegra_sflash_parse_dt(tsd);
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "No IO memory resource\n");
@@ -538,7 +516,6 @@ static int tegra_sflash_probe(struct platform_device *pdev)
goto exit_free_irq;
}
- tsd->spi_max_frequency = pdata->spi_max_frequency;
init_completion(&tsd->xfer_completion);
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
@@ -658,7 +635,7 @@ static struct platform_driver tegra_sflash_driver = {
.name = "spi-tegra-sflash",
.owner = THIS_MODULE,
.pm = &slink_pm_ops,
- .of_match_table = of_match_ptr(tegra_sflash_of_match),
+ .of_match_table = tegra_sflash_of_match,
},
.probe = tegra_sflash_probe,
.remove = tegra_sflash_remove,
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index b8698b389ef3..3faf88d003de 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -34,7 +34,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi-tegra.h>
#include <linux/clk/tegra.h>
#define SLINK_COMMAND 0x000
@@ -189,7 +188,6 @@ struct tegra_slink_data {
unsigned dma_buf_size;
unsigned max_buf_size;
bool is_curr_dma_xfer;
- bool is_hw_based_cs;
struct completion rx_dma_complete;
struct completion tx_dma_complete;
@@ -375,9 +373,6 @@ static unsigned int tegra_slink_read_rx_fifo_to_client_rxbuf(
tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word;
read_words += tspi->curr_dma_words;
} else {
- unsigned int bits_per_word;
-
- bits_per_word = t->bits_per_word;
for (count = 0; count < rx_full_count; count++) {
x = tegra_slink_readl(tspi, SLINK_RX_FIFO);
for (i = 0; (i < tspi->bytes_per_word); i++)
@@ -720,7 +715,6 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi,
u8 bits_per_word;
unsigned total_fifo_words;
int ret;
- struct tegra_spi_device_controller_data *cdata = spi->controller_data;
unsigned long command;
unsigned long command2;
@@ -743,39 +737,11 @@ static int tegra_slink_start_transfer_one(struct spi_device *spi,
command = tspi->def_command_reg;
command |= SLINK_BIT_LENGTH(bits_per_word - 1);
+ command |= SLINK_CS_SW | SLINK_CS_VALUE;
command2 = tspi->def_command2_reg;
command2 |= SLINK_SS_EN_CS(spi->chip_select);
- /* possibly use the hw based chip select */
- tspi->is_hw_based_cs = false;
- if (cdata && cdata->is_hw_based_cs && is_single_xfer &&
- ((tspi->curr_dma_words * tspi->bytes_per_word) ==
- (t->len - tspi->cur_pos))) {
- int setup_count;
- int sts2;
-
- setup_count = cdata->cs_setup_clk_count >> 1;
- setup_count = max(setup_count, 3);
- command2 |= SLINK_SS_SETUP(setup_count);
- if (tspi->chip_data->cs_hold_time) {
- int hold_count;
-
- hold_count = cdata->cs_hold_clk_count;
- hold_count = max(hold_count, 0xF);
- sts2 = tegra_slink_readl(tspi, SLINK_STATUS2);
- sts2 &= ~SLINK_SS_HOLD_TIME(0xF);
- sts2 |= SLINK_SS_HOLD_TIME(hold_count);
- tegra_slink_writel(tspi, sts2, SLINK_STATUS2);
- }
- tspi->is_hw_based_cs = true;
- }
-
- if (tspi->is_hw_based_cs)
- command &= ~SLINK_CS_SW;
- else
- command |= SLINK_CS_SW | SLINK_CS_VALUE;
-
command &= ~SLINK_MODES;
if (spi->mode & SPI_CPHA)
command |= SLINK_CK_SDA;
@@ -858,21 +824,6 @@ static int tegra_slink_setup(struct spi_device *spi)
return 0;
}
-static int tegra_slink_prepare_transfer(struct spi_master *master)
-{
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
-
- return pm_runtime_get_sync(tspi->dev);
-}
-
-static int tegra_slink_unprepare_transfer(struct spi_master *master)
-{
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
-
- pm_runtime_put(tspi->dev);
- return 0;
-}
-
static int tegra_slink_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -885,6 +836,12 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
msg->status = 0;
msg->actual_length = 0;
+ ret = pm_runtime_get_sync(tspi->dev);
+ if (ret < 0) {
+ dev_err(tspi->dev, "runtime get failed: %d\n", ret);
+ goto done;
+ }
+
single_xfer = list_is_singular(&msg->transfers);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
INIT_COMPLETION(tspi->xfer_completion);
@@ -921,6 +878,8 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
exit:
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
+ pm_runtime_put(tspi->dev);
+done:
msg->status = ret;
spi_finalize_current_message(master);
return ret;
@@ -1072,36 +1031,25 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
-static struct tegra_spi_platform_data *tegra_slink_parse_dt(
- struct platform_device *pdev)
+static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
{
- struct tegra_spi_platform_data *pdata;
- const unsigned int *prop;
- struct device_node *np = pdev->dev.of_node;
+ struct device_node *np = tspi->dev->of_node;
u32 of_dma[2];
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "Memory alloc for pdata failed\n");
- return NULL;
- }
-
if (of_property_read_u32_array(np, "nvidia,dma-request-selector",
of_dma, 2) >= 0)
- pdata->dma_req_sel = of_dma[1];
+ tspi->dma_req_sel = of_dma[1];
- prop = of_get_property(np, "spi-max-frequency", NULL);
- if (prop)
- pdata->spi_max_frequency = be32_to_cpup(prop);
-
- return pdata;
+ if (of_property_read_u32(np, "spi-max-frequency",
+ &tspi->spi_max_frequency))
+ tspi->spi_max_frequency = 25000000; /* 25MHz */
}
-const struct tegra_slink_chip_data tegra30_spi_cdata = {
+static const struct tegra_slink_chip_data tegra30_spi_cdata = {
.cs_hold_time = true,
};
-const struct tegra_slink_chip_data tegra20_spi_cdata = {
+static const struct tegra_slink_chip_data tegra20_spi_cdata = {
.cs_hold_time = false,
};
@@ -1117,27 +1065,16 @@ static int tegra_slink_probe(struct platform_device *pdev)
struct spi_master *master;
struct tegra_slink_data *tspi;
struct resource *r;
- struct tegra_spi_platform_data *pdata = pdev->dev.platform_data;
int ret, spi_irq;
const struct tegra_slink_chip_data *cdata = NULL;
const struct of_device_id *match;
- match = of_match_device(of_match_ptr(tegra_slink_of_match), &pdev->dev);
+ match = of_match_device(tegra_slink_of_match, &pdev->dev);
if (!match) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
cdata = match->data;
- if (!pdata && pdev->dev.of_node)
- pdata = tegra_slink_parse_dt(pdev);
-
- if (!pdata) {
- dev_err(&pdev->dev, "No platform data, exiting\n");
- return -ENODEV;
- }
-
- if (!pdata->spi_max_frequency)
- pdata->spi_max_frequency = 25000000; /* 25MHz */
master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
if (!master) {
@@ -1148,20 +1085,19 @@ static int tegra_slink_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_slink_setup;
- master->prepare_transfer_hardware = tegra_slink_prepare_transfer;
master->transfer_one_message = tegra_slink_transfer_one_message;
- master->unprepare_transfer_hardware = tegra_slink_unprepare_transfer;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
dev_set_drvdata(&pdev->dev, master);
tspi = spi_master_get_devdata(master);
tspi->master = master;
- tspi->dma_req_sel = pdata->dma_req_sel;
tspi->dev = &pdev->dev;
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
+ tegra_slink_parse_dt(tspi);
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "No IO memory resource\n");
@@ -1195,9 +1131,8 @@ static int tegra_slink_probe(struct platform_device *pdev)
tspi->max_buf_size = SLINK_FIFO_DEPTH << 2;
tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN;
- tspi->spi_max_frequency = pdata->spi_max_frequency;
- if (pdata->dma_req_sel) {
+ if (tspi->dma_req_sel) {
ret = tegra_slink_init_dma_param(tspi, true);
if (ret < 0) {
dev_err(&pdev->dev, "RxDma Init failed, err %d\n", ret);
@@ -1340,7 +1275,7 @@ static struct platform_driver tegra_slink_driver = {
.name = "spi-tegra-slink",
.owner = THIS_MODULE,
.pm = &slink_pm_ops,
- .of_match_table = of_match_ptr(tegra_slink_of_match),
+ .of_match_table = tegra_slink_of_match,
},
.probe = tegra_slink_probe,
.remove = tegra_slink_remove,
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index f756481b0fea..35f60bd252dd 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -615,7 +615,7 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
int size;
u32 n_writes;
int j;
- struct spi_message *pmsg;
+ struct spi_message *pmsg, *tmp;
const u8 *tx_buf;
const u16 *tx_sbuf;
@@ -656,7 +656,7 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
if (!data->pkt_rx_buff) {
/* flush queue and set status of all transfers to -ENOMEM */
dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__);
- list_for_each_entry(pmsg, data->queue.next, queue) {
+ list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
pmsg->status = -ENOMEM;
if (pmsg->complete != 0)
@@ -703,7 +703,7 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
static void pch_spi_nomore_transfer(struct pch_spi_data *data)
{
- struct spi_message *pmsg;
+ struct spi_message *pmsg, *tmp;
dev_dbg(&data->master->dev, "%s called\n", __func__);
/* Invoke complete callback
* [To the spi core..indicating end of transfer] */
@@ -740,7 +740,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
dev_dbg(&data->master->dev,
"%s suspend/remove initiated, flushing queue\n",
__func__);
- list_for_each_entry(pmsg, data->queue.next, queue) {
+ list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
pmsg->status = -EIO;
if (pmsg->complete)
@@ -1187,7 +1187,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
static void pch_spi_process_messages(struct work_struct *pwork)
{
- struct spi_message *pmsg;
+ struct spi_message *pmsg, *tmp;
struct pch_spi_data *data;
int bpw;
@@ -1199,7 +1199,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
dev_dbg(&data->master->dev, "%s suspend/remove initiated,"
"flushing queue\n", __func__);
- list_for_each_entry(pmsg, data->queue.next, queue) {
+ list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
pmsg->status = -EIO;
if (pmsg->complete != 0) {
@@ -1789,8 +1789,10 @@ static int __init pch_spi_init(void)
return ret;
ret = pci_register_driver(&pch_spi_pcidev_driver);
- if (ret)
+ if (ret) {
+ platform_driver_unregister(&pch_spi_pd_driver);
return ret;
+ }
return 0;
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index f996c600eb8c..163fd802b7ac 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -543,17 +543,16 @@ static void spi_pump_messages(struct kthread_work *work)
/* Lock queue and check for queue work */
spin_lock_irqsave(&master->queue_lock, flags);
if (list_empty(&master->queue) || !master->running) {
- if (master->busy && master->unprepare_transfer_hardware) {
- ret = master->unprepare_transfer_hardware(master);
- if (ret) {
- spin_unlock_irqrestore(&master->queue_lock, flags);
- dev_err(&master->dev,
- "failed to unprepare transfer hardware\n");
- return;
- }
+ if (!master->busy) {
+ spin_unlock_irqrestore(&master->queue_lock, flags);
+ return;
}
master->busy = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
+ if (master->unprepare_transfer_hardware &&
+ master->unprepare_transfer_hardware(master))
+ dev_err(&master->dev,
+ "failed to unprepare transfer hardware\n");
return;
}
@@ -984,7 +983,7 @@ static void acpi_register_spi_devices(struct spi_master *master)
acpi_status status;
acpi_handle handle;
- handle = ACPI_HANDLE(&master->dev);
+ handle = ACPI_HANDLE(master->dev.parent);
if (!handle)
return;
@@ -1377,6 +1376,14 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
xfer->bits_per_word = spi->bits_per_word;
if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz;
+ if (master->bits_per_word_mask) {
+ /* Only 32 bits fit in the mask */
+ if (xfer->bits_per_word > 32)
+ return -EINVAL;
+ if (!(master->bits_per_word_mask &
+ BIT(xfer->bits_per_word - 1)))
+ return -EINVAL;
+ }
}
message->spi = spi;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 2e0655dbe070..911e9e0711d2 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -603,7 +603,7 @@ static int spidev_probe(struct spi_device *spi)
dev = device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num, spi->chip_select);
- status = IS_ERR(dev) ? PTR_ERR(dev) : 0;
+ status = PTR_RET(dev);
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
status = -ENODEV;
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 71098a7b5fed..7cb7d2c8fd86 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -354,7 +354,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
if (cc->dev->id.revision >= 11)
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
- ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
+ ssb_dbg("chipcommon status is 0x%x\n", cc->status);
if (cc->dev->id.revision >= 20) {
chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 4c0f6d883dd3..1173a091b402 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -110,8 +110,8 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
return;
}
- ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
- (crystalfreq / 1000), (crystalfreq % 1000));
+ ssb_info("Programming PLL to %u.%03u MHz\n",
+ crystalfreq / 1000, crystalfreq % 1000);
/* First turn the PLL off. */
switch (bus->chip_id) {
@@ -138,7 +138,7 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
}
tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
- ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
+ ssb_emerg("Failed to turn the PLL off!\n");
/* Set PDIV in PLL control 0. */
pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
@@ -249,8 +249,8 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
return;
}
- ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n",
- (crystalfreq / 1000), (crystalfreq % 1000));
+ ssb_info("Programming PLL to %u.%03u MHz\n",
+ crystalfreq / 1000, crystalfreq % 1000);
/* First turn the PLL off. */
switch (bus->chip_id) {
@@ -275,7 +275,7 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
}
tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
- ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n");
+ ssb_emerg("Failed to turn the PLL off!\n");
/* Set p1div and p2div. */
pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
@@ -349,9 +349,8 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
case 43222:
break;
default:
- ssb_printk(KERN_ERR PFX
- "ERROR: PLL init unknown for device %04X\n",
- bus->chip_id);
+ ssb_err("ERROR: PLL init unknown for device %04X\n",
+ bus->chip_id);
}
}
@@ -472,9 +471,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
max_msk = 0xFFFFF;
break;
default:
- ssb_printk(KERN_ERR PFX
- "ERROR: PMU resource config unknown for device %04X\n",
- bus->chip_id);
+ ssb_err("ERROR: PMU resource config unknown for device %04X\n",
+ bus->chip_id);
}
if (updown_tab) {
@@ -526,8 +524,8 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)
pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
- ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
- cc->pmu.rev, pmucap);
+ ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n",
+ cc->pmu.rev, pmucap);
if (cc->pmu.rev == 1)
chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
@@ -638,9 +636,8 @@ u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
case 0x5354:
ssb_pmu_get_alp_clock_clk0(cc);
default:
- ssb_printk(KERN_ERR PFX
- "ERROR: PMU alp clock unknown for device %04X\n",
- bus->chip_id);
+ ssb_err("ERROR: PMU alp clock unknown for device %04X\n",
+ bus->chip_id);
return 0;
}
}
@@ -654,9 +651,8 @@ u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
/* 5354 chip uses a non programmable PLL of frequency 240MHz */
return 240000000;
default:
- ssb_printk(KERN_ERR PFX
- "ERROR: PMU cpu clock unknown for device %04X\n",
- bus->chip_id);
+ ssb_err("ERROR: PMU cpu clock unknown for device %04X\n",
+ bus->chip_id);
return 0;
}
}
@@ -669,9 +665,52 @@ u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
case 0x5354:
return 120000000;
default:
- ssb_printk(KERN_ERR PFX
- "ERROR: PMU controlclock unknown for device %04X\n",
- bus->chip_id);
+ ssb_err("ERROR: PMU controlclock unknown for device %04X\n",
+ bus->chip_id);
return 0;
}
}
+
+void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid)
+{
+ u32 pmu_ctl = 0;
+
+ switch (cc->dev->bus->chip_id) {
+ case 0x4322:
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854);
+ if (spuravoid == 1)
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828);
+ else
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828);
+ pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
+ break;
+ case 43222:
+ if (spuravoid == 1) {
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815);
+ } else {
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0);
+ ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855);
+ }
+ pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
+ break;
+ default:
+ ssb_printk(KERN_ERR PFX
+ "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
+ cc->dev->bus->chip_id);
+ return;
+ }
+
+ chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl);
+}
+EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
index 33b37dac40bd..fa385a368a56 100644
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
@@ -167,21 +167,22 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
ssb_write32(mdev, SSB_IPSFLAG, irqflag);
}
- ssb_dprintk(KERN_INFO PFX
- "set_irq: core 0x%04x, irq %d => %d\n",
- dev->id.coreid, oldirq+2, irq+2);
+ ssb_dbg("set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.coreid, oldirq+2, irq+2);
}
static void print_irq(struct ssb_device *dev, unsigned int irq)
{
- int i;
static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
- ssb_dprintk(KERN_INFO PFX
- "core 0x%04x, irq :", dev->id.coreid);
- for (i = 0; i <= 6; i++) {
- ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
- }
- ssb_dprintk("\n");
+ ssb_dbg("core 0x%04x, irq : %s%s %s%s %s%s %s%s %s%s %s%s %s%s\n",
+ dev->id.coreid,
+ irq_name[0], irq == 0 ? "*" : " ",
+ irq_name[1], irq == 1 ? "*" : " ",
+ irq_name[2], irq == 2 ? "*" : " ",
+ irq_name[3], irq == 3 ? "*" : " ",
+ irq_name[4], irq == 4 ? "*" : " ",
+ irq_name[5], irq == 5 ? "*" : " ",
+ irq_name[6], irq == 6 ? "*" : " ");
}
static void dump_irq(struct ssb_bus *bus)
@@ -286,7 +287,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
if (!mcore->dev)
return; /* We don't have a MIPS core */
- ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+ ssb_dbg("Initializing MIPS core...\n");
bus = mcore->dev->bus;
hz = ssb_clockspeed(bus);
@@ -334,7 +335,7 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
break;
}
}
- ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
+ ssb_dbg("after irq reconfiguration\n");
dump_irq(bus);
ssb_mips_serial_init(mcore);
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 59801d23d7ec..d75b72ba2672 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -263,8 +263,7 @@ int ssb_pcicore_plat_dev_init(struct pci_dev *d)
return -ENODEV;
}
- ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
- pci_name(d));
+ ssb_info("PCI: Fixing up device %s\n", pci_name(d));
/* Fix up interrupt lines */
d->irq = ssb_mips_irq(extpci_core->dev) + 2;
@@ -285,12 +284,12 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
return;
- ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
+ ssb_info("PCI: Fixing up bridge %s\n", pci_name(dev));
/* Enable PCI bridge bus mastering and memory space */
pci_set_master(dev);
if (pcibios_enable_device(dev, ~0) < 0) {
- ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+ ssb_err("PCI: SSB bridge enable failed\n");
return;
}
@@ -299,8 +298,8 @@ static void ssb_pcicore_fixup_pcibridge(struct pci_dev *dev)
/* Make sure our latency is high enough to handle the devices behind us */
lat = 168;
- ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
- pci_name(dev), lat);
+ ssb_info("PCI: Fixing latency timer of device %s to %u\n",
+ pci_name(dev), lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_pcicore_fixup_pcibridge);
@@ -323,7 +322,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
return;
extpci_core = pc;
- ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
+ ssb_dbg("PCIcore in host mode found\n");
/* Reset devices on the external PCI bus */
val = SSB_PCICORE_CTL_RST_OE;
val |= SSB_PCICORE_CTL_CLK_OE;
@@ -338,7 +337,7 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
udelay(1); /* Assertion time demanded by the PCI standard */
if (pc->dev->bus->has_cardbus_slot) {
- ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
+ ssb_dbg("CardBus slot detected\n");
pc->cardbusmode = 1;
/* GPIO 1 resets the bridge */
ssb_gpio_out(pc->dev->bus, 1, 1);
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c
index bb18d76f9f2c..55e101115038 100644
--- a/drivers/ssb/embedded.c
+++ b/drivers/ssb/embedded.c
@@ -57,9 +57,8 @@ int ssb_watchdog_register(struct ssb_bus *bus)
bus->busnumber, &wdt,
sizeof(wdt));
if (IS_ERR(pdev)) {
- ssb_dprintk(KERN_INFO PFX
- "can not register watchdog device, err: %li\n",
- PTR_ERR(pdev));
+ ssb_dbg("can not register watchdog device, err: %li\n",
+ PTR_ERR(pdev));
return PTR_ERR(pdev);
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 3b645b8a261f..812775a4bfb6 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -275,8 +275,8 @@ int ssb_devices_thaw(struct ssb_freeze_context *ctx)
err = sdrv->probe(sdev, &sdev->id);
if (err) {
- ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
- dev_name(sdev->dev));
+ ssb_err("Failed to thaw device %s\n",
+ dev_name(sdev->dev));
result = err;
}
ssb_device_put(sdev);
@@ -447,10 +447,9 @@ void ssb_bus_unregister(struct ssb_bus *bus)
err = ssb_gpio_unregister(bus);
if (err == -EBUSY)
- ssb_dprintk(KERN_ERR PFX "Some GPIOs are still in use.\n");
+ ssb_dbg("Some GPIOs are still in use\n");
else if (err)
- ssb_dprintk(KERN_ERR PFX
- "Can not unregister GPIO driver: %i\n", err);
+ ssb_dbg("Can not unregister GPIO driver: %i\n", err);
ssb_buses_lock();
ssb_devices_unregister(bus);
@@ -497,8 +496,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
if (!devwrap) {
- ssb_printk(KERN_ERR PFX
- "Could not allocate device\n");
+ ssb_err("Could not allocate device\n");
err = -ENOMEM;
goto error;
}
@@ -537,9 +535,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
sdev->dev = dev;
err = device_register(dev);
if (err) {
- ssb_printk(KERN_ERR PFX
- "Could not register %s\n",
- dev_name(dev));
+ ssb_err("Could not register %s\n", dev_name(dev));
/* Set dev to NULL to not unregister
* dev on error unwinding. */
sdev->dev = NULL;
@@ -825,10 +821,9 @@ static int ssb_bus_register(struct ssb_bus *bus,
ssb_mipscore_init(&bus->mipscore);
err = ssb_gpio_init(bus);
if (err == -ENOTSUPP)
- ssb_dprintk(KERN_DEBUG PFX "GPIO driver not activated\n");
+ ssb_dbg("GPIO driver not activated\n");
else if (err)
- ssb_dprintk(KERN_ERR PFX
- "Error registering GPIO driver: %i\n", err);
+ ssb_dbg("Error registering GPIO driver: %i\n", err);
err = ssb_fetch_invariants(bus, get_invariants);
if (err) {
ssb_bus_may_powerdown(bus);
@@ -878,11 +873,11 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, struct pci_dev *host_pci)
err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
if (!err) {
- ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
- "PCI device %s\n", dev_name(&host_pci->dev));
+ ssb_info("Sonics Silicon Backplane found on PCI device %s\n",
+ dev_name(&host_pci->dev));
} else {
- ssb_printk(KERN_ERR PFX "Failed to register PCI version"
- " of SSB with error %d\n", err);
+ ssb_err("Failed to register PCI version of SSB with error %d\n",
+ err);
}
return err;
@@ -903,8 +898,8 @@ int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
if (!err) {
- ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
- "PCMCIA device %s\n", pcmcia_dev->devname);
+ ssb_info("Sonics Silicon Backplane found on PCMCIA device %s\n",
+ pcmcia_dev->devname);
}
return err;
@@ -925,8 +920,8 @@ int ssb_bus_sdiobus_register(struct ssb_bus *bus, struct sdio_func *func,
err = ssb_bus_register(bus, ssb_sdio_get_invariants, ~0);
if (!err) {
- ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
- "SDIO device %s\n", sdio_func_id(func));
+ ssb_info("Sonics Silicon Backplane found on SDIO device %s\n",
+ sdio_func_id(func));
}
return err;
@@ -944,8 +939,8 @@ int ssb_bus_ssbbus_register(struct ssb_bus *bus, unsigned long baseaddr,
err = ssb_bus_register(bus, get_invariants, baseaddr);
if (!err) {
- ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
- "address 0x%08lX\n", baseaddr);
+ ssb_info("Sonics Silicon Backplane found at address 0x%08lX\n",
+ baseaddr);
}
return err;
@@ -1339,7 +1334,7 @@ out:
#endif
return err;
error:
- ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
+ ssb_err("Bus powerdown failed\n");
goto out;
}
EXPORT_SYMBOL(ssb_bus_may_powerdown);
@@ -1362,7 +1357,7 @@ int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
return 0;
error:
- ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+ ssb_err("Bus powerup failed\n");
return err;
}
EXPORT_SYMBOL(ssb_bus_powerup);
@@ -1470,15 +1465,13 @@ static int __init ssb_modinit(void)
err = b43_pci_ssb_bridge_init();
if (err) {
- ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
- "initialization failed\n");
+ ssb_err("Broadcom 43xx PCI-SSB-bridge initialization failed\n");
/* don't fail SSB init because of this */
err = 0;
}
err = ssb_gige_init();
if (err) {
- ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet "
- "driver initialization failed\n");
+ ssb_err("SSB Broadcom Gigabit Ethernet driver initialization failed\n");
/* don't fail SSB init because of this */
err = 0;
}
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index e9d94968f394..a8dc95ebf2d6 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -56,7 +56,7 @@ int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
}
return 0;
error:
- ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ ssb_err("Failed to switch to core %u\n", coreidx);
return -ENODEV;
}
@@ -67,10 +67,9 @@ int ssb_pci_switch_core(struct ssb_bus *bus,
unsigned long flags;
#if SSB_VERBOSE_PCICORESWITCH_DEBUG
- ssb_printk(KERN_INFO PFX
- "Switching to %s core, index %d\n",
- ssb_core_name(dev->id.coreid),
- dev->core_index);
+ ssb_info("Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
#endif
spin_lock_irqsave(&bus->bar_lock, flags);
@@ -231,6 +230,15 @@ static inline u8 ssb_crc8(u8 crc, u8 data)
return t[crc ^ data];
}
+static void sprom_get_mac(char *mac, const u16 *in)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ *mac++ = in[i] >> 8;
+ *mac++ = in[i];
+ }
+}
+
static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
{
int word;
@@ -278,7 +286,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
u32 spromctl;
u16 size = bus->sprom_size;
- ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+ ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
if (err)
goto err_ctlreg;
@@ -286,17 +294,17 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
if (err)
goto err_ctlreg;
- ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ ssb_notice("[ 0%%");
msleep(500);
for (i = 0; i < size; i++) {
if (i == size / 4)
- ssb_printk("25%%");
+ ssb_cont("25%%");
else if (i == size / 2)
- ssb_printk("50%%");
+ ssb_cont("50%%");
else if (i == (size * 3) / 4)
- ssb_printk("75%%");
+ ssb_cont("75%%");
else if (i % 2)
- ssb_printk(".");
+ ssb_cont(".");
writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
mmiowb();
msleep(20);
@@ -309,12 +317,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
if (err)
goto err_ctlreg;
msleep(500);
- ssb_printk("100%% ]\n");
- ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+ ssb_cont("100%% ]\n");
+ ssb_notice("SPROM written\n");
return 0;
err_ctlreg:
- ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+ ssb_err("Could not access SPROM control register.\n");
return err;
}
@@ -339,10 +347,23 @@ static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
return (s8)gain;
}
+static void sprom_extract_r23(struct ssb_sprom *out, const u16 *in)
+{
+ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+ SPEX(opo, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+ SPEX(maxpwr_ah, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+ SPEX(maxpwr_al, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+ SSB_SPROM2_MAXP_A_LO_SHIFT);
+}
+
static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
{
- int i;
- u16 v;
u16 loc[3];
if (out->revision == 3) /* rev 3 moved MAC */
@@ -352,19 +373,10 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
loc[1] = SSB_SPROM1_ET0MAC;
loc[2] = SSB_SPROM1_ET1MAC;
}
- for (i = 0; i < 3; i++) {
- v = in[SPOFF(loc[0]) + i];
- *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
- }
+ sprom_get_mac(out->il0mac, &in[SPOFF(loc[0])]);
if (out->revision < 3) { /* only rev 1-2 have et0, et1 */
- for (i = 0; i < 3; i++) {
- v = in[SPOFF(loc[1]) + i];
- *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
- }
- for (i = 0; i < 3; i++) {
- v = in[SPOFF(loc[2]) + i];
- *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
- }
+ sprom_get_mac(out->et0mac, &in[SPOFF(loc[1])]);
+ sprom_get_mac(out->et1mac, &in[SPOFF(loc[2])]);
}
SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
@@ -372,6 +384,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
if (out->revision == 1)
SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
SSB_SPROM1_BINF_CCODE_SHIFT);
@@ -398,8 +411,7 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SSB_SPROM1_ITSSI_A_SHIFT);
SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
- if (out->revision >= 2)
- SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+
SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
@@ -410,6 +422,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
out->antenna_gain.a1 = r123_extract_antgain(out->revision, in,
SSB_SPROM1_AGAIN_A,
SSB_SPROM1_AGAIN_A_SHIFT);
+ if (out->revision >= 2)
+ sprom_extract_r23(out, in);
}
/* Revs 4 5 and 8 have partially shared layout */
@@ -454,23 +468,20 @@ static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
{
- int i;
- u16 v;
u16 il0mac_offset;
if (out->revision == 4)
il0mac_offset = SSB_SPROM4_IL0MAC;
else
il0mac_offset = SSB_SPROM5_IL0MAC;
- /* extract the MAC address */
- for (i = 0; i < 3; i++) {
- v = in[SPOFF(il0mac_offset) + i];
- *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
- }
+
+ sprom_get_mac(out->il0mac, &in[SPOFF(il0mac_offset)]);
+
SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
SSB_SPROM4_ETHPHY_ET1A_SHIFT);
SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
if (out->revision == 4) {
SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
@@ -530,7 +541,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
{
int i;
- u16 v, o;
+ u16 o;
u16 pwr_info_offset[] = {
SSB_SROM8_PWR_INFO_CORE0, SSB_SROM8_PWR_INFO_CORE1,
SSB_SROM8_PWR_INFO_CORE2, SSB_SROM8_PWR_INFO_CORE3
@@ -539,11 +550,10 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
ARRAY_SIZE(out->core_pwr_info));
/* extract the MAC address */
- for (i = 0; i < 3; i++) {
- v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
- *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
- }
+ sprom_get_mac(out->il0mac, &in[SPOFF(SSB_SPROM8_IL0MAC)]);
+
SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
+ SPEX(board_type, SSB_SPROM1_SPID, 0xFFFF, 0);
SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
@@ -743,7 +753,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
memset(out, 0, sizeof(*out));
out->revision = in[size - 1] & 0x00FF;
- ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
+ ssb_dbg("SPROM revision %d detected\n", out->revision);
memset(out->et0mac, 0xFF, 6); /* preset et0 and et1 mac */
memset(out->et1mac, 0xFF, 6);
@@ -752,7 +762,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
* number stored in the SPROM.
* Always extract r1. */
out->revision = 1;
- ssb_dprintk(KERN_DEBUG PFX "SPROM treated as revision %d\n", out->revision);
+ ssb_dbg("SPROM treated as revision %d\n", out->revision);
}
switch (out->revision) {
@@ -769,9 +779,8 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
sprom_extract_r8(out, in);
break;
default:
- ssb_printk(KERN_WARNING PFX "Unsupported SPROM"
- " revision %d detected. Will extract"
- " v1\n", out->revision);
+ ssb_warn("Unsupported SPROM revision %d detected. Will extract v1\n",
+ out->revision);
out->revision = 1;
sprom_extract_r123(out, in);
}
@@ -791,7 +800,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
u16 *buf;
if (!ssb_is_sprom_available(bus)) {
- ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+ ssb_err("No SPROM available!\n");
return -ENODEV;
}
if (bus->chipco.dev) { /* can be unavailable! */
@@ -810,7 +819,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
} else {
bus->sprom_offset = SSB_SPROM_BASE1;
}
- ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
+ ssb_dbg("SPROM offset is 0x%x\n", bus->sprom_offset);
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
@@ -835,18 +844,15 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
* available for this device in some other storage */
err = ssb_fill_sprom_with_fallback(bus, sprom);
if (err) {
- ssb_printk(KERN_WARNING PFX "WARNING: Using"
- " fallback SPROM failed (err %d)\n",
- err);
+ ssb_warn("WARNING: Using fallback SPROM failed (err %d)\n",
+ err);
} else {
- ssb_dprintk(KERN_DEBUG PFX "Using SPROM"
- " revision %d provided by"
- " platform.\n", sprom->revision);
+ ssb_dbg("Using SPROM revision %d provided by platform\n",
+ sprom->revision);
err = 0;
goto out_free;
}
- ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
- " SPROM CRC (corrupt SPROM)\n");
+ ssb_warn("WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
}
}
err = sprom_extract(bus, sprom, buf, bus->sprom_size);
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index fbafed5b729b..b413e0187087 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -143,7 +143,7 @@ int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
return 0;
error:
- ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ ssb_err("Failed to switch to core %u\n", coreidx);
return err;
}
@@ -153,10 +153,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus,
int err;
#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
- ssb_printk(KERN_INFO PFX
- "Switching to %s core, index %d\n",
- ssb_core_name(dev->id.coreid),
- dev->core_index);
+ ssb_info("Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
#endif
err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
@@ -192,7 +191,7 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
return 0;
error:
- ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+ ssb_err("Failed to switch pcmcia segment\n");
return err;
}
@@ -549,44 +548,39 @@ static int ssb_pcmcia_sprom_write_all(struct ssb_bus *bus, const u16 *sprom)
bool failed = 0;
size_t size = SSB_PCMCIA_SPROM_SIZE;
- ssb_printk(KERN_NOTICE PFX
- "Writing SPROM. Do NOT turn off the power! "
- "Please stand by...\n");
+ ssb_notice("Writing SPROM. Do NOT turn off the power! Please stand by...\n");
err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEEN);
if (err) {
- ssb_printk(KERN_NOTICE PFX
- "Could not enable SPROM write access.\n");
+ ssb_notice("Could not enable SPROM write access\n");
return -EBUSY;
}
- ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ ssb_notice("[ 0%%");
msleep(500);
for (i = 0; i < size; i++) {
if (i == size / 4)
- ssb_printk("25%%");
+ ssb_cont("25%%");
else if (i == size / 2)
- ssb_printk("50%%");
+ ssb_cont("50%%");
else if (i == (size * 3) / 4)
- ssb_printk("75%%");
+ ssb_cont("75%%");
else if (i % 2)
- ssb_printk(".");
+ ssb_cont(".");
err = ssb_pcmcia_sprom_write(bus, i, sprom[i]);
if (err) {
- ssb_printk(KERN_NOTICE PFX
- "Failed to write to SPROM.\n");
+ ssb_notice("Failed to write to SPROM\n");
failed = 1;
break;
}
}
err = ssb_pcmcia_sprom_command(bus, SSB_PCMCIA_SPROMCTL_WRITEDIS);
if (err) {
- ssb_printk(KERN_NOTICE PFX
- "Could not disable SPROM write access.\n");
+ ssb_notice("Could not disable SPROM write access\n");
failed = 1;
}
msleep(500);
if (!failed) {
- ssb_printk("100%% ]\n");
- ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+ ssb_cont("100%% ]\n");
+ ssb_notice("SPROM written\n");
}
return failed ? -EBUSY : 0;
@@ -700,7 +694,7 @@ static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev,
return -ENOSPC; /* continue with next entry */
error:
- ssb_printk(KERN_ERR PFX
+ ssb_err(
"PCMCIA: Failed to fetch device invariants: %s\n",
error_description);
return -ENODEV;
@@ -722,7 +716,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE,
ssb_pcmcia_get_mac, sprom);
if (res != 0) {
- ssb_printk(KERN_ERR PFX
+ ssb_err(
"PCMCIA: Failed to fetch MAC address\n");
return -ENODEV;
}
@@ -733,7 +727,7 @@ int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
if ((res == 0) || (res == -ENOSPC))
return 0;
- ssb_printk(KERN_ERR PFX
+ ssb_err(
"PCMCIA: Failed to fetch device invariants\n");
return -ENODEV;
}
@@ -843,6 +837,6 @@ int ssb_pcmcia_init(struct ssb_bus *bus)
return 0;
error:
- ssb_printk(KERN_ERR PFX "Failed to initialize PCMCIA host device\n");
+ ssb_err("Failed to initialize PCMCIA host device\n");
return err;
}
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index ab4627cf1114..b9429df583eb 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -125,8 +125,7 @@ static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
chipid_fallback = 0x4401;
break;
default:
- ssb_printk(KERN_ERR PFX
- "PCI-ID not in fallback list\n");
+ ssb_err("PCI-ID not in fallback list\n");
}
return chipid_fallback;
@@ -152,8 +151,7 @@ static u8 chipid_to_nrcores(u16 chipid)
case 0x4704:
return 9;
default:
- ssb_printk(KERN_ERR PFX
- "CHIPID not in nrcores fallback list\n");
+ ssb_err("CHIPID not in nrcores fallback list\n");
}
return 1;
@@ -320,15 +318,13 @@ int ssb_bus_scan(struct ssb_bus *bus,
bus->chip_package = 0;
}
}
- ssb_printk(KERN_INFO PFX "Found chip with id 0x%04X, rev 0x%02X and "
- "package 0x%02X\n", bus->chip_id, bus->chip_rev,
- bus->chip_package);
+ ssb_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
+ bus->chip_id, bus->chip_rev, bus->chip_package);
if (!bus->nr_devices)
bus->nr_devices = chipid_to_nrcores(bus->chip_id);
if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
- ssb_printk(KERN_ERR PFX
- "More than %d ssb cores found (%d)\n",
- SSB_MAX_NR_CORES, bus->nr_devices);
+ ssb_err("More than %d ssb cores found (%d)\n",
+ SSB_MAX_NR_CORES, bus->nr_devices);
goto err_unmap;
}
if (bus->bustype == SSB_BUSTYPE_SSB) {
@@ -370,8 +366,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
nr_80211_cores++;
if (nr_80211_cores > 1) {
if (!we_support_multiple_80211_cores(bus)) {
- ssb_dprintk(KERN_INFO PFX "Ignoring additional "
- "802.11 core\n");
+ ssb_dbg("Ignoring additional 802.11 core\n");
continue;
}
}
@@ -379,8 +374,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
case SSB_DEV_EXTIF:
#ifdef CONFIG_SSB_DRIVER_EXTIF
if (bus->extif.dev) {
- ssb_printk(KERN_WARNING PFX
- "WARNING: Multiple EXTIFs found\n");
+ ssb_warn("WARNING: Multiple EXTIFs found\n");
break;
}
bus->extif.dev = dev;
@@ -388,8 +382,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
break;
case SSB_DEV_CHIPCOMMON:
if (bus->chipco.dev) {
- ssb_printk(KERN_WARNING PFX
- "WARNING: Multiple ChipCommon found\n");
+ ssb_warn("WARNING: Multiple ChipCommon found\n");
break;
}
bus->chipco.dev = dev;
@@ -398,8 +391,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
case SSB_DEV_MIPS_3302:
#ifdef CONFIG_SSB_DRIVER_MIPS
if (bus->mipscore.dev) {
- ssb_printk(KERN_WARNING PFX
- "WARNING: Multiple MIPS cores found\n");
+ ssb_warn("WARNING: Multiple MIPS cores found\n");
break;
}
bus->mipscore.dev = dev;
@@ -420,8 +412,7 @@ int ssb_bus_scan(struct ssb_bus *bus,
}
}
if (bus->pcicore.dev) {
- ssb_printk(KERN_WARNING PFX
- "WARNING: Multiple PCI(E) cores found\n");
+ ssb_warn("WARNING: Multiple PCI(E) cores found\n");
break;
}
bus->pcicore.dev = dev;
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index 80d366fcf8d3..a3b23644b0fb 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -127,13 +127,13 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
goto out_kfree;
err = ssb_devices_freeze(bus, &freeze);
if (err) {
- ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+ ssb_err("SPROM write: Could not freeze all devices\n");
goto out_unlock;
}
res = sprom_write(bus, sprom);
err = ssb_devices_thaw(&freeze);
if (err)
- ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+ ssb_err("SPROM write: Could not thaw all devices\n");
out_unlock:
mutex_unlock(&bus->sprom_mutex);
out_kfree:
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index 466171b77f68..4671f17f09af 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -9,16 +9,27 @@
#define PFX "ssb: "
#ifdef CONFIG_SSB_SILENT
-# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
+# define ssb_printk(fmt, ...) \
+ do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
#else
-# define ssb_printk printk
+# define ssb_printk(fmt, ...) \
+ printk(fmt, ##__VA_ARGS__)
#endif /* CONFIG_SSB_SILENT */
+#define ssb_emerg(fmt, ...) ssb_printk(KERN_EMERG PFX fmt, ##__VA_ARGS__)
+#define ssb_err(fmt, ...) ssb_printk(KERN_ERR PFX fmt, ##__VA_ARGS__)
+#define ssb_warn(fmt, ...) ssb_printk(KERN_WARNING PFX fmt, ##__VA_ARGS__)
+#define ssb_notice(fmt, ...) ssb_printk(KERN_NOTICE PFX fmt, ##__VA_ARGS__)
+#define ssb_info(fmt, ...) ssb_printk(KERN_INFO PFX fmt, ##__VA_ARGS__)
+#define ssb_cont(fmt, ...) ssb_printk(KERN_CONT fmt, ##__VA_ARGS__)
+
/* dprintk: Debugging printk; vanishes for non-debug compilation */
#ifdef CONFIG_SSB_DEBUG
-# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x)
+# define ssb_dbg(fmt, ...) \
+ ssb_printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__)
#else
-# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0)
+# define ssb_dbg(fmt, ...) \
+ do { if (0) printk(KERN_DEBUG PFX fmt, ##__VA_ARGS__); } while (0)
#endif
#ifdef CONFIG_SSB_DEBUG
diff --git a/drivers/ssbi/Kconfig b/drivers/ssbi/Kconfig
new file mode 100644
index 000000000000..1ae4040afedd
--- /dev/null
+++ b/drivers/ssbi/Kconfig
@@ -0,0 +1,16 @@
+#
+# SSBI bus support
+#
+
+menu "Qualcomm MSM SSBI bus support"
+
+config SSBI
+ tristate "Qualcomm Single-wire Serial Bus Interface (SSBI)"
+ help
+ If you say yes to this option, support will be included for the
+ built-in SSBI interface on Qualcomm MSM family processors.
+
+ This is required for communicating with Qualcomm PMICs and
+ other devices that have the SSBI interface.
+
+endmenu
diff --git a/drivers/ssbi/Makefile b/drivers/ssbi/Makefile
new file mode 100644
index 000000000000..38fb70c31caf
--- /dev/null
+++ b/drivers/ssbi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SSBI) += ssbi.o
diff --git a/drivers/ssbi/ssbi.c b/drivers/ssbi/ssbi.c
new file mode 100644
index 000000000000..f32da0258a8e
--- /dev/null
+++ b/drivers/ssbi/ssbi.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010, Google Inc.
+ *
+ * Original authors: Code Aurora Forum
+ *
+ * Author: Dima Zavin <dima@android.com>
+ * - Largely rewritten from original to not be an i2c driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/ssbi.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* SSBI 2.0 controller registers */
+#define SSBI2_CMD 0x0008
+#define SSBI2_RD 0x0010
+#define SSBI2_STATUS 0x0014
+#define SSBI2_MODE2 0x001C
+
+/* SSBI_CMD fields */
+#define SSBI_CMD_RDWRN (1 << 24)
+
+/* SSBI_STATUS fields */
+#define SSBI_STATUS_RD_READY (1 << 2)
+#define SSBI_STATUS_READY (1 << 1)
+#define SSBI_STATUS_MCHN_BUSY (1 << 0)
+
+/* SSBI_MODE2 fields */
+#define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04
+#define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT)
+
+#define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
+ (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
+ SSBI_MODE2_REG_ADDR_15_8_MASK))
+
+/* SSBI PMIC Arbiter command registers */
+#define SSBI_PA_CMD 0x0000
+#define SSBI_PA_RD_STATUS 0x0004
+
+/* SSBI_PA_CMD fields */
+#define SSBI_PA_CMD_RDWRN (1 << 24)
+#define SSBI_PA_CMD_ADDR_MASK 0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/
+
+/* SSBI_PA_RD_STATUS fields */
+#define SSBI_PA_RD_STATUS_TRANS_DONE (1 << 27)
+#define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26)
+
+#define SSBI_TIMEOUT_US 100
+
+struct ssbi {
+ struct device *slave;
+ void __iomem *base;
+ spinlock_t lock;
+ enum ssbi_controller_type controller_type;
+ int (*read)(struct ssbi *, u16 addr, u8 *buf, int len);
+ int (*write)(struct ssbi *, u16 addr, u8 *buf, int len);
+};
+
+#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev))
+
+static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
+{
+ return readl(ssbi->base + reg);
+}
+
+static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg)
+{
+ writel(val, ssbi->base + reg);
+}
+
+/*
+ * Via private exchange with one of the original authors, the hardware
+ * should generally finish a transaction in about 5us. The worst
+ * case, is when using the arbiter and both other CPUs have just
+ * started trying to use the SSBI bus will result in a time of about
+ * 20us. It should never take longer than this.
+ *
+ * As such, this wait merely spins, with a udelay.
+ */
+static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask)
+{
+ u32 timeout = SSBI_TIMEOUT_US;
+ u32 val;
+
+ while (timeout--) {
+ val = ssbi_readl(ssbi, SSBI2_STATUS);
+ if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0))
+ return 0;
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int
+ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+ u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16);
+ int ret = 0;
+
+ if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+ u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+ mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
+ ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+ }
+
+ while (len) {
+ ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+ if (ret)
+ goto err;
+
+ ssbi_writel(ssbi, cmd, SSBI2_CMD);
+ ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0);
+ if (ret)
+ goto err;
+ *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff;
+ len--;
+ }
+
+err:
+ return ret;
+}
+
+static int
+ssbi_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+ int ret = 0;
+
+ if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+ u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+ mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr);
+ ssbi_writel(ssbi, mode2, SSBI2_MODE2);
+ }
+
+ while (len) {
+ ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0);
+ if (ret)
+ goto err;
+
+ ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD);
+ ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY);
+ if (ret)
+ goto err;
+ buf++;
+ len--;
+ }
+
+err:
+ return ret;
+}
+
+/*
+ * See ssbi_wait_mask for an explanation of the time and the
+ * busywait.
+ */
+static inline int
+ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data)
+{
+ u32 timeout = SSBI_TIMEOUT_US;
+ u32 rd_status = 0;
+
+ ssbi_writel(ssbi, cmd, SSBI_PA_CMD);
+
+ while (timeout--) {
+ rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
+
+ if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED)
+ return -EPERM;
+
+ if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) {
+ if (data)
+ *data = rd_status & 0xff;
+ return 0;
+ }
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int
+ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+ u32 cmd;
+ int ret = 0;
+
+ cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8;
+
+ while (len) {
+ ret = ssbi_pa_transfer(ssbi, cmd, buf);
+ if (ret)
+ goto err;
+ buf++;
+ len--;
+ }
+
+err:
+ return ret;
+}
+
+static int
+ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
+{
+ u32 cmd;
+ int ret = 0;
+
+ while (len) {
+ cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf;
+ ret = ssbi_pa_transfer(ssbi, cmd, NULL);
+ if (ret)
+ goto err;
+ buf++;
+ len--;
+ }
+
+err:
+ return ret;
+}
+
+int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
+{
+ struct ssbi *ssbi = to_ssbi(dev);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ssbi->lock, flags);
+ ret = ssbi->read(ssbi, addr, buf, len);
+ spin_unlock_irqrestore(&ssbi->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ssbi_read);
+
+int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len)
+{
+ struct ssbi *ssbi = to_ssbi(dev);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&ssbi->lock, flags);
+ ret = ssbi->write(ssbi, addr, buf, len);
+ spin_unlock_irqrestore(&ssbi->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ssbi_write);
+
+static int ssbi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *mem_res;
+ struct ssbi *ssbi;
+ int ret = 0;
+ const char *type;
+
+ ssbi = kzalloc(sizeof(struct ssbi), GFP_KERNEL);
+ if (!ssbi) {
+ pr_err("can not allocate ssbi_data\n");
+ return -ENOMEM;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ pr_err("missing mem resource\n");
+ ret = -EINVAL;
+ goto err_get_mem_res;
+ }
+
+ ssbi->base = ioremap(mem_res->start, resource_size(mem_res));
+ if (!ssbi->base) {
+ pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start);
+ ret = -EINVAL;
+ goto err_ioremap;
+ }
+ platform_set_drvdata(pdev, ssbi);
+
+ type = of_get_property(np, "qcom,controller-type", NULL);
+ if (type == NULL) {
+ pr_err("Missing qcom,controller-type property\n");
+ ret = -EINVAL;
+ goto err_ssbi_controller;
+ }
+ dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type);
+ if (strcmp(type, "ssbi") == 0)
+ ssbi->controller_type = MSM_SBI_CTRL_SSBI;
+ else if (strcmp(type, "ssbi2") == 0)
+ ssbi->controller_type = MSM_SBI_CTRL_SSBI2;
+ else if (strcmp(type, "pmic-arbiter") == 0)
+ ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER;
+ else {
+ pr_err("Unknown qcom,controller-type\n");
+ ret = -EINVAL;
+ goto err_ssbi_controller;
+ }
+
+ if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
+ ssbi->read = ssbi_pa_read_bytes;
+ ssbi->write = ssbi_pa_write_bytes;
+ } else {
+ ssbi->read = ssbi_read_bytes;
+ ssbi->write = ssbi_write_bytes;
+ }
+
+ spin_lock_init(&ssbi->lock);
+
+ ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
+ if (ret)
+ goto err_ssbi_controller;
+
+ return 0;
+
+err_ssbi_controller:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(ssbi->base);
+err_ioremap:
+err_get_mem_res:
+ kfree(ssbi);
+ return ret;
+}
+
+static int ssbi_remove(struct platform_device *pdev)
+{
+ struct ssbi *ssbi = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ iounmap(ssbi->base);
+ kfree(ssbi);
+ return 0;
+}
+
+static struct of_device_id ssbi_match_table[] = {
+ { .compatible = "qcom,ssbi" },
+ {}
+};
+
+static struct platform_driver ssbi_driver = {
+ .probe = ssbi_probe,
+ .remove = ssbi_remove,
+ .driver = {
+ .name = "ssbi",
+ .owner = THIS_MODULE,
+ .of_match_table = ssbi_match_table,
+ },
+};
+
+static int __init ssbi_init(void)
+{
+ return platform_driver_register(&ssbi_driver);
+}
+module_init(ssbi_init);
+
+static void __exit ssbi_exit(void)
+{
+ platform_driver_unregister(&ssbi_driver);
+}
+module_exit(ssbi_exit)
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:ssbi");
+MODULE_AUTHOR("Dima Zavin <dima@android.com>");
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 093f10c88cce..4e8a1794f50a 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -110,19 +110,15 @@ source "drivers/staging/nvec/Kconfig"
source "drivers/staging/media/Kconfig"
-source "drivers/staging/net/Kconfig"
-
source "drivers/staging/android/Kconfig"
source "drivers/staging/ozwpan/Kconfig"
-source "drivers/staging/ccg/Kconfig"
-
source "drivers/staging/gdm72xx/Kconfig"
source "drivers/staging/csr/Kconfig"
-source "drivers/staging/omap-thermal/Kconfig"
+source "drivers/staging/ti-soc-thermal/Kconfig"
source "drivers/staging/silicom/Kconfig"
@@ -140,4 +136,8 @@ source "drivers/staging/zcache/Kconfig"
source "drivers/staging/goldfish/Kconfig"
+source "drivers/staging/netlogic/Kconfig"
+
+source "drivers/staging/dwc2/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index fa41b04cf4cb..415772ea306d 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -4,7 +4,6 @@
obj-$(CONFIG_STAGING) += staging.o
obj-y += media/
-obj-y += net/
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_USBIP_CORE) += usbip/
@@ -23,6 +22,7 @@ obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/
+obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/
@@ -50,10 +50,9 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
-obj-$(CONFIG_USB_G_CCG) += ccg/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_CSR_WIFI) += csr/
-obj-$(CONFIG_OMAP_BANDGAP) += omap-thermal/
+obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/
obj-$(CONFIG_CED1401) += ced1401/
obj-$(CONFIG_DRM_IMX) += imx-drm/
@@ -62,3 +61,4 @@ obj-$(CONFIG_SB105X) += sb105x/
obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/
obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_GOLDFISH) += goldfish/
+obj-$(CONFIG_USB_DWC2) += dwc2/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 465a28c08f20..9f61d46da157 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC
config ASHMEM
bool "Enable the Anonymous Shared Memory Subsystem"
default n
- depends on SHMEM || TINY_SHMEM
+ depends on SHMEM
---help---
The ashmem subsystem is a new shared memory allocator, similar to
POSIX SHM but with different behavior and sporting a simpler
@@ -72,6 +72,33 @@ config ANDROID_INTF_ALARM_DEV
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
Also exports the alarm interface to user-space.
+config SYNC
+ bool "Synchronization framework"
+ default n
+ select ANON_INODES
+ help
+ This option enables the framework for synchronization between multiple
+ drivers. Sync implementations can take advantage of hardware
+ synchronization built into devices like GPUs.
+
+config SW_SYNC
+ bool "Software synchronization objects"
+ default n
+ depends on SYNC
+ help
+ A sync object driver that uses a 32bit counter to coordinate
+ syncrhronization. Useful when there is no hardware primitive backing
+ the synchronization.
+
+config SW_SYNC_USER
+ bool "Userspace API for SW_SYNC"
+ default n
+ depends on SW_SYNC
+ help
+ Provides a user space API to the sw sync object.
+ *WARNING* improper use of this can result in deadlocking kernel
+ drivers from userspace.
+
endif # if ANDROID
endmenu
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index b35a631734d6..c136299e05af 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
+obj-$(CONFIG_SYNC) += sync.o
+obj-$(CONFIG_SW_SYNC) += sw_sync.o
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 634b9ae713e0..e681bdd9aa5f 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -414,20 +414,29 @@ out:
static int set_name(struct ashmem_area *asma, void __user *name)
{
int ret = 0;
+ char local_name[ASHMEM_NAME_LEN];
- mutex_lock(&ashmem_mutex);
+ /*
+ * Holding the ashmem_mutex while doing a copy_from_user might cause
+ * an data abort which would try to access mmap_sem. If another
+ * thread has invoked ashmem_mmap then it will be holding the
+ * semaphore and will be waiting for ashmem_mutex, there by leading to
+ * deadlock. We'll release the mutex and take the name to a local
+ * variable that does not need protection and later copy the local
+ * variable to the structure member with lock held.
+ */
+ if (copy_from_user(local_name, name, ASHMEM_NAME_LEN))
+ return -EFAULT;
+ mutex_lock(&ashmem_mutex);
/* cannot change an existing mapping's name */
if (unlikely(asma->file)) {
ret = -EINVAL;
goto out;
}
-
- if (unlikely(copy_from_user(asma->name + ASHMEM_NAME_PREFIX_LEN,
- name, ASHMEM_NAME_LEN)))
- ret = -EFAULT;
+ memcpy(asma->name + ASHMEM_NAME_PREFIX_LEN,
+ local_name, ASHMEM_NAME_LEN);
asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0';
-
out:
mutex_unlock(&ashmem_mutex);
@@ -437,26 +446,36 @@ out:
static int get_name(struct ashmem_area *asma, void __user *name)
{
int ret = 0;
+ size_t len;
+ /*
+ * Have a local variable to which we'll copy the content
+ * from asma with the lock held. Later we can copy this to the user
+ * space safely without holding any locks. So even if we proceed to
+ * wait for mmap_sem, it won't lead to deadlock.
+ */
+ char local_name[ASHMEM_NAME_LEN];
mutex_lock(&ashmem_mutex);
if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {
- size_t len;
/*
* Copying only `len', instead of ASHMEM_NAME_LEN, bytes
* prevents us from revealing one user's stack to another.
*/
len = strlen(asma->name + ASHMEM_NAME_PREFIX_LEN) + 1;
- if (unlikely(copy_to_user(name,
- asma->name + ASHMEM_NAME_PREFIX_LEN, len)))
- ret = -EFAULT;
+ memcpy(local_name, asma->name + ASHMEM_NAME_PREFIX_LEN, len);
} else {
- if (unlikely(copy_to_user(name, ASHMEM_NAME_DEF,
- sizeof(ASHMEM_NAME_DEF))))
- ret = -EFAULT;
+ len = sizeof(ASHMEM_NAME_DEF);
+ memcpy(local_name, ASHMEM_NAME_DEF, len);
}
mutex_unlock(&ashmem_mutex);
+ /*
+ * Now we are just copying from the stack variable to userland
+ * No lock held
+ */
+ if (unlikely(copy_to_user(name, local_name, len)))
+ ret = -EFAULT;
return ret;
}
@@ -683,6 +702,23 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
}
+/* support of 32bit userspace on 64bit platforms */
+#ifdef CONFIG_COMPAT
+static long compat_ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+
+ switch (cmd) {
+ case COMPAT_ASHMEM_SET_SIZE:
+ cmd = ASHMEM_SET_SIZE;
+ break;
+ case COMPAT_ASHMEM_SET_PROT_MASK:
+ cmd = ASHMEM_SET_PROT_MASK;
+ break;
+ }
+ return ashmem_ioctl(file, cmd, arg);
+}
+#endif
+
static const struct file_operations ashmem_fops = {
.owner = THIS_MODULE,
.open = ashmem_open,
@@ -691,7 +727,9 @@ static const struct file_operations ashmem_fops = {
.llseek = ashmem_llseek,
.mmap = ashmem_mmap,
.unlocked_ioctl = ashmem_ioctl,
- .compat_ioctl = ashmem_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_ashmem_ioctl,
+#endif
};
static struct miscdevice ashmem_misc = {
diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h
index 1976b10ef93e..8dc0f0d3adf3 100644
--- a/drivers/staging/android/ashmem.h
+++ b/drivers/staging/android/ashmem.h
@@ -14,6 +14,7 @@
#include <linux/limits.h>
#include <linux/ioctl.h>
+#include <linux/compat.h>
#define ASHMEM_NAME_LEN 256
@@ -45,4 +46,10 @@ struct ashmem_pin {
#define ASHMEM_GET_PIN_STATUS _IO(__ASHMEMIOC, 9)
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
+/* support of 32bit userspace on 64bit platforms */
+#ifdef CONFIG_COMPAT
+#define COMPAT_ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, compat_size_t)
+#define COMPAT_ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned int)
+#endif
+
#endif /* _LINUX_ASHMEM_H */
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 24456a0de6b2..1567ac296b39 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -2878,82 +2878,109 @@ static int binder_release(struct inode *nodp, struct file *filp)
return 0;
}
+static int binder_node_release(struct binder_node *node, int refs)
+{
+ struct binder_ref *ref;
+ int death = 0;
+
+ list_del_init(&node->work.entry);
+ binder_release_work(&node->async_todo);
+
+ if (hlist_empty(&node->refs)) {
+ kfree(node);
+ binder_stats_deleted(BINDER_STAT_NODE);
+
+ return refs;
+ }
+
+ node->proc = NULL;
+ node->local_strong_refs = 0;
+ node->local_weak_refs = 0;
+ hlist_add_head(&node->dead_node, &binder_dead_nodes);
+
+ hlist_for_each_entry(ref, &node->refs, node_entry) {
+ refs++;
+
+ if (!ref->death)
+ goto out;
+
+ death++;
+
+ if (list_empty(&ref->death->work.entry)) {
+ ref->death->work.type = BINDER_WORK_DEAD_BINDER;
+ list_add_tail(&ref->death->work.entry,
+ &ref->proc->todo);
+ wake_up_interruptible(&ref->proc->wait);
+ } else
+ BUG();
+ }
+
+out:
+ binder_debug(BINDER_DEBUG_DEAD_BINDER,
+ "node %d now dead, refs %d, death %d\n",
+ node->debug_id, refs, death);
+
+ return refs;
+}
+
static void binder_deferred_release(struct binder_proc *proc)
{
struct binder_transaction *t;
struct rb_node *n;
- int threads, nodes, incoming_refs, outgoing_refs, buffers, active_transactions, page_count;
+ int threads, nodes, incoming_refs, outgoing_refs, buffers,
+ active_transactions, page_count;
BUG_ON(proc->vma);
BUG_ON(proc->files);
hlist_del(&proc->proc_node);
+
if (binder_context_mgr_node && binder_context_mgr_node->proc == proc) {
binder_debug(BINDER_DEBUG_DEAD_BINDER,
- "binder_release: %d context_mgr_node gone\n",
- proc->pid);
+ "%s: %d context_mgr_node gone\n",
+ __func__, proc->pid);
binder_context_mgr_node = NULL;
}
threads = 0;
active_transactions = 0;
while ((n = rb_first(&proc->threads))) {
- struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);
+ struct binder_thread *thread;
+
+ thread = rb_entry(n, struct binder_thread, rb_node);
threads++;
active_transactions += binder_free_thread(proc, thread);
}
+
nodes = 0;
incoming_refs = 0;
while ((n = rb_first(&proc->nodes))) {
- struct binder_node *node = rb_entry(n, struct binder_node, rb_node);
+ struct binder_node *node;
+ node = rb_entry(n, struct binder_node, rb_node);
nodes++;
rb_erase(&node->rb_node, &proc->nodes);
- list_del_init(&node->work.entry);
- binder_release_work(&node->async_todo);
- if (hlist_empty(&node->refs)) {
- kfree(node);
- binder_stats_deleted(BINDER_STAT_NODE);
- } else {
- struct binder_ref *ref;
- int death = 0;
-
- node->proc = NULL;
- node->local_strong_refs = 0;
- node->local_weak_refs = 0;
- hlist_add_head(&node->dead_node, &binder_dead_nodes);
-
- hlist_for_each_entry(ref, &node->refs, node_entry) {
- incoming_refs++;
- if (ref->death) {
- death++;
- if (list_empty(&ref->death->work.entry)) {
- ref->death->work.type = BINDER_WORK_DEAD_BINDER;
- list_add_tail(&ref->death->work.entry, &ref->proc->todo);
- wake_up_interruptible(&ref->proc->wait);
- } else
- BUG();
- }
- }
- binder_debug(BINDER_DEBUG_DEAD_BINDER,
- "node %d now dead, refs %d, death %d\n",
- node->debug_id, incoming_refs, death);
- }
+ incoming_refs = binder_node_release(node, incoming_refs);
}
+
outgoing_refs = 0;
while ((n = rb_first(&proc->refs_by_desc))) {
- struct binder_ref *ref = rb_entry(n, struct binder_ref,
- rb_node_desc);
+ struct binder_ref *ref;
+
+ ref = rb_entry(n, struct binder_ref, rb_node_desc);
outgoing_refs++;
binder_delete_ref(ref);
}
+
binder_release_work(&proc->todo);
binder_release_work(&proc->delivered_death);
- buffers = 0;
+ buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) {
- struct binder_buffer *buffer = rb_entry(n, struct binder_buffer,
- rb_node);
+ struct binder_buffer *buffer;
+
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+
t = buffer->transaction;
if (t) {
t->buffer = NULL;
@@ -2962,6 +2989,7 @@ static void binder_deferred_release(struct binder_proc *proc)
proc->pid, t->debug_id);
/*BUG();*/
}
+
binder_free_buf(proc, buffer);
buffers++;
}
@@ -2971,18 +2999,20 @@ static void binder_deferred_release(struct binder_proc *proc)
page_count = 0;
if (proc->pages) {
int i;
+
for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) {
- if (proc->pages[i]) {
- void *page_addr = proc->buffer + i * PAGE_SIZE;
- binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "binder_release: %d: page %d at %p not freed\n",
- proc->pid, i,
- page_addr);
- unmap_kernel_range((unsigned long)page_addr,
- PAGE_SIZE);
- __free_page(proc->pages[i]);
- page_count++;
- }
+ void *page_addr;
+
+ if (!proc->pages[i])
+ continue;
+
+ page_addr = proc->buffer + i * PAGE_SIZE;
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%s: %d: page %d at %p not freed\n",
+ __func__, proc->pid, i, page_addr);
+ unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
+ __free_page(proc->pages[i]);
+ page_count++;
}
kfree(proc->pages);
vfree(proc->buffer);
@@ -2991,9 +3021,9 @@ static void binder_deferred_release(struct binder_proc *proc)
put_task_struct(proc->tsk);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
- "binder_release: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
- proc->pid, threads, nodes, incoming_refs, outgoing_refs,
- active_transactions, buffers, page_count);
+ "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n",
+ __func__, proc->pid, threads, nodes, incoming_refs,
+ outgoing_refs, active_transactions, buffers, page_count);
kfree(proc);
}
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index f240464effde..dbe81ceca1bd 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -85,11 +85,11 @@ struct binder_version {
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
-#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t)
+#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
-#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int)
-#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int)
-#define BINDER_THREAD_EXIT _IOW('b', 8, int)
+#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
+#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
+#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
/*
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index dbc63cbb4d3a..b14a55742559 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -68,6 +68,8 @@ static LIST_HEAD(log_list);
* @log: The associated log
* @list: The associated entry in @logger_log's list
* @r_off: The current read head offset.
+ * @r_all: Reader can read all entries
+ * @r_ver: Reader ABI version
*
* This object lives from open to release, so we don't need additional
* reference counting. The structure is protected by log->mutex.
@@ -76,6 +78,8 @@ struct logger_reader {
struct logger_log *log;
struct list_head list;
size_t r_off;
+ bool r_all;
+ int r_ver;
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
@@ -109,8 +113,29 @@ static inline struct logger_log *file_get_log(struct file *file)
}
/*
- * get_entry_len - Grabs the length of the payload of the next entry starting
- * from 'off'.
+ * get_entry_header - returns a pointer to the logger_entry header within
+ * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
+ * be provided. Typically the return value will be a pointer within
+ * 'logger->buf'. However, a pointer to 'scratch' may be returned if
+ * the log entry spans the end and beginning of the circular buffer.
+ */
+static struct logger_entry *get_entry_header(struct logger_log *log,
+ size_t off, struct logger_entry *scratch)
+{
+ size_t len = min(sizeof(struct logger_entry), log->size - off);
+ if (len != sizeof(struct logger_entry)) {
+ memcpy(((void *) scratch), log->buffer + off, len);
+ memcpy(((void *) scratch) + len, log->buffer,
+ sizeof(struct logger_entry) - len);
+ return scratch;
+ }
+
+ return (struct logger_entry *) (log->buffer + off);
+}
+
+/*
+ * get_entry_msg_len - Grabs the length of the message of the entry
+ * starting from from 'off'.
*
* An entry length is 2 bytes (16 bits) in host endian order.
* In the log, the length does not include the size of the log entry structure.
@@ -118,20 +143,45 @@ static inline struct logger_log *file_get_log(struct file *file)
*
* Caller needs to hold log->mutex.
*/
-static __u32 get_entry_len(struct logger_log *log, size_t off)
+static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
{
- __u16 val;
+ struct logger_entry scratch;
+ struct logger_entry *entry;
- /* copy 2 bytes from buffer, in memcpy order, */
- /* handling possible wrap at end of buffer */
+ entry = get_entry_header(log, off, &scratch);
+ return entry->len;
+}
- ((__u8 *)&val)[0] = log->buffer[off];
- if (likely(off+1 < log->size))
- ((__u8 *)&val)[1] = log->buffer[off+1];
+static size_t get_user_hdr_len(int ver)
+{
+ if (ver < 2)
+ return sizeof(struct user_logger_entry_compat);
else
- ((__u8 *)&val)[1] = log->buffer[0];
+ return sizeof(struct logger_entry);
+}
- return sizeof(struct logger_entry) + val;
+static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
+ char __user *buf)
+{
+ void *hdr;
+ size_t hdr_len;
+ struct user_logger_entry_compat v1;
+
+ if (ver < 2) {
+ v1.len = entry->len;
+ v1.__pad = 0;
+ v1.pid = entry->pid;
+ v1.tid = entry->tid;
+ v1.sec = entry->sec;
+ v1.nsec = entry->nsec;
+ hdr = &v1;
+ hdr_len = sizeof(struct user_logger_entry_compat);
+ } else {
+ hdr = entry;
+ hdr_len = sizeof(struct logger_entry);
+ }
+
+ return copy_to_user(buf, hdr, hdr_len);
}
/*
@@ -145,15 +195,31 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
char __user *buf,
size_t count)
{
+ struct logger_entry scratch;
+ struct logger_entry *entry;
size_t len;
+ size_t msg_start;
/*
- * We read from the log in two disjoint operations. First, we read from
- * the current read head offset up to 'count' bytes or to the end of
+ * First, copy the header to userspace, using the version of
+ * the header requested
+ */
+ entry = get_entry_header(log, reader->r_off, &scratch);
+ if (copy_header_to_user(reader->r_ver, entry, buf))
+ return -EFAULT;
+
+ count -= get_user_hdr_len(reader->r_ver);
+ buf += get_user_hdr_len(reader->r_ver);
+ msg_start = logger_offset(log,
+ reader->r_off + sizeof(struct logger_entry));
+
+ /*
+ * We read from the msg in two disjoint operations. First, we read from
+ * the current msg head offset up to 'count' bytes or to the end of
* the log, whichever comes first.
*/
- len = min(count, log->size - reader->r_off);
- if (copy_to_user(buf, log->buffer + reader->r_off, len))
+ len = min(count, log->size - msg_start);
+ if (copy_to_user(buf, log->buffer + msg_start, len))
return -EFAULT;
/*
@@ -164,9 +230,34 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT;
- reader->r_off = logger_offset(log, reader->r_off + count);
+ reader->r_off = logger_offset(log, reader->r_off +
+ sizeof(struct logger_entry) + count);
- return count;
+ return count + get_user_hdr_len(reader->r_ver);
+}
+
+/*
+ * get_next_entry_by_uid - Starting at 'off', returns an offset into
+ * 'log->buffer' which contains the first entry readable by 'euid'
+ */
+static size_t get_next_entry_by_uid(struct logger_log *log,
+ size_t off, uid_t euid)
+{
+ while (off != log->w_off) {
+ struct logger_entry *entry;
+ struct logger_entry scratch;
+ size_t next_len;
+
+ entry = get_entry_header(log, off, &scratch);
+
+ if (entry->euid == euid)
+ return off;
+
+ next_len = sizeof(struct logger_entry) + entry->len;
+ off = logger_offset(log, off + next_len);
+ }
+
+ return off;
}
/*
@@ -178,7 +269,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
* - If there are no log entries to read, blocks until log is written to
* - Atomically reads exactly one log entry
*
- * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
+ * Will set errno to EINVAL if read
* buffer is insufficient to hold next entry.
*/
static ssize_t logger_read(struct file *file, char __user *buf,
@@ -219,6 +310,10 @@ start:
mutex_lock(&log->mutex);
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
/* is there still something to read or did we race? */
if (unlikely(log->w_off == reader->r_off)) {
mutex_unlock(&log->mutex);
@@ -226,7 +321,8 @@ start:
}
/* get the size of the next entry */
- ret = get_entry_len(log, reader->r_off);
+ ret = get_user_hdr_len(reader->r_ver) +
+ get_entry_msg_len(log, reader->r_off);
if (count < ret) {
ret = -EINVAL;
goto out;
@@ -252,7 +348,8 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
size_t count = 0;
do {
- size_t nr = get_entry_len(log, off);
+ size_t nr = sizeof(struct logger_entry) +
+ get_entry_msg_len(log, off);
off = logger_offset(log, off + nr);
count += nr;
} while (count < len);
@@ -382,7 +479,9 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
header.tid = current->pid;
header.sec = now.tv_sec;
header.nsec = now.tv_nsec;
+ header.euid = current_euid();
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
+ header.hdr_size = sizeof(struct logger_entry);
/* null writes succeed, return zero */
if (unlikely(!header.len))
@@ -463,6 +562,10 @@ static int logger_open(struct inode *inode, struct file *file)
return -ENOMEM;
reader->log = log;
+ reader->r_ver = 1;
+ reader->r_all = in_egroup_p(inode->i_gid) ||
+ capable(CAP_SYSLOG);
+
INIT_LIST_HEAD(&reader->list);
mutex_lock(&log->mutex);
@@ -522,6 +625,10 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
poll_wait(file, &log->wq, wait);
mutex_lock(&log->mutex);
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
if (log->w_off != reader->r_off)
ret |= POLLIN | POLLRDNORM;
mutex_unlock(&log->mutex);
@@ -529,11 +636,25 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
return ret;
}
+static long logger_set_version(struct logger_reader *reader, void __user *arg)
+{
+ int version;
+ if (copy_from_user(&version, arg, sizeof(int)))
+ return -EFAULT;
+
+ if ((version < 1) || (version > 2))
+ return -EINVAL;
+
+ reader->r_ver = version;
+ return 0;
+}
+
static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct logger_log *log = file_get_log(file);
struct logger_reader *reader;
- long ret = -ENOTTY;
+ long ret = -EINVAL;
+ void __user *argp = (void __user *) arg;
mutex_lock(&log->mutex);
@@ -558,8 +679,14 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
reader = file->private_data;
+
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
if (log->w_off != reader->r_off)
- ret = get_entry_len(log, reader->r_off);
+ ret = get_user_hdr_len(reader->r_ver) +
+ get_entry_msg_len(log, reader->r_off);
else
ret = 0;
break;
@@ -568,11 +695,32 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -EBADF;
break;
}
+ if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
+ capable(CAP_SYSLOG))) {
+ ret = -EPERM;
+ break;
+ }
list_for_each_entry(reader, &log->readers, list)
reader->r_off = log->w_off;
log->head = log->w_off;
ret = 0;
break;
+ case LOGGER_GET_VERSION:
+ if (!(file->f_mode & FMODE_READ)) {
+ ret = -EBADF;
+ break;
+ }
+ reader = file->private_data;
+ ret = reader->r_ver;
+ break;
+ case LOGGER_SET_VERSION:
+ if (!(file->f_mode & FMODE_READ)) {
+ ret = -EBADF;
+ break;
+ }
+ reader = file->private_data;
+ ret = logger_set_version(reader, argp);
+ break;
}
mutex_unlock(&log->mutex);
@@ -592,8 +740,8 @@ static const struct file_operations logger_fops = {
};
/*
- * Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN,
- * and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
+ * Log size must must be a power of two, and greater than
+ * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
*/
static int __init create_log(char *log_name, int size)
{
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
index 9b929a8c7468..cc6bbd99c8e0 100644
--- a/drivers/staging/android/logger.h
+++ b/drivers/staging/android/logger.h
@@ -21,7 +21,7 @@
#include <linux/ioctl.h>
/**
- * struct logger_entry - defines a single entry that is given to a logger
+ * struct user_logger_entry_compat - defines a single entry that is given to a logger
* @len: The length of the payload
* @__pad: Two bytes of padding that appear to be required
* @pid: The generating process' process ID
@@ -29,8 +29,12 @@
* @sec: The number of seconds that have elapsed since the Epoch
* @nsec: The number of nanoseconds that have elapsed since @sec
* @msg: The message that is to be logged
+ *
+ * The userspace structure for version 1 of the logger_entry ABI.
+ * This structure is returned to userspace unless the caller requests
+ * an upgrade to a newer ABI version.
*/
-struct logger_entry {
+struct user_logger_entry_compat {
__u16 len;
__u16 __pad;
__s32 pid;
@@ -40,14 +44,38 @@ struct logger_entry {
char msg[0];
};
+/**
+ * struct logger_entry - defines a single entry that is given to a logger
+ * @len: The length of the payload
+ * @hdr_size: sizeof(struct logger_entry_v2)
+ * @pid: The generating process' process ID
+ * @tid: The generating process' thread ID
+ * @sec: The number of seconds that have elapsed since the Epoch
+ * @nsec: The number of nanoseconds that have elapsed since @sec
+ * @euid: Effective UID of logger
+ * @msg: The message that is to be logged
+ *
+ * The structure for version 2 of the logger_entry ABI.
+ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
+ * is called with version >= 2
+ */
+struct logger_entry {
+ __u16 len;
+ __u16 hdr_size;
+ __s32 pid;
+ __s32 tid;
+ __s32 sec;
+ __s32 nsec;
+ uid_t euid;
+ char msg[0];
+};
+
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
#define LOGGER_LOG_MAIN "log_main" /* everything else */
-#define LOGGER_ENTRY_MAX_LEN (4*1024)
-#define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
+#define LOGGER_ENTRY_MAX_PAYLOAD 4076
#define __LOGGERIO 0xAE
@@ -55,5 +83,7 @@ struct logger_entry {
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
+#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
+#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
#endif /* _LINUX_LOGGER_H */
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 3b91b0fd4de3..fe74494868ef 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -30,16 +30,19 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/oom.h>
#include <linux/sched.h>
+#include <linux/swap.h>
#include <linux/rcupdate.h>
#include <linux/profile.h>
#include <linux/notifier.h>
-static uint32_t lowmem_debug_level = 2;
+static uint32_t lowmem_debug_level = 1;
static short lowmem_adj[6] = {
0,
1,
@@ -60,7 +63,7 @@ static unsigned long lowmem_deathpending_timeout;
#define lowmem_print(level, x...) \
do { \
if (lowmem_debug_level >= (level)) \
- printk(x); \
+ pr_info(x); \
} while (0)
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
@@ -74,7 +77,7 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
int selected_tasksize = 0;
short selected_oom_score_adj;
int array_size = ARRAY_SIZE(lowmem_adj);
- int other_free = global_page_state(NR_FREE_PAGES);
+ int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
int other_file = global_page_state(NR_FILE_PAGES) -
global_page_state(NR_SHMEM);
diff --git a/drivers/staging/android/sw_sync.c b/drivers/staging/android/sw_sync.c
new file mode 100644
index 000000000000..4928f93bdf3d
--- /dev/null
+++ b/drivers/staging/android/sw_sync.c
@@ -0,0 +1,264 @@
+/*
+ * drivers/base/sw_sync.c
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include "sw_sync.h"
+
+static int sw_sync_cmp(u32 a, u32 b)
+{
+ if (a == b)
+ return 0;
+
+ return ((s32)a - (s32)b) < 0 ? -1 : 1;
+}
+
+struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value)
+{
+ struct sw_sync_pt *pt;
+
+ pt = (struct sw_sync_pt *)
+ sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt));
+
+ pt->value = value;
+
+ return (struct sync_pt *)pt;
+}
+EXPORT_SYMBOL(sw_sync_pt_create);
+
+static struct sync_pt *sw_sync_pt_dup(struct sync_pt *sync_pt)
+{
+ struct sw_sync_pt *pt = (struct sw_sync_pt *) sync_pt;
+ struct sw_sync_timeline *obj =
+ (struct sw_sync_timeline *)sync_pt->parent;
+
+ return (struct sync_pt *) sw_sync_pt_create(obj, pt->value);
+}
+
+static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt)
+{
+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
+ struct sw_sync_timeline *obj =
+ (struct sw_sync_timeline *)sync_pt->parent;
+
+ return sw_sync_cmp(obj->value, pt->value) >= 0;
+}
+
+static int sw_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
+{
+ struct sw_sync_pt *pt_a = (struct sw_sync_pt *)a;
+ struct sw_sync_pt *pt_b = (struct sw_sync_pt *)b;
+
+ return sw_sync_cmp(pt_a->value, pt_b->value);
+}
+
+static int sw_sync_fill_driver_data(struct sync_pt *sync_pt,
+ void *data, int size)
+{
+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
+
+ if (size < sizeof(pt->value))
+ return -ENOMEM;
+
+ memcpy(data, &pt->value, sizeof(pt->value));
+
+ return sizeof(pt->value);
+}
+
+static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline,
+ char *str, int size)
+{
+ struct sw_sync_timeline *timeline =
+ (struct sw_sync_timeline *)sync_timeline;
+ snprintf(str, size, "%d", timeline->value);
+}
+
+static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
+ char *str, int size)
+{
+ struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
+ snprintf(str, size, "%d", pt->value);
+}
+
+static struct sync_timeline_ops sw_sync_timeline_ops = {
+ .driver_name = "sw_sync",
+ .dup = sw_sync_pt_dup,
+ .has_signaled = sw_sync_pt_has_signaled,
+ .compare = sw_sync_pt_compare,
+ .fill_driver_data = sw_sync_fill_driver_data,
+ .timeline_value_str = sw_sync_timeline_value_str,
+ .pt_value_str = sw_sync_pt_value_str,
+};
+
+
+struct sw_sync_timeline *sw_sync_timeline_create(const char *name)
+{
+ struct sw_sync_timeline *obj = (struct sw_sync_timeline *)
+ sync_timeline_create(&sw_sync_timeline_ops,
+ sizeof(struct sw_sync_timeline),
+ name);
+
+ return obj;
+}
+EXPORT_SYMBOL(sw_sync_timeline_create);
+
+void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
+{
+ obj->value += inc;
+
+ sync_timeline_signal(&obj->obj);
+}
+EXPORT_SYMBOL(sw_sync_timeline_inc);
+
+#ifdef CONFIG_SW_SYNC_USER
+/* *WARNING*
+ *
+ * improper use of this can result in deadlocking kernel drivers from userspace.
+ */
+
+/* opening sw_sync create a new sync obj */
+static int sw_sync_open(struct inode *inode, struct file *file)
+{
+ struct sw_sync_timeline *obj;
+ char task_comm[TASK_COMM_LEN];
+
+ get_task_comm(task_comm, current);
+
+ obj = sw_sync_timeline_create(task_comm);
+ if (obj == NULL)
+ return -ENOMEM;
+
+ file->private_data = obj;
+
+ return 0;
+}
+
+static int sw_sync_release(struct inode *inode, struct file *file)
+{
+ struct sw_sync_timeline *obj = file->private_data;
+ sync_timeline_destroy(&obj->obj);
+ return 0;
+}
+
+static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj, unsigned long arg)
+{
+ int fd = get_unused_fd();
+ int err;
+ struct sync_pt *pt;
+ struct sync_fence *fence;
+ struct sw_sync_create_fence_data data;
+
+ if (fd < 0)
+ return fd;
+
+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
+ err = -EFAULT;
+ goto err;
+ }
+
+ pt = sw_sync_pt_create(obj, data.value);
+ if (pt == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ data.name[sizeof(data.name) - 1] = '\0';
+ fence = sync_fence_create(data.name, pt);
+ if (fence == NULL) {
+ sync_pt_free(pt);
+ err = -ENOMEM;
+ goto err;
+ }
+
+ data.fence = fd;
+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
+ sync_fence_put(fence);
+ err = -EFAULT;
+ goto err;
+ }
+
+ sync_fence_install(fence, fd);
+
+ return 0;
+
+err:
+ put_unused_fd(fd);
+ return err;
+}
+
+static long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg)
+{
+ u32 value;
+
+ if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
+ return -EFAULT;
+
+ sw_sync_timeline_inc(obj, value);
+
+ return 0;
+}
+
+static long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct sw_sync_timeline *obj = file->private_data;
+
+ switch (cmd) {
+ case SW_SYNC_IOC_CREATE_FENCE:
+ return sw_sync_ioctl_create_fence(obj, arg);
+
+ case SW_SYNC_IOC_INC:
+ return sw_sync_ioctl_inc(obj, arg);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations sw_sync_fops = {
+ .owner = THIS_MODULE,
+ .open = sw_sync_open,
+ .release = sw_sync_release,
+ .unlocked_ioctl = sw_sync_ioctl,
+ .compat_ioctl = sw_sync_ioctl,
+};
+
+static struct miscdevice sw_sync_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sw_sync",
+ .fops = &sw_sync_fops,
+};
+
+static int __init sw_sync_device_init(void)
+{
+ return misc_register(&sw_sync_dev);
+}
+
+static void __exit sw_sync_device_remove(void)
+{
+ misc_deregister(&sw_sync_dev);
+}
+
+module_init(sw_sync_device_init);
+module_exit(sw_sync_device_remove);
+
+#endif /* CONFIG_SW_SYNC_USER */
diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h
new file mode 100644
index 000000000000..585040be5f18
--- /dev/null
+++ b/drivers/staging/android/sw_sync.h
@@ -0,0 +1,58 @@
+/*
+ * include/linux/sw_sync.h
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SW_SYNC_H
+#define _LINUX_SW_SYNC_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+#include "sync.h"
+
+struct sw_sync_timeline {
+ struct sync_timeline obj;
+
+ u32 value;
+};
+
+struct sw_sync_pt {
+ struct sync_pt pt;
+
+ u32 value;
+};
+
+struct sw_sync_timeline *sw_sync_timeline_create(const char *name);
+void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc);
+
+struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value);
+
+#endif /* __KERNEL __ */
+
+struct sw_sync_create_fence_data {
+ __u32 value;
+ char name[32];
+ __s32 fence; /* fd of new fence */
+};
+
+#define SW_SYNC_IOC_MAGIC 'W'
+
+#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
+ struct sw_sync_create_fence_data)
+#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
+
+
+#endif /* _LINUX_SW_SYNC_H */
diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c
new file mode 100644
index 000000000000..3893a3574769
--- /dev/null
+++ b/drivers/staging/android/sync.c
@@ -0,0 +1,1017 @@
+/*
+ * drivers/base/sync.c
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/anon_inodes.h>
+
+#include "sync.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace/sync.h"
+
+static void sync_fence_signal_pt(struct sync_pt *pt);
+static int _sync_pt_has_signaled(struct sync_pt *pt);
+static void sync_fence_free(struct kref *kref);
+static void sync_dump(void);
+
+static LIST_HEAD(sync_timeline_list_head);
+static DEFINE_SPINLOCK(sync_timeline_list_lock);
+
+static LIST_HEAD(sync_fence_list_head);
+static DEFINE_SPINLOCK(sync_fence_list_lock);
+
+struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
+ int size, const char *name)
+{
+ struct sync_timeline *obj;
+ unsigned long flags;
+
+ if (size < sizeof(struct sync_timeline))
+ return NULL;
+
+ obj = kzalloc(size, GFP_KERNEL);
+ if (obj == NULL)
+ return NULL;
+
+ kref_init(&obj->kref);
+ obj->ops = ops;
+ strlcpy(obj->name, name, sizeof(obj->name));
+
+ INIT_LIST_HEAD(&obj->child_list_head);
+ spin_lock_init(&obj->child_list_lock);
+
+ INIT_LIST_HEAD(&obj->active_list_head);
+ spin_lock_init(&obj->active_list_lock);
+
+ spin_lock_irqsave(&sync_timeline_list_lock, flags);
+ list_add_tail(&obj->sync_timeline_list, &sync_timeline_list_head);
+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
+
+ return obj;
+}
+EXPORT_SYMBOL(sync_timeline_create);
+
+static void sync_timeline_free(struct kref *kref)
+{
+ struct sync_timeline *obj =
+ container_of(kref, struct sync_timeline, kref);
+ unsigned long flags;
+
+ if (obj->ops->release_obj)
+ obj->ops->release_obj(obj);
+
+ spin_lock_irqsave(&sync_timeline_list_lock, flags);
+ list_del(&obj->sync_timeline_list);
+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
+
+ kfree(obj);
+}
+
+void sync_timeline_destroy(struct sync_timeline *obj)
+{
+ obj->destroyed = true;
+
+ /*
+ * If this is not the last reference, signal any children
+ * that their parent is going away.
+ */
+
+ if (!kref_put(&obj->kref, sync_timeline_free))
+ sync_timeline_signal(obj);
+}
+EXPORT_SYMBOL(sync_timeline_destroy);
+
+static void sync_timeline_add_pt(struct sync_timeline *obj, struct sync_pt *pt)
+{
+ unsigned long flags;
+
+ pt->parent = obj;
+
+ spin_lock_irqsave(&obj->child_list_lock, flags);
+ list_add_tail(&pt->child_list, &obj->child_list_head);
+ spin_unlock_irqrestore(&obj->child_list_lock, flags);
+}
+
+static void sync_timeline_remove_pt(struct sync_pt *pt)
+{
+ struct sync_timeline *obj = pt->parent;
+ unsigned long flags;
+
+ spin_lock_irqsave(&obj->active_list_lock, flags);
+ if (!list_empty(&pt->active_list))
+ list_del_init(&pt->active_list);
+ spin_unlock_irqrestore(&obj->active_list_lock, flags);
+
+ spin_lock_irqsave(&obj->child_list_lock, flags);
+ if (!list_empty(&pt->child_list)) {
+ list_del_init(&pt->child_list);
+ }
+ spin_unlock_irqrestore(&obj->child_list_lock, flags);
+}
+
+void sync_timeline_signal(struct sync_timeline *obj)
+{
+ unsigned long flags;
+ LIST_HEAD(signaled_pts);
+ struct list_head *pos, *n;
+
+ trace_sync_timeline(obj);
+
+ spin_lock_irqsave(&obj->active_list_lock, flags);
+
+ list_for_each_safe(pos, n, &obj->active_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, active_list);
+
+ if (_sync_pt_has_signaled(pt)) {
+ list_del_init(pos);
+ list_add(&pt->signaled_list, &signaled_pts);
+ kref_get(&pt->fence->kref);
+ }
+ }
+
+ spin_unlock_irqrestore(&obj->active_list_lock, flags);
+
+ list_for_each_safe(pos, n, &signaled_pts) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, signaled_list);
+
+ list_del_init(pos);
+ sync_fence_signal_pt(pt);
+ kref_put(&pt->fence->kref, sync_fence_free);
+ }
+}
+EXPORT_SYMBOL(sync_timeline_signal);
+
+struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size)
+{
+ struct sync_pt *pt;
+
+ if (size < sizeof(struct sync_pt))
+ return NULL;
+
+ pt = kzalloc(size, GFP_KERNEL);
+ if (pt == NULL)
+ return NULL;
+
+ INIT_LIST_HEAD(&pt->active_list);
+ kref_get(&parent->kref);
+ sync_timeline_add_pt(parent, pt);
+
+ return pt;
+}
+EXPORT_SYMBOL(sync_pt_create);
+
+void sync_pt_free(struct sync_pt *pt)
+{
+ if (pt->parent->ops->free_pt)
+ pt->parent->ops->free_pt(pt);
+
+ sync_timeline_remove_pt(pt);
+
+ kref_put(&pt->parent->kref, sync_timeline_free);
+
+ kfree(pt);
+}
+EXPORT_SYMBOL(sync_pt_free);
+
+/* call with pt->parent->active_list_lock held */
+static int _sync_pt_has_signaled(struct sync_pt *pt)
+{
+ int old_status = pt->status;
+
+ if (!pt->status)
+ pt->status = pt->parent->ops->has_signaled(pt);
+
+ if (!pt->status && pt->parent->destroyed)
+ pt->status = -ENOENT;
+
+ if (pt->status != old_status)
+ pt->timestamp = ktime_get();
+
+ return pt->status;
+}
+
+static struct sync_pt *sync_pt_dup(struct sync_pt *pt)
+{
+ return pt->parent->ops->dup(pt);
+}
+
+/* Adds a sync pt to the active queue. Called when added to a fence */
+static void sync_pt_activate(struct sync_pt *pt)
+{
+ struct sync_timeline *obj = pt->parent;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&obj->active_list_lock, flags);
+
+ err = _sync_pt_has_signaled(pt);
+ if (err != 0)
+ goto out;
+
+ list_add_tail(&pt->active_list, &obj->active_list_head);
+
+out:
+ spin_unlock_irqrestore(&obj->active_list_lock, flags);
+}
+
+static int sync_fence_release(struct inode *inode, struct file *file);
+static unsigned int sync_fence_poll(struct file *file, poll_table *wait);
+static long sync_fence_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
+
+
+static const struct file_operations sync_fence_fops = {
+ .release = sync_fence_release,
+ .poll = sync_fence_poll,
+ .unlocked_ioctl = sync_fence_ioctl,
+ .compat_ioctl = sync_fence_ioctl,
+};
+
+static struct sync_fence *sync_fence_alloc(const char *name)
+{
+ struct sync_fence *fence;
+ unsigned long flags;
+
+ fence = kzalloc(sizeof(struct sync_fence), GFP_KERNEL);
+ if (fence == NULL)
+ return NULL;
+
+ fence->file = anon_inode_getfile("sync_fence", &sync_fence_fops,
+ fence, 0);
+ if (IS_ERR(fence->file))
+ goto err;
+
+ kref_init(&fence->kref);
+ strlcpy(fence->name, name, sizeof(fence->name));
+
+ INIT_LIST_HEAD(&fence->pt_list_head);
+ INIT_LIST_HEAD(&fence->waiter_list_head);
+ spin_lock_init(&fence->waiter_list_lock);
+
+ init_waitqueue_head(&fence->wq);
+
+ spin_lock_irqsave(&sync_fence_list_lock, flags);
+ list_add_tail(&fence->sync_fence_list, &sync_fence_list_head);
+ spin_unlock_irqrestore(&sync_fence_list_lock, flags);
+
+ return fence;
+
+err:
+ kfree(fence);
+ return NULL;
+}
+
+/* TODO: implement a create which takes more that one sync_pt */
+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt)
+{
+ struct sync_fence *fence;
+
+ if (pt->fence)
+ return NULL;
+
+ fence = sync_fence_alloc(name);
+ if (fence == NULL)
+ return NULL;
+
+ pt->fence = fence;
+ list_add(&pt->pt_list, &fence->pt_list_head);
+ sync_pt_activate(pt);
+
+ /*
+ * signal the fence in case pt was activated before
+ * sync_pt_activate(pt) was called
+ */
+ sync_fence_signal_pt(pt);
+
+ return fence;
+}
+EXPORT_SYMBOL(sync_fence_create);
+
+static int sync_fence_copy_pts(struct sync_fence *dst, struct sync_fence *src)
+{
+ struct list_head *pos;
+
+ list_for_each(pos, &src->pt_list_head) {
+ struct sync_pt *orig_pt =
+ container_of(pos, struct sync_pt, pt_list);
+ struct sync_pt *new_pt = sync_pt_dup(orig_pt);
+
+ if (new_pt == NULL)
+ return -ENOMEM;
+
+ new_pt->fence = dst;
+ list_add(&new_pt->pt_list, &dst->pt_list_head);
+ }
+
+ return 0;
+}
+
+static int sync_fence_merge_pts(struct sync_fence *dst, struct sync_fence *src)
+{
+ struct list_head *src_pos, *dst_pos, *n;
+
+ list_for_each(src_pos, &src->pt_list_head) {
+ struct sync_pt *src_pt =
+ container_of(src_pos, struct sync_pt, pt_list);
+ bool collapsed = false;
+
+ list_for_each_safe(dst_pos, n, &dst->pt_list_head) {
+ struct sync_pt *dst_pt =
+ container_of(dst_pos, struct sync_pt, pt_list);
+ /* collapse two sync_pts on the same timeline
+ * to a single sync_pt that will signal at
+ * the later of the two
+ */
+ if (dst_pt->parent == src_pt->parent) {
+ if (dst_pt->parent->ops->compare(dst_pt, src_pt)
+ == -1) {
+ struct sync_pt *new_pt =
+ sync_pt_dup(src_pt);
+ if (new_pt == NULL)
+ return -ENOMEM;
+
+ new_pt->fence = dst;
+ list_replace(&dst_pt->pt_list,
+ &new_pt->pt_list);
+ sync_pt_free(dst_pt);
+ }
+ collapsed = true;
+ break;
+ }
+ }
+
+ if (!collapsed) {
+ struct sync_pt *new_pt = sync_pt_dup(src_pt);
+
+ if (new_pt == NULL)
+ return -ENOMEM;
+
+ new_pt->fence = dst;
+ list_add(&new_pt->pt_list, &dst->pt_list_head);
+ }
+ }
+
+ return 0;
+}
+
+static void sync_fence_detach_pts(struct sync_fence *fence)
+{
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &fence->pt_list_head) {
+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
+ sync_timeline_remove_pt(pt);
+ }
+}
+
+static void sync_fence_free_pts(struct sync_fence *fence)
+{
+ struct list_head *pos, *n;
+
+ list_for_each_safe(pos, n, &fence->pt_list_head) {
+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
+ sync_pt_free(pt);
+ }
+}
+
+struct sync_fence *sync_fence_fdget(int fd)
+{
+ struct file *file = fget(fd);
+
+ if (file == NULL)
+ return NULL;
+
+ if (file->f_op != &sync_fence_fops)
+ goto err;
+
+ return file->private_data;
+
+err:
+ fput(file);
+ return NULL;
+}
+EXPORT_SYMBOL(sync_fence_fdget);
+
+void sync_fence_put(struct sync_fence *fence)
+{
+ fput(fence->file);
+}
+EXPORT_SYMBOL(sync_fence_put);
+
+void sync_fence_install(struct sync_fence *fence, int fd)
+{
+ fd_install(fd, fence->file);
+}
+EXPORT_SYMBOL(sync_fence_install);
+
+static int sync_fence_get_status(struct sync_fence *fence)
+{
+ struct list_head *pos;
+ int status = 1;
+
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
+ int pt_status = pt->status;
+
+ if (pt_status < 0) {
+ status = pt_status;
+ break;
+ } else if (status == 1) {
+ status = pt_status;
+ }
+ }
+
+ return status;
+}
+
+struct sync_fence *sync_fence_merge(const char *name,
+ struct sync_fence *a, struct sync_fence *b)
+{
+ struct sync_fence *fence;
+ struct list_head *pos;
+ int err;
+
+ fence = sync_fence_alloc(name);
+ if (fence == NULL)
+ return NULL;
+
+ err = sync_fence_copy_pts(fence, a);
+ if (err < 0)
+ goto err;
+
+ err = sync_fence_merge_pts(fence, b);
+ if (err < 0)
+ goto err;
+
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, pt_list);
+ sync_pt_activate(pt);
+ }
+
+ /*
+ * signal the fence in case one of it's pts were activated before
+ * they were activated
+ */
+ sync_fence_signal_pt(list_first_entry(&fence->pt_list_head,
+ struct sync_pt,
+ pt_list));
+
+ return fence;
+err:
+ sync_fence_free_pts(fence);
+ kfree(fence);
+ return NULL;
+}
+EXPORT_SYMBOL(sync_fence_merge);
+
+static void sync_fence_signal_pt(struct sync_pt *pt)
+{
+ LIST_HEAD(signaled_waiters);
+ struct sync_fence *fence = pt->fence;
+ struct list_head *pos;
+ struct list_head *n;
+ unsigned long flags;
+ int status;
+
+ status = sync_fence_get_status(fence);
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+ /*
+ * this should protect against two threads racing on the signaled
+ * false -> true transition
+ */
+ if (status && !fence->status) {
+ list_for_each_safe(pos, n, &fence->waiter_list_head)
+ list_move(pos, &signaled_waiters);
+
+ fence->status = status;
+ } else {
+ status = 0;
+ }
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+
+ if (status) {
+ list_for_each_safe(pos, n, &signaled_waiters) {
+ struct sync_fence_waiter *waiter =
+ container_of(pos, struct sync_fence_waiter,
+ waiter_list);
+
+ list_del(pos);
+ waiter->callback(fence, waiter);
+ }
+ wake_up(&fence->wq);
+ }
+}
+
+int sync_fence_wait_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter)
+{
+ unsigned long flags;
+ int err = 0;
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+
+ if (fence->status) {
+ err = fence->status;
+ goto out;
+ }
+
+ list_add_tail(&waiter->waiter_list, &fence->waiter_list_head);
+out:
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(sync_fence_wait_async);
+
+int sync_fence_cancel_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter)
+{
+ struct list_head *pos;
+ struct list_head *n;
+ unsigned long flags;
+ int ret = -ENOENT;
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+ /*
+ * Make sure waiter is still in waiter_list because it is possible for
+ * the waiter to be removed from the list while the callback is still
+ * pending.
+ */
+ list_for_each_safe(pos, n, &fence->waiter_list_head) {
+ struct sync_fence_waiter *list_waiter =
+ container_of(pos, struct sync_fence_waiter,
+ waiter_list);
+ if (list_waiter == waiter) {
+ list_del(pos);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(sync_fence_cancel_async);
+
+static bool sync_fence_check(struct sync_fence *fence)
+{
+ /*
+ * Make sure that reads to fence->status are ordered with the
+ * wait queue event triggering
+ */
+ smp_rmb();
+ return fence->status != 0;
+}
+
+int sync_fence_wait(struct sync_fence *fence, long timeout)
+{
+ int err = 0;
+ struct sync_pt *pt;
+
+ trace_sync_wait(fence, 1);
+ list_for_each_entry(pt, &fence->pt_list_head, pt_list)
+ trace_sync_pt(pt);
+
+ if (timeout > 0) {
+ timeout = msecs_to_jiffies(timeout);
+ err = wait_event_interruptible_timeout(fence->wq,
+ sync_fence_check(fence),
+ timeout);
+ } else if (timeout < 0) {
+ err = wait_event_interruptible(fence->wq,
+ sync_fence_check(fence));
+ }
+ trace_sync_wait(fence, 0);
+
+ if (err < 0)
+ return err;
+
+ if (fence->status < 0) {
+ pr_info("fence error %d on [%p]\n", fence->status, fence);
+ sync_dump();
+ return fence->status;
+ }
+
+ if (fence->status == 0) {
+ if (timeout > 0) {
+ pr_info("fence timeout on [%p] after %dms\n", fence,
+ jiffies_to_msecs(timeout));
+ sync_dump();
+ }
+ return -ETIME;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sync_fence_wait);
+
+static void sync_fence_free(struct kref *kref)
+{
+ struct sync_fence *fence = container_of(kref, struct sync_fence, kref);
+
+ sync_fence_free_pts(fence);
+
+ kfree(fence);
+}
+
+static int sync_fence_release(struct inode *inode, struct file *file)
+{
+ struct sync_fence *fence = file->private_data;
+ unsigned long flags;
+
+ /*
+ * We need to remove all ways to access this fence before droping
+ * our ref.
+ *
+ * start with its membership in the global fence list
+ */
+ spin_lock_irqsave(&sync_fence_list_lock, flags);
+ list_del(&fence->sync_fence_list);
+ spin_unlock_irqrestore(&sync_fence_list_lock, flags);
+
+ /*
+ * remove its pts from their parents so that sync_timeline_signal()
+ * can't reference the fence.
+ */
+ sync_fence_detach_pts(fence);
+
+ kref_put(&fence->kref, sync_fence_free);
+
+ return 0;
+}
+
+static unsigned int sync_fence_poll(struct file *file, poll_table *wait)
+{
+ struct sync_fence *fence = file->private_data;
+
+ poll_wait(file, &fence->wq, wait);
+
+ /*
+ * Make sure that reads to fence->status are ordered with the
+ * wait queue event triggering
+ */
+ smp_rmb();
+
+ if (fence->status == 1)
+ return POLLIN;
+ else if (fence->status < 0)
+ return POLLERR;
+ else
+ return 0;
+}
+
+static long sync_fence_ioctl_wait(struct sync_fence *fence, unsigned long arg)
+{
+ __s32 value;
+
+ if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
+ return -EFAULT;
+
+ return sync_fence_wait(fence, value);
+}
+
+static long sync_fence_ioctl_merge(struct sync_fence *fence, unsigned long arg)
+{
+ int fd = get_unused_fd();
+ int err;
+ struct sync_fence *fence2, *fence3;
+ struct sync_merge_data data;
+
+ if (fd < 0)
+ return fd;
+
+ if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
+ err = -EFAULT;
+ goto err_put_fd;
+ }
+
+ fence2 = sync_fence_fdget(data.fd2);
+ if (fence2 == NULL) {
+ err = -ENOENT;
+ goto err_put_fd;
+ }
+
+ data.name[sizeof(data.name) - 1] = '\0';
+ fence3 = sync_fence_merge(data.name, fence, fence2);
+ if (fence3 == NULL) {
+ err = -ENOMEM;
+ goto err_put_fence2;
+ }
+
+ data.fence = fd;
+ if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
+ err = -EFAULT;
+ goto err_put_fence3;
+ }
+
+ sync_fence_install(fence3, fd);
+ sync_fence_put(fence2);
+ return 0;
+
+err_put_fence3:
+ sync_fence_put(fence3);
+
+err_put_fence2:
+ sync_fence_put(fence2);
+
+err_put_fd:
+ put_unused_fd(fd);
+ return err;
+}
+
+static int sync_fill_pt_info(struct sync_pt *pt, void *data, int size)
+{
+ struct sync_pt_info *info = data;
+ int ret;
+
+ if (size < sizeof(struct sync_pt_info))
+ return -ENOMEM;
+
+ info->len = sizeof(struct sync_pt_info);
+
+ if (pt->parent->ops->fill_driver_data) {
+ ret = pt->parent->ops->fill_driver_data(pt, info->driver_data,
+ size - sizeof(*info));
+ if (ret < 0)
+ return ret;
+
+ info->len += ret;
+ }
+
+ strlcpy(info->obj_name, pt->parent->name, sizeof(info->obj_name));
+ strlcpy(info->driver_name, pt->parent->ops->driver_name,
+ sizeof(info->driver_name));
+ info->status = pt->status;
+ info->timestamp_ns = ktime_to_ns(pt->timestamp);
+
+ return info->len;
+}
+
+static long sync_fence_ioctl_fence_info(struct sync_fence *fence,
+ unsigned long arg)
+{
+ struct sync_fence_info_data *data;
+ struct list_head *pos;
+ __u32 size;
+ __u32 len = 0;
+ int ret;
+
+ if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
+ return -EFAULT;
+
+ if (size < sizeof(struct sync_fence_info_data))
+ return -EINVAL;
+
+ if (size > 4096)
+ size = 4096;
+
+ data = kzalloc(size, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ strlcpy(data->name, fence->name, sizeof(data->name));
+ data->status = fence->status;
+ len = sizeof(struct sync_fence_info_data);
+
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, pt_list);
+
+ ret = sync_fill_pt_info(pt, (u8 *)data + len, size - len);
+
+ if (ret < 0)
+ goto out;
+
+ len += ret;
+ }
+
+ data->len = len;
+
+ if (copy_to_user((void __user *)arg, data, len))
+ ret = -EFAULT;
+ else
+ ret = 0;
+
+out:
+ kfree(data);
+
+ return ret;
+}
+
+static long sync_fence_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sync_fence *fence = file->private_data;
+ switch (cmd) {
+ case SYNC_IOC_WAIT:
+ return sync_fence_ioctl_wait(fence, arg);
+
+ case SYNC_IOC_MERGE:
+ return sync_fence_ioctl_merge(fence, arg);
+
+ case SYNC_IOC_FENCE_INFO:
+ return sync_fence_ioctl_fence_info(fence, arg);
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+#ifdef CONFIG_DEBUG_FS
+static const char *sync_status_str(int status)
+{
+ if (status > 0)
+ return "signaled";
+ else if (status == 0)
+ return "active";
+ else
+ return "error";
+}
+
+static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
+{
+ int status = pt->status;
+ seq_printf(s, " %s%spt %s",
+ fence ? pt->parent->name : "",
+ fence ? "_" : "",
+ sync_status_str(status));
+ if (pt->status) {
+ struct timeval tv = ktime_to_timeval(pt->timestamp);
+ seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
+ }
+
+ if (pt->parent->ops->timeline_value_str &&
+ pt->parent->ops->pt_value_str) {
+ char value[64];
+ pt->parent->ops->pt_value_str(pt, value, sizeof(value));
+ seq_printf(s, ": %s", value);
+ if (fence) {
+ pt->parent->ops->timeline_value_str(pt->parent, value,
+ sizeof(value));
+ seq_printf(s, " / %s", value);
+ }
+ } else if (pt->parent->ops->print_pt) {
+ seq_printf(s, ": ");
+ pt->parent->ops->print_pt(s, pt);
+ }
+
+ seq_printf(s, "\n");
+}
+
+static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
+{
+ struct list_head *pos;
+ unsigned long flags;
+
+ seq_printf(s, "%s %s", obj->name, obj->ops->driver_name);
+
+ if (obj->ops->timeline_value_str) {
+ char value[64];
+ obj->ops->timeline_value_str(obj, value, sizeof(value));
+ seq_printf(s, ": %s", value);
+ } else if (obj->ops->print_obj) {
+ seq_printf(s, ": ");
+ obj->ops->print_obj(s, obj);
+ }
+
+ seq_printf(s, "\n");
+
+ spin_lock_irqsave(&obj->child_list_lock, flags);
+ list_for_each(pos, &obj->child_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, child_list);
+ sync_print_pt(s, pt, false);
+ }
+ spin_unlock_irqrestore(&obj->child_list_lock, flags);
+}
+
+static void sync_print_fence(struct seq_file *s, struct sync_fence *fence)
+{
+ struct list_head *pos;
+ unsigned long flags;
+
+ seq_printf(s, "[%p] %s: %s\n", fence, fence->name,
+ sync_status_str(fence->status));
+
+ list_for_each(pos, &fence->pt_list_head) {
+ struct sync_pt *pt =
+ container_of(pos, struct sync_pt, pt_list);
+ sync_print_pt(s, pt, true);
+ }
+
+ spin_lock_irqsave(&fence->waiter_list_lock, flags);
+ list_for_each(pos, &fence->waiter_list_head) {
+ struct sync_fence_waiter *waiter =
+ container_of(pos, struct sync_fence_waiter,
+ waiter_list);
+
+ seq_printf(s, "waiter %pF\n", waiter->callback);
+ }
+ spin_unlock_irqrestore(&fence->waiter_list_lock, flags);
+}
+
+static int sync_debugfs_show(struct seq_file *s, void *unused)
+{
+ unsigned long flags;
+ struct list_head *pos;
+
+ seq_printf(s, "objs:\n--------------\n");
+
+ spin_lock_irqsave(&sync_timeline_list_lock, flags);
+ list_for_each(pos, &sync_timeline_list_head) {
+ struct sync_timeline *obj =
+ container_of(pos, struct sync_timeline,
+ sync_timeline_list);
+
+ sync_print_obj(s, obj);
+ seq_printf(s, "\n");
+ }
+ spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
+
+ seq_printf(s, "fences:\n--------------\n");
+
+ spin_lock_irqsave(&sync_fence_list_lock, flags);
+ list_for_each(pos, &sync_fence_list_head) {
+ struct sync_fence *fence =
+ container_of(pos, struct sync_fence, sync_fence_list);
+
+ sync_print_fence(s, fence);
+ seq_printf(s, "\n");
+ }
+ spin_unlock_irqrestore(&sync_fence_list_lock, flags);
+ return 0;
+}
+
+static int sync_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sync_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations sync_debugfs_fops = {
+ .open = sync_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static __init int sync_debugfs_init(void)
+{
+ debugfs_create_file("sync", S_IRUGO, NULL, NULL, &sync_debugfs_fops);
+ return 0;
+}
+late_initcall(sync_debugfs_init);
+
+#define DUMP_CHUNK 256
+static char sync_dump_buf[64 * 1024];
+void sync_dump(void)
+{
+ struct seq_file s = {
+ .buf = sync_dump_buf,
+ .size = sizeof(sync_dump_buf) - 1,
+ };
+ int i;
+
+ sync_debugfs_show(&s, NULL);
+
+ for (i = 0; i < s.count; i += DUMP_CHUNK) {
+ if ((s.count - i) > DUMP_CHUNK) {
+ char c = s.buf[i + DUMP_CHUNK];
+ s.buf[i + DUMP_CHUNK] = 0;
+ pr_cont("%s", s.buf + i);
+ s.buf[i + DUMP_CHUNK] = c;
+ } else {
+ s.buf[s.count] = 0;
+ pr_cont("%s", s.buf + i);
+ }
+ }
+}
+#else
+static void sync_dump(void)
+{
+}
+#endif
diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h
new file mode 100644
index 000000000000..38ea986dc70f
--- /dev/null
+++ b/drivers/staging/android/sync.h
@@ -0,0 +1,426 @@
+/*
+ * include/linux/sync.h
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_SYNC_H
+#define _LINUX_SYNC_H
+
+#include <linux/types.h>
+#ifdef __KERNEL__
+
+#include <linux/kref.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+struct sync_timeline;
+struct sync_pt;
+struct sync_fence;
+
+/**
+ * struct sync_timeline_ops - sync object implementation ops
+ * @driver_name: name of the implentation
+ * @dup: duplicate a sync_pt
+ * @has_signaled: returns:
+ * 1 if pt has signaled
+ * 0 if pt has not signaled
+ * <0 on error
+ * @compare: returns:
+ * 1 if b will signal before a
+ * 0 if a and b will signal at the same time
+ * -1 if a will signabl before b
+ * @free_pt: called before sync_pt is freed
+ * @release_obj: called before sync_timeline is freed
+ * @print_obj: deprecated
+ * @print_pt: deprecated
+ * @fill_driver_data: write implmentation specific driver data to data.
+ * should return an error if there is not enough room
+ * as specified by size. This information is returned
+ * to userspace by SYNC_IOC_FENCE_INFO.
+ * @timeline_value_str: fill str with the value of the sync_timeline's counter
+ * @pt_value_str: fill str with the value of the sync_pt
+ */
+struct sync_timeline_ops {
+ const char *driver_name;
+
+ /* required */
+ struct sync_pt *(*dup)(struct sync_pt *pt);
+
+ /* required */
+ int (*has_signaled)(struct sync_pt *pt);
+
+ /* required */
+ int (*compare)(struct sync_pt *a, struct sync_pt *b);
+
+ /* optional */
+ void (*free_pt)(struct sync_pt *sync_pt);
+
+ /* optional */
+ void (*release_obj)(struct sync_timeline *sync_timeline);
+
+ /* deprecated */
+ void (*print_obj)(struct seq_file *s,
+ struct sync_timeline *sync_timeline);
+
+ /* deprecated */
+ void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt);
+
+ /* optional */
+ int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
+
+ /* optional */
+ void (*timeline_value_str)(struct sync_timeline *timeline, char *str,
+ int size);
+
+ /* optional */
+ void (*pt_value_str)(struct sync_pt *pt, char *str, int size);
+};
+
+/**
+ * struct sync_timeline - sync object
+ * @kref: reference count on fence.
+ * @ops: ops that define the implementaiton of the sync_timeline
+ * @name: name of the sync_timeline. Useful for debugging
+ * @destoryed: set when sync_timeline is destroyed
+ * @child_list_head: list of children sync_pts for this sync_timeline
+ * @child_list_lock: lock protecting @child_list_head, destroyed, and
+ * sync_pt.status
+ * @active_list_head: list of active (unsignaled/errored) sync_pts
+ * @sync_timeline_list: membership in global sync_timeline_list
+ */
+struct sync_timeline {
+ struct kref kref;
+ const struct sync_timeline_ops *ops;
+ char name[32];
+
+ /* protected by child_list_lock */
+ bool destroyed;
+
+ struct list_head child_list_head;
+ spinlock_t child_list_lock;
+
+ struct list_head active_list_head;
+ spinlock_t active_list_lock;
+
+ struct list_head sync_timeline_list;
+};
+
+/**
+ * struct sync_pt - sync point
+ * @parent: sync_timeline to which this sync_pt belongs
+ * @child_list: membership in sync_timeline.child_list_head
+ * @active_list: membership in sync_timeline.active_list_head
+ * @signaled_list: membership in temorary signaled_list on stack
+ * @fence: sync_fence to which the sync_pt belongs
+ * @pt_list: membership in sync_fence.pt_list_head
+ * @status: 1: signaled, 0:active, <0: error
+ * @timestamp: time which sync_pt status transitioned from active to
+ * singaled or error.
+ */
+struct sync_pt {
+ struct sync_timeline *parent;
+ struct list_head child_list;
+
+ struct list_head active_list;
+ struct list_head signaled_list;
+
+ struct sync_fence *fence;
+ struct list_head pt_list;
+
+ /* protected by parent->active_list_lock */
+ int status;
+
+ ktime_t timestamp;
+};
+
+/**
+ * struct sync_fence - sync fence
+ * @file: file representing this fence
+ * @kref: referenace count on fence.
+ * @name: name of sync_fence. Useful for debugging
+ * @pt_list_head: list of sync_pts in ths fence. immutable once fence
+ * is created
+ * @waiter_list_head: list of asynchronous waiters on this fence
+ * @waiter_list_lock: lock protecting @waiter_list_head and @status
+ * @status: 1: signaled, 0:active, <0: error
+ *
+ * @wq: wait queue for fence signaling
+ * @sync_fence_list: membership in global fence list
+ */
+struct sync_fence {
+ struct file *file;
+ struct kref kref;
+ char name[32];
+
+ /* this list is immutable once the fence is created */
+ struct list_head pt_list_head;
+
+ struct list_head waiter_list_head;
+ spinlock_t waiter_list_lock; /* also protects status */
+ int status;
+
+ wait_queue_head_t wq;
+
+ struct list_head sync_fence_list;
+};
+
+struct sync_fence_waiter;
+typedef void (*sync_callback_t)(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * struct sync_fence_waiter - metadata for asynchronous waiter on a fence
+ * @waiter_list: membership in sync_fence.waiter_list_head
+ * @callback: function pointer to call when fence signals
+ * @callback_data: pointer to pass to @callback
+ */
+struct sync_fence_waiter {
+ struct list_head waiter_list;
+
+ sync_callback_t callback;
+};
+
+static inline void sync_fence_waiter_init(struct sync_fence_waiter *waiter,
+ sync_callback_t callback)
+{
+ waiter->callback = callback;
+}
+
+/*
+ * API for sync_timeline implementers
+ */
+
+/**
+ * sync_timeline_create() - creates a sync object
+ * @ops: specifies the implemention ops for the object
+ * @size: size to allocate for this obj
+ * @name: sync_timeline name
+ *
+ * Creates a new sync_timeline which will use the implemetation specified by
+ * @ops. @size bytes will be allocated allowing for implemntation specific
+ * data to be kept after the generic sync_timeline stuct.
+ */
+struct sync_timeline *sync_timeline_create(const struct sync_timeline_ops *ops,
+ int size, const char *name);
+
+/**
+ * sync_timeline_destory() - destorys a sync object
+ * @obj: sync_timeline to destroy
+ *
+ * A sync implemntation should call this when the @obj is going away
+ * (i.e. module unload.) @obj won't actually be freed until all its childern
+ * sync_pts are freed.
+ */
+void sync_timeline_destroy(struct sync_timeline *obj);
+
+/**
+ * sync_timeline_signal() - signal a status change on a sync_timeline
+ * @obj: sync_timeline to signal
+ *
+ * A sync implemntation should call this any time one of it's sync_pts
+ * has signaled or has an error condition.
+ */
+void sync_timeline_signal(struct sync_timeline *obj);
+
+/**
+ * sync_pt_create() - creates a sync pt
+ * @parent: sync_pt's parent sync_timeline
+ * @size: size to allocate for this pt
+ *
+ * Creates a new sync_pt as a chiled of @parent. @size bytes will be
+ * allocated allowing for implemntation specific data to be kept after
+ * the generic sync_timeline struct.
+ */
+struct sync_pt *sync_pt_create(struct sync_timeline *parent, int size);
+
+/**
+ * sync_pt_free() - frees a sync pt
+ * @pt: sync_pt to free
+ *
+ * This should only be called on sync_pts which have been created but
+ * not added to a fence.
+ */
+void sync_pt_free(struct sync_pt *pt);
+
+/**
+ * sync_fence_create() - creates a sync fence
+ * @name: name of fence to create
+ * @pt: sync_pt to add to the fence
+ *
+ * Creates a fence containg @pt. Once this is called, the fence takes
+ * ownership of @pt.
+ */
+struct sync_fence *sync_fence_create(const char *name, struct sync_pt *pt);
+
+/*
+ * API for sync_fence consumers
+ */
+
+/**
+ * sync_fence_merge() - merge two fences
+ * @name: name of new fence
+ * @a: fence a
+ * @b: fence b
+ *
+ * Creates a new fence which contains copies of all the sync_pts in both
+ * @a and @b. @a and @b remain valid, independent fences.
+ */
+struct sync_fence *sync_fence_merge(const char *name,
+ struct sync_fence *a, struct sync_fence *b);
+
+/**
+ * sync_fence_fdget() - get a fence from an fd
+ * @fd: fd referencing a fence
+ *
+ * Ensures @fd references a valid fence, increments the refcount of the backing
+ * file, and returns the fence.
+ */
+struct sync_fence *sync_fence_fdget(int fd);
+
+/**
+ * sync_fence_put() - puts a refernnce of a sync fence
+ * @fence: fence to put
+ *
+ * Puts a reference on @fence. If this is the last reference, the fence and
+ * all it's sync_pts will be freed
+ */
+void sync_fence_put(struct sync_fence *fence);
+
+/**
+ * sync_fence_install() - installs a fence into a file descriptor
+ * @fence: fence to instal
+ * @fd: file descriptor in which to install the fence
+ *
+ * Installs @fence into @fd. @fd's should be acquired through get_unused_fd().
+ */
+void sync_fence_install(struct sync_fence *fence, int fd);
+
+/**
+ * sync_fence_wait_async() - registers and async wait on the fence
+ * @fence: fence to wait on
+ * @waiter: waiter callback struck
+ *
+ * Returns 1 if @fence has already signaled.
+ *
+ * Registers a callback to be called when @fence signals or has an error.
+ * @waiter should be initialized with sync_fence_waiter_init().
+ */
+int sync_fence_wait_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * sync_fence_cancel_async() - cancels an async wait
+ * @fence: fence to wait on
+ * @waiter: waiter callback struck
+ *
+ * returns 0 if waiter was removed from fence's async waiter list.
+ * returns -ENOENT if waiter was not found on fence's async waiter list.
+ *
+ * Cancels a previously registered async wait. Will fail gracefully if
+ * @waiter was never registered or if @fence has already signaled @waiter.
+ */
+int sync_fence_cancel_async(struct sync_fence *fence,
+ struct sync_fence_waiter *waiter);
+
+/**
+ * sync_fence_wait() - wait on fence
+ * @fence: fence to wait on
+ * @tiemout: timeout in ms
+ *
+ * Wait for @fence to be signaled or have an error. Waits indefinitely
+ * if @timeout < 0
+ */
+int sync_fence_wait(struct sync_fence *fence, long timeout);
+
+#endif /* __KERNEL__ */
+
+/**
+ * struct sync_merge_data - data passed to merge ioctl
+ * @fd2: file descriptor of second fence
+ * @name: name of new fence
+ * @fence: returns the fd of the new fence to userspace
+ */
+struct sync_merge_data {
+ __s32 fd2; /* fd of second fence */
+ char name[32]; /* name of new fence */
+ __s32 fence; /* fd on newly created fence */
+};
+
+/**
+ * struct sync_pt_info - detailed sync_pt information
+ * @len: length of sync_pt_info including any driver_data
+ * @obj_name: name of parent sync_timeline
+ * @driver_name: name of driver implmenting the parent
+ * @status: status of the sync_pt 0:active 1:signaled <0:error
+ * @timestamp_ns: timestamp of status change in nanoseconds
+ * @driver_data: any driver dependant data
+ */
+struct sync_pt_info {
+ __u32 len;
+ char obj_name[32];
+ char driver_name[32];
+ __s32 status;
+ __u64 timestamp_ns;
+
+ __u8 driver_data[0];
+};
+
+/**
+ * struct sync_fence_info_data - data returned from fence info ioctl
+ * @len: ioctl caller writes the size of the buffer its passing in.
+ * ioctl returns length of sync_fence_data reutnred to userspace
+ * including pt_info.
+ * @name: name of fence
+ * @status: status of fence. 1: signaled 0:active <0:error
+ * @pt_info: a sync_pt_info struct for every sync_pt in the fence
+ */
+struct sync_fence_info_data {
+ __u32 len;
+ char name[32];
+ __s32 status;
+
+ __u8 pt_info[0];
+};
+
+#define SYNC_IOC_MAGIC '>'
+
+/**
+ * DOC: SYNC_IOC_WAIT - wait for a fence to signal
+ *
+ * pass timeout in milliseconds. Waits indefinitely timeout < 0.
+ */
+#define SYNC_IOC_WAIT _IOW(SYNC_IOC_MAGIC, 0, __s32)
+
+/**
+ * DOC: SYNC_IOC_MERGE - merge two fences
+ *
+ * Takes a struct sync_merge_data. Creates a new fence containing copies of
+ * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
+ * new fence's fd in sync_merge_data.fence
+ */
+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
+
+/**
+ * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
+ *
+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
+ * Caller should write the size of the buffer into len. On return, len is
+ * updated to reflect the total size of the sync_fence_info_data including
+ * pt_info.
+ *
+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
+ * To itterate over the sync_pt_infos, use the sync_pt_info.len field.
+ */
+#define SYNC_IOC_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
+ struct sync_fence_info_data)
+
+#endif /* _LINUX_SYNC_H */
diff --git a/drivers/staging/android/trace/sync.h b/drivers/staging/android/trace/sync.h
new file mode 100644
index 000000000000..95462359ba57
--- /dev/null
+++ b/drivers/staging/android/trace/sync.h
@@ -0,0 +1,82 @@
+#undef TRACE_SYSTEM
+#define TRACE_INCLUDE_PATH ../../drivers/staging/android/trace
+#define TRACE_SYSTEM sync
+
+#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_SYNC_H
+
+#include "../sync.h"
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(sync_timeline,
+ TP_PROTO(struct sync_timeline *timeline),
+
+ TP_ARGS(timeline),
+
+ TP_STRUCT__entry(
+ __string(name, timeline->name)
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, timeline->name);
+ if (timeline->ops->timeline_value_str) {
+ timeline->ops->timeline_value_str(timeline,
+ __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(name), __entry->value)
+);
+
+TRACE_EVENT(sync_wait,
+ TP_PROTO(struct sync_fence *fence, int begin),
+
+ TP_ARGS(fence, begin),
+
+ TP_STRUCT__entry(
+ __string(name, fence->name)
+ __field(s32, status)
+ __field(u32, begin)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, fence->name);
+ __entry->status = fence->status;
+ __entry->begin = begin;
+ ),
+
+ TP_printk("%s name=%s state=%d", __entry->begin ? "begin" : "end",
+ __get_str(name), __entry->status)
+);
+
+TRACE_EVENT(sync_pt,
+ TP_PROTO(struct sync_pt *pt),
+
+ TP_ARGS(pt),
+
+ TP_STRUCT__entry(
+ __string(timeline, pt->parent->name)
+ __array(char, value, 32)
+ ),
+
+ TP_fast_assign(
+ __assign_str(timeline, pt->parent->name);
+ if (pt->parent->ops->pt_value_str) {
+ pt->parent->ops->pt_value_str(pt, __entry->value,
+ sizeof(__entry->value));
+ } else {
+ __entry->value[0] = '\0';
+ }
+ ),
+
+ TP_printk("name=%s value=%s", __get_str(timeline), __entry->value)
+);
+
+#endif /* if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c
index 491e2bfbc464..35641e529396 100644
--- a/drivers/staging/bcm/Bcmchar.c
+++ b/drivers/staging/bcm/Bcmchar.c
@@ -1148,8 +1148,8 @@ cntrlEnd:
if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
((ULONG)pBulkBuffer->Register & 0x3)) {
- kfree(pvBuffer);
BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n", (int)pBulkBuffer->Register);
+ kfree(pvBuffer);
Status = -EINVAL;
break;
}
diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c
index 64ea6edb9dc2..348ad75b340d 100644
--- a/drivers/staging/bcm/InterfaceDld.c
+++ b/drivers/staging/bcm/InterfaceDld.c
@@ -205,30 +205,6 @@ static int bcm_download_config_file(struct bcm_mini_adapter *Adapter, struct bcm
return retval;
}
-static int bcm_compare_buff_contents(unsigned char *readbackbuff, unsigned char *buff, unsigned int len)
-{
- int retval = STATUS_SUCCESS;
- struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if ((len-sizeof(unsigned int)) < 4) {
- if (memcmp(readbackbuff , buff, len))
- retval = -EINVAL;
- } else {
- len -= 4;
-
- while (len) {
- if (*(unsigned int *)&readbackbuff[len] != *(unsigned int *)&buff[len]) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Firmware Download is not proper");
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Val from Binary %x, Val From Read Back %x ", *(unsigned int *)&buff[len], *(unsigned int*)&readbackbuff[len]);
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "len =%x!!!", len);
- retval = -EINVAL;
- break;
- }
- len -= 4;
- }
- }
- return retval;
-}
-
int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo)
{
int retval = STATUS_SUCCESS;
@@ -321,9 +297,11 @@ static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter, PUCHAR mappedbuffer,
break;
}
- retval = bcm_compare_buff_contents(readbackbuff, mappedbuffer, len);
- if (STATUS_SUCCESS != retval)
- break;
+ if (memcmp(readbackbuff, mappedbuffer, len) != 0) {
+ pr_err("%s() failed. The firmware doesn't match what was written",
+ __func__);
+ retval = -EIO;
+ }
u32StartingAddress += len;
u32FirmwareLength -= len;
diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c
index 7028bc95b4f9..af5d22faa7f0 100644
--- a/drivers/staging/bcm/PHSModule.c
+++ b/drivers/staging/bcm/PHSModule.c
@@ -1,263 +1,238 @@
#include "headers.h"
-static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId, struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
+static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
-static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16 uiClsId, struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
+static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
-static UINT CreateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, enum bcm_phs_classifier_context eClsContext,B_UINT8 u8AssociatedPHSI);
+static UINT CreateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, enum bcm_phs_classifier_context eClsContext, B_UINT8 u8AssociatedPHSI);
-static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_entry *pstClassifierEntry, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
+static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_entry *pstClassifierEntry, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI);
static BOOLEAN ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule);
-static BOOLEAN DerefPhsRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule);
+static BOOLEAN DerefPhsRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule);
-static UINT GetClassifierEntry(struct bcm_phs_classifier_table *pstClassifierTable,B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_classifier_entry **ppstClassifierEntry);
+static UINT GetClassifierEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_classifier_entry **ppstClassifierEntry);
-static UINT GetPhsRuleEntry(struct bcm_phs_classifier_table *pstClassifierTable,B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_rule **ppstPhsRule);
+static UINT GetPhsRuleEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_rule **ppstPhsRule);
static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable);
static int phs_compress(struct bcm_phs_rule *phs_members, unsigned char *in_buf,
- unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
+ unsigned char *out_buf, unsigned int *header_size, UINT *new_header_size);
+static int verify_suppress_phsf(unsigned char *in_buffer, unsigned char *out_buffer,
+ unsigned char *phsf, unsigned char *phsm, unsigned int phss, unsigned int phsv, UINT *new_header_size);
-static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
- unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
-
-static int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
- struct bcm_phs_rule *phs_rules, UINT *header_size);
-
-
-static ULONG PhsCompress(void* pvContext,
- B_UINT16 uiVcid,
- B_UINT16 uiClsId,
- void *pvInputBuffer,
- void *pvOutputBuffer,
- UINT *pOldHeaderSize,
- UINT *pNewHeaderSize );
-
-static ULONG PhsDeCompress(void* pvContext,
- B_UINT16 uiVcid,
- void *pvInputBuffer,
- void *pvOutputBuffer,
- UINT *pInHeaderSize,
- UINT *pOutHeaderSize);
+static int phs_decompress(unsigned char *in_buf, unsigned char *out_buf,
+ struct bcm_phs_rule *phs_rules, UINT *header_size);
+static ULONG PhsCompress(void *pvContext,
+ B_UINT16 uiVcid,
+ B_UINT16 uiClsId,
+ void *pvInputBuffer,
+ void *pvOutputBuffer,
+ UINT *pOldHeaderSize,
+ UINT *pNewHeaderSize);
+static ULONG PhsDeCompress(void *pvContext,
+ B_UINT16 uiVcid,
+ void *pvInputBuffer,
+ void *pvOutputBuffer,
+ UINT *pInHeaderSize,
+ UINT *pOutHeaderSize);
#define IN
#define OUT
/*
-Function: PHSTransmit
-
-Description: This routine handle PHS(Payload Header Suppression for Tx path.
- It extracts a fragment of the NDIS_PACKET containing the header
- to be suppressed. It then suppresses the header by invoking PHS exported compress routine.
- The header data after suppression is copied back to the NDIS_PACKET.
-
-
-Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context
- IN Packet - NDIS packet containing data to be transmitted
- IN USHORT Vcid - vcid pertaining to connection on which the packet is being sent.Used to
- identify PHS rule to be applied.
- B_UINT16 uiClassifierRuleID - Classifier Rule ID
- BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF.
-
-Return: STATUS_SUCCESS - If the send was successful.
- Other - If an error occurred.
-*/
+ * Function: PHSTransmit
+ * Description: This routine handle PHS(Payload Header Suppression for Tx path.
+ * It extracts a fragment of the NDIS_PACKET containing the header
+ * to be suppressed. It then suppresses the header by invoking PHS exported compress routine.
+ * The header data after suppression is copied back to the NDIS_PACKET.
+ *
+ * Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context
+ * IN Packet - NDIS packet containing data to be transmitted
+ * IN USHORT Vcid - vcid pertaining to connection on which the packet is being sent.Used to
+ * identify PHS rule to be applied.
+ * B_UINT16 uiClassifierRuleID - Classifier Rule ID
+ * BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF.
+ *
+ * Return: STATUS_SUCCESS - If the send was successful.
+ * Other - If an error occurred.
+ */
int PHSTransmit(struct bcm_mini_adapter *Adapter,
- struct sk_buff **pPacket,
- USHORT Vcid,
- B_UINT16 uiClassifierRuleID,
- BOOLEAN bHeaderSuppressionEnabled,
- UINT *PacketLen,
- UCHAR bEthCSSupport)
+ struct sk_buff **pPacket,
+ USHORT Vcid,
+ B_UINT16 uiClassifierRuleID,
+ BOOLEAN bHeaderSuppressionEnabled,
+ UINT *PacketLen,
+ UCHAR bEthCSSupport)
{
-
- //PHS Sepcific
- UINT unPHSPktHdrBytesCopied = 0;
- UINT unPhsOldHdrSize = 0;
- UINT unPHSNewPktHeaderLen = 0;
+ /* PHS Sepcific */
+ UINT unPHSPktHdrBytesCopied = 0;
+ UINT unPhsOldHdrSize = 0;
+ UINT unPHSNewPktHeaderLen = 0;
/* Pointer to PHS IN Hdr Buffer */
- PUCHAR pucPHSPktHdrInBuf =
- Adapter->stPhsTxContextInfo.ucaHdrSuppressionInBuf;
+ PUCHAR pucPHSPktHdrInBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionInBuf;
/* Pointer to PHS OUT Hdr Buffer */
- PUCHAR pucPHSPktHdrOutBuf =
- Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf;
- UINT usPacketType;
- UINT BytesToRemove=0;
- BOOLEAN bPHSI = 0;
+ PUCHAR pucPHSPktHdrOutBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf;
+ UINT usPacketType;
+ UINT BytesToRemove = 0;
+ BOOLEAN bPHSI = 0;
LONG ulPhsStatus = 0;
- UINT numBytesCompressed = 0;
+ UINT numBytesCompressed = 0;
struct sk_buff *newPacket = NULL;
struct sk_buff *Packet = *pPacket;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "In PHSTransmit");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "In PHSTransmit");
- if(!bEthCSSupport)
- BytesToRemove=ETH_HLEN;
+ if (!bEthCSSupport)
+ BytesToRemove = ETH_HLEN;
/*
- Accumulate the header upto the size we support suppression
- from NDIS packet
- */
-
- usPacketType=((struct ethhdr *)(Packet->data))->h_proto;
+ * Accumulate the header upto the size we support suppression
+ * from NDIS packet
+ */
+ usPacketType = ((struct ethhdr *)(Packet->data))->h_proto;
pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
- //considering data after ethernet header
- if((*PacketLen - BytesToRemove) < MAX_PHS_LENGTHS)
- {
-
+ /* considering data after ethernet header */
+ if ((*PacketLen - BytesToRemove) < MAX_PHS_LENGTHS)
unPHSPktHdrBytesCopied = (*PacketLen - BytesToRemove);
- }
else
- {
unPHSPktHdrBytesCopied = MAX_PHS_LENGTHS;
- }
- if( (unPHSPktHdrBytesCopied > 0 ) &&
- (unPHSPktHdrBytesCopied <= MAX_PHS_LENGTHS))
- {
-
-
- // Step 2 Suppress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
- // Suppress only if IP Header and PHS Enabled For the Service Flow
- if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
- (usPacketType == ETHERNET_FRAMETYPE_IPV6)) &&
- (bHeaderSuppressionEnabled))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nTrying to PHS Compress Using Classifier rule 0x%X",uiClassifierRuleID);
-
-
- unPHSNewPktHeaderLen = unPHSPktHdrBytesCopied;
- ulPhsStatus = PhsCompress(&Adapter->stBCMPhsContext,
- Vcid,
- uiClassifierRuleID,
- pucPHSPktHdrInBuf,
- pucPHSPktHdrOutBuf,
- &unPhsOldHdrSize,
- &unPHSNewPktHeaderLen);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nPHS Old header Size : %d New Header Size %d\n",unPhsOldHdrSize,unPHSNewPktHeaderLen);
-
- if(unPHSNewPktHeaderLen == unPhsOldHdrSize)
- {
- if( ulPhsStatus == STATUS_PHS_COMPRESSED)
- bPHSI = *pucPHSPktHdrOutBuf;
- ulPhsStatus = STATUS_PHS_NOCOMPRESSION;
- }
-
- if( ulPhsStatus == STATUS_PHS_COMPRESSED)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHS Sending packet Compressed");
+ if ((unPHSPktHdrBytesCopied > 0) &&
+ (unPHSPktHdrBytesCopied <= MAX_PHS_LENGTHS)) {
- if(skb_cloned(Packet))
- {
- newPacket = skb_copy(Packet, GFP_ATOMIC);
+ /*
+ * Step 2 Suppress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
+ * Suppress only if IP Header and PHS Enabled For the Service Flow
+ */
+ if (((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
+ (usPacketType == ETHERNET_FRAMETYPE_IPV6)) &&
+ (bHeaderSuppressionEnabled)) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nTrying to PHS Compress Using Classifier rule 0x%X", uiClassifierRuleID);
+ unPHSNewPktHeaderLen = unPHSPktHdrBytesCopied;
+ ulPhsStatus = PhsCompress(&Adapter->stBCMPhsContext,
+ Vcid,
+ uiClassifierRuleID,
+ pucPHSPktHdrInBuf,
+ pucPHSPktHdrOutBuf,
+ &unPhsOldHdrSize,
+ &unPHSNewPktHeaderLen);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nPHS Old header Size : %d New Header Size %d\n", unPhsOldHdrSize, unPHSNewPktHeaderLen);
+
+ if (unPHSNewPktHeaderLen == unPhsOldHdrSize) {
+
+ if (ulPhsStatus == STATUS_PHS_COMPRESSED)
+ bPHSI = *pucPHSPktHdrOutBuf;
+
+ ulPhsStatus = STATUS_PHS_NOCOMPRESSION;
+ }
- if(newPacket == NULL)
- return STATUS_FAILURE;
+ if (ulPhsStatus == STATUS_PHS_COMPRESSED) {
- dev_kfree_skb(Packet);
- *pPacket = Packet = newPacket;
- pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
- }
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "PHS Sending packet Compressed");
- numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN);
+ if (skb_cloned(Packet)) {
+ newPacket = skb_copy(Packet, GFP_ATOMIC);
- memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
- memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
- skb_pull(Packet, numBytesCompressed);
+ if (newPacket == NULL)
+ return STATUS_FAILURE;
- return STATUS_SUCCESS;
+ dev_kfree_skb(Packet);
+ *pPacket = Packet = newPacket;
+ pucPHSPktHdrInBuf = Packet->data + BytesToRemove;
}
- else
- {
- //if one byte headroom is not available, increase it through skb_cow
- if(!(skb_headroom(Packet) > 0))
- {
- if(skb_cow(Packet, 1))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "SKB Cow Failed\n");
- return STATUS_FAILURE;
- }
- }
- skb_push(Packet, 1);
+ numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen + PHSI_LEN);
- // CAUTION: The MAC Header is getting corrupted here for IP CS - can be saved by copying 14 Bytes. not needed .... hence corrupting it.
- *(Packet->data + BytesToRemove) = bPHSI;
- return STATUS_SUCCESS;
- }
- }
- else
- {
- if(!bHeaderSuppressionEnabled)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nHeader Suppression Disabled For SF: No PHS\n");
+ memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
+ memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
+ skb_pull(Packet, numBytesCompressed);
+
+ return STATUS_SUCCESS;
+ } else {
+ /* if one byte headroom is not available, increase it through skb_cow */
+ if (!(skb_headroom(Packet) > 0)) {
+
+ if (skb_cow(Packet, 1)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SKB Cow Failed\n");
+ return STATUS_FAILURE;
+ }
+ }
+ skb_push(Packet, 1);
+
+ /*
+ * CAUTION: The MAC Header is getting corrupted
+ * here for IP CS - can be saved by copying 14
+ * Bytes. not needed .... hence corrupting it.
+ */
+ *(Packet->data + BytesToRemove) = bPHSI;
+ return STATUS_SUCCESS;
}
+ } else {
+
+ if (!bHeaderSuppressionEnabled)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nHeader Suppression Disabled For SF: No PHS\n");
return STATUS_SUCCESS;
}
}
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHSTransmit : Dumping data packet After PHS");
+ /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHSTransmit : Dumping data packet After PHS"); */
return STATUS_SUCCESS;
}
int PHSReceive(struct bcm_mini_adapter *Adapter,
- USHORT usVcid,
- struct sk_buff *packet,
- UINT *punPacketLen,
- UCHAR *pucEthernetHdr,
- UINT bHeaderSuppressionEnabled)
+ USHORT usVcid,
+ struct sk_buff *packet,
+ UINT *punPacketLen,
+ UCHAR *pucEthernetHdr,
+ UINT bHeaderSuppressionEnabled)
{
- u32 nStandardPktHdrLen = 0;
- u32 nTotalsuppressedPktHdrBytes = 0;
- int ulPhsStatus = 0;
- PUCHAR pucInBuff = NULL ;
+ u32 nStandardPktHdrLen = 0;
+ u32 nTotalsuppressedPktHdrBytes = 0;
+ int ulPhsStatus = 0;
+ PUCHAR pucInBuff = NULL;
UINT TotalBytesAdded = 0;
- if(!bHeaderSuppressionEnabled)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nPhs Disabled for incoming packet");
+
+ if (!bHeaderSuppressionEnabled) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nPhs Disabled for incoming packet");
return ulPhsStatus;
}
pucInBuff = packet->data;
- //Restore PHS suppressed header
+ /* Restore PHS suppressed header */
nStandardPktHdrLen = packet->len;
ulPhsStatus = PhsDeCompress(&Adapter->stBCMPhsContext,
- usVcid,
- pucInBuff,
- Adapter->ucaPHSPktRestoreBuf,
- &nTotalsuppressedPktHdrBytes,
- &nStandardPktHdrLen);
+ usVcid,
+ pucInBuff,
+ Adapter->ucaPHSPktRestoreBuf,
+ &nTotalsuppressedPktHdrBytes,
+ &nStandardPktHdrLen);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
- nTotalsuppressedPktHdrBytes,nStandardPktHdrLen);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x",
+ nTotalsuppressedPktHdrBytes, nStandardPktHdrLen);
- if(ulPhsStatus != STATUS_PHS_COMPRESSED)
- {
+ if (ulPhsStatus != STATUS_PHS_COMPRESSED) {
skb_pull(packet, 1);
return STATUS_SUCCESS;
- }
- else
- {
+ } else {
TotalBytesAdded = nStandardPktHdrLen - nTotalsuppressedPktHdrBytes - PHSI_LEN;
- if(TotalBytesAdded)
- {
- if(skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded))
+
+ if (TotalBytesAdded) {
+ if (skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded))
skb_push(packet, TotalBytesAdded);
- else
- {
- if(skb_cow(packet, skb_headroom(packet) + TotalBytesAdded))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "cow failed in receive\n");
+ else {
+ if (skb_cow(packet, skb_headroom(packet) + TotalBytesAdded)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "cow failed in receive\n");
return STATUS_FAILURE;
}
@@ -271,90 +246,80 @@ int PHSReceive(struct bcm_mini_adapter *Adapter,
return STATUS_SUCCESS;
}
-void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
+void DumpFullPacket(UCHAR *pBuf, UINT nPktLen)
{
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,"Dumping Data Packet");
- BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,pBuf,nPktLen);
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dumping Data Packet");
+ BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, pBuf, nPktLen);
}
-//-----------------------------------------------------------------------------
-// Procedure: phs_init
-//
-// Description: This routine is responsible for allocating memory for classifier and
-// PHS rules.
-//
-// Arguments:
-// pPhsdeviceExtension - ptr to Device extension containing PHS Classifier rules and PHS Rules , RX, TX buffer etc
-//
-// Returns:
-// TRUE(1) -If allocation of memory was success full.
-// FALSE -If allocation of memory fails.
-//-----------------------------------------------------------------------------
+/*
+ * Procedure: phs_init
+ *
+ * Description: This routine is responsible for allocating memory for classifier and
+ * PHS rules.
+ *
+ * Arguments:
+ * pPhsdeviceExtension - ptr to Device extension containing PHS Classifier rules and PHS Rules , RX, TX buffer etc
+ *
+ * Returns:
+ * TRUE(1) -If allocation of memory was successful.
+ * FALSE -If allocation of memory fails.
+ */
int phs_init(struct bcm_phs_extension *pPhsdeviceExtension, struct bcm_mini_adapter *Adapter)
{
int i;
struct bcm_phs_table *pstServiceFlowTable;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nPHS:phs_init function ");
- if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nPHS:phs_init function");
+
+ if (pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
return -EINVAL;
- pPhsdeviceExtension->pstServiceFlowPhsRulesTable =
- kzalloc(sizeof(struct bcm_phs_table), GFP_KERNEL);
+ pPhsdeviceExtension->pstServiceFlowPhsRulesTable = kzalloc(sizeof(struct bcm_phs_table), GFP_KERNEL);
- if(!pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
+ if (!pPhsdeviceExtension->pstServiceFlowPhsRulesTable) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
return -ENOMEM;
}
pstServiceFlowTable = pPhsdeviceExtension->pstServiceFlowPhsRulesTable;
- for(i=0;i<MAX_SERVICEFLOWS;i++)
- {
+ for (i = 0; i < MAX_SERVICEFLOWS; i++) {
struct bcm_phs_entry sServiceFlow = pstServiceFlowTable->stSFList[i];
sServiceFlow.pstClassifierTable = kzalloc(sizeof(struct bcm_phs_classifier_table), GFP_KERNEL);
- if(!sServiceFlow.pstClassifierTable)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
- free_phs_serviceflow_rules(pPhsdeviceExtension->
- pstServiceFlowPhsRulesTable);
+ if (!sServiceFlow.pstClassifierTable) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
+ free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
}
pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
-
- if(pPhsdeviceExtension->CompressedTxBuffer == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
+ if (pPhsdeviceExtension->CompressedTxBuffer == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
- pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
- if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
+ pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
+ if (pPhsdeviceExtension->UnCompressedRxBuffer == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
kfree(pPhsdeviceExtension->CompressedTxBuffer);
free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
return -ENOMEM;
}
-
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful");
return STATUS_SUCCESS;
}
-
int PhsCleanup(IN struct bcm_phs_extension *pPHSDeviceExt)
{
- if(pPHSDeviceExt->pstServiceFlowPhsRulesTable)
- {
+ if (pPHSDeviceExt->pstServiceFlowPhsRulesTable) {
free_phs_serviceflow_rules(pPHSDeviceExt->pstServiceFlowPhsRulesTable);
pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL;
}
@@ -368,200 +333,173 @@ int PhsCleanup(IN struct bcm_phs_extension *pPHSDeviceExt)
return 0;
}
-
-
-//PHS functions
-/*++
-PhsUpdateClassifierRule
-
-Routine Description:
- Exported function to add or modify a PHS Rule.
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context
- IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
- IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
- IN struct bcm_phs_rule *psPhsRule - The PHS Rule strcuture to be added to the PHS Rule table.
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-ULONG PhsUpdateClassifierRule(IN void* pvContext,
- IN B_UINT16 uiVcid ,
- IN B_UINT16 uiClsId ,
- IN struct bcm_phs_rule *psPhsRule,
- IN B_UINT8 u8AssociatedPHSI)
+/*
+ * PHS functions
+ * PhsUpdateClassifierRule
+ *
+ * Routine Description:
+ * Exported function to add or modify a PHS Rule.
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context
+ * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
+ * IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
+ * IN struct bcm_phs_rule *psPhsRule - The PHS Rule strcuture to be added to the PHS Rule table.
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsUpdateClassifierRule(IN void *pvContext,
+ IN B_UINT16 uiVcid ,
+ IN B_UINT16 uiClsId ,
+ IN struct bcm_phs_rule *psPhsRule,
+ IN B_UINT8 u8AssociatedPHSI)
{
- ULONG lStatus =0;
- UINT nSFIndex =0 ;
+ ULONG lStatus = 0;
+ UINT nSFIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS With Corr2 Changes\n");
-
- struct bcm_phs_extension *pDeviceExtension= (struct bcm_phs_extension *)pvContext;
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"PHS With Corr2 Changes \n");
-
- if(pDeviceExtension == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"Invalid Device Extension\n");
+ if (pDeviceExtension == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Invalid Device Extension\n");
return ERR_PHS_INVALID_DEVICE_EXETENSION;
}
-
- if(u8AssociatedPHSI == 0)
- {
+ if (u8AssociatedPHSI == 0)
return ERR_PHS_INVALID_PHS_RULE;
- }
/* Retrieve the SFID Entry Index for requested Service Flow */
-
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
- uiVcid,&pstServiceFlowEntry);
+ uiVcid, &pstServiceFlowEntry);
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
/* This is a new SF. Create a mapping entry for this */
lStatus = CreateSFToClassifierRuleMapping(uiVcid, uiClsId,
- pDeviceExtension->pstServiceFlowPhsRulesTable, psPhsRule, u8AssociatedPHSI);
+ pDeviceExtension->pstServiceFlowPhsRulesTable, psPhsRule, u8AssociatedPHSI);
return lStatus;
}
/* SF already Exists Add PHS Rule to existing SF */
- lStatus = CreateClassiferToPHSRuleMapping(uiVcid, uiClsId,
- pstServiceFlowEntry, psPhsRule, u8AssociatedPHSI);
+ lStatus = CreateClassiferToPHSRuleMapping(uiVcid, uiClsId,
+ pstServiceFlowEntry, psPhsRule, u8AssociatedPHSI);
- return lStatus;
+ return lStatus;
}
-/*++
-PhsDeletePHSRule
-
-Routine Description:
- Deletes the specified phs Rule within Vcid
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context
- IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
- IN B_UINT8 u8PHSI - the PHS Index identifying PHS rule to be deleted.
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-
-ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI)
+/*
+ * PhsDeletePHSRule
+ *
+ * Routine Description:
+ * Deletes the specified phs Rule within Vcid
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context
+ * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
+ * IN B_UINT8 u8PHSI - the PHS Index identifying PHS rule to be deleted.
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI)
{
- ULONG lStatus =0;
- UINT nSFIndex =0, nClsidIndex =0 ;
+ ULONG lStatus = 0;
+ UINT nSFIndex = 0, nClsidIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "======>\n");
- struct bcm_phs_extension *pDeviceExtension= (struct bcm_phs_extension *)pvContext;
+ if (pDeviceExtension) {
+ /* Retrieve the SFID Entry Index for requested Service Flow */
+ nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "======>\n");
-
- if(pDeviceExtension)
- {
-
- //Retrieve the SFID Entry Index for requested Service Flow
- nSFIndex = GetServiceFlowEntry(pDeviceExtension
- ->pstServiceFlowPhsRulesTable,uiVcid,&pstServiceFlowEntry);
-
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
- pstClassifierRulesTable=pstServiceFlowEntry->pstClassifierTable;
- if(pstClassifierRulesTable)
- {
- for(nClsidIndex=0;nClsidIndex<MAX_PHSRULE_PER_SF;nClsidIndex++)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable;
+ if (pstClassifierRulesTable) {
+ for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) {
+ if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) {
+ if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) {
+
+ if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
- if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+
+ if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
+
memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0,
sizeof(struct bcm_phs_classifier_entry));
}
}
}
}
-
}
return lStatus;
}
-/*++
-PhsDeleteClassifierRule
-
-Routine Description:
- Exported function to Delete a PHS Rule for the SFID,CLSID Pair.
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context
- IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
- IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16 uiClsId)
+/*
+ * PhsDeleteClassifierRule
+ *
+ * Routine Description:
+ * Exported function to Delete a PHS Rule for the SFID,CLSID Pair.
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context
+ * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies
+ * IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies.
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT16 uiClsId)
{
- ULONG lStatus =0;
- UINT nSFIndex =0, nClsidIndex =0 ;
+ ULONG lStatus = 0;
+ UINT nSFIndex = 0, nClsidIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- struct bcm_phs_extension *pDeviceExtension= (struct bcm_phs_extension *)pvContext;
-
- if(pDeviceExtension)
- {
- //Retrieve the SFID Entry Index for requested Service Flow
- nSFIndex = GetServiceFlowEntry(pDeviceExtension
- ->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"SFID Match Failed\n");
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
+
+ if (pDeviceExtension) {
+ /* Retrieve the SFID Entry Index for requested Service Flow */
+ nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry);
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
- uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
- if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
- {
- if(pstClassifierEntry->pstPhsRule)
- {
- if(pstClassifierEntry->pstPhsRule->u8RefCnt)
- pstClassifierEntry->pstPhsRule->u8RefCnt--;
- if(0==pstClassifierEntry->pstPhsRule->u8RefCnt)
- kfree(pstClassifierEntry->pstPhsRule);
+ uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
+ if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) {
+ if (pstClassifierEntry->pstPhsRule) {
+ if (pstClassifierEntry->pstPhsRule->u8RefCnt)
+ pstClassifierEntry->pstPhsRule->u8RefCnt--;
+
+ if (0 == pstClassifierEntry->pstPhsRule->u8RefCnt)
+ kfree(pstClassifierEntry->pstPhsRule);
}
memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry));
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
- uiClsId,eOldClassifierRuleContext,&pstClassifierEntry);
+ uiClsId, eOldClassifierRuleContext, &pstClassifierEntry);
- if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
- {
+ if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) {
kfree(pstClassifierEntry->pstPhsRule);
memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry));
}
@@ -569,261 +507,223 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
return lStatus;
}
-/*++
-PhsDeleteSFRules
-
-Routine Description:
- Exported function to Delete a all PHS Rules for the SFID.
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context
- IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rules need to be deleted
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
+/*
+ * PhsDeleteSFRules
+ *
+ * Routine Description:
+ * Exported function to Delete a all PHS Rules for the SFID.
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context
+ * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rules need to be deleted
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid)
{
-
- ULONG lStatus =0;
- UINT nSFIndex =0, nClsidIndex =0 ;
+ ULONG lStatus = 0;
+ UINT nSFIndex = 0, nClsidIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- struct bcm_phs_extension *pDeviceExtension= (struct bcm_phs_extension *)pvContext;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"====> \n");
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "====>\n");
- if(pDeviceExtension)
- {
- //Retrieve the SFID Entry Index for requested Service Flow
+ if (pDeviceExtension) {
+ /* Retrieve the SFID Entry Index for requested Service Flow */
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
- uiVcid,&pstServiceFlowEntry);
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
+ uiVcid, &pstServiceFlowEntry);
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n");
return ERR_SF_MATCH_FAIL;
}
- pstClassifierRulesTable=pstServiceFlowEntry->pstClassifierTable;
- if(pstClassifierRulesTable)
- {
- for(nClsidIndex=0;nClsidIndex<MAX_PHSRULE_PER_SF;nClsidIndex++)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt)
- pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt--;
- if(0==pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable;
+ if (pstClassifierRulesTable) {
+ for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) {
+ if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) {
+
+ if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
+
+ if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
- pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
- .pstPhsRule = NULL;
+
+ pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule = NULL;
}
memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry));
- if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule)
- {
- if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt)
- pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt--;
- if(0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
- .pstPhsRule->u8RefCnt)
- kfree(pstClassifierRulesTable
- ->stOldPhsRulesList[nClsidIndex].pstPhsRule);
- pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
- .pstPhsRule = NULL;
+ if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule) {
+
+ if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
+
+ if (0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+ kfree(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule);
+
+ pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule = NULL;
}
memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry));
}
}
pstServiceFlowEntry->bUsed = FALSE;
pstServiceFlowEntry->uiVcid = 0;
-
}
return lStatus;
}
-
-/*++
-PhsCompress
-
-Routine Description:
- Exported function to compress the data using PHS.
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context.
- IN B_UINT16 uiVcid - The Service Flow ID to which current packet header compression applies.
- IN UINT uiClsId - The Classifier ID to which current packet header compression applies.
- IN void *pvInputBuffer - The Input buffer containg packet header data
- IN void *pvOutputBuffer - The output buffer returned by this function after PHS
- IN UINT *pOldHeaderSize - The actual size of the header before PHS
- IN UINT *pNewHeaderSize - The new size of the header after applying PHS
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-ULONG PhsCompress(IN void* pvContext,
- IN B_UINT16 uiVcid,
- IN B_UINT16 uiClsId,
- IN void *pvInputBuffer,
- OUT void *pvOutputBuffer,
- OUT UINT *pOldHeaderSize,
- OUT UINT *pNewHeaderSize )
+/*
+ * PhsCompress
+ *
+ * Routine Description:
+ * Exported function to compress the data using PHS.
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context.
+ * IN B_UINT16 uiVcid - The Service Flow ID to which current packet header compression applies.
+ * IN UINT uiClsId - The Classifier ID to which current packet header compression applies.
+ * IN void *pvInputBuffer - The Input buffer containg packet header data
+ * IN void *pvOutputBuffer - The output buffer returned by this function after PHS
+ * IN UINT *pOldHeaderSize - The actual size of the header before PHS
+ * IN UINT *pNewHeaderSize - The new size of the header after applying PHS
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsCompress(IN void *pvContext,
+ IN B_UINT16 uiVcid,
+ IN B_UINT16 uiClsId,
+ IN void *pvInputBuffer,
+ OUT void *pvOutputBuffer,
+ OUT UINT *pOldHeaderSize,
+ OUT UINT *pNewHeaderSize)
{
- UINT nSFIndex =0, nClsidIndex =0 ;
+ UINT nSFIndex = 0, nClsidIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
struct bcm_phs_rule *pstPhsRule = NULL;
- ULONG lStatus =0;
+ ULONG lStatus = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
-
-
- struct bcm_phs_extension *pDeviceExtension= (struct bcm_phs_extension *)pvContext;
-
-
- if(pDeviceExtension == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Invalid Device Extension\n");
- lStatus = STATUS_PHS_NOCOMPRESSION ;
+ if (pDeviceExtension == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Invalid Device Extension\n");
+ lStatus = STATUS_PHS_NOCOMPRESSION;
return lStatus;
-
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Suppressing header \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Suppressing header\n");
-
- //Retrieve the SFID Entry Index for requested Service Flow
+ /* Retrieve the SFID Entry Index for requested Service Flow */
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
- uiVcid,&pstServiceFlowEntry);
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"SFID Match Failed\n");
- lStatus = STATUS_PHS_NOCOMPRESSION ;
+ uiVcid, &pstServiceFlowEntry);
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "SFID Match Failed\n");
+ lStatus = STATUS_PHS_NOCOMPRESSION;
return lStatus;
}
nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
- uiClsId,eActiveClassifierRuleContext,&pstClassifierEntry);
+ uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry);
- if(nClsidIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"No PHS Rule Defined For Classifier\n");
- lStatus = STATUS_PHS_NOCOMPRESSION ;
+ if (nClsidIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "No PHS Rule Defined For Classifier\n");
+ lStatus = STATUS_PHS_NOCOMPRESSION;
return lStatus;
}
-
- //get rule from SF id,Cls ID pair and proceed
- pstPhsRule = pstClassifierEntry->pstPhsRule;
-
- if(!ValidatePHSRuleComplete(pstPhsRule))
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"PHS Rule Defined For Classifier But Not Complete\n");
- lStatus = STATUS_PHS_NOCOMPRESSION ;
+ /* get rule from SF id,Cls ID pair and proceed */
+ pstPhsRule = pstClassifierEntry->pstPhsRule;
+ if (!ValidatePHSRuleComplete(pstPhsRule)) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS Rule Defined For Classifier But Not Complete\n");
+ lStatus = STATUS_PHS_NOCOMPRESSION;
return lStatus;
}
- //Compress Packet
- lStatus = phs_compress(pstPhsRule,(PUCHAR)pvInputBuffer,
- (PUCHAR)pvOutputBuffer, pOldHeaderSize,pNewHeaderSize);
+ /* Compress Packet */
+ lStatus = phs_compress(pstPhsRule, (PUCHAR)pvInputBuffer,
+ (PUCHAR)pvOutputBuffer, pOldHeaderSize, pNewHeaderSize);
- if(lStatus == STATUS_PHS_COMPRESSED)
- {
+ if (lStatus == STATUS_PHS_COMPRESSED) {
pstPhsRule->PHSModifiedBytes += *pOldHeaderSize - *pNewHeaderSize - 1;
pstPhsRule->PHSModifiedNumPackets++;
- }
- else
+ } else
pstPhsRule->PHSErrorNumPackets++;
return lStatus;
}
-/*++
-PhsDeCompress
-
-Routine Description:
- Exported function to restore the packet header in Rx path.
-
-Arguments:
- IN void* pvContext - PHS Driver Specific Context.
- IN B_UINT16 uiVcid - The Service Flow ID to which current packet header restoration applies.
- IN void *pvInputBuffer - The Input buffer containg suppressed packet header data
- OUT void *pvOutputBuffer - The output buffer returned by this function after restoration
- OUT UINT *pHeaderSize - The packet header size after restoration is returned in this parameter.
-
-Return Value:
-
- 0 if successful,
- >0 Error.
-
---*/
-ULONG PhsDeCompress(IN void* pvContext,
- IN B_UINT16 uiVcid,
- IN void *pvInputBuffer,
- OUT void *pvOutputBuffer,
- OUT UINT *pInHeaderSize,
- OUT UINT *pOutHeaderSize )
+/*
+ * PhsDeCompress
+ *
+ * Routine Description:
+ * Exported function to restore the packet header in Rx path.
+ *
+ * Arguments:
+ * IN void* pvContext - PHS Driver Specific Context.
+ * IN B_UINT16 uiVcid - The Service Flow ID to which current packet header restoration applies.
+ * IN void *pvInputBuffer - The Input buffer containg suppressed packet header data
+ * OUT void *pvOutputBuffer - The output buffer returned by this function after restoration
+ * OUT UINT *pHeaderSize - The packet header size after restoration is returned in this parameter.
+ *
+ * Return Value:
+ *
+ * 0 if successful,
+ * >0 Error.
+ */
+ULONG PhsDeCompress(IN void *pvContext,
+ IN B_UINT16 uiVcid,
+ IN void *pvInputBuffer,
+ OUT void *pvOutputBuffer,
+ OUT UINT *pInHeaderSize,
+ OUT UINT *pOutHeaderSize)
{
- UINT nSFIndex =0, nPhsRuleIndex =0 ;
+ UINT nSFIndex = 0, nPhsRuleIndex = 0;
struct bcm_phs_entry *pstServiceFlowEntry = NULL;
struct bcm_phs_rule *pstPhsRule = NULL;
UINT phsi;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- struct bcm_phs_extension *pDeviceExtension=
- (struct bcm_phs_extension *)pvContext;
+ struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext;
*pInHeaderSize = 0;
-
- if(pDeviceExtension == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"Invalid Device Extension\n");
+ if (pDeviceExtension == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Invalid Device Extension\n");
return ERR_PHS_INVALID_DEVICE_EXETENSION;
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"Restoring header\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Restoring header\n");
phsi = *((unsigned char *)(pvInputBuffer));
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"PHSI To Be Used For restore : %x\n",phsi);
- if(phsi == UNCOMPRESSED_PACKET )
- {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "PHSI To Be Used For restore : %x\n", phsi);
+ if (phsi == UNCOMPRESSED_PACKET)
return STATUS_PHS_NOCOMPRESSION;
- }
- //Retrieve the SFID Entry Index for requested Service Flow
+ /* Retrieve the SFID Entry Index for requested Service Flow */
nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable,
- uiVcid,&pstServiceFlowEntry);
- if(nSFIndex == PHS_INVALID_TABLE_INDEX)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"SFID Match Failed During Lookup\n");
+ uiVcid, &pstServiceFlowEntry);
+ if (nSFIndex == PHS_INVALID_TABLE_INDEX) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "SFID Match Failed During Lookup\n");
return ERR_SF_MATCH_FAIL;
}
- nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable,phsi,
- eActiveClassifierRuleContext,&pstPhsRule);
- if(nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
- {
- //Phs Rule does not exist in active rules table. Lets try in the old rules table.
+ nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable, phsi,
+ eActiveClassifierRuleContext, &pstPhsRule);
+ if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX) {
+ /* Phs Rule does not exist in active rules table. Lets try in the old rules table. */
nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable,
- phsi,eOldClassifierRuleContext,&pstPhsRule);
- if(nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
- {
+ phsi, eOldClassifierRuleContext, &pstPhsRule);
+ if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX)
return ERR_PHSRULE_MATCH_FAIL;
- }
-
}
*pInHeaderSize = phs_decompress((PUCHAR)pvInputBuffer,
- (PUCHAR)pvOutputBuffer,pstPhsRule,pOutHeaderSize);
+ (PUCHAR)pvOutputBuffer, pstPhsRule, pOutHeaderSize);
pstPhsRule->PHSModifiedBytes += *pOutHeaderSize - *pInHeaderSize - 1;
@@ -831,112 +731,94 @@ ULONG PhsDeCompress(IN void* pvContext,
return STATUS_PHS_COMPRESSED;
}
-
-//-----------------------------------------------------------------------------
-// Procedure: free_phs_serviceflow_rules
-//
-// Description: This routine is responsible for freeing memory allocated for PHS rules.
-//
-// Arguments:
-// rules - ptr to S_SERVICEFLOW_TABLE structure.
-//
-// Returns:
-// Does not return any value.
-//-----------------------------------------------------------------------------
-
+/*
+ * Procedure: free_phs_serviceflow_rules
+ *
+ * Description: This routine is responsible for freeing memory allocated for PHS rules.
+ *
+ * Arguments:
+ * rules - ptr to S_SERVICEFLOW_TABLE structure.
+ *
+ * Returns:
+ * Does not return any value.
+ */
static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable)
{
- int i,j;
+ int i, j;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n");
- if(psServiceFlowRulesTable)
- {
- for(i=0;i<MAX_SERVICEFLOWS;i++)
- {
- struct bcm_phs_entry stServiceFlowEntry =
- psServiceFlowRulesTable->stSFList[i];
- struct bcm_phs_classifier_table *pstClassifierRulesTable =
- stServiceFlowEntry.pstClassifierTable;
-
- if(pstClassifierRulesTable)
- {
- for(j=0;j<MAX_PHSRULE_PER_SF;j++)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule)
- {
- if(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
- ->u8RefCnt)
- pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
- ->u8RefCnt--;
- if(0==pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
- ->u8RefCnt)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n");
+
+ if (psServiceFlowRulesTable) {
+ for (i = 0; i < MAX_SERVICEFLOWS; i++) {
+ struct bcm_phs_entry stServiceFlowEntry = psServiceFlowRulesTable->stSFList[i];
+ struct bcm_phs_classifier_table *pstClassifierRulesTable = stServiceFlowEntry.pstClassifierTable;
+
+ if (pstClassifierRulesTable) {
+ for (j = 0; j < MAX_PHSRULE_PER_SF; j++) {
+ if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule) {
+
+ if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt--;
+
+ if (0 == pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule);
+
pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL;
}
- if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule)
- {
- if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
- ->u8RefCnt)
- pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
- ->u8RefCnt--;
- if(0==pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
- ->u8RefCnt)
+
+ if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule) {
+
+ if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt)
+ pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt--;
+
+ if (0 == pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt)
kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule);
+
pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL;
}
}
kfree(pstClassifierRulesTable);
- stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
+ stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
}
}
}
- kfree(psServiceFlowRulesTable);
- psServiceFlowRulesTable = NULL;
+ kfree(psServiceFlowRulesTable);
+ psServiceFlowRulesTable = NULL;
}
-
-
static BOOLEAN ValidatePHSRuleComplete(IN struct bcm_phs_rule *psPhsRule)
{
- if(psPhsRule)
- {
- if(!psPhsRule->u8PHSI)
- {
- // PHSI is not valid
+ if (psPhsRule) {
+ if (!psPhsRule->u8PHSI) {
+ /* PHSI is not valid */
return FALSE;
}
- if(!psPhsRule->u8PHSS)
- {
- //PHSS Is Undefined
+ if (!psPhsRule->u8PHSS) {
+ /* PHSS Is Undefined */
return FALSE;
}
- //Check if PHSF is defines for the PHS Rule
- if(!psPhsRule->u8PHSFLength) // If any part of PHSF is valid then Rule contains valid PHSF
- {
+ /* Check if PHSF is defines for the PHS Rule */
+ if (!psPhsRule->u8PHSFLength) /* If any part of PHSF is valid then Rule contains valid PHSF */
return FALSE;
- }
+
return TRUE;
- }
- else
- {
+ } else
return FALSE;
- }
}
UINT GetServiceFlowEntry(IN struct bcm_phs_table *psServiceFlowTable,
- IN B_UINT16 uiVcid, struct bcm_phs_entry **ppstServiceFlowEntry)
+ IN B_UINT16 uiVcid,
+ struct bcm_phs_entry **ppstServiceFlowEntry)
{
- int i;
- for(i=0;i<MAX_SERVICEFLOWS;i++)
- {
- if(psServiceFlowTable->stSFList[i].bUsed)
- {
- if(psServiceFlowTable->stSFList[i].uiVcid == uiVcid)
- {
+ int i;
+
+ for (i = 0; i < MAX_SERVICEFLOWS; i++) {
+ if (psServiceFlowTable->stSFList[i].bUsed) {
+ if (psServiceFlowTable->stSFList[i].uiVcid == uiVcid) {
*ppstServiceFlowEntry = &psServiceFlowTable->stSFList[i];
return i;
}
@@ -947,34 +829,26 @@ UINT GetServiceFlowEntry(IN struct bcm_phs_table *psServiceFlowTable,
return PHS_INVALID_TABLE_INDEX;
}
-
UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable,
- IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext,
- OUT struct bcm_phs_classifier_entry **ppstClassifierEntry)
+ IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext,
+ OUT struct bcm_phs_classifier_entry **ppstClassifierEntry)
{
int i;
struct bcm_phs_classifier_entry *psClassifierRules = NULL;
- for(i=0;i<MAX_PHSRULE_PER_SF;i++)
- {
- if(eClsContext == eActiveClassifierRuleContext)
- {
+ for (i = 0; i < MAX_PHSRULE_PER_SF; i++) {
+
+ if (eClsContext == eActiveClassifierRuleContext)
psClassifierRules = &pstClassifierTable->stActivePhsRulesList[i];
- }
else
- {
psClassifierRules = &pstClassifierTable->stOldPhsRulesList[i];
- }
- if(psClassifierRules->bUsed)
- {
- if(psClassifierRules->uiClassifierRuleId == uiClsid)
- {
+ if (psClassifierRules->bUsed) {
+ if (psClassifierRules->uiClassifierRuleId == uiClsid) {
*ppstClassifierEntry = psClassifierRules;
return i;
}
}
-
}
*ppstClassifierEntry = NULL;
@@ -982,254 +856,227 @@ UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable,
}
static UINT GetPhsRuleEntry(IN struct bcm_phs_classifier_table *pstClassifierTable,
- IN B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext,
- OUT struct bcm_phs_rule **ppstPhsRule)
+ IN B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext,
+ OUT struct bcm_phs_rule **ppstPhsRule)
{
int i;
struct bcm_phs_classifier_entry *pstClassifierRule = NULL;
- for(i=0;i<MAX_PHSRULE_PER_SF;i++)
- {
- if(eClsContext == eActiveClassifierRuleContext)
- {
+
+ for (i = 0; i < MAX_PHSRULE_PER_SF; i++) {
+ if (eClsContext == eActiveClassifierRuleContext)
pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[i];
- }
else
- {
pstClassifierRule = &pstClassifierTable->stOldPhsRulesList[i];
- }
- if(pstClassifierRule->bUsed)
- {
- if(pstClassifierRule->u8PHSI == uiPHSI)
- {
+
+ if (pstClassifierRule->bUsed) {
+ if (pstClassifierRule->u8PHSI == uiPHSI) {
*ppstPhsRule = pstClassifierRule->pstPhsRule;
return i;
}
}
-
}
*ppstPhsRule = NULL;
return PHS_INVALID_TABLE_INDEX;
}
-UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid,IN B_UINT16 uiClsId,
- IN struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule,
- B_UINT8 u8AssociatedPHSI)
+UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId,
+ IN struct bcm_phs_table *psServiceFlowTable,
+ struct bcm_phs_rule *psPhsRule,
+ B_UINT8 u8AssociatedPHSI)
{
-
struct bcm_phs_classifier_table *psaClassifiertable = NULL;
UINT uiStatus = 0;
int iSfIndex;
- BOOLEAN bFreeEntryFound =FALSE;
- //Check for a free entry in SFID table
- for(iSfIndex=0;iSfIndex < MAX_SERVICEFLOWS;iSfIndex++)
- {
- if(!psServiceFlowTable->stSFList[iSfIndex].bUsed)
- {
+ BOOLEAN bFreeEntryFound = FALSE;
+
+ /* Check for a free entry in SFID table */
+ for (iSfIndex = 0; iSfIndex < MAX_SERVICEFLOWS; iSfIndex++) {
+ if (!psServiceFlowTable->stSFList[iSfIndex].bUsed) {
bFreeEntryFound = TRUE;
break;
}
}
- if(!bFreeEntryFound)
+ if (!bFreeEntryFound)
return ERR_SFTABLE_FULL;
-
psaClassifiertable = psServiceFlowTable->stSFList[iSfIndex].pstClassifierTable;
- uiStatus = CreateClassifierPHSRule(uiClsId,psaClassifiertable,psPhsRule,
- eActiveClassifierRuleContext,u8AssociatedPHSI);
- if(uiStatus == PHS_SUCCESS)
- {
- //Add entry at free index to the SF
+ uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable, psPhsRule,
+ eActiveClassifierRuleContext, u8AssociatedPHSI);
+ if (uiStatus == PHS_SUCCESS) {
+ /* Add entry at free index to the SF */
psServiceFlowTable->stSFList[iSfIndex].bUsed = TRUE;
psServiceFlowTable->stSFList[iSfIndex].uiVcid = uiVcid;
}
return uiStatus;
-
}
UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
- IN B_UINT16 uiClsId,IN struct bcm_phs_entry *pstServiceFlowEntry,
- struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI)
+ IN B_UINT16 uiClsId,
+ IN struct bcm_phs_entry *pstServiceFlowEntry,
+ struct bcm_phs_rule *psPhsRule,
+ B_UINT8 u8AssociatedPHSI)
{
struct bcm_phs_classifier_entry *pstClassifierEntry = NULL;
- UINT uiStatus =PHS_SUCCESS;
+ UINT uiStatus = PHS_SUCCESS;
UINT nClassifierIndex = 0;
struct bcm_phs_classifier_table *psaClassifiertable = NULL;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- psaClassifiertable = pstServiceFlowEntry->pstClassifierTable;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>");
+ psaClassifiertable = pstServiceFlowEntry->pstClassifierTable;
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>");
/* Check if the supplied Classifier already exists */
- nClassifierIndex =GetClassifierEntry(
- pstServiceFlowEntry->pstClassifierTable,uiClsId,
- eActiveClassifierRuleContext,&pstClassifierEntry);
- if(nClassifierIndex == PHS_INVALID_TABLE_INDEX)
- {
+ nClassifierIndex = GetClassifierEntry(
+ pstServiceFlowEntry->pstClassifierTable,
+ uiClsId,
+ eActiveClassifierRuleContext,
+ &pstClassifierEntry);
+
+ if (nClassifierIndex == PHS_INVALID_TABLE_INDEX) {
/*
- The Classifier doesn't exist. So its a new classifier being added.
- Add new entry to associate PHS Rule to the Classifier
- */
+ * The Classifier doesn't exist. So its a new classifier being added.
+ * Add new entry to associate PHS Rule to the Classifier
+ */
- uiStatus = CreateClassifierPHSRule(uiClsId,psaClassifiertable,
- psPhsRule,eActiveClassifierRuleContext,u8AssociatedPHSI);
+ uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable,
+ psPhsRule,
+ eActiveClassifierRuleContext,
+ u8AssociatedPHSI);
return uiStatus;
}
/*
- The Classifier exists.The PHS Rule for this classifier
- is being modified
- */
- if(pstClassifierEntry->u8PHSI == psPhsRule->u8PHSI)
- {
- if(pstClassifierEntry->pstPhsRule == NULL)
+ * The Classifier exists.The PHS Rule for this classifier
+ * is being modified
+ */
+
+ if (pstClassifierEntry->u8PHSI == psPhsRule->u8PHSI) {
+ if (pstClassifierEntry->pstPhsRule == NULL)
return ERR_PHS_INVALID_PHS_RULE;
/*
- This rule already exists if any fields are changed for this PHS
- rule update them.
+ * This rule already exists if any fields are changed for this PHS
+ * rule update them.
*/
- /* If any part of PHSF is valid then we update PHSF */
- if(psPhsRule->u8PHSFLength)
- {
- //update PHSF
+ /* If any part of PHSF is valid then we update PHSF */
+ if (psPhsRule->u8PHSFLength) {
+ /* update PHSF */
memcpy(pstClassifierEntry->pstPhsRule->u8PHSF,
- psPhsRule->u8PHSF , MAX_PHS_LENGTHS);
+ psPhsRule->u8PHSF, MAX_PHS_LENGTHS);
}
- if(psPhsRule->u8PHSFLength)
- {
- //update PHSFLen
- pstClassifierEntry->pstPhsRule->u8PHSFLength =
- psPhsRule->u8PHSFLength;
+
+ if (psPhsRule->u8PHSFLength) {
+ /* update PHSFLen */
+ pstClassifierEntry->pstPhsRule->u8PHSFLength = psPhsRule->u8PHSFLength;
}
- if(psPhsRule->u8PHSMLength)
- {
- //update PHSM
+
+ if (psPhsRule->u8PHSMLength) {
+ /* update PHSM */
memcpy(pstClassifierEntry->pstPhsRule->u8PHSM,
- psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
+ psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
}
- if(psPhsRule->u8PHSMLength)
- {
- //update PHSM Len
+
+ if (psPhsRule->u8PHSMLength) {
+ /* update PHSM Len */
pstClassifierEntry->pstPhsRule->u8PHSMLength =
- psPhsRule->u8PHSMLength;
+ psPhsRule->u8PHSMLength;
}
- if(psPhsRule->u8PHSS)
- {
- //update PHSS
+
+ if (psPhsRule->u8PHSS) {
+ /* update PHSS */
pstClassifierEntry->pstPhsRule->u8PHSS = psPhsRule->u8PHSS;
}
- //update PHSV
+ /* update PHSV */
pstClassifierEntry->pstPhsRule->u8PHSV = psPhsRule->u8PHSV;
-
+ } else {
+ /* A new rule is being set for this classifier. */
+ uiStatus = UpdateClassifierPHSRule(uiClsId, pstClassifierEntry,
+ psaClassifiertable, psPhsRule, u8AssociatedPHSI);
}
- else
- {
- /*
- A new rule is being set for this classifier.
- */
- uiStatus=UpdateClassifierPHSRule( uiClsId, pstClassifierEntry,
- psaClassifiertable, psPhsRule, u8AssociatedPHSI);
- }
-
-
return uiStatus;
}
static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
- struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule,
- enum bcm_phs_classifier_context eClsContext,B_UINT8 u8AssociatedPHSI)
+ struct bcm_phs_classifier_table *psaClassifiertable,
+ struct bcm_phs_rule *psPhsRule,
+ enum bcm_phs_classifier_context eClsContext,
+ B_UINT8 u8AssociatedPHSI)
{
UINT iClassifierIndex = 0;
BOOLEAN bFreeEntryFound = FALSE;
struct bcm_phs_classifier_entry *psClassifierRules = NULL;
UINT nStatus = PHS_SUCCESS;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL,"Inside CreateClassifierPHSRule");
- if(psaClassifiertable == NULL)
- {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Inside CreateClassifierPHSRule");
+
+ if (psaClassifiertable == NULL)
return ERR_INVALID_CLASSIFIERTABLE_FOR_SF;
- }
- if(eClsContext == eOldClassifierRuleContext)
- {
- /* If An Old Entry for this classifier ID already exists in the
- old rules table replace it. */
+ if (eClsContext == eOldClassifierRuleContext) {
+ /*
+ * If An Old Entry for this classifier ID already exists in the
+ * old rules table replace it.
+ */
iClassifierIndex =
- GetClassifierEntry(psaClassifiertable, uiClsId,
- eClsContext,&psClassifierRules);
- if(iClassifierIndex != PHS_INVALID_TABLE_INDEX)
- {
+ GetClassifierEntry(psaClassifiertable, uiClsId,
+ eClsContext, &psClassifierRules);
+
+ if (iClassifierIndex != PHS_INVALID_TABLE_INDEX) {
/*
- The Classifier already exists in the old rules table
- Lets replace the old classifier with the new one.
- */
+ * The Classifier already exists in the old rules table
+ * Lets replace the old classifier with the new one.
+ */
bFreeEntryFound = TRUE;
}
}
- if(!bFreeEntryFound)
- {
- /*
- Continue to search for a free location to add the rule
- */
- for(iClassifierIndex = 0; iClassifierIndex <
- MAX_PHSRULE_PER_SF; iClassifierIndex++)
- {
- if(eClsContext == eActiveClassifierRuleContext)
- {
- psClassifierRules =
- &psaClassifiertable->stActivePhsRulesList[iClassifierIndex];
- }
+ if (!bFreeEntryFound) {
+ /* Continue to search for a free location to add the rule */
+ for (iClassifierIndex = 0; iClassifierIndex <
+ MAX_PHSRULE_PER_SF; iClassifierIndex++) {
+ if (eClsContext == eActiveClassifierRuleContext)
+ psClassifierRules = &psaClassifiertable->stActivePhsRulesList[iClassifierIndex];
else
- {
- psClassifierRules =
- &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
- }
+ psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
- if(!psClassifierRules->bUsed)
- {
+ if (!psClassifierRules->bUsed) {
bFreeEntryFound = TRUE;
break;
}
}
}
- if(!bFreeEntryFound)
- {
- if(eClsContext == eActiveClassifierRuleContext)
- {
+ if (!bFreeEntryFound) {
+
+ if (eClsContext == eActiveClassifierRuleContext)
return ERR_CLSASSIFIER_TABLE_FULL;
- }
- else
- {
- //Lets replace the oldest rule if we are looking in old Rule table
- if(psaClassifiertable->uiOldestPhsRuleIndex >=
- MAX_PHSRULE_PER_SF)
- {
- psaClassifiertable->uiOldestPhsRuleIndex =0;
- }
+ else {
+ /* Lets replace the oldest rule if we are looking in old Rule table */
+ if (psaClassifiertable->uiOldestPhsRuleIndex >= MAX_PHSRULE_PER_SF)
+ psaClassifiertable->uiOldestPhsRuleIndex = 0;
iClassifierIndex = psaClassifiertable->uiOldestPhsRuleIndex;
- psClassifierRules =
- &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
+ psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex];
- (psaClassifiertable->uiOldestPhsRuleIndex)++;
+ (psaClassifiertable->uiOldestPhsRuleIndex)++;
}
}
- if(eClsContext == eOldClassifierRuleContext)
- {
- if(psClassifierRules->pstPhsRule == NULL)
- {
- psClassifierRules->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule),GFP_KERNEL);
+ if (eClsContext == eOldClassifierRuleContext) {
+
+ if (psClassifierRules->pstPhsRule == NULL) {
- if(NULL == psClassifierRules->pstPhsRule)
+ psClassifierRules->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL);
+
+ if (NULL == psClassifierRules->pstPhsRule)
return ERR_PHSRULE_MEMALLOC_FAIL;
}
@@ -1238,70 +1085,62 @@ static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId,
psClassifierRules->u8PHSI = psPhsRule->u8PHSI;
psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule;
- /* Update The PHS rule */
- memcpy(psClassifierRules->pstPhsRule,
- psPhsRule, sizeof(struct bcm_phs_rule));
- }
- else
- {
- nStatus = UpdateClassifierPHSRule(uiClsId,psClassifierRules,
- psaClassifiertable,psPhsRule,u8AssociatedPHSI);
- }
+ /* Update The PHS rule */
+ memcpy(psClassifierRules->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule));
+ } else
+ nStatus = UpdateClassifierPHSRule(uiClsId, psClassifierRules,
+ psaClassifiertable, psPhsRule, u8AssociatedPHSI);
+
return nStatus;
}
-
static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
- IN struct bcm_phs_classifier_entry *pstClassifierEntry,
- struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule,
- B_UINT8 u8AssociatedPHSI)
+ IN struct bcm_phs_classifier_entry *pstClassifierEntry,
+ struct bcm_phs_classifier_table *psaClassifiertable,
+ struct bcm_phs_rule *psPhsRule,
+ B_UINT8 u8AssociatedPHSI)
{
struct bcm_phs_rule *pstAddPhsRule = NULL;
- UINT nPhsRuleIndex = 0;
- BOOLEAN bPHSRuleOrphaned = FALSE;
+ UINT nPhsRuleIndex = 0;
+ BOOLEAN bPHSRuleOrphaned = FALSE;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- psPhsRule->u8RefCnt =0;
-
- /* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry*/
- bPHSRuleOrphaned = DerefPhsRule( uiClsId, psaClassifiertable,
- pstClassifierEntry->pstPhsRule);
-
- //Step 2 Search if there is a PHS Rule with u8AssociatedPHSI in Classifier table for this SF
- nPhsRuleIndex =GetPhsRuleEntry(psaClassifiertable,u8AssociatedPHSI,
- eActiveClassifierRuleContext, &pstAddPhsRule);
- if(PHS_INVALID_TABLE_INDEX == nPhsRuleIndex)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAdding New PHSRuleEntry For Classifier");
-
- if(psPhsRule->u8PHSI == 0)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nError PHSI is Zero\n");
+
+ psPhsRule->u8RefCnt = 0;
+
+ /* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry */
+ bPHSRuleOrphaned = DerefPhsRule(uiClsId, psaClassifiertable,
+ pstClassifierEntry->pstPhsRule);
+
+ /* Step 2 Search if there is a PHS Rule with u8AssociatedPHSI in Classifier table for this SF */
+ nPhsRuleIndex = GetPhsRuleEntry(psaClassifiertable, u8AssociatedPHSI,
+ eActiveClassifierRuleContext, &pstAddPhsRule);
+ if (PHS_INVALID_TABLE_INDEX == nPhsRuleIndex) {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAdding New PHSRuleEntry For Classifier");
+
+ if (psPhsRule->u8PHSI == 0) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nError PHSI is Zero\n");
return ERR_PHS_INVALID_PHS_RULE;
}
- //Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId
- if(FALSE == bPHSRuleOrphaned)
- {
+
+ /* Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId */
+ if (FALSE == bPHSRuleOrphaned) {
+
pstClassifierEntry->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL);
- if(NULL == pstClassifierEntry->pstPhsRule)
- {
+ if (NULL == pstClassifierEntry->pstPhsRule)
return ERR_PHSRULE_MEMALLOC_FAIL;
- }
}
memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule));
-
- }
- else
- {
- //Step 2.b PHS Rule Exists Tie uiClsId with the existing PHS Rule
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
- if(bPHSRuleOrphaned)
- {
+ } else {
+ /* Step 2.b PHS Rule Exists Tie uiClsId with the existing PHS Rule */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
+ if (bPHSRuleOrphaned) {
kfree(pstClassifierEntry->pstPhsRule);
pstClassifierEntry->pstPhsRule = NULL;
}
pstClassifierEntry->pstPhsRule = pstAddPhsRule;
-
}
+
pstClassifierEntry->bUsed = TRUE;
pstClassifierEntry->u8PHSI = pstClassifierEntry->pstPhsRule->u8PHSI;
pstClassifierEntry->uiClassifierRuleId = uiClsId;
@@ -1309,79 +1148,74 @@ static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId,
pstClassifierEntry->bUnclassifiedPHSRule = pstClassifierEntry->pstPhsRule->bUnclassifiedPHSRule;
return PHS_SUCCESS;
-
}
static BOOLEAN DerefPhsRule(IN B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule)
{
- if(pstPhsRule==NULL)
+ if (pstPhsRule == NULL)
return FALSE;
- if(pstPhsRule->u8RefCnt)
+
+ if (pstPhsRule->u8RefCnt)
pstPhsRule->u8RefCnt--;
- if(0==pstPhsRule->u8RefCnt)
- {
- /*if(pstPhsRule->u8PHSI)
- //Store the currently active rule into the old rules list
- CreateClassifierPHSRule(uiClsId,psaClassifiertable,pstPhsRule,eOldClassifierRuleContext,pstPhsRule->u8PHSI);*/
+
+ if (0 == pstPhsRule->u8RefCnt) {
+ /*
+ * if(pstPhsRule->u8PHSI)
+ * Store the currently active rule into the old rules list
+ * CreateClassifierPHSRule(uiClsId,psaClassifiertable,pstPhsRule,eOldClassifierRuleContext,pstPhsRule->u8PHSI);
+ */
return TRUE;
- }
- else
- {
+ } else
return FALSE;
- }
}
void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension)
{
- int i,j,k,l;
+ int i, j, k, l;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules : \n");
- for(i=0;i<MAX_SERVICEFLOWS;i++)
- {
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules :\n");
+
+ for (i = 0; i < MAX_SERVICEFLOWS; i++) {
+
struct bcm_phs_entry stServFlowEntry =
- pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i];
- if(stServFlowEntry.bUsed)
- {
- for(j=0;j<MAX_PHSRULE_PER_SF;j++)
- {
- for(l=0;l<2;l++)
- {
+ pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i];
+ if (stServFlowEntry.bUsed) {
+
+ for (j = 0; j < MAX_PHSRULE_PER_SF; j++) {
+
+ for (l = 0; l < 2; l++) {
struct bcm_phs_classifier_entry stClsEntry;
- if(l==0)
- {
+
+ if (l == 0) {
stClsEntry = stServFlowEntry.pstClassifierTable->stActivePhsRulesList[j];
- if(stClsEntry.bUsed)
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Active PHS Rule : \n");
- }
- else
- {
+ if (stClsEntry.bUsed)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Active PHS Rule :\n");
+ } else {
stClsEntry = stServFlowEntry.pstClassifierTable->stOldPhsRulesList[j];
- if(stClsEntry.bUsed)
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Old PHS Rule : \n");
+ if (stClsEntry.bUsed)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Old PHS Rule :\n");
}
- if(stClsEntry.bUsed)
- {
-
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n VCID : %#X",stServFlowEntry.uiVcid);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n ClassifierID : %#X",stClsEntry.uiClassifierRuleId);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSRuleID : %#X",stClsEntry.u8PHSI);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n****************PHS Rule********************\n");
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSI : %#X",stClsEntry.pstPhsRule->u8PHSI);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSFLength : %#X ",stClsEntry.pstPhsRule->u8PHSFLength);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSF : ");
- for(k=0;k<stClsEntry.pstPhsRule->u8PHSFLength;k++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ",stClsEntry.pstPhsRule->u8PHSF[k]);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSMLength : %#X",stClsEntry.pstPhsRule->u8PHSMLength);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSM :");
- for(k=0;k<stClsEntry.pstPhsRule->u8PHSMLength;k++)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ",stClsEntry.pstPhsRule->u8PHSM[k]);
- }
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSS : %#X ",stClsEntry.pstPhsRule->u8PHSS);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSV : %#X",stClsEntry.pstPhsRule->u8PHSV);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n********************************************\n");
+
+ if (stClsEntry.bUsed) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n VCID : %#X", stServFlowEntry.uiVcid);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n ClassifierID : %#X", stClsEntry.uiClassifierRuleId);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSRuleID : %#X", stClsEntry.u8PHSI);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n****************PHS Rule********************\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSI : %#X", stClsEntry.pstPhsRule->u8PHSI);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSFLength : %#X ", stClsEntry.pstPhsRule->u8PHSFLength);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSF : ");
+
+ for (k = 0 ; k < stClsEntry.pstPhsRule->u8PHSFLength; k++)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ", stClsEntry.pstPhsRule->u8PHSF[k]);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSMLength : %#X", stClsEntry.pstPhsRule->u8PHSMLength);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSM :");
+
+ for (k = 0; k < stClsEntry.pstPhsRule->u8PHSMLength; k++)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ", stClsEntry.pstPhsRule->u8PHSM[k]);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSS : %#X ", stClsEntry.pstPhsRule->u8PHSS);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSV : %#X", stClsEntry.pstPhsRule->u8PHSV);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n********************************************\n");
}
}
}
@@ -1389,66 +1223,69 @@ void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension)
}
}
-
-//-----------------------------------------------------------------------------
-// Procedure: phs_decompress
-//
-// Description: This routine restores the static fields within the packet.
-//
-// Arguments:
-// in_buf - ptr to incoming packet buffer.
-// out_buf - ptr to output buffer where the suppressed header is copied.
-// decomp_phs_rules - ptr to PHS rule.
-// header_size - ptr to field which holds the phss or phsf_length.
-//
-// Returns:
-// size -The number of bytes of dynamic fields present with in the incoming packet
-// header.
-// 0 -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed.
-//-----------------------------------------------------------------------------
-
-int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
- struct bcm_phs_rule *decomp_phs_rules, UINT *header_size)
+/*
+ * Procedure: phs_decompress
+ *
+ * Description: This routine restores the static fields within the packet.
+ *
+ * Arguments:
+ * in_buf - ptr to incoming packet buffer.
+ * out_buf - ptr to output buffer where the suppressed header is copied.
+ * decomp_phs_rules - ptr to PHS rule.
+ * header_size - ptr to field which holds the phss or phsf_length.
+ *
+ * Returns:
+ * size -The number of bytes of dynamic fields present with in the incoming packet
+ * header.
+ * 0 -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed.
+ */
+int phs_decompress(unsigned char *in_buf,
+ unsigned char *out_buf,
+ struct bcm_phs_rule *decomp_phs_rules,
+ UINT *header_size)
{
- int phss,size=0;
+ int phss, size = 0;
struct bcm_phs_rule *tmp_memb;
- int bit,i=0;
- unsigned char *phsf,*phsm;
- int in_buf_len = *header_size-1;
+ int bit, i = 0;
+ unsigned char *phsf, *phsm;
+ int in_buf_len = *header_size - 1;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
+
in_buf++;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"====>\n");
+
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "====>\n");
*header_size = 0;
- if((decomp_phs_rules == NULL ))
+ if ((decomp_phs_rules == NULL))
return 0;
-
tmp_memb = decomp_phs_rules;
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI 1 %d",phsi));
- //*header_size = tmp_memb->u8PHSFLength;
- phss = tmp_memb->u8PHSS;
- phsf = tmp_memb->u8PHSF;
- phsm = tmp_memb->u8PHSM;
-
- if(phss > MAX_PHS_LENGTHS)
+ /*
+ * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI 1 %d",phsi));
+ * header_size = tmp_memb->u8PHSFLength;
+ */
+ phss = tmp_memb->u8PHSS;
+ phsf = tmp_memb->u8PHSF;
+ phsm = tmp_memb->u8PHSM;
+
+ if (phss > MAX_PHS_LENGTHS)
phss = MAX_PHS_LENGTHS;
- //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI %d phss %d index %d",phsi,phss,index));
- while((phss > 0) && (size < in_buf_len))
- {
- bit = ((*phsm << i)& SUPPRESS);
- if(bit == SUPPRESS)
- {
+ /*
+ * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:
+ * In phs_decompress PHSI %d phss %d index %d",phsi,phss,index));
+ */
+ while ((phss > 0) && (size < in_buf_len)) {
+ bit = ((*phsm << i) & SUPPRESS);
+
+ if (bit == SUPPRESS) {
*out_buf = *phsf;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phss %d phsf %d ouput %d",
- phss,*phsf,*out_buf);
- }
- else
- {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss %d phsf %d ouput %d",
+ phss, *phsf, *out_buf);
+ } else {
*out_buf = *in_buf;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phss %d input %d ouput %d",
- phss,*in_buf,*out_buf);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss %d input %d ouput %d",
+ phss, *in_buf, *out_buf);
in_buf++;
size++;
}
@@ -1456,156 +1293,159 @@ int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
phsf++;
phss--;
i++;
- *header_size=*header_size + 1;
+ *header_size = *header_size + 1;
- if(i > MAX_NO_BIT)
- {
- i=0;
+ if (i > MAX_NO_BIT) {
+ i = 0;
phsm++;
}
}
+
return size;
}
-
-
-
-//-----------------------------------------------------------------------------
-// Procedure: phs_compress
-//
-// Description: This routine suppresses the static fields within the packet.Before
-// that it will verify the fields to be suppressed with the corresponding fields in the
-// phsf. For verification it checks the phsv field of PHS rule. If set and verification
-// succeeds it suppresses the field.If any one static field is found different none of
-// the static fields are suppressed then the packet is sent as uncompressed packet with
-// phsi=0.
-//
-// Arguments:
-// phs_rule - ptr to PHS rule.
-// in_buf - ptr to incoming packet buffer.
-// out_buf - ptr to output buffer where the suppressed header is copied.
-// header_size - ptr to field which holds the phss.
-//
-// Returns:
-// size-The number of bytes copied into the output buffer i.e dynamic fields
-// 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
-//-----------------------------------------------------------------------------
-static int phs_compress(struct bcm_phs_rule *phs_rule, unsigned char *in_buf
- ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
+/*
+ * Procedure: phs_compress
+ *
+ * Description: This routine suppresses the static fields within the packet.Before
+ * that it will verify the fields to be suppressed with the corresponding fields in the
+ * phsf. For verification it checks the phsv field of PHS rule. If set and verification
+ * succeeds it suppresses the field.If any one static field is found different none of
+ * the static fields are suppressed then the packet is sent as uncompressed packet with
+ * phsi=0.
+ *
+ * Arguments:
+ * phs_rule - ptr to PHS rule.
+ * in_buf - ptr to incoming packet buffer.
+ * out_buf - ptr to output buffer where the suppressed header is copied.
+ * header_size - ptr to field which holds the phss.
+ *
+ * Returns:
+ * size-The number of bytes copied into the output buffer i.e dynamic fields
+ * 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
+ */
+static int phs_compress(struct bcm_phs_rule *phs_rule,
+ unsigned char *in_buf,
+ unsigned char *out_buf,
+ UINT *header_size,
+ UINT *new_header_size)
{
unsigned char *old_addr = out_buf;
int suppress = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if(phs_rule == NULL)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nphs_compress(): phs_rule null!");
+
+ if (phs_rule == NULL) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nphs_compress(): phs_rule null!");
*out_buf = ZERO_PHSI;
return STATUS_PHS_NOCOMPRESSION;
}
-
- if(phs_rule->u8PHSS <= *new_header_size)
- {
+ if (phs_rule->u8PHSS <= *new_header_size)
*header_size = phs_rule->u8PHSS;
- }
else
- {
*header_size = *new_header_size;
- }
- //To copy PHSI
+
+ /* To copy PHSI */
out_buf++;
- suppress = verify_suppress_phsf(in_buf,out_buf,phs_rule->u8PHSF,
- phs_rule->u8PHSM, phs_rule->u8PHSS, phs_rule->u8PHSV,new_header_size);
+ suppress = verify_suppress_phsf(in_buf, out_buf, phs_rule->u8PHSF,
+ phs_rule->u8PHSM, phs_rule->u8PHSS,
+ phs_rule->u8PHSV, new_header_size);
- if(suppress == STATUS_PHS_COMPRESSED)
- {
+ if (suppress == STATUS_PHS_COMPRESSED) {
*old_addr = (unsigned char)phs_rule->u8PHSI;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress phsi %d",phs_rule->u8PHSI);
- }
- else
- {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress phsi %d", phs_rule->u8PHSI);
+ } else {
*old_addr = ZERO_PHSI;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In phs_compress PHSV Verification failed");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress PHSV Verification failed");
}
+
return suppress;
}
-
-//-----------------------------------------------------------------------------
-// Procedure: verify_suppress_phsf
-//
-// Description: This routine verifies the fields of the packet and if all the
-// static fields are equal it adds the phsi of that PHS rule.If any static
-// field differs it woun't suppress any field.
-//
-// Arguments:
-// rules_set - ptr to classifier_rules.
-// in_buffer - ptr to incoming packet buffer.
-// out_buffer - ptr to output buffer where the suppressed header is copied.
-// phsf - ptr to phsf.
-// phsm - ptr to phsm.
-// phss - variable holding phss.
-//
-// Returns:
-// size-The number of bytes copied into the output buffer i.e dynamic fields.
-// 0 -Packet has failed the verification.
-//-----------------------------------------------------------------------------
-
-static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
- unsigned char *phsf,unsigned char *phsm,unsigned int phss,
- unsigned int phsv,UINT* new_header_size)
+/*
+ * Procedure: verify_suppress_phsf
+ *
+ * Description: This routine verifies the fields of the packet and if all the
+ * static fields are equal it adds the phsi of that PHS rule.If any static
+ * field differs it woun't suppress any field.
+ *
+ * Arguments:
+ * rules_set - ptr to classifier_rules.
+ * in_buffer - ptr to incoming packet buffer.
+ * out_buffer - ptr to output buffer where the suppressed header is copied.
+ * phsf - ptr to phsf.
+ * phsm - ptr to phsm.
+ * phss - variable holding phss.
+ *
+ * Returns:
+ * size-The number of bytes copied into the output buffer i.e dynamic fields.
+ * 0 -Packet has failed the verification.
+ */
+static int verify_suppress_phsf(unsigned char *in_buffer,
+ unsigned char *out_buffer,
+ unsigned char *phsf,
+ unsigned char *phsm,
+ unsigned int phss,
+ unsigned int phsv,
+ UINT *new_header_size)
{
- unsigned int size=0;
- int bit,i=0;
+ unsigned int size = 0;
+ int bit, i = 0;
struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf PHSM - 0x%X",*phsm);
-
- if(phss>(*new_header_size))
- {
- phss=*new_header_size;
- }
- while(phss > 0)
- {
- bit = ((*phsm << i)& SUPPRESS);
- if(bit == SUPPRESS)
- {
-
- if(*in_buffer != *phsf)
- {
- if(phsv == VERIFY)
- {
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf failed for field %d buf %d phsf %d",phss,*in_buffer,*phsf);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf PHSM - 0x%X", *phsm);
+
+ if (phss > (*new_header_size))
+ phss = *new_header_size;
+
+ while (phss > 0) {
+ bit = ((*phsm << i) & SUPPRESS);
+ if (bit == SUPPRESS) {
+ if (*in_buffer != *phsf) {
+ if (phsv == VERIFY) {
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS,
+ PHS_SEND,
+ DBG_LVL_ALL,
+ "\nCOMP:In verify_phsf failed for field %d buf %d phsf %d",
+ phss,
+ *in_buffer,
+ *phsf);
return STATUS_PHS_NOCOMPRESSION;
}
- }
- else
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf success for field %d buf %d phsf %d",phss,*in_buffer,*phsf);
- }
- else
- {
+ } else
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS,
+ PHS_SEND,
+ DBG_LVL_ALL,
+ "\nCOMP:In verify_phsf success for field %d buf %d phsf %d",
+ phss,
+ *in_buffer,
+ *phsf);
+ } else {
*out_buffer = *in_buffer;
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In copying_header input %d out %d",*in_buffer,*out_buffer);
+ BCM_DEBUG_PRINT(Adapter,
+ DBG_TYPE_OTHERS,
+ PHS_SEND,
+ DBG_LVL_ALL,
+ "\nCOMP:In copying_header input %d out %d",
+ *in_buffer,
+ *out_buffer);
out_buffer++;
size++;
}
+
in_buffer++;
phsf++;
phss--;
i++;
- if(i > MAX_NO_BIT)
- {
- i=0;
+
+ if (i > MAX_NO_BIT) {
+ i = 0;
phsm++;
}
}
- BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"\nCOMP:In verify_phsf success");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf success");
*new_header_size = size;
return STATUS_PHS_COMPRESSED;
}
-
-
-
-
-
-
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index e6152f4df14b..bea1330f7ea6 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -2228,20 +2228,20 @@ int BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter)
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL");
return -EINVAL;
}
- psAdapter->psFlashCSInfo = (struct bcm_flash_cs_info *)kzalloc(sizeof(struct bcm_flash_cs_info), GFP_KERNEL);
+ psAdapter->psFlashCSInfo = kzalloc(sizeof(struct bcm_flash_cs_info), GFP_KERNEL);
if (psAdapter->psFlashCSInfo == NULL) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 1.x");
return -ENOMEM;
}
- psAdapter->psFlash2xCSInfo = (struct bcm_flash2x_cs_info *)kzalloc(sizeof(struct bcm_flash2x_cs_info), GFP_KERNEL);
+ psAdapter->psFlash2xCSInfo = kzalloc(sizeof(struct bcm_flash2x_cs_info), GFP_KERNEL);
if (!psAdapter->psFlash2xCSInfo) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 2.x");
kfree(psAdapter->psFlashCSInfo);
return -ENOMEM;
}
- psAdapter->psFlash2xVendorInfo = (struct bcm_flash2x_vendor_info *)kzalloc(sizeof(struct bcm_flash2x_vendor_info), GFP_KERNEL);
+ psAdapter->psFlash2xVendorInfo = kzalloc(sizeof(struct bcm_flash2x_vendor_info), GFP_KERNEL);
if (!psAdapter->psFlash2xVendorInfo) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate Vendor Info Memory for Flash 2.x");
kfree(psAdapter->psFlashCSInfo);
@@ -4074,7 +4074,7 @@ int BcmCopySection(struct bcm_mini_adapter *Adapter,
else
BuffSize = numOfBytes;
- pBuff = (PCHAR)kzalloc(BuffSize, GFP_KERNEL);
+ pBuff = kzalloc(BuffSize, GFP_KERNEL);
if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed.. ");
return -ENOMEM;
@@ -4154,7 +4154,7 @@ int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned
}
/* If Header is present overwrite passed buffer with this */
if (bHasHeader && (Adapter->bHeaderChangeAllowed == FALSE)) {
- pTempBuff = (PUCHAR)kzalloc(HeaderSizeToProtect, GFP_KERNEL);
+ pTempBuff = kzalloc(HeaderSizeToProtect, GFP_KERNEL);
if (!pTempBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed");
return -ENOMEM;
@@ -4563,7 +4563,7 @@ static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect
}
}
- pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL);
+ pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL);
if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
return -ENOMEM;
@@ -4622,7 +4622,7 @@ static int CorruptISOSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_sect
return SECTOR_IS_NOT_WRITABLE;
}
- pBuff = (PUCHAR)kzalloc(MAX_RW_SIZE, GFP_KERNEL);
+ pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL);
if (!pBuff) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey");
return -ENOMEM;
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
deleted file mode 100644
index 7ed5bc6caadb..000000000000
--- a/drivers/staging/ccg/Kconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-if USB_GADGET
-
-config USB_G_CCG
- tristate "Configurable Composite Gadget (STAGING)"
- depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM && TTY
- help
- The Configurable Composite Gadget supports multiple USB
- functions: acm, mass storage, rndis and FunctionFS.
- Each function can be configured and enabled/disabled
- dynamically from userspace through a sysfs interface.
-
- In order to compile this (either as a module or built-in),
- "USB Gadget Drivers" and anything under it must not be
- selected compiled-in in
- Device Drivers->USB Support->USB Gadget Support.
- However, you can say "M" there, if you do, the
- Configurable Composite Gadget can be compiled "M" only
- or not at all.
-
- BIG FAT NOTE: DON'T RELY ON THIS USERINTERFACE HERE! AS PART
- OF THE REWORK DONE HERE WILL BE A NEW USER INTERFACE WITHOUT ANY
- COMPATIBILITY TO THIS SYSFS INTERFACE HERE. BE AWARE OF THIS
- BEFORE SELECTING THIS.
-
-endif # USB_GADGET
diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile
deleted file mode 100644
index 814fa9de5f57..000000000000
--- a/drivers/staging/ccg/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-g_ccg-y := ccg.o
-obj-$(CONFIG_USB_G_CCG) += g_ccg.o
diff --git a/drivers/staging/ccg/TODO b/drivers/staging/ccg/TODO
deleted file mode 100644
index 18612fe70171..000000000000
--- a/drivers/staging/ccg/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-TODO:
- - change configuration interface from sysfs to configfs
-
-Please send patches to Greg Kroah-Hartmann <gregkh@linuxfoundation.org>,
-Andrzej Pietrasiewicz <andrzej.p@samsung.com>, and
-Cc: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c
deleted file mode 100644
index ffc5f73a5b5b..000000000000
--- a/drivers/staging/ccg/ccg.c
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- * Configurable Composite Gadget
- *
- * Initially contributed as "Android Composite Gdaget" by:
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- * Benoit Goby <benoit@android.com>
- *
- * Tailoring it to become a generic Configurable Composite Gadget is
- *
- * Copyright (C) 2012 Samsung Electronics
- * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/utsname.h>
-#include <linux/platform_device.h>
-
-#include <linux/usb/ch9.h>
-#include "composite.h"
-#include <linux/usb/gadget.h>
-
-#include "gadget_chips.h"
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module. So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "usbstring.c"
-#include "config.c"
-#include "epautoconf.c"
-#include "composite.c"
-
-#include "f_mass_storage.c"
-#include "u_serial.c"
-#include "f_acm.c"
-#define USB_ETH_RNDIS y
-#include "f_rndis.c"
-#include "rndis.c"
-#include "u_ether.c"
-#include "f_fs.c"
-
-MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
-MODULE_DESCRIPTION("Configurable Composite USB Gadget");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0");
-
-static const char longname[] = "Configurable Composite Gadget";
-
-/* Default vendor and product IDs, overridden by userspace */
-#define VENDOR_ID 0x1d6b /* Linux Foundation */
-#define PRODUCT_ID 0x0107
-#define GFS_MAX_DEVS 10
-
-struct ccg_usb_function {
- char *name;
- void *config;
-
- struct device *dev;
- char *dev_name;
- struct device_attribute **attributes;
-
- /* for ccg_dev.enabled_functions */
- struct list_head enabled_list;
-
- /* Optional: initialization during gadget bind */
- int (*init)(struct ccg_usb_function *, struct usb_composite_dev *);
- /* Optional: cleanup during gadget unbind */
- void (*cleanup)(struct ccg_usb_function *);
-
- int (*bind_config)(struct ccg_usb_function *,
- struct usb_configuration *);
-
- /* Optional: called when the configuration is removed */
- void (*unbind_config)(struct ccg_usb_function *,
- struct usb_configuration *);
- /* Optional: handle ctrl requests before the device is configured */
- int (*ctrlrequest)(struct ccg_usb_function *,
- struct usb_composite_dev *,
- const struct usb_ctrlrequest *);
-};
-
-struct ffs_obj {
- const char *name;
- bool mounted;
- bool desc_ready;
- bool used;
- struct ffs_data *ffs_data;
-};
-
-struct ccg_dev {
- struct ccg_usb_function **functions;
- struct list_head enabled_functions;
- struct usb_composite_dev *cdev;
- struct device *dev;
-
- bool enabled;
- struct mutex mutex;
- bool connected;
- bool sw_connected;
- struct work_struct work;
-
- unsigned int max_func_num;
- unsigned int func_num;
- struct ffs_obj ffs_tab[GFS_MAX_DEVS];
-};
-
-static struct class *ccg_class;
-static struct ccg_dev *_ccg_dev;
-static int ccg_bind_config(struct usb_configuration *c);
-static void ccg_unbind_config(struct usb_configuration *c);
-
-static char func_names_buf[256];
-
-static struct usb_device_descriptor device_desc = {
- .bLength = sizeof(device_desc),
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16(0x0200),
- .bDeviceClass = USB_CLASS_PER_INTERFACE,
- .idVendor = __constant_cpu_to_le16(VENDOR_ID),
- .idProduct = __constant_cpu_to_le16(PRODUCT_ID),
- .bcdDevice = __constant_cpu_to_le16(0xffff),
- .bNumConfigurations = 1,
-};
-
-static struct usb_configuration ccg_config_driver = {
- .label = "ccg",
- .unbind = ccg_unbind_config,
- .bConfigurationValue = 1,
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = 0xFA, /* 500ma */
-};
-
-static void ccg_work(struct work_struct *data)
-{
- struct ccg_dev *dev = container_of(data, struct ccg_dev, work);
- struct usb_composite_dev *cdev = dev->cdev;
- static char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
- static char *connected[2] = { "USB_STATE=CONNECTED", NULL };
- static char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
- char **uevent_envp = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->config)
- uevent_envp = configured;
- else if (dev->connected != dev->sw_connected)
- uevent_envp = dev->connected ? connected : disconnected;
- dev->sw_connected = dev->connected;
- spin_unlock_irqrestore(&cdev->lock, flags);
-
- if (uevent_envp) {
- kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
- pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
- } else {
- pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
- dev->connected, dev->sw_connected, cdev->config);
- }
-}
-
-
-/*-------------------------------------------------------------------------*/
-/* Supported functions initialization */
-
-static struct ffs_obj *functionfs_find_dev(struct ccg_dev *dev,
- const char *dev_name)
-{
- int i;
-
- for (i = 0; i < dev->max_func_num; i++)
- if (strcmp(dev->ffs_tab[i].name, dev_name) == 0)
- return &dev->ffs_tab[i];
-
- return NULL;
-}
-
-static bool functionfs_all_ready(struct ccg_dev *dev)
-{
- int i;
-
- for (i = 0; i < dev->max_func_num; i++)
- if (dev->ffs_tab[i].used && !dev->ffs_tab[i].desc_ready)
- return false;
-
- return true;
-}
-
-static int functionfs_ready_callback(struct ffs_data *ffs)
-{
- struct ffs_obj *ffs_obj;
- int ret;
-
- mutex_lock(&_ccg_dev->mutex);
-
- ffs_obj = ffs->private_data;
- if (!ffs_obj) {
- ret = -EINVAL;
- goto done;
- }
- if (WARN_ON(ffs_obj->desc_ready)) {
- ret = -EBUSY;
- goto done;
- }
- ffs_obj->ffs_data = ffs;
-
- if (functionfs_all_ready(_ccg_dev)) {
- ret = -EBUSY;
- goto done;
- }
- ffs_obj->desc_ready = true;
-
-done:
- mutex_unlock(&_ccg_dev->mutex);
- return ret;
-}
-
-static void reset_usb(struct ccg_dev *dev)
-{
- /* Cancel pending control requests */
- usb_ep_dequeue(dev->cdev->gadget->ep0, dev->cdev->req);
- usb_remove_config(dev->cdev, &ccg_config_driver);
- dev->enabled = false;
- usb_gadget_disconnect(dev->cdev->gadget);
-}
-
-static void functionfs_closed_callback(struct ffs_data *ffs)
-{
- struct ffs_obj *ffs_obj;
-
- mutex_lock(&_ccg_dev->mutex);
-
- ffs_obj = ffs->private_data;
- if (!ffs_obj)
- goto done;
-
- ffs_obj->desc_ready = false;
-
- if (_ccg_dev->enabled)
- reset_usb(_ccg_dev);
-
-done:
- mutex_unlock(&_ccg_dev->mutex);
-}
-
-static void *functionfs_acquire_dev_callback(const char *dev_name)
-{
- struct ffs_obj *ffs_dev;
-
- mutex_lock(&_ccg_dev->mutex);
-
- ffs_dev = functionfs_find_dev(_ccg_dev, dev_name);
- if (!ffs_dev) {
- ffs_dev = ERR_PTR(-ENODEV);
- goto done;
- }
-
- if (ffs_dev->mounted) {
- ffs_dev = ERR_PTR(-EBUSY);
- goto done;
- }
- ffs_dev->mounted = true;
-
-done:
- mutex_unlock(&_ccg_dev->mutex);
- return ffs_dev;
-}
-
-static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
-{
- struct ffs_obj *ffs_dev;
-
- mutex_lock(&_ccg_dev->mutex);
-
- ffs_dev = ffs_data->private_data;
- if (ffs_dev)
- ffs_dev->mounted = false;
-
- mutex_unlock(&_ccg_dev->mutex);
-}
-
-static int functionfs_function_init(struct ccg_usb_function *f,
- struct usb_composite_dev *cdev)
-{
- return functionfs_init();
-}
-
-static void functionfs_function_cleanup(struct ccg_usb_function *f)
-{
- functionfs_cleanup();
-}
-
-static int functionfs_function_bind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- struct ccg_dev *dev = _ccg_dev;
- int i, ret;
-
- for (i = dev->max_func_num; i--; ) {
- if (!dev->ffs_tab[i].used)
- continue;
- ret = functionfs_bind(dev->ffs_tab[i].ffs_data, c->cdev);
- if (unlikely(ret < 0)) {
- while (++i < dev->max_func_num)
- functionfs_unbind(dev->ffs_tab[i].ffs_data);
- return ret;
- }
- }
-
- for (i = dev->max_func_num; i--; ) {
- if (!dev->ffs_tab[i].used)
- continue;
- ret = functionfs_bind_config(c->cdev, c,
- dev->ffs_tab[i].ffs_data);
- if (unlikely(ret < 0))
- return ret;
- }
-
- return 0;
-}
-
-static void functionfs_function_unbind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- struct ccg_dev *dev = _ccg_dev;
- int i;
-
- for (i = dev->max_func_num; i--; )
- if (dev->ffs_tab[i].ffs_data)
- functionfs_unbind(dev->ffs_tab[i].ffs_data);
-}
-
-static ssize_t functionfs_user_functions_show(struct device *_dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ccg_dev *dev = _ccg_dev;
- char *buff = buf;
- int i;
-
- mutex_lock(&dev->mutex);
-
- for (i = 0; i < dev->max_func_num; i++)
- buff += snprintf(buff, PAGE_SIZE + buf - buff, "%s,",
- dev->ffs_tab[i].name);
-
- mutex_unlock(&dev->mutex);
-
- if (buff != buf)
- *(buff - 1) = '\n';
- return buff - buf;
-}
-
-static ssize_t functionfs_user_functions_store(struct device *_dev,
- struct device_attribute *attr,
- const char *buff, size_t size)
-{
- struct ccg_dev *dev = _ccg_dev;
- char *name, *b;
- ssize_t ret = size;
- int i;
-
- buff = skip_spaces(buff);
- if (!*buff)
- return -EINVAL;
-
- mutex_lock(&dev->mutex);
-
- if (dev->enabled) {
- ret = -EBUSY;
- goto end;
- }
-
- for (i = 0; i < dev->max_func_num; i++)
- if (dev->ffs_tab[i].mounted) {
- ret = -EBUSY;
- goto end;
- }
-
- strlcpy(func_names_buf, buff, sizeof(func_names_buf));
- b = strim(func_names_buf);
-
- /* replace the list of functions */
- dev->max_func_num = 0;
- while (b) {
- name = strsep(&b, ",");
- if (dev->max_func_num == GFS_MAX_DEVS) {
- ret = -ENOSPC;
- goto end;
- }
- if (functionfs_find_dev(dev, name)) {
- ret = -EEXIST;
- continue;
- }
- dev->ffs_tab[dev->max_func_num++].name = name;
- }
-
-end:
- mutex_unlock(&dev->mutex);
- return ret;
-}
-
-static DEVICE_ATTR(user_functions, S_IRUGO | S_IWUSR,
- functionfs_user_functions_show,
- functionfs_user_functions_store);
-
-static ssize_t functionfs_max_user_functions_show(struct device *_dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d", GFS_MAX_DEVS);
-}
-
-static DEVICE_ATTR(max_user_functions, S_IRUGO,
- functionfs_max_user_functions_show, NULL);
-
-static struct device_attribute *functionfs_function_attributes[] = {
- &dev_attr_user_functions,
- &dev_attr_max_user_functions,
- NULL
-};
-
-static struct ccg_usb_function functionfs_function = {
- .name = "fs",
- .init = functionfs_function_init,
- .cleanup = functionfs_function_cleanup,
- .bind_config = functionfs_function_bind_config,
- .unbind_config = functionfs_function_unbind_config,
- .attributes = functionfs_function_attributes,
-};
-
-#define MAX_ACM_INSTANCES 4
-struct acm_function_config {
- int instances;
-};
-
-static int
-acm_function_init(struct ccg_usb_function *f, struct usb_composite_dev *cdev)
-{
- f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
- if (!f->config)
- return -ENOMEM;
-
- return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
-}
-
-static void acm_function_cleanup(struct ccg_usb_function *f)
-{
- gserial_cleanup();
- kfree(f->config);
- f->config = NULL;
-}
-
-static int
-acm_function_bind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- int i;
- int ret = 0;
- struct acm_function_config *config = f->config;
-
- for (i = 0; i < config->instances; i++) {
- ret = acm_bind_config(c, i);
- if (ret) {
- pr_err("Could not bind acm%u config\n", i);
- break;
- }
- }
-
- return ret;
-}
-
-static ssize_t acm_instances_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct acm_function_config *config = f->config;
- return sprintf(buf, "%d\n", config->instances);
-}
-
-static ssize_t acm_instances_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct acm_function_config *config = f->config;
- int value;
- int ret = 0;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret)
- return ret;
-
- if (value > MAX_ACM_INSTANCES)
- return -EINVAL;
-
- config->instances = value;
-
- return size;
-}
-
-static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show,
- acm_instances_store);
-static struct device_attribute *acm_function_attributes[] = {
- &dev_attr_instances,
- NULL
-};
-
-static struct ccg_usb_function acm_function = {
- .name = "acm",
- .init = acm_function_init,
- .cleanup = acm_function_cleanup,
- .bind_config = acm_function_bind_config,
- .attributes = acm_function_attributes,
-};
-
-struct rndis_function_config {
- u8 ethaddr[ETH_ALEN];
- u32 vendorID;
- char manufacturer[256];
- /* "Wireless" RNDIS; auto-detected by Windows */
- bool wceis;
-};
-
-static int rndis_function_init(struct ccg_usb_function *f,
- struct usb_composite_dev *cdev)
-{
- f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
- if (!f->config)
- return -ENOMEM;
- return 0;
-}
-
-static void rndis_function_cleanup(struct ccg_usb_function *f)
-{
- kfree(f->config);
- f->config = NULL;
-}
-
-static int rndis_function_bind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- int ret;
- struct rndis_function_config *rndis = f->config;
-
- if (!rndis) {
- pr_err("%s: rndis_pdata\n", __func__);
- return -1;
- }
-
- pr_info("%s MAC: %pM\n", __func__, rndis->ethaddr);
-
- ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
- if (ret) {
- pr_err("%s: gether_setup failed\n", __func__);
- return ret;
- }
-
- if (rndis->wceis) {
- /* "Wireless" RNDIS; auto-detected by Windows */
- rndis_iad_descriptor.bFunctionClass =
- USB_CLASS_WIRELESS_CONTROLLER;
- rndis_iad_descriptor.bFunctionSubClass = 0x01;
- rndis_iad_descriptor.bFunctionProtocol = 0x03;
- rndis_control_intf.bInterfaceClass =
- USB_CLASS_WIRELESS_CONTROLLER;
- rndis_control_intf.bInterfaceSubClass = 0x01;
- rndis_control_intf.bInterfaceProtocol = 0x03;
- }
-
- return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
- rndis->manufacturer);
-}
-
-static void rndis_function_unbind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- gether_cleanup();
-}
-
-static ssize_t rndis_manufacturer_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
- return sprintf(buf, "%s\n", config->manufacturer);
-}
-
-static ssize_t rndis_manufacturer_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
-
- if (size >= sizeof(config->manufacturer))
- return -EINVAL;
- memcpy(config->manufacturer, buf, size);
- config->manufacturer[size] = 0;
-
- return size;
-}
-
-static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show,
- rndis_manufacturer_store);
-
-static ssize_t rndis_wceis_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
- return sprintf(buf, "%d\n", config->wceis);
-}
-
-static ssize_t rndis_wceis_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
- int value;
- int ret;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret)
- return ret;
-
- config->wceis = value;
-
- return size;
-}
-
-static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show,
- rndis_wceis_store);
-
-static ssize_t rndis_ethaddr_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *rndis = f->config;
- return sprintf(buf, "%pM\n", rndis->ethaddr);
-}
-
-static ssize_t rndis_ethaddr_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *rndis = f->config;
- unsigned char tmp[6];
-
- if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
- tmp + 0, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5) !=
- ETH_ALEN)
- return -EINVAL;
-
- memcpy(rndis->ethaddr, tmp, ETH_ALEN);
-
- return ETH_ALEN;
-
-}
-
-static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show,
- rndis_ethaddr_store);
-
-static ssize_t rndis_vendorID_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
- return sprintf(buf, "%04x\n", config->vendorID);
-}
-
-static ssize_t rndis_vendorID_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct ccg_usb_function *f = dev_get_drvdata(dev);
- struct rndis_function_config *config = f->config;
- int value;
- int ret;
-
- ret = kstrtou32(buf, 16, &value);
- if (ret)
- return ret;
-
- config->vendorID = value;
-
- return size;
-}
-
-static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
- rndis_vendorID_store);
-
-static struct device_attribute *rndis_function_attributes[] = {
- &dev_attr_manufacturer,
- &dev_attr_wceis,
- &dev_attr_ethaddr,
- &dev_attr_vendorID,
- NULL
-};
-
-static struct ccg_usb_function rndis_function = {
- .name = "rndis",
- .init = rndis_function_init,
- .cleanup = rndis_function_cleanup,
- .bind_config = rndis_function_bind_config,
- .unbind_config = rndis_function_unbind_config,
- .attributes = rndis_function_attributes,
-};
-
-static int mass_storage_function_init(struct ccg_usb_function *f,
- struct usb_composite_dev *cdev)
-{
- struct fsg_config fsg;
- struct fsg_common *common;
- int err;
-
- memset(&fsg, 0, sizeof(fsg));
- fsg.nluns = 1;
- fsg.luns[0].removable = 1;
- fsg.vendor_name = iManufacturer;
- fsg.product_name = iProduct;
-
- common = fsg_common_init(NULL, cdev, &fsg);
- if (IS_ERR(common))
- return PTR_ERR(common);
-
- err = sysfs_create_link(&f->dev->kobj,
- &common->luns[0].dev.kobj,
- "lun");
- if (err) {
- fsg_common_put(common);
- return err;
- }
-
- f->config = common;
- return 0;
-}
-
-static void mass_storage_function_cleanup(struct ccg_usb_function *f)
-{
- fsg_common_put(f->config);
- f->config = NULL;
-}
-
-static int mass_storage_function_bind_config(struct ccg_usb_function *f,
- struct usb_configuration *c)
-{
- struct fsg_common *common = f->config;
- return fsg_bind_config(c->cdev, c, common);
-}
-
-static struct ccg_usb_function mass_storage_function = {
- .name = "mass_storage",
- .init = mass_storage_function_init,
- .cleanup = mass_storage_function_cleanup,
- .bind_config = mass_storage_function_bind_config,
-};
-
-static struct ccg_usb_function *supported_functions[] = {
- &functionfs_function,
- &acm_function,
- &rndis_function,
- &mass_storage_function,
- NULL
-};
-
-
-static int ccg_init_functions(struct ccg_usb_function **functions,
- struct usb_composite_dev *cdev)
-{
- struct ccg_dev *dev = _ccg_dev;
- struct ccg_usb_function *f;
- struct device_attribute **attrs;
- struct device_attribute *attr;
- int err;
- int index = 0;
-
- for (; (f = *functions++); index++) {
- f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
- if (!f->dev_name) {
- pr_err("%s: Failed to alloc name %s", __func__,
- f->name);
- err = -ENOMEM;
- goto err_alloc;
- }
- f->dev = device_create(ccg_class, dev->dev,
- MKDEV(0, index), f, f->dev_name);
- if (IS_ERR(f->dev)) {
- pr_err("%s: Failed to create dev %s", __func__,
- f->dev_name);
- err = PTR_ERR(f->dev);
- f->dev = NULL;
- goto err_create;
- }
-
- if (f->init) {
- err = f->init(f, cdev);
- if (err) {
- pr_err("%s: Failed to init %s", __func__,
- f->name);
- goto err_out;
- }
- }
-
- attrs = f->attributes;
- if (attrs) {
- while ((attr = *attrs++) && !err)
- err = device_create_file(f->dev, attr);
- }
- if (err) {
- pr_err("%s: Failed to create function %s attributes",
- __func__, f->name);
- goto err_uninit;
- }
- }
- return 0;
-
-err_uninit:
- if (f->cleanup)
- f->cleanup(f);
-err_out:
- device_destroy(ccg_class, f->dev->devt);
- f->dev = NULL;
-err_create:
- kfree(f->dev_name);
-err_alloc:
- return err;
-}
-
-static void ccg_cleanup_functions(struct ccg_usb_function **functions)
-{
- struct ccg_usb_function *f;
-
- while (*functions) {
- f = *functions++;
-
- if (f->dev) {
- if (f->cleanup)
- f->cleanup(f);
- device_destroy(ccg_class, f->dev->devt);
- kfree(f->dev_name);
- }
- }
-}
-
-static int ccg_bind_enabled_functions(struct ccg_dev *dev,
- struct usb_configuration *c)
-{
- struct ccg_usb_function *f;
- int ret;
-
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- ret = f->bind_config(f, c);
- if (ret) {
- pr_err("%s: %s failed", __func__, f->name);
- return ret;
- }
- }
- return 0;
-}
-
-static void ccg_unbind_enabled_functions(struct ccg_dev *dev,
- struct usb_configuration *c)
-{
- struct ccg_usb_function *f;
-
- list_for_each_entry(f, &dev->enabled_functions, enabled_list)
- if (f->unbind_config)
- f->unbind_config(f, c);
-}
-
-static int ccg_enable_function(struct ccg_dev *dev, char *name)
-{
- struct ccg_usb_function **functions = dev->functions;
- struct ccg_usb_function *f;
- while ((f = *functions++)) {
- if (!strcmp(name, f->name)) {
- list_add_tail(&f->enabled_list,
- &dev->enabled_functions);
- return 0;
- }
- }
- return -EINVAL;
-}
-
-/*-------------------------------------------------------------------------*/
-/* /sys/class/ccg_usb/ccg%d/ interface */
-
-static ssize_t
-functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
-{
- struct ccg_dev *dev = dev_get_drvdata(pdev);
- struct ccg_usb_function *f;
- char *buff = buf;
- int i;
-
- mutex_lock(&dev->mutex);
-
- list_for_each_entry(f, &dev->enabled_functions, enabled_list)
- buff += sprintf(buff, "%s,", f->name);
- for (i = 0; i < dev->max_func_num; i++)
- if (dev->ffs_tab[i].used)
- buff += sprintf(buff, "%s", dev->ffs_tab[i].name);
-
- mutex_unlock(&dev->mutex);
-
- if (buff != buf)
- *(buff-1) = '\n';
- return buff - buf;
-}
-
-static ssize_t
-functions_store(struct device *pdev, struct device_attribute *attr,
- const char *buff, size_t size)
-{
- struct ccg_dev *dev = dev_get_drvdata(pdev);
- char *name;
- char buf[256], *b;
- int err, i;
- bool functionfs_enabled;
-
- buff = skip_spaces(buff);
- if (!*buff)
- return -EINVAL;
-
- mutex_lock(&dev->mutex);
-
- if (dev->enabled) {
- mutex_unlock(&dev->mutex);
- return -EBUSY;
- }
-
- INIT_LIST_HEAD(&dev->enabled_functions);
- functionfs_enabled = false;
- for (i = 0; i < dev->max_func_num; i++)
- dev->ffs_tab[i].used = false;
-
- strlcpy(buf, buff, sizeof(buf));
- b = strim(buf);
-
- while (b) {
- struct ffs_obj *user_func;
-
- name = strsep(&b, ",");
- /* handle FunctionFS implicitly */
- if (!strcmp(name, functionfs_function.name)) {
- pr_err("ccg_usb: Cannot explicitly enable '%s'", name);
- continue;
- }
- user_func = functionfs_find_dev(dev, name);
- if (user_func)
- name = functionfs_function.name;
- err = 0;
- if (!user_func || !functionfs_enabled)
- err = ccg_enable_function(dev, name);
- if (err)
- pr_err("ccg_usb: Cannot enable '%s'", name);
- else if (user_func) {
- user_func->used = true;
- dev->func_num++;
- functionfs_enabled = true;
- }
- }
-
- mutex_unlock(&dev->mutex);
-
- return size;
-}
-
-static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
- char *buf)
-{
- struct ccg_dev *dev = dev_get_drvdata(pdev);
- return sprintf(buf, "%d\n", dev->enabled);
-}
-
-static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
- const char *buff, size_t size)
-{
- struct ccg_dev *dev = dev_get_drvdata(pdev);
- struct usb_composite_dev *cdev = dev->cdev;
- int enabled = 0;
-
- mutex_lock(&dev->mutex);
- sscanf(buff, "%d", &enabled);
- if (enabled && dev->func_num && !functionfs_all_ready(dev)) {
- mutex_unlock(&dev->mutex);
- return -ENODEV;
- }
-
- if (enabled && !dev->enabled) {
- int ret;
-
- cdev->next_string_id = 0;
- /*
- * Update values in composite driver's copy of
- * device descriptor.
- */
- cdev->desc.bDeviceClass = device_desc.bDeviceClass;
- cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
- cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
- cdev->desc.idVendor = idVendor;
- cdev->desc.idProduct = idProduct;
- cdev->desc.bcdDevice = bcdDevice;
-
- usb_add_config(cdev, &ccg_config_driver, ccg_bind_config);
- dev->enabled = true;
- ret = usb_gadget_connect(cdev->gadget);
- if (ret) {
- dev->enabled = false;
- usb_remove_config(cdev, &ccg_config_driver);
- }
- } else if (!enabled && dev->enabled) {
- reset_usb(dev);
- } else {
- pr_err("ccg_usb: already %s\n",
- dev->enabled ? "enabled" : "disabled");
- }
-
- mutex_unlock(&dev->mutex);
- return size;
-}
-
-static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
- char *buf)
-{
- struct ccg_dev *dev = dev_get_drvdata(pdev);
- struct usb_composite_dev *cdev = dev->cdev;
- char *state = "DISCONNECTED";
- unsigned long flags;
-
- if (!cdev)
- goto out;
-
- spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->config)
- state = "CONFIGURED";
- else if (dev->connected)
- state = "CONNECTED";
- spin_unlock_irqrestore(&cdev->lock, flags);
-out:
- return sprintf(buf, "%s\n", state);
-}
-
-#define DESCRIPTOR_ATTR(field, format_string) \
-static ssize_t \
-field ## _show(struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return sprintf(buf, format_string, device_desc.field); \
-} \
-static ssize_t \
-field ## _store(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t size) \
-{ \
- int value; \
- if (sscanf(buf, format_string, &value) == 1) { \
- device_desc.field = value; \
- return size; \
- } \
- return -1; \
-} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
-
-DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
-DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
-DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
-
-static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,
- functions_store);
-static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
-static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
-
-static struct device_attribute *ccg_usb_attributes[] = {
- &dev_attr_bDeviceClass,
- &dev_attr_bDeviceSubClass,
- &dev_attr_bDeviceProtocol,
- &dev_attr_functions,
- &dev_attr_enable,
- &dev_attr_state,
- NULL
-};
-
-/*-------------------------------------------------------------------------*/
-/* Composite driver */
-
-static int ccg_bind_config(struct usb_configuration *c)
-{
- struct ccg_dev *dev = _ccg_dev;
- return ccg_bind_enabled_functions(dev, c);
-}
-
-static void ccg_unbind_config(struct usb_configuration *c)
-{
- struct ccg_dev *dev = _ccg_dev;
-
- ccg_unbind_enabled_functions(dev, c);
-
- usb_ep_autoconfig_reset(dev->cdev->gadget);
-}
-
-static int ccg_bind(struct usb_composite_dev *cdev)
-{
- struct ccg_dev *dev = _ccg_dev;
- struct usb_gadget *gadget = cdev->gadget;
- int gcnum, ret;
-
- /*
- * Start disconnected. Userspace will connect the gadget once
- * it is done configuring the functions.
- */
- usb_gadget_disconnect(gadget);
-
- ret = ccg_init_functions(dev->functions, cdev);
- if (ret)
- return ret;
-
- gcnum = usb_gadget_controller_number(gadget);
- if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
- else {
- pr_warn("%s: controller '%s' not recognized\n",
- longname, gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
- }
-
- usb_gadget_set_selfpowered(gadget);
- dev->cdev = cdev;
-
- return 0;
-}
-
-static int ccg_usb_unbind(struct usb_composite_dev *cdev)
-{
- struct ccg_dev *dev = _ccg_dev;
-
- cancel_work_sync(&dev->work);
- ccg_cleanup_functions(dev->functions);
- return 0;
-}
-
-static struct usb_composite_driver ccg_usb_driver = {
- .name = "configurable_usb",
- .dev = &device_desc,
- .bind = ccg_bind,
- .unbind = ccg_usb_unbind,
- .needs_serial = true,
- .iManufacturer = "Linux Foundation",
- .iProduct = longname,
- .iSerialNumber = "1234567890123456",
-};
-
-static int ccg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
-{
- struct ccg_dev *dev = _ccg_dev;
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- struct usb_request *req = cdev->req;
- struct ccg_usb_function *f;
- int value = -EOPNOTSUPP;
- unsigned long flags;
-
- req->zero = 0;
- req->complete = composite_setup_complete;
- req->length = 0;
- gadget->ep0->driver_data = cdev;
-
- list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
- if (f->ctrlrequest) {
- value = f->ctrlrequest(f, cdev, c);
- if (value >= 0)
- break;
- }
- }
-
- if (value < 0)
- value = composite_setup(gadget, c);
-
- spin_lock_irqsave(&cdev->lock, flags);
- if (!dev->connected) {
- dev->connected = 1;
- schedule_work(&dev->work);
- } else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
- cdev->config) {
- schedule_work(&dev->work);
- }
- spin_unlock_irqrestore(&cdev->lock, flags);
-
- return value;
-}
-
-static void ccg_disconnect(struct usb_gadget *gadget)
-{
- struct ccg_dev *dev = _ccg_dev;
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- unsigned long flags;
-
- composite_disconnect(gadget);
-
- spin_lock_irqsave(&cdev->lock, flags);
- dev->connected = 0;
- schedule_work(&dev->work);
- spin_unlock_irqrestore(&cdev->lock, flags);
-}
-
-static int ccg_create_device(struct ccg_dev *dev)
-{
- struct device_attribute **attrs = ccg_usb_attributes;
- struct device_attribute *attr;
- int err;
-
- dev->dev = device_create(ccg_class, NULL, MKDEV(0, 0), NULL, "ccg0");
- if (IS_ERR(dev->dev))
- return PTR_ERR(dev->dev);
-
- dev_set_drvdata(dev->dev, dev);
-
- while ((attr = *attrs++)) {
- err = device_create_file(dev->dev, attr);
- if (err) {
- device_destroy(ccg_class, dev->dev->devt);
- return err;
- }
- }
- return 0;
-}
-
-
-static int __init ccg_init(void)
-{
- struct ccg_dev *dev;
- int err;
-
- ccg_class = class_create(THIS_MODULE, "ccg_usb");
- if (IS_ERR(ccg_class))
- return PTR_ERR(ccg_class);
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- class_destroy(ccg_class);
- return -ENOMEM;
- }
-
- dev->functions = supported_functions;
- INIT_LIST_HEAD(&dev->enabled_functions);
- INIT_WORK(&dev->work, ccg_work);
- mutex_init(&dev->mutex);
-
- err = ccg_create_device(dev);
- if (err) {
- class_destroy(ccg_class);
- kfree(dev);
- return err;
- }
-
- _ccg_dev = dev;
-
- /* Override composite driver functions */
- composite_driver.setup = ccg_setup;
- composite_driver.disconnect = ccg_disconnect;
-
- err = usb_composite_probe(&ccg_usb_driver);
- if (err) {
- class_destroy(ccg_class);
- kfree(dev);
- }
-
- return err;
-}
-module_init(ccg_init);
-
-static void __exit ccg_exit(void)
-{
- usb_composite_unregister(&ccg_usb_driver);
- class_destroy(ccg_class);
- kfree(_ccg_dev);
- _ccg_dev = NULL;
-}
-module_exit(ccg_exit);
diff --git a/drivers/staging/ccg/composite.c b/drivers/staging/ccg/composite.c
deleted file mode 100644
index 228b4574f228..000000000000
--- a/drivers/staging/ccg/composite.c
+++ /dev/null
@@ -1,1688 +0,0 @@
-/*
- * composite.c - infrastructure for Composite USB Gadgets
- *
- * Copyright (C) 2006-2008 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kallsyms.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/utsname.h>
-
-#include <linux/usb/composite.h>
-#include <asm/unaligned.h>
-
-/*
- * The code in this file is utility code, used to build a gadget driver
- * from one or more "function" drivers, one or more "configuration"
- * objects, and a "usb_composite_driver" by gluing them together along
- * with the relevant device-wide data.
- */
-
-/* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ 1024
-
-static struct usb_composite_driver *composite;
-
-/* Some systems will need runtime overrides for the product identifiers
- * published in the device descriptor, either numbers or strings or both.
- * String parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-static ushort idVendor;
-module_param(idVendor, ushort, 0644);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, 0644);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0644);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, 0644);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, 0644);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
-static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0644);
-MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
-
-static char composite_manufacturer[50];
-
-/*-------------------------------------------------------------------------*/
-/**
- * next_ep_desc() - advance to the next EP descriptor
- * @t: currect pointer within descriptor array
- *
- * Return: next EP descriptor or NULL
- *
- * Iterate over @t until either EP descriptor found or
- * NULL (that indicates end of list) encountered
- */
-static struct usb_descriptor_header**
-next_ep_desc(struct usb_descriptor_header **t)
-{
- for (; *t; t++) {
- if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
- return t;
- }
- return NULL;
-}
-
-/*
- * for_each_ep_desc()- iterate over endpoint descriptors in the
- * descriptors list
- * @start: pointer within descriptor array.
- * @ep_desc: endpoint descriptor to use as the loop cursor
- */
-#define for_each_ep_desc(start, ep_desc) \
- for (ep_desc = next_ep_desc(start); \
- ep_desc; ep_desc = next_ep_desc(ep_desc+1))
-
-/**
- * config_ep_by_speed() - configures the given endpoint
- * according to gadget speed.
- * @g: pointer to the gadget
- * @f: usb function
- * @_ep: the endpoint to configure
- *
- * Return: error code, 0 on success
- *
- * This function chooses the right descriptors for a given
- * endpoint according to gadget speed and saves it in the
- * endpoint desc field. If the endpoint already has a descriptor
- * assigned to it - overwrites it with currently corresponding
- * descriptor. The endpoint maxpacket field is updated according
- * to the chosen descriptor.
- * Note: the supplied function should hold all the descriptors
- * for supported speeds
- */
-int config_ep_by_speed(struct usb_gadget *g,
- struct usb_function *f,
- struct usb_ep *_ep)
-{
- struct usb_composite_dev *cdev = get_gadget_data(g);
- struct usb_endpoint_descriptor *chosen_desc = NULL;
- struct usb_descriptor_header **speed_desc = NULL;
-
- struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
- int want_comp_desc = 0;
-
- struct usb_descriptor_header **d_spd; /* cursor for speed desc */
-
- if (!g || !f || !_ep)
- return -EIO;
-
- /* select desired speed */
- switch (g->speed) {
- case USB_SPEED_SUPER:
- if (gadget_is_superspeed(g)) {
- speed_desc = f->ss_descriptors;
- want_comp_desc = 1;
- break;
- }
- /* else: Fall trough */
- case USB_SPEED_HIGH:
- if (gadget_is_dualspeed(g)) {
- speed_desc = f->hs_descriptors;
- break;
- }
- /* else: fall through */
- default:
- speed_desc = f->descriptors;
- }
- /* find descriptors */
- for_each_ep_desc(speed_desc, d_spd) {
- chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
- if (chosen_desc->bEndpointAddress == _ep->address)
- goto ep_found;
- }
- return -EIO;
-
-ep_found:
- /* commit results */
- _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
- _ep->desc = chosen_desc;
- _ep->comp_desc = NULL;
- _ep->maxburst = 0;
- _ep->mult = 0;
- if (!want_comp_desc)
- return 0;
-
- /*
- * Companion descriptor should follow EP descriptor
- * USB 3.0 spec, #9.6.7
- */
- comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
- if (!comp_desc ||
- (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
- return -EIO;
- _ep->comp_desc = comp_desc;
- if (g->speed == USB_SPEED_SUPER) {
- switch (usb_endpoint_type(_ep->desc)) {
- case USB_ENDPOINT_XFER_ISOC:
- /* mult: bits 1:0 of bmAttributes */
- _ep->mult = comp_desc->bmAttributes & 0x3;
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- _ep->maxburst = comp_desc->bMaxBurst + 1;
- break;
- default:
- if (comp_desc->bMaxBurst != 0)
- ERROR(cdev, "ep0 bMaxBurst must be 0\n");
- _ep->maxburst = 1;
- break;
- }
- }
- return 0;
-}
-
-/**
- * usb_add_function() - add a function to a configuration
- * @config: the configuration
- * @function: the function being added
- * Context: single threaded during gadget setup
- *
- * After initialization, each configuration must have one or more
- * functions added to it. Adding a function involves calling its @bind()
- * method to allocate resources such as interface and string identifiers
- * and endpoints.
- *
- * This function returns the value of the function's bind(), which is
- * zero for success else a negative errno value.
- */
-int usb_add_function(struct usb_configuration *config,
- struct usb_function *function)
-{
- int value = -EINVAL;
-
- DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
- function->name, function,
- config->label, config);
-
- if (!function->set_alt || !function->disable)
- goto done;
-
- function->config = config;
- list_add_tail(&function->list, &config->functions);
-
- /* REVISIT *require* function->bind? */
- if (function->bind) {
- value = function->bind(config, function);
- if (value < 0) {
- list_del(&function->list);
- function->config = NULL;
- }
- } else
- value = 0;
-
- /* We allow configurations that don't work at both speeds.
- * If we run into a lowspeed Linux system, treat it the same
- * as full speed ... it's the function drivers that will need
- * to avoid bulk and ISO transfers.
- */
- if (!config->fullspeed && function->descriptors)
- config->fullspeed = true;
- if (!config->highspeed && function->hs_descriptors)
- config->highspeed = true;
- if (!config->superspeed && function->ss_descriptors)
- config->superspeed = true;
-
-done:
- if (value)
- DBG(config->cdev, "adding '%s'/%p --> %d\n",
- function->name, function, value);
- return value;
-}
-
-/**
- * usb_function_deactivate - prevent function and gadget enumeration
- * @function: the function that isn't yet ready to respond
- *
- * Blocks response of the gadget driver to host enumeration by
- * preventing the data line pullup from being activated. This is
- * normally called during @bind() processing to change from the
- * initial "ready to respond" state, or when a required resource
- * becomes available.
- *
- * For example, drivers that serve as a passthrough to a userspace
- * daemon can block enumeration unless that daemon (such as an OBEX,
- * MTP, or print server) is ready to handle host requests.
- *
- * Not all systems support software control of their USB peripheral
- * data pullups.
- *
- * Returns zero on success, else negative errno.
- */
-int usb_function_deactivate(struct usb_function *function)
-{
- struct usb_composite_dev *cdev = function->config->cdev;
- unsigned long flags;
- int status = 0;
-
- spin_lock_irqsave(&cdev->lock, flags);
-
- if (cdev->deactivations == 0)
- status = usb_gadget_disconnect(cdev->gadget);
- if (status == 0)
- cdev->deactivations++;
-
- spin_unlock_irqrestore(&cdev->lock, flags);
- return status;
-}
-
-/**
- * usb_function_activate - allow function and gadget enumeration
- * @function: function on which usb_function_activate() was called
- *
- * Reverses effect of usb_function_deactivate(). If no more functions
- * are delaying their activation, the gadget driver will respond to
- * host enumeration procedures.
- *
- * Returns zero on success, else negative errno.
- */
-int usb_function_activate(struct usb_function *function)
-{
- struct usb_composite_dev *cdev = function->config->cdev;
- unsigned long flags;
- int status = 0;
-
- spin_lock_irqsave(&cdev->lock, flags);
-
- if (WARN_ON(cdev->deactivations == 0))
- status = -EINVAL;
- else {
- cdev->deactivations--;
- if (cdev->deactivations == 0)
- status = usb_gadget_connect(cdev->gadget);
- }
-
- spin_unlock_irqrestore(&cdev->lock, flags);
- return status;
-}
-
-/**
- * usb_interface_id() - allocate an unused interface ID
- * @config: configuration associated with the interface
- * @function: function handling the interface
- * Context: single threaded during gadget setup
- *
- * usb_interface_id() is called from usb_function.bind() callbacks to
- * allocate new interface IDs. The function driver will then store that
- * ID in interface, association, CDC union, and other descriptors. It
- * will also handle any control requests targeted at that interface,
- * particularly changing its altsetting via set_alt(). There may
- * also be class-specific or vendor-specific requests to handle.
- *
- * All interface identifier should be allocated using this routine, to
- * ensure that for example different functions don't wrongly assign
- * different meanings to the same identifier. Note that since interface
- * identifiers are configuration-specific, functions used in more than
- * one configuration (or more than once in a given configuration) need
- * multiple versions of the relevant descriptors.
- *
- * Returns the interface ID which was allocated; or -ENODEV if no
- * more interface IDs can be allocated.
- */
-int usb_interface_id(struct usb_configuration *config,
- struct usb_function *function)
-{
- unsigned id = config->next_interface_id;
-
- if (id < MAX_CONFIG_INTERFACES) {
- config->interface[id] = function;
- config->next_interface_id = id + 1;
- return id;
- }
- return -ENODEV;
-}
-
-static int config_buf(struct usb_configuration *config,
- enum usb_device_speed speed, void *buf, u8 type)
-{
- struct usb_config_descriptor *c = buf;
- void *next = buf + USB_DT_CONFIG_SIZE;
- int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE;
- struct usb_function *f;
- int status;
-
- /* write the config descriptor */
- c = buf;
- c->bLength = USB_DT_CONFIG_SIZE;
- c->bDescriptorType = type;
- /* wTotalLength is written later */
- c->bNumInterfaces = config->next_interface_id;
- c->bConfigurationValue = config->bConfigurationValue;
- c->iConfiguration = config->iConfiguration;
- c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes;
- c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2);
-
- /* There may be e.g. OTG descriptors */
- if (config->descriptors) {
- status = usb_descriptor_fillbuf(next, len,
- config->descriptors);
- if (status < 0)
- return status;
- len -= status;
- next += status;
- }
-
- /* add each function's descriptors */
- list_for_each_entry(f, &config->functions, list) {
- struct usb_descriptor_header **descriptors;
-
- switch (speed) {
- case USB_SPEED_SUPER:
- descriptors = f->ss_descriptors;
- break;
- case USB_SPEED_HIGH:
- descriptors = f->hs_descriptors;
- break;
- default:
- descriptors = f->descriptors;
- }
-
- if (!descriptors)
- continue;
- status = usb_descriptor_fillbuf(next, len,
- (const struct usb_descriptor_header **) descriptors);
- if (status < 0)
- return status;
- len -= status;
- next += status;
- }
-
- len = next - buf;
- c->wTotalLength = cpu_to_le16(len);
- return len;
-}
-
-static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
-{
- struct usb_gadget *gadget = cdev->gadget;
- struct usb_configuration *c;
- u8 type = w_value >> 8;
- enum usb_device_speed speed = USB_SPEED_UNKNOWN;
-
- if (gadget->speed == USB_SPEED_SUPER)
- speed = gadget->speed;
- else if (gadget_is_dualspeed(gadget)) {
- int hs = 0;
- if (gadget->speed == USB_SPEED_HIGH)
- hs = 1;
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
- if (hs)
- speed = USB_SPEED_HIGH;
-
- }
-
- /* This is a lookup by config *INDEX* */
- w_value &= 0xff;
- list_for_each_entry(c, &cdev->configs, list) {
- /* ignore configs that won't work at this speed */
- switch (speed) {
- case USB_SPEED_SUPER:
- if (!c->superspeed)
- continue;
- break;
- case USB_SPEED_HIGH:
- if (!c->highspeed)
- continue;
- break;
- default:
- if (!c->fullspeed)
- continue;
- }
-
- if (w_value == 0)
- return config_buf(c, speed, cdev->req->buf, type);
- w_value--;
- }
- return -EINVAL;
-}
-
-static int count_configs(struct usb_composite_dev *cdev, unsigned type)
-{
- struct usb_gadget *gadget = cdev->gadget;
- struct usb_configuration *c;
- unsigned count = 0;
- int hs = 0;
- int ss = 0;
-
- if (gadget_is_dualspeed(gadget)) {
- if (gadget->speed == USB_SPEED_HIGH)
- hs = 1;
- if (gadget->speed == USB_SPEED_SUPER)
- ss = 1;
- if (type == USB_DT_DEVICE_QUALIFIER)
- hs = !hs;
- }
- list_for_each_entry(c, &cdev->configs, list) {
- /* ignore configs that won't work at this speed */
- if (ss) {
- if (!c->superspeed)
- continue;
- } else if (hs) {
- if (!c->highspeed)
- continue;
- } else {
- if (!c->fullspeed)
- continue;
- }
- count++;
- }
- return count;
-}
-
-/**
- * bos_desc() - prepares the BOS descriptor.
- * @cdev: pointer to usb_composite device to generate the bos
- * descriptor for
- *
- * This function generates the BOS (Binary Device Object)
- * descriptor and its device capabilities descriptors. The BOS
- * descriptor should be supported by a SuperSpeed device.
- */
-static int bos_desc(struct usb_composite_dev *cdev)
-{
- struct usb_ext_cap_descriptor *usb_ext;
- struct usb_ss_cap_descriptor *ss_cap;
- struct usb_dcd_config_params dcd_config_params;
- struct usb_bos_descriptor *bos = cdev->req->buf;
-
- bos->bLength = USB_DT_BOS_SIZE;
- bos->bDescriptorType = USB_DT_BOS;
-
- bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
- bos->bNumDeviceCaps = 0;
-
- /*
- * A SuperSpeed device shall include the USB2.0 extension descriptor
- * and shall support LPM when operating in USB2.0 HS mode.
- */
- usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
- bos->bNumDeviceCaps++;
- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
- usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
- usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
-
- /*
- * The Superspeed USB Capability descriptor shall be implemented by all
- * SuperSpeed devices.
- */
- ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
- bos->bNumDeviceCaps++;
- le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
- ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
- ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
- ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
- ss_cap->bmAttributes = 0; /* LTM is not supported yet */
- ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
- USB_FULL_SPEED_OPERATION |
- USB_HIGH_SPEED_OPERATION |
- USB_5GBPS_OPERATION);
- ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
-
- /* Get Controller configuration */
- if (cdev->gadget->ops->get_config_params)
- cdev->gadget->ops->get_config_params(&dcd_config_params);
- else {
- dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
- dcd_config_params.bU2DevExitLat =
- cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
- }
- ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
- ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
-
- return le16_to_cpu(bos->wTotalLength);
-}
-
-static void device_qual(struct usb_composite_dev *cdev)
-{
- struct usb_qualifier_descriptor *qual = cdev->req->buf;
-
- qual->bLength = sizeof(*qual);
- qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
- /* POLICY: same bcdUSB and device type info at both speeds */
- qual->bcdUSB = cdev->desc.bcdUSB;
- qual->bDeviceClass = cdev->desc.bDeviceClass;
- qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
- qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
- /* ASSUME same EP0 fifo size at both speeds */
- qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
- qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
- qual->bRESERVED = 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void reset_config(struct usb_composite_dev *cdev)
-{
- struct usb_function *f;
-
- DBG(cdev, "reset config\n");
-
- list_for_each_entry(f, &cdev->config->functions, list) {
- if (f->disable)
- f->disable(f);
-
- bitmap_zero(f->endpoints, 32);
- }
- cdev->config = NULL;
-}
-
-static int set_config(struct usb_composite_dev *cdev,
- const struct usb_ctrlrequest *ctrl, unsigned number)
-{
- struct usb_gadget *gadget = cdev->gadget;
- struct usb_configuration *c = NULL;
- int result = -EINVAL;
- unsigned power = gadget_is_otg(gadget) ? 8 : 100;
- int tmp;
-
- if (number) {
- list_for_each_entry(c, &cdev->configs, list) {
- if (c->bConfigurationValue == number) {
- /*
- * We disable the FDs of the previous
- * configuration only if the new configuration
- * is a valid one
- */
- if (cdev->config)
- reset_config(cdev);
- result = 0;
- break;
- }
- }
- if (result < 0)
- goto done;
- } else { /* Zero configuration value - need to reset the config */
- if (cdev->config)
- reset_config(cdev);
- result = 0;
- }
-
- INFO(cdev, "%s config #%d: %s\n",
- usb_speed_string(gadget->speed),
- number, c ? c->label : "unconfigured");
-
- if (!c)
- goto done;
-
- cdev->config = c;
-
- /* Initialize all interfaces by setting them to altsetting zero. */
- for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
- struct usb_function *f = c->interface[tmp];
- struct usb_descriptor_header **descriptors;
-
- if (!f)
- break;
-
- /*
- * Record which endpoints are used by the function. This is used
- * to dispatch control requests targeted at that endpoint to the
- * function's setup callback instead of the current
- * configuration's setup callback.
- */
- switch (gadget->speed) {
- case USB_SPEED_SUPER:
- descriptors = f->ss_descriptors;
- break;
- case USB_SPEED_HIGH:
- descriptors = f->hs_descriptors;
- break;
- default:
- descriptors = f->descriptors;
- }
-
- for (; *descriptors; ++descriptors) {
- struct usb_endpoint_descriptor *ep;
- int addr;
-
- if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
- continue;
-
- ep = (struct usb_endpoint_descriptor *)*descriptors;
- addr = ((ep->bEndpointAddress & 0x80) >> 3)
- | (ep->bEndpointAddress & 0x0f);
- set_bit(addr, f->endpoints);
- }
-
- result = f->set_alt(f, tmp, 0);
- if (result < 0) {
- DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n",
- tmp, f->name, f, result);
-
- reset_config(cdev);
- goto done;
- }
-
- if (result == USB_GADGET_DELAYED_STATUS) {
- DBG(cdev,
- "%s: interface %d (%s) requested delayed status\n",
- __func__, tmp, f->name);
- cdev->delayed_status++;
- DBG(cdev, "delayed_status count %d\n",
- cdev->delayed_status);
- }
- }
-
- /* when we return, be sure our power usage is valid */
- power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
-done:
- usb_gadget_vbus_draw(gadget, power);
- if (result >= 0 && cdev->delayed_status)
- result = USB_GADGET_DELAYED_STATUS;
- return result;
-}
-
-/**
- * usb_add_config() - add a configuration to a device.
- * @cdev: wraps the USB gadget
- * @config: the configuration, with bConfigurationValue assigned
- * @bind: the configuration's bind function
- * Context: single threaded during gadget setup
- *
- * One of the main tasks of a composite @bind() routine is to
- * add each of the configurations it supports, using this routine.
- *
- * This function returns the value of the configuration's @bind(), which
- * is zero for success else a negative errno value. Binding configurations
- * assigns global resources including string IDs, and per-configuration
- * resources such as interface IDs and endpoints.
- */
-int usb_add_config(struct usb_composite_dev *cdev,
- struct usb_configuration *config,
- int (*bind)(struct usb_configuration *))
-{
- int status = -EINVAL;
- struct usb_configuration *c;
-
- DBG(cdev, "adding config #%u '%s'/%p\n",
- config->bConfigurationValue,
- config->label, config);
-
- if (!config->bConfigurationValue || !bind)
- goto done;
-
- /* Prevent duplicate configuration identifiers */
- list_for_each_entry(c, &cdev->configs, list) {
- if (c->bConfigurationValue == config->bConfigurationValue) {
- status = -EBUSY;
- goto done;
- }
- }
-
- config->cdev = cdev;
- list_add_tail(&config->list, &cdev->configs);
-
- INIT_LIST_HEAD(&config->functions);
- config->next_interface_id = 0;
- memset(config->interface, 0, sizeof(config->interface));
-
- status = bind(config);
- if (status < 0) {
- while (!list_empty(&config->functions)) {
- struct usb_function *f;
-
- f = list_first_entry(&config->functions,
- struct usb_function, list);
- list_del(&f->list);
- if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n",
- f->name, f);
- f->unbind(config, f);
- /* may free memory for "f" */
- }
- }
- list_del(&config->list);
- config->cdev = NULL;
- } else {
- unsigned i;
-
- DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
- config->bConfigurationValue, config,
- config->superspeed ? " super" : "",
- config->highspeed ? " high" : "",
- config->fullspeed
- ? (gadget_is_dualspeed(cdev->gadget)
- ? " full"
- : " full/low")
- : "");
-
- for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
- struct usb_function *f = config->interface[i];
-
- if (!f)
- continue;
- DBG(cdev, " interface %d = %s/%p\n",
- i, f->name, f);
- }
- }
-
- /* set_alt(), or next bind(), sets up
- * ep->driver_data as needed.
- */
- usb_ep_autoconfig_reset(cdev->gadget);
-
-done:
- if (status)
- DBG(cdev, "added config '%s'/%u --> %d\n", config->label,
- config->bConfigurationValue, status);
- return status;
-}
-
-static void remove_config(struct usb_composite_dev *cdev,
- struct usb_configuration *config)
-{
- while (!list_empty(&config->functions)) {
- struct usb_function *f;
-
- f = list_first_entry(&config->functions,
- struct usb_function, list);
- list_del(&f->list);
- if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
- f->unbind(config, f);
- /* may free memory for "f" */
- }
- }
- list_del(&config->list);
- if (config->unbind) {
- DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
- config->unbind(config);
- /* may free memory for "c" */
- }
-}
-
-/**
- * usb_remove_config() - remove a configuration from a device.
- * @cdev: wraps the USB gadget
- * @config: the configuration
- *
- * Drivers must call usb_gadget_disconnect before calling this function
- * to disconnect the device from the host and make sure the host will not
- * try to enumerate the device while we are changing the config list.
- */
-void usb_remove_config(struct usb_composite_dev *cdev,
- struct usb_configuration *config)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cdev->lock, flags);
-
- if (cdev->config == config)
- reset_config(cdev);
-
- spin_unlock_irqrestore(&cdev->lock, flags);
-
- remove_config(cdev, config);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* We support strings in multiple languages ... string descriptor zero
- * says which languages are supported. The typical case will be that
- * only one language (probably English) is used, with I18N handled on
- * the host side.
- */
-
-static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
-{
- const struct usb_gadget_strings *s;
- __le16 language;
- __le16 *tmp;
-
- while (*sp) {
- s = *sp;
- language = cpu_to_le16(s->language);
- for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) {
- if (*tmp == language)
- goto repeat;
- }
- *tmp++ = language;
-repeat:
- sp++;
- }
-}
-
-static int lookup_string(
- struct usb_gadget_strings **sp,
- void *buf,
- u16 language,
- int id
-)
-{
- struct usb_gadget_strings *s;
- int value;
-
- while (*sp) {
- s = *sp++;
- if (s->language != language)
- continue;
- value = usb_gadget_get_string(s, id, buf);
- if (value > 0)
- return value;
- }
- return -EINVAL;
-}
-
-static int get_string(struct usb_composite_dev *cdev,
- void *buf, u16 language, int id)
-{
- struct usb_configuration *c;
- struct usb_function *f;
- int len;
- const char *str;
-
- /* Yes, not only is USB's I18N support probably more than most
- * folk will ever care about ... also, it's all supported here.
- * (Except for UTF8 support for Unicode's "Astral Planes".)
- */
-
- /* 0 == report all available language codes */
- if (id == 0) {
- struct usb_string_descriptor *s = buf;
- struct usb_gadget_strings **sp;
-
- memset(s, 0, 256);
- s->bDescriptorType = USB_DT_STRING;
-
- sp = composite->strings;
- if (sp)
- collect_langs(sp, s->wData);
-
- list_for_each_entry(c, &cdev->configs, list) {
- sp = c->strings;
- if (sp)
- collect_langs(sp, s->wData);
-
- list_for_each_entry(f, &c->functions, list) {
- sp = f->strings;
- if (sp)
- collect_langs(sp, s->wData);
- }
- }
-
- for (len = 0; len <= 126 && s->wData[len]; len++)
- continue;
- if (!len)
- return -EINVAL;
-
- s->bLength = 2 * (len + 1);
- return s->bLength;
- }
-
- /* Otherwise, look up and return a specified string. First
- * check if the string has not been overridden.
- */
- if (cdev->manufacturer_override == id)
- str = iManufacturer ?: composite->iManufacturer ?:
- composite_manufacturer;
- else if (cdev->product_override == id)
- str = iProduct ?: composite->iProduct;
- else if (cdev->serial_override == id)
- str = iSerialNumber ?: composite->iSerialNumber;
- else
- str = NULL;
- if (str) {
- struct usb_gadget_strings strings = {
- .language = language,
- .strings = &(struct usb_string) { 0xff, str }
- };
- return usb_gadget_get_string(&strings, 0xff, buf);
- }
-
- /* String IDs are device-scoped, so we look up each string
- * table we're told about. These lookups are infrequent;
- * simpler-is-better here.
- */
- if (composite->strings) {
- len = lookup_string(composite->strings, buf, language, id);
- if (len > 0)
- return len;
- }
- list_for_each_entry(c, &cdev->configs, list) {
- if (c->strings) {
- len = lookup_string(c->strings, buf, language, id);
- if (len > 0)
- return len;
- }
- list_for_each_entry(f, &c->functions, list) {
- if (!f->strings)
- continue;
- len = lookup_string(f->strings, buf, language, id);
- if (len > 0)
- return len;
- }
- }
- return -EINVAL;
-}
-
-/**
- * usb_string_id() - allocate an unused string ID
- * @cdev: the device whose string descriptor IDs are being allocated
- * Context: single threaded during gadget setup
- *
- * @usb_string_id() is called from bind() callbacks to allocate
- * string IDs. Drivers for functions, configurations, or gadgets will
- * then store that ID in the appropriate descriptors and string table.
- *
- * All string identifier should be allocated using this,
- * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
- * that for example different functions don't wrongly assign different
- * meanings to the same identifier.
- */
-int usb_string_id(struct usb_composite_dev *cdev)
-{
- if (cdev->next_string_id < 254) {
- /* string id 0 is reserved by USB spec for list of
- * supported languages */
- /* 255 reserved as well? -- mina86 */
- cdev->next_string_id++;
- return cdev->next_string_id;
- }
- return -ENODEV;
-}
-
-/**
- * usb_string_ids() - allocate unused string IDs in batch
- * @cdev: the device whose string descriptor IDs are being allocated
- * @str: an array of usb_string objects to assign numbers to
- * Context: single threaded during gadget setup
- *
- * @usb_string_ids() is called from bind() callbacks to allocate
- * string IDs. Drivers for functions, configurations, or gadgets will
- * then copy IDs from the string table to the appropriate descriptors
- * and string table for other languages.
- *
- * All string identifier should be allocated using this,
- * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
- * example different functions don't wrongly assign different meanings
- * to the same identifier.
- */
-int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
-{
- int next = cdev->next_string_id;
-
- for (; str->s; ++str) {
- if (unlikely(next >= 254))
- return -ENODEV;
- str->id = ++next;
- }
-
- cdev->next_string_id = next;
-
- return 0;
-}
-
-/**
- * usb_string_ids_n() - allocate unused string IDs in batch
- * @c: the device whose string descriptor IDs are being allocated
- * @n: number of string IDs to allocate
- * Context: single threaded during gadget setup
- *
- * Returns the first requested ID. This ID and next @n-1 IDs are now
- * valid IDs. At least provided that @n is non-zero because if it
- * is, returns last requested ID which is now very useful information.
- *
- * @usb_string_ids_n() is called from bind() callbacks to allocate
- * string IDs. Drivers for functions, configurations, or gadgets will
- * then store that ID in the appropriate descriptors and string table.
- *
- * All string identifier should be allocated using this,
- * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
- * example different functions don't wrongly assign different meanings
- * to the same identifier.
- */
-int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
-{
- unsigned next = c->next_string_id;
- if (unlikely(n > 254 || (unsigned)next + n > 254))
- return -ENODEV;
- c->next_string_id += n;
- return next + 1;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
- if (req->status || req->actual != req->length)
- DBG((struct usb_composite_dev *) ep->driver_data,
- "setup complete --> %d, %d/%d\n",
- req->status, req->actual, req->length);
-}
-
-/*
- * The setup() callback implements all the ep0 functionality that's
- * not handled lower down, in hardware or the hardware driver(like
- * device and endpoint feature flags, and their status). It's all
- * housekeeping for the gadget function we're implementing. Most of
- * the work is in config and function specific setup.
- */
-static int
-composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
-{
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- struct usb_request *req = cdev->req;
- int value = -EOPNOTSUPP;
- int status = 0;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u8 intf = w_index & 0xFF;
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
- struct usb_function *f = NULL;
- u8 endp;
-
- /* partial re-init of the response message; the function or the
- * gadget might need to intercept e.g. a control-OUT completion
- * when we delegate to it.
- */
- req->zero = 0;
- req->complete = composite_setup_complete;
- req->length = 0;
- gadget->ep0->driver_data = cdev;
-
- switch (ctrl->bRequest) {
-
- /* we handle all standard USB descriptors */
- case USB_REQ_GET_DESCRIPTOR:
- if (ctrl->bRequestType != USB_DIR_IN)
- goto unknown;
- switch (w_value >> 8) {
-
- case USB_DT_DEVICE:
- cdev->desc.bNumConfigurations =
- count_configs(cdev, USB_DT_DEVICE);
- cdev->desc.bMaxPacketSize0 =
- cdev->gadget->ep0->maxpacket;
- if (gadget_is_superspeed(gadget)) {
- if (gadget->speed >= USB_SPEED_SUPER) {
- cdev->desc.bcdUSB = cpu_to_le16(0x0300);
- cdev->desc.bMaxPacketSize0 = 9;
- } else {
- cdev->desc.bcdUSB = cpu_to_le16(0x0210);
- }
- }
-
- value = min(w_length, (u16) sizeof cdev->desc);
- memcpy(req->buf, &cdev->desc, value);
- break;
- case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget) ||
- gadget->speed >= USB_SPEED_SUPER)
- break;
- device_qual(cdev);
- value = min_t(int, w_length,
- sizeof(struct usb_qualifier_descriptor));
- break;
- case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget) ||
- gadget->speed >= USB_SPEED_SUPER)
- break;
- /* FALLTHROUGH */
- case USB_DT_CONFIG:
- value = config_desc(cdev, w_value);
- if (value >= 0)
- value = min(w_length, (u16) value);
- break;
- case USB_DT_STRING:
- value = get_string(cdev, req->buf,
- w_index, w_value & 0xff);
- if (value >= 0)
- value = min(w_length, (u16) value);
- break;
- case USB_DT_BOS:
- if (gadget_is_superspeed(gadget)) {
- value = bos_desc(cdev);
- value = min(w_length, (u16) value);
- }
- break;
- }
- break;
-
- /* any number of configs can work */
- case USB_REQ_SET_CONFIGURATION:
- if (ctrl->bRequestType != 0)
- goto unknown;
- if (gadget_is_otg(gadget)) {
- if (gadget->a_hnp_support)
- DBG(cdev, "HNP available\n");
- else if (gadget->a_alt_hnp_support)
- DBG(cdev, "HNP on another port\n");
- else
- VDBG(cdev, "HNP inactive\n");
- }
- spin_lock(&cdev->lock);
- value = set_config(cdev, ctrl, w_value);
- spin_unlock(&cdev->lock);
- break;
- case USB_REQ_GET_CONFIGURATION:
- if (ctrl->bRequestType != USB_DIR_IN)
- goto unknown;
- if (cdev->config)
- *(u8 *)req->buf = cdev->config->bConfigurationValue;
- else
- *(u8 *)req->buf = 0;
- value = min(w_length, (u16) 1);
- break;
-
- /* function drivers must handle get/set altsetting; if there's
- * no get() method, we know only altsetting zero works.
- */
- case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE)
- goto unknown;
- if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
- if (w_value && !f->set_alt)
- break;
- value = f->set_alt(f, w_index, w_value);
- if (value == USB_GADGET_DELAYED_STATUS) {
- DBG(cdev,
- "%s: interface %d (%s) requested delayed status\n",
- __func__, intf, f->name);
- cdev->delayed_status++;
- DBG(cdev, "delayed_status count %d\n",
- cdev->delayed_status);
- }
- break;
- case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
- goto unknown;
- if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
- /* lots of interfaces only need altsetting zero... */
- value = f->get_alt ? f->get_alt(f, w_index) : 0;
- if (value < 0)
- break;
- *((u8 *)req->buf) = value;
- value = min(w_length, (u16) 1);
- break;
-
- /*
- * USB 3.0 additions:
- * Function driver should handle get_status request. If such cb
- * wasn't supplied we respond with default value = 0
- * Note: function driver should supply such cb only for the first
- * interface of the function
- */
- case USB_REQ_GET_STATUS:
- if (!gadget_is_superspeed(gadget))
- goto unknown;
- if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
- goto unknown;
- value = 2; /* This is the length of the get_status reply */
- put_unaligned_le16(0, req->buf);
- if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
- status = f->get_status ? f->get_status(f) : 0;
- if (status < 0)
- break;
- put_unaligned_le16(status & 0x0000ffff, req->buf);
- break;
- /*
- * Function drivers should handle SetFeature/ClearFeature
- * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
- * only for the first interface of the function
- */
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- if (!gadget_is_superspeed(gadget))
- goto unknown;
- if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
- goto unknown;
- switch (w_value) {
- case USB_INTRF_FUNC_SUSPEND:
- if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- if (!f)
- break;
- value = 0;
- if (f->func_suspend)
- value = f->func_suspend(f, w_index >> 8);
- if (value < 0) {
- ERROR(cdev,
- "func_suspend() returned error %d\n",
- value);
- value = 0;
- }
- break;
- }
- break;
- default:
-unknown:
- VDBG(cdev,
- "non-core control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
-
- /* functions always handle their interfaces and endpoints...
- * punt other recipients (other, WUSB, ...) to the current
- * configuration code.
- *
- * REVISIT it could make sense to let the composite device
- * take such requests too, if that's ever needed: to work
- * in config 0, etc.
- */
- switch (ctrl->bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_INTERFACE:
- if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
- break;
- f = cdev->config->interface[intf];
- break;
-
- case USB_RECIP_ENDPOINT:
- endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
- list_for_each_entry(f, &cdev->config->functions, list) {
- if (test_bit(endp, f->endpoints))
- break;
- }
- if (&f->list == &cdev->config->functions)
- f = NULL;
- break;
- }
-
- if (f && f->setup)
- value = f->setup(f, ctrl);
- else {
- struct usb_configuration *c;
-
- c = cdev->config;
- if (c && c->setup)
- value = c->setup(c, ctrl);
- }
-
- goto done;
- }
-
- /* respond with data transfer before status phase? */
- if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
- req->length = value;
- req->zero = value < w_length;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(gadget->ep0, req);
- }
- } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
- WARN(cdev,
- "%s: Delayed status not supported for w_length != 0",
- __func__);
- }
-
-done:
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
-static void composite_disconnect(struct usb_gadget *gadget)
-{
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- unsigned long flags;
-
- /* REVISIT: should we have config and device level
- * disconnect callbacks?
- */
- spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->config)
- reset_config(cdev);
- if (composite->disconnect)
- composite->disconnect(cdev);
- spin_unlock_irqrestore(&cdev->lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static ssize_t composite_show_suspended(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct usb_gadget *gadget = dev_to_usb_gadget(dev);
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
-
- return sprintf(buf, "%d\n", cdev->suspended);
-}
-
-static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
-
-static void
-composite_unbind(struct usb_gadget *gadget)
-{
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
-
- /* composite_disconnect() must already have been called
- * by the underlying peripheral controller driver!
- * so there's no i/o concurrency that could affect the
- * state protected by cdev->lock.
- */
- WARN_ON(cdev->config);
-
- while (!list_empty(&cdev->configs)) {
- struct usb_configuration *c;
- c = list_first_entry(&cdev->configs,
- struct usb_configuration, list);
- remove_config(cdev, c);
- }
- if (composite->unbind)
- composite->unbind(cdev);
-
- if (cdev->req) {
- kfree(cdev->req->buf);
- usb_ep_free_request(gadget->ep0, cdev->req);
- }
- device_remove_file(&gadget->dev, &dev_attr_suspended);
- kfree(cdev);
- set_gadget_data(gadget, NULL);
- composite = NULL;
-}
-
-static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
-{
- if (!*desc) {
- int ret = usb_string_id(cdev);
- if (unlikely(ret < 0))
- WARNING(cdev, "failed to override string ID\n");
- else
- *desc = ret;
- }
-
- return *desc;
-}
-
-static int composite_bind(struct usb_gadget *gadget,
- struct usb_gadget_driver *driver)
-{
- struct usb_composite_dev *cdev;
- int status = -ENOMEM;
-
- cdev = kzalloc(sizeof *cdev, GFP_KERNEL);
- if (!cdev)
- return status;
-
- spin_lock_init(&cdev->lock);
- cdev->gadget = gadget;
- set_gadget_data(gadget, cdev);
- INIT_LIST_HEAD(&cdev->configs);
-
- /* preallocate control response and buffer */
- cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
- if (!cdev->req)
- goto fail;
- cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
- if (!cdev->req->buf)
- goto fail;
- cdev->req->complete = composite_setup_complete;
- gadget->ep0->driver_data = cdev;
-
- cdev->bufsiz = USB_BUFSIZ;
- cdev->driver = composite;
-
- /*
- * As per USB compliance update, a device that is actively drawing
- * more than 100mA from USB must report itself as bus-powered in
- * the GetStatus(DEVICE) call.
- */
- if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
- usb_gadget_set_selfpowered(gadget);
-
- /* interface and string IDs start at zero via kzalloc.
- * we force endpoints to start unassigned; few controller
- * drivers will zero ep->driver_data.
- */
- usb_ep_autoconfig_reset(cdev->gadget);
-
- /* composite gadget needs to assign strings for whole device (like
- * serial number), register function drivers, potentially update
- * power state and consumption, etc
- */
- status = composite->bind(cdev);
- if (status < 0)
- goto fail;
-
- cdev->desc = *composite->dev;
-
- /* standardized runtime overrides for device ID data */
- if (idVendor)
- cdev->desc.idVendor = cpu_to_le16(idVendor);
- else
- idVendor = le16_to_cpu(cdev->desc.idVendor);
- if (idProduct)
- cdev->desc.idProduct = cpu_to_le16(idProduct);
- else
- idProduct = le16_to_cpu(cdev->desc.idProduct);
- if (bcdDevice)
- cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
- else
- bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
-
- /* string overrides */
- if (iManufacturer || !cdev->desc.iManufacturer) {
- if (!iManufacturer && !composite->iManufacturer &&
- !*composite_manufacturer)
- snprintf(composite_manufacturer,
- sizeof composite_manufacturer,
- "%s %s with %s",
- init_utsname()->sysname,
- init_utsname()->release,
- gadget->name);
-
- cdev->manufacturer_override =
- override_id(cdev, &cdev->desc.iManufacturer);
- }
-
- if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
- cdev->product_override =
- override_id(cdev, &cdev->desc.iProduct);
-
- if (iSerialNumber ||
- (!cdev->desc.iSerialNumber && composite->iSerialNumber))
- cdev->serial_override =
- override_id(cdev, &cdev->desc.iSerialNumber);
-
- /* has userspace failed to provide a serial number? */
- if (composite->needs_serial && !cdev->desc.iSerialNumber)
- WARNING(cdev, "userspace failed to provide iSerialNumber\n");
-
- /* finish up */
- status = device_create_file(&gadget->dev, &dev_attr_suspended);
- if (status)
- goto fail;
-
- INFO(cdev, "%s ready\n", composite->name);
- return 0;
-
-fail:
- composite_unbind(gadget);
- return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void
-composite_suspend(struct usb_gadget *gadget)
-{
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- struct usb_function *f;
-
- /* REVISIT: should we have config level
- * suspend/resume callbacks?
- */
- DBG(cdev, "suspend\n");
- if (cdev->config) {
- list_for_each_entry(f, &cdev->config->functions, list) {
- if (f->suspend)
- f->suspend(f);
- }
- }
- if (composite->suspend)
- composite->suspend(cdev);
-
- cdev->suspended = 1;
-
- usb_gadget_vbus_draw(gadget, 2);
-}
-
-static void
-composite_resume(struct usb_gadget *gadget)
-{
- struct usb_composite_dev *cdev = get_gadget_data(gadget);
- struct usb_function *f;
- u8 maxpower;
-
- /* REVISIT: should we have config level
- * suspend/resume callbacks?
- */
- DBG(cdev, "resume\n");
- if (composite->resume)
- composite->resume(cdev);
- if (cdev->config) {
- list_for_each_entry(f, &cdev->config->functions, list) {
- if (f->resume)
- f->resume(f);
- }
-
- maxpower = cdev->config->bMaxPower;
-
- usb_gadget_vbus_draw(gadget, maxpower ?
- (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW);
- }
-
- cdev->suspended = 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_gadget_driver composite_driver = {
- .bind = composite_bind,
- .unbind = composite_unbind,
-
- .setup = composite_setup,
- .disconnect = composite_disconnect,
-
- .suspend = composite_suspend,
- .resume = composite_resume,
-
- .driver = {
- .owner = THIS_MODULE,
- },
-};
-
-/**
- * usb_composite_probe() - register a composite driver
- * @driver: the driver to register
- * @bind: the callback used to allocate resources that are shared across the
- * whole device, such as string IDs, and add its configurations using
- * @usb_add_config(). This may fail by returning a negative errno
- * value; it should return zero on successful initialization.
- * Context: single threaded during gadget setup
- *
- * This function is used to register drivers using the composite driver
- * framework. The return value is zero, or a negative errno value.
- * Those values normally come from the driver's @bind method, which does
- * all the work of setting up the driver to match the hardware.
- *
- * On successful return, the gadget is ready to respond to requests from
- * the host, unless one of its components invokes usb_gadget_disconnect()
- * while it was binding. That would usually be done in order to wait for
- * some userspace participation.
- */
-int usb_composite_probe(struct usb_composite_driver *driver)
-{
- if (!driver || !driver->dev || composite || !driver->bind)
- return -EINVAL;
-
- if (!driver->name)
- driver->name = "composite";
- if (!driver->iProduct)
- driver->iProduct = driver->name;
- composite_driver.function = (char *) driver->name;
- composite_driver.driver.name = driver->name;
- composite_driver.max_speed = driver->max_speed;
- composite = driver;
-
- return usb_gadget_probe_driver(&composite_driver);
-}
-
-/**
- * usb_composite_unregister() - unregister a composite driver
- * @driver: the driver to unregister
- *
- * This function is used to unregister drivers using the composite
- * driver framework.
- */
-void usb_composite_unregister(struct usb_composite_driver *driver)
-{
- if (composite != driver)
- return;
- usb_gadget_unregister_driver(&composite_driver);
-}
-
-/**
- * usb_composite_setup_continue() - Continue with the control transfer
- * @cdev: the composite device who's control transfer was kept waiting
- *
- * This function must be called by the USB function driver to continue
- * with the control transfer's data/status stage in case it had requested to
- * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
- * can request the composite framework to delay the setup request's data/status
- * stages by returning USB_GADGET_DELAYED_STATUS.
- */
-void usb_composite_setup_continue(struct usb_composite_dev *cdev)
-{
- int value;
- struct usb_request *req = cdev->req;
- unsigned long flags;
-
- DBG(cdev, "%s\n", __func__);
- spin_lock_irqsave(&cdev->lock, flags);
-
- if (cdev->delayed_status == 0) {
- WARN(cdev, "%s: Unexpected call\n", __func__);
-
- } else if (--cdev->delayed_status == 0) {
- DBG(cdev, "%s: Completing delayed status\n", __func__);
- req->length = 0;
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(cdev, "ep_queue --> %d\n", value);
- req->status = 0;
- composite_setup_complete(cdev->gadget->ep0, req);
- }
- }
-
- spin_unlock_irqrestore(&cdev->lock, flags);
-}
-
diff --git a/drivers/staging/ccg/composite.h b/drivers/staging/ccg/composite.h
deleted file mode 100644
index 19a5adf18bf4..000000000000
--- a/drivers/staging/ccg/composite.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * composite.h -- framework for usb gadgets which are composite devices
- *
- * Copyright (C) 2006-2008 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef __LINUX_USB_COMPOSITE_H
-#define __LINUX_USB_COMPOSITE_H
-
-/*
- * This framework is an optional layer on top of the USB Gadget interface,
- * making it easier to build (a) Composite devices, supporting multiple
- * functions within any single configuration, and (b) Multi-configuration
- * devices, also supporting multiple functions but without necessarily
- * having more than one function per configuration.
- *
- * Example: a device with a single configuration supporting both network
- * link and mass storage functions is a composite device. Those functions
- * might alternatively be packaged in individual configurations, but in
- * the composite model the host can use both functions at the same time.
- */
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-/*
- * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
- * wish to delay the data/status stages of the control transfer till they
- * are ready. The control transfer will then be kept from completing till
- * all the function drivers that requested for USB_GADGET_DELAYED_STAUS
- * invoke usb_composite_setup_continue().
- */
-#define USB_GADGET_DELAYED_STATUS 0x7fff /* Impossibly large value */
-
-struct usb_configuration;
-
-/**
- * struct usb_function - describes one function of a configuration
- * @name: For diagnostics, identifies the function.
- * @strings: tables of strings, keyed by identifiers assigned during bind()
- * and by language IDs provided in control requests
- * @descriptors: Table of full (or low) speed descriptors, using interface and
- * string identifiers assigned during @bind(). If this pointer is null,
- * the function will not be available at full speed (or at low speed).
- * @hs_descriptors: Table of high speed descriptors, using interface and
- * string identifiers assigned during @bind(). If this pointer is null,
- * the function will not be available at high speed.
- * @ss_descriptors: Table of super speed descriptors, using interface and
- * string identifiers assigned during @bind(). If this
- * pointer is null after initiation, the function will not
- * be available at super speed.
- * @config: assigned when @usb_add_function() is called; this is the
- * configuration with which this function is associated.
- * @bind: Before the gadget can register, all of its functions bind() to the
- * available resources including string and interface identifiers used
- * in interface or class descriptors; endpoints; I/O buffers; and so on.
- * @unbind: Reverses @bind; called as a side effect of unregistering the
- * driver which added this function.
- * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
- * initialize usb_ep.driver data at this time (when it is used).
- * Note that setting an interface to its current altsetting resets
- * interface state, and that all interfaces have a disabled state.
- * @get_alt: Returns the active altsetting. If this is not provided,
- * then only altsetting zero is supported.
- * @disable: (REQUIRED) Indicates the function should be disabled. Reasons
- * include host resetting or reconfiguring the gadget, and disconnection.
- * @setup: Used for interface-specific control requests.
- * @suspend: Notifies functions when the host stops sending USB traffic.
- * @resume: Notifies functions when the host restarts USB traffic.
- * @get_status: Returns function status as a reply to
- * GetStatus() request when the recepient is Interface.
- * @func_suspend: callback to be called when
- * SetFeature(FUNCTION_SUSPEND) is reseived
- *
- * A single USB function uses one or more interfaces, and should in most
- * cases support operation at both full and high speeds. Each function is
- * associated by @usb_add_function() with a one configuration; that function
- * causes @bind() to be called so resources can be allocated as part of
- * setting up a gadget driver. Those resources include endpoints, which
- * should be allocated using @usb_ep_autoconfig().
- *
- * To support dual speed operation, a function driver provides descriptors
- * for both high and full speed operation. Except in rare cases that don't
- * involve bulk endpoints, each speed needs different endpoint descriptors.
- *
- * Function drivers choose their own strategies for managing instance data.
- * The simplest strategy just declares it "static', which means the function
- * can only be activated once. If the function needs to be exposed in more
- * than one configuration at a given speed, it needs to support multiple
- * usb_function structures (one for each configuration).
- *
- * A more complex strategy might encapsulate a @usb_function structure inside
- * a driver-specific instance structure to allows multiple activations. An
- * example of multiple activations might be a CDC ACM function that supports
- * two or more distinct instances within the same configuration, providing
- * several independent logical data links to a USB host.
- */
-struct usb_function {
- const char *name;
- struct usb_gadget_strings **strings;
- struct usb_descriptor_header **descriptors;
- struct usb_descriptor_header **hs_descriptors;
- struct usb_descriptor_header **ss_descriptors;
-
- struct usb_configuration *config;
-
- /* REVISIT: bind() functions can be marked __init, which
- * makes trouble for section mismatch analysis. See if
- * we can't restructure things to avoid mismatching.
- * Related: unbind() may kfree() but bind() won't...
- */
-
- /* configuration management: bind/unbind */
- int (*bind)(struct usb_configuration *,
- struct usb_function *);
- void (*unbind)(struct usb_configuration *,
- struct usb_function *);
-
- /* runtime state management */
- int (*set_alt)(struct usb_function *,
- unsigned interface, unsigned alt);
- int (*get_alt)(struct usb_function *,
- unsigned interface);
- void (*disable)(struct usb_function *);
- int (*setup)(struct usb_function *,
- const struct usb_ctrlrequest *);
- void (*suspend)(struct usb_function *);
- void (*resume)(struct usb_function *);
-
- /* USB 3.0 additions */
- int (*get_status)(struct usb_function *);
- int (*func_suspend)(struct usb_function *,
- u8 suspend_opt);
- /* private: */
- /* internals */
- struct list_head list;
- DECLARE_BITMAP(endpoints, 32);
-};
-
-int usb_add_function(struct usb_configuration *, struct usb_function *);
-
-int usb_function_deactivate(struct usb_function *);
-int usb_function_activate(struct usb_function *);
-
-int usb_interface_id(struct usb_configuration *, struct usb_function *);
-
-int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
- struct usb_ep *_ep);
-
-#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
-
-/**
- * struct usb_configuration - represents one gadget configuration
- * @label: For diagnostics, describes the configuration.
- * @strings: Tables of strings, keyed by identifiers assigned during @bind()
- * and by language IDs provided in control requests.
- * @descriptors: Table of descriptors preceding all function descriptors.
- * Examples include OTG and vendor-specific descriptors.
- * @unbind: Reverses @bind; called as a side effect of unregistering the
- * driver which added this configuration.
- * @setup: Used to delegate control requests that aren't handled by standard
- * device infrastructure or directed at a specific interface.
- * @bConfigurationValue: Copied into configuration descriptor.
- * @iConfiguration: Copied into configuration descriptor.
- * @bmAttributes: Copied into configuration descriptor.
- * @bMaxPower: Copied into configuration descriptor.
- * @cdev: assigned by @usb_add_config() before calling @bind(); this is
- * the device associated with this configuration.
- *
- * Configurations are building blocks for gadget drivers structured around
- * function drivers. Simple USB gadgets require only one function and one
- * configuration, and handle dual-speed hardware by always providing the same
- * functionality. Slightly more complex gadgets may have more than one
- * single-function configuration at a given speed; or have configurations
- * that only work at one speed.
- *
- * Composite devices are, by definition, ones with configurations which
- * include more than one function.
- *
- * The lifecycle of a usb_configuration includes allocation, initialization
- * of the fields described above, and calling @usb_add_config() to set up
- * internal data and bind it to a specific device. The configuration's
- * @bind() method is then used to initialize all the functions and then
- * call @usb_add_function() for them.
- *
- * Those functions would normally be independent of each other, but that's
- * not mandatory. CDC WMC devices are an example where functions often
- * depend on other functions, with some functions subsidiary to others.
- * Such interdependency may be managed in any way, so long as all of the
- * descriptors complete by the time the composite driver returns from
- * its bind() routine.
- */
-struct usb_configuration {
- const char *label;
- struct usb_gadget_strings **strings;
- const struct usb_descriptor_header **descriptors;
-
- /* REVISIT: bind() functions can be marked __init, which
- * makes trouble for section mismatch analysis. See if
- * we can't restructure things to avoid mismatching...
- */
-
- /* configuration management: unbind/setup */
- void (*unbind)(struct usb_configuration *);
- int (*setup)(struct usb_configuration *,
- const struct usb_ctrlrequest *);
-
- /* fields in the config descriptor */
- u8 bConfigurationValue;
- u8 iConfiguration;
- u8 bmAttributes;
- u8 bMaxPower;
-
- struct usb_composite_dev *cdev;
-
- /* private: */
- /* internals */
- struct list_head list;
- struct list_head functions;
- u8 next_interface_id;
- unsigned superspeed:1;
- unsigned highspeed:1;
- unsigned fullspeed:1;
- struct usb_function *interface[MAX_CONFIG_INTERFACES];
-};
-
-int usb_add_config(struct usb_composite_dev *,
- struct usb_configuration *,
- int (*)(struct usb_configuration *));
-
-void usb_remove_config(struct usb_composite_dev *,
- struct usb_configuration *);
-
-/**
- * struct usb_composite_driver - groups configurations into a gadget
- * @name: For diagnostics, identifies the driver.
- * @iProduct: Used as iProduct override if @dev->iProduct is not set.
- * If NULL value of @name is taken.
- * @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
- * not set. If NULL a default "<system> <release> with <udc>" value
- * will be used.
- * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
- * not set.
- * @dev: Template descriptor for the device, including default device
- * identifiers.
- * @strings: tables of strings, keyed by identifiers assigned during @bind
- * and language IDs provided in control requests
- * @max_speed: Highest speed the driver supports.
- * @needs_serial: set to 1 if the gadget needs userspace to provide
- * a serial number. If one is not provided, warning will be printed.
- * @bind: (REQUIRED) Used to allocate resources that are shared across the
- * whole device, such as string IDs, and add its configurations using
- * @usb_add_config(). This may fail by returning a negative errno
- * value; it should return zero on successful initialization.
- * @unbind: Reverses @bind; called as a side effect of unregistering
- * this driver.
- * @disconnect: optional driver disconnect method
- * @suspend: Notifies when the host stops sending USB traffic,
- * after function notifications
- * @resume: Notifies configuration when the host restarts USB traffic,
- * before function notifications
- *
- * Devices default to reporting self powered operation. Devices which rely
- * on bus powered operation should report this in their @bind method.
- *
- * Before returning from @bind, various fields in the template descriptor
- * may be overridden. These include the idVendor/idProduct/bcdDevice values
- * normally to bind the appropriate host side driver, and the three strings
- * (iManufacturer, iProduct, iSerialNumber) normally used to provide user
- * meaningful device identifiers. (The strings will not be defined unless
- * they are defined in @dev and @strings.) The correct ep0 maxpacket size
- * is also reported, as defined by the underlying controller driver.
- */
-struct usb_composite_driver {
- const char *name;
- const char *iProduct;
- const char *iManufacturer;
- const char *iSerialNumber;
- const struct usb_device_descriptor *dev;
- struct usb_gadget_strings **strings;
- enum usb_device_speed max_speed;
- unsigned needs_serial:1;
-
- int (*bind)(struct usb_composite_dev *cdev);
- int (*unbind)(struct usb_composite_dev *);
-
- void (*disconnect)(struct usb_composite_dev *);
-
- /* global suspend hooks */
- void (*suspend)(struct usb_composite_dev *);
- void (*resume)(struct usb_composite_dev *);
-};
-
-extern int usb_composite_probe(struct usb_composite_driver *driver);
-extern void usb_composite_unregister(struct usb_composite_driver *driver);
-extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
-
-
-/**
- * struct usb_composite_device - represents one composite usb gadget
- * @gadget: read-only, abstracts the gadget's usb peripheral controller
- * @req: used for control responses; buffer is pre-allocated
- * @bufsiz: size of buffer pre-allocated in @req
- * @config: the currently active configuration
- *
- * One of these devices is allocated and initialized before the
- * associated device driver's bind() is called.
- *
- * OPEN ISSUE: it appears that some WUSB devices will need to be
- * built by combining a normal (wired) gadget with a wireless one.
- * This revision of the gadget framework should probably try to make
- * sure doing that won't hurt too much.
- *
- * One notion for how to handle Wireless USB devices involves:
- * (a) a second gadget here, discovery mechanism TBD, but likely
- * needing separate "register/unregister WUSB gadget" calls;
- * (b) updates to usb_gadget to include flags "is it wireless",
- * "is it wired", plus (presumably in a wrapper structure)
- * bandgroup and PHY info;
- * (c) presumably a wireless_ep wrapping a usb_ep, and reporting
- * wireless-specific parameters like maxburst and maxsequence;
- * (d) configurations that are specific to wireless links;
- * (e) function drivers that understand wireless configs and will
- * support wireless for (additional) function instances;
- * (f) a function to support association setup (like CBAF), not
- * necessarily requiring a wireless adapter;
- * (g) composite device setup that can create one or more wireless
- * configs, including appropriate association setup support;
- * (h) more, TBD.
- */
-struct usb_composite_dev {
- struct usb_gadget *gadget;
- struct usb_request *req;
- unsigned bufsiz;
-
- struct usb_configuration *config;
-
- /* private: */
- /* internals */
- unsigned int suspended:1;
- struct usb_device_descriptor desc;
- struct list_head configs;
- struct usb_composite_driver *driver;
- u8 next_string_id;
- u8 manufacturer_override;
- u8 product_override;
- u8 serial_override;
-
- /* the gadget driver won't enable the data pullup
- * while the deactivation count is nonzero.
- */
- unsigned deactivations;
-
- /* the composite driver won't complete the control transfer's
- * data/status stages till delayed_status is zero.
- */
- int delayed_status;
-
- /* protects deactivations and delayed_status counts*/
- spinlock_t lock;
-};
-
-extern int usb_string_id(struct usb_composite_dev *c);
-extern int usb_string_ids_tab(struct usb_composite_dev *c,
- struct usb_string *str);
-extern int usb_string_ids_n(struct usb_composite_dev *c, unsigned n);
-
-
-/* messaging utils */
-#define DBG(d, fmt, args...) \
- dev_dbg(&(d)->gadget->dev , fmt , ## args)
-#define VDBG(d, fmt, args...) \
- dev_vdbg(&(d)->gadget->dev , fmt , ## args)
-#define ERROR(d, fmt, args...) \
- dev_err(&(d)->gadget->dev , fmt , ## args)
-#define WARNING(d, fmt, args...) \
- dev_warn(&(d)->gadget->dev , fmt , ## args)
-#define INFO(d, fmt, args...) \
- dev_info(&(d)->gadget->dev , fmt , ## args)
-
-#endif /* __LINUX_USB_COMPOSITE_H */
diff --git a/drivers/staging/ccg/config.c b/drivers/staging/ccg/config.c
deleted file mode 100644
index 7542a72ce51a..000000000000
--- a/drivers/staging/ccg/config.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * usb/gadget/config.c -- simplify building config descriptors
- *
- * Copyright (C) 2003 David Brownell
- *
- * 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/errno.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/device.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-
-/**
- * usb_descriptor_fillbuf - fill buffer with descriptors
- * @buf: Buffer to be filled
- * @buflen: Size of buf
- * @src: Array of descriptor pointers, terminated by null pointer.
- *
- * Copies descriptors into the buffer, returning the length or a
- * negative error code if they can't all be copied. Useful when
- * assembling descriptors for an associated set of interfaces used
- * as part of configuring a composite device; or in other cases where
- * sets of descriptors need to be marshaled.
- */
-int
-usb_descriptor_fillbuf(void *buf, unsigned buflen,
- const struct usb_descriptor_header **src)
-{
- u8 *dest = buf;
-
- if (!src)
- return -EINVAL;
-
- /* fill buffer from src[] until null descriptor ptr */
- for (; NULL != *src; src++) {
- unsigned len = (*src)->bLength;
-
- if (len > buflen)
- return -EINVAL;
- memcpy(dest, *src, len);
- buflen -= len;
- dest += len;
- }
- return dest - (u8 *)buf;
-}
-
-
-/**
- * usb_gadget_config_buf - builts a complete configuration descriptor
- * @config: Header for the descriptor, including characteristics such
- * as power requirements and number of interfaces.
- * @desc: Null-terminated vector of pointers to the descriptors (interface,
- * endpoint, etc) defining all functions in this device configuration.
- * @buf: Buffer for the resulting configuration descriptor.
- * @length: Length of buffer. If this is not big enough to hold the
- * entire configuration descriptor, an error code will be returned.
- *
- * This copies descriptors into the response buffer, building a descriptor
- * for that configuration. It returns the buffer length or a negative
- * status code. The config.wTotalLength field is set to match the length
- * of the result, but other descriptor fields (including power usage and
- * interface count) must be set by the caller.
- *
- * Gadget drivers could use this when constructing a config descriptor
- * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the
- * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed.
- */
-int usb_gadget_config_buf(
- const struct usb_config_descriptor *config,
- void *buf,
- unsigned length,
- const struct usb_descriptor_header **desc
-)
-{
- struct usb_config_descriptor *cp = buf;
- int len;
-
- /* config descriptor first */
- if (length < USB_DT_CONFIG_SIZE || !desc)
- return -EINVAL;
- *cp = *config;
-
- /* then interface/endpoint/class/vendor/... */
- len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf,
- length - USB_DT_CONFIG_SIZE, desc);
- if (len < 0)
- return len;
- len += USB_DT_CONFIG_SIZE;
- if (len > 0xffff)
- return -EINVAL;
-
- /* patch up the config descriptor */
- cp->bLength = USB_DT_CONFIG_SIZE;
- cp->bDescriptorType = USB_DT_CONFIG;
- cp->wTotalLength = cpu_to_le16(len);
- cp->bmAttributes |= USB_CONFIG_ATT_ONE;
- return len;
-}
-
-/**
- * usb_copy_descriptors - copy a vector of USB descriptors
- * @src: null-terminated vector to copy
- * Context: initialization code, which may sleep
- *
- * This makes a copy of a vector of USB descriptors. Its primary use
- * is to support usb_function objects which can have multiple copies,
- * each needing different descriptors. Functions may have static
- * tables of descriptors, which are used as templates and customized
- * with identifiers (for interfaces, strings, endpoints, and more)
- * as needed by a given function instance.
- */
-struct usb_descriptor_header **
-usb_copy_descriptors(struct usb_descriptor_header **src)
-{
- struct usb_descriptor_header **tmp;
- unsigned bytes;
- unsigned n_desc;
- void *mem;
- struct usb_descriptor_header **ret;
-
- /* count descriptors and their sizes; then add vector size */
- for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++)
- bytes += (*tmp)->bLength;
- bytes += (n_desc + 1) * sizeof(*tmp);
-
- mem = kmalloc(bytes, GFP_KERNEL);
- if (!mem)
- return NULL;
-
- /* fill in pointers starting at "tmp",
- * to descriptors copied starting at "mem";
- * and return "ret"
- */
- tmp = mem;
- ret = mem;
- mem += (n_desc + 1) * sizeof(*tmp);
- while (*src) {
- memcpy(mem, *src, (*src)->bLength);
- *tmp = mem;
- tmp++;
- mem += (*src)->bLength;
- src++;
- }
- *tmp = NULL;
-
- return ret;
-}
-
diff --git a/drivers/staging/ccg/epautoconf.c b/drivers/staging/ccg/epautoconf.c
deleted file mode 100644
index 51f3d42f5a64..000000000000
--- a/drivers/staging/ccg/epautoconf.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers
- *
- * Copyright (C) 2004 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/device.h>
-
-#include <linux/ctype.h>
-#include <linux/string.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include "gadget_chips.h"
-
-
-/* we must assign addresses for configurable endpoints (like net2280) */
-static unsigned epnum;
-
-// #define MANY_ENDPOINTS
-#ifdef MANY_ENDPOINTS
-/* more than 15 configurable endpoints */
-static unsigned in_epnum;
-#endif
-
-
-/*
- * This should work with endpoints from controller drivers sharing the
- * same endpoint naming convention. By example:
- *
- * - ep1, ep2, ... address is fixed, not direction or type
- * - ep1in, ep2out, ... address and direction are fixed, not type
- * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
- * - ep1in-bulk, ep2out-iso, ... all three are fixed
- * - ep-* ... no functionality restrictions
- *
- * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal.
- * Less common restrictions are implied by gadget_is_*().
- *
- * NOTE: each endpoint is unidirectional, as specified by its USB
- * descriptor; and isn't specific to a configuration or altsetting.
- */
-static int
-ep_matches (
- struct usb_gadget *gadget,
- struct usb_ep *ep,
- struct usb_endpoint_descriptor *desc,
- struct usb_ss_ep_comp_descriptor *ep_comp
-)
-{
- u8 type;
- const char *tmp;
- u16 max;
-
- int num_req_streams = 0;
-
- /* endpoint already claimed? */
- if (NULL != ep->driver_data)
- return 0;
-
- /* only support ep0 for portable CONTROL traffic */
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- if (USB_ENDPOINT_XFER_CONTROL == type)
- return 0;
-
- /* some other naming convention */
- if ('e' != ep->name[0])
- return 0;
-
- /* type-restriction: "-iso", "-bulk", or "-int".
- * direction-restriction: "in", "out".
- */
- if ('-' != ep->name[2]) {
- tmp = strrchr (ep->name, '-');
- if (tmp) {
- switch (type) {
- case USB_ENDPOINT_XFER_INT:
- /* bulk endpoints handle interrupt transfers,
- * except the toggle-quirky iso-synch kind
- */
- if ('s' == tmp[2]) // == "-iso"
- return 0;
- /* for now, avoid PXA "interrupt-in";
- * it's documented as never using DATA1.
- */
- if (gadget_is_pxa (gadget)
- && 'i' == tmp [1])
- return 0;
- break;
- case USB_ENDPOINT_XFER_BULK:
- if ('b' != tmp[1]) // != "-bulk"
- return 0;
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if ('s' != tmp[2]) // != "-iso"
- return 0;
- }
- } else {
- tmp = ep->name + strlen (ep->name);
- }
-
- /* direction-restriction: "..in-..", "out-.." */
- tmp--;
- if (!isdigit (*tmp)) {
- if (desc->bEndpointAddress & USB_DIR_IN) {
- if ('n' != *tmp)
- return 0;
- } else {
- if ('t' != *tmp)
- return 0;
- }
- }
- }
-
- /*
- * Get the number of required streams from the EP companion
- * descriptor and see if the EP matches it
- */
- if (usb_endpoint_xfer_bulk(desc)) {
- if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
- num_req_streams = ep_comp->bmAttributes & 0x1f;
- if (num_req_streams > ep->max_streams)
- return 0;
- }
-
- }
-
- /*
- * If the protocol driver hasn't yet decided on wMaxPacketSize
- * and wants to know the maximum possible, provide the info.
- */
- if (desc->wMaxPacketSize == 0)
- desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket);
-
- /* endpoint maxpacket size is an input parameter, except for bulk
- * where it's an output parameter representing the full speed limit.
- * the usb spec fixes high speed bulk maxpacket at 512 bytes.
- */
- max = 0x7ff & usb_endpoint_maxp(desc);
- switch (type) {
- case USB_ENDPOINT_XFER_INT:
- /* INT: limit 64 bytes full speed, 1024 high/super speed */
- if (!gadget_is_dualspeed(gadget) && max > 64)
- return 0;
- /* FALLTHROUGH */
-
- case USB_ENDPOINT_XFER_ISOC:
- /* ISO: limit 1023 bytes full speed, 1024 high/super speed */
- if (ep->maxpacket < max)
- return 0;
- if (!gadget_is_dualspeed(gadget) && max > 1023)
- return 0;
-
- /* BOTH: "high bandwidth" works only at high speed */
- if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
- if (!gadget_is_dualspeed(gadget))
- return 0;
- /* configure your hardware with enough buffering!! */
- }
- break;
- }
-
- /* MATCH!! */
-
- /* report address */
- desc->bEndpointAddress &= USB_DIR_IN;
- if (isdigit (ep->name [2])) {
- u8 num = simple_strtoul (&ep->name [2], NULL, 10);
- desc->bEndpointAddress |= num;
-#ifdef MANY_ENDPOINTS
- } else if (desc->bEndpointAddress & USB_DIR_IN) {
- if (++in_epnum > 15)
- return 0;
- desc->bEndpointAddress = USB_DIR_IN | in_epnum;
-#endif
- } else {
- if (++epnum > 15)
- return 0;
- desc->bEndpointAddress |= epnum;
- }
-
- /* report (variable) full speed bulk maxpacket */
- if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
- int size = ep->maxpacket;
-
- /* min() doesn't work on bitfields with gcc-3.5 */
- if (size > 64)
- size = 64;
- desc->wMaxPacketSize = cpu_to_le16(size);
- }
- ep->address = desc->bEndpointAddress;
- return 1;
-}
-
-static struct usb_ep *
-find_ep (struct usb_gadget *gadget, const char *name)
-{
- struct usb_ep *ep;
-
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- if (0 == strcmp (ep->name, name))
- return ep;
- }
- return NULL;
-}
-
-/**
- * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
- * descriptor and ep companion descriptor
- * @gadget: The device to which the endpoint must belong.
- * @desc: Endpoint descriptor, with endpoint direction and transfer mode
- * initialized. For periodic transfers, the maximum packet
- * size must also be initialized. This is modified on
- * success.
- * @ep_comp: Endpoint companion descriptor, with the required
- * number of streams. Will be modified when the chosen EP
- * supports a different number of streams.
- *
- * This routine replaces the usb_ep_autoconfig when needed
- * superspeed enhancments. If such enhancemnets are required,
- * the FD should call usb_ep_autoconfig_ss directly and provide
- * the additional ep_comp parameter.
- *
- * By choosing an endpoint to use with the specified descriptor,
- * this routine simplifies writing gadget drivers that work with
- * multiple USB device controllers. The endpoint would be
- * passed later to usb_ep_enable(), along with some descriptor.
- *
- * That second descriptor won't always be the same as the first one.
- * For example, isochronous endpoints can be autoconfigured for high
- * bandwidth, and then used in several lower bandwidth altsettings.
- * Also, high and full speed descriptors will be different.
- *
- * Be sure to examine and test the results of autoconfiguration
- * on your hardware. This code may not make the best choices
- * about how to use the USB controller, and it can't know all
- * the restrictions that may apply. Some combinations of driver
- * and hardware won't be able to autoconfigure.
- *
- * On success, this returns an un-claimed usb_ep, and modifies the endpoint
- * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed and
- * the bmAttribute field in the ep companion descriptor is
- * updated with the assigned number of streams if it is
- * different from the original value. To prevent the endpoint
- * from being returned by a later autoconfig call, claim it by
- * assigning ep->driver_data to some non-null value.
- *
- * On failure, this returns a null endpoint descriptor.
- */
-struct usb_ep *usb_ep_autoconfig_ss(
- struct usb_gadget *gadget,
- struct usb_endpoint_descriptor *desc,
- struct usb_ss_ep_comp_descriptor *ep_comp
-)
-{
- struct usb_ep *ep;
- u8 type;
-
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
- /* First, apply chip-specific "best usage" knowledge.
- * This might make a good usb_gadget_ops hook ...
- */
- if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
- /* ep-e, ep-f are PIO with only 64 byte fifos */
- ep = find_ep (gadget, "ep-e");
- if (ep && ep_matches(gadget, ep, desc, ep_comp))
- goto found_ep;
- ep = find_ep (gadget, "ep-f");
- if (ep && ep_matches(gadget, ep, desc, ep_comp))
- goto found_ep;
-
- } else if (gadget_is_goku (gadget)) {
- if (USB_ENDPOINT_XFER_INT == type) {
- /* single buffering is enough */
- ep = find_ep(gadget, "ep3-bulk");
- if (ep && ep_matches(gadget, ep, desc, ep_comp))
- goto found_ep;
- } else if (USB_ENDPOINT_XFER_BULK == type
- && (USB_DIR_IN & desc->bEndpointAddress)) {
- /* DMA may be available */
- ep = find_ep(gadget, "ep2-bulk");
- if (ep && ep_matches(gadget, ep, desc,
- ep_comp))
- goto found_ep;
- }
-
-#ifdef CONFIG_BLACKFIN
- } else if (gadget_is_musbhdrc(gadget)) {
- if ((USB_ENDPOINT_XFER_BULK == type) ||
- (USB_ENDPOINT_XFER_ISOC == type)) {
- if (USB_DIR_IN & desc->bEndpointAddress)
- ep = find_ep (gadget, "ep5in");
- else
- ep = find_ep (gadget, "ep6out");
- } else if (USB_ENDPOINT_XFER_INT == type) {
- if (USB_DIR_IN & desc->bEndpointAddress)
- ep = find_ep(gadget, "ep1in");
- else
- ep = find_ep(gadget, "ep2out");
- } else
- ep = NULL;
- if (ep && ep_matches(gadget, ep, desc, ep_comp))
- goto found_ep;
-#endif
- }
-
- /* Second, look at endpoints until an unclaimed one looks usable */
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- if (ep_matches(gadget, ep, desc, ep_comp))
- goto found_ep;
- }
-
- /* Fail */
- return NULL;
-found_ep:
- ep->desc = NULL;
- ep->comp_desc = NULL;
- return ep;
-}
-
-/**
- * usb_ep_autoconfig() - choose an endpoint matching the
- * descriptor
- * @gadget: The device to which the endpoint must belong.
- * @desc: Endpoint descriptor, with endpoint direction and transfer mode
- * initialized. For periodic transfers, the maximum packet
- * size must also be initialized. This is modified on success.
- *
- * By choosing an endpoint to use with the specified descriptor, this
- * routine simplifies writing gadget drivers that work with multiple
- * USB device controllers. The endpoint would be passed later to
- * usb_ep_enable(), along with some descriptor.
- *
- * That second descriptor won't always be the same as the first one.
- * For example, isochronous endpoints can be autoconfigured for high
- * bandwidth, and then used in several lower bandwidth altsettings.
- * Also, high and full speed descriptors will be different.
- *
- * Be sure to examine and test the results of autoconfiguration on your
- * hardware. This code may not make the best choices about how to use the
- * USB controller, and it can't know all the restrictions that may apply.
- * Some combinations of driver and hardware won't be able to autoconfigure.
- *
- * On success, this returns an un-claimed usb_ep, and modifies the endpoint
- * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed. To prevent
- * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
- *
- * On failure, this returns a null endpoint descriptor.
- */
-struct usb_ep *usb_ep_autoconfig(
- struct usb_gadget *gadget,
- struct usb_endpoint_descriptor *desc
-)
-{
- return usb_ep_autoconfig_ss(gadget, desc, NULL);
-}
-
-
-/**
- * usb_ep_autoconfig_reset - reset endpoint autoconfig state
- * @gadget: device for which autoconfig state will be reset
- *
- * Use this for devices where one configuration may need to assign
- * endpoint resources very differently from the next one. It clears
- * state such as ep->driver_data and the record of assigned endpoints
- * used by usb_ep_autoconfig().
- */
-void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
-{
- struct usb_ep *ep;
-
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- ep->driver_data = NULL;
- }
-#ifdef MANY_ENDPOINTS
- in_epnum = 0;
-#endif
- epnum = 0;
-}
-
diff --git a/drivers/staging/ccg/f_acm.c b/drivers/staging/ccg/f_acm.c
deleted file mode 100644
index d672250a61fa..000000000000
--- a/drivers/staging/ccg/f_acm.c
+++ /dev/null
@@ -1,814 +0,0 @@
-/*
- * f_acm.c -- USB CDC serial (ACM) function driver
- *
- * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
- * Copyright (C) 2008 by David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- * Copyright (C) 2009 by Samsung Electronics
- * Author: Michal Nazarewicz (mina86@mina86.com)
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * either version 2 of that License or (at your option) any later version.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-
-#include "u_serial.h"
-#include "gadget_chips.h"
-
-
-/*
- * This CDC ACM function support just wraps control functions and
- * notifications around the generic serial-over-usb code.
- *
- * Because CDC ACM is standardized by the USB-IF, many host operating
- * systems have drivers for it. Accordingly, ACM is the preferred
- * interop solution for serial-port type connections. The control
- * models are often not necessary, and in any case don't do much in
- * this bare-bones implementation.
- *
- * Note that even MS-Windows has some support for ACM. However, that
- * support is somewhat broken because when you use ACM in a composite
- * device, having multiple interfaces confuses the poor OS. It doesn't
- * seem to understand CDC Union descriptors. The new "association"
- * descriptors (roughly equivalent to CDC Unions) may sometimes help.
- */
-
-struct f_acm {
- struct gserial port;
- u8 ctrl_id, data_id;
- u8 port_num;
-
- u8 pending;
-
- /* lock is mostly for pending and notify_req ... they get accessed
- * by callbacks both from tty (open/close/break) under its spinlock,
- * and notify_req.complete() which can't use that lock.
- */
- spinlock_t lock;
-
- struct usb_ep *notify;
- struct usb_request *notify_req;
-
- struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
-
- /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */
- u16 port_handshake_bits;
-#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */
-#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */
-
- /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */
- u16 serial_state;
-#define ACM_CTRL_OVERRUN (1 << 6)
-#define ACM_CTRL_PARITY (1 << 5)
-#define ACM_CTRL_FRAMING (1 << 4)
-#define ACM_CTRL_RI (1 << 3)
-#define ACM_CTRL_BRK (1 << 2)
-#define ACM_CTRL_DSR (1 << 1)
-#define ACM_CTRL_DCD (1 << 0)
-};
-
-static inline struct f_acm *func_to_acm(struct usb_function *f)
-{
- return container_of(f, struct f_acm, port.func);
-}
-
-static inline struct f_acm *port_to_acm(struct gserial *p)
-{
- return container_of(p, struct f_acm, port);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* notification endpoint uses smallish and infrequent fixed-size messages */
-
-#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */
-#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */
-
-/* interface and class descriptors: */
-
-static struct usb_interface_assoc_descriptor
-acm_iad_descriptor = {
- .bLength = sizeof acm_iad_descriptor,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
-
- /* .bFirstInterface = DYNAMIC, */
- .bInterfaceCount = 2, // control + data
- .bFunctionClass = USB_CLASS_COMM,
- .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
- .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
- /* .iFunction = DYNAMIC */
-};
-
-
-static struct usb_interface_descriptor acm_control_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- /* .bInterfaceNumber = DYNAMIC */
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
- /* .iInterface = DYNAMIC */
-};
-
-static struct usb_interface_descriptor acm_data_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- /* .bInterfaceNumber = DYNAMIC */
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- /* .iInterface = DYNAMIC */
-};
-
-static struct usb_cdc_header_desc acm_header_desc = {
- .bLength = sizeof(acm_header_desc),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_HEADER_TYPE,
- .bcdCDC = cpu_to_le16(0x0110),
-};
-
-static struct usb_cdc_call_mgmt_descriptor
-acm_call_mgmt_descriptor = {
- .bLength = sizeof(acm_call_mgmt_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
- .bmCapabilities = 0,
- /* .bDataInterface = DYNAMIC */
-};
-
-static struct usb_cdc_acm_descriptor acm_descriptor = {
- .bLength = sizeof(acm_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = USB_CDC_CAP_LINE,
-};
-
-static struct usb_cdc_union_desc acm_union_desc = {
- .bLength = sizeof(acm_union_desc),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_UNION_TYPE,
- /* .bMasterInterface0 = DYNAMIC */
- /* .bSlaveInterface0 = DYNAMIC */
-};
-
-/* full speed support: */
-
-static struct usb_endpoint_descriptor acm_fs_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
- .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor acm_fs_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_endpoint_descriptor acm_fs_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_descriptor_header *acm_fs_function[] = {
- (struct usb_descriptor_header *) &acm_iad_descriptor,
- (struct usb_descriptor_header *) &acm_control_interface_desc,
- (struct usb_descriptor_header *) &acm_header_desc,
- (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
- (struct usb_descriptor_header *) &acm_descriptor,
- (struct usb_descriptor_header *) &acm_union_desc,
- (struct usb_descriptor_header *) &acm_fs_notify_desc,
- (struct usb_descriptor_header *) &acm_data_interface_desc,
- (struct usb_descriptor_header *) &acm_fs_in_desc,
- (struct usb_descriptor_header *) &acm_fs_out_desc,
- NULL,
-};
-
-/* high speed support: */
-
-static struct usb_endpoint_descriptor acm_hs_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET),
- .bInterval = GS_LOG2_NOTIFY_INTERVAL+4,
-};
-
-static struct usb_endpoint_descriptor acm_hs_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor acm_hs_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_descriptor_header *acm_hs_function[] = {
- (struct usb_descriptor_header *) &acm_iad_descriptor,
- (struct usb_descriptor_header *) &acm_control_interface_desc,
- (struct usb_descriptor_header *) &acm_header_desc,
- (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
- (struct usb_descriptor_header *) &acm_descriptor,
- (struct usb_descriptor_header *) &acm_union_desc,
- (struct usb_descriptor_header *) &acm_hs_notify_desc,
- (struct usb_descriptor_header *) &acm_data_interface_desc,
- (struct usb_descriptor_header *) &acm_hs_in_desc,
- (struct usb_descriptor_header *) &acm_hs_out_desc,
- NULL,
-};
-
-static struct usb_endpoint_descriptor acm_ss_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor acm_ss_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
- .bLength = sizeof acm_ss_bulk_comp_desc,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_descriptor_header *acm_ss_function[] = {
- (struct usb_descriptor_header *) &acm_iad_descriptor,
- (struct usb_descriptor_header *) &acm_control_interface_desc,
- (struct usb_descriptor_header *) &acm_header_desc,
- (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
- (struct usb_descriptor_header *) &acm_descriptor,
- (struct usb_descriptor_header *) &acm_union_desc,
- (struct usb_descriptor_header *) &acm_hs_notify_desc,
- (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
- (struct usb_descriptor_header *) &acm_data_interface_desc,
- (struct usb_descriptor_header *) &acm_ss_in_desc,
- (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
- (struct usb_descriptor_header *) &acm_ss_out_desc,
- (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
- NULL,
-};
-
-/* string descriptors: */
-
-#define ACM_CTRL_IDX 0
-#define ACM_DATA_IDX 1
-#define ACM_IAD_IDX 2
-
-/* static strings, in UTF-8 */
-static struct usb_string acm_string_defs[] = {
- [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)",
- [ACM_DATA_IDX].s = "CDC ACM Data",
- [ACM_IAD_IDX ].s = "CDC Serial",
- { /* ZEROES END LIST */ },
-};
-
-static struct usb_gadget_strings acm_string_table = {
- .language = 0x0409, /* en-us */
- .strings = acm_string_defs,
-};
-
-static struct usb_gadget_strings *acm_strings[] = {
- &acm_string_table,
- NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* ACM control ... data handling is delegated to tty library code.
- * The main task of this function is to activate and deactivate
- * that code based on device state; track parameters like line
- * speed, handshake state, and so on; and issue notifications.
- */
-
-static void acm_complete_set_line_coding(struct usb_ep *ep,
- struct usb_request *req)
-{
- struct f_acm *acm = ep->driver_data;
- struct usb_composite_dev *cdev = acm->port.func.config->cdev;
-
- if (req->status != 0) {
- DBG(cdev, "acm ttyGS%d completion, err %d\n",
- acm->port_num, req->status);
- return;
- }
-
- /* normal completion */
- if (req->actual != sizeof(acm->port_line_coding)) {
- DBG(cdev, "acm ttyGS%d short resp, len %d\n",
- acm->port_num, req->actual);
- usb_ep_set_halt(ep);
- } else {
- struct usb_cdc_line_coding *value = req->buf;
-
- /* REVISIT: we currently just remember this data.
- * If we change that, (a) validate it first, then
- * (b) update whatever hardware needs updating,
- * (c) worry about locking. This is information on
- * the order of 9600-8-N-1 ... most of which means
- * nothing unless we control a real RS232 line.
- */
- acm->port_line_coding = *value;
- }
-}
-
-static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
-{
- struct f_acm *acm = func_to_acm(f);
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_request *req = cdev->req;
- int value = -EOPNOTSUPP;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
-
- /* composite driver infrastructure handles everything except
- * CDC class messages; interface activation uses set_alt().
- *
- * Note CDC spec table 4 lists the ACM request profile. It requires
- * encapsulated command support ... we don't handle any, and respond
- * to them by stalling. Options include get/set/clear comm features
- * (not that useful) and SEND_BREAK.
- */
- switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
-
- /* SET_LINE_CODING ... just read and save what the host sends */
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
- | USB_CDC_REQ_SET_LINE_CODING:
- if (w_length != sizeof(struct usb_cdc_line_coding)
- || w_index != acm->ctrl_id)
- goto invalid;
-
- value = w_length;
- cdev->gadget->ep0->driver_data = acm;
- req->complete = acm_complete_set_line_coding;
- break;
-
- /* GET_LINE_CODING ... return what host sent, or initial value */
- case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
- | USB_CDC_REQ_GET_LINE_CODING:
- if (w_index != acm->ctrl_id)
- goto invalid;
-
- value = min_t(unsigned, w_length,
- sizeof(struct usb_cdc_line_coding));
- memcpy(req->buf, &acm->port_line_coding, value);
- break;
-
- /* SET_CONTROL_LINE_STATE ... save what the host sent */
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
- | USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- if (w_index != acm->ctrl_id)
- goto invalid;
-
- value = 0;
-
- /* FIXME we should not allow data to flow until the
- * host sets the ACM_CTRL_DTR bit; and when it clears
- * that bit, we should return to that no-flow state.
- */
- acm->port_handshake_bits = w_value;
- break;
-
- default:
-invalid:
- VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- }
-
- /* respond with data transfer or status phase? */
- if (value >= 0) {
- DBG(cdev, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
- acm->port_num, ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- req->zero = 0;
- req->length = value;
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
- if (value < 0)
- ERROR(cdev, "acm response on ttyGS%d, err %d\n",
- acm->port_num, value);
- }
-
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
-static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
- struct f_acm *acm = func_to_acm(f);
- struct usb_composite_dev *cdev = f->config->cdev;
-
- /* we know alt == 0, so this is an activation or a reset */
-
- if (intf == acm->ctrl_id) {
- if (acm->notify->driver_data) {
- VDBG(cdev, "reset acm control interface %d\n", intf);
- usb_ep_disable(acm->notify);
- } else {
- VDBG(cdev, "init acm ctrl interface %d\n", intf);
- if (config_ep_by_speed(cdev->gadget, f, acm->notify))
- return -EINVAL;
- }
- usb_ep_enable(acm->notify);
- acm->notify->driver_data = acm;
-
- } else if (intf == acm->data_id) {
- if (acm->port.in->driver_data) {
- DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
- gserial_disconnect(&acm->port);
- }
- if (!acm->port.in->desc || !acm->port.out->desc) {
- DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
- if (config_ep_by_speed(cdev->gadget, f,
- acm->port.in) ||
- config_ep_by_speed(cdev->gadget, f,
- acm->port.out)) {
- acm->port.in->desc = NULL;
- acm->port.out->desc = NULL;
- return -EINVAL;
- }
- }
- gserial_connect(&acm->port, acm->port_num);
-
- } else
- return -EINVAL;
-
- return 0;
-}
-
-static void acm_disable(struct usb_function *f)
-{
- struct f_acm *acm = func_to_acm(f);
- struct usb_composite_dev *cdev = f->config->cdev;
-
- DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num);
- gserial_disconnect(&acm->port);
- usb_ep_disable(acm->notify);
- acm->notify->driver_data = NULL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/**
- * acm_cdc_notify - issue CDC notification to host
- * @acm: wraps host to be notified
- * @type: notification type
- * @value: Refer to cdc specs, wValue field.
- * @data: data to be sent
- * @length: size of data
- * Context: irqs blocked, acm->lock held, acm_notify_req non-null
- *
- * Returns zero on success or a negative errno.
- *
- * See section 6.3.5 of the CDC 1.1 specification for information
- * about the only notification we issue: SerialState change.
- */
-static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value,
- void *data, unsigned length)
-{
- struct usb_ep *ep = acm->notify;
- struct usb_request *req;
- struct usb_cdc_notification *notify;
- const unsigned len = sizeof(*notify) + length;
- void *buf;
- int status;
-
- req = acm->notify_req;
- acm->notify_req = NULL;
- acm->pending = false;
-
- req->length = len;
- notify = req->buf;
- buf = notify + 1;
-
- notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
- | USB_RECIP_INTERFACE;
- notify->bNotificationType = type;
- notify->wValue = cpu_to_le16(value);
- notify->wIndex = cpu_to_le16(acm->ctrl_id);
- notify->wLength = cpu_to_le16(length);
- memcpy(buf, data, length);
-
- /* ep_queue() can complete immediately if it fills the fifo... */
- spin_unlock(&acm->lock);
- status = usb_ep_queue(ep, req, GFP_ATOMIC);
- spin_lock(&acm->lock);
-
- if (status < 0) {
- ERROR(acm->port.func.config->cdev,
- "acm ttyGS%d can't notify serial state, %d\n",
- acm->port_num, status);
- acm->notify_req = req;
- }
-
- return status;
-}
-
-static int acm_notify_serial_state(struct f_acm *acm)
-{
- struct usb_composite_dev *cdev = acm->port.func.config->cdev;
- int status;
-
- spin_lock(&acm->lock);
- if (acm->notify_req) {
- DBG(cdev, "acm ttyGS%d serial state %04x\n",
- acm->port_num, acm->serial_state);
- status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE,
- 0, &acm->serial_state, sizeof(acm->serial_state));
- } else {
- acm->pending = true;
- status = 0;
- }
- spin_unlock(&acm->lock);
- return status;
-}
-
-static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_acm *acm = req->context;
- u8 doit = false;
-
- /* on this call path we do NOT hold the port spinlock,
- * which is why ACM needs its own spinlock
- */
- spin_lock(&acm->lock);
- if (req->status != -ESHUTDOWN)
- doit = acm->pending;
- acm->notify_req = req;
- spin_unlock(&acm->lock);
-
- if (doit)
- acm_notify_serial_state(acm);
-}
-
-/* connect == the TTY link is open */
-
-static void acm_connect(struct gserial *port)
-{
- struct f_acm *acm = port_to_acm(port);
-
- acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
- acm_notify_serial_state(acm);
-}
-
-static void acm_disconnect(struct gserial *port)
-{
- struct f_acm *acm = port_to_acm(port);
-
- acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
- acm_notify_serial_state(acm);
-}
-
-static int acm_send_break(struct gserial *port, int duration)
-{
- struct f_acm *acm = port_to_acm(port);
- u16 state;
-
- state = acm->serial_state;
- state &= ~ACM_CTRL_BRK;
- if (duration)
- state |= ACM_CTRL_BRK;
-
- acm->serial_state = state;
- return acm_notify_serial_state(acm);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* ACM function driver setup/binding */
-static int
-acm_bind(struct usb_configuration *c, struct usb_function *f)
-{
- struct usb_composite_dev *cdev = c->cdev;
- struct f_acm *acm = func_to_acm(f);
- int status;
- struct usb_ep *ep;
-
- /* allocate instance-specific interface IDs, and patch descriptors */
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- acm->ctrl_id = status;
- acm_iad_descriptor.bFirstInterface = status;
-
- acm_control_interface_desc.bInterfaceNumber = status;
- acm_union_desc .bMasterInterface0 = status;
-
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- acm->data_id = status;
-
- acm_data_interface_desc.bInterfaceNumber = status;
- acm_union_desc.bSlaveInterface0 = status;
- acm_call_mgmt_descriptor.bDataInterface = status;
-
- status = -ENODEV;
-
- /* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
- if (!ep)
- goto fail;
- acm->port.in = ep;
- ep->driver_data = cdev; /* claim */
-
- ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
- if (!ep)
- goto fail;
- acm->port.out = ep;
- ep->driver_data = cdev; /* claim */
-
- ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
- if (!ep)
- goto fail;
- acm->notify = ep;
- ep->driver_data = cdev; /* claim */
-
- /* allocate notification */
- acm->notify_req = gs_alloc_req(ep,
- sizeof(struct usb_cdc_notification) + 2,
- GFP_KERNEL);
- if (!acm->notify_req)
- goto fail;
-
- acm->notify_req->complete = acm_cdc_notify_complete;
- acm->notify_req->context = acm;
-
- /* copy descriptors */
- f->descriptors = usb_copy_descriptors(acm_fs_function);
- if (!f->descriptors)
- goto fail;
-
- /* support all relevant hardware speeds... we expect that when
- * hardware is dual speed, all bulk-capable endpoints work at
- * both speeds
- */
- if (gadget_is_dualspeed(c->cdev->gadget)) {
- acm_hs_in_desc.bEndpointAddress =
- acm_fs_in_desc.bEndpointAddress;
- acm_hs_out_desc.bEndpointAddress =
- acm_fs_out_desc.bEndpointAddress;
- acm_hs_notify_desc.bEndpointAddress =
- acm_fs_notify_desc.bEndpointAddress;
-
- /* copy descriptors */
- f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
- }
- if (gadget_is_superspeed(c->cdev->gadget)) {
- acm_ss_in_desc.bEndpointAddress =
- acm_fs_in_desc.bEndpointAddress;
- acm_ss_out_desc.bEndpointAddress =
- acm_fs_out_desc.bEndpointAddress;
-
- /* copy descriptors, and track endpoint copies */
- f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
- if (!f->ss_descriptors)
- goto fail;
- }
-
- DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
- acm->port_num,
- gadget_is_superspeed(c->cdev->gadget) ? "super" :
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- acm->port.in->name, acm->port.out->name,
- acm->notify->name);
- return 0;
-
-fail:
- if (acm->notify_req)
- gs_free_req(acm->notify, acm->notify_req);
-
- /* we might as well release our claims on endpoints */
- if (acm->notify)
- acm->notify->driver_data = NULL;
- if (acm->port.out)
- acm->port.out->driver_data = NULL;
- if (acm->port.in)
- acm->port.in->driver_data = NULL;
-
- ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);
-
- return status;
-}
-
-static void
-acm_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct f_acm *acm = func_to_acm(f);
-
- if (gadget_is_dualspeed(c->cdev->gadget))
- usb_free_descriptors(f->hs_descriptors);
- if (gadget_is_superspeed(c->cdev->gadget))
- usb_free_descriptors(f->ss_descriptors);
- usb_free_descriptors(f->descriptors);
- gs_free_req(acm->notify, acm->notify_req);
- kfree(acm);
-}
-
-/* Some controllers can't support CDC ACM ... */
-static inline bool can_support_cdc(struct usb_configuration *c)
-{
- /* everything else is *probably* fine ... */
- return true;
-}
-
-/**
- * acm_bind_config - add a CDC ACM function to a configuration
- * @c: the configuration to support the CDC ACM instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gserial_setup() with enough ports to
- * handle all the ones it binds. Caller is also responsible
- * for calling @gserial_cleanup() before module unload.
- */
-int acm_bind_config(struct usb_configuration *c, u8 port_num)
-{
- struct f_acm *acm;
- int status;
-
- if (!can_support_cdc(c))
- return -EINVAL;
-
- /* REVISIT might want instance-specific strings to help
- * distinguish instances ...
- */
-
- /* maybe allocate device-global string IDs, and patch descriptors */
- if (acm_string_defs[ACM_CTRL_IDX].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- acm_string_defs[ACM_CTRL_IDX].id = status;
-
- acm_control_interface_desc.iInterface = status;
-
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- acm_string_defs[ACM_DATA_IDX].id = status;
-
- acm_data_interface_desc.iInterface = status;
-
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- acm_string_defs[ACM_IAD_IDX].id = status;
-
- acm_iad_descriptor.iFunction = status;
- }
-
- /* allocate and initialize one new instance */
- acm = kzalloc(sizeof *acm, GFP_KERNEL);
- if (!acm)
- return -ENOMEM;
-
- spin_lock_init(&acm->lock);
-
- acm->port_num = port_num;
-
- acm->port.connect = acm_connect;
- acm->port.disconnect = acm_disconnect;
- acm->port.send_break = acm_send_break;
-
- acm->port.func.name = "acm";
- acm->port.func.strings = acm_strings;
- /* descriptors are per-instance copies */
- acm->port.func.bind = acm_bind;
- acm->port.func.unbind = acm_unbind;
- acm->port.func.set_alt = acm_set_alt;
- acm->port.func.setup = acm_setup;
- acm->port.func.disable = acm_disable;
-
- status = usb_add_function(c, &acm->port.func);
- if (status)
- kfree(acm);
- return status;
-}
diff --git a/drivers/staging/ccg/f_fs.c b/drivers/staging/ccg/f_fs.c
deleted file mode 100644
index e82b1cdfd189..000000000000
--- a/drivers/staging/ccg/f_fs.c
+++ /dev/null
@@ -1,2454 +0,0 @@
-/*
- * f_fs.c -- user mode file system API for USB composite function controllers
- *
- * Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <mina86@mina86.com>
- *
- * Based on inode.c (GadgetFS) which was:
- * Copyright (C) 2003-2004 David Brownell
- * Copyright (C) 2003 Agilent Technologies
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-/* #define DEBUG */
-/* #define VERBOSE_DEBUG */
-
-#include <linux/blkdev.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-#include <linux/hid.h>
-#include <asm/unaligned.h>
-
-#include <linux/usb/composite.h>
-#include <linux/usb/functionfs.h>
-
-
-#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */
-
-
-/* Debugging ****************************************************************/
-
-#ifdef VERBOSE_DEBUG
-# define pr_vdebug pr_debug
-# define ffs_dump_mem(prefix, ptr, len) \
- print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len)
-#else
-# define pr_vdebug(...) do { } while (0)
-# define ffs_dump_mem(prefix, ptr, len) do { } while (0)
-#endif /* VERBOSE_DEBUG */
-
-#define ENTER() pr_vdebug("%s()\n", __func__)
-
-
-/* The data structure and setup file ****************************************/
-
-enum ffs_state {
- /*
- * Waiting for descriptors and strings.
- *
- * In this state no open(2), read(2) or write(2) on epfiles
- * may succeed (which should not be the problem as there
- * should be no such files opened in the first place).
- */
- FFS_READ_DESCRIPTORS,
- FFS_READ_STRINGS,
-
- /*
- * We've got descriptors and strings. We are or have called
- * functionfs_ready_callback(). functionfs_bind() may have
- * been called but we don't know.
- *
- * This is the only state in which operations on epfiles may
- * succeed.
- */
- FFS_ACTIVE,
-
- /*
- * All endpoints have been closed. This state is also set if
- * we encounter an unrecoverable error. The only
- * unrecoverable error is situation when after reading strings
- * from user space we fail to initialise epfiles or
- * functionfs_ready_callback() returns with error (<0).
- *
- * In this state no open(2), read(2) or write(2) (both on ep0
- * as well as epfile) may succeed (at this point epfiles are
- * unlinked and all closed so this is not a problem; ep0 is
- * also closed but ep0 file exists and so open(2) on ep0 must
- * fail).
- */
- FFS_CLOSING
-};
-
-
-enum ffs_setup_state {
- /* There is no setup request pending. */
- FFS_NO_SETUP,
- /*
- * User has read events and there was a setup request event
- * there. The next read/write on ep0 will handle the
- * request.
- */
- FFS_SETUP_PENDING,
- /*
- * There was event pending but before user space handled it
- * some other event was introduced which canceled existing
- * setup. If this state is set read/write on ep0 return
- * -EIDRM. This state is only set when adding event.
- */
- FFS_SETUP_CANCELED
-};
-
-
-
-struct ffs_epfile;
-struct ffs_function;
-
-struct ffs_data {
- struct usb_gadget *gadget;
-
- /*
- * Protect access read/write operations, only one read/write
- * at a time. As a consequence protects ep0req and company.
- * While setup request is being processed (queued) this is
- * held.
- */
- struct mutex mutex;
-
- /*
- * Protect access to endpoint related structures (basically
- * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for
- * endpoint zero.
- */
- spinlock_t eps_lock;
-
- /*
- * XXX REVISIT do we need our own request? Since we are not
- * handling setup requests immediately user space may be so
- * slow that another setup will be sent to the gadget but this
- * time not to us but another function and then there could be
- * a race. Is that the case? Or maybe we can use cdev->req
- * after all, maybe we just need some spinlock for that?
- */
- struct usb_request *ep0req; /* P: mutex */
- struct completion ep0req_completion; /* P: mutex */
- int ep0req_status; /* P: mutex */
-
- /* reference counter */
- atomic_t ref;
- /* how many files are opened (EP0 and others) */
- atomic_t opened;
-
- /* EP0 state */
- enum ffs_state state;
-
- /*
- * Possible transitions:
- * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock
- * happens only in ep0 read which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock
- * happens only in ep0 i/o which is P: mutex
- * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock
- * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg
- */
- enum ffs_setup_state setup_state;
-
-#define FFS_SETUP_STATE(ffs) \
- ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \
- FFS_SETUP_CANCELED, FFS_NO_SETUP))
-
- /* Events & such. */
- struct {
- u8 types[4];
- unsigned short count;
- /* XXX REVISIT need to update it in some places, or do we? */
- unsigned short can_stall;
- struct usb_ctrlrequest setup;
-
- wait_queue_head_t waitq;
- } ev; /* the whole structure, P: ev.waitq.lock */
-
- /* Flags */
- unsigned long flags;
-#define FFS_FL_CALL_CLOSED_CALLBACK 0
-#define FFS_FL_BOUND 1
-
- /* Active function */
- struct ffs_function *func;
-
- /*
- * Device name, write once when file system is mounted.
- * Intended for user to read if she wants.
- */
- const char *dev_name;
- /* Private data for our user (ie. gadget). Managed by user. */
- void *private_data;
-
- /* filled by __ffs_data_got_descs() */
- /*
- * Real descriptors are 16 bytes after raw_descs (so you need
- * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the
- * first full speed descriptor). raw_descs_length and
- * raw_fs_descs_length do not have those 16 bytes added.
- */
- const void *raw_descs;
- unsigned raw_descs_length;
- unsigned raw_fs_descs_length;
- unsigned fs_descs_count;
- unsigned hs_descs_count;
-
- unsigned short strings_count;
- unsigned short interfaces_count;
- unsigned short eps_count;
- unsigned short _pad1;
-
- /* filled by __ffs_data_got_strings() */
- /* ids in stringtabs are set in functionfs_bind() */
- const void *raw_strings;
- struct usb_gadget_strings **stringtabs;
-
- /*
- * File system's super block, write once when file system is
- * mounted.
- */
- struct super_block *sb;
-
- /* File permissions, written once when fs is mounted */
- struct ffs_file_perms {
- umode_t mode;
- uid_t uid;
- gid_t gid;
- } file_perms;
-
- /*
- * The endpoint files, filled by ffs_epfiles_create(),
- * destroyed by ffs_epfiles_destroy().
- */
- struct ffs_epfile *epfiles;
-};
-
-/* Reference counter handling */
-static void ffs_data_get(struct ffs_data *ffs);
-static void ffs_data_put(struct ffs_data *ffs);
-/* Creates new ffs_data object. */
-static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc));
-
-/* Opened counter handling. */
-static void ffs_data_opened(struct ffs_data *ffs);
-static void ffs_data_closed(struct ffs_data *ffs);
-
-/* Called with ffs->mutex held; take over ownership of data. */
-static int __must_check
-__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len);
-static int __must_check
-__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
-
-
-/* The function structure ***************************************************/
-
-struct ffs_ep;
-
-struct ffs_function {
- struct usb_configuration *conf;
- struct usb_gadget *gadget;
- struct ffs_data *ffs;
-
- struct ffs_ep *eps;
- u8 eps_revmap[16];
- short *interfaces_nums;
-
- struct usb_function function;
-};
-
-
-static struct ffs_function *ffs_func_from_usb(struct usb_function *f)
-{
- return container_of(f, struct ffs_function, function);
-}
-
-static void ffs_func_free(struct ffs_function *func);
-
-static void ffs_func_eps_disable(struct ffs_function *func);
-static int __must_check ffs_func_eps_enable(struct ffs_function *func);
-
-static int ffs_func_bind(struct usb_configuration *,
- struct usb_function *);
-static void ffs_func_unbind(struct usb_configuration *,
- struct usb_function *);
-static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);
-static void ffs_func_disable(struct usb_function *);
-static int ffs_func_setup(struct usb_function *,
- const struct usb_ctrlrequest *);
-static void ffs_func_suspend(struct usb_function *);
-static void ffs_func_resume(struct usb_function *);
-
-
-static int ffs_func_revmap_ep(struct ffs_function *func, u8 num);
-static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf);
-
-
-/* The endpoints structures *************************************************/
-
-struct ffs_ep {
- struct usb_ep *ep; /* P: ffs->eps_lock */
- struct usb_request *req; /* P: epfile->mutex */
-
- /* [0]: full speed, [1]: high speed */
- struct usb_endpoint_descriptor *descs[2];
-
- u8 num;
-
- int status; /* P: epfile->mutex */
-};
-
-struct ffs_epfile {
- /* Protects ep->ep and ep->req. */
- struct mutex mutex;
- wait_queue_head_t wait;
-
- struct ffs_data *ffs;
- struct ffs_ep *ep; /* P: ffs->eps_lock */
-
- struct dentry *dentry;
-
- char name[5];
-
- unsigned char in; /* P: ffs->eps_lock */
- unsigned char isoc; /* P: ffs->eps_lock */
-
- unsigned char _pad;
-};
-
-static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
-
-static struct inode *__must_check
-ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
- const struct file_operations *fops,
- struct dentry **dentry_p);
-
-
-/* Misc helper functions ****************************************************/
-
-static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
- __attribute__((warn_unused_result, nonnull));
-static char *ffs_prepare_buffer(const char * __user buf, size_t len)
- __attribute__((warn_unused_result, nonnull));
-
-
-/* Control file aka ep0 *****************************************************/
-
-static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct ffs_data *ffs = req->context;
-
- complete_all(&ffs->ep0req_completion);
-}
-
-static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
-{
- struct usb_request *req = ffs->ep0req;
- int ret;
-
- req->zero = len < le16_to_cpu(ffs->ev.setup.wLength);
-
- spin_unlock_irq(&ffs->ev.waitq.lock);
-
- req->buf = data;
- req->length = len;
-
- /*
- * UDC layer requires to provide a buffer even for ZLP, but should
- * not use it at all. Let's provide some poisoned pointer to catch
- * possible bug in the driver.
- */
- if (req->buf == NULL)
- req->buf = (void *)0xDEADBABE;
-
- INIT_COMPLETION(ffs->ep0req_completion);
-
- ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
- if (unlikely(ret < 0))
- return ret;
-
- ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
- if (unlikely(ret)) {
- usb_ep_dequeue(ffs->gadget->ep0, req);
- return -EINTR;
- }
-
- ffs->setup_state = FFS_NO_SETUP;
- return ffs->ep0req_status;
-}
-
-static int __ffs_ep0_stall(struct ffs_data *ffs)
-{
- if (ffs->ev.can_stall) {
- pr_vdebug("ep0 stall\n");
- usb_ep_set_halt(ffs->gadget->ep0);
- ffs->setup_state = FFS_NO_SETUP;
- return -EL2HLT;
- } else {
- pr_debug("bogus ep0 stall!\n");
- return -ESRCH;
- }
-}
-
-static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ptr)
-{
- struct ffs_data *ffs = file->private_data;
- ssize_t ret;
- char *data;
-
- ENTER();
-
- /* Fast check if setup was canceled */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
- return -EIDRM;
-
- /* Acquire mutex */
- ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret < 0))
- return ret;
-
- /* Check state */
- switch (ffs->state) {
- case FFS_READ_DESCRIPTORS:
- case FFS_READ_STRINGS:
- /* Copy data */
- if (unlikely(len < 16)) {
- ret = -EINVAL;
- break;
- }
-
- data = ffs_prepare_buffer(buf, len);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- break;
- }
-
- /* Handle data */
- if (ffs->state == FFS_READ_DESCRIPTORS) {
- pr_info("read descriptors\n");
- ret = __ffs_data_got_descs(ffs, data, len);
- if (unlikely(ret < 0))
- break;
-
- ffs->state = FFS_READ_STRINGS;
- ret = len;
- } else {
- pr_info("read strings\n");
- ret = __ffs_data_got_strings(ffs, data, len);
- if (unlikely(ret < 0))
- break;
-
- ret = ffs_epfiles_create(ffs);
- if (unlikely(ret)) {
- ffs->state = FFS_CLOSING;
- break;
- }
-
- ffs->state = FFS_ACTIVE;
- mutex_unlock(&ffs->mutex);
-
- ret = functionfs_ready_callback(ffs);
- if (unlikely(ret < 0)) {
- ffs->state = FFS_CLOSING;
- return ret;
- }
-
- set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags);
- return len;
- }
- break;
-
- case FFS_ACTIVE:
- data = NULL;
- /*
- * We're called from user space, we can use _irq
- * rather then _irqsave
- */
- spin_lock_irq(&ffs->ev.waitq.lock);
- switch (FFS_SETUP_STATE(ffs)) {
- case FFS_SETUP_CANCELED:
- ret = -EIDRM;
- goto done_spin;
-
- case FFS_NO_SETUP:
- ret = -ESRCH;
- goto done_spin;
-
- case FFS_SETUP_PENDING:
- break;
- }
-
- /* FFS_SETUP_PENDING */
- if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
- spin_unlock_irq(&ffs->ev.waitq.lock);
- ret = __ffs_ep0_stall(ffs);
- break;
- }
-
- /* FFS_SETUP_PENDING and not stall */
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
-
- spin_unlock_irq(&ffs->ev.waitq.lock);
-
- data = ffs_prepare_buffer(buf, len);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- break;
- }
-
- spin_lock_irq(&ffs->ev.waitq.lock);
-
- /*
- * We are guaranteed to be still in FFS_ACTIVE state
- * but the state of setup could have changed from
- * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need
- * to check for that. If that happened we copied data
- * from user space in vain but it's unlikely.
- *
- * For sure we are not in FFS_NO_SETUP since this is
- * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
- * transition can be performed and it's protected by
- * mutex.
- */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
- ret = -EIDRM;
-done_spin:
- spin_unlock_irq(&ffs->ev.waitq.lock);
- } else {
- /* unlocks spinlock */
- ret = __ffs_ep0_queue_wait(ffs, data, len);
- }
- kfree(data);
- break;
-
- default:
- ret = -EBADFD;
- break;
- }
-
- mutex_unlock(&ffs->mutex);
- return ret;
-}
-
-static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
- size_t n)
-{
- /*
- * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
- * to release them.
- */
- struct usb_functionfs_event events[n];
- unsigned i = 0;
-
- memset(events, 0, sizeof events);
-
- do {
- events[i].type = ffs->ev.types[i];
- if (events[i].type == FUNCTIONFS_SETUP) {
- events[i].u.setup = ffs->ev.setup;
- ffs->setup_state = FFS_SETUP_PENDING;
- }
- } while (++i < n);
-
- if (n < ffs->ev.count) {
- ffs->ev.count -= n;
- memmove(ffs->ev.types, ffs->ev.types + n,
- ffs->ev.count * sizeof *ffs->ev.types);
- } else {
- ffs->ev.count = 0;
- }
-
- spin_unlock_irq(&ffs->ev.waitq.lock);
- mutex_unlock(&ffs->mutex);
-
- return unlikely(__copy_to_user(buf, events, sizeof events))
- ? -EFAULT : sizeof events;
-}
-
-static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
- size_t len, loff_t *ptr)
-{
- struct ffs_data *ffs = file->private_data;
- char *data = NULL;
- size_t n;
- int ret;
-
- ENTER();
-
- /* Fast check if setup was canceled */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED)
- return -EIDRM;
-
- /* Acquire mutex */
- ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
- if (unlikely(ret < 0))
- return ret;
-
- /* Check state */
- if (ffs->state != FFS_ACTIVE) {
- ret = -EBADFD;
- goto done_mutex;
- }
-
- /*
- * We're called from user space, we can use _irq rather then
- * _irqsave
- */
- spin_lock_irq(&ffs->ev.waitq.lock);
-
- switch (FFS_SETUP_STATE(ffs)) {
- case FFS_SETUP_CANCELED:
- ret = -EIDRM;
- break;
-
- case FFS_NO_SETUP:
- n = len / sizeof(struct usb_functionfs_event);
- if (unlikely(!n)) {
- ret = -EINVAL;
- break;
- }
-
- if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) {
- ret = -EAGAIN;
- break;
- }
-
- if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq,
- ffs->ev.count)) {
- ret = -EINTR;
- break;
- }
-
- return __ffs_ep0_read_events(ffs, buf,
- min(n, (size_t)ffs->ev.count));
-
- case FFS_SETUP_PENDING:
- if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
- spin_unlock_irq(&ffs->ev.waitq.lock);
- ret = __ffs_ep0_stall(ffs);
- goto done_mutex;
- }
-
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
-
- spin_unlock_irq(&ffs->ev.waitq.lock);
-
- if (likely(len)) {
- data = kmalloc(len, GFP_KERNEL);
- if (unlikely(!data)) {
- ret = -ENOMEM;
- goto done_mutex;
- }
- }
-
- spin_lock_irq(&ffs->ev.waitq.lock);
-
- /* See ffs_ep0_write() */
- if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) {
- ret = -EIDRM;
- break;
- }
-
- /* unlocks spinlock */
- ret = __ffs_ep0_queue_wait(ffs, data, len);
- if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
- ret = -EFAULT;
- goto done_mutex;
-
- default:
- ret = -EBADFD;
- break;
- }
-
- spin_unlock_irq(&ffs->ev.waitq.lock);
-done_mutex:
- mutex_unlock(&ffs->mutex);
- kfree(data);
- return ret;
-}
-
-static int ffs_ep0_open(struct inode *inode, struct file *file)
-{
- struct ffs_data *ffs = inode->i_private;
-
- ENTER();
-
- if (unlikely(ffs->state == FFS_CLOSING))
- return -EBUSY;
-
- file->private_data = ffs;
- ffs_data_opened(ffs);
-
- return 0;
-}
-
-static int ffs_ep0_release(struct inode *inode, struct file *file)
-{
- struct ffs_data *ffs = file->private_data;
-
- ENTER();
-
- ffs_data_closed(ffs);
-
- return 0;
-}
-
-static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
-{
- struct ffs_data *ffs = file->private_data;
- struct usb_gadget *gadget = ffs->gadget;
- long ret;
-
- ENTER();
-
- if (code == FUNCTIONFS_INTERFACE_REVMAP) {
- struct ffs_function *func = ffs->func;
- ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
- } else if (gadget && gadget->ops->ioctl) {
- ret = gadget->ops->ioctl(gadget, code, value);
- } else {
- ret = -ENOTTY;
- }
-
- return ret;
-}
-
-static const struct file_operations ffs_ep0_operations = {
- .llseek = no_llseek,
-
- .open = ffs_ep0_open,
- .write = ffs_ep0_write,
- .read = ffs_ep0_read,
- .release = ffs_ep0_release,
- .unlocked_ioctl = ffs_ep0_ioctl,
-};
-
-
-/* "Normal" endpoints operations ********************************************/
-
-static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)
-{
- ENTER();
- if (likely(req->context)) {
- struct ffs_ep *ep = _ep->driver_data;
- ep->status = req->status ? req->status : req->actual;
- complete(req->context);
- }
-}
-
-static ssize_t ffs_epfile_io(struct file *file,
- char __user *buf, size_t len, int read)
-{
- struct ffs_epfile *epfile = file->private_data;
- struct ffs_ep *ep;
- char *data = NULL;
- ssize_t ret;
- int halt;
-
- goto first_try;
- do {
- spin_unlock_irq(&epfile->ffs->eps_lock);
- mutex_unlock(&epfile->mutex);
-
-first_try:
- /* Are we still active? */
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) {
- ret = -ENODEV;
- goto error;
- }
-
- /* Wait for endpoint to be enabled */
- ep = epfile->ep;
- if (!ep) {
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- goto error;
- }
-
- if (wait_event_interruptible(epfile->wait,
- (ep = epfile->ep))) {
- ret = -EINTR;
- goto error;
- }
- }
-
- /* Do we halt? */
- halt = !read == !epfile->in;
- if (halt && epfile->isoc) {
- ret = -EINVAL;
- goto error;
- }
-
- /* Allocate & copy */
- if (!halt && !data) {
- data = kzalloc(len, GFP_KERNEL);
- if (unlikely(!data))
- return -ENOMEM;
-
- if (!read &&
- unlikely(__copy_from_user(data, buf, len))) {
- ret = -EFAULT;
- goto error;
- }
- }
-
- /* We will be using request */
- ret = ffs_mutex_lock(&epfile->mutex,
- file->f_flags & O_NONBLOCK);
- if (unlikely(ret))
- goto error;
-
- /*
- * We're called from user space, we can use _irq rather then
- * _irqsave
- */
- spin_lock_irq(&epfile->ffs->eps_lock);
-
- /*
- * While we were acquiring mutex endpoint got disabled
- * or changed?
- */
- } while (unlikely(epfile->ep != ep));
-
- /* Halt */
- if (unlikely(halt)) {
- if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))
- usb_ep_set_halt(ep->ep);
- spin_unlock_irq(&epfile->ffs->eps_lock);
- ret = -EBADMSG;
- } else {
- /* Fire the request */
- DECLARE_COMPLETION_ONSTACK(done);
-
- struct usb_request *req = ep->req;
- req->context = &done;
- req->complete = ffs_epfile_io_complete;
- req->buf = data;
- req->length = len;
-
- ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
-
- spin_unlock_irq(&epfile->ffs->eps_lock);
-
- if (unlikely(ret < 0)) {
- /* nop */
- } else if (unlikely(wait_for_completion_interruptible(&done))) {
- ret = -EINTR;
- usb_ep_dequeue(ep->ep, req);
- } else {
- ret = ep->status;
- if (read && ret > 0 &&
- unlikely(copy_to_user(buf, data, ret)))
- ret = -EFAULT;
- }
- }
-
- mutex_unlock(&epfile->mutex);
-error:
- kfree(data);
- return ret;
-}
-
-static ssize_t
-ffs_epfile_write(struct file *file, const char __user *buf, size_t len,
- loff_t *ptr)
-{
- ENTER();
-
- return ffs_epfile_io(file, (char __user *)buf, len, 0);
-}
-
-static ssize_t
-ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)
-{
- ENTER();
-
- return ffs_epfile_io(file, buf, len, 1);
-}
-
-static int
-ffs_epfile_open(struct inode *inode, struct file *file)
-{
- struct ffs_epfile *epfile = inode->i_private;
-
- ENTER();
-
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
- return -ENODEV;
-
- file->private_data = epfile;
- ffs_data_opened(epfile->ffs);
-
- return 0;
-}
-
-static int
-ffs_epfile_release(struct inode *inode, struct file *file)
-{
- struct ffs_epfile *epfile = inode->i_private;
-
- ENTER();
-
- ffs_data_closed(epfile->ffs);
-
- return 0;
-}
-
-static long ffs_epfile_ioctl(struct file *file, unsigned code,
- unsigned long value)
-{
- struct ffs_epfile *epfile = file->private_data;
- int ret;
-
- ENTER();
-
- if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
- return -ENODEV;
-
- spin_lock_irq(&epfile->ffs->eps_lock);
- if (likely(epfile->ep)) {
- switch (code) {
- case FUNCTIONFS_FIFO_STATUS:
- ret = usb_ep_fifo_status(epfile->ep->ep);
- break;
- case FUNCTIONFS_FIFO_FLUSH:
- usb_ep_fifo_flush(epfile->ep->ep);
- ret = 0;
- break;
- case FUNCTIONFS_CLEAR_HALT:
- ret = usb_ep_clear_halt(epfile->ep->ep);
- break;
- case FUNCTIONFS_ENDPOINT_REVMAP:
- ret = epfile->ep->num;
- break;
- default:
- ret = -ENOTTY;
- }
- } else {
- ret = -ENODEV;
- }
- spin_unlock_irq(&epfile->ffs->eps_lock);
-
- return ret;
-}
-
-static const struct file_operations ffs_epfile_operations = {
- .llseek = no_llseek,
-
- .open = ffs_epfile_open,
- .write = ffs_epfile_write,
- .read = ffs_epfile_read,
- .release = ffs_epfile_release,
- .unlocked_ioctl = ffs_epfile_ioctl,
-};
-
-
-/* File system and super block operations ***********************************/
-
-/*
- * Mounting the file system creates a controller file, used first for
- * function configuration then later for event monitoring.
- */
-
-static struct inode *__must_check
-ffs_sb_make_inode(struct super_block *sb, void *data,
- const struct file_operations *fops,
- const struct inode_operations *iops,
- struct ffs_file_perms *perms)
-{
- struct inode *inode;
-
- ENTER();
-
- inode = new_inode(sb);
-
- if (likely(inode)) {
- struct timespec current_time = CURRENT_TIME;
-
- inode->i_ino = get_next_ino();
- inode->i_mode = perms->mode;
- inode->i_uid = perms->uid;
- inode->i_gid = perms->gid;
- inode->i_atime = current_time;
- inode->i_mtime = current_time;
- inode->i_ctime = current_time;
- inode->i_private = data;
- if (fops)
- inode->i_fop = fops;
- if (iops)
- inode->i_op = iops;
- }
-
- return inode;
-}
-
-/* Create "regular" file */
-static struct inode *ffs_sb_create_file(struct super_block *sb,
- const char *name, void *data,
- const struct file_operations *fops,
- struct dentry **dentry_p)
-{
- struct ffs_data *ffs = sb->s_fs_info;
- struct dentry *dentry;
- struct inode *inode;
-
- ENTER();
-
- dentry = d_alloc_name(sb->s_root, name);
- if (unlikely(!dentry))
- return NULL;
-
- inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
- if (unlikely(!inode)) {
- dput(dentry);
- return NULL;
- }
-
- d_add(dentry, inode);
- if (dentry_p)
- *dentry_p = dentry;
-
- return inode;
-}
-
-/* Super block */
-static const struct super_operations ffs_sb_operations = {
- .statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
-};
-
-struct ffs_sb_fill_data {
- struct ffs_file_perms perms;
- umode_t root_mode;
- const char *dev_name;
- union {
- /* set by ffs_fs_mount(), read by ffs_sb_fill() */
- void *private_data;
- /* set by ffs_sb_fill(), read by ffs_fs_mount */
- struct ffs_data *ffs_data;
- };
-};
-
-static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
-{
- struct ffs_sb_fill_data *data = _data;
- struct inode *inode;
- struct ffs_data *ffs;
-
- ENTER();
-
- /* Initialise data */
- ffs = ffs_data_new();
- if (unlikely(!ffs))
- goto Enomem;
-
- ffs->sb = sb;
- ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL);
- if (unlikely(!ffs->dev_name))
- goto Enomem;
- ffs->file_perms = data->perms;
- ffs->private_data = data->private_data;
-
- /* used by the caller of this function */
- data->ffs_data = ffs;
-
- sb->s_fs_info = ffs;
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = FUNCTIONFS_MAGIC;
- sb->s_op = &ffs_sb_operations;
- sb->s_time_gran = 1;
-
- /* Root inode */
- data->perms.mode = data->root_mode;
- inode = ffs_sb_make_inode(sb, NULL,
- &simple_dir_operations,
- &simple_dir_inode_operations,
- &data->perms);
- sb->s_root = d_make_root(inode);
- if (unlikely(!sb->s_root))
- goto Enomem;
-
- /* EP0 file */
- if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
- &ffs_ep0_operations, NULL)))
- goto Enomem;
-
- return 0;
-
-Enomem:
- return -ENOMEM;
-}
-
-static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
-{
- ENTER();
-
- if (!opts || !*opts)
- return 0;
-
- for (;;) {
- char *end, *eq, *comma;
- unsigned long value;
-
- /* Option limit */
- comma = strchr(opts, ',');
- if (comma)
- *comma = 0;
-
- /* Value limit */
- eq = strchr(opts, '=');
- if (unlikely(!eq)) {
- pr_err("'=' missing in %s\n", opts);
- return -EINVAL;
- }
- *eq = 0;
-
- /* Parse value */
- value = simple_strtoul(eq + 1, &end, 0);
- if (unlikely(*end != ',' && *end != 0)) {
- pr_err("%s: invalid value: %s\n", opts, eq + 1);
- return -EINVAL;
- }
-
- /* Interpret option */
- switch (eq - opts) {
- case 5:
- if (!memcmp(opts, "rmode", 5))
- data->root_mode = (value & 0555) | S_IFDIR;
- else if (!memcmp(opts, "fmode", 5))
- data->perms.mode = (value & 0666) | S_IFREG;
- else
- goto invalid;
- break;
-
- case 4:
- if (!memcmp(opts, "mode", 4)) {
- data->root_mode = (value & 0555) | S_IFDIR;
- data->perms.mode = (value & 0666) | S_IFREG;
- } else {
- goto invalid;
- }
- break;
-
- case 3:
- if (!memcmp(opts, "uid", 3))
- data->perms.uid = value;
- else if (!memcmp(opts, "gid", 3))
- data->perms.gid = value;
- else
- goto invalid;
- break;
-
- default:
-invalid:
- pr_err("%s: invalid option\n", opts);
- return -EINVAL;
- }
-
- /* Next iteration */
- if (!comma)
- break;
- opts = comma + 1;
- }
-
- return 0;
-}
-
-/* "mount -t functionfs dev_name /dev/function" ends up here */
-
-static struct dentry *
-ffs_fs_mount(struct file_system_type *t, int flags,
- const char *dev_name, void *opts)
-{
- struct ffs_sb_fill_data data = {
- .perms = {
- .mode = S_IFREG | 0600,
- .uid = 0,
- .gid = 0
- },
- .root_mode = S_IFDIR | 0500,
- };
- struct dentry *rv;
- int ret;
- void *ffs_dev;
-
- ENTER();
-
- ret = ffs_fs_parse_opts(&data, opts);
- if (unlikely(ret < 0))
- return ERR_PTR(ret);
-
- ffs_dev = functionfs_acquire_dev_callback(dev_name);
- if (IS_ERR(ffs_dev))
- return ffs_dev;
-
- data.dev_name = dev_name;
- data.private_data = ffs_dev;
- rv = mount_nodev(t, flags, &data, ffs_sb_fill);
-
- /* data.ffs_data is set by ffs_sb_fill */
- if (IS_ERR(rv))
- functionfs_release_dev_callback(data.ffs_data);
-
- return rv;
-}
-
-static void
-ffs_fs_kill_sb(struct super_block *sb)
-{
- ENTER();
-
- kill_litter_super(sb);
- if (sb->s_fs_info) {
- functionfs_release_dev_callback(sb->s_fs_info);
- ffs_data_put(sb->s_fs_info);
- }
-}
-
-static struct file_system_type ffs_fs_type = {
- .owner = THIS_MODULE,
- .name = "functionfs",
- .mount = ffs_fs_mount,
- .kill_sb = ffs_fs_kill_sb,
-};
-MODULE_ALIAS_FS("functionfs");
-
-
-/* Driver's main init/cleanup functions *************************************/
-
-static int functionfs_init(void)
-{
- int ret;
-
- ENTER();
-
- ret = register_filesystem(&ffs_fs_type);
- if (likely(!ret))
- pr_info("file system registered\n");
- else
- pr_err("failed registering file system (%d)\n", ret);
-
- return ret;
-}
-
-static void functionfs_cleanup(void)
-{
- ENTER();
-
- pr_info("unloading\n");
- unregister_filesystem(&ffs_fs_type);
-}
-
-
-/* ffs_data and ffs_function construction and destruction code **************/
-
-static void ffs_data_clear(struct ffs_data *ffs);
-static void ffs_data_reset(struct ffs_data *ffs);
-
-static void ffs_data_get(struct ffs_data *ffs)
-{
- ENTER();
-
- atomic_inc(&ffs->ref);
-}
-
-static void ffs_data_opened(struct ffs_data *ffs)
-{
- ENTER();
-
- atomic_inc(&ffs->ref);
- atomic_inc(&ffs->opened);
-}
-
-static void ffs_data_put(struct ffs_data *ffs)
-{
- ENTER();
-
- if (unlikely(atomic_dec_and_test(&ffs->ref))) {
- pr_info("%s(): freeing\n", __func__);
- ffs_data_clear(ffs);
- BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
- waitqueue_active(&ffs->ep0req_completion.wait));
- kfree(ffs->dev_name);
- kfree(ffs);
- }
-}
-
-static void ffs_data_closed(struct ffs_data *ffs)
-{
- ENTER();
-
- if (atomic_dec_and_test(&ffs->opened)) {
- ffs->state = FFS_CLOSING;
- ffs_data_reset(ffs);
- }
-
- ffs_data_put(ffs);
-}
-
-static struct ffs_data *ffs_data_new(void)
-{
- struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);
- if (unlikely(!ffs))
- return 0;
-
- ENTER();
-
- atomic_set(&ffs->ref, 1);
- atomic_set(&ffs->opened, 0);
- ffs->state = FFS_READ_DESCRIPTORS;
- mutex_init(&ffs->mutex);
- spin_lock_init(&ffs->eps_lock);
- init_waitqueue_head(&ffs->ev.waitq);
- init_completion(&ffs->ep0req_completion);
-
- /* XXX REVISIT need to update it in some places, or do we? */
- ffs->ev.can_stall = 1;
-
- return ffs;
-}
-
-static void ffs_data_clear(struct ffs_data *ffs)
-{
- ENTER();
-
- if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags))
- functionfs_closed_callback(ffs);
-
- BUG_ON(ffs->gadget);
-
- if (ffs->epfiles)
- ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
-
- kfree(ffs->raw_descs);
- kfree(ffs->raw_strings);
- kfree(ffs->stringtabs);
-}
-
-static void ffs_data_reset(struct ffs_data *ffs)
-{
- ENTER();
-
- ffs_data_clear(ffs);
-
- ffs->epfiles = NULL;
- ffs->raw_descs = NULL;
- ffs->raw_strings = NULL;
- ffs->stringtabs = NULL;
-
- ffs->raw_descs_length = 0;
- ffs->raw_fs_descs_length = 0;
- ffs->fs_descs_count = 0;
- ffs->hs_descs_count = 0;
-
- ffs->strings_count = 0;
- ffs->interfaces_count = 0;
- ffs->eps_count = 0;
-
- ffs->ev.count = 0;
-
- ffs->state = FFS_READ_DESCRIPTORS;
- ffs->setup_state = FFS_NO_SETUP;
- ffs->flags = 0;
-}
-
-
-static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
-{
- struct usb_gadget_strings **lang;
- int first_id;
-
- ENTER();
-
- if (WARN_ON(ffs->state != FFS_ACTIVE
- || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
- return -EBADFD;
-
- first_id = usb_string_ids_n(cdev, ffs->strings_count);
- if (unlikely(first_id < 0))
- return first_id;
-
- ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
- if (unlikely(!ffs->ep0req))
- return -ENOMEM;
- ffs->ep0req->complete = ffs_ep0_complete;
- ffs->ep0req->context = ffs;
-
- lang = ffs->stringtabs;
- for (lang = ffs->stringtabs; *lang; ++lang) {
- struct usb_string *str = (*lang)->strings;
- int id = first_id;
- for (; str->s; ++id, ++str)
- str->id = id;
- }
-
- ffs->gadget = cdev->gadget;
- ffs_data_get(ffs);
- return 0;
-}
-
-static void functionfs_unbind(struct ffs_data *ffs)
-{
- ENTER();
-
- if (!WARN_ON(!ffs->gadget)) {
- usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
- ffs->ep0req = NULL;
- ffs->gadget = NULL;
- ffs_data_put(ffs);
- clear_bit(FFS_FL_BOUND, &ffs->flags);
- }
-}
-
-static int ffs_epfiles_create(struct ffs_data *ffs)
-{
- struct ffs_epfile *epfile, *epfiles;
- unsigned i, count;
-
- ENTER();
-
- count = ffs->eps_count;
- epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
- if (!epfiles)
- return -ENOMEM;
-
- epfile = epfiles;
- for (i = 1; i <= count; ++i, ++epfile) {
- epfile->ffs = ffs;
- mutex_init(&epfile->mutex);
- init_waitqueue_head(&epfile->wait);
- sprintf(epfiles->name, "ep%u", i);
- if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile,
- &ffs_epfile_operations,
- &epfile->dentry))) {
- ffs_epfiles_destroy(epfiles, i - 1);
- return -ENOMEM;
- }
- }
-
- ffs->epfiles = epfiles;
- return 0;
-}
-
-static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
-{
- struct ffs_epfile *epfile = epfiles;
-
- ENTER();
-
- for (; count; --count, ++epfile) {
- BUG_ON(mutex_is_locked(&epfile->mutex) ||
- waitqueue_active(&epfile->wait));
- if (epfile->dentry) {
- d_delete(epfile->dentry);
- dput(epfile->dentry);
- epfile->dentry = NULL;
- }
- }
-
- kfree(epfiles);
-}
-
-static int functionfs_bind_config(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct ffs_data *ffs)
-{
- struct ffs_function *func;
- int ret;
-
- ENTER();
-
- func = kzalloc(sizeof *func, GFP_KERNEL);
- if (unlikely(!func))
- return -ENOMEM;
-
- func->function.name = "Function FS Gadget";
- func->function.strings = ffs->stringtabs;
-
- func->function.bind = ffs_func_bind;
- func->function.unbind = ffs_func_unbind;
- func->function.set_alt = ffs_func_set_alt;
- func->function.disable = ffs_func_disable;
- func->function.setup = ffs_func_setup;
- func->function.suspend = ffs_func_suspend;
- func->function.resume = ffs_func_resume;
-
- func->conf = c;
- func->gadget = cdev->gadget;
- func->ffs = ffs;
- ffs_data_get(ffs);
-
- ret = usb_add_function(c, &func->function);
- if (unlikely(ret))
- ffs_func_free(func);
-
- return ret;
-}
-
-static void ffs_func_free(struct ffs_function *func)
-{
- struct ffs_ep *ep = func->eps;
- unsigned count = func->ffs->eps_count;
- unsigned long flags;
-
- ENTER();
-
- /* cleanup after autoconfig */
- spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
- if (ep->ep && ep->req)
- usb_ep_free_request(ep->ep, ep->req);
- ep->req = NULL;
- ++ep;
- } while (--count);
- spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
-
- ffs_data_put(func->ffs);
-
- kfree(func->eps);
- /*
- * eps and interfaces_nums are allocated in the same chunk so
- * only one free is required. Descriptors are also allocated
- * in the same chunk.
- */
-
- kfree(func);
-}
-
-static void ffs_func_eps_disable(struct ffs_function *func)
-{
- struct ffs_ep *ep = func->eps;
- struct ffs_epfile *epfile = func->ffs->epfiles;
- unsigned count = func->ffs->eps_count;
- unsigned long flags;
-
- spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
- /* pending requests get nuked */
- if (likely(ep->ep))
- usb_ep_disable(ep->ep);
- epfile->ep = NULL;
-
- ++ep;
- ++epfile;
- } while (--count);
- spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
-}
-
-static int ffs_func_eps_enable(struct ffs_function *func)
-{
- struct ffs_data *ffs = func->ffs;
- struct ffs_ep *ep = func->eps;
- struct ffs_epfile *epfile = ffs->epfiles;
- unsigned count = ffs->eps_count;
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
- struct usb_endpoint_descriptor *ds;
- ds = ep->descs[ep->descs[1] ? 1 : 0];
-
- ep->ep->driver_data = ep;
- ep->ep->desc = ds;
- ret = usb_ep_enable(ep->ep);
- if (likely(!ret)) {
- epfile->ep = ep;
- epfile->in = usb_endpoint_dir_in(ds);
- epfile->isoc = usb_endpoint_xfer_isoc(ds);
- } else {
- break;
- }
-
- wake_up(&epfile->wait);
-
- ++ep;
- ++epfile;
- } while (--count);
- spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
-
- return ret;
-}
-
-
-/* Parsing and building descriptors and strings *****************************/
-
-/*
- * This validates if data pointed by data is a valid USB descriptor as
- * well as record how many interfaces, endpoints and strings are
- * required by given configuration. Returns address after the
- * descriptor or NULL if data is invalid.
- */
-
-enum ffs_entity_type {
- FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT
-};
-
-typedef int (*ffs_entity_callback)(enum ffs_entity_type entity,
- u8 *valuep,
- struct usb_descriptor_header *desc,
- void *priv);
-
-static int __must_check ffs_do_desc(char *data, unsigned len,
- ffs_entity_callback entity, void *priv)
-{
- struct usb_descriptor_header *_ds = (void *)data;
- u8 length;
- int ret;
-
- ENTER();
-
- /* At least two bytes are required: length and type */
- if (len < 2) {
- pr_vdebug("descriptor too short\n");
- return -EINVAL;
- }
-
- /* If we have at least as many bytes as the descriptor takes? */
- length = _ds->bLength;
- if (len < length) {
- pr_vdebug("descriptor longer then available data\n");
- return -EINVAL;
- }
-
-#define __entity_check_INTERFACE(val) 1
-#define __entity_check_STRING(val) (val)
-#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK)
-#define __entity(type, val) do { \
- pr_vdebug("entity " #type "(%02x)\n", (val)); \
- if (unlikely(!__entity_check_ ##type(val))) { \
- pr_vdebug("invalid entity's value\n"); \
- return -EINVAL; \
- } \
- ret = entity(FFS_ ##type, &val, _ds, priv); \
- if (unlikely(ret < 0)) { \
- pr_debug("entity " #type "(%02x); ret = %d\n", \
- (val), ret); \
- return ret; \
- } \
- } while (0)
-
- /* Parse descriptor depending on type. */
- switch (_ds->bDescriptorType) {
- case USB_DT_DEVICE:
- case USB_DT_CONFIG:
- case USB_DT_STRING:
- case USB_DT_DEVICE_QUALIFIER:
- /* function can't have any of those */
- pr_vdebug("descriptor reserved for gadget: %d\n",
- _ds->bDescriptorType);
- return -EINVAL;
-
- case USB_DT_INTERFACE: {
- struct usb_interface_descriptor *ds = (void *)_ds;
- pr_vdebug("interface descriptor\n");
- if (length != sizeof *ds)
- goto inv_length;
-
- __entity(INTERFACE, ds->bInterfaceNumber);
- if (ds->iInterface)
- __entity(STRING, ds->iInterface);
- }
- break;
-
- case USB_DT_ENDPOINT: {
- struct usb_endpoint_descriptor *ds = (void *)_ds;
- pr_vdebug("endpoint descriptor\n");
- if (length != USB_DT_ENDPOINT_SIZE &&
- length != USB_DT_ENDPOINT_AUDIO_SIZE)
- goto inv_length;
- __entity(ENDPOINT, ds->bEndpointAddress);
- }
- break;
-
- case HID_DT_HID:
- pr_vdebug("hid descriptor\n");
- if (length != sizeof(struct hid_descriptor))
- goto inv_length;
- break;
-
- case USB_DT_OTG:
- if (length != sizeof(struct usb_otg_descriptor))
- goto inv_length;
- break;
-
- case USB_DT_INTERFACE_ASSOCIATION: {
- struct usb_interface_assoc_descriptor *ds = (void *)_ds;
- pr_vdebug("interface association descriptor\n");
- if (length != sizeof *ds)
- goto inv_length;
- if (ds->iFunction)
- __entity(STRING, ds->iFunction);
- }
- break;
-
- case USB_DT_OTHER_SPEED_CONFIG:
- case USB_DT_INTERFACE_POWER:
- case USB_DT_DEBUG:
- case USB_DT_SECURITY:
- case USB_DT_CS_RADIO_CONTROL:
- /* TODO */
- pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType);
- return -EINVAL;
-
- default:
- /* We should never be here */
- pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType);
- return -EINVAL;
-
-inv_length:
- pr_vdebug("invalid length: %d (descriptor %d)\n",
- _ds->bLength, _ds->bDescriptorType);
- return -EINVAL;
- }
-
-#undef __entity
-#undef __entity_check_DESCRIPTOR
-#undef __entity_check_INTERFACE
-#undef __entity_check_STRING
-#undef __entity_check_ENDPOINT
-
- return length;
-}
-
-static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len,
- ffs_entity_callback entity, void *priv)
-{
- const unsigned _len = len;
- unsigned long num = 0;
-
- ENTER();
-
- for (;;) {
- int ret;
-
- if (num == count)
- data = NULL;
-
- /* Record "descriptor" entity */
- ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv);
- if (unlikely(ret < 0)) {
- pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n",
- num, ret);
- return ret;
- }
-
- if (!data)
- return _len - len;
-
- ret = ffs_do_desc(data, len, entity, priv);
- if (unlikely(ret < 0)) {
- pr_debug("%s returns %d\n", __func__, ret);
- return ret;
- }
-
- len -= ret;
- data += ret;
- ++num;
- }
-}
-
-static int __ffs_data_do_entity(enum ffs_entity_type type,
- u8 *valuep, struct usb_descriptor_header *desc,
- void *priv)
-{
- struct ffs_data *ffs = priv;
-
- ENTER();
-
- switch (type) {
- case FFS_DESCRIPTOR:
- break;
-
- case FFS_INTERFACE:
- /*
- * Interfaces are indexed from zero so if we
- * encountered interface "n" then there are at least
- * "n+1" interfaces.
- */
- if (*valuep >= ffs->interfaces_count)
- ffs->interfaces_count = *valuep + 1;
- break;
-
- case FFS_STRING:
- /*
- * Strings are indexed from 1 (0 is magic ;) reserved
- * for languages list or some such)
- */
- if (*valuep > ffs->strings_count)
- ffs->strings_count = *valuep;
- break;
-
- case FFS_ENDPOINT:
- /* Endpoints are indexed from 1 as well. */
- if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
- ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
- break;
- }
-
- return 0;
-}
-
-static int __ffs_data_got_descs(struct ffs_data *ffs,
- char *const _data, size_t len)
-{
- unsigned fs_count, hs_count;
- int fs_len, ret = -EINVAL;
- char *data = _data;
-
- ENTER();
-
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC ||
- get_unaligned_le32(data + 4) != len))
- goto error;
- fs_count = get_unaligned_le32(data + 8);
- hs_count = get_unaligned_le32(data + 12);
-
- if (!fs_count && !hs_count)
- goto einval;
-
- data += 16;
- len -= 16;
-
- if (likely(fs_count)) {
- fs_len = ffs_do_descs(fs_count, data, len,
- __ffs_data_do_entity, ffs);
- if (unlikely(fs_len < 0)) {
- ret = fs_len;
- goto error;
- }
-
- data += fs_len;
- len -= fs_len;
- } else {
- fs_len = 0;
- }
-
- if (likely(hs_count)) {
- ret = ffs_do_descs(hs_count, data, len,
- __ffs_data_do_entity, ffs);
- if (unlikely(ret < 0))
- goto error;
- } else {
- ret = 0;
- }
-
- if (unlikely(len != ret))
- goto einval;
-
- ffs->raw_fs_descs_length = fs_len;
- ffs->raw_descs_length = fs_len + ret;
- ffs->raw_descs = _data;
- ffs->fs_descs_count = fs_count;
- ffs->hs_descs_count = hs_count;
-
- return 0;
-
-einval:
- ret = -EINVAL;
-error:
- kfree(_data);
- return ret;
-}
-
-static int __ffs_data_got_strings(struct ffs_data *ffs,
- char *const _data, size_t len)
-{
- u32 str_count, needed_count, lang_count;
- struct usb_gadget_strings **stringtabs, *t;
- struct usb_string *strings, *s;
- const char *data = _data;
-
- ENTER();
-
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
- get_unaligned_le32(data + 4) != len))
- goto error;
- str_count = get_unaligned_le32(data + 8);
- lang_count = get_unaligned_le32(data + 12);
-
- /* if one is zero the other must be zero */
- if (unlikely(!str_count != !lang_count))
- goto error;
-
- /* Do we have at least as many strings as descriptors need? */
- needed_count = ffs->strings_count;
- if (unlikely(str_count < needed_count))
- goto error;
-
- /*
- * If we don't need any strings just return and free all
- * memory.
- */
- if (!needed_count) {
- kfree(_data);
- return 0;
- }
-
- /* Allocate everything in one chunk so there's less maintenance. */
- {
- struct {
- struct usb_gadget_strings *stringtabs[lang_count + 1];
- struct usb_gadget_strings stringtab[lang_count];
- struct usb_string strings[lang_count*(needed_count+1)];
- } *d;
- unsigned i = 0;
-
- d = kmalloc(sizeof *d, GFP_KERNEL);
- if (unlikely(!d)) {
- kfree(_data);
- return -ENOMEM;
- }
-
- stringtabs = d->stringtabs;
- t = d->stringtab;
- i = lang_count;
- do {
- *stringtabs++ = t++;
- } while (--i);
- *stringtabs = NULL;
-
- stringtabs = d->stringtabs;
- t = d->stringtab;
- s = d->strings;
- strings = s;
- }
-
- /* For each language */
- data += 16;
- len -= 16;
-
- do { /* lang_count > 0 so we can use do-while */
- unsigned needed = needed_count;
-
- if (unlikely(len < 3))
- goto error_free;
- t->language = get_unaligned_le16(data);
- t->strings = s;
- ++t;
-
- data += 2;
- len -= 2;
-
- /* For each string */
- do { /* str_count > 0 so we can use do-while */
- size_t length = strnlen(data, len);
-
- if (unlikely(length == len))
- goto error_free;
-
- /*
- * User may provide more strings then we need,
- * if that's the case we simply ignore the
- * rest
- */
- if (likely(needed)) {
- /*
- * s->id will be set while adding
- * function to configuration so for
- * now just leave garbage here.
- */
- s->s = data;
- --needed;
- ++s;
- }
-
- data += length + 1;
- len -= length + 1;
- } while (--str_count);
-
- s->id = 0; /* terminator */
- s->s = NULL;
- ++s;
-
- } while (--lang_count);
-
- /* Some garbage left? */
- if (unlikely(len))
- goto error_free;
-
- /* Done! */
- ffs->stringtabs = stringtabs;
- ffs->raw_strings = _data;
-
- return 0;
-
-error_free:
- kfree(stringtabs);
-error:
- kfree(_data);
- return -EINVAL;
-}
-
-
-/* Events handling and management *******************************************/
-
-static void __ffs_event_add(struct ffs_data *ffs,
- enum usb_functionfs_event_type type)
-{
- enum usb_functionfs_event_type rem_type1, rem_type2 = type;
- int neg = 0;
-
- /*
- * Abort any unhandled setup
- *
- * We do not need to worry about some cmpxchg() changing value
- * of ffs->setup_state without holding the lock because when
- * state is FFS_SETUP_PENDING cmpxchg() in several places in
- * the source does nothing.
- */
- if (ffs->setup_state == FFS_SETUP_PENDING)
- ffs->setup_state = FFS_SETUP_CANCELED;
-
- switch (type) {
- case FUNCTIONFS_RESUME:
- rem_type2 = FUNCTIONFS_SUSPEND;
- /* FALL THROUGH */
- case FUNCTIONFS_SUSPEND:
- case FUNCTIONFS_SETUP:
- rem_type1 = type;
- /* Discard all similar events */
- break;
-
- case FUNCTIONFS_BIND:
- case FUNCTIONFS_UNBIND:
- case FUNCTIONFS_DISABLE:
- case FUNCTIONFS_ENABLE:
- /* Discard everything other then power management. */
- rem_type1 = FUNCTIONFS_SUSPEND;
- rem_type2 = FUNCTIONFS_RESUME;
- neg = 1;
- break;
-
- default:
- BUG();
- }
-
- {
- u8 *ev = ffs->ev.types, *out = ev;
- unsigned n = ffs->ev.count;
- for (; n; --n, ++ev)
- if ((*ev == rem_type1 || *ev == rem_type2) == neg)
- *out++ = *ev;
- else
- pr_vdebug("purging event %d\n", *ev);
- ffs->ev.count = out - ffs->ev.types;
- }
-
- pr_vdebug("adding event %d\n", type);
- ffs->ev.types[ffs->ev.count++] = type;
- wake_up_locked(&ffs->ev.waitq);
-}
-
-static void ffs_event_add(struct ffs_data *ffs,
- enum usb_functionfs_event_type type)
-{
- unsigned long flags;
- spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
- __ffs_event_add(ffs, type);
- spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
-}
-
-
-/* Bind/unbind USB function hooks *******************************************/
-
-static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
- struct usb_descriptor_header *desc,
- void *priv)
-{
- struct usb_endpoint_descriptor *ds = (void *)desc;
- struct ffs_function *func = priv;
- struct ffs_ep *ffs_ep;
-
- /*
- * If hs_descriptors is not NULL then we are reading hs
- * descriptors now
- */
- const int isHS = func->function.hs_descriptors != NULL;
- unsigned idx;
-
- if (type != FFS_DESCRIPTOR)
- return 0;
-
- if (isHS)
- func->function.hs_descriptors[(long)valuep] = desc;
- else
- func->function.descriptors[(long)valuep] = desc;
-
- if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
- return 0;
-
- idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
- ffs_ep = func->eps + idx;
-
- if (unlikely(ffs_ep->descs[isHS])) {
- pr_vdebug("two %sspeed descriptors for EP %d\n",
- isHS ? "high" : "full",
- ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
- return -EINVAL;
- }
- ffs_ep->descs[isHS] = ds;
-
- ffs_dump_mem(": Original ep desc", ds, ds->bLength);
- if (ffs_ep->ep) {
- ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress;
- if (!ds->wMaxPacketSize)
- ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize;
- } else {
- struct usb_request *req;
- struct usb_ep *ep;
-
- pr_vdebug("autoconfig\n");
- ep = usb_ep_autoconfig(func->gadget, ds);
- if (unlikely(!ep))
- return -ENOTSUPP;
- ep->driver_data = func->eps + idx;
-
- req = usb_ep_alloc_request(ep, GFP_KERNEL);
- if (unlikely(!req))
- return -ENOMEM;
-
- ffs_ep->ep = ep;
- ffs_ep->req = req;
- func->eps_revmap[ds->bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK] = idx + 1;
- }
- ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
-
- return 0;
-}
-
-static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,
- struct usb_descriptor_header *desc,
- void *priv)
-{
- struct ffs_function *func = priv;
- unsigned idx;
- u8 newValue;
-
- switch (type) {
- default:
- case FFS_DESCRIPTOR:
- /* Handled in previous pass by __ffs_func_bind_do_descs() */
- return 0;
-
- case FFS_INTERFACE:
- idx = *valuep;
- if (func->interfaces_nums[idx] < 0) {
- int id = usb_interface_id(func->conf, &func->function);
- if (unlikely(id < 0))
- return id;
- func->interfaces_nums[idx] = id;
- }
- newValue = func->interfaces_nums[idx];
- break;
-
- case FFS_STRING:
- /* String' IDs are allocated when fsf_data is bound to cdev */
- newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id;
- break;
-
- case FFS_ENDPOINT:
- /*
- * USB_DT_ENDPOINT are handled in
- * __ffs_func_bind_do_descs().
- */
- if (desc->bDescriptorType == USB_DT_ENDPOINT)
- return 0;
-
- idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1;
- if (unlikely(!func->eps[idx].ep))
- return -EINVAL;
-
- {
- struct usb_endpoint_descriptor **descs;
- descs = func->eps[idx].descs;
- newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress;
- }
- break;
- }
-
- pr_vdebug("%02x -> %02x\n", *valuep, newValue);
- *valuep = newValue;
- return 0;
-}
-
-static int ffs_func_bind(struct usb_configuration *c,
- struct usb_function *f)
-{
- struct ffs_function *func = ffs_func_from_usb(f);
- struct ffs_data *ffs = func->ffs;
-
- const int full = !!func->ffs->fs_descs_count;
- const int high = gadget_is_dualspeed(func->gadget) &&
- func->ffs->hs_descs_count;
-
- int ret;
-
- /* Make it a single chunk, less management later on */
- struct {
- struct ffs_ep eps[ffs->eps_count];
- struct usb_descriptor_header
- *fs_descs[full ? ffs->fs_descs_count + 1 : 0];
- struct usb_descriptor_header
- *hs_descs[high ? ffs->hs_descs_count + 1 : 0];
- short inums[ffs->interfaces_count];
- char raw_descs[high ? ffs->raw_descs_length
- : ffs->raw_fs_descs_length];
- } *data;
-
- ENTER();
-
- /* Only high speed but not supported by gadget? */
- if (unlikely(!(full | high)))
- return -ENOTSUPP;
-
- /* Allocate */
- data = kmalloc(sizeof *data, GFP_KERNEL);
- if (unlikely(!data))
- return -ENOMEM;
-
- /* Zero */
- memset(data->eps, 0, sizeof data->eps);
- memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
- memset(data->inums, 0xff, sizeof data->inums);
- for (ret = ffs->eps_count; ret; --ret)
- data->eps[ret].num = -1;
-
- /* Save pointers */
- func->eps = data->eps;
- func->interfaces_nums = data->inums;
-
- /*
- * Go through all the endpoint descriptors and allocate
- * endpoints first, so that later we can rewrite the endpoint
- * numbers without worrying that it may be described later on.
- */
- if (likely(full)) {
- func->function.descriptors = data->fs_descs;
- ret = ffs_do_descs(ffs->fs_descs_count,
- data->raw_descs,
- sizeof data->raw_descs,
- __ffs_func_bind_do_descs, func);
- if (unlikely(ret < 0))
- goto error;
- } else {
- ret = 0;
- }
-
- if (likely(high)) {
- func->function.hs_descriptors = data->hs_descs;
- ret = ffs_do_descs(ffs->hs_descs_count,
- data->raw_descs + ret,
- (sizeof data->raw_descs) - ret,
- __ffs_func_bind_do_descs, func);
- }
-
- /*
- * Now handle interface numbers allocation and interface and
- * endpoint numbers rewriting. We can do that in one go
- * now.
- */
- ret = ffs_do_descs(ffs->fs_descs_count +
- (high ? ffs->hs_descs_count : 0),
- data->raw_descs, sizeof data->raw_descs,
- __ffs_func_bind_do_nums, func);
- if (unlikely(ret < 0))
- goto error;
-
- /* And we're done */
- ffs_event_add(ffs, FUNCTIONFS_BIND);
- return 0;
-
-error:
- /* XXX Do we need to release all claimed endpoints here? */
- return ret;
-}
-
-
-/* Other USB function hooks *************************************************/
-
-static void ffs_func_unbind(struct usb_configuration *c,
- struct usb_function *f)
-{
- struct ffs_function *func = ffs_func_from_usb(f);
- struct ffs_data *ffs = func->ffs;
-
- ENTER();
-
- if (ffs->func == func) {
- ffs_func_eps_disable(func);
- ffs->func = NULL;
- }
-
- ffs_event_add(ffs, FUNCTIONFS_UNBIND);
-
- ffs_func_free(func);
-}
-
-static int ffs_func_set_alt(struct usb_function *f,
- unsigned interface, unsigned alt)
-{
- struct ffs_function *func = ffs_func_from_usb(f);
- struct ffs_data *ffs = func->ffs;
- int ret = 0, intf;
-
- if (alt != (unsigned)-1) {
- intf = ffs_func_revmap_intf(func, interface);
- if (unlikely(intf < 0))
- return intf;
- }
-
- if (ffs->func)
- ffs_func_eps_disable(ffs->func);
-
- if (ffs->state != FFS_ACTIVE)
- return -ENODEV;
-
- if (alt == (unsigned)-1) {
- ffs->func = NULL;
- ffs_event_add(ffs, FUNCTIONFS_DISABLE);
- return 0;
- }
-
- ffs->func = func;
- ret = ffs_func_eps_enable(func);
- if (likely(ret >= 0))
- ffs_event_add(ffs, FUNCTIONFS_ENABLE);
- return ret;
-}
-
-static void ffs_func_disable(struct usb_function *f)
-{
- ffs_func_set_alt(f, 0, (unsigned)-1);
-}
-
-static int ffs_func_setup(struct usb_function *f,
- const struct usb_ctrlrequest *creq)
-{
- struct ffs_function *func = ffs_func_from_usb(f);
- struct ffs_data *ffs = func->ffs;
- unsigned long flags;
- int ret;
-
- ENTER();
-
- pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType);
- pr_vdebug("creq->bRequest = %02x\n", creq->bRequest);
- pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue));
- pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex));
- pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength));
-
- /*
- * Most requests directed to interface go through here
- * (notable exceptions are set/get interface) so we need to
- * handle them. All other either handled by composite or
- * passed to usb_configuration->setup() (if one is set). No
- * matter, we will handle requests directed to endpoint here
- * as well (as it's straightforward) but what to do with any
- * other request?
- */
- if (ffs->state != FFS_ACTIVE)
- return -ENODEV;
-
- switch (creq->bRequestType & USB_RECIP_MASK) {
- case USB_RECIP_INTERFACE:
- ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex));
- if (unlikely(ret < 0))
- return ret;
- break;
-
- case USB_RECIP_ENDPOINT:
- ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex));
- if (unlikely(ret < 0))
- return ret;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
-
- spin_lock_irqsave(&ffs->ev.waitq.lock, flags);
- ffs->ev.setup = *creq;
- ffs->ev.setup.wIndex = cpu_to_le16(ret);
- __ffs_event_add(ffs, FUNCTIONFS_SETUP);
- spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
-
- return 0;
-}
-
-static void ffs_func_suspend(struct usb_function *f)
-{
- ENTER();
- ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND);
-}
-
-static void ffs_func_resume(struct usb_function *f)
-{
- ENTER();
- ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME);
-}
-
-
-/* Endpoint and interface numbers reverse mapping ***************************/
-
-static int ffs_func_revmap_ep(struct ffs_function *func, u8 num)
-{
- num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK];
- return num ? num : -EDOM;
-}
-
-static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
-{
- short *nums = func->interfaces_nums;
- unsigned count = func->ffs->interfaces_count;
-
- for (; count; --count, ++nums) {
- if (*nums >= 0 && *nums == intf)
- return nums - func->interfaces_nums;
- }
-
- return -EDOM;
-}
-
-
-/* Misc helper functions ****************************************************/
-
-static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
-{
- return nonblock
- ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN
- : mutex_lock_interruptible(mutex);
-}
-
-static char *ffs_prepare_buffer(const char * __user buf, size_t len)
-{
- char *data;
-
- if (unlikely(!len))
- return NULL;
-
- data = kmalloc(len, GFP_KERNEL);
- if (unlikely(!data))
- return ERR_PTR(-ENOMEM);
-
- if (unlikely(__copy_from_user(data, buf, len))) {
- kfree(data);
- return ERR_PTR(-EFAULT);
- }
-
- pr_vdebug("Buffer from user space:\n");
- ffs_dump_mem("", data, len);
-
- return data;
-}
diff --git a/drivers/staging/ccg/f_mass_storage.c b/drivers/staging/ccg/f_mass_storage.c
deleted file mode 100644
index 20bc2b454ac2..000000000000
--- a/drivers/staging/ccg/f_mass_storage.c
+++ /dev/null
@@ -1,3135 +0,0 @@
-/*
- * f_mass_storage.c -- Mass Storage USB Composite Function
- *
- * Copyright (C) 2003-2008 Alan Stern
- * Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz <mina86@mina86.com>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * The Mass Storage Function acts as a USB Mass Storage device,
- * appearing to the host as a disk drive or as a CD-ROM drive. In
- * addition to providing an example of a genuinely useful composite
- * function for a USB device, it also illustrates a technique of
- * double-buffering for increased throughput.
- *
- * For more information about MSF and in particular its module
- * parameters and sysfs interface read the
- * <Documentation/usb/mass-storage.txt> file.
- */
-
-/*
- * MSF is configured by specifying a fsg_config structure. It has the
- * following fields:
- *
- * nluns Number of LUNs function have (anywhere from 1
- * to FSG_MAX_LUNS which is 8).
- * luns An array of LUN configuration values. This
- * should be filled for each LUN that
- * function will include (ie. for "nluns"
- * LUNs). Each element of the array has
- * the following fields:
- * ->filename The path to the backing file for the LUN.
- * Required if LUN is not marked as
- * removable.
- * ->ro Flag specifying access to the LUN shall be
- * read-only. This is implied if CD-ROM
- * emulation is enabled as well as when
- * it was impossible to open "filename"
- * in R/W mode.
- * ->removable Flag specifying that LUN shall be indicated as
- * being removable.
- * ->cdrom Flag specifying that LUN shall be reported as
- * being a CD-ROM.
- * ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12)
- * commands for this LUN shall be ignored.
- *
- * vendor_name
- * product_name
- * release Information used as a reply to INQUIRY
- * request. To use default set to NULL,
- * NULL, 0xffff respectively. The first
- * field should be 8 and the second 16
- * characters or less.
- *
- * can_stall Set to permit function to halt bulk endpoints.
- * Disabled on some USB devices known not
- * to work correctly. You should set it
- * to true.
- *
- * If "removable" is not set for a LUN then a backing file must be
- * specified. If it is set, then NULL filename means the LUN's medium
- * is not loaded (an empty string as "filename" in the fsg_config
- * structure causes error). The CD-ROM emulation includes a single
- * data track and no audio tracks; hence there need be only one
- * backing file per LUN.
- *
- * This function is heavily based on "File-backed Storage Gadget" by
- * Alan Stern which in turn is heavily based on "Gadget Zero" by David
- * Brownell. The driver's SCSI command interface was based on the
- * "Information technology - Small Computer System Interface - 2"
- * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93,
- * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
- * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which
- * was based on the "Universal Serial Bus Mass Storage Class UFI
- * Command Specification" document, Revision 1.0, December 14, 1998,
- * available at
- * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
- */
-
-/*
- * Driver Design
- *
- * The MSF is fairly straightforward. There is a main kernel
- * thread that handles most of the work. Interrupt routines field
- * callbacks from the controller driver: bulk- and interrupt-request
- * completion notifications, endpoint-0 events, and disconnect events.
- * Completion events are passed to the main thread by wakeup calls. Many
- * ep0 requests are handled at interrupt time, but SetInterface,
- * SetConfiguration, and device reset requests are forwarded to the
- * thread in the form of "exceptions" using SIGUSR1 signals (since they
- * should interrupt any ongoing file I/O operations).
- *
- * The thread's main routine implements the standard command/data/status
- * parts of a SCSI interaction. It and its subroutines are full of tests
- * for pending signals/exceptions -- all this polling is necessary since
- * the kernel has no setjmp/longjmp equivalents. (Maybe this is an
- * indication that the driver really wants to be running in userspace.)
- * An important point is that so long as the thread is alive it keeps an
- * open reference to the backing file. This will prevent unmounting
- * the backing file's underlying filesystem and could cause problems
- * during system shutdown, for example. To prevent such problems, the
- * thread catches INT, TERM, and KILL signals and converts them into
- * an EXIT exception.
- *
- * In normal operation the main thread is started during the gadget's
- * fsg_bind() callback and stopped during fsg_unbind(). But it can
- * also exit when it receives a signal, and there's no point leaving
- * the gadget running when the thread is dead. As of this moment, MSF
- * provides no way to deregister the gadget when thread dies -- maybe
- * a callback functions is needed.
- *
- * To provide maximum throughput, the driver uses a circular pipeline of
- * buffer heads (struct fsg_buffhd). In principle the pipeline can be
- * arbitrarily long; in practice the benefits don't justify having more
- * than 2 stages (i.e., double buffering). But it helps to think of the
- * pipeline as being a long one. Each buffer head contains a bulk-in and
- * a bulk-out request pointer (since the buffer can be used for both
- * output and input -- directions always are given from the host's
- * point of view) as well as a pointer to the buffer and various state
- * variables.
- *
- * Use of the pipeline follows a simple protocol. There is a variable
- * (fsg->next_buffhd_to_fill) that points to the next buffer head to use.
- * At any time that buffer head may still be in use from an earlier
- * request, so each buffer head has a state variable indicating whether
- * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the
- * buffer head to be EMPTY, filling the buffer either by file I/O or by
- * USB I/O (during which the buffer head is BUSY), and marking the buffer
- * head FULL when the I/O is complete. Then the buffer will be emptied
- * (again possibly by USB I/O, during which it is marked BUSY) and
- * finally marked EMPTY again (possibly by a completion routine).
- *
- * A module parameter tells the driver to avoid stalling the bulk
- * endpoints wherever the transport specification allows. This is
- * necessary for some UDCs like the SuperH, which cannot reliably clear a
- * halt on a bulk endpoint. However, under certain circumstances the
- * Bulk-only specification requires a stall. In such cases the driver
- * will halt the endpoint and set a flag indicating that it should clear
- * the halt in software during the next device reset. Hopefully this
- * will permit everything to work correctly. Furthermore, although the
- * specification allows the bulk-out endpoint to halt when the host sends
- * too much data, implementing this would cause an unavoidable race.
- * The driver will always use the "no-stall" approach for OUT transfers.
- *
- * One subtle point concerns sending status-stage responses for ep0
- * requests. Some of these requests, such as device reset, can involve
- * interrupting an ongoing file I/O operation, which might take an
- * arbitrarily long time. During that delay the host might give up on
- * the original ep0 request and issue a new one. When that happens the
- * driver should not notify the host about completion of the original
- * request, as the host will no longer be waiting for it. So the driver
- * assigns to each ep0 request a unique tag, and it keeps track of the
- * tag value of the request associated with a long-running exception
- * (device-reset, interface-change, or configuration-change). When the
- * exception handler is finished, the status-stage response is submitted
- * only if the current ep0 request tag is equal to the exception request
- * tag. Thus only the most recently received ep0 request will get a
- * status-stage response.
- *
- * Warning: This driver source file is too long. It ought to be split up
- * into a header file plus about 3 separate .c files, to handle the details
- * of the Gadget, USB Mass Storage, and SCSI protocols.
- */
-
-
-/* #define VERBOSE_DEBUG */
-/* #define DUMP_MSGS */
-
-#include <linux/blkdev.h>
-#include <linux/completion.h>
-#include <linux/dcache.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/fcntl.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/kref.h>
-#include <linux/kthread.h>
-#include <linux/limits.h>
-#include <linux/rwsem.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-#include <linux/freezer.h>
-#include <linux/utsname.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/composite.h>
-
-#include "gadget_chips.h"
-
-
-/*------------------------------------------------------------------------*/
-
-#define FSG_DRIVER_DESC "Mass Storage Function"
-#define FSG_DRIVER_VERSION "2009/09/11"
-
-static const char fsg_string_interface[] = "Mass Storage";
-
-#define FSG_NO_DEVICE_STRINGS 1
-#define FSG_NO_OTG 1
-#define FSG_NO_INTR_EP 1
-
-#include "storage_common.c"
-
-
-/*-------------------------------------------------------------------------*/
-
-struct fsg_dev;
-struct fsg_common;
-
-/* FSF callback functions */
-struct fsg_operations {
- /*
- * Callback function to call when thread exits. If no
- * callback is set or it returns value lower then zero MSF
- * will force eject all LUNs it operates on (including those
- * marked as non-removable or with prevent_medium_removal flag
- * set).
- */
- int (*thread_exits)(struct fsg_common *common);
-
- /*
- * Called prior to ejection. Negative return means error,
- * zero means to continue with ejection, positive means not to
- * eject.
- */
- int (*pre_eject)(struct fsg_common *common,
- struct fsg_lun *lun, int num);
- /*
- * Called after ejection. Negative return means error, zero
- * or positive is just a success.
- */
- int (*post_eject)(struct fsg_common *common,
- struct fsg_lun *lun, int num);
-};
-
-/* Data shared by all the FSG instances. */
-struct fsg_common {
- struct usb_gadget *gadget;
- struct usb_composite_dev *cdev;
- struct fsg_dev *fsg, *new_fsg;
- wait_queue_head_t fsg_wait;
-
- /* filesem protects: backing files in use */
- struct rw_semaphore filesem;
-
- /* lock protects: state, all the req_busy's */
- spinlock_t lock;
-
- struct usb_ep *ep0; /* Copy of gadget->ep0 */
- struct usb_request *ep0req; /* Copy of cdev->req */
- unsigned int ep0_req_tag;
-
- struct fsg_buffhd *next_buffhd_to_fill;
- struct fsg_buffhd *next_buffhd_to_drain;
- struct fsg_buffhd *buffhds;
-
- int cmnd_size;
- u8 cmnd[MAX_COMMAND_SIZE];
-
- unsigned int nluns;
- unsigned int lun;
- struct fsg_lun *luns;
- struct fsg_lun *curlun;
-
- unsigned int bulk_out_maxpacket;
- enum fsg_state state; /* For exception handling */
- unsigned int exception_req_tag;
-
- enum data_direction data_dir;
- u32 data_size;
- u32 data_size_from_cmnd;
- u32 tag;
- u32 residue;
- u32 usb_amount_left;
-
- unsigned int can_stall:1;
- unsigned int free_storage_on_release:1;
- unsigned int phase_error:1;
- unsigned int short_packet_received:1;
- unsigned int bad_lun_okay:1;
- unsigned int running:1;
-
- int thread_wakeup_needed;
- struct completion thread_notifier;
- struct task_struct *thread_task;
-
- /* Callback functions. */
- const struct fsg_operations *ops;
- /* Gadget's private data. */
- void *private_data;
-
- /*
- * Vendor (8 chars), product (16 chars), release (4
- * hexadecimal digits) and NUL byte
- */
- char inquiry_string[8 + 16 + 4 + 1];
-
- struct kref ref;
-};
-
-struct fsg_config {
- unsigned nluns;
- struct fsg_lun_config {
- const char *filename;
- char ro;
- char removable;
- char cdrom;
- char nofua;
- } luns[FSG_MAX_LUNS];
-
- /* Callback functions. */
- const struct fsg_operations *ops;
- /* Gadget's private data. */
- void *private_data;
-
- const char *vendor_name; /* 8 characters or less */
- const char *product_name; /* 16 characters or less */
- u16 release;
-
- char can_stall;
-};
-
-struct fsg_dev {
- struct usb_function function;
- struct usb_gadget *gadget; /* Copy of cdev->gadget */
- struct fsg_common *common;
-
- u16 interface_number;
-
- unsigned int bulk_in_enabled:1;
- unsigned int bulk_out_enabled:1;
-
- unsigned long atomic_bitflags;
-#define IGNORE_BULK_OUT 0
-
- struct usb_ep *bulk_in;
- struct usb_ep *bulk_out;
-};
-
-static inline int __fsg_is_set(struct fsg_common *common,
- const char *func, unsigned line)
-{
- if (common->fsg)
- return 1;
- ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
- WARN_ON(1);
- return 0;
-}
-
-#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
-
-static inline struct fsg_dev *fsg_from_func(struct usb_function *f)
-{
- return container_of(f, struct fsg_dev, function);
-}
-
-typedef void (*fsg_routine_t)(struct fsg_dev *);
-
-static int exception_in_progress(struct fsg_common *common)
-{
- return common->state > FSG_STATE_IDLE;
-}
-
-/* Make bulk-out requests be divisible by the maxpacket size */
-static void set_bulk_out_req_length(struct fsg_common *common,
- struct fsg_buffhd *bh, unsigned int length)
-{
- unsigned int rem;
-
- bh->bulk_out_intended_length = length;
- rem = length % common->bulk_out_maxpacket;
- if (rem > 0)
- length += common->bulk_out_maxpacket - rem;
- bh->outreq->length = length;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
-{
- const char *name;
-
- if (ep == fsg->bulk_in)
- name = "bulk-in";
- else if (ep == fsg->bulk_out)
- name = "bulk-out";
- else
- name = ep->name;
- DBG(fsg, "%s set halt\n", name);
- return usb_ep_set_halt(ep);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* These routines may be called in process context or in_irq */
-
-/* Caller must hold fsg->lock */
-static void wakeup_thread(struct fsg_common *common)
-{
- /* Tell the main thread that something has happened */
- common->thread_wakeup_needed = 1;
- if (common->thread_task)
- wake_up_process(common->thread_task);
-}
-
-static void raise_exception(struct fsg_common *common, enum fsg_state new_state)
-{
- unsigned long flags;
-
- /*
- * Do nothing if a higher-priority exception is already in progress.
- * If a lower-or-equal priority exception is in progress, preempt it
- * and notify the main thread by sending it a signal.
- */
- spin_lock_irqsave(&common->lock, flags);
- if (common->state <= new_state) {
- common->exception_req_tag = common->ep0_req_tag;
- common->state = new_state;
- if (common->thread_task)
- send_sig_info(SIGUSR1, SEND_SIG_FORCED,
- common->thread_task);
- }
- spin_unlock_irqrestore(&common->lock, flags);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int ep0_queue(struct fsg_common *common)
-{
- int rc;
-
- rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC);
- common->ep0->driver_data = common;
- if (rc != 0 && rc != -ESHUTDOWN) {
- /* We can't do much more than wait for a reset */
- WARNING(common, "error in submission: %s --> %d\n",
- common->ep0->name, rc);
- }
- return rc;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* Completion handlers. These always run in_irq. */
-
-static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct fsg_common *common = ep->driver_data;
- struct fsg_buffhd *bh = req->context;
-
- if (req->status || req->actual != req->length)
- DBG(common, "%s --> %d, %u/%u\n", __func__,
- req->status, req->actual, req->length);
- if (req->status == -ECONNRESET) /* Request was cancelled */
- usb_ep_fifo_flush(ep);
-
- /* Hold the lock while we update the request and buffer states */
- smp_wmb();
- spin_lock(&common->lock);
- bh->inreq_busy = 0;
- bh->state = BUF_STATE_EMPTY;
- wakeup_thread(common);
- spin_unlock(&common->lock);
-}
-
-static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct fsg_common *common = ep->driver_data;
- struct fsg_buffhd *bh = req->context;
-
- dump_msg(common, "bulk-out", req->buf, req->actual);
- if (req->status || req->actual != bh->bulk_out_intended_length)
- DBG(common, "%s --> %d, %u/%u\n", __func__,
- req->status, req->actual, bh->bulk_out_intended_length);
- if (req->status == -ECONNRESET) /* Request was cancelled */
- usb_ep_fifo_flush(ep);
-
- /* Hold the lock while we update the request and buffer states */
- smp_wmb();
- spin_lock(&common->lock);
- bh->outreq_busy = 0;
- bh->state = BUF_STATE_FULL;
- wakeup_thread(common);
- spin_unlock(&common->lock);
-}
-
-static int fsg_setup(struct usb_function *f,
- const struct usb_ctrlrequest *ctrl)
-{
- struct fsg_dev *fsg = fsg_from_func(f);
- struct usb_request *req = fsg->common->ep0req;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
-
- if (!fsg_is_set(fsg->common))
- return -EOPNOTSUPP;
-
- ++fsg->common->ep0_req_tag; /* Record arrival of a new request */
- req->context = NULL;
- req->length = 0;
- dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl));
-
- switch (ctrl->bRequest) {
-
- case US_BULK_RESET_REQUEST:
- if (ctrl->bRequestType !=
- (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
- break;
- if (w_index != fsg->interface_number || w_value != 0 ||
- w_length != 0)
- return -EDOM;
-
- /*
- * Raise an exception to stop the current operation
- * and reinitialize our state.
- */
- DBG(fsg, "bulk reset request\n");
- raise_exception(fsg->common, FSG_STATE_RESET);
- return DELAYED_STATUS;
-
- case US_BULK_GET_MAX_LUN:
- if (ctrl->bRequestType !=
- (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
- break;
- if (w_index != fsg->interface_number || w_value != 0 ||
- w_length != 1)
- return -EDOM;
- VDBG(fsg, "get max LUN\n");
- *(u8 *)req->buf = fsg->common->nluns - 1;
-
- /* Respond with data/status */
- req->length = min((u16)1, w_length);
- return ep0_queue(fsg->common);
- }
-
- VDBG(fsg,
- "unknown class-specific control req %02x.%02x v%04x i%04x l%u\n",
- ctrl->bRequestType, ctrl->bRequest,
- le16_to_cpu(ctrl->wValue), w_index, w_length);
- return -EOPNOTSUPP;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* All the following routines run in process context */
-
-/* Use this for bulk or interrupt transfers, not ep0 */
-static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
- struct usb_request *req, int *pbusy,
- enum fsg_buffer_state *state)
-{
- int rc;
-
- if (ep == fsg->bulk_in)
- dump_msg(fsg, "bulk-in", req->buf, req->length);
-
- spin_lock_irq(&fsg->common->lock);
- *pbusy = 1;
- *state = BUF_STATE_BUSY;
- spin_unlock_irq(&fsg->common->lock);
- rc = usb_ep_queue(ep, req, GFP_KERNEL);
- if (rc != 0) {
- *pbusy = 0;
- *state = BUF_STATE_EMPTY;
-
- /* We can't do much more than wait for a reset */
-
- /*
- * Note: currently the net2280 driver fails zero-length
- * submissions if DMA is enabled.
- */
- if (rc != -ESHUTDOWN &&
- !(rc == -EOPNOTSUPP && req->length == 0))
- WARNING(fsg, "error in submission: %s --> %d\n",
- ep->name, rc);
- }
-}
-
-static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- if (!fsg_is_set(common))
- return false;
- start_transfer(common->fsg, common->fsg->bulk_in,
- bh->inreq, &bh->inreq_busy, &bh->state);
- return true;
-}
-
-static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- if (!fsg_is_set(common))
- return false;
- start_transfer(common->fsg, common->fsg->bulk_out,
- bh->outreq, &bh->outreq_busy, &bh->state);
- return true;
-}
-
-static int sleep_thread(struct fsg_common *common)
-{
- int rc = 0;
-
- /* Wait until a signal arrives or we are woken up */
- for (;;) {
- try_to_freeze();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- rc = -EINTR;
- break;
- }
- if (common->thread_wakeup_needed)
- break;
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- common->thread_wakeup_needed = 0;
- return rc;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int do_read(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- u32 lba;
- struct fsg_buffhd *bh;
- int rc;
- u32 amount_left;
- loff_t file_offset, file_offset_tmp;
- unsigned int amount;
- ssize_t nread;
-
- /*
- * Get the starting Logical Block Address and check that it's
- * not too big.
- */
- if (common->cmnd[0] == READ_6)
- lba = get_unaligned_be24(&common->cmnd[1]);
- else {
- lba = get_unaligned_be32(&common->cmnd[2]);
-
- /*
- * We allow DPO (Disable Page Out = don't save data in the
- * cache) and FUA (Force Unit Access = don't read from the
- * cache), but we don't implement them.
- */
- if ((common->cmnd[1] & ~0x18) != 0) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
- }
- if (lba >= curlun->num_sectors) {
- curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- return -EINVAL;
- }
- file_offset = ((loff_t) lba) << curlun->blkbits;
-
- /* Carry out the file reads */
- amount_left = common->data_size_from_cmnd;
- if (unlikely(amount_left == 0))
- return -EIO; /* No default reply */
-
- for (;;) {
- /*
- * Figure out how much we need to read:
- * Try to read the remaining amount.
- * But don't read more than the buffer size.
- * And don't try to read past the end of the file.
- */
- amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
- curlun->file_length - file_offset);
-
- /* Wait for the next buffer to become available */
- bh = common->next_buffhd_to_fill;
- while (bh->state != BUF_STATE_EMPTY) {
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
-
- /*
- * If we were asked to read past the end of file,
- * end with an empty buffer.
- */
- if (amount == 0) {
- curlun->sense_data =
- SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- bh->inreq->length = 0;
- bh->state = BUF_STATE_FULL;
- break;
- }
-
- /* Perform the read */
- file_offset_tmp = file_offset;
- nread = vfs_read(curlun->filp,
- (char __user *)bh->buf,
- amount, &file_offset_tmp);
- VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
- (unsigned long long)file_offset, (int)nread);
- if (signal_pending(current))
- return -EINTR;
-
- if (nread < 0) {
- LDBG(curlun, "error in file read: %d\n", (int)nread);
- nread = 0;
- } else if (nread < amount) {
- LDBG(curlun, "partial file read: %d/%u\n",
- (int)nread, amount);
- nread = round_down(nread, curlun->blksize);
- }
- file_offset += nread;
- amount_left -= nread;
- common->residue -= nread;
-
- /*
- * Except at the end of the transfer, nread will be
- * equal to the buffer size, which is divisible by the
- * bulk-in maxpacket size.
- */
- bh->inreq->length = nread;
- bh->state = BUF_STATE_FULL;
-
- /* If an error occurred, report it and its position */
- if (nread < amount) {
- curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- break;
- }
-
- if (amount_left == 0)
- break; /* No more left to read */
-
- /* Send this buffer and go read some more */
- bh->inreq->zero = 0;
- if (!start_in_transfer(common, bh))
- /* Don't know what to do if common->fsg is NULL */
- return -EIO;
- common->next_buffhd_to_fill = bh->next;
- }
-
- return -EIO; /* No default reply */
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int do_write(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- u32 lba;
- struct fsg_buffhd *bh;
- int get_some_more;
- u32 amount_left_to_req, amount_left_to_write;
- loff_t usb_offset, file_offset, file_offset_tmp;
- unsigned int amount;
- ssize_t nwritten;
- int rc;
-
- if (curlun->ro) {
- curlun->sense_data = SS_WRITE_PROTECTED;
- return -EINVAL;
- }
- spin_lock(&curlun->filp->f_lock);
- curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */
- spin_unlock(&curlun->filp->f_lock);
-
- /*
- * Get the starting Logical Block Address and check that it's
- * not too big
- */
- if (common->cmnd[0] == WRITE_6)
- lba = get_unaligned_be24(&common->cmnd[1]);
- else {
- lba = get_unaligned_be32(&common->cmnd[2]);
-
- /*
- * We allow DPO (Disable Page Out = don't save data in the
- * cache) and FUA (Force Unit Access = write directly to the
- * medium). We don't implement DPO; we implement FUA by
- * performing synchronous output.
- */
- if (common->cmnd[1] & ~0x18) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
- if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
- spin_lock(&curlun->filp->f_lock);
- curlun->filp->f_flags |= O_SYNC;
- spin_unlock(&curlun->filp->f_lock);
- }
- }
- if (lba >= curlun->num_sectors) {
- curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- return -EINVAL;
- }
-
- /* Carry out the file writes */
- get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
- amount_left_to_req = common->data_size_from_cmnd;
- amount_left_to_write = common->data_size_from_cmnd;
-
- while (amount_left_to_write > 0) {
-
- /* Queue a request for more data from the host */
- bh = common->next_buffhd_to_fill;
- if (bh->state == BUF_STATE_EMPTY && get_some_more) {
-
- /*
- * Figure out how much we want to get:
- * Try to get the remaining amount,
- * but not more than the buffer size.
- */
- amount = min(amount_left_to_req, FSG_BUFLEN);
-
- /* Beyond the end of the backing file? */
- if (usb_offset >= curlun->file_length) {
- get_some_more = 0;
- curlun->sense_data =
- SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info =
- usb_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- continue;
- }
-
- /* Get the next buffer */
- usb_offset += amount;
- common->usb_amount_left -= amount;
- amount_left_to_req -= amount;
- if (amount_left_to_req == 0)
- get_some_more = 0;
-
- /*
- * Except at the end of the transfer, amount will be
- * equal to the buffer size, which is divisible by
- * the bulk-out maxpacket size.
- */
- set_bulk_out_req_length(common, bh, amount);
- if (!start_out_transfer(common, bh))
- /* Dunno what to do if common->fsg is NULL */
- return -EIO;
- common->next_buffhd_to_fill = bh->next;
- continue;
- }
-
- /* Write the received data to the backing file */
- bh = common->next_buffhd_to_drain;
- if (bh->state == BUF_STATE_EMPTY && !get_some_more)
- break; /* We stopped early */
- if (bh->state == BUF_STATE_FULL) {
- smp_rmb();
- common->next_buffhd_to_drain = bh->next;
- bh->state = BUF_STATE_EMPTY;
-
- /* Did something go wrong with the transfer? */
- if (bh->outreq->status != 0) {
- curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- break;
- }
-
- amount = bh->outreq->actual;
- if (curlun->file_length - file_offset < amount) {
- LERROR(curlun,
- "write %u @ %llu beyond end %llu\n",
- amount, (unsigned long long)file_offset,
- (unsigned long long)curlun->file_length);
- amount = curlun->file_length - file_offset;
- }
-
- /* Don't accept excess data. The spec doesn't say
- * what to do in this case. We'll ignore the error.
- */
- amount = min(amount, bh->bulk_out_intended_length);
-
- /* Don't write a partial block */
- amount = round_down(amount, curlun->blksize);
- if (amount == 0)
- goto empty_write;
-
- /* Perform the write */
- file_offset_tmp = file_offset;
- nwritten = vfs_write(curlun->filp,
- (char __user *)bh->buf,
- amount, &file_offset_tmp);
- VLDBG(curlun, "file write %u @ %llu -> %d\n", amount,
- (unsigned long long)file_offset, (int)nwritten);
- if (signal_pending(current))
- return -EINTR; /* Interrupted! */
-
- if (nwritten < 0) {
- LDBG(curlun, "error in file write: %d\n",
- (int)nwritten);
- nwritten = 0;
- } else if (nwritten < amount) {
- LDBG(curlun, "partial file write: %d/%u\n",
- (int)nwritten, amount);
- nwritten = round_down(nwritten, curlun->blksize);
- }
- file_offset += nwritten;
- amount_left_to_write -= nwritten;
- common->residue -= nwritten;
-
- /* If an error occurred, report it and its position */
- if (nwritten < amount) {
- curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- break;
- }
-
- empty_write:
- /* Did the host decide to stop early? */
- if (bh->outreq->actual < bh->bulk_out_intended_length) {
- common->short_packet_received = 1;
- break;
- }
- continue;
- }
-
- /* Wait for something to happen */
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
-
- return -EIO; /* No default reply */
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int do_synchronize_cache(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- int rc;
-
- /* We ignore the requested LBA and write out all file's
- * dirty data buffers. */
- rc = fsg_lun_fsync_sub(curlun);
- if (rc)
- curlun->sense_data = SS_WRITE_ERROR;
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void invalidate_sub(struct fsg_lun *curlun)
-{
- struct file *filp = curlun->filp;
- struct inode *inode = file_inode(filp);
- unsigned long rc;
-
- rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
- VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
-}
-
-static int do_verify(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- u32 lba;
- u32 verification_length;
- struct fsg_buffhd *bh = common->next_buffhd_to_fill;
- loff_t file_offset, file_offset_tmp;
- u32 amount_left;
- unsigned int amount;
- ssize_t nread;
-
- /*
- * Get the starting Logical Block Address and check that it's
- * not too big.
- */
- lba = get_unaligned_be32(&common->cmnd[2]);
- if (lba >= curlun->num_sectors) {
- curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- return -EINVAL;
- }
-
- /*
- * We allow DPO (Disable Page Out = don't save data in the
- * cache) but we don't implement it.
- */
- if (common->cmnd[1] & ~0x10) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- verification_length = get_unaligned_be16(&common->cmnd[7]);
- if (unlikely(verification_length == 0))
- return -EIO; /* No default reply */
-
- /* Prepare to carry out the file verify */
- amount_left = verification_length << curlun->blkbits;
- file_offset = ((loff_t) lba) << curlun->blkbits;
-
- /* Write out all the dirty buffers before invalidating them */
- fsg_lun_fsync_sub(curlun);
- if (signal_pending(current))
- return -EINTR;
-
- invalidate_sub(curlun);
- if (signal_pending(current))
- return -EINTR;
-
- /* Just try to read the requested blocks */
- while (amount_left > 0) {
- /*
- * Figure out how much we need to read:
- * Try to read the remaining amount, but not more than
- * the buffer size.
- * And don't try to read past the end of the file.
- */
- amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
- curlun->file_length - file_offset);
- if (amount == 0) {
- curlun->sense_data =
- SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- break;
- }
-
- /* Perform the read */
- file_offset_tmp = file_offset;
- nread = vfs_read(curlun->filp,
- (char __user *) bh->buf,
- amount, &file_offset_tmp);
- VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
- (unsigned long long) file_offset,
- (int) nread);
- if (signal_pending(current))
- return -EINTR;
-
- if (nread < 0) {
- LDBG(curlun, "error in file verify: %d\n", (int)nread);
- nread = 0;
- } else if (nread < amount) {
- LDBG(curlun, "partial file verify: %d/%u\n",
- (int)nread, amount);
- nread = round_down(nread, curlun->blksize);
- }
- if (nread == 0) {
- curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info =
- file_offset >> curlun->blkbits;
- curlun->info_valid = 1;
- break;
- }
- file_offset += nread;
- amount_left -= nread;
- }
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- u8 *buf = (u8 *) bh->buf;
-
- if (!curlun) { /* Unsupported LUNs are okay */
- common->bad_lun_okay = 1;
- memset(buf, 0, 36);
- buf[0] = 0x7f; /* Unsupported, no device-type */
- buf[4] = 31; /* Additional length */
- return 36;
- }
-
- buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK;
- buf[1] = curlun->removable ? 0x80 : 0;
- buf[2] = 2; /* ANSI SCSI level 2 */
- buf[3] = 2; /* SCSI-2 INQUIRY data format */
- buf[4] = 31; /* Additional length */
- buf[5] = 0; /* No special options */
- buf[6] = 0;
- buf[7] = 0;
- memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string);
- return 36;
-}
-
-static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- u8 *buf = (u8 *) bh->buf;
- u32 sd, sdinfo;
- int valid;
-
- /*
- * From the SCSI-2 spec., section 7.9 (Unit attention condition):
- *
- * If a REQUEST SENSE command is received from an initiator
- * with a pending unit attention condition (before the target
- * generates the contingent allegiance condition), then the
- * target shall either:
- * a) report any pending sense data and preserve the unit
- * attention condition on the logical unit, or,
- * b) report the unit attention condition, may discard any
- * pending sense data, and clear the unit attention
- * condition on the logical unit for that initiator.
- *
- * FSG normally uses option a); enable this code to use option b).
- */
-#if 0
- if (curlun && curlun->unit_attention_data != SS_NO_SENSE) {
- curlun->sense_data = curlun->unit_attention_data;
- curlun->unit_attention_data = SS_NO_SENSE;
- }
-#endif
-
- if (!curlun) { /* Unsupported LUNs are okay */
- common->bad_lun_okay = 1;
- sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
- sdinfo = 0;
- valid = 0;
- } else {
- sd = curlun->sense_data;
- sdinfo = curlun->sense_data_info;
- valid = curlun->info_valid << 7;
- curlun->sense_data = SS_NO_SENSE;
- curlun->sense_data_info = 0;
- curlun->info_valid = 0;
- }
-
- memset(buf, 0, 18);
- buf[0] = valid | 0x70; /* Valid, current error */
- buf[2] = SK(sd);
- put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
- buf[7] = 18 - 8; /* Additional sense length */
- buf[12] = ASC(sd);
- buf[13] = ASCQ(sd);
- return 18;
-}
-
-static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- u32 lba = get_unaligned_be32(&common->cmnd[2]);
- int pmi = common->cmnd[8];
- u8 *buf = (u8 *)bh->buf;
-
- /* Check the PMI and LBA fields */
- if (pmi > 1 || (pmi == 0 && lba != 0)) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
- /* Max logical block */
- put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
- return 8;
-}
-
-static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- int msf = common->cmnd[1] & 0x02;
- u32 lba = get_unaligned_be32(&common->cmnd[2]);
- u8 *buf = (u8 *)bh->buf;
-
- if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
- if (lba >= curlun->num_sectors) {
- curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- return -EINVAL;
- }
-
- memset(buf, 0, 8);
- buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
- store_cdrom_address(&buf[4], msf, lba);
- return 8;
-}
-
-static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- int msf = common->cmnd[1] & 0x02;
- int start_track = common->cmnd[6];
- u8 *buf = (u8 *)bh->buf;
-
- if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
- start_track > 1) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- memset(buf, 0, 20);
- buf[1] = (20-2); /* TOC data length */
- buf[2] = 1; /* First track number */
- buf[3] = 1; /* Last track number */
- buf[5] = 0x16; /* Data track, copying allowed */
- buf[6] = 0x01; /* Only track is number 1 */
- store_cdrom_address(&buf[8], msf, 0);
-
- buf[13] = 0x16; /* Lead-out track is data */
- buf[14] = 0xAA; /* Lead-out track number */
- store_cdrom_address(&buf[16], msf, curlun->num_sectors);
- return 20;
-}
-
-static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- int mscmnd = common->cmnd[0];
- u8 *buf = (u8 *) bh->buf;
- u8 *buf0 = buf;
- int pc, page_code;
- int changeable_values, all_pages;
- int valid_page = 0;
- int len, limit;
-
- if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
- pc = common->cmnd[2] >> 6;
- page_code = common->cmnd[2] & 0x3f;
- if (pc == 3) {
- curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED;
- return -EINVAL;
- }
- changeable_values = (pc == 1);
- all_pages = (page_code == 0x3f);
-
- /*
- * Write the mode parameter header. Fixed values are: default
- * medium type, no cache control (DPOFUA), and no block descriptors.
- * The only variable value is the WriteProtect bit. We will fill in
- * the mode data length later.
- */
- memset(buf, 0, 8);
- if (mscmnd == MODE_SENSE) {
- buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
- buf += 4;
- limit = 255;
- } else { /* MODE_SENSE_10 */
- buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
- buf += 8;
- limit = 65535; /* Should really be FSG_BUFLEN */
- }
-
- /* No block descriptors */
-
- /*
- * The mode pages, in numerical order. The only page we support
- * is the Caching page.
- */
- if (page_code == 0x08 || all_pages) {
- valid_page = 1;
- buf[0] = 0x08; /* Page code */
- buf[1] = 10; /* Page length */
- memset(buf+2, 0, 10); /* None of the fields are changeable */
-
- if (!changeable_values) {
- buf[2] = 0x04; /* Write cache enable, */
- /* Read cache not disabled */
- /* No cache retention priorities */
- put_unaligned_be16(0xffff, &buf[4]);
- /* Don't disable prefetch */
- /* Minimum prefetch = 0 */
- put_unaligned_be16(0xffff, &buf[8]);
- /* Maximum prefetch */
- put_unaligned_be16(0xffff, &buf[10]);
- /* Maximum prefetch ceiling */
- }
- buf += 12;
- }
-
- /*
- * Check that a valid page was requested and the mode data length
- * isn't too long.
- */
- len = buf - buf0;
- if (!valid_page || len > limit) {
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- /* Store the mode data length */
- if (mscmnd == MODE_SENSE)
- buf0[0] = len - 1;
- else
- put_unaligned_be16(len - 2, buf0);
- return len;
-}
-
-static int do_start_stop(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- int loej, start;
-
- if (!curlun) {
- return -EINVAL;
- } else if (!curlun->removable) {
- curlun->sense_data = SS_INVALID_COMMAND;
- return -EINVAL;
- } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
- (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- loej = common->cmnd[4] & 0x02;
- start = common->cmnd[4] & 0x01;
-
- /*
- * Our emulation doesn't support mounting; the medium is
- * available for use as soon as it is loaded.
- */
- if (start) {
- if (!fsg_lun_is_open(curlun)) {
- curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
- return -EINVAL;
- }
- return 0;
- }
-
- /* Are we allowed to unload the media? */
- if (curlun->prevent_medium_removal) {
- LDBG(curlun, "unload attempt prevented\n");
- curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
- return -EINVAL;
- }
-
- if (!loej)
- return 0;
-
- /* Simulate an unload/eject */
- if (common->ops && common->ops->pre_eject) {
- int r = common->ops->pre_eject(common, curlun,
- curlun - common->luns);
- if (unlikely(r < 0))
- return r;
- else if (r)
- return 0;
- }
-
- up_read(&common->filesem);
- down_write(&common->filesem);
- fsg_lun_close(curlun);
- up_write(&common->filesem);
- down_read(&common->filesem);
-
- return common->ops && common->ops->post_eject
- ? min(0, common->ops->post_eject(common, curlun,
- curlun - common->luns))
- : 0;
-}
-
-static int do_prevent_allow(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- int prevent;
-
- if (!common->curlun) {
- return -EINVAL;
- } else if (!common->curlun->removable) {
- common->curlun->sense_data = SS_INVALID_COMMAND;
- return -EINVAL;
- }
-
- prevent = common->cmnd[4] & 0x01;
- if ((common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
-
- if (curlun->prevent_medium_removal && !prevent)
- fsg_lun_fsync_sub(curlun);
- curlun->prevent_medium_removal = prevent;
- return 0;
-}
-
-static int do_read_format_capacities(struct fsg_common *common,
- struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
- u8 *buf = (u8 *) bh->buf;
-
- buf[0] = buf[1] = buf[2] = 0;
- buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */
- buf += 4;
-
- put_unaligned_be32(curlun->num_sectors, &buf[0]);
- /* Number of blocks */
- put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
- buf[4] = 0x02; /* Current capacity */
- return 12;
-}
-
-static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
-{
- struct fsg_lun *curlun = common->curlun;
-
- /* We don't support MODE SELECT */
- if (curlun)
- curlun->sense_data = SS_INVALID_COMMAND;
- return -EINVAL;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int halt_bulk_in_endpoint(struct fsg_dev *fsg)
-{
- int rc;
-
- rc = fsg_set_halt(fsg, fsg->bulk_in);
- if (rc == -EAGAIN)
- VDBG(fsg, "delayed bulk-in endpoint halt\n");
- while (rc != 0) {
- if (rc != -EAGAIN) {
- WARNING(fsg, "usb_ep_set_halt -> %d\n", rc);
- rc = 0;
- break;
- }
-
- /* Wait for a short time and then try again */
- if (msleep_interruptible(100) != 0)
- return -EINTR;
- rc = usb_ep_set_halt(fsg->bulk_in);
- }
- return rc;
-}
-
-static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
-{
- int rc;
-
- DBG(fsg, "bulk-in set wedge\n");
- rc = usb_ep_set_wedge(fsg->bulk_in);
- if (rc == -EAGAIN)
- VDBG(fsg, "delayed bulk-in endpoint wedge\n");
- while (rc != 0) {
- if (rc != -EAGAIN) {
- WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc);
- rc = 0;
- break;
- }
-
- /* Wait for a short time and then try again */
- if (msleep_interruptible(100) != 0)
- return -EINTR;
- rc = usb_ep_set_wedge(fsg->bulk_in);
- }
- return rc;
-}
-
-static int throw_away_data(struct fsg_common *common)
-{
- struct fsg_buffhd *bh;
- u32 amount;
- int rc;
-
- for (bh = common->next_buffhd_to_drain;
- bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0;
- bh = common->next_buffhd_to_drain) {
-
- /* Throw away the data in a filled buffer */
- if (bh->state == BUF_STATE_FULL) {
- smp_rmb();
- bh->state = BUF_STATE_EMPTY;
- common->next_buffhd_to_drain = bh->next;
-
- /* A short packet or an error ends everything */
- if (bh->outreq->actual < bh->bulk_out_intended_length ||
- bh->outreq->status != 0) {
- raise_exception(common,
- FSG_STATE_ABORT_BULK_OUT);
- return -EINTR;
- }
- continue;
- }
-
- /* Try to submit another request if we need one */
- bh = common->next_buffhd_to_fill;
- if (bh->state == BUF_STATE_EMPTY
- && common->usb_amount_left > 0) {
- amount = min(common->usb_amount_left, FSG_BUFLEN);
-
- /*
- * Except at the end of the transfer, amount will be
- * equal to the buffer size, which is divisible by
- * the bulk-out maxpacket size.
- */
- set_bulk_out_req_length(common, bh, amount);
- if (!start_out_transfer(common, bh))
- /* Dunno what to do if common->fsg is NULL */
- return -EIO;
- common->next_buffhd_to_fill = bh->next;
- common->usb_amount_left -= amount;
- continue;
- }
-
- /* Otherwise wait for something to happen */
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
- return 0;
-}
-
-static int finish_reply(struct fsg_common *common)
-{
- struct fsg_buffhd *bh = common->next_buffhd_to_fill;
- int rc = 0;
-
- switch (common->data_dir) {
- case DATA_DIR_NONE:
- break; /* Nothing to send */
-
- /*
- * If we don't know whether the host wants to read or write,
- * this must be CB or CBI with an unknown command. We mustn't
- * try to send or receive any data. So stall both bulk pipes
- * if we can and wait for a reset.
- */
- case DATA_DIR_UNKNOWN:
- if (!common->can_stall) {
- /* Nothing */
- } else if (fsg_is_set(common)) {
- fsg_set_halt(common->fsg, common->fsg->bulk_out);
- rc = halt_bulk_in_endpoint(common->fsg);
- } else {
- /* Don't know what to do if common->fsg is NULL */
- rc = -EIO;
- }
- break;
-
- /* All but the last buffer of data must have already been sent */
- case DATA_DIR_TO_HOST:
- if (common->data_size == 0) {
- /* Nothing to send */
-
- /* Don't know what to do if common->fsg is NULL */
- } else if (!fsg_is_set(common)) {
- rc = -EIO;
-
- /* If there's no residue, simply send the last buffer */
- } else if (common->residue == 0) {
- bh->inreq->zero = 0;
- if (!start_in_transfer(common, bh))
- return -EIO;
- common->next_buffhd_to_fill = bh->next;
-
- /*
- * For Bulk-only, mark the end of the data with a short
- * packet. If we are allowed to stall, halt the bulk-in
- * endpoint. (Note: This violates the Bulk-Only Transport
- * specification, which requires us to pad the data if we
- * don't halt the endpoint. Presumably nobody will mind.)
- */
- } else {
- bh->inreq->zero = 1;
- if (!start_in_transfer(common, bh))
- rc = -EIO;
- common->next_buffhd_to_fill = bh->next;
- if (common->can_stall)
- rc = halt_bulk_in_endpoint(common->fsg);
- }
- break;
-
- /*
- * We have processed all we want from the data the host has sent.
- * There may still be outstanding bulk-out requests.
- */
- case DATA_DIR_FROM_HOST:
- if (common->residue == 0) {
- /* Nothing to receive */
-
- /* Did the host stop sending unexpectedly early? */
- } else if (common->short_packet_received) {
- raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
- rc = -EINTR;
-
- /*
- * We haven't processed all the incoming data. Even though
- * we may be allowed to stall, doing so would cause a race.
- * The controller may already have ACK'ed all the remaining
- * bulk-out packets, in which case the host wouldn't see a
- * STALL. Not realizing the endpoint was halted, it wouldn't
- * clear the halt -- leading to problems later on.
- */
-#if 0
- } else if (common->can_stall) {
- if (fsg_is_set(common))
- fsg_set_halt(common->fsg,
- common->fsg->bulk_out);
- raise_exception(common, FSG_STATE_ABORT_BULK_OUT);
- rc = -EINTR;
-#endif
-
- /*
- * We can't stall. Read in the excess data and throw it
- * all away.
- */
- } else {
- rc = throw_away_data(common);
- }
- break;
- }
- return rc;
-}
-
-static int send_status(struct fsg_common *common)
-{
- struct fsg_lun *curlun = common->curlun;
- struct fsg_buffhd *bh;
- struct bulk_cs_wrap *csw;
- int rc;
- u8 status = US_BULK_STAT_OK;
- u32 sd, sdinfo = 0;
-
- /* Wait for the next buffer to become available */
- bh = common->next_buffhd_to_fill;
- while (bh->state != BUF_STATE_EMPTY) {
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
-
- if (curlun) {
- sd = curlun->sense_data;
- sdinfo = curlun->sense_data_info;
- } else if (common->bad_lun_okay)
- sd = SS_NO_SENSE;
- else
- sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
-
- if (common->phase_error) {
- DBG(common, "sending phase-error status\n");
- status = US_BULK_STAT_PHASE;
- sd = SS_INVALID_COMMAND;
- } else if (sd != SS_NO_SENSE) {
- DBG(common, "sending command-failure status\n");
- status = US_BULK_STAT_FAIL;
- VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
- " info x%x\n",
- SK(sd), ASC(sd), ASCQ(sd), sdinfo);
- }
-
- /* Store and send the Bulk-only CSW */
- csw = (void *)bh->buf;
-
- csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
- csw->Tag = common->tag;
- csw->Residue = cpu_to_le32(common->residue);
- csw->Status = status;
-
- bh->inreq->length = US_BULK_CS_WRAP_LEN;
- bh->inreq->zero = 0;
- if (!start_in_transfer(common, bh))
- /* Don't know what to do if common->fsg is NULL */
- return -EIO;
-
- common->next_buffhd_to_fill = bh->next;
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Check whether the command is properly formed and whether its data size
- * and direction agree with the values we already have.
- */
-static int check_command(struct fsg_common *common, int cmnd_size,
- enum data_direction data_dir, unsigned int mask,
- int needs_medium, const char *name)
-{
- int i;
- int lun = common->cmnd[1] >> 5;
- static const char dirletter[4] = {'u', 'o', 'i', 'n'};
- char hdlen[20];
- struct fsg_lun *curlun;
-
- hdlen[0] = 0;
- if (common->data_dir != DATA_DIR_UNKNOWN)
- sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir],
- common->data_size);
- VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n",
- name, cmnd_size, dirletter[(int) data_dir],
- common->data_size_from_cmnd, common->cmnd_size, hdlen);
-
- /*
- * We can't reply at all until we know the correct data direction
- * and size.
- */
- if (common->data_size_from_cmnd == 0)
- data_dir = DATA_DIR_NONE;
- if (common->data_size < common->data_size_from_cmnd) {
- /*
- * Host data size < Device data size is a phase error.
- * Carry out the command, but only transfer as much as
- * we are allowed.
- */
- common->data_size_from_cmnd = common->data_size;
- common->phase_error = 1;
- }
- common->residue = common->data_size;
- common->usb_amount_left = common->data_size;
-
- /* Conflicting data directions is a phase error */
- if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) {
- common->phase_error = 1;
- return -EINVAL;
- }
-
- /* Verify the length of the command itself */
- if (cmnd_size != common->cmnd_size) {
-
- /*
- * Special case workaround: There are plenty of buggy SCSI
- * implementations. Many have issues with cbw->Length
- * field passing a wrong command size. For those cases we
- * always try to work around the problem by using the length
- * sent by the host side provided it is at least as large
- * as the correct command length.
- * Examples of such cases would be MS-Windows, which issues
- * REQUEST SENSE with cbw->Length == 12 where it should
- * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and
- * REQUEST SENSE with cbw->Length == 10 where it should
- * be 6 as well.
- */
- if (cmnd_size <= common->cmnd_size) {
- DBG(common, "%s is buggy! Expected length %d "
- "but we got %d\n", name,
- cmnd_size, common->cmnd_size);
- cmnd_size = common->cmnd_size;
- } else {
- common->phase_error = 1;
- return -EINVAL;
- }
- }
-
- /* Check that the LUN values are consistent */
- if (common->lun != lun)
- DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n",
- common->lun, lun);
-
- /* Check the LUN */
- curlun = common->curlun;
- if (curlun) {
- if (common->cmnd[0] != REQUEST_SENSE) {
- curlun->sense_data = SS_NO_SENSE;
- curlun->sense_data_info = 0;
- curlun->info_valid = 0;
- }
- } else {
- common->bad_lun_okay = 0;
-
- /*
- * INQUIRY and REQUEST SENSE commands are explicitly allowed
- * to use unsupported LUNs; all others may not.
- */
- if (common->cmnd[0] != INQUIRY &&
- common->cmnd[0] != REQUEST_SENSE) {
- DBG(common, "unsupported LUN %d\n", common->lun);
- return -EINVAL;
- }
- }
-
- /*
- * If a unit attention condition exists, only INQUIRY and
- * REQUEST SENSE commands are allowed; anything else must fail.
- */
- if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
- common->cmnd[0] != INQUIRY &&
- common->cmnd[0] != REQUEST_SENSE) {
- curlun->sense_data = curlun->unit_attention_data;
- curlun->unit_attention_data = SS_NO_SENSE;
- return -EINVAL;
- }
-
- /* Check that only command bytes listed in the mask are non-zero */
- common->cmnd[1] &= 0x1f; /* Mask away the LUN */
- for (i = 1; i < cmnd_size; ++i) {
- if (common->cmnd[i] && !(mask & (1 << i))) {
- if (curlun)
- curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
- return -EINVAL;
- }
- }
-
- /* If the medium isn't mounted and the command needs to access
- * it, return an error. */
- if (curlun && !fsg_lun_is_open(curlun) && needs_medium) {
- curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* wrapper of check_command for data size in blocks handling */
-static int check_command_size_in_blocks(struct fsg_common *common,
- int cmnd_size, enum data_direction data_dir,
- unsigned int mask, int needs_medium, const char *name)
-{
- if (common->curlun)
- common->data_size_from_cmnd <<= common->curlun->blkbits;
- return check_command(common, cmnd_size, data_dir,
- mask, needs_medium, name);
-}
-
-static int do_scsi_command(struct fsg_common *common)
-{
- struct fsg_buffhd *bh;
- int rc;
- int reply = -EINVAL;
- int i;
- static char unknown[16];
-
- dump_cdb(common);
-
- /* Wait for the next buffer to become available for data or status */
- bh = common->next_buffhd_to_fill;
- common->next_buffhd_to_drain = bh;
- while (bh->state != BUF_STATE_EMPTY) {
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
- common->phase_error = 0;
- common->short_packet_received = 0;
-
- down_read(&common->filesem); /* We're using the backing file */
- switch (common->cmnd[0]) {
-
- case INQUIRY:
- common->data_size_from_cmnd = common->cmnd[4];
- reply = check_command(common, 6, DATA_DIR_TO_HOST,
- (1<<4), 0,
- "INQUIRY");
- if (reply == 0)
- reply = do_inquiry(common, bh);
- break;
-
- case MODE_SELECT:
- common->data_size_from_cmnd = common->cmnd[4];
- reply = check_command(common, 6, DATA_DIR_FROM_HOST,
- (1<<1) | (1<<4), 0,
- "MODE SELECT(6)");
- if (reply == 0)
- reply = do_mode_select(common, bh);
- break;
-
- case MODE_SELECT_10:
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command(common, 10, DATA_DIR_FROM_HOST,
- (1<<1) | (3<<7), 0,
- "MODE SELECT(10)");
- if (reply == 0)
- reply = do_mode_select(common, bh);
- break;
-
- case MODE_SENSE:
- common->data_size_from_cmnd = common->cmnd[4];
- reply = check_command(common, 6, DATA_DIR_TO_HOST,
- (1<<1) | (1<<2) | (1<<4), 0,
- "MODE SENSE(6)");
- if (reply == 0)
- reply = do_mode_sense(common, bh);
- break;
-
- case MODE_SENSE_10:
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (1<<1) | (1<<2) | (3<<7), 0,
- "MODE SENSE(10)");
- if (reply == 0)
- reply = do_mode_sense(common, bh);
- break;
-
- case ALLOW_MEDIUM_REMOVAL:
- common->data_size_from_cmnd = 0;
- reply = check_command(common, 6, DATA_DIR_NONE,
- (1<<4), 0,
- "PREVENT-ALLOW MEDIUM REMOVAL");
- if (reply == 0)
- reply = do_prevent_allow(common);
- break;
-
- case READ_6:
- i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0) ? 256 : i;
- reply = check_command_size_in_blocks(common, 6,
- DATA_DIR_TO_HOST,
- (7<<1) | (1<<4), 1,
- "READ(6)");
- if (reply == 0)
- reply = do_read(common);
- break;
-
- case READ_10:
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command_size_in_blocks(common, 10,
- DATA_DIR_TO_HOST,
- (1<<1) | (0xf<<2) | (3<<7), 1,
- "READ(10)");
- if (reply == 0)
- reply = do_read(common);
- break;
-
- case READ_12:
- common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]);
- reply = check_command_size_in_blocks(common, 12,
- DATA_DIR_TO_HOST,
- (1<<1) | (0xf<<2) | (0xf<<6), 1,
- "READ(12)");
- if (reply == 0)
- reply = do_read(common);
- break;
-
- case READ_CAPACITY:
- common->data_size_from_cmnd = 8;
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (0xf<<2) | (1<<8), 1,
- "READ CAPACITY");
- if (reply == 0)
- reply = do_read_capacity(common, bh);
- break;
-
- case READ_HEADER:
- if (!common->curlun || !common->curlun->cdrom)
- goto unknown_cmnd;
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (3<<7) | (0x1f<<1), 1,
- "READ HEADER");
- if (reply == 0)
- reply = do_read_header(common, bh);
- break;
-
- case READ_TOC:
- if (!common->curlun || !common->curlun->cdrom)
- goto unknown_cmnd;
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (7<<6) | (1<<1), 1,
- "READ TOC");
- if (reply == 0)
- reply = do_read_toc(common, bh);
- break;
-
- case READ_FORMAT_CAPACITIES:
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command(common, 10, DATA_DIR_TO_HOST,
- (3<<7), 1,
- "READ FORMAT CAPACITIES");
- if (reply == 0)
- reply = do_read_format_capacities(common, bh);
- break;
-
- case REQUEST_SENSE:
- common->data_size_from_cmnd = common->cmnd[4];
- reply = check_command(common, 6, DATA_DIR_TO_HOST,
- (1<<4), 0,
- "REQUEST SENSE");
- if (reply == 0)
- reply = do_request_sense(common, bh);
- break;
-
- case START_STOP:
- common->data_size_from_cmnd = 0;
- reply = check_command(common, 6, DATA_DIR_NONE,
- (1<<1) | (1<<4), 0,
- "START-STOP UNIT");
- if (reply == 0)
- reply = do_start_stop(common);
- break;
-
- case SYNCHRONIZE_CACHE:
- common->data_size_from_cmnd = 0;
- reply = check_command(common, 10, DATA_DIR_NONE,
- (0xf<<2) | (3<<7), 1,
- "SYNCHRONIZE CACHE");
- if (reply == 0)
- reply = do_synchronize_cache(common);
- break;
-
- case TEST_UNIT_READY:
- common->data_size_from_cmnd = 0;
- reply = check_command(common, 6, DATA_DIR_NONE,
- 0, 1,
- "TEST UNIT READY");
- break;
-
- /*
- * Although optional, this command is used by MS-Windows. We
- * support a minimal version: BytChk must be 0.
- */
- case VERIFY:
- common->data_size_from_cmnd = 0;
- reply = check_command(common, 10, DATA_DIR_NONE,
- (1<<1) | (0xf<<2) | (3<<7), 1,
- "VERIFY");
- if (reply == 0)
- reply = do_verify(common);
- break;
-
- case WRITE_6:
- i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0) ? 256 : i;
- reply = check_command_size_in_blocks(common, 6,
- DATA_DIR_FROM_HOST,
- (7<<1) | (1<<4), 1,
- "WRITE(6)");
- if (reply == 0)
- reply = do_write(common);
- break;
-
- case WRITE_10:
- common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]);
- reply = check_command_size_in_blocks(common, 10,
- DATA_DIR_FROM_HOST,
- (1<<1) | (0xf<<2) | (3<<7), 1,
- "WRITE(10)");
- if (reply == 0)
- reply = do_write(common);
- break;
-
- case WRITE_12:
- common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]);
- reply = check_command_size_in_blocks(common, 12,
- DATA_DIR_FROM_HOST,
- (1<<1) | (0xf<<2) | (0xf<<6), 1,
- "WRITE(12)");
- if (reply == 0)
- reply = do_write(common);
- break;
-
- /*
- * Some mandatory commands that we recognize but don't implement.
- * They don't mean much in this setting. It's left as an exercise
- * for anyone interested to implement RESERVE and RELEASE in terms
- * of Posix locks.
- */
- case FORMAT_UNIT:
- case RELEASE:
- case RESERVE:
- case SEND_DIAGNOSTIC:
- /* Fall through */
-
- default:
-unknown_cmnd:
- common->data_size_from_cmnd = 0;
- sprintf(unknown, "Unknown x%02x", common->cmnd[0]);
- reply = check_command(common, common->cmnd_size,
- DATA_DIR_UNKNOWN, ~0, 0, unknown);
- if (reply == 0) {
- common->curlun->sense_data = SS_INVALID_COMMAND;
- reply = -EINVAL;
- }
- break;
- }
- up_read(&common->filesem);
-
- if (reply == -EINTR || signal_pending(current))
- return -EINTR;
-
- /* Set up the single reply buffer for finish_reply() */
- if (reply == -EINVAL)
- reply = 0; /* Error reply length */
- if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
- reply = min((u32)reply, common->data_size_from_cmnd);
- bh->inreq->length = reply;
- bh->state = BUF_STATE_FULL;
- common->residue -= reply;
- } /* Otherwise it's already set */
-
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
-{
- struct usb_request *req = bh->outreq;
- struct bulk_cb_wrap *cbw = req->buf;
- struct fsg_common *common = fsg->common;
-
- /* Was this a real packet? Should it be ignored? */
- if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
- return -EINVAL;
-
- /* Is the CBW valid? */
- if (req->actual != US_BULK_CB_WRAP_LEN ||
- cbw->Signature != cpu_to_le32(
- US_BULK_CB_SIGN)) {
- DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
- req->actual,
- le32_to_cpu(cbw->Signature));
-
- /*
- * The Bulk-only spec says we MUST stall the IN endpoint
- * (6.6.1), so it's unavoidable. It also says we must
- * retain this state until the next reset, but there's
- * no way to tell the controller driver it should ignore
- * Clear-Feature(HALT) requests.
- *
- * We aren't required to halt the OUT endpoint; instead
- * we can simply accept and discard any data received
- * until the next reset.
- */
- wedge_bulk_in_endpoint(fsg);
- set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
- return -EINVAL;
- }
-
- /* Is the CBW meaningful? */
- if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
- cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
- DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
- "cmdlen %u\n",
- cbw->Lun, cbw->Flags, cbw->Length);
-
- /*
- * We can do anything we want here, so let's stall the
- * bulk pipes if we are allowed to.
- */
- if (common->can_stall) {
- fsg_set_halt(fsg, fsg->bulk_out);
- halt_bulk_in_endpoint(fsg);
- }
- return -EINVAL;
- }
-
- /* Save the command for later */
- common->cmnd_size = cbw->Length;
- memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
- if (cbw->Flags & US_BULK_FLAG_IN)
- common->data_dir = DATA_DIR_TO_HOST;
- else
- common->data_dir = DATA_DIR_FROM_HOST;
- common->data_size = le32_to_cpu(cbw->DataTransferLength);
- if (common->data_size == 0)
- common->data_dir = DATA_DIR_NONE;
- common->lun = cbw->Lun;
- if (common->lun >= 0 && common->lun < common->nluns)
- common->curlun = &common->luns[common->lun];
- else
- common->curlun = NULL;
- common->tag = cbw->Tag;
- return 0;
-}
-
-static int get_next_command(struct fsg_common *common)
-{
- struct fsg_buffhd *bh;
- int rc = 0;
-
- /* Wait for the next buffer to become available */
- bh = common->next_buffhd_to_fill;
- while (bh->state != BUF_STATE_EMPTY) {
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
-
- /* Queue a request to read a Bulk-only CBW */
- set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
- if (!start_out_transfer(common, bh))
- /* Don't know what to do if common->fsg is NULL */
- return -EIO;
-
- /*
- * We will drain the buffer in software, which means we
- * can reuse it for the next filling. No need to advance
- * next_buffhd_to_fill.
- */
-
- /* Wait for the CBW to arrive */
- while (bh->state != BUF_STATE_FULL) {
- rc = sleep_thread(common);
- if (rc)
- return rc;
- }
- smp_rmb();
- rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO;
- bh->state = BUF_STATE_EMPTY;
-
- return rc;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
- struct usb_request **preq)
-{
- *preq = usb_ep_alloc_request(ep, GFP_ATOMIC);
- if (*preq)
- return 0;
- ERROR(common, "can't allocate request for %s\n", ep->name);
- return -ENOMEM;
-}
-
-/* Reset interface setting and re-init endpoint state (toggle etc). */
-static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
-{
- struct fsg_dev *fsg;
- int i, rc = 0;
-
- if (common->running)
- DBG(common, "reset interface\n");
-
-reset:
- /* Deallocate the requests */
- if (common->fsg) {
- fsg = common->fsg;
-
- for (i = 0; i < fsg_num_buffers; ++i) {
- struct fsg_buffhd *bh = &common->buffhds[i];
-
- if (bh->inreq) {
- usb_ep_free_request(fsg->bulk_in, bh->inreq);
- bh->inreq = NULL;
- }
- if (bh->outreq) {
- usb_ep_free_request(fsg->bulk_out, bh->outreq);
- bh->outreq = NULL;
- }
- }
-
- /* Disable the endpoints */
- if (fsg->bulk_in_enabled) {
- usb_ep_disable(fsg->bulk_in);
- fsg->bulk_in_enabled = 0;
- }
- if (fsg->bulk_out_enabled) {
- usb_ep_disable(fsg->bulk_out);
- fsg->bulk_out_enabled = 0;
- }
-
- common->fsg = NULL;
- wake_up(&common->fsg_wait);
- }
-
- common->running = 0;
- if (!new_fsg || rc)
- return rc;
-
- common->fsg = new_fsg;
- fsg = common->fsg;
-
- /* Enable the endpoints */
- rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
- if (rc)
- goto reset;
- rc = usb_ep_enable(fsg->bulk_in);
- if (rc)
- goto reset;
- fsg->bulk_in->driver_data = common;
- fsg->bulk_in_enabled = 1;
-
- rc = config_ep_by_speed(common->gadget, &(fsg->function),
- fsg->bulk_out);
- if (rc)
- goto reset;
- rc = usb_ep_enable(fsg->bulk_out);
- if (rc)
- goto reset;
- fsg->bulk_out->driver_data = common;
- fsg->bulk_out_enabled = 1;
- common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
- clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
-
- /* Allocate the requests */
- for (i = 0; i < fsg_num_buffers; ++i) {
- struct fsg_buffhd *bh = &common->buffhds[i];
-
- rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
- if (rc)
- goto reset;
- rc = alloc_request(common, fsg->bulk_out, &bh->outreq);
- if (rc)
- goto reset;
- bh->inreq->buf = bh->outreq->buf = bh->buf;
- bh->inreq->context = bh->outreq->context = bh;
- bh->inreq->complete = bulk_in_complete;
- bh->outreq->complete = bulk_out_complete;
- }
-
- common->running = 1;
- for (i = 0; i < common->nluns; ++i)
- common->luns[i].unit_attention_data = SS_RESET_OCCURRED;
- return rc;
-}
-
-
-/****************************** ALT CONFIGS ******************************/
-
-static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
- struct fsg_dev *fsg = fsg_from_func(f);
- fsg->common->new_fsg = fsg;
- raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
- return USB_GADGET_DELAYED_STATUS;
-}
-
-static void fsg_disable(struct usb_function *f)
-{
- struct fsg_dev *fsg = fsg_from_func(f);
- fsg->common->new_fsg = NULL;
- raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void handle_exception(struct fsg_common *common)
-{
- siginfo_t info;
- int i;
- struct fsg_buffhd *bh;
- enum fsg_state old_state;
- struct fsg_lun *curlun;
- unsigned int exception_req_tag;
-
- /*
- * Clear the existing signals. Anything but SIGUSR1 is converted
- * into a high-priority EXIT exception.
- */
- for (;;) {
- int sig =
- dequeue_signal_lock(current, &current->blocked, &info);
- if (!sig)
- break;
- if (sig != SIGUSR1) {
- if (common->state < FSG_STATE_EXIT)
- DBG(common, "Main thread exiting on signal\n");
- raise_exception(common, FSG_STATE_EXIT);
- }
- }
-
- /* Cancel all the pending transfers */
- if (likely(common->fsg)) {
- for (i = 0; i < fsg_num_buffers; ++i) {
- bh = &common->buffhds[i];
- if (bh->inreq_busy)
- usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
- if (bh->outreq_busy)
- usb_ep_dequeue(common->fsg->bulk_out,
- bh->outreq);
- }
-
- /* Wait until everything is idle */
- for (;;) {
- int num_active = 0;
- for (i = 0; i < fsg_num_buffers; ++i) {
- bh = &common->buffhds[i];
- num_active += bh->inreq_busy + bh->outreq_busy;
- }
- if (num_active == 0)
- break;
- if (sleep_thread(common))
- return;
- }
-
- /* Clear out the controller's fifos */
- if (common->fsg->bulk_in_enabled)
- usb_ep_fifo_flush(common->fsg->bulk_in);
- if (common->fsg->bulk_out_enabled)
- usb_ep_fifo_flush(common->fsg->bulk_out);
- }
-
- /*
- * Reset the I/O buffer states and pointers, the SCSI
- * state, and the exception. Then invoke the handler.
- */
- spin_lock_irq(&common->lock);
-
- for (i = 0; i < fsg_num_buffers; ++i) {
- bh = &common->buffhds[i];
- bh->state = BUF_STATE_EMPTY;
- }
- common->next_buffhd_to_fill = &common->buffhds[0];
- common->next_buffhd_to_drain = &common->buffhds[0];
- exception_req_tag = common->exception_req_tag;
- old_state = common->state;
-
- if (old_state == FSG_STATE_ABORT_BULK_OUT)
- common->state = FSG_STATE_STATUS_PHASE;
- else {
- for (i = 0; i < common->nluns; ++i) {
- curlun = &common->luns[i];
- curlun->prevent_medium_removal = 0;
- curlun->sense_data = SS_NO_SENSE;
- curlun->unit_attention_data = SS_NO_SENSE;
- curlun->sense_data_info = 0;
- curlun->info_valid = 0;
- }
- common->state = FSG_STATE_IDLE;
- }
- spin_unlock_irq(&common->lock);
-
- /* Carry out any extra actions required for the exception */
- switch (old_state) {
- case FSG_STATE_ABORT_BULK_OUT:
- send_status(common);
- spin_lock_irq(&common->lock);
- if (common->state == FSG_STATE_STATUS_PHASE)
- common->state = FSG_STATE_IDLE;
- spin_unlock_irq(&common->lock);
- break;
-
- case FSG_STATE_RESET:
- /*
- * In case we were forced against our will to halt a
- * bulk endpoint, clear the halt now. (The SuperH UDC
- * requires this.)
- */
- if (!fsg_is_set(common))
- break;
- if (test_and_clear_bit(IGNORE_BULK_OUT,
- &common->fsg->atomic_bitflags))
- usb_ep_clear_halt(common->fsg->bulk_in);
-
- if (common->ep0_req_tag == exception_req_tag)
- ep0_queue(common); /* Complete the status stage */
-
- /*
- * Technically this should go here, but it would only be
- * a waste of time. Ditto for the INTERFACE_CHANGE and
- * CONFIG_CHANGE cases.
- */
- /* for (i = 0; i < common->nluns; ++i) */
- /* common->luns[i].unit_attention_data = */
- /* SS_RESET_OCCURRED; */
- break;
-
- case FSG_STATE_CONFIG_CHANGE:
- do_set_interface(common, common->new_fsg);
- if (common->new_fsg)
- usb_composite_setup_continue(common->cdev);
- break;
-
- case FSG_STATE_EXIT:
- case FSG_STATE_TERMINATED:
- do_set_interface(common, NULL); /* Free resources */
- spin_lock_irq(&common->lock);
- common->state = FSG_STATE_TERMINATED; /* Stop the thread */
- spin_unlock_irq(&common->lock);
- break;
-
- case FSG_STATE_INTERFACE_CHANGE:
- case FSG_STATE_DISCONNECT:
- case FSG_STATE_COMMAND_PHASE:
- case FSG_STATE_DATA_PHASE:
- case FSG_STATE_STATUS_PHASE:
- case FSG_STATE_IDLE:
- break;
- }
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static int fsg_main_thread(void *common_)
-{
- struct fsg_common *common = common_;
-
- /*
- * Allow the thread to be killed by a signal, but set the signal mask
- * to block everything but INT, TERM, KILL, and USR1.
- */
- allow_signal(SIGINT);
- allow_signal(SIGTERM);
- allow_signal(SIGKILL);
- allow_signal(SIGUSR1);
-
- /* Allow the thread to be frozen */
- set_freezable();
-
- /*
- * Arrange for userspace references to be interpreted as kernel
- * pointers. That way we can pass a kernel pointer to a routine
- * that expects a __user pointer and it will work okay.
- */
- set_fs(get_ds());
-
- /* The main loop */
- while (common->state != FSG_STATE_TERMINATED) {
- if (exception_in_progress(common) || signal_pending(current)) {
- handle_exception(common);
- continue;
- }
-
- if (!common->running) {
- sleep_thread(common);
- continue;
- }
-
- if (get_next_command(common))
- continue;
-
- spin_lock_irq(&common->lock);
- if (!exception_in_progress(common))
- common->state = FSG_STATE_DATA_PHASE;
- spin_unlock_irq(&common->lock);
-
- if (do_scsi_command(common) || finish_reply(common))
- continue;
-
- spin_lock_irq(&common->lock);
- if (!exception_in_progress(common))
- common->state = FSG_STATE_STATUS_PHASE;
- spin_unlock_irq(&common->lock);
-
- if (send_status(common))
- continue;
-
- spin_lock_irq(&common->lock);
- if (!exception_in_progress(common))
- common->state = FSG_STATE_IDLE;
- spin_unlock_irq(&common->lock);
- }
-
- spin_lock_irq(&common->lock);
- common->thread_task = NULL;
- spin_unlock_irq(&common->lock);
-
- if (!common->ops || !common->ops->thread_exits
- || common->ops->thread_exits(common) < 0) {
- struct fsg_lun *curlun = common->luns;
- unsigned i = common->nluns;
-
- down_write(&common->filesem);
- for (; i--; ++curlun) {
- if (!fsg_lun_is_open(curlun))
- continue;
-
- fsg_lun_close(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
- up_write(&common->filesem);
- }
-
- /* Let fsg_unbind() know the thread has exited */
- complete_and_exit(&common->thread_notifier, 0);
-}
-
-
-/*************************** DEVICE ATTRIBUTES ***************************/
-
-static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
-static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
-static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
-
-static struct device_attribute dev_attr_ro_cdrom =
- __ATTR(ro, 0444, fsg_show_ro, NULL);
-static struct device_attribute dev_attr_file_nonremovable =
- __ATTR(file, 0444, fsg_show_file, NULL);
-
-
-/****************************** FSG COMMON ******************************/
-
-static void fsg_common_release(struct kref *ref);
-
-static void fsg_lun_release(struct device *dev)
-{
- /* Nothing needs to be done */
-}
-
-static inline void fsg_common_get(struct fsg_common *common)
-{
- kref_get(&common->ref);
-}
-
-static inline void fsg_common_put(struct fsg_common *common)
-{
- kref_put(&common->ref, fsg_common_release);
-}
-
-static struct fsg_common *fsg_common_init(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- struct fsg_config *cfg)
-{
- struct usb_gadget *gadget = cdev->gadget;
- struct fsg_buffhd *bh;
- struct fsg_lun *curlun;
- struct fsg_lun_config *lcfg;
- int nluns, i, rc;
- char *pathbuf;
-
- rc = fsg_num_buffers_validate();
- if (rc != 0)
- return ERR_PTR(rc);
-
- /* Find out how many LUNs there should be */
- nluns = cfg->nluns;
- if (nluns < 1 || nluns > FSG_MAX_LUNS) {
- dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns);
- return ERR_PTR(-EINVAL);
- }
-
- /* Allocate? */
- if (!common) {
- common = kzalloc(sizeof *common, GFP_KERNEL);
- if (!common)
- return ERR_PTR(-ENOMEM);
- common->free_storage_on_release = 1;
- } else {
- memset(common, 0, sizeof *common);
- common->free_storage_on_release = 0;
- }
-
- common->buffhds = kcalloc(fsg_num_buffers,
- sizeof *(common->buffhds), GFP_KERNEL);
- if (!common->buffhds) {
- if (common->free_storage_on_release)
- kfree(common);
- return ERR_PTR(-ENOMEM);
- }
-
- common->ops = cfg->ops;
- common->private_data = cfg->private_data;
-
- common->gadget = gadget;
- common->ep0 = gadget->ep0;
- common->ep0req = cdev->req;
- common->cdev = cdev;
-
- /* Maybe allocate device-global string IDs, and patch descriptors */
- if (fsg_strings[FSG_STRING_INTERFACE].id == 0) {
- rc = usb_string_id(cdev);
- if (unlikely(rc < 0))
- goto error_release;
- fsg_strings[FSG_STRING_INTERFACE].id = rc;
- fsg_intf_desc.iInterface = rc;
- }
-
- /*
- * Create the LUNs, open their backing files, and register the
- * LUN devices in sysfs.
- */
- curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
- if (unlikely(!curlun)) {
- rc = -ENOMEM;
- goto error_release;
- }
- common->luns = curlun;
-
- init_rwsem(&common->filesem);
-
- for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) {
- curlun->cdrom = !!lcfg->cdrom;
- curlun->ro = lcfg->cdrom || lcfg->ro;
- curlun->initially_ro = curlun->ro;
- curlun->removable = lcfg->removable;
- curlun->dev.release = fsg_lun_release;
- curlun->dev.parent = &gadget->dev;
- /* curlun->dev.driver = &fsg_driver.driver; XXX */
- dev_set_drvdata(&curlun->dev, &common->filesem);
- dev_set_name(&curlun->dev, "lun%d", i);
-
- rc = device_register(&curlun->dev);
- if (rc) {
- INFO(common, "failed to register LUN%d: %d\n", i, rc);
- common->nluns = i;
- put_device(&curlun->dev);
- goto error_release;
- }
-
- rc = device_create_file(&curlun->dev,
- curlun->cdrom
- ? &dev_attr_ro_cdrom
- : &dev_attr_ro);
- if (rc)
- goto error_luns;
- rc = device_create_file(&curlun->dev,
- curlun->removable
- ? &dev_attr_file
- : &dev_attr_file_nonremovable);
- if (rc)
- goto error_luns;
- rc = device_create_file(&curlun->dev, &dev_attr_nofua);
- if (rc)
- goto error_luns;
-
- if (lcfg->filename) {
- rc = fsg_lun_open(curlun, lcfg->filename);
- if (rc)
- goto error_luns;
- } else if (!curlun->removable) {
- ERROR(common, "no file given for LUN%d\n", i);
- rc = -EINVAL;
- goto error_luns;
- }
- }
- common->nluns = nluns;
-
- /* Data buffers cyclic list */
- bh = common->buffhds;
- i = fsg_num_buffers;
- goto buffhds_first_it;
- do {
- bh->next = bh + 1;
- ++bh;
-buffhds_first_it:
- bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL);
- if (unlikely(!bh->buf)) {
- rc = -ENOMEM;
- goto error_release;
- }
- } while (--i);
- bh->next = common->buffhds;
-
- /* Prepare inquiryString */
- if (cfg->release != 0xffff) {
- i = cfg->release;
- } else {
- i = usb_gadget_controller_number(gadget);
- if (i >= 0) {
- i = 0x0300 + i;
- } else {
- WARNING(common, "controller '%s' not recognized\n",
- gadget->name);
- i = 0x0399;
- }
- }
- snprintf(common->inquiry_string, sizeof common->inquiry_string,
- "%-8s%-16s%04x", cfg->vendor_name ?: "Linux",
- /* Assume product name dependent on the first LUN */
- cfg->product_name ?: (common->luns->cdrom
- ? "File-Stor Gadget"
- : "File-CD Gadget"),
- i);
-
- /*
- * Some peripheral controllers are known not to be able to
- * halt bulk endpoints correctly. If one of them is present,
- * disable stalls.
- */
- common->can_stall = cfg->can_stall &&
- !(gadget_is_at91(common->gadget));
-
- spin_lock_init(&common->lock);
- kref_init(&common->ref);
-
- /* Tell the thread to start working */
- common->thread_task =
- kthread_create(fsg_main_thread, common, "file-storage");
- if (IS_ERR(common->thread_task)) {
- rc = PTR_ERR(common->thread_task);
- goto error_release;
- }
- init_completion(&common->thread_notifier);
- init_waitqueue_head(&common->fsg_wait);
-
- /* Information */
- INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
- INFO(common, "Number of LUNs=%d\n", common->nluns);
-
- pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
- for (i = 0, nluns = common->nluns, curlun = common->luns;
- i < nluns;
- ++curlun, ++i) {
- char *p = "(no medium)";
- if (fsg_lun_is_open(curlun)) {
- p = "(error)";
- if (pathbuf) {
- p = d_path(&curlun->filp->f_path,
- pathbuf, PATH_MAX);
- if (IS_ERR(p))
- p = "(error)";
- }
- }
- LINFO(curlun, "LUN: %s%s%sfile: %s\n",
- curlun->removable ? "removable " : "",
- curlun->ro ? "read only " : "",
- curlun->cdrom ? "CD-ROM " : "",
- p);
- }
- kfree(pathbuf);
-
- DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));
-
- wake_up_process(common->thread_task);
-
- return common;
-
-error_luns:
- common->nluns = i + 1;
-error_release:
- common->state = FSG_STATE_TERMINATED; /* The thread is dead */
- /* Call fsg_common_release() directly, ref might be not initialised. */
- fsg_common_release(&common->ref);
- return ERR_PTR(rc);
-}
-
-static void fsg_common_release(struct kref *ref)
-{
- struct fsg_common *common = container_of(ref, struct fsg_common, ref);
-
- /* If the thread isn't already dead, tell it to exit now */
- if (common->state != FSG_STATE_TERMINATED) {
- raise_exception(common, FSG_STATE_EXIT);
- wait_for_completion(&common->thread_notifier);
- }
-
- if (likely(common->luns)) {
- struct fsg_lun *lun = common->luns;
- unsigned i = common->nluns;
-
- /* In error recovery common->nluns may be zero. */
- for (; i; --i, ++lun) {
- device_remove_file(&lun->dev, &dev_attr_nofua);
- device_remove_file(&lun->dev,
- lun->cdrom
- ? &dev_attr_ro_cdrom
- : &dev_attr_ro);
- device_remove_file(&lun->dev,
- lun->removable
- ? &dev_attr_file
- : &dev_attr_file_nonremovable);
- fsg_lun_close(lun);
- device_unregister(&lun->dev);
- }
-
- kfree(common->luns);
- }
-
- {
- struct fsg_buffhd *bh = common->buffhds;
- unsigned i = fsg_num_buffers;
- do {
- kfree(bh->buf);
- } while (++bh, --i);
- }
-
- kfree(common->buffhds);
- if (common->free_storage_on_release)
- kfree(common);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct fsg_dev *fsg = fsg_from_func(f);
- struct fsg_common *common = fsg->common;
-
- DBG(fsg, "unbind\n");
- if (fsg->common->fsg == fsg) {
- fsg->common->new_fsg = NULL;
- raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
- /* FIXME: make interruptible or killable somehow? */
- wait_event(common->fsg_wait, common->fsg != fsg);
- }
-
- fsg_common_put(common);
- usb_free_descriptors(fsg->function.descriptors);
- usb_free_descriptors(fsg->function.hs_descriptors);
- usb_free_descriptors(fsg->function.ss_descriptors);
- kfree(fsg);
-}
-
-static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
-{
- struct fsg_dev *fsg = fsg_from_func(f);
- struct usb_gadget *gadget = c->cdev->gadget;
- int i;
- struct usb_ep *ep;
-
- fsg->gadget = gadget;
-
- /* New interface */
- i = usb_interface_id(c, f);
- if (i < 0)
- return i;
- fsg_intf_desc.bInterfaceNumber = i;
- fsg->interface_number = i;
-
- /* Find all the endpoints we will use */
- ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc);
- if (!ep)
- goto autoconf_fail;
- ep->driver_data = fsg->common; /* claim the endpoint */
- fsg->bulk_in = ep;
-
- ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc);
- if (!ep)
- goto autoconf_fail;
- ep->driver_data = fsg->common; /* claim the endpoint */
- fsg->bulk_out = ep;
-
- /* Copy descriptors */
- f->descriptors = usb_copy_descriptors(fsg_fs_function);
- if (unlikely(!f->descriptors))
- return -ENOMEM;
-
- if (gadget_is_dualspeed(gadget)) {
- /* Assume endpoint addresses are the same for both speeds */
- fsg_hs_bulk_in_desc.bEndpointAddress =
- fsg_fs_bulk_in_desc.bEndpointAddress;
- fsg_hs_bulk_out_desc.bEndpointAddress =
- fsg_fs_bulk_out_desc.bEndpointAddress;
- f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
- if (unlikely(!f->hs_descriptors)) {
- usb_free_descriptors(f->descriptors);
- return -ENOMEM;
- }
- }
-
- if (gadget_is_superspeed(gadget)) {
- unsigned max_burst;
-
- /* Calculate bMaxBurst, we know packet size is 1024 */
- max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
-
- fsg_ss_bulk_in_desc.bEndpointAddress =
- fsg_fs_bulk_in_desc.bEndpointAddress;
- fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
-
- fsg_ss_bulk_out_desc.bEndpointAddress =
- fsg_fs_bulk_out_desc.bEndpointAddress;
- fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
-
- f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
- if (unlikely(!f->ss_descriptors)) {
- usb_free_descriptors(f->hs_descriptors);
- usb_free_descriptors(f->descriptors);
- return -ENOMEM;
- }
- }
-
- return 0;
-
-autoconf_fail:
- ERROR(fsg, "unable to autoconfigure all endpoints\n");
- return -ENOTSUPP;
-}
-
-
-/****************************** ADD FUNCTION ******************************/
-
-static struct usb_gadget_strings *fsg_strings_array[] = {
- &fsg_stringtab,
- NULL,
-};
-
-static int fsg_bind_config(struct usb_composite_dev *cdev,
- struct usb_configuration *c,
- struct fsg_common *common)
-{
- struct fsg_dev *fsg;
- int rc;
-
- fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
- if (unlikely(!fsg))
- return -ENOMEM;
-
- fsg->function.name = FSG_DRIVER_DESC;
- fsg->function.strings = fsg_strings_array;
- fsg->function.bind = fsg_bind;
- fsg->function.unbind = fsg_unbind;
- fsg->function.setup = fsg_setup;
- fsg->function.set_alt = fsg_set_alt;
- fsg->function.disable = fsg_disable;
-
- fsg->common = common;
- /*
- * Our caller holds a reference to common structure so we
- * don't have to be worry about it being freed until we return
- * from this function. So instead of incrementing counter now
- * and decrement in error recovery we increment it only when
- * call to usb_add_function() was successful.
- */
-
- rc = usb_add_function(c, &fsg->function);
- if (unlikely(rc))
- kfree(fsg);
- else
- fsg_common_get(fsg->common);
- return rc;
-}
-
-
-/************************* Module parameters *************************/
-
-struct fsg_module_parameters {
- char *file[FSG_MAX_LUNS];
- bool ro[FSG_MAX_LUNS];
- bool removable[FSG_MAX_LUNS];
- bool cdrom[FSG_MAX_LUNS];
- bool nofua[FSG_MAX_LUNS];
-
- unsigned int file_count, ro_count, removable_count, cdrom_count;
- unsigned int nofua_count;
- unsigned int luns; /* nluns */
- bool stall; /* can_stall */
-};
-
-#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
- module_param_array_named(prefix ## name, params.name, type, \
- &prefix ## params.name ## _count, \
- S_IRUGO); \
- MODULE_PARM_DESC(prefix ## name, desc)
-
-#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
- module_param_named(prefix ## name, params.name, type, \
- S_IRUGO); \
- MODULE_PARM_DESC(prefix ## name, desc)
-
-#define FSG_MODULE_PARAMETERS(prefix, params) \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \
- "names of backing files or devices"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \
- "true to force read-only"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \
- "true to simulate removable media"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
- "true to simulate CD-ROM instead of disk"); \
- _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \
- "true to ignore SCSI WRITE(10,12) FUA bit"); \
- _FSG_MODULE_PARAM(prefix, params, luns, uint, \
- "number of LUNs"); \
- _FSG_MODULE_PARAM(prefix, params, stall, bool, \
- "false to prevent bulk stalls")
-
-static void
-fsg_config_from_params(struct fsg_config *cfg,
- const struct fsg_module_parameters *params)
-{
- struct fsg_lun_config *lun;
- unsigned i;
-
- /* Configure LUNs */
- cfg->nluns =
- min(params->luns ?: (params->file_count ?: 1u),
- (unsigned)FSG_MAX_LUNS);
- for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
- lun->ro = !!params->ro[i];
- lun->cdrom = !!params->cdrom[i];
- lun->removable = !!params->removable[i];
- lun->filename =
- params->file_count > i && params->file[i][0]
- ? params->file[i]
- : 0;
- }
-
- /* Let MSF use defaults */
- cfg->vendor_name = 0;
- cfg->product_name = 0;
- cfg->release = 0xffff;
-
- cfg->ops = NULL;
- cfg->private_data = NULL;
-
- /* Finalise */
- cfg->can_stall = params->stall;
-}
-
-static inline struct fsg_common *
-fsg_common_from_params(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- const struct fsg_module_parameters *params)
- __attribute__((unused));
-static inline struct fsg_common *
-fsg_common_from_params(struct fsg_common *common,
- struct usb_composite_dev *cdev,
- const struct fsg_module_parameters *params)
-{
- struct fsg_config cfg;
- fsg_config_from_params(&cfg, params);
- return fsg_common_init(common, cdev, &cfg);
-}
diff --git a/drivers/staging/ccg/f_rndis.c b/drivers/staging/ccg/f_rndis.c
deleted file mode 100644
index b1681e45aca7..000000000000
--- a/drivers/staging/ccg/f_rndis.c
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * f_rndis.c -- RNDIS link function driver
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- * Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (mina86@mina86.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.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/etherdevice.h>
-
-#include <linux/atomic.h>
-
-#include "u_ether.h"
-#include "rndis.h"
-
-
-/*
- * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
- * been promoted instead of the standard CDC Ethernet. The published RNDIS
- * spec is ambiguous, incomplete, and needlessly complex. Variants such as
- * ActiveSync have even worse status in terms of specification.
- *
- * In short: it's a protocol controlled by (and for) Microsoft, not for an
- * Open ecosystem or markets. Linux supports it *only* because Microsoft
- * doesn't support the CDC Ethernet standard.
- *
- * The RNDIS data transfer model is complex, with multiple Ethernet packets
- * per USB message, and out of band data. The control model is built around
- * what's essentially an "RNDIS RPC" protocol. It's all wrapped in a CDC ACM
- * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
- * useless (they're ignored). RNDIS expects to be the only function in its
- * configuration, so it's no real help if you need composite devices; and
- * it expects to be the first configuration too.
- *
- * There is a single technical advantage of RNDIS over CDC Ethernet, if you
- * discount the fluff that its RPC can be made to deliver: it doesn't need
- * a NOP altsetting for the data interface. That lets it work on some of the
- * "so smart it's stupid" hardware which takes over configuration changes
- * from the software, and adds restrictions like "no altsettings".
- *
- * Unfortunately MSFT's RNDIS drivers are buggy. They hang or oops, and
- * have all sorts of contrary-to-specification oddities that can prevent
- * them from working sanely. Since bugfixes (or accurate specs, letting
- * Linux work around those bugs) are unlikely to ever come from MSFT, you
- * may want to avoid using RNDIS on purely operational grounds.
- *
- * Omissions from the RNDIS 1.0 specification include:
- *
- * - Power management ... references data that's scattered around lots
- * of other documentation, which is incorrect/incomplete there too.
- *
- * - There are various undocumented protocol requirements, like the need
- * to send garbage in some control-OUT messages.
- *
- * - MS-Windows drivers sometimes emit undocumented requests.
- */
-
-struct f_rndis {
- struct gether port;
- u8 ctrl_id, data_id;
- u8 ethaddr[ETH_ALEN];
- u32 vendorID;
- const char *manufacturer;
- int config;
-
- struct usb_ep *notify;
- struct usb_request *notify_req;
- atomic_t notify_count;
-};
-
-static inline struct f_rndis *func_to_rndis(struct usb_function *f)
-{
- return container_of(f, struct f_rndis, port.func);
-}
-
-/* peak (theoretical) bulk transfer rate in bits-per-second */
-static unsigned int bitrate(struct usb_gadget *g)
-{
- if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
- return 13 * 1024 * 8 * 1000 * 8;
- else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
- return 13 * 512 * 8 * 1000 * 8;
- else
- return 19 * 64 * 1 * 1000 * 8;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- */
-
-#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
-#define STATUS_BYTECOUNT 8 /* 8 bytes data */
-
-
-/* interface descriptor: */
-
-static struct usb_interface_descriptor rndis_control_intf = {
- .bLength = sizeof rndis_control_intf,
- .bDescriptorType = USB_DT_INTERFACE,
-
- /* .bInterfaceNumber = DYNAMIC */
- /* status endpoint is optional; this could be patched later */
- .bNumEndpoints = 1,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
- .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR,
- /* .iInterface = DYNAMIC */
-};
-
-static struct usb_cdc_header_desc header_desc = {
- .bLength = sizeof header_desc,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_HEADER_TYPE,
-
- .bcdCDC = cpu_to_le16(0x0110),
-};
-
-static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
- .bLength = sizeof call_mgmt_descriptor,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
-
- .bmCapabilities = 0x00,
- .bDataInterface = 0x01,
-};
-
-static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
- .bLength = sizeof rndis_acm_descriptor,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_ACM_TYPE,
-
- .bmCapabilities = 0x00,
-};
-
-static struct usb_cdc_union_desc rndis_union_desc = {
- .bLength = sizeof(rndis_union_desc),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_UNION_TYPE,
- /* .bMasterInterface0 = DYNAMIC */
- /* .bSlaveInterface0 = DYNAMIC */
-};
-
-/* the data interface has two bulk endpoints */
-
-static struct usb_interface_descriptor rndis_data_intf = {
- .bLength = sizeof rndis_data_intf,
- .bDescriptorType = USB_DT_INTERFACE,
-
- /* .bInterfaceNumber = DYNAMIC */
- .bNumEndpoints = 2,
- .bInterfaceClass = USB_CLASS_CDC_DATA,
- .bInterfaceSubClass = 0,
- .bInterfaceProtocol = 0,
- /* .iInterface = DYNAMIC */
-};
-
-
-static struct usb_interface_assoc_descriptor
-rndis_iad_descriptor = {
- .bLength = sizeof rndis_iad_descriptor,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
-
- .bFirstInterface = 0, /* XXX, hardcoded */
- .bInterfaceCount = 2, // control + data
- .bFunctionClass = USB_CLASS_COMM,
- .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
- .bFunctionProtocol = USB_CDC_PROTO_NONE,
- /* .iFunction = DYNAMIC */
-};
-
-/* full speed support: */
-
-static struct usb_endpoint_descriptor fs_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
- .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
-};
-
-static struct usb_endpoint_descriptor fs_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_endpoint_descriptor fs_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_descriptor_header *eth_fs_function[] = {
- (struct usb_descriptor_header *) &rndis_iad_descriptor,
-
- /* control interface matches ACM, not Ethernet */
- (struct usb_descriptor_header *) &rndis_control_intf,
- (struct usb_descriptor_header *) &header_desc,
- (struct usb_descriptor_header *) &call_mgmt_descriptor,
- (struct usb_descriptor_header *) &rndis_acm_descriptor,
- (struct usb_descriptor_header *) &rndis_union_desc,
- (struct usb_descriptor_header *) &fs_notify_desc,
-
- /* data interface has no altsetting */
- (struct usb_descriptor_header *) &rndis_data_intf,
- (struct usb_descriptor_header *) &fs_in_desc,
- (struct usb_descriptor_header *) &fs_out_desc,
- NULL,
-};
-
-/* high speed support: */
-
-static struct usb_endpoint_descriptor hs_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
- .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
-};
-
-static struct usb_endpoint_descriptor hs_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor hs_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_descriptor_header *eth_hs_function[] = {
- (struct usb_descriptor_header *) &rndis_iad_descriptor,
-
- /* control interface matches ACM, not Ethernet */
- (struct usb_descriptor_header *) &rndis_control_intf,
- (struct usb_descriptor_header *) &header_desc,
- (struct usb_descriptor_header *) &call_mgmt_descriptor,
- (struct usb_descriptor_header *) &rndis_acm_descriptor,
- (struct usb_descriptor_header *) &rndis_union_desc,
- (struct usb_descriptor_header *) &hs_notify_desc,
-
- /* data interface has no altsetting */
- (struct usb_descriptor_header *) &rndis_data_intf,
- (struct usb_descriptor_header *) &hs_in_desc,
- (struct usb_descriptor_header *) &hs_out_desc,
- NULL,
-};
-
-/* super speed support: */
-
-static struct usb_endpoint_descriptor ss_notify_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
- .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
-};
-
-static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
- .bLength = sizeof ss_intr_comp_desc,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 3 values can be tweaked if necessary */
- /* .bMaxBurst = 0, */
- /* .bmAttributes = 0, */
- .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
-};
-
-static struct usb_endpoint_descriptor ss_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_endpoint_descriptor ss_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
- .bLength = sizeof ss_bulk_comp_desc,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 2 values can be tweaked if necessary */
- /* .bMaxBurst = 0, */
- /* .bmAttributes = 0, */
-};
-
-static struct usb_descriptor_header *eth_ss_function[] = {
- (struct usb_descriptor_header *) &rndis_iad_descriptor,
-
- /* control interface matches ACM, not Ethernet */
- (struct usb_descriptor_header *) &rndis_control_intf,
- (struct usb_descriptor_header *) &header_desc,
- (struct usb_descriptor_header *) &call_mgmt_descriptor,
- (struct usb_descriptor_header *) &rndis_acm_descriptor,
- (struct usb_descriptor_header *) &rndis_union_desc,
- (struct usb_descriptor_header *) &ss_notify_desc,
- (struct usb_descriptor_header *) &ss_intr_comp_desc,
-
- /* data interface has no altsetting */
- (struct usb_descriptor_header *) &rndis_data_intf,
- (struct usb_descriptor_header *) &ss_in_desc,
- (struct usb_descriptor_header *) &ss_bulk_comp_desc,
- (struct usb_descriptor_header *) &ss_out_desc,
- (struct usb_descriptor_header *) &ss_bulk_comp_desc,
- NULL,
-};
-
-/* string descriptors: */
-
-static struct usb_string rndis_string_defs[] = {
- [0].s = "RNDIS Communications Control",
- [1].s = "RNDIS Ethernet Data",
- [2].s = "RNDIS",
- { } /* end of list */
-};
-
-static struct usb_gadget_strings rndis_string_table = {
- .language = 0x0409, /* en-us */
- .strings = rndis_string_defs,
-};
-
-static struct usb_gadget_strings *rndis_strings[] = {
- &rndis_string_table,
- NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static struct sk_buff *rndis_add_header(struct gether *port,
- struct sk_buff *skb)
-{
- struct sk_buff *skb2;
-
- skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
- if (skb2)
- rndis_add_hdr(skb2);
-
- dev_kfree_skb_any(skb);
- return skb2;
-}
-
-static void rndis_response_available(void *_rndis)
-{
- struct f_rndis *rndis = _rndis;
- struct usb_request *req = rndis->notify_req;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
- __le32 *data = req->buf;
- int status;
-
- if (atomic_inc_return(&rndis->notify_count) != 1)
- return;
-
- /* Send RNDIS RESPONSE_AVAILABLE notification; a
- * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
- *
- * This is the only notification defined by RNDIS.
- */
- data[0] = cpu_to_le32(1);
- data[1] = cpu_to_le32(0);
-
- status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
- if (status) {
- atomic_dec(&rndis->notify_count);
- DBG(cdev, "notify/0 --> %d\n", status);
- }
-}
-
-static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_rndis *rndis = req->context;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
- int status = req->status;
-
- /* after TX:
- * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
- * - RNDIS_RESPONSE_AVAILABLE (status/irq)
- */
- switch (status) {
- case -ECONNRESET:
- case -ESHUTDOWN:
- /* connection gone */
- atomic_set(&rndis->notify_count, 0);
- break;
- default:
- DBG(cdev, "RNDIS %s response error %d, %d/%d\n",
- ep->name, status,
- req->actual, req->length);
- /* FALLTHROUGH */
- case 0:
- if (ep != rndis->notify)
- break;
-
- /* handle multiple pending RNDIS_RESPONSE_AVAILABLE
- * notifications by resending until we're done
- */
- if (atomic_dec_and_test(&rndis->notify_count))
- break;
- status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
- if (status) {
- atomic_dec(&rndis->notify_count);
- DBG(cdev, "notify/1 --> %d\n", status);
- }
- break;
- }
-}
-
-static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct f_rndis *rndis = req->context;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
- int status;
-
- /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
-// spin_lock(&dev->lock);
- status = rndis_msg_parser(rndis->config, (u8 *) req->buf);
- if (status < 0)
- ERROR(cdev, "RNDIS command error %d, %d/%d\n",
- status, req->actual, req->length);
-// spin_unlock(&dev->lock);
-}
-
-static int
-rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
-{
- struct f_rndis *rndis = func_to_rndis(f);
- struct usb_composite_dev *cdev = f->config->cdev;
- struct usb_request *req = cdev->req;
- int value = -EOPNOTSUPP;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
-
- /* composite driver infrastructure handles everything except
- * CDC class messages; interface activation uses set_alt().
- */
- switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
-
- /* RNDIS uses the CDC command encapsulation mechanism to implement
- * an RPC scheme, with much getting/setting of attributes by OID.
- */
- case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
- | USB_CDC_SEND_ENCAPSULATED_COMMAND:
- if (w_value || w_index != rndis->ctrl_id)
- goto invalid;
- /* read the request; process it later */
- value = w_length;
- req->complete = rndis_command_complete;
- req->context = rndis;
- /* later, rndis_response_available() sends a notification */
- break;
-
- case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
- | USB_CDC_GET_ENCAPSULATED_RESPONSE:
- if (w_value || w_index != rndis->ctrl_id)
- goto invalid;
- else {
- u8 *buf;
- u32 n;
-
- /* return the result */
- buf = rndis_get_next_response(rndis->config, &n);
- if (buf) {
- memcpy(req->buf, buf, n);
- req->complete = rndis_response_complete;
- req->context = rndis;
- rndis_free_response(rndis->config, buf);
- value = n;
- }
- /* else stalls ... spec says to avoid that */
- }
- break;
-
- default:
-invalid:
- VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- }
-
- /* respond with data transfer or status phase? */
- if (value >= 0) {
- DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- req->zero = (value < w_length);
- req->length = value;
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
- if (value < 0)
- ERROR(cdev, "rndis response on err %d\n", value);
- }
-
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
-
-static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
- struct f_rndis *rndis = func_to_rndis(f);
- struct usb_composite_dev *cdev = f->config->cdev;
-
- /* we know alt == 0 */
-
- if (intf == rndis->ctrl_id) {
- if (rndis->notify->driver_data) {
- VDBG(cdev, "reset rndis control %d\n", intf);
- usb_ep_disable(rndis->notify);
- }
- if (!rndis->notify->desc) {
- VDBG(cdev, "init rndis ctrl %d\n", intf);
- if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
- goto fail;
- }
- usb_ep_enable(rndis->notify);
- rndis->notify->driver_data = rndis;
-
- } else if (intf == rndis->data_id) {
- struct net_device *net;
-
- if (rndis->port.in_ep->driver_data) {
- DBG(cdev, "reset rndis\n");
- gether_disconnect(&rndis->port);
- }
-
- if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
- DBG(cdev, "init rndis\n");
- if (config_ep_by_speed(cdev->gadget, f,
- rndis->port.in_ep) ||
- config_ep_by_speed(cdev->gadget, f,
- rndis->port.out_ep)) {
- rndis->port.in_ep->desc = NULL;
- rndis->port.out_ep->desc = NULL;
- goto fail;
- }
- }
-
- /* Avoid ZLPs; they can be troublesome. */
- rndis->port.is_zlp_ok = false;
-
- /* RNDIS should be in the "RNDIS uninitialized" state,
- * either never activated or after rndis_uninit().
- *
- * We don't want data to flow here until a nonzero packet
- * filter is set, at which point it enters "RNDIS data
- * initialized" state ... but we do want the endpoints
- * to be activated. It's a strange little state.
- *
- * REVISIT the RNDIS gadget code has done this wrong for a
- * very long time. We need another call to the link layer
- * code -- gether_updown(...bool) maybe -- to do it right.
- */
- rndis->port.cdc_filter = 0;
-
- DBG(cdev, "RNDIS RX/TX early activation ... \n");
- net = gether_connect(&rndis->port);
- if (IS_ERR(net))
- return PTR_ERR(net);
-
- rndis_set_param_dev(rndis->config, net,
- &rndis->port.cdc_filter);
- } else
- goto fail;
-
- return 0;
-fail:
- return -EINVAL;
-}
-
-static void rndis_disable(struct usb_function *f)
-{
- struct f_rndis *rndis = func_to_rndis(f);
- struct usb_composite_dev *cdev = f->config->cdev;
-
- if (!rndis->notify->driver_data)
- return;
-
- DBG(cdev, "rndis deactivated\n");
-
- rndis_uninit(rndis->config);
- gether_disconnect(&rndis->port);
-
- usb_ep_disable(rndis->notify);
- rndis->notify->driver_data = NULL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * This isn't quite the same mechanism as CDC Ethernet, since the
- * notification scheme passes less data, but the same set of link
- * states must be tested. A key difference is that altsettings are
- * not used to tell whether the link should send packets or not.
- */
-
-static void rndis_open(struct gether *geth)
-{
- struct f_rndis *rndis = func_to_rndis(&geth->func);
- struct usb_composite_dev *cdev = geth->func.config->cdev;
-
- DBG(cdev, "%s\n", __func__);
-
- rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3,
- bitrate(cdev->gadget) / 100);
- rndis_signal_connect(rndis->config);
-}
-
-static void rndis_close(struct gether *geth)
-{
- struct f_rndis *rndis = func_to_rndis(&geth->func);
-
- DBG(geth->func.config->cdev, "%s\n", __func__);
-
- rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
- rndis_signal_disconnect(rndis->config);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* ethernet function driver setup/binding */
-
-static int
-rndis_bind(struct usb_configuration *c, struct usb_function *f)
-{
- struct usb_composite_dev *cdev = c->cdev;
- struct f_rndis *rndis = func_to_rndis(f);
- int status;
- struct usb_ep *ep;
-
- /* allocate instance-specific interface IDs */
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- rndis->ctrl_id = status;
- rndis_iad_descriptor.bFirstInterface = status;
-
- rndis_control_intf.bInterfaceNumber = status;
- rndis_union_desc.bMasterInterface0 = status;
-
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- rndis->data_id = status;
-
- rndis_data_intf.bInterfaceNumber = status;
- rndis_union_desc.bSlaveInterface0 = status;
-
- status = -ENODEV;
-
- /* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
- if (!ep)
- goto fail;
- rndis->port.in_ep = ep;
- ep->driver_data = cdev; /* claim */
-
- ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
- if (!ep)
- goto fail;
- rndis->port.out_ep = ep;
- ep->driver_data = cdev; /* claim */
-
- /* NOTE: a status/notification endpoint is, strictly speaking,
- * optional. We don't treat it that way though! It's simpler,
- * and some newer profiles don't treat it as optional.
- */
- ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
- if (!ep)
- goto fail;
- rndis->notify = ep;
- ep->driver_data = cdev; /* claim */
-
- status = -ENOMEM;
-
- /* allocate notification request and buffer */
- rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
- if (!rndis->notify_req)
- goto fail;
- rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
- if (!rndis->notify_req->buf)
- goto fail;
- rndis->notify_req->length = STATUS_BYTECOUNT;
- rndis->notify_req->context = rndis;
- rndis->notify_req->complete = rndis_response_complete;
-
- /* copy descriptors, and track endpoint copies */
- f->descriptors = usb_copy_descriptors(eth_fs_function);
- if (!f->descriptors)
- goto fail;
-
- /* support all relevant hardware speeds... we expect that when
- * hardware is dual speed, all bulk-capable endpoints work at
- * both speeds
- */
- if (gadget_is_dualspeed(c->cdev->gadget)) {
- hs_in_desc.bEndpointAddress =
- fs_in_desc.bEndpointAddress;
- hs_out_desc.bEndpointAddress =
- fs_out_desc.bEndpointAddress;
- hs_notify_desc.bEndpointAddress =
- fs_notify_desc.bEndpointAddress;
-
- /* copy descriptors, and track endpoint copies */
- f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
- if (!f->hs_descriptors)
- goto fail;
- }
-
- if (gadget_is_superspeed(c->cdev->gadget)) {
- ss_in_desc.bEndpointAddress =
- fs_in_desc.bEndpointAddress;
- ss_out_desc.bEndpointAddress =
- fs_out_desc.bEndpointAddress;
- ss_notify_desc.bEndpointAddress =
- fs_notify_desc.bEndpointAddress;
-
- /* copy descriptors, and track endpoint copies */
- f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
- if (!f->ss_descriptors)
- goto fail;
- }
-
- rndis->port.open = rndis_open;
- rndis->port.close = rndis_close;
-
- status = rndis_register(rndis_response_available, rndis);
- if (status < 0)
- goto fail;
- rndis->config = status;
-
- rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
- rndis_set_host_mac(rndis->config, rndis->ethaddr);
-
- if (rndis->manufacturer && rndis->vendorID &&
- rndis_set_param_vendor(rndis->config, rndis->vendorID,
- rndis->manufacturer))
- goto fail;
-
- /* NOTE: all that is done without knowing or caring about
- * the network link ... which is unavailable to this code
- * until we're activated via set_alt().
- */
-
- DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
- gadget_is_superspeed(c->cdev->gadget) ? "super" :
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- rndis->port.in_ep->name, rndis->port.out_ep->name,
- rndis->notify->name);
- return 0;
-
-fail:
- if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
- usb_free_descriptors(f->ss_descriptors);
- if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
- usb_free_descriptors(f->hs_descriptors);
- if (f->descriptors)
- usb_free_descriptors(f->descriptors);
-
- if (rndis->notify_req) {
- kfree(rndis->notify_req->buf);
- usb_ep_free_request(rndis->notify, rndis->notify_req);
- }
-
- /* we might as well release our claims on endpoints */
- if (rndis->notify)
- rndis->notify->driver_data = NULL;
- if (rndis->port.out_ep->desc)
- rndis->port.out_ep->driver_data = NULL;
- if (rndis->port.in_ep->desc)
- rndis->port.in_ep->driver_data = NULL;
-
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
- return status;
-}
-
-static void
-rndis_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct f_rndis *rndis = func_to_rndis(f);
-
- rndis_deregister(rndis->config);
- rndis_exit();
- rndis_string_defs[0].id = 0;
-
- if (gadget_is_superspeed(c->cdev->gadget))
- usb_free_descriptors(f->ss_descriptors);
- if (gadget_is_dualspeed(c->cdev->gadget))
- usb_free_descriptors(f->hs_descriptors);
- usb_free_descriptors(f->descriptors);
-
- kfree(rndis->notify_req->buf);
- usb_ep_free_request(rndis->notify, rndis->notify_req);
-
- kfree(rndis);
-}
-
-/* Some controllers can't support RNDIS ... */
-static inline bool can_support_rndis(struct usb_configuration *c)
-{
- /* everything else is *presumably* fine */
- return true;
-}
-
-int
-rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
-{
- struct f_rndis *rndis;
- int status;
-
- if (!can_support_rndis(c) || !ethaddr)
- return -EINVAL;
-
- /* maybe allocate device-global string IDs */
- if (rndis_string_defs[0].id == 0) {
-
- /* ... and setup RNDIS itself */
- status = rndis_init();
- if (status < 0)
- return status;
-
- /* control interface label */
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- rndis_string_defs[0].id = status;
- rndis_control_intf.iInterface = status;
-
- /* data interface label */
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- rndis_string_defs[1].id = status;
- rndis_data_intf.iInterface = status;
-
- /* IAD iFunction label */
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- rndis_string_defs[2].id = status;
- rndis_iad_descriptor.iFunction = status;
- }
-
- /* allocate and initialize one new instance */
- status = -ENOMEM;
- rndis = kzalloc(sizeof *rndis, GFP_KERNEL);
- if (!rndis)
- goto fail;
-
- memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
- rndis->vendorID = vendorID;
- rndis->manufacturer = manufacturer;
-
- /* RNDIS activates when the host changes this filter */
- rndis->port.cdc_filter = 0;
-
- /* RNDIS has special (and complex) framing */
- rndis->port.header_len = sizeof(struct rndis_packet_msg_type);
- rndis->port.wrap = rndis_add_header;
- rndis->port.unwrap = rndis_rm_hdr;
-
- rndis->port.func.name = "rndis";
- rndis->port.func.strings = rndis_strings;
- /* descriptors are per-instance copies */
- rndis->port.func.bind = rndis_bind;
- rndis->port.func.unbind = rndis_unbind;
- rndis->port.func.set_alt = rndis_set_alt;
- rndis->port.func.setup = rndis_setup;
- rndis->port.func.disable = rndis_disable;
-
- status = usb_add_function(c, &rndis->port.func);
- if (status) {
- kfree(rndis);
-fail:
- rndis_exit();
- }
- return status;
-}
diff --git a/drivers/staging/ccg/gadget_chips.h b/drivers/staging/ccg/gadget_chips.h
deleted file mode 100644
index 0ccca58e7a8f..000000000000
--- a/drivers/staging/ccg/gadget_chips.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * USB device controllers have lots of quirks. Use these macros in
- * gadget drivers or other code that needs to deal with them, and which
- * autoconfigures instead of using early binding to the hardware.
- *
- * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
- * some config file that gets updated as new hardware is supported.
- * (And avoiding all runtime comparisons in typical one-choice configs!)
- *
- * NOTE: some of these controller drivers may not be available yet.
- * Some are available on 2.4 kernels; several are available, but not
- * yet pushed in the 2.6 mainline tree.
- */
-
-#ifndef __GADGET_CHIPS_H
-#define __GADGET_CHIPS_H
-
-/*
- * NOTICE: the entries below are alphabetical and should be kept
- * that way.
- *
- * Always be sure to add new entries to the correct position or
- * accept the bashing later.
- *
- * If you have forgotten the alphabetical order let VIM/EMACS
- * do that for you.
- */
-#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name))
-#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name))
-#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name))
-#define gadget_is_bcm63xx(g) (!strcmp("bcm63xx_udc", (g)->name))
-#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name))
-#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name))
-#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name))
-#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name))
-#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name))
-#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name))
-#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
-#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name))
-#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
-#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name))
-#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name))
-#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
-#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name))
-#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name))
-#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name))
-#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name))
-#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name))
-#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name))
-#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name))
-#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
-#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name))
-#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name))
-#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
-
-/**
- * usb_gadget_controller_number - support bcdDevice id convention
- * @gadget: the controller being driven
- *
- * Return a 2-digit BCD value associated with the peripheral controller,
- * suitable for use as part of a bcdDevice value, or a negative error code.
- *
- * NOTE: this convention is purely optional, and has no meaning in terms of
- * any USB specification. If you want to use a different convention in your
- * gadget driver firmware -- maybe a more formal revision ID -- feel free.
- *
- * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!)
- * to change their behavior accordingly. For example it might help avoiding
- * some chip bug.
- */
-static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
-{
- if (gadget_is_net2280(gadget))
- return 0x01;
- else if (gadget_is_dummy(gadget))
- return 0x02;
- else if (gadget_is_pxa(gadget))
- return 0x03;
- else if (gadget_is_goku(gadget))
- return 0x06;
- else if (gadget_is_omap(gadget))
- return 0x08;
- else if (gadget_is_pxa27x(gadget))
- return 0x11;
- else if (gadget_is_s3c2410(gadget))
- return 0x12;
- else if (gadget_is_at91(gadget))
- return 0x13;
- else if (gadget_is_imx(gadget))
- return 0x14;
- else if (gadget_is_musbhdrc(gadget))
- return 0x16;
- else if (gadget_is_atmel_usba(gadget))
- return 0x18;
- else if (gadget_is_fsl_usb2(gadget))
- return 0x19;
- else if (gadget_is_amd5536udc(gadget))
- return 0x20;
- else if (gadget_is_m66592(gadget))
- return 0x21;
- else if (gadget_is_fsl_qe(gadget))
- return 0x22;
- else if (gadget_is_ci13xxx_pci(gadget))
- return 0x23;
- else if (gadget_is_langwell(gadget))
- return 0x24;
- else if (gadget_is_r8a66597(gadget))
- return 0x25;
- else if (gadget_is_s3c_hsotg(gadget))
- return 0x26;
- else if (gadget_is_pch(gadget))
- return 0x27;
- else if (gadget_is_ci13xxx_msm(gadget))
- return 0x28;
- else if (gadget_is_renesas_usbhs(gadget))
- return 0x29;
- else if (gadget_is_s3c_hsudc(gadget))
- return 0x30;
- else if (gadget_is_net2272(gadget))
- return 0x31;
- else if (gadget_is_dwc3(gadget))
- return 0x32;
- else if (gadget_is_lpc32xx(gadget))
- return 0x33;
- else if (gadget_is_bcm63xx(gadget))
- return 0x34;
-
- return -ENOENT;
-}
-
-
-/**
- * gadget_supports_altsettings - return true if altsettings work
- * @gadget: the gadget in question
- */
-static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
-{
- /* PXA 21x/25x/26x has no altsettings at all */
- if (gadget_is_pxa(gadget))
- return false;
-
- /* PXA 27x and 3xx have *broken* altsetting support */
- if (gadget_is_pxa27x(gadget))
- return false;
-
- /* Everything else is *presumably* fine ... */
- return true;
-}
-
-#endif /* __GADGET_CHIPS_H */
diff --git a/drivers/staging/ccg/ndis.h b/drivers/staging/ccg/ndis.h
deleted file mode 100644
index a19f72dec0cd..000000000000
--- a/drivers/staging/ccg/ndis.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ndis.h
- *
- * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de>
- *
- * Thanks to the cygwin development team,
- * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net>
- *
- * THIS SOFTWARE IS NOT COPYRIGHTED
- *
- * This source code is offered for use in the public domain. You may
- * use, modify or distribute it freely.
- */
-
-#ifndef _LINUX_NDIS_H
-#define _LINUX_NDIS_H
-
-enum NDIS_DEVICE_POWER_STATE {
- NdisDeviceStateUnspecified = 0,
- NdisDeviceStateD0,
- NdisDeviceStateD1,
- NdisDeviceStateD2,
- NdisDeviceStateD3,
- NdisDeviceStateMaximum
-};
-
-struct NDIS_PM_WAKE_UP_CAPABILITIES {
- enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp;
- enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp;
- enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp;
-};
-
-struct NDIS_PNP_CAPABILITIES {
- __le32 Flags;
- struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities;
-};
-
-struct NDIS_PM_PACKET_PATTERN {
- __le32 Priority;
- __le32 Reserved;
- __le32 MaskSize;
- __le32 PatternOffset;
- __le32 PatternSize;
- __le32 PatternFlags;
-};
-
-#endif /* _LINUX_NDIS_H */
diff --git a/drivers/staging/ccg/rndis.c b/drivers/staging/ccg/rndis.c
deleted file mode 100644
index 1e4cfb05f70b..000000000000
--- a/drivers/staging/ccg/rndis.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-/*
- * RNDIS MSG parser
- *
- * Authors: Benedikt Spranger, Pengutronix
- * Robert Schwebel, Pengutronix
- *
- * 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 software was originally developed in conformance with
- * Microsoft's Remote NDIS Specification License Agreement.
- *
- * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
- * Fixed message length bug in init_response
- *
- * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
- * Fixed rndis_rm_hdr length bug.
- *
- * Copyright (C) 2004 by David Brownell
- * updates to merge with Linux 2.6, better match RNDIS spec
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/seq_file.h>
-#include <linux/netdevice.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-
-#undef VERBOSE_DEBUG
-
-#include "rndis.h"
-
-
-/* The driver for your USB chip needs to support ep0 OUT to work with
- * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
- *
- * Windows hosts need an INF file like Documentation/usb/linux.inf
- * and will be happier if you provide the host_addr module parameter.
- */
-
-#if 0
-static int rndis_debug = 0;
-module_param (rndis_debug, int, 0);
-MODULE_PARM_DESC (rndis_debug, "enable debugging");
-#else
-#define rndis_debug 0
-#endif
-
-#define RNDIS_MAX_CONFIGS 1
-
-
-static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
-
-/* Driver Version */
-static const __le32 rndis_driver_version = cpu_to_le32(1);
-
-/* Function Prototypes */
-static rndis_resp_t *rndis_add_response(int configNr, u32 length);
-
-
-/* supported OIDs */
-static const u32 oid_supported_list[] =
-{
- /* the general stuff */
- RNDIS_OID_GEN_SUPPORTED_LIST,
- RNDIS_OID_GEN_HARDWARE_STATUS,
- RNDIS_OID_GEN_MEDIA_SUPPORTED,
- RNDIS_OID_GEN_MEDIA_IN_USE,
- RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
- RNDIS_OID_GEN_LINK_SPEED,
- RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
- RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
- RNDIS_OID_GEN_VENDOR_ID,
- RNDIS_OID_GEN_VENDOR_DESCRIPTION,
- RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
- RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
- RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
- RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
- RNDIS_OID_GEN_PHYSICAL_MEDIUM,
-
- /* the statistical stuff */
- RNDIS_OID_GEN_XMIT_OK,
- RNDIS_OID_GEN_RCV_OK,
- RNDIS_OID_GEN_XMIT_ERROR,
- RNDIS_OID_GEN_RCV_ERROR,
- RNDIS_OID_GEN_RCV_NO_BUFFER,
-#ifdef RNDIS_OPTIONAL_STATS
- RNDIS_OID_GEN_DIRECTED_BYTES_XMIT,
- RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT,
- RNDIS_OID_GEN_MULTICAST_BYTES_XMIT,
- RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT,
- RNDIS_OID_GEN_BROADCAST_BYTES_XMIT,
- RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT,
- RNDIS_OID_GEN_DIRECTED_BYTES_RCV,
- RNDIS_OID_GEN_DIRECTED_FRAMES_RCV,
- RNDIS_OID_GEN_MULTICAST_BYTES_RCV,
- RNDIS_OID_GEN_MULTICAST_FRAMES_RCV,
- RNDIS_OID_GEN_BROADCAST_BYTES_RCV,
- RNDIS_OID_GEN_BROADCAST_FRAMES_RCV,
- RNDIS_OID_GEN_RCV_CRC_ERROR,
- RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH,
-#endif /* RNDIS_OPTIONAL_STATS */
-
- /* mandatory 802.3 */
- /* the general stuff */
- RNDIS_OID_802_3_PERMANENT_ADDRESS,
- RNDIS_OID_802_3_CURRENT_ADDRESS,
- RNDIS_OID_802_3_MULTICAST_LIST,
- RNDIS_OID_802_3_MAC_OPTIONS,
- RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
-
- /* the statistical stuff */
- RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
- RNDIS_OID_802_3_XMIT_ONE_COLLISION,
- RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
-#ifdef RNDIS_OPTIONAL_STATS
- RNDIS_OID_802_3_XMIT_DEFERRED,
- RNDIS_OID_802_3_XMIT_MAX_COLLISIONS,
- RNDIS_OID_802_3_RCV_OVERRUN,
- RNDIS_OID_802_3_XMIT_UNDERRUN,
- RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE,
- RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST,
- RNDIS_OID_802_3_XMIT_LATE_COLLISIONS,
-#endif /* RNDIS_OPTIONAL_STATS */
-
-#ifdef RNDIS_PM
- /* PM and wakeup are "mandatory" for USB, but the RNDIS specs
- * don't say what they mean ... and the NDIS specs are often
- * confusing and/or ambiguous in this context. (That is, more
- * so than their specs for the other OIDs.)
- *
- * FIXME someone who knows what these should do, please
- * implement them!
- */
-
- /* power management */
- OID_PNP_CAPABILITIES,
- OID_PNP_QUERY_POWER,
- OID_PNP_SET_POWER,
-
-#ifdef RNDIS_WAKEUP
- /* wake up host */
- OID_PNP_ENABLE_WAKE_UP,
- OID_PNP_ADD_WAKE_UP_PATTERN,
- OID_PNP_REMOVE_WAKE_UP_PATTERN,
-#endif /* RNDIS_WAKEUP */
-#endif /* RNDIS_PM */
-};
-
-
-/* NDIS Functions */
-static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf,
- unsigned buf_len, rndis_resp_t *r)
-{
- int retval = -ENOTSUPP;
- u32 length = 4; /* usually */
- __le32 *outbuf;
- int i, count;
- rndis_query_cmplt_type *resp;
- struct net_device *net;
- struct rtnl_link_stats64 temp;
- const struct rtnl_link_stats64 *stats;
-
- if (!r) return -ENOMEM;
- resp = (rndis_query_cmplt_type *)r->buf;
-
- if (!resp) return -ENOMEM;
-
- if (buf_len && rndis_debug > 1) {
- pr_debug("query OID %08x value, len %d:\n", OID, buf_len);
- for (i = 0; i < buf_len; i += 16) {
- pr_debug("%03d: %08x %08x %08x %08x\n", i,
- get_unaligned_le32(&buf[i]),
- get_unaligned_le32(&buf[i + 4]),
- get_unaligned_le32(&buf[i + 8]),
- get_unaligned_le32(&buf[i + 12]));
- }
- }
-
- /* response goes here, right after the header */
- outbuf = (__le32 *)&resp[1];
- resp->InformationBufferOffset = cpu_to_le32(16);
-
- net = rndis_per_dev_params[configNr].dev;
- stats = dev_get_stats(net, &temp);
-
- switch (OID) {
-
- /* general oids (table 4-1) */
-
- /* mandatory */
- case RNDIS_OID_GEN_SUPPORTED_LIST:
- pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
- length = sizeof(oid_supported_list);
- count = length / sizeof(u32);
- for (i = 0; i < count; i++)
- outbuf[i] = cpu_to_le32(oid_supported_list[i]);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_HARDWARE_STATUS:
- pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__);
- /* Bogus question!
- * Hardware must be ready to receive high level protocols.
- * BTW:
- * reddite ergo quae sunt Caesaris Caesari
- * et quae sunt Dei Deo!
- */
- *outbuf = cpu_to_le32(0);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_MEDIA_SUPPORTED:
- pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
- *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_MEDIA_IN_USE:
- pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
- /* one medium, one transport... (maybe you do it better) */
- *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
- pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
- if (rndis_per_dev_params[configNr].dev) {
- *outbuf = cpu_to_le32(
- rndis_per_dev_params[configNr].dev->mtu);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_LINK_SPEED:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
- if (rndis_per_dev_params[configNr].media_state
- == RNDIS_MEDIA_STATE_DISCONNECTED)
- *outbuf = cpu_to_le32(0);
- else
- *outbuf = cpu_to_le32(
- rndis_per_dev_params[configNr].speed);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
- pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
- if (rndis_per_dev_params[configNr].dev) {
- *outbuf = cpu_to_le32(
- rndis_per_dev_params[configNr].dev->mtu);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
- pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
- if (rndis_per_dev_params[configNr].dev) {
- *outbuf = cpu_to_le32(
- rndis_per_dev_params[configNr].dev->mtu);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_VENDOR_ID:
- pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
- *outbuf = cpu_to_le32(
- rndis_per_dev_params[configNr].vendorID);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
- pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
- if (rndis_per_dev_params[configNr].vendorDescr) {
- length = strlen(rndis_per_dev_params[configNr].
- vendorDescr);
- memcpy(outbuf,
- rndis_per_dev_params[configNr].vendorDescr,
- length);
- } else {
- outbuf[0] = 0;
- }
- retval = 0;
- break;
-
- case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
- pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
- /* Created as LE */
- *outbuf = rndis_driver_version;
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
- pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
- *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE:
- pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
- *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
- *outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
- .media_state);
- retval = 0;
- break;
-
- case RNDIS_OID_GEN_PHYSICAL_MEDIUM:
- pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__);
- *outbuf = cpu_to_le32(0);
- retval = 0;
- break;
-
- /* The RNDIS specification is incomplete/wrong. Some versions
- * of MS-Windows expect OIDs that aren't specified there. Other
- * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
- */
- case RNDIS_OID_GEN_MAC_OPTIONS: /* from WinME */
- pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__);
- *outbuf = cpu_to_le32(
- RNDIS_MAC_OPTION_RECEIVE_SERIALIZED
- | RNDIS_MAC_OPTION_FULL_DUPLEX);
- retval = 0;
- break;
-
- /* statistics OIDs (table 4-2) */
-
- /* mandatory */
- case RNDIS_OID_GEN_XMIT_OK:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->tx_packets
- - stats->tx_errors - stats->tx_dropped);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_RCV_OK:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->rx_packets
- - stats->rx_errors - stats->rx_dropped);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_XMIT_ERROR:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->tx_errors);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_RCV_ERROR:
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->rx_errors);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_GEN_RCV_NO_BUFFER:
- pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->rx_dropped);
- retval = 0;
- }
- break;
-
- /* ieee802.3 OIDs (table 4-3) */
-
- /* mandatory */
- case RNDIS_OID_802_3_PERMANENT_ADDRESS:
- pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
- if (rndis_per_dev_params[configNr].dev) {
- length = ETH_ALEN;
- memcpy(outbuf,
- rndis_per_dev_params[configNr].host_mac,
- length);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_802_3_CURRENT_ADDRESS:
- pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
- if (rndis_per_dev_params[configNr].dev) {
- length = ETH_ALEN;
- memcpy(outbuf,
- rndis_per_dev_params [configNr].host_mac,
- length);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_802_3_MULTICAST_LIST:
- pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
- /* Multicast base address only */
- *outbuf = cpu_to_le32(0xE0000000);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE:
- pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
- /* Multicast base address only */
- *outbuf = cpu_to_le32(1);
- retval = 0;
- break;
-
- case RNDIS_OID_802_3_MAC_OPTIONS:
- pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__);
- *outbuf = cpu_to_le32(0);
- retval = 0;
- break;
-
- /* ieee802.3 statistics OIDs (table 4-4) */
-
- /* mandatory */
- case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
- pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
- if (stats) {
- *outbuf = cpu_to_le32(stats->rx_frame_errors);
- retval = 0;
- }
- break;
-
- /* mandatory */
- case RNDIS_OID_802_3_XMIT_ONE_COLLISION:
- pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__);
- *outbuf = cpu_to_le32(0);
- retval = 0;
- break;
-
- /* mandatory */
- case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS:
- pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
- *outbuf = cpu_to_le32(0);
- retval = 0;
- break;
-
- default:
- pr_warning("%s: query unknown OID 0x%08X\n",
- __func__, OID);
- }
- if (retval < 0)
- length = 0;
-
- resp->InformationBufferLength = cpu_to_le32(length);
- r->length = length + sizeof(*resp);
- resp->MessageLength = cpu_to_le32(r->length);
- return retval;
-}
-
-static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
- rndis_resp_t *r)
-{
- rndis_set_cmplt_type *resp;
- int i, retval = -ENOTSUPP;
- struct rndis_params *params;
-
- if (!r)
- return -ENOMEM;
- resp = (rndis_set_cmplt_type *)r->buf;
- if (!resp)
- return -ENOMEM;
-
- if (buf_len && rndis_debug > 1) {
- pr_debug("set OID %08x value, len %d:\n", OID, buf_len);
- for (i = 0; i < buf_len; i += 16) {
- pr_debug("%03d: %08x %08x %08x %08x\n", i,
- get_unaligned_le32(&buf[i]),
- get_unaligned_le32(&buf[i + 4]),
- get_unaligned_le32(&buf[i + 8]),
- get_unaligned_le32(&buf[i + 12]));
- }
- }
-
- params = &rndis_per_dev_params[configNr];
- switch (OID) {
- case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
-
- /* these NDIS_PACKET_TYPE_* bitflags are shared with
- * cdc_filter; it's not RNDIS-specific
- * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
- * PROMISCUOUS, DIRECTED,
- * MULTICAST, ALL_MULTICAST, BROADCAST
- */
- *params->filter = (u16)get_unaligned_le32(buf);
- pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
- __func__, *params->filter);
-
- /* this call has a significant side effect: it's
- * what makes the packet flow start and stop, like
- * activating the CDC Ethernet altsetting.
- */
- retval = 0;
- if (*params->filter) {
- params->state = RNDIS_DATA_INITIALIZED;
- netif_carrier_on(params->dev);
- if (netif_running(params->dev))
- netif_wake_queue(params->dev);
- } else {
- params->state = RNDIS_INITIALIZED;
- netif_carrier_off(params->dev);
- netif_stop_queue(params->dev);
- }
- break;
-
- case RNDIS_OID_802_3_MULTICAST_LIST:
- /* I think we can ignore this */
- pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
- retval = 0;
- break;
-
- default:
- pr_warning("%s: set unknown OID 0x%08X, size %d\n",
- __func__, OID, buf_len);
- }
-
- return retval;
-}
-
-/*
- * Response Functions
- */
-
-static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
-{
- rndis_init_cmplt_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- if (!params->dev)
- return -ENOTSUPP;
-
- r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_init_cmplt_type *)r->buf;
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C);
- resp->MessageLength = cpu_to_le32(52);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
- resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
- resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
- resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
- resp->MaxPacketsPerTransfer = cpu_to_le32(1);
- resp->MaxTransferSize = cpu_to_le32(
- params->dev->mtu
- + sizeof(struct ethhdr)
- + sizeof(struct rndis_packet_msg_type)
- + 22);
- resp->PacketAlignmentFactor = cpu_to_le32(0);
- resp->AFListOffset = cpu_to_le32(0);
- resp->AFListSize = cpu_to_le32(0);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
-{
- rndis_query_cmplt_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
- if (!params->dev)
- return -ENOTSUPP;
-
- /*
- * we need more memory:
- * gen_ndis_query_resp expects enough space for
- * rndis_query_cmplt_type followed by data.
- * oid_supported_list is the largest data reply
- */
- r = rndis_add_response(configNr,
- sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_query_cmplt_type *)r->buf;
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-
- if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID),
- le32_to_cpu(buf->InformationBufferOffset)
- + 8 + (u8 *)buf,
- le32_to_cpu(buf->InformationBufferLength),
- r)) {
- /* OID not supported */
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- resp->MessageLength = cpu_to_le32(sizeof *resp);
- resp->InformationBufferLength = cpu_to_le32(0);
- resp->InformationBufferOffset = cpu_to_le32(0);
- } else
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
-{
- u32 BufLength, BufOffset;
- rndis_set_cmplt_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_set_cmplt_type *)r->buf;
-
- BufLength = le32_to_cpu(buf->InformationBufferLength);
- BufOffset = le32_to_cpu(buf->InformationBufferOffset);
-
-#ifdef VERBOSE_DEBUG
- pr_debug("%s: Length: %d\n", __func__, BufLength);
- pr_debug("%s: Offset: %d\n", __func__, BufOffset);
- pr_debug("%s: InfoBuffer: ", __func__);
-
- for (i = 0; i < BufLength; i++) {
- pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
- }
-
- pr_debug("\n");
-#endif
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
- resp->MessageLength = cpu_to_le32(16);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID),
- ((u8 *)buf) + 8 + BufOffset, BufLength, r))
- resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
- else
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
-{
- rndis_reset_cmplt_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_reset_cmplt_type *)r->buf;
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C);
- resp->MessageLength = cpu_to_le32(16);
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
- /* resent information */
- resp->AddressingReset = cpu_to_le32(1);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-static int rndis_keepalive_response(int configNr,
- rndis_keepalive_msg_type *buf)
-{
- rndis_keepalive_cmplt_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- /* host "should" check only in RNDIS_DATA_INITIALIZED state */
-
- r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_keepalive_cmplt_type *)r->buf;
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
- resp->MessageLength = cpu_to_le32(16);
- resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
- resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-
-/*
- * Device to Host Comunication
- */
-static int rndis_indicate_status_msg(int configNr, u32 status)
-{
- rndis_indicate_status_msg_type *resp;
- rndis_resp_t *r;
- struct rndis_params *params = rndis_per_dev_params + configNr;
-
- if (params->state == RNDIS_UNINITIALIZED)
- return -ENOTSUPP;
-
- r = rndis_add_response(configNr,
- sizeof(rndis_indicate_status_msg_type));
- if (!r)
- return -ENOMEM;
- resp = (rndis_indicate_status_msg_type *)r->buf;
-
- resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE);
- resp->MessageLength = cpu_to_le32(20);
- resp->Status = cpu_to_le32(status);
- resp->StatusBufferLength = cpu_to_le32(0);
- resp->StatusBufferOffset = cpu_to_le32(0);
-
- params->resp_avail(params->v);
- return 0;
-}
-
-int rndis_signal_connect(int configNr)
-{
- rndis_per_dev_params[configNr].media_state
- = RNDIS_MEDIA_STATE_CONNECTED;
- return rndis_indicate_status_msg(configNr,
- RNDIS_STATUS_MEDIA_CONNECT);
-}
-
-int rndis_signal_disconnect(int configNr)
-{
- rndis_per_dev_params[configNr].media_state
- = RNDIS_MEDIA_STATE_DISCONNECTED;
- return rndis_indicate_status_msg(configNr,
- RNDIS_STATUS_MEDIA_DISCONNECT);
-}
-
-void rndis_uninit(int configNr)
-{
- u8 *buf;
- u32 length;
-
- if (configNr >= RNDIS_MAX_CONFIGS)
- return;
- rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED;
-
- /* drain the response queue */
- while ((buf = rndis_get_next_response(configNr, &length)))
- rndis_free_response(configNr, buf);
-}
-
-void rndis_set_host_mac(int configNr, const u8 *addr)
-{
- rndis_per_dev_params[configNr].host_mac = addr;
-}
-
-/*
- * Message Parser
- */
-int rndis_msg_parser(u8 configNr, u8 *buf)
-{
- u32 MsgType, MsgLength;
- __le32 *tmp;
- struct rndis_params *params;
-
- if (!buf)
- return -ENOMEM;
-
- tmp = (__le32 *)buf;
- MsgType = get_unaligned_le32(tmp++);
- MsgLength = get_unaligned_le32(tmp++);
-
- if (configNr >= RNDIS_MAX_CONFIGS)
- return -ENOTSUPP;
- params = &rndis_per_dev_params[configNr];
-
- /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
- * rx/tx statistics and link status, in addition to KEEPALIVE traffic
- * and normal HC level polling to see if there's any IN traffic.
- */
-
- /* For USB: responses may take up to 10 seconds */
- switch (MsgType) {
- case RNDIS_MSG_INIT:
- pr_debug("%s: RNDIS_MSG_INIT\n",
- __func__);
- params->state = RNDIS_INITIALIZED;
- return rndis_init_response(configNr,
- (rndis_init_msg_type *)buf);
-
- case RNDIS_MSG_HALT:
- pr_debug("%s: RNDIS_MSG_HALT\n",
- __func__);
- params->state = RNDIS_UNINITIALIZED;
- if (params->dev) {
- netif_carrier_off(params->dev);
- netif_stop_queue(params->dev);
- }
- return 0;
-
- case RNDIS_MSG_QUERY:
- return rndis_query_response(configNr,
- (rndis_query_msg_type *)buf);
-
- case RNDIS_MSG_SET:
- return rndis_set_response(configNr,
- (rndis_set_msg_type *)buf);
-
- case RNDIS_MSG_RESET:
- pr_debug("%s: RNDIS_MSG_RESET\n",
- __func__);
- return rndis_reset_response(configNr,
- (rndis_reset_msg_type *)buf);
-
- case RNDIS_MSG_KEEPALIVE:
- /* For USB: host does this every 5 seconds */
- if (rndis_debug > 1)
- pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
- __func__);
- return rndis_keepalive_response(configNr,
- (rndis_keepalive_msg_type *)
- buf);
-
- default:
- /* At least Windows XP emits some undefined RNDIS messages.
- * In one case those messages seemed to relate to the host
- * suspending itself.
- */
- pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
- __func__, MsgType, MsgLength);
- print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
- buf, MsgLength);
- break;
- }
-
- return -ENOTSUPP;
-}
-
-int rndis_register(void (*resp_avail)(void *v), void *v)
-{
- u8 i;
-
- if (!resp_avail)
- return -EINVAL;
-
- for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
- if (!rndis_per_dev_params[i].used) {
- rndis_per_dev_params[i].used = 1;
- rndis_per_dev_params[i].resp_avail = resp_avail;
- rndis_per_dev_params[i].v = v;
- pr_debug("%s: configNr = %d\n", __func__, i);
- return i;
- }
- }
- pr_debug("failed\n");
-
- return -ENODEV;
-}
-
-void rndis_deregister(int configNr)
-{
- pr_debug("%s:\n", __func__);
-
- if (configNr >= RNDIS_MAX_CONFIGS) return;
- rndis_per_dev_params[configNr].used = 0;
-}
-
-int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
-{
- pr_debug("%s:\n", __func__);
- if (!dev)
- return -EINVAL;
- if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-
- rndis_per_dev_params[configNr].dev = dev;
- rndis_per_dev_params[configNr].filter = cdc_filter;
-
- return 0;
-}
-
-int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
-{
- pr_debug("%s:\n", __func__);
- if (!vendorDescr) return -1;
- if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-
- rndis_per_dev_params[configNr].vendorID = vendorID;
- rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
-
- return 0;
-}
-
-int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
-{
- pr_debug("%s: %u %u\n", __func__, medium, speed);
- if (configNr >= RNDIS_MAX_CONFIGS) return -1;
-
- rndis_per_dev_params[configNr].medium = medium;
- rndis_per_dev_params[configNr].speed = speed;
-
- return 0;
-}
-
-void rndis_add_hdr(struct sk_buff *skb)
-{
- struct rndis_packet_msg_type *header;
-
- if (!skb)
- return;
- header = (void *)skb_push(skb, sizeof(*header));
- memset(header, 0, sizeof *header);
- header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
- header->MessageLength = cpu_to_le32(skb->len);
- header->DataOffset = cpu_to_le32(36);
- header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
-}
-
-void rndis_free_response(int configNr, u8 *buf)
-{
- rndis_resp_t *r;
- struct list_head *act, *tmp;
-
- list_for_each_safe(act, tmp,
- &(rndis_per_dev_params[configNr].resp_queue))
- {
- r = list_entry(act, rndis_resp_t, list);
- if (r && r->buf == buf) {
- list_del(&r->list);
- kfree(r);
- }
- }
-}
-
-u8 *rndis_get_next_response(int configNr, u32 *length)
-{
- rndis_resp_t *r;
- struct list_head *act, *tmp;
-
- if (!length) return NULL;
-
- list_for_each_safe(act, tmp,
- &(rndis_per_dev_params[configNr].resp_queue))
- {
- r = list_entry(act, rndis_resp_t, list);
- if (!r->send) {
- r->send = 1;
- *length = r->length;
- return r->buf;
- }
- }
-
- return NULL;
-}
-
-static rndis_resp_t *rndis_add_response(int configNr, u32 length)
-{
- rndis_resp_t *r;
-
- /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
- r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
- if (!r) return NULL;
-
- r->buf = (u8 *)(r + 1);
- r->length = length;
- r->send = 0;
-
- list_add_tail(&r->list,
- &(rndis_per_dev_params[configNr].resp_queue));
- return r;
-}
-
-int rndis_rm_hdr(struct gether *port,
- struct sk_buff *skb,
- struct sk_buff_head *list)
-{
- /* tmp points to a struct rndis_packet_msg_type */
- __le32 *tmp = (void *)skb->data;
-
- /* MessageType, MessageLength */
- if (cpu_to_le32(RNDIS_MSG_PACKET)
- != get_unaligned(tmp++)) {
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
- tmp++;
-
- /* DataOffset, DataLength */
- if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
- dev_kfree_skb_any(skb);
- return -EOVERFLOW;
- }
- skb_trim(skb, get_unaligned_le32(tmp++));
-
- skb_queue_tail(list, skb);
- return 0;
-}
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static int rndis_proc_show(struct seq_file *m, void *v)
-{
- rndis_params *param = m->private;
-
- seq_printf(m,
- "Config Nr. %d\n"
- "used : %s\n"
- "state : %s\n"
- "medium : 0x%08X\n"
- "speed : %d\n"
- "cable : %s\n"
- "vendor ID : 0x%08X\n"
- "vendor : %s\n",
- param->confignr, (param->used) ? "y" : "n",
- ({ char *s = "?";
- switch (param->state) {
- case RNDIS_UNINITIALIZED:
- s = "RNDIS_UNINITIALIZED"; break;
- case RNDIS_INITIALIZED:
- s = "RNDIS_INITIALIZED"; break;
- case RNDIS_DATA_INITIALIZED:
- s = "RNDIS_DATA_INITIALIZED"; break;
- }; s; }),
- param->medium,
- (param->media_state) ? 0 : param->speed*100,
- (param->media_state) ? "disconnected" : "connected",
- param->vendorID, param->vendorDescr);
- return 0;
-}
-
-static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
-{
- rndis_params *p = PDE_DATA(file_inode(file));
- u32 speed = 0;
- int i, fl_speed = 0;
-
- for (i = 0; i < count; i++) {
- char c;
- if (get_user(c, buffer))
- return -EFAULT;
- switch (c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- fl_speed = 1;
- speed = speed * 10 + c - '0';
- break;
- case 'C':
- case 'c':
- rndis_signal_connect(p->confignr);
- break;
- case 'D':
- case 'd':
- rndis_signal_disconnect(p->confignr);
- break;
- default:
- if (fl_speed) p->speed = speed;
- else pr_debug("%c is not valid\n", c);
- break;
- }
-
- buffer++;
- }
-
- return count;
-}
-
-static int rndis_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, rndis_proc_show, PDE_DATA(inode));
-}
-
-static const struct file_operations rndis_proc_fops = {
- .owner = THIS_MODULE,
- .open = rndis_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = rndis_proc_write,
-};
-
-#define NAME_TEMPLATE "driver/rndis-%03d"
-
-static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
-
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-
-int rndis_init(void)
-{
- u8 i;
-
- for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- char name [20];
-
- sprintf(name, NAME_TEMPLATE, i);
- rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
- &rndis_proc_fops,
- (void *)(rndis_per_dev_params + i));
- if (!rndis_connect_state[i]) {
- pr_debug("%s: remove entries", __func__);
- while (i) {
- sprintf(name, NAME_TEMPLATE, --i);
- remove_proc_entry(name, NULL);
- }
- pr_debug("\n");
- return -EIO;
- }
-#endif
- rndis_per_dev_params[i].confignr = i;
- rndis_per_dev_params[i].used = 0;
- rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
- rndis_per_dev_params[i].media_state
- = RNDIS_MEDIA_STATE_DISCONNECTED;
- INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
- }
-
- return 0;
-}
-
-void rndis_exit(void)
-{
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- u8 i;
- char name[20];
-
- for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
- sprintf(name, NAME_TEMPLATE, i);
- remove_proc_entry(name, NULL);
- }
-#endif
-}
diff --git a/drivers/staging/ccg/rndis.h b/drivers/staging/ccg/rndis.h
deleted file mode 100644
index 0647f2f34e89..000000000000
--- a/drivers/staging/ccg/rndis.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * RNDIS Definitions for Remote NDIS
- *
- * Authors: Benedikt Spranger, Pengutronix
- * Robert Schwebel, Pengutronix
- *
- * 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 software was originally developed in conformance with
- * Microsoft's Remote NDIS Specification License Agreement.
- */
-
-#ifndef _LINUX_RNDIS_H
-#define _LINUX_RNDIS_H
-
-#include <linux/rndis.h>
-#include "ndis.h"
-
-#define RNDIS_MAXIMUM_FRAME_SIZE 1518
-#define RNDIS_MAX_TOTAL_SIZE 1558
-
-typedef struct rndis_init_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 MajorVersion;
- __le32 MinorVersion;
- __le32 MaxTransferSize;
-} rndis_init_msg_type;
-
-typedef struct rndis_init_cmplt_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 Status;
- __le32 MajorVersion;
- __le32 MinorVersion;
- __le32 DeviceFlags;
- __le32 Medium;
- __le32 MaxPacketsPerTransfer;
- __le32 MaxTransferSize;
- __le32 PacketAlignmentFactor;
- __le32 AFListOffset;
- __le32 AFListSize;
-} rndis_init_cmplt_type;
-
-typedef struct rndis_halt_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
-} rndis_halt_msg_type;
-
-typedef struct rndis_query_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 OID;
- __le32 InformationBufferLength;
- __le32 InformationBufferOffset;
- __le32 DeviceVcHandle;
-} rndis_query_msg_type;
-
-typedef struct rndis_query_cmplt_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 Status;
- __le32 InformationBufferLength;
- __le32 InformationBufferOffset;
-} rndis_query_cmplt_type;
-
-typedef struct rndis_set_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 OID;
- __le32 InformationBufferLength;
- __le32 InformationBufferOffset;
- __le32 DeviceVcHandle;
-} rndis_set_msg_type;
-
-typedef struct rndis_set_cmplt_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 Status;
-} rndis_set_cmplt_type;
-
-typedef struct rndis_reset_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 Reserved;
-} rndis_reset_msg_type;
-
-typedef struct rndis_reset_cmplt_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 Status;
- __le32 AddressingReset;
-} rndis_reset_cmplt_type;
-
-typedef struct rndis_indicate_status_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 Status;
- __le32 StatusBufferLength;
- __le32 StatusBufferOffset;
-} rndis_indicate_status_msg_type;
-
-typedef struct rndis_keepalive_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
-} rndis_keepalive_msg_type;
-
-typedef struct rndis_keepalive_cmplt_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 RequestID;
- __le32 Status;
-} rndis_keepalive_cmplt_type;
-
-struct rndis_packet_msg_type
-{
- __le32 MessageType;
- __le32 MessageLength;
- __le32 DataOffset;
- __le32 DataLength;
- __le32 OOBDataOffset;
- __le32 OOBDataLength;
- __le32 NumOOBDataElements;
- __le32 PerPacketInfoOffset;
- __le32 PerPacketInfoLength;
- __le32 VcHandle;
- __le32 Reserved;
-} __attribute__ ((packed));
-
-struct rndis_config_parameter
-{
- __le32 ParameterNameOffset;
- __le32 ParameterNameLength;
- __le32 ParameterType;
- __le32 ParameterValueOffset;
- __le32 ParameterValueLength;
-};
-
-/* implementation specific */
-enum rndis_state
-{
- RNDIS_UNINITIALIZED,
- RNDIS_INITIALIZED,
- RNDIS_DATA_INITIALIZED,
-};
-
-typedef struct rndis_resp_t
-{
- struct list_head list;
- u8 *buf;
- u32 length;
- int send;
-} rndis_resp_t;
-
-typedef struct rndis_params
-{
- u8 confignr;
- u8 used;
- u16 saved_filter;
- enum rndis_state state;
- u32 medium;
- u32 speed;
- u32 media_state;
-
- const u8 *host_mac;
- u16 *filter;
- struct net_device *dev;
-
- u32 vendorID;
- const char *vendorDescr;
- void (*resp_avail)(void *v);
- void *v;
- struct list_head resp_queue;
-} rndis_params;
-
-/* RNDIS Message parser and other useless functions */
-int rndis_msg_parser (u8 configNr, u8 *buf);
-int rndis_register(void (*resp_avail)(void *v), void *v);
-void rndis_deregister (int configNr);
-int rndis_set_param_dev (u8 configNr, struct net_device *dev,
- u16 *cdc_filter);
-int rndis_set_param_vendor (u8 configNr, u32 vendorID,
- const char *vendorDescr);
-int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
-void rndis_add_hdr (struct sk_buff *skb);
-int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
- struct sk_buff_head *list);
-u8 *rndis_get_next_response (int configNr, u32 *length);
-void rndis_free_response (int configNr, u8 *buf);
-
-void rndis_uninit (int configNr);
-int rndis_signal_connect (int configNr);
-int rndis_signal_disconnect (int configNr);
-int rndis_state (int configNr);
-extern void rndis_set_host_mac (int configNr, const u8 *addr);
-
-int rndis_init(void);
-void rndis_exit (void);
-
-#endif /* _LINUX_RNDIS_H */
diff --git a/drivers/staging/ccg/storage_common.c b/drivers/staging/ccg/storage_common.c
deleted file mode 100644
index abb01ac74cec..000000000000
--- a/drivers/staging/ccg/storage_common.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * storage_common.c -- Common definitions for mass storage functionality
- *
- * Copyright (C) 2003-2008 Alan Stern
- * Copyeight (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (mina86@mina86.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-/*
- * This file requires the following identifiers used in USB strings to
- * be defined (each of type pointer to char):
- * - fsg_string_manufacturer -- name of the manufacturer
- * - fsg_string_product -- name of the product
- * - fsg_string_config -- name of the configuration
- * - fsg_string_interface -- name of the interface
- * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
- * macro is defined prior to including this file.
- */
-
-/*
- * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
- * fsg_hs_intr_in_desc objects as well as
- * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
- * macros are not defined.
- *
- * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
- * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
- * defined (as well as corresponding entries in string tables are
- * missing) and FSG_STRING_INTERFACE has value of zero.
- *
- * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
- */
-
-/*
- * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
- * sets the number of pipeline buffers (length of the fsg_buffhd array).
- * The valid range of num_buffers is: num >= 2 && num <= 4.
- */
-
-
-#include <linux/usb/storage.h>
-#include <scsi/scsi.h>
-#include <asm/unaligned.h>
-
-
-/*
- * Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with any other driver!! Ever!!
- * Instead: allocate your own, using normal USB-IF procedures.
- */
-#define FSG_VENDOR_ID 0x0525 /* NetChip */
-#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
-
-
-/*-------------------------------------------------------------------------*/
-
-
-#ifndef DEBUG
-#undef VERBOSE_DEBUG
-#undef DUMP_MSGS
-#endif /* !DEBUG */
-
-#ifdef VERBOSE_DEBUG
-#define VLDBG LDBG
-#else
-#define VLDBG(lun, fmt, args...) do { } while (0)
-#endif /* VERBOSE_DEBUG */
-
-#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
-#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
-#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
-#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
-
-/*
- * Keep those macros in sync with those in
- * include/linux/usb/composite.h or else GCC will complain. If they
- * are identical (the same names of arguments, white spaces in the
- * same places) GCC will allow redefinition otherwise (even if some
- * white space is removed or added) warning will be issued.
- *
- * Those macros are needed here because File Storage Gadget does not
- * include the composite.h header. For composite gadgets those macros
- * are redundant since composite.h is included any way.
- *
- * One could check whether those macros are already defined (which
- * would indicate composite.h had been included) or not (which would
- * indicate we were in FSG) but this is not done because a warning is
- * desired if definitions here differ from the ones in composite.h.
- *
- * We want the definitions to match and be the same in File Storage
- * Gadget as well as Mass Storage Function (and so composite gadgets
- * using MSF). If someone changes them in composite.h it will produce
- * a warning in this file when building MSF.
- */
-#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
-#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
-#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
-#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
-#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
-
-
-
-#ifdef DUMP_MSGS
-
-# define dump_msg(fsg, /* const char * */ label, \
- /* const u8 * */ buf, /* unsigned */ length) do { \
- if (length < 512) { \
- DBG(fsg, "%s, length %u:\n", label, length); \
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \
- 16, 1, buf, length, 0); \
- } \
-} while (0)
-
-# define dump_cdb(fsg) do { } while (0)
-
-#else
-
-# define dump_msg(fsg, /* const char * */ label, \
- /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
-
-# ifdef VERBOSE_DEBUG
-
-# define dump_cdb(fsg) \
- print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \
- 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \
-
-# else
-
-# define dump_cdb(fsg) do { } while (0)
-
-# endif /* VERBOSE_DEBUG */
-
-#endif /* DUMP_MSGS */
-
-/*-------------------------------------------------------------------------*/
-
-/* CBI Interrupt data structure */
-struct interrupt_data {
- u8 bType;
- u8 bValue;
-};
-
-#define CBI_INTERRUPT_DATA_LEN 2
-
-/* CBI Accept Device-Specific Command request */
-#define USB_CBI_ADSC_REQUEST 0x00
-
-
-/* Length of a SCSI Command Data Block */
-#define MAX_COMMAND_SIZE 16
-
-/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
-#define SS_NO_SENSE 0
-#define SS_COMMUNICATION_FAILURE 0x040800
-#define SS_INVALID_COMMAND 0x052000
-#define SS_INVALID_FIELD_IN_CDB 0x052400
-#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
-#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
-#define SS_MEDIUM_NOT_PRESENT 0x023a00
-#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
-#define SS_NOT_READY_TO_READY_TRANSITION 0x062800
-#define SS_RESET_OCCURRED 0x062900
-#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
-#define SS_UNRECOVERED_READ_ERROR 0x031100
-#define SS_WRITE_ERROR 0x030c02
-#define SS_WRITE_PROTECTED 0x072700
-
-#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
-#define ASC(x) ((u8) ((x) >> 8))
-#define ASCQ(x) ((u8) (x))
-
-
-/*-------------------------------------------------------------------------*/
-
-
-struct fsg_lun {
- struct file *filp;
- loff_t file_length;
- loff_t num_sectors;
-
- unsigned int initially_ro:1;
- unsigned int ro:1;
- unsigned int removable:1;
- unsigned int cdrom:1;
- unsigned int prevent_medium_removal:1;
- unsigned int registered:1;
- unsigned int info_valid:1;
- unsigned int nofua:1;
-
- u32 sense_data;
- u32 sense_data_info;
- u32 unit_attention_data;
-
- unsigned int blkbits; /* Bits of logical block size of bound block device */
- unsigned int blksize; /* logical block size of bound block device */
- struct device dev;
-};
-
-#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
-
-static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
-{
- return container_of(dev, struct fsg_lun, dev);
-}
-
-
-/* Big enough to hold our biggest descriptor */
-#define EP0_BUFSIZE 256
-#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
-module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);
-MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers");
-
-#else
-
-/*
- * Number of buffers we will use.
- * 2 is usually enough for good buffering pipeline
- */
-#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
-
-#endif /* CONFIG_USB_DEBUG */
-
-/* check if fsg_num_buffers is within a valid range */
-static inline int fsg_num_buffers_validate(void)
-{
- if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4)
- return 0;
- pr_err("fsg_num_buffers %u is out of range (%d to %d)\n",
- fsg_num_buffers, 2 ,4);
- return -EINVAL;
-}
-
-/* Default size of buffer length. */
-#define FSG_BUFLEN ((u32)16384)
-
-/* Maximal number of LUNs supported in mass storage function */
-#define FSG_MAX_LUNS 8
-
-enum fsg_buffer_state {
- BUF_STATE_EMPTY = 0,
- BUF_STATE_FULL,
- BUF_STATE_BUSY
-};
-
-struct fsg_buffhd {
- void *buf;
- enum fsg_buffer_state state;
- struct fsg_buffhd *next;
-
- /*
- * The NetChip 2280 is faster, and handles some protocol faults
- * better, if we don't submit any short bulk-out read requests.
- * So we will record the intended request length here.
- */
- unsigned int bulk_out_intended_length;
-
- struct usb_request *inreq;
- int inreq_busy;
- struct usb_request *outreq;
- int outreq_busy;
-};
-
-enum fsg_state {
- /* This one isn't used anywhere */
- FSG_STATE_COMMAND_PHASE = -10,
- FSG_STATE_DATA_PHASE,
- FSG_STATE_STATUS_PHASE,
-
- FSG_STATE_IDLE = 0,
- FSG_STATE_ABORT_BULK_OUT,
- FSG_STATE_RESET,
- FSG_STATE_INTERFACE_CHANGE,
- FSG_STATE_CONFIG_CHANGE,
- FSG_STATE_DISCONNECT,
- FSG_STATE_EXIT,
- FSG_STATE_TERMINATED
-};
-
-enum data_direction {
- DATA_DIR_UNKNOWN = 0,
- DATA_DIR_FROM_HOST,
- DATA_DIR_TO_HOST,
- DATA_DIR_NONE
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-
-static inline u32 get_unaligned_be24(u8 *buf)
-{
- return 0xffffff & (u32) get_unaligned_be32(buf - 1);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-
-enum {
-#ifndef FSG_NO_DEVICE_STRINGS
- FSG_STRING_MANUFACTURER = 1,
- FSG_STRING_PRODUCT,
- FSG_STRING_SERIAL,
- FSG_STRING_CONFIG,
-#endif
- FSG_STRING_INTERFACE
-};
-
-
-#ifndef FSG_NO_OTG
-static struct usb_otg_descriptor
-fsg_otg_desc = {
- .bLength = sizeof fsg_otg_desc,
- .bDescriptorType = USB_DT_OTG,
-
- .bmAttributes = USB_OTG_SRP,
-};
-#endif
-
-/* There is only one interface. */
-
-static struct usb_interface_descriptor
-fsg_intf_desc = {
- .bLength = sizeof fsg_intf_desc,
- .bDescriptorType = USB_DT_INTERFACE,
-
- .bNumEndpoints = 2, /* Adjusted during fsg_bind() */
- .bInterfaceClass = USB_CLASS_MASS_STORAGE,
- .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */
- .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */
- .iInterface = FSG_STRING_INTERFACE,
-};
-
-/*
- * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
- * interrupt-in.
- */
-
-static struct usb_endpoint_descriptor
-fsg_fs_bulk_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- /* wMaxPacketSize set by autoconfiguration */
-};
-
-static struct usb_endpoint_descriptor
-fsg_fs_bulk_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- /* wMaxPacketSize set by autoconfiguration */
-};
-
-#ifndef FSG_NO_INTR_EP
-
-static struct usb_endpoint_descriptor
-fsg_fs_intr_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(2),
- .bInterval = 32, /* frames -> 32 ms */
-};
-
-#ifndef FSG_NO_OTG
-# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
-#else
-# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
-#endif
-
-#endif
-
-static struct usb_descriptor_header *fsg_fs_function[] = {
-#ifndef FSG_NO_OTG
- (struct usb_descriptor_header *) &fsg_otg_desc,
-#endif
- (struct usb_descriptor_header *) &fsg_intf_desc,
- (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
- (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
-#ifndef FSG_NO_INTR_EP
- (struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
-#endif
- NULL,
-};
-
-
-/*
- * USB 2.0 devices need to expose both high speed and full speed
- * descriptors, unless they only run at full speed.
- *
- * That means alternate endpoint descriptors (bigger packets)
- * and a "device qualifier" ... plus more construction options
- * for the configuration descriptor.
- */
-static struct usb_endpoint_descriptor
-fsg_hs_bulk_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor
-fsg_hs_bulk_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(512),
- .bInterval = 1, /* NAK every 1 uframe */
-};
-
-#ifndef FSG_NO_INTR_EP
-
-static struct usb_endpoint_descriptor
-fsg_hs_intr_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(2),
- .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
-};
-
-#ifndef FSG_NO_OTG
-# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
-#else
-# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
-#endif
-
-#endif
-
-static struct usb_descriptor_header *fsg_hs_function[] = {
-#ifndef FSG_NO_OTG
- (struct usb_descriptor_header *) &fsg_otg_desc,
-#endif
- (struct usb_descriptor_header *) &fsg_intf_desc,
- (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
- (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
-#ifndef FSG_NO_INTR_EP
- (struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
-#endif
- NULL,
-};
-
-static struct usb_endpoint_descriptor
-fsg_ss_bulk_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
- .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /*.bMaxBurst = DYNAMIC, */
-};
-
-static struct usb_endpoint_descriptor
-fsg_ss_bulk_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
- .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /*.bMaxBurst = DYNAMIC, */
-};
-
-#ifndef FSG_NO_INTR_EP
-
-static struct usb_endpoint_descriptor
-fsg_ss_intr_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(2),
- .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
-};
-
-static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
- .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- .wBytesPerInterval = cpu_to_le16(2),
-};
-
-#ifndef FSG_NO_OTG
-# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2
-#else
-# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1
-#endif
-
-#endif
-
-static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
- .bLength = USB_DT_USB_EXT_CAP_SIZE,
- .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
- .bDevCapabilityType = USB_CAP_TYPE_EXT,
-
- .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT),
-};
-
-static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
- .bLength = USB_DT_USB_SS_CAP_SIZE,
- .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
- .bDevCapabilityType = USB_SS_CAP_TYPE,
-
- /* .bmAttributes = LTM is not supported yet */
-
- .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION
- | USB_FULL_SPEED_OPERATION
- | USB_HIGH_SPEED_OPERATION
- | USB_5GBPS_OPERATION),
- .bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
- .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT,
- .bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT),
-};
-
-static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
- .bLength = USB_DT_BOS_SIZE,
- .bDescriptorType = USB_DT_BOS,
-
- .wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE
- + USB_DT_USB_EXT_CAP_SIZE
- + USB_DT_USB_SS_CAP_SIZE),
-
- .bNumDeviceCaps = 2,
-};
-
-static struct usb_descriptor_header *fsg_ss_function[] = {
-#ifndef FSG_NO_OTG
- (struct usb_descriptor_header *) &fsg_otg_desc,
-#endif
- (struct usb_descriptor_header *) &fsg_intf_desc,
- (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
- (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
- (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
- (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
-#ifndef FSG_NO_INTR_EP
- (struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
- (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
-#endif
- NULL,
-};
-
-/* Maxpacket and other transfer characteristics vary by speed. */
-static __maybe_unused struct usb_endpoint_descriptor *
-fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
- struct usb_endpoint_descriptor *hs,
- struct usb_endpoint_descriptor *ss)
-{
- if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
- return ss;
- else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
- return hs;
- return fs;
-}
-
-
-/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
-static struct usb_string fsg_strings[] = {
-#ifndef FSG_NO_DEVICE_STRINGS
- {FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
- {FSG_STRING_PRODUCT, fsg_string_product},
- {FSG_STRING_SERIAL, ""},
- {FSG_STRING_CONFIG, fsg_string_config},
-#endif
- {FSG_STRING_INTERFACE, fsg_string_interface},
- {}
-};
-
-static struct usb_gadget_strings fsg_stringtab = {
- .language = 0x0409, /* en-us */
- .strings = fsg_strings,
-};
-
-
- /*-------------------------------------------------------------------------*/
-
-/*
- * If the next two routines are called while the gadget is registered,
- * the caller must own fsg->filesem for writing.
- */
-
-static void fsg_lun_close(struct fsg_lun *curlun)
-{
- if (curlun->filp) {
- LDBG(curlun, "close backing file\n");
- fput(curlun->filp);
- curlun->filp = NULL;
- }
-}
-
-
-static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
-{
- int ro;
- struct file *filp = NULL;
- int rc = -EINVAL;
- struct inode *inode = NULL;
- loff_t size;
- loff_t num_sectors;
- loff_t min_sectors;
- unsigned int blkbits;
- unsigned int blksize;
-
- /* R/W if we can, R/O if we must */
- ro = curlun->initially_ro;
- if (!ro) {
- filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
- if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
- ro = 1;
- }
- if (ro)
- filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
- if (IS_ERR(filp)) {
- LINFO(curlun, "unable to open backing file: %s\n", filename);
- return PTR_ERR(filp);
- }
-
- if (!(filp->f_mode & FMODE_WRITE))
- ro = 1;
-
- inode = file_inode(filp);
- if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
- LINFO(curlun, "invalid file type: %s\n", filename);
- goto out;
- }
-
- /*
- * If we can't read the file, it's no good.
- * If we can't write the file, use it read-only.
- */
- if (!(filp->f_op->read || filp->f_op->aio_read)) {
- LINFO(curlun, "file not readable: %s\n", filename);
- goto out;
- }
- if (!(filp->f_op->write || filp->f_op->aio_write))
- ro = 1;
-
- size = i_size_read(inode->i_mapping->host);
- if (size < 0) {
- LINFO(curlun, "unable to find file size: %s\n", filename);
- rc = (int) size;
- goto out;
- }
-
- if (curlun->cdrom) {
- blksize = 2048;
- blkbits = 11;
- } else if (inode->i_bdev) {
- blksize = bdev_logical_block_size(inode->i_bdev);
- blkbits = blksize_bits(blksize);
- } else {
- blksize = 512;
- blkbits = 9;
- }
-
- num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
- min_sectors = 1;
- if (curlun->cdrom) {
- min_sectors = 300; /* Smallest track is 300 frames */
- if (num_sectors >= 256*60*75) {
- num_sectors = 256*60*75 - 1;
- LINFO(curlun, "file too big: %s\n", filename);
- LINFO(curlun, "using only first %d blocks\n",
- (int) num_sectors);
- }
- }
- if (num_sectors < min_sectors) {
- LINFO(curlun, "file too small: %s\n", filename);
- rc = -ETOOSMALL;
- goto out;
- }
-
- if (fsg_lun_is_open(curlun))
- fsg_lun_close(curlun);
-
- curlun->blksize = blksize;
- curlun->blkbits = blkbits;
- curlun->ro = ro;
- curlun->filp = filp;
- curlun->file_length = size;
- curlun->num_sectors = num_sectors;
- LDBG(curlun, "open backing file: %s\n", filename);
- return 0;
-
-out:
- fput(filp);
- return rc;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Sync the file data, don't bother with the metadata.
- * This code was copied from fs/buffer.c:sys_fdatasync().
- */
-static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
-{
- struct file *filp = curlun->filp;
-
- if (curlun->ro || !filp)
- return 0;
- return vfs_fsync(filp, 1);
-}
-
-static void store_cdrom_address(u8 *dest, int msf, u32 addr)
-{
- if (msf) {
- /* Convert to Minutes-Seconds-Frames */
- addr >>= 2; /* Convert to 2048-byte frames */
- addr += 2*75; /* Lead-in occupies 2 seconds */
- dest[3] = addr % 75; /* Frames */
- addr /= 75;
- dest[2] = addr % 60; /* Seconds */
- addr /= 60;
- dest[1] = addr; /* Minutes */
- dest[0] = 0; /* Reserved */
- } else {
- /* Absolute sector */
- put_unaligned_be32(addr, dest);
- }
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-
-static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
-
- return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
- ? curlun->ro
- : curlun->initially_ro);
-}
-
-static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
-
- return sprintf(buf, "%u\n", curlun->nofua);
-}
-
-static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
- char *p;
- ssize_t rc;
-
- down_read(filesem);
- if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */
- p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
- if (IS_ERR(p))
- rc = PTR_ERR(p);
- else {
- rc = strlen(p);
- memmove(buf, p, rc);
- buf[rc] = '\n'; /* Add a newline */
- buf[++rc] = 0;
- }
- } else { /* No file, return 0 bytes */
- *buf = 0;
- rc = 0;
- }
- up_read(filesem);
- return rc;
-}
-
-
-static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- ssize_t rc;
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
- unsigned ro;
-
- rc = kstrtouint(buf, 2, &ro);
- if (rc)
- return rc;
-
- /*
- * Allow the write-enable status to change only while the
- * backing file is closed.
- */
- down_read(filesem);
- if (fsg_lun_is_open(curlun)) {
- LDBG(curlun, "read-only status change prevented\n");
- rc = -EBUSY;
- } else {
- curlun->ro = ro;
- curlun->initially_ro = ro;
- LDBG(curlun, "read-only status set to %d\n", curlun->ro);
- rc = count;
- }
- up_read(filesem);
- return rc;
-}
-
-static ssize_t fsg_store_nofua(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- unsigned nofua;
- int ret;
-
- ret = kstrtouint(buf, 2, &nofua);
- if (ret)
- return ret;
-
- /* Sync data when switching from async mode to sync */
- if (!nofua && curlun->nofua)
- fsg_lun_fsync_sub(curlun);
-
- curlun->nofua = nofua;
-
- return count;
-}
-
-static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct fsg_lun *curlun = fsg_lun_from_dev(dev);
- struct rw_semaphore *filesem = dev_get_drvdata(dev);
- int rc = 0;
-
- if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
- LDBG(curlun, "eject attempt prevented\n");
- return -EBUSY; /* "Door is locked" */
- }
-
- /* Remove a trailing newline */
- if (count > 0 && buf[count-1] == '\n')
- ((char *) buf)[count-1] = 0; /* Ugh! */
-
- /* Load new medium */
- down_write(filesem);
- if (count > 0 && buf[0]) {
- /* fsg_lun_open() will close existing file if any. */
- rc = fsg_lun_open(curlun, buf);
- if (rc == 0)
- curlun->unit_attention_data =
- SS_NOT_READY_TO_READY_TRANSITION;
- } else if (fsg_lun_is_open(curlun)) {
- fsg_lun_close(curlun);
- curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
- }
- up_write(filesem);
- return (rc < 0 ? rc : count);
-}
diff --git a/drivers/staging/ccg/sysfs-class-ccg_usb b/drivers/staging/ccg/sysfs-class-ccg_usb
deleted file mode 100644
index dd12a332fb00..000000000000
--- a/drivers/staging/ccg/sysfs-class-ccg_usb
+++ /dev/null
@@ -1,158 +0,0 @@
-What: /sys/class/ccg_usb
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The ccg_usb/ class subdirectory belongs to ccg
- USB gadget.
-
-What: /sys/class/ccg_usb/ccgX
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccg{0,1,2,3...} class
- subdirectories correspond to each ccg gadget device;
- at the time of this writing there is only ccg0 and it
- represents the ccg gadget.
-
-What: /sys/class/ccg_usb/ccgX/functions
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- A comma-separated list of USB function names to be activated
- in this ccg gadget. It includes both the functions provided
- in-kernel by the ccg gadget and the functions provided from
- userspace through FunctionFS.
-
-What: /sys/class/ccg_usb/ccgX/enable
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- A flag activating/deactivating the ccg usb gadget.
-
-What: /sys/class/ccg_usb/ccgX/state
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- Configurable usb gadget state:
-
- DISCONNECTED
- CONNECTED
- CONFIGURED
-
-What: /sys/class/ccg_usb/ccgX/f_acm/
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_acm subdirectory
- corresponds to the gadget's USB CDC serial (ACM) function
- driver.
-
-What: /sys/class/ccg_usb/ccgX/f_acm/instances
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- Maximum number of the /dev/ttyGS<X> interface the driver uses.
-
-What: /sys/class/ccg_usb/ccgX/f_fs
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_fs subdirectory
- corresponds to the gadget's FunctionFS driver.
-
-What: /sys/class/ccg_usb/ccgX/f_fs/user_functions
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- A comma-separeted list of USB function names to be supported
- from userspace. No other userspace FunctionFS functions can
- be supported than listed here. However, the actual activation
- of these functions is still done through
- /sys/class/ccg_usb/ccgX/functions, where it is possible
- to specify any subset (including maximum and empty) of
- /sys/class/ccg_usb/ccgX/f_fs/user_functions.
-
-What: /sys/class/ccg_usb/ccgX/f_fs/max_user_functions
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- Maximum number of USB functions to be supported from userspace.
-
-What: /sys/class/ccg_usb/ccgX/f_rndis
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_rndis subdirectory
- corresponds to the gadget's RNDIS driver.
-
-What: /sys/class/ccg_usb/ccgX/f_rndis/manufacturer
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- RNDIS Ethernet port manufacturer string.
-
-What: /sys/class/ccg_usb/ccgX/f_rndis/wceis
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- RNDIS Ethernet port wireless flag.
-
-What: /sys/class/ccg_usb/ccgX/f_rndis/ethaddr
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- RNDIS Ethernet port Ethernet address.
-
-What: /sys/class/ccg_usb/ccgX/f_rndis/vendorID
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- RNDIS Ethernet port vendor ID.
-
-What: /sys/class/ccg_usb/ccgX/f_mass_storage
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_mass_storage subdirectory
- corresponds to the gadget's USB mass storage driver.
-
-What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
- subdirectory corresponds to the gadget's USB mass storage
- driver and its underlying storage.
-
-What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
- subdirectory corresponds to the gadget's USB mass storage
- driver and its underlying storage.
-
-What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun/file
-Date: May 2012
-KernelVersion: 3.4
-Contact: linux-usb@vger.kernel.org
-Description:
- Gadget's USB mass storage underlying file.
diff --git a/drivers/staging/ccg/u_ether.c b/drivers/staging/ccg/u_ether.c
deleted file mode 100644
index fed78865adc6..000000000000
--- a/drivers/staging/ccg/u_ether.c
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/device.h>
-#include <linux/ctype.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-
-#include "u_ether.h"
-
-
-/*
- * This component encapsulates the Ethernet link glue needed to provide
- * one (!) network link through the USB gadget stack, normally "usb0".
- *
- * The control and data models are handled by the function driver which
- * connects to this code; such as CDC Ethernet (ECM or EEM),
- * "CDC Subset", or RNDIS. That includes all descriptor and endpoint
- * management.
- *
- * Link level addressing is handled by this component using module
- * parameters; if no such parameters are provided, random link level
- * addresses are used. Each end of the link uses one address. The
- * host end address is exported in various ways, and is often recorded
- * in configuration databases.
- *
- * The driver which assembles each configuration using such a link is
- * responsible for ensuring that each configuration includes at most one
- * instance of is network link. (The network layer provides ways for
- * this single "physical" link to be used by multiple virtual links.)
- */
-
-#define UETH__VERSION "29-May-2008"
-
-struct eth_dev {
- /* lock is held while accessing port_usb
- * or updating its backlink port_usb->ioport
- */
- spinlock_t lock;
- struct gether *port_usb;
-
- struct net_device *net;
- struct usb_gadget *gadget;
-
- spinlock_t req_lock; /* guard {rx,tx}_reqs */
- struct list_head tx_reqs, rx_reqs;
- atomic_t tx_qlen;
-
- struct sk_buff_head rx_frames;
-
- unsigned header_len;
- struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
- int (*unwrap)(struct gether *,
- struct sk_buff *skb,
- struct sk_buff_head *list);
-
- struct work_struct work;
-
- unsigned long todo;
-#define WORK_RX_MEMORY 0
-
- bool zlp;
- u8 host_mac[ETH_ALEN];
-};
-
-/*-------------------------------------------------------------------------*/
-
-#define RX_EXTRA 20 /* bytes guarding against rx overflows */
-
-#define DEFAULT_QLEN 2 /* double buffering by default */
-
-static unsigned qmult = 5;
-module_param(qmult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
-
-/* for dual-speed hardware, use deeper queues at high/super speed */
-static inline int qlen(struct usb_gadget *gadget)
-{
- if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
- gadget->speed == USB_SPEED_SUPER))
- return qmult * DEFAULT_QLEN;
- else
- return DEFAULT_QLEN;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* REVISIT there must be a better way than having two sets
- * of debug calls ...
- */
-
-#undef DBG
-#undef VDBG
-#undef ERROR
-#undef INFO
-
-#define xprintk(d, level, fmt, args...) \
- printk(level "%s: " fmt , (d)->net->name , ## args)
-
-#ifdef DEBUG
-#undef DEBUG
-#define DBG(dev, fmt, args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE_DEBUG
-#define VDBG DBG
-#else
-#define VDBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#define ERROR(dev, fmt, args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define INFO(dev, fmt, args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
-
-/*-------------------------------------------------------------------------*/
-
-/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
-
-static int ueth_change_mtu(struct net_device *net, int new_mtu)
-{
- struct eth_dev *dev = netdev_priv(net);
- unsigned long flags;
- int status = 0;
-
- /* don't change MTU on "live" link (peer won't know) */
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- status = -EBUSY;
- else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN)
- status = -ERANGE;
- else
- net->mtu = new_mtu;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return status;
-}
-
-static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
-{
- struct eth_dev *dev = netdev_priv(net);
-
- strlcpy(p->driver, "g_ether", sizeof(p->driver));
- strlcpy(p->version, UETH__VERSION, sizeof(p->version));
- strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version));
- strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info));
-}
-
-/* REVISIT can also support:
- * - WOL (by tracking suspends and issuing remote wakeup)
- * - msglevel (implies updated messaging)
- * - ... probably more ethtool ops
- */
-
-static const struct ethtool_ops ops = {
- .get_drvinfo = eth_get_drvinfo,
- .get_link = ethtool_op_get_link,
-};
-
-static void defer_kevent(struct eth_dev *dev, int flag)
-{
- if (test_and_set_bit(flag, &dev->todo))
- return;
- if (!schedule_work(&dev->work))
- ERROR(dev, "kevent %d may have been dropped\n", flag);
- else
- DBG(dev, "kevent %d scheduled\n", flag);
-}
-
-static void rx_complete(struct usb_ep *ep, struct usb_request *req);
-
-static int
-rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
-{
- struct sk_buff *skb;
- int retval = -ENOMEM;
- size_t size = 0;
- struct usb_ep *out;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- out = dev->port_usb->out_ep;
- else
- out = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- if (!out)
- return -ENOTCONN;
-
-
- /* Padding up to RX_EXTRA handles minor disagreements with host.
- * Normally we use the USB "terminate on short read" convention;
- * so allow up to (N*maxpacket), since that memory is normally
- * already allocated. Some hardware doesn't deal well with short
- * reads (e.g. DMA must be N*maxpacket), so for now don't trim a
- * byte off the end (to force hardware errors on overflow).
- *
- * RNDIS uses internal framing, and explicitly allows senders to
- * pad to end-of-packet. That's potentially nice for speed, but
- * means receivers can't recover lost synch on their own (because
- * new packets don't only start after a short RX).
- */
- size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
- size += dev->port_usb->header_len;
- size += out->maxpacket - 1;
- size -= size % out->maxpacket;
-
- if (dev->port_usb->is_fixed)
- size = max_t(size_t, size, dev->port_usb->fixed_out_len);
-
- skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
- if (skb == NULL) {
- DBG(dev, "no rx skb\n");
- goto enomem;
- }
-
- /* Some platforms perform better when IP packets are aligned,
- * but on at least one, checksumming fails otherwise. Note:
- * RNDIS headers involve variable numbers of LE32 values.
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
- req->buf = skb->data;
- req->length = size;
- req->complete = rx_complete;
- req->context = skb;
-
- retval = usb_ep_queue(out, req, gfp_flags);
- if (retval == -ENOMEM)
-enomem:
- defer_kevent(dev, WORK_RX_MEMORY);
- if (retval) {
- DBG(dev, "rx submit --> %d\n", retval);
- if (skb)
- dev_kfree_skb_any(skb);
- spin_lock_irqsave(&dev->req_lock, flags);
- list_add(&req->list, &dev->rx_reqs);
- spin_unlock_irqrestore(&dev->req_lock, flags);
- }
- return retval;
-}
-
-static void rx_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct sk_buff *skb = req->context, *skb2;
- struct eth_dev *dev = ep->driver_data;
- int status = req->status;
-
- switch (status) {
-
- /* normal completion */
- case 0:
- skb_put(skb, req->actual);
-
- if (dev->unwrap) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb) {
- status = dev->unwrap(dev->port_usb,
- skb,
- &dev->rx_frames);
- } else {
- dev_kfree_skb_any(skb);
- status = -ENOTCONN;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- skb_queue_tail(&dev->rx_frames, skb);
- }
- skb = NULL;
-
- skb2 = skb_dequeue(&dev->rx_frames);
- while (skb2) {
- if (status < 0
- || ETH_HLEN > skb2->len
- || skb2->len > ETH_FRAME_LEN) {
- dev->net->stats.rx_errors++;
- dev->net->stats.rx_length_errors++;
- DBG(dev, "rx length %d\n", skb2->len);
- dev_kfree_skb_any(skb2);
- goto next_frame;
- }
- skb2->protocol = eth_type_trans(skb2, dev->net);
- dev->net->stats.rx_packets++;
- dev->net->stats.rx_bytes += skb2->len;
-
- /* no buffer copies needed, unless hardware can't
- * use skb buffers.
- */
- status = netif_rx(skb2);
-next_frame:
- skb2 = skb_dequeue(&dev->rx_frames);
- }
- break;
-
- /* software-driven interface shutdown */
- case -ECONNRESET: /* unlink */
- case -ESHUTDOWN: /* disconnect etc */
- VDBG(dev, "rx shutdown, code %d\n", status);
- goto quiesce;
-
- /* for hardware automagic (such as pxa) */
- case -ECONNABORTED: /* endpoint reset */
- DBG(dev, "rx %s reset\n", ep->name);
- defer_kevent(dev, WORK_RX_MEMORY);
-quiesce:
- dev_kfree_skb_any(skb);
- goto clean;
-
- /* data overrun */
- case -EOVERFLOW:
- dev->net->stats.rx_over_errors++;
- /* FALLTHROUGH */
-
- default:
- dev->net->stats.rx_errors++;
- DBG(dev, "rx status %d\n", status);
- break;
- }
-
- if (skb)
- dev_kfree_skb_any(skb);
- if (!netif_running(dev->net)) {
-clean:
- spin_lock(&dev->req_lock);
- list_add(&req->list, &dev->rx_reqs);
- spin_unlock(&dev->req_lock);
- req = NULL;
- }
- if (req)
- rx_submit(dev, req, GFP_ATOMIC);
-}
-
-static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n)
-{
- unsigned i;
- struct usb_request *req;
-
- if (!n)
- return -ENOMEM;
-
- /* queue/recycle up to N requests */
- i = n;
- list_for_each_entry(req, list, list) {
- if (i-- == 0)
- goto extra;
- }
- while (i--) {
- req = usb_ep_alloc_request(ep, GFP_ATOMIC);
- if (!req)
- return list_empty(list) ? -ENOMEM : 0;
- list_add(&req->list, list);
- }
- return 0;
-
-extra:
- /* free extras */
- for (;;) {
- struct list_head *next;
-
- next = req->list.next;
- list_del(&req->list);
- usb_ep_free_request(ep, req);
-
- if (next == list)
- break;
-
- req = container_of(next, struct usb_request, list);
- }
- return 0;
-}
-
-static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
-{
- int status;
-
- spin_lock(&dev->req_lock);
- status = prealloc(&dev->tx_reqs, link->in_ep, n);
- if (status < 0)
- goto fail;
- status = prealloc(&dev->rx_reqs, link->out_ep, n);
- if (status < 0)
- goto fail;
- goto done;
-fail:
- DBG(dev, "can't alloc requests\n");
-done:
- spin_unlock(&dev->req_lock);
- return status;
-}
-
-static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
-{
- struct usb_request *req;
- unsigned long flags;
-
- /* fill unused rxq slots with some skb */
- spin_lock_irqsave(&dev->req_lock, flags);
- while (!list_empty(&dev->rx_reqs)) {
- req = container_of(dev->rx_reqs.next,
- struct usb_request, list);
- list_del_init(&req->list);
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
- if (rx_submit(dev, req, gfp_flags) < 0) {
- defer_kevent(dev, WORK_RX_MEMORY);
- return;
- }
-
- spin_lock_irqsave(&dev->req_lock, flags);
- }
- spin_unlock_irqrestore(&dev->req_lock, flags);
-}
-
-static void eth_work(struct work_struct *work)
-{
- struct eth_dev *dev = container_of(work, struct eth_dev, work);
-
- if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) {
- if (netif_running(dev->net))
- rx_fill(dev, GFP_KERNEL);
- }
-
- if (dev->todo)
- DBG(dev, "work done, flags = 0x%lx\n", dev->todo);
-}
-
-static void tx_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct sk_buff *skb = req->context;
- struct eth_dev *dev = ep->driver_data;
-
- switch (req->status) {
- default:
- dev->net->stats.tx_errors++;
- VDBG(dev, "tx err %d\n", req->status);
- /* FALLTHROUGH */
- case -ECONNRESET: /* unlink */
- case -ESHUTDOWN: /* disconnect etc */
- break;
- case 0:
- dev->net->stats.tx_bytes += skb->len;
- }
- dev->net->stats.tx_packets++;
-
- spin_lock(&dev->req_lock);
- list_add(&req->list, &dev->tx_reqs);
- spin_unlock(&dev->req_lock);
- dev_kfree_skb_any(skb);
-
- atomic_dec(&dev->tx_qlen);
- if (netif_carrier_ok(dev->net))
- netif_wake_queue(dev->net);
-}
-
-static inline int is_promisc(u16 cdc_filter)
-{
- return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
-}
-
-static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
- struct net_device *net)
-{
- struct eth_dev *dev = netdev_priv(net);
- int length = skb->len;
- int retval;
- struct usb_request *req = NULL;
- unsigned long flags;
- struct usb_ep *in;
- u16 cdc_filter;
-
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb) {
- in = dev->port_usb->in_ep;
- cdc_filter = dev->port_usb->cdc_filter;
- } else {
- in = NULL;
- cdc_filter = 0;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- if (!in) {
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- /* apply outgoing CDC or RNDIS filters */
- if (!is_promisc(cdc_filter)) {
- u8 *dest = skb->data;
-
- if (is_multicast_ether_addr(dest)) {
- u16 type;
-
- /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host
- * SET_ETHERNET_MULTICAST_FILTERS requests
- */
- if (is_broadcast_ether_addr(dest))
- type = USB_CDC_PACKET_TYPE_BROADCAST;
- else
- type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
- if (!(cdc_filter & type)) {
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
- }
- /* ignores USB_CDC_PACKET_TYPE_DIRECTED */
- }
-
- spin_lock_irqsave(&dev->req_lock, flags);
- /*
- * this freelist can be empty if an interrupt triggered disconnect()
- * and reconfigured the gadget (shutting down this queue) after the
- * network stack decided to xmit but before we got the spinlock.
- */
- if (list_empty(&dev->tx_reqs)) {
- spin_unlock_irqrestore(&dev->req_lock, flags);
- return NETDEV_TX_BUSY;
- }
-
- req = container_of(dev->tx_reqs.next, struct usb_request, list);
- list_del(&req->list);
-
- /* temporarily stop TX queue when the freelist empties */
- if (list_empty(&dev->tx_reqs))
- netif_stop_queue(net);
- spin_unlock_irqrestore(&dev->req_lock, flags);
-
- /* no buffer copies needed, unless the network stack did it
- * or the hardware can't use skb buffers.
- * or there's not enough space for extra headers we need
- */
- if (dev->wrap) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb)
- skb = dev->wrap(dev->port_usb, skb);
- spin_unlock_irqrestore(&dev->lock, flags);
- if (!skb)
- goto drop;
-
- length = skb->len;
- }
- req->buf = skb->data;
- req->context = skb;
- req->complete = tx_complete;
-
- /* NCM requires no zlp if transfer is dwNtbInMaxSize */
- if (dev->port_usb->is_fixed &&
- length == dev->port_usb->fixed_in_len &&
- (length % in->maxpacket) == 0)
- req->zero = 0;
- else
- req->zero = 1;
-
- /* use zlp framing on tx for strict CDC-Ether conformance,
- * though any robust network rx path ignores extra padding.
- * and some hardware doesn't like to write zlps.
- */
- if (req->zero && !dev->zlp && (length % in->maxpacket) == 0)
- length++;
-
- req->length = length;
-
- /* throttle high/super speed IRQ rate back slightly */
- if (gadget_is_dualspeed(dev->gadget))
- req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
- dev->gadget->speed == USB_SPEED_SUPER)
- ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
- : 0;
-
- retval = usb_ep_queue(in, req, GFP_ATOMIC);
- switch (retval) {
- default:
- DBG(dev, "tx queue err %d\n", retval);
- break;
- case 0:
- net->trans_start = jiffies;
- atomic_inc(&dev->tx_qlen);
- }
-
- if (retval) {
- dev_kfree_skb_any(skb);
-drop:
- dev->net->stats.tx_dropped++;
- spin_lock_irqsave(&dev->req_lock, flags);
- if (list_empty(&dev->tx_reqs))
- netif_start_queue(net);
- list_add(&req->list, &dev->tx_reqs);
- spin_unlock_irqrestore(&dev->req_lock, flags);
- }
- return NETDEV_TX_OK;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void eth_start(struct eth_dev *dev, gfp_t gfp_flags)
-{
- DBG(dev, "%s\n", __func__);
-
- /* fill the rx queue */
- rx_fill(dev, gfp_flags);
-
- /* and open the tx floodgates */
- atomic_set(&dev->tx_qlen, 0);
- netif_wake_queue(dev->net);
-}
-
-static int eth_open(struct net_device *net)
-{
- struct eth_dev *dev = netdev_priv(net);
- struct gether *link;
-
- DBG(dev, "%s\n", __func__);
- if (netif_carrier_ok(dev->net))
- eth_start(dev, GFP_KERNEL);
-
- spin_lock_irq(&dev->lock);
- link = dev->port_usb;
- if (link && link->open)
- link->open(link);
- spin_unlock_irq(&dev->lock);
-
- return 0;
-}
-
-static int eth_stop(struct net_device *net)
-{
- struct eth_dev *dev = netdev_priv(net);
- unsigned long flags;
-
- VDBG(dev, "%s\n", __func__);
- netif_stop_queue(net);
-
- DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
- dev->net->stats.rx_packets, dev->net->stats.tx_packets,
- dev->net->stats.rx_errors, dev->net->stats.tx_errors
- );
-
- /* ensure there are no more active requests */
- spin_lock_irqsave(&dev->lock, flags);
- if (dev->port_usb) {
- struct gether *link = dev->port_usb;
-
- if (link->close)
- link->close(link);
-
- /* NOTE: we have no abort-queue primitive we could use
- * to cancel all pending I/O. Instead, we disable then
- * reenable the endpoints ... this idiom may leave toggle
- * wrong, but that's a self-correcting error.
- *
- * REVISIT: we *COULD* just let the transfers complete at
- * their own pace; the network stack can handle old packets.
- * For the moment we leave this here, since it works.
- */
- usb_ep_disable(link->in_ep);
- usb_ep_disable(link->out_ep);
- if (netif_carrier_ok(net)) {
- DBG(dev, "host still using in/out endpoints\n");
- usb_ep_enable(link->in_ep);
- usb_ep_enable(link->out_ep);
- }
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */
-static char *dev_addr;
-module_param(dev_addr, charp, S_IRUGO);
-MODULE_PARM_DESC(dev_addr, "Device Ethernet Address");
-
-/* this address is invisible to ifconfig */
-static char *host_addr;
-module_param(host_addr, charp, S_IRUGO);
-MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
-
-static int get_ether_addr(const char *str, u8 *dev_addr)
-{
- if (str) {
- unsigned i;
-
- for (i = 0; i < 6; i++) {
- unsigned char num;
-
- if ((*str == '.') || (*str == ':'))
- str++;
- num = hex_to_bin(*str++) << 4;
- num |= hex_to_bin(*str++);
- dev_addr [i] = num;
- }
- if (is_valid_ether_addr(dev_addr))
- return 0;
- }
- eth_random_addr(dev_addr);
- return 1;
-}
-
-static struct eth_dev *the_dev;
-
-static const struct net_device_ops eth_netdev_ops = {
- .ndo_open = eth_open,
- .ndo_stop = eth_stop,
- .ndo_start_xmit = eth_start_xmit,
- .ndo_change_mtu = ueth_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static struct device_type gadget_type = {
- .name = "gadget",
-};
-
-/**
- * gether_setup_name - initialize one ethernet-over-usb link
- * @g: gadget to associated with these links
- * @ethaddr: NULL, or a buffer in which the ethernet address of the
- * host side of the link is recorded
- * @netname: name for network device (for example, "usb")
- * Context: may sleep
- *
- * This sets up the single network link that may be exported by a
- * gadget driver using this framework. The link layer addresses are
- * set up using module parameters.
- *
- * Returns negative errno, or zero on success
- */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
- const char *netname)
-{
- struct eth_dev *dev;
- struct net_device *net;
- int status;
-
- if (the_dev)
- return -EBUSY;
-
- net = alloc_etherdev(sizeof *dev);
- if (!net)
- return -ENOMEM;
-
- dev = netdev_priv(net);
- spin_lock_init(&dev->lock);
- spin_lock_init(&dev->req_lock);
- INIT_WORK(&dev->work, eth_work);
- INIT_LIST_HEAD(&dev->tx_reqs);
- INIT_LIST_HEAD(&dev->rx_reqs);
-
- skb_queue_head_init(&dev->rx_frames);
-
- /* network device setup */
- dev->net = net;
- snprintf(net->name, sizeof(net->name), "%s%%d", netname);
-
- if (get_ether_addr(dev_addr, net->dev_addr))
- dev_warn(&g->dev,
- "using random %s ethernet address\n", "self");
- if (get_ether_addr(host_addr, dev->host_mac))
- dev_warn(&g->dev,
- "using random %s ethernet address\n", "host");
-
- if (ethaddr)
- memcpy(ethaddr, dev->host_mac, ETH_ALEN);
-
- net->netdev_ops = &eth_netdev_ops;
-
- SET_ETHTOOL_OPS(net, &ops);
-
- dev->gadget = g;
- SET_NETDEV_DEV(net, &g->dev);
- SET_NETDEV_DEVTYPE(net, &gadget_type);
-
- status = register_netdev(net);
- if (status < 0) {
- dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
- free_netdev(net);
- } else {
- INFO(dev, "MAC %pM\n", net->dev_addr);
- INFO(dev, "HOST MAC %pM\n", dev->host_mac);
-
- the_dev = dev;
-
- /* two kinds of host-initiated state changes:
- * - iff DATA transfer is active, carrier is "on"
- * - tx queueing enabled if open *and* carrier is "on"
- */
- netif_carrier_off(net);
- }
-
- return status;
-}
-
-/**
- * gether_cleanup - remove Ethernet-over-USB device
- * Context: may sleep
- *
- * This is called to free all resources allocated by @gether_setup().
- */
-void gether_cleanup(void)
-{
- if (!the_dev)
- return;
-
- unregister_netdev(the_dev->net);
- flush_work(&the_dev->work);
- free_netdev(the_dev->net);
-
- the_dev = NULL;
-}
-
-
-/**
- * gether_connect - notify network layer that USB link is active
- * @link: the USB link, set up with endpoints, descriptors matching
- * current device speed, and any framing wrapper(s) set up.
- * Context: irqs blocked
- *
- * This is called to activate endpoints and let the network layer know
- * the connection is active ("carrier detect"). It may cause the I/O
- * queues to open and start letting network packets flow, but will in
- * any case activate the endpoints so that they respond properly to the
- * USB host.
- *
- * Verify net_device pointer returned using IS_ERR(). If it doesn't
- * indicate some error code (negative errno), ep->driver_data values
- * have been overwritten.
- */
-struct net_device *gether_connect(struct gether *link)
-{
- struct eth_dev *dev = the_dev;
- int result = 0;
-
- if (!dev)
- return ERR_PTR(-EINVAL);
-
- link->in_ep->driver_data = dev;
- result = usb_ep_enable(link->in_ep);
- if (result != 0) {
- DBG(dev, "enable %s --> %d\n",
- link->in_ep->name, result);
- goto fail0;
- }
-
- link->out_ep->driver_data = dev;
- result = usb_ep_enable(link->out_ep);
- if (result != 0) {
- DBG(dev, "enable %s --> %d\n",
- link->out_ep->name, result);
- goto fail1;
- }
-
- if (result == 0)
- result = alloc_requests(dev, link, qlen(dev->gadget));
-
- if (result == 0) {
- dev->zlp = link->is_zlp_ok;
- DBG(dev, "qlen %d\n", qlen(dev->gadget));
-
- dev->header_len = link->header_len;
- dev->unwrap = link->unwrap;
- dev->wrap = link->wrap;
-
- spin_lock(&dev->lock);
- dev->port_usb = link;
- link->ioport = dev;
- if (netif_running(dev->net)) {
- if (link->open)
- link->open(link);
- } else {
- if (link->close)
- link->close(link);
- }
- spin_unlock(&dev->lock);
-
- netif_carrier_on(dev->net);
- if (netif_running(dev->net))
- eth_start(dev, GFP_ATOMIC);
-
- /* on error, disable any endpoints */
- } else {
- (void) usb_ep_disable(link->out_ep);
-fail1:
- (void) usb_ep_disable(link->in_ep);
- }
-fail0:
- /* caller is responsible for cleanup on error */
- if (result < 0)
- return ERR_PTR(result);
- return dev->net;
-}
-
-/**
- * gether_disconnect - notify network layer that USB link is inactive
- * @link: the USB link, on which gether_connect() was called
- * Context: irqs blocked
- *
- * This is called to deactivate endpoints and let the network layer know
- * the connection went inactive ("no carrier").
- *
- * On return, the state is as if gether_connect() had never been called.
- * The endpoints are inactive, and accordingly without active USB I/O.
- * Pointers to endpoint descriptors and endpoint private data are nulled.
- */
-void gether_disconnect(struct gether *link)
-{
- struct eth_dev *dev = link->ioport;
- struct usb_request *req;
-
- WARN_ON(!dev);
- if (!dev)
- return;
-
- DBG(dev, "%s\n", __func__);
-
- netif_stop_queue(dev->net);
- netif_carrier_off(dev->net);
-
- /* disable endpoints, forcing (synchronous) completion
- * of all pending i/o. then free the request objects
- * and forget about the endpoints.
- */
- usb_ep_disable(link->in_ep);
- spin_lock(&dev->req_lock);
- while (!list_empty(&dev->tx_reqs)) {
- req = container_of(dev->tx_reqs.next,
- struct usb_request, list);
- list_del(&req->list);
-
- spin_unlock(&dev->req_lock);
- usb_ep_free_request(link->in_ep, req);
- spin_lock(&dev->req_lock);
- }
- spin_unlock(&dev->req_lock);
- link->in_ep->driver_data = NULL;
- link->in_ep->desc = NULL;
-
- usb_ep_disable(link->out_ep);
- spin_lock(&dev->req_lock);
- while (!list_empty(&dev->rx_reqs)) {
- req = container_of(dev->rx_reqs.next,
- struct usb_request, list);
- list_del(&req->list);
-
- spin_unlock(&dev->req_lock);
- usb_ep_free_request(link->out_ep, req);
- spin_lock(&dev->req_lock);
- }
- spin_unlock(&dev->req_lock);
- link->out_ep->driver_data = NULL;
- link->out_ep->desc = NULL;
-
- /* finish forgetting about this USB link episode */
- dev->header_len = 0;
- dev->unwrap = NULL;
- dev->wrap = NULL;
-
- spin_lock(&dev->lock);
- dev->port_usb = NULL;
- link->ioport = NULL;
- spin_unlock(&dev->lock);
-}
diff --git a/drivers/staging/ccg/u_ether.h b/drivers/staging/ccg/u_ether.h
deleted file mode 100644
index 6f4a1623d854..000000000000
--- a/drivers/staging/ccg/u_ether.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * u_ether.h -- interface to USB gadget "ethernet link" utilities
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __U_ETHER_H
-#define __U_ETHER_H
-
-#include <linux/err.h>
-#include <linux/if_ether.h>
-#include <linux/usb/composite.h>
-#include <linux/usb/cdc.h>
-
-#include "gadget_chips.h"
-
-
-/*
- * This represents the USB side of an "ethernet" link, managed by a USB
- * function which provides control and (maybe) framing. Two functions
- * in different configurations could share the same ethernet link/netdev,
- * using different host interaction models.
- *
- * There is a current limitation that only one instance of this link may
- * be present in any given configuration. When that's a problem, network
- * layer facilities can be used to package multiple logical links on this
- * single "physical" one.
- */
-struct gether {
- struct usb_function func;
-
- /* updated by gether_{connect,disconnect} */
- struct eth_dev *ioport;
-
- /* endpoints handle full and/or high speeds */
- struct usb_ep *in_ep;
- struct usb_ep *out_ep;
-
- bool is_zlp_ok;
-
- u16 cdc_filter;
-
- /* hooks for added framing, as needed for RNDIS and EEM. */
- u32 header_len;
- /* NCM requires fixed size bundles */
- bool is_fixed;
- u32 fixed_out_len;
- u32 fixed_in_len;
- struct sk_buff *(*wrap)(struct gether *port,
- struct sk_buff *skb);
- int (*unwrap)(struct gether *port,
- struct sk_buff *skb,
- struct sk_buff_head *list);
-
- /* called on network open/close */
- void (*open)(struct gether *);
- void (*close)(struct gether *);
-};
-
-#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
- |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
- |USB_CDC_PACKET_TYPE_PROMISCUOUS \
- |USB_CDC_PACKET_TYPE_DIRECTED)
-
-/* variant of gether_setup that allows customizing network device name */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
- const char *netname);
-
-/* netdev setup/teardown as directed by the gadget driver */
-/* gether_setup - initialize one ethernet-over-usb link
- * @g: gadget to associated with these links
- * @ethaddr: NULL, or a buffer in which the ethernet address of the
- * host side of the link is recorded
- * Context: may sleep
- *
- * This sets up the single network link that may be exported by a
- * gadget driver using this framework. The link layer addresses are
- * set up using module parameters.
- *
- * Returns negative errno, or zero on success
- */
-static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
-{
- return gether_setup_name(g, ethaddr, "usb");
-}
-
-void gether_cleanup(void);
-
-/* connect/disconnect is handled by individual functions */
-struct net_device *gether_connect(struct gether *);
-void gether_disconnect(struct gether *);
-
-/* Some controllers can't support CDC Ethernet (ECM) ... */
-static inline bool can_support_ecm(struct usb_gadget *gadget)
-{
- if (!gadget_supports_altsettings(gadget))
- return false;
-
- /* Everything else is *presumably* fine ... but this is a bit
- * chancy, so be **CERTAIN** there are no hardware issues with
- * your controller. Add it above if it can't handle CDC.
- */
- return true;
-}
-
-/* each configuration may bind one instance of an ethernet link */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int eem_bind_config(struct usb_configuration *c);
-
-#ifdef USB_ETH_RNDIS
-
-int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer);
-
-#else
-
-static inline int
-rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
-{
- return 0;
-}
-
-#endif
-
-/**
- * rndis_bind_config - add RNDIS network link to a configuration
- * @c: the configuration to support the network link
- * @ethaddr: a buffer in which the ethernet address of the host side
- * side of the link was recorded
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gether_setup(). Caller is also responsible
- * for calling @gether_cleanup() before module unload.
- */
-static inline int rndis_bind_config(struct usb_configuration *c,
- u8 ethaddr[ETH_ALEN])
-{
- return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
-}
-
-
-#endif /* __U_ETHER_H */
diff --git a/drivers/staging/ccg/u_serial.c b/drivers/staging/ccg/u_serial.c
deleted file mode 100644
index b10947ae0ac5..000000000000
--- a/drivers/staging/ccg/u_serial.c
+++ /dev/null
@@ -1,1339 +0,0 @@
-/*
- * u_serial.c - utilities for USB gadget "serial port"/TTY support
- *
- * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This code also borrows from usbserial.c, which is
- * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
- * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com)
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * either version 2 of that License or (at your option) any later version.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "u_serial.h"
-
-
-/*
- * This component encapsulates the TTY layer glue needed to provide basic
- * "serial port" functionality through the USB gadget stack. Each such
- * port is exposed through a /dev/ttyGS* node.
- *
- * After initialization (gserial_setup), these TTY port devices stay
- * available until they are removed (gserial_cleanup). Each one may be
- * connected to a USB function (gserial_connect), or disconnected (with
- * gserial_disconnect) when the USB host issues a config change event.
- * Data can only flow when the port is connected to the host.
- *
- * A given TTY port can be made available in multiple configurations.
- * For example, each one might expose a ttyGS0 node which provides a
- * login application. In one case that might use CDC ACM interface 0,
- * while another configuration might use interface 3 for that. The
- * work to handle that (including descriptor management) is not part
- * of this component.
- *
- * Configurations may expose more than one TTY port. For example, if
- * ttyGS0 provides login service, then ttyGS1 might provide dialer access
- * for a telephone or fax link. And ttyGS2 might be something that just
- * needs a simple byte stream interface for some messaging protocol that
- * is managed in userspace ... OBEX, PTP, and MTP have been mentioned.
- */
-
-#define PREFIX "ttyGS"
-
-/*
- * gserial is the lifecycle interface, used by USB functions
- * gs_port is the I/O nexus, used by the tty driver
- * tty_struct links to the tty/filesystem framework
- *
- * gserial <---> gs_port ... links will be null when the USB link is
- * inactive; managed by gserial_{connect,disconnect}(). each gserial
- * instance can wrap its own USB control protocol.
- * gserial->ioport == usb_ep->driver_data ... gs_port
- * gs_port->port_usb ... gserial
- *
- * gs_port <---> tty_struct ... links will be null when the TTY file
- * isn't opened; managed by gs_open()/gs_close()
- * gserial->port_tty ... tty_struct
- * tty_struct->driver_data ... gserial
- */
-
-/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the
- * next layer of buffering. For TX that's a circular buffer; for RX
- * consider it a NOP. A third layer is provided by the TTY code.
- */
-#define QUEUE_SIZE 16
-#define WRITE_BUF_SIZE 8192 /* TX only */
-
-/* circular buffer */
-struct gs_buf {
- unsigned buf_size;
- char *buf_buf;
- char *buf_get;
- char *buf_put;
-};
-
-/*
- * The port structure holds info for each port, one for each minor number
- * (and thus for each /dev/ node).
- */
-struct gs_port {
- struct tty_port port;
- spinlock_t port_lock; /* guard port_* access */
-
- struct gserial *port_usb;
-
- bool openclose; /* open/close in progress */
- u8 port_num;
-
- struct list_head read_pool;
- int read_started;
- int read_allocated;
- struct list_head read_queue;
- unsigned n_read;
- struct tasklet_struct push;
-
- struct list_head write_pool;
- int write_started;
- int write_allocated;
- struct gs_buf port_write_buf;
- wait_queue_head_t drain_wait; /* wait while writes drain */
-
- /* REVISIT this state ... */
- struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
-};
-
-/* increase N_PORTS if you need more */
-#define N_PORTS 4
-static struct portmaster {
- struct mutex lock; /* protect open/close */
- struct gs_port *port;
-} ports[N_PORTS];
-static unsigned n_ports;
-
-#define GS_CLOSE_TIMEOUT 15 /* seconds */
-
-
-
-#ifdef VERBOSE_DEBUG
-#define pr_vdebug(fmt, arg...) \
- pr_debug(fmt, ##arg)
-#else
-#define pr_vdebug(fmt, arg...) \
- ({ if (0) pr_debug(fmt, ##arg); })
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* Circular Buffer */
-
-/*
- * gs_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-static int gs_buf_alloc(struct gs_buf *gb, unsigned size)
-{
- gb->buf_buf = kmalloc(size, GFP_KERNEL);
- if (gb->buf_buf == NULL)
- return -ENOMEM;
-
- gb->buf_size = size;
- gb->buf_put = gb->buf_buf;
- gb->buf_get = gb->buf_buf;
-
- return 0;
-}
-
-/*
- * gs_buf_free
- *
- * Free the buffer and all associated memory.
- */
-static void gs_buf_free(struct gs_buf *gb)
-{
- kfree(gb->buf_buf);
- gb->buf_buf = NULL;
-}
-
-/*
- * gs_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-static void gs_buf_clear(struct gs_buf *gb)
-{
- gb->buf_get = gb->buf_put;
- /* equivalent to a get of all data available */
-}
-
-/*
- * gs_buf_data_avail
- *
- * Return the number of bytes of data written into the circular
- * buffer.
- */
-static unsigned gs_buf_data_avail(struct gs_buf *gb)
-{
- return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
-}
-
-/*
- * gs_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-static unsigned gs_buf_space_avail(struct gs_buf *gb)
-{
- return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
-}
-
-/*
- * gs_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-static unsigned
-gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count)
-{
- unsigned len;
-
- len = gs_buf_space_avail(gb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = gb->buf_buf + gb->buf_size - gb->buf_put;
- if (count > len) {
- memcpy(gb->buf_put, buf, len);
- memcpy(gb->buf_buf, buf+len, count - len);
- gb->buf_put = gb->buf_buf + count - len;
- } else {
- memcpy(gb->buf_put, buf, count);
- if (count < len)
- gb->buf_put += count;
- else /* count == len */
- gb->buf_put = gb->buf_buf;
- }
-
- return count;
-}
-
-/*
- * gs_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-static unsigned
-gs_buf_get(struct gs_buf *gb, char *buf, unsigned count)
-{
- unsigned len;
-
- len = gs_buf_data_avail(gb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = gb->buf_buf + gb->buf_size - gb->buf_get;
- if (count > len) {
- memcpy(buf, gb->buf_get, len);
- memcpy(buf+len, gb->buf_buf, count - len);
- gb->buf_get = gb->buf_buf + count - len;
- } else {
- memcpy(buf, gb->buf_get, count);
- if (count < len)
- gb->buf_get += count;
- else /* count == len */
- gb->buf_get = gb->buf_buf;
- }
-
- return count;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* I/O glue between TTY (upper) and USB function (lower) driver layers */
-
-/*
- * gs_alloc_req
- *
- * Allocate a usb_request and its buffer. Returns a pointer to the
- * usb_request or NULL if there is an error.
- */
-struct usb_request *
-gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags)
-{
- struct usb_request *req;
-
- req = usb_ep_alloc_request(ep, kmalloc_flags);
-
- if (req != NULL) {
- req->length = len;
- req->buf = kmalloc(len, kmalloc_flags);
- if (req->buf == NULL) {
- usb_ep_free_request(ep, req);
- return NULL;
- }
- }
-
- return req;
-}
-
-/*
- * gs_free_req
- *
- * Free a usb_request and its buffer.
- */
-void gs_free_req(struct usb_ep *ep, struct usb_request *req)
-{
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
-/*
- * gs_send_packet
- *
- * If there is data to send, a packet is built in the given
- * buffer and the size is returned. If there is no data to
- * send, 0 is returned.
- *
- * Called with port_lock held.
- */
-static unsigned
-gs_send_packet(struct gs_port *port, char *packet, unsigned size)
-{
- unsigned len;
-
- len = gs_buf_data_avail(&port->port_write_buf);
- if (len < size)
- size = len;
- if (size != 0)
- size = gs_buf_get(&port->port_write_buf, packet, size);
- return size;
-}
-
-/*
- * gs_start_tx
- *
- * This function finds available write requests, calls
- * gs_send_packet to fill these packets with data, and
- * continues until either there are no more write requests
- * available or no more data to send. This function is
- * run whenever data arrives or write requests are available.
- *
- * Context: caller owns port_lock; port_usb is non-null.
- */
-static int gs_start_tx(struct gs_port *port)
-/*
-__releases(&port->port_lock)
-__acquires(&port->port_lock)
-*/
-{
- struct list_head *pool = &port->write_pool;
- struct usb_ep *in = port->port_usb->in;
- int status = 0;
- bool do_tty_wake = false;
-
- while (!list_empty(pool)) {
- struct usb_request *req;
- int len;
-
- if (port->write_started >= QUEUE_SIZE)
- break;
-
- req = list_entry(pool->next, struct usb_request, list);
- len = gs_send_packet(port, req->buf, in->maxpacket);
- if (len == 0) {
- wake_up_interruptible(&port->drain_wait);
- break;
- }
- do_tty_wake = true;
-
- req->length = len;
- list_del(&req->list);
- req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
-
- pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
- port->port_num, len, *((u8 *)req->buf),
- *((u8 *)req->buf+1), *((u8 *)req->buf+2));
-
- /* Drop lock while we call out of driver; completions
- * could be issued while we do so. Disconnection may
- * happen too; maybe immediately before we queue this!
- *
- * NOTE that we may keep sending data for a while after
- * the TTY closed (dev->ioport->port_tty is NULL).
- */
- spin_unlock(&port->port_lock);
- status = usb_ep_queue(in, req, GFP_ATOMIC);
- spin_lock(&port->port_lock);
-
- if (status) {
- pr_debug("%s: %s %s err %d\n",
- __func__, "queue", in->name, status);
- list_add(&req->list, pool);
- break;
- }
-
- port->write_started++;
-
- /* abort immediately after disconnect */
- if (!port->port_usb)
- break;
- }
-
- if (do_tty_wake && port->port.tty)
- tty_wakeup(port->port.tty);
- return status;
-}
-
-/*
- * Context: caller owns port_lock, and port_usb is set
- */
-static unsigned gs_start_rx(struct gs_port *port)
-/*
-__releases(&port->port_lock)
-__acquires(&port->port_lock)
-*/
-{
- struct list_head *pool = &port->read_pool;
- struct usb_ep *out = port->port_usb->out;
-
- while (!list_empty(pool)) {
- struct usb_request *req;
- int status;
- struct tty_struct *tty;
-
- /* no more rx if closed */
- tty = port->port.tty;
- if (!tty)
- break;
-
- if (port->read_started >= QUEUE_SIZE)
- break;
-
- req = list_entry(pool->next, struct usb_request, list);
- list_del(&req->list);
- req->length = out->maxpacket;
-
- /* drop lock while we call out; the controller driver
- * may need to call us back (e.g. for disconnect)
- */
- spin_unlock(&port->port_lock);
- status = usb_ep_queue(out, req, GFP_ATOMIC);
- spin_lock(&port->port_lock);
-
- if (status) {
- pr_debug("%s: %s %s err %d\n",
- __func__, "queue", out->name, status);
- list_add(&req->list, pool);
- break;
- }
- port->read_started++;
-
- /* abort immediately after disconnect */
- if (!port->port_usb)
- break;
- }
- return port->read_started;
-}
-
-/*
- * RX tasklet takes data out of the RX queue and hands it up to the TTY
- * layer until it refuses to take any more data (or is throttled back).
- * Then it issues reads for any further data.
- *
- * If the RX queue becomes full enough that no usb_request is queued,
- * the OUT endpoint may begin NAKing as soon as its FIFO fills up.
- * So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
- * can be buffered before the TTY layer's buffers (currently 64 KB).
- */
-static void gs_rx_push(unsigned long _port)
-{
- struct gs_port *port = (void *)_port;
- struct tty_struct *tty;
- struct list_head *queue = &port->read_queue;
- bool disconnect = false;
- bool do_push = false;
-
- /* hand any queued data to the tty */
- spin_lock_irq(&port->port_lock);
- tty = port->port.tty;
- while (!list_empty(queue)) {
- struct usb_request *req;
-
- req = list_first_entry(queue, struct usb_request, list);
-
- /* leave data queued if tty was rx throttled */
- if (tty && test_bit(TTY_THROTTLED, &tty->flags))
- break;
-
- switch (req->status) {
- case -ESHUTDOWN:
- disconnect = true;
- pr_vdebug(PREFIX "%d: shutdown\n", port->port_num);
- break;
-
- default:
- /* presumably a transient fault */
- pr_warning(PREFIX "%d: unexpected RX status %d\n",
- port->port_num, req->status);
- /* FALLTHROUGH */
- case 0:
- /* normal completion */
- break;
- }
-
- /* push data to (open) tty */
- if (req->actual) {
- char *packet = req->buf;
- unsigned size = req->actual;
- unsigned n;
- int count;
-
- /* we may have pushed part of this packet already... */
- n = port->n_read;
- if (n) {
- packet += n;
- size -= n;
- }
-
- count = tty_insert_flip_string(&port->port, packet, size);
- if (count)
- do_push = true;
- if (count != size) {
- /* stop pushing; TTY layer can't handle more */
- port->n_read += count;
- pr_vdebug(PREFIX "%d: rx block %d/%d\n",
- port->port_num,
- count, req->actual);
- break;
- }
- port->n_read = 0;
- }
- list_move(&req->list, &port->read_pool);
- port->read_started--;
- }
-
- /* Push from tty to ldisc; without low_latency set this is handled by
- * a workqueue, so we won't get callbacks and can hold port_lock
- */
- if (do_push)
- tty_flip_buffer_push(&port->port);
-
-
- /* We want our data queue to become empty ASAP, keeping data
- * in the tty and ldisc (not here). If we couldn't push any
- * this time around, there may be trouble unless there's an
- * implicit tty_unthrottle() call on its way...
- *
- * REVISIT we should probably add a timer to keep the tasklet
- * from starving ... but it's not clear that case ever happens.
- */
- if (!list_empty(queue) && tty) {
- if (!test_bit(TTY_THROTTLED, &tty->flags)) {
- if (do_push)
- tasklet_schedule(&port->push);
- else
- pr_warning(PREFIX "%d: RX not scheduled?\n",
- port->port_num);
- }
- }
-
- /* If we're still connected, refill the USB RX queue. */
- if (!disconnect && port->port_usb)
- gs_start_rx(port);
-
- spin_unlock_irq(&port->port_lock);
-}
-
-static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct gs_port *port = ep->driver_data;
-
- /* Queue all received data until the tty layer is ready for it. */
- spin_lock(&port->port_lock);
- list_add_tail(&req->list, &port->read_queue);
- tasklet_schedule(&port->push);
- spin_unlock(&port->port_lock);
-}
-
-static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct gs_port *port = ep->driver_data;
-
- spin_lock(&port->port_lock);
- list_add(&req->list, &port->write_pool);
- port->write_started--;
-
- switch (req->status) {
- default:
- /* presumably a transient fault */
- pr_warning("%s: unexpected %s status %d\n",
- __func__, ep->name, req->status);
- /* FALL THROUGH */
- case 0:
- /* normal completion */
- gs_start_tx(port);
- break;
-
- case -ESHUTDOWN:
- /* disconnect */
- pr_vdebug("%s: %s shutdown\n", __func__, ep->name);
- break;
- }
-
- spin_unlock(&port->port_lock);
-}
-
-static void gs_free_requests(struct usb_ep *ep, struct list_head *head,
- int *allocated)
-{
- struct usb_request *req;
-
- while (!list_empty(head)) {
- req = list_entry(head->next, struct usb_request, list);
- list_del(&req->list);
- gs_free_req(ep, req);
- if (allocated)
- (*allocated)--;
- }
-}
-
-static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head,
- void (*fn)(struct usb_ep *, struct usb_request *),
- int *allocated)
-{
- int i;
- struct usb_request *req;
- int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE;
-
- /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't
- * do quite that many this time, don't fail ... we just won't
- * be as speedy as we might otherwise be.
- */
- for (i = 0; i < n; i++) {
- req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC);
- if (!req)
- return list_empty(head) ? -ENOMEM : 0;
- req->complete = fn;
- list_add_tail(&req->list, head);
- if (allocated)
- (*allocated)++;
- }
- return 0;
-}
-
-/**
- * gs_start_io - start USB I/O streams
- * @dev: encapsulates endpoints to use
- * Context: holding port_lock; port_tty and port_usb are non-null
- *
- * We only start I/O when something is connected to both sides of
- * this port. If nothing is listening on the host side, we may
- * be pointlessly filling up our TX buffers and FIFO.
- */
-static int gs_start_io(struct gs_port *port)
-{
- struct list_head *head = &port->read_pool;
- struct usb_ep *ep = port->port_usb->out;
- int status;
- unsigned started;
-
- /* Allocate RX and TX I/O buffers. We can't easily do this much
- * earlier (with GFP_KERNEL) because the requests are coupled to
- * endpoints, as are the packet sizes we'll be using. Different
- * configurations may use different endpoints with a given port;
- * and high speed vs full speed changes packet sizes too.
- */
- status = gs_alloc_requests(ep, head, gs_read_complete,
- &port->read_allocated);
- if (status)
- return status;
-
- status = gs_alloc_requests(port->port_usb->in, &port->write_pool,
- gs_write_complete, &port->write_allocated);
- if (status) {
- gs_free_requests(ep, head, &port->read_allocated);
- return status;
- }
-
- /* queue read requests */
- port->n_read = 0;
- started = gs_start_rx(port);
-
- /* unblock any pending writes into our circular buffer */
- if (started) {
- tty_wakeup(port->port.tty);
- } else {
- gs_free_requests(ep, head, &port->read_allocated);
- gs_free_requests(port->port_usb->in, &port->write_pool,
- &port->write_allocated);
- status = -EIO;
- }
-
- return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* TTY Driver */
-
-/*
- * gs_open sets up the link between a gs_port and its associated TTY.
- * That link is broken *only* by TTY close(), and all driver methods
- * know that.
- */
-static int gs_open(struct tty_struct *tty, struct file *file)
-{
- int port_num = tty->index;
- struct gs_port *port;
- int status;
-
- do {
- mutex_lock(&ports[port_num].lock);
- port = ports[port_num].port;
- if (!port)
- status = -ENODEV;
- else {
- spin_lock_irq(&port->port_lock);
-
- /* already open? Great. */
- if (port->port.count) {
- status = 0;
- port->port.count++;
-
- /* currently opening/closing? wait ... */
- } else if (port->openclose) {
- status = -EBUSY;
-
- /* ... else we do the work */
- } else {
- status = -EAGAIN;
- port->openclose = true;
- }
- spin_unlock_irq(&port->port_lock);
- }
- mutex_unlock(&ports[port_num].lock);
-
- switch (status) {
- default:
- /* fully handled */
- return status;
- case -EAGAIN:
- /* must do the work */
- break;
- case -EBUSY:
- /* wait for EAGAIN task to finish */
- msleep(1);
- /* REVISIT could have a waitchannel here, if
- * concurrent open performance is important
- */
- break;
- }
- } while (status != -EAGAIN);
-
- /* Do the "real open" */
- spin_lock_irq(&port->port_lock);
-
- /* allocate circular buffer on first open */
- if (port->port_write_buf.buf_buf == NULL) {
-
- spin_unlock_irq(&port->port_lock);
- status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE);
- spin_lock_irq(&port->port_lock);
-
- if (status) {
- pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n",
- port->port_num, tty, file);
- port->openclose = false;
- goto exit_unlock_port;
- }
- }
-
- /* REVISIT if REMOVED (ports[].port NULL), abort the open
- * to let rmmod work faster (but this way isn't wrong).
- */
-
- /* REVISIT maybe wait for "carrier detect" */
-
- tty->driver_data = port;
- port->port.tty = tty;
-
- port->port.count = 1;
- port->openclose = false;
-
- /* if connected, start the I/O stream */
- if (port->port_usb) {
- struct gserial *gser = port->port_usb;
-
- pr_debug("gs_open: start ttyGS%d\n", port->port_num);
- gs_start_io(port);
-
- if (gser->connect)
- gser->connect(gser);
- }
-
- pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
-
- status = 0;
-
-exit_unlock_port:
- spin_unlock_irq(&port->port_lock);
- return status;
-}
-
-static int gs_writes_finished(struct gs_port *p)
-{
- int cond;
-
- /* return true on disconnect or empty buffer */
- spin_lock_irq(&p->port_lock);
- cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf);
- spin_unlock_irq(&p->port_lock);
-
- return cond;
-}
-
-static void gs_close(struct tty_struct *tty, struct file *file)
-{
- struct gs_port *port = tty->driver_data;
- struct gserial *gser;
-
- spin_lock_irq(&port->port_lock);
-
- if (port->port.count != 1) {
- if (port->port.count == 0)
- WARN_ON(1);
- else
- --port->port.count;
- goto exit;
- }
-
- pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
-
- /* mark port as closing but in use; we can drop port lock
- * and sleep if necessary
- */
- port->openclose = true;
- port->port.count = 0;
-
- gser = port->port_usb;
- if (gser && gser->disconnect)
- gser->disconnect(gser);
-
- /* wait for circular write buffer to drain, disconnect, or at
- * most GS_CLOSE_TIMEOUT seconds; then discard the rest
- */
- if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) {
- spin_unlock_irq(&port->port_lock);
- wait_event_interruptible_timeout(port->drain_wait,
- gs_writes_finished(port),
- GS_CLOSE_TIMEOUT * HZ);
- spin_lock_irq(&port->port_lock);
- gser = port->port_usb;
- }
-
- /* Iff we're disconnected, there can be no I/O in flight so it's
- * ok to free the circular buffer; else just scrub it. And don't
- * let the push tasklet fire again until we're re-opened.
- */
- if (gser == NULL)
- gs_buf_free(&port->port_write_buf);
- else
- gs_buf_clear(&port->port_write_buf);
-
- tty->driver_data = NULL;
- port->port.tty = NULL;
-
- port->openclose = false;
-
- pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
- port->port_num, tty, file);
-
- wake_up_interruptible(&port->port.close_wait);
-exit:
- spin_unlock_irq(&port->port_lock);
-}
-
-static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
- int status;
-
- pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n",
- port->port_num, tty, count);
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (count)
- count = gs_buf_put(&port->port_write_buf, buf, count);
- /* treat count == 0 as flush_chars() */
- if (port->port_usb)
- status = gs_start_tx(port);
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- return count;
-}
-
-static int gs_put_char(struct tty_struct *tty, unsigned char ch)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
- int status;
-
- pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
- port->port_num, tty, ch, __builtin_return_address(0));
-
- spin_lock_irqsave(&port->port_lock, flags);
- status = gs_buf_put(&port->port_write_buf, &ch, 1);
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- return status;
-}
-
-static void gs_flush_chars(struct tty_struct *tty)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
-
- pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty);
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port_usb)
- gs_start_tx(port);
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
-
-static int gs_write_room(struct tty_struct *tty)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
- int room = 0;
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port_usb)
- room = gs_buf_space_avail(&port->port_write_buf);
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
- port->port_num, tty, room);
-
- return room;
-}
-
-static int gs_chars_in_buffer(struct tty_struct *tty)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
- int chars = 0;
-
- spin_lock_irqsave(&port->port_lock, flags);
- chars = gs_buf_data_avail(&port->port_write_buf);
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
- port->port_num, tty, chars);
-
- return chars;
-}
-
-/* undo side effects of setting TTY_THROTTLED */
-static void gs_unthrottle(struct tty_struct *tty)
-{
- struct gs_port *port = tty->driver_data;
- unsigned long flags;
-
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port_usb) {
- /* Kickstart read queue processing. We don't do xon/xoff,
- * rts/cts, or other handshaking with the host, but if the
- * read queue backs up enough we'll be NAKing OUT packets.
- */
- tasklet_schedule(&port->push);
- pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num);
- }
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
-
-static int gs_break_ctl(struct tty_struct *tty, int duration)
-{
- struct gs_port *port = tty->driver_data;
- int status = 0;
- struct gserial *gser;
-
- pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n",
- port->port_num, duration);
-
- spin_lock_irq(&port->port_lock);
- gser = port->port_usb;
- if (gser && gser->send_break)
- status = gser->send_break(gser, duration);
- spin_unlock_irq(&port->port_lock);
-
- return status;
-}
-
-static const struct tty_operations gs_tty_ops = {
- .open = gs_open,
- .close = gs_close,
- .write = gs_write,
- .put_char = gs_put_char,
- .flush_chars = gs_flush_chars,
- .write_room = gs_write_room,
- .chars_in_buffer = gs_chars_in_buffer,
- .unthrottle = gs_unthrottle,
- .break_ctl = gs_break_ctl,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static struct tty_driver *gs_tty_driver;
-
-static int
-gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
-{
- struct gs_port *port;
-
- port = kzalloc(sizeof(struct gs_port), GFP_KERNEL);
- if (port == NULL)
- return -ENOMEM;
-
- tty_port_init(&port->port);
- spin_lock_init(&port->port_lock);
- init_waitqueue_head(&port->drain_wait);
-
- tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
-
- INIT_LIST_HEAD(&port->read_pool);
- INIT_LIST_HEAD(&port->read_queue);
- INIT_LIST_HEAD(&port->write_pool);
-
- port->port_num = port_num;
- port->port_line_coding = *coding;
-
- ports[port_num].port = port;
-
- return 0;
-}
-
-/**
- * gserial_setup - initialize TTY driver for one or more ports
- * @g: gadget to associate with these ports
- * @count: how many ports to support
- * Context: may sleep
- *
- * The TTY stack needs to know in advance how many devices it should
- * plan to manage. Use this call to set up the ports you will be
- * exporting through USB. Later, connect them to functions based
- * on what configuration is activated by the USB host; and disconnect
- * them as appropriate.
- *
- * An example would be a two-configuration device in which both
- * configurations expose port 0, but through different functions.
- * One configuration could even expose port 1 while the other
- * one doesn't.
- *
- * Returns negative errno or zero.
- */
-int gserial_setup(struct usb_gadget *g, unsigned count)
-{
- unsigned i;
- struct usb_cdc_line_coding coding;
- int status;
-
- if (count == 0 || count > N_PORTS)
- return -EINVAL;
-
- gs_tty_driver = alloc_tty_driver(count);
- if (!gs_tty_driver)
- return -ENOMEM;
-
- gs_tty_driver->driver_name = "g_serial";
- gs_tty_driver->name = PREFIX;
- /* uses dynamically assigned dev_t values */
-
- gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- gs_tty_driver->init_termios = tty_std_termios;
-
- /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
- * MS-Windows. Otherwise, most of these flags shouldn't affect
- * anything unless we were to actually hook up to a serial line.
- */
- gs_tty_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- gs_tty_driver->init_termios.c_ispeed = 9600;
- gs_tty_driver->init_termios.c_ospeed = 9600;
-
- coding.dwDTERate = cpu_to_le32(9600);
- coding.bCharFormat = 8;
- coding.bParityType = USB_CDC_NO_PARITY;
- coding.bDataBits = USB_CDC_1_STOP_BITS;
-
- tty_set_operations(gs_tty_driver, &gs_tty_ops);
-
- /* make devices be openable */
- for (i = 0; i < count; i++) {
- mutex_init(&ports[i].lock);
- status = gs_port_alloc(i, &coding);
- if (status) {
- count = i;
- goto fail;
- }
- }
- n_ports = count;
-
- /* export the driver ... */
- status = tty_register_driver(gs_tty_driver);
- if (status) {
- pr_err("%s: cannot register, err %d\n",
- __func__, status);
- goto fail;
- }
-
- /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */
- for (i = 0; i < count; i++) {
- struct device *tty_dev;
-
- tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
- if (IS_ERR(tty_dev))
- pr_warning("%s: no classdev for port %d, err %ld\n",
- __func__, i, PTR_ERR(tty_dev));
- }
-
- pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
- count, (count == 1) ? "" : "s");
-
- return status;
-fail:
- while (count--) {
- tty_port_destroy(&ports[count].port->port);
- kfree(ports[count].port);
- }
- put_tty_driver(gs_tty_driver);
- gs_tty_driver = NULL;
- return status;
-}
-
-static int gs_closed(struct gs_port *port)
-{
- int cond;
-
- spin_lock_irq(&port->port_lock);
- cond = (port->port.count == 0) && !port->openclose;
- spin_unlock_irq(&port->port_lock);
- return cond;
-}
-
-/**
- * gserial_cleanup - remove TTY-over-USB driver and devices
- * Context: may sleep
- *
- * This is called to free all resources allocated by @gserial_setup().
- * Accordingly, it may need to wait until some open /dev/ files have
- * closed.
- *
- * The caller must have issued @gserial_disconnect() for any ports
- * that had previously been connected, so that there is never any
- * I/O pending when it's called.
- */
-void gserial_cleanup(void)
-{
- unsigned i;
- struct gs_port *port;
-
- if (!gs_tty_driver)
- return;
-
- /* start sysfs and /dev/ttyGS* node removal */
- for (i = 0; i < n_ports; i++)
- tty_unregister_device(gs_tty_driver, i);
-
- for (i = 0; i < n_ports; i++) {
- /* prevent new opens */
- mutex_lock(&ports[i].lock);
- port = ports[i].port;
- ports[i].port = NULL;
- mutex_unlock(&ports[i].lock);
-
- tasklet_kill(&port->push);
-
- /* wait for old opens to finish */
- wait_event(port->port.close_wait, gs_closed(port));
-
- WARN_ON(port->port_usb != NULL);
-
- tty_port_destroy(&port->port);
- kfree(port);
- }
- n_ports = 0;
-
- tty_unregister_driver(gs_tty_driver);
- put_tty_driver(gs_tty_driver);
- gs_tty_driver = NULL;
-
- pr_debug("%s: cleaned up ttyGS* support\n", __func__);
-}
-
-/**
- * gserial_connect - notify TTY I/O glue that USB link is active
- * @gser: the function, set up with endpoints and descriptors
- * @port_num: which port is active
- * Context: any (usually from irq)
- *
- * This is called activate endpoints and let the TTY layer know that
- * the connection is active ... not unlike "carrier detect". It won't
- * necessarily start I/O queues; unless the TTY is held open by any
- * task, there would be no point. However, the endpoints will be
- * activated so the USB host can perform I/O, subject to basic USB
- * hardware flow control.
- *
- * Caller needs to have set up the endpoints and USB function in @dev
- * before calling this, as well as the appropriate (speed-specific)
- * endpoint descriptors, and also have set up the TTY driver by calling
- * @gserial_setup().
- *
- * Returns negative errno or zero.
- * On success, ep->driver_data will be overwritten.
- */
-int gserial_connect(struct gserial *gser, u8 port_num)
-{
- struct gs_port *port;
- unsigned long flags;
- int status;
-
- if (!gs_tty_driver || port_num >= n_ports)
- return -ENXIO;
-
- /* we "know" gserial_cleanup() hasn't been called */
- port = ports[port_num].port;
-
- /* activate the endpoints */
- status = usb_ep_enable(gser->in);
- if (status < 0)
- return status;
- gser->in->driver_data = port;
-
- status = usb_ep_enable(gser->out);
- if (status < 0)
- goto fail_out;
- gser->out->driver_data = port;
-
- /* then tell the tty glue that I/O can work */
- spin_lock_irqsave(&port->port_lock, flags);
- gser->ioport = port;
- port->port_usb = gser;
-
- /* REVISIT unclear how best to handle this state...
- * we don't really couple it with the Linux TTY.
- */
- gser->port_line_coding = port->port_line_coding;
-
- /* REVISIT if waiting on "carrier detect", signal. */
-
- /* if it's already open, start I/O ... and notify the serial
- * protocol about open/close status (connect/disconnect).
- */
- if (port->port.count) {
- pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
- gs_start_io(port);
- if (gser->connect)
- gser->connect(gser);
- } else {
- if (gser->disconnect)
- gser->disconnect(gser);
- }
-
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- return status;
-
-fail_out:
- usb_ep_disable(gser->in);
- gser->in->driver_data = NULL;
- return status;
-}
-
-/**
- * gserial_disconnect - notify TTY I/O glue that USB link is inactive
- * @gser: the function, on which gserial_connect() was called
- * Context: any (usually from irq)
- *
- * This is called to deactivate endpoints and let the TTY layer know
- * that the connection went inactive ... not unlike "hangup".
- *
- * On return, the state is as if gserial_connect() had never been called;
- * there is no active USB I/O on these endpoints.
- */
-void gserial_disconnect(struct gserial *gser)
-{
- struct gs_port *port = gser->ioport;
- unsigned long flags;
-
- if (!port)
- return;
-
- /* tell the TTY glue not to do I/O here any more */
- spin_lock_irqsave(&port->port_lock, flags);
-
- /* REVISIT as above: how best to track this? */
- port->port_line_coding = gser->port_line_coding;
-
- port->port_usb = NULL;
- gser->ioport = NULL;
- if (port->port.count > 0 || port->openclose) {
- wake_up_interruptible(&port->drain_wait);
- if (port->port.tty)
- tty_hangup(port->port.tty);
- }
- spin_unlock_irqrestore(&port->port_lock, flags);
-
- /* disable endpoints, aborting down any active I/O */
- usb_ep_disable(gser->out);
- gser->out->driver_data = NULL;
-
- usb_ep_disable(gser->in);
- gser->in->driver_data = NULL;
-
- /* finally, free any unused/unusable I/O buffers */
- spin_lock_irqsave(&port->port_lock, flags);
- if (port->port.count == 0 && !port->openclose)
- gs_buf_free(&port->port_write_buf);
- gs_free_requests(gser->out, &port->read_pool, NULL);
- gs_free_requests(gser->out, &port->read_queue, NULL);
- gs_free_requests(gser->in, &port->write_pool, NULL);
-
- port->read_allocated = port->read_started =
- port->write_allocated = port->write_started = 0;
-
- spin_unlock_irqrestore(&port->port_lock, flags);
-}
diff --git a/drivers/staging/ccg/u_serial.h b/drivers/staging/ccg/u_serial.h
deleted file mode 100644
index 9b0fe6450fbf..000000000000
--- a/drivers/staging/ccg/u_serial.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * u_serial.h - interface to USB gadget "serial port"/TTY utilities
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * either version 2 of that License or (at your option) any later version.
- */
-
-#ifndef __U_SERIAL_H
-#define __U_SERIAL_H
-
-#include <linux/usb/composite.h>
-#include <linux/usb/cdc.h>
-
-/*
- * One non-multiplexed "serial" I/O port ... there can be several of these
- * on any given USB peripheral device, if it provides enough endpoints.
- *
- * The "u_serial" utility component exists to do one thing: manage TTY
- * style I/O using the USB peripheral endpoints listed here, including
- * hookups to sysfs and /dev for each logical "tty" device.
- *
- * REVISIT at least ACM could support tiocmget() if needed.
- *
- * REVISIT someday, allow multiplexing several TTYs over these endpoints.
- */
-struct gserial {
- struct usb_function func;
-
- /* port is managed by gserial_{connect,disconnect} */
- struct gs_port *ioport;
-
- struct usb_ep *in;
- struct usb_ep *out;
-
- /* REVISIT avoid this CDC-ACM support harder ... */
- struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
-
- /* notification callbacks */
- void (*connect)(struct gserial *p);
- void (*disconnect)(struct gserial *p);
- int (*send_break)(struct gserial *p, int duration);
-};
-
-/* utilities to allocate/free request and buffer */
-struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags);
-void gs_free_req(struct usb_ep *, struct usb_request *req);
-
-/* port setup/teardown is handled by gadget driver */
-int gserial_setup(struct usb_gadget *g, unsigned n_ports);
-void gserial_cleanup(void);
-
-/* connect/disconnect is handled by individual functions */
-int gserial_connect(struct gserial *, u8 port_num);
-void gserial_disconnect(struct gserial *);
-
-/* functions are bound to configurations by a config or gadget driver */
-int acm_bind_config(struct usb_configuration *c, u8 port_num);
-int gser_bind_config(struct usb_configuration *c, u8 port_num);
-int obex_bind_config(struct usb_configuration *c, u8 port_num);
-
-#endif /* __U_SERIAL_H */
diff --git a/drivers/staging/ccg/usbstring.c b/drivers/staging/ccg/usbstring.c
deleted file mode 100644
index 4d25b9009edf..000000000000
--- a/drivers/staging/ccg/usbstring.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2003 David Brownell
- *
- * 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.1 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/nls.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-
-/**
- * usb_gadget_get_string - fill out a string descriptor
- * @table: of c strings encoded using UTF-8
- * @id: string id, from low byte of wValue in get string descriptor
- * @buf: at least 256 bytes, must be 16-bit aligned
- *
- * Finds the UTF-8 string matching the ID, and converts it into a
- * string descriptor in utf16-le.
- * Returns length of descriptor (always even) or negative errno
- *
- * If your driver needs stings in multiple languages, you'll probably
- * "switch (wIndex) { ... }" in your ep0 string descriptor logic,
- * using this routine after choosing which set of UTF-8 strings to use.
- * Note that US-ASCII is a strict subset of UTF-8; any string bytes with
- * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1
- * characters (which are also widely used in C strings).
- */
-int
-usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
-{
- struct usb_string *s;
- int len;
-
- /* descriptor 0 has the language id */
- if (id == 0) {
- buf [0] = 4;
- buf [1] = USB_DT_STRING;
- buf [2] = (u8) table->language;
- buf [3] = (u8) (table->language >> 8);
- return 4;
- }
- for (s = table->strings; s && s->s; s++)
- if (s->id == id)
- break;
-
- /* unrecognized: stall. */
- if (!s || !s->s)
- return -EINVAL;
-
- /* string descriptors have length, tag, then UTF16-LE text */
- len = min ((size_t) 126, strlen (s->s));
- len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
- (wchar_t *) &buf[2], 126);
- if (len < 0)
- return -EINVAL;
- buf [0] = (len + 1) * 2;
- buf [1] = USB_DT_STRING;
- return buf [0];
-}
-
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 1967852eeb17..7871579bb83d 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -230,9 +230,9 @@ config COMEDI_AMPLC_PC236_ISA
config COMEDI_AMPLC_PC263_ISA
tristate "Amplicon PC263 relay board support"
- select COMEDI_AMPLC_PC263
---help---
- Enable support for Amplicon PC263 ISA relay board.
+ Enable support for Amplicon PC263 ISA relay board. This board has
+ 16 reed relay output channels.
To compile this driver as a module, choose M here: the module will be
called amplc_pc263.
@@ -484,6 +484,19 @@ config COMEDI_NI_ATMIO16D
To compile this driver as a module, choose M here: the module will be
called ni_atmio16d.
+config COMEDI_NI_LABPC_ISA
+ tristate "NI Lab-PC and compatibles ISA support"
+ select COMEDI_NI_LABPC
+ depends on VIRT_TO_BUS
+ ---help---
+ Enable support for National Instruments Lab-PC and compatibles
+ Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
+ Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has
+ not yet been added to the driver.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ni_labpc.
+
config COMEDI_PCMAD
tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support"
---help---
@@ -728,6 +741,16 @@ config COMEDI_ADV_PCI1723
To compile this driver as a module, choose M here: the module will be
called adv_pci1723.
+config COMEDI_ADV_PCI1724
+ tristate "Advantech PCI-1724U support"
+ ---help---
+ Enable support for Advantech PCI-1724U cards. These are 32-channel
+ analog output cards with voltage and current loop output ranges and
+ 14-bit resolution.
+
+ To compile this driver as a module, choose M here: the module will be
+ called adv_pci1724.
+
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8255
@@ -748,7 +771,7 @@ config COMEDI_AMPLC_DIO200_PCI
and PCIe296 DIO boards.
To compile this driver as a module, choose M here: the module will be
- called amplc_dio200.
+ called amplc_dio200_pci.
config COMEDI_AMPLC_PC236_PCI
tristate "Amplicon PCI236 DIO board support"
@@ -761,12 +784,12 @@ config COMEDI_AMPLC_PC236_PCI
config COMEDI_AMPLC_PC263_PCI
tristate "Amplicon PCI263 relay board support"
- select COMEDI_AMPLC_PC263
---help---
- Enable support for Amplicon PCI263 relay board.
+ Enable support for Amplicon PCI263 relay board. This is a PCI board
+ with 16 reed relay output channels.
To compile this driver as a module, choose M here: the module will be
- called amplc_pc263.
+ called amplc_pci263.
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
@@ -983,7 +1006,7 @@ config COMEDI_NI_660X
select COMEDI_NI_TIOCMD
---help---
Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
- PXI-6602 and PXI-6608.
+ PXI-6602, PXI-6608 and PXI-6624.
To compile this driver as a module, choose M here: the module will be
called ni_660x.
@@ -997,20 +1020,15 @@ config COMEDI_NI_670X
To compile this driver as a module, choose M here: the module will be
called ni_670x.
-config COMEDI_NI_LABPC
- tristate "NI Lab-PC and compatibles ISA and PCI support"
+config COMEDI_NI_LABPC_PCI
+ tristate "NI Lab-PC PCI-1200 support"
+ select COMEDI_NI_LABPC
select COMEDI_MITE
- select COMEDI_8255
- select COMEDI_FC
- depends on VIRT_TO_BUS
---help---
- Enable support for National Instruments Lab-PC and compatibles
- Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
- Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has
- not yet been added to the driver.
+ Enable support for National Instruments Lab-PC PCI-1200.
To compile this driver as a module, choose M here: the module will be
- called ni_labpc.
+ called ni_labpc_pci.
config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support"
@@ -1132,7 +1150,7 @@ config COMEDI_NI_DAQ_DIO24_CS
config COMEDI_NI_LABPC_CS
tristate "NI DAQCard-1200 PCMCIA support"
- depends on COMEDI_NI_LABPC
+ select COMEDI_NI_LABPC
---help---
Enable support for the National Instruments PCMCIA DAQCard-1200
@@ -1241,12 +1259,14 @@ config COMEDI_AMPLC_PC236
tristate
select COMEDI_8255
-config COMEDI_AMPLC_PC263
+config COMEDI_DAS08
tristate
+ select COMEDI_8255
-config COMEDI_DAS08
+config COMEDI_NI_LABPC
tristate
select COMEDI_8255
+ select COMEDI_FC
config COMEDI_NI_TIO
tristate
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index 9b997ae67796..ca709901fb3e 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -192,7 +192,7 @@ unsigned int comedi_buf_write_alloc(struct comedi_async *async,
{
return __comedi_buf_write_alloc(async, nbytes, 0);
}
-EXPORT_SYMBOL(comedi_buf_write_alloc);
+EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
/*
* munging is applied to data by core as it passes between user
@@ -263,7 +263,7 @@ unsigned int comedi_buf_write_free(struct comedi_async *async,
return nbytes;
}
-EXPORT_SYMBOL(comedi_buf_write_free);
+EXPORT_SYMBOL_GPL(comedi_buf_write_free);
unsigned int comedi_buf_read_n_available(struct comedi_async *async)
{
@@ -282,7 +282,7 @@ unsigned int comedi_buf_read_n_available(struct comedi_async *async)
return num_bytes;
}
-EXPORT_SYMBOL(comedi_buf_read_n_available);
+EXPORT_SYMBOL_GPL(comedi_buf_read_n_available);
/* allocates a chunk for the reader from filled (and munged) buffer space */
unsigned int comedi_buf_read_alloc(struct comedi_async *async,
@@ -304,7 +304,7 @@ unsigned int comedi_buf_read_alloc(struct comedi_async *async,
return nbytes;
}
-EXPORT_SYMBOL(comedi_buf_read_alloc);
+EXPORT_SYMBOL_GPL(comedi_buf_read_alloc);
static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async)
{
@@ -332,7 +332,7 @@ unsigned int comedi_buf_read_free(struct comedi_async *async,
async->buf_read_ptr %= async->prealloc_bufsz;
return nbytes;
}
-EXPORT_SYMBOL(comedi_buf_read_free);
+EXPORT_SYMBOL_GPL(comedi_buf_read_free);
int comedi_buf_put(struct comedi_async *async, short x)
{
@@ -346,7 +346,7 @@ int comedi_buf_put(struct comedi_async *async, short x)
comedi_buf_write_free(async, sizeof(short));
return 1;
}
-EXPORT_SYMBOL(comedi_buf_put);
+EXPORT_SYMBOL_GPL(comedi_buf_put);
int comedi_buf_get(struct comedi_async *async, short *x)
{
@@ -359,7 +359,7 @@ int comedi_buf_get(struct comedi_async *async, short *x)
comedi_buf_read_free(async, sizeof(short));
return 1;
}
-EXPORT_SYMBOL(comedi_buf_get);
+EXPORT_SYMBOL_GPL(comedi_buf_get);
void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
const void *data, unsigned int num_bytes)
@@ -385,7 +385,7 @@ void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset,
write_ptr = 0;
}
}
-EXPORT_SYMBOL(comedi_buf_memcpy_to);
+EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to);
void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
void *dest, unsigned int nbytes)
@@ -412,4 +412,4 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
read_ptr = 0;
}
}
-EXPORT_SYMBOL(comedi_buf_memcpy_from);
+EXPORT_SYMBOL_GPL(comedi_buf_memcpy_from);
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index e336b281b847..00f2547024ec 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -49,9 +49,13 @@
#include "comedi_internal.h"
+#define COMEDI_NUM_MINORS 0x100
+#define COMEDI_NUM_SUBDEVICE_MINORS \
+ (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS)
+
#ifdef CONFIG_COMEDI_DEBUG
int comedi_debug;
-EXPORT_SYMBOL(comedi_debug);
+EXPORT_SYMBOL_GPL(comedi_debug);
module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(comedi_debug,
"enable comedi core and driver debugging if non-zero (default 0)"
@@ -77,57 +81,151 @@ MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
"default maximum size of asynchronous buffer in KiB (default "
__MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
-struct comedi_file_info {
- struct comedi_device *device;
- struct comedi_subdevice *read_subdevice;
- struct comedi_subdevice *write_subdevice;
- struct device *hardware_device;
-};
+static DEFINE_MUTEX(comedi_board_minor_table_lock);
+static struct comedi_device
+*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS];
+
+static DEFINE_MUTEX(comedi_subdevice_minor_table_lock);
+/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */
+static struct comedi_subdevice
+*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS];
+
+static struct class *comedi_class;
+static struct cdev comedi_cdev;
+
+static void comedi_device_init(struct comedi_device *dev)
+{
+ spin_lock_init(&dev->spinlock);
+ mutex_init(&dev->mutex);
+ dev->minor = -1;
+}
+
+static void comedi_device_cleanup(struct comedi_device *dev)
+{
+ struct module *driver_module = NULL;
+
+ if (dev == NULL)
+ return;
+ mutex_lock(&dev->mutex);
+ if (dev->attached)
+ driver_module = dev->driver->module;
+ comedi_device_detach(dev);
+ while (dev->use_count > 0) {
+ if (driver_module)
+ module_put(driver_module);
+ module_put(THIS_MODULE);
+ dev->use_count--;
+ }
+ mutex_unlock(&dev->mutex);
+ mutex_destroy(&dev->mutex);
+}
+
+static bool comedi_clear_board_dev(struct comedi_device *dev)
+{
+ unsigned int i = dev->minor;
+ bool cleared = false;
+
+ mutex_lock(&comedi_board_minor_table_lock);
+ if (dev == comedi_board_minor_table[i]) {
+ comedi_board_minor_table[i] = NULL;
+ cleared = true;
+ }
+ mutex_unlock(&comedi_board_minor_table_lock);
+ return cleared;
+}
+
+static struct comedi_device *comedi_clear_board_minor(unsigned minor)
+{
+ struct comedi_device *dev;
+
+ mutex_lock(&comedi_board_minor_table_lock);
+ dev = comedi_board_minor_table[minor];
+ comedi_board_minor_table[minor] = NULL;
+ mutex_unlock(&comedi_board_minor_table_lock);
+ return dev;
+}
+
+static void comedi_free_board_dev(struct comedi_device *dev)
+{
+ if (dev) {
+ if (dev->class_dev) {
+ device_destroy(comedi_class,
+ MKDEV(COMEDI_MAJOR, dev->minor));
+ }
+ comedi_device_cleanup(dev);
+ kfree(dev);
+ }
+}
-static DEFINE_SPINLOCK(comedi_file_info_table_lock);
-static struct comedi_file_info *comedi_file_info_table[COMEDI_NUM_MINORS];
+static struct comedi_subdevice
+*comedi_subdevice_from_minor(unsigned minor)
+{
+ struct comedi_subdevice *s;
+ unsigned int i = minor - COMEDI_NUM_BOARD_MINORS;
+
+ BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS);
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ s = comedi_subdevice_minor_table[i];
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
+ return s;
+}
-static struct comedi_file_info *comedi_file_info_from_minor(unsigned minor)
+static struct comedi_device *comedi_dev_from_board_minor(unsigned minor)
{
- struct comedi_file_info *info;
+ struct comedi_device *dev;
- BUG_ON(minor >= COMEDI_NUM_MINORS);
- spin_lock(&comedi_file_info_table_lock);
- info = comedi_file_info_table[minor];
- spin_unlock(&comedi_file_info_table_lock);
- return info;
+ BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+ mutex_lock(&comedi_board_minor_table_lock);
+ dev = comedi_board_minor_table[minor];
+ mutex_unlock(&comedi_board_minor_table_lock);
+ return dev;
}
-static struct comedi_device *
-comedi_dev_from_file_info(struct comedi_file_info *info)
+static struct comedi_device *comedi_dev_from_subdevice_minor(unsigned minor)
{
- return info ? info->device : NULL;
+ struct comedi_subdevice *s;
+
+ s = comedi_subdevice_from_minor(minor);
+ return s ? s->device : NULL;
}
struct comedi_device *comedi_dev_from_minor(unsigned minor)
{
- return comedi_dev_from_file_info(comedi_file_info_from_minor(minor));
+ if (minor < COMEDI_NUM_BOARD_MINORS)
+ return comedi_dev_from_board_minor(minor);
+ else
+ return comedi_dev_from_subdevice_minor(minor);
}
EXPORT_SYMBOL_GPL(comedi_dev_from_minor);
static struct comedi_subdevice *
-comedi_read_subdevice(const struct comedi_file_info *info)
+comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor)
{
- if (info->read_subdevice)
- return info->read_subdevice;
- if (info->device)
- return info->device->read_subdev;
- return NULL;
+ struct comedi_subdevice *s;
+
+ if (minor >= COMEDI_NUM_BOARD_MINORS) {
+ s = comedi_subdevice_from_minor(minor);
+ if (!s || s->device != dev)
+ return NULL;
+ if (s->subdev_flags & SDF_CMD_READ)
+ return s;
+ }
+ return dev->read_subdev;
}
static struct comedi_subdevice *
-comedi_write_subdevice(const struct comedi_file_info *info)
+comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor)
{
- if (info->write_subdevice)
- return info->write_subdevice;
- if (info->device)
- return info->device->write_subdev;
- return NULL;
+ struct comedi_subdevice *s;
+
+ if (minor >= COMEDI_NUM_BOARD_MINORS) {
+ s = comedi_subdevice_from_minor(minor);
+ if (!s || s->device != dev)
+ return NULL;
+ if (s->subdev_flags & SDF_CMD_WRITE)
+ return s;
+ }
+ return dev->write_subdev;
}
static int resize_async_buffer(struct comedi_device *dev,
@@ -172,27 +270,34 @@ static int resize_async_buffer(struct comedi_device *dev,
/* sysfs attribute files */
-static ssize_t show_max_read_buffer_kb(struct device *dev,
+static ssize_t show_max_read_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
size = s->async->max_bufsize / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_read_buffer_kb(struct device *dev,
+static ssize_t store_max_read_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
@@ -203,37 +308,49 @@ static ssize_t store_max_read_buffer_kb(struct device *dev,
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
s->async->max_bufsize = size;
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_read_buffer_kb(struct device *dev,
+static ssize_t show_read_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
size = s->async->prealloc_bufsz / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_read_buffer_kb(struct device *dev,
+static ssize_t store_read_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_read_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
@@ -244,38 +361,50 @@ static ssize_t store_read_buffer_kb(struct device *dev,
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_read_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_READ) && s->async)
- err = resize_async_buffer(info->device, s, s->async, size);
+ err = resize_async_buffer(dev, s, s->async, size);
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_max_write_buffer_kb(struct device *dev,
+static ssize_t show_max_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
size = s->async->max_bufsize / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_max_write_buffer_kb(struct device *dev,
+static ssize_t store_max_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
@@ -286,37 +415,49 @@ static ssize_t store_max_write_buffer_kb(struct device *dev,
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
s->async->max_bufsize = size;
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
-static ssize_t show_write_buffer_kb(struct device *dev,
+static ssize_t show_write_buffer_kb(struct device *csdev,
struct device_attribute *attr, char *buf)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size = 0;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
size = s->async->prealloc_bufsz / 1024;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return snprintf(buf, PAGE_SIZE, "%i\n", size);
}
-static ssize_t store_write_buffer_kb(struct device *dev,
+static ssize_t store_write_buffer_kb(struct device *csdev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct comedi_file_info *info = dev_get_drvdata(dev);
- struct comedi_subdevice *s = comedi_write_subdevice(info);
+ unsigned int minor = MINOR(csdev->devt);
+ struct comedi_device *dev;
+ struct comedi_subdevice *s;
unsigned int size;
int err;
@@ -327,12 +468,17 @@ static ssize_t store_write_buffer_kb(struct device *dev,
return -EINVAL;
size *= 1024;
- mutex_lock(&info->device->mutex);
+ dev = comedi_dev_from_minor(minor);
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
+ s = comedi_write_subdevice(dev, minor);
if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async)
- err = resize_async_buffer(info->device, s, s->async, size);
+ err = resize_async_buffer(dev, s, s->async, size);
else
err = -EINVAL;
- mutex_unlock(&info->device->mutex);
+ mutex_unlock(&dev->mutex);
return err ? err : count;
}
@@ -463,7 +609,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
struct comedi_devconfig __user *arg)
{
struct comedi_devconfig it;
- int ret;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -490,15 +635,12 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
return -EINVAL;
}
- ret = comedi_device_attach(dev, &it);
- if (ret == 0) {
- if (!try_module_get(dev->driver->module)) {
- comedi_device_detach(dev);
- ret = -ENOSYS;
- }
- }
+ if (dev->minor >= comedi_num_legacy_minors)
+ /* don't re-use dynamically allocated comedi devices */
+ return -EBUSY;
- return ret;
+ /* This increments the driver module count on success. */
+ return comedi_device_attach(dev, &it);
}
/*
@@ -581,7 +723,6 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
struct file *file)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
struct comedi_subdevice *s;
struct comedi_devinfo devinfo;
@@ -593,13 +734,13 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN);
strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN);
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (s)
devinfo.read_subdevice = s->index;
else
devinfo.read_subdevice = -1;
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (s)
devinfo.write_subdevice = s->index;
else
@@ -1616,8 +1757,7 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
int rc;
if (!dev)
@@ -1635,9 +1775,18 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
}
rc = do_devconfig_ioctl(dev,
(struct comedi_devconfig __user *)arg);
- if (rc == 0)
- /* Evade comedi_auto_unconfig(). */
- info->hardware_device = NULL;
+ if (rc == 0) {
+ if (arg == 0 &&
+ dev->minor >= comedi_num_legacy_minors) {
+ /* Successfully unconfigured a dynamically
+ * allocated device. Try and remove it. */
+ if (comedi_clear_board_dev(dev)) {
+ mutex_unlock(&dev->mutex);
+ comedi_free_board_dev(dev);
+ return rc;
+ }
+ }
+ }
goto done;
}
@@ -1744,8 +1893,7 @@ static struct vm_operations_struct comedi_vm_ops = {
static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
{
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
struct comedi_subdevice *s;
struct comedi_async *async;
unsigned long start = vma->vm_start;
@@ -1766,9 +1914,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma)
}
if (vma->vm_flags & VM_WRITE)
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
else
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (!s) {
retval = -EINVAL;
goto done;
@@ -1824,8 +1972,7 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
struct comedi_subdevice *s;
if (!dev)
@@ -1838,7 +1985,7 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
goto done;
}
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (s && s->async) {
poll_wait(file, &s->async->wait_head, wait);
if (!s->busy || !comedi_is_subdevice_running(s) ||
@@ -1846,7 +1993,7 @@ static unsigned int comedi_poll(struct file *file, poll_table *wait)
mask |= POLLIN | POLLRDNORM;
}
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (s && s->async) {
unsigned int bps = bytes_per_sample(s->async->subdevice);
@@ -1870,8 +2017,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -1881,7 +2027,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
return -ENODEV;
}
- s = comedi_write_subdevice(info);
+ s = comedi_write_subdevice(dev, minor);
if (!s || !s->async)
return -EIO;
@@ -1965,8 +2111,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
int n, m, count = 0, retval = 0;
DECLARE_WAITQUEUE(wait, current);
const unsigned minor = iminor(file_inode(file));
- struct comedi_file_info *info = comedi_file_info_from_minor(minor);
- struct comedi_device *dev = comedi_dev_from_file_info(info);
+ struct comedi_device *dev = comedi_dev_from_minor(minor);
if (!dev)
return -ENODEV;
@@ -1976,7 +2121,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
return -ENODEV;
}
- s = comedi_read_subdevice(info);
+ s = comedi_read_subdevice(dev, minor);
if (!s || !s->async)
return -EIO;
@@ -2067,12 +2212,12 @@ static int comedi_open(struct inode *inode, struct file *file)
/* This is slightly hacky, but we want module autoloading
* to work for root.
* case: user opens device, attached -> ok
- * case: user opens device, unattached, in_request_module=0 -> autoload
- * case: user opens device, unattached, in_request_module=1 -> fail
+ * case: user opens device, unattached, !in_request_module -> autoload
+ * case: user opens device, unattached, in_request_module -> fail
* case: root opens device, attached -> ok
- * case: root opens device, unattached, in_request_module=1 -> ok
+ * case: root opens device, unattached, in_request_module -> ok
* (typically called from modprobe)
- * case: root opens device, unattached, in_request_module=0 -> autoload
+ * case: root opens device, unattached, !in_request_module -> autoload
*
* The last could be changed to "-> ok", which would deny root
* autoloading.
@@ -2088,7 +2233,7 @@ static int comedi_open(struct inode *inode, struct file *file)
if (capable(CAP_NET_ADMIN) && dev->in_request_module)
goto ok;
- dev->in_request_module = 1;
+ dev->in_request_module = true;
#ifdef CONFIG_KMOD
mutex_unlock(&dev->mutex);
@@ -2096,7 +2241,7 @@ static int comedi_open(struct inode *inode, struct file *file)
mutex_lock(&dev->mutex);
#endif
- dev->in_request_module = 0;
+ dev->in_request_module = false;
if (!dev->attached && !capable(CAP_NET_ADMIN)) {
DPRINTK("not attached and not CAP_NET_ADMIN\n");
@@ -2195,14 +2340,11 @@ static const struct file_operations comedi_fops = {
.llseek = noop_llseek,
};
-static struct class *comedi_class;
-static struct cdev comedi_cdev;
-
void comedi_error(const struct comedi_device *dev, const char *s)
{
dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
}
-EXPORT_SYMBOL(comedi_error);
+EXPORT_SYMBOL_GPL(comedi_error);
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
@@ -2245,150 +2387,104 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
}
s->async->events = 0;
}
-EXPORT_SYMBOL(comedi_event);
-
-static void comedi_device_init(struct comedi_device *dev)
-{
- memset(dev, 0, sizeof(*dev));
- spin_lock_init(&dev->spinlock);
- mutex_init(&dev->mutex);
- dev->minor = -1;
-}
-
-static void comedi_device_cleanup(struct comedi_device *dev)
-{
- if (dev == NULL)
- return;
- mutex_lock(&dev->mutex);
- comedi_device_detach(dev);
- mutex_unlock(&dev->mutex);
- mutex_destroy(&dev->mutex);
-}
+EXPORT_SYMBOL_GPL(comedi_event);
-int comedi_alloc_board_minor(struct device *hardware_device)
+/* Note: the ->mutex is pre-locked on successful return */
+struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device)
{
- struct comedi_file_info *info;
+ struct comedi_device *dev;
struct device *csdev;
unsigned i;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (info == NULL)
- return -ENOMEM;
- info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
- if (info->device == NULL) {
- kfree(info);
- return -ENOMEM;
- }
- info->hardware_device = hardware_device;
- comedi_device_init(info->device);
- spin_lock(&comedi_file_info_table_lock);
- for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
- if (comedi_file_info_table[i] == NULL) {
- comedi_file_info_table[i] = info;
+ dev = kzalloc(sizeof(struct comedi_device), GFP_KERNEL);
+ if (dev == NULL)
+ return ERR_PTR(-ENOMEM);
+ comedi_device_init(dev);
+ comedi_set_hw_dev(dev, hardware_device);
+ mutex_lock(&dev->mutex);
+ mutex_lock(&comedi_board_minor_table_lock);
+ for (i = hardware_device ? comedi_num_legacy_minors : 0;
+ i < COMEDI_NUM_BOARD_MINORS; ++i) {
+ if (comedi_board_minor_table[i] == NULL) {
+ comedi_board_minor_table[i] = dev;
break;
}
}
- spin_unlock(&comedi_file_info_table_lock);
+ mutex_unlock(&comedi_board_minor_table_lock);
if (i == COMEDI_NUM_BOARD_MINORS) {
- comedi_device_cleanup(info->device);
- kfree(info->device);
- kfree(info);
+ mutex_unlock(&dev->mutex);
+ comedi_device_cleanup(dev);
+ kfree(dev);
pr_err("comedi: error: ran out of minor numbers for board device files.\n");
- return -EBUSY;
+ return ERR_PTR(-EBUSY);
}
- info->device->minor = i;
+ dev->minor = i;
csdev = device_create(comedi_class, hardware_device,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i);
if (!IS_ERR(csdev))
- info->device->class_dev = csdev;
- dev_set_drvdata(csdev, info);
+ dev->class_dev = csdev;
- return i;
+ /* Note: dev->mutex needs to be unlocked by the caller. */
+ return dev;
}
-void comedi_free_board_minor(unsigned minor)
+static void comedi_free_board_minor(unsigned minor)
{
- struct comedi_file_info *info;
-
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
- spin_lock(&comedi_file_info_table_lock);
- info = comedi_file_info_table[minor];
- comedi_file_info_table[minor] = NULL;
- spin_unlock(&comedi_file_info_table_lock);
-
- if (info) {
- struct comedi_device *dev = info->device;
- if (dev) {
- if (dev->class_dev) {
- device_destroy(comedi_class,
- MKDEV(COMEDI_MAJOR, dev->minor));
- }
- comedi_device_cleanup(dev);
- kfree(dev);
- }
- kfree(info);
- }
+ comedi_free_board_dev(comedi_clear_board_minor(minor));
}
-int comedi_find_board_minor(struct device *hardware_device)
+void comedi_release_hardware_device(struct device *hardware_device)
{
int minor;
- struct comedi_file_info *info;
-
- for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
- spin_lock(&comedi_file_info_table_lock);
- info = comedi_file_info_table[minor];
- if (info && info->hardware_device == hardware_device) {
- spin_unlock(&comedi_file_info_table_lock);
- return minor;
+ struct comedi_device *dev;
+
+ for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS;
+ minor++) {
+ mutex_lock(&comedi_board_minor_table_lock);
+ dev = comedi_board_minor_table[minor];
+ if (dev && dev->hw_dev == hardware_device) {
+ comedi_board_minor_table[minor] = NULL;
+ mutex_unlock(&comedi_board_minor_table_lock);
+ comedi_free_board_dev(dev);
+ break;
}
- spin_unlock(&comedi_file_info_table_lock);
+ mutex_unlock(&comedi_board_minor_table_lock);
}
- return -ENODEV;
}
int comedi_alloc_subdevice_minor(struct comedi_subdevice *s)
{
struct comedi_device *dev = s->device;
- struct comedi_file_info *info;
struct device *csdev;
unsigned i;
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- info->device = dev;
- if (s->subdev_flags & SDF_CMD_READ)
- info->read_subdevice = s;
- if (s->subdev_flags & SDF_CMD_WRITE)
- info->write_subdevice = s;
- spin_lock(&comedi_file_info_table_lock);
- for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
- if (comedi_file_info_table[i] == NULL) {
- comedi_file_info_table[i] = info;
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) {
+ if (comedi_subdevice_minor_table[i] == NULL) {
+ comedi_subdevice_minor_table[i] = s;
break;
}
}
- spin_unlock(&comedi_file_info_table_lock);
- if (i == COMEDI_NUM_MINORS) {
- kfree(info);
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
+ if (i == COMEDI_NUM_SUBDEVICE_MINORS) {
pr_err("comedi: error: ran out of minor numbers for subdevice files.\n");
return -EBUSY;
}
+ i += COMEDI_NUM_BOARD_MINORS;
s->minor = i;
csdev = device_create(comedi_class, dev->class_dev,
MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i",
dev->minor, s->index);
if (!IS_ERR(csdev))
s->class_dev = csdev;
- dev_set_drvdata(csdev, info);
return 0;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
- struct comedi_file_info *info;
+ unsigned int i;
if (s == NULL)
return;
@@ -2396,18 +2492,17 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
return;
BUG_ON(s->minor >= COMEDI_NUM_MINORS);
- BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
-
- spin_lock(&comedi_file_info_table_lock);
- info = comedi_file_info_table[s->minor];
- comedi_file_info_table[s->minor] = NULL;
- spin_unlock(&comedi_file_info_table_lock);
+ BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS);
+ i = s->minor - COMEDI_NUM_BOARD_MINORS;
+ mutex_lock(&comedi_subdevice_minor_table_lock);
+ if (s == comedi_subdevice_minor_table[i])
+ comedi_subdevice_minor_table[i] = NULL;
+ mutex_unlock(&comedi_subdevice_minor_table_lock);
if (s->class_dev) {
device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
s->class_dev = NULL;
}
- kfree(info);
}
static void comedi_cleanup_board_minors(void)
@@ -2432,9 +2527,6 @@ static int __init comedi_init(void)
return -EINVAL;
}
- memset(comedi_file_info_table, 0,
- sizeof(struct comedi_file_info *) * COMEDI_NUM_MINORS);
-
retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
COMEDI_NUM_MINORS, "comedi");
if (retval)
@@ -2463,14 +2555,17 @@ static int __init comedi_init(void)
/* create devices files for legacy/manual use */
for (i = 0; i < comedi_num_legacy_minors; i++) {
- int minor;
- minor = comedi_alloc_board_minor(NULL);
- if (minor < 0) {
+ struct comedi_device *dev;
+ dev = comedi_alloc_board_minor(NULL);
+ if (IS_ERR(dev)) {
comedi_cleanup_board_minors();
cdev_del(&comedi_cdev);
unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
COMEDI_NUM_MINORS);
- return minor;
+ return PTR_ERR(dev);
+ } else {
+ /* comedi_alloc_board_minor() locked the mutex */
+ mutex_unlock(&dev->mutex);
}
}
@@ -2483,8 +2578,10 @@ static void __exit comedi_cleanup(void)
int i;
comedi_cleanup_board_minors();
- for (i = 0; i < COMEDI_NUM_MINORS; ++i)
- BUG_ON(comedi_file_info_table[i]);
+ for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i)
+ BUG_ON(comedi_board_minor_table[i]);
+ for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i)
+ BUG_ON(comedi_subdevice_minor_table[i]);
class_destroy(comedi_class);
cdev_del(&comedi_cdev);
diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h
index b3743135f4aa..d5e03e558b35 100644
--- a/drivers/staging/comedi/comedi_internal.h
+++ b/drivers/staging/comedi/comedi_internal.h
@@ -8,9 +8,8 @@
*/
int do_rangeinfo_ioctl(struct comedi_device *dev,
struct comedi_rangeinfo __user *arg);
-int comedi_alloc_board_minor(struct device *hardware_device);
-void comedi_free_board_minor(unsigned minor);
-int comedi_find_board_minor(struct device *hardware_device);
+struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device);
+void comedi_release_hardware_device(struct device *hardware_device);
int comedi_alloc_subdevice_minor(struct comedi_subdevice *s);
void comedi_free_subdevice_minor(struct comedi_subdevice *s);
diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c
index 37d2e4677360..5fad084cfbd4 100644
--- a/drivers/staging/comedi/comedi_pci.c
+++ b/drivers/staging/comedi/comedi_pci.c
@@ -36,20 +36,25 @@ EXPORT_SYMBOL_GPL(comedi_to_pci_dev);
/**
* comedi_pci_enable() - Enable the PCI device and request the regions.
- * @pcidev: pci_dev struct
- * @res_name: name for the requested reqource
+ * @dev: comedi_device struct
*/
-int comedi_pci_enable(struct pci_dev *pcidev, const char *res_name)
+int comedi_pci_enable(struct comedi_device *dev)
{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
int rc;
+ if (!pcidev)
+ return -ENODEV;
+
rc = pci_enable_device(pcidev);
if (rc < 0)
return rc;
- rc = pci_request_regions(pcidev, res_name);
+ rc = pci_request_regions(pcidev, dev->board_name);
if (rc < 0)
pci_disable_device(pcidev);
+ else
+ dev->ioenabled = true;
return rc;
}
@@ -57,14 +62,17 @@ EXPORT_SYMBOL_GPL(comedi_pci_enable);
/**
* comedi_pci_disable() - Release the regions and disable the PCI device.
- * @pcidev: pci_dev struct
- *
- * This must be matched with a previous successful call to comedi_pci_enable().
+ * @dev: comedi_device struct
*/
-void comedi_pci_disable(struct pci_dev *pcidev)
+void comedi_pci_disable(struct comedi_device *dev)
{
- pci_release_regions(pcidev);
- pci_disable_device(pcidev);
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+ if (pcidev && dev->ioenabled) {
+ pci_release_regions(pcidev);
+ pci_disable_device(pcidev);
+ }
+ dev->ioenabled = false;
}
EXPORT_SYMBOL_GPL(comedi_pci_disable);
@@ -72,13 +80,15 @@ EXPORT_SYMBOL_GPL(comedi_pci_disable);
* comedi_pci_auto_config() - Configure/probe a comedi PCI driver.
* @pcidev: pci_dev struct
* @driver: comedi_driver struct
+ * @context: driver specific data, passed to comedi_auto_config()
*
* Typically called from the pci_driver (*probe) function.
*/
int comedi_pci_auto_config(struct pci_dev *pcidev,
- struct comedi_driver *driver)
+ struct comedi_driver *driver,
+ unsigned long context)
{
- return comedi_auto_config(&pcidev->dev, driver, 0);
+ return comedi_auto_config(&pcidev->dev, driver, context);
}
EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index f3a990b45df5..cdd472094cee 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -53,9 +53,7 @@
COMEDI_MINORVERSION, COMEDI_MICROVERSION)
#define COMEDI_RELEASE VERSION
-#define COMEDI_NUM_MINORS 0x100
#define COMEDI_NUM_BOARD_MINORS 0x30
-#define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS
struct comedi_subdevice {
struct comedi_device *device;
@@ -207,16 +205,18 @@ struct comedi_device {
const char *board_name;
const void *board_ptr;
- int attached;
+ bool attached:1;
+ bool in_request_module:1;
+ bool ioenabled:1;
spinlock_t spinlock;
struct mutex mutex;
- int in_request_module;
int n_subdevices;
struct comedi_subdevice *subdevices;
/* dumb */
unsigned long iobase;
+ unsigned long iolen;
unsigned int irq;
struct comedi_subdevice *read_subdev;
@@ -293,6 +293,10 @@ extern const struct comedi_lrange range_bipolar5;
extern const struct comedi_lrange range_bipolar2_5;
extern const struct comedi_lrange range_unipolar10;
extern const struct comedi_lrange range_unipolar5;
+extern const struct comedi_lrange range_unipolar2_5;
+extern const struct comedi_lrange range_0_20mA;
+extern const struct comedi_lrange range_4_20mA;
+extern const struct comedi_lrange range_0_32mA;
extern const struct comedi_lrange range_unknown;
#define range_digital range_unipolar5
@@ -345,6 +349,14 @@ void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset,
int comedi_alloc_subdevices(struct comedi_device *, int);
+void comedi_spriv_free(struct comedi_device *, int subdev_num);
+
+int __comedi_request_region(struct comedi_device *,
+ unsigned long start, unsigned long len);
+int comedi_request_region(struct comedi_device *,
+ unsigned long start, unsigned long len);
+void comedi_legacy_detach(struct comedi_device *);
+
int comedi_auto_config(struct device *, struct comedi_driver *,
unsigned long context);
void comedi_auto_unconfig(struct device *);
@@ -384,10 +396,11 @@ struct pci_driver;
struct pci_dev *comedi_to_pci_dev(struct comedi_device *);
-int comedi_pci_enable(struct pci_dev *, const char *);
-void comedi_pci_disable(struct pci_dev *);
+int comedi_pci_enable(struct comedi_device *);
+void comedi_pci_disable(struct comedi_device *);
-int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *);
+int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *,
+ unsigned long context);
void comedi_pci_auto_unconfig(struct pci_dev *);
int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
@@ -420,12 +433,12 @@ static inline struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev)
return NULL;
}
-static inline int comedi_pci_enable(struct pci_dev *dev, const char *name)
+static inline int comedi_pci_enable(struct comedi_device *dev)
{
return -ENOSYS;
}
-static inline void comedi_pci_disable(struct pci_dev *dev)
+static inline void comedi_pci_disable(struct comedi_device *dev)
{
}
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 64be7c5e891e..06d190f8fd34 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -37,6 +37,7 @@
#include <linux/cdev.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include "comedidev.h"
#include "comedi_internal.h"
@@ -86,6 +87,18 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices)
}
EXPORT_SYMBOL_GPL(comedi_alloc_subdevices);
+void comedi_spriv_free(struct comedi_device *dev, int subdev_num)
+{
+ struct comedi_subdevice *s;
+
+ if (dev->subdevices && subdev_num < dev->n_subdevices) {
+ s = &dev->subdevices[subdev_num];
+ kfree(s->private);
+ s->private = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(comedi_spriv_free);
+
static void cleanup_device(struct comedi_device *dev)
{
int i;
@@ -110,6 +123,8 @@ static void cleanup_device(struct comedi_device *dev)
dev->board_name = NULL;
dev->board_ptr = NULL;
dev->iobase = 0;
+ dev->iolen = 0;
+ dev->ioenabled = false;
dev->irq = 0;
dev->read_subdev = NULL;
dev->write_subdev = NULL;
@@ -118,24 +133,14 @@ static void cleanup_device(struct comedi_device *dev)
comedi_clear_hw_dev(dev);
}
-static void __comedi_device_detach(struct comedi_device *dev)
+void comedi_device_detach(struct comedi_device *dev)
{
- dev->attached = 0;
+ dev->attached = false;
if (dev->driver)
dev->driver->detach(dev);
- else
- dev_warn(dev->class_dev,
- "BUG: dev->driver=NULL in comedi_device_detach()\n");
cleanup_device(dev);
}
-void comedi_device_detach(struct comedi_device *dev)
-{
- if (!dev->attached)
- return;
- __comedi_device_detach(dev);
-}
-
static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
{
return -EINVAL;
@@ -276,21 +281,15 @@ static int __comedi_device_postconfig(struct comedi_device *dev)
}
/* do a little post-config cleanup */
-/* called with module refcount incremented, decrements it */
static int comedi_device_postconfig(struct comedi_device *dev)
{
- int ret = __comedi_device_postconfig(dev);
- module_put(dev->driver->module);
- if (ret < 0) {
- __comedi_device_detach(dev);
+ int ret;
+
+ ret = __comedi_device_postconfig(dev);
+ if (ret < 0)
return ret;
- }
- if (!dev->board_name) {
- dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n");
- dev->board_name = "BUG";
- }
smp_wmb();
- dev->attached = 1;
+ dev->attached = true;
return 0;
}
@@ -352,6 +351,71 @@ static void comedi_report_boards(struct comedi_driver *driv)
pr_info(" %s\n", driv->driver_name);
}
+/**
+ * __comedi_request_region() - Request an I/O reqion for a legacy driver.
+ * @dev: comedi_device struct
+ * @start: base address of the I/O reqion
+ * @len: length of the I/O region
+ */
+int __comedi_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len)
+{
+ if (!start) {
+ dev_warn(dev->class_dev,
+ "%s: a I/O base address must be specified\n",
+ dev->board_name);
+ return -EINVAL;
+ }
+
+ if (!request_region(start, len, dev->board_name)) {
+ dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
+ dev->board_name, start, len);
+ return -EIO;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__comedi_request_region);
+
+/**
+ * comedi_request_region() - Request an I/O reqion for a legacy driver.
+ * @dev: comedi_device struct
+ * @start: base address of the I/O reqion
+ * @len: length of the I/O region
+ */
+int comedi_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len)
+{
+ int ret;
+
+ ret = __comedi_request_region(dev, start, len);
+ if (ret == 0) {
+ dev->iobase = start;
+ dev->iolen = len;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(comedi_request_region);
+
+/**
+ * comedi_legacy_detach() - A generic (*detach) function for legacy drivers.
+ * @dev: comedi_device struct
+ */
+void comedi_legacy_detach(struct comedi_device *dev)
+{
+ if (dev->irq) {
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+ }
+ if (dev->iobase && dev->iolen) {
+ release_region(dev->iobase, dev->iolen);
+ dev->iobase = 0;
+ dev->iolen = 0;
+ }
+}
+EXPORT_SYMBOL_GPL(comedi_legacy_detach);
+
int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_driver *driv;
@@ -393,22 +457,35 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* initialize dev->driver here so
* comedi_error() can be called from attach */
dev->driver = driv;
+ dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr
+ : dev->driver->driver_name;
ret = driv->attach(dev, it);
+ if (ret >= 0)
+ ret = comedi_device_postconfig(dev);
if (ret < 0) {
+ comedi_device_detach(dev);
module_put(dev->driver->module);
- __comedi_device_detach(dev);
- return ret;
}
- return comedi_device_postconfig(dev);
+ /* On success, the driver module count has been incremented. */
+ return ret;
}
int comedi_auto_config(struct device *hardware_device,
struct comedi_driver *driver, unsigned long context)
{
- int minor;
- struct comedi_device *comedi_dev;
+ struct comedi_device *dev;
int ret;
+ if (!hardware_device) {
+ pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n");
+ return -EINVAL;
+ }
+ if (!driver) {
+ dev_warn(hardware_device,
+ "BUG! comedi_auto_config called with NULL comedi driver\n");
+ return -EINVAL;
+ }
+
if (!driver->auto_attach) {
dev_warn(hardware_device,
"BUG! comedi driver '%s' has no auto_attach handler\n",
@@ -416,46 +493,31 @@ int comedi_auto_config(struct device *hardware_device,
return -EINVAL;
}
- minor = comedi_alloc_board_minor(hardware_device);
- if (minor < 0)
- return minor;
-
- comedi_dev = comedi_dev_from_minor(minor);
-
- mutex_lock(&comedi_dev->mutex);
- if (comedi_dev->attached)
- ret = -EBUSY;
- else if (!try_module_get(driver->module))
- ret = -EIO;
- else {
- comedi_set_hw_dev(comedi_dev, hardware_device);
- comedi_dev->driver = driver;
- ret = driver->auto_attach(comedi_dev, context);
- if (ret < 0) {
- module_put(driver->module);
- __comedi_device_detach(comedi_dev);
- } else {
- ret = comedi_device_postconfig(comedi_dev);
- }
- }
- mutex_unlock(&comedi_dev->mutex);
+ dev = comedi_alloc_board_minor(hardware_device);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+ /* Note: comedi_alloc_board_minor() locked dev->mutex. */
+ dev->driver = driver;
+ dev->board_name = dev->driver->driver_name;
+ ret = driver->auto_attach(dev, context);
+ if (ret >= 0)
+ ret = comedi_device_postconfig(dev);
if (ret < 0)
- comedi_free_board_minor(minor);
+ comedi_device_detach(dev);
+ mutex_unlock(&dev->mutex);
+
+ if (ret < 0)
+ comedi_release_hardware_device(hardware_device);
return ret;
}
EXPORT_SYMBOL_GPL(comedi_auto_config);
void comedi_auto_unconfig(struct device *hardware_device)
{
- int minor;
-
if (hardware_device == NULL)
return;
- minor = comedi_find_board_minor(hardware_device);
- if (minor < 0)
- return;
- comedi_free_board_minor(minor);
+ comedi_release_hardware_device(hardware_device);
}
EXPORT_SYMBOL_GPL(comedi_auto_unconfig);
@@ -466,7 +528,7 @@ int comedi_driver_register(struct comedi_driver *driver)
return 0;
}
-EXPORT_SYMBOL(comedi_driver_register);
+EXPORT_SYMBOL_GPL(comedi_driver_register);
int comedi_driver_unregister(struct comedi_driver *driver)
{
@@ -504,4 +566,4 @@ int comedi_driver_unregister(struct comedi_driver *driver)
}
return -EINVAL;
}
-EXPORT_SYMBOL(comedi_driver_unregister);
+EXPORT_SYMBOL_GPL(comedi_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index c7aa41ad842f..1d48aa602ece 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -129,7 +129,7 @@ void subdev_8255_interrupt(struct comedi_device *dev,
comedi_event(dev, s);
}
-EXPORT_SYMBOL(subdev_8255_interrupt);
+EXPORT_SYMBOL_GPL(subdev_8255_interrupt);
static int subdev_8255_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -314,7 +314,7 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-EXPORT_SYMBOL(subdev_8255_init);
+EXPORT_SYMBOL_GPL(subdev_8255_init);
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
int (*io) (int, int, int, unsigned long),
@@ -332,13 +332,7 @@ int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
-EXPORT_SYMBOL(subdev_8255_init_irq);
-
-void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- kfree(s->private);
-}
-EXPORT_SYMBOL(subdev_8255_cleanup);
+EXPORT_SYMBOL_GPL(subdev_8255_init_irq);
/*
@@ -354,8 +348,6 @@ static int dev_8255_attach(struct comedi_device *dev,
unsigned long iobase;
int i;
- dev->board_name = "8255";
-
for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
iobase = it->options[i];
if (!iobase)
@@ -374,16 +366,13 @@ static int dev_8255_attach(struct comedi_device *dev,
s = &dev->subdevices[i];
iobase = it->options[i];
- if (!request_region(iobase, _8255_SIZE, "8255")) {
- dev_warn(dev->class_dev,
- "0x%04lx (I/O port conflict)\n", iobase);
-
+ ret = __comedi_request_region(dev, iobase, _8255_SIZE);
+ if (ret) {
s->type = COMEDI_SUBD_UNUSED;
} else {
ret = subdev_8255_init(dev, s, NULL, iobase);
if (ret)
return ret;
- dev_info(dev->class_dev, "0x%04lx\n", iobase);
}
}
@@ -402,7 +391,7 @@ static void dev_8255_detach(struct comedi_device *dev)
spriv = s->private;
release_region(spriv->iobase, _8255_SIZE);
}
- subdev_8255_cleanup(dev, s);
+ comedi_spriv_free(dev, i);
}
}
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index 1e589b4b8b73..0f6e7492b7db 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -32,7 +32,6 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
int (*io) (int, int, int, unsigned long),
unsigned long iobase);
-void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s);
void subdev_8255_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s);
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 0ae356ae56ea..76dec96aeb2a 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -60,126 +60,98 @@ Configuration Options: not applicable, uses PCI auto config
#include "8255.h"
-/*
- * PCI Device ID's supported by this driver
- */
-#define PCI_DEVICE_ID_ADLINK_PCI7224 0x7224
-#define PCI_DEVICE_ID_ADLINK_PCI7248 0x7248
-#define PCI_DEVICE_ID_ADLINK_PCI7296 0x7296
-
-#define PCI_DEVICE_ID_CB_PCIDIO48H 0x000b
-#define PCI_DEVICE_ID_CB_PCIDIO24H 0x0014
-#define PCI_DEVICE_ID_CB_PCIDIO96H 0x0017
-#define PCI_DEVICE_ID_CB_PCIDIO24 0x0028
-
-#define PCI_DEVICE_ID_NI_PCIDIO96 0x0160
-#define PCI_DEVICE_ID_NI_PCI6503 0x0400
-#define PCI_DEVICE_ID_NI_PCI6503B 0x1250
-#define PCI_DEVICE_ID_NI_PXI6508 0x13c0
-#define PCI_DEVICE_ID_NI_PCIDIO96B 0x1630
-#define PCI_DEVICE_ID_NI_PCI6503X 0x17d0
-#define PCI_DEVICE_ID_NI_PXI_6503 0x1800
+enum pci_8255_boardid {
+ BOARD_ADLINK_PCI7224,
+ BOARD_ADLINK_PCI7248,
+ BOARD_ADLINK_PCI7296,
+ BOARD_CB_PCIDIO24,
+ BOARD_CB_PCIDIO24H,
+ BOARD_CB_PCIDIO48H,
+ BOARD_CB_PCIDIO96H,
+ BOARD_NI_PCIDIO96,
+ BOARD_NI_PCIDIO96B,
+ BOARD_NI_PXI6508,
+ BOARD_NI_PCI6503,
+ BOARD_NI_PCI6503B,
+ BOARD_NI_PCI6503X,
+ BOARD_NI_PXI_6503,
+};
struct pci_8255_boardinfo {
const char *name;
- unsigned short vendor;
- unsigned short device;
int dio_badr;
- int is_mmio;
int n_8255;
};
static const struct pci_8255_boardinfo pci_8255_boards[] = {
- {
+ [BOARD_ADLINK_PCI7224] = {
.name = "adl_pci-7224",
- .vendor = PCI_VENDOR_ID_ADLINK,
- .device = PCI_DEVICE_ID_ADLINK_PCI7224,
.dio_badr = 2,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_ADLINK_PCI7248] = {
.name = "adl_pci-7248",
- .vendor = PCI_VENDOR_ID_ADLINK,
- .device = PCI_DEVICE_ID_ADLINK_PCI7248,
.dio_badr = 2,
.n_8255 = 2,
- }, {
+ },
+ [BOARD_ADLINK_PCI7296] = {
.name = "adl_pci-7296",
- .vendor = PCI_VENDOR_ID_ADLINK,
- .device = PCI_DEVICE_ID_ADLINK_PCI7296,
.dio_badr = 2,
.n_8255 = 4,
- }, {
+ },
+ [BOARD_CB_PCIDIO24] = {
.name = "cb_pci-dio24",
- .vendor = PCI_VENDOR_ID_CB,
- .device = PCI_DEVICE_ID_CB_PCIDIO24,
.dio_badr = 2,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_CB_PCIDIO24H] = {
.name = "cb_pci-dio24h",
- .vendor = PCI_VENDOR_ID_CB,
- .device = PCI_DEVICE_ID_CB_PCIDIO24H,
.dio_badr = 2,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_CB_PCIDIO48H] = {
.name = "cb_pci-dio48h",
- .vendor = PCI_VENDOR_ID_CB,
- .device = PCI_DEVICE_ID_CB_PCIDIO48H,
.dio_badr = 1,
.n_8255 = 2,
- }, {
+ },
+ [BOARD_CB_PCIDIO96H] = {
.name = "cb_pci-dio96h",
- .vendor = PCI_VENDOR_ID_CB,
- .device = PCI_DEVICE_ID_CB_PCIDIO96H,
.dio_badr = 2,
.n_8255 = 4,
- }, {
+ },
+ [BOARD_NI_PCIDIO96] = {
.name = "ni_pci-dio-96",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PCIDIO96,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 4,
- }, {
+ },
+ [BOARD_NI_PCIDIO96B] = {
.name = "ni_pci-dio-96b",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PCIDIO96B,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 4,
- }, {
+ },
+ [BOARD_NI_PXI6508] = {
.name = "ni_pxi-6508",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PXI6508,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 4,
- }, {
+ },
+ [BOARD_NI_PCI6503] = {
.name = "ni_pci-6503",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PCI6503,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_NI_PCI6503B] = {
.name = "ni_pci-6503b",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PCI6503B,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_NI_PCI6503X] = {
.name = "ni_pci-6503x",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PCI6503X,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 1,
- }, {
+ },
+ [BOARD_NI_PXI_6503] = {
.name = "ni_pxi-6503",
- .vendor = PCI_VENDOR_ID_NI,
- .device = PCI_DEVICE_ID_NI_PXI_6503,
.dio_badr = 1,
- .is_mmio = 1,
.n_8255 = 1,
},
};
@@ -200,34 +172,19 @@ static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase)
}
}
-static const void *pci_8255_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct pci_8255_boardinfo *board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pci_8255_boards); i++) {
- board = &pci_8255_boards[i];
- if (pcidev->vendor == board->vendor &&
- pcidev->device == board->device)
- return board;
- }
- return NULL;
-}
-
static int pci_8255_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct pci_8255_boardinfo *board;
+ const struct pci_8255_boardinfo *board = NULL;
struct pci_8255_private *devpriv;
struct comedi_subdevice *s;
- resource_size_t iobase;
- unsigned long len;
+ bool is_mmio;
int ret;
int i;
- board = pci_8255_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(pci_8255_boards))
+ board = &pci_8255_boards[context];
if (!board)
return -ENODEV;
dev->board_ptr = board;
@@ -238,18 +195,19 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
- iobase = pci_resource_start(pcidev, board->dio_badr);
- len = pci_resource_len(pcidev, board->dio_badr);
- if (board->is_mmio) {
- devpriv->mmio_base = ioremap(iobase, len);
+ is_mmio = (pci_resource_flags(pcidev, board->dio_badr) &
+ IORESOURCE_MEM) != 0;
+ if (is_mmio) {
+ devpriv->mmio_base = pci_ioremap_bar(pcidev, board->dio_badr);
if (!devpriv->mmio_base)
return -ENOMEM;
+ } else {
+ dev->iobase = pci_resource_start(pcidev, board->dio_badr);
}
- dev->iobase = iobase;
/*
* One, two, or four subdevices are setup by this driver depending
@@ -261,8 +219,10 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
return ret;
for (i = 0; i < board->n_8255; i++) {
+ unsigned long iobase;
+
s = &dev->subdevices[i];
- if (board->is_mmio) {
+ if (is_mmio) {
iobase = (unsigned long)(devpriv->mmio_base + (i * 4));
ret = subdev_8255_init(dev, s, pci_8255_mmio, iobase);
} else {
@@ -281,26 +241,14 @@ static int pci_8255_auto_attach(struct comedi_device *dev,
static void pci_8255_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct pci_8255_boardinfo *board = comedi_board(dev);
struct pci_8255_private *devpriv = dev->private;
- struct comedi_subdevice *s;
int i;
- if (!board || !devpriv)
- return;
- if (dev->subdevices) {
- for (i = 0; i < board->n_8255; i++) {
- s = &dev->subdevices[i];
- subdev_8255_cleanup(dev, s);
- }
- }
- if (pcidev) {
- if (devpriv->mmio_base)
- iounmap(devpriv->mmio_base);
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ for (i = 0; i < dev->n_subdevices; i++)
+ comedi_spriv_free(dev, i);
+ if (devpriv && devpriv->mmio_base)
+ iounmap(devpriv->mmio_base);
+ comedi_pci_disable(dev);
}
static struct comedi_driver pci_8255_driver = {
@@ -311,26 +259,26 @@ static struct comedi_driver pci_8255_driver = {
};
static int pci_8255_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &pci_8255_driver);
+ return comedi_pci_auto_config(dev, &pci_8255_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7224) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7248) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7296) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24H) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO48H) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO96H) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96B) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI6508) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503B) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503X) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI_6503) },
+ { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 },
+ { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 },
+ { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 },
+ { PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 },
+ { PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H },
+ { PCI_VDEVICE(CB, 0x000b), BOARD_CB_PCIDIO48H },
+ { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H },
+ { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 },
+ { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B },
+ { PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 },
+ { PCI_VDEVICE(NI, 0x0400), BOARD_NI_PCI6503 },
+ { PCI_VDEVICE(NI, 0x1250), BOARD_NI_PCI6503B },
+ { PCI_VDEVICE(NI, 0x17d0), BOARD_NI_PCI6503X },
+ { PCI_VDEVICE(NI, 0x1800), BOARD_NI_PXI_6503 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, pci_8255_pci_table);
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 315e836ff99b..57e984f0f462 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -12,6 +12,8 @@ obj-$(CONFIG_COMEDI_SKEL) += skel.o
# Comedi ISA drivers
obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o
+obj-$(CONFIG_COMEDI_AMPLC_DIO200_ISA) += amplc_dio200.o
+obj-$(CONFIG_COMEDI_AMPLC_PC263_ISA) += amplc_pc263.o
obj-$(CONFIG_COMEDI_PCL711) += pcl711.o
obj-$(CONFIG_COMEDI_PCL724) += pcl724.o
obj-$(CONFIG_COMEDI_PCL725) += pcl725.o
@@ -75,10 +77,11 @@ obj-$(CONFIG_COMEDI_ADL_PCI9111) += adl_pci9111.o
obj-$(CONFIG_COMEDI_ADL_PCI9118) += adl_pci9118.o
obj-$(CONFIG_COMEDI_ADV_PCI1710) += adv_pci1710.o
obj-$(CONFIG_COMEDI_ADV_PCI1723) += adv_pci1723.o
+obj-$(CONFIG_COMEDI_ADV_PCI1724) += adv_pci1724.o
obj-$(CONFIG_COMEDI_ADV_PCI_DIO) += adv_pci_dio.o
-obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200.o
+obj-$(CONFIG_COMEDI_AMPLC_DIO200_PCI) += amplc_dio200_pci.o
obj-$(CONFIG_COMEDI_AMPLC_PC236) += amplc_pc236.o
-obj-$(CONFIG_COMEDI_AMPLC_PC263) += amplc_pc263.o
+obj-$(CONFIG_COMEDI_AMPLC_PC263_PCI) += amplc_pci263.o
obj-$(CONFIG_COMEDI_AMPLC_PCI224) += amplc_pci224.o
obj-$(CONFIG_COMEDI_AMPLC_PCI230) += amplc_pci230.o
obj-$(CONFIG_COMEDI_CONTEC_PCI_DIO) += contec_pci_dio.o
@@ -103,6 +106,7 @@ obj-$(CONFIG_COMEDI_NI_6527) += ni_6527.o
obj-$(CONFIG_COMEDI_NI_65XX) += ni_65xx.o
obj-$(CONFIG_COMEDI_NI_660X) += ni_660x.o
obj-$(CONFIG_COMEDI_NI_670X) += ni_670x.o
+obj-$(CONFIG_COMEDI_NI_LABPC_PCI) += ni_labpc_pci.o
obj-$(CONFIG_COMEDI_NI_PCIDIO) += ni_pcidio.o
obj-$(CONFIG_COMEDI_NI_PCIMIO) += ni_pcimio.o
obj-$(CONFIG_COMEDI_RTD520) += rtd520.o
@@ -133,5 +137,6 @@ obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o
obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o
obj-$(CONFIG_COMEDI_8255) += 8255.o
+obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200_common.o
obj-$(CONFIG_COMEDI_DAS08) += das08.o
obj-$(CONFIG_COMEDI_FC) += comedi_fc.o
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index 28c7fd3a96b6..9e2c7aeea535 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -15,43 +15,59 @@ Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
#include <linux/ioport.h>
-#define ACL7225_SIZE 8 /* Requires 8 ioports, but only 4 are used */
-#define P16R16DIO_SIZE 4
#define ACL7225_RIO_LO 0 /* Relays input/output low byte (R0-R7) */
#define ACL7225_RIO_HI 1 /* Relays input/output high byte (R8-R15) */
#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */
#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */
-struct boardtype {
- const char *name; /* driver name */
- int io_range; /* len of I/O space */
+struct acl7225b_boardinfo {
+ const char *name;
+ int io_range;
};
-static int acl7225b_do_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static const struct acl7225b_boardinfo acl7225b_boards[] = {
+ {
+ .name = "acl7225b",
+ .io_range = 8, /* only 4 are used */
+ }, {
+ .name = "p16r16dio",
+ .io_range = 4,
+ },
+};
+
+static int acl7225b_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
+ unsigned long reg = (unsigned long)s->private;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
+
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
+
+ if (mask & 0x00ff)
+ outb(s->state & 0xff, dev->iobase + reg);
+ if (mask & 0xff00)
+ outb((s->state >> 8), dev->iobase + reg + 1);
}
- if (data[0] & 0x00ff)
- outb(s->state & 0xff, dev->iobase + (unsigned long)s->private);
- if (data[0] & 0xff00)
- outb((s->state >> 8),
- dev->iobase + (unsigned long)s->private + 1);
data[1] = s->state;
return insn->n;
}
-static int acl7225b_di_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int acl7225b_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- data[1] = inb(dev->iobase + (unsigned long)s->private) |
- (inb(dev->iobase + (unsigned long)s->private + 1) << 8);
+ unsigned long reg = (unsigned long)s->private;
+
+ data[1] = inb(dev->iobase + reg) |
+ (inb(dev->iobase + reg + 1) << 8);
return insn->n;
}
@@ -59,23 +75,13 @@ static int acl7225b_di_insn(struct comedi_device *dev,
static int acl7225b_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- const struct boardtype *board = comedi_board(dev);
+ const struct acl7225b_boardinfo *board = comedi_board(dev);
struct comedi_subdevice *s;
- int iobase, iorange;
int ret;
- iobase = it->options[0];
- iorange = board->io_range;
- printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor,
- board->name, iobase);
- if (!request_region(iobase, iorange, "acl7225b")) {
- printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n",
- dev->minor);
- return -EIO;
- }
- dev->board_name = board->name;
- dev->iobase = iobase;
- dev->irq = 0;
+ ret = comedi_request_region(dev, it->options[0], board->io_range);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
@@ -83,61 +89,48 @@ static int acl7225b_attach(struct comedi_device *dev,
s = &dev->subdevices[0];
/* Relays outputs */
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = acl7225b_do_insn;
- s->range_table = &range_digital;
- s->private = (void *)ACL7225_RIO_LO;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->maxdata = 1;
+ s->n_chan = 16;
+ s->insn_bits = acl7225b_do_insn_bits;
+ s->range_table = &range_digital;
+ s->private = (void *)ACL7225_RIO_LO;
s = &dev->subdevices[1];
/* Relays status */
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = acl7225b_di_insn;
- s->range_table = &range_digital;
- s->private = (void *)ACL7225_RIO_LO;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->maxdata = 1;
+ s->n_chan = 16;
+ s->insn_bits = acl7225b_di_insn_bits;
+ s->range_table = &range_digital;
+ s->private = (void *)ACL7225_RIO_LO;
s = &dev->subdevices[2];
/* Isolated digital inputs */
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->maxdata = 1;
- s->n_chan = 16;
- s->insn_bits = acl7225b_di_insn;
- s->range_table = &range_digital;
- s->private = (void *)ACL7225_DI_LO;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->maxdata = 1;
+ s->n_chan = 16;
+ s->insn_bits = acl7225b_di_insn_bits;
+ s->range_table = &range_digital;
+ s->private = (void *)ACL7225_DI_LO;
return 0;
}
-static void acl7225b_detach(struct comedi_device *dev)
-{
- const struct boardtype *board = comedi_board(dev);
-
- if (dev->iobase)
- release_region(dev->iobase, board->io_range);
-}
-
-static const struct boardtype boardtypes[] = {
- { "acl7225b", ACL7225_SIZE, },
- { "p16r16dio", P16R16DIO_SIZE, },
-};
-
static struct comedi_driver acl7225b_driver = {
.driver_name = "acl7225b",
.module = THIS_MODULE,
.attach = acl7225b_attach,
- .detach = acl7225b_detach,
- .board_name = &boardtypes[0].name,
- .num_names = ARRAY_SIZE(boardtypes),
- .offset = sizeof(struct boardtype),
+ .detach = comedi_legacy_detach,
+ .board_name = &acl7225b_boards[0].name,
+ .num_names = ARRAY_SIZE(acl7225b_boards),
+ .offset = sizeof(struct acl7225b_boardinfo),
};
module_comedi_driver(acl7225b_driver);
+MODULE_DESCRIPTION("Comedi: NuDAQ ACL-7225B, 16 Relay & 16 Isolated DI Card");
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
index 1e05732e9f3d..97e7eec343d7 100644
--- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
+++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c
@@ -704,9 +704,9 @@ static int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev,
| unsigned char *_ pb_ChannelStatus) |
+----------------------------------------------------------------------------+
| Task :
- (0) Set the digital output from selected SSI moule |
+ (0) Set the digital output from selected SSI module |
| (b_ModuleNbr) ON
- (1) Set the digital output from selected SSI moule |
+ (1) Set the digital output from selected SSI module |
| (b_ModuleNbr) OFF
(2)Read the status from selected SSI digital input |
| (b_InputChannel)
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index 1051fa5ce8f7..0c3db57a50f4 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -84,37 +84,16 @@ static int i_ADDI_Reset(struct comedi_device *dev)
return 0;
}
-static const void *addi_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const void *p = dev->driver->board_name;
- const struct addi_board *this_board;
- int i;
-
- for (i = 0; i < dev->driver->num_names; i++) {
- this_board = p;
- if (this_board->i_VendorId == pcidev->vendor &&
- this_board->i_DeviceId == pcidev->device)
- return this_board;
- p += dev->driver->offset;
- }
- return NULL;
-}
-
static int addi_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct addi_board *this_board;
+ const struct addi_board *this_board = comedi_board(dev);
struct addi_private *devpriv;
struct comedi_subdevice *s;
int ret, n_subdevices;
unsigned int dw_Dummy;
- this_board = addi_find_boardinfo(dev, pcidev);
- if (!this_board)
- return -ENODEV;
- dev->board_ptr = this_board;
dev->board_name = this_board->pc_DriverName;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
@@ -122,7 +101,7 @@ static int addi_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -141,8 +120,7 @@ static int addi_auto_attach(struct comedi_device *dev,
/* board has an ADDIDATA_9054 eeprom */
dev->iobase = pci_resource_start(pcidev, 2);
devpriv->iobase = pci_resource_start(pcidev, 2);
- devpriv->dw_AiBase = ioremap(pci_resource_start(pcidev, 3),
- this_board->i_IorangeBase3);
+ devpriv->dw_AiBase = pci_ioremap_bar(pcidev, 3);
}
devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
@@ -338,7 +316,6 @@ static int addi_auto_attach(struct comedi_device *dev,
static void i_ADDI_Detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct addi_private *devpriv = dev->private;
if (devpriv) {
@@ -349,8 +326,5 @@ static void i_ADDI_Detach(struct comedi_device *dev)
if (devpriv->dw_AiBase)
iounmap(devpriv->dw_AiBase);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index 6d8b29f945d5..c034bf1426eb 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -45,12 +45,7 @@
/* structure for the boardtype */
struct addi_board {
const char *pc_DriverName; /* driver name */
- int i_VendorId; /* PCI vendor a device ID of card */
- int i_DeviceId;
- int i_IorangeBase0;
int i_IorangeBase1;
- int i_IorangeBase2; /* base 2 range */
- int i_IorangeBase3; /* base 3 range */
int i_PCIEeprom; /* eeprom present or not */
char *pc_EepromChip; /* type of chip */
int i_NbrAiChannel; /* num of A/D chans */
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index 5a53e58258a0..43c2c10a7c32 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -15,9 +15,6 @@
static const struct addi_board apci035_boardtypes[] = {
{
.pc_DriverName = "apci035",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x0300,
- .i_IorangeBase0 = 127,
.i_IorangeBase1 = APCI035_ADDRESS_RANGE,
.i_PCIEeprom = 1,
.pc_EepromChip = ADDIDATA_S5920,
@@ -39,20 +36,25 @@ static const struct addi_board apci035_boardtypes[] = {
},
};
+static int apci035_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ dev->board_ptr = &apci035_boardtypes[0];
+
+ return addi_auto_attach(dev, context);
+}
+
static struct comedi_driver apci035_driver = {
.driver_name = "addi_apci_035",
.module = THIS_MODULE,
- .auto_attach = addi_auto_attach,
+ .auto_attach = apci035_auto_attach,
.detach = i_ADDI_Detach,
- .num_names = ARRAY_SIZE(apci035_boardtypes),
- .board_name = &apci035_boardtypes[0].pc_DriverName,
- .offset = sizeof(struct addi_board),
};
static int apci035_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci035_driver);
+ return comedi_pci_auto_config(dev, &apci035_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci035_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index c0d0429c35c8..3d4878facc26 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -296,14 +296,12 @@ static int apci1032_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -353,16 +351,11 @@ static int apci1032_auto_attach(struct comedi_device *dev,
static void apci1032_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
apci1032_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci1032_driver = {
@@ -373,9 +366,9 @@ static struct comedi_driver apci1032_driver = {
};
static int apci1032_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci1032_driver);
+ return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci1032_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 9c2f8eeb7977..b52cfe01e6c8 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -13,11 +13,7 @@
static const struct addi_board apci1500_boardtypes[] = {
{
.pc_DriverName = "apci1500",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA_OLD,
- .i_DeviceId = 0x80fc,
- .i_IorangeBase0 = 128,
.i_IorangeBase1 = APCI1500_ADDRESS_RANGE,
- .i_IorangeBase2 = 4,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.i_NbrDiChannel = 16,
.i_NbrDoChannel = 16,
@@ -39,24 +35,29 @@ static const struct addi_board apci1500_boardtypes[] = {
},
};
+static int apci1500_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ dev->board_ptr = &apci1500_boardtypes[0];
+
+ return addi_auto_attach(dev, context);
+}
+
static struct comedi_driver apci1500_driver = {
.driver_name = "addi_apci_1500",
.module = THIS_MODULE,
- .auto_attach = addi_auto_attach,
+ .auto_attach = apci1500_auto_attach,
.detach = i_ADDI_Detach,
- .num_names = ARRAY_SIZE(apci1500_boardtypes),
- .board_name = &apci1500_boardtypes[0].pc_DriverName,
- .offset = sizeof(struct addi_board),
};
static int apci1500_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci1500_driver);
+ return comedi_pci_auto_config(dev, &apci1500_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci1500_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x80fc) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80fc) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci1500_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index 69e399638419..ed01c56630bb 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -36,13 +36,6 @@
#include "comedi_fc.h"
/*
- * PCI device ids supported by this driver
- */
-#define PCI_DEVICE_ID_APCI1016 0x1000
-#define PCI_DEVICE_ID_APCI1516 0x1001
-#define PCI_DEVICE_ID_APCI2016 0x1002
-
-/*
* PCI bar 1 I/O Register map - Digital input/output
*/
#define APCI1516_DI_REG 0x00
@@ -53,28 +46,32 @@
*/
#define APCI1516_WDOG_REG 0x00
+enum apci1516_boardid {
+ BOARD_APCI1016,
+ BOARD_APCI1516,
+ BOARD_APCI2016,
+};
+
struct apci1516_boardinfo {
const char *name;
- unsigned short device;
int di_nchan;
int do_nchan;
int has_wdog;
};
static const struct apci1516_boardinfo apci1516_boardtypes[] = {
- {
+ [BOARD_APCI1016] = {
.name = "apci1016",
- .device = PCI_DEVICE_ID_APCI1016,
.di_nchan = 16,
- }, {
+ },
+ [BOARD_APCI1516] = {
.name = "apci1516",
- .device = PCI_DEVICE_ID_APCI1516,
.di_nchan = 8,
.do_nchan = 8,
.has_wdog = 1,
- }, {
+ },
+ [BOARD_APCI2016] = {
.name = "apci2016",
- .device = PCI_DEVICE_ID_APCI2016,
.do_nchan = 16,
.has_wdog = 1,
},
@@ -130,30 +127,17 @@ static int apci1516_reset(struct comedi_device *dev)
return 0;
}
-static const void *apci1516_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct apci1516_boardinfo *this_board;
- int i;
-
- for (i = 0; i < dev->driver->num_names; i++) {
- this_board = &apci1516_boardtypes[i];
- if (this_board->device == pcidev->device)
- return this_board;
- }
- return NULL;
-}
-
static int apci1516_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct apci1516_boardinfo *this_board;
+ const struct apci1516_boardinfo *this_board = NULL;
struct apci1516_private *devpriv;
struct comedi_subdevice *s;
int ret;
- this_board = apci1516_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(apci1516_boardtypes))
+ this_board = &apci1516_boardtypes[context];
if (!this_board)
return -ENODEV;
dev->board_ptr = this_board;
@@ -164,7 +148,7 @@ static int apci1516_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -217,14 +201,10 @@ static int apci1516_auto_attach(struct comedi_device *dev,
static void apci1516_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
apci1516_reset(dev);
- if (dev->subdevices)
- addi_watchdog_cleanup(&dev->subdevices[2]);
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ comedi_spriv_free(dev, 2);
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci1516_driver = {
@@ -235,15 +215,15 @@ static struct comedi_driver apci1516_driver = {
};
static int apci1516_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci1516_driver);
+ return comedi_pci_auto_config(dev, &apci1516_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci1516_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1016) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1516) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI2016) },
+ { PCI_VDEVICE(ADDIDATA, 0x1000), BOARD_APCI1016 },
+ { PCI_VDEVICE(ADDIDATA, 0x1001), BOARD_APCI1516 },
+ { PCI_VDEVICE(ADDIDATA, 0x1002), BOARD_APCI2016 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci1516_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index ddea64df9180..22bace62210c 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -13,9 +13,6 @@
static const struct addi_board apci1564_boardtypes[] = {
{
.pc_DriverName = "apci1564",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x1006,
- .i_IorangeBase0 = 128,
.i_IorangeBase1 = APCI1564_ADDRESS_RANGE,
.i_PCIEeprom = ADDIDATA_EEPROM,
.pc_EepromChip = ADDIDATA_93C76,
@@ -36,20 +33,25 @@ static const struct addi_board apci1564_boardtypes[] = {
},
};
+static int apci1564_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ dev->board_ptr = &apci1564_boardtypes[0];
+
+ return addi_auto_attach(dev, context);
+}
+
static struct comedi_driver apci1564_driver = {
.driver_name = "addi_apci_1564",
.module = THIS_MODULE,
- .auto_attach = addi_auto_attach,
+ .auto_attach = apci1564_auto_attach,
.detach = i_ADDI_Detach,
- .num_names = ARRAY_SIZE(apci1564_boardtypes),
- .board_name = &apci1564_boardtypes[0].pc_DriverName,
- .offset = sizeof(struct addi_board),
};
static int apci1564_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci1564_driver);
+ return comedi_pci_auto_config(dev, &apci1564_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci1564_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index e51f80001363..4c6a9b5a06ae 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -34,35 +34,29 @@
#include "../comedidev.h"
/*
- * PCI device ids supported by this driver
- */
-#define PCI_DEVICE_ID_APCI1648 0x1009
-#define PCI_DEVICE_ID_APCI1696 0x100a
-
-/*
* Register I/O map
*/
#define APCI16XX_IN_REG(x) (((x) * 4) + 0x08)
#define APCI16XX_OUT_REG(x) (((x) * 4) + 0x14)
#define APCI16XX_DIR_REG(x) (((x) * 4) + 0x20)
+enum apci16xx_boardid {
+ BOARD_APCI1648,
+ BOARD_APCI1696,
+};
+
struct apci16xx_boardinfo {
const char *name;
- unsigned short vendor;
- unsigned short device;
int n_chan;
};
static const struct apci16xx_boardinfo apci16xx_boardtypes[] = {
- {
+ [BOARD_APCI1648] = {
.name = "apci1648",
- .vendor = PCI_VENDOR_ID_ADDIDATA,
- .device = PCI_DEVICE_ID_APCI1648,
.n_chan = 48, /* 2 subdevices */
- }, {
+ },
+ [BOARD_APCI1696] = {
.name = "apci1696",
- .vendor = PCI_VENDOR_ID_ADDIDATA,
- .device = PCI_DEVICE_ID_APCI1696,
.n_chan = 96, /* 3 subdevices */
},
};
@@ -130,39 +124,25 @@ static int apci16xx_dio_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static const void *apci16xx_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct apci16xx_boardinfo *board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(apci16xx_boardtypes); i++) {
- board = &apci16xx_boardtypes[i];
- if (board->vendor == pcidev->vendor &&
- board->device == pcidev->device)
- return board;
- }
- return NULL;
-}
-
static int apci16xx_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct apci16xx_boardinfo *board;
+ const struct apci16xx_boardinfo *board = NULL;
struct comedi_subdevice *s;
unsigned int n_subdevs;
unsigned int last;
int i;
int ret;
- board = apci16xx_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(apci16xx_boardtypes))
+ board = &apci16xx_boardtypes[context];
if (!board)
return -ENODEV;
dev->board_ptr = board;
dev->board_name = board->name;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -204,35 +184,22 @@ static int apci16xx_auto_attach(struct comedi_device *dev,
return 0;
}
-static void apci16xx_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver apci16xx_driver = {
.driver_name = "addi_apci_16xx",
.module = THIS_MODULE,
.auto_attach = apci16xx_auto_attach,
- .detach = apci16xx_detach,
- .num_names = ARRAY_SIZE(apci16xx_boardtypes),
- .board_name = &apci16xx_boardtypes[0].name,
- .offset = sizeof(struct apci16xx_boardinfo),
+ .detach = comedi_pci_disable,
};
static int apci16xx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci16xx_driver);
+ return comedi_pci_auto_config(dev, &apci16xx_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci16xx_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1648) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, PCI_DEVICE_ID_APCI1696) },
+ { PCI_VDEVICE(ADDIDATA, 0x1009), BOARD_APCI1648 },
+ { PCI_VDEVICE(ADDIDATA, 0x100a), BOARD_APCI1696 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci16xx_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c
index e83e829831b0..c9e6471eb06b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1710.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1710.c
@@ -21,72 +21,29 @@ static void fpu_end(void)
#include "addi-data/addi_eeprom.c"
#include "addi-data/hwdrv_APCI1710.c"
-static const struct addi_board apci1710_boardtypes[] = {
- {
- .pc_DriverName = "apci1710",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA_OLD,
- .i_DeviceId = APCI1710_BOARD_DEVICE_ID,
- .interrupt = v_APCI1710_Interrupt,
- },
-};
-
static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
{
- struct comedi_device *dev = d;
- const struct addi_board *this_board = comedi_board(dev);
-
- this_board->interrupt(irq, d);
+ v_APCI1710_Interrupt(irq, d);
return IRQ_RETVAL(1);
}
-static const void *apci1710_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct addi_board *this_board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(apci1710_boardtypes); i++) {
- this_board = &apci1710_boardtypes[i];
- if (this_board->i_VendorId == pcidev->vendor &&
- this_board->i_DeviceId == pcidev->device)
- return this_board;
- }
- return NULL;
-}
-
static int apci1710_auto_attach(struct comedi_device *dev,
unsigned long context_unused)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct addi_board *this_board;
struct addi_private *devpriv;
struct comedi_subdevice *s;
int ret;
- this_board = apci1710_find_boardinfo(dev, pcidev);
- if (!this_board)
- return -ENODEV;
- dev->board_ptr = this_board;
- dev->board_name = this_board->pc_DriverName;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
-
- if (this_board->i_IorangeBase1)
- dev->iobase = pci_resource_start(pcidev, 1);
- else
- dev->iobase = pci_resource_start(pcidev, 0);
-
- devpriv->iobase = dev->iobase;
- devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
- devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2);
- devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
+ devpriv->s_BoardInfos.ui_Address = pci_resource_start(pcidev, 2);
if (pcidev->irq > 0) {
ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
@@ -97,24 +54,17 @@ static int apci1710_auto_attach(struct comedi_device *dev,
i_ADDI_AttachPCI1710(dev);
- devpriv->s_BoardInfos.ui_Address = pci_resource_start(pcidev, 2);
-
i_APCI1710_Reset(dev);
return 0;
}
static void apci1710_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
i_APCI1710_Reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci1710_driver = {
@@ -125,13 +75,13 @@ static struct comedi_driver apci1710_driver = {
};
static int apci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci1710_driver);
+ return comedi_pci_auto_config(dev, &apci1710_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, APCI1710_BOARD_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMCC, APCI1710_BOARD_DEVICE_ID) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci1710_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index 9ce1d26aff2f..b666637f61be 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -287,9 +287,7 @@ static int apci2032_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 1);
@@ -350,20 +348,14 @@ static int apci2032_auto_attach(struct comedi_device *dev,
static void apci2032_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
apci2032_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->read_subdev)
kfree(dev->read_subdev->private);
- if (dev->subdevices)
- addi_watchdog_cleanup(&dev->subdevices[1]);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 1);
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci2032_driver = {
@@ -374,9 +366,9 @@ static struct comedi_driver apci2032_driver = {
};
static int apci2032_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci2032_driver);
+ return comedi_pci_auto_config(dev, &apci2032_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci2032_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index b1c4226902e1..1cdc08d79792 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -88,9 +88,7 @@ static int apci2200_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -130,16 +128,10 @@ static int apci2200_auto_attach(struct comedi_device *dev,
static void apci2200_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
apci2200_reset(dev);
- if (dev->subdevices)
- addi_watchdog_cleanup(&dev->subdevices[2]);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 2);
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci2200_driver = {
@@ -150,9 +142,9 @@ static struct comedi_driver apci2200_driver = {
};
static int apci2200_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci2200_driver);
+ return comedi_pci_auto_config(dev, &apci2200_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci2200_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 917234d24e99..317a26d97c2e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -8,11 +8,14 @@
#include "addi-data/hwdrv_apci3120.c"
+enum apci3120_boardid {
+ BOARD_APCI3120,
+ BOARD_APCI3001,
+};
+
static const struct addi_board apci3120_boardtypes[] = {
- {
+ [BOARD_APCI3120] = {
.pc_DriverName = "apci3120",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA_OLD,
- .i_DeviceId = 0x818D,
.i_NbrAiChannel = 16,
.i_NbrAiChannelDiff = 8,
.i_AiChannelList = 16,
@@ -23,10 +26,9 @@ static const struct addi_board apci3120_boardtypes[] = {
.i_NbrDoChannel = 4,
.i_DoMaxdata = 0x0f,
.interrupt = v_APCI3120_Interrupt,
- }, {
+ },
+ [BOARD_APCI3001] = {
.pc_DriverName = "apci3001",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA_OLD,
- .i_DeviceId = 0x828D,
.i_NbrAiChannel = 16,
.i_NbrAiChannelDiff = 8,
.i_AiChannelList = 16,
@@ -47,31 +49,17 @@ static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
return IRQ_RETVAL(1);
}
-static const void *apci3120_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct addi_board *this_board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(apci3120_boardtypes); i++) {
- this_board = &apci3120_boardtypes[i];
- if (this_board->i_VendorId == pcidev->vendor &&
- this_board->i_DeviceId == pcidev->device)
- return this_board;
- }
- return NULL;
-}
-
static int apci3120_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct addi_board *this_board;
+ const struct addi_board *this_board = NULL;
struct addi_private *devpriv;
struct comedi_subdevice *s;
int ret, pages, i;
- this_board = apci3120_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(apci3120_boardtypes))
+ this_board = &apci3120_boardtypes[context];
if (!this_board)
return -ENODEV;
dev->board_ptr = this_board;
@@ -82,7 +70,7 @@ static int apci3120_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
pci_set_master(pcidev);
@@ -215,7 +203,6 @@ static int apci3120_auto_attach(struct comedi_device *dev,
static void apci3120_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct addi_private *devpriv = dev->private;
if (devpriv) {
@@ -234,10 +221,7 @@ static void apci3120_detach(struct comedi_device *dev)
devpriv->ui_DmaBufferPages[1]);
}
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci3120_driver = {
@@ -248,14 +232,14 @@ static struct comedi_driver apci3120_driver = {
};
static int apci3120_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci3120_driver);
+ return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci3120_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x818d) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA_OLD, 0x828d) },
+ { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 },
+ { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci3120_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index 90ee4f844f91..17b540d3c6ae 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -22,15 +22,15 @@ static void fpu_end(void)
#include "addi-data/hwdrv_apci3200.c"
#include "addi-data/addi_common.c"
+enum apci3200_boardid {
+ BOARD_APCI3200,
+ BOARD_APCI3300,
+};
+
static const struct addi_board apci3200_boardtypes[] = {
- {
+ [BOARD_APCI3200] = {
.pc_DriverName = "apci3200",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3000,
- .i_IorangeBase0 = 128,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 4,
- .i_IorangeBase3 = 4,
.i_PCIEeprom = ADDIDATA_EEPROM,
.pc_EepromChip = ADDIDATA_S5920,
.i_NbrAiChannel = 16,
@@ -53,14 +53,10 @@ static const struct addi_board apci3200_boardtypes[] = {
.ai_cancel = i_APCI3200_StopCyclicAcquisition,
.di_bits = apci3200_di_insn_bits,
.do_bits = apci3200_do_insn_bits,
- }, {
+ },
+ [BOARD_APCI3300] = {
.pc_DriverName = "apci3300",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3007,
- .i_IorangeBase0 = 128,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 4,
- .i_IorangeBase3 = 4,
.i_PCIEeprom = ADDIDATA_EEPROM,
.pc_EepromChip = ADDIDATA_S5920,
.i_NbrAiChannelDiff = 8,
@@ -85,29 +81,40 @@ static const struct addi_board apci3200_boardtypes[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(apci3200_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3000) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3007) },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, apci3200_pci_table);
+static int apci3200_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ const struct addi_board *board = NULL;
+
+ if (context < ARRAY_SIZE(apci3200_boardtypes))
+ board = &apci3200_boardtypes[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+
+ return addi_auto_attach(dev, context);
+}
static struct comedi_driver apci3200_driver = {
.driver_name = "addi_apci_3200",
.module = THIS_MODULE,
- .auto_attach = addi_auto_attach,
+ .auto_attach = apci3200_auto_attach,
.detach = i_ADDI_Detach,
- .num_names = ARRAY_SIZE(apci3200_boardtypes),
- .board_name = &apci3200_boardtypes[0].pc_DriverName,
- .offset = sizeof(struct addi_board),
};
static int apci3200_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci3200_driver);
+ return comedi_pci_auto_config(dev, &apci3200_driver, id->driver_data);
}
+static DEFINE_PCI_DEVICE_TABLE(apci3200_pci_table) = {
+ { PCI_VDEVICE(ADDIDATA, 0x3000), BOARD_APCI3200 },
+ { PCI_VDEVICE(ADDIDATA, 0x3007), BOARD_APCI3300 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, apci3200_pci_table);
+
static struct pci_driver apci3200_pci_driver = {
.name = "addi_apci_3200",
.id_table = apci3200_pci_table,
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 786fcaf82c32..a0cf6ecdef0e 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -339,14 +339,12 @@ static int apci3501_auto_attach(struct comedi_device *dev,
int ao_n_chan;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -423,16 +421,11 @@ static int apci3501_auto_attach(struct comedi_device *dev,
static void apci3501_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
apci3501_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver apci3501_driver = {
@@ -443,9 +436,9 @@ static struct comedi_driver apci3501_driver = {
};
static int apci3501_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci3501_driver);
+ return comedi_pci_auto_config(dev, &apci3501_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci3501_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index 09d4b21fce23..ec4d6ca6863f 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -10,15 +10,38 @@
#include "addi-data/hwdrv_apci3xxx.c"
#include "addi-data/addi_common.c"
+enum apci3xxx_boardid {
+ BOARD_APCI3000_16,
+ BOARD_APCI3000_8,
+ BOARD_APCI3000_4,
+ BOARD_APCI3006_16,
+ BOARD_APCI3006_8,
+ BOARD_APCI3006_4,
+ BOARD_APCI3010_16,
+ BOARD_APCI3010_8,
+ BOARD_APCI3010_4,
+ BOARD_APCI3016_16,
+ BOARD_APCI3016_8,
+ BOARD_APCI3016_4,
+ BOARD_APCI3100_16_4,
+ BOARD_APCI3100_8_4,
+ BOARD_APCI3106_16_4,
+ BOARD_APCI3106_8_4,
+ BOARD_APCI3110_16_4,
+ BOARD_APCI3110_8_4,
+ BOARD_APCI3116_16_4,
+ BOARD_APCI3116_8_4,
+ BOARD_APCI3003,
+ BOARD_APCI3002_16,
+ BOARD_APCI3002_8,
+ BOARD_APCI3002_4,
+ BOARD_APCI3500,
+};
+
static const struct addi_board apci3xxx_boardtypes[] = {
- {
+ [BOARD_APCI3000_16] = {
.pc_DriverName = "apci3000-16",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3010,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -37,14 +60,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3000_8] = {
.pc_DriverName = "apci3000-8",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x300F,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -63,14 +82,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3000_4] = {
.pc_DriverName = "apci3000-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x300E,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 4,
@@ -89,14 +104,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3006_16] = {
.pc_DriverName = "apci3006-16",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3013,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -115,14 +126,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3006_8] = {
.pc_DriverName = "apci3006-8",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3014,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -141,14 +148,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3006_4] = {
.pc_DriverName = "apci3006-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3015,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 4,
@@ -167,14 +170,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3010_16] = {
.pc_DriverName = "apci3010-16",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3016,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -198,14 +197,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3010_8] = {
.pc_DriverName = "apci3010-8",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3017,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -229,14 +224,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3010_4] = {
.pc_DriverName = "apci3010-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3018,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 4,
@@ -260,14 +251,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3016_16] = {
.pc_DriverName = "apci3016-16",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3019,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -291,14 +278,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3016_8] = {
.pc_DriverName = "apci3016-8",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301A,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -322,14 +305,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3016_4] = {
.pc_DriverName = "apci3016-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301B,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 4,
@@ -353,14 +332,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3100_16_4] = {
.pc_DriverName = "apci3100-16-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301C,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -383,14 +358,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3100_8_4] = {
.pc_DriverName = "apci3100-8-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301D,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -413,14 +384,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3106_16_4] = {
.pc_DriverName = "apci3106-16-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301E,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -443,14 +410,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3106_8_4] = {
.pc_DriverName = "apci3106-8-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x301F,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -473,14 +436,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3110_16_4] = {
.pc_DriverName = "apci3110-16-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3020,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -508,14 +467,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3110_8_4] = {
.pc_DriverName = "apci3110-8-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3021,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -543,14 +498,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3116_16_4] = {
.pc_DriverName = "apci3116-16-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3022,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 16,
@@ -578,14 +529,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3116_8_4] = {
.pc_DriverName = "apci3116-8-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3023,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannel = 8,
@@ -613,14 +560,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
.ttl_read = i_APCI3XXX_InsnReadTTLIO,
.ttl_write = i_APCI3XXX_InsnWriteTTLIO,
- }, {
+ },
+ [BOARD_APCI3003] = {
.pc_DriverName = "apci3003",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x300B,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannelDiff = 4,
@@ -638,14 +581,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ai_read = i_APCI3XXX_InsnReadAnalogInput,
.di_bits = apci3xxx_di_insn_bits,
.do_bits = apci3xxx_do_insn_bits,
- }, {
+ },
+ [BOARD_APCI3002_16] = {
.pc_DriverName = "apci3002-16",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3002,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannelDiff = 16,
@@ -663,14 +602,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ai_read = i_APCI3XXX_InsnReadAnalogInput,
.di_bits = apci3xxx_di_insn_bits,
.do_bits = apci3xxx_do_insn_bits,
- }, {
+ },
+ [BOARD_APCI3002_8] = {
.pc_DriverName = "apci3002-8",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3003,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannelDiff = 8,
@@ -688,14 +623,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ai_read = i_APCI3XXX_InsnReadAnalogInput,
.di_bits = apci3xxx_di_insn_bits,
.do_bits = apci3xxx_do_insn_bits,
- }, {
+ },
+ [BOARD_APCI3002_4] = {
.pc_DriverName = "apci3002-4",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3004,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAiChannelDiff = 4,
@@ -713,14 +644,10 @@ static const struct addi_board apci3xxx_boardtypes[] = {
.ai_read = i_APCI3XXX_InsnReadAnalogInput,
.di_bits = apci3xxx_di_insn_bits,
.do_bits = apci3xxx_do_insn_bits,
- }, {
+ },
+ [BOARD_APCI3500] = {
.pc_DriverName = "apci3500",
- .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
- .i_DeviceId = 0x3024,
- .i_IorangeBase0 = 256,
.i_IorangeBase1 = 256,
- .i_IorangeBase2 = 256,
- .i_IorangeBase3 = 256,
.i_PCIEeprom = ADDIDATA_NO_EEPROM,
.pc_EepromChip = ADDIDATA_9054,
.i_NbrAoChannel = 4,
@@ -737,48 +664,59 @@ static const struct addi_board apci3xxx_boardtypes[] = {
},
};
+static int apci3xxx_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ const struct addi_board *board = NULL;
+
+ if (context < ARRAY_SIZE(apci3xxx_boardtypes))
+ board = &apci3xxx_boardtypes[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+
+ return addi_auto_attach(dev, context);
+}
+
static struct comedi_driver apci3xxx_driver = {
.driver_name = "addi_apci_3xxx",
.module = THIS_MODULE,
- .auto_attach = addi_auto_attach,
+ .auto_attach = apci3xxx_auto_attach,
.detach = i_ADDI_Detach,
- .num_names = ARRAY_SIZE(apci3xxx_boardtypes),
- .board_name = &apci3xxx_boardtypes[0].pc_DriverName,
- .offset = sizeof(struct addi_board),
};
static int apci3xxx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &apci3xxx_driver);
+ return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(apci3xxx_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3010) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300f) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300e) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3013) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3014) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3015) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3016) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3017) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3018) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3019) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301a) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301b) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301c) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301d) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301e) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x301f) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3020) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3021) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3022) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3023) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x300B) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3002) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3003) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3004) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3024) },
+ { PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 },
+ { PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 },
+ { PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 },
+ { PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 },
+ { PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 },
+ { PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 },
+ { PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 },
+ { PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 },
+ { PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 },
+ { PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 },
+ { PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 },
+ { PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 },
+ { PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table);
diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c
index 375ab665e091..1666b5f510d3 100644
--- a/drivers/staging/comedi/drivers/addi_watchdog.c
+++ b/drivers/staging/comedi/drivers/addi_watchdog.c
@@ -150,12 +150,6 @@ int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase)
}
EXPORT_SYMBOL_GPL(addi_watchdog_init);
-void addi_watchdog_cleanup(struct comedi_subdevice *s)
-{
- kfree(s->private);
-}
-EXPORT_SYMBOL_GPL(addi_watchdog_cleanup);
-
static int __init addi_watchdog_module_init(void)
{
return 0;
diff --git a/drivers/staging/comedi/drivers/addi_watchdog.h b/drivers/staging/comedi/drivers/addi_watchdog.h
index f374a7bff44d..83b47befa4d1 100644
--- a/drivers/staging/comedi/drivers/addi_watchdog.h
+++ b/drivers/staging/comedi/drivers/addi_watchdog.h
@@ -5,6 +5,5 @@
void addi_watchdog_reset(unsigned long iobase);
int addi_watchdog_init(struct comedi_subdevice *, unsigned long iobase);
-void addi_watchdog_cleanup(struct comedi_subdevice *s);
#endif
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 7b3e331616ed..8a438ff1bd45 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -47,12 +47,6 @@ References:
#include "../comedidev.h"
/*
- * ADLINK PCI Device ID's supported by this driver
- */
-#define PCI_DEVICE_ID_PCI6208 0x6208
-#define PCI_DEVICE_ID_PCI6216 0x6216
-
-/*
* PCI-6208/6216-GL register map
*/
#define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x)))
@@ -66,20 +60,23 @@ References:
#define PCI6208_MAX_AO_CHANNELS 16
+enum pci6208_boardid {
+ BOARD_PCI6208,
+ BOARD_PCI6216,
+};
+
struct pci6208_board {
const char *name;
- unsigned short dev_id;
int ao_chans;
};
static const struct pci6208_board pci6208_boards[] = {
- {
+ [BOARD_PCI6208] = {
.name = "adl_pci6208",
- .dev_id = PCI_DEVICE_ID_PCI6208,
.ao_chans = 8,
- }, {
+ },
+ [BOARD_PCI6216] = {
.name = "adl_pci6216",
- .dev_id = PCI_DEVICE_ID_PCI6216,
.ao_chans = 16,
},
};
@@ -162,31 +159,18 @@ static int pci6208_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static const void *pci6208_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct pci6208_board *boardinfo;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
- boardinfo = &pci6208_boards[i];
- if (boardinfo->dev_id == pcidev->device)
- return boardinfo;
- }
- return NULL;
-}
-
static int pci6208_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct pci6208_board *boardinfo;
+ const struct pci6208_board *boardinfo = NULL;
struct pci6208_private *devpriv;
struct comedi_subdevice *s;
unsigned int val;
int ret;
- boardinfo = pci6208_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(pci6208_boards))
+ boardinfo = &pci6208_boards[context];
if (!boardinfo)
return -ENODEV;
dev->board_ptr = boardinfo;
@@ -197,7 +181,7 @@ static int pci6208_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -249,32 +233,23 @@ static int pci6208_auto_attach(struct comedi_device *dev,
return 0;
}
-static void pci6208_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver adl_pci6208_driver = {
.driver_name = "adl_pci6208",
.module = THIS_MODULE,
.auto_attach = pci6208_auto_attach,
- .detach = pci6208_detach,
+ .detach = comedi_pci_disable,
};
static int adl_pci6208_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adl_pci6208_driver);
+ return comedi_pci_auto_config(dev, &adl_pci6208_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6208) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6216) },
+ { PCI_VDEVICE(ADLINK, 0x6208), BOARD_PCI6208 },
+ { PCI_VDEVICE(ADLINK, 0x6216), BOARD_PCI6216 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index f27f48e6e702..e3960745f506 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -53,60 +53,57 @@ Configuration Options: not applicable, uses comedi PCI auto config
#include "../comedidev.h"
/*
- * PCI Device ID's supported by this driver
- */
-#define PCI_DEVICE_ID_PCI7230 0x7230
-#define PCI_DEVICE_ID_PCI7233 0x7233
-#define PCI_DEVICE_ID_PCI7234 0x7234
-#define PCI_DEVICE_ID_PCI7432 0x7432
-#define PCI_DEVICE_ID_PCI7433 0x7433
-#define PCI_DEVICE_ID_PCI7434 0x7434
-
-/*
* Register I/O map (32-bit access only)
*/
#define PCI7X3X_DIO_REG 0x00
#define PCI743X_DIO_REG 0x04
+enum apci1516_boardid {
+ BOARD_PCI7230,
+ BOARD_PCI7233,
+ BOARD_PCI7234,
+ BOARD_PCI7432,
+ BOARD_PCI7433,
+ BOARD_PCI7434,
+};
+
struct adl_pci7x3x_boardinfo {
const char *name;
- unsigned short device;
int nsubdevs;
int di_nchan;
int do_nchan;
};
static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
- {
+ [BOARD_PCI7230] = {
.name = "adl_pci7230",
- .device = PCI_DEVICE_ID_PCI7230,
.nsubdevs = 2,
.di_nchan = 16,
.do_nchan = 16,
- }, {
+ },
+ [BOARD_PCI7233] = {
.name = "adl_pci7233",
- .device = PCI_DEVICE_ID_PCI7233,
.nsubdevs = 1,
.di_nchan = 32,
- }, {
+ },
+ [BOARD_PCI7234] = {
.name = "adl_pci7234",
- .device = PCI_DEVICE_ID_PCI7234,
.nsubdevs = 1,
.do_nchan = 32,
- }, {
+ },
+ [BOARD_PCI7432] = {
.name = "adl_pci7432",
- .device = PCI_DEVICE_ID_PCI7432,
.nsubdevs = 2,
.di_nchan = 32,
.do_nchan = 32,
- }, {
+ },
+ [BOARD_PCI7433] = {
.name = "adl_pci7433",
- .device = PCI_DEVICE_ID_PCI7433,
.nsubdevs = 2,
.di_nchan = 64,
- }, {
+ },
+ [BOARD_PCI7434] = {
.name = "adl_pci7434",
- .device = PCI_DEVICE_ID_PCI7434,
.nsubdevs = 2,
.do_nchan = 64,
}
@@ -150,37 +147,24 @@ static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static const void *adl_pci7x3x_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct adl_pci7x3x_boardinfo *board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(adl_pci7x3x_boards); i++) {
- board = &adl_pci7x3x_boards[i];
- if (pcidev->device == board->device)
- return board;
- }
- return NULL;
-}
-
static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct adl_pci7x3x_boardinfo *board;
+ const struct adl_pci7x3x_boardinfo *board = NULL;
struct comedi_subdevice *s;
int subdev;
int nchan;
int ret;
- board = adl_pci7x3x_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(adl_pci7x3x_boards))
+ board = &adl_pci7x3x_boards[context];
if (!board)
return -ENODEV;
dev->board_ptr = board;
dev->board_name = board->name;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -275,36 +259,27 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
return 0;
}
-static void adl_pci7x3x_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver adl_pci7x3x_driver = {
.driver_name = "adl_pci7x3x",
.module = THIS_MODULE,
.auto_attach = adl_pci7x3x_auto_attach,
- .detach = adl_pci7x3x_detach,
+ .detach = comedi_pci_disable,
};
static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adl_pci7x3x_driver);
+ return comedi_pci_auto_config(dev, &adl_pci7x3x_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7233) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7234) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7433) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7434) },
+ { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 },
+ { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 },
+ { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 },
+ { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 },
+ { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 },
+ { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index d06b83f38653..b3ec60afe3a0 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -1,217 +1,74 @@
/*
- comedi/drivers/adl_pci8164.c
-
- Hardware comedi driver fot PCI-8164 Adlink card
- Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * comedi/drivers/adl_pci8164.c
+ *
+ * Hardware comedi driver for PCI-8164 Adlink card
+ * Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
-*/
/*
-Driver: adl_pci8164
-Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
-Devices: [ADLink] PCI-8164 (adl_pci8164)
-Author: Michel Lachaine <mike@mikelachaine.ca>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:10:32 +0100
-
-Configuration Options: not applicable, uses PCI auto config
-*/
+ * Driver: adl_pci8164
+ * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
+ * Devices: (ADLink) PCI-8164 [adl_pci8164]
+ * Author: Michel Lachaine <mike@mikelachaine.ca>
+ * Status: experimental
+ * Updated: Mon, 14 Apr 2008 15:10:32 +0100
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/delay.h>
#include "../comedidev.h"
-#include "comedi_fc.h"
-#include "8253.h"
-
-#define PCI8164_AXIS_X 0x00
-#define PCI8164_AXIS_Y 0x08
-#define PCI8164_AXIS_Z 0x10
-#define PCI8164_AXIS_U 0x18
-#define PCI8164_MSTS 0x00
-#define PCI8164_SSTS 0x02
-#define PCI8164_BUF0 0x04
-#define PCI8164_BUF1 0x06
-
-#define PCI8164_CMD 0x00
-#define PCI8164_OTP 0x02
-
-#define PCI_DEVICE_ID_PCI8164 0x8164
-
-/*
- all the read commands are the same except for the addition a constant
- * const to the data for inw()
- */
-static void adl_pci8164_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data,
- char *action, unsigned short offset)
-{
- int axis, axis_reg;
- char axisname;
-
- axis = CR_CHAN(insn->chanspec);
-
- switch (axis) {
- case 0:
- axis_reg = PCI8164_AXIS_X;
- axisname = 'X';
- break;
- case 1:
- axis_reg = PCI8164_AXIS_Y;
- axisname = 'Y';
- break;
- case 2:
- axis_reg = PCI8164_AXIS_Z;
- axisname = 'Z';
- break;
- case 3:
- axis_reg = PCI8164_AXIS_U;
- axisname = 'U';
- break;
- default:
- axis_reg = PCI8164_AXIS_X;
- axisname = 'X';
- }
-
- data[0] = inw(dev->iobase + axis_reg + offset);
- dev_dbg(dev->class_dev,
- "pci8164 %s read -> %04X:%04X on axis %c\n",
- action, data[0], data[1], axisname);
-}
-
-static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
- return 2;
-}
-
-static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
- return 2;
-}
-
-static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
- return 2;
-}
+#define PCI8164_AXIS(x) ((x) * 0x08)
+#define PCI8164_CMD_MSTS_REG 0x00
+#define PCI8164_OTP_SSTS_REG 0x02
+#define PCI8164_BUF0_REG 0x04
+#define PCI8164_BUF1_REG 0x06
-static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
- return 2;
-}
-
-/*
- all the write commands are the same except for the addition a constant
- * const to the data for outw()
- */
-static void adl_pci8164_insn_out(struct comedi_device *dev,
+static int adl_pci8164_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data,
- char *action, unsigned short offset)
+ unsigned int *data)
{
- unsigned int axis, axis_reg;
-
- char axisname;
-
- axis = CR_CHAN(insn->chanspec);
+ unsigned long offset = (unsigned long)s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
- switch (axis) {
- case 0:
- axis_reg = PCI8164_AXIS_X;
- axisname = 'X';
- break;
- case 1:
- axis_reg = PCI8164_AXIS_Y;
- axisname = 'Y';
- break;
- case 2:
- axis_reg = PCI8164_AXIS_Z;
- axisname = 'Z';
- break;
- case 3:
- axis_reg = PCI8164_AXIS_U;
- axisname = 'U';
- break;
- default:
- axis_reg = PCI8164_AXIS_X;
- axisname = 'X';
- }
-
- outw(data[0], dev->iobase + axis_reg + offset);
-
- dev_dbg(dev->class_dev,
- "pci8164 %s write -> %04X:%04X on axis %c\n",
- action, data[0], data[1], axisname);
+ for (i = 0; i < insn->n; i++)
+ data[i] = inw(dev->iobase + PCI8164_AXIS(chan) + offset);
+ return insn->n;
}
-static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
- return 2;
-}
-
-static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int adl_pci8164_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
- return 2;
-}
+ unsigned long offset = (unsigned long)s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
-static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
- return 2;
-}
+ for (i = 0; i < insn->n; i++)
+ outw(data[i], dev->iobase + PCI8164_AXIS(chan) + offset);
-static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
- return 2;
+ return insn->n;
}
static int adl_pci8164_auto_attach(struct comedi_device *dev,
@@ -221,9 +78,7 @@ static int adl_pci8164_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -232,77 +87,70 @@ static int adl_pci8164_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
+ /* read MSTS register / write CMD register for each axis (channel) */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_msts;
- s->insn_write = adl_pci8164_insn_write_cmd;
-
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ s->insn_read = adl_pci8164_insn_read;
+ s->insn_write = adl_pci8164_insn_write;
+ s->private = (void *)PCI8164_CMD_MSTS_REG;
+
+ /* read SSTS register / write OTP register for each axis (channel) */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_ssts;
- s->insn_write = adl_pci8164_insn_write_otp;
-
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ s->insn_read = adl_pci8164_insn_read;
+ s->insn_write = adl_pci8164_insn_write;
+ s->private = (void *)PCI8164_OTP_SSTS_REG;
+
+ /* read/write BUF0 register for each axis (channel) */
s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf0;
- s->insn_write = adl_pci8164_insn_write_buf0;
-
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ s->insn_read = adl_pci8164_insn_read;
+ s->insn_write = adl_pci8164_insn_write;
+ s->private = (void *)PCI8164_BUF0_REG;
+
+ /* read/write BUF1 register for each axis (channel) */
s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf1;
- s->insn_write = adl_pci8164_insn_write_buf1;
-
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ s->insn_read = adl_pci8164_insn_read;
+ s->insn_write = adl_pci8164_insn_write;
+ s->private = (void *)PCI8164_BUF1_REG;
return 0;
}
-static void adl_pci8164_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver adl_pci8164_driver = {
.driver_name = "adl_pci8164",
.module = THIS_MODULE,
.auto_attach = adl_pci8164_auto_attach,
- .detach = adl_pci8164_detach,
+ .detach = comedi_pci_disable,
};
static int adl_pci8164_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adl_pci8164_driver);
+ return comedi_pci_auto_config(dev, &adl_pci8164_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
- {0}
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index eeb10ec7f178..6247fdcedcbf 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -75,6 +75,7 @@ TODO:
#include "../comedidev.h"
#include "8253.h"
+#include "plx9052.h"
#include "comedi_fc.h"
#define PCI9111_DRIVER_NAME "adl_pci9111"
@@ -120,6 +121,14 @@ TODO:
#define PCI9111_8254_BASE_REG 0x40
#define PCI9111_INT_CLR_REG 0x48
+/* PLX 9052 Local Interrupt 1 enabled and active */
+#define PCI9111_LI1_ACTIVE (PLX9052_INTCSR_LI1ENAB | \
+ PLX9052_INTCSR_LI1STAT)
+
+/* PLX 9052 Local Interrupt 2 enabled and active */
+#define PCI9111_LI2_ACTIVE (PLX9052_INTCSR_LI2ENAB | \
+ PLX9052_INTCSR_LI2STAT)
+
static const struct comedi_lrange pci9111_ai_range = {
5,
{
@@ -150,17 +159,6 @@ struct pci9111_private_data {
short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE];
};
-#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c
-
-#define PLX9050_LINTI1_ENABLE (1 << 0)
-#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1)
-#define PLX9050_LINTI1_STATUS (1 << 2)
-#define PLX9050_LINTI2_ENABLE (1 << 3)
-#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4)
-#define PLX9050_LINTI2_STATUS (1 << 5)
-#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6)
-#define PLX9050_SOFTWARE_INTERRUPT (1 << 7)
-
static void plx9050_interrupt_control(unsigned long io_base,
bool LINTi1_enable,
bool LINTi1_active_high,
@@ -171,18 +169,18 @@ static void plx9050_interrupt_control(unsigned long io_base,
int flags = 0;
if (LINTi1_enable)
- flags |= PLX9050_LINTI1_ENABLE;
+ flags |= PLX9052_INTCSR_LI1ENAB;
if (LINTi1_active_high)
- flags |= PLX9050_LINTI1_ACTIVE_HIGH;
+ flags |= PLX9052_INTCSR_LI1POL;
if (LINTi2_enable)
- flags |= PLX9050_LINTI2_ENABLE;
+ flags |= PLX9052_INTCSR_LI2ENAB;
if (LINTi2_active_high)
- flags |= PLX9050_LINTI2_ACTIVE_HIGH;
+ flags |= PLX9052_INTCSR_LI2POL;
if (interrupt_enable)
- flags |= PLX9050_PCI_INTERRUPT_ENABLE;
+ flags |= PLX9052_INTCSR_PCIENAB;
- outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL);
+ outb(flags, io_base + PLX9052_INTCSR);
}
static void pci9111_timer_set(struct comedi_device *dev)
@@ -607,21 +605,17 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
spin_lock_irqsave(&dev->spinlock, irq_flags);
/* Check if we are source of interrupt */
- intcsr = inb(dev_private->lcr_io_base +
- PLX9050_REGISTER_INTERRUPT_CONTROL);
- if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0)
- && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
- == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS))
- || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))
- == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) {
+ intcsr = inb(dev_private->lcr_io_base + PLX9052_INTCSR);
+ if (!(((intcsr & PLX9052_INTCSR_PCIENAB) != 0) &&
+ (((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) ||
+ ((intcsr & PCI9111_LI2_ACTIVE) == PCI9111_LI2_ACTIVE)))) {
/* Not the source of the interrupt. */
- /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */
+ /* (N.B. not using PLX9052_INTCSR_SOFTINT) */
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
return IRQ_NONE;
}
- if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) ==
- (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) {
+ if ((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) {
/* Interrupt comes from fifo_half-full signal */
status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG);
@@ -865,14 +859,12 @@ static int pci9111_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
dev_private = kzalloc(sizeof(*dev_private), GFP_KERNEL);
if (!dev_private)
return -ENOMEM;
dev->private = dev_private;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev_private->lcr_io_base = pci_resource_start(pcidev, 1);
@@ -939,16 +931,11 @@ static int pci9111_auto_attach(struct comedi_device *dev,
static void pci9111_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
pci9111_reset(dev);
if (dev->irq != 0)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver adl_pci9111_driver = {
@@ -959,9 +946,10 @@ static struct comedi_driver adl_pci9111_driver = {
};
static int pci9111_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adl_pci9111_driver);
+ return comedi_pci_auto_config(dev, &adl_pci9111_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 4dbac7459a48..cb4ef2dcbf02 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -1970,12 +1970,9 @@ static int pci9118_common_attach(struct comedi_device *dev, int disable_irq,
u16 u16w;
dev->board_name = this_board->name;
- ret = comedi_pci_enable(pcidev, dev->board_name);
- if (ret) {
- dev_err(dev->class_dev,
- "cannot enable PCI device %s\n", pci_name(pcidev));
+ ret = comedi_pci_enable(dev);
+ if (ret)
return ret;
- }
if (master)
pci_set_master(pcidev);
@@ -2202,12 +2199,9 @@ static void pci9118_detach(struct comedi_device *dev)
free_pages((unsigned long)devpriv->dmabuf_virt[1],
devpriv->dmabuf_pages[1]);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
-
+ comedi_pci_disable(dev);
+ if (pcidev)
pci_dev_put(pcidev);
- }
}
static struct comedi_driver adl_pci9118_driver = {
@@ -2222,9 +2216,10 @@ static struct comedi_driver adl_pci9118_driver = {
};
static int adl_pci9118_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adl_pci9118_driver);
+ return comedi_pci_auto_config(dev, &adl_pci9118_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index f7950dfe2ddb..71142e36e7fb 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -213,43 +213,19 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct adq12b_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
- int unipolar, differential;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
- unipolar = it->options[1];
- differential = it->options[2];
-
- printk(KERN_INFO "comedi%d: adq12b called with options base=0x%03lx, "
- "%s and %s\n", dev->minor, iobase,
- (unipolar == 1) ? "unipolar" : "bipolar",
- (differential == 1) ? "differential" : "single-ended");
-
- /* if no address was specified, try the default 0x300 */
- if (iobase == 0) {
- printk(KERN_WARNING "comedi%d: adq12b warning: I/O base "
- "address not specified. Trying the default 0x300.\n",
- dev->minor);
- iobase = 0x300;
- }
-
- printk("comedi%d: adq12b: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, ADQ12B_SIZE, "adq12b")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], ADQ12B_SIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- devpriv->unipolar = unipolar;
- devpriv->differential = differential;
+ devpriv->unipolar = it->options[1];
+ devpriv->differential = it->options[2];
devpriv->digital_state = 0;
/*
* initialize channel and range to -1 so we make sure we
@@ -265,7 +241,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s = &dev->subdevices[0];
/* analog input subdevice */
s->type = COMEDI_SUBD_AI;
- if (differential) {
+ if (devpriv->differential) {
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
s->n_chan = 8;
} else {
@@ -273,7 +249,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->n_chan = 16;
}
- if (unipolar)
+ if (devpriv->unipolar)
s->range_table = &range_adq12b_ai_unipolar;
else
s->range_table = &range_adq12b_ai_bipolar;
@@ -302,22 +278,14 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_digital;
s->insn_bits = adq12b_do_insn_bits;
- printk(KERN_INFO "attached\n");
-
return 0;
}
-static void adq12b_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, ADQ12B_SIZE);
-}
-
static struct comedi_driver adq12b_driver = {
.driver_name = "adq12b",
.module = THIS_MODULE,
.attach = adq12b_attach,
- .detach = adq12b_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(adq12b_driver);
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 3d788c76d648..f847bbc175e7 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -59,9 +59,6 @@ Configuration options:
#define TYPE_PCI1713 2
#define TYPE_PCI1720 3
-#define IORANGE_171x 32
-#define IORANGE_1720 16
-
#define PCI171x_AD_DATA 0 /* R: A/D data */
#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
#define PCI171x_RANGE 2 /* W: A/D gain/range register */
@@ -178,10 +175,17 @@ static const struct comedi_lrange range_pci171x_da = { 2, {
}
};
+enum pci1710_boardid {
+ BOARD_PCI1710,
+ BOARD_PCI1710HG,
+ BOARD_PCI1711,
+ BOARD_PCI1713,
+ BOARD_PCI1720,
+ BOARD_PCI1731,
+};
+
struct boardtype {
const char *name; /* board name */
- int device_id;
- int iorange; /* I/O range len */
char have_irq; /* 1=card support IRQ */
char cardtype; /* 0=1710& co. 2=1713, ... */
int n_aichan; /* num of A/D chans */
@@ -200,10 +204,8 @@ struct boardtype {
};
static const struct boardtype boardtypes[] = {
- {
+ [BOARD_PCI1710] = {
.name = "pci1710",
- .device_id = 0x1710,
- .iorange = IORANGE_171x,
.have_irq = 1,
.cardtype = TYPE_PCI171X,
.n_aichan = 16,
@@ -219,10 +221,9 @@ static const struct boardtype boardtypes[] = {
.rangelist_ao = &range_pci171x_da,
.ai_ns_min = 10000,
.fifo_half_size = 2048,
- }, {
+ },
+ [BOARD_PCI1710HG] = {
.name = "pci1710hg",
- .device_id = 0x1710,
- .iorange = IORANGE_171x,
.have_irq = 1,
.cardtype = TYPE_PCI171X,
.n_aichan = 16,
@@ -238,10 +239,9 @@ static const struct boardtype boardtypes[] = {
.rangelist_ao = &range_pci171x_da,
.ai_ns_min = 10000,
.fifo_half_size = 2048,
- }, {
+ },
+ [BOARD_PCI1711] = {
.name = "pci1711",
- .device_id = 0x1711,
- .iorange = IORANGE_171x,
.have_irq = 1,
.cardtype = TYPE_PCI171X,
.n_aichan = 16,
@@ -256,10 +256,9 @@ static const struct boardtype boardtypes[] = {
.rangelist_ao = &range_pci171x_da,
.ai_ns_min = 10000,
.fifo_half_size = 512,
- }, {
+ },
+ [BOARD_PCI1713] = {
.name = "pci1713",
- .device_id = 0x1713,
- .iorange = IORANGE_171x,
.have_irq = 1,
.cardtype = TYPE_PCI1713,
.n_aichan = 32,
@@ -269,18 +268,16 @@ static const struct boardtype boardtypes[] = {
.rangecode_ai = range_codes_pci1710_3,
.ai_ns_min = 10000,
.fifo_half_size = 2048,
- }, {
+ },
+ [BOARD_PCI1720] = {
.name = "pci1720",
- .device_id = 0x1720,
- .iorange = IORANGE_1720,
.cardtype = TYPE_PCI1720,
.n_aochan = 4,
.ao_maxdata = 0x0fff,
.rangelist_ao = &range_pci1720,
- }, {
+ },
+ [BOARD_PCI1731] = {
.name = "pci1731",
- .device_id = 0x1731,
- .iorange = IORANGE_171x,
.have_irq = 1,
.cardtype = TYPE_PCI171X,
.n_aichan = 16,
@@ -307,7 +304,7 @@ struct pci1710_private {
unsigned int ai_et_CntrlReg;
unsigned int ai_et_MuxVal;
unsigned int ai_et_div1, ai_et_div2;
- unsigned int act_chanlist[32]; /* list of scaned channel */
+ unsigned int act_chanlist[32]; /* list of scanned channel */
unsigned char act_chanlist_len; /* len of scanlist */
unsigned char act_chanlist_pos; /* actual position in MUX list */
unsigned char da_ranges; /* copy of D/A outpit range register */
@@ -334,7 +331,7 @@ static const unsigned int muxonechan[] = {
/*
==============================================================================
- Check if channel list from user is builded correctly
+ Check if channel list from user is built correctly
If it's ok, then program scan/gain logic.
This works for all cards.
*/
@@ -1220,30 +1217,17 @@ static int pci1710_reset(struct comedi_device *dev)
}
}
-static const void *pci1710_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct boardtype *this_board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
- this_board = &boardtypes[i];
- if (pcidev->device == this_board->device_id)
- return this_board;
- }
- return NULL;
-}
-
static int pci1710_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct boardtype *this_board;
+ const struct boardtype *this_board = NULL;
struct pci1710_private *devpriv;
struct comedi_subdevice *s;
int ret, subdev, n_subdevices;
- this_board = pci1710_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(boardtypes))
+ this_board = &boardtypes[context];
if (!this_board)
return -ENODEV;
dev->board_ptr = this_board;
@@ -1254,7 +1238,7 @@ static int pci1710_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -1378,16 +1362,11 @@ static int pci1710_auto_attach(struct comedi_device *dev,
static void pci1710_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->iobase)
pci1710_reset(dev);
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver adv_pci1710_driver = {
@@ -1398,17 +1377,68 @@ static struct comedi_driver adv_pci1710_driver = {
};
static int adv_pci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adv_pci1710_driver);
+ return comedi_pci_auto_config(dev, &adv_pci1710_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
+ {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0x0000),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xb100),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xb200),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xc100),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xc200),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
+ .driver_data = BOARD_PCI1710,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0x0002),
+ .driver_data = BOARD_PCI1710HG,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xb102),
+ .driver_data = BOARD_PCI1710HG,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xb202),
+ .driver_data = BOARD_PCI1710HG,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xc102),
+ .driver_data = BOARD_PCI1710HG,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
+ PCI_VENDOR_ID_ADVANTECH, 0xc202),
+ .driver_data = BOARD_PCI1710HG,
+ }, {
+ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
+ .driver_data = BOARD_PCI1710HG,
+ },
+ { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
+ { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
+ { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
+ { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 02ce55a01d2a..ccc114d6c08b 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -242,14 +242,12 @@ static int pci1723_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -306,14 +304,9 @@ static int pci1723_auto_attach(struct comedi_device *dev,
static void pci1723_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase) {
- pci1723_reset(dev);
- comedi_pci_disable(pcidev);
- }
- }
+ if (dev->iobase)
+ pci1723_reset(dev);
+ comedi_pci_disable(dev);
}
static struct comedi_driver adv_pci1723_driver = {
@@ -324,9 +317,10 @@ static struct comedi_driver adv_pci1723_driver = {
};
static int adv_pci1723_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adv_pci1723_driver);
+ return comedi_pci_auto_config(dev, &adv_pci1723_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
new file mode 100644
index 000000000000..e60f12578d44
--- /dev/null
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -0,0 +1,409 @@
+/*
+ comedi/drivers/adv_pci1724.c
+ This is a driver for the Advantech PCI-1724U card.
+
+ Author: Frank Mori Hess <fmh6jj@gmail.com>
+ Copyright (C) 2013 GnuBIO Inc
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+************************************************************************/
+
+/*
+
+Driver: adv_1724
+Description: Advantech PCI-1724U
+Author: Frank Mori Hess <fmh6jj@gmail.com>
+Status: works
+Updated: 2013-02-09
+Devices: [Advantech] PCI-1724U (adv_pci1724)
+
+Subdevice 0 is the analog output.
+Subdevice 1 is the offset calibration for the analog output.
+Subdevice 2 is the gain calibration for the analog output.
+
+The calibration offset and gains have quite a large effect
+on the analog output, so it is possible to adjust the analog output to
+have an output range significantly different from the board's
+nominal output ranges. For a calibrated +/- 10V range, the analog
+output's offset will be set somewhere near mid-range (0x2000) and its
+gain will be near maximum (0x3fff).
+
+There is really no difference between the board's documented 0-20mA
+versus 4-20mA output ranges. To pick one or the other is simply a matter
+of adjusting the offset and gain calibration until the board outputs in
+the desired range.
+
+Configuration options:
+ None
+
+Manual configuration of comedi devices is not supported by this driver;
+supported PCI devices are configured as comedi devices automatically.
+
+*/
+
+#include <linux/pci.h>
+
+#include "../comedidev.h"
+
+#define PCI_VENDOR_ID_ADVANTECH 0x13fe
+
+#define NUM_AO_CHANNELS 32
+
+/* register offsets */
+enum board_registers {
+ DAC_CONTROL_REG = 0x0,
+ SYNC_OUTPUT_REG = 0x4,
+ EEPROM_CONTROL_REG = 0x8,
+ SYNC_OUTPUT_TRIGGER_REG = 0xc,
+ BOARD_ID_REG = 0x10
+};
+
+/* bit definitions for registers */
+enum dac_control_contents {
+ DAC_DATA_MASK = 0x3fff,
+ DAC_DESTINATION_MASK = 0xc000,
+ DAC_NORMAL_MODE = 0xc000,
+ DAC_OFFSET_MODE = 0x8000,
+ DAC_GAIN_MODE = 0x4000,
+ DAC_CHANNEL_SELECT_MASK = 0xf0000,
+ DAC_GROUP_SELECT_MASK = 0xf00000
+};
+
+static uint32_t dac_data_bits(uint16_t dac_data)
+{
+ return dac_data & DAC_DATA_MASK;
+}
+
+static uint32_t dac_channel_select_bits(unsigned channel)
+{
+ return (channel << 16) & DAC_CHANNEL_SELECT_MASK;
+}
+
+static uint32_t dac_group_select_bits(unsigned group)
+{
+ return (1 << (20 + group)) & DAC_GROUP_SELECT_MASK;
+}
+
+static uint32_t dac_channel_and_group_select_bits(unsigned comedi_channel)
+{
+ return dac_channel_select_bits(comedi_channel % 8) |
+ dac_group_select_bits(comedi_channel / 8);
+}
+
+enum sync_output_contents {
+ SYNC_MODE = 0x1,
+ DAC_BUSY = 0x2, /* dac state machine is not ready */
+};
+
+enum sync_output_trigger_contents {
+ SYNC_TRIGGER_BITS = 0x0 /* any value works */
+};
+
+enum board_id_contents {
+ BOARD_ID_MASK = 0xf
+};
+
+static const struct comedi_lrange ao_ranges_1724 = { 4,
+ {
+ BIP_RANGE(10),
+ RANGE_mA(0, 20),
+ RANGE_mA(4, 20),
+ RANGE_unitless(0, 1)
+ }
+};
+
+static const struct comedi_lrange *const ao_range_list_1724[NUM_AO_CHANNELS] = {
+ [0 ... NUM_AO_CHANNELS - 1] = &ao_ranges_1724,
+};
+
+/* this structure is for data unique to this hardware driver. */
+struct adv_pci1724_private {
+ int ao_value[NUM_AO_CHANNELS];
+ int offset_value[NUM_AO_CHANNELS];
+ int gain_value[NUM_AO_CHANNELS];
+};
+
+static int wait_for_dac_idle(struct comedi_device *dev)
+{
+ static const int timeout = 10000;
+ int i;
+
+ for (i = 0; i < timeout; ++i) {
+ if ((inl(dev->iobase + SYNC_OUTPUT_REG) & DAC_BUSY) == 0)
+ break;
+ udelay(1);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "Timed out waiting for dac to become idle.");
+ return -EIO;
+ }
+ return 0;
+}
+
+static int set_dac(struct comedi_device *dev, unsigned mode, unsigned channel,
+ unsigned data)
+{
+ int retval;
+ unsigned control_bits;
+
+ retval = wait_for_dac_idle(dev);
+ if (retval < 0)
+ return retval;
+
+ control_bits = mode;
+ control_bits |= dac_channel_and_group_select_bits(channel);
+ control_bits |= dac_data_bits(data);
+ outl(control_bits, dev->iobase + DAC_CONTROL_REG);
+ return 0;
+}
+
+static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ int channel = CR_CHAN(insn->chanspec);
+ int retval;
+ int i;
+
+ /* turn off synchronous mode */
+ outl(0, dev->iobase + SYNC_OUTPUT_REG);
+
+ for (i = 0; i < insn->n; ++i) {
+ retval = set_dac(dev, DAC_NORMAL_MODE, channel, data[i]);
+ if (retval < 0)
+ return retval;
+ devpriv->ao_value[channel] = data[i];
+ }
+ return insn->n;
+}
+
+static int ao_readback_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ int channel = CR_CHAN(insn->chanspec);
+ int i;
+
+ if (devpriv->ao_value[channel] < 0) {
+ comedi_error(dev,
+ "Cannot read back channels which have not yet been written to.");
+ return -EIO;
+ }
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_value[channel];
+
+ return insn->n;
+}
+
+static int offset_write_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ int channel = CR_CHAN(insn->chanspec);
+ int retval;
+ int i;
+
+ /* turn off synchronous mode */
+ outl(0, dev->iobase + SYNC_OUTPUT_REG);
+
+ for (i = 0; i < insn->n; ++i) {
+ retval = set_dac(dev, DAC_OFFSET_MODE, channel, data[i]);
+ if (retval < 0)
+ return retval;
+ devpriv->offset_value[channel] = data[i];
+ }
+
+ return insn->n;
+}
+
+static int offset_read_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ unsigned int channel = CR_CHAN(insn->chanspec);
+ int i;
+
+ if (devpriv->offset_value[channel] < 0) {
+ comedi_error(dev,
+ "Cannot read back channels which have not yet been written to.");
+ return -EIO;
+ }
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->offset_value[channel];
+
+ return insn->n;
+}
+
+static int gain_write_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ int channel = CR_CHAN(insn->chanspec);
+ int retval;
+ int i;
+
+ /* turn off synchronous mode */
+ outl(0, dev->iobase + SYNC_OUTPUT_REG);
+
+ for (i = 0; i < insn->n; ++i) {
+ retval = set_dac(dev, DAC_GAIN_MODE, channel, data[i]);
+ if (retval < 0)
+ return retval;
+ devpriv->gain_value[channel] = data[i];
+ }
+
+ return insn->n;
+}
+
+static int gain_read_insn(struct comedi_device *dev,
+ struct comedi_subdevice *s, struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct adv_pci1724_private *devpriv = dev->private;
+ unsigned int channel = CR_CHAN(insn->chanspec);
+ int i;
+
+ if (devpriv->gain_value[channel] < 0) {
+ comedi_error(dev,
+ "Cannot read back channels which have not yet been written to.");
+ return -EIO;
+ }
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->gain_value[channel];
+
+ return insn->n;
+}
+
+/* Allocate and initialize the subdevice structures.
+ */
+static int setup_subdevices(struct comedi_device *dev)
+{
+ struct comedi_subdevice *s;
+ int ret;
+
+ ret = comedi_alloc_subdevices(dev, 3);
+ if (ret)
+ return ret;
+
+ /* analog output subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = NUM_AO_CHANNELS;
+ s->maxdata = 0x3fff;
+ s->range_table_list = ao_range_list_1724;
+ s->insn_read = ao_readback_insn;
+ s->insn_write = ao_winsn;
+
+ /* offset calibration */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = NUM_AO_CHANNELS;
+ s->insn_read = offset_read_insn;
+ s->insn_write = offset_write_insn;
+ s->maxdata = 0x3fff;
+
+ /* gain calibration */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = NUM_AO_CHANNELS;
+ s->insn_read = gain_read_insn;
+ s->insn_write = gain_write_insn;
+ s->maxdata = 0x3fff;
+
+ return 0;
+}
+
+static int adv_pci1724_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct adv_pci1724_private *devpriv;
+ int i;
+ int retval;
+ unsigned int board_id;
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ /* init software copies of output values to indicate we don't know
+ * what the output value is since it has never been written. */
+ for (i = 0; i < NUM_AO_CHANNELS; ++i) {
+ devpriv->ao_value[i] = -1;
+ devpriv->offset_value[i] = -1;
+ devpriv->gain_value[i] = -1;
+ }
+
+ retval = comedi_pci_enable(dev);
+ if (retval)
+ return retval;
+
+ dev->iobase = pci_resource_start(pcidev, 2);
+ board_id = inl(dev->iobase + BOARD_ID_REG) & BOARD_ID_MASK;
+ dev_info(dev->class_dev, "board id: %d\n", board_id);
+
+ retval = setup_subdevices(dev);
+ if (retval < 0)
+ return retval;
+
+ dev_info(dev->class_dev, "%s (pci %s) attached, board id: %u\n",
+ dev->board_name, pci_name(pcidev), board_id);
+ return 0;
+}
+
+static struct comedi_driver adv_pci1724_driver = {
+ .driver_name = "adv_pci1724",
+ .module = THIS_MODULE,
+ .auto_attach = adv_pci1724_auto_attach,
+ .detach = comedi_pci_disable,
+};
+
+static int adv_pci1724_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &adv_pci1724_driver,
+ id->driver_data);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1724_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1724) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adv_pci1724_pci_table);
+
+static struct pci_driver adv_pci1724_pci_driver = {
+ .name = "adv_pci1724",
+ .id_table = adv_pci1724_pci_table,
+ .probe = adv_pci1724_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+
+module_comedi_pci_driver(adv_pci1724_driver, adv_pci1724_pci_driver);
+
+MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>");
+MODULE_DESCRIPTION("Advantech PCI-1724U Comedi driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 338c43e716ba..f70c67471c13 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -236,8 +236,6 @@ struct diosubd_data {
struct dio_boardtype {
const char *name; /* board name */
- int vendor_id; /* vendor/device PCI ID */
- int device_id;
int main_pci_region; /* main I/O PCI region */
enum hw_cards_id cardtype;
int nsubdevs;
@@ -250,10 +248,8 @@ struct dio_boardtype {
};
static const struct dio_boardtype boardtypes[] = {
- {
+ [TYPE_PCI1730] = {
.name = "pci1730",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1730,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1730,
.nsubdevs = 5,
@@ -263,30 +259,27 @@ static const struct dio_boardtype boardtypes[] = {
.sdo[1] = { 16, PCI1730_IDO, 2, 0, },
.boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1733] = {
.name = "pci1733",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1733,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1733,
.nsubdevs = 2,
.sdi[1] = { 32, PCI1733_IDI, 4, 0, },
.boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1734] = {
.name = "pci1734",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1734,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1734,
.nsubdevs = 2,
.sdo[1] = { 32, PCI1734_IDO, 4, 0, },
.boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1735] = {
.name = "pci1735",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1735,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1735,
.nsubdevs = 4,
@@ -295,10 +288,9 @@ static const struct dio_boardtype boardtypes[] = {
.boardid = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, },
.s8254[0] = { 3, PCI1735_C8254, 1, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1736] = {
.name = "pci1736",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1736,
.main_pci_region = PCI1736_MAINREG,
.cardtype = TYPE_PCI1736,
.nsubdevs = 3,
@@ -306,39 +298,35 @@ static const struct dio_boardtype boardtypes[] = {
.sdo[1] = { 16, PCI1736_IDO, 2, 0, },
.boardid = { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1739] = {
.name = "pci1739",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1739,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1739,
.nsubdevs = 2,
.sdio[0] = { 48, PCI1739_DIO, 2, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1750] = {
.name = "pci1750",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1750,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1750,
.nsubdevs = 2,
.sdi[1] = { 16, PCI1750_IDI, 2, 0, },
.sdo[1] = { 16, PCI1750_IDO, 2, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1751] = {
.name = "pci1751",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1751,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1751,
.nsubdevs = 3,
.sdio[0] = { 48, PCI1751_DIO, 2, 0, },
.s8254[0] = { 3, PCI1751_CNT, 1, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1752] = {
.name = "pci1752",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1752,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1752,
.nsubdevs = 3,
@@ -346,29 +334,26 @@ static const struct dio_boardtype boardtypes[] = {
.sdo[1] = { 32, PCI1752_IDO2, 2, 0, },
.boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_16b,
- }, {
+ },
+ [TYPE_PCI1753] = {
.name = "pci1753",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1753,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1753,
.nsubdevs = 4,
.sdio[0] = { 96, PCI1753_DIO, 4, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1753E] = {
.name = "pci1753e",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1753,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1753E,
.nsubdevs = 8,
.sdio[0] = { 96, PCI1753_DIO, 4, 0, },
.sdio[1] = { 96, PCI1753E_DIO, 4, 0, },
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1754] = {
.name = "pci1754",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1754,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1754,
.nsubdevs = 3,
@@ -376,10 +361,9 @@ static const struct dio_boardtype boardtypes[] = {
.sdi[1] = { 32, PCI1754_IDI2, 2, 0, },
.boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_16b,
- }, {
+ },
+ [TYPE_PCI1756] = {
.name = "pci1756",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1756,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1756,
.nsubdevs = 3,
@@ -387,19 +371,17 @@ static const struct dio_boardtype boardtypes[] = {
.sdo[1] = { 32, PCI1756_IDO, 2, 0, },
.boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
.io_access = IO_16b,
- }, {
+ },
+ [TYPE_PCI1760] = {
/* This card has its own 'attach' */
.name = "pci1760",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1760,
.main_pci_region = 0,
.cardtype = TYPE_PCI1760,
.nsubdevs = 4,
.io_access = IO_8b,
- }, {
+ },
+ [TYPE_PCI1762] = {
.name = "pci1762",
- .vendor_id = PCI_VENDOR_ID_ADVANTECH,
- .device_id = 0x1762,
.main_pci_region = PCIDIO_MAINREG,
.cardtype = TYPE_PCI1762,
.nsubdevs = 3,
@@ -1076,31 +1058,50 @@ static int pci_dio_add_8254(struct comedi_device *dev,
return 0;
}
-static const void *pci_dio_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
+static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
+ unsigned long cardtype)
{
- const struct dio_boardtype *this_board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
- this_board = &boardtypes[i];
- if (this_board->vendor_id == pcidev->vendor &&
- this_board->device_id == pcidev->device)
- return this_board;
+ /*
+ * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
+ * board available. Need to enable PCI device and request the main
+ * registers PCI BAR temporarily to perform the test.
+ */
+ if (cardtype != TYPE_PCI1753)
+ return cardtype;
+ if (pci_enable_device(pcidev) < 0)
+ return cardtype;
+ if (pci_request_region(pcidev, PCIDIO_MAINREG, "adv_pci_dio") == 0) {
+ /*
+ * This test is based on Advantech's "advdaq" driver source
+ * (which declares its module licence as "GPL" although the
+ * driver source does not include a "COPYING" file).
+ */
+ unsigned long reg =
+ pci_resource_start(pcidev, PCIDIO_MAINREG) + 53;
+
+ outb(0x05, reg);
+ if ((inb(reg) & 0x07) == 0x02) {
+ outb(0x02, reg);
+ if ((inb(reg) & 0x07) == 0x05)
+ cardtype = TYPE_PCI1753E;
+ }
+ pci_release_region(pcidev, PCIDIO_MAINREG);
}
- return NULL;
+ pci_disable_device(pcidev);
+ return cardtype;
}
static int pci_dio_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct dio_boardtype *this_board;
+ const struct dio_boardtype *this_board = NULL;
struct pci_dio_private *devpriv;
struct comedi_subdevice *s;
int ret, subdev, i, j;
- this_board = pci_dio_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(boardtypes))
+ this_board = &boardtypes[context];
if (!this_board)
return -ENODEV;
dev->board_ptr = this_board;
@@ -1111,7 +1112,7 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region);
@@ -1172,7 +1173,6 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
static void pci_dio_detach(struct comedi_device *dev)
{
struct pci_dio_private *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct comedi_subdevice *s;
int i;
@@ -1180,18 +1180,13 @@ static void pci_dio_detach(struct comedi_device *dev)
if (devpriv->valid)
pci_dio_reset(dev);
}
- if (dev->subdevices) {
- for (i = 0; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- if (s->type == COMEDI_SUBD_DIO)
- subdev_8255_cleanup(dev, s);
- s->private = NULL;
- }
- }
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ for (i = 0; i < dev->n_subdevices; i++) {
+ s = &dev->subdevices[i];
+ if (s->type == COMEDI_SUBD_DIO)
+ comedi_spriv_free(dev, i);
+ s->private = NULL; /* some private data is static */
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver adv_pci_dio_driver = {
@@ -1202,26 +1197,29 @@ static struct comedi_driver adv_pci_dio_driver = {
};
static int adv_pci_dio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
+ unsigned long cardtype;
+
+ cardtype = pci_dio_override_cardtype(dev, id->driver_data);
+ return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype);
}
static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
+ { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 },
+ { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 },
+ { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 },
+ { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 },
+ { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 },
+ { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 },
+ { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 },
+ { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 },
+ { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 },
+ { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 },
+ { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 },
+ { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 },
+ { PCI_VDEVICE(ADVANTECH, 0x1760), TYPE_PCI1760 },
+ { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index 601f03d5897f..e2dc08a058bc 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -200,17 +200,11 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
const struct aio12_8_boardtype *board = comedi_board(dev);
struct aio12_8_private *devpriv;
struct comedi_subdevice *s;
- int iobase;
int ret;
- dev->board_name = board->name;
-
- iobase = it->options[0];
- if (!request_region(iobase, 32, dev->board_name)) {
- printk(KERN_ERR "I/O port conflict");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], 32);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -250,8 +244,8 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
s = &dev->subdevices[2];
/* 8255 Digital i/o subdevice */
- iobase = dev->iobase + AIO12_8_8255_BASE_REG;
- ret = subdev_8255_init(dev, s, NULL, iobase);
+ ret = subdev_8255_init(dev, s, NULL,
+ dev->iobase + AIO12_8_8255_BASE_REG);
if (ret)
return ret;
@@ -267,10 +261,8 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
static void aio_aio12_8_detach(struct comedi_device *dev)
{
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[2]);
- if (dev->iobase)
- release_region(dev->iobase, 24);
+ comedi_spriv_free(dev, 2);
+ comedi_legacy_detach(dev);
}
static struct comedi_driver aio_aio12_8_driver = {
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 64c1ae58ce7f..126854c05093 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -77,22 +77,12 @@ static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
static int aio_iiro_16_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- int iobase;
struct comedi_subdevice *s;
int ret;
- printk(KERN_INFO "comedi%d: aio_iiro_16: ", dev->minor);
-
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
-
- if (!request_region(iobase, AIO_IIRO_16_SIZE, dev->board_name)) {
- printk("I/O port conflict");
- return -EIO;
- }
-
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], AIO_IIRO_16_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
@@ -114,22 +104,14 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
s->range_table = &range_digital;
s->insn_bits = aio_iiro_16_dio_insn_bits_read;
- printk("attached\n");
-
return 1;
}
-static void aio_iiro_16_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, AIO_IIRO_16_SIZE);
-}
-
static struct comedi_driver aio_iiro_16_driver = {
.driver_name = "aio_iiro_16",
.module = THIS_MODULE,
.attach = aio_iiro_16_attach,
- .detach = aio_iiro_16_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(aio_iiro_16_driver);
diff --git a/drivers/staging/comedi/drivers/am9513.h b/drivers/staging/comedi/drivers/am9513.h
deleted file mode 100644
index 0bb839e51493..000000000000
--- a/drivers/staging/comedi/drivers/am9513.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- module/am9513.h
- value added preprocessor definitions for Am9513 timer chip
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef _AM9513_H_
-#define _AM9513_H_
-
-#if 0
-
-/*
- * Before including this file, the following need to be defined:
- */
-#define Am9513_8BITBUS xxx
-/* or */
-#define Am9513_16BITBUS xxx
-
-#define Am9513_output_control(a) xxx
-#define Am9513_input_status() xxx
-#define Am9513_output_data(a) xxx
-#define Am9513_input_data() xxx
-
-#endif
-
-/*
- *
- */
-
-#ifdef Am9513_8BITBUS
-
-#define Am9513_write_register(reg, val) \
- do { \
- Am9513_output_control(reg); \
- Am9513_output_data(val>>8); \
- Am9513_output_data(val&0xff); \
- } while (0)
-
-#define Am9513_read_register(reg, val) \
- do { \
- Am9513_output_control(reg); \
- val = Am9513_input_data()<<8; \
- val |= Am9513_input_data(); \
- } while (0)
-
-#else /* Am9513_16BITBUS */
-
-#define Am9513_write_register(reg, val) \
- do { \
- Am9513_output_control(reg); \
- Am9513_output_data(val); \
- } while (0)
-
-#define Am9513_read_register(reg, val) \
- do { \
- Am9513_output_control(reg); \
- val = Am9513_input_data(); \
- } while (0)
-
-#endif
-
-#endif
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 7c53dea12c76..297750bef0f7 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -1,10 +1,9 @@
/*
comedi/drivers/amplc_dio200.c
- Driver for Amplicon PC272E and PCI272 DIO boards.
- (Support for other boards in Amplicon 200 series may be added at
- a later date, e.g. PCI215.)
- Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/>
+ Driver for Amplicon PC212E, PC214E, PC215E, PC218E, PC272E.
+
+ Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
COMEDI - Linux Control and Measurement Device Interface
Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
@@ -26,26 +25,23 @@
*/
/*
* Driver: amplc_dio200
- * Description: Amplicon 200 Series Digital I/O
+ * Description: Amplicon 200 Series ISA Digital I/O
* Author: Ian Abbott <abbotti@mev.co.uk>
* Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e),
- * PCI215 (pci215), PCIe215 (pcie215), PC218E (pc218e), PCIe236 (pcie236),
- * PC272E (pc272e), PCI272 (pci272), PCIe296 (pcie296)
- * Updated: Wed, 24 Oct 2012 16:22:34 +0100
+ * PC218E (pc218e), PC272E (pc272e)
+ * Updated: Mon, 18 Mar 2013 14:40:41 +0000
+ *
* Status: works
*
- * Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E:
+ * Configuration options:
* [0] - I/O port base address
* [1] - IRQ (optional, but commands won't work without it)
*
- * Manual configuration of PCI(e) cards is not supported; they are configured
- * automatically.
- *
* Passing a zero for an option is the same as leaving it unspecified.
*
* SUBDEVICES
*
- * PC212E PC214E PC215E/PCI215
+ * PC212E PC214E PC215E
* ------------- ------------- -------------
* Subdevices 6 4 5
* 0 PPI-X PPI-X PPI-X
@@ -55,29 +51,16 @@
* 4 CTR-Z2 INTERRUPT
* 5 INTERRUPT
*
- * PCIe215 PC218E PCIe236
- * ------------- ------------- -------------
- * Subdevices 8 7 8
- * 0 PPI-X CTR-X1 PPI-X
- * 1 UNUSED CTR-X2 UNUSED
- * 2 PPI-Y CTR-Y1 UNUSED
- * 3 UNUSED CTR-Y2 UNUSED
- * 4 CTR-Z1 CTR-Z1 CTR-Z1
- * 5 CTR-Z2 CTR-Z2 CTR-Z2
- * 6 TIMER INTERRUPT TIMER
- * 7 INTERRUPT INTERRUPT
- *
- * PC272E/PCI272 PCIe296
+ * PC218E PC272E
* ------------- -------------
- * Subdevices 4 8
- * 0 PPI-X PPI-X1
- * 1 PPI-Y PPI-X2
- * 2 PPI-Z PPI-Y1
- * 3 INTERRUPT PPI-Y2
- * 4 CTR-Z1
- * 5 CTR-Z2
- * 6 TIMER
- * 7 INTERRUPT
+ * Subdevices 7 4
+ * 0 CTR-X1 PPI-X
+ * 1 CTR-X2 PPI-Y
+ * 2 CTR-Y1 PPI-Z
+ * 3 CTR-Y2 INTERRUPT
+ * 4 CTR-Z1
+ * 5 CTR-Z2
+ * 6 INTERRUPT
*
* Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels
* are configurable as inputs or outputs in four groups:
@@ -120,14 +103,6 @@
* the SK1 connector. This pin is shared by all three counter
* channels on the chip.
*
- * For the PCIe boards, clock sources in the range 0 to 31 are allowed
- * and the following additional clock sources are defined:
- *
- * 8. HIGH logic level.
- * 9. LOW logic level.
- * 10. "Pattern present" signal.
- * 11. Internal 20 MHz clock.
- *
* INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current
* clock source in data[1]. For internal clock sources, data[2] is set
* to the period in ns.
@@ -149,27 +124,6 @@
* 6. Reserved.
* 7. Reserved.
*
- * For the PCIe boards, gate sources in the range 0 to 31 are allowed;
- * the following additional clock sources and clock sources 6 and 7 are
- * (re)defined:
- *
- * 6. /GAT n, negated version of the counter channel's dedicated
- * GAT input (negated version of gate source 2).
- * 7. OUT n-2, the non-inverted output of counter channel n-2
- * (negated version of gate source 3).
- * 8. "Pattern present" signal, HIGH while pattern present.
- * 9. "Pattern occurred" latched signal, latches HIGH when pattern
- * occurs.
- * 10. "Pattern gone away" latched signal, latches LOW when pattern
- * goes away after it occurred.
- * 11. Negated "pattern present" signal, LOW while pattern present
- * (negated version of gate source 8).
- * 12. Negated "pattern occurred" latched signal, latches LOW when
- * pattern occurs (negated version of gate source 9).
- * 13. Negated "pattern gone away" latched signal, latches LOW when
- * pattern goes away after it occurred (negated version of gate
- * source 10).
- *
* INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate
* source in data[2].
*
@@ -186,8 +140,6 @@
* 3. The counter subdevices are connected in a ring, so the highest
* counter subdevice precedes the lowest.
*
- * The 'TIMER' subdevice is a free-running 32-bit timer subdevice.
- *
* The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The
* digital inputs come from the interrupt status register. The number of
* channels matches the number of interrupt sources. The PC214E does not
@@ -196,7 +148,7 @@
*
* INTERRUPT SOURCES
*
- * PC212E PC214E PC215E/PCI215
+ * PC212E PC214E PC215E
* ------------- ------------- -------------
* Sources 6 1 6
* 0 PPI-X-C0 JUMPER-J5 PPI-X-C0
@@ -206,25 +158,15 @@
* 4 CTR-Z1-OUT1 CTR-Z1-OUT1
* 5 CTR-Z2-OUT1 CTR-Z2-OUT1
*
- * PCIe215 PC218E PCIe236
- * ------------- ------------- -------------
- * Sources 6 6 6
- * 0 PPI-X-C0 CTR-X1-OUT1 PPI-X-C0
- * 1 PPI-X-C3 CTR-X2-OUT1 PPI-X-C3
- * 2 PPI-Y-C0 CTR-Y1-OUT1 unused
- * 3 PPI-Y-C3 CTR-Y2-OUT1 unused
- * 4 CTR-Z1-OUT1 CTR-Z1-OUT1 CTR-Z1-OUT1
- * 5 CTR-Z2-OUT1 CTR-Z2-OUT1 CTR-Z2-OUT1
- *
- * PC272E/PCI272 PCIe296
+ * PC218E PC272E
* ------------- -------------
* Sources 6 6
- * 0 PPI-X-C0 PPI-X1-C0
- * 1 PPI-X-C3 PPI-X1-C3
- * 2 PPI-Y-C0 PPI-Y1-C0
- * 3 PPI-Y-C3 PPI-Y1-C3
- * 4 PPI-Z-C0 CTR-Z1-OUT1
- * 5 PPI-Z-C3 CTR-Z2-OUT1
+ * 0 CTR-X1-OUT1 PPI-X-C0
+ * 1 CTR-X2-OUT1 PPI-X-C3
+ * 2 CTR-Y1-OUT1 PPI-Y-C0
+ * 3 CTR-Y2-OUT1 PPI-Y-C3
+ * 4 CTR-Z1-OUT1 PPI-Z-C0
+ * 5 CTR-Z2-OUT1 PPI-Z-C3
*
* When an interrupt source is enabled in the interrupt source enable
* register, a rising edge on the source signal latches the corresponding
@@ -232,14 +174,11 @@
*
* When the interrupt status register value as a whole (actually, just the
* 6 least significant bits) goes from zero to non-zero, the board will
- * generate an interrupt. For level-triggered hardware interrupts (PCI
- * card), the interrupt will remain asserted until the interrupt status
- * register is cleared to zero. For edge-triggered hardware interrupts
- * (ISA card), no further interrupts will occur until the interrupt status
- * register is cleared to zero. To clear a bit to zero in the interrupt
- * status register, the corresponding interrupt source must be disabled
- * in the interrupt source enable register (there is no separate interrupt
- * clear register).
+ * generate an interrupt. No further interrupts will occur until the
+ * interrupt status register is cleared to zero. To clear a bit to zero in
+ * the interrupt status register, the corresponding interrupt source must
+ * be disabled in the interrupt source enable register (there is no
+ * separate interrupt clear register).
*
* The PC214E does not have an interrupt source enable register or an
* interrupt status register; its 'INTERRUPT' subdevice has a single
@@ -258,1835 +197,116 @@
* order they appear in the channel list.
*/
-#include <linux/pci.h>
-#include <linux/interrupt.h>
#include <linux/slab.h>
#include "../comedidev.h"
-#include "comedi_fc.h"
-#include "8253.h"
-
-#define DIO200_DRIVER_NAME "amplc_dio200"
-
-#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
-#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
-
-/* PCI IDs */
-#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
-#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
-#define PCI_DEVICE_ID_AMPLICON_PCIE236 0x0011
-#define PCI_DEVICE_ID_AMPLICON_PCIE215 0x0012
-#define PCI_DEVICE_ID_AMPLICON_PCIE296 0x0014
-
-/* 8255 control register bits */
-#define CR_C_LO_IO 0x01
-#define CR_B_IO 0x02
-#define CR_B_MODE 0x04
-#define CR_C_HI_IO 0x08
-#define CR_A_IO 0x10
-#define CR_A_MODE(a) ((a)<<5)
-#define CR_CW 0x80
-
-/* 200 series registers */
-#define DIO200_IO_SIZE 0x20
-#define DIO200_PCIE_IO_SIZE 0x4000
-#define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
-#define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
-#define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
-#define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
-#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
-#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
-#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
-/* Extra registers for new PCIe boards */
-#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */
-#define DIO200_VERSION 0x24 /* Hardware version register */
-#define DIO200_TS_CONFIG 0x600 /* Timestamp timer config register */
-#define DIO200_TS_COUNT 0x602 /* Timestamp timer count register */
-
-/*
- * Functions for constructing value for DIO_200_?CLK_SCE and
- * DIO_200_?GAT_SCE registers:
- *
- * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
- * 'chan' is the channel: 0, 1 or 2.
- * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
- */
-static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return (which << 5) | (chan << 3) |
- ((source & 030) << 3) | (source & 007);
-}
-
-static unsigned char clk_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
-static unsigned char gat_sce(unsigned int which, unsigned int chan,
- unsigned int source)
-{
- return clk_gat_sce(which, chan, source);
-}
-
-/*
- * Periods of the internal clock sources in nanoseconds.
- */
-static const unsigned int clock_period[32] = {
- [1] = 100, /* 10 MHz */
- [2] = 1000, /* 1 MHz */
- [3] = 10000, /* 100 kHz */
- [4] = 100000, /* 10 kHz */
- [5] = 1000000, /* 1 kHz */
- [11] = 50, /* 20 MHz (enhanced boards) */
- /* clock sources 12 and later reserved for enhanced boards */
-};
-
-/*
- * Timestamp timer configuration register (for new PCIe boards).
- */
-#define TS_CONFIG_RESET 0x100 /* Reset counter to zero. */
-#define TS_CONFIG_CLK_SRC_MASK 0x0FF /* Clock source. */
-#define TS_CONFIG_MAX_CLK_SRC 2 /* Maximum clock source value. */
-
-/*
- * Periods of the timestamp timer clock sources in nanoseconds.
- */
-static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
- 1, /* 1 nanosecond (but with 20 ns granularity). */
- 1000, /* 1 microsecond. */
- 1000000, /* 1 millisecond. */
-};
-
-/*
- * Register region.
- */
-enum dio200_regtype { no_regtype = 0, io_regtype, mmio_regtype };
-struct dio200_region {
- union {
- unsigned long iobase; /* I/O base address */
- unsigned char __iomem *membase; /* mapped MMIO base address */
- } u;
- enum dio200_regtype regtype;
-};
+#include "amplc_dio200.h"
/*
* Board descriptions.
*/
-
-enum dio200_bustype { isa_bustype, pci_bustype };
-
-enum dio200_model {
- pc212e_model,
- pc214e_model,
- pc215e_model, pci215_model, pcie215_model,
- pc218e_model,
- pcie236_model,
- pc272e_model, pci272_model,
- pcie296_model,
-};
-
-enum dio200_layout_idx {
-#if DO_ISA
- pc212_layout,
- pc214_layout,
-#endif
- pc215_layout,
-#if DO_ISA
- pc218_layout,
-#endif
- pc272_layout,
-#if DO_PCI
- pcie215_layout,
- pcie236_layout,
- pcie296_layout,
-#endif
-};
-
-struct dio200_board {
- const char *name;
- unsigned short devid;
- enum dio200_bustype bustype;
- enum dio200_model model;
- enum dio200_layout_idx layout;
- unsigned char mainbar;
- unsigned char mainshift;
- unsigned int mainsize;
-};
-
-static const struct dio200_board dio200_boards[] = {
-#if DO_ISA
- {
- .name = "pc212e",
- .bustype = isa_bustype,
- .model = pc212e_model,
- .layout = pc212_layout,
- .mainsize = DIO200_IO_SIZE,
- },
- {
- .name = "pc214e",
- .bustype = isa_bustype,
- .model = pc214e_model,
- .layout = pc214_layout,
- .mainsize = DIO200_IO_SIZE,
- },
- {
- .name = "pc215e",
- .bustype = isa_bustype,
- .model = pc215e_model,
- .layout = pc215_layout,
- .mainsize = DIO200_IO_SIZE,
- },
- {
- .name = "pc218e",
- .bustype = isa_bustype,
- .model = pc218e_model,
- .layout = pc218_layout,
- .mainsize = DIO200_IO_SIZE,
- },
+static const struct dio200_board dio200_isa_boards[] = {
{
- .name = "pc272e",
- .bustype = isa_bustype,
- .model = pc272e_model,
- .layout = pc272_layout,
- .mainsize = DIO200_IO_SIZE,
- },
-#endif
-#if DO_PCI
+ .name = "pc212e",
+ .bustype = isa_bustype,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 6,
+ .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254, sd_8254,
+ sd_intr},
+ .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ },
+ },
{
- .name = "pci215",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
- .bustype = pci_bustype,
- .model = pci215_model,
- .layout = pc215_layout,
- .mainbar = 2,
- .mainsize = DIO200_IO_SIZE,
- },
+ .name = "pc214e",
+ .bustype = isa_bustype,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 4,
+ .sdtype = {sd_8255, sd_8255, sd_8254, sd_intr},
+ .sdinfo = {0x00, 0x08, 0x10, 0x01},
+ },
+ },
{
- .name = "pci272",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI272,
- .bustype = pci_bustype,
- .model = pci272_model,
- .layout = pc272_layout,
- .mainbar = 2,
- .mainsize = DIO200_IO_SIZE,
- },
+ .name = "pc215e",
+ .bustype = isa_bustype,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 5,
+ .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr},
+ .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ },
+ },
{
- .name = "pcie215",
- .devid = PCI_DEVICE_ID_AMPLICON_PCIE215,
- .bustype = pci_bustype,
- .model = pcie215_model,
- .layout = pcie215_layout,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- },
+ .name = "pc218e",
+ .bustype = isa_bustype,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 7,
+ .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254, sd_8254,
+ sd_intr},
+ .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ },
+ },
{
- .name = "pcie236",
- .devid = PCI_DEVICE_ID_AMPLICON_PCIE236,
- .bustype = pci_bustype,
- .model = pcie236_model,
- .layout = pcie236_layout,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- },
- {
- .name = "pcie296",
- .devid = PCI_DEVICE_ID_AMPLICON_PCIE296,
- .bustype = pci_bustype,
- .model = pcie296_model,
- .layout = pcie296_layout,
- .mainbar = 1,
- .mainshift = 3,
- .mainsize = DIO200_PCIE_IO_SIZE,
- },
-#endif
-};
-
-/*
- * Layout descriptions - some ISA and PCI board descriptions share the same
- * layout.
- */
-
-enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254, sd_timer };
-
-#define DIO200_MAX_SUBDEVS 8
-#define DIO200_MAX_ISNS 6
-
-struct dio200_layout {
- unsigned short n_subdevs; /* number of subdevices */
- unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
- unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
- char has_int_sce; /* has interrupt enable/status register */
- char has_clk_gat_sce; /* has clock/gate selection registers */
- char has_enhancements; /* has enhanced features */
-};
-
-static const struct dio200_layout dio200_layouts[] = {
-#if DO_ISA
- [pc212_layout] = {
- .n_subdevs = 6,
- .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
- sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x08, 0x0C, 0x10, 0x14,
- 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- },
- [pc214_layout] = {
- .n_subdevs = 4,
- .sdtype = {sd_8255, sd_8255, sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x01},
- .has_int_sce = 0,
- .has_clk_gat_sce = 0,
- },
-#endif
- [pc215_layout] = {
- .n_subdevs = 5,
- .sdtype = {sd_8255, sd_8255, sd_8254,
- sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- },
-#if DO_ISA
- [pc218_layout] = {
- .n_subdevs = 7,
- .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
- sd_8254,
- sd_intr},
- .sdinfo = {0x00, 0x04, 0x08, 0x0C, 0x10,
- 0x14,
- 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- },
-#endif
- [pc272_layout] = {
- .n_subdevs = 4,
- .sdtype = {sd_8255, sd_8255, sd_8255,
- sd_intr},
- .sdinfo = {0x00, 0x08, 0x10, 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 0,
- },
-#if DO_PCI
- [pcie215_layout] = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_none, sd_8255, sd_none,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x00, 0x08, 0x00,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- .has_enhancements = 1,
- },
- [pcie236_layout] = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_none, sd_none, sd_none,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x00, 0x00, 0x00,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- .has_enhancements = 1,
- },
- [pcie296_layout] = {
- .n_subdevs = 8,
- .sdtype = {sd_8255, sd_8255, sd_8255, sd_8255,
- sd_8254, sd_8254, sd_timer, sd_intr},
- .sdinfo = {0x00, 0x04, 0x08, 0x0C,
- 0x10, 0x14, 0x00, 0x3F},
- .has_int_sce = 1,
- .has_clk_gat_sce = 1,
- .has_enhancements = 1,
- },
-#endif
-};
-
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct.
- */
-struct dio200_private {
- struct dio200_region io; /* Register region */
- int intr_sd;
-};
-
-struct dio200_subdev_8254 {
- unsigned int ofs; /* Counter base offset */
- unsigned int clk_sce_ofs; /* CLK_SCE base address */
- unsigned int gat_sce_ofs; /* GAT_SCE base address */
- int which; /* Bit 5 of CLK_SCE or GAT_SCE */
- unsigned int clock_src[3]; /* Current clock sources */
- unsigned int gate_src[3]; /* Current gate sources */
- spinlock_t spinlock;
-};
-
-struct dio200_subdev_8255 {
- unsigned int ofs; /* DIO base offset */
+ .name = "pc272e",
+ .bustype = isa_bustype,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 4,
+ .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr},
+ .sdinfo = {0x00, 0x08, 0x10, 0x3F},
+ .has_int_sce = true,
+ },
+ },
};
-struct dio200_subdev_intr {
- unsigned int ofs;
- spinlock_t spinlock;
- int active;
- unsigned int valid_isns;
- unsigned int enabled_isns;
- unsigned int stopcount;
- int continuous;
-};
-
-static inline const struct dio200_layout *
-dio200_board_layout(const struct dio200_board *board)
-{
- return &dio200_layouts[board->layout];
-}
-
-static inline const struct dio200_layout *
-dio200_dev_layout(struct comedi_device *dev)
-{
- return dio200_board_layout(comedi_board(dev));
-}
-
-static inline bool is_pci_board(const struct dio200_board *board)
-{
- return DO_PCI && board->bustype == pci_bustype;
-}
-
-static inline bool is_isa_board(const struct dio200_board *board)
-{
- return DO_ISA && board->bustype == isa_bustype;
-}
-
-/*
- * Read 8-bit register.
- */
-static unsigned char dio200_read8(struct comedi_device *dev,
- unsigned int offset)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
-
- offset <<= thisboard->mainshift;
- if (devpriv->io.regtype == io_regtype)
- return inb(devpriv->io.u.iobase + offset);
- else
- return readb(devpriv->io.u.membase + offset);
-}
-
-/*
- * Write 8-bit register.
- */
-static void dio200_write8(struct comedi_device *dev, unsigned int offset,
- unsigned char val)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
-
- offset <<= thisboard->mainshift;
- if (devpriv->io.regtype == io_regtype)
- outb(val, devpriv->io.u.iobase + offset);
- else
- writeb(val, devpriv->io.u.membase + offset);
-}
-
-/*
- * Read 32-bit register.
- */
-static unsigned int dio200_read32(struct comedi_device *dev,
- unsigned int offset)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
-
- offset <<= thisboard->mainshift;
- if (devpriv->io.regtype == io_regtype)
- return inl(devpriv->io.u.iobase + offset);
- else
- return readl(devpriv->io.u.membase + offset);
-}
-
-/*
- * Write 32-bit register.
- */
-static void dio200_write32(struct comedi_device *dev, unsigned int offset,
- unsigned int val)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
-
- offset <<= thisboard->mainshift;
- if (devpriv->io.regtype == io_regtype)
- outl(val, devpriv->io.u.iobase + offset);
- else
- writel(val, devpriv->io.u.membase + offset);
-}
-
-/*
- * This function looks for a board matching the supplied PCI device.
- */
-static const struct dio200_board *
-dio200_find_pci_board(struct pci_dev *pci_dev)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dio200_boards); i++)
- if (is_pci_board(&dio200_boards[i]) &&
- pci_dev->device == dio200_boards[i].devid)
- return &dio200_boards[i];
- return NULL;
-}
-
-/*
- * This function checks and requests an I/O region, reporting an error
- * if there is a conflict.
- */
-static int
-dio200_request_region(struct comedi_device *dev,
- unsigned long from, unsigned long extent)
-{
- if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
- from, extent);
- return -EIO;
- }
- return 0;
-}
-
-/*
- * 'insn_bits' function for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_intr *subpriv = s->private;
-
- if (layout->has_int_sce) {
- /* Just read the interrupt status register. */
- data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
- } else {
- /* No interrupt status register. */
- data[0] = 0;
- }
-
- return insn->n;
-}
-
-/*
- * Called to stop acquisition for an 'INTERRUPT' subdevice.
- */
-static void dio200_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_intr *subpriv = s->private;
-
- subpriv->active = 0;
- subpriv->enabled_isns = 0;
- if (layout->has_int_sce)
- dio200_write8(dev, subpriv->ofs, 0);
-}
-
-/*
- * Called to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int dio200_start_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- unsigned int n;
- unsigned isn_bits;
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_intr *subpriv = s->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- int retval = 0;
-
- if (!subpriv->continuous && subpriv->stopcount == 0) {
- /* An empty acquisition! */
- s->async->events |= COMEDI_CB_EOA;
- subpriv->active = 0;
- retval = 1;
- } else {
- /* Determine interrupt sources to enable. */
- isn_bits = 0;
- if (cmd->chanlist) {
- for (n = 0; n < cmd->chanlist_len; n++)
- isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
- }
- isn_bits &= subpriv->valid_isns;
- /* Enable interrupt sources. */
- subpriv->enabled_isns = isn_bits;
- if (layout->has_int_sce)
- dio200_write8(dev, subpriv->ofs, isn_bits);
- }
-
- return retval;
-}
-
-/*
- * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int trignum)
-{
- struct dio200_subdev_intr *subpriv;
- unsigned long flags;
- int event = 0;
-
- if (trignum != 0)
- return -EINVAL;
-
- subpriv = s->private;
-
- spin_lock_irqsave(&subpriv->spinlock, flags);
- s->async->inttrig = NULL;
- if (subpriv->active)
- event = dio200_start_intr(dev, s);
-
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
-
- if (event)
- comedi_event(dev, s);
-
- return 1;
-}
-
-/*
- * This is called from the interrupt service routine to handle a read
- * scan on an 'INTERRUPT' subdevice.
- */
-static int dio200_handle_read_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_intr *subpriv = s->private;
- unsigned triggered;
- unsigned intstat;
- unsigned cur_enabled;
- unsigned int oldevents;
- unsigned long flags;
-
- triggered = 0;
-
- spin_lock_irqsave(&subpriv->spinlock, flags);
- oldevents = s->async->events;
- if (layout->has_int_sce) {
- /*
- * Collect interrupt sources that have triggered and disable
- * them temporarily. Loop around until no extra interrupt
- * sources have triggered, at which point, the valid part of
- * the interrupt status register will read zero, clearing the
- * cause of the interrupt.
- *
- * Mask off interrupt sources already seen to avoid infinite
- * loop in case of misconfiguration.
- */
- cur_enabled = subpriv->enabled_isns;
- while ((intstat = (dio200_read8(dev, subpriv->ofs) &
- subpriv->valid_isns & ~triggered)) != 0) {
- triggered |= intstat;
- cur_enabled &= ~triggered;
- dio200_write8(dev, subpriv->ofs, cur_enabled);
- }
- } else {
- /*
- * No interrupt status register. Assume the single interrupt
- * source has triggered.
- */
- triggered = subpriv->enabled_isns;
- }
-
- if (triggered) {
- /*
- * Some interrupt sources have triggered and have been
- * temporarily disabled to clear the cause of the interrupt.
- *
- * Reenable them NOW to minimize the time they are disabled.
- */
- cur_enabled = subpriv->enabled_isns;
- if (layout->has_int_sce)
- dio200_write8(dev, subpriv->ofs, cur_enabled);
-
- if (subpriv->active) {
- /*
- * The command is still active.
- *
- * Ignore interrupt sources that the command isn't
- * interested in (just in case there's a race
- * condition).
- */
- if (triggered & subpriv->enabled_isns) {
- /* Collect scan data. */
- short val;
- unsigned int n, ch, len;
-
- val = 0;
- len = s->async->cmd.chanlist_len;
- for (n = 0; n < len; n++) {
- ch = CR_CHAN(s->async->cmd.chanlist[n]);
- if (triggered & (1U << ch))
- val |= (1U << n);
- }
- /* Write the scan to the buffer. */
- if (comedi_buf_put(s->async, val)) {
- s->async->events |= (COMEDI_CB_BLOCK |
- COMEDI_CB_EOS);
- } else {
- /* Error! Stop acquisition. */
- dio200_stop_intr(dev, s);
- s->async->events |= COMEDI_CB_ERROR
- | COMEDI_CB_OVERFLOW;
- comedi_error(dev, "buffer overflow");
- }
-
- /* Check for end of acquisition. */
- if (!subpriv->continuous) {
- /* stop_src == TRIG_COUNT */
- if (subpriv->stopcount > 0) {
- subpriv->stopcount--;
- if (subpriv->stopcount == 0) {
- s->async->events |=
- COMEDI_CB_EOA;
- dio200_stop_intr(dev,
- s);
- }
- }
- }
- }
- }
- }
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
-
- if (oldevents != s->async->events)
- comedi_event(dev, s);
-
- return (triggered != 0);
-}
-
-/*
- * 'cancel' function for an 'INTERRUPT' subdevice.
- */
-static int dio200_subdev_intr_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct dio200_subdev_intr *subpriv = s->private;
- unsigned long flags;
-
- spin_lock_irqsave(&subpriv->spinlock, flags);
- if (subpriv->active)
- dio200_stop_intr(dev, s);
-
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
-
- return 0;
-}
-
-/*
- * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd)
-{
- int err = 0;
-
- /* Step 1 : check if triggers are trivially valid */
-
- err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
- err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
- err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
- err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
- err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
-
- if (err)
- return 1;
-
- /* Step 2a : make sure trigger sources are unique */
-
- err |= cfc_check_trigger_is_unique(cmd->start_src);
- err |= cfc_check_trigger_is_unique(cmd->stop_src);
-
- /* Step 2b : and mutually compatible */
-
- if (err)
- return 2;
-
- /* Step 3: check if arguments are trivially valid */
-
- err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
- err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
-
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- /* any count allowed */
- break;
- case TRIG_NONE:
- err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
- break;
- default:
- break;
- }
-
- if (err)
- return 3;
-
- /* step 4: fix up any arguments */
-
- /* if (err) return 4; */
-
- return 0;
-}
-
-/*
- * 'do_cmd' function for an 'INTERRUPT' subdevice.
- */
-static int dio200_subdev_intr_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct comedi_cmd *cmd = &s->async->cmd;
- struct dio200_subdev_intr *subpriv = s->private;
- unsigned long flags;
- int event = 0;
-
- spin_lock_irqsave(&subpriv->spinlock, flags);
- subpriv->active = 1;
-
- /* Set up end of acquisition. */
- switch (cmd->stop_src) {
- case TRIG_COUNT:
- subpriv->continuous = 0;
- subpriv->stopcount = cmd->stop_arg;
- break;
- default:
- /* TRIG_NONE */
- subpriv->continuous = 1;
- subpriv->stopcount = 0;
- break;
- }
-
- /* Set up start of acquisition. */
- switch (cmd->start_src) {
- case TRIG_INT:
- s->async->inttrig = dio200_inttrig_start_intr;
- break;
- default:
- /* TRIG_NOW */
- event = dio200_start_intr(dev, s);
- break;
- }
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
-
- if (event)
- comedi_event(dev, s);
-
- return 0;
-}
-
-/*
- * This function initializes an 'INTERRUPT' subdevice.
- */
-static int
-dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int offset, unsigned valid_isns)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_intr *subpriv;
-
- subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
- if (!subpriv)
- return -ENOMEM;
-
- subpriv->ofs = offset;
- subpriv->valid_isns = valid_isns;
- spin_lock_init(&subpriv->spinlock);
-
- if (layout->has_int_sce)
- /* Disable interrupt sources. */
- dio200_write8(dev, subpriv->ofs, 0);
-
- s->private = subpriv;
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
- if (layout->has_int_sce) {
- s->n_chan = DIO200_MAX_ISNS;
- s->len_chanlist = DIO200_MAX_ISNS;
- } else {
- /* No interrupt source register. Support single channel. */
- s->n_chan = 1;
- s->len_chanlist = 1;
- }
- s->range_table = &range_digital;
- s->maxdata = 1;
- s->insn_bits = dio200_subdev_intr_insn_bits;
- s->do_cmdtest = dio200_subdev_intr_cmdtest;
- s->do_cmd = dio200_subdev_intr_cmd;
- s->cancel = dio200_subdev_intr_cancel;
-
- return 0;
-}
-
-/*
- * This function cleans up an 'INTERRUPT' subdevice.
- */
-static void
-dio200_subdev_intr_cleanup(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct dio200_subdev_intr *subpriv = s->private;
- kfree(subpriv);
-}
-
-/*
- * Interrupt service routine.
- */
-static irqreturn_t dio200_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct dio200_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int handled;
-
- if (!dev->attached)
- return IRQ_NONE;
-
- if (devpriv->intr_sd >= 0) {
- s = &dev->subdevices[devpriv->intr_sd];
- handled = dio200_handle_read_intr(dev, s);
- } else {
- handled = 0;
- }
-
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Read an '8254' counter subdevice channel.
- */
-static unsigned int
-dio200_subdev_8254_read_chan(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
- unsigned int val;
-
- /* latch counter */
- val = chan << 6;
- dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
- /* read lsb, msb */
- val = dio200_read8(dev, subpriv->ofs + chan);
- val += dio200_read8(dev, subpriv->ofs + chan) << 8;
- return val;
-}
-
-/*
- * Write an '8254' subdevice channel.
- */
-static void
-dio200_subdev_8254_write_chan(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan,
- unsigned int count)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
-
- /* write lsb, msb */
- dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
- dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
-}
-
-/*
- * Set mode of an '8254' subdevice channel.
- */
-static void
-dio200_subdev_8254_set_mode(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan,
- unsigned int mode)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
- unsigned int byte;
-
- byte = chan << 6;
- byte |= 0x30; /* access order: lsb, msb */
- byte |= (mode & 0xf); /* counter mode and BCD|binary */
- dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
-}
-
-/*
- * Read status byte of an '8254' counter subdevice channel.
- */
-static unsigned int
-dio200_subdev_8254_status(struct comedi_device *dev,
- struct comedi_subdevice *s, unsigned int chan)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
-
- /* latch status */
- dio200_write8(dev, subpriv->ofs + i8254_control_reg,
- 0xe0 | (2 << chan));
- /* read status */
- return dio200_read8(dev, subpriv->ofs + chan);
-}
-
-/*
- * Handle 'insn_read' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
- int chan = CR_CHAN(insn->chanspec);
- unsigned int n;
- unsigned long flags;
-
- for (n = 0; n < insn->n; n++) {
- spin_lock_irqsave(&subpriv->spinlock, flags);
- data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
- }
- return insn->n;
-}
-
-/*
- * Handle 'insn_write' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
- int chan = CR_CHAN(insn->chanspec);
- unsigned int n;
- unsigned long flags;
-
- for (n = 0; n < insn->n; n++) {
- spin_lock_irqsave(&subpriv->spinlock, flags);
- dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
- }
- return insn->n;
-}
-
-/*
- * Set gate source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int gate_src)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_8254 *subpriv = s->private;
- unsigned char byte;
-
- if (!layout->has_clk_gat_sce)
- return -1;
- if (counter_number > 2)
- return -1;
- if (gate_src > (layout->has_enhancements ? 31 : 7))
- return -1;
-
- subpriv->gate_src[counter_number] = gate_src;
- byte = gat_sce(subpriv->which, counter_number, gate_src);
- dio200_write8(dev, subpriv->gat_sce_ofs, byte);
-
- return 0;
-}
-
-/*
- * Get gate source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_8254 *subpriv = s->private;
-
- if (!layout->has_clk_gat_sce)
- return -1;
- if (counter_number > 2)
- return -1;
-
- return subpriv->gate_src[counter_number];
-}
-
-/*
- * Set clock source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int clock_src)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_8254 *subpriv = s->private;
- unsigned char byte;
-
- if (!layout->has_clk_gat_sce)
- return -1;
- if (counter_number > 2)
- return -1;
- if (clock_src > (layout->has_enhancements ? 31 : 7))
- return -1;
-
- subpriv->clock_src[counter_number] = clock_src;
- byte = clk_sce(subpriv->which, counter_number, clock_src);
- dio200_write8(dev, subpriv->clk_sce_ofs, byte);
-
- return 0;
-}
-
-/*
- * Get clock source for an '8254' counter subdevice channel.
- */
-static int
-dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int counter_number,
- unsigned int *period_ns)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_8254 *subpriv = s->private;
- unsigned clock_src;
-
- if (!layout->has_clk_gat_sce)
- return -1;
- if (counter_number > 2)
- return -1;
-
- clock_src = subpriv->clock_src[counter_number];
- *period_ns = clock_period[clock_src];
- return clock_src;
-}
-
-/*
- * Handle 'insn_config' for an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dio200_subdev_8254 *subpriv = s->private;
- int ret = 0;
- int chan = CR_CHAN(insn->chanspec);
- unsigned long flags;
-
- spin_lock_irqsave(&subpriv->spinlock, flags);
- switch (data[0]) {
- case INSN_CONFIG_SET_COUNTER_MODE:
- if (data[1] > (I8254_MODE5 | I8254_BINARY))
- ret = -EINVAL;
- else
- dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
- break;
- case INSN_CONFIG_8254_READ_STATUS:
- data[1] = dio200_subdev_8254_status(dev, s, chan);
- break;
- case INSN_CONFIG_SET_GATE_SRC:
- ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
- if (ret < 0)
- ret = -EINVAL;
- break;
- case INSN_CONFIG_GET_GATE_SRC:
- ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
- if (ret < 0) {
- ret = -EINVAL;
- break;
- }
- data[2] = ret;
- break;
- case INSN_CONFIG_SET_CLOCK_SRC:
- ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
- if (ret < 0)
- ret = -EINVAL;
- break;
- case INSN_CONFIG_GET_CLOCK_SRC:
- ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
- if (ret < 0) {
- ret = -EINVAL;
- break;
- }
- data[1] = ret;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- spin_unlock_irqrestore(&subpriv->spinlock, flags);
- return ret < 0 ? ret : insn->n;
-}
-
-/*
- * This function initializes an '8254' counter subdevice.
- */
-static int
-dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
- unsigned int offset)
-{
- const struct dio200_layout *layout = dio200_dev_layout(dev);
- struct dio200_subdev_8254 *subpriv;
- unsigned int chan;
-
- subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
- if (!subpriv)
- return -ENOMEM;
-
- s->private = subpriv;
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 3;
- s->maxdata = 0xFFFF;
- s->insn_read = dio200_subdev_8254_read;
- s->insn_write = dio200_subdev_8254_write;
- s->insn_config = dio200_subdev_8254_config;
-
- spin_lock_init(&subpriv->spinlock);
- subpriv->ofs = offset;
- if (layout->has_clk_gat_sce) {
- /* Derive CLK_SCE and GAT_SCE register offsets from
- * 8254 offset. */
- subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
- subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3);
- subpriv->which = (offset >> 2) & 1;
- }
-
- /* Initialize channels. */
- for (chan = 0; chan < 3; chan++) {
- dio200_subdev_8254_set_mode(dev, s, chan,
- I8254_MODE0 | I8254_BINARY);
- if (layout->has_clk_gat_sce) {
- /* Gate source 0 is VCC (logic 1). */
- dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
- /* Clock source 0 is the dedicated clock input. */
- dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
- }
- }
-
- return 0;
-}
-
-/*
- * This function cleans up an '8254' counter subdevice.
- */
-static void
-dio200_subdev_8254_cleanup(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct dio200_subdev_intr *subpriv = s->private;
- kfree(subpriv);
-}
-
-/*
- * This function sets I/O directions for an '8255' DIO subdevice.
- */
-static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct dio200_subdev_8255 *subpriv = s->private;
- int config;
-
- config = CR_CW;
- /* 1 in io_bits indicates output, 1 in config indicates input */
- if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
- if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
- if (!(s->io_bits & 0x0f0000))
- config |= CR_C_LO_IO;
- if (!(s->io_bits & 0xf00000))
- config |= CR_C_HI_IO;
- dio200_write8(dev, subpriv->ofs + 3, config);
-}
-
-/*
- * Handle 'insn_bits' for an '8255' DIO subdevice.
- */
-static int dio200_subdev_8255_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct dio200_subdev_8255 *subpriv = s->private;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
- if (data[0] & 0xff)
- dio200_write8(dev, subpriv->ofs, s->state & 0xff);
- if (data[0] & 0xff00)
- dio200_write8(dev, subpriv->ofs + 1,
- (s->state >> 8) & 0xff);
- if (data[0] & 0xff0000)
- dio200_write8(dev, subpriv->ofs + 2,
- (s->state >> 16) & 0xff);
- }
- data[1] = dio200_read8(dev, subpriv->ofs);
- data[1] |= dio200_read8(dev, subpriv->ofs + 1) << 8;
- data[1] |= dio200_read8(dev, subpriv->ofs + 2) << 16;
- return 2;
-}
-
-/*
- * Handle 'insn_config' for an '8255' DIO subdevice.
- */
-static int dio200_subdev_8255_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int mask;
- unsigned int bits;
-
- mask = 1 << CR_CHAN(insn->chanspec);
- if (mask & 0x0000ff)
- bits = 0x0000ff;
- else if (mask & 0x00ff00)
- bits = 0x00ff00;
- else if (mask & 0x0f0000)
- bits = 0x0f0000;
- else
- bits = 0xf00000;
- switch (data[0]) {
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~bits;
- break;
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= bits;
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- break;
- default:
- return -EINVAL;
- }
- dio200_subdev_8255_set_dir(dev, s);
- return 1;
-}
-
-/*
- * This function initializes an '8255' DIO subdevice.
- *
- * offset is the offset to the 8255 chip.
- */
-static int dio200_subdev_8255_init(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int offset)
-{
- struct dio200_subdev_8255 *subpriv;
-
- subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
- if (!subpriv)
- return -ENOMEM;
- subpriv->ofs = offset;
- s->private = subpriv;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 24;
- s->range_table = &range_digital;
- s->maxdata = 1;
- s->insn_bits = dio200_subdev_8255_bits;
- s->insn_config = dio200_subdev_8255_config;
- s->state = 0;
- s->io_bits = 0;
- dio200_subdev_8255_set_dir(dev, s);
- return 0;
-}
-
-/*
- * This function cleans up an '8255' DIO subdevice.
- */
-static void dio200_subdev_8255_cleanup(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct dio200_subdev_8255 *subpriv = s->private;
-
- kfree(subpriv);
-}
-
-/*
- * Handle 'insn_read' for a timer subdevice.
- */
-static int dio200_subdev_timer_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- unsigned int n;
-
- for (n = 0; n < insn->n; n++)
- data[n] = dio200_read32(dev, DIO200_TS_COUNT);
- return n;
-}
-
-/*
- * Reset timer subdevice.
- */
-static void dio200_subdev_timer_reset(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- unsigned int clock;
-
- clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
- dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
- dio200_write32(dev, DIO200_TS_CONFIG, clock);
-}
-
-/*
- * Get timer subdevice clock source and period.
- */
-static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *src,
- unsigned int *period)
-{
- unsigned int clk;
-
- clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
- *src = clk;
- *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
- ts_clock_period[clk] : 0;
-}
-
-/*
- * Set timer subdevice clock source.
- */
-static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int src)
-{
- if (src > TS_CONFIG_MAX_CLK_SRC)
- return -EINVAL;
- dio200_write32(dev, DIO200_TS_CONFIG, src);
- return 0;
-}
-
-/*
- * Handle 'insn_config' for a timer subdevice.
- */
-static int dio200_subdev_timer_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- int ret = 0;
-
- switch (data[0]) {
- case INSN_CONFIG_RESET:
- dio200_subdev_timer_reset(dev, s);
- break;
- case INSN_CONFIG_SET_CLOCK_SRC:
- ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
- if (ret < 0)
- ret = -EINVAL;
- break;
- case INSN_CONFIG_GET_CLOCK_SRC:
- dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret < 0 ? ret : insn->n;
-}
-
-/*
- * This function initializes a timer subdevice.
- *
- * Uses the timestamp timer registers. There is only one timestamp timer.
- */
-static int dio200_subdev_timer_init(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- s->type = COMEDI_SUBD_TIMER;
- s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
- s->n_chan = 1;
- s->maxdata = 0xFFFFFFFF;
- s->insn_read = dio200_subdev_timer_read;
- s->insn_config = dio200_subdev_timer_config;
- return 0;
-}
-
-/*
- * This function cleans up a timer subdevice.
- */
-static void dio200_subdev_timer_cleanup(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- /* Nothing to do. */
-}
-
-/*
- * This function does some special set-up for the PCIe boards
- * PCIe215, PCIe236, PCIe296.
- */
-static int dio200_pcie_board_setup(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- void __iomem *brbase;
- resource_size_t brlen;
-
- /*
- * The board uses Altera Cyclone IV with PCI-Express hard IP.
- * The FPGA configuration has the PCI-Express Avalon-MM Bridge
- * Control registers in PCI BAR 0, offset 0, and the length of
- * these registers is 0x4000.
- *
- * We need to write 0x80 to the "Avalon-MM to PCI-Express Interrupt
- * Enable" register at offset 0x50 to allow generation of PCIe
- * interrupts when RXmlrq_i is asserted in the SOPC Builder system.
- */
- brlen = pci_resource_len(pcidev, 0);
- if (brlen < 0x4000 ||
- !(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
- dev_err(dev->class_dev, "error! bad PCI region!\n");
- return -EINVAL;
- }
- brbase = ioremap_nocache(pci_resource_start(pcidev, 0), brlen);
- if (!brbase) {
- dev_err(dev->class_dev, "error! failed to map registers!\n");
- return -ENOMEM;
- }
- writel(0x80, brbase + 0x50);
- iounmap(brbase);
- /* Enable "enhanced" features of board. */
- dio200_write8(dev, DIO200_ENHANCE, 1);
- return 0;
-}
-
-static void dio200_report_attach(struct comedi_device *dev, unsigned int irq)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[60];
- int tmplen;
-
- if (is_isa_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(base %#lx) ", devpriv->io.u.iobase);
- else if (is_pci_board(thisboard))
- tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
- "(pci %s) ", pci_name(pcidev));
- else
- tmplen = 0;
- if (irq)
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(irq %u%s) ", irq,
- (dev->irq ? "" : " UNAVAILABLE"));
- else
- tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
- "(no irq) ");
- dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
-}
-
-static int dio200_common_attach(struct comedi_device *dev, unsigned int irq,
- unsigned long req_irq_flags)
-{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
- const struct dio200_layout *layout = dio200_board_layout(thisboard);
- struct comedi_subdevice *s;
- int sdx;
- unsigned int n;
- int ret;
-
- devpriv->intr_sd = -1;
- dev->board_name = thisboard->name;
-
- ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
- if (ret)
- return ret;
-
- for (n = 0; n < dev->n_subdevices; n++) {
- s = &dev->subdevices[n];
- switch (layout->sdtype[n]) {
- case sd_8254:
- /* counter subdevice (8254) */
- ret = dio200_subdev_8254_init(dev, s,
- layout->sdinfo[n]);
- if (ret < 0)
- return ret;
- break;
- case sd_8255:
- /* digital i/o subdevice (8255) */
- ret = dio200_subdev_8255_init(dev, s,
- layout->sdinfo[n]);
- if (ret < 0)
- return ret;
- break;
- case sd_intr:
- /* 'INTERRUPT' subdevice */
- if (irq) {
- ret = dio200_subdev_intr_init(dev, s,
- DIO200_INT_SCE,
- layout->sdinfo[n]
- );
- if (ret < 0)
- return ret;
- devpriv->intr_sd = n;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
- break;
- case sd_timer:
- /* Only on PCIe boards. */
- if (DO_PCI) {
- ret = dio200_subdev_timer_init(dev, s);
- if (ret < 0)
- return ret;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
- break;
- default:
- s->type = COMEDI_SUBD_UNUSED;
- break;
- }
- }
- sdx = devpriv->intr_sd;
- if (sdx >= 0 && sdx < dev->n_subdevices)
- dev->read_subdev = &dev->subdevices[sdx];
- if (irq) {
- if (request_irq(irq, dio200_interrupt, req_irq_flags,
- DIO200_DRIVER_NAME, dev) >= 0) {
- dev->irq = irq;
- } else {
- dev_warn(dev->class_dev,
- "warning! irq %u unavailable!\n", irq);
- }
- }
- dio200_report_attach(dev, irq);
- return 1;
-}
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct dio200_board *thisboard = comedi_board(dev);
struct dio200_private *devpriv;
+ unsigned int irq;
int ret;
- dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach\n");
+ irq = it->options[1];
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- /* Process options and reserve resources according to bus type. */
- if (is_isa_board(thisboard)) {
- unsigned long iobase;
- unsigned int irq;
-
- iobase = it->options[0];
- irq = it->options[1];
- ret = dio200_request_region(dev, iobase, thisboard->mainsize);
- if (ret < 0)
- return ret;
- devpriv->io.u.iobase = iobase;
- devpriv->io.regtype = io_regtype;
- return dio200_common_attach(dev, irq, 0);
- } else if (is_pci_board(thisboard)) {
- dev_err(dev->class_dev,
- "Manual configuration of PCI board '%s' is not supported\n",
- thisboard->name);
- return -EIO;
- } else {
- dev_err(dev->class_dev, DIO200_DRIVER_NAME
- ": BUG! cannot determine board type!\n");
- return -EINVAL;
- }
-}
-
-/*
- * The auto_attach hook is called at PCI probe time via
- * comedi_pci_auto_config(). dev->board_ptr is NULL on entry.
- * There should be a board entry matching the supplied PCI device.
- */
-static int dio200_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
-{
- struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
- const struct dio200_board *thisboard;
- struct dio200_private *devpriv;
- resource_size_t base, len;
- unsigned int bar;
- int ret;
-
- if (!DO_PCI)
- return -EINVAL;
-
- dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n",
- pci_name(pci_dev));
-
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
-
- dev->board_ptr = dio200_find_pci_board(pci_dev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
- return -EINVAL;
- }
- thisboard = comedi_board(dev);
- ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
- if (ret < 0) {
- dev_err(dev->class_dev,
- "error! cannot enable PCI device and request regions!\n");
+ ret = comedi_request_region(dev, it->options[0], thisboard->mainsize);
+ if (ret)
return ret;
- }
- bar = thisboard->mainbar;
- base = pci_resource_start(pci_dev, bar);
- len = pci_resource_len(pci_dev, bar);
- if (len < thisboard->mainsize) {
- dev_err(dev->class_dev, "error! PCI region size too small!\n");
- return -EINVAL;
- }
- if ((pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) != 0) {
- devpriv->io.u.membase = ioremap_nocache(base, len);
- if (!devpriv->io.u.membase) {
- dev_err(dev->class_dev,
- "error! cannot remap registers\n");
- return -ENOMEM;
- }
- devpriv->io.regtype = mmio_regtype;
- } else {
- devpriv->io.u.iobase = (unsigned long)base;
- devpriv->io.regtype = io_regtype;
- }
- switch (thisboard->model) {
- case pcie215_model:
- case pcie236_model:
- case pcie296_model:
- ret = dio200_pcie_board_setup(dev);
- if (ret < 0)
- return ret;
- break;
- default:
- break;
- }
- return dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED);
+ devpriv->io.u.iobase = dev->iobase;
+ devpriv->io.regtype = io_regtype;
+ return amplc_dio200_common_attach(dev, irq, 0);
}
static void dio200_detach(struct comedi_device *dev)
{
- const struct dio200_board *thisboard = comedi_board(dev);
- struct dio200_private *devpriv = dev->private;
- const struct dio200_layout *layout;
- unsigned n;
-
- if (!thisboard || !devpriv)
- return;
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->subdevices) {
- layout = dio200_board_layout(thisboard);
- for (n = 0; n < dev->n_subdevices; n++) {
- struct comedi_subdevice *s = &dev->subdevices[n];
- switch (layout->sdtype[n]) {
- case sd_8254:
- dio200_subdev_8254_cleanup(dev, s);
- break;
- case sd_8255:
- dio200_subdev_8255_cleanup(dev, s);
- break;
- case sd_intr:
- dio200_subdev_intr_cleanup(dev, s);
- break;
- case sd_timer:
- /* Only on PCIe boards. */
- if (DO_PCI)
- dio200_subdev_timer_cleanup(dev, s);
- break;
- default:
- break;
- }
- }
- }
- if (is_isa_board(thisboard)) {
- if (devpriv->io.regtype == io_regtype)
- release_region(devpriv->io.u.iobase,
- thisboard->mainsize);
- } else if (is_pci_board(thisboard)) {
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- if (pcidev) {
- if (devpriv->io.regtype != no_regtype) {
- if (devpriv->io.regtype == mmio_regtype)
- iounmap(devpriv->io.u.membase);
- comedi_pci_disable(pcidev);
- }
- }
- }
+ amplc_dio200_common_detach(dev);
+ comedi_legacy_detach(dev);
}
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
static struct comedi_driver amplc_dio200_driver = {
- .driver_name = DIO200_DRIVER_NAME,
+ .driver_name = "amplc_dio200",
.module = THIS_MODULE,
.attach = dio200_attach,
- .auto_attach = dio200_auto_attach,
.detach = dio200_detach,
- .board_name = &dio200_boards[0].name,
+ .board_name = &dio200_isa_boards[0].name,
.offset = sizeof(struct dio200_board),
- .num_names = ARRAY_SIZE(dio200_boards),
-};
-
-#if DO_PCI
-static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE236) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE215) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE296) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, dio200_pci_table);
-
-static int amplc_dio200_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, &amplc_dio200_driver);
-}
-
-static struct pci_driver amplc_dio200_pci_driver = {
- .name = DIO200_DRIVER_NAME,
- .id_table = dio200_pci_table,
- .probe = &amplc_dio200_pci_probe,
- .remove = comedi_pci_auto_unconfig,
+ .num_names = ARRAY_SIZE(dio200_isa_boards),
};
-module_comedi_pci_driver(amplc_dio200_driver, amplc_dio200_pci_driver);
-#else
module_comedi_driver(amplc_dio200_driver);
-#endif
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Amplicon 200 Series ISA DIO boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/staging/comedi/drivers/amplc_dio200.h
new file mode 100644
index 000000000000..cf2e7261740e
--- /dev/null
+++ b/drivers/staging/comedi/drivers/amplc_dio200.h
@@ -0,0 +1,95 @@
+/*
+ comedi/drivers/amplc_dio.h
+
+ Header for amplc_dio200.c, amplc_dio200_common.c and
+ amplc_dio200_pci.c.
+
+ Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef AMPLC_DIO200_H_INCLUDED
+#define AMPLC_DIO200_H_INCLUDED
+
+/* 200 series register area sizes */
+#define DIO200_IO_SIZE 0x20
+#define DIO200_PCIE_IO_SIZE 0x4000
+
+/*
+ * Register region.
+ */
+enum dio200_regtype { no_regtype = 0, io_regtype, mmio_regtype };
+struct dio200_region {
+ union {
+ unsigned long iobase; /* I/O base address */
+ unsigned char __iomem *membase; /* mapped MMIO base address */
+ } u;
+ enum dio200_regtype regtype;
+};
+
+/*
+ * Subdevice types.
+ */
+enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254, sd_timer };
+
+#define DIO200_MAX_SUBDEVS 8
+#define DIO200_MAX_ISNS 6
+
+/*
+ * Board descriptions.
+ */
+
+struct dio200_layout {
+ unsigned short n_subdevs; /* number of subdevices */
+ unsigned char sdtype[DIO200_MAX_SUBDEVS]; /* enum dio200_sdtype */
+ unsigned char sdinfo[DIO200_MAX_SUBDEVS]; /* depends on sdtype */
+ bool has_int_sce:1; /* has interrupt enable/status reg */
+ bool has_clk_gat_sce:1; /* has clock/gate selection registers */
+ bool has_enhancements:1; /* has enhanced features */
+};
+
+enum dio200_bustype { isa_bustype, pci_bustype };
+
+struct dio200_board {
+ const char *name;
+ struct dio200_layout layout;
+ enum dio200_bustype bustype;
+ unsigned char mainbar;
+ unsigned char mainshift;
+ unsigned int mainsize;
+};
+
+/*
+ * Comedi device private data.
+ */
+struct dio200_private {
+ struct dio200_region io; /* Register region */
+ int intr_sd;
+};
+
+int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
+ unsigned long req_irq_flags);
+
+void amplc_dio200_common_detach(struct comedi_device *dev);
+
+/* Used by initialization of PCIe boards. */
+void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val);
+
+#endif
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c
new file mode 100644
index 000000000000..3403e5ccfa93
--- /dev/null
+++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c
@@ -0,0 +1,1271 @@
+/*
+ comedi/drivers/amplc_dio200_common.c
+
+ Common support code for "amplc_dio200" and "amplc_dio200_pci".
+
+ Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "../comedidev.h"
+
+#include "amplc_dio200.h"
+#include "comedi_fc.h"
+#include "8253.h"
+
+/* 8255 control register bits */
+#define CR_C_LO_IO 0x01
+#define CR_B_IO 0x02
+#define CR_B_MODE 0x04
+#define CR_C_HI_IO 0x08
+#define CR_A_IO 0x10
+#define CR_A_MODE(a) ((a)<<5)
+#define CR_CW 0x80
+
+/* 200 series registers */
+#define DIO200_IO_SIZE 0x20
+#define DIO200_PCIE_IO_SIZE 0x4000
+#define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */
+#define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */
+#define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */
+#define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */
+#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */
+#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */
+#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */
+/* Extra registers for new PCIe boards */
+#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */
+#define DIO200_VERSION 0x24 /* Hardware version register */
+#define DIO200_TS_CONFIG 0x600 /* Timestamp timer config register */
+#define DIO200_TS_COUNT 0x602 /* Timestamp timer count register */
+
+/*
+ * Functions for constructing value for DIO_200_?CLK_SCE and
+ * DIO_200_?GAT_SCE registers:
+ *
+ * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
+ * 'chan' is the channel: 0, 1 or 2.
+ * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
+ */
+static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
+ unsigned int source)
+{
+ return (which << 5) | (chan << 3) |
+ ((source & 030) << 3) | (source & 007);
+}
+
+static unsigned char clk_sce(unsigned int which, unsigned int chan,
+ unsigned int source)
+{
+ return clk_gat_sce(which, chan, source);
+}
+
+static unsigned char gat_sce(unsigned int which, unsigned int chan,
+ unsigned int source)
+{
+ return clk_gat_sce(which, chan, source);
+}
+
+/*
+ * Periods of the internal clock sources in nanoseconds.
+ */
+static const unsigned int clock_period[32] = {
+ [1] = 100, /* 10 MHz */
+ [2] = 1000, /* 1 MHz */
+ [3] = 10000, /* 100 kHz */
+ [4] = 100000, /* 10 kHz */
+ [5] = 1000000, /* 1 kHz */
+ [11] = 50, /* 20 MHz (enhanced boards) */
+ /* clock sources 12 and later reserved for enhanced boards */
+};
+
+/*
+ * Timestamp timer configuration register (for new PCIe boards).
+ */
+#define TS_CONFIG_RESET 0x100 /* Reset counter to zero. */
+#define TS_CONFIG_CLK_SRC_MASK 0x0FF /* Clock source. */
+#define TS_CONFIG_MAX_CLK_SRC 2 /* Maximum clock source value. */
+
+/*
+ * Periods of the timestamp timer clock sources in nanoseconds.
+ */
+static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
+ 1, /* 1 nanosecond (but with 20 ns granularity). */
+ 1000, /* 1 microsecond. */
+ 1000000, /* 1 millisecond. */
+};
+
+struct dio200_subdev_8254 {
+ unsigned int ofs; /* Counter base offset */
+ unsigned int clk_sce_ofs; /* CLK_SCE base address */
+ unsigned int gat_sce_ofs; /* GAT_SCE base address */
+ int which; /* Bit 5 of CLK_SCE or GAT_SCE */
+ unsigned int clock_src[3]; /* Current clock sources */
+ unsigned int gate_src[3]; /* Current gate sources */
+ spinlock_t spinlock;
+};
+
+struct dio200_subdev_8255 {
+ unsigned int ofs; /* DIO base offset */
+};
+
+struct dio200_subdev_intr {
+ spinlock_t spinlock;
+ unsigned int ofs;
+ unsigned int valid_isns;
+ unsigned int enabled_isns;
+ unsigned int stopcount;
+ bool active:1;
+ bool continuous:1;
+};
+
+static inline const struct dio200_layout *
+dio200_board_layout(const struct dio200_board *board)
+{
+ return &board->layout;
+}
+
+static inline const struct dio200_layout *
+dio200_dev_layout(struct comedi_device *dev)
+{
+ return dio200_board_layout(comedi_board(dev));
+}
+
+/*
+ * Read 8-bit register.
+ */
+static unsigned char dio200_read8(struct comedi_device *dev,
+ unsigned int offset)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+
+ offset <<= thisboard->mainshift;
+ if (devpriv->io.regtype == io_regtype)
+ return inb(devpriv->io.u.iobase + offset);
+ else
+ return readb(devpriv->io.u.membase + offset);
+}
+
+/*
+ * Write 8-bit register.
+ */
+static void dio200_write8(struct comedi_device *dev, unsigned int offset,
+ unsigned char val)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+
+ offset <<= thisboard->mainshift;
+ if (devpriv->io.regtype == io_regtype)
+ outb(val, devpriv->io.u.iobase + offset);
+ else
+ writeb(val, devpriv->io.u.membase + offset);
+}
+
+/*
+ * Read 32-bit register.
+ */
+static unsigned int dio200_read32(struct comedi_device *dev,
+ unsigned int offset)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+
+ offset <<= thisboard->mainshift;
+ if (devpriv->io.regtype == io_regtype)
+ return inl(devpriv->io.u.iobase + offset);
+ else
+ return readl(devpriv->io.u.membase + offset);
+}
+
+/*
+ * Write 32-bit register.
+ */
+static void dio200_write32(struct comedi_device *dev, unsigned int offset,
+ unsigned int val)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+
+ offset <<= thisboard->mainshift;
+ if (devpriv->io.regtype == io_regtype)
+ outl(val, devpriv->io.u.iobase + offset);
+ else
+ writel(val, devpriv->io.u.membase + offset);
+}
+
+/*
+ * 'insn_bits' function for an 'INTERRUPT' subdevice.
+ */
+static int
+dio200_subdev_intr_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_intr *subpriv = s->private;
+
+ if (layout->has_int_sce) {
+ /* Just read the interrupt status register. */
+ data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
+ } else {
+ /* No interrupt status register. */
+ data[0] = 0;
+ }
+
+ return insn->n;
+}
+
+/*
+ * Called to stop acquisition for an 'INTERRUPT' subdevice.
+ */
+static void dio200_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_intr *subpriv = s->private;
+
+ subpriv->active = false;
+ subpriv->enabled_isns = 0;
+ if (layout->has_int_sce)
+ dio200_write8(dev, subpriv->ofs, 0);
+}
+
+/*
+ * Called to start acquisition for an 'INTERRUPT' subdevice.
+ */
+static int dio200_start_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int n;
+ unsigned isn_bits;
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_intr *subpriv = s->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ int retval = 0;
+
+ if (!subpriv->continuous && subpriv->stopcount == 0) {
+ /* An empty acquisition! */
+ s->async->events |= COMEDI_CB_EOA;
+ subpriv->active = false;
+ retval = 1;
+ } else {
+ /* Determine interrupt sources to enable. */
+ isn_bits = 0;
+ if (cmd->chanlist) {
+ for (n = 0; n < cmd->chanlist_len; n++)
+ isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
+ }
+ isn_bits &= subpriv->valid_isns;
+ /* Enable interrupt sources. */
+ subpriv->enabled_isns = isn_bits;
+ if (layout->has_int_sce)
+ dio200_write8(dev, subpriv->ofs, isn_bits);
+ }
+
+ return retval;
+}
+
+/*
+ * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
+ */
+static int
+dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned int trignum)
+{
+ struct dio200_subdev_intr *subpriv;
+ unsigned long flags;
+ int event = 0;
+
+ if (trignum != 0)
+ return -EINVAL;
+
+ subpriv = s->private;
+
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ s->async->inttrig = NULL;
+ if (subpriv->active)
+ event = dio200_start_intr(dev, s);
+
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+
+ if (event)
+ comedi_event(dev, s);
+
+ return 1;
+}
+
+static void dio200_read_scan_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int triggered)
+{
+ struct dio200_subdev_intr *subpriv = s->private;
+ unsigned short val;
+ unsigned int n, ch, len;
+
+ val = 0;
+ len = s->async->cmd.chanlist_len;
+ for (n = 0; n < len; n++) {
+ ch = CR_CHAN(s->async->cmd.chanlist[n]);
+ if (triggered & (1U << ch))
+ val |= (1U << n);
+ }
+ /* Write the scan to the buffer. */
+ if (comedi_buf_put(s->async, val)) {
+ s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
+ } else {
+ /* Error! Stop acquisition. */
+ dio200_stop_intr(dev, s);
+ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
+ comedi_error(dev, "buffer overflow");
+ }
+
+ /* Check for end of acquisition. */
+ if (!subpriv->continuous) {
+ /* stop_src == TRIG_COUNT */
+ if (subpriv->stopcount > 0) {
+ subpriv->stopcount--;
+ if (subpriv->stopcount == 0) {
+ s->async->events |= COMEDI_CB_EOA;
+ dio200_stop_intr(dev, s);
+ }
+ }
+ }
+}
+
+/*
+ * This is called from the interrupt service routine to handle a read
+ * scan on an 'INTERRUPT' subdevice.
+ */
+static int dio200_handle_read_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_intr *subpriv = s->private;
+ unsigned triggered;
+ unsigned intstat;
+ unsigned cur_enabled;
+ unsigned int oldevents;
+ unsigned long flags;
+
+ triggered = 0;
+
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ oldevents = s->async->events;
+ if (layout->has_int_sce) {
+ /*
+ * Collect interrupt sources that have triggered and disable
+ * them temporarily. Loop around until no extra interrupt
+ * sources have triggered, at which point, the valid part of
+ * the interrupt status register will read zero, clearing the
+ * cause of the interrupt.
+ *
+ * Mask off interrupt sources already seen to avoid infinite
+ * loop in case of misconfiguration.
+ */
+ cur_enabled = subpriv->enabled_isns;
+ while ((intstat = (dio200_read8(dev, subpriv->ofs) &
+ subpriv->valid_isns & ~triggered)) != 0) {
+ triggered |= intstat;
+ cur_enabled &= ~triggered;
+ dio200_write8(dev, subpriv->ofs, cur_enabled);
+ }
+ } else {
+ /*
+ * No interrupt status register. Assume the single interrupt
+ * source has triggered.
+ */
+ triggered = subpriv->enabled_isns;
+ }
+
+ if (triggered) {
+ /*
+ * Some interrupt sources have triggered and have been
+ * temporarily disabled to clear the cause of the interrupt.
+ *
+ * Reenable them NOW to minimize the time they are disabled.
+ */
+ cur_enabled = subpriv->enabled_isns;
+ if (layout->has_int_sce)
+ dio200_write8(dev, subpriv->ofs, cur_enabled);
+
+ if (subpriv->active) {
+ /*
+ * The command is still active.
+ *
+ * Ignore interrupt sources that the command isn't
+ * interested in (just in case there's a race
+ * condition).
+ */
+ if (triggered & subpriv->enabled_isns)
+ /* Collect scan data. */
+ dio200_read_scan_intr(dev, s, triggered);
+ }
+ }
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+
+ if (oldevents != s->async->events)
+ comedi_event(dev, s);
+
+ return (triggered != 0);
+}
+
+/*
+ * 'cancel' function for an 'INTERRUPT' subdevice.
+ */
+static int dio200_subdev_intr_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct dio200_subdev_intr *subpriv = s->private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ if (subpriv->active)
+ dio200_stop_intr(dev, s);
+
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+
+ return 0;
+}
+
+/*
+ * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
+ */
+static int
+dio200_subdev_intr_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s, struct comedi_cmd *cmd)
+{
+ int err = 0;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+
+ err |= cfc_check_trigger_is_unique(cmd->start_src);
+ err |= cfc_check_trigger_is_unique(cmd->stop_src);
+
+ /* Step 2b : and mutually compatible */
+
+ if (err)
+ return 2;
+
+ /* Step 3: check if arguments are trivially valid */
+
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+
+ switch (cmd->stop_src) {
+ case TRIG_COUNT:
+ /* any count allowed */
+ break;
+ case TRIG_NONE:
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+ break;
+ default:
+ break;
+ }
+
+ if (err)
+ return 3;
+
+ /* step 4: fix up any arguments */
+
+ /* if (err) return 4; */
+
+ return 0;
+}
+
+/*
+ * 'do_cmd' function for an 'INTERRUPT' subdevice.
+ */
+static int dio200_subdev_intr_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct comedi_cmd *cmd = &s->async->cmd;
+ struct dio200_subdev_intr *subpriv = s->private;
+ unsigned long flags;
+ int event = 0;
+
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ subpriv->active = 1;
+
+ /* Set up end of acquisition. */
+ switch (cmd->stop_src) {
+ case TRIG_COUNT:
+ subpriv->continuous = false;
+ subpriv->stopcount = cmd->stop_arg;
+ break;
+ default:
+ /* TRIG_NONE */
+ subpriv->continuous = true;
+ subpriv->stopcount = 0;
+ break;
+ }
+
+ /* Set up start of acquisition. */
+ switch (cmd->start_src) {
+ case TRIG_INT:
+ s->async->inttrig = dio200_inttrig_start_intr;
+ break;
+ default:
+ /* TRIG_NOW */
+ event = dio200_start_intr(dev, s);
+ break;
+ }
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+
+ if (event)
+ comedi_event(dev, s);
+
+ return 0;
+}
+
+/*
+ * This function initializes an 'INTERRUPT' subdevice.
+ */
+static int
+dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned int offset, unsigned valid_isns)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_intr *subpriv;
+
+ subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
+ if (!subpriv)
+ return -ENOMEM;
+
+ subpriv->ofs = offset;
+ subpriv->valid_isns = valid_isns;
+ spin_lock_init(&subpriv->spinlock);
+
+ if (layout->has_int_sce)
+ /* Disable interrupt sources. */
+ dio200_write8(dev, subpriv->ofs, 0);
+
+ s->private = subpriv;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
+ if (layout->has_int_sce) {
+ s->n_chan = DIO200_MAX_ISNS;
+ s->len_chanlist = DIO200_MAX_ISNS;
+ } else {
+ /* No interrupt source register. Support single channel. */
+ s->n_chan = 1;
+ s->len_chanlist = 1;
+ }
+ s->range_table = &range_digital;
+ s->maxdata = 1;
+ s->insn_bits = dio200_subdev_intr_insn_bits;
+ s->do_cmdtest = dio200_subdev_intr_cmdtest;
+ s->do_cmd = dio200_subdev_intr_cmd;
+ s->cancel = dio200_subdev_intr_cancel;
+
+ return 0;
+}
+
+/*
+ * Interrupt service routine.
+ */
+static irqreturn_t dio200_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct dio200_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ int handled;
+
+ if (!dev->attached)
+ return IRQ_NONE;
+
+ if (devpriv->intr_sd >= 0) {
+ s = &dev->subdevices[devpriv->intr_sd];
+ handled = dio200_handle_read_intr(dev, s);
+ } else {
+ handled = 0;
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+/*
+ * Read an '8254' counter subdevice channel.
+ */
+static unsigned int
+dio200_subdev_8254_read_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int chan)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+ unsigned int val;
+
+ /* latch counter */
+ val = chan << 6;
+ dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
+ /* read lsb, msb */
+ val = dio200_read8(dev, subpriv->ofs + chan);
+ val += dio200_read8(dev, subpriv->ofs + chan) << 8;
+ return val;
+}
+
+/*
+ * Write an '8254' subdevice channel.
+ */
+static void
+dio200_subdev_8254_write_chan(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int chan,
+ unsigned int count)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+
+ /* write lsb, msb */
+ dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
+ dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
+}
+
+/*
+ * Set mode of an '8254' subdevice channel.
+ */
+static void
+dio200_subdev_8254_set_mode(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int chan,
+ unsigned int mode)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+ unsigned int byte;
+
+ byte = chan << 6;
+ byte |= 0x30; /* access order: lsb, msb */
+ byte |= (mode & 0xf); /* counter mode and BCD|binary */
+ dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
+}
+
+/*
+ * Read status byte of an '8254' counter subdevice channel.
+ */
+static unsigned int
+dio200_subdev_8254_status(struct comedi_device *dev,
+ struct comedi_subdevice *s, unsigned int chan)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+
+ /* latch status */
+ dio200_write8(dev, subpriv->ofs + i8254_control_reg,
+ 0xe0 | (2 << chan));
+ /* read status */
+ return dio200_read8(dev, subpriv->ofs + chan);
+}
+
+/*
+ * Handle 'insn_read' for an '8254' counter subdevice.
+ */
+static int
+dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+ int chan = CR_CHAN(insn->chanspec);
+ unsigned int n;
+ unsigned long flags;
+
+ for (n = 0; n < insn->n; n++) {
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ }
+ return insn->n;
+}
+
+/*
+ * Handle 'insn_write' for an '8254' counter subdevice.
+ */
+static int
+dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+ int chan = CR_CHAN(insn->chanspec);
+ unsigned int n;
+ unsigned long flags;
+
+ for (n = 0; n < insn->n; n++) {
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ }
+ return insn->n;
+}
+
+/*
+ * Set gate source for an '8254' counter subdevice channel.
+ */
+static int
+dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int gate_src)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_8254 *subpriv = s->private;
+ unsigned char byte;
+
+ if (!layout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+ if (gate_src > (layout->has_enhancements ? 31 : 7))
+ return -1;
+
+ subpriv->gate_src[counter_number] = gate_src;
+ byte = gat_sce(subpriv->which, counter_number, gate_src);
+ dio200_write8(dev, subpriv->gat_sce_ofs, byte);
+
+ return 0;
+}
+
+/*
+ * Get gate source for an '8254' counter subdevice channel.
+ */
+static int
+dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_8254 *subpriv = s->private;
+
+ if (!layout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+
+ return subpriv->gate_src[counter_number];
+}
+
+/*
+ * Set clock source for an '8254' counter subdevice channel.
+ */
+static int
+dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int clock_src)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_8254 *subpriv = s->private;
+ unsigned char byte;
+
+ if (!layout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+ if (clock_src > (layout->has_enhancements ? 31 : 7))
+ return -1;
+
+ subpriv->clock_src[counter_number] = clock_src;
+ byte = clk_sce(subpriv->which, counter_number, clock_src);
+ dio200_write8(dev, subpriv->clk_sce_ofs, byte);
+
+ return 0;
+}
+
+/*
+ * Get clock source for an '8254' counter subdevice channel.
+ */
+static int
+dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int counter_number,
+ unsigned int *period_ns)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_8254 *subpriv = s->private;
+ unsigned clock_src;
+
+ if (!layout->has_clk_gat_sce)
+ return -1;
+ if (counter_number > 2)
+ return -1;
+
+ clock_src = subpriv->clock_src[counter_number];
+ *period_ns = clock_period[clock_src];
+ return clock_src;
+}
+
+/*
+ * Handle 'insn_config' for an '8254' counter subdevice.
+ */
+static int
+dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct dio200_subdev_8254 *subpriv = s->private;
+ int ret = 0;
+ int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+
+ spin_lock_irqsave(&subpriv->spinlock, flags);
+ switch (data[0]) {
+ case INSN_CONFIG_SET_COUNTER_MODE:
+ if (data[1] > (I8254_MODE5 | I8254_BINARY))
+ ret = -EINVAL;
+ else
+ dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
+ break;
+ case INSN_CONFIG_8254_READ_STATUS:
+ data[1] = dio200_subdev_8254_status(dev, s, chan);
+ break;
+ case INSN_CONFIG_SET_GATE_SRC:
+ ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
+ if (ret < 0)
+ ret = -EINVAL;
+ break;
+ case INSN_CONFIG_GET_GATE_SRC:
+ ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
+ data[2] = ret;
+ break;
+ case INSN_CONFIG_SET_CLOCK_SRC:
+ ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
+ break;
+ case INSN_CONFIG_GET_CLOCK_SRC:
+ ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
+ data[1] = ret;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ return ret < 0 ? ret : insn->n;
+}
+
+/*
+ * This function initializes an '8254' counter subdevice.
+ */
+static int
+dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
+ unsigned int offset)
+{
+ const struct dio200_layout *layout = dio200_dev_layout(dev);
+ struct dio200_subdev_8254 *subpriv;
+ unsigned int chan;
+
+ subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
+ if (!subpriv)
+ return -ENOMEM;
+
+ s->private = subpriv;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 3;
+ s->maxdata = 0xFFFF;
+ s->insn_read = dio200_subdev_8254_read;
+ s->insn_write = dio200_subdev_8254_write;
+ s->insn_config = dio200_subdev_8254_config;
+
+ spin_lock_init(&subpriv->spinlock);
+ subpriv->ofs = offset;
+ if (layout->has_clk_gat_sce) {
+ /* Derive CLK_SCE and GAT_SCE register offsets from
+ * 8254 offset. */
+ subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
+ subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3);
+ subpriv->which = (offset >> 2) & 1;
+ }
+
+ /* Initialize channels. */
+ for (chan = 0; chan < 3; chan++) {
+ dio200_subdev_8254_set_mode(dev, s, chan,
+ I8254_MODE0 | I8254_BINARY);
+ if (layout->has_clk_gat_sce) {
+ /* Gate source 0 is VCC (logic 1). */
+ dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
+ /* Clock source 0 is the dedicated clock input. */
+ dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function sets I/O directions for an '8255' DIO subdevice.
+ */
+static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ struct dio200_subdev_8255 *subpriv = s->private;
+ int config;
+
+ config = CR_CW;
+ /* 1 in io_bits indicates output, 1 in config indicates input */
+ if (!(s->io_bits & 0x0000ff))
+ config |= CR_A_IO;
+ if (!(s->io_bits & 0x00ff00))
+ config |= CR_B_IO;
+ if (!(s->io_bits & 0x0f0000))
+ config |= CR_C_LO_IO;
+ if (!(s->io_bits & 0xf00000))
+ config |= CR_C_HI_IO;
+ dio200_write8(dev, subpriv->ofs + 3, config);
+}
+
+/*
+ * Handle 'insn_bits' for an '8255' DIO subdevice.
+ */
+static int dio200_subdev_8255_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ struct dio200_subdev_8255 *subpriv = s->private;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+ if (data[0] & 0xff)
+ dio200_write8(dev, subpriv->ofs, s->state & 0xff);
+ if (data[0] & 0xff00)
+ dio200_write8(dev, subpriv->ofs + 1,
+ (s->state >> 8) & 0xff);
+ if (data[0] & 0xff0000)
+ dio200_write8(dev, subpriv->ofs + 2,
+ (s->state >> 16) & 0xff);
+ }
+ data[1] = dio200_read8(dev, subpriv->ofs);
+ data[1] |= dio200_read8(dev, subpriv->ofs + 1) << 8;
+ data[1] |= dio200_read8(dev, subpriv->ofs + 2) << 16;
+ return 2;
+}
+
+/*
+ * Handle 'insn_config' for an '8255' DIO subdevice.
+ */
+static int dio200_subdev_8255_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int mask;
+ unsigned int bits;
+
+ mask = 1 << CR_CHAN(insn->chanspec);
+ if (mask & 0x0000ff)
+ bits = 0x0000ff;
+ else if (mask & 0x00ff00)
+ bits = 0x00ff00;
+ else if (mask & 0x0f0000)
+ bits = 0x0f0000;
+ else
+ bits = 0xf00000;
+ switch (data[0]) {
+ case INSN_CONFIG_DIO_INPUT:
+ s->io_bits &= ~bits;
+ break;
+ case INSN_CONFIG_DIO_OUTPUT:
+ s->io_bits |= bits;
+ break;
+ case INSN_CONFIG_DIO_QUERY:
+ data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
+ return insn->n;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dio200_subdev_8255_set_dir(dev, s);
+ return 1;
+}
+
+/*
+ * This function initializes an '8255' DIO subdevice.
+ *
+ * offset is the offset to the 8255 chip.
+ */
+static int dio200_subdev_8255_init(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int offset)
+{
+ struct dio200_subdev_8255 *subpriv;
+
+ subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL);
+ if (!subpriv)
+ return -ENOMEM;
+ subpriv->ofs = offset;
+ s->private = subpriv;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 24;
+ s->range_table = &range_digital;
+ s->maxdata = 1;
+ s->insn_bits = dio200_subdev_8255_bits;
+ s->insn_config = dio200_subdev_8255_config;
+ s->state = 0;
+ s->io_bits = 0;
+ dio200_subdev_8255_set_dir(dev, s);
+ return 0;
+}
+
+/*
+ * Handle 'insn_read' for a timer subdevice.
+ */
+static int dio200_subdev_timer_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int n;
+
+ for (n = 0; n < insn->n; n++)
+ data[n] = dio200_read32(dev, DIO200_TS_COUNT);
+ return n;
+}
+
+/*
+ * Reset timer subdevice.
+ */
+static void dio200_subdev_timer_reset(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ unsigned int clock;
+
+ clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
+ dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
+ dio200_write32(dev, DIO200_TS_CONFIG, clock);
+}
+
+/*
+ * Get timer subdevice clock source and period.
+ */
+static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *src,
+ unsigned int *period)
+{
+ unsigned int clk;
+
+ clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
+ *src = clk;
+ *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
+ ts_clock_period[clk] : 0;
+}
+
+/*
+ * Set timer subdevice clock source.
+ */
+static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int src)
+{
+ if (src > TS_CONFIG_MAX_CLK_SRC)
+ return -EINVAL;
+ dio200_write32(dev, DIO200_TS_CONFIG, src);
+ return 0;
+}
+
+/*
+ * Handle 'insn_config' for a timer subdevice.
+ */
+static int dio200_subdev_timer_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ int ret = 0;
+
+ switch (data[0]) {
+ case INSN_CONFIG_RESET:
+ dio200_subdev_timer_reset(dev, s);
+ break;
+ case INSN_CONFIG_SET_CLOCK_SRC:
+ ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
+ break;
+ case INSN_CONFIG_GET_CLOCK_SRC:
+ dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret < 0 ? ret : insn->n;
+}
+
+/*
+ * This function initializes a timer subdevice.
+ *
+ * Uses the timestamp timer registers. There is only one timestamp timer.
+ */
+static int dio200_subdev_timer_init(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ s->type = COMEDI_SUBD_TIMER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 1;
+ s->maxdata = 0xFFFFFFFF;
+ s->insn_read = dio200_subdev_timer_read;
+ s->insn_config = dio200_subdev_timer_config;
+ return 0;
+}
+
+void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
+{
+ dio200_write8(dev, DIO200_ENHANCE, val);
+}
+EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
+
+int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
+ unsigned long req_irq_flags)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+ const struct dio200_layout *layout = dio200_board_layout(thisboard);
+ struct comedi_subdevice *s;
+ int sdx;
+ unsigned int n;
+ int ret;
+
+ devpriv->intr_sd = -1;
+
+ ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
+ if (ret)
+ return ret;
+
+ for (n = 0; n < dev->n_subdevices; n++) {
+ s = &dev->subdevices[n];
+ switch (layout->sdtype[n]) {
+ case sd_8254:
+ /* counter subdevice (8254) */
+ ret = dio200_subdev_8254_init(dev, s,
+ layout->sdinfo[n]);
+ if (ret < 0)
+ return ret;
+ break;
+ case sd_8255:
+ /* digital i/o subdevice (8255) */
+ ret = dio200_subdev_8255_init(dev, s,
+ layout->sdinfo[n]);
+ if (ret < 0)
+ return ret;
+ break;
+ case sd_intr:
+ /* 'INTERRUPT' subdevice */
+ if (irq) {
+ ret = dio200_subdev_intr_init(dev, s,
+ DIO200_INT_SCE,
+ layout->sdinfo[n]
+ );
+ if (ret < 0)
+ return ret;
+ devpriv->intr_sd = n;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+ break;
+ case sd_timer:
+ ret = dio200_subdev_timer_init(dev, s);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ s->type = COMEDI_SUBD_UNUSED;
+ break;
+ }
+ }
+ sdx = devpriv->intr_sd;
+ if (sdx >= 0 && sdx < dev->n_subdevices)
+ dev->read_subdev = &dev->subdevices[sdx];
+ if (irq) {
+ if (request_irq(irq, dio200_interrupt, req_irq_flags,
+ dev->board_name, dev) >= 0) {
+ dev->irq = irq;
+ } else {
+ dev_warn(dev->class_dev,
+ "warning! irq %u unavailable!\n", irq);
+ }
+ }
+ dev_info(dev->class_dev, "attached\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
+
+void amplc_dio200_common_detach(struct comedi_device *dev)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+ const struct dio200_layout *layout;
+ unsigned n;
+
+ if (!thisboard || !devpriv)
+ return;
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->subdevices) {
+ layout = dio200_board_layout(thisboard);
+ for (n = 0; n < dev->n_subdevices; n++) {
+ switch (layout->sdtype[n]) {
+ case sd_8254:
+ case sd_8255:
+ case sd_intr:
+ comedi_spriv_free(dev, n);
+ break;
+ case sd_timer:
+ default:
+ break;
+ }
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(amplc_dio200_common_detach);
+
+static int __init amplc_dio200_common_init(void)
+{
+ return 0;
+}
+module_init(amplc_dio200_common_init);
+
+static void __exit amplc_dio200_common_exit(void)
+{
+}
+module_exit(amplc_dio200_common_exit);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
new file mode 100644
index 000000000000..4be44e877373
--- /dev/null
+++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c
@@ -0,0 +1,486 @@
+/* comedi/drivers/amplc_dio200_pci.c
+
+ Driver for Amplicon PCI215, PCI272, PCIe215, PCIe236, PCIe296.
+
+ Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/*
+ * Driver: amplc_dio200_pci
+ * Description: Amplicon 200 Series PCI Digital I/O
+ * Author: Ian Abbott <abbotti@mev.co.uk>
+ * Devices: [Amplicon] PCI215 (amplc_dio200_pci), PCIe215, PCIe236,
+ * PCI272, PCIe296
+ * Updated: Mon, 18 Mar 2013 15:03:50 +0000
+ * Status: works
+ *
+ * Configuration options:
+ * none
+ *
+ * Manual configuration of PCI(e) cards is not supported; they are configured
+ * automatically.
+ *
+ * SUBDEVICES
+ *
+ * PCI215 PCIe215 PCIe236
+ * ------------- ------------- -------------
+ * Subdevices 5 8 8
+ * 0 PPI-X PPI-X PPI-X
+ * 1 PPI-Y UNUSED UNUSED
+ * 2 CTR-Z1 PPI-Y UNUSED
+ * 3 CTR-Z2 UNUSED UNUSED
+ * 4 INTERRUPT CTR-Z1 CTR-Z1
+ * 5 CTR-Z2 CTR-Z2
+ * 6 TIMER TIMER
+ * 7 INTERRUPT INTERRUPT
+ *
+ *
+ * PCI272 PCIe296
+ * ------------- -------------
+ * Subdevices 4 8
+ * 0 PPI-X PPI-X1
+ * 1 PPI-Y PPI-X2
+ * 2 PPI-Z PPI-Y1
+ * 3 INTERRUPT PPI-Y2
+ * 4 CTR-Z1
+ * 5 CTR-Z2
+ * 6 TIMER
+ * 7 INTERRUPT
+ *
+ * Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels
+ * are configurable as inputs or outputs in four groups:
+ *
+ * Port A - channels 0 to 7
+ * Port B - channels 8 to 15
+ * Port CL - channels 16 to 19
+ * Port CH - channels 20 to 23
+ *
+ * Only mode 0 of the 8255 chips is supported.
+ *
+ * Each CTR is a 8254 chip providing 3 16-bit counter channels. Each
+ * channel is configured individually with INSN_CONFIG instructions. The
+ * specific type of configuration instruction is specified in data[0].
+ * Some configuration instructions expect an additional parameter in
+ * data[1]; others return a value in data[1]. The following configuration
+ * instructions are supported:
+ *
+ * INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and
+ * BCD/binary setting specified in data[1].
+ *
+ * INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the
+ * counter channel into data[1].
+ *
+ * INSN_CONFIG_SET_CLOCK_SRC. Sets the counter channel's clock source as
+ * specified in data[1] (this is a hardware-specific value). Not
+ * supported on PC214E. For the other boards, valid clock sources are
+ * 0 to 7 as follows:
+ *
+ * 0. CLK n, the counter channel's dedicated CLK input from the SK1
+ * connector. (N.B. for other values, the counter channel's CLKn
+ * pin on the SK1 connector is an output!)
+ * 1. Internal 10 MHz clock.
+ * 2. Internal 1 MHz clock.
+ * 3. Internal 100 kHz clock.
+ * 4. Internal 10 kHz clock.
+ * 5. Internal 1 kHz clock.
+ * 6. OUT n-1, the output of counter channel n-1 (see note 1 below).
+ * 7. Ext Clock, the counter chip's dedicated Ext Clock input from
+ * the SK1 connector. This pin is shared by all three counter
+ * channels on the chip.
+ *
+ * For the PCIe boards, clock sources in the range 0 to 31 are allowed
+ * and the following additional clock sources are defined:
+ *
+ * 8. HIGH logic level.
+ * 9. LOW logic level.
+ * 10. "Pattern present" signal.
+ * 11. Internal 20 MHz clock.
+ *
+ * INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current
+ * clock source in data[1]. For internal clock sources, data[2] is set
+ * to the period in ns.
+ *
+ * INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as
+ * specified in data[2] (this is a hardware-specific value). Not
+ * supported on PC214E. For the other boards, valid gate sources are 0
+ * to 7 as follows:
+ *
+ * 0. VCC (internal +5V d.c.), i.e. gate permanently enabled.
+ * 1. GND (internal 0V d.c.), i.e. gate permanently disabled.
+ * 2. GAT n, the counter channel's dedicated GAT input from the SK1
+ * connector. (N.B. for other values, the counter channel's GATn
+ * pin on the SK1 connector is an output!)
+ * 3. /OUT n-2, the inverted output of counter channel n-2 (see note
+ * 2 below).
+ * 4. Reserved.
+ * 5. Reserved.
+ * 6. Reserved.
+ * 7. Reserved.
+ *
+ * For the PCIe boards, gate sources in the range 0 to 31 are allowed;
+ * the following additional clock sources and clock sources 6 and 7 are
+ * (re)defined:
+ *
+ * 6. /GAT n, negated version of the counter channel's dedicated
+ * GAT input (negated version of gate source 2).
+ * 7. OUT n-2, the non-inverted output of counter channel n-2
+ * (negated version of gate source 3).
+ * 8. "Pattern present" signal, HIGH while pattern present.
+ * 9. "Pattern occurred" latched signal, latches HIGH when pattern
+ * occurs.
+ * 10. "Pattern gone away" latched signal, latches LOW when pattern
+ * goes away after it occurred.
+ * 11. Negated "pattern present" signal, LOW while pattern present
+ * (negated version of gate source 8).
+ * 12. Negated "pattern occurred" latched signal, latches LOW when
+ * pattern occurs (negated version of gate source 9).
+ * 13. Negated "pattern gone away" latched signal, latches LOW when
+ * pattern goes away after it occurred (negated version of gate
+ * source 10).
+ *
+ * INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate
+ * source in data[2].
+ *
+ * Clock and gate interconnection notes:
+ *
+ * 1. Clock source OUT n-1 is the output of the preceding channel on the
+ * same counter subdevice if n > 0, or the output of channel 2 on the
+ * preceding counter subdevice (see note 3) if n = 0.
+ *
+ * 2. Gate source /OUT n-2 is the inverted output of channel 0 on the
+ * same counter subdevice if n = 2, or the inverted output of channel n+1
+ * on the preceding counter subdevice (see note 3) if n < 2.
+ *
+ * 3. The counter subdevices are connected in a ring, so the highest
+ * counter subdevice precedes the lowest.
+ *
+ * The 'TIMER' subdevice is a free-running 32-bit timer subdevice.
+ *
+ * The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The
+ * digital inputs come from the interrupt status register. The number of
+ * channels matches the number of interrupt sources. The PC214E does not
+ * have an interrupt status register; see notes on 'INTERRUPT SOURCES'
+ * below.
+ *
+ * INTERRUPT SOURCES
+ *
+ * PCI215 PCIe215 PCIe236
+ * ------------- ------------- -------------
+ * Sources 6 6 6
+ * 0 PPI-X-C0 PPI-X-C0 PPI-X-C0
+ * 1 PPI-X-C3 PPI-X-C3 PPI-X-C3
+ * 2 PPI-Y-C0 PPI-Y-C0 unused
+ * 3 PPI-Y-C3 PPI-Y-C3 unused
+ * 4 CTR-Z1-OUT1 CTR-Z1-OUT1 CTR-Z1-OUT1
+ * 5 CTR-Z2-OUT1 CTR-Z2-OUT1 CTR-Z2-OUT1
+ *
+ * PCI272 PCIe296
+ * ------------- -------------
+ * Sources 6 6
+ * 0 PPI-X-C0 PPI-X1-C0
+ * 1 PPI-X-C3 PPI-X1-C3
+ * 2 PPI-Y-C0 PPI-Y1-C0
+ * 3 PPI-Y-C3 PPI-Y1-C3
+ * 4 PPI-Z-C0 CTR-Z1-OUT1
+ * 5 PPI-Z-C3 CTR-Z2-OUT1
+ *
+ * When an interrupt source is enabled in the interrupt source enable
+ * register, a rising edge on the source signal latches the corresponding
+ * bit to 1 in the interrupt status register.
+ *
+ * When the interrupt status register value as a whole (actually, just the
+ * 6 least significant bits) goes from zero to non-zero, the board will
+ * generate an interrupt. The interrupt will remain asserted until the
+ * interrupt status register is cleared to zero. To clear a bit to zero in
+ * the interrupt status register, the corresponding interrupt source must
+ * be disabled in the interrupt source enable register (there is no
+ * separate interrupt clear register).
+ *
+ * COMMANDS
+ *
+ * The driver supports a read streaming acquisition command on the
+ * 'INTERRUPT' subdevice. The channel list selects the interrupt sources
+ * to be enabled. All channels will be sampled together (convert_src ==
+ * TRIG_NOW). The scan begins a short time after the hardware interrupt
+ * occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT,
+ * scan_begin_arg == 0). The value read from the interrupt status register
+ * is packed into a short value, one bit per requested channel, in the
+ * order they appear in the channel list.
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include "../comedidev.h"
+
+#include "amplc_dio200.h"
+
+/* PCI IDs */
+#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
+#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b
+#define PCI_DEVICE_ID_AMPLICON_PCIE236 0x0011
+#define PCI_DEVICE_ID_AMPLICON_PCIE215 0x0012
+#define PCI_DEVICE_ID_AMPLICON_PCIE296 0x0014
+
+/*
+ * Board descriptions.
+ */
+
+enum dio200_pci_model {
+ pci215_model,
+ pci272_model,
+ pcie215_model,
+ pcie236_model,
+ pcie296_model
+};
+
+static const struct dio200_board dio200_pci_boards[] = {
+ [pci215_model] = {
+ .name = "pci215",
+ .bustype = pci_bustype,
+ .mainbar = 2,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 5,
+ .sdtype = {sd_8255, sd_8255, sd_8254, sd_8254, sd_intr},
+ .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ },
+ },
+ [pci272_model] = {
+ .name = "pci272",
+ .bustype = pci_bustype,
+ .mainbar = 2,
+ .mainsize = DIO200_IO_SIZE,
+ .layout = {
+ .n_subdevs = 4,
+ .sdtype = {sd_8255, sd_8255, sd_8255, sd_intr},
+ .sdinfo = {0x00, 0x08, 0x10, 0x3F},
+ .has_int_sce = true,
+ },
+ },
+ [pcie215_model] = {
+ .name = "pcie215",
+ .bustype = pci_bustype,
+ .mainbar = 1,
+ .mainshift = 3,
+ .mainsize = DIO200_PCIE_IO_SIZE,
+ .layout = {
+ .n_subdevs = 8,
+ .sdtype = {sd_8255, sd_none, sd_8255, sd_none,
+ sd_8254, sd_8254, sd_timer, sd_intr},
+ .sdinfo = {0x00, 0x00, 0x08, 0x00,
+ 0x10, 0x14, 0x00, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .has_enhancements = true,
+ },
+ },
+ [pcie236_model] = {
+ .name = "pcie236",
+ .bustype = pci_bustype,
+ .mainbar = 1,
+ .mainshift = 3,
+ .mainsize = DIO200_PCIE_IO_SIZE,
+ .layout = {
+ .n_subdevs = 8,
+ .sdtype = {sd_8255, sd_none, sd_none, sd_none,
+ sd_8254, sd_8254, sd_timer, sd_intr},
+ .sdinfo = {0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x14, 0x00, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .has_enhancements = true,
+ },
+ },
+ [pcie296_model] = {
+ .name = "pcie296",
+ .bustype = pci_bustype,
+ .mainbar = 1,
+ .mainshift = 3,
+ .mainsize = DIO200_PCIE_IO_SIZE,
+ .layout = {
+ .n_subdevs = 8,
+ .sdtype = {sd_8255, sd_8255, sd_8255, sd_8255,
+ sd_8254, sd_8254, sd_timer, sd_intr},
+ .sdinfo = {0x00, 0x04, 0x08, 0x0C,
+ 0x10, 0x14, 0x00, 0x3F},
+ .has_int_sce = true,
+ .has_clk_gat_sce = true,
+ .has_enhancements = true,
+ },
+ },
+};
+
+/*
+ * This function does some special set-up for the PCIe boards
+ * PCIe215, PCIe236, PCIe296.
+ */
+static int dio200_pcie_board_setup(struct comedi_device *dev)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ void __iomem *brbase;
+
+ /*
+ * The board uses Altera Cyclone IV with PCI-Express hard IP.
+ * The FPGA configuration has the PCI-Express Avalon-MM Bridge
+ * Control registers in PCI BAR 0, offset 0, and the length of
+ * these registers is 0x4000.
+ *
+ * We need to write 0x80 to the "Avalon-MM to PCI-Express Interrupt
+ * Enable" register at offset 0x50 to allow generation of PCIe
+ * interrupts when RXmlrq_i is asserted in the SOPC Builder system.
+ */
+ if (pci_resource_len(pcidev, 0) < 0x4000) {
+ dev_err(dev->class_dev, "error! bad PCI region!\n");
+ return -EINVAL;
+ }
+ brbase = pci_ioremap_bar(pcidev, 0);
+ if (!brbase) {
+ dev_err(dev->class_dev, "error! failed to map registers!\n");
+ return -ENOMEM;
+ }
+ writel(0x80, brbase + 0x50);
+ iounmap(brbase);
+ /* Enable "enhanced" features of board. */
+ amplc_dio200_set_enhance(dev, 1);
+ return 0;
+}
+
+static int dio200_pci_auto_attach(struct comedi_device *dev,
+ unsigned long context_model)
+{
+ struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
+ const struct dio200_board *thisboard = NULL;
+ struct dio200_private *devpriv;
+ unsigned int bar;
+ int ret;
+
+ if (context_model < ARRAY_SIZE(dio200_pci_boards))
+ thisboard = &dio200_pci_boards[context_model];
+ if (!thisboard)
+ return -EINVAL;
+ dev->board_ptr = thisboard;
+ dev->board_name = thisboard->name;
+
+ dev_info(dev->class_dev, "%s: attach pci %s (%s)\n",
+ dev->driver->driver_name, pci_name(pci_dev), dev->board_name);
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
+ bar = thisboard->mainbar;
+ if (pci_resource_len(pci_dev, bar) < thisboard->mainsize) {
+ dev_err(dev->class_dev, "error! PCI region size too small!\n");
+ return -EINVAL;
+ }
+ if (pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) {
+ devpriv->io.u.membase = pci_ioremap_bar(pci_dev, bar);
+ if (!devpriv->io.u.membase) {
+ dev_err(dev->class_dev,
+ "error! cannot remap registers\n");
+ return -ENOMEM;
+ }
+ devpriv->io.regtype = mmio_regtype;
+ } else {
+ devpriv->io.u.iobase = pci_resource_start(pci_dev, bar);
+ devpriv->io.regtype = io_regtype;
+ }
+ switch (context_model) {
+ case pcie215_model:
+ case pcie236_model:
+ case pcie296_model:
+ ret = dio200_pcie_board_setup(dev);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ break;
+ }
+ return amplc_dio200_common_attach(dev, pci_dev->irq, IRQF_SHARED);
+}
+
+static void dio200_pci_detach(struct comedi_device *dev)
+{
+ const struct dio200_board *thisboard = comedi_board(dev);
+ struct dio200_private *devpriv = dev->private;
+
+ if (!thisboard || !devpriv)
+ return;
+ amplc_dio200_common_detach(dev);
+ if (devpriv->io.regtype == mmio_regtype)
+ iounmap(devpriv->io.u.membase);
+ comedi_pci_disable(dev);
+}
+
+static struct comedi_driver dio200_pci_comedi_driver = {
+ .driver_name = "amplc_dio200_pci",
+ .module = THIS_MODULE,
+ .auto_attach = dio200_pci_auto_attach,
+ .detach = dio200_pci_detach,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
+ {
+ PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215),
+ pci215_model
+ }, {
+ PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272),
+ pci272_model
+ }, {
+ PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE236),
+ pcie236_model
+ }, {
+ PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE215),
+ pcie215_model
+ }, {
+ PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE296),
+ pcie296_model
+ },
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, dio200_pci_table);
+
+static int dio200_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &dio200_pci_comedi_driver,
+ id->driver_data);
+}
+
+static struct pci_driver dio200_pci_pci_driver = {
+ .name = "amplc_dio200_pci",
+ .id_table = dio200_pci_table,
+ .probe = dio200_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+module_comedi_pci_driver(dio200_pci_comedi_driver, dio200_pci_pci_driver);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi driver for Amplicon 200 Series PCI(e) DIO boards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 479e10fddd22..115ecd51677e 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -75,23 +75,19 @@ unused.
#define PC236_IO_SIZE 4
#define PC236_LCR_IO_SIZE 128
-/*
- * INTCSR values for PCI236.
- */
-/* Disable interrupt, also clear any interrupt there */
-#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1ENAB_DISABLED \
- | PLX9052_INTCSR_LI1POL_HIGH \
- | PLX9052_INTCSR_LI2POL_HIGH \
- | PLX9052_INTCSR_PCIENAB_DISABLED \
- | PLX9052_INTCSR_LI1SEL_EDGE \
- | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
-/* Enable interrupt, also clear any interrupt there. */
-#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB_ENABLED \
- | PLX9052_INTCSR_LI1POL_HIGH \
- | PLX9052_INTCSR_LI2POL_HIGH \
- | PLX9052_INTCSR_PCIENAB_ENABLED \
- | PLX9052_INTCSR_LI1SEL_EDGE \
- | PLX9052_INTCSR_LI1CLRINT_ASSERTED)
+/* Disable, and clear, interrupts */
+#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1POL | \
+ PLX9052_INTCSR_LI2POL | \
+ PLX9052_INTCSR_LI1SEL | \
+ PLX9052_INTCSR_LI1CLRINT)
+
+/* Enable, and clear, interrupts */
+#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB | \
+ PLX9052_INTCSR_LI1POL | \
+ PLX9052_INTCSR_LI2POL | \
+ PLX9052_INTCSR_PCIENAB | \
+ PLX9052_INTCSR_LI1SEL | \
+ PLX9052_INTCSR_LI1CLRINT)
/*
* Board descriptions for Amplicon PC36AT and PCI236.
@@ -209,21 +205,6 @@ static struct pci_dev *pc236_find_pci_dev(struct comedi_device *dev,
}
/*
- * This function checks and requests an I/O region, reporting an error
- * if there is a conflict.
- */
-static int pc236_request_region(struct comedi_device *dev, unsigned long from,
- unsigned long extent)
-{
- if (!from || !request_region(from, extent, PC236_DRIVER_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
- from, extent);
- return -EIO;
- }
- return 0;
-}
-
-/*
* This function is called to mark the interrupt as disabled (no command
* configured on subdevice 1) and to physically disable the interrupt
* (not possible on the PC36AT, except by removing the IRQ jumper!).
@@ -272,14 +253,14 @@ static int pc236_intr_check(struct comedi_device *dev)
struct pc236_private *devpriv = dev->private;
int retval = 0;
unsigned long flags;
+ unsigned int intcsr;
spin_lock_irqsave(&dev->spinlock, flags);
if (devpriv->enable_irq) {
retval = 1;
if (is_pci_board(thisboard)) {
- if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
- & PLX9052_INTCSR_LI1STAT_MASK)
- == PLX9052_INTCSR_LI1STAT_INACTIVE) {
+ intcsr = inl(devpriv->lcr_iobase + PLX9052_INTCSR);
+ if (!(intcsr & PLX9052_INTCSR_LI1STAT)) {
retval = 0;
} else {
/* Clear interrupt and keep it enabled. */
@@ -470,12 +451,10 @@ static int pc236_pci_common_attach(struct comedi_device *dev,
comedi_set_hw_dev(dev, &pci_dev->dev);
- ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
- if (ret < 0) {
- dev_err(dev->class_dev,
- "error! cannot enable PCI device and request regions!\n");
+ ret = comedi_pci_enable(dev);
+ if (ret)
return ret;
- }
+
devpriv->lcr_iobase = pci_resource_start(pci_dev, 1);
iobase = pci_resource_start(pci_dev, 2);
return pc236_common_attach(dev, iobase, pci_dev->irq, IRQF_SHARED);
@@ -493,8 +472,6 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct pc236_private *devpriv;
int ret;
- dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach\n");
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
@@ -502,12 +479,11 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Process options according to bus type. */
if (is_isa_board(thisboard)) {
- unsigned long iobase = it->options[0];
- unsigned int irq = it->options[1];
- ret = pc236_request_region(dev, iobase, PC236_IO_SIZE);
- if (ret < 0)
+ ret = comedi_request_region(dev, it->options[0], PC236_IO_SIZE);
+ if (ret)
return ret;
- return pc236_common_attach(dev, iobase, irq, 0);
+
+ return pc236_common_attach(dev, dev->iobase, it->options[1], 0);
} else if (is_pci_board(thisboard)) {
struct pci_dev *pci_dev;
@@ -567,20 +543,16 @@ static void pc236_detach(struct comedi_device *dev)
return;
if (dev->iobase)
pc236_intr_disable(dev);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[0]);
+ comedi_spriv_free(dev, 0);
if (is_isa_board(thisboard)) {
- if (dev->iobase)
- release_region(dev->iobase, PC236_IO_SIZE);
+ comedi_legacy_detach(dev);
} else if (is_pci_board(thisboard)) {
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ comedi_pci_disable(dev);
+ if (pcidev)
pci_dev_put(pcidev);
- }
}
}
@@ -610,9 +582,10 @@ static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
MODULE_DEVICE_TABLE(pci, pc236_pci_table);
static int amplc_pc236_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &amplc_pc236_driver);
+ return comedi_pci_auto_config(dev, &amplc_pc236_driver,
+ id->driver_data);
}
static struct pci_driver amplc_pc236_pci_driver = {
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 11c1f4764eac..94a752d852bb 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -24,163 +24,41 @@
*/
/*
Driver: amplc_pc263
-Description: Amplicon PC263, PCI263
+Description: Amplicon PC263
Author: Ian Abbott <abbotti@mev.co.uk>
-Devices: [Amplicon] PC263 (pc263), PCI263 (pci263 or amplc_pc263)
-Updated: Wed, 22 Oct 2008 14:10:53 +0100
+Devices: [Amplicon] PC263 (pc263)
+Updated: Fri, 12 Apr 2013 15:19:36 +0100
Status: works
-Configuration options - PC263:
+Configuration options:
[0] - I/O port base address
-Configuration options - PCI263:
- [0] - PCI bus of device (optional)
- [1] - PCI slot of device (optional)
- If bus/slot is not specified, the first available PCI device will be
- used.
-
-Each board appears as one subdevice, with 16 digital outputs, each
+The board appears as one subdevice, with 16 digital outputs, each
connected to a reed-relay. Relay contacts are closed when output is 1.
The state of the outputs can be read.
*/
-#include <linux/pci.h>
-
#include "../comedidev.h"
#define PC263_DRIVER_NAME "amplc_pc263"
-#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
-#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
-
-/* PCI263 PCI configuration register information */
-#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
-#define PCI_DEVICE_ID_INVALID 0xffff
-
-/* PC263 / PCI263 registers */
+/* PC263 registers */
#define PC263_IO_SIZE 2
/*
- * Board descriptions for Amplicon PC263 / PCI263.
+ * Board descriptions for Amplicon PC263.
*/
-enum pc263_bustype { isa_bustype, pci_bustype };
-enum pc263_model { pc263_model, pci263_model, anypci_model };
-
struct pc263_board {
const char *name;
- unsigned short devid;
- enum pc263_bustype bustype;
- enum pc263_model model;
};
+
static const struct pc263_board pc263_boards[] = {
-#if DO_ISA
{
.name = "pc263",
- .bustype = isa_bustype,
- .model = pc263_model,
},
-#endif
-#if DO_PCI
- {
- .name = "pci263",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
- .bustype = pci_bustype,
- .model = pci263_model,
- },
- {
- .name = PC263_DRIVER_NAME,
- .devid = PCI_DEVICE_ID_INVALID,
- .bustype = pci_bustype,
- .model = anypci_model, /* wildcard */
- },
-#endif
};
-/* test if ISA supported and this is an ISA board */
-static inline bool is_isa_board(const struct pc263_board *board)
-{
- return DO_ISA && board->bustype == isa_bustype;
-}
-
-/* test if PCI supported and this is a PCI board */
-static inline bool is_pci_board(const struct pc263_board *board)
-{
- return DO_PCI && board->bustype == pci_bustype;
-}
-
-/*
- * This function looks for a board matching the supplied PCI device.
- */
-static const struct pc263_board *pc263_find_pci_board(struct pci_dev *pci_dev)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(pc263_boards); i++)
- if (is_pci_board(&pc263_boards[i]) &&
- pci_dev->device == pc263_boards[i].devid)
- return &pc263_boards[i];
- return NULL;
-}
-
-
-/*
- * This function looks for a PCI device matching the requested board name,
- * bus and slot.
- */
-static struct pci_dev *pc263_find_pci_dev(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- const struct pc263_board *thisboard = comedi_board(dev);
- struct pci_dev *pci_dev = NULL;
- int bus = it->options[0];
- int slot = it->options[1];
-
- for_each_pci_dev(pci_dev) {
- if (bus || slot) {
- if (bus != pci_dev->bus->number ||
- slot != PCI_SLOT(pci_dev->devfn))
- continue;
- }
- if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON)
- continue;
-
- if (thisboard->model == anypci_model) {
- /* Wildcard board matches any supported PCI board. */
- const struct pc263_board *foundboard;
-
- foundboard = pc263_find_pci_board(pci_dev);
- if (foundboard == NULL)
- continue;
- /* Replace wildcard board_ptr. */
- dev->board_ptr = thisboard = foundboard;
- } else {
- /* Match specific model name. */
- if (pci_dev->device != thisboard->devid)
- continue;
- }
- return pci_dev;
- }
- dev_err(dev->class_dev,
- "No supported board found! (req. bus %d, slot %d)\n",
- bus, slot);
- return NULL;
-}
-/*
- * This function checks and requests an I/O region, reporting an error
- * if there is a conflict.
- */
-static int pc263_request_region(struct comedi_device *dev, unsigned long from,
- unsigned long extent)
-{
- if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict (%#lx,%lu)!\n",
- from, extent);
- return -EIO;
- }
- return 0;
-}
-
static int pc263_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -197,30 +75,14 @@ static int pc263_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-static void pc263_report_attach(struct comedi_device *dev)
-{
- const struct pc263_board *thisboard = comedi_board(dev);
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- char tmpbuf[40];
-
- if (is_isa_board(thisboard))
- snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase);
- else if (is_pci_board(thisboard))
- snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ",
- pci_name(pcidev));
- else
- tmpbuf[0] = '\0';
- dev_info(dev->class_dev, "%s %sattached\n", dev->board_name, tmpbuf);
-}
-
-static int pc263_common_attach(struct comedi_device *dev, unsigned long iobase)
+static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- const struct pc263_board *thisboard = comedi_board(dev);
struct comedi_subdevice *s;
int ret;
- dev->board_name = thisboard->name;
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], PC263_IO_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -237,154 +99,23 @@ static int pc263_common_attach(struct comedi_device *dev, unsigned long iobase)
/* read initial relay state */
s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
- pc263_report_attach(dev);
- return 1;
-}
-
-static int pc263_pci_common_attach(struct comedi_device *dev,
- struct pci_dev *pci_dev)
-{
- unsigned long iobase;
- int ret;
-
- comedi_set_hw_dev(dev, &pci_dev->dev);
-
- ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
- if (ret < 0) {
- dev_err(dev->class_dev,
- "error! cannot enable PCI device and request regions!\n");
- return ret;
- }
- iobase = pci_resource_start(pci_dev, 2);
- return pc263_common_attach(dev, iobase);
-}
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- const struct pc263_board *thisboard = comedi_board(dev);
- int ret;
-
- dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n");
-
- /* Process options and reserve resources according to bus type. */
- if (is_isa_board(thisboard)) {
- unsigned long iobase = it->options[0];
- ret = pc263_request_region(dev, iobase, PC263_IO_SIZE);
- if (ret < 0)
- return ret;
- return pc263_common_attach(dev, iobase);
- } else if (is_pci_board(thisboard)) {
- struct pci_dev *pci_dev;
-
- pci_dev = pc263_find_pci_dev(dev, it);
- if (!pci_dev)
- return -EIO;
- return pc263_pci_common_attach(dev, pci_dev);
- } else {
- dev_err(dev->class_dev, PC263_DRIVER_NAME
- ": BUG! cannot determine board type!\n");
- return -EINVAL;
- }
-}
-
-/*
- * The auto_attach hook is called at PCI probe time via
- * comedi_pci_auto_config(). dev->board_ptr is NULL on entry.
- * There should be a board entry matching the supplied PCI device.
- */
-static int pc263_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
-{
- struct pci_dev *pci_dev;
-
- if (!DO_PCI)
- return -EINVAL;
-
- pci_dev = comedi_to_pci_dev(dev);
- dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n",
- pci_name(pci_dev));
- dev->board_ptr = pc263_find_pci_board(pci_dev);
- if (dev->board_ptr == NULL) {
- dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
- return -EINVAL;
- }
- /*
- * Need to 'get' the PCI device to match the 'put' in pc263_detach().
- * TODO: Remove the pci_dev_get() and matching pci_dev_put() once
- * support for manual attachment of PCI devices via pc263_attach()
- * has been removed.
- */
- pci_dev_get(pci_dev);
- return pc263_pci_common_attach(dev, pci_dev);
-}
-
-static void pc263_detach(struct comedi_device *dev)
-{
- const struct pc263_board *thisboard = comedi_board(dev);
-
- if (!thisboard)
- return;
- if (is_isa_board(thisboard)) {
- if (dev->iobase)
- release_region(dev->iobase, PC263_IO_SIZE);
- } else if (is_pci_board(thisboard)) {
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- pci_dev_put(pcidev);
- }
- }
+ dev_info(dev->class_dev, "%s (base %#lx) attached\n", dev->board_name,
+ dev->iobase);
+ return 0;
}
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
static struct comedi_driver amplc_pc263_driver = {
.driver_name = PC263_DRIVER_NAME,
.module = THIS_MODULE,
.attach = pc263_attach,
- .auto_attach = pc263_auto_attach,
- .detach = pc263_detach,
+ .detach = comedi_legacy_detach,
.board_name = &pc263_boards[0].name,
.offset = sizeof(struct pc263_board),
.num_names = ARRAY_SIZE(pc263_boards),
};
-#if DO_PCI
-static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
- {0}
-};
-MODULE_DEVICE_TABLE(pci, pc263_pci_table);
-
-static int amplc_pc263_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, &amplc_pc263_driver);
-}
-
-static struct pci_driver amplc_pc263_pci_driver = {
- .name = PC263_DRIVER_NAME,
- .id_table = pc263_pci_table,
- .probe = &amplc_pc263_pci_probe,
- .remove = comedi_pci_auto_unconfig,
-};
-module_comedi_pci_driver(amplc_pc263_driver, amplc_pc263_pci_driver);
-#else
module_comedi_driver(amplc_pc263_driver);
-#endif
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Amplicon PC263 relay board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index c9da4cd74baa..4d7eab9b5565 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -1280,13 +1280,10 @@ static int pci224_attach_common(struct comedi_device *dev,
comedi_set_hw_dev(dev, &pci_dev->dev);
- ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
- if (ret < 0) {
- dev_err(dev->class_dev,
- "error! cannot enable PCI device and request regions!\n"
- );
+ ret = comedi_pci_enable(dev);
+ if (ret)
return ret;
- }
+
spin_lock_init(&devpriv->ao_spinlock);
devpriv->iobase1 = pci_resource_start(pci_dev, 2);
@@ -1488,11 +1485,9 @@ static void pci224_detach(struct comedi_device *dev)
kfree(devpriv->ao_scan_vals);
kfree(devpriv->ao_scan_order);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ comedi_pci_disable(dev);
+ if (pcidev)
pci_dev_put(pcidev);
- }
}
static struct comedi_driver amplc_pci224_driver = {
@@ -1507,10 +1502,10 @@ static struct comedi_driver amplc_pci224_driver = {
};
static int amplc_pci224_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &amplc_pci224_driver);
+ return comedi_pci_auto_config(dev, &amplc_pci224_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index e2244c6e536b..49200fbd60b9 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2645,12 +2645,11 @@ static int pci230_attach_common(struct comedi_device *dev,
comedi_set_hw_dev(dev, &pci_dev->dev);
dev->board_name = thisboard->name;
- /* Enable PCI device and reserve I/O spaces. */
- if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) {
- dev_err(dev->class_dev,
- "failed to enable PCI device and request regions\n");
- return -EIO;
- }
+
+ rc = comedi_pci_enable(dev);
+ if (rc)
+ return rc;
+
/* Read base addresses of the PCI230's two I/O regions from PCI
* configuration register. */
iobase1 = pci_resource_start(pci_dev, 2);
@@ -2833,18 +2832,14 @@ static int pci230_auto_attach(struct comedi_device *dev,
static void pci230_detach(struct comedi_device *dev)
{
- const struct pci230_board *thisboard = comedi_board(dev);
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- if (dev->subdevices && thisboard->have_dio)
- subdev_8255_cleanup(dev, &dev->subdevices[2]);
+ comedi_spriv_free(dev, 2);
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ comedi_pci_disable(dev);
+ if (pcidev)
pci_dev_put(pcidev);
- }
}
static struct comedi_driver amplc_pci230_driver = {
@@ -2859,9 +2854,10 @@ static struct comedi_driver amplc_pci230_driver = {
};
static int amplc_pci230_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &amplc_pci230_driver);
+ return comedi_pci_auto_config(dev, &amplc_pci230_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c
new file mode 100644
index 000000000000..8b57533bf406
--- /dev/null
+++ b/drivers/staging/comedi/drivers/amplc_pci263.c
@@ -0,0 +1,127 @@
+/*
+ comedi/drivers/amplc_pci263.c
+ Driver for Amplicon PCI263 relay board.
+
+ Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/>
+
+ COMEDI - Linux Control and Measurement Device Interface
+ Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+/*
+Driver: amplc_pci263
+Description: Amplicon PCI263
+Author: Ian Abbott <abbotti@mev.co.uk>
+Devices: [Amplicon] PCI263 (amplc_pci263)
+Updated: Fri, 12 Apr 2013 15:19:36 +0100
+Status: works
+
+Configuration options: not applicable, uses PCI auto config
+
+The board appears as one subdevice, with 16 digital outputs, each
+connected to a reed-relay. Relay contacts are closed when output is 1.
+The state of the outputs can be read.
+*/
+
+#include <linux/pci.h>
+
+#include "../comedidev.h"
+
+#define PCI263_DRIVER_NAME "amplc_pci263"
+
+/* PCI263 PCI configuration register information */
+#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
+
+static int pci263_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ /* The insn data is a mask in data[0] and the new data
+ * in data[1], each channel cooresponding to a bit. */
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ /* Write out the new digital output lines */
+ outb(s->state & 0xFF, dev->iobase);
+ outb(s->state >> 8, dev->iobase + 1);
+ }
+ return insn->n;
+}
+
+static int pci263_auto_attach(struct comedi_device *dev,
+ unsigned long context_unused)
+{
+ struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
+ struct comedi_subdevice *s;
+ int ret;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
+ dev->iobase = pci_resource_start(pci_dev, 2);
+ ret = comedi_alloc_subdevices(dev, 1);
+ if (ret)
+ return ret;
+
+ s = &dev->subdevices[0];
+ /* digital output subdevice */
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci263_do_insn_bits;
+ /* read initial relay state */
+ s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8);
+
+ dev_info(dev->class_dev, "%s (pci %s) attached\n", dev->board_name,
+ pci_name(pci_dev));
+ return 0;
+}
+
+static struct comedi_driver amplc_pci263_driver = {
+ .driver_name = PCI263_DRIVER_NAME,
+ .module = THIS_MODULE,
+ .auto_attach = pci263_auto_attach,
+ .detach = comedi_pci_disable,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(pci263_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, pci263_pci_table);
+
+static int amplc_pci263_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &amplc_pci263_driver,
+ id->driver_data);
+}
+
+static struct pci_driver amplc_pci263_pci_driver = {
+ .name = PCI263_DRIVER_NAME,
+ .id_table = pci263_pci_table,
+ .probe = &amplc_pci263_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+module_comedi_pci_driver(amplc_pci263_driver, amplc_pci263_pci_driver);
+
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_DESCRIPTION("Comedi driver for Amplicon PCI263 relay board");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 070037c22db7..92376dc86dd8 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -397,12 +397,6 @@ static void board_init(struct comedi_device *dev)
}
-/*
- options[0] - I/O port
- options[1] - irq
- options[2] - number of encoder chips installed
- */
-
static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
/* Standard LPT Printer Port */
{.id = "PNP0400", .driver_data = 0},
@@ -419,34 +413,20 @@ static struct pnp_driver c6xdigio_pnp_driver = {
static int c6xdigio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
- int result = 0;
- unsigned long iobase;
- unsigned int irq;
struct comedi_subdevice *s;
+ int ret;
- iobase = it->options[0];
- printk(KERN_DEBUG "comedi%d: c6xdigio: 0x%04lx\n", dev->minor, iobase);
- if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) {
- printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = "c6xdigio";
+ ret = comedi_request_region(dev, it->options[0], C6XDIGIO_SIZE);
+ if (ret)
+ return ret;
- result = comedi_alloc_subdevices(dev, 2);
- if (result)
- return result;
+ ret = comedi_alloc_subdevices(dev, 2);
+ if (ret)
+ return ret;
/* Make sure that PnP ports get activated */
pnp_register_driver(&c6xdigio_pnp_driver);
- irq = it->options[1];
- if (irq > 0)
- printk(KERN_DEBUG "comedi%d: irq = %u ignored\n",
- dev->minor, irq);
- else if (irq == 0)
- printk(KERN_DEBUG "comedi%d: no irq\n", dev->minor);
-
s = &dev->subdevices[0];
/* pwm output subdevice */
s->type = COMEDI_SUBD_AO; /* Not sure what to put here */
@@ -488,10 +468,7 @@ static int c6xdigio_attach(struct comedi_device *dev,
static void c6xdigio_detach(struct comedi_device *dev)
{
- if (dev->iobase)
- release_region(dev->iobase, C6XDIGIO_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
+ comedi_legacy_detach(dev);
pnp_unregister_driver(&c6xdigio_pnp_driver);
}
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 79c72118a090..53dd298d2b54 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -231,9 +231,19 @@ enum trimpot_model {
AD8402,
};
+enum cb_pcidas_boardid {
+ BOARD_PCIDAS1602_16,
+ BOARD_PCIDAS1200,
+ BOARD_PCIDAS1602_12,
+ BOARD_PCIDAS1200_JR,
+ BOARD_PCIDAS1602_16_JR,
+ BOARD_PCIDAS1000,
+ BOARD_PCIDAS1001,
+ BOARD_PCIDAS1002,
+};
+
struct cb_pcidas_board {
const char *name;
- unsigned short device_id;
int ai_nchan; /* Inputs in single-ended mode */
int ai_bits; /* analog input resolution */
int ai_speed; /* fastest conversion period in ns */
@@ -248,9 +258,8 @@ struct cb_pcidas_board {
};
static const struct cb_pcidas_board cb_pcidas_boards[] = {
- {
+ [BOARD_PCIDAS1602_16] = {
.name = "pci-das1602/16",
- .device_id = 0x1,
.ai_nchan = 16,
.ai_bits = 16,
.ai_speed = 5000,
@@ -262,9 +271,9 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
.trimpot = AD8402,
.has_dac08 = 1,
.is_1602 = 1,
- }, {
+ },
+ [BOARD_PCIDAS1200] = {
.name = "pci-das1200",
- .device_id = 0xF,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 3200,
@@ -272,9 +281,9 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
.fifo_size = 1024,
.ranges = &cb_pcidas_ranges,
.trimpot = AD7376,
- }, {
+ },
+ [BOARD_PCIDAS1602_12] = {
.name = "pci-das1602/12",
- .device_id = 0x10,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 3200,
@@ -285,18 +294,18 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
.ranges = &cb_pcidas_ranges,
.trimpot = AD7376,
.is_1602 = 1,
- }, {
+ },
+ [BOARD_PCIDAS1200_JR] = {
.name = "pci-das1200/jr",
- .device_id = 0x19,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 3200,
.fifo_size = 1024,
.ranges = &cb_pcidas_ranges,
.trimpot = AD7376,
- }, {
+ },
+ [BOARD_PCIDAS1602_16_JR] = {
.name = "pci-das1602/16/jr",
- .device_id = 0x1C,
.ai_nchan = 16,
.ai_bits = 16,
.ai_speed = 5000,
@@ -305,18 +314,18 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
.trimpot = AD8402,
.has_dac08 = 1,
.is_1602 = 1,
- }, {
+ },
+ [BOARD_PCIDAS1000] = {
.name = "pci-das1000",
- .device_id = 0x4C,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 4000,
.fifo_size = 1024,
.ranges = &cb_pcidas_ranges,
.trimpot = AD7376,
- }, {
+ },
+ [BOARD_PCIDAS1001] = {
.name = "pci-das1001",
- .device_id = 0x1a,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 6800,
@@ -324,9 +333,9 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
.fifo_size = 1024,
.ranges = &cb_pcidas_alt_ranges,
.trimpot = AD7376,
- }, {
+ },
+ [BOARD_PCIDAS1002] = {
.name = "pci-das1002",
- .device_id = 0x1b,
.ai_nchan = 16,
.ai_bits = 12,
.ai_speed = 6800,
@@ -1332,7 +1341,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
static const int timeout = 10000;
unsigned long flags;
- if (dev->attached == 0)
+ if (!dev->attached)
return IRQ_NONE;
async = s->async;
@@ -1424,31 +1433,18 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
-static const void *cb_pcidas_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct cb_pcidas_board *thisboard;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) {
- thisboard = &cb_pcidas_boards[i];
- if (thisboard->device_id == pcidev->device)
- return thisboard;
- }
- return NULL;
-}
-
static int cb_pcidas_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct cb_pcidas_board *thisboard;
+ const struct cb_pcidas_board *thisboard = NULL;
struct cb_pcidas_private *devpriv;
struct comedi_subdevice *s;
int i;
int ret;
- thisboard = cb_pcidas_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(cb_pcidas_boards))
+ thisboard = &cb_pcidas_boards[context];
if (!thisboard)
return -ENODEV;
dev->board_ptr = thisboard;
@@ -1459,7 +1455,7 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -1603,7 +1599,6 @@ static int cb_pcidas_auto_attach(struct comedi_device *dev,
static void cb_pcidas_detach(struct comedi_device *dev)
{
struct cb_pcidas_private *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
if (devpriv) {
if (devpriv->s5933_config) {
@@ -1613,12 +1608,8 @@ static void cb_pcidas_detach(struct comedi_device *dev)
}
if (dev->irq)
free_irq(dev->irq, dev);
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[2]);
- if (pcidev) {
- if (devpriv->s5933_config)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 2);
+ comedi_pci_disable(dev);
}
static struct comedi_driver cb_pcidas_driver = {
@@ -1629,20 +1620,21 @@ static struct comedi_driver cb_pcidas_driver = {
};
static int cb_pcidas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &cb_pcidas_driver);
+ return comedi_pci_auto_config(dev, &cb_pcidas_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
+ { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
+ { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
+ { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
+ { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
+ { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
+ { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
+ { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
+ { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 9f3112cb7a21..c3e5495b4f06 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -118,13 +118,6 @@ static const int max_counter_value = 0xffffff;
/* PCI-DAS64xxx base addresses */
-/* indices of base address regions */
-enum base_address_regions {
- PLX9080_BADDRINDEX = 0,
- MAIN_BADDRINDEX = 2,
- DIO_COUNTER_BADDRINDEX = 3,
-};
-
/* devpriv->main_iobase registers */
enum write_only_registers {
INTR_ENABLE_REG = 0x0, /* interrupt enable register */
@@ -543,13 +536,6 @@ static const int ao_range_code_64xx[] = {
0x3,
};
-static const struct comedi_lrange ao_ranges_60xx = {
- 1,
- {
- BIP_RANGE(10),
- }
-};
-
static const int ao_range_code_60xx[] = {
0x0,
};
@@ -593,9 +579,39 @@ struct hw_fifo_info {
uint16_t fifo_size_reg_mask;
};
+enum pcidas64_boardid {
+ BOARD_PCIDAS6402_16,
+ BOARD_PCIDAS6402_12,
+ BOARD_PCIDAS64_M1_16,
+ BOARD_PCIDAS64_M2_16,
+ BOARD_PCIDAS64_M3_16,
+ BOARD_PCIDAS6013,
+ BOARD_PCIDAS6014,
+ BOARD_PCIDAS6023,
+ BOARD_PCIDAS6025,
+ BOARD_PCIDAS6030,
+ BOARD_PCIDAS6031,
+ BOARD_PCIDAS6032,
+ BOARD_PCIDAS6033,
+ BOARD_PCIDAS6034,
+ BOARD_PCIDAS6035,
+ BOARD_PCIDAS6036,
+ BOARD_PCIDAS6040,
+ BOARD_PCIDAS6052,
+ BOARD_PCIDAS6070,
+ BOARD_PCIDAS6071,
+ BOARD_PCIDAS4020_12,
+ BOARD_PCIDAS6402_16_JR,
+ BOARD_PCIDAS64_M1_16_JR,
+ BOARD_PCIDAS64_M2_16_JR,
+ BOARD_PCIDAS64_M3_16_JR,
+ BOARD_PCIDAS64_M1_14,
+ BOARD_PCIDAS64_M2_14,
+ BOARD_PCIDAS64_M3_14,
+};
+
struct pcidas64_board {
const char *name;
- int device_id; /* pci device id */
int ai_se_chans; /* number of ai inputs in single-ended mode */
int ai_bits; /* analog input resolution */
int ai_speed; /* fastest conversion period in ns */
@@ -648,421 +664,397 @@ static inline unsigned int ai_dma_ring_count(const struct pcidas64_board *board)
static const int bytes_in_sample = 2;
static const struct pcidas64_board pcidas64_boards[] = {
- {
- .name = "pci-das6402/16",
- .device_id = 0x1d,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ao_range_table = &ao_ranges_64xx,
- .ao_range_code = ao_range_code_64xx,
- .ai_fifo = &ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das6402/12", /* XXX check */
- .device_id = 0x1e,
- .ai_se_chans = 64,
- .ai_bits = 12,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ao_range_table = &ao_ranges_64xx,
- .ao_range_code = ao_range_code_64xx,
- .ai_fifo = &ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m1/16",
- .device_id = 0x35,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 1000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ao_range_table = &ao_ranges_64xx,
- .ao_range_code = ao_range_code_64xx,
- .ai_fifo = &ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m2/16",
- .device_id = 0x36,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 500,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ao_range_table = &ao_ranges_64xx,
- .ao_range_code = ao_range_code_64xx,
- .ai_fifo = &ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m3/16",
- .device_id = 0x37,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 333,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ao_range_table = &ao_ranges_64xx,
- .ao_range_code = ao_range_code_64xx,
- .ai_fifo = &ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das6013",
- .device_id = 0x78,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 0,
- .ao_bits = 16,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6014",
- .device_id = 0x79,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 100000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6023",
- .device_id = 0x5d,
- .ai_se_chans = 16,
- .ai_bits = 12,
- .ai_speed = 5000,
- .ao_nchan = 0,
- .ao_scan_speed = 100000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das6025",
- .device_id = 0x5e,
- .ai_se_chans = 16,
- .ai_bits = 12,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 100000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das6030",
- .device_id = 0x5f,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 10000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6030,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6031",
- .device_id = 0x60,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 10000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6030,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6032",
- .device_id = 0x61,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 10000,
- .ao_nchan = 0,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6033",
- .device_id = 0x62,
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 10000,
- .ao_nchan = 0,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6034",
- .device_id = 0x63,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 0,
- .ao_scan_speed = 0,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6035",
- .device_id = 0x64,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 100000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6036",
- .device_id = 0x6f,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 100000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_60xx,
- .ao_range_table = &ao_ranges_60xx,
- .ao_range_code = ao_range_code_60xx,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6040",
- .device_id = 0x65,
- .ai_se_chans = 16,
- .ai_bits = 12,
- .ai_speed = 2000,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 1000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6052,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6052",
- .device_id = 0x66,
- .ai_se_chans = 16,
- .ai_bits = 16,
- .ai_speed = 3333,
- .ao_nchan = 2,
- .ao_bits = 16,
- .ao_scan_speed = 3333,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6052,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6070",
- .device_id = 0x67,
- .ai_se_chans = 16,
- .ai_bits = 12,
- .ai_speed = 800,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 1000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6052,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das6071",
- .device_id = 0x68,
- .ai_se_chans = 64,
- .ai_bits = 12,
- .ai_speed = 800,
- .ao_nchan = 2,
- .ao_bits = 12,
- .ao_scan_speed = 1000,
- .layout = LAYOUT_60XX,
- .ai_range_table = &ai_ranges_6052,
- .ao_range_table = &ao_ranges_6030,
- .ao_range_code = ao_range_code_6030,
- .ai_fifo = &ai_fifo_60xx,
- .has_8255 = 0,
- },
- {
- .name = "pci-das4020/12",
- .device_id = 0x52,
- .ai_se_chans = 4,
- .ai_bits = 12,
- .ai_speed = 50,
- .ao_bits = 12,
- .ao_nchan = 2,
- .ao_scan_speed = 0, /* no hardware pacing on ao */
- .layout = LAYOUT_4020,
- .ai_range_table = &ai_ranges_4020,
- .ao_range_table = &ao_ranges_4020,
- .ao_range_code = ao_range_code_4020,
- .ai_fifo = &ai_fifo_4020,
- .has_8255 = 1,
- },
+ [BOARD_PCIDAS6402_16] = {
+ .name = "pci-das6402/16",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS6402_12] = {
+ .name = "pci-das6402/12", /* XXX check */
+ .ai_se_chans = 64,
+ .ai_bits = 12,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M1_16] = {
+ .name = "pci-das64/m1/16",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 1000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M2_16] = {
+ .name = "pci-das64/m2/16",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 500,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M3_16] = {
+ .name = "pci-das64/m3/16",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 333,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ao_range_table = &ao_ranges_64xx,
+ .ao_range_code = ao_range_code_64xx,
+ .ai_fifo = &ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS6013] = {
+ .name = "pci-das6013",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 0,
+ .ao_bits = 16,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6014] = {
+ .name = "pci-das6014",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6023] = {
+ .name = "pci-das6023",
+ .ai_se_chans = 16,
+ .ai_bits = 12,
+ .ai_speed = 5000,
+ .ao_nchan = 0,
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS6025] = {
+ .name = "pci-das6025",
+ .ai_se_chans = 16,
+ .ai_bits = 12,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS6030] = {
+ .name = "pci-das6030",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 10000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6031] = {
+ .name = "pci-das6031",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 10000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6032] = {
+ .name = "pci-das6032",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 10000,
+ .ao_nchan = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6033] = {
+ .name = "pci-das6033",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 10000,
+ .ao_nchan = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6034] = {
+ .name = "pci-das6034",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 0,
+ .ao_scan_speed = 0,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6035] = {
+ .name = "pci-das6035",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6036] = {
+ .name = "pci-das6036",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 100000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_60xx,
+ .ao_range_table = &range_bipolar10,
+ .ao_range_code = ao_range_code_60xx,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6040] = {
+ .name = "pci-das6040",
+ .ai_se_chans = 16,
+ .ai_bits = 12,
+ .ai_speed = 2000,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6052] = {
+ .name = "pci-das6052",
+ .ai_se_chans = 16,
+ .ai_bits = 16,
+ .ai_speed = 3333,
+ .ao_nchan = 2,
+ .ao_bits = 16,
+ .ao_scan_speed = 3333,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6070] = {
+ .name = "pci-das6070",
+ .ai_se_chans = 16,
+ .ai_bits = 12,
+ .ai_speed = 800,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS6071] = {
+ .name = "pci-das6071",
+ .ai_se_chans = 64,
+ .ai_bits = 12,
+ .ai_speed = 800,
+ .ao_nchan = 2,
+ .ao_bits = 12,
+ .ao_scan_speed = 1000,
+ .layout = LAYOUT_60XX,
+ .ai_range_table = &ai_ranges_6052,
+ .ao_range_table = &ao_ranges_6030,
+ .ao_range_code = ao_range_code_6030,
+ .ai_fifo = &ai_fifo_60xx,
+ .has_8255 = 0,
+ },
+ [BOARD_PCIDAS4020_12] = {
+ .name = "pci-das4020/12",
+ .ai_se_chans = 4,
+ .ai_bits = 12,
+ .ai_speed = 50,
+ .ao_bits = 12,
+ .ao_nchan = 2,
+ .ao_scan_speed = 0, /* no hardware pacing on ao */
+ .layout = LAYOUT_4020,
+ .ai_range_table = &ai_ranges_4020,
+ .ao_range_table = &ao_ranges_4020,
+ .ao_range_code = ao_range_code_4020,
+ .ai_fifo = &ai_fifo_4020,
+ .has_8255 = 1,
+ },
#if 0
- {
- .name = "pci-das6402/16/jr",
- .device_id = 0 /* XXX, */
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 5000,
- .ao_nchan = 0,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m1/16/jr",
- .device_id = 0 /* XXX, */
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 1000,
- .ao_nchan = 0,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m2/16/jr",
- .device_id = 0 /* XXX, */
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 500,
- .ao_nchan = 0,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m3/16/jr",
- .device_id = 0 /* XXX, */
- .ai_se_chans = 64,
- .ai_bits = 16,
- .ai_speed = 333,
- .ao_nchan = 0,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m1/14",
- .device_id = 0, /* XXX */
- .ai_se_chans = 64,
- .ai_bits = 14,
- .ai_speed = 1000,
- .ao_nchan = 2,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m2/14",
- .device_id = 0, /* XXX */
- .ai_se_chans = 64,
- .ai_bits = 14,
- .ai_speed = 500,
- .ao_nchan = 2,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
- {
- .name = "pci-das64/m3/14",
- .device_id = 0, /* XXX */
- .ai_se_chans = 64,
- .ai_bits = 14,
- .ai_speed = 333,
- .ao_nchan = 2,
- .ao_scan_speed = 10000,
- .layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
- .ai_fifo = ai_fifo_64xx,
- .has_8255 = 1,
- },
+ /*
+ * The device id for these boards is unknown
+ */
+
+ [BOARD_PCIDAS6402_16_JR] = {
+ .name = "pci-das6402/16/jr",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 5000,
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M1_16_JR] = {
+ .name = "pci-das64/m1/16/jr",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 1000,
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M2_16_JR] = {
+ .name = "pci-das64/m2/16/jr",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 500,
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M3_16_JR] = {
+ .name = "pci-das64/m3/16/jr",
+ .ai_se_chans = 64,
+ .ai_bits = 16,
+ .ai_speed = 333,
+ .ao_nchan = 0,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M1_14] = {
+ .name = "pci-das64/m1/14",
+ .ai_se_chans = 64,
+ .ai_bits = 14,
+ .ai_speed = 1000,
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M2_14] = {
+ .name = "pci-das64/m2/14",
+ .ai_se_chans = 64,
+ .ai_bits = 14,
+ .ai_speed = 500,
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
+ [BOARD_PCIDAS64_M3_14] = {
+ .name = "pci-das64/m3/14",
+ .ai_se_chans = 64,
+ .ai_bits = 14,
+ .ai_speed = 333,
+ .ao_nchan = 2,
+ .ao_scan_speed = 10000,
+ .layout = LAYOUT_64XX,
+ .ai_range_table = &ai_ranges_64xx,
+ .ai_fifo = ai_fifo_64xx,
+ .has_8255 = 1,
+ },
#endif
};
@@ -1088,7 +1080,6 @@ struct ext_clock_info {
/* this structure is for data unique to this hardware driver. */
struct pcidas64_private {
/* base addresses (physical) */
- resource_size_t plx9080_phys_iobase;
resource_size_t main_phys_iobase;
resource_size_t dio_counter_phys_iobase;
/* base addresses (ioremapped) */
@@ -1523,7 +1514,7 @@ static int alloc_and_init_dma_members(struct comedi_device *dev)
struct pcidas64_private *devpriv = dev->private;
int i;
- /* alocate pci dma buffers */
+ /* allocate pci dma buffers */
for (i = 0; i < ai_dma_ring_count(thisboard); i++) {
devpriv->ai_buffer[i] =
pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE,
@@ -3107,7 +3098,7 @@ static irqreturn_t handle_interrupt(int irq, void *d)
/* an interrupt before all the postconfig stuff gets done could
* cause a NULL dereference if we continue through the
* interrupt handler */
- if (dev->attached == 0) {
+ if (!dev->attached) {
DEBUG_PRINT("premature interrupt, ignoring\n");
return IRQ_HANDLED;
}
@@ -4033,68 +4024,40 @@ static int setup_subdevices(struct comedi_device *dev)
return 0;
}
-static const struct pcidas64_board
-*cb_pcidas64_find_pci_board(struct pci_dev *pcidev)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(pcidas64_boards); i++)
- if (pcidev->device == pcidas64_boards[i].device_id)
- return &pcidas64_boards[i];
- return NULL;
-}
-
static int auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
- const struct pcidas64_board *thisboard;
- struct pcidas64_private *devpriv;
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct pcidas64_board *thisboard = NULL;
+ struct pcidas64_private *devpriv;
uint32_t local_range, local_decode;
int retval;
- dev->board_ptr = cb_pcidas64_find_pci_board(pcidev);
- if (!dev->board_ptr) {
- dev_err(dev->class_dev,
- "cb_pcidas64: does not support pci %s\n",
- pci_name(pcidev));
- return -EINVAL;
- }
- thisboard = comedi_board(dev);
+ if (context < ARRAY_SIZE(pcidas64_boards))
+ thisboard = &pcidas64_boards[context];
+ if (!thisboard)
+ return -ENODEV;
+ dev->board_ptr = thisboard;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
- dev_warn(dev->class_dev,
- "failed to enable PCI device and request regions\n");
- return -EIO;
- }
+ retval = comedi_pci_enable(dev);
+ if (retval)
+ return retval;
pci_set_master(pcidev);
/* Initialize dev->board_name */
dev->board_name = thisboard->name;
- dev->iobase = pci_resource_start(pcidev, MAIN_BADDRINDEX);
-
- devpriv->plx9080_phys_iobase =
- pci_resource_start(pcidev, PLX9080_BADDRINDEX);
- devpriv->main_phys_iobase = dev->iobase;
- devpriv->dio_counter_phys_iobase =
- pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX);
-
- /* remap, won't work with 2.0 kernels but who cares */
- devpriv->plx9080_iobase =
- ioremap(devpriv->plx9080_phys_iobase,
- pci_resource_len(pcidev, PLX9080_BADDRINDEX));
- devpriv->main_iobase =
- ioremap(devpriv->main_phys_iobase,
- pci_resource_len(pcidev, MAIN_BADDRINDEX));
- devpriv->dio_counter_iobase =
- ioremap(devpriv->dio_counter_phys_iobase,
- pci_resource_len(pcidev, DIO_COUNTER_BADDRINDEX));
+ devpriv->main_phys_iobase = pci_resource_start(pcidev, 2);
+ devpriv->dio_counter_phys_iobase = pci_resource_start(pcidev, 3);
+
+ devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0);
+ devpriv->main_iobase = pci_ioremap_bar(pcidev, 2);
+ devpriv->dio_counter_iobase = pci_ioremap_bar(pcidev, 3);
if (!devpriv->plx9080_iobase || !devpriv->main_iobase
|| !devpriv->dio_counter_iobase) {
@@ -4200,12 +4163,8 @@ static void detach(struct comedi_device *dev)
devpriv->ao_dma_desc_bus_addr);
}
}
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[4]);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 4);
+ comedi_pci_disable(dev);
}
static struct comedi_driver cb_pcidas64_driver = {
@@ -4216,31 +4175,34 @@ static struct comedi_driver cb_pcidas64_driver = {
};
static int cb_pcidas64_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &cb_pcidas64_driver);
+ return comedi_pci_auto_config(dev, &cb_pcidas64_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001d) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001e) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0035) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0036) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0037) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0052) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005d) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005e) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x005f) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0061) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0062) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0063) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0064) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0066) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0067) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0068) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x006f) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0078) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0079) },
+ { PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 },
+ { PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 },
+ { PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 },
+ { PCI_VDEVICE(CB, 0x0036), BOARD_PCIDAS64_M2_16 },
+ { PCI_VDEVICE(CB, 0x0037), BOARD_PCIDAS64_M3_16 },
+ { PCI_VDEVICE(CB, 0x0052), BOARD_PCIDAS4020_12 },
+ { PCI_VDEVICE(CB, 0x005d), BOARD_PCIDAS6023 },
+ { PCI_VDEVICE(CB, 0x005e), BOARD_PCIDAS6025 },
+ { PCI_VDEVICE(CB, 0x005f), BOARD_PCIDAS6030 },
+ { PCI_VDEVICE(CB, 0x0060), BOARD_PCIDAS6031 },
+ { PCI_VDEVICE(CB, 0x0061), BOARD_PCIDAS6032 },
+ { PCI_VDEVICE(CB, 0x0062), BOARD_PCIDAS6033 },
+ { PCI_VDEVICE(CB, 0x0063), BOARD_PCIDAS6034 },
+ { PCI_VDEVICE(CB, 0x0064), BOARD_PCIDAS6035 },
+ { PCI_VDEVICE(CB, 0x0065), BOARD_PCIDAS6040 },
+ { PCI_VDEVICE(CB, 0x0066), BOARD_PCIDAS6052 },
+ { PCI_VDEVICE(CB, 0x0067), BOARD_PCIDAS6070 },
+ { PCI_VDEVICE(CB, 0x0068), BOARD_PCIDAS6071 },
+ { PCI_VDEVICE(CB, 0x006f), BOARD_PCIDAS6036 },
+ { PCI_VDEVICE(CB, 0x0078), BOARD_PCIDAS6013 },
+ { PCI_VDEVICE(CB, 0x0079), BOARD_PCIDAS6014 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table);
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index e2cadc728455..f9b459888b8b 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -48,16 +48,6 @@
#include "comedi_fc.h"
#include "8255.h"
-/*
- * ComputerBoards PCI Device ID's supported by this driver
- */
-#define PCI_DEVICE_ID_DDA02_12 0x0020
-#define PCI_DEVICE_ID_DDA04_12 0x0021
-#define PCI_DEVICE_ID_DDA08_12 0x0022
-#define PCI_DEVICE_ID_DDA02_16 0x0023
-#define PCI_DEVICE_ID_DDA04_16 0x0024
-#define PCI_DEVICE_ID_DDA08_16 0x0025
-
#define EEPROM_SIZE 128 /* number of entries in eeprom */
/* maximum number of ao channels for supported boards */
#define MAX_AO_CHANNELS 8
@@ -118,42 +108,49 @@ static const struct comedi_lrange cb_pcidda_ranges = {
}
};
+enum cb_pcidda_boardid {
+ BOARD_DDA02_12,
+ BOARD_DDA04_12,
+ BOARD_DDA08_12,
+ BOARD_DDA02_16,
+ BOARD_DDA04_16,
+ BOARD_DDA08_16,
+};
+
struct cb_pcidda_board {
const char *name;
- unsigned short device_id;
int ao_chans;
int ao_bits;
};
static const struct cb_pcidda_board cb_pcidda_boards[] = {
- {
+ [BOARD_DDA02_12] = {
.name = "pci-dda02/12",
- .device_id = PCI_DEVICE_ID_DDA02_12,
.ao_chans = 2,
.ao_bits = 12,
- }, {
+ },
+ [BOARD_DDA04_12] = {
.name = "pci-dda04/12",
- .device_id = PCI_DEVICE_ID_DDA04_12,
.ao_chans = 4,
.ao_bits = 12,
- }, {
+ },
+ [BOARD_DDA08_12] = {
.name = "pci-dda08/12",
- .device_id = PCI_DEVICE_ID_DDA08_12,
.ao_chans = 8,
.ao_bits = 12,
- }, {
+ },
+ [BOARD_DDA02_16] = {
.name = "pci-dda02/16",
- .device_id = PCI_DEVICE_ID_DDA02_16,
.ao_chans = 2,
.ao_bits = 16,
- }, {
+ },
+ [BOARD_DDA04_16] = {
.name = "pci-dda04/16",
- .device_id = PCI_DEVICE_ID_DDA04_16,
.ao_chans = 4,
.ao_bits = 16,
- }, {
+ },
+ [BOARD_DDA08_16] = {
.name = "pci-dda08/16",
- .device_id = PCI_DEVICE_ID_DDA08_16,
.ao_chans = 8,
.ao_bits = 16,
},
@@ -337,32 +334,19 @@ static int cb_pcidda_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
-static const void *cb_pcidda_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct cb_pcidda_board *thisboard;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) {
- thisboard = &cb_pcidda_boards[i];
- if (thisboard->device_id != pcidev->device)
- return thisboard;
- }
- return NULL;
-}
-
static int cb_pcidda_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct cb_pcidda_board *thisboard;
+ const struct cb_pcidda_board *thisboard = NULL;
struct cb_pcidda_private *devpriv;
struct comedi_subdevice *s;
unsigned long iobase_8255;
int i;
int ret;
- thisboard = cb_pcidda_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(cb_pcidda_boards))
+ thisboard = &cb_pcidda_boards[context];
if (!thisboard)
return -ENODEV;
dev->board_ptr = thisboard;
@@ -373,7 +357,7 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 3);
@@ -415,16 +399,9 @@ static int cb_pcidda_auto_attach(struct comedi_device *dev,
static void cb_pcidda_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (dev->subdevices) {
- subdev_8255_cleanup(dev, &dev->subdevices[1]);
- subdev_8255_cleanup(dev, &dev->subdevices[2]);
- }
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 1);
+ comedi_spriv_free(dev, 2);
+ comedi_pci_disable(dev);
}
static struct comedi_driver cb_pcidda_driver = {
@@ -435,18 +412,19 @@ static struct comedi_driver cb_pcidda_driver = {
};
static int cb_pcidda_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &cb_pcidda_driver);
+ return comedi_pci_auto_config(dev, &cb_pcidda_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA02_12) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA04_12) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA08_12) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA02_16) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA04_16) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA08_16) },
+ { PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 },
+ { PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 },
+ { PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 },
+ { PCI_VDEVICE(CB, 0x0023), BOARD_DDA02_16 },
+ { PCI_VDEVICE(CB, 0x0024), BOARD_DDA04_16 },
+ { PCI_VDEVICE(CB, 0x0025), BOARD_DDA08_16 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index aae063ca85a0..29813c9d4a2a 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -215,14 +215,12 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
unsigned long iobase_8255;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -277,14 +275,9 @@ static int cb_pcimdas_auto_attach(struct comedi_device *dev,
static void cb_pcimdas_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver cb_pcimdas_driver = {
@@ -295,9 +288,10 @@ static struct comedi_driver cb_pcimdas_driver = {
};
static int cb_pcimdas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &cb_pcimdas_driver);
+ return comedi_pci_auto_config(dev, &cb_pcimdas_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 63cfbaf3a3fe..88f03ae6f3e6 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -161,14 +161,12 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 3);
@@ -201,14 +199,8 @@ static int cb_pcimdda_auto_attach(struct comedi_device *dev,
static void cb_pcimdda_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[1]);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_spriv_free(dev, 1);
+ comedi_pci_disable(dev);
}
static struct comedi_driver cb_pcimdda_driver = {
@@ -219,9 +211,10 @@ static struct comedi_driver cb_pcimdda_driver = {
};
static int cb_pcimdda_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
+ return comedi_pci_auto_config(dev, &cb_pcimdda_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c
index 83728298eefb..37dc79637d2a 100644
--- a/drivers/staging/comedi/drivers/comedi_fc.c
+++ b/drivers/staging/comedi/drivers/comedi_fc.c
@@ -65,7 +65,7 @@ unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd,
return num_bytes;
}
-EXPORT_SYMBOL(cfc_write_array_to_buffer);
+EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer);
unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
void *data, unsigned int num_bytes)
@@ -83,7 +83,7 @@ unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd,
return num_bytes;
}
-EXPORT_SYMBOL(cfc_read_array_from_buffer);
+EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer);
unsigned int cfc_handle_events(struct comedi_device *dev,
struct comedi_subdevice *subd)
@@ -100,7 +100,7 @@ unsigned int cfc_handle_events(struct comedi_device *dev,
return events;
}
-EXPORT_SYMBOL(cfc_handle_events);
+EXPORT_SYMBOL_GPL(cfc_handle_events);
MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>");
MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers");
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 76d59dcbea07..3e061cc9b48e 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -261,19 +261,13 @@ static int parport_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct parport_private *devpriv;
- int ret;
- unsigned int irq;
- unsigned long iobase;
struct comedi_subdevice *s;
+ unsigned int irq;
+ int ret;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
- if (!request_region(iobase, PARPORT_SIZE, dev->board_name)) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], PARPORT_SIZE);
+ if (ret)
+ return ret;
irq = it->options[1];
if (irq) {
@@ -341,25 +335,14 @@ static int parport_attach(struct comedi_device *dev,
devpriv->c_data = 0;
outb(devpriv->c_data, dev->iobase + PARPORT_C);
- dev_info(dev->class_dev, "%s: iobase=0x%04lx, irq %sabled",
- dev->board_name, dev->iobase, dev->irq ? "en" : "dis");
-
return 0;
}
-static void parport_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, PARPORT_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-}
-
static struct comedi_driver parport_driver = {
.driver_name = "comedi_parport",
.module = THIS_MODULE,
.attach = parport_attach,
- .detach = parport_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(parport_driver);
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index 270fea5c6b51..c1d8e86f53a2 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -384,8 +384,6 @@ static int waveform_attach(struct comedi_device *dev,
int i;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index 182dea669ef2..f2230bfd4eb9 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -77,9 +77,7 @@ static int contec_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 0);
@@ -109,27 +107,18 @@ static int contec_auto_attach(struct comedi_device *dev,
return 0;
}
-static void contec_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver contec_pci_dio_driver = {
.driver_name = "contec_pci_dio",
.module = THIS_MODULE,
.auto_attach = contec_auto_attach,
- .detach = contec_detach,
+ .detach = comedi_pci_disable,
};
static int contec_pci_dio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &contec_pci_dio_driver);
+ return comedi_pci_auto_config(dev, &contec_pci_dio_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index 50b450f09c65..b87f95c3e17d 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -462,9 +462,9 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev)
struct daqboard2000_private *devpriv = dev->private;
writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
}
static void daqboard2000_reloadPLX(struct comedi_device *dev)
@@ -472,11 +472,11 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev)
struct daqboard2000_private *devpriv = dev->private;
writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
}
static void daqboard2000_pulseProgPin(struct comedi_device *dev)
@@ -484,9 +484,9 @@ static void daqboard2000_pulseProgPin(struct comedi_device *dev)
struct daqboard2000_private *devpriv = dev->private;
writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c);
- udelay(10000);
+ mdelay(10);
writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c);
- udelay(10000); /* Not in the original code, but I like symmetry... */
+ mdelay(10); /* Not in the original code, but I like symmetry... */
}
static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask)
@@ -709,15 +709,12 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- result = comedi_pci_enable(pcidev, dev->driver->driver_name);
- if (result < 0)
+ result = comedi_pci_enable(dev);
+ if (result)
return result;
- dev->iobase = 1; /* the "detach" needs this */
- devpriv->plx = ioremap(pci_resource_start(pcidev, 0),
- pci_resource_len(pcidev, 0));
- devpriv->daq = ioremap(pci_resource_start(pcidev, 2),
- pci_resource_len(pcidev, 2));
+ devpriv->plx = pci_ioremap_bar(pcidev, 0);
+ devpriv->daq = pci_ioremap_bar(pcidev, 2);
if (!devpriv->plx || !devpriv->daq)
return -ENOMEM;
@@ -767,11 +764,9 @@ static int daqboard2000_auto_attach(struct comedi_device *dev,
static void daqboard2000_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct daqboard2000_private *devpriv = dev->private;
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[2]);
+ comedi_spriv_free(dev, 2);
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
@@ -780,11 +775,7 @@ static void daqboard2000_detach(struct comedi_device *dev)
if (devpriv->plx)
iounmap(devpriv->plx);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- pci_dev_put(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver daqboard2000_driver = {
@@ -795,9 +786,10 @@ static struct comedi_driver daqboard2000_driver = {
};
static int daqboard2000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &daqboard2000_driver);
+ return comedi_pci_auto_config(dev, &daqboard2000_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 9823aa06787a..ba12c1d605fb 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -568,8 +568,7 @@ EXPORT_SYMBOL_GPL(das08_common_attach);
void das08_common_detach(struct comedi_device *dev)
{
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[4]);
+ comedi_spriv_free(dev, 4);
}
EXPORT_SYMBOL_GPL(das08_common_detach);
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index b102ad4918c4..89bb8d6fdfc6 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -32,7 +32,6 @@ enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl,
struct das08_board_struct {
const char *name;
- unsigned int id; /* id for pci/pcmcia boards */
bool is_jr; /* true for 'JR' boards */
unsigned int ai_nbits;
enum das08_lrange ai_pg;
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index cfeebe4d1ddd..d9f3e92317d3 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -59,7 +59,6 @@ Command support does not exist, but could be added for this board.
static const struct das08_board_struct das08_cs_boards[] = {
{
.name = "pcm-das08",
- .id = 0x0, /* XXX */
.ai_nbits = 12,
.ai_pg = das08_bipolar5,
.ai_encoding = das08_pcm_encode12,
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index f12078247163..f09f6966ed65 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -179,26 +179,24 @@ static int das08_isa_attach(struct comedi_device *dev,
{
const struct das08_board_struct *thisboard = comedi_board(dev);
struct das08_private_struct *devpriv;
+ int ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- if (!request_region(it->options[0], thisboard->iosize,
- thisboard->name))
- return -EIO;
+ ret = comedi_request_region(dev, it->options[0], thisboard->iosize);
+ if (ret)
+ return ret;
- return das08_common_attach(dev, it->options[0]);
+ return das08_common_attach(dev, dev->iobase);
}
static void das08_isa_detach(struct comedi_device *dev)
{
- const struct das08_board_struct *thisboard = comedi_board(dev);
-
das08_common_detach(dev);
- if (dev->iobase)
- release_region(dev->iobase, thisboard->iosize);
+ comedi_legacy_detach(dev);
}
static struct comedi_driver das08_isa_driver = {
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index c405876ddcf7..53fa943dd0b7 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -46,7 +46,6 @@
static const struct das08_board_struct das08_pci_boards[] = {
{
.name = "pci-das08",
- .id = PCI_DEVICE_ID_PCIDAS08,
.ai_nbits = 12,
.ai_pg = das08_bipolar5,
.ai_encoding = das08_encode12,
@@ -72,7 +71,7 @@ static int das08_pci_auto_attach(struct comedi_device *dev,
/* The das08 driver needs the board_ptr */
dev->board_ptr = &das08_pci_boards[0];
- ret = comedi_pci_enable(pdev, dev->driver->driver_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pdev, 2);
@@ -82,11 +81,8 @@ static int das08_pci_auto_attach(struct comedi_device *dev,
static void das08_pci_detach(struct comedi_device *dev)
{
- struct pci_dev *pdev = comedi_to_pci_dev(dev);
-
das08_common_detach(dev);
- if (dev->iobase)
- comedi_pci_disable(pdev);
+ comedi_pci_disable(dev);
}
static struct comedi_driver das08_pci_comedi_driver = {
@@ -97,9 +93,10 @@ static struct comedi_driver das08_pci_comedi_driver = {
};
static int das08_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &das08_pci_comedi_driver);
+ return comedi_pci_auto_config(dev, &das08_pci_comedi_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index f238a1fbccbf..762b5a6eac5a 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -393,6 +393,8 @@ struct das16_private_struct {
struct timer_list timer; /* for timed interrupt */
volatile short timer_running;
volatile short timer_mode; /* true if using timer mode */
+
+ unsigned long extra_iobase;
};
static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -876,7 +878,7 @@ static void das16_interrupt(struct comedi_device *dev)
int num_bytes, residue;
int buffer_index;
- if (dev->attached == 0) {
+ if (!dev->attached) {
comedi_error(dev, "premature interrupt");
return;
}
@@ -1079,13 +1081,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
unsigned int irq;
- unsigned long iobase;
unsigned int dma_chan;
int timer_mode;
unsigned long flags;
struct comedi_krange *user_ai_range, *user_ao_range;
- iobase = it->options[0];
#if 0
irq = it->options[1];
timer_mode = it->options[8];
@@ -1097,8 +1097,6 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (timer_mode)
irq = 0;
- printk(KERN_INFO "comedi%d: das16:", dev->minor);
-
/* check that clock setting is valid */
if (it->options[3]) {
if (it->options[3] != 0 &&
@@ -1116,39 +1114,26 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->private = devpriv;
if (board->size < 0x400) {
- printk(" 0x%04lx-0x%04lx\n", iobase, iobase + board->size);
- if (!request_region(iobase, board->size, "das16")) {
- printk(KERN_ERR " I/O port conflict\n");
- return -EIO;
- }
+ ret = comedi_request_region(dev, it->options[0], board->size);
+ if (ret)
+ return ret;
} else {
- printk(KERN_INFO " 0x%04lx-0x%04lx 0x%04lx-0x%04lx\n",
- iobase, iobase + 0x0f,
- iobase + 0x400,
- iobase + 0x400 + (board->size & 0x3ff));
- if (!request_region(iobase, 0x10, "das16")) {
- printk(KERN_ERR " I/O port conflict: 0x%04lx-0x%04lx\n",
- iobase, iobase + 0x0f);
- return -EIO;
- }
- if (!request_region(iobase + 0x400, board->size & 0x3ff,
- "das16")) {
- release_region(iobase, 0x10);
- printk(KERN_ERR " I/O port conflict: 0x%04lx-0x%04lx\n",
- iobase + 0x400,
- iobase + 0x400 + (board->size & 0x3ff));
- return -EIO;
- }
+ ret = comedi_request_region(dev, it->options[0], 0x10);
+ if (ret)
+ return ret;
+ /* Request an additional region for the 8255 */
+ ret = __comedi_request_region(dev, dev->iobase + 0x400,
+ board->size & 0x3ff);
+ if (ret)
+ return ret;
+ devpriv->extra_iobase = dev->iobase + 0x400;
}
- dev->iobase = iobase;
-
/* probe id bits to make sure they are consistent */
if (das16_probe(dev, it)) {
printk(KERN_ERR " id bits do not match selected board, aborting\n");
return -EINVAL;
}
- dev->board_name = board->name;
/* get master clock speed */
if (board->size < 0x400) {
@@ -1162,7 +1147,8 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* now for the irq */
if (irq > 1 && irq < 8) {
- ret = request_irq(irq, das16_dma_interrupt, 0, "das16", dev);
+ ret = request_irq(irq, das16_dma_interrupt, 0,
+ dev->board_name, dev);
if (ret < 0)
return ret;
@@ -1188,7 +1174,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (devpriv->dma_buffer[i] == NULL)
return -ENOMEM;
}
- if (request_dma(dma_chan, "das16")) {
+ if (request_dma(dma_chan, dev->board_name)) {
printk(KERN_ERR " failed to allocate dma channel %i\n",
dma_chan);
return -EINVAL;
@@ -1353,8 +1339,7 @@ static void das16_detach(struct comedi_device *dev)
struct das16_private_struct *devpriv = dev->private;
das16_reset(dev);
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[4]);
+ comedi_spriv_free(dev, 4);
if (devpriv) {
int i;
for (i = 0; i < 2; i++) {
@@ -1369,17 +1354,9 @@ static void das16_detach(struct comedi_device *dev)
kfree(devpriv->user_ai_range_table);
kfree(devpriv->user_ao_range_table);
}
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase) {
- if (board->size < 0x400) {
- release_region(dev->iobase, board->size);
- } else {
- release_region(dev->iobase, 0x10);
- release_region(dev->iobase + 0x400,
- board->size & 0x3ff);
- }
- }
+ if (devpriv->extra_iobase)
+ release_region(devpriv->extra_iobase, board->size & 0x3ff);
+ comedi_legacy_detach(dev);
}
static const struct das16_board das16_boards[] = {
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index b0a861a779bd..9cb9c3b04797 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -143,6 +143,7 @@ struct das16m1_private_struct {
unsigned int do_bits; /* saves status of digital output bits */
unsigned int divisor1; /* divides master clock to obtain conversion speed */
unsigned int divisor2; /* divides master clock to obtain conversion speed */
+ unsigned long extra_iobase;
};
static inline short munge_sample(short data)
@@ -499,7 +500,7 @@ static irqreturn_t das16m1_interrupt(int irq, void *d)
int status;
struct comedi_device *dev = d;
- if (dev->attached == 0) {
+ if (!dev->attached) {
comedi_error(dev, "premature interrupt");
return IRQ_HANDLED;
}
@@ -571,28 +572,21 @@ static int das16m1_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
unsigned int irq;
- unsigned long iobase;
-
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- if (!request_region(iobase, DAS16M1_SIZE, dev->board_name)) {
- comedi_error(dev, "I/O port conflict\n");
- return -EIO;
- }
- if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2,
- dev->board_name)) {
- release_region(iobase, DAS16M1_SIZE);
- comedi_error(dev, "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], DAS16M1_SIZE);
+ if (ret)
+ return ret;
+ /* Request an additional region for the 8255 */
+ ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55,
+ DAS16M1_SIZE2);
+ if (ret)
+ return ret;
+ devpriv->extra_iobase = dev->iobase + DAS16M1_82C55;
/* now for the irq */
irq = it->options[1];
@@ -654,7 +648,9 @@ static int das16m1_attach(struct comedi_device *dev,
s = &dev->subdevices[3];
/* 8255 */
- subdev_8255_init(dev, s, NULL, dev->iobase + DAS16M1_82C55);
+ ret = subdev_8255_init(dev, s, NULL, devpriv->extra_iobase);
+ if (ret)
+ return ret;
/* disable upper half of hardware conversion counter so it doesn't mess with us */
outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL);
@@ -674,14 +670,12 @@ static int das16m1_attach(struct comedi_device *dev,
static void das16m1_detach(struct comedi_device *dev)
{
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[3]);
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase) {
- release_region(dev->iobase, DAS16M1_SIZE);
- release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2);
- }
+ struct das16m1_private_struct *devpriv = dev->private;
+
+ comedi_spriv_free(dev, 3);
+ if (devpriv && devpriv->extra_iobase)
+ release_region(devpriv->extra_iobase, DAS16M1_SIZE2);
+ comedi_legacy_detach(dev);
}
static struct comedi_driver das16m1_driver = {
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 7900f959555d..abf7638a9f71 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -429,11 +429,6 @@ static const struct das1800_board das1800_boards[] = {
},
};
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct das1800_board *)dev->board_ptr)
-
struct das1800_private {
volatile unsigned int count; /* number of data points left to be taken */
unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */
@@ -454,14 +449,6 @@ struct das1800_private {
short ao_update_bits; /* remembers the last write to the 'update' dac */
};
-/* analog out range for boards with basic analog out */
-static const struct comedi_lrange range_ao_1 = {
- 1,
- {
- RANGE(-10, 10),
- }
-};
-
/* analog out range for 'ao' boards */
/*
static const struct comedi_lrange range_ao_2 = {
@@ -476,6 +463,8 @@ static const struct comedi_lrange range_ao_2 = {
static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev,
uint16_t sample)
{
+ const struct das1800_board *thisboard = comedi_board(dev);
+
sample += 1 << (thisboard->resolution - 1);
return sample;
}
@@ -731,7 +720,7 @@ static irqreturn_t das1800_interrupt(int irq, void *d)
struct comedi_device *dev = d;
unsigned int status;
- if (dev->attached == 0) {
+ if (!dev->attached) {
comedi_error(dev, "premature interrupt");
return IRQ_HANDLED;
}
@@ -789,6 +778,7 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct das1800_board *thisboard = comedi_board(dev);
struct das1800_private *devpriv = dev->private;
int err = 0;
unsigned int tmp_arg;
@@ -1232,6 +1222,7 @@ static int das1800_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct das1800_board *thisboard = comedi_board(dev);
int i, n;
int chan, range, aref, chan_range;
int timeout = 1000;
@@ -1295,6 +1286,7 @@ static int das1800_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct das1800_board *thisboard = comedi_board(dev);
struct das1800_private *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
/* int range = CR_RANGE(insn->chanspec); */
@@ -1516,46 +1508,23 @@ static int das1800_probe(struct comedi_device *dev)
static int das1800_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
+ const struct das1800_board *thisboard = comedi_board(dev);
struct das1800_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase = it->options[0];
unsigned int irq = it->options[1];
unsigned int dma0 = it->options[2];
unsigned int dma1 = it->options[3];
- unsigned long iobase2;
int board;
- int retval;
+ int ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
- dev->driver->driver_name, iobase);
- if (irq) {
- printk(KERN_CONT ", irq %u", irq);
- if (dma0) {
- printk(KERN_CONT ", dma %u", dma0);
- if (dma1)
- printk(KERN_CONT " and %u", dma1);
- }
- }
- printk(KERN_CONT "\n");
-
- if (iobase == 0) {
- dev_err(dev->class_dev, "io base address required\n");
- return -EINVAL;
- }
-
- /* check if io addresses are available */
- if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
- printk
- (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
- iobase, iobase + DAS1800_SIZE - 1);
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE);
+ if (ret)
+ return ret;
board = das1800_probe(dev);
if (board < 0) {
@@ -1564,18 +1533,16 @@ static int das1800_attach(struct comedi_device *dev,
}
dev->board_ptr = das1800_boards + board;
+ thisboard = comedi_board(dev);
dev->board_name = thisboard->name;
/* if it is an 'ao' board with fancy analog out then we need extra io ports */
if (thisboard->ao_ability == 2) {
- iobase2 = iobase + IOBASE2;
- if (!request_region(iobase2, DAS1800_SIZE,
- dev->driver->driver_name)) {
- printk
- (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
- iobase2, iobase2 + DAS1800_SIZE - 1);
- return -EIO;
- }
+ unsigned long iobase2 = dev->iobase + IOBASE2;
+
+ ret = __comedi_request_region(dev, iobase2, DAS1800_SIZE);
+ if (ret)
+ return ret;
devpriv->iobase2 = iobase2;
}
@@ -1618,9 +1585,9 @@ static int das1800_attach(struct comedi_device *dev,
break;
}
- retval = das1800_init_dma(dev, dma0, dma1);
- if (retval < 0)
- return retval;
+ ret = das1800_init_dma(dev, dma0, dma1);
+ if (ret < 0)
+ return ret;
if (devpriv->ai_buf0 == NULL) {
devpriv->ai_buf0 =
@@ -1629,9 +1596,9 @@ static int das1800_attach(struct comedi_device *dev,
return -ENOMEM;
}
- retval = comedi_alloc_subdevices(dev, 4);
- if (retval)
- return retval;
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
/* analog input subdevice */
s = &dev->subdevices[0];
@@ -1657,7 +1624,7 @@ static int das1800_attach(struct comedi_device *dev,
s->subdev_flags = SDF_WRITABLE;
s->n_chan = thisboard->ao_n_chan;
s->maxdata = (1 << thisboard->resolution) - 1;
- s->range_table = &range_ao_1;
+ s->range_table = &range_bipolar10;
s->insn_write = das1800_ao_winsn;
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -1701,21 +1668,18 @@ static void das1800_detach(struct comedi_device *dev)
{
struct das1800_private *devpriv = dev->private;
- if (dev->iobase)
- release_region(dev->iobase, DAS1800_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
if (devpriv) {
- if (devpriv->iobase2)
- release_region(devpriv->iobase2, DAS1800_SIZE);
if (devpriv->dma0)
free_dma(devpriv->dma0);
if (devpriv->dma1)
free_dma(devpriv->dma1);
kfree(devpriv->ai_buf0);
kfree(devpriv->ai_buf1);
+ if (devpriv->iobase2)
+ release_region(devpriv->iobase2, DAS1800_SIZE);
}
-};
+ comedi_legacy_detach(dev);
+}
static struct comedi_driver das1800_driver = {
.driver_name = "das1800",
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 2efddb89bbcb..11424fb5b4d4 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -284,23 +284,12 @@ static int das6402_attach(struct comedi_device *dev,
{
struct das6402_private *devpriv;
unsigned int irq;
- unsigned long iobase;
int ret;
struct comedi_subdevice *s;
- dev->board_name = "das6402";
-
- iobase = it->options[0];
- if (iobase == 0)
- iobase = 0x300;
-
- if (!request_region(iobase, DAS6402_SIZE, "das6402")) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* should do a probe here */
+ ret = comedi_request_region(dev, it->options[0], DAS6402_SIZE);
+ if (ret)
+ return ret;
irq = it->options[0];
dev_dbg(dev->class_dev, "( irq = %u )\n", irq);
@@ -335,19 +324,11 @@ static int das6402_attach(struct comedi_device *dev,
return 0;
}
-static void das6402_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DAS6402_SIZE);
-}
-
static struct comedi_driver das6402_driver = {
.driver_name = "das6402",
.module = THIS_MODULE,
.attach = das6402_attach,
- .detach = das6402_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(das6402_driver)
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 38f625be812a..9ce6cbcc7ee8 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -95,8 +95,8 @@ cmd triggers supported:
#define IRQ 0x8
#define BUSY 0x80
#define DAS800_GAIN 3
-#define CIO_FFOV 0x8 /* fifo overflow for cio-das802/16 */
-#define CIO_ENHF 0x90 /* interrupt fifo half full for cio-das802/16 */
+#define CIO_FFOV 0x8 /* cio-das802/16 fifo overflow */
+#define CIO_ENHF 0x90 /* cio-das802/16 fifo half full int ena */
#define CONTROL1 0x80
#define CONV_CONTROL 0xa0
#define SCAN_LIMITS 0xc0
@@ -107,6 +107,8 @@ cmd triggers supported:
#define STATUS2_INTE 0X20
#define DAS800_ID 7
+#define DAS802_16_HALF_FIFO_SZ 128
+
struct das800_board {
const char *name;
int ai_speed;
@@ -114,491 +116,204 @@ struct das800_board {
int resolution;
};
-/* analog input ranges */
-static const struct comedi_lrange range_das800_ai = {
- 1,
- {
- RANGE(-5, 5),
- }
-};
-
static const struct comedi_lrange range_das801_ai = {
- 9,
- {
- RANGE(-5, 5),
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE(-0.5, 0.5),
- RANGE(0, 1),
- RANGE(-0.05, 0.05),
- RANGE(0, 0.1),
- RANGE(-0.01, 0.01),
- RANGE(0, 0.02),
- }
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ BIP_RANGE(0.5),
+ UNI_RANGE(1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(0.1),
+ BIP_RANGE(0.01),
+ UNI_RANGE(0.02)
+ }
};
static const struct comedi_lrange range_cio_das801_ai = {
- 9,
- {
- RANGE(-5, 5),
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE(-0.5, 0.5),
- RANGE(0, 1),
- RANGE(-0.05, 0.05),
- RANGE(0, 0.1),
- RANGE(-0.005, 0.005),
- RANGE(0, 0.01),
- }
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ BIP_RANGE(0.5),
+ UNI_RANGE(1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(0.1),
+ BIP_RANGE(0.005),
+ UNI_RANGE(0.01)
+ }
};
static const struct comedi_lrange range_das802_ai = {
- 9,
- {
- RANGE(-5, 5),
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE(-2.5, 2.5),
- RANGE(0, 5),
- RANGE(-1.25, 1.25),
- RANGE(0, 2.5),
- RANGE(-0.625, 0.625),
- RANGE(0, 1.25),
- }
+ 9, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ BIP_RANGE(2.5),
+ UNI_RANGE(5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(2.5),
+ BIP_RANGE(0.625),
+ UNI_RANGE(1.25)
+ }
};
static const struct comedi_lrange range_das80216_ai = {
- 8,
- {
- RANGE(-10, 10),
- RANGE(0, 10),
- RANGE(-5, 5),
- RANGE(0, 5),
- RANGE(-2.5, 2.5),
- RANGE(0, 2.5),
- RANGE(-1.25, 1.25),
- RANGE(0, 1.25),
- }
+ 8, {
+ BIP_RANGE(10),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ UNI_RANGE(5),
+ BIP_RANGE(2.5),
+ UNI_RANGE(2.5),
+ BIP_RANGE(1.25),
+ UNI_RANGE(1.25)
+ }
};
-enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 };
+enum das800_boardinfo {
+ BOARD_DAS800,
+ BOARD_CIODAS800,
+ BOARD_DAS801,
+ BOARD_CIODAS801,
+ BOARD_DAS802,
+ BOARD_CIODAS802,
+ BOARD_CIODAS80216,
+};
static const struct das800_board das800_boards[] = {
- {
- .name = "das-800",
- .ai_speed = 25000,
- .ai_range = &range_das800_ai,
- .resolution = 12,
- },
- {
- .name = "cio-das800",
- .ai_speed = 20000,
- .ai_range = &range_das800_ai,
- .resolution = 12,
- },
- {
- .name = "das-801",
- .ai_speed = 25000,
- .ai_range = &range_das801_ai,
- .resolution = 12,
- },
- {
- .name = "cio-das801",
- .ai_speed = 20000,
- .ai_range = &range_cio_das801_ai,
- .resolution = 12,
- },
- {
- .name = "das-802",
- .ai_speed = 25000,
- .ai_range = &range_das802_ai,
- .resolution = 12,
- },
- {
- .name = "cio-das802",
- .ai_speed = 20000,
- .ai_range = &range_das802_ai,
- .resolution = 12,
- },
- {
- .name = "cio-das802/16",
- .ai_speed = 10000,
- .ai_range = &range_das80216_ai,
- .resolution = 16,
- },
+ [BOARD_DAS800] = {
+ .name = "das-800",
+ .ai_speed = 25000,
+ .ai_range = &range_bipolar5,
+ .resolution = 12,
+ },
+ [BOARD_CIODAS800] = {
+ .name = "cio-das800",
+ .ai_speed = 20000,
+ .ai_range = &range_bipolar5,
+ .resolution = 12,
+ },
+ [BOARD_DAS801] = {
+ .name = "das-801",
+ .ai_speed = 25000,
+ .ai_range = &range_das801_ai,
+ .resolution = 12,
+ },
+ [BOARD_CIODAS801] = {
+ .name = "cio-das801",
+ .ai_speed = 20000,
+ .ai_range = &range_cio_das801_ai,
+ .resolution = 12,
+ },
+ [BOARD_DAS802] = {
+ .name = "das-802",
+ .ai_speed = 25000,
+ .ai_range = &range_das802_ai,
+ .resolution = 12,
+ },
+ [BOARD_CIODAS802] = {
+ .name = "cio-das802",
+ .ai_speed = 20000,
+ .ai_range = &range_das802_ai,
+ .resolution = 12,
+ },
+ [BOARD_CIODAS80216] = {
+ .name = "cio-das802/16",
+ .ai_speed = 10000,
+ .ai_range = &range_das80216_ai,
+ .resolution = 16,
+ },
};
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct das800_board *)dev->board_ptr)
-
struct das800_private {
- volatile unsigned int count; /* number of data points left to be taken */
- volatile int forever; /* flag indicating whether we should take data forever */
- unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */
- unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */
- volatile int do_bits; /* digital output bits */
-};
-
-static int das800_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static void das800_detach(struct comedi_device *dev);
-static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-
-static struct comedi_driver driver_das800 = {
- .driver_name = "das800",
- .module = THIS_MODULE,
- .attach = das800_attach,
- .detach = das800_detach,
- .num_names = ARRAY_SIZE(das800_boards),
- .board_name = &das800_boards[0].name,
- .offset = sizeof(struct das800_board),
+ unsigned int count; /* number of data points left to be taken */
+ unsigned int divisor1; /* counter 1 value for timed conversions */
+ unsigned int divisor2; /* counter 2 value for timed conversions */
+ unsigned int do_bits; /* digital output bits */
+ bool forever; /* flag that we should take data forever */
};
-static irqreturn_t das800_interrupt(int irq, void *d);
-static void enable_das800(struct comedi_device *dev);
-static void disable_das800(struct comedi_device *dev);
-static int das800_ai_do_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int das800_ai_do_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int das800_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int das800_di_rbits(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int das800_do_wbits(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int das800_probe(struct comedi_device *dev);
-static int das800_set_frequency(struct comedi_device *dev);
-
-/* checks and probes das-800 series board type */
-static int das800_probe(struct comedi_device *dev)
+static void das800_ind_write(struct comedi_device *dev,
+ unsigned val, unsigned reg)
{
- int id_bits;
- unsigned long irq_flags;
- int board;
-
- /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */
- spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */
- id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
-
- board = thisboard - das800_boards;
-
- switch (id_bits) {
- case 0x0:
- if (board == das800) {
- dev_dbg(dev->class_dev, "Board model: DAS-800\n");
- return board;
- }
- if (board == ciodas800) {
- dev_dbg(dev->class_dev, "Board model: CIO-DAS800\n");
- return board;
- }
- dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
- return das800;
- break;
- case 0x2:
- if (board == das801) {
- dev_dbg(dev->class_dev, "Board model: DAS-801\n");
- return board;
- }
- if (board == ciodas801) {
- dev_dbg(dev->class_dev, "Board model: CIO-DAS801\n");
- return board;
- }
- dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
- return das801;
- break;
- case 0x3:
- if (board == das802) {
- dev_dbg(dev->class_dev, "Board model: DAS-802\n");
- return board;
- }
- if (board == ciodas802) {
- dev_dbg(dev->class_dev, "Board model: CIO-DAS802\n");
- return board;
- }
- if (board == ciodas80216) {
- dev_dbg(dev->class_dev, "Board model: CIO-DAS802/16\n");
- return board;
- }
- dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
- return das802;
- break;
- default:
- dev_dbg(dev->class_dev,
- "Board model: probe returned 0x%x (unknown)\n",
- id_bits);
- return board;
- break;
- }
- return -1;
+ /*
+ * Select dev->iobase + 2 to be desired register
+ * then write to that register.
+ */
+ outb(reg, dev->iobase + DAS800_GAIN);
+ outb(val, dev->iobase + 2);
}
-module_comedi_driver(driver_das800);
+static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
+{
+ /*
+ * Select dev->iobase + 7 to be desired register
+ * then read from that register.
+ */
+ outb(reg, dev->iobase + DAS800_GAIN);
+ return inb(dev->iobase + 7);
+}
-/* interrupt service routine */
-static irqreturn_t das800_interrupt(int irq, void *d)
+static void das800_enable(struct comedi_device *dev)
{
- short i; /* loop index */
- short dataPoint = 0;
- struct comedi_device *dev = d;
+ const struct das800_board *thisboard = comedi_board(dev);
struct das800_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */
- struct comedi_async *async;
- int status;
unsigned long irq_flags;
- static const int max_loops = 128; /* half-fifo size for cio-das802/16 */
- /* flags */
- int fifo_empty = 0;
- int fifo_overflow = 0;
- status = inb(dev->iobase + DAS800_STATUS);
- /* if interrupt was not generated by board or driver not attached, quit */
- if (!(status & IRQ))
- return IRQ_NONE;
- if (!(dev->attached))
- return IRQ_HANDLED;
-
- /* wait until here to initialize async, since we will get null dereference
- * if interrupt occurs before driver is fully attached!
- */
- async = s->async;
-
- /* if hardware conversions are not enabled, then quit */
spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */
- status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN;
- /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */
- if (status == 0) {
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- return IRQ_HANDLED;
- }
-
- /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */
- for (i = 0; i < max_loops; i++) {
- /* read 16 bits from dev->iobase and dev->iobase + 1 */
- dataPoint = inb(dev->iobase + DAS800_LSB);
- dataPoint += inb(dev->iobase + DAS800_MSB) << 8;
- if (thisboard->resolution == 12) {
- fifo_empty = dataPoint & FIFO_EMPTY;
- fifo_overflow = dataPoint & FIFO_OVF;
- if (fifo_overflow)
- break;
- } else {
- fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */
- }
- if (fifo_empty)
- break;
- /* strip off extraneous bits for 12 bit cards */
- if (thisboard->resolution == 12)
- dataPoint = (dataPoint >> 4) & 0xfff;
- /* if there are more data points to collect */
- if (devpriv->count > 0 || devpriv->forever == 1) {
- /* write data point to buffer */
- cfc_write_to_buffer(s, dataPoint);
- if (devpriv->count > 0)
- devpriv->count--;
- }
- }
- async->events |= COMEDI_CB_BLOCK;
- /* check for fifo overflow */
- if (thisboard->resolution == 12) {
- fifo_overflow = dataPoint & FIFO_OVF;
- /* else cio-das802/16 */
- } else {
- fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV;
- }
- if (fifo_overflow) {
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- comedi_error(dev, "DAS800 FIFO overflow");
- das800_cancel(dev, s);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- async->events = 0;
- return IRQ_HANDLED;
- }
- if (devpriv->count > 0 || devpriv->forever == 1) {
- /* Re-enable card's interrupt.
- * We already have spinlock, so indirect addressing is safe */
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
- outb(CONTROL1_INTE | devpriv->do_bits,
- dev->iobase + DAS800_CONTROL1);
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- /* otherwise, stop taking data */
- } else {
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- disable_das800(dev); /* disable hardware triggered conversions */
- async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
- async->events = 0;
- return IRQ_HANDLED;
+ /* enable fifo-half full interrupts for cio-das802/16 */
+ if (thisboard->resolution == 16)
+ outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
+ /* enable hardware triggering */
+ das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
+ /* enable card's interrupt */
+ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
}
-static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static void das800_disable(struct comedi_device *dev)
{
- struct das800_private *devpriv;
- struct comedi_subdevice *s;
- unsigned long iobase = it->options[0];
- unsigned int irq = it->options[1];
unsigned long irq_flags;
- int board;
- int ret;
-
- dev_info(dev->class_dev, "das800: io 0x%lx\n", iobase);
- if (irq)
- dev_dbg(dev->class_dev, "irq %u\n", irq);
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
-
- if (iobase == 0) {
- dev_err(dev->class_dev,
- "io base address required for das800\n");
- return -EINVAL;
- }
-
- /* check if io addresses are available */
- if (!request_region(iobase, DAS800_SIZE, "das800")) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- board = das800_probe(dev);
- if (board < 0) {
- dev_dbg(dev->class_dev, "unable to determine board type\n");
- return -ENODEV;
- }
- dev->board_ptr = das800_boards + board;
-
- /* grab our IRQ */
- if (irq == 1 || irq > 7) {
- dev_err(dev->class_dev, "irq out of range\n");
- return -EINVAL;
- }
- if (irq) {
- if (request_irq(irq, das800_interrupt, 0, "das800", dev)) {
- dev_err(dev->class_dev, "unable to allocate irq %u\n",
- irq);
- return -EINVAL;
- }
- }
- dev->irq = irq;
-
- dev->board_name = thisboard->name;
-
- ret = comedi_alloc_subdevices(dev, 3);
- if (ret)
- return ret;
-
- /* analog input subdevice */
- s = &dev->subdevices[0];
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->maxdata = (1 << thisboard->resolution) - 1;
- s->range_table = thisboard->ai_range;
- s->do_cmd = das800_ai_do_cmd;
- s->do_cmdtest = das800_ai_do_cmdtest;
- s->insn_read = das800_ai_rinsn;
- s->cancel = das800_cancel;
-
- /* di */
- s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 3;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = das800_di_rbits;
-
- /* do */
- s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 4;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = das800_do_wbits;
-
- disable_das800(dev);
-
- /* initialize digital out channels */
spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
- outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
+ /* disable hardware triggering of conversions */
+ das800_ind_write(dev, 0x0, CONV_CONTROL);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+}
- return 0;
-};
-
-static void das800_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, DAS800_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-};
-
-static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+static int das800_set_frequency(struct comedi_device *dev)
{
struct das800_private *devpriv = dev->private;
+ int err = 0;
+
+ if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
+ err++;
+ if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
+ err++;
+ if (err)
+ return -1;
- devpriv->forever = 0;
- devpriv->count = 0;
- disable_das800(dev);
return 0;
}
-/* enable_das800 makes the card start taking hardware triggered conversions */
-static void enable_das800(struct comedi_device *dev)
+static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct das800_private *devpriv = dev->private;
- unsigned long irq_flags;
- spin_lock_irqsave(&dev->spinlock, irq_flags);
- /* enable fifo-half full interrupts for cio-das802/16 */
- if (thisboard->resolution == 16)
- outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
- outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
- outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
- outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
-}
-
-/* disable_das800 stops hardware triggered conversions */
-static void disable_das800(struct comedi_device *dev)
-{
- unsigned long irq_flags;
- spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
- outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ devpriv->forever = false;
+ devpriv->count = 0;
+ das800_disable(dev);
+ return 0;
}
static int das800_ai_do_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct das800_board *thisboard = comedi_board(dev);
struct das800_private *devpriv = dev->private;
int err = 0;
- int tmp;
- int gain, startChan;
- int i;
/* Step 1 : check if triggers are trivially valid */
@@ -644,11 +359,13 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
/* step 4: fix up any arguments */
if (cmd->convert_src == TRIG_TIMER) {
- tmp = cmd->convert_arg;
+ int tmp = cmd->convert_arg;
+
/* calculate counter values that give desired timing */
- i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(cmd->convert_arg),
+ i8253_cascade_ns_to_timer_2div(TIMER_BASE,
+ &devpriv->divisor1,
+ &devpriv->divisor2,
+ &cmd->convert_arg,
cmd->flags & TRIG_ROUND_MASK);
if (tmp != cmd->convert_arg)
err++;
@@ -659,18 +376,21 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
/* check channel/gain list against card's limitations */
if (cmd->chanlist) {
- gain = CR_RANGE(cmd->chanlist[0]);
- startChan = CR_CHAN(cmd->chanlist[0]);
+ unsigned int chan = CR_CHAN(cmd->chanlist[0]);
+ unsigned int range = CR_RANGE(cmd->chanlist[0]);
+ unsigned int next;
+ int i;
+
for (i = 1; i < cmd->chanlist_len; i++) {
- if (CR_CHAN(cmd->chanlist[i]) !=
- (startChan + i) % N_CHAN_AI) {
- comedi_error(dev,
- "entries in chanlist must be consecutive channels, counting upwards\n");
+ next = cmd->chanlist[i];
+ if (CR_CHAN(next) != (chan + i) % N_CHAN_AI) {
+ dev_err(dev->class_dev,
+ "chanlist must be consecutive, counting upwards\n");
err++;
}
- if (CR_RANGE(cmd->chanlist[i]) != gain) {
- comedi_error(dev,
- "entries in chanlist must all have the same gain\n");
+ if (CR_RANGE(next) != range) {
+ dev_err(dev->class_dev,
+ "chanlist must all have the same gain\n");
err++;
}
}
@@ -685,32 +405,24 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev,
static int das800_ai_do_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ const struct das800_board *thisboard = comedi_board(dev);
struct das800_private *devpriv = dev->private;
- int startChan, endChan, scan, gain;
+ struct comedi_async *async = s->async;
+ unsigned int gain = CR_RANGE(async->cmd.chanlist[0]);
+ unsigned int start_chan = CR_CHAN(async->cmd.chanlist[0]);
+ unsigned int end_chan = (start_chan + async->cmd.chanlist_len - 1) % 8;
+ unsigned int scan_chans = (end_chan << 3) | start_chan;
int conv_bits;
unsigned long irq_flags;
- struct comedi_async *async = s->async;
- if (!dev->irq) {
- comedi_error(dev,
- "no irq assigned for das-800, cannot do hardware conversions");
- return -1;
- }
-
- disable_das800(dev);
-
- /* set channel scan limits */
- startChan = CR_CHAN(async->cmd.chanlist[0]);
- endChan = (startChan + async->cmd.chanlist_len - 1) % 8;
- scan = (endChan << 3) | startChan;
+ das800_disable(dev);
spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */
- outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */
+ /* set scan limits */
+ das800_ind_write(dev, scan_chans, SCAN_LIMITS);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
/* set gain */
- gain = CR_RANGE(async->cmd.chanlist[0]);
if (thisboard->resolution == 12 && gain > 0)
gain += 0x7;
gain &= 0xf;
@@ -719,10 +431,10 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
switch (async->cmd.stop_src) {
case TRIG_COUNT:
devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len;
- devpriv->forever = 0;
+ devpriv->forever = false;
break;
case TRIG_NONE:
- devpriv->forever = 1;
+ devpriv->forever = true;
devpriv->count = 0;
break;
default:
@@ -740,11 +452,6 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
case TRIG_TIMER:
conv_bits |= CASC | ITE;
/* set conversion frequency */
- i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1),
- &(devpriv->divisor2),
- &(async->cmd.convert_arg),
- async->cmd.
- flags & TRIG_ROUND_MASK);
if (das800_set_frequency(dev) < 0) {
comedi_error(dev, "Error setting up counters");
return -1;
@@ -757,125 +464,333 @@ static int das800_ai_do_cmd(struct comedi_device *dev,
}
spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */
- outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL);
+ das800_ind_write(dev, conv_bits, CONV_CONTROL);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+
async->events = 0;
- enable_das800(dev);
+ das800_enable(dev);
return 0;
}
-static int das800_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static unsigned int das800_ai_get_sample(struct comedi_device *dev)
{
+ unsigned int lsb = inb(dev->iobase + DAS800_LSB);
+ unsigned int msb = inb(dev->iobase + DAS800_MSB);
+
+ return (msb << 8) | lsb;
+}
+
+static irqreturn_t das800_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
struct das800_private *devpriv = dev->private;
- int i, n;
- int chan;
- int range;
- int lsb, msb;
- int timeout = 1000;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s ? s->async : NULL;
unsigned long irq_flags;
+ unsigned int status;
+ unsigned int val;
+ bool fifo_empty;
+ bool fifo_overflow;
+ int i;
- disable_das800(dev); /* disable hardware conversions (enables software conversions) */
+ status = inb(dev->iobase + DAS800_STATUS);
+ if (!(status & IRQ))
+ return IRQ_NONE;
+ if (!dev->attached)
+ return IRQ_HANDLED;
- /* set multiplexer */
- chan = CR_CHAN(insn->chanspec);
+ spin_lock_irqsave(&dev->spinlock, irq_flags);
+ status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
+ /*
+ * Don't release spinlock yet since we want to make sure
+ * no one else disables hardware conversions.
+ */
+ /* if hardware conversions are not enabled, then quit */
+ if (status == 0) {
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ return IRQ_HANDLED;
+ }
+
+ for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) {
+ val = das800_ai_get_sample(dev);
+ if (s->maxdata == 0x0fff) {
+ fifo_empty = !!(val & FIFO_EMPTY);
+ fifo_overflow = !!(val & FIFO_OVF);
+ } else {
+ /* cio-das802/16 has no fifo empty status bit */
+ fifo_empty = false;
+ fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) &
+ CIO_FFOV);
+ }
+ if (fifo_empty || fifo_overflow)
+ break;
+
+ if (s->maxdata == 0x0fff)
+ val >>= 4; /* 12-bit sample */
+
+ /* if there are more data points to collect */
+ if (devpriv->count > 0 || devpriv->forever) {
+ /* write data point to buffer */
+ cfc_write_to_buffer(s, val & s->maxdata);
+ devpriv->count--;
+ }
+ }
+ async->events |= COMEDI_CB_BLOCK;
+
+ if (fifo_overflow) {
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ das800_cancel(dev, s);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ async->events = 0;
+ return IRQ_HANDLED;
+ }
+
+ if (devpriv->count > 0 || devpriv->forever) {
+ /* Re-enable card's interrupt.
+ * We already have spinlock, so indirect addressing is safe */
+ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
+ CONTROL1);
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ } else {
+ /* otherwise, stop taking data */
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ das800_disable(dev);
+ async->events |= COMEDI_CB_EOA;
+ }
+ comedi_event(dev, s);
+ async->events = 0;
+ return IRQ_HANDLED;
+}
+
+static int das800_wait_for_conv(struct comedi_device *dev, int timeout)
+{
+ int i;
+
+ for (i = 0; i < timeout; i++) {
+ if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
+ return 0;
+ }
+ return -ETIME;
+}
+
+static int das800_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct das800_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned long irq_flags;
+ unsigned int val;
+ int ret;
+ int i;
+
+ das800_disable(dev);
+
+ /* set multiplexer */
spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
- outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1);
+ das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
/* set gain / range */
- range = CR_RANGE(insn->chanspec);
- if (thisboard->resolution == 12 && range)
+ if (s->maxdata == 0x0fff && range)
range += 0x7;
range &= 0xf;
outb(range, dev->iobase + DAS800_GAIN);
udelay(5);
- for (n = 0; n < insn->n; n++) {
+ for (i = 0; i < insn->n; i++) {
/* trigger conversion */
outb_p(0, dev->iobase + DAS800_MSB);
- for (i = 0; i < timeout; i++) {
- if (!(inb(dev->iobase + DAS800_STATUS) & BUSY))
- break;
- }
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
- }
- lsb = inb(dev->iobase + DAS800_LSB);
- msb = inb(dev->iobase + DAS800_MSB);
- if (thisboard->resolution == 12) {
- data[n] = (lsb >> 4) & 0xff;
- data[n] |= (msb << 4);
- } else {
- data[n] = (msb << 8) | lsb;
- }
+ ret = das800_wait_for_conv(dev, 1000);
+ if (ret)
+ return ret;
+
+ val = das800_ai_get_sample(dev);
+ if (s->maxdata == 0x0fff)
+ val >>= 4; /* 12-bit sample */
+ data[i] = val & s->maxdata;
}
- return n;
+ return insn->n;
}
-static int das800_di_rbits(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int das800_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- unsigned int bits;
-
- bits = inb(dev->iobase + DAS800_STATUS) >> 4;
- bits &= 0x7;
- data[1] = bits;
- data[0] = 0;
+ data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
return insn->n;
}
-static int das800_do_wbits(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
+static int das800_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct das800_private *devpriv = dev->private;
- int wbits;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
unsigned long irq_flags;
- /* only set bits that have been masked */
- data[0] &= 0xf;
- wbits = devpriv->do_bits >> 4;
- wbits &= ~data[0];
- wbits |= data[0] & data[1];
- devpriv->do_bits = wbits << 4;
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
+ devpriv->do_bits = s->state << 4;
- spin_lock_irqsave(&dev->spinlock, irq_flags);
- outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */
- outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1);
- spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ spin_lock_irqsave(&dev->spinlock, irq_flags);
+ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
+ CONTROL1);
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+ }
- data[1] = wbits;
+ data[1] = s->state;
return insn->n;
}
-/* loads counters with divisor1, divisor2 from private structure */
-static int das800_set_frequency(struct comedi_device *dev)
+static int das800_probe(struct comedi_device *dev)
{
- struct das800_private *devpriv = dev->private;
- int err = 0;
+ const struct das800_board *thisboard = comedi_board(dev);
+ int board = thisboard ? thisboard - das800_boards : -EINVAL;
+ int id_bits;
+ unsigned long irq_flags;
- if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2))
- err++;
- if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2))
- err++;
- if (err)
- return -1;
+ spin_lock_irqsave(&dev->spinlock, irq_flags);
+ id_bits = das800_ind_read(dev, ID) & 0x3;
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- return 0;
+ switch (id_bits) {
+ case 0x0:
+ if (board == BOARD_DAS800 || board == BOARD_CIODAS800)
+ break;
+ dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
+ board = BOARD_DAS800;
+ break;
+ case 0x2:
+ if (board == BOARD_DAS801 || board == BOARD_CIODAS801)
+ break;
+ dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
+ board = BOARD_DAS801;
+ break;
+ case 0x3:
+ if (board == BOARD_DAS802 || board == BOARD_CIODAS802 ||
+ board == BOARD_CIODAS80216)
+ break;
+ dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
+ board = BOARD_DAS802;
+ break;
+ default:
+ dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
+ id_bits);
+ board = -EINVAL;
+ break;
+ }
+ return board;
}
+static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ const struct das800_board *thisboard = comedi_board(dev);
+ struct das800_private *devpriv;
+ struct comedi_subdevice *s;
+ unsigned int irq = it->options[1];
+ unsigned long irq_flags;
+ int board;
+ int ret;
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ ret = comedi_request_region(dev, it->options[0], DAS800_SIZE);
+ if (ret)
+ return ret;
+
+ board = das800_probe(dev);
+ if (board < 0) {
+ dev_dbg(dev->class_dev, "unable to determine board type\n");
+ return -ENODEV;
+ }
+ dev->board_ptr = das800_boards + board;
+ thisboard = comedi_board(dev);
+ dev->board_name = thisboard->name;
+
+ if (irq > 1 && irq <= 7) {
+ ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
+ dev);
+ if (ret == 0)
+ dev->irq = irq;
+ }
+
+ ret = comedi_alloc_subdevices(dev, 3);
+ if (ret)
+ return ret;
+
+ /* Analog Input subdevice */
+ s = &dev->subdevices[0];
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 8;
+ s->maxdata = (1 << thisboard->resolution) - 1;
+ s->range_table = thisboard->ai_range;
+ s->insn_read = das800_ai_insn_read;
+ if (dev->irq) {
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 8;
+ s->do_cmdtest = das800_ai_do_cmdtest;
+ s->do_cmd = das800_ai_do_cmd;
+ s->cancel = das800_cancel;
+ }
+
+ /* Digital Input subdevice */
+ s = &dev->subdevices[1];
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 3;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das800_di_insn_bits;
+
+ /* Digital Output subdevice */
+ s = &dev->subdevices[2];
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 4;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = das800_do_insn_bits;
+
+ das800_disable(dev);
+
+ /* initialize digital out channels */
+ spin_lock_irqsave(&dev->spinlock, irq_flags);
+ das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
+ spin_unlock_irqrestore(&dev->spinlock, irq_flags);
+
+ return 0;
+};
+
+static struct comedi_driver driver_das800 = {
+ .driver_name = "das800",
+ .module = THIS_MODULE,
+ .attach = das800_attach,
+ .detach = comedi_legacy_detach,
+ .num_names = ARRAY_SIZE(das800_boards),
+ .board_name = &das800_boards[0].name,
+ .offset = sizeof(struct das800_board),
+};
+module_comedi_driver(driver_das800);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 9e2124179a0c..6c85dd2d549b 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -695,25 +695,13 @@ static int dmm32at_attach(struct comedi_device *dev,
int ret;
struct comedi_subdevice *s;
unsigned char aihi, ailo, fifostat, aistat, intstat, airback;
- unsigned long iobase;
unsigned int irq;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
irq = it->options[1];
- printk(KERN_INFO "comedi%d: dmm32at: attaching\n", dev->minor);
- printk(KERN_DEBUG "dmm32at: probing at address 0x%04lx, irq %u\n",
- iobase, irq);
-
- /* register address space */
- if (!request_region(iobase, DMM32AT_MEMSIZE, dev->board_name)) {
- printk(KERN_ERR "comedi%d: dmm32at: I/O port conflict\n",
- dev->minor);
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], DMM32AT_MEMSIZE);
+ if (ret)
+ return ret;
/* the following just makes sure the board is there and gets
it to a known state */
@@ -832,19 +820,11 @@ static int dmm32at_attach(struct comedi_device *dev,
}
-static void dmm32at_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DMM32AT_MEMSIZE);
-}
-
static struct comedi_driver dmm32at_driver = {
.driver_name = "dmm32at",
.module = THIS_MODULE,
.attach = dmm32at_attach,
- .detach = dmm32at_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(dmm32at_driver);
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index f6942aaf0ecd..8f5006d70daf 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -225,8 +225,6 @@ static const struct dt2801_board boardtypes[] = {
.dabits = 12},
};
-#define boardtype (*(const struct dt2801_board *)dev->board_ptr)
-
struct dt2801_private {
const struct comedi_lrange *dac_range_types[2];
@@ -592,19 +590,16 @@ static int dt2801_dio_insn_config(struct comedi_device *dev,
*/
static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
+ const struct dt2801_board *board = comedi_board(dev);
struct dt2801_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
int board_code, type;
int ret = 0;
int n_ai_chans;
- iobase = it->options[0];
- if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
- comedi_error(dev, "I/O port conflict");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], DT2801_IOSIZE);
+ if (ret)
+ return ret;
/* do some checking */
@@ -624,10 +619,9 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
havetype:
dev->board_ptr = boardtypes + type;
- printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
+ board = comedi_board(dev);
n_ai_chans = probe_number_of_ai_chans(dev);
- printk(" (ai channels = %d)\n", n_ai_chans);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -638,7 +632,7 @@ havetype:
return -ENOMEM;
dev->private = devpriv;
- dev->board_name = boardtype.name;
+ dev->board_name = board->name;
s = &dev->subdevices[0];
/* ai subdevice */
@@ -648,12 +642,12 @@ havetype:
s->n_chan = n_ai_chans;
#else
if (it->options[2])
- s->n_chan = boardtype.ad_chan;
+ s->n_chan = board->ad_chan;
else
- s->n_chan = boardtype.ad_chan / 2;
+ s->n_chan = board->ad_chan / 2;
#endif
- s->maxdata = (1 << boardtype.adbits) - 1;
- s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
+ s->maxdata = (1 << board->adbits) - 1;
+ s->range_table = ai_range_lkup(board->adrangetype, it->options[3]);
s->insn_read = dt2801_ai_insn_read;
s = &dev->subdevices[1];
@@ -661,7 +655,7 @@ havetype:
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
- s->maxdata = (1 << boardtype.dabits) - 1;
+ s->maxdata = (1 << board->dabits) - 1;
s->range_table_list = devpriv->dac_range_types;
devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
@@ -693,17 +687,11 @@ out:
return ret;
}
-static void dt2801_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, DT2801_IOSIZE);
-}
-
static struct comedi_driver dt2801_driver = {
.driver_name = "dt2801",
.module = THIS_MODULE,
.attach = dt2801_attach,
- .detach = dt2801_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(dt2801_driver);
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index f90ecf494aaf..8757b54ad4ac 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -50,8 +50,6 @@ Configuration options:
#include <linux/ioport.h>
-static const char *driver_name = "dt2811";
-
static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
4, {
RANGE(0, 5),
@@ -401,19 +399,10 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct dt2811_private *devpriv;
int ret;
struct comedi_subdevice *s;
- unsigned long iobase;
-
- iobase = it->options[0];
-
- printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase);
-
- if (!request_region(iobase, DT2811_SIZE, driver_name)) {
- printk(KERN_ERR "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], DT2811_SIZE);
+ if (ret)
+ return ret;
#if 0
outb(0, dev->iobase + DT2811_ADCSR);
@@ -449,7 +438,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
i = inb(dev->iobase + DT2811_ADDATHI);
printk(KERN_INFO "(irq = %d)\n", irq);
ret = request_irq(irq, dt2811_interrupt, 0,
- driver_name, dev);
+ dev->board_name, dev);
if (ret < 0)
return -EIO;
dev->irq = irq;
@@ -567,14 +556,6 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void dt2811_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DT2811_SIZE);
-}
-
static const struct dt2811_board boardtypes[] = {
{
.name = "dt2811-pgh",
@@ -593,7 +574,7 @@ static struct comedi_driver dt2811_driver = {
.driver_name = "dt2811",
.module = THIS_MODULE,
.attach = dt2811_attach,
- .detach = dt2811_detach,
+ .detach = comedi_legacy_detach,
.board_name = &boardtypes[0].name,
.num_names = ARRAY_SIZE(boardtypes),
.offset = sizeof(struct dt2811_board),
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index e520dbaaa194..7c95b3b68131 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -246,16 +246,10 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i, irq;
int ret;
struct comedi_subdevice *s;
- unsigned long iobase;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: dt2814: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, DT2814_SIZE, "dt2814")) {
- printk(KERN_ERR "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = "dt2814";
+ ret = comedi_request_region(dev, it->options[0], DT2814_SIZE);
+ if (ret)
+ return ret;
outb(0, dev->iobase + DT2814_CSR);
udelay(100);
@@ -329,19 +323,11 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void dt2814_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DT2814_SIZE);
-}
-
static struct comedi_driver dt2814_driver = {
.driver_name = "dt2814",
.module = THIS_MODULE,
.attach = dt2814_attach,
- .detach = dt2814_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(dt2814_driver);
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 1e0cfe4972a6..b24e87681fe3 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -61,12 +61,6 @@ Configuration options:
#include <linux/ioport.h>
#include <linux/delay.h>
-static const struct comedi_lrange
- range_dt2815_ao_32_current = {1, {RANGE_mA(0, 32)} };
-
-static const struct comedi_lrange
- range_dt2815_ao_20_current = {1, {RANGE_mA(4, 20)} };
-
#define DT2815_SIZE 2
#define DT2815_DATA 0
@@ -166,18 +160,11 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int i;
const struct comedi_lrange *current_range_type, *voltage_range_type;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: dt2815: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, DT2815_SIZE, "dt2815")) {
- printk(KERN_WARNING "I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
- dev->board_name = "dt2815";
+ ret = comedi_request_region(dev, it->options[0], DT2815_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -199,7 +186,7 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table_list = devpriv->range_type_list;
current_range_type = (it->options[3])
- ? &range_dt2815_ao_20_current : &range_dt2815_ao_32_current;
+ ? &range_4_20mA : &range_0_32mA;
voltage_range_type = (it->options[2])
? &range_bipolar5 : &range_unipolar5;
for (i = 0; i < 8; i++) {
@@ -233,17 +220,11 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void dt2815_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, DT2815_SIZE);
-}
-
static struct comedi_driver dt2815_driver = {
.driver_name = "dt2815",
.module = THIS_MODULE,
.attach = dt2815_attach,
- .detach = dt2815_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(dt2815_driver);
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 502e42e0753e..b5c8e8213faf 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -126,16 +126,10 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
struct comedi_subdevice *s;
- unsigned long iobase;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: dt2817: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, DT2817_SIZE, "dt2817")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = "dt2817";
+ ret = comedi_request_region(dev, it->options[0], DT2817_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -154,22 +148,14 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->state = 0;
outb(0, dev->iobase + DT2817_CR);
- printk(KERN_INFO "\n");
-
return 0;
}
-static void dt2817_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, DT2817_SIZE);
-}
-
static struct comedi_driver dt2817_driver = {
.driver_name = "dt2817",
.module = THIS_MODULE,
.attach = dt2817_attach,
- .detach = dt2817_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(dt2817_driver);
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 122d980a95a0..90f2de9bc402 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -248,8 +248,6 @@ struct dt282x_private {
int dma_dir;
};
-#define boardtype (*(const struct dt282x_board *)dev->board_ptr)
-
/*
* Some useless abstractions
*/
@@ -289,14 +287,15 @@ static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2);
static void dt282x_munge(struct comedi_device *dev, short *buf,
unsigned int nbytes)
{
+ const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv = dev->private;
unsigned int i;
- unsigned short mask = (1 << boardtype.adbits) - 1;
- unsigned short sign = 1 << (boardtype.adbits - 1);
+ unsigned short mask = (1 << board->adbits) - 1;
+ unsigned short sign = 1 << (board->adbits - 1);
int n;
if (devpriv->ad_2scomp)
- sign = 1 << (boardtype.adbits - 1);
+ sign = 1 << (board->adbits - 1);
else
sign = 0;
@@ -501,10 +500,10 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
short data;
data = (short)inw(dev->iobase + DT2821_ADDAT);
- data &= (1 << boardtype.adbits) - 1;
+ data &= (1 << board->adbits) - 1;
if (devpriv->ad_2scomp)
- data ^= 1 << (boardtype.adbits - 1);
+ data ^= 1 << (board->adbits - 1);
ret = comedi_buf_put(s->async, data);
if (ret == 0)
@@ -554,6 +553,7 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv = dev->private;
int i;
@@ -574,9 +574,9 @@ static int dt282x_ai_insn_read(struct comedi_device *dev,
data[i] =
inw(dev->iobase +
- DT2821_ADDAT) & ((1 << boardtype.adbits) - 1);
+ DT2821_ADDAT) & ((1 << board->adbits) - 1);
if (devpriv->ad_2scomp)
- data[i] ^= (1 << (boardtype.adbits - 1));
+ data[i] ^= (1 << (board->adbits - 1));
}
return i;
@@ -795,13 +795,14 @@ static int dt282x_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct dt282x_board *board = comedi_board(dev);
struct dt282x_private *devpriv = dev->private;
short d;
unsigned int chan;
chan = CR_CHAN(insn->chanspec);
d = data[0];
- d &= (1 << boardtype.dabits) - 1;
+ d &= (1 << board->dabits) - 1;
devpriv->ao[chan] = d;
devpriv->dacsr |= DT2821_SSEL;
@@ -810,11 +811,11 @@ static int dt282x_ao_insn_write(struct comedi_device *dev,
/* select channel */
devpriv->dacsr |= DT2821_YSEL;
if (devpriv->da0_2scomp)
- d ^= (1 << (boardtype.dabits - 1));
+ d ^= (1 << (board->dabits - 1));
} else {
devpriv->dacsr &= ~DT2821_YSEL;
if (devpriv->da1_2scomp)
- d ^= (1 << (boardtype.dabits - 1));
+ d ^= (1 << (board->dabits - 1));
}
outw(devpriv->dacsr, dev->iobase + DT2821_DACSR);
@@ -1122,20 +1123,10 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i, irq;
int ret;
struct comedi_subdevice *s;
- unsigned long iobase;
-
- dev->board_name = board->name;
- iobase = it->options[opt_iobase];
- if (!iobase)
- iobase = 0x240;
-
- printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase);
- if (!request_region(iobase, DT2821_SIZE, "dt282x")) {
- printk(KERN_INFO " I/O port conflict\n");
- return -EBUSY;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], DT2821_SIZE);
+ if (ret)
+ return ret;
outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR);
i = inw(dev->iobase + DT2821_ADCSR);
@@ -1185,7 +1176,8 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
if (irq > 0) {
printk(KERN_INFO " ( irq = %d )", irq);
- ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev);
+ ret = request_irq(irq, dt282x_interrupt, 0,
+ dev->board_name, dev);
if (ret < 0) {
printk(KERN_ERR " failed to get irq\n");
return -EIO;
@@ -1223,20 +1215,20 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->subdev_flags = SDF_READABLE | SDF_CMD_READ |
((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON);
s->n_chan =
- (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se;
+ (it->options[opt_diff]) ? board->adchan_di : board->adchan_se;
s->insn_read = dt282x_ai_insn_read;
s->do_cmdtest = dt282x_ai_cmdtest;
s->do_cmd = dt282x_ai_cmd;
s->cancel = dt282x_ai_cancel;
- s->maxdata = (1 << boardtype.adbits) - 1;
+ s->maxdata = (1 << board->adbits) - 1;
s->len_chanlist = 16;
s->range_table =
- opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]);
+ opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]);
devpriv->ad_2scomp = it->options[opt_ai_twos];
s = &dev->subdevices[1];
- s->n_chan = boardtype.dachan;
+ s->n_chan = board->dachan;
if (s->n_chan) {
/* ao subsystem */
s->type = COMEDI_SUBD_AO;
@@ -1247,7 +1239,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->do_cmdtest = dt282x_ao_cmdtest;
s->do_cmd = dt282x_ao_cmd;
s->cancel = dt282x_ao_cancel;
- s->maxdata = (1 << boardtype.dabits) - 1;
+ s->maxdata = (1 << board->dabits) - 1;
s->len_chanlist = 2;
s->range_table_list = devpriv->darangelist;
devpriv->darangelist[0] =
@@ -1279,10 +1271,6 @@ static void dt282x_detach(struct comedi_device *dev)
{
struct dt282x_private *devpriv = dev->private;
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DT2821_SIZE);
if (dev->private) {
if (devpriv->dma[0].chan)
free_dma(devpriv->dma[0].chan);
@@ -1293,6 +1281,7 @@ static void dt282x_detach(struct comedi_device *dev)
if (devpriv->dma[1].buf)
free_page((unsigned long)devpriv->dma[1].buf);
}
+ comedi_legacy_detach(dev);
}
static const struct dt282x_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 3ce499fa5dbf..7e03929c9a14 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -63,17 +63,6 @@ AO commands are not supported.
#include "comedi_fc.h"
-/*
- * PCI device id's supported by this driver
- */
-#define PCI_DEVICE_ID_DT3001 0x0022
-#define PCI_DEVICE_ID_DT3002 0x0023
-#define PCI_DEVICE_ID_DT3003 0x0024
-#define PCI_DEVICE_ID_DT3004 0x0025
-#define PCI_DEVICE_ID_DT3005 0x0026
-#define PCI_DEVICE_ID_DT3001_PGL 0x0027
-#define PCI_DEVICE_ID_DT3003_PGL 0x0028
-
static const struct comedi_lrange range_dt3000_ai = {
4, {
BIP_RANGE(10),
@@ -92,9 +81,18 @@ static const struct comedi_lrange range_dt3000_ai_pgl = {
}
};
+enum dt3k_boardid {
+ BOARD_DT3001,
+ BOARD_DT3001_PGL,
+ BOARD_DT3002,
+ BOARD_DT3003,
+ BOARD_DT3003_PGL,
+ BOARD_DT3004,
+ BOARD_DT3005,
+};
+
struct dt3k_boardtype {
const char *name;
- unsigned int device_id;
int adchan;
int adbits;
int ai_speed;
@@ -104,61 +102,60 @@ struct dt3k_boardtype {
};
static const struct dt3k_boardtype dt3k_boardtypes[] = {
- {
+ [BOARD_DT3001] = {
.name = "dt3001",
- .device_id = PCI_DEVICE_ID_DT3001,
.adchan = 16,
.adbits = 12,
.adrange = &range_dt3000_ai,
.ai_speed = 3000,
.dachan = 2,
.dabits = 12,
- }, {
+ },
+ [BOARD_DT3001_PGL] = {
.name = "dt3001-pgl",
- .device_id = PCI_DEVICE_ID_DT3001_PGL,
.adchan = 16,
.adbits = 12,
.adrange = &range_dt3000_ai_pgl,
.ai_speed = 3000,
.dachan = 2,
.dabits = 12,
- }, {
+ },
+ [BOARD_DT3002] = {
.name = "dt3002",
- .device_id = PCI_DEVICE_ID_DT3002,
.adchan = 32,
.adbits = 12,
.adrange = &range_dt3000_ai,
.ai_speed = 3000,
- }, {
+ },
+ [BOARD_DT3003] = {
.name = "dt3003",
- .device_id = PCI_DEVICE_ID_DT3003,
.adchan = 64,
.adbits = 12,
.adrange = &range_dt3000_ai,
.ai_speed = 3000,
.dachan = 2,
.dabits = 12,
- }, {
+ },
+ [BOARD_DT3003_PGL] = {
.name = "dt3003-pgl",
- .device_id = PCI_DEVICE_ID_DT3003_PGL,
.adchan = 64,
.adbits = 12,
.adrange = &range_dt3000_ai_pgl,
.ai_speed = 3000,
.dachan = 2,
.dabits = 12,
- }, {
+ },
+ [BOARD_DT3004] = {
.name = "dt3004",
- .device_id = PCI_DEVICE_ID_DT3004,
.adchan = 16,
.adbits = 16,
.adrange = &range_dt3000_ai,
.ai_speed = 10000,
.dachan = 2,
.dabits = 12,
- }, {
+ },
+ [BOARD_DT3005] = {
.name = "dt3005", /* a.k.a. 3004-200 */
- .device_id = PCI_DEVICE_ID_DT3005,
.adchan = 16,
.adbits = 16,
.adrange = &range_dt3000_ai,
@@ -168,8 +165,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = {
},
};
-#define DT3000_SIZE (4*0x1000)
-
/* dual-ported RAM location definitions */
#define DPR_DAC_buffer (4*0x000)
@@ -716,31 +711,17 @@ static int dt3k_mem_insn_read(struct comedi_device *dev,
return i;
}
-static const void *dt3000_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct dt3k_boardtype *this_board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
- this_board = &dt3k_boardtypes[i];
- if (this_board->device_id == pcidev->device)
- return this_board;
- }
- return NULL;
-}
-
static int dt3000_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct dt3k_boardtype *this_board;
+ const struct dt3k_boardtype *this_board = NULL;
struct dt3k_private *devpriv;
struct comedi_subdevice *s;
- resource_size_t pci_base;
int ret = 0;
- this_board = dt3000_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(dt3k_boardtypes))
+ this_board = &dt3k_boardtypes[context];
if (!this_board)
return -ENODEV;
dev->board_ptr = this_board;
@@ -751,13 +732,11 @@ static int dt3000_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret < 0)
return ret;
- dev->iobase = 1; /* the "detach" needs this */
- pci_base = pci_resource_start(pcidev, 0);
- devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
+ devpriv->io_addr = pci_ioremap_bar(pcidev, 0);
if (!devpriv->io_addr)
return -ENOMEM;
@@ -830,7 +809,6 @@ static int dt3000_auto_attach(struct comedi_device *dev,
static void dt3000_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct dt3k_private *devpriv = dev->private;
if (dev->irq)
@@ -839,10 +817,7 @@ static void dt3000_detach(struct comedi_device *dev)
if (devpriv->io_addr)
iounmap(devpriv->io_addr);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver dt3000_driver = {
@@ -853,19 +828,19 @@ static struct comedi_driver dt3000_driver = {
};
static int dt3000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &dt3000_driver);
+ return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3001_PGL) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3002) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3003_PGL) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3004) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, PCI_DEVICE_ID_DT3005) },
+ { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 },
+ { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 },
+ { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 },
+ { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 },
+ { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 },
+ { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL },
+ { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 57b451904791..81eb5ed6ec97 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -303,26 +303,6 @@ struct slot_dt9812 {
struct comedi_dt9812 *comedi;
};
-static const struct comedi_lrange dt9812_10_ain_range = { 1, {
- BIP_RANGE(10),
- }
-};
-
-static const struct comedi_lrange dt9812_2pt5_ain_range = { 1, {
- UNI_RANGE(2.5),
- }
-};
-
-static const struct comedi_lrange dt9812_10_aout_range = { 1, {
- BIP_RANGE(10),
- }
-};
-
-static const struct comedi_lrange dt9812_2pt5_aout_range = { 1, {
- UNI_RANGE(2.5),
- }
-};
-
static struct slot_dt9812 dt9812[DT9812_NUM_SLOTS];
static inline struct usb_dt9812 *to_dt9812_dev(struct kref *d)
@@ -912,12 +892,12 @@ static int dt9812_comedi_open(struct comedi_device *dev)
switch (devpriv->slot->usb->device) {
case 0:{
s->maxdata = 4095;
- s->range_table = &dt9812_10_ain_range;
+ s->range_table = &range_bipolar10;
}
break;
case 1:{
s->maxdata = 4095;
- s->range_table = &dt9812_2pt5_ain_range;
+ s->range_table = &range_unipolar2_5;
}
break;
}
@@ -927,12 +907,12 @@ static int dt9812_comedi_open(struct comedi_device *dev)
switch (devpriv->slot->usb->device) {
case 0:{
s->maxdata = 4095;
- s->range_table = &dt9812_10_aout_range;
+ s->range_table = &range_bipolar10;
}
break;
case 1:{
s->maxdata = 4095;
- s->range_table = &dt9812_2pt5_aout_range;
+ s->range_table = &range_unipolar2_5;
}
break;
}
@@ -1032,8 +1012,6 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
- dev->board_name = "dt9812";
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index decc17f1867e..93ec8e492ccc 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -187,14 +187,12 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
@@ -254,15 +252,11 @@ static int dyna_pci10xx_auto_attach(struct comedi_device *dev,
static void dyna_pci10xx_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct dyna_pci10xx_private *devpriv = dev->private;
if (devpriv)
mutex_destroy(&devpriv->mutex);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver dyna_pci10xx_driver = {
@@ -273,9 +267,10 @@ static struct comedi_driver dyna_pci10xx_driver = {
};
static int dyna_pci10xx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &dyna_pci10xx_driver);
+ return comedi_pci_auto_config(dev, &dyna_pci10xx_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 019c96eda6fd..ff6f0bd7c863 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -111,31 +111,18 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct fl512_private *devpriv;
- unsigned long iobase;
- int ret;
-
- /* pointer to the subdevice: Analog in, Analog out,
- (not made ->and Digital IO) */
struct comedi_subdevice *s;
+ int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi:%d fl512: 0x%04lx", dev->minor, iobase);
- if (!request_region(iobase, FL512_SIZE, "fl512")) {
- printk(KERN_WARNING " I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = "fl512";
+ ret = comedi_request_region(dev, it->options[0], FL512_SIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
-#if DEBUG
- printk(KERN_DEBUG "malloc ok\n");
-#endif
-
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
return ret;
@@ -157,7 +144,6 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_fl512;
/* function to call when read AD */
s->insn_read = fl512_ai_insn;
- printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n");
/* Analog output */
s = &dev->subdevices[1];
@@ -175,22 +161,15 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_write = fl512_ao_insn;
/* function to call when reading DA */
s->insn_read = fl512_ao_insn_readback;
- printk(KERN_INFO "comedi: fl512: subdevice 1 initialized\n");
return 1;
}
-static void fl512_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, FL512_SIZE);
-}
-
static struct comedi_driver fl512_driver = {
.driver_name = "fl512",
.module = THIS_MODULE,
.attach = fl512_attach,
- .detach = fl512_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(fl512_driver);
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index b60c97562676..0c061df0978c 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -78,12 +78,6 @@ static int dio_config_block_size(struct comedi_device *dev, unsigned int *data);
#define NUM_DMA_BUFFERS 4
#define NUM_DMA_DESCRIPTORS 256
-/* indices of base address regions */
-enum base_address_regions {
- PLX9080_BADDRINDEX = 0,
- HPDI_BADDRINDEX = 2,
-};
-
enum hpdi_registers {
FIRMWARE_REV_REG = 0x0,
BOARD_CONTROL_REG = 0x4,
@@ -499,20 +493,13 @@ static int hpdi_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- if (comedi_pci_enable(pcidev, dev->board_name)) {
- dev_warn(dev->class_dev,
- "failed enable PCI device and request regions\n");
- return -EIO;
- }
- dev->iobase = 1; /* the "detach" needs this */
+ retval = comedi_pci_enable(dev);
+ if (retval)
+ return retval;
pci_set_master(pcidev);
- devpriv->plx9080_iobase =
- ioremap(pci_resource_start(pcidev, PLX9080_BADDRINDEX),
- pci_resource_len(pcidev, PLX9080_BADDRINDEX));
- devpriv->hpdi_iobase =
- ioremap(pci_resource_start(pcidev, HPDI_BADDRINDEX),
- pci_resource_len(pcidev, HPDI_BADDRINDEX));
+ devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0);
+ devpriv->hpdi_iobase = pci_ioremap_bar(pcidev, 2);
if (!devpriv->plx9080_iobase || !devpriv->hpdi_iobase) {
dev_warn(dev->class_dev, "failed to remap io memory\n");
return -ENOMEM;
@@ -596,9 +583,8 @@ static void hpdi_detach(struct comedi_device *dev)
NUM_DMA_DESCRIPTORS,
devpriv->dma_desc,
devpriv->dma_desc_phys_addr);
- if (dev->iobase)
- comedi_pci_disable(pcidev);
}
+ comedi_pci_disable(dev);
}
static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
@@ -943,9 +929,9 @@ static struct comedi_driver gsc_hpdi_driver = {
};
static int gsc_hpdi_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &gsc_hpdi_driver);
+ return comedi_pci_auto_config(dev, &gsc_hpdi_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 1e08f9141fad..08ab9d6e7190 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -68,8 +68,6 @@ Configuration options: not applicable, uses PCI auto config
#define ICP_MULTI_CNTR2 0x14 /* R/W: Counter 2 */
#define ICP_MULTI_CNTR3 0x16 /* R/W: Counter 3 */
-#define ICP_MULTI_SIZE 0x20 /* 32 bytes */
-
/* Define bits from ADC command/status register */
#define ADC_ST 0x0001 /* Start ADC */
#define ADC_BSY 0x0001 /* ADC busy */
@@ -120,7 +118,7 @@ struct icp_multi_private {
unsigned int DacCmdStatus; /* DAC Command/Status register */
unsigned int IntEnable; /* Interrupt Enable register */
unsigned int IntStatus; /* Interrupt Status register */
- unsigned int act_chanlist[32]; /* list of scaned channel */
+ unsigned int act_chanlist[32]; /* list of scanned channel */
unsigned char act_chanlist_len; /* len of scanlist */
unsigned char act_chanlist_pos; /* actual position in MUX list */
unsigned int *ai_chanlist; /* actaul chanlist */
@@ -500,23 +498,18 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct icp_multi_private *devpriv;
struct comedi_subdevice *s;
- resource_size_t iobase;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
- iobase = pci_resource_start(pcidev, 2);
- dev->iobase = iobase;
- devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE);
+ devpriv->io_addr = pci_ioremap_bar(pcidev, 2);
if (!devpriv->io_addr)
return -ENOMEM;
@@ -594,7 +587,6 @@ static int icp_multi_auto_attach(struct comedi_device *dev,
static void icp_multi_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct icp_multi_private *devpriv = dev->private;
if (devpriv)
@@ -604,10 +596,7 @@ static void icp_multi_detach(struct comedi_device *dev)
free_irq(dev->irq, dev);
if (devpriv && devpriv->io_addr)
iounmap(devpriv->io_addr);
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver icp_multi_driver = {
@@ -618,9 +607,9 @@ static struct comedi_driver icp_multi_driver = {
};
static int icp_multi_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &icp_multi_driver);
+ return comedi_pci_auto_config(dev, &icp_multi_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 93584e2be35a..ee7537daf473 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -77,9 +77,6 @@ options for PCI-20341M:
3 200
*/
-/* XXX needs to use ioremap() for compatibility with 2.4 kernels. Should also
- * check_mem_region() etc. - fmhess */
-
#include "../comedidev.h"
#define PCI20000_ID 0x1d
@@ -212,7 +209,6 @@ static int pci20xxx_attach(struct comedi_device *dev,
dev->private = devpriv;
devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0];
- dev->board_name = "pci20kc";
/* Check PCI-20001 C-2A Carrier Board ID */
if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) {
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 17ba75e0ab89..90b303ab2300 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -700,16 +700,12 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
return -EINVAL;
break;
}
- dev->board_name = "jr3_pci";
- result = comedi_pci_enable(pcidev, "jr3_pci");
- if (result < 0)
+ result = comedi_pci_enable(dev);
+ if (result)
return result;
- dev->iobase = 1; /* the "detach" needs this */
- devpriv->iobase = ioremap(pci_resource_start(pcidev, 0),
- offsetof(struct jr3_t,
- channel[devpriv->n_channels]));
+ devpriv->iobase = pci_ioremap_bar(pcidev, 0);
if (!devpriv->iobase)
return -ENOMEM;
@@ -816,7 +812,6 @@ static int jr3_pci_auto_attach(struct comedi_device *dev,
static void jr3_pci_detach(struct comedi_device *dev)
{
int i;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct jr3_pci_dev_private *devpriv = dev->private;
if (devpriv) {
@@ -828,9 +823,8 @@ static void jr3_pci_detach(struct comedi_device *dev)
}
if (devpriv->iobase)
iounmap(devpriv->iobase);
- if (dev->iobase)
- comedi_pci_disable(pcidev);
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver jr3_pci_driver = {
@@ -841,9 +835,9 @@ static struct comedi_driver jr3_pci_driver = {
};
static int jr3_pci_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &jr3_pci_driver);
+ return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 8c09c026508a..e0e64752e310 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -96,9 +96,7 @@ static int cnt_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
dev->iobase = pci_resource_start(pcidev, 0);
@@ -131,27 +129,18 @@ static int cnt_auto_attach(struct comedi_device *dev,
return 0;
}
-static void cnt_detach(struct comedi_device *dev)
-{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
-}
-
static struct comedi_driver ke_counter_driver = {
.driver_name = "ke_counter",
.module = THIS_MODULE,
.auto_attach = cnt_auto_attach,
- .detach = cnt_detach,
+ .detach = comedi_pci_disable,
};
static int ke_counter_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ke_counter_driver);
+ return comedi_pci_auto_config(dev, &ke_counter_driver,
+ id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index b766bb93efd6..641e693d5d0e 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -55,26 +55,13 @@ broken.
#include "comedi_fc.h"
#include "8253.h"
+#include "plx9052.h"
#if 0
/* file removed due to GPL incompatibility */
#include "me4000_fw.h"
#endif
-#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650
-#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660
-#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661
-#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662
-#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663
-#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670
-#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671
-#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672
-#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673
-#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680
-#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681
-#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682
-#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683
-
/*
* ME4000 Register map and bit defines
*/
@@ -183,28 +170,6 @@ broken.
#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c
#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0
-/*
- * PLX Register map and bit defines
- */
-#define PLX_INTCSR 0x4c
-#define PLX_INTCSR_LOCAL_INT1_EN (1 << 0)
-#define PLX_INTCSR_LOCAL_INT1_POL (1 << 1)
-#define PLX_INTCSR_LOCAL_INT1_STATE (1 << 2)
-#define PLX_INTCSR_LOCAL_INT2_EN (1 << 3)
-#define PLX_INTCSR_LOCAL_INT2_POL (1 << 4)
-#define PLX_INTCSR_LOCAL_INT2_STATE (1 << 5)
-#define PLX_INTCSR_PCI_INT_EN (1 << 6)
-#define PLX_INTCSR_SOFT_INT (1 << 7)
-#define PLX_ICR 0x50
-#define PLX_ICR_BIT_EEPROM_CLOCK_SET (1 << 24)
-#define PLX_ICR_BIT_EEPROM_CHIP_SELECT (1 << 25)
-#define PLX_ICR_BIT_EEPROM_WRITE (1 << 26)
-#define PLX_ICR_BIT_EEPROM_READ (1 << 27)
-#define PLX_ICR_BIT_EEPROM_VALID (1 << 28)
-#define PLX_ICR_MASK_EEPROM (0x1f << 24)
-
-#define EEPROM_DELAY 1
-
#define ME4000_AI_FIFO_COUNT 2048
#define ME4000_AI_MIN_TICKS 66
@@ -220,9 +185,24 @@ struct me4000_info {
unsigned int ao_readback[4];
};
+enum me4000_boardid {
+ BOARD_ME4650,
+ BOARD_ME4660,
+ BOARD_ME4660I,
+ BOARD_ME4660S,
+ BOARD_ME4660IS,
+ BOARD_ME4670,
+ BOARD_ME4670I,
+ BOARD_ME4670S,
+ BOARD_ME4670IS,
+ BOARD_ME4680,
+ BOARD_ME4680I,
+ BOARD_ME4680S,
+ BOARD_ME4680IS,
+};
+
struct me4000_board {
const char *name;
- unsigned short device_id;
int ao_nchan;
int ao_fifo;
int ai_nchan;
@@ -234,62 +214,61 @@ struct me4000_board {
};
static const struct me4000_board me4000_boards[] = {
- {
+ [BOARD_ME4650] = {
.name = "ME-4650",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4650,
.ai_nchan = 16,
.dio_nchan = 32,
- }, {
+ },
+ [BOARD_ME4660] = {
.name = "ME-4660",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4660I] = {
.name = "ME-4660i",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660I,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4660S] = {
.name = "ME-4660s",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660S,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.ai_sh_nchan = 8,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4660IS] = {
.name = "ME-4660is",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660IS,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.ai_sh_nchan = 8,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4670] = {
.name = "ME-4670",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670,
.ao_nchan = 4,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4670I] = {
.name = "ME-4670i",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670I,
.ao_nchan = 4,
.ai_nchan = 32,
.ai_diff_nchan = 16,
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4670S] = {
.name = "ME-4670s",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670S,
.ao_nchan = 4,
.ai_nchan = 32,
.ai_diff_nchan = 16,
@@ -297,9 +276,9 @@ static const struct me4000_board me4000_boards[] = {
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4670IS] = {
.name = "ME-4670is",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670IS,
.ao_nchan = 4,
.ai_nchan = 32,
.ai_diff_nchan = 16,
@@ -307,9 +286,9 @@ static const struct me4000_board me4000_boards[] = {
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4680] = {
.name = "ME-4680",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680,
.ao_nchan = 4,
.ao_fifo = 4,
.ai_nchan = 32,
@@ -317,9 +296,9 @@ static const struct me4000_board me4000_boards[] = {
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4680I] = {
.name = "ME-4680i",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680I,
.ao_nchan = 4,
.ao_fifo = 4,
.ai_nchan = 32,
@@ -327,9 +306,9 @@ static const struct me4000_board me4000_boards[] = {
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4680S] = {
.name = "ME-4680s",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680S,
.ao_nchan = 4,
.ao_fifo = 4,
.ai_nchan = 32,
@@ -338,9 +317,9 @@ static const struct me4000_board me4000_boards[] = {
.ex_trig_analog = 1,
.dio_nchan = 32,
.has_counter = 1,
- }, {
+ },
+ [BOARD_ME4680IS] = {
.name = "ME-4680is",
- .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680IS,
.ao_nchan = 4,
.ao_fifo = 4,
.ai_nchan = 32,
@@ -376,6 +355,7 @@ static int xilinx_download(struct comedi_device *dev)
wait_queue_head_t queue;
int idx = 0;
int size = 0;
+ unsigned int intcsr;
if (!xilinx_iobase)
return -ENODEV;
@@ -386,27 +366,28 @@ static int xilinx_download(struct comedi_device *dev)
* Set PLX local interrupt 2 polarity to high.
* Interrupt is thrown by init pin of xilinx.
*/
- outl(0x10, info->plx_regbase + PLX_INTCSR);
+ outl(PLX9052_INTCSR_LI2POL, info->plx_regbase + PLX9052_INTCSR);
/* Set /CS and /WRITE of the Xilinx */
- value = inl(info->plx_regbase + PLX_ICR);
- value |= 0x100;
- outl(value, info->plx_regbase + PLX_ICR);
+ value = inl(info->plx_regbase + PLX9052_CNTRL);
+ value |= PLX9052_CNTRL_UIO2_DATA;
+ outl(value, info->plx_regbase + PLX9052_CNTRL);
/* Init Xilinx with CS1 */
inb(xilinx_iobase + 0xC8);
/* Wait until /INIT pin is set */
udelay(20);
- if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) {
+ intcsr = inl(info->plx_regbase + PLX9052_INTCSR);
+ if (!(intcsr & PLX9052_INTCSR_LI2STAT)) {
dev_err(dev->class_dev, "Can't init Xilinx\n");
return -EIO;
}
/* Reset /CS and /WRITE of the Xilinx */
- value = inl(info->plx_regbase + PLX_ICR);
- value &= ~0x100;
- outl(value, info->plx_regbase + PLX_ICR);
+ value = inl(info->plx_regbase + PLX9052_CNTRL);
+ value &= ~PLX9052_CNTRL_UIO2_DATA;
+ outl(value, info->plx_regbase + PLX9052_CNTRL);
if (FIRMWARE_NOT_AVAILABLE) {
dev_err(dev->class_dev,
"xilinx firmware unavailable due to licensing, aborting");
@@ -422,7 +403,7 @@ static int xilinx_download(struct comedi_device *dev)
udelay(10);
/* Check if BUSY flag is low */
- if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
+ if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO1_DATA) {
dev_err(dev->class_dev,
"Xilinx is still busy (idx = %d)\n",
idx);
@@ -432,7 +413,7 @@ static int xilinx_download(struct comedi_device *dev)
}
/* If done flag is high download was successful */
- if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
+ if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO0_DATA) {
} else {
dev_err(dev->class_dev, "DONE flag is not set\n");
dev_err(dev->class_dev, "Download not successful\n");
@@ -440,9 +421,9 @@ static int xilinx_download(struct comedi_device *dev)
}
/* Set /CS and /WRITE */
- value = inl(info->plx_regbase + PLX_ICR);
- value |= 0x100;
- outl(value, info->plx_regbase + PLX_ICR);
+ value = inl(info->plx_regbase + PLX9052_CNTRL);
+ value |= PLX9052_CNTRL_UIO2_DATA;
+ outl(value, info->plx_regbase + PLX9052_CNTRL);
return 0;
}
@@ -454,11 +435,11 @@ static void me4000_reset(struct comedi_device *dev)
int chan;
/* Make a hardware reset */
- val = inl(info->plx_regbase + PLX_ICR);
- val |= 0x40000000;
- outl(val, info->plx_regbase + PLX_ICR);
- val &= ~0x40000000;
- outl(val , info->plx_regbase + PLX_ICR);
+ val = inl(info->plx_regbase + PLX9052_CNTRL);
+ val |= PLX9052_CNTRL_PCI_RESET;
+ outl(val, info->plx_regbase + PLX9052_CNTRL);
+ val &= ~PLX9052_CNTRL_PCI_RESET;
+ outl(val , info->plx_regbase + PLX9052_CNTRL);
/* 0x8000 to the DACs means an output voltage of 0V */
for (chan = 0; chan < 4; chan++)
@@ -474,7 +455,9 @@ static void me4000_reset(struct comedi_device *dev)
outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan));
/* Enable interrupts on the PLX */
- outl(0x43, info->plx_regbase + PLX_INTCSR);
+ outl(PLX9052_INTCSR_LI1ENAB |
+ PLX9052_INTCSR_LI1POL |
+ PLX9052_INTCSR_PCIENAB, info->plx_regbase + PLX9052_INTCSR);
/* Set the adustment register for AO demux */
outl(ME4000_AO_DEMUX_ADJUST_VALUE,
@@ -1550,30 +1533,17 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
return 1;
}
-static const void *me4000_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct me4000_board *thisboard;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) {
- thisboard = &me4000_boards[i];
- if (thisboard->device_id == pcidev->device)
- return thisboard;
- }
- return NULL;
-}
-
static int me4000_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct me4000_board *thisboard;
+ const struct me4000_board *thisboard = NULL;
struct me4000_info *info;
struct comedi_subdevice *s;
int result;
- thisboard = me4000_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(me4000_boards))
+ thisboard = &me4000_boards[context];
if (!thisboard)
return -ENODEV;
dev->board_ptr = thisboard;
@@ -1584,7 +1554,7 @@ static int me4000_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = info;
- result = comedi_pci_enable(pcidev, dev->board_name);
+ result = comedi_pci_enable(dev);
if (result)
return result;
@@ -1710,16 +1680,11 @@ static int me4000_auto_attach(struct comedi_device *dev,
static void me4000_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
- if (pcidev) {
- if (dev->iobase) {
- me4000_reset(dev);
- comedi_pci_disable(pcidev);
- }
- }
+ if (dev->iobase)
+ me4000_reset(dev);
+ comedi_pci_disable(dev);
}
static struct comedi_driver me4000_driver = {
@@ -1730,26 +1695,26 @@ static struct comedi_driver me4000_driver = {
};
static int me4000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &me4000_driver);
+ return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)},
- {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)},
- {0}
+ { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 },
+ { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 },
+ { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I },
+ { PCI_VDEVICE(MEILHAUS, 0x4662), BOARD_ME4660S },
+ { PCI_VDEVICE(MEILHAUS, 0x4663), BOARD_ME4660IS },
+ { PCI_VDEVICE(MEILHAUS, 0x4670), BOARD_ME4670 },
+ { PCI_VDEVICE(MEILHAUS, 0x4671), BOARD_ME4670I },
+ { PCI_VDEVICE(MEILHAUS, 0x4672), BOARD_ME4670S },
+ { PCI_VDEVICE(MEILHAUS, 0x4673), BOARD_ME4670IS },
+ { PCI_VDEVICE(MEILHAUS, 0x4680), BOARD_ME4680 },
+ { PCI_VDEVICE(MEILHAUS, 0x4681), BOARD_ME4680I },
+ { PCI_VDEVICE(MEILHAUS, 0x4682), BOARD_ME4680S },
+ { PCI_VDEVICE(MEILHAUS, 0x4683), BOARD_ME4680IS },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, me4000_pci_table);
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 06490ebc8cc8..09f2a9feaf7c 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -41,12 +41,10 @@
#include "../comedidev.h"
-#define ME2600_FIRMWARE "me2600_firmware.bin"
+#include "plx9052.h"
-#define ME2000_DEVICE_ID 0x2000
-#define ME2600_DEVICE_ID 0x2600
+#define ME2600_FIRMWARE "me2600_firmware.bin"
-#define PLX_INTCSR 0x4C /* PLX interrupt status register */
#define XILINX_DOWNLOAD_RESET 0x42 /* Xilinx registers */
#define ME_CONTROL_1 0x0000 /* - | W */
@@ -149,21 +147,26 @@ static const struct comedi_lrange me_ao_range = {
}
};
+enum me_boardid {
+ BOARD_ME2600,
+ BOARD_ME2000,
+};
+
struct me_board {
const char *name;
- int device_id;
+ int needs_firmware;
int has_ao;
};
static const struct me_board me_boards[] = {
- {
+ [BOARD_ME2600] = {
.name = "me-2600i",
- .device_id = ME2600_DEVICE_ID,
+ .needs_firmware = 1,
.has_ao = 1,
- }, {
+ },
+ [BOARD_ME2000] = {
.name = "me-2000i",
- .device_id = ME2000_DEVICE_ID,
- }
+ },
};
struct me_private_data {
@@ -396,7 +399,7 @@ static int me2600_xilinx_download(struct comedi_device *dev,
unsigned int i;
/* disable irq's on PLX */
- writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
+ writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR);
/* First, make a dummy read to reset xilinx */
value = readw(dev_private->me_regbase + XILINX_DOWNLOAD_RESET);
@@ -426,7 +429,7 @@ static int me2600_xilinx_download(struct comedi_device *dev,
/*
* Loop for writing firmware byte by byte to xilinx
- * Firmware data start at offfset 16
+ * Firmware data start at offset 16
*/
for (i = 0; i < file_length; i++)
writeb((data[16 + i] & 0xff),
@@ -437,10 +440,10 @@ static int me2600_xilinx_download(struct comedi_device *dev,
writeb(0x00, dev_private->me_regbase + 0x0);
/* Test if there was an error during download -> INTB was thrown */
- value = readl(dev_private->plx_regbase + PLX_INTCSR);
- if (value & 0x20) {
+ value = readl(dev_private->plx_regbase + PLX9052_INTCSR);
+ if (value & PLX9052_INTCSR_LI2STAT) {
/* Disable interrupt */
- writel(0x00, dev_private->plx_regbase + PLX_INTCSR);
+ writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR);
dev_err(dev->class_dev, "Xilinx download failed\n");
return -EIO;
}
@@ -449,7 +452,10 @@ static int me2600_xilinx_download(struct comedi_device *dev,
sleep(1);
/* Enable PLX-Interrupts */
- writel(0x43, dev_private->plx_regbase + PLX_INTCSR);
+ writel(PLX9052_INTCSR_LI1ENAB |
+ PLX9052_INTCSR_LI1POL |
+ PLX9052_INTCSR_PCIENAB,
+ dev_private->plx_regbase + PLX9052_INTCSR);
return 0;
}
@@ -488,30 +494,17 @@ static int me_reset(struct comedi_device *dev)
return 0;
}
-static const void *me_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct me_board *board;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(me_boards); i++) {
- board = &me_boards[i];
- if (board->device_id == pcidev->device)
- return board;
- }
- return NULL;
-}
-
static int me_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct me_board *board;
+ const struct me_board *board = NULL;
struct me_private_data *dev_private;
struct comedi_subdevice *s;
int ret;
- board = me_find_boardinfo(dev, pcidev);
+ if (context < ARRAY_SIZE(me_boards))
+ board = &me_boards[context];
if (!board)
return -ENODEV;
dev->board_ptr = board;
@@ -522,23 +515,20 @@ static int me_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = dev_private;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
- dev->iobase = 1; /* detach needs this */
- dev_private->plx_regbase = ioremap(pci_resource_start(pcidev, 0),
- pci_resource_len(pcidev, 0));
+ dev_private->plx_regbase = pci_ioremap_bar(pcidev, 0);
if (!dev_private->plx_regbase)
return -ENOMEM;
- dev_private->me_regbase = ioremap(pci_resource_start(pcidev, 2),
- pci_resource_len(pcidev, 2));
+ dev_private->me_regbase = pci_ioremap_bar(pcidev, 2);
if (!dev_private->me_regbase)
return -ENOMEM;
/* Download firmware and reset card */
- if (board->device_id == ME2600_DEVICE_ID) {
+ if (board->needs_firmware) {
ret = me2600_upload_firmware(dev);
if (ret < 0)
return ret;
@@ -591,7 +581,6 @@ static int me_auto_attach(struct comedi_device *dev,
static void me_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct me_private_data *dev_private = dev->private;
if (dev_private) {
@@ -602,10 +591,7 @@ static void me_detach(struct comedi_device *dev)
if (dev_private->plx_regbase)
iounmap(dev_private->plx_regbase);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver me_daq_driver = {
@@ -616,14 +602,14 @@ static struct comedi_driver me_daq_driver = {
};
static int me_daq_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &me_daq_driver);
+ return comedi_pci_auto_config(dev, &me_daq_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
+ { PCI_VDEVICE(MEILHAUS, 0x2600), BOARD_ME2600 },
+ { PCI_VDEVICE(MEILHAUS, 0x2000), BOARD_ME2000 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, me_daq_pci_table);
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index be2c15f84614..523c6564ffca 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -58,10 +58,6 @@
#include "comedi_fc.h"
#include "mite.h"
-#define PCI_MITE_SIZE 4096
-#define PCI_DAQ_SIZE 4096
-#define PCI_DAQ_SIZE_660X 8192
-
#define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK)))
struct mite_struct *mite_alloc(struct pci_dev *pcidev)
@@ -81,7 +77,7 @@ struct mite_struct *mite_alloc(struct pci_dev *pcidev)
}
return mite;
}
-EXPORT_SYMBOL(mite_alloc);
+EXPORT_SYMBOL_GPL(mite_alloc);
static void dump_chip_signature(u32 csigr_bits)
{
@@ -104,40 +100,28 @@ static unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel)
int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
{
unsigned long length;
- resource_size_t addr;
int i;
u32 csigr_bits;
unsigned unknown_dma_burst_bits;
- if (comedi_pci_enable(mite->pcidev, "mite")) {
- dev_err(&mite->pcidev->dev,
- "error enabling mite and requesting io regions\n");
- return -EIO;
- }
pci_set_master(mite->pcidev);
- addr = pci_resource_start(mite->pcidev, 0);
- mite->mite_phys_addr = addr;
- mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE);
+ mite->mite_io_addr = pci_ioremap_bar(mite->pcidev, 0);
if (!mite->mite_io_addr) {
dev_err(&mite->pcidev->dev,
"Failed to remap mite io memory address\n");
return -ENOMEM;
}
+ mite->mite_phys_addr = pci_resource_start(mite->pcidev, 0);
- addr = pci_resource_start(mite->pcidev, 1);
- mite->daq_phys_addr = addr;
- length = pci_resource_len(mite->pcidev, 1);
- /*
- * In case of a 660x board, DAQ size is 8k instead of 4k
- * (see as shown by lspci output)
- */
- mite->daq_io_addr = ioremap(mite->daq_phys_addr, length);
+ mite->daq_io_addr = pci_ioremap_bar(mite->pcidev, 1);
if (!mite->daq_io_addr) {
dev_err(&mite->pcidev->dev,
"Failed to remap daq io memory address\n");
return -ENOMEM;
}
+ mite->daq_phys_addr = pci_resource_start(mite->pcidev, 1);
+ length = pci_resource_len(mite->pcidev, 1);
if (use_iodwbsr_1) {
writel(0, mite->mite_io_addr + MITE_IODWBSR);
@@ -185,13 +169,13 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1)
dev_info(&mite->pcidev->dev, "fifo size is %i.\n", mite->fifo_size);
return 0;
}
-EXPORT_SYMBOL(mite_setup2);
+EXPORT_SYMBOL_GPL(mite_setup2);
int mite_setup(struct mite_struct *mite)
{
return mite_setup2(mite, 0);
}
-EXPORT_SYMBOL(mite_setup);
+EXPORT_SYMBOL_GPL(mite_setup);
void mite_unsetup(struct mite_struct *mite)
{
@@ -208,12 +192,10 @@ void mite_unsetup(struct mite_struct *mite)
iounmap(mite->daq_io_addr);
mite->daq_io_addr = NULL;
}
- if (mite->mite_phys_addr) {
- comedi_pci_disable(mite->pcidev);
+ if (mite->mite_phys_addr)
mite->mite_phys_addr = 0;
- }
}
-EXPORT_SYMBOL(mite_unsetup);
+EXPORT_SYMBOL_GPL(mite_unsetup);
struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite)
{
@@ -232,7 +214,7 @@ struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite)
ring->descriptors_dma_addr = 0;
return ring;
};
-EXPORT_SYMBOL(mite_alloc_ring);
+EXPORT_SYMBOL_GPL(mite_alloc_ring);
void mite_free_ring(struct mite_dma_descriptor_ring *ring)
{
@@ -248,7 +230,7 @@ void mite_free_ring(struct mite_dma_descriptor_ring *ring)
kfree(ring);
}
};
-EXPORT_SYMBOL(mite_free_ring);
+EXPORT_SYMBOL_GPL(mite_free_ring);
struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
struct
@@ -275,7 +257,7 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite,
spin_unlock_irqrestore(&mite->lock, flags);
return channel;
}
-EXPORT_SYMBOL(mite_request_channel_in_range);
+EXPORT_SYMBOL_GPL(mite_request_channel_in_range);
void mite_release_channel(struct mite_channel *mite_chan)
{
@@ -302,7 +284,7 @@ void mite_release_channel(struct mite_channel *mite_chan)
}
spin_unlock_irqrestore(&mite->lock, flags);
}
-EXPORT_SYMBOL(mite_release_channel);
+EXPORT_SYMBOL_GPL(mite_release_channel);
void mite_dma_arm(struct mite_channel *mite_chan)
{
@@ -325,7 +307,7 @@ void mite_dma_arm(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
/* mite_dma_tcr(mite, channel); */
}
-EXPORT_SYMBOL(mite_dma_arm);
+EXPORT_SYMBOL_GPL(mite_dma_arm);
/**************************************/
@@ -382,7 +364,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
smp_wmb();
return 0;
}
-EXPORT_SYMBOL(mite_buf_change);
+EXPORT_SYMBOL_GPL(mite_buf_change);
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits)
@@ -473,7 +455,7 @@ void mite_prep_dma(struct mite_channel *mite_chan,
MDPRINTK("exit mite_prep_dma\n");
}
-EXPORT_SYMBOL(mite_prep_dma);
+EXPORT_SYMBOL_GPL(mite_prep_dma);
static u32 mite_device_bytes_transferred(struct mite_channel *mite_chan)
{
@@ -487,7 +469,7 @@ u32 mite_bytes_in_transit(struct mite_channel *mite_chan)
return readl(mite->mite_io_addr +
MITE_FCR(mite_chan->channel)) & 0x000000FF;
}
-EXPORT_SYMBOL(mite_bytes_in_transit);
+EXPORT_SYMBOL_GPL(mite_bytes_in_transit);
/* returns lower bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan)
@@ -497,7 +479,7 @@ u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan)
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count - mite_bytes_in_transit(mite_chan);
}
-EXPORT_SYMBOL(mite_bytes_written_to_memory_lb);
+EXPORT_SYMBOL_GPL(mite_bytes_written_to_memory_lb);
/* returns upper bound for number of bytes transferred from device to memory */
u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan)
@@ -507,7 +489,7 @@ u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan)
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) - in_transit_count;
}
-EXPORT_SYMBOL(mite_bytes_written_to_memory_ub);
+EXPORT_SYMBOL_GPL(mite_bytes_written_to_memory_ub);
/* returns lower bound for number of bytes read from memory to device */
u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan)
@@ -517,7 +499,7 @@ u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan)
device_byte_count = mite_device_bytes_transferred(mite_chan);
return device_byte_count + mite_bytes_in_transit(mite_chan);
}
-EXPORT_SYMBOL(mite_bytes_read_from_memory_lb);
+EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_lb);
/* returns upper bound for number of bytes read from memory to device */
u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan)
@@ -527,7 +509,7 @@ u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan)
in_transit_count = mite_bytes_in_transit(mite_chan);
return mite_device_bytes_transferred(mite_chan) + in_transit_count;
}
-EXPORT_SYMBOL(mite_bytes_read_from_memory_ub);
+EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_ub);
unsigned mite_dma_tcr(struct mite_channel *mite_chan)
{
@@ -542,7 +524,7 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan)
return tcr;
}
-EXPORT_SYMBOL(mite_dma_tcr);
+EXPORT_SYMBOL_GPL(mite_dma_tcr);
void mite_dma_disarm(struct mite_channel *mite_chan)
{
@@ -553,7 +535,7 @@ void mite_dma_disarm(struct mite_channel *mite_chan)
chor = CHOR_ABORT;
writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel));
}
-EXPORT_SYMBOL(mite_dma_disarm);
+EXPORT_SYMBOL_GPL(mite_dma_disarm);
int mite_sync_input_dma(struct mite_channel *mite_chan,
struct comedi_async *async)
@@ -591,7 +573,7 @@ int mite_sync_input_dma(struct mite_channel *mite_chan,
async->events |= COMEDI_CB_BLOCK;
return 0;
}
-EXPORT_SYMBOL(mite_sync_input_dma);
+EXPORT_SYMBOL_GPL(mite_sync_input_dma);
int mite_sync_output_dma(struct mite_channel *mite_chan,
struct comedi_async *async)
@@ -629,7 +611,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
}
return 0;
}
-EXPORT_SYMBOL(mite_sync_output_dma);
+EXPORT_SYMBOL_GPL(mite_sync_output_dma);
unsigned mite_get_status(struct mite_channel *mite_chan)
{
@@ -648,7 +630,7 @@ unsigned mite_get_status(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
return status;
}
-EXPORT_SYMBOL(mite_get_status);
+EXPORT_SYMBOL_GPL(mite_get_status);
int mite_done(struct mite_channel *mite_chan)
{
@@ -662,7 +644,7 @@ int mite_done(struct mite_channel *mite_chan)
spin_unlock_irqrestore(&mite->lock, flags);
return done;
}
-EXPORT_SYMBOL(mite_done);
+EXPORT_SYMBOL_GPL(mite_done);
#ifdef DEBUG_MITE
@@ -795,7 +777,7 @@ void mite_dump_regs(struct mite_channel *mite_chan)
value = readl(mite_io_addr + offset);
pr_debug("mite status[FCR] at 0x%08x =0x%08x\n", offset, value);
}
-EXPORT_SYMBOL(mite_dump_regs);
+EXPORT_SYMBOL_GPL(mite_dump_regs);
#endif
static int __init mite_module_init(void)
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index 67dc5ad81b0d..4717be4ad268 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -285,18 +285,11 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct mpc624_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
- if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
- printk(KERN_ERR "I/O port(s) in use\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
- dev->board_name = "mpc624";
+ ret = comedi_request_region(dev, it->options[0], MPC624_SIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -306,48 +299,35 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
switch (it->options[1]) {
case 0:
devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
- printk(KERN_INFO "3.52 kHz, ");
break;
case 1:
devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
- printk(KERN_INFO "1.76 kHz, ");
break;
case 2:
devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
- printk(KERN_INFO "880 Hz, ");
break;
case 3:
devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
- printk(KERN_INFO "440 Hz, ");
break;
case 4:
devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
- printk(KERN_INFO "220 Hz, ");
break;
case 5:
devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
- printk(KERN_INFO "110 Hz, ");
break;
case 6:
devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
- printk(KERN_INFO "55 Hz, ");
break;
case 7:
devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
- printk(KERN_INFO "27.5 Hz, ");
break;
case 8:
devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
- printk(KERN_INFO "13.75 Hz, ");
break;
case 9:
devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
- printk(KERN_INFO "6.875 Hz, ");
break;
default:
- printk
- (KERN_ERR "illegal conversion rate setting!"
- " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
}
@@ -362,37 +342,26 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
switch (it->options[1]) {
default:
s->maxdata = 0x3FFFFFFF;
- printk(KERN_INFO "30 bit, ");
}
switch (it->options[1]) {
case 0:
s->range_table = &range_mpc624_bipolar1;
- printk(KERN_INFO "1.01V]: ");
break;
default:
s->range_table = &range_mpc624_bipolar10;
- printk(KERN_INFO "10.1V]: ");
}
s->len_chanlist = 1;
s->insn_read = mpc624_ai_rinsn;
- printk(KERN_INFO "attached\n");
-
return 1;
}
-static void mpc624_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, MPC624_SIZE);
-}
-
static struct comedi_driver mpc624_driver = {
.driver_name = "mpc624",
.module = THIS_MODULE,
.attach = mpc624_attach,
- .detach = mpc624_detach
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(mpc624_driver);
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index 1f5f402f3d17..7a8292086e18 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -222,41 +222,20 @@ static void encoder_reset(struct comedi_device *dev)
}
}
-/*
- options[0] - I/O port
- options[1] - irq
- options[2] - number of encoder chips installed
- */
-
static int multiq3_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct multiq3_private *devpriv;
- int result = 0;
- unsigned long iobase;
- unsigned int irq;
struct comedi_subdevice *s;
+ int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: multiq3: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, MULTIQ3_SIZE, "multiq3")) {
- printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
- return -EIO;
- }
-
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], MULTIQ3_SIZE);
+ if (ret)
+ return ret;
- irq = it->options[1];
- if (irq)
- printk(KERN_WARNING "comedi%d: irq = %u ignored\n",
- dev->minor, irq);
- else
- printk(KERN_WARNING "comedi%d: no irq\n", dev->minor);
- dev->board_name = "multiq3";
-
- result = comedi_alloc_subdevices(dev, 5);
- if (result)
- return result;
+ ret = comedi_alloc_subdevices(dev, 5);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -315,19 +294,11 @@ static int multiq3_attach(struct comedi_device *dev,
return 0;
}
-static void multiq3_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, MULTIQ3_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-}
-
static struct comedi_driver multiq3_driver = {
.driver_name = "multiq3",
.module = THIS_MODULE,
.attach = multiq3_attach,
- .detach = multiq3_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(multiq3_driver);
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index bcd4df290ec4..d10f777b7f17 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -81,33 +81,24 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800
#define Rising_Edge_Detection_Enable(x) (0x018+(x))
#define Falling_Edge_Detection_Enable(x) (0x020+(x))
-struct ni6527_board {
+enum ni6527_boardid {
+ BOARD_PCI6527,
+ BOARD_PXI6527,
+};
- int dev_id;
+struct ni6527_board {
const char *name;
};
static const struct ni6527_board ni6527_boards[] = {
- {
- .dev_id = 0x2b20,
- .name = "pci-6527",
- },
- {
- .dev_id = 0x2b10,
- .name = "pxi-6527",
- },
-};
-
-#define this_board ((const struct ni6527_board *)dev->board_ptr)
-
-static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b10)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b20)},
- {0}
+ [BOARD_PCI6527] = {
+ .name = "pci-6527",
+ },
+ [BOARD_PXI6527] = {
+ .name = "pxi-6527",
+ },
};
-MODULE_DEVICE_TABLE(pci, ni6527_pci_table);
-
struct ni6527_private {
struct mite_struct *mite;
unsigned int filter_interval;
@@ -329,37 +320,31 @@ static int ni6527_intr_insn_config(struct comedi_device *dev,
return 2;
}
-static const struct ni6527_board *
-ni6527_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int dev_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(ni6527_boards); n++) {
- const struct ni6527_board *board = &ni6527_boards[n];
- if (board->dev_id == dev_id)
- return board;
- }
- return NULL;
-}
-
static int ni6527_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct ni6527_board *board = NULL;
struct ni6527_private *devpriv;
struct comedi_subdevice *s;
int ret;
+ if (context < ARRAY_SIZE(ni6527_boards))
+ board = &ni6527_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- dev->board_ptr = ni6527_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
-
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
@@ -370,7 +355,6 @@ static int ni6527_auto_attach(struct comedi_device *dev,
return ret;
}
- dev->board_name = this_board->name;
dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name,
readb(devpriv->mite->daq_io_addr + ID_Register));
@@ -439,6 +423,7 @@ static void ni6527_detach(struct comedi_device *dev)
mite_unsetup(devpriv->mite);
mite_free(devpriv->mite);
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver ni6527_driver = {
@@ -449,15 +434,22 @@ static struct comedi_driver ni6527_driver = {
};
static int ni6527_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni6527_driver);
+ return comedi_pci_auto_config(dev, &ni6527_driver, id->driver_data);
}
+static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
+ { PCI_VDEVICE(NI, 0x2b10), BOARD_PXI6527 },
+ { PCI_VDEVICE(NI, 0x2b20), BOARD_PCI6527 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni6527_pci_table);
+
static struct pci_driver ni6527_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = ni6527_pci_table,
- .probe = ni6527_pci_probe,
+ .name = DRIVER_NAME,
+ .id_table = ni6527_pci_table,
+ .probe = ni6527_pci_probe,
.remove = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver);
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index bfa790ecf41d..3f71f0f54d3c 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -112,8 +112,32 @@ static inline unsigned Filter_Enable(unsigned port)
#define OverflowIntEnable 0x02
#define EdgeIntEnable 0x01
+enum ni_65xx_boardid {
+ BOARD_PCI6509,
+ BOARD_PXI6509,
+ BOARD_PCI6510,
+ BOARD_PCI6511,
+ BOARD_PXI6511,
+ BOARD_PCI6512,
+ BOARD_PXI6512,
+ BOARD_PCI6513,
+ BOARD_PXI6513,
+ BOARD_PCI6514,
+ BOARD_PXI6514,
+ BOARD_PCI6515,
+ BOARD_PXI6515,
+ BOARD_PCI6516,
+ BOARD_PCI6517,
+ BOARD_PCI6518,
+ BOARD_PCI6519,
+ BOARD_PCI6520,
+ BOARD_PCI6521,
+ BOARD_PXI6521,
+ BOARD_PCI6528,
+ BOARD_PXI6528,
+};
+
struct ni_65xx_board {
- int dev_id;
const char *name;
unsigned num_dio_ports;
unsigned num_di_ports;
@@ -122,130 +146,117 @@ struct ni_65xx_board {
};
static const struct ni_65xx_board ni_65xx_boards[] = {
- {
- .dev_id = 0x7085,
- .name = "pci-6509",
- .num_dio_ports = 12,
- .invert_outputs = 0},
- {
- .dev_id = 0x1710,
- .name = "pxi-6509",
- .num_dio_ports = 12,
- .invert_outputs = 0},
- {
- .dev_id = 0x7124,
- .name = "pci-6510",
- .num_di_ports = 4},
- {
- .dev_id = 0x70c3,
- .name = "pci-6511",
- .num_di_ports = 8},
- {
- .dev_id = 0x70d3,
- .name = "pxi-6511",
- .num_di_ports = 8},
- {
- .dev_id = 0x70cc,
- .name = "pci-6512",
- .num_do_ports = 8},
- {
- .dev_id = 0x70d2,
- .name = "pxi-6512",
- .num_do_ports = 8},
- {
- .dev_id = 0x70c8,
- .name = "pci-6513",
- .num_do_ports = 8,
- .invert_outputs = 1},
- {
- .dev_id = 0x70d1,
- .name = "pxi-6513",
- .num_do_ports = 8,
- .invert_outputs = 1},
- {
- .dev_id = 0x7088,
- .name = "pci-6514",
- .num_di_ports = 4,
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x70CD,
- .name = "pxi-6514",
- .num_di_ports = 4,
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x7087,
- .name = "pci-6515",
- .num_di_ports = 4,
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x70c9,
- .name = "pxi-6515",
- .num_di_ports = 4,
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x7125,
- .name = "pci-6516",
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x7126,
- .name = "pci-6517",
- .num_do_ports = 4,
- .invert_outputs = 1},
- {
- .dev_id = 0x7127,
- .name = "pci-6518",
- .num_di_ports = 2,
- .num_do_ports = 2,
- .invert_outputs = 1},
- {
- .dev_id = 0x7128,
- .name = "pci-6519",
- .num_di_ports = 2,
- .num_do_ports = 2,
- .invert_outputs = 1},
- {
- .dev_id = 0x71c5,
- .name = "pci-6520",
- .num_di_ports = 1,
- .num_do_ports = 1,
- },
- {
- .dev_id = 0x718b,
- .name = "pci-6521",
- .num_di_ports = 1,
- .num_do_ports = 1,
- },
- {
- .dev_id = 0x718c,
- .name = "pxi-6521",
- .num_di_ports = 1,
- .num_do_ports = 1,
- },
- {
- .dev_id = 0x70a9,
- .name = "pci-6528",
- .num_di_ports = 3,
- .num_do_ports = 3,
- },
- {
- .dev_id = 0x7086,
- .name = "pxi-6528",
- .num_di_ports = 3,
- .num_do_ports = 3,
- },
+ [BOARD_PCI6509] = {
+ .name = "pci-6509",
+ .num_dio_ports = 12,
+ },
+ [BOARD_PXI6509] = {
+ .name = "pxi-6509",
+ .num_dio_ports = 12,
+ },
+ [BOARD_PCI6510] = {
+ .name = "pci-6510",
+ .num_di_ports = 4,
+ },
+ [BOARD_PCI6511] = {
+ .name = "pci-6511",
+ .num_di_ports = 8,
+ },
+ [BOARD_PXI6511] = {
+ .name = "pxi-6511",
+ .num_di_ports = 8,
+ },
+ [BOARD_PCI6512] = {
+ .name = "pci-6512",
+ .num_do_ports = 8,
+ },
+ [BOARD_PXI6512] = {
+ .name = "pxi-6512",
+ .num_do_ports = 8,
+ },
+ [BOARD_PCI6513] = {
+ .name = "pci-6513",
+ .num_do_ports = 8,
+ .invert_outputs = 1,
+ },
+ [BOARD_PXI6513] = {
+ .name = "pxi-6513",
+ .num_do_ports = 8,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6514] = {
+ .name = "pci-6514",
+ .num_di_ports = 4,
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PXI6514] = {
+ .name = "pxi-6514",
+ .num_di_ports = 4,
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6515] = {
+ .name = "pci-6515",
+ .num_di_ports = 4,
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PXI6515] = {
+ .name = "pxi-6515",
+ .num_di_ports = 4,
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6516] = {
+ .name = "pci-6516",
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6517] = {
+ .name = "pci-6517",
+ .num_do_ports = 4,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6518] = {
+ .name = "pci-6518",
+ .num_di_ports = 2,
+ .num_do_ports = 2,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6519] = {
+ .name = "pci-6519",
+ .num_di_ports = 2,
+ .num_do_ports = 2,
+ .invert_outputs = 1,
+ },
+ [BOARD_PCI6520] = {
+ .name = "pci-6520",
+ .num_di_ports = 1,
+ .num_do_ports = 1,
+ },
+ [BOARD_PCI6521] = {
+ .name = "pci-6521",
+ .num_di_ports = 1,
+ .num_do_ports = 1,
+ },
+ [BOARD_PXI6521] = {
+ .name = "pxi-6521",
+ .num_di_ports = 1,
+ .num_do_ports = 1,
+ },
+ [BOARD_PCI6528] = {
+ .name = "pci-6528",
+ .num_di_ports = 3,
+ .num_do_ports = 3,
+ },
+ [BOARD_PXI6528] = {
+ .name = "pxi-6528",
+ .num_di_ports = 3,
+ .num_do_ports = 3,
+ },
};
-#define n_ni_65xx_boards ARRAY_SIZE(ni_65xx_boards)
-static inline const struct ni_65xx_board *board(struct comedi_device *dev)
-{
- return dev->board_ptr;
-}
-
static inline unsigned ni_65xx_port_by_channel(unsigned channel)
{
return channel / ni_65xx_channels_per_port;
@@ -257,34 +268,6 @@ static inline unsigned ni_65xx_total_num_ports(const struct ni_65xx_board
return board->num_dio_ports + board->num_di_ports + board->num_do_ports;
}
-static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1710)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7085)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7086)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7087)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7088)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70a9)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c3)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c8)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c9)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70cc)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70CD)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d1)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d2)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d3)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7124)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7125)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7126)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7127)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7128)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x718b)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x718c)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71c5)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table);
-
struct ni_65xx_private {
struct mite_struct *mite;
unsigned int filter_interval;
@@ -398,6 +381,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_65xx_board *board = comedi_board(dev);
struct ni_65xx_private *devpriv = dev->private;
unsigned base_bitfield_channel;
const unsigned max_ports_per_bitfield = 5;
@@ -413,7 +397,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
unsigned base_port_channel;
unsigned port_mask, port_data, port_read_bits;
int bitshift;
- if (port >= ni_65xx_total_num_ports(board(dev)))
+ if (port >= ni_65xx_total_num_ports(board))
break;
base_port_channel = port_offset * ni_65xx_channels_per_port;
port_mask = data[0];
@@ -436,7 +420,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
devpriv->output_bits[port] |=
port_data & port_mask;
bits = devpriv->output_bits[port];
- if (board(dev)->invert_outputs)
+ if (board->invert_outputs)
bits = ~bits;
writeb(bits,
devpriv->mite->daq_io_addr +
@@ -444,7 +428,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
}
port_read_bits =
readb(devpriv->mite->daq_io_addr + Port_Data(port));
- if (s->type == COMEDI_SUBD_DO && board(dev)->invert_outputs) {
+ if (s->type == COMEDI_SUBD_DO && board->invert_outputs) {
/* Outputs inverted, so invert value read back from
* DO subdevice. (Does not apply to boards with DIO
* subdevice.) */
@@ -599,38 +583,32 @@ static int ni_65xx_intr_insn_config(struct comedi_device *dev,
return 2;
}
-static const struct ni_65xx_board *
-ni_65xx_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int dev_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(ni_65xx_boards); n++) {
- const struct ni_65xx_board *board = &ni_65xx_boards[n];
- if (board->dev_id == dev_id)
- return board;
- }
- return NULL;
-}
-
static int ni_65xx_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct ni_65xx_board *board = NULL;
struct ni_65xx_private *devpriv;
struct comedi_subdevice *s;
unsigned i;
int ret;
+ if (context < ARRAY_SIZE(ni_65xx_boards))
+ board = &ni_65xx_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- dev->board_ptr = ni_65xx_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
-
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
@@ -641,7 +619,6 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
return ret;
}
- dev->board_name = board(dev)->name;
dev->irq = mite_irq(devpriv->mite);
dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name,
readb(devpriv->mite->daq_io_addr + ID_Register));
@@ -651,11 +628,11 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
return ret;
s = &dev->subdevices[0];
- if (board(dev)->num_di_ports) {
+ if (board->num_di_ports) {
s->type = COMEDI_SUBD_DI;
s->subdev_flags = SDF_READABLE;
s->n_chan =
- board(dev)->num_di_ports * ni_65xx_channels_per_port;
+ board->num_di_ports * ni_65xx_channels_per_port;
s->range_table = &range_digital;
s->maxdata = 1;
s->insn_config = ni_65xx_dio_insn_config;
@@ -669,28 +646,28 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
}
s = &dev->subdevices[1];
- if (board(dev)->num_do_ports) {
+ if (board->num_do_ports) {
s->type = COMEDI_SUBD_DO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
s->n_chan =
- board(dev)->num_do_ports * ni_65xx_channels_per_port;
+ board->num_do_ports * ni_65xx_channels_per_port;
s->range_table = &range_digital;
s->maxdata = 1;
s->insn_bits = ni_65xx_dio_insn_bits;
s->private = ni_65xx_alloc_subdevice_private();
if (s->private == NULL)
return -ENOMEM;
- sprivate(s)->base_port = board(dev)->num_di_ports;
+ sprivate(s)->base_port = board->num_di_ports;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
s = &dev->subdevices[2];
- if (board(dev)->num_dio_ports) {
+ if (board->num_dio_ports) {
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
s->n_chan =
- board(dev)->num_dio_ports * ni_65xx_channels_per_port;
+ board->num_dio_ports * ni_65xx_channels_per_port;
s->range_table = &range_digital;
s->maxdata = 1;
s->insn_config = ni_65xx_dio_insn_config;
@@ -699,7 +676,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
if (s->private == NULL)
return -ENOMEM;
sprivate(s)->base_port = 0;
- for (i = 0; i < board(dev)->num_dio_ports; ++i) {
+ for (i = 0; i < board->num_dio_ports; ++i) {
/* configure all ports for input */
writeb(0x1,
devpriv->mite->daq_io_addr +
@@ -722,10 +699,10 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
s->insn_bits = ni_65xx_intr_insn_bits;
s->insn_config = ni_65xx_intr_insn_config;
- for (i = 0; i < ni_65xx_total_num_ports(board(dev)); ++i) {
+ for (i = 0; i < ni_65xx_total_num_ports(board); ++i) {
writeb(0x00,
devpriv->mite->daq_io_addr + Filter_Enable(i));
- if (board(dev)->invert_outputs)
+ if (board->invert_outputs)
writeb(0x01,
devpriv->mite->daq_io_addr + Port_Data(i));
else
@@ -753,6 +730,7 @@ static int ni_65xx_auto_attach(struct comedi_device *dev,
static void ni_65xx_detach(struct comedi_device *dev)
{
struct ni_65xx_private *devpriv = dev->private;
+ int i;
if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) {
writeb(0x00,
@@ -761,20 +739,15 @@ static void ni_65xx_detach(struct comedi_device *dev)
}
if (dev->irq)
free_irq(dev->irq, dev);
+ for (i = 0; i < dev->n_subdevices; ++i)
+ comedi_spriv_free(dev, i);
if (devpriv) {
- struct comedi_subdevice *s;
- unsigned i;
-
- for (i = 0; i < dev->n_subdevices; ++i) {
- s = &dev->subdevices[i];
- kfree(s->private);
- s->private = NULL;
- }
if (devpriv->mite) {
mite_unsetup(devpriv->mite);
mite_free(devpriv->mite);
}
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver ni_65xx_driver = {
@@ -785,15 +758,42 @@ static struct comedi_driver ni_65xx_driver = {
};
static int ni_65xx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni_65xx_driver);
+ return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data);
}
+static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = {
+ { PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 },
+ { PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 },
+ { PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 },
+ { PCI_VDEVICE(NI, 0x7087), BOARD_PCI6515 },
+ { PCI_VDEVICE(NI, 0x7088), BOARD_PCI6514 },
+ { PCI_VDEVICE(NI, 0x70a9), BOARD_PCI6528 },
+ { PCI_VDEVICE(NI, 0x70c3), BOARD_PCI6511 },
+ { PCI_VDEVICE(NI, 0x70c8), BOARD_PCI6513 },
+ { PCI_VDEVICE(NI, 0x70c9), BOARD_PXI6515 },
+ { PCI_VDEVICE(NI, 0x70cc), BOARD_PCI6512 },
+ { PCI_VDEVICE(NI, 0x70cd), BOARD_PXI6514 },
+ { PCI_VDEVICE(NI, 0x70d1), BOARD_PXI6513 },
+ { PCI_VDEVICE(NI, 0x70d2), BOARD_PXI6512 },
+ { PCI_VDEVICE(NI, 0x70d3), BOARD_PXI6511 },
+ { PCI_VDEVICE(NI, 0x7124), BOARD_PCI6510 },
+ { PCI_VDEVICE(NI, 0x7125), BOARD_PCI6516 },
+ { PCI_VDEVICE(NI, 0x7126), BOARD_PCI6517 },
+ { PCI_VDEVICE(NI, 0x7127), BOARD_PCI6518 },
+ { PCI_VDEVICE(NI, 0x7128), BOARD_PCI6519 },
+ { PCI_VDEVICE(NI, 0x718b), BOARD_PCI6521 },
+ { PCI_VDEVICE(NI, 0x718c), BOARD_PXI6521 },
+ { PCI_VDEVICE(NI, 0x71c5), BOARD_PCI6520 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table);
+
static struct pci_driver ni_65xx_pci_driver = {
- .name = "ni_65xx",
- .id_table = ni_65xx_pci_table,
- .probe = ni_65xx_pci_probe,
+ .name = "ni_65xx",
+ .id_table = ni_65xx_pci_table,
+ .probe = ni_65xx_pci_probe,
.remove = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver);
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index e46dd7a1a724..5cdda7fe97a7 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -18,27 +18,25 @@
*/
/*
-Driver: ni_660x
-Description: National Instruments 660x counter/timer boards
-Devices:
-[National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602,
- PXI-6608
-Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
- Herman.Bruyninckx@mech.kuleuven.ac.be,
- Wim.Meeussen@mech.kuleuven.ac.be,
- Klaas.Gadeyne@mech.kuleuven.ac.be,
- Frank Mori Hess <fmhess@users.sourceforge.net>
-Updated: Thu Oct 18 12:56:06 EDT 2007
-Status: experimental
-
-Encoders work. PulseGeneration (both single pulse and pulse train)
-works. Buffered commands work for input but not output.
-
-References:
-DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
-DAQ 6601/6602 User Manual (NI 322137B-01)
-
-*/
+ * Driver: ni_660x
+ * Description: National Instruments 660x counter/timer boards
+ * Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602,
+ * PXI-6608, PXI-6624
+ * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
+ * Herman.Bruyninckx@mech.kuleuven.ac.be,
+ * Wim.Meeussen@mech.kuleuven.ac.be,
+ * Klaas.Gadeyne@mech.kuleuven.ac.be,
+ * Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Updated: Fri, 15 Mar 2013 10:47:56 +0000
+ * Status: experimental
+ *
+ * Encoders work. PulseGeneration (both single pulse and pulse train)
+ * works. Buffered commands work for input but not output.
+ *
+ * References:
+ * DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
+ * DAQ 6601/6602 User Manual (NI 322137B-01)
+ */
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -389,34 +387,40 @@ enum global_interrupt_config_register_bits {
/* First chip is at base-address + 0x00, etc. */
static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 };
-/* Board description*/
+enum ni_660x_boardid {
+ BOARD_PCI6601,
+ BOARD_PCI6602,
+ BOARD_PXI6602,
+ BOARD_PXI6608,
+ BOARD_PXI6624
+};
+
struct ni_660x_board {
- unsigned short dev_id; /* `lspci` will show you this */
const char *name;
unsigned n_chips; /* total number of TIO chips */
};
static const struct ni_660x_board ni_660x_boards[] = {
- {
- .dev_id = 0x2c60,
- .name = "PCI-6601",
- .n_chips = 1,
- },
- {
- .dev_id = 0x1310,
- .name = "PCI-6602",
- .n_chips = 2,
- },
- {
- .dev_id = 0x1360,
- .name = "PXI-6602",
- .n_chips = 2,
- },
- {
- .dev_id = 0x2cc0,
- .name = "PXI-6608",
- .n_chips = 2,
- },
+ [BOARD_PCI6601] = {
+ .name = "PCI-6601",
+ .n_chips = 1,
+ },
+ [BOARD_PCI6602] = {
+ .name = "PCI-6602",
+ .n_chips = 2,
+ },
+ [BOARD_PXI6602] = {
+ .name = "PXI-6602",
+ .n_chips = 2,
+ },
+ [BOARD_PXI6608] = {
+ .name = "PXI-6608",
+ .n_chips = 2,
+ },
+ [BOARD_PXI6624] = {
+ .name = "PXI-6624",
+ .n_chips = 2,
+ },
};
#define NI_660X_MAX_NUM_CHIPS 2
@@ -883,7 +887,7 @@ static irqreturn_t ni_660x_interrupt(int irq, void *d)
unsigned i;
unsigned long flags;
- if (dev->attached == 0)
+ if (!dev->attached)
return IRQ_NONE;
/* lock to avoid race with comedi_poll */
spin_lock_irqsave(&devpriv->interrupt_lock, flags);
@@ -974,20 +978,6 @@ static void ni_660x_free_mite_rings(struct comedi_device *dev)
}
}
-static const struct ni_660x_board *
-ni_660x_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int dev_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(ni_660x_boards); n++) {
- const struct ni_660x_board *board = &ni_660x_boards[n];
- if (board->dev_id == dev_id)
- return board;
- }
- return NULL;
-}
-
static int
ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -1170,32 +1160,36 @@ static int ni_660x_dio_insn_config(struct comedi_device *dev,
}
static int ni_660x_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct ni_660x_board *board;
+ const struct ni_660x_board *board = NULL;
struct ni_660x_private *devpriv;
struct comedi_subdevice *s;
int ret;
unsigned i;
unsigned global_interrupt_config_bits;
+ if (context < ARRAY_SIZE(ni_660x_boards))
+ board = &ni_660x_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
ret = ni_660x_allocate_private(dev);
if (ret < 0)
return ret;
devpriv = dev->private;
- dev->board_ptr = ni_660x_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
- board = comedi_board(dev);
-
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
- dev->board_name = board->name;
-
ret = mite_setup2(devpriv->mite, 1);
if (ret < 0) {
dev_warn(dev->class_dev, "error setting up mite\n");
@@ -1315,6 +1309,7 @@ static void ni_660x_detach(struct comedi_device *dev)
mite_free(devpriv->mite);
}
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver ni_660x_driver = {
@@ -1325,17 +1320,18 @@ static struct comedi_driver ni_660x_driver = {
};
static int ni_660x_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni_660x_driver);
+ return comedi_pci_auto_config(dev, &ni_660x_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c60)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1310)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1360)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2cc0)},
- {0}
+ { PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 },
+ { PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 },
+ { PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 },
+ { PCI_VDEVICE(NI, 0x2cc0), BOARD_PXI6608 },
+ { PCI_VDEVICE(NI, 0x1e40), BOARD_PXI6624 },
+ { 0 }
};
MODULE_DEVICE_TABLE(pci, ni_660x_pci_table);
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index 2faf86c83dc5..42ab6dbf9d39 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -60,26 +60,28 @@ Commands are not supported.
#define MISC_STATUS_OFFSET 0x14
#define MISC_CONTROL_OFFSET 0x14
-/* Board description*/
+enum ni_670x_boardid {
+ BOARD_PCI6703,
+ BOARD_PXI6704,
+ BOARD_PCI6704,
+};
struct ni_670x_board {
const char *name;
- unsigned short dev_id;
unsigned short ao_chans;
};
static const struct ni_670x_board ni_670x_boards[] = {
- {
+ [BOARD_PCI6703] = {
.name = "PCI-6703",
- .dev_id = 0x2c90,
.ao_chans = 16,
- }, {
+ },
+ [BOARD_PXI6704] = {
.name = "PXI-6704",
- .dev_id = 0x1920,
.ao_chans = 32,
- }, {
+ },
+ [BOARD_PCI6704] = {
.name = "PCI-6704",
- .dev_id = 0x1290,
.ao_chans = 32,
},
};
@@ -92,8 +94,6 @@ struct ni_670x_private {
unsigned int ao_readback[32];
};
-static struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
-
static int ni_670x_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -189,49 +189,41 @@ static int ni_670x_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
-static const struct ni_670x_board *
-ni_670x_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int dev_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(ni_670x_boards); n++) {
- const struct ni_670x_board *board = &ni_670x_boards[n];
- if (board->dev_id == dev_id)
- return board;
- }
- return NULL;
-}
-
static int ni_670x_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct ni_670x_board *thisboard;
+ const struct ni_670x_board *thisboard = NULL;
struct ni_670x_private *devpriv;
struct comedi_subdevice *s;
int ret;
int i;
+ if (context < ARRAY_SIZE(ni_670x_boards))
+ thisboard = &ni_670x_boards[context];
+ if (!thisboard)
+ return -ENODEV;
+ dev->board_ptr = thisboard;
+ dev->board_name = thisboard->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- dev->board_ptr = ni_670x_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
- thisboard = comedi_board(dev);
ret = mite_setup(devpriv->mite);
if (ret < 0) {
dev_warn(dev->class_dev, "error setting up mite\n");
return ret;
}
- dev->board_name = thisboard->name;
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
@@ -296,6 +288,7 @@ static void ni_670x_detach(struct comedi_device *dev)
mite_unsetup(devpriv->mite);
mite_free(devpriv->mite);
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver ni_670x_driver = {
@@ -306,14 +299,15 @@ static struct comedi_driver ni_670x_driver = {
};
static int ni_670x_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni_670x_driver);
+ return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c90) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1920) },
+ { PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 },
+ { PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 },
+ { PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ni_670x_pci_table);
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 06de25bb2f56..2d375168f36d 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -154,11 +154,6 @@ static const struct a2150_board a2150_boards[] = {
},
};
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct a2150_board *)dev->board_ptr)
-
struct a2150_private {
volatile unsigned int count; /* number of data points left to be taken */
@@ -204,7 +199,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
short dpnt;
static const int sample_size = sizeof(devpriv->dma_buffer[0]);
- if (dev->attached == 0) {
+ if (!dev->attached) {
comedi_error(dev, "premature interrupt");
return IRQ_HANDLED;
}
@@ -319,6 +314,7 @@ static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static int a2150_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
+ const struct a2150_board *thisboard = comedi_board(dev);
int err = 0;
int tmp;
int startChan;
@@ -604,6 +600,7 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
int flags)
{
+ const struct a2150_board *thisboard = comedi_board(dev);
struct a2150_private *devpriv = dev->private;
int lub, glb, temp;
int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index;
@@ -719,45 +716,23 @@ static int a2150_probe(struct comedi_device *dev)
static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
+ const struct a2150_board *thisboard = comedi_board(dev);
struct a2150_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase = it->options[0];
unsigned int irq = it->options[1];
unsigned int dma = it->options[2];
static const int timeout = 2000;
int i;
int ret;
- printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
- iobase);
- if (irq) {
- printk(", irq %u", irq);
- } else {
- printk(", no irq");
- }
- if (dma) {
- printk(", dma %u", dma);
- } else {
- printk(", no dma");
- }
- printk("\n");
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- if (iobase == 0) {
- printk(" io base address required\n");
- return -EINVAL;
- }
-
- /* check if io addresses are available */
- if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], A2150_SIZE);
+ if (ret)
+ return ret;
/* grab our IRQ */
if (irq) {
@@ -797,6 +772,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
dev->board_ptr = a2150_boards + a2150_probe(dev);
+ thisboard = comedi_board(dev);
dev->board_name = thisboard->name;
ret = comedi_alloc_subdevices(dev, 1);
@@ -851,17 +827,14 @@ static void a2150_detach(struct comedi_device *dev)
{
struct a2150_private *devpriv = dev->private;
- if (dev->iobase) {
+ if (dev->iobase)
outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
- release_region(dev->iobase, A2150_SIZE);
- }
- if (dev->irq)
- free_irq(dev->irq, dev);
if (devpriv) {
if (devpriv->dma)
free_dma(devpriv->dma);
kfree(devpriv->dma_buffer);
}
+ comedi_legacy_detach(dev);
};
static struct comedi_driver ni_at_a2150_driver = {
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 907f65cdbdc0..7e5783a4f4e7 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -337,24 +337,14 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct atao_board *board = comedi_board(dev);
struct atao_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
int ao_unipolar;
int ret;
- iobase = it->options[0];
- if (iobase == 0)
- iobase = 0x1c0;
ao_unipolar = it->options[3];
- printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
-
- if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], ATAO_SIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -409,12 +399,6 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void atao_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, ATAO_SIZE);
-}
-
static const struct atao_board atao_boards[] = {
{
.name = "ai-ao-6",
@@ -429,7 +413,7 @@ static struct comedi_driver ni_at_ao_driver = {
.driver_name = "ni_at_ao",
.module = THIS_MODULE,
.attach = atao_attach,
- .detach = atao_detach,
+ .detach = comedi_legacy_detach,
.board_name = &atao_boards[0].name,
.offset = sizeof(struct atao_board),
.num_names = ARRAY_SIZE(atao_boards),
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 2cc29965e157..4ced7ba119b0 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -350,7 +350,7 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
struct pnp_dev *isapnp_dev = NULL;
int i;
- for (i = 0; i < n_ni_boards; i++) {
+ for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
isapnp_dev = pnp_find_dev(NULL,
ISAPNP_VENDOR('N', 'I', 'C'),
ISAPNP_FUNCTION(ni_boards[i].
@@ -377,7 +377,7 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
}
break;
}
- if (i == n_ni_boards)
+ if (i == ARRAY_SIZE(ni_boards))
return -ENODEV;
*dev = isapnp_dev;
return 0;
@@ -388,7 +388,7 @@ static int ni_getboardtype(struct comedi_device *dev)
int device_id = ni_read_eeprom(dev, 511);
int i;
- for (i = 0; i < n_ni_boards; i++) {
+ for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
if (ni_boards[i].device_id == device_id)
return i;
@@ -406,6 +406,7 @@ static int ni_getboardtype(struct comedi_device *dev)
static int ni_atmio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
+ const struct ni_board_struct *boardtype;
struct ni_private *devpriv;
struct pnp_dev *isapnp_dev;
int ret;
@@ -436,15 +437,9 @@ static int ni_atmio_attach(struct comedi_device *dev,
devpriv->isapnp_dev = isapnp_dev;
}
- /* reserve our I/O region */
-
- printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase);
- if (!request_region(iobase, NI_SIZE, "ni_atmio")) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, iobase, NI_SIZE);
+ if (ret)
+ return ret;
#ifdef DEBUG
/* board existence sanity check */
@@ -466,9 +461,10 @@ static int ni_atmio_attach(struct comedi_device *dev,
return -EIO;
dev->board_ptr = ni_boards + board;
+ boardtype = comedi_board(dev);
- printk(" %s", boardtype.name);
- dev->board_name = boardtype.name;
+ printk(" %s", boardtype->name);
+ dev->board_name = boardtype->name;
/* irq stuff */
@@ -503,10 +499,7 @@ static void ni_atmio_detach(struct comedi_device *dev)
struct ni_private *devpriv = dev->private;
mio_common_detach(dev);
- if (dev->iobase)
- release_region(dev->iobase, NI_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
+ comedi_legacy_detach(dev);
if (devpriv->isapnp_dev)
pnp_device_detach(devpriv->isapnp_dev);
}
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 4a17494f55ed..6c97a0925aad 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -638,22 +638,13 @@ static int atmio16d_attach(struct comedi_device *dev,
{
const struct atmio16_board_t *board = comedi_board(dev);
struct atmio16d_private *devpriv;
+ struct comedi_subdevice *s;
unsigned int irq;
- unsigned long iobase;
int ret;
- struct comedi_subdevice *s;
-
- /* make sure the address range is free and allocate it */
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: atmio16d: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], ATMIO16D_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -776,18 +767,9 @@ static int atmio16d_attach(struct comedi_device *dev,
static void atmio16d_detach(struct comedi_device *dev)
{
- const struct atmio16_board_t *board = comedi_board(dev);
- struct comedi_subdevice *s;
-
- if (dev->subdevices && board->has_8255) {
- s = &dev->subdevices[3];
- subdev_8255_cleanup(dev, s);
- }
- if (dev->irq)
- free_irq(dev->irq, dev);
+ comedi_spriv_free(dev, 3);
reset_atmio16d(dev);
- if (dev->iobase)
- release_region(dev->iobase, ATMIO16D_SIZE);
+ comedi_legacy_detach(dev);
}
static const struct atmio16_board_t atmio16_boards[] = {
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 9cc6092eacdd..d067ef70e194 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -202,8 +202,6 @@ static int daq700_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
link->config_flags |= CONF_AUTO_SET_IO;
ret = comedi_pcmcia_enable(dev, NULL);
if (ret)
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index e1cc9d01f200..9b7805fda932 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -52,8 +52,6 @@ static int dio24_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
link->config_flags |= CONF_AUTO_SET_IO;
ret = comedi_pcmcia_enable(dev, NULL);
if (ret)
@@ -75,8 +73,7 @@ static int dio24_auto_attach(struct comedi_device *dev,
static void dio24_detach(struct comedi_device *dev)
{
- if (dev->subdevices)
- subdev_8255_cleanup(dev, &dev->subdevices[0]);
+ comedi_spriv_free(dev, 0);
comedi_pcmcia_disable(dev);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index f957b8859b3d..3d978f34d212 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -1,79 +1,66 @@
/*
- comedi/drivers/ni_labpc.c
- Driver for National Instruments Lab-PC series boards and compatibles
- Copyright (C) 2001, 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-************************************************************************
-*/
-/*
-Driver: ni_labpc
-Description: National Instruments Lab-PC (& compatibles)
-Author: Frank Mori Hess <fmhess@users.sourceforge.net>
-Devices: [National Instruments] Lab-PC-1200 (labpc-1200),
- Lab-PC-1200AI (labpc-1200ai), Lab-PC+ (lab-pc+), PCI-1200 (ni_labpc)
-Status: works
-
-Tested with lab-pc-1200. For the older Lab-PC+, not all input ranges
-and analog references will work, the available ranges/arefs will
-depend on how you have configured the jumpers on your board
-(see your owner's manual).
-
-Kernel-level ISA plug-and-play support for the lab-pc-1200
-boards has not
-yet been added to the driver, mainly due to the fact that
-I don't know the device id numbers. If you have one
-of these boards,
-please file a bug report at http://comedi.org/
-so I can get the necessary information from you.
-
-The 1200 series boards have onboard calibration dacs for correcting
-analog input/output offsets and gains. The proper settings for these
-caldacs are stored on the board's eeprom. To read the caldac values
-from the eeprom and store them into a file that can be then be used by
-comedilib, use the comedi_calibrate program.
-
-Configuration options - ISA boards:
- [0] - I/O port base address
- [1] - IRQ (optional, required for timed or externally triggered conversions)
- [2] - DMA channel (optional)
-
-Configuration options - PCI boards:
- [0] - bus (optional)
- [1] - slot (optional)
-
-The Lab-pc+ has quirky chanlist requirements
-when scanning multiple channels. Multiple channel scan
-sequence must start at highest channel, then decrement down to
-channel 0. The rest of the cards can scan down like lab-pc+ or scan
-up from channel zero. Chanlists consisting of all one channel
-are also legal, and allow you to pace conversions in bursts.
-
-*/
+ * comedi/drivers/ni_labpc.c
+ * Driver for National Instruments Lab-PC series boards and compatibles
+ * Copyright (C) 2001-2003 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
/*
+ * Driver: ni_labpc
+ * Description: National Instruments Lab-PC (& compatibles)
+ * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200]
+ * (National Instruments) Lab-PC-1200AI [lab-pc-1200ai]
+ * (National Instruments) Lab-PC+ [lab-pc+]
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Status: works
+ *
+ * Configuration options - ISA boards:
+ * [0] - I/O port base address
+ * [1] - IRQ (optional, required for timed or externally triggered
+ * conversions)
+ * [2] - DMA channel (optional)
+ *
+ * Tested with lab-pc-1200. For the older Lab-PC+, not all input
+ * ranges and analog references will work, the available ranges/arefs
+ * will depend on how you have configured the jumpers on your board
+ * (see your owner's manual).
+ *
+ * Kernel-level ISA plug-and-play support for the lab-pc-1200 boards
+ * has not yet been added to the driver, mainly due to the fact that
+ * I don't know the device id numbers. If you have one of these boards,
+ * please file a bug report at http://comedi.org/ so I can get the
+ * necessary information from you.
+ *
+ * The 1200 series boards have onboard calibration dacs for correcting
+ * analog input/output offsets and gains. The proper settings for these
+ * caldacs are stored on the board's eeprom. To read the caldac values
+ * from the eeprom and store them into a file that can be then be used
+ * by comedilib, use the comedi_calibrate program.
+ *
+ * The Lab-pc+ has quirky chanlist requirements when scanning multiple
+ * channels. Multiple channel scan sequence must start at highest channel,
+ * then decrement down to channel 0. The rest of the cards can scan down
+ * like lab-pc+ or scan up from channel zero. Chanlists consisting of all
+ * one channel are also legal, and allow you to pace conversions in bursts.
+ *
+ * NI manuals:
+ * 341309a (labpc-1200 register manual)
+ * 320502b (lab-pc+)
+ */
-NI manuals:
-341309a (labpc-1200 register manual)
-340914a (pci-1200)
-320502b (lab-pc+)
-
-*/
-
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
@@ -85,128 +72,79 @@ NI manuals:
#include "8253.h"
#include "8255.h"
-#include "mite.h"
#include "comedi_fc.h"
#include "ni_labpc.h"
-#define DRV_NAME "ni_labpc"
-
-/* size of io region used by board */
-#define LABPC_SIZE 32
-/* 2 MHz master clock */
-#define LABPC_TIMER_BASE 500
-
-/* Registers for the lab-pc+ */
-
-/* write-only registers */
-#define COMMAND1_REG 0x0
-#define ADC_GAIN_MASK (0x7 << 4)
-#define ADC_CHAN_BITS(x) ((x) & 0x7)
-/* enables multi channel scans */
-#define ADC_SCAN_EN_BIT 0x80
-#define COMMAND2_REG 0x1
-/* enable pretriggering (used in conjunction with SWTRIG) */
-#define PRETRIG_BIT 0x1
-/* enable paced conversions on external trigger */
-#define HWTRIG_BIT 0x2
-/* enable paced conversions */
-#define SWTRIG_BIT 0x4
-/* use two cascaded counters for pacing */
-#define CASCADE_BIT 0x8
-#define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1))
-#define COMMAND3_REG 0x2
-/* enable dma transfers */
-#define DMA_EN_BIT 0x1
-/* enable interrupts for 8255 */
-#define DIO_INTR_EN_BIT 0x2
-/* enable dma terminal count interrupt */
-#define DMATC_INTR_EN_BIT 0x4
-/* enable timer interrupt */
-#define TIMER_INTR_EN_BIT 0x8
-/* enable error interrupt */
-#define ERR_INTR_EN_BIT 0x10
-/* enable fifo not empty interrupt */
-#define ADC_FNE_INTR_EN_BIT 0x20
-#define ADC_CONVERT_REG 0x3
-#define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1))
-#define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1))
-#define ADC_CLEAR_REG 0x8
-#define DMATC_CLEAR_REG 0xa
-#define TIMER_CLEAR_REG 0xc
-/* 1200 boards only */
-#define COMMAND6_REG 0xe
-/* select ground or common-mode reference */
-#define ADC_COMMON_BIT 0x1
-/* adc unipolar */
-#define ADC_UNIP_BIT 0x2
-/* dac unipolar */
-#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1))
-/* enable fifo half full interrupt */
-#define ADC_FHF_INTR_EN_BIT 0x20
-/* enable interrupt on end of hardware count */
-#define A1_INTR_EN_BIT 0x40
-/* scan up from channel zero instead of down to zero */
-#define ADC_SCAN_UP_BIT 0x80
-#define COMMAND4_REG 0xf
-/* enables 'interval' scanning */
-#define INTERVAL_SCAN_EN_BIT 0x1
-/* enables external signal on counter b1 output to trigger scan */
-#define EXT_SCAN_EN_BIT 0x2
-/* chooses direction (output or input) for EXTCONV* line */
-#define EXT_CONVERT_OUT_BIT 0x4
-/* chooses differential inputs for adc (in conjunction with board jumper) */
-#define ADC_DIFF_BIT 0x8
-#define EXT_CONVERT_DISABLE_BIT 0x10
-/* 1200 boards only, calibration stuff */
-#define COMMAND5_REG 0x1c
-/* enable eeprom for write */
-#define EEPROM_WRITE_UNPROTECT_BIT 0x4
-/* enable dithering */
-#define DITHER_EN_BIT 0x8
-/* load calibration dac */
-#define CALDAC_LOAD_BIT 0x10
-/* serial clock - rising edge writes, falling edge reads */
-#define SCLOCK_BIT 0x20
-/* serial data bit for writing to eeprom or calibration dacs */
-#define SDATA_BIT 0x40
-/* enable eeprom for read/write */
-#define EEPROM_EN_BIT 0x80
-#define INTERVAL_COUNT_REG 0x1e
-#define INTERVAL_LOAD_REG 0x1f
-#define INTERVAL_LOAD_BITS 0x1
-
-/* read-only registers */
-#define STATUS1_REG 0x0
-/* data is available in fifo */
-#define DATA_AVAIL_BIT 0x1
-/* overrun has occurred */
-#define OVERRUN_BIT 0x2
-/* fifo overflow */
-#define OVERFLOW_BIT 0x4
-/* timer interrupt has occurred */
-#define TIMER_BIT 0x8
-/* dma terminal count has occurred */
-#define DMATC_BIT 0x10
-/* external trigger has occurred */
-#define EXT_TRIG_BIT 0x40
-/* 1200 boards only */
-#define STATUS2_REG 0x1d
-/* programmable eeprom serial output */
-#define EEPROM_OUT_BIT 0x1
-/* counter A1 terminal count */
-#define A1_TC_BIT 0x2
-/* fifo not half full */
-#define FNHF_BIT 0x4
-#define ADC_FIFO_REG 0xa
-
-#define DIO_BASE_REG 0x10
-#define COUNTER_A_BASE_REG 0x14
-#define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3)
-/* check modes put conversion pacer output in harmless state (a0 mode 2) */
-#define INIT_A0_BITS 0x14
-/* put hardware conversion counter output in harmless state (a1 mode 0) */
-#define INIT_A1_BITS 0x70
-#define COUNTER_B_BASE_REG 0x18
+/*
+ * Register map (all registers are 8-bit)
+ */
+#define STAT1_REG 0x00 /* R: Status 1 reg */
+#define STAT1_DAVAIL (1 << 0)
+#define STAT1_OVERRUN (1 << 1)
+#define STAT1_OVERFLOW (1 << 2)
+#define STAT1_CNTINT (1 << 3)
+#define STAT1_GATA0 (1 << 5)
+#define STAT1_EXTGATA0 (1 << 6)
+#define CMD1_REG 0x00 /* W: Command 1 reg */
+#define CMD1_MA(x) (((x) & 0x7) << 0)
+#define CMD1_TWOSCMP (1 << 3)
+#define CMD1_GAIN_MASK (7 << 4)
+#define CMD1_SCANEN (1 << 7)
+#define CMD2_REG 0x01 /* W: Command 2 reg */
+#define CMD2_PRETRIG (1 << 0)
+#define CMD2_HWTRIG (1 << 1)
+#define CMD2_SWTRIG (1 << 2)
+#define CMD2_TBSEL (1 << 3)
+#define CMD2_2SDAC0 (1 << 4)
+#define CMD2_2SDAC1 (1 << 5)
+#define CMD2_LDAC(x) (1 << (6 + (x)))
+#define CMD3_REG 0x02 /* W: Command 3 reg */
+#define CMD3_DMAEN (1 << 0)
+#define CMD3_DIOINTEN (1 << 1)
+#define CMD3_DMATCINTEN (1 << 2)
+#define CMD3_CNTINTEN (1 << 3)
+#define CMD3_ERRINTEN (1 << 4)
+#define CMD3_FIFOINTEN (1 << 5)
+#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */
+#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */
+#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */
+#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */
+#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */
+#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */
+#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */
+#define CMD6_REG 0x0e /* W: Command 6 reg */
+#define CMD6_NRSE (1 << 0)
+#define CMD6_ADCUNI (1 << 1)
+#define CMD6_DACUNI(x) (1 << (2 + (x)))
+#define CMD6_HFINTEN (1 << 5)
+#define CMD6_DQINTEN (1 << 6)
+#define CMD6_SCANUP (1 << 7)
+#define CMD4_REG 0x0f /* W: Command 3 reg */
+#define CMD4_INTSCAN (1 << 0)
+#define CMD4_EOIRCV (1 << 1)
+#define CMD4_ECLKDRV (1 << 2)
+#define CMD4_SEDIFF (1 << 3)
+#define CMD4_ECLKRCV (1 << 4)
+#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */
+#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */
+#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */
+#define CMD5_REG 0x1c /* W: Command 5 reg */
+#define CMD5_WRTPRT (1 << 2)
+#define CMD5_DITHEREN (1 << 3)
+#define CMD5_CALDACLD (1 << 4)
+#define CMD5_SCLK (1 << 5)
+#define CMD5_SDATA (1 << 6)
+#define CMD5_EEPROMCS (1 << 7)
+#define STAT2_REG 0x1d /* R: Status 2 reg */
+#define STAT2_PROMOUT (1 << 0)
+#define STAT2_OUTA1 (1 << 1)
+#define STAT2_FIFONHF (1 << 2)
+#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */
+#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */
+
+#define LABPC_SIZE 0x20 /* size of ISA io region */
+#define LABPC_TIMER_BASE 500 /* 2 MHz master clock */
+#define LABPC_ADC_TIMEOUT 1000
enum scan_mode {
MODE_SINGLE_CHAN,
@@ -215,187 +153,63 @@ enum scan_mode {
MODE_MULT_CHAN_DOWN,
};
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t labpc_interrupt(int irq, void *d);
-static int labpc_drain_fifo(struct comedi_device *dev);
-#ifdef CONFIG_ISA_DMA_API
-static void labpc_drain_dma(struct comedi_device *dev);
-static void handle_isa_dma(struct comedi_device *dev);
-#endif
-static void labpc_drain_dregs(struct comedi_device *dev);
-static int labpc_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode scan_mode);
-#ifdef CONFIG_ISA_DMA_API
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd);
-#endif
-static int labpc_dio_mem_callback(int dir, int port, int data,
- unsigned long arg);
-static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
- unsigned int num_bits);
-static unsigned int labpc_serial_in(struct comedi_device *dev);
-static unsigned int labpc_eeprom_read(struct comedi_device *dev,
- unsigned int address);
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev);
-static int labpc_eeprom_write(struct comedi_device *dev,
- unsigned int address,
- unsigned int value);
-static void write_caldac(struct comedi_device *dev, unsigned int channel,
- unsigned int value);
-
-/* analog input ranges */
-#define NUM_LABPC_PLUS_AI_RANGES 16
-/* indicates unipolar ranges */
-static const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
-};
-
-/* map range index to gain bits */
-static const int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] = {
- 0x00,
- 0x10,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
- 0x00,
- 0x10,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
+static const int labpc_plus_ai_gain_bits[] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
};
static const struct comedi_lrange range_labpc_plus_ai = {
- NUM_LABPC_PLUS_AI_RANGES,
- {
- BIP_RANGE(5),
- BIP_RANGE(4),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(8),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 16, {
+ BIP_RANGE(5),
+ BIP_RANGE(4),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(8),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
-#define NUM_LABPC_1200_AI_RANGES 14
-/* indicates unipolar ranges */
-const int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = {
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
-};
-EXPORT_SYMBOL_GPL(labpc_1200_is_unipolar);
-
-/* map range index to gain bits */
-const int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] = {
- 0x00,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
- 0x00,
- 0x20,
- 0x30,
- 0x40,
- 0x50,
- 0x60,
- 0x70,
+const int labpc_1200_ai_gain_bits[] = {
+ 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x00, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
};
EXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits);
const struct comedi_lrange range_labpc_1200_ai = {
- NUM_LABPC_1200_AI_RANGES,
- {
- BIP_RANGE(5),
- BIP_RANGE(2.5),
- BIP_RANGE(1),
- BIP_RANGE(0.5),
- BIP_RANGE(0.25),
- BIP_RANGE(0.1),
- BIP_RANGE(0.05),
- UNI_RANGE(10),
- UNI_RANGE(5),
- UNI_RANGE(2),
- UNI_RANGE(1),
- UNI_RANGE(0.5),
- UNI_RANGE(0.2),
- UNI_RANGE(0.1),
- }
+ 14, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.25),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.05),
+ UNI_RANGE(10),
+ UNI_RANGE(5),
+ UNI_RANGE(2),
+ UNI_RANGE(1),
+ UNI_RANGE(0.5),
+ UNI_RANGE(0.2),
+ UNI_RANGE(0.1)
+ }
};
EXPORT_SYMBOL_GPL(range_labpc_1200_ai);
-/* analog output ranges */
-#define AO_RANGE_IS_UNIPOLAR 0x1
static const struct comedi_lrange range_labpc_ao = {
- 2,
- {
- BIP_RANGE(5),
- UNI_RANGE(10),
- }
+ 2, {
+ BIP_RANGE(5),
+ UNI_RANGE(10)
+ }
};
/* functions that do inb/outb and readb/writeb so we can use
@@ -420,413 +234,417 @@ static inline void labpc_writeb(unsigned int byte, unsigned long address)
writeb(byte, (void __iomem *)address);
}
-static const struct labpc_board_struct labpc_boards[] = {
- {
- .name = "lab-pc-1200",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
+static const struct labpc_boardinfo labpc_boards[] = {
{
- .name = "lab-pc-1200ai",
- .ai_speed = 10000,
- .bustype = isa_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 0,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 0,
- },
- {
- .name = "lab-pc+",
- .ai_speed = 12000,
- .bustype = isa_bustype,
- .register_layout = labpc_plus_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_plus_ai,
- .ai_range_code = labpc_plus_ai_gain_bits,
- .ai_range_is_unipolar = labpc_plus_is_unipolar,
- .ai_scan_up = 0,
- .memory_mapped_io = 0,
- },
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- {
- .name = "pci-1200",
- .device_id = 0x161,
- .ai_speed = 10000,
- .bustype = pci_bustype,
- .register_layout = labpc_1200_layout,
- .has_ao = 1,
- .ai_range_table = &range_labpc_1200_ai,
- .ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
- .ai_scan_up = 1,
- .memory_mapped_io = 1,
- },
-/* dummy entry so pci board works when comedi_config is passed driver name */
- {
- .name = DRV_NAME,
- .bustype = pci_bustype,
- },
-#endif
+ .name = "lab-pc-1200",
+ .ai_speed = 10000,
+ .register_layout = labpc_1200_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc-1200ai",
+ .ai_speed = 10000,
+ .register_layout = labpc_1200_layout,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_scan_up = 1,
+ }, {
+ .name = "lab-pc+",
+ .ai_speed = 12000,
+ .register_layout = labpc_plus_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_plus_ai,
+ .ai_range_code = labpc_plus_ai_gain_bits,
+ },
};
-
-/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((struct labpc_board_struct *)dev->board_ptr)
+#endif
/* size in bytes of dma buffer */
static const int dma_buffer_size = 0xff00;
/* 2 bytes per sample */
static const int sample_size = 2;
-static inline int labpc_counter_load(struct comedi_device *dev,
- unsigned long base_address,
- unsigned int counter_number,
- unsigned int count, unsigned int mode)
+static int labpc_counter_load(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int count, unsigned int mode)
{
- if (thisboard->memory_mapped_io)
+ const struct labpc_boardinfo *board = comedi_board(dev);
+
+ if (board->has_mmio)
return i8254_mm_load((void __iomem *)base_address, 0,
counter_number, count, mode);
else
return i8254_load(base_address, 0, counter_number, count, mode);
}
-int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
- unsigned int irq, unsigned int dma_chan)
+static int labpc_counter_set_mode(struct comedi_device *dev,
+ unsigned long base_address,
+ unsigned int counter_number,
+ unsigned int mode)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+
+ if (board->has_mmio)
+ return i8254_mm_set_mode((void __iomem *)base_address, 0,
+ counter_number, mode);
+ else
+ return i8254_set_mode(base_address, 0, counter_number, mode);
+}
+
+static bool labpc_range_is_unipolar(struct comedi_subdevice *s,
+ unsigned int range)
+{
+ return s->range_table->range[range].min >= 0;
+}
+
+static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- int i;
- unsigned long isr_flags;
-#ifdef CONFIG_ISA_DMA_API
- unsigned long dma_flags;
-#endif
- short lsb, msb;
- int ret;
+ unsigned long flags;
- dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name);
- if (iobase == 0) {
- dev_err(dev->class_dev, "io base address is zero!\n");
- return -EINVAL;
- }
- /* request io regions for isa boards */
- if (thisboard->bustype == isa_bustype) {
- /* check if io addresses are available */
- if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
- }
- dev->iobase = iobase;
+ spin_lock_irqsave(&dev->spinlock, flags);
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- if (thisboard->memory_mapped_io) {
- devpriv->read_byte = labpc_readb;
- devpriv->write_byte = labpc_writeb;
- } else {
- devpriv->read_byte = labpc_inb;
- devpriv->write_byte = labpc_outb;
- }
- /* initialize board's command registers */
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- if (thisboard->register_layout == labpc_1200_layout) {
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
- }
+ devpriv->cmd3 = 0;
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
- /* grab our IRQ */
- if (irq) {
- isr_flags = 0;
- if (thisboard->bustype == pci_bustype
- || thisboard->bustype == pcmcia_bustype)
- isr_flags |= IRQF_SHARED;
- if (request_irq(irq, labpc_interrupt, isr_flags,
- DRV_NAME, dev)) {
- dev_err(dev->class_dev, "unable to allocate irq %u\n",
- irq);
- return -EINVAL;
- }
- }
- dev->irq = irq;
+ return 0;
+}
-#ifdef CONFIG_ISA_DMA_API
- /* grab dma channel */
- if (dma_chan > 3) {
- dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan);
- return -EINVAL;
- } else if (dma_chan) {
- /* allocate dma buffer */
- devpriv->dma_buffer = kmalloc(dma_buffer_size,
- GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
+static void labpc_ai_set_chan_and_gain(struct comedi_device *dev,
+ enum scan_mode mode,
+ unsigned int chan,
+ unsigned int range,
+ unsigned int aref)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
- if (request_dma(dma_chan, DRV_NAME)) {
- dev_err(dev->class_dev,
- "failed to allocate dma channel %u\n",
- dma_chan);
- return -EINVAL;
- }
- devpriv->dma_chan = dma_chan;
- dma_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(dma_flags);
- }
-#endif
+ /* munge channel bits for differential/scan disabled mode */
+ if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
+ aref == AREF_DIFF)
+ chan *= 2;
+ devpriv->cmd1 = CMD1_MA(chan);
+ devpriv->cmd1 |= board->ai_range_code[range];
- dev->board_name = thisboard->name;
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
+}
- ret = comedi_alloc_subdevices(dev, 5);
- if (ret)
- return ret;
+static void labpc_setup_cmd6_reg(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ enum scan_mode mode,
+ enum transfer_type xfer,
+ unsigned int range,
+ unsigned int aref,
+ bool ena_intr)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
- /* analog input subdevice */
- s = &dev->subdevices[0];
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
- s->n_chan = 8;
- s->len_chanlist = 8;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = thisboard->ai_range_table;
- s->do_cmd = labpc_ai_cmd;
- s->do_cmdtest = labpc_ai_cmdtest;
- s->insn_read = labpc_ai_rinsn;
- s->cancel = labpc_cancel;
+ if (board->register_layout != labpc_1200_layout)
+ return;
- /* analog output */
- s = &dev->subdevices[1];
- if (thisboard->has_ao) {
- /*
- * Could provide command support, except it only has a
- * one sample hardware buffer for analog output and no
- * underrun flag.
- */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
- s->n_chan = NUM_AO_CHAN;
- s->maxdata = (1 << 12) - 1; /* 12 bit resolution */
- s->range_table = &range_labpc_ao;
- s->insn_read = labpc_ao_rinsn;
- s->insn_write = labpc_ao_winsn;
- /* initialize analog outputs to a known value */
- for (i = 0; i < s->n_chan; i++) {
- devpriv->ao_value[i] = s->maxdata / 2;
- lsb = devpriv->ao_value[i] & 0xff;
- msb = (devpriv->ao_value[i] >> 8) & 0xff;
- devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
- devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
+ /* reference inputs to ground or common? */
+ if (aref != AREF_GROUND)
+ devpriv->cmd6 |= CMD6_NRSE;
+ else
+ devpriv->cmd6 &= ~CMD6_NRSE;
- /* 8255 dio */
- s = &dev->subdevices[2];
- /* if board uses io memory we have to give a custom callback
- * function to the 8255 driver */
- if (thisboard->memory_mapped_io)
- subdev_8255_init(dev, s, labpc_dio_mem_callback,
- (unsigned long)(dev->iobase + DIO_BASE_REG));
+ /* bipolar or unipolar range? */
+ if (labpc_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_ADCUNI;
else
- subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG);
+ devpriv->cmd6 &= ~CMD6_ADCUNI;
- /* calibration subdevices for boards that have one */
- s = &dev->subdevices[3];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 16;
- s->maxdata = 0xff;
- s->insn_read = labpc_calib_read_insn;
- s->insn_write = labpc_calib_write_insn;
+ /* interrupt on fifo half full? */
+ if (xfer == fifo_half_full_transfer)
+ devpriv->cmd6 |= CMD6_HFINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_HFINTEN;
- for (i = 0; i < s->n_chan; i++)
- write_caldac(dev, i, s->maxdata / 2);
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ /* enable interrupt on counter a1 terminal count? */
+ if (ena_intr)
+ devpriv->cmd6 |= CMD6_DQINTEN;
+ else
+ devpriv->cmd6 &= ~CMD6_DQINTEN;
- /* EEPROM */
- s = &dev->subdevices[4];
- if (thisboard->register_layout == labpc_1200_layout) {
- s->type = COMEDI_SUBD_MEMORY;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = EEPROM_SIZE;
- s->maxdata = 0xff;
- s->insn_read = labpc_eeprom_read_insn;
- s->insn_write = labpc_eeprom_write_insn;
-
- for (i = 0; i < EEPROM_SIZE; i++)
- devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
- } else
- s->type = COMEDI_SUBD_UNUSED;
+ /* are we scanning up or down through channels? */
+ if (mode == MODE_MULT_CHAN_UP)
+ devpriv->cmd6 |= CMD6_SCANUP;
+ else
+ devpriv->cmd6 &= ~CMD6_SCANUP;
- return 0;
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
}
-EXPORT_SYMBOL_GPL(labpc_common_attach);
-static const struct labpc_board_struct *
-labpc_pci_find_boardinfo(struct pci_dev *pcidev)
+static unsigned int labpc_read_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ unsigned int msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+
+ return (msb << 8) | lsb;
+}
+
+static void labpc_clear_adc_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ labpc_read_adc_fifo(dev);
+}
+
+static int labpc_ai_wait_for_data(struct comedi_device *dev,
+ int timeout)
{
- unsigned int device_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) {
- const struct labpc_board_struct *board = &labpc_boards[n];
- if (board->bustype == pci_bustype &&
- board->device_id == device_id)
- return board;
+ struct labpc_private *devpriv = dev->private;
+ int i;
+
+ for (i = 0; i < timeout; i++) {
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (devpriv->stat1 & STAT1_DAVAIL)
+ return 0;
+ udelay(1);
}
- return NULL;
+ return -ETIME;
}
-static int labpc_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int labpc_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- struct labpc_private *devpriv;
- unsigned long iobase;
- unsigned int irq;
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int aref = CR_AREF(insn->chanspec);
int ret;
+ int i;
- if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
- return -ENODEV;
+ /* disable timed conversions, interrupt generation and dma */
+ labpc_cancel(dev, s);
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref);
- dev->board_ptr = labpc_pci_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
- devpriv->mite = mite_alloc(pcidev);
- if (!devpriv->mite)
- return -ENOMEM;
- ret = mite_setup(devpriv->mite);
- if (ret < 0)
+ labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer,
+ range, aref, false);
+
+ /* setup cmd4 register */
+ devpriv->cmd4 = 0;
+ devpriv->cmd4 |= CMD4_ECLKRCV;
+ /* single-ended/differential */
+ if (aref == AREF_DIFF)
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
+
+ /* initialize pacer counter to prevent any problems */
+ ret = labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
+ if (ret)
return ret;
- iobase = (unsigned long)devpriv->mite->daq_io_addr;
- irq = mite_irq(devpriv->mite);
- return labpc_common_attach(dev, iobase, irq, 0);
+
+ labpc_clear_adc_fifo(dev);
+
+ for (i = 0; i < insn->n; i++) {
+ /* trigger conversion */
+ devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG);
+
+ ret = labpc_ai_wait_for_data(dev, LABPC_ADC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ data[i] = labpc_read_adc_fifo(dev);
+ }
+
+ return insn->n;
}
-static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+#ifdef CONFIG_ISA_DMA_API
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
{
- struct labpc_private *devpriv;
- unsigned long iobase = 0;
- unsigned int irq = 0;
- unsigned int dma_chan = 0;
+ unsigned int size;
+ unsigned int freq;
- devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv)
- return -ENOMEM;
- dev->private = devpriv;
+ if (cmd->convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd->convert_arg;
+ /* return some default value */
+ else
+ freq = 0xffffffff;
- /* get base address, irq etc. based on bustype */
- switch (thisboard->bustype) {
- case isa_bustype:
-#ifdef CONFIG_ISA_DMA_API
- iobase = it->options[0];
- irq = it->options[1];
- dma_chan = it->options[2];
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with ISA DMA support.\n");
- return -EINVAL;
-#endif
- break;
- case pci_bustype:
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- dev_err(dev->class_dev,
- "manual configuration of PCI board '%s' is not supported\n",
- thisboard->name);
- return -EINVAL;
-#else
- dev_err(dev->class_dev,
- "ni_labpc driver has not been built with PCI support.\n");
- return -EINVAL;
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+
+ /* set a minimum and maximum size allowed */
+ if (size > dma_buffer_size)
+ size = dma_buffer_size - dma_buffer_size % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ return size;
+}
#endif
- break;
- default:
- dev_err(dev->class_dev,
- "ni_labpc: bug! couldn't determine board type\n");
- return -EINVAL;
- break;
- }
- return labpc_common_attach(dev, iobase, irq, dma_chan);
+static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
+{
+ if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW)
+ return true;
+
+ return false;
}
-void labpc_common_detach(struct comedi_device *dev)
+static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s;
+ if (cmd->convert_src != TRIG_TIMER)
+ return 0;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
+ return cmd->scan_begin_arg;
- if (!thisboard)
+ return cmd->convert_arg;
+}
+
+static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->convert_src != TRIG_TIMER)
return;
- if (dev->subdevices) {
- s = &dev->subdevices[2];
- subdev_8255_cleanup(dev, s);
- }
-#ifdef CONFIG_ISA_DMA_API
- /* only free stuff if it has been allocated by _attach */
- kfree(devpriv->dma_buffer);
- if (devpriv->dma_chan)
- free_dma(devpriv->dma_chan);
-#endif
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (thisboard->bustype == isa_bustype && dev->iobase)
- release_region(dev->iobase, LABPC_SIZE);
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
- if (devpriv->mite) {
- mite_unsetup(devpriv->mite);
- mite_free(devpriv->mite);
- }
-#endif
-};
-EXPORT_SYMBOL_GPL(labpc_common_detach);
-static void labpc_clear_adc_fifo(const struct comedi_device *dev)
+ if (mode == MODE_SINGLE_CHAN &&
+ cmd->scan_begin_src == TRIG_TIMER) {
+ cmd->scan_begin_arg = ns;
+ if (cmd->convert_arg > cmd->scan_begin_arg)
+ cmd->convert_arg = cmd->scan_begin_arg;
+ } else
+ cmd->convert_arg = ns;
+}
+
+static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
- struct labpc_private *devpriv = dev->private;
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return 0;
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return 0;
+
+ return cmd->scan_begin_arg;
}
-static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
+static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
+ enum scan_mode mode, unsigned int ns)
+{
+ if (cmd->scan_begin_src != TRIG_TIMER)
+ return;
+
+ if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
+ return;
+
+ cmd->scan_begin_arg = ns;
+}
+
+/* figures out what counter values to use based on command */
+static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
+ enum scan_mode mode)
{
struct labpc_private *devpriv = dev->private;
- unsigned long flags;
+ /* max value for 16 bit counter in mode 2 */
+ const int max_counter_value = 0x10000;
+ /* min value for 16 bit counter in mode 2 */
+ const int min_counter_value = 2;
+ unsigned int base_period;
+ unsigned int scan_period;
+ unsigned int convert_period;
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
+ /*
+ * if both convert and scan triggers are TRIG_TIMER, then they
+ * both rely on counter b0
+ */
+ convert_period = labpc_ai_convert_period(cmd, mode);
+ scan_period = labpc_ai_scan_period(cmd, mode);
+ if (convert_period && scan_period) {
+ /*
+ * pick the lowest b0 divisor value we can (for maximum input
+ * clock speed on convert and scan counters)
+ */
+ devpriv->divisor_b0 = (scan_period - 1) /
+ (LABPC_TIMER_BASE * max_counter_value) + 1;
+ if (devpriv->divisor_b0 < min_counter_value)
+ devpriv->divisor_b0 = min_counter_value;
+ if (devpriv->divisor_b0 > max_counter_value)
+ devpriv->divisor_b0 = max_counter_value;
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
- return 0;
+ /* set a0 for conversion frequency and b1 for scan frequency */
+ switch (cmd->flags & TRIG_ROUND_MASK) {
+ default:
+ case TRIG_ROUND_NEAREST:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period / 2)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period / 2)) / base_period;
+ break;
+ case TRIG_ROUND_UP:
+ devpriv->divisor_a0 =
+ (convert_period + (base_period - 1)) / base_period;
+ devpriv->divisor_b1 =
+ (scan_period + (base_period - 1)) / base_period;
+ break;
+ case TRIG_ROUND_DOWN:
+ devpriv->divisor_a0 = convert_period / base_period;
+ devpriv->divisor_b1 = scan_period / base_period;
+ break;
+ }
+ /* make sure a0 and b1 values are acceptable */
+ if (devpriv->divisor_a0 < min_counter_value)
+ devpriv->divisor_a0 = min_counter_value;
+ if (devpriv->divisor_a0 > max_counter_value)
+ devpriv->divisor_a0 = max_counter_value;
+ if (devpriv->divisor_b1 < min_counter_value)
+ devpriv->divisor_b1 = min_counter_value;
+ if (devpriv->divisor_b1 > max_counter_value)
+ devpriv->divisor_b1 = max_counter_value;
+ /* write corrected timings to command */
+ labpc_set_ai_convert_period(cmd, mode,
+ base_period * devpriv->divisor_a0);
+ labpc_set_ai_scan_period(cmd, mode,
+ base_period * devpriv->divisor_b1);
+ /*
+ * if only one TRIG_TIMER is used, we can employ the generic
+ * cascaded timing functions
+ */
+ } else if (scan_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired scan timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_b1),
+ &(devpriv->divisor_b0),
+ &scan_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_scan_period(cmd, mode, scan_period);
+ } else if (convert_period) {
+ /*
+ * calculate cascaded counter values
+ * that give desired conversion timing
+ */
+ i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
+ &(devpriv->divisor_a0),
+ &(devpriv->divisor_b0),
+ &convert_period,
+ cmd->flags & TRIG_ROUND_MASK);
+ labpc_set_ai_convert_period(cmd, mode, convert_period);
+ }
}
static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd)
@@ -923,72 +741,10 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device *dev,
return 0;
}
-static int labpc_use_continuous_mode(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (mode == MODE_SINGLE_CHAN)
- return 1;
-
- if (cmd->scan_begin_src == TRIG_FOLLOW)
- return 1;
-
- return 0;
-}
-
-static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER)
- return cmd->scan_begin_arg;
-
- return cmd->convert_arg;
-}
-
-static void labpc_set_ai_convert_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->convert_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN &&
- cmd->scan_begin_src == TRIG_TIMER) {
- cmd->scan_begin_arg = ns;
- if (cmd->convert_arg > cmd->scan_begin_arg)
- cmd->convert_arg = cmd->scan_begin_arg;
- } else
- cmd->convert_arg = ns;
-}
-
-static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return 0;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return 0;
-
- return cmd->scan_begin_arg;
-}
-
-static void labpc_set_ai_scan_period(struct comedi_cmd *cmd,
- enum scan_mode mode, unsigned int ns)
-{
- if (cmd->scan_begin_src != TRIG_TIMER)
- return;
-
- if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER)
- return;
-
- cmd->scan_begin_arg = ns;
-}
-
static int labpc_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
int err = 0;
int tmp, tmp2;
unsigned int stop_mask;
@@ -1003,7 +759,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
stop_mask = TRIG_COUNT | TRIG_NONE;
- if (thisboard->register_layout == labpc_1200_layout)
+ if (board->register_layout == labpc_1200_layout)
stop_mask |= TRIG_EXT;
err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask);
@@ -1037,7 +793,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
if (cmd->convert_src == TRIG_TIMER)
err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- thisboard->ai_speed);
+ board->ai_speed);
/* make sure scan timing is not too fast */
if (cmd->scan_begin_src == TRIG_TIMER) {
@@ -1045,7 +801,7 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
cmd->convert_arg * cmd->chanlist_len);
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- thisboard->ai_speed * cmd->chanlist_len);
+ board->ai_speed * cmd->chanlist_len);
}
switch (cmd->stop_src) {
@@ -1086,34 +842,23 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- int channel, range, aref;
-#ifdef CONFIG_ISA_DMA_API
- unsigned long irq_flags;
-#endif
- int ret;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ enum scan_mode mode = labpc_ai_scan_mode(cmd);
+ unsigned int chanspec = (mode == MODE_MULT_CHAN_UP)
+ ? cmd->chanlist[cmd->chanlist_len - 1]
+ : cmd->chanlist[0];
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
enum transfer_type xfer;
- enum scan_mode mode;
unsigned long flags;
-
- if (!dev->irq) {
- comedi_error(dev, "no irq assigned, cannot perform command");
- return -1;
- }
-
- range = CR_RANGE(cmd->chanlist[0]);
- aref = CR_AREF(cmd->chanlist[0]);
+ int ret;
/* make sure board is disabled before setting up acquisition */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ labpc_cancel(dev, s);
/* initialize software conversion count */
if (cmd->stop_src == TRIG_COUNT)
@@ -1126,17 +871,17 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* (pc+ manual says this is minimum allowed) using mode 0
*/
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 1, 3, 0);
- if (ret < 0) {
- comedi_error(dev, "error loading counter a1");
- return -1;
- }
- } else /*
- * otherwise, just put a1 in mode 0
- * with no count to set its output low
- */
- devpriv->write_byte(INIT_A1_BITS,
- dev->iobase + COUNTER_A_CONTROL_REG);
+ 1, 3, I8254_MODE0);
+ } else {
+ /* just put counter a1 in mode 0 to set its output low */
+ ret = labpc_counter_set_mode(dev,
+ dev->iobase + COUNTER_A_BASE_REG,
+ 1, I8254_MODE0);
+ }
+ if (ret) {
+ comedi_error(dev, "error loading counter a1");
+ return ret;
+ }
#ifdef CONFIG_ISA_DMA_API
/* figure out what method we will use to transfer data */
@@ -1145,14 +890,12 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* dma unsafe at RT priority,
* and too much setup time for TRIG_WAKE_EOS for
*/
- (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 &&
- /* only available on the isa boards */
- thisboard->bustype == isa_bustype) {
+ (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0) {
xfer = isa_dma_transfer;
/* pc-plus has no fifo-half full interrupt */
} else
#endif
- if (thisboard->register_layout == labpc_1200_layout &&
+ if (board->register_layout == labpc_1200_layout &&
/* wake-end-of-scan should interrupt on fifo not empty */
(cmd->flags & TRIG_WAKE_EOS) == 0 &&
/* make sure we are taking more than just a few points */
@@ -1161,76 +904,34 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
} else
xfer = fifo_not_empty_transfer;
devpriv->current_transfer = xfer;
- mode = labpc_ai_scan_mode(cmd);
- /* setup command6 register for 1200 boards */
- if (thisboard->register_layout == labpc_1200_layout) {
- /* reference inputs to ground or common? */
- if (aref != AREF_GROUND)
- devpriv->command6_bits |= ADC_COMMON_BIT;
- else
- devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
- if (thisboard->ai_range_is_unipolar[range])
- devpriv->command6_bits |= ADC_UNIP_BIT;
- else
- devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* interrupt on fifo half full? */
- if (xfer == fifo_half_full_transfer)
- devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT;
- else
- devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* enable interrupt on counter a1 terminal count? */
- if (cmd->stop_src == TRIG_EXT)
- devpriv->command6_bits |= A1_INTR_EN_BIT;
- else
- devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* are we scanning up or down through channels? */
- if (mode == MODE_MULT_CHAN_UP)
- devpriv->command6_bits |= ADC_SCAN_UP_BIT;
- else
- devpriv->command6_bits &= ~ADC_SCAN_UP_BIT;
- /* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
- }
+ labpc_ai_set_chan_and_gain(dev, mode, chan, range, aref);
+
+ labpc_setup_cmd6_reg(dev, s, mode, xfer, range, aref,
+ (cmd->stop_src == TRIG_EXT));
- /* setup channel list, etc (command1 register) */
- devpriv->command1_bits = 0;
- if (mode == MODE_MULT_CHAN_UP)
- channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
- else
- channel = CR_CHAN(cmd->chanlist[0]);
- /* munge channel bits for differential / scan disabled mode */
- if ((mode == MODE_SINGLE_CHAN || mode == MODE_SINGLE_CHAN_INTERVAL) &&
- aref == AREF_DIFF)
- channel *= 2;
- devpriv->command1_bits |= ADC_CHAN_BITS(channel);
- devpriv->command1_bits |= thisboard->ai_range_code[range];
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
/* manual says to set scan enable bit on second pass */
if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) {
- devpriv->command1_bits |= ADC_SCAN_EN_BIT;
+ devpriv->cmd1 |= CMD1_SCANEN;
/* need a brief delay before enabling scan, or scan
* list will get screwed when you switch
* between scan up to scan down mode - dunno why */
udelay(1);
- devpriv->write_byte(devpriv->command1_bits,
- dev->iobase + COMMAND1_REG);
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
}
devpriv->write_byte(cmd->chanlist_len,
dev->iobase + INTERVAL_COUNT_REG);
/* load count */
- devpriv->write_byte(INTERVAL_LOAD_BITS,
- dev->iobase + INTERVAL_LOAD_REG);
+ devpriv->write_byte(0x1, dev->iobase + INTERVAL_STROBE_REG);
- if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) {
+ if (cmd->convert_src == TRIG_TIMER ||
+ cmd->scan_begin_src == TRIG_TIMER) {
/* set up pacing */
labpc_adc_timing(dev, cmd, mode);
/* load counter b0 in mode 3 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 0, devpriv->divisor_b0, 3);
+ 0, devpriv->divisor_b0, I8254_MODE3);
if (ret < 0) {
comedi_error(dev, "error loading counter b0");
return -1;
@@ -1240,20 +941,23 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (labpc_ai_convert_period(cmd, mode)) {
/* load counter a0 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG,
- 0, devpriv->divisor_a0, 2);
- if (ret < 0) {
- comedi_error(dev, "error loading counter a0");
- return -1;
- }
- } else
- devpriv->write_byte(INIT_A0_BITS,
- dev->iobase + COUNTER_A_CONTROL_REG);
+ 0, devpriv->divisor_a0, I8254_MODE2);
+ } else {
+ /* initialize pacer counter to prevent any problems */
+ ret = labpc_counter_set_mode(dev,
+ dev->iobase + COUNTER_A_BASE_REG,
+ 0, I8254_MODE2);
+ }
+ if (ret) {
+ comedi_error(dev, "error loading counter a0");
+ return ret;
+ }
/* set up scan pacing */
if (labpc_ai_scan_period(cmd, mode)) {
/* load counter b1 in mode 2 */
ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG,
- 1, devpriv->divisor_b1, 2);
+ 1, devpriv->divisor_b1, I8254_MODE2);
if (ret < 0) {
comedi_error(dev, "error loading counter b1");
return -1;
@@ -1265,6 +969,8 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
#ifdef CONFIG_ISA_DMA_API
/* set up dma transfer */
if (xfer == isa_dma_transfer) {
+ unsigned long irq_flags;
+
irq_flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
/* clear flip-flop to make sure 2-byte registers for
@@ -1283,197 +989,54 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
enable_dma(devpriv->dma_chan);
release_dma_lock(irq_flags);
/* enable board's dma */
- devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT;
+ devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
} else
- devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT;
+ devpriv->cmd3 &= ~(CMD3_DMAEN | CMD3_DMATCINTEN);
#endif
/* enable error interrupts */
- devpriv->command3_bits |= ERR_INTR_EN_BIT;
+ devpriv->cmd3 |= CMD3_ERRINTEN;
/* enable fifo not empty interrupt? */
if (xfer == fifo_not_empty_transfer)
- devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT;
+ devpriv->cmd3 |= CMD3_FIFOINTEN;
else
- devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ devpriv->cmd3 &= ~CMD3_FIFOINTEN;
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
- /* setup any external triggering/pacing (command4 register) */
- devpriv->command4_bits = 0;
+ /* setup any external triggering/pacing (cmd4 register) */
+ devpriv->cmd4 = 0;
if (cmd->convert_src != TRIG_EXT)
- devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
+ devpriv->cmd4 |= CMD4_ECLKRCV;
/* XXX should discard first scan when using interval scanning
* since manual says it is not synced with scan clock */
- if (labpc_use_continuous_mode(cmd, mode) == 0) {
- devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT;
+ if (!labpc_use_continuous_mode(cmd, mode)) {
+ devpriv->cmd4 |= CMD4_INTSCAN;
if (cmd->scan_begin_src == TRIG_EXT)
- devpriv->command4_bits |= EXT_SCAN_EN_BIT;
+ devpriv->cmd4 |= CMD4_EOIRCV;
}
/* single-ended/differential */
if (aref == AREF_DIFF)
- devpriv->command4_bits |= ADC_DIFF_BIT;
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
+ devpriv->cmd4 |= CMD4_SEDIFF;
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
/* startup acquisition */
- /* command2 reg */
- /* use 2 cascaded counters for pacing */
spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits |= CASCADE_BIT;
- switch (cmd->start_src) {
- case TRIG_EXT:
- devpriv->command2_bits |= HWTRIG_BIT;
- devpriv->command2_bits &= ~PRETRIG_BIT & ~SWTRIG_BIT;
- break;
- case TRIG_NOW:
- devpriv->command2_bits |= SWTRIG_BIT;
- devpriv->command2_bits &= ~PRETRIG_BIT & ~HWTRIG_BIT;
- break;
- default:
- comedi_error(dev, "bug with start_src");
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return -1;
- break;
- }
- switch (cmd->stop_src) {
- case TRIG_EXT:
- devpriv->command2_bits |= HWTRIG_BIT | PRETRIG_BIT;
- break;
- case TRIG_COUNT:
- case TRIG_NONE:
- break;
- default:
- comedi_error(dev, "bug with stop_src");
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return -1;
- }
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- return 0;
-}
-
-/* interrupt service routine */
-static irqreturn_t labpc_interrupt(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct labpc_private *devpriv = dev->private;
- struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
-
- if (dev->attached == 0) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
-
- async = s->async;
- cmd = &async->cmd;
- async->events = 0;
-
- /* read board status */
- devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
- if (thisboard->register_layout == labpc_1200_layout)
- devpriv->status2_bits =
- devpriv->read_byte(dev->iobase + STATUS2_REG);
-
- if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT |
- OVERRUN_BIT | DATA_AVAIL_BIT)) == 0
- && (devpriv->status2_bits & A1_TC_BIT) == 0
- && (devpriv->status2_bits & FNHF_BIT)) {
- return IRQ_NONE;
- }
-
- if (devpriv->status1_bits & OVERRUN_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overrun");
- return IRQ_HANDLED;
- }
-
-#ifdef CONFIG_ISA_DMA_API
- if (devpriv->current_transfer == isa_dma_transfer) {
- /*
- * if a dma terminal count of external stop trigger
- * has occurred
- */
- if (devpriv->status1_bits & DMATC_BIT ||
- (thisboard->register_layout == labpc_1200_layout
- && devpriv->status2_bits & A1_TC_BIT)) {
- handle_isa_dma(dev);
- }
- } else
-#endif
- labpc_drain_fifo(dev);
-
- if (devpriv->status1_bits & TIMER_BIT) {
- comedi_error(dev, "handled timer interrupt?");
- /* clear it */
- devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
- }
-
- if (devpriv->status1_bits & OVERFLOW_BIT) {
- /* clear error interrupt */
- devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- comedi_event(dev, s);
- comedi_error(dev, "overflow");
- return IRQ_HANDLED;
- }
- /* handle external stop trigger */
- if (cmd->stop_src == TRIG_EXT) {
- if (devpriv->status2_bits & A1_TC_BIT) {
- labpc_drain_dregs(dev);
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
-
- /* TRIG_COUNT end of acquisition */
- if (cmd->stop_src == TRIG_COUNT) {
- if (devpriv->count == 0) {
- labpc_cancel(dev, s);
- async->events |= COMEDI_CB_EOA;
- }
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
-}
+ /* use 2 cascaded counters for pacing */
+ devpriv->cmd2 |= CMD2_TBSEL;
-/* read all available samples from ai fifo */
-static int labpc_drain_fifo(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int lsb, msb;
- short data;
- struct comedi_async *async = dev->read_subdev->async;
- const int timeout = 10000;
- unsigned int i;
+ devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG);
+ if (cmd->start_src == TRIG_EXT)
+ devpriv->cmd2 |= CMD2_HWTRIG;
+ else
+ devpriv->cmd2 |= CMD2_SWTRIG;
+ if (cmd->stop_src == TRIG_EXT)
+ devpriv->cmd2 |= (CMD2_HWTRIG | CMD2_PRETRIG);
- devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
- for (i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout;
- i++) {
- /* quit if we have all the data we want */
- if (async->cmd.stop_src == TRIG_COUNT) {
- if (devpriv->count == 0)
- break;
- devpriv->count--;
- }
- lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- data = (msb << 8) | lsb;
- cfc_write_to_buffer(dev->read_subdev, data);
- devpriv->status1_bits =
- devpriv->read_byte(dev->iobase + STATUS1_REG);
- }
- if (i == timeout) {
- comedi_error(dev, "ai timeout, fifo never empties");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- return -1;
- }
+ spin_unlock_irqrestore(&dev->spinlock, flags);
return 0;
}
@@ -1489,7 +1052,7 @@ static void labpc_drain_dma(struct comedi_device *dev)
unsigned int max_points, num_points, residue, leftover;
int i;
- status = devpriv->status1_bits;
+ status = devpriv->stat1;
flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
@@ -1546,6 +1109,38 @@ static void handle_isa_dma(struct comedi_device *dev)
}
#endif
+/* read all available samples from ai fifo */
+static int labpc_drain_fifo(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ short data;
+ struct comedi_async *async = dev->read_subdev->async;
+ const int timeout = 10000;
+ unsigned int i;
+
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+
+ for (i = 0; (devpriv->stat1 & STAT1_DAVAIL) && i < timeout;
+ i++) {
+ /* quit if we have all the data we want */
+ if (async->cmd.stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0)
+ break;
+ devpriv->count--;
+ }
+ data = labpc_read_adc_fifo(dev);
+ cfc_write_to_buffer(dev->read_subdev, data);
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ }
+ if (i == timeout) {
+ comedi_error(dev, "ai timeout, fifo never empties");
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ return -1;
+ }
+
+ return 0;
+}
+
/* makes sure all data acquired by board is transferred to comedi (used
* when acquisition is terminated by stop_src == TRIG_EXT). */
static void labpc_drain_dregs(struct comedi_device *dev)
@@ -1560,99 +1155,102 @@ static void labpc_drain_dregs(struct comedi_device *dev)
labpc_drain_fifo(dev);
}
-static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+/* interrupt service routine */
+static irqreturn_t labpc_interrupt(int irq, void *d)
{
+ struct comedi_device *dev = d;
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
- int i, n;
- int chan, range;
- int lsb, msb;
- int timeout = 1000;
- unsigned long flags;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async;
+ struct comedi_cmd *cmd;
- /* disable timed conversions */
- spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT;
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
- spin_unlock_irqrestore(&dev->spinlock, flags);
+ if (!dev->attached) {
+ comedi_error(dev, "premature interrupt");
+ return IRQ_HANDLED;
+ }
- /* disable interrupt generation and dma */
- devpriv->command3_bits = 0;
- devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG);
+ async = s->async;
+ cmd = &async->cmd;
+ async->events = 0;
- /* set gain and channel */
- devpriv->command1_bits = 0;
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
- devpriv->command1_bits |= thisboard->ai_range_code[range];
- /* munge channel bits for differential/scan disabled mode */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- chan *= 2;
- devpriv->command1_bits |= ADC_CHAN_BITS(chan);
- devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG);
-
- /* setup command6 register for 1200 boards */
- if (thisboard->register_layout == labpc_1200_layout) {
- /* reference inputs to ground or common? */
- if (CR_AREF(insn->chanspec) != AREF_GROUND)
- devpriv->command6_bits |= ADC_COMMON_BIT;
- else
- devpriv->command6_bits &= ~ADC_COMMON_BIT;
- /* bipolar or unipolar range? */
- if (thisboard->ai_range_is_unipolar[range])
- devpriv->command6_bits |= ADC_UNIP_BIT;
- else
- devpriv->command6_bits &= ~ADC_UNIP_BIT;
- /* don't interrupt on fifo half full */
- devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT;
- /* don't enable interrupt on counter a1 terminal count? */
- devpriv->command6_bits &= ~A1_INTR_EN_BIT;
- /* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
+ /* read board status */
+ devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG);
+ if (board->register_layout == labpc_1200_layout)
+ devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG);
+
+ if ((devpriv->stat1 & (STAT1_GATA0 | STAT1_CNTINT | STAT1_OVERFLOW |
+ STAT1_OVERRUN | STAT1_DAVAIL)) == 0
+ && (devpriv->stat2 & STAT2_OUTA1) == 0
+ && (devpriv->stat2 & STAT2_FIFONHF)) {
+ return IRQ_NONE;
}
- /* setup command4 register */
- devpriv->command4_bits = 0;
- devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT;
- /* single-ended/differential */
- if (CR_AREF(insn->chanspec) == AREF_DIFF)
- devpriv->command4_bits |= ADC_DIFF_BIT;
- devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG);
- /*
- * initialize pacer counter output to make sure it doesn't
- * cause any problems
- */
- devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG);
+ if (devpriv->stat1 & STAT1_OVERRUN) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overrun");
+ return IRQ_HANDLED;
+ }
- labpc_clear_adc_fifo(dev);
+#ifdef CONFIG_ISA_DMA_API
+ if (devpriv->current_transfer == isa_dma_transfer) {
+ /*
+ * if a dma terminal count of external stop trigger
+ * has occurred
+ */
+ if (devpriv->stat1 & STAT1_GATA0 ||
+ (board->register_layout == labpc_1200_layout
+ && devpriv->stat2 & STAT2_OUTA1)) {
+ handle_isa_dma(dev);
+ }
+ } else
+#endif
+ labpc_drain_fifo(dev);
- for (n = 0; n < insn->n; n++) {
- /* trigger conversion */
- devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG);
+ if (devpriv->stat1 & STAT1_CNTINT) {
+ comedi_error(dev, "handled timer interrupt?");
+ /* clear it */
+ devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG);
+ }
- for (i = 0; i < timeout; i++) {
- if (devpriv->read_byte(dev->iobase +
- STATUS1_REG) & DATA_AVAIL_BIT)
- break;
- udelay(1);
+ if (devpriv->stat1 & STAT1_OVERFLOW) {
+ /* clear error interrupt */
+ devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG);
+ async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ comedi_event(dev, s);
+ comedi_error(dev, "overflow");
+ return IRQ_HANDLED;
+ }
+ /* handle external stop trigger */
+ if (cmd->stop_src == TRIG_EXT) {
+ if (devpriv->stat2 & STAT2_OUTA1) {
+ labpc_drain_dregs(dev);
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
}
- if (i == timeout) {
- comedi_error(dev, "timeout");
- return -ETIME;
+ }
+
+ /* TRIG_COUNT end of acquisition */
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count == 0) {
+ labpc_cancel(dev, s);
+ async->events |= COMEDI_CB_EOA;
}
- lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG);
- data[n] = (msb << 8) | lsb;
}
- return n;
+ comedi_event(dev, s);
+ return IRQ_HANDLED;
}
-/* analog output insn */
-static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int labpc_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ const struct labpc_boardinfo *board = comedi_board(dev);
struct labpc_private *devpriv = dev->private;
int channel, range;
unsigned long flags;
@@ -1664,20 +1262,19 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* note: hardware bug in daqcard-1200 means pacing cannot
* be independently enabled/disabled for its the two channels */
spin_lock_irqsave(&dev->spinlock, flags);
- devpriv->command2_bits &= ~DAC_PACED_BIT(channel);
- devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG);
+ devpriv->cmd2 &= ~CMD2_LDAC(channel);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
spin_unlock_irqrestore(&dev->spinlock, flags);
/* set range */
- if (thisboard->register_layout == labpc_1200_layout) {
+ if (board->register_layout == labpc_1200_layout) {
range = CR_RANGE(insn->chanspec);
- if (range & AO_RANGE_IS_UNIPOLAR)
- devpriv->command6_bits |= DAC_UNIP_BIT(channel);
+ if (labpc_range_is_unipolar(s, range))
+ devpriv->cmd6 |= CMD6_DACUNI(channel);
else
- devpriv->command6_bits &= ~DAC_UNIP_BIT(channel);
+ devpriv->cmd6 &= ~CMD6_DACUNI(channel);
/* write to register */
- devpriv->write_byte(devpriv->command6_bits,
- dev->iobase + COMMAND6_REG);
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
}
/* send data */
lsb = data[0] & 0xff;
@@ -1691,9 +1288,10 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return 1;
}
-/* analog output readback insn */
-static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int labpc_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct labpc_private *devpriv = dev->private;
@@ -1702,183 +1300,7 @@ static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return 1;
}
-static int labpc_calib_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_calib_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
-
- write_caldac(dev, channel, data[0]);
- return 1;
-}
-
-static int labpc_eeprom_read_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct labpc_private *devpriv = dev->private;
-
- data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int labpc_eeprom_write_insn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel = CR_CHAN(insn->chanspec);
- int ret;
-
- /* only allow writes to user area of eeprom */
- if (channel < 16 || channel > 127) {
- dev_dbg(dev->class_dev,
- "eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n");
- return -EINVAL;
- }
-
- ret = labpc_eeprom_write(dev, channel, data[0]);
- if (ret < 0)
- return ret;
-
- return 1;
-}
-
-#ifdef CONFIG_ISA_DMA_API
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- if (cmd->convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd->convert_arg;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
-
- /* set a minimum and maximum size allowed */
- if (size > dma_buffer_size)
- size = dma_buffer_size - dma_buffer_size % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- return size;
-}
-#endif
-
-/* figures out what counter values to use based on command */
-static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
- enum scan_mode mode)
-{
- struct labpc_private *devpriv = dev->private;
- /* max value for 16 bit counter in mode 2 */
- const int max_counter_value = 0x10000;
- /* min value for 16 bit counter in mode 2 */
- const int min_counter_value = 2;
- unsigned int base_period;
- unsigned int scan_period;
- unsigned int convert_period;
-
- /*
- * if both convert and scan triggers are TRIG_TIMER, then they
- * both rely on counter b0
- */
- convert_period = labpc_ai_convert_period(cmd, mode);
- scan_period = labpc_ai_scan_period(cmd, mode);
- if (convert_period && scan_period) {
- /*
- * pick the lowest b0 divisor value we can (for maximum input
- * clock speed on convert and scan counters)
- */
- devpriv->divisor_b0 = (scan_period - 1) /
- (LABPC_TIMER_BASE * max_counter_value) + 1;
- if (devpriv->divisor_b0 < min_counter_value)
- devpriv->divisor_b0 = min_counter_value;
- if (devpriv->divisor_b0 > max_counter_value)
- devpriv->divisor_b0 = max_counter_value;
-
- base_period = LABPC_TIMER_BASE * devpriv->divisor_b0;
-
- /* set a0 for conversion frequency and b1 for scan frequency */
- switch (cmd->flags & TRIG_ROUND_MASK) {
- default:
- case TRIG_ROUND_NEAREST:
- devpriv->divisor_a0 =
- (convert_period + (base_period / 2)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period / 2)) / base_period;
- break;
- case TRIG_ROUND_UP:
- devpriv->divisor_a0 =
- (convert_period + (base_period - 1)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period - 1)) / base_period;
- break;
- case TRIG_ROUND_DOWN:
- devpriv->divisor_a0 = convert_period / base_period;
- devpriv->divisor_b1 = scan_period / base_period;
- break;
- }
- /* make sure a0 and b1 values are acceptable */
- if (devpriv->divisor_a0 < min_counter_value)
- devpriv->divisor_a0 = min_counter_value;
- if (devpriv->divisor_a0 > max_counter_value)
- devpriv->divisor_a0 = max_counter_value;
- if (devpriv->divisor_b1 < min_counter_value)
- devpriv->divisor_b1 = min_counter_value;
- if (devpriv->divisor_b1 > max_counter_value)
- devpriv->divisor_b1 = max_counter_value;
- /* write corrected timings to command */
- labpc_set_ai_convert_period(cmd, mode,
- base_period * devpriv->divisor_a0);
- labpc_set_ai_scan_period(cmd, mode,
- base_period * devpriv->divisor_b1);
- /*
- * if only one TRIG_TIMER is used, we can employ the generic
- * cascaded timing functions
- */
- } else if (scan_period) {
- /*
- * calculate cascaded counter values
- * that give desired scan timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_b1),
- &(devpriv->divisor_b0),
- &scan_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_scan_period(cmd, mode, scan_period);
- } else if (convert_period) {
- /*
- * calculate cascaded counter values
- * that give desired conversion timing
- */
- i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE,
- &(devpriv->divisor_a0),
- &(devpriv->divisor_b0),
- &convert_period,
- cmd->flags & TRIG_ROUND_MASK);
- labpc_set_ai_convert_period(cmd, mode, convert_period);
- }
-}
-
-static int labpc_dio_mem_callback(int dir, int port, int data,
- unsigned long iobase)
+static int labpc_8255_mmio(int dir, int port, int data, unsigned long iobase)
{
if (dir) {
writeb(data, (void __iomem *)(iobase + port));
@@ -1897,20 +1319,18 @@ static void labpc_serial_out(struct comedi_device *dev, unsigned int value,
for (i = 1; i <= value_width; i++) {
/* clear serial clock */
- devpriv->command5_bits &= ~SCLOCK_BIT;
+ devpriv->cmd5 &= ~CMD5_SCLK;
/* send bits most significant bit first */
if (value & (1 << (value_width - i)))
- devpriv->command5_bits |= SDATA_BIT;
+ devpriv->cmd5 |= CMD5_SDATA;
else
- devpriv->command5_bits &= ~SDATA_BIT;
+ devpriv->cmd5 &= ~CMD5_SDATA;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* set clock to load bit */
- devpriv->command5_bits |= SCLOCK_BIT;
+ devpriv->cmd5 |= CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
}
}
@@ -1924,20 +1344,17 @@ static unsigned int labpc_serial_in(struct comedi_device *dev)
for (i = 1; i <= value_width; i++) {
/* set serial clock */
- devpriv->command5_bits |= SCLOCK_BIT;
+ devpriv->cmd5 |= CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* clear clock bit */
- devpriv->command5_bits &= ~SCLOCK_BIT;
+ devpriv->cmd5 &= ~CMD5_SCLK;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits,
- dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* read bits most significant bit first */
udelay(1);
- devpriv->status2_bits =
- devpriv->read_byte(dev->iobase + STATUS2_REG);
- if (devpriv->status2_bits & EEPROM_OUT_BIT)
+ devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG);
+ if (devpriv->stat2 & STAT2_PROMOUT)
value |= 1 << (value_width - i);
}
@@ -1955,12 +1372,12 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev,
const int write_length = 8;
/* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send read instruction */
labpc_serial_out(dev, read_instruction, write_length);
@@ -1970,9 +1387,37 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev,
value = labpc_serial_in(dev);
/* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+
+ return value;
+}
+
+static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int value;
+ const int read_status_instruction = 0x5;
+ const int write_length = 8; /* 8 bit write lengths to eeprom */
+
+ /* enable read/write to eeprom */
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
+ udelay(1);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+
+ /* send read status instruction */
+ labpc_serial_out(dev, read_status_instruction, write_length);
+ /* read result */
+ value = labpc_serial_in(dev);
+
+ /* disable read/write to eeprom */
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
return value;
}
@@ -2002,68 +1447,40 @@ static int labpc_eeprom_write(struct comedi_device *dev,
devpriv->eeprom_data[address] = value;
/* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send write_enable instruction */
labpc_serial_out(dev, write_enable_instruction, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* send write instruction */
- devpriv->command5_bits |= EEPROM_EN_BIT;
+ devpriv->cmd5 |= CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
labpc_serial_out(dev, write_instruction, write_length);
/* send 8 bit address to write to */
labpc_serial_out(dev, address, write_length);
/* write value */
labpc_serial_out(dev, value, write_length);
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
+ devpriv->cmd5 &= ~CMD5_EEPROMCS;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
return 0;
}
-static unsigned int labpc_eeprom_read_status(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
- unsigned int value;
- const int read_status_instruction = 0x5;
- const int write_length = 8; /* 8 bit write lengths to eeprom */
-
- /* enable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
-
- /* send read status instruction */
- labpc_serial_out(dev, read_status_instruction, write_length);
- /* read result */
- value = labpc_serial_in(dev);
-
- /* disable read/write to eeprom */
- devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
- udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
-
- return value;
-}
-
/* writes to 8 bit calibration dacs */
static void write_caldac(struct comedi_device *dev, unsigned int channel,
unsigned int value)
@@ -2075,10 +1492,9 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
devpriv->caldac[channel] = value;
/* clear caldac load bit and make sure we don't write to eeprom */
- devpriv->command5_bits &=
- ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT;
+ devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT);
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
/* write 4 bit channel */
labpc_serial_out(dev, channel, 4);
@@ -2086,49 +1502,295 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
labpc_serial_out(dev, value, 8);
/* set and clear caldac bit to load caldac value */
- devpriv->command5_bits |= CALDAC_LOAD_BIT;
+ devpriv->cmd5 |= CMD5_CALDACLD;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
- devpriv->command5_bits &= ~CALDAC_LOAD_BIT;
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->cmd5 &= ~CMD5_CALDACLD;
udelay(1);
- devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG);
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
}
-static struct comedi_driver labpc_driver = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = labpc_attach,
- .auto_attach = labpc_auto_attach,
- .detach = labpc_common_detach,
- .num_names = ARRAY_SIZE(labpc_boards),
- .board_name = &labpc_boards[0].name,
- .offset = sizeof(struct labpc_board_struct),
-};
+static int labpc_calib_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
-#ifdef CONFIG_COMEDI_PCI_DRIVERS
-static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)},
- {0}
-};
-MODULE_DEVICE_TABLE(pci, labpc_pci_table);
+ /*
+ * Only write the last data value to the caldac. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0)
+ write_caldac(dev, chan, data[insn->n - 1]);
+
+ return insn->n;
+}
-static int labpc_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int labpc_calib_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- return comedi_pci_auto_config(dev, &labpc_driver);
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->caldac[chan];
+
+ return insn->n;
}
-static struct pci_driver labpc_pci_driver = {
- .name = DRV_NAME,
- .id_table = labpc_pci_table,
- .probe = labpc_pci_probe,
- .remove = comedi_pci_auto_unconfig,
+static int labpc_eeprom_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int ret;
+
+ /* only allow writes to user area of eeprom */
+ if (chan < 16 || chan > 127)
+ return -EINVAL;
+
+ /*
+ * Only write the last data value to the eeprom. Preceding
+ * data would be overwritten anyway.
+ */
+ if (insn->n > 0) {
+ ret = labpc_eeprom_write(dev, chan, data[insn->n - 1]);
+ if (ret)
+ return ret;
+ }
+
+ return insn->n;
+}
+
+static int labpc_eeprom_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct labpc_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int i;
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->eeprom_data[chan];
+
+ return insn->n;
+}
+
+int labpc_common_attach(struct comedi_device *dev,
+ unsigned int irq, unsigned long isr_flags)
+{
+ const struct labpc_boardinfo *board = comedi_board(dev);
+ struct labpc_private *devpriv = dev->private;
+ struct comedi_subdevice *s;
+ int ret;
+ int i;
+
+ if (board->has_mmio) {
+ devpriv->read_byte = labpc_readb;
+ devpriv->write_byte = labpc_writeb;
+ } else {
+ devpriv->read_byte = labpc_inb;
+ devpriv->write_byte = labpc_outb;
+ }
+
+ /* initialize board's command registers */
+ devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG);
+ devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG);
+ devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG);
+ devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG);
+ if (board->register_layout == labpc_1200_layout) {
+ devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG);
+ devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG);
+ }
+
+ if (irq) {
+ ret = request_irq(irq, labpc_interrupt, isr_flags,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = irq;
+ }
+
+ ret = comedi_alloc_subdevices(dev, 5);
+ if (ret)
+ return ret;
+
+ /* analog input subdevice */
+ s = &dev->subdevices[0];
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
+ s->n_chan = 8;
+ s->len_chanlist = 8;
+ s->maxdata = 0x0fff;
+ s->range_table = board->ai_range_table;
+ s->insn_read = labpc_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->do_cmd = labpc_ai_cmd;
+ s->do_cmdtest = labpc_ai_cmdtest;
+ s->cancel = labpc_cancel;
+ }
+
+ /* analog output */
+ s = &dev->subdevices[1];
+ if (board->has_ao) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
+ s->n_chan = NUM_AO_CHAN;
+ s->maxdata = 0x0fff;
+ s->range_table = &range_labpc_ao;
+ s->insn_read = labpc_ao_insn_read;
+ s->insn_write = labpc_ao_insn_write;
+
+ /* initialize analog outputs to a known value */
+ for (i = 0; i < s->n_chan; i++) {
+ short lsb, msb;
+
+ devpriv->ao_value[i] = s->maxdata / 2;
+ lsb = devpriv->ao_value[i] & 0xff;
+ msb = (devpriv->ao_value[i] >> 8) & 0xff;
+ devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i));
+ devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i));
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /* 8255 dio */
+ s = &dev->subdevices[2];
+ ret = subdev_8255_init(dev, s,
+ (board->has_mmio) ? labpc_8255_mmio : NULL,
+ dev->iobase + DIO_BASE_REG);
+ if (ret)
+ return ret;
+
+ /* calibration subdevices for boards that have one */
+ s = &dev->subdevices[3];
+ if (board->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 16;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_calib_insn_read;
+ s->insn_write = labpc_calib_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ write_caldac(dev, i, s->maxdata / 2);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
+
+ /* EEPROM */
+ s = &dev->subdevices[4];
+ if (board->register_layout == labpc_1200_layout) {
+ s->type = COMEDI_SUBD_MEMORY;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = EEPROM_SIZE;
+ s->maxdata = 0xff;
+ s->insn_read = labpc_eeprom_insn_read;
+ s->insn_write = labpc_eeprom_insn_write;
+
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i);
+ } else
+ s->type = COMEDI_SUBD_UNUSED;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(labpc_common_attach);
+
+void labpc_common_detach(struct comedi_device *dev)
+{
+ comedi_spriv_free(dev, 2);
+}
+EXPORT_SYMBOL_GPL(labpc_common_detach);
+
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA)
+static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct labpc_private *devpriv;
+ unsigned int irq = it->options[1];
+ unsigned int dma_chan = it->options[2];
+ int ret;
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ ret = comedi_request_region(dev, it->options[0], LABPC_SIZE);
+ if (ret)
+ return ret;
+
+ ret = labpc_common_attach(dev, irq, 0);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_ISA_DMA_API
+ if (dev->irq && (dma_chan == 1 || dma_chan == 3)) {
+ devpriv->dma_buffer = kmalloc(dma_buffer_size,
+ GFP_KERNEL | GFP_DMA);
+ if (devpriv->dma_buffer) {
+ ret = request_dma(dma_chan, dev->board_name);
+ if (ret == 0) {
+ unsigned long dma_flags;
+
+ devpriv->dma_chan = dma_chan;
+ dma_flags = claim_dma_lock();
+ disable_dma(devpriv->dma_chan);
+ set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
+ release_dma_lock(dma_flags);
+ } else {
+ kfree(devpriv->dma_buffer);
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static void labpc_detach(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ labpc_common_detach(dev);
+
+ if (devpriv) {
+ kfree(devpriv->dma_buffer);
+ if (devpriv->dma_chan)
+ free_dma(devpriv->dma_chan);
+ }
+ comedi_legacy_detach(dev);
+}
+
+static struct comedi_driver labpc_driver = {
+ .driver_name = "ni_labpc",
+ .module = THIS_MODULE,
+ .attach = labpc_attach,
+ .detach = labpc_detach,
+ .num_names = ARRAY_SIZE(labpc_boards),
+ .board_name = &labpc_boards[0].name,
+ .offset = sizeof(struct labpc_boardinfo),
};
-module_comedi_pci_driver(labpc_driver, labpc_pci_driver);
-#else
module_comedi_driver(labpc_driver);
-#endif
+#else
+static int __init labpc_common_init(void)
+{
+ return 0;
+}
+module_init(labpc_common_init);
+static void __exit labpc_common_exit(void)
+{
+}
+module_exit(labpc_common_exit);
+#endif
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index e052ed3ba544..615f16f271c0 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -27,48 +27,45 @@
#define EEPROM_SIZE 256 /* 256 byte eeprom */
#define NUM_AO_CHAN 2 /* boards have two analog output channels */
-enum labpc_bustype { isa_bustype, pci_bustype, pcmcia_bustype };
enum labpc_register_layout { labpc_plus_layout, labpc_1200_layout };
enum transfer_type { fifo_not_empty_transfer, fifo_half_full_transfer,
isa_dma_transfer
};
-struct labpc_board_struct {
+struct labpc_boardinfo {
const char *name;
int device_id; /* device id for pci and pcmcia boards */
int ai_speed; /* maximum input speed in nanoseconds */
- enum labpc_bustype bustype; /* ISA/PCI/etc. */
/* 1200 has extra registers compared to pc+ */
enum labpc_register_layout register_layout;
int has_ao; /* has analog output true/false */
const struct comedi_lrange *ai_range_table;
const int *ai_range_code;
- const int *ai_range_is_unipolar;
/* board can auto scan up in ai channels, not just down */
unsigned ai_scan_up:1;
/* uses memory mapped io instead of ioports */
- unsigned memory_mapped_io:1;
+ unsigned has_mmio:1;
};
struct labpc_private {
struct mite_struct *mite; /* for mite chip on pci-1200 */
/* number of data points left to be taken */
- volatile unsigned long long count;
+ unsigned long long count;
/* software copy of analog output values */
unsigned int ao_value[NUM_AO_CHAN];
/* software copys of bits written to command registers */
- volatile unsigned int command1_bits;
- volatile unsigned int command2_bits;
- volatile unsigned int command3_bits;
- volatile unsigned int command4_bits;
- volatile unsigned int command5_bits;
- volatile unsigned int command6_bits;
+ unsigned int cmd1;
+ unsigned int cmd2;
+ unsigned int cmd3;
+ unsigned int cmd4;
+ unsigned int cmd5;
+ unsigned int cmd6;
/* store last read of board status registers */
- volatile unsigned int status1_bits;
- volatile unsigned int status2_bits;
+ unsigned int stat1;
+ unsigned int stat2;
/*
* value to load into board's counter a0 (conversion pacing) for timed
* conversions
@@ -101,11 +98,10 @@ struct labpc_private {
void (*write_byte) (unsigned int byte, unsigned long address);
};
-int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
- unsigned int irq, unsigned int dma);
+int labpc_common_attach(struct comedi_device *dev,
+ unsigned int irq, unsigned long isr_flags);
void labpc_common_detach(struct comedi_device *dev);
-extern const int labpc_1200_is_unipolar[];
extern const int labpc_1200_ai_gain_bits[];
extern const struct comedi_lrange range_labpc_1200_ai;
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index be7d1413b2e5..9e3737c6918d 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -73,17 +73,15 @@ NI manuals:
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-static const struct labpc_board_struct labpc_cs_boards[] = {
+static const struct labpc_boardinfo labpc_cs_boards[] = {
{
.name = "daqcard-1200",
.device_id = 0x103,
.ai_speed = 10000,
- .bustype = pcmcia_bustype,
.register_layout = labpc_1200_layout,
.has_ao = 1,
.ai_range_table = &range_labpc_1200_ai,
.ai_range_code = labpc_1200_ai_gain_bits,
- .ai_range_is_unipolar = labpc_1200_is_unipolar,
},
};
@@ -112,7 +110,7 @@ static int labpc_auto_attach(struct comedi_device *dev,
return -ENOMEM;
dev->private = devpriv;
- return labpc_common_attach(dev, dev->iobase, link->irq, 0);
+ return labpc_common_attach(dev, link->irq, IRQF_SHARED);
}
static void labpc_detach(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
new file mode 100644
index 000000000000..8e916f86ccea
--- /dev/null
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -0,0 +1,142 @@
+/*
+ * comedi/drivers/ni_labpc_pci.c
+ * Driver for National Instruments Lab-PC PCI-1200
+ * Copyright (C) 2001, 2002, 2003 Frank Mori Hess <fmhess@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Driver: ni_labpc_pci
+ * Description: National Instruments Lab-PC PCI-1200
+ * Devices: (National Instruments) PCI-1200 [ni_pci-1200]
+ * Author: Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Status: works
+ *
+ * This is the PCI-specific support split off from the ni_labpc driver.
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ *
+ * NI manuals:
+ * 340914a (pci-1200)
+ */
+
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+#include "../comedidev.h"
+
+#include "mite.h"
+#include "ni_labpc.h"
+
+enum labpc_pci_boardid {
+ BOARD_NI_PCI1200,
+};
+
+static const struct labpc_boardinfo labpc_pci_boards[] = {
+ [BOARD_NI_PCI1200] = {
+ .name = "ni_pci-1200",
+ .ai_speed = 10000,
+ .register_layout = labpc_1200_layout,
+ .has_ao = 1,
+ .ai_range_table = &range_labpc_1200_ai,
+ .ai_range_code = labpc_1200_ai_gain_bits,
+ .ai_scan_up = 1,
+ .has_mmio = 1,
+ },
+};
+
+static int labpc_pci_auto_attach(struct comedi_device *dev,
+ unsigned long context)
+{
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct labpc_boardinfo *board = NULL;
+ struct labpc_private *devpriv;
+ int ret;
+
+ if (context < ARRAY_SIZE(labpc_pci_boards))
+ board = &labpc_pci_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
+ devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
+ if (!devpriv)
+ return -ENOMEM;
+ dev->private = devpriv;
+
+ devpriv->mite = mite_alloc(pcidev);
+ if (!devpriv->mite)
+ return -ENOMEM;
+ ret = mite_setup(devpriv->mite);
+ if (ret < 0)
+ return ret;
+ dev->iobase = (unsigned long)devpriv->mite->daq_io_addr;
+
+ return labpc_common_attach(dev, mite_irq(devpriv->mite), IRQF_SHARED);
+}
+
+static void labpc_pci_detach(struct comedi_device *dev)
+{
+ struct labpc_private *devpriv = dev->private;
+
+ labpc_common_detach(dev);
+
+ if (devpriv && devpriv->mite) {
+ mite_unsetup(devpriv->mite);
+ mite_free(devpriv->mite);
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ comedi_pci_disable(dev);
+}
+
+static struct comedi_driver labpc_pci_comedi_driver = {
+ .driver_name = "labpc_pci",
+ .module = THIS_MODULE,
+ .auto_attach = labpc_pci_auto_attach,
+ .detach = labpc_pci_detach,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = {
+ { PCI_VDEVICE(NI, 0x161), BOARD_NI_PCI1200 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, labpc_pci_table);
+
+static int labpc_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &labpc_pci_comedi_driver,
+ id->driver_data);
+}
+
+static struct pci_driver labpc_pci_driver = {
+ .name = "labpc_pci",
+ .id_table = labpc_pci_table,
+ .probe = labpc_pci_probe,
+ .remove = comedi_pci_auto_unconfig,
+};
+module_comedi_pci_driver(labpc_pci_comedi_driver, labpc_pci_driver);
+
+MODULE_DESCRIPTION("Comedi: National Instruments Lab-PC PCI-1200 driver");
+MODULE_AUTHOR("Comedi http://www.comedi.org");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index b7403597e905..a46d579016d9 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -189,11 +189,6 @@ static const struct comedi_lrange range_ni_M_ai_628x = { 7, {
}
};
-static const struct comedi_lrange range_ni_S_ai_6143 = { 1, {
- RANGE(-5, +5),
- }
-};
-
static const struct comedi_lrange range_ni_E_ao_ext = { 4, {
RANGE(-10, 10),
RANGE(0, 10),
@@ -210,7 +205,7 @@ static const struct comedi_lrange *const ni_range_lkup[] = {
[ai_gain_611x] = &range_ni_E_ai_611x,
[ai_gain_622x] = &range_ni_M_ai_622x,
[ai_gain_628x] = &range_ni_M_ai_628x,
- [ai_gain_6143] = &range_ni_S_ai_6143
+ [ai_gain_6143] = &range_bipolar5
};
static int ni_dio_insn_config(struct comedi_device *dev,
@@ -696,9 +691,10 @@ static void ni_release_cdo_mite_channel(struct comedi_device *dev)
static void ni_e_series_enable_second_irq(struct comedi_device *dev,
unsigned gpct_index, short enable)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
return;
switch (gpct_index) {
case 0:
@@ -728,16 +724,17 @@ static void ni_e_series_enable_second_irq(struct comedi_device *dev,
static void ni_clear_ai_fifo(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
- if (boardtype.reg_type == ni_reg_6143) {
+ if (board->reg_type == ni_reg_6143) {
/* Flush the 6143 data FIFO */
ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */
ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */
while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */
} else {
devpriv->stc_writew(dev, 1, ADC_FIFO_Clear);
- if (boardtype.reg_type == ni_reg_625x) {
+ if (board->reg_type == ni_reg_625x) {
ni_writeb(0, M_Offset_Static_AI_Control(0));
ni_writeb(1, M_Offset_Static_AI_Control(0));
#if 0
@@ -845,7 +842,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d)
struct mite_struct *mite = devpriv->mite;
#endif
- if (dev->attached == 0)
+ if (!dev->attached)
return IRQ_NONE;
smp_mb(); /* make sure dev->attached is checked before handler does anything else. */
@@ -1292,6 +1289,7 @@ static void ni_mio_print_status_b(int status)
static void ni_ao_fifo_load(struct comedi_device *dev,
struct comedi_subdevice *s, int n)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
int chan;
@@ -1309,10 +1307,10 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
range = CR_RANGE(cmd->chanlist[chan]);
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask) {
packed_data = d & 0xffff;
/* 6711 only has 16 bit wide ao fifo */
- if (boardtype.reg_type != ni_reg_6711) {
+ if (board->reg_type != ni_reg_6711) {
err &= comedi_buf_get(async, &d);
if (err == 0)
break;
@@ -1352,6 +1350,7 @@ static void ni_ao_fifo_load(struct comedi_device *dev,
static int ni_ao_fifo_half_empty(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
int n;
n = comedi_buf_read_n_available(s->async);
@@ -1361,8 +1360,8 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev,
}
n /= sizeof(short);
- if (n > boardtype.ao_fifo_depth / 2)
- n = boardtype.ao_fifo_depth / 2;
+ if (n > board->ao_fifo_depth / 2)
+ n = board->ao_fifo_depth / 2;
ni_ao_fifo_load(dev, s, n);
@@ -1374,12 +1373,13 @@ static int ni_ao_fifo_half_empty(struct comedi_device *dev,
static int ni_ao_prep_fifo(struct comedi_device *dev,
struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int n;
/* reset fifo */
devpriv->stc_writew(dev, 1, DAC_FIFO_Clear);
- if (boardtype.reg_type & ni_reg_6xxx_mask)
+ if (board->reg_type & ni_reg_6xxx_mask)
ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
/* load some data */
@@ -1388,8 +1388,8 @@ static int ni_ao_prep_fifo(struct comedi_device *dev,
return 0;
n /= sizeof(short);
- if (n > boardtype.ao_fifo_depth)
- n = boardtype.ao_fifo_depth;
+ if (n > board->ao_fifo_depth)
+ n = board->ao_fifo_depth;
ni_ao_fifo_load(dev, s, n);
@@ -1399,11 +1399,12 @@ static int ni_ao_prep_fifo(struct comedi_device *dev,
static void ni_ai_fifo_read(struct comedi_device *dev,
struct comedi_subdevice *s, int n)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
struct comedi_async *async = s->async;
int i;
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
short data[2];
u32 dl;
@@ -1420,7 +1421,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev,
data[0] = dl & 0xffff;
cfc_write_to_buffer(s, data[0]);
}
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
short data[2];
u32 dl;
@@ -1458,10 +1459,11 @@ static void ni_ai_fifo_read(struct comedi_device *dev,
static void ni_handle_fifo_half_full(struct comedi_device *dev)
{
- int n;
+ const struct ni_board_struct *board = comedi_board(dev);
struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
+ int n;
- n = boardtype.ai_fifo_depth / 2;
+ n = board->ai_fifo_depth / 2;
ni_ai_fifo_read(dev, s, n);
}
@@ -1508,6 +1510,7 @@ static int ni_ai_drain_dma(struct comedi_device *dev)
*/
static void ni_handle_fifo_dregs(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
short data[2];
@@ -1515,7 +1518,7 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev)
short fifo_empty;
int i;
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
while ((devpriv->stc_readw(dev,
AI_Status_1_Register) &
AI_FIFO_Empty_St) == 0) {
@@ -1526,7 +1529,7 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev)
data[1] = (dl & 0xffff);
cfc_write_array_to_buffer(s, data, sizeof(data));
}
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
i = 0;
while (ni_readl(AIFIFO_Status_6143) & 0x04) {
dl = ni_readl(AIFIFO_Data_6143);
@@ -1573,12 +1576,13 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev)
static void get_last_sample_611x(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv __maybe_unused = dev->private;
struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
short data;
u32 dl;
- if (boardtype.reg_type != ni_reg_611x)
+ if (board->reg_type != ni_reg_611x)
return;
/* Check if there's a single sample stuck in the FIFO */
@@ -1591,12 +1595,13 @@ static void get_last_sample_611x(struct comedi_device *dev)
static void get_last_sample_6143(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv __maybe_unused = dev->private;
struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
short data;
u32 dl;
- if (boardtype.reg_type != ni_reg_6143)
+ if (board->reg_type != ni_reg_6143)
return;
/* Check if there's a single sample stuck in the FIFO */
@@ -1641,6 +1646,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s,
static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV];
int retval;
@@ -1660,7 +1666,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
return -EIO;
}
- switch (boardtype.reg_type) {
+ switch (board->reg_type) {
case ni_reg_611x:
case ni_reg_6143:
mite_prep_dma(devpriv->ai_mite_chan, 32, 16);
@@ -1681,6 +1687,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev)
static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV];
int retval;
@@ -1695,7 +1702,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->ao_mite_chan) {
- if (boardtype.reg_type & (ni_reg_611x | ni_reg_6713)) {
+ if (board->reg_type & (ni_reg_611x | ni_reg_6713)) {
mite_prep_dma(devpriv->ao_mite_chan, 32, 32);
} else {
/* doing 32 instead of 16 bit wide transfers from memory
@@ -1720,6 +1727,7 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev)
static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
ni_release_ai_mite_channel(dev);
@@ -1735,7 +1743,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
ni_clear_ai_fifo(dev);
- if (boardtype.reg_type != ni_reg_6143)
+ if (board->reg_type != ni_reg_6143)
ni_writeb(0, Misc_Command);
devpriv->stc_writew(dev, AI_Disarm, AI_Command_1_Register); /* reset pulses */
@@ -1746,7 +1754,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->stc_writew(dev, 0x0000, AI_Mode_2_Register);
/* generate FIFO interrupts on non-empty */
devpriv->stc_writew(dev, (0 << 6) | 0x0000, AI_Mode_3_Register);
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
AI_SOC_Polarity |
AI_LOCALMUX_CLK_Pulse_Width,
@@ -1759,7 +1767,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
AI_CONVERT_Output_Select
(AI_CONVERT_Output_Enable_High),
AI_Output_Control_Register);
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width |
AI_SOC_Polarity |
AI_LOCALMUX_CLK_Pulse_Width,
@@ -1784,7 +1792,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s)
AI_EXTMUX_CLK_Output_Select(0) |
AI_LOCALMUX_CLK_Output_Select(2) |
AI_SC_TC_Output_Select(3);
- if (boardtype.reg_type == ni_reg_622x)
+ if (board->reg_type == ni_reg_622x)
ai_output_control_bits |=
AI_CONVERT_Output_Select
(AI_CONVERT_Output_Enable_High);
@@ -1832,9 +1840,10 @@ static int ni_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int i, n;
- const unsigned int mask = (1 << boardtype.adbits) - 1;
+ const unsigned int mask = (1 << board->adbits) - 1;
unsigned signbits;
unsigned short d;
unsigned long dl;
@@ -1844,7 +1853,7 @@ static int ni_ai_insn_read(struct comedi_device *dev,
ni_clear_ai_fifo(dev);
signbits = devpriv->ai_offset[0];
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
for (n = 0; n < num_adc_stages_611x; n++) {
devpriv->stc_writew(dev, AI_CONVERT_Pulse,
AI_Command_1_Register);
@@ -1877,7 +1886,7 @@ static int ni_ai_insn_read(struct comedi_device *dev,
d += signbits;
data[n] = d;
}
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
for (n = 0; n < insn->n; n++) {
devpriv->stc_writew(dev, AI_CONVERT_Pulse,
AI_Command_1_Register);
@@ -1913,7 +1922,7 @@ static int ni_ai_insn_read(struct comedi_device *dev,
("ni_mio_common: timeout in ni_ai_insn_read\n");
return -ETIME;
}
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
data[n] =
ni_readl(M_Offset_AI_FIFO_Data) & mask;
} else {
@@ -1948,6 +1957,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
unsigned int n_chan,
unsigned int *list)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int chan, range, aref;
unsigned int i;
@@ -1957,12 +1967,12 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
devpriv->stc_writew(dev, 1, Configuration_Memory_Clear);
-/* offset = 1 << (boardtype.adbits - 1); */
+/* offset = 1 << (board->adbits - 1); */
if ((list[0] & CR_ALT_SOURCE)) {
unsigned bypass_bits;
chan = CR_CHAN(list[0]);
range = CR_RANGE(list[0]);
- range_code = ni_gainlkup[boardtype.gainlkup][range];
+ range_code = ni_gainlkup[board->gainlkup][range];
dither = ((list[0] & CR_ALT_FILTER) != 0);
bypass_bits = MSeries_AI_Bypass_Config_FIFO_Bit;
bypass_bits |= chan;
@@ -1989,7 +1999,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
range = CR_RANGE(list[i]);
dither = ((list[i] & CR_ALT_FILTER) != 0);
- range_code = ni_gainlkup[boardtype.gainlkup][range];
+ range_code = ni_gainlkup[board->gainlkup][range];
devpriv->ai_offset[i] = offset;
switch (aref) {
case AREF_DIFF:
@@ -2009,7 +2019,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
}
config_bits |= MSeries_AI_Config_Channel_Bits(chan);
config_bits |=
- MSeries_AI_Config_Bank_Bits(boardtype.reg_type, chan);
+ MSeries_AI_Config_Bank_Bits(board->reg_type, chan);
config_bits |= MSeries_AI_Config_Gain_Bits(range_code);
if (i == n_chan - 1)
config_bits |= MSeries_AI_Config_Last_Channel_Bit;
@@ -2054,6 +2064,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev,
static void ni_load_channelgain_list(struct comedi_device *dev,
unsigned int n_chan, unsigned int *list)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int chan, range, aref;
unsigned int i;
@@ -2061,12 +2072,12 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
unsigned offset;
unsigned int dither;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
ni_m_series_load_channelgain_list(dev, n_chan, list);
return;
}
- if (n_chan == 1 && (boardtype.reg_type != ni_reg_611x)
- && (boardtype.reg_type != ni_reg_6143)) {
+ if (n_chan == 1 && (board->reg_type != ni_reg_611x)
+ && (board->reg_type != ni_reg_6143)) {
if (devpriv->changain_state
&& devpriv->changain_spec == list[0]) {
/* ready to go. */
@@ -2081,7 +2092,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
devpriv->stc_writew(dev, 1, Configuration_Memory_Clear);
/* Set up Calibration mode if required */
- if (boardtype.reg_type == ni_reg_6143) {
+ if (board->reg_type == ni_reg_6143) {
if ((list[0] & CR_ALT_SOURCE)
&& !devpriv->ai_calib_source_enabled) {
/* Strobe Relay enable bit */
@@ -2105,9 +2116,9 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
}
}
- offset = 1 << (boardtype.adbits - 1);
+ offset = 1 << (board->adbits - 1);
for (i = 0; i < n_chan; i++) {
- if ((boardtype.reg_type != ni_reg_6143)
+ if ((board->reg_type != ni_reg_6143)
&& (list[i] & CR_ALT_SOURCE)) {
chan = devpriv->ai_calib_source;
} else {
@@ -2118,21 +2129,21 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
dither = ((list[i] & CR_ALT_FILTER) != 0);
/* fix the external/internal range differences */
- range = ni_gainlkup[boardtype.gainlkup][range];
- if (boardtype.reg_type == ni_reg_611x)
+ range = ni_gainlkup[board->gainlkup][range];
+ if (board->reg_type == ni_reg_611x)
devpriv->ai_offset[i] = offset;
else
devpriv->ai_offset[i] = (range & 0x100) ? 0 : offset;
hi = 0;
if ((list[i] & CR_ALT_SOURCE)) {
- if (boardtype.reg_type == ni_reg_611x)
+ if (board->reg_type == ni_reg_611x)
ni_writew(CR_CHAN(list[i]) & 0x0003,
Calibration_Channel_Select_611x);
} else {
- if (boardtype.reg_type == ni_reg_611x)
+ if (board->reg_type == ni_reg_611x)
aref = AREF_DIFF;
- else if (boardtype.reg_type == ni_reg_6143)
+ else if (board->reg_type == ni_reg_6143)
aref = AREF_OTHER;
switch (aref) {
case AREF_DIFF:
@@ -2152,7 +2163,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
ni_writew(hi, Configuration_Memory_High);
- if (boardtype.reg_type != ni_reg_6143) {
+ if (board->reg_type != ni_reg_6143) {
lo = range;
if (i == n_chan - 1)
lo |= AI_LAST_CHANNEL;
@@ -2164,8 +2175,8 @@ static void ni_load_channelgain_list(struct comedi_device *dev,
}
/* prime the channel/gain list */
- if ((boardtype.reg_type != ni_reg_611x)
- && (boardtype.reg_type != ni_reg_6143)) {
+ if ((board->reg_type != ni_reg_611x)
+ && (board->reg_type != ni_reg_6143)) {
ni_prime_channelgain_list(dev);
}
}
@@ -2201,22 +2212,25 @@ static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer)
static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev,
unsigned num_channels)
{
- switch (boardtype.reg_type) {
+ const struct ni_board_struct *board = comedi_board(dev);
+
+ switch (board->reg_type) {
case ni_reg_611x:
case ni_reg_6143:
/* simultaneously-sampled inputs */
- return boardtype.ai_speed;
+ return board->ai_speed;
break;
default:
/* multiplexed inputs */
break;
}
- return boardtype.ai_speed * num_channels;
+ return board->ai_speed * num_channels;
}
static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int err = 0;
int tmp;
@@ -2233,8 +2247,8 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
TRIG_TIMER | TRIG_EXT);
sources = TRIG_TIMER | TRIG_EXT;
- if (boardtype.reg_type == ni_reg_611x ||
- boardtype.reg_type == ni_reg_6143)
+ if (board->reg_type == ni_reg_611x ||
+ board->reg_type == ni_reg_6143)
sources |= TRIG_NOW;
err |= cfc_check_trigger_src(&cmd->convert_src, sources);
@@ -2289,12 +2303,12 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
}
if (cmd->convert_src == TRIG_TIMER) {
- if ((boardtype.reg_type == ni_reg_611x)
- || (boardtype.reg_type == ni_reg_6143)) {
+ if ((board->reg_type == ni_reg_611x)
+ || (board->reg_type == ni_reg_6143)) {
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
} else {
err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- boardtype.ai_speed);
+ board->ai_speed);
err |= cfc_check_trigger_arg_max(&cmd->convert_arg,
devpriv->clock_ns * 0xffff);
}
@@ -2315,7 +2329,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (cmd->stop_src == TRIG_COUNT) {
unsigned int max_count = 0x01000000;
- if (boardtype.reg_type == ni_reg_611x)
+ if (board->reg_type == ni_reg_611x)
max_count -= num_adc_stages_611x;
err |= cfc_check_trigger_arg_max(&cmd->stop_arg, max_count);
err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
@@ -2341,8 +2355,8 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
err++;
}
if (cmd->convert_src == TRIG_TIMER) {
- if ((boardtype.reg_type != ni_reg_611x)
- && (boardtype.reg_type != ni_reg_6143)) {
+ if ((board->reg_type != ni_reg_611x)
+ && (board->reg_type != ni_reg_6143)) {
tmp = cmd->convert_arg;
cmd->convert_arg =
ni_timer_to_ns(dev, ni_ns_to_timer(dev,
@@ -2370,6 +2384,7 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
const struct comedi_cmd *cmd = &s->async->cmd;
int timer;
@@ -2426,8 +2441,8 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
mode2 &= ~AI_SC_Reload_Mode;
devpriv->stc_writew(dev, mode2, AI_Mode_2_Register);
- if (cmd->chanlist_len == 1 || (boardtype.reg_type == ni_reg_611x)
- || (boardtype.reg_type == ni_reg_6143)) {
+ if (cmd->chanlist_len == 1 || (board->reg_type == ni_reg_611x)
+ || (board->reg_type == ni_reg_6143)) {
start_stop_select |= AI_STOP_Polarity;
start_stop_select |= AI_STOP_Select(31); /* logic low */
start_stop_select |= AI_STOP_Sync;
@@ -2442,7 +2457,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
case TRIG_COUNT:
stop_count = cmd->stop_arg - 1;
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
/* have to take 3 stage adc pipeline into account */
stop_count += num_adc_stages_611x;
}
@@ -2698,6 +2713,7 @@ static int ni_ai_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
if (insn->n < 1)
@@ -2707,7 +2723,7 @@ static int ni_ai_insn_config(struct comedi_device *dev,
case INSN_CONFIG_ANALOG_TRIG:
return ni_ai_config_analog_trig(dev, s, insn, data);
case INSN_CONFIG_ALT_SOURCE:
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
if (data[1] & ~(MSeries_AI_Bypass_Cal_Sel_Pos_Mask |
MSeries_AI_Bypass_Cal_Sel_Neg_Mask |
MSeries_AI_Bypass_Mode_Mux_Mask |
@@ -2715,7 +2731,7 @@ static int ni_ai_insn_config(struct comedi_device *dev,
return -EINVAL;
}
devpriv->ai_calib_source = data[1];
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
unsigned int calib_source;
calib_source = data[1] & 0xf;
@@ -2735,7 +2751,7 @@ static int ni_ai_insn_config(struct comedi_device *dev,
if (calib_source >= 8)
return -EINVAL;
devpriv->ai_calib_source = calib_source;
- if (boardtype.reg_type == ni_reg_611x) {
+ if (board->reg_type == ni_reg_611x) {
ni_writeb(calib_source_adjust,
Cal_Gain_Select_611x);
}
@@ -2753,6 +2769,7 @@ static int ni_ai_config_analog_trig(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int a, b, modebits;
int err = 0;
@@ -2761,14 +2778,14 @@ static int ni_ai_config_analog_trig(struct comedi_device *dev,
* data[2] is analog line
* data[3] is set level
* data[4] is reset level */
- if (!boardtype.has_analog_trig)
+ if (!board->has_analog_trig)
return -EINVAL;
if ((data[1] & 0xffff0000) != COMEDI_EV_SCAN_BEGIN) {
data[1] &= (COMEDI_EV_SCAN_BEGIN | 0xffff);
err++;
}
- if (data[2] >= boardtype.n_adchan) {
- data[2] = boardtype.n_adchan - 1;
+ if (data[2] >= board->n_adchan) {
+ data[2] = board->n_adchan - 1;
err++;
}
if (data[3] > 255) { /* a */
@@ -2852,6 +2869,7 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
void *data, unsigned int num_bytes,
unsigned int chan_index)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct comedi_async *async = s->async;
unsigned int range;
unsigned int i;
@@ -2859,10 +2877,10 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int length = num_bytes / sizeof(short);
short *array = data;
- offset = 1 << (boardtype.aobits - 1);
+ offset = 1 << (board->aobits - 1);
for (i = 0; i < length; i++) {
range = CR_RANGE(async->cmd.chanlist[chan_index]);
- if (boardtype.ao_unipolar == 0 || (range & 1) == 0)
+ if (board->ao_unipolar == 0 || (range & 1) == 0)
array[i] -= offset;
#ifdef PCIDMA
array[i] = cpu_to_le16(array[i]);
@@ -2877,6 +2895,7 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device *dev,
unsigned int chanspec[],
unsigned int n_chans, int timed)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int range;
unsigned int chan;
@@ -2885,7 +2904,7 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device *dev,
int invert = 0;
if (timed) {
- for (i = 0; i < boardtype.n_aochan; ++i) {
+ for (i = 0; i < board->n_aochan; ++i) {
devpriv->ao_conf[i] &= ~MSeries_AO_Update_Timed_Bit;
ni_writeb(devpriv->ao_conf[i],
M_Offset_AO_Config_Bank(i));
@@ -2949,6 +2968,7 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev,
unsigned int chanspec[],
unsigned int n_chans)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int range;
unsigned int chan;
@@ -2961,10 +2981,10 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev,
range = CR_RANGE(chanspec[i]);
conf = AO_Channel(chan);
- if (boardtype.ao_unipolar) {
+ if (board->ao_unipolar) {
if ((range & 1) == 0) {
conf |= AO_Bipolar;
- invert = (1 << (boardtype.aobits - 1));
+ invert = (1 << (board->aobits - 1));
} else {
invert = 0;
}
@@ -2972,7 +2992,7 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev,
conf |= AO_Ext_Ref;
} else {
conf |= AO_Bipolar;
- invert = (1 << (boardtype.aobits - 1));
+ invert = (1 << (board->aobits - 1));
}
/* not all boards can deglitch, but this shouldn't hurt */
@@ -2995,7 +3015,9 @@ static int ni_ao_config_chanlist(struct comedi_device *dev,
unsigned int chanspec[], unsigned int n_chans,
int timed)
{
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ const struct ni_board_struct *board = comedi_board(dev);
+
+ if (board->reg_type & ni_reg_m_series_mask)
return ni_m_series_ao_config_chanlist(dev, s, chanspec, n_chans,
timed);
else
@@ -3017,6 +3039,7 @@ static int ni_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int invert;
@@ -3025,7 +3048,7 @@ static int ni_ao_insn_write(struct comedi_device *dev,
devpriv->ao[chan] = data[0];
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
ni_writew(data[0], M_Offset_DAC_Direct_Data(chan));
} else
ni_writew(data[0] ^ invert,
@@ -3038,12 +3061,13 @@ static int ni_ao_insn_write_671x(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int invert;
ao_win_out(1 << chan, AO_Immediate_671x);
- invert = 1 << (boardtype.aobits - 1);
+ invert = 1 << (board->aobits - 1);
ni_ao_config_chanlist(dev, s, &insn->chanspec, 1, 0);
@@ -3057,13 +3081,14 @@ static int ni_ao_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
switch (data[0]) {
case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE:
switch (data[1]) {
case COMEDI_OUTPUT:
- data[2] = 1 + boardtype.ao_fifo_depth * sizeof(short);
+ data[2] = 1 + board->ao_fifo_depth * sizeof(short);
if (devpriv->mite)
data[2] += devpriv->mite->fifo_size;
break;
@@ -3085,6 +3110,7 @@ static int ni_ao_insn_config(struct comedi_device *dev,
static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned int trignum)
{
+ const struct ni_board_struct *board __maybe_unused = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int ret;
int interrupt_b_bits;
@@ -3104,7 +3130,7 @@ static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
interrupt_b_bits = AO_Error_Interrupt_Enable;
#ifdef PCIDMA
devpriv->stc_writew(dev, 1, DAC_FIFO_Clear);
- if (boardtype.reg_type & ni_reg_6xxx_mask)
+ if (board->reg_type & ni_reg_6xxx_mask)
ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x);
ret = ni_ao_setup_MITE_dma(dev);
if (ret)
@@ -3155,6 +3181,7 @@ static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s,
static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
const struct comedi_cmd *cmd = &s->async->cmd;
int bits;
@@ -3170,7 +3197,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->stc_writew(dev, AO_Disarm, AO_Command_1_Register);
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask) {
ao_win_out(CLEAR_WG, AO_Misc_611x);
bits = 0;
@@ -3233,7 +3260,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
switch (cmd->stop_src) {
case TRIG_COUNT:
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
/* this is how the NI example code does it for m-series boards, verified correct with 6259 */
devpriv->stc_writel(dev, cmd->stop_arg - 1,
AO_UC_Load_A_Register);
@@ -3301,8 +3328,8 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
unsigned bits;
devpriv->ao_mode1 &= ~AO_Multiple_Channels;
bits = AO_UPDATE_Output_Select(AO_Update_Output_High_Z);
- if (boardtype.
- reg_type & (ni_reg_m_series_mask | ni_reg_6xxx_mask)) {
+ if (board->reg_type &
+ (ni_reg_m_series_mask | ni_reg_6xxx_mask)) {
bits |= AO_Number_Of_Channels(0);
} else {
bits |=
@@ -3329,14 +3356,14 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
bits = AO_BC_Source_Select | AO_UPDATE_Pulse_Width |
AO_TMRDACWR_Pulse_Width;
- if (boardtype.ao_fifo_depth)
+ if (board->ao_fifo_depth)
bits |= AO_FIFO_Enable;
else
bits |= AO_DMA_PIO_Control;
#if 0
/* F Hess: windows driver does not set AO_Number_Of_DAC_Packages bit for 6281,
verified with bus analyzer. */
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
bits |= AO_Number_Of_DAC_Packages;
#endif
devpriv->stc_writew(dev, bits, AO_Personal_Register);
@@ -3360,6 +3387,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int err = 0;
int tmp;
@@ -3407,7 +3435,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
if (cmd->scan_begin_src == TRIG_TIMER) {
err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
- boardtype.ao_speed);
+ board->ao_speed);
err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
devpriv->clock_ns * 0xffffff);
}
@@ -3448,6 +3476,7 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
/* devpriv->ao0p=0x0000; */
@@ -3475,7 +3504,7 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register);
devpriv->ao_mode2 = 0;
devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register);
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
devpriv->ao_mode3 = AO_Last_Gate_Disable;
else
devpriv->ao_mode3 = 0;
@@ -3483,7 +3512,7 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ao_trigger_select = 0;
devpriv->stc_writew(dev, devpriv->ao_trigger_select,
AO_Trigger_Select_Register);
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask) {
unsigned immediate_bits = 0;
unsigned i;
for (i = 0; i < s->n_chan; ++i) {
@@ -3784,6 +3813,7 @@ static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
static void handle_cdio_interrupt(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv __maybe_unused = dev->private;
unsigned cdio_status;
struct comedi_subdevice *s = &dev->subdevices[NI_DIO_SUBDEV];
@@ -3791,7 +3821,7 @@ static void handle_cdio_interrupt(struct comedi_device *dev)
unsigned long flags;
#endif
- if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) {
+ if ((board->reg_type & ni_reg_m_series_mask) == 0) {
return;
}
#ifdef PCIDMA
@@ -4039,17 +4069,13 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev,
static void mio_common_detach(struct comedi_device *dev)
{
struct ni_private *devpriv = dev->private;
- struct comedi_subdevice *s;
if (devpriv) {
if (devpriv->counter_dev) {
ni_gpct_device_destroy(devpriv->counter_dev);
}
}
- if (dev->subdevices && boardtype.has_8255) {
- s = &dev->subdevices[NI_8255_DIO_SUBDEV];
- subdev_8255_cleanup(dev, s);
- }
+ comedi_spriv_free(dev, NI_8255_DIO_SUBDEV);
}
static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -4355,14 +4381,15 @@ static int ni_alloc_private(struct comedi_device *dev)
static int ni_E_init(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
struct comedi_subdevice *s;
unsigned j;
enum ni_gpct_variant counter_variant;
int ret;
- if (boardtype.n_aochan > MAX_N_AO_CHAN) {
- printk("bug! boardtype.n_aochan > MAX_N_AO_CHAN\n");
+ if (board->n_aochan > MAX_N_AO_CHAN) {
+ printk("bug! n_aochan > MAX_N_AO_CHAN\n");
return -EINVAL;
}
@@ -4374,20 +4401,20 @@ static int ni_E_init(struct comedi_device *dev)
s = &dev->subdevices[NI_AI_SUBDEV];
dev->read_subdev = s;
- if (boardtype.n_adchan) {
+ if (board->n_adchan) {
s->type = COMEDI_SUBD_AI;
s->subdev_flags =
SDF_READABLE | SDF_DIFF | SDF_DITHER | SDF_CMD_READ;
- if (boardtype.reg_type != ni_reg_611x)
+ if (board->reg_type != ni_reg_611x)
s->subdev_flags |= SDF_GROUND | SDF_COMMON | SDF_OTHER;
- if (boardtype.adbits > 16)
+ if (board->adbits > 16)
s->subdev_flags |= SDF_LSAMPL;
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
- s->n_chan = boardtype.n_adchan;
+ s->n_chan = board->n_adchan;
s->len_chanlist = 512;
- s->maxdata = (1 << boardtype.adbits) - 1;
- s->range_table = ni_range_lkup[boardtype.gainlkup];
+ s->maxdata = (1 << board->adbits) - 1;
+ s->range_table = ni_range_lkup[board->gainlkup];
s->insn_read = &ni_ai_insn_read;
s->insn_config = &ni_ai_insn_config;
s->do_cmdtest = &ni_ai_cmdtest;
@@ -4405,40 +4432,40 @@ static int ni_E_init(struct comedi_device *dev)
/* analog output subdevice */
s = &dev->subdevices[NI_AO_SUBDEV];
- if (boardtype.n_aochan) {
+ if (board->n_aochan) {
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND;
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
s->subdev_flags |= SDF_SOFT_CALIBRATED;
- s->n_chan = boardtype.n_aochan;
- s->maxdata = (1 << boardtype.aobits) - 1;
- s->range_table = boardtype.ao_range_table;
+ s->n_chan = board->n_aochan;
+ s->maxdata = (1 << board->aobits) - 1;
+ s->range_table = board->ao_range_table;
s->insn_read = &ni_ao_insn_read;
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask) {
s->insn_write = &ni_ao_insn_write_671x;
} else {
s->insn_write = &ni_ao_insn_write;
}
s->insn_config = &ni_ao_insn_config;
#ifdef PCIDMA
- if (boardtype.n_aochan) {
+ if (board->n_aochan) {
s->async_dma_dir = DMA_TO_DEVICE;
#else
- if (boardtype.ao_fifo_depth) {
+ if (board->ao_fifo_depth) {
#endif
dev->write_subdev = s;
s->subdev_flags |= SDF_CMD_WRITE;
s->do_cmd = &ni_ao_cmd;
s->do_cmdtest = &ni_ao_cmdtest;
- s->len_chanlist = boardtype.n_aochan;
- if ((boardtype.reg_type & ni_reg_m_series_mask) == 0)
+ s->len_chanlist = board->n_aochan;
+ if ((board->reg_type & ni_reg_m_series_mask) == 0)
s->munge = ni_ao_munge;
}
s->cancel = &ni_ao_reset;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
- if ((boardtype.reg_type & ni_reg_67xx_mask))
+ if ((board->reg_type & ni_reg_67xx_mask))
init_ao_67xx(dev, s);
/* digital i/o subdevice */
@@ -4449,8 +4476,8 @@ static int ni_E_init(struct comedi_device *dev)
s->maxdata = 1;
s->io_bits = 0; /* all bits input */
s->range_table = &range_digital;
- s->n_chan = boardtype.num_p0_dio_channels;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ s->n_chan = board->num_p0_dio_channels;
+ if (board->reg_type & ni_reg_m_series_mask) {
s->subdev_flags |=
SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */ ;
s->insn_bits = &ni_m_series_dio_insn_bits;
@@ -4472,7 +4499,7 @@ static int ni_E_init(struct comedi_device *dev)
/* 8255 device */
s = &dev->subdevices[NI_8255_DIO_SUBDEV];
- if (boardtype.has_8255) {
+ if (board->has_8255) {
subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev);
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -4485,14 +4512,14 @@ static int ni_E_init(struct comedi_device *dev)
/* calibration subdevice -- ai and ao */
s = &dev->subdevices[NI_CALIBRATION_SUBDEV];
s->type = COMEDI_SUBD_CALIB;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
/* internal PWM analog output used for AI nonlinearity calibration */
s->subdev_flags = SDF_INTERNAL;
s->insn_config = &ni_m_series_pwm_config;
s->n_chan = 1;
s->maxdata = 0;
ni_writel(0x0, M_Offset_Cal_PWM);
- } else if (boardtype.reg_type == ni_reg_6143) {
+ } else if (board->reg_type == ni_reg_6143) {
/* internal PWM analog output used for AI nonlinearity calibration */
s->subdev_flags = SDF_INTERNAL;
s->insn_config = &ni_6143_pwm_config;
@@ -4510,7 +4537,7 @@ static int ni_E_init(struct comedi_device *dev)
s->type = COMEDI_SUBD_MEMORY;
s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
s->maxdata = 0xff;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
s->n_chan = M_SERIES_EEPROM_SIZE;
s->insn_read = &ni_m_series_eeprom_insn_read;
} else {
@@ -4522,7 +4549,7 @@ static int ni_E_init(struct comedi_device *dev)
s = &dev->subdevices[NI_PFI_DIO_SUBDEV];
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
unsigned i;
s->n_chan = 16;
ni_writew(s->state, M_Offset_PFI_DO);
@@ -4534,7 +4561,7 @@ static int ni_E_init(struct comedi_device *dev)
s->n_chan = 10;
}
s->maxdata = 1;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
s->insn_bits = &ni_pfi_insn_bits;
}
s->insn_config = &ni_pfi_insn_config;
@@ -4542,11 +4569,11 @@ static int ni_E_init(struct comedi_device *dev)
/* cs5529 calibration adc */
s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV];
- if (boardtype.reg_type & ni_reg_67xx_mask) {
+ if (board->reg_type & ni_reg_67xx_mask) {
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL;
/* one channel for each analog output channel */
- s->n_chan = boardtype.n_aochan;
+ s->n_chan = board->n_aochan;
s->maxdata = (1 << 16) - 1;
s->range_table = &range_unknown; /* XXX */
s->insn_read = cs5529_ai_insn_read;
@@ -4576,7 +4603,7 @@ static int ni_E_init(struct comedi_device *dev)
s->insn_config = ni_rtsi_insn_config;
ni_rtsi_init(dev);
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
counter_variant = ni_gpct_variant_m_series;
} else {
counter_variant = ni_gpct_variant_e_series;
@@ -4594,7 +4621,7 @@ static int ni_E_init(struct comedi_device *dev)
SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ
/* | SDF_CMD_WRITE */ ;
s->n_chan = 3;
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
s->maxdata = 0xffffffff;
else
s->maxdata = 0xffffff;
@@ -4626,7 +4653,7 @@ static int ni_E_init(struct comedi_device *dev)
/* ai configuration */
s = &dev->subdevices[NI_AI_SUBDEV];
ni_ai_reset(dev, s);
- if ((boardtype.reg_type & ni_reg_6xxx_mask) == 0) {
+ if ((board->reg_type & ni_reg_6xxx_mask) == 0) {
/* BEAM is this needed for PCI-6143 ?? */
devpriv->clock_and_fout =
Slow_Internal_Time_Divide_By_2 |
@@ -4663,11 +4690,11 @@ static int ni_E_init(struct comedi_device *dev)
ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select);
ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select);
- if (boardtype.reg_type & ni_reg_6xxx_mask) {
+ if (board->reg_type & ni_reg_6xxx_mask) {
ni_writeb(0, Magic_611x);
- } else if (boardtype.reg_type & ni_reg_m_series_mask) {
+ } else if (board->reg_type & ni_reg_m_series_mask) {
int channel;
- for (channel = 0; channel < boardtype.n_aochan; ++channel) {
+ for (channel = 0; channel < board->n_aochan; ++channel) {
ni_writeb(0xf, M_Offset_AO_Waveform_Order(channel));
ni_writeb(0x0,
M_Offset_AO_Reference_Attenuation(channel));
@@ -4938,6 +4965,7 @@ static struct caldac_struct caldacs[] = {
static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
int i, j;
int n_dacs;
@@ -4947,12 +4975,12 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
int type;
int chan;
- type = boardtype.caldac[0];
+ type = board->caldac[0];
if (type == caldac_none)
return;
n_bits = caldacs[type].n_bits;
for (i = 0; i < 3; i++) {
- type = boardtype.caldac[i];
+ type = board->caldac[i];
if (type == caldac_none)
break;
if (caldacs[type].n_bits != n_bits)
@@ -4971,7 +4999,7 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
s->maxdata_list = maxdata_list = devpriv->caldac_maxdata_list;
chan = 0;
for (i = 0; i < n_dacs; i++) {
- type = boardtype.caldac[i];
+ type = board->caldac[i];
for (j = 0; j < caldacs[type].n_chans; j++) {
maxdata_list[chan] =
(1 << caldacs[type].n_bits) - 1;
@@ -4982,7 +5010,7 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
for (chan = 0; chan < s->n_chan; chan++)
ni_write_caldac(dev, i, s->maxdata_list[i] / 2);
} else {
- type = boardtype.caldac[0];
+ type = board->caldac[0];
s->maxdata = (1 << caldacs[type].n_bits) - 1;
for (chan = 0; chan < s->n_chan; chan++)
@@ -4992,6 +5020,7 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s)
static void ni_write_caldac(struct comedi_device *dev, int addr, int val)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int loadbit = 0, bits = 0, bit, bitstring = 0;
int i;
@@ -5003,7 +5032,7 @@ static void ni_write_caldac(struct comedi_device *dev, int addr, int val)
devpriv->caldacs[addr] = val;
for (i = 0; i < 3; i++) {
- type = boardtype.caldac[i];
+ type = board->caldac[i];
if (type == caldac_none)
break;
if (addr < caldacs[type].n_chans) {
@@ -5275,7 +5304,9 @@ static int ni_old_set_pfi_routing(struct comedi_device *dev, unsigned chan,
static int ni_set_pfi_routing(struct comedi_device *dev, unsigned chan,
unsigned source)
{
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ const struct ni_board_struct *board = comedi_board(dev);
+
+ if (board->reg_type & ni_reg_m_series_mask)
return ni_m_series_set_pfi_routing(dev, chan, source);
else
return ni_old_set_pfi_routing(dev, chan, source);
@@ -5336,7 +5367,9 @@ static unsigned ni_old_get_pfi_routing(struct comedi_device *dev, unsigned chan)
static unsigned ni_get_pfi_routing(struct comedi_device *dev, unsigned chan)
{
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ const struct ni_board_struct *board = comedi_board(dev);
+
+ if (board->reg_type & ni_reg_m_series_mask)
return ni_m_series_get_pfi_routing(dev, chan);
else
return ni_old_get_pfi_routing(dev, chan);
@@ -5345,10 +5378,11 @@ static unsigned ni_get_pfi_routing(struct comedi_device *dev, unsigned chan)
static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel,
enum ni_pfi_filter_select filter)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv __maybe_unused = dev->private;
unsigned bits;
- if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) {
+ if ((board->reg_type & ni_reg_m_series_mask) == 0) {
return -ENOTSUPP;
}
bits = ni_readl(M_Offset_PFI_Filter);
@@ -5362,9 +5396,10 @@ static int ni_pfi_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv __maybe_unused = dev->private;
- if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) {
+ if ((board->reg_type & ni_reg_m_series_mask) == 0) {
return -ENOTSUPP;
}
if (data[0]) {
@@ -5423,6 +5458,7 @@ static int ni_pfi_insn_config(struct comedi_device *dev,
*/
static void ni_rtsi_init(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
/* Initialises the RTSI bus signal switch to a default state */
@@ -5449,7 +5485,7 @@ static void ni_rtsi_init(struct comedi_device *dev)
RTSI_Trig_Output_Bits(5,
NI_RTSI_OUTPUT_G_SRC0) |
RTSI_Trig_Output_Bits(6, NI_RTSI_OUTPUT_G_GATE0);
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
devpriv->rtsi_trig_b_output_reg |=
RTSI_Trig_Output_Bits(7, NI_RTSI_OUTPUT_RTSI_OSC);
devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg,
@@ -5517,7 +5553,9 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns,
static inline unsigned num_configurable_rtsi_channels(struct comedi_device *dev)
{
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ const struct ni_board_struct *board = comedi_board(dev);
+
+ if (board->reg_type & ni_reg_m_series_mask)
return 8;
else
return 7;
@@ -5629,6 +5667,7 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev,
static int ni_set_master_clock(struct comedi_device *dev, unsigned source,
unsigned period_ns)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
if (source == NI_MIO_INTERNAL_CLOCK) {
@@ -5636,7 +5675,7 @@ static int ni_set_master_clock(struct comedi_device *dev, unsigned source,
devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg,
RTSI_Trig_Direction_Register);
devpriv->clock_ns = TIMEBASE_1_NS;
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
devpriv->clock_and_fout2 &=
~(MSeries_Timebase1_Select_Bit |
MSeries_Timebase3_Select_Bit);
@@ -5646,7 +5685,7 @@ static int ni_set_master_clock(struct comedi_device *dev, unsigned source,
}
devpriv->clock_source = source;
} else {
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
return ni_mseries_set_pll_master_clock(dev, source,
period_ns);
} else {
@@ -5676,6 +5715,8 @@ static int ni_set_master_clock(struct comedi_device *dev, unsigned source,
static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan,
unsigned source)
{
+ const struct ni_board_struct *board = comedi_board(dev);
+
if (chan >= num_configurable_rtsi_channels(dev)) {
if (chan == old_RTSI_clock_channel) {
if (source == NI_RTSI_OUTPUT_RTSI_OSC)
@@ -5702,7 +5743,7 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan,
return 1;
break;
case NI_RTSI_OUTPUT_RTSI_OSC:
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
return 1;
else
return 0;
@@ -5758,6 +5799,7 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
@@ -5766,9 +5808,7 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
if (chan < num_configurable_rtsi_channels(dev)) {
devpriv->rtsi_trig_direction_reg |=
RTSI_Output_Bit(chan,
- (boardtype.
- reg_type & ni_reg_m_series_mask) !=
- 0);
+ (board->reg_type & ni_reg_m_series_mask) != 0);
} else if (chan == old_RTSI_clock_channel) {
devpriv->rtsi_trig_direction_reg |=
Drive_RTSI_Clock_Bit;
@@ -5780,9 +5820,7 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
if (chan < num_configurable_rtsi_channels(dev)) {
devpriv->rtsi_trig_direction_reg &=
~RTSI_Output_Bit(chan,
- (boardtype.
- reg_type & ni_reg_m_series_mask)
- != 0);
+ (board->reg_type & ni_reg_m_series_mask) != 0);
} else if (chan == old_RTSI_clock_channel) {
devpriv->rtsi_trig_direction_reg &=
~Drive_RTSI_Clock_Bit;
@@ -5795,10 +5833,9 @@ static int ni_rtsi_insn_config(struct comedi_device *dev,
data[1] =
(devpriv->rtsi_trig_direction_reg &
RTSI_Output_Bit(chan,
- (boardtype.reg_type &
- ni_reg_m_series_mask)
- != 0)) ? INSN_CONFIG_DIO_OUTPUT :
- INSN_CONFIG_DIO_INPUT;
+ (board->reg_type & ni_reg_m_series_mask) != 0))
+ ? INSN_CONFIG_DIO_OUTPUT
+ : INSN_CONFIG_DIO_INPUT;
} else if (chan == old_RTSI_clock_channel) {
data[1] =
(devpriv->rtsi_trig_direction_reg &
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 0a00260d11f3..b5f340c186ec 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -280,29 +280,30 @@ enum FPGA_Control_Bits {
static int ni_pcidio_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
+enum nidio_boardid {
+ BOARD_PCIDIO_32HS,
+ BOARD_PXI6533,
+ BOARD_PCI6534,
+};
+
struct nidio_board {
- int dev_id;
const char *name;
unsigned int uses_firmware:1;
};
static const struct nidio_board nidio_boards[] = {
- {
- .dev_id = 0x1150,
+ [BOARD_PCIDIO_32HS] = {
.name = "pci-dio-32hs",
- }, {
- .dev_id = 0x1320,
+ },
+ [BOARD_PXI6533] = {
.name = "pxi-6533",
- }, {
- .dev_id = 0x12b0,
+ },
+ [BOARD_PCI6534] = {
.name = "pci-6534",
.uses_firmware = 1,
},
};
-#define n_nidio_boards ARRAY_SIZE(nidio_boards)
-#define this_board ((const struct nidio_board *)dev->board_ptr)
-
struct nidio96_private {
struct mite_struct *mite;
int boardtype;
@@ -419,7 +420,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
unsigned int m_status = 0;
/* interrupcions parasites */
- if (dev->attached == 0) {
+ if (!dev->attached) {
/* assume it's from another card */
return IRQ_NONE;
}
@@ -1094,29 +1095,27 @@ static int pci_6534_upload_firmware(struct comedi_device *dev)
return ret;
}
-static const struct nidio_board *
-nidio_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int dev_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(nidio_boards); n++) {
- const struct nidio_board *board = &nidio_boards[n];
- if (board->dev_id == dev_id)
- return board;
- }
- return NULL;
-}
-
static int nidio_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct nidio_board *board = NULL;
struct nidio96_private *devpriv;
struct comedi_subdevice *s;
int ret;
unsigned int irq;
+ if (context < ARRAY_SIZE(nidio_boards))
+ board = &nidio_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
+
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
@@ -1124,9 +1123,6 @@ static int nidio_auto_attach(struct comedi_device *dev,
spin_lock_init(&devpriv->mite_channel_lock);
- dev->board_ptr = nidio_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
@@ -1141,9 +1137,8 @@ static int nidio_auto_attach(struct comedi_device *dev,
if (devpriv->di_mite_ring == NULL)
return -ENOMEM;
- dev->board_name = this_board->name;
irq = mite_irq(devpriv->mite);
- if (this_board->uses_firmware) {
+ if (board->uses_firmware) {
ret = pci_6534_upload_firmware(dev);
if (ret < 0)
return ret;
@@ -1211,6 +1206,7 @@ static void nidio_detach(struct comedi_device *dev)
mite_free(devpriv->mite);
}
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver ni_pcidio_driver = {
@@ -1221,15 +1217,15 @@ static struct comedi_driver ni_pcidio_driver = {
};
static int ni_pcidio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni_pcidio_driver);
+ return comedi_pci_auto_config(dev, &ni_pcidio_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) },
+ { PCI_VDEVICE(NI, 0x1150), BOARD_PCIDIO_32HS },
+ { PCI_VDEVICE(NI, 0x12b0), BOARD_PCI6534 },
+ { PCI_VDEVICE(NI, 0x1320), BOARD_PXI6533 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 98b43f2fc65d..634d02303aa0 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -111,7 +111,6 @@ Bugs:
*/
#include <linux/delay.h>
-#include <linux/delay.h>
#include "../comedidev.h"
@@ -158,1036 +157,894 @@ static const struct comedi_lrange range_ni_M_625x_ao = { 3, {
}
};
-static const struct comedi_lrange range_ni_M_622x_ao = { 1, {
- RANGE(-10, 10),
- }
+enum ni_pcimio_boardid {
+ BOARD_PCIMIO_16XE_50,
+ BOARD_PCIMIO_16XE_10,
+ BOARD_PCI6014,
+ BOARD_PXI6030E,
+ BOARD_PCIMIO_16E_1,
+ BOARD_PCIMIO_16E_4,
+ BOARD_PXI6040E,
+ BOARD_PCI6031E,
+ BOARD_PCI6032E,
+ BOARD_PCI6033E,
+ BOARD_PCI6071E,
+ BOARD_PCI6023E,
+ BOARD_PCI6024E,
+ BOARD_PCI6025E,
+ BOARD_PXI6025E,
+ BOARD_PCI6034E,
+ BOARD_PCI6035E,
+ BOARD_PCI6052E,
+ BOARD_PCI6110,
+ BOARD_PCI6111,
+ /* BOARD_PCI6115, */
+ /* BOARD_PXI6115, */
+ BOARD_PCI6711,
+ BOARD_PXI6711,
+ BOARD_PCI6713,
+ BOARD_PXI6713,
+ BOARD_PCI6731,
+ /* BOARD_PXI6731, */
+ BOARD_PCI6733,
+ BOARD_PXI6733,
+ BOARD_PXI6071E,
+ BOARD_PXI6070E,
+ BOARD_PXI6052E,
+ BOARD_PXI6031E,
+ BOARD_PCI6036E,
+ BOARD_PCI6220,
+ BOARD_PCI6221,
+ BOARD_PCI6221_37PIN,
+ BOARD_PCI6224,
+ BOARD_PXI6224,
+ BOARD_PCI6225,
+ BOARD_PXI6225,
+ BOARD_PCI6229,
+ BOARD_PCI6250,
+ BOARD_PCI6251,
+ BOARD_PCIE6251,
+ BOARD_PXIE6251,
+ BOARD_PCI6254,
+ BOARD_PCI6259,
+ BOARD_PCIE6259,
+ BOARD_PCI6280,
+ BOARD_PCI6281,
+ BOARD_PXI6281,
+ BOARD_PCI6284,
+ BOARD_PCI6289,
+ BOARD_PCI6143,
+ BOARD_PXI6143,
};
static const struct ni_board_struct ni_boards[] = {
- {
- .device_id = 0x0162, /* NI also says 0x1620. typo? */
- .name = "pci-mio-16xe-50",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 2048,
- .alwaysdither = 1,
- .gainlkup = ai_gain_8,
- .ai_speed = 50000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 50000,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1170,
- .name = "pci-mio-16xe-10", /* aka pci-6030E */
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 10000,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- .has_8255 = 0,
- },
- {
- .device_id = 0x28c0,
- .name = "pci-6014",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x11d0,
- .name = "pxi-6030e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 10000,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1180,
- .name = "pci-mio-16e-1", /* aka pci-6070e */
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_16,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {mb88341},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1190,
- .name = "pci-mio-16e-4", /* aka pci-6040e */
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_16,
- /* .Note = there have been reported problems with full speed
- * on this board */
- .ai_speed = 2000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 512,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug}, /* doc says mb88341 */
- .has_8255 = 0,
- },
- {
- .device_id = 0x11c0,
- .name = "pxi-6040e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_16,
- .ai_speed = 2000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 512,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {mb88341},
- .has_8255 = 0,
- },
-
- {
- .device_id = 0x1330,
- .name = "pci-6031e",
- .n_adchan = 64,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 10000,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1270,
- .name = "pci-6032e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1340,
- .name = "pci-6033e",
- .n_adchan = 64,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- .has_8255 = 0,
- },
- {
- .device_id = 0x1350,
- .name = "pci-6071e",
- .n_adchan = 64,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_16,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x2a60,
- .name = "pci-6023e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug}, /* manual is wrong */
- .has_8255 = 0,
- },
- {
- .device_id = 0x2a70,
- .name = "pci-6024e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug}, /* manual is wrong */
- .has_8255 = 0,
- },
- {
- .device_id = 0x2a80,
- .name = "pci-6025e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug}, /* manual is wrong */
- .has_8255 = 1,
- },
- {
- .device_id = 0x2ab0,
- .name = "pxi-6025e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 0,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug}, /* manual is wrong */
- .has_8255 = 1,
- },
-
- {
- .device_id = 0x2ca0,
- .name = "pci-6034e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x2c80,
- .name = "pci-6035e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x18b0,
- .name = "pci-6052e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_16,
- .ai_speed = 3000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_unipolar = 1,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_speed = 3000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug, ad8804_debug, ad8522}, /* manual is wrong */
- },
- {.device_id = 0x14e0,
- .name = "pci-6110",
- .n_adchan = 4,
- .adbits = 12,
- .ai_fifo_depth = 8192,
- .alwaysdither = 0,
- .gainlkup = ai_gain_611x,
- .ai_speed = 200,
- .n_aochan = 2,
- .aobits = 16,
- .reg_type = ni_reg_611x,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_fifo_depth = 2048,
- .ao_speed = 250,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804, ad8804},
- },
- {
- .device_id = 0x14f0,
- .name = "pci-6111",
- .n_adchan = 2,
- .adbits = 12,
- .ai_fifo_depth = 8192,
- .alwaysdither = 0,
- .gainlkup = ai_gain_611x,
- .ai_speed = 200,
- .n_aochan = 2,
- .aobits = 16,
- .reg_type = ni_reg_611x,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_fifo_depth = 2048,
- .ao_speed = 250,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804, ad8804},
- },
+ [BOARD_PCIMIO_16XE_50] = {
+ .name = "pci-mio-16xe-50",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 2048,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_8,
+ .ai_speed = 50000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 50000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043 },
+ },
+ [BOARD_PCIMIO_16XE_10] = {
+ .name = "pci-mio-16xe-10", /* aka pci-6030E */
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCI6014] = {
+ .name = "pci-6014",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PXI6030E] = {
+ .name = "pxi-6030e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCIMIO_16E_1] = {
+ .name = "pci-mio-16e-1", /* aka pci-6070e */
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { mb88341 },
+ },
+ [BOARD_PCIMIO_16E_4] = {
+ .name = "pci-mio-16e-4", /* aka pci-6040e */
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_16,
+ /*
+ * there have been reported problems with
+ * full speed on this board
+ */
+ .ai_speed = 2000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 512,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug }, /* doc says mb88341 */
+ },
+ [BOARD_PXI6040E] = {
+ .name = "pxi-6040e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 2000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 512,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { mb88341 },
+ },
+ [BOARD_PCI6031E] = {
+ .name = "pci-6031e",
+ .n_adchan = 64,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCI6032E] = {
+ .name = "pci-6032e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCI6033E] = {
+ .name = "pci-6033e",
+ .n_adchan = 64,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCI6071E] = {
+ .name = "pci-6071e",
+ .n_adchan = 64,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PCI6023E] = {
+ .name = "pci-6023e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug }, /* manual is wrong */
+ },
+ [BOARD_PCI6024E] = {
+ .name = "pci-6024e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug }, /* manual is wrong */
+ },
+ [BOARD_PCI6025E] = {
+ .name = "pci-6025e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug }, /* manual is wrong */
+ .has_8255 = 1,
+ },
+ [BOARD_PXI6025E] = {
+ .name = "pxi-6025e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug }, /* manual is wrong */
+ .has_8255 = 1,
+ },
+ [BOARD_PCI6034E] = {
+ .name = "pci-6034e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PCI6035E] = {
+ .name = "pci-6035e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PCI6052E] = {
+ .name = "pci-6052e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 3000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_unipolar = 1,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_speed = 3000,
+ .num_p0_dio_channels = 8,
+ /* manual is wrong */
+ .caldac = { ad8804_debug, ad8804_debug, ad8522 },
+ },
+ [BOARD_PCI6110] = {
+ .name = "pci-6110",
+ .n_adchan = 4,
+ .adbits = 12,
+ .ai_fifo_depth = 8192,
+ .alwaysdither = 0,
+ .gainlkup = ai_gain_611x,
+ .ai_speed = 200,
+ .n_aochan = 2,
+ .aobits = 16,
+ .reg_type = ni_reg_611x,
+ .ao_range_table = &range_bipolar10,
+ .ao_fifo_depth = 2048,
+ .ao_speed = 250,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804, ad8804 },
+ },
+ [BOARD_PCI6111] = {
+ .name = "pci-6111",
+ .n_adchan = 2,
+ .adbits = 12,
+ .ai_fifo_depth = 8192,
+ .gainlkup = ai_gain_611x,
+ .ai_speed = 200,
+ .n_aochan = 2,
+ .aobits = 16,
+ .reg_type = ni_reg_611x,
+ .ao_range_table = &range_bipolar10,
+ .ao_fifo_depth = 2048,
+ .ao_speed = 250,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804, ad8804 },
+ },
#if 0
/* The 6115 boards probably need their own driver */
- {
- .device_id = 0x2ed0,
- .name = "pci-6115",
- .n_adchan = 4,
- .adbits = 12,
- .ai_fifo_depth = 8192,
- .alwaysdither = 0,
- .gainlkup = ai_gain_611x,
- .ai_speed = 100,
- .n_aochan = 2,
- .aobits = 16,
- .ao_671x = 1,
- .ao_unipolar = 0,
- .ao_fifo_depth = 2048,
- .ao_speed = 250,
- .num_p0_dio_channels = 8,
- .reg_611x = 1,
- .caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */
- },
+ [BOARD_PCI6115] = { /* .device_id = 0x2ed0, */
+ .name = "pci-6115",
+ .n_adchan = 4,
+ .adbits = 12,
+ .ai_fifo_depth = 8192,
+ .gainlkup = ai_gain_611x,
+ .ai_speed = 100,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_671x = 1,
+ .ao_fifo_depth = 2048,
+ .ao_speed = 250,
+ .num_p0_dio_channels = 8,
+ .reg_611x = 1,
+ /* XXX */
+ .caldac = { ad8804_debug, ad8804_debug, ad8804_debug },
+ },
#endif
#if 0
- {
- .device_id = 0x0000,
- .name = "pxi-6115",
- .n_adchan = 4,
- .adbits = 12,
- .ai_fifo_depth = 8192,
- .alwaysdither = 0,
- .gainlkup = ai_gain_611x,
- .ai_speed = 100,
- .n_aochan = 2,
- .aobits = 16,
- .ao_671x = 1,
- .ao_unipolar = 0,
- .ao_fifo_depth = 2048,
- .ao_speed = 250,
- .reg_611x = 1,
- .num_p0_dio_channels = 8,
- caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */
- },
+ [BOARD_PXI6115] = { /* .device_id = ????, */
+ .name = "pxi-6115",
+ .n_adchan = 4,
+ .adbits = 12,
+ .ai_fifo_depth = 8192,
+ .gainlkup = ai_gain_611x,
+ .ai_speed = 100,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_671x = 1,
+ .ao_fifo_depth = 2048,
+ .ao_speed = 250,
+ .reg_611x = 1,
+ .num_p0_dio_channels = 8,
+ /* XXX */
+ .caldac = { ad8804_debug, ad8804_debug, ad8804_debug },
+ },
#endif
- {
- .device_id = 0x1880,
- .name = "pci-6711",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 4,
- .aobits = 12,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- /* data sheet says 8192, but fifo really holds 16384 samples */
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6711,
- .caldac = {ad8804_debug},
- },
- {
- .device_id = 0x2b90,
- .name = "pxi-6711",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 4,
- .aobits = 12,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6711,
- .caldac = {ad8804_debug},
- },
- {
- .device_id = 0x1870,
- .name = "pci-6713",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 8,
- .aobits = 12,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6713,
- .caldac = {ad8804_debug, ad8804_debug},
- },
- {
- .device_id = 0x2b80,
- .name = "pxi-6713",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 8,
- .aobits = 12,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6713,
- .caldac = {ad8804_debug, ad8804_debug},
- },
- {
- .device_id = 0x2430,
- .name = "pci-6731",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 4,
- .aobits = 16,
- .ao_unipolar = 0,
- .ao_fifo_depth = 8192,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6711,
- .caldac = {ad8804_debug},
- },
-#if 0 /* need device ids */
- {
- .device_id = 0x0,
- .name = "pxi-6731",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 4,
- .aobits = 16,
- .ao_unipolar = 0,
- .ao_fifo_depth = 8192,
- .ao_range_table = &range_bipolar10,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6711,
- .caldac = {ad8804_debug},
- },
+ [BOARD_PCI6711] = {
+ .name = "pci-6711",
+ .n_aochan = 4,
+ .aobits = 12,
+ /* data sheet says 8192, but fifo really holds 16384 samples */
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6711,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PXI6711] = {
+ .name = "pxi-6711",
+ .n_aochan = 4,
+ .aobits = 12,
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6711,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PCI6713] = {
+ .name = "pci-6713",
+ .n_aochan = 8,
+ .aobits = 12,
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6713,
+ .caldac = { ad8804_debug, ad8804_debug },
+ },
+ [BOARD_PXI6713] = {
+ .name = "pxi-6713",
+ .n_aochan = 8,
+ .aobits = 12,
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6713,
+ .caldac = { ad8804_debug, ad8804_debug },
+ },
+ [BOARD_PCI6731] = {
+ .name = "pci-6731",
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8192,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6711,
+ .caldac = { ad8804_debug },
+ },
+#if 0
+ [BOARD_PXI6731] = { /* .device_id = ????, */
+ .name = "pxi-6731",
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8192,
+ .ao_range_table = &range_bipolar10,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6711,
+ .caldac = { ad8804_debug },
+ },
#endif
- {
- .device_id = 0x2410,
- .name = "pci-6733",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 8,
- .aobits = 16,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6713,
- .caldac = {ad8804_debug, ad8804_debug},
- },
- {
- .device_id = 0x2420,
- .name = "pxi-6733",
- .n_adchan = 0, /* no analog input */
- .n_aochan = 8,
- .aobits = 16,
- .ao_unipolar = 0,
- .ao_fifo_depth = 16384,
- .ao_range_table = &range_bipolar10,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_6713,
- .caldac = {ad8804_debug, ad8804_debug},
- },
- {
- .device_id = 0x15b0,
- .name = "pxi-6071e",
- .n_adchan = 64,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_16,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x11b0,
- .name = "pxi-6070e",
- .n_adchan = 16,
- .adbits = 12,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_16,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 12,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 1000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x18c0,
- .name = "pxi-6052e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_16,
- .ai_speed = 3000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_unipolar = 1,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_speed = 3000,
- .num_p0_dio_channels = 8,
- .caldac = {mb88341, mb88341, ad8522},
- },
- {
- .device_id = 0x1580,
- .name = "pxi-6031e",
- .n_adchan = 64,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_14,
- .ai_speed = 10000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 2048,
- .ao_range_table = &range_ni_E_ao_ext,
- .ao_unipolar = 1,
- .ao_speed = 10000,
- .num_p0_dio_channels = 8,
- .caldac = {dac8800, dac8043, ad8522},
- },
- {
- .device_id = 0x2890,
- .name = "pci-6036e",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- .alwaysdither = 1,
- .gainlkup = ai_gain_4,
- .ai_speed = 5000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 0,
- .ao_range_table = &range_bipolar10,
- .ao_unipolar = 0,
- .ao_speed = 100000,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70b0,
- .name = "pci-6220",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 512,
- /* .FIXME = guess */
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .num_p0_dio_channels = 8,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70af,
- .name = "pci-6221",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_622x_ao,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .ao_speed = 1200,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x71bc,
- .name = "pci-6221_37pin",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_622x_ao,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .ao_speed = 1200,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70f2,
- .name = "pci-6224",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70f3,
- .name = "pxi-6224",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x716c,
- .name = "pci-6225",
- .n_adchan = 80,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_622x_ao,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .ao_speed = 1200,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x716d,
- .name = "pxi-6225",
- .n_adchan = 80,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_622x_ao,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .ao_speed = 1200,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
+ [BOARD_PCI6733] = {
+ .name = "pci-6733",
+ .n_aochan = 8,
+ .aobits = 16,
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6713,
+ .caldac = { ad8804_debug, ad8804_debug },
+ },
+ [BOARD_PXI6733] = {
+ .name = "pxi-6733",
+ .n_aochan = 8,
+ .aobits = 16,
+ .ao_fifo_depth = 16384,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_6713,
+ .caldac = { ad8804_debug, ad8804_debug },
+ },
+ [BOARD_PXI6071E] = {
+ .name = "pxi-6071e",
+ .n_adchan = 64,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PXI6070E] = {
+ .name = "pxi-6070e",
+ .n_adchan = 16,
+ .adbits = 12,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 12,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 1000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PXI6052E] = {
+ .name = "pxi-6052e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_16,
+ .ai_speed = 3000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_unipolar = 1,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_speed = 3000,
+ .num_p0_dio_channels = 8,
+ .caldac = { mb88341, mb88341, ad8522 },
+ },
+ [BOARD_PXI6031E] = {
+ .name = "pxi-6031e",
+ .n_adchan = 64,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_14,
+ .ai_speed = 10000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 2048,
+ .ao_range_table = &range_ni_E_ao_ext,
+ .ao_unipolar = 1,
+ .ao_speed = 10000,
+ .num_p0_dio_channels = 8,
+ .caldac = { dac8800, dac8043, ad8522 },
+ },
+ [BOARD_PCI6036E] = {
+ .name = "pci-6036e",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512,
+ .alwaysdither = 1,
+ .gainlkup = ai_gain_4,
+ .ai_speed = 5000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_range_table = &range_bipolar10,
+ .ao_speed = 100000,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug },
+ },
+ [BOARD_PCI6220] = {
+ .name = "pci-6220",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 512, /* FIXME: guess */
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .num_p0_dio_channels = 8,
+ .reg_type = ni_reg_622x,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6221] = {
+ .name = "pci-6221",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6221_37PIN] = {
+ .name = "pci-6221_37pin",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6224] = {
+ .name = "pci-6224",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .reg_type = ni_reg_622x,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PXI6224] = {
+ .name = "pxi-6224",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .reg_type = ni_reg_622x,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6225] = {
+ .name = "pci-6225",
+ .n_adchan = 80,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PXI6225] = {
+ .name = "pxi-6225",
+ .n_adchan = 80,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6229] = {
+ .name = "pci-6229",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6250] = {
+ .name = "pci-6250",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .reg_type = ni_reg_625x,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6251] = {
+ .name = "pci-6251",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCIE6251] = {
+ .name = "pcie-6251",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PXIE6251] = {
+ .name = "pxie-6251",
+ .n_adchan = 16,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6254] = {
+ .name = "pci-6254",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .reg_type = ni_reg_625x,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6259] = {
+ .name = "pci-6259",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCIE6259] = {
+ .name = "pcie-6259",
+ .n_adchan = 32,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6280] = {
+ .name = "pci-6280",
+ .n_adchan = 16,
+ .adbits = 18,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .ao_fifo_depth = 8191,
+ .reg_type = ni_reg_628x,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6281] = {
+ .name = "pci-6281",
+ .n_adchan = 16,
+ .adbits = 18,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_628x_ao,
+ .reg_type = ni_reg_628x,
+ .ao_unipolar = 1,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PXI6281] = {
+ .name = "pxi-6281",
+ .n_adchan = 16,
+ .adbits = 18,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_628x_ao,
+ .reg_type = ni_reg_628x,
+ .ao_unipolar = 1,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 8,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6284] = {
+ .name = "pci-6284",
+ .n_adchan = 32,
+ .adbits = 18,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .reg_type = ni_reg_628x,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6289] = {
+ .name = "pci-6289",
+ .n_adchan = 32,
+ .adbits = 18,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .n_aochan = 4,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_628x_ao,
+ .reg_type = ni_reg_628x,
+ .ao_unipolar = 1,
+ .ao_speed = 350,
+ .num_p0_dio_channels = 32,
+ .caldac = { caldac_none },
+ },
+ [BOARD_PCI6143] = {
+ .name = "pci-6143",
+ .n_adchan = 8,
+ .adbits = 16,
+ .ai_fifo_depth = 1024,
+ .gainlkup = ai_gain_6143,
+ .ai_speed = 4000,
+ .reg_type = ni_reg_6143,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug, ad8804_debug },
+ },
+ [BOARD_PXI6143] = {
+ .name = "pxi-6143",
+ .n_adchan = 8,
+ .adbits = 16,
+ .ai_fifo_depth = 1024,
+ .gainlkup = ai_gain_6143,
+ .ai_speed = 4000,
+ .reg_type = ni_reg_6143,
+ .num_p0_dio_channels = 8,
+ .caldac = { ad8804_debug, ad8804_debug },
},
- {
- .device_id = 0x70aa,
- .name = "pci-6229",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_622x,
- .ai_speed = 4000,
- .n_aochan = 4,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_622x_ao,
- .reg_type = ni_reg_622x,
- .ao_unipolar = 0,
- .ao_speed = 1200,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70b4,
- .name = "pci-6250",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70b8,
- .name = "pci-6251",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_625x_ao,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .ao_speed = 350,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x717d,
- .name = "pcie-6251",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_625x_ao,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .ao_speed = 350,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x72e8,
- .name = "pxie-6251",
- .n_adchan = 16,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_625x_ao,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .ao_speed = 350,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70b7,
- .name = "pci-6254",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70ab,
- .name = "pci-6259",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 4,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_625x_ao,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .ao_speed = 350,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x717f,
- .name = "pcie-6259",
- .n_adchan = 32,
- .adbits = 16,
- .ai_fifo_depth = 4095,
- .gainlkup = ai_gain_628x,
- .ai_speed = 800,
- .n_aochan = 4,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_625x_ao,
- .reg_type = ni_reg_625x,
- .ao_unipolar = 0,
- .ao_speed = 350,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70b6,
- .name = "pci-6280",
- .n_adchan = 16,
- .adbits = 18,
- .ai_fifo_depth = 2047,
- .gainlkup = ai_gain_628x,
- .ai_speed = 1600,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 8191,
- .reg_type = ni_reg_628x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70bd,
- .name = "pci-6281",
- .n_adchan = 16,
- .adbits = 18,
- .ai_fifo_depth = 2047,
- .gainlkup = ai_gain_628x,
- .ai_speed = 1600,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_628x_ao,
- .reg_type = ni_reg_628x,
- .ao_unipolar = 1,
- .ao_speed = 350,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70bf,
- .name = "pxi-6281",
- .n_adchan = 16,
- .adbits = 18,
- .ai_fifo_depth = 2047,
- .gainlkup = ai_gain_628x,
- .ai_speed = 1600,
- .n_aochan = 2,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_628x_ao,
- .reg_type = ni_reg_628x,
- .ao_unipolar = 1,
- .ao_speed = 350,
- .num_p0_dio_channels = 8,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70bc,
- .name = "pci-6284",
- .n_adchan = 32,
- .adbits = 18,
- .ai_fifo_depth = 2047,
- .gainlkup = ai_gain_628x,
- .ai_speed = 1600,
- .n_aochan = 0,
- .aobits = 0,
- .ao_fifo_depth = 0,
- .reg_type = ni_reg_628x,
- .ao_unipolar = 0,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70ac,
- .name = "pci-6289",
- .n_adchan = 32,
- .adbits = 18,
- .ai_fifo_depth = 2047,
- .gainlkup = ai_gain_628x,
- .ai_speed = 1600,
- .n_aochan = 4,
- .aobits = 16,
- .ao_fifo_depth = 8191,
- .ao_range_table = &range_ni_M_628x_ao,
- .reg_type = ni_reg_628x,
- .ao_unipolar = 1,
- .ao_speed = 350,
- .num_p0_dio_channels = 32,
- .caldac = {caldac_none},
- .has_8255 = 0,
- },
- {
- .device_id = 0x70C0,
- .name = "pci-6143",
- .n_adchan = 8,
- .adbits = 16,
- .ai_fifo_depth = 1024,
- .alwaysdither = 0,
- .gainlkup = ai_gain_6143,
- .ai_speed = 4000,
- .n_aochan = 0,
- .aobits = 0,
- .reg_type = ni_reg_6143,
- .ao_unipolar = 0,
- .ao_fifo_depth = 0,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug, ad8804_debug},
- },
- {
- .device_id = 0x710D,
- .name = "pxi-6143",
- .n_adchan = 8,
- .adbits = 16,
- .ai_fifo_depth = 1024,
- .alwaysdither = 0,
- .gainlkup = ai_gain_6143,
- .ai_speed = 4000,
- .n_aochan = 0,
- .aobits = 0,
- .reg_type = ni_reg_6143,
- .ao_unipolar = 0,
- .ao_fifo_depth = 0,
- .num_p0_dio_channels = 8,
- .caldac = {ad8804_debug, ad8804_debug},
- },
};
struct ni_private {
@@ -1569,6 +1426,7 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev)
static void init_6143(struct comedi_device *dev)
{
+ const struct ni_board_struct *board = comedi_board(dev);
struct ni_private *devpriv = dev->private;
/* Disable interrupts */
@@ -1579,7 +1437,8 @@ static void init_6143(struct comedi_device *dev)
ni_writeb(0x80, PipelineDelay_6143); /* Set EOCMode, ADCMode and pipelinedelay */
ni_writeb(0x00, EOC_Set_6143); /* Set EOC Delay */
- ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143); /* Set the FIFO half full level */
+ /* Set the FIFO half full level */
+ ni_writel(board->ai_fifo_depth / 2, AIFIFO_Flag_6143);
/* Strobe Relay disable bit */
devpriv->ai_calib_source_enabled = 0;
@@ -1606,48 +1465,38 @@ static void pcimio_detach(struct comedi_device *dev)
mite_free(devpriv->mite);
}
}
-}
-
-static const struct ni_board_struct *
-pcimio_find_boardinfo(struct pci_dev *pcidev)
-{
- unsigned int device_id = pcidev->device;
- unsigned int n;
-
- for (n = 0; n < ARRAY_SIZE(ni_boards); n++) {
- const struct ni_board_struct *board = &ni_boards[n];
- if (board->device_id == device_id)
- return board;
- }
- return NULL;
+ comedi_pci_disable(dev);
}
static int pcimio_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ const struct ni_board_struct *board = NULL;
struct ni_private *devpriv;
int ret;
- dev_info(dev->class_dev, "ni_pcimio: attach %s\n", pci_name(pcidev));
+ if (context < ARRAY_SIZE(ni_boards))
+ board = &ni_boards[context];
+ if (!board)
+ return -ENODEV;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
+
+ ret = comedi_pci_enable(dev);
+ if (ret)
+ return ret;
ret = ni_alloc_private(dev);
if (ret)
return ret;
devpriv = dev->private;
- dev->board_ptr = pcimio_find_boardinfo(pcidev);
- if (!dev->board_ptr)
- return -ENODEV;
-
devpriv->mite = mite_alloc(pcidev);
if (!devpriv->mite)
return -ENOMEM;
- dev_dbg(dev->class_dev, "%s\n", boardtype.name);
- dev->board_name = boardtype.name;
-
- if (boardtype.reg_type & ni_reg_m_series_mask) {
+ if (board->reg_type & ni_reg_m_series_mask) {
devpriv->stc_writew = &m_series_stc_writew;
devpriv->stc_readw = &m_series_stc_readw;
devpriv->stc_writel = &m_series_stc_writel;
@@ -1681,9 +1530,9 @@ static int pcimio_auto_attach(struct comedi_device *dev,
if (devpriv->gpct_mite_ring[1] == NULL)
return -ENOMEM;
- if (boardtype.reg_type & ni_reg_m_series_mask)
+ if (board->reg_type & ni_reg_m_series_mask)
m_series_init_eeprom_buffer(dev);
- if (boardtype.reg_type == ni_reg_6143)
+ if (board->reg_type == ni_reg_6143)
init_6143(dev);
dev->irq = mite_irq(devpriv->mite);
@@ -1788,65 +1637,66 @@ static struct comedi_driver ni_pcimio_driver = {
};
static int ni_pcimio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &ni_pcimio_driver);
+ return comedi_pci_auto_config(dev, &ni_pcimio_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) },
- { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) },
+ { PCI_VDEVICE(NI, 0x0162), BOARD_PCIMIO_16XE_50 }, /* 0x1620? */
+ { PCI_VDEVICE(NI, 0x1170), BOARD_PCIMIO_16XE_10 },
+ { PCI_VDEVICE(NI, 0x1180), BOARD_PCIMIO_16E_1 },
+ { PCI_VDEVICE(NI, 0x1190), BOARD_PCIMIO_16E_4 },
+ { PCI_VDEVICE(NI, 0x11b0), BOARD_PXI6070E },
+ { PCI_VDEVICE(NI, 0x11c0), BOARD_PXI6040E },
+ { PCI_VDEVICE(NI, 0x11d0), BOARD_PXI6030E },
+ { PCI_VDEVICE(NI, 0x1270), BOARD_PCI6032E },
+ { PCI_VDEVICE(NI, 0x1330), BOARD_PCI6031E },
+ { PCI_VDEVICE(NI, 0x1340), BOARD_PCI6033E },
+ { PCI_VDEVICE(NI, 0x1350), BOARD_PCI6071E },
+ { PCI_VDEVICE(NI, 0x14e0), BOARD_PCI6110 },
+ { PCI_VDEVICE(NI, 0x14f0), BOARD_PCI6111 },
+ { PCI_VDEVICE(NI, 0x1580), BOARD_PXI6031E },
+ { PCI_VDEVICE(NI, 0x15b0), BOARD_PXI6071E },
+ { PCI_VDEVICE(NI, 0x1880), BOARD_PCI6711 },
+ { PCI_VDEVICE(NI, 0x1870), BOARD_PCI6713 },
+ { PCI_VDEVICE(NI, 0x18b0), BOARD_PCI6052E },
+ { PCI_VDEVICE(NI, 0x18c0), BOARD_PXI6052E },
+ { PCI_VDEVICE(NI, 0x2410), BOARD_PCI6733 },
+ { PCI_VDEVICE(NI, 0x2420), BOARD_PXI6733 },
+ { PCI_VDEVICE(NI, 0x2430), BOARD_PCI6731 },
+ { PCI_VDEVICE(NI, 0x2890), BOARD_PCI6036E },
+ { PCI_VDEVICE(NI, 0x28c0), BOARD_PCI6014 },
+ { PCI_VDEVICE(NI, 0x2a60), BOARD_PCI6023E },
+ { PCI_VDEVICE(NI, 0x2a70), BOARD_PCI6024E },
+ { PCI_VDEVICE(NI, 0x2a80), BOARD_PCI6025E },
+ { PCI_VDEVICE(NI, 0x2ab0), BOARD_PXI6025E },
+ { PCI_VDEVICE(NI, 0x2b80), BOARD_PXI6713 },
+ { PCI_VDEVICE(NI, 0x2b90), BOARD_PXI6711 },
+ { PCI_VDEVICE(NI, 0x2c80), BOARD_PCI6035E },
+ { PCI_VDEVICE(NI, 0x2ca0), BOARD_PCI6034E },
+ { PCI_VDEVICE(NI, 0x70aa), BOARD_PCI6229 },
+ { PCI_VDEVICE(NI, 0x70ab), BOARD_PCI6259 },
+ { PCI_VDEVICE(NI, 0x70ac), BOARD_PCI6289 },
+ { PCI_VDEVICE(NI, 0x70af), BOARD_PCI6221 },
+ { PCI_VDEVICE(NI, 0x70b0), BOARD_PCI6220 },
+ { PCI_VDEVICE(NI, 0x70b4), BOARD_PCI6250 },
+ { PCI_VDEVICE(NI, 0x70b6), BOARD_PCI6280 },
+ { PCI_VDEVICE(NI, 0x70b7), BOARD_PCI6254 },
+ { PCI_VDEVICE(NI, 0x70b8), BOARD_PCI6251 },
+ { PCI_VDEVICE(NI, 0x70bc), BOARD_PCI6284 },
+ { PCI_VDEVICE(NI, 0x70bd), BOARD_PCI6281 },
+ { PCI_VDEVICE(NI, 0x70bf), BOARD_PXI6281 },
+ { PCI_VDEVICE(NI, 0x70c0), BOARD_PCI6143 },
+ { PCI_VDEVICE(NI, 0x70f2), BOARD_PCI6224 },
+ { PCI_VDEVICE(NI, 0x70f3), BOARD_PXI6224 },
+ { PCI_VDEVICE(NI, 0x710d), BOARD_PXI6143 },
+ { PCI_VDEVICE(NI, 0x716c), BOARD_PCI6225 },
+ { PCI_VDEVICE(NI, 0x716d), BOARD_PXI6225 },
+ { PCI_VDEVICE(NI, 0x717f), BOARD_PCIE6259 },
+ { PCI_VDEVICE(NI, 0x71bc), BOARD_PCI6221_37PIN },
+ { PCI_VDEVICE(NI, 0x717d), BOARD_PCIE6251 },
+ { PCI_VDEVICE(NI, 0x72e8), BOARD_PXIE6251 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table);
diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h
index 504ea7155334..0a613c077608 100644
--- a/drivers/staging/comedi/drivers/ni_stc.h
+++ b/drivers/staging/comedi/drivers/ni_stc.h
@@ -1421,10 +1421,6 @@ struct ni_board_struct {
enum caldac_enum caldac[3];
};
-#define n_ni_boards (sizeof(ni_boards)/sizeof(struct ni_board_struct))
-
-#define boardtype (*(struct ni_board_struct *)dev->board_ptr)
-
#define MAX_N_AO_CHAN 8
#define NUM_GPCT 2
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 6ee5da24a961..8be2a4c503cc 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -451,23 +451,12 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct pcl711_board *board = comedi_board(dev);
struct pcl711_private *devpriv;
int ret;
- unsigned long iobase;
unsigned int irq;
struct comedi_subdevice *s;
- /* claim our I/O space */
-
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: pcl711: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, PCL711_SIZE, "pcl711")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* there should be a sanity check here */
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], PCL711_SIZE);
+ if (ret)
+ return ret;
/* grab our IRQ */
irq = it->options[1];
@@ -476,7 +465,8 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EINVAL;
}
if (irq) {
- if (request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) {
+ if (request_irq(irq, pcl711_interrupt, 0, dev->board_name,
+ dev)) {
printk(KERN_ERR "unable to allocate irq %u\n", irq);
return -EINVAL;
} else {
@@ -560,14 +550,6 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void pcl711_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, PCL711_SIZE);
-}
-
static const struct pcl711_board boardtypes[] = {
{ "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 },
{ "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai },
@@ -579,7 +561,7 @@ static struct comedi_driver pcl711_driver = {
.driver_name = "pcl711",
.module = THIS_MODULE,
.attach = pcl711_attach,
- .detach = pcl711_detach,
+ .detach = comedi_legacy_detach,
.board_name = &boardtypes[0].name,
.num_names = ARRAY_SIZE(boardtypes),
.offset = sizeof(struct pcl711_board),
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 7b3c4293c01b..4f033d88eeca 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -100,28 +100,19 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl724_board *board = comedi_board(dev);
struct comedi_subdevice *s;
- unsigned long iobase;
unsigned int iorange;
int ret, i, n_subdevices;
#ifdef PCL724_IRQ
unsigned int irq;
#endif
- iobase = it->options[0];
iorange = board->io_range;
- if ((board->can_have96) && ((it->options[1] == 1)
- || (it->options[1] == 96)))
+ if ((board->can_have96) &&
+ ((it->options[1] == 1) || (it->options[1] == 96)))
iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */
- printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor,
- board->name, iobase);
- if (!request_region(iobase, iorange, "pcl724")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], iorange);
+ if (ret)
+ return ret;
#ifdef PCL724_IRQ
irq = 0;
@@ -134,8 +125,8 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
- if (request_irq
- (irq, interrupt_pcl724, 0, "pcl724", dev)) {
+ if (request_irq(irq, interrupt_pcl724, 0,
+ dev->board_name, dev)) {
printk(KERN_WARNING
", unable to allocate IRQ %u, "
"DISABLING IT", irq);
@@ -178,19 +169,11 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void pcl724_detach(struct comedi_device *dev)
{
- const struct pcl724_board *board = comedi_board(dev);
- struct comedi_subdevice *s;
int i;
- for (i = 0; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- subdev_8255_cleanup(dev, s);
- }
-#ifdef PCL724_IRQ
- if (dev->irq)
- free_irq(dev->irq, dev);
-#endif
- release_region(dev->iobase, board->io_range);
+ for (i = 0; i < dev->n_subdevices; i++)
+ comedi_spriv_free(dev, i);
+ comedi_legacy_detach(dev);
}
static const struct pcl724_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 21fbc1ae1e73..6b02f0631b4c 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -45,18 +45,11 @@ static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, PCL725_SIZE, "pcl725")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->board_name = "pcl725";
- dev->iobase = iobase;
- dev->irq = 0;
+ ret = comedi_request_region(dev, it->options[0], PCL725_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
@@ -85,17 +78,11 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void pcl725_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, PCL725_SIZE);
-}
-
static struct comedi_driver pcl725_driver = {
.driver_name = "pcl725",
.module = THIS_MODULE,
.attach = pcl725_attach,
- .detach = pcl725_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(pcl725_driver);
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 50e01968f19c..4aa994393fae 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -90,9 +90,6 @@ Interrupts are not supported.
#define PCL727_DI_HI 0
#define PCL727_DI_LO 1
-static const struct comedi_lrange range_4_20mA = { 1, {RANGE_mA(4, 20)} };
-static const struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
-
static const struct comedi_lrange *const rangelist_726[] = {
&range_unipolar5, &range_unipolar10,
&range_bipolar5, &range_bipolar10,
@@ -228,25 +225,14 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct pcl726_board *board = comedi_board(dev);
struct pcl726_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iorange;
int ret, i;
#ifdef ACL6126_IRQ
unsigned int irq;
#endif
- iobase = it->options[0];
- iorange = board->io_range;
- printk(KERN_WARNING "comedi%d: pcl726: board=%s, 0x%03lx ", dev->minor,
- board->name, iobase);
- if (!request_region(iobase, iorange, "pcl726")) {
- printk(KERN_WARNING "I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0], board->io_range);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -271,7 +257,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
irq = 0; /* Bad IRQ */
} else {
if (request_irq(irq, interrupt_pcl818, 0,
- "pcl726", dev)) {
+ dev->board_name, dev)) {
printk(KERN_WARNING
", unable to allocate IRQ %d,"
" DISABLING IT", irq);
@@ -349,23 +335,11 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void pcl726_detach(struct comedi_device *dev)
-{
- const struct pcl726_board *board = comedi_board(dev);
-
-#ifdef ACL6126_IRQ
- if (dev->irq)
- free_irq(dev->irq, dev);
-#endif
- if (dev->iobase)
- release_region(dev->iobase, board->io_range);
-}
-
static struct comedi_driver pcl726_driver = {
.driver_name = "pcl726",
.module = THIS_MODULE,
.attach = pcl726_attach,
- .detach = pcl726_detach,
+ .detach = comedi_legacy_detach,
.board_name = &boardtypes[0].name,
.num_names = ARRAY_SIZE(boardtypes),
.offset = sizeof(struct pcl726_board),
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index e3de49937452..2879db75da3e 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -64,21 +64,11 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl730_board *board = comedi_board(dev);
struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iorange;
int ret;
- iobase = it->options[0];
- iorange = board->io_range;
- printk(KERN_INFO "comedi%d: pcl730: board=%s 0x%04lx ", dev->minor,
- board->name, iobase);
- if (!request_region(iobase, iorange, "pcl730")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->board_name = board->name;
- dev->iobase = iobase;
- dev->irq = 0;
+ ret = comedi_request_region(dev, it->options[0], board->io_range);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -129,14 +119,6 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void pcl730_detach(struct comedi_device *dev)
-{
- const struct pcl730_board *board = comedi_board(dev);
-
- if (dev->iobase)
- release_region(dev->iobase, board->io_range);
-}
-
static const struct pcl730_board boardtypes[] = {
{ "pcl730", PCL730_SIZE, },
{ "iso730", PCL730_SIZE, },
@@ -147,7 +129,7 @@ static struct comedi_driver pcl730_driver = {
.driver_name = "pcl730",
.module = THIS_MODULE,
.attach = pcl730_attach,
- .detach = pcl730_detach,
+ .detach = comedi_legacy_detach,
.board_name = &boardtypes[0].name,
.num_names = ARRAY_SIZE(boardtypes),
.offset = sizeof(struct pcl730_board),
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 560930e6a8e9..cd02786702c8 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -1041,28 +1041,6 @@ static void start_pacer(struct comedi_device *dev, int mode,
/*
==============================================================================
*/
-static void free_resources(struct comedi_device *dev)
-{
- const struct pcl812_board *board = comedi_board(dev);
- struct pcl812_private *devpriv = dev->private;
-
- if (devpriv) {
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- }
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, board->io_range);
-}
-
-/*
-==============================================================================
-*/
static int pcl812_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1122,32 +1100,21 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct pcl812_board *board = comedi_board(dev);
struct pcl812_private *devpriv;
int ret, subdev;
- unsigned long iobase;
unsigned int irq;
unsigned int dma;
unsigned long pages;
struct comedi_subdevice *s;
int n_subdevices;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: pcl812: board=%s, ioport=0x%03lx",
- dev->minor, board->name, iobase);
-
- if (!request_region(iobase, board->io_range, "pcl812")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], board->io_range);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
- if (!devpriv) {
- free_resources(dev);
+ if (!devpriv)
return -ENOMEM;
- }
dev->private = devpriv;
- dev->board_name = board->name;
-
irq = 0;
if (board->IRQbits != 0) { /* board support IRQ */
irq = it->options[1];
@@ -1158,8 +1125,8 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
- if (request_irq
- (irq, interrupt_pcl812, 0, "pcl812", dev)) {
+ if (request_irq(irq, interrupt_pcl812, 0,
+ dev->board_name, dev)) {
printk
(", unable to allocate IRQ %u, "
"DISABLING IT", irq);
@@ -1183,7 +1150,7 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
printk(", DMA is out of allowed range, FAIL!\n");
return -EINVAL; /* Bad DMA */
}
- ret = request_dma(dma, "pcl812");
+ ret = request_dma(dma, dev->board_name);
if (ret) {
printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n",
dma);
@@ -1199,7 +1166,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* maybe experiment with try_to_free_pages()
* will help ....
*/
- free_resources(dev);
return -EBUSY; /* no buffer :-( */
}
devpriv->dmapages[0] = pages;
@@ -1208,7 +1174,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
if (!devpriv->dmabuf[1]) {
printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n");
- free_resources(dev);
return -EBUSY;
}
devpriv->dmapages[1] = pages;
@@ -1228,10 +1193,8 @@ no_dma:
n_subdevices++;
ret = comedi_alloc_subdevices(dev, n_subdevices);
- if (ret) {
- free_resources(dev);
+ if (ret)
return ret;
- }
subdev = 0;
@@ -1465,7 +1428,17 @@ no_dma:
static void pcl812_detach(struct comedi_device *dev)
{
- free_resources(dev);
+ struct pcl812_private *devpriv = dev->private;
+
+ if (devpriv) {
+ if (devpriv->dmabuf[0])
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ if (devpriv->dmabuf[1])
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ }
+ comedi_legacy_detach(dev);
}
static const struct pcl812_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index f625fdab335c..91bd2071f571 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -35,10 +35,10 @@ Configuration Options:
#include "../comedidev.h"
#include <linux/ioport.h>
-#include <linux/mc146818rtc.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <asm/dma.h>
#include "comedi_fc.h"
@@ -82,14 +82,6 @@ Configuration Options:
#define INT_TYPE_AI1_DMA 2
#define INT_TYPE_AI3_INT 4
#define INT_TYPE_AI3_DMA 5
-#ifdef unused
-#define INT_TYPE_AI1_DMA_RTC 9
-#define INT_TYPE_AI3_DMA_RTC 10
-
-/* RTC stuff... */
-#define RTC_IRQ 8
-#define RTC_IO_EXTENT 0x10
-#endif
#define MAGIC_DMA_WORD 0x5a5a
@@ -126,26 +118,14 @@ struct pcl816_board {
int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
};
-#ifdef unused
-static int RTC_lock; /* RTC lock */
-static int RTC_timer_lock; /* RTC int lock */
-#endif
-
struct pcl816_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
- int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
-#ifdef unused
- unsigned long rtc_iobase; /* RTC port region */
- unsigned int rtc_iosize;
- unsigned int rtc_irq;
-#endif
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
- unsigned int last_top_dma; /* DMA pointer in last RTC int */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
@@ -154,9 +134,6 @@ struct pcl816_private {
unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */
int irq_free; /* 1=have allocated IRQ */
int irq_blocked; /* 1=IRQ now uses any subdev */
-#ifdef unused
- int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
-#endif
int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */
int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */
struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */
@@ -167,10 +144,6 @@ struct pcl816_private {
unsigned int ai_n_chan; /* how many channels per scan */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */
-#ifdef unused
- struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
- unsigned long rtc_freq; /* RTC int freq */
-#endif
};
/*
@@ -186,9 +159,6 @@ static int pcl816_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
static void start_pacer(struct comedi_device *dev, int mode,
unsigned int divisor1, unsigned int divisor2);
-#ifdef unused
-static int set_rtc_irq_bit(unsigned char bit);
-#endif
static int pcl816_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -718,12 +688,6 @@ static int pcl816_ai_cancel(struct comedi_device *dev,
if (devpriv->irq_blocked > 0) {
switch (devpriv->int816_mode) {
-#ifdef unused
- case INT_TYPE_AI1_DMA_RTC:
- case INT_TYPE_AI3_DMA_RTC:
- set_rtc_irq_bit(0); /* stop RTC */
- del_timer(&devpriv->rtc_irq_timer);
-#endif
case INT_TYPE_AI1_DMA:
case INT_TYPE_AI3_DMA:
disable_dma(devpriv->dma);
@@ -837,7 +801,7 @@ start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1,
/*
==============================================================================
- Check if channel list from user is builded correctly
+ Check if channel list from user is built correctly
If it's ok, then return non-zero length of repeated segment of channel list
*/
static int
@@ -939,67 +903,21 @@ setup_channel_list(struct comedi_device *dev,
dev->iobase + PCL816_MUX);
}
-#ifdef unused
-/*
-==============================================================================
- Enable(1)/disable(0) periodic interrupts from RTC
-*/
-static int set_rtc_irq_bit(unsigned char bit)
-{
- unsigned char val;
- unsigned long flags;
-
- if (bit == 1) {
- RTC_timer_lock++;
- if (RTC_timer_lock > 1)
- return 0;
- } else {
- RTC_timer_lock--;
- if (RTC_timer_lock < 0)
- RTC_timer_lock = 0;
- if (RTC_timer_lock > 0)
- return 0;
- }
-
- save_flags(flags);
- cli();
- val = CMOS_READ(RTC_CONTROL);
- if (bit)
- val |= RTC_PIE;
- else
- val &= ~RTC_PIE;
-
- CMOS_WRITE(val, RTC_CONTROL);
- CMOS_READ(RTC_INTR_FLAGS);
- restore_flags(flags);
- return 0;
-}
-#endif
-
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv;
int ret;
- unsigned long iobase;
unsigned int irq, dma;
unsigned long pages;
/* int i; */
struct comedi_subdevice *s;
- /* claim our I/O space */
- iobase = it->options[0];
- printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor,
- board->name, iobase);
-
- if (!request_region(iobase, board->io_range, "pcl816")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], board->io_range);
+ if (ret)
+ return ret;
- if (pcl816_check(iobase)) {
+ if (pcl816_check(dev->iobase)) {
printk(KERN_ERR ", I cann't detect board. FAIL!\n");
return -EIO;
}
@@ -1009,8 +927,6 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
dev->private = devpriv;
- dev->board_name = board->name;
-
/* grab our IRQ */
irq = 0;
if (board->IRQbits != 0) { /* board support IRQ */
@@ -1022,8 +938,8 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"DISABLING IT", irq);
irq = 0; /* Bad IRQ */
} else {
- if (request_irq
- (irq, interrupt_pcl816, 0, "pcl816", dev)) {
+ if (request_irq(irq, interrupt_pcl816, 0,
+ dev->board_name, dev)) {
printk
(", unable to allocate IRQ %u, "
"DISABLING IT", irq);
@@ -1044,46 +960,10 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
devpriv->int816_mode = 0; /* mode of irq */
-#ifdef unused
- /* grab RTC for DMA operations */
- devpriv->dma_rtc = 0;
- if (it->options[2] > 0) { /* we want to use DMA */
- if (RTC_lock == 0) {
- if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
- "pcl816 (RTC)"))
- goto no_rtc;
- }
- devpriv->rtc_iobase = RTC_PORT(0);
- devpriv->rtc_iosize = RTC_IO_EXTENT;
- RTC_lock++;
-#ifdef UNTESTED_CODE
- if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0,
- "pcl816 DMA (RTC)", dev)) {
- devpriv->dma_rtc = 1;
- devpriv->rtc_irq = RTC_IRQ;
- printk(", dma_irq=%u", devpriv->rtc_irq);
- } else {
- RTC_lock--;
- if (RTC_lock == 0) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
- devpriv->rtc_iobase = 0;
- devpriv->rtc_iosize = 0;
- }
-#else
- printk("pcl816: RTC code missing");
-#endif
-
- }
-
-no_rtc:
-#endif
/* grab our DMA */
dma = 0;
devpriv->dma = dma;
- if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
+ if (!devpriv->irq_free)
goto no_dma; /* if we haven't IRQ, we can't use DMA */
if (board->DMAbits != 0) { /* board support DMA */
@@ -1095,7 +975,7 @@ no_rtc:
printk(", DMA is out of allowed range, FAIL!\n");
return -EINVAL; /* Bad DMA */
}
- ret = request_dma(dma, "pcl816");
+ ret = request_dma(dma, dev->board_name);
if (ret) {
printk(KERN_ERR
", unable to allocate DMA %u, FAIL!\n", dma);
@@ -1120,19 +1000,16 @@ no_rtc:
devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
/* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
- if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1]) {
- printk(KERN_ERR
- ", unable to allocate DMA buffer, "
- "FAIL!\n");
- return -EBUSY;
- }
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] =
- virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
+ devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
+ if (!devpriv->dmabuf[1]) {
+ printk(KERN_ERR
+ ", unable to allocate DMA buffer, "
+ "FAIL!\n");
+ return -EBUSY;
}
+ devpriv->dmapages[1] = pages;
+ devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
+ devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
}
no_dma:
@@ -1205,7 +1082,6 @@ case COMEDI_SUBD_DO:
static void pcl816_detach(struct comedi_device *dev)
{
- const struct pcl816_board *board = comedi_board(dev);
struct pcl816_private *devpriv = dev->private;
if (dev->private) {
@@ -1217,24 +1093,8 @@ static void pcl816_detach(struct comedi_device *dev)
free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
if (devpriv->dmabuf[1])
free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
-#endif
}
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, board->io_range);
-#ifdef unused
- if (devpriv->dma_rtc)
- RTC_lock--;
-#endif
+ comedi_legacy_detach(dev);
}
static const struct pcl816_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index b5af22eb7c37..91cb1bd6717f 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -98,15 +98,15 @@ A word or two about DMA. Driver support DMA operations at two ways:
*/
-#include "../comedidev.h"
-
#include <linux/ioport.h>
-#include <linux/mc146818rtc.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <asm/dma.h>
+#include "../comedidev.h"
+
#include "comedi_fc.h"
#include "8253.h"
@@ -186,15 +186,6 @@ A word or two about DMA. Driver support DMA operations at two ways:
#define INT_TYPE_AO3_INT 8
#endif
-#ifdef unused
-/* RTC stuff... */
-#define INT_TYPE_AI1_DMA_RTC 9
-#define INT_TYPE_AI3_DMA_RTC 10
-
-#define RTC_IRQ 8
-#define RTC_IO_EXTENT 0x10
-#endif
-
#define MAGIC_DMA_WORD 0x5a5a
static const struct comedi_lrange range_pcl818h_ai = { 9, {
@@ -248,11 +239,6 @@ static const struct comedi_lrange range718_bipolar0_5 = {
static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
-#ifdef unused
-static int RTC_lock; /* RTC lock */
-static int RTC_timer_lock; /* RTC int lock */
-#endif
-
struct pcl818_board {
const char *name; /* driver name */
@@ -277,22 +263,11 @@ struct pcl818_board {
struct pcl818_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
- int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */
unsigned int io_range;
-#ifdef unused
- unsigned long rtc_iobase; /* RTC port region */
- unsigned int rtc_iosize;
- unsigned int rtc_irq;
- struct timer_list rtc_irq_timer; /* timer for RTC sanity check */
- unsigned long rtc_freq; /* RTC int freq */
- int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */
-#endif
unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */
unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */
- unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */
- unsigned int last_top_dma; /* DMA pointer in last RTC int */
int next_dma_buf; /* which DMA buffer will be used next round */
long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
@@ -342,12 +317,6 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
static void start_pacer(struct comedi_device *dev, int mode,
unsigned int divisor1, unsigned int divisor2);
-#ifdef unused
-static int set_rtc_irq_bit(unsigned char bit);
-static void rtc_dropped_irq(unsigned long data);
-static int rtc_setfreq_irq(int freq);
-#endif
-
/*
==============================================================================
ANALOG INPUT MODE0, 818 cards, slow version
@@ -610,113 +579,6 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d)
return IRQ_HANDLED;
}
-#ifdef unused
-/*
-==============================================================================
- analog input dma mode 1 & 3 over RTC, 818 cards
-*/
-static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d)
-{
- struct comedi_device *dev = d;
- struct pcl818_private *devpriv = dev->private;
- struct comedi_subdevice *s = &dev->subdevices[0];
- unsigned long tmp;
- unsigned int top1, top2, i, bufptr;
- long ofs_dats;
- short *dmabuf = (short *)devpriv->dmabuf[0];
-
- /* outb(2,0x378); */
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA_RTC:
- case INT_TYPE_AI3_DMA_RTC:
- tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
- mod_timer(&devpriv->rtc_irq_timer,
- jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
-
- for (i = 0; i < 10; i++) {
- top1 = get_dma_residue(devpriv->dma);
- top2 = get_dma_residue(devpriv->dma);
- if (top1 == top2)
- break;
- }
-
- if (top1 != top2)
- return IRQ_HANDLED;
- top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */
- top1 >>= 1;
- ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */
- if (ofs_dats < 0)
- ofs_dats = (devpriv->dmasamplsize) + ofs_dats;
- if (!ofs_dats)
- return IRQ_HANDLED; /* exit=no new samples from last call */
- /* obsluz data */
- i = devpriv->last_top_dma - 1;
- i &= (devpriv->dmasamplsize - 1);
-
- if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */
- comedi_error(dev, "A/D mode1/3 DMA buffer overflow!");
- /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
- /* printk("r %ld ",ofs_dats); */
-
- bufptr = devpriv->last_top_dma;
-
- for (i = 0; i < ofs_dats; i++) {
- if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */
- printk
- ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n",
- (dmabuf[bufptr] & 0xf),
- devpriv->
- act_chanlist[devpriv->act_chanlist_pos]);
- pcl818_ai_cancel(dev, s);
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_event(dev, s);
- return IRQ_HANDLED;
- }
-
- comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */
- bufptr &= (devpriv->dmasamplsize - 1);
-
- devpriv->act_chanlist_pos++;
- if (devpriv->act_chanlist_pos >=
- devpriv->act_chanlist_len) {
- devpriv->act_chanlist_pos = 0;
- }
- s->async->cur_chan++;
- if (s->async->cur_chan >= devpriv->ai_n_chan) {
- s->async->cur_chan = 0;
- devpriv->ai_act_scan--;
- }
-
- if (!devpriv->neverending_ai)
- if (devpriv->ai_act_scan == 0) { /* all data sampled */
- pcl818_ai_cancel(dev, s);
- s->async->events |= COMEDI_CB_EOA;
- comedi_event(dev, s);
- /* printk("done int ai13 dma\n"); */
- return IRQ_HANDLED;
- }
- }
-
- devpriv->last_top_dma = bufptr;
- bufptr--;
- bufptr &= (devpriv->dmasamplsize - 1);
- dmabuf[bufptr] = MAGIC_DMA_WORD;
- comedi_event(dev, s);
- /* outb(0,0x378); */
- return IRQ_HANDLED;
- }
-
- /* outb(0,0x378); */
- return IRQ_HANDLED;
-}
-#endif
-
/*
==============================================================================
analog input interrupt mode 1 & 3, 818HD/HG cards
@@ -900,49 +762,6 @@ static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev,
};
}
-#ifdef unused
-/*
-==============================================================================
- ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards
-*/
-static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- unsigned int flags;
- short *pole;
-
- set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT);
- flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, devpriv->hwdmasize[0]);
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
- devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */
- pole = (short *)devpriv->dmabuf[0];
- devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2;
- pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD;
-#ifdef unused
- devpriv->rtc_freq = rtc_setfreq_irq(2048);
- devpriv->rtc_irq_timer.expires =
- jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100;
- devpriv->rtc_irq_timer.data = (unsigned long)dev;
- devpriv->rtc_irq_timer.function = rtc_dropped_irq;
-
- add_timer(&devpriv->rtc_irq_timer);
-#endif
-
- if (mode == 1) {
- devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC;
- outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */
- } else {
- devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC;
- outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */
- };
-}
-#endif
-
/*
==============================================================================
ANALOG INPUT MODE 1 or 3, 818 cards
@@ -956,7 +775,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
unsigned int seglen;
dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode()\n");
- if ((!dev->irq) && (!devpriv->dma_rtc)) {
+ if (!dev->irq) {
comedi_error(dev, "IRQ not defined!");
return -EINVAL;
}
@@ -1005,15 +824,7 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
switch (devpriv->dma) {
case 1: /* DMA */
case 3:
- if (devpriv->dma_rtc == 0)
- pcl818_ai_mode13dma_int(mode, dev, s);
-#ifdef unused
- else
- pcl818_ai_mode13dma_rtc(mode, dev, s);
-#else
- else
- return -EINVAL;
-#endif
+ pcl818_ai_mode13dma_int(mode, dev, s);
break;
case 0:
if (!devpriv->usefifo) {
@@ -1047,97 +858,10 @@ static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev,
start_pacer(dev, mode, divisor1, divisor2);
-#ifdef unused
- switch (devpriv->ai_mode) {
- case INT_TYPE_AI1_DMA_RTC:
- case INT_TYPE_AI3_DMA_RTC:
- set_rtc_irq_bit(1); /* start RTC */
- break;
- }
-#endif
dev_dbg(dev->class_dev, "pcl818_ai_cmd_mode() end\n");
return 0;
}
-#ifdef unused
-/*
-==============================================================================
- ANALOG OUTPUT MODE 1 or 3, 818 cards
-*/
-#ifdef PCL818_MODE13_AO
-static int pcl818_ao_mode13(int mode, struct comedi_device *dev,
- struct comedi_subdevice *s, comedi_trig *it)
-{
- struct pcl818_private *devpriv = dev->private;
- int divisor1 = 0, divisor2 = 0;
-
- if (!dev->irq) {
- comedi_error(dev, "IRQ not defined!");
- return -EINVAL;
- }
-
- if (devpriv->irq_blocked)
- return -EBUSY;
-
- start_pacer(dev, -1, 0, 0); /* stop pacer */
-
- devpriv->int13_act_scan = it->n;
- devpriv->int13_act_chan = 0;
- devpriv->irq_blocked = 1;
- devpriv->irq_was_now_closed = 0;
- devpriv->neverending_ai = 0;
- devpriv->act_chanlist_pos = 0;
-
- if (mode == 1) {
- i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1,
- &divisor2, &it->trigvar,
- TRIG_ROUND_NEAREST);
- if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */
- divisor1 = 2;
- divisor2 /= 2;
- }
- if (divisor2 == 1) {
- divisor2 = 2;
- divisor1 /= 2;
- }
- }
-
- outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */
- if (mode == 1) {
- devpriv->int818_mode = INT_TYPE_AO1_INT;
- outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */
- } else {
- devpriv->int818_mode = INT_TYPE_AO3_INT;
- outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */
- };
-
- start_pacer(dev, mode, divisor1, divisor2);
-
- return 0;
-}
-
-/*
-==============================================================================
- ANALOG OUTPUT MODE 1, 818 cards
-*/
-static int pcl818_ao_mode1(struct comedi_device *dev,
- struct comedi_subdevice *s, comedi_trig *it)
-{
- return pcl818_ao_mode13(1, dev, s, it);
-}
-
-/*
-==============================================================================
- ANALOG OUTPUT MODE 3, 818 cards
-*/
-static int pcl818_ao_mode3(struct comedi_device *dev,
- struct comedi_subdevice *s, comedi_trig *it)
-{
- return pcl818_ao_mode13(3, dev, s, it);
-}
-#endif
-#endif
-
/*
==============================================================================
Start/stop pacer onboard pacer
@@ -1391,12 +1115,6 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
devpriv->irq_was_now_closed = 1;
switch (devpriv->ai_mode) {
-#ifdef unused
- case INT_TYPE_AI1_DMA_RTC:
- case INT_TYPE_AI3_DMA_RTC:
- set_rtc_irq_bit(0); /* stop RTC */
- del_timer(&devpriv->rtc_irq_timer);
-#endif
case INT_TYPE_AI1_DMA:
case INT_TYPE_AI3_DMA:
if (devpriv->neverending_ai ||
@@ -1499,102 +1217,11 @@ static void pcl818_reset(struct comedi_device *dev)
}
}
-#ifdef unused
-/*
-==============================================================================
- Enable(1)/disable(0) periodic interrupts from RTC
-*/
-static int set_rtc_irq_bit(unsigned char bit)
-{
- unsigned char val;
- unsigned long flags;
-
- if (bit == 1) {
- RTC_timer_lock++;
- if (RTC_timer_lock > 1)
- return 0;
- } else {
- RTC_timer_lock--;
- if (RTC_timer_lock < 0)
- RTC_timer_lock = 0;
- if (RTC_timer_lock > 0)
- return 0;
- }
-
- save_flags(flags);
- cli();
- val = CMOS_READ(RTC_CONTROL);
- if (bit)
- val |= RTC_PIE;
- else
- val &= ~RTC_PIE;
-
- CMOS_WRITE(val, RTC_CONTROL);
- CMOS_READ(RTC_INTR_FLAGS);
- restore_flags(flags);
- return 0;
-}
-
-/*
-==============================================================================
- Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers)
-*/
-static void rtc_dropped_irq(unsigned long data)
-{
- struct comedi_device *dev = (void *)data;
- struct pcl818_private *devpriv = dev->private;
- unsigned long flags, tmp;
-
- switch (devpriv->int818_mode) {
- case INT_TYPE_AI1_DMA_RTC:
- case INT_TYPE_AI3_DMA_RTC:
- mod_timer(&devpriv->rtc_irq_timer,
- jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100);
- save_flags(flags);
- cli();
- tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */
- restore_flags(flags);
- break;
- }
-}
-
-/*
-==============================================================================
- Set frequency of interrupts from RTC
-*/
-static int rtc_setfreq_irq(int freq)
-{
- int tmp = 0;
- int rtc_freq;
- unsigned char val;
- unsigned long flags;
-
- if (freq < 2)
- freq = 2;
- if (freq > 8192)
- freq = 8192;
-
- while (freq > (1 << tmp))
- tmp++;
-
- rtc_freq = 1 << tmp;
-
- save_flags(flags);
- cli();
- val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
- val |= (16 - tmp);
- CMOS_WRITE(val, RTC_FREQ_SELECT);
- restore_flags(flags);
- return rtc_freq;
-}
-#endif
-
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl818_board *board = comedi_board(dev);
struct pcl818_private *devpriv;
int ret;
- unsigned long iobase;
unsigned int irq;
int dma;
unsigned long pages;
@@ -1605,31 +1232,21 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
dev->private = devpriv;
- /* claim our I/O space */
- iobase = it->options[0];
- printk
- ("comedi%d: pcl818: board=%s, ioport=0x%03lx",
- dev->minor, board->name, iobase);
devpriv->io_range = board->io_range;
if ((board->fifo) && (it->options[2] == -1)) {
/* we've board with FIFO and we want to use FIFO */
devpriv->io_range = PCLx1xFIFO_RANGE;
devpriv->usefifo = 1;
}
- if (!request_region(iobase, devpriv->io_range, "pcl818")) {
- comedi_error(dev, "I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], devpriv->io_range);
+ if (ret)
+ return ret;
- if (pcl818_check(iobase)) {
+ if (pcl818_check(dev->iobase)) {
comedi_error(dev, "I can't detect board. FAIL!\n");
return -EIO;
}
- dev->board_name = board->name;
-
/* grab our IRQ */
irq = 0;
if (board->IRQbits != 0) { /* board support IRQ */
@@ -1641,8 +1258,8 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
irq);
irq = 0; /* Bad IRQ */
} else {
- if (request_irq
- (irq, interrupt_pcl818, 0, "pcl818", dev)) {
+ if (request_irq(irq, interrupt_pcl818, 0,
+ dev->board_name, dev)) {
printk
(", unable to allocate IRQ %u, DISABLING IT",
irq);
@@ -1663,41 +1280,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */
devpriv->ai_mode = 0; /* mode of irq */
-#ifdef unused
- /* grab RTC for DMA operations */
- devpriv->dma_rtc = 0;
- if (it->options[2] > 0) { /* we want to use DMA */
- if (RTC_lock == 0) {
- if (!request_region(RTC_PORT(0), RTC_IO_EXTENT,
- "pcl818 (RTC)"))
- goto no_rtc;
- }
- devpriv->rtc_iobase = RTC_PORT(0);
- devpriv->rtc_iosize = RTC_IO_EXTENT;
- RTC_lock++;
- if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0,
- "pcl818 DMA (RTC)", dev)) {
- devpriv->dma_rtc = 1;
- devpriv->rtc_irq = RTC_IRQ;
- printk(KERN_DEBUG "dma_irq=%u", devpriv->rtc_irq);
- } else {
- RTC_lock--;
- if (RTC_lock == 0) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
- devpriv->rtc_iobase = 0;
- devpriv->rtc_iosize = 0;
- }
- }
-
-no_rtc:
-#endif
/* grab our DMA */
dma = 0;
devpriv->dma = dma;
- if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0))
+ if (!devpriv->irq_free)
goto no_dma; /* if we haven't IRQ, we can't use DMA */
if (board->DMAbits != 0) { /* board support DMA */
dma = it->options[2];
@@ -1707,7 +1293,7 @@ no_rtc:
printk(KERN_ERR "DMA is out of allowed range, FAIL!\n");
return -EINVAL; /* Bad DMA */
}
- ret = request_dma(dma, "pcl818");
+ ret = request_dma(dma, dev->board_name);
if (ret)
return -EBUSY; /* DMA isn't free */
devpriv->dma = dma;
@@ -1720,15 +1306,12 @@ no_rtc:
devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]);
devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE;
/* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */
- if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */
- devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
- if (!devpriv->dmabuf[1])
- return -EBUSY;
- devpriv->dmapages[1] = pages;
- devpriv->hwdmaptr[1] =
- virt_to_bus((void *)devpriv->dmabuf[1]);
- devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
- }
+ devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages);
+ if (!devpriv->dmabuf[1])
+ return -EBUSY;
+ devpriv->dmapages[1] = pages;
+ devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]);
+ devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE;
}
no_dma:
@@ -1758,7 +1341,7 @@ no_dma:
s->range_table = board->ai_range_type;
s->cancel = pcl818_ai_cancel;
s->insn_read = pcl818_ai_insn_read;
- if ((irq) || (devpriv->dma_rtc)) {
+ if (irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->do_cmdtest = ai_cmdtest;
@@ -1815,14 +1398,6 @@ no_dma:
s->range_table = board->ao_range_type;
s->insn_read = pcl818_ao_insn_read;
s->insn_write = pcl818_ao_insn_write;
-#ifdef unused
-#ifdef PCL818_MODE13_AO
- if (irq) {
- s->trig[1] = pcl818_ao_mode1;
- s->trig[3] = pcl818_ao_mode3;
- }
-#endif
-#endif
if (board->is_818) {
if ((it->options[4] == 1) || (it->options[4] == 10))
s->range_table = &range_unipolar10;
@@ -1896,22 +1471,8 @@ static void pcl818_detach(struct comedi_device *dev)
free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
if (devpriv->dmabuf[1])
free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
- if (devpriv->dma_rtc)
- RTC_lock--;
-#endif
}
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, devpriv->io_range);
+ comedi_legacy_detach(dev);
}
static const struct pcl818_board boardtypes[] = {
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index 5f062df1ead4..4ef0df30b07a 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -226,29 +226,16 @@ static int pcm3724_attach(struct comedi_device *dev,
{
struct priv_pcm3724 *priv;
struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iorange;
int ret, i;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
- iorange = PCM3724_SIZE;
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev->private = priv;
- printk(KERN_INFO "comedi%d: pcm3724: board=%s, 0x%03lx ", dev->minor,
- dev->board_name, iobase);
- if (!iobase || !request_region(iobase, iorange, "pcm3724")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
- printk(KERN_INFO "\n");
+ ret = comedi_request_region(dev, it->options[0], PCM3724_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
@@ -265,17 +252,11 @@ static int pcm3724_attach(struct comedi_device *dev,
static void pcm3724_detach(struct comedi_device *dev)
{
- struct comedi_subdevice *s;
int i;
- if (dev->subdevices) {
- for (i = 0; i < dev->n_subdevices; i++) {
- s = &dev->subdevices[i];
- subdev_8255_cleanup(dev, s);
- }
- }
- if (dev->iobase)
- release_region(dev->iobase, PCM3724_SIZE);
+ for (i = 0; i < dev->n_subdevices; i++)
+ comedi_spriv_free(dev, i);
+ comedi_legacy_detach(dev);
}
static struct comedi_driver pcm3724_driver = {
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index 067f14d22610..3a3ce2c769a2 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -54,19 +54,11 @@ static int pcm3730_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, PCM3730_SIZE, "pcm3730")) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
- dev->board_name = "pcm3730";
- dev->iobase = dev->iobase;
- dev->irq = 0;
+ ret = comedi_request_region(dev, it->options[0], PCM3730_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 6);
if (ret)
@@ -131,17 +123,11 @@ static int pcm3730_attach(struct comedi_device *dev,
return 0;
}
-static void pcm3730_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, PCM3730_SIZE);
-}
-
static struct comedi_driver pcm3730_driver = {
.driver_name = "pcm3730",
.module = THIS_MODULE,
.attach = pcm3730_attach,
- .detach = pcm3730_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(pcm3730_driver);
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 13e84215fac3..b7c932e152e0 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -105,18 +105,12 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcmad_board_struct *board = comedi_board(dev);
struct pcmad_priv_struct *devpriv;
- int ret;
struct comedi_subdevice *s;
- unsigned long iobase;
+ int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: pcmad: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, PCMAD_SIZE, "pcmad")) {
- printk(KERN_CONT "I/O port conflict\n");
- return -EIO;
- }
- printk(KERN_CONT "\n");
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], PCMAD_SIZE);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -127,8 +121,6 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
dev->private = devpriv;
- dev->board_name = board->name;
-
s = &dev->subdevices[0];
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | AREF_GROUND;
@@ -141,14 +133,6 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void pcmad_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, PCMAD_SIZE);
-}
-
static const struct pcmad_board_struct pcmad_boards[] = {
{
.name = "pcmad12",
@@ -162,7 +146,7 @@ static struct comedi_driver pcmad_driver = {
.driver_name = "pcmad",
.module = THIS_MODULE,
.attach = pcmad_attach,
- .detach = pcmad_detach,
+ .detach = comedi_legacy_detach,
.board_name = &pcmad_boards[0].name,
.num_names = ARRAY_SIZE(pcmad_boards),
.offset = sizeof(pcmad_boards[0]),
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 13f79f49748a..61e7fd14a1e8 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -154,21 +154,11 @@ static int pcmda12_attach(struct comedi_device *dev,
{
struct pcmda12_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO
- "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name,
- iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
-
- if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- dev->board_name = dev->driver->driver_name;
+ ret = comedi_request_region(dev, it->options[0], IOSIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -193,22 +183,14 @@ static int pcmda12_attach(struct comedi_device *dev,
zero_chans(dev); /* clear out all the registers, basically */
- printk(KERN_INFO "attached\n");
-
return 1;
}
-static void pcmda12_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, IOSIZE);
-}
-
static struct comedi_driver pcmda12_driver = {
.driver_name = "pcmda12",
.module = THIS_MODULE,
.attach = pcmda12_attach,
- .detach = pcmda12_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(pcmda12_driver);
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index 5fa1fe08eb97..5a236cd5b33d 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -1034,24 +1034,14 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
thisasic_chanct = 0;
- unsigned long iobase;
unsigned int irq[MAX_ASICS];
int ret;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
irq[0] = it->options[1];
- printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
- dev->board_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase, 32, dev->board_name)) {
- printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
- return -EIO;
- }
+ ret = comedi_request_region(dev, it->options[0], 32);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -1203,13 +1193,6 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->asics[asic].irq = irq[asic];
}
- dev->irq = irq[0]; /*
- * grr.. wish comedi dev struct supported
- * multiple irqs..
- */
-
- printk(KERN_INFO "comedi%d: attached\n", dev->minor);
-
return 1;
}
@@ -1218,14 +1201,13 @@ static void pcmmio_detach(struct comedi_device *dev)
struct pcmmio_private *devpriv = dev->private;
int i;
- if (dev->iobase)
- release_region(dev->iobase, 32);
for (i = 0; i < MAX_ASICS; ++i) {
if (devpriv && devpriv->asics[i].irq)
free_irq(devpriv->asics[i].irq, dev);
}
if (devpriv && devpriv->sprivs)
kfree(devpriv->sprivs);
+ comedi_legacy_detach(dev);
}
static struct comedi_driver pcmmio_driver = {
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 433270ceda4f..0c98e26bbba1 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -800,27 +800,16 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct pcmuio_private *devpriv;
struct comedi_subdevice *s;
int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
- unsigned long iobase;
unsigned int irq[MAX_ASICS];
int ret;
- iobase = it->options[0];
irq[0] = it->options[1];
irq[1] = it->options[2];
- dev_dbg(dev->class_dev, "%s: io: %lx attach\n",
- dev->driver->driver_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase,
- board->num_asics * ASIC_IOSIZE,
- dev->driver->driver_name)) {
- dev_err(dev->class_dev, "I/O port conflict\n");
- return -EIO;
- }
-
- dev->board_name = board->name;
+ ret = comedi_request_region(dev, it->options[0],
+ board->num_asics * ASIC_IOSIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -928,9 +917,6 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->asics[asic].irq = irq[asic];
}
- dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
- irqs.. */
-
if (irq[0]) {
dev_dbg(dev->class_dev, "irq: %u\n", irq[0]);
if (irq[1] && board->num_asics == 2)
@@ -946,18 +932,16 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void pcmuio_detach(struct comedi_device *dev)
{
- const struct pcmuio_board *board = comedi_board(dev);
struct pcmuio_private *devpriv = dev->private;
int i;
- if (dev->iobase)
- release_region(dev->iobase, ASIC_IOSIZE * board->num_asics);
for (i = 0; i < MAX_ASICS; ++i) {
if (devpriv->asics[i].irq)
free_irq(devpriv->asics[i].irq, dev);
}
if (devpriv && devpriv->sprivs)
kfree(devpriv->sprivs);
+ comedi_legacy_detach(dev);
}
static const struct pcmuio_board pcmuio_boards[] = {
diff --git a/drivers/staging/comedi/drivers/plx9052.h b/drivers/staging/comedi/drivers/plx9052.h
index 5894739ff426..ff76fbb4b3ef 100644
--- a/drivers/staging/comedi/drivers/plx9052.h
+++ b/drivers/staging/comedi/drivers/plx9052.h
@@ -27,60 +27,58 @@
#define _PLX9052_H_
/*
- * PLX PCI9052 INTCSR register.
+ * INTCSR - Interrupt Control/Status register
*/
-#define PLX9052_INTCSR 0x4C /* Offset in Local Configuration Registers */
-/* Local Interrupt 1 Enable */
-#define PLX9052_INTCSR_LI1ENAB_MASK 0x0001
-#define PLX9052_INTCSR_LI1ENAB_DISABLED 0x0000
-#define PLX9052_INTCSR_LI1ENAB_ENABLED 0x0001
-/* Local Interrupt 1 Polarity */
-#define PLX9052_INTCSR_LI1POL_MASK 0x0002
-#define PLX9052_INTCSR_LI1POL_LOW 0x0000
-#define PLX9052_INTCSR_LI1POL_HIGH 0x0002
-/* Local Interrupt 1 Status (read-only) */
-#define PLX9052_INTCSR_LI1STAT_MASK 0x0004
-#define PLX9052_INTCSR_LI1STAT_INACTIVE 0x0000
-#define PLX9052_INTCSR_LI1STAT_ACTIVE 0x0004
-/* Local Interrupt 2 Enable */
-#define PLX9052_INTCSR_LI2ENAB_MASK 0x0008
-#define PLX9052_INTCSR_LI2ENAB_DISABLED 0x0000
-#define PLX9052_INTCSR_LI2ENAB_ENABLED 0x0008
-/* Local Interrupt 2 Polarity */
-#define PLX9052_INTCSR_LI2POL_MASK 0x0010
-#define PLX9052_INTCSR_LI2POL_LOW 0x0000
-#define PLX9052_INTCSR_LI2POL_HIGH 0x0010
-/* Local Interrupt 2 Status (read-only) */
-#define PLX9052_INTCSR_LI2STAT_MASK 0x0020
-#define PLX9052_INTCSR_LI2STAT_INACTIVE 0x0000
-#define PLX9052_INTCSR_LI2STAT_ACTIVE 0x0020
-/* PCI Interrupt Enable */
-#define PLX9052_INTCSR_PCIENAB_MASK 0x0040
-#define PLX9052_INTCSR_PCIENAB_DISABLED 0x0000
-#define PLX9052_INTCSR_PCIENAB_ENABLED 0x0040
-/* Software Interrupt */
-#define PLX9052_INTCSR_SOFTINT_MASK 0x0080
-#define PLX9052_INTCSR_SOFTINT_UNASSERTED 0x0000
-#define PLX9052_INTCSR_SOFTINT_ASSERTED 0x0080
-/* Local Interrupt 1 Select Enable */
-#define PLX9052_INTCSR_LI1SEL_MASK 0x0100
-#define PLX9052_INTCSR_LI1SEL_LEVEL 0x0000
-#define PLX9052_INTCSR_LI1SEL_EDGE 0x0100
-/* Local Interrupt 2 Select Enable */
-#define PLX9052_INTCSR_LI2SEL_MASK 0x0200
-#define PLX9052_INTCSR_LI2SEL_LEVEL 0x0000
-#define PLX9052_INTCSR_LI2SEL_EDGE 0x0200
-/* Local Edge Triggerable Interrupt 1 Clear Bit */
-#define PLX9052_INTCSR_LI1CLRINT_MASK 0x0400
-#define PLX9052_INTCSR_LI1CLRINT_UNASSERTED 0x0000
-#define PLX9052_INTCSR_LI1CLRINT_ASSERTED 0x0400
-/* Local Edge Triggerable Interrupt 2 Clear Bit */
-#define PLX9052_INTCSR_LI2CLRINT_MASK 0x0800
-#define PLX9052_INTCSR_LI2CLRINT_UNASSERTED 0x0000
-#define PLX9052_INTCSR_LI2CLRINT_ASSERTED 0x0800
-/* ISA Interface Mode Enable (read-only over PCI bus) */
-#define PLX9052_INTCSR_ISAMODE_MASK 0x1000
-#define PLX9052_INTCSR_ISAMODE_DISABLED 0x0000
-#define PLX9052_INTCSR_ISAMODE_ENABLED 0x1000
+#define PLX9052_INTCSR 0x4c
+#define PLX9052_INTCSR_LI1ENAB (1 << 0) /* LI1 enabled */
+#define PLX9052_INTCSR_LI1POL (1 << 1) /* LI1 active high */
+#define PLX9052_INTCSR_LI1STAT (1 << 2) /* LI1 active */
+#define PLX9052_INTCSR_LI2ENAB (1 << 3) /* LI2 enabled */
+#define PLX9052_INTCSR_LI2POL (1 << 4) /* LI2 active high */
+#define PLX9052_INTCSR_LI2STAT (1 << 5) /* LI2 active */
+#define PLX9052_INTCSR_PCIENAB (1 << 6) /* PCIINT enabled */
+#define PLX9052_INTCSR_SOFTINT (1 << 7) /* generate soft int */
+#define PLX9052_INTCSR_LI1SEL (1 << 8) /* LI1 edge */
+#define PLX9052_INTCSR_LI2SEL (1 << 9) /* LI2 edge */
+#define PLX9052_INTCSR_LI1CLRINT (1 << 10) /* LI1 clear int */
+#define PLX9052_INTCSR_LI2CLRINT (1 << 11) /* LI2 clear int */
+#define PLX9052_INTCSR_ISAMODE (1 << 12) /* ISA interface mode */
+
+/*
+ * CNTRL - User I/O, Direct Slave Response, Serial EEPROM, and
+ * Initialization Control register
+ */
+#define PLX9052_CNTRL 0x50
+#define PLX9052_CNTRL_WAITO (1 << 0) /* UIO0 or WAITO# select */
+#define PLX9052_CNTRL_UIO0_DIR (1 << 1) /* UIO0 direction */
+#define PLX9052_CNTRL_UIO0_DATA (1 << 2) /* UIO0 data */
+#define PLX9052_CNTRL_LLOCKO (1 << 3) /* UIO1 or LLOCKo# select */
+#define PLX9052_CNTRL_UIO1_DIR (1 << 4) /* UIO1 direction */
+#define PLX9052_CNTRL_UIO1_DATA (1 << 5) /* UIO1 data */
+#define PLX9052_CNTRL_CS2 (1 << 6) /* UIO2 or CS2# select */
+#define PLX9052_CNTRL_UIO2_DIR (1 << 7) /* UIO2 direction */
+#define PLX9052_CNTRL_UIO2_DATA (1 << 8) /* UIO2 data */
+#define PLX9052_CNTRL_CS3 (1 << 9) /* UIO3 or CS3# select */
+#define PLX9052_CNTRL_UIO3_DIR (1 << 10) /* UIO3 direction */
+#define PLX9052_CNTRL_UIO3_DATA (1 << 11) /* UIO3 data */
+#define PLX9052_CNTRL_PCIBAR01 (0 << 12) /* bar 0 (mem) and 1 (I/O) */
+#define PLX9052_CNTRL_PCIBAR0 (1 << 12) /* bar 0 (mem) only */
+#define PLX9052_CNTRL_PCIBAR1 (2 << 12) /* bar 1 (I/O) only */
+#define PLX9052_CNTRL_PCI2_1_FEATURES (1 << 14) /* PCI r2.1 features enabled */
+#define PLX9052_CNTRL_PCI_R_W_FLUSH (1 << 15) /* read w/write flush mode */
+#define PLX9052_CNTRL_PCI_R_NO_FLUSH (1 << 16) /* read no flush mode */
+#define PLX9052_CNTRL_PCI_R_NO_WRITE (1 << 17) /* read no write mode */
+#define PLX9052_CNTRL_PCI_W_RELEASE (1 << 18) /* write release bus mode */
+#define PLX9052_CNTRL_RETRY_CLKS(x) (((x) & 0xf) << 19) /* slave retry clks */
+#define PLX9052_CNTRL_LOCK_ENAB (1 << 23) /* slave LOCK# enable */
+#define PLX9052_CNTRL_EEPROM_MASK (0x1f << 24) /* EEPROM bits */
+#define PLX9052_CNTRL_EEPROM_CLK (1 << 24) /* EEPROM clock */
+#define PLX9052_CNTRL_EEPROM_CS (1 << 25) /* EEPROM chip select */
+#define PLX9052_CNTRL_EEPROM_DOUT (1 << 26) /* EEPROM write bit */
+#define PLX9052_CNTRL_EEPROM_DIN (1 << 27) /* EEPROM read bit */
+#define PLX9052_CNTRL_EEPROM_PRESENT (1 << 28) /* EEPROM present */
+#define PLX9052_CNTRL_RELOAD_CFG (1 << 29) /* reload configuration */
+#define PLX9052_CNTRL_PCI_RESET (1 << 30) /* PCI adapter reset */
+#define PLX9052_CNTRL_MASK_REV (1 << 31) /* mask revision */
#endif /* _PLX9052_H_ */
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index d7842c95d982..b55a16baeb14 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -139,29 +139,11 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct boarddef_struct *board = comedi_board(dev);
struct poc_private *devpriv;
struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iosize;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
- board->name, iobase);
-
- dev->board_name = board->name;
-
- if (iobase == 0) {
- printk(KERN_ERR "io base address required\n");
- return -EINVAL;
- }
-
- iosize = board->iosize;
- /* check if io addresses are available */
- if (!request_region(iobase, iosize, "dac02")) {
- printk(KERN_ERR "I/O port conflict: failed to allocate ports "
- "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], board->iosize);
+ if (ret)
+ return ret;
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -187,14 +169,6 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void poc_detach(struct comedi_device *dev)
-{
- const struct boarddef_struct *board = comedi_board(dev);
-
- if (dev->iobase)
- release_region(dev->iobase, board->iosize);
-}
-
static const struct boarddef_struct boards[] = {
{
.name = "dac02",
@@ -229,7 +203,7 @@ static struct comedi_driver poc_driver = {
.driver_name = "poc",
.module = THIS_MODULE,
.attach = poc_attach,
- .detach = poc_detach,
+ .detach = comedi_legacy_detach,
.board_name = &boards[0].name,
.num_names = ARRAY_SIZE(boards),
.offset = sizeof(boards[0]),
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 911eb6b32296..e092ce87722e 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -715,8 +715,6 @@ static int daqp_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 6a5c914fa501..30a17284fac9 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -1,105 +1,103 @@
/*
- comedi/drivers/rtd520.c
- Comedi driver for Real Time Devices (RTD) PCI4520/DM7520
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2001 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ * comedi/drivers/rtd520.c
+ * Comedi driver for Real Time Devices (RTD) PCI4520/DM7520
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2001 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-/*
-Driver: rtd520
-Description: Real Time Devices PCI4520/DM7520
-Author: Dan Christian
-Devices: [Real Time Devices] DM7520HR-1 (rtd520), DM7520HR-8,
- PCI4520, PCI4520-8
-Status: Works. Only tested on DM7520-8. Not SMP safe.
-
-Configuration options:
- [0] - PCI bus of device (optional)
- If bus / slot is not specified, the first available PCI
- device will be used.
- [1] - PCI slot of device (optional)
-*/
/*
- Created by Dan Christian, NASA Ames Research Center.
-
- The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card.
- Both have:
- 8/16 12 bit ADC with FIFO and channel gain table
- 8 bits high speed digital out (for external MUX) (or 8 in or 8 out)
- 8 bits high speed digital in with FIFO and interrupt on change (or 8 IO)
- 2 12 bit DACs with FIFOs
- 2 bits output
- 2 bits input
- bus mastering DMA
- timers: ADC sample, pacer, burst, about, delay, DA1, DA2
- sample counter
- 3 user timer/counters (8254)
- external interrupt
-
- The DM7520 has slightly fewer features (fewer gain steps).
-
- These boards can support external multiplexors and multi-board
- synchronization, but this driver doesn't support that.
-
- Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
- Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
- Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
- Call them and ask for the register level manual.
- PCI chip: http://www.plxtech.com/products/io/pci9080
-
- Notes:
- This board is memory mapped. There is some IO stuff, but it isn't needed.
-
- I use a pretty loose naming style within the driver (rtd_blah).
- All externally visible names should be rtd520_blah.
- I use camelCase for structures (and inside them).
- I may also use upper CamelCase for function names (old habit).
-
- This board is somewhat related to the RTD PCI4400 board.
-
- I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and
- das1800, since they have the best documented code. Driver
- cb_pcidas64.c uses the same DMA controller.
-
- As far as I can tell, the About interrupt doesn't work if Sample is
- also enabled. It turns out that About really isn't needed, since
- we always count down samples read.
-
- There was some timer/counter code, but it didn't follow the right API.
-
-*/
+ * Driver: rtd520
+ * Description: Real Time Devices PCI4520/DM7520
+ * Devices: (Real Time Devices) DM7520HR-1 [DM7520]
+ * (Real Time Devices) DM7520HR-8 [DM7520]
+ * (Real Time Devices) PCI4520 [PCI4520]
+ * (Real Time Devices) PCI4520-8 [PCI4520]
+ * Author: Dan Christian
+ * Status: Works. Only tested on DM7520-8. Not SMP safe.
+ *
+ * Configuration options: not applicable, uses PCI auto config
+ */
/*
- driver status:
-
- Analog-In supports instruction and command mode.
-
- With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2
- (single channel, 64K read buffer). I get random system lockups when
- using DMA with ALI-15xx based systems. I haven't been able to test
- any other chipsets. The lockups happen soon after the start of an
- acquistion, not in the middle of a long run.
-
- Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2
- (with a 256K read buffer).
-
- Digital-IO and Analog-Out only support instruction mode.
+ * Created by Dan Christian, NASA Ames Research Center.
+ *
+ * The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card.
+ * Both have:
+ * 8/16 12 bit ADC with FIFO and channel gain table
+ * 8 bits high speed digital out (for external MUX) (or 8 in or 8 out)
+ * 8 bits high speed digital in with FIFO and interrupt on change (or 8 IO)
+ * 2 12 bit DACs with FIFOs
+ * 2 bits output
+ * 2 bits input
+ * bus mastering DMA
+ * timers: ADC sample, pacer, burst, about, delay, DA1, DA2
+ * sample counter
+ * 3 user timer/counters (8254)
+ * external interrupt
+ *
+ * The DM7520 has slightly fewer features (fewer gain steps).
+ *
+ * These boards can support external multiplexors and multi-board
+ * synchronization, but this driver doesn't support that.
+ *
+ * Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
+ * Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
+ * Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
+ * Call them and ask for the register level manual.
+ * PCI chip: http://www.plxtech.com/products/io/pci9080
+ *
+ * Notes:
+ * This board is memory mapped. There is some IO stuff, but it isn't needed.
+ *
+ * I use a pretty loose naming style within the driver (rtd_blah).
+ * All externally visible names should be rtd520_blah.
+ * I use camelCase for structures (and inside them).
+ * I may also use upper CamelCase for function names (old habit).
+ *
+ * This board is somewhat related to the RTD PCI4400 board.
+ *
+ * I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and
+ * das1800, since they have the best documented code. Driver cb_pcidas64.c
+ * uses the same DMA controller.
+ *
+ * As far as I can tell, the About interrupt doesn't work if Sample is
+ * also enabled. It turns out that About really isn't needed, since
+ * we always count down samples read.
+ *
+ * There was some timer/counter code, but it didn't follow the right API.
+ */
-*/
+/*
+ * driver status:
+ *
+ * Analog-In supports instruction and command mode.
+ *
+ * With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2
+ * (single channel, 64K read buffer). I get random system lockups when
+ * using DMA with ALI-15xx based systems. I haven't been able to test
+ * any other chipsets. The lockups happen soon after the start of an
+ * acquistion, not in the middle of a long run.
+ *
+ * Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2
+ * (with a 256K read buffer).
+ *
+ * Digital-IO and Analog-Out only support instruction mode.
+ */
#include <linux/pci.h>
#include <linux/delay.h>
@@ -108,9 +106,123 @@ Configuration options:
#include "../comedidev.h"
#include "comedi_fc.h"
-#include "rtd520.h"
#include "plx9080.h"
+/*
+ * Local Address Space 0 Offsets
+ */
+#define LAS0_USER_IO 0x0008 /* User I/O */
+#define LAS0_ADC 0x0010 /* FIFO Status/Software A/D Start */
+#define FS_DAC1_NOT_EMPTY (1 << 0) /* DAC1 FIFO not empty */
+#define FS_DAC1_HEMPTY (1 << 1) /* DAC1 FIFO half empty */
+#define FS_DAC1_NOT_FULL (1 << 2) /* DAC1 FIFO not full */
+#define FS_DAC2_NOT_EMPTY (1 << 4) /* DAC2 FIFO not empty */
+#define FS_DAC2_HEMPTY (1 << 5) /* DAC2 FIFO half empty */
+#define FS_DAC2_NOT_FULL (1 << 6) /* DAC2 FIFO not full */
+#define FS_ADC_NOT_EMPTY (1 << 8) /* ADC FIFO not empty */
+#define FS_ADC_HEMPTY (1 << 9) /* ADC FIFO half empty */
+#define FS_ADC_NOT_FULL (1 << 10) /* ADC FIFO not full */
+#define FS_DIN_NOT_EMPTY (1 << 12) /* DIN FIFO not empty */
+#define FS_DIN_HEMPTY (1 << 13) /* DIN FIFO half empty */
+#define FS_DIN_NOT_FULL (1 << 14) /* DIN FIFO not full */
+#define LAS0_DAC1 0x0014 /* Software D/A1 Update (w) */
+#define LAS0_DAC2 0x0018 /* Software D/A2 Update (w) */
+#define LAS0_DAC 0x0024 /* Software Simultaneous Update (w) */
+#define LAS0_PACER 0x0028 /* Software Pacer Start/Stop */
+#define LAS0_TIMER 0x002c /* Timer Status/HDIN Software Trig. */
+#define LAS0_IT 0x0030 /* Interrupt Status/Enable */
+#define IRQM_ADC_FIFO_WRITE (1 << 0) /* ADC FIFO Write */
+#define IRQM_CGT_RESET (1 << 1) /* Reset CGT */
+#define IRQM_CGT_PAUSE (1 << 3) /* Pause CGT */
+#define IRQM_ADC_ABOUT_CNT (1 << 4) /* About Counter out */
+#define IRQM_ADC_DELAY_CNT (1 << 5) /* Delay Counter out */
+#define IRQM_ADC_SAMPLE_CNT (1 << 6) /* ADC Sample Counter */
+#define IRQM_DAC1_UCNT (1 << 7) /* DAC1 Update Counter */
+#define IRQM_DAC2_UCNT (1 << 8) /* DAC2 Update Counter */
+#define IRQM_UTC1 (1 << 9) /* User TC1 out */
+#define IRQM_UTC1_INV (1 << 10) /* User TC1 out, inverted */
+#define IRQM_UTC2 (1 << 11) /* User TC2 out */
+#define IRQM_DIGITAL_IT (1 << 12) /* Digital Interrupt */
+#define IRQM_EXTERNAL_IT (1 << 13) /* External Interrupt */
+#define IRQM_ETRIG_RISING (1 << 14) /* Ext Trigger rising-edge */
+#define IRQM_ETRIG_FALLING (1 << 15) /* Ext Trigger falling-edge */
+#define LAS0_CLEAR 0x0034 /* Clear/Set Interrupt Clear Mask */
+#define LAS0_OVERRUN 0x0038 /* Pending interrupts/Clear Overrun */
+#define LAS0_PCLK 0x0040 /* Pacer Clock (24bit) */
+#define LAS0_BCLK 0x0044 /* Burst Clock (10bit) */
+#define LAS0_ADC_SCNT 0x0048 /* A/D Sample counter (10bit) */
+#define LAS0_DAC1_UCNT 0x004c /* D/A1 Update counter (10 bit) */
+#define LAS0_DAC2_UCNT 0x0050 /* D/A2 Update counter (10 bit) */
+#define LAS0_DCNT 0x0054 /* Delay counter (16 bit) */
+#define LAS0_ACNT 0x0058 /* About counter (16 bit) */
+#define LAS0_DAC_CLK 0x005c /* DAC clock (16bit) */
+#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 */
+#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 */
+#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 */
+#define LAS0_UTC_CTRL 0x006c /* 8254 TC Control */
+#define LAS0_DIO0 0x0070 /* Digital I/O Port 0 */
+#define LAS0_DIO1 0x0074 /* Digital I/O Port 1 */
+#define LAS0_DIO0_CTRL 0x0078 /* Digital I/O Control */
+#define LAS0_DIO_STATUS 0x007c /* Digital I/O Status */
+#define LAS0_BOARD_RESET 0x0100 /* Board reset */
+#define LAS0_DMA0_SRC 0x0104 /* DMA 0 Sources select */
+#define LAS0_DMA1_SRC 0x0108 /* DMA 1 Sources select */
+#define LAS0_ADC_CONVERSION 0x010c /* A/D Conversion Signal select */
+#define LAS0_BURST_START 0x0110 /* Burst Clock Start Trigger select */
+#define LAS0_PACER_START 0x0114 /* Pacer Clock Start Trigger select */
+#define LAS0_PACER_STOP 0x0118 /* Pacer Clock Stop Trigger select */
+#define LAS0_ACNT_STOP_ENABLE 0x011c /* About Counter Stop Enable */
+#define LAS0_PACER_REPEAT 0x0120 /* Pacer Start Trigger Mode select */
+#define LAS0_DIN_START 0x0124 /* HiSpd DI Sampling Signal select */
+#define LAS0_DIN_FIFO_CLEAR 0x0128 /* Digital Input FIFO Clear */
+#define LAS0_ADC_FIFO_CLEAR 0x012c /* A/D FIFO Clear */
+#define LAS0_CGT_WRITE 0x0130 /* Channel Gain Table Write */
+#define LAS0_CGL_WRITE 0x0134 /* Channel Gain Latch Write */
+#define LAS0_CG_DATA 0x0138 /* Digital Table Write */
+#define LAS0_CGT_ENABLE 0x013c /* Channel Gain Table Enable */
+#define LAS0_CG_ENABLE 0x0140 /* Digital Table Enable */
+#define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */
+#define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */
+#define LAS0_CGT_CLEAR 0x014c /* Clear Channel Gain Table */
+#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */
+#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */
+#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */
+#define LAS0_DAC1_RESET 0x015c /* D/A1 FIFO reset */
+#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */
+#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */
+#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */
+#define LAS0_DAC2_CYCLE 0x016c /* D/A2 cycle mode */
+#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */
+#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */
+#define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */
+#define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */
+#define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */
+#define LAS0_SBUS0_ENABLE 0x0188 /* SyncBus 0 enable */
+#define LAS0_SBUS1_SRC 0x018c /* SyncBus 1 Source select */
+#define LAS0_SBUS1_ENABLE 0x0190 /* SyncBus 1 enable */
+#define LAS0_SBUS2_SRC 0x0198 /* SyncBus 2 Source select */
+#define LAS0_SBUS2_ENABLE 0x019c /* SyncBus 2 enable */
+#define LAS0_ETRG_POLARITY 0x01a4 /* Ext. Trigger polarity select */
+#define LAS0_EINT_POLARITY 0x01a8 /* Ext. Interrupt polarity select */
+#define LAS0_UTC0_CLOCK 0x01ac /* UTC0 Clock select */
+#define LAS0_UTC0_GATE 0x01b0 /* UTC0 Gate select */
+#define LAS0_UTC1_CLOCK 0x01b4 /* UTC1 Clock select */
+#define LAS0_UTC1_GATE 0x01b8 /* UTC1 Gate select */
+#define LAS0_UTC2_CLOCK 0x01bc /* UTC2 Clock select */
+#define LAS0_UTC2_GATE 0x01c0 /* UTC2 Gate select */
+#define LAS0_UOUT0_SELECT 0x01c4 /* User Output 0 source select */
+#define LAS0_UOUT1_SELECT 0x01c8 /* User Output 1 source select */
+#define LAS0_DMA0_RESET 0x01cc /* DMA0 Request state machine reset */
+#define LAS0_DMA1_RESET 0x01d0 /* DMA1 Request state machine reset */
+
+/*
+ * Local Address Space 1 Offsets
+ */
+#define LAS1_ADC_FIFO 0x0000 /* A/D FIFO (16bit) */
+#define LAS1_HDIO_FIFO 0x0004 /* HiSpd DI FIFO (16bit) */
+#define LAS1_DAC1_FIFO 0x0008 /* D/A1 FIFO (16bit) */
+#define LAS1_DAC2_FIFO 0x000c /* D/A2 FIFO (16bit) */
+
/*======================================================================
Driver specific stuff (tunable)
======================================================================*/
@@ -249,61 +361,48 @@ static const struct comedi_lrange rtd_ao_range = {
}
};
-struct rtdBoard {
+enum rtd_boardid {
+ BOARD_DM7520,
+ BOARD_PCI4520,
+};
+
+struct rtd_boardinfo {
const char *name;
- int device_id;
- int range10Start; /* start of +-10V range */
- int rangeUniStart; /* start of +10V range */
+ int range_bip10; /* start of +-10V range */
+ int range_uni10; /* start of +10V range */
const struct comedi_lrange *ai_range;
};
-static const struct rtdBoard rtd520Boards[] = {
- {
+static const struct rtd_boardinfo rtd520Boards[] = {
+ [BOARD_DM7520] = {
.name = "DM7520",
- .device_id = 0x7520,
- .range10Start = 6,
- .rangeUniStart = 12,
+ .range_bip10 = 6,
+ .range_uni10 = 12,
.ai_range = &rtd_ai_7520_range,
- }, {
+ },
+ [BOARD_PCI4520] = {
.name = "PCI4520",
- .device_id = 0x4520,
- .range10Start = 8,
- .rangeUniStart = 16,
+ .range_bip10 = 8,
+ .range_uni10 = 16,
.ai_range = &rtd_ai_4520_range,
},
};
-/*
- This structure is for data unique to this hardware driver.
- This is also unique for each board in the system.
-*/
-struct rtdPrivate {
+struct rtd_private {
/* memory mapped board structures */
void __iomem *las0;
void __iomem *las1;
void __iomem *lcfg;
- long aiCount; /* total transfer size (samples) */
- int transCount; /* # to transfer data. 0->1/2FIFO */
+ long ai_count; /* total transfer size (samples) */
+ int xfer_count; /* # to transfer data. 0->1/2FIFO */
int flags; /* flag event modes */
- /* channel list info */
- /* chanBipolar tracks whether a channel is bipolar (and needs +2048) */
- unsigned char chanBipolar[RTD_MAX_CHANLIST / 8]; /* bit array */
+ unsigned char chan_is_bipolar[RTD_MAX_CHANLIST / 8]; /* bit array */
- /* read back data */
- unsigned int aoValue[2]; /* Used for AO read back */
+ unsigned int ao_readback[2];
- /* timer gate (when enabled) */
- u8 utcGate[4]; /* 1 extra allows simple range check */
-
- /* shadow registers affect other registers, but can't be read back */
- /* The macros below update these on writes */
- u16 intMask; /* interrupt mask */
- u16 intClearMask; /* interrupt clear mask */
- u8 utcCtrl[4]; /* crtl mode for 3 utc + read back */
- u8 dioStatus; /* could be read back (dio0Ctrl) */
- unsigned fifoLen;
+ unsigned fifosz;
};
/* bit defines for "flags" */
@@ -365,36 +464,34 @@ static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
/*
Convert a single comedi channel-gain entry to a RTD520 table entry
*/
-static unsigned short rtdConvertChanGain(struct comedi_device *dev,
- unsigned int comediChan, int chanIndex)
-{ /* index in channel list */
- const struct rtdBoard *thisboard = comedi_board(dev);
- struct rtdPrivate *devpriv = dev->private;
- unsigned int chan, range, aref;
+static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
+ unsigned int chanspec, int index)
+{
+ const struct rtd_boardinfo *board = comedi_board(dev);
+ struct rtd_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(chanspec);
+ unsigned int range = CR_RANGE(chanspec);
+ unsigned int aref = CR_AREF(chanspec);
unsigned short r = 0;
- chan = CR_CHAN(comediChan);
- range = CR_RANGE(comediChan);
- aref = CR_AREF(comediChan);
-
r |= chan & 0xf;
/* Note: we also setup the channel list bipolar flag array */
- if (range < thisboard->range10Start) {
+ if (range < board->range_bip10) {
/* +-5 range */
r |= 0x000;
r |= (range & 0x7) << 4;
- CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
- } else if (range < thisboard->rangeUniStart) {
+ CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index);
+ } else if (range < board->range_uni10) {
/* +-10 range */
r |= 0x100;
- r |= ((range - thisboard->range10Start) & 0x7) << 4;
- CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex);
+ r |= ((range - board->range_bip10) & 0x7) << 4;
+ CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index);
} else {
/* +10 range */
r |= 0x200;
- r |= ((range - thisboard->rangeUniStart) & 0x7) << 4;
- CHAN_ARRAY_CLEAR(devpriv->chanBipolar, chanIndex);
+ r |= ((range - board->range_uni10) & 0x7) << 4;
+ CHAN_ARRAY_CLEAR(devpriv->chan_is_bipolar, index);
}
switch (aref) {
@@ -423,7 +520,7 @@ static unsigned short rtdConvertChanGain(struct comedi_device *dev,
static void rtd_load_channelgain_list(struct comedi_device *dev,
unsigned int n_chan, unsigned int *list)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
if (n_chan > 1) { /* setup channel gain table */
int ii;
@@ -431,12 +528,12 @@ static void rtd_load_channelgain_list(struct comedi_device *dev,
writel(0, devpriv->las0 + LAS0_CGT_CLEAR);
writel(1, devpriv->las0 + LAS0_CGT_ENABLE);
for (ii = 0; ii < n_chan; ii++) {
- writel(rtdConvertChanGain(dev, list[ii], ii),
+ writel(rtd_convert_chan_gain(dev, list[ii], ii),
devpriv->las0 + LAS0_CGT_WRITE);
}
} else { /* just use the channel gain latch */
writel(0, devpriv->las0 + LAS0_CGT_ENABLE);
- writel(rtdConvertChanGain(dev, list[0], 0),
+ writel(rtd_convert_chan_gain(dev, list[0], 0),
devpriv->las0 + LAS0_CGL_WRITE);
}
}
@@ -445,7 +542,7 @@ static void rtd_load_channelgain_list(struct comedi_device *dev,
empty status flag clears */
static int rtd520_probe_fifo_depth(struct comedi_device *dev)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
unsigned i;
static const unsigned limit = 0x2000;
@@ -493,7 +590,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
int n, ii;
int stat;
@@ -525,7 +622,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
d = readw(devpriv->las1 + LAS1_ADC_FIFO);
/*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, 0))
+ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, 0))
/* convert to comedi unsigned data */
data[n] = d + 2048;
else
@@ -545,21 +642,22 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
int count)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
int ii;
for (ii = 0; ii < count; ii++) {
short sample;
s16 d;
- if (0 == devpriv->aiCount) { /* done */
+ if (0 == devpriv->ai_count) { /* done */
d = readw(devpriv->las1 + LAS1_ADC_FIFO);
continue;
}
d = readw(devpriv->las1 + LAS1_ADC_FIFO);
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar,
+ s->async->cur_chan)) {
/* convert to comedi unsigned data */
sample = d + 2048;
} else
@@ -568,8 +666,8 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
if (!comedi_buf_put(s->async, sample))
return -1;
- if (devpriv->aiCount > 0) /* < 0, means read forever */
- devpriv->aiCount--;
+ if (devpriv->ai_count > 0) /* < 0, means read forever */
+ devpriv->ai_count--;
}
return 0;
}
@@ -579,18 +677,19 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
*/
static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) {
short sample;
s16 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
- if (0 == devpriv->aiCount) { /* done */
+ if (0 == devpriv->ai_count) { /* done */
continue; /* read rest */
}
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar,
+ s->async->cur_chan)) {
/* convert to comedi unsigned data */
sample = d + 2048;
} else
@@ -599,8 +698,8 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
if (!comedi_buf_put(s->async, sample))
return -1;
- if (devpriv->aiCount > 0) /* < 0, means read forever */
- devpriv->aiCount--;
+ if (devpriv->ai_count > 0) /* < 0, means read forever */
+ devpriv->ai_count--;
}
return 0;
}
@@ -611,23 +710,22 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
This is a "slow handler"; other interrupts may be active.
The data conversion may someday happen in a "bottom half".
*/
-static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
- void *d)
-{ /* our data *//* cpu context (ignored) */
+static irqreturn_t rtd_interrupt(int irq, void *d)
+{
struct comedi_device *dev = d;
struct comedi_subdevice *s = &dev->subdevices[0];
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
u32 overrun;
u16 status;
- u16 fifoStatus;
+ u16 fifo_status;
if (!dev->attached)
return IRQ_NONE;
- fifoStatus = readl(devpriv->las0 + LAS0_ADC);
+ fifo_status = readl(devpriv->las0 + LAS0_ADC);
/* check for FIFO full, this automatically halts the ADC! */
- if (!(fifoStatus & FS_ADC_NOT_FULL)) /* 0 -> full */
- goto abortTransfer;
+ if (!(fifo_status & FS_ADC_NOT_FULL)) /* 0 -> full */
+ goto xfer_abort;
status = readw(devpriv->las0 + LAS0_IT);
/* if interrupt was not caused by our board, or handled above */
@@ -641,23 +739,23 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
* finished, we must handle the possibility that there is
* no data here
*/
- if (!(fifoStatus & FS_ADC_HEMPTY)) {
+ if (!(fifo_status & FS_ADC_HEMPTY)) {
/* FIFO half full */
- if (ai_read_n(dev, s, devpriv->fifoLen / 2) < 0)
- goto abortTransfer;
+ if (ai_read_n(dev, s, devpriv->fifosz / 2) < 0)
+ goto xfer_abort;
- if (0 == devpriv->aiCount)
- goto transferDone;
+ if (0 == devpriv->ai_count)
+ goto xfer_done;
comedi_event(dev, s);
- } else if (devpriv->transCount > 0) {
- if (fifoStatus & FS_ADC_NOT_EMPTY) {
+ } else if (devpriv->xfer_count > 0) {
+ if (fifo_status & FS_ADC_NOT_EMPTY) {
/* FIFO not empty */
- if (ai_read_n(dev, s, devpriv->transCount) < 0)
- goto abortTransfer;
+ if (ai_read_n(dev, s, devpriv->xfer_count) < 0)
+ goto xfer_abort;
- if (0 == devpriv->aiCount)
- goto transferDone;
+ if (0 == devpriv->ai_count)
+ goto xfer_done;
comedi_event(dev, s);
}
@@ -666,30 +764,28 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
if (overrun)
- goto abortTransfer;
+ goto xfer_abort;
/* clear the interrupt */
- devpriv->intClearMask = status;
- writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ writew(status, devpriv->las0 + LAS0_CLEAR);
readw(devpriv->las0 + LAS0_CLEAR);
return IRQ_HANDLED;
-abortTransfer:
+xfer_abort:
writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
s->async->events |= COMEDI_CB_ERROR;
- devpriv->aiCount = 0; /* stop and don't transfer any more */
- /* fall into transferDone */
+ devpriv->ai_count = 0; /* stop and don't transfer any more */
+ /* fall into xfer_done */
-transferDone:
+xfer_done:
/* pacer stop source: SOFTWARE */
writel(0, devpriv->las0 + LAS0_PACER_STOP);
writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
- devpriv->intMask = 0;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ writew(0, devpriv->las0 + LAS0_IT);
- if (devpriv->aiCount > 0) { /* there shouldn't be anything left */
- fifoStatus = readl(devpriv->las0 + LAS0_ADC);
+ if (devpriv->ai_count > 0) { /* there shouldn't be anything left */
+ fifo_status = readl(devpriv->las0 + LAS0_ADC);
ai_read_dregs(dev, s); /* read anything left in FIFO */
}
@@ -698,11 +794,10 @@ transferDone:
/* clear the interrupt */
status = readw(devpriv->las0 + LAS0_IT);
- devpriv->intClearMask = status;
- writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ writew(status, devpriv->las0 + LAS0_CLEAR);
readw(devpriv->las0 + LAS0_CLEAR);
- fifoStatus = readl(devpriv->las0 + LAS0_ADC);
+ fifo_status = readl(devpriv->las0 + LAS0_ADC);
overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
return IRQ_HANDLED;
@@ -875,7 +970,7 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
*/
static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int timer;
@@ -884,8 +979,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
writel(0, devpriv->las0 + LAS0_PACER_STOP);
writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
- devpriv->intMask = 0;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ writew(0, devpriv->las0 + LAS0_IT);
writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
writel(0, devpriv->las0 + LAS0_OVERRUN);
@@ -907,7 +1001,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* ADC conversion trigger source: PACER */
writel(1, devpriv->las0 + LAS0_ADC_CONVERSION);
}
- writel((devpriv->fifoLen / 2 - 1) & 0xffff, devpriv->las0 + LAS0_ACNT);
+ writel((devpriv->fifosz / 2 - 1) & 0xffff, devpriv->las0 + LAS0_ACNT);
if (TRIG_TIMER == cmd->scan_begin_src) {
/* scan_begin_arg is in nanoseconds */
@@ -918,37 +1012,36 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
* the application is responsible for doing the
* right thing
*/
- devpriv->transCount = cmd->chanlist_len;
+ devpriv->xfer_count = cmd->chanlist_len;
devpriv->flags |= SEND_EOS;
} else {
/* arrange to transfer data periodically */
- devpriv->transCount
- =
+ devpriv->xfer_count =
(TRANS_TARGET_PERIOD * cmd->chanlist_len) /
cmd->scan_begin_arg;
- if (devpriv->transCount < cmd->chanlist_len) {
+ if (devpriv->xfer_count < cmd->chanlist_len) {
/* transfer after each scan (and avoid 0) */
- devpriv->transCount = cmd->chanlist_len;
+ devpriv->xfer_count = cmd->chanlist_len;
} else { /* make a multiple of scan length */
- devpriv->transCount =
- (devpriv->transCount +
+ devpriv->xfer_count =
+ (devpriv->xfer_count +
cmd->chanlist_len - 1)
/ cmd->chanlist_len;
- devpriv->transCount *= cmd->chanlist_len;
+ devpriv->xfer_count *= cmd->chanlist_len;
}
devpriv->flags |= SEND_EOS;
}
- if (devpriv->transCount >= (devpriv->fifoLen / 2)) {
+ if (devpriv->xfer_count >= (devpriv->fifosz / 2)) {
/* out of counter range, use 1/2 fifo instead */
- devpriv->transCount = 0;
+ devpriv->xfer_count = 0;
devpriv->flags &= ~SEND_EOS;
} else {
/* interrupt for each transfer */
- writel((devpriv->transCount - 1) & 0xffff,
+ writel((devpriv->xfer_count - 1) & 0xffff,
devpriv->las0 + LAS0_ACNT);
}
} else { /* unknown timing, just use 1/2 FIFO */
- devpriv->transCount = 0;
+ devpriv->xfer_count = 0;
devpriv->flags &= ~SEND_EOS;
}
/* pacer clock source: INTERNAL 8MHz */
@@ -961,15 +1054,15 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* First, setup when to stop */
switch (cmd->stop_src) {
case TRIG_COUNT: /* stop after N scans */
- devpriv->aiCount = cmd->stop_arg * cmd->chanlist_len;
- if ((devpriv->transCount > 0)
- && (devpriv->transCount > devpriv->aiCount)) {
- devpriv->transCount = devpriv->aiCount;
+ devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;
+ if ((devpriv->xfer_count > 0)
+ && (devpriv->xfer_count > devpriv->ai_count)) {
+ devpriv->xfer_count = devpriv->ai_count;
}
break;
case TRIG_NONE: /* stop when cancel is called */
- devpriv->aiCount = -1; /* read forever */
+ devpriv->ai_count = -1; /* read forever */
break;
}
@@ -1011,17 +1104,14 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* This doesn't seem to work. There is no way to clear an interrupt
that the priority controller has queued! */
- devpriv->intClearMask = ~0;
- writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ writew(~0, devpriv->las0 + LAS0_CLEAR);
readw(devpriv->las0 + LAS0_CLEAR);
/* TODO: allow multiple interrupt sources */
- if (devpriv->transCount > 0) { /* transfer every N samples */
- devpriv->intMask = IRQM_ADC_ABOUT_CNT;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ if (devpriv->xfer_count > 0) { /* transfer every N samples */
+ writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT);
} else { /* 1/2 FIFO transfers */
- devpriv->intMask = IRQM_ADC_ABOUT_CNT;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT);
}
/* BUG: start_src is ASSUMED to be TRIG_NOW */
@@ -1035,7 +1125,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*/
static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
u32 overrun;
u16 status;
@@ -1043,9 +1133,8 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
writel(0, devpriv->las0 + LAS0_PACER_STOP);
writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
- devpriv->intMask = 0;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
- devpriv->aiCount = 0; /* stop and don't transfer any more */
+ writew(0, devpriv->las0 + LAS0_IT);
+ devpriv->ai_count = 0; /* stop and don't transfer any more */
status = readw(devpriv->las0 + LAS0_IT);
overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
return 0;
@@ -1058,7 +1147,7 @@ static int rtd_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
@@ -1090,7 +1179,7 @@ static int rtd_ao_winsn(struct comedi_device *dev,
writew(0, devpriv->las0 +
((chan == 0) ? LAS0_DAC1 : LAS0_DAC2));
- devpriv->aoValue[chan] = data[i]; /* save for read back */
+ devpriv->ao_readback[chan] = data[i];
for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
stat = readl(devpriv->las0 + LAS0_ADC);
@@ -1114,73 +1203,56 @@ static int rtd_ao_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++)
- data[i] = devpriv->aoValue[chan];
+ data[i] = devpriv->ao_readback[chan];
return i;
}
-/*
- Write a masked set of bits and the read back the port.
- We track what the bits should be (i.e. we don't read the port first).
-
- DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The
- * comedi core can convert between insn_bits and insn_read/write
- */
static int rtd_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
- /* The insn data is a mask in data[0] and the new data
- * in data[1], each channel cooresponding to a bit. */
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
- /* Write out the new digital output lines */
writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0);
}
- /* on return, data[1] contains the value of the digital
- * input lines. */
+
data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff;
return insn->n;
}
-/*
- Configure one bit on a IO port as Input or Output (hence the name :-).
-*/
static int rtd_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- struct rtdPrivate *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
+ struct rtd_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask = 1 << chan;
- /* The input or output configuration of each digital line is
- * configured by a special insn_config instruction. chanspec
- * contains the channel to be changed, and data[0] contains the
- * value COMEDI_INPUT or COMEDI_OUTPUT. */
switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits |= 1 << chan; /* 1 means Out */
+ s->io_bits |= mask;
break;
case INSN_CONFIG_DIO_INPUT:
- s->io_bits &= ~(1 << chan);
+ s->io_bits &= ~mask;
break;
case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
+ data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n;
break;
default:
@@ -1188,30 +1260,30 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
}
/* TODO support digital match interrupts and strobes */
- devpriv->dioStatus = 0x01; /* set direction */
- writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
+
+ /* set direction */
+ writew(0x01, devpriv->las0 + LAS0_DIO_STATUS);
writew(s->io_bits & 0xff, devpriv->las0 + LAS0_DIO0_CTRL);
- devpriv->dioStatus = 0x00; /* clear interrupts */
- writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
+
+ /* clear interrupts */
+ writew(0x00, devpriv->las0 + LAS0_DIO_STATUS);
/* port1 can only be all input or all output */
/* there are also 2 user input lines and 2 user output lines */
- return 1;
+ return insn->n;
}
static void rtd_reset(struct comedi_device *dev)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
writel(0, devpriv->las0 + LAS0_BOARD_RESET);
udelay(100); /* needed? */
- writel(0, devpriv->lcfg + LCFG_ITCSR);
- devpriv->intMask = 0;
- writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
- devpriv->intClearMask = ~0;
- writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ writel(0, devpriv->lcfg + PLX_INTRCS_REG);
+ writew(0, devpriv->las0 + LAS0_IT);
+ writew(~0, devpriv->las0 + LAS0_CLEAR);
readw(devpriv->las0 + LAS0_CLEAR);
}
@@ -1221,7 +1293,7 @@ static void rtd_reset(struct comedi_device *dev)
*/
static void rtd_init_board(struct comedi_device *dev)
{
- struct rtdPrivate *devpriv = dev->private;
+ struct rtd_private *devpriv = dev->private;
rtd_reset(dev);
@@ -1231,16 +1303,11 @@ static void rtd_init_board(struct comedi_device *dev)
writel(0, devpriv->las0 + LAS0_DAC1_RESET);
writel(0, devpriv->las0 + LAS0_DAC2_RESET);
/* clear digital IO fifo */
- devpriv->dioStatus = 0;
- writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
- devpriv->utcCtrl[0] = (0 << 6) | 0x30;
- devpriv->utcCtrl[1] = (1 << 6) | 0x30;
- devpriv->utcCtrl[2] = (2 << 6) | 0x30;
- devpriv->utcCtrl[3] = (3 << 6) | 0x00;
- writeb(devpriv->utcCtrl[0], devpriv->las0 + LAS0_UTC_CTRL);
- writeb(devpriv->utcCtrl[1], devpriv->las0 + LAS0_UTC_CTRL);
- writeb(devpriv->utcCtrl[2], devpriv->las0 + LAS0_UTC_CTRL);
- writeb(devpriv->utcCtrl[3], devpriv->las0 + LAS0_UTC_CTRL);
+ writew(0, devpriv->las0 + LAS0_DIO_STATUS);
+ writeb((0 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
+ writeb((1 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
+ writeb((2 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
+ writeb((3 << 6) | 0x00, devpriv->las0 + LAS0_UTC_CTRL);
/* TODO: set user out source ??? */
}
@@ -1259,51 +1326,34 @@ static void rtd_pci_latency_quirk(struct comedi_device *dev,
}
}
-static const void *rtd_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct rtdBoard *thisboard;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(rtd520Boards); i++) {
- thisboard = &rtd520Boards[i];
- if (pcidev->device == thisboard->device_id)
- return thisboard;
- }
- return NULL;
-}
-
static int rtd_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct rtdBoard *thisboard;
- struct rtdPrivate *devpriv;
+ const struct rtd_boardinfo *board = NULL;
+ struct rtd_private *devpriv;
struct comedi_subdevice *s;
int ret;
- thisboard = rtd_find_boardinfo(dev, pcidev);
- if (!thisboard)
+ if (context < ARRAY_SIZE(rtd520Boards))
+ board = &rtd520Boards[context];
+ if (!board)
return -ENODEV;
- dev->board_ptr = thisboard;
- dev->board_name = thisboard->name;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
- dev->iobase = 1; /* the "detach" needs this */
-
- devpriv->las0 = ioremap_nocache(pci_resource_start(pcidev, 2),
- pci_resource_len(pcidev, 2));
- devpriv->las1 = ioremap_nocache(pci_resource_start(pcidev, 3),
- pci_resource_len(pcidev, 3));
- devpriv->lcfg = ioremap_nocache(pci_resource_start(pcidev, 0),
- pci_resource_len(pcidev, 0));
+
+ devpriv->las0 = pci_ioremap_bar(pcidev, 2);
+ devpriv->las1 = pci_ioremap_bar(pcidev, 3);
+ devpriv->lcfg = pci_ioremap_bar(pcidev, 0);
if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
return -ENOMEM;
@@ -1326,7 +1376,7 @@ static int rtd_auto_attach(struct comedi_device *dev,
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
s->n_chan = 16;
s->maxdata = 0x0fff;
- s->range_table = thisboard->ai_range;
+ s->range_table = board->ai_range;
s->len_chanlist = RTD_MAX_CHANLIST;
s->insn_read = rtd_ai_rinsn;
if (dev->irq) {
@@ -1370,10 +1420,10 @@ static int rtd_auto_attach(struct comedi_device *dev,
ret = rtd520_probe_fifo_depth(dev);
if (ret < 0)
return ret;
- devpriv->fifoLen = ret;
+ devpriv->fifosz = ret;
if (dev->irq)
- writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + LCFG_ITCSR);
+ writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG);
dev_info(dev->class_dev, "%s attached\n", dev->board_name);
@@ -1382,17 +1432,16 @@ static int rtd_auto_attach(struct comedi_device *dev,
static void rtd_detach(struct comedi_device *dev)
{
- struct rtdPrivate *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+ struct rtd_private *devpriv = dev->private;
if (devpriv) {
/* Shut down any board ops by resetting it */
if (devpriv->las0 && devpriv->lcfg)
rtd_reset(dev);
if (dev->irq) {
- writel(readl(devpriv->lcfg + LCFG_ITCSR) &
+ writel(readl(devpriv->lcfg + PLX_INTRCS_REG) &
~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E),
- devpriv->lcfg + LCFG_ITCSR);
+ devpriv->lcfg + PLX_INTRCS_REG);
free_irq(dev->irq, dev);
}
if (devpriv->las0)
@@ -1402,10 +1451,7 @@ static void rtd_detach(struct comedi_device *dev)
if (devpriv->lcfg)
iounmap(devpriv->lcfg);
}
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
- }
+ comedi_pci_disable(dev);
}
static struct comedi_driver rtd520_driver = {
@@ -1416,14 +1462,14 @@ static struct comedi_driver rtd520_driver = {
};
static int rtd520_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &rtd520_driver);
+ return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data);
}
static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
+ { PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 },
+ { PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
diff --git a/drivers/staging/comedi/drivers/rtd520.h b/drivers/staging/comedi/drivers/rtd520.h
deleted file mode 100644
index 25188a581455..000000000000
--- a/drivers/staging/comedi/drivers/rtd520.h
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- comedi/drivers/rtd520.h
- Comedi driver defines for Real Time Devices (RTD) PCI4520/DM7520
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2001 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- Created by Dan Christian, NASA Ames Research Center.
- See board notes in rtd520.c
-*/
-
-/*
- * Local Address Space 0 Offsets
- */
-#define LAS0_USER_IO 0x0008 /* User I/O */
-#define LAS0_ADC 0x0010 /* FIFO Status/Software A/D Start */
-#define LAS0_DAC1 0x0014 /* Software D/A1 Update (w) */
-#define LAS0_DAC2 0x0018 /* Software D/A2 Update (w) */
-#define LAS0_DAC 0x0024 /* Software Simultaneous Update (w) */
-#define LAS0_PACER 0x0028 /* Software Pacer Start/Stop */
-#define LAS0_TIMER 0x002c /* Timer Status/HDIN Software Trig. */
-#define LAS0_IT 0x0030 /* Interrupt Status/Enable */
-#define LAS0_CLEAR 0x0034 /* Clear/Set Interrupt Clear Mask */
-#define LAS0_OVERRUN 0x0038 /* Pending interrupts/Clear Overrun */
-#define LAS0_PCLK 0x0040 /* Pacer Clock (24bit) */
-#define LAS0_BCLK 0x0044 /* Burst Clock (10bit) */
-#define LAS0_ADC_SCNT 0x0048 /* A/D Sample counter (10bit) */
-#define LAS0_DAC1_UCNT 0x004c /* D/A1 Update counter (10 bit) */
-#define LAS0_DAC2_UCNT 0x0050 /* D/A2 Update counter (10 bit) */
-#define LAS0_DCNT 0x0054 /* Delay counter (16 bit) */
-#define LAS0_ACNT 0x0058 /* About counter (16 bit) */
-#define LAS0_DAC_CLK 0x005c /* DAC clock (16bit) */
-#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 */
-#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 */
-#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 */
-#define LAS0_UTC_CTRL 0x006c /* 8254 TC Control */
-#define LAS0_DIO0 0x0070 /* Digital I/O Port 0 */
-#define LAS0_DIO1 0x0074 /* Digital I/O Port 1 */
-#define LAS0_DIO0_CTRL 0x0078 /* Digital I/O Control */
-#define LAS0_DIO_STATUS 0x007c /* Digital I/O Status */
-#define LAS0_BOARD_RESET 0x0100 /* Board reset */
-#define LAS0_DMA0_SRC 0x0104 /* DMA 0 Sources select */
-#define LAS0_DMA1_SRC 0x0108 /* DMA 1 Sources select */
-#define LAS0_ADC_CONVERSION 0x010c /* A/D Conversion Signal select */
-#define LAS0_BURST_START 0x0110 /* Burst Clock Start Trigger select */
-#define LAS0_PACER_START 0x0114 /* Pacer Clock Start Trigger select */
-#define LAS0_PACER_STOP 0x0118 /* Pacer Clock Stop Trigger select */
-#define LAS0_ACNT_STOP_ENABLE 0x011c /* About Counter Stop Enable */
-#define LAS0_PACER_REPEAT 0x0120 /* Pacer Start Trigger Mode select */
-#define LAS0_DIN_START 0x0124 /* HiSpd DI Sampling Signal select */
-#define LAS0_DIN_FIFO_CLEAR 0x0128 /* Digital Input FIFO Clear */
-#define LAS0_ADC_FIFO_CLEAR 0x012c /* A/D FIFO Clear */
-#define LAS0_CGT_WRITE 0x0130 /* Channel Gain Table Write */
-#define LAS0_CGL_WRITE 0x0134 /* Channel Gain Latch Write */
-#define LAS0_CG_DATA 0x0138 /* Digital Table Write */
-#define LAS0_CGT_ENABLE 0x013c /* Channel Gain Table Enable */
-#define LAS0_CG_ENABLE 0x0140 /* Digital Table Enable */
-#define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */
-#define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */
-#define LAS0_CGT_CLEAR 0x014c /* Clear Channel Gain Table */
-#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */
-#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */
-#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */
-#define LAS0_DAC1_RESET 0x015c /* D/A1 FIFO reset */
-#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */
-#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */
-#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */
-#define LAS0_DAC2_CYCLE 0x016c /* D/A2 cycle mode */
-#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */
-#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */
-#define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */
-#define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */
-#define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */
-#define LAS0_SBUS0_ENABLE 0x0188 /* SyncBus 0 enable */
-#define LAS0_SBUS1_SRC 0x018c /* SyncBus 1 Source select */
-#define LAS0_SBUS1_ENABLE 0x0190 /* SyncBus 1 enable */
-#define LAS0_SBUS2_SRC 0x0198 /* SyncBus 2 Source select */
-#define LAS0_SBUS2_ENABLE 0x019c /* SyncBus 2 enable */
-#define LAS0_ETRG_POLARITY 0x01a4 /* Ext. Trigger polarity select */
-#define LAS0_EINT_POLARITY 0x01a8 /* Ext. Interrupt polarity select */
-#define LAS0_UTC0_CLOCK 0x01ac /* UTC0 Clock select */
-#define LAS0_UTC0_GATE 0x01b0 /* UTC0 Gate select */
-#define LAS0_UTC1_CLOCK 0x01b4 /* UTC1 Clock select */
-#define LAS0_UTC1_GATE 0x01b8 /* UTC1 Gate select */
-#define LAS0_UTC2_CLOCK 0x01bc /* UTC2 Clock select */
-#define LAS0_UTC2_GATE 0x01c0 /* UTC2 Gate select */
-#define LAS0_UOUT0_SELECT 0x01c4 /* User Output 0 source select */
-#define LAS0_UOUT1_SELECT 0x01c8 /* User Output 1 source select */
-#define LAS0_DMA0_RESET 0x01cc /* DMA0 Request state machine reset */
-#define LAS0_DMA1_RESET 0x01d0 /* DMA1 Request state machine reset */
-
-/*
- * Local Address Space 1 Offsets
- */
-#define LAS1_ADC_FIFO 0x0000 /* A/D FIFO (16bit) */
-#define LAS1_HDIO_FIFO 0x0004 /* HiSpd DI FIFO (16bit) */
-#define LAS1_DAC1_FIFO 0x0008 /* D/A1 FIFO (16bit) */
-#define LAS1_DAC2_FIFO 0x000c /* D/A2 FIFO (16bit) */
-
-/*
- * PLX 9080 local config & runtime registers
- */
-#define LCFG_ITCSR 0x0068 /* Interrupt Control/Status */
-#define LCFG_DMAMODE0 0x0080 /* DMA0 Mode */
-#define LCFG_DMAPADR0 0x0084 /* DMA0 PCI Address */
-#define LCFG_DMALADR0 0x0088 /* DMA0 Local Address */
-#define LCFG_DMASIZ0 0x008c /* DMA0 Transfer Size (Bytes) */
-#define LCFG_DMADPR0 0x0090 /* DMA0 Descriptor Pointer */
-#define LCFG_DMAMODE1 0x0094 /* DMA1 Mode */
-#define LCFG_DMAPADR1 0x0098 /* DMA1 PCI Address */
-#define LCFG_DMALADR1 0x009c /* DMA1 Local Address */
-#define LCFG_DMASIZ1 0x00a0 /* DMA1 Transfer Size (Bytes) */
-#define LCFG_DMADPR1 0x00a4 /* DMA1 Descriptor Pointer */
-#define LCFG_DMACSR0 0x00a8 /* DMA0 Command/Status */
-#define LCFG_DMACSR1 0x00a9 /* DMA0 Command/Status */
-#define LCFG_DMAARB 0x00ac /* DMA Arbitration */
-#define LCFG_DMATHR 0x00b0 /* DMA Threshold */
-
-/* FIFO Status Word Bits (RtdFifoStatus) */
-#define FS_DAC1_NOT_EMPTY (1 << 0) /* DAC1 FIFO not empty */
-#define FS_DAC1_HEMPTY (1 << 1) /* DAC1 FIFO half empty */
-#define FS_DAC1_NOT_FULL (1 << 2) /* DAC1 FIFO not full */
-#define FS_DAC2_NOT_EMPTY (1 << 4) /* DAC2 FIFO not empty */
-#define FS_DAC2_HEMPTY (1 << 5) /* DAC2 FIFO half empty */
-#define FS_DAC2_NOT_FULL (1 << 6) /* DAC2 FIFO not full */
-#define FS_ADC_NOT_EMPTY (1 << 8) /* ADC FIFO not empty */
-#define FS_ADC_HEMPTY (1 << 9) /* ADC FIFO half empty */
-#define FS_ADC_NOT_FULL (1 << 10) /* ADC FIFO not full */
-#define FS_DIN_NOT_EMPTY (1 << 12) /* DIN FIFO not empty */
-#define FS_DIN_HEMPTY (1 << 13) /* DIN FIFO half empty */
-#define FS_DIN_NOT_FULL (1 << 14) /* DIN FIFO not full */
-
-/* Timer Status Word Bits (GetTimerStatus) */
-#define TS_PCLK_GATE (1 << 0) /* Pacer Clock Gate enabled */
-#define TS_BCLK_GATE (1 << 1) /* Burst Clock Gate running */
-#define TS_DCNT_GATE (1 << 2) /* Pacer Clock Delayed Start Trig. */
-#define TS_ACNT_GATE (1 << 3) /* Pacer Clock About Trig. */
-#define TS_PCLK_RUN (1 << 4) /* Pacer Clock Shutdown Flag */
-
-/* External Trigger polarity select */
-/* External Interrupt polarity select */
-#define POL_POSITIVE 0x0 /* positive edge */
-#define POL_NEGATIVE 0x1 /* negative edge */
-
-/* User Output Signal select (SetUout0Source, SetUout1Source) */
-#define UOUT_ADC 0x0 /* A/D Conversion Signal */
-#define UOUT_DAC1 0x1 /* D/A1 Update */
-#define UOUT_DAC2 0x2 /* D/A2 Update */
-#define UOUT_SOFTWARE 0x3 /* Software Programmable */
-
-/* Pacer clock select (SetPacerSource) */
-#define PCLK_INTERNAL 1 /* Internal Pacer Clock */
-#define PCLK_EXTERNAL 0 /* External Pacer Clock */
-
-/* A/D Sample Counter Sources (SetAdcntSource, SetupSampleCounter) */
-#define ADC_SCNT_CGT_RESET 0x0 /* needs restart with StartPacer */
-#define ADC_SCNT_FIFO_WRITE 0x1
-
-/* A/D Conversion Signal Select (for SetConversionSelect) */
-#define ADC_START_SOFTWARE 0x0 /* Software A/D Start */
-#define ADC_START_PCLK 0x1 /* Pacer Clock (Ext. Int. see Func.509) */
-#define ADC_START_BCLK 0x2 /* Burst Clock */
-#define ADC_START_DIGITAL_IT 0x3 /* Digital Interrupt */
-#define ADC_START_DAC1_MARKER1 0x4 /* D/A 1 Data Marker 1 */
-#define ADC_START_DAC2_MARKER1 0x5 /* D/A 2 Data Marker 1 */
-#define ADC_START_SBUS0 0x6 /* SyncBus 0 */
-#define ADC_START_SBUS1 0x7 /* SyncBus 1 */
-#define ADC_START_SBUS2 0x8 /* SyncBus 2 */
-
-/* Burst Clock start trigger select (SetBurstStart) */
-#define BCLK_START_SOFTWARE 0x0 /* Software A/D Start (StartBurst) */
-#define BCLK_START_PCLK 0x1 /* Pacer Clock */
-#define BCLK_START_ETRIG 0x2 /* External Trigger */
-#define BCLK_START_DIGITAL_IT 0x3 /* Digital Interrupt */
-#define BCLK_START_SBUS0 0x4 /* SyncBus 0 */
-#define BCLK_START_SBUS1 0x5 /* SyncBus 1 */
-#define BCLK_START_SBUS2 0x6 /* SyncBus 2 */
-
-/* Pacer Clock start trigger select (SetPacerStart) */
-#define PCLK_START_SOFTWARE 0x0 /* Software Pacer Start (StartPacer) */
-#define PCLK_START_ETRIG 0x1 /* External trigger */
-#define PCLK_START_DIGITAL_IT 0x2 /* Digital interrupt */
-#define PCLK_START_UTC2 0x3 /* User TC 2 out */
-#define PCLK_START_SBUS0 0x4 /* SyncBus 0 */
-#define PCLK_START_SBUS1 0x5 /* SyncBus 1 */
-#define PCLK_START_SBUS2 0x6 /* SyncBus 2 */
-#define PCLK_START_D_SOFTWARE 0x8 /* Delayed Software Pacer Start */
-#define PCLK_START_D_ETRIG 0x9 /* Delayed external trigger */
-#define PCLK_START_D_DIGITAL_IT 0xA /* Delayed digital interrupt */
-#define PCLK_START_D_UTC2 0xB /* Delayed User TC 2 out */
-#define PCLK_START_D_SBUS0 0xC /* Delayed SyncBus 0 */
-#define PCLK_START_D_SBUS1 0xD /* Delayed SyncBus 1 */
-#define PCLK_START_D_SBUS2 0xE /* Delayed SyncBus 2 */
-#define PCLK_START_ETRIG_GATED 0xF /* External Trigger Gated controlled mode */
-
-/* Pacer Clock Stop Trigger select (SetPacerStop) */
-#define PCLK_STOP_SOFTWARE 0x0 /* Software Pacer Stop (StopPacer) */
-#define PCLK_STOP_ETRIG 0x1 /* External Trigger */
-#define PCLK_STOP_DIGITAL_IT 0x2 /* Digital Interrupt */
-#define PCLK_STOP_ACNT 0x3 /* About Counter */
-#define PCLK_STOP_UTC2 0x4 /* User TC2 out */
-#define PCLK_STOP_SBUS0 0x5 /* SyncBus 0 */
-#define PCLK_STOP_SBUS1 0x6 /* SyncBus 1 */
-#define PCLK_STOP_SBUS2 0x7 /* SyncBus 2 */
-#define PCLK_STOP_A_SOFTWARE 0x8 /* About Software Pacer Stop */
-#define PCLK_STOP_A_ETRIG 0x9 /* About External Trigger */
-#define PCLK_STOP_A_DIGITAL_IT 0xA /* About Digital Interrupt */
-#define PCLK_STOP_A_UTC2 0xC /* About User TC2 out */
-#define PCLK_STOP_A_SBUS0 0xD /* About SyncBus 0 */
-#define PCLK_STOP_A_SBUS1 0xE /* About SyncBus 1 */
-#define PCLK_STOP_A_SBUS2 0xF /* About SyncBus 2 */
-
-/* About Counter Stop Enable */
-#define ACNT_STOP 0x0 /* stop enable */
-#define ACNT_NO_STOP 0x1 /* stop disabled */
-
-/* DAC update source (SetDAC1Start & SetDAC2Start) */
-#define DAC_START_SOFTWARE 0x0 /* Software Update */
-#define DAC_START_CGT 0x1 /* CGT controlled Update */
-#define DAC_START_DAC_CLK 0x2 /* D/A Clock */
-#define DAC_START_EPCLK 0x3 /* External Pacer Clock */
-#define DAC_START_SBUS0 0x4 /* SyncBus 0 */
-#define DAC_START_SBUS1 0x5 /* SyncBus 1 */
-#define DAC_START_SBUS2 0x6 /* SyncBus 2 */
-
-/* DAC Cycle Mode (SetDAC1Cycle, SetDAC2Cycle, SetupDAC) */
-#define DAC_CYCLE_SINGLE 0x0 /* not cycle */
-#define DAC_CYCLE_MULTI 0x1 /* cycle */
-
-/* 8254 Operation Modes (Set8254Mode, SetupTimerCounter) */
-#define M8254_EVENT_COUNTER 0 /* Event Counter */
-#define M8254_HW_ONE_SHOT 1 /* Hardware-Retriggerable One-Shot */
-#define M8254_RATE_GENERATOR 2 /* Rate Generator */
-#define M8254_SQUARE_WAVE 3 /* Square Wave Mode */
-#define M8254_SW_STROBE 4 /* Software Triggered Strobe */
-#define M8254_HW_STROBE 5 /* Hardware Triggered Strobe (Retriggerable) */
-
-/* User Timer/Counter 0 Clock Select (SetUtc0Clock) */
-#define CUTC0_8MHZ 0x0 /* 8MHz */
-#define CUTC0_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */
-#define CUTC0_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */
-#define CUTC0_EXT_PCLK 0x3 /* Ext. Pacer Clock */
-
-/* User Timer/Counter 1 Clock Select (SetUtc1Clock) */
-#define CUTC1_8MHZ 0x0 /* 8MHz */
-#define CUTC1_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */
-#define CUTC1_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */
-#define CUTC1_EXT_PCLK 0x3 /* Ext. Pacer Clock */
-#define CUTC1_UTC0_OUT 0x4 /* User Timer/Counter 0 out */
-#define CUTC1_DIN_SIGNAL 0x5 /* High-Speed Digital Input Sampling signal */
-
-/* User Timer/Counter 2 Clock Select (SetUtc2Clock) */
-#define CUTC2_8MHZ 0x0 /* 8MHz */
-#define CUTC2_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */
-#define CUTC2_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */
-#define CUTC2_EXT_PCLK 0x3 /* Ext. Pacer Clock */
-#define CUTC2_UTC1_OUT 0x4 /* User Timer/Counter 1 out */
-
-/* User Timer/Counter 0 Gate Select (SetUtc0Gate) */
-#define GUTC0_NOT_GATED 0x0 /* Not gated */
-#define GUTC0_GATED 0x1 /* Gated */
-#define GUTC0_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */
-#define GUTC0_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */
-
-/* User Timer/Counter 1 Gate Select (SetUtc1Gate) */
-#define GUTC1_NOT_GATED 0x0 /* Not gated */
-#define GUTC1_GATED 0x1 /* Gated */
-#define GUTC1_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */
-#define GUTC1_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */
-#define GUTC1_UTC0_OUT 0x4 /* User Timer/Counter 0 out */
-
-/* User Timer/Counter 2 Gate Select (SetUtc2Gate) */
-#define GUTC2_NOT_GATED 0x0 /* Not gated */
-#define GUTC2_GATED 0x1 /* Gated */
-#define GUTC2_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */
-#define GUTC2_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */
-#define GUTC2_UTC1_OUT 0x4 /* User Timer/Counter 1 out */
-
-/* Interrupt Source Masks (SetITMask, ClearITMask, GetITStatus) */
-#define IRQM_ADC_FIFO_WRITE 0x0001 /* ADC FIFO Write */
-#define IRQM_CGT_RESET 0x0002 /* Reset CGT */
-#define IRQM_CGT_PAUSE 0x0008 /* Pause CGT */
-#define IRQM_ADC_ABOUT_CNT 0x0010 /* About Counter out */
-#define IRQM_ADC_DELAY_CNT 0x0020 /* Delay Counter out */
-#define IRQM_ADC_SAMPLE_CNT 0x0040 /* ADC Sample Counter */
-#define IRQM_DAC1_UCNT 0x0080 /* DAC1 Update Counter */
-#define IRQM_DAC2_UCNT 0x0100 /* DAC2 Update Counter */
-#define IRQM_UTC1 0x0200 /* User TC1 out */
-#define IRQM_UTC1_INV 0x0400 /* User TC1 out, inverted */
-#define IRQM_UTC2 0x0800 /* User TC2 out */
-#define IRQM_DIGITAL_IT 0x1000 /* Digital Interrupt */
-#define IRQM_EXTERNAL_IT 0x2000 /* External Interrupt */
-#define IRQM_ETRIG_RISING 0x4000 /* External Trigger rising-edge */
-#define IRQM_ETRIG_FALLING 0x8000 /* External Trigger falling-edge */
-
-/* DMA Request Sources (LAS0) */
-#define DMAS_DISABLED 0x0 /* DMA Disabled */
-#define DMAS_ADC_SCNT 0x1 /* ADC Sample Counter */
-#define DMAS_DAC1_UCNT 0x2 /* D/A1 Update Counter */
-#define DMAS_DAC2_UCNT 0x3 /* D/A2 Update Counter */
-#define DMAS_UTC1 0x4 /* User TC1 out */
-#define DMAS_ADFIFO_HALF_FULL 0x8 /* A/D FIFO half full */
-#define DMAS_DAC1_FIFO_HALF_EMPTY 0x9 /* D/A1 FIFO half empty */
-#define DMAS_DAC2_FIFO_HALF_EMPTY 0xA /* D/A2 FIFO half empty */
-
-/* DMA Local Addresses (0x40000000+LAS1 offset) */
-#define DMALADDR_ADC 0x40000000 /* A/D FIFO */
-#define DMALADDR_HDIN 0x40000004 /* High Speed Digital Input FIFO */
-#define DMALADDR_DAC1 0x40000008 /* D/A1 FIFO */
-#define DMALADDR_DAC2 0x4000000C /* D/A2 FIFO */
-
-/* Port 0 compare modes (SetDIO0CompareMode) */
-#define DIO_MODE_EVENT 0 /* Event Mode */
-#define DIO_MODE_MATCH 1 /* Match Mode */
-
-/* Digital Table Enable (Port 1 disable) */
-#define DTBL_DISABLE 0 /* Enable Digital Table */
-#define DTBL_ENABLE 1 /* Disable Digital Table */
-
-/* Sampling Signal for High Speed Digital Input (SetHdinStart) */
-#define HDIN_SOFTWARE 0x0 /* Software Trigger */
-#define HDIN_ADC 0x1 /* A/D Conversion Signal */
-#define HDIN_UTC0 0x2 /* User TC out 0 */
-#define HDIN_UTC1 0x3 /* User TC out 1 */
-#define HDIN_UTC2 0x4 /* User TC out 2 */
-#define HDIN_EPCLK 0x5 /* External Pacer Clock */
-#define HDIN_ETRG 0x6 /* External Trigger */
-
-/* Channel Gain Table / Channel Gain Latch */
-#define CSC_LATCH 0 /* Channel Gain Latch mode */
-#define CSC_CGT 1 /* Channel Gain Table mode */
-
-/* Channel Gain Table Pause Enable */
-#define CGT_PAUSE_DISABLE 0 /* Channel Gain Table Pause Disable */
-#define CGT_PAUSE_ENABLE 1 /* Channel Gain Table Pause Enable */
-
-/* DAC output type/range (p63) */
-#define AOUT_UNIP5 0 /* 0..+5 Volt */
-#define AOUT_UNIP10 1 /* 0..+10 Volt */
-#define AOUT_BIP5 2 /* -5..+5 Volt */
-#define AOUT_BIP10 3 /* -10..+10 Volt */
-
-/* Ghannel Gain Table field definitions (p61) */
-/* Gain */
-#define GAIN1 0
-#define GAIN2 1
-#define GAIN4 2
-#define GAIN8 3
-#define GAIN16 4
-#define GAIN32 5
-#define GAIN64 6
-#define GAIN128 7
-
-/* Input range/polarity */
-#define AIN_BIP5 0 /* -5..+5 Volt */
-#define AIN_BIP10 1 /* -10..+10 Volt */
-#define AIN_UNIP10 2 /* 0..+10 Volt */
-
-/* non referenced single ended select bit */
-#define NRSE_AGND 0 /* AGND referenced SE input */
-#define NRSE_AINS 1 /* AIN SENSE referenced SE input */
-
-/* single ended vs differential */
-#define GND_SE 0 /* Single-Ended */
-#define GND_DIFF 1 /* Differential */
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 7e577e444909..f4163fd35a00 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -1,186 +1,184 @@
/*
- comedi/drivers/rti800.c
- Hardware driver for Analog Devices RTI-800/815 board
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
+ * comedi/drivers/rti800.c
+ * Hardware driver for Analog Devices RTI-800/815 board
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
/*
-Driver: rti800
-Description: Analog Devices RTI-800/815
-Author: ds
-Status: unknown
-Updated: Fri, 05 Sep 2008 14:50:44 +0100
-Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
-
-Configuration options:
- [0] - I/O port base address
- [1] - IRQ
- [2] - A/D reference
- 0 = differential
- 1 = pseudodifferential (common)
- 2 = single-ended
- [3] - A/D range
- 0 = [-10,10]
- 1 = [-5,5]
- 2 = [0,10]
- [4] - A/D encoding
- 0 = two's complement
- 1 = straight binary
- [5] - DAC 0 range
- 0 = [-10,10]
- 1 = [0,10]
- [6] - DAC 0 encoding
- 0 = two's complement
- 1 = straight binary
- [7] - DAC 1 range (same as DAC 0)
- [8] - DAC 1 encoding (same as DAC 0)
-*/
+ * Driver: rti800
+ * Description: Analog Devices RTI-800/815
+ * Devices: (Analog Devices) RTI-800 [rti800]
+ * (Analog Devices) RTI-815 [rti815]
+ * Author: David A. Schleef <ds@schleef.org>
+ * Status: unknown
+ * Updated: Fri, 05 Sep 2008 14:50:44 +0100
+ *
+ * Configuration options:
+ * [0] - I/O port base address
+ * [1] - IRQ (not supported / unused)
+ * [2] - A/D mux/reference (number of channels)
+ * 0 = differential
+ * 1 = pseudodifferential (common)
+ * 2 = single-ended
+ * [3] - A/D range
+ * 0 = [-10,10]
+ * 1 = [-5,5]
+ * 2 = [0,10]
+ * [4] - A/D encoding
+ * 0 = two's complement
+ * 1 = straight binary
+ * [5] - DAC 0 range
+ * 0 = [-10,10]
+ * 1 = [0,10]
+ * [6] - DAC 0 encoding
+ * 0 = two's complement
+ * 1 = straight binary
+ * [7] - DAC 1 range (same as DAC 0)
+ * [8] - DAC 1 encoding (same as DAC 0)
+ */
#include <linux/interrupt.h>
#include "../comedidev.h"
#include <linux/ioport.h>
-#define RTI800_SIZE 16
-
-#define RTI800_CSR 0
-#define RTI800_MUXGAIN 1
-#define RTI800_CONVERT 2
-#define RTI800_ADCLO 3
-#define RTI800_ADCHI 4
-#define RTI800_DAC0LO 5
-#define RTI800_DAC0HI 6
-#define RTI800_DAC1LO 7
-#define RTI800_DAC1HI 8
-#define RTI800_CLRFLAGS 9
-#define RTI800_DI 10
-#define RTI800_DO 11
-#define RTI800_9513A_DATA 12
-#define RTI800_9513A_CNTRL 13
-#define RTI800_9513A_STATUS 13
-
/*
- * flags for CSR register
+ * Register map
*/
+#define RTI800_CSR 0x00
+#define RTI800_CSR_BUSY (1 << 7)
+#define RTI800_CSR_DONE (1 << 6)
+#define RTI800_CSR_OVERRUN (1 << 5)
+#define RTI800_CSR_TCR (1 << 4)
+#define RTI800_CSR_DMA_ENAB (1 << 3)
+#define RTI800_CSR_INTR_TC (1 << 2)
+#define RTI800_CSR_INTR_EC (1 << 1)
+#define RTI800_CSR_INTR_OVRN (1 << 0)
+#define RTI800_MUXGAIN 0x01
+#define RTI800_CONVERT 0x02
+#define RTI800_ADCLO 0x03
+#define RTI800_ADCHI 0x04
+#define RTI800_DAC0LO 0x05
+#define RTI800_DAC0HI 0x06
+#define RTI800_DAC1LO 0x07
+#define RTI800_DAC1HI 0x08
+#define RTI800_CLRFLAGS 0x09
+#define RTI800_DI 0x0a
+#define RTI800_DO 0x0b
+#define RTI800_9513A_DATA 0x0c
+#define RTI800_9513A_CNTRL 0x0d
+#define RTI800_9513A_STATUS 0x0d
+
+#define RTI800_IOSIZE 0x10
+
+#define RTI800_AI_TIMEOUT 100
+
+static const struct comedi_lrange range_rti800_ai_10_bipolar = {
+ 4, {
+ BIP_RANGE(10),
+ BIP_RANGE(1),
+ BIP_RANGE(0.1),
+ BIP_RANGE(0.02)
+ }
+};
-#define RTI800_BUSY 0x80
-#define RTI800_DONE 0x40
-#define RTI800_OVERRUN 0x20
-#define RTI800_TCR 0x10
-#define RTI800_DMA_ENAB 0x08
-#define RTI800_INTR_TC 0x04
-#define RTI800_INTR_EC 0x02
-#define RTI800_INTR_OVRN 0x01
-
-#define Am9513_8BITBUS
-
-#define Am9513_output_control(a) outb(a, dev->iobase+RTI800_9513A_CNTRL)
-#define Am9513_output_data(a) outb(a, dev->iobase+RTI800_9513A_DATA)
-#define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA)
-#define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS)
-
-#include "am9513.h"
-
-static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, {
- BIP_RANGE
- (10),
- BIP_RANGE
- (1),
- BIP_RANGE
- (0.1),
- BIP_RANGE
- (0.02)
- }
+static const struct comedi_lrange range_rti800_ai_5_bipolar = {
+ 4, {
+ BIP_RANGE(5),
+ BIP_RANGE(0.5),
+ BIP_RANGE(0.05),
+ BIP_RANGE(0.01)
+ }
};
-static const struct comedi_lrange range_rti800_ai_5_bipolar = { 4, {
- BIP_RANGE
- (5),
- BIP_RANGE
- (0.5),
- BIP_RANGE
- (0.05),
- BIP_RANGE
- (0.01)
- }
+static const struct comedi_lrange range_rti800_ai_unipolar = {
+ 4, {
+ UNI_RANGE(10),
+ UNI_RANGE(1),
+ UNI_RANGE(0.1),
+ UNI_RANGE(0.02)
+ }
};
-static const struct comedi_lrange range_rti800_ai_unipolar = { 4, {
- UNI_RANGE
- (10),
- UNI_RANGE(1),
- UNI_RANGE
- (0.1),
- UNI_RANGE
- (0.02)
- }
+static const struct comedi_lrange *const rti800_ai_ranges[] = {
+ &range_rti800_ai_10_bipolar,
+ &range_rti800_ai_5_bipolar,
+ &range_rti800_ai_unipolar,
};
-struct rti800_board {
+static const struct comedi_lrange *const rti800_ao_ranges[] = {
+ &range_bipolar10,
+ &range_unipolar10,
+};
+struct rti800_board {
const char *name;
int has_ao;
};
-static irqreturn_t rti800_interrupt(int irq, void *dev);
+static const struct rti800_board rti800_boardtypes[] = {
+ {
+ .name = "rti800",
+ }, {
+ .name = "rti815",
+ .has_ao = 1,
+ },
+};
struct rti800_private {
- enum {
- adc_diff, adc_pseudodiff, adc_singleended
- } adc_mux;
- enum {
- adc_bipolar10, adc_bipolar5, adc_unipolar10
- } adc_range;
- enum {
- adc_2comp, adc_straight
- } adc_coding;
- enum {
- dac_bipolar10, dac_unipolar10
- } dac0_range, dac1_range;
- enum {
- dac_2comp, dac_straight
- } dac0_coding, dac1_coding;
+ bool adc_2comp;
+ bool dac_2comp[2];
const struct comedi_lrange *ao_range_type_list[2];
unsigned int ao_readback[2];
- int muxgain_bits;
+ unsigned char muxgain_bits;
};
-#define RTI800_TIMEOUT 100
-
-static irqreturn_t rti800_interrupt(int irq, void *dev)
+static int rti800_ai_wait_for_conversion(struct comedi_device *dev,
+ int timeout)
{
- return IRQ_HANDLED;
-}
+ unsigned char status;
+ int i;
-/* settling delay times in usec for different gains */
-static const int gaindelay[] = { 10, 20, 40, 80 };
+ for (i = 0; i < timeout; i++) {
+ status = inb(dev->iobase + RTI800_CSR);
+ if (status & RTI800_CSR_OVERRUN) {
+ outb(0, dev->iobase + RTI800_CLRFLAGS);
+ return -EIO;
+ }
+ if (status & RTI800_CSR_DONE)
+ return 0;
+ udelay(1);
+ }
+ return -ETIME;
+}
static int rti800_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti800_private *devpriv = dev->private;
- int i, t;
- int status;
- int chan = CR_CHAN(insn->chanspec);
- unsigned gain = CR_RANGE(insn->chanspec);
- unsigned muxgain_bits;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int gain = CR_RANGE(insn->chanspec);
+ unsigned char muxgain_bits;
+ int ret;
+ int i;
inb(dev->iobase + RTI800_ADCHI);
outb(0, dev->iobase + RTI800_CLRFLAGS);
@@ -189,80 +187,80 @@ static int rti800_ai_insn_read(struct comedi_device *dev,
if (muxgain_bits != devpriv->muxgain_bits) {
devpriv->muxgain_bits = muxgain_bits;
outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
- /* without a delay here, the RTI_OVERRUN bit
- * gets set, and you will have an error. */
+ /*
+ * Without a delay here, the RTI_CSR_OVERRUN bit
+ * gets set, and you will have an error.
+ */
if (insn->n > 0) {
- BUG_ON(gain >= ARRAY_SIZE(gaindelay));
- udelay(gaindelay[gain]);
+ int delay = (gain == 0) ? 10 :
+ (gain == 1) ? 20 :
+ (gain == 2) ? 40 : 80;
+
+ udelay(delay);
}
}
for (i = 0; i < insn->n; i++) {
outb(0, dev->iobase + RTI800_CONVERT);
- for (t = RTI800_TIMEOUT; t; t--) {
- status = inb(dev->iobase + RTI800_CSR);
- if (status & RTI800_OVERRUN) {
- printk(KERN_WARNING "rti800: a/d overrun\n");
- outb(0, dev->iobase + RTI800_CLRFLAGS);
- return -EIO;
- }
- if (status & RTI800_DONE)
- break;
- udelay(1);
- }
- if (t == 0) {
- printk(KERN_WARNING "rti800: timeout\n");
- return -ETIME;
- }
+ ret = rti800_ai_wait_for_conversion(dev, RTI800_AI_TIMEOUT);
+ if (ret)
+ return ret;
+
data[i] = inb(dev->iobase + RTI800_ADCLO);
- data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
+ data[i] |= (inb(dev->iobase + RTI800_ADCHI) & 0xf) << 8;
- if (devpriv->adc_coding == adc_2comp)
+ if (devpriv->adc_2comp)
data[i] ^= 0x800;
}
- return i;
+ return insn->n;
}
static int rti800_ao_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti800_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int i;
- int chan = CR_CHAN(insn->chanspec);
for (i = 0; i < insn->n; i++)
data[i] = devpriv->ao_readback[chan];
- return i;
+ return insn->n;
}
static int rti800_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct rti800_private *devpriv = dev->private;
- int chan = CR_CHAN(insn->chanspec);
- int d;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ int reg_lo = chan ? RTI800_DAC1LO : RTI800_DAC0LO;
+ int reg_hi = chan ? RTI800_DAC1HI : RTI800_DAC0HI;
+ int val = devpriv->ao_readback[chan];
int i;
for (i = 0; i < insn->n; i++) {
- devpriv->ao_readback[chan] = d = data[i];
- if (devpriv->dac0_coding == dac_2comp)
- d ^= 0x800;
-
- outb(d & 0xff,
- dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
- outb(d >> 8,
- dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
+ val = data[i];
+ if (devpriv->dac_2comp[chan])
+ val ^= 0x800;
+
+ outb(val & 0xff, dev->iobase + reg_lo);
+ outb((val >> 8) & 0xff, dev->iobase + reg_hi);
}
- return i;
+
+ devpriv->ao_readback[chan] = val;
+
+ return insn->n;
}
static int rti800_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
data[1] = inb(dev->iobase + RTI800_DI);
return insn->n;
@@ -270,11 +268,16 @@ static int rti800_di_insn_bits(struct comedi_device *dev,
static int rti800_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
+ unsigned int mask = data[0];
+ unsigned int bits = data[1];
+
+ if (mask) {
+ s->state &= ~mask;
+ s->state |= (bits & mask);
+
/* Outputs are inverted... */
outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
}
@@ -284,186 +287,106 @@ static int rti800_do_insn_bits(struct comedi_device *dev,
return insn->n;
}
-/*
- options[0] - I/O port
- options[1] - irq
- options[2] - a/d mux
- 0=differential, 1=pseudodiff, 2=single
- options[3] - a/d range
- 0=bipolar10, 1=bipolar5, 2=unipolar10
- options[4] - a/d coding
- 0=2's comp, 1=straight binary
- options[5] - dac0 range
- 0=bipolar10, 1=unipolar10
- options[6] - dac0 coding
- 0=2's comp, 1=straight binary
- options[7] - dac1 range
- options[8] - dac1 coding
- */
-
static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct rti800_board *board = comedi_board(dev);
struct rti800_private *devpriv;
- unsigned int irq;
- unsigned long iobase;
- int ret;
struct comedi_subdevice *s;
+ int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: rti800: 0x%04lx\n", dev->minor, iobase);
- if (!request_region(iobase, RTI800_SIZE, "rti800")) {
- printk(KERN_WARNING "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "fingerprint=%x,%x,%x,%x,%x ",
- inb(dev->iobase + 0),
- inb(dev->iobase + 1),
- inb(dev->iobase + 2),
- inb(dev->iobase + 3), inb(dev->iobase + 4));
-#endif
+ ret = comedi_request_region(dev, it->options[0], RTI800_IOSIZE);
+ if (ret)
+ return ret;
outb(0, dev->iobase + RTI800_CSR);
inb(dev->iobase + RTI800_ADCHI);
outb(0, dev->iobase + RTI800_CLRFLAGS);
- irq = it->options[1];
- if (irq) {
- printk(KERN_INFO "( irq = %u )\n", irq);
- ret = request_irq(irq, rti800_interrupt, 0, "rti800", dev);
- if (ret < 0) {
- printk(KERN_WARNING " Failed to allocate IRQ\n");
- return ret;
- }
- dev->irq = irq;
- } else {
- printk(KERN_INFO "( no irq )\n");
- }
-
- dev->board_name = board->name;
-
- ret = comedi_alloc_subdevices(dev, 4);
- if (ret)
- return ret;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- devpriv->adc_mux = it->options[2];
- devpriv->adc_range = it->options[3];
- devpriv->adc_coding = it->options[4];
- devpriv->dac0_range = it->options[5];
- devpriv->dac0_coding = it->options[6];
- devpriv->dac1_range = it->options[7];
- devpriv->dac1_coding = it->options[8];
- devpriv->muxgain_bits = -1;
+ devpriv->adc_2comp = (it->options[4] == 0);
+ devpriv->dac_2comp[0] = (it->options[6] == 0);
+ devpriv->dac_2comp[1] = (it->options[8] == 0);
+ /* invalid, forces the MUXGAIN register to be set when first used */
+ devpriv->muxgain_bits = 0xff;
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
s = &dev->subdevices[0];
/* ai subdevice */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- s->n_chan = (devpriv->adc_mux ? 16 : 8);
- s->insn_read = rti800_ai_insn_read;
- s->maxdata = 0xfff;
- switch (devpriv->adc_range) {
- case adc_bipolar10:
- s->range_table = &range_rti800_ai_10_bipolar;
- break;
- case adc_bipolar5:
- s->range_table = &range_rti800_ai_5_bipolar;
- break;
- case adc_unipolar10:
- s->range_table = &range_rti800_ai_unipolar;
- break;
- }
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = (it->options[2] ? 16 : 8);
+ s->insn_read = rti800_ai_insn_read;
+ s->maxdata = 0x0fff;
+ s->range_table = (it->options[3] < ARRAY_SIZE(rti800_ai_ranges))
+ ? rti800_ai_ranges[it->options[3]]
+ : &range_unknown;
s = &dev->subdevices[1];
if (board->has_ao) {
/* ao subdevice (only on rti815) */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 2;
- s->insn_read = rti800_ao_insn_read;
- s->insn_write = rti800_ao_insn_write;
- s->maxdata = 0xfff;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->insn_read = rti800_ao_insn_read;
+ s->insn_write = rti800_ao_insn_write;
+ s->maxdata = 0x0fff;
s->range_table_list = devpriv->ao_range_type_list;
- switch (devpriv->dac0_range) {
- case dac_bipolar10:
- devpriv->ao_range_type_list[0] = &range_bipolar10;
- break;
- case dac_unipolar10:
- devpriv->ao_range_type_list[0] = &range_unipolar10;
- break;
- }
- switch (devpriv->dac1_range) {
- case dac_bipolar10:
- devpriv->ao_range_type_list[1] = &range_bipolar10;
- break;
- case dac_unipolar10:
- devpriv->ao_range_type_list[1] = &range_unipolar10;
- break;
- }
+ devpriv->ao_range_type_list[0] =
+ (it->options[5] < ARRAY_SIZE(rti800_ao_ranges))
+ ? rti800_ao_ranges[it->options[5]]
+ : &range_unknown;
+ devpriv->ao_range_type_list[1] =
+ (it->options[7] < ARRAY_SIZE(rti800_ao_ranges))
+ ? rti800_ao_ranges[it->options[7]]
+ : &range_unknown;
} else {
- s->type = COMEDI_SUBD_UNUSED;
+ s->type = COMEDI_SUBD_UNUSED;
}
s = &dev->subdevices[2];
/* di */
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 8;
- s->insn_bits = rti800_di_insn_bits;
- s->maxdata = 1;
- s->range_table = &range_digital;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 8;
+ s->insn_bits = rti800_di_insn_bits;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
s = &dev->subdevices[3];
/* do */
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 8;
- s->insn_bits = rti800_do_insn_bits;
- s->maxdata = 1;
- s->range_table = &range_digital;
-
-/* don't yet know how to deal with counter/timers */
-#if 0
- s = &dev->subdevices[4];
- /* do */
- s->type = COMEDI_SUBD_TIMER;
-#endif
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 8;
+ s->insn_bits = rti800_do_insn_bits;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+
+ /*
+ * There is also an Am9513 timer on these boards. This subdevice
+ * is not currently supported.
+ */
return 0;
}
-static void rti800_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, RTI800_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-}
-
-static const struct rti800_board boardtypes[] = {
- { "rti800", 0 },
- { "rti815", 1 },
-};
-
static struct comedi_driver rti800_driver = {
.driver_name = "rti800",
.module = THIS_MODULE,
.attach = rti800_attach,
- .detach = rti800_detach,
- .num_names = ARRAY_SIZE(boardtypes),
- .board_name = &boardtypes[0].name,
+ .detach = comedi_legacy_detach,
+ .num_names = ARRAY_SIZE(rti800_boardtypes),
+ .board_name = &rti800_boardtypes[0].name,
.offset = sizeof(struct rti800_board),
};
module_comedi_driver(rti800_driver);
+MODULE_DESCRIPTION("Comedi: RTI-800 Multifunction Analog/Digital board");
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 2185ca1bcf02..46dbbe6cdd76 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -92,18 +92,11 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct rti802_private *devpriv;
struct comedi_subdevice *s;
int i;
- unsigned long iobase;
int ret;
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: rti802: 0x%04lx ", dev->minor, iobase);
- if (!request_region(iobase, RTI802_SIZE, "rti802")) {
- printk(KERN_WARNING "I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- dev->board_name = "rti802";
+ ret = comedi_request_region(dev, it->options[0], RTI802_SIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -135,17 +128,11 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void rti802_detach(struct comedi_device *dev)
-{
- if (dev->iobase)
- release_region(dev->iobase, RTI802_SIZE);
-}
-
static struct comedi_driver rti802_driver = {
.driver_name = "rti802",
.module = THIS_MODULE,
.attach = rti802_attach,
- .detach = rti802_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(rti802_driver);
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 39232b359453..d240ce87bd68 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -552,17 +552,11 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct s526_private *devpriv;
struct comedi_subdevice *s;
- int iobase;
int ret;
- dev->board_name = dev->driver->driver_name;
-
- iobase = it->options[0];
- if (!iobase || !request_region(iobase, S526_IOSIZE, dev->board_name)) {
- comedi_error(dev, "I/O port conflict");
- return -EIO;
- }
- dev->iobase = iobase;
+ ret = comedi_request_region(dev, it->options[0], S526_IOSIZE);
+ if (ret)
+ return ret;
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
@@ -616,22 +610,14 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->insn_bits = s526_dio_insn_bits;
s->insn_config = s526_dio_insn_config;
- dev_info(dev->class_dev, "%s attached\n", dev->board_name);
-
return 1;
}
-static void s526_detach(struct comedi_device *dev)
-{
- if (dev->iobase > 0)
- release_region(dev->iobase, S526_IOSIZE);
-}
-
static struct comedi_driver s526_driver = {
.driver_name = "s526",
.module = THIS_MODULE,
.attach = s526_attach,
- .detach = s526_detach,
+ .detach = comedi_legacy_detach,
};
module_comedi_driver(s526_driver);
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 81a1fe661579..0cf4b3d1279a 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -80,7 +80,7 @@ INSN_CONFIG instructions:
#define PCI_SUBDEVICE_ID_S626 0x0272
struct s626_private {
- void __iomem *base_addr;
+ void __iomem *mmio;
uint8_t ai_cmd_running; /* ai_cmd is running */
uint8_t ai_continous; /* continous acquisition */
int ai_sample_count; /* number of samples to acquire */
@@ -106,64 +106,6 @@ struct s626_private {
unsigned int ao_readback[S626_DAC_CHANNELS];
};
-struct dio_private {
- uint16_t RDDIn;
- uint16_t WRDOut;
- uint16_t RDEdgSel;
- uint16_t WREdgSel;
- uint16_t RDCapSel;
- uint16_t WRCapSel;
- uint16_t RDCapFlg;
- uint16_t RDIntSel;
- uint16_t WRIntSel;
-};
-
-static struct dio_private dio_private_A = {
- .RDDIn = LP_RDDINA,
- .WRDOut = LP_WRDOUTA,
- .RDEdgSel = LP_RDEDGSELA,
- .WREdgSel = LP_WREDGSELA,
- .RDCapSel = LP_RDCAPSELA,
- .WRCapSel = LP_WRCAPSELA,
- .RDCapFlg = LP_RDCAPFLGA,
- .RDIntSel = LP_RDINTSELA,
- .WRIntSel = LP_WRINTSELA,
-};
-
-static struct dio_private dio_private_B = {
- .RDDIn = LP_RDDINB,
- .WRDOut = LP_WRDOUTB,
- .RDEdgSel = LP_RDEDGSELB,
- .WREdgSel = LP_WREDGSELB,
- .RDCapSel = LP_RDCAPSELB,
- .WRCapSel = LP_WRCAPSELB,
- .RDCapFlg = LP_RDCAPFLGB,
- .RDIntSel = LP_RDINTSELB,
- .WRIntSel = LP_WRINTSELB,
-};
-
-static struct dio_private dio_private_C = {
- .RDDIn = LP_RDDINC,
- .WRDOut = LP_WRDOUTC,
- .RDEdgSel = LP_RDEDGSELC,
- .WREdgSel = LP_WREDGSELC,
- .RDCapSel = LP_RDCAPSELC,
- .WRCapSel = LP_WRCAPSELC,
- .RDCapFlg = LP_RDCAPFLGC,
- .RDIntSel = LP_RDINTSELC,
- .WRIntSel = LP_WRINTSELC,
-};
-
-/* to group dio devices (48 bits mask and data are not allowed ???)
-static struct dio_private *dio_private_word[]={
- &dio_private_A,
- &dio_private_B,
- &dio_private_C,
-};
-*/
-
-#define diopriv ((struct dio_private *)s->private)
-
/* COUNTER OBJECT ------------------------------------------------ */
struct enc_private {
/* Pointers to functions that differ for A and B counters: */
@@ -195,37 +137,53 @@ struct enc_private {
/* Translation table to map IntSrc into equivalent RDMISC2 event flag bits. */
/* static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; */
-/* enab/disable a function or test status bit(s) that are accessed */
-/* through Main Control Registers 1 or 2. */
-#define MC_ENABLE(REGADRS, CTRLWORD) writel(((uint32_t)(CTRLWORD) << 16) | (uint32_t)(CTRLWORD), devpriv->base_addr+(REGADRS))
+/*
+ * Enable/disable a function or test status bit(s) that are accessed
+ * through Main Control Registers 1 or 2.
+ */
+static void s626_mc_enable(struct comedi_device *dev,
+ unsigned int cmd, unsigned int reg)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int val = (cmd << 16) | cmd;
-#define MC_DISABLE(REGADRS, CTRLWORD) writel((uint32_t)(CTRLWORD) << 16 , devpriv->base_addr+(REGADRS))
+ writel(val, devpriv->mmio + reg);
+}
-#define MC_TEST(REGADRS, CTRLWORD) ((readl(devpriv->base_addr+(REGADRS)) & CTRLWORD) != 0)
+static void s626_mc_disable(struct comedi_device *dev,
+ unsigned int cmd, unsigned int reg)
+{
+ struct s626_private *devpriv = dev->private;
-/* #define WR7146(REGARDS,CTRLWORD)
- writel(CTRLWORD,(uint32_t)(devpriv->base_addr+(REGARDS))) */
-#define WR7146(REGARDS, CTRLWORD) writel(CTRLWORD, devpriv->base_addr+(REGARDS))
+ writel(cmd << 16 , devpriv->mmio + reg);
+}
-/* #define RR7146(REGARDS)
- readl((uint32_t)(devpriv->base_addr+(REGARDS))) */
-#define RR7146(REGARDS) readl(devpriv->base_addr+(REGARDS))
+static bool s626_mc_test(struct comedi_device *dev,
+ unsigned int cmd, unsigned int reg)
+{
+ struct s626_private *devpriv = dev->private;
+ unsigned int val;
+
+ val = readl(devpriv->mmio + reg);
+
+ return (val & cmd) ? true : false;
+}
#define BUGFIX_STREG(REGADRS) (REGADRS - 4)
/* Write a time slot control record to TSL2. */
#define VECTPORT(VECTNUM) (P_TSL2 + ((VECTNUM) << 2))
-#define SETVECT(VECTNUM, VECTVAL) WR7146(VECTPORT(VECTNUM), (VECTVAL))
/* Code macros used for constructing I2C command bytes. */
#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24))
#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16))
#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8))
-static const struct comedi_lrange s626_range_table = { 2, {
- RANGE(-5, 5),
- RANGE(-10, 10),
- }
+static const struct comedi_lrange s626_range_table = {
+ 2, {
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ }
};
/* Execute a DEBI transfer. This must be called from within a */
@@ -234,16 +192,18 @@ static void DEBItransfer(struct comedi_device *dev)
{
struct s626_private *devpriv = dev->private;
- /* Initiate upload of shadow RAM to DEBI control register. */
- MC_ENABLE(P_MC2, MC2_UPLD_DEBI);
+ /* Initiate upload of shadow RAM to DEBI control register */
+ s626_mc_enable(dev, MC2_UPLD_DEBI, P_MC2);
- /* Wait for completion of upload from shadow RAM to DEBI control */
- /* register. */
- while (!MC_TEST(P_MC2, MC2_UPLD_DEBI))
+ /*
+ * Wait for completion of upload from shadow RAM to
+ * DEBI control register.
+ */
+ while (!s626_mc_test(dev, MC2_UPLD_DEBI, P_MC2))
;
- /* Wait until DEBI transfer is done. */
- while (RR7146(P_PSR) & PSR_DEBI_S)
+ /* Wait until DEBI transfer is done */
+ while (readl(devpriv->mmio + P_PSR) & PSR_DEBI_S)
;
}
@@ -252,19 +212,14 @@ static void DEBItransfer(struct comedi_device *dev)
static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr)
{
struct s626_private *devpriv = dev->private;
- uint16_t retval;
- /* Set up DEBI control register value in shadow RAM. */
- WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
+ /* Set up DEBI control register value in shadow RAM */
+ writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD);
/* Execute the DEBI transfer. */
DEBItransfer(dev);
- /* Fetch target register value. */
- retval = (uint16_t) RR7146(P_DEBIAD);
-
- /* Return register value. */
- return retval;
+ return readl(devpriv->mmio + P_DEBIAD);
}
/* Write a value to a gate array register. */
@@ -272,9 +227,9 @@ static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata)
{
struct s626_private *devpriv = dev->private;
- /* Set up DEBI control register value in shadow RAM. */
- WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
- WR7146(P_DEBIAD, wdata);
+ /* Set up DEBI control register value in shadow RAM */
+ writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD);
+ writel(wdata, devpriv->mmio + P_DEBIAD);
/* Execute the DEBI transfer. */
DEBItransfer(dev);
@@ -284,23 +239,22 @@ static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata)
* specifies bits that are to be preserved, wdata is new value to be
* or'd with the masked original.
*/
-static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask,
- uint16_t wdata)
+static void DEBIreplace(struct comedi_device *dev, unsigned int addr,
+ unsigned int mask, unsigned int wdata)
{
struct s626_private *devpriv = dev->private;
+ unsigned int val;
- /* Copy target gate array register into P_DEBIAD register. */
- WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr);
- /* Set up DEBI control reg value in shadow RAM. */
- DEBItransfer(dev); /* Execute the DEBI Read transfer. */
-
- /* Write back the modified image. */
- WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr);
- /* Set up DEBI control reg value in shadow RAM. */
+ addr &= 0xffff;
+ writel(DEBI_CMD_RDWORD | addr, devpriv->mmio + P_DEBICMD);
+ DEBItransfer(dev);
- WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask));
- /* Modify the register image. */
- DEBItransfer(dev); /* Execute the DEBI Write transfer. */
+ writel(DEBI_CMD_WRWORD | addr, devpriv->mmio + P_DEBICMD);
+ val = readl(devpriv->mmio + P_DEBIAD);
+ val &= mask;
+ val |= wdata;
+ writel(val & 0xffff, devpriv->mmio + P_DEBIAD);
+ DEBItransfer(dev);
}
/* ************** EEPROM ACCESS FUNCTIONS ************** */
@@ -308,31 +262,32 @@ static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask,
static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val)
{
struct s626_private *devpriv = dev->private;
+ unsigned int ctrl;
- /* Write I2C command to I2C Transfer Control shadow register. */
- WR7146(P_I2CCTRL, val);
-
- /* Upload I2C shadow registers into working registers and wait for */
- /* upload confirmation. */
-
- MC_ENABLE(P_MC2, MC2_UPLD_IIC);
- while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
- ;
+ /* Write I2C command to I2C Transfer Control shadow register */
+ writel(val, devpriv->mmio + P_I2CCTRL);
- /* Wait until I2C bus transfer is finished or an error occurs. */
- while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY)
+ /*
+ * Upload I2C shadow registers into working registers and
+ * wait for upload confirmation.
+ */
+ s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2);
+ while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2))
;
- /* Return non-zero if I2C error occurred. */
- return RR7146(P_I2CCTRL) & I2C_ERR;
+ /* Wait until I2C bus transfer is finished or an error occurs */
+ do {
+ ctrl = readl(devpriv->mmio + P_I2CCTRL);
+ } while ((ctrl & (I2C_BUSY | I2C_ERR)) == I2C_BUSY);
+ /* Return non-zero if I2C error occurred */
+ return ctrl & I2C_ERR;
}
/* Read uint8_t from EEPROM. */
static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr)
{
struct s626_private *devpriv = dev->private;
- uint8_t rtnval;
/* Send EEPROM target address. */
if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW)
@@ -360,9 +315,8 @@ static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr)
/* Abort function and declare error if handshake failed. */
return 0;
}
- /* Return copy of EEPROM value. */
- rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16);
- return rtnval;
+
+ return (readl(devpriv->mmio + P_I2CCTRL) >> 16) & 0xff;
}
/* *********** DAC FUNCTIONS *********** */
@@ -402,23 +356,25 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
/* Copy DAC setpoint value to DAC's output DMA buffer. */
- /* WR7146( (uint32_t)devpriv->pDacWBuf, val ); */
+ /* writel(val, devpriv->mmio + (uint32_t)devpriv->pDacWBuf); */
*devpriv->pDacWBuf = val;
- /* enab the output DMA transfer. This will cause the DMAC to copy
- * the DAC's data value to A2's output FIFO. The DMA transfer will
+ /*
+ * Enable the output DMA transfer. This will cause the DMAC to copy
+ * the DAC's data value to A2's output FIFO. The DMA transfer will
* then immediately terminate because the protection address is
* reached upon transfer of the first DWORD value.
*/
- MC_ENABLE(P_MC1, MC1_A2OUT);
+ s626_mc_enable(dev, MC1_A2OUT, P_MC1);
/* While the DMA transfer is executing ... */
- /* Reset Audio2 output FIFO's underflow flag (along with any other
- * FIFO underflow/overflow flags). When set, this flag will
- * indicate that we have emerged from slot 0.
+ /*
+ * Reset Audio2 output FIFO's underflow flag (along with any
+ * other FIFO underflow/overflow flags). When set, this flag
+ * will indicate that we have emerged from slot 0.
*/
- WR7146(P_ISR, ISR_AFOU);
+ writel(ISR_AFOU, devpriv->mmio + P_ISR);
/* Wait for the DMA transfer to finish so that there will be data
* available in the FIFO when time slot 1 tries to transfer a DWORD
@@ -426,7 +382,7 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* Done by polling the DMAC enable flag; this flag is automatically
* cleared when the transfer has finished.
*/
- while ((RR7146(P_MC1) & MC1_A2OUT) != 0)
+ while (readl(devpriv->mmio + P_MC1) & MC1_A2OUT)
;
/* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */
@@ -436,7 +392,7 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* will be shifted in and stored in FB_BUFFER2 for end-of-slot-list
* detection.
*/
- SETVECT(0, XSD2 | RSD3 | SIB_A2);
+ writel(XSD2 | RSD3 | SIB_A2, devpriv->mmio + VECTPORT(0));
/* Wait for slot 1 to execute to ensure that the Packet will be
* transmitted. This is detected by polling the Audio2 output FIFO
@@ -444,7 +400,7 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* finished transferring the DAC's data DWORD from the output FIFO
* to the output buffer register.
*/
- while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0)
+ while (!(readl(devpriv->mmio + P_SSR) & SSR_AF2_OUT))
;
/* Set up to trap execution at slot 0 when the TSL sequencer cycles
@@ -453,7 +409,8 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* stored in the last byte to be shifted out of the FIFO's DWORD
* buffer register.
*/
- SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS);
+ writel(XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS,
+ devpriv->mmio + VECTPORT(0));
/* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */
@@ -474,14 +431,14 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If
* the TSL has not yet finished executing slot 5 ...
*/
- if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) {
+ if (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000) {
/* The trap was set on time and we are still executing somewhere
* in slots 2-5, so we now wait for slot 0 to execute and trap
* TSL execution. This is detected when FB_BUFFER2 MSB changes
* from 0xFF to 0x00, which slot 0 causes to happen by shifting
* out/in on SD2 the 0x00 that is always referenced by slot 5.
*/
- while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0)
+ while (readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000)
;
}
/* Either (1) we were too late setting the slot 0 trap; the TSL
@@ -492,13 +449,13 @@ static void SendDAC(struct comedi_device *dev, uint32_t val)
* In order to do this, we reprogram slot 0 so that it will shift in
* SD3, which is driven only by a pull-up resistor.
*/
- SETVECT(0, RSD3 | SIB_A2 | EOS);
+ writel(RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0));
/* Wait for slot 0 to execute, at which time the TSL is setup for
* the next DAC write. This is detected when FB_BUFFER2 MSB changes
* from 0x00 to 0xFF.
*/
- while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0)
+ while (!(readl(devpriv->mmio + P_FB_BUFFER2) & 0xff000000))
;
}
@@ -532,16 +489,16 @@ static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata)
* disables gating for the DAC clock and all DAC chip selects.
*/
+ /* Choose DAC chip select to be asserted */
WSImage = (chan & 2) ? WS1 : WS2;
- /* Choose DAC chip select to be asserted. */
- SETVECT(2, XSD2 | XFIFO_1 | WSImage);
- /* Slot 2: Transmit high data byte to target DAC. */
- SETVECT(3, XSD2 | XFIFO_0 | WSImage);
- /* Slot 3: Transmit low data byte to target DAC. */
- SETVECT(4, XSD2 | XFIFO_3 | WS3);
+ /* Slot 2: Transmit high data byte to target DAC */
+ writel(XSD2 | XFIFO_1 | WSImage, devpriv->mmio + VECTPORT(2));
+ /* Slot 3: Transmit low data byte to target DAC */
+ writel(XSD2 | XFIFO_0 | WSImage, devpriv->mmio + VECTPORT(3));
/* Slot 4: Transmit to non-existent TrimDac channel to keep clock */
- SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS);
- /* Slot 5: running after writing target DAC's low data byte. */
+ writel(XSD2 | XFIFO_3 | WS3, devpriv->mmio + VECTPORT(4));
+ /* Slot 5: running after writing target DAC's low data byte */
+ writel(XSD2 | XFIFO_2 | WS3 | EOS, devpriv->mmio + VECTPORT(5));
/* Construct and transmit target DAC's serial packet:
* ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>,
@@ -577,14 +534,14 @@ static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan,
* can be detected.
*/
- SETVECT(2, XSD2 | XFIFO_1 | WS3);
- /* Slot 2: Send high uint8_t to target TrimDac. */
- SETVECT(3, XSD2 | XFIFO_0 | WS3);
- /* Slot 3: Send low uint8_t to target TrimDac. */
- SETVECT(4, XSD2 | XFIFO_3 | WS1);
- /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running. */
- SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS);
- /* Slot 5: Send NOP low uint8_t to DAC0. */
+ /* Slot 2: Send high uint8_t to target TrimDac */
+ writel(XSD2 | XFIFO_1 | WS3, devpriv->mmio + VECTPORT(2));
+ /* Slot 3: Send low uint8_t to target TrimDac */
+ writel(XSD2 | XFIFO_0 | WS3, devpriv->mmio + VECTPORT(3));
+ /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running */
+ writel(XSD2 | XFIFO_3 | WS1, devpriv->mmio + VECTPORT(4));
+ /* Slot 5: Send NOP low uint8_t to DAC0 */
+ writel(XSD2 | XFIFO_2 | WS1 | EOS, devpriv->mmio + VECTPORT(5));
/* Construct and transmit target DAC's serial packet:
* ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the
@@ -638,8 +595,8 @@ static void SetLatchSource(struct comedi_device *dev, struct enc_private *k,
uint16_t value)
{
DEBIreplace(dev, k->MyCRB,
- (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)),
- (uint16_t) (value << CRBBIT_LATCHSRC));
+ ~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC),
+ value << CRBBIT_LATCHSRC);
}
/* Write value into counter preload register. */
@@ -670,43 +627,24 @@ static unsigned int s626_ai_reg_to_uint(int data)
static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan)
{
- unsigned int group;
- unsigned int bitmask;
+ unsigned int group = chan / 16;
+ unsigned int mask = 1 << (chan - (16 * group));
unsigned int status;
- /* select dio bank */
- group = chan / 16;
- bitmask = 1 << (chan - (16 * group));
-
/* set channel to capture positive edge */
- status = DEBIread(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->RDEdgSel);
- DEBIwrite(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->WREdgSel,
- bitmask | status);
+ status = DEBIread(dev, LP_RDEDGSEL(group));
+ DEBIwrite(dev, LP_WREDGSEL(group), mask | status);
/* enable interrupt on selected channel */
- status = DEBIread(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->RDIntSel);
- DEBIwrite(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->WRIntSel,
- bitmask | status);
+ status = DEBIread(dev, LP_RDINTSEL(group));
+ DEBIwrite(dev, LP_WRINTSEL(group), mask | status);
/* enable edge capture write command */
DEBIwrite(dev, LP_MISC1, MISC1_EDCAP);
/* enable edge capture on selected channel */
- status = DEBIread(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->RDCapSel);
- DEBIwrite(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->WRCapSel,
- bitmask | status);
+ status = DEBIread(dev, LP_RDCAPSEL(group));
+ DEBIwrite(dev, LP_WRCAPSEL(group), mask | status);
return 0;
}
@@ -718,9 +656,7 @@ static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group,
DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
/* enable edge capture on selected channel */
- DEBIwrite(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->WRCapSel, mask);
+ DEBIwrite(dev, LP_WRCAPSEL(group), mask);
return 0;
}
@@ -732,244 +668,249 @@ static int s626_dio_clear_irq(struct comedi_device *dev)
/* disable edge capture write command */
DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
- for (group = 0; group < S626_DIO_BANKS; group++) {
- /* clear pending events and interrupt */
- DEBIwrite(dev,
- ((struct dio_private *)(dev->subdevices + 2 +
- group)->private)->WRCapSel,
- 0xffff);
- }
+ /* clear all dio pending events and interrupt */
+ for (group = 0; group < S626_DIO_BANKS; group++)
+ DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff);
return 0;
}
-static irqreturn_t s626_irq_handler(int irq, void *d)
+static void handle_dio_interrupt(struct comedi_device *dev,
+ uint16_t irqbit, uint8_t group)
{
- struct comedi_device *dev = d;
struct s626_private *devpriv = dev->private;
- struct comedi_subdevice *s;
- struct comedi_cmd *cmd;
- struct enc_private *k;
- unsigned long flags;
- int32_t *readaddr;
- uint32_t irqtype, irqstatus;
- int i = 0;
- short tempdata;
- uint8_t group;
- uint16_t irqbit;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_cmd *cmd = &s->async->cmd;
- if (dev->attached == 0)
- return IRQ_NONE;
- /* lock to avoid race with comedi_poll */
- spin_lock_irqsave(&dev->spinlock, flags);
+ s626_dio_reset_irq(dev, group, irqbit);
- /* save interrupt enable register state */
- irqstatus = readl(devpriv->base_addr + P_IER);
+ if (devpriv->ai_cmd_running) {
+ /* check if interrupt is an ai acquisition start trigger */
+ if ((irqbit >> (cmd->start_arg - (16 * group))) == 1 &&
+ cmd->start_src == TRIG_EXT) {
+ /* Start executing the RPS program */
+ s626_mc_enable(dev, MC1_ERPS1, P_MC1);
+
+ if (cmd->scan_begin_src == TRIG_EXT)
+ s626_dio_set_irq(dev, cmd->scan_begin_arg);
+ }
+ if ((irqbit >> (cmd->scan_begin_arg - (16 * group))) == 1 &&
+ cmd->scan_begin_src == TRIG_EXT) {
+ /* Trigger ADC scan loop start */
+ s626_mc_enable(dev, MC2_ADC_RPS, P_MC2);
- /* read interrupt type */
- irqtype = readl(devpriv->base_addr + P_ISR);
+ if (cmd->convert_src == TRIG_EXT) {
+ devpriv->ai_convert_count = cmd->chanlist_len;
- /* disable master interrupt */
- writel(0, devpriv->base_addr + P_IER);
+ s626_dio_set_irq(dev, cmd->convert_arg);
+ }
- /* clear interrupt */
- writel(irqtype, devpriv->base_addr + P_ISR);
+ if (cmd->convert_src == TRIG_TIMER) {
+ struct enc_private *k = &encpriv[5];
- switch (irqtype) {
- case IRQ_RPS1: /* end_of_scan occurs */
- /* manage ai subdevice */
- s = dev->subdevices;
- cmd = &(s->async->cmd);
+ devpriv->ai_convert_count = cmd->chanlist_len;
+ k->SetEnable(dev, k, CLKENAB_ALWAYS);
+ }
+ }
+ if ((irqbit >> (cmd->convert_arg - (16 * group))) == 1 &&
+ cmd->convert_src == TRIG_EXT) {
+ /* Trigger ADC scan loop start */
+ s626_mc_enable(dev, MC2_ADC_RPS, P_MC2);
+
+ devpriv->ai_convert_count--;
+ if (devpriv->ai_convert_count > 0)
+ s626_dio_set_irq(dev, cmd->convert_arg);
+ }
+ }
+}
- /* Init ptr to DMA buffer that holds new ADC data. We skip the
- * first uint16_t in the buffer because it contains junk data from
- * the final ADC of the previous poll list scan.
- */
- readaddr = (int32_t *) devpriv->ANABuf.LogicalBase + 1;
-
- /* get the data and hand it over to comedi */
- for (i = 0; i < (s->async->cmd.chanlist_len); i++) {
- /* Convert ADC data to 16-bit integer values and copy to application */
- /* buffer. */
- tempdata = s626_ai_reg_to_uint((int)*readaddr);
- readaddr++;
-
- /* put data into read buffer */
- /* comedi_buf_put(s->async, tempdata); */
- if (cfc_write_to_buffer(s, tempdata) == 0)
- printk
- ("s626_irq_handler: cfc_write_to_buffer error!\n");
+static void check_dio_interrupts(struct comedi_device *dev)
+{
+ uint16_t irqbit;
+ uint8_t group;
+
+ for (group = 0; group < S626_DIO_BANKS; group++) {
+ irqbit = 0;
+ /* read interrupt type */
+ irqbit = DEBIread(dev, LP_RDCAPFLG(group));
+
+ /* check if interrupt is generated from dio channels */
+ if (irqbit) {
+ handle_dio_interrupt(dev, irqbit, group);
+ return;
}
+ }
+}
- /* end of scan occurs */
- s->async->events |= COMEDI_CB_EOS;
+static void check_counter_interrupts(struct comedi_device *dev)
+{
+ struct s626_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ struct enc_private *k;
+ uint16_t irqbit;
- if (!(devpriv->ai_continous))
- devpriv->ai_sample_count--;
- if (devpriv->ai_sample_count <= 0) {
- devpriv->ai_cmd_running = 0;
+ /* read interrupt type */
+ irqbit = DEBIread(dev, LP_RDMISC2);
- /* Stop RPS program. */
- MC_DISABLE(P_MC1, MC1_ERPS1);
+ /* check interrupt on counters */
+ if (irqbit & IRQ_COINT1A) {
+ k = &encpriv[0];
- /* send end of acquisition */
- s->async->events |= COMEDI_CB_EOA;
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
+ }
+ if (irqbit & IRQ_COINT2A) {
+ k = &encpriv[1];
- /* disable master interrupt */
- irqstatus = 0;
- }
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
+ }
+ if (irqbit & IRQ_COINT3A) {
+ k = &encpriv[2];
- if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT)
- s626_dio_set_irq(dev, cmd->scan_begin_arg);
- /* tell comedi that data is there */
- comedi_event(dev, s);
- break;
- case IRQ_GPIO3: /* check dio and conter interrupt */
- /* manage ai subdevice */
- s = dev->subdevices;
- cmd = &(s->async->cmd);
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
+ }
+ if (irqbit & IRQ_COINT1B) {
+ k = &encpriv[3];
- /* s626_dio_clear_irq(dev); */
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
+ }
+ if (irqbit & IRQ_COINT2B) {
+ k = &encpriv[4];
+
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
+
+ if (devpriv->ai_convert_count > 0) {
+ devpriv->ai_convert_count--;
+ if (devpriv->ai_convert_count == 0)
+ k->SetEnable(dev, k, CLKENAB_INDEX);
- for (group = 0; group < S626_DIO_BANKS; group++) {
- irqbit = 0;
- /* read interrupt type */
- irqbit = DEBIread(dev,
- ((struct dio_private *)(dev->
- subdevices +
- 2 +
- group)->
- private)->RDCapFlg);
-
- /* check if interrupt is generated from dio channels */
- if (irqbit) {
- s626_dio_reset_irq(dev, group, irqbit);
- if (devpriv->ai_cmd_running) {
- /* check if interrupt is an ai acquisition start trigger */
- if ((irqbit >> (cmd->start_arg -
- (16 * group)))
- == 1 && cmd->start_src == TRIG_EXT) {
- /* Start executing the RPS program. */
- MC_ENABLE(P_MC1, MC1_ERPS1);
-
- if (cmd->scan_begin_src ==
- TRIG_EXT) {
- s626_dio_set_irq(dev,
- cmd->scan_begin_arg);
- }
- }
- if ((irqbit >> (cmd->scan_begin_arg -
- (16 * group)))
- == 1
- && cmd->scan_begin_src ==
- TRIG_EXT) {
- /* Trigger ADC scan loop start by setting RPS Signal 0. */
- MC_ENABLE(P_MC2, MC2_ADC_RPS);
-
- if (cmd->convert_src ==
- TRIG_EXT) {
- devpriv->ai_convert_count
- = cmd->chanlist_len;
-
- s626_dio_set_irq(dev,
- cmd->convert_arg);
- }
-
- if (cmd->convert_src ==
- TRIG_TIMER) {
- k = &encpriv[5];
- devpriv->ai_convert_count
- = cmd->chanlist_len;
- k->SetEnable(dev, k,
- CLKENAB_ALWAYS);
- }
- }
- if ((irqbit >> (cmd->convert_arg -
- (16 * group)))
- == 1
- && cmd->convert_src == TRIG_EXT) {
- /* Trigger ADC scan loop start by setting RPS Signal 0. */
- MC_ENABLE(P_MC2, MC2_ADC_RPS);
-
- devpriv->ai_convert_count--;
-
- if (devpriv->ai_convert_count >
- 0) {
- s626_dio_set_irq(dev,
- cmd->convert_arg);
- }
- }
- }
- break;
+ if (cmd->convert_src == TRIG_TIMER) {
+ /* Trigger ADC scan loop start */
+ s626_mc_enable(dev, MC2_ADC_RPS, P_MC2);
}
}
+ }
+ if (irqbit & IRQ_COINT3B) {
+ k = &encpriv[5];
- /* read interrupt type */
- irqbit = DEBIread(dev, LP_RDMISC2);
-
- /* check interrupt on counters */
- if (irqbit & IRQ_COINT1A) {
- k = &encpriv[0];
+ /* clear interrupt capture flag */
+ k->ResetCapFlags(dev, k);
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
+ if (cmd->scan_begin_src == TRIG_TIMER) {
+ /* Trigger ADC scan loop start */
+ s626_mc_enable(dev, MC2_ADC_RPS, P_MC2);
}
- if (irqbit & IRQ_COINT2A) {
- k = &encpriv[1];
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
+ if (cmd->convert_src == TRIG_TIMER) {
+ k = &encpriv[4];
+ devpriv->ai_convert_count = cmd->chanlist_len;
+ k->SetEnable(dev, k, CLKENAB_ALWAYS);
}
- if (irqbit & IRQ_COINT3A) {
- k = &encpriv[2];
+ }
+}
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
- }
- if (irqbit & IRQ_COINT1B) {
- k = &encpriv[3];
+static bool handle_eos_interrupt(struct comedi_device *dev)
+{
+ struct s626_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ /*
+ * Init ptr to DMA buffer that holds new ADC data. We skip the
+ * first uint16_t in the buffer because it contains junk data
+ * from the final ADC of the previous poll list scan.
+ */
+ int32_t *readaddr = (int32_t *)devpriv->ANABuf.LogicalBase + 1;
+ bool finished = false;
+ int i;
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
- }
- if (irqbit & IRQ_COINT2B) {
- k = &encpriv[4];
+ /* get the data and hand it over to comedi */
+ for (i = 0; i < cmd->chanlist_len; i++) {
+ short tempdata;
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
+ /*
+ * Convert ADC data to 16-bit integer values and copy
+ * to application buffer.
+ */
+ tempdata = s626_ai_reg_to_uint((int)*readaddr);
+ readaddr++;
- if (devpriv->ai_convert_count > 0) {
- devpriv->ai_convert_count--;
- if (devpriv->ai_convert_count == 0)
- k->SetEnable(dev, k, CLKENAB_INDEX);
+ /* put data into read buffer */
+ /* comedi_buf_put(async, tempdata); */
+ cfc_write_to_buffer(s, tempdata);
+ }
- if (cmd->convert_src == TRIG_TIMER) {
- /* Trigger ADC scan loop start by setting RPS Signal 0. */
- MC_ENABLE(P_MC2, MC2_ADC_RPS);
- }
- }
- }
- if (irqbit & IRQ_COINT3B) {
- k = &encpriv[5];
+ /* end of scan occurs */
+ async->events |= COMEDI_CB_EOS;
- /* clear interrupt capture flag */
- k->ResetCapFlags(dev, k);
+ if (!devpriv->ai_continous)
+ devpriv->ai_sample_count--;
+ if (devpriv->ai_sample_count <= 0) {
+ devpriv->ai_cmd_running = 0;
- if (cmd->scan_begin_src == TRIG_TIMER) {
- /* Trigger ADC scan loop start by setting RPS Signal 0. */
- MC_ENABLE(P_MC2, MC2_ADC_RPS);
- }
+ /* Stop RPS program */
+ s626_mc_disable(dev, MC1_ERPS1, P_MC1);
- if (cmd->convert_src == TRIG_TIMER) {
- k = &encpriv[4];
- devpriv->ai_convert_count = cmd->chanlist_len;
- k->SetEnable(dev, k, CLKENAB_ALWAYS);
- }
- }
+ /* send end of acquisition */
+ async->events |= COMEDI_CB_EOA;
+
+ /* disable master interrupt */
+ finished = true;
+ }
+
+ if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT)
+ s626_dio_set_irq(dev, cmd->scan_begin_arg);
+
+ /* tell comedi that data is there */
+ comedi_event(dev, s);
+
+ return finished;
+}
+
+static irqreturn_t s626_irq_handler(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct s626_private *devpriv = dev->private;
+ unsigned long flags;
+ uint32_t irqtype, irqstatus;
+
+ if (!dev->attached)
+ return IRQ_NONE;
+ /* lock to avoid race with comedi_poll */
+ spin_lock_irqsave(&dev->spinlock, flags);
+
+ /* save interrupt enable register state */
+ irqstatus = readl(devpriv->mmio + P_IER);
+
+ /* read interrupt type */
+ irqtype = readl(devpriv->mmio + P_ISR);
+
+ /* disable master interrupt */
+ writel(0, devpriv->mmio + P_IER);
+
+ /* clear interrupt */
+ writel(irqtype, devpriv->mmio + P_ISR);
+
+ switch (irqtype) {
+ case IRQ_RPS1: /* end_of_scan occurs */
+ if (handle_eos_interrupt(dev))
+ irqstatus = 0;
+ break;
+ case IRQ_GPIO3: /* check dio and conter interrupt */
+ /* s626_dio_clear_irq(dev); */
+ check_dio_interrupts(dev);
+ check_counter_interrupts(dev);
+ break;
}
/* enable interrupt */
- writel(irqstatus, devpriv->base_addr + P_IER);
+ writel(irqstatus, devpriv->mmio + P_IER);
spin_unlock_irqrestore(&dev->spinlock, flags);
return IRQ_HANDLED;
@@ -988,14 +929,15 @@ static void ResetADC(struct comedi_device *dev, uint8_t *ppl)
uint32_t LocalPPL;
struct comedi_cmd *cmd = &(dev->subdevices->async->cmd);
- /* Stop RPS program in case it is currently running. */
- MC_DISABLE(P_MC1, MC1_ERPS1);
+ /* Stop RPS program in case it is currently running */
+ s626_mc_disable(dev, MC1_ERPS1, P_MC1);
/* Set starting logical address to write RPS commands. */
pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase;
- /* Initialize RPS instruction pointer. */
- WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase);
+ /* Initialize RPS instruction pointer */
+ writel((uint32_t)devpriv->RPSBuf.PhysicalBase,
+ devpriv->mmio + P_RPSADDR1);
/* Construct RPS program in RPSBuf DMA buffer */
@@ -1165,41 +1107,42 @@ static void ResetADC(struct comedi_device *dev, uint8_t *ppl)
/* End of RPS program build */
}
-/* TO COMPLETE, IF NECESSARY */
-static int s626_ai_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+#ifdef unused_code
+static int s626_ai_rinsn(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ struct s626_private *devpriv = dev->private;
+ register uint8_t i;
+ register int32_t *readaddr;
- return -EINVAL;
-}
-
-/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) */
-/* { */
-/* struct s626_private *devpriv = dev->private; */
-/* register uint8_t i; */
-/* register int32_t *readaddr; */
-
-/* Trigger ADC scan loop start by setting RPS Signal 0. */
-/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */
+ /* Trigger ADC scan loop start */
+ s626_mc_enable(dev, MC2_ADC_RPS, P_MC2);
-/* Wait until ADC scan loop is finished (RPS Signal 0 reset). */
-/* while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */
+ /* Wait until ADC scan loop is finished (RPS Signal 0 reset) */
+ while (s626_mc_test(dev, MC2_ADC_RPS, P_MC2))
+ ;
-/* Init ptr to DMA buffer that holds new ADC data. We skip the
- * first uint16_t in the buffer because it contains junk data from
- * the final ADC of the previous poll list scan.
- */
-/* readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */
+ /*
+ * Init ptr to DMA buffer that holds new ADC data. We skip the
+ * first uint16_t in the buffer because it contains junk data from
+ * the final ADC of the previous poll list scan.
+ */
+ readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1;
-/* Convert ADC data to 16-bit integer values and copy to application buffer. */
-/* for ( i = 0; i < devpriv->AdcItems; i++ ) { */
-/* *data = s626_ai_reg_to_uint( *readaddr++ ); */
-/* data++; */
-/* } */
+ /*
+ * Convert ADC data to 16-bit integer values and
+ * copy to application buffer.
+ */
+ for (i = 0; i < devpriv->AdcItems; i++) {
+ *data = s626_ai_reg_to_uint(*readaddr++);
+ data++;
+ }
-/* return i; */
-/* } */
+ return i;
+}
+#endif
static int s626_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -1210,14 +1153,9 @@ static int s626_ai_insn_read(struct comedi_device *dev,
uint16_t range = CR_RANGE(insn->chanspec);
uint16_t AdcSpec = 0;
uint32_t GpioImage;
+ int tmp;
int n;
- /* interrupt call test */
-/* writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); */
- /* Writing a logical 1 into any of the RPS_PSR bits causes the
- * corresponding interrupt to be generated if enabled
- */
-
/* Convert application's ADC specification into form
* appropriate for register programming.
*/
@@ -1237,27 +1175,29 @@ static int s626_ai_insn_read(struct comedi_device *dev,
/* Delay 10 microseconds for analog input settling. */
udelay(10);
- /* Start ADC by pulsing GPIO1 low. */
- GpioImage = RR7146(P_GPIO);
- /* Assert ADC Start command */
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- /* and stretch it out. */
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- /* Negate ADC Start command. */
- WR7146(P_GPIO, GpioImage | GPIO1_HI);
+ /* Start ADC by pulsing GPIO1 low */
+ GpioImage = readl(devpriv->mmio + P_GPIO);
+ /* Assert ADC Start command */
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ /* and stretch it out */
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ /* Negate ADC Start command */
+ writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO);
/* Wait for ADC to complete (GPIO2 is asserted high when */
/* ADC not busy) and for data from previous conversion to */
/* shift into FB BUFFER 1 register. */
- /* Wait for ADC done. */
- while (!(RR7146(P_PSR) & PSR_GPIO2))
+ /* Wait for ADC done */
+ while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2))
;
- /* Fetch ADC data. */
- if (n != 0)
- data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1));
+ /* Fetch ADC data */
+ if (n != 0) {
+ tmp = readl(devpriv->mmio + P_FB_BUFFER1);
+ data[n - 1] = s626_ai_reg_to_uint(tmp);
+ }
/* Allow the ADC to stabilize for 4 microseconds before
* starting the next (final) conversion. This delay is
@@ -1272,27 +1212,28 @@ static int s626_ai_insn_read(struct comedi_device *dev,
/* Start a dummy conversion to cause the data from the
* previous conversion to be shifted in. */
- GpioImage = RR7146(P_GPIO);
-
+ GpioImage = readl(devpriv->mmio + P_GPIO);
/* Assert ADC Start command */
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- /* and stretch it out. */
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- WR7146(P_GPIO, GpioImage & ~GPIO1_HI);
- /* Negate ADC Start command. */
- WR7146(P_GPIO, GpioImage | GPIO1_HI);
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ /* and stretch it out */
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ writel(GpioImage & ~GPIO1_HI, devpriv->mmio + P_GPIO);
+ /* Negate ADC Start command */
+ writel(GpioImage | GPIO1_HI, devpriv->mmio + P_GPIO);
/* Wait for the data to arrive in FB BUFFER 1 register. */
- /* Wait for ADC done. */
- while (!(RR7146(P_PSR) & PSR_GPIO2))
+ /* Wait for ADC done */
+ while (!(readl(devpriv->mmio + P_PSR) & PSR_GPIO2))
;
/* Fetch ADC data from audio interface's input shift register. */
- /* Fetch ADC data. */
- if (n != 0)
- data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1));
+ /* Fetch ADC data */
+ if (n != 0) {
+ tmp = readl(devpriv->mmio + P_FB_BUFFER1);
+ data[n - 1] = s626_ai_reg_to_uint(tmp);
+ }
return n;
}
@@ -1317,13 +1258,11 @@ static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd)
static int s626_ai_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int trignum)
{
- struct s626_private *devpriv = dev->private;
-
if (trignum != 0)
return -EINVAL;
- /* Start executing the RPS program. */
- MC_ENABLE(P_MC1, MC1_ERPS1);
+ /* Start executing the RPS program */
+ s626_mc_enable(dev, MC1_ERPS1, P_MC1);
s->async->inttrig = NULL;
@@ -1407,10 +1346,10 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return -EBUSY;
}
/* disable interrupt */
- writel(0, devpriv->base_addr + P_IER);
+ writel(0, devpriv->mmio + P_IER);
/* clear interrupt request */
- writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->base_addr + P_ISR);
+ writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->mmio + P_ISR);
/* clear any pending interrupt */
s626_dio_clear_irq(dev);
@@ -1483,7 +1422,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
case TRIG_NONE:
/* continous acquisition */
devpriv->ai_continous = 1;
- devpriv->ai_sample_count = 0;
+ devpriv->ai_sample_count = 1;
break;
}
@@ -1491,11 +1430,11 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
switch (cmd->start_src) {
case TRIG_NOW:
- /* Trigger ADC scan loop start by setting RPS Signal 0. */
- /* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */
+ /* Trigger ADC scan loop start */
+ /* s626_mc_enable(dev, MC2_ADC_RPS, P_MC2); */
- /* Start executing the RPS program. */
- MC_ENABLE(P_MC1, MC1_ERPS1);
+ /* Start executing the RPS program */
+ s626_mc_enable(dev, MC1_ERPS1, P_MC1);
s->async->inttrig = NULL;
break;
@@ -1511,7 +1450,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* enable interrupt */
- writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER);
+ writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->mmio + P_IER);
return 0;
}
@@ -1628,11 +1567,11 @@ static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct s626_private *devpriv = dev->private;
- /* Stop RPS program in case it is currently running. */
- MC_DISABLE(P_MC1, MC1_ERPS1);
+ /* Stop RPS program in case it is currently running */
+ s626_mc_disable(dev, MC1_ERPS1, P_MC1);
/* disable master interrupt */
- writel(0, devpriv->base_addr + P_IER);
+ writel(0, devpriv->mmio + P_IER);
devpriv->ai_cmd_running = 0;
@@ -1679,84 +1618,74 @@ static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
static void s626_dio_init(struct comedi_device *dev)
{
uint16_t group;
- struct comedi_subdevice *s;
/* Prepare to treat writes to WRCapSel as capture disables. */
DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP);
/* For each group of sixteen channels ... */
for (group = 0; group < S626_DIO_BANKS; group++) {
- s = dev->subdevices + 2 + group;
- DEBIwrite(dev, diopriv->WRIntSel, 0); /* Disable all interrupts. */
- DEBIwrite(dev, diopriv->WRCapSel, 0xFFFF); /* Disable all event */
- /* captures. */
- DEBIwrite(dev, diopriv->WREdgSel, 0); /* Init all DIOs to */
- /* default edge */
- /* polarity. */
- DEBIwrite(dev, diopriv->WRDOut, 0); /* Program all outputs */
- /* to inactive state. */
+ /* Disable all interrupts */
+ DEBIwrite(dev, LP_WRINTSEL(group), 0);
+ /* Disable all event captures */
+ DEBIwrite(dev, LP_WRCAPSEL(group), 0xffff);
+ /* Init all DIOs to default edge polarity */
+ DEBIwrite(dev, LP_WREDGSEL(group), 0);
+ /* Program all outputs to inactive state */
+ DEBIwrite(dev, LP_WRDOUT(group), 0);
}
}
-/* DIO devices are slightly special. Although it is possible to
- * implement the insn_read/insn_write interface, it is much more
- * useful to applications if you implement the insn_bits interface.
- * This allows packed reading/writing of the DIO channels. The comedi
- * core can convert between insn_bits and insn_read/write */
-
static int s626_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- /*
- * The insn data consists of a mask in data[0] and the new data in
- * data[1]. The mask defines which bits we are concerning about.
- * The new data must be anded with the mask. Each channel
- * corresponds to a bit.
- */
- if (data[0]) {
- /* Check if requested ports are configured for output */
- if ((s->io_bits & data[0]) != data[0])
- return -EIO;
+ unsigned long group = (unsigned long)s->private;
+ unsigned long mask = data[0];
+ unsigned long bits = data[1];
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
+ if (mask) {
+ /* Check if requested channels are configured for output */
+ if ((s->io_bits & mask) != mask)
+ return -EIO;
- /* Write out the new digital output lines */
+ s->state &= ~mask;
+ s->state |= (bits & mask);
- DEBIwrite(dev, diopriv->WRDOut, s->state);
+ DEBIwrite(dev, LP_WRDOUT(group), s->state);
}
- data[1] = DEBIread(dev, diopriv->RDDIn);
+ data[1] = DEBIread(dev, LP_RDDIN(group));
return insn->n;
}
static int s626_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
+ unsigned long group = (unsigned long)s->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int mask = 1 << chan;
switch (data[0]) {
case INSN_CONFIG_DIO_QUERY:
- data[1] =
- (s->
- io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
- COMEDI_INPUT;
+ data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n;
break;
case COMEDI_INPUT:
- s->io_bits &= ~(1 << CR_CHAN(insn->chanspec));
+ s->io_bits &= ~mask;
break;
case COMEDI_OUTPUT:
- s->io_bits |= 1 << CR_CHAN(insn->chanspec);
+ s->io_bits |= mask;
break;
default:
return -EINVAL;
break;
}
- DEBIwrite(dev, diopriv->WRDOut, s->io_bits);
+ DEBIwrite(dev, LP_WRDOUT(group), s->io_bits);
- return 1;
+ return insn->n;
}
/* Now this function initializes the value of the counter (data[0])
@@ -1861,13 +1790,13 @@ static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma,
static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k)
{
- DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+ DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL,
CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
}
static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k)
{
- DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+ DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL,
CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B);
}
@@ -2012,8 +1941,7 @@ static void SetMode_A(struct comedi_device *dev, struct enc_private *k,
/* While retaining CounterB and LatchSrc configurations, program the */
/* new counter operating mode. */
DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra);
- DEBIreplace(dev, k->MyCRB,
- (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb);
+ DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A), crb);
}
static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
@@ -2074,8 +2002,7 @@ static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
/* While retaining CounterA and LatchSrc configurations, program the */
/* new counter operating mode. */
- DEBIreplace(dev, k->MyCRA,
- (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra);
+ DEBIreplace(dev, k->MyCRA, ~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B), cra);
DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb);
}
@@ -2084,17 +2011,15 @@ static void SetMode_B(struct comedi_device *dev, struct enc_private *k,
static void SetEnable_A(struct comedi_device *dev, struct enc_private *k,
uint16_t enab)
{
- DEBIreplace(dev, k->MyCRB,
- (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)),
- (uint16_t) (enab << CRBBIT_CLKENAB_A));
+ DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A),
+ enab << CRBBIT_CLKENAB_A);
}
static void SetEnable_B(struct comedi_device *dev, struct enc_private *k,
uint16_t enab)
{
- DEBIreplace(dev, k->MyCRB,
- (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)),
- (uint16_t) (enab << CRBBIT_CLKENAB_B));
+ DEBIreplace(dev, k->MyCRB, ~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B),
+ enab << CRBBIT_CLKENAB_B);
}
static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k)
@@ -2123,16 +2048,15 @@ static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k)
static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k,
uint16_t Trig)
{
- DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A),
- (uint16_t) (Trig << CRABIT_LOADSRC_A));
+ DEBIreplace(dev, k->MyCRA, ~CRAMSK_LOADSRC_A,
+ Trig << CRABIT_LOADSRC_A);
}
static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k,
uint16_t Trig)
{
- DEBIreplace(dev, k->MyCRB,
- (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)),
- (uint16_t) (Trig << CRBBIT_LOADSRC_B));
+ DEBIreplace(dev, k->MyCRB, ~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL),
+ Trig << CRBBIT_LOADSRC_B);
}
static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k)
@@ -2156,12 +2080,12 @@ static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k,
struct s626_private *devpriv = dev->private;
/* Reset any pending counter overflow or index captures. */
- DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL),
+ DEBIreplace(dev, k->MyCRB, ~CRBMSK_INTCTRL,
CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A);
/* Program counter interrupt source. */
DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A,
- (uint16_t) (IntSource << CRABIT_INTSRC_A));
+ IntSource << CRABIT_INTSRC_A);
/* Update MISC2 interrupt enable mask. */
devpriv->CounterIntEnabs =
@@ -2430,7 +2354,7 @@ static void s626_initialize(struct comedi_device *dev)
int i;
/* Enable DEBI and audio pins, enable I2C interface */
- MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C);
+ s626_mc_enable(dev, MC1_DEBI | MC1_AUDIO | MC1_I2C, P_MC1);
/*
* Configure DEBI operating mode
@@ -2440,15 +2364,16 @@ static void s626_initialize(struct comedi_device *dev)
* Set up byte lane steering
* Intel-compatible local bus (DEBI never times out)
*/
- WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 |
- (DEBI_TOUT << DEBI_CFG_TOUT_BIT) |
- DEBI_SWAP | DEBI_CFG_INTEL);
+ writel(DEBI_CFG_SLAVE16 |
+ (DEBI_TOUT << DEBI_CFG_TOUT_BIT) |
+ DEBI_SWAP | DEBI_CFG_INTEL,
+ devpriv->mmio + P_DEBICFG);
/* Disable MMU paging */
- WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE);
+ writel(DEBI_PAGE_DISABLE, devpriv->mmio + P_DEBIPAGE);
/* Init GPIO so that ADC Start* is negated */
- WR7146(P_GPIO, GPIO_BASE | GPIO1_HI);
+ writel(GPIO_BASE | GPIO1_HI, devpriv->mmio + P_GPIO);
/* I2C device address for onboard eeprom (revb) */
devpriv->I2CAdrs = 0xA0;
@@ -2457,9 +2382,9 @@ static void s626_initialize(struct comedi_device *dev)
* Issue an I2C ABORT command to halt any I2C
* operation in progress and reset BUSY flag.
*/
- WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT);
- MC_ENABLE(P_MC2, MC2_UPLD_IIC);
- while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0)
+ writel(I2C_CLKSEL | I2C_ABORT, devpriv->mmio + P_I2CSTAT);
+ s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2);
+ while (!(readl(devpriv->mmio + P_MC2) & MC2_UPLD_IIC))
;
/*
@@ -2467,9 +2392,9 @@ static void s626_initialize(struct comedi_device *dev)
* reg twice to reset all I2C error flags.
*/
for (i = 0; i < 2; i++) {
- WR7146(P_I2CSTAT, I2C_CLKSEL);
- MC_ENABLE(P_MC2, MC2_UPLD_IIC);
- while (!MC_TEST(P_MC2, MC2_UPLD_IIC))
+ writel(I2C_CLKSEL, devpriv->mmio + P_I2CSTAT);
+ s626_mc_enable(dev, MC2_UPLD_IIC, P_MC2);
+ while (!s626_mc_test(dev, MC2_UPLD_IIC, P_MC2))
;
}
@@ -2479,7 +2404,7 @@ static void s626_initialize(struct comedi_device *dev)
* DAC data setup times are satisfied, enable DAC serial
* clock out.
*/
- WR7146(P_ACON2, ACON2_INIT);
+ writel(ACON2_INIT, devpriv->mmio + P_ACON2);
/*
* Set up TSL1 slot list, which is used to control the
@@ -2487,22 +2412,23 @@ static void s626_initialize(struct comedi_device *dev)
* SIB_A1 = store data uint8_t at next available location
* in FB BUFFER1 register.
*/
- WR7146(P_TSL1, RSD1 | SIB_A1);
- WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS);
+ writel(RSD1 | SIB_A1, devpriv->mmio + P_TSL1);
+ writel(RSD1 | SIB_A1 | EOS, devpriv->mmio + P_TSL1 + 4);
/* Enable TSL1 slot list so that it executes all the time */
- WR7146(P_ACON1, ACON1_ADCSTART);
+ writel(ACON1_ADCSTART, devpriv->mmio + P_ACON1);
/*
* Initialize RPS registers used for ADC
*/
/* Physical start of RPS program */
- WR7146(P_RPSADDR1, (uint32_t)devpriv->RPSBuf.PhysicalBase);
+ writel((uint32_t)devpriv->RPSBuf.PhysicalBase,
+ devpriv->mmio + P_RPSADDR1);
/* RPS program performs no explicit mem writes */
- WR7146(P_RPSPAGE1, 0);
+ writel(0, devpriv->mmio + P_RPSPAGE1);
/* Disable RPS timeouts */
- WR7146(P_RPS1_TOUT, 0);
+ writel(0, devpriv->mmio + P_RPS1_TOUT);
#if 0
/*
@@ -2558,7 +2484,7 @@ static void s626_initialize(struct comedi_device *dev)
* burst length = 1 DWORD
* threshold = 1 DWORD.
*/
- WR7146(P_PCI_BT_A, 0);
+ writel(0, devpriv->mmio + P_PCI_BT_A);
/*
* Init Audio2's output DMA physical addresses. The protection
@@ -2568,8 +2494,9 @@ static void s626_initialize(struct comedi_device *dev)
*/
pPhysBuf = devpriv->ANABuf.PhysicalBase +
(DAC_WDMABUF_OS * sizeof(uint32_t));
- WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf);
- WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t)));
+ writel((uint32_t)pPhysBuf, devpriv->mmio + P_BASEA2_OUT);
+ writel((uint32_t)(pPhysBuf + sizeof(uint32_t)),
+ devpriv->mmio + P_PROTA2_OUT);
/*
* Cache Audio2's output DMA buffer logical address. This is
@@ -2584,7 +2511,7 @@ static void s626_initialize(struct comedi_device *dev)
* DMAC will automatically halt and its PCI address pointer
* will be reset when the protection address is reached.
*/
- WR7146(P_PAGEA2_OUT, 8);
+ writel(8, devpriv->mmio + P_PAGEA2_OUT);
/*
* Initialize time slot list 2 (TSL2), which is used to control
@@ -2599,7 +2526,7 @@ static void s626_initialize(struct comedi_device *dev)
*/
/* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */
- SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS);
+ writel(XSD2 | RSD3 | SIB_A2 | EOS, devpriv->mmio + VECTPORT(0));
/*
* Initialize slot 1, which is constant. Slot 1 causes a
@@ -2611,10 +2538,10 @@ static void s626_initialize(struct comedi_device *dev)
*/
/* Slot 1: Fetch DWORD from Audio2's output FIFO */
- SETVECT(1, LF_A2);
+ writel(LF_A2, devpriv->mmio + VECTPORT(1));
/* Start DAC's audio interface (TSL2) running */
- WR7146(P_ACON1, ACON1_DACSTART);
+ writel(ACON1_DACSTART, devpriv->mmio + P_ACON1);
/*
* Init Trim DACs to calibrated values. Do it twice because the
@@ -2653,9 +2580,6 @@ static void s626_initialize(struct comedi_device *dev)
/* Initialize the digital I/O subsystem */
s626_dio_init(dev);
-
- /* enable interrupt test */
- /* writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER); */
}
static int s626_auto_attach(struct comedi_device *dev,
@@ -2666,28 +2590,24 @@ static int s626_auto_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
- dev->iobase = 1; /* detach needs this */
- devpriv->base_addr = ioremap(pci_resource_start(pcidev, 0),
- pci_resource_len(pcidev, 0));
- if (!devpriv->base_addr)
+ devpriv->mmio = pci_ioremap_bar(pcidev, 0);
+ if (!devpriv->mmio)
return -ENOMEM;
/* disable master interrupt */
- writel(0, devpriv->base_addr + P_IER);
+ writel(0, devpriv->mmio + P_IER);
/* soft reset */
- writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1);
+ writel(MC1_SOFT_RESET, devpriv->mmio + P_MC1);
/* DMA FIXME DMA// */
@@ -2707,79 +2627,79 @@ static int s626_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- s = dev->subdevices + 0;
+ s = &dev->subdevices[0];
/* analog input subdevice */
- dev->read_subdev = s;
- /* we support single-ended (ground) and differential */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
- s->n_chan = S626_ADC_CHANNELS;
- s->maxdata = (0xffff >> 2);
- s->range_table = &s626_range_table;
- s->len_chanlist = S626_ADC_CHANNELS;
- s->insn_config = s626_ai_insn_config;
- s->insn_read = s626_ai_insn_read;
- s->do_cmd = s626_ai_cmd;
- s->do_cmdtest = s626_ai_cmdtest;
- s->cancel = s626_ai_cancel;
-
- s = dev->subdevices + 1;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ;
+ s->n_chan = S626_ADC_CHANNELS;
+ s->maxdata = 0x3fff;
+ s->range_table = &s626_range_table;
+ s->len_chanlist = S626_ADC_CHANNELS;
+ s->insn_read = s626_ai_insn_read;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->do_cmd = s626_ai_cmd;
+ s->do_cmdtest = s626_ai_cmdtest;
+ s->cancel = s626_ai_cancel;
+ }
+
+ s = &dev->subdevices[1];
/* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = S626_DAC_CHANNELS;
- s->maxdata = (0x3fff);
- s->range_table = &range_bipolar10;
- s->insn_write = s626_ao_winsn;
- s->insn_read = s626_ao_rinsn;
-
- s = dev->subdevices + 2;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = S626_DAC_CHANNELS;
+ s->maxdata = 0x3fff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = s626_ao_winsn;
+ s->insn_read = s626_ao_rinsn;
+
+ s = &dev->subdevices[2];
/* digital I/O subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->io_bits = 0xffff;
- s->private = &dio_private_A;
- s->range_table = &range_digital;
- s->insn_config = s626_dio_insn_config;
- s->insn_bits = s626_dio_insn_bits;
-
- s = dev->subdevices + 3;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->io_bits = 0xffff;
+ s->private = (void *)0; /* DIO group 0 */
+ s->range_table = &range_digital;
+ s->insn_config = s626_dio_insn_config;
+ s->insn_bits = s626_dio_insn_bits;
+
+ s = &dev->subdevices[3];
/* digital I/O subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->io_bits = 0xffff;
- s->private = &dio_private_B;
- s->range_table = &range_digital;
- s->insn_config = s626_dio_insn_config;
- s->insn_bits = s626_dio_insn_bits;
-
- s = dev->subdevices + 4;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->io_bits = 0xffff;
+ s->private = (void *)1; /* DIO group 1 */
+ s->range_table = &range_digital;
+ s->insn_config = s626_dio_insn_config;
+ s->insn_bits = s626_dio_insn_bits;
+
+ s = &dev->subdevices[4];
/* digital I/O subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->io_bits = 0xffff;
- s->private = &dio_private_C;
- s->range_table = &range_digital;
- s->insn_config = s626_dio_insn_config;
- s->insn_bits = s626_dio_insn_bits;
-
- s = dev->subdevices + 5;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->io_bits = 0xffff;
+ s->private = (void *)2; /* DIO group 2 */
+ s->range_table = &range_digital;
+ s->insn_config = s626_dio_insn_config;
+ s->insn_bits = s626_dio_insn_bits;
+
+ s = &dev->subdevices[5];
/* encoder (counter) subdevice */
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
- s->n_chan = S626_ENCODER_CHANNELS;
- s->private = enc_private_data;
- s->insn_config = s626_enc_insn_config;
- s->insn_read = s626_enc_insn_read;
- s->insn_write = s626_enc_insn_write;
- s->maxdata = 0xffffff;
- s->range_table = &range_unknown;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = S626_ENCODER_CHANNELS;
+ s->maxdata = 0xffffff;
+ s->private = enc_private_data;
+ s->range_table = &range_unknown;
+ s->insn_config = s626_enc_insn_config;
+ s->insn_read = s626_enc_insn_read;
+ s->insn_write = s626_enc_insn_write;
s626_initialize(dev);
@@ -2790,24 +2710,26 @@ static int s626_auto_attach(struct comedi_device *dev,
static void s626_detach(struct comedi_device *dev)
{
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
struct s626_private *devpriv = dev->private;
if (devpriv) {
/* stop ai_command */
devpriv->ai_cmd_running = 0;
- if (devpriv->base_addr) {
+ if (devpriv->mmio) {
/* interrupt mask */
- WR7146(P_IER, 0); /* Disable master interrupt. */
- WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1); /* Clear board's IRQ status flag. */
+ /* Disable master interrupt */
+ writel(0, devpriv->mmio + P_IER);
+ /* Clear board's IRQ status flag */
+ writel(IRQ_GPIO3 | IRQ_RPS1,
+ devpriv->mmio + P_ISR);
/* Disable the watchdog timer and battery charger. */
WriteMISC2(dev, 0);
- /* Close all interfaces on 7146 device. */
- WR7146(P_MC1, MC1_SHUTDOWN);
- WR7146(P_ACON1, ACON1_BASE);
+ /* Close all interfaces on 7146 device */
+ writel(MC1_SHUTDOWN, devpriv->mmio + P_MC1);
+ writel(ACON1_BASE, devpriv->mmio + P_ACON1);
CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE);
CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE);
@@ -2815,13 +2737,10 @@ static void s626_detach(struct comedi_device *dev)
if (dev->irq)
free_irq(dev->irq, dev);
- if (devpriv->base_addr)
- iounmap(devpriv->base_addr);
- }
- if (pcidev) {
- if (dev->iobase)
- comedi_pci_disable(pcidev);
+ if (devpriv->mmio)
+ iounmap(devpriv->mmio);
}
+ comedi_pci_disable(dev);
}
static struct comedi_driver s626_driver = {
@@ -2832,9 +2751,9 @@ static struct comedi_driver s626_driver = {
};
static int s626_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &s626_driver);
+ return comedi_pci_auto_config(dev, &s626_driver, id->driver_data);
}
/*
diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h
index ff4b3a5e4e5f..99cd57b092ea 100644
--- a/drivers/staging/comedi/drivers/s626.h
+++ b/drivers/staging/comedi/drivers/s626.h
@@ -267,36 +267,17 @@
#define LP_DACPOL 0x0082 /* Write DAC polarity. */
#define LP_GSEL 0x0084 /* Write ADC gain. */
#define LP_ISEL 0x0086 /* Write ADC channel select. */
-/* Digital I/O (write only): */
-#define LP_WRINTSELA 0x0042 /* Write A interrupt enable. */
-#define LP_WREDGSELA 0x0044 /* Write A edge selection. */
-#define LP_WRCAPSELA 0x0046 /* Write A capture enable. */
-#define LP_WRDOUTA 0x0048 /* Write A digital output. */
-#define LP_WRINTSELB 0x0052 /* Write B interrupt enable. */
-#define LP_WREDGSELB 0x0054 /* Write B edge selection. */
-#define LP_WRCAPSELB 0x0056 /* Write B capture enable. */
-#define LP_WRDOUTB 0x0058 /* Write B digital output. */
-#define LP_WRINTSELC 0x0062 /* Write C interrupt enable. */
-#define LP_WREDGSELC 0x0064 /* Write C edge selection. */
-#define LP_WRCAPSELC 0x0066 /* Write C capture enable. */
-#define LP_WRDOUTC 0x0068 /* Write C digital output. */
-
-/* Digital I/O (read only): */
-#define LP_RDDINA 0x0040 /* Read digital input. */
-#define LP_RDCAPFLGA 0x0048 /* Read edges captured. */
-#define LP_RDINTSELA 0x004A /* Read interrupt enable register. */
-#define LP_RDEDGSELA 0x004C /* Read edge selection register. */
-#define LP_RDCAPSELA 0x004E /* Read capture enable register. */
-#define LP_RDDINB 0x0050 /* Read digital input. */
-#define LP_RDCAPFLGB 0x0058 /* Read edges captured. */
-#define LP_RDINTSELB 0x005A /* Read interrupt enable register. */
-#define LP_RDEDGSELB 0x005C /* Read edge selection register. */
-#define LP_RDCAPSELB 0x005E /* Read capture enable register. */
-#define LP_RDDINC 0x0060 /* Read digital input. */
-#define LP_RDCAPFLGC 0x0068 /* Read edges captured. */
-#define LP_RDINTSELC 0x006A /* Read interrupt enable register. */
-#define LP_RDEDGSELC 0x006C /* Read edge selection register. */
-#define LP_RDCAPSELC 0x006E /* Read capture enable register. */
+
+/* Digital I/O registers */
+#define LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */
+#define LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */
+#define LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */
+#define LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */
+#define LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */
+#define LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */
+#define LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */
+#define LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */
+#define LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */
/* Counter Registers (read/write): */
#define LP_CR0A 0x0000 /* 0A setup register. */
@@ -661,27 +642,27 @@
/* Bit field masks for CRA and CRB. */
-#define CRAMSK_INDXSRC_B ((uint16_t)(3 << CRABIT_INDXSRC_B))
-#define CRAMSK_CLKSRC_B ((uint16_t)(3 << CRABIT_CLKSRC_B))
-#define CRAMSK_INDXPOL_A ((uint16_t)(1 << CRABIT_INDXPOL_A))
-#define CRAMSK_LOADSRC_A ((uint16_t)(3 << CRABIT_LOADSRC_A))
-#define CRAMSK_CLKMULT_A ((uint16_t)(3 << CRABIT_CLKMULT_A))
-#define CRAMSK_INTSRC_A ((uint16_t)(3 << CRABIT_INTSRC_A))
-#define CRAMSK_CLKPOL_A ((uint16_t)(3 << CRABIT_CLKPOL_A))
-#define CRAMSK_INDXSRC_A ((uint16_t)(3 << CRABIT_INDXSRC_A))
-#define CRAMSK_CLKSRC_A ((uint16_t)(3 << CRABIT_CLKSRC_A))
-
-#define CRBMSK_INTRESETCMD ((uint16_t)(1 << CRBBIT_INTRESETCMD))
-#define CRBMSK_INTRESET_B ((uint16_t)(1 << CRBBIT_INTRESET_B))
-#define CRBMSK_INTRESET_A ((uint16_t)(1 << CRBBIT_INTRESET_A))
-#define CRBMSK_CLKENAB_A ((uint16_t)(1 << CRBBIT_CLKENAB_A))
-#define CRBMSK_INTSRC_B ((uint16_t)(3 << CRBBIT_INTSRC_B))
-#define CRBMSK_LATCHSRC ((uint16_t)(3 << CRBBIT_LATCHSRC))
-#define CRBMSK_LOADSRC_B ((uint16_t)(3 << CRBBIT_LOADSRC_B))
-#define CRBMSK_CLKMULT_B ((uint16_t)(3 << CRBBIT_CLKMULT_B))
-#define CRBMSK_CLKENAB_B ((uint16_t)(1 << CRBBIT_CLKENAB_B))
-#define CRBMSK_INDXPOL_B ((uint16_t)(1 << CRBBIT_INDXPOL_B))
-#define CRBMSK_CLKPOL_B ((uint16_t)(1 << CRBBIT_CLKPOL_B))
+#define CRAMSK_INDXSRC_B (3 << CRABIT_INDXSRC_B)
+#define CRAMSK_CLKSRC_B (3 << CRABIT_CLKSRC_B)
+#define CRAMSK_INDXPOL_A (1 << CRABIT_INDXPOL_A)
+#define CRAMSK_LOADSRC_A (3 << CRABIT_LOADSRC_A)
+#define CRAMSK_CLKMULT_A (3 << CRABIT_CLKMULT_A)
+#define CRAMSK_INTSRC_A (3 << CRABIT_INTSRC_A)
+#define CRAMSK_CLKPOL_A (3 << CRABIT_CLKPOL_A)
+#define CRAMSK_INDXSRC_A (3 << CRABIT_INDXSRC_A)
+#define CRAMSK_CLKSRC_A (3 << CRABIT_CLKSRC_A)
+
+#define CRBMSK_INTRESETCMD (1 << CRBBIT_INTRESETCMD)
+#define CRBMSK_INTRESET_B (1 << CRBBIT_INTRESET_B)
+#define CRBMSK_INTRESET_A (1 << CRBBIT_INTRESET_A)
+#define CRBMSK_CLKENAB_A (1 << CRBBIT_CLKENAB_A)
+#define CRBMSK_INTSRC_B (3 << CRBBIT_INTSRC_B)
+#define CRBMSK_LATCHSRC (3 << CRBBIT_LATCHSRC)
+#define CRBMSK_LOADSRC_B (3 << CRBBIT_LOADSRC_B)
+#define CRBMSK_CLKMULT_B (3 << CRBBIT_CLKMULT_B)
+#define CRBMSK_CLKENAB_B (1 << CRBBIT_CLKENAB_B)
+#define CRBMSK_INDXPOL_B (1 << CRBBIT_INDXPOL_B)
+#define CRBMSK_CLKPOL_B (1 << CRBBIT_CLKPOL_B)
#define CRBMSK_INTCTRL (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A | CRBMSK_INTRESET_B) /* Interrupt reset control bits. */
@@ -699,15 +680,15 @@
/* Bit field masks for standardized SETUP structure. */
-#define STDMSK_INTSRC ((uint16_t)(3 << STDBIT_INTSRC))
-#define STDMSK_LATCHSRC ((uint16_t)(3 << STDBIT_LATCHSRC))
-#define STDMSK_LOADSRC ((uint16_t)(3 << STDBIT_LOADSRC))
-#define STDMSK_INDXSRC ((uint16_t)(1 << STDBIT_INDXSRC))
-#define STDMSK_INDXPOL ((uint16_t)(1 << STDBIT_INDXPOL))
-#define STDMSK_CLKSRC ((uint16_t)(3 << STDBIT_CLKSRC))
-#define STDMSK_CLKPOL ((uint16_t)(1 << STDBIT_CLKPOL))
-#define STDMSK_CLKMULT ((uint16_t)(3 << STDBIT_CLKMULT))
-#define STDMSK_CLKENAB ((uint16_t)(1 << STDBIT_CLKENAB))
+#define STDMSK_INTSRC (3 << STDBIT_INTSRC)
+#define STDMSK_LATCHSRC (3 << STDBIT_LATCHSRC)
+#define STDMSK_LOADSRC (3 << STDBIT_LOADSRC)
+#define STDMSK_INDXSRC (1 << STDBIT_INDXSRC)
+#define STDMSK_INDXPOL (1 << STDBIT_INDXPOL)
+#define STDMSK_CLKSRC (3 << STDBIT_CLKSRC)
+#define STDMSK_CLKPOL (1 << STDBIT_CLKPOL)
+#define STDMSK_CLKMULT (3 << STDBIT_CLKMULT)
+#define STDMSK_CLKENAB (1 << STDBIT_CLKENAB)
struct bufferDMA {
dma_addr_t PhysicalBase;
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index e6177b48ccaf..8900086374db 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -31,8 +31,6 @@ Status: in development
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include "../comedidev.h"
#include <linux/delay.h>
@@ -72,7 +70,40 @@ struct serial_data {
unsigned long value;
};
-static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
+/*
+ * The configuration serial_data.value read from the device is
+ * a bitmask that defines specific options of a channel:
+ *
+ * 4:0 - the channel to configure
+ * 7:5 - the kind of channel
+ * 9:8 - the command used to configure the channel
+ *
+ * The remaining bits vary in use depending on the command:
+ *
+ * BITS 15:10 - the channel bits (maxdata)
+ * MIN/MAX 12:10 - the units multiplier for the scale
+ * 13 - the sign of the scale
+ * 33:14 - the base value for the range
+ */
+#define S2002_CFG_CHAN(x) ((x) & 0x1f)
+#define S2002_CFG_KIND(x) (((x) >> 5) & 0x7)
+#define S2002_CFG_KIND_INVALID 0
+#define S2002_CFG_KIND_DIGITAL_IN 1
+#define S2002_CFG_KIND_DIGITAL_OUT 2
+#define S2002_CFG_KIND_ANALOG_IN 3
+#define S2002_CFG_KIND_ANALOG_OUT 4
+#define S2002_CFG_KIND_ENCODER_IN 5
+#define S2002_CFG_CMD(x) (((x) >> 8) & 0x3)
+#define S2002_CFG_CMD_BITS 0
+#define S2002_CFG_CMD_MIN 1
+#define S2002_CFG_CMD_MAX 2
+#define S2002_CFG_BITS(x) (((x) >> 10) & 0x3f)
+#define S2002_CFG_UNITS(x) (((x) >> 10) & 0x7)
+#define S2002_CFG_SIGN(x) (((x) >> 13) & 0x1)
+#define S2002_CFG_BASE(x) (((x) >> 14) & 0xfffff)
+
+static long serial2002_tty_ioctl(struct file *f, unsigned op,
+ unsigned long param)
{
if (f->f_op->unlocked_ioctl)
return f->f_op->unlocked_ioctl(f, op, param);
@@ -80,39 +111,58 @@ static long tty_ioctl(struct file *f, unsigned op, unsigned long param)
return -ENOSYS;
}
-static int tty_write(struct file *f, unsigned char *buf, int count)
+static int serial2002_tty_write(struct file *f, unsigned char *buf, int count)
{
+ const char __user *p = (__force const char __user *)buf;
int result;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
f->f_pos = 0;
- result = f->f_op->write(f, buf, count, &f->f_pos);
+ result = f->f_op->write(f, p, count, &f->f_pos);
set_fs(oldfs);
return result;
}
-#if 0
-/*
- * On 2.6.26.3 this occaisonally gave me page faults, worked around by
- * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0
- */
-static int tty_available(struct file *f)
+static int serial2002_tty_readb(struct file *f, unsigned char *buf)
{
- long result = 0;
- mm_segment_t oldfs;
+ char __user *p = (__force char __user *)buf;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- tty_ioctl(f, FIONREAD, (unsigned long)&result);
- set_fs(oldfs);
- return result;
+ f->f_pos = 0;
+ return f->f_op->read(f, p, 1, &f->f_pos);
+}
+
+static void serial2002_tty_read_poll_wait(struct file *f, int timeout)
+{
+ struct poll_wqueues table;
+ struct timeval start, now;
+
+ do_gettimeofday(&start);
+ poll_initwait(&table);
+ while (1) {
+ long elapsed;
+ int mask;
+
+ mask = f->f_op->poll(f, &table.pt);
+ if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
+ POLLHUP | POLLERR)) {
+ break;
+ }
+ do_gettimeofday(&now);
+ elapsed = (1000000 * (now.tv_sec - start.tv_sec) +
+ now.tv_usec - start.tv_usec);
+ if (elapsed > timeout)
+ break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(((timeout - elapsed) * HZ) / 10000);
+ }
+ poll_freewait(&table);
}
-#endif
-static int tty_read(struct file *f, int timeout)
+static int serial2002_tty_read(struct file *f, int timeout)
{
+ unsigned char ch;
int result;
result = -1;
@@ -122,50 +172,19 @@ static int tty_read(struct file *f, int timeout)
oldfs = get_fs();
set_fs(KERNEL_DS);
if (f->f_op->poll) {
- struct poll_wqueues table;
- struct timeval start, now;
-
- do_gettimeofday(&start);
- poll_initwait(&table);
- while (1) {
- long elapsed;
- int mask;
-
- mask = f->f_op->poll(f, &table.pt);
- if (mask & (POLLRDNORM | POLLRDBAND | POLLIN |
- POLLHUP | POLLERR)) {
- break;
- }
- do_gettimeofday(&now);
- elapsed =
- (1000000 * (now.tv_sec - start.tv_sec) +
- now.tv_usec - start.tv_usec);
- if (elapsed > timeout)
- break;
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(((timeout -
- elapsed) * HZ) / 10000);
- }
- poll_freewait(&table);
- {
- unsigned char ch;
+ serial2002_tty_read_poll_wait(f, timeout);
- f->f_pos = 0;
- if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1)
- result = ch;
- }
+ if (serial2002_tty_readb(f, &ch) == 1)
+ result = ch;
} else {
/* Device does not support poll, busy wait */
int retries = 0;
while (1) {
- unsigned char ch;
-
retries++;
if (retries >= timeout)
break;
- f->f_pos = 0;
- if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) {
+ if (serial2002_tty_readb(f, &ch) == 1) {
result = ch;
break;
}
@@ -177,90 +196,76 @@ static int tty_read(struct file *f, int timeout)
return result;
}
-static void tty_setspeed(struct file *f, int speed)
+static void serial2002_tty_setspeed(struct file *f, int speed)
{
+ struct termios termios;
+ struct serial_struct serial;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
- {
- /* Set speed */
- struct termios settings;
-
- tty_ioctl(f, TCGETS, (unsigned long)&settings);
-/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
- settings.c_iflag = 0;
- settings.c_oflag = 0;
- settings.c_lflag = 0;
- settings.c_cflag = CLOCAL | CS8 | CREAD;
- settings.c_cc[VMIN] = 0;
- settings.c_cc[VTIME] = 0;
- switch (speed) {
- case 2400:{
- settings.c_cflag |= B2400;
- }
- break;
- case 4800:{
- settings.c_cflag |= B4800;
- }
- break;
- case 9600:{
- settings.c_cflag |= B9600;
- }
- break;
- case 19200:{
- settings.c_cflag |= B19200;
- }
- break;
- case 38400:{
- settings.c_cflag |= B38400;
- }
- break;
- case 57600:{
- settings.c_cflag |= B57600;
- }
- break;
- case 115200:{
- settings.c_cflag |= B115200;
- }
- break;
- default:{
- settings.c_cflag |= B9600;
- }
- break;
- }
- tty_ioctl(f, TCSETS, (unsigned long)&settings);
-/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */
- }
- {
- /* Set low latency */
- struct serial_struct settings;
- tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings);
- settings.flags |= ASYNC_LOW_LATENCY;
- tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings);
+ /* Set speed */
+ serial2002_tty_ioctl(f, TCGETS, (unsigned long)&termios);
+ termios.c_iflag = 0;
+ termios.c_oflag = 0;
+ termios.c_lflag = 0;
+ termios.c_cflag = CLOCAL | CS8 | CREAD;
+ termios.c_cc[VMIN] = 0;
+ termios.c_cc[VTIME] = 0;
+ switch (speed) {
+ case 2400:
+ termios.c_cflag |= B2400;
+ break;
+ case 4800:
+ termios.c_cflag |= B4800;
+ break;
+ case 9600:
+ termios.c_cflag |= B9600;
+ break;
+ case 19200:
+ termios.c_cflag |= B19200;
+ break;
+ case 38400:
+ termios.c_cflag |= B38400;
+ break;
+ case 57600:
+ termios.c_cflag |= B57600;
+ break;
+ case 115200:
+ termios.c_cflag |= B115200;
+ break;
+ default:
+ termios.c_cflag |= B9600;
+ break;
}
+ serial2002_tty_ioctl(f, TCSETS, (unsigned long)&termios);
+
+ /* Set low latency */
+ serial2002_tty_ioctl(f, TIOCGSERIAL, (unsigned long)&serial);
+ serial.flags |= ASYNC_LOW_LATENCY;
+ serial2002_tty_ioctl(f, TIOCSSERIAL, (unsigned long)&serial);
set_fs(oldfs);
}
-static void poll_digital(struct file *f, int channel)
+static void serial2002_poll_digital(struct file *f, int channel)
{
char cmd;
cmd = 0x40 | (channel & 0x1f);
- tty_write(f, &cmd, 1);
+ serial2002_tty_write(f, &cmd, 1);
}
-static void poll_channel(struct file *f, int channel)
+static void serial2002_poll_channel(struct file *f, int channel)
{
char cmd;
cmd = 0x60 | (channel & 0x1f);
- tty_write(f, &cmd, 1);
+ serial2002_tty_write(f, &cmd, 1);
}
-static struct serial_data serial_read(struct file *f, int timeout)
+static struct serial_data serial2002_read(struct file *f, int timeout)
{
struct serial_data result;
int length;
@@ -270,26 +275,23 @@ static struct serial_data serial_read(struct file *f, int timeout)
result.value = 0;
length = 0;
while (1) {
- int data = tty_read(f, timeout);
+ int data = serial2002_tty_read(f, timeout);
length++;
if (data < 0) {
- pr_err("Failed to read serial.\n");
break;
} else if (data & 0x80) {
result.value = (result.value << 7) | (data & 0x7f);
} else {
if (length == 1) {
switch ((data >> 5) & 0x03) {
- case 0:{
- result.value = 0;
- result.kind = is_digital;
- }
+ case 0:
+ result.value = 0;
+ result.kind = is_digital;
break;
- case 1:{
- result.value = 1;
- result.kind = is_digital;
- }
+ case 1:
+ result.value = 1;
+ result.kind = is_digital;
break;
}
} else {
@@ -305,12 +307,12 @@ static struct serial_data serial_read(struct file *f, int timeout)
}
-static void serial_write(struct file *f, struct serial_data data)
+static void serial2002_write(struct file *f, struct serial_data data)
{
if (data.kind == is_digital) {
unsigned char ch =
((data.value << 5) & 0x20) | (data.index & 0x1f);
- tty_write(f, &ch, 1);
+ serial2002_tty_write(f, &ch, 1);
} else {
unsigned char ch[6];
int i = 0;
@@ -334,319 +336,250 @@ static void serial_write(struct file *f, struct serial_data data)
i++;
ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f);
i++;
- tty_write(f, ch, i);
+ serial2002_tty_write(f, ch, i);
}
}
-static int serial_2002_open(struct comedi_device *dev)
+struct config_t {
+ short int kind;
+ short int bits;
+ int min;
+ int max;
+};
+
+static int serial2002_setup_subdevice(struct comedi_subdevice *s,
+ struct config_t *cfg,
+ struct serial2002_range_table_t *range,
+ unsigned char *mapping,
+ int kind)
{
- struct serial2002_private *devpriv = dev->private;
- int result;
- char port[20];
+ const struct comedi_lrange **range_table_list = NULL;
+ unsigned int *maxdata_list;
+ int j, chan;
- sprintf(port, "/dev/ttyS%d", devpriv->port);
- devpriv->tty = filp_open(port, O_RDWR, 0);
- if (IS_ERR(devpriv->tty)) {
- result = (int)PTR_ERR(devpriv->tty);
- dev_err(dev->class_dev, "file open error = %d\n", result);
- } else {
- struct config_t {
-
- short int kind;
- short int bits;
- int min;
- int max;
- };
-
- struct config_t *dig_in_config;
- struct config_t *dig_out_config;
- struct config_t *chan_in_config;
- struct config_t *chan_out_config;
- int i;
-
- result = 0;
- dig_in_config = kcalloc(32, sizeof(struct config_t),
- GFP_KERNEL);
- dig_out_config = kcalloc(32, sizeof(struct config_t),
- GFP_KERNEL);
- chan_in_config = kcalloc(32, sizeof(struct config_t),
- GFP_KERNEL);
- chan_out_config = kcalloc(32, sizeof(struct config_t),
- GFP_KERNEL);
- if (!dig_in_config || !dig_out_config
- || !chan_in_config || !chan_out_config) {
- result = -ENOMEM;
- goto err_alloc_configs;
+ for (chan = 0, j = 0; j < 32; j++) {
+ if (cfg[j].kind == kind)
+ chan++;
+ }
+ s->n_chan = chan;
+ s->maxdata = 0;
+ kfree(s->maxdata_list);
+ maxdata_list = kmalloc(sizeof(unsigned int) * s->n_chan, GFP_KERNEL);
+ if (!maxdata_list)
+ return -ENOMEM;
+ s->maxdata_list = maxdata_list;
+ kfree(s->range_table_list);
+ s->range_table = NULL;
+ s->range_table_list = NULL;
+ if (kind == 1 || kind == 2) {
+ s->range_table = &range_digital;
+ } else if (range) {
+ range_table_list =
+ kmalloc(sizeof(struct serial2002_range_table_t) *
+ s->n_chan, GFP_KERNEL);
+ if (!range_table_list)
+ return -ENOMEM;
+ s->range_table_list = range_table_list;
+ }
+ for (chan = 0, j = 0; j < 32; j++) {
+ if (cfg[j].kind == kind) {
+ if (mapping)
+ mapping[chan] = j;
+ if (range) {
+ range[j].length = 1;
+ range[j].range.min = cfg[j].min;
+ range[j].range.max = cfg[j].max;
+ range_table_list[chan] =
+ (const struct comedi_lrange *)&range[j];
+ }
+ maxdata_list[chan] = ((long long)1 << cfg[j].bits) - 1;
+ chan++;
}
+ }
+ return 0;
+}
- tty_setspeed(devpriv->tty, devpriv->speed);
- poll_channel(devpriv->tty, 31); /* Start reading configuration */
- while (1) {
- struct serial_data data;
+static int serial2002_setup_subdevs(struct comedi_device *dev)
+{
+ struct serial2002_private *devpriv = dev->private;
+ struct config_t *di_cfg;
+ struct config_t *do_cfg;
+ struct config_t *ai_cfg;
+ struct config_t *ao_cfg;
+ struct config_t *cfg;
+ struct comedi_subdevice *s;
+ int result = 0;
+ int i;
- data = serial_read(devpriv->tty, 1000);
- if (data.kind != is_channel || data.index != 31
- || !(data.value & 0xe0)) {
- break;
- } else {
- int command, channel, kind;
- struct config_t *cur_config = NULL;
-
- channel = data.value & 0x1f;
- kind = (data.value >> 5) & 0x7;
- command = (data.value >> 8) & 0x3;
- switch (kind) {
- case 1:{
- cur_config = dig_in_config;
- }
- break;
- case 2:{
- cur_config = dig_out_config;
- }
- break;
- case 3:{
- cur_config = chan_in_config;
- }
- break;
- case 4:{
- cur_config = chan_out_config;
- }
- break;
- case 5:{
- cur_config = chan_in_config;
- }
- break;
- }
+ /* Allocate the temporary structs to hold the configuration data */
+ di_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
+ do_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
+ ai_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
+ ao_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL);
+ if (!di_cfg || !do_cfg || !ai_cfg || !ao_cfg) {
+ result = -ENOMEM;
+ goto err_alloc_configs;
+ }
- if (cur_config) {
- cur_config[channel].kind = kind;
- switch (command) {
- case 0:{
- cur_config[channel].bits
- =
- (data.value >> 10) &
- 0x3f;
- }
- break;
- case 1:{
- int unit, sign, min;
- unit =
- (data.value >> 10) &
- 0x7;
- sign =
- (data.value >> 13) &
- 0x1;
- min =
- (data.value >> 14) &
- 0xfffff;
-
- switch (unit) {
- case 0:{
- min =
- min
- *
- 1000000;
- }
- break;
- case 1:{
- min =
- min
- *
- 1000;
- }
- break;
- case 2:{
- min =
- min
- * 1;
- }
- break;
- }
- if (sign)
- min = -min;
- cur_config[channel].min
- = min;
- }
- break;
- case 2:{
- int unit, sign, max;
- unit =
- (data.value >> 10) &
- 0x7;
- sign =
- (data.value >> 13) &
- 0x1;
- max =
- (data.value >> 14) &
- 0xfffff;
-
- switch (unit) {
- case 0:{
- max =
- max
- *
- 1000000;
- }
- break;
- case 1:{
- max =
- max
- *
- 1000;
- }
- break;
- case 2:{
- max =
- max
- * 1;
- }
- break;
- }
- if (sign)
- max = -max;
- cur_config[channel].max
- = max;
- }
- break;
- }
- }
- }
- }
- for (i = 0; i <= 4; i++) {
- /* Fill in subdev data */
- struct config_t *c;
- unsigned char *mapping = NULL;
- struct serial2002_range_table_t *range = NULL;
- int kind = 0;
-
- switch (i) {
- case 0:{
- c = dig_in_config;
- mapping = devpriv->digital_in_mapping;
- kind = 1;
- }
+ /* Read the configuration from the connected device */
+ serial2002_tty_setspeed(devpriv->tty, devpriv->speed);
+ serial2002_poll_channel(devpriv->tty, 31);
+ while (1) {
+ struct serial_data data;
+
+ data = serial2002_read(devpriv->tty, 1000);
+ if (data.kind != is_channel || data.index != 31 ||
+ S2002_CFG_KIND(data.value) == S2002_CFG_KIND_INVALID) {
+ break;
+ } else {
+ int channel = S2002_CFG_CHAN(data.value);
+ int range = S2002_CFG_BASE(data.value);
+
+ switch (S2002_CFG_KIND(data.value)) {
+ case S2002_CFG_KIND_DIGITAL_IN:
+ cfg = di_cfg;
break;
- case 1:{
- c = dig_out_config;
- mapping = devpriv->digital_out_mapping;
- kind = 2;
- }
+ case S2002_CFG_KIND_DIGITAL_OUT:
+ cfg = do_cfg;
break;
- case 2:{
- c = chan_in_config;
- mapping = devpriv->analog_in_mapping;
- range = devpriv->in_range;
- kind = 3;
- }
+ case S2002_CFG_KIND_ANALOG_IN:
+ cfg = ai_cfg;
break;
- case 3:{
- c = chan_out_config;
- mapping = devpriv->analog_out_mapping;
- range = devpriv->out_range;
- kind = 4;
- }
+ case S2002_CFG_KIND_ANALOG_OUT:
+ cfg = ao_cfg;
break;
- case 4:{
- c = chan_in_config;
- mapping = devpriv->encoder_in_mapping;
- range = devpriv->in_range;
- kind = 5;
- }
+ case S2002_CFG_KIND_ENCODER_IN:
+ cfg = ai_cfg;
break;
- default:{
- c = NULL;
- }
+ default:
+ cfg = NULL;
break;
}
- if (c) {
- struct comedi_subdevice *s;
- const struct comedi_lrange **range_table_list =
- NULL;
- unsigned int *maxdata_list;
- int j, chan;
-
- for (chan = 0, j = 0; j < 32; j++) {
- if (c[j].kind == kind)
- chan++;
- }
- s = &dev->subdevices[i];
- s->n_chan = chan;
- s->maxdata = 0;
- kfree(s->maxdata_list);
- s->maxdata_list = maxdata_list =
- kmalloc(sizeof(unsigned int) * s->n_chan,
- GFP_KERNEL);
- if (!s->maxdata_list)
- break; /* error handled below */
- kfree(s->range_table_list);
- s->range_table = NULL;
- s->range_table_list = NULL;
- if (kind == 1 || kind == 2) {
- s->range_table = &range_digital;
- } else if (range) {
- s->range_table_list = range_table_list =
- kmalloc(sizeof
- (struct
- serial2002_range_table_t) *
- s->n_chan, GFP_KERNEL);
- if (!s->range_table_list)
- break; /* err handled below */
- }
- for (chan = 0, j = 0; j < 32; j++) {
- if (c[j].kind == kind) {
- if (mapping)
- mapping[chan] = j;
- if (range) {
- range[j].length = 1;
- range[j].range.min =
- c[j].min;
- range[j].range.max =
- c[j].max;
- range_table_list[chan] =
- (const struct
- comedi_lrange *)
- &range[j];
- }
- maxdata_list[chan] =
- ((long long)1 << c[j].bits)
- - 1;
- chan++;
- }
+ if (!cfg)
+ continue; /* unknown kind, skip it */
+
+ cfg[channel].kind = S2002_CFG_KIND(data.value);
+
+ switch (S2002_CFG_CMD(data.value)) {
+ case S2002_CFG_CMD_BITS:
+ cfg[channel].bits = S2002_CFG_BITS(data.value);
+ break;
+ case S2002_CFG_CMD_MIN:
+ case S2002_CFG_CMD_MAX:
+ switch (S2002_CFG_UNITS(data.value)) {
+ case 0:
+ range *= 1000000;
+ break;
+ case 1:
+ range *= 1000;
+ break;
+ case 2:
+ range *= 1;
+ break;
}
+ if (S2002_CFG_SIGN(data.value))
+ range = -range;
+ if (S2002_CFG_CMD(data.value) ==
+ S2002_CFG_CMD_MIN)
+ cfg[channel].min = range;
+ else
+ cfg[channel].max = range;
+ break;
}
}
- if (i <= 4) {
- /* Failed to allocate maxdata_list or range_table_list
- * for a subdevice that needed it. */
- result = -ENOMEM;
- for (i = 0; i <= 4; i++) {
- struct comedi_subdevice *s;
-
- s = &dev->subdevices[i];
- kfree(s->maxdata_list);
- s->maxdata_list = NULL;
- kfree(s->range_table_list);
- s->range_table_list = NULL;
- }
+ }
+
+ /* Fill in subdevice data */
+ for (i = 0; i <= 4; i++) {
+ unsigned char *mapping = NULL;
+ struct serial2002_range_table_t *range = NULL;
+ int kind = 0;
+
+ s = &dev->subdevices[i];
+
+ switch (i) {
+ case 0:
+ cfg = di_cfg;
+ mapping = devpriv->digital_in_mapping;
+ kind = S2002_CFG_KIND_DIGITAL_IN;
+ break;
+ case 1:
+ cfg = do_cfg;
+ mapping = devpriv->digital_out_mapping;
+ kind = S2002_CFG_KIND_DIGITAL_OUT;
+ break;
+ case 2:
+ cfg = ai_cfg;
+ mapping = devpriv->analog_in_mapping;
+ range = devpriv->in_range;
+ kind = S2002_CFG_KIND_ANALOG_IN;
+ break;
+ case 3:
+ cfg = ao_cfg;
+ mapping = devpriv->analog_out_mapping;
+ range = devpriv->out_range;
+ kind = S2002_CFG_KIND_ANALOG_OUT;
+ break;
+ case 4:
+ cfg = ai_cfg;
+ mapping = devpriv->encoder_in_mapping;
+ range = devpriv->in_range;
+ kind = S2002_CFG_KIND_ENCODER_IN;
+ break;
}
+ if (serial2002_setup_subdevice(s, cfg, range, mapping, kind))
+ break; /* err handled below */
+ }
+ if (i <= 4) {
+ /*
+ * Failed to allocate maxdata_list or range_table_list
+ * for a subdevice that needed it.
+ */
+ result = -ENOMEM;
+ for (i = 0; i <= 4; i++) {
+ s = &dev->subdevices[i];
+ kfree(s->maxdata_list);
+ s->maxdata_list = NULL;
+ kfree(s->range_table_list);
+ s->range_table_list = NULL;
+ }
+ }
+
err_alloc_configs:
- kfree(dig_in_config);
- kfree(dig_out_config);
- kfree(chan_in_config);
- kfree(chan_out_config);
-
- if (result) {
- if (devpriv->tty) {
- filp_close(devpriv->tty, NULL);
- devpriv->tty = NULL;
- }
+ kfree(di_cfg);
+ kfree(do_cfg);
+ kfree(ai_cfg);
+ kfree(ao_cfg);
+
+ if (result) {
+ if (devpriv->tty) {
+ filp_close(devpriv->tty, NULL);
+ devpriv->tty = NULL;
}
}
+
+ return result;
+}
+
+static int serial2002_open(struct comedi_device *dev)
+{
+ struct serial2002_private *devpriv = dev->private;
+ int result;
+ char port[20];
+
+ sprintf(port, "/dev/ttyS%d", devpriv->port);
+ devpriv->tty = filp_open(port, O_RDWR, 0);
+ if (IS_ERR(devpriv->tty)) {
+ result = (int)PTR_ERR(devpriv->tty);
+ dev_err(dev->class_dev, "file open error = %d\n", result);
+ } else {
+ result = serial2002_setup_subdevs(dev);
+ }
return result;
}
-static void serial_2002_close(struct comedi_device *dev)
+static void serial2002_close(struct comedi_device *dev)
{
struct serial2002_private *devpriv = dev->private;
@@ -654,9 +587,10 @@ static void serial_2002_close(struct comedi_device *dev)
filp_close(devpriv->tty, NULL);
}
-static int serial2002_di_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_di_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -666,9 +600,9 @@ static int serial2002_di_rinsn(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
struct serial_data read;
- poll_digital(devpriv->tty, chan);
+ serial2002_poll_digital(devpriv->tty, chan);
while (1) {
- read = serial_read(devpriv->tty, 1000);
+ read = serial2002_read(devpriv->tty, 1000);
if (read.kind != is_digital || read.index == chan)
break;
}
@@ -677,9 +611,10 @@ static int serial2002_di_rinsn(struct comedi_device *dev,
return n;
}
-static int serial2002_do_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_do_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -692,14 +627,15 @@ static int serial2002_do_winsn(struct comedi_device *dev,
write.kind = is_digital;
write.index = chan;
write.value = data[n];
- serial_write(devpriv->tty, write);
+ serial2002_write(devpriv->tty, write);
}
return n;
}
-static int serial2002_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -709,9 +645,9 @@ static int serial2002_ai_rinsn(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
struct serial_data read;
- poll_channel(devpriv->tty, chan);
+ serial2002_poll_channel(devpriv->tty, chan);
while (1) {
- read = serial_read(devpriv->tty, 1000);
+ read = serial2002_read(devpriv->tty, 1000);
if (read.kind != is_channel || read.index == chan)
break;
}
@@ -720,9 +656,10 @@ static int serial2002_ai_rinsn(struct comedi_device *dev,
return n;
}
-static int serial2002_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -735,15 +672,16 @@ static int serial2002_ao_winsn(struct comedi_device *dev,
write.kind = is_channel;
write.index = chan;
write.value = data[n];
- serial_write(devpriv->tty, write);
+ serial2002_write(devpriv->tty, write);
devpriv->ao_readback[chan] = data[n];
}
return n;
}
-static int serial2002_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -755,9 +693,10 @@ static int serial2002_ao_rinsn(struct comedi_device *dev,
return n;
}
-static int serial2002_ei_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+static int serial2002_encoder_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct serial2002_private *devpriv = dev->private;
int n;
@@ -767,9 +706,9 @@ static int serial2002_ei_rinsn(struct comedi_device *dev,
for (n = 0; n < insn->n; n++) {
struct serial_data read;
- poll_channel(devpriv->tty, chan);
+ serial2002_poll_channel(devpriv->tty, chan);
while (1) {
- read = serial_read(devpriv->tty, 1000);
+ read = serial2002_read(devpriv->tty, 1000);
if (read.kind != is_channel || read.index == chan)
break;
}
@@ -785,20 +724,13 @@ static int serial2002_attach(struct comedi_device *dev,
struct comedi_subdevice *s;
int ret;
- dev_dbg(dev->class_dev, "serial2002: attach\n");
- dev->board_name = dev->driver->driver_name;
-
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
if (!devpriv)
return -ENOMEM;
dev->private = devpriv;
- dev->open = serial_2002_open;
- dev->close = serial_2002_close;
devpriv->port = it->options[0];
devpriv->speed = it->options[1];
- dev_dbg(dev->class_dev, "/dev/ttyS%d @ %d\n", devpriv->port,
- devpriv->speed);
ret = comedi_alloc_subdevices(dev, 5);
if (ret)
@@ -806,51 +738,54 @@ static int serial2002_attach(struct comedi_device *dev,
/* digital input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 0;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_read = &serial2002_di_rinsn;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 0;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_read = serial2002_di_insn_read;
/* digital output subdevice */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITEABLE;
- s->n_chan = 0;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_write = &serial2002_do_winsn;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 0;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_write = serial2002_do_insn_write;
/* analog input subdevice */
s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND;
- s->n_chan = 0;
- s->maxdata = 1;
- s->range_table = NULL;
- s->insn_read = &serial2002_ai_rinsn;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND;
+ s->n_chan = 0;
+ s->maxdata = 1;
+ s->range_table = NULL;
+ s->insn_read = serial2002_ai_insn_read;
/* analog output subdevice */
s = &dev->subdevices[3];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE;
- s->n_chan = 0;
- s->maxdata = 1;
- s->range_table = NULL;
- s->insn_write = &serial2002_ao_winsn;
- s->insn_read = &serial2002_ao_rinsn;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE;
+ s->n_chan = 0;
+ s->maxdata = 1;
+ s->range_table = NULL;
+ s->insn_write = serial2002_ao_insn_write;
+ s->insn_read = serial2002_ao_insn_read;
/* encoder input subdevice */
s = &dev->subdevices[4];
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
- s->n_chan = 0;
- s->maxdata = 1;
- s->range_table = NULL;
- s->insn_read = &serial2002_ei_rinsn;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
+ s->n_chan = 0;
+ s->maxdata = 1;
+ s->range_table = NULL;
+ s->insn_read = serial2002_encoder_insn_read;
+
+ dev->open = serial2002_open;
+ dev->close = serial2002_close;
- return 1;
+ return 0;
}
static void serial2002_detach(struct comedi_device *dev)
@@ -858,7 +793,7 @@ static void serial2002_detach(struct comedi_device *dev)
struct comedi_subdevice *s;
int i;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
kfree(s->maxdata_list);
kfree(s->range_table_list);
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index cb83f6ae48b9..dbc8c54d6da7 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -90,29 +90,30 @@ Configuration Options:
* boards in this way is optional, and completely driver-dependent.
* Some drivers use arrays such as this, other do not.
*/
+enum skel_boardid {
+ BOARD_SKEL100,
+ BOARD_SKEL200,
+};
+
struct skel_board {
const char *name;
- unsigned int devid;
int ai_chans;
int ai_bits;
int have_dio;
};
static const struct skel_board skel_boards[] = {
- {
- .name = "skel-100",
- .devid = 0x100,
- .ai_chans = 16,
- .ai_bits = 12,
- .have_dio = 1,
- },
- {
- .name = "skel-200",
- .devid = 0x200,
- .ai_chans = 8,
- .ai_bits = 16,
- .have_dio = 0,
- },
+ [BOARD_SKEL100] = {
+ .name = "skel-100",
+ .ai_chans = 16,
+ .ai_bits = 12,
+ .have_dio = 1,
+ },
+ [BOARD_SKEL200] = {
+ .name = "skel-200",
+ .ai_chans = 8,
+ .ai_bits = 16,
+ },
};
/* this structure is for data unique to this hardware driver. If
@@ -394,22 +395,6 @@ static int skel_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
-static const struct skel_board *skel_find_pci_board(struct pci_dev *pcidev)
-{
- unsigned int i;
-
-/*
- * This example code assumes all the entries in skel_boards[] are PCI boards
- * and all use the same PCI vendor ID. If skel_boards[] contains a mixture
- * of PCI and non-PCI boards, this loop should skip over the non-PCI boards.
- */
- for (i = 0; i < ARRAY_SIZE(skel_boards); i++)
- if (/* skel_boards[i].bustype == pci_bustype && */
- pcidev->device == skel_boards[i].devid)
- return &skel_boards[i];
- return NULL;
-}
-
/*
* Handle common part of skel_attach() and skel_auto_attach().
*/
@@ -496,10 +481,12 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
thisboard = comedi_board(dev);
-/*
- * Initialize dev->board_name.
- */
- dev->board_name = thisboard->name;
+ /*
+ * The dev->board_name is initialized by the comedi core before
+ * calling the (*attach) function. It can be optionally set by
+ * the driver if additional probing has been done.
+ */
+ /* dev->board_name = thisboard->name; */
/* Allocate the private data */
devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
@@ -541,16 +528,13 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* comedi_usb_auto_config(), etc.) to handle devices that can be attached
* to the Comedi core automatically without the COMEDI_DEVCONFIG ioctl.
*
- * The context parameter is usually unused, but if the driver called
- * comedi_auto_config() directly instead of the comedi_pci_auto_config()
- * wrapper function, this will be a copy of the context passed to
- * comedi_auto_config().
+ * The context parameter is driver dependent.
*/
static int skel_auto_attach(struct comedi_device *dev,
- unsigned long context)
+ unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct skel_board *thisboard;
+ const struct skel_board *thisboard = NULL;
struct skel_private *devpriv;
int ret;
@@ -558,12 +542,18 @@ static int skel_auto_attach(struct comedi_device *dev,
if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS))
return -EINVAL;
- /* Find a matching board in skel_boards[]. */
- thisboard = skel_find_pci_board(pcidev);
- if (!thisboard) {
- dev_err(dev->class_dev, "BUG! cannot determine board type!\n");
- return -EINVAL;
- }
+ /*
+ * In this example, the _auto_attach is for a PCI device.
+ *
+ * The 'context' passed to this function is the id->driver_data
+ * associated with the PCI device found in the id_table during
+ * the modprobe. This 'context' is the index of the entry in
+ * skel_boards[i] that contains the boardinfo for the PCI device.
+ */
+ if (context < ARRAY_SIZE(skel_boards))
+ thisboard = &skel_boards[context];
+ if (!thisboard)
+ return -ENODEV;
/*
* Point the struct comedi_device to the matching board info
@@ -579,7 +569,7 @@ static int skel_auto_attach(struct comedi_device *dev,
dev->private = devpriv;
/* Enable the PCI device. */
- ret = comedi_pci_enable(pcidev, dev->board_name);
+ ret = comedi_pci_enable(dev);
if (ret)
return ret;
@@ -618,7 +608,6 @@ static void skel_detach(struct comedi_device *dev)
{
const struct skel_board *thisboard = comedi_board(dev);
struct skel_private *devpriv = dev->private;
- struct pci_dev *pcidev = comedi_to_pci_dev(dev);
if (!thisboard || !devpriv)
return;
@@ -638,17 +627,17 @@ static void skel_detach(struct comedi_device *dev)
* If PCI device enabled by _auto_attach() (or _attach()),
* disable it here.
*/
- if (pcidev && dev->iobase)
- comedi_pci_disable(pcidev);
+ comedi_pci_disable(dev);
} else {
/*
* ISA board
*
- * If I/O regions successfully requested by _attach(),
- * release them here.
+ * Release the first I/O region requested during the
+ * _attach(). This is safe to call even if the request
+ * failed. If any additional I/O regions are requested
+ * they need to be released by the driver.
*/
- if (dev->iobase)
- release_region(dev->iobase, SKEL_SIZE);
+ comedi_legacy_detach(dev);
}
}
@@ -689,28 +678,33 @@ static struct comedi_driver skel_driver = {
#ifdef CONFIG_COMEDI_PCI_DRIVERS
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-#define PCI_VENDOR_ID_SKEL 0xdafe
+static int skel_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ return comedi_pci_auto_config(dev, &skel_driver, id->driver_data);
+}
+
+/*
+ * Please add your PCI vendor ID to comedidev.h, and it will
+ * be forwarded upstream.
+ */
+#define PCI_VENDOR_ID_SKEL 0xdafe
+
+/*
+ * This is used by modprobe to translate PCI IDs to drivers.
+ * Should only be used for PCI and ISA-PnP devices
+ */
static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0100) },
- { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0200) },
+ { PCI_VDEVICE(SKEL, 0x0100), BOARD_SKEL100 },
+ { PCI_VDEVICE(SKEL, 0x0200), BOARD_SKEL200 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skel_pci_table);
-static int skel_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, &skel_driver);
-}
-
static struct pci_driver skel_pci_driver = {
- .name = "dummy",
- .id_table = skel_pci_table,
- .probe = &skel_pci_probe,
+ .name = "dummy",
+ .id_table = skel_pci_table,
+ .probe = skel_pci_probe,
.remove = comedi_pci_auto_unconfig,
};
module_comedi_pci_driver(skel_driver, skel_pci_driver);
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index afa4016f906a..a76df092a57b 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -167,8 +167,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
int ret;
- dev->board_name = dev->driver->driver_name;
-
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index 74b974bf1032..0c243477cbe5 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -367,24 +367,24 @@ static int unioxx5_insn_config(struct comedi_device *dev,
}
/* initializing subdevice with given address */
-static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
- int subdev_iobase, int minor)
+static int __unioxx5_subdev_init(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ int iobase)
{
struct unioxx5_subd_priv *usp;
int i, to, ndef_flag = 0;
-
- if (!request_region(subdev_iobase, UNIOXX5_SIZE, DRIVER_NAME)) {
- dev_err(subdev->class_dev,
- "comedi%d: I/O port conflict\n", minor);
- return -EIO;
- }
+ int ret;
usp = kzalloc(sizeof(*usp), GFP_KERNEL);
if (usp == NULL)
- return -1;
+ return -ENOMEM;
- usp->usp_iobase = subdev_iobase;
- dev_info(subdev->class_dev, "comedi%d: |", minor);
+ ret = __comedi_request_region(dev, iobase, UNIOXX5_SIZE);
+ if (ret) {
+ kfree(usp);
+ return ret;
+ }
+ usp->usp_iobase = iobase;
/* defining modules types */
for (i = 0; i < 12; i++) {
@@ -392,14 +392,14 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
__unioxx5_analog_config(usp, i * 2);
/* sends channel number to card */
- outb(i + 1, subdev_iobase + 5);
- outb('H', subdev_iobase + 6); /* requests EEPROM world */
- while (!(inb(subdev_iobase + 0) & TxBE))
+ outb(i + 1, iobase + 5);
+ outb('H', iobase + 6); /* requests EEPROM world */
+ while (!(inb(iobase + 0) & TxBE))
; /* waits while writting will be allowed */
- outb(0, subdev_iobase + 6);
+ outb(0, iobase + 6);
/* waits while reading of two bytes will be allowed */
- while (!(inb(subdev_iobase + 0) & Rx2CA)) {
+ while (!(inb(iobase + 0) & Rx2CA)) {
if (--to <= 0) {
ndef_flag = 1;
break;
@@ -410,25 +410,22 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
usp->usp_module_type[i] = 0;
ndef_flag = 0;
} else
- usp->usp_module_type[i] = inb(subdev_iobase + 6);
+ usp->usp_module_type[i] = inb(iobase + 6);
- printk(" [%d] 0x%02x |", i, usp->usp_module_type[i]);
udelay(1);
}
- printk("\n");
-
/* initial subdevice for digital or analog i/o */
- subdev->type = COMEDI_SUBD_DIO;
- subdev->private = usp;
- subdev->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- subdev->n_chan = UNIOXX5_NUM_OF_CHANS;
- subdev->maxdata = 0xFFF;
- subdev->range_table = &range_digital;
- subdev->insn_read = unioxx5_subdev_read;
- subdev->insn_write = unioxx5_subdev_write;
+ s->type = COMEDI_SUBD_DIO;
+ s->private = usp;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = UNIOXX5_NUM_OF_CHANS;
+ s->maxdata = 0xFFF;
+ s->range_table = &range_digital;
+ s->insn_read = unioxx5_subdev_read;
+ s->insn_write = unioxx5_subdev_write;
/* for digital modules only!!! */
- subdev->insn_config = unioxx5_insn_config;
+ s->insn_config = unioxx5_insn_config;
return 0;
}
@@ -436,13 +433,13 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
static int unioxx5_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
+ struct comedi_subdevice *s;
int iobase, i, n_subd;
int id, num, ba;
int ret;
iobase = it->options[0];
- dev->board_name = DRIVER_NAME;
dev->iobase = iobase;
iobase += UNIOXX5_SUBDEV_BASE;
@@ -470,9 +467,10 @@ static int unioxx5_attach(struct comedi_device *dev,
/* initializing each of for same subdevices */
for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
- if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
- dev->minor) < 0)
- return -1;
+ s = &dev->subdevices[i];
+ ret = __unioxx5_subdev_init(dev, s, iobase);
+ if (ret)
+ return ret;
}
return 0;
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 6aac1f60bc42..6f5da67e26cb 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -56,7 +56,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
* functions firmware upload is by fxload and no longer by comedi (due to
* enumeration)
* 0.97: USB IDs received, adjusted table
- * 0.98: SMP, locking, memroy alloc: moved all usb memory alloc
+ * 0.98: SMP, locking, memory alloc: moved all usb memory alloc
* to the usb subsystem and moved all comedi related memory
* alloc to comedi.
* | kernel | registration | usbdux-usb | usbdux-comedi | comedi |
@@ -250,26 +250,26 @@ struct usbduxsub {
/* pointer to the usb-device */
struct usb_device *usbdev;
/* actual number of in-buffers */
- int numOfInBuffers;
+ int num_in_buffers;
/* actual number of out-buffers */
- int numOfOutBuffers;
+ int num_out_buffers;
/* ISO-transfer handling: buffers */
- struct urb **urbIn;
- struct urb **urbOut;
+ struct urb **urb_in;
+ struct urb **urb_out;
/* pwm-transfer handling */
- struct urb *urbPwm;
+ struct urb *urb_pwm;
/* PWM period */
- unsigned int pwmPeriod;
+ unsigned int pwm_period;
/* PWM internal delay for the GPIF in the FX2 */
- int8_t pwmDelay;
+ int8_t pwn_delay;
/* size of the PWM buffer which holds the bit pattern */
- int sizePwmBuf;
+ int size_pwm_buf;
/* input buffer for the ISO-transfer */
- int16_t *inBuffer;
+ int16_t *in_buffer;
/* input buffer for single insn */
- int16_t *insnBuffer;
+ int16_t *insn_buffer;
/* output buffer for single DA outputs */
- int16_t *outBuffer;
+ int16_t *out_buffer;
/* interface number */
int ifnum;
/* interface structure in 2.6 */
@@ -319,17 +319,17 @@ static DEFINE_SEMAPHORE(start_stop_sem);
* Stops the data acquision
* It should be safe to call this function from any context
*/
-static int usbduxsub_unlink_InURBs(struct usbduxsub *usbduxsub_tmp)
+static int usbduxsub_unlink_inurbs(struct usbduxsub *usbduxsub_tmp)
{
int i = 0;
int err = 0;
- if (usbduxsub_tmp && usbduxsub_tmp->urbIn) {
- for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
- if (usbduxsub_tmp->urbIn[i]) {
+ if (usbduxsub_tmp && usbduxsub_tmp->urb_in) {
+ for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
+ if (usbduxsub_tmp->urb_in[i]) {
/* We wait here until all transfers have been
* cancelled. */
- usb_kill_urb(usbduxsub_tmp->urbIn[i]);
+ usb_kill_urb(usbduxsub_tmp->urb_in[i]);
}
dev_dbg(&usbduxsub_tmp->interface->dev,
"comedi: usbdux: unlinked InURB %d, err=%d\n",
@@ -356,7 +356,7 @@ static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
if (do_unlink) {
/* stop aquistion */
- ret = usbduxsub_unlink_InURBs(this_usbduxsub);
+ ret = usbduxsub_unlink_inurbs(this_usbduxsub);
}
this_usbduxsub->ai_cmd_running = 0;
@@ -394,7 +394,7 @@ static int usbdux_ai_cancel(struct comedi_device *dev,
}
/* analogue IN - interrupt service routine */
-static void usbduxsub_ai_IsocIrq(struct urb *urb)
+static void usbduxsub_ai_isoc_irq(struct urb *urb)
{
int i, err, n;
struct usbduxsub *this_usbduxsub;
@@ -412,7 +412,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
switch (urb->status) {
case 0:
/* copy the result in the transfer buffer */
- memcpy(this_usbduxsub->inBuffer,
+ memcpy(this_usbduxsub->in_buffer,
urb->transfer_buffer, SIZEINBUF);
break;
case -EILSEQ:
@@ -517,11 +517,11 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) {
err = comedi_buf_put
(s->async,
- le16_to_cpu(this_usbduxsub->inBuffer[i]) ^ 0x800);
+ le16_to_cpu(this_usbduxsub->in_buffer[i]) ^ 0x800);
} else {
err = comedi_buf_put
(s->async,
- le16_to_cpu(this_usbduxsub->inBuffer[i]));
+ le16_to_cpu(this_usbduxsub->in_buffer[i]));
}
if (unlikely(err == 0)) {
/* buffer overflow */
@@ -534,15 +534,15 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
comedi_event(this_usbduxsub->comedidev, s);
}
-static int usbduxsub_unlink_OutURBs(struct usbduxsub *usbduxsub_tmp)
+static int usbduxsub_unlink_outurbs(struct usbduxsub *usbduxsub_tmp)
{
int i = 0;
int err = 0;
- if (usbduxsub_tmp && usbduxsub_tmp->urbOut) {
- for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
- if (usbduxsub_tmp->urbOut[i])
- usb_kill_urb(usbduxsub_tmp->urbOut[i]);
+ if (usbduxsub_tmp && usbduxsub_tmp->urb_out) {
+ for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
+ if (usbduxsub_tmp->urb_out[i])
+ usb_kill_urb(usbduxsub_tmp->urb_out[i]);
dev_dbg(&usbduxsub_tmp->interface->dev,
"comedi: usbdux: unlinked OutURB %d: res=%d\n",
@@ -564,7 +564,7 @@ static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n");
if (do_unlink)
- ret = usbduxsub_unlink_OutURBs(this_usbduxsub);
+ ret = usbduxsub_unlink_outurbs(this_usbduxsub);
this_usbduxsub->ao_cmd_running = 0;
@@ -593,7 +593,7 @@ static int usbdux_ao_cancel(struct comedi_device *dev,
return res;
}
-static void usbduxsub_ao_IsocIrq(struct urb *urb)
+static void usbduxsub_ao_isoc_irq(struct urb *urb)
{
int i, ret;
int8_t *datap;
@@ -798,7 +798,7 @@ static int usbduxsub_stop(struct usbduxsub *usbduxsub)
static int usbduxsub_upload(struct usbduxsub *usbduxsub,
uint8_t *local_transfer_buffer,
- unsigned int startAddr, unsigned int len)
+ unsigned int start_addr, unsigned int len)
{
int errcode;
@@ -809,7 +809,7 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub,
/* bmRequestType */
VENDOR_DIR_OUT,
/* value */
- startAddr,
+ start_addr,
/* index */
0x0000,
/* our local safe buffer */
@@ -828,24 +828,24 @@ static int usbduxsub_upload(struct usbduxsub *usbduxsub,
#define FIRMWARE_MAX_LEN 0x2000
-static int firmwareUpload(struct usbduxsub *usbduxsub,
- const u8 *firmwareBinary, int sizeFirmware)
+static int firmware_upload(struct usbduxsub *usbduxsub,
+ const u8 *firmware_binary, int size_firmware)
{
int ret;
- uint8_t *fwBuf;
+ uint8_t *fw_buf;
- if (!firmwareBinary)
+ if (!firmware_binary)
return 0;
- if (sizeFirmware > FIRMWARE_MAX_LEN) {
+ if (size_firmware > FIRMWARE_MAX_LEN) {
dev_err(&usbduxsub->interface->dev,
"usbdux firmware binary it too large for FX2.\n");
return -ENOMEM;
}
/* we generate a local buffer for the firmware */
- fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL);
- if (!fwBuf) {
+ fw_buf = kmemdup(firmware_binary, size_firmware, GFP_KERNEL);
+ if (!fw_buf) {
dev_err(&usbduxsub->interface->dev,
"comedi_: mem alloc for firmware failed\n");
return -ENOMEM;
@@ -855,81 +855,81 @@ static int firmwareUpload(struct usbduxsub *usbduxsub,
if (ret < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: can not stop firmware\n");
- kfree(fwBuf);
+ kfree(fw_buf);
return ret;
}
- ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware);
+ ret = usbduxsub_upload(usbduxsub, fw_buf, 0, size_firmware);
if (ret < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: firmware upload failed\n");
- kfree(fwBuf);
+ kfree(fw_buf);
return ret;
}
ret = usbduxsub_start(usbduxsub);
if (ret < 0) {
dev_err(&usbduxsub->interface->dev,
"comedi_: can not start firmware\n");
- kfree(fwBuf);
+ kfree(fw_buf);
return ret;
}
- kfree(fwBuf);
+ kfree(fw_buf);
return 0;
}
-static int usbduxsub_submit_InURBs(struct usbduxsub *usbduxsub)
+static int usbduxsub_submit_inurbs(struct usbduxsub *usbduxsub)
{
- int i, errFlag;
+ int i, err_flag;
if (!usbduxsub)
return -EFAULT;
/* Submit all URBs and start the transfer on the bus */
- for (i = 0; i < usbduxsub->numOfInBuffers; i++) {
+ for (i = 0; i < usbduxsub->num_in_buffers; i++) {
/* in case of a resubmission after an unlink... */
- usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval;
- usbduxsub->urbIn[i]->context = usbduxsub->comedidev;
- usbduxsub->urbIn[i]->dev = usbduxsub->usbdev;
- usbduxsub->urbIn[i]->status = 0;
- usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP;
+ usbduxsub->urb_in[i]->interval = usbduxsub->ai_interval;
+ usbduxsub->urb_in[i]->context = usbduxsub->comedidev;
+ usbduxsub->urb_in[i]->dev = usbduxsub->usbdev;
+ usbduxsub->urb_in[i]->status = 0;
+ usbduxsub->urb_in[i]->transfer_flags = URB_ISO_ASAP;
dev_dbg(&usbduxsub->interface->dev,
"comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n",
usbduxsub->comedidev->minor, i,
- (usbduxsub->urbIn[i]->context),
- (usbduxsub->urbIn[i]->dev),
- (usbduxsub->urbIn[i]->interval));
- errFlag = usb_submit_urb(usbduxsub->urbIn[i], GFP_ATOMIC);
- if (errFlag) {
+ (usbduxsub->urb_in[i]->context),
+ (usbduxsub->urb_in[i]->dev),
+ (usbduxsub->urb_in[i]->interval));
+ err_flag = usb_submit_urb(usbduxsub->urb_in[i], GFP_ATOMIC);
+ if (err_flag) {
dev_err(&usbduxsub->interface->dev,
"comedi_: ai: usb_submit_urb(%d) error %d\n",
- i, errFlag);
- return errFlag;
+ i, err_flag);
+ return err_flag;
}
}
return 0;
}
-static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub)
+static int usbduxsub_submit_outurbs(struct usbduxsub *usbduxsub)
{
- int i, errFlag;
+ int i, err_flag;
if (!usbduxsub)
return -EFAULT;
- for (i = 0; i < usbduxsub->numOfOutBuffers; i++) {
+ for (i = 0; i < usbduxsub->num_out_buffers; i++) {
dev_dbg(&usbduxsub->interface->dev,
"comedi_: submitting out-urb[%d]\n", i);
/* in case of a resubmission after an unlink... */
- usbduxsub->urbOut[i]->context = usbduxsub->comedidev;
- usbduxsub->urbOut[i]->dev = usbduxsub->usbdev;
- usbduxsub->urbOut[i]->status = 0;
- usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP;
- errFlag = usb_submit_urb(usbduxsub->urbOut[i], GFP_ATOMIC);
- if (errFlag) {
+ usbduxsub->urb_out[i]->context = usbduxsub->comedidev;
+ usbduxsub->urb_out[i]->dev = usbduxsub->usbdev;
+ usbduxsub->urb_out[i]->status = 0;
+ usbduxsub->urb_out[i]->transfer_flags = URB_ISO_ASAP;
+ err_flag = usb_submit_urb(usbduxsub->urb_out[i], GFP_ATOMIC);
+ if (err_flag) {
dev_err(&usbduxsub->interface->dev,
"comedi_: ao: usb_submit_urb(%d) error %d\n",
- i, errFlag);
- return errFlag;
+ i, err_flag);
+ return err_flag;
}
}
return 0;
@@ -940,7 +940,7 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
{
struct usbduxsub *this_usbduxsub = dev->private;
int err = 0, i;
- unsigned int tmpTimer;
+ unsigned int tmp_timer;
if (!(this_usbduxsub->probed))
return -ENODEV;
@@ -990,7 +990,7 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
1000000 / 8 * i);
/* now calc the real sampling rate with all the
* rounding errors */
- tmpTimer =
+ tmp_timer =
((unsigned int)(cmd->scan_begin_arg / 125000)) *
125000;
} else {
@@ -1001,11 +1001,11 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
/*
* calc the real sampling rate with the rounding errors
*/
- tmpTimer = ((unsigned int)(cmd->scan_begin_arg /
+ tmp_timer = ((unsigned int)(cmd->scan_begin_arg /
1000000)) * 1000000;
}
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg,
- tmpTimer);
+ tmp_timer);
}
err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
@@ -1081,7 +1081,7 @@ static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
result = usb_bulk_msg(this_usbduxsub->usbdev,
usb_rcvbulkpipe(this_usbduxsub->usbdev,
COMMAND_IN_EP),
- this_usbduxsub->insnBuffer, SIZEINSNBUF,
+ this_usbduxsub->insn_buffer, SIZEINSNBUF,
&nrec, BULK_TIMEOUT);
if (result < 0) {
dev_err(&this_usbduxsub->interface->dev, "comedi%d: "
@@ -1089,7 +1089,7 @@ static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
"\n", this_usbduxsub->comedidev->minor, result);
return result;
}
- if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command)
+ if (le16_to_cpu(this_usbduxsub->insn_buffer[0]) == command)
return result;
}
/* this is only reached if the data has been requested a couple of
@@ -1097,7 +1097,7 @@ static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command)
dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: "
"wrong data returned from firmware: want cmd %d, got cmd %d.\n",
this_usbduxsub->comedidev->minor, command,
- le16_to_cpu(this_usbduxsub->insnBuffer[0]));
+ le16_to_cpu(this_usbduxsub->insn_buffer[0]));
return -EFAULT;
}
@@ -1126,7 +1126,7 @@ static int usbdux_ai_inttrig(struct comedi_device *dev,
}
if (!(this_usbduxsub->ai_cmd_running)) {
this_usbduxsub->ai_cmd_running = 1;
- ret = usbduxsub_submit_InURBs(this_usbduxsub);
+ ret = usbduxsub_submit_inurbs(this_usbduxsub);
if (ret < 0) {
dev_err(&this_usbduxsub->interface->dev,
"comedi%d: usbdux_ai_inttrig: "
@@ -1243,7 +1243,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
this_usbduxsub->ai_cmd_running = 1;
- ret = usbduxsub_submit_InURBs(this_usbduxsub);
+ ret = usbduxsub_submit_inurbs(this_usbduxsub);
if (ret < 0) {
this_usbduxsub->ai_cmd_running = 0;
/* fixme: unlink here?? */
@@ -1311,7 +1311,7 @@ static int usbdux_ai_insn_read(struct comedi_device *dev,
up(&this_usbduxsub->sem);
return 0;
}
- one = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
+ one = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
if (CR_RANGE(insn->chanspec) <= 1)
one = one ^ 0x800;
@@ -1341,7 +1341,7 @@ static int usbdux_ao_insn_read(struct comedi_device *dev,
return -ENODEV;
}
for (i = 0; i < insn->n; i++)
- data[i] = this_usbduxsub->outBuffer[chan];
+ data[i] = this_usbduxsub->out_buffer[chan];
up(&this_usbduxsub->sem);
return i;
@@ -1384,7 +1384,7 @@ static int usbdux_ao_insn_write(struct comedi_device *dev,
/* one 16 bit value */
*((int16_t *) (this_usbduxsub->dux_commands + 2)) =
cpu_to_le16(data[i]);
- this_usbduxsub->outBuffer[chan] = data[i];
+ this_usbduxsub->out_buffer[chan] = data[i];
/* channel number */
this_usbduxsub->dux_commands[4] = (chan << 6);
err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS);
@@ -1421,7 +1421,7 @@ static int usbdux_ao_inttrig(struct comedi_device *dev,
}
if (!(this_usbduxsub->ao_cmd_running)) {
this_usbduxsub->ao_cmd_running = 1;
- ret = usbduxsub_submit_OutURBs(this_usbduxsub);
+ ret = usbduxsub_submit_outurbs(this_usbduxsub);
if (ret < 0) {
dev_err(&this_usbduxsub->interface->dev,
"comedi%d: usbdux_ao_inttrig: submitURB: "
@@ -1616,7 +1616,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->start_src == TRIG_NOW) {
/* enable this acquisition operation */
this_usbduxsub->ao_cmd_running = 1;
- ret = usbduxsub_submit_OutURBs(this_usbduxsub);
+ ret = usbduxsub_submit_outurbs(this_usbduxsub);
if (ret < 0) {
this_usbduxsub->ao_cmd_running = 0;
/* fixme: unlink here?? */
@@ -1704,7 +1704,7 @@ static int usbdux_dio_insn_bits(struct comedi_device *dev,
return err;
}
- data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]);
+ data[1] = le16_to_cpu(this_usbduxsub->insn_buffer[1]);
up(&this_usbduxsub->sem);
return insn->n;
}
@@ -1740,7 +1740,7 @@ static int usbdux_counter_read(struct comedi_device *dev,
return err;
}
- data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]);
+ data[0] = le16_to_cpu(this_usbduxsub->insn_buffer[chan + 1]);
up(&this_usbduxsub->sem);
return 1;
}
@@ -1787,13 +1787,13 @@ static int usbdux_counter_config(struct comedi_device *dev,
/***********************************/
/* PWM */
-static int usbduxsub_unlink_PwmURBs(struct usbduxsub *usbduxsub_tmp)
+static int usbduxsub_unlink_pwm_urbs(struct usbduxsub *usbduxsub_tmp)
{
int err = 0;
- if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) {
- if (usbduxsub_tmp->urbPwm)
- usb_kill_urb(usbduxsub_tmp->urbPwm);
+ if (usbduxsub_tmp && usbduxsub_tmp->urb_pwm) {
+ if (usbduxsub_tmp->urb_pwm)
+ usb_kill_urb(usbduxsub_tmp->urb_pwm);
dev_dbg(&usbduxsub_tmp->interface->dev,
"comedi: unlinked PwmURB: res=%d\n", err);
}
@@ -1812,7 +1812,7 @@ static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__);
if (do_unlink)
- ret = usbduxsub_unlink_PwmURBs(this_usbduxsub);
+ ret = usbduxsub_unlink_pwm_urbs(this_usbduxsub);
this_usbduxsub->pwm_cmd_running = 0;
@@ -1885,7 +1885,7 @@ static void usbduxsub_pwm_irq(struct urb *urb)
if (!(this_usbduxsub->pwm_cmd_running))
return;
- urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf;
+ urb->transfer_buffer_length = this_usbduxsub->size_pwm_buf;
urb->dev = this_usbduxsub->usbdev;
urb->status = 0;
if (this_usbduxsub->pwm_cmd_running) {
@@ -1905,9 +1905,9 @@ static void usbduxsub_pwm_irq(struct urb *urb)
}
}
-static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub)
+static int usbduxsub_submit_pwm_urbs(struct usbduxsub *usbduxsub)
{
- int errFlag;
+ int err_flag;
if (!usbduxsub)
return -EFAULT;
@@ -1915,19 +1915,19 @@ static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub)
dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n");
/* in case of a resubmission after an unlink... */
- usb_fill_bulk_urb(usbduxsub->urbPwm,
+ usb_fill_bulk_urb(usbduxsub->urb_pwm,
usbduxsub->usbdev,
usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP),
- usbduxsub->urbPwm->transfer_buffer,
- usbduxsub->sizePwmBuf, usbduxsub_pwm_irq,
+ usbduxsub->urb_pwm->transfer_buffer,
+ usbduxsub->size_pwm_buf, usbduxsub_pwm_irq,
usbduxsub->comedidev);
- errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC);
- if (errFlag) {
+ err_flag = usb_submit_urb(usbduxsub->urb_pwm, GFP_ATOMIC);
+ if (err_flag) {
dev_err(&usbduxsub->interface->dev,
"comedi_: usbdux: pwm: usb_submit_urb error %d\n",
- errFlag);
- return errFlag;
+ err_flag);
+ return err_flag;
}
return 0;
}
@@ -1952,8 +1952,8 @@ static int usbdux_pwm_period(struct comedi_device *dev,
return -EAGAIN;
}
}
- this_usbduxsub->pwmDelay = fx2delay;
- this_usbduxsub->pwmPeriod = period;
+ this_usbduxsub->pwn_delay = fx2delay;
+ this_usbduxsub->pwm_period = period;
dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n",
__func__, period, fx2delay);
return 0;
@@ -1974,17 +1974,17 @@ static int usbdux_pwm_start(struct comedi_device *dev,
return 0;
}
- this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay);
+ this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwn_delay);
ret = send_dux_commands(this_usbduxsub, SENDPWMON);
if (ret < 0)
return ret;
/* initialise the buffer */
- for (i = 0; i < this_usbduxsub->sizePwmBuf; i++)
- ((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0;
+ for (i = 0; i < this_usbduxsub->size_pwm_buf; i++)
+ ((char *)(this_usbduxsub->urb_pwm->transfer_buffer))[i] = 0;
this_usbduxsub->pwm_cmd_running = 1;
- ret = usbduxsub_submit_PwmURBs(this_usbduxsub);
+ ret = usbduxsub_submit_pwm_urbs(this_usbduxsub);
if (ret < 0) {
this_usbduxsub->pwm_cmd_running = 0;
return ret;
@@ -1999,7 +1999,7 @@ static int usbdux_pwm_pattern(struct comedi_device *dev,
{
struct usbduxsub *this_usbduxsub = dev->private;
int i, szbuf;
- char *pBuf;
+ char *p_buf;
char pwm_mask;
char sgn_mask;
char c;
@@ -2013,10 +2013,10 @@ static int usbdux_pwm_pattern(struct comedi_device *dev,
sgn_mask = (16 << channel);
/* this is the buffer which will be filled with the with bit */
/* pattern for one period */
- szbuf = this_usbduxsub->sizePwmBuf;
- pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer);
+ szbuf = this_usbduxsub->size_pwm_buf;
+ p_buf = (char *)(this_usbduxsub->urb_pwm->transfer_buffer);
for (i = 0; i < szbuf; i++) {
- c = *pBuf;
+ c = *p_buf;
/* reset bits */
c = c & (~pwm_mask);
/* set the bit as long as the index is lower than the value */
@@ -2030,7 +2030,7 @@ static int usbdux_pwm_pattern(struct comedi_device *dev,
/* negative value */
c = c | sgn_mask;
}
- *(pBuf++) = c;
+ *(p_buf++) = c;
}
return 1;
}
@@ -2102,7 +2102,7 @@ static int usbdux_pwm_config(struct comedi_device *dev,
"comedi%d: %s: setting period\n", dev->minor, __func__);
return usbdux_pwm_period(dev, s, data[1]);
case INSN_CONFIG_PWM_GET_PERIOD:
- data[1] = this_usbduxsub->pwmPeriod;
+ data[1] = this_usbduxsub->pwm_period;
return 0;
case INSN_CONFIG_PWM_SET_H_BRIDGE:
/* value in the first byte and the sign in the second for a
@@ -2138,55 +2138,55 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp)
usbduxsub_tmp->probed = 0;
- if (usbduxsub_tmp->urbIn) {
+ if (usbduxsub_tmp->urb_in) {
if (usbduxsub_tmp->ai_cmd_running) {
usbduxsub_tmp->ai_cmd_running = 0;
- usbduxsub_unlink_InURBs(usbduxsub_tmp);
+ usbduxsub_unlink_inurbs(usbduxsub_tmp);
}
- for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) {
- kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer);
- usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL;
- usb_kill_urb(usbduxsub_tmp->urbIn[i]);
- usb_free_urb(usbduxsub_tmp->urbIn[i]);
- usbduxsub_tmp->urbIn[i] = NULL;
+ for (i = 0; i < usbduxsub_tmp->num_in_buffers; i++) {
+ kfree(usbduxsub_tmp->urb_in[i]->transfer_buffer);
+ usbduxsub_tmp->urb_in[i]->transfer_buffer = NULL;
+ usb_kill_urb(usbduxsub_tmp->urb_in[i]);
+ usb_free_urb(usbduxsub_tmp->urb_in[i]);
+ usbduxsub_tmp->urb_in[i] = NULL;
}
- kfree(usbduxsub_tmp->urbIn);
- usbduxsub_tmp->urbIn = NULL;
+ kfree(usbduxsub_tmp->urb_in);
+ usbduxsub_tmp->urb_in = NULL;
}
- if (usbduxsub_tmp->urbOut) {
+ if (usbduxsub_tmp->urb_out) {
if (usbduxsub_tmp->ao_cmd_running) {
usbduxsub_tmp->ao_cmd_running = 0;
- usbduxsub_unlink_OutURBs(usbduxsub_tmp);
+ usbduxsub_unlink_outurbs(usbduxsub_tmp);
}
- for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) {
- kfree(usbduxsub_tmp->urbOut[i]->transfer_buffer);
- usbduxsub_tmp->urbOut[i]->transfer_buffer = NULL;
- if (usbduxsub_tmp->urbOut[i]) {
- usb_kill_urb(usbduxsub_tmp->urbOut[i]);
- usb_free_urb(usbduxsub_tmp->urbOut[i]);
- usbduxsub_tmp->urbOut[i] = NULL;
+ for (i = 0; i < usbduxsub_tmp->num_out_buffers; i++) {
+ kfree(usbduxsub_tmp->urb_out[i]->transfer_buffer);
+ usbduxsub_tmp->urb_out[i]->transfer_buffer = NULL;
+ if (usbduxsub_tmp->urb_out[i]) {
+ usb_kill_urb(usbduxsub_tmp->urb_out[i]);
+ usb_free_urb(usbduxsub_tmp->urb_out[i]);
+ usbduxsub_tmp->urb_out[i] = NULL;
}
}
- kfree(usbduxsub_tmp->urbOut);
- usbduxsub_tmp->urbOut = NULL;
+ kfree(usbduxsub_tmp->urb_out);
+ usbduxsub_tmp->urb_out = NULL;
}
- if (usbduxsub_tmp->urbPwm) {
+ if (usbduxsub_tmp->urb_pwm) {
if (usbduxsub_tmp->pwm_cmd_running) {
usbduxsub_tmp->pwm_cmd_running = 0;
- usbduxsub_unlink_PwmURBs(usbduxsub_tmp);
+ usbduxsub_unlink_pwm_urbs(usbduxsub_tmp);
}
- kfree(usbduxsub_tmp->urbPwm->transfer_buffer);
- usbduxsub_tmp->urbPwm->transfer_buffer = NULL;
- usb_kill_urb(usbduxsub_tmp->urbPwm);
- usb_free_urb(usbduxsub_tmp->urbPwm);
- usbduxsub_tmp->urbPwm = NULL;
- }
- kfree(usbduxsub_tmp->inBuffer);
- usbduxsub_tmp->inBuffer = NULL;
- kfree(usbduxsub_tmp->insnBuffer);
- usbduxsub_tmp->insnBuffer = NULL;
- kfree(usbduxsub_tmp->outBuffer);
- usbduxsub_tmp->outBuffer = NULL;
+ kfree(usbduxsub_tmp->urb_pwm->transfer_buffer);
+ usbduxsub_tmp->urb_pwm->transfer_buffer = NULL;
+ usb_kill_urb(usbduxsub_tmp->urb_pwm);
+ usb_free_urb(usbduxsub_tmp->urb_pwm);
+ usbduxsub_tmp->urb_pwm = NULL;
+ }
+ kfree(usbduxsub_tmp->in_buffer);
+ usbduxsub_tmp->in_buffer = NULL;
+ kfree(usbduxsub_tmp->insn_buffer);
+ usbduxsub_tmp->insn_buffer = NULL;
+ kfree(usbduxsub_tmp->out_buffer);
+ usbduxsub_tmp->out_buffer = NULL;
kfree(usbduxsub_tmp->dac_commands);
usbduxsub_tmp->dac_commands = NULL;
kfree(usbduxsub_tmp->dux_commands);
@@ -2207,8 +2207,6 @@ static int usbdux_attach_common(struct comedi_device *dev,
/* pointer back to the corresponding comedi device */
udev->comedidev = dev;
- dev->board_name = "usbdux";
-
/* set number of subdevices */
if (udev->high_speed) {
/* with pwm */
@@ -2309,7 +2307,7 @@ static int usbdux_attach_common(struct comedi_device *dev,
s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE;
s->n_chan = 8;
/* this defines the max duty cycle resolution */
- s->maxdata = udev->sizePwmBuf;
+ s->maxdata = udev->size_pwm_buf;
s->insn_write = usbdux_pwm_write;
s->insn_read = usbdux_pwm_read;
s->insn_config = usbdux_pwm_config;
@@ -2388,7 +2386,7 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
* we need to upload the firmware here because fw will be
* freed once we've left this function
*/
- ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
+ ret = firmware_upload(usbduxsub_tmp, fw->data, fw->size);
if (ret) {
dev_err(&uinterf->dev,
@@ -2464,22 +2462,22 @@ static int usbdux_usb_probe(struct usb_interface *uinterf,
return -ENOMEM;
}
/* create space for the in buffer and set it to zero */
- usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL);
- if (!(usbduxsub[index].inBuffer)) {
+ usbduxsub[index].in_buffer = kzalloc(SIZEINBUF, GFP_KERNEL);
+ if (!(usbduxsub[index].in_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
/* create space of the instruction buffer */
- usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
- if (!(usbduxsub[index].insnBuffer)) {
+ usbduxsub[index].insn_buffer = kzalloc(SIZEINSNBUF, GFP_KERNEL);
+ if (!(usbduxsub[index].insn_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
/* create space for the outbuffer */
- usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
- if (!(usbduxsub[index].outBuffer)) {
+ usbduxsub[index].out_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL);
+ if (!(usbduxsub[index].out_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
@@ -2496,124 +2494,124 @@ static int usbdux_usb_probe(struct usb_interface *uinterf,
return -ENODEV;
}
if (usbduxsub[index].high_speed)
- usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH;
+ usbduxsub[index].num_in_buffers = NUMOFINBUFFERSHIGH;
else
- usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL;
+ usbduxsub[index].num_in_buffers = NUMOFINBUFFERSFULL;
- usbduxsub[index].urbIn =
- kcalloc(usbduxsub[index].numOfInBuffers, sizeof(struct urb *),
+ usbduxsub[index].urb_in =
+ kcalloc(usbduxsub[index].num_in_buffers, sizeof(struct urb *),
GFP_KERNEL);
- if (!(usbduxsub[index].urbIn)) {
+ if (!(usbduxsub[index].urb_in)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) {
+ for (i = 0; i < usbduxsub[index].num_in_buffers; i++) {
/* one frame: 1ms */
- usbduxsub[index].urbIn[i] = usb_alloc_urb(1, GFP_KERNEL);
- if (usbduxsub[index].urbIn[i] == NULL) {
+ usbduxsub[index].urb_in[i] = usb_alloc_urb(1, GFP_KERNEL);
+ if (usbduxsub[index].urb_in[i] == NULL) {
dev_err(dev, "comedi_: usbdux%d: "
"Could not alloc. urb(%d)\n", index, i);
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev;
+ usbduxsub[index].urb_in[i]->dev = usbduxsub[index].usbdev;
/* will be filled later with a pointer to the comedi-device */
/* and ONLY then the urb should be submitted */
- usbduxsub[index].urbIn[i]->context = NULL;
- usbduxsub[index].urbIn[i]->pipe =
+ usbduxsub[index].urb_in[i]->context = NULL;
+ usbduxsub[index].urb_in[i]->pipe =
usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP);
- usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP;
- usbduxsub[index].urbIn[i]->transfer_buffer =
+ usbduxsub[index].urb_in[i]->transfer_flags = URB_ISO_ASAP;
+ usbduxsub[index].urb_in[i]->transfer_buffer =
kzalloc(SIZEINBUF, GFP_KERNEL);
- if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) {
+ if (!(usbduxsub[index].urb_in[i]->transfer_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq;
- usbduxsub[index].urbIn[i]->number_of_packets = 1;
- usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF;
- usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0;
- usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = SIZEINBUF;
+ usbduxsub[index].urb_in[i]->complete = usbduxsub_ai_isoc_irq;
+ usbduxsub[index].urb_in[i]->number_of_packets = 1;
+ usbduxsub[index].urb_in[i]->transfer_buffer_length = SIZEINBUF;
+ usbduxsub[index].urb_in[i]->iso_frame_desc[0].offset = 0;
+ usbduxsub[index].urb_in[i]->iso_frame_desc[0].length = SIZEINBUF;
}
/* out */
if (usbduxsub[index].high_speed)
- usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH;
+ usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSHIGH;
else
- usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL;
+ usbduxsub[index].num_out_buffers = NUMOFOUTBUFFERSFULL;
- usbduxsub[index].urbOut =
- kcalloc(usbduxsub[index].numOfOutBuffers, sizeof(struct urb *),
+ usbduxsub[index].urb_out =
+ kcalloc(usbduxsub[index].num_out_buffers, sizeof(struct urb *),
GFP_KERNEL);
- if (!(usbduxsub[index].urbOut)) {
+ if (!(usbduxsub[index].urb_out)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) {
+ for (i = 0; i < usbduxsub[index].num_out_buffers; i++) {
/* one frame: 1ms */
- usbduxsub[index].urbOut[i] = usb_alloc_urb(1, GFP_KERNEL);
- if (usbduxsub[index].urbOut[i] == NULL) {
+ usbduxsub[index].urb_out[i] = usb_alloc_urb(1, GFP_KERNEL);
+ if (usbduxsub[index].urb_out[i] == NULL) {
dev_err(dev, "comedi_: usbdux%d: "
"Could not alloc. urb(%d)\n", index, i);
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev;
+ usbduxsub[index].urb_out[i]->dev = usbduxsub[index].usbdev;
/* will be filled later with a pointer to the comedi-device */
/* and ONLY then the urb should be submitted */
- usbduxsub[index].urbOut[i]->context = NULL;
- usbduxsub[index].urbOut[i]->pipe =
+ usbduxsub[index].urb_out[i]->context = NULL;
+ usbduxsub[index].urb_out[i]->pipe =
usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP);
- usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP;
- usbduxsub[index].urbOut[i]->transfer_buffer =
+ usbduxsub[index].urb_out[i]->transfer_flags = URB_ISO_ASAP;
+ usbduxsub[index].urb_out[i]->transfer_buffer =
kzalloc(SIZEOUTBUF, GFP_KERNEL);
- if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) {
+ if (!(usbduxsub[index].urb_out[i]->transfer_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq;
- usbduxsub[index].urbOut[i]->number_of_packets = 1;
- usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF;
- usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0;
- usbduxsub[index].urbOut[i]->iso_frame_desc[0].length =
+ usbduxsub[index].urb_out[i]->complete = usbduxsub_ao_isoc_irq;
+ usbduxsub[index].urb_out[i]->number_of_packets = 1;
+ usbduxsub[index].urb_out[i]->transfer_buffer_length = SIZEOUTBUF;
+ usbduxsub[index].urb_out[i]->iso_frame_desc[0].offset = 0;
+ usbduxsub[index].urb_out[i]->iso_frame_desc[0].length =
SIZEOUTBUF;
if (usbduxsub[index].high_speed) {
/* uframes */
- usbduxsub[index].urbOut[i]->interval = 8;
+ usbduxsub[index].urb_out[i]->interval = 8;
} else {
/* frames */
- usbduxsub[index].urbOut[i]->interval = 1;
+ usbduxsub[index].urb_out[i]->interval = 1;
}
}
/* pwm */
if (usbduxsub[index].high_speed) {
/* max bulk ep size in high speed */
- usbduxsub[index].sizePwmBuf = 512;
- usbduxsub[index].urbPwm = usb_alloc_urb(0, GFP_KERNEL);
- if (usbduxsub[index].urbPwm == NULL) {
+ usbduxsub[index].size_pwm_buf = 512;
+ usbduxsub[index].urb_pwm = usb_alloc_urb(0, GFP_KERNEL);
+ if (usbduxsub[index].urb_pwm == NULL) {
dev_err(dev, "comedi_: usbdux%d: "
"Could not alloc. pwm urb\n", index);
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
- usbduxsub[index].urbPwm->transfer_buffer =
- kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL);
- if (!(usbduxsub[index].urbPwm->transfer_buffer)) {
+ usbduxsub[index].urb_pwm->transfer_buffer =
+ kzalloc(usbduxsub[index].size_pwm_buf, GFP_KERNEL);
+ if (!(usbduxsub[index].urb_pwm->transfer_buffer)) {
tidy_up(&(usbduxsub[index]));
up(&start_stop_sem);
return -ENOMEM;
}
} else {
- usbduxsub[index].urbPwm = NULL;
- usbduxsub[index].sizePwmBuf = 0;
+ usbduxsub[index].urb_pwm = NULL;
+ usbduxsub[index].size_pwm_buf = 0;
}
usbduxsub[index].ai_cmd_running = 0;
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 1ba0e3df492d..7f95af33085d 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -1387,7 +1387,7 @@ static int usbduxfast_attach_common(struct comedi_device *dev,
down(&udfs->sem);
/* pointer back to the corresponding comedi device */
udfs->comedidev = dev;
- dev->board_name = "usbduxfast";
+
ret = comedi_alloc_subdevices(dev, 1);
if (ret) {
up(&udfs->sem);
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index a728c8fc32a2..d3bc1b9910a7 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -176,12 +176,6 @@ static const struct comedi_lrange range_usbdux_ai_range = { 1, {
}
};
-static const struct comedi_lrange range_usbdux_ao_range = { 1, {
- UNI_RANGE
- (2.5),
- }
-};
-
/*
* private structure of one subdevice
*/
@@ -1376,7 +1370,7 @@ static int usbdux_getstatusinfo(struct comedi_device *dev, int chan)
/* 32 bits big endian from the A/D converter */
one = be32_to_cpu(*((int32_t *)((this_usbduxsub->insnBuffer)+1)));
- /* mask out the staus byte */
+ /* mask out the status byte */
one = one & 0x00ffffff;
one = one ^ 0x00800000;
@@ -2211,7 +2205,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev,
down(&uds->sem);
/* pointer back to the corresponding comedi device */
uds->comedidev = dev;
- dev->board_name = "usbduxsigma";
+
/* set number of subdevices */
if (uds->high_speed)
n_subdevs = 4; /* with pwm */
@@ -2269,7 +2263,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev,
/* 8 bit resolution */
s->maxdata = 0x00ff;
/* unipolar range */
- s->range_table = (&range_usbdux_ao_range);
+ s->range_table = &range_unipolar2_5;
/* callback */
s->do_cmdtest = usbdux_ao_cmdtest;
s->do_cmd = usbdux_ao_cmd;
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 8932a510d96c..3231a483f561 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -63,7 +63,7 @@ struct comedi_device *comedi_open(const char *filename)
return dev;
}
-EXPORT_SYMBOL(comedi_open);
+EXPORT_SYMBOL_GPL(comedi_open);
int comedi_close(struct comedi_device *d)
{
@@ -73,7 +73,7 @@ int comedi_close(struct comedi_device *d)
return 0;
}
-EXPORT_SYMBOL(comedi_close);
+EXPORT_SYMBOL_GPL(comedi_close);
static int comedi_do_insn(struct comedi_device *dev,
struct comedi_insn *insn,
@@ -143,7 +143,7 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev,
return comedi_do_insn(dev, &insn, &io);
}
-EXPORT_SYMBOL(comedi_dio_config);
+EXPORT_SYMBOL_GPL(comedi_dio_config);
int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
unsigned int mask, unsigned int *bits)
@@ -166,7 +166,7 @@ int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev,
return ret;
}
-EXPORT_SYMBOL(comedi_dio_bitfield);
+EXPORT_SYMBOL_GPL(comedi_dio_bitfield);
int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
unsigned int subd)
@@ -183,7 +183,7 @@ int comedi_find_subdevice_by_type(struct comedi_device *dev, int type,
}
return -1;
}
-EXPORT_SYMBOL(comedi_find_subdevice_by_type);
+EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type);
int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
{
@@ -191,4 +191,4 @@ int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice)
return s->n_chan;
}
-EXPORT_SYMBOL(comedi_get_n_channels);
+EXPORT_SYMBOL_GPL(comedi_get_n_channels);
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 59ff0cf73381..1dc391b76447 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -26,17 +26,25 @@
#include "comedi_internal.h"
const struct comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} };
-EXPORT_SYMBOL(range_bipolar10);
+EXPORT_SYMBOL_GPL(range_bipolar10);
const struct comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} };
-EXPORT_SYMBOL(range_bipolar5);
+EXPORT_SYMBOL_GPL(range_bipolar5);
const struct comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} };
-EXPORT_SYMBOL(range_bipolar2_5);
+EXPORT_SYMBOL_GPL(range_bipolar2_5);
const struct comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} };
-EXPORT_SYMBOL(range_unipolar10);
+EXPORT_SYMBOL_GPL(range_unipolar10);
const struct comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} };
-EXPORT_SYMBOL(range_unipolar5);
+EXPORT_SYMBOL_GPL(range_unipolar5);
+const struct comedi_lrange range_unipolar2_5 = { 1, {UNI_RANGE(2.5)} };
+EXPORT_SYMBOL_GPL(range_unipolar2_5);
+const struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} };
+EXPORT_SYMBOL_GPL(range_0_20mA);
+const struct comedi_lrange range_4_20mA = { 1, {RANGE_mA(4, 20)} };
+EXPORT_SYMBOL_GPL(range_4_20mA);
+const struct comedi_lrange range_0_32mA = { 1, {RANGE_mA(0, 32)} };
+EXPORT_SYMBOL_GPL(range_0_32mA);
const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none} } };
-EXPORT_SYMBOL(range_unknown);
+EXPORT_SYMBOL_GPL(range_unknown);
/*
COMEDI_RANGEINFO
@@ -165,4 +173,4 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n,
}
return 0;
}
-EXPORT_SYMBOL(comedi_check_chanlist);
+EXPORT_SYMBOL_GPL(comedi_check_chanlist);
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
index 31fb5d31bb3a..e96eee3ca898 100644
--- a/drivers/staging/cptm1217/clearpad_tm1217.c
+++ b/drivers/staging/cptm1217/clearpad_tm1217.c
@@ -557,12 +557,15 @@ fail:
}
+#ifdef CONFIG_PM_SLEEP
+
/*
* cp_tm1217 suspend
*
*/
-static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg)
+static int cp_tm1217_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cp_tm1217_device *ts = i2c_get_clientdata(client);
u8 req[2];
int retval;
@@ -583,8 +586,9 @@ static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg)
* cp_tm1217_resume
*
*/
-static int cp_tm1217_resume(struct i2c_client *client)
+static int cp_tm1217_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct cp_tm1217_device *ts = i2c_get_clientdata(client);
u8 req[2];
int retval;
@@ -618,6 +622,11 @@ static int cp_tm1217_resume(struct i2c_client *client)
return 0;
}
+#endif
+
+static SIMPLE_DEV_PM_OPS(cp_tm1217_pm_ops, cp_tm1217_suspend,
+ cp_tm1217_resume);
+
/*
* cp_tm1217_remove
*
@@ -647,12 +656,11 @@ static struct i2c_driver cp_tm1217_driver = {
.driver = {
.owner = THIS_MODULE,
.name = CPTM1217_DRIVER_NAME,
+ .pm = &cp_tm1217_pm_ops,
},
.id_table = cp_tm1217_idtable,
.probe = cp_tm1217_probe,
.remove = cp_tm1217_remove,
- .suspend = cp_tm1217_suspend,
- .resume = cp_tm1217_resume,
};
module_i2c_driver(cp_tm1217_driver);
diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c
index 7b133597e923..b53a9e29a97c 100644
--- a/drivers/staging/csr/bh.c
+++ b/drivers/staging/csr/bh.c
@@ -373,7 +373,7 @@ CsrResult unifi_run_bh(void *ospriv)
unifi_priv_t *priv = ospriv;
/*
- * If an error has occured, we discard silently all messages from the bh
+ * If an error has occurred, we discard silently all messages from the bh
* until the error has been processed and the unifi has been reinitialised.
*/
if (priv->bh_thread.block_thread == 1) {
diff --git a/drivers/staging/csr/csr_log.h b/drivers/staging/csr/csr_log.h
index 5de5650767de..982941043ddc 100644
--- a/drivers/staging/csr/csr_log.h
+++ b/drivers/staging/csr/csr_log.h
@@ -34,7 +34,7 @@ typedef u32 CsrLogLevelEnvironment;
#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_START ((CsrLogLevelEnvironment) 0x00000100) /* Background Interrupt start events are logged */
#define CSR_LOG_LEVEL_ENVIRONMENT_BGINT_DONE ((CsrLogLevelEnvironment) 0x00000200) /* Background Interrupt done events are logged */
#define CSR_LOG_LEVEL_ENVIRONMENT_PROTO ((CsrLogLevelEnvironment) 0x00000400) /* Transport protocol events are logged */
-#define CSR_LOG_LEVEL_ENVIRONMENT_PROTO_LOC ((CsrLogLevelEnvironment) 0x00000800) /* The Location where the transport protocol event occured are logged NB: This is a supplement to CSR_LOG_LEVEL_ENVIRONMENT_PROTO, it has no effect without it */
+#define CSR_LOG_LEVEL_ENVIRONMENT_PROTO_LOC ((CsrLogLevelEnvironment) 0x00000800) /* The Location where the transport protocol event occurred are logged NB: This is a supplement to CSR_LOG_LEVEL_ENVIRONMENT_PROTO, it has no effect without it */
/* The bit masks between here are reserved for future usage */
#define CSR_LOG_LEVEL_ENVIRONMENT_ALL ((CsrLogLevelEnvironment) 0xFFFFFFFF) /* All possible environment data/events are logged WARNING: By using this define the application also accepts future possible environment data/events in the logs */
@@ -44,10 +44,10 @@ typedef u32 CsrLogLevelEnvironment;
typedef u32 CsrLogLevelTask;
#define CSR_LOG_LEVEL_TASK_OFF ((CsrLogLevelTask) 0x00000000) /* No events are logged for this task */
#define CSR_LOG_LEVEL_TASK_TEXT ((CsrLogLevelTask) 0x00000001) /* Text strings printed by a task are logged NB: This bit does not affect the CSR_LOG_TEXT_LEVEL interface. This has to be configured separately */
-#define CSR_LOG_LEVEL_TASK_TEXT_LOC ((CsrLogLevelTask) 0x00000002) /* The locaction where the text string call occured are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_TEXT, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_TEXT_LOC ((CsrLogLevelTask) 0x00000002) /* The locaction where the text string call occurred are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_TEXT, it has no effect without it */
#define CSR_LOG_LEVEL_TASK_STATE ((CsrLogLevelTask) 0x00000004) /* FSM state transitions in a task are logged */
#define CSR_LOG_LEVEL_TASK_STATE_NAME ((CsrLogLevelTask) 0x00000008) /* The name of each state in a FSM state transition are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_STATE, it has no effect without it */
-#define CSR_LOG_LEVEL_TASK_STATE_LOC ((CsrLogLevelTask) 0x00000010) /* The location where the FSM state transition occured are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_STATE, it has no effect without it */
+#define CSR_LOG_LEVEL_TASK_STATE_LOC ((CsrLogLevelTask) 0x00000010) /* The location where the FSM state transition occurred are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_STATE, it has no effect without it */
#define CSR_LOG_LEVEL_TASK_TASK_SWITCH ((CsrLogLevelTask) 0x00000020) /* Activation and deactiation of a task are logged */
#define CSR_LOG_LEVEL_TASK_MESSAGE_PUT ((CsrLogLevelTask) 0x00000080) /* Message put operations are logged */
#define CSR_LOG_LEVEL_TASK_MESSAGE_PUT_LOC ((CsrLogLevelTask) 0x00000100) /* The location where a message was sent are logged. NB: This is a supplement to CSR_LOG_LEVEL_TASK_MESSAGE_PUT, it has no effect without it */
diff --git a/drivers/staging/csr/csr_sdio.h b/drivers/staging/csr/csr_sdio.h
index 624a53fa1d7e..0971d135abf6 100644
--- a/drivers/staging/csr/csr_sdio.h
+++ b/drivers/staging/csr/csr_sdio.h
@@ -257,7 +257,7 @@ void CsrSdioFunctionDriverUnregister(CsrSdioFunctionDriver *functionDriver);
* CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. The state of the
* related bit in the I/O Enable register is
* undefined.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device, or the related
@@ -295,7 +295,7 @@ CsrResult CsrSdioFunctionDisable(CsrSdioFunction *function);
* CSR_RESULT_SUCCESS - The specified function was enabled/disabled.
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The state of the
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. The state of the
* related bit in the INT Enable register is
* unchanged.
* CSR_SDIO_RESULT_INVALID_VALUE - The specified function cannot be
@@ -408,7 +408,7 @@ void CsrSdioResumeAcknowledge(CsrSdioFunction *function, CsrResult result);
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. The configured block
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. The configured block
* size is undefined.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device.
*
@@ -456,7 +456,7 @@ CsrResult CsrSdioBlockSizeSet(CsrSdioFunction *function, u16 blockSize);
* maxFrequency - The maximum clock frequency for the function in Hertz.
*
* RETURNS
- * CSR_RESULT_SUCCESS - The maximum clock frequency was succesfully
+ * CSR_RESULT_SUCCESS - The maximum clock frequency was successfully
* set for the function.
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
@@ -494,7 +494,7 @@ CsrResult CsrSdioMaxBusClockFrequencySet(CsrSdioFunction *function, u32 maxFrequ
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. No data read/written.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device.
*
* NOTE: If the SDIO R5 response is available, and either of the
@@ -537,7 +537,7 @@ void CsrSdioWrite8Async(CsrSdioFunction *function, u32 address, u8 data, CsrSdio
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. Data may have been
* partially read/written.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device.
*
@@ -583,7 +583,7 @@ void CsrSdioWrite16Async(CsrSdioFunction *function, u32 address, u16 data, CsrSd
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. No data read/written.
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. No data read/written.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device.
*
* NOTE: If the SDIO R5 response is available, and either of the
@@ -628,7 +628,7 @@ void CsrSdioF0Write8Async(CsrSdioFunction *function, u32 address, u8 data, CsrSd
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_INVALID_VALUE - One or more arguments were invalid.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured. Data may have been
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred. Data may have been
* partially read/written.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device.
*
@@ -666,11 +666,11 @@ void CsrSdioWriteAsync(CsrSdioFunction *function, u32 address, const void *data,
* the device to power on/off.
*
* RETURNS (only CsrSdioPowerOn)
- * CSR_RESULT_SUCCESS - Power was succesfully reapplied and the device
+ * CSR_RESULT_SUCCESS - Power was successfully reapplied and the device
* has been reinitialised.
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred during reinitialisation.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device during
* reinitialisation.
* CSR_SDIO_RESULT_NOT_RESET - The power was not removed by the
@@ -693,11 +693,11 @@ void CsrSdioPowerOff(CsrSdioFunction *function);
* the device to hard reset.
*
* RETURNS
- * CSR_RESULT_SUCCESS - Reset was succesfully performed and the device
+ * CSR_RESULT_SUCCESS - Reset was successfully performed and the device
* has been reinitialised.
* CSR_RESULT_FAILURE - Unspecified/unknown error.
* CSR_SDIO_RESULT_NO_DEVICE - The device does not exist anymore.
- * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occured during reinitialisation.
+ * CSR_SDIO_RESULT_CRC_ERROR - A CRC error occurred during reinitialisation.
* CSR_SDIO_RESULT_TIMEOUT - No response from the device during
* reinitialisation.
* CSR_SDIO_RESULT_NOT_RESET - The reset was not applied because it is not
diff --git a/drivers/staging/csr/csr_time.c b/drivers/staging/csr/csr_time.c
index f3f4a9c9c67a..01179e46f47d 100644
--- a/drivers/staging/csr/csr_time.c
+++ b/drivers/staging/csr/csr_time.c
@@ -1,10 +1,10 @@
/*****************************************************************************
- (c) Cambridge Silicon Radio Limited 2010
- All rights reserved and confidential information of CSR
+ (c) Cambridge Silicon Radio Limited 2010
+ All rights reserved and confidential information of CSR
- Refer to LICENSE.txt included with this source for details
- on the license terms.
+ Refer to LICENSE.txt included with this source for details
+ on the license terms.
*****************************************************************************/
diff --git a/drivers/staging/csr/csr_wifi_fsm.h b/drivers/staging/csr/csr_wifi_fsm.h
index fde1508c1eae..fc5c5aa6a3c4 100644
--- a/drivers/staging/csr/csr_wifi_fsm.h
+++ b/drivers/staging/csr/csr_wifi_fsm.h
@@ -70,7 +70,7 @@ extern CsrWifiFsmContext* CsrWifiFsmInit(void *applicationContext, void *externa
* This function is used to free any dynamic resources allocated for the
* given context by CsrWifiFsmInit().
* The FSM's reset function is called to cleanup any fsm specific memory
- * The reset funtion does NOT need to free the fsm data pointer as
+ * The reset function does NOT need to free the fsm data pointer as
* CsrWifiFsmShutdown() will do it.
* the FSM's init function is call again to reinitialise the FSM context.
* CsrWifiFsmReset() should NEVER be called when CsrWifiFsmExecute() is running.
@@ -91,7 +91,7 @@ extern void CsrWifiFsmReset(CsrWifiFsmContext *context);
* given context by CsrWifiFsmInit(), prior to complete termination of
* the program.
* The FSM's reset function is called to cleanup any fsm specific memory.
- * The reset funtion does NOT need to free the fsm data pointer as
+ * The reset function does NOT need to free the fsm data pointer as
* CsrWifiFsmShutdown() will do it.
* CsrWifiFsmShutdown() should NEVER be called when CsrWifiFsmExecute() is running.
*
@@ -203,7 +203,7 @@ extern void CsrWifiFsmFastForward(CsrWifiFsmContext *context, u16 ms);
* shift the current time of day by ms amount
*
* @par Description
- * usefull to speed up tests where time needs to pass
+ * useful to speed up tests where time needs to pass
*
* @param[in] context : FSM context
* @param[in] ms : ms to adjust time by
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio.c b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
index 25cabf3234c2..d5425325894c 100644
--- a/drivers/staging/csr/csr_wifi_hip_card_sdio.c
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio.c
@@ -559,7 +559,7 @@ static void _build_sdio_config_data(sdio_config_data_t *cfg_data,
* padding bytes. Every read from this memory has to be transformed in
* host (cpu specific) format, before it is stored in driver's parameters
* or/and structures. Athough unifi_card_read16() and unifi_read32() do perform
- * the convertion internally, unifi_readn() does not.
+ * the conversion internally, unifi_readn() does not.
* ---------------------------------------------------------------------------
*/
static CsrResult card_hw_init(card_t *card)
@@ -1332,7 +1332,7 @@ static CsrResult card_access_panic(card_t *card)
s32 i;
CsrResult r, sr;
- /* A chip version of zero means that the version never got succesfully read
+ /* A chip version of zero means that the version never got successfully read
* during reset. In this case give up because it will not be possible to
* verify the chip version.
*/
@@ -2446,7 +2446,7 @@ static CsrResult unifi_prepare_hw(card_t *card)
if (old_state == UNIFI_HOST_STATE_TORPID)
{
- /* Ensure the initial clock rate is set; if a reset occured when the chip was
+ /* Ensure the initial clock rate is set; if a reset occurred when the chip was
* TORPID, unifi_set_host_state() may have raised it to MAX.
*/
csrResult = CsrSdioMaxBusClockFrequencySet(card->sdio_if, UNIFI_SDIO_CLOCK_INIT_HZ);
@@ -2567,7 +2567,7 @@ static CsrResult unifi_reset_hardware(card_t *card)
csrResult = CsrSdioHardReset(card->sdio_if);
if (csrResult == CSR_RESULT_SUCCESS)
{
- unifi_info(card->ospriv, "CsrSdioHardReset succeeded on reseting UniFi\n");
+ unifi_info(card->ospriv, "CsrSdioHardReset succeeded on resetting UniFi\n");
r = unifi_prepare_hw(card);
if (r == CSR_WIFI_HIP_RESULT_NO_DEVICE)
{
diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c b/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
index 97f645c06818..cfe186e07071 100644
--- a/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
+++ b/drivers/staging/csr/csr_wifi_hip_card_sdio_intr.c
@@ -883,7 +883,7 @@ static CsrResult handle_host_protocol(card_t *card, u8 *processed_something)
r = read_to_host_signals(card, &done);
if (r != CSR_RESULT_SUCCESS)
{
- unifi_error(card->ospriv, "Error occured reading to-host signals\n");
+ unifi_error(card->ospriv, "Error occurred reading to-host signals\n");
return r;
}
if (done > 0)
@@ -899,7 +899,7 @@ static CsrResult handle_host_protocol(card_t *card, u8 *processed_something)
r = process_to_host_signals(card, &done);
if (r != CSR_RESULT_SUCCESS)
{
- unifi_error(card->ospriv, "Error occured processing to-host signals\n");
+ unifi_error(card->ospriv, "Error occurred processing to-host signals\n");
return r;
}
@@ -908,7 +908,7 @@ static CsrResult handle_host_protocol(card_t *card, u8 *processed_something)
r = process_fh_cmd_queue(card, &done);
if (r != CSR_RESULT_SUCCESS)
{
- unifi_error(card->ospriv, "Error occured processing from-host signals\n");
+ unifi_error(card->ospriv, "Error occurred processing from-host signals\n");
return r;
}
if (done > 0)
@@ -919,7 +919,7 @@ static CsrResult handle_host_protocol(card_t *card, u8 *processed_something)
r = process_fh_traffic_queue(card, &done);
if (r != CSR_RESULT_SUCCESS)
{
- unifi_error(card->ospriv, "Error occured processing from-host data signals\n");
+ unifi_error(card->ospriv, "Error occurred processing from-host data signals\n");
return r;
}
if (done > 0)
@@ -1953,7 +1953,7 @@ static CsrResult check_fh_sig_slots(card_t *card, u16 needed, s32 *space_fh)
* in the from-host queue using the wire-format structures, as they arrive.
* All other requests are stored in the from-host queue using the host
* (cpu specific) structures. We use the is_packed member of the card_signal_t
- * structure that describes the queue to make the distiction.
+ * structure that describes the queue to make the distinction.
* ---------------------------------------------------------------------------
*/
static CsrResult process_fh_cmd_queue(card_t *card, s32 *processed)
diff --git a/drivers/staging/csr/csr_wifi_hip_chiphelper.h b/drivers/staging/csr/csr_wifi_hip_chiphelper.h
index b6b67ee11db8..09b3aefcbced 100644
--- a/drivers/staging/csr/csr_wifi_hip_chiphelper.h
+++ b/drivers/staging/csr/csr_wifi_hip_chiphelper.h
@@ -354,7 +354,7 @@ CHIP_HELPER_LIST(C_DEC)
map that is part of the window and the size is the number of
visible words.
- Some of the windows have thier lowest portion covered by
+ Some of the windows have their lowest portion covered by
registers. For these windows address is the first address
after the registers and size is the siave excluding the part
covered by registers.
@@ -375,7 +375,7 @@ CHIP_HELPER_LIST(C_DEC)
will be needed if the device is being booted from cold. These
register writes enable the clocks and setup the PLL to a basic
working state. SPI access might be unreliable until these writes
- have occured (And they may take mulitple goes).
+ have occurred (And they may take mulitple goes).
*/
/* HostResetSequence
diff --git a/drivers/staging/csr/csr_wifi_hip_unifi.h b/drivers/staging/csr/csr_wifi_hip_unifi.h
index c2a2231680f5..1160a0e25c7d 100644
--- a/drivers/staging/csr/csr_wifi_hip_unifi.h
+++ b/drivers/staging/csr/csr_wifi_hip_unifi.h
@@ -117,9 +117,9 @@ typedef enum
UNIFI_TRAFFIC_Q_BE,
UNIFI_TRAFFIC_Q_VI,
UNIFI_TRAFFIC_Q_VO,
- UNIFI_TRAFFIC_Q_EAPOL, /* Non existant in HIP */
- UNIFI_TRAFFIC_Q_MAX, /* Non existant */
- UNIFI_TRAFFIC_Q_MLME /* Non existant */
+ UNIFI_TRAFFIC_Q_EAPOL, /* Non existent in HIP */
+ UNIFI_TRAFFIC_Q_MAX, /* Non existent */
+ UNIFI_TRAFFIC_Q_MLME /* Non existent */
} unifi_TrafficQueue;
/*
@@ -263,7 +263,7 @@ card_t* unifi_alloc_card(CsrSdioFunction *sdiopriv, void *ospriv);
*
* @return \b 0 if UniFi is initialized.
*
- * @return \b -CSR_EIO if an I/O error occured while initializing UniFi
+ * @return \b -CSR_EIO if an I/O error occurred while initializing UniFi
*
* @return \b -CSR_ENODEV if the card is no longer present.
*
@@ -311,7 +311,7 @@ void unifi_cancel_pending_signals(card_t *card);
*
* @return \b 0 signal is sent.
*
- * @return \b -CSR_EIO if an error occured while sending the signal
+ * @return \b -CSR_EIO if an error occurred while sending the signal
*
* @return \b -CSR_ENODEV if the card is no longer present.
*
@@ -361,7 +361,7 @@ void unifi_card_info(card_t *card, card_info_t *card_info);
*
* @return \b 0 if the check was performed.
*
- * @return \b -CSR_EIO if an error occured while checking the status.
+ * @return \b -CSR_EIO if an error occurred while checking the status.
*
* @return \b -CSR_ENODEV if the card is no longer present.
*
@@ -383,11 +383,11 @@ CsrResult unifi_check_io_status(card_t *card, s32 *status);
* is required. If unifi_bh() is called before the timeout expires,
* the caller must pass in the remaining time.
*
- * @return \b 0 if no error occured.
+ * @return \b 0 if no error occurred.
*
* @return \b -CSR_ENODEV if the card is no longer present.
*
- * @return \b -CSR_E* if an error occured while running the bottom half.
+ * @return \b -CSR_E* if an error occurred while running the bottom half.
*
* @ingroup upperedge
*/
@@ -439,7 +439,7 @@ enum unifi_periodic_wake_mode
*
* @param periodic_wake_mode the Periodic Wake Mode.
*
- * @return \b 0 if no error occured.
+ * @return \b 0 if no error occurred.
*
* @return \b -CSR_E* if the request failed.
*
@@ -458,7 +458,7 @@ CsrResult unifi_configure_low_power_mode(card_t *card,
*
* @param card the HIP core lib API context.
*
- * @return \b 0 if no error occured.
+ * @return \b 0 if no error occurred.
*
* @return \b -CSR_ENODEV if the card is no longer present.
*
diff --git a/drivers/staging/csr/drv.c b/drivers/staging/csr/drv.c
index 33742ba13779..bdc25236ab00 100644
--- a/drivers/staging/csr/drv.c
+++ b/drivers/staging/csr/drv.c
@@ -1815,7 +1815,7 @@ udi_log_event(ul_client_t *pcli,
}
/* Allocate log structure plus actual signal. */
- logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
+ logptr = kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
if (logptr == NULL) {
printk(KERN_ERR
@@ -1890,7 +1890,7 @@ uf_sme_queue_message(unifi_priv_t *priv, u8 *buffer, int length)
}
/* Allocate log structure plus actual signal. */
- logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + length, GFP_ATOMIC);
+ logptr = kmalloc(sizeof(udi_log_t) + length, GFP_ATOMIC);
if (logptr == NULL) {
unifi_error(priv, "Failed to allocate %d bytes for an SME message\n",
sizeof(udi_log_t) + length);
diff --git a/drivers/staging/csr/netdev.c b/drivers/staging/csr/netdev.c
index 7dad26f70175..a0177d998978 100644
--- a/drivers/staging/csr/netdev.c
+++ b/drivers/staging/csr/netdev.c
@@ -2365,7 +2365,7 @@ unifi_rx(unifi_priv_t *priv, CSR_SIGNAL *signal, bulk_data_param_t *bulkdata)
rx_buffered_packets_t *rx_q_item;
struct list_head *rx_list;
- rx_q_item = (rx_buffered_packets_t *)kmalloc(sizeof(rx_buffered_packets_t),
+ rx_q_item = kmalloc(sizeof(rx_buffered_packets_t),
GFP_KERNEL);
if (rx_q_item == NULL) {
unifi_error(priv, "%s: Failed to allocate %d bytes for rx packet record\n",
diff --git a/drivers/staging/csr/sdio_mmc.c b/drivers/staging/csr/sdio_mmc.c
index b6a16de08f4e..30271d35af55 100644
--- a/drivers/staging/csr/sdio_mmc.c
+++ b/drivers/staging/csr/sdio_mmc.c
@@ -1031,8 +1031,7 @@ uf_glue_sdio_probe(struct sdio_func *func,
sdio_func_id(func), instance);
/* Allocate context */
- sdio_ctx = (CsrSdioFunction *)kmalloc(sizeof(CsrSdioFunction),
- GFP_KERNEL);
+ sdio_ctx = kmalloc(sizeof(CsrSdioFunction), GFP_KERNEL);
if (sdio_ctx == NULL) {
sdio_release_host(func);
return -ENOMEM;
diff --git a/drivers/staging/csr/sme_native.c b/drivers/staging/csr/sme_native.c
index 525fe1bce0e6..ca55249bde3e 100644
--- a/drivers/staging/csr/sme_native.c
+++ b/drivers/staging/csr/sme_native.c
@@ -273,7 +273,7 @@ sme_native_log_event(ul_client_t *pcli,
}
/* Allocate log structure plus actual signal. */
- logptr = (udi_log_t *)kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
+ logptr = kmalloc(sizeof(udi_log_t) + total_len, GFP_KERNEL);
if (logptr == NULL) {
unifi_error(priv,
diff --git a/drivers/staging/csr/sme_wext.c b/drivers/staging/csr/sme_wext.c
index 5e06a380b40a..4129a6436b76 100644
--- a/drivers/staging/csr/sme_wext.c
+++ b/drivers/staging/csr/sme_wext.c
@@ -1273,7 +1273,6 @@ unifi_siwscan(struct net_device *dev, struct iw_request_info *info,
{
netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev);
unifi_priv_t *priv = interfacePriv->privPtr;
- int scantype;
int r;
CsrWifiSsid scan_ssid;
unsigned char *channel_list = NULL;
@@ -1293,8 +1292,6 @@ unifi_siwscan(struct net_device *dev, struct iw_request_info *info,
}
- scantype = UNIFI_SCAN_ACTIVE;
-
#if WIRELESS_EXT > 17
/* Providing a valid channel list will force an active scan */
if (req) {
diff --git a/drivers/staging/csr/unifi_pdu_processing.c b/drivers/staging/csr/unifi_pdu_processing.c
index 95efc360cc2d..f9b421b5aa35 100644
--- a/drivers/staging/csr/unifi_pdu_processing.c
+++ b/drivers/staging/csr/unifi_pdu_processing.c
@@ -403,7 +403,7 @@ CsrResult enque_tx_data_pdu(unifi_priv_t *priv, bulk_data_param_t *bulkdata,
- tx_q_item = (tx_buffered_packets_t *)kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
+ tx_q_item = kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
if (tx_q_item == NULL) {
unifi_error(priv,
"Failed to allocate %d bytes for tx packet record\n",
@@ -1468,7 +1468,7 @@ static int update_macheader(unifi_priv_t *priv, struct sk_buff *skb,
}
}
- /* prepare the complete skb, by pushing the MAC header to the begining of the skb->data */
+ /* prepare the complete skb, by pushing the MAC header to the beginning of the skb->data */
unifi_trace(priv, UDBG5, "updated Mac Header: %d \n",macHeaderLengthInBytes);
memcpy(bufPtr, macHeaderBuf, macHeaderLengthInBytes);
@@ -1546,7 +1546,7 @@ uf_ap_process_data_pdu(unifi_priv_t *priv, struct sk_buff *skb,
return -1;
}
- /* fetch the destination record from staion record database */
+ /* fetch the destination record from station record database */
dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, ehdr->h_dest, interfaceTag);
/* AP mode processing, & if packet is unicast */
@@ -1878,13 +1878,13 @@ CsrResult uf_process_ma_packet_req(unifi_priv_t *priv,
}
else if ((pktType == CSR_WIFI_MULTICAST_PDU) && (!status))
{
- /* If broadcast Tim is set && queuing is successfull, then only update TIM */
+ /* If broadcast Tim is set && queuing is successful, then only update TIM */
spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
interfacePriv->noOfbroadcastPktQueued++;
spin_unlock_irqrestore(&priv->staRecord_lock,lock_flags);
}
}
- /* If broadcast Tim is set && queuing is successfull, then only update TIM */
+ /* If broadcast Tim is set && queuing is successful, then only update TIM */
if(setBcTim && !status) {
unifi_trace(priv, UDBG3, "tim set due to broadcast pkt\n");
if (!interfacePriv->bcTimSetReqPendingFlag)
@@ -1995,7 +1995,7 @@ s8 uf_get_protection_bit_from_interfacemode(unifi_priv_t *priv, u16 interfaceTag
*/
protection = interfacePriv->protect;
} else {
- /* fetch the destination record from staion record database */
+ /* fetch the destination record from station record database */
dstStaInfo = CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(priv, daddr, interfaceTag);
if (!dstStaInfo) {
unifi_trace(priv, UDBG3, "peer not found in station record in send_ma_pkt_request\n");
@@ -3170,7 +3170,7 @@ void uf_process_ps_poll(unifi_priv_t *priv,u8* sa,u8* da,u8 pmBit,u16 interfaceT
/*Send Data From Management Frames*/
/* Priority orders for delivering the buffered packets are
* 1. Deliver the Management frames if there
- * 2. Other access catagory frames which are non deliver enable including UNIFI_TRAFFIC_Q_VO
+ * 2. Other access category frames which are non deliver enable including UNIFI_TRAFFIC_Q_VO
* priority is from VO->BK
*/
@@ -3282,7 +3282,7 @@ void add_to_send_cfm_list(unifi_priv_t * priv,
{
tx_buffered_packets_t *send_cfm_list_item = NULL;
- send_cfm_list_item = (tx_buffered_packets_t *) kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
+ send_cfm_list_item = kmalloc(sizeof(tx_buffered_packets_t), GFP_ATOMIC);
if(send_cfm_list_item == NULL){
unifi_warning(priv, "%s: Failed to allocate memory for new list item \n");
@@ -3439,7 +3439,7 @@ CsrWifiRouterCtrlStaInfo_t *CsrWifiRouterCtrlGetStationRecordFromPeerMacAddress(
interfacePriv = priv->interfacePriv[interfaceTag];
- /* disable the preemption untill station record is fetched */
+ /* disable the preemption until station record is fetched */
spin_lock_irqsave(&priv->staRecord_lock,lock_flags);
for (i = 0; i < UNIFI_MAX_CONNECTIONS; i++) {
@@ -3665,7 +3665,7 @@ void update_eosp_to_head_of_broadcast_list_head(unifi_priv_t *priv,u16 interface
if (interfacePriv->noOfbroadcastPktQueued) {
/* Update the EOSP to the HEAD of b/c list
- * beacuse we have received any mgmt packet so it should not hold for long time
+ * because we have received any mgmt packet so it should not hold for long time
* peer may time out.
*/
spin_lock_irqsave(&priv->tx_q_lock,lock_flags);
diff --git a/drivers/staging/csr/unifi_sme.c b/drivers/staging/csr/unifi_sme.c
index 7d19e632a5e4..90295035621f 100644
--- a/drivers/staging/csr/unifi_sme.c
+++ b/drivers/staging/csr/unifi_sme.c
@@ -876,6 +876,8 @@ int unifi_cfg_get_info(unifi_priv_t *priv, unsigned char *arg)
{
#ifdef CSR_SUPPORT_WEXT_AP
uf_cfg_ap_config_t cfg_ap_config;
+
+ memset(&cfg_ap_config, 0, sizeof(cfg_ap_config));
cfg_ap_config.channel = priv->ap_config.channel;
cfg_ap_config.beaconInterval = priv->ap_mac_config.beaconInterval;
cfg_ap_config.wmmEnabled = priv->ap_mac_config.wmmEnabled;
diff --git a/drivers/staging/cxt1e1/pmcc4_drv.c b/drivers/staging/cxt1e1/pmcc4_drv.c
index 8a7b3a646451..8d8a22be5b2e 100644
--- a/drivers/staging/cxt1e1/pmcc4_drv.c
+++ b/drivers/staging/cxt1e1/pmcc4_drv.c
@@ -1545,6 +1545,7 @@ c4_get_iidinfo (ci_t * ci, struct sbe_iid_info * iip)
np = dev->name;
strncpy (iip->iname, np, CHNM_STRLEN - 1);
+ iip->iname[CHNM_STRLEN - 1] = '\0';
return 0;
}
diff --git a/drivers/staging/dgrp/dgrp_common.h b/drivers/staging/dgrp/dgrp_common.h
index 076dd6bc5ac4..23aba6c4d22c 100644
--- a/drivers/staging/dgrp/dgrp_common.h
+++ b/drivers/staging/dgrp/dgrp_common.h
@@ -66,7 +66,7 @@ extern const struct file_operations dgrp_dpa_ops;
extern void dgrp_dpa_data(struct nd_struct *, int, u8 *, int);
/* from dgrp_sysfs.c */
-extern void dgrp_create_class_sysfs_files(void);
+extern int dgrp_create_class_sysfs_files(void);
extern void dgrp_remove_class_sysfs_files(void);
extern void dgrp_create_node_class_sysfs_files(struct nd_struct *nd);
diff --git a/drivers/staging/dgrp/dgrp_dpa_ops.c b/drivers/staging/dgrp/dgrp_dpa_ops.c
index 1fc13de4bdd6..114799cddd85 100644
--- a/drivers/staging/dgrp/dgrp_dpa_ops.c
+++ b/drivers/staging/dgrp/dgrp_dpa_ops.c
@@ -409,6 +409,7 @@ static long dgrp_dpa_ioctl(struct file *file, unsigned int cmd,
case DIGI_GETVPD:
+ memset(&vpd, 0, sizeof(vpd));
if (nd->nd_vpd_len > 0) {
vpd.vpd_len = nd->nd_vpd_len;
memcpy(&vpd.vpd_data, &nd->nd_vpd, nd->nd_vpd_len);
diff --git a/drivers/staging/dgrp/dgrp_driver.c b/drivers/staging/dgrp/dgrp_driver.c
index aa262588e9b9..e456dc6cb367 100644
--- a/drivers/staging/dgrp/dgrp_driver.c
+++ b/drivers/staging/dgrp/dgrp_driver.c
@@ -66,6 +66,8 @@ module_exit(dgrp_cleanup_module);
*/
static int dgrp_init_module(void)
{
+ int ret;
+
INIT_LIST_HEAD(&nd_struct_list);
spin_lock_init(&dgrp_poll_data.poll_lock);
@@ -74,7 +76,9 @@ static int dgrp_init_module(void)
dgrp_poll_data.timer.function = dgrp_poll_handler;
dgrp_poll_data.timer.data = (unsigned long) &dgrp_poll_data;
- dgrp_create_class_sysfs_files();
+ ret = dgrp_create_class_sysfs_files();
+ if (ret)
+ return ret;
dgrp_register_proc();
diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c
index 9914f1c5bcd3..5b7833f593ff 100644
--- a/drivers/staging/dgrp/dgrp_net_ops.c
+++ b/drivers/staging/dgrp/dgrp_net_ops.c
@@ -3381,7 +3381,7 @@ static long dgrp_net_ioctl(struct file *file, unsigned int cmd,
if (size != sizeof(struct link_struct))
return -EINVAL;
- if (copy_from_user((void *)(&link), (void __user *) arg, size))
+ if (copy_from_user(&link, (void __user *)arg, size))
return -EFAULT;
if (link.lk_fast_rate < 9600)
diff --git a/drivers/staging/dgrp/dgrp_sysfs.c b/drivers/staging/dgrp/dgrp_sysfs.c
index be179adfb7c7..7d1b36d1e75f 100644
--- a/drivers/staging/dgrp/dgrp_sysfs.c
+++ b/drivers/staging/dgrp/dgrp_sysfs.c
@@ -85,30 +85,50 @@ static struct attribute_group dgrp_global_settings_attribute_group = {
-void dgrp_create_class_sysfs_files(void)
+int dgrp_create_class_sysfs_files(void)
{
int ret = 0;
int max_majors = 1U << (32 - MINORBITS);
dgrp_class = class_create(THIS_MODULE, "digi_realport");
+ if (IS_ERR(dgrp_class))
+ return PTR_ERR(dgrp_class);
ret = class_create_file(dgrp_class, &class_attr_driver_version);
+ if (ret)
+ goto err_class;
dgrp_class_global_settings_dev = device_create(dgrp_class, NULL,
MKDEV(0, max_majors + 1), NULL, "driver_settings");
-
+ if (IS_ERR(dgrp_class_global_settings_dev)) {
+ ret = PTR_ERR(dgrp_class_global_settings_dev);
+ goto err_file;
+ }
ret = sysfs_create_group(&dgrp_class_global_settings_dev->kobj,
&dgrp_global_settings_attribute_group);
if (ret) {
pr_alert("%s: failed to create sysfs global settings device attributes.\n",
__func__);
- sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
- &dgrp_global_settings_attribute_group);
- return;
+ goto err_dev1;
}
dgrp_class_nodes_dev = device_create(dgrp_class, NULL,
MKDEV(0, max_majors + 2), NULL, "nodes");
+ if (IS_ERR(dgrp_class_nodes_dev)) {
+ ret = PTR_ERR(dgrp_class_nodes_dev);
+ goto err_group;
+ }
+ return 0;
+err_group:
+ sysfs_remove_group(&dgrp_class_global_settings_dev->kobj,
+ &dgrp_global_settings_attribute_group);
+err_dev1:
+ device_destroy(dgrp_class, MKDEV(0, max_majors + 1));
+err_file:
+ class_remove_file(dgrp_class, &class_attr_driver_version);
+err_class:
+ class_destroy(dgrp_class);
+ return ret;
}
diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig
new file mode 100644
index 000000000000..f0b4739c65a1
--- /dev/null
+++ b/drivers/staging/dwc2/Kconfig
@@ -0,0 +1,54 @@
+config USB_DWC2
+ tristate "DesignWare USB2 DRD Core Support"
+ depends on USB
+ depends on VIRT_TO_BUS
+ select USB_OTG_UTILS
+ help
+ Say Y or M here if your system has a Dual Role HighSpeed
+ USB controller based on the DesignWare HSOTG IP Core.
+
+ If you choose to build this driver as dynamically linked
+ modules, the core module will be called dwc2.ko, the
+ PCI bus interface module (if you have a PCI bus system)
+ will be called dwc2_pci.ko and the platform interface module
+ (for controllers directly connected to the CPU) will be called
+ dwc2_platform.ko.
+
+ NOTE: This driver at present only implements the Host mode
+ of the controller. The existing s3c-hsotg driver supports
+ Peripheral mode, but only for the Samsung S3C platforms.
+ There are plans to merge the s3c-hsotg driver with this
+ driver in the near future to create a dual-role driver.
+
+if USB_DWC2
+
+config USB_DWC2_DEBUG
+ bool "Enable Debugging Messages"
+ help
+ Say Y here to enable debugging messages in the DWC2 Driver.
+
+config USB_DWC2_VERBOSE
+ bool "Enable Verbose Debugging Messages"
+ depends on USB_DWC2_DEBUG
+ help
+ Say Y here to enable verbose debugging messages in the DWC2 Driver.
+ WARNING: Enabling this will quickly fill your message log.
+ If in doubt, say N.
+
+config USB_DWC2_TRACK_MISSED_SOFS
+ bool "Enable Missed SOF Tracking"
+ help
+ Say Y here to enable logging of missed SOF events to the dmesg log.
+ If in doubt, say N.
+
+config USB_DWC2_DEBUG_PERIODIC
+ bool "Enable Debugging Messages For Periodic Transfers"
+ depends on USB_DWC2_DEBUG || USB_DWC2_VERBOSE
+ default y
+ help
+ Say N here to disable (verbose) debugging messages to be
+ logged for periodic transfers. This allows better debugging of
+ non-periodic transfers, but of course the debug logs will be
+ incomplete. Note that this also disables some debug messages
+ for which the transfer type cannot be deduced.
+endif
diff --git a/drivers/staging/dwc2/Makefile b/drivers/staging/dwc2/Makefile
new file mode 100644
index 000000000000..11529d3439b0
--- /dev/null
+++ b/drivers/staging/dwc2/Makefile
@@ -0,0 +1,25 @@
+ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC2) += dwc2.o
+
+dwc2-y += core.o core_intr.o
+
+# NOTE: This driver at present only implements the Host mode
+# of the controller. The existing s3c-hsotg driver supports
+# Peripheral mode, but only for the Samsung S3C platforms.
+# There are plans to merge the s3c-hsotg driver with this
+# driver in the near future to create a dual-role driver. Once
+# that is done, Host mode will become an optional feature that
+# is selected with a config option.
+
+dwc2-y += hcd.o hcd_intr.o
+dwc2-y += hcd_queue.o hcd_ddma.o
+
+ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_USB_DWC2) += dwc2_pci.o
+endif
+obj-$(CONFIG_USB_DWC2) += dwc2_platform.o
+
+dwc2_pci-y += pci.o
+dwc2_platform-y += platform.o
diff --git a/drivers/staging/dwc2/core.c b/drivers/staging/dwc2/core.c
new file mode 100644
index 000000000000..3177db2380bf
--- /dev/null
+++ b/drivers/staging/dwc2/core.c
@@ -0,0 +1,2759 @@
+/*
+ * core.c - DesignWare HS OTG Controller common routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The Core code provides basic services for accessing and managing the
+ * DWC_otg hardware. These services are used by both the Host Controller
+ * Driver and the Peripheral Controller Driver.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_enable_common_interrupts() - Initializes the commmon interrupts,
+ * used in both device and host modes
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ */
+static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk;
+
+ /* Clear any pending OTG Interrupts */
+ writel(0xffffffff, hsotg->regs + GOTGINT);
+
+ /* Clear any pending interrupts */
+ writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Enable the interrupts in the GINTMSK */
+ intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
+
+ if (hsotg->core_params->dma_enable <= 0)
+ intmsk |= GINTSTS_RXFLVL;
+
+ intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP |
+ GINTSTS_SESSREQINT;
+
+ writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/*
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the
+ * PHY type
+ */
+static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
+{
+ u32 hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
+ u32 fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
+ u32 hcfg, val;
+
+ if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ hsotg->core_params->ulpi_fs_ls > 0) ||
+ hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+ /* Full speed PHY */
+ val = HCFG_FSLSPCLKSEL_48_MHZ;
+ } else {
+ /* High speed PHY running at full speed or high speed */
+ val = HCFG_FSLSPCLKSEL_30_60_MHZ;
+ }
+
+ dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
+ hcfg = readl(hsotg->regs + HCFG);
+ hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+ hcfg |= val;
+ writel(hcfg, hsotg->regs + HCFG);
+}
+
+/*
+ * Do core a soft reset of the core. Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+static void dwc2_core_reset(struct dwc2_hsotg *hsotg)
+{
+ u32 greset;
+ int count = 0;
+
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Wait for AHB master IDLE state */
+ do {
+ usleep_range(20000, 40000);
+ greset = readl(hsotg->regs + GRSTCTL);
+ if (++count > 50) {
+ dev_warn(hsotg->dev,
+ "%s() HANG! AHB Idle GRSTCTL=%0x\n",
+ __func__, greset);
+ return;
+ }
+ } while (!(greset & GRSTCTL_AHBIDLE));
+
+ /* Core Soft Reset */
+ count = 0;
+ greset |= GRSTCTL_CSFTRST;
+ writel(greset, hsotg->regs + GRSTCTL);
+ do {
+ usleep_range(20000, 40000);
+ greset = readl(hsotg->regs + GRSTCTL);
+ if (++count > 50) {
+ dev_warn(hsotg->dev,
+ "%s() HANG! Soft Reset GRSTCTL=%0x\n",
+ __func__, greset);
+ break;
+ }
+ } while (greset & GRSTCTL_CSFTRST);
+
+ /*
+ * NOTE: This long sleep is _very_ important, otherwise the core will
+ * not stay in host mode after a connector ID change!
+ */
+ usleep_range(150000, 200000);
+}
+
+static void dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg, i2cctl;
+
+ /*
+ * core_init() is now called on every switch so only call the
+ * following for the first time through
+ */
+ if (select_phy) {
+ dev_dbg(hsotg->dev, "FS PHY selected\n");
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_PHYSEL;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Reset after a PHY select */
+ dwc2_core_reset(hsotg);
+ }
+
+ /*
+ * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also
+ * do this on HNP Dev/Host mode switches (done in dev_init and
+ * host_init).
+ */
+ if (dwc2_is_host_mode(hsotg))
+ dwc2_init_fs_ls_pclk_sel(hsotg);
+
+ if (hsotg->core_params->i2c_enable > 0) {
+ dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
+
+ /* Program GUSBCFG.OtgUtmiFsSel to I2C */
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Program GI2CCTL.I2CEn */
+ i2cctl = readl(hsotg->regs + GI2CCTL);
+ i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
+ i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
+ i2cctl &= ~GI2CCTL_I2CEN;
+ writel(i2cctl, hsotg->regs + GI2CCTL);
+ i2cctl |= GI2CCTL_I2CEN;
+ writel(i2cctl, hsotg->regs + GI2CCTL);
+ }
+}
+
+static void dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg;
+
+ if (!select_phy)
+ return;
+
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+
+ /*
+ * HS PHY parameters. These parameters are preserved during soft reset
+ * so only program the first time. Do a soft reset immediately after
+ * setting phyif.
+ */
+ switch (hsotg->core_params->phy_type) {
+ case DWC2_PHY_TYPE_PARAM_ULPI:
+ /* ULPI interface */
+ dev_dbg(hsotg->dev, "HS ULPI PHY selected\n");
+ usbcfg |= GUSBCFG_ULPI_UTMI_SEL;
+ usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
+ if (hsotg->core_params->phy_ulpi_ddr > 0)
+ usbcfg |= GUSBCFG_DDRSEL;
+ break;
+ case DWC2_PHY_TYPE_PARAM_UTMI:
+ /* UTMI+ interface */
+ dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n");
+ usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16);
+ if (hsotg->core_params->phy_utmi_width == 16)
+ usbcfg |= GUSBCFG_PHYIF16;
+ break;
+ default:
+ dev_err(hsotg->dev, "FS PHY selected at HS!\n");
+ break;
+ }
+
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Reset after setting the PHY parameters */
+ dwc2_core_reset(hsotg);
+}
+
+static void dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
+{
+ u32 usbcfg, hs_phy_type, fs_phy_type;
+
+ if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL &&
+ hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) {
+ /* If FS mode with FS PHY */
+ dwc2_fs_phy_init(hsotg, select_phy);
+ } else {
+ /* High speed PHY */
+ dwc2_hs_phy_init(hsotg, select_phy);
+ }
+
+ hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
+ fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
+
+ if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI &&
+ fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
+ hsotg->core_params->ulpi_fs_ls > 0) {
+ dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ usbcfg |= GUSBCFG_ULPI_FS_LS;
+ usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+ } else {
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ usbcfg &= ~GUSBCFG_ULPI_FS_LS;
+ usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+ }
+}
+
+static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
+{
+ u32 ahbcfg = 0;
+
+ switch (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) {
+ case GHWCFG2_EXT_DMA_ARCH:
+ dev_err(hsotg->dev, "External DMA Mode not supported\n");
+ return -EINVAL;
+
+ case GHWCFG2_INT_DMA_ARCH:
+ dev_dbg(hsotg->dev, "Internal DMA Mode\n");
+ /*
+ * Old value was GAHBCFG_HBSTLEN_INCR - done for
+ * Host mode ISOC in issue fix - vahrama
+ */
+ ahbcfg |= GAHBCFG_HBSTLEN_INCR4;
+ break;
+
+ case GHWCFG2_SLAVE_ONLY_ARCH:
+ default:
+ dev_dbg(hsotg->dev, "Slave Only Mode\n");
+ break;
+ }
+
+ dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n",
+ hsotg->core_params->dma_enable,
+ hsotg->core_params->dma_desc_enable);
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (hsotg->core_params->dma_desc_enable > 0)
+ dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n");
+ else
+ dev_dbg(hsotg->dev, "Using Buffer DMA mode\n");
+ } else {
+ dev_dbg(hsotg->dev, "Using Slave mode\n");
+ hsotg->core_params->dma_desc_enable = 0;
+ }
+
+ if (hsotg->core_params->ahb_single > 0)
+ ahbcfg |= GAHBCFG_AHB_SINGLE;
+
+ if (hsotg->core_params->dma_enable > 0)
+ ahbcfg |= GAHBCFG_DMA_EN;
+
+ writel(ahbcfg, hsotg->regs + GAHBCFG);
+
+ return 0;
+}
+
+static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
+
+ switch (hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK) {
+ case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+ if (hsotg->core_params->otg_cap ==
+ DWC2_CAP_PARAM_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_HNPCAP;
+ if (hsotg->core_params->otg_cap !=
+ DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_SRPCAP;
+ break;
+
+ case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+ if (hsotg->core_params->otg_cap !=
+ DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE)
+ usbcfg |= GUSBCFG_SRPCAP;
+ break;
+
+ case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE:
+ case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST:
+ default:
+ break;
+ }
+
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+}
+
+/**
+ * dwc2_core_init() - Initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ * @select_phy: If true then also set the Phy type
+ * @irq: If >= 0, the irq to register
+ */
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
+{
+ u32 usbcfg, otgctl;
+ int retval;
+
+ dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+
+ /* Set ULPI External VBUS bit if needed */
+ usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
+ if (hsotg->core_params->phy_ulpi_ext_vbus ==
+ DWC2_PHY_ULPI_EXTERNAL_VBUS)
+ usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV;
+
+ /* Set external TS Dline pulsing bit if needed */
+ usbcfg &= ~GUSBCFG_TERMSELDLPULSE;
+ if (hsotg->core_params->ts_dline > 0)
+ usbcfg |= GUSBCFG_TERMSELDLPULSE;
+
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+
+ /* Reset the Controller */
+ dwc2_core_reset(hsotg);
+
+ dev_dbg(hsotg->dev, "num_dev_perio_in_ep=%d\n",
+ hsotg->hwcfg4 >> GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT &
+ GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK >>
+ GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT);
+
+ hsotg->total_fifo_size = hsotg->hwcfg3 >> GHWCFG3_DFIFO_DEPTH_SHIFT &
+ GHWCFG3_DFIFO_DEPTH_MASK >> GHWCFG3_DFIFO_DEPTH_SHIFT;
+ hsotg->rx_fifo_size = readl(hsotg->regs + GRXFSIZ);
+ hsotg->nperio_tx_fifo_size =
+ readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
+
+ dev_dbg(hsotg->dev, "Total FIFO SZ=%d\n", hsotg->total_fifo_size);
+ dev_dbg(hsotg->dev, "RxFIFO SZ=%d\n", hsotg->rx_fifo_size);
+ dev_dbg(hsotg->dev, "NP TxFIFO SZ=%d\n", hsotg->nperio_tx_fifo_size);
+
+ /*
+ * This needs to happen in FS mode before any other programming occurs
+ */
+ dwc2_phy_init(hsotg, select_phy);
+
+ /* Program the GAHBCFG Register */
+ retval = dwc2_gahbcfg_init(hsotg);
+ if (retval)
+ return retval;
+
+ /* Program the GUSBCFG register */
+ dwc2_gusbcfg_init(hsotg);
+
+ /* Program the GOTGCTL register */
+ otgctl = readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_OTGVER;
+ if (hsotg->core_params->otg_ver > 0)
+ otgctl |= GOTGCTL_OTGVER;
+ writel(otgctl, hsotg->regs + GOTGCTL);
+ dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver);
+
+ /* Clear the SRP success bit for FS-I2c */
+ hsotg->srp_success = 0;
+
+ if (irq >= 0) {
+ dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+ irq);
+ retval = devm_request_irq(hsotg->dev, irq,
+ dwc2_handle_common_intr, IRQF_SHARED,
+ dev_name(hsotg->dev), hsotg);
+ if (retval)
+ return retval;
+ }
+
+ /* Enable common interrupts */
+ dwc2_enable_common_interrupts(hsotg);
+
+ /*
+ * Do device or host intialization based on mode during PCD and
+ * HCD initialization
+ */
+ if (dwc2_is_host_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "Host Mode\n");
+ hsotg->op_state = OTG_STATE_A_HOST;
+ } else {
+ dev_dbg(hsotg->dev, "Device Mode\n");
+ hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+ }
+
+ return 0;
+}
+
+/**
+ * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Disable all interrupts */
+ writel(0, hsotg->regs + GINTMSK);
+ writel(0, hsotg->regs + HAINTMSK);
+
+ /* Clear any pending interrupts */
+ writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ /* Enable the common interrupts */
+ dwc2_enable_common_interrupts(hsotg);
+
+ /* Enable host mode interrupts without disturbing common interrupts */
+ intmsk = readl(hsotg->regs + GINTMSK);
+ intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
+ writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+/**
+ * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 intmsk = readl(hsotg->regs + GINTMSK);
+
+ /* Disable host mode interrupts without disturbing common interrupts */
+ intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
+ GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP);
+ writel(intmsk, hsotg->regs + GINTMSK);
+}
+
+static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *params = hsotg->core_params;
+ u32 rxfsiz, nptxfsiz, ptxfsiz, hptxfsiz, dfifocfg;
+
+ if (!(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO) ||
+ !params->enable_dynamic_fifo)
+ return;
+
+ dev_dbg(hsotg->dev, "Total FIFO Size=%d\n", hsotg->total_fifo_size);
+ dev_dbg(hsotg->dev, "Rx FIFO Size=%d\n", params->host_rx_fifo_size);
+ dev_dbg(hsotg->dev, "NP Tx FIFO Size=%d\n",
+ params->host_nperio_tx_fifo_size);
+ dev_dbg(hsotg->dev, "P Tx FIFO Size=%d\n",
+ params->host_perio_tx_fifo_size);
+
+ /* Rx FIFO */
+ dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n",
+ readl(hsotg->regs + GRXFSIZ));
+ writel(params->host_rx_fifo_size, hsotg->regs + GRXFSIZ);
+ dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ));
+
+ /* Non-periodic Tx FIFO */
+ dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
+ readl(hsotg->regs + GNPTXFSIZ));
+ nptxfsiz = params->host_nperio_tx_fifo_size <<
+ FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+ nptxfsiz |= params->host_rx_fifo_size <<
+ FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+ writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
+ dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
+ readl(hsotg->regs + GNPTXFSIZ));
+
+ /* Periodic Tx FIFO */
+ dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
+ readl(hsotg->regs + HPTXFSIZ));
+ ptxfsiz = params->host_perio_tx_fifo_size <<
+ FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
+ ptxfsiz |= (params->host_rx_fifo_size +
+ params->host_nperio_tx_fifo_size) <<
+ FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
+ writel(ptxfsiz, hsotg->regs + HPTXFSIZ);
+ dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
+ readl(hsotg->regs + HPTXFSIZ));
+
+ if (hsotg->core_params->en_multiple_tx_fifo > 0 &&
+ hsotg->snpsid <= DWC2_CORE_REV_2_94a) {
+ /*
+ * Global DFIFOCFG calculation for Host mode -
+ * include RxFIFO, NPTXFIFO and HPTXFIFO
+ */
+ dfifocfg = readl(hsotg->regs + GDFIFOCFG);
+ rxfsiz = readl(hsotg->regs + GRXFSIZ) & 0x0000ffff;
+ nptxfsiz = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
+ hptxfsiz = readl(hsotg->regs + HPTXFSIZ) >> 16 & 0xffff;
+ dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
+ dfifocfg |= (rxfsiz + nptxfsiz + hptxfsiz) <<
+ GDFIFOCFG_EPINFOBASE_SHIFT &
+ GDFIFOCFG_EPINFOBASE_MASK;
+ writel(dfifocfg, hsotg->regs + GDFIFOCFG);
+ }
+}
+
+/**
+ * dwc2_core_host_init() - Initializes the DWC_otg controller registers for
+ * Host mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * This function flushes the Tx and Rx FIFOs and flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ */
+void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
+{
+ u32 hcfg, hfir, otgctl;
+
+ dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+ /* Restart the Phy Clock */
+ writel(0, hsotg->regs + PCGCTL);
+
+ /* Initialize Host Configuration Register */
+ dwc2_init_fs_ls_pclk_sel(hsotg);
+ if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) {
+ hcfg = readl(hsotg->regs + HCFG);
+ hcfg |= HCFG_FSLSSUPP;
+ writel(hcfg, hsotg->regs + HCFG);
+ }
+
+ /*
+ * This bit allows dynamic reloading of the HFIR register during
+ * runtime. This bit needs to be programmed during inital configuration
+ * and its value must not be changed during runtime.
+ */
+ if (hsotg->core_params->reload_ctl > 0) {
+ hfir = readl(hsotg->regs + HFIR);
+ hfir |= HFIR_RLDCTRL;
+ writel(hfir, hsotg->regs + HFIR);
+ }
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ u32 op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
+
+ if (hsotg->snpsid < DWC2_CORE_REV_2_90a ||
+ !(hsotg->hwcfg4 & GHWCFG4_DESC_DMA) ||
+ op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE ||
+ op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE ||
+ op_mode == GHWCFG2_OP_MODE_UNDEFINED) {
+ dev_err(hsotg->dev,
+ "Hardware does not support descriptor DMA mode -\n");
+ dev_err(hsotg->dev,
+ "falling back to buffer DMA mode.\n");
+ hsotg->core_params->dma_desc_enable = 0;
+ } else {
+ hcfg = readl(hsotg->regs + HCFG);
+ hcfg |= HCFG_DESCDMA;
+ writel(hcfg, hsotg->regs + HCFG);
+ }
+ }
+
+ /* Configure data FIFO sizes */
+ dwc2_config_fifos(hsotg);
+
+ /* TODO - check this */
+ /* Clear Host Set HNP Enable in the OTG Control Register */
+ otgctl = readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_HSTSETHNPEN;
+ writel(otgctl, hsotg->regs + GOTGCTL);
+
+ /* Make sure the FIFOs are flushed */
+ dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
+ dwc2_flush_rx_fifo(hsotg);
+
+ /* Clear Host Set HNP Enable in the OTG Control Register */
+ otgctl = readl(hsotg->regs + GOTGCTL);
+ otgctl &= ~GOTGCTL_HSTSETHNPEN;
+ writel(otgctl, hsotg->regs + GOTGCTL);
+
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ int num_channels, i;
+ u32 hcchar;
+
+ /* Flush out any leftover queued requests */
+ num_channels = hsotg->core_params->host_channels;
+ for (i = 0; i < num_channels; i++) {
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ hcchar &= ~HCCHAR_CHENA;
+ hcchar |= HCCHAR_CHDIS;
+ hcchar &= ~HCCHAR_EPDIR;
+ writel(hcchar, hsotg->regs + HCCHAR(i));
+ }
+
+ /* Halt all channels to put them into a known state */
+ for (i = 0; i < num_channels; i++) {
+ int count = 0;
+
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
+ hcchar &= ~HCCHAR_EPDIR;
+ writel(hcchar, hsotg->regs + HCCHAR(i));
+ dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
+ __func__, i);
+ do {
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ if (++count > 1000) {
+ dev_err(hsotg->dev,
+ "Unable to clear enable on channel %d\n",
+ i);
+ break;
+ }
+ udelay(1);
+ } while (hcchar & HCCHAR_CHENA);
+ }
+ }
+
+ /* Turn on the vbus power */
+ dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
+ if (hsotg->op_state == OTG_STATE_A_HOST) {
+ u32 hprt0 = dwc2_read_hprt0(hsotg);
+
+ dev_dbg(hsotg->dev, "Init: Power Port (%d)\n",
+ !!(hprt0 & HPRT0_PWR));
+ if (!(hprt0 & HPRT0_PWR)) {
+ hprt0 |= HPRT0_PWR;
+ writel(hprt0, hsotg->regs + HPRT0);
+ }
+ }
+
+ dwc2_enable_host_interrupts(hsotg);
+}
+
+static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ switch (chan->ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ dev_vdbg(hsotg->dev, "control/bulk\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_STALL;
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_BBLERR;
+ } else {
+ hcintmsk |= HCINTMSK_NAK;
+ hcintmsk |= HCINTMSK_NYET;
+ if (chan->do_ping)
+ hcintmsk |= HCINTMSK_ACK;
+ }
+
+ if (chan->do_split) {
+ hcintmsk |= HCINTMSK_NAK;
+ if (chan->complete_split)
+ hcintmsk |= HCINTMSK_NYET;
+ else
+ hcintmsk |= HCINTMSK_ACK;
+ }
+
+ if (chan->error_state)
+ hcintmsk |= HCINTMSK_ACK;
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "intr\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_NAK;
+ hcintmsk |= HCINTMSK_STALL;
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ hcintmsk |= HCINTMSK_FRMOVRUN;
+
+ if (chan->ep_is_in)
+ hcintmsk |= HCINTMSK_BBLERR;
+ if (chan->error_state)
+ hcintmsk |= HCINTMSK_ACK;
+ if (chan->do_split) {
+ if (chan->complete_split)
+ hcintmsk |= HCINTMSK_NYET;
+ else
+ hcintmsk |= HCINTMSK_ACK;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "isoc\n");
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ hcintmsk |= HCINTMSK_FRMOVRUN;
+ hcintmsk |= HCINTMSK_ACK;
+
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_XACTERR;
+ hcintmsk |= HCINTMSK_BBLERR;
+ }
+ break;
+ default:
+ dev_err(hsotg->dev, "## Unknown EP type ##\n");
+ break;
+ }
+
+ writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ /*
+ * For Descriptor DMA mode core halts the channel on AHB error.
+ * Interrupt is not required.
+ */
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+ hcintmsk |= HCINTMSK_AHBERR;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA enabled\n");
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ hcintmsk |= HCINTMSK_XFERCOMPL;
+ }
+
+ if (chan->error_state && !chan->do_split &&
+ chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "setting ACK\n");
+ hcintmsk |= HCINTMSK_ACK;
+ if (chan->ep_is_in) {
+ hcintmsk |= HCINTMSK_DATATGLERR;
+ if (chan->ep_type != USB_ENDPOINT_XFER_INT)
+ hcintmsk |= HCINTMSK_NAK;
+ }
+ }
+
+ writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
+}
+
+static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 intmsk;
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA enabled\n");
+ dwc2_hc_enable_dma_ints(hsotg, chan);
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA disabled\n");
+ dwc2_hc_enable_slave_ints(hsotg, chan);
+ }
+
+ /* Enable the top level host channel interrupt */
+ intmsk = readl(hsotg->regs + HAINTMSK);
+ intmsk |= 1 << chan->hc_num;
+ writel(intmsk, hsotg->regs + HAINTMSK);
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
+
+ /* Make sure host channel interrupts are enabled */
+ intmsk = readl(hsotg->regs + GINTMSK);
+ intmsk |= GINTSTS_HCHINT;
+ writel(intmsk, hsotg->regs + GINTMSK);
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
+}
+
+/**
+ * dwc2_hc_init() - Prepares a host channel for transferring packets to/from
+ * a specific endpoint
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * The HCCHARn register is set up with the characteristics specified in chan.
+ * Host channel interrupts that may need to be serviced while this transfer is
+ * in progress are enabled.
+ */
+void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+ u8 hc_num = chan->hc_num;
+ u32 hcintmsk;
+ u32 hcchar;
+ u32 hcsplt = 0;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Clear old interrupt conditions for this host channel */
+ hcintmsk = 0xffffffff;
+ hcintmsk &= ~HCINTMSK_RESERVED14_31;
+ writel(hcintmsk, hsotg->regs + HCINT(hc_num));
+
+ /* Enable channel interrupts required for this transfer */
+ dwc2_hc_enable_ints(hsotg, chan);
+
+ /*
+ * Program the HCCHARn register with the endpoint characteristics for
+ * the current transfer
+ */
+ hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK;
+ hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK;
+ if (chan->ep_is_in)
+ hcchar |= HCCHAR_EPDIR;
+ if (chan->speed == USB_SPEED_LOW)
+ hcchar |= HCCHAR_LSPDDEV;
+ hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
+ hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
+ writel(hcchar, hsotg->regs + HCCHAR(hc_num));
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
+ hc_num, hcchar);
+
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, hc_num);
+ dev_vdbg(hsotg->dev, " Dev Addr: %d\n",
+ hcchar >> HCCHAR_DEVADDR_SHIFT &
+ HCCHAR_DEVADDR_MASK >> HCCHAR_DEVADDR_SHIFT);
+ dev_vdbg(hsotg->dev, " Ep Num: %d\n",
+ hcchar >> HCCHAR_EPNUM_SHIFT &
+ HCCHAR_EPNUM_MASK >> HCCHAR_EPNUM_SHIFT);
+ dev_vdbg(hsotg->dev, " Is In: %d\n",
+ !!(hcchar & HCCHAR_EPDIR));
+ dev_vdbg(hsotg->dev, " Is Low Speed: %d\n",
+ !!(hcchar & HCCHAR_LSPDDEV));
+ dev_vdbg(hsotg->dev, " Ep Type: %d\n",
+ hcchar >> HCCHAR_EPTYPE_SHIFT &
+ HCCHAR_EPTYPE_MASK >> HCCHAR_EPTYPE_SHIFT);
+ dev_vdbg(hsotg->dev, " Max Pkt: %d\n",
+ hcchar >> HCCHAR_MPS_SHIFT &
+ HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
+ dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
+ hcchar >> HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+ }
+
+ /* Program the HCSPLT register for SPLITs */
+ if (chan->do_split) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev,
+ "Programming HC %d with split --> %s\n",
+ hc_num,
+ chan->complete_split ? "CSPLIT" : "SSPLIT");
+ if (chan->complete_split)
+ hcsplt |= HCSPLT_COMPSPLT;
+ hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT &
+ HCSPLT_XACTPOS_MASK;
+ hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT &
+ HCSPLT_HUBADDR_MASK;
+ hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT &
+ HCSPLT_PRTADDR_MASK;
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, " comp split %d\n",
+ chan->complete_split);
+ dev_vdbg(hsotg->dev, " xact pos %d\n",
+ chan->xact_pos);
+ dev_vdbg(hsotg->dev, " hub addr %d\n",
+ chan->hub_addr);
+ dev_vdbg(hsotg->dev, " hub port %d\n",
+ chan->hub_port);
+ dev_vdbg(hsotg->dev, " is_in %d\n",
+ chan->ep_is_in);
+ dev_vdbg(hsotg->dev, " Max Pkt %d\n",
+ hcchar >> HCCHAR_MPS_SHIFT &
+ HCCHAR_MPS_MASK >> HCCHAR_MPS_SHIFT);
+ dev_vdbg(hsotg->dev, " xferlen %d\n",
+ chan->xfer_len);
+ }
+ }
+
+ writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
+}
+
+/**
+ * dwc2_hc_halt() - Attempts to halt a host channel
+ *
+ * @hsotg: Controller register interface
+ * @chan: Host channel to halt
+ * @halt_status: Reason for halting the channel
+ *
+ * This function should only be called in Slave mode or to abort a transfer in
+ * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the
+ * controller halts the channel when the transfer is complete or a condition
+ * occurs that requires application intervention.
+ *
+ * In slave mode, checks for a free request queue entry, then sets the Channel
+ * Enable and Channel Disable bits of the Host Channel Characteristics
+ * register of the specified channel to intiate the halt. If there is no free
+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
+ * register to flush requests for this channel. In the latter case, sets a
+ * flag to indicate that the host channel needs to be halted when a request
+ * queue slot is open.
+ *
+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+ * HCCHARn register. The controller ensures there is space in the request
+ * queue before submitting the halt request.
+ *
+ * Some time may elapse before the core flushes any posted requests for this
+ * host channel and halts. The Channel Halted interrupt handler completes the
+ * deactivation of the host channel.
+ */
+void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+ enum dwc2_halt_status halt_status)
+{
+ u32 nptxsts, hptxsts, hcchar;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+ if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS)
+ dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status);
+
+ if (halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
+ halt_status == DWC2_HC_XFER_AHB_ERR) {
+ /*
+ * Disable all channel interrupts except Ch Halted. The QTD
+ * and QH state associated with this transfer has been cleared
+ * (in the case of URB_DEQUEUE), so the channel needs to be
+ * shut down carefully to prevent crashes.
+ */
+ u32 hcintmsk = HCINTMSK_CHHLTD;
+
+ dev_vdbg(hsotg->dev, "dequeue/error\n");
+ writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+
+ /*
+ * Make sure no other interrupts besides halt are currently
+ * pending. Handling another interrupt could cause a crash due
+ * to the QTD and QH state.
+ */
+ writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+
+ /*
+ * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+ * even if the channel was already halted for some other
+ * reason
+ */
+ chan->halt_status = halt_status;
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+ if (!(hcchar & HCCHAR_CHENA)) {
+ /*
+ * The channel is either already halted or it hasn't
+ * started yet. In DMA mode, the transfer may halt if
+ * it finishes normally or a condition occurs that
+ * requires driver intervention. Don't want to halt
+ * the channel again. In either Slave or DMA mode,
+ * it's possible that the transfer has been assigned
+ * to a channel, but not started yet when an URB is
+ * dequeued. Don't want to halt a channel that hasn't
+ * started yet.
+ */
+ return;
+ }
+ }
+ if (chan->halt_pending) {
+ /*
+ * A halt has already been issued for this channel. This might
+ * happen when a transfer is aborted by a higher level in
+ * the stack.
+ */
+ dev_vdbg(hsotg->dev,
+ "*** %s: Channel %d, chan->halt_pending already set ***\n",
+ __func__, chan->hc_num);
+ return;
+ }
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+ /* No need to set the bit in DDMA for disabling the channel */
+ /* TODO check it everywhere channel is disabled */
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "desc DMA disabled\n");
+ hcchar |= HCCHAR_CHENA;
+ } else {
+ if (dbg_hc(chan))
+ dev_dbg(hsotg->dev, "desc DMA enabled\n");
+ }
+ hcchar |= HCCHAR_CHDIS;
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA not enabled\n");
+ hcchar |= HCCHAR_CHENA;
+
+ /* Check for space in the request queue to issue the halt */
+ if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+ chan->ep_type == USB_ENDPOINT_XFER_BULK) {
+ dev_vdbg(hsotg->dev, "control/bulk\n");
+ nptxsts = readl(hsotg->regs + GNPTXSTS);
+ if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
+ dev_vdbg(hsotg->dev, "Disabling channel\n");
+ hcchar &= ~HCCHAR_CHENA;
+ }
+ } else {
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "isoc/intr\n");
+ hptxsts = readl(hsotg->regs + HPTXSTS);
+ if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
+ hsotg->queuing_high_bandwidth) {
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "Disabling channel\n");
+ hcchar &= ~HCCHAR_CHENA;
+ }
+ }
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA enabled\n");
+ }
+
+ writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ chan->halt_status = halt_status;
+
+ if (hcchar & HCCHAR_CHENA) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Channel enabled\n");
+ chan->halt_pending = 1;
+ chan->halt_on_queue = 0;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Channel disabled\n");
+ chan->halt_on_queue = 1;
+ }
+
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " hcchar: 0x%08x\n",
+ hcchar);
+ dev_vdbg(hsotg->dev, " halt_pending: %d\n",
+ chan->halt_pending);
+ dev_vdbg(hsotg->dev, " halt_on_queue: %d\n",
+ chan->halt_on_queue);
+ dev_vdbg(hsotg->dev, " halt_status: %d\n",
+ chan->halt_status);
+ }
+}
+
+/**
+ * dwc2_hc_cleanup() - Clears the transfer state for a host channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Identifies the host channel to clean up
+ *
+ * This function is normally called after a transfer is done and the host
+ * channel is being released
+ */
+void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+ u32 hcintmsk;
+
+ chan->xfer_started = 0;
+
+ /*
+ * Clear channel interrupt enables and any unhandled channel interrupt
+ * conditions
+ */
+ writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
+ hcintmsk = 0xffffffff;
+ hcintmsk &= ~HCINTMSK_RESERVED14_31;
+ writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+}
+
+/**
+ * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in
+ * which frame a periodic transfer should occur
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Identifies the host channel to set up and its properties
+ * @hcchar: Current value of the HCCHAR register for the specified host channel
+ *
+ * This function has no effect on non-periodic transfers
+ */
+static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, u32 *hcchar)
+{
+ u32 hfnum, frnum;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ hfnum = readl(hsotg->regs + HFNUM);
+ frnum = hfnum >> HFNUM_FRNUM_SHIFT &
+ HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT;
+
+ /* 1 if _next_ frame is odd, 0 if it's even */
+ if (frnum & 0x1)
+ *hcchar |= HCCHAR_ODDFRM;
+ }
+}
+
+static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan)
+{
+ /* Set up the initial PID for the transfer */
+ if (chan->speed == USB_SPEED_HIGH) {
+ if (chan->ep_is_in) {
+ if (chan->multi_count == 1)
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ else if (chan->multi_count == 2)
+ chan->data_pid_start = DWC2_HC_PID_DATA1;
+ else
+ chan->data_pid_start = DWC2_HC_PID_DATA2;
+ } else {
+ if (chan->multi_count == 1)
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ else
+ chan->data_pid_start = DWC2_HC_PID_MDATA;
+ }
+ } else {
+ chan->data_pid_start = DWC2_HC_PID_DATA0;
+ }
+}
+
+/**
+ * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with
+ * the Host Channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. For a channel associated
+ * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel
+ * associated with a periodic EP, the periodic Tx FIFO is written.
+ *
+ * Upon return the xfer_buf and xfer_count fields in chan are incremented by
+ * the number of bytes written to the Tx FIFO.
+ */
+static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 i;
+ u32 remaining_count;
+ u32 byte_count;
+ u32 dword_count;
+ u32 __iomem *data_fifo;
+ u32 *data_buf = (u32 *)chan->xfer_buf;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num));
+
+ remaining_count = chan->xfer_len - chan->xfer_count;
+ if (remaining_count > chan->max_packet)
+ byte_count = chan->max_packet;
+ else
+ byte_count = remaining_count;
+
+ dword_count = (byte_count + 3) / 4;
+
+ if (((unsigned long)data_buf & 0x3) == 0) {
+ /* xfer_buf is DWORD aligned */
+ for (i = 0; i < dword_count; i++, data_buf++)
+ writel(*data_buf, data_fifo);
+ } else {
+ /* xfer_buf is not DWORD aligned */
+ for (i = 0; i < dword_count; i++, data_buf++) {
+ u32 data = data_buf[0] | data_buf[1] << 8 |
+ data_buf[2] << 16 | data_buf[3] << 24;
+ writel(data, data_fifo);
+ }
+ }
+
+ chan->xfer_count += byte_count;
+ chan->xfer_buf += byte_count;
+}
+
+/**
+ * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host
+ * channel and starts the transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel. The xfer_len value
+ * may be reduced to accommodate the max widths of the XferSize and
+ * PktCnt fields in the HCTSIZn register. The multi_count value may be
+ * changed to reflect the final xfer_len value.
+ *
+ * This function may be called in either Slave mode or DMA mode. In Slave mode,
+ * the caller must ensure that there is sufficient space in the request queue
+ * and Tx Data FIFO.
+ *
+ * For an OUT transfer in Slave mode, it loads a data packet into the
+ * appropriate FIFO. If necessary, additional data packets are loaded in the
+ * Host ISR.
+ *
+ * For an IN transfer in Slave mode, a data packet is requested. The data
+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+ * additional data packets are requested in the Host ISR.
+ *
+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+ * register along with a packet count of 1 and the channel is enabled. This
+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
+ * simply set to 0 since no data transfer occurs in this case.
+ *
+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+ * all the information required to perform the subsequent data transfer. In
+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+ * controller performs the entire PING protocol, then starts the data
+ * transfer.
+ */
+void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size;
+ u16 max_hc_pkt_count = hsotg->core_params->max_packet_count;
+ u32 hcchar;
+ u32 hctsiz = 0;
+ u16 num_packets;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (chan->do_ping) {
+ if (hsotg->core_params->dma_enable <= 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "ping, no DMA\n");
+ dwc2_hc_do_ping(hsotg, chan);
+ chan->xfer_started = 1;
+ return;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "ping, DMA\n");
+ hctsiz |= TSIZ_DOPNG;
+ }
+ }
+
+ if (chan->do_split) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "split\n");
+ num_packets = 1;
+
+ if (chan->complete_split && !chan->ep_is_in)
+ /*
+ * For CSPLIT OUT Transfer, set the size to 0 so the
+ * core doesn't expect any data written to the FIFO
+ */
+ chan->xfer_len = 0;
+ else if (chan->ep_is_in || chan->xfer_len > chan->max_packet)
+ chan->xfer_len = chan->max_packet;
+ else if (!chan->ep_is_in && chan->xfer_len > 188)
+ chan->xfer_len = 188;
+
+ hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK;
+ } else {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "no split\n");
+ /*
+ * Ensure that the transfer length and packet count will fit
+ * in the widths allocated for them in the HCTSIZn register
+ */
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ /*
+ * Make sure the transfer size is no larger than one
+ * (micro)frame's worth of data. (A check was done
+ * when the periodic transfer was accepted to ensure
+ * that a (micro)frame's worth of data can be
+ * programmed into a channel.)
+ */
+ u32 max_periodic_len =
+ chan->multi_count * chan->max_packet;
+
+ if (chan->xfer_len > max_periodic_len)
+ chan->xfer_len = max_periodic_len;
+ } else if (chan->xfer_len > max_hc_xfer_size) {
+ /*
+ * Make sure that xfer_len is a multiple of max packet
+ * size
+ */
+ chan->xfer_len =
+ max_hc_xfer_size - chan->max_packet + 1;
+ }
+
+ if (chan->xfer_len > 0) {
+ num_packets = (chan->xfer_len + chan->max_packet - 1) /
+ chan->max_packet;
+ if (num_packets > max_hc_pkt_count) {
+ num_packets = max_hc_pkt_count;
+ chan->xfer_len = num_packets * chan->max_packet;
+ }
+ } else {
+ /* Need 1 packet for transfer length of 0 */
+ num_packets = 1;
+ }
+
+ if (chan->ep_is_in)
+ /*
+ * Always program an integral # of max packets for IN
+ * transfers
+ */
+ chan->xfer_len = num_packets * chan->max_packet;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ /*
+ * Make sure that the multi_count field matches the
+ * actual transfer length
+ */
+ chan->multi_count = num_packets;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ dwc2_set_pid_isoc(chan);
+
+ hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK;
+ }
+
+ chan->start_pkt_count = num_packets;
+ hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
+ hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+ TSIZ_SC_MC_PID_MASK;
+ writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
+ hctsiz, chan->hc_num);
+
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " Xfer Size: %d\n",
+ hctsiz >> TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+ dev_vdbg(hsotg->dev, " Num Pkts: %d\n",
+ hctsiz >> TSIZ_PKTCNT_SHIFT &
+ TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+ dev_vdbg(hsotg->dev, " Start PID: %d\n",
+ hctsiz >> TSIZ_SC_MC_PID_SHIFT &
+ TSIZ_SC_MC_PID_MASK >> TSIZ_SC_MC_PID_SHIFT);
+ }
+
+ if (hsotg->core_params->dma_enable > 0) {
+ dma_addr_t dma_addr;
+
+ if (chan->align_buf) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "align_buf\n");
+ dma_addr = chan->align_buf;
+ } else {
+ dma_addr = chan->xfer_dma;
+ }
+ writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
+ (unsigned long)dma_addr, chan->hc_num);
+ }
+
+ /* Start the split */
+ if (chan->do_split) {
+ u32 hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
+
+ hcsplt |= HCSPLT_SPLTENA;
+ writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
+ }
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar &= ~HCCHAR_MULTICNT_MASK;
+ hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK;
+ dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+
+ if (hcchar & HCCHAR_CHDIS)
+ dev_warn(hsotg->dev,
+ "%s: chdis set, channel %d, hcchar 0x%08x\n",
+ __func__, chan->hc_num, hcchar);
+
+ /* Set host channel enable after all other setup is complete */
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
+ hcchar >> HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+
+ writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+ chan->hc_num);
+
+ chan->xfer_started = 1;
+ chan->requests++;
+
+ if (hsotg->core_params->dma_enable <= 0 &&
+ !chan->ep_is_in && chan->xfer_len > 0)
+ /* Load OUT packet into the appropriate Tx FIFO */
+ dwc2_hc_write_packet(hsotg, chan);
+}
+
+/**
+ * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a
+ * host channel and starts the transfer in Descriptor DMA mode
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set.
+ * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field
+ * with micro-frame bitmap.
+ *
+ * Initializes HCDMA register with descriptor list address and CTD value then
+ * starts the transfer via enabling the channel.
+ */
+void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ u32 hcchar;
+ u32 hc_dma;
+ u32 hctsiz = 0;
+
+ if (chan->do_ping)
+ hctsiz |= TSIZ_DOPNG;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ dwc2_set_pid_isoc(chan);
+
+ /* Packet Count and Xfer Size are not used in Descriptor DMA mode */
+ hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
+ TSIZ_SC_MC_PID_MASK;
+
+ /* 0 - 1 descriptor, 1 - 2 descriptors, etc */
+ hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK;
+
+ /* Non-zero only for high-speed interrupt endpoints */
+ hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK;
+
+ if (dbg_hc(chan)) {
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+ dev_vdbg(hsotg->dev, " Start PID: %d\n",
+ chan->data_pid_start);
+ dev_vdbg(hsotg->dev, " NTD: %d\n", chan->ntd - 1);
+ }
+
+ writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+ hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK;
+
+ /* Always start from first descriptor */
+ hc_dma &= ~HCDMA_CTD_MASK;
+ writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n",
+ hc_dma, chan->hc_num);
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar &= ~HCCHAR_MULTICNT_MASK;
+ hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK;
+
+ if (hcchar & HCCHAR_CHDIS)
+ dev_warn(hsotg->dev,
+ "%s: chdis set, channel %d, hcchar 0x%08x\n",
+ __func__, chan->hc_num, hcchar);
+
+ /* Set host channel enable after all other setup is complete */
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " Multi Cnt: %d\n",
+ hcchar >> HCCHAR_MULTICNT_SHIFT &
+ HCCHAR_MULTICNT_MASK >> HCCHAR_MULTICNT_SHIFT);
+
+ writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
+ chan->hc_num);
+
+ chan->xfer_started = 1;
+ chan->requests++;
+}
+
+/**
+ * dwc2_hc_continue_transfer() - Continues a data transfer that was started by
+ * a previous call to dwc2_hc_start_transfer()
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * The caller must ensure there is sufficient space in the request queue and Tx
+ * Data FIFO. This function should only be called in Slave mode. In DMA mode,
+ * the controller acts autonomously to complete transfers programmed to a host
+ * channel.
+ *
+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
+ * if there is any data remaining to be queued. For an IN transfer, another
+ * data packet is always requested. For the SETUP phase of a control transfer,
+ * this function does nothing.
+ *
+ * Return: 1 if a new request is queued, 0 if no more requests are required
+ * for this transfer
+ */
+int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+
+ if (chan->do_split)
+ /* SPLITs always queue just once per channel */
+ return 0;
+
+ if (chan->data_pid_start == DWC2_HC_PID_SETUP)
+ /* SETUPs are queued only once since they can't be NAK'd */
+ return 0;
+
+ if (chan->ep_is_in) {
+ /*
+ * Always queue another request for other IN transfers. If
+ * back-to-back INs are issued and NAKs are received for both,
+ * the driver may still be processing the first NAK when the
+ * second NAK is received. When the interrupt handler clears
+ * the NAK interrupt for the first NAK, the second NAK will
+ * not be seen. So we can't depend on the NAK interrupt
+ * handler to requeue a NAK'd request. Instead, IN requests
+ * are issued each time this function is called. When the
+ * transfer completes, the extra requests for the channel will
+ * be flushed.
+ */
+ u32 hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+
+ dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " IN xfer: hcchar = 0x%08x\n",
+ hcchar);
+ writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+ chan->requests++;
+ return 1;
+ }
+
+ /* OUT transfers */
+
+ if (chan->xfer_count < chan->xfer_len) {
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ u32 hcchar = readl(hsotg->regs +
+ HCCHAR(chan->hc_num));
+
+ dwc2_hc_set_even_odd_frame(hsotg, chan,
+ &hcchar);
+ }
+
+ /* Load OUT packet into the appropriate Tx FIFO */
+ dwc2_hc_write_packet(hsotg, chan);
+ chan->requests++;
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * dwc2_hc_do_ping() - Starts a PING transfer
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Information needed to initialize the host channel
+ *
+ * This function should only be called in Slave mode. The Do Ping bit is set in
+ * the HCTSIZ register, then the channel is enabled.
+ */
+void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
+{
+ u32 hcchar;
+ u32 hctsiz;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__,
+ chan->hc_num);
+
+
+ hctsiz = TSIZ_DOPNG;
+ hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
+ writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcchar |= HCCHAR_CHENA;
+ hcchar &= ~HCCHAR_CHDIS;
+ writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+}
+
+/**
+ * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for
+ * the HFIR register according to PHY type and speed
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: The caller can modify the value of the HFIR register only after the
+ * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort)
+ * has been set
+ */
+u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
+{
+ u32 usbcfg;
+ u32 hwcfg2;
+ u32 hprt0;
+ int clock = 60; /* default value */
+
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ hwcfg2 = readl(hsotg->regs + GHWCFG2);
+ hprt0 = readl(hsotg->regs + HPRT0);
+
+ if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
+ !(usbcfg & GUSBCFG_PHYIF16))
+ clock = 60;
+ if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
+ GHWCFG2_FS_PHY_TYPE_SHARED_ULPI)
+ clock = 48;
+ if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+ clock = 30;
+ if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16))
+ clock = 60;
+ if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) &&
+ !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16))
+ clock = 48;
+ if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) &&
+ (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
+ GHWCFG2_FS_PHY_TYPE_SHARED_UTMI)
+ clock = 48;
+ if ((usbcfg & GUSBCFG_PHYSEL) && (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) ==
+ GHWCFG2_FS_PHY_TYPE_DEDICATED)
+ clock = 48;
+
+ if ((hprt0 & HPRT0_SPD_MASK) == 0)
+ /* High speed case */
+ return 125 * clock;
+ else
+ /* FS/LS case */
+ return 1000 * clock;
+}
+
+/**
+ * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination
+ * buffer
+ *
+ * @core_if: Programming view of DWC_otg controller
+ * @dest: Destination buffer for the packet
+ * @bytes: Number of bytes to copy to the destination
+ */
+void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
+{
+ u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
+ u32 *data_buf = (u32 *)dest;
+ int word_count = (bytes + 3) / 4;
+ int i;
+
+ /*
+ * Todo: Account for the case where dest is not dword aligned. This
+ * requires reading data from the FIFO into a u32 temp buffer, then
+ * moving it into the data buffer.
+ */
+
+ dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
+
+ for (i = 0; i < word_count; i++, data_buf++)
+ *data_buf = readl(fifo);
+}
+
+/**
+ * dwc2_dump_host_registers() - Prints the host registers
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+ u32 __iomem *addr;
+ int i;
+
+ dev_dbg(hsotg->dev, "Host Global Registers\n");
+ addr = hsotg->regs + HCFG;
+ dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HFIR;
+ dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HFNUM;
+ dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HPTXSTS;
+ dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HAINT;
+ dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HAINTMSK;
+ dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ addr = hsotg->regs + HFLBADDR;
+ dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ }
+
+ addr = hsotg->regs + HPRT0;
+ dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+
+ for (i = 0; i < hsotg->core_params->host_channels; i++) {
+ dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
+ addr = hsotg->regs + HCCHAR(i);
+ dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HCSPLT(i);
+ dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HCINT(i);
+ dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HCINTMSK(i);
+ dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HCTSIZ(i);
+ dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HCDMA(i);
+ dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ addr = hsotg->regs + HCDMAB(i);
+ dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ }
+ }
+#endif
+}
+
+/**
+ * dwc2_dump_global_registers() - Prints the core global registers
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+ u32 __iomem *addr;
+ int i, ep_num;
+ char *txfsiz;
+
+ dev_dbg(hsotg->dev, "Core Global Registers\n");
+ addr = hsotg->regs + GOTGCTL;
+ dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GOTGINT;
+ dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GAHBCFG;
+ dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GUSBCFG;
+ dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GRSTCTL;
+ dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GINTSTS;
+ dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GINTMSK;
+ dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GRXSTSR;
+ dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GRXFSIZ;
+ dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GNPTXFSIZ;
+ dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GNPTXSTS;
+ dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GI2CCTL;
+ dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GPVNDCTL;
+ dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GGPIO;
+ dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GUID;
+ dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GSNPSID;
+ dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GHWCFG1;
+ dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GHWCFG2;
+ dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GHWCFG3;
+ dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GHWCFG4;
+ dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GLPMCFG;
+ dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GPWRDN;
+ dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + GDFIFOCFG;
+ dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+ addr = hsotg->regs + HPTXFSIZ;
+ dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+
+ if (hsotg->core_params->en_multiple_tx_fifo <= 0) {
+ ep_num = hsotg->hwcfg4 >> GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT &
+ GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK >>
+ GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT;
+ txfsiz = "DPTXFSIZ";
+ } else {
+ ep_num = hsotg->hwcfg4 >> GHWCFG4_NUM_IN_EPS_SHIFT &
+ GHWCFG4_NUM_IN_EPS_MASK >> GHWCFG4_NUM_IN_EPS_SHIFT;
+ txfsiz = "DIENPTXF";
+ }
+
+ for (i = 0; i < ep_num; i++) {
+ addr = hsotg->regs + DPTXFSIZN(i + 1);
+ dev_dbg(hsotg->dev, "%s[%d] @0x%08lX : 0x%08X\n", txfsiz, i + 1,
+ (unsigned long)addr, readl(addr));
+ }
+
+ addr = hsotg->regs + PCGCTL;
+ dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n",
+ (unsigned long)addr, readl(addr));
+#endif
+}
+
+/**
+ * dwc2_flush_tx_fifo() - Flushes a Tx FIFO
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @num: Tx FIFO to flush
+ */
+void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
+{
+ u32 greset;
+ int count = 0;
+
+ dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num);
+
+ greset = GRSTCTL_TXFFLSH;
+ greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
+ writel(greset, hsotg->regs + GRSTCTL);
+
+ do {
+ greset = readl(hsotg->regs + GRSTCTL);
+ if (++count > 10000) {
+ dev_warn(hsotg->dev,
+ "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
+ __func__, greset,
+ readl(hsotg->regs + GNPTXSTS));
+ break;
+ }
+ udelay(1);
+ } while (greset & GRSTCTL_TXFFLSH);
+
+ /* Wait for at least 3 PHY Clocks */
+ udelay(1);
+}
+
+/**
+ * dwc2_flush_rx_fifo() - Flushes the Rx FIFO
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
+{
+ u32 greset;
+ int count = 0;
+
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ greset = GRSTCTL_RXFFLSH;
+ writel(greset, hsotg->regs + GRSTCTL);
+
+ do {
+ greset = readl(hsotg->regs + GRSTCTL);
+ if (++count > 10000) {
+ dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n",
+ __func__, greset);
+ break;
+ }
+ udelay(1);
+ } while (greset & GRSTCTL_RXFFLSH);
+
+ /* Wait for at least 3 PHY Clocks */
+ udelay(1);
+}
+
+#define DWC2_PARAM_TEST(a, b, c) ((a) < (b) || (a) > (c))
+
+/* Parameter access functions */
+int dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+ u32 op_mode;
+
+ op_mode = hsotg->hwcfg2 & GHWCFG2_OP_MODE_MASK;
+
+ switch (val) {
+ case DWC2_CAP_PARAM_HNP_SRP_CAPABLE:
+ if (op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE)
+ valid = 0;
+ break;
+ case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE:
+ switch (op_mode) {
+ case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+ case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+ break;
+ default:
+ valid = 0;
+ break;
+ }
+ break;
+ case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE:
+ /* always valid */
+ break;
+ default:
+ valid = 0;
+ break;
+ }
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for otg_cap parameter. Check HW configuration.\n",
+ val);
+ switch (op_mode) {
+ case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE:
+ val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE;
+ break;
+ case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE:
+ case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST:
+ val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE;
+ break;
+ default:
+ val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+ break;
+ }
+ dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->otg_cap = val;
+ return retval;
+}
+
+int dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val > 0 && (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) ==
+ GHWCFG2_SLAVE_ONLY_ARCH)
+ valid = 0;
+ if (val < 0)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for dma_enable parameter. Check HW configuration.\n",
+ val);
+ val = (hsotg->hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) !=
+ GHWCFG2_SLAVE_ONLY_ARCH;
+ dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->dma_enable = val;
+ return retval;
+}
+
+int dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val > 0 && (hsotg->core_params->dma_enable <= 0 ||
+ !(hsotg->hwcfg4 & GHWCFG4_DESC_DMA)))
+ valid = 0;
+ if (val < 0)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for dma_desc_enable parameter. Check HW configuration.\n",
+ val);
+ val = (hsotg->core_params->dma_enable > 0 &&
+ (hsotg->hwcfg4 & GHWCFG4_DESC_DMA));
+ dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->dma_desc_enable = val;
+ return retval;
+}
+
+int dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
+ int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "Wrong value for host_support_fs_low_power\n");
+ dev_err(hsotg->dev,
+ "host_support_fs_low_power must be 0 or 1\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev,
+ "Setting host_support_fs_low_power to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_support_fs_ls_low_power = val;
+ return retval;
+}
+
+int dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val > 0 && !(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO))
+ valid = 0;
+ if (val < 0)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n",
+ val);
+ val = !!(hsotg->hwcfg2 & GHWCFG2_DYNAMIC_FIFO);
+ dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->enable_dynamic_fifo = val;
+ return retval;
+}
+
+int dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val < 16 || val > readl(hsotg->regs + GRXFSIZ))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for host_rx_fifo_size. Check HW configuration.\n",
+ val);
+ val = readl(hsotg->regs + GRXFSIZ);
+ dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_rx_fifo_size = val;
+ return retval;
+}
+
+int dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val < 16 || val > (readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n",
+ val);
+ val = readl(hsotg->regs + GNPTXFSIZ) >> 16 & 0xffff;
+ dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n",
+ val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_nperio_tx_fifo_size = val;
+ return retval;
+}
+
+int dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (val < 16 || val > (hsotg->hptxfsiz >> 16))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n",
+ val);
+ val = hsotg->hptxfsiz >> 16;
+ dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n",
+ val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_perio_tx_fifo_size = val;
+ return retval;
+}
+
+int dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+ int width = hsotg->hwcfg3 >> GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT &
+ GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
+ GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT;
+
+ if (val < 2047 || val >= (1 << (width + 11)))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for max_transfer_size. Check HW configuration.\n",
+ val);
+ val = (1 << (width + 11)) - 1;
+ dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->max_transfer_size = val;
+ return retval;
+}
+
+int dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+ int width = hsotg->hwcfg3 >> GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT &
+ GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK >>
+ GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT;
+
+ if (val < 15 || val > (1 << (width + 4)))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for max_packet_count. Check HW configuration.\n",
+ val);
+ val = (1 << (width + 4)) - 1;
+ dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->max_packet_count = val;
+ return retval;
+}
+
+int dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+ int num_chan = hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
+ GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT;
+
+ if (val < 1 || val > num_chan + 1)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for host_channels. Check HW configuration.\n",
+ val);
+ val = num_chan + 1;
+ dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_channels = val;
+ return retval;
+}
+
+int dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val)
+{
+#ifndef NO_FS_PHY_HW_CHECKS
+ int valid = 0;
+ u32 hs_phy_type;
+ u32 fs_phy_type;
+#endif
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, DWC2_PHY_TYPE_PARAM_FS,
+ DWC2_PHY_TYPE_PARAM_ULPI)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for phy_type\n");
+ dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n");
+ }
+
+#ifndef NO_FS_PHY_HW_CHECKS
+ valid = 0;
+#else
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val);
+ retval = -EINVAL;
+#endif
+ }
+
+#ifndef NO_FS_PHY_HW_CHECKS
+ hs_phy_type = hsotg->hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK;
+ fs_phy_type = hsotg->hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK;
+
+ if (val == DWC2_PHY_TYPE_PARAM_UTMI &&
+ (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
+ hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
+ valid = 1;
+ else if (val == DWC2_PHY_TYPE_PARAM_ULPI &&
+ (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI ||
+ hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI))
+ valid = 1;
+ else if (val == DWC2_PHY_TYPE_PARAM_FS &&
+ fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED)
+ valid = 1;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for phy_type. Check HW configuration.\n",
+ val);
+ val = 0;
+ if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) {
+ if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI ||
+ hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)
+ val = DWC2_PHY_TYPE_PARAM_UTMI;
+ else
+ val = DWC2_PHY_TYPE_PARAM_ULPI;
+ }
+ dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val);
+ retval = -EINVAL;
+ }
+#endif
+
+ hsotg->core_params->phy_type = val;
+ return retval;
+}
+
+static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg)
+{
+ return hsotg->core_params->phy_type;
+}
+
+int dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for speed parameter\n");
+ dev_err(hsotg->dev, "max_speed parameter must be 0 or 1\n");
+ }
+ valid = 0;
+ }
+
+ if (val == 0 && dwc2_get_param_phy_type(hsotg) ==
+ DWC2_PHY_TYPE_PARAM_FS)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for speed parameter. Check HW configuration.\n",
+ val);
+ val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ?
+ 1 : 0;
+ dev_dbg(hsotg->dev, "Setting speed to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->speed = val;
+ return retval;
+}
+
+int dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ,
+ DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "Wrong value for host_ls_low_power_phy_clk parameter\n");
+ dev_err(hsotg->dev,
+ "host_ls_low_power_phy_clk must be 0 or 1\n");
+ }
+ valid = 0;
+ }
+
+ if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ &&
+ dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n",
+ val);
+ val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS
+ ? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ
+ : DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ;
+ dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n",
+ val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->host_ls_low_power_phy_clk = val;
+ return retval;
+}
+
+int dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n");
+ dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->phy_ulpi_ddr = val;
+ return retval;
+}
+
+int dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "Wrong value for phy_ulpi_ext_vbus\n");
+ dev_err(hsotg->dev,
+ "phy_ulpi_ext_vbus must be 0 or 1\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->phy_ulpi_ext_vbus = val;
+ return retval;
+}
+
+int dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 8, 8) && DWC2_PARAM_TEST(val, 16, 16)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for phy_utmi_width\n");
+ dev_err(hsotg->dev, "phy_utmi_width must be 8 or 16\n");
+ }
+ val = 8;
+ dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->phy_utmi_width = val;
+ return retval;
+}
+
+int dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n");
+ dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->ulpi_fs_ls = val;
+ return retval;
+}
+
+int dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for ts_dline\n");
+ dev_err(hsotg->dev, "ts_dline must be 0 or 1\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->ts_dline = val;
+ return retval;
+}
+
+int dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val)
+{
+#ifndef NO_FS_PHY_HW_CHECKS
+ int valid = 1;
+#endif
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev, "Wrong value for i2c_enable\n");
+ dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n");
+ }
+
+#ifndef NO_FS_PHY_HW_CHECKS
+ valid = 0;
+#else
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
+ retval = -EINVAL;
+#endif
+ }
+
+#ifndef NO_FS_PHY_HW_CHECKS
+ if (val == 1 && !(hsotg->hwcfg3 & GHWCFG3_I2C))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for i2c_enable. Check HW configuration.\n",
+ val);
+ val = !!(hsotg->hwcfg3 & GHWCFG3_I2C);
+ dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val);
+ retval = -EINVAL;
+ }
+#endif
+
+ hsotg->core_params->i2c_enable = val;
+ return retval;
+}
+
+int dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "Wrong value for en_multiple_tx_fifo,\n");
+ dev_err(hsotg->dev,
+ "en_multiple_tx_fifo must be 0 or 1\n");
+ }
+ valid = 0;
+ }
+
+ if (val == 1 && !(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN))
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n",
+ val);
+ val = !!(hsotg->hwcfg4 & GHWCFG4_DED_FIFO_EN);
+ dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->en_multiple_tx_fifo = val;
+ return retval;
+}
+
+int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "'%d' invalid for parameter reload_ctl\n", val);
+ dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n");
+ }
+ valid = 0;
+ }
+
+ if (val == 1 && hsotg->snpsid < DWC2_CORE_REV_2_92a)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for parameter reload_ctl. Check HW configuration.\n",
+ val);
+ val = hsotg->snpsid >= DWC2_CORE_REV_2_92a;
+ dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->reload_ctl = val;
+ return retval;
+}
+
+int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val)
+{
+ int valid = 1;
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "'%d' invalid for parameter ahb_single\n", val);
+ dev_err(hsotg->dev, "ahb_single must be 0 or 1\n");
+ }
+ valid = 0;
+ }
+
+ if (val > 0 && hsotg->snpsid < DWC2_CORE_REV_2_94a)
+ valid = 0;
+
+ if (!valid) {
+ if (val >= 0)
+ dev_err(hsotg->dev,
+ "%d invalid for parameter ahb_single. Check HW configuration.\n",
+ val);
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting ahb_single to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->ahb_single = val;
+ return retval;
+}
+
+int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val)
+{
+ int retval = 0;
+
+ if (DWC2_PARAM_TEST(val, 0, 1)) {
+ if (val >= 0) {
+ dev_err(hsotg->dev,
+ "'%d' invalid for parameter otg_ver\n", val);
+ dev_err(hsotg->dev,
+ "otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n");
+ }
+ val = 0;
+ dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val);
+ retval = -EINVAL;
+ }
+
+ hsotg->core_params->otg_ver = val;
+ return retval;
+}
+
+/*
+ * This function is called during module intialization to pass module parameters
+ * for the DWC_otg core. It returns non-0 if any parameters are invalid.
+ */
+int dwc2_set_parameters(struct dwc2_hsotg *hsotg,
+ struct dwc2_core_params *params)
+{
+ int retval = 0;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ retval |= dwc2_set_param_otg_cap(hsotg, params->otg_cap);
+ retval |= dwc2_set_param_dma_enable(hsotg, params->dma_enable);
+ retval |= dwc2_set_param_dma_desc_enable(hsotg,
+ params->dma_desc_enable);
+ retval |= dwc2_set_param_host_support_fs_ls_low_power(hsotg,
+ params->host_support_fs_ls_low_power);
+ retval |= dwc2_set_param_enable_dynamic_fifo(hsotg,
+ params->enable_dynamic_fifo);
+ retval |= dwc2_set_param_host_rx_fifo_size(hsotg,
+ params->host_rx_fifo_size);
+ retval |= dwc2_set_param_host_nperio_tx_fifo_size(hsotg,
+ params->host_nperio_tx_fifo_size);
+ retval |= dwc2_set_param_host_perio_tx_fifo_size(hsotg,
+ params->host_perio_tx_fifo_size);
+ retval |= dwc2_set_param_max_transfer_size(hsotg,
+ params->max_transfer_size);
+ retval |= dwc2_set_param_max_packet_count(hsotg,
+ params->max_packet_count);
+ retval |= dwc2_set_param_host_channels(hsotg, params->host_channels);
+ retval |= dwc2_set_param_phy_type(hsotg, params->phy_type);
+ retval |= dwc2_set_param_speed(hsotg, params->speed);
+ retval |= dwc2_set_param_host_ls_low_power_phy_clk(hsotg,
+ params->host_ls_low_power_phy_clk);
+ retval |= dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr);
+ retval |= dwc2_set_param_phy_ulpi_ext_vbus(hsotg,
+ params->phy_ulpi_ext_vbus);
+ retval |= dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width);
+ retval |= dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls);
+ retval |= dwc2_set_param_ts_dline(hsotg, params->ts_dline);
+ retval |= dwc2_set_param_i2c_enable(hsotg, params->i2c_enable);
+ retval |= dwc2_set_param_en_multiple_tx_fifo(hsotg,
+ params->en_multiple_tx_fifo);
+ retval |= dwc2_set_param_reload_ctl(hsotg, params->reload_ctl);
+ retval |= dwc2_set_param_ahb_single(hsotg, params->ahb_single);
+ retval |= dwc2_set_param_otg_ver(hsotg, params->otg_ver);
+
+ return retval;
+}
+
+u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg)
+{
+ return (u16)(hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103);
+}
+
+int dwc2_check_core_status(struct dwc2_hsotg *hsotg)
+{
+ if (readl(hsotg->regs + GSNPSID) == 0xffffffff)
+ return -1;
+ else
+ return 0;
+}
+
+/**
+ * dwc2_enable_global_interrupts() - Enables the controller's Global
+ * Interrupt in the AHB Config register
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+ ahbcfg |= GAHBCFG_GLBL_INTR_EN;
+ writel(ahbcfg, hsotg->regs + GAHBCFG);
+}
+
+/**
+ * dwc2_disable_global_interrupts() - Disables the controller's Global
+ * Interrupt in the AHB Config register
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
+{
+ u32 ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+ ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
+ writel(ahbcfg, hsotg->regs + GAHBCFG);
+}
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG Core");
+MODULE_AUTHOR("Synopsys, Inc.");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/dwc2/core.h b/drivers/staging/dwc2/core.h
new file mode 100644
index 000000000000..fc075a7c1de5
--- /dev/null
+++ b/drivers/staging/dwc2/core.h
@@ -0,0 +1,662 @@
+/*
+ * core.h - DesignWare HS OTG Controller common declarations
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DWC2_CORE_H__
+#define __DWC2_CORE_H__
+
+#include <linux/usb/phy.h>
+#include "hw.h"
+
+#ifdef DWC2_LOG_WRITES
+static inline void do_write(u32 value, void *addr)
+{
+ writel(value, addr);
+ pr_info("INFO:: wrote %08x to %p\n", value, addr);
+}
+
+#undef writel
+#define writel(v, a) do_write(v, a)
+#endif
+
+/* Maximum number of Endpoints/HostChannels */
+#define MAX_EPS_CHANNELS 16
+
+struct dwc2_hsotg;
+struct dwc2_host_chan;
+
+/* Device States */
+enum dwc2_lx_state {
+ DWC2_L0, /* On state */
+ DWC2_L1, /* LPM sleep state */
+ DWC2_L2, /* USB suspend state */
+ DWC2_L3, /* Off state */
+};
+
+/**
+ * struct dwc2_core_params - Parameters for configuring the core
+ *
+ * @otg_cap: Specifies the OTG capabilities. The driver will
+ * automatically detect the value for this parameter if
+ * none is specified.
+ * 0 - HNP and SRP capable (default)
+ * 1 - SRP Only capable
+ * 2 - No HNP/SRP capable
+ * @dma_enable: Specifies whether to use slave or DMA mode for accessing
+ * the data FIFOs. The driver will automatically detect the
+ * value for this parameter if none is specified.
+ * 0 - Slave
+ * 1 - DMA (default, if available)
+ * @dma_desc_enable: When DMA mode is enabled, specifies whether to use
+ * address DMA mode or descriptor DMA mode for accessing
+ * the data FIFOs. The driver will automatically detect the
+ * value for this if none is specified.
+ * 0 - Address DMA
+ * 1 - Descriptor DMA (default, if available)
+ * @speed: Specifies the maximum speed of operation in host and
+ * device mode. The actual speed depends on the speed of
+ * the attached device and the value of phy_type.
+ * 0 - High Speed (default)
+ * 1 - Full Speed
+ * @host_support_fs_ls_low_power: Specifies whether low power mode is supported
+ * when attached to a Full Speed or Low Speed device in
+ * host mode.
+ * 0 - Don't support low power mode (default)
+ * 1 - Support low power mode
+ * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode
+ * when connected to a Low Speed device in host mode. This
+ * parameter is applicable only if
+ * host_support_fs_ls_low_power is enabled. If phy_type is
+ * set to FS then defaults to 6 MHZ otherwise 48 MHZ.
+ * 0 - 48 MHz
+ * 1 - 6 MHz
+ * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters
+ * 1 - Allow dynamic FIFO sizing (default)
+ * @host_rx_fifo_size: Number of 4-byte words in the Rx FIFO in host mode when
+ * dynamic FIFO sizing is enabled
+ * 16 to 32768 (default 1024)
+ * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO
+ * in host mode when dynamic FIFO sizing is enabled
+ * 16 to 32768 (default 1024)
+ * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in
+ * host mode when dynamic FIFO sizing is enabled
+ * 16 to 32768 (default 1024)
+ * @max_transfer_size: The maximum transfer size supported, in bytes
+ * 2047 to 65,535 (default 65,535)
+ * @max_packet_count: The maximum number of packets in a transfer
+ * 15 to 511 (default 511)
+ * @host_channels: The number of host channel registers to use
+ * 1 to 16 (default 12)
+ * @phy_type: Specifies the type of PHY interface to use. By default,
+ * the driver will automatically detect the phy_type.
+ * @phy_utmi_width: Specifies the UTMI+ Data Width (in bits). This parameter
+ * is applicable for a phy_type of UTMI+ or ULPI. (For a
+ * ULPI phy_type, this parameter indicates the data width
+ * between the MAC and the ULPI Wrapper.) Also, this
+ * parameter is applicable only if the OTG_HSPHY_WIDTH cC
+ * parameter was set to "8 and 16 bits", meaning that the
+ * core has been configured to work at either data path
+ * width.
+ * 8 or 16 (default 16)
+ * @phy_ulpi_ddr: Specifies whether the ULPI operates at double or single
+ * data rate. This parameter is only applicable if phy_type
+ * is ULPI.
+ * 0 - single data rate ULPI interface with 8 bit wide
+ * data bus (default)
+ * 1 - double data rate ULPI interface with 4 bit wide
+ * data bus
+ * @phy_ulpi_ext_vbus: For a ULPI phy, specifies whether to use the internal or
+ * external supply to drive the VBus
+ * @i2c_enable: Specifies whether to use the I2Cinterface for a full
+ * speed PHY. This parameter is only applicable if phy_type
+ * is FS.
+ * 0 - No (default)
+ * 1 - Yes
+ * @ulpi_fs_ls: True to make ULPI phy operate in FS/LS mode only
+ * @ts_dline: True to enable Term Select Dline pulsing
+ * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs
+ * are enabled
+ * @reload_ctl: True to allow dynamic reloading of HFIR register during
+ * runtime
+ * @ahb_single: This bit enables SINGLE transfers for remainder data in
+ * a transfer for DMA mode of operation.
+ * 0 - remainder data will be sent using INCR burst size
+ * 1 - remainder data will be sent using SINGLE burst size
+ * @otg_ver: OTG version supported
+ * 0 - 1.3
+ * 1 - 2.0
+ *
+ * The following parameters may be specified when starting the module. These
+ * parameters define how the DWC_otg controller should be configured.
+ */
+struct dwc2_core_params {
+ /*
+ * Don't add any non-int members here, this will break
+ * dwc2_set_all_params!
+ */
+ int otg_cap;
+ int otg_ver;
+ int dma_enable;
+ int dma_desc_enable;
+ int speed;
+ int enable_dynamic_fifo;
+ int en_multiple_tx_fifo;
+ int host_rx_fifo_size;
+ int host_nperio_tx_fifo_size;
+ int host_perio_tx_fifo_size;
+ int max_transfer_size;
+ int max_packet_count;
+ int host_channels;
+ int phy_type;
+ int phy_utmi_width;
+ int phy_ulpi_ddr;
+ int phy_ulpi_ext_vbus;
+ int i2c_enable;
+ int ulpi_fs_ls;
+ int host_support_fs_ls_low_power;
+ int host_ls_low_power_phy_clk;
+ int ts_dline;
+ int reload_ctl;
+ int ahb_single;
+};
+
+/**
+ * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
+ * and periodic schedules
+ *
+ * @dev: The struct device pointer
+ * @regs: Pointer to controller regs
+ * @core_params: Parameters that define how the core should be configured
+ * @hwcfg1: Hardware Configuration - stored here for convenience
+ * @hwcfg2: Hardware Configuration - stored here for convenience
+ * @hwcfg3: Hardware Configuration - stored here for convenience
+ * @hwcfg4: Hardware Configuration - stored here for convenience
+ * @hptxfsiz: Hardware Configuration - stored here for convenience
+ * @snpsid: Value from SNPSID register
+ * @total_fifo_size: Total internal RAM for FIFOs (bytes)
+ * @rx_fifo_size: Size of Rx FIFO (bytes)
+ * @nperio_tx_fifo_size: Size of Non-periodic Tx FIFO (Bytes)
+ * @op_state: The operational State, during transitions (a_host=>
+ * a_peripheral and b_device=>b_host) this may not match
+ * the core, but allows the software to determine
+ * transitions
+ * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
+ * transfer are in process of being queued
+ * @srp_success: Stores status of SRP request in the case of a FS PHY
+ * with an I2C interface
+ * @wq_otg: Workqueue object used for handling of some interrupts
+ * @wf_otg: Work object for handling Connector ID Status Change
+ * interrupt
+ * @wkp_timer: Timer object for handling Wakeup Detected interrupt
+ * @lx_state: Lx state of connected device
+ * @flags: Flags for handling root port state changes
+ * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule.
+ * Transfers associated with these QHs are not currently
+ * assigned to a host channel.
+ * @non_periodic_sched_active: Active QHs in the non-periodic schedule.
+ * Transfers associated with these QHs are currently
+ * assigned to a host channel.
+ * @non_periodic_qh_ptr: Pointer to next QH to process in the active
+ * non-periodic schedule
+ * @periodic_sched_inactive: Inactive QHs in the periodic schedule. This is a
+ * list of QHs for periodic transfers that are _not_
+ * scheduled for the next frame. Each QH in the list has an
+ * interval counter that determines when it needs to be
+ * scheduled for execution. This scheduling mechanism
+ * allows only a simple calculation for periodic bandwidth
+ * used (i.e. must assume that all periodic transfers may
+ * need to execute in the same frame). However, it greatly
+ * simplifies scheduling and should be sufficient for the
+ * vast majority of OTG hosts, which need to connect to a
+ * small number of peripherals at one time. Items move from
+ * this list to periodic_sched_ready when the QH interval
+ * counter is 0 at SOF.
+ * @periodic_sched_ready: List of periodic QHs that are ready for execution in
+ * the next frame, but have not yet been assigned to host
+ * channels. Items move from this list to
+ * periodic_sched_assigned as host channels become
+ * available during the current frame.
+ * @periodic_sched_assigned: List of periodic QHs to be executed in the next
+ * frame that are assigned to host channels. Items move
+ * from this list to periodic_sched_queued as the
+ * transactions for the QH are queued to the DWC_otg
+ * controller.
+ * @periodic_sched_queued: List of periodic QHs that have been queued for
+ * execution. Items move from this list to either
+ * periodic_sched_inactive or periodic_sched_ready when the
+ * channel associated with the transfer is released. If the
+ * interval for the QH is 1, the item moves to
+ * periodic_sched_ready because it must be rescheduled for
+ * the next frame. Otherwise, the item moves to
+ * periodic_sched_inactive.
+ * @periodic_usecs: Total bandwidth claimed so far for periodic transfers.
+ * This value is in microseconds per (micro)frame. The
+ * assumption is that all periodic transfers may occur in
+ * the same (micro)frame.
+ * @frame_number: Frame number read from the core at SOF. The value ranges
+ * from 0 to HFNUM_MAX_FRNUM.
+ * @periodic_qh_count: Count of periodic QHs, if using several eps. Used for
+ * SOF enable/disable.
+ * @free_hc_list: Free host channels in the controller. This is a list of
+ * struct dwc2_host_chan items.
+ * @periodic_channels: Number of host channels assigned to periodic transfers.
+ * Currently assuming that there is a dedicated host
+ * channel for each periodic transaction and at least one
+ * host channel is available for non-periodic transactions.
+ * @non_periodic_channels: Number of host channels assigned to non-periodic
+ * transfers
+ * @hc_ptr_array: Array of pointers to the host channel descriptors.
+ * Allows accessing a host channel descriptor given the
+ * host channel number. This is useful in interrupt
+ * handlers.
+ * @status_buf: Buffer used for data received during the status phase of
+ * a control transfer.
+ * @status_buf_dma: DMA address for status_buf
+ * @start_work: Delayed work for handling host A-cable connection
+ * @reset_work: Delayed work for handling a port reset
+ * @lock: Spinlock that protects all the driver data structures
+ * @priv: Stores a pointer to the struct usb_hcd
+ * @otg_port: OTG port number
+ * @frame_list: Frame list
+ * @frame_list_dma: Frame list DMA address
+ */
+struct dwc2_hsotg {
+ struct device *dev;
+ void __iomem *regs;
+ struct dwc2_core_params *core_params;
+ u32 hwcfg1;
+ u32 hwcfg2;
+ u32 hwcfg3;
+ u32 hwcfg4;
+ u32 hptxfsiz;
+ u32 snpsid;
+ u16 total_fifo_size;
+ u16 rx_fifo_size;
+ u16 nperio_tx_fifo_size;
+ enum usb_otg_state op_state;
+
+ unsigned int queuing_high_bandwidth:1;
+ unsigned int srp_success:1;
+
+ struct workqueue_struct *wq_otg;
+ struct work_struct wf_otg;
+ struct timer_list wkp_timer;
+ enum dwc2_lx_state lx_state;
+
+ union dwc2_hcd_internal_flags {
+ u32 d32;
+ struct {
+ unsigned port_connect_status_change:1;
+ unsigned port_connect_status:1;
+ unsigned port_reset_change:1;
+ unsigned port_enable_change:1;
+ unsigned port_suspend_change:1;
+ unsigned port_over_current_change:1;
+ unsigned port_l1_change:1;
+ unsigned reserved:26;
+ } b;
+ } flags;
+
+ struct list_head non_periodic_sched_inactive;
+ struct list_head non_periodic_sched_active;
+ struct list_head *non_periodic_qh_ptr;
+ struct list_head periodic_sched_inactive;
+ struct list_head periodic_sched_ready;
+ struct list_head periodic_sched_assigned;
+ struct list_head periodic_sched_queued;
+ u16 periodic_usecs;
+ u16 frame_number;
+ u16 periodic_qh_count;
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+#define FRAME_NUM_ARRAY_SIZE 1000
+ u16 last_frame_num;
+ u16 *frame_num_array;
+ u16 *last_frame_num_array;
+ int frame_num_idx;
+ int dumped_frame_num_array;
+#endif
+
+ struct list_head free_hc_list;
+ int periodic_channels;
+ int non_periodic_channels;
+ struct dwc2_host_chan *hc_ptr_array[MAX_EPS_CHANNELS];
+ u8 *status_buf;
+ dma_addr_t status_buf_dma;
+#define DWC2_HCD_STATUS_BUF_SIZE 64
+
+ struct delayed_work start_work;
+ struct delayed_work reset_work;
+ spinlock_t lock;
+ void *priv;
+ u8 otg_port;
+ u32 *frame_list;
+ dma_addr_t frame_list_dma;
+
+ /* DWC OTG HW Release versions */
+#define DWC2_CORE_REV_2_71a 0x4f54271a
+#define DWC2_CORE_REV_2_90a 0x4f54290a
+#define DWC2_CORE_REV_2_92a 0x4f54292a
+#define DWC2_CORE_REV_2_94a 0x4f54294a
+#define DWC2_CORE_REV_3_00a 0x4f54300a
+
+#ifdef DEBUG
+ u32 frrem_samples;
+ u64 frrem_accum;
+
+ u32 hfnum_7_samples_a;
+ u64 hfnum_7_frrem_accum_a;
+ u32 hfnum_0_samples_a;
+ u64 hfnum_0_frrem_accum_a;
+ u32 hfnum_other_samples_a;
+ u64 hfnum_other_frrem_accum_a;
+
+ u32 hfnum_7_samples_b;
+ u64 hfnum_7_frrem_accum_b;
+ u32 hfnum_0_samples_b;
+ u64 hfnum_0_frrem_accum_b;
+ u32 hfnum_other_samples_b;
+ u64 hfnum_other_frrem_accum_b;
+#endif
+};
+
+/* Reasons for halting a host channel */
+enum dwc2_halt_status {
+ DWC2_HC_XFER_NO_HALT_STATUS,
+ DWC2_HC_XFER_COMPLETE,
+ DWC2_HC_XFER_URB_COMPLETE,
+ DWC2_HC_XFER_ACK,
+ DWC2_HC_XFER_NAK,
+ DWC2_HC_XFER_NYET,
+ DWC2_HC_XFER_STALL,
+ DWC2_HC_XFER_XACT_ERR,
+ DWC2_HC_XFER_FRAME_OVERRUN,
+ DWC2_HC_XFER_BABBLE_ERR,
+ DWC2_HC_XFER_DATA_TOGGLE_ERR,
+ DWC2_HC_XFER_AHB_ERR,
+ DWC2_HC_XFER_PERIODIC_INCOMPLETE,
+ DWC2_HC_XFER_URB_DEQUEUE,
+};
+
+/*
+ * The following functions support initialization of the core driver component
+ * and the DWC_otg controller
+ */
+extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
+
+/*
+ * Host core Functions.
+ * The following functions support managing the DWC_otg controller in host
+ * mode.
+ */
+extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
+extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+ enum dwc2_halt_status halt_status);
+extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan);
+extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg);
+extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg);
+
+extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg);
+extern int dwc2_check_core_status(struct dwc2_hsotg *hsotg);
+
+/*
+ * Common core Functions.
+ * The following functions support managing the DWC_otg controller in either
+ * device or host mode.
+ */
+extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
+extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
+extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
+
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
+extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
+extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
+
+/* This function should be called on every hardware interrupt. */
+extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
+
+/* OTG Core Parameters */
+
+/*
+ * Specifies the OTG capabilities. The driver will automatically
+ * detect the value for this parameter if none is specified.
+ * 0 - HNP and SRP capable (default)
+ * 1 - SRP Only capable
+ * 2 - No HNP/SRP capable
+ */
+extern int dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0
+#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1
+#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
+
+/*
+ * Specifies whether to use slave or DMA mode for accessing the data
+ * FIFOs. The driver will automatically detect the value for this
+ * parameter if none is specified.
+ * 0 - Slave
+ * 1 - DMA (default, if available)
+ */
+extern int dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * When DMA mode is enabled specifies whether to use
+ * address DMA or DMA Descritor mode for accessing the data
+ * FIFOs in device mode. The driver will automatically detect
+ * the value for this parameter if none is specified.
+ * 0 - address DMA
+ * 1 - DMA Descriptor(default, if available)
+ */
+extern int dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies the maximum speed of operation in host and device mode.
+ * The actual speed depends on the speed of the attached device and
+ * the value of phy_type. The actual speed depends on the speed of the
+ * attached device.
+ * 0 - High Speed (default)
+ * 1 - Full Speed
+ */
+extern int dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_SPEED_PARAM_HIGH 0
+#define DWC2_SPEED_PARAM_FULL 1
+
+/*
+ * Specifies whether low power mode is supported when attached
+ * to a Full Speed or Low Speed device in host mode.
+ *
+ * 0 - Don't support low power mode (default)
+ * 1 - Support low power mode
+ */
+extern int dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg,
+ int val);
+
+/*
+ * Specifies the PHY clock rate in low power mode when connected to a
+ * Low Speed device in host mode. This parameter is applicable only if
+ * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS
+ * then defaults to 6 MHZ otherwise 48 MHZ.
+ *
+ * 0 - 48 MHz
+ * 1 - 6 MHz
+ */
+extern int dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg,
+ int val);
+#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
+#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
+
+/*
+ * 0 - Use cC FIFO size parameters
+ * 1 - Allow dynamic FIFO sizing (default)
+ */
+extern int dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg,
+ int val);
+
+/*
+ * Number of 4-byte words in the Rx FIFO in host mode when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 1024)
+ */
+extern int dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Number of 4-byte words in the non-periodic Tx FIFO in host mode
+ * when Dynamic FIFO sizing is enabled in the core.
+ * 16 to 32768 (default 256)
+ */
+extern int dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg,
+ int val);
+
+/*
+ * Number of 4-byte words in the host periodic Tx FIFO when dynamic
+ * FIFO sizing is enabled.
+ * 16 to 32768 (default 256)
+ */
+extern int dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg,
+ int val);
+
+/*
+ * The maximum transfer size supported in bytes.
+ * 2047 to 65,535 (default 65,535)
+ */
+extern int dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * The maximum number of packets in a transfer.
+ * 15 to 511 (default 511)
+ */
+extern int dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * The number of host channel registers to use.
+ * 1 to 16 (default 11)
+ * Note: The FPGA configuration supports a maximum of 11 host channels.
+ */
+extern int dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies the type of PHY interface to use. By default, the driver
+ * will automatically detect the phy_type.
+ *
+ * 0 - Full Speed PHY
+ * 1 - UTMI+ (default)
+ * 2 - ULPI
+ */
+extern int dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_PHY_TYPE_PARAM_FS 0
+#define DWC2_PHY_TYPE_PARAM_UTMI 1
+#define DWC2_PHY_TYPE_PARAM_ULPI 2
+
+/*
+ * Specifies the UTMI+ Data Width. This parameter is
+ * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
+ * PHY_TYPE, this parameter indicates the data width between
+ * the MAC and the ULPI Wrapper.) Also, this parameter is
+ * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
+ * to "8 and 16 bits", meaning that the core has been
+ * configured to work at either data path width.
+ *
+ * 8 or 16 bits (default 16)
+ */
+extern int dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether the ULPI operates at double or single
+ * data rate. This parameter is only applicable if PHY_TYPE is
+ * ULPI.
+ *
+ * 0 - single data rate ULPI interface with 8 bit wide data
+ * bus (default)
+ * 1 - double data rate ULPI interface with 4 bit wide data
+ * bus
+ */
+extern int dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether to use the internal or external supply to
+ * drive the vbus with a ULPI phy.
+ */
+extern int dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val);
+#define DWC2_PHY_ULPI_INTERNAL_VBUS 0
+#define DWC2_PHY_ULPI_EXTERNAL_VBUS 1
+
+/*
+ * Specifies whether to use the I2Cinterface for full speed PHY. This
+ * parameter is only applicable if PHY_TYPE is FS.
+ * 0 - No (default)
+ * 1 - Yes
+ */
+extern int dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val);
+
+extern int dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val);
+
+extern int dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Specifies whether dedicated transmit FIFOs are
+ * enabled for non periodic IN endpoints in device mode
+ * 0 - No
+ * 1 - Yes
+ */
+extern int dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg,
+ int val);
+
+extern int dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val);
+
+extern int dwc2_set_param_ahb_single(struct dwc2_hsotg *hsotg, int val);
+
+extern int dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
+
+/*
+ * Dump core registers and SPRAM
+ */
+extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg);
+extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg);
+extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg);
+
+/*
+ * Return OTG version - either 1.3 or 2.0
+ */
+extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg);
+
+#endif /* __DWC2_CORE_H__ */
diff --git a/drivers/staging/dwc2/core_intr.c b/drivers/staging/dwc2/core_intr.c
new file mode 100644
index 000000000000..4c9ad14e90ec
--- /dev/null
+++ b/drivers/staging/dwc2/core_intr.c
@@ -0,0 +1,505 @@
+/*
+ * core_intr.c - DesignWare HS OTG Controller common interrupt handling
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains the common interrupt handlers
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+ switch (hsotg->op_state) {
+ case OTG_STATE_A_HOST:
+ return "a_host";
+ case OTG_STATE_A_SUSPEND:
+ return "a_suspend";
+ case OTG_STATE_A_PERIPHERAL:
+ return "a_peripheral";
+ case OTG_STATE_B_PERIPHERAL:
+ return "b_peripheral";
+ case OTG_STATE_B_HOST:
+ return "b_host";
+ default:
+ return "unknown";
+ }
+#else
+ return "";
+#endif
+}
+
+/**
+ * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
+{
+ dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
+ dwc2_is_host_mode(hsotg) ? "Host" : "Device");
+
+ /* Clear interrupt */
+ writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
+}
+
+/**
+ * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG
+ * Interrupt Register (GOTGINT) to determine what interrupt has occurred.
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ */
+static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 gotgint;
+ u32 gotgctl;
+ u32 gintmsk;
+
+ gotgint = readl(hsotg->regs + GOTGINT);
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
+ dwc2_op_state_str(hsotg));
+
+ if (gotgint & GOTGINT_SES_END_DET) {
+ dev_dbg(hsotg->dev,
+ " ++OTG Interrupt: Session End Detected++ (%s)\n",
+ dwc2_op_state_str(hsotg));
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+
+ if (hsotg->op_state == OTG_STATE_B_HOST) {
+ hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+ } else {
+ /*
+ * If not B_HOST and Device HNP still set, HNP did
+ * not succeed!
+ */
+ if (gotgctl & GOTGCTL_DEVHNPEN) {
+ dev_dbg(hsotg->dev, "Session End Detected\n");
+ dev_err(hsotg->dev,
+ "Device Not Connected/Responding!\n");
+ }
+
+ /*
+ * If Session End Detected the B-Cable has been
+ * disconnected
+ */
+ /* Reset to a clean state */
+ hsotg->lx_state = DWC2_L0;
+ }
+
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ gotgctl &= ~GOTGCTL_DEVHNPEN;
+ writel(gotgctl, hsotg->regs + GOTGCTL);
+ }
+
+ if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
+ dev_dbg(hsotg->dev,
+ " ++OTG Interrupt: Session Request Success Status Change++\n");
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ if (gotgctl & GOTGCTL_SESREQSCS) {
+ if (hsotg->core_params->phy_type ==
+ DWC2_PHY_TYPE_PARAM_FS
+ && hsotg->core_params->i2c_enable > 0) {
+ hsotg->srp_success = 1;
+ } else {
+ /* Clear Session Request */
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ gotgctl &= ~GOTGCTL_SESREQ;
+ writel(gotgctl, hsotg->regs + GOTGCTL);
+ }
+ }
+ }
+
+ if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) {
+ /*
+ * Print statements during the HNP interrupt handling
+ * can cause it to fail
+ */
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ /*
+ * WA for 3.00a- HW is not setting cur_mode, even sometimes
+ * this does not help
+ */
+ if (hsotg->snpsid >= DWC2_CORE_REV_3_00a)
+ udelay(100);
+ if (gotgctl & GOTGCTL_HSTNEGSCS) {
+ if (dwc2_is_host_mode(hsotg)) {
+ hsotg->op_state = OTG_STATE_B_HOST;
+ /*
+ * Need to disable SOF interrupt immediately.
+ * When switching from device to host, the PCD
+ * interrupt handler won't handle the interrupt
+ * if host mode is already set. The HCD
+ * interrupt handler won't get called if the
+ * HCD state is HALT. This means that the
+ * interrupt does not get handled and Linux
+ * complains loudly.
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk &= ~GINTSTS_SOF;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+
+ /*
+ * Call callback function with spin lock
+ * released
+ */
+ spin_unlock(&hsotg->lock);
+
+ /* Initialize the Core for Host mode */
+ dwc2_hcd_start(hsotg);
+ spin_lock(&hsotg->lock);
+ hsotg->op_state = OTG_STATE_B_HOST;
+ }
+ } else {
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
+ writel(gotgctl, hsotg->regs + GOTGCTL);
+ dev_dbg(hsotg->dev, "HNP Failed\n");
+ dev_err(hsotg->dev,
+ "Device Not Connected/Responding\n");
+ }
+ }
+
+ if (gotgint & GOTGINT_HST_NEG_DET) {
+ /*
+ * The disconnect interrupt is set at the same time as
+ * Host Negotiation Detected. During the mode switch all
+ * interrupts are cleared so the disconnect interrupt
+ * handler will not get executed.
+ */
+ dev_dbg(hsotg->dev,
+ " ++OTG Interrupt: Host Negotiation Detected++ (%s)\n",
+ (dwc2_is_host_mode(hsotg) ? "Host" : "Device"));
+ if (dwc2_is_device_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n",
+ hsotg->op_state);
+ spin_unlock(&hsotg->lock);
+ dwc2_hcd_disconnect(hsotg);
+ spin_lock(&hsotg->lock);
+ hsotg->op_state = OTG_STATE_A_PERIPHERAL;
+ } else {
+ /* Need to disable SOF interrupt immediately */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk &= ~GINTSTS_SOF;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ spin_unlock(&hsotg->lock);
+ dwc2_hcd_start(hsotg);
+ spin_lock(&hsotg->lock);
+ hsotg->op_state = OTG_STATE_A_HOST;
+ }
+ }
+
+ if (gotgint & GOTGINT_A_DEV_TOUT_CHG)
+ dev_dbg(hsotg->dev,
+ " ++OTG Interrupt: A-Device Timeout Change++\n");
+ if (gotgint & GOTGINT_DBNCE_DONE)
+ dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
+
+ /* Clear GOTGINT */
+ writel(gotgint, hsotg->regs + GOTGINT);
+}
+
+/**
+ * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status
+ * Change Interrupt
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a
+ * Device to Host Mode transition or a Host to Device Mode transition. This only
+ * occurs when the cable is connected/removed from the PHY connector.
+ */
+static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 gintmsk = readl(hsotg->regs + GINTMSK);
+
+ /* Need to disable SOF interrupt immediately */
+ gintmsk &= ~GINTSTS_SOF;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+
+ dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
+ dwc2_is_host_mode(hsotg) ? "Host" : "Device");
+
+ /*
+ * Need to schedule a work, as there are possible DELAY function calls.
+ * Release lock before scheduling workq as it holds spinlock during
+ * scheduling.
+ */
+ spin_unlock(&hsotg->lock);
+ queue_work(hsotg->wq_otg, &hsotg->wf_otg);
+ spin_lock(&hsotg->lock);
+
+ /* Clear interrupt */
+ writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
+}
+
+/**
+ * dwc2_handle_session_req_intr() - This interrupt indicates that a device is
+ * initiating the Session Request Protocol to request the host to turn on bus
+ * power so a new session can begin
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ *
+ * This handler responds by turning on bus power. If the DWC_otg controller is
+ * in low power mode, this handler brings the controller out of low power mode
+ * before turning on bus power.
+ */
+static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
+{
+ dev_dbg(hsotg->dev, "++Session Request Interrupt++\n");
+
+ /* Clear interrupt */
+ writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that the DWC_otg controller has detected a
+ * resume or remote wakeup sequence. If the DWC_otg controller is in
+ * low power mode, the handler must brings the controller out of low
+ * power mode. The controller automatically begins resume signaling.
+ * The handler schedules a time to stop resume signaling.
+ */
+static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
+{
+ dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
+ dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
+
+ if (dwc2_is_device_mode(hsotg)) {
+ dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS));
+ if (hsotg->lx_state == DWC2_L2) {
+ u32 dctl = readl(hsotg->regs + DCTL);
+
+ /* Clear Remote Wakeup Signaling */
+ dctl &= ~DCTL_RMTWKUPSIG;
+ writel(dctl, hsotg->regs + DCTL);
+ }
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
+ } else {
+ if (hsotg->lx_state != DWC2_L1) {
+ u32 pcgcctl = readl(hsotg->regs + PCGCTL);
+
+ /* Restart the Phy Clock */
+ pcgcctl &= ~PCGCTL_STOPPCLK;
+ writel(pcgcctl, hsotg->regs + PCGCTL);
+ mod_timer(&hsotg->wkp_timer,
+ jiffies + msecs_to_jiffies(71));
+ } else {
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
+ }
+ }
+
+ /* Clear interrupt */
+ writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that a device has been disconnected from the
+ * root port
+ */
+static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
+{
+ dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
+ dwc2_is_host_mode(hsotg) ? "Host" : "Device",
+ dwc2_op_state_str(hsotg));
+
+ /* Change to L3 (OFF) state */
+ hsotg->lx_state = DWC2_L3;
+
+ writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
+}
+
+/*
+ * This interrupt indicates that SUSPEND state has been detected on the USB.
+ *
+ * For HNP the USB Suspend interrupt signals the change from "a_peripheral"
+ * to "a_host".
+ *
+ * When power management is enabled the core will be put in low power mode.
+ */
+static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 dsts;
+
+ dev_dbg(hsotg->dev, "USB SUSPEND\n");
+
+ if (dwc2_is_device_mode(hsotg)) {
+ /*
+ * Check the Device status register to determine if the Suspend
+ * state is active
+ */
+ dsts = readl(hsotg->regs + DSTS);
+ dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts);
+ dev_dbg(hsotg->dev,
+ "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
+ !!(dsts & DSTS_SUSPSTS),
+ !!(hsotg->hwcfg4 & GHWCFG4_POWER_OPTIMIZ));
+ } else {
+ if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
+ dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
+
+ /* Clear the a_peripheral flag, back to a_host */
+ spin_unlock(&hsotg->lock);
+ dwc2_hcd_start(hsotg);
+ spin_lock(&hsotg->lock);
+ hsotg->op_state = OTG_STATE_A_HOST;
+ }
+ }
+
+ /* Change to L2 (suspend) state */
+ hsotg->lx_state = DWC2_L2;
+
+ /* Clear interrupt */
+ writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
+}
+
+#define GINTMSK_COMMON (GINTSTS_WKUPINT | GINTSTS_SESSREQINT | \
+ GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT | \
+ GINTSTS_MODEMIS | GINTSTS_DISCONNINT | \
+ GINTSTS_USBSUSP | GINTSTS_RESTOREDONE | \
+ GINTSTS_PRTINT)
+
+/*
+ * This function returns the Core Interrupt register
+ */
+static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 gintsts;
+ u32 gintmsk;
+ u32 gahbcfg;
+ u32 gintmsk_common = GINTMSK_COMMON;
+
+ gintsts = readl(hsotg->regs + GINTSTS);
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gahbcfg = readl(hsotg->regs + GAHBCFG);
+
+#ifdef DEBUG
+ /* If any common interrupts set */
+ if (gintsts & gintmsk_common)
+ dev_dbg(hsotg->dev, "gintsts=%08x gintmsk=%08x\n",
+ gintsts, gintmsk);
+#endif
+
+ if (gahbcfg & GAHBCFG_GLBL_INTR_EN)
+ return gintsts & gintmsk & gintmsk_common;
+ else
+ return 0;
+}
+
+/*
+ * Common interrupt handler
+ *
+ * The common interrupts are those that occur in both Host and Device mode.
+ * This handler handles the following interrupts:
+ * - Mode Mismatch Interrupt
+ * - OTG Interrupt
+ * - Connector ID Status Change Interrupt
+ * - Disconnect Interrupt
+ * - Session Request Interrupt
+ * - Resume / Remote Wakeup Detected Interrupt
+ * - Suspend Interrupt
+ */
+irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
+{
+ struct dwc2_hsotg *hsotg = dev;
+ u32 gintsts;
+ int retval = 0;
+
+ if (dwc2_check_core_status(hsotg) < 0) {
+ dev_warn(hsotg->dev, "Controller is disconnected\n");
+ goto out;
+ }
+
+ spin_lock(&hsotg->lock);
+
+ gintsts = dwc2_read_common_intr(hsotg);
+ if (gintsts & ~GINTSTS_PRTINT)
+ retval = 1;
+
+ if (gintsts & GINTSTS_MODEMIS)
+ dwc2_handle_mode_mismatch_intr(hsotg);
+ if (gintsts & GINTSTS_OTGINT)
+ dwc2_handle_otg_intr(hsotg);
+ if (gintsts & GINTSTS_CONIDSTSCHNG)
+ dwc2_handle_conn_id_status_change_intr(hsotg);
+ if (gintsts & GINTSTS_DISCONNINT)
+ dwc2_handle_disconnect_intr(hsotg);
+ if (gintsts & GINTSTS_SESSREQINT)
+ dwc2_handle_session_req_intr(hsotg);
+ if (gintsts & GINTSTS_WKUPINT)
+ dwc2_handle_wakeup_detected_intr(hsotg);
+ if (gintsts & GINTSTS_USBSUSP)
+ dwc2_handle_usb_suspend_intr(hsotg);
+
+ if (gintsts & GINTSTS_RESTOREDONE) {
+ gintsts = GINTSTS_RESTOREDONE;
+ writel(gintsts, hsotg->regs + GINTSTS);
+ dev_dbg(hsotg->dev, " --Restore done interrupt received--\n");
+ }
+
+ if (gintsts & GINTSTS_PRTINT) {
+ /*
+ * The port interrupt occurs while in device mode with HPRT0
+ * Port Enable/Disable
+ */
+ if (dwc2_is_device_mode(hsotg)) {
+ dev_dbg(hsotg->dev,
+ " --Port interrupt received in Device mode--\n");
+ gintsts = GINTSTS_PRTINT;
+ writel(gintsts, hsotg->regs + GINTSTS);
+ retval = 1;
+ }
+ }
+
+ spin_unlock(&hsotg->lock);
+out:
+ return IRQ_RETVAL(retval);
+}
+EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c
new file mode 100644
index 000000000000..827ab781ae9b
--- /dev/null
+++ b/drivers/staging/dwc2/hcd.c
@@ -0,0 +1,2981 @@
+/*
+ * hcd.c - DesignWare HS OTG Controller host-mode routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains the core HCD code, and implements the Linux hc_driver
+ * API
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_dump_channel_info() - Prints the state of a host channel
+ *
+ * @hsotg: Programming view of DWC_otg controller
+ * @chan: Pointer to the channel to dump
+ *
+ * Must be called with interrupt disabled and spinlock held
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan)
+{
+#ifdef VERBOSE_DEBUG
+ int num_channels = hsotg->core_params->host_channels;
+ struct dwc2_qh *qh;
+ u32 hcchar;
+ u32 hcsplt;
+ u32 hctsiz;
+ u32 hc_dma;
+ int i;
+
+ if (chan == NULL)
+ return;
+
+ hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num));
+ hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num));
+ hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num));
+ hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num));
+
+ dev_dbg(hsotg->dev, " Assigned to channel %p:\n", chan);
+ dev_dbg(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n",
+ hcchar, hcsplt);
+ dev_dbg(hsotg->dev, " hctsiz 0x%08x, hc_dma 0x%08x\n",
+ hctsiz, hc_dma);
+ dev_dbg(hsotg->dev, " dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+ chan->dev_addr, chan->ep_num, chan->ep_is_in);
+ dev_dbg(hsotg->dev, " ep_type: %d\n", chan->ep_type);
+ dev_dbg(hsotg->dev, " max_packet: %d\n", chan->max_packet);
+ dev_dbg(hsotg->dev, " data_pid_start: %d\n", chan->data_pid_start);
+ dev_dbg(hsotg->dev, " xfer_started: %d\n", chan->xfer_started);
+ dev_dbg(hsotg->dev, " halt_status: %d\n", chan->halt_status);
+ dev_dbg(hsotg->dev, " xfer_buf: %p\n", chan->xfer_buf);
+ dev_dbg(hsotg->dev, " xfer_dma: %08lx\n",
+ (unsigned long)chan->xfer_dma);
+ dev_dbg(hsotg->dev, " xfer_len: %d\n", chan->xfer_len);
+ dev_dbg(hsotg->dev, " qh: %p\n", chan->qh);
+ dev_dbg(hsotg->dev, " NP inactive sched:\n");
+ list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive,
+ qh_list_entry)
+ dev_dbg(hsotg->dev, " %p\n", qh);
+ dev_dbg(hsotg->dev, " NP active sched:\n");
+ list_for_each_entry(qh, &hsotg->non_periodic_sched_active,
+ qh_list_entry)
+ dev_dbg(hsotg->dev, " %p\n", qh);
+ dev_dbg(hsotg->dev, " Channels:\n");
+ for (i = 0; i < num_channels; i++) {
+ struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
+
+ dev_dbg(hsotg->dev, " %2d: %p\n", i, chan);
+ }
+#endif /* VERBOSE_DEBUG */
+}
+
+/*
+ * Processes all the URBs in a single list of QHs. Completes them with
+ * -ETIMEDOUT and frees the QTD.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg,
+ struct list_head *qh_list)
+{
+ struct dwc2_qh *qh, *qh_tmp;
+ struct dwc2_qtd *qtd, *qtd_tmp;
+
+ list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
+ list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+ qtd_list_entry) {
+ if (qtd->urb != NULL) {
+ dwc2_host_complete(hsotg, qtd->urb->priv,
+ qtd->urb, -ETIMEDOUT);
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+ }
+ }
+ }
+}
+
+static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg,
+ struct list_head *qh_list)
+{
+ struct dwc2_qtd *qtd, *qtd_tmp;
+ struct dwc2_qh *qh, *qh_tmp;
+ unsigned long flags;
+
+ if (!qh_list->next)
+ /* The list hasn't been initialized yet */
+ return;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ /* Ensure there are no QTDs or URBs left */
+ dwc2_kill_urbs_in_qh_list(hsotg, qh_list);
+
+ list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) {
+ dwc2_hcd_qh_unlink(hsotg, qh);
+
+ /* Free each QTD in the QH's QTD list */
+ list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+ qtd_list_entry)
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ dwc2_hcd_qh_free(hsotg, qh);
+ spin_lock_irqsave(&hsotg->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Responds with an error status of -ETIMEDOUT to all URBs in the non-periodic
+ * and periodic schedules. The QTD associated with each URB is removed from
+ * the schedule and freed. This function may be called when a disconnect is
+ * detected or when the HCD is being stopped.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg)
+{
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive);
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active);
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive);
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready);
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_assigned);
+ dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_queued);
+}
+
+/**
+ * dwc2_hcd_start() - Starts the HCD when switching to Host mode
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ */
+void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
+{
+ u32 hprt0;
+
+ if (hsotg->op_state == OTG_STATE_B_HOST) {
+ /*
+ * Reset the port. During a HNP mode switch the reset
+ * needs to occur within 1ms and have a duration of at
+ * least 50ms.
+ */
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_RST;
+ writel(hprt0, hsotg->regs + HPRT0);
+ }
+
+ queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
+ msecs_to_jiffies(50));
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
+{
+ int num_channels = hsotg->core_params->host_channels;
+ struct dwc2_host_chan *channel;
+ u32 hcchar;
+ int i;
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ /* Flush out any channel requests in slave mode */
+ for (i = 0; i < num_channels; i++) {
+ channel = hsotg->hc_ptr_array[i];
+ if (!list_empty(&channel->hc_list_entry))
+ continue;
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ if (hcchar & HCCHAR_CHENA) {
+ hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
+ hcchar |= HCCHAR_CHDIS;
+ writel(hcchar, hsotg->regs + HCCHAR(i));
+ }
+ }
+ }
+
+ for (i = 0; i < num_channels; i++) {
+ channel = hsotg->hc_ptr_array[i];
+ if (!list_empty(&channel->hc_list_entry))
+ continue;
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ if (hcchar & HCCHAR_CHENA) {
+ /* Halt the channel */
+ hcchar |= HCCHAR_CHDIS;
+ writel(hcchar, hsotg->regs + HCCHAR(i));
+ }
+
+ dwc2_hc_cleanup(hsotg, channel);
+ list_add_tail(&channel->hc_list_entry, &hsotg->free_hc_list);
+ /*
+ * Added for Descriptor DMA to prevent channel double cleanup in
+ * release_channel_ddma(), which is called from ep_disable when
+ * device disconnects
+ */
+ channel->qh = NULL;
+ }
+}
+
+/**
+ * dwc2_hcd_disconnect() - Handles disconnect of the HCD
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
+{
+ u32 intr;
+
+ /* Set status flags for the hub driver */
+ hsotg->flags.b.port_connect_status_change = 1;
+ hsotg->flags.b.port_connect_status = 0;
+
+ /*
+ * Shutdown any transfers in process by clearing the Tx FIFO Empty
+ * interrupt mask and status bits and disabling subsequent host
+ * channel interrupts.
+ */
+ intr = readl(hsotg->regs + GINTMSK);
+ intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
+ writel(intr, hsotg->regs + GINTMSK);
+ intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
+ writel(intr, hsotg->regs + GINTSTS);
+
+ /*
+ * Turn off the vbus power only if the core has transitioned to device
+ * mode. If still in host mode, need to keep power on to detect a
+ * reconnection.
+ */
+ if (dwc2_is_device_mode(hsotg)) {
+ if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
+ dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
+ writel(0, hsotg->regs + HPRT0);
+ }
+
+ dwc2_disable_host_interrupts(hsotg);
+ }
+
+ /* Respond with an error status to all URBs in the schedule */
+ dwc2_kill_all_urbs(hsotg);
+
+ if (dwc2_is_host_mode(hsotg))
+ /* Clean up any host channels that were in use */
+ dwc2_hcd_cleanup_channels(hsotg);
+
+ dwc2_host_disconnect(hsotg);
+}
+
+/**
+ * dwc2_hcd_rem_wakeup() - Handles Remote Wakeup
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ */
+static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
+{
+ if (hsotg->lx_state == DWC2_L2)
+ hsotg->flags.b.port_suspend_change = 1;
+ else
+ hsotg->flags.b.port_l1_change = 1;
+}
+
+/**
+ * dwc2_hcd_stop() - Halts the DWC_otg host mode operations in a clean manner
+ *
+ * @hsotg: Pointer to struct dwc2_hsotg
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
+{
+ dev_dbg(hsotg->dev, "DWC OTG HCD STOP\n");
+
+ /*
+ * The root hub should be disconnected before this function is called.
+ * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
+ * and the QH lists (via ..._hcd_endpoint_disable).
+ */
+
+ /* Turn off all host-specific interrupts */
+ dwc2_disable_host_interrupts(hsotg);
+
+ /* Turn off the vbus power */
+ dev_dbg(hsotg->dev, "PortPower off\n");
+ writel(0, hsotg->regs + HPRT0);
+}
+
+static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb, void **ep_handle,
+ gfp_t mem_flags)
+{
+ struct dwc2_qtd *qtd;
+ unsigned long flags;
+ u32 intr_mask;
+ int retval;
+
+ if (!hsotg->flags.b.port_connect_status) {
+ /* No longer connected */
+ dev_err(hsotg->dev, "Not connected\n");
+ return -ENODEV;
+ }
+
+ qtd = kzalloc(sizeof(*qtd), mem_flags);
+ if (!qtd)
+ return -ENOMEM;
+
+ dwc2_hcd_qtd_init(qtd, urb);
+ retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle,
+ mem_flags);
+ if (retval < 0) {
+ dev_err(hsotg->dev,
+ "DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n",
+ retval);
+ kfree(qtd);
+ return retval;
+ }
+
+ intr_mask = readl(hsotg->regs + GINTMSK);
+ if (!(intr_mask & GINTSTS_SOF) && retval == 0) {
+ enum dwc2_transaction_type tr_type;
+
+ if (qtd->qh->ep_type == USB_ENDPOINT_XFER_BULK &&
+ !(qtd->urb->flags & URB_GIVEBACK_ASAP))
+ /*
+ * Do not schedule SG transactions until qtd has
+ * URB_GIVEBACK_ASAP set
+ */
+ return 0;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ tr_type = dwc2_hcd_select_transactions(hsotg);
+ if (tr_type != DWC2_TRANSACTION_NONE)
+ dwc2_hcd_queue_transactions(hsotg, tr_type);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+
+ return retval;
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb)
+{
+ struct dwc2_qh *qh;
+ struct dwc2_qtd *urb_qtd;
+
+ urb_qtd = urb->qtd;
+ if (!urb_qtd) {
+ dev_dbg(hsotg->dev, "## Urb QTD is NULL ##\n");
+ return -EINVAL;
+ }
+
+ qh = urb_qtd->qh;
+ if (!qh) {
+ dev_dbg(hsotg->dev, "## Urb QTD QH is NULL ##\n");
+ return -EINVAL;
+ }
+
+ if (urb_qtd->in_process && qh->channel) {
+ dwc2_dump_channel_info(hsotg, qh->channel);
+
+ /* The QTD is in process (it has been assigned to a channel) */
+ if (hsotg->flags.b.port_connect_status)
+ /*
+ * If still connected (i.e. in host mode), halt the
+ * channel so it can be used for other transfers. If
+ * no longer connected, the host registers can't be
+ * written to halt the channel since the core is in
+ * device mode.
+ */
+ dwc2_hc_halt(hsotg, qh->channel,
+ DWC2_HC_XFER_URB_DEQUEUE);
+ }
+
+ /*
+ * Free the QTD and clean up the associated QH. Leave the QH in the
+ * schedule if it has any remaining QTDs.
+ */
+ if (hsotg->core_params->dma_desc_enable <= 0) {
+ u8 in_process = urb_qtd->in_process;
+
+ dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
+ if (in_process) {
+ dwc2_hcd_qh_deactivate(hsotg, qh, 0);
+ qh->channel = NULL;
+ } else if (list_empty(&qh->qtd_list)) {
+ dwc2_hcd_qh_unlink(hsotg, qh);
+ }
+ } else {
+ dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh);
+ }
+
+ return 0;
+}
+
+/* Must NOT be called with interrupt disabled or spinlock held */
+static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg,
+ struct usb_host_endpoint *ep, int retry)
+{
+ struct dwc2_qtd *qtd, *qtd_tmp;
+ struct dwc2_qh *qh;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ qh = ep->hcpriv;
+ if (!qh) {
+ rc = -EINVAL;
+ goto err;
+ }
+
+ while (!list_empty(&qh->qtd_list) && retry--) {
+ if (retry == 0) {
+ dev_err(hsotg->dev,
+ "## timeout in dwc2_hcd_endpoint_disable() ##\n");
+ rc = -EBUSY;
+ goto err;
+ }
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ usleep_range(20000, 40000);
+ spin_lock_irqsave(&hsotg->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh) {
+ rc = -EINVAL;
+ goto err;
+ }
+ }
+
+ dwc2_hcd_qh_unlink(hsotg, qh);
+
+ /* Free each QTD in the QH's QTD list */
+ list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry)
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+ ep->hcpriv = NULL;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ dwc2_hcd_qh_free(hsotg, qh);
+
+ return 0;
+
+err:
+ ep->hcpriv = NULL;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ return rc;
+}
+
+/* Must be called with interrupt disabled and spinlock held */
+static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_qh *qh = ep->hcpriv;
+
+ if (!qh)
+ return -EINVAL;
+
+ qh->data_toggle = DWC2_HC_PID_DATA0;
+
+ return 0;
+}
+
+/*
+ * Initializes dynamic portions of the DWC_otg HCD state
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_host_chan *chan, *chan_tmp;
+ int num_channels;
+ int i;
+
+ hsotg->flags.d32 = 0;
+
+ hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active;
+ hsotg->non_periodic_channels = 0;
+ hsotg->periodic_channels = 0;
+
+ /*
+ * Put all channels in the free channel list and clean up channel
+ * states
+ */
+ list_for_each_entry_safe(chan, chan_tmp, &hsotg->free_hc_list,
+ hc_list_entry)
+ list_del_init(&chan->hc_list_entry);
+
+ num_channels = hsotg->core_params->host_channels;
+ for (i = 0; i < num_channels; i++) {
+ chan = hsotg->hc_ptr_array[i];
+ list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+ dwc2_hc_cleanup(hsotg, chan);
+ }
+
+ /* Initialize the DWC core for host mode operation */
+ dwc2_core_host_init(hsotg);
+}
+
+static void dwc2_hc_init_split(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
+{
+ int hub_addr, hub_port;
+
+ chan->do_split = 1;
+ chan->xact_pos = qtd->isoc_split_pos;
+ chan->complete_split = qtd->complete_split;
+ dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
+ chan->hub_addr = (u8)hub_addr;
+ chan->hub_port = (u8)hub_port;
+}
+
+static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd, void *bufptr)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+ switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ chan->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+ switch (qtd->control_phase) {
+ case DWC2_CONTROL_SETUP:
+ dev_vdbg(hsotg->dev, " Control setup transaction\n");
+ chan->do_ping = 0;
+ chan->ep_is_in = 0;
+ chan->data_pid_start = DWC2_HC_PID_SETUP;
+ if (hsotg->core_params->dma_enable > 0)
+ chan->xfer_dma = urb->setup_dma;
+ else
+ chan->xfer_buf = urb->setup_packet;
+ chan->xfer_len = 8;
+ bufptr = NULL;
+ break;
+
+ case DWC2_CONTROL_DATA:
+ dev_vdbg(hsotg->dev, " Control data transaction\n");
+ chan->data_pid_start = qtd->data_toggle;
+ break;
+
+ case DWC2_CONTROL_STATUS:
+ /*
+ * Direction is opposite of data direction or IN if no
+ * data
+ */
+ dev_vdbg(hsotg->dev, " Control status transaction\n");
+ if (urb->length == 0)
+ chan->ep_is_in = 1;
+ else
+ chan->ep_is_in =
+ dwc2_hcd_is_pipe_out(&urb->pipe_info);
+ if (chan->ep_is_in)
+ chan->do_ping = 0;
+ chan->data_pid_start = DWC2_HC_PID_DATA1;
+ chan->xfer_len = 0;
+ if (hsotg->core_params->dma_enable > 0)
+ chan->xfer_dma = hsotg->status_buf_dma;
+ else
+ chan->xfer_buf = hsotg->status_buf;
+ bufptr = NULL;
+ break;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ chan->ep_type = USB_ENDPOINT_XFER_BULK;
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ chan->ep_type = USB_ENDPOINT_XFER_INT;
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ chan->ep_type = USB_ENDPOINT_XFER_ISOC;
+ if (hsotg->core_params->dma_desc_enable > 0)
+ break;
+
+ frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+ frame_desc->status = 0;
+
+ if (hsotg->core_params->dma_enable > 0) {
+ chan->xfer_dma = urb->dma;
+ chan->xfer_dma += frame_desc->offset +
+ qtd->isoc_split_offset;
+ } else {
+ chan->xfer_buf = urb->buf;
+ chan->xfer_buf += frame_desc->offset +
+ qtd->isoc_split_offset;
+ }
+
+ chan->xfer_len = frame_desc->length - qtd->isoc_split_offset;
+
+ /* For non-dword aligned buffers */
+ if (hsotg->core_params->dma_enable > 0 &&
+ (chan->xfer_dma & 0x3))
+ bufptr = (u8 *)urb->buf + frame_desc->offset +
+ qtd->isoc_split_offset;
+ else
+ bufptr = NULL;
+
+ if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) {
+ if (chan->xfer_len <= 188)
+ chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL;
+ else
+ chan->xact_pos = DWC2_HCSPLT_XACTPOS_BEGIN;
+ }
+ break;
+ }
+
+ return bufptr;
+}
+
+static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ struct dwc2_host_chan *chan, void *bufptr)
+{
+ u32 buf_size;
+
+ if (chan->ep_type != USB_ENDPOINT_XFER_ISOC)
+ buf_size = hsotg->core_params->max_transfer_size;
+ else
+ buf_size = 4096;
+
+ if (!qh->dw_align_buf) {
+ qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
+ &qh->dw_align_buf_dma,
+ GFP_ATOMIC);
+ if (!qh->dw_align_buf)
+ return -ENOMEM;
+ }
+
+ if (!chan->ep_is_in && chan->xfer_len) {
+ dma_sync_single_for_cpu(hsotg->dev, chan->xfer_dma, buf_size,
+ DMA_TO_DEVICE);
+ memcpy(qh->dw_align_buf, bufptr, chan->xfer_len);
+ dma_sync_single_for_device(hsotg->dev, chan->xfer_dma, buf_size,
+ DMA_TO_DEVICE);
+ }
+
+ chan->align_buf = qh->dw_align_buf_dma;
+ return 0;
+}
+
+/**
+ * dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host
+ * channel and initializes the host channel to perform the transactions. The
+ * host channel is removed from the free list.
+ *
+ * @hsotg: The HCD state structure
+ * @qh: Transactions from the first QTD for this QH are selected and assigned
+ * to a free host channel
+ */
+static void dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ struct dwc2_host_chan *chan;
+ struct dwc2_hcd_urb *urb;
+ struct dwc2_qtd *qtd;
+ void *bufptr = NULL;
+
+ if (dbg_qh(qh))
+ dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh);
+
+ if (list_empty(&qh->qtd_list)) {
+ dev_dbg(hsotg->dev, "No QTDs in QH list\n");
+ return;
+ }
+
+ if (list_empty(&hsotg->free_hc_list)) {
+ dev_dbg(hsotg->dev, "No free channel to assign\n");
+ return;
+ }
+
+ chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan,
+ hc_list_entry);
+
+ /* Remove the host channel from the free list */
+ list_del_init(&chan->hc_list_entry);
+
+ qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
+ urb = qtd->urb;
+ qh->channel = chan;
+ qtd->in_process = 1;
+
+ /*
+ * Use usb_pipedevice to determine device address. This address is
+ * 0 before the SET_ADDRESS command and the correct address afterward.
+ */
+ chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info);
+ chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info);
+ chan->speed = qh->dev_speed;
+ chan->max_packet = dwc2_max_packet(qh->maxp);
+
+ chan->xfer_started = 0;
+ chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
+ chan->error_state = (qtd->error_count > 0);
+ chan->halt_on_queue = 0;
+ chan->halt_pending = 0;
+ chan->requests = 0;
+
+ /*
+ * The following values may be modified in the transfer type section
+ * below. The xfer_len value may be reduced when the transfer is
+ * started to accommodate the max widths of the XferSize and PktCnt
+ * fields in the HCTSIZn register.
+ */
+
+ chan->ep_is_in = (dwc2_hcd_is_pipe_in(&urb->pipe_info) != 0);
+ if (chan->ep_is_in)
+ chan->do_ping = 0;
+ else
+ chan->do_ping = qh->ping_state;
+
+ chan->data_pid_start = qh->data_toggle;
+ chan->multi_count = 1;
+
+ if (hsotg->core_params->dma_enable > 0) {
+ chan->xfer_dma = urb->dma + urb->actual_length;
+
+ /* For non-dword aligned case */
+ if (hsotg->core_params->dma_desc_enable <= 0 &&
+ (chan->xfer_dma & 0x3))
+ bufptr = (u8 *)urb->buf + urb->actual_length;
+ } else {
+ chan->xfer_buf = (u8 *)urb->buf + urb->actual_length;
+ }
+
+ chan->xfer_len = urb->length - urb->actual_length;
+ chan->xfer_count = 0;
+
+ /* Set the split attributes if required */
+ if (qh->do_split)
+ dwc2_hc_init_split(hsotg, chan, qtd, urb);
+ else
+ chan->do_split = 0;
+
+ /* Set the transfer attributes */
+ bufptr = dwc2_hc_init_xfer(hsotg, chan, qtd, bufptr);
+
+ /* Non DWORD-aligned buffer case */
+ if (bufptr) {
+ dev_vdbg(hsotg->dev, "Non-aligned buffer\n");
+ if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) {
+ dev_err(hsotg->dev,
+ "%s: Failed to allocate memory to handle non-dword aligned buffer\n",
+ __func__);
+ /* Add channel back to free list */
+ chan->align_buf = 0;
+ chan->multi_count = 0;
+ list_add_tail(&chan->hc_list_entry,
+ &hsotg->free_hc_list);
+ qtd->in_process = 0;
+ qh->channel = NULL;
+ return;
+ }
+ } else {
+ chan->align_buf = 0;
+ }
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC)
+ /*
+ * This value may be modified when the transfer is started
+ * to reflect the actual transfer length
+ */
+ chan->multi_count = dwc2_hb_mult(qh->maxp);
+
+ if (hsotg->core_params->dma_desc_enable > 0)
+ chan->desc_list_addr = qh->desc_list_dma;
+
+ dwc2_hc_init(hsotg, chan);
+ chan->qh = qh;
+}
+
+/**
+ * dwc2_hcd_select_transactions() - Selects transactions from the HCD transfer
+ * schedule and assigns them to available host channels. Called from the HCD
+ * interrupt handler functions.
+ *
+ * @hsotg: The HCD state structure
+ *
+ * Return: The types of new transactions that were assigned to host channels
+ */
+enum dwc2_transaction_type dwc2_hcd_select_transactions(
+ struct dwc2_hsotg *hsotg)
+{
+ enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE;
+ struct list_head *qh_ptr;
+ struct dwc2_qh *qh;
+ int num_channels;
+
+#ifdef DWC2_DEBUG_SOF
+ dev_vdbg(hsotg->dev, " Select Transactions\n");
+#endif
+
+ /* Process entries in the periodic ready list */
+ qh_ptr = hsotg->periodic_sched_ready.next;
+ while (qh_ptr != &hsotg->periodic_sched_ready) {
+ if (list_empty(&hsotg->free_hc_list))
+ break;
+ qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+ dwc2_assign_and_init_hc(hsotg, qh);
+
+ /*
+ * Move the QH from the periodic ready schedule to the
+ * periodic assigned schedule
+ */
+ qh_ptr = qh_ptr->next;
+ list_move(&qh->qh_list_entry, &hsotg->periodic_sched_assigned);
+ ret_val = DWC2_TRANSACTION_PERIODIC;
+ }
+
+ /*
+ * Process entries in the inactive portion of the non-periodic
+ * schedule. Some free host channels may not be used if they are
+ * reserved for periodic transfers.
+ */
+ num_channels = hsotg->core_params->host_channels;
+ qh_ptr = hsotg->non_periodic_sched_inactive.next;
+ while (qh_ptr != &hsotg->non_periodic_sched_inactive) {
+ if (hsotg->non_periodic_channels >= num_channels -
+ hsotg->periodic_channels)
+ break;
+ if (list_empty(&hsotg->free_hc_list))
+ break;
+ qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+ dwc2_assign_and_init_hc(hsotg, qh);
+
+ /*
+ * Move the QH from the non-periodic inactive schedule to the
+ * non-periodic active schedule
+ */
+ qh_ptr = qh_ptr->next;
+ list_move(&qh->qh_list_entry,
+ &hsotg->non_periodic_sched_active);
+
+ if (ret_val == DWC2_TRANSACTION_NONE)
+ ret_val = DWC2_TRANSACTION_NON_PERIODIC;
+ else
+ ret_val = DWC2_TRANSACTION_ALL;
+
+ hsotg->non_periodic_channels++;
+ }
+
+ return ret_val;
+}
+
+/**
+ * dwc2_queue_transaction() - Attempts to queue a single transaction request for
+ * a host channel associated with either a periodic or non-periodic transfer
+ *
+ * @hsotg: The HCD state structure
+ * @chan: Host channel descriptor associated with either a periodic or
+ * non-periodic transfer
+ * @fifo_dwords_avail: Number of DWORDs available in the periodic Tx FIFO
+ * for periodic transfers or the non-periodic Tx FIFO
+ * for non-periodic transfers
+ *
+ * Return: 1 if a request is queued and more requests may be needed to
+ * complete the transfer, 0 if no more requests are required for this
+ * transfer, -1 if there is insufficient space in the Tx FIFO
+ *
+ * This function assumes that there is space available in the appropriate
+ * request queue. For an OUT transfer or SETUP transaction in Slave mode,
+ * it checks whether space is available in the appropriate Tx FIFO.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ u16 fifo_dwords_avail)
+{
+ int retval = 0;
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ if (!chan->xfer_started ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ dwc2_hcd_start_xfer_ddma(hsotg, chan->qh);
+ chan->qh->ping_state = 0;
+ }
+ } else if (!chan->xfer_started) {
+ dwc2_hc_start_transfer(hsotg, chan);
+ chan->qh->ping_state = 0;
+ }
+ } else if (chan->halt_pending) {
+ /* Don't queue a request if the channel has been halted */
+ } else if (chan->halt_on_queue) {
+ dwc2_hc_halt(hsotg, chan, chan->halt_status);
+ } else if (chan->do_ping) {
+ if (!chan->xfer_started)
+ dwc2_hc_start_transfer(hsotg, chan);
+ } else if (!chan->ep_is_in ||
+ chan->data_pid_start == DWC2_HC_PID_SETUP) {
+ if ((fifo_dwords_avail * 4) >= chan->max_packet) {
+ if (!chan->xfer_started) {
+ dwc2_hc_start_transfer(hsotg, chan);
+ retval = 1;
+ } else {
+ retval = dwc2_hc_continue_transfer(hsotg, chan);
+ }
+ } else {
+ retval = -1;
+ }
+ } else {
+ if (!chan->xfer_started) {
+ dwc2_hc_start_transfer(hsotg, chan);
+ retval = 1;
+ } else {
+ retval = dwc2_hc_continue_transfer(hsotg, chan);
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Processes periodic channels for the next frame and queues transactions for
+ * these channels to the DWC_otg controller. After queueing transactions, the
+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
+ * to queue as Periodic Tx FIFO or request queue space becomes available.
+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
+{
+ struct list_head *qh_ptr;
+ struct dwc2_qh *qh;
+ u32 tx_status;
+ u32 fspcavail;
+ u32 gintmsk;
+ int status;
+ int no_queue_space = 0;
+ int no_fifo_space = 0;
+ u32 qspcavail;
+
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
+
+ tx_status = readl(hsotg->regs + HPTXSTS);
+ qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+
+ if (dbg_perio()) {
+ dev_vdbg(hsotg->dev, " P Tx Req Queue Space Avail (before queue): %d\n",
+ qspcavail);
+ dev_vdbg(hsotg->dev, " P Tx FIFO Space Avail (before queue): %d\n",
+ fspcavail);
+ }
+
+ qh_ptr = hsotg->periodic_sched_assigned.next;
+ while (qh_ptr != &hsotg->periodic_sched_assigned) {
+ tx_status = readl(hsotg->regs + HPTXSTS);
+ if ((tx_status & TXSTS_QSPCAVAIL_MASK) == 0) {
+ no_queue_space = 1;
+ break;
+ }
+
+ qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry);
+ if (!qh->channel) {
+ qh_ptr = qh_ptr->next;
+ continue;
+ }
+
+ /* Make sure EP's TT buffer is clean before queueing qtds */
+ if (qh->tt_buffer_dirty) {
+ qh_ptr = qh_ptr->next;
+ continue;
+ }
+
+ /*
+ * Set a flag if we're queuing high-bandwidth in slave mode.
+ * The flag prevents any halts to get into the request queue in
+ * the middle of multiple high-bandwidth packets getting queued.
+ */
+ if (hsotg->core_params->dma_enable <= 0 &&
+ qh->channel->multi_count > 1)
+ hsotg->queuing_high_bandwidth = 1;
+
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
+ if (status < 0) {
+ no_fifo_space = 1;
+ break;
+ }
+
+ /*
+ * In Slave mode, stay on the current transfer until there is
+ * nothing more to do or the high-bandwidth request count is
+ * reached. In DMA mode, only need to queue one request. The
+ * controller automatically handles multiple packets for
+ * high-bandwidth transfers.
+ */
+ if (hsotg->core_params->dma_enable > 0 || status == 0 ||
+ qh->channel->requests == qh->channel->multi_count) {
+ qh_ptr = qh_ptr->next;
+ /*
+ * Move the QH from the periodic assigned schedule to
+ * the periodic queued schedule
+ */
+ list_move(&qh->qh_list_entry,
+ &hsotg->periodic_sched_queued);
+
+ /* done queuing high bandwidth */
+ hsotg->queuing_high_bandwidth = 0;
+ }
+ }
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ tx_status = readl(hsotg->regs + HPTXSTS);
+ qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ if (dbg_perio()) {
+ dev_vdbg(hsotg->dev,
+ " P Tx Req Queue Space Avail (after queue): %d\n",
+ qspcavail);
+ dev_vdbg(hsotg->dev,
+ " P Tx FIFO Space Avail (after queue): %d\n",
+ fspcavail);
+ }
+
+ if (!list_empty(&hsotg->periodic_sched_assigned) ||
+ no_queue_space || no_fifo_space) {
+ /*
+ * May need to queue more transactions as the request
+ * queue or Tx FIFO empties. Enable the periodic Tx
+ * FIFO empty interrupt. (Always use the half-empty
+ * level to ensure that new requests are loaded as
+ * soon as possible.)
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk |= GINTSTS_PTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ } else {
+ /*
+ * Disable the Tx FIFO empty interrupt since there are
+ * no more transactions that need to be queued right
+ * now. This function is called from interrupt
+ * handlers to queue more transactions as transfer
+ * states change.
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk &= ~GINTSTS_PTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ }
+ }
+}
+
+/*
+ * Processes active non-periodic channels and queues transactions for these
+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
+ * FIFO Empty interrupt is enabled if there are more transactions to queue as
+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
+ * FIFO Empty interrupt is disabled.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
+{
+ struct list_head *orig_qh_ptr;
+ struct dwc2_qh *qh;
+ u32 tx_status;
+ u32 qspcavail;
+ u32 fspcavail;
+ u32 gintmsk;
+ int status;
+ int no_queue_space = 0;
+ int no_fifo_space = 0;
+ int more_to_do = 0;
+
+ dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
+
+ tx_status = readl(hsotg->regs + GNPTXSTS);
+ qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ dev_vdbg(hsotg->dev, " NP Tx Req Queue Space Avail (before queue): %d\n",
+ qspcavail);
+ dev_vdbg(hsotg->dev, " NP Tx FIFO Space Avail (before queue): %d\n",
+ fspcavail);
+
+ /*
+ * Keep track of the starting point. Skip over the start-of-list
+ * entry.
+ */
+ if (hsotg->non_periodic_qh_ptr == &hsotg->non_periodic_sched_active)
+ hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
+ orig_qh_ptr = hsotg->non_periodic_qh_ptr;
+
+ /*
+ * Process once through the active list or until no more space is
+ * available in the request queue or the Tx FIFO
+ */
+ do {
+ tx_status = readl(hsotg->regs + GNPTXSTS);
+ qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) {
+ no_queue_space = 1;
+ break;
+ }
+
+ qh = list_entry(hsotg->non_periodic_qh_ptr, struct dwc2_qh,
+ qh_list_entry);
+ if (!qh->channel)
+ goto next;
+
+ /* Make sure EP's TT buffer is clean before queueing qtds */
+ if (qh->tt_buffer_dirty)
+ goto next;
+
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail);
+
+ if (status > 0) {
+ more_to_do = 1;
+ } else if (status < 0) {
+ no_fifo_space = 1;
+ break;
+ }
+next:
+ /* Advance to next QH, skipping start-of-list entry */
+ hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next;
+ if (hsotg->non_periodic_qh_ptr ==
+ &hsotg->non_periodic_sched_active)
+ hsotg->non_periodic_qh_ptr =
+ hsotg->non_periodic_qh_ptr->next;
+ } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ tx_status = readl(hsotg->regs + GNPTXSTS);
+ qspcavail = tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT;
+ fspcavail = tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT;
+ dev_vdbg(hsotg->dev,
+ " NP Tx Req Queue Space Avail (after queue): %d\n",
+ qspcavail);
+ dev_vdbg(hsotg->dev,
+ " NP Tx FIFO Space Avail (after queue): %d\n",
+ fspcavail);
+
+ if (more_to_do || no_queue_space || no_fifo_space) {
+ /*
+ * May need to queue more transactions as the request
+ * queue or Tx FIFO empties. Enable the non-periodic
+ * Tx FIFO empty interrupt. (Always use the half-empty
+ * level to ensure that new requests are loaded as
+ * soon as possible.)
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk |= GINTSTS_NPTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ } else {
+ /*
+ * Disable the Tx FIFO empty interrupt since there are
+ * no more transactions that need to be queued right
+ * now. This function is called from interrupt
+ * handlers to queue more transactions as transfer
+ * states change.
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk &= ~GINTSTS_NPTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ }
+ }
+}
+
+/**
+ * dwc2_hcd_queue_transactions() - Processes the currently active host channels
+ * and queues transactions for these channels to the DWC_otg controller. Called
+ * from the HCD interrupt handler functions.
+ *
+ * @hsotg: The HCD state structure
+ * @tr_type: The type(s) of transactions to queue (non-periodic, periodic,
+ * or both)
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
+ enum dwc2_transaction_type tr_type)
+{
+#ifdef DWC2_DEBUG_SOF
+ dev_vdbg(hsotg->dev, "Queue Transactions\n");
+#endif
+ /* Process host channels associated with periodic transfers */
+ if ((tr_type == DWC2_TRANSACTION_PERIODIC ||
+ tr_type == DWC2_TRANSACTION_ALL) &&
+ !list_empty(&hsotg->periodic_sched_assigned))
+ dwc2_process_periodic_channels(hsotg);
+
+ /* Process host channels associated with non-periodic transfers */
+ if (tr_type == DWC2_TRANSACTION_NON_PERIODIC ||
+ tr_type == DWC2_TRANSACTION_ALL) {
+ if (!list_empty(&hsotg->non_periodic_sched_active)) {
+ dwc2_process_non_periodic_channels(hsotg);
+ } else {
+ /*
+ * Ensure NP Tx FIFO empty interrupt is disabled when
+ * there are no non-periodic transfers to process
+ */
+ u32 gintmsk = readl(hsotg->regs + GINTMSK);
+
+ gintmsk &= ~GINTSTS_NPTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ }
+ }
+}
+
+static void dwc2_conn_id_status_change(struct work_struct *work)
+{
+ struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+ wf_otg);
+ u32 count = 0;
+ u32 gotgctl;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
+ dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
+ !!(gotgctl & GOTGCTL_CONID_B));
+
+ /* B-Device connector (Device Mode) */
+ if (gotgctl & GOTGCTL_CONID_B) {
+ /* Wait for switch to device mode */
+ dev_dbg(hsotg->dev, "connId B\n");
+ while (!dwc2_is_device_mode(hsotg)) {
+ dev_info(hsotg->dev,
+ "Waiting for Peripheral Mode, Mode=%s\n",
+ dwc2_is_host_mode(hsotg) ? "Host" :
+ "Peripheral");
+ usleep_range(20000, 40000);
+ if (++count > 250)
+ break;
+ }
+ if (count > 250)
+ dev_err(hsotg->dev,
+ "Connection id status change timed out\n");
+ hsotg->op_state = OTG_STATE_B_PERIPHERAL;
+ dwc2_core_init(hsotg, false, -1);
+ dwc2_enable_global_interrupts(hsotg);
+ } else {
+ /* A-Device connector (Host Mode) */
+ dev_dbg(hsotg->dev, "connId A\n");
+ while (!dwc2_is_host_mode(hsotg)) {
+ dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n",
+ dwc2_is_host_mode(hsotg) ?
+ "Host" : "Peripheral");
+ usleep_range(20000, 40000);
+ if (++count > 250)
+ break;
+ }
+ if (count > 250)
+ dev_err(hsotg->dev,
+ "Connection id status change timed out\n");
+ hsotg->op_state = OTG_STATE_A_HOST;
+
+ /* Initialize the Core for Host mode */
+ dwc2_core_init(hsotg, false, -1);
+ dwc2_enable_global_interrupts(hsotg);
+ dwc2_hcd_start(hsotg);
+ }
+}
+
+static void dwc2_wakeup_detected(unsigned long data)
+{
+ struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)data;
+ u32 hprt0;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ /*
+ * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
+ * so that OPT tests pass with all PHYs.)
+ */
+ hprt0 = dwc2_read_hprt0(hsotg);
+ dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
+ hprt0 &= ~HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
+ readl(hsotg->regs + HPRT0));
+
+ dwc2_hcd_rem_wakeup(hsotg);
+
+ /* Change to L0 state */
+ hsotg->lx_state = DWC2_L0;
+}
+
+static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg)
+{
+ struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+ return hcd->self.b_hnp_enable;
+}
+
+/* Must NOT be called with interrupt disabled or spinlock held */
+static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
+{
+ unsigned long flags;
+ u32 hprt0;
+ u32 pcgctl;
+ u32 gotgctl;
+
+ dev_dbg(hsotg->dev, "%s()\n", __func__);
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
+ gotgctl = readl(hsotg->regs + GOTGCTL);
+ gotgctl |= GOTGCTL_HSTSETHNPEN;
+ writel(gotgctl, hsotg->regs + GOTGCTL);
+ hsotg->op_state = OTG_STATE_A_SUSPEND;
+ }
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_SUSP;
+ writel(hprt0, hsotg->regs + HPRT0);
+
+ /* Update lx_state */
+ hsotg->lx_state = DWC2_L2;
+
+ /* Suspend the Phy Clock */
+ pcgctl = readl(hsotg->regs + PCGCTL);
+ pcgctl |= PCGCTL_STOPPCLK;
+ writel(pcgctl, hsotg->regs + PCGCTL);
+ udelay(10);
+
+ /* For HNP the bus must be suspended for at least 200ms */
+ if (dwc2_host_is_b_hnp_enabled(hsotg)) {
+ pcgctl = readl(hsotg->regs + PCGCTL);
+ pcgctl &= ~PCGCTL_STOPPCLK;
+ writel(pcgctl, hsotg->regs + PCGCTL);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ usleep_range(200000, 250000);
+ } else {
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+}
+
+/* Handles hub class-specific requests */
+static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
+ u16 wvalue, u16 windex, char *buf, u16 wlength)
+{
+ struct usb_hub_descriptor *hub_desc;
+ int retval = 0;
+ u32 hprt0;
+ u32 port_status;
+ u32 speed;
+ u32 pcgctl;
+
+ switch (typereq) {
+ case ClearHubFeature:
+ dev_dbg(hsotg->dev, "ClearHubFeature %1xh\n", wvalue);
+
+ switch (wvalue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* Nothing required here */
+ break;
+
+ default:
+ retval = -EINVAL;
+ dev_err(hsotg->dev,
+ "ClearHubFeature request %1xh unknown\n",
+ wvalue);
+ }
+ break;
+
+ case ClearPortFeature:
+ if (wvalue != USB_PORT_FEAT_L1)
+ if (!windex || windex > 1)
+ goto error;
+ switch (wvalue) {
+ case USB_PORT_FEAT_ENABLE:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_ENA;
+ writel(hprt0, hsotg->regs + HPRT0);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+ writel(0, hsotg->regs + PCGCTL);
+ usleep_range(20000, 40000);
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hprt0 &= ~HPRT0_SUSP;
+ usleep_range(100000, 150000);
+
+ hprt0 &= ~HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_POWER\n");
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 &= ~HPRT0_PWR;
+ writel(hprt0, hsotg->regs + HPRT0);
+ break;
+
+ case USB_PORT_FEAT_INDICATOR:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+ /* Port indicator not supported */
+ break;
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ /*
+ * Clears driver's internal Connect Status Change flag
+ */
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+ hsotg->flags.b.port_connect_status_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_RESET:
+ /* Clears driver's internal Port Reset Change flag */
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+ hsotg->flags.b.port_reset_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_ENABLE:
+ /*
+ * Clears the driver's internal Port Enable/Disable
+ * Change flag
+ */
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+ hsotg->flags.b.port_enable_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ /*
+ * Clears the driver's internal Port Suspend Change
+ * flag, which is set when resume signaling on the host
+ * port is complete
+ */
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+ hsotg->flags.b.port_suspend_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_PORT_L1:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_PORT_L1\n");
+ hsotg->flags.b.port_l1_change = 0;
+ break;
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(hsotg->dev,
+ "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+ hsotg->flags.b.port_over_current_change = 0;
+ break;
+
+ default:
+ retval = -EINVAL;
+ dev_err(hsotg->dev,
+ "ClearPortFeature request %1xh unknown or unsupported\n",
+ wvalue);
+ }
+ break;
+
+ case GetHubDescriptor:
+ dev_dbg(hsotg->dev, "GetHubDescriptor\n");
+ hub_desc = (struct usb_hub_descriptor *)buf;
+ hub_desc->bDescLength = 9;
+ hub_desc->bDescriptorType = 0x29;
+ hub_desc->bNbrPorts = 1;
+ hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
+ hub_desc->bPwrOn2PwrGood = 1;
+ hub_desc->bHubContrCurrent = 0;
+ hub_desc->u.hs.DeviceRemovable[0] = 0;
+ hub_desc->u.hs.DeviceRemovable[1] = 0xff;
+ break;
+
+ case GetHubStatus:
+ dev_dbg(hsotg->dev, "GetHubStatus\n");
+ memset(buf, 0, 4);
+ break;
+
+ case GetPortStatus:
+ dev_dbg(hsotg->dev,
+ "GetPortStatus wIndex=0x%04x flags=0x%08x\n", windex,
+ hsotg->flags.d32);
+ if (!windex || windex > 1)
+ goto error;
+
+ port_status = 0;
+ if (hsotg->flags.b.port_connect_status_change)
+ port_status |= USB_PORT_STAT_C_CONNECTION << 16;
+ if (hsotg->flags.b.port_enable_change)
+ port_status |= USB_PORT_STAT_C_ENABLE << 16;
+ if (hsotg->flags.b.port_suspend_change)
+ port_status |= USB_PORT_STAT_C_SUSPEND << 16;
+ if (hsotg->flags.b.port_l1_change)
+ port_status |= USB_PORT_STAT_C_L1 << 16;
+ if (hsotg->flags.b.port_reset_change)
+ port_status |= USB_PORT_STAT_C_RESET << 16;
+ if (hsotg->flags.b.port_over_current_change) {
+ dev_warn(hsotg->dev, "Overcurrent change detected\n");
+ port_status |= USB_PORT_STAT_C_OVERCURRENT << 16;
+ }
+
+ if (!hsotg->flags.b.port_connect_status) {
+ /*
+ * The port is disconnected, which means the core is
+ * either in device mode or it soon will be. Just
+ * return 0's for the remainder of the port status
+ * since the port register can't be read if the core
+ * is in device mode.
+ */
+ *(__le32 *)buf = cpu_to_le32(port_status);
+ break;
+ }
+
+ hprt0 = readl(hsotg->regs + HPRT0);
+ dev_dbg(hsotg->dev, " HPRT0: 0x%08x\n", hprt0);
+
+ if (hprt0 & HPRT0_CONNSTS)
+ port_status |= USB_PORT_STAT_CONNECTION;
+ if (hprt0 & HPRT0_ENA)
+ port_status |= USB_PORT_STAT_ENABLE;
+ if (hprt0 & HPRT0_SUSP)
+ port_status |= USB_PORT_STAT_SUSPEND;
+ if (hprt0 & HPRT0_OVRCURRACT)
+ port_status |= USB_PORT_STAT_OVERCURRENT;
+ if (hprt0 & HPRT0_RST)
+ port_status |= USB_PORT_STAT_RESET;
+ if (hprt0 & HPRT0_PWR)
+ port_status |= USB_PORT_STAT_POWER;
+
+ speed = hprt0 & HPRT0_SPD_MASK;
+ if (speed == HPRT0_SPD_HIGH_SPEED)
+ port_status |= USB_PORT_STAT_HIGH_SPEED;
+ else if (speed == HPRT0_SPD_LOW_SPEED)
+ port_status |= USB_PORT_STAT_LOW_SPEED;
+
+ if (hprt0 & HPRT0_TSTCTL_MASK)
+ port_status |= USB_PORT_STAT_TEST;
+ /* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+
+ dev_dbg(hsotg->dev, "port_status=%08x\n", port_status);
+ *(__le32 *)buf = cpu_to_le32(port_status);
+ break;
+
+ case SetHubFeature:
+ dev_dbg(hsotg->dev, "SetHubFeature\n");
+ /* No HUB features supported */
+ break;
+
+ case SetPortFeature:
+ dev_dbg(hsotg->dev, "SetPortFeature\n");
+ if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1))
+ goto error;
+
+ if (!hsotg->flags.b.port_connect_status) {
+ /*
+ * The port is disconnected, which means the core is
+ * either in device mode or it soon will be. Just
+ * return without doing anything since the port
+ * register can't be written if the core is in device
+ * mode.
+ */
+ break;
+ }
+
+ switch (wvalue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(hsotg->dev,
+ "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+ if (windex != hsotg->otg_port)
+ goto error;
+ dwc2_port_suspend(hsotg, windex);
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(hsotg->dev,
+ "SetPortFeature - USB_PORT_FEAT_POWER\n");
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_PWR;
+ writel(hprt0, hsotg->regs + HPRT0);
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ hprt0 = dwc2_read_hprt0(hsotg);
+ dev_dbg(hsotg->dev,
+ "SetPortFeature - USB_PORT_FEAT_RESET\n");
+ pcgctl = readl(hsotg->regs + PCGCTL);
+ pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
+ writel(pcgctl, hsotg->regs + PCGCTL);
+ /* ??? Original driver does this */
+ writel(0, hsotg->regs + PCGCTL);
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ /* Clear suspend bit if resetting from suspend state */
+ hprt0 &= ~HPRT0_SUSP;
+
+ /*
+ * When B-Host the Port reset bit is set in the Start
+ * HCD Callback function, so that the reset is started
+ * within 1ms of the HNP success interrupt
+ */
+ if (!dwc2_hcd_is_b_host(hsotg)) {
+ hprt0 |= HPRT0_PWR | HPRT0_RST;
+ dev_dbg(hsotg->dev,
+ "In host mode, hprt0=%08x\n", hprt0);
+ writel(hprt0, hsotg->regs + HPRT0);
+ }
+
+ /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+ usleep_range(50000, 70000);
+ hprt0 &= ~HPRT0_RST;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hsotg->lx_state = DWC2_L0; /* Now back to On state */
+ break;
+
+ case USB_PORT_FEAT_INDICATOR:
+ dev_dbg(hsotg->dev,
+ "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+ /* Not supported */
+ break;
+
+ default:
+ retval = -EINVAL;
+ dev_err(hsotg->dev,
+ "SetPortFeature %1xh unknown or unsupported\n",
+ wvalue);
+ break;
+ }
+ break;
+
+ default:
+error:
+ retval = -EINVAL;
+ dev_dbg(hsotg->dev,
+ "Unknown hub control request: %1xh wIndex: %1xh wValue: %1xh\n",
+ typereq, windex, wvalue);
+ break;
+ }
+
+ return retval;
+}
+
+static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
+{
+ int retval;
+
+ if (port != 1)
+ return -EINVAL;
+
+ retval = (hsotg->flags.b.port_connect_status_change ||
+ hsotg->flags.b.port_reset_change ||
+ hsotg->flags.b.port_enable_change ||
+ hsotg->flags.b.port_suspend_change ||
+ hsotg->flags.b.port_over_current_change);
+
+ if (retval) {
+ dev_dbg(hsotg->dev,
+ "DWC OTG HCD HUB STATUS DATA: Root port status changed\n");
+ dev_dbg(hsotg->dev, " port_connect_status_change: %d\n",
+ hsotg->flags.b.port_connect_status_change);
+ dev_dbg(hsotg->dev, " port_reset_change: %d\n",
+ hsotg->flags.b.port_reset_change);
+ dev_dbg(hsotg->dev, " port_enable_change: %d\n",
+ hsotg->flags.b.port_enable_change);
+ dev_dbg(hsotg->dev, " port_suspend_change: %d\n",
+ hsotg->flags.b.port_suspend_change);
+ dev_dbg(hsotg->dev, " port_over_current_change: %d\n",
+ hsotg->flags.b.port_over_current_change);
+ }
+
+ return retval;
+}
+
+int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
+{
+ u32 hfnum = readl(hsotg->regs + HFNUM);
+
+#ifdef DWC2_DEBUG_SOF
+ dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
+ hfnum >> HFNUM_FRNUM_SHIFT &
+ HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT);
+#endif
+ return hfnum >> HFNUM_FRNUM_SHIFT &
+ HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT;
+}
+
+int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg)
+{
+ return (hsotg->op_state == OTG_STATE_B_HOST);
+}
+
+static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
+ int iso_desc_count,
+ gfp_t mem_flags)
+{
+ struct dwc2_hcd_urb *urb;
+ u32 size = sizeof(*urb) + iso_desc_count *
+ sizeof(struct dwc2_hcd_iso_packet_desc);
+
+ urb = kzalloc(size, mem_flags);
+ if (urb)
+ urb->packet_count = iso_desc_count;
+ return urb;
+}
+
+static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb, u8 dev_addr,
+ u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps)
+{
+ if (dbg_perio() ||
+ ep_type == USB_ENDPOINT_XFER_BULK ||
+ ep_type == USB_ENDPOINT_XFER_CONTROL)
+ dev_vdbg(hsotg->dev,
+ "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n",
+ dev_addr, ep_num, ep_dir, ep_type, mps);
+ urb->pipe_info.dev_addr = dev_addr;
+ urb->pipe_info.ep_num = ep_num;
+ urb->pipe_info.pipe_type = ep_type;
+ urb->pipe_info.pipe_dir = ep_dir;
+ urb->pipe_info.mps = mps;
+}
+
+/*
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
+{
+#ifdef DEBUG
+ struct dwc2_host_chan *chan;
+ struct dwc2_hcd_urb *urb;
+ struct dwc2_qtd *qtd;
+ int num_channels;
+ u32 np_tx_status;
+ u32 p_tx_status;
+ int i;
+
+ num_channels = hsotg->core_params->host_channels;
+ dev_dbg(hsotg->dev, "\n");
+ dev_dbg(hsotg->dev,
+ "************************************************************\n");
+ dev_dbg(hsotg->dev, "HCD State:\n");
+ dev_dbg(hsotg->dev, " Num channels: %d\n", num_channels);
+
+ for (i = 0; i < num_channels; i++) {
+ chan = hsotg->hc_ptr_array[i];
+ dev_dbg(hsotg->dev, " Channel %d:\n", i);
+ dev_dbg(hsotg->dev,
+ " dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+ chan->dev_addr, chan->ep_num, chan->ep_is_in);
+ dev_dbg(hsotg->dev, " speed: %d\n", chan->speed);
+ dev_dbg(hsotg->dev, " ep_type: %d\n", chan->ep_type);
+ dev_dbg(hsotg->dev, " max_packet: %d\n", chan->max_packet);
+ dev_dbg(hsotg->dev, " data_pid_start: %d\n",
+ chan->data_pid_start);
+ dev_dbg(hsotg->dev, " multi_count: %d\n", chan->multi_count);
+ dev_dbg(hsotg->dev, " xfer_started: %d\n",
+ chan->xfer_started);
+ dev_dbg(hsotg->dev, " xfer_buf: %p\n", chan->xfer_buf);
+ dev_dbg(hsotg->dev, " xfer_dma: %08lx\n",
+ (unsigned long)chan->xfer_dma);
+ dev_dbg(hsotg->dev, " xfer_len: %d\n", chan->xfer_len);
+ dev_dbg(hsotg->dev, " xfer_count: %d\n", chan->xfer_count);
+ dev_dbg(hsotg->dev, " halt_on_queue: %d\n",
+ chan->halt_on_queue);
+ dev_dbg(hsotg->dev, " halt_pending: %d\n",
+ chan->halt_pending);
+ dev_dbg(hsotg->dev, " halt_status: %d\n", chan->halt_status);
+ dev_dbg(hsotg->dev, " do_split: %d\n", chan->do_split);
+ dev_dbg(hsotg->dev, " complete_split: %d\n",
+ chan->complete_split);
+ dev_dbg(hsotg->dev, " hub_addr: %d\n", chan->hub_addr);
+ dev_dbg(hsotg->dev, " hub_port: %d\n", chan->hub_port);
+ dev_dbg(hsotg->dev, " xact_pos: %d\n", chan->xact_pos);
+ dev_dbg(hsotg->dev, " requests: %d\n", chan->requests);
+ dev_dbg(hsotg->dev, " qh: %p\n", chan->qh);
+
+ if (chan->xfer_started) {
+ u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
+
+ hfnum = readl(hsotg->regs + HFNUM);
+ hcchar = readl(hsotg->regs + HCCHAR(i));
+ hctsiz = readl(hsotg->regs + HCTSIZ(i));
+ hcint = readl(hsotg->regs + HCINT(i));
+ hcintmsk = readl(hsotg->regs + HCINTMSK(i));
+ dev_dbg(hsotg->dev, " hfnum: 0x%08x\n", hfnum);
+ dev_dbg(hsotg->dev, " hcchar: 0x%08x\n", hcchar);
+ dev_dbg(hsotg->dev, " hctsiz: 0x%08x\n", hctsiz);
+ dev_dbg(hsotg->dev, " hcint: 0x%08x\n", hcint);
+ dev_dbg(hsotg->dev, " hcintmsk: 0x%08x\n", hcintmsk);
+ }
+
+ if (!(chan->xfer_started && chan->qh))
+ continue;
+
+ list_for_each_entry(qtd, &chan->qh->qtd_list, qtd_list_entry) {
+ if (!qtd->in_process)
+ break;
+ urb = qtd->urb;
+ dev_dbg(hsotg->dev, " URB Info:\n");
+ dev_dbg(hsotg->dev, " qtd: %p, urb: %p\n",
+ qtd, urb);
+ if (urb) {
+ dev_dbg(hsotg->dev,
+ " Dev: %d, EP: %d %s\n",
+ dwc2_hcd_get_dev_addr(&urb->pipe_info),
+ dwc2_hcd_get_ep_num(&urb->pipe_info),
+ dwc2_hcd_is_pipe_in(&urb->pipe_info) ?
+ "IN" : "OUT");
+ dev_dbg(hsotg->dev,
+ " Max packet size: %d\n",
+ dwc2_hcd_get_mps(&urb->pipe_info));
+ dev_dbg(hsotg->dev,
+ " transfer_buffer: %p\n",
+ urb->buf);
+ dev_dbg(hsotg->dev,
+ " transfer_dma: %08lx\n",
+ (unsigned long)urb->dma);
+ dev_dbg(hsotg->dev,
+ " transfer_buffer_length: %d\n",
+ urb->length);
+ dev_dbg(hsotg->dev, " actual_length: %d\n",
+ urb->actual_length);
+ }
+ }
+ }
+
+ dev_dbg(hsotg->dev, " non_periodic_channels: %d\n",
+ hsotg->non_periodic_channels);
+ dev_dbg(hsotg->dev, " periodic_channels: %d\n",
+ hsotg->periodic_channels);
+ dev_dbg(hsotg->dev, " periodic_usecs: %d\n", hsotg->periodic_usecs);
+ np_tx_status = readl(hsotg->regs + GNPTXSTS);
+ dev_dbg(hsotg->dev, " NP Tx Req Queue Space Avail: %d\n",
+ np_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+ dev_dbg(hsotg->dev, " NP Tx FIFO Space Avail: %d\n",
+ np_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+ p_tx_status = readl(hsotg->regs + HPTXSTS);
+ dev_dbg(hsotg->dev, " P Tx Req Queue Space Avail: %d\n",
+ p_tx_status >> TXSTS_QSPCAVAIL_SHIFT &
+ TXSTS_QSPCAVAIL_MASK >> TXSTS_QSPCAVAIL_SHIFT);
+ dev_dbg(hsotg->dev, " P Tx FIFO Space Avail: %d\n",
+ p_tx_status >> TXSTS_FSPCAVAIL_SHIFT &
+ TXSTS_FSPCAVAIL_MASK >> TXSTS_FSPCAVAIL_SHIFT);
+ dwc2_hcd_dump_frrem(hsotg);
+ dwc2_dump_global_registers(hsotg);
+ dwc2_dump_host_registers(hsotg);
+ dev_dbg(hsotg->dev,
+ "************************************************************\n");
+ dev_dbg(hsotg->dev, "\n");
+#endif
+}
+
+/*
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg)
+{
+#ifdef DWC2_DUMP_FRREM
+ dev_dbg(hsotg->dev, "Frame remaining at SOF:\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->frrem_samples, hsotg->frrem_accum,
+ hsotg->frrem_samples > 0 ?
+ hsotg->frrem_accum / hsotg->frrem_samples : 0);
+ dev_dbg(hsotg->dev, "\n");
+ dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 7):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_7_samples,
+ hsotg->hfnum_7_frrem_accum,
+ hsotg->hfnum_7_samples > 0 ?
+ hsotg->hfnum_7_frrem_accum / hsotg->hfnum_7_samples : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 0):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_0_samples,
+ hsotg->hfnum_0_frrem_accum,
+ hsotg->hfnum_0_samples > 0 ?
+ hsotg->hfnum_0_frrem_accum / hsotg->hfnum_0_samples : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 1-6):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_other_samples,
+ hsotg->hfnum_other_frrem_accum,
+ hsotg->hfnum_other_samples > 0 ?
+ hsotg->hfnum_other_frrem_accum / hsotg->hfnum_other_samples :
+ 0);
+ dev_dbg(hsotg->dev, "\n");
+ dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 7):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_7_samples_a, hsotg->hfnum_7_frrem_accum_a,
+ hsotg->hfnum_7_samples_a > 0 ?
+ hsotg->hfnum_7_frrem_accum_a / hsotg->hfnum_7_samples_a : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 0):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_0_samples_a, hsotg->hfnum_0_frrem_accum_a,
+ hsotg->hfnum_0_samples_a > 0 ?
+ hsotg->hfnum_0_frrem_accum_a / hsotg->hfnum_0_samples_a : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 1-6):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_other_samples_a, hsotg->hfnum_other_frrem_accum_a,
+ hsotg->hfnum_other_samples_a > 0 ?
+ hsotg->hfnum_other_frrem_accum_a / hsotg->hfnum_other_samples_a
+ : 0);
+ dev_dbg(hsotg->dev, "\n");
+ dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 7):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_7_samples_b, hsotg->hfnum_7_frrem_accum_b,
+ hsotg->hfnum_7_samples_b > 0 ?
+ hsotg->hfnum_7_frrem_accum_b / hsotg->hfnum_7_samples_b : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 0):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_0_samples_b, hsotg->hfnum_0_frrem_accum_b,
+ (hsotg->hfnum_0_samples_b > 0) ?
+ hsotg->hfnum_0_frrem_accum_b / hsotg->hfnum_0_samples_b : 0);
+ dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 1-6):\n");
+ dev_dbg(hsotg->dev, " samples %u, accum %llu, avg %llu\n",
+ hsotg->hfnum_other_samples_b, hsotg->hfnum_other_frrem_accum_b,
+ (hsotg->hfnum_other_samples_b > 0) ?
+ hsotg->hfnum_other_frrem_accum_b / hsotg->hfnum_other_samples_b
+ : 0);
+#endif
+}
+
+struct wrapper_priv_data {
+ struct dwc2_hsotg *hsotg;
+};
+
+/* Gets the dwc2_hsotg from a usb_hcd */
+static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd)
+{
+ struct wrapper_priv_data *p;
+
+ p = (struct wrapper_priv_data *) &hcd->hcd_priv;
+ return p->hsotg;
+}
+
+static int _dwc2_hcd_start(struct usb_hcd *hcd);
+
+void dwc2_host_start(struct dwc2_hsotg *hsotg)
+{
+ struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+ hcd->self.is_b_host = dwc2_hcd_is_b_host(hsotg);
+ _dwc2_hcd_start(hcd);
+}
+
+void dwc2_host_disconnect(struct dwc2_hsotg *hsotg)
+{
+ struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg);
+
+ hcd->self.is_b_host = 0;
+}
+
+void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, int *hub_addr,
+ int *hub_port)
+{
+ struct urb *urb = context;
+
+ if (urb->dev->tt)
+ *hub_addr = urb->dev->tt->hub->devnum;
+ else
+ *hub_addr = 0;
+ *hub_port = urb->dev->ttport;
+}
+
+int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context)
+{
+ struct urb *urb = context;
+
+ return urb->dev->speed;
+}
+
+static void dwc2_allocate_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
+ struct urb *urb)
+{
+ struct usb_bus *bus = hcd_to_bus(hcd);
+
+ if (urb->interval)
+ bus->bandwidth_allocated += bw / urb->interval;
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+ bus->bandwidth_isoc_reqs++;
+ else
+ bus->bandwidth_int_reqs++;
+}
+
+static void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw,
+ struct urb *urb)
+{
+ struct usb_bus *bus = hcd_to_bus(hcd);
+
+ if (urb->interval)
+ bus->bandwidth_allocated -= bw / urb->interval;
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+ bus->bandwidth_isoc_reqs--;
+ else
+ bus->bandwidth_int_reqs--;
+}
+
+/*
+ * Sets the final status of an URB and returns it to the upper layer. Any
+ * required cleanup of the URB is performed.
+ *
+ * Must be called with interrupt disabled and spinlock held
+ */
+void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
+ struct dwc2_hcd_urb *dwc2_urb, int status)
+{
+ struct urb *urb = context;
+ int i;
+
+ if (!urb) {
+ dev_dbg(hsotg->dev, "## %s: context is NULL ##\n", __func__);
+ return;
+ }
+
+ if (!dwc2_urb) {
+ dev_dbg(hsotg->dev, "## %s: dwc2_urb is NULL ##\n", __func__);
+ return;
+ }
+
+ urb->actual_length = dwc2_hcd_urb_get_actual_length(dwc2_urb);
+
+ if (dbg_urb(urb))
+ dev_vdbg(hsotg->dev,
+ "%s: urb %p device %d ep %d-%s status %d actual %d\n",
+ __func__, urb, usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "IN" : "OUT", status,
+ urb->actual_length);
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) {
+ for (i = 0; i < urb->number_of_packets; i++)
+ dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n",
+ i, urb->iso_frame_desc[i].status);
+ }
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ urb->error_count = dwc2_hcd_urb_get_error_count(dwc2_urb);
+ for (i = 0; i < urb->number_of_packets; ++i) {
+ urb->iso_frame_desc[i].actual_length =
+ dwc2_hcd_urb_get_iso_desc_actual_length(
+ dwc2_urb, i);
+ urb->iso_frame_desc[i].status =
+ dwc2_hcd_urb_get_iso_desc_status(dwc2_urb, i);
+ }
+ }
+
+ urb->status = status;
+ urb->hcpriv = NULL;
+ if (!status) {
+ if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length)
+ urb->status = -EREMOTEIO;
+ }
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
+ usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ struct usb_host_endpoint *ep = urb->ep;
+
+ if (ep)
+ dwc2_free_bus_bandwidth(dwc2_hsotg_to_hcd(hsotg),
+ dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+ urb);
+ }
+
+ kfree(dwc2_urb);
+
+ spin_unlock(&hsotg->lock);
+ usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status);
+ spin_lock(&hsotg->lock);
+}
+
+/*
+ * Work queue function for starting the HCD when A-Cable is connected
+ */
+static void dwc2_hcd_start_func(struct work_struct *work)
+{
+ struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+ start_work.work);
+
+ dev_dbg(hsotg->dev, "%s() %p\n", __func__, hsotg);
+ dwc2_host_start(hsotg);
+}
+
+/*
+ * Reset work queue function
+ */
+static void dwc2_hcd_reset_func(struct work_struct *work)
+{
+ struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg,
+ reset_work.work);
+ u32 hprt0;
+
+ dev_dbg(hsotg->dev, "USB RESET function called\n");
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 &= ~HPRT0_RST;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hsotg->flags.b.port_reset_change = 1;
+}
+
+/*
+ * =========================================================================
+ * Linux HC Driver Functions
+ * =========================================================================
+ */
+
+/*
+ * Initializes the DWC_otg controller and its root hub and prepares it for host
+ * mode operation. Activates the root port. Returns 0 on success and a negative
+ * error code on failure.
+ */
+static int _dwc2_hcd_start(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ struct usb_bus *bus = hcd_to_bus(hcd);
+ unsigned long flags;
+
+ dev_dbg(hsotg->dev, "DWC OTG HCD START\n");
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ hcd->state = HC_STATE_RUNNING;
+
+ if (dwc2_is_device_mode(hsotg)) {
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return 0; /* why 0 ?? */
+ }
+
+ dwc2_hcd_reinit(hsotg);
+
+ /* Initialize and connect root hub if one is not already attached */
+ if (bus->root_hub) {
+ dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n");
+ /* Inform the HUB driver to resume */
+ usb_hcd_resume_root_hub(hcd);
+ }
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return 0;
+}
+
+/*
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped.
+ */
+static void _dwc2_hcd_stop(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_hcd_stop(hsotg);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ usleep_range(1000, 3000);
+}
+
+/* Returns the current frame number */
+static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+ return dwc2_hcd_get_frame_number(hsotg);
+}
+
+static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb,
+ char *fn_name)
+{
+#ifdef VERBOSE_DEBUG
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ char *pipetype;
+ char *speed;
+
+ dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb);
+ dev_vdbg(hsotg->dev, " Device address: %d\n",
+ usb_pipedevice(urb->pipe));
+ dev_vdbg(hsotg->dev, " Endpoint: %d, %s\n",
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "IN" : "OUT");
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ pipetype = "CONTROL";
+ break;
+ case PIPE_BULK:
+ pipetype = "BULK";
+ break;
+ case PIPE_INTERRUPT:
+ pipetype = "INTERRUPT";
+ break;
+ case PIPE_ISOCHRONOUS:
+ pipetype = "ISOCHRONOUS";
+ break;
+ default:
+ pipetype = "UNKNOWN";
+ break;
+ }
+
+ dev_vdbg(hsotg->dev, " Endpoint type: %s %s (%s)\n", pipetype,
+ usb_urb_dir_in(urb) ? "IN" : "OUT", usb_pipein(urb->pipe) ?
+ "IN" : "OUT");
+
+ switch (urb->dev->speed) {
+ case USB_SPEED_HIGH:
+ speed = "HIGH";
+ break;
+ case USB_SPEED_FULL:
+ speed = "FULL";
+ break;
+ case USB_SPEED_LOW:
+ speed = "LOW";
+ break;
+ default:
+ speed = "UNKNOWN";
+ break;
+ }
+
+ dev_vdbg(hsotg->dev, " Speed: %s\n", speed);
+ dev_vdbg(hsotg->dev, " Max packet size: %d\n",
+ usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+ dev_vdbg(hsotg->dev, " Data buffer length: %d\n",
+ urb->transfer_buffer_length);
+ dev_vdbg(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n",
+ urb->transfer_buffer, (unsigned long)urb->transfer_dma);
+ dev_vdbg(hsotg->dev, " Setup buffer: %p, Setup DMA: %08lx\n",
+ urb->setup_packet, (unsigned long)urb->setup_dma);
+ dev_vdbg(hsotg->dev, " Interval: %d\n", urb->interval);
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ int i;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ dev_vdbg(hsotg->dev, " ISO Desc %d:\n", i);
+ dev_vdbg(hsotg->dev, " offset: %d, length %d\n",
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].length);
+ }
+ }
+#endif
+}
+
+/*
+ * Starts processing a USB transfer request specified by a USB Request Block
+ * (URB). mem_flags indicates the type of memory allocation to use while
+ * processing this URB.
+ */
+static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ struct usb_host_endpoint *ep = urb->ep;
+ struct dwc2_hcd_urb *dwc2_urb;
+ int i;
+ int alloc_bandwidth = 0;
+ int retval = 0;
+ u8 ep_type = 0;
+ u32 tflags = 0;
+ void *buf;
+ unsigned long flags;
+
+ if (dbg_urb(urb)) {
+ dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n");
+ dwc2_dump_urb_info(hcd, urb, "urb_enqueue");
+ }
+
+ if (ep == NULL)
+ return -EINVAL;
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS ||
+ usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ spin_lock_irqsave(&hsotg->lock, flags);
+ if (!dwc2_hcd_is_bandwidth_allocated(hsotg, ep))
+ alloc_bandwidth = 1;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ep_type = USB_ENDPOINT_XFER_CONTROL;
+ break;
+ case PIPE_ISOCHRONOUS:
+ ep_type = USB_ENDPOINT_XFER_ISOC;
+ break;
+ case PIPE_BULK:
+ ep_type = USB_ENDPOINT_XFER_BULK;
+ break;
+ case PIPE_INTERRUPT:
+ ep_type = USB_ENDPOINT_XFER_INT;
+ break;
+ default:
+ dev_warn(hsotg->dev, "Wrong ep type\n");
+ }
+
+ dwc2_urb = dwc2_hcd_urb_alloc(hsotg, urb->number_of_packets,
+ mem_flags);
+ if (!dwc2_urb)
+ return -ENOMEM;
+
+ dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe), ep_type,
+ usb_pipein(urb->pipe),
+ usb_maxpacket(urb->dev, urb->pipe,
+ !(usb_pipein(urb->pipe))));
+
+ buf = urb->transfer_buffer;
+ if (hcd->self.uses_dma) {
+ /*
+ * Calculate virtual address from physical address, because
+ * some class driver may not fill transfer_buffer.
+ * In Buffer DMA mode virtual address is used, when handling
+ * non-DWORD aligned buffers.
+ */
+ buf = bus_to_virt(urb->transfer_dma);
+ }
+
+ if (!(urb->transfer_flags & URB_NO_INTERRUPT))
+ tflags |= URB_GIVEBACK_ASAP;
+ if (urb->transfer_flags & URB_ZERO_PACKET)
+ tflags |= URB_SEND_ZERO_PACKET;
+
+ dwc2_urb->priv = urb;
+ dwc2_urb->buf = buf;
+ dwc2_urb->dma = urb->transfer_dma;
+ dwc2_urb->length = urb->transfer_buffer_length;
+ dwc2_urb->setup_packet = urb->setup_packet;
+ dwc2_urb->setup_dma = urb->setup_dma;
+ dwc2_urb->flags = tflags;
+ dwc2_urb->interval = urb->interval;
+ dwc2_urb->status = -EINPROGRESS;
+
+ for (i = 0; i < urb->number_of_packets; ++i)
+ dwc2_hcd_urb_set_iso_desc_params(dwc2_urb, i,
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].length);
+
+ urb->hcpriv = dwc2_urb;
+ retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv,
+ mem_flags);
+ if (retval) {
+ urb->hcpriv = NULL;
+ kfree(dwc2_urb);
+ } else {
+ if (alloc_bandwidth) {
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_allocate_bus_bandwidth(hcd,
+ dwc2_hcd_get_ep_bandwidth(hsotg, ep),
+ urb);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+ }
+
+ return retval;
+}
+
+/*
+ * Aborts/cancels a USB transfer request. Always returns 0 to indicate success.
+ */
+static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ int rc = 0;
+ unsigned long flags;
+
+ dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n");
+ dwc2_dump_urb_info(hcd, urb, "urb_dequeue");
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ if (!urb->hcpriv) {
+ dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n");
+ goto out;
+ }
+
+ rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv);
+
+ kfree(urb->hcpriv);
+ urb->hcpriv = NULL;
+
+ /* Higher layer software sets URB status */
+ spin_unlock(&hsotg->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hsotg->lock);
+
+ dev_dbg(hsotg->dev, "Called usb_hcd_giveback_urb()\n");
+ dev_dbg(hsotg->dev, " urb->status = %d\n", urb->status);
+out:
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ return rc;
+}
+
+/*
+ * Frees resources in the DWC_otg controller related to a given endpoint. Also
+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
+ * must already be dequeued.
+ */
+static void _dwc2_hcd_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+ dev_dbg(hsotg->dev,
+ "DWC OTG HCD EP DISABLE: bEndpointAddress=0x%02x, ep->hcpriv=%p\n",
+ ep->desc.bEndpointAddress, ep->hcpriv);
+ dwc2_hcd_endpoint_disable(hsotg, ep, 250);
+}
+
+/*
+ * Resets endpoint specific parameter values, in current version used to reset
+ * the data toggle (as a WA). This function can be called from usb_clear_halt
+ * routine.
+ */
+static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int epnum = usb_endpoint_num(&ep->desc);
+ struct usb_device *udev;
+ unsigned long flags;
+
+ dev_dbg(hsotg->dev,
+ "DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n",
+ ep->desc.bEndpointAddress);
+
+ udev = to_usb_device(hsotg->dev);
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ usb_settoggle(udev, epnum, is_out, 0);
+ if (is_control)
+ usb_settoggle(udev, epnum, !is_out, 0);
+ dwc2_hcd_endpoint_reset(hsotg, ep);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
+ * interrupt.
+ *
+ * This function is called by the USB core when an interrupt occurs
+ */
+static irqreturn_t _dwc2_hcd_irq(struct usb_hcd *hcd)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ int retval = dwc2_hcd_intr(hsotg);
+
+ return IRQ_RETVAL(retval);
+}
+
+/*
+ * Creates Status Change bitmap for the root hub and root port. The bitmap is
+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
+ * is the status change indicator for the single root port. Returns 1 if either
+ * change indicator is 1, otherwise returns 0.
+ */
+static int _dwc2_hcd_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+
+ buf[0] = dwc2_hcd_is_status_changed(hsotg, 1) << 1;
+ return buf[0] != 0;
+}
+
+/* Handles hub class-specific requests */
+static int _dwc2_hcd_hub_control(struct usb_hcd *hcd, u16 typereq, u16 wvalue,
+ u16 windex, char *buf, u16 wlength)
+{
+ int retval = dwc2_hcd_hub_control(dwc2_hcd_to_hsotg(hcd), typereq,
+ wvalue, windex, buf, wlength);
+ return retval;
+}
+
+/* Handles hub TT buffer clear completions */
+static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
+ struct dwc2_qh *qh;
+ unsigned long flags;
+
+ qh = ep->hcpriv;
+ if (!qh)
+ return;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ qh->tt_buffer_dirty = 0;
+
+ if (hsotg->flags.b.port_connect_status)
+ dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_ALL);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+static struct hc_driver dwc2_hc_driver = {
+ .description = "dwc2_hsotg",
+ .product_desc = "DWC OTG Controller",
+ .hcd_priv_size = sizeof(struct wrapper_priv_data),
+
+ .irq = _dwc2_hcd_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ .start = _dwc2_hcd_start,
+ .stop = _dwc2_hcd_stop,
+ .urb_enqueue = _dwc2_hcd_urb_enqueue,
+ .urb_dequeue = _dwc2_hcd_urb_dequeue,
+ .endpoint_disable = _dwc2_hcd_endpoint_disable,
+ .endpoint_reset = _dwc2_hcd_endpoint_reset,
+ .get_frame_number = _dwc2_hcd_get_frame_number,
+
+ .hub_status_data = _dwc2_hcd_hub_status_data,
+ .hub_control = _dwc2_hcd_hub_control,
+ .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
+};
+
+/*
+ * Frees secondary storage associated with the dwc2_hsotg structure contained
+ * in the struct usb_hcd field
+ */
+static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
+{
+ u32 ahbcfg;
+ u32 dctl;
+ int i;
+
+ dev_dbg(hsotg->dev, "DWC OTG HCD FREE\n");
+
+ /* Free memory for QH/QTD lists */
+ dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive);
+ dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active);
+ dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive);
+ dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready);
+ dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_assigned);
+ dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_queued);
+
+ /* Free memory for the host channels */
+ for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+ struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i];
+
+ if (chan != NULL) {
+ dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n",
+ i, chan);
+ hsotg->hc_ptr_array[i] = NULL;
+ kfree(chan);
+ }
+ }
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (hsotg->status_buf) {
+ dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE,
+ hsotg->status_buf,
+ hsotg->status_buf_dma);
+ hsotg->status_buf = NULL;
+ }
+ } else {
+ kfree(hsotg->status_buf);
+ hsotg->status_buf = NULL;
+ }
+
+ ahbcfg = readl(hsotg->regs + GAHBCFG);
+
+ /* Disable all interrupts */
+ ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
+ writel(ahbcfg, hsotg->regs + GAHBCFG);
+ writel(0, hsotg->regs + GINTMSK);
+
+ if (hsotg->snpsid >= DWC2_CORE_REV_3_00a) {
+ dctl = readl(hsotg->regs + DCTL);
+ dctl |= DCTL_SFTDISCON;
+ writel(dctl, hsotg->regs + DCTL);
+ }
+
+ if (hsotg->wq_otg) {
+ if (!cancel_work_sync(&hsotg->wf_otg))
+ flush_workqueue(hsotg->wq_otg);
+ destroy_workqueue(hsotg->wq_otg);
+ }
+
+ kfree(hsotg->core_params);
+ hsotg->core_params = NULL;
+ del_timer(&hsotg->wkp_timer);
+}
+
+static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
+{
+ /* Turn off all host-specific interrupts */
+ dwc2_disable_host_interrupts(hsotg);
+
+ dwc2_hcd_free(hsotg);
+}
+
+/*
+ * Sets all parameters to the given value.
+ *
+ * Assumes that the dwc2_core_params struct contains only integers.
+ */
+void dwc2_set_all_params(struct dwc2_core_params *params, int value)
+{
+ int *p = (int *)params;
+ size_t size = sizeof(*params) / sizeof(*p);
+ int i;
+
+ for (i = 0; i < size; i++)
+ p[i] = -1;
+}
+EXPORT_SYMBOL_GPL(dwc2_set_all_params);
+
+/*
+ * Initializes the HCD. This function allocates memory for and initializes the
+ * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
+ * USB bus with the core and calls the hc_driver->start() function. It returns
+ * a negative error on failure.
+ */
+int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
+ struct dwc2_core_params *params)
+{
+ struct usb_hcd *hcd;
+ struct dwc2_host_chan *channel;
+ u32 snpsid, gusbcfg, hcfg;
+ int i, num_channels;
+ int retval = -ENOMEM;
+
+ dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
+
+ /*
+ * Attempt to ensure this device is really a DWC_otg Controller.
+ * Read and verify the GSNPSID register contents. The value should be
+ * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3",
+ * as in "OTG version 2.xx" or "OTG version 3.xx".
+ */
+ snpsid = readl(hsotg->regs + GSNPSID);
+ if ((snpsid & 0xfffff000) != 0x4f542000 &&
+ (snpsid & 0xfffff000) != 0x4f543000) {
+ dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", snpsid);
+ retval = -ENODEV;
+ goto error1;
+ }
+
+ /*
+ * Store the contents of the hardware configuration registers here for
+ * easy access later
+ */
+ hsotg->hwcfg1 = readl(hsotg->regs + GHWCFG1);
+ hsotg->hwcfg2 = readl(hsotg->regs + GHWCFG2);
+ hsotg->hwcfg3 = readl(hsotg->regs + GHWCFG3);
+ hsotg->hwcfg4 = readl(hsotg->regs + GHWCFG4);
+
+ dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hsotg->hwcfg1);
+ dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hsotg->hwcfg2);
+ dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hsotg->hwcfg3);
+ dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hsotg->hwcfg4);
+
+ /* Force host mode to get HPTXFSIZ exact power on value */
+ gusbcfg = readl(hsotg->regs + GUSBCFG);
+ gusbcfg |= GUSBCFG_FORCEHOSTMODE;
+ writel(gusbcfg, hsotg->regs + GUSBCFG);
+ usleep_range(100000, 150000);
+
+ hsotg->hptxfsiz = readl(hsotg->regs + HPTXFSIZ);
+ dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hsotg->hptxfsiz);
+ gusbcfg = readl(hsotg->regs + GUSBCFG);
+ gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
+ writel(gusbcfg, hsotg->regs + GUSBCFG);
+ usleep_range(100000, 150000);
+
+ hcfg = readl(hsotg->regs + HCFG);
+ dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
+ dev_dbg(hsotg->dev, "op_mode=%0x\n",
+ hsotg->hwcfg2 >> GHWCFG2_OP_MODE_SHIFT &
+ GHWCFG2_OP_MODE_MASK >> GHWCFG2_OP_MODE_SHIFT);
+ dev_dbg(hsotg->dev, "arch=%0x\n",
+ hsotg->hwcfg2 >> GHWCFG2_ARCHITECTURE_SHIFT &
+ GHWCFG2_ARCHITECTURE_MASK >> GHWCFG2_ARCHITECTURE_SHIFT);
+ dev_dbg(hsotg->dev, "num_dev_ep=%d\n",
+ hsotg->hwcfg2 >> GHWCFG2_NUM_DEV_EP_SHIFT &
+ GHWCFG2_NUM_DEV_EP_MASK >> GHWCFG2_NUM_DEV_EP_SHIFT);
+ dev_dbg(hsotg->dev, "max_host_chan=%d\n",
+ hsotg->hwcfg2 >> GHWCFG2_NUM_HOST_CHAN_SHIFT &
+ GHWCFG2_NUM_HOST_CHAN_MASK >> GHWCFG2_NUM_HOST_CHAN_SHIFT);
+ dev_dbg(hsotg->dev, "nonperio_tx_q_depth=0x%0x\n",
+ hsotg->hwcfg2 >> GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT &
+ GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK >>
+ GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT);
+ dev_dbg(hsotg->dev, "host_perio_tx_q_depth=0x%0x\n",
+ hsotg->hwcfg2 >> GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT &
+ GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK >>
+ GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT);
+ dev_dbg(hsotg->dev, "dev_token_q_depth=0x%0x\n",
+ hsotg->hwcfg2 >> GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT &
+ GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK >>
+ GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+ hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) *
+ FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
+ if (!hsotg->frame_num_array)
+ goto error1;
+ hsotg->last_frame_num_array = kzalloc(
+ sizeof(*hsotg->last_frame_num_array) *
+ FRAME_NUM_ARRAY_SIZE, GFP_KERNEL);
+ if (!hsotg->last_frame_num_array)
+ goto error1;
+ hsotg->last_frame_num = HFNUM_MAX_FRNUM;
+#endif
+
+ hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
+ if (!hsotg->core_params)
+ goto error1;
+
+ dwc2_set_all_params(hsotg->core_params, -1);
+
+ /* Validate parameter values */
+ dwc2_set_parameters(hsotg, params);
+
+ /* Set device flags indicating whether the HCD supports DMA */
+ if (hsotg->core_params->dma_enable > 0) {
+ if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
+ dev_warn(hsotg->dev,
+ "can't enable workaround for >2GB RAM\n");
+ if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
+ dev_warn(hsotg->dev,
+ "can't enable workaround for >2GB RAM\n");
+ } else {
+ dma_set_mask(hsotg->dev, 0);
+ dma_set_coherent_mask(hsotg->dev, 0);
+ }
+
+ hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));
+ if (!hcd)
+ goto error1;
+
+ hcd->has_tt = 1;
+
+ spin_lock_init(&hsotg->lock);
+ ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg;
+ hsotg->priv = hcd;
+
+ /*
+ * Disable the global interrupt until all the interrupt handlers are
+ * installed
+ */
+ dwc2_disable_global_interrupts(hsotg);
+
+ /* Initialize the DWC_otg core, and select the Phy type */
+ retval = dwc2_core_init(hsotg, true, irq);
+ if (retval)
+ goto error2;
+
+ /* Create new workqueue and init work */
+ retval = -ENOMEM;
+ hsotg->wq_otg = create_singlethread_workqueue("dwc2");
+ if (!hsotg->wq_otg) {
+ dev_err(hsotg->dev, "Failed to create workqueue\n");
+ goto error2;
+ }
+ INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change);
+
+ hsotg->snpsid = readl(hsotg->regs + GSNPSID);
+ dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x\n",
+ hsotg->snpsid >> 12 & 0xf, hsotg->snpsid >> 8 & 0xf,
+ hsotg->snpsid >> 4 & 0xf, hsotg->snpsid & 0xf);
+
+ setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected,
+ (unsigned long)hsotg);
+
+ /* Initialize the non-periodic schedule */
+ INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive);
+ INIT_LIST_HEAD(&hsotg->non_periodic_sched_active);
+
+ /* Initialize the periodic schedule */
+ INIT_LIST_HEAD(&hsotg->periodic_sched_inactive);
+ INIT_LIST_HEAD(&hsotg->periodic_sched_ready);
+ INIT_LIST_HEAD(&hsotg->periodic_sched_assigned);
+ INIT_LIST_HEAD(&hsotg->periodic_sched_queued);
+
+ /*
+ * Create a host channel descriptor for each host channel implemented
+ * in the controller. Initialize the channel descriptor array.
+ */
+ INIT_LIST_HEAD(&hsotg->free_hc_list);
+ num_channels = hsotg->core_params->host_channels;
+ memset(&hsotg->hc_ptr_array[0], 0, sizeof(hsotg->hc_ptr_array));
+
+ for (i = 0; i < num_channels; i++) {
+ channel = kzalloc(sizeof(*channel), GFP_KERNEL);
+ if (channel == NULL)
+ goto error3;
+ channel->hc_num = i;
+ hsotg->hc_ptr_array[i] = channel;
+ }
+
+ /* Initialize hsotg start work */
+ INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func);
+
+ /* Initialize port reset work */
+ INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func);
+
+ /*
+ * Allocate space for storing data on status transactions. Normally no
+ * data is sent, but this space acts as a bit bucket. This must be
+ * done after usb_add_hcd since that function allocates the DMA buffer
+ * pool.
+ */
+ if (hsotg->core_params->dma_enable > 0)
+ hsotg->status_buf = dma_alloc_coherent(hsotg->dev,
+ DWC2_HCD_STATUS_BUF_SIZE,
+ &hsotg->status_buf_dma, GFP_KERNEL);
+ else
+ hsotg->status_buf = kzalloc(DWC2_HCD_STATUS_BUF_SIZE,
+ GFP_KERNEL);
+
+ if (!hsotg->status_buf)
+ goto error3;
+
+ hsotg->otg_port = 1;
+ hsotg->frame_list = NULL;
+ hsotg->frame_list_dma = 0;
+ hsotg->periodic_qh_count = 0;
+
+ /* Initiate lx_state to L3 disconnected state */
+ hsotg->lx_state = DWC2_L3;
+
+ hcd->self.otg_port = hsotg->otg_port;
+
+ /* Don't support SG list at this point */
+ hcd->self.sg_tablesize = 0;
+
+ /*
+ * Finish generic HCD initialization and start the HCD. This function
+ * allocates the DMA buffer pool, registers the USB bus, requests the
+ * IRQ line, and calls hcd_start method.
+ */
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
+ if (retval < 0)
+ goto error3;
+
+ dwc2_dump_global_registers(hsotg);
+ dwc2_dump_host_registers(hsotg);
+ dwc2_hcd_dump_state(hsotg);
+
+ dwc2_enable_global_interrupts(hsotg);
+
+ return 0;
+
+error3:
+ dwc2_hcd_release(hsotg);
+error2:
+ usb_put_hcd(hcd);
+error1:
+ kfree(hsotg->core_params);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+ kfree(hsotg->last_frame_num_array);
+ kfree(hsotg->frame_num_array);
+#endif
+
+ dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(dwc2_hcd_init);
+
+/*
+ * Removes the HCD.
+ * Frees memory and resources associated with the HCD and deregisters the bus.
+ */
+void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
+{
+ struct usb_hcd *hcd;
+
+ dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n");
+
+ hcd = dwc2_hsotg_to_hcd(hsotg);
+ dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd);
+
+ if (!hcd) {
+ dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n",
+ __func__);
+ return;
+ }
+
+ usb_remove_hcd(hcd);
+ hsotg->priv = NULL;
+ dwc2_hcd_release(hsotg);
+ usb_put_hcd(hcd);
+
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+ kfree(hsotg->last_frame_num_array);
+ kfree(hsotg->frame_num_array);
+#endif
+}
+EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
diff --git a/drivers/staging/dwc2/hcd.h b/drivers/staging/dwc2/hcd.h
new file mode 100644
index 000000000000..d071f1a05df1
--- /dev/null
+++ b/drivers/staging/dwc2/hcd.h
@@ -0,0 +1,765 @@
+/*
+ * hcd.h - DesignWare HS OTG Controller host-mode declarations
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __DWC2_HCD_H__
+#define __DWC2_HCD_H__
+
+/*
+ * This file contains the structures, constants, and interfaces for the
+ * Host Contoller Driver (HCD)
+ *
+ * The Host Controller Driver (HCD) is responsible for translating requests
+ * from the USB Driver into the appropriate actions on the DWC_otg controller.
+ * It isolates the USBD from the specifics of the controller by providing an
+ * API to the USBD.
+ */
+
+struct dwc2_qh;
+
+/**
+ * struct dwc2_host_chan - Software host channel descriptor
+ *
+ * @hc_num: Host channel number, used for register address lookup
+ * @dev_addr: Address of the device
+ * @ep_num: Endpoint of the device
+ * @ep_is_in: Endpoint direction
+ * @speed: Device speed. One of the following values:
+ * - USB_SPEED_LOW
+ * - USB_SPEED_FULL
+ * - USB_SPEED_HIGH
+ * @ep_type: Endpoint type. One of the following values:
+ * - USB_ENDPOINT_XFER_CONTROL: 0
+ * - USB_ENDPOINT_XFER_ISOC: 1
+ * - USB_ENDPOINT_XFER_BULK: 2
+ * - USB_ENDPOINT_XFER_INTR: 3
+ * @max_packet: Max packet size in bytes
+ * @data_pid_start: PID for initial transaction.
+ * 0: DATA0
+ * 1: DATA2
+ * 2: DATA1
+ * 3: MDATA (non-Control EP),
+ * SETUP (Control EP)
+ * @multi_count: Number of additional periodic transactions per
+ * (micro)frame
+ * @xfer_buf: Pointer to current transfer buffer position
+ * @xfer_dma: DMA address of xfer_buf
+ * @align_buf: In Buffer DMA mode this will be used if xfer_buf is not
+ * DWORD aligned
+ * @xfer_len: Total number of bytes to transfer
+ * @xfer_count: Number of bytes transferred so far
+ * @start_pkt_count: Packet count at start of transfer
+ * @xfer_started: True if the transfer has been started
+ * @ping: True if a PING request should be issued on this channel
+ * @error_state: True if the error count for this transaction is non-zero
+ * @halt_on_queue: True if this channel should be halted the next time a
+ * request is queued for the channel. This is necessary in
+ * slave mode if no request queue space is available when
+ * an attempt is made to halt the channel.
+ * @halt_pending: True if the host channel has been halted, but the core
+ * is not finished flushing queued requests
+ * @do_split: Enable split for the channel
+ * @complete_split: Enable complete split
+ * @hub_addr: Address of high speed hub for the split
+ * @hub_port: Port of the low/full speed device for the split
+ * @xact_pos: Split transaction position. One of the following values:
+ * - DWC2_HCSPLT_XACTPOS_MID
+ * - DWC2_HCSPLT_XACTPOS_BEGIN
+ * - DWC2_HCSPLT_XACTPOS_END
+ * - DWC2_HCSPLT_XACTPOS_ALL
+ * @requests: Number of requests issued for this channel since it was
+ * assigned to the current transfer (not counting PINGs)
+ * @schinfo: Scheduling micro-frame bitmap
+ * @ntd: Number of transfer descriptors for the transfer
+ * @halt_status: Reason for halting the host channel
+ * @hcint Contents of the HCINT register when the interrupt came
+ * @qh: QH for the transfer being processed by this channel
+ * @hc_list_entry: For linking to list of host channels
+ * @desc_list_addr: Current QH's descriptor list DMA address
+ *
+ * This structure represents the state of a single host channel when acting in
+ * host mode. It contains the data items needed to transfer packets to an
+ * endpoint via a host channel.
+ */
+struct dwc2_host_chan {
+ u8 hc_num;
+
+ unsigned dev_addr:7;
+ unsigned ep_num:4;
+ unsigned ep_is_in:1;
+ unsigned speed:4;
+ unsigned ep_type:2;
+ unsigned max_packet:11;
+ unsigned data_pid_start:2;
+#define DWC2_HC_PID_DATA0 (TSIZ_SC_MC_PID_DATA0 >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_DATA2 (TSIZ_SC_MC_PID_DATA2 >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_DATA1 (TSIZ_SC_MC_PID_DATA1 >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_MDATA (TSIZ_SC_MC_PID_MDATA >> TSIZ_SC_MC_PID_SHIFT)
+#define DWC2_HC_PID_SETUP (TSIZ_SC_MC_PID_SETUP >> TSIZ_SC_MC_PID_SHIFT)
+
+ unsigned multi_count:2;
+
+ u8 *xfer_buf;
+ dma_addr_t xfer_dma;
+ dma_addr_t align_buf;
+ u32 xfer_len;
+ u32 xfer_count;
+ u16 start_pkt_count;
+ u8 xfer_started;
+ u8 do_ping;
+ u8 error_state;
+ u8 halt_on_queue;
+ u8 halt_pending;
+ u8 do_split;
+ u8 complete_split;
+ u8 hub_addr;
+ u8 hub_port;
+ u8 xact_pos;
+#define DWC2_HCSPLT_XACTPOS_MID (HCSPLT_XACTPOS_MID >> HCSPLT_XACTPOS_SHIFT)
+#define DWC2_HCSPLT_XACTPOS_END (HCSPLT_XACTPOS_END >> HCSPLT_XACTPOS_SHIFT)
+#define DWC2_HCSPLT_XACTPOS_BEGIN (HCSPLT_XACTPOS_BEGIN >> HCSPLT_XACTPOS_SHIFT)
+#define DWC2_HCSPLT_XACTPOS_ALL (HCSPLT_XACTPOS_ALL >> HCSPLT_XACTPOS_SHIFT)
+
+ u8 requests;
+ u8 schinfo;
+ u16 ntd;
+ enum dwc2_halt_status halt_status;
+ u32 hcint;
+ struct dwc2_qh *qh;
+ struct list_head hc_list_entry;
+ dma_addr_t desc_list_addr;
+};
+
+struct dwc2_hcd_pipe_info {
+ u8 dev_addr;
+ u8 ep_num;
+ u8 pipe_type;
+ u8 pipe_dir;
+ u16 mps;
+};
+
+struct dwc2_hcd_iso_packet_desc {
+ u32 offset;
+ u32 length;
+ u32 actual_length;
+ u32 status;
+};
+
+struct dwc2_qtd;
+
+struct dwc2_hcd_urb {
+ void *priv;
+ struct dwc2_qtd *qtd;
+ void *buf;
+ dma_addr_t dma;
+ void *setup_packet;
+ dma_addr_t setup_dma;
+ u32 length;
+ u32 actual_length;
+ u32 status;
+ u32 error_count;
+ u32 packet_count;
+ u32 flags;
+ u16 interval;
+ struct dwc2_hcd_pipe_info pipe_info;
+ struct dwc2_hcd_iso_packet_desc iso_descs[0];
+};
+
+/* Phases for control transfers */
+enum dwc2_control_phase {
+ DWC2_CONTROL_SETUP,
+ DWC2_CONTROL_DATA,
+ DWC2_CONTROL_STATUS,
+};
+
+/* Transaction types */
+enum dwc2_transaction_type {
+ DWC2_TRANSACTION_NONE,
+ DWC2_TRANSACTION_PERIODIC,
+ DWC2_TRANSACTION_NON_PERIODIC,
+ DWC2_TRANSACTION_ALL,
+};
+
+/**
+ * struct dwc2_qh - Software queue head structure
+ *
+ * @ep_type: Endpoint type. One of the following values:
+ * - USB_ENDPOINT_XFER_CONTROL
+ * - USB_ENDPOINT_XFER_BULK
+ * - USB_ENDPOINT_XFER_INT
+ * - USB_ENDPOINT_XFER_ISOC
+ * @ep_is_in: Endpoint direction
+ * @maxp: Value from wMaxPacketSize field of Endpoint Descriptor
+ * @dev_speed: Device speed. One of the following values:
+ * - USB_SPEED_LOW
+ * - USB_SPEED_FULL
+ * - USB_SPEED_HIGH
+ * @data_toggle: Determines the PID of the next data packet for
+ * non-controltransfers. Ignored for control transfers.
+ * One of the following values:
+ * - DWC2_HC_PID_DATA0
+ * - DWC2_HC_PID_DATA1
+ * @ping_state: Ping state
+ * @do_split: Full/low speed endpoint on high-speed hub requires split
+ * @qtd_list: List of QTDs for this QH
+ * @channel: Host channel currently processing transfers for this QH
+ * @usecs: Bandwidth in microseconds per (micro)frame
+ * @interval: Interval between transfers in (micro)frames
+ * @sched_frame: (micro)frame to initialize a periodic transfer.
+ * The transfer executes in the following (micro)frame.
+ * @start_split_frame: (Micro)frame at which last start split was initialized
+ * @dw_align_buf: Used instead of original buffer if its physical address
+ * is not dword-aligned
+ * @dw_align_buf_dma: DMA address for align_buf
+ * @qh_list_entry: Entry for QH in either the periodic or non-periodic
+ * schedule
+ * @desc_list: List of transfer descriptors
+ * @desc_list_dma: Physical address of desc_list
+ * @n_bytes: Xfer Bytes array. Each element corresponds to a transfer
+ * descriptor and indicates original XferSize value for the
+ * descriptor
+ * @ntd: Actual number of transfer descriptors in a list
+ * @td_first: Index of first activated isochronous transfer descriptor
+ * @td_last: Index of last activated isochronous transfer descriptor
+ * @tt_buffer_dirty True if clear_tt_buffer_complete is pending
+ *
+ * A Queue Head (QH) holds the static characteristics of an endpoint and
+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
+ * be entered in either the non-periodic or periodic schedule.
+ */
+struct dwc2_qh {
+ u8 ep_type;
+ u8 ep_is_in;
+ u16 maxp;
+ u8 dev_speed;
+ u8 data_toggle;
+ u8 ping_state;
+ u8 do_split;
+ struct list_head qtd_list;
+ struct dwc2_host_chan *channel;
+ u16 usecs;
+ u16 interval;
+ u16 sched_frame;
+ u16 start_split_frame;
+ u8 *dw_align_buf;
+ dma_addr_t dw_align_buf_dma;
+ struct list_head qh_list_entry;
+ struct dwc2_hcd_dma_desc *desc_list;
+ dma_addr_t desc_list_dma;
+ u32 *n_bytes;
+ u16 ntd;
+ u8 td_first;
+ u8 td_last;
+ unsigned tt_buffer_dirty:1;
+};
+
+/**
+ * struct dwc2_qtd - Software queue transfer descriptor (QTD)
+ *
+ * @control_phase: Current phase for control transfers (Setup, Data, or
+ * Status)
+ * @in_process: Indicates if this QTD is currently processed by HW
+ * @data_toggle: Determines the PID of the next data packet for the
+ * data phase of control transfers. Ignored for other
+ * transfer types. One of the following values:
+ * - DWC2_HC_PID_DATA0
+ * - DWC2_HC_PID_DATA1
+ * @complete_split: Keeps track of the current split type for FS/LS
+ * endpoints on a HS Hub
+ * @isoc_split_pos: Position of the ISOC split in full/low speed
+ * @isoc_frame_index: Index of the next frame descriptor for an isochronous
+ * transfer. A frame descriptor describes the buffer
+ * position and length of the data to be transferred in the
+ * next scheduled (micro)frame of an isochronous transfer.
+ * It also holds status for that transaction. The frame
+ * index starts at 0.
+ * @isoc_split_offset: Position of the ISOC split in the buffer for the
+ * current frame
+ * @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT
+ * @error_count: Holds the number of bus errors that have occurred for
+ * a transaction within this transfer
+ * @n_desc: Number of DMA descriptors for this QTD
+ * @isoc_frame_index_last: Last activated frame (packet) index, used in
+ * descriptor DMA mode only
+ * @urb: URB for this transfer
+ * @qh: Queue head for this QTD
+ * @qtd_list_entry: For linking to the QH's list of QTDs
+ *
+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
+ * interrupt, or isochronous transfer. A single QTD is created for each URB
+ * (of one of these types) submitted to the HCD. The transfer associated with
+ * a QTD may require one or multiple transactions.
+ *
+ * A QTD is linked to a Queue Head, which is entered in either the
+ * non-periodic or periodic schedule for execution. When a QTD is chosen for
+ * execution, some or all of its transactions may be executed. After
+ * execution, the state of the QTD is updated. The QTD may be retired if all
+ * its transactions are complete or if an error occurred. Otherwise, it
+ * remains in the schedule so more transactions can be executed later.
+ */
+struct dwc2_qtd {
+ enum dwc2_control_phase control_phase;
+ u8 in_process;
+ u8 data_toggle;
+ u8 complete_split;
+ u8 isoc_split_pos;
+ u16 isoc_frame_index;
+ u16 isoc_split_offset;
+ u32 ssplit_out_xfer_count;
+ u8 error_count;
+ u8 n_desc;
+ u16 isoc_frame_index_last;
+ struct dwc2_hcd_urb *urb;
+ struct dwc2_qh *qh;
+ struct list_head qtd_list_entry;
+};
+
+#ifdef DEBUG
+struct hc_xfer_info {
+ struct dwc2_hsotg *hsotg;
+ struct dwc2_host_chan *chan;
+};
+#endif
+
+/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */
+static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
+{
+ return (struct usb_hcd *)hsotg->priv;
+}
+
+/*
+ * Inline used to disable one channel interrupt. Channel interrupts are
+ * disabled when the channel is halted or released by the interrupt handler.
+ * There is no need to handle further interrupts of that type until the
+ * channel is re-assigned. In fact, subsequent handling may cause crashes
+ * because the channel structures are cleaned up when the channel is released.
+ */
+static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
+{
+ u32 mask = readl(hsotg->regs + HCINTMSK(chnum));
+
+ mask &= ~intr;
+ writel(mask, hsotg->regs + HCINTMSK(chnum));
+}
+
+/*
+ * Returns the mode of operation, host or device
+ */
+static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
+{
+ return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+}
+static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
+{
+ return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+}
+
+/*
+ * Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they
+ * are read as 1, they won't clear when written back.
+ */
+static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
+{
+ u32 hprt0 = readl(hsotg->regs + HPRT0);
+
+ hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
+ return hprt0;
+}
+
+static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->ep_num;
+}
+
+static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_type;
+}
+
+static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->mps;
+}
+
+static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->dev_addr;
+}
+
+static inline u8 dwc2_hcd_is_pipe_isoc(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_type == USB_ENDPOINT_XFER_ISOC;
+}
+
+static inline u8 dwc2_hcd_is_pipe_int(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_type == USB_ENDPOINT_XFER_INT;
+}
+
+static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_type == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe)
+{
+ return pipe->pipe_dir == USB_DIR_IN;
+}
+
+static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
+{
+ return !dwc2_hcd_is_pipe_in(pipe);
+}
+
+extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
+ struct dwc2_core_params *params);
+extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
+extern int dwc2_set_parameters(struct dwc2_hsotg *hsotg,
+ struct dwc2_core_params *params);
+extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
+
+/* Transaction Execution Functions */
+extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
+ struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
+ enum dwc2_transaction_type tr_type);
+
+/* Schedule Queue Functions */
+/* Implemented in hcd_queue.c */
+extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ int sched_csplit);
+
+extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb);
+extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+ struct dwc2_qh **qh, gfp_t mem_flags);
+
+/* Unlinks and frees a QTD */
+static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg,
+ struct dwc2_qtd *qtd,
+ struct dwc2_qh *qh)
+{
+ list_del(&qtd->qtd_list_entry);
+ kfree(qtd);
+}
+
+/* Descriptor DMA support functions */
+extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh);
+extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ enum dwc2_halt_status halt_status);
+
+extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ gfp_t mem_flags);
+extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh);
+
+/* Check if QH is non-periodic */
+#define dwc2_qh_is_non_per(_qh_ptr_) \
+ ((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \
+ (_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL)
+
+#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC
+static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; }
+static inline bool dbg_qh(struct dwc2_qh *qh) { return true; }
+static inline bool dbg_urb(struct urb *urb) { return true; }
+static inline bool dbg_perio(void) { return true; }
+#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */
+static inline bool dbg_hc(struct dwc2_host_chan *hc)
+{
+ return hc->ep_type == USB_ENDPOINT_XFER_BULK ||
+ hc->ep_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline bool dbg_qh(struct dwc2_qh *qh)
+{
+ return qh->ep_type == USB_ENDPOINT_XFER_BULK ||
+ qh->ep_type == USB_ENDPOINT_XFER_CONTROL;
+}
+
+static inline bool dbg_urb(struct urb *urb)
+{
+ return usb_pipetype(urb->pipe) == PIPE_BULK ||
+ usb_pipetype(urb->pipe) == PIPE_CONTROL;
+}
+
+static inline bool dbg_perio(void) { return false; }
+#endif
+
+/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */
+#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03))
+
+/* Packet size for any kind of endpoint descriptor */
+#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff)
+
+/*
+ * Returns true if frame1 is less than or equal to frame2. The comparison is
+ * done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the
+ * frame number when the max frame number is reached.
+ */
+static inline int dwc2_frame_num_le(u16 frame1, u16 frame2)
+{
+ return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1);
+}
+
+/*
+ * Returns true if frame1 is greater than frame2. The comparison is done
+ * modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
+ * number when the max frame number is reached.
+ */
+static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2)
+{
+ return (frame1 != frame2) &&
+ ((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1);
+}
+
+/*
+ * Increments frame by the amount specified by inc. The addition is done
+ * modulo HFNUM_MAX_FRNUM. Returns the incremented value.
+ */
+static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc)
+{
+ return (frame + inc) & HFNUM_MAX_FRNUM;
+}
+
+static inline u16 dwc2_full_frame_num(u16 frame)
+{
+ return (frame & HFNUM_MAX_FRNUM) >> 3;
+}
+
+static inline u16 dwc2_micro_frame_num(u16 frame)
+{
+ return frame & 0x7;
+}
+
+/*
+ * Returns the Core Interrupt Status register contents, ANDed with the Core
+ * Interrupt Mask register contents
+ */
+static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
+{
+ return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK);
+}
+
+static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
+{
+ return dwc2_urb->status;
+}
+
+static inline u32 dwc2_hcd_urb_get_actual_length(
+ struct dwc2_hcd_urb *dwc2_urb)
+{
+ return dwc2_urb->actual_length;
+}
+
+static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb)
+{
+ return dwc2_urb->error_count;
+}
+
+static inline void dwc2_hcd_urb_set_iso_desc_params(
+ struct dwc2_hcd_urb *dwc2_urb, int desc_num, u32 offset,
+ u32 length)
+{
+ dwc2_urb->iso_descs[desc_num].offset = offset;
+ dwc2_urb->iso_descs[desc_num].length = length;
+}
+
+static inline u32 dwc2_hcd_urb_get_iso_desc_status(
+ struct dwc2_hcd_urb *dwc2_urb, int desc_num)
+{
+ return dwc2_urb->iso_descs[desc_num].status;
+}
+
+static inline u32 dwc2_hcd_urb_get_iso_desc_actual_length(
+ struct dwc2_hcd_urb *dwc2_urb, int desc_num)
+{
+ return dwc2_urb->iso_descs[desc_num].actual_length;
+}
+
+static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_qh *qh = ep->hcpriv;
+
+ if (qh && !list_empty(&qh->qh_list_entry))
+ return 1;
+
+ return 0;
+}
+
+static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg,
+ struct usb_host_endpoint *ep)
+{
+ struct dwc2_qh *qh = ep->hcpriv;
+
+ if (!qh) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ return qh->usecs;
+}
+
+extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd);
+
+/* HCD Core API */
+
+/**
+ * dwc2_hcd_intr() - Called on every hardware interrupt
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * Returns non zero if interrupt is handled
+ * Return 0 if interrupt is not handled
+ */
+extern int dwc2_hcd_intr(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_stop() - Halts the DWC_otg host mode operation
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
+
+extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
+extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
+ * and 0 otherwise
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_get_frame_number() - Returns current frame number
+ *
+ * @hsotg: The DWC2 HCD
+ */
+extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_dump_state() - Dumps hsotg state
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg);
+
+/**
+ * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF
+ *
+ * @hsotg: The DWC2 HCD
+ *
+ * This can be used to determine average interrupt latency. Frame remaining is
+ * also shown for start transfer and two additional sample points.
+ *
+ * NOTE: This function will be removed once the peripheral controller code
+ * is integrated and the driver is stable
+ */
+extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg);
+
+/* URB interface */
+
+/* Transfer flags */
+#define URB_GIVEBACK_ASAP 0x1
+#define URB_SEND_ZERO_PACKET 0x2
+
+/* Host driver callbacks */
+
+extern void dwc2_host_start(struct dwc2_hsotg *hsotg);
+extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg);
+extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context,
+ int *hub_addr, int *hub_port);
+extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context);
+extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, void *context,
+ struct dwc2_hcd_urb *dwc2_urb, int status);
+
+#ifdef DEBUG
+/*
+ * Macro to sample the remaining PHY clocks left in the current frame. This
+ * may be used during debugging to determine the average time it takes to
+ * execute sections of code. There are two possible sample points, "a" and
+ * "b", so the _letter_ argument must be one of these values.
+ *
+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
+ * example, "cat /sys/devices/lm0/hcd_frrem".
+ */
+#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) \
+do { \
+ struct hfnum_data _hfnum_; \
+ struct dwc2_qtd *_qtd_; \
+ \
+ _qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd, \
+ qtd_list_entry); \
+ if (usb_pipeint(_qtd_->urb->pipe) && \
+ (_qh_)->start_split_frame != 0 && !_qtd_->complete_split) { \
+ _hfnum_.d32 = readl((_hcd_)->regs + HFNUM); \
+ switch (_hfnum_.b.frnum & 0x7) { \
+ case 7: \
+ (_hcd_)->hfnum_7_samples_##_letter_++; \
+ (_hcd_)->hfnum_7_frrem_accum_##_letter_ += \
+ _hfnum_.b.frrem; \
+ break; \
+ case 0: \
+ (_hcd_)->hfnum_0_samples_##_letter_++; \
+ (_hcd_)->hfnum_0_frrem_accum_##_letter_ += \
+ _hfnum_.b.frrem; \
+ break; \
+ default: \
+ (_hcd_)->hfnum_other_samples_##_letter_++; \
+ (_hcd_)->hfnum_other_frrem_accum_##_letter_ += \
+ _hfnum_.b.frrem; \
+ break; \
+ } \
+ } \
+} while (0)
+#else
+#define dwc2_sample_frrem(_hcd_, _qh_, _letter_) do {} while (0)
+#endif
+
+#endif /* __DWC2_HCD_H__ */
diff --git a/drivers/staging/dwc2/hcd_ddma.c b/drivers/staging/dwc2/hcd_ddma.c
new file mode 100644
index 000000000000..5c0fd273a7bf
--- /dev/null
+++ b/drivers/staging/dwc2/hcd_ddma.c
@@ -0,0 +1,1196 @@
+/*
+ * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains the Descriptor DMA implementation for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static u16 dwc2_frame_list_idx(u16 frame)
+{
+ return frame & (FRLISTEN_64_SIZE - 1);
+}
+
+static u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed)
+{
+ return (idx + inc) &
+ ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
+ MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed)
+{
+ return (idx - inc) &
+ ((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC :
+ MAX_DMA_DESC_NUM_GENERIC) - 1);
+}
+
+static u16 dwc2_max_desc_num(struct dwc2_qh *qh)
+{
+ return (qh->ep_type == USB_ENDPOINT_XFER_ISOC &&
+ qh->dev_speed == USB_SPEED_HIGH) ?
+ MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC;
+}
+
+static u16 dwc2_frame_incr_val(struct dwc2_qh *qh)
+{
+ return qh->dev_speed == USB_SPEED_HIGH ?
+ (qh->interval + 8 - 1) / 8 : qh->interval;
+}
+
+static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ gfp_t flags)
+{
+ qh->desc_list = dma_alloc_coherent(hsotg->dev,
+ sizeof(struct dwc2_hcd_dma_desc) *
+ dwc2_max_desc_num(qh), &qh->desc_list_dma,
+ flags);
+
+ if (!qh->desc_list)
+ return -ENOMEM;
+
+ memset(qh->desc_list, 0,
+ sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh));
+
+ qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags);
+ if (!qh->n_bytes) {
+ dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
+ * dwc2_max_desc_num(qh), qh->desc_list,
+ qh->desc_list_dma);
+ qh->desc_list = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ if (qh->desc_list) {
+ dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc)
+ * dwc2_max_desc_num(qh), qh->desc_list,
+ qh->desc_list_dma);
+ qh->desc_list = NULL;
+ }
+
+ kfree(qh->n_bytes);
+ qh->n_bytes = NULL;
+}
+
+static int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags)
+{
+ if (hsotg->frame_list)
+ return 0;
+
+ hsotg->frame_list = dma_alloc_coherent(hsotg->dev,
+ 4 * FRLISTEN_64_SIZE,
+ &hsotg->frame_list_dma,
+ mem_flags);
+ if (!hsotg->frame_list)
+ return -ENOMEM;
+
+ memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE);
+ return 0;
+}
+
+static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg)
+{
+ u32 *frame_list;
+ dma_addr_t frame_list_dma;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ if (!hsotg->frame_list) {
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return;
+ }
+
+ frame_list = hsotg->frame_list;
+ frame_list_dma = hsotg->frame_list_dma;
+ hsotg->frame_list = NULL;
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ dma_free_coherent(hsotg->dev, 4 * FRLISTEN_64_SIZE, frame_list,
+ frame_list_dma);
+}
+
+static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
+{
+ u32 hcfg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ hcfg = readl(hsotg->regs + HCFG);
+ if (hcfg & HCFG_PERSCHEDENA) {
+ /* already enabled */
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return;
+ }
+
+ writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
+
+ hcfg &= ~HCFG_FRLISTEN_MASK;
+ hcfg |= fr_list_en | HCFG_PERSCHEDENA;
+ dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
+ writel(hcfg, hsotg->regs + HCFG);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
+{
+ u32 hcfg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ hcfg = readl(hsotg->regs + HCFG);
+ if (!(hcfg & HCFG_PERSCHEDENA)) {
+ /* already disabled */
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return;
+ }
+
+ hcfg &= ~HCFG_PERSCHEDENA;
+ dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
+ writel(hcfg, hsotg->regs + HCFG);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+}
+
+/*
+ * Activates/Deactivates FrameList entries for the channel based on endpoint
+ * servicing period
+ */
+static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ int enable)
+{
+ struct dwc2_host_chan *chan;
+ u16 i, j, inc;
+
+ if (!hsotg) {
+ pr_err("hsotg = %p\n", hsotg);
+ return;
+ }
+
+ if (!qh->channel) {
+ dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel);
+ return;
+ }
+
+ if (!hsotg->frame_list) {
+ dev_err(hsotg->dev, "hsotg->frame_list = %p\n",
+ hsotg->frame_list);
+ return;
+ }
+
+ chan = qh->channel;
+ inc = dwc2_frame_incr_val(qh);
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
+ i = dwc2_frame_list_idx(qh->sched_frame);
+ else
+ i = 0;
+
+ j = i;
+ do {
+ if (enable)
+ hsotg->frame_list[j] |= 1 << chan->hc_num;
+ else
+ hsotg->frame_list[j] &= ~(1 << chan->hc_num);
+ j = (j + inc) & (FRLISTEN_64_SIZE - 1);
+ } while (j != i);
+
+ if (!enable)
+ return;
+
+ chan->schinfo = 0;
+ if (chan->speed == USB_SPEED_HIGH && qh->interval) {
+ j = 1;
+ /* TODO - check this */
+ inc = (8 + qh->interval - 1) / qh->interval;
+ for (i = 0; i < inc; i++) {
+ chan->schinfo |= j;
+ j = j << qh->interval;
+ }
+ } else {
+ chan->schinfo = 0xff;
+ }
+}
+
+static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ struct dwc2_host_chan *chan = qh->channel;
+
+ if (dwc2_qh_is_non_per(qh))
+ hsotg->non_periodic_channels--;
+ else
+ dwc2_update_frame_list(hsotg, qh, 0);
+
+ /*
+ * The condition is added to prevent double cleanup try in case of
+ * device disconnect. See channel cleanup in dwc2_hcd_disconnect().
+ */
+ if (chan->qh) {
+ if (!list_empty(&chan->hc_list_entry))
+ list_del(&chan->hc_list_entry);
+ dwc2_hc_cleanup(hsotg, chan);
+ list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+ chan->qh = NULL;
+ }
+
+ qh->channel = NULL;
+ qh->ntd = 0;
+
+ if (qh->desc_list)
+ memset(qh->desc_list, 0, sizeof(struct dwc2_hcd_dma_desc) *
+ dwc2_max_desc_num(qh));
+}
+
+/**
+ * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA
+ * related members
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to init
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * Allocates memory for the descriptor list. For the first periodic QH,
+ * allocates memory for the FrameList and enables periodic scheduling.
+ */
+int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ gfp_t mem_flags)
+{
+ int retval;
+
+ if (qh->do_split) {
+ dev_err(hsotg->dev,
+ "SPLIT Transfers are not supported in Descriptor DMA mode.\n");
+ retval = -EINVAL;
+ goto err0;
+ }
+
+ retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags);
+ if (retval)
+ goto err0;
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
+ qh->ep_type == USB_ENDPOINT_XFER_INT) {
+ if (!hsotg->frame_list) {
+ retval = dwc2_frame_list_alloc(hsotg, mem_flags);
+ if (retval)
+ goto err1;
+ /* Enable periodic schedule on first periodic QH */
+ dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64);
+ }
+ }
+
+ qh->ntd = 0;
+ return 0;
+
+err1:
+ dwc2_desc_list_free(hsotg, qh);
+err0:
+ return retval;
+}
+
+/**
+ * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related
+ * members
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to free
+ *
+ * Frees descriptor list memory associated with the QH. If QH is periodic and
+ * the last, frees FrameList memory and disables periodic scheduling.
+ */
+void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ dwc2_desc_list_free(hsotg, qh);
+
+ /*
+ * Channel still assigned due to some reasons.
+ * Seen on Isoc URB dequeue. Channel halted but no subsequent
+ * ChHalted interrupt to release the channel. Afterwards
+ * when it comes here from endpoint disable routine
+ * channel remains assigned.
+ */
+ if (qh->channel)
+ dwc2_release_channel_ddma(hsotg, qh);
+
+ if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC ||
+ qh->ep_type == USB_ENDPOINT_XFER_INT) &&
+ !hsotg->periodic_channels && hsotg->frame_list) {
+ dwc2_per_sched_disable(hsotg);
+ dwc2_frame_list_free(hsotg);
+ }
+}
+
+static u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx)
+{
+ if (qh->dev_speed == USB_SPEED_HIGH)
+ /* Descriptor set (8 descriptors) index which is 8-aligned */
+ return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8;
+ else
+ return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1);
+}
+
+/*
+ * Determine starting frame for Isochronous transfer.
+ * Few frames skipped to prevent race condition with HC.
+ */
+static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, u16 *skip_frames)
+{
+ u16 frame;
+
+ hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+ /* sched_frame is always frame number (not uFrame) both in FS and HS! */
+
+ /*
+ * skip_frames is used to limit activated descriptors number
+ * to avoid the situation when HC services the last activated
+ * descriptor firstly.
+ * Example for FS:
+ * Current frame is 1, scheduled frame is 3. Since HC always fetches
+ * the descriptor corresponding to curr_frame+1, the descriptor
+ * corresponding to frame 2 will be fetched. If the number of
+ * descriptors is max=64 (or greather) the list will be fully programmed
+ * with Active descriptors and it is possible case (rare) that the
+ * latest descriptor(considering rollback) corresponding to frame 2 will
+ * be serviced first. HS case is more probable because, in fact, up to
+ * 11 uframes (16 in the code) may be skipped.
+ */
+ if (qh->dev_speed == USB_SPEED_HIGH) {
+ /*
+ * Consider uframe counter also, to start xfer asap. If half of
+ * the frame elapsed skip 2 frames otherwise just 1 frame.
+ * Starting descriptor index must be 8-aligned, so if the
+ * current frame is near to complete the next one is skipped as
+ * well.
+ */
+ if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) {
+ *skip_frames = 2 * 8;
+ frame = dwc2_frame_num_inc(hsotg->frame_number,
+ *skip_frames);
+ } else {
+ *skip_frames = 1 * 8;
+ frame = dwc2_frame_num_inc(hsotg->frame_number,
+ *skip_frames);
+ }
+
+ frame = dwc2_full_frame_num(frame);
+ } else {
+ /*
+ * Two frames are skipped for FS - the current and the next.
+ * But for descriptor programming, 1 frame (descriptor) is
+ * enough, see example above.
+ */
+ *skip_frames = 1;
+ frame = dwc2_frame_num_inc(hsotg->frame_number, 2);
+ }
+
+ return frame;
+}
+
+/*
+ * Calculate initial descriptor index for isochronous transfer based on
+ * scheduled frame
+ */
+static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ u16 frame, fr_idx, fr_idx_tmp, skip_frames;
+
+ /*
+ * With current ISOC processing algorithm the channel is being released
+ * when no more QTDs in the list (qh->ntd == 0). Thus this function is
+ * called only when qh->ntd == 0 and qh->channel == 0.
+ *
+ * So qh->channel != NULL branch is not used and just not removed from
+ * the source file. It is required for another possible approach which
+ * is, do not disable and release the channel when ISOC session
+ * completed, just move QH to inactive schedule until new QTD arrives.
+ * On new QTD, the QH moved back to 'ready' schedule, starting frame and
+ * therefore starting desc_index are recalculated. In this case channel
+ * is released only on ep_disable.
+ */
+
+ /*
+ * Calculate starting descriptor index. For INTERRUPT endpoint it is
+ * always 0.
+ */
+ if (qh->channel) {
+ frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames);
+ /*
+ * Calculate initial descriptor index based on FrameList current
+ * bitmap and servicing period
+ */
+ fr_idx_tmp = dwc2_frame_list_idx(frame);
+ fr_idx = (FRLISTEN_64_SIZE +
+ dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp)
+ % dwc2_frame_incr_val(qh);
+ fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE;
+ } else {
+ qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh,
+ &skip_frames);
+ fr_idx = dwc2_frame_list_idx(qh->sched_frame);
+ }
+
+ qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx);
+
+ return skip_frames;
+}
+
+#define ISOC_URB_GIVEBACK_ASAP
+
+#define MAX_ISOC_XFER_SIZE_FS 1023
+#define MAX_ISOC_XFER_SIZE_HS 3072
+#define DESCNUM_THRESHOLD 4
+
+static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_qtd *qtd,
+ struct dwc2_qh *qh, u32 max_xfer_size,
+ u16 idx)
+{
+ struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+ memset(dma_desc, 0, sizeof(*dma_desc));
+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+
+ if (frame_desc->length > max_xfer_size)
+ qh->n_bytes[idx] = max_xfer_size;
+ else
+ qh->n_bytes[idx] = frame_desc->length;
+
+ dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
+ dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT &
+ HOST_DMA_ISOC_NBYTES_MASK;
+
+#ifdef ISOC_URB_GIVEBACK_ASAP
+ /* Set IOC for each descriptor corresponding to last frame of URB */
+ if (qtd->isoc_frame_index_last == qtd->urb->packet_count)
+ dma_desc->status |= HOST_DMA_IOC;
+#endif
+
+ qh->ntd++;
+ qtd->isoc_frame_index_last++;
+}
+
+static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, u16 skip_frames)
+{
+ struct dwc2_qtd *qtd;
+ u32 max_xfer_size;
+ u16 idx, inc, n_desc, ntd_max = 0;
+
+ idx = qh->td_last;
+ inc = qh->interval;
+ n_desc = 0;
+
+ if (qh->interval) {
+ ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) /
+ qh->interval;
+ if (skip_frames && !qh->channel)
+ ntd_max -= skip_frames / qh->interval;
+ }
+
+ max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ?
+ MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS;
+
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+ while (qh->ntd < ntd_max && qtd->isoc_frame_index_last <
+ qtd->urb->packet_count) {
+ if (n_desc > 1)
+ qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+ dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh,
+ max_xfer_size, idx);
+ idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed);
+ n_desc++;
+ }
+ qtd->in_process = 1;
+ }
+
+ qh->td_last = idx;
+
+#ifdef ISOC_URB_GIVEBACK_ASAP
+ /* Set IOC for last descriptor if descriptor list is full */
+ if (qh->ntd == ntd_max) {
+ idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+ qh->desc_list[idx].status |= HOST_DMA_IOC;
+ }
+#else
+ /*
+ * Set IOC bit only for one descriptor. Always try to be ahead of HW
+ * processing, i.e. on IOC generation driver activates next descriptor
+ * but core continues to process descriptors following the one with IOC
+ * set.
+ */
+
+ if (n_desc > DESCNUM_THRESHOLD)
+ /*
+ * Move IOC "up". Required even if there is only one QTD
+ * in the list, because QTDs might continue to be queued,
+ * but during the activation it was only one queued.
+ * Actually more than one QTD might be in the list if this
+ * function called from XferCompletion - QTDs was queued during
+ * HW processing of the previous descriptor chunk.
+ */
+ idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2),
+ qh->dev_speed);
+ else
+ /*
+ * Set the IOC for the latest descriptor if either number of
+ * descriptors is not greater than threshold or no more new
+ * descriptors activated
+ */
+ idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed);
+
+ qh->desc_list[idx].status |= HOST_DMA_IOC;
+#endif
+
+ if (n_desc) {
+ qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+ if (n_desc > 1)
+ qh->desc_list[0].status |= HOST_DMA_A;
+ }
+}
+
+static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd, struct dwc2_qh *qh,
+ int n_desc)
+{
+ struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[n_desc];
+ int len = chan->xfer_len;
+
+ if (len > MAX_DMA_DESC_SIZE)
+ len = MAX_DMA_DESC_SIZE - chan->max_packet + 1;
+
+ if (chan->ep_is_in) {
+ int num_packets;
+
+ if (len > 0 && chan->max_packet)
+ num_packets = (len + chan->max_packet - 1)
+ / chan->max_packet;
+ else
+ /* Need 1 packet for transfer length of 0 */
+ num_packets = 1;
+
+ /* Always program an integral # of packets for IN transfers */
+ len = num_packets * chan->max_packet;
+ }
+
+ dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK;
+ qh->n_bytes[n_desc] = len;
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL &&
+ qtd->control_phase == DWC2_CONTROL_SETUP)
+ dma_desc->status |= HOST_DMA_SUP;
+
+ dma_desc->buf = (u32)chan->xfer_dma;
+
+ /*
+ * Last (or only) descriptor of IN transfer with actual size less
+ * than MaxPacket
+ */
+ if (len > chan->xfer_len) {
+ chan->xfer_len = 0;
+ } else {
+ chan->xfer_dma += len;
+ chan->xfer_len -= len;
+ }
+}
+
+static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ struct dwc2_qtd *qtd;
+ struct dwc2_host_chan *chan = qh->channel;
+ int n_desc = 0;
+
+ dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh,
+ (unsigned long)chan->xfer_dma, chan->xfer_len);
+
+ /*
+ * Start with chan->xfer_dma initialized in assign_and_init_hc(), then
+ * if SG transfer consists of multiple URBs, this pointer is re-assigned
+ * to the buffer of the currently processed QTD. For non-SG request
+ * there is always one QTD active.
+ */
+
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) {
+ dev_vdbg(hsotg->dev, "qtd=%p\n", qtd);
+
+ if (n_desc) {
+ /* SG request - more than 1 QTD */
+ chan->xfer_dma = qtd->urb->dma +
+ qtd->urb->actual_length;
+ chan->xfer_len = qtd->urb->length -
+ qtd->urb->actual_length;
+ dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n",
+ (unsigned long)chan->xfer_dma, chan->xfer_len);
+ }
+
+ qtd->n_desc = 0;
+ do {
+ if (n_desc > 1) {
+ qh->desc_list[n_desc - 1].status |= HOST_DMA_A;
+ dev_vdbg(hsotg->dev,
+ "set A bit in desc %d (%p)\n",
+ n_desc - 1,
+ &qh->desc_list[n_desc - 1]);
+ }
+ dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc);
+ dev_vdbg(hsotg->dev,
+ "desc %d (%p) buf=%08x status=%08x\n",
+ n_desc, &qh->desc_list[n_desc],
+ qh->desc_list[n_desc].buf,
+ qh->desc_list[n_desc].status);
+ qtd->n_desc++;
+ n_desc++;
+ } while (chan->xfer_len > 0 &&
+ n_desc != MAX_DMA_DESC_NUM_GENERIC);
+
+ dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc);
+ qtd->in_process = 1;
+ if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL)
+ break;
+ if (n_desc == MAX_DMA_DESC_NUM_GENERIC)
+ break;
+ }
+
+ if (n_desc) {
+ qh->desc_list[n_desc - 1].status |=
+ HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A;
+ dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n",
+ n_desc - 1, &qh->desc_list[n_desc - 1]);
+ if (n_desc > 1) {
+ qh->desc_list[0].status |= HOST_DMA_A;
+ dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n",
+ &qh->desc_list[0]);
+ }
+ chan->ntd = n_desc;
+ }
+}
+
+/**
+ * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to init
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * For Control and Bulk endpoints, initializes descriptor list and starts the
+ * transfer. For Interrupt and Isochronous endpoints, initializes descriptor
+ * list then updates FrameList, marking appropriate entries as active.
+ *
+ * For Isochronous endpoints the starting descriptor index is calculated based
+ * on the scheduled frame, but only on the first transfer descriptor within a
+ * session. Then the transfer is started via enabling the channel.
+ *
+ * For Isochronous endpoints the channel is not halted on XferComplete
+ * interrupt so remains assigned to the endpoint(QH) until session is done.
+ */
+void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ /* Channel is already assigned */
+ struct dwc2_host_chan *chan = qh->channel;
+ u16 skip_frames = 0;
+
+ switch (chan->ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ dwc2_init_non_isoc_dma_desc(hsotg, qh);
+ dwc2_hc_start_transfer_ddma(hsotg, chan);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ dwc2_init_non_isoc_dma_desc(hsotg, qh);
+ dwc2_update_frame_list(hsotg, qh, 1);
+ dwc2_hc_start_transfer_ddma(hsotg, chan);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!qh->ntd)
+ skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh);
+ dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames);
+
+ if (!chan->xfer_started) {
+ dwc2_update_frame_list(hsotg, qh, 1);
+
+ /*
+ * Always set to max, instead of actual size. Otherwise
+ * ntd will be changed with channel being enabled. Not
+ * recommended.
+ */
+ chan->ntd = dwc2_max_desc_num(qh);
+
+ /* Enable channel only once for ISOC */
+ dwc2_hc_start_transfer_ddma(hsotg, chan);
+ }
+
+ break;
+ default:
+ break;
+ }
+}
+
+#define DWC2_CMPL_DONE 1
+#define DWC2_CMPL_STOP 2
+
+static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd,
+ struct dwc2_qh *qh, u16 idx)
+{
+ struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx];
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+ u16 remain = 0;
+ int rc = 0;
+
+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last];
+ dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset);
+ if (chan->ep_is_in)
+ remain = dma_desc->status >> HOST_DMA_ISOC_NBYTES_SHIFT &
+ HOST_DMA_ISOC_NBYTES_MASK >> HOST_DMA_ISOC_NBYTES_SHIFT;
+
+ if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
+ /*
+ * XactError, or unable to complete all the transactions
+ * in the scheduled micro-frame/frame, both indicated by
+ * HOST_DMA_STS_PKTERR
+ */
+ qtd->urb->error_count++;
+ frame_desc->actual_length = qh->n_bytes[idx] - remain;
+ frame_desc->status = -EPROTO;
+ } else {
+ /* Success */
+ frame_desc->actual_length = qh->n_bytes[idx] - remain;
+ frame_desc->status = 0;
+ }
+
+ if (++qtd->isoc_frame_index == qtd->urb->packet_count) {
+ /*
+ * urb->status is not used for isoc transfers here. The
+ * individual frame_desc status are used instead.
+ */
+ dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+
+ /*
+ * This check is necessary because urb_dequeue can be called
+ * from urb complete callback (sound driver for example). All
+ * pending URBs are dequeued there, so no need for further
+ * processing.
+ */
+ if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE)
+ return -1;
+ rc = DWC2_CMPL_DONE;
+ }
+
+ qh->ntd--;
+
+ /* Stop if IOC requested descriptor reached */
+ if (dma_desc->status & HOST_DMA_IOC)
+ rc = DWC2_CMPL_STOP;
+
+ return rc;
+}
+
+static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ enum dwc2_halt_status halt_status)
+{
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+ struct dwc2_qtd *qtd, *qtd_tmp;
+ struct dwc2_qh *qh;
+ u16 idx;
+ int rc;
+
+ qh = chan->qh;
+ idx = qh->td_first;
+
+ if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
+ qtd->in_process = 0;
+ return;
+ }
+
+ if (halt_status == DWC2_HC_XFER_AHB_ERR ||
+ halt_status == DWC2_HC_XFER_BABBLE_ERR) {
+ /*
+ * Channel is halted in these error cases, considered as serious
+ * issues.
+ * Complete all URBs marking all frames as failed, irrespective
+ * whether some of the descriptors (frames) succeeded or not.
+ * Pass error code to completion routine as well, to update
+ * urb->status, some of class drivers might use it to stop
+ * queing transfer requests.
+ */
+ int err = halt_status == DWC2_HC_XFER_AHB_ERR ?
+ -EIO : -EOVERFLOW;
+
+ list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list,
+ qtd_list_entry) {
+ for (idx = 0; idx < qtd->urb->packet_count; idx++) {
+ frame_desc = &qtd->urb->iso_descs[idx];
+ frame_desc->status = err;
+ }
+
+ dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
+ err);
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+ }
+
+ return;
+ }
+
+ list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
+ if (!qtd->in_process)
+ break;
+ do {
+ rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
+ idx);
+ if (rc < 0)
+ return;
+ idx = dwc2_desclist_idx_inc(idx, qh->interval,
+ chan->speed);
+ if (rc == DWC2_CMPL_STOP)
+ goto stop_scan;
+ if (rc == DWC2_CMPL_DONE)
+ break;
+ } while (idx != qh->td_first);
+ }
+
+stop_scan:
+ qh->td_first = idx;
+}
+
+static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd,
+ struct dwc2_hcd_dma_desc *dma_desc,
+ enum dwc2_halt_status halt_status,
+ u32 n_bytes, int *xfer_done)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ u16 remain = 0;
+
+ if (chan->ep_is_in)
+ remain = dma_desc->status >> HOST_DMA_NBYTES_SHIFT &
+ HOST_DMA_NBYTES_MASK >> HOST_DMA_NBYTES_SHIFT;
+
+ dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb);
+
+ if (halt_status == DWC2_HC_XFER_AHB_ERR) {
+ dev_err(hsotg->dev, "EIO\n");
+ urb->status = -EIO;
+ return 1;
+ }
+
+ if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) {
+ switch (halt_status) {
+ case DWC2_HC_XFER_STALL:
+ dev_vdbg(hsotg->dev, "Stall\n");
+ urb->status = -EPIPE;
+ break;
+ case DWC2_HC_XFER_BABBLE_ERR:
+ dev_err(hsotg->dev, "Babble\n");
+ urb->status = -EOVERFLOW;
+ break;
+ case DWC2_HC_XFER_XACT_ERR:
+ dev_err(hsotg->dev, "XactErr\n");
+ urb->status = -EPROTO;
+ break;
+ default:
+ dev_err(hsotg->dev,
+ "%s: Unhandled descriptor error status (%d)\n",
+ __func__, halt_status);
+ break;
+ }
+ return 1;
+ }
+
+ if (dma_desc->status & HOST_DMA_A) {
+ dev_vdbg(hsotg->dev,
+ "Active descriptor encountered on channel %d\n",
+ chan->hc_num);
+ return 0;
+ }
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) {
+ if (qtd->control_phase == DWC2_CONTROL_DATA) {
+ urb->actual_length += n_bytes - remain;
+ if (remain || urb->actual_length >= urb->length) {
+ /*
+ * For Control Data stage do not set urb->status
+ * to 0, to prevent URB callback. Set it when
+ * Status phase is done. See below.
+ */
+ *xfer_done = 1;
+ }
+ } else if (qtd->control_phase == DWC2_CONTROL_STATUS) {
+ urb->status = 0;
+ *xfer_done = 1;
+ }
+ /* No handling for SETUP stage */
+ } else {
+ /* BULK and INTR */
+ urb->actual_length += n_bytes - remain;
+ dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length,
+ urb->actual_length);
+ if (remain || urb->actual_length >= urb->length) {
+ urb->status = 0;
+ *xfer_done = 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ int chnum, struct dwc2_qtd *qtd,
+ int desc_num,
+ enum dwc2_halt_status halt_status,
+ int *xfer_done)
+{
+ struct dwc2_qh *qh = chan->qh;
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ struct dwc2_hcd_dma_desc *dma_desc;
+ u32 n_bytes;
+ int failed;
+
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ dma_desc = &qh->desc_list[desc_num];
+ n_bytes = qh->n_bytes[desc_num];
+ dev_vdbg(hsotg->dev,
+ "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n",
+ qtd, urb, desc_num, dma_desc, n_bytes);
+ failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc,
+ halt_status, n_bytes,
+ xfer_done);
+ if (failed || (*xfer_done && urb->status != -EINPROGRESS)) {
+ dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+ dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n",
+ failed, *xfer_done, urb->status);
+ return failed;
+ }
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) {
+ switch (qtd->control_phase) {
+ case DWC2_CONTROL_SETUP:
+ if (urb->length > 0)
+ qtd->control_phase = DWC2_CONTROL_DATA;
+ else
+ qtd->control_phase = DWC2_CONTROL_STATUS;
+ dev_vdbg(hsotg->dev,
+ " Control setup transaction done\n");
+ break;
+ case DWC2_CONTROL_DATA:
+ if (*xfer_done) {
+ qtd->control_phase = DWC2_CONTROL_STATUS;
+ dev_vdbg(hsotg->dev,
+ " Control data transfer done\n");
+ } else if (desc_num + 1 == qtd->n_desc) {
+ /*
+ * Last descriptor for Control data stage which
+ * is not completed yet
+ */
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
+ qtd);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ int chnum,
+ enum dwc2_halt_status halt_status)
+{
+ struct list_head *qtd_item, *qtd_tmp;
+ struct dwc2_qh *qh = chan->qh;
+ struct dwc2_qtd *qtd = NULL;
+ int xfer_done;
+ int desc_num = 0;
+
+ if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry)
+ qtd->in_process = 0;
+ return;
+ }
+
+ list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) {
+ int i;
+
+ qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry);
+ xfer_done = 0;
+
+ for (i = 0; i < qtd->n_desc; i++) {
+ if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd,
+ desc_num, halt_status,
+ &xfer_done))
+ break;
+ desc_num++;
+ }
+ }
+
+ if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+ /*
+ * Resetting the data toggle for bulk and interrupt endpoints
+ * in case of stall. See handle_hc_stall_intr().
+ */
+ if (halt_status == DWC2_HC_XFER_STALL)
+ qh->data_toggle = DWC2_HC_PID_DATA0;
+ else if (qtd)
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+ }
+
+ if (halt_status == DWC2_HC_XFER_COMPLETE) {
+ if (chan->hcint & HCINTMSK_NYET) {
+ /*
+ * Got a NYET on the last transaction of the transfer.
+ * It means that the endpoint should be in the PING
+ * state at the beginning of the next transfer.
+ */
+ qh->ping_state = 1;
+ }
+ }
+}
+
+/**
+ * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's
+ * status and calls completion routine for the URB if it's done. Called from
+ * interrupt handlers.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @chan: Host channel the transfer is completed on
+ * @chnum: Index of Host channel registers
+ * @halt_status: Reason the channel is being halted or just XferComplete
+ * for isochronous transfers
+ *
+ * Releases the channel to be used by other transfers.
+ * In case of Isochronous endpoint the channel is not halted until the end of
+ * the session, i.e. QTD list is empty.
+ * If periodic channel released the FrameList is updated accordingly.
+ * Calls transaction selection routines to activate pending transfers.
+ */
+void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ enum dwc2_halt_status halt_status)
+{
+ struct dwc2_qh *qh = chan->qh;
+ int continue_isoc_xfer = 0;
+ enum dwc2_transaction_type tr_type;
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status);
+
+ /* Release the channel if halted or session completed */
+ if (halt_status != DWC2_HC_XFER_COMPLETE ||
+ list_empty(&qh->qtd_list)) {
+ /* Halt the channel if session completed */
+ if (halt_status == DWC2_HC_XFER_COMPLETE)
+ dwc2_hc_halt(hsotg, chan, halt_status);
+ dwc2_release_channel_ddma(hsotg, qh);
+ dwc2_hcd_qh_unlink(hsotg, qh);
+ } else {
+ /* Keep in assigned schedule to continue transfer */
+ list_move(&qh->qh_list_entry,
+ &hsotg->periodic_sched_assigned);
+ continue_isoc_xfer = 1;
+ }
+ /*
+ * Todo: Consider the case when period exceeds FrameList size.
+ * Frame Rollover interrupt should be used.
+ */
+ } else {
+ /*
+ * Scan descriptor list to complete the URB(s), then release
+ * the channel
+ */
+ dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum,
+ halt_status);
+ dwc2_release_channel_ddma(hsotg, qh);
+ dwc2_hcd_qh_unlink(hsotg, qh);
+
+ if (!list_empty(&qh->qtd_list)) {
+ /*
+ * Add back to inactive non-periodic schedule on normal
+ * completion
+ */
+ dwc2_hcd_qh_add(hsotg, qh);
+ }
+ }
+
+ tr_type = dwc2_hcd_select_transactions(hsotg);
+ if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) {
+ if (continue_isoc_xfer) {
+ if (tr_type == DWC2_TRANSACTION_NONE)
+ tr_type = DWC2_TRANSACTION_PERIODIC;
+ else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC)
+ tr_type = DWC2_TRANSACTION_ALL;
+ }
+ dwc2_hcd_queue_transactions(hsotg, tr_type);
+ }
+}
diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
new file mode 100644
index 000000000000..6e5dbed6ccec
--- /dev/null
+++ b/drivers/staging/dwc2/hcd_intr.c
@@ -0,0 +1,2130 @@
+/*
+ * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains the interrupt handlers for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/* This function is for debug only */
+static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
+{
+#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
+#warning Compiling code to track missed SOFs
+
+ u16 curr_frame_number = hsotg->frame_number;
+
+ if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
+ if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) !=
+ curr_frame_number) {
+ hsotg->frame_num_array[hsotg->frame_num_idx] =
+ curr_frame_number;
+ hsotg->last_frame_num_array[hsotg->frame_num_idx] =
+ hsotg->last_frame_num;
+ hsotg->frame_num_idx++;
+ }
+ } else if (!hsotg->dumped_frame_num_array) {
+ int i;
+
+ dev_info(hsotg->dev, "Frame Last Frame\n");
+ dev_info(hsotg->dev, "----- ----------\n");
+ for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
+ dev_info(hsotg->dev, "0x%04x 0x%04x\n",
+ hsotg->frame_num_array[i],
+ hsotg->last_frame_num_array[i]);
+ }
+ hsotg->dumped_frame_num_array = 1;
+ }
+ hsotg->last_frame_num = curr_frame_number;
+#endif
+}
+
+static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd)
+{
+ struct urb *usb_urb;
+
+ if (!chan->qh || !qtd->urb)
+ return;
+
+ usb_urb = qtd->urb->priv;
+ if (!usb_urb || !usb_urb->dev)
+ return;
+
+ if (chan->qh->dev_speed != USB_SPEED_HIGH &&
+ qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) {
+ chan->qh->tt_buffer_dirty = 1;
+ if (usb_hub_clear_tt_buffer(usb_urb))
+ /* Clear failed; let's hope things work anyway */
+ chan->qh->tt_buffer_dirty = 0;
+ }
+}
+
+/*
+ * Handles the start-of-frame interrupt in host mode. Non-periodic
+ * transactions may be queued to the DWC_otg controller for the current
+ * (micro)frame. Periodic transactions may be queued to the controller
+ * for the next (micro)frame.
+ */
+static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
+{
+ struct list_head *qh_entry;
+ struct dwc2_qh *qh;
+ u32 hfnum;
+ enum dwc2_transaction_type tr_type;
+
+#ifdef DEBUG_SOF
+ dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
+#endif
+
+ hfnum = readl(hsotg->regs + HFNUM);
+ hsotg->frame_number = hfnum >> HFNUM_FRNUM_SHIFT &
+ HFNUM_FRNUM_MASK >> HFNUM_FRNUM_SHIFT;
+
+ dwc2_track_missed_sofs(hsotg);
+
+ /* Determine whether any periodic QHs should be executed */
+ qh_entry = hsotg->periodic_sched_inactive.next;
+ while (qh_entry != &hsotg->periodic_sched_inactive) {
+ qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry);
+ qh_entry = qh_entry->next;
+ if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number))
+ /*
+ * Move QH to the ready list to be executed next
+ * (micro)frame
+ */
+ list_move(&qh->qh_list_entry,
+ &hsotg->periodic_sched_ready);
+ }
+ tr_type = dwc2_hcd_select_transactions(hsotg);
+ if (tr_type != DWC2_TRANSACTION_NONE)
+ dwc2_hcd_queue_transactions(hsotg, tr_type);
+
+ /* Clear interrupt */
+ writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
+}
+
+/*
+ * Handles the Rx FIFO Level Interrupt, which indicates that there is
+ * at least one packet in the Rx FIFO. The packets are moved from the FIFO to
+ * memory if the DWC_otg controller is operating in Slave mode.
+ */
+static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 grxsts, chnum, bcnt, dpid, pktsts;
+ struct dwc2_host_chan *chan;
+
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
+
+ grxsts = readl(hsotg->regs + GRXSTSP);
+ chnum = grxsts >> GRXSTS_HCHNUM_SHIFT &
+ GRXSTS_HCHNUM_MASK >> GRXSTS_HCHNUM_SHIFT;
+ chan = hsotg->hc_ptr_array[chnum];
+ if (!chan) {
+ dev_err(hsotg->dev, "Unable to get corresponding channel\n");
+ return;
+ }
+
+ bcnt = grxsts >> GRXSTS_BYTECNT_SHIFT &
+ GRXSTS_BYTECNT_MASK >> GRXSTS_BYTECNT_SHIFT;
+ dpid = grxsts >> GRXSTS_DPID_SHIFT &
+ GRXSTS_DPID_MASK >> GRXSTS_DPID_SHIFT;
+ pktsts = grxsts & GRXSTS_PKTSTS_MASK;
+
+ /* Packet Status */
+ if (dbg_perio()) {
+ dev_vdbg(hsotg->dev, " Ch num = %d\n", chnum);
+ dev_vdbg(hsotg->dev, " Count = %d\n", bcnt);
+ dev_vdbg(hsotg->dev, " DPID = %d, chan.dpid = %d\n", dpid,
+ chan->data_pid_start);
+ dev_vdbg(hsotg->dev, " PStatus = %d\n",
+ pktsts >> GRXSTS_PKTSTS_SHIFT &
+ GRXSTS_PKTSTS_MASK >> GRXSTS_PKTSTS_SHIFT);
+ }
+
+ switch (pktsts) {
+ case GRXSTS_PKTSTS_HCHIN:
+ /* Read the data into the host buffer */
+ if (bcnt > 0) {
+ dwc2_read_packet(hsotg, chan->xfer_buf, bcnt);
+
+ /* Update the HC fields for the next packet received */
+ chan->xfer_count += bcnt;
+ chan->xfer_buf += bcnt;
+ }
+ break;
+ case GRXSTS_PKTSTS_HCHIN_XFER_COMP:
+ case GRXSTS_PKTSTS_DATATOGGLEERR:
+ case GRXSTS_PKTSTS_HCHHALTED:
+ /* Handled in interrupt, just ignore data */
+ break;
+ default:
+ dev_err(hsotg->dev,
+ "RxFIFO Level Interrupt: Unknown status %d\n", pktsts);
+ break;
+ }
+}
+
+/*
+ * This interrupt occurs when the non-periodic Tx FIFO is half-empty. More
+ * data packets may be written to the FIFO for OUT transfers. More requests
+ * may be written to the non-periodic request queue for IN transfers. This
+ * interrupt is enabled only in Slave mode.
+ */
+static void dwc2_np_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
+{
+ dev_vdbg(hsotg->dev, "--Non-Periodic TxFIFO Empty Interrupt--\n");
+ dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_NON_PERIODIC);
+}
+
+/*
+ * This interrupt occurs when the periodic Tx FIFO is half-empty. More data
+ * packets may be written to the FIFO for OUT transfers. More requests may be
+ * written to the periodic request queue for IN transfers. This interrupt is
+ * enabled only in Slave mode.
+ */
+static void dwc2_perio_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg)
+{
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, "--Periodic TxFIFO Empty Interrupt--\n");
+ dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_PERIODIC);
+}
+
+static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
+ u32 *hprt0_modify)
+{
+ struct dwc2_core_params *params = hsotg->core_params;
+ int do_reset = 0;
+ u32 usbcfg;
+ u32 prtspd;
+ u32 hcfg;
+ u32 hfir;
+
+ dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
+
+ /* Every time when port enables calculate HFIR.FrInterval */
+ hfir = readl(hsotg->regs + HFIR);
+ hfir &= ~HFIR_FRINT_MASK;
+ hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
+ HFIR_FRINT_MASK;
+ writel(hfir, hsotg->regs + HFIR);
+
+ /* Check if we need to adjust the PHY clock speed for low power */
+ if (!params->host_support_fs_ls_low_power) {
+ /* Port has been enabled, set the reset change flag */
+ hsotg->flags.b.port_reset_change = 1;
+ return;
+ }
+
+ usbcfg = readl(hsotg->regs + GUSBCFG);
+ prtspd = hprt0 & HPRT0_SPD_MASK;
+
+ if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
+ /* Low power */
+ if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
+ /* Set PHY low power clock select for FS/LS devices */
+ usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+ do_reset = 1;
+ }
+
+ hcfg = readl(hsotg->regs + HCFG);
+
+ if (prtspd == HPRT0_SPD_LOW_SPEED &&
+ params->host_ls_low_power_phy_clk ==
+ DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) {
+ /* 6 MHZ */
+ dev_vdbg(hsotg->dev,
+ "FS_PHY programming HCFG to 6 MHz\n");
+ if ((hcfg & HCFG_FSLSPCLKSEL_MASK) !=
+ HCFG_FSLSPCLKSEL_6_MHZ) {
+ hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+ hcfg |= HCFG_FSLSPCLKSEL_6_MHZ;
+ writel(hcfg, hsotg->regs + HCFG);
+ do_reset = 1;
+ }
+ } else {
+ /* 48 MHZ */
+ dev_vdbg(hsotg->dev,
+ "FS_PHY programming HCFG to 48 MHz\n");
+ if ((hcfg & HCFG_FSLSPCLKSEL_MASK) !=
+ HCFG_FSLSPCLKSEL_48_MHZ) {
+ hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
+ hcfg |= HCFG_FSLSPCLKSEL_48_MHZ;
+ writel(hcfg, hsotg->regs + HCFG);
+ do_reset = 1;
+ }
+ }
+ } else {
+ /* Not low power */
+ if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
+ usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
+ writel(usbcfg, hsotg->regs + GUSBCFG);
+ do_reset = 1;
+ }
+ }
+
+ if (do_reset) {
+ *hprt0_modify |= HPRT0_RST;
+ queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
+ msecs_to_jiffies(60));
+ } else {
+ /* Port has been enabled, set the reset change flag */
+ hsotg->flags.b.port_reset_change = 1;
+ }
+}
+
+/*
+ * There are multiple conditions that can cause a port interrupt. This function
+ * determines which interrupt conditions have occurred and handles them
+ * appropriately.
+ */
+static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 hprt0;
+ u32 hprt0_modify;
+
+ dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
+
+ hprt0 = readl(hsotg->regs + HPRT0);
+ hprt0_modify = hprt0;
+
+ /*
+ * Clear appropriate bits in HPRT0 to clear the interrupt bit in
+ * GINTSTS
+ */
+ hprt0_modify &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG |
+ HPRT0_OVRCURRCHG);
+
+ /*
+ * Port Connect Detected
+ * Set flag and clear if detected
+ */
+ if (hprt0 & HPRT0_CONNDET) {
+ dev_vdbg(hsotg->dev,
+ "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
+ hprt0);
+ hsotg->flags.b.port_connect_status_change = 1;
+ hsotg->flags.b.port_connect_status = 1;
+ hprt0_modify |= HPRT0_CONNDET;
+
+ /*
+ * The Hub driver asserts a reset when it sees port connect
+ * status change flag
+ */
+ }
+
+ /*
+ * Port Enable Changed
+ * Clear if detected - Set internal flag if disabled
+ */
+ if (hprt0 & HPRT0_ENACHG) {
+ dev_vdbg(hsotg->dev,
+ " --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
+ hprt0, !!(hprt0 & HPRT0_ENA));
+ hprt0_modify |= HPRT0_ENACHG;
+ if (hprt0 & HPRT0_ENA)
+ dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify);
+ else
+ hsotg->flags.b.port_enable_change = 1;
+ }
+
+ /* Overcurrent Change Interrupt */
+ if (hprt0 & HPRT0_OVRCURRCHG) {
+ dev_vdbg(hsotg->dev,
+ " --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
+ hprt0);
+ hsotg->flags.b.port_over_current_change = 1;
+ hprt0_modify |= HPRT0_OVRCURRCHG;
+ }
+
+ /* Clear Port Interrupts */
+ writel(hprt0_modify, hsotg->regs + HPRT0);
+}
+
+/*
+ * Gets the actual length of a transfer after the transfer halts. halt_status
+ * holds the reason for the halt.
+ *
+ * For IN transfers where halt_status is DWC2_HC_XFER_COMPLETE, *short_read
+ * is set to 1 upon return if less than the requested number of bytes were
+ * transferred. short_read may also be NULL on entry, in which case it remains
+ * unchanged.
+ */
+static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status,
+ int *short_read)
+{
+ u32 hctsiz, count, length;
+
+ hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+
+ if (halt_status == DWC2_HC_XFER_COMPLETE) {
+ if (chan->ep_is_in) {
+ count = hctsiz >> TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT;
+ length = chan->xfer_len - count;
+ if (short_read != NULL)
+ *short_read = (count != 0);
+ } else if (chan->qh->do_split) {
+ length = qtd->ssplit_out_xfer_count;
+ } else {
+ length = chan->xfer_len;
+ }
+ } else {
+ /*
+ * Must use the hctsiz.pktcnt field to determine how much data
+ * has been transferred. This field reflects the number of
+ * packets that have been transferred via the USB. This is
+ * always an integral number of packets if the transfer was
+ * halted before its normal completion. (Can't use the
+ * hctsiz.xfersize field because that reflects the number of
+ * bytes transferred via the AHB, not the USB).
+ */
+ count = hctsiz >> TSIZ_PKTCNT_SHIFT &
+ TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT;
+ length = (chan->start_pkt_count - count) * chan->max_packet;
+ }
+
+ return length;
+}
+
+/**
+ * dwc2_update_urb_state() - Updates the state of the URB after a Transfer
+ * Complete interrupt on the host channel. Updates the actual_length field
+ * of the URB based on the number of bytes transferred via the host channel.
+ * Sets the URB status if the data transfer is finished.
+ *
+ * Return: 1 if the data transfer specified by the URB is completely finished,
+ * 0 otherwise
+ */
+static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_hcd_urb *urb,
+ struct dwc2_qtd *qtd)
+{
+ u32 hctsiz;
+ int xfer_done = 0;
+ int short_read = 0;
+ int xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
+ DWC2_HC_XFER_COMPLETE,
+ &short_read);
+
+ if (urb->actual_length + xfer_length > urb->length) {
+ dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
+ xfer_length = urb->length - urb->actual_length;
+ }
+
+ /* Non DWORD-aligned buffer case handling */
+ if (chan->align_buf && xfer_length && chan->ep_is_in) {
+ dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
+ DMA_FROM_DEVICE);
+ memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
+ xfer_length);
+ dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
+ DMA_FROM_DEVICE);
+ }
+
+ dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n",
+ urb->actual_length, xfer_length);
+ urb->actual_length += xfer_length;
+
+ if (xfer_length && chan->ep_type == USB_ENDPOINT_XFER_BULK &&
+ (urb->flags & URB_SEND_ZERO_PACKET) &&
+ urb->actual_length >= urb->length &&
+ !(urb->length % chan->max_packet)) {
+ xfer_done = 0;
+ } else if (short_read || urb->actual_length >= urb->length) {
+ xfer_done = 1;
+ urb->status = 0;
+ }
+
+ hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+ dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
+ __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
+ dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
+ dev_vdbg(hsotg->dev, " hctsiz.xfersize %d\n",
+ hctsiz >> TSIZ_XFERSIZE_SHIFT &
+ TSIZ_XFERSIZE_MASK >> TSIZ_XFERSIZE_SHIFT);
+ dev_vdbg(hsotg->dev, " urb->transfer_buffer_length %d\n", urb->length);
+ dev_vdbg(hsotg->dev, " urb->actual_length %d\n", urb->actual_length);
+ dev_vdbg(hsotg->dev, " short_read %d, xfer_done %d\n", short_read,
+ xfer_done);
+
+ return xfer_done;
+}
+
+/*
+ * Save the starting data toggle for the next transfer. The data toggle is
+ * saved in the QH for non-control transfers and it's saved in the QTD for
+ * control transfers.
+ */
+void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+ u32 pid = hctsiz & TSIZ_SC_MC_PID_MASK;
+
+ if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
+ if (pid == TSIZ_SC_MC_PID_DATA0)
+ chan->qh->data_toggle = DWC2_HC_PID_DATA0;
+ else
+ chan->qh->data_toggle = DWC2_HC_PID_DATA1;
+ } else {
+ if (pid == TSIZ_SC_MC_PID_DATA0)
+ qtd->data_toggle = DWC2_HC_PID_DATA0;
+ else
+ qtd->data_toggle = DWC2_HC_PID_DATA1;
+ }
+}
+
+/**
+ * dwc2_update_isoc_urb_state() - Updates the state of an Isochronous URB when
+ * the transfer is stopped for any reason. The fields of the current entry in
+ * the frame descriptor array are set based on the transfer state and the input
+ * halt_status. Completes the Isochronous URB if all the URB frames have been
+ * completed.
+ *
+ * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be
+ * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE.
+ */
+static enum dwc2_halt_status dwc2_update_isoc_urb_state(
+ struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
+ int chnum, struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+ struct dwc2_hcd_urb *urb = qtd->urb;
+
+ if (!urb)
+ return DWC2_HC_XFER_NO_HALT_STATUS;
+
+ frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
+
+ switch (halt_status) {
+ case DWC2_HC_XFER_COMPLETE:
+ frame_desc->status = 0;
+ frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
+ chan, chnum, qtd, halt_status, NULL);
+
+ /* Non DWORD-aligned buffer case handling */
+ if (chan->align_buf && frame_desc->actual_length &&
+ chan->ep_is_in) {
+ dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
+ __func__);
+ dma_sync_single_for_cpu(hsotg->dev, urb->dma,
+ urb->length, DMA_FROM_DEVICE);
+ memcpy(urb->buf + frame_desc->offset +
+ qtd->isoc_split_offset, chan->qh->dw_align_buf,
+ frame_desc->actual_length);
+ dma_sync_single_for_device(hsotg->dev, urb->dma,
+ urb->length,
+ DMA_FROM_DEVICE);
+ }
+ break;
+ case DWC2_HC_XFER_FRAME_OVERRUN:
+ urb->error_count++;
+ if (chan->ep_is_in)
+ frame_desc->status = -ENOSR;
+ else
+ frame_desc->status = -ECOMM;
+ frame_desc->actual_length = 0;
+ break;
+ case DWC2_HC_XFER_BABBLE_ERR:
+ urb->error_count++;
+ frame_desc->status = -EOVERFLOW;
+ /* Don't need to update actual_length in this case */
+ break;
+ case DWC2_HC_XFER_XACT_ERR:
+ urb->error_count++;
+ frame_desc->status = -EPROTO;
+ frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg,
+ chan, chnum, qtd, halt_status, NULL);
+
+ /* Non DWORD-aligned buffer case handling */
+ if (chan->align_buf && frame_desc->actual_length &&
+ chan->ep_is_in) {
+ dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n",
+ __func__);
+ dma_sync_single_for_cpu(hsotg->dev, urb->dma,
+ urb->length, DMA_FROM_DEVICE);
+ memcpy(urb->buf + frame_desc->offset +
+ qtd->isoc_split_offset, chan->qh->dw_align_buf,
+ frame_desc->actual_length);
+ dma_sync_single_for_device(hsotg->dev, urb->dma,
+ urb->length,
+ DMA_FROM_DEVICE);
+ }
+
+ /* Skip whole frame */
+ if (chan->qh->do_split &&
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
+ hsotg->core_params->dma_enable > 0) {
+ qtd->complete_split = 0;
+ qtd->isoc_split_offset = 0;
+ }
+
+ break;
+ default:
+ dev_err(hsotg->dev, "Unhandled halt_status (%d)\n",
+ halt_status);
+ break;
+ }
+
+ if (++qtd->isoc_frame_index == urb->packet_count) {
+ /*
+ * urb->status is not used for isoc transfers. The individual
+ * frame_desc statuses are used instead.
+ */
+ dwc2_host_complete(hsotg, urb->priv, urb, 0);
+ halt_status = DWC2_HC_XFER_URB_COMPLETE;
+ } else {
+ halt_status = DWC2_HC_XFER_COMPLETE;
+ }
+
+ return halt_status;
+}
+
+/*
+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
+ * still linked to the QH, the QH is added to the end of the inactive
+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
+ * schedule if no more QTDs are linked to the QH.
+ */
+static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ int free_qtd)
+{
+ int continue_split = 0;
+ struct dwc2_qtd *qtd;
+
+ if (dbg_qh(qh))
+ dev_vdbg(hsotg->dev, " %s(%p,%p,%d)\n", __func__,
+ hsotg, qh, free_qtd);
+
+ if (list_empty(&qh->qtd_list)) {
+ dev_dbg(hsotg->dev, "## QTD list empty ##\n");
+ goto no_qtd;
+ }
+
+ qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry);
+
+ if (qtd->complete_split)
+ continue_split = 1;
+ else if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_MID ||
+ qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_END)
+ continue_split = 1;
+
+ if (free_qtd) {
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh);
+ continue_split = 0;
+ }
+
+no_qtd:
+ if (qh->channel)
+ qh->channel->align_buf = 0;
+ qh->channel = NULL;
+ dwc2_hcd_qh_deactivate(hsotg, qh, continue_split);
+}
+
+/**
+ * dwc2_release_channel() - Releases a host channel for use by other transfers
+ *
+ * @hsotg: The HCD state structure
+ * @chan: The host channel to release
+ * @qtd: The QTD associated with the host channel. This QTD may be
+ * freed if the transfer is complete or an error has occurred.
+ * @halt_status: Reason the channel is being released. This status
+ * determines the actions taken by this function.
+ *
+ * Also attempts to select and queue more transactions since at least one host
+ * channel is available.
+ */
+static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ enum dwc2_transaction_type tr_type;
+ u32 haintmsk;
+ int free_qtd = 0;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, " %s: channel %d, halt_status %d\n",
+ __func__, chan->hc_num, halt_status);
+
+ switch (halt_status) {
+ case DWC2_HC_XFER_URB_COMPLETE:
+ free_qtd = 1;
+ break;
+ case DWC2_HC_XFER_AHB_ERR:
+ case DWC2_HC_XFER_STALL:
+ case DWC2_HC_XFER_BABBLE_ERR:
+ free_qtd = 1;
+ break;
+ case DWC2_HC_XFER_XACT_ERR:
+ if (qtd && qtd->error_count >= 3) {
+ dev_vdbg(hsotg->dev,
+ " Complete URB with transaction error\n");
+ free_qtd = 1;
+ if (qtd->urb) {
+ qtd->urb->status = -EPROTO;
+ dwc2_host_complete(hsotg, qtd->urb->priv,
+ qtd->urb, -EPROTO);
+ }
+ }
+ break;
+ case DWC2_HC_XFER_URB_DEQUEUE:
+ /*
+ * The QTD has already been removed and the QH has been
+ * deactivated. Don't want to do anything except release the
+ * host channel and try to queue more transfers.
+ */
+ goto cleanup;
+ case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
+ dev_vdbg(hsotg->dev, " Complete URB with I/O error\n");
+ free_qtd = 1;
+ if (qtd && qtd->urb) {
+ qtd->urb->status = -EIO;
+ dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
+ -EIO);
+ }
+ break;
+ case DWC2_HC_XFER_NO_HALT_STATUS:
+ default:
+ break;
+ }
+
+ dwc2_deactivate_qh(hsotg, chan->qh, free_qtd);
+
+cleanup:
+ /*
+ * Release the host channel for use by other transfers. The cleanup
+ * function clears the channel interrupt enables and conditions, so
+ * there's no need to clear the Channel Halted interrupt separately.
+ */
+ if (!list_empty(&chan->hc_list_entry))
+ list_del(&chan->hc_list_entry);
+ dwc2_hc_cleanup(hsotg, chan);
+ list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list);
+
+ switch (chan->ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ hsotg->non_periodic_channels--;
+ break;
+ default:
+ /*
+ * Don't release reservations for periodic channels here.
+ * That's done when a periodic transfer is descheduled (i.e.
+ * when the QH is removed from the periodic schedule).
+ */
+ break;
+ }
+
+ haintmsk = readl(hsotg->regs + HAINTMSK);
+ haintmsk &= ~(1 << chan->hc_num);
+ writel(haintmsk, hsotg->regs + HAINTMSK);
+
+ /* Try to queue more transfers now that there's a free channel */
+ tr_type = dwc2_hcd_select_transactions(hsotg);
+ if (tr_type != DWC2_TRANSACTION_NONE)
+ dwc2_hcd_queue_transactions(hsotg, tr_type);
+}
+
+/*
+ * Halts a host channel. If the channel cannot be halted immediately because
+ * the request queue is full, this function ensures that the FIFO empty
+ * interrupt for the appropriate queue is enabled so that the halt request can
+ * be queued when there is space in the request queue.
+ *
+ * This function may also be called in DMA mode. In that case, the channel is
+ * simply released since the core always halts the channel automatically in
+ * DMA mode.
+ */
+static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (hsotg->core_params->dma_enable > 0) {
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "DMA enabled\n");
+ dwc2_release_channel(hsotg, chan, qtd, halt_status);
+ return;
+ }
+
+ /* Slave mode processing */
+ dwc2_hc_halt(hsotg, chan, halt_status);
+
+ if (chan->halt_on_queue) {
+ u32 gintmsk;
+
+ dev_vdbg(hsotg->dev, "Halt on queue\n");
+ if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+ chan->ep_type == USB_ENDPOINT_XFER_BULK) {
+ dev_vdbg(hsotg->dev, "control/bulk\n");
+ /*
+ * Make sure the Non-periodic Tx FIFO empty interrupt
+ * is enabled so that the non-periodic schedule will
+ * be processed
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk |= GINTSTS_NPTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ } else {
+ dev_vdbg(hsotg->dev, "isoc/intr\n");
+ /*
+ * Move the QH from the periodic queued schedule to
+ * the periodic assigned schedule. This allows the
+ * halt to be queued when the periodic schedule is
+ * processed.
+ */
+ list_move(&chan->qh->qh_list_entry,
+ &hsotg->periodic_sched_assigned);
+
+ /*
+ * Make sure the Periodic Tx FIFO Empty interrupt is
+ * enabled so that the periodic schedule will be
+ * processed
+ */
+ gintmsk = readl(hsotg->regs + GINTMSK);
+ gintmsk |= GINTSTS_PTXFEMP;
+ writel(gintmsk, hsotg->regs + GINTMSK);
+ }
+ }
+}
+
+/*
+ * Performs common cleanup for non-periodic transfers after a Transfer
+ * Complete interrupt. This function should be called after any endpoint type
+ * specific handling is finished to release the host channel.
+ */
+static void dwc2_complete_non_periodic_xfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan,
+ int chnum, struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ qtd->error_count = 0;
+
+ if (chan->hcint & HCINTMSK_NYET) {
+ /*
+ * Got a NYET on the last transaction of the transfer. This
+ * means that the endpoint should be in the PING state at the
+ * beginning of the next transfer.
+ */
+ dev_vdbg(hsotg->dev, "got NYET\n");
+ chan->qh->ping_state = 1;
+ }
+
+ /*
+ * Always halt and release the host channel to make it available for
+ * more transfers. There may still be more phases for a control
+ * transfer or more data packets for a bulk transfer at this point,
+ * but the host channel is still halted. A channel will be reassigned
+ * to the transfer when the non-periodic schedule is processed after
+ * the channel is released. This allows transactions to be queued
+ * properly via dwc2_hcd_queue_transactions, which also enables the
+ * Tx FIFO Empty interrupt if necessary.
+ */
+ if (chan->ep_is_in) {
+ /*
+ * IN transfers in Slave mode require an explicit disable to
+ * halt the channel. (In DMA mode, this call simply releases
+ * the channel.)
+ */
+ dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+ } else {
+ /*
+ * The channel is automatically disabled by the core for OUT
+ * transfers in Slave mode
+ */
+ dwc2_release_channel(hsotg, chan, qtd, halt_status);
+ }
+}
+
+/*
+ * Performs common cleanup for periodic transfers after a Transfer Complete
+ * interrupt. This function should be called after any endpoint type specific
+ * handling is finished to release the host channel.
+ */
+static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+
+ qtd->error_count = 0;
+
+ if (!chan->ep_is_in || (hctsiz & TSIZ_PKTCNT_MASK) == 0)
+ /* Core halts channel in these cases */
+ dwc2_release_channel(hsotg, chan, qtd, halt_status);
+ else
+ /* Flush any outstanding requests from the Tx queue */
+ dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+}
+
+static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+ u32 len;
+
+ if (!qtd->urb)
+ return 0;
+
+ frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
+ len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd,
+ DWC2_HC_XFER_COMPLETE, NULL);
+ if (!len) {
+ qtd->complete_split = 0;
+ qtd->isoc_split_offset = 0;
+ return 0;
+ }
+
+ frame_desc->actual_length += len;
+
+ if (chan->align_buf && len) {
+ dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma,
+ qtd->urb->length, DMA_FROM_DEVICE);
+ memcpy(qtd->urb->buf + frame_desc->offset +
+ qtd->isoc_split_offset, chan->qh->dw_align_buf, len);
+ dma_sync_single_for_device(hsotg->dev, qtd->urb->dma,
+ qtd->urb->length, DMA_FROM_DEVICE);
+ }
+
+ qtd->isoc_split_offset += len;
+
+ if (frame_desc->actual_length >= frame_desc->length) {
+ frame_desc->status = 0;
+ qtd->isoc_frame_index++;
+ qtd->complete_split = 0;
+ qtd->isoc_split_offset = 0;
+ }
+
+ if (qtd->isoc_frame_index == qtd->urb->packet_count) {
+ dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, 0);
+ dwc2_release_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_URB_COMPLETE);
+ } else {
+ dwc2_release_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_NO_HALT_STATUS);
+ }
+
+ return 1; /* Indicates that channel released */
+}
+
+/*
+ * Handles a host channel Transfer Complete interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+ enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE;
+ int urb_xfer_done;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev,
+ "--Host Channel %d Interrupt: Transfer Complete--\n",
+ chnum);
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status);
+ if (pipe_type == USB_ENDPOINT_XFER_ISOC)
+ /* Do not disable the interrupt, just clear it */
+ return;
+ goto handle_xfercomp_done;
+ }
+
+ /* Handle xfer complete on CSPLIT */
+ if (chan->qh->do_split) {
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in &&
+ hsotg->core_params->dma_enable > 0) {
+ if (qtd->complete_split &&
+ dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum,
+ qtd))
+ goto handle_xfercomp_done;
+ } else {
+ qtd->complete_split = 0;
+ }
+ }
+
+ if (!urb)
+ goto handle_xfercomp_done;
+
+ /* Update the QTD and URB states */
+ switch (pipe_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ switch (qtd->control_phase) {
+ case DWC2_CONTROL_SETUP:
+ if (urb->length > 0)
+ qtd->control_phase = DWC2_CONTROL_DATA;
+ else
+ qtd->control_phase = DWC2_CONTROL_STATUS;
+ dev_vdbg(hsotg->dev,
+ " Control setup transaction done\n");
+ halt_status = DWC2_HC_XFER_COMPLETE;
+ break;
+ case DWC2_CONTROL_DATA:
+ urb_xfer_done = dwc2_update_urb_state(hsotg, chan,
+ chnum, urb, qtd);
+ if (urb_xfer_done) {
+ qtd->control_phase = DWC2_CONTROL_STATUS;
+ dev_vdbg(hsotg->dev,
+ " Control data transfer done\n");
+ } else {
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum,
+ qtd);
+ }
+ halt_status = DWC2_HC_XFER_COMPLETE;
+ break;
+ case DWC2_CONTROL_STATUS:
+ dev_vdbg(hsotg->dev, " Control transfer complete\n");
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ halt_status = DWC2_HC_XFER_URB_COMPLETE;
+ break;
+ }
+
+ dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
+ halt_status);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ dev_vdbg(hsotg->dev, " Bulk transfer complete\n");
+ urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
+ qtd);
+ if (urb_xfer_done) {
+ dwc2_host_complete(hsotg, urb->priv, urb, urb->status);
+ halt_status = DWC2_HC_XFER_URB_COMPLETE;
+ } else {
+ halt_status = DWC2_HC_XFER_COMPLETE;
+ }
+
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+ dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd,
+ halt_status);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ dev_vdbg(hsotg->dev, " Interrupt transfer complete\n");
+ urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb,
+ qtd);
+
+ /*
+ * Interrupt URB is done on the first transfer complete
+ * interrupt
+ */
+ if (urb_xfer_done) {
+ dwc2_host_complete(hsotg, urb->priv, urb,
+ urb->status);
+ halt_status = DWC2_HC_XFER_URB_COMPLETE;
+ } else {
+ halt_status = DWC2_HC_XFER_COMPLETE;
+ }
+
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+ dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
+ halt_status);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (dbg_perio())
+ dev_vdbg(hsotg->dev, " Isochronous transfer complete\n");
+ if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL)
+ halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
+ chnum, qtd, DWC2_HC_XFER_COMPLETE);
+ dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd,
+ halt_status);
+ break;
+ }
+
+handle_xfercomp_done:
+ disable_hc_int(hsotg, chnum, HCINTMSK_XFERCOMPL);
+}
+
+/*
+ * Handles a host channel STALL interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ int pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+
+ dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n",
+ chnum);
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ DWC2_HC_XFER_STALL);
+ goto handle_stall_done;
+ }
+
+ if (!urb)
+ goto handle_stall_halt;
+
+ if (pipe_type == USB_ENDPOINT_XFER_CONTROL)
+ dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+
+ if (pipe_type == USB_ENDPOINT_XFER_BULK ||
+ pipe_type == USB_ENDPOINT_XFER_INT) {
+ dwc2_host_complete(hsotg, urb->priv, urb, -EPIPE);
+ /*
+ * USB protocol requires resetting the data toggle for bulk
+ * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
+ * setup command is issued to the endpoint. Anticipate the
+ * CLEAR_FEATURE command since a STALL has occurred and reset
+ * the data toggle now.
+ */
+ chan->qh->data_toggle = 0;
+ }
+
+handle_stall_halt:
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_STALL);
+
+handle_stall_done:
+ disable_hc_int(hsotg, chnum, HCINTMSK_STALL);
+}
+
+/*
+ * Updates the state of the URB when a transfer has been stopped due to an
+ * abnormal condition before the transfer completes. Modifies the
+ * actual_length field of the URB to reflect the number of bytes that have
+ * actually been transferred via the host channel.
+ */
+static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_hcd_urb *urb,
+ struct dwc2_qtd *qtd,
+ enum dwc2_halt_status halt_status)
+{
+ u32 xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum,
+ qtd, halt_status, NULL);
+ u32 hctsiz;
+
+ if (urb->actual_length + xfer_length > urb->length) {
+ dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__);
+ xfer_length = urb->length - urb->actual_length;
+ }
+
+ /* Non DWORD-aligned buffer case handling */
+ if (chan->align_buf && xfer_length && chan->ep_is_in) {
+ dev_dbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__);
+ dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length,
+ DMA_FROM_DEVICE);
+ memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf,
+ xfer_length);
+ dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length,
+ DMA_FROM_DEVICE);
+ }
+
+ urb->actual_length += xfer_length;
+
+ hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+ dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
+ __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
+ dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
+ chan->start_pkt_count);
+ dev_vdbg(hsotg->dev, " hctsiz.pktcnt %d\n",
+ hctsiz >> TSIZ_PKTCNT_SHIFT &
+ TSIZ_PKTCNT_MASK >> TSIZ_PKTCNT_SHIFT);
+ dev_vdbg(hsotg->dev, " chan->max_packet %d\n", chan->max_packet);
+ dev_vdbg(hsotg->dev, " bytes_transferred %d\n",
+ xfer_length);
+ dev_vdbg(hsotg->dev, " urb->actual_length %d\n",
+ urb->actual_length);
+ dev_vdbg(hsotg->dev, " urb->transfer_buffer_length %d\n",
+ urb->length);
+}
+
+/*
+ * Handles a host channel NAK interrupt. This handler may be called in either
+ * DMA mode or Slave mode.
+ */
+static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n",
+ chnum);
+
+ /*
+ * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+ * interrupt. Re-start the SSPLIT transfer.
+ */
+ if (chan->do_split) {
+ if (chan->complete_split)
+ qtd->error_count = 0;
+ qtd->complete_split = 0;
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+ goto handle_nak_done;
+ }
+
+ switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ if (hsotg->core_params->dma_enable > 0 && chan->ep_is_in) {
+ /*
+ * NAK interrupts are enabled on bulk/control IN
+ * transfers in DMA mode for the sole purpose of
+ * resetting the error count after a transaction error
+ * occurs. The core will continue transferring data.
+ */
+ qtd->error_count = 0;
+ break;
+ }
+
+ /*
+ * NAK interrupts normally occur during OUT transfers in DMA
+ * or Slave mode. For IN transfers, more requests will be
+ * queued as request queue space is available.
+ */
+ qtd->error_count = 0;
+
+ if (!chan->qh->ping_state) {
+ dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
+ qtd, DWC2_HC_XFER_NAK);
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+
+ if (chan->speed == USB_SPEED_HIGH)
+ chan->qh->ping_state = 1;
+ }
+
+ /*
+ * Halt the channel so the transfer can be re-started from
+ * the appropriate point or the PING protocol will
+ * start/continue
+ */
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ qtd->error_count = 0;
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* Should never get called for isochronous transfers */
+ dev_err(hsotg->dev, "NACK interrupt for ISOC transfer\n");
+ break;
+ }
+
+handle_nak_done:
+ disable_hc_int(hsotg, chnum, HCINTMSK_NAK);
+}
+
+/*
+ * Handles a host channel ACK interrupt. This interrupt is enabled when
+ * performing the PING protocol in Slave mode, when errors occur during
+ * either Slave mode or DMA mode, and during Start Split transactions.
+ */
+static void dwc2_hc_ack_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ struct dwc2_hcd_iso_packet_desc *frame_desc;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: ACK Received--\n",
+ chnum);
+
+ if (chan->do_split) {
+ /* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */
+ if (!chan->ep_is_in &&
+ chan->data_pid_start != DWC2_HC_PID_SETUP)
+ qtd->ssplit_out_xfer_count = chan->xfer_len;
+
+ if (chan->ep_type != USB_ENDPOINT_XFER_ISOC || chan->ep_is_in) {
+ qtd->complete_split = 1;
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
+ } else {
+ /* ISOC OUT */
+ switch (chan->xact_pos) {
+ case DWC2_HCSPLT_XACTPOS_ALL:
+ break;
+ case DWC2_HCSPLT_XACTPOS_END:
+ qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
+ qtd->isoc_split_offset = 0;
+ break;
+ case DWC2_HCSPLT_XACTPOS_BEGIN:
+ case DWC2_HCSPLT_XACTPOS_MID:
+ /*
+ * For BEGIN or MID, calculate the length for
+ * the next microframe to determine the correct
+ * SSPLIT token, either MID or END
+ */
+ frame_desc = &qtd->urb->iso_descs[
+ qtd->isoc_frame_index];
+ qtd->isoc_split_offset += 188;
+
+ if (frame_desc->length - qtd->isoc_split_offset
+ <= 188)
+ qtd->isoc_split_pos =
+ DWC2_HCSPLT_XACTPOS_END;
+ else
+ qtd->isoc_split_pos =
+ DWC2_HCSPLT_XACTPOS_MID;
+ break;
+ }
+ }
+ } else {
+ qtd->error_count = 0;
+
+ if (chan->qh->ping_state) {
+ chan->qh->ping_state = 0;
+ /*
+ * Halt the channel so the transfer can be re-started
+ * from the appropriate point. This only happens in
+ * Slave mode. In DMA mode, the ping_state is cleared
+ * when the transfer is started because the core
+ * automatically executes the PING, then the transfer.
+ */
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK);
+ }
+ }
+
+ /*
+ * If the ACK occurred when _not_ in the PING state, let the channel
+ * continue transferring data after clearing the error count
+ */
+ disable_hc_int(hsotg, chnum, HCINTMSK_ACK);
+}
+
+/*
+ * Handles a host channel NYET interrupt. This interrupt should only occur on
+ * Bulk and Control OUT endpoints and for complete split transactions. If a
+ * NYET occurs at the same time as a Transfer Complete interrupt, it is
+ * handled in the xfercomp interrupt handler, not here. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NYET Received--\n",
+ chnum);
+
+ /*
+ * NYET on CSPLIT
+ * re-do the CSPLIT immediately on non-periodic
+ */
+ if (chan->do_split && chan->complete_split) {
+ if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC &&
+ hsotg->core_params->dma_enable > 0) {
+ qtd->complete_split = 0;
+ qtd->isoc_split_offset = 0;
+ if (qtd->urb &&
+ ++qtd->isoc_frame_index == qtd->urb->packet_count) {
+ dwc2_host_complete(hsotg, qtd->urb->priv,
+ qtd->urb, 0);
+ dwc2_release_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_URB_COMPLETE);
+ } else {
+ dwc2_release_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_NO_HALT_STATUS);
+ }
+ goto handle_nyet_done;
+ }
+
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ int frnum = dwc2_hcd_get_frame_number(hsotg);
+
+ if (dwc2_full_frame_num(frnum) !=
+ dwc2_full_frame_num(chan->qh->sched_frame)) {
+ /*
+ * No longer in the same full speed frame.
+ * Treat this as a transaction error.
+ */
+#if 0
+ /*
+ * Todo: Fix system performance so this can
+ * be treated as an error. Right now complete
+ * splits cannot be scheduled precisely enough
+ * due to other system activity, so this error
+ * occurs regularly in Slave mode.
+ */
+ qtd->error_count++;
+#endif
+ qtd->complete_split = 0;
+ dwc2_halt_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_XACT_ERR);
+ /* Todo: add support for isoc release */
+ goto handle_nyet_done;
+ }
+ }
+
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
+ goto handle_nyet_done;
+ }
+
+ chan->qh->ping_state = 1;
+ qtd->error_count = 0;
+
+ dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd,
+ DWC2_HC_XFER_NYET);
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+
+ /*
+ * Halt the channel and re-start the transfer so the PING protocol
+ * will start
+ */
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET);
+
+handle_nyet_done:
+ disable_hc_int(hsotg, chnum, HCINTMSK_NYET);
+}
+
+/*
+ * Handles a host channel babble interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n",
+ chnum);
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ DWC2_HC_XFER_BABBLE_ERR);
+ goto handle_babble_done;
+ }
+
+ if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) {
+ if (qtd->urb)
+ dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
+ -EOVERFLOW);
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR);
+ } else {
+ enum dwc2_halt_status halt_status;
+
+ halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
+ qtd, DWC2_HC_XFER_BABBLE_ERR);
+ dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+ }
+
+handle_babble_done:
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+ disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR);
+}
+
+/*
+ * Handles a host channel AHB error interrupt. This handler is only called in
+ * DMA mode.
+ */
+static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ char *pipetype, *speed;
+ u32 hcchar;
+ u32 hcsplt;
+ u32 hctsiz;
+ u32 hc_dma;
+
+ dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: AHB Error--\n",
+ chnum);
+
+ if (!urb)
+ goto handle_ahberr_halt;
+
+ hcchar = readl(hsotg->regs + HCCHAR(chnum));
+ hcsplt = readl(hsotg->regs + HCSPLT(chnum));
+ hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+ hc_dma = readl(hsotg->regs + HCDMA(chnum));
+
+ dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
+ dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
+ dev_err(hsotg->dev, " hctsiz 0x%08x, hc_dma 0x%08x\n", hctsiz, hc_dma);
+ dev_err(hsotg->dev, " Device address: %d\n",
+ dwc2_hcd_get_dev_addr(&urb->pipe_info));
+ dev_err(hsotg->dev, " Endpoint: %d, %s\n",
+ dwc2_hcd_get_ep_num(&urb->pipe_info),
+ dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+
+ switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ pipetype = "CONTROL";
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ pipetype = "BULK";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ pipetype = "INTERRUPT";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ pipetype = "ISOCHRONOUS";
+ break;
+ default:
+ pipetype = "UNKNOWN";
+ break;
+ }
+
+ dev_err(hsotg->dev, " Endpoint type: %s\n", pipetype);
+
+ switch (chan->speed) {
+ case USB_SPEED_HIGH:
+ speed = "HIGH";
+ break;
+ case USB_SPEED_FULL:
+ speed = "FULL";
+ break;
+ case USB_SPEED_LOW:
+ speed = "LOW";
+ break;
+ default:
+ speed = "UNKNOWN";
+ break;
+ }
+
+ dev_err(hsotg->dev, " Speed: %s\n", speed);
+
+ dev_err(hsotg->dev, " Max packet size: %d\n",
+ dwc2_hcd_get_mps(&urb->pipe_info));
+ dev_err(hsotg->dev, " Data buffer length: %d\n", urb->length);
+ dev_err(hsotg->dev, " Transfer buffer: %p, Transfer DMA: %08lx\n",
+ urb->buf, (unsigned long)urb->dma);
+ dev_err(hsotg->dev, " Setup buffer: %p, Setup DMA: %08lx\n",
+ urb->setup_packet, (unsigned long)urb->setup_dma);
+ dev_err(hsotg->dev, " Interval: %d\n", urb->interval);
+
+ /* Core halts the channel for Descriptor DMA mode */
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ DWC2_HC_XFER_AHB_ERR);
+ goto handle_ahberr_done;
+ }
+
+ dwc2_host_complete(hsotg, urb->priv, urb, -EIO);
+
+handle_ahberr_halt:
+ /*
+ * Force a channel halt. Don't call dwc2_halt_channel because that won't
+ * write to the HCCHARn register in DMA mode to force the halt.
+ */
+ dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR);
+
+handle_ahberr_done:
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+ disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR);
+}
+
+/*
+ * Handles a host channel transaction error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ dev_dbg(hsotg->dev,
+ "--Host Channel %d Interrupt: Transaction Error--\n", chnum);
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ DWC2_HC_XFER_XACT_ERR);
+ goto handle_xacterr_done;
+ }
+
+ switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ qtd->error_count++;
+ if (!chan->qh->ping_state) {
+
+ dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb,
+ qtd, DWC2_HC_XFER_XACT_ERR);
+ dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd);
+ if (!chan->ep_is_in && chan->speed == USB_SPEED_HIGH)
+ chan->qh->ping_state = 1;
+ }
+
+ /*
+ * Halt the channel so the transfer can be re-started from
+ * the appropriate point or the PING protocol will start
+ */
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ qtd->error_count++;
+ if (chan->do_split && chan->complete_split)
+ qtd->complete_split = 0;
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ {
+ enum dwc2_halt_status halt_status;
+
+ halt_status = dwc2_update_isoc_urb_state(hsotg, chan,
+ chnum, qtd, DWC2_HC_XFER_XACT_ERR);
+ dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+ }
+ break;
+ }
+
+handle_xacterr_done:
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+ disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR);
+}
+
+/*
+ * Handles a host channel frame overrun interrupt. This handler may be called
+ * in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ enum dwc2_halt_status halt_status;
+
+ if (dbg_hc(chan))
+ dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n",
+ chnum);
+
+ switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_FRAME_OVERRUN);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum,
+ qtd, DWC2_HC_XFER_FRAME_OVERRUN);
+ dwc2_halt_channel(hsotg, chan, qtd, halt_status);
+ break;
+ }
+
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+ disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN);
+}
+
+/*
+ * Handles a host channel data toggle error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static void dwc2_hc_datatglerr_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ dev_dbg(hsotg->dev,
+ "--Host Channel %d Interrupt: Data Toggle Error--\n", chnum);
+
+ if (chan->ep_is_in)
+ qtd->error_count = 0;
+ else
+ dev_err(hsotg->dev,
+ "Data Toggle Error on OUT transfer, channel %d\n",
+ chnum);
+
+ dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
+ disable_hc_int(hsotg, chnum, HCINTMSK_DATATGLERR);
+}
+
+/*
+ * For debug only. It checks that a valid halt status is set and that
+ * HCCHARn.chdis is clear. If there's a problem, corrective action is
+ * taken and a warning is issued.
+ *
+ * Return: true if halt status is ok, false otherwise
+ */
+static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+#ifdef DEBUG
+ u32 hcchar;
+ u32 hctsiz;
+ u32 hcintmsk;
+ u32 hcsplt;
+
+ if (chan->halt_status == DWC2_HC_XFER_NO_HALT_STATUS) {
+ /*
+ * This code is here only as a check. This condition should
+ * never happen. Ignore the halt if it does occur.
+ */
+ hcchar = readl(hsotg->regs + HCCHAR(chnum));
+ hctsiz = readl(hsotg->regs + HCTSIZ(chnum));
+ hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+ hcsplt = readl(hsotg->regs + HCSPLT(chnum));
+ dev_dbg(hsotg->dev,
+ "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
+ __func__);
+ dev_dbg(hsotg->dev,
+ "channel %d, hcchar 0x%08x, hctsiz 0x%08x,\n",
+ chnum, hcchar, hctsiz);
+ dev_dbg(hsotg->dev,
+ "hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n",
+ chan->hcint, hcintmsk, hcsplt);
+ if (qtd)
+ dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
+ qtd->complete_split);
+ dev_warn(hsotg->dev,
+ "%s: no halt status, channel %d, ignoring interrupt\n",
+ __func__, chnum);
+ return false;
+ }
+
+ /*
+ * This code is here only as a check. hcchar.chdis should never be set
+ * when the halt interrupt occurs. Halt the channel again if it does
+ * occur.
+ */
+ hcchar = readl(hsotg->regs + HCCHAR(chnum));
+ if (hcchar & HCCHAR_CHDIS) {
+ dev_warn(hsotg->dev,
+ "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
+ __func__, hcchar);
+ chan->halt_pending = 0;
+ dwc2_halt_channel(hsotg, chan, qtd, chan->halt_status);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+/*
+ * Handles a host Channel Halted interrupt in DMA mode. This handler
+ * determines the reason the channel halted and proceeds accordingly.
+ */
+static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ u32 hcintmsk;
+ int out_nak_enh = 0;
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev,
+ "--Host Channel %d Interrupt: DMA Channel Halted--\n",
+ chnum);
+
+ /*
+ * For core with OUT NAK enhancement, the flow for high-speed
+ * CONTROL/BULK OUT is handled a little differently
+ */
+ if (hsotg->snpsid >= DWC2_CORE_REV_2_71a) {
+ if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in &&
+ (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
+ chan->ep_type == USB_ENDPOINT_XFER_BULK)) {
+ out_nak_enh = 1;
+ }
+ }
+
+ if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE ||
+ (chan->halt_status == DWC2_HC_XFER_AHB_ERR &&
+ hsotg->core_params->dma_desc_enable <= 0)) {
+ if (hsotg->core_params->dma_desc_enable > 0)
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ chan->halt_status);
+ else
+ /*
+ * Just release the channel. A dequeue can happen on a
+ * transfer timeout. In the case of an AHB Error, the
+ * channel was forced to halt because there's no way to
+ * gracefully recover.
+ */
+ dwc2_release_channel(hsotg, chan, qtd,
+ chan->halt_status);
+ return;
+ }
+
+ hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+
+ if (chan->hcint & HCINTMSK_XFERCOMPL) {
+ /*
+ * Todo: This is here because of a possible hardware bug. Spec
+ * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT
+ * interrupt w/ACK bit set should occur, but I only see the
+ * XFERCOMP bit, even with it masked out. This is a workaround
+ * for that behavior. Should fix this when hardware is fixed.
+ */
+ if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && !chan->ep_is_in)
+ dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+ dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
+ } else if (chan->hcint & HCINTMSK_STALL) {
+ dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
+ } else if ((chan->hcint & HCINTMSK_XACTERR) &&
+ hsotg->core_params->dma_desc_enable <= 0) {
+ if (out_nak_enh) {
+ if (chan->hcint &
+ (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) {
+ dev_vdbg(hsotg->dev,
+ "XactErr with NYET/NAK/ACK\n");
+ qtd->error_count = 0;
+ } else {
+ dev_vdbg(hsotg->dev,
+ "XactErr without NYET/NAK/ACK\n");
+ }
+ }
+
+ /*
+ * Must handle xacterr before nak or ack. Could get a xacterr
+ * at the same time as either of these on a BULK/CONTROL OUT
+ * that started with a PING. The xacterr takes precedence.
+ */
+ dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+ } else if ((chan->hcint & HCINTMSK_XCS_XACT) &&
+ hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+ } else if ((chan->hcint & HCINTMSK_AHBERR) &&
+ hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
+ } else if (chan->hcint & HCINTMSK_BBLERR) {
+ dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
+ } else if (chan->hcint & HCINTMSK_FRMOVRUN) {
+ dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
+ } else if (!out_nak_enh) {
+ if (chan->hcint & HCINTMSK_NYET) {
+ /*
+ * Must handle nyet before nak or ack. Could get a nyet
+ * at the same time as either of those on a BULK/CONTROL
+ * OUT that started with a PING. The nyet takes
+ * precedence.
+ */
+ dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
+ } else if ((chan->hcint & HCINTMSK_NAK) &&
+ !(hcintmsk & HCINTMSK_NAK)) {
+ /*
+ * If nak is not masked, it's because a non-split IN
+ * transfer is in an error state. In that case, the nak
+ * is handled by the nak interrupt handler, not here.
+ * Handle nak here for BULK/CONTROL OUT transfers, which
+ * halt on a NAK to allow rewinding the buffer pointer.
+ */
+ dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
+ } else if ((chan->hcint & HCINTMSK_ACK) &&
+ !(hcintmsk & HCINTMSK_ACK)) {
+ /*
+ * If ack is not masked, it's because a non-split IN
+ * transfer is in an error state. In that case, the ack
+ * is handled by the ack interrupt handler, not here.
+ * Handle ack here for split transfers. Start splits
+ * halt on ACK.
+ */
+ dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+ } else {
+ if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
+ chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ /*
+ * A periodic transfer halted with no other
+ * channel interrupts set. Assume it was halted
+ * by the core because it could not be completed
+ * in its scheduled (micro)frame.
+ */
+ dev_dbg(hsotg->dev,
+ "%s: Halt channel %d (assume incomplete periodic transfer)\n",
+ __func__, chnum);
+ dwc2_halt_channel(hsotg, chan, qtd,
+ DWC2_HC_XFER_PERIODIC_INCOMPLETE);
+ } else {
+ dev_err(hsotg->dev,
+ "%s: Channel %d - ChHltd set, but reason is unknown\n",
+ __func__, chnum);
+ dev_err(hsotg->dev,
+ "hcint 0x%08x, intsts 0x%08x\n",
+ chan->hcint,
+ readl(hsotg->regs + GINTSTS));
+ }
+ }
+ } else {
+ dev_info(hsotg->dev,
+ "NYET/NAK/ACK/other in non-error case, 0x%08x\n",
+ chan->hcint);
+ }
+}
+
+/*
+ * Handles a host channel Channel Halted interrupt
+ *
+ * In slave mode, this handler is called only when the driver specifically
+ * requests a halt. This occurs during handling other host channel interrupts
+ * (e.g. nak, xacterr, stall, nyet, etc.).
+ *
+ * In DMA mode, this is the interrupt that occurs when the core has finished
+ * processing a transfer on a channel. Other host channel interrupts (except
+ * ahberr) are disabled in DMA mode.
+ */
+static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg,
+ struct dwc2_host_chan *chan, int chnum,
+ struct dwc2_qtd *qtd)
+{
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n",
+ chnum);
+
+ if (hsotg->core_params->dma_enable > 0) {
+ dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd);
+ } else {
+ if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd))
+ return;
+ dwc2_release_channel(hsotg, chan, qtd, chan->halt_status);
+ }
+}
+
+/* Handles interrupt for a specific Host Channel */
+static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
+{
+ struct dwc2_qtd *qtd;
+ struct dwc2_host_chan *chan;
+ u32 hcint, hcintmsk;
+
+ chan = hsotg->hc_ptr_array[chnum];
+
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev, "--Host Channel Interrupt--, Channel %d\n",
+ chnum);
+
+ hcint = readl(hsotg->regs + HCINT(chnum));
+ hcintmsk = readl(hsotg->regs + HCINTMSK(chnum));
+ if (dbg_hc(chan))
+ dev_vdbg(hsotg->dev,
+ " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+ hcint, hcintmsk, hcint & hcintmsk);
+
+ if (!chan) {
+ dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
+ writel(hcint, hsotg->regs + HCINT(chnum));
+ return;
+ }
+
+ writel(hcint, hsotg->regs + HCINT(chnum));
+ chan->hcint = hcint;
+ hcint &= hcintmsk;
+
+ /*
+ * If the channel was halted due to a dequeue, the qtd list might
+ * be empty or at least the first entry will not be the active qtd.
+ * In this case, take a shortcut and just release the channel.
+ */
+ if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+ /*
+ * If the channel was halted, this should be the only
+ * interrupt unmasked
+ */
+ WARN_ON(hcint != HCINTMSK_CHHLTD);
+ if (hsotg->core_params->dma_desc_enable > 0)
+ dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+ chan->halt_status);
+ else
+ dwc2_release_channel(hsotg, chan, NULL,
+ chan->halt_status);
+ return;
+ }
+
+ if (list_empty(&chan->qh->qtd_list)) {
+ /*
+ * TODO: Will this ever happen with the
+ * DWC2_HC_XFER_URB_DEQUEUE handling above?
+ */
+ dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n",
+ chnum);
+ dev_dbg(hsotg->dev,
+ " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+ chan->hcint, hcintmsk, hcint);
+ chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS;
+ disable_hc_int(hsotg, chnum, HCINTMSK_CHHLTD);
+ chan->hcint = 0;
+ return;
+ }
+
+ qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd,
+ qtd_list_entry);
+
+ if (hsotg->core_params->dma_enable <= 0) {
+ if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD)
+ hcint &= ~HCINTMSK_CHHLTD;
+ }
+
+ if (hcint & HCINTMSK_XFERCOMPL) {
+ dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd);
+ /*
+ * If NYET occurred at same time as Xfer Complete, the NYET is
+ * handled by the Xfer Complete interrupt handler. Don't want
+ * to call the NYET interrupt handler in this case.
+ */
+ hcint &= ~HCINTMSK_NYET;
+ }
+ if (hcint & HCINTMSK_CHHLTD)
+ dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_AHBERR)
+ dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_STALL)
+ dwc2_hc_stall_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_NAK)
+ dwc2_hc_nak_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_ACK)
+ dwc2_hc_ack_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_NYET)
+ dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_XACTERR)
+ dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_BBLERR)
+ dwc2_hc_babble_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_FRMOVRUN)
+ dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd);
+ if (hcint & HCINTMSK_DATATGLERR)
+ dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd);
+
+ chan->hcint = 0;
+}
+
+/*
+ * This interrupt indicates that one or more host channels has a pending
+ * interrupt. There are multiple conditions that can cause each host channel
+ * interrupt. This function determines which conditions have occurred for each
+ * host channel interrupt and handles them appropriately.
+ */
+static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 haint;
+ int i;
+
+ haint = readl(hsotg->regs + HAINT);
+ if (dbg_perio()) {
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint);
+ }
+
+ for (i = 0; i < hsotg->core_params->host_channels; i++) {
+ if (haint & (1 << i))
+ dwc2_hc_n_intr(hsotg, i);
+ }
+}
+
+/* This function handles interrupts for the HCD */
+int dwc2_hcd_intr(struct dwc2_hsotg *hsotg)
+{
+ u32 gintsts, dbg_gintsts;
+ int retval = 0;
+
+ if (dwc2_check_core_status(hsotg) < 0) {
+ dev_warn(hsotg->dev, "Controller is disconnected\n");
+ return 0;
+ }
+
+ spin_lock(&hsotg->lock);
+
+ /* Check if HOST Mode */
+ if (dwc2_is_host_mode(hsotg)) {
+ gintsts = dwc2_read_core_intr(hsotg);
+ if (!gintsts) {
+ spin_unlock(&hsotg->lock);
+ return 0;
+ }
+
+ retval = 1;
+
+ dbg_gintsts = gintsts;
+#ifndef DEBUG_SOF
+ dbg_gintsts &= ~GINTSTS_SOF;
+#endif
+ if (!dbg_perio())
+ dbg_gintsts &= ~(GINTSTS_HCHINT | GINTSTS_RXFLVL |
+ GINTSTS_PTXFEMP);
+
+ /* Only print if there are any non-suppressed interrupts left */
+ if (dbg_gintsts)
+ dev_vdbg(hsotg->dev,
+ "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
+ gintsts);
+
+ if (gintsts & GINTSTS_SOF)
+ dwc2_sof_intr(hsotg);
+ if (gintsts & GINTSTS_RXFLVL)
+ dwc2_rx_fifo_level_intr(hsotg);
+ if (gintsts & GINTSTS_NPTXFEMP)
+ dwc2_np_tx_fifo_empty_intr(hsotg);
+ if (gintsts & GINTSTS_I2CINT)
+ /* Todo: Implement i2cintr handler */
+ writel(GINTSTS_I2CINT, hsotg->regs + GINTSTS);
+ if (gintsts & GINTSTS_PRTINT)
+ dwc2_port_intr(hsotg);
+ if (gintsts & GINTSTS_HCHINT)
+ dwc2_hc_intr(hsotg);
+ if (gintsts & GINTSTS_PTXFEMP)
+ dwc2_perio_tx_fifo_empty_intr(hsotg);
+
+ if (dbg_gintsts) {
+ dev_vdbg(hsotg->dev,
+ "DWC OTG HCD Finished Servicing Interrupts\n");
+ dev_vdbg(hsotg->dev,
+ "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
+ readl(hsotg->regs + GINTSTS),
+ readl(hsotg->regs + GINTMSK));
+ }
+ }
+
+ spin_unlock(&hsotg->lock);
+
+ return retval;
+}
diff --git a/drivers/staging/dwc2/hcd_queue.c b/drivers/staging/dwc2/hcd_queue.c
new file mode 100644
index 000000000000..b36f783dd3e9
--- /dev/null
+++ b/drivers/staging/dwc2/hcd_queue.c
@@ -0,0 +1,677 @@
+/*
+ * hcd_queue.c - DesignWare HS OTG Controller host queuing routines
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains the functions to manage Queue Heads and Queue
+ * Transfer Descriptors for Host mode
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+/**
+ * dwc2_qh_init() - Initializes a QH structure
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to init
+ * @urb: Holds the information about the device/endpoint needed to initialize
+ * the QH
+ */
+#define SCHEDULE_SLOP 10
+static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ struct dwc2_hcd_urb *urb)
+{
+ int dev_speed, hub_addr, hub_port;
+ char *speed, *type;
+
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ /* Initialize QH */
+ qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info);
+ qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0;
+
+ qh->data_toggle = DWC2_HC_PID_DATA0;
+ qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info);
+ INIT_LIST_HEAD(&qh->qtd_list);
+ INIT_LIST_HEAD(&qh->qh_list_entry);
+
+ /* FS/LS Endpoint on HS Hub, NOT virtual root hub */
+ dev_speed = dwc2_host_get_speed(hsotg, urb->priv);
+
+ dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port);
+
+ if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) &&
+ hub_addr != 0 && hub_addr != 1) {
+ dev_vdbg(hsotg->dev,
+ "QH init: EP %d: TT found at hub addr %d, for port %d\n",
+ dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr,
+ hub_port);
+ qh->do_split = 1;
+ }
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
+ qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
+ /* Compute scheduling parameters once and save them */
+ u32 hprt, prtspd;
+
+ /* Todo: Account for split transfers in the bus time */
+ int bytecount =
+ dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp);
+
+ qh->usecs = NS_TO_US(usb_calc_bus_time(qh->do_split ?
+ USB_SPEED_HIGH : dev_speed, qh->ep_is_in,
+ qh->ep_type == USB_ENDPOINT_XFER_ISOC,
+ bytecount));
+ /* Start in a slightly future (micro)frame */
+ qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number,
+ SCHEDULE_SLOP);
+ qh->interval = urb->interval;
+#if 0
+ /* Increase interrupt polling rate for debugging */
+ if (qh->ep_type == USB_ENDPOINT_XFER_INT)
+ qh->interval = 8;
+#endif
+ hprt = readl(hsotg->regs + HPRT0);
+ prtspd = hprt & HPRT0_SPD_MASK;
+ if (prtspd == HPRT0_SPD_HIGH_SPEED &&
+ (dev_speed == USB_SPEED_LOW ||
+ dev_speed == USB_SPEED_FULL)) {
+ qh->interval *= 8;
+ qh->sched_frame |= 0x7;
+ qh->start_split_frame = qh->sched_frame;
+ }
+ dev_dbg(hsotg->dev, "interval=%d\n", qh->interval);
+ }
+
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n");
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh);
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n",
+ dwc2_hcd_get_dev_addr(&urb->pipe_info));
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n",
+ dwc2_hcd_get_ep_num(&urb->pipe_info),
+ dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT");
+
+ qh->dev_speed = dev_speed;
+
+ switch (dev_speed) {
+ case USB_SPEED_LOW:
+ speed = "low";
+ break;
+ case USB_SPEED_FULL:
+ speed = "full";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "high";
+ break;
+ default:
+ speed = "?";
+ break;
+ }
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed);
+
+ switch (qh->ep_type) {
+ case USB_ENDPOINT_XFER_ISOC:
+ type = "isochronous";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = "interrupt";
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ type = "control";
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = "bulk";
+ break;
+ default:
+ type = "?";
+ break;
+ }
+
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type);
+
+ if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n",
+ qh->usecs);
+ dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n",
+ qh->interval);
+ }
+}
+
+/**
+ * dwc2_hcd_qh_create() - Allocates and initializes a QH
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @urb: Holds the information about the device/endpoint needed
+ * to initialize the QH
+ * @atomic_alloc: Flag to do atomic allocation if needed
+ *
+ * Return: Pointer to the newly allocated QH, or NULL on error
+ */
+static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
+ struct dwc2_hcd_urb *urb,
+ gfp_t mem_flags)
+{
+ struct dwc2_qh *qh;
+
+ /* Allocate memory */
+ qh = kzalloc(sizeof(*qh), mem_flags);
+ if (!qh)
+ return NULL;
+
+ dwc2_qh_init(hsotg, qh, urb);
+
+ if (hsotg->core_params->dma_desc_enable > 0 &&
+ dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) {
+ dwc2_hcd_qh_free(hsotg, qh);
+ return NULL;
+ }
+
+ return qh;
+}
+
+/**
+ * dwc2_hcd_qh_free() - Frees the QH
+ *
+ * @hsotg: HCD instance
+ * @qh: The QH to free
+ *
+ * QH should already be removed from the list. QTD list should already be empty
+ * if called from URB Dequeue.
+ *
+ * Must NOT be called with interrupt disabled or spinlock held
+ */
+void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ u32 buf_size;
+
+ if (hsotg->core_params->dma_desc_enable > 0) {
+ dwc2_hcd_qh_free_ddma(hsotg, qh);
+ } else if (qh->dw_align_buf) {
+ if (qh->ep_type == USB_ENDPOINT_XFER_ISOC)
+ buf_size = 4096;
+ else
+ buf_size = hsotg->core_params->max_transfer_size;
+ dma_free_coherent(hsotg->dev, buf_size, qh->dw_align_buf,
+ qh->dw_align_buf_dma);
+ }
+
+ kfree(qh);
+}
+
+/**
+ * dwc2_periodic_channel_available() - Checks that a channel is available for a
+ * periodic transfer
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ *
+ * Return: 0 if successful, negative error code otherise
+ */
+static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg)
+{
+ /*
+ * Currently assuming that there is a dedicated host channnel for
+ * each periodic transaction plus at least one host channel for
+ * non-periodic transactions
+ */
+ int status;
+ int num_channels;
+
+ num_channels = hsotg->core_params->host_channels;
+ if (hsotg->periodic_channels + hsotg->non_periodic_channels <
+ num_channels
+ && hsotg->periodic_channels < num_channels - 1) {
+ status = 0;
+ } else {
+ dev_dbg(hsotg->dev,
+ "%s: Total channels: %d, Periodic: %d, "
+ "Non-periodic: %d\n", __func__, num_channels,
+ hsotg->periodic_channels, hsotg->non_periodic_channels);
+ status = -ENOSPC;
+ }
+
+ return status;
+}
+
+/**
+ * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth
+ * for the specified QH in the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH containing periodic bandwidth required
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * For simplicity, this calculation assumes that all the transfers in the
+ * periodic schedule may occur in the same (micro)frame
+ */
+static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ int status;
+ s16 max_claimed_usecs;
+
+ status = 0;
+
+ if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) {
+ /*
+ * High speed mode
+ * Max periodic usecs is 80% x 125 usec = 100 usec
+ */
+ max_claimed_usecs = 100 - qh->usecs;
+ } else {
+ /*
+ * Full speed mode
+ * Max periodic usecs is 90% x 1000 usec = 900 usec
+ */
+ max_claimed_usecs = 900 - qh->usecs;
+ }
+
+ if (hsotg->periodic_usecs > max_claimed_usecs) {
+ dev_err(hsotg->dev,
+ "%s: already claimed usecs %d, required usecs %d\n",
+ __func__, hsotg->periodic_usecs, qh->usecs);
+ status = -ENOSPC;
+ }
+
+ return status;
+}
+
+/**
+ * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a
+ * host channel is large enough to handle the maximum data transfer in a single
+ * (micro)frame for a periodic transfer
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for a periodic endpoint
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ u32 max_xfer_size;
+ u32 max_channel_xfer_size;
+ int status = 0;
+
+ max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp);
+ max_channel_xfer_size = hsotg->core_params->max_transfer_size;
+
+ if (max_xfer_size > max_channel_xfer_size) {
+ dev_err(hsotg->dev,
+ "%s: Periodic xfer length %d > max xfer length for channel %d\n",
+ __func__, max_xfer_size, max_channel_xfer_size);
+ status = -ENOSPC;
+ }
+
+ return status;
+}
+
+/**
+ * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in
+ * the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for the periodic transfer. The QH should already contain the
+ * scheduling information.
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ int status;
+
+ status = dwc2_periodic_channel_available(hsotg);
+ if (status) {
+ dev_dbg(hsotg->dev,
+ "%s: No host channel available for periodic transfer\n",
+ __func__);
+ return status;
+ }
+
+ status = dwc2_check_periodic_bandwidth(hsotg, qh);
+ if (status) {
+ dev_dbg(hsotg->dev,
+ "%s: Insufficient periodic bandwidth for periodic transfer\n",
+ __func__);
+ return status;
+ }
+
+ status = dwc2_check_max_xfer_size(hsotg, qh);
+ if (status) {
+ dev_dbg(hsotg->dev,
+ "%s: Channel max transfer size too small for periodic transfer\n",
+ __func__);
+ return status;
+ }
+
+ if (hsotg->core_params->dma_desc_enable > 0)
+ /* Don't rely on SOF and start in ready schedule */
+ list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready);
+ else
+ /* Always start in inactive schedule */
+ list_add_tail(&qh->qh_list_entry,
+ &hsotg->periodic_sched_inactive);
+
+ /* Reserve periodic channel */
+ hsotg->periodic_channels++;
+
+ /* Update claimed usecs per (micro)frame */
+ hsotg->periodic_usecs += qh->usecs;
+
+ return status;
+}
+
+/**
+ * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer
+ * from the periodic schedule
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: QH for the periodic transfer
+ */
+static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh)
+{
+ list_del_init(&qh->qh_list_entry);
+
+ /* Release periodic channel reservation */
+ hsotg->periodic_channels--;
+
+ /* Update claimed usecs per (micro)frame */
+ hsotg->periodic_usecs -= qh->usecs;
+}
+
+/**
+ * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic
+ * schedule if it is not already in the schedule. If the QH is already in
+ * the schedule, no action is taken.
+ *
+ * @hsotg: The HCD state structure for the DWC OTG controller
+ * @qh: The QH to add
+ *
+ * Return: 0 if successful, negative error code otherwise
+ */
+int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ int status = 0;
+ u32 intr_mask;
+
+ if (dbg_qh(qh))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (!list_empty(&qh->qh_list_entry))
+ /* QH already in a schedule */
+ return status;
+
+ /* Add the new QH to the appropriate schedule */
+ if (dwc2_qh_is_non_per(qh)) {
+ /* Always start in inactive schedule */
+ list_add_tail(&qh->qh_list_entry,
+ &hsotg->non_periodic_sched_inactive);
+ } else {
+ status = dwc2_schedule_periodic(hsotg, qh);
+ if (status == 0) {
+ if (!hsotg->periodic_qh_count) {
+ intr_mask = readl(hsotg->regs + GINTMSK);
+ intr_mask |= GINTSTS_SOF;
+ writel(intr_mask, hsotg->regs + GINTMSK);
+ }
+ hsotg->periodic_qh_count++;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic
+ * schedule. Memory is not freed.
+ *
+ * @hsotg: The HCD state structure
+ * @qh: QH to remove from schedule
+ */
+void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
+{
+ u32 intr_mask;
+
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (list_empty(&qh->qh_list_entry))
+ /* QH is not in a schedule */
+ return;
+
+ if (dwc2_qh_is_non_per(qh)) {
+ if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry)
+ hsotg->non_periodic_qh_ptr =
+ hsotg->non_periodic_qh_ptr->next;
+ list_del_init(&qh->qh_list_entry);
+ } else {
+ dwc2_deschedule_periodic(hsotg, qh);
+ hsotg->periodic_qh_count--;
+ if (!hsotg->periodic_qh_count) {
+ intr_mask = readl(hsotg->regs + GINTMSK);
+ intr_mask &= ~GINTSTS_SOF;
+ writel(intr_mask, hsotg->regs + GINTMSK);
+ }
+ }
+}
+
+/*
+ * Schedule the next continuing periodic split transfer
+ */
+static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg,
+ struct dwc2_qh *qh, u16 frame_number,
+ int sched_next_periodic_split)
+{
+ u16 incr;
+
+ if (sched_next_periodic_split) {
+ qh->sched_frame = frame_number;
+ incr = dwc2_frame_num_inc(qh->start_split_frame, 1);
+ if (dwc2_frame_num_le(frame_number, incr)) {
+ /*
+ * Allow one frame to elapse after start split
+ * microframe before scheduling complete split, but
+ * DON'T if we are doing the next start split in the
+ * same frame for an ISOC out
+ */
+ if (qh->ep_type != USB_ENDPOINT_XFER_ISOC ||
+ qh->ep_is_in != 0) {
+ qh->sched_frame =
+ dwc2_frame_num_inc(qh->sched_frame, 1);
+ }
+ }
+ } else {
+ qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame,
+ qh->interval);
+ if (dwc2_frame_num_le(qh->sched_frame, frame_number))
+ qh->sched_frame = frame_number;
+ qh->sched_frame |= 0x7;
+ qh->start_split_frame = qh->sched_frame;
+ }
+}
+
+/*
+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
+ * non-periodic schedule. The QH is added to the inactive non-periodic
+ * schedule if any QTDs are still attached to the QH.
+ *
+ * For periodic QHs, the QH is removed from the periodic queued schedule. If
+ * there are any QTDs still attached to the QH, the QH is added to either the
+ * periodic inactive schedule or the periodic ready schedule and its next
+ * scheduled frame is calculated. The QH is placed in the ready schedule if
+ * the scheduled frame has been reached already. Otherwise it's placed in the
+ * inactive schedule. If there are no QTDs attached to the QH, the QH is
+ * completely removed from the periodic schedule.
+ */
+void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
+ int sched_next_periodic_split)
+{
+ if (dbg_qh(qh))
+ dev_vdbg(hsotg->dev, "%s()\n", __func__);
+
+ if (dwc2_qh_is_non_per(qh)) {
+ dwc2_hcd_qh_unlink(hsotg, qh);
+ if (!list_empty(&qh->qtd_list))
+ /* Add back to inactive non-periodic schedule */
+ dwc2_hcd_qh_add(hsotg, qh);
+ } else {
+ u16 frame_number = dwc2_hcd_get_frame_number(hsotg);
+
+ if (qh->do_split) {
+ dwc2_sched_periodic_split(hsotg, qh, frame_number,
+ sched_next_periodic_split);
+ } else {
+ qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame,
+ qh->interval);
+ if (dwc2_frame_num_le(qh->sched_frame, frame_number))
+ qh->sched_frame = frame_number;
+ }
+
+ if (list_empty(&qh->qtd_list)) {
+ dwc2_hcd_qh_unlink(hsotg, qh);
+ } else {
+ /*
+ * Remove from periodic_sched_queued and move to
+ * appropriate queue
+ */
+ if (qh->sched_frame == frame_number)
+ list_move(&qh->qh_list_entry,
+ &hsotg->periodic_sched_ready);
+ else
+ list_move(&qh->qh_list_entry,
+ &hsotg->periodic_sched_inactive);
+ }
+ }
+}
+
+/**
+ * dwc2_hcd_qtd_init() - Initializes a QTD structure
+ *
+ * @qtd: The QTD to initialize
+ * @urb: The associated URB
+ */
+void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
+{
+ qtd->urb = urb;
+ if (dwc2_hcd_get_pipe_type(&urb->pipe_info) ==
+ USB_ENDPOINT_XFER_CONTROL) {
+ /*
+ * The only time the QTD data toggle is used is on the data
+ * phase of control transfers. This phase always starts with
+ * DATA1.
+ */
+ qtd->data_toggle = DWC2_HC_PID_DATA1;
+ qtd->control_phase = DWC2_CONTROL_SETUP;
+ }
+
+ /* Start split */
+ qtd->complete_split = 0;
+ qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL;
+ qtd->isoc_split_offset = 0;
+ qtd->in_process = 0;
+
+ /* Store the qtd ptr in the urb to reference the QTD */
+ urb->qtd = qtd;
+}
+
+/**
+ * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
+ *
+ * @hsotg: The DWC HCD structure
+ * @qtd: The QTD to add
+ * @qh: Out parameter to return queue head
+ * @atomic_alloc: Flag to do atomic alloc if needed
+ *
+ * Return: 0 if successful, negative error code otherwise
+ *
+ * Finds the correct QH to place the QTD into. If it does not find a QH, it
+ * will create a new QH. If the QH to which the QTD is added is not currently
+ * scheduled, it is placed into the proper schedule based on its EP type.
+ */
+int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
+ struct dwc2_qh **qh, gfp_t mem_flags)
+{
+ struct dwc2_hcd_urb *urb = qtd->urb;
+ unsigned long flags;
+ int allocated = 0;
+ int retval = 0;
+
+ /*
+ * Get the QH which holds the QTD-list to insert to. Create QH if it
+ * doesn't exist.
+ */
+ if (*qh == NULL) {
+ *qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags);
+ if (*qh == NULL)
+ return -ENOMEM;
+ allocated = 1;
+ }
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ retval = dwc2_hcd_qh_add(hsotg, *qh);
+ if (retval && allocated) {
+ struct dwc2_qtd *qtd2, *qtd2_tmp;
+ struct dwc2_qh *qh_tmp = *qh;
+
+ *qh = NULL;
+ dwc2_hcd_qh_unlink(hsotg, qh_tmp);
+
+ /* Free each QTD in the QH's QTD list */
+ list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list,
+ qtd_list_entry)
+ dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ dwc2_hcd_qh_free(hsotg, qh_tmp);
+ } else {
+ qtd->qh = *qh;
+ list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ }
+
+ return retval;
+}
diff --git a/drivers/staging/dwc2/hw.h b/drivers/staging/dwc2/hw.h
new file mode 100644
index 000000000000..382a1d74865d
--- /dev/null
+++ b/drivers/staging/dwc2/hw.h
@@ -0,0 +1,811 @@
+/*
+ * hw.h - DesignWare HS OTG Controller hardware definitions
+ *
+ * Copyright 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DWC2_HW_H__
+#define __DWC2_HW_H__
+
+#define HSOTG_REG(x) (x)
+
+#define GOTGCTL HSOTG_REG(0x000)
+#define GOTGCTL_CHIRPEN (1 << 27)
+#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
+#define GOTGCTL_MULT_VALID_BC_SHIFT 22
+#define GOTGCTL_OTGVER (1 << 20)
+#define GOTGCTL_BSESVLD (1 << 19)
+#define GOTGCTL_ASESVLD (1 << 18)
+#define GOTGCTL_DBNC_SHORT (1 << 17)
+#define GOTGCTL_CONID_B (1 << 16)
+#define GOTGCTL_DEVHNPEN (1 << 11)
+#define GOTGCTL_HSTSETHNPEN (1 << 10)
+#define GOTGCTL_HNPREQ (1 << 9)
+#define GOTGCTL_HSTNEGSCS (1 << 8)
+#define GOTGCTL_SESREQ (1 << 1)
+#define GOTGCTL_SESREQSCS (1 << 0)
+
+#define GOTGINT HSOTG_REG(0x004)
+#define GOTGINT_DBNCE_DONE (1 << 19)
+#define GOTGINT_A_DEV_TOUT_CHG (1 << 18)
+#define GOTGINT_HST_NEG_DET (1 << 17)
+#define GOTGINT_HST_NEG_SUC_STS_CHNG (1 << 9)
+#define GOTGINT_SES_REQ_SUC_STS_CHNG (1 << 8)
+#define GOTGINT_SES_END_DET (1 << 2)
+
+#define GAHBCFG HSOTG_REG(0x008)
+#define GAHBCFG_AHB_SINGLE (1 << 23)
+#define GAHBCFG_NOTI_ALL_DMA_WRIT (1 << 22)
+#define GAHBCFG_REM_MEM_SUPP (1 << 21)
+#define GAHBCFG_P_TXF_EMP_LVL (1 << 8)
+#define GAHBCFG_NP_TXF_EMP_LVL (1 << 7)
+#define GAHBCFG_DMA_EN (1 << 5)
+#define GAHBCFG_HBSTLEN_MASK (0xf << 1)
+#define GAHBCFG_HBSTLEN_SHIFT 1
+#define GAHBCFG_HBSTLEN_SINGLE (0 << 1)
+#define GAHBCFG_HBSTLEN_INCR (1 << 1)
+#define GAHBCFG_HBSTLEN_INCR4 (3 << 1)
+#define GAHBCFG_HBSTLEN_INCR8 (5 << 1)
+#define GAHBCFG_HBSTLEN_INCR16 (7 << 1)
+#define GAHBCFG_GLBL_INTR_EN (1 << 0)
+
+#define GUSBCFG HSOTG_REG(0x00C)
+#define GUSBCFG_FORCEDEVMODE (1 << 30)
+#define GUSBCFG_FORCEHOSTMODE (1 << 29)
+#define GUSBCFG_TXENDDELAY (1 << 28)
+#define GUSBCFG_ICTRAFFICPULLREMOVE (1 << 27)
+#define GUSBCFG_ICUSBCAP (1 << 26)
+#define GUSBCFG_ULPI_INT_PROT_DIS (1 << 25)
+#define GUSBCFG_INDICATORPASSTHROUGH (1 << 24)
+#define GUSBCFG_INDICATORCOMPLEMENT (1 << 23)
+#define GUSBCFG_TERMSELDLPULSE (1 << 22)
+#define GUSBCFG_ULPI_INT_VBUS_IND (1 << 21)
+#define GUSBCFG_ULPI_EXT_VBUS_DRV (1 << 20)
+#define GUSBCFG_ULPI_CLK_SUSP_M (1 << 19)
+#define GUSBCFG_ULPI_AUTO_RES (1 << 18)
+#define GUSBCFG_ULPI_FS_LS (1 << 17)
+#define GUSBCFG_OTG_UTMI_FS_SEL (1 << 16)
+#define GUSBCFG_PHY_LP_CLK_SEL (1 << 15)
+#define GUSBCFG_USBTRDTIM_MASK (0xf << 10)
+#define GUSBCFG_USBTRDTIM_SHIFT 10
+#define GUSBCFG_HNPCAP (1 << 9)
+#define GUSBCFG_SRPCAP (1 << 8)
+#define GUSBCFG_DDRSEL (1 << 7)
+#define GUSBCFG_PHYSEL (1 << 6)
+#define GUSBCFG_FSINTF (1 << 5)
+#define GUSBCFG_ULPI_UTMI_SEL (1 << 4)
+#define GUSBCFG_PHYIF16 (1 << 3)
+#define GUSBCFG_TOUTCAL_MASK (0x7 << 0)
+#define GUSBCFG_TOUTCAL_SHIFT 0
+#define GUSBCFG_TOUTCAL_LIMIT 0x7
+#define GUSBCFG_TOUTCAL(_x) ((_x) << 0)
+
+#define GRSTCTL HSOTG_REG(0x010)
+#define GRSTCTL_AHBIDLE (1 << 31)
+#define GRSTCTL_DMAREQ (1 << 30)
+#define GRSTCTL_TXFNUM_MASK (0x1f << 6)
+#define GRSTCTL_TXFNUM_SHIFT 6
+#define GRSTCTL_TXFNUM_LIMIT 0x1f
+#define GRSTCTL_TXFNUM(_x) ((_x) << 6)
+#define GRSTCTL_TXFFLSH (1 << 5)
+#define GRSTCTL_RXFFLSH (1 << 4)
+#define GRSTCTL_IN_TKNQ_FLSH (1 << 3)
+#define GRSTCTL_FRMCNTRRST (1 << 2)
+#define GRSTCTL_HSFTRST (1 << 1)
+#define GRSTCTL_CSFTRST (1 << 0)
+
+#define GINTSTS HSOTG_REG(0x014)
+#define GINTMSK HSOTG_REG(0x018)
+#define GINTSTS_WKUPINT (1 << 31)
+#define GINTSTS_SESSREQINT (1 << 30)
+#define GINTSTS_DISCONNINT (1 << 29)
+#define GINTSTS_CONIDSTSCHNG (1 << 28)
+#define GINTSTS_LPMTRANRCVD (1 << 27)
+#define GINTSTS_PTXFEMP (1 << 26)
+#define GINTSTS_HCHINT (1 << 25)
+#define GINTSTS_PRTINT (1 << 24)
+#define GINTSTS_RESETDET (1 << 23)
+#define GINTSTS_FET_SUSP (1 << 22)
+#define GINTSTS_INCOMPL_IP (1 << 21)
+#define GINTSTS_INCOMPL_SOIN (1 << 20)
+#define GINTSTS_OEPINT (1 << 19)
+#define GINTSTS_IEPINT (1 << 18)
+#define GINTSTS_EPMIS (1 << 17)
+#define GINTSTS_RESTOREDONE (1 << 16)
+#define GINTSTS_EOPF (1 << 15)
+#define GINTSTS_ISOUTDROP (1 << 14)
+#define GINTSTS_ENUMDONE (1 << 13)
+#define GINTSTS_USBRST (1 << 12)
+#define GINTSTS_USBSUSP (1 << 11)
+#define GINTSTS_ERLYSUSP (1 << 10)
+#define GINTSTS_I2CINT (1 << 9)
+#define GINTSTS_ULPI_CK_INT (1 << 8)
+#define GINTSTS_GOUTNAKEFF (1 << 7)
+#define GINTSTS_GINNAKEFF (1 << 6)
+#define GINTSTS_NPTXFEMP (1 << 5)
+#define GINTSTS_RXFLVL (1 << 4)
+#define GINTSTS_SOF (1 << 3)
+#define GINTSTS_OTGINT (1 << 2)
+#define GINTSTS_MODEMIS (1 << 1)
+#define GINTSTS_CURMODE_HOST (1 << 0)
+
+#define GRXSTSR HSOTG_REG(0x01C)
+#define GRXSTSP HSOTG_REG(0x020)
+#define GRXSTS_FN_MASK (0x7f << 25)
+#define GRXSTS_FN_SHIFT 25
+#define GRXSTS_PKTSTS_MASK (0xf << 17)
+#define GRXSTS_PKTSTS_SHIFT 17
+#define GRXSTS_PKTSTS_GLOBALOUTNAK (1 << 17)
+#define GRXSTS_PKTSTS_OUTRX (2 << 17)
+#define GRXSTS_PKTSTS_HCHIN (2 << 17)
+#define GRXSTS_PKTSTS_OUTDONE (3 << 17)
+#define GRXSTS_PKTSTS_HCHIN_XFER_COMP (3 << 17)
+#define GRXSTS_PKTSTS_SETUPDONE (4 << 17)
+#define GRXSTS_PKTSTS_DATATOGGLEERR (5 << 17)
+#define GRXSTS_PKTSTS_SETUPRX (6 << 17)
+#define GRXSTS_PKTSTS_HCHHALTED (7 << 17)
+#define GRXSTS_HCHNUM_MASK (0xf << 0)
+#define GRXSTS_HCHNUM_SHIFT 0
+#define GRXSTS_DPID_MASK (0x3 << 15)
+#define GRXSTS_DPID_SHIFT 15
+#define GRXSTS_BYTECNT_MASK (0x7ff << 4)
+#define GRXSTS_BYTECNT_SHIFT 4
+#define GRXSTS_EPNUM_MASK (0xf << 0)
+#define GRXSTS_EPNUM_SHIFT 0
+
+#define GRXFSIZ HSOTG_REG(0x024)
+
+#define GNPTXFSIZ HSOTG_REG(0x028)
+#define GNPTXFSIZ_NP_TXF_DEP_MASK (0xffff << 16)
+#define GNPTXFSIZ_NP_TXF_DEP_SHIFT 16
+#define GNPTXFSIZ_NP_TXF_DEP_LIMIT 0xffff
+#define GNPTXFSIZ_NP_TXF_DEP(_x) ((_x) << 16)
+#define GNPTXFSIZ_NP_TXF_ST_ADDR_MASK (0xffff << 0)
+#define GNPTXFSIZ_NP_TXF_ST_ADDR_SHIFT 0
+#define GNPTXFSIZ_NP_TXF_ST_ADDR_LIMIT 0xffff
+#define GNPTXFSIZ_NP_TXF_ST_ADDR(_x) ((_x) << 0)
+
+#define GNPTXSTS HSOTG_REG(0x02C)
+#define GNPTXSTS_NP_TXQ_TOP_MASK (0x7f << 24)
+#define GNPTXSTS_NP_TXQ_TOP_SHIFT 24
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK (0xff << 16)
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT 16
+#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v) (((_v) >> 16) & 0xff)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK (0xffff << 0)
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT 0
+#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff)
+
+#define GI2CCTL HSOTG_REG(0x0030)
+#define GI2CCTL_BSYDNE (1 << 31)
+#define GI2CCTL_RW (1 << 30)
+#define GI2CCTL_I2CDATSE0 (1 << 28)
+#define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26)
+#define GI2CCTL_I2CDEVADDR_SHIFT 26
+#define GI2CCTL_I2CSUSPCTL (1 << 25)
+#define GI2CCTL_ACK (1 << 24)
+#define GI2CCTL_I2CEN (1 << 23)
+#define GI2CCTL_ADDR_MASK (0x7f << 16)
+#define GI2CCTL_ADDR_SHIFT 16
+#define GI2CCTL_REGADDR_MASK (0xff << 8)
+#define GI2CCTL_REGADDR_SHIFT 8
+#define GI2CCTL_RWDATA_MASK (0xff << 0)
+#define GI2CCTL_RWDATA_SHIFT 0
+
+#define GPVNDCTL HSOTG_REG(0x0034)
+#define GGPIO HSOTG_REG(0x0038)
+#define GUID HSOTG_REG(0x003c)
+#define GSNPSID HSOTG_REG(0x0040)
+#define GHWCFG1 HSOTG_REG(0x0044)
+
+#define GHWCFG2 HSOTG_REG(0x0048)
+#define GHWCFG2_OTG_ENABLE_IC_USB (1 << 31)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26)
+#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24)
+#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22)
+#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22
+#define GHWCFG2_MULTI_PROC_INT (1 << 20)
+#define GHWCFG2_DYNAMIC_FIFO (1 << 19)
+#define GHWCFG2_PERIO_EP_SUPPORTED (1 << 18)
+#define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14)
+#define GHWCFG2_NUM_HOST_CHAN_SHIFT 14
+#define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10)
+#define GHWCFG2_NUM_DEV_EP_SHIFT 10
+#define GHWCFG2_FS_PHY_TYPE_MASK (0x3 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHIFT 8
+#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED (0 << 8)
+#define GHWCFG2_FS_PHY_TYPE_DEDICATED (1 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI (2 << 8)
+#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI (3 << 8)
+#define GHWCFG2_HS_PHY_TYPE_MASK (0x3 << 6)
+#define GHWCFG2_HS_PHY_TYPE_SHIFT 6
+#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED (0 << 6)
+#define GHWCFG2_HS_PHY_TYPE_UTMI (1 << 6)
+#define GHWCFG2_HS_PHY_TYPE_ULPI (2 << 6)
+#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI (3 << 6)
+#define GHWCFG2_POINT2POINT (1 << 5)
+#define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3)
+#define GHWCFG2_ARCHITECTURE_SHIFT 3
+#define GHWCFG2_SLAVE_ONLY_ARCH (0 << 3)
+#define GHWCFG2_EXT_DMA_ARCH (1 << 3)
+#define GHWCFG2_INT_DMA_ARCH (2 << 3)
+#define GHWCFG2_OP_MODE_MASK (0x7 << 0)
+#define GHWCFG2_OP_MODE_SHIFT 0
+#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE (0 << 0)
+#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE (1 << 0)
+#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE (2 << 0)
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE (3 << 0)
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE (4 << 0)
+#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST (5 << 0)
+#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST (6 << 0)
+#define GHWCFG2_OP_MODE_UNDEFINED (7 << 0)
+
+#define GHWCFG3 HSOTG_REG(0x004c)
+#define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16)
+#define GHWCFG3_DFIFO_DEPTH_SHIFT 16
+#define GHWCFG3_OTG_LPM_EN (1 << 15)
+#define GHWCFG3_BC_SUPPORT (1 << 14)
+#define GHWCFG3_OTG_ENABLE_HSIC (1 << 13)
+#define GHWCFG3_ADP_SUPP (1 << 12)
+#define GHWCFG3_SYNCH_RESET_TYPE (1 << 11)
+#define GHWCFG3_OPTIONAL_FEATURES (1 << 10)
+#define GHWCFG3_VENDOR_CTRL_IF (1 << 9)
+#define GHWCFG3_I2C (1 << 8)
+#define GHWCFG3_OTG_FUNC (1 << 7)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4)
+#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0)
+#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0
+
+#define GHWCFG4 HSOTG_REG(0x0050)
+#define GHWCFG4_DESC_DMA_DYN (1 << 31)
+#define GHWCFG4_DESC_DMA (1 << 30)
+#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
+#define GHWCFG4_NUM_IN_EPS_SHIFT 26
+#define GHWCFG4_DED_FIFO_EN (1 << 25)
+#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
+#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
+#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
+#define GHWCFG4_VBUS_VALID_FILT_EN (1 << 21)
+#define GHWCFG4_IDDIG_FILT_EN (1 << 20)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16)
+#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
+#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define GHWCFG4_XHIBER (1 << 7)
+#define GHWCFG4_HIBER (1 << 6)
+#define GHWCFG4_MIN_AHB_FREQ (1 << 5)
+#define GHWCFG4_POWER_OPTIMIZ (1 << 4)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0)
+#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0
+
+#define GLPMCFG HSOTG_REG(0x0054)
+#define GLPMCFG_INV_SEL_HSIC (1 << 31)
+#define GLPMCFG_HSIC_CONNECT (1 << 30)
+#define GLPMCFG_RETRY_COUNT_STS_MASK (0x7 << 25)
+#define GLPMCFG_RETRY_COUNT_STS_SHIFT 25
+#define GLPMCFG_SEND_LPM (1 << 24)
+#define GLPMCFG_RETRY_COUNT_MASK (0x7 << 21)
+#define GLPMCFG_RETRY_COUNT_SHIFT 21
+#define GLPMCFG_LPM_CHAN_INDEX_MASK (0xf << 17)
+#define GLPMCFG_LPM_CHAN_INDEX_SHIFT 17
+#define GLPMCFG_SLEEP_STATE_RESUMEOK (1 << 16)
+#define GLPMCFG_PRT_SLEEP_STS (1 << 15)
+#define GLPMCFG_LPM_RESP_MASK (0x3 << 13)
+#define GLPMCFG_LPM_RESP_SHIFT 13
+#define GLPMCFG_HIRD_THRES_MASK (0x1f << 8)
+#define GLPMCFG_HIRD_THRES_SHIFT 8
+#define GLPMCFG_HIRD_THRES_EN (0x10 << 8)
+#define GLPMCFG_EN_UTMI_SLEEP (1 << 7)
+#define GLPMCFG_REM_WKUP_EN (1 << 6)
+#define GLPMCFG_HIRD_MASK (0xf << 2)
+#define GLPMCFG_HIRD_SHIFT 2
+#define GLPMCFG_APPL_RESP (1 << 1)
+#define GLPMCFG_LPM_CAP_EN (1 << 0)
+
+#define GPWRDN HSOTG_REG(0x0058)
+#define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24)
+#define GPWRDN_MULT_VAL_ID_BC_SHIFT 24
+#define GPWRDN_ADP_INT (1 << 23)
+#define GPWRDN_BSESSVLD (1 << 22)
+#define GPWRDN_IDSTS (1 << 21)
+#define GPWRDN_LINESTATE_MASK (0x3 << 19)
+#define GPWRDN_LINESTATE_SHIFT 19
+#define GPWRDN_STS_CHGINT_MSK (1 << 18)
+#define GPWRDN_STS_CHGINT (1 << 17)
+#define GPWRDN_SRP_DET_MSK (1 << 16)
+#define GPWRDN_SRP_DET (1 << 15)
+#define GPWRDN_CONNECT_DET_MSK (1 << 14)
+#define GPWRDN_CONNECT_DET (1 << 13)
+#define GPWRDN_DISCONN_DET_MSK (1 << 12)
+#define GPWRDN_DISCONN_DET (1 << 11)
+#define GPWRDN_RST_DET_MSK (1 << 10)
+#define GPWRDN_RST_DET (1 << 9)
+#define GPWRDN_LNSTSCHG_MSK (1 << 8)
+#define GPWRDN_LNSTSCHG (1 << 7)
+#define GPWRDN_DIS_VBUS (1 << 6)
+#define GPWRDN_PWRDNSWTCH (1 << 5)
+#define GPWRDN_PWRDNRSTN (1 << 4)
+#define GPWRDN_PWRDNCLMP (1 << 3)
+#define GPWRDN_RESTORE (1 << 2)
+#define GPWRDN_PMUACTV (1 << 1)
+#define GPWRDN_PMUINTSEL (1 << 0)
+
+#define GDFIFOCFG HSOTG_REG(0x005c)
+#define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16)
+#define GDFIFOCFG_EPINFOBASE_SHIFT 16
+#define GDFIFOCFG_GDFIFOCFG_MASK (0xffff << 0)
+#define GDFIFOCFG_GDFIFOCFG_SHIFT 0
+
+#define ADPCTL HSOTG_REG(0x0060)
+#define ADPCTL_AR_MASK (0x3 << 27)
+#define ADPCTL_AR_SHIFT 27
+#define ADPCTL_ADP_TMOUT_INT_MSK (1 << 26)
+#define ADPCTL_ADP_SNS_INT_MSK (1 << 25)
+#define ADPCTL_ADP_PRB_INT_MSK (1 << 24)
+#define ADPCTL_ADP_TMOUT_INT (1 << 23)
+#define ADPCTL_ADP_SNS_INT (1 << 22)
+#define ADPCTL_ADP_PRB_INT (1 << 21)
+#define ADPCTL_ADPENA (1 << 20)
+#define ADPCTL_ADPRES (1 << 19)
+#define ADPCTL_ENASNS (1 << 18)
+#define ADPCTL_ENAPRB (1 << 17)
+#define ADPCTL_RTIM_MASK (0x7ff << 6)
+#define ADPCTL_RTIM_SHIFT 6
+#define ADPCTL_PRB_PER_MASK (0x3 << 4)
+#define ADPCTL_PRB_PER_SHIFT 4
+#define ADPCTL_PRB_DELTA_MASK (0x3 << 2)
+#define ADPCTL_PRB_DELTA_SHIFT 2
+#define ADPCTL_PRB_DSCHRG_MASK (0x3 << 0)
+#define ADPCTL_PRB_DSCHRG_SHIFT 0
+
+#define HPTXFSIZ HSOTG_REG(0x100)
+
+#define DPTXFSIZN(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
+#define DPTXFSIZN_DP_TXF_SIZE_MASK (0xffff << 16)
+#define DPTXFSIZN_DP_TXF_SIZE_SHIFT 16
+#define DPTXFSIZN_DP_TXF_SIZE_GET(_v) (((_v) >> 16) & 0xffff)
+#define DPTXFSIZN_DP_TXF_SIZE_LIMIT 0xffff
+#define DPTXFSIZN_DP_TXF_SIZE(_x) ((_x) << 16)
+#define DPTXFSIZN_DP_TXF_ST_ADDR_MASK (0xffff << 0)
+#define DPTXFSIZN_DP_TXF_ST_ADDR_SHIFT 0
+
+#define FIFOSIZE_DEPTH_MASK (0xffff << 16)
+#define FIFOSIZE_DEPTH_SHIFT 16
+#define FIFOSIZE_STARTADDR_MASK (0xffff << 0)
+#define FIFOSIZE_STARTADDR_SHIFT 0
+
+/* Device mode registers */
+
+#define DCFG HSOTG_REG(0x800)
+#define DCFG_EPMISCNT_MASK (0x1f << 18)
+#define DCFG_EPMISCNT_SHIFT 18
+#define DCFG_EPMISCNT_LIMIT 0x1f
+#define DCFG_EPMISCNT(_x) ((_x) << 18)
+#define DCFG_PERFRINT_MASK (0x3 << 11)
+#define DCFG_PERFRINT_SHIFT 11
+#define DCFG_PERFRINT_LIMIT 0x3
+#define DCFG_PERFRINT(_x) ((_x) << 11)
+#define DCFG_DEVADDR_MASK (0x7f << 4)
+#define DCFG_DEVADDR_SHIFT 4
+#define DCFG_DEVADDR_LIMIT 0x7f
+#define DCFG_DEVADDR(_x) ((_x) << 4)
+#define DCFG_NZ_STS_OUT_HSHK (1 << 2)
+#define DCFG_DEVSPD_MASK (0x3 << 0)
+#define DCFG_DEVSPD_SHIFT 0
+#define DCFG_DEVSPD_HS (0 << 0)
+#define DCFG_DEVSPD_FS (1 << 0)
+#define DCFG_DEVSPD_LS (2 << 0)
+#define DCFG_DEVSPD_FS48 (3 << 0)
+
+#define DCTL HSOTG_REG(0x804)
+#define DCTL_PWRONPRGDONE (1 << 11)
+#define DCTL_CGOUTNAK (1 << 10)
+#define DCTL_SGOUTNAK (1 << 9)
+#define DCTL_CGNPINNAK (1 << 8)
+#define DCTL_SGNPINNAK (1 << 7)
+#define DCTL_TSTCTL_MASK (0x7 << 4)
+#define DCTL_TSTCTL_SHIFT 4
+#define DCTL_GOUTNAKSTS (1 << 3)
+#define DCTL_GNPINNAKSTS (1 << 2)
+#define DCTL_SFTDISCON (1 << 1)
+#define DCTL_RMTWKUPSIG (1 << 0)
+
+#define DSTS HSOTG_REG(0x808)
+#define DSTS_SOFFN_MASK (0x3fff << 8)
+#define DSTS_SOFFN_SHIFT 8
+#define DSTS_SOFFN_LIMIT 0x3fff
+#define DSTS_SOFFN(_x) ((_x) << 8)
+#define DSTS_ERRATICERR (1 << 3)
+#define DSTS_ENUMSPD_MASK (0x3 << 1)
+#define DSTS_ENUMSPD_SHIFT 1
+#define DSTS_ENUMSPD_HS (0 << 1)
+#define DSTS_ENUMSPD_FS (1 << 1)
+#define DSTS_ENUMSPD_LS (2 << 1)
+#define DSTS_ENUMSPD_FS48 (3 << 1)
+#define DSTS_SUSPSTS (1 << 0)
+
+#define DIEPMSK HSOTG_REG(0x810)
+#define DIEPMSK_TXFIFOEMPTY (1 << 7)
+#define DIEPMSK_INEPNAKEFFMSK (1 << 6)
+#define DIEPMSK_INTKNEPMISMSK (1 << 5)
+#define DIEPMSK_INTKNTXFEMPMSK (1 << 4)
+#define DIEPMSK_TIMEOUTMSK (1 << 3)
+#define DIEPMSK_AHBERRMSK (1 << 2)
+#define DIEPMSK_EPDISBLDMSK (1 << 1)
+#define DIEPMSK_XFERCOMPLMSK (1 << 0)
+
+#define DOEPMSK HSOTG_REG(0x814)
+#define DOEPMSK_BACK2BACKSETUP (1 << 6)
+#define DOEPMSK_OUTTKNEPDISMSK (1 << 4)
+#define DOEPMSK_SETUPMSK (1 << 3)
+#define DOEPMSK_AHBERRMSK (1 << 2)
+#define DOEPMSK_EPDISBLDMSK (1 << 1)
+#define DOEPMSK_XFERCOMPLMSK (1 << 0)
+
+#define DAINT HSOTG_REG(0x818)
+#define DAINTMSK HSOTG_REG(0x81C)
+#define DAINT_OUTEP_SHIFT 16
+#define DAINT_OUTEP(_x) (1 << ((_x) + 16))
+#define DAINT_INEP(_x) (1 << (_x))
+
+#define DTKNQR1 HSOTG_REG(0x820)
+#define DTKNQR2 HSOTG_REG(0x824)
+#define DTKNQR3 HSOTG_REG(0x830)
+#define DTKNQR4 HSOTG_REG(0x834)
+
+#define DVBUSDIS HSOTG_REG(0x828)
+#define DVBUSPULSE HSOTG_REG(0x82C)
+
+#define DIEPCTL0 HSOTG_REG(0x900)
+#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20))
+
+#define DOEPCTL0 HSOTG_REG(0xB00)
+#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting different for EP0
+ */
+#define D0EPCTL_MPS_MASK (0x3 << 0)
+#define D0EPCTL_MPS_SHIFT 0
+#define D0EPCTL_MPS_64 (0 << 0)
+#define D0EPCTL_MPS_32 (1 << 0)
+#define D0EPCTL_MPS_16 (2 << 0)
+#define D0EPCTL_MPS_8 (3 << 0)
+
+#define DXEPCTL_EPENA (1 << 31)
+#define DXEPCTL_EPDIS (1 << 30)
+#define DXEPCTL_SETD1PID (1 << 29)
+#define DXEPCTL_SETODDFR (1 << 29)
+#define DXEPCTL_SETD0PID (1 << 28)
+#define DXEPCTL_SETEVENFR (1 << 28)
+#define DXEPCTL_SNAK (1 << 27)
+#define DXEPCTL_CNAK (1 << 26)
+#define DXEPCTL_TXFNUM_MASK (0xf << 22)
+#define DXEPCTL_TXFNUM_SHIFT 22
+#define DXEPCTL_TXFNUM_LIMIT 0xf
+#define DXEPCTL_TXFNUM(_x) ((_x) << 22)
+#define DXEPCTL_STALL (1 << 21)
+#define DXEPCTL_SNP (1 << 20)
+#define DXEPCTL_EPTYPE_MASK (0x3 << 18)
+#define DXEPCTL_EPTYPE_SHIFT 18
+#define DXEPCTL_EPTYPE_CONTROL (0 << 18)
+#define DXEPCTL_EPTYPE_ISO (1 << 18)
+#define DXEPCTL_EPTYPE_BULK (2 << 18)
+#define DXEPCTL_EPTYPE_INTTERUPT (3 << 18)
+#define DXEPCTL_NAKSTS (1 << 17)
+#define DXEPCTL_DPID (1 << 16)
+#define DXEPCTL_EOFRNUM (1 << 16)
+#define DXEPCTL_USBACTEP (1 << 15)
+#define DXEPCTL_NEXTEP_MASK (0xf << 11)
+#define DXEPCTL_NEXTEP_SHIFT 11
+#define DXEPCTL_NEXTEP_LIMIT 0xf
+#define DXEPCTL_NEXTEP(_x) ((_x) << 11)
+#define DXEPCTL_MPS_MASK (0x7ff << 0)
+#define DXEPCTL_MPS_SHIFT 0
+#define DXEPCTL_MPS_LIMIT 0x7ff
+#define DXEPCTL_MPS(_x) ((_x) << 0)
+
+#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_INEPNAKEFF (1 << 6)
+#define DXEPINT_BACK2BACKSETUP (1 << 6)
+#define DXEPINT_INTKNEPMIS (1 << 5)
+#define DXEPINT_INTKNTXFEMP (1 << 4)
+#define DXEPINT_OUTTKNEPDIS (1 << 4)
+#define DXEPINT_TIMEOUT (1 << 3)
+#define DXEPINT_SETUP (1 << 3)
+#define DXEPINT_AHBERR (1 << 2)
+#define DXEPINT_EPDISBLD (1 << 1)
+#define DXEPINT_XFERCOMPL (1 << 0)
+
+#define DIEPTSIZ0 HSOTG_REG(0x910)
+#define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19)
+#define DIEPTSIZ0_PKTCNT_SHIFT 19
+#define DIEPTSIZ0_PKTCNT_LIMIT 0x3
+#define DIEPTSIZ0_PKTCNT(_x) ((_x) << 19)
+#define DIEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
+#define DIEPTSIZ0_XFERSIZE_SHIFT 0
+#define DIEPTSIZ0_XFERSIZE_LIMIT 0x7f
+#define DIEPTSIZ0_XFERSIZE(_x) ((_x) << 0)
+
+#define DOEPTSIZ0 HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCNT_MASK (0x3 << 29)
+#define DOEPTSIZ0_SUPCNT_SHIFT 29
+#define DOEPTSIZ0_SUPCNT_LIMIT 0x3
+#define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29)
+#define DOEPTSIZ0_PKTCNT (1 << 19)
+#define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0)
+#define DOEPTSIZ0_XFERSIZE_SHIFT 0
+
+#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
+#define DXEPTSIZ_MC_MASK (0x3 << 29)
+#define DXEPTSIZ_MC_SHIFT 29
+#define DXEPTSIZ_MC_LIMIT 0x3
+#define DXEPTSIZ_MC(_x) ((_x) << 29)
+#define DXEPTSIZ_PKTCNT_MASK (0x3ff << 19)
+#define DXEPTSIZ_PKTCNT_SHIFT 19
+#define DXEPTSIZ_PKTCNT_LIMIT 0x3ff
+#define DXEPTSIZ_PKTCNT_GET(_v) (((_v) >> 19) & 0x3ff)
+#define DXEPTSIZ_PKTCNT(_x) ((_x) << 19)
+#define DXEPTSIZ_XFERSIZE_MASK (0x7ffff << 0)
+#define DXEPTSIZ_XFERSIZE_SHIFT 0
+#define DXEPTSIZ_XFERSIZE_LIMIT 0x7ffff
+#define DXEPTSIZ_XFERSIZE_GET(_v) (((_v) >> 0) & 0x7ffff)
+#define DXEPTSIZ_XFERSIZE(_x) ((_x) << 0)
+
+#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define PCGCTL HSOTG_REG(0x0e00)
+#define PCGCTL_IF_DEV_MODE (1 << 31)
+#define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29)
+#define PCGCTL_P2HD_PRT_SPD_SHIFT 29
+#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27)
+#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
+#define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20)
+#define PCGCTL_MAC_DEV_ADDR_SHIFT 20
+#define PCGCTL_MAX_TERMSEL (1 << 19)
+#define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17)
+#define PCGCTL_MAX_XCVRSELECT_SHIFT 17
+#define PCGCTL_PORT_POWER (1 << 16)
+#define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14)
+#define PCGCTL_PRT_CLK_SEL_SHIFT 14
+#define PCGCTL_ESS_REG_RESTORED (1 << 13)
+#define PCGCTL_EXTND_HIBER_SWITCH (1 << 12)
+#define PCGCTL_EXTND_HIBER_PWRCLMP (1 << 11)
+#define PCGCTL_ENBL_EXTND_HIBER (1 << 10)
+#define PCGCTL_RESTOREMODE (1 << 9)
+#define PCGCTL_RESETAFTSUSP (1 << 8)
+#define PCGCTL_DEEP_SLEEP (1 << 7)
+#define PCGCTL_PHY_IN_SLEEP (1 << 6)
+#define PCGCTL_ENBL_SLEEP_GATING (1 << 5)
+#define PCGCTL_RSTPDWNMODULE (1 << 3)
+#define PCGCTL_PWRCLMP (1 << 2)
+#define PCGCTL_GATEHCLK (1 << 1)
+#define PCGCTL_STOPPCLK (1 << 0)
+
+#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+/* Host Mode Registers */
+
+#define HCFG HSOTG_REG(0x0400)
+#define HCFG_MODECHTIMEN (1 << 31)
+#define HCFG_PERSCHEDENA (1 << 26)
+#define HCFG_FRLISTEN_MASK (0x3 << 24)
+#define HCFG_FRLISTEN_SHIFT 24
+#define HCFG_FRLISTEN_8 (0 << 24)
+#define FRLISTEN_8_SIZE 8
+#define HCFG_FRLISTEN_16 (1 << 24)
+#define FRLISTEN_16_SIZE 16
+#define HCFG_FRLISTEN_32 (2 << 24)
+#define FRLISTEN_32_SIZE 32
+#define HCFG_FRLISTEN_64 (3 << 24)
+#define FRLISTEN_64_SIZE 64
+#define HCFG_DESCDMA (1 << 23)
+#define HCFG_RESVALID_MASK (0xff << 8)
+#define HCFG_RESVALID_SHIFT 8
+#define HCFG_ENA32KHZ (1 << 7)
+#define HCFG_FSLSSUPP (1 << 2)
+#define HCFG_FSLSPCLKSEL_MASK (0x3 << 0)
+#define HCFG_FSLSPCLKSEL_SHIFT 0
+#define HCFG_FSLSPCLKSEL_30_60_MHZ (0 << 0)
+#define HCFG_FSLSPCLKSEL_48_MHZ (1 << 0)
+#define HCFG_FSLSPCLKSEL_6_MHZ (2 << 0)
+
+#define HFIR HSOTG_REG(0x0404)
+#define HFIR_FRINT_MASK (0xffff << 0)
+#define HFIR_FRINT_SHIFT 0
+#define HFIR_RLDCTRL (1 << 16)
+
+#define HFNUM HSOTG_REG(0x0408)
+#define HFNUM_FRREM_MASK (0xffff << 16)
+#define HFNUM_FRREM_SHIFT 16
+#define HFNUM_FRNUM_MASK (0xffff << 0)
+#define HFNUM_FRNUM_SHIFT 0
+#define HFNUM_MAX_FRNUM 0x3fff
+
+#define HPTXSTS HSOTG_REG(0x0410)
+#define TXSTS_QTOP_ODD (1 << 31)
+#define TXSTS_QTOP_CHNEP_MASK (0xf << 27)
+#define TXSTS_QTOP_CHNEP_SHIFT 27
+#define TXSTS_QTOP_TOKEN_MASK (0x3 << 25)
+#define TXSTS_QTOP_TOKEN_SHIFT 25
+#define TXSTS_QTOP_TERMINATE (1 << 24)
+#define TXSTS_QSPCAVAIL_MASK (0xff << 16)
+#define TXSTS_QSPCAVAIL_SHIFT 16
+#define TXSTS_FSPCAVAIL_MASK (0xffff << 0)
+#define TXSTS_FSPCAVAIL_SHIFT 0
+
+#define HAINT HSOTG_REG(0x0414)
+#define HAINTMSK HSOTG_REG(0x0418)
+#define HFLBADDR HSOTG_REG(0x041c)
+
+#define HPRT0 HSOTG_REG(0x0440)
+#define HPRT0_SPD_MASK (0x3 << 17)
+#define HPRT0_SPD_SHIFT 17
+#define HPRT0_SPD_HIGH_SPEED (0 << 17)
+#define HPRT0_SPD_FULL_SPEED (1 << 17)
+#define HPRT0_SPD_LOW_SPEED (2 << 17)
+#define HPRT0_TSTCTL_MASK (0xf << 13)
+#define HPRT0_TSTCTL_SHIFT 13
+#define HPRT0_PWR (1 << 12)
+#define HPRT0_LNSTS_MASK (0x3 << 10)
+#define HPRT0_LNSTS_SHIFT 10
+#define HPRT0_RST (1 << 8)
+#define HPRT0_SUSP (1 << 7)
+#define HPRT0_RES (1 << 6)
+#define HPRT0_OVRCURRCHG (1 << 5)
+#define HPRT0_OVRCURRACT (1 << 4)
+#define HPRT0_ENACHG (1 << 3)
+#define HPRT0_ENA (1 << 2)
+#define HPRT0_CONNDET (1 << 1)
+#define HPRT0_CONNSTS (1 << 0)
+
+#define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch))
+#define HCCHAR_CHENA (1 << 31)
+#define HCCHAR_CHDIS (1 << 30)
+#define HCCHAR_ODDFRM (1 << 29)
+#define HCCHAR_DEVADDR_MASK (0x7f << 22)
+#define HCCHAR_DEVADDR_SHIFT 22
+#define HCCHAR_MULTICNT_MASK (0x3 << 20)
+#define HCCHAR_MULTICNT_SHIFT 20
+#define HCCHAR_EPTYPE_MASK (0x3 << 18)
+#define HCCHAR_EPTYPE_SHIFT 18
+#define HCCHAR_LSPDDEV (1 << 17)
+#define HCCHAR_EPDIR (1 << 15)
+#define HCCHAR_EPNUM_MASK (0xf << 11)
+#define HCCHAR_EPNUM_SHIFT 11
+#define HCCHAR_MPS_MASK (0x7ff << 0)
+#define HCCHAR_MPS_SHIFT 0
+
+#define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch))
+#define HCSPLT_SPLTENA (1 << 31)
+#define HCSPLT_COMPSPLT (1 << 16)
+#define HCSPLT_XACTPOS_MASK (0x3 << 14)
+#define HCSPLT_XACTPOS_SHIFT 14
+#define HCSPLT_XACTPOS_MID (0 << 14)
+#define HCSPLT_XACTPOS_END (1 << 14)
+#define HCSPLT_XACTPOS_BEGIN (2 << 14)
+#define HCSPLT_XACTPOS_ALL (3 << 14)
+#define HCSPLT_HUBADDR_MASK (0x7f << 7)
+#define HCSPLT_HUBADDR_SHIFT 7
+#define HCSPLT_PRTADDR_MASK (0x7f << 0)
+#define HCSPLT_PRTADDR_SHIFT 0
+
+#define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch))
+#define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch))
+#define HCINTMSK_RESERVED14_31 (0x3ffff << 14)
+#define HCINTMSK_FRM_LIST_ROLL (1 << 13)
+#define HCINTMSK_XCS_XACT (1 << 12)
+#define HCINTMSK_BNA (1 << 11)
+#define HCINTMSK_DATATGLERR (1 << 10)
+#define HCINTMSK_FRMOVRUN (1 << 9)
+#define HCINTMSK_BBLERR (1 << 8)
+#define HCINTMSK_XACTERR (1 << 7)
+#define HCINTMSK_NYET (1 << 6)
+#define HCINTMSK_ACK (1 << 5)
+#define HCINTMSK_NAK (1 << 4)
+#define HCINTMSK_STALL (1 << 3)
+#define HCINTMSK_AHBERR (1 << 2)
+#define HCINTMSK_CHHLTD (1 << 1)
+#define HCINTMSK_XFERCOMPL (1 << 0)
+
+#define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch))
+#define TSIZ_DOPNG (1 << 31)
+#define TSIZ_SC_MC_PID_MASK (0x3 << 29)
+#define TSIZ_SC_MC_PID_SHIFT 29
+#define TSIZ_SC_MC_PID_DATA0 (0 << 29)
+#define TSIZ_SC_MC_PID_DATA2 (1 << 29)
+#define TSIZ_SC_MC_PID_DATA1 (2 << 29)
+#define TSIZ_SC_MC_PID_MDATA (3 << 29)
+#define TSIZ_SC_MC_PID_SETUP (3 << 29)
+#define TSIZ_PKTCNT_MASK (0x3ff << 19)
+#define TSIZ_PKTCNT_SHIFT 19
+#define TSIZ_NTD_MASK (0xff << 8)
+#define TSIZ_NTD_SHIFT 8
+#define TSIZ_SCHINFO_MASK (0xff << 0)
+#define TSIZ_SCHINFO_SHIFT 0
+#define TSIZ_XFERSIZE_MASK (0x7ffff << 0)
+#define TSIZ_XFERSIZE_SHIFT 0
+
+#define HCDMA(_ch) HSOTG_REG(0x0514 + 0x20 * (_ch))
+#define HCDMA_DMA_ADDR_MASK (0x1fffff << 11)
+#define HCDMA_DMA_ADDR_SHIFT 11
+#define HCDMA_CTD_MASK (0xff << 3)
+#define HCDMA_CTD_SHIFT 3
+
+#define HCDMAB(_ch) HSOTG_REG(0x051c + 0x20 * (_ch))
+
+#define HCFIFO(_ch) HSOTG_REG(0x1000 + 0x1000 * (_ch))
+
+/**
+ * struct dwc2_hcd_dma_desc - Host-mode DMA descriptor structure
+ *
+ * @status: DMA descriptor status quadlet
+ * @buf: DMA descriptor data buffer pointer
+ *
+ * DMA Descriptor structure contains two quadlets:
+ * Status quadlet and Data buffer pointer.
+ */
+struct dwc2_hcd_dma_desc {
+ u32 status;
+ u32 buf;
+};
+
+#define HOST_DMA_A (1 << 31)
+#define HOST_DMA_STS_MASK (0x3 << 28)
+#define HOST_DMA_STS_SHIFT 28
+#define HOST_DMA_STS_PKTERR (1 << 28)
+#define HOST_DMA_EOL (1 << 26)
+#define HOST_DMA_IOC (1 << 25)
+#define HOST_DMA_SUP (1 << 24)
+#define HOST_DMA_ALT_QTD (1 << 23)
+#define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17)
+#define HOST_DMA_QTD_OFFSET_SHIFT 17
+#define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0)
+#define HOST_DMA_ISOC_NBYTES_SHIFT 0
+#define HOST_DMA_NBYTES_MASK (0x1ffff << 0)
+#define HOST_DMA_NBYTES_SHIFT 0
+
+#define MAX_DMA_DESC_SIZE 131071
+#define MAX_DMA_DESC_NUM_GENERIC 64
+#define MAX_DMA_DESC_NUM_HS_ISOC 256
+
+#endif /* __DWC2_HW_H__ */
diff --git a/drivers/staging/dwc2/pci.c b/drivers/staging/dwc2/pci.c
new file mode 100644
index 000000000000..69c65eb8683f
--- /dev/null
+++ b/drivers/staging/dwc2/pci.c
@@ -0,0 +1,180 @@
+/*
+ * pci.c - DesignWare HS OTG Controller PCI driver
+ *
+ * Copyright (C) 2004-2013 Synopsys, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Provides the initialization and cleanup entry points for the DWC_otg PCI
+ * driver
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch11.h>
+
+#include "core.h"
+#include "hcd.h"
+
+#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
+#define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
+
+static const char dwc2_driver_name[] = "dwc2";
+
+static struct dwc2_core_params dwc2_module_params = {
+ .otg_cap = -1,
+ .otg_ver = -1,
+ .dma_enable = -1,
+ .dma_desc_enable = 0,
+ .speed = -1,
+ .enable_dynamic_fifo = -1,
+ .en_multiple_tx_fifo = -1,
+ .host_rx_fifo_size = 1024,
+ .host_nperio_tx_fifo_size = 256,
+ .host_perio_tx_fifo_size = 1024,
+ .max_transfer_size = 65535,
+ .max_packet_count = 511,
+ .host_channels = -1,
+ .phy_type = -1,
+ .phy_utmi_width = 16, /* 16 bits - NOT DETECTABLE */
+ .phy_ulpi_ddr = -1,
+ .phy_ulpi_ext_vbus = -1,
+ .i2c_enable = -1,
+ .ulpi_fs_ls = -1,
+ .host_support_fs_ls_low_power = -1,
+ .host_ls_low_power_phy_clk = -1,
+ .ts_dline = -1,
+ .reload_ctl = -1,
+ .ahb_single = -1,
+};
+
+/**
+ * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
+ * DWC_otg driver
+ *
+ * @dev: Bus device
+ *
+ * This routine is called, for example, when the rmmod command is executed. The
+ * device may or may not be electrically present. If it is present, the driver
+ * stops device processing. Any resources used on behalf of this device are
+ * freed.
+ */
+static void dwc2_driver_remove(struct pci_dev *dev)
+{
+ struct dwc2_hsotg *hsotg = pci_get_drvdata(dev);
+
+ dev_dbg(&dev->dev, "%s(%p)\n", __func__, dev);
+
+ dwc2_hcd_remove(hsotg);
+ pci_disable_device(dev);
+}
+
+/**
+ * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
+ * driver
+ *
+ * @dev: Bus device
+ *
+ * This routine creates the driver components required to control the device
+ * (core, HCD, and PCD) and initializes the device. The driver components are
+ * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
+ * in the device private data. This allows the driver to access the dwc2_hsotg
+ * structure on subsequent calls to driver methods for this device.
+ */
+static int dwc2_driver_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct dwc2_hsotg *hsotg;
+ int retval;
+
+ dev_dbg(&dev->dev, "%s(%p)\n", __func__, dev);
+
+ hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
+ if (!hsotg)
+ return -ENOMEM;
+
+ pci_set_power_state(dev, PCI_D0);
+
+ hsotg->dev = &dev->dev;
+ hsotg->regs = devm_request_and_ioremap(&dev->dev, &dev->resource[0]);
+ if (!hsotg->regs)
+ return -ENOMEM;
+
+ dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
+ (unsigned long)pci_resource_start(dev, 0), hsotg->regs);
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ pci_set_master(dev);
+
+ retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
+ if (retval) {
+ pci_disable_device(dev);
+ return retval;
+ }
+
+ pci_set_drvdata(dev, hsotg);
+ dev_dbg(&dev->dev, "hsotg=%p\n", hsotg);
+
+ return retval;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dwc2_pci_ids) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
+ },
+ { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
+
+static struct pci_driver dwc2_pci_driver = {
+ .name = dwc2_driver_name,
+ .id_table = dwc2_pci_ids,
+ .probe = dwc2_driver_probe,
+ .remove = dwc2_driver_remove,
+};
+
+module_pci_driver(dwc2_pci_driver);
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
+MODULE_AUTHOR("Synopsys, Inc.");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/dwc2/platform.c b/drivers/staging/dwc2/platform.c
new file mode 100644
index 000000000000..1f3d581a1078
--- /dev/null
+++ b/drivers/staging/dwc2/platform.c
@@ -0,0 +1,145 @@
+/*
+ * platform.c - DesignWare HS OTG Controller platform driver
+ *
+ * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "hcd.h"
+
+static const char dwc2_driver_name[] = "dwc2";
+
+/**
+ * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
+ * DWC_otg driver
+ *
+ * @dev: Platform device
+ *
+ * This routine is called, for example, when the rmmod command is executed. The
+ * device may or may not be electrically present. If it is present, the driver
+ * stops device processing. Any resources used on behalf of this device are
+ * freed.
+ */
+static int dwc2_driver_remove(struct platform_device *dev)
+{
+ struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
+
+ dwc2_hcd_remove(hsotg);
+
+ return 0;
+}
+
+/**
+ * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
+ * driver
+ *
+ * @dev: Platform device
+ *
+ * This routine creates the driver components required to control the device
+ * (core, HCD, and PCD) and initializes the device. The driver components are
+ * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
+ * in the device private data. This allows the driver to access the dwc2_hsotg
+ * structure on subsequent calls to driver methods for this device.
+ */
+static int dwc2_driver_probe(struct platform_device *dev)
+{
+ struct dwc2_hsotg *hsotg;
+ struct resource *res;
+ int retval;
+ int irq;
+ struct dwc2_core_params params;
+
+ /* Default all params to autodetect */
+ dwc2_set_all_params(&params, -1);
+
+ hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
+ if (!hsotg)
+ return -ENOMEM;
+
+ hsotg->dev = &dev->dev;
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "missing IRQ resource\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&dev->dev, "missing memory base resource\n");
+ return -EINVAL;
+ }
+
+ hsotg->regs = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(hsotg->regs))
+ return PTR_ERR(hsotg->regs);
+
+ dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
+ (unsigned long)res->start, hsotg->regs);
+
+ retval = dwc2_hcd_init(hsotg, irq, &params);
+ if (retval)
+ return retval;
+
+ platform_set_drvdata(dev, hsotg);
+
+ return retval;
+}
+
+static const struct of_device_id dwc2_of_match_table[] = {
+ { .compatible = "snps,dwc2" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
+
+static struct platform_driver dwc2_platform_driver = {
+ .driver = {
+ .name = (char *)dwc2_driver_name,
+ .of_match_table = dwc2_of_match_table,
+ },
+ .probe = dwc2_driver_probe,
+ .remove = dwc2_driver_remove,
+};
+
+module_platform_driver(dwc2_platform_driver);
+
+MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue");
+MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 42ae5e83f907..f73e58f5ef8d 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -595,7 +595,7 @@ static int eeprom_write(struct et131x_adapter *adapter, u32 addr, u8 data)
*/
err = eeprom_wait_ready(pdev, NULL);
- if (err)
+ if (err < 0)
return err;
/* 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0,
@@ -709,7 +709,7 @@ static int eeprom_read(struct et131x_adapter *adapter, u32 addr, u8 *pdata)
*/
err = eeprom_wait_ready(pdev, NULL);
- if (err)
+ if (err < 0)
return err;
/* Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0,
* and bits 1:0 both =0. Bit 5 should be set according to the type
@@ -3953,6 +3953,7 @@ static void et131x_pci_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
phy_disconnect(adapter->phydev);
mdiobus_unregister(adapter->mii_bus);
+ cancel_work_sync(&adapter->task);
kfree(adapter->mii_bus->irq);
mdiobus_free(adapter->mii_bus);
diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c
index 5a6fb44f38a8..e5818a1c2262 100644
--- a/drivers/staging/fwserial/fwserial.c
+++ b/drivers/staging/fwserial/fwserial.c
@@ -744,7 +744,6 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,
struct fwtty_transaction *txn)
{
struct fwtty_port *port = txn->port;
- struct tty_struct *tty;
int len;
fwtty_dbg(port, "rcode: %d", rcode);
@@ -769,13 +768,8 @@ static void fwtty_tx_complete(struct fw_card *card, int rcode,
port->stats.dropped += txn->dma_pended.len;
}
- if (len < WAKEUP_CHARS) {
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
- }
+ if (len < WAKEUP_CHARS)
+ tty_port_tty_wakeup(&port->port);
}
static int fwtty_tx(struct fwtty_port *port, bool drain)
@@ -1527,7 +1521,7 @@ static void fwtty_debugfs_show_port(struct seq_file *m, struct fwtty_port *port)
stats.watermark);
if (port->port.console) {
- seq_printf(m, "\n ");
+ seq_puts(m, "\n ");
(*port->fwcon_ops->proc_show)(m, port->con_data);
}
@@ -1559,7 +1553,7 @@ static int fwtty_proc_show(struct seq_file *m, void *v)
if (capable(CAP_SYS_ADMIN))
fwtty_proc_show_port(m, port);
fwtty_port_put(port);
- seq_printf(m, "\n");
+ seq_puts(m, "\n");
}
return 0;
}
@@ -1577,7 +1571,7 @@ static int fwtty_debugfs_stats_show(struct seq_file *m, void *v)
fwtty_proc_show_port(m, port);
fwtty_debugfs_show_port(m, port);
fwtty_port_put(port);
- seq_printf(m, "\n");
+ seq_puts(m, "\n");
}
}
return 0;
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
index 1e6303123722..b795353e8348 100644
--- a/drivers/staging/gdm72xx/gdm_qos.c
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -337,7 +337,6 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
struct nic *nic = nic_ptr;
u32 i, SFID, index, pos;
u8 subCmdEvt;
- u8 len;
struct qos_cb_s *qcb = &nic->qos;
struct qos_entry_s *entry, *n;
struct list_head send_list;
@@ -347,8 +346,6 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
subCmdEvt = (u8)buf[4];
if (subCmdEvt == QOS_REPORT) {
- len = (u8)buf[5];
-
spin_lock_irqsave(&qcb->qos_lock, flags);
for (i = 0; i < qcb->qos_list_cnt; i++) {
SFID = ((buf[(i*5)+6]<<24)&0xff000000);
@@ -368,21 +365,24 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
spin_unlock_irqrestore(&qcb->qos_lock, flags);
send_qos_list(nic, &send_list);
return;
- } else if (subCmdEvt == QOS_ADD) {
- pos = 5;
- len = (u8)buf[pos++];
-
- SFID = ((buf[pos++]<<24)&0xff000000);
- SFID += ((buf[pos++]<<16)&0xff0000);
- SFID += ((buf[pos++]<<8)&0xff00);
- SFID += (buf[pos++]);
-
- index = get_csr(qcb, SFID, 1);
- if (index == -1) {
- netdev_err(nic->netdev, "QoS ERROR: csr Update Error\n");
- return;
- }
+ }
+
+ /* subCmdEvt == QOS_ADD || subCmdEvt == QOS_CHANG_DEL */
+ pos = 6;
+ SFID = ((buf[pos++]<<24)&0xff000000);
+ SFID += ((buf[pos++]<<16)&0xff0000);
+ SFID += ((buf[pos++]<<8)&0xff00);
+ SFID += (buf[pos++]);
+
+ index = get_csr(qcb, SFID, 1);
+ if (index == -1) {
+ netdev_err(nic->netdev,
+ "QoS ERROR: csr Update Error / Wrong index (%d) \n",
+ index);
+ return;
+ }
+ if (subCmdEvt == QOS_ADD) {
netdev_dbg(nic->netdev, "QOS_ADD SFID = 0x%x, index=%d\n",
SFID, index);
@@ -424,19 +424,6 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
qcb->qos_limit_size = 254/qcb->qos_list_cnt;
spin_unlock_irqrestore(&qcb->qos_lock, flags);
} else if (subCmdEvt == QOS_CHANGE_DEL) {
- pos = 5;
- len = (u8)buf[pos++];
- SFID = ((buf[pos++]<<24)&0xff000000);
- SFID += ((buf[pos++]<<16)&0xff0000);
- SFID += ((buf[pos++]<<8)&0xff00);
- SFID += (buf[pos++]);
- index = get_csr(qcb, SFID, 1);
- if (index == -1) {
- netdev_err(nic->netdev, "QoS ERROR: Wrong index(%d)\n",
- index);
- return;
- }
-
netdev_dbg(nic->netdev, "QOS_CHANGE_DEL SFID = 0x%x, index=%d\n",
SFID, index);
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
index 695762b0e942..047a4d77f5ee 100644
--- a/drivers/staging/gdm72xx/gdm_sdio.c
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -689,6 +689,7 @@ static void sdio_wimax_remove(struct sdio_func *func)
struct phy_dev *phy_dev = sdio_get_drvdata(func);
struct sdiowm_dev *sdev = phy_dev->priv_dev;
+ cancel_work_sync(&sdev->ws);
if (phy_dev->netdev)
unregister_wimax_device(phy_dev);
sdio_claim_host(func);
diff --git a/drivers/staging/gdm72xx/netlink_k.c b/drivers/staging/gdm72xx/netlink_k.c
index 52c25ba5831d..af7f1c1d0b5c 100644
--- a/drivers/staging/gdm72xx/netlink_k.c
+++ b/drivers/staging/gdm72xx/netlink_k.c
@@ -15,9 +15,10 @@
#include <linux/module.h>
#include <linux/etherdevice.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <asm/byteorder.h>
#include <net/sock.h>
+#include "netlink_k.h"
#if !defined(NLMSG_HDRLEN)
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
@@ -25,12 +26,12 @@
#define ND_MAX_GROUP 30
#define ND_IFINDEX_LEN sizeof(int)
-#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_SPACE(len) (nlmsg_total_size(len) + ND_IFINDEX_LEN)
#define ND_NLMSG_DATA(nlh) \
- ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+ ((void *)((char *)nlmsg_data(nlh) + ND_IFINDEX_LEN))
#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
-#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
+#define ND_NLMSG_IFIDX(nlh) nlmsg_data(nlh)
#define ND_MAX_MSG_LEN 8096
#if defined(DEFINE_MUTEX)
@@ -51,7 +52,7 @@ static void netlink_rcv_cb(struct sk_buff *skb)
void *msg;
int ifindex;
- if (skb->len >= NLMSG_SPACE(0)) {
+ if (skb->len >= NLMSG_HDRLEN) {
nlh = (struct nlmsghdr *)skb->data;
if (skb->len < nlh->nlmsg_len ||
@@ -124,7 +125,7 @@ int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
return -EINVAL;
}
- skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+ skb = nlmsg_new(len, GFP_ATOMIC);
if (!skb) {
pr_err("netlink_broadcast ret=%d\n", ret);
return -ENOMEM;
diff --git a/drivers/staging/gdm72xx/sdio_boot.c b/drivers/staging/gdm72xx/sdio_boot.c
index 93046dda78f0..4302fcbdfdc3 100644
--- a/drivers/staging/gdm72xx/sdio_boot.c
+++ b/drivers/staging/gdm72xx/sdio_boot.c
@@ -27,6 +27,7 @@
#include <linux/firmware.h>
#include "gdm_sdio.h"
+#include "sdio_boot.h"
#define TYPE_A_HEADER_SIZE 4
#define TYPE_A_LOOKAHEAD_SIZE 16
diff --git a/drivers/staging/iio/Documentation/trigger.txt b/drivers/staging/iio/Documentation/trigger.txt
index 75cc37ff1ed0..64e2e08fb4d0 100644
--- a/drivers/staging/iio/Documentation/trigger.txt
+++ b/drivers/staging/iio/Documentation/trigger.txt
@@ -10,9 +10,6 @@ struct iio_trig *trig = iio_trigger_alloc("<trigger format string>", ...);
allocates a trigger structure. The key elements to then fill in within
a driver are:
-trig->private_data
- Device specific private data.
-
trig->owner
Typically set to THIS_MODULE. Used to ensure correct
ownership of core allocated resources.
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index dc267175a2b5..db4d6dc03243 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -4,14 +4,6 @@
menu "IIO staging drivers"
depends on IIO
-config IIO_ST_HWMON
- tristate "Hwmon driver that uses channels specified via iio maps"
- depends on HWMON
- help
- This is a platform driver that in combination with a suitable
- map allows IIO devices to provide basic hwmon functionality
- for those channels specified in the map.
-
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 158e0a017e7b..d87106135b27 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -9,8 +9,6 @@ iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
-obj-$(CONFIG_IIO_ST_HWMON) += iio_hwmon.o
-
obj-y += accel/
obj-y += adc/
obj-y += addac/
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index 9e5791ff2a04..ab8ec7af88b4 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -134,14 +134,14 @@ static const struct iio_chan_spec adis16201_channels[] = {
ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 12),
ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 8c235273ff13..b08ac8fdeee2 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -102,7 +102,7 @@ static const struct iio_chan_spec adis16203_channels[] = {
ADIS_SUPPLY_CHAN(ADIS16203_SUPPLY_OUT, ADIS16203_SCAN_SUPPLY, 12),
ADIS_AUX_ADC_CHAN(ADIS16203_AUX_ADC, ADIS16203_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16203_XINCL_OUT, ADIS16203_SCAN_INCLI_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
/* Fixme: Not what it appears to be - see data sheet */
ADIS_INCLI_CHAN(Y, ADIS16203_YINCL_OUT, ADIS16203_SCAN_INCLI_Y, 0, 14),
ADIS_TEMP_CHAN(ADIS16203_TEMP_OUT, ADIS16203_SCAN_TEMP, 12),
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index f3592668e066..792ec25a50dc 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -140,13 +140,11 @@ static const struct iio_chan_spec adis16204_channels[] = {
ADIS_AUX_ADC_CHAN(ADIS16204_AUX_ADC, ADIS16204_SCAN_AUX_ADC, 12),
ADIS_TEMP_CHAN(ADIS16204_TEMP_OUT, ADIS16204_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16204_XACCL_OUT, ADIS16204_SCAN_ACC_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), 14),
ADIS_ACCEL_CHAN(Y, ADIS16204_YACCL_OUT, ADIS16204_SCAN_ACC_Y,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), 14),
ADIS_ACCEL_CHAN(ROOT_SUM_SQUARED_X_Y, ADIS16204_XY_RSS_OUT,
- ADIS16204_SCAN_ACC_XY, IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 14),
+ ADIS16204_SCAN_ACC_XY, BIT(IIO_CHAN_INFO_PEAK), 14),
IIO_CHAN_SOFT_TIMESTAMP(5),
};
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index 69c50ee44ce3..323c169d699c 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -133,9 +133,9 @@ static const struct iio_chan_spec adis16209_channels[] = {
ADIS_SUPPLY_CHAN(ADIS16209_SUPPLY_OUT, ADIS16209_SCAN_SUPPLY, 14),
ADIS_TEMP_CHAN(ADIS16209_TEMP_OUT, ADIS16209_SCAN_TEMP, 12),
ADIS_ACCEL_CHAN(X, ADIS16209_XACCL_OUT, ADIS16209_SCAN_ACC_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
ADIS_ACCEL_CHAN(Y, ADIS16209_YACCL_OUT, ADIS16209_SCAN_ACC_Y,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, 14),
+ BIT(IIO_CHAN_INFO_CALIBBIAS), 14),
ADIS_AUX_ADC_CHAN(ADIS16209_AUX_ADC, ADIS16209_SCAN_AUX_ADC, 12),
ADIS_INCLI_CHAN(X, ADIS16209_XINCL_OUT, ADIS16209_SCAN_INCLI_X, 0, 14),
ADIS_INCLI_CHAN(Y, ADIS16209_YINCL_OUT, ADIS16209_SCAN_INCLI_Y, 0, 14),
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 370b01aa767a..0e72f795ed09 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -344,37 +344,37 @@ static const struct iio_chan_spec adis16220_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = in_supply,
}, {
.type = IIO_ACCEL,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_PEAK),
.address = accel,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = temp,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = in_1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = in_2,
}
};
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index e97fa0b0233d..fd1f0fd0fba8 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -176,14 +176,11 @@ static const struct iio_chan_spec adis16240_channels[] = {
ADIS_SUPPLY_CHAN(ADIS16240_SUPPLY_OUT, ADIS16240_SCAN_SUPPLY, 10),
ADIS_AUX_ADC_CHAN(ADIS16240_AUX_ADC, ADIS16240_SCAN_AUX_ADC, 10),
ADIS_ACCEL_CHAN(X, ADIS16240_XACCL_OUT, ADIS16240_SCAN_ACC_X,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), 10),
ADIS_ACCEL_CHAN(Y, ADIS16240_YACCL_OUT, ADIS16240_SCAN_ACC_Y,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), 10),
ADIS_ACCEL_CHAN(Z, ADIS16240_ZACCL_OUT, ADIS16240_SCAN_ACC_Z,
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT, 10),
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK), 10),
ADIS_TEMP_CHAN(ADIS16240_TEMP_OUT, ADIS16240_SCAN_TEMP, 10),
IIO_CHAN_SOFT_TIMESTAMP(6)
};
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 0e019306439c..1bfe5d81792b 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -501,12 +501,6 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
-#define LIS3L02DQ_INFO_MASK \
- (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT)
-
#define LIS3L02DQ_EVENT_MASK \
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
@@ -516,7 +510,10 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = mod, \
- .info_mask = LIS3L02DQ_INFO_MASK, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
.scan_index = index, \
.scan_type = { \
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index e676403ea3ea..5b8f0f6c9938 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -228,7 +228,7 @@ error_ret:
static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
int ret = 0;
u8 t;
@@ -252,7 +252,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
*/
static int lis3l02dq_trig_try_reen(struct iio_trigger *trig)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct lis3l02dq_state *st = iio_priv(indio_dev);
int i;
@@ -290,7 +290,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &lis3l02dq_trigger_ops;
- st->trig->private_data = indio_dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
if (ret)
goto error_free_trig;
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 14683f583ccf..32950ad94857 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -419,8 +419,6 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR,
static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
-#define SCA3000_INFO_MASK \
- IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT
#define SCA3000_EVENT_MASK \
(IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING))
@@ -429,7 +427,8 @@ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = mod, \
- .info_mask = SCA3000_INFO_MASK, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
.address = index, \
.scan_index = index, \
.scan_type = { \
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 7b2a01d64f5e..d990829008ff 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -90,13 +90,6 @@ config AD7192
To compile this driver as a module, choose M here: the
module will be called ad7192.
-config ADT7410
- tristate "Analog Devices ADT7310/ADT7410 temperature sensor driver"
- depends on I2C || SPI_MASTER
- help
- Say yes here to build support for Analog Devices ADT7310/ADT7410
- temperature sensors.
-
config AD7280
tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
depends on SPI
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index d285596272a0..3e9fb143d25b 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7780) += ad7780.o
obj-$(CONFIG_AD7816) += ad7816.o
obj-$(CONFIG_AD7192) += ad7192.o
-obj-$(CONFIG_ADT7410) += adt7410.o
obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 1f190c1b12a6..2fd6ee3c1902 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -503,9 +503,10 @@ static int ad7280_channel_init(struct ad7280_state *st)
st->channels[cnt].channel = (dev * 6) + ch - 6;
}
st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask =
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT;
+ st->channels[cnt].info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW);
+ st->channels[cnt].info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SCALE);
st->channels[cnt].address =
AD7280A_DEVADDR(dev) << 8 | ch;
st->channels[cnt].scan_index = cnt;
@@ -521,9 +522,8 @@ static int ad7280_channel_init(struct ad7280_state *st)
st->channels[cnt].channel2 = dev * 6;
st->channels[cnt].address = AD7280A_ALL_CELLS;
st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask =
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT;
+ st->channels[cnt].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ st->channels[cnt].info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
st->channels[cnt].scan_index = cnt;
st->channels[cnt].scan_type.sign = 'u';
st->channels[cnt].scan_type.realbits = 32;
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
index 6e58e36d242c..d088c662d5cd 100644
--- a/drivers/staging/iio/adc/ad7291.c
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -536,8 +536,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
#define AD7291_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = _chan, \
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\
@@ -555,9 +555,9 @@ static const struct iio_chan_spec ad7291_channels[] = {
AD7291_VOLTAGE_CHAN(7),
{
.type = IIO_TEMP,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = 0,
.event_mask =
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index bae61cbe9212..d104b4378424 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -235,8 +235,8 @@ static const struct attribute_group ad7606_attribute_group_range = {
.indexed = 1, \
.channel = num, \
.address = num, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
.scan_index = num, \
.scan_type = IIO_ST('s', 16, 16, 0), \
}
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 3e363c4ba211..b51680c1c331 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -87,7 +87,6 @@ struct ad799x_state;
* struct ad799x_chip_info - chip specifc information
* @channel: channel specification
* @num_channels: number of channels
- * @int_vref_mv: the internal reference voltage
* @monitor_mode: whether the chip supports monitor interrupts
* @default_config: device default configuration
* @event_attrs: pointer to the monitor event attribute group
@@ -96,7 +95,6 @@ struct ad799x_state;
struct ad799x_chip_info {
struct iio_chan_spec channel[9];
int num_channels;
- u16 int_vref_mv;
u16 default_config;
const struct iio_info *info;
};
@@ -104,12 +102,13 @@ struct ad799x_chip_info {
struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
- struct iio_trigger *trig;
struct regulator *reg;
u16 int_vref_mv;
unsigned id;
- char *name;
u16 config;
+
+ u8 *rx_buf;
+ unsigned int transfer_size;
};
/*
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index 077eedbd0a0c..8dc97b36e05a 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -48,13 +48,13 @@ static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data)
struct i2c_client *client = st->client;
int ret = 0;
- ret = i2c_smbus_read_word_data(client, reg);
+ ret = i2c_smbus_read_word_swapped(client, reg);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
- *data = swab16((u16)ret);
+ *data = (u16)ret;
return 0;
}
@@ -80,7 +80,7 @@ static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data)
struct i2c_client *client = st->client;
int ret = 0;
- ret = i2c_smbus_write_word_data(client, reg, swab16(data));
+ ret = i2c_smbus_write_word_swapped(client, reg, data);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
@@ -104,6 +104,13 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
{
struct ad799x_state *st = iio_priv(indio_dev);
+ kfree(st->rx_buf);
+ st->rx_buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ if (!st->rx_buf)
+ return -ENOMEM;
+
+ st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
+
switch (st->id) {
case ad7997:
case ad7998:
@@ -460,395 +467,114 @@ static const struct iio_info ad7993_4_7_8_info = {
#define AD799X_EV_MASK (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define AD799X_CHANNEL(_index, _realbits, _evmask) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_index = (_index), \
+ .scan_type = IIO_ST('u', _realbits, 16, 12 - (_realbits)), \
+ .event_mask = (_evmask), \
+}
+
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
[ad7991] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [4] = IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD799X_CHANNEL(0, 12, 0),
+ AD799X_CHANNEL(1, 12, 0),
+ AD799X_CHANNEL(2, 12, 0),
+ AD799X_CHANNEL(3, 12, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
},
.num_channels = 5,
- .int_vref_mv = 4096,
.info = &ad7991_info,
},
[ad7995] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [4] = IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD799X_CHANNEL(0, 10, 0),
+ AD799X_CHANNEL(1, 10, 0),
+ AD799X_CHANNEL(2, 10, 0),
+ AD799X_CHANNEL(3, 10, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
},
.num_channels = 5,
- .int_vref_mv = 1024,
.info = &ad7991_info,
},
[ad7999] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 8, 16, 4),
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 8, 16, 4),
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 8, 16, 4),
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 8, 16, 4),
- },
- [4] = IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD799X_CHANNEL(0, 8, 0),
+ AD799X_CHANNEL(1, 8, 0),
+ AD799X_CHANNEL(2, 8, 0),
+ AD799X_CHANNEL(3, 8, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
},
.num_channels = 5,
- .int_vref_mv = 1024,
.info = &ad7991_info,
},
[ad7992] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [2] = IIO_CHAN_SOFT_TIMESTAMP(2),
+ AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
},
.num_channels = 3,
- .int_vref_mv = 4096,
.default_config = AD7998_ALERT_EN,
.info = &ad7992_info,
},
[ad7993] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .scan_index = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [4] = IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD799X_CHANNEL(0, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(1, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(2, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(3, 10, AD799X_EV_MASK),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
},
.num_channels = 5,
- .int_vref_mv = 1024,
.default_config = AD7998_ALERT_EN,
.info = &ad7993_4_7_8_info,
},
[ad7994] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [4] = IIO_CHAN_SOFT_TIMESTAMP(4),
+ AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(2, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(3, 12, AD799X_EV_MASK),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
},
.num_channels = 5,
- .int_vref_mv = 4096,
.default_config = AD7998_ALERT_EN,
.info = &ad7993_4_7_8_info,
},
[ad7997] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 10, 16, 2),
- .event_mask = AD799X_EV_MASK,
- },
- [4] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 4,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 4,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [5] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 5,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 5,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [6] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 6,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 6,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [7] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 7,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 7,
- .scan_type = IIO_ST('u', 10, 16, 2),
- },
- [8] = IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD799X_CHANNEL(0, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(1, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(2, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(3, 10, AD799X_EV_MASK),
+ AD799X_CHANNEL(4, 10, 0),
+ AD799X_CHANNEL(5, 10, 0),
+ AD799X_CHANNEL(6, 10, 0),
+ AD799X_CHANNEL(7, 10, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
},
.num_channels = 9,
- .int_vref_mv = 1024,
.default_config = AD7998_ALERT_EN,
.info = &ad7993_4_7_8_info,
},
[ad7998] = {
.channel = {
- [0] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 0,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [1] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 1,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [2] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 2,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [3] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 3,
- .scan_type = IIO_ST('u', 12, 16, 0),
- .event_mask = AD799X_EV_MASK,
- },
- [4] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 4,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 4,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [5] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 5,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 5,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [6] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 6,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 6,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [7] = {
- .type = IIO_VOLTAGE,
- .indexed = 1,
- .channel = 7,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
- .scan_index = 7,
- .scan_type = IIO_ST('u', 12, 16, 0),
- },
- [8] = IIO_CHAN_SOFT_TIMESTAMP(8),
+ AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(2, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(3, 12, AD799X_EV_MASK),
+ AD799X_CHANNEL(4, 12, 0),
+ AD799X_CHANNEL(5, 12, 0),
+ AD799X_CHANNEL(6, 12, 0),
+ AD799X_CHANNEL(7, 12, 0),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
},
.num_channels = 9,
- .int_vref_mv = 4096,
.default_config = AD7998_ALERT_EN,
.info = &ad7993_4_7_8_info,
},
@@ -875,10 +601,10 @@ static int ad799x_probe(struct i2c_client *client,
/* TODO: Add pdata options for filtering and bit delay */
- if (pdata)
- st->int_vref_mv = pdata->vref_mv;
- else
- st->int_vref_mv = st->chip_info->int_vref_mv;
+ if (!pdata)
+ return -EINVAL;
+
+ st->int_vref_mv = pdata->vref_mv;
st->reg = regulator_get(&client->dev, "vcc");
if (!IS_ERR(st->reg)) {
@@ -946,6 +672,7 @@ static int ad799x_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
+ kfree(st->rx_buf);
iio_device_free(indio_dev);
return 0;
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 2c5f38475a8e..c2ebae12ee19 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -36,14 +36,9 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct ad799x_state *st = iio_priv(indio_dev);
s64 time_ns;
- __u8 *rxbuf;
int b_sent;
u8 cmd;
- rxbuf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (rxbuf == NULL)
- goto out;
-
switch (st->id) {
case ad7991:
case ad7995:
@@ -66,20 +61,17 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
}
b_sent = i2c_smbus_read_i2c_block_data(st->client,
- cmd, bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) * 2, rxbuf);
+ cmd, st->transfer_size, st->rx_buf);
if (b_sent < 0)
- goto done;
+ goto out;
time_ns = iio_get_time_ns();
if (indio_dev->scan_timestamp)
- memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
+ memcpy(st->rx_buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- iio_push_to_buffers(indio_dev, rxbuf);
-done:
- kfree(rxbuf);
+ iio_push_to_buffers(indio_dev, st->rx_buf);
out:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
deleted file mode 100644
index 35455e160945..000000000000
--- a/drivers/staging/iio/adc/adt7410.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * ADT7410 digital temperature sensor driver supporting ADT7310/ADT7410
- *
- * Copyright 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/sysfs.h>
-#include <linux/list.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-
-/*
- * ADT7410 registers definition
- */
-
-#define ADT7410_TEMPERATURE 0
-#define ADT7410_STATUS 2
-#define ADT7410_CONFIG 3
-#define ADT7410_T_ALARM_HIGH 4
-#define ADT7410_T_ALARM_LOW 6
-#define ADT7410_T_CRIT 8
-#define ADT7410_T_HYST 0xA
-#define ADT7410_ID 0xB
-#define ADT7410_RESET 0x2F
-
-/*
- * ADT7310 registers definition
- */
-
-#define ADT7310_STATUS 0
-#define ADT7310_CONFIG 1
-#define ADT7310_TEMPERATURE 2
-#define ADT7310_ID 3
-#define ADT7310_T_CRIT 4
-#define ADT7310_T_HYST 5
-#define ADT7310_T_ALARM_HIGH 6
-#define ADT7310_T_ALARM_LOW 7
-
-/*
- * ADT7410 status
- */
-#define ADT7410_STAT_T_LOW 0x10
-#define ADT7410_STAT_T_HIGH 0x20
-#define ADT7410_STAT_T_CRIT 0x40
-#define ADT7410_STAT_NOT_RDY 0x80
-
-/*
- * ADT7410 config
- */
-#define ADT7410_FAULT_QUEUE_MASK 0x3
-#define ADT7410_CT_POLARITY 0x4
-#define ADT7410_INT_POLARITY 0x8
-#define ADT7410_EVENT_MODE 0x10
-#define ADT7410_MODE_MASK 0x60
-#define ADT7410_ONESHOT 0x20
-#define ADT7410_SPS 0x40
-#define ADT7410_PD 0x60
-#define ADT7410_RESOLUTION 0x80
-
-/*
- * ADT7410 masks
- */
-#define ADT7410_T16_VALUE_SIGN 0x8000
-#define ADT7410_T16_VALUE_FLOAT_OFFSET 7
-#define ADT7410_T16_VALUE_FLOAT_MASK 0x7F
-#define ADT7410_T13_VALUE_SIGN 0x1000
-#define ADT7410_T13_VALUE_OFFSET 3
-#define ADT7410_T13_VALUE_FLOAT_OFFSET 4
-#define ADT7410_T13_VALUE_FLOAT_MASK 0xF
-#define ADT7410_T_HYST_MASK 0xF
-#define ADT7410_DEVICE_ID_MASK 0xF
-#define ADT7410_MANUFACTORY_ID_MASK 0xF0
-#define ADT7410_MANUFACTORY_ID_OFFSET 4
-
-
-#define ADT7310_CMD_REG_MASK 0x28
-#define ADT7310_CMD_REG_OFFSET 3
-#define ADT7310_CMD_READ 0x40
-#define ADT7310_CMD_CON_READ 0x4
-
-#define ADT7410_IRQS 2
-
-/*
- * struct adt7410_chip_info - chip specifc information
- */
-
-struct adt7410_chip_info;
-
-struct adt7410_ops {
- int (*read_word)(struct adt7410_chip_info *, u8 reg, u16 *data);
- int (*write_word)(struct adt7410_chip_info *, u8 reg, u16 data);
- int (*read_byte)(struct adt7410_chip_info *, u8 reg, u8 *data);
- int (*write_byte)(struct adt7410_chip_info *, u8 reg, u8 data);
-};
-
-struct adt7410_chip_info {
- struct device *dev;
- u8 config;
-
- const struct adt7410_ops *ops;
-};
-
-static int adt7410_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data)
-{
- return chip->ops->read_word(chip, reg, data);
-}
-
-static int adt7410_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data)
-{
- return chip->ops->write_word(chip, reg, data);
-}
-
-static int adt7410_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data)
-{
- return chip->ops->read_byte(chip, reg, data);
-}
-
-static int adt7410_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data)
-{
- return chip->ops->write_byte(chip, reg, data);
-}
-
-static ssize_t adt7410_show_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u8 config;
-
- config = chip->config & ADT7410_MODE_MASK;
-
- switch (config) {
- case ADT7410_PD:
- return sprintf(buf, "power-down\n");
- case ADT7410_ONESHOT:
- return sprintf(buf, "one-shot\n");
- case ADT7410_SPS:
- return sprintf(buf, "sps\n");
- default:
- return sprintf(buf, "full\n");
- }
-}
-
-static ssize_t adt7410_store_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u16 config;
- int ret;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- config = chip->config & (~ADT7410_MODE_MASK);
- if (strcmp(buf, "power-down"))
- config |= ADT7410_PD;
- else if (strcmp(buf, "one-shot"))
- config |= ADT7410_ONESHOT;
- else if (strcmp(buf, "sps"))
- config |= ADT7410_SPS;
-
- ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
- if (ret)
- return -EIO;
-
- chip->config = config;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
- adt7410_show_mode,
- adt7410_store_mode,
- 0);
-
-static ssize_t adt7410_show_available_modes(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "full\none-shot\nsps\npower-down\n");
-}
-
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0);
-
-static ssize_t adt7410_show_resolution(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- int ret;
- int bits;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- if (chip->config & ADT7410_RESOLUTION)
- bits = 16;
- else
- bits = 13;
-
- return sprintf(buf, "%d bits\n", bits);
-}
-
-static ssize_t adt7410_store_resolution(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- unsigned long data;
- u16 config;
- int ret;
-
- ret = strict_strtoul(buf, 10, &data);
- if (ret)
- return -EINVAL;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- config = chip->config & (~ADT7410_RESOLUTION);
- if (data)
- config |= ADT7410_RESOLUTION;
-
- ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
- if (ret)
- return -EIO;
-
- chip->config = config;
-
- return len;
-}
-
-static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
- adt7410_show_resolution,
- adt7410_store_resolution,
- 0);
-
-static ssize_t adt7410_show_id(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u8 id;
- int ret;
-
- ret = adt7410_read_byte(chip, ADT7410_ID, &id);
- if (ret)
- return -EIO;
-
- return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
- id & ADT7410_DEVICE_ID_MASK,
- (id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET);
-}
-
-static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
- adt7410_show_id,
- NULL,
- 0);
-
-static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip,
- u16 data, char *buf)
-{
- char sign = ' ';
-
- if (!(chip->config & ADT7410_RESOLUTION))
- data &= ~0x7;
-
- if (data & ADT7410_T16_VALUE_SIGN) {
- /* convert supplement to positive value */
- data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
- sign = '-';
- }
- return sprintf(buf, "%c%d.%.7d\n", sign,
- (data >> ADT7410_T16_VALUE_FLOAT_OFFSET),
- (data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125);
-}
-
-static ssize_t adt7410_show_value(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u8 status;
- u16 data;
- int ret, i = 0;
-
- do {
- ret = adt7410_read_byte(chip, ADT7410_STATUS, &status);
- if (ret)
- return -EIO;
- i++;
- if (i == 10000)
- return -EIO;
- } while (status & ADT7410_STAT_NOT_RDY);
-
- ret = adt7410_read_word(chip, ADT7410_TEMPERATURE, &data);
- if (ret)
- return -EIO;
-
- return adt7410_convert_temperature(chip, data, buf);
-}
-
-static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0);
-
-static struct attribute *adt7410_attributes[] = {
- &iio_dev_attr_available_modes.dev_attr.attr,
- &iio_dev_attr_mode.dev_attr.attr,
- &iio_dev_attr_resolution.dev_attr.attr,
- &iio_dev_attr_id.dev_attr.attr,
- &iio_dev_attr_value.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group adt7410_attribute_group = {
- .attrs = adt7410_attributes,
-};
-
-static irqreturn_t adt7410_event_handler(int irq, void *private)
-{
- struct iio_dev *indio_dev = private;
- struct adt7410_chip_info *chip = iio_priv(indio_dev);
- s64 timestamp = iio_get_time_ns();
- u8 status;
-
- if (adt7410_read_byte(chip, ADT7410_STATUS, &status))
- return IRQ_HANDLED;
-
- if (status & ADT7410_STAT_T_HIGH)
- iio_push_event(indio_dev,
- IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_RISING),
- timestamp);
- if (status & ADT7410_STAT_T_LOW)
- iio_push_event(indio_dev,
- IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_FALLING),
- timestamp);
- if (status & ADT7410_STAT_T_CRIT)
- iio_push_event(indio_dev,
- IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0,
- IIO_EV_TYPE_THRESH,
- IIO_EV_DIR_RISING),
- timestamp);
-
- return IRQ_HANDLED;
-}
-
-static ssize_t adt7410_show_event_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- int ret;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- if (chip->config & ADT7410_EVENT_MODE)
- return sprintf(buf, "interrupt\n");
- else
- return sprintf(buf, "comparator\n");
-}
-
-static ssize_t adt7410_set_event_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u16 config;
- int ret;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- config = chip->config &= ~ADT7410_EVENT_MODE;
- if (strcmp(buf, "comparator") != 0)
- config |= ADT7410_EVENT_MODE;
-
- ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
- if (ret)
- return -EIO;
-
- chip->config = config;
-
- return ret;
-}
-
-static ssize_t adt7410_show_available_event_modes(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "comparator\ninterrupt\n");
-}
-
-static ssize_t adt7410_show_fault_queue(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- int ret;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK);
-}
-
-static ssize_t adt7410_set_fault_queue(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- unsigned long data;
- int ret;
- u8 config;
-
- ret = strict_strtoul(buf, 10, &data);
- if (ret || data > 3)
- return -EINVAL;
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret)
- return -EIO;
-
- config = chip->config & ~ADT7410_FAULT_QUEUE_MASK;
- config |= data;
- ret = adt7410_write_byte(chip, ADT7410_CONFIG, config);
- if (ret)
- return -EIO;
-
- chip->config = config;
-
- return ret;
-}
-
-static inline ssize_t adt7410_show_t_bound(struct device *dev,
- struct device_attribute *attr,
- u8 bound_reg,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- u16 data;
- int ret;
-
- ret = adt7410_read_word(chip, bound_reg, &data);
- if (ret)
- return -EIO;
-
- return adt7410_convert_temperature(chip, data, buf);
-}
-
-static inline ssize_t adt7410_set_t_bound(struct device *dev,
- struct device_attribute *attr,
- u8 bound_reg,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- long tmp1, tmp2;
- u16 data;
- char *pos;
- int ret;
-
- pos = strchr(buf, '.');
-
- ret = strict_strtol(buf, 10, &tmp1);
-
- if (ret || tmp1 > 127 || tmp1 < -128)
- return -EINVAL;
-
- if (pos) {
- len = strlen(pos);
-
- if (chip->config & ADT7410_RESOLUTION) {
- if (len > ADT7410_T16_VALUE_FLOAT_OFFSET)
- len = ADT7410_T16_VALUE_FLOAT_OFFSET;
- pos[len] = 0;
- ret = strict_strtol(pos, 10, &tmp2);
-
- if (!ret)
- tmp2 = (tmp2 / 78125) * 78125;
- } else {
- if (len > ADT7410_T13_VALUE_FLOAT_OFFSET)
- len = ADT7410_T13_VALUE_FLOAT_OFFSET;
- pos[len] = 0;
- ret = strict_strtol(pos, 10, &tmp2);
-
- if (!ret)
- tmp2 = (tmp2 / 625) * 625;
- }
- }
-
- if (tmp1 < 0)
- data = (u16)(-tmp1);
- else
- data = (u16)tmp1;
-
- if (chip->config & ADT7410_RESOLUTION) {
- data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) |
- (tmp2 & ADT7410_T16_VALUE_FLOAT_MASK);
-
- if (tmp1 < 0)
- /* convert positive value to supplyment */
- data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
- } else {
- data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) |
- (tmp2 & ADT7410_T13_VALUE_FLOAT_MASK);
-
- if (tmp1 < 0)
- /* convert positive value to supplyment */
- data = (ADT7410_T13_VALUE_SIGN << 1) - data;
- data <<= ADT7410_T13_VALUE_OFFSET;
- }
-
- ret = adt7410_write_word(chip, bound_reg, data);
- if (ret)
- return -EIO;
-
- return ret;
-}
-
-static ssize_t adt7410_show_t_alarm_high(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return adt7410_show_t_bound(dev, attr,
- ADT7410_T_ALARM_HIGH, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_high(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return adt7410_set_t_bound(dev, attr,
- ADT7410_T_ALARM_HIGH, buf, len);
-}
-
-static ssize_t adt7410_show_t_alarm_low(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return adt7410_show_t_bound(dev, attr,
- ADT7410_T_ALARM_LOW, buf);
-}
-
-static inline ssize_t adt7410_set_t_alarm_low(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return adt7410_set_t_bound(dev, attr,
- ADT7410_T_ALARM_LOW, buf, len);
-}
-
-static ssize_t adt7410_show_t_crit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return adt7410_show_t_bound(dev, attr,
- ADT7410_T_CRIT, buf);
-}
-
-static inline ssize_t adt7410_set_t_crit(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- return adt7410_set_t_bound(dev, attr,
- ADT7410_T_CRIT, buf, len);
-}
-
-static ssize_t adt7410_show_t_hyst(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- int ret;
- u8 t_hyst;
-
- ret = adt7410_read_byte(chip, ADT7410_T_HYST, &t_hyst);
- if (ret)
- return -EIO;
-
- return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK);
-}
-
-static inline ssize_t adt7410_set_t_hyst(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- struct iio_dev *dev_info = dev_to_iio_dev(dev);
- struct adt7410_chip_info *chip = iio_priv(dev_info);
- int ret;
- unsigned long data;
- u8 t_hyst;
-
- ret = strict_strtol(buf, 10, &data);
-
- if (ret || data > ADT7410_T_HYST_MASK)
- return -EINVAL;
-
- t_hyst = (u8)data;
-
- ret = adt7410_write_byte(chip, ADT7410_T_HYST, t_hyst);
- if (ret)
- return -EIO;
-
- return ret;
-}
-
-static IIO_DEVICE_ATTR(event_mode,
- S_IRUGO | S_IWUSR,
- adt7410_show_event_mode, adt7410_set_event_mode, 0);
-static IIO_DEVICE_ATTR(available_event_modes,
- S_IRUGO,
- adt7410_show_available_event_modes, NULL, 0);
-static IIO_DEVICE_ATTR(fault_queue,
- S_IRUGO | S_IWUSR,
- adt7410_show_fault_queue, adt7410_set_fault_queue, 0);
-static IIO_DEVICE_ATTR(t_alarm_high,
- S_IRUGO | S_IWUSR,
- adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0);
-static IIO_DEVICE_ATTR(t_alarm_low,
- S_IRUGO | S_IWUSR,
- adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0);
-static IIO_DEVICE_ATTR(t_crit,
- S_IRUGO | S_IWUSR,
- adt7410_show_t_crit, adt7410_set_t_crit, 0);
-static IIO_DEVICE_ATTR(t_hyst,
- S_IRUGO | S_IWUSR,
- adt7410_show_t_hyst, adt7410_set_t_hyst, 0);
-
-static struct attribute *adt7410_event_int_attributes[] = {
- &iio_dev_attr_event_mode.dev_attr.attr,
- &iio_dev_attr_available_event_modes.dev_attr.attr,
- &iio_dev_attr_fault_queue.dev_attr.attr,
- &iio_dev_attr_t_alarm_high.dev_attr.attr,
- &iio_dev_attr_t_alarm_low.dev_attr.attr,
- &iio_dev_attr_t_crit.dev_attr.attr,
- &iio_dev_attr_t_hyst.dev_attr.attr,
- NULL,
-};
-
-static struct attribute_group adt7410_event_attribute_group = {
- .attrs = adt7410_event_int_attributes,
- .name = "events",
-};
-
-static const struct iio_info adt7410_info = {
- .attrs = &adt7410_attribute_group,
- .event_attrs = &adt7410_event_attribute_group,
- .driver_module = THIS_MODULE,
-};
-
-/*
- * device probe and remove
- */
-
-static int adt7410_probe(struct device *dev, int irq,
- const char *name, const struct adt7410_ops *ops)
-{
- unsigned long *adt7410_platform_data = dev->platform_data;
- unsigned long local_pdata[] = {0, 0};
- struct adt7410_chip_info *chip;
- struct iio_dev *indio_dev;
- int ret = 0;
-
- indio_dev = iio_device_alloc(sizeof(*chip));
- if (indio_dev == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
- chip = iio_priv(indio_dev);
- /* this is only used for device removal purposes */
- dev_set_drvdata(dev, indio_dev);
-
- chip->dev = dev;
- chip->ops = ops;
-
- indio_dev->name = name;
- indio_dev->dev.parent = dev;
- indio_dev->info = &adt7410_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
-
- if (!adt7410_platform_data)
- adt7410_platform_data = local_pdata;
-
- /* CT critcal temperature event. line 0 */
- if (irq) {
- ret = request_threaded_irq(irq,
- NULL,
- &adt7410_event_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- name,
- indio_dev);
- if (ret)
- goto error_free_dev;
- }
-
- /* INT bound temperature alarm event. line 1 */
- if (adt7410_platform_data[0]) {
- ret = request_threaded_irq(adt7410_platform_data[0],
- NULL,
- &adt7410_event_handler,
- adt7410_platform_data[1] |
- IRQF_ONESHOT,
- name,
- indio_dev);
- if (ret)
- goto error_unreg_ct_irq;
- }
-
- ret = adt7410_read_byte(chip, ADT7410_CONFIG, &chip->config);
- if (ret) {
- ret = -EIO;
- goto error_unreg_int_irq;
- }
-
- chip->config |= ADT7410_RESOLUTION;
-
- if (irq && adt7410_platform_data[0]) {
-
- /* set irq polarity low level */
- chip->config &= ~ADT7410_CT_POLARITY;
-
- if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH)
- chip->config |= ADT7410_INT_POLARITY;
- else
- chip->config &= ~ADT7410_INT_POLARITY;
- }
-
- ret = adt7410_write_byte(chip, ADT7410_CONFIG, chip->config);
- if (ret) {
- ret = -EIO;
- goto error_unreg_int_irq;
- }
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_unreg_int_irq;
-
- dev_info(dev, "%s temperature sensor registered.\n",
- name);
-
- return 0;
-
-error_unreg_int_irq:
- free_irq(adt7410_platform_data[0], indio_dev);
-error_unreg_ct_irq:
- free_irq(irq, indio_dev);
-error_free_dev:
- iio_device_free(indio_dev);
-error_ret:
- return ret;
-}
-
-static int adt7410_remove(struct device *dev, int irq)
-{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
- unsigned long *adt7410_platform_data = dev->platform_data;
-
- iio_device_unregister(indio_dev);
- if (adt7410_platform_data[0])
- free_irq(adt7410_platform_data[0], indio_dev);
- if (irq)
- free_irq(irq, indio_dev);
- iio_device_free(indio_dev);
-
- return 0;
-}
-
-#if IS_ENABLED(CONFIG_I2C)
-
-static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg,
- u16 *data)
-{
- struct i2c_client *client = to_i2c_client(chip->dev);
- int ret = 0;
-
- ret = i2c_smbus_read_word_data(client, reg);
- if (ret < 0) {
- dev_err(&client->dev, "I2C read error\n");
- return ret;
- }
-
- *data = swab16((u16)ret);
-
- return 0;
-}
-
-static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg,
- u16 data)
-{
- struct i2c_client *client = to_i2c_client(chip->dev);
- int ret = 0;
-
- ret = i2c_smbus_write_word_data(client, reg, swab16(data));
- if (ret < 0)
- dev_err(&client->dev, "I2C write error\n");
-
- return ret;
-}
-
-static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg,
- u8 *data)
-{
- struct i2c_client *client = to_i2c_client(chip->dev);
- int ret = 0;
-
- ret = i2c_smbus_read_byte_data(client, reg);
- if (ret < 0) {
- dev_err(&client->dev, "I2C read error\n");
- return ret;
- }
-
- *data = (u8)ret;
-
- return 0;
-}
-
-static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg,
- u8 data)
-{
- struct i2c_client *client = to_i2c_client(chip->dev);
- int ret = 0;
-
- ret = i2c_smbus_write_byte_data(client, reg, data);
- if (ret < 0)
- dev_err(&client->dev, "I2C write error\n");
-
- return ret;
-}
-
-static const struct adt7410_ops adt7410_i2c_ops = {
- .read_word = adt7410_i2c_read_word,
- .write_word = adt7410_i2c_write_word,
- .read_byte = adt7410_i2c_read_byte,
- .write_byte = adt7410_i2c_write_byte,
-};
-
-static int adt7410_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- return adt7410_probe(&client->dev, client->irq, id->name,
- &adt7410_i2c_ops);
-}
-
-static int adt7410_i2c_remove(struct i2c_client *client)
-{
- return adt7410_remove(&client->dev, client->irq);
-}
-
-static const struct i2c_device_id adt7410_id[] = {
- { "adt7410", 0 },
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, adt7410_id);
-
-static struct i2c_driver adt7410_driver = {
- .driver = {
- .name = "adt7410",
- },
- .probe = adt7410_i2c_probe,
- .remove = adt7410_i2c_remove,
- .id_table = adt7410_id,
-};
-
-static int __init adt7410_i2c_init(void)
-{
- return i2c_add_driver(&adt7410_driver);
-}
-
-static void __exit adt7410_i2c_exit(void)
-{
- i2c_del_driver(&adt7410_driver);
-}
-
-#else
-
-static int __init adt7410_i2c_init(void) { return 0; };
-static void __exit adt7410_i2c_exit(void) {};
-
-#endif
-
-#if IS_ENABLED(CONFIG_SPI_MASTER)
-
-static const u8 adt7371_reg_table[] = {
- [ADT7410_TEMPERATURE] = ADT7310_TEMPERATURE,
- [ADT7410_STATUS] = ADT7310_STATUS,
- [ADT7410_CONFIG] = ADT7310_CONFIG,
- [ADT7410_T_ALARM_HIGH] = ADT7310_T_ALARM_HIGH,
- [ADT7410_T_ALARM_LOW] = ADT7310_T_ALARM_LOW,
- [ADT7410_T_CRIT] = ADT7310_T_CRIT,
- [ADT7410_T_HYST] = ADT7310_T_HYST,
- [ADT7410_ID] = ADT7310_ID,
-};
-
-#define AD7310_COMMAND(reg) (adt7371_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
-
-static int adt7310_spi_read_word(struct adt7410_chip_info *chip,
- u8 reg, u16 *data)
-{
- struct spi_device *spi = to_spi_device(chip->dev);
- u8 command = AD7310_COMMAND(reg);
- int ret = 0;
-
- command |= ADT7310_CMD_READ;
- ret = spi_write(spi, &command, sizeof(command));
- if (ret < 0) {
- dev_err(&spi->dev, "SPI write command error\n");
- return ret;
- }
-
- ret = spi_read(spi, (u8 *)data, sizeof(*data));
- if (ret < 0) {
- dev_err(&spi->dev, "SPI read word error\n");
- return ret;
- }
-
- *data = be16_to_cpu(*data);
-
- return 0;
-}
-
-static int adt7310_spi_write_word(struct adt7410_chip_info *chip, u8 reg,
- u16 data)
-{
- struct spi_device *spi = to_spi_device(chip->dev);
- u8 buf[3];
- int ret = 0;
-
- buf[0] = AD7310_COMMAND(reg);
- buf[1] = (u8)(data >> 8);
- buf[2] = (u8)(data & 0xFF);
-
- ret = spi_write(spi, buf, 3);
- if (ret < 0) {
- dev_err(&spi->dev, "SPI write word error\n");
- return ret;
- }
-
- return ret;
-}
-
-static int adt7310_spi_read_byte(struct adt7410_chip_info *chip, u8 reg,
- u8 *data)
-{
- struct spi_device *spi = to_spi_device(chip->dev);
- u8 command = AD7310_COMMAND(reg);
- int ret = 0;
-
- command |= ADT7310_CMD_READ;
- ret = spi_write(spi, &command, sizeof(command));
- if (ret < 0) {
- dev_err(&spi->dev, "SPI write command error\n");
- return ret;
- }
-
- ret = spi_read(spi, data, sizeof(*data));
- if (ret < 0) {
- dev_err(&spi->dev, "SPI read byte error\n");
- return ret;
- }
-
- return 0;
-}
-
-static int adt7310_spi_write_byte(struct adt7410_chip_info *chip, u8 reg,
- u8 data)
-{
- struct spi_device *spi = to_spi_device(chip->dev);
- u8 buf[2];
- int ret = 0;
-
- buf[0] = AD7310_COMMAND(reg);
- buf[1] = data;
-
- ret = spi_write(spi, buf, 2);
- if (ret < 0) {
- dev_err(&spi->dev, "SPI write byte error\n");
- return ret;
- }
-
- return ret;
-}
-
-static const struct adt7410_ops adt7310_spi_ops = {
- .read_word = adt7310_spi_read_word,
- .write_word = adt7310_spi_write_word,
- .read_byte = adt7310_spi_read_byte,
- .write_byte = adt7310_spi_write_byte,
-};
-
-static int adt7310_spi_probe(struct spi_device *spi)
-{
- return adt7410_probe(&spi->dev, spi->irq,
- spi_get_device_id(spi)->name, &adt7310_spi_ops);
-}
-
-static int adt7310_spi_remove(struct spi_device *spi)
-{
- return adt7410_remove(&spi->dev, spi->irq);
-}
-
-static const struct spi_device_id adt7310_id[] = {
- { "adt7310", 0 },
- {}
-};
-MODULE_DEVICE_TABLE(spi, adt7310_id);
-
-static struct spi_driver adt7310_driver = {
- .driver = {
- .name = "adt7310",
- .owner = THIS_MODULE,
- },
- .probe = adt7310_spi_probe,
- .remove = adt7310_spi_remove,
- .id_table = adt7310_id,
-};
-
-static int __init adt7310_spi_init(void)
-{
- return spi_register_driver(&adt7310_driver);
-}
-
-static void adt7310_spi_exit(void)
-{
- spi_unregister_driver(&adt7310_driver);
-}
-
-#else
-
-static int __init adt7310_spi_init(void) { return 0; };
-static void adt7310_spi_exit(void) {};
-
-#endif
-
-static int __init adt7410_init(void)
-{
- int ret;
-
- ret = adt7310_spi_init();
- if (ret)
- return ret;
-
- ret = adt7410_i2c_init();
- if (ret)
- adt7310_spi_exit();
-
- return ret;
-}
-module_init(adt7410_init);
-
-static void __exit adt7410_exit(void)
-{
- adt7410_i2c_exit();
- adt7310_spi_exit();
-}
-module_exit(adt7410_exit);
-
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("Analog Devices ADT7310/ADT7410 digital temperature sensor driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index 0bf2a6cc79e0..2f2f7fdd0691 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -103,7 +103,7 @@ static const struct iio_info lpc32xx_adc_iio_info = {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.address = AD_IN * _index, \
.scan_index = _index, \
}
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index 55a459b61907..6044e1717b20 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -646,7 +646,7 @@ static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p)
static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state)
{
- struct iio_dev *iio = trig->private_data;
+ struct iio_dev *iio = iio_trigger_get_drvdata(trig);
struct mxs_lradc *lradc = iio_priv(iio);
const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
@@ -670,7 +670,7 @@ static int mxs_lradc_trigger_init(struct iio_dev *iio)
return -ENOMEM;
trig->dev.parent = iio->dev.parent;
- trig->private_data = iio;
+ iio_trigger_set_drvdata(trig, iio);
trig->ops = &mxs_lradc_trigger_ops;
ret = iio_trigger_register(trig);
@@ -822,7 +822,7 @@ static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
.type = (chan_type), \
.indexed = 1, \
.scan_index = (idx), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.channel = (idx), \
.scan_type = { \
.sign = 'u', \
@@ -983,6 +983,9 @@ static int mxs_lradc_probe(struct platform_device *pdev)
if (ret)
goto err_trig;
+ /* Configure the hardware. */
+ mxs_lradc_hw_init(lradc);
+
/* Register the touchscreen input device. */
ret = mxs_lradc_ts_register(lradc);
if (ret)
@@ -995,9 +998,6 @@ static int mxs_lradc_probe(struct platform_device *pdev)
goto err_ts;
}
- /* Configure the hardware. */
- mxs_lradc_hw_init(lradc);
-
return 0;
err_ts:
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
index 13052ceb2f2b..f45da4266950 100644
--- a/drivers/staging/iio/adc/spear_adc.c
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -180,8 +180,8 @@ static int spear_read_raw(struct iio_dev *indio_dev,
#define SPEAR_ADC_CHAN(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.channel = idx, \
.scan_type = { \
.sign = 'u', \
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index 0b431bc4f627..506b5a7d96c8 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -256,7 +256,7 @@ static ssize_t adt7316_store_enabled(struct device *dev,
struct adt7316_chip_info *chip = iio_priv(dev_info);
int enable;
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
enable = 1;
else
enable = 0;
@@ -299,7 +299,7 @@ static ssize_t adt7316_store_select_ex_temp(struct device *dev,
return -EPERM;
config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config1 |= ADT7516_SEL_EX_TEMP;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
@@ -495,7 +495,7 @@ static ssize_t adt7316_store_disable_averaging(struct device *dev,
int ret;
config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config2 |= ADT7316_DISABLE_AVERAGING;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
@@ -534,7 +534,7 @@ static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
int ret;
config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config2 |= ADT7316_EN_SMBUS_TIMEOUT;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
@@ -597,7 +597,7 @@ static ssize_t adt7316_store_powerdown(struct device *dev,
int ret;
config1 = chip->config1 & (~ADT7316_PD);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config1 |= ADT7316_PD;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
@@ -635,7 +635,7 @@ static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
int ret;
config3 = chip->config3 & (~ADT7316_ADCLK_22_5);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config3 |= ADT7316_ADCLK_22_5;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
@@ -681,7 +681,7 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev,
chip->dac_bits = 8;
- if (!memcmp(buf, "1", 1)) {
+ if (buf[0] == '1') {
config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION;
if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
chip->dac_bits = 12;
@@ -731,7 +731,7 @@ static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
return -EPERM;
- if (memcmp(buf, "1", 1))
+ if (buf[0] != '1')
config3 = chip->config3 & (~ADT7516_AIN_IN_VREF);
else
config3 = chip->config3 | ADT7516_AIN_IN_VREF;
@@ -773,7 +773,7 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
int ret;
config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config3 |= ADT7316_EN_IN_TEMP_PROP_DACA;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
@@ -812,7 +812,7 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
int ret;
config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config3 |= ADT7316_EN_EX_TEMP_PROP_DACB;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
@@ -1018,7 +1018,7 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
return -EPERM;
dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
dac_config |= ADT7316_VREF_BYPASS_DAC_AB;
ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
@@ -1063,7 +1063,7 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
return -EPERM;
dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
dac_config |= ADT7316_VREF_BYPASS_DAC_CD;
ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
@@ -1982,7 +1982,7 @@ static ssize_t adt7316_set_int_enabled(struct device *dev,
int ret;
config1 = chip->config1 & (~ADT7316_INT_EN);
- if (!memcmp(buf, "1", 1))
+ if (buf[0] == '1')
config1 |= ADT7316_INT_EN;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index 3c608c14dd99..687dd2c91437 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -429,8 +429,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW),
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -442,8 +442,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW),
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index 3c92ba3722a8..1d7c5283a85c 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -436,38 +436,38 @@ static const struct iio_chan_spec ad7152_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_CAPACITANCE,
.differential = 1,
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_CAPACITANCE,
.differential = 1,
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
}
};
/*
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 466b82ecfbe0..94f9ca726d1c 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -123,8 +123,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_VIN,
},
@@ -133,8 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_VDD_MON,
},
@@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_INT_TEMP,
},
@@ -150,7 +150,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_TEMP,
},
@@ -158,11 +158,10 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_CAP_DATA_HIGH << 8,
},
[CIN1_DIFF] = {
@@ -171,11 +170,10 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_CAP_DATA_HIGH << 8 |
AD7746_CAPSETUP_CAPDIFF
},
@@ -183,11 +181,10 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_CAP_DATA_HIGH << 8 |
AD7746_CAPSETUP_CIN2,
},
@@ -197,11 +194,10 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD7746_REG_CAP_DATA_HIGH << 8 |
AD7746_CAPSETUP_CAPDIFF | AD7746_CAPSETUP_CIN2,
}
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index 687c151f9847..c67d3a832aef 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -120,27 +120,26 @@ static const struct iio_chan_spec adis16060_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16060_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
.address = ADIS16060_TEMP_OUT,
}
};
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index 835801ee7e80..531b803cb2ac 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -100,13 +100,13 @@ static const struct iio_chan_spec adis16130_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16130_RATEDATA,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.address = ADIS16130_TEMPDATA,
}
};
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 6e80b8c768ae..620d63fd099b 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -124,8 +124,8 @@ static IIO_DEVICE_ATTR(sampling_frequency_available,
#define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \
struct iio_chan_spec adis16260_channels_##axis[] = { \
ADIS_GYRO_CHAN(mod, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, 14), \
+ BIT(IIO_CHAN_INFO_CALIBBIAS) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE), 14), \
ADIS_INCLI_CHAN(mod, ADIS16260_ANGL_OUT, ADIS16260_SCAN_ANGL, 0, 14), \
ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, 12), \
ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, 12), \
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index aee76c710a3b..0e8e02a3cf5b 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -71,25 +71,25 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
.indexed = 1,
.channel = 0,
/* What other information is available? */
- .info_mask =
+ .info_mask_separate =
/*
* in_voltage0_raw
* Raw (unscaled no bias removal etc) measurement
* from the device.
*/
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ BIT(IIO_CHAN_INFO_RAW) |
/*
* in_voltage0_offset
* Offset for userspace to apply prior to scale
* when converting to standard units (microvolts)
*/
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ BIT(IIO_CHAN_INFO_OFFSET) |
/*
* in_voltage0_scale
* Multipler for userspace to apply post offset
* when converting to standard units (microvolts)
*/
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ BIT(IIO_CHAN_INFO_SCALE),
/* The ordering of elements in the buffer via an enum */
.scan_index = voltage0,
.scan_type = { /* Description of storage in buffer */
@@ -118,19 +118,18 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 2,
- .info_mask =
/*
* in_voltage1-voltage2_raw
* Raw (unscaled no bias removal etc) measurement
* from the device.
*/
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
/*
* in_voltage-voltage_scale
* Shared version of scale - shared by differential
* input channels of type IIO_VOLTAGE.
*/
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_index = diffvoltage1m2,
.scan_type = { /* Description of storage in buffer */
.sign = 's', /* signed */
@@ -146,9 +145,8 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
.indexed = 1,
.channel = 3,
.channel2 = 4,
- .info_mask =
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_index = diffvoltage3m4,
.scan_type = {
.sign = 's',
@@ -166,15 +164,15 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
.modified = 1,
/* Channel 2 is use for modifiers */
.channel2 = IIO_MOD_X,
- .info_mask =
- IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
/*
- * Internal bias correction value. Applied
+ * Internal bias and gain correction values. Applied
* by the hardware or driver prior to userspace
* seeing the readings. Typically part of hardware
* calibration.
*/
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.scan_index = accelx,
.scan_type = { /* Description of storage in buffer */
.sign = 's', /* signed */
@@ -191,7 +189,7 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
/* DAC channel out_voltage0_raw */
{
.type = IIO_VOLTAGE,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.output = 1,
.indexed = 1,
.channel = 0,
@@ -204,8 +202,8 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
* @chan: the channel whose data is to be read
* @val: first element of returned value (typically INT)
* @val2: second element of returned value (typically MICRO)
- * @mask: what we actually want to read. 0 is the channel, everything else
- * is as per the info_mask in iio_chan_spec.
+ * @mask: what we actually want to read as per the info_mask_*
+ * in iio_chan_spec.
*/
static int iio_dummy_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@@ -287,8 +285,8 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
* @chan: the channel whose data is to be written
* @val: first element of value to set (typically INT)
* @val2: second element of value to set (typically MICRO)
- * @mask: what we actually want to write. 0 is the channel, everything else
- * is as per the info_mask in iio_chan_spec.
+ * @mask: what we actually want to write as per the info_mask_*
+ * in iio_chan_spec.
*
* Note that all raw writes are assumed IIO_VAL_INT and info mask elements
* are assumed to be IIO_INT_PLUS_MICRO unless the callback write_raw_get_fmt
@@ -314,7 +312,7 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
st->dac_val = val;
mutex_unlock(&st->lock);
return 0;
- case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE:
mutex_lock(&st->lock);
/* Compare against table - hard matching here */
for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
@@ -327,6 +325,12 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
st->accel_calibscale = &dummy_scales[i];
mutex_unlock(&st->lock);
return ret;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ mutex_lock(&st->lock);
+ st->accel_calibbias = val;
+ mutex_unlock(&st->lock);
+ return 0;
+
default:
return -EINVAL;
}
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index 440e2261e8cb..6330af656a0f 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -113,7 +113,7 @@ static const struct iio_chan_spec ad5933_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.address = AD5933_REG_TEMP_DATA,
.scan_type = {
.sign = 's',
@@ -125,8 +125,8 @@ static const struct iio_chan_spec ad5933_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "real_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD5933_REG_REAL_DATA,
.scan_index = 0,
.scan_type = {
@@ -139,8 +139,8 @@ static const struct iio_chan_spec ad5933_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "imag_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD5933_REG_IMAG_DATA,
.scan_index = 1,
.scan_type = {
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index b0adac0bf5d5..82478a59e42e 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -412,17 +412,17 @@ static const struct iio_chan_spec isl29018_channels[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
}, {
.type = IIO_INTENSITY,
.modified = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.channel2 = IIO_MOD_LIGHT_IR,
}, {
/* Unindexed in current ABI. But perhaps it should be. */
.type = IIO_PROXIMITY,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index e52af77f7782..8bb0d03627f2 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -391,15 +391,15 @@ static const struct attribute_group isl29108_group = {
static const struct iio_chan_spec isl29028_channels[] = {
{
.type = IIO_LIGHT,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_SCALE),
}, {
.type = IIO_INTENSITY,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}, {
.type = IIO_PROXIMITY,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
}
};
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index a58731e70bb9..d060f2572512 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -1733,14 +1733,14 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_mask = TSL2X7X_EVENT_MASK
}, {
.type = IIO_INTENSITY,
@@ -1757,7 +1757,7 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_PROXIMITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.event_mask = TSL2X7X_EVENT_MASK
},
},
@@ -1770,25 +1770,25 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_mask = TSL2X7X_EVENT_MASK
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}, {
.type = IIO_PROXIMITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.event_mask = TSL2X7X_EVENT_MASK
},
},
@@ -1801,8 +1801,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_PROXIMITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
.event_mask = TSL2X7X_EVENT_MASK
},
},
@@ -1815,26 +1815,26 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
.event_mask = TSL2X7X_EVENT_MASK
}, {
.type = IIO_INTENSITY,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}, {
.type = IIO_PROXIMITY,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE),
.event_mask = TSL2X7X_EVENT_MASK
},
},
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index df5e0d4ea295..a3ea69e9d800 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -3,17 +3,6 @@
#
menu "Magnetometer sensors"
-config SENSORS_AK8975
- tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
- depends on I2C
- depends on GPIOLIB
- help
- Say yes here to build support for Asahi Kasei AK8975 3-Axis
- Magnetometer.
-
- To compile this driver as a module, choose M here: the module
- will be called ak8975.
-
config SENSORS_HMC5843
tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
depends on I2C
diff --git a/drivers/staging/iio/magnetometer/Makefile b/drivers/staging/iio/magnetometer/Makefile
index f2a753f80796..f9bfb2e11d7d 100644
--- a/drivers/staging/iio/magnetometer/Makefile
+++ b/drivers/staging/iio/magnetometer/Makefile
@@ -2,5 +2,4 @@
# Makefile for industrial I/O Magnetometer sensors
#
-obj-$(CONFIG_SENSORS_AK8975) += ak8975.o
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index 1a520ecfa3e2..86c6bf9d5dd8 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -564,8 +564,8 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = add \
}
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index 53c68dcc4544..8f5bcfab3563 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -649,8 +649,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
.scan_index = 0,
.scan_type = {
@@ -663,8 +663,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
.scan_index = 1,
.scan_type = {
@@ -677,8 +677,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "apparent_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
.scan_index = 2,
.scan_type = {
@@ -691,8 +691,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "active_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
.scan_index = 3,
.scan_type = {
@@ -705,8 +705,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "reactive_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
.scan_index = 4,
.scan_type = {
@@ -719,8 +719,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
.scan_index = 5,
.scan_type = {
@@ -733,8 +733,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
.scan_index = 6,
.scan_type = {
@@ -747,8 +747,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "apparent_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
.scan_index = 7,
.scan_type = {
@@ -761,8 +761,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "active_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
.scan_index = 8,
.scan_type = {
@@ -775,8 +775,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "reactive_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
.scan_index = 9,
.scan_type = {
@@ -789,8 +789,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
.scan_index = 10,
.scan_type = {
@@ -803,8 +803,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
.scan_index = 11,
.scan_type = {
@@ -817,8 +817,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "apparent_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
.scan_index = 12,
.scan_type = {
@@ -831,8 +831,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "active_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
.scan_index = 13,
.scan_type = {
@@ -845,8 +845,8 @@ static const struct iio_chan_spec ade7758_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "reactive_raw",
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
.scan_index = 14,
.scan_type = {
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
index f9c6a340092b..7a94ddd42f59 100644
--- a/drivers/staging/iio/meter/ade7758_trigger.c
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -32,7 +32,7 @@ static irqreturn_t ade7758_data_rdy_trig_poll(int irq, void *private)
static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
return ade7758_set_irq(&indio_dev->dev, state);
@@ -44,7 +44,7 @@ static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
**/
static int ade7758_trig_try_reen(struct iio_trigger *trig)
{
- struct iio_dev *indio_dev = trig->private_data;
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct ade7758_state *st = iio_priv(indio_dev);
enable_irq(st->us->irq);
@@ -81,7 +81,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
st->trig->dev.parent = &st->us->dev;
st->trig->ops = &ade7758_trigger_ops;
- st->trig->private_data = indio_dev;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
ret = iio_trigger_register(st->trig);
/* select default trigger */
diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c
index 4fe349914f9a..71221161aa6b 100644
--- a/drivers/staging/iio/resolver/ad2s1200.c
+++ b/drivers/staging/iio/resolver/ad2s1200.c
@@ -85,12 +85,12 @@ static const struct iio_chan_spec ad2s1200_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index 53110b6a3c74..0d3356d4b7d2 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -577,12 +577,12 @@ static const struct iio_chan_spec ad2s1210_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
index 0aecfbcdb992..40b825286d4a 100644
--- a/drivers/staging/iio/resolver/ad2s90.c
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -55,7 +55,7 @@ static const struct iio_chan_spec ad2s90_chan = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
};
static int ad2s90_probe(struct spi_device *spi)
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 42798da575c0..38a158b77b1d 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -65,7 +65,7 @@ struct bfin_tmr_state {
static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
{
- struct bfin_tmr_state *st = trig->private_data;
+ struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig);
if (get_gptimer_period(st->t->id) == 0)
return -EINVAL;
@@ -82,7 +82,7 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct iio_trigger *trig = to_iio_trigger(dev);
- struct bfin_tmr_state *st = trig->private_data;
+ struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig);
unsigned long val;
bool enabled;
int ret;
@@ -125,7 +125,7 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
char *buf)
{
struct iio_trigger *trig = to_iio_trigger(dev);
- struct bfin_tmr_state *st = trig->private_data;
+ struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig);
unsigned int period = get_gptimer_period(st->t->id);
unsigned long val;
@@ -213,9 +213,9 @@ static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
goto out1;
}
- st->trig->private_data = st;
st->trig->ops = &iio_bfin_tmr_trigger_ops;
st->trig->dev.groups = iio_bfin_tmr_trigger_attr_groups;
+ iio_trigger_set_drvdata(st->trig, st);
ret = iio_trigger_register(st->trig);
if (ret)
goto out2;
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index fcc4cb048c9a..7c593d18a910 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -83,7 +83,7 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto error_put_trigger;
}
- trig->private_data = trig_info;
+ iio_trigger_set_drvdata(trig, trig_info);
trig_info->irq = irq;
trig->ops = &iio_gpio_trigger_ops;
ret = request_irq(irq, iio_gpio_trigger_poll,
@@ -121,7 +121,7 @@ error_free_completed_registrations:
trig2,
&iio_gpio_trigger_list,
alloc_list) {
- trig_info = trig->private_data;
+ trig_info = iio_trigger_get_drvdata(trig);
free_irq(gpio_to_irq(trig_info->irq), trig);
kfree(trig_info);
iio_trigger_unregister(trig);
@@ -140,7 +140,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev)
trig2,
&iio_gpio_trigger_list,
alloc_list) {
- trig_info = trig->private_data;
+ trig_info = iio_trigger_get_drvdata(trig);
iio_trigger_unregister(trig);
free_irq(trig_info->irq, trig);
kfree(trig_info);
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index 9102b1ba2530..79695974b1d4 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -30,7 +30,7 @@ struct iio_prtc_trigger_info {
static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state)
{
- struct iio_prtc_trigger_info *trig_info = trig->private_data;
+ struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
if (trig_info->frequency == 0)
return -EINVAL;
printk(KERN_INFO "trigger frequency is %d\n", trig_info->frequency);
@@ -42,7 +42,7 @@ static ssize_t iio_trig_periodic_read_freq(struct device *dev,
char *buf)
{
struct iio_trigger *trig = to_iio_trigger(dev);
- struct iio_prtc_trigger_info *trig_info = trig->private_data;
+ struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
return sprintf(buf, "%u\n", trig_info->frequency);
}
@@ -52,7 +52,7 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev,
size_t len)
{
struct iio_trigger *trig = to_iio_trigger(dev);
- struct iio_prtc_trigger_info *trig_info = trig->private_data;
+ struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig);
unsigned long val;
int ret;
@@ -124,7 +124,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
ret = -ENOMEM;
goto error_put_trigger_and_remove_from_list;
}
- trig->private_data = trig_info;
+ iio_trigger_set_drvdata(trig, trig_info);
trig->ops = &iio_prtc_trigger_ops;
/* RTC access */
trig_info->rtc
@@ -158,7 +158,7 @@ error_free_completed_registrations:
trig2,
&iio_prtc_trigger_list,
alloc_list) {
- trig_info = trig->private_data;
+ trig_info = iio_trigger_get_drvdata(trig);
rtc_irq_unregister(trig_info->rtc, &trig_info->task);
rtc_class_close(trig_info->rtc);
kfree(trig_info);
@@ -176,7 +176,7 @@ static int iio_trig_periodic_rtc_remove(struct platform_device *dev)
trig2,
&iio_prtc_trigger_list,
alloc_list) {
- trig_info = trig->private_data;
+ trig_info = iio_trigger_get_drvdata(trig);
rtc_irq_unregister(trig_info->rtc, &trig_info->task);
rtc_class_close(trig_info->rtc);
kfree(trig_info);
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 3bac97224bf4..b727bde8b7fe 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -103,7 +103,7 @@ static ssize_t iio_sysfs_trigger_poll(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct iio_trigger *trig = to_iio_trigger(dev);
- struct iio_sysfs_trig *sysfs_trig = trig->private_data;
+ struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig);
irq_work_queue(&sysfs_trig->work);
@@ -160,7 +160,7 @@ static int iio_sysfs_trigger_probe(int id)
t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
t->trig->ops = &iio_sysfs_trigger_ops;
t->trig->dev.parent = &iio_sysfs_trig_dev;
- t->trig->private_data = t;
+ iio_trigger_set_drvdata(t->trig, t);
init_irq_work(&t->work, iio_sysfs_trigger_work);
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index be7e2e30ac14..8c9e40390f42 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -20,6 +20,13 @@ config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
depends on DRM_IMX
+config DRM_IMX_TVE
+ tristate "Support for TV and VGA displays"
+ depends on DRM_IMX
+ help
+ Choose this to enable the internal Television Encoder (TVe)
+ found on i.MX53 processors.
+
config DRM_IMX_IPUV3_CORE
tristate "IPUv3 core support"
depends on DRM_IMX
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 83a9056546e6..7e50184523c4 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -4,6 +4,7 @@ imxdrm-objs := imx-drm-core.o imx-fb.o
obj-$(CONFIG_DRM_IMX) += imxdrm.o
obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
+obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index e52adc44e607..123acbe9b379 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -1,5 +1,8 @@
TODO:
- get DRM Maintainer review for this code
+- Wait for common display framework to hit mainline and update the IPU
+ driver to use it. This will most probably make changes to the devicetree
+ bindings necessary.
- Factor out more code to common helper functions
- decide where to put the base driver. It is not specific to a subsystem
and would be used by DRM/KMS and media/V4L2
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index cec19f1cf56c..64553058b67e 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -112,8 +112,8 @@ static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
return NULL;
}
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
- u32 interface_pix_fmt)
+int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+ u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
{
struct imx_drm_device *imxdrm = crtc->dev->dev_private;
struct imx_drm_crtc *imx_crtc;
@@ -134,9 +134,18 @@ found:
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
return helper->set_interface_pix_fmt(crtc,
- encoder_type, interface_pix_fmt);
+ encoder_type, interface_pix_fmt,
+ hsync_pin, vsync_pin);
return 0;
}
+EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+
+int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+ u32 interface_pix_fmt)
+{
+ return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
+ interface_pix_fmt, 0, 0);
+}
EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae28a490c445..f2aac91ddf5d 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -1,14 +1,24 @@
#ifndef _IMX_DRM_H_
#define _IMX_DRM_H_
+#include <linux/videodev2.h>
+
+#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3')
+
+struct drm_crtc;
+struct drm_connector;
+struct drm_device;
+struct drm_encoder;
struct imx_drm_crtc;
struct drm_fbdev_cma;
+struct drm_framebuffer;
+struct platform_device;
struct imx_drm_crtc_helper_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
- u32 pix_fmt);
+ u32 pix_fmt, int hsync_pin, int vsync_pin);
const struct drm_crtc_helper_funcs *crtc_helper_funcs;
const struct drm_crtc_funcs *crtc_funcs;
};
@@ -44,6 +54,8 @@ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
struct drm_device *imx_drm_device_get(void);
void imx_drm_device_put(void);
+int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+ u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
u32 interface_pix_fmt);
void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
new file mode 100644
index 000000000000..ac1634464407
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -0,0 +1,755 @@
+/*
+ * i.MX drm driver - Television Encoder (TVEv2)
+ *
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "imx-drm.h"
+
+#define TVE_COM_CONF_REG 0x00
+#define TVE_TVDAC0_CONT_REG 0x28
+#define TVE_TVDAC1_CONT_REG 0x2c
+#define TVE_TVDAC2_CONT_REG 0x30
+#define TVE_CD_CONT_REG 0x34
+#define TVE_INT_CONT_REG 0x64
+#define TVE_STAT_REG 0x68
+#define TVE_TST_MODE_REG 0x6c
+#define TVE_MV_CONT_REG 0xdc
+
+/* TVE_COM_CONF_REG */
+#define TVE_SYNC_CH_2_EN BIT(22)
+#define TVE_SYNC_CH_1_EN BIT(21)
+#define TVE_SYNC_CH_0_EN BIT(20)
+#define TVE_TV_OUT_MODE_MASK (0x7 << 12)
+#define TVE_TV_OUT_DISABLE (0x0 << 12)
+#define TVE_TV_OUT_CVBS_0 (0x1 << 12)
+#define TVE_TV_OUT_CVBS_2 (0x2 << 12)
+#define TVE_TV_OUT_CVBS_0_2 (0x3 << 12)
+#define TVE_TV_OUT_SVIDEO_0_1 (0x4 << 12)
+#define TVE_TV_OUT_SVIDEO_0_1_CVBS2_2 (0x5 << 12)
+#define TVE_TV_OUT_YPBPR (0x6 << 12)
+#define TVE_TV_OUT_RGB (0x7 << 12)
+#define TVE_TV_STAND_MASK (0xf << 8)
+#define TVE_TV_STAND_HD_1080P30 (0xc << 8)
+#define TVE_P2I_CONV_EN BIT(7)
+#define TVE_INP_VIDEO_FORM BIT(6)
+#define TVE_INP_YCBCR_422 (0x0 << 6)
+#define TVE_INP_YCBCR_444 (0x1 << 6)
+#define TVE_DATA_SOURCE_MASK (0x3 << 4)
+#define TVE_DATA_SOURCE_BUS1 (0x0 << 4)
+#define TVE_DATA_SOURCE_BUS2 (0x1 << 4)
+#define TVE_DATA_SOURCE_EXT (0x2 << 4)
+#define TVE_DATA_SOURCE_TESTGEN (0x3 << 4)
+#define TVE_IPU_CLK_EN_OFS 3
+#define TVE_IPU_CLK_EN BIT(3)
+#define TVE_DAC_SAMP_RATE_OFS 1
+#define TVE_DAC_SAMP_RATE_WIDTH 2
+#define TVE_DAC_SAMP_RATE_MASK (0x3 << 1)
+#define TVE_DAC_FULL_RATE (0x0 << 1)
+#define TVE_DAC_DIV2_RATE (0x1 << 1)
+#define TVE_DAC_DIV4_RATE (0x2 << 1)
+#define TVE_EN BIT(0)
+
+/* TVE_TVDACx_CONT_REG */
+#define TVE_TVDAC_GAIN_MASK (0x3f << 0)
+
+/* TVE_CD_CONT_REG */
+#define TVE_CD_CH_2_SM_EN BIT(22)
+#define TVE_CD_CH_1_SM_EN BIT(21)
+#define TVE_CD_CH_0_SM_EN BIT(20)
+#define TVE_CD_CH_2_LM_EN BIT(18)
+#define TVE_CD_CH_1_LM_EN BIT(17)
+#define TVE_CD_CH_0_LM_EN BIT(16)
+#define TVE_CD_CH_2_REF_LVL BIT(10)
+#define TVE_CD_CH_1_REF_LVL BIT(9)
+#define TVE_CD_CH_0_REF_LVL BIT(8)
+#define TVE_CD_EN BIT(0)
+
+/* TVE_INT_CONT_REG */
+#define TVE_FRAME_END_IEN BIT(13)
+#define TVE_CD_MON_END_IEN BIT(2)
+#define TVE_CD_SM_IEN BIT(1)
+#define TVE_CD_LM_IEN BIT(0)
+
+/* TVE_TST_MODE_REG */
+#define TVE_TVDAC_TEST_MODE_MASK (0x7 << 0)
+
+#define con_to_tve(x) container_of(x, struct imx_tve, connector)
+#define enc_to_tve(x) container_of(x, struct imx_tve, encoder)
+
+enum {
+ TVE_MODE_TVOUT,
+ TVE_MODE_VGA,
+};
+
+struct imx_tve {
+ struct drm_connector connector;
+ struct imx_drm_connector *imx_drm_connector;
+ struct drm_encoder encoder;
+ struct imx_drm_encoder *imx_drm_encoder;
+ struct device *dev;
+ spinlock_t enable_lock; /* serializes tve_enable/disable */
+ spinlock_t lock; /* register lock */
+ bool enabled;
+ int mode;
+
+ struct regmap *regmap;
+ struct regulator *dac_reg;
+ struct i2c_adapter *ddc;
+ struct clk *clk;
+ struct clk *di_sel_clk;
+ struct clk_hw clk_hw_di;
+ struct clk *di_clk;
+ int vsync_pin;
+ int hsync_pin;
+};
+
+static void tve_lock(void *__tve)
+{
+ struct imx_tve *tve = __tve;
+ spin_lock(&tve->lock);
+}
+
+static void tve_unlock(void *__tve)
+{
+ struct imx_tve *tve = __tve;
+ spin_unlock(&tve->lock);
+}
+
+static void tve_enable(struct imx_tve *tve)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&tve->enable_lock, flags);
+ if (!tve->enabled) {
+ tve->enabled = 1;
+ clk_prepare_enable(tve->clk);
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+ TVE_IPU_CLK_EN | TVE_EN,
+ TVE_IPU_CLK_EN | TVE_EN);
+ }
+
+ /* clear interrupt status register */
+ regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
+
+ /* cable detection irq disabled in VGA mode, enabled in TVOUT mode */
+ if (tve->mode == TVE_MODE_VGA)
+ regmap_write(tve->regmap, TVE_INT_CONT_REG, 0);
+ else
+ regmap_write(tve->regmap, TVE_INT_CONT_REG,
+ TVE_CD_SM_IEN | TVE_CD_LM_IEN | TVE_CD_MON_END_IEN);
+ spin_unlock_irqrestore(&tve->enable_lock, flags);
+}
+
+static void tve_disable(struct imx_tve *tve)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&tve->enable_lock, flags);
+ if (tve->enabled) {
+ tve->enabled = 0;
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+ TVE_IPU_CLK_EN | TVE_EN, 0);
+ clk_disable_unprepare(tve->clk);
+ }
+ spin_unlock_irqrestore(&tve->enable_lock, flags);
+}
+
+static int tve_setup_tvout(struct imx_tve *tve)
+{
+ return -ENOTSUPP;
+}
+
+static int tve_setup_vga(struct imx_tve *tve)
+{
+ unsigned int mask;
+ unsigned int val;
+ int ret;
+
+ /* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
+ ret = regmap_update_bits(tve->regmap, TVE_TVDAC0_CONT_REG,
+ TVE_TVDAC_GAIN_MASK, 0x0a);
+ ret = regmap_update_bits(tve->regmap, TVE_TVDAC1_CONT_REG,
+ TVE_TVDAC_GAIN_MASK, 0x0a);
+ ret = regmap_update_bits(tve->regmap, TVE_TVDAC2_CONT_REG,
+ TVE_TVDAC_GAIN_MASK, 0x0a);
+
+ /* set configuration register */
+ mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM;
+ val = TVE_DATA_SOURCE_BUS2 | TVE_INP_YCBCR_444;
+ mask |= TVE_TV_STAND_MASK | TVE_P2I_CONV_EN;
+ val |= TVE_TV_STAND_HD_1080P30 | 0;
+ mask |= TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN;
+ val |= TVE_TV_OUT_RGB | TVE_SYNC_CH_0_EN;
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, mask, val);
+ if (ret < 0) {
+ dev_err(tve->dev, "failed to set configuration: %d\n", ret);
+ return ret;
+ }
+
+ /* set test mode (as documented) */
+ ret = regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
+ TVE_TVDAC_TEST_MODE_MASK, 1);
+
+ return 0;
+}
+
+static enum drm_connector_status imx_tve_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void imx_tve_connector_destroy(struct drm_connector *connector)
+{
+ /* do not free here */
+}
+
+static int imx_tve_connector_get_modes(struct drm_connector *connector)
+{
+ struct imx_tve *tve = con_to_tve(connector);
+ struct edid *edid;
+ int ret = 0;
+
+ if (!tve->ddc)
+ return 0;
+
+ edid = drm_get_edid(connector, tve->ddc);
+ if (edid) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+ }
+
+ return ret;
+}
+
+static int imx_tve_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct imx_tve *tve = con_to_tve(connector);
+ unsigned long rate;
+
+ /* pixel clock with 2x oversampling */
+ rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
+ if (rate == mode->clock)
+ return MODE_OK;
+
+ /* pixel clock without oversampling */
+ rate = clk_round_rate(tve->clk, 1000UL * mode->clock) / 1000;
+ if (rate == mode->clock)
+ return MODE_OK;
+
+ dev_warn(tve->dev, "ignoring mode %dx%d\n",
+ mode->hdisplay, mode->vdisplay);
+
+ return MODE_BAD;
+}
+
+static struct drm_encoder *imx_tve_connector_best_encoder(
+ struct drm_connector *connector)
+{
+ struct imx_tve *tve = con_to_tve(connector);
+
+ return &tve->encoder;
+}
+
+static void imx_tve_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct imx_tve *tve = enc_to_tve(encoder);
+ int ret;
+
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG,
+ TVE_TV_OUT_MODE_MASK, TVE_TV_OUT_DISABLE);
+ if (ret < 0)
+ dev_err(tve->dev, "failed to disable TVOUT: %d\n", ret);
+}
+
+static bool imx_tve_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
+{
+ struct imx_tve *tve = enc_to_tve(encoder);
+
+ tve_disable(tve);
+
+ switch (tve->mode) {
+ case TVE_MODE_VGA:
+ imx_drm_crtc_panel_format_pins(encoder->crtc,
+ DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+ tve->hsync_pin, tve->vsync_pin);
+ break;
+ case TVE_MODE_TVOUT:
+ imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
+ V4L2_PIX_FMT_YUV444);
+ break;
+ }
+}
+
+static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct imx_tve *tve = enc_to_tve(encoder);
+ unsigned long rounded_rate;
+ unsigned long rate;
+ int div = 1;
+ int ret;
+
+ /*
+ * FIXME
+ * we should try 4k * mode->clock first,
+ * and enable 4x oversampling for lower resolutions
+ */
+ rate = 2000UL * mode->clock;
+ clk_set_rate(tve->clk, rate);
+ rounded_rate = clk_get_rate(tve->clk);
+ if (rounded_rate >= rate)
+ div = 2;
+ clk_set_rate(tve->di_clk, rounded_rate / div);
+
+ ret = clk_set_parent(tve->di_sel_clk, tve->di_clk);
+ if (ret < 0) {
+ dev_err(tve->dev, "failed to set di_sel parent to tve_di: %d\n",
+ ret);
+ }
+
+ if (tve->mode == TVE_MODE_VGA)
+ tve_setup_vga(tve);
+ else
+ tve_setup_tvout(tve);
+}
+
+static void imx_tve_encoder_commit(struct drm_encoder *encoder)
+{
+ struct imx_tve *tve = enc_to_tve(encoder);
+
+ tve_enable(tve);
+}
+
+static void imx_tve_encoder_disable(struct drm_encoder *encoder)
+{
+ struct imx_tve *tve = enc_to_tve(encoder);
+
+ tve_disable(tve);
+}
+
+static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
+{
+ /* do not free here */
+}
+
+static struct drm_connector_funcs imx_tve_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = imx_tve_connector_detect,
+ .destroy = imx_tve_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
+ .get_modes = imx_tve_connector_get_modes,
+ .best_encoder = imx_tve_connector_best_encoder,
+ .mode_valid = imx_tve_connector_mode_valid,
+};
+
+static struct drm_encoder_funcs imx_tve_encoder_funcs = {
+ .destroy = imx_tve_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
+ .dpms = imx_tve_encoder_dpms,
+ .mode_fixup = imx_tve_encoder_mode_fixup,
+ .prepare = imx_tve_encoder_prepare,
+ .mode_set = imx_tve_encoder_mode_set,
+ .commit = imx_tve_encoder_commit,
+ .disable = imx_tve_encoder_disable,
+};
+
+static irqreturn_t imx_tve_irq_handler(int irq, void *data)
+{
+ struct imx_tve *tve = data;
+ unsigned int val;
+
+ regmap_read(tve->regmap, TVE_STAT_REG, &val);
+
+ /* clear interrupt status register */
+ regmap_write(tve->regmap, TVE_STAT_REG, 0xffffffff);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned long clk_tve_di_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
+ if (ret < 0)
+ return 0;
+
+ switch (val & TVE_DAC_SAMP_RATE_MASK) {
+ case TVE_DAC_DIV4_RATE:
+ return parent_rate / 4;
+ case TVE_DAC_DIV2_RATE:
+ return parent_rate / 2;
+ case TVE_DAC_FULL_RATE:
+ default:
+ return parent_rate;
+ }
+
+ return 0;
+}
+
+static long clk_tve_di_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long div;
+
+ div = *prate / rate;
+ if (div >= 4)
+ return *prate / 4;
+ else if (div >= 2)
+ return *prate / 2;
+ else
+ return *prate;
+}
+
+static int clk_tve_di_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct imx_tve *tve = container_of(hw, struct imx_tve, clk_hw_di);
+ unsigned long div;
+ u32 val;
+ int ret;
+
+ div = parent_rate / rate;
+ if (div >= 4)
+ val = TVE_DAC_DIV4_RATE;
+ else if (div >= 2)
+ val = TVE_DAC_DIV2_RATE;
+ else
+ val = TVE_DAC_FULL_RATE;
+
+ ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, TVE_DAC_SAMP_RATE_MASK, val);
+ if (ret < 0) {
+ dev_err(tve->dev, "failed to set divider: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct clk_ops clk_tve_di_ops = {
+ .round_rate = clk_tve_di_round_rate,
+ .set_rate = clk_tve_di_set_rate,
+ .recalc_rate = clk_tve_di_recalc_rate,
+};
+
+static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
+{
+ const char *tve_di_parent[1];
+ struct clk_init_data init = {
+ .name = "tve_di",
+ .ops = &clk_tve_di_ops,
+ .num_parents = 1,
+ .flags = 0,
+ };
+
+ tve_di_parent[0] = __clk_get_name(tve->clk);
+ init.parent_names = (const char **)&tve_di_parent;
+
+ tve->clk_hw_di.init = &init;
+ tve->di_clk = clk_register(tve->dev, &tve->clk_hw_di);
+ if (IS_ERR(tve->di_clk)) {
+ dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
+ PTR_ERR(tve->di_clk));
+ return PTR_ERR(tve->di_clk);
+ }
+
+ return 0;
+}
+
+static int imx_tve_register(struct imx_tve *tve)
+{
+ int ret;
+
+ tve->connector.funcs = &imx_tve_connector_funcs;
+ tve->encoder.funcs = &imx_tve_encoder_funcs;
+
+ tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+ tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+
+ drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
+ ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
+ THIS_MODULE);
+ if (ret) {
+ dev_err(tve->dev, "adding encoder failed with %d\n", ret);
+ return ret;
+ }
+
+ drm_connector_helper_add(&tve->connector,
+ &imx_tve_connector_helper_funcs);
+
+ ret = imx_drm_add_connector(&tve->connector,
+ &tve->imx_drm_connector, THIS_MODULE);
+ if (ret) {
+ imx_drm_remove_encoder(tve->imx_drm_encoder);
+ dev_err(tve->dev, "adding connector failed with %d\n", ret);
+ return ret;
+ }
+
+ drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
+
+ return 0;
+}
+
+static bool imx_tve_readable_reg(struct device *dev, unsigned int reg)
+{
+ return (reg % 4 == 0) && (reg <= 0xdc);
+}
+
+static struct regmap_config tve_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+
+ .readable_reg = imx_tve_readable_reg,
+
+ .lock = tve_lock,
+ .unlock = tve_unlock,
+
+ .max_register = 0xdc,
+};
+
+static const char *imx_tve_modes[] = {
+ [TVE_MODE_TVOUT] = "tvout",
+ [TVE_MODE_VGA] = "vga",
+};
+
+const int of_get_tve_mode(struct device_node *np)
+{
+ const char *bm;
+ int ret, i;
+
+ ret = of_property_read_string(np, "fsl,tve-mode", &bm);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(imx_tve_modes); i++)
+ if (!strcasecmp(bm, imx_tve_modes[i]))
+ return i;
+
+ return -EINVAL;
+}
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ddc_node;
+ struct imx_tve *tve;
+ struct resource *res;
+ void __iomem *base;
+ unsigned int val;
+ int irq;
+ int ret;
+
+ tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+ if (!tve)
+ return -ENOMEM;
+
+ tve->dev = &pdev->dev;
+ spin_lock_init(&tve->lock);
+ spin_lock_init(&tve->enable_lock);
+
+ ddc_node = of_parse_phandle(np, "ddc", 0);
+ if (ddc_node) {
+ tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
+ of_node_put(ddc_node);
+ }
+
+ tve->mode = of_get_tve_mode(np);
+ if (tve->mode != TVE_MODE_VGA) {
+ dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+ return -EINVAL;
+ }
+
+ if (tve->mode == TVE_MODE_VGA) {
+ struct pinctrl *pinctrl;
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ dev_warn(&pdev->dev, "failed to setup pinctrl: %d", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "fsl,hsync-pin", &tve->hsync_pin);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get vsync pin\n");
+ return ret;
+ }
+
+ ret |= of_property_read_u32(np, "fsl,vsync-pin", &tve->vsync_pin);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get vsync pin\n");
+ return ret;
+ }
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory region\n");
+ return -ENOENT;
+ }
+
+ base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!base) {
+ dev_err(&pdev->dev, "failed to remap memory region\n");
+ return -ENOENT;
+ }
+
+ tve_regmap_config.lock_arg = tve;
+ tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+ &tve_regmap_config);
+ if (IS_ERR(tve->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(tve->regmap));
+ return PTR_ERR(tve->regmap);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq\n");
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ imx_tve_irq_handler, IRQF_ONESHOT,
+ "imx-tve", tve);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+ if (!IS_ERR(tve->dac_reg)) {
+ regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
+ regulator_enable(tve->dac_reg);
+ }
+
+ tve->clk = devm_clk_get(&pdev->dev, "tve");
+ if (IS_ERR(tve->clk)) {
+ dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+ PTR_ERR(tve->clk));
+ return PTR_ERR(tve->clk);
+ }
+
+ /* this is the IPU DI clock input selector, can be parented to tve_di */
+ tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+ if (IS_ERR(tve->di_sel_clk)) {
+ dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+ PTR_ERR(tve->di_sel_clk));
+ return PTR_ERR(tve->di_sel_clk);
+ }
+
+ ret = tve_clk_init(tve, base);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+ return ret;
+ }
+ if (val != 0x00100000) {
+ dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+ return -ENODEV;
+ };
+
+ /* disable cable detection for VGA mode */
+ ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
+
+ ret = imx_tve_register(tve);
+ if (ret)
+ return ret;
+
+ ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
+
+ platform_set_drvdata(pdev, tve);
+
+ return 0;
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+ struct imx_tve *tve = platform_get_drvdata(pdev);
+ struct drm_connector *connector = &tve->connector;
+ struct drm_encoder *encoder = &tve->encoder;
+
+ drm_mode_connector_detach_encoder(connector, encoder);
+
+ imx_drm_remove_connector(tve->imx_drm_connector);
+ imx_drm_remove_encoder(tve->imx_drm_encoder);
+
+ if (!IS_ERR(tve->dac_reg))
+ regulator_disable(tve->dac_reg);
+
+ return 0;
+}
+
+static const struct of_device_id imx_tve_dt_ids[] = {
+ { .compatible = "fsl,imx53-tve", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver imx_tve_driver = {
+ .probe = imx_tve_probe,
+ .remove = imx_tve_remove,
+ .driver = {
+ .of_match_table = imx_tve_dt_ids,
+ .name = "imx-tve",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(imx_tve_driver);
+
+MODULE_DESCRIPTION("i.MX Television Encoder driver");
+MODULE_AUTHOR("Philipp Zabel, Pengutronix");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 99d1cceaa3de..74c022e2a532 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -54,6 +54,9 @@ struct ipu_di_signal_cfg {
#define IPU_DI_CLKMODE_SYNC (1 << 0)
#define IPU_DI_CLKMODE_EXT (1 << 1)
unsigned long clkflags;
+
+ u8 hsync_pin;
+ u8 vsync_pin;
};
enum ipu_color_space {
@@ -292,7 +295,8 @@ static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
int stride, int height);
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param *p, u32 pixel_format);
+void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
+ u32 pixel_format);
void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
u32 pixel_format, int stride, int u_offset, int v_offset);
int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 366f259e3756..055b99db50ff 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -225,7 +225,8 @@ int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
}
EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param *p, u32 pixel_format)
+void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
+ u32 pixel_format)
{
switch (pixel_format) {
case V4L2_PIX_FMT_UYVY:
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index 93c7579417be..59f03f9aefc3 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/io.h>
+#include "../imx-drm.h"
#include "imx-ipu-v3.h"
#include "ipu-prv.h"
@@ -60,8 +61,10 @@
#define WROD(lf) (0x18 | ((lf) << 1))
#define WRG 0x01
+#define WCLK 0xc9
#define SYNC_WAVE 0
+#define NULL_WAVE (-1)
#define DC_GEN_SYNC_1_6_SYNC (2 << 1)
#define DC_GEN_SYNC_PRIORITY_1 (1 << 7)
@@ -86,6 +89,8 @@ struct ipu_dc_priv;
enum ipu_dc_map {
IPU_DC_MAP_RGB24,
IPU_DC_MAP_RGB565,
+ IPU_DC_MAP_GBR24, /* TVEv2 */
+ IPU_DC_MAP_BGR666,
};
struct ipu_dc {
@@ -117,16 +122,23 @@ static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
}
static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand,
- int map, int wave, int glue, int sync)
+ int map, int wave, int glue, int sync, int stop)
{
struct ipu_dc_priv *priv = dc->priv;
- u32 reg;
- int stop = 1;
-
- reg = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
- writel(reg, priv->dc_tmpl_reg + word * 8);
- reg = operand >> 12 | opcode << 4 | stop << 9;
- writel(reg, priv->dc_tmpl_reg + word * 8 + 4);
+ u32 reg1, reg2;
+
+ if (opcode == WCLK) {
+ reg1 = (operand << 20) & 0xfff00000;
+ reg2 = operand >> 12 | opcode << 1 | stop << 9;
+ } else if (opcode == WRG) {
+ reg1 = sync | glue << 4 | ++wave << 11 | ((operand << 15) & 0xffff8000);
+ reg2 = operand >> 17 | opcode << 7 | stop << 9;
+ } else {
+ reg1 = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000);
+ reg2 = operand >> 12 | opcode << 4 | stop << 9;
+ }
+ writel(reg1, priv->dc_tmpl_reg + word * 8);
+ writel(reg2, priv->dc_tmpl_reg + word * 8 + 4);
}
static int ipu_pixfmt_to_map(u32 fmt)
@@ -136,6 +148,10 @@ static int ipu_pixfmt_to_map(u32 fmt)
return IPU_DC_MAP_RGB24;
case V4L2_PIX_FMT_RGB565:
return IPU_DC_MAP_RGB565;
+ case IPU_PIX_FMT_GBR24:
+ return IPU_DC_MAP_GBR24;
+ case V4L2_PIX_FMT_BGR666:
+ return IPU_DC_MAP_BGR666;
default:
return -EINVAL;
}
@@ -161,24 +177,26 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1);
/* Init template microcode */
- dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+ dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
} else {
if (dc->di) {
dc_link_event(dc, DC_EVT_NL, 2, 3);
dc_link_event(dc, DC_EVT_EOL, 3, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 4, 1);
+ dc_link_event(dc, DC_EVT_NEW_DATA, 1, 1);
/* Init template microcode */
- dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
- dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
- dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+ dc_write_tmpl(dc, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+ dc_write_tmpl(dc, 1, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
} else {
dc_link_event(dc, DC_EVT_NL, 5, 3);
dc_link_event(dc, DC_EVT_EOL, 6, 2);
- dc_link_event(dc, DC_EVT_NEW_DATA, 7, 1);
+ dc_link_event(dc, DC_EVT_NEW_DATA, 8, 1);
/* Init template microcode */
- dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
- dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
- dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+ dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+ dc_write_tmpl(dc, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+ dc_write_tmpl(dc, 8, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
}
}
dc_link_event(dc, DC_EVT_NF, 0, 0);
@@ -364,6 +382,18 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */
ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */
+ /* gbr24 */
+ ipu_dc_map_clear(priv, IPU_DC_MAP_GBR24);
+ ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 2, 15, 0xff); /* green */
+ ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 1, 7, 0xff); /* blue */
+ ipu_dc_map_config(priv, IPU_DC_MAP_GBR24, 0, 23, 0xff); /* red */
+
+ /* bgr666 */
+ ipu_dc_map_clear(priv, IPU_DC_MAP_BGR666);
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 0, 5, 0xfc); /* blue */
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 1, 11, 0xfc); /* green */
+ ipu_dc_map_config(priv, IPU_DC_MAP_BGR666, 2, 17, 0xfc); /* red */
+
return 0;
}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index ec340da968ac..19d777e39d0b 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -413,9 +413,11 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
sig->v_end_width;
struct di_sync_config cfg[] = {
{
+ /* 1: INT_HSYNC */
.run_count = h_total - 1,
.run_src = DI_SYNC_CLK,
} , {
+ /* PIN2: HSYNC */
.run_count = h_total - 1,
.run_src = DI_SYNC_CLK,
.offset_count = div * sig->v_to_h_sync,
@@ -424,36 +426,106 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
.cnt_down = sig->h_sync_width * 2,
} , {
+ /* PIN3: VSYNC */
.run_count = v_total - 1,
.run_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
.cnt_down = sig->v_sync_width * 2,
} , {
+ /* 4: Line Active */
.run_src = DI_SYNC_HSYNC,
.offset_count = sig->v_sync_width + sig->v_start_width,
.offset_src = DI_SYNC_HSYNC,
.repeat_count = sig->height,
.cnt_clr_src = DI_SYNC_VSYNC,
} , {
+ /* 5: Pixel Active, referenced by DC */
.run_src = DI_SYNC_CLK,
.offset_count = sig->h_sync_width + sig->h_start_width,
.offset_src = DI_SYNC_CLK,
.repeat_count = sig->width,
- .cnt_clr_src = 5,
+ .cnt_clr_src = 5, /* Line Active */
+ } , {
+ /* unused */
} , {
/* unused */
} , {
/* unused */
} , {
/* unused */
+ },
+ };
+ /* can't use #7 and #8 for line active and pixel active counters */
+ struct di_sync_config cfg_vga[] = {
+ {
+ /* 1: INT_HSYNC */
+ .run_count = h_total - 1,
+ .run_src = DI_SYNC_CLK,
+ } , {
+ /* 2: VSYNC */
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ } , {
+ /* 3: Line Active */
+ .run_src = DI_SYNC_INT_HSYNC,
+ .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_src = DI_SYNC_INT_HSYNC,
+ .repeat_count = sig->height,
+ .cnt_clr_src = 3 /* VSYNC */,
+ } , {
+ /* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
+ .run_count = h_total - 1,
+ .run_src = DI_SYNC_CLK,
+ .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+ .offset_src = DI_SYNC_CLK,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_CLK,
+ .cnt_down = sig->h_sync_width * 2,
+ } , {
+ /* 5: Pixel Active signal to DC */
+ .run_src = DI_SYNC_CLK,
+ .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_src = DI_SYNC_CLK,
+ .repeat_count = sig->width,
+ .cnt_clr_src = 4, /* Line Active */
+ } , {
+ /* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ .offset_count = 1, /* magic value from Freescale TVE driver */
+ .offset_src = DI_SYNC_INT_HSYNC,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+ .cnt_down = sig->v_sync_width * 2,
+ } , {
+ /* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
+ .run_count = h_total - 1,
+ .run_src = DI_SYNC_CLK,
+ .offset_count = div * sig->v_to_h_sync + 18, /* magic value from Freescale TVE driver */
+ .offset_src = DI_SYNC_CLK,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_CLK,
+ .cnt_down = sig->h_sync_width * 2,
+ } , {
+ /* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
+ .run_count = v_total - 1,
+ .run_src = DI_SYNC_INT_HSYNC,
+ .offset_count = 1, /* magic value from Freescale TVE driver */
+ .offset_src = DI_SYNC_INT_HSYNC,
+ .cnt_polarity_gen_en = 1,
+ .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+ .cnt_down = sig->v_sync_width * 2,
} , {
/* unused */
},
};
ipu_di_write(di, v_total - 1, DI_SCR_CONF);
- ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+ if (sig->hsync_pin == 2 && sig->vsync_pin == 3)
+ ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg));
+ else
+ ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
}
int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
@@ -530,11 +602,25 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
ipu_di_sync_config_noninterlaced(di, sig, div);
vsync_cnt = 3;
-
- if (sig->Hsync_pol)
- di_gen |= DI_GEN_POLARITY_2;
- if (sig->Vsync_pol)
- di_gen |= DI_GEN_POLARITY_3;
+ if (di->id == 1)
+ vsync_cnt = 6;
+
+ if (sig->Hsync_pol) {
+ if (sig->hsync_pin == 2)
+ di_gen |= DI_GEN_POLARITY_2;
+ else if (sig->hsync_pin == 4)
+ di_gen |= DI_GEN_POLARITY_4;
+ else if (sig->hsync_pin == 7)
+ di_gen |= DI_GEN_POLARITY_7;
+ }
+ if (sig->Vsync_pol) {
+ if (sig->hsync_pin == 3)
+ di_gen |= DI_GEN_POLARITY_3;
+ else if (sig->hsync_pin == 6)
+ di_gen |= DI_GEN_POLARITY_6;
+ else if (sig->hsync_pin == 8)
+ di_gen |= DI_GEN_POLARITY_8;
+ }
}
if (!sig->clk_pol)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 26aecaf9677f..113b046c0225 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -316,7 +316,6 @@ int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
priv->base = devm_ioremap(dev, base, PAGE_SIZE);
if (!priv->base) {
- kfree(priv);
return -ENOMEM;
}
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index b028b0d1317b..ea61c869110f 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -60,6 +60,8 @@ struct ipu_crtc {
int irq;
u32 interface_pix_fmt;
unsigned long di_clkflags;
+ int di_hsync_pin;
+ int di_vsync_pin;
};
#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
@@ -255,6 +257,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
sig_cfg.v_to_h_sync = 0;
+ sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
+ sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
+
if (ipu_crtc->dp) {
ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
IPUV3_COLORSPACE_RGB);
@@ -406,13 +411,17 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
}
static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
- u32 pixfmt)
+ u32 pixfmt, int hsync_pin, int vsync_pin)
{
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
ipu_crtc->interface_pix_fmt = pixfmt;
+ ipu_crtc->di_hsync_pin = hsync_pin;
+ ipu_crtc->di_vsync_pin = vsync_pin;
switch (encoder_type) {
+ case DRM_MODE_ENCODER_DAC:
+ case DRM_MODE_ENCODER_TVDAC:
case DRM_MODE_ENCODER_LVDS:
ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
IPU_DI_CLKMODE_EXT;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index a8064fcc03d1..e7fba62c10e9 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -57,6 +57,7 @@ static void imx_pd_connector_destroy(struct drm_connector *connector)
static int imx_pd_connector_get_modes(struct drm_connector *connector)
{
struct imx_parallel_display *imxpd = con_to_imxpd(connector);
+ struct device_node *np = imxpd->dev->of_node;
int num_modes = 0;
if (imxpd->edid) {
@@ -72,6 +73,15 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
num_modes++;
}
+ if (np) {
+ struct drm_display_mode *mode = drm_mode_create(connector->dev);
+ of_get_drm_display_mode(np, &imxpd->mode, 0);
+ drm_mode_copy(mode, &imxpd->mode);
+ mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ drm_mode_probed_add(connector, mode);
+ num_modes++;
+ }
+
return num_modes;
}
@@ -220,6 +230,8 @@ static int imx_pd_probe(struct platform_device *pdev)
imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
else if (!strcmp(fmt, "rgb565"))
imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
+ else if (!strcmp(fmt, "bgr666"))
+ imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
}
imxpd->dev = &pdev->dev;
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
index 74898c3c9f90..699b21725062 100644
--- a/drivers/staging/line6/pod.c
+++ b/drivers/staging/line6/pod.c
@@ -148,9 +148,8 @@ void line6_pod_process_message(struct usb_line6_pod *pod)
buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
return;
}
- if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) {
+ if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
return;
- }
if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile
index d8dfb757f1e2..8916d8a909bc 100644
--- a/drivers/staging/media/as102/Makefile
+++ b/drivers/staging/media/as102/Makefile
@@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
obj-$(CONFIG_DVB_AS102) += dvb-as102.o
-EXTRA_CFLAGS += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
diff --git a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt
index 1dbd56418704..a1e91778aa9b 100644
--- a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt
+++ b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt
@@ -38,7 +38,7 @@ interface to userspace.
DAVINCI RESIZER A
DAVINCI RESIZER B
-Each possible link in the VPFE is modeled by a link in the Media controller
+Each possible link in the VPFE is modelled by a link in the Media controller
interface. For an example program see [1].
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 92853539cc0a..05673ed45ce4 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -1859,5 +1859,5 @@ void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe,
iounmap(ipipe->isp5_base_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
if (res)
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
index c8cae51d3d00..b2f4ef84f3db 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
@@ -1065,7 +1065,6 @@ vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif,
iounmap(ipipeif->ipipeif_base_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
if (res)
- release_mem_region(res->start,
- res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index ebeea72e176a..5829360f74c9 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -685,7 +685,7 @@ static void isif_config_bclamp(struct vpfe_isif_device *isif,
val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) <<
ISIF_BC_MODE_COLOR_SHIFT;
- /* Enable BC and horizontal clamp caculation paramaters */
+ /* Enable BC and horizontal clamp calculation paramaters */
val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) <<
ISIF_HORZ_BC_MODE_SHIFT);
@@ -722,7 +722,7 @@ static void isif_config_bclamp(struct vpfe_isif_device *isif,
isif_write(isif->isif_cfg.base_addr, val, CLHWIN2);
}
- /* vertical clamp caculation paramaters */
+ /* vertical clamp calculation paramaters */
/* OB H Valid */
val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK;
@@ -1569,7 +1569,7 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
crop->rect.width = format->width;
crop->rect.height = format->height;
}
- /* adjust the width to 16 pixel boundry */
+ /* adjust the width to 16 pixel boundary */
crop->rect.width = ((crop->rect.width + 15) & ~0xf);
vpfe_isif->crop = crop->rect;
if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
@@ -1953,7 +1953,7 @@ static void isif_remove(struct vpfe_isif_device *isif,
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
if (res)
release_mem_region(res->start,
- res->end - res->start + 1);
+ resource_size(res));
i++;
}
}
@@ -2003,7 +2003,7 @@ int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev)
status = -ENOENT;
goto fail_nobase_res;
}
- res_len = res->end - res->start + 1;
+ res_len = resource_size(res);
res = request_mem_region(res->start, res_len, res->name);
if (!res) {
status = -EBUSY;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index 9cb0262b9b33..126f84c4cb64 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -1995,5 +1995,5 @@ vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz,
res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
if (res)
release_mem_region(res->start,
- res->end - res->start + 1);
+ resource_size(res));
}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index 7b351717bcbb..b88e1ddce229 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -243,7 +243,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
vpfe_dev->clks[i] =
clk_get(vpfe_dev->pdev, vpfe_cfg->clocks[i]);
- if (vpfe_dev->clks[i] == NULL) {
+ if (IS_ERR(vpfe_dev->clks[i])) {
v4l2_err(vpfe_dev->pdev->driver,
"Failed to get clock %s\n",
vpfe_cfg->clocks[i]);
@@ -264,7 +264,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
return 0;
out:
for (i = 0; i < vpfe_cfg->num_clocks; i++)
- if (vpfe_dev->clks[i]) {
+ if (!IS_ERR(vpfe_dev->clks[i])) {
clk_disable_unprepare(vpfe_dev->clks[i]);
clk_put(vpfe_dev->clks[i]);
}
@@ -719,22 +719,4 @@ static struct platform_driver vpfe_driver = {
.remove = vpfe_remove,
};
-/**
- * vpfe_init : This function registers device driver
- */
-static __init int vpfe_init(void)
-{
- /* Register driver to the kernel */
- return platform_driver_register(&vpfe_driver);
-}
-
-/**
- * vpfe_cleanup : This function un-registers device driver
- */
-static void vpfe_cleanup(void)
-{
- platform_driver_unregister(&vpfe_driver);
-}
-
-module_init(vpfe_init);
-module_exit(vpfe_cleanup);
+module_platform_driver(vpfe_driver);
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 99ccbebea598..ba913f1d955b 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -357,7 +357,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
*
* Set the pipeline to the given stream state.
*
- * Return 0 if successfull, or the return value of the failed video::s_stream
+ * Return 0 if successful, or the return value of the failed video::s_stream
* operation otherwise.
*/
static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe,
@@ -644,7 +644,7 @@ static int vpfe_g_fmt(struct file *file, void *priv,
* fills v4l2_fmtdesc structure with output format set on adjacent subdev,
* only one format is enumearted as subdevs are already configured
*
- * Return 0 if successfull, error code otherwise
+ * Return 0 if successful, error code otherwise
*/
static int vpfe_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
@@ -769,7 +769,7 @@ static int vpfe_try_fmt(struct file *file, void *priv,
* fills v4l2_input structure with input available on media chain,
* only one input is enumearted as media chain is setup by this time
*
- * Return 0 if successfull, -EINVAL is media chain is invalid
+ * Return 0 if successful, -EINVAL is media chain is invalid
*/
static int vpfe_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
@@ -779,7 +779,7 @@ static int vpfe_enum_input(struct file *file, void *priv,
struct vpfe_device *vpfe_dev = video->vpfe_dev;
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n");
- /* enumerate from the subdev user has choosen through mc */
+ /* enumerate from the subdev user has chosen through mc */
if (inp->index < sdinfo->num_inputs) {
memcpy(inp, &sdinfo->inputs[inp->index],
sizeof(struct v4l2_input));
@@ -924,7 +924,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
*
* Return 0 on success, error code otherwise
*/
-static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
struct vpfe_video_device *video = video_drvdata(file);
struct vpfe_device *vpfe_dev = video->vpfe_dev;
@@ -945,13 +945,13 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
goto unlock_out;
}
ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_std, *std_id);
+ core, s_std, std_id);
if (ret < 0) {
v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
video->stdid = V4L2_STD_UNKNOWN;
goto unlock_out;
}
- video->stdid = *std_id;
+ video->stdid = std_id;
unlock_out:
mutex_unlock(&video->lock);
return ret;
@@ -1016,12 +1016,12 @@ vpfe_query_dv_timings(struct file *file, void *fh,
}
/*
- * vpfe_s_dv_timings() - set dv_preset on external subdev
+ * vpfe_s_dv_timings() - set dv_timings on external subdev
* @file: file pointer
* @priv: void pointer
* @timings: pointer to v4l2_dv_timings structure
*
- * set dv_timings pointed by preset on external subdev through
+ * set dv_timings pointed by timings on external subdev through
* v4l2_device_call_until_err, this configures amplifier also
*
* Return 0 on success, error code otherwise
@@ -1042,12 +1042,12 @@ vpfe_s_dv_timings(struct file *file, void *fh,
}
/*
- * vpfe_g_dv_timings() - get dv_preset which is set on external subdev
+ * vpfe_g_dv_timings() - get dv_timings which is set on external subdev
* @file: file pointer
* @priv: void pointer
* @timings: pointer to v4l2_dv_timings structure
*
- * get dv_preset which is set on external subdev through
+ * get dv_timings which is set on external subdev through
* v4l2_subdev_call
*
* Return 0 on success, error code otherwise
@@ -1423,7 +1423,7 @@ static int vpfe_dqbuf(struct file *file, void *priv,
}
/*
- * vpfe_streamon() - get dv_preset which is set on external subdev
+ * vpfe_streamon() - start streaming
* @file: file pointer
* @priv: void pointer
* @buf_type: enum v4l2_buf_type
@@ -1472,7 +1472,7 @@ static int vpfe_streamon(struct file *file, void *priv,
}
/*
- * vpfe_streamoff() - get dv_preset which is set on external subdev
+ * vpfe_streamoff() - stop streaming
* @file: file pointer
* @priv: void pointer
* @buf_type: enum v4l2_buf_type
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h
index bf8af01d4a1b..df0aeec8b588 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.h
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.h
@@ -138,7 +138,7 @@ struct vpfe_video_device {
v4l2_std_id stdid;
/*
* offset where second field starts from the starting of the
- * buffer for field seperated YCbCr formats
+ * buffer for field separated YCbCr formats
*/
u32 field_off;
};
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index e33b7f55d84e..c32e0acde4f4 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -26,6 +26,7 @@
#include <linux/slab.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
#include <media/videobuf2-dma-contig.h>
#include "dt3155v4l.h"
@@ -341,7 +342,7 @@ dt3155_irq_handler_even(int irq, void *dev_id)
spin_lock(&ipd->lock);
if (ipd->curr_buf) {
- do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp);
+ v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp);
ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1;
vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE);
}
@@ -390,6 +391,7 @@ dt3155_open(struct file *filp)
goto err_alloc_queue;
}
pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ pd->q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
pd->q->io_modes = VB2_READ | VB2_MMAP;
pd->q->ops = &q_ops;
pd->q->mem_ops = &vb2_dma_contig_memops;
@@ -398,7 +400,7 @@ dt3155_open(struct file *filp)
pd->field_count = 0;
ret = vb2_queue_init(pd->q);
if (ret < 0)
- return ret;
+ goto err_request_irq;
INIT_LIST_HEAD(&pd->dmaq);
spin_lock_init(&pd->lock);
/* disable all irqs, clear all irq flags */
@@ -410,6 +412,7 @@ dt3155_open(struct file *filp)
goto err_request_irq;
}
pd->users++;
+ mutex_unlock(&pd->mux);
return 0; /* success */
err_request_irq:
kfree(pd->q);
@@ -612,9 +615,9 @@ dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm)
}
static int
-dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm)
+dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id norm)
{
- if (*norm & DT3155_CURRENT_NORM)
+ if (norm & DT3155_CURRENT_NORM)
return 0;
return -EINVAL;
}
diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig
index 7dfb2815b9ec..04bd0fba7b1f 100644
--- a/drivers/staging/media/go7007/Kconfig
+++ b/drivers/staging/media/go7007/Kconfig
@@ -1,20 +1,25 @@
config VIDEO_GO7007
tristate "WIS GO7007 MPEG encoder support"
- depends on VIDEO_DEV && PCI && I2C
- depends on SND
- select VIDEOBUF_DMA_SG
- depends on RC_CORE
+ depends on VIDEO_DEV && I2C
+ depends on SND && USB
+ select VIDEOBUF2_VMALLOC
select VIDEO_TUNER
- select VIDEO_TVEEPROM
+ select CYPRESS_FIRMWARE
select SND_PCM
- select CRC32
+ select VIDEO_SONY_BTF_MPX if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT
default N
---help---
This is a video4linux driver for the WIS GO7007 MPEG
encoder chip.
To compile this driver as a module, choose M here: the
- module will be called go7007
+ module will be called go7007.
config VIDEO_GO7007_USB
tristate "WIS GO7007 USB support"
@@ -25,85 +30,25 @@ config VIDEO_GO7007_USB
encoder chip over USB.
To compile this driver as a module, choose M here: the
- module will be called go7007-usb
+ module will be called go7007-usb.
-config VIDEO_GO7007_USB_S2250_BOARD
- tristate "Sensoray 2250/2251 support"
- depends on VIDEO_GO7007_USB && DVB_USB
- default N
- ---help---
- This is a video4linux driver for the Sensoray 2250/2251 device.
-
- To compile this driver as a module, choose M here: the
- module will be called s2250
-
-config VIDEO_GO7007_OV7640
- tristate "OV7640 subdev support"
- depends on VIDEO_GO7007
- default N
- ---help---
- This is a video4linux driver for the OV7640 sub-device.
-
- To compile this driver as a module, choose M here: the
- module will be called wis-ov7640
-
-config VIDEO_GO7007_SAA7113
- tristate "SAA7113 subdev support"
- depends on VIDEO_GO7007
- default N
- ---help---
- This is a video4linux driver for the SAA7113 sub-device.
-
- To compile this driver as a module, choose M here: the
- module will be called wis-saa7113
-
-config VIDEO_GO7007_SAA7115
- tristate "SAA7115 subdev support"
- depends on VIDEO_GO7007
- default N
- ---help---
- This is a video4linux driver for the SAA7115 sub-device.
-
- To compile this driver as a module, choose M here: the
- module will be called wis-saa7115
-
-config VIDEO_GO7007_TW9903
- tristate "TW9903 subdev support"
- depends on VIDEO_GO7007
- default N
- ---help---
- This is a video4linux driver for the TW9903 sub-device.
-
- To compile this driver as a module, choose M here: the
- module will be called wis-tw9903
-
-config VIDEO_GO7007_UDA1342
- tristate "UDA1342 subdev support"
- depends on VIDEO_GO7007
- default N
- ---help---
- This is a video4linux driver for the UDA1342 sub-device.
-
- To compile this driver as a module, choose M here: the
- module will be called wis-uda1342
-
-config VIDEO_GO7007_SONY_TUNER
- tristate "Sony tuner subdev support"
+config VIDEO_GO7007_LOADER
+ tristate "WIS GO7007 Loader support"
depends on VIDEO_GO7007
- default N
+ default y
---help---
- This is a video4linux driver for the Sony Tuner sub-device.
+ This is a go7007 firmware loader driver for the WIS GO7007
+ MPEG encoder chip over USB.
To compile this driver as a module, choose M here: the
- module will be called wis-sony-tuner
+ module will be called go7007-loader.
-config VIDEO_GO7007_TW2804
- tristate "TW2804 subdev support"
- depends on VIDEO_GO7007
+config VIDEO_GO7007_USB_S2250_BOARD
+ tristate "Sensoray 2250/2251 support"
+ depends on VIDEO_GO7007_USB && USB
default N
---help---
- This is a video4linux driver for the TW2804 sub-device.
+ This is a video4linux driver for the Sensoray 2250/2251 device.
To compile this driver as a module, choose M here: the
- module will be called wis-tw2804
-
+ module will be called s2250.
diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile
index 3fdbef5306a0..9c6ad4a263ec 100644
--- a/drivers/staging/media/go7007/Makefile
+++ b/drivers/staging/media/go7007/Makefile
@@ -1,18 +1,7 @@
-#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \
- wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \
- wis-tw2804.o
-
-
obj-$(CONFIG_VIDEO_GO7007) += go7007.o
obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
-obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o
-obj-$(CONFIG_VIDEO_GO7007_SAA7113) += wis-saa7113.o
-obj-$(CONFIG_VIDEO_GO7007_OV7640) += wis-ov7640.o
-obj-$(CONFIG_VIDEO_GO7007_SAA7115) += wis-saa7115.o
-obj-$(CONFIG_VIDEO_GO7007_TW9903) += wis-tw9903.o
-obj-$(CONFIG_VIDEO_GO7007_UDA1342) += wis-uda1342.o
-obj-$(CONFIG_VIDEO_GO7007_SONY_TUNER) += wis-sony-tuner.o
-obj-$(CONFIG_VIDEO_GO7007_TW2804) += wis-tw2804.o
+obj-$(CONFIG_VIDEO_GO7007_LOADER) += go7007-loader.o
+obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o
go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
snd-go7007.o
@@ -21,10 +10,6 @@ s2250-y := s2250-board.o
# Uncomment when the saa7134 patches get into upstream
#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
-#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3
-
-# S2250 needs cypress ezusb loader from dvb-usb
-ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb
+#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134
-ccflags-y += -Idrivers/media/dvb-frontends
-ccflags-y += -Idrivers/media/dvb-core
+ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/common
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
index aeba1324a9c5..3af0d9062811 100644
--- a/drivers/staging/media/go7007/README
+++ b/drivers/staging/media/go7007/README
@@ -1,11 +1,137 @@
Todo:
- - checkpatch.pl cleanups
- - sparse cleanups
- - lots of little modules, should be merged together
- and added to the build.
- - testing?
- - handle churn in v4l layer.
+ - create an API for motion detection
+ - let s2250-board use i2c subdevs as well instead of hardcoding
+ support for the i2c devices.
+ - when the driver is moved out of staging, support for saa7134-go7007
+ should be added to the saa7134 driver. The patch for that is
+ included below.
-Please send patches to Greg Kroah-Hartman <greg@linuxfoundation.org> and Cc: Ross
-Cohen <rcohen@snurgle.org> as well.
+Patch for saa7134:
+diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
+index dc68cf1..9a53794 100644
+--- a/drivers/media/pci/saa7134/saa7134-cards.c
++++ b/drivers/media/pci/saa7134/saa7134-cards.c
+@@ -5790,6 +5790,29 @@ struct saa7134_board saa7134_boards[] = {
+ .gpio = 0x6010000,
+ } },
+ },
++ [SAA7134_BOARD_WIS_VOYAGER] = {
++ .name = "WIS Voyager or compatible",
++ .audio_clock = 0x00200000,
++ .tuner_type = TUNER_PHILIPS_TDA8290,
++ .radio_type = UNSET,
++ .tuner_addr = ADDR_UNSET,
++ .radio_addr = ADDR_UNSET,
++ .mpeg = SAA7134_MPEG_GO7007,
++ .inputs = { {
++ .name = name_comp1,
++ .vmux = 0,
++ .amux = LINE2,
++ }, {
++ .name = name_tv,
++ .vmux = 3,
++ .amux = TV,
++ .tv = 1,
++ }, {
++ .name = name_svideo,
++ .vmux = 6,
++ .amux = LINE1,
++ } },
++ },
+
+ };
+
+@@ -7037,6 +7060,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
+ .subdevice = 0x0911,
+ .driver_data = SAA7134_BOARD_SENSORAY811_911,
+ }, {
++ .vendor = PCI_VENDOR_ID_PHILIPS,
++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
++ .subvendor = 0x1905, /* WIS */
++ .subdevice = 0x7007,
++ .driver_data = SAA7134_BOARD_WIS_VOYAGER,
++ }, {
+ /* --- boards without eeprom + subsystem ID --- */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
+index 8fd24e7..0a849ea 100644
+--- a/drivers/media/pci/saa7134/saa7134-core.c
++++ b/drivers/media/pci/saa7134/saa7134-core.c
+@@ -156,6 +156,8 @@ static void request_module_async(struct work_struct *work){
+ request_module("saa7134-empress");
+ if (card_is_dvb(dev))
+ request_module("saa7134-dvb");
++ if (card_is_go7007(dev))
++ request_module("saa7134-go7007");
+ if (alsa) {
+ if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
+ request_module("saa7134-alsa");
+@@ -557,8 +559,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
+ saa7134_irq_vbi_done(dev,status);
+
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
+- card_has_mpeg(dev))
+- saa7134_irq_ts_done(dev,status);
++ card_has_mpeg(dev)) {
++ if (dev->mops->irq_ts_done != NULL)
++ dev->mops->irq_ts_done(dev, status);
++ else
++ saa7134_irq_ts_done(dev, status);
++ }
+
+ if (report & SAA7134_IRQ_REPORT_GPIO16) {
+ switch (dev->has_remote) {
+diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
+index 62169dd..5fad39a 100644
+--- a/drivers/media/pci/saa7134/saa7134.h
++++ b/drivers/media/pci/saa7134/saa7134.h
+@@ -334,6 +334,7 @@ struct saa7134_card_ir {
+ #define SAA7134_BOARD_KWORLD_PC150U 189
+ #define SAA7134_BOARD_ASUSTeK_PS3_100 190
+ #define SAA7134_BOARD_HAWELL_HW_9004V1 191
++#define SAA7134_BOARD_WIS_VOYAGER 192
+
+ #define SAA7134_MAXBOARDS 32
+ #define SAA7134_INPUT_MAX 8
+@@ -364,6 +365,7 @@ enum saa7134_mpeg_type {
+ SAA7134_MPEG_UNUSED,
+ SAA7134_MPEG_EMPRESS,
+ SAA7134_MPEG_DVB,
++ SAA7134_MPEG_GO7007,
+ };
+
+ enum saa7134_mpeg_ts_type {
+@@ -403,6 +405,7 @@ struct saa7134_board {
+ #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
+ #define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
+ #define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
++#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg)
+ #define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg)
+ #define card(dev) (saa7134_boards[dev->board])
+ #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
+@@ -535,6 +538,8 @@ struct saa7134_mpeg_ops {
+ int (*init)(struct saa7134_dev *dev);
+ int (*fini)(struct saa7134_dev *dev);
+ void (*signal_change)(struct saa7134_dev *dev);
++ void (*irq_ts_done)(struct saa7134_dev *dev,
++ unsigned long status);
+ };
+
+ /* global device status */
+diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile
+index 9c6ad4a..1b23689 100644
+--- a/drivers/staging/media/go7007/Makefile
++++ b/drivers/staging/media/go7007/Makefile
+@@ -8,8 +8,7 @@ go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
+
+ s2250-y := s2250-board.o
+
+-# Uncomment when the saa7134 patches get into upstream
+-#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
+-#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134
++obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
++ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134
+
+ ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/common
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c
index 66950916df23..a5ca99d7c0b2 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/staging/media/go7007/go7007-driver.c
@@ -35,7 +35,6 @@
#include <media/v4l2-common.h>
#include "go7007-priv.h"
-#include "wis-i2c.h"
/*
* Wait for an interrupt to be delivered from the GO7007SB and return
@@ -91,43 +90,43 @@ EXPORT_SYMBOL(go7007_read_addr);
static int go7007_load_encoder(struct go7007 *go)
{
const struct firmware *fw_entry;
- char fw_name[] = "go7007fw.bin";
+ char fw_name[] = "go7007/go7007fw.bin";
void *bounce;
int fw_len, rv = 0;
u16 intr_val, intr_data;
- if (request_firmware(&fw_entry, fw_name, go->dev)) {
- v4l2_err(go, "unable to load firmware from file "
- "\"%s\"\n", fw_name);
- return -1;
- }
- if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
- v4l2_err(go, "file \"%s\" does not appear to be "
- "go7007 firmware\n", fw_name);
- release_firmware(fw_entry);
- return -1;
- }
- fw_len = fw_entry->size - 16;
- bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL);
- if (bounce == NULL) {
- v4l2_err(go, "unable to allocate %d bytes for "
- "firmware transfer\n", fw_len);
+ if (go->boot_fw == NULL) {
+ if (request_firmware(&fw_entry, fw_name, go->dev)) {
+ v4l2_err(go, "unable to load firmware from file \"%s\"\n", fw_name);
+ return -1;
+ }
+ if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
+ v4l2_err(go, "file \"%s\" does not appear to be go7007 firmware\n", fw_name);
+ release_firmware(fw_entry);
+ return -1;
+ }
+ fw_len = fw_entry->size - 16;
+ bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL);
+ if (bounce == NULL) {
+ v4l2_err(go, "unable to allocate %d bytes for firmware transfer\n", fw_len);
+ release_firmware(fw_entry);
+ return -1;
+ }
release_firmware(fw_entry);
- return -1;
+ go->boot_fw_len = fw_len;
+ go->boot_fw = bounce;
}
- release_firmware(fw_entry);
if (go7007_interface_reset(go) < 0 ||
- go7007_send_firmware(go, bounce, fw_len) < 0 ||
- go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ go7007_send_firmware(go, go->boot_fw, go->boot_fw_len) < 0 ||
+ go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
(intr_val & ~0x1) != 0x5a5a) {
v4l2_err(go, "error transferring firmware\n");
rv = -1;
}
- kfree(bounce);
return rv;
}
-MODULE_FIRMWARE("go7007fw.bin");
+MODULE_FIRMWARE("go7007/go7007fw.bin");
/*
* Boot the encoder and register the I2C adapter if requested. Do the
@@ -167,15 +166,24 @@ static int go7007_init_encoder(struct go7007 *go)
go7007_write_addr(go, 0x1000, 0x0811);
go7007_write_addr(go, 0x1000, 0x0c11);
}
- if (go->board_id == GO7007_BOARDID_MATRIX_REV) {
+ switch (go->board_id) {
+ case GO7007_BOARDID_MATRIX_REV:
/* Set GPIO pin 0 to be an output (audio clock control) */
go7007_write_addr(go, 0x3c82, 0x0001);
go7007_write_addr(go, 0x3c80, 0x00fe);
- }
- if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
+ break;
+ case GO7007_BOARDID_ADLINK_MPG24:
/* set GPIO5 to be an output, currently low */
go7007_write_addr(go, 0x3c82, 0x0000);
go7007_write_addr(go, 0x3c80, 0x00df);
+ break;
+ case GO7007_BOARDID_ADS_USBAV_709:
+ /* GPIO pin 0: audio clock control */
+ /* pin 2: TW9906 reset */
+ /* pin 3: capture LED */
+ go7007_write_addr(go, 0x3c82, 0x000d);
+ go7007_write_addr(go, 0x3c80, 0x00f2);
+ break;
}
return 0;
}
@@ -196,18 +204,54 @@ int go7007_reset_encoder(struct go7007 *go)
/*
* Attempt to instantiate an I2C client by ID, probably loading a module.
*/
-static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
- int addr)
+static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *const i2c)
{
struct go7007 *go = i2c_get_adapdata(adapter);
struct v4l2_device *v4l2_dev = &go->v4l2_dev;
-
- if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL))
+ struct v4l2_subdev *sd;
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.type, i2c->type, sizeof(info.type));
+ info.addr = i2c->addr;
+ info.flags = i2c->flags;
+
+ sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL);
+ if (sd) {
+ if (i2c->is_video)
+ go->sd_video = sd;
+ if (i2c->is_audio)
+ go->sd_audio = sd;
return 0;
+ }
- dev_info(&adapter->dev,
- "go7007: probing for module i2c:%s failed\n", type);
- return -1;
+ printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", i2c->type);
+ return -EINVAL;
+}
+
+/*
+ * Detach and unregister the encoder. The go7007 struct won't be freed
+ * until v4l2 finishes releasing its resources and all associated fds are
+ * closed by applications.
+ */
+static void go7007_remove(struct v4l2_device *v4l2_dev)
+{
+ struct go7007 *go = container_of(v4l2_dev, struct go7007, v4l2_dev);
+
+ v4l2_device_unregister(v4l2_dev);
+ if (go->hpi_ops->release)
+ go->hpi_ops->release(go);
+ if (go->i2c_adapter_online) {
+ if (i2c_del_adapter(&go->i2c_adapter) == 0)
+ go->i2c_adapter_online = 0;
+ else
+ v4l2_err(&go->v4l2_dev,
+ "error removing I2C adapter!\n");
+ }
+
+ kfree(go->boot_fw);
+ go7007_v4l2_remove(go);
+ kfree(go);
}
/*
@@ -218,38 +262,63 @@ static int init_i2c_module(struct i2c_adapter *adapter, const char *type,
*
* Must NOT be called with the hw_lock held.
*/
-int go7007_register_encoder(struct go7007 *go)
+int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs)
{
int i, ret;
dev_info(go->dev, "go7007: registering new %s\n", go->name);
+ go->v4l2_dev.release = go7007_remove;
+ ret = v4l2_device_register(go->dev, &go->v4l2_dev);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&go->hw_lock);
ret = go7007_init_encoder(go);
mutex_unlock(&go->hw_lock);
if (ret < 0)
- return -1;
+ return ret;
- /* v4l2 init must happen before i2c subdevs */
- ret = go7007_v4l2_init(go);
+ ret = go7007_v4l2_ctrl_init(go);
if (ret < 0)
return ret;
if (!go->i2c_adapter_online &&
go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
- if (go7007_i2c_init(go) < 0)
- return -1;
+ ret = go7007_i2c_init(go);
+ if (ret < 0)
+ return ret;
go->i2c_adapter_online = 1;
}
if (go->i2c_adapter_online) {
- for (i = 0; i < go->board_info->num_i2c_devs; ++i)
- init_i2c_module(&go->i2c_adapter,
- go->board_info->i2c_devs[i].type,
- go->board_info->i2c_devs[i].addr);
+ if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) {
+ /* Reset the TW9906 */
+ go7007_write_addr(go, 0x3c82, 0x0009);
+ msleep(50);
+ go7007_write_addr(go, 0x3c82, 0x000d);
+ }
+ for (i = 0; i < num_i2c_devs; ++i)
+ init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]);
+
+ if (go->tuner_type >= 0) {
+ struct tuner_setup setup = {
+ .addr = ADDR_UNSET,
+ .type = go->tuner_type,
+ .mode_mask = T_ANALOG_TV,
+ };
+
+ v4l2_device_call_all(&go->v4l2_dev, 0, tuner,
+ s_type_addr, &setup);
+ }
if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
- i2c_clients_command(&go->i2c_adapter,
- DECODER_SET_CHANNEL, &go->channel_number);
+ v4l2_subdev_call(go->sd_video, video, s_routing,
+ 0, 0, go->channel_number + 1);
}
+
+ ret = go7007_v4l2_init(go);
+ if (ret < 0)
+ return ret;
+
if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
go->audio_enabled = 1;
go7007_snd_init(go);
@@ -309,48 +378,54 @@ start_error:
/*
* Store a byte in the current video buffer, if there is one.
*/
-static inline void store_byte(struct go7007_buffer *gobuf, u8 byte)
+static inline void store_byte(struct go7007_buffer *vb, u8 byte)
{
- if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) {
- unsigned int pgidx = gobuf->offset >> PAGE_SHIFT;
- unsigned int pgoff = gobuf->offset & ~PAGE_MASK;
+ if (vb && vb->vb.v4l2_planes[0].bytesused < GO7007_BUF_SIZE) {
+ u8 *ptr = vb2_plane_vaddr(&vb->vb, 0);
- *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte;
- ++gobuf->offset;
- ++gobuf->bytesused;
+ ptr[vb->vb.v4l2_planes[0].bytesused++] = byte;
}
}
/*
* Deliver the last video buffer and get a new one to start writing to.
*/
-static void frame_boundary(struct go7007 *go)
+static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
{
- struct go7007_buffer *gobuf;
+ struct go7007_buffer *vb_tmp = NULL;
+ u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
int i;
- if (go->active_buf) {
- if (go->active_buf->modet_active) {
- if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) {
+ if (vb) {
+ if (vb->modet_active) {
+ if (*bytesused + 216 < GO7007_BUF_SIZE) {
for (i = 0; i < 216; ++i)
- store_byte(go->active_buf,
- go->active_map[i]);
- go->active_buf->bytesused -= 216;
+ store_byte(vb, go->active_map[i]);
+ *bytesused -= 216;
} else
- go->active_buf->modet_active = 0;
+ vb->modet_active = 0;
}
- go->active_buf->state = BUF_STATE_DONE;
- wake_up_interruptible(&go->frame_waitq);
- go->active_buf = NULL;
+ vb->vb.v4l2_buf.sequence = go->next_seq++;
+ v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
+ vb_tmp = vb;
+ spin_lock(&go->spinlock);
+ list_del(&vb->list);
+ if (list_empty(&go->vidq_active))
+ vb = NULL;
+ else
+ vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+ go->active_buf = vb;
+ spin_unlock(&go->spinlock);
+ vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
+ return vb;
}
- list_for_each_entry(gobuf, &go->stream, stream)
- if (gobuf->state == BUF_STATE_QUEUED) {
- gobuf->seq = go->next_seq;
- do_gettimeofday(&gobuf->timestamp);
- go->active_buf = gobuf;
- break;
- }
- ++go->next_seq;
+ spin_lock(&go->spinlock);
+ if (!list_empty(&go->vidq_active))
+ vb = go->active_buf =
+ list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+ spin_unlock(&go->spinlock);
+ go->next_seq++;
+ return vb;
}
static void write_bitmap_word(struct go7007 *go)
@@ -374,30 +449,30 @@ static void write_bitmap_word(struct go7007 *go)
*/
void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
{
- int i, seq_start_code = -1, frame_start_code = -1;
-
- spin_lock(&go->spinlock);
+ struct go7007_buffer *vb = go->active_buf;
+ int i, seq_start_code = -1, gop_start_code = -1, frame_start_code = -1;
switch (go->format) {
- case GO7007_FORMAT_MPEG4:
+ case V4L2_PIX_FMT_MPEG4:
seq_start_code = 0xB0;
+ gop_start_code = 0xB3;
frame_start_code = 0xB6;
break;
- case GO7007_FORMAT_MPEG1:
- case GO7007_FORMAT_MPEG2:
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
seq_start_code = 0xB3;
+ gop_start_code = 0xB8;
frame_start_code = 0x00;
break;
}
for (i = 0; i < length; ++i) {
- if (go->active_buf != NULL &&
- go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) {
+ if (vb && vb->vb.v4l2_planes[0].bytesused >= GO7007_BUF_SIZE - 3) {
v4l2_info(&go->v4l2_dev, "dropping oversized frame\n");
- go->active_buf->offset -= go->active_buf->bytesused;
- go->active_buf->bytesused = 0;
- go->active_buf->modet_active = 0;
- go->active_buf = NULL;
+ vb->vb.v4l2_planes[0].bytesused = 0;
+ vb->frame_offset = 0;
+ vb->modet_active = 0;
+ vb = go->active_buf = NULL;
}
switch (go->state) {
@@ -410,7 +485,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
go->state = STATE_FF;
break;
default:
- store_byte(go->active_buf, buf[i]);
+ store_byte(vb, buf[i]);
break;
}
break;
@@ -420,12 +495,12 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
go->state = STATE_00_00;
break;
case 0xFF:
- store_byte(go->active_buf, 0x00);
+ store_byte(vb, 0x00);
go->state = STATE_FF;
break;
default:
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, buf[i]);
+ store_byte(vb, 0x00);
+ store_byte(vb, buf[i]);
go->state = STATE_DATA;
break;
}
@@ -433,21 +508,21 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
case STATE_00_00:
switch (buf[i]) {
case 0x00:
- store_byte(go->active_buf, 0x00);
+ store_byte(vb, 0x00);
/* go->state remains STATE_00_00 */
break;
case 0x01:
go->state = STATE_00_00_01;
break;
case 0xFF:
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x00);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x00);
go->state = STATE_FF;
break;
default:
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, buf[i]);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x00);
+ store_byte(vb, buf[i]);
go->state = STATE_DATA;
break;
}
@@ -455,31 +530,26 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
case STATE_00_00_01:
if (buf[i] == 0xF8 && go->modet_enable == 0) {
/* MODET start code, but MODET not enabled */
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x01);
- store_byte(go->active_buf, 0xF8);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x01);
+ store_byte(vb, 0xF8);
go->state = STATE_DATA;
break;
}
/* If this is the start of a new MPEG frame,
* get a new buffer */
- if ((go->format == GO7007_FORMAT_MPEG1 ||
- go->format == GO7007_FORMAT_MPEG2 ||
- go->format == GO7007_FORMAT_MPEG4) &&
- (buf[i] == seq_start_code ||
- buf[i] == 0xB8 || /* GOP code */
- buf[i] == frame_start_code)) {
- if (go->active_buf == NULL || go->seen_frame)
- frame_boundary(go);
- if (buf[i] == frame_start_code) {
- if (go->active_buf != NULL)
- go->active_buf->frame_offset =
- go->active_buf->offset;
- go->seen_frame = 1;
- } else {
- go->seen_frame = 0;
- }
+ if ((go->format == V4L2_PIX_FMT_MPEG1 ||
+ go->format == V4L2_PIX_FMT_MPEG2 ||
+ go->format == V4L2_PIX_FMT_MPEG4) &&
+ (buf[i] == seq_start_code ||
+ buf[i] == gop_start_code ||
+ buf[i] == frame_start_code)) {
+ if (vb == NULL || go->seen_frame)
+ vb = frame_boundary(go, vb);
+ go->seen_frame = buf[i] == frame_start_code;
+ if (vb && go->seen_frame)
+ vb->frame_offset = vb->vb.v4l2_planes[0].bytesused;
}
/* Handle any special chunk types, or just write the
* start code to the (potentially new) buffer */
@@ -498,16 +568,16 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
go->state = STATE_MODET_MAP;
break;
case 0xFF: /* Potential JPEG start code */
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x01);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x01);
go->state = STATE_FF;
break;
default:
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x00);
- store_byte(go->active_buf, 0x01);
- store_byte(go->active_buf, buf[i]);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x00);
+ store_byte(vb, 0x01);
+ store_byte(vb, buf[i]);
go->state = STATE_DATA;
break;
}
@@ -515,20 +585,20 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
case STATE_FF:
switch (buf[i]) {
case 0x00:
- store_byte(go->active_buf, 0xFF);
+ store_byte(vb, 0xFF);
go->state = STATE_00;
break;
case 0xFF:
- store_byte(go->active_buf, 0xFF);
+ store_byte(vb, 0xFF);
/* go->state remains STATE_FF */
break;
case 0xD8:
- if (go->format == GO7007_FORMAT_MJPEG)
- frame_boundary(go);
+ if (go->format == V4L2_PIX_FMT_MJPEG)
+ vb = frame_boundary(go, vb);
/* fall through */
default:
- store_byte(go->active_buf, 0xFF);
- store_byte(go->active_buf, buf[i]);
+ store_byte(vb, 0xFF);
+ store_byte(vb, buf[i]);
go->state = STATE_DATA;
break;
}
@@ -551,8 +621,8 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
write_bitmap_word(go);
} else
go->modet_word = buf[i] << 8;
- } else if (go->parse_length == 207 && go->active_buf) {
- go->active_buf->modet_active = buf[i];
+ } else if (go->parse_length == 207 && vb) {
+ vb->modet_active = buf[i];
}
if (++go->parse_length == 208)
go->state = STATE_DATA;
@@ -563,15 +633,14 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
break;
}
}
-
- spin_unlock(&go->spinlock);
}
EXPORT_SYMBOL(go7007_parse_video_stream);
/*
* Allocate a new go7007 struct. Used by the hardware-specific probe.
*/
-struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
+struct go7007 *go7007_alloc(const struct go7007_board_info *board,
+ struct device *dev)
{
struct go7007 *go;
int i;
@@ -588,33 +657,17 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
mutex_init(&go->hw_lock);
init_waitqueue_head(&go->frame_waitq);
spin_lock_init(&go->spinlock);
- go->video_dev = NULL;
- go->ref_count = 0;
go->status = STATUS_INIT;
memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
go->i2c_adapter_online = 0;
go->interrupt_available = 0;
init_waitqueue_head(&go->interrupt_waitq);
- go->in_use = 0;
go->input = 0;
- if (board->sensor_flags & GO7007_SENSOR_TV) {
- go->standard = GO7007_STD_NTSC;
- go->width = 720;
- go->height = 480;
- go->sensor_framerate = 30000;
- } else {
- go->standard = GO7007_STD_OTHER;
- go->width = board->sensor_width;
- go->height = board->sensor_height;
- go->sensor_framerate = board->sensor_framerate;
- }
- go->encoder_v_offset = board->sensor_v_offset;
- go->encoder_h_offset = board->sensor_h_offset;
+ go7007_update_board(go);
go->encoder_h_halve = 0;
go->encoder_v_halve = 0;
go->encoder_subsample = 0;
- go->streaming = 0;
- go->format = GO7007_FORMAT_MJPEG;
+ go->format = V4L2_PIX_FMT_MJPEG;
go->bitrate = 1500000;
go->fps_scale = 1;
go->pali = 0;
@@ -633,31 +686,30 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
go->modet_map[i] = 0;
go->audio_deliver = NULL;
go->audio_enabled = 0;
- INIT_LIST_HEAD(&go->stream);
return go;
}
EXPORT_SYMBOL(go7007_alloc);
-/*
- * Detach and unregister the encoder. The go7007 struct won't be freed
- * until v4l2 finishes releasing its resources and all associated fds are
- * closed by applications.
- */
-void go7007_remove(struct go7007 *go)
+void go7007_update_board(struct go7007 *go)
{
- if (go->i2c_adapter_online) {
- if (i2c_del_adapter(&go->i2c_adapter) == 0)
- go->i2c_adapter_online = 0;
- else
- v4l2_err(&go->v4l2_dev,
- "error removing I2C adapter!\n");
- }
+ const struct go7007_board_info *board = go->board_info;
- if (go->audio_enabled)
- go7007_snd_remove(go);
- go7007_v4l2_remove(go);
+ if (board->sensor_flags & GO7007_SENSOR_TV) {
+ go->standard = GO7007_STD_NTSC;
+ go->std = V4L2_STD_NTSC_M;
+ go->width = 720;
+ go->height = 480;
+ go->sensor_framerate = 30000;
+ } else {
+ go->standard = GO7007_STD_OTHER;
+ go->width = board->sensor_width;
+ go->height = board->sensor_height;
+ go->sensor_framerate = board->sensor_framerate;
+ }
+ go->encoder_v_offset = board->sensor_v_offset;
+ go->encoder_h_offset = board->sensor_h_offset;
}
-EXPORT_SYMBOL(go7007_remove);
+EXPORT_SYMBOL(go7007_update_board);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c
index a5ede1c109d0..c2d0e58afc34 100644
--- a/drivers/staging/media/go7007/go7007-fw.c
+++ b/drivers/staging/media/go7007/go7007-fw.c
@@ -36,6 +36,8 @@
#include "go7007-priv.h"
+#define GO7007_FW_NAME "go7007/go7007tv.bin"
+
/* Constants used in the source firmware image to describe code segments */
#define FLAG_MODE_MJPEG (1)
@@ -455,9 +457,9 @@ static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13);
CODE_ADD(c, 0xffff, 16);
- CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+ CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0x7 : 0x4, 4);
if (frame != PFRAME)
- CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+ CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0x7 : 0x4, 4);
else
CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */
CODE_ADD(c, 0, 3); /* What is this?? */
@@ -466,7 +468,7 @@ static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
if (j != 8)
CODE_ADD(c, 0, j);
- if (go->format == GO7007_FORMAT_MPEG2) {
+ if (go->format == V4L2_PIX_FMT_MPEG2) {
CODE_ADD(c, 0x1, 24);
CODE_ADD(c, 0xb5, 8);
CODE_ADD(c, 0x844, 12);
@@ -537,7 +539,7 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
int i, aspect_ratio, picture_rate;
CODE_GEN(c, buf + 6);
- if (go->format == GO7007_FORMAT_MPEG1) {
+ if (go->format == V4L2_PIX_FMT_MPEG1) {
switch (go->aspect_ratio) {
case GO7007_RATIO_4_3:
aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
@@ -587,9 +589,9 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
CODE_ADD(c, go->height, 12);
CODE_ADD(c, aspect_ratio, 4);
CODE_ADD(c, picture_rate, 4);
- CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18);
+ CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 20000 : 0x3ffff, 18);
CODE_ADD(c, 1, 1);
- CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10);
+ CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 112 : 20, 10);
CODE_ADD(c, 0, 3);
/* Byte-align with zeros */
@@ -597,7 +599,7 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
if (i != 8)
CODE_ADD(c, 0, i);
- if (go->format == GO7007_FORMAT_MPEG2) {
+ if (go->format == V4L2_PIX_FMT_MPEG2) {
CODE_ADD(c, 0x1, 24);
CODE_ADD(c, 0xb5, 8);
CODE_ADD(c, 0x148, 12);
@@ -930,10 +932,10 @@ static int brctrl_to_package(struct go7007 *go,
__le16 *code, int space, int *framelen)
{
int converge_speed = 0;
- int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ?
+ int lambda = (go->format == V4L2_PIX_FMT_MJPEG || go->dvd_mode) ?
100 : 0;
int peak_rate = 6 * go->bitrate / 5;
- int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ?
+ int vbv_buffer = go->format == V4L2_PIX_FMT_MJPEG ?
go->bitrate :
(go->dvd_mode ? 900000 : peak_rate);
int fps = go->sensor_framerate / go->fps_scale;
@@ -1096,10 +1098,10 @@ static int config_package(struct go7007 *go, __le16 *code, int space)
0xc003, 0x28b4,
0xc004, 0x3c5a,
0xdc05, 0x2a77,
- 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 :
- (go->format == GO7007_FORMAT_H263 ? 0 : 1),
- 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 :
- (go->format == GO7007_FORMAT_H263 ? 0x61 :
+ 0xc6c3, go->format == V4L2_PIX_FMT_MPEG4 ? 0 :
+ (go->format == V4L2_PIX_FMT_H263 ? 0 : 1),
+ 0xc680, go->format == V4L2_PIX_FMT_MPEG4 ? 0xf1 :
+ (go->format == V4L2_PIX_FMT_H263 ? 0x61 :
0xd3),
0xc780, 0x0140,
0xe009, 0x0001,
@@ -1123,15 +1125,15 @@ static int config_package(struct go7007 *go, __le16 *code, int space)
(!go->interlace_coding) ?
0x0008 : 0x0009,
0xc404, go->interlace_coding ? 0x44 :
- (go->format == GO7007_FORMAT_MPEG4 ? 0x11 :
- (go->format == GO7007_FORMAT_MPEG1 ? 0x02 :
- (go->format == GO7007_FORMAT_MPEG2 ? 0x04 :
- (go->format == GO7007_FORMAT_H263 ? 0x08 :
+ (go->format == V4L2_PIX_FMT_MPEG4 ? 0x11 :
+ (go->format == V4L2_PIX_FMT_MPEG1 ? 0x02 :
+ (go->format == V4L2_PIX_FMT_MPEG2 ? 0x04 :
+ (go->format == V4L2_PIX_FMT_H263 ? 0x08 :
0x20)))),
- 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 :
- (go->format == GO7007_FORMAT_MPEG1 ? 1 :
- (go->format == GO7007_FORMAT_MPEG2 ? 2 :
- (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) |
+ 0xbf0a, (go->format == V4L2_PIX_FMT_MPEG4 ? 8 :
+ (go->format == V4L2_PIX_FMT_MPEG1 ? 1 :
+ (go->format == V4L2_PIX_FMT_MPEG2 ? 2 :
+ (go->format == V4L2_PIX_FMT_H263 ? 4 : 16)))) |
((go->repeat_seqhead ? 1 : 0) << 6) |
((go->dvd_mode ? 1 : 0) << 9) |
((go->gop_header_enable ? 1 : 0) << 10),
@@ -1348,19 +1350,19 @@ static int final_package(struct go7007 *go, __le16 *code, int space)
0x41,
go->ipb ? 0xd4c : 0x36b,
(rows << 8) | (go->width >> 4),
- go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0,
+ go->format == V4L2_PIX_FMT_MPEG4 ? 0x0404 : 0,
(1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) |
((go->closed_gop ? 1 : 0) << 12) |
- ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) |
+ ((go->format == V4L2_PIX_FMT_MPEG4 ? 1 : 0) << 11) |
/* (1 << 9) | */
((go->ipb ? 3 : 0) << 7) |
((go->modet_enable ? 1 : 0) << 2) |
((go->dvd_mode ? 1 : 0) << 1) | 1,
- (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 :
- (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 :
- (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 :
- (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 :
- (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))),
+ (go->format == V4L2_PIX_FMT_MPEG1 ? 0x89a0 :
+ (go->format == V4L2_PIX_FMT_MPEG2 ? 0x89a0 :
+ (go->format == V4L2_PIX_FMT_MJPEG ? 0x89a0 :
+ (go->format == V4L2_PIX_FMT_MPEG4 ? 0x8920 :
+ (go->format == V4L2_PIX_FMT_H263 ? 0x8920 : 0))))),
go->ipb ? 0x1f15 : 0x1f0b,
go->ipb ? 0x0015 : 0x000b,
go->ipb ? 0xa800 : 0x5800,
@@ -1503,13 +1505,13 @@ static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
switch (type) {
case SPECIAL_FRM_HEAD:
switch (go->format) {
- case GO7007_FORMAT_MJPEG:
+ case V4L2_PIX_FMT_MJPEG:
return gen_mjpeghdr_to_package(go, code, space);
- case GO7007_FORMAT_MPEG1:
- case GO7007_FORMAT_MPEG2:
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
return gen_mpeg1hdr_to_package(go, code, space,
framelen);
- case GO7007_FORMAT_MPEG4:
+ case V4L2_PIX_FMT_MPEG4:
return gen_mpeg4hdr_to_package(go, code, space,
framelen);
}
@@ -1519,11 +1521,11 @@ static int do_special(struct go7007 *go, u16 type, __le16 *code, int space,
return config_package(go, code, space);
case SPECIAL_SEQHEAD:
switch (go->format) {
- case GO7007_FORMAT_MPEG1:
- case GO7007_FORMAT_MPEG2:
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
return seqhead_to_package(go, code, space,
mpeg1_sequence_header);
- case GO7007_FORMAT_MPEG4:
+ case V4L2_PIX_FMT_MPEG4:
return seqhead_to_package(go, code, space,
mpeg4_sequence_header);
default:
@@ -1553,25 +1555,25 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
int ret;
switch (go->format) {
- case GO7007_FORMAT_MJPEG:
+ case V4L2_PIX_FMT_MJPEG:
mode_flag = FLAG_MODE_MJPEG;
break;
- case GO7007_FORMAT_MPEG1:
+ case V4L2_PIX_FMT_MPEG1:
mode_flag = FLAG_MODE_MPEG1;
break;
- case GO7007_FORMAT_MPEG2:
+ case V4L2_PIX_FMT_MPEG2:
mode_flag = FLAG_MODE_MPEG2;
break;
- case GO7007_FORMAT_MPEG4:
+ case V4L2_PIX_FMT_MPEG4:
mode_flag = FLAG_MODE_MPEG4;
break;
default:
return -1;
}
- if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) {
+ if (request_firmware(&fw_entry, GO7007_FW_NAME, go->dev)) {
dev_err(go->dev,
"unable to load firmware from file \"%s\"\n",
- go->board_info->firmware);
+ GO7007_FW_NAME);
return -1;
}
code = kzalloc(codespace * 2, GFP_KERNEL);
@@ -1586,7 +1588,7 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
if (chunk_len + 2 > srclen) {
dev_err(go->dev,
"firmware file \"%s\" appears to be corrupted\n",
- go->board_info->firmware);
+ GO7007_FW_NAME);
goto fw_failed;
}
if (chunk_flags & mode_flag) {
@@ -1622,3 +1624,5 @@ fw_failed:
release_firmware(fw_entry);
return -1;
}
+
+MODULE_FIRMWARE(GO7007_FW_NAME);
diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c
index 39456a36b2c6..74f25e03c326 100644
--- a/drivers/staging/media/go7007/go7007-i2c.c
+++ b/drivers/staging/media/go7007/go7007-i2c.c
@@ -28,7 +28,6 @@
#include <linux/uaccess.h>
#include "go7007-priv.h"
-#include "wis-i2c.h"
/********************* Driver for on-board I2C adapter *********************/
@@ -52,11 +51,11 @@ static DEFINE_MUTEX(adlink_mpg24_i2c_lock);
static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
u16 command, int flags, u8 *data)
{
- int i, ret = -1;
+ int i, ret = -EIO;
u16 val;
if (go->status == STATUS_SHUTDOWN)
- return -1;
+ return -ENODEV;
#ifdef GO7007_I2C_DEBUG
if (read)
@@ -146,7 +145,7 @@ static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
struct go7007 *go = i2c_get_adapdata(adapter);
if (size != I2C_SMBUS_BYTE_DATA)
- return -1;
+ return -EIO;
return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command,
flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte);
}
@@ -170,26 +169,26 @@ static int go7007_i2c_master_xfer(struct i2c_adapter *adapter,
(msgs[i].flags & I2C_M_RD) ||
!(msgs[i + 1].flags & I2C_M_RD) ||
msgs[i + 1].len != 1)
- return -1;
+ return -EIO;
if (go7007_i2c_xfer(go, msgs[i].addr, 1,
(msgs[i].buf[0] << 8) | msgs[i].buf[1],
0x01, &msgs[i + 1].buf[0]) < 0)
- return -1;
+ return -EIO;
++i;
} else if (msgs[i].len == 3) {
if (msgs[i].flags & I2C_M_RD)
- return -1;
+ return -EIO;
if (msgs[i].len != 3)
- return -1;
+ return -EIO;
if (go7007_i2c_xfer(go, msgs[i].addr, 0,
(msgs[i].buf[0] << 8) | msgs[i].buf[1],
0x01, &msgs[i].buf[2]) < 0)
- return -1;
+ return -EIO;
} else
- return -1;
+ return -EIO;
}
- return 0;
+ return num;
}
static u32 go7007_functionality(struct i2c_adapter *adapter)
diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/staging/media/go7007/go7007-loader.c
new file mode 100644
index 000000000000..f846ad5819dc
--- /dev/null
+++ b/drivers/staging/media/go7007/go7007-loader.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2008 Sensoray Company Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <cypress_firmware.h>
+
+struct fw_config {
+ u16 vendor;
+ u16 product;
+ const char * const fw_name1;
+ const char * const fw_name2;
+};
+
+struct fw_config fw_configs[] = {
+ { 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" },
+ { 0x093b, 0xa002, "go7007/px-m402u.fw", NULL },
+ { 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL },
+ { 0x0eb1, 0x6666, "go7007/lr192.fw", NULL },
+ { 0x0eb1, 0x6668, "go7007/wis-startrek.fw", NULL },
+ { 0, 0, NULL, NULL }
+};
+MODULE_FIRMWARE("go7007/s2250-1.fw");
+MODULE_FIRMWARE("go7007/s2250-2.fw");
+MODULE_FIRMWARE("go7007/px-m402u.fw");
+MODULE_FIRMWARE("go7007/px-tv402u.fw");
+MODULE_FIRMWARE("go7007/lr192.fw");
+MODULE_FIRMWARE("go7007/wis-startrek.fw");
+
+static int go7007_loader_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev;
+ const struct firmware *fw;
+ u16 vendor, product;
+ const char *fw1, *fw2;
+ int ret;
+ int i;
+
+ usbdev = usb_get_dev(interface_to_usbdev(interface));
+ if (!usbdev)
+ goto failed2;
+
+ if (usbdev->descriptor.bNumConfigurations != 1) {
+ dev_err(&interface->dev, "can't handle multiple config\n");
+ return -ENODEV;
+ }
+
+ vendor = le16_to_cpu(usbdev->descriptor.idVendor);
+ product = le16_to_cpu(usbdev->descriptor.idProduct);
+
+ for (i = 0; fw_configs[i].fw_name1; i++)
+ if (fw_configs[i].vendor == vendor &&
+ fw_configs[i].product == product)
+ break;
+
+ /* Should never happen */
+ if (fw_configs[i].fw_name1 == NULL)
+ goto failed2;
+
+ fw1 = fw_configs[i].fw_name1;
+ fw2 = fw_configs[i].fw_name2;
+
+ dev_info(&interface->dev, "loading firmware %s\n", fw1);
+
+ if (request_firmware(&fw, fw1, &usbdev->dev)) {
+ dev_err(&interface->dev,
+ "unable to load firmware from file \"%s\"\n", fw1);
+ goto failed2;
+ }
+ ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
+ release_firmware(fw);
+ if (0 != ret) {
+ dev_err(&interface->dev, "loader download failed\n");
+ goto failed2;
+ }
+
+ if (fw2 == NULL)
+ return 0;
+
+ if (request_firmware(&fw, fw2, &usbdev->dev)) {
+ dev_err(&interface->dev,
+ "unable to load firmware from file \"%s\"\n", fw2);
+ goto failed2;
+ }
+ ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
+ release_firmware(fw);
+ if (0 != ret) {
+ dev_err(&interface->dev, "firmware download failed\n");
+ goto failed2;
+ }
+ return 0;
+
+failed2:
+ dev_err(&interface->dev, "probe failed\n");
+ return -ENODEV;
+}
+
+static void go7007_loader_disconnect(struct usb_interface *interface)
+{
+ dev_info(&interface->dev, "disconnect\n");
+ usb_set_intfdata(interface, NULL);
+}
+
+static const struct usb_device_id go7007_loader_ids[] = {
+ { USB_DEVICE(0x1943, 0xa250) },
+ { USB_DEVICE(0x093b, 0xa002) },
+ { USB_DEVICE(0x093b, 0xa004) },
+ { USB_DEVICE(0x0eb1, 0x6666) },
+ { USB_DEVICE(0x0eb1, 0x6668) },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, go7007_loader_ids);
+
+static struct usb_driver go7007_loader_driver = {
+ .name = "go7007-loader",
+ .probe = go7007_loader_probe,
+ .disconnect = go7007_loader_disconnect,
+ .id_table = go7007_loader_ids,
+};
+
+module_usb_driver(go7007_loader_driver);
+
+MODULE_AUTHOR("");
+MODULE_DESCRIPTION("firmware loader for go7007-usb");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h
index b58c394c6555..6e16af720504 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/staging/media/go7007/go7007-priv.h
@@ -22,6 +22,9 @@
*/
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
struct go7007;
@@ -34,15 +37,13 @@ struct go7007;
#define GO7007_BOARDID_XMEN_II 5
#define GO7007_BOARDID_XMEN_III 6
#define GO7007_BOARDID_MATRIX_REV 7
-#define GO7007_BOARDID_PX_M402U 16
-#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */
-#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */
-#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */
-#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */
-#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */
-#define GO7007_BOARDID_ENDURA 22
-#define GO7007_BOARDID_ADLINK_MPG24 23
-#define GO7007_BOARDID_SENSORAY_2250 24 /* Sensoray 2250/2251 */
+#define GO7007_BOARDID_PX_M402U 8
+#define GO7007_BOARDID_PX_TV402U 9
+#define GO7007_BOARDID_LIFEVIEW_LR192 10 /* TV Walker Ultra */
+#define GO7007_BOARDID_ENDURA 11
+#define GO7007_BOARDID_ADLINK_MPG24 12
+#define GO7007_BOARDID_SENSORAY_2250 13 /* Sensoray 2250/2251 */
+#define GO7007_BOARDID_ADS_USBAV_709 14
/* Various characteristics of each board */
#define GO7007_BOARD_HAS_AUDIO (1<<0)
@@ -61,6 +62,7 @@ struct go7007;
#define GO7007_SENSOR_TV (1<<7)
#define GO7007_SENSOR_VBI (1<<8)
#define GO7007_SENSOR_SCALING (1<<9)
+#define GO7007_SENSOR_SAA7115 (1<<10)
/* Characteristics of audio sensor devices */
#define GO7007_AUDIO_I2S_MODE_1 (1)
@@ -74,7 +76,6 @@ struct go7007;
#define GO7007_AUDIO_OKI_MODE (1<<17)
struct go7007_board_info {
- char *firmware;
unsigned int flags;
int hpi_buffer_cap;
unsigned int sensor_flags;
@@ -88,17 +89,25 @@ struct go7007_board_info {
int audio_bclk_div;
int audio_main_div;
int num_i2c_devs;
- struct {
+ struct go_i2c {
const char *type;
- int id;
+ unsigned int is_video:1;
+ unsigned int is_audio:1;
int addr;
- } i2c_devs[4];
+ u32 flags;
+ } i2c_devs[5];
int num_inputs;
struct {
int video_input;
- int audio_input;
+ int audio_index;
char *name;
} inputs[4];
+ int video_config;
+ int num_aud_inputs;
+ struct {
+ int audio_input;
+ char *name;
+ } aud_inputs[3];
};
struct go7007_hpi_ops {
@@ -109,6 +118,7 @@ struct go7007_hpi_ops {
int (*stream_stop)(struct go7007 *go);
int (*send_firmware)(struct go7007 *go, u8 *data, int len);
int (*send_command)(struct go7007 *go, unsigned int cmd, void *arg);
+ void (*release)(struct go7007 *go);
};
/* The video buffer size must be a multiple of PAGE_SIZE */
@@ -116,35 +126,12 @@ struct go7007_hpi_ops {
#define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT)
struct go7007_buffer {
- struct go7007 *go; /* Reverse reference for VMA ops */
- int index; /* Reverse reference for DQBUF */
- enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state;
- u32 seq;
- struct timeval timestamp;
- struct list_head stream;
- struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */
- unsigned long user_addr;
- unsigned int page_count;
- unsigned int offset;
- unsigned int bytesused;
+ struct vb2_buffer vb;
+ struct list_head list;
unsigned int frame_offset;
u32 modet_active;
- int mapped;
};
-struct go7007_file {
- struct go7007 *go;
- struct mutex lock;
- int buf_count;
- struct go7007_buffer *bufs;
-};
-
-#define GO7007_FORMAT_MJPEG 0
-#define GO7007_FORMAT_MPEG4 1
-#define GO7007_FORMAT_MPEG1 2
-#define GO7007_FORMAT_MPEG2 3
-#define GO7007_FORMAT_H263 4
-
#define GO7007_RATIO_1_1 0
#define GO7007_RATIO_4_3 1
#define GO7007_RATIO_16_9 2
@@ -163,24 +150,38 @@ enum go7007_parser_state {
struct go7007 {
struct device *dev;
- struct go7007_board_info *board_info;
+ u8 bus_info[32];
+ const struct go7007_board_info *board_info;
unsigned int board_id;
int tuner_type;
int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */
char name[64];
- struct video_device *video_dev;
+ struct video_device vdev;
+ void *boot_fw;
+ unsigned boot_fw_len;
struct v4l2_device v4l2_dev;
- int ref_count;
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *mpeg_video_encoding;
+ struct v4l2_ctrl *mpeg_video_gop_size;
+ struct v4l2_ctrl *mpeg_video_gop_closure;
+ struct v4l2_ctrl *mpeg_video_bitrate;
+ struct v4l2_ctrl *mpeg_video_aspect_ratio;
+ struct v4l2_ctrl *mpeg_video_b_frames;
+ struct v4l2_ctrl *mpeg_video_rep_seqheader;
enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
spinlock_t spinlock;
struct mutex hw_lock;
- int streaming;
- int in_use;
+ struct mutex serialize_lock;
int audio_enabled;
+ struct v4l2_subdev *sd_video;
+ struct v4l2_subdev *sd_audio;
+ u8 usb_buf[16];
/* Video input */
int input;
+ int aud_input;
enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard;
+ v4l2_std_id std;
int sensor_framerate;
int width;
int height;
@@ -191,7 +192,7 @@ struct go7007 {
unsigned int encoder_subsample:1;
/* Encoder config */
- int format;
+ u32 format;
int bitrate;
int fps_scale;
int pali;
@@ -217,14 +218,16 @@ struct go7007 {
unsigned char active_map[216];
/* Video streaming */
- struct go7007_buffer *active_buf;
+ struct mutex queue_lock;
+ struct vb2_queue vidq;
enum go7007_parser_state state;
int parse_length;
u16 modet_word;
int seen_frame;
u32 next_seq;
- struct list_head stream;
+ struct list_head vidq_active;
wait_queue_head_t frame_waitq;
+ struct go7007_buffer *active_buf;
/* Audio streaming */
void (*audio_deliver)(struct go7007 *go, u8 *buf, int length);
@@ -267,12 +270,12 @@ int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data);
int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data);
int go7007_boot_encoder(struct go7007 *go, int init_i2c);
int go7007_reset_encoder(struct go7007 *go);
-int go7007_register_encoder(struct go7007 *go);
+int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs);
int go7007_start_encoder(struct go7007 *go);
void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length);
-struct go7007 *go7007_alloc(struct go7007_board_info *board,
+struct go7007 *go7007_alloc(const struct go7007_board_info *board,
struct device *dev);
-void go7007_remove(struct go7007 *go);
+void go7007_update_board(struct go7007 *go);
/* go7007-fw.c */
int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen);
@@ -283,6 +286,7 @@ int go7007_i2c_remove(struct go7007 *go);
/* go7007-v4l2.c */
int go7007_v4l2_init(struct go7007 *go);
+int go7007_v4l2_ctrl_init(struct go7007 *go);
void go7007_v4l2_remove(struct go7007 *go);
/* snd-go7007.c */
diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c
index 9dbf5ecd05a2..50066e01a6ed 100644
--- a/drivers/staging/media/go7007/go7007-usb.c
+++ b/drivers/staging/media/go7007/go7007-usb.c
@@ -26,10 +26,11 @@
#include <linux/usb.h>
#include <linux/i2c.h>
#include <asm/byteorder.h>
-#include <media/tvaudio.h>
+#include <media/saa7115.h>
+#include <media/tuner.h>
+#include <media/uda1342.h>
#include "go7007-priv.h"
-#include "wis-i2c.h"
static unsigned int assume_endura;
module_param(assume_endura, int, 0644);
@@ -62,7 +63,7 @@ struct go7007_usb_board {
};
struct go7007_usb {
- struct go7007_usb_board *board;
+ const struct go7007_usb_board *board;
struct mutex i2c_lock;
struct usb_device *usbdev;
struct urb *video_urbs[8];
@@ -72,10 +73,9 @@ struct go7007_usb {
/*********************** Product specification data ***********************/
-static struct go7007_usb_board board_matrix_ii = {
+static const struct go7007_usb_board board_matrix_ii = {
.flags = GO7007_USB_EZUSB,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -87,14 +87,15 @@ static struct go7007_usb_board board_matrix_ii = {
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
+ GO7007_SENSOR_SAA7115 |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_saa7115",
- .id = I2C_DRIVERID_WIS_SAA7115,
+ .type = "saa7115",
.addr = 0x20,
+ .is_video = 1,
},
},
.num_inputs = 2,
@@ -108,13 +109,13 @@ static struct go7007_usb_board board_matrix_ii = {
.name = "S-Video",
},
},
+ .video_config = SAA7115_IDQ_IS_DEFAULT,
},
};
-static struct go7007_usb_board board_matrix_reload = {
+static const struct go7007_usb_board board_matrix_reload = {
.flags = GO7007_USB_EZUSB,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -129,9 +130,9 @@ static struct go7007_usb_board board_matrix_reload = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_saa7113",
- .id = I2C_DRIVERID_WIS_SAA7113,
+ .type = "saa7113",
.addr = 0x25,
+ .is_video = 1,
},
},
.num_inputs = 2,
@@ -145,18 +146,19 @@ static struct go7007_usb_board board_matrix_reload = {
.name = "S-Video",
},
},
+ .video_config = SAA7115_IDQ_IS_DEFAULT,
},
};
-static struct go7007_usb_board board_star_trek = {
+static const struct go7007_usb_board board_star_trek = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO, /* |
GO7007_BOARD_HAS_TUNER, */
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
+ GO7007_SENSOR_SAA7115 |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -167,42 +169,43 @@ static struct go7007_usb_board board_star_trek = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_saa7115",
- .id = I2C_DRIVERID_WIS_SAA7115,
+ .type = "saa7115",
.addr = 0x20,
+ .is_video = 1,
},
},
.num_inputs = 2,
.inputs = {
+ /* {
+ * .video_input = 3,
+ * .audio_index = AUDIO_TUNER,
+ * .name = "Tuner",
+ * },
+ */
{
.video_input = 1,
- /* .audio_input = AUDIO_EXTERN, */
+ /* .audio_index = AUDIO_EXTERN, */
.name = "Composite",
},
{
.video_input = 8,
- /* .audio_input = AUDIO_EXTERN, */
+ /* .audio_index = AUDIO_EXTERN, */
.name = "S-Video",
},
- /* {
- * .video_input = 3,
- * .audio_input = AUDIO_TUNER,
- * .name = "Tuner",
- * },
- */
},
+ .video_config = SAA7115_IDQ_IS_DEFAULT,
},
};
-static struct go7007_usb_board board_px_tv402u = {
+static const struct go7007_usb_board board_px_tv402u = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_HAS_TUNER,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
GO7007_SENSOR_TV |
+ GO7007_SENSOR_SAA7115 |
GO7007_SENSOR_VBI |
GO7007_SENSOR_SCALING,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -210,49 +213,67 @@ static struct go7007_usb_board board_px_tv402u = {
.audio_bclk_div = 8,
.audio_main_div = 2,
.hpi_buffer_cap = 7,
- .num_i2c_devs = 3,
+ .num_i2c_devs = 5,
.i2c_devs = {
{
- .type = "wis_saa7115",
- .id = I2C_DRIVERID_WIS_SAA7115,
+ .type = "saa7115",
.addr = 0x20,
+ .is_video = 1,
},
{
- .type = "wis_uda1342",
- .id = I2C_DRIVERID_WIS_UDA1342,
+ .type = "uda1342",
.addr = 0x1a,
+ .is_audio = 1,
},
{
- .type = "wis_sony_tuner",
- .id = I2C_DRIVERID_WIS_SONY_TUNER,
+ .type = "tuner",
.addr = 0x60,
},
+ {
+ .type = "tuner",
+ .addr = 0x43,
+ },
+ {
+ .type = "sony-btf-mpx",
+ .addr = 0x44,
+ },
},
.num_inputs = 3,
.inputs = {
{
+ .video_input = 3,
+ .audio_index = 0,
+ .name = "Tuner",
+ },
+ {
.video_input = 1,
- .audio_input = TVAUDIO_INPUT_EXTERN,
+ .audio_index = 1,
.name = "Composite",
},
{
.video_input = 8,
- .audio_input = TVAUDIO_INPUT_EXTERN,
+ .audio_index = 1,
.name = "S-Video",
},
+ },
+ .video_config = SAA7115_IDQ_IS_DEFAULT,
+ .num_aud_inputs = 2,
+ .aud_inputs = {
{
- .video_input = 3,
- .audio_input = TVAUDIO_INPUT_TUNER,
+ .audio_input = UDA1342_IN2,
.name = "Tuner",
},
+ {
+ .audio_input = UDA1342_IN1,
+ .name = "Line In",
+ },
},
},
};
-static struct go7007_usb_board board_xmen = {
+static const struct go7007_usb_board board_xmen = {
.flags = 0,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_USE_ONBOARD_I2C,
.hpi_buffer_cap = 0,
.sensor_flags = GO7007_SENSOR_VREF_POLAR,
@@ -271,8 +292,7 @@ static struct go7007_usb_board board_xmen = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_ov7640",
- .id = I2C_DRIVERID_WIS_OV7640,
+ .type = "ov7640",
.addr = 0x21,
},
},
@@ -285,10 +305,9 @@ static struct go7007_usb_board board_xmen = {
},
};
-static struct go7007_usb_board board_matrix_revolution = {
+static const struct go7007_usb_board board_matrix_revolution = {
.flags = GO7007_USB_EZUSB,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -304,8 +323,8 @@ static struct go7007_usb_board board_matrix_revolution = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_tw9903",
- .id = I2C_DRIVERID_WIS_TW9903,
+ .type = "tw9903",
+ .is_video = 1,
.addr = 0x44,
},
},
@@ -323,10 +342,9 @@ static struct go7007_usb_board board_matrix_revolution = {
},
};
-static struct go7007_usb_board board_lifeview_lr192 = {
+static const struct go7007_usb_board board_lifeview_lr192 = {
.flags = GO7007_USB_EZUSB,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_HAS_AUDIO |
GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
@@ -351,10 +369,9 @@ static struct go7007_usb_board board_lifeview_lr192 = {
},
};
-static struct go7007_usb_board board_endura = {
+static const struct go7007_usb_board board_endura = {
.flags = 0,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = 0,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
@@ -376,10 +393,9 @@ static struct go7007_usb_board board_endura = {
},
};
-static struct go7007_usb_board board_adlink_mpg24 = {
+static const struct go7007_usb_board board_adlink_mpg24 = {
.flags = 0,
.main_info = {
- .firmware = "go7007tv.bin",
.flags = GO7007_BOARD_USE_ONBOARD_I2C,
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
@@ -394,9 +410,10 @@ static struct go7007_usb_board board_adlink_mpg24 = {
.num_i2c_devs = 1,
.i2c_devs = {
{
- .type = "wis_tw2804",
- .id = I2C_DRIVERID_WIS_TW2804,
+ .type = "tw2804",
.addr = 0x00, /* yes, really */
+ .flags = I2C_CLIENT_TEN,
+ .is_video = 1,
},
},
.num_inputs = 1,
@@ -408,10 +425,9 @@ static struct go7007_usb_board board_adlink_mpg24 = {
},
};
-static struct go7007_usb_board board_sensoray_2250 = {
+static const struct go7007_usb_board board_sensoray_2250 = {
.flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
.main_info = {
- .firmware = "go7007tv.bin",
.audio_flags = GO7007_AUDIO_I2S_MODE_1 |
GO7007_AUDIO_I2S_MASTER |
GO7007_AUDIO_WORD_16,
@@ -426,8 +442,9 @@ static struct go7007_usb_board board_sensoray_2250 = {
.i2c_devs = {
{
.type = "s2250",
- .id = I2C_DRIVERID_S2250,
.addr = 0x43,
+ .is_video = 1,
+ .is_audio = 1,
},
},
.num_inputs = 2,
@@ -441,10 +458,60 @@ static struct go7007_usb_board board_sensoray_2250 = {
.name = "S-Video",
},
},
+ .num_aud_inputs = 3,
+ .aud_inputs = {
+ {
+ .audio_input = 0,
+ .name = "Line In",
+ },
+ {
+ .audio_input = 1,
+ .name = "Mic",
+ },
+ {
+ .audio_input = 2,
+ .name = "Mic Boost",
+ },
+ },
},
};
-MODULE_FIRMWARE("go7007tv.bin");
+static const struct go7007_usb_board board_ads_usbav_709 = {
+ .flags = GO7007_USB_EZUSB,
+ .main_info = {
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .type = "tw9906",
+ .is_video = 1,
+ .addr = 0x44,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 0,
+ .name = "Composite",
+ },
+ {
+ .video_input = 10,
+ .name = "S-Video",
+ },
+ },
+ },
+};
static const struct usb_device_id go7007_usb_id_table[] = {
{
@@ -529,7 +596,7 @@ static const struct usb_device_id go7007_usb_id_table[] = {
.idProduct = 0xa104, /* Product ID of TV402U */
.bcdDevice_lo = 0x1,
.bcdDevice_hi = 0x1,
- .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U,
},
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
@@ -547,6 +614,14 @@ static const struct usb_device_id go7007_usb_id_table[] = {
.bcdDevice_hi = 0x1,
.driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250,
},
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x06e1, /* Vendor ID of ADS Technologies */
+ .idProduct = 0x0709, /* Product ID of DVD Xpress DX2 */
+ .bcdDevice_lo = 0x204,
+ .bcdDevice_hi = 0x204,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709,
+ },
{ } /* Terminating entry */
};
@@ -578,6 +653,8 @@ static int go7007_usb_interface_reset(struct go7007 *go)
struct go7007_usb *usb = go->hpi_context;
u16 intr_val, intr_data;
+ if (go->status == STATUS_SHUTDOWN)
+ return -1;
/* Reset encoder */
if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
return -1;
@@ -613,7 +690,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
{
struct go7007_usb *usb = go->hpi_context;
int i, r;
- u16 status_reg;
+ u16 status_reg = 0;
int timeout = 500;
#ifdef GO7007_USB_DEBUG
@@ -625,15 +702,17 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
r = usb_control_msg(usb->usbdev,
usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, HPI_STATUS_ADDR, &status_reg,
+ 0, HPI_STATUS_ADDR, go->usb_buf,
sizeof(status_reg), timeout);
if (r < 0)
- goto write_int_error;
- __le16_to_cpus(&status_reg);
+ break;
+ status_reg = le16_to_cpu(*((u16 *)go->usb_buf));
if (!(status_reg & 0x0010))
break;
msleep(10);
}
+ if (r < 0)
+ goto write_int_error;
if (i == 100) {
printk(KERN_ERR
"go7007-usb: device is hung, status reg = 0x%04x\n",
@@ -661,7 +740,6 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
int addr, int data)
{
struct go7007_usb *usb = go->hpi_context;
- u8 *tbuf;
int r;
int timeout = 500;
@@ -670,17 +748,14 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
"go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
#endif
- tbuf = kzalloc(8, GFP_KERNEL);
- if (tbuf == NULL)
- return -ENOMEM;
- tbuf[0] = data & 0xff;
- tbuf[1] = data >> 8;
- tbuf[2] = addr & 0xff;
- tbuf[3] = addr >> 8;
+ go->usb_buf[0] = data & 0xff;
+ go->usb_buf[1] = data >> 8;
+ go->usb_buf[2] = addr & 0xff;
+ go->usb_buf[3] = addr >> 8;
+ go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0;
r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
- 0xf0f0, tbuf, 8, timeout);
- kfree(tbuf);
+ 0xf0f0, go->usb_buf, 8, timeout);
if (r < 0) {
printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
return r;
@@ -738,7 +813,7 @@ static void go7007_usb_read_video_pipe_complete(struct urb *urb)
struct go7007 *go = (struct go7007 *)urb->context;
int r, status = urb->status;
- if (!go->streaming) {
+ if (!vb2_is_streaming(&go->vidq)) {
wake_up_interruptible(&go->frame_waitq);
return;
}
@@ -762,7 +837,7 @@ static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
struct go7007 *go = (struct go7007 *)urb->context;
int r, status = urb->status;
- if (!go->streaming)
+ if (!vb2_is_streaming(&go->vidq))
return;
if (status) {
printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n",
@@ -849,6 +924,37 @@ static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
&transferred, timeout);
}
+static void go7007_usb_release(struct go7007 *go)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ struct urb *vurb, *aurb;
+ int i;
+
+ if (usb->intr_urb) {
+ usb_kill_urb(usb->intr_urb);
+ kfree(usb->intr_urb->transfer_buffer);
+ usb_free_urb(usb->intr_urb);
+ }
+
+ /* Free USB-related structs */
+ for (i = 0; i < 8; ++i) {
+ vurb = usb->video_urbs[i];
+ if (vurb) {
+ usb_kill_urb(vurb);
+ kfree(vurb->transfer_buffer);
+ usb_free_urb(vurb);
+ }
+ aurb = usb->audio_urbs[i];
+ if (aurb) {
+ usb_kill_urb(aurb);
+ kfree(aurb->transfer_buffer);
+ usb_free_urb(aurb);
+ }
+ }
+
+ kfree(go->hpi_context);
+}
+
static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
.interface_reset = go7007_usb_interface_reset,
.write_interrupt = go7007_usb_ezusb_write_interrupt,
@@ -856,6 +962,7 @@ static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
.stream_start = go7007_usb_stream_start,
.stream_stop = go7007_usb_stream_stop,
.send_firmware = go7007_usb_send_firmware,
+ .release = go7007_usb_release,
};
static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
@@ -865,6 +972,7 @@ static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
.stream_start = go7007_usb_stream_start,
.stream_stop = go7007_usb_stream_stop,
.send_firmware = go7007_usb_send_firmware,
+ .release = go7007_usb_release,
};
/********************* Driver for EZ-USB I2C adapter *********************/
@@ -874,12 +982,12 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
{
struct go7007 *go = i2c_get_adapdata(adapter);
struct go7007_usb *usb = go->hpi_context;
- u8 buf[16];
+ u8 *buf = go->usb_buf;
int buf_len, i;
- int ret = -1;
+ int ret = -EIO;
if (go->status == STATUS_SHUTDOWN)
- return -1;
+ return -ENODEV;
mutex_lock(&usb->i2c_lock);
@@ -929,14 +1037,14 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
buf, buf_len, 0) < 0)
goto i2c_done;
if (msgs[i].flags & I2C_M_RD) {
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, msgs[i].len + 1);
if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
msgs[i].len + 1, 1) < 0)
goto i2c_done;
memcpy(msgs[i].buf, buf + 1, msgs[i].len);
}
}
- ret = 0;
+ ret = num;
i2c_done:
mutex_unlock(&usb->i2c_lock);
@@ -968,8 +1076,9 @@ static int go7007_usb_probe(struct usb_interface *intf,
{
struct go7007 *go;
struct go7007_usb *usb;
- struct go7007_usb_board *board;
+ const struct go7007_usb_board *board;
struct usb_device *usbdev = interface_to_usbdev(intf);
+ unsigned num_i2c_devs;
char *name;
int video_pipe, i, v_urb_len;
@@ -1008,7 +1117,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
name = "Plextor PX-M402U";
board = &board_matrix_ii;
break;
- case GO7007_BOARDID_PX_TV402U_ANY:
+ case GO7007_BOARDID_PX_TV402U:
name = "Plextor PX-TV402U (unknown tuner)";
board = &board_px_tv402u;
break;
@@ -1024,29 +1133,29 @@ static int go7007_usb_probe(struct usb_interface *intf,
name = "Sensoray 2250/2251";
board = &board_sensoray_2250;
break;
+ case GO7007_BOARDID_ADS_USBAV_709:
+ name = "ADS Tech DVD Xpress DX2";
+ board = &board_ads_usbav_709;
+ break;
default:
printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
(unsigned int)id->driver_info);
return 0;
}
- usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
- if (usb == NULL)
+ go = go7007_alloc(&board->main_info, &intf->dev);
+ if (go == NULL)
return -ENOMEM;
- /* Allocate the URB and buffer for receiving incoming interrupts */
- usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (usb->intr_urb == NULL)
- goto allocfail;
- usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
- if (usb->intr_urb->transfer_buffer == NULL)
- goto allocfail;
+ usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL);
+ if (usb == NULL) {
+ kfree(go);
+ return -ENOMEM;
+ }
- go = go7007_alloc(&board->main_info, &intf->dev);
- if (go == NULL)
- goto allocfail;
usb->board = board;
usb->usbdev = usbdev;
+ usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info));
go->board_id = id->driver_info;
strncpy(go->name, name, sizeof(go->name));
if (board->flags & GO7007_USB_EZUSB)
@@ -1054,6 +1163,15 @@ static int go7007_usb_probe(struct usb_interface *intf,
else
go->hpi_ops = &go7007_usb_onboard_hpi_ops;
go->hpi_context = usb;
+
+ /* Allocate the URB and buffer for receiving incoming interrupts */
+ usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (usb->intr_urb == NULL)
+ goto allocfail;
+ usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
+ if (usb->intr_urb->transfer_buffer == NULL)
+ goto allocfail;
+
if (go->board_id == GO7007_BOARDID_SENSORAY_2250)
usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
usb_rcvbulkpipe(usb->usbdev, 4),
@@ -1069,7 +1187,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
/* Boot the GO7007 */
if (go7007_boot_encoder(go, go->board_info->flags &
GO7007_BOARD_USE_ONBOARD_I2C) < 0)
- goto initfail;
+ goto allocfail;
/* Register the EZ-USB I2C adapter, if we're using it */
if (board->flags & GO7007_USB_EZUSB_I2C) {
@@ -1081,7 +1199,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
if (i2c_add_adapter(&go->i2c_adapter) < 0) {
printk(KERN_ERR
"go7007-usb: error: i2c_add_adapter failed\n");
- goto initfail;
+ goto allocfail;
}
go->i2c_adapter_online = 1;
}
@@ -1121,34 +1239,36 @@ static int go7007_usb_probe(struct usb_interface *intf,
"Adlink PCI-MPG24, channel #%d",
channel);
}
+ go7007_update_board(go);
}
}
- /* Probe the tuner model on the TV402U */
- if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) {
- u8 data[3];
+ num_i2c_devs = go->board_info->num_i2c_devs;
+ /* Probe the tuner model on the TV402U */
+ if (go->board_id == GO7007_BOARDID_PX_TV402U) {
/* Board strapping indicates tuner model */
- if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) {
+ if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 1) < 0) {
printk(KERN_ERR "go7007-usb: GPIO read failed!\n");
- goto initfail;
+ goto allocfail;
}
- switch (data[0] >> 6) {
+ switch (go->usb_buf[0] >> 6) {
case 1:
- go->board_id = GO7007_BOARDID_PX_TV402U_EU;
go->tuner_type = TUNER_SONY_BTF_PG472Z;
+ go->std = V4L2_STD_PAL;
strncpy(go->name, "Plextor PX-TV402U-EU",
sizeof(go->name));
break;
case 2:
- go->board_id = GO7007_BOARDID_PX_TV402U_JP;
go->tuner_type = TUNER_SONY_BTF_PK467Z;
+ go->std = V4L2_STD_NTSC_M_JP;
+ num_i2c_devs -= 2;
strncpy(go->name, "Plextor PX-TV402U-JP",
sizeof(go->name));
break;
case 3:
- go->board_id = GO7007_BOARDID_PX_TV402U_NA;
go->tuner_type = TUNER_SONY_BTF_PB463Z;
+ num_i2c_devs -= 2;
strncpy(go->name, "Plextor PX-TV402U-NA",
sizeof(go->name));
break;
@@ -1162,7 +1282,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
NULL, 0, 0) < 0) {
printk(KERN_ERR "go7007-usb: GPIO write failed!\n");
- goto initfail;
+ goto allocfail;
}
}
@@ -1176,11 +1296,6 @@ static int go7007_usb_probe(struct usb_interface *intf,
"port will result in stream corruption, even "
"at low bitrates!\n");
- /* Do any final GO7007 initialization, then register the
- * V4L2 and ALSA interfaces */
- if (go7007_register_encoder(go) < 0)
- goto initfail;
-
/* Allocate the URBs and buffers for receiving the video stream */
if (board->flags & GO7007_USB_EZUSB) {
v_urb_len = 1024;
@@ -1192,80 +1307,65 @@ static int go7007_usb_probe(struct usb_interface *intf,
for (i = 0; i < 8; ++i) {
usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (usb->video_urbs[i] == NULL)
- goto initfail;
+ goto allocfail;
usb->video_urbs[i]->transfer_buffer =
kmalloc(v_urb_len, GFP_KERNEL);
if (usb->video_urbs[i]->transfer_buffer == NULL)
- goto initfail;
+ goto allocfail;
usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
usb->video_urbs[i]->transfer_buffer, v_urb_len,
go7007_usb_read_video_pipe_complete, go);
}
/* Allocate the URBs and buffers for receiving the audio stream */
- if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled)
+ if ((board->flags & GO7007_USB_EZUSB) &&
+ (board->flags & GO7007_BOARD_HAS_AUDIO)) {
for (i = 0; i < 8; ++i) {
usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (usb->audio_urbs[i] == NULL)
- goto initfail;
+ goto allocfail;
usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
GFP_KERNEL);
if (usb->audio_urbs[i]->transfer_buffer == NULL)
- goto initfail;
+ goto allocfail;
usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
usb_rcvbulkpipe(usb->usbdev, 8),
usb->audio_urbs[i]->transfer_buffer, 4096,
go7007_usb_read_audio_pipe_complete, go);
}
+ }
+ /* Do any final GO7007 initialization, then register the
+ * V4L2 and ALSA interfaces */
+ if (go7007_register_encoder(go, num_i2c_devs) < 0)
+ goto allocfail;
go->status = STATUS_ONLINE;
return 0;
-initfail:
- go->status = STATUS_SHUTDOWN;
- return 0;
-
allocfail:
- if (usb->intr_urb) {
- kfree(usb->intr_urb->transfer_buffer);
- usb_free_urb(usb->intr_urb);
- }
- kfree(usb);
+ go7007_usb_release(go);
+ kfree(go);
return -ENOMEM;
}
static void go7007_usb_disconnect(struct usb_interface *intf)
{
struct go7007 *go = to_go7007(usb_get_intfdata(intf));
- struct go7007_usb *usb = go->hpi_context;
- struct urb *vurb, *aurb;
- int i;
- usb_kill_urb(usb->intr_urb);
+ mutex_lock(&go->queue_lock);
+ mutex_lock(&go->serialize_lock);
- /* Free USB-related structs */
- for (i = 0; i < 8; ++i) {
- vurb = usb->video_urbs[i];
- if (vurb) {
- usb_kill_urb(vurb);
- kfree(vurb->transfer_buffer);
- usb_free_urb(vurb);
- }
- aurb = usb->audio_urbs[i];
- if (aurb) {
- usb_kill_urb(aurb);
- kfree(aurb->transfer_buffer);
- usb_free_urb(aurb);
- }
- }
- kfree(usb->intr_urb->transfer_buffer);
- usb_free_urb(usb->intr_urb);
-
- kfree(go->hpi_context);
+ if (go->audio_enabled)
+ go7007_snd_remove(go);
- go7007_remove(go);
go->status = STATUS_SHUTDOWN;
+ v4l2_device_disconnect(&go->v4l2_dev);
+ video_unregister_device(&go->vdev);
+ mutex_unlock(&go->serialize_lock);
+ mutex_unlock(&go->queue_lock);
+
+ v4l2_device_put(&go->v4l2_dev);
}
static struct usb_driver go7007_usb_driver = {
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index cb9fe33050c7..50eb69a8ef07 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
@@ -27,115 +26,45 @@
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/saa7115.h>
#include "go7007.h"
#include "go7007-priv.h"
-#include "wis-i2c.h"
-
-/* Temporary defines until accepted in v4l-dvb */
-#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM
-#define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */
-#endif
-#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4
-#define V4L2_MPEG_VIDEO_ENCODING_MPEG_4 3
-#endif
#define call_all(dev, o, f, args...) \
v4l2_device_call_until_err(dev, 0, o, f, ##args)
-static void deactivate_buffer(struct go7007_buffer *gobuf)
-{
- int i;
-
- if (gobuf->state != BUF_STATE_IDLE) {
- list_del(&gobuf->stream);
- gobuf->state = BUF_STATE_IDLE;
- }
- if (gobuf->page_count > 0) {
- for (i = 0; i < gobuf->page_count; ++i)
- page_cache_release(gobuf->pages[i]);
- gobuf->page_count = 0;
- }
-}
-
-static void abort_queued(struct go7007 *go)
-{
- struct go7007_buffer *gobuf, *next;
-
- list_for_each_entry_safe(gobuf, next, &go->stream, stream) {
- deactivate_buffer(gobuf);
- }
-}
-
-static int go7007_streamoff(struct go7007 *go)
-{
- unsigned long flags;
-
- mutex_lock(&go->hw_lock);
- if (go->streaming) {
- go->streaming = 0;
- go7007_stream_stop(go);
- spin_lock_irqsave(&go->spinlock, flags);
- abort_queued(go);
- spin_unlock_irqrestore(&go->spinlock, flags);
- go7007_reset_encoder(go);
- }
- mutex_unlock(&go->hw_lock);
- return 0;
-}
-
-static int go7007_open(struct file *file)
-{
- struct go7007 *go = video_get_drvdata(video_devdata(file));
- struct go7007_file *gofh;
-
- if (go->status != STATUS_ONLINE)
- return -EBUSY;
- gofh = kzalloc(sizeof(struct go7007_file), GFP_KERNEL);
- if (gofh == NULL)
- return -ENOMEM;
- ++go->ref_count;
- gofh->go = go;
- mutex_init(&gofh->lock);
- gofh->buf_count = 0;
- file->private_data = gofh;
- return 0;
-}
-
-static int go7007_release(struct file *file)
+static bool valid_pixelformat(u32 pixelformat)
{
- struct go7007_file *gofh = file->private_data;
- struct go7007 *go = gofh->go;
-
- if (gofh->buf_count > 0) {
- go7007_streamoff(go);
- go->in_use = 0;
- kfree(gofh->bufs);
- gofh->buf_count = 0;
+ switch (pixelformat) {
+ case V4L2_PIX_FMT_MJPEG:
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
+ case V4L2_PIX_FMT_MPEG4:
+ return true;
+ default:
+ return false;
}
- kfree(gofh);
- if (--go->ref_count == 0)
- kfree(go);
- file->private_data = NULL;
- return 0;
}
-static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
+static u32 get_frame_type_flag(struct go7007_buffer *vb, int format)
{
- u8 *f = page_address(gobuf->pages[0]);
+ u8 *ptr = vb2_plane_vaddr(&vb->vb, 0);
switch (format) {
- case GO7007_FORMAT_MJPEG:
+ case V4L2_PIX_FMT_MJPEG:
return V4L2_BUF_FLAG_KEYFRAME;
- case GO7007_FORMAT_MPEG4:
- switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) {
+ case V4L2_PIX_FMT_MPEG4:
+ switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) {
case 0:
return V4L2_BUF_FLAG_KEYFRAME;
case 1:
@@ -145,9 +74,9 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
default:
return 0;
}
- case GO7007_FORMAT_MPEG1:
- case GO7007_FORMAT_MPEG2:
- switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) {
+ case V4L2_PIX_FMT_MPEG1:
+ case V4L2_PIX_FMT_MPEG2:
+ switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) {
case 1:
return V4L2_BUF_FLAG_KEYFRAME;
case 2:
@@ -162,30 +91,111 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
return 0;
}
-static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
+static void get_resolution(struct go7007 *go, int *width, int *height)
{
- int sensor_height = 0, sensor_width = 0;
- int width, height, i;
-
- if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
- fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG &&
- fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4)
- return -EINVAL;
-
switch (go->standard) {
case GO7007_STD_NTSC:
- sensor_width = 720;
- sensor_height = 480;
+ *width = 720;
+ *height = 480;
break;
case GO7007_STD_PAL:
- sensor_width = 720;
- sensor_height = 576;
+ *width = 720;
+ *height = 576;
break;
case GO7007_STD_OTHER:
- sensor_width = go->board_info->sensor_width;
- sensor_height = go->board_info->sensor_height;
+ default:
+ *width = go->board_info->sensor_width;
+ *height = go->board_info->sensor_height;
+ break;
+ }
+}
+
+static void set_formatting(struct go7007 *go)
+{
+ if (go->format == V4L2_PIX_FMT_MJPEG) {
+ go->pali = 0;
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ go->gop_size = 0;
+ go->ipb = 0;
+ go->closed_gop = 0;
+ go->repeat_seqhead = 0;
+ go->seq_header_enable = 0;
+ go->gop_header_enable = 0;
+ go->dvd_mode = 0;
+ return;
+ }
+
+ switch (go->format) {
+ case V4L2_PIX_FMT_MPEG1:
+ go->pali = 0;
+ break;
+ default:
+ case V4L2_PIX_FMT_MPEG2:
+ go->pali = 0x48;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ /* For future reference: this is the list of MPEG4
+ * profiles that are available, although they are
+ * untested:
+ *
+ * Profile pali
+ * -------------- ----
+ * PROFILE_S_L0 0x08
+ * PROFILE_S_L1 0x01
+ * PROFILE_S_L2 0x02
+ * PROFILE_S_L3 0x03
+ * PROFILE_ARTS_L1 0x91
+ * PROFILE_ARTS_L2 0x92
+ * PROFILE_ARTS_L3 0x93
+ * PROFILE_ARTS_L4 0x94
+ * PROFILE_AS_L0 0xf0
+ * PROFILE_AS_L1 0xf1
+ * PROFILE_AS_L2 0xf2
+ * PROFILE_AS_L3 0xf3
+ * PROFILE_AS_L4 0xf4
+ * PROFILE_AS_L5 0xf5
+ */
+ go->pali = 0xf5;
+ break;
+ }
+ go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size);
+ go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure);
+ go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0;
+ go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate);
+ go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader);
+ go->gop_header_enable = 1;
+ go->dvd_mode = 0;
+ if (go->format == V4L2_PIX_FMT_MPEG2)
+ go->dvd_mode =
+ go->bitrate == 9800000 &&
+ go->gop_size == 15 &&
+ go->ipb == 0 &&
+ go->repeat_seqhead == 1 &&
+ go->closed_gop;
+
+ switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) {
+ default:
+ case V4L2_MPEG_VIDEO_ASPECT_1x1:
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
+ go->aspect_ratio = GO7007_RATIO_4_3;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
+ go->aspect_ratio = GO7007_RATIO_16_9;
break;
}
+}
+
+static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
+{
+ int sensor_height = 0, sensor_width = 0;
+ int width, height, i;
+
+ if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat))
+ return -EINVAL;
+
+ get_resolution(go, &sensor_width, &sensor_height);
if (fmt == NULL) {
width = sensor_width;
@@ -205,13 +215,12 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
else
height = fmt->fmt.pix.height & ~0x0f;
} else {
- int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height;
- int sensor_size = sensor_width * sensor_height;
+ width = fmt->fmt.pix.width;
- if (64 * requested_size < 9 * sensor_size) {
+ if (width <= sensor_width / 4) {
width = sensor_width / 4;
height = sensor_height / 4;
- } else if (64 * requested_size < 36 * sensor_size) {
+ } else if (width <= sensor_width / 2) {
width = sensor_width / 2;
height = sensor_height / 2;
} else {
@@ -233,12 +242,14 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = 0;
fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
- fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
}
if (try)
return 0;
+ if (fmt)
+ go->format = fmt->fmt.pix.pixelformat;
go->width = width;
go->height = height;
go->encoder_h_offset = go->board_info->sensor_h_offset;
@@ -252,18 +263,11 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
struct v4l2_mbus_framefmt mbus_fmt;
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
- if (fmt != NULL)
- mbus_fmt.width = fmt->fmt.pix.width;
- else
- mbus_fmt.width = width;
-
- if (height > sensor_height / 2) {
- mbus_fmt.height = height / 2;
- go->encoder_v_halve = 0;
- } else {
- mbus_fmt.height = height;
- go->encoder_v_halve = 1;
- }
+ mbus_fmt.width = fmt ? fmt->fmt.pix.width : width;
+ mbus_fmt.height = height;
+ go->encoder_h_halve = 0;
+ go->encoder_v_halve = 0;
+ go->encoder_subsample = 0;
call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt);
} else {
if (width <= sensor_width / 4) {
@@ -280,55 +284,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
go->encoder_subsample = 0;
}
}
-
- if (fmt == NULL)
- return 0;
-
- switch (fmt->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_MPEG:
- if (go->format == GO7007_FORMAT_MPEG1 ||
- go->format == GO7007_FORMAT_MPEG2 ||
- go->format == GO7007_FORMAT_MPEG4)
- break;
- go->format = GO7007_FORMAT_MPEG1;
- go->pali = 0;
- go->aspect_ratio = GO7007_RATIO_1_1;
- go->gop_size = go->sensor_framerate / 1000;
- go->ipb = 0;
- go->closed_gop = 1;
- go->repeat_seqhead = 1;
- go->seq_header_enable = 1;
- go->gop_header_enable = 1;
- go->dvd_mode = 0;
- break;
- /* Backwards compatibility only! */
- case V4L2_PIX_FMT_MPEG4:
- if (go->format == GO7007_FORMAT_MPEG4)
- break;
- go->format = GO7007_FORMAT_MPEG4;
- go->pali = 0xf5;
- go->aspect_ratio = GO7007_RATIO_1_1;
- go->gop_size = go->sensor_framerate / 1000;
- go->ipb = 0;
- go->closed_gop = 1;
- go->repeat_seqhead = 1;
- go->seq_header_enable = 1;
- go->gop_header_enable = 1;
- go->dvd_mode = 0;
- break;
- case V4L2_PIX_FMT_MJPEG:
- go->format = GO7007_FORMAT_MJPEG;
- go->pali = 0;
- go->aspect_ratio = GO7007_RATIO_1_1;
- go->gop_size = 0;
- go->ipb = 0;
- go->closed_gop = 0;
- go->repeat_seqhead = 0;
- go->seq_header_enable = 0;
- go->gop_header_enable = 0;
- go->dvd_mode = 0;
- break;
- }
return 0;
}
@@ -390,230 +345,23 @@ static int clip_to_modet_map(struct go7007 *go, int region,
}
#endif
-static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl)
-{
- static const u32 mpeg_ctrls[] = {
- V4L2_CID_MPEG_CLASS,
- V4L2_CID_MPEG_STREAM_TYPE,
- V4L2_CID_MPEG_VIDEO_ENCODING,
- V4L2_CID_MPEG_VIDEO_ASPECT,
- V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
- V4L2_CID_MPEG_VIDEO_BITRATE,
- 0
- };
- static const u32 *ctrl_classes[] = {
- mpeg_ctrls,
- NULL
- };
-
- ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id);
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_CLASS:
- return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0);
- case V4L2_CID_MPEG_STREAM_TYPE:
- return v4l2_ctrl_query_fill(ctrl,
- V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
- V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1,
- V4L2_MPEG_STREAM_TYPE_MPEG_ELEM);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(ctrl,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return v4l2_ctrl_query_fill(ctrl,
- V4L2_MPEG_VIDEO_ASPECT_1x1,
- V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
- V4L2_MPEG_VIDEO_ASPECT_1x1);
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15);
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- return v4l2_ctrl_query_fill(ctrl,
- 64000,
- 10000000, 1,
- 1500000);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
-{
- /* pretty sure we can't change any of these while streaming */
- if (go->streaming)
- return -EBUSY;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_STREAM_TYPE:
- switch (ctrl->value) {
- case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
- go->format = GO7007_FORMAT_MPEG2;
- go->bitrate = 9800000;
- go->gop_size = 15;
- go->pali = 0x48;
- go->closed_gop = 1;
- go->repeat_seqhead = 0;
- go->seq_header_enable = 1;
- go->gop_header_enable = 1;
- go->dvd_mode = 1;
- break;
- case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM:
- /* todo: */
- break;
- default:
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- switch (ctrl->value) {
- case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
- go->format = GO7007_FORMAT_MPEG1;
- go->pali = 0;
- break;
- case V4L2_MPEG_VIDEO_ENCODING_MPEG_2:
- go->format = GO7007_FORMAT_MPEG2;
- /*if (mpeg->pali >> 24 == 2)
- go->pali = mpeg->pali & 0xff;
- else*/
- go->pali = 0x48;
- break;
- case V4L2_MPEG_VIDEO_ENCODING_MPEG_4:
- go->format = GO7007_FORMAT_MPEG4;
- /*if (mpeg->pali >> 24 == 4)
- go->pali = mpeg->pali & 0xff;
- else*/
- go->pali = 0xf5;
- break;
- default:
- return -EINVAL;
- }
- go->gop_header_enable =
- /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
- ? 0 :*/ 1;
- /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
- go->repeat_seqhead = 1;
- else*/
- go->repeat_seqhead = 0;
- go->dvd_mode = 0;
- break;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- if (go->format == GO7007_FORMAT_MJPEG)
- return -EINVAL;
- switch (ctrl->value) {
- case V4L2_MPEG_VIDEO_ASPECT_1x1:
- go->aspect_ratio = GO7007_RATIO_1_1;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_4x3:
- go->aspect_ratio = GO7007_RATIO_4_3;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_16x9:
- go->aspect_ratio = GO7007_RATIO_16_9;
- break;
- case V4L2_MPEG_VIDEO_ASPECT_221x100:
- default:
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- if (ctrl->value < 0 || ctrl->value > 34)
- return -EINVAL;
- go->gop_size = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- if (ctrl->value != 0 && ctrl->value != 1)
- return -EINVAL;
- go->closed_gop = ctrl->value;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- /* Upper bound is kind of arbitrary here */
- if (ctrl->value < 64000 || ctrl->value > 10000000)
- return -EINVAL;
- go->bitrate = ctrl->value;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go)
-{
- switch (ctrl->id) {
- case V4L2_CID_MPEG_STREAM_TYPE:
- if (go->dvd_mode)
- ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
- else
- ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM;
- break;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- switch (go->format) {
- case GO7007_FORMAT_MPEG1:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- break;
- case GO7007_FORMAT_MPEG2:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
- break;
- case GO7007_FORMAT_MPEG4:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4;
- break;
- default:
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- switch (go->aspect_ratio) {
- case GO7007_RATIO_1_1:
- ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
- break;
- case GO7007_RATIO_4_3:
- ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3;
- break;
- case GO7007_RATIO_16_9:
- ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9;
- break;
- default:
- return -EINVAL;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- ctrl->value = go->gop_size;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- ctrl->value = go->closed_gop;
- break;
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- ctrl->value = go->bitrate;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
strlcpy(cap->driver, "go7007", sizeof(cap->driver));
strlcpy(cap->card, go->name, sizeof(cap->card));
-#if 0
- strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
-#endif
-
- cap->version = KERNEL_VERSION(0, 9, 8);
+ strlcpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ if (go->board_info->num_aud_inputs)
+ cap->device_caps |= V4L2_CAP_AUDIO;
if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
- cap->capabilities |= V4L2_CAP_TUNER;
-
+ cap->device_caps |= V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -625,11 +373,19 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
switch (fmt->index) {
case 0:
fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
- desc = "Motion-JPEG";
+ desc = "Motion JPEG";
break;
case 1:
- fmt->pixelformat = V4L2_PIX_FMT_MPEG;
- desc = "MPEG1/MPEG2/MPEG4";
+ fmt->pixelformat = V4L2_PIX_FMT_MPEG1;
+ desc = "MPEG-1 ES";
+ break;
+ case 2:
+ fmt->pixelformat = V4L2_PIX_FMT_MPEG2;
+ desc = "MPEG-2 ES";
+ break;
+ case 3:
+ fmt->pixelformat = V4L2_PIX_FMT_MPEG4;
+ desc = "MPEG-4 ES";
break;
default:
return -EINVAL;
@@ -645,13 +401,12 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt->fmt.pix.width = go->width;
fmt->fmt.pix.height = go->height;
- fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ?
- V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
+ fmt->fmt.pix.pixelformat = go->format;
fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = 0;
fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
@@ -663,7 +418,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
return set_capture_size(go, fmt, 1);
}
@@ -671,348 +426,137 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (go->streaming)
+ if (vb2_is_busy(&go->vidq))
return -EBUSY;
return set_capture_size(go, fmt, 0);
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
+static int go7007_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct go7007_file *gofh = priv;
- struct go7007 *go = gofh->go;
- int retval = -EBUSY;
- unsigned int count, i;
-
- if (go->streaming)
- return retval;
-
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- mutex_lock(&gofh->lock);
- for (i = 0; i < gofh->buf_count; ++i)
- if (gofh->bufs[i].mapped > 0)
- goto unlock_and_return;
-
- mutex_lock(&go->hw_lock);
- if (go->in_use > 0 && gofh->buf_count == 0) {
- mutex_unlock(&go->hw_lock);
- goto unlock_and_return;
- }
+ sizes[0] = GO7007_BUF_SIZE;
+ *num_planes = 1;
- if (gofh->buf_count > 0)
- kfree(gofh->bufs);
-
- retval = -ENOMEM;
- count = req->count;
- if (count > 0) {
- if (count < 2)
- count = 2;
- if (count > 32)
- count = 32;
-
- gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer),
- GFP_KERNEL);
-
- if (!gofh->bufs) {
- mutex_unlock(&go->hw_lock);
- goto unlock_and_return;
- }
-
- for (i = 0; i < count; ++i) {
- gofh->bufs[i].go = go;
- gofh->bufs[i].index = i;
- gofh->bufs[i].state = BUF_STATE_IDLE;
- gofh->bufs[i].mapped = 0;
- }
-
- go->in_use = 1;
- } else {
- go->in_use = 0;
- }
-
- gofh->buf_count = count;
- mutex_unlock(&go->hw_lock);
- mutex_unlock(&gofh->lock);
-
- memset(req, 0, sizeof(*req));
-
- req->count = count;
- req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req->memory = V4L2_MEMORY_MMAP;
-
- return 0;
-
-unlock_and_return:
- mutex_unlock(&gofh->lock);
- return retval;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct go7007_file *gofh = priv;
- int retval = -EINVAL;
- unsigned int index;
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return retval;
-
- index = buf->index;
-
- mutex_lock(&gofh->lock);
- if (index >= gofh->buf_count)
- goto unlock_and_return;
-
- memset(buf, 0, sizeof(*buf));
- buf->index = index;
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- switch (gofh->bufs[index].state) {
- case BUF_STATE_QUEUED:
- buf->flags = V4L2_BUF_FLAG_QUEUED;
- break;
- case BUF_STATE_DONE:
- buf->flags = V4L2_BUF_FLAG_DONE;
- break;
- default:
- buf->flags = 0;
- }
-
- if (gofh->bufs[index].mapped)
- buf->flags |= V4L2_BUF_FLAG_MAPPED;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = index * GO7007_BUF_SIZE;
- buf->length = GO7007_BUF_SIZE;
- mutex_unlock(&gofh->lock);
+ if (*num_buffers < 2)
+ *num_buffers = 2;
return 0;
-
-unlock_and_return:
- mutex_unlock(&gofh->lock);
- return retval;
}
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+static void go7007_buf_queue(struct vb2_buffer *vb)
{
- struct go7007_file *gofh = priv;
- struct go7007 *go = gofh->go;
- struct go7007_buffer *gobuf;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct go7007 *go = vb2_get_drv_priv(vq);
+ struct go7007_buffer *go7007_vb =
+ container_of(vb, struct go7007_buffer, vb);
unsigned long flags;
- int retval = -EINVAL;
- int ret;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- buf->memory != V4L2_MEMORY_MMAP)
- return retval;
-
- mutex_lock(&gofh->lock);
- if (buf->index >= gofh->buf_count)
- goto unlock_and_return;
-
- gobuf = &gofh->bufs[buf->index];
- if (!gobuf->mapped)
- goto unlock_and_return;
-
- retval = -EBUSY;
- if (gobuf->state != BUF_STATE_IDLE)
- goto unlock_and_return;
-
- /* offset will be 0 until we really support USERPTR streaming */
- gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
- gobuf->bytesused = 0;
- gobuf->frame_offset = 0;
- gobuf->modet_active = 0;
- if (gobuf->offset > 0)
- gobuf->page_count = GO7007_BUF_PAGES + 1;
- else
- gobuf->page_count = GO7007_BUF_PAGES;
-
- retval = -ENOMEM;
- down_read(&current->mm->mmap_sem);
- ret = get_user_pages(current, current->mm,
- gobuf->user_addr & PAGE_MASK, gobuf->page_count,
- 1, 1, gobuf->pages, NULL);
- up_read(&current->mm->mmap_sem);
-
- if (ret != gobuf->page_count) {
- int i;
- for (i = 0; i < ret; ++i)
- page_cache_release(gobuf->pages[i]);
- gobuf->page_count = 0;
- goto unlock_and_return;
- }
-
- gobuf->state = BUF_STATE_QUEUED;
spin_lock_irqsave(&go->spinlock, flags);
- list_add_tail(&gobuf->stream, &go->stream);
+ list_add_tail(&go7007_vb->list, &go->vidq_active);
spin_unlock_irqrestore(&go->spinlock, flags);
- mutex_unlock(&gofh->lock);
+}
- return 0;
+static int go7007_buf_prepare(struct vb2_buffer *vb)
+{
+ struct go7007_buffer *go7007_vb =
+ container_of(vb, struct go7007_buffer, vb);
-unlock_and_return:
- mutex_unlock(&gofh->lock);
- return retval;
+ go7007_vb->modet_active = 0;
+ go7007_vb->frame_offset = 0;
+ vb->v4l2_planes[0].bytesused = 0;
+ return 0;
}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+static int go7007_buf_finish(struct vb2_buffer *vb)
{
- struct go7007_file *gofh = priv;
- struct go7007 *go = gofh->go;
- struct go7007_buffer *gobuf;
- int retval = -EINVAL;
- unsigned long flags;
- u32 frame_type_flag;
- DEFINE_WAIT(wait);
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return retval;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return retval;
-
- mutex_lock(&gofh->lock);
- if (list_empty(&go->stream))
- goto unlock_and_return;
- gobuf = list_entry(go->stream.next,
- struct go7007_buffer, stream);
-
- retval = -EAGAIN;
- if (gobuf->state != BUF_STATE_DONE &&
- !(file->f_flags & O_NONBLOCK)) {
- for (;;) {
- prepare_to_wait(&go->frame_waitq, &wait,
- TASK_INTERRUPTIBLE);
- if (gobuf->state == BUF_STATE_DONE)
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- finish_wait(&go->frame_waitq, &wait);
- }
- if (gobuf->state != BUF_STATE_DONE)
- goto unlock_and_return;
-
- spin_lock_irqsave(&go->spinlock, flags);
- deactivate_buffer(gobuf);
- spin_unlock_irqrestore(&go->spinlock, flags);
- frame_type_flag = get_frame_type_flag(gobuf, go->format);
- gobuf->state = BUF_STATE_IDLE;
-
- memset(buf, 0, sizeof(*buf));
- buf->index = gobuf->index;
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->bytesused = gobuf->bytesused;
- buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct go7007 *go = vb2_get_drv_priv(vq);
+ struct go7007_buffer *go7007_vb =
+ container_of(vb, struct go7007_buffer, vb);
+ u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format);
+ struct v4l2_buffer *buf = &vb->v4l2_buf;
+
+ buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME |
+ V4L2_BUF_FLAG_PFRAME);
+ buf->flags |= frame_type_flag;
buf->field = V4L2_FIELD_NONE;
- buf->timestamp = gobuf->timestamp;
- buf->sequence = gobuf->seq;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
- buf->length = GO7007_BUF_SIZE;
- buf->reserved = gobuf->modet_active;
-
- mutex_unlock(&gofh->lock);
return 0;
-
-unlock_and_return:
- mutex_unlock(&gofh->lock);
- return retval;
}
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
+static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct go7007_file *gofh = priv;
- struct go7007 *go = gofh->go;
- int retval = 0;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
+ struct go7007 *go = vb2_get_drv_priv(q);
+ int ret;
- mutex_lock(&gofh->lock);
+ set_formatting(go);
mutex_lock(&go->hw_lock);
-
- if (!go->streaming) {
- go->streaming = 1;
- go->next_seq = 0;
- go->active_buf = NULL;
- if (go7007_start_encoder(go) < 0)
- retval = -EIO;
- else
- retval = 0;
- }
+ go->next_seq = 0;
+ go->active_buf = NULL;
+ q->streaming = 1;
+ if (go7007_start_encoder(go) < 0)
+ ret = -EIO;
+ else
+ ret = 0;
mutex_unlock(&go->hw_lock);
- mutex_unlock(&gofh->lock);
+ if (ret) {
+ q->streaming = 0;
+ return ret;
+ }
call_all(&go->v4l2_dev, video, s_stream, 1);
-
- return retval;
+ v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
+ v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
+ v4l2_ctrl_grab(go->mpeg_video_bitrate, true);
+ v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true);
+ /* Turn on Capture LED */
+ if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
+ go7007_write_addr(go, 0x3c82, 0x0005);
+ return ret;
}
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
+static int go7007_stop_streaming(struct vb2_queue *q)
{
- struct go7007_file *gofh = priv;
- struct go7007 *go = gofh->go;
+ struct go7007 *go = vb2_get_drv_priv(q);
+ unsigned long flags;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- mutex_lock(&gofh->lock);
- go7007_streamoff(go);
- mutex_unlock(&gofh->lock);
+ q->streaming = 0;
+ go7007_stream_stop(go);
+ mutex_lock(&go->hw_lock);
+ go7007_reset_encoder(go);
+ mutex_unlock(&go->hw_lock);
call_all(&go->v4l2_dev, video, s_stream, 0);
+ spin_lock_irqsave(&go->spinlock, flags);
+ INIT_LIST_HEAD(&go->vidq_active);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ v4l2_ctrl_grab(go->mpeg_video_gop_size, false);
+ v4l2_ctrl_grab(go->mpeg_video_gop_closure, false);
+ v4l2_ctrl_grab(go->mpeg_video_bitrate, false);
+ v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false);
+ /* Turn on Capture LED */
+ if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
+ go7007_write_addr(go, 0x3c82, 0x000d);
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *query)
-{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
- int id = query->id;
-
- if (0 == call_all(&go->v4l2_dev, core, queryctrl, query))
- return 0;
-
- query->id = id;
- return mpeg_query_ctrl(query);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
-
- if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl))
- return 0;
-
- return mpeg_g_ctrl(ctrl, go);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
-
- if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl))
- return 0;
-
- return mpeg_s_ctrl(ctrl, go);
-}
+static struct vb2_ops go7007_video_qops = {
+ .queue_setup = go7007_queue_setup,
+ .buf_queue = go7007_buf_queue,
+ .buf_prepare = go7007_buf_prepare,
+ .buf_finish = go7007_buf_finish,
+ .start_streaming = go7007_start_streaming,
+ .stop_streaming = go7007_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
static int vidioc_g_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(filp);
struct v4l2_fract timeperframe = {
.numerator = 1001 * go->fps_scale,
.denominator = go->sensor_framerate,
@@ -1021,7 +565,8 @@ static int vidioc_g_parm(struct file *filp, void *priv,
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.readbuffers = 2;
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
parm->parm.capture.timeperframe = timeperframe;
return 0;
@@ -1030,13 +575,11 @@ static int vidioc_g_parm(struct file *filp, void *priv,
static int vidioc_s_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(filp);
unsigned int n, d;
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (parm->parm.capture.capturemode != 0)
- return -EINVAL;
n = go->sensor_framerate *
parm->parm.capture.timeperframe.numerator;
@@ -1046,7 +589,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
else
go->fps_scale = 1;
- return 0;
+ return vidioc_g_parm(filp, priv, parm);
}
/* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and
@@ -1062,121 +605,96 @@ static int vidioc_s_parm(struct file *filp, void *priv,
static int vidioc_enum_framesizes(struct file *filp, void *priv,
struct v4l2_frmsizeenum *fsize)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(filp);
+ int width, height;
- /* Return -EINVAL, if it is a TV board */
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
- (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+ if (fsize->index > 2)
return -EINVAL;
- if (fsize->index > 0)
+ if (!valid_pixelformat(fsize->pixel_format))
return -EINVAL;
+ get_resolution(go, &width, &height);
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = go->board_info->sensor_width;
- fsize->discrete.height = go->board_info->sensor_height;
-
+ fsize->discrete.width = (width >> fsize->index) & ~0xf;
+ fsize->discrete.height = (height >> fsize->index) & ~0xf;
return 0;
}
static int vidioc_enum_frameintervals(struct file *filp, void *priv,
struct v4l2_frmivalenum *fival)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(filp);
+ int width, height;
+ int i;
- /* Return -EINVAL, if it is a TV board */
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
- (go->board_info->sensor_flags & GO7007_SENSOR_TV))
+ if (fival->index > 4)
return -EINVAL;
- if (fival->index > 0)
+ if (!valid_pixelformat(fival->pixel_format))
return -EINVAL;
+ if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) {
+ get_resolution(go, &width, &height);
+ for (i = 0; i <= 2; i++)
+ if (fival->width == ((width >> i) & ~0xf) &&
+ fival->height == ((height >> i) & ~0xf))
+ break;
+ if (i > 2)
+ return -EINVAL;
+ }
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete.numerator = 1001;
- fival->discrete.denominator = go->board_info->sensor_framerate;
-
+ fival->discrete.numerator = 1001 * (fival->index + 1);
+ fival->discrete.denominator = go->sensor_framerate;
return 0;
}
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- switch (go->standard) {
- case GO7007_STD_NTSC:
- *std = V4L2_STD_NTSC;
- break;
- case GO7007_STD_PAL:
- *std = V4L2_STD_PAL;
- break;
- default:
- return -EINVAL;
+ *std = go->std;
+ return 0;
+}
+
+static int go7007_s_std(struct go7007 *go)
+{
+ if (go->std & V4L2_STD_625_50) {
+ go->standard = GO7007_STD_PAL;
+ go->sensor_framerate = 25025;
+ } else {
+ go->standard = GO7007_STD_NTSC;
+ go->sensor_framerate = 30000;
}
+ call_all(&go->v4l2_dev, core, s_std, go->std);
+ set_capture_size(go, NULL, 0);
return 0;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (go->streaming)
+ if (vb2_is_busy(&go->vidq))
return -EBUSY;
- if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0)
- return -EINVAL;
-
- if (*std == 0)
- return -EINVAL;
-
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
- go->input == go->board_info->num_inputs - 1) {
- if (!go->i2c_adapter_online)
- return -EIO;
- if (call_all(&go->v4l2_dev, core, s_std, *std) < 0)
- return -EINVAL;
- }
-
- if (*std & V4L2_STD_NTSC) {
- go->standard = GO7007_STD_NTSC;
- go->sensor_framerate = 30000;
- } else if (*std & V4L2_STD_PAL) {
- go->standard = GO7007_STD_PAL;
- go->sensor_framerate = 25025;
- } else if (*std & V4L2_STD_SECAM) {
- go->standard = GO7007_STD_PAL;
- go->sensor_framerate = 25025;
- } else
- return -EINVAL;
-
- call_all(&go->v4l2_dev, core, s_std, *std);
- set_capture_size(go, NULL, 0);
+ go->std = std;
- return 0;
+ return go7007_s_std(go);
}
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
-
- if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
- go->input == go->board_info->num_inputs - 1) {
- if (!go->i2c_adapter_online)
- return -EIO;
- return call_all(&go->v4l2_dev, video, querystd, std);
- } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
- *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
- else
- *std = 0;
+ struct go7007 *go = video_drvdata(file);
- return 0;
+ return call_all(&go->v4l2_dev, video, querystd, std);
}
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
if (inp->index >= go->board_info->num_inputs)
return -EINVAL;
@@ -1184,18 +702,20 @@ static int vidioc_enum_input(struct file *file, void *priv,
strncpy(inp->name, go->board_info->inputs[inp->index].name,
sizeof(inp->name));
- /* If this board has a tuner, it will be the last input */
+ /* If this board has a tuner, it will be the first input */
if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
- inp->index == go->board_info->num_inputs - 1)
+ inp->index == 0)
inp->type = V4L2_INPUT_TYPE_TUNER;
else
inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->audioset = 0;
+ if (go->board_info->num_aud_inputs)
+ inp->audioset = (1 << go->board_info->num_aud_inputs) - 1;
+ else
+ inp->audioset = 0;
inp->tuner = 0;
if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
- inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
- V4L2_STD_SECAM;
+ inp->std = video_devdata(file)->tvnorms;
else
inp->std = 0;
@@ -1205,203 +725,128 @@ static int vidioc_enum_input(struct file *file, void *priv,
static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
*input = go->input;
return 0;
}
-static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (input >= go->board_info->num_inputs)
+ if (a->index >= go->board_info->num_aud_inputs)
return -EINVAL;
- if (go->streaming)
- return -EBUSY;
+ strlcpy(a->name, go->board_info->aud_inputs[a->index].name, sizeof(a->name));
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
- go->input = input;
+static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ struct go7007 *go = video_drvdata(file);
- return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0);
+ a->index = go->aud_input;
+ strlcpy(a->name, go->board_info->aud_inputs[go->aud_input].name, sizeof(a->name));
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
- return -EINVAL;
- if (t->index != 0)
+ if (a->index >= go->board_info->num_aud_inputs)
return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
-
- return call_all(&go->v4l2_dev, tuner, g_tuner, t);
+ go->aud_input = a->index;
+ v4l2_subdev_call(go->sd_audio, audio, s_routing,
+ go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0);
+ return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+static void go7007_s_input(struct go7007 *go)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ unsigned int input = go->input;
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
- return -EINVAL;
- if (t->index != 0)
- return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
-
- switch (go->board_id) {
- case GO7007_BOARDID_PX_TV402U_NA:
- case GO7007_BOARDID_PX_TV402U_JP:
- /* No selectable options currently */
- if (t->audmode != V4L2_TUNER_MODE_STEREO)
- return -EINVAL;
- break;
- }
+ v4l2_subdev_call(go->sd_video, video, s_routing,
+ go->board_info->inputs[input].video_input, 0,
+ go->board_info->video_config);
+ if (go->board_info->num_aud_inputs) {
+ int aud_input = go->board_info->inputs[input].audio_index;
- return call_all(&go->v4l2_dev, tuner, s_tuner, t);
+ v4l2_subdev_call(go->sd_audio, audio, s_routing,
+ go->board_info->aud_inputs[aud_input].audio_input, 0, 0);
+ go->aud_input = aud_input;
+ }
}
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ if (input >= go->board_info->num_inputs)
return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
+ if (vb2_is_busy(&go->vidq))
+ return -EBUSY;
- f->type = V4L2_TUNER_ANALOG_TV;
+ go->input = input;
+ go7007_s_input(go);
- return call_all(&go->v4l2_dev, tuner, g_frequency, f);
+ return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ if (t->index != 0)
return -EINVAL;
- if (!go->i2c_adapter_online)
- return -EIO;
- return call_all(&go->v4l2_dev, tuner, s_frequency, f);
+ strlcpy(t->name, "Tuner", sizeof(t->name));
+ return call_all(&go->v4l2_dev, tuner, g_tuner, t);
}
-static int vidioc_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *cropcap)
+static int vidioc_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *t)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (t->index != 0)
return -EINVAL;
- /* These specify the raw input of the sensor */
- switch (go->standard) {
- case GO7007_STD_NTSC:
- cropcap->bounds.top = 0;
- cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = 480;
- cropcap->defrect.top = 0;
- cropcap->defrect.left = 0;
- cropcap->defrect.width = 720;
- cropcap->defrect.height = 480;
- break;
- case GO7007_STD_PAL:
- cropcap->bounds.top = 0;
- cropcap->bounds.left = 0;
- cropcap->bounds.width = 720;
- cropcap->bounds.height = 576;
- cropcap->defrect.top = 0;
- cropcap->defrect.left = 0;
- cropcap->defrect.width = 720;
- cropcap->defrect.height = 576;
- break;
- case GO7007_STD_OTHER:
- cropcap->bounds.top = 0;
- cropcap->bounds.left = 0;
- cropcap->bounds.width = go->board_info->sensor_width;
- cropcap->bounds.height = go->board_info->sensor_height;
- cropcap->defrect.top = 0;
- cropcap->defrect.left = 0;
- cropcap->defrect.width = go->board_info->sensor_width;
- cropcap->defrect.height = go->board_info->sensor_height;
- break;
- }
-
- return 0;
+ return call_all(&go->v4l2_dev, tuner, s_tuner, t);
}
-static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
- struct go7007 *go = ((struct go7007_file *) priv)->go;
+ struct go7007 *go = video_drvdata(file);
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->tuner)
return -EINVAL;
- crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- /* These specify the raw input of the sensor */
- switch (go->standard) {
- case GO7007_STD_NTSC:
- crop->c.top = 0;
- crop->c.left = 0;
- crop->c.width = 720;
- crop->c.height = 480;
- break;
- case GO7007_STD_PAL:
- crop->c.top = 0;
- crop->c.left = 0;
- crop->c.width = 720;
- crop->c.height = 576;
- break;
- case GO7007_STD_OTHER:
- crop->c.top = 0;
- crop->c.left = 0;
- crop->c.width = go->board_info->sensor_width;
- crop->c.height = go->board_info->sensor_height;
- break;
- }
-
- return 0;
+ return call_all(&go->v4l2_dev, tuner, g_frequency, f);
}
-/* FIXME: vidioc_s_crop is not really implemented!!!
- */
-static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop)
+static int vidioc_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
{
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return 0;
-}
+ struct go7007 *go = video_drvdata(file);
-static int vidioc_g_jpegcomp(struct file *file, void *priv,
- struct v4l2_jpegcompression *params)
-{
- memset(params, 0, sizeof(*params));
- params->quality = 50; /* ?? */
- params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
- V4L2_JPEG_MARKER_DQT;
+ if (f->tuner)
+ return -EINVAL;
- return 0;
+ return call_all(&go->v4l2_dev, tuner, s_frequency, f);
}
-static int vidioc_s_jpegcomp(struct file *file, void *priv,
- const struct v4l2_jpegcompression *params)
+static int vidioc_log_status(struct file *file, void *priv)
{
- if (params->quality != 50 ||
- params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
- V4L2_JPEG_MARKER_DQT))
- return -EINVAL;
+ struct go7007 *go = video_drvdata(file);
- return 0;
+ v4l2_ctrl_log_status(file, priv);
+ return call_all(&go->v4l2_dev, core, log_status);
}
/* FIXME:
@@ -1412,180 +857,6 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
*/
#if 0
- /* Temporary ioctls for controlling compression characteristics */
- case GO7007IOC_S_BITRATE:
- {
- int *bitrate = arg;
-
- if (go->streaming)
- return -EINVAL;
- /* Upper bound is kind of arbitrary here */
- if (*bitrate < 64000 || *bitrate > 10000000)
- return -EINVAL;
- go->bitrate = *bitrate;
- return 0;
- }
- case GO7007IOC_G_BITRATE:
- {
- int *bitrate = arg;
-
- *bitrate = go->bitrate;
- return 0;
- }
- case GO7007IOC_S_COMP_PARAMS:
- {
- struct go7007_comp_params *comp = arg;
-
- if (go->format == GO7007_FORMAT_MJPEG)
- return -EINVAL;
- if (comp->gop_size > 0)
- go->gop_size = comp->gop_size;
- else
- go->gop_size = go->sensor_framerate / 1000;
- if (go->gop_size != 15)
- go->dvd_mode = 0;
- /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */
- if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
- switch (comp->aspect_ratio) {
- case GO7007_ASPECT_RATIO_4_3_NTSC:
- case GO7007_ASPECT_RATIO_4_3_PAL:
- go->aspect_ratio = GO7007_RATIO_4_3;
- break;
- case GO7007_ASPECT_RATIO_16_9_NTSC:
- case GO7007_ASPECT_RATIO_16_9_PAL:
- go->aspect_ratio = GO7007_RATIO_16_9;
- break;
- default:
- go->aspect_ratio = GO7007_RATIO_1_1;
- break;
- }
- }
- if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) {
- go->dvd_mode = 0;
- go->seq_header_enable = 0;
- } else {
- go->seq_header_enable = 1;
- }
- /* fall-through */
- }
- case GO7007IOC_G_COMP_PARAMS:
- {
- struct go7007_comp_params *comp = arg;
-
- if (go->format == GO7007_FORMAT_MJPEG)
- return -EINVAL;
- memset(comp, 0, sizeof(*comp));
- comp->gop_size = go->gop_size;
- comp->max_b_frames = go->ipb ? 2 : 0;
- switch (go->aspect_ratio) {
- case GO7007_RATIO_4_3:
- if (go->standard == GO7007_STD_NTSC)
- comp->aspect_ratio =
- GO7007_ASPECT_RATIO_4_3_NTSC;
- else
- comp->aspect_ratio =
- GO7007_ASPECT_RATIO_4_3_PAL;
- break;
- case GO7007_RATIO_16_9:
- if (go->standard == GO7007_STD_NTSC)
- comp->aspect_ratio =
- GO7007_ASPECT_RATIO_16_9_NTSC;
- else
- comp->aspect_ratio =
- GO7007_ASPECT_RATIO_16_9_PAL;
- break;
- default:
- comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1;
- break;
- }
- if (go->closed_gop)
- comp->flags |= GO7007_COMP_CLOSED_GOP;
- if (!go->seq_header_enable)
- comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER;
- return 0;
- }
- case GO7007IOC_S_MPEG_PARAMS:
- {
- struct go7007_mpeg_params *mpeg = arg;
-
- if (go->format != GO7007_FORMAT_MPEG1 &&
- go->format != GO7007_FORMAT_MPEG2 &&
- go->format != GO7007_FORMAT_MPEG4)
- return -EINVAL;
-
- if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) {
- go->format = GO7007_FORMAT_MPEG2;
- go->bitrate = 9800000;
- go->gop_size = 15;
- go->pali = 0x48;
- go->closed_gop = 1;
- go->repeat_seqhead = 0;
- go->seq_header_enable = 1;
- go->gop_header_enable = 1;
- go->dvd_mode = 1;
- } else {
- switch (mpeg->mpeg_video_standard) {
- case GO7007_MPEG_VIDEO_MPEG1:
- go->format = GO7007_FORMAT_MPEG1;
- go->pali = 0;
- break;
- case GO7007_MPEG_VIDEO_MPEG2:
- go->format = GO7007_FORMAT_MPEG2;
- if (mpeg->pali >> 24 == 2)
- go->pali = mpeg->pali & 0xff;
- else
- go->pali = 0x48;
- break;
- case GO7007_MPEG_VIDEO_MPEG4:
- go->format = GO7007_FORMAT_MPEG4;
- if (mpeg->pali >> 24 == 4)
- go->pali = mpeg->pali & 0xff;
- else
- go->pali = 0xf5;
- break;
- default:
- return -EINVAL;
- }
- go->gop_header_enable =
- mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
- ? 0 : 1;
- if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
- go->repeat_seqhead = 1;
- else
- go->repeat_seqhead = 0;
- go->dvd_mode = 0;
- }
- /* fall-through */
- }
- case GO7007IOC_G_MPEG_PARAMS:
- {
- struct go7007_mpeg_params *mpeg = arg;
-
- memset(mpeg, 0, sizeof(*mpeg));
- switch (go->format) {
- case GO7007_FORMAT_MPEG1:
- mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;
- mpeg->pali = 0;
- break;
- case GO7007_FORMAT_MPEG2:
- mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
- mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali);
- break;
- case GO7007_FORMAT_MPEG4:
- mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
- mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali);
- break;
- default:
- return -EINVAL;
- }
- if (!go->gop_header_enable)
- mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER;
- if (go->repeat_seqhead)
- mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER;
- if (go->dvd_mode)
- mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE;
- return 0;
- }
case GO7007IOC_S_MD_PARAMS:
{
struct go7007_md_params *mdp = arg;
@@ -1604,25 +875,6 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
go->modet[mdp->region].enable = 0;
/* fall-through */
}
- case GO7007IOC_G_MD_PARAMS:
- {
- struct go7007_md_params *mdp = arg;
- int region = mdp->region;
-
- if (mdp->region > 3)
- return -EINVAL;
- memset(mdp, 0, sizeof(struct go7007_md_params));
- mdp->region = region;
- if (!go->modet[region].enable)
- return 0;
- mdp->pixel_threshold =
- (go->modet[region].pixel_threshold << 1) + 1;
- mdp->motion_threshold =
- (go->modet[region].motion_threshold << 1) + 1;
- mdp->trigger =
- (go->modet[region].mb_threshold << 1) + 1;
- return 0;
- }
case GO7007IOC_S_MD_REGION:
{
struct go7007_md_region *region = arg;
@@ -1633,116 +885,14 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
}
#endif
-static ssize_t go7007_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static void go7007_vm_open(struct vm_area_struct *vma)
-{
- struct go7007_buffer *gobuf = vma->vm_private_data;
-
- ++gobuf->mapped;
-}
-
-static void go7007_vm_close(struct vm_area_struct *vma)
-{
- struct go7007_buffer *gobuf = vma->vm_private_data;
- unsigned long flags;
-
- if (--gobuf->mapped == 0) {
- spin_lock_irqsave(&gobuf->go->spinlock, flags);
- deactivate_buffer(gobuf);
- spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
- }
-}
-
-/* Copied from videobuf-dma-sg.c */
-static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
- struct page *page;
-
- page = alloc_page(GFP_USER | __GFP_DMA32);
- if (!page)
- return VM_FAULT_OOM;
- clear_user_highpage(page, (unsigned long)vmf->virtual_address);
- vmf->page = page;
- return 0;
-}
-
-static struct vm_operations_struct go7007_vm_ops = {
- .open = go7007_vm_open,
- .close = go7007_vm_close,
- .fault = go7007_vm_fault,
-};
-
-static int go7007_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct go7007_file *gofh = file->private_data;
- unsigned int index;
-
- if (gofh->go->status != STATUS_ONLINE)
- return -EIO;
- if (!(vma->vm_flags & VM_SHARED))
- return -EINVAL; /* only support VM_SHARED mapping */
- if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE)
- return -EINVAL; /* must map exactly one full buffer */
- mutex_lock(&gofh->lock);
- index = vma->vm_pgoff / GO7007_BUF_PAGES;
- if (index >= gofh->buf_count) {
- mutex_unlock(&gofh->lock);
- return -EINVAL; /* trying to map beyond requested buffers */
- }
- if (index * GO7007_BUF_PAGES != vma->vm_pgoff) {
- mutex_unlock(&gofh->lock);
- return -EINVAL; /* offset is not aligned on buffer boundary */
- }
- if (gofh->bufs[index].mapped > 0) {
- mutex_unlock(&gofh->lock);
- return -EBUSY;
- }
- gofh->bufs[index].mapped = 1;
- gofh->bufs[index].user_addr = vma->vm_start;
- vma->vm_ops = &go7007_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_flags &= ~VM_IO;
- vma->vm_private_data = &gofh->bufs[index];
- mutex_unlock(&gofh->lock);
- return 0;
-}
-
-static unsigned int go7007_poll(struct file *file, poll_table *wait)
-{
- struct go7007_file *gofh = file->private_data;
- struct go7007_buffer *gobuf;
-
- if (list_empty(&gofh->go->stream))
- return POLLERR;
- gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream);
- poll_wait(file, &gofh->go->frame_waitq, wait);
- if (gobuf->state == BUF_STATE_DONE)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static void go7007_vfl_release(struct video_device *vfd)
-{
- struct go7007 *go = video_get_drvdata(vfd);
-
- video_device_release(vfd);
- if (--go->ref_count == 0)
- kfree(go);
-}
-
static struct v4l2_file_operations go7007_fops = {
.owner = THIS_MODULE,
- .open = go7007_open,
- .release = go7007_release,
- .ioctl = video_ioctl2,
- .read = go7007_read,
- .mmap = go7007_mmap,
- .poll = go7007_poll,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1751,21 +901,21 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_querystd = vidioc_querystd,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_enumaudio = vidioc_enumaudio,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1774,66 +924,129 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_parm = vidioc_s_parm,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
- .vidioc_cropcap = vidioc_cropcap,
- .vidioc_g_crop = vidioc_g_crop,
- .vidioc_s_crop = vidioc_s_crop,
- .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
- .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device go7007_template = {
.name = "go7007",
.fops = &go7007_fops,
- .release = go7007_vfl_release,
+ .release = video_device_release_empty,
.ioctl_ops = &video_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
- .current_norm = V4L2_STD_NTSC,
};
+int go7007_v4l2_ctrl_init(struct go7007 *go)
+{
+ struct v4l2_ctrl_handler *hdl = &go->hdl;
+ struct v4l2_ctrl *ctrl;
+
+ v4l2_ctrl_handler_init(hdl, 13);
+ go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15);
+ go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
+ go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 64000, 10000000, 1, 9800000);
+ go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0);
+ go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1);
+
+ go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_MPEG_VIDEO_ASPECT_16x9, 0,
+ V4L2_MPEG_VIDEO_ASPECT_1x1);
+ ctrl = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ if (hdl->error) {
+ int rv = hdl->error;
+
+ v4l2_err(&go->v4l2_dev, "Could not register controls\n");
+ return rv;
+ }
+ go->v4l2_dev.ctrl_handler = hdl;
+ return 0;
+}
+
int go7007_v4l2_init(struct go7007 *go)
{
+ struct video_device *vdev = &go->vdev;
int rv;
- go->video_dev = video_device_alloc();
- if (go->video_dev == NULL)
- return -ENOMEM;
- *go->video_dev = go7007_template;
- go->video_dev->parent = go->dev;
- rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1);
- if (rv < 0) {
- video_device_release(go->video_dev);
- go->video_dev = NULL;
+ mutex_init(&go->serialize_lock);
+ mutex_init(&go->queue_lock);
+
+ INIT_LIST_HEAD(&go->vidq_active);
+ go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ go->vidq.ops = &go7007_video_qops;
+ go->vidq.mem_ops = &vb2_vmalloc_memops;
+ go->vidq.drv_priv = go;
+ go->vidq.buf_struct_size = sizeof(struct go7007_buffer);
+ go->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ go->vidq.lock = &go->queue_lock;
+ rv = vb2_queue_init(&go->vidq);
+ if (rv)
return rv;
+ *vdev = go7007_template;
+ vdev->lock = &go->serialize_lock;
+ vdev->queue = &go->vidq;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
+ video_set_drvdata(vdev, go);
+ vdev->v4l2_dev = &go->v4l2_dev;
+ if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd))
+ v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD);
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) {
+ v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER);
+ } else {
+ struct v4l2_frequency f = {
+ .type = V4L2_TUNER_ANALOG_TV,
+ .frequency = 980,
+ };
+
+ call_all(&go->v4l2_dev, tuner, s_frequency, &f);
}
- rv = v4l2_device_register(go->dev, &go->v4l2_dev);
- if (rv < 0) {
- video_device_release(go->video_dev);
- go->video_dev = NULL;
- return rv;
+ if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) {
+ v4l2_disable_ioctl(vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(vdev, VIDIOC_S_STD);
+ vdev->tvnorms = 0;
+ }
+ if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING)
+ v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES);
+ if (go->board_info->num_aud_inputs == 0) {
+ v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO);
}
- video_set_drvdata(go->video_dev, go);
- ++go->ref_count;
+ /* Setup correct crystal frequency on this board */
+ if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115)
+ v4l2_subdev_call(go->sd_video, video, s_crystal_freq,
+ SAA7115_FREQ_24_576_MHZ,
+ SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC |
+ SAA7115_FREQ_FL_DOUBLE_ASCLK);
+ go7007_s_input(go);
+ if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+ go7007_s_std(go);
+ rv = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+ if (rv < 0)
+ return rv;
dev_info(go->dev, "registered device %s [v4l2]\n",
- video_device_node_name(go->video_dev));
+ video_device_node_name(vdev));
return 0;
}
void go7007_v4l2_remove(struct go7007 *go)
{
- unsigned long flags;
-
- mutex_lock(&go->hw_lock);
- if (go->streaming) {
- go->streaming = 0;
- go7007_stream_stop(go);
- spin_lock_irqsave(&go->spinlock, flags);
- abort_queued(go);
- spin_unlock_irqrestore(&go->spinlock, flags);
- }
- mutex_unlock(&go->hw_lock);
- if (go->video_dev)
- video_unregister_device(go->video_dev);
- if (go->status != STATUS_SHUTDOWN)
- v4l2_device_unregister(&go->v4l2_dev);
+ v4l2_ctrl_handler_free(&go->hdl);
}
diff --git a/drivers/staging/media/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h
index 7399c915a934..54b989738982 100644
--- a/drivers/staging/media/go7007/go7007.h
+++ b/drivers/staging/media/go7007/go7007.h
@@ -17,72 +17,6 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS
- * to select between MPEG1, MPEG2, and MPEG4 */
-#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */
-
-/* These will be replaced with a better interface
- * soon, so don't get too attached to them */
-#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int)
-#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int)
-
-enum go7007_aspect_ratio {
- GO7007_ASPECT_RATIO_1_1 = 0,
- GO7007_ASPECT_RATIO_4_3_NTSC = 1,
- GO7007_ASPECT_RATIO_4_3_PAL = 2,
- GO7007_ASPECT_RATIO_16_9_NTSC = 3,
- GO7007_ASPECT_RATIO_16_9_PAL = 4,
-};
-
-/* Used to set generic compression parameters */
-struct go7007_comp_params {
- __u32 gop_size;
- __u32 max_b_frames;
- enum go7007_aspect_ratio aspect_ratio;
- __u32 flags;
- __u32 reserved[8];
-};
-
-#define GO7007_COMP_CLOSED_GOP 0x00000001
-#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002
-
-enum go7007_mpeg_video_standard {
- GO7007_MPEG_VIDEO_MPEG1 = 0,
- GO7007_MPEG_VIDEO_MPEG2 = 1,
- GO7007_MPEG_VIDEO_MPEG4 = 2,
-};
-
-/* Used to set parameters for V4L2_PIX_FMT_MPEG format */
-struct go7007_mpeg_params {
- enum go7007_mpeg_video_standard mpeg_video_standard;
- __u32 flags;
- __u32 pali;
- __u32 reserved[8];
-};
-
-#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001
-#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002
-#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004
-
-#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali))
-
-#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48)
-
-#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08)
-#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01)
-#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02)
-#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03)
-#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91)
-#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92)
-#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93)
-#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94)
-#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0)
-#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1)
-#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2)
-#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3)
-#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4)
-#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5)
-
struct go7007_md_params {
__u16 region;
__u16 trigger;
@@ -98,14 +32,6 @@ struct go7007_md_region {
__u32 reserved[8];
};
-#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \
- struct go7007_mpeg_params)
-#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \
- struct go7007_mpeg_params)
-#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \
- struct go7007_comp_params)
-#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \
- struct go7007_comp_params)
#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
struct go7007_md_params)
#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \
diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c
index 37400bfa6ccb..beaa98b9c85a 100644
--- a/drivers/staging/media/go7007/s2250-board.c
+++ b/drivers/staging/media/go7007/s2250-board.c
@@ -29,6 +29,13 @@
MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver");
MODULE_LICENSE("GPL v2");
+/*
+ * Note: this board has two i2c devices: a vpx3226f and a tlv320aic23b.
+ * Due to the unusual way these are accessed on this device we do not
+ * reuse the i2c drivers, but instead they are implemented in this
+ * driver. It would be nice to improve on this, though.
+ */
+
#define TLV320_ADDRESS 0x34
#define VPX322_ADDR_ANALOGCONTROL1 0x02
#define VPX322_ADDR_BRIGHTNESS0 0x0127
@@ -116,6 +123,7 @@ static u16 vid_regs_fp_pal[] = {
struct s2250 {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
v4l2_std_id std;
int input;
int brightness;
@@ -353,127 +361,48 @@ static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
u16 vidsource;
vidsource = (state->input == 1) ? 0x040 : 0x020;
- switch (norm) {
- case V4L2_STD_NTSC:
- write_regs_fp(client, vid_regs_fp);
- write_reg_fp(client, 0x20, vidsource | 1);
- break;
- case V4L2_STD_PAL:
+ if (norm & V4L2_STD_625_50) {
write_regs_fp(client, vid_regs_fp);
write_regs_fp(client, vid_regs_fp_pal);
write_reg_fp(client, 0x20, vidsource);
- break;
- default:
- return -EINVAL;
+ } else {
+ write_regs_fp(client, vid_regs_fp);
+ write_reg_fp(client, 0x20, vidsource | 1);
}
state->std = norm;
return 0;
}
-static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query)
+static int s2250_s_ctrl(struct v4l2_ctrl *ctrl)
{
- switch (query->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(query, 0, 100, 1, 50);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(query, -50, 50, 1, 0);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct s2250 *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int value1;
+ struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl);
+ struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
u16 oldvalue;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- if (ctrl->value > 100)
- state->brightness = 100;
- else if (ctrl->value < 0)
- state->brightness = 0;
- else
- state->brightness = ctrl->value;
- value1 = (state->brightness - 50) * 255 / 100;
read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);
write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,
- value1 | (oldvalue & ~0xff));
+ ctrl->val | (oldvalue & ~0xff));
read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);
write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,
- value1 | (oldvalue & ~0xff));
+ ctrl->val | (oldvalue & ~0xff));
write_reg_fp(client, 0x140, 0x60);
break;
case V4L2_CID_CONTRAST:
- if (ctrl->value > 100)
- state->contrast = 100;
- else if (ctrl->value < 0)
- state->contrast = 0;
- else
- state->contrast = ctrl->value;
- value1 = state->contrast * 0x40 / 100;
- if (value1 > 0x3f)
- value1 = 0x3f; /* max */
read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);
write_reg_fp(client, VPX322_ADDR_CONTRAST0,
- value1 | (oldvalue & ~0x3f));
+ ctrl->val | (oldvalue & ~0x3f));
read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);
write_reg_fp(client, VPX322_ADDR_CONTRAST1,
- value1 | (oldvalue & ~0x3f));
+ ctrl->val | (oldvalue & ~0x3f));
write_reg_fp(client, 0x140, 0x60);
break;
case V4L2_CID_SATURATION:
- if (ctrl->value > 100)
- state->saturation = 100;
- else if (ctrl->value < 0)
- state->saturation = 0;
- else
- state->saturation = ctrl->value;
- value1 = state->saturation * 4140 / 100;
- if (value1 > 4094)
- value1 = 4094;
- write_reg_fp(client, VPX322_ADDR_SAT, value1);
- break;
- case V4L2_CID_HUE:
- if (ctrl->value > 50)
- state->hue = 50;
- else if (ctrl->value < -50)
- state->hue = -50;
- else
- state->hue = ctrl->value;
- /* clamp the hue range */
- value1 = state->hue * 280 / 50;
- write_reg_fp(client, VPX322_ADDR_HUE, value1);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct s2250 *state = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = state->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = state->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = state->saturation;
+ write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val);
break;
case V4L2_CID_HUE:
- ctrl->value = state->hue;
+ write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val);
break;
default:
return -EINVAL;
@@ -531,24 +460,21 @@ static int s2250_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" :
state->input == 1 ? "S-video" :
"error");
- v4l2_info(sd, "Brightness: %d\n", state->brightness);
- v4l2_info(sd, "Contrast: %d\n", state->contrast);
- v4l2_info(sd, "Saturation: %d\n", state->saturation);
- v4l2_info(sd, "Hue: %d\n", state->hue);
v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" :
state->audio_input == 1 ? "Mic" :
state->audio_input == 2 ? "Mic Boost" :
"error");
- return 0;
+ return v4l2_ctrl_subdev_log_status(sd);
}
/* --------------------------------------------------------------------------*/
+static const struct v4l2_ctrl_ops s2250_ctrl_ops = {
+ .s_ctrl = s2250_s_ctrl,
+};
+
static const struct v4l2_subdev_core_ops s2250_core_ops = {
.log_status = s2250_log_status,
- .g_ctrl = s2250_g_ctrl,
- .s_ctrl = s2250_s_ctrl,
- .queryctrl = s2250_queryctrl,
.s_std = s2250_s_std,
};
@@ -584,7 +510,7 @@ static int s2250_probe(struct i2c_client *client,
if (audio == NULL)
return -ENOMEM;
- state = kmalloc(sizeof(struct s2250), GFP_KERNEL);
+ state = kzalloc(sizeof(struct s2250), GFP_KERNEL);
if (state == NULL) {
i2c_unregister_device(audio);
return -ENOMEM;
@@ -596,6 +522,24 @@ static int s2250_probe(struct i2c_client *client,
v4l2_info(sd, "initializing %s at address 0x%x on %s\n",
"Sensoray 2250/2251", client->addr, client->adapter->name);
+ v4l2_ctrl_handler_init(&state->hdl, 4);
+ v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x32);
+ v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 4094, 1, 2070);
+ v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,
+ V4L2_CID_HUE, -512, 511, 1, 0);
+ sd->ctrl_handler = &state->hdl;
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
+
state->std = V4L2_STD_NTSC;
state->brightness = 50;
state->contrast = 50;
@@ -606,22 +550,16 @@ static int s2250_probe(struct i2c_client *client,
/* initialize the audio */
if (write_regs(audio, aud_regs) < 0) {
dev_err(&client->dev, "error initializing audio\n");
- i2c_unregister_device(audio);
- kfree(state);
- return 0;
+ goto fail;
}
if (write_regs(client, vid_regs) < 0) {
dev_err(&client->dev, "error initializing decoder\n");
- i2c_unregister_device(audio);
- kfree(state);
- return 0;
+ goto fail;
}
if (write_regs_fp(client, vid_regs_fp) < 0) {
dev_err(&client->dev, "error initializing decoder\n");
- i2c_unregister_device(audio);
- kfree(state);
- return 0;
+ goto fail;
}
/* set default channel */
/* composite */
@@ -657,14 +595,21 @@ static int s2250_probe(struct i2c_client *client,
v4l2_info(sd, "initialized successfully\n");
return 0;
+
+fail:
+ i2c_unregister_device(audio);
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return -EIO;
}
static int s2250_remove(struct i2c_client *client)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct s2250 *state = to_state(i2c_get_clientdata(client));
- v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
+ v4l2_device_unregister_subdev(&state->sd);
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
return 0;
}
diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c
deleted file mode 100644
index 72e5175fe7e3..000000000000
--- a/drivers/staging/media/go7007/s2250-loader.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2008 Sensoray Company Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <dvb-usb.h>
-
-#define S2250_LOADER_FIRMWARE "s2250_loader.fw"
-#define S2250_FIRMWARE "s2250.fw"
-
-typedef struct device_extension_s {
- struct kref kref;
- int minor;
- struct usb_device *usbdev;
-} device_extension_t, *pdevice_extension_t;
-
-#define USB_s2250loader_MAJOR 240
-#define USB_s2250loader_MINOR_BASE 0
-#define MAX_DEVICES 256
-
-static pdevice_extension_t s2250_dev_table[MAX_DEVICES];
-static DEFINE_MUTEX(s2250_dev_table_mutex);
-
-#define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref)
-static void s2250loader_delete(struct kref *kref)
-{
- pdevice_extension_t s = to_s2250loader_dev_common(kref);
- s2250_dev_table[s->minor] = NULL;
- kfree(s);
-}
-
-static int s2250loader_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *usbdev;
- int minor, ret;
- pdevice_extension_t s = NULL;
- const struct firmware *fw;
-
- usbdev = usb_get_dev(interface_to_usbdev(interface));
- if (!usbdev) {
- dev_err(&interface->dev, "Enter s2250loader_probe failed\n");
- return -1;
- }
- dev_info(&interface->dev, "Enter s2250loader_probe 2.6 kernel\n");
- dev_info(&interface->dev, "vendor id 0x%x, device id 0x%x devnum:%d\n",
- usbdev->descriptor.idVendor, usbdev->descriptor.idProduct,
- usbdev->devnum);
-
- if (usbdev->descriptor.bNumConfigurations != 1) {
- dev_err(&interface->dev, "can't handle multiple config\n");
- return -1;
- }
- mutex_lock(&s2250_dev_table_mutex);
-
- for (minor = 0; minor < MAX_DEVICES; minor++) {
- if (s2250_dev_table[minor] == NULL)
- break;
- }
-
- if (minor < 0 || minor >= MAX_DEVICES) {
- dev_err(&interface->dev, "Invalid minor: %d\n", minor);
- goto failed;
- }
-
- /* Allocate dev data structure */
- s = kmalloc(sizeof(device_extension_t), GFP_KERNEL);
- if (s == NULL)
- goto failed;
-
- s2250_dev_table[minor] = s;
-
- dev_info(&interface->dev,
- "s2250loader_probe: Device %d on Bus %d Minor %d\n",
- usbdev->devnum, usbdev->bus->busnum, minor);
-
- memset(s, 0, sizeof(device_extension_t));
- s->usbdev = usbdev;
- dev_info(&interface->dev, "loading 2250 loader\n");
-
- kref_init(&(s->kref));
-
- mutex_unlock(&s2250_dev_table_mutex);
-
- if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) {
- dev_err(&interface->dev,
- "s2250: unable to load firmware from file \"%s\"\n",
- S2250_LOADER_FIRMWARE);
- goto failed2;
- }
- ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
- release_firmware(fw);
- if (0 != ret) {
- dev_err(&interface->dev, "loader download failed\n");
- goto failed2;
- }
-
- if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) {
- dev_err(&interface->dev,
- "s2250: unable to load firmware from file \"%s\"\n",
- S2250_FIRMWARE);
- goto failed2;
- }
- ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2);
- release_firmware(fw);
- if (0 != ret) {
- dev_err(&interface->dev, "firmware_s2250 download failed\n");
- goto failed2;
- }
-
- usb_set_intfdata(interface, s);
- return 0;
-
-failed:
- mutex_unlock(&s2250_dev_table_mutex);
-failed2:
- if (s)
- kref_put(&(s->kref), s2250loader_delete);
-
- dev_err(&interface->dev, "probe failed\n");
- return -1;
-}
-
-static void s2250loader_disconnect(struct usb_interface *interface)
-{
- pdevice_extension_t s;
- dev_info(&interface->dev, "s2250: disconnect\n");
- s = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
- kref_put(&(s->kref), s2250loader_delete);
-}
-
-static const struct usb_device_id s2250loader_ids[] = {
- {USB_DEVICE(0x1943, 0xa250)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, s2250loader_ids);
-
-static struct usb_driver s2250loader_driver = {
- .name = "s2250-loader",
- .probe = s2250loader_probe,
- .disconnect = s2250loader_disconnect,
- .id_table = s2250loader_ids,
-};
-
-module_usb_driver(s2250loader_driver);
-
-MODULE_AUTHOR("");
-MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
-MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE(S2250_LOADER_FIRMWARE);
-MODULE_FIRMWARE(S2250_FIRMWARE);
diff --git a/drivers/staging/media/go7007/s2250-loader.h b/drivers/staging/media/go7007/s2250-loader.h
deleted file mode 100644
index b7c301af16cc..000000000000
--- a/drivers/staging/media/go7007/s2250-loader.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#ifndef _S2250_LOADER_H_
-#define _S2250_LOADER_H_
-
-extern int s2250loader_init(void);
-extern void s2250loader_cleanup(void);
-
-#endif
diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c
index cf7c34a99459..d80b235d72ee 100644
--- a/drivers/staging/media/go7007/saa7134-go7007.c
+++ b/drivers/staging/media/go7007/saa7134-go7007.c
@@ -28,12 +28,15 @@
#include <linux/i2c.h>
#include <asm/byteorder.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
-#include "saa7134-reg.h"
#include "saa7134.h"
+#include "saa7134-reg.h"
+#include "go7007.h"
#include "go7007-priv.h"
-#define GO7007_HPI_DEBUG
+/*#define GO7007_HPI_DEBUG*/
enum hpi_address {
HPI_ADDR_VIDEO_BUFFER = 0xe4,
@@ -57,6 +60,7 @@ enum gpio_command {
};
struct saa7134_go7007 {
+ struct v4l2_subdev sd;
struct saa7134_dev *dev;
u8 *top;
u8 *bottom;
@@ -64,8 +68,12 @@ struct saa7134_go7007 {
dma_addr_t bottom_dma;
};
-static struct go7007_board_info board_voyager = {
- .firmware = "go7007tv.bin",
+static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7134_go7007, sd);
+}
+
+static const struct go7007_board_info board_voyager = {
.flags = 0,
.sensor_flags = GO7007_SENSOR_656 |
GO7007_SENSOR_VALID_ENABLE |
@@ -84,7 +92,6 @@ static struct go7007_board_info board_voyager = {
},
},
};
-MODULE_FIRMWARE("go7007tv.bin");
/********************* Driver for GPIO HPI interface *********************/
@@ -236,7 +243,7 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
struct go7007 *go = video_get_drvdata(dev->empress_dev);
struct saa7134_go7007 *saa = go->hpi_context;
- if (!go->streaming)
+ if (!vb2_is_streaming(&go->vidq))
return;
if (0 != (status & 0x000f0000))
printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
@@ -261,12 +268,12 @@ static int saa7134_go7007_stream_start(struct go7007 *go)
saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
0, PAGE_SIZE, DMA_FROM_DEVICE);
- if (!saa->top_dma)
+ if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
return -ENOMEM;
saa->bottom_dma = dma_map_page(&dev->pci->dev,
virt_to_page(saa->bottom),
0, PAGE_SIZE, DMA_FROM_DEVICE);
- if (!saa->bottom_dma) {
+ if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
DMA_FROM_DEVICE);
return -ENOMEM;
@@ -380,47 +387,6 @@ static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
return 0;
}
-static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd,
- void *arg)
-{
- struct saa7134_go7007 *saa = go->hpi_context;
- struct saa7134_dev *dev = saa->dev;
-
- switch (cmd) {
- case VIDIOC_S_STD:
- {
- v4l2_std_id *std = arg;
- return saa7134_s_std_internal(dev, NULL, std);
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *std = arg;
- *std = dev->tvnorm->id;
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
- return saa7134_queryctrl(NULL, NULL, ctrl);
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
- return saa7134_g_ctrl_internal(dev, NULL, ctrl);
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER)
- return saa7134_s_ctrl_internal(dev, NULL, ctrl);
- }
- }
- return -EINVAL;
-
-}
-
static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
.interface_reset = saa7134_go7007_interface_reset,
.write_interrupt = saa7134_go7007_write_interrupt,
@@ -428,21 +394,88 @@ static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
.stream_start = saa7134_go7007_stream_start,
.stream_stop = saa7134_go7007_stream_stop,
.send_firmware = saa7134_go7007_send_firmware,
- .send_command = saa7134_go7007_send_command,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+ struct saa7134_go7007 *saa = to_state(sd);
+ struct saa7134_dev *dev = saa->dev;
+
+ return saa7134_s_std_internal(dev, NULL, norm);
+}
+
+static int saa7134_go7007_queryctrl(struct v4l2_subdev *sd,
+ struct v4l2_queryctrl *query)
+{
+ return saa7134_queryctrl(NULL, NULL, query);
+}
+static int saa7134_go7007_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct saa7134_go7007 *saa = to_state(sd);
+ struct saa7134_dev *dev = saa->dev;
+ return saa7134_s_ctrl_internal(dev, NULL, ctrl);
+}
+
+static int saa7134_go7007_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct saa7134_go7007 *saa = to_state(sd);
+ struct saa7134_dev *dev = saa->dev;
+ return saa7134_g_ctrl_internal(dev, NULL, ctrl);
+}
+
+/* --------------------------------------------------------------------------*/
+
+static const struct v4l2_subdev_core_ops saa7134_go7007_core_ops = {
+ .g_ctrl = saa7134_go7007_g_ctrl,
+ .s_ctrl = saa7134_go7007_s_ctrl,
+ .queryctrl = saa7134_go7007_queryctrl,
+ .s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+ .core = &saa7134_go7007_core_ops,
};
+/* --------------------------------------------------------------------------*/
+
+
/********************* Add/remove functions *********************/
static int saa7134_go7007_init(struct saa7134_dev *dev)
{
struct go7007 *go;
struct saa7134_go7007 *saa;
+ struct v4l2_subdev *sd;
printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n");
+ go = go7007_alloc(&board_voyager, &dev->pci->dev);
+ if (go == NULL)
+ return -ENOMEM;
+
saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
- if (saa == NULL)
+ if (saa == NULL) {
+ kfree(go);
return -ENOMEM;
+ }
+
+ go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+ snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+ strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+ go->hpi_ops = &saa7134_go7007_hpi_ops;
+ go->hpi_context = saa;
+ saa->dev = dev;
+
+ /* Init the subdevice interface */
+ sd = &saa->sd;
+ v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+ v4l2_set_subdevdata(sd, saa);
+ strncpy(sd->name, "saa7134-go7007", sizeof(sd->name));
/* Allocate a couple pages for receiving the compressed stream */
saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
@@ -452,32 +485,23 @@ static int saa7134_go7007_init(struct saa7134_dev *dev)
if (!saa->bottom)
goto allocfail;
- go = go7007_alloc(&board_voyager, &dev->pci->dev);
- if (go == NULL)
- goto allocfail;
- go->board_id = GO7007_BOARDID_PCI_VOYAGER;
- strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
- go->hpi_ops = &saa7134_go7007_hpi_ops;
- go->hpi_context = saa;
- saa->dev = dev;
-
/* Boot the GO7007 */
if (go7007_boot_encoder(go, go->board_info->flags &
GO7007_BOARD_USE_ONBOARD_I2C) < 0)
- goto initfail;
+ goto allocfail;
/* Do any final GO7007 initialization, then register the
* V4L2 and ALSA interfaces */
- if (go7007_register_encoder(go) < 0)
- goto initfail;
- dev->empress_dev = go->video_dev;
- video_set_drvdata(dev->empress_dev, go);
+ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+ goto allocfail;
- go->status = STATUS_ONLINE;
- return 0;
+ /* Register the subdevice interface with the go7007 device */
+ if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+ printk(KERN_INFO "saa7134-go7007: register subdev failed\n");
-initfail:
- go->status = STATUS_SHUTDOWN;
+ dev->empress_dev = &go->vdev;
+
+ go->status = STATUS_ONLINE;
return 0;
allocfail:
@@ -486,6 +510,7 @@ allocfail:
if (saa->bottom)
free_page((unsigned long)saa->bottom);
kfree(saa);
+ kfree(go);
return -ENOMEM;
}
@@ -498,12 +523,18 @@ static int saa7134_go7007_fini(struct saa7134_dev *dev)
return 0;
go = video_get_drvdata(dev->empress_dev);
+ if (go->audio_enabled)
+ go7007_snd_remove(go);
+
saa = go->hpi_context;
go->status = STATUS_SHUTDOWN;
free_page((unsigned long)saa->top);
free_page((unsigned long)saa->bottom);
+ v4l2_device_unregister_subdev(&saa->sd);
kfree(saa);
- go7007_remove(go);
+ video_unregister_device(&go->vdev);
+
+ v4l2_device_put(&go->v4l2_dev);
dev->empress_dev = NULL;
return 0;
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c
index 5af29ff68bfd..4be0fa40a39a 100644
--- a/drivers/staging/media/go7007/snd-go7007.c
+++ b/drivers/staging/media/go7007/snd-go7007.c
@@ -221,8 +221,6 @@ static int go7007_snd_free(struct snd_device *device)
kfree(go->snd_context);
go->snd_context = NULL;
- if (--go->ref_count == 0)
- kfree(go);
return 0;
}
@@ -267,9 +265,9 @@ int go7007_snd_init(struct go7007 *go)
kfree(gosnd);
return ret;
}
- strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
- strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
- strncpy(gosnd->card->longname, gosnd->card->shortname,
+ strlcpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
+ strlcpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
+ strlcpy(gosnd->card->longname, gosnd->card->shortname,
sizeof(gosnd->card->longname));
gosnd->pcm->private_data = go;
@@ -285,8 +283,8 @@ int go7007_snd_init(struct go7007 *go)
gosnd->substream = NULL;
go->snd_context = gosnd;
+ v4l2_device_get(&go->v4l2_dev);
++dev;
- ++go->ref_count;
return 0;
}
@@ -298,6 +296,7 @@ int go7007_snd_remove(struct go7007 *go)
snd_card_disconnect(gosnd->card);
snd_card_free_when_closed(gosnd->card);
+ v4l2_device_put(&go->v4l2_dev);
return 0;
}
EXPORT_SYMBOL(go7007_snd_remove);
diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h
deleted file mode 100644
index 6d09c06c8560..000000000000
--- a/drivers/staging/media/go7007/wis-i2c.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-/* Temporary I2C IDs -- these need to be replaced with real registered IDs */
-#define I2C_DRIVERID_WIS_SAA7115 0xf0f0
-#define I2C_DRIVERID_WIS_UDA1342 0xf0f1
-#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2
-#define I2C_DRIVERID_WIS_TW9903 0xf0f3
-#define I2C_DRIVERID_WIS_SAA7113 0xf0f4
-#define I2C_DRIVERID_WIS_OV7640 0xf0f5
-#define I2C_DRIVERID_WIS_TW2804 0xf0f6
-#define I2C_DRIVERID_S2250 0xf0f7
-
-/* Definitions for new video decoder commands */
-
-struct video_decoder_resolution {
- unsigned int width;
- unsigned int height;
-};
-
-#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution)
-#define DECODER_SET_CHANNEL _IOW('d', 201, int)
-
-/* Sony tuner types */
-
-#define TUNER_SONY_BTF_PG472Z 200
-#define TUNER_SONY_BTF_PK467Z 201
-#define TUNER_SONY_BTF_PB463Z 202
diff --git a/drivers/staging/media/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c
deleted file mode 100644
index 891cde713a47..000000000000
--- a/drivers/staging/media/go7007/wis-saa7113.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_saa7113 {
- int norm;
- int brightness;
- int contrast;
- int saturation;
- int hue;
-};
-
-static u8 initial_registers[] = {
- 0x01, 0x08,
- 0x02, 0xc0,
- 0x03, 0x33,
- 0x04, 0x00,
- 0x05, 0x00,
- 0x06, 0xe9,
- 0x07, 0x0d,
- 0x08, 0xd8,
- 0x09, 0x40,
- 0x0a, 0x80,
- 0x0b, 0x47,
- 0x0c, 0x40,
- 0x0d, 0x00,
- 0x0e, 0x01,
- 0x0f, 0x2a,
- 0x10, 0x40,
- 0x11, 0x0c,
- 0x12, 0xfe,
- 0x13, 0x00,
- 0x14, 0x00,
- 0x15, 0x04,
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1a, 0x00,
- 0x1b, 0x00,
- 0x1c, 0x00,
- 0x1d, 0x00,
- 0x1e, 0x00,
- 0x1f, 0xc8,
- 0x40, 0x00,
- 0x41, 0xff,
- 0x42, 0xff,
- 0x43, 0xff,
- 0x44, 0xff,
- 0x45, 0xff,
- 0x46, 0xff,
- 0x47, 0xff,
- 0x48, 0xff,
- 0x49, 0xff,
- 0x4a, 0xff,
- 0x4b, 0xff,
- 0x4c, 0xff,
- 0x4d, 0xff,
- 0x4e, 0xff,
- 0x4f, 0xff,
- 0x50, 0xff,
- 0x51, 0xff,
- 0x52, 0xff,
- 0x53, 0xff,
- 0x54, 0xff,
- 0x55, 0xff,
- 0x56, 0xff,
- 0x57, 0xff,
- 0x58, 0x00,
- 0x59, 0x54,
- 0x5a, 0x07,
- 0x5b, 0x83,
- 0x5c, 0x00,
- 0x5d, 0x00,
- 0x5e, 0x00,
- 0x5f, 0x00,
- 0x60, 0x00,
- 0x61, 0x00,
- 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
- int i;
-
- for (i = 0; regs[i] != 0x00; i += 2)
- if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
- return -1;
- return 0;
-}
-
-static int wis_saa7113_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct wis_saa7113 *dec = i2c_get_clientdata(client);
-
- switch (cmd) {
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
-
- i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
- i2c_smbus_write_byte_data(client, 0x09,
- *input < 6 ? 0x40 : 0x80);
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *input = arg;
- dec->norm = *input;
- if (dec->norm & V4L2_STD_NTSC) {
- write_reg(client, 0x0e, 0x01);
- write_reg(client, 0x10, 0x40);
- } else if (dec->norm & V4L2_STD_PAL) {
- write_reg(client, 0x0e, 0x01);
- write_reg(client, 0x10, 0x48);
- } else if (dec->norm & V4L2_STD_SECAM) {
- write_reg(client, 0x0e, 0x50);
- write_reg(client, 0x10, 0x48);
- }
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 71;
- ctrl->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 64;
- ctrl->flags = 0;
- break;
- case V4L2_CID_HUE:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
- ctrl->minimum = -128;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 0;
- ctrl->flags = 0;
- break;
- }
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (ctrl->value > 255)
- dec->brightness = 255;
- else if (ctrl->value < 0)
- dec->brightness = 0;
- else
- dec->brightness = ctrl->value;
- write_reg(client, 0x0a, dec->brightness);
- break;
- case V4L2_CID_CONTRAST:
- if (ctrl->value > 127)
- dec->contrast = 127;
- else if (ctrl->value < 0)
- dec->contrast = 0;
- else
- dec->contrast = ctrl->value;
- write_reg(client, 0x0b, dec->contrast);
- break;
- case V4L2_CID_SATURATION:
- if (ctrl->value > 127)
- dec->saturation = 127;
- else if (ctrl->value < 0)
- dec->saturation = 0;
- else
- dec->saturation = ctrl->value;
- write_reg(client, 0x0c, dec->saturation);
- break;
- case V4L2_CID_HUE:
- if (ctrl->value > 127)
- dec->hue = 127;
- else if (ctrl->value < -128)
- dec->hue = -128;
- else
- dec->hue = ctrl->value;
- write_reg(client, 0x0d, dec->hue);
- break;
- }
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dec->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dec->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dec->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dec->hue;
- break;
- }
- break;
- }
- default:
- break;
- }
- return 0;
-}
-
-static int wis_saa7113_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct wis_saa7113 *dec;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL);
- if (dec == NULL)
- return -ENOMEM;
-
- dec->norm = V4L2_STD_NTSC;
- dec->brightness = 128;
- dec->contrast = 71;
- dec->saturation = 64;
- dec->hue = 0;
- i2c_set_clientdata(client, dec);
-
- dev_dbg(&client->dev,
- "wis-saa7113: initializing SAA7113 at address %d on %s\n",
- client->addr, adapter->name);
-
- if (write_regs(client, initial_registers) < 0) {
- dev_err(&client->dev,
- "wis-saa7113: error initializing SAA7113\n");
- kfree(dec);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int wis_saa7113_remove(struct i2c_client *client)
-{
- struct wis_saa7113 *dec = i2c_get_clientdata(client);
-
- kfree(dec);
- return 0;
-}
-
-static const struct i2c_device_id wis_saa7113_id[] = {
- { "wis_saa7113", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_saa7113_id);
-
-static struct i2c_driver wis_saa7113_driver = {
- .driver = {
- .name = "WIS SAA7113 I2C driver",
- },
- .probe = wis_saa7113_probe,
- .remove = wis_saa7113_remove,
- .command = wis_saa7113_command,
- .id_table = wis_saa7113_id,
-};
-
-module_i2c_driver(wis_saa7113_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c
deleted file mode 100644
index fa86acd3fdf0..000000000000
--- a/drivers/staging/media/go7007/wis-saa7115.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_saa7115 {
- int norm;
- int brightness;
- int contrast;
- int saturation;
- int hue;
-};
-
-static u8 initial_registers[] = {
- 0x01, 0x08,
- 0x02, 0xc0,
- 0x03, 0x20,
- 0x04, 0x80,
- 0x05, 0x80,
- 0x06, 0xeb,
- 0x07, 0xe0,
- 0x08, 0xf0, /* always toggle FID */
- 0x09, 0x40,
- 0x0a, 0x80,
- 0x0b, 0x40,
- 0x0c, 0x40,
- 0x0d, 0x00,
- 0x0e, 0x03,
- 0x0f, 0x2a,
- 0x10, 0x0e,
- 0x11, 0x00,
- 0x12, 0x8d,
- 0x13, 0x00,
- 0x14, 0x00,
- 0x15, 0x11,
- 0x16, 0x01,
- 0x17, 0xda,
- 0x18, 0x40,
- 0x19, 0x80,
- 0x1a, 0x00,
- 0x1b, 0x42,
- 0x1c, 0xa9,
- 0x30, 0x66,
- 0x31, 0x90,
- 0x32, 0x01,
- 0x34, 0x00,
- 0x35, 0x00,
- 0x36, 0x20,
- 0x38, 0x03,
- 0x39, 0x20,
- 0x3a, 0x88,
- 0x40, 0x00,
- 0x41, 0xff,
- 0x42, 0xff,
- 0x43, 0xff,
- 0x44, 0xff,
- 0x45, 0xff,
- 0x46, 0xff,
- 0x47, 0xff,
- 0x48, 0xff,
- 0x49, 0xff,
- 0x4a, 0xff,
- 0x4b, 0xff,
- 0x4c, 0xff,
- 0x4d, 0xff,
- 0x4e, 0xff,
- 0x4f, 0xff,
- 0x50, 0xff,
- 0x51, 0xff,
- 0x52, 0xff,
- 0x53, 0xff,
- 0x54, 0xf4 /*0xff*/,
- 0x55, 0xff,
- 0x56, 0xff,
- 0x57, 0xff,
- 0x58, 0x40,
- 0x59, 0x47,
- 0x5a, 0x06 /*0x03*/,
- 0x5b, 0x83,
- 0x5d, 0x06,
- 0x5e, 0x00,
- 0x80, 0x30, /* window defined scaler operation, task A and B enabled */
- 0x81, 0x03, /* use scaler datapath generated V */
- 0x83, 0x00,
- 0x84, 0x00,
- 0x85, 0x00,
- 0x86, 0x45,
- 0x87, 0x31,
- 0x88, 0xc0,
- 0x90, 0x02, /* task A process top field */
- 0x91, 0x08,
- 0x92, 0x09,
- 0x93, 0x80,
- 0x94, 0x06,
- 0x95, 0x00,
- 0x96, 0xc0,
- 0x97, 0x02,
- 0x98, 0x12,
- 0x99, 0x00,
- 0x9a, 0xf2,
- 0x9b, 0x00,
- 0x9c, 0xd0,
- 0x9d, 0x02,
- 0x9e, 0xf2,
- 0x9f, 0x00,
- 0xa0, 0x01,
- 0xa1, 0x01,
- 0xa2, 0x01,
- 0xa4, 0x80,
- 0xa5, 0x40,
- 0xa6, 0x40,
- 0xa8, 0x00,
- 0xa9, 0x04,
- 0xaa, 0x00,
- 0xac, 0x00,
- 0xad, 0x02,
- 0xae, 0x00,
- 0xb0, 0x00,
- 0xb1, 0x04,
- 0xb2, 0x00,
- 0xb3, 0x04,
- 0xb4, 0x00,
- 0xb8, 0x00,
- 0xbc, 0x00,
- 0xc0, 0x03, /* task B process bottom field */
- 0xc1, 0x08,
- 0xc2, 0x09,
- 0xc3, 0x80,
- 0xc4, 0x06,
- 0xc5, 0x00,
- 0xc6, 0xc0,
- 0xc7, 0x02,
- 0xc8, 0x12,
- 0xc9, 0x00,
- 0xca, 0xf2,
- 0xcb, 0x00,
- 0xcc, 0xd0,
- 0xcd, 0x02,
- 0xce, 0xf2,
- 0xcf, 0x00,
- 0xd0, 0x01,
- 0xd1, 0x01,
- 0xd2, 0x01,
- 0xd4, 0x80,
- 0xd5, 0x40,
- 0xd6, 0x40,
- 0xd8, 0x00,
- 0xd9, 0x04,
- 0xda, 0x00,
- 0xdc, 0x00,
- 0xdd, 0x02,
- 0xde, 0x00,
- 0xe0, 0x00,
- 0xe1, 0x04,
- 0xe2, 0x00,
- 0xe3, 0x04,
- 0xe4, 0x00,
- 0xe8, 0x00,
- 0x88, 0xf0, /* End of original static list */
- 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
- int i;
-
- for (i = 0; regs[i] != 0x00; i += 2)
- if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
- return -1;
- return 0;
-}
-
-static int wis_saa7115_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct wis_saa7115 *dec = i2c_get_clientdata(client);
-
- switch (cmd) {
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
-
- i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
- i2c_smbus_write_byte_data(client, 0x09,
- *input < 6 ? 0x40 : 0xC0);
- break;
- }
- case DECODER_SET_RESOLUTION:
- {
- struct video_decoder_resolution *res = arg;
- /* Course-grained scaler */
- int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
- /* Fine-grained scaler to take care of remainder */
- int h_scaling_increment = (704 / h_integer_scaler) *
- 1024 / res->width;
- /* Fine-grained scaler only */
- int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
- 240 : 288) * 1024 / res->height;
- u8 regs[] = {
- 0x88, 0xc0,
- 0x9c, res->width & 0xff,
- 0x9d, res->width >> 8,
- 0x9e, res->height & 0xff,
- 0x9f, res->height >> 8,
- 0xa0, h_integer_scaler,
- 0xa1, 1,
- 0xa2, 1,
- 0xa8, h_scaling_increment & 0xff,
- 0xa9, h_scaling_increment >> 8,
- 0xac, (h_scaling_increment / 2) & 0xff,
- 0xad, (h_scaling_increment / 2) >> 8,
- 0xb0, v_scaling_increment & 0xff,
- 0xb1, v_scaling_increment >> 8,
- 0xb2, v_scaling_increment & 0xff,
- 0xb3, v_scaling_increment >> 8,
- 0xcc, res->width & 0xff,
- 0xcd, res->width >> 8,
- 0xce, res->height & 0xff,
- 0xcf, res->height >> 8,
- 0xd0, h_integer_scaler,
- 0xd1, 1,
- 0xd2, 1,
- 0xd8, h_scaling_increment & 0xff,
- 0xd9, h_scaling_increment >> 8,
- 0xdc, (h_scaling_increment / 2) & 0xff,
- 0xdd, (h_scaling_increment / 2) >> 8,
- 0xe0, v_scaling_increment & 0xff,
- 0xe1, v_scaling_increment >> 8,
- 0xe2, v_scaling_increment & 0xff,
- 0xe3, v_scaling_increment >> 8,
- 0x88, 0xf0,
- 0, 0,
- };
- write_regs(client, regs);
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *input = arg;
- u8 regs[] = {
- 0x88, 0xc0,
- 0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
- 0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
- 0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
- 0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
- 0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
- 0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
- 0x88, 0xf0,
- 0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00,
- 0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
- 0, 0,
- };
- write_regs(client, regs);
- dec->norm = *input;
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 64;
- ctrl->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 64;
- ctrl->flags = 0;
- break;
- case V4L2_CID_HUE:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
- ctrl->minimum = -128;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 0;
- ctrl->flags = 0;
- break;
- }
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (ctrl->value > 255)
- dec->brightness = 255;
- else if (ctrl->value < 0)
- dec->brightness = 0;
- else
- dec->brightness = ctrl->value;
- write_reg(client, 0x0a, dec->brightness);
- break;
- case V4L2_CID_CONTRAST:
- if (ctrl->value > 127)
- dec->contrast = 127;
- else if (ctrl->value < 0)
- dec->contrast = 0;
- else
- dec->contrast = ctrl->value;
- write_reg(client, 0x0b, dec->contrast);
- break;
- case V4L2_CID_SATURATION:
- if (ctrl->value > 127)
- dec->saturation = 127;
- else if (ctrl->value < 0)
- dec->saturation = 0;
- else
- dec->saturation = ctrl->value;
- write_reg(client, 0x0c, dec->saturation);
- break;
- case V4L2_CID_HUE:
- if (ctrl->value > 127)
- dec->hue = 127;
- else if (ctrl->value < -128)
- dec->hue = -128;
- else
- dec->hue = ctrl->value;
- write_reg(client, 0x0d, dec->hue);
- break;
- }
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dec->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dec->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dec->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dec->hue;
- break;
- }
- break;
- }
- default:
- break;
- }
- return 0;
-}
-
-static int wis_saa7115_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct wis_saa7115 *dec;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
- if (dec == NULL)
- return -ENOMEM;
-
- dec->norm = V4L2_STD_NTSC;
- dec->brightness = 128;
- dec->contrast = 64;
- dec->saturation = 64;
- dec->hue = 0;
- i2c_set_clientdata(client, dec);
-
- dev_dbg(&client->dev,
- "wis-saa7115: initializing SAA7115 at address %d on %s\n",
- client->addr, adapter->name);
-
- if (write_regs(client, initial_registers) < 0) {
- dev_err(&client->dev,
- "wis-saa7115: error initializing SAA7115\n");
- kfree(dec);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int wis_saa7115_remove(struct i2c_client *client)
-{
- struct wis_saa7115 *dec = i2c_get_clientdata(client);
-
- kfree(dec);
- return 0;
-}
-
-static const struct i2c_device_id wis_saa7115_id[] = {
- { "wis_saa7115", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_saa7115_id);
-
-static struct i2c_driver wis_saa7115_driver = {
- .driver = {
- .name = "WIS SAA7115 I2C driver",
- },
- .probe = wis_saa7115_probe,
- .remove = wis_saa7115_remove,
- .command = wis_saa7115_command,
- .id_table = wis_saa7115_id,
-};
-
-module_i2c_driver(wis_saa7115_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c
deleted file mode 100644
index 5d7ff8c81d6d..000000000000
--- a/drivers/staging/media/go7007/wis-sony-tuner.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/tuner.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "wis-i2c.h"
-
-/* #define MPX_DEBUG */
-
-/* AS(IF/MPX) pin: LOW HIGH/OPEN
- * IF/MPX address: 0x42/0x40 0x43/0x44
- */
-#define IF_I2C_ADDR 0x43
-#define MPX_I2C_ADDR 0x44
-
-static v4l2_std_id force_band;
-static char force_band_str[] = "-";
-module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
-static int force_mpx_mode = -1;
-module_param(force_mpx_mode, int, 0644);
-
-/* Store tuner info in the same format as tuner.c, so maybe we can put the
- * Sony tuner support in there. */
-struct sony_tunertype {
- char *name;
- unsigned char Vendor; /* unused here */
- unsigned char Type; /* unused here */
-
- unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */
- unsigned short thresh2; /* band switch VHF_HI <=> UHF */
- unsigned char VHF_L;
- unsigned char VHF_H;
- unsigned char UHF;
- unsigned char config;
- unsigned short IFPCoff;
-};
-
-/* This array is indexed by (tuner_type - 200) */
-static struct sony_tunertype sony_tuners[] = {
- { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
- 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
- { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
- 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
- { "Sony NTSC (BTF-PB463Z)", 0, 0,
- 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
-};
-
-struct wis_sony_tuner {
- int type;
- v4l2_std_id std;
- unsigned int freq;
- int mpxmode;
- u32 audmode;
-};
-
-/* Basically the same as default_set_tv_freq() in tuner.c */
-static int set_freq(struct i2c_client *client, int freq)
-{
- struct wis_sony_tuner *t = i2c_get_clientdata(client);
- char *band_name;
- int n;
- int band_select;
- struct sony_tunertype *tun;
- u8 buffer[4];
-
- tun = &sony_tuners[t->type - 200];
- if (freq < tun->thresh1) {
- band_name = "VHF_L";
- band_select = tun->VHF_L;
- } else if (freq < tun->thresh2) {
- band_name = "VHF_H";
- band_select = tun->VHF_H;
- } else {
- band_name = "UHF";
- band_select = tun->UHF;
- }
- dev_dbg(&client->dev, "tuning to frequency %d.%04d (%s)\n",
- freq / 16, (freq % 16) * 625, band_name);
- n = freq + tun->IFPCoff;
-
- buffer[0] = n >> 8;
- buffer[1] = n & 0xff;
- buffer[2] = tun->config;
- buffer[3] = band_select;
- i2c_master_send(client, buffer, 4);
-
- return 0;
-}
-
-static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
-{
- u8 buffer[5];
- struct i2c_msg msg;
-
- buffer[0] = dev;
- buffer[1] = addr >> 8;
- buffer[2] = addr & 0xff;
- buffer[3] = val >> 8;
- buffer[4] = val & 0xff;
- msg.addr = MPX_I2C_ADDR;
- msg.flags = 0;
- msg.len = 5;
- msg.buf = buffer;
- i2c_transfer(client->adapter, &msg, 1);
- return 0;
-}
-
-/*
- * MPX register values for the BTF-PG472Z:
- *
- * FM_ NICAM_ SCART_
- * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
- * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
- * ---------------------------------------------------------------
- * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
- *
- * B/G
- * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
- * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
- * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
- *
- * I
- * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
- * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
- *
- * D/K
- * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
- * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
- * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
- * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
- * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
- *
- * L/L'
- * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
- * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
- *
- * M
- * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
- *
- * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
- *
- * Bilingual selection in A2/NICAM:
- *
- * High byte of SOURCE Left chan Right chan
- * 0x01 MAIN SUB
- * 0x03 MAIN MAIN
- * 0x04 SUB SUB
- *
- * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
- * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
- *
- * FMONO_A2
- * 10/0022
- * --------
- * Forced mono ON 07F0
- * Forced mono OFF 0190
- */
-
-static struct {
- enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
- u16 modus;
- u16 source;
- u16 acb;
- u16 fm_prescale;
- u16 nicam_prescale;
- u16 scart_prescale;
- u16 system;
- u16 volume;
-} mpx_audio_modes[] = {
- /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
- 0x5000, 0x0000, 0x0001, 0x7500 },
- /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
- 0x5000, 0x0000, 0x0003, 0x7500 },
- /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
- 0x5000, 0x0000, 0x0003, 0x7500 },
- /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
- 0x5000, 0x0000, 0x0008, 0x7500 },
- /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
- 0x7900, 0x0000, 0x000A, 0x7500 },
- /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
- 0x7900, 0x0000, 0x000A, 0x7500 },
- /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
- 0x5000, 0x0000, 0x0004, 0x7500 },
- /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
- 0x5000, 0x0000, 0x0004, 0x7500 },
- /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
- 0x5000, 0x0000, 0x0005, 0x7500 },
- /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
- 0x5000, 0x0000, 0x0007, 0x7500 },
- /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
- 0x5000, 0x0000, 0x000B, 0x7500 },
- /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
- 0x5000, 0x2200, 0x0009, 0x7500 },
- /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
- 0x5000, 0x0000, 0x0009, 0x7500 },
-};
-
-#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
-
-static int mpx_setup(struct i2c_client *client)
-{
- struct wis_sony_tuner *t = i2c_get_clientdata(client);
- u16 source = 0;
- u8 buffer[3];
- struct i2c_msg msg;
-
- /* reset MPX */
- buffer[0] = 0x00;
- buffer[1] = 0x80;
- buffer[2] = 0x00;
- msg.addr = MPX_I2C_ADDR;
- msg.flags = 0;
- msg.len = 3;
- msg.buf = buffer;
- i2c_transfer(client->adapter, &msg, 1);
- buffer[1] = 0x00;
- i2c_transfer(client->adapter, &msg, 1);
-
- if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
- switch (t->audmode) {
- case V4L2_TUNER_MODE_MONO:
- switch (mpx_audio_modes[t->mpxmode].audio_mode) {
- case AUD_A2:
- source = mpx_audio_modes[t->mpxmode].source;
- break;
- case AUD_NICAM:
- source = 0x0000;
- break;
- case AUD_NICAM_L:
- source = 0x0200;
- break;
- default:
- break;
- }
- break;
- case V4L2_TUNER_MODE_STEREO:
- source = mpx_audio_modes[t->mpxmode].source;
- break;
- case V4L2_TUNER_MODE_LANG1:
- source = 0x0300;
- break;
- case V4L2_TUNER_MODE_LANG2:
- source = 0x0400;
- break;
- }
- source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
- } else
- source = mpx_audio_modes[t->mpxmode].source;
-
- mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
- mpx_write(client, 0x12, 0x0008, source);
- mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
- mpx_write(client, 0x12, 0x000e,
- mpx_audio_modes[t->mpxmode].fm_prescale);
- mpx_write(client, 0x12, 0x0010,
- mpx_audio_modes[t->mpxmode].nicam_prescale);
- mpx_write(client, 0x12, 0x000d,
- mpx_audio_modes[t->mpxmode].scart_prescale);
- mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
- mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
- if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
- mpx_write(client, 0x10, 0x0022,
- t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
-
-#ifdef MPX_DEBUG
- {
- u8 buf1[3], buf2[2];
- struct i2c_msg msgs[2];
-
- dev_dbg(&client->dev,
- "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n",
- mpx_audio_modes[t->mpxmode].modus,
- source,
- mpx_audio_modes[t->mpxmode].acb,
- mpx_audio_modes[t->mpxmode].fm_prescale,
- mpx_audio_modes[t->mpxmode].nicam_prescale,
- mpx_audio_modes[t->mpxmode].scart_prescale,
- mpx_audio_modes[t->mpxmode].system,
- mpx_audio_modes[t->mpxmode].volume);
- buf1[0] = 0x11;
- buf1[1] = 0x00;
- buf1[2] = 0x7e;
- msgs[0].addr = MPX_I2C_ADDR;
- msgs[0].flags = 0;
- msgs[0].len = 3;
- msgs[0].buf = buf1;
- msgs[1].addr = MPX_I2C_ADDR;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = 2;
- msgs[1].buf = buf2;
- i2c_transfer(client->adapter, msgs, 2);
- dev_dbg(&client->dev, "MPX system: %02x%02x\n",
- buf2[0], buf2[1]);
- buf1[0] = 0x11;
- buf1[1] = 0x02;
- buf1[2] = 0x00;
- i2c_transfer(client->adapter, msgs, 2);
- dev_dbg(&client->dev, "MPX status: %02x%02x\n",
- buf2[0], buf2[1]);
- }
-#endif
- return 0;
-}
-
-/*
- * IF configuration values for the BTF-PG472Z:
- *
- * B/G: 0x94 0x70 0x49
- * I: 0x14 0x70 0x4a
- * D/K: 0x14 0x70 0x4b
- * L: 0x04 0x70 0x4b
- * L': 0x44 0x70 0x53
- * M: 0x50 0x30 0x4c
- */
-
-static int set_if(struct i2c_client *client)
-{
- struct wis_sony_tuner *t = i2c_get_clientdata(client);
- u8 buffer[4];
- struct i2c_msg msg;
- int default_mpx_mode = 0;
-
- /* configure IF */
- buffer[0] = 0;
- if (t->std & V4L2_STD_PAL_BG) {
- buffer[1] = 0x94;
- buffer[2] = 0x70;
- buffer[3] = 0x49;
- default_mpx_mode = 1;
- } else if (t->std & V4L2_STD_PAL_I) {
- buffer[1] = 0x14;
- buffer[2] = 0x70;
- buffer[3] = 0x4a;
- default_mpx_mode = 4;
- } else if (t->std & V4L2_STD_PAL_DK) {
- buffer[1] = 0x14;
- buffer[2] = 0x70;
- buffer[3] = 0x4b;
- default_mpx_mode = 6;
- } else if (t->std & V4L2_STD_SECAM_L) {
- buffer[1] = 0x04;
- buffer[2] = 0x70;
- buffer[3] = 0x4b;
- default_mpx_mode = 11;
- }
- msg.addr = IF_I2C_ADDR;
- msg.flags = 0;
- msg.len = 4;
- msg.buf = buffer;
- i2c_transfer(client->adapter, &msg, 1);
-
- /* Select MPX mode if not forced by the user */
- if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES)
- t->mpxmode = force_mpx_mode;
- else
- t->mpxmode = default_mpx_mode;
- dev_dbg(&client->dev, "setting MPX to mode %d\n", t->mpxmode);
- mpx_setup(client);
-
- return 0;
-}
-
-static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
- struct wis_sony_tuner *t = i2c_get_clientdata(client);
-
- switch (cmd) {
-#if 0
-#ifdef TUNER_SET_TYPE_ADDR
- case TUNER_SET_TYPE_ADDR:
- {
- struct tuner_setup *tun_setup = arg;
- int *type = &tun_setup->type;
-#else
- case TUNER_SET_TYPE:
- {
- int *type = arg;
-#endif
-
- if (t->type >= 0) {
- if (t->type != *type)
- dev_err(&client->dev,
- "type already set to %d, ignoring request for %d\n",
- t->type, *type);
- break;
- }
- t->type = *type;
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- switch (force_band_str[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- dev_info(&client->dev,
- "forcing tuner to PAL-B/G bands\n");
- force_band = V4L2_STD_PAL_BG;
- break;
- case 'i':
- case 'I':
- dev_info(&client->dev,
- "forcing tuner to PAL-I band\n");
- force_band = V4L2_STD_PAL_I;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- dev_info(&client->dev,
- "forcing tuner to PAL-D/K bands\n");
- force_band = V4L2_STD_PAL_I;
- break;
- case 'l':
- case 'L':
- dev_info(&client->dev,
- "forcing tuner to SECAM-L band\n");
- force_band = V4L2_STD_SECAM_L;
- break;
- default:
- force_band = 0;
- break;
- }
- if (force_band)
- t->std = force_band;
- else
- t->std = V4L2_STD_PAL_BG;
- set_if(client);
- break;
- case TUNER_SONY_BTF_PK467Z:
- t->std = V4L2_STD_NTSC_M_JP;
- break;
- case TUNER_SONY_BTF_PB463Z:
- t->std = V4L2_STD_NTSC_M;
- break;
- default:
- dev_err(&client->dev,
- "tuner type %d is not supported by this module\n",
- *type);
- break;
- }
- if (type >= 0)
- dev_info(&clinet->dev,
- "type set to %d (%s)\n",
- t->type, sony_tuners[t->type - 200].name);
- break;
- }
-#endif
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- f->frequency = t->freq;
- break;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- t->freq = f->frequency;
- set_freq(client, t->freq);
- break;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *std = arg;
-
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- switch (std->index) {
- case 0:
- v4l2_video_std_construct(std,
- V4L2_STD_PAL_BG, "PAL-B/G");
- break;
- case 1:
- v4l2_video_std_construct(std,
- V4L2_STD_PAL_I, "PAL-I");
- break;
- case 2:
- v4l2_video_std_construct(std,
- V4L2_STD_PAL_DK, "PAL-D/K");
- break;
- case 3:
- v4l2_video_std_construct(std,
- V4L2_STD_SECAM_L, "SECAM-L");
- break;
- default:
- std->id = 0; /* hack to indicate EINVAL */
- break;
- }
- break;
- case TUNER_SONY_BTF_PK467Z:
- if (std->index != 0) {
- std->id = 0; /* hack to indicate EINVAL */
- break;
- }
- v4l2_video_std_construct(std,
- V4L2_STD_NTSC_M_JP, "NTSC-J");
- break;
- case TUNER_SONY_BTF_PB463Z:
- if (std->index != 0) {
- std->id = 0; /* hack to indicate EINVAL */
- break;
- }
- v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
- break;
- }
- break;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *std = arg;
-
- *std = t->std;
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *std = arg;
- v4l2_std_id old = t->std;
-
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- if (force_band && (*std & force_band) != *std &&
- *std != V4L2_STD_PAL &&
- *std != V4L2_STD_SECAM) {
- dev_dbg(&client->dev,
- "ignoring requested TV standard in favor of force_band value\n");
- t->std = force_band;
- } else if (*std & V4L2_STD_PAL_BG) { /* default */
- t->std = V4L2_STD_PAL_BG;
- } else if (*std & V4L2_STD_PAL_I) {
- t->std = V4L2_STD_PAL_I;
- } else if (*std & V4L2_STD_PAL_DK) {
- t->std = V4L2_STD_PAL_DK;
- } else if (*std & V4L2_STD_SECAM_L) {
- t->std = V4L2_STD_SECAM_L;
- } else {
- dev_err(&client->dev,
- "TV standard not supported\n");
- *std = 0; /* hack to indicate EINVAL */
- break;
- }
- if (old != t->std)
- set_if(client);
- break;
- case TUNER_SONY_BTF_PK467Z:
- if (!(*std & V4L2_STD_NTSC_M_JP)) {
- dev_err(&client->dev,
- "TV standard not supported\n");
- *std = 0; /* hack to indicate EINVAL */
- }
- break;
- case TUNER_SONY_BTF_PB463Z:
- if (!(*std & V4L2_STD_NTSC_M)) {
- dev_err(&client->dev,
- "TV standard not supported\n");
- *std = 0; /* hack to indicate EINVAL */
- }
- break;
- }
- break;
- }
- case VIDIOC_QUERYSTD:
- {
- v4l2_std_id *std = arg;
-
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- if (force_band)
- *std = force_band;
- else
- *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
- V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
- break;
- case TUNER_SONY_BTF_PK467Z:
- *std = V4L2_STD_NTSC_M_JP;
- break;
- case TUNER_SONY_BTF_PB463Z:
- *std = V4L2_STD_NTSC_M;
- break;
- }
- break;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *tun = arg;
-
- memset(tun, 0, sizeof(*tun));
- strcpy(tun->name, "Television");
- tun->type = V4L2_TUNER_ANALOG_TV;
- tun->rangelow = 0UL; /* does anything use these? */
- tun->rangehigh = 0xffffffffUL;
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- tun->capability = V4L2_TUNER_CAP_NORM |
- V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2;
- tun->rxsubchans = V4L2_TUNER_SUB_MONO |
- V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2;
- break;
- case TUNER_SONY_BTF_PK467Z:
- case TUNER_SONY_BTF_PB463Z:
- tun->capability = V4L2_TUNER_CAP_STEREO;
- tun->rxsubchans = V4L2_TUNER_SUB_MONO |
- V4L2_TUNER_SUB_STEREO;
- break;
- }
- tun->audmode = t->audmode;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *tun = arg;
-
- switch (t->type) {
- case TUNER_SONY_BTF_PG472Z:
- if (tun->audmode != t->audmode) {
- t->audmode = tun->audmode;
- mpx_setup(client);
- }
- break;
- case TUNER_SONY_BTF_PK467Z:
- case TUNER_SONY_BTF_PB463Z:
- break;
- }
- return 0;
- }
- default:
- break;
- }
- return 0;
-}
-
-static int wis_sony_tuner_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct wis_sony_tuner *t;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
- return -ENODEV;
-
- t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
- if (t == NULL)
- return -ENOMEM;
-
- t->type = -1;
- t->freq = 0;
- t->mpxmode = 0;
- t->audmode = V4L2_TUNER_MODE_STEREO;
- i2c_set_clientdata(client, t);
-
- dev_dbg(&client->dev, "initializing tuner at address %d on %s\n",
- client->addr, adapter->name);
-
- return 0;
-}
-
-static int wis_sony_tuner_remove(struct i2c_client *client)
-{
- struct wis_sony_tuner *t = i2c_get_clientdata(client);
-
- kfree(t);
- return 0;
-}
-
-static const struct i2c_device_id wis_sony_tuner_id[] = {
- { "wis_sony_tuner", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id);
-
-static struct i2c_driver wis_sony_tuner_driver = {
- .driver = {
- .name = "WIS Sony TV Tuner I2C driver",
- },
- .probe = wis_sony_tuner_probe,
- .remove = wis_sony_tuner_remove,
- .command = tuner_command,
- .id_table = wis_sony_tuner_id,
-};
-
-module_i2c_driver(wis_sony_tuner_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c
deleted file mode 100644
index 290fd8c7bfef..000000000000
--- a/drivers/staging/media/go7007/wis-tw2804.c
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_tw2804 {
- int channel;
- int norm;
- int brightness;
- int contrast;
- int saturation;
- int hue;
-};
-
-static u8 global_registers[] = {
- 0x39, 0x00,
- 0x3a, 0xff,
- 0x3b, 0x84,
- 0x3c, 0x80,
- 0x3d, 0x80,
- 0x3e, 0x82,
- 0x3f, 0x82,
- 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
-};
-
-static u8 channel_registers[] = {
- 0x01, 0xc4,
- 0x02, 0xa5,
- 0x03, 0x20,
- 0x04, 0xd0,
- 0x05, 0x20,
- 0x06, 0xd0,
- 0x07, 0x88,
- 0x08, 0x20,
- 0x09, 0x07,
- 0x0a, 0xf0,
- 0x0b, 0x07,
- 0x0c, 0xf0,
- 0x0d, 0x40,
- 0x0e, 0xd2,
- 0x0f, 0x80,
- 0x10, 0x80,
- 0x11, 0x80,
- 0x12, 0x80,
- 0x13, 0x1f,
- 0x14, 0x00,
- 0x15, 0x00,
- 0x16, 0x00,
- 0x17, 0x00,
- 0x18, 0xff,
- 0x19, 0xff,
- 0x1a, 0xff,
- 0x1b, 0xff,
- 0x1c, 0xff,
- 0x1d, 0xff,
- 0x1e, 0xff,
- 0x1f, 0xff,
- 0x20, 0x07,
- 0x21, 0x07,
- 0x22, 0x00,
- 0x23, 0x91,
- 0x24, 0x51,
- 0x25, 0x03,
- 0x26, 0x00,
- 0x27, 0x00,
- 0x28, 0x00,
- 0x29, 0x00,
- 0x2a, 0x00,
- 0x2b, 0x00,
- 0x2c, 0x00,
- 0x2d, 0x00,
- 0x2e, 0x00,
- 0x2f, 0x00,
- 0x30, 0x00,
- 0x31, 0x00,
- 0x32, 0x00,
- 0x33, 0x00,
- 0x34, 0x00,
- 0x35, 0x00,
- 0x36, 0x00,
- 0x37, 0x00,
- 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
-{
- return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs, int channel)
-{
- int i;
-
- for (i = 0; regs[i] != 0xff; i += 2)
- if (i2c_smbus_write_byte_data(client,
- regs[i] | (channel << 6), regs[i + 1]) < 0)
- return -1;
- return 0;
-}
-
-static int wis_tw2804_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct wis_tw2804 *dec = i2c_get_clientdata(client);
-
- if (cmd == DECODER_SET_CHANNEL) {
- int *input = arg;
-
- if (*input < 0 || *input > 3) {
- dev_err(&client->dev,
- "channel %d is not between 0 and 3!\n", *input);
- return 0;
- }
- dec->channel = *input;
- dev_dbg(&client->dev, "initializing TW2804 channel %d\n",
- dec->channel);
- if (dec->channel == 0 &&
- write_regs(client, global_registers, 0) < 0) {
- dev_err(&client->dev,
- "error initializing TW2804 global registers\n");
- return 0;
- }
- if (write_regs(client, channel_registers, dec->channel) < 0) {
- dev_err(&client->dev,
- "error initializing TW2804 channel %d\n",
- dec->channel);
- return 0;
- }
- return 0;
- }
-
- if (dec->channel < 0) {
- dev_dbg(&client->dev,
- "ignoring command %08x until channel number is set\n",
- cmd);
- return 0;
- }
-
- switch (cmd) {
- case VIDIOC_S_STD:
- {
- v4l2_std_id *input = arg;
- u8 regs[] = {
- 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
- 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
- 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
- 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
- 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
- 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
- 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
- 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
- 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
- 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
- 0xff, 0xff,
- };
- write_regs(client, regs, dec->channel);
- dec->norm = *input;
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- case V4L2_CID_HUE:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 128;
- ctrl->flags = 0;
- break;
- }
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (ctrl->value > 255)
- dec->brightness = 255;
- else if (ctrl->value < 0)
- dec->brightness = 0;
- else
- dec->brightness = ctrl->value;
- write_reg(client, 0x12, dec->brightness, dec->channel);
- break;
- case V4L2_CID_CONTRAST:
- if (ctrl->value > 255)
- dec->contrast = 255;
- else if (ctrl->value < 0)
- dec->contrast = 0;
- else
- dec->contrast = ctrl->value;
- write_reg(client, 0x11, dec->contrast, dec->channel);
- break;
- case V4L2_CID_SATURATION:
- if (ctrl->value > 255)
- dec->saturation = 255;
- else if (ctrl->value < 0)
- dec->saturation = 0;
- else
- dec->saturation = ctrl->value;
- write_reg(client, 0x10, dec->saturation, dec->channel);
- break;
- case V4L2_CID_HUE:
- if (ctrl->value > 255)
- dec->hue = 255;
- else if (ctrl->value < 0)
- dec->hue = 0;
- else
- dec->hue = ctrl->value;
- write_reg(client, 0x0f, dec->hue, dec->channel);
- break;
- }
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dec->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dec->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dec->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dec->hue;
- break;
- }
- break;
- }
- default:
- break;
- }
- return 0;
-}
-
-static int wis_tw2804_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct wis_tw2804 *dec;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
- if (dec == NULL)
- return -ENOMEM;
-
- dec->channel = -1;
- dec->norm = V4L2_STD_NTSC;
- dec->brightness = 128;
- dec->contrast = 128;
- dec->saturation = 128;
- dec->hue = 128;
- i2c_set_clientdata(client, dec);
-
- dev_dbg(&client->dev, "creating TW2804 at address %d on %s\n",
- client->addr, adapter->name);
-
- return 0;
-}
-
-static int wis_tw2804_remove(struct i2c_client *client)
-{
- struct wis_tw2804 *dec = i2c_get_clientdata(client);
-
- kfree(dec);
- return 0;
-}
-
-static const struct i2c_device_id wis_tw2804_id[] = {
- { "wis_tw2804", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_tw2804_id);
-
-static struct i2c_driver wis_tw2804_driver = {
- .driver = {
- .name = "WIS TW2804 I2C driver",
- },
- .probe = wis_tw2804_probe,
- .remove = wis_tw2804_remove,
- .command = wis_tw2804_command,
- .id_table = wis_tw2804_id,
-};
-
-module_i2c_driver(wis_tw2804_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c
deleted file mode 100644
index 684ca37f0382..000000000000
--- a/drivers/staging/media/go7007/wis-tw9903.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Micronas USA Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-
-#include "wis-i2c.h"
-
-struct wis_tw9903 {
- int norm;
- int brightness;
- int contrast;
- int hue;
-};
-
-static u8 initial_registers[] = {
- 0x02, 0x44, /* input 1, composite */
- 0x03, 0x92, /* correct digital format */
- 0x04, 0x00,
- 0x05, 0x80, /* or 0x00 for PAL */
- 0x06, 0x40, /* second internal current reference */
- 0x07, 0x02, /* window */
- 0x08, 0x14, /* window */
- 0x09, 0xf0, /* window */
- 0x0a, 0x81, /* window */
- 0x0b, 0xd0, /* window */
- 0x0c, 0x8c,
- 0x0d, 0x00, /* scaling */
- 0x0e, 0x11, /* scaling */
- 0x0f, 0x00, /* scaling */
- 0x10, 0x00, /* brightness */
- 0x11, 0x60, /* contrast */
- 0x12, 0x01, /* sharpness */
- 0x13, 0x7f, /* U gain */
- 0x14, 0x5a, /* V gain */
- 0x15, 0x00, /* hue */
- 0x16, 0xc3, /* sharpness */
- 0x18, 0x00,
- 0x19, 0x58, /* vbi */
- 0x1a, 0x80,
- 0x1c, 0x0f, /* video norm */
- 0x1d, 0x7f, /* video norm */
- 0x20, 0xa0, /* clamping gain (working 0x50) */
- 0x21, 0x22,
- 0x22, 0xf0,
- 0x23, 0xfe,
- 0x24, 0x3c,
- 0x25, 0x38,
- 0x26, 0x44,
- 0x27, 0x20,
- 0x28, 0x00,
- 0x29, 0x15,
- 0x2a, 0xa0,
- 0x2b, 0x44,
- 0x2c, 0x37,
- 0x2d, 0x00,
- 0x2e, 0xa5, /* burst PLL control (working: a9) */
- 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */
- 0x31, 0x00,
- 0x33, 0x22,
- 0x34, 0x11,
- 0x35, 0x35,
- 0x3b, 0x05,
- 0x06, 0xc0, /* reset device */
- 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
-};
-
-static int write_reg(struct i2c_client *client, u8 reg, u8 value)
-{
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-static int write_regs(struct i2c_client *client, u8 *regs)
-{
- int i;
-
- for (i = 0; regs[i] != 0x00; i += 2)
- if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
- return -1;
- return 0;
-}
-
-static int wis_tw9903_command(struct i2c_client *client,
- unsigned int cmd, void *arg)
-{
- struct wis_tw9903 *dec = i2c_get_clientdata(client);
-
- switch (cmd) {
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
-
- i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1));
- break;
- }
-#if 0
- /* The scaler on this thing seems to be horribly broken */
- case DECODER_SET_RESOLUTION:
- {
- struct video_decoder_resolution *res = arg;
- /*int hscale = 256 * 720 / res->width;*/
- int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8));
- int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288)
- / res->height;
- u8 regs[] = {
- 0x0d, vscale & 0xff,
- 0x0f, hscale & 0xff,
- 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8),
- 0x06, 0xc0, /* reset device */
- 0, 0,
- };
- dev_dbg(&client->dev, "vscale is %04x, hscale is %04x\n",
- vscale, hscale);
- /*write_regs(client, regs);*/
- break;
- }
-#endif
- case VIDIOC_S_STD:
- {
- v4l2_std_id *input = arg;
- u8 regs[] = {
- 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00,
- 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12,
- 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18,
- 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
- 0, 0,
- };
- write_regs(client, regs);
- dec->norm = *input;
- break;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
- ctrl->minimum = -128;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 0x00;
- ctrl->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 255;
- ctrl->step = 1;
- ctrl->default_value = 0x60;
- ctrl->flags = 0;
- break;
-#if 0
- /* I don't understand how the Chroma Gain registers work... */
- case V4L2_CID_SATURATION:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
- ctrl->minimum = 0;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 64;
- ctrl->flags = 0;
- break;
-#endif
- case V4L2_CID_HUE:
- ctrl->type = V4L2_CTRL_TYPE_INTEGER;
- strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
- ctrl->minimum = -128;
- ctrl->maximum = 127;
- ctrl->step = 1;
- ctrl->default_value = 0;
- ctrl->flags = 0;
- break;
- }
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (ctrl->value > 127)
- dec->brightness = 127;
- else if (ctrl->value < -128)
- dec->brightness = -128;
- else
- dec->brightness = ctrl->value;
- write_reg(client, 0x10, dec->brightness);
- break;
- case V4L2_CID_CONTRAST:
- if (ctrl->value > 255)
- dec->contrast = 255;
- else if (ctrl->value < 0)
- dec->contrast = 0;
- else
- dec->contrast = ctrl->value;
- write_reg(client, 0x11, dec->contrast);
- break;
-#if 0
- case V4L2_CID_SATURATION:
- if (ctrl->value > 127)
- dec->saturation = 127;
- else if (ctrl->value < 0)
- dec->saturation = 0;
- else
- dec->saturation = ctrl->value;
- /*write_reg(client, 0x0c, dec->saturation);*/
- break;
-#endif
- case V4L2_CID_HUE:
- if (ctrl->value > 127)
- dec->hue = 127;
- else if (ctrl->value < -128)
- dec->hue = -128;
- else
- dec->hue = ctrl->value;
- write_reg(client, 0x15, dec->hue);
- break;
- }
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dec->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dec->contrast;
- break;
-#if 0
- case V4L2_CID_SATURATION:
- ctrl->value = dec->saturation;
- break;
-#endif
- case V4L2_CID_HUE:
- ctrl->value = dec->hue;
- break;
- }
- break;
- }
- default:
- break;
- }
- return 0;
-}
-
-static int wis_tw9903_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct i2c_adapter *adapter = client->adapter;
- struct wis_tw9903 *dec;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -ENODEV;
-
- dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL);
- if (dec == NULL)
- return -ENOMEM;
-
- dec->norm = V4L2_STD_NTSC;
- dec->brightness = 0;
- dec->contrast = 0x60;
- dec->hue = 0;
- i2c_set_clientdata(client, dec);
-
- dev_dbg(&client->dev, "initializing TW9903 at address %d on %s\n",
- client->addr, adapter->name);
-
- if (write_regs(client, initial_registers) < 0) {
- dev_err(&client->dev, "error initializing TW9903\n");
- kfree(dec);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int wis_tw9903_remove(struct i2c_client *client)
-{
- struct wis_tw9903 *dec = i2c_get_clientdata(client);
-
- kfree(dec);
- return 0;
-}
-
-static const struct i2c_device_id wis_tw9903_id[] = {
- { "wis_tw9903", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wis_tw9903_id);
-
-static struct i2c_driver wis_tw9903_driver = {
- .driver = {
- .name = "WIS TW9903 I2C driver",
- },
- .probe = wis_tw9903_probe,
- .remove = wis_tw9903_remove,
- .command = wis_tw9903_command,
- .id_table = wis_tw9903_id,
-};
-
-module_i2c_driver(wis_tw9903_driver);
-
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c
index 63a554c36f75..f781c532b3c4 100644
--- a/drivers/staging/media/lirc/lirc_sir.c
+++ b/drivers/staging/media/lirc/lirc_sir.c
@@ -787,12 +787,6 @@ static int init_hardware(void)
spin_lock_irqsave(&hardware_lock, flags);
/* reset UART */
#ifdef LIRC_ON_SA1100
-#ifdef CONFIG_SA1100_BITSY
- if (machine_is_bitsy()) {
- pr_info("Power on IR module\n");
- set_bitsy_egpio(EGPIO_BITSY_IR_ON);
- }
-#endif
#ifdef CONFIG_SA1100_COLLIE
sa1100_irda_set_power_collie(3); /* power on */
#endif
@@ -942,10 +936,6 @@ static void drop_hardware(void)
Ser2UTCR3 = sr.utcr3;
Ser2HSCR0 = sr.hscr0;
-#ifdef CONFIG_SA1100_BITSY
- if (machine_is_bitsy())
- clr_bitsy_egpio(EGPIO_BITSY_IR_ON);
-#endif
#ifdef CONFIG_SA1100_COLLIE
sa1100_irda_set_power_collie(0); /* power off */
#endif
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
index 63352de5eabf..ec32776ff547 100644
--- a/drivers/staging/media/solo6x10/Kconfig
+++ b/drivers/staging/media/solo6x10/Kconfig
@@ -1,7 +1,8 @@
config SOLO6X10
tristate "Softlogic 6x10 MPEG codec cards"
depends on PCI && VIDEO_DEV && SND && I2C
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
+ select VIDEOBUF2_DMA_CONTIG
select SND_PCM
---help---
This driver supports the Softlogic based MPEG-4 and h.264 codec
diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile
index 337e38c3a0f0..7aae118947b2 100644
--- a/drivers/staging/media/solo6x10/Makefile
+++ b/drivers/staging/media/solo6x10/Makefile
@@ -1,3 +1,5 @@
-solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o
+solo6x10-y := solo6x10-core.o solo6x10-i2c.o solo6x10-p2m.o solo6x10-v4l2.o \
+ solo6x10-tw28.o solo6x10-gpio.o solo6x10-disp.o solo6x10-enc.o \
+ solo6x10-v4l2-enc.o solo6x10-g723.o solo6x10-eeprom.o
obj-$(CONFIG_SOLO6X10) += solo6x10.o
diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO
index 539f739fe9e6..7b8db75b1acb 100644
--- a/drivers/staging/media/solo6x10/TODO
+++ b/drivers/staging/media/solo6x10/TODO
@@ -1,24 +1,15 @@
-TODO (staging => main):
-
- * Motion detection flags need to be moved to v4l2
- * Some private CIDs need to be moved to v4l2
-
-TODO (general):
-
- * encoder on/off controls
- * mpeg cid bitrate mode (vbr/cbr)
- * mpeg cid bitrate/bitrate-peak
- * mpeg encode of user data
- * mpeg decode of user data
- * switch between 4 frames/irq to 1 when using mjpeg (and then back
- when not)
- * implement a CID control for motion areas/thresholds
- * implement CID controls for mozaic areas
- * allow for higher level of interval (for < 1 fps)
- * sound:
- - implement playback via external sound jack
- - implement loopback of external sound jack with incoming audio?
- - implement pause/resume
-
-Plase send patches to Mauro Carvalho Chehab <mchehab@redhat.com> and Cc Ben Collins
-<bcollins@bluecherry.net>
+- batch up desc requests for more efficient use of p2m?
+- encoder on/off controls
+- mpeg cid bitrate mode (vbr/cbr)
+- mpeg cid bitrate/bitrate-peak
+- mpeg encode of user data
+- mpeg decode of user data
+- implement CID controls for mozaic areas
+
+- sound
+ - implement playback via external sound jack
+ - implement loopback of external sound jack with incoming audio?
+ - implement pause/resume (make use of in bc-server)
+
+Please send patches to the linux media list <linux-media@vger.kernel.org> and
+Cc Ismael Luceno <ismael.luceno@corp.bluecherry.net>.
diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c
deleted file mode 100644
index fd83d6d028bf..000000000000
--- a/drivers/staging/media/solo6x10/core.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver");
-MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>");
-MODULE_VERSION(SOLO6X10_VERSION);
-MODULE_LICENSE("GPL");
-
-void solo_irq_on(struct solo_dev *solo_dev, u32 mask)
-{
- solo_dev->irq_mask |= mask;
- solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
-}
-
-void solo_irq_off(struct solo_dev *solo_dev, u32 mask)
-{
- solo_dev->irq_mask &= ~mask;
- solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask);
-}
-
-/* XXX We should check the return value of the sub-device ISR's */
-static irqreturn_t solo_isr(int irq, void *data)
-{
- struct solo_dev *solo_dev = data;
- u32 status;
- int i;
-
- status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
- if (!status)
- return IRQ_NONE;
-
- if (status & ~solo_dev->irq_mask) {
- solo_reg_write(solo_dev, SOLO_IRQ_STAT,
- status & ~solo_dev->irq_mask);
- status &= solo_dev->irq_mask;
- }
-
- if (status & SOLO_IRQ_PCI_ERR) {
- u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
- solo_p2m_error_isr(solo_dev, err);
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR);
- }
-
- for (i = 0; i < SOLO_NR_P2M; i++)
- if (status & SOLO_IRQ_P2M(i))
- solo_p2m_isr(solo_dev, i);
-
- if (status & SOLO_IRQ_IIC)
- solo_i2c_isr(solo_dev);
-
- if (status & SOLO_IRQ_VIDEO_IN)
- solo_video_in_isr(solo_dev);
-
- /* Call this first so enc gets detected flag set */
- if (status & SOLO_IRQ_MOTION)
- solo_motion_isr(solo_dev);
-
- if (status & SOLO_IRQ_ENCODER)
- solo_enc_v4l2_isr(solo_dev);
-
- if (status & SOLO_IRQ_G723)
- solo_g723_isr(solo_dev);
-
- return IRQ_HANDLED;
-}
-
-static void free_solo_dev(struct solo_dev *solo_dev)
-{
- struct pci_dev *pdev;
-
- if (!solo_dev)
- return;
-
- pdev = solo_dev->pdev;
-
- /* If we never initialized the PCI device, then nothing else
- * below here needs cleanup */
- if (!pdev) {
- kfree(solo_dev);
- return;
- }
-
- /* Bring down the sub-devices first */
- solo_g723_exit(solo_dev);
- solo_enc_v4l2_exit(solo_dev);
- solo_enc_exit(solo_dev);
- solo_v4l2_exit(solo_dev);
- solo_disp_exit(solo_dev);
- solo_gpio_exit(solo_dev);
- solo_p2m_exit(solo_dev);
- solo_i2c_exit(solo_dev);
-
- /* Now cleanup the PCI device */
- if (solo_dev->reg_base) {
- solo_irq_off(solo_dev, ~0);
- pci_iounmap(pdev, solo_dev->reg_base);
- free_irq(pdev->irq, solo_dev);
- }
-
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
-
- kfree(solo_dev);
-}
-
-static int solo_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct solo_dev *solo_dev;
- int ret;
- int sdram;
- u8 chip_id;
- u32 reg;
-
- solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
- if (solo_dev == NULL)
- return -ENOMEM;
-
- solo_dev->pdev = pdev;
- spin_lock_init(&solo_dev->reg_io_lock);
- pci_set_drvdata(pdev, solo_dev);
-
- ret = pci_enable_device(pdev);
- if (ret)
- goto fail_probe;
-
- pci_set_master(pdev);
-
- ret = pci_request_regions(pdev, SOLO6X10_NAME);
- if (ret)
- goto fail_probe;
-
- solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
- if (solo_dev->reg_base == NULL) {
- ret = -ENOMEM;
- goto fail_probe;
- }
-
- chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
- SOLO_CHIP_ID_MASK;
- switch (chip_id) {
- case 7:
- solo_dev->nr_chans = 16;
- solo_dev->nr_ext = 5;
- break;
- case 6:
- solo_dev->nr_chans = 8;
- solo_dev->nr_ext = 2;
- break;
- default:
- dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, "
- "defaulting to 4 channels\n",
- chip_id);
- case 5:
- solo_dev->nr_chans = 4;
- solo_dev->nr_ext = 1;
- }
-
- solo_dev->flags = id->driver_data;
-
- /* Disable all interrupts to start */
- solo_irq_off(solo_dev, ~0);
-
- reg = SOLO_SYS_CFG_SDRAM64BIT;
- /* Initial global settings */
- if (!(solo_dev->flags & FLAGS_6110))
- reg |= SOLO6010_SYS_CFG_INPUTDIV(25) |
- SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) |
- SOLO6010_SYS_CFG_OUTDIV(3);
- solo_reg_write(solo_dev, SOLO_SYS_CFG, reg);
-
- if (solo_dev->flags & FLAGS_6110) {
- u32 sys_clock_MHz = SOLO_CLOCK_MHZ;
- u32 pll_DIVQ;
- u32 pll_DIVF;
-
- if (sys_clock_MHz < 125) {
- pll_DIVQ = 3;
- pll_DIVF = (sys_clock_MHz * 4) / 3;
- } else {
- pll_DIVQ = 2;
- pll_DIVF = (sys_clock_MHz * 2) / 3;
- }
-
- solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG,
- SOLO6110_PLL_RANGE_5_10MHZ |
- SOLO6110_PLL_DIVR(9) |
- SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) |
- SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN);
- mdelay(1); /* PLL Locking time (1ms) */
-
- solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */
- } else
- solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */
-
- solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1);
-
- /* PLL locking time of 1ms */
- mdelay(1);
-
- ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
- solo_dev);
- if (ret)
- goto fail_probe;
-
- /* Handle this from the start */
- solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
-
- ret = solo_i2c_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- /* Setup the DMA engine */
- sdram = (solo_dev->nr_chans >= 8) ? 2 : 1;
- solo_reg_write(solo_dev, SOLO_DMA_CTRL,
- SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
- SOLO_DMA_CTRL_SDRAM_SIZE(sdram) |
- SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
- SOLO_DMA_CTRL_READ_CLK_SELECT |
- SOLO_DMA_CTRL_LATENCY(1));
-
- ret = solo_p2m_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_disp_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_gpio_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_tw28_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_v4l2_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_enc_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_enc_v4l2_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- ret = solo_g723_init(solo_dev);
- if (ret)
- goto fail_probe;
-
- return 0;
-
-fail_probe:
- free_solo_dev(solo_dev);
- return ret;
-}
-
-static void solo_pci_remove(struct pci_dev *pdev)
-{
- struct solo_dev *solo_dev = pci_get_drvdata(pdev);
-
- free_solo_dev(solo_dev);
-}
-
-static struct pci_device_id solo_id_table[] = {
- /* 6010 based cards */
- {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)},
- {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
- .driver_data = FLAGS_6110},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)},
- /* 6110 based cards */
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)},
- {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, solo_id_table);
-
-static struct pci_driver solo_pci_driver = {
- .name = SOLO6X10_NAME,
- .id_table = solo_id_table,
- .probe = solo_pci_probe,
- .remove = solo_pci_remove,
-};
-
-module_pci_driver(solo_pci_driver);
diff --git a/drivers/staging/media/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h
deleted file mode 100644
index 3d7e569f1cf8..000000000000
--- a/drivers/staging/media/solo6x10/offsets.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_OFFSETS_H
-#define __SOLO6X10_OFFSETS_H
-
-/* Offsets and sizes of the external address */
-#define SOLO_DISP_EXT_ADDR 0x00000000
-#define SOLO_DISP_EXT_SIZE 0x00480000
-
-#define SOLO_DEC2LIVE_EXT_ADDR (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
-#define SOLO_DEC2LIVE_EXT_SIZE 0x00240000
-
-#define SOLO_OSG_EXT_ADDR (SOLO_DEC2LIVE_EXT_ADDR + SOLO_DEC2LIVE_EXT_SIZE)
-#define SOLO_OSG_EXT_SIZE 0x00120000
-
-#define SOLO_EOSD_EXT_ADDR (SOLO_OSG_EXT_ADDR + SOLO_OSG_EXT_SIZE)
-#define SOLO_EOSD_EXT_SIZE 0x00010000
-
-#define SOLO_MOTION_EXT_ADDR(__solo) (SOLO_EOSD_EXT_ADDR + \
- (SOLO_EOSD_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MOTION_EXT_SIZE 0x00080000
-
-#define SOLO_G723_EXT_ADDR(__solo) \
- (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
-#define SOLO_G723_EXT_SIZE 0x00010000
-
-#define SOLO_CAP_EXT_ADDR(__solo) \
- (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
-#define SOLO_CAP_EXT_MAX_PAGE (18 + 15)
-#define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536)
-
-/* This +1 is very important -- Why?! -- BenC */
-#define SOLO_EREF_EXT_ADDR(__solo) \
- (SOLO_CAP_EXT_ADDR(__solo) + \
- (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1)))
-#define SOLO_EREF_EXT_SIZE 0x00140000
-
-#define SOLO_MP4E_EXT_ADDR(__solo) \
- (SOLO_EREF_EXT_ADDR(__solo) + \
- (SOLO_EREF_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
-
-#define SOLO_DREF_EXT_ADDR(__solo) \
- (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
-#define SOLO_DREF_EXT_SIZE 0x00140000
-
-#define SOLO_MP4D_EXT_ADDR(__solo) \
- (SOLO_DREF_EXT_ADDR(__solo) + \
- (SOLO_DREF_EXT_SIZE * __solo->nr_chans))
-#define SOLO_MP4D_EXT_SIZE 0x00080000
-
-#define SOLO_JPEG_EXT_ADDR(__solo) \
- (SOLO_MP4D_EXT_ADDR(__solo) + \
- (SOLO_MP4D_EXT_SIZE * __solo->nr_chans))
-#define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans)
-
-#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/staging/media/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h
deleted file mode 100644
index 591e0e82e0e8..000000000000
--- a/drivers/staging/media/solo6x10/osd-font.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __SOLO6X10_OSD_FONT_H
-#define __SOLO6X10_OSD_FONT_H
-
-static const unsigned int solo_osd_font[] = {
- 0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000,
- 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */
- 0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000,
- 0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000,
- 0x00000000, 0x00001038, 0x10000000, 0x00000000,
- 0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000,
- 0x00000000, 0x00384444, 0x44380000, 0x00000000,
- 0x00000000, 0x38448282, 0x82443800, 0x00000000,
- 0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000,
- 0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000,
- 0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000,
- 0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000,
- 0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000,
- 0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000,
- 0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000,
- 0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000,
- 0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000,
- 0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000,
- 0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000,
- 0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000,
- 0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000,
- 0x00000082, 0x44288244, 0x38c6827c, 0x00000000,
- 0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000,
- 0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000,
- 0x00000000, 0x3854929a, 0x82443800, 0x00000000,
- 0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000,
- 0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000,
- 0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000,
- 0x0000007c, 0x82829292, 0x929282fe, 0x00000000,
- 0x000000f8, 0xfc046494, 0x946404fc, 0x00000000,
- 0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000,
- 0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32 ! */
- 0x00000066, 0x66240000, 0x00000000, 0x00000000,
- 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */
- 0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000,
- 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */
- 0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000,
- 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */
- 0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000,
- 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */
- 0x00000000, 0x0000663c, 0xff3c6600, 0x00000000,
- 0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */
- 0x00000000, 0x00000000, 0x00000e0e, 0x0c060000,
- 0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */
- 0x00000000, 0x00000000, 0x00000006, 0x06000000,
- 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */
- 0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000,
- 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */
- 0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000,
- 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */
- 0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000,
- 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */
- 0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000,
- 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */
- 0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000,
- 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */
- 0x00000000, 0x18180000, 0x00181800, 0x00000000,
- 0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */
- 0x00000060, 0x30180c06, 0x0c183060, 0x00000000,
- 0x00000000, 0x007e0000, 0x007e0000, 0x00000000,
- 0x00000006, 0x0c183060, 0x30180c06, 0x00000000,
- 0x0000007c, 0xc6c66030, 0x30003030, 0x00000000,
- 0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000,
- 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */
- 0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000,
- 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */
- 0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000,
- 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */
- 0x000000fe, 0x0606063e, 0x06060606, 0x00000000,
- 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */
- 0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000,
- 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */
- 0x00000060, 0x60606060, 0x6066663c, 0x00000000,
- 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */
- 0x00000006, 0x06060606, 0x060606fe, 0x00000000,
- 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */
- 0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000,
- 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */
- 0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000,
- 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */
- 0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000,
- 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */
- 0x0000007e, 0x18181818, 0x18181818, 0x00000000,
- 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */
- 0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000,
- 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */
- 0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000,
- 0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */
- 0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000,
- 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */
- 0x00000002, 0x060c1830, 0x60c08000, 0x00000000,
- 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */
- 0x00001038, 0x6cc60000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00fe0000,
- 0x00001818, 0x30000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00003c60, 0x7c66667c, 0x00000000,
- 0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000,
- 0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000,
- 0x00000060, 0x60607c66, 0x6666667c, 0x00000000,
- 0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000,
- 0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000,
- 0x00000000, 0x00007c66, 0x6666667c, 0x60603e00,
- 0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000,
- 0x00000030, 0x30003830, 0x30303078, 0x00000000,
- 0x00000030, 0x30003c30, 0x30303030, 0x30301f00,
- 0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000,
- 0x00000030, 0x30303030, 0x30303030, 0x00000000,
- 0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000,
- 0x00000000, 0x000078cc, 0xcccccccc, 0x00000000,
- 0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000,
- 0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00,
- 0x00000000, 0x00007c66, 0x6666667c, 0x60606000,
- 0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000,
- 0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000,
- 0x00000000, 0x1818fe18, 0x18181870, 0x00000000,
- 0x00000000, 0x00006666, 0x6666663c, 0x00000000,
- 0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000,
- 0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000,
- 0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000,
- 0x00000000, 0x00006666, 0x6666667c, 0x60603e00,
- 0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000,
- 0x00000070, 0x1818180e, 0x18181870, 0x00000000,
- 0x00000018, 0x18181800, 0x18181818, 0x00000000,
- 0x0000000e, 0x18181870, 0x1818180e, 0x00000000,
- 0x000000dc, 0x76000000, 0x00000000, 0x00000000,
- 0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000
-};
-
-#endif /* __SOLO6X10_OSD_FONT_H */
diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c
deleted file mode 100644
index 58ab61b1f1d9..000000000000
--- a/drivers/staging/media/solo6x10/p2m.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include "solo6x10.h"
-
-/* #define SOLO_TEST_P2M */
-
-int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
- void *sys_addr, u32 ext_addr, u32 size)
-{
- dma_addr_t dma_addr;
- int ret;
-
- WARN_ON(!size);
- BUG_ON(id >= SOLO_NR_P2M);
-
- if (!size)
- return -EINVAL;
-
- dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
- wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
- ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size);
-
- pci_unmap_single(solo_dev->pdev, dma_addr, size,
- wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
- return ret;
-}
-
-int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
- dma_addr_t dma_addr, u32 ext_addr, u32 size)
-{
- struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA);
- int ret;
-
- if (desc == NULL)
- return -ENOMEM;
-
- solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0);
- ret = solo_p2m_dma_desc(solo_dev, id, desc, 2);
- kfree(desc);
-
- return ret;
-}
-
-void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
- u32 ext_addr, u32 size, int repeat, u32 ext_size)
-{
- desc->ta = cpu_to_le32(dma_addr);
- desc->fa = cpu_to_le32(ext_addr);
-
- desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2));
- desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
- (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);
-
- /* Ext size only matters when we're repeating */
- if (repeat) {
- desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2));
- desc->ctrl |= cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) |
- SOLO_P2M_REPEAT(repeat));
- }
-}
-
-int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
- struct p2m_desc *desc, int desc_count)
-{
- struct solo_p2m_dev *p2m_dev;
- unsigned int timeout;
- int ret = 0;
- u32 config = 0;
- dma_addr_t desc_dma = 0;
-
- BUG_ON(id >= SOLO_NR_P2M);
- BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC);
-
- p2m_dev = &solo_dev->p2m_dev[id];
-
- mutex_lock(&p2m_dev->mutex);
-
- solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-
- INIT_COMPLETION(p2m_dev->completion);
- p2m_dev->error = 0;
-
- /* Enable the descriptors */
- config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id));
- desc_dma = pci_map_single(solo_dev->pdev, desc,
- desc_count * sizeof(*desc),
- PCI_DMA_TODEVICE);
- solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma);
- solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1);
- solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config |
- SOLO_P2M_DESC_MODE);
-
- /* Should have all descriptors completed from one interrupt */
- timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);
-
- solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
-
- /* Reset back to non-descriptor mode */
- solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config);
- solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0);
- solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0);
- pci_unmap_single(solo_dev->pdev, desc_dma,
- desc_count * sizeof(*desc),
- PCI_DMA_TODEVICE);
-
- if (p2m_dev->error)
- ret = -EIO;
- else if (timeout == 0)
- ret = -EAGAIN;
-
- mutex_unlock(&p2m_dev->mutex);
-
- WARN_ON_ONCE(ret);
-
- return ret;
-}
-
-int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
- struct p2m_desc *pdesc, int wr,
- struct scatterlist *sg, u32 sg_off,
- u32 ext_addr, u32 size)
-{
- int i;
- int idx;
-
- BUG_ON(id >= SOLO_NR_P2M);
-
- if (WARN_ON_ONCE(!size))
- return -EINVAL;
-
- memset(pdesc, 0, sizeof(*pdesc));
-
- /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */
- for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0;
- i++, sg = sg_next(sg)) {
- struct p2m_desc *desc = &pdesc[idx];
- u32 sg_len = sg_dma_len(sg);
- u32 len;
-
- if (sg_off >= sg_len) {
- sg_off -= sg_len;
- continue;
- }
-
- sg_len -= sg_off;
- len = min(sg_len, size);
-
- solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off,
- ext_addr, len, 0, 0);
-
- size -= len;
- ext_addr += len;
- idx++;
-
- sg_off = 0;
- }
-
- WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC);
-
- return solo_p2m_dma_desc(solo_dev, id, pdesc, idx);
-}
-
-#ifdef SOLO_TEST_P2M
-
-#define P2M_TEST_CHAR 0xbe
-
-static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id,
- u32 base, int size)
-{
- u8 *wr_buf;
- u8 *rd_buf;
- int i;
- unsigned long long err_cnt = 0;
-
- wr_buf = kmalloc(size, GFP_KERNEL);
- if (!wr_buf) {
- printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
- return size;
- }
-
- rd_buf = kmalloc(size, GFP_KERNEL);
- if (!rd_buf) {
- printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n");
- kfree(wr_buf);
- return size;
- }
-
- memset(wr_buf, P2M_TEST_CHAR, size);
- memset(rd_buf, P2M_TEST_CHAR + 1, size);
-
- solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size);
- solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size);
-
- for (i = 0; i < size; i++)
- if (wr_buf[i] != rd_buf[i])
- err_cnt++;
-
- kfree(wr_buf);
- kfree(rd_buf);
-
- return err_cnt;
-}
-
-#define TEST_CHUNK_SIZE (8 * 1024)
-
-static void run_p2m_test(struct solo_dev *solo_dev)
-{
- unsigned long long errs = 0;
- u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev);
- int i, d;
-
- dev_warn(&solo_dev->pdev->dev, "Testing %u bytes of external ram\n",
- size);
-
- for (i = 0; i < size; i += TEST_CHUNK_SIZE)
- for (d = 0; d < 4; d++)
- errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE);
-
- dev_warn(&solo_dev->pdev->dev, "Found %llu errors during p2m test\n",
- errs);
-
- return;
-}
-#else
-#define run_p2m_test(__solo) do {} while (0)
-#endif
-
-void solo_p2m_isr(struct solo_dev *solo_dev, int id)
-{
- struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
-
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id));
-
- complete(&p2m_dev->completion);
-}
-
-void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status)
-{
- struct solo_p2m_dev *p2m_dev;
- int i;
-
- if (!(status & SOLO_PCI_ERR_P2M))
- return;
-
- for (i = 0; i < SOLO_NR_P2M; i++) {
- p2m_dev = &solo_dev->p2m_dev[i];
- p2m_dev->error = 1;
- solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
- complete(&p2m_dev->completion);
- }
-}
-
-void solo_p2m_exit(struct solo_dev *solo_dev)
-{
- int i;
-
- for (i = 0; i < SOLO_NR_P2M; i++)
- solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
-}
-
-int solo_p2m_init(struct solo_dev *solo_dev)
-{
- struct solo_p2m_dev *p2m_dev;
- int i;
-
- for (i = 0; i < SOLO_NR_P2M; i++) {
- p2m_dev = &solo_dev->p2m_dev[i];
-
- mutex_init(&p2m_dev->mutex);
- init_completion(&p2m_dev->completion);
-
- solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
- solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
- SOLO_P2M_CSC_16BIT_565 |
- SOLO_P2M_DMA_INTERVAL(3) |
- SOLO_P2M_DESC_INTR_OPT |
- SOLO_P2M_PCI_MASTER_MODE);
- solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
- }
-
- run_p2m_test(solo_dev);
-
- return 0;
-}
diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/staging/media/solo6x10/solo6x10-core.c
new file mode 100644
index 000000000000..36750205d23f
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-core.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver");
+MODULE_AUTHOR("Bluecherry <maintainers@bluecherrydvr.com>");
+MODULE_VERSION(SOLO6X10_VERSION);
+MODULE_LICENSE("GPL");
+
+unsigned video_nr = -1;
+module_param(video_nr, uint, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
+
+static int full_eeprom; /* default is only top 64B */
+module_param(full_eeprom, uint, 0644);
+MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)");
+
+
+static void solo_set_time(struct solo_dev *solo_dev)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+
+ solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec);
+ solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC);
+}
+
+static void solo_timer_sync(struct solo_dev *solo_dev)
+{
+ u32 sec, usec;
+ struct timespec ts;
+ long diff;
+
+ if (solo_dev->type != SOLO_DEV_6110)
+ return;
+
+ if (++solo_dev->time_sync < 60)
+ return;
+
+ solo_dev->time_sync = 0;
+
+ sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC);
+ usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC);
+
+ ktime_get_ts(&ts);
+
+ diff = (long)ts.tv_sec - (long)sec;
+ diff = (diff * 1000000)
+ + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec);
+
+ if (diff > 1000 || diff < -1000) {
+ solo_set_time(solo_dev);
+ } else if (diff) {
+ long usec_lsb = solo_dev->usec_lsb;
+
+ usec_lsb -= diff / 4;
+ if (usec_lsb < 0)
+ usec_lsb = 0;
+ else if (usec_lsb > 255)
+ usec_lsb = 255;
+
+ solo_dev->usec_lsb = usec_lsb;
+ solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB,
+ solo_dev->usec_lsb);
+ }
+}
+
+static irqreturn_t solo_isr(int irq, void *data)
+{
+ struct solo_dev *solo_dev = data;
+ u32 status;
+ int i;
+
+ status = solo_reg_read(solo_dev, SOLO_IRQ_STAT);
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & ~solo_dev->irq_mask) {
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT,
+ status & ~solo_dev->irq_mask);
+ status &= solo_dev->irq_mask;
+ }
+
+ if (status & SOLO_IRQ_PCI_ERR)
+ solo_p2m_error_isr(solo_dev);
+
+ for (i = 0; i < SOLO_NR_P2M; i++)
+ if (status & SOLO_IRQ_P2M(i))
+ solo_p2m_isr(solo_dev, i);
+
+ if (status & SOLO_IRQ_IIC)
+ solo_i2c_isr(solo_dev);
+
+ if (status & SOLO_IRQ_VIDEO_IN) {
+ solo_video_in_isr(solo_dev);
+ solo_timer_sync(solo_dev);
+ }
+
+ if (status & SOLO_IRQ_ENCODER)
+ solo_enc_v4l2_isr(solo_dev);
+
+ if (status & SOLO_IRQ_G723)
+ solo_g723_isr(solo_dev);
+
+ /* Clear all interrupts handled */
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
+
+ return IRQ_HANDLED;
+}
+
+static void free_solo_dev(struct solo_dev *solo_dev)
+{
+ struct pci_dev *pdev;
+
+ if (!solo_dev)
+ return;
+
+ if (solo_dev->dev.parent)
+ device_unregister(&solo_dev->dev);
+
+ pdev = solo_dev->pdev;
+
+ /* If we never initialized the PCI device, then nothing else
+ * below here needs cleanup */
+ if (!pdev) {
+ kfree(solo_dev);
+ return;
+ }
+
+ if (solo_dev->reg_base) {
+ /* Bring down the sub-devices first */
+ solo_g723_exit(solo_dev);
+ solo_enc_v4l2_exit(solo_dev);
+ solo_enc_exit(solo_dev);
+ solo_v4l2_exit(solo_dev);
+ solo_disp_exit(solo_dev);
+ solo_gpio_exit(solo_dev);
+ solo_p2m_exit(solo_dev);
+ solo_i2c_exit(solo_dev);
+
+ /* Now cleanup the PCI device */
+ solo_irq_off(solo_dev, ~0);
+ pci_iounmap(pdev, solo_dev->reg_base);
+ if (pdev->irq)
+ free_irq(pdev->irq, solo_dev);
+ }
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ v4l2_device_unregister(&solo_dev->v4l2_dev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(solo_dev);
+}
+
+static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ unsigned short *p = (unsigned short *)buf;
+ int i;
+
+ if (count & 0x1)
+ dev_warn(dev, "EEPROM Write not aligned (truncating)\n");
+
+ if (!full_eeprom && count > 64) {
+ dev_warn(dev, "EEPROM Write truncated to 64 bytes\n");
+ count = 64;
+ } else if (full_eeprom && count > 128) {
+ dev_warn(dev, "EEPROM Write truncated to 128 bytes\n");
+ count = 128;
+ }
+
+ solo_eeprom_ewen(solo_dev, 1);
+
+ for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32),
+ (int)(count / 2)); i++)
+ solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i]));
+
+ solo_eeprom_ewen(solo_dev, 0);
+
+ return count;
+}
+
+static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ unsigned short *p = (unsigned short *)buf;
+ int count = (full_eeprom ? 128 : 64);
+ int i;
+
+ for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++)
+ p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i));
+
+ return count;
+}
+
+static ssize_t p2m_timeouts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+
+ return sprintf(buf, "%d\n", solo_dev->p2m_timeouts);
+}
+
+static ssize_t sdram_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+
+ return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20);
+}
+
+static ssize_t tw28xx_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+
+ return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n",
+ hweight32(solo_dev->tw2815),
+ hweight32(solo_dev->tw2864),
+ hweight32(solo_dev->tw2865));
+}
+
+static ssize_t input_map_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ unsigned int val;
+ char *out = buf;
+
+ val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0);
+ out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f);
+ out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f);
+ out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f);
+ out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f);
+ out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f);
+ out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f);
+
+ val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1);
+ out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f);
+ out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f);
+ out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f);
+ out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f);
+ out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f);
+ out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f);
+
+ val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2);
+ out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f);
+ out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f);
+ out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f);
+ out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f);
+ out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f);
+
+ return out - buf;
+}
+
+static ssize_t p2m_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ unsigned long ms;
+
+ int ret = kstrtoul(buf, 10, &ms);
+ if (ret < 0 || ms > 200)
+ return -EINVAL;
+ solo_dev->p2m_jiffies = msecs_to_jiffies(ms);
+
+ return count;
+}
+
+static ssize_t p2m_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+
+ return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies));
+}
+
+static ssize_t intervals_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ char *out = buf;
+ int fps = solo_dev->fps;
+ int i;
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n",
+ i, solo_dev->v4l2_enc[i]->interval, fps,
+ solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i)));
+ }
+
+ return out - buf;
+}
+
+static ssize_t sdram_offsets_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ char *out = buf;
+
+ out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n",
+ SOLO_DISP_EXT_ADDR,
+ SOLO_DISP_EXT_SIZE);
+
+ out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+ SOLO_EOSD_EXT_ADDR,
+ SOLO_EOSD_EXT_AREA(solo_dev),
+ SOLO_EOSD_EXT_SIZE(solo_dev),
+ SOLO_EOSD_EXT_AREA(solo_dev) /
+ SOLO_EOSD_EXT_SIZE(solo_dev));
+
+ out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n",
+ SOLO_MOTION_EXT_ADDR(solo_dev),
+ SOLO_MOTION_EXT_SIZE);
+
+ out += sprintf(out, "G723: 0x%08x @ 0x%08x\n",
+ SOLO_G723_EXT_ADDR(solo_dev),
+ SOLO_G723_EXT_SIZE);
+
+ out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+ SOLO_CAP_EXT_ADDR(solo_dev),
+ SOLO_CAP_EXT_SIZE(solo_dev),
+ SOLO_CAP_PAGE_SIZE,
+ SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE);
+
+ out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n",
+ SOLO_EREF_EXT_ADDR(solo_dev),
+ SOLO_EREF_EXT_AREA(solo_dev),
+ SOLO_EREF_EXT_SIZE,
+ SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE);
+
+ out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n",
+ SOLO_MP4E_EXT_ADDR(solo_dev),
+ SOLO_MP4E_EXT_SIZE(solo_dev));
+
+ out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n",
+ SOLO_JPEG_EXT_ADDR(solo_dev),
+ SOLO_JPEG_EXT_SIZE(solo_dev));
+
+ return out - buf;
+}
+
+static ssize_t sdram_show(struct file *file, struct kobject *kobj,
+ struct bin_attribute *a, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct solo_dev *solo_dev =
+ container_of(dev, struct solo_dev, dev);
+ const int size = solo_dev->sdram_size;
+
+ if (off >= size)
+ return 0;
+
+ if (off + count > size)
+ count = size - off;
+
+ if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0))
+ return -EIO;
+
+ return count;
+}
+
+static const struct device_attribute solo_dev_attrs[] = {
+ __ATTR(eeprom, 0640, eeprom_show, eeprom_store),
+ __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store),
+ __ATTR_RO(p2m_timeouts),
+ __ATTR_RO(sdram_size),
+ __ATTR_RO(tw28xx),
+ __ATTR_RO(input_map),
+ __ATTR_RO(intervals),
+ __ATTR_RO(sdram_offsets),
+};
+
+static void solo_device_release(struct device *dev)
+{
+ /* Do nothing */
+}
+
+static int solo_sysfs_init(struct solo_dev *solo_dev)
+{
+ struct bin_attribute *sdram_attr = &solo_dev->sdram_attr;
+ struct device *dev = &solo_dev->dev;
+ const char *driver;
+ int i;
+
+ if (solo_dev->type == SOLO_DEV_6110)
+ driver = "solo6110";
+ else
+ driver = "solo6010";
+
+ dev->release = solo_device_release;
+ dev->parent = &solo_dev->pdev->dev;
+ set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev));
+ dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num,
+ solo_dev->nr_chans);
+
+ if (device_register(dev)) {
+ dev->parent = NULL;
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) {
+ if (device_create_file(dev, &solo_dev_attrs[i])) {
+ device_unregister(dev);
+ return -ENOMEM;
+ }
+ }
+
+ sysfs_attr_init(&sdram_attr->attr);
+ sdram_attr->attr.name = "sdram";
+ sdram_attr->attr.mode = 0440;
+ sdram_attr->read = sdram_show;
+ sdram_attr->size = solo_dev->sdram_size;
+
+ if (device_create_bin_file(dev, sdram_attr)) {
+ device_unregister(dev);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct solo_dev *solo_dev;
+ int ret;
+ u8 chip_id;
+
+ solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL);
+ if (solo_dev == NULL)
+ return -ENOMEM;
+
+ if (id->driver_data == SOLO_DEV_6010)
+ dev_info(&pdev->dev, "Probing Softlogic 6010\n");
+ else
+ dev_info(&pdev->dev, "Probing Softlogic 6110\n");
+
+ solo_dev->type = id->driver_data;
+ solo_dev->pdev = pdev;
+ spin_lock_init(&solo_dev->reg_io_lock);
+ ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev);
+ if (ret)
+ goto fail_probe;
+
+ /* Only for during init */
+ solo_dev->p2m_jiffies = msecs_to_jiffies(100);
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ goto fail_probe;
+
+ pci_set_master(pdev);
+
+ /* RETRY/TRDY Timeout disabled */
+ pci_write_config_byte(pdev, 0x40, 0x00);
+ pci_write_config_byte(pdev, 0x41, 0x00);
+
+ ret = pci_request_regions(pdev, SOLO6X10_NAME);
+ if (ret)
+ goto fail_probe;
+
+ solo_dev->reg_base = pci_ioremap_bar(pdev, 0);
+ if (solo_dev->reg_base == NULL) {
+ ret = -ENOMEM;
+ goto fail_probe;
+ }
+
+ chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) &
+ SOLO_CHIP_ID_MASK;
+ switch (chip_id) {
+ case 7:
+ solo_dev->nr_chans = 16;
+ solo_dev->nr_ext = 5;
+ break;
+ case 6:
+ solo_dev->nr_chans = 8;
+ solo_dev->nr_ext = 2;
+ break;
+ default:
+ dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n",
+ chip_id);
+ case 5:
+ solo_dev->nr_chans = 4;
+ solo_dev->nr_ext = 1;
+ }
+
+ /* Disable all interrupts to start */
+ solo_irq_off(solo_dev, ~0);
+
+ /* Initial global settings */
+ if (solo_dev->type == SOLO_DEV_6010) {
+ solo_dev->clock_mhz = 108;
+ solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT
+ | SOLO_SYS_CFG_INPUTDIV(25)
+ | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2)
+ | SOLO_SYS_CFG_OUTDIV(3);
+ solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+ } else {
+ u32 divq, divf;
+
+ solo_dev->clock_mhz = 135;
+
+ if (solo_dev->clock_mhz < 125) {
+ divq = 3;
+ divf = (solo_dev->clock_mhz * 4) / 3 - 1;
+ } else {
+ divq = 2;
+ divf = (solo_dev->clock_mhz * 2) / 3 - 1;
+ }
+
+ solo_reg_write(solo_dev, SOLO_PLL_CONFIG,
+ (1 << 20) | /* PLL_RANGE */
+ (8 << 15) | /* PLL_DIVR */
+ (divq << 12) |
+ (divf << 4) |
+ (1 << 1) /* PLL_FSEN */);
+
+ solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT;
+ }
+
+ solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+ solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM,
+ solo_dev->clock_mhz - 1);
+
+ /* PLL locking time of 1ms */
+ mdelay(1);
+
+ ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME,
+ solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ /* Handle this from the start */
+ solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR);
+
+ ret = solo_i2c_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ /* Setup the DMA engine */
+ solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+ SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+ SOLO_DMA_CTRL_SDRAM_SIZE(2) |
+ SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+ SOLO_DMA_CTRL_READ_CLK_SELECT |
+ SOLO_DMA_CTRL_LATENCY(1));
+
+ /* Undocumented crap */
+ solo_reg_write(solo_dev, SOLO_DMA_CTRL1,
+ solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300);
+
+ if (solo_dev->type != SOLO_DEV_6010) {
+ solo_dev->usec_lsb = 0x3f;
+ solo_set_time(solo_dev);
+ }
+
+ /* Disable watchdog */
+ solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
+
+ /* Initialize sub components */
+
+ ret = solo_p2m_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_disp_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_gpio_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_tw28_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_v4l2_init(solo_dev, video_nr);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_enc_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_enc_v4l2_init(solo_dev, video_nr);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_g723_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ ret = solo_sysfs_init(solo_dev);
+ if (ret)
+ goto fail_probe;
+
+ /* Now that init is over, set this lower */
+ solo_dev->p2m_jiffies = msecs_to_jiffies(20);
+
+ return 0;
+
+fail_probe:
+ free_solo_dev(solo_dev);
+ return ret;
+}
+
+static void solo_pci_remove(struct pci_dev *pdev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev);
+
+ free_solo_dev(solo_dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(solo_id_table) = {
+ /* 6010 based cards */
+ { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9),
+ .driver_data = SOLO_DEV_6010 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16),
+ .driver_data = SOLO_DEV_6010 },
+ /* 6110 based cards */
+ { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110),
+ .driver_data = SOLO_DEV_6110 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4),
+ .driver_data = SOLO_DEV_6110 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8),
+ .driver_data = SOLO_DEV_6110 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16),
+ .driver_data = SOLO_DEV_6110 },
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, solo_id_table);
+
+static struct pci_driver solo_pci_driver = {
+ .name = SOLO6X10_NAME,
+ .id_table = solo_id_table,
+ .probe = solo_pci_probe,
+ .remove = solo_pci_remove,
+};
+
+module_pci_driver(solo_pci_driver);
diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c
index 884c0eb757c4..32d9953bc36e 100644
--- a/drivers/staging/media/solo6x10/disp.c
+++ b/drivers/staging/media/solo6x10/solo6x10-disp.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -21,6 +26,7 @@
#include <linux/module.h>
#include <linux/videodev2.h>
#include <media/v4l2-ioctl.h>
+
#include "solo6x10.h"
#define SOLO_VCLK_DELAY 3
@@ -30,12 +36,8 @@
#define SOLO_MOT_THRESH_H 64
#define SOLO_MOT_THRESH_SIZE 8192
#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H)
-#define SOLO_MOT_FLAG_SIZE 512
-#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32)
-
-static unsigned video_type;
-module_param(video_type, uint, 0644);
-MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)");
+#define SOLO_MOT_FLAG_SIZE 1024
+#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16)
static void solo_vin_config(struct solo_dev *solo_dev)
{
@@ -73,7 +75,12 @@ static void solo_vin_config(struct solo_dev *solo_dev)
solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT,
SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0));
- solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
+ /* On 6110, initialize mozaic darkness stength */
+ if (solo_dev->type == SOLO_DEV_6010)
+ solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0);
+ else
+ solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22);
+
solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2);
if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
@@ -97,21 +104,30 @@ static void solo_vin_config(struct solo_dev *solo_dev)
SOLO_VI_PB_HSTOP(16 + 720));
}
-static void solo_disp_config(struct solo_dev *solo_dev)
+static void solo_vout_config_cursor(struct solo_dev *dev)
+{
+ int i;
+
+ /* Load (blank) cursor bitmap mask (2bpp) */
+ for (i = 0; i < 20; i++)
+ solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0);
+
+ solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0);
+
+ solo_reg_write(dev, SOLO_VO_CURSOR_CLR,
+ (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80);
+ solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80);
+}
+
+static void solo_vout_config(struct solo_dev *solo_dev)
{
solo_dev->vout_hstart = 6;
solo_dev->vout_vstart = 8;
- solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
- (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
- solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
- (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
- solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
- (16 << 24) | (128 << 16) | (16 << 8) | 128);
-
solo_reg_write(solo_dev, SOLO_VO_FMT_ENC,
solo_dev->video_type |
SOLO_VO_USER_COLOR_SET_NAV |
+ SOLO_VO_USER_COLOR_SET_NAH |
SOLO_VO_NA_COLOR_Y(0) |
SOLO_VO_NA_COLOR_CB(0) |
SOLO_VO_NA_COLOR_CR(0));
@@ -130,19 +146,31 @@ static void solo_disp_config(struct solo_dev *solo_dev)
SOLO_VO_H_LEN(solo_dev->video_hsize) |
SOLO_VO_V_LEN(solo_dev->video_vsize));
- solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5);
+ /* Border & background colors */
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR,
+ (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88);
+ solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR,
+ (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f);
+ solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR,
+ (16 << 24) | (128 << 16) | (16 << 8) | 128);
+
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+
+ solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0);
+
+ solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
+ solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON |
SOLO_VO_DISP_ERASE_COUNT(8) |
SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR));
- solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
- /* Enable channels we support */
- solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1);
+ solo_vout_config_cursor(solo_dev);
- /* Disable the watchdog */
- solo_reg_write(solo_dev, SOLO_WATCHDOG, 0);
+ /* Enable channels we support */
+ solo_reg_write(solo_dev, SOLO_VI_CH_ENA,
+ (1 << solo_dev->nr_chans) - 1);
}
static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
@@ -153,29 +181,48 @@ static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
int ret = 0;
for (i = 0; i < sizeof(buf) >> 1; i++)
- buf[i] = val;
+ buf[i] = cpu_to_le16(val);
for (i = 0; i < reg_size; i += sizeof(buf))
- ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf,
+ ret |= solo_p2m_dma(solo_dev, 1, buf,
SOLO_MOTION_EXT_ADDR(solo_dev) + off + i,
- sizeof(buf));
+ sizeof(buf), 0, 0);
return ret;
}
-void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
+int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
{
if (ch > solo_dev->nr_chans)
- return;
+ return -EINVAL;
- solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
- (ch * SOLO_MOT_THRESH_SIZE * 2),
- val, SOLO_MOT_THRESH_REAL);
+ return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
+ (ch * SOLO_MOT_THRESH_SIZE * 2),
+ val, SOLO_MOT_THRESH_SIZE);
+}
+
+int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
+ const struct solo_motion_thresholds *thresholds)
+{
+ u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
+ u16 buf[64];
+ int x, y;
+ int ret = 0;
+
+ memset(buf, 0, sizeof(buf));
+ for (y = 0; y < SOLO_MOTION_SZ; y++) {
+ for (x = 0; x < SOLO_MOTION_SZ; x++)
+ buf[x] = cpu_to_le16(thresholds->thresholds[y][x]);
+ ret |= solo_p2m_dma(solo_dev, 1, buf,
+ SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf),
+ sizeof(buf), 0, 0);
+ }
+ return ret;
}
/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k
* threshold and working table for each channel. Atleast that's what the
- * spec says. However, this code (take from rdk) has some mystery 8k
+ * spec says. However, this code (taken from rdk) has some mystery 8k
* block right after the flag area, before the first thresh table. */
static void solo_motion_config(struct solo_dev *solo_dev)
{
@@ -188,9 +235,9 @@ static void solo_motion_config(struct solo_dev *solo_dev)
/* Clear working cache table */
solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA +
- SOLO_MOT_THRESH_SIZE +
- (i * SOLO_MOT_THRESH_SIZE * 2),
- 0x0000, SOLO_MOT_THRESH_REAL);
+ (i * SOLO_MOT_THRESH_SIZE * 2) +
+ SOLO_MOT_THRESH_SIZE, 0x0000,
+ SOLO_MOT_THRESH_SIZE);
/* Set default threshold table */
solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH);
@@ -202,8 +249,8 @@ static void solo_motion_config(struct solo_dev *solo_dev)
solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL,
SOLO_VI_MOTION_FRAME_COUNT(3) |
SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16)
- | /* SOLO_VI_MOTION_INTR_START_STOP | */
- SOLO_VI_MOTION_SAMPLE_COUNT(10));
+ /* | SOLO_VI_MOTION_INTR_START_STOP */
+ | SOLO_VI_MOTION_SAMPLE_COUNT(10));
solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
@@ -214,19 +261,17 @@ int solo_disp_init(struct solo_dev *solo_dev)
int i;
solo_dev->video_hsize = 704;
- if (video_type == 0) {
- solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC;
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
solo_dev->video_vsize = 240;
solo_dev->fps = 30;
} else {
- solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL;
solo_dev->video_vsize = 288;
solo_dev->fps = 25;
}
solo_vin_config(solo_dev);
solo_motion_config(solo_dev);
- solo_disp_config(solo_dev);
+ solo_vout_config(solo_dev);
for (i = 0; i < solo_dev->nr_chans; i++)
solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1);
@@ -238,8 +283,6 @@ void solo_disp_exit(struct solo_dev *solo_dev)
{
int i;
- solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0);
solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0);
solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0);
diff --git a/drivers/staging/media/solo6x10/solo6x10-eeprom.c b/drivers/staging/media/solo6x10/solo6x10-eeprom.c
new file mode 100644
index 000000000000..9d1c9bb53d6b
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-eeprom.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include "solo6x10.h"
+
+/* Control */
+#define EE_SHIFT_CLK 0x04
+#define EE_CS 0x08
+#define EE_DATA_WRITE 0x02
+#define EE_DATA_READ 0x01
+#define EE_ENB (0x80 | EE_CS)
+
+#define eeprom_delay() udelay(100)
+#if 0
+#define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
+#define eeprom_delay() ({ \
+ int i, ret; \
+ udelay(100); \
+ for (i = ret = 0; i < 1000 && !ret; i++) \
+ ret = solo_eeprom_reg_read(solo_dev); \
+})
+#endif
+#define ADDR_LEN 6
+
+/* Commands */
+#define EE_EWEN_CMD 4
+#define EE_EWDS_CMD 4
+#define EE_WRITE_CMD 5
+#define EE_READ_CMD 6
+#define EE_ERASE_CMD 7
+
+static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
+{
+ return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
+}
+
+static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
+{
+ solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
+ eeprom_delay();
+}
+
+static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
+{
+ int i;
+
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+
+ for (i = 4 + ADDR_LEN; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+ EE_SHIFT_CLK | dataval);
+ }
+
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+}
+
+unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
+{
+ int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
+ unsigned int retval = 0;
+ int i;
+
+ solo_eeprom_cmd(solo_dev, ewen_cmd);
+
+ for (i = 0; i < 16; i++) {
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+ EE_SHIFT_CLK);
+ retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+ retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+ }
+
+ solo_eeprom_reg_write(solo_dev, ~EE_CS);
+ retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+
+ return retval;
+}
+
+unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+{
+ int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
+ unsigned short retval = 0;
+ int i;
+
+ solo_eeprom_cmd(solo_dev, read_cmd);
+
+ for (i = 0; i < 16; i++) {
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
+ EE_SHIFT_CLK);
+ retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
+ solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
+ }
+
+ solo_eeprom_reg_write(solo_dev, ~EE_CS);
+
+ return retval;
+}
+
+int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
+ unsigned short data)
+{
+ int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
+ unsigned int retval;
+ int i;
+
+ solo_eeprom_cmd(solo_dev, write_cmd);
+
+ for (i = 15; i >= 0; i--) {
+ unsigned int dataval = (data >> i) & 1;
+
+ solo_eeprom_reg_write(solo_dev, EE_ENB);
+ solo_eeprom_reg_write(solo_dev,
+ EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
+ }
+
+ solo_eeprom_reg_write(solo_dev, EE_ENB);
+ solo_eeprom_reg_write(solo_dev, ~EE_CS);
+ solo_eeprom_reg_write(solo_dev, EE_ENB);
+
+ for (i = retval = 0; i < 10000 && !retval; i++)
+ retval = solo_eeprom_reg_read(solo_dev);
+
+ solo_eeprom_reg_write(solo_dev, ~EE_CS);
+
+ return !retval;
+}
diff --git a/drivers/staging/media/solo6x10/enc.c b/drivers/staging/media/solo6x10/solo6x10-enc.c
index de502599bb19..94d5735abf85 100644
--- a/drivers/staging/media/solo6x10/enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-enc.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -18,30 +23,41 @@
*/
#include <linux/kernel.h>
+#include <linux/font.h>
+#include <linux/bitrev.h>
#include <linux/slab.h>
-#include "solo6x10.h"
-#include "osd-font.h"
-#define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */
-#define OSG_BUFFER_SIZE 1024
+#include "solo6x10.h"
#define VI_PROG_HSIZE (1280 - 16)
#define VI_PROG_VSIZE (1024 - 16)
+#define IRQ_LEVEL 2
+
static void solo_capture_config(struct solo_dev *solo_dev)
{
- int i, j;
unsigned long height;
unsigned long width;
- unsigned char *buf;
+ void *buf;
+ int i;
solo_reg_write(solo_dev, SOLO_CAP_BASE,
- SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE *
- solo_dev->nr_chans) |
- SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
- solo_reg_write(solo_dev, SOLO_CAP_BTW,
- (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
- SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH));
+ SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev)
+ - SOLO_CAP_PAGE_SIZE) >> 16)
+ | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16));
+
+ /* XXX: Undocumented bits at b17 and b24 */
+ if (solo_dev->type == SOLO_DEV_6110) {
+ /* NOTE: Ref driver has (62 << 24) here as well, but it causes
+ * wacked out frame timing on 4-port 6110. */
+ solo_reg_write(solo_dev, SOLO_CAP_BTW,
+ (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+ SOLO_CAP_MAX_BANDWIDTH(36));
+ } else {
+ solo_reg_write(solo_dev, SOLO_CAP_BTW,
+ (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) |
+ SOLO_CAP_MAX_BANDWIDTH(32));
+ }
/* Set scale 1, 9 dimension */
width = solo_dev->video_hsize;
@@ -96,115 +112,212 @@ static void solo_capture_config(struct solo_dev *solo_dev)
solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16);
solo_reg_write(solo_dev, SOLO_VE_OSD_CLR,
0xF0 << 16 | 0x80 << 8 | 0x80);
- solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0);
+
+ if (solo_dev->type == SOLO_DEV_6010)
+ solo_reg_write(solo_dev, SOLO_VE_OSD_OPT,
+ SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
+ else
+ solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE
+ | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW);
/* Clear OSG buffer */
- buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL);
+ buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL);
if (!buf)
return;
for (i = 0; i < solo_dev->nr_chans; i++) {
- for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) {
- solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf,
- SOLO_EOSD_EXT_ADDR +
- (i * SOLO_EOSD_EXT_SIZE) + j,
- OSG_BUFFER_SIZE);
- }
+ solo_p2m_dma(solo_dev, 1, buf,
+ SOLO_EOSD_EXT_ADDR +
+ (SOLO_EOSD_EXT_SIZE(solo_dev) * i),
+ SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0);
}
kfree(buf);
}
+/* Should be called with enable_lock held */
int solo_osd_print(struct solo_enc_dev *solo_enc)
{
struct solo_dev *solo_dev = solo_enc->solo_dev;
- char *str = solo_enc->osd_text;
- u8 *buf;
+ unsigned char *str = solo_enc->osd_text;
+ u8 *buf = solo_enc->osd_buf;
u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
- int len = strlen(str);
+ const struct font_desc *vga = find_font("VGA8x16");
+ const unsigned char *vga_data;
+ int len;
int i, j;
- int x = 1, y = 1;
+
+ if (WARN_ON_ONCE(!vga))
+ return -ENODEV;
+
+ len = strlen(str);
if (len == 0) {
+ /* Disable OSD on this channel */
reg &= ~(1 << solo_enc->ch);
solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
return 0;
}
- buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX);
+ vga_data = (const unsigned char *)vga->data;
for (i = 0; i < len; i++) {
+ unsigned char c = str[i];
+
for (j = 0; j < 16; j++) {
- buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] =
- (solo_osd_font[(str[i] * 4) + (j / 4)]
- >> ((3 - (j % 4)) * 8)) & 0xff;
+ buf[(j * 2) + (i % 2) + (i / 2 * 32)] =
+ bitrev8(vga_data[(c * 16) + j]);
}
}
- solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR +
- (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE);
+ solo_p2m_dma(solo_dev, 1, buf,
+ SOLO_EOSD_EXT_ADDR +
+ (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)),
+ SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0);
+
+ /* Enable OSD on this channel */
reg |= (1 << solo_enc->ch);
solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
- kfree(buf);
-
return 0;
}
+/**
+ * Set channel Quality Profile (0-3).
+ */
+void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
+ unsigned int qp)
+{
+ unsigned long flags;
+ unsigned int idx, reg;
+
+ if ((ch > 31) || (qp > 3))
+ return;
+
+ if (solo_dev->type == SOLO_DEV_6010)
+ return;
+
+ if (ch < 16) {
+ idx = 0;
+ reg = SOLO_VE_JPEG_QP_CH_L;
+ } else {
+ ch -= 16;
+ idx = 1;
+ reg = SOLO_VE_JPEG_QP_CH_H;
+ }
+ ch *= 2;
+
+ spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags);
+
+ solo_dev->jpeg_qp[idx] &= ~(3 << ch);
+ solo_dev->jpeg_qp[idx] |= (qp & 3) << ch;
+
+ solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]);
+
+ spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags);
+}
+
+int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch)
+{
+ int idx;
+
+ if (solo_dev->type == SOLO_DEV_6010)
+ return 2;
+
+ if (WARN_ON_ONCE(ch > 31))
+ return 2;
+
+ if (ch < 16) {
+ idx = 0;
+ } else {
+ ch -= 16;
+ idx = 1;
+ }
+ ch *= 2;
+
+ return (solo_dev->jpeg_qp[idx] >> ch) & 3;
+}
+
+#define SOLO_QP_INIT 0xaaaaaaaa
+
static void solo_jpeg_config(struct solo_dev *solo_dev)
{
- u32 reg;
- if (solo_dev->flags & FLAGS_6110)
- reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0);
- else
- reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0);
- solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg);
- solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0);
- solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0);
+ if (solo_dev->type == SOLO_DEV_6010) {
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
+ (2 << 24) | (2 << 16) | (2 << 8) | 2);
+ } else {
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL,
+ (4 << 24) | (3 << 16) | (2 << 8) | 1);
+ }
+
+ spin_lock_init(&solo_dev->jpeg_qp_lock);
+
+ /* Initialize Quality Profile for all channels */
+ solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT;
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT);
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT);
+
solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG,
(SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) |
((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff));
solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff);
- /* que limit, samp limit, pos limit */
- solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60);
+ if (solo_dev->type == SOLO_DEV_6110) {
+ solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1,
+ (0 << 16) | (30 << 8) | 60);
+ }
}
static void solo_mp4e_config(struct solo_dev *solo_dev)
{
int i;
- u32 reg;
+ u32 cfg;
- /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */
solo_reg_write(solo_dev, SOLO_VE_CFG0,
- SOLO_VE_INTR_CTRL(0) |
+ SOLO_VE_INTR_CTRL(IRQ_LEVEL) |
SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) |
SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16));
- solo_reg_write(solo_dev, SOLO_VE_CFG1,
- SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0));
+
+ cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX
+ | SOLO_VE_MOTION_MODE(0);
+ if (solo_dev->type != SOLO_DEV_6010) {
+ cfg |= SOLO_VE_MPEG_SIZE_H(
+ (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f);
+ cfg |= SOLO_VE_JPEG_SIZE_H(
+ (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f);
+ }
+ solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg);
solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0);
solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0);
solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0);
+ if (solo_dev->type == SOLO_DEV_6110)
+ solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0);
solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0);
- reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) |
- SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15);
- if (solo_dev->flags & FLAGS_6110)
- reg |= SOLO_DCT_INTERVAL(10);
- else
- reg |= SOLO_DCT_INTERVAL(36 / 4);
- solo_reg_write(solo_dev, SOLO_VE_ATTR, reg);
+ solo_reg_write(solo_dev, SOLO_VE_ATTR,
+ SOLO_VE_LITTLE_ENDIAN |
+ SOLO_COMP_ATTR_FCODE(1) |
+ SOLO_COMP_TIME_INC(0) |
+ SOLO_COMP_TIME_WIDTH(15) |
+ SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10));
- for (i = 0; i < solo_dev->nr_chans; i++)
+ for (i = 0; i < solo_dev->nr_chans; i++) {
solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i),
(SOLO_EREF_EXT_ADDR(solo_dev) +
(i * SOLO_EREF_EXT_SIZE)) >> 16);
+ solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i),
+ (SOLO_EREF_EXT_ADDR(solo_dev) +
+ ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16);
+ }
- if (solo_dev->flags & FLAGS_6110)
- solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */
+ if (solo_dev->type == SOLO_DEV_6110) {
+ solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008);
+ } else {
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100);
+ }
}
int solo_enc_init(struct solo_dev *solo_dev)
@@ -220,8 +333,6 @@ int solo_enc_init(struct solo_dev *solo_dev)
solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
}
- solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
-
return 0;
}
@@ -229,8 +340,6 @@ void solo_enc_exit(struct solo_dev *solo_dev)
{
int i;
- solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
-
for (i = 0; i < solo_dev->nr_chans; i++) {
solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0);
solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0);
diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/solo6x10-g723.c
index 2cd0de28a633..1db18c7972a0 100644
--- a/drivers/staging/media/solo6x10/g723.c
+++ b/drivers/staging/media/solo6x10/solo6x10-g723.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -21,17 +26,18 @@
#include <linux/mempool.h>
#include <linux/poll.h>
#include <linux/kthread.h>
-#include <linux/slab.h>
#include <linux/freezer.h>
-#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/control.h>
+
#include "solo6x10.h"
-#include "tw28.h"
+#include "solo6x10-tw28.h"
-#define G723_INTR_ORDER 0
#define G723_FDMA_PAGES 32
#define G723_PERIOD_BYTES 48
#define G723_PERIOD_BLOCK 1024
@@ -46,36 +52,40 @@
/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page
* is broken down to 20 * 48 byte regions (one for each channel possible)
* with the rest of the page being dummy data. */
-#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
-#define IRQ_PAGES 4 /* 0 - 4 */
-#define PERIODS_MIN (1 << IRQ_PAGES)
+#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX)
+#define G723_INTR_ORDER 4 /* 0 - 4 */
+#define PERIODS_MIN (1 << G723_INTR_ORDER)
#define PERIODS_MAX G723_FDMA_PAGES
struct solo_snd_pcm {
- int on;
- spinlock_t lock;
- struct solo_dev *solo_dev;
- unsigned char g723_buf[G723_PERIOD_BYTES];
+ int on;
+ spinlock_t lock;
+ struct solo_dev *solo_dev;
+ unsigned char *g723_buf;
+ dma_addr_t g723_dma;
};
static void solo_g723_config(struct solo_dev *solo_dev)
{
int clk_div;
- clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2);
+ clk_div = (solo_dev->clock_mhz * 1000000)
+ / (SAMPLERATE * (BITRATE * 2) * 2);
solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE,
- SOLO_AUDIO_BITRATE(BITRATE) |
- SOLO_AUDIO_CLK_DIV(clk_div));
+ SOLO_AUDIO_BITRATE(BITRATE)
+ | SOLO_AUDIO_CLK_DIV(clk_div));
solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR,
- SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) |
- SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) |
- SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
+ SOLO_AUDIO_FDMA_INTERVAL(1)
+ | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER)
+ | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16));
solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL,
- SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE |
- SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK));
+ SOLO_AUDIO_ENABLE
+ | SOLO_AUDIO_I2S_MODE
+ | SOLO_AUDIO_I2S_MULTI(3)
+ | SOLO_AUDIO_MODE(OUTMODE_MASK));
}
void solo_g723_isr(struct solo_dev *solo_dev)
@@ -85,8 +95,6 @@ void solo_g723_isr(struct solo_dev *solo_dev)
struct snd_pcm_substream *ss;
struct solo_snd_pcm *solo_pcm;
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723);
-
for (ss = pstr->substream; ss != NULL; ss = ss->next) {
if (snd_pcm_substream_chip(ss) == NULL)
continue;
@@ -115,18 +123,18 @@ static int snd_solo_hw_free(struct snd_pcm_substream *ss)
return snd_pcm_lib_free_pages(ss);
}
-static struct snd_pcm_hardware snd_solo_pcm_hw = {
+static const struct snd_pcm_hardware snd_solo_pcm_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U8,
.rates = SNDRV_PCM_RATE_8000,
- .rate_min = 8000,
- .rate_max = 8000,
+ .rate_min = SAMPLERATE,
+ .rate_max = SAMPLERATE,
.channels_min = 1,
.channels_max = 1,
- .buffer_bytes_max = MAX_BUFFER,
+ .buffer_bytes_max = G723_MAX_BUFFER,
.period_bytes_min = G723_PERIOD_BYTES,
.period_bytes_max = G723_PERIOD_BYTES,
.periods_min = PERIODS_MIN,
@@ -140,7 +148,13 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL);
if (solo_pcm == NULL)
- return -ENOMEM;
+ goto oom;
+
+ solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev,
+ G723_PERIOD_BYTES,
+ &solo_pcm->g723_dma);
+ if (solo_pcm->g723_buf == NULL)
+ goto oom;
spin_lock_init(&solo_pcm->lock);
solo_pcm->solo_dev = solo_dev;
@@ -149,6 +163,10 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss)
snd_pcm_substream_chip(ss) = solo_pcm;
return 0;
+
+oom:
+ kfree(solo_pcm);
+ return -ENOMEM;
}
static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
@@ -156,6 +174,8 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss)
struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
snd_pcm_substream_chip(ss) = solo_pcm->solo_dev;
+ pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES,
+ solo_pcm->g723_buf, solo_pcm->g723_dma);
kfree(solo_pcm);
return 0;
@@ -220,12 +240,11 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) {
int page = (pos / G723_FRAMES_PER_PAGE) + i;
- err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0,
- solo_pcm->g723_buf,
- SOLO_G723_EXT_ADDR(solo_dev) +
- (page * G723_PERIOD_BLOCK) +
- (ss->number * G723_PERIOD_BYTES),
- G723_PERIOD_BYTES);
+ err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma,
+ SOLO_G723_EXT_ADDR(solo_dev) +
+ (page * G723_PERIOD_BLOCK) +
+ (ss->number * G723_PERIOD_BYTES),
+ G723_PERIOD_BYTES, 0, 0);
if (err)
return err;
@@ -325,7 +344,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev)
ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL),
- MAX_BUFFER, MAX_BUFFER);
+ G723_MAX_BUFFER, G723_MAX_BUFFER);
if (ret < 0)
return ret;
@@ -368,6 +387,7 @@ int solo_g723_init(struct solo_dev *solo_dev)
strcpy(card->mixername, "SOLO-6x10");
kctl = snd_solo_capture_volume;
kctl.count = solo_dev->nr_chans;
+
ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev));
if (ret < 0)
return ret;
@@ -393,8 +413,12 @@ snd_error:
void solo_g723_exit(struct solo_dev *solo_dev)
{
+ if (!solo_dev->snd_card)
+ return;
+
solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0);
solo_irq_off(solo_dev, SOLO_IRQ_G723);
snd_card_free(solo_dev->snd_card);
+ solo_dev->snd_card = NULL;
}
diff --git a/drivers/staging/media/solo6x10/gpio.c b/drivers/staging/media/solo6x10/solo6x10-gpio.c
index 0925e6f33a99..73276dc92875 100644
--- a/drivers/staging/media/solo6x10/gpio.c
+++ b/drivers/staging/media/solo6x10/solo6x10-gpio.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -19,7 +24,9 @@
#include <linux/kernel.h>
#include <linux/fs.h>
-#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
#include "solo6x10.h"
static void solo_gpio_mode(struct solo_dev *solo_dev,
diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/solo6x10-i2c.c
index 398070a3d293..01aa417c9258 100644
--- a/drivers/staging/media/solo6x10/i2c.c
+++ b/drivers/staging/media/solo6x10/solo6x10-i2c.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -26,6 +31,7 @@
* thread context, ACK the interrupt, and move on. -- BenC */
#include <linux/kernel.h>
+
#include "solo6x10.h"
u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
@@ -173,10 +179,9 @@ int solo_i2c_isr(struct solo_dev *solo_dev)
u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
int ret = -EINVAL;
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC);
- if (status & (SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) ||
- solo_dev->i2c_id < 0) {
+ if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR)
+ || solo_dev->i2c_id < 0) {
solo_i2c_stop(solo_dev);
return -ENXIO;
}
@@ -239,7 +244,8 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap,
timeout = HZ / 2;
for (;;) {
- prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE);
+ prepare_to_wait(&solo_dev->i2c_wait, &wait,
+ TASK_INTERRUPTIBLE);
if (solo_dev->i2c_state == IIC_STATE_STOP)
break;
@@ -267,7 +273,7 @@ static u32 solo_i2c_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C;
}
-static struct i2c_algorithm solo_i2c_algo = {
+static const struct i2c_algorithm solo_i2c_algo = {
.master_xfer = solo_i2c_master_xfer,
.functionality = solo_i2c_functionality,
};
@@ -288,7 +294,8 @@ int solo_i2c_init(struct solo_dev *solo_dev)
for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
- snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i);
+ snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
+ SOLO6X10_NAME, i);
adap->algo = &solo_i2c_algo;
adap->algo_data = solo_dev;
adap->retries = 1;
@@ -311,9 +318,6 @@ int solo_i2c_init(struct solo_dev *solo_dev)
return ret;
}
- dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n",
- SOLO_I2C_ADAPTERS);
-
return 0;
}
diff --git a/drivers/staging/media/solo6x10/solo6x10-jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h
index 50defec318cc..c5218ceeabca 100644
--- a/drivers/staging/media/solo6x10/solo6x10-jpeg.h
+++ b/drivers/staging/media/solo6x10/solo6x10-jpeg.h
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -20,7 +25,7 @@
#ifndef __SOLO6X10_JPEG_H
#define __SOLO6X10_JPEG_H
-static unsigned char jpeg_header[] = {
+static const unsigned char jpeg_header[] = {
0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
@@ -102,4 +107,87 @@ static unsigned char jpeg_header[] = {
/* This is the byte marker for the start of SOF0: 0xffc0 marker */
#define SOF0_START 575
+/* This is the byte marker for the start of the DQT */
+#define DQT_START 17
+#define DQT_LEN 138
+const unsigned char jpeg_dqt[4][DQT_LEN] = {
+ {
+ 0xff, 0xdb, 0x00, 0x43, 0x00,
+ 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
+ 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14,
+ 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13,
+ 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a,
+ 0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22,
+ 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c,
+ 0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39,
+ 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32,
+ 0xff, 0xdb, 0x00, 0x43, 0x01,
+ 0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d,
+ 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32
+ }, {
+ 0xff, 0xdb, 0x00, 0x43, 0x00,
+ 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
+ 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
+ 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
+ 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33,
+ 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44,
+ 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57,
+ 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
+ 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
+ 0xff, 0xdb, 0x00, 0x43, 0x01,
+ 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
+ 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
+ }, {
+ 0xff, 0xdb, 0x00, 0x43, 0x00,
+ 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c,
+ 0x1a, 0x1c, 0x24, 0x22, 0x20, 0x26, 0x30, 0x50,
+ 0x34, 0x30, 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a,
+ 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66,
+ 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88,
+ 0xae, 0x8a, 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae,
+ 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2,
+ 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6,
+ 0xff, 0xdb, 0x00, 0x43, 0x01,
+ 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34,
+ 0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
+ 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6
+ }, {
+ 0xff, 0xdb, 0x00, 0x43, 0x00,
+ 0x30, 0x21, 0x24, 0x2a, 0x24, 0x1e, 0x30, 0x2a,
+ 0x27, 0x2a, 0x36, 0x33, 0x30, 0x39, 0x48, 0x78,
+ 0x4e, 0x48, 0x42, 0x42, 0x48, 0x93, 0x69, 0x6f,
+ 0x57, 0x78, 0xae, 0x99, 0xb7, 0xb4, 0xab, 0x99,
+ 0xa8, 0xa5, 0xc0, 0xd8, 0xff, 0xea, 0xc0, 0xcc,
+ 0xff, 0xcf, 0xa5, 0xa8, 0xf0, 0xff, 0xf3, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xe7, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xdb, 0x00, 0x43, 0x01,
+ 0x33, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e,
+ 0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ }
+};
+
#endif /* __SOLO6X10_JPEG_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-offsets.h b/drivers/staging/media/solo6x10/solo6x10-offsets.h
new file mode 100644
index 000000000000..f005dca501f1
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-offsets.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __SOLO6X10_OFFSETS_H
+#define __SOLO6X10_OFFSETS_H
+
+#define SOLO_DISP_EXT_ADDR 0x00000000
+#define SOLO_DISP_EXT_SIZE 0x00480000
+
+#define SOLO_EOSD_EXT_ADDR \
+ (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE)
+#define SOLO_EOSD_EXT_SIZE(__solo) \
+ (__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000)
+#define SOLO_EOSD_EXT_SIZE_MAX 0x20000
+#define SOLO_EOSD_EXT_AREA(__solo) \
+ (SOLO_EOSD_EXT_SIZE(__solo) * 32)
+
+#define SOLO_MOTION_EXT_ADDR(__solo) \
+ (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo))
+#define SOLO_MOTION_EXT_SIZE 0x00080000
+
+#define SOLO_G723_EXT_ADDR(__solo) \
+ (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE)
+#define SOLO_G723_EXT_SIZE 0x00010000
+
+#define SOLO_CAP_EXT_ADDR(__solo) \
+ (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE)
+
+/* 18 is the maximum number of pages required for PAL@D1, the largest frame
+ * possible */
+#define SOLO_CAP_PAGE_SIZE (18 << 16)
+
+/* Always allow the encoder enough for 16 channels, even if we have less. The
+ * exception is if we have card with only 32Megs of memory. */
+#define SOLO_CAP_EXT_SIZE(__solo) \
+ ((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1) \
+ * SOLO_CAP_PAGE_SIZE)
+
+#define SOLO_EREF_EXT_ADDR(__solo) \
+ (SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo))
+#define SOLO_EREF_EXT_SIZE 0x00140000
+#define SOLO_EREF_EXT_AREA(__solo) \
+ (SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2)
+
+#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000)
+
+#define SOLO_MP4E_EXT_ADDR(__solo) \
+ (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo))
+#define SOLO_MP4E_EXT_SIZE(__solo) \
+ max((__solo->nr_chans * 0x00080000), \
+ min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \
+ __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000))
+
+#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000)
+#define SOLO_JPEG_EXT_ADDR(__solo) \
+ (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo))
+#define SOLO_JPEG_EXT_SIZE(__solo) \
+ max(__SOLO_JPEG_MIN_SIZE(__solo), \
+ min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000))
+
+#define SOLO_SDRAM_END(__solo) \
+ (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo))
+
+#endif /* __SOLO6X10_OFFSETS_H */
diff --git a/drivers/staging/media/solo6x10/solo6x10-p2m.c b/drivers/staging/media/solo6x10/solo6x10-p2m.c
new file mode 100644
index 000000000000..333594189b81
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-p2m.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "solo6x10.h"
+
+static int multi_p2m;
+module_param(multi_p2m, uint, 0644);
+MODULE_PARM_DESC(multi_p2m,
+ "Use multiple P2M DMA channels (default: no, 6010-only)");
+
+static int desc_mode;
+module_param(desc_mode, uint, 0644);
+MODULE_PARM_DESC(desc_mode,
+ "Allow use of descriptor mode DMA (default: no, 6010-only)");
+
+int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
+ void *sys_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size)
+{
+ dma_addr_t dma_addr;
+ int ret;
+
+ if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03))
+ return -EINVAL;
+ if (WARN_ON_ONCE(!size))
+ return -EINVAL;
+
+ dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size,
+ wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(solo_dev->pdev, dma_addr))
+ return -ENOMEM;
+
+ ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size,
+ repeat, ext_size);
+
+ pci_unmap_single(solo_dev->pdev, dma_addr, size,
+ wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+ return ret;
+}
+
+/* Mutex must be held for p2m_id before calling this!! */
+int solo_p2m_dma_desc(struct solo_dev *solo_dev,
+ struct solo_p2m_desc *desc, dma_addr_t desc_dma,
+ int desc_cnt)
+{
+ struct solo_p2m_dev *p2m_dev;
+ unsigned int timeout;
+ unsigned int config = 0;
+ int ret = 0;
+ int p2m_id = 0;
+
+ /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */
+ if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) {
+ p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M;
+ if (p2m_id < 0)
+ p2m_id = -p2m_id;
+ }
+
+ p2m_dev = &solo_dev->p2m_dev[p2m_id];
+
+ if (mutex_lock_interruptible(&p2m_dev->mutex))
+ return -EINTR;
+
+ INIT_COMPLETION(p2m_dev->completion);
+ p2m_dev->error = 0;
+
+ if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) {
+ /* For 6010 with more than one desc, we can do a one-shot */
+ p2m_dev->desc_count = p2m_dev->desc_idx = 0;
+ config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id));
+
+ solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma);
+ solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt);
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config |
+ SOLO_P2M_DESC_MODE);
+ } else {
+ /* For single descriptors and 6110, we need to run each desc */
+ p2m_dev->desc_count = desc_cnt;
+ p2m_dev->desc_idx = 1;
+ p2m_dev->descs = desc;
+
+ solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id),
+ desc[1].dma_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id),
+ desc[1].ext_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id),
+ desc[1].cfg);
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id),
+ desc[1].ctrl);
+ }
+
+ timeout = wait_for_completion_timeout(&p2m_dev->completion,
+ solo_dev->p2m_jiffies);
+
+ if (WARN_ON_ONCE(p2m_dev->error))
+ ret = -EIO;
+ else if (timeout == 0) {
+ solo_dev->p2m_timeouts++;
+ ret = -EAGAIN;
+ }
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0);
+
+ /* Don't write here for the no_desc_mode case, because config is 0.
+ * We can't test no_desc_mode again, it might race. */
+ if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config)
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config);
+
+ mutex_unlock(&p2m_dev->mutex);
+
+ return ret;
+}
+
+void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size)
+{
+ WARN_ON_ONCE(dma_addr & 0x03);
+ WARN_ON_ONCE(!size);
+
+ desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2);
+ desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
+ (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON;
+
+ if (repeat) {
+ desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2);
+ desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) |
+ SOLO_P2M_REPEAT(repeat);
+ }
+
+ desc->dma_addr = dma_addr;
+ desc->ext_addr = ext_addr;
+}
+
+int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size)
+{
+ struct solo_p2m_desc desc[2];
+
+ solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat,
+ ext_size);
+
+ /* No need for desc_dma since we know it is a single-shot */
+ return solo_p2m_dma_desc(solo_dev, desc, 0, 1);
+}
+
+void solo_p2m_isr(struct solo_dev *solo_dev, int id)
+{
+ struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
+ struct solo_p2m_desc *desc;
+
+ if (p2m_dev->desc_count <= p2m_dev->desc_idx) {
+ complete(&p2m_dev->completion);
+ return;
+ }
+
+ /* Setup next descriptor */
+ p2m_dev->desc_idx++;
+ desc = &p2m_dev->descs[p2m_dev->desc_idx];
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
+ solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr);
+ solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg);
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl);
+}
+
+void solo_p2m_error_isr(struct solo_dev *solo_dev)
+{
+ unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
+ struct solo_p2m_dev *p2m_dev;
+ int i;
+
+ if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC)))
+ return;
+
+ for (i = 0; i < SOLO_NR_P2M; i++) {
+ p2m_dev = &solo_dev->p2m_dev[i];
+ p2m_dev->error = 1;
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+ complete(&p2m_dev->completion);
+ }
+}
+
+void solo_p2m_exit(struct solo_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < SOLO_NR_P2M; i++)
+ solo_irq_off(solo_dev, SOLO_IRQ_P2M(i));
+}
+
+static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size)
+{
+ u32 *wr_buf;
+ u32 *rd_buf;
+ int i;
+ int ret = -EIO;
+ int order = get_order(size);
+
+ wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
+ if (wr_buf == NULL)
+ return -1;
+
+ rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order);
+ if (rd_buf == NULL) {
+ free_pages((unsigned long)wr_buf, order);
+ return -1;
+ }
+
+ for (i = 0; i < (size >> 3); i++)
+ *(wr_buf + i) = (i << 16) | (i + 1);
+
+ for (i = (size >> 3); i < (size >> 2); i++)
+ *(wr_buf + i) = ~((i << 16) | (i + 1));
+
+ memset(rd_buf, 0x55, size);
+
+ if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0))
+ goto test_fail;
+
+ if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0))
+ goto test_fail;
+
+ for (i = 0; i < (size >> 2); i++) {
+ if (*(wr_buf + i) != *(rd_buf + i))
+ goto test_fail;
+ }
+
+ ret = 0;
+
+test_fail:
+ free_pages((unsigned long)wr_buf, order);
+ free_pages((unsigned long)rd_buf, order);
+
+ return ret;
+}
+
+int solo_p2m_init(struct solo_dev *solo_dev)
+{
+ struct solo_p2m_dev *p2m_dev;
+ int i;
+
+ for (i = 0; i < SOLO_NR_P2M; i++) {
+ p2m_dev = &solo_dev->p2m_dev[i];
+
+ mutex_init(&p2m_dev->mutex);
+ init_completion(&p2m_dev->completion);
+
+ solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
+ solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i),
+ SOLO_P2M_CSC_16BIT_565 |
+ SOLO_P2M_DESC_INTR_OPT |
+ SOLO_P2M_DMA_INTERVAL(0) |
+ SOLO_P2M_PCI_MASTER_MODE);
+ solo_irq_on(solo_dev, SOLO_IRQ_P2M(i));
+ }
+
+ /* Find correct SDRAM size */
+ for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) {
+ solo_reg_write(solo_dev, SOLO_DMA_CTRL,
+ SOLO_DMA_CTRL_REFRESH_CYCLE(1) |
+ SOLO_DMA_CTRL_SDRAM_SIZE(i) |
+ SOLO_DMA_CTRL_SDRAM_CLK_INVERT |
+ SOLO_DMA_CTRL_READ_CLK_SELECT |
+ SOLO_DMA_CTRL_LATENCY(1));
+
+ solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config |
+ SOLO_SYS_CFG_RESET);
+ solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config);
+
+ switch (i) {
+ case 2:
+ if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) ||
+ solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000))
+ continue;
+ break;
+
+ case 1:
+ if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000))
+ continue;
+ break;
+
+ default:
+ if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000))
+ continue;
+ }
+
+ solo_dev->sdram_size = (32 << 20) << i;
+ break;
+ }
+
+ if (!solo_dev->sdram_size) {
+ dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n");
+ return -EIO;
+ }
+
+ if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) {
+ dev_err(&solo_dev->pdev->dev,
+ "SDRAM is not large enough (%u < %u)\n",
+ solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev));
+ return -EIO;
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/media/solo6x10/registers.h b/drivers/staging/media/solo6x10/solo6x10-regs.h
index aca544472c93..428f6c951180 100644
--- a/drivers/staging/media/solo6x10/registers.h
+++ b/drivers/staging/media/solo6x10/solo6x10-regs.h
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -20,20 +25,20 @@
#ifndef __SOLO6X10_REGISTERS_H
#define __SOLO6X10_REGISTERS_H
-#include "offsets.h"
+#include "solo6x10-offsets.h"
-/* Global 6X10 system configuration */
+/* Global 6010 system configuration */
#define SOLO_SYS_CFG 0x0000
-#define SOLO6010_SYS_CFG_FOUT_EN 0x00000001 /* 6010 only */
-#define SOLO6010_SYS_CFG_PLL_BYPASS 0x00000002 /* 6010 only */
-#define SOLO6010_SYS_CFG_PLL_PWDN 0x00000004 /* 6010 only */
-#define SOLO6010_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) /* 6010 only */
-#define SOLO6010_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) /* 6010 only */
-#define SOLO6010_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) /* 6010 only */
+#define SOLO_SYS_CFG_FOUT_EN 0x00000001
+#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002
+#define SOLO_SYS_CFG_PLL_PWDN 0x00000004
+#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3)
+#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5)
+#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14)
#define SOLO_SYS_CFG_CLOCK_DIV 0x00080000
#define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24)
#define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26)
-#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 /* 6110: must be set */
+#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000
#define SOLO_SYS_CFG_RESET 0x80000000
#define SOLO_DMA_CTRL 0x0004
@@ -45,7 +50,9 @@
#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3)
#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2)
#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0)
-#define SOLO_DMA_CTRL1 0x0008
+
+/* Some things we set in this are undocumented. Why Softlogic?!?! */
+#define SOLO_DMA_CTRL1 0x0008
#define SOLO_SYS_VCLK 0x000C
#define SOLO_VCLK_INVERT (1<<22)
@@ -61,7 +68,7 @@
#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0)
#define SOLO_IRQ_STAT 0x0010
-#define SOLO_IRQ_ENABLE 0x0014
+#define SOLO_IRQ_MASK 0x0014
#define SOLO_IRQ_P2M(n) (1<<((n)+17))
#define SOLO_IRQ_GPIO (1<<16)
#define SOLO_IRQ_VIDEO_LOSS (1<<15)
@@ -82,22 +89,7 @@
#define SOLO_CHIP_OPTION 0x001C
#define SOLO_CHIP_ID_MASK 0x00000007
-#define SOLO6110_PLL_CONFIG 0x0020
-#define SOLO6110_PLL_RANGE_BYPASS (0 << 20)
-#define SOLO6110_PLL_RANGE_5_10MHZ (1 << 20)
-#define SOLO6110_PLL_RANGE_8_16MHZ (2 << 20)
-#define SOLO6110_PLL_RANGE_13_26MHZ (3 << 20)
-#define SOLO6110_PLL_RANGE_21_42MHZ (4 << 20)
-#define SOLO6110_PLL_RANGE_34_68MHZ (5 << 20)
-#define SOLO6110_PLL_RANGE_54_108MHZ (6 << 20)
-#define SOLO6110_PLL_RANGE_88_200MHZ (7 << 20)
-#define SOLO6110_PLL_DIVR(x) (((x) - 1) << 15)
-#define SOLO6110_PLL_DIVQ_EXP(x) ((x) << 12)
-#define SOLO6110_PLL_DIVF(x) (((x) - 1) << 4)
-#define SOLO6110_PLL_RESET (1 << 3)
-#define SOLO6110_PLL_BYPASS (1 << 2)
-#define SOLO6110_PLL_FSEN (1 << 1)
-#define SOLO6110_PLL_FB (1 << 0)
+#define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */
#define SOLO_EEPROM_CTRL 0x0060
#define SOLO_EEPROM_ACCESS_EN (1<<7)
@@ -105,7 +97,7 @@
#define SOLO_EEPROM_CLK (1<<2)
#define SOLO_EEPROM_DO (1<<1)
#define SOLO_EEPROM_DI (1<<0)
-#define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS)
+#define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS)
#define SOLO_PCI_ERR 0x0070
#define SOLO_PCI_ERR_FATAL 0x00000001
@@ -274,8 +266,8 @@
#define SOLO_VO_FI_CHANGE (1<<20)
#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19)
#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18)
-#define SOLO_VO_USER_COLOR_SET_NAV (1<<17)
-#define SOLO_VO_USER_COLOR_SET_NAH (1<<16)
+#define SOLO_VO_USER_COLOR_SET_NAH (1<<17)
+#define SOLO_VO_USER_COLOR_SET_NAV (1<<16)
#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8)
#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4)
#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0)
@@ -401,12 +393,13 @@
#define SOLO_VE_BLOCK_BASE(n) ((n)<<0)
#define SOLO_VE_CFG1 0x0614
-#define SOLO6110_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 only */
-#define SOLO6010_VE_BYTE_ALIGN(n) ((n)<<24) /* 6010 only */
-#define SOLO6110_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 only */
+#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24)
#define SOLO_VE_INSERT_INDEX (1<<18)
#define SOLO_VE_MOTION_MODE(n) ((n)<<16)
#define SOLO_VE_MOTION_BASE(n) ((n)<<0)
+#define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */
+#define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */
+#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */
#define SOLO_VE_WMRK_POLY 0x061C
#define SOLO_VE_VMRK_INIT_KEY 0x0620
@@ -420,6 +413,7 @@
#define SOLO_COMP_TIME_INC(n) ((n)<<25)
#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21)
#define SOLO_DCT_INTERVAL(n) ((n)<<16)
+#define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */
#define SOLO_VE_STATE(n) (0x0640+((n)*4))
@@ -428,14 +422,21 @@
#define SOLO_VE_JPEG_QP_CH_H 0x0678
#define SOLO_VE_JPEG_CFG 0x067C
#define SOLO_VE_JPEG_CTRL 0x0680
-
+#define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */
+#define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */
+#define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */
#define SOLO_VE_OSD_CH 0x0690
#define SOLO_VE_OSD_BASE 0x0694
#define SOLO_VE_OSD_CLR 0x0698
#define SOLO_VE_OSD_OPT 0x069C
+#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */
+#define SOLO_VE_OSD_H_SHADOW (1<<15)
+#define SOLO_VE_OSD_V_SHADOW (1<<14)
+#define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7)
+#define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f)
#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4))
-#define SOLO6010_VE_CH_MOT(ch) (0x0740+((ch)*4)) /* 6010 only */
+#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4))
#define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4))
#define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4))
#define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4))
@@ -447,7 +448,7 @@
#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8))
#define SOLO_VD_CFG0 0x0900
-#define SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) /* 6010 only */
+#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24)
#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23)
#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22)
#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21)
@@ -599,9 +600,9 @@
#define SOLO_UART_RX_DATA_POP (1<<8)
#define SOLO_TIMER_CLOCK_NUM 0x0be0
-#define SOLO_TIMER_WATCHDOG 0x0be4
#define SOLO_TIMER_USEC 0x0be8
#define SOLO_TIMER_SEC 0x0bec
+#define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */
#define SOLO_AUDIO_CONTROL 0x0D00
#define SOLO_AUDIO_ENABLE (1<<31)
@@ -629,9 +630,10 @@
#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10))
#define SOLO_AUDIO_STA 0x0D14
-
-#define SOLO_WATCHDOG 0x0BE4
-#define WATCHDOG_STAT(status) (status<<8)
-#define WATCHDOG_TIME(sec) (sec&0xff)
+/*
+ * Watchdog configuration
+ */
+#define SOLO_WATCHDOG 0x0be4
+#define SOLO_WATCHDOG_SET(status, sec) (status << 8 | (sec & 0xff))
#endif /* __SOLO6X10_REGISTERS_H */
diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/solo6x10-tw28.c
index db56b42c56c6..ad00e2b60323 100644
--- a/drivers/staging/media/solo6x10/tw28.c
+++ b/drivers/staging/media/solo6x10/solo6x10-tw28.c
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -18,12 +23,12 @@
*/
#include <linux/kernel.h>
+#include <linux/delay.h>
+
#include "solo6x10.h"
-#include "tw28.h"
+#include "solo6x10-tw28.h"
-/* XXX: Some of these values are masked into an 8-bit regs, and shifted
- * around for other 8-bit regs. What are the magic bits in these values? */
-#define DEFAULT_HDELAY_NTSC (32 - 4)
+#define DEFAULT_HDELAY_NTSC (32 - 8)
#define DEFAULT_HACTIVE_NTSC (720 + 16)
#define DEFAULT_VDELAY_NTSC (7 - 2)
#define DEFAULT_VACTIVE_NTSC (240 + 4)
@@ -33,15 +38,16 @@
#define DEFAULT_VDELAY_PAL (6)
#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
-static u8 tbl_tw2864_template[] = {
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
- 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
- 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
- 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
- 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
- 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+
+static const u8 tbl_tw2864_ntsc_template[] = {
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+ 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+ 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+ 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+ 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
@@ -61,14 +67,49 @@ static u8 tbl_tw2864_template[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
- 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
- 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+ 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+ 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
};
-static u8 tbl_tw2865_ntsc_template[] = {
+static const u8 tbl_tw2864_pal_template[] = {
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
+ 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
+ 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
+ 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
+ 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+ 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+ 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
+ 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01,
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
+ 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+ 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+ 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+ 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
+ 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+ 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */
+ 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static const u8 tbl_tw2865_ntsc_template[] = {
0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
@@ -103,7 +144,7 @@ static u8 tbl_tw2865_ntsc_template[] = {
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
};
-static u8 tbl_tw2865_pal_template[] = {
+static const u8 tbl_tw2865_pal_template[] = {
0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
@@ -180,8 +221,8 @@ static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
msleep_interruptible(1);
}
-/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
- addr, off, val); */
+/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */
+/* addr, off, val); */
}
static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
@@ -216,16 +257,17 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
for (i = 0; i < 0xff; i++) {
/* Skip read only registers */
- if (i >= 0xb8 && i <= 0xc1)
- continue;
- if ((i & ~0x30) == 0x00 ||
- (i & ~0x30) == 0x0c ||
- (i & ~0x30) == 0x0d)
- continue;
- if (i >= 0xc4 && i <= 0xc7)
+ switch (i) {
+ case 0xb8 ... 0xc1:
+ case 0xc4 ... 0xc7:
+ case 0xfd:
continue;
- if (i == 0xfd)
+ }
+ switch (i & ~0x30) {
+ case 0x00:
+ case 0x0c ... 0x0d:
continue;
+ }
tw_write_and_verify(solo_dev, dev_addr, i,
tbl_tw2865_common[i]);
@@ -236,11 +278,15 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
{
- u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
+ u8 tbl_tw2864_common[256];
int i;
- memcpy(tbl_tw2864_common, tbl_tw2864_template,
- sizeof(tbl_tw2864_common));
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+ memcpy(tbl_tw2864_common, tbl_tw2864_pal_template,
+ sizeof(tbl_tw2864_common));
+ else
+ memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template,
+ sizeof(tbl_tw2864_common));
if (solo_dev->tw2865 == 0) {
/* IRQ Mode */
@@ -285,33 +331,19 @@ static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
}
}
- /* NTSC or PAL */
- if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
- for (i = 0; i < 4; i++) {
- tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
- tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
- tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
- tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
- tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
- }
- tbl_tw2864_common[0x9d] = 0x90;
- tbl_tw2864_common[0xf3] = 0x00;
- tbl_tw2864_common[0xf4] = 0xa0;
- }
-
for (i = 0; i < 0xff; i++) {
/* Skip read only registers */
- if (i >= 0xb8 && i <= 0xc1)
+ switch (i) {
+ case 0xb8 ... 0xc1:
+ case 0xfd:
continue;
- if ((i & ~0x30) == 0x00 ||
- (i & ~0x30) == 0x0c ||
- (i & ~0x30) == 0x0d)
- continue;
- if (i == 0x74 || i == 0x77 || i == 0x78 ||
- i == 0x79 || i == 0x7a)
- continue;
- if (i == 0xfd)
+ }
+ switch (i & ~0x30) {
+ case 0x00:
+ case 0x0c:
+ case 0x0d:
continue;
+ }
tw_write_and_verify(solo_dev, dev_addr, i,
tbl_tw2864_common[i]);
@@ -544,8 +576,10 @@ int solo_tw28_init(struct solo_dev *solo_dev)
int i;
u8 value;
- /* Detect techwell chip type */
- for (i = 0; i < TW_NUM_CHIP; i++) {
+ solo_dev->tw28_cnt = 0;
+
+ /* Detect techwell chip type(s) */
+ for (i = 0; i < solo_dev->nr_chans / 4; i++) {
value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(i), 0xFF);
@@ -560,7 +594,8 @@ int solo_tw28_init(struct solo_dev *solo_dev)
break;
default:
value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
- TW_CHIP_OFFSET_ADDR(i), 0x59);
+ TW_CHIP_OFFSET_ADDR(i),
+ 0x59);
if ((value >> 3) == 0x04) {
solo_dev->tw2815 |= 1 << i;
solo_dev->tw28_cnt++;
@@ -568,8 +603,11 @@ int solo_tw28_init(struct solo_dev *solo_dev)
}
}
- if (!solo_dev->tw28_cnt)
+ if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) {
+ dev_err(&solo_dev->pdev->dev,
+ "Could not initialize any techwell chips\n");
return -EINVAL;
+ }
saa7128_setup(solo_dev);
@@ -582,17 +620,6 @@ int solo_tw28_init(struct solo_dev *solo_dev)
tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
}
- dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
- solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
-
- if (solo_dev->tw2865)
- printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
- if (solo_dev->tw2864)
- printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
- if (solo_dev->tw2815)
- printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
- printk("\n");
-
return 0;
}
@@ -610,7 +637,7 @@ int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
chip_num = ch / 4;
ch %= 4;
- val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
+ val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR,
TW_AV_STAT_ADDR) & 0x0f;
return val & (1 << ch) ? 1 : 0;
@@ -626,7 +653,7 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev)
int i;
for (i = 0; i < solo_dev->tw28_cnt; i++) {
- val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
+ val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR,
TW_AV_STAT_ADDR) & 0xf0) >> 4;
status |= val << (i * 4);
}
@@ -635,7 +662,13 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev)
}
#endif
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
+bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
+{
+ return is_tw286x(solo_dev, ch / 4);
+}
+
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
+ s32 val)
{
char sval;
u8 chip_num;
@@ -650,8 +683,6 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
switch (ctrl) {
case V4L2_CID_SHARPNESS:
/* Only 286x has sharpness */
- if (val > 0x0f || val < 0)
- return -ERANGE;
if (is_tw286x(solo_dev, chip_num)) {
u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num),
@@ -661,8 +692,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num),
TW286x_SHARPNESS(chip_num), v);
- } else if (val != 0)
- return -ERANGE;
+ } else {
+ return -EINVAL;
+ }
break;
case V4L2_CID_HUE:
@@ -676,6 +708,7 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
break;
case V4L2_CID_SATURATION:
+ /* 286x chips have a U and V component for saturation */
if (is_tw286x(solo_dev, chip_num)) {
solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num),
diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/solo6x10-tw28.h
index a44a03afbd30..1a02c87d4cf0 100644
--- a/drivers/staging/media/solo6x10/tw28.h
+++ b/drivers/staging/media/solo6x10/solo6x10-tw28.h
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -36,7 +41,7 @@
#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0))
/* tw286x */
-#define TW286X_AV_STAT_ADDR 0xfd
+#define TW286x_AV_STAT_ADDR 0xfd
#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4))
#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4))
#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4))
@@ -50,6 +55,7 @@ int solo_tw28_init(struct solo_dev *solo_dev);
int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val);
int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val);
+bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch);
u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch);
void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val);
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
new file mode 100644
index 000000000000..98e2902afd74
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -0,0 +1,1385 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+#include "solo6x10-jpeg.h"
+
+#define MIN_VID_BUFFERS 2
+#define FRAME_BUF_SIZE (196 * 1024)
+#define MP4_QS 16
+#define DMA_ALIGN 4096
+
+/* 6010 M4V */
+static unsigned char vop_6010_ntsc_d1[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+ 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
+ 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+ 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_ntsc_cif[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+ 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
+ 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+ 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_pal_d1[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+ 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
+ 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+ 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
+};
+
+static unsigned char vop_6010_pal_cif[] = {
+ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
+ 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
+ 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
+ 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f,
+};
+
+/* 6110 h.264 */
+static unsigned char vop_6110_ntsc_d1[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+ 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
+ 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_ntsc_cif[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+ 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
+ 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_pal_d1[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+ 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
+ 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
+};
+
+static unsigned char vop_6110_pal_cif[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
+ 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
+ 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
+};
+
+struct vop_header {
+ /* VE_STATUS0 */
+ u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2,
+ channel:5, source_fl:1, interlace:1, progressive:1;
+
+ /* VE_STATUS1 */
+ u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4;
+
+ /* VE_STATUS2 */
+ u32 mpeg_off;
+
+ /* VE_STATUS3 */
+ u32 jpeg_off;
+
+ /* VE_STATUS4 */
+ u32 jpeg_size:20, interval:10, nop1:2;
+
+ /* VE_STATUS5/6 */
+ u32 sec, usec;
+
+ /* VE_STATUS7/8/9 */
+ u32 nop2[3];
+
+ /* VE_STATUS10 */
+ u32 mpeg_size_alt:20, nop3:12;
+
+ u32 end_nops[5];
+} __packed;
+
+struct solo_enc_buf {
+ enum solo_enc_types type;
+ struct vop_header *vh;
+ int motion;
+};
+
+static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ return (solo_dev->motion_mask >> solo_enc->ch) & 1;
+}
+
+static int solo_motion_detected(struct solo_enc_dev *solo_enc)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ unsigned long flags;
+ u32 ch_mask = 1 << solo_enc->ch;
+ int ret = 0;
+
+ spin_lock_irqsave(&solo_enc->motion_lock, flags);
+ if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) {
+ solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask);
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
+
+ return ret;
+}
+
+static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ u32 mask = 1 << solo_enc->ch;
+ unsigned long flags;
+
+ spin_lock_irqsave(&solo_enc->motion_lock, flags);
+
+ if (on)
+ solo_dev->motion_mask |= mask;
+ else
+ solo_dev->motion_mask &= ~mask;
+
+ solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask);
+
+ solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
+ SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
+ (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
+
+ spin_unlock_irqrestore(&solo_enc->motion_lock, flags);
+}
+
+void solo_update_mode(struct solo_enc_dev *solo_enc)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ int vop_len;
+ unsigned char *vop;
+
+ solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
+ solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
+
+ if (solo_enc->mode == SOLO_ENC_MODE_CIF) {
+ solo_enc->width = solo_dev->video_hsize >> 1;
+ solo_enc->height = solo_dev->video_vsize;
+ if (solo_dev->type == SOLO_DEV_6110) {
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+ vop = vop_6110_ntsc_cif;
+ vop_len = sizeof(vop_6110_ntsc_cif);
+ } else {
+ vop = vop_6110_pal_cif;
+ vop_len = sizeof(vop_6110_pal_cif);
+ }
+ } else {
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+ vop = vop_6010_ntsc_cif;
+ vop_len = sizeof(vop_6010_ntsc_cif);
+ } else {
+ vop = vop_6010_pal_cif;
+ vop_len = sizeof(vop_6010_pal_cif);
+ }
+ }
+ } else {
+ solo_enc->width = solo_dev->video_hsize;
+ solo_enc->height = solo_dev->video_vsize << 1;
+ solo_enc->bw_weight <<= 2;
+ if (solo_dev->type == SOLO_DEV_6110) {
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+ vop = vop_6110_ntsc_d1;
+ vop_len = sizeof(vop_6110_ntsc_d1);
+ } else {
+ vop = vop_6110_pal_d1;
+ vop_len = sizeof(vop_6110_pal_d1);
+ }
+ } else {
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) {
+ vop = vop_6010_ntsc_d1;
+ vop_len = sizeof(vop_6010_ntsc_d1);
+ } else {
+ vop = vop_6010_pal_d1;
+ vop_len = sizeof(vop_6010_pal_d1);
+ }
+ }
+ }
+
+ memcpy(solo_enc->vop, vop, vop_len);
+
+ /* Some fixups for 6010/M4V */
+ if (solo_dev->type == SOLO_DEV_6010) {
+ u16 fps = solo_dev->fps * 1000;
+ u16 interval = solo_enc->interval * 1000;
+
+ vop = solo_enc->vop;
+
+ /* Frame rate and interval */
+ vop[22] = fps >> 4;
+ vop[23] = ((fps << 4) & 0xf0) | 0x0c
+ | ((interval >> 13) & 0x3);
+ vop[24] = (interval >> 5) & 0xff;
+ vop[25] = ((interval << 3) & 0xf8) | 0x04;
+ }
+
+ solo_enc->vop_len = vop_len;
+
+ /* Now handle the jpeg header */
+ vop = solo_enc->jpeg_header;
+ vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8);
+ vop[SOF0_START + 6] = 0xff & solo_enc->height;
+ vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8);
+ vop[SOF0_START + 8] = 0xff & solo_enc->width;
+
+ memcpy(vop + DQT_START,
+ jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN);
+}
+
+static int solo_enc_on(struct solo_enc_dev *solo_enc)
+{
+ u8 ch = solo_enc->ch;
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ u8 interval;
+
+ solo_update_mode(solo_enc);
+
+ /* Make sure to do a bandwidth check */
+ if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
+ return -EBUSY;
+ solo_enc->sequence = 0;
+ solo_dev->enc_bw_remain -= solo_enc->bw_weight;
+
+ if (solo_enc->type == SOLO_ENC_TYPE_EXT)
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
+
+ /* Disable all encoding for this channel */
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
+
+ /* Common for both std and ext encoding */
+ solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
+ solo_enc->interlaced ? 1 : 0);
+
+ if (solo_enc->interlaced)
+ interval = solo_enc->interval - 1;
+ else
+ interval = solo_enc->interval;
+
+ /* Standard encoding only */
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
+
+ /* Extended encoding only */
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
+
+ /* Enables the standard encoder */
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
+
+ return 0;
+}
+
+static void solo_enc_off(struct solo_enc_dev *solo_enc)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ solo_dev->enc_bw_remain += solo_enc->bw_weight;
+
+ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
+ solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
+}
+
+static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma,
+ unsigned int off, unsigned int size)
+{
+ int ret;
+
+ if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
+ return -EINVAL;
+
+ /* Single shot */
+ if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
+ return solo_p2m_dma_t(solo_dev, 0, dma,
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off, size,
+ 0, 0);
+ }
+
+ /* Buffer wrap */
+ ret = solo_p2m_dma_t(solo_dev, 0, dma,
+ SOLO_MP4E_EXT_ADDR(solo_dev) + off,
+ SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0);
+
+ if (!ret) {
+ ret = solo_p2m_dma_t(solo_dev, 0,
+ dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
+ SOLO_MP4E_EXT_ADDR(solo_dev),
+ size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0);
+ }
+
+ return ret;
+}
+
+/* Build a descriptor queue out of an SG list and send it to the P2M for
+ * processing. */
+static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip,
+ struct vb2_dma_sg_desc *vbuf, int off, int size,
+ unsigned int base, unsigned int base_size)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct scatterlist *sg;
+ int i;
+ int ret;
+
+ if (WARN_ON_ONCE(size > FRAME_BUF_SIZE))
+ return -EINVAL;
+
+ solo_enc->desc_count = 1;
+
+ for_each_sg(vbuf->sglist, sg, vbuf->num_pages, i) {
+ struct solo_p2m_desc *desc;
+ dma_addr_t dma;
+ int len;
+ int left = base_size - off;
+
+ desc = &solo_enc->desc_items[solo_enc->desc_count++];
+ dma = sg_dma_address(sg);
+ len = sg_dma_len(sg);
+
+ /* We assume this is smaller than the scatter size */
+ BUG_ON(skip >= len);
+ if (skip) {
+ len -= skip;
+ dma += skip;
+ size -= skip;
+ skip = 0;
+ }
+
+ len = min(len, size);
+
+ if (len <= left) {
+ /* Single descriptor */
+ solo_p2m_fill_desc(desc, 0, dma, base + off,
+ len, 0, 0);
+ } else {
+ /* Buffer wrap */
+ /* XXX: Do these as separate DMA requests, to avoid
+ timeout errors triggered by awkwardly sized
+ descriptors. See
+ <https://github.com/bluecherrydvr/solo6x10/issues/8>
+ */
+ ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off,
+ left, 0, 0);
+ if (ret)
+ return ret;
+
+ ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base,
+ len - left, 0, 0);
+ if (ret)
+ return ret;
+
+ solo_enc->desc_count--;
+ }
+
+ size -= len;
+ if (size <= 0)
+ break;
+
+ off += len;
+ if (off >= base_size)
+ off -= base_size;
+
+ /* Because we may use two descriptors per loop */
+ if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) {
+ ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items,
+ solo_enc->desc_dma,
+ solo_enc->desc_count - 1);
+ if (ret)
+ return ret;
+ solo_enc->desc_count = 1;
+ }
+ }
+
+ if (solo_enc->desc_count <= 1)
+ return 0;
+
+ return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma,
+ solo_enc->desc_count - 1);
+}
+
+static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
+ struct vb2_buffer *vb, struct vop_header *vh)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+ int frame_size;
+ int ret;
+
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+
+ if (vb2_plane_size(vb, 0) < vh->jpeg_size + solo_enc->jpeg_len)
+ return -EIO;
+
+ sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages,
+ solo_enc->jpeg_header,
+ solo_enc->jpeg_len);
+
+ frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1))
+ & ~(DMA_ALIGN - 1);
+ vb2_set_plane_payload(vb, 0, vh->jpeg_size + solo_enc->jpeg_len);
+
+ dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+ DMA_FROM_DEVICE);
+ ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off,
+ frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
+ SOLO_JPEG_EXT_SIZE(solo_dev));
+ dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+ DMA_FROM_DEVICE);
+ return ret;
+}
+
+static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
+ struct vb2_buffer *vb, struct vop_header *vh)
+{
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+ int frame_off, frame_size;
+ int skip = 0;
+ int ret;
+
+ if (vb2_plane_size(vb, 0) < vh->mpeg_size)
+ return -EIO;
+
+ /* If this is a key frame, add extra header */
+ if (!vh->vop_type) {
+ sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages,
+ solo_enc->vop,
+ solo_enc->vop_len);
+
+ skip = solo_enc->vop_len;
+
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+ vb2_set_plane_payload(vb, 0, vh->mpeg_size + solo_enc->vop_len);
+ } else {
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+ vb2_set_plane_payload(vb, 0, vh->mpeg_size);
+ }
+
+ /* Now get the actual mpeg payload */
+ frame_off = (vh->mpeg_off + sizeof(*vh))
+ % SOLO_MP4E_EXT_SIZE(solo_dev);
+ frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1))
+ & ~(DMA_ALIGN - 1);
+
+ dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+ DMA_FROM_DEVICE);
+ ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
+ SOLO_MP4E_EXT_ADDR(solo_dev),
+ SOLO_MP4E_EXT_SIZE(solo_dev));
+ dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages,
+ DMA_FROM_DEVICE);
+ return ret;
+}
+
+static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
+ struct vb2_buffer *vb, struct solo_enc_buf *enc_buf)
+{
+ struct vop_header *vh = enc_buf->vh;
+ int ret;
+
+ /* Check for motion flags */
+ vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON |
+ V4L2_BUF_FLAG_MOTION_DETECTED);
+ if (solo_is_motion_on(solo_enc)) {
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON;
+ if (enc_buf->motion)
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
+ }
+
+ switch (solo_enc->fmt) {
+ case V4L2_PIX_FMT_MPEG4:
+ case V4L2_PIX_FMT_H264:
+ ret = solo_fill_mpeg(solo_enc, vb, vh);
+ break;
+ default: /* V4L2_PIX_FMT_MJPEG */
+ ret = solo_fill_jpeg(solo_enc, vb, vh);
+ break;
+ }
+
+ if (!ret) {
+ vb->v4l2_buf.sequence = solo_enc->sequence++;
+ vb->v4l2_buf.timestamp.tv_sec = vh->sec;
+ vb->v4l2_buf.timestamp.tv_usec = vh->usec;
+ }
+
+ vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+
+ return ret;
+}
+
+static void solo_enc_handle_one(struct solo_enc_dev *solo_enc,
+ struct solo_enc_buf *enc_buf)
+{
+ struct solo_vb2_buf *vb;
+ unsigned long flags;
+
+ mutex_lock(&solo_enc->lock);
+ if (solo_enc->type != enc_buf->type)
+ goto unlock;
+
+ spin_lock_irqsave(&solo_enc->av_lock, flags);
+ if (list_empty(&solo_enc->vidq_active)) {
+ spin_unlock_irqrestore(&solo_enc->av_lock, flags);
+ goto unlock;
+ }
+ vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf, list);
+ list_del(&vb->list);
+ spin_unlock_irqrestore(&solo_enc->av_lock, flags);
+
+ solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf);
+unlock:
+ mutex_unlock(&solo_enc->lock);
+}
+
+void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
+{
+ wake_up_interruptible_all(&solo_dev->ring_thread_wait);
+}
+
+static void solo_handle_ring(struct solo_dev *solo_dev)
+{
+ for (;;) {
+ struct solo_enc_dev *solo_enc;
+ struct solo_enc_buf enc_buf;
+ u32 mpeg_current, off;
+ u8 ch;
+ u8 cur_q;
+
+ /* Check if the hardware has any new ones in the queue */
+ cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff;
+ if (cur_q == solo_dev->enc_idx)
+ break;
+
+ mpeg_current = solo_reg_read(solo_dev,
+ SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
+ solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
+
+ ch = (mpeg_current >> 24) & 0x1f;
+ off = mpeg_current & 0x00ffffff;
+
+ if (ch >= SOLO_MAX_CHANNELS) {
+ ch -= SOLO_MAX_CHANNELS;
+ enc_buf.type = SOLO_ENC_TYPE_EXT;
+ } else
+ enc_buf.type = SOLO_ENC_TYPE_STD;
+
+ solo_enc = solo_dev->v4l2_enc[ch];
+ if (solo_enc == NULL) {
+ dev_err(&solo_dev->pdev->dev,
+ "Got spurious packet for channel %d\n", ch);
+ continue;
+ }
+
+ /* FAIL... */
+ if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off,
+ sizeof(struct vop_header)))
+ continue;
+
+ enc_buf.vh = (struct vop_header *)solo_dev->vh_buf;
+ enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev);
+ enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev);
+
+ /* Sanity check */
+ if (enc_buf.vh->mpeg_off != off)
+ continue;
+
+ if (solo_motion_detected(solo_enc))
+ enc_buf.motion = 1;
+ else
+ enc_buf.motion = 0;
+
+ solo_enc_handle_one(solo_enc, &enc_buf);
+ }
+}
+
+static int solo_ring_thread(void *data)
+{
+ struct solo_dev *solo_dev = data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_freezable();
+ add_wait_queue(&solo_dev->ring_thread_wait, &wait);
+
+ for (;;) {
+ long timeout = schedule_timeout_interruptible(HZ);
+ if (timeout == -ERESTARTSYS || kthread_should_stop())
+ break;
+ solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+ solo_handle_ring(solo_dev);
+ solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+ try_to_freeze();
+ }
+
+ remove_wait_queue(&solo_dev->ring_thread_wait, &wait);
+
+ return 0;
+}
+
+static int solo_enc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ sizes[0] = FRAME_BUF_SIZE;
+ *num_planes = 1;
+
+ if (*num_buffers < MIN_VID_BUFFERS)
+ *num_buffers = MIN_VID_BUFFERS;
+
+ return 0;
+}
+
+static void solo_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq);
+ struct solo_vb2_buf *solo_vb =
+ container_of(vb, struct solo_vb2_buf, vb);
+
+ spin_lock(&solo_enc->av_lock);
+ list_add_tail(&solo_vb->list, &solo_enc->vidq_active);
+ spin_unlock(&solo_enc->av_lock);
+}
+
+static int solo_ring_start(struct solo_dev *solo_dev)
+{
+ solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev,
+ SOLO6X10_NAME "_ring");
+ if (IS_ERR(solo_dev->ring_thread)) {
+ int err = PTR_ERR(solo_dev->ring_thread);
+ solo_dev->ring_thread = NULL;
+ return err;
+ }
+
+ solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
+
+ return 0;
+}
+
+static void solo_ring_stop(struct solo_dev *solo_dev)
+{
+ if (solo_dev->ring_thread) {
+ kthread_stop(solo_dev->ring_thread);
+ solo_dev->ring_thread = NULL;
+ }
+
+ solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
+}
+
+static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+ int ret;
+
+ ret = solo_enc_on(solo_enc);
+ if (ret)
+ return ret;
+ return solo_ring_start(solo_enc->solo_dev);
+}
+
+static int solo_enc_stop_streaming(struct vb2_queue *q)
+{
+ struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+
+ solo_enc_off(solo_enc);
+ INIT_LIST_HEAD(&solo_enc->vidq_active);
+ solo_ring_stop(solo_enc->solo_dev);
+ return 0;
+}
+
+static struct vb2_ops solo_enc_video_qops = {
+ .queue_setup = solo_enc_queue_setup,
+ .buf_queue = solo_enc_buf_queue,
+ .start_streaming = solo_enc_start_streaming,
+ .stop_streaming = solo_enc_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int solo_enc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ strcpy(cap->driver, SOLO6X10_NAME);
+ snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
+ solo_enc->ch);
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+ pci_name(solo_dev->pdev));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int solo_enc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ if (input->index)
+ return -EINVAL;
+
+ snprintf(input->name, sizeof(input->name), "Encoder %d",
+ solo_enc->ch + 1);
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = solo_enc->vfd->tvnorms;
+
+ if (!tw28_get_video_status(solo_dev, solo_enc->ch))
+ input->status = V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
+static int solo_enc_set_input(struct file *file, void *priv,
+ unsigned int index)
+{
+ if (index)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int solo_enc_get_input(struct file *file, void *priv,
+ unsigned int *index)
+{
+ *index = 0;
+
+ return 0;
+}
+
+static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ int dev_type = solo_enc->solo_dev->type;
+
+ switch (f->index) {
+ case 0:
+ switch (dev_type) {
+ case SOLO_DEV_6010:
+ f->pixelformat = V4L2_PIX_FMT_MPEG4;
+ strcpy(f->description, "MPEG-4 part 2");
+ break;
+ case SOLO_DEV_6110:
+ f->pixelformat = V4L2_PIX_FMT_H264;
+ strcpy(f->description, "H.264");
+ break;
+ }
+ break;
+ case 1:
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
+ strcpy(f->description, "MJPEG");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+ return 0;
+}
+
+static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type)
+{
+ return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110)
+ || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010)
+ || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL;
+}
+
+static int solo_enc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type))
+ return -EINVAL;
+
+ if (pix->width < solo_dev->video_hsize ||
+ pix->height < solo_dev->video_vsize << 1) {
+ /* Default to CIF 1/2 size */
+ pix->width = solo_dev->video_hsize >> 1;
+ pix->height = solo_dev->video_vsize;
+ } else {
+ /* Full frame */
+ pix->width = solo_dev->video_hsize;
+ pix->height = solo_dev->video_vsize << 1;
+ }
+
+ switch (pix->field) {
+ case V4L2_FIELD_NONE:
+ case V4L2_FIELD_INTERLACED:
+ break;
+ case V4L2_FIELD_ANY:
+ default:
+ pix->field = V4L2_FIELD_INTERLACED;
+ break;
+ }
+
+ /* Just set these */
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->sizeimage = FRAME_BUF_SIZE;
+ pix->bytesperline = 0;
+ pix->priv = 0;
+
+ return 0;
+}
+
+static int solo_enc_set_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int ret;
+
+ if (vb2_is_busy(&solo_enc->vidq))
+ return -EBUSY;
+
+ ret = solo_enc_try_fmt_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (pix->width == solo_dev->video_hsize)
+ solo_enc->mode = SOLO_ENC_MODE_D1;
+ else
+ solo_enc->mode = SOLO_ENC_MODE_CIF;
+
+ /* This does not change the encoder at all */
+ solo_enc->fmt = pix->pixelformat;
+
+ /*
+ * More information is needed about these 'extended' types. As far
+ * as I can tell these are basically additional video streams with
+ * different MPEG encoding attributes that can run in parallel with
+ * the main stream. If so, then this should be implemented as a
+ * second video node. Abusing priv like this is certainly not the
+ * right approach.
+ if (pix->priv)
+ solo_enc->type = SOLO_ENC_TYPE_EXT;
+ */
+ solo_update_mode(solo_enc);
+ return 0;
+}
+
+static int solo_enc_get_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = solo_enc->width;
+ pix->height = solo_enc->height;
+ pix->pixelformat = solo_enc->fmt;
+ pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
+ V4L2_FIELD_NONE;
+ pix->sizeimage = FRAME_BUF_SIZE;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->priv = 0;
+
+ return 0;
+}
+
+static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+ *i = V4L2_STD_NTSC_M;
+ else
+ *i = V4L2_STD_PAL;
+ return 0;
+}
+
+static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+
+ return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_PAL);
+}
+
+static int solo_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type))
+ return -EINVAL;
+
+ switch (fsize->index) {
+ case 0:
+ fsize->discrete.width = solo_dev->video_hsize >> 1;
+ fsize->discrete.height = solo_dev->video_vsize;
+ break;
+ case 1:
+ fsize->discrete.width = solo_dev->video_hsize;
+ fsize->discrete.height = solo_dev->video_vsize << 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+
+ return 0;
+}
+
+static int solo_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fintv)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+
+ if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type))
+ return -EINVAL;
+ if (fintv->index)
+ return -EINVAL;
+ if ((fintv->width != solo_dev->video_hsize >> 1 ||
+ fintv->height != solo_dev->video_vsize) &&
+ (fintv->width != solo_dev->video_hsize ||
+ fintv->height != solo_dev->video_vsize << 1))
+ return -EINVAL;
+
+ fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+
+ fintv->stepwise.min.numerator = 1;
+ fintv->stepwise.min.denominator = solo_dev->fps;
+
+ fintv->stepwise.max.numerator = 15;
+ fintv->stepwise.max.denominator = solo_dev->fps;
+
+ fintv->stepwise.step.numerator = 1;
+ fintv->stepwise.step.denominator = solo_dev->fps;
+
+ return 0;
+}
+
+static int solo_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = solo_enc->interval;
+ cp->timeperframe.denominator = solo_dev->fps;
+ cp->capturemode = 0;
+ /* XXX: Shouldn't we be able to get/set this from videobuf? */
+ cp->readbuffers = 2;
+
+ return 0;
+}
+
+static int solo_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ if (vb2_is_streaming(&solo_enc->vidq))
+ return -EBUSY;
+
+ if ((cp->timeperframe.numerator == 0) ||
+ (cp->timeperframe.denominator == 0)) {
+ /* reset framerate */
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = solo_dev->fps;
+ }
+
+ if (cp->timeperframe.denominator != solo_dev->fps)
+ cp->timeperframe.denominator = solo_dev->fps;
+
+ if (cp->timeperframe.numerator > 15)
+ cp->timeperframe.numerator = 15;
+
+ solo_enc->interval = cp->timeperframe.numerator;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->readbuffers = 2;
+
+ solo_update_mode(solo_enc);
+ return 0;
+}
+
+static long solo_enc_default(struct file *file, void *fh,
+ bool valid_prio, unsigned int cmd, void *arg)
+{
+ struct solo_enc_dev *solo_enc = video_drvdata(file);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ struct solo_motion_thresholds *thresholds = arg;
+
+ switch (cmd) {
+ case SOLO_IOC_G_MOTION_THRESHOLDS:
+ *thresholds = solo_enc->motion_thresholds;
+ return 0;
+
+ case SOLO_IOC_S_MOTION_THRESHOLDS:
+ if (!valid_prio)
+ return -EBUSY;
+ solo_enc->motion_thresholds = *thresholds;
+ if (solo_enc->motion_enabled && !solo_enc->motion_global)
+ return solo_set_motion_block(solo_dev, solo_enc->ch,
+ &solo_enc->motion_thresholds);
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+}
+
+static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct solo_enc_dev *solo_enc =
+ container_of(ctrl->handler, struct solo_enc_dev, hdl);
+ struct solo_dev *solo_dev = solo_enc->solo_dev;
+ int err;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SHARPNESS:
+ return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
+ ctrl->val);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ solo_enc->gop = ctrl->val;
+ return 0;
+ case V4L2_CID_MOTION_THRESHOLD:
+ solo_enc->motion_thresh = ctrl->val;
+ if (!solo_enc->motion_global || !solo_enc->motion_enabled)
+ return 0;
+ return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val);
+ case V4L2_CID_MOTION_MODE:
+ solo_enc->motion_global = ctrl->val == 1;
+ solo_enc->motion_enabled = ctrl->val > 0;
+ if (ctrl->val) {
+ if (solo_enc->motion_global)
+ solo_set_motion_threshold(solo_dev, solo_enc->ch,
+ solo_enc->motion_thresh);
+ else
+ solo_set_motion_block(solo_dev, solo_enc->ch,
+ &solo_enc->motion_thresholds);
+ }
+ solo_motion_toggle(solo_enc, ctrl->val);
+ return 0;
+ case V4L2_CID_OSD_TEXT:
+ strcpy(solo_enc->osd_text, ctrl->string);
+ err = solo_osd_print(solo_enc);
+ return err;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_file_operations solo_enc_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
+ .vidioc_querycap = solo_enc_querycap,
+ .vidioc_s_std = solo_enc_s_std,
+ .vidioc_g_std = solo_enc_g_std,
+ /* Input callbacks */
+ .vidioc_enum_input = solo_enc_enum_input,
+ .vidioc_s_input = solo_enc_set_input,
+ .vidioc_g_input = solo_enc_get_input,
+ /* Video capture format callbacks */
+ .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
+ .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
+ .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
+ /* Streaming I/O */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ /* Frame size and interval */
+ .vidioc_enum_framesizes = solo_enum_framesizes,
+ .vidioc_enum_frameintervals = solo_enum_frameintervals,
+ /* Video capture parameters */
+ .vidioc_s_parm = solo_s_parm,
+ .vidioc_g_parm = solo_g_parm,
+ /* Logging and events */
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_default = solo_enc_default,
+};
+
+static const struct video_device solo_enc_template = {
+ .name = SOLO6X10_NAME,
+ .fops = &solo_enc_fops,
+ .ioctl_ops = &solo_enc_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+};
+
+static const struct v4l2_ctrl_ops solo_ctrl_ops = {
+ .s_ctrl = solo_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = {
+ .ops = &solo_ctrl_ops,
+ .id = V4L2_CID_MOTION_THRESHOLD,
+ .name = "Motion Detection Threshold",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .max = 0xffff,
+ .def = SOLO_DEF_MOT_THRESH,
+ .step = 1,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+};
+
+static const char * const solo_motion_mode_menu[] = {
+ "Disabled",
+ "Global Threshold",
+ "Regional Threshold",
+ NULL
+};
+
+static const struct v4l2_ctrl_config solo_motion_enable_ctrl = {
+ .ops = &solo_ctrl_ops,
+ .id = V4L2_CID_MOTION_MODE,
+ .name = "Motion Detection Mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .qmenu = solo_motion_mode_menu,
+ .max = 2,
+};
+
+static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
+ .ops = &solo_ctrl_ops,
+ .id = V4L2_CID_OSD_TEXT,
+ .name = "OSD Text",
+ .type = V4L2_CTRL_TYPE_STRING,
+ .max = OSD_TEXT_MAX,
+ .step = 1,
+};
+
+static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
+ u8 ch, unsigned nr)
+{
+ struct solo_enc_dev *solo_enc;
+ struct v4l2_ctrl_handler *hdl;
+ int ret;
+ int x, y;
+
+ solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
+ if (!solo_enc)
+ return ERR_PTR(-ENOMEM);
+
+ hdl = &solo_enc->hdl;
+ v4l2_ctrl_handler_init(hdl, 10);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_HUE, 0, 255, 1, 128);
+ if (tw28_has_sharpness(solo_dev, ch))
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 15, 1, 0);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
+ v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
+ if (hdl->error) {
+ ret = hdl->error;
+ goto hdl_free;
+ }
+
+ solo_enc->solo_dev = solo_dev;
+ solo_enc->ch = ch;
+ mutex_init(&solo_enc->lock);
+ spin_lock_init(&solo_enc->av_lock);
+ INIT_LIST_HEAD(&solo_enc->vidq_active);
+ solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ?
+ V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264;
+ solo_enc->type = SOLO_ENC_TYPE_STD;
+
+ solo_enc->qp = SOLO_DEFAULT_QP;
+ solo_enc->gop = solo_dev->fps;
+ solo_enc->interval = 1;
+ solo_enc->mode = SOLO_ENC_MODE_CIF;
+ solo_enc->motion_global = true;
+ solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
+ for (y = 0; y < SOLO_MOTION_SZ; y++)
+ for (x = 0; x < SOLO_MOTION_SZ; x++)
+ solo_enc->motion_thresholds.thresholds[y][x] =
+ SOLO_DEF_MOT_THRESH;
+
+ solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ solo_enc->vidq.ops = &solo_enc_video_qops;
+ solo_enc->vidq.mem_ops = &vb2_dma_sg_memops;
+ solo_enc->vidq.drv_priv = solo_enc;
+ solo_enc->vidq.gfp_flags = __GFP_DMA32;
+ solo_enc->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+ solo_enc->vidq.lock = &solo_enc->lock;
+ ret = vb2_queue_init(&solo_enc->vidq);
+ if (ret)
+ goto hdl_free;
+ solo_update_mode(solo_enc);
+
+ spin_lock_init(&solo_enc->motion_lock);
+
+ /* Initialize this per encoder */
+ solo_enc->jpeg_len = sizeof(jpeg_header);
+ memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len);
+
+ solo_enc->desc_nelts = 32;
+ solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev,
+ sizeof(struct solo_p2m_desc) *
+ solo_enc->desc_nelts, &solo_enc->desc_dma);
+ ret = -ENOMEM;
+ if (solo_enc->desc_items == NULL)
+ goto hdl_free;
+
+ solo_enc->vfd = video_device_alloc();
+ if (!solo_enc->vfd)
+ goto pci_free;
+
+ *solo_enc->vfd = solo_enc_template;
+ solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+ solo_enc->vfd->ctrl_handler = hdl;
+ solo_enc->vfd->queue = &solo_enc->vidq;
+ solo_enc->vfd->lock = &solo_enc->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags);
+ video_set_drvdata(solo_enc->vfd, solo_enc);
+ ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
+ if (ret < 0)
+ goto vdev_release;
+
+ snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
+ "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
+ solo_enc->vfd->num);
+
+ return solo_enc;
+
+vdev_release:
+ video_device_release(solo_enc->vfd);
+pci_free:
+ pci_free_consistent(solo_enc->solo_dev->pdev,
+ sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
+ solo_enc->desc_items, solo_enc->desc_dma);
+hdl_free:
+ v4l2_ctrl_handler_free(hdl);
+ kfree(solo_enc);
+ return ERR_PTR(ret);
+}
+
+static void solo_enc_free(struct solo_enc_dev *solo_enc)
+{
+ if (solo_enc == NULL)
+ return;
+
+ video_unregister_device(solo_enc->vfd);
+ v4l2_ctrl_handler_free(&solo_enc->hdl);
+ kfree(solo_enc);
+}
+
+int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
+{
+ int i;
+
+ init_waitqueue_head(&solo_dev->ring_thread_wait);
+
+ solo_dev->vh_size = sizeof(struct vop_header);
+ solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev,
+ solo_dev->vh_size,
+ &solo_dev->vh_dma);
+ if (solo_dev->vh_buf == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr);
+ if (IS_ERR(solo_dev->v4l2_enc[i]))
+ break;
+ }
+
+ if (i != solo_dev->nr_chans) {
+ int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
+ while (i--)
+ solo_enc_free(solo_dev->v4l2_enc[i]);
+ pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
+ solo_dev->vh_buf, solo_dev->vh_dma);
+ solo_dev->vh_buf = NULL;
+ return ret;
+ }
+
+ if (solo_dev->type == SOLO_DEV_6010)
+ solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
+ else
+ solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5;
+
+ dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
+ solo_dev->v4l2_enc[0]->vfd->num,
+ solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
+
+ return 0;
+}
+
+void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
+{
+ int i;
+
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_enc_free(solo_dev->v4l2_enc[i]);
+
+ if (solo_dev->vh_buf)
+ pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
+ solo_dev->vh_buf, solo_dev->vh_dma);
+}
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/staging/media/solo6x10/solo6x10-v4l2.c
new file mode 100644
index 000000000000..7b26de3488da
--- /dev/null
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2.c
@@ -0,0 +1,734 @@
+/*
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "solo6x10.h"
+#include "solo6x10-tw28.h"
+
+/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */
+#define SOLO_HW_BPL 2048
+#define solo_vlines(__solo) (__solo->video_vsize * 2)
+#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
+ solo_vlines(__solo))
+#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
+
+#define MIN_VID_BUFFERS 2
+
+static inline void erase_on(struct solo_dev *solo_dev)
+{
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
+ solo_dev->erasing = 1;
+ solo_dev->frame_blank = 0;
+}
+
+static inline int erase_off(struct solo_dev *solo_dev)
+{
+ if (!solo_dev->erasing)
+ return 0;
+
+ /* First time around, assert erase off */
+ if (!solo_dev->frame_blank)
+ solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
+ /* Keep the erasing flag on for 8 frames minimum */
+ if (solo_dev->frame_blank++ >= 8)
+ solo_dev->erasing = 0;
+
+ return 1;
+}
+
+void solo_video_in_isr(struct solo_dev *solo_dev)
+{
+ wake_up_interruptible_all(&solo_dev->disp_thread_wait);
+}
+
+static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
+ int sx, int sy, int ex, int ey, int scale)
+{
+ if (ch >= solo_dev->nr_chans)
+ return;
+
+ /* Here, we just keep window/channel the same */
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
+ SOLO_VI_WIN_CHANNEL(ch) |
+ SOLO_VI_WIN_SX(sx) |
+ SOLO_VI_WIN_EX(ex) |
+ SOLO_VI_WIN_SCALE(scale));
+
+ solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
+ SOLO_VI_WIN_SY(sy) |
+ SOLO_VI_WIN_EY(ey));
+}
+
+static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
+{
+ u8 ch = idx * 4;
+
+ if (ch >= solo_dev->nr_chans)
+ return -EINVAL;
+
+ if (!on) {
+ u8 i;
+ for (i = ch; i < ch + 4; i++)
+ solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+ solo_vlines(solo_dev),
+ solo_dev->video_hsize,
+ solo_vlines(solo_dev), 0);
+ return 0;
+ }
+
+ /* Row 1 */
+ solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
+ solo_vlines(solo_dev) / 2, 3);
+ solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
+ solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
+ /* Row 2 */
+ solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
+ solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
+ solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
+ solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
+ solo_vlines(solo_dev), 3);
+
+ return 0;
+}
+
+static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
+{
+ int sy, ysize, hsize, i;
+
+ if (!on) {
+ for (i = 0; i < 16; i++)
+ solo_win_setup(solo_dev, i, solo_dev->video_hsize,
+ solo_vlines(solo_dev),
+ solo_dev->video_hsize,
+ solo_vlines(solo_dev), 0);
+ return 0;
+ }
+
+ ysize = solo_vlines(solo_dev) / 4;
+ hsize = solo_dev->video_hsize / 4;
+
+ for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
+ solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
+ sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
+ hsize * 2, sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
+ hsize * 3, sy + ysize, 5);
+ solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
+ solo_dev->video_hsize, sy + ysize, 5);
+ }
+
+ return 0;
+}
+
+static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
+{
+ u8 ext_ch;
+
+ if (ch < solo_dev->nr_chans) {
+ solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
+ on ? 0 : solo_vlines(solo_dev),
+ solo_dev->video_hsize, solo_vlines(solo_dev),
+ on ? 1 : 0);
+ return 0;
+ }
+
+ if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+ return -EINVAL;
+
+ ext_ch = ch - solo_dev->nr_chans;
+
+ /* 4up's first */
+ if (ext_ch < 4)
+ return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
+
+ /* Remaining case is 16up for 16-port */
+ return solo_v4l2_ch_ext_16up(solo_dev, on);
+}
+
+static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
+{
+ if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
+ return -EINVAL;
+
+ erase_on(solo_dev);
+
+ solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
+ solo_v4l2_ch(solo_dev, ch, 1);
+
+ solo_dev->cur_disp_ch = ch;
+
+ return 0;
+}
+
+static void solo_fillbuf(struct solo_dev *solo_dev,
+ struct vb2_buffer *vb)
+{
+ dma_addr_t vbuf;
+ unsigned int fdma_addr;
+ int error = -1;
+ int i;
+
+ vbuf = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (!vbuf)
+ goto finish_buf;
+
+ if (erase_off(solo_dev)) {
+ void *p = vb2_plane_vaddr(vb, 0);
+ int image_size = solo_image_size(solo_dev);
+ for (i = 0; i < image_size; i += 2) {
+ ((u8 *)p)[i] = 0x80;
+ ((u8 *)p)[i + 1] = 0x00;
+ }
+ error = 0;
+ } else {
+ fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write *
+ (SOLO_HW_BPL * solo_vlines(solo_dev)));
+
+ error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr,
+ solo_bytesperline(solo_dev),
+ solo_vlines(solo_dev), SOLO_HW_BPL);
+ }
+
+finish_buf:
+ if (!error) {
+ vb2_set_plane_payload(vb, 0,
+ solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
+ vb->v4l2_buf.sequence = solo_dev->sequence++;
+ v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
+ }
+
+ vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+}
+
+static void solo_thread_try(struct solo_dev *solo_dev)
+{
+ struct solo_vb2_buf *vb;
+
+ /* Only "break" from this loop if slock is held, otherwise
+ * just return. */
+ for (;;) {
+ unsigned int cur_write;
+
+ cur_write = SOLO_VI_STATUS0_PAGE(
+ solo_reg_read(solo_dev, SOLO_VI_STATUS0));
+ if (cur_write == solo_dev->old_write)
+ return;
+
+ spin_lock(&solo_dev->slock);
+
+ if (list_empty(&solo_dev->vidq_active))
+ break;
+
+ vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf,
+ list);
+
+ solo_dev->old_write = cur_write;
+ list_del(&vb->list);
+
+ spin_unlock(&solo_dev->slock);
+
+ solo_fillbuf(solo_dev, &vb->vb);
+ }
+
+ assert_spin_locked(&solo_dev->slock);
+ spin_unlock(&solo_dev->slock);
+}
+
+static int solo_thread(void *data)
+{
+ struct solo_dev *solo_dev = data;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_freezable();
+ add_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+ for (;;) {
+ long timeout = schedule_timeout_interruptible(HZ);
+ if (timeout == -ERESTARTSYS || kthread_should_stop())
+ break;
+ solo_thread_try(solo_dev);
+ try_to_freeze();
+ }
+
+ remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
+
+ return 0;
+}
+
+static int solo_start_thread(struct solo_dev *solo_dev)
+{
+ int ret = 0;
+
+ solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp");
+
+ if (IS_ERR(solo_dev->kthread)) {
+ ret = PTR_ERR(solo_dev->kthread);
+ solo_dev->kthread = NULL;
+ return ret;
+ }
+ solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
+
+ return ret;
+}
+
+static void solo_stop_thread(struct solo_dev *solo_dev)
+{
+ if (!solo_dev->kthread)
+ return;
+
+ solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
+ kthread_stop(solo_dev->kthread);
+ solo_dev->kthread = NULL;
+}
+
+static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+ sizes[0] = solo_image_size(solo_dev);
+ alloc_ctxs[0] = solo_dev->alloc_ctx;
+ *num_planes = 1;
+
+ if (*num_buffers < MIN_VID_BUFFERS)
+ *num_buffers = MIN_VID_BUFFERS;
+
+ return 0;
+}
+
+static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+ solo_dev->sequence = 0;
+ return solo_start_thread(solo_dev);
+}
+
+static int solo_stop_streaming(struct vb2_queue *q)
+{
+ struct solo_dev *solo_dev = vb2_get_drv_priv(q);
+
+ solo_stop_thread(solo_dev);
+ INIT_LIST_HEAD(&solo_dev->vidq_active);
+ return 0;
+}
+
+static void solo_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct solo_dev *solo_dev = vb2_get_drv_priv(vq);
+ struct solo_vb2_buf *solo_vb =
+ container_of(vb, struct solo_vb2_buf, vb);
+
+ spin_lock(&solo_dev->slock);
+ list_add_tail(&solo_vb->list, &solo_dev->vidq_active);
+ spin_unlock(&solo_dev->slock);
+ wake_up_interruptible(&solo_dev->disp_thread_wait);
+}
+
+static const struct vb2_ops solo_video_qops = {
+ .queue_setup = solo_queue_setup,
+ .buf_queue = solo_buf_queue,
+ .start_streaming = solo_start_streaming,
+ .stop_streaming = solo_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int solo_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ strcpy(cap->driver, SOLO6X10_NAME);
+ strcpy(cap->card, "Softlogic 6x10");
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+ pci_name(solo_dev->pdev));
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int solo_enum_ext_input(struct solo_dev *solo_dev,
+ struct v4l2_input *input)
+{
+ static const char * const dispnames_1[] = { "4UP" };
+ static const char * const dispnames_2[] = { "4UP-1", "4UP-2" };
+ static const char * const dispnames_5[] = {
+ "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
+ };
+ const char * const *dispnames;
+
+ if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
+ return -EINVAL;
+
+ if (solo_dev->nr_ext == 5)
+ dispnames = dispnames_5;
+ else if (solo_dev->nr_ext == 2)
+ dispnames = dispnames_2;
+ else
+ dispnames = dispnames_1;
+
+ snprintf(input->name, sizeof(input->name), "Multi %s",
+ dispnames[input->index - solo_dev->nr_chans]);
+
+ return 0;
+}
+
+static int solo_enum_input(struct file *file, void *priv,
+ struct v4l2_input *input)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ if (input->index >= solo_dev->nr_chans) {
+ int ret = solo_enum_ext_input(solo_dev, input);
+ if (ret < 0)
+ return ret;
+ } else {
+ snprintf(input->name, sizeof(input->name), "Camera %d",
+ input->index + 1);
+
+ /* We can only check this for normal inputs */
+ if (!tw28_get_video_status(solo_dev, input->index))
+ input->status = V4L2_IN_ST_NO_SIGNAL;
+ }
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = solo_dev->vfd->tvnorms;
+ return 0;
+}
+
+static int solo_set_input(struct file *file, void *priv, unsigned int index)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+ int ret = solo_v4l2_set_ch(solo_dev, index);
+
+ if (!ret) {
+ while (erase_off(solo_dev))
+ /* Do nothing */;
+ }
+
+ return ret;
+}
+
+static int solo_get_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ *index = solo_dev->cur_disp_ch;
+
+ return 0;
+}
+
+static int solo_enum_fmt_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+ strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
+
+ return 0;
+}
+
+static int solo_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int image_size = solo_image_size(solo_dev);
+
+ if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
+ return -EINVAL;
+
+ pix->width = solo_dev->video_hsize;
+ pix->height = solo_vlines(solo_dev);
+ pix->sizeimage = image_size;
+ pix->field = V4L2_FIELD_INTERLACED;
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->priv = 0;
+ return 0;
+}
+
+static int solo_set_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ if (vb2_is_busy(&solo_dev->vidq))
+ return -EBUSY;
+
+ /* For right now, if it doesn't match our running config,
+ * then fail */
+ return solo_try_fmt_cap(file, priv, f);
+}
+
+static int solo_get_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ pix->width = solo_dev->video_hsize;
+ pix->height = solo_vlines(solo_dev);
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ pix->field = V4L2_FIELD_INTERLACED;
+ pix->sizeimage = solo_image_size(solo_dev);
+ pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ pix->bytesperline = solo_bytesperline(solo_dev);
+ pix->priv = 0;
+
+ return 0;
+}
+
+static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
+ *i = V4L2_STD_NTSC_M;
+ else
+ *i = V4L2_STD_PAL;
+ return 0;
+}
+
+int solo_set_video_type(struct solo_dev *solo_dev, bool type)
+{
+ int i;
+
+ /* Make sure all video nodes are idle */
+ if (vb2_is_busy(&solo_dev->vidq))
+ return -EBUSY;
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
+ return -EBUSY;
+ solo_dev->video_type = type;
+ /* Reconfigure for the new standard */
+ solo_disp_init(solo_dev);
+ solo_enc_init(solo_dev);
+ solo_tw28_init(solo_dev);
+ for (i = 0; i < solo_dev->nr_chans; i++)
+ solo_update_mode(solo_dev->v4l2_enc[i]);
+ return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch);
+}
+
+static int solo_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+ struct solo_dev *solo_dev = video_drvdata(file);
+
+ return solo_set_video_type(solo_dev, std & V4L2_STD_PAL);
+}
+
+static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct solo_dev *solo_dev =
+ container_of(ctrl->handler, struct solo_dev, disp_hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MOTION_TRACE:
+ if (ctrl->val) {
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
+ SOLO_VI_MOTION_Y_ADD |
+ SOLO_VI_MOTION_Y_VALUE(0x20) |
+ SOLO_VI_MOTION_CB_VALUE(0x10) |
+ SOLO_VI_MOTION_CR_VALUE(0x10));
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
+ SOLO_VI_MOTION_CR_ADD |
+ SOLO_VI_MOTION_Y_VALUE(0x10) |
+ SOLO_VI_MOTION_CB_VALUE(0x80) |
+ SOLO_VI_MOTION_CR_VALUE(0x10));
+ } else {
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
+ solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
+ }
+ return 0;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static const struct v4l2_file_operations solo_v4l2_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
+ .vidioc_querycap = solo_querycap,
+ .vidioc_s_std = solo_s_std,
+ .vidioc_g_std = solo_g_std,
+ /* Input callbacks */
+ .vidioc_enum_input = solo_enum_input,
+ .vidioc_s_input = solo_set_input,
+ .vidioc_g_input = solo_get_input,
+ /* Video capture format callbacks */
+ .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap,
+ .vidioc_try_fmt_vid_cap = solo_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
+ .vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
+ /* Streaming I/O */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ /* Logging and events */
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static struct video_device solo_v4l2_template = {
+ .name = SOLO6X10_NAME,
+ .fops = &solo_v4l2_fops,
+ .ioctl_ops = &solo_v4l2_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release,
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+};
+
+static const struct v4l2_ctrl_ops solo_ctrl_ops = {
+ .s_ctrl = solo_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config solo_motion_trace_ctrl = {
+ .ops = &solo_ctrl_ops,
+ .id = V4L2_CID_MOTION_TRACE,
+ .name = "Motion Detection Trace",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .step = 1,
+};
+
+int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
+{
+ int ret;
+ int i;
+
+ init_waitqueue_head(&solo_dev->disp_thread_wait);
+ spin_lock_init(&solo_dev->slock);
+ mutex_init(&solo_dev->lock);
+ INIT_LIST_HEAD(&solo_dev->vidq_active);
+
+ solo_dev->vfd = video_device_alloc();
+ if (!solo_dev->vfd)
+ return -ENOMEM;
+
+ *solo_dev->vfd = solo_v4l2_template;
+ solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev;
+ solo_dev->vfd->queue = &solo_dev->vidq;
+ solo_dev->vfd->lock = &solo_dev->lock;
+ v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1);
+ v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL);
+ if (solo_dev->disp_hdl.error) {
+ ret = solo_dev->disp_hdl.error;
+ goto fail;
+ }
+ solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags);
+
+ video_set_drvdata(solo_dev->vfd, solo_dev);
+
+ solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ solo_dev->vidq.ops = &solo_video_qops;
+ solo_dev->vidq.mem_ops = &vb2_dma_contig_memops;
+ solo_dev->vidq.drv_priv = solo_dev;
+ solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ solo_dev->vidq.gfp_flags = __GFP_DMA32;
+ solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf);
+ solo_dev->vidq.lock = &solo_dev->lock;
+ ret = vb2_queue_init(&solo_dev->vidq);
+ if (ret < 0)
+ goto fail;
+
+ solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev);
+ if (IS_ERR(solo_dev->alloc_ctx)) {
+ dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context");
+ return PTR_ERR(solo_dev->alloc_ctx);
+ }
+
+ /* Cycle all the channels and clear */
+ for (i = 0; i < solo_dev->nr_chans; i++) {
+ solo_v4l2_set_ch(solo_dev, i);
+ while (erase_off(solo_dev))
+ /* Do nothing */;
+ }
+
+ /* Set the default display channel */
+ solo_v4l2_set_ch(solo_dev, 0);
+ while (erase_off(solo_dev))
+ /* Do nothing */;
+
+ ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
+ if (ret < 0)
+ goto fail;
+
+ snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
+ SOLO6X10_NAME, solo_dev->vfd->num);
+
+ dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
+ "%d inputs (%d extended)\n", solo_dev->vfd->num,
+ solo_dev->nr_chans, solo_dev->nr_ext);
+
+ return 0;
+
+fail:
+ video_device_release(solo_dev->vfd);
+ vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+ v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+ solo_dev->vfd = NULL;
+ return ret;
+}
+
+void solo_v4l2_exit(struct solo_dev *solo_dev)
+{
+ if (solo_dev->vfd == NULL)
+ return;
+
+ video_unregister_device(solo_dev->vfd);
+ vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx);
+ v4l2_ctrl_handler_free(&solo_dev->disp_hdl);
+ solo_dev->vfd = NULL;
+}
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h
index abee7213202f..6f91d2e34b2a 100644
--- a/drivers/staging/media/solo6x10/solo6x10.h
+++ b/drivers/staging/media/solo6x10/solo6x10.h
@@ -1,6 +1,11 @@
/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
*
* 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
@@ -20,21 +25,23 @@
#ifndef __SOLO6X10_H
#define __SOLO6X10_H
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/i2c.h>
-#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <asm/io.h>
+#include <linux/stringify.h>
+#include <linux/io.h>
#include <linux/atomic.h>
+#include <linux/slab.h>
#include <linux/videodev2.h>
+
#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-#include "registers.h"
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+
+#include "solo6x10-regs.h"
#ifndef PCI_VENDOR_ID_SOFTLOGIC
#define PCI_VENDOR_ID_SOFTLOGIC 0x9413
@@ -58,19 +65,15 @@
#define PCI_DEVICE_ID_BC_6110_16 0x5310
#endif /* Bluecherry */
+/* Used in pci_device_id, and solo_dev->type */
+#define SOLO_DEV_6010 0
+#define SOLO_DEV_6110 1
+
#define SOLO6X10_NAME "solo6x10"
#define SOLO_MAX_CHANNELS 16
-/* Make sure these two match */
-#define SOLO6X10_VERSION "2.1.0"
-#define SOLO6X10_VER_MAJOR 2
-#define SOLO6X10_VER_MINOR 0
-#define SOLO6X10_VER_SUB 0
-#define SOLO6X10_VER_NUM \
- KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB)
-
-#define FLAGS_6110 1
+#define SOLO6X10_VERSION "3.0.0"
/*
* The SOLO6x10 actually has 8 i2c channels, but we only use 2.
@@ -84,16 +87,7 @@
/* DMA Engine setup */
#define SOLO_NR_P2M 4
#define SOLO_NR_P2M_DESC 256
-/* MPEG and JPEG share the same interrupt and locks so they must be together
- * in the same dma channel. */
-#define SOLO_P2M_DMA_ID_MP4E 0
-#define SOLO_P2M_DMA_ID_JPEG 0
-#define SOLO_P2M_DMA_ID_MP4D 1
-#define SOLO_P2M_DMA_ID_G723D 1
-#define SOLO_P2M_DMA_ID_DISP 2
-#define SOLO_P2M_DMA_ID_OSG 2
-#define SOLO_P2M_DMA_ID_G723E 3
-#define SOLO_P2M_DMA_ID_VIN 3
+#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16)
/* Encoder standard modes */
#define SOLO_ENC_MODE_CIF 2
@@ -103,23 +97,37 @@
#define SOLO_DEFAULT_GOP 30
#define SOLO_DEFAULT_QP 3
-/* There is 8MB memory available for solo to buffer MPEG4 frames.
- * This gives us 512 * 16kbyte queues. */
-#define SOLO_NR_RING_BUFS 512
-
-#define SOLO_CLOCK_MHZ 108
-
#ifndef V4L2_BUF_FLAG_MOTION_ON
-#define V4L2_BUF_FLAG_MOTION_ON 0x0400
-#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800
-#endif
-#ifndef V4L2_CID_MOTION_ENABLE
-#define PRIVATE_CIDS
-#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0)
-#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1)
-#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2)
+#define V4L2_BUF_FLAG_MOTION_ON 0x10000
+#define V4L2_BUF_FLAG_MOTION_DETECTED 0x20000
#endif
+#define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
+#define V4L2_CID_MOTION_MODE (SOLO_CID_CUSTOM_BASE+0)
+#define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1)
+#define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2)
+#define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3)
+
+/*
+ * Motion thresholds are in a table of 64x64 samples, with
+ * each sample representing 16x16 pixels of the source. In
+ * effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
+ * The 5th sample on the 10th row is (10*64)+5 = 645.
+ *
+ * Using a 64x64 array will result in a problem on some architectures like
+ * the powerpc where the size of the argument is limited to 13 bits.
+ * Since both PAL and NTSC do not use the full table anyway I've chosen
+ * to limit the array to 45x45 (45*16 = 720, which is the maximum PAL/NTSC
+ * width).
+ */
+#define SOLO_MOTION_SZ (45)
+struct solo_motion_thresholds {
+ __u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ];
+};
+
+#define SOLO_IOC_G_MOTION_THRESHOLDS _IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds)
+#define SOLO_IOC_S_MOTION_THRESHOLDS _IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds)
+
enum SOLO_I2C_STATE {
IIC_STATE_IDLE,
IIC_STATE_START,
@@ -128,20 +136,29 @@ enum SOLO_I2C_STATE {
IIC_STATE_STOP
};
-struct p2m_desc {
- u32 ctrl;
- u32 ext;
- u32 ta;
- u32 fa;
+/* Defined in Table 4-16, Page 68-69 of the 6010 Datasheet */
+struct solo_p2m_desc {
+ u32 ctrl;
+ u32 cfg;
+ u32 dma_addr;
+ u32 ext_addr;
};
struct solo_p2m_dev {
struct mutex mutex;
struct completion completion;
+ int desc_count;
+ int desc_idx;
+ struct solo_p2m_desc *descs;
int error;
};
-#define OSD_TEXT_MAX 30
+#define OSD_TEXT_MAX 44
+
+struct solo_vb2_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
enum solo_enc_types {
SOLO_ENC_TYPE_STD,
@@ -149,46 +166,61 @@ enum solo_enc_types {
};
struct solo_enc_dev {
- struct solo_dev *solo_dev;
+ struct solo_dev *solo_dev;
/* V4L2 Items */
+ struct v4l2_ctrl_handler hdl;
struct video_device *vfd;
/* General accounting */
- wait_queue_head_t thread_wait;
- spinlock_t lock;
- atomic_t readers;
+ struct mutex lock;
+ spinlock_t motion_lock;
u8 ch;
u8 mode, gop, qp, interlaced, interval;
- u8 reset_gop;
u8 bw_weight;
- u8 motion_detected;
u16 motion_thresh;
+ struct solo_motion_thresholds motion_thresholds;
+ bool motion_global;
+ bool motion_enabled;
u16 width;
u16 height;
+
+ /* OSD buffers */
char osd_text[OSD_TEXT_MAX + 1];
-};
+ u8 osd_buf[SOLO_EOSD_EXT_SIZE_MAX]
+ __aligned(4);
-struct solo_enc_buf {
- u8 vop;
- u8 ch;
+ /* VOP stuff */
+ unsigned char vop[64];
+ int vop_len;
+ unsigned char jpeg_header[1024];
+ int jpeg_len;
+
+ u32 fmt;
enum solo_enc_types type;
- u32 off;
- u32 size;
- u32 jpeg_off;
- u32 jpeg_size;
- struct timeval ts;
+ u32 sequence;
+ struct vb2_queue vidq;
+ struct list_head vidq_active;
+ int desc_count;
+ int desc_nelts;
+ struct solo_p2m_desc *desc_items;
+ dma_addr_t desc_dma;
+ spinlock_t av_lock;
};
/* The SOLO6x10 PCI Device */
struct solo_dev {
/* General stuff */
struct pci_dev *pdev;
+ int type;
+ unsigned int time_sync;
+ unsigned int usec_lsb;
+ unsigned int clock_mhz;
u8 __iomem *reg_base;
int nr_chans;
int nr_ext;
- u32 flags;
u32 irq_mask;
u32 motion_mask;
spinlock_t reg_io_lock;
+ struct v4l2_device v4l2_dev;
/* tw28xx accounting */
u8 tw2865, tw2864, tw2815;
@@ -206,6 +238,9 @@ struct solo_dev {
/* P2M DMA Engine */
struct solo_p2m_dev p2m_dev[SOLO_NR_P2M];
+ atomic_t p2m_count;
+ int p2m_jiffies;
+ unsigned int p2m_timeouts;
/* V4L2 Display items */
struct video_device *vfd;
@@ -213,15 +248,13 @@ struct solo_dev {
unsigned int frame_blank;
u8 cur_disp_ch;
wait_queue_head_t disp_thread_wait;
+ struct v4l2_ctrl_handler disp_hdl;
/* V4L2 Encoder items */
struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS];
u16 enc_bw_remain;
/* IDX into hw mp4 encoder */
u8 enc_idx;
- /* Our software ring of enc buf references */
- u16 enc_wr_idx;
- struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS];
/* Current video settings */
u32 video_type;
@@ -230,11 +263,40 @@ struct solo_dev {
u16 vin_hstart, vin_vstart;
u8 fps;
+ /* JPEG Qp setting */
+ spinlock_t jpeg_qp_lock;
+ u32 jpeg_qp[2];
+
/* Audio components */
struct snd_card *snd_card;
struct snd_pcm *snd_pcm;
atomic_t snd_users;
int g723_hw_idx;
+
+ /* sysfs stuffs */
+ struct device dev;
+ int sdram_size;
+ struct bin_attribute sdram_attr;
+ unsigned int sys_config;
+
+ /* Ring thread */
+ struct task_struct *ring_thread;
+ wait_queue_head_t ring_thread_wait;
+
+ /* VOP_HEADER handling */
+ void *vh_buf;
+ dma_addr_t vh_dma;
+ int vh_size;
+
+ /* Buffer handling */
+ struct vb2_queue vidq;
+ struct vb2_alloc_ctx *alloc_ctx;
+ u32 sequence;
+ struct task_struct *kthread;
+ struct mutex lock;
+ spinlock_t slock;
+ int old_write;
+ struct list_head vidq_active;
};
static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
@@ -255,7 +317,8 @@ static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg)
return ret;
}
-static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data)
+static inline void solo_reg_write(struct solo_dev *solo_dev, int reg,
+ u32 data)
{
unsigned long flags;
u16 val;
@@ -270,10 +333,19 @@ static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data)
spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags);
}
-void solo_irq_on(struct solo_dev *solo_dev, u32 mask);
-void solo_irq_off(struct solo_dev *solo_dev, u32 mask);
+static inline void solo_irq_on(struct solo_dev *dev, u32 mask)
+{
+ dev->irq_mask |= mask;
+ solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
+}
+
+static inline void solo_irq_off(struct solo_dev *dev, u32 mask)
+{
+ dev->irq_mask &= ~mask;
+ solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask);
+}
-/* Init/exit routeines for subsystems */
+/* Init/exit routines for subsystems */
int solo_disp_init(struct solo_dev *solo_dev);
void solo_disp_exit(struct solo_dev *solo_dev);
@@ -286,13 +358,13 @@ void solo_i2c_exit(struct solo_dev *solo_dev);
int solo_p2m_init(struct solo_dev *solo_dev);
void solo_p2m_exit(struct solo_dev *solo_dev);
-int solo_v4l2_init(struct solo_dev *solo_dev);
+int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
void solo_v4l2_exit(struct solo_dev *solo_dev);
int solo_enc_init(struct solo_dev *solo_dev);
void solo_enc_exit(struct solo_dev *solo_dev);
-int solo_enc_v4l2_init(struct solo_dev *solo_dev);
+int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr);
void solo_enc_v4l2_exit(struct solo_dev *solo_dev);
int solo_g723_init(struct solo_dev *solo_dev);
@@ -301,7 +373,7 @@ void solo_g723_exit(struct solo_dev *solo_dev);
/* ISR's */
int solo_i2c_isr(struct solo_dev *solo_dev);
void solo_p2m_isr(struct solo_dev *solo_dev, int id);
-void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status);
+void solo_p2m_error_isr(struct solo_dev *solo_dev);
void solo_enc_v4l2_isr(struct solo_dev *solo_dev);
void solo_g723_isr(struct solo_dev *solo_dev);
void solo_motion_isr(struct solo_dev *solo_dev);
@@ -313,24 +385,43 @@ void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off,
u8 data);
/* P2M DMA */
-int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr,
- dma_addr_t dma_addr, u32 ext_addr, u32 size);
-int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr,
- void *sys_addr, u32 ext_addr, u32 size);
-int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id,
- struct p2m_desc *pdesc, int wr,
- struct scatterlist *sglist, u32 sg_off,
- u32 ext_addr, u32 size);
-void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr,
- u32 ext_addr, u32 size, int repeat, u32 ext_size);
-int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id,
- struct p2m_desc *desc, int desc_count);
+int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size);
+int solo_p2m_dma(struct solo_dev *solo_dev, int wr,
+ void *sys_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size);
+void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
+ dma_addr_t dma_addr, u32 ext_addr, u32 size,
+ int repeat, u32 ext_size);
+int solo_p2m_dma_desc(struct solo_dev *solo_dev,
+ struct solo_p2m_desc *desc, dma_addr_t desc_dma,
+ int desc_cnt);
+
+/* Global s_std ioctl */
+int solo_set_video_type(struct solo_dev *solo_dev, bool type);
+void solo_update_mode(struct solo_enc_dev *solo_enc);
/* Set the threshold for motion detection */
-void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
+int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
+int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
+ const struct solo_motion_thresholds *thresholds);
#define SOLO_DEF_MOT_THRESH 0x0300
/* Write text on OSD */
int solo_osd_print(struct solo_enc_dev *solo_enc);
+/* EEPROM commands */
+unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
+unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
+ unsigned short data);
+
+/* JPEG Qp functions */
+void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
+ unsigned int qp);
+int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch);
+
+#define CHK_FLAGS(v, flags) (((v) & (flags)) == (flags))
+
#endif /* __SOLO6X10_H */
diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c
deleted file mode 100644
index 4977e869d5b7..000000000000
--- a/drivers/staging/media/solo6x10/v4l2-enc.c
+++ /dev/null
@@ -1,1829 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-dma-sg.h>
-#include "solo6x10.h"
-#include "tw28.h"
-#include "solo6x10-jpeg.h"
-
-#define MIN_VID_BUFFERS 4
-#define FRAME_BUF_SIZE (128 * 1024)
-#define MP4_QS 16
-
-static int solo_enc_thread(void *data);
-
-extern unsigned video_nr;
-
-struct solo_enc_fh {
- struct solo_enc_dev *enc;
- u32 fmt;
- u16 rd_idx;
- u8 enc_on;
- enum solo_enc_types type;
- struct videobuf_queue vidq;
- struct list_head vidq_active;
- struct task_struct *kthread;
- struct p2m_desc desc[SOLO_NR_P2M_DESC];
-};
-
-static const u32 solo_user_ctrls[] = {
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_SHARPNESS,
- 0
-};
-
-static const u32 solo_mpeg_ctrls[] = {
- V4L2_CID_MPEG_VIDEO_ENCODING,
- V4L2_CID_MPEG_VIDEO_GOP_SIZE,
- 0
-};
-
-static const u32 solo_private_ctrls[] = {
- V4L2_CID_MOTION_ENABLE,
- V4L2_CID_MOTION_THRESHOLD,
- 0
-};
-
-static const u32 solo_fmtx_ctrls[] = {
- V4L2_CID_RDS_TX_RADIO_TEXT,
- 0
-};
-
-static const u32 *solo_ctrl_classes[] = {
- solo_user_ctrls,
- solo_mpeg_ctrls,
- solo_fmtx_ctrls,
- solo_private_ctrls,
- NULL
-};
-
-static int solo_is_motion_on(struct solo_enc_dev *solo_enc)
-{
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- u8 ch = solo_enc->ch;
-
- if (solo_dev->motion_mask & (1 << ch))
- return 1;
- return 0;
-}
-
-static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on)
-{
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- u8 ch = solo_enc->ch;
-
- spin_lock(&solo_enc->lock);
-
- if (on)
- solo_dev->motion_mask |= (1 << ch);
- else
- solo_dev->motion_mask &= ~(1 << ch);
-
- /* Do this regardless of if we are turning on or off */
- solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
- 1 << solo_enc->ch);
- solo_enc->motion_detected = 0;
-
- solo_reg_write(solo_dev, SOLO_VI_MOT_ADR,
- SOLO_VI_MOTION_EN(solo_dev->motion_mask) |
- (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16));
-
- if (solo_dev->motion_mask)
- solo_irq_on(solo_dev, SOLO_IRQ_MOTION);
- else
- solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
- spin_unlock(&solo_enc->lock);
-}
-
-/* Should be called with solo_enc->lock held */
-static void solo_update_mode(struct solo_enc_dev *solo_enc)
-{
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- assert_spin_locked(&solo_enc->lock);
-
- solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
- solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
-
- switch (solo_enc->mode) {
- case SOLO_ENC_MODE_CIF:
- solo_enc->width = solo_dev->video_hsize >> 1;
- solo_enc->height = solo_dev->video_vsize;
- break;
- case SOLO_ENC_MODE_D1:
- solo_enc->width = solo_dev->video_hsize;
- solo_enc->height = solo_dev->video_vsize << 1;
- solo_enc->bw_weight <<= 2;
- break;
- default:
- WARN(1, "mode is unknown\n");
- }
-}
-
-/* Should be called with solo_enc->lock held */
-static int solo_enc_on(struct solo_enc_fh *fh)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
- u8 ch = solo_enc->ch;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- u8 interval;
-
- assert_spin_locked(&solo_enc->lock);
-
- if (fh->enc_on)
- return 0;
-
- solo_update_mode(solo_enc);
-
- /* Make sure to bw check on first reader */
- if (!atomic_read(&solo_enc->readers)) {
- if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
- return -EBUSY;
- else
- solo_dev->enc_bw_remain -= solo_enc->bw_weight;
- }
-
- fh->enc_on = 1;
- fh->rd_idx = solo_enc->solo_dev->enc_wr_idx;
-
- if (fh->type == SOLO_ENC_TYPE_EXT)
- solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1);
-
- if (atomic_inc_return(&solo_enc->readers) > 1)
- return 0;
-
- /* Disable all encoding for this channel */
- solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0);
-
- /* Common for both std and ext encoding */
- solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch),
- solo_enc->interlaced ? 1 : 0);
-
- if (solo_enc->interlaced)
- interval = solo_enc->interval - 1;
- else
- interval = solo_enc->interval;
-
- /* Standard encoding only */
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop);
- solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp);
- solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval);
-
- /* Extended encoding only */
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop);
- solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp);
- solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval);
-
- /* Enables the standard encoder */
- solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode);
-
- /* Settle down Beavis... */
- mdelay(10);
-
- return 0;
-}
-
-static void solo_enc_off(struct solo_enc_fh *fh)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- if (!fh->enc_on)
- return;
-
- if (fh->kthread) {
- kthread_stop(fh->kthread);
- fh->kthread = NULL;
- }
-
- solo_dev->enc_bw_remain += solo_enc->bw_weight;
- fh->enc_on = 0;
-
- if (atomic_dec_return(&solo_enc->readers) > 0)
- return;
-
- solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0);
- solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0);
-}
-
-static int solo_start_fh_thread(struct solo_enc_fh *fh)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
-
- fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc");
-
- /* Oops, we had a problem */
- if (IS_ERR(fh->kthread)) {
- spin_lock(&solo_enc->lock);
- solo_enc_off(fh);
- spin_unlock(&solo_enc->lock);
-
- return PTR_ERR(fh->kthread);
- }
-
- return 0;
-}
-
-static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch)
-{
- BUG_ON(ch >= solo_dev->nr_chans);
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1);
- solo_dev->v4l2_enc[ch]->reset_gop = 1;
-}
-
-static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop)
-{
- BUG_ON(ch >= solo_dev->nr_chans);
- if (!solo_dev->v4l2_enc[ch]->reset_gop)
- return 0;
- if (vop)
- return 1;
- solo_dev->v4l2_enc[ch]->reset_gop = 0;
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch),
- solo_dev->v4l2_enc[ch]->gop);
- return 0;
-}
-
-static void enc_write_sg(struct scatterlist *sglist, void *buf, int size)
-{
- struct scatterlist *sg;
- u8 *src = buf;
-
- for (sg = sglist; sg && size > 0; sg = sg_next(sg)) {
- u8 *p = sg_virt(sg);
- size_t len = sg_dma_len(sg);
- int i;
-
- for (i = 0; i < len && size; i++)
- p[i] = *(src++);
- }
-}
-
-static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev,
- struct p2m_desc *desc,
- struct scatterlist *sglist, int skip,
- unsigned int off, unsigned int size)
-{
- int ret;
-
- if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
- return -EINVAL;
-
- if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
- return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E,
- desc, 0, sglist, skip,
- SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
- }
-
- /* Buffer wrap */
- ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
- sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off,
- SOLO_MP4E_EXT_SIZE(solo_dev) - off);
-
- ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0,
- sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
- SOLO_MP4E_EXT_ADDR(solo_dev),
- size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
-
- return ret;
-}
-
-static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev,
- dma_addr_t buf, unsigned int off,
- unsigned int size)
-{
- int ret;
-
- if (off > SOLO_MP4E_EXT_SIZE(solo_dev))
- return -EINVAL;
-
- if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) {
- return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
- SOLO_MP4E_EXT_ADDR(solo_dev) + off, size);
- }
-
- /* Buffer wrap */
- ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf,
- SOLO_MP4E_EXT_ADDR(solo_dev) + off,
- SOLO_MP4E_EXT_SIZE(solo_dev) - off);
-
- ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0,
- buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off,
- SOLO_MP4E_EXT_ADDR(solo_dev),
- size + off - SOLO_MP4E_EXT_SIZE(solo_dev));
-
- return ret;
-}
-
-static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf,
- unsigned int off, unsigned int size)
-{
- int ret;
-
- dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size,
- PCI_DMA_FROMDEVICE);
- ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size);
- pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE);
-
- return ret;
-}
-
-static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev,
- struct p2m_desc *desc,
- struct scatterlist *sglist, int skip,
- unsigned int off, unsigned int size)
-{
- int ret;
-
- if (off > SOLO_JPEG_EXT_SIZE(solo_dev))
- return -EINVAL;
-
- if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) {
- return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG,
- desc, 0, sglist, skip,
- SOLO_JPEG_EXT_ADDR(solo_dev) + off, size);
- }
-
- /* Buffer wrap */
- ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
- sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off,
- SOLO_JPEG_EXT_SIZE(solo_dev) - off);
-
- ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0,
- sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off,
- SOLO_JPEG_EXT_ADDR(solo_dev),
- size + off - SOLO_JPEG_EXT_SIZE(solo_dev));
-
- return ret;
-}
-
-/* Returns true of __chk is within the first __range bytes of __off */
-#define OFF_IN_RANGE(__off, __range, __chk) \
- ((__off <= __chk) && ((__off + __range) >= __chk))
-
-static void solo_jpeg_header(struct solo_enc_dev *solo_enc,
- struct videobuf_dmabuf *vbuf)
-{
- struct scatterlist *sg;
- void *src = jpeg_header;
- size_t copied = 0;
- size_t to_copy = sizeof(jpeg_header);
-
- for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) {
- size_t this_copy = min(sg_dma_len(sg),
- (unsigned int)(to_copy - copied));
- u8 *p = sg_virt(sg);
-
- memcpy(p, src + copied, this_copy);
-
- if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5))
- p[(SOF0_START + 5) - copied] =
- 0xff & (solo_enc->height >> 8);
- if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6))
- p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height;
- if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7))
- p[(SOF0_START + 7) - copied] =
- 0xff & (solo_enc->width >> 8);
- if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8))
- p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width;
-
- copied += this_copy;
- }
-}
-
-static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
- struct videobuf_buffer *vb,
- struct videobuf_dmabuf *vbuf)
-{
- struct solo_dev *solo_dev = fh->enc->solo_dev;
- int size = enc_buf->jpeg_size;
-
- /* Copy the header first (direct write) */
- solo_jpeg_header(fh->enc, vbuf);
-
- vb->size = size + sizeof(jpeg_header);
-
- /* Grab the jpeg frame */
- return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
- sizeof(jpeg_header),
- enc_buf->jpeg_off, size);
-}
-
-static inline int vop_interlaced(__le32 *vh)
-{
- return (__le32_to_cpu(vh[0]) >> 30) & 1;
-}
-
-static inline u32 vop_size(__le32 *vh)
-{
- return __le32_to_cpu(vh[0]) & 0xFFFFF;
-}
-
-static inline u8 vop_hsize(__le32 *vh)
-{
- return (__le32_to_cpu(vh[1]) >> 8) & 0xFF;
-}
-
-static inline u8 vop_vsize(__le32 *vh)
-{
- return __le32_to_cpu(vh[1]) & 0xFF;
-}
-
-/* must be called with *bits % 8 = 0 */
-static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count)
-{
- memcpy(*out, src, count);
- *out += count;
- *bits += count * 8;
-}
-
-static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count)
-{
-
- value <<= 32 - count; // shift to the right
-
- while (count--) {
- **out <<= 1;
- **out |= !!(value & (1 << 31)); /* MSB */
- value <<= 1;
- if (++(*bits) % 8 == 0)
- (*out)++;
- }
-}
-
-static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */
-{
- uint32_t max = 0, cnt = 0;
-
- while (value > max) {
- max = (max + 2) * 2 - 2;
- cnt++;
- }
- write_bits(out, bits, 1, cnt + 1);
- write_bits(out, bits, ~(max - value), cnt);
-}
-
-static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */
-{
- if (value <= 0)
- write_ue(out, bits, -value * 2);
- else
- write_ue(out, bits, value * 2 - 1);
-}
-
-static void write_mpeg4_end(u8 **out, unsigned *bits)
-{
- write_bits(out, bits, 0, 1);
- /* align on 32-bit boundary */
- if (*bits % 32)
- write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32);
-}
-
-static void write_h264_end(u8 **out, unsigned *bits, int align)
-{
- write_bits(out, bits, 1, 1);
- while ((*bits) % 8)
- write_bits(out, bits, 0, 1);
- if (align)
- while ((*bits) % 32)
- write_bits(out, bits, 0, 1);
-}
-
-static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev,
- __le32 *vh, unsigned fps, unsigned interval)
-{
- static const u8 hdr[] = {
- 0, 0, 1, 0x00 /* video_object_start_code */,
- 0, 0, 1, 0x20 /* video_object_layer_start_code */
- };
- unsigned bits = 0;
- unsigned width = vop_hsize(vh) << 4;
- unsigned height = vop_vsize(vh) << 4;
- unsigned interlaced = vop_interlaced(vh);
-
- write_bytes(out, &bits, hdr, sizeof(hdr));
- write_bits(out, &bits, 0, 1); /* random_accessible_vol */
- write_bits(out, &bits, 0x04, 8); /* video_object_type_indication: main */
- write_bits(out, &bits, 1, 1); /* is_object_layer_identifier */
- write_bits(out, &bits, 2, 4); /* video_object_layer_verid: table V2-39 */
- write_bits(out, &bits, 0, 3); /* video_object_layer_priority */
- if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
- write_bits(out, &bits, 3, 4); /* aspect_ratio_info, assuming 4:3 */
- else
- write_bits(out, &bits, 2, 4);
- write_bits(out, &bits, 1, 1); /* vol_control_parameters */
- write_bits(out, &bits, 1, 2); /* chroma_format: 4:2:0 */
- write_bits(out, &bits, 1, 1); /* low_delay */
- write_bits(out, &bits, 0, 1); /* vbv_parameters */
- write_bits(out, &bits, 0, 2); /* video_object_layer_shape: rectangular */
- write_bits(out, &bits, 1, 1); /* marker_bit */
- write_bits(out, &bits, fps, 16); /* vop_time_increment_resolution */
- write_bits(out, &bits, 1, 1); /* marker_bit */
- write_bits(out, &bits, 1, 1); /* fixed_vop_rate */
- write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */
- write_bits(out, &bits, 1, 1); /* marker_bit */
- write_bits(out, &bits, width, 13); /* video_object_layer_width */
- write_bits(out, &bits, 1, 1); /* marker_bit */
- write_bits(out, &bits, height, 13); /* video_object_layer_height */
- write_bits(out, &bits, 1, 1); /* marker_bit */
- write_bits(out, &bits, interlaced, 1); /* interlaced */
- write_bits(out, &bits, 1, 1); /* obmc_disable */
- write_bits(out, &bits, 0, 2); /* sprite_enable */
- write_bits(out, &bits, 0, 1); /* not_8_bit */
- write_bits(out, &bits, 1, 0); /* quant_type */
- write_bits(out, &bits, 0, 1); /* load_intra_quant_mat */
- write_bits(out, &bits, 0, 1); /* load_nonintra_quant_mat */
- write_bits(out, &bits, 0, 1); /* quarter_sample */
- write_bits(out, &bits, 1, 1); /* complexity_estimation_disable */
- write_bits(out, &bits, 1, 1); /* resync_marker_disable */
- write_bits(out, &bits, 0, 1); /* data_partitioned */
- write_bits(out, &bits, 0, 1); /* newpred_enable */
- write_bits(out, &bits, 0, 1); /* reduced_resolution_vop_enable */
- write_bits(out, &bits, 0, 1); /* scalability */
- write_mpeg4_end(out, &bits);
-}
-
-static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh)
-{
- static const u8 sps[] = {
- 0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */,
- 0 /* constraints */, 30 /* level_idc */
- };
- static const u8 pps[] = {
- 0, 0, 0, 1 /* start code */, 0x68
- };
-
- unsigned bits = 0;
- unsigned mbs_w = vop_hsize(vh);
- unsigned mbs_h = vop_vsize(vh);
-
- write_bytes(out, &bits, sps, sizeof(sps));
- write_ue(out, &bits, 0); /* seq_parameter_set_id */
- write_ue(out, &bits, 5); /* log2_max_frame_num_minus4 */
- write_ue(out, &bits, 0); /* pic_order_cnt_type */
- write_ue(out, &bits, 6); /* log2_max_pic_order_cnt_lsb_minus4 */
- write_ue(out, &bits, 1); /* max_num_ref_frames */
- write_bits(out, &bits, 0, 1); /* gaps_in_frame_num_value_allowed_flag */
- write_ue(out, &bits, mbs_w - 1); /* pic_width_in_mbs_minus1 */
- write_ue(out, &bits, mbs_h - 1); /* pic_height_in_map_units_minus1 */
- write_bits(out, &bits, 1, 1); /* frame_mbs_only_flag */
- write_bits(out, &bits, 1, 1); /* direct_8x8_frame_field_flag */
- write_bits(out, &bits, 0, 1); /* frame_cropping_flag */
- write_bits(out, &bits, 0, 1); /* vui_parameters_present_flag */
- write_h264_end(out, &bits, 0);
-
- write_bytes(out, &bits, pps, sizeof(pps));
- write_ue(out, &bits, 0); /* pic_parameter_set_id */
- write_ue(out, &bits, 0); /* seq_parameter_set_id */
- write_bits(out, &bits, 0, 1); /* entropy_coding_mode_flag */
- write_bits(out, &bits, 0, 1); /* bottom_field_pic_order_in_frame_present_flag */
- write_ue(out, &bits, 0); /* num_slice_groups_minus1 */
- write_ue(out, &bits, 0); /* num_ref_idx_l0_default_active_minus1 */
- write_ue(out, &bits, 0); /* num_ref_idx_l1_default_active_minus1 */
- write_bits(out, &bits, 0, 1); /* weighted_pred_flag */
- write_bits(out, &bits, 0, 2); /* weighted_bipred_idc */
- write_se(out, &bits, 0); /* pic_init_qp_minus26 */
- write_se(out, &bits, 0); /* pic_init_qs_minus26 */
- write_se(out, &bits, 2); /* chroma_qp_index_offset */
- write_bits(out, &bits, 0, 1); /* deblocking_filter_control_present_flag */
- write_bits(out, &bits, 1, 1); /* constrained_intra_pred_flag */
- write_bits(out, &bits, 0, 1); /* redundant_pic_cnt_present_flag */
- write_h264_end(out, &bits, 1);
-}
-
-static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf,
- struct videobuf_buffer *vb,
- struct videobuf_dmabuf *vbuf)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
-#define VH_WORDS 16
-#define MAX_VOL_HEADER_LENGTH 64
-
- __le32 vh[VH_WORDS];
- int ret;
- int frame_size, frame_off;
- int skip = 0;
-
- if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh)))
- return -EINVAL;
-
- /* First get the hardware vop header (not real mpeg) */
- ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh));
- if (WARN_ON_ONCE(ret))
- return ret;
-
- if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size))
- return -EINVAL;
-
- vb->width = vop_hsize(vh) << 4;
- vb->height = vop_vsize(vh) << 4;
- vb->size = vop_size(vh);
-
- /* If this is a key frame, add extra m4v header */
- if (!enc_buf->vop) {
- u8 header[MAX_VOL_HEADER_LENGTH], *out = header;
-
- if (solo_dev->flags & FLAGS_6110)
- h264_write_vol(&out, solo_dev, vh);
- else
- mpeg4_write_vol(&out, solo_dev, vh,
- solo_dev->fps * 1000,
- solo_enc->interval * 1000);
- skip = out - header;
- enc_write_sg(vbuf->sglist, header, skip);
- /* Adjust the dma buffer past this header */
- vb->size += skip;
- }
-
- /* Now get the actual mpeg payload */
- frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
- frame_size = enc_buf->size - sizeof(vh);
-
- ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist,
- skip, frame_off, frame_size);
- WARN_ON_ONCE(ret);
-
- return ret;
-}
-
-static void solo_enc_fillbuf(struct solo_enc_fh *fh,
- struct videobuf_buffer *vb)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct solo_enc_buf *enc_buf = NULL;
- struct videobuf_dmabuf *vbuf;
- int ret;
- int error = 1;
- u16 idx = fh->rd_idx;
-
- while (idx != solo_dev->enc_wr_idx) {
- struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx];
-
- idx = (idx + 1) % SOLO_NR_RING_BUFS;
-
- if (ebuf->ch != solo_enc->ch)
- continue;
-
- if (fh->fmt == V4L2_PIX_FMT_MPEG) {
- if (fh->type == ebuf->type) {
- enc_buf = ebuf;
- break;
- }
- } else {
- /* For mjpeg, keep reading to the newest frame */
- enc_buf = ebuf;
- }
- }
-
- fh->rd_idx = idx;
-
- if (WARN_ON_ONCE(!enc_buf))
- goto buf_err;
-
- if ((fh->fmt == V4L2_PIX_FMT_MPEG &&
- vb->bsize < enc_buf->size) ||
- (fh->fmt == V4L2_PIX_FMT_MJPEG &&
- vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) {
- WARN_ON_ONCE(1);
- goto buf_err;
- }
-
- vbuf = videobuf_to_dma(vb);
- if (WARN_ON_ONCE(!vbuf))
- goto buf_err;
-
- if (fh->fmt == V4L2_PIX_FMT_MPEG)
- ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf);
- else
- ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf);
-
- if (!ret)
- error = 0;
-
-buf_err:
- if (error) {
- vb->state = VIDEOBUF_ERROR;
- } else {
- vb->field_count++;
- vb->ts = enc_buf->ts;
- vb->state = VIDEOBUF_DONE;
- }
-
- wake_up(&vb->done);
-
- return;
-}
-
-static void solo_enc_thread_try(struct solo_enc_fh *fh)
-{
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct videobuf_buffer *vb;
-
- for (;;) {
- spin_lock(&solo_enc->lock);
-
- if (fh->rd_idx == solo_dev->enc_wr_idx)
- break;
-
- if (list_empty(&fh->vidq_active))
- break;
-
- vb = list_first_entry(&fh->vidq_active,
- struct videobuf_buffer, queue);
-
- if (!waitqueue_active(&vb->done))
- break;
-
- list_del(&vb->queue);
-
- spin_unlock(&solo_enc->lock);
-
- solo_enc_fillbuf(fh, vb);
- }
-
- assert_spin_locked(&solo_enc->lock);
- spin_unlock(&solo_enc->lock);
-}
-
-static int solo_enc_thread(void *data)
-{
- struct solo_enc_fh *fh = data;
- struct solo_enc_dev *solo_enc = fh->enc;
- DECLARE_WAITQUEUE(wait, current);
-
- set_freezable();
- add_wait_queue(&solo_enc->thread_wait, &wait);
-
- for (;;) {
- long timeout = schedule_timeout_interruptible(HZ);
- if (timeout == -ERESTARTSYS || kthread_should_stop())
- break;
- solo_enc_thread_try(fh);
- try_to_freeze();
- }
-
- remove_wait_queue(&solo_enc->thread_wait, &wait);
-
- return 0;
-}
-
-void solo_motion_isr(struct solo_dev *solo_dev)
-{
- u32 status;
- int i;
-
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION);
-
- status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS);
-
- for (i = 0; i < solo_dev->nr_chans; i++) {
- struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i];
-
- BUG_ON(solo_enc == NULL);
-
- if (solo_enc->motion_detected)
- continue;
- if (!(status & (1 << i)))
- continue;
-
- solo_enc->motion_detected = 1;
- }
-}
-
-void solo_enc_v4l2_isr(struct solo_dev *solo_dev)
-{
- struct solo_enc_buf *enc_buf;
- u32 mpeg_current, mpeg_next, mpeg_size;
- u32 jpeg_current, jpeg_next, jpeg_size;
- u32 reg_mpeg_size;
- u8 cur_q, vop_type;
- u8 ch;
- enum solo_enc_types enc_type;
-
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER);
-
- cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS;
-
- reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7;
-
- while (solo_dev->enc_idx != cur_q) {
- mpeg_current = solo_reg_read(solo_dev,
- SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
- jpeg_current = solo_reg_read(solo_dev,
- SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
- solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS;
- mpeg_next = solo_reg_read(solo_dev,
- SOLO_VE_MPEG4_QUE(solo_dev->enc_idx));
- jpeg_next = solo_reg_read(solo_dev,
- SOLO_VE_JPEG_QUE(solo_dev->enc_idx));
-
- ch = (mpeg_current >> 24) & 0x1f;
- if (ch >= SOLO_MAX_CHANNELS) {
- ch -= SOLO_MAX_CHANNELS;
- enc_type = SOLO_ENC_TYPE_EXT;
- } else
- enc_type = SOLO_ENC_TYPE_STD;
-
- vop_type = (mpeg_current >> 29) & 3;
-
- mpeg_current &= 0x00ffffff;
- mpeg_next &= 0x00ffffff;
- jpeg_current &= 0x00ffffff;
- jpeg_next &= 0x00ffffff;
-
- mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) +
- mpeg_next - mpeg_current) %
- SOLO_MP4E_EXT_SIZE(solo_dev);
-
- jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) +
- jpeg_next - jpeg_current) %
- SOLO_JPEG_EXT_SIZE(solo_dev);
-
- /* XXX I think this means we had a ring overflow? */
- if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) {
- enc_reset_gop(solo_dev, ch);
- continue;
- }
-
- /* When resetting the GOP, skip frames until I-frame */
- if (enc_gop_reset(solo_dev, ch, vop_type))
- continue;
-
- enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx];
-
- enc_buf->vop = vop_type;
- enc_buf->ch = ch;
- enc_buf->off = mpeg_current;
- enc_buf->size = mpeg_size;
- enc_buf->jpeg_off = jpeg_current;
- enc_buf->jpeg_size = jpeg_size;
- enc_buf->type = enc_type;
-
- do_gettimeofday(&enc_buf->ts);
-
- solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) %
- SOLO_NR_RING_BUFS;
-
- wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait);
- }
-
- return;
-}
-
-static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- *size = FRAME_BUF_SIZE;
-
- if (*count < MIN_VID_BUFFERS)
- *count = MIN_VID_BUFFERS;
-
- return 0;
-}
-
-static int solo_enc_buf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct solo_enc_fh *fh = vq->priv_data;
- struct solo_enc_dev *solo_enc = fh->enc;
-
- vb->size = FRAME_BUF_SIZE;
- if (vb->baddr != 0 && vb->bsize < vb->size)
- return -EINVAL;
-
- /* These properties only change when queue is idle */
- vb->width = solo_enc->width;
- vb->height = solo_enc->height;
- vb->field = field;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- int rc = videobuf_iolock(vq, vb, NULL);
- if (rc < 0) {
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- videobuf_dma_unmap(vq->dev, dma);
- videobuf_dma_free(dma);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return rc;
- }
- }
- vb->state = VIDEOBUF_PREPARED;
-
- return 0;
-}
-
-static void solo_enc_buf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct solo_enc_fh *fh = vq->priv_data;
-
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &fh->vidq_active);
- wake_up_interruptible(&fh->enc->thread_wait);
-}
-
-static void solo_enc_buf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- videobuf_dma_unmap(vq->dev, dma);
- videobuf_dma_free(dma);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops solo_enc_video_qops = {
- .buf_setup = solo_enc_buf_setup,
- .buf_prepare = solo_enc_buf_prepare,
- .buf_queue = solo_enc_buf_queue,
- .buf_release = solo_enc_buf_release,
-};
-
-static unsigned int solo_enc_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct solo_enc_fh *fh = file->private_data;
-
- return videobuf_poll_stream(file, &fh->vidq, wait);
-}
-
-static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct solo_enc_fh *fh = file->private_data;
-
- return videobuf_mmap_mapper(&fh->vidq, vma);
-}
-
-static int solo_enc_open(struct file *file)
-{
- struct solo_enc_dev *solo_enc = video_drvdata(file);
- struct solo_enc_fh *fh;
-
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (fh == NULL)
- return -ENOMEM;
-
- fh->enc = solo_enc;
- file->private_data = fh;
- INIT_LIST_HEAD(&fh->vidq_active);
- fh->fmt = V4L2_PIX_FMT_MPEG;
- fh->type = SOLO_ENC_TYPE_STD;
-
- videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops,
- &solo_enc->solo_dev->pdev->dev,
- &solo_enc->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer), fh, NULL);
-
- return 0;
-}
-
-static ssize_t solo_enc_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct solo_enc_fh *fh = file->private_data;
- struct solo_enc_dev *solo_enc = fh->enc;
-
- /* Make sure the encoder is on */
- if (!fh->enc_on) {
- int ret;
-
- spin_lock(&solo_enc->lock);
- ret = solo_enc_on(fh);
- spin_unlock(&solo_enc->lock);
- if (ret)
- return ret;
-
- ret = solo_start_fh_thread(fh);
- if (ret)
- return ret;
- }
-
- return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static int solo_enc_release(struct file *file)
-{
- struct solo_enc_fh *fh = file->private_data;
- struct solo_enc_dev *solo_enc = fh->enc;
-
- videobuf_stop(&fh->vidq);
- videobuf_mmap_free(&fh->vidq);
-
- spin_lock(&solo_enc->lock);
- solo_enc_off(fh);
- spin_unlock(&solo_enc->lock);
-
- kfree(fh);
-
- return 0;
-}
-
-static int solo_enc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- strcpy(cap->driver, SOLO6X10_NAME);
- snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
- solo_enc->ch);
- snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
- pci_name(solo_dev->pdev));
- cap->version = SOLO6X10_VER_NUM;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- return 0;
-}
-
-static int solo_enc_enum_input(struct file *file, void *priv,
- struct v4l2_input *input)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- if (input->index)
- return -EINVAL;
-
- snprintf(input->name, sizeof(input->name), "Encoder %d",
- solo_enc->ch + 1);
- input->type = V4L2_INPUT_TYPE_CAMERA;
-
- if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
- input->std = V4L2_STD_NTSC_M;
- else
- input->std = V4L2_STD_PAL_B;
-
- if (!tw28_get_video_status(solo_dev, solo_enc->ch))
- input->status = V4L2_IN_ST_NO_SIGNAL;
-
- return 0;
-}
-
-static int solo_enc_set_input(struct file *file, void *priv, unsigned int index)
-{
- if (index)
- return -EINVAL;
-
- return 0;
-}
-
-static int solo_enc_get_input(struct file *file, void *priv,
- unsigned int *index)
-{
- *index = 0;
-
- return 0;
-}
-
-static int solo_enc_enum_fmt_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- switch (f->index) {
- case 0:
- f->pixelformat = V4L2_PIX_FMT_MPEG;
- strcpy(f->description, "MPEG-4 AVC");
- break;
- case 1:
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- strcpy(f->description, "MJPEG");
- break;
- default:
- return -EINVAL;
- }
-
- f->flags = V4L2_FMT_FLAG_COMPRESSED;
-
- return 0;
-}
-
-static int solo_enc_try_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- if (pix->pixelformat != V4L2_PIX_FMT_MPEG &&
- pix->pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
-
- /* We cannot change width/height in mid read */
- if (atomic_read(&solo_enc->readers) > 0) {
- if (pix->width != solo_enc->width ||
- pix->height != solo_enc->height)
- return -EBUSY;
- }
-
- if (pix->width < solo_dev->video_hsize ||
- pix->height < solo_dev->video_vsize << 1) {
- /* Default to CIF 1/2 size */
- pix->width = solo_dev->video_hsize >> 1;
- pix->height = solo_dev->video_vsize;
- } else {
- /* Full frame */
- pix->width = solo_dev->video_hsize;
- pix->height = solo_dev->video_vsize << 1;
- }
-
- if (pix->field == V4L2_FIELD_ANY)
- pix->field = V4L2_FIELD_INTERLACED;
- else if (pix->field != V4L2_FIELD_INTERLACED)
- pix->field = V4L2_FIELD_INTERLACED;
-
- /* Just set these */
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
- pix->sizeimage = FRAME_BUF_SIZE;
-
- return 0;
-}
-
-static int solo_enc_set_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int ret;
-
- spin_lock(&solo_enc->lock);
-
- ret = solo_enc_try_fmt_cap(file, priv, f);
- if (ret) {
- spin_unlock(&solo_enc->lock);
- return ret;
- }
-
- if (pix->width == solo_dev->video_hsize)
- solo_enc->mode = SOLO_ENC_MODE_D1;
- else
- solo_enc->mode = SOLO_ENC_MODE_CIF;
-
- /* This does not change the encoder at all */
- fh->fmt = pix->pixelformat;
-
- if (pix->priv)
- fh->type = SOLO_ENC_TYPE_EXT;
- ret = solo_enc_on(fh);
-
- spin_unlock(&solo_enc->lock);
-
- if (ret)
- return ret;
-
- return solo_start_fh_thread(fh);
-}
-
-static int solo_enc_get_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- pix->width = solo_enc->width;
- pix->height = solo_enc->height;
- pix->pixelformat = fh->fmt;
- pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED :
- V4L2_FIELD_NONE;
- pix->sizeimage = FRAME_BUF_SIZE;
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
- return 0;
-}
-
-static int solo_enc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
-{
- struct solo_enc_fh *fh = priv;
-
- return videobuf_reqbufs(&fh->vidq, req);
-}
-
-static int solo_enc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct solo_enc_fh *fh = priv;
-
- return videobuf_querybuf(&fh->vidq, buf);
-}
-
-static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_enc_fh *fh = priv;
-
- return videobuf_qbuf(&fh->vidq, buf);
-}
-
-static int solo_enc_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- int ret;
-
- /* Make sure the encoder is on */
- if (!fh->enc_on) {
- spin_lock(&solo_enc->lock);
- ret = solo_enc_on(fh);
- spin_unlock(&solo_enc->lock);
- if (ret)
- return ret;
-
- ret = solo_start_fh_thread(fh);
- if (ret)
- return ret;
- }
-
- ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
- if (ret)
- return ret;
-
- /* Signal motion detection */
- if (solo_is_motion_on(solo_enc)) {
- buf->flags |= V4L2_BUF_FLAG_MOTION_ON;
- if (solo_enc->motion_detected) {
- buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
- solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR,
- 1 << solo_enc->ch);
- solo_enc->motion_detected = 0;
- }
- }
-
- /* Check for key frame on mpeg data */
- if (fh->fmt == V4L2_PIX_FMT_MPEG) {
- struct videobuf_dmabuf *vbuf =
- videobuf_to_dma(fh->vidq.bufs[buf->index]);
-
- if (vbuf) {
- u8 *p = sg_virt(vbuf->sglist);
- if (p[3] == 0x00)
- buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
- else
- buf->flags |= V4L2_BUF_FLAG_PFRAME;
- }
- }
-
- return 0;
-}
-
-static int solo_enc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct solo_enc_fh *fh = priv;
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return videobuf_streamon(&fh->vidq);
-}
-
-static int solo_enc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct solo_enc_fh *fh = priv;
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return videobuf_streamoff(&fh->vidq);
-}
-
-static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
- return 0;
-}
-
-static int solo_enum_framesizes(struct file *file, void *priv,
- struct v4l2_frmsizeenum *fsize)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_dev *solo_dev = fh->enc->solo_dev;
-
- if (fsize->pixel_format != V4L2_PIX_FMT_MPEG)
- return -EINVAL;
-
- switch (fsize->index) {
- case 0:
- fsize->discrete.width = solo_dev->video_hsize >> 1;
- fsize->discrete.height = solo_dev->video_vsize;
- break;
- case 1:
- fsize->discrete.width = solo_dev->video_hsize;
- fsize->discrete.height = solo_dev->video_vsize << 1;
- break;
- default:
- return -EINVAL;
- }
-
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
- return 0;
-}
-
-static int solo_enum_frameintervals(struct file *file, void *priv,
- struct v4l2_frmivalenum *fintv)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_dev *solo_dev = fh->enc->solo_dev;
-
- if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index)
- return -EINVAL;
-
- fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
-
- fintv->stepwise.min.numerator = solo_dev->fps;
- fintv->stepwise.min.denominator = 1;
-
- fintv->stepwise.max.numerator = solo_dev->fps;
- fintv->stepwise.max.denominator = 15;
-
- fintv->stepwise.step.numerator = 1;
- fintv->stepwise.step.denominator = 1;
-
- return 0;
-}
-
-static int solo_g_parm(struct file *file, void *priv,
- struct v4l2_streamparm *sp)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct v4l2_captureparm *cp = &sp->parm.capture;
-
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = solo_enc->interval;
- cp->timeperframe.denominator = solo_dev->fps;
- cp->capturemode = 0;
- /* XXX: Shouldn't we be able to get/set this from videobuf? */
- cp->readbuffers = 2;
-
- return 0;
-}
-
-static int solo_s_parm(struct file *file, void *priv,
- struct v4l2_streamparm *sp)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct v4l2_captureparm *cp = &sp->parm.capture;
-
- spin_lock(&solo_enc->lock);
-
- if (atomic_read(&solo_enc->readers) > 0) {
- spin_unlock(&solo_enc->lock);
- return -EBUSY;
- }
-
- if ((cp->timeperframe.numerator == 0) ||
- (cp->timeperframe.denominator == 0)) {
- /* reset framerate */
- cp->timeperframe.numerator = 1;
- cp->timeperframe.denominator = solo_dev->fps;
- }
-
- if (cp->timeperframe.denominator != solo_dev->fps)
- cp->timeperframe.denominator = solo_dev->fps;
-
- if (cp->timeperframe.numerator > 15)
- cp->timeperframe.numerator = 15;
-
- solo_enc->interval = cp->timeperframe.numerator;
-
- cp->capability = V4L2_CAP_TIMEPERFRAME;
-
- solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1);
- solo_update_mode(solo_enc);
-
- spin_unlock(&solo_enc->lock);
-
- return 0;
-}
-
-static int solo_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
- if (!qc->id)
- return -EINVAL;
-
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80);
- case V4L2_CID_SHARPNESS:
- return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(
- qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC);
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps);
-#ifdef PRIVATE_CIDS
- case V4L2_CID_MOTION_THRESHOLD:
- qc->flags |= V4L2_CTRL_FLAG_SLIDER;
- qc->type = V4L2_CTRL_TYPE_INTEGER;
- qc->minimum = 0;
- qc->maximum = 0xffff;
- qc->step = 1;
- qc->default_value = SOLO_DEF_MOT_THRESH;
- strlcpy(qc->name, "Motion Detection Threshold",
- sizeof(qc->name));
- return 0;
- case V4L2_CID_MOTION_ENABLE:
- qc->type = V4L2_CTRL_TYPE_BOOLEAN;
- qc->minimum = 0;
- qc->maximum = qc->step = 1;
- qc->default_value = 0;
- strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name));
- return 0;
-#else
- case V4L2_CID_MOTION_THRESHOLD:
- return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1,
- SOLO_DEF_MOT_THRESH);
- case V4L2_CID_MOTION_ENABLE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-#endif
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- qc->type = V4L2_CTRL_TYPE_STRING;
- qc->minimum = 0;
- qc->maximum = OSD_TEXT_MAX;
- qc->step = 1;
- qc->default_value = 0;
- strlcpy(qc->name, "OSD Text", sizeof(qc->name));
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int solo_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
- int err;
-
- qctrl.id = qmenu->id;
- err = solo_queryctrl(file, priv, &qctrl);
- if (err)
- return err;
-
- return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL);
-}
-
-static int solo_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_SHARPNESS:
- return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
- &ctrl->value);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- ctrl->value = solo_enc->gop;
- break;
- case V4L2_CID_MOTION_THRESHOLD:
- ctrl->value = solo_enc->motion_thresh;
- break;
- case V4L2_CID_MOTION_ENABLE:
- ctrl->value = solo_is_motion_on(solo_enc);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int solo_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- struct solo_dev *solo_dev = solo_enc->solo_dev;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_SHARPNESS:
- return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch,
- ctrl->value);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC)
- return -ERANGE;
- break;
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- if (ctrl->value < 1 || ctrl->value > 255)
- return -ERANGE;
- solo_enc->gop = ctrl->value;
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch),
- solo_enc->gop);
- solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch),
- solo_enc->gop);
- break;
- case V4L2_CID_MOTION_THRESHOLD:
- /* TODO accept value on lower 16-bits and use high
- * 16-bits to assign the value to a specific block */
- if (ctrl->value < 0 || ctrl->value > 0xffff)
- return -ERANGE;
- solo_enc->motion_thresh = ctrl->value;
- solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value);
- break;
- case V4L2_CID_MOTION_ENABLE:
- solo_motion_toggle(solo_enc, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int solo_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- int i;
-
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = (ctrls->controls + i);
- int err;
-
- switch (ctrl->id) {
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- if (ctrl->size - 1 > OSD_TEXT_MAX)
- err = -ERANGE;
- else {
- err = copy_from_user(solo_enc->osd_text,
- ctrl->string,
- OSD_TEXT_MAX);
- solo_enc->osd_text[OSD_TEXT_MAX] = '\0';
- if (!err)
- err = solo_osd_print(solo_enc);
- else
- err = -EFAULT;
- }
- break;
- default:
- err = -EINVAL;
- }
-
- if (err < 0) {
- ctrls->error_idx = i;
- return err;
- }
- }
-
- return 0;
-}
-
-static int solo_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *ctrls)
-{
- struct solo_enc_fh *fh = priv;
- struct solo_enc_dev *solo_enc = fh->enc;
- int i;
-
- for (i = 0; i < ctrls->count; i++) {
- struct v4l2_ext_control *ctrl = (ctrls->controls + i);
- int err;
-
- switch (ctrl->id) {
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- if (ctrl->size < OSD_TEXT_MAX) {
- ctrl->size = OSD_TEXT_MAX;
- err = -ENOSPC;
- } else {
- err = copy_to_user(ctrl->string,
- solo_enc->osd_text,
- OSD_TEXT_MAX);
- if (err)
- err = -EFAULT;
- }
- break;
- default:
- err = -EINVAL;
- }
-
- if (err < 0) {
- ctrls->error_idx = i;
- return err;
- }
- }
-
- return 0;
-}
-
-static const struct v4l2_file_operations solo_enc_fops = {
- .owner = THIS_MODULE,
- .open = solo_enc_open,
- .release = solo_enc_release,
- .read = solo_enc_read,
- .poll = solo_enc_poll,
- .mmap = solo_enc_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
- .vidioc_querycap = solo_enc_querycap,
- .vidioc_s_std = solo_enc_s_std,
- /* Input callbacks */
- .vidioc_enum_input = solo_enc_enum_input,
- .vidioc_s_input = solo_enc_set_input,
- .vidioc_g_input = solo_enc_get_input,
- /* Video capture format callbacks */
- .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap,
- .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap,
- .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap,
- .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap,
- /* Streaming I/O */
- .vidioc_reqbufs = solo_enc_reqbufs,
- .vidioc_querybuf = solo_enc_querybuf,
- .vidioc_qbuf = solo_enc_qbuf,
- .vidioc_dqbuf = solo_enc_dqbuf,
- .vidioc_streamon = solo_enc_streamon,
- .vidioc_streamoff = solo_enc_streamoff,
- /* Frame size and interval */
- .vidioc_enum_framesizes = solo_enum_framesizes,
- .vidioc_enum_frameintervals = solo_enum_frameintervals,
- /* Video capture parameters */
- .vidioc_s_parm = solo_s_parm,
- .vidioc_g_parm = solo_g_parm,
- /* Controls */
- .vidioc_queryctrl = solo_queryctrl,
- .vidioc_querymenu = solo_querymenu,
- .vidioc_g_ctrl = solo_g_ctrl,
- .vidioc_s_ctrl = solo_s_ctrl,
- .vidioc_g_ext_ctrls = solo_g_ext_ctrls,
- .vidioc_s_ext_ctrls = solo_s_ext_ctrls,
-};
-
-static struct video_device solo_enc_template = {
- .name = SOLO6X10_NAME,
- .fops = &solo_enc_fops,
- .ioctl_ops = &solo_enc_ioctl_ops,
- .minor = -1,
- .release = video_device_release,
-
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch)
-{
- struct solo_enc_dev *solo_enc;
- int ret;
-
- solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
- if (!solo_enc)
- return ERR_PTR(-ENOMEM);
-
- solo_enc->vfd = video_device_alloc();
- if (!solo_enc->vfd) {
- kfree(solo_enc);
- return ERR_PTR(-ENOMEM);
- }
-
- solo_enc->solo_dev = solo_dev;
- solo_enc->ch = ch;
-
- *solo_enc->vfd = solo_enc_template;
- solo_enc->vfd->parent = &solo_dev->pdev->dev;
- ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER,
- video_nr);
- if (ret < 0) {
- video_device_release(solo_enc->vfd);
- kfree(solo_enc);
- return ERR_PTR(ret);
- }
-
- video_set_drvdata(solo_enc->vfd, solo_enc);
-
- snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name),
- "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num,
- solo_enc->vfd->num);
-
- if (video_nr != -1)
- video_nr++;
-
- spin_lock_init(&solo_enc->lock);
- init_waitqueue_head(&solo_enc->thread_wait);
- atomic_set(&solo_enc->readers, 0);
-
- solo_enc->qp = SOLO_DEFAULT_QP;
- solo_enc->gop = solo_dev->fps;
- solo_enc->interval = 1;
- solo_enc->mode = SOLO_ENC_MODE_CIF;
- solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
-
- spin_lock(&solo_enc->lock);
- solo_update_mode(solo_enc);
- spin_unlock(&solo_enc->lock);
-
- return solo_enc;
-}
-
-static void solo_enc_free(struct solo_enc_dev *solo_enc)
-{
- if (solo_enc == NULL)
- return;
-
- video_unregister_device(solo_enc->vfd);
- kfree(solo_enc);
-}
-
-int solo_enc_v4l2_init(struct solo_dev *solo_dev)
-{
- int i;
-
- for (i = 0; i < solo_dev->nr_chans; i++) {
- solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i);
- if (IS_ERR(solo_dev->v4l2_enc[i]))
- break;
- }
-
- if (i != solo_dev->nr_chans) {
- int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
- while (i--)
- solo_enc_free(solo_dev->v4l2_enc[i]);
- return ret;
- }
-
- /* D1@MAX-FPS * 4 */
- solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4;
-
- dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n",
- solo_dev->v4l2_enc[0]->vfd->num,
- solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
-
- return 0;
-}
-
-void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
-{
- int i;
-
- solo_irq_off(solo_dev, SOLO_IRQ_MOTION);
-
- for (i = 0; i < solo_dev->nr_chans; i++)
- solo_enc_free(solo_dev->v4l2_enc[i]);
-}
diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c
deleted file mode 100644
index ca774cc57539..000000000000
--- a/drivers/staging/media/solo6x10/v4l2.c
+++ /dev/null
@@ -1,961 +0,0 @@
-/*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <media/videobuf-dma-sg.h>
-#include "solo6x10.h"
-#include "tw28.h"
-
-#define SOLO_HW_BPL 2048
-#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
-
-/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
-#define solo_vlines(__solo) (__solo->video_vsize * 2)
-#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
- solo_vlines(__solo))
-#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
-
-#define MIN_VID_BUFFERS 4
-
-/* Simple file handle */
-struct solo_filehandle {
- struct solo_dev *solo_dev;
- struct videobuf_queue vidq;
- struct task_struct *kthread;
- spinlock_t slock;
- int old_write;
- struct list_head vidq_active;
- struct p2m_desc desc[SOLO_NR_P2M_DESC];
- int desc_idx;
-};
-
-unsigned video_nr = -1;
-module_param(video_nr, uint, 0644);
-MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
-
-static void erase_on(struct solo_dev *solo_dev)
-{
- solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
- solo_dev->erasing = 1;
- solo_dev->frame_blank = 0;
-}
-
-static int erase_off(struct solo_dev *solo_dev)
-{
- if (!solo_dev->erasing)
- return 0;
-
- /* First time around, assert erase off */
- if (!solo_dev->frame_blank)
- solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
- /* Keep the erasing flag on for 8 frames minimum */
- if (solo_dev->frame_blank++ >= 8)
- solo_dev->erasing = 0;
-
- return 1;
-}
-
-void solo_video_in_isr(struct solo_dev *solo_dev)
-{
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
- wake_up_interruptible(&solo_dev->disp_thread_wait);
-}
-
-static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
- int sx, int sy, int ex, int ey, int scale)
-{
- if (ch >= solo_dev->nr_chans)
- return;
-
- /* Here, we just keep window/channel the same */
- solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
- SOLO_VI_WIN_CHANNEL(ch) |
- SOLO_VI_WIN_SX(sx) |
- SOLO_VI_WIN_EX(ex) |
- SOLO_VI_WIN_SCALE(scale));
-
- solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
- SOLO_VI_WIN_SY(sy) |
- SOLO_VI_WIN_EY(ey));
-}
-
-static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
-{
- u8 ch = idx * 4;
-
- if (ch >= solo_dev->nr_chans)
- return -EINVAL;
-
- if (!on) {
- u8 i;
- for (i = ch; i < ch + 4; i++)
- solo_win_setup(solo_dev, i, solo_dev->video_hsize,
- solo_vlines(solo_dev),
- solo_dev->video_hsize,
- solo_vlines(solo_dev), 0);
- return 0;
- }
-
- /* Row 1 */
- solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
- solo_vlines(solo_dev) / 2, 3);
- solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
- solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
- /* Row 2 */
- solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
- solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
- solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
- solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
- solo_vlines(solo_dev), 3);
-
- return 0;
-}
-
-static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
-{
- int sy, ysize, hsize, i;
-
- if (!on) {
- for (i = 0; i < 16; i++)
- solo_win_setup(solo_dev, i, solo_dev->video_hsize,
- solo_vlines(solo_dev),
- solo_dev->video_hsize,
- solo_vlines(solo_dev), 0);
- return 0;
- }
-
- ysize = solo_vlines(solo_dev) / 4;
- hsize = solo_dev->video_hsize / 4;
-
- for (sy = 0, i = 0; i < 4; i++, sy += ysize) {
- solo_win_setup(solo_dev, i * 4, 0, sy, hsize,
- sy + ysize, 5);
- solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy,
- hsize * 2, sy + ysize, 5);
- solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy,
- hsize * 3, sy + ysize, 5);
- solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy,
- solo_dev->video_hsize, sy + ysize, 5);
- }
-
- return 0;
-}
-
-static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on)
-{
- u8 ext_ch;
-
- if (ch < solo_dev->nr_chans) {
- solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize,
- on ? 0 : solo_vlines(solo_dev),
- solo_dev->video_hsize, solo_vlines(solo_dev),
- on ? 1 : 0);
- return 0;
- }
-
- if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
- return -EINVAL;
-
- ext_ch = ch - solo_dev->nr_chans;
-
- /* 4up's first */
- if (ext_ch < 4)
- return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on);
-
- /* Remaining case is 16up for 16-port */
- return solo_v4l2_ch_ext_16up(solo_dev, on);
-}
-
-static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch)
-{
- if (ch >= solo_dev->nr_chans + solo_dev->nr_ext)
- return -EINVAL;
-
- erase_on(solo_dev);
-
- solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0);
- solo_v4l2_ch(solo_dev, ch, 1);
-
- solo_dev->cur_disp_ch = ch;
-
- return 0;
-}
-
-static void disp_reset_desc(struct solo_filehandle *fh)
-{
- /* We use desc mode, which ignores desc 0 */
- memset(fh->desc, 0, sizeof(*fh->desc));
- fh->desc_idx = 1;
-}
-
-static int disp_flush_descs(struct solo_filehandle *fh)
-{
- int ret;
-
- if (!fh->desc_idx)
- return 0;
-
- ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP,
- fh->desc, fh->desc_idx);
- disp_reset_desc(fh);
-
- return ret;
-}
-
-static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr,
- u32 ext_addr, int size, int repeat, int ext_size)
-{
- if (fh->desc_idx >= SOLO_NR_P2M_DESC) {
- int ret = disp_flush_descs(fh);
- if (ret)
- return ret;
- }
-
- solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr,
- size, repeat, ext_size);
- fh->desc_idx++;
-
- return 0;
-}
-
-static void solo_fillbuf(struct solo_filehandle *fh,
- struct videobuf_buffer *vb)
-{
- struct solo_dev *solo_dev = fh->solo_dev;
- struct videobuf_dmabuf *vbuf;
- unsigned int fdma_addr;
- int error = 1;
- int i;
- struct scatterlist *sg;
- dma_addr_t sg_dma;
- int sg_size_left;
-
- vbuf = videobuf_to_dma(vb);
- if (!vbuf)
- goto finish_buf;
-
- if (erase_off(solo_dev)) {
- int i;
-
- /* Just blit to the entire sg list, ignoring size */
- for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) {
- void *p = sg_virt(sg);
- size_t len = sg_dma_len(sg);
-
- for (i = 0; i < len; i += 2) {
- ((u8 *)p)[i] = 0x80;
- ((u8 *)p)[i + 1] = 0x00;
- }
- }
-
- error = 0;
- goto finish_buf;
- }
-
- disp_reset_desc(fh);
- sg = vbuf->sglist;
- sg_dma = sg_dma_address(sg);
- sg_size_left = sg_dma_len(sg);
-
- fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write *
- (SOLO_HW_BPL * solo_vlines(solo_dev)));
-
- for (i = 0; i < solo_vlines(solo_dev); i++) {
- int line_len = solo_bytesperline(solo_dev);
- int lines;
-
- if (!sg_size_left) {
- sg = sg_next(sg);
- if (sg == NULL)
- goto finish_buf;
- sg_dma = sg_dma_address(sg);
- sg_size_left = sg_dma_len(sg);
- }
-
- /* No room for an entire line, so chunk it up */
- if (sg_size_left < line_len) {
- int this_addr = fdma_addr;
-
- while (line_len > 0) {
- int this_write;
-
- if (!sg_size_left) {
- sg = sg_next(sg);
- if (sg == NULL)
- goto finish_buf;
- sg_dma = sg_dma_address(sg);
- sg_size_left = sg_dma_len(sg);
- }
-
- this_write = min(sg_size_left, line_len);
-
- if (disp_push_desc(fh, sg_dma, this_addr,
- this_write, 0, 0))
- goto finish_buf;
-
- line_len -= this_write;
- sg_size_left -= this_write;
- sg_dma += this_write;
- this_addr += this_write;
- }
-
- fdma_addr += SOLO_HW_BPL;
- continue;
- }
-
- /* Shove as many lines into a repeating descriptor as possible */
- lines = min(sg_size_left / line_len,
- solo_vlines(solo_dev) - i);
-
- if (disp_push_desc(fh, sg_dma, fdma_addr, line_len,
- lines - 1, SOLO_HW_BPL))
- goto finish_buf;
-
- i += lines - 1;
- fdma_addr += SOLO_HW_BPL * lines;
- sg_dma += lines * line_len;
- sg_size_left -= lines * line_len;
- }
-
- error = disp_flush_descs(fh);
-
-finish_buf:
- if (error) {
- vb->state = VIDEOBUF_ERROR;
- } else {
- vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev);
- vb->state = VIDEOBUF_DONE;
- vb->field_count++;
- do_gettimeofday(&vb->ts);
- }
-
- wake_up(&vb->done);
-
- return;
-}
-
-static void solo_thread_try(struct solo_filehandle *fh)
-{
- struct videobuf_buffer *vb;
- unsigned int cur_write;
-
- for (;;) {
- spin_lock(&fh->slock);
-
- if (list_empty(&fh->vidq_active))
- break;
-
- vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer,
- queue);
-
- if (!waitqueue_active(&vb->done))
- break;
-
- cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev,
- SOLO_VI_STATUS0));
- if (cur_write == fh->old_write)
- break;
-
- fh->old_write = cur_write;
- list_del(&vb->queue);
-
- spin_unlock(&fh->slock);
-
- solo_fillbuf(fh, vb);
- }
-
- assert_spin_locked(&fh->slock);
- spin_unlock(&fh->slock);
-}
-
-static int solo_thread(void *data)
-{
- struct solo_filehandle *fh = data;
- struct solo_dev *solo_dev = fh->solo_dev;
- DECLARE_WAITQUEUE(wait, current);
-
- set_freezable();
- add_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
- for (;;) {
- long timeout = schedule_timeout_interruptible(HZ);
- if (timeout == -ERESTARTSYS || kthread_should_stop())
- break;
- solo_thread_try(fh);
- try_to_freeze();
- }
-
- remove_wait_queue(&solo_dev->disp_thread_wait, &wait);
-
- return 0;
-}
-
-static int solo_start_thread(struct solo_filehandle *fh)
-{
- fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp");
-
- return PTR_RET(fh->kthread);
-}
-
-static void solo_stop_thread(struct solo_filehandle *fh)
-{
- if (fh->kthread) {
- kthread_stop(fh->kthread);
- fh->kthread = NULL;
- }
-}
-
-static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct solo_filehandle *fh = vq->priv_data;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- *size = solo_image_size(solo_dev);
-
- if (*count < MIN_VID_BUFFERS)
- *count = MIN_VID_BUFFERS;
-
- return 0;
-}
-
-static int solo_buf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct solo_filehandle *fh = vq->priv_data;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- vb->size = solo_image_size(solo_dev);
- if (vb->baddr != 0 && vb->bsize < vb->size)
- return -EINVAL;
-
- /* XXX: These properties only change when queue is idle */
- vb->width = solo_dev->video_hsize;
- vb->height = solo_vlines(solo_dev);
- vb->bytesperline = solo_bytesperline(solo_dev);
- vb->field = field;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- int rc = videobuf_iolock(vq, vb, NULL);
- if (rc < 0) {
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- videobuf_dma_unmap(vq->dev, dma);
- videobuf_dma_free(dma);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return rc;
- }
- }
- vb->state = VIDEOBUF_PREPARED;
-
- return 0;
-}
-
-static void solo_buf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct solo_filehandle *fh = vq->priv_data;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &fh->vidq_active);
- wake_up_interruptible(&solo_dev->disp_thread_wait);
-}
-
-static void solo_buf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- videobuf_dma_unmap(vq->dev, dma);
- videobuf_dma_free(dma);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops solo_video_qops = {
- .buf_setup = solo_buf_setup,
- .buf_prepare = solo_buf_prepare,
- .buf_queue = solo_buf_queue,
- .buf_release = solo_buf_release,
-};
-
-static unsigned int solo_v4l2_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct solo_filehandle *fh = file->private_data;
-
- return videobuf_poll_stream(file, &fh->vidq, wait);
-}
-
-static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct solo_filehandle *fh = file->private_data;
-
- return videobuf_mmap_mapper(&fh->vidq, vma);
-}
-
-static int solo_v4l2_open(struct file *file)
-{
- struct solo_dev *solo_dev = video_drvdata(file);
- struct solo_filehandle *fh;
- int ret;
-
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (fh == NULL)
- return -ENOMEM;
-
- spin_lock_init(&fh->slock);
- INIT_LIST_HEAD(&fh->vidq_active);
- fh->solo_dev = solo_dev;
- file->private_data = fh;
-
- ret = solo_start_thread(fh);
- if (ret) {
- kfree(fh);
- return ret;
- }
-
- videobuf_queue_sg_init(&fh->vidq, &solo_video_qops,
- &solo_dev->pdev->dev, &fh->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- SOLO_DISP_PIX_FIELD,
- sizeof(struct videobuf_buffer), fh, NULL);
-
- return 0;
-}
-
-static ssize_t solo_v4l2_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct solo_filehandle *fh = file->private_data;
-
- return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static int solo_v4l2_release(struct file *file)
-{
- struct solo_filehandle *fh = file->private_data;
-
- videobuf_stop(&fh->vidq);
- videobuf_mmap_free(&fh->vidq);
- solo_stop_thread(fh);
- kfree(fh);
-
- return 0;
-}
-
-static int solo_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- strcpy(cap->driver, SOLO6X10_NAME);
- strcpy(cap->card, "Softlogic 6x10");
- snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s",
- pci_name(solo_dev->pdev));
- cap->version = SOLO6X10_VER_NUM;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- return 0;
-}
-
-static int solo_enum_ext_input(struct solo_dev *solo_dev,
- struct v4l2_input *input)
-{
- static const char *dispnames_1[] = { "4UP" };
- static const char *dispnames_2[] = { "4UP-1", "4UP-2" };
- static const char *dispnames_5[] = {
- "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP"
- };
- const char **dispnames;
-
- if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext))
- return -EINVAL;
-
- if (solo_dev->nr_ext == 5)
- dispnames = dispnames_5;
- else if (solo_dev->nr_ext == 2)
- dispnames = dispnames_2;
- else
- dispnames = dispnames_1;
-
- snprintf(input->name, sizeof(input->name), "Multi %s",
- dispnames[input->index - solo_dev->nr_chans]);
-
- return 0;
-}
-
-static int solo_enum_input(struct file *file, void *priv,
- struct v4l2_input *input)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- if (input->index >= solo_dev->nr_chans) {
- int ret = solo_enum_ext_input(solo_dev, input);
- if (ret < 0)
- return ret;
- } else {
- snprintf(input->name, sizeof(input->name), "Camera %d",
- input->index + 1);
-
- /* We can only check this for normal inputs */
- if (!tw28_get_video_status(solo_dev, input->index))
- input->status = V4L2_IN_ST_NO_SIGNAL;
- }
-
- input->type = V4L2_INPUT_TYPE_CAMERA;
-
- if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC)
- input->std = V4L2_STD_NTSC_M;
- else
- input->std = V4L2_STD_PAL_B;
-
- return 0;
-}
-
-static int solo_set_input(struct file *file, void *priv, unsigned int index)
-{
- struct solo_filehandle *fh = priv;
-
- return solo_v4l2_set_ch(fh->solo_dev, index);
-}
-
-static int solo_get_input(struct file *file, void *priv, unsigned int *index)
-{
- struct solo_filehandle *fh = priv;
-
- *index = fh->solo_dev->cur_disp_ch;
-
- return 0;
-}
-
-static int solo_enum_fmt_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- if (f->index)
- return -EINVAL;
-
- f->pixelformat = V4L2_PIX_FMT_UYVY;
- strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description));
-
- return 0;
-}
-
-static int solo_try_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int image_size = solo_image_size(solo_dev);
-
- /* Check supported sizes */
- if (pix->width != solo_dev->video_hsize)
- pix->width = solo_dev->video_hsize;
- if (pix->height != solo_vlines(solo_dev))
- pix->height = solo_vlines(solo_dev);
- if (pix->sizeimage != image_size)
- pix->sizeimage = image_size;
-
- /* Check formats */
- if (pix->field == V4L2_FIELD_ANY)
- pix->field = SOLO_DISP_PIX_FIELD;
-
- if (pix->pixelformat != V4L2_PIX_FMT_UYVY ||
- pix->field != SOLO_DISP_PIX_FIELD ||
- pix->colorspace != V4L2_COLORSPACE_SMPTE170M)
- return -EINVAL;
-
- return 0;
-}
-
-static int solo_set_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_filehandle *fh = priv;
-
- if (videobuf_queue_is_busy(&fh->vidq))
- return -EBUSY;
-
- /* For right now, if it doesn't match our running config,
- * then fail */
- return solo_try_fmt_cap(file, priv, f);
-}
-
-static int solo_get_fmt_cap(struct file *file, void *priv,
- struct v4l2_format *f)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- pix->width = solo_dev->video_hsize;
- pix->height = solo_vlines(solo_dev);
- pix->pixelformat = V4L2_PIX_FMT_UYVY;
- pix->field = SOLO_DISP_PIX_FIELD;
- pix->sizeimage = solo_image_size(solo_dev);
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
- pix->bytesperline = solo_bytesperline(solo_dev);
-
- return 0;
-}
-
-static int solo_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req)
-{
- struct solo_filehandle *fh = priv;
-
- return videobuf_reqbufs(&fh->vidq, req);
-}
-
-static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_filehandle *fh = priv;
-
- return videobuf_querybuf(&fh->vidq, buf);
-}
-
-static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_filehandle *fh = priv;
-
- return videobuf_qbuf(&fh->vidq, buf);
-}
-
-static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct solo_filehandle *fh = priv;
-
- return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK);
-}
-
-static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct solo_filehandle *fh = priv;
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return videobuf_streamon(&fh->vidq);
-}
-
-static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct solo_filehandle *fh = priv;
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- return videobuf_streamoff(&fh->vidq);
-}
-
-static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i)
-{
- return 0;
-}
-
-static const u32 solo_motion_ctrls[] = {
- V4L2_CID_MOTION_TRACE,
- 0
-};
-
-static const u32 *solo_ctrl_classes[] = {
- solo_motion_ctrls,
- NULL
-};
-
-static int solo_disp_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id);
- if (!qc->id)
- return -EINVAL;
-
- switch (qc->id) {
-#ifdef PRIVATE_CIDS
- case V4L2_CID_MOTION_TRACE:
- qc->type = V4L2_CTRL_TYPE_BOOLEAN;
- qc->minimum = 0;
- qc->maximum = qc->step = 1;
- qc->default_value = 0;
- strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name));
- return 0;
-#else
- case V4L2_CID_MOTION_TRACE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-#endif
- }
- return -EINVAL;
-}
-
-static int solo_disp_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- switch (ctrl->id) {
- case V4L2_CID_MOTION_TRACE:
- ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR)
- ? 1 : 0;
- return 0;
- }
- return -EINVAL;
-}
-
-static int solo_disp_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct solo_filehandle *fh = priv;
- struct solo_dev *solo_dev = fh->solo_dev;
-
- switch (ctrl->id) {
- case V4L2_CID_MOTION_TRACE:
- if (ctrl->value) {
- solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER,
- SOLO_VI_MOTION_Y_ADD |
- SOLO_VI_MOTION_Y_VALUE(0x20) |
- SOLO_VI_MOTION_CB_VALUE(0x10) |
- SOLO_VI_MOTION_CR_VALUE(0x10));
- solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR,
- SOLO_VI_MOTION_CR_ADD |
- SOLO_VI_MOTION_Y_VALUE(0x10) |
- SOLO_VI_MOTION_CB_VALUE(0x80) |
- SOLO_VI_MOTION_CR_VALUE(0x10));
- } else {
- solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0);
- solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0);
- }
- return 0;
- }
- return -EINVAL;
-}
-
-static const struct v4l2_file_operations solo_v4l2_fops = {
- .owner = THIS_MODULE,
- .open = solo_v4l2_open,
- .release = solo_v4l2_release,
- .read = solo_v4l2_read,
- .poll = solo_v4l2_poll,
- .mmap = solo_v4l2_mmap,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = {
- .vidioc_querycap = solo_querycap,
- .vidioc_s_std = solo_s_std,
- /* Input callbacks */
- .vidioc_enum_input = solo_enum_input,
- .vidioc_s_input = solo_set_input,
- .vidioc_g_input = solo_get_input,
- /* Video capture format callbacks */
- .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap,
- .vidioc_try_fmt_vid_cap = solo_try_fmt_cap,
- .vidioc_s_fmt_vid_cap = solo_set_fmt_cap,
- .vidioc_g_fmt_vid_cap = solo_get_fmt_cap,
- /* Streaming I/O */
- .vidioc_reqbufs = solo_reqbufs,
- .vidioc_querybuf = solo_querybuf,
- .vidioc_qbuf = solo_qbuf,
- .vidioc_dqbuf = solo_dqbuf,
- .vidioc_streamon = solo_streamon,
- .vidioc_streamoff = solo_streamoff,
- /* Controls */
- .vidioc_queryctrl = solo_disp_queryctrl,
- .vidioc_g_ctrl = solo_disp_g_ctrl,
- .vidioc_s_ctrl = solo_disp_s_ctrl,
-};
-
-static struct video_device solo_v4l2_template = {
- .name = SOLO6X10_NAME,
- .fops = &solo_v4l2_fops,
- .ioctl_ops = &solo_v4l2_ioctl_ops,
- .minor = -1,
- .release = video_device_release,
-
- .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B,
- .current_norm = V4L2_STD_NTSC_M,
-};
-
-int solo_v4l2_init(struct solo_dev *solo_dev)
-{
- int ret;
- int i;
-
- init_waitqueue_head(&solo_dev->disp_thread_wait);
-
- solo_dev->vfd = video_device_alloc();
- if (!solo_dev->vfd)
- return -ENOMEM;
-
- *solo_dev->vfd = solo_v4l2_template;
- solo_dev->vfd->parent = &solo_dev->pdev->dev;
-
- ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr);
- if (ret < 0) {
- video_device_release(solo_dev->vfd);
- solo_dev->vfd = NULL;
- return ret;
- }
-
- video_set_drvdata(solo_dev->vfd, solo_dev);
-
- snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)",
- SOLO6X10_NAME, solo_dev->vfd->num);
-
- if (video_nr != -1)
- video_nr++;
-
- dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with "
- "%d inputs (%d extended)\n", solo_dev->vfd->num,
- solo_dev->nr_chans, solo_dev->nr_ext);
-
- /* Cycle all the channels and clear */
- for (i = 0; i < solo_dev->nr_chans; i++) {
- solo_v4l2_set_ch(solo_dev, i);
- while (erase_off(solo_dev))
- ;/* Do nothing */
- }
-
- /* Set the default display channel */
- solo_v4l2_set_ch(solo_dev, 0);
- while (erase_off(solo_dev))
- ;/* Do nothing */
-
- solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN);
-
- return 0;
-}
-
-void solo_v4l2_exit(struct solo_dev *solo_dev)
-{
- solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN);
- if (solo_dev->vfd) {
- video_unregister_device(solo_dev->vfd);
- solo_dev->vfd = NULL;
- }
-}
diff --git a/drivers/staging/net/Kconfig b/drivers/staging/net/Kconfig
deleted file mode 100644
index a64e56b1898a..000000000000
--- a/drivers/staging/net/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-if NETDEVICES
-
-if WAN
-
-config PC300
- tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
- depends on HDLC && PCI && BROKEN
- ---help---
- This driver is broken because of struct tty_driver change.
-
- Driver for the Cyclades-PC300 synchronous communication boards.
-
- These boards provide synchronous serial interfaces to your
- Linux box (interfaces currently available are RS-232/V.35, X.21 and
- T1/E1). If you wish to support Multilink PPP, please select the
- option later and read the file README.mlppp provided by PC300
- package.
-
- To compile this as a module, choose M here: the module
- will be called pc300.
-
- If unsure, say N.
-
-config PC300_MLPPP
- bool "Cyclades-PC300 MLPPP support"
- depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
- help
- Multilink PPP over the PC300 synchronous communication boards.
-
-comment "Cyclades-PC300 MLPPP support is disabled."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
-comment "Refer to the file README.mlppp, provided by PC300 package."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
-endif # WAN
-
-endif # NETDEVICES
diff --git a/drivers/staging/net/Makefile b/drivers/staging/net/Makefile
deleted file mode 100644
index 0799c43d5114..000000000000
--- a/drivers/staging/net/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-pc300-y := pc300_drv.o
-pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
-pc300-objs := $(pc300-y)
-
-obj-$(CONFIG_PC300) += pc300.o
diff --git a/drivers/staging/net/TODO b/drivers/staging/net/TODO
deleted file mode 100644
index e3446f2ad7c7..000000000000
--- a/drivers/staging/net/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-PC300
-The driver is very broken and cannot work with the current TTY layer. It is
-inevitable to convert it to the new TTY API.
-
-If no one steps in to adopt the driver, it will be removed in the 3.7 release.
diff --git a/drivers/staging/net/pc300-falc-lh.h b/drivers/staging/net/pc300-falc-lh.h
deleted file mode 100644
index 01ed23ca76c7..000000000000
--- a/drivers/staging/net/pc300-falc-lh.h
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*
- * falc.h Description of the Siemens FALC T1/E1 framer.
- *
- * Author: Ivan Passos <ivan@cyclades.com>
- *
- * Copyright: (c) 2000-2001 Cyclades Corp.
- *
- * 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.
- *
- * $Log: falc-lh.h,v $
- * Revision 3.1 2001/06/15 12:41:10 regina
- * upping major version number
- *
- * Revision 1.1.1.1 2001/06/13 20:24:47 daniela
- * PC300 initial CVS version (3.4.0-pre1)
- *
- * Revision 1.1 2000/05/15 ivan
- * Included DJA bits for the LIM2 register.
- *
- * Revision 1.0 2000/02/22 ivan
- * Initial version.
- *
- */
-
-#ifndef _FALC_LH_H
-#define _FALC_LH_H
-
-#define NUM_OF_T1_CHANNELS 24
-#define NUM_OF_E1_CHANNELS 32
-
-/*>>>>>>>>>>>>>>>>> FALC Register Bits (Transmit Mode) <<<<<<<<<<<<<<<<<<< */
-
-/* CMDR (Command Register)
- ---------------- E1 & T1 ------------------------------ */
-#define CMDR_RMC 0x80
-#define CMDR_RRES 0x40
-#define CMDR_XREP 0x20
-#define CMDR_XRES 0x10
-#define CMDR_XHF 0x08
-#define CMDR_XTF 0x04
-#define CMDR_XME 0x02
-#define CMDR_SRES 0x01
-
-/* MODE (Mode Register)
- ----------------- E1 & T1 ----------------------------- */
-#define MODE_MDS2 0x80
-#define MODE_MDS1 0x40
-#define MODE_MDS0 0x20
-#define MODE_BRAC 0x10
-#define MODE_HRAC 0x08
-
-/* IPC (Interrupt Port Configuration)
- ----------------- E1 & T1 ----------------------------- */
-#define IPC_VIS 0x80
-#define IPC_SCI 0x04
-#define IPC_IC1 0x02
-#define IPC_IC0 0x01
-
-/* CCR1 (Common Configuration Register 1)
- ----------------- E1 & T1 ----------------------------- */
-#define CCR1_SFLG 0x80
-#define CCR1_XTS16RA 0x40
-#define CCR1_BRM 0x40
-#define CCR1_CASSYM 0x20
-#define CCR1_EDLX 0x20
-#define CCR1_EITS 0x10
-#define CCR1_ITF 0x08
-#define CCR1_RFT1 0x02
-#define CCR1_RFT0 0x01
-
-/* CCR3 (Common Configuration Register 3)
- ---------------- E1 & T1 ------------------------------ */
-
-#define CCR3_PRE1 0x80
-#define CCR3_PRE0 0x40
-#define CCR3_EPT 0x20
-#define CCR3_RADD 0x10
-#define CCR3_RCRC 0x04
-#define CCR3_XCRC 0x02
-
-
-/* RTR1-4 (Receive Timeslot Register 1-4)
- ---------------- E1 & T1 ------------------------------ */
-
-#define RTR1_TS0 0x80
-#define RTR1_TS1 0x40
-#define RTR1_TS2 0x20
-#define RTR1_TS3 0x10
-#define RTR1_TS4 0x08
-#define RTR1_TS5 0x04
-#define RTR1_TS6 0x02
-#define RTR1_TS7 0x01
-
-#define RTR2_TS8 0x80
-#define RTR2_TS9 0x40
-#define RTR2_TS10 0x20
-#define RTR2_TS11 0x10
-#define RTR2_TS12 0x08
-#define RTR2_TS13 0x04
-#define RTR2_TS14 0x02
-#define RTR2_TS15 0x01
-
-#define RTR3_TS16 0x80
-#define RTR3_TS17 0x40
-#define RTR3_TS18 0x20
-#define RTR3_TS19 0x10
-#define RTR3_TS20 0x08
-#define RTR3_TS21 0x04
-#define RTR3_TS22 0x02
-#define RTR3_TS23 0x01
-
-#define RTR4_TS24 0x80
-#define RTR4_TS25 0x40
-#define RTR4_TS26 0x20
-#define RTR4_TS27 0x10
-#define RTR4_TS28 0x08
-#define RTR4_TS29 0x04
-#define RTR4_TS30 0x02
-#define RTR4_TS31 0x01
-
-
-/* TTR1-4 (Transmit Timeslot Register 1-4)
- ---------------- E1 & T1 ------------------------------ */
-
-#define TTR1_TS0 0x80
-#define TTR1_TS1 0x40
-#define TTR1_TS2 0x20
-#define TTR1_TS3 0x10
-#define TTR1_TS4 0x08
-#define TTR1_TS5 0x04
-#define TTR1_TS6 0x02
-#define TTR1_TS7 0x01
-
-#define TTR2_TS8 0x80
-#define TTR2_TS9 0x40
-#define TTR2_TS10 0x20
-#define TTR2_TS11 0x10
-#define TTR2_TS12 0x08
-#define TTR2_TS13 0x04
-#define TTR2_TS14 0x02
-#define TTR2_TS15 0x01
-
-#define TTR3_TS16 0x80
-#define TTR3_TS17 0x40
-#define TTR3_TS18 0x20
-#define TTR3_TS19 0x10
-#define TTR3_TS20 0x08
-#define TTR3_TS21 0x04
-#define TTR3_TS22 0x02
-#define TTR3_TS23 0x01
-
-#define TTR4_TS24 0x80
-#define TTR4_TS25 0x40
-#define TTR4_TS26 0x20
-#define TTR4_TS27 0x10
-#define TTR4_TS28 0x08
-#define TTR4_TS29 0x04
-#define TTR4_TS30 0x02
-#define TTR4_TS31 0x01
-
-
-
-/* IMR0-4 (Interrupt Mask Register 0-4)
-
- ----------------- E1 & T1 ----------------------------- */
-
-#define IMR0_RME 0x80
-#define IMR0_RFS 0x40
-#define IMR0_T8MS 0x20
-#define IMR0_ISF 0x20
-#define IMR0_RMB 0x10
-#define IMR0_CASC 0x08
-#define IMR0_RSC 0x08
-#define IMR0_CRC6 0x04
-#define IMR0_CRC4 0x04
-#define IMR0_PDEN 0x02
-#define IMR0_RPF 0x01
-
-#define IMR1_CASE 0x80
-#define IMR1_RDO 0x40
-#define IMR1_ALLS 0x20
-#define IMR1_XDU 0x10
-#define IMR1_XMB 0x08
-#define IMR1_XLSC 0x02
-#define IMR1_XPR 0x01
-#define IMR1_LLBSC 0x80
-
-#define IMR2_FAR 0x80
-#define IMR2_LFA 0x40
-#define IMR2_MFAR 0x20
-#define IMR2_T400MS 0x10
-#define IMR2_LMFA 0x10
-#define IMR2_AIS 0x08
-#define IMR2_LOS 0x04
-#define IMR2_RAR 0x02
-#define IMR2_RA 0x01
-
-#define IMR3_ES 0x80
-#define IMR3_SEC 0x40
-#define IMR3_LMFA16 0x20
-#define IMR3_AIS16 0x10
-#define IMR3_RA16 0x08
-#define IMR3_API 0x04
-#define IMR3_XSLP 0x20
-#define IMR3_XSLN 0x10
-#define IMR3_LLBSC 0x08
-#define IMR3_XRS 0x04
-#define IMR3_SLN 0x02
-#define IMR3_SLP 0x01
-
-#define IMR4_LFA 0x80
-#define IMR4_FER 0x40
-#define IMR4_CER 0x20
-#define IMR4_AIS 0x10
-#define IMR4_LOS 0x08
-#define IMR4_CVE 0x04
-#define IMR4_SLIP 0x02
-#define IMR4_EBE 0x01
-
-/* FMR0-5 for E1 and T1 (Framer Mode Register ) */
-
-#define FMR0_XC1 0x80
-#define FMR0_XC0 0x40
-#define FMR0_RC1 0x20
-#define FMR0_RC0 0x10
-#define FMR0_EXTD 0x08
-#define FMR0_ALM 0x04
-#define E1_FMR0_FRS 0x02
-#define T1_FMR0_FRS 0x08
-#define FMR0_SRAF 0x04
-#define FMR0_EXLS 0x02
-#define FMR0_SIM 0x01
-
-#define FMR1_MFCS 0x80
-#define FMR1_AFR 0x40
-#define FMR1_ENSA 0x20
-#define FMR1_CTM 0x80
-#define FMR1_SIGM 0x40
-#define FMR1_EDL 0x20
-#define FMR1_PMOD 0x10
-#define FMR1_XFS 0x08
-#define FMR1_CRC 0x08
-#define FMR1_ECM 0x04
-#define FMR1_IMOD 0x02
-#define FMR1_XAIS 0x01
-
-#define FMR2_RFS1 0x80
-#define FMR2_RFS0 0x40
-#define FMR2_MCSP 0x40
-#define FMR2_RTM 0x20
-#define FMR2_SSP 0x20
-#define FMR2_DAIS 0x10
-#define FMR2_SAIS 0x08
-#define FMR2_PLB 0x04
-#define FMR2_AXRA 0x02
-#define FMR2_ALMF 0x01
-#define FMR2_EXZE 0x01
-
-#define LOOP_RTM 0x40
-#define LOOP_SFM 0x40
-#define LOOP_ECLB 0x20
-#define LOOP_CLA 0x1f
-
-/*--------------------- E1 ----------------------------*/
-#define FMR3_XLD 0x20
-#define FMR3_XLU 0x10
-
-/*--------------------- T1 ----------------------------*/
-#define FMR4_AIS3 0x80
-#define FMR4_TM 0x40
-#define FMR4_XRA 0x20
-#define FMR4_SSC1 0x10
-#define FMR4_SSC0 0x08
-#define FMR4_AUTO 0x04
-#define FMR4_FM1 0x02
-#define FMR4_FM0 0x01
-
-#define FMR5_SRS 0x80
-#define FMR5_EIBR 0x40
-#define FMR5_XLD 0x20
-#define FMR5_XLU 0x10
-
-
-/* LOOP (Channel Loop Back)
-
- ------------------ E1 & T1 ---------------------------- */
-
-#define LOOP_SFM 0x40
-#define LOOP_ECLB 0x20
-#define LOOP_CLA4 0x10
-#define LOOP_CLA3 0x08
-#define LOOP_CLA2 0x04
-#define LOOP_CLA1 0x02
-#define LOOP_CLA0 0x01
-
-
-
-/* XSW (Transmit Service Word Pulseframe)
-
- ------------------- E1 --------------------------- */
-
-#define XSW_XSIS 0x80
-#define XSW_XTM 0x40
-#define XSW_XRA 0x20
-#define XSW_XY0 0x10
-#define XSW_XY1 0x08
-#define XSW_XY2 0x04
-#define XSW_XY3 0x02
-#define XSW_XY4 0x01
-
-
-/* XSP (Transmit Spare Bits)
-
- ------------------- E1 --------------------------- */
-
-#define XSP_XAP 0x80
-#define XSP_CASEN 0x40
-#define XSP_TT0 0x20
-#define XSP_EBP 0x10
-#define XSP_AXS 0x08
-#define XSP_XSIF 0x04
-#define XSP_XS13 0x02
-#define XSP_XS15 0x01
-
-
-/* XC0/1 (Transmit Control 0/1)
- ------------------ E1 & T1 ---------------------------- */
-
-#define XC0_SA8E 0x80
-#define XC0_SA7E 0x40
-#define XC0_SA6E 0x20
-#define XC0_SA5E 0x10
-#define XC0_SA4E 0x08
-#define XC0_BRM 0x80
-#define XC0_MFBS 0x40
-#define XC0_SFRZ 0x10
-#define XC0_XCO2 0x04
-#define XC0_XCO1 0x02
-#define XC0_XCO0 0x01
-
-#define XC1_XTO5 0x20
-#define XC1_XTO4 0x10
-#define XC1_XTO3 0x08
-#define XC1_XTO2 0x04
-#define XC1_XTO1 0x02
-#define XC1_XTO0 0x01
-
-
-/* RC0/1 (Receive Control 0/1)
- ------------------ E1 & T1 ---------------------------- */
-
-#define RC0_SICS 0x40
-#define RC0_CRCI 0x20
-#define RC0_XCRCI 0x10
-#define RC0_RDIS 0x08
-#define RC0_RCO2 0x04
-#define RC0_RCO1 0x02
-#define RC0_RCO0 0x01
-
-#define RC1_SWD 0x80
-#define RC1_ASY4 0x40
-#define RC1_RRAM 0x40
-#define RC1_RTO5 0x20
-#define RC1_RTO4 0x10
-#define RC1_RTO3 0x08
-#define RC1_RTO2 0x04
-#define RC1_RTO1 0x02
-#define RC1_RTO0 0x01
-
-
-
-/* XPM0-2 (Transmit Pulse Mask 0-2)
- --------------------- E1 & T1 ------------------------- */
-
-#define XPM0_XP12 0x80
-#define XPM0_XP11 0x40
-#define XPM0_XP10 0x20
-#define XPM0_XP04 0x10
-#define XPM0_XP03 0x08
-#define XPM0_XP02 0x04
-#define XPM0_XP01 0x02
-#define XPM0_XP00 0x01
-
-#define XPM1_XP30 0x80
-#define XPM1_XP24 0x40
-#define XPM1_XP23 0x20
-#define XPM1_XP22 0x10
-#define XPM1_XP21 0x08
-#define XPM1_XP20 0x04
-#define XPM1_XP14 0x02
-#define XPM1_XP13 0x01
-
-#define XPM2_XLHP 0x80
-#define XPM2_XLT 0x40
-#define XPM2_DAXLT 0x20
-#define XPM2_XP34 0x08
-#define XPM2_XP33 0x04
-#define XPM2_XP32 0x02
-#define XPM2_XP31 0x01
-
-
-/* TSWM (Transparent Service Word Mask)
- ------------------ E1 ---------------------------- */
-
-#define TSWM_TSIS 0x80
-#define TSWM_TSIF 0x40
-#define TSWM_TRA 0x20
-#define TSWM_TSA4 0x10
-#define TSWM_TSA5 0x08
-#define TSWM_TSA6 0x04
-#define TSWM_TSA7 0x02
-#define TSWM_TSA8 0x01
-
-/* IDLE <Idle Channel Code Register>
-
- ------------------ E1 & T1 ----------------------- */
-
-#define IDLE_IDL7 0x80
-#define IDLE_IDL6 0x40
-#define IDLE_IDL5 0x20
-#define IDLE_IDL4 0x10
-#define IDLE_IDL3 0x08
-#define IDLE_IDL2 0x04
-#define IDLE_IDL1 0x02
-#define IDLE_IDL0 0x01
-
-
-/* XSA4-8 <Transmit SA4-8 Register(Read/Write) >
- -------------------E1 ----------------------------- */
-
-#define XSA4_XS47 0x80
-#define XSA4_XS46 0x40
-#define XSA4_XS45 0x20
-#define XSA4_XS44 0x10
-#define XSA4_XS43 0x08
-#define XSA4_XS42 0x04
-#define XSA4_XS41 0x02
-#define XSA4_XS40 0x01
-
-#define XSA5_XS57 0x80
-#define XSA5_XS56 0x40
-#define XSA5_XS55 0x20
-#define XSA5_XS54 0x10
-#define XSA5_XS53 0x08
-#define XSA5_XS52 0x04
-#define XSA5_XS51 0x02
-#define XSA5_XS50 0x01
-
-#define XSA6_XS67 0x80
-#define XSA6_XS66 0x40
-#define XSA6_XS65 0x20
-#define XSA6_XS64 0x10
-#define XSA6_XS63 0x08
-#define XSA6_XS62 0x04
-#define XSA6_XS61 0x02
-#define XSA6_XS60 0x01
-
-#define XSA7_XS77 0x80
-#define XSA7_XS76 0x40
-#define XSA7_XS75 0x20
-#define XSA7_XS74 0x10
-#define XSA7_XS73 0x08
-#define XSA7_XS72 0x04
-#define XSA7_XS71 0x02
-#define XSA7_XS70 0x01
-
-#define XSA8_XS87 0x80
-#define XSA8_XS86 0x40
-#define XSA8_XS85 0x20
-#define XSA8_XS84 0x10
-#define XSA8_XS83 0x08
-#define XSA8_XS82 0x04
-#define XSA8_XS81 0x02
-#define XSA8_XS80 0x01
-
-
-/* XDL1-3 (Transmit DL-Bit Register1-3 (read/write))
- ----------------------- T1 --------------------- */
-
-#define XDL1_XDL17 0x80
-#define XDL1_XDL16 0x40
-#define XDL1_XDL15 0x20
-#define XDL1_XDL14 0x10
-#define XDL1_XDL13 0x08
-#define XDL1_XDL12 0x04
-#define XDL1_XDL11 0x02
-#define XDL1_XDL10 0x01
-
-#define XDL2_XDL27 0x80
-#define XDL2_XDL26 0x40
-#define XDL2_XDL25 0x20
-#define XDL2_XDL24 0x10
-#define XDL2_XDL23 0x08
-#define XDL2_XDL22 0x04
-#define XDL2_XDL21 0x02
-#define XDL2_XDL20 0x01
-
-#define XDL3_XDL37 0x80
-#define XDL3_XDL36 0x40
-#define XDL3_XDL35 0x20
-#define XDL3_XDL34 0x10
-#define XDL3_XDL33 0x08
-#define XDL3_XDL32 0x04
-#define XDL3_XDL31 0x02
-#define XDL3_XDL30 0x01
-
-
-/* ICB1-4 (Idle Channel Register 1-4)
- ------------------ E1 ---------------------------- */
-
-#define E1_ICB1_IC0 0x80
-#define E1_ICB1_IC1 0x40
-#define E1_ICB1_IC2 0x20
-#define E1_ICB1_IC3 0x10
-#define E1_ICB1_IC4 0x08
-#define E1_ICB1_IC5 0x04
-#define E1_ICB1_IC6 0x02
-#define E1_ICB1_IC7 0x01
-
-#define E1_ICB2_IC8 0x80
-#define E1_ICB2_IC9 0x40
-#define E1_ICB2_IC10 0x20
-#define E1_ICB2_IC11 0x10
-#define E1_ICB2_IC12 0x08
-#define E1_ICB2_IC13 0x04
-#define E1_ICB2_IC14 0x02
-#define E1_ICB2_IC15 0x01
-
-#define E1_ICB3_IC16 0x80
-#define E1_ICB3_IC17 0x40
-#define E1_ICB3_IC18 0x20
-#define E1_ICB3_IC19 0x10
-#define E1_ICB3_IC20 0x08
-#define E1_ICB3_IC21 0x04
-#define E1_ICB3_IC22 0x02
-#define E1_ICB3_IC23 0x01
-
-#define E1_ICB4_IC24 0x80
-#define E1_ICB4_IC25 0x40
-#define E1_ICB4_IC26 0x20
-#define E1_ICB4_IC27 0x10
-#define E1_ICB4_IC28 0x08
-#define E1_ICB4_IC29 0x04
-#define E1_ICB4_IC30 0x02
-#define E1_ICB4_IC31 0x01
-
-/* ICB1-4 (Idle Channel Register 1-4)
- ------------------ T1 ---------------------------- */
-
-#define T1_ICB1_IC1 0x80
-#define T1_ICB1_IC2 0x40
-#define T1_ICB1_IC3 0x20
-#define T1_ICB1_IC4 0x10
-#define T1_ICB1_IC5 0x08
-#define T1_ICB1_IC6 0x04
-#define T1_ICB1_IC7 0x02
-#define T1_ICB1_IC8 0x01
-
-#define T1_ICB2_IC9 0x80
-#define T1_ICB2_IC10 0x40
-#define T1_ICB2_IC11 0x20
-#define T1_ICB2_IC12 0x10
-#define T1_ICB2_IC13 0x08
-#define T1_ICB2_IC14 0x04
-#define T1_ICB2_IC15 0x02
-#define T1_ICB2_IC16 0x01
-
-#define T1_ICB3_IC17 0x80
-#define T1_ICB3_IC18 0x40
-#define T1_ICB3_IC19 0x20
-#define T1_ICB3_IC20 0x10
-#define T1_ICB3_IC21 0x08
-#define T1_ICB3_IC22 0x04
-#define T1_ICB3_IC23 0x02
-#define T1_ICB3_IC24 0x01
-
-/* FMR3 (Framer Mode Register 3)
- --------------------E1------------------------ */
-
-#define FMR3_CMI 0x08
-#define FMR3_SYNSA 0x04
-#define FMR3_CFRZ 0x02
-#define FMR3_EXTIW 0x01
-
-
-
-/* CCB1-3 (Clear Channel Register)
- ------------------- T1 ----------------------- */
-
-#define CCB1_CH1 0x80
-#define CCB1_CH2 0x40
-#define CCB1_CH3 0x20
-#define CCB1_CH4 0x10
-#define CCB1_CH5 0x08
-#define CCB1_CH6 0x04
-#define CCB1_CH7 0x02
-#define CCB1_CH8 0x01
-
-#define CCB2_CH9 0x80
-#define CCB2_CH10 0x40
-#define CCB2_CH11 0x20
-#define CCB2_CH12 0x10
-#define CCB2_CH13 0x08
-#define CCB2_CH14 0x04
-#define CCB2_CH15 0x02
-#define CCB2_CH16 0x01
-
-#define CCB3_CH17 0x80
-#define CCB3_CH18 0x40
-#define CCB3_CH19 0x20
-#define CCB3_CH20 0x10
-#define CCB3_CH21 0x08
-#define CCB3_CH22 0x04
-#define CCB3_CH23 0x02
-#define CCB3_CH24 0x01
-
-
-/* LIM0/1 (Line Interface Mode 0/1)
- ------------------- E1 & T1 --------------------------- */
-
-#define LIM0_XFB 0x80
-#define LIM0_XDOS 0x40
-#define LIM0_SCL1 0x20
-#define LIM0_SCL0 0x10
-#define LIM0_EQON 0x08
-#define LIM0_ELOS 0x04
-#define LIM0_LL 0x02
-#define LIM0_MAS 0x01
-
-#define LIM1_EFSC 0x80
-#define LIM1_RIL2 0x40
-#define LIM1_RIL1 0x20
-#define LIM1_RIL0 0x10
-#define LIM1_DCOC 0x08
-#define LIM1_JATT 0x04
-#define LIM1_RL 0x02
-#define LIM1_DRS 0x01
-
-
-/* PCDR (Pulse Count Detection Register(Read/Write))
- ------------------ E1 & T1 ------------------------- */
-
-#define PCDR_PCD7 0x80
-#define PCDR_PCD6 0x40
-#define PCDR_PCD5 0x20
-#define PCDR_PCD4 0x10
-#define PCDR_PCD3 0x08
-#define PCDR_PCD2 0x04
-#define PCDR_PCD1 0x02
-#define PCDR_PCD0 0x01
-
-#define PCRR_PCR7 0x80
-#define PCRR_PCR6 0x40
-#define PCRR_PCR5 0x20
-#define PCRR_PCR4 0x10
-#define PCRR_PCR3 0x08
-#define PCRR_PCR2 0x04
-#define PCRR_PCR1 0x02
-#define PCRR_PCR0 0x01
-
-
-/* LIM2 (Line Interface Mode 2)
-
- ------------------ E1 & T1 ---------------------------- */
-
-#define LIM2_DJA2 0x20
-#define LIM2_DJA1 0x10
-#define LIM2_LOS2 0x02
-#define LIM2_LOS1 0x01
-
-/* LCR1 (Loop Code Register 1) */
-
-#define LCR1_EPRM 0x80
-#define LCR1_XPRBS 0x40
-
-/* SIC1 (System Interface Control 1) */
-#define SIC1_SRSC 0x80
-#define SIC1_RBS1 0x20
-#define SIC1_RBS0 0x10
-#define SIC1_SXSC 0x08
-#define SIC1_XBS1 0x02
-#define SIC1_XBS0 0x01
-
-/* DEC (Disable Error Counter)
- ------------------ E1 & T1 ---------------------------- */
-
-#define DEC_DCEC3 0x20
-#define DEC_DBEC 0x10
-#define DEC_DCEC1 0x08
-#define DEC_DCEC 0x08
-#define DEC_DEBC 0x04
-#define DEC_DCVC 0x02
-#define DEC_DFEC 0x01
-
-
-/* FALC Register Bits (Receive Mode)
- ---------------------------------------------------------------------------- */
-
-
-/* FRS0/1 (Framer Receive Status Register 0/1)
- ----------------- E1 & T1 ---------------------------------- */
-
-#define FRS0_LOS 0x80
-#define FRS0_AIS 0x40
-#define FRS0_LFA 0x20
-#define FRS0_RRA 0x10
-#define FRS0_API 0x08
-#define FRS0_NMF 0x04
-#define FRS0_LMFA 0x02
-#define FRS0_FSRF 0x01
-
-#define FRS1_TS16RA 0x40
-#define FRS1_TS16LOS 0x20
-#define FRS1_TS16AIS 0x10
-#define FRS1_TS16LFA 0x08
-#define FRS1_EXZD 0x80
-#define FRS1_LLBDD 0x10
-#define FRS1_LLBAD 0x08
-#define FRS1_XLS 0x02
-#define FRS1_XLO 0x01
-#define FRS1_PDEN 0x40
-
-/* FRS2/3 (Framer Receive Status Register 2/3)
- ----------------- T1 ---------------------------------- */
-
-#define FRS2_ESC2 0x80
-#define FRS2_ESC1 0x40
-#define FRS2_ESC0 0x20
-
-#define FRS3_FEH5 0x20
-#define FRS3_FEH4 0x10
-#define FRS3_FEH3 0x08
-#define FRS3_FEH2 0x04
-#define FRS3_FEH1 0x02
-#define FRS3_FEH0 0x01
-
-
-/* RSW (Receive Service Word Pulseframe)
- ----------------- E1 ------------------------------ */
-
-#define RSW_RSI 0x80
-#define RSW_RRA 0x20
-#define RSW_RYO 0x10
-#define RSW_RY1 0x08
-#define RSW_RY2 0x04
-#define RSW_RY3 0x02
-#define RSW_RY4 0x01
-
-
-/* RSP (Receive Spare Bits / Additional Status)
- ---------------- E1 ------------------------------- */
-
-#define RSP_SI1 0x80
-#define RSP_SI2 0x40
-#define RSP_LLBDD 0x10
-#define RSP_LLBAD 0x08
-#define RSP_RSIF 0x04
-#define RSP_RS13 0x02
-#define RSP_RS15 0x01
-
-
-/* FECL (Framing Error Counter)
- ---------------- E1 & T1 -------------------------- */
-
-#define FECL_FE7 0x80
-#define FECL_FE6 0x40
-#define FECL_FE5 0x20
-#define FECL_FE4 0x10
-#define FECL_FE3 0x08
-#define FECL_FE2 0x04
-#define FECL_FE1 0x02
-#define FECL_FE0 0x01
-
-#define FECH_FE15 0x80
-#define FECH_FE14 0x40
-#define FECH_FE13 0x20
-#define FECH_FE12 0x10
-#define FECH_FE11 0x08
-#define FECH_FE10 0x04
-#define FECH_FE9 0x02
-#define FECH_FE8 0x01
-
-
-/* CVCl (Code Violation Counter)
- ----------------- E1 ------------------------- */
-
-#define CVCL_CV7 0x80
-#define CVCL_CV6 0x40
-#define CVCL_CV5 0x20
-#define CVCL_CV4 0x10
-#define CVCL_CV3 0x08
-#define CVCL_CV2 0x04
-#define CVCL_CV1 0x02
-#define CVCL_CV0 0x01
-
-#define CVCH_CV15 0x80
-#define CVCH_CV14 0x40
-#define CVCH_CV13 0x20
-#define CVCH_CV12 0x10
-#define CVCH_CV11 0x08
-#define CVCH_CV10 0x04
-#define CVCH_CV9 0x02
-#define CVCH_CV8 0x01
-
-
-/* CEC1-3L (CRC Error Counter)
- ------------------ E1 ----------------------------- */
-
-#define CEC1L_CR7 0x80
-#define CEC1L_CR6 0x40
-#define CEC1L_CR5 0x20
-#define CEC1L_CR4 0x10
-#define CEC1L_CR3 0x08
-#define CEC1L_CR2 0x04
-#define CEC1L_CR1 0x02
-#define CEC1L_CR0 0x01
-
-#define CEC1H_CR15 0x80
-#define CEC1H_CR14 0x40
-#define CEC1H_CR13 0x20
-#define CEC1H_CR12 0x10
-#define CEC1H_CR11 0x08
-#define CEC1H_CR10 0x04
-#define CEC1H_CR9 0x02
-#define CEC1H_CR8 0x01
-
-#define CEC2L_CR7 0x80
-#define CEC2L_CR6 0x40
-#define CEC2L_CR5 0x20
-#define CEC2L_CR4 0x10
-#define CEC2L_CR3 0x08
-#define CEC2L_CR2 0x04
-#define CEC2L_CR1 0x02
-#define CEC2L_CR0 0x01
-
-#define CEC2H_CR15 0x80
-#define CEC2H_CR14 0x40
-#define CEC2H_CR13 0x20
-#define CEC2H_CR12 0x10
-#define CEC2H_CR11 0x08
-#define CEC2H_CR10 0x04
-#define CEC2H_CR9 0x02
-#define CEC2H_CR8 0x01
-
-#define CEC3L_CR7 0x80
-#define CEC3L_CR6 0x40
-#define CEC3L_CR5 0x20
-#define CEC3L_CR4 0x10
-#define CEC3L_CR3 0x08
-#define CEC3L_CR2 0x04
-#define CEC3L_CR1 0x02
-#define CEC3L_CR0 0x01
-
-#define CEC3H_CR15 0x80
-#define CEC3H_CR14 0x40
-#define CEC3H_CR13 0x20
-#define CEC3H_CR12 0x10
-#define CEC3H_CR11 0x08
-#define CEC3H_CR10 0x04
-#define CEC3H_CR9 0x02
-#define CEC3H_CR8 0x01
-
-
-/* CECL (CRC Error Counter)
-
- ------------------ T1 ----------------------------- */
-
-#define CECL_CR7 0x80
-#define CECL_CR6 0x40
-#define CECL_CR5 0x20
-#define CECL_CR4 0x10
-#define CECL_CR3 0x08
-#define CECL_CR2 0x04
-#define CECL_CR1 0x02
-#define CECL_CR0 0x01
-
-#define CECH_CR15 0x80
-#define CECH_CR14 0x40
-#define CECH_CR13 0x20
-#define CECH_CR12 0x10
-#define CECH_CR11 0x08
-#define CECH_CR10 0x04
-#define CECH_CR9 0x02
-#define CECH_CR8 0x01
-
-/* EBCL (E Bit Error Counter)
- ------------------- E1 & T1 ------------------------- */
-
-#define EBCL_EB7 0x80
-#define EBCL_EB6 0x40
-#define EBCL_EB5 0x20
-#define EBCL_EB4 0x10
-#define EBCL_EB3 0x08
-#define EBCL_EB2 0x04
-#define EBCL_EB1 0x02
-#define EBCL_EB0 0x01
-
-#define EBCH_EB15 0x80
-#define EBCH_EB14 0x40
-#define EBCH_EB13 0x20
-#define EBCH_EB12 0x10
-#define EBCH_EB11 0x08
-#define EBCH_EB10 0x04
-#define EBCH_EB9 0x02
-#define EBCH_EB8 0x01
-
-
-/* RSA4-8 (Receive Sa4-8-Bit Register)
- -------------------- E1 --------------------------- */
-
-#define RSA4_RS47 0x80
-#define RSA4_RS46 0x40
-#define RSA4_RS45 0x20
-#define RSA4_RS44 0x10
-#define RSA4_RS43 0x08
-#define RSA4_RS42 0x04
-#define RSA4_RS41 0x02
-#define RSA4_RS40 0x01
-
-#define RSA5_RS57 0x80
-#define RSA5_RS56 0x40
-#define RSA5_RS55 0x20
-#define RSA5_RS54 0x10
-#define RSA5_RS53 0x08
-#define RSA5_RS52 0x04
-#define RSA5_RS51 0x02
-#define RSA5_RS50 0x01
-
-#define RSA6_RS67 0x80
-#define RSA6_RS66 0x40
-#define RSA6_RS65 0x20
-#define RSA6_RS64 0x10
-#define RSA6_RS63 0x08
-#define RSA6_RS62 0x04
-#define RSA6_RS61 0x02
-#define RSA6_RS60 0x01
-
-#define RSA7_RS77 0x80
-#define RSA7_RS76 0x40
-#define RSA7_RS75 0x20
-#define RSA7_RS74 0x10
-#define RSA7_RS73 0x08
-#define RSA7_RS72 0x04
-#define RSA7_RS71 0x02
-#define RSA7_RS70 0x01
-
-#define RSA8_RS87 0x80
-#define RSA8_RS86 0x40
-#define RSA8_RS85 0x20
-#define RSA8_RS84 0x10
-#define RSA8_RS83 0x08
-#define RSA8_RS82 0x04
-#define RSA8_RS81 0x02
-#define RSA8_RS80 0x01
-
-/* RSA6S (Receive Sa6 Bit Status Register)
- ------------------------ T1 ------------------------- */
-
-#define RSA6S_SX 0x20
-#define RSA6S_SF 0x10
-#define RSA6S_SE 0x08
-#define RSA6S_SC 0x04
-#define RSA6S_SA 0x02
-#define RSA6S_S8 0x01
-
-
-/* RDL1-3 Receive DL-Bit Register1-3)
- ------------------------ T1 ------------------------- */
-
-#define RDL1_RDL17 0x80
-#define RDL1_RDL16 0x40
-#define RDL1_RDL15 0x20
-#define RDL1_RDL14 0x10
-#define RDL1_RDL13 0x08
-#define RDL1_RDL12 0x04
-#define RDL1_RDL11 0x02
-#define RDL1_RDL10 0x01
-
-#define RDL2_RDL27 0x80
-#define RDL2_RDL26 0x40
-#define RDL2_RDL25 0x20
-#define RDL2_RDL24 0x10
-#define RDL2_RDL23 0x08
-#define RDL2_RDL22 0x04
-#define RDL2_RDL21 0x02
-#define RDL2_RDL20 0x01
-
-#define RDL3_RDL37 0x80
-#define RDL3_RDL36 0x40
-#define RDL3_RDL35 0x20
-#define RDL3_RDL34 0x10
-#define RDL3_RDL33 0x08
-#define RDL3_RDL32 0x04
-#define RDL3_RDL31 0x02
-#define RDL3_RDL30 0x01
-
-
-/* SIS (Signaling Status Register)
-
- -------------------- E1 & T1 -------------------------- */
-
-#define SIS_XDOV 0x80
-#define SIS_XFW 0x40
-#define SIS_XREP 0x20
-#define SIS_RLI 0x08
-#define SIS_CEC 0x04
-#define SIS_BOM 0x01
-
-
-/* RSIS (Receive Signaling Status Register)
-
- -------------------- E1 & T1 --------------------------- */
-
-#define RSIS_VFR 0x80
-#define RSIS_RDO 0x40
-#define RSIS_CRC16 0x20
-#define RSIS_RAB 0x10
-#define RSIS_HA1 0x08
-#define RSIS_HA0 0x04
-#define RSIS_HFR 0x02
-#define RSIS_LA 0x01
-
-
-/* RBCL/H (Receive Byte Count Low/High)
-
- ------------------- E1 & T1 ----------------------- */
-
-#define RBCL_RBC7 0x80
-#define RBCL_RBC6 0x40
-#define RBCL_RBC5 0x20
-#define RBCL_RBC4 0x10
-#define RBCL_RBC3 0x08
-#define RBCL_RBC2 0x04
-#define RBCL_RBC1 0x02
-#define RBCL_RBC0 0x01
-
-#define RBCH_OV 0x10
-#define RBCH_RBC11 0x08
-#define RBCH_RBC10 0x04
-#define RBCH_RBC9 0x02
-#define RBCH_RBC8 0x01
-
-
-/* ISR1-3 (Interrupt Status Register 1-3)
-
- ------------------ E1 & T1 ------------------------------ */
-
-#define FISR0_RME 0x80
-#define FISR0_RFS 0x40
-#define FISR0_T8MS 0x20
-#define FISR0_ISF 0x20
-#define FISR0_RMB 0x10
-#define FISR0_CASC 0x08
-#define FISR0_RSC 0x08
-#define FISR0_CRC6 0x04
-#define FISR0_CRC4 0x04
-#define FISR0_PDEN 0x02
-#define FISR0_RPF 0x01
-
-#define FISR1_CASE 0x80
-#define FISR1_LLBSC 0x80
-#define FISR1_RDO 0x40
-#define FISR1_ALLS 0x20
-#define FISR1_XDU 0x10
-#define FISR1_XMB 0x08
-#define FISR1_XLSC 0x02
-#define FISR1_XPR 0x01
-
-#define FISR2_FAR 0x80
-#define FISR2_LFA 0x40
-#define FISR2_MFAR 0x20
-#define FISR2_T400MS 0x10
-#define FISR2_LMFA 0x10
-#define FISR2_AIS 0x08
-#define FISR2_LOS 0x04
-#define FISR2_RAR 0x02
-#define FISR2_RA 0x01
-
-#define FISR3_ES 0x80
-#define FISR3_SEC 0x40
-#define FISR3_LMFA16 0x20
-#define FISR3_AIS16 0x10
-#define FISR3_RA16 0x08
-#define FISR3_API 0x04
-#define FISR3_XSLP 0x20
-#define FISR3_XSLN 0x10
-#define FISR3_LLBSC 0x08
-#define FISR3_XRS 0x04
-#define FISR3_SLN 0x02
-#define FISR3_SLP 0x01
-
-
-/* GIS (Global Interrupt Status Register)
-
- --------------------- E1 & T1 --------------------- */
-
-#define GIS_ISR3 0x08
-#define GIS_ISR2 0x04
-#define GIS_ISR1 0x02
-#define GIS_ISR0 0x01
-
-
-/* VSTR (Version Status Register)
-
- --------------------- E1 & T1 --------------------- */
-
-#define VSTR_VN3 0x08
-#define VSTR_VN2 0x04
-#define VSTR_VN1 0x02
-#define VSTR_VN0 0x01
-
-
-/*>>>>>>>>>>>>>>>>>>>>> Local Control Structures <<<<<<<<<<<<<<<<<<<<<<<<< */
-
-/* Write-only Registers (E1/T1 control mode write registers) */
-#define XFIFOH 0x00 /* Tx FIFO High Byte */
-#define XFIFOL 0x01 /* Tx FIFO Low Byte */
-#define CMDR 0x02 /* Command Reg */
-#define DEC 0x60 /* Disable Error Counter */
-#define TEST2 0x62 /* Manuf. Test Reg 2 */
-#define XS(nbr) (0x70 + (nbr)) /* Tx CAS Reg (0 to 15) */
-
-/* Read-write Registers (E1/T1 status mode read registers) */
-#define MODE 0x03 /* Mode Reg */
-#define RAH1 0x04 /* Receive Address High 1 */
-#define RAH2 0x05 /* Receive Address High 2 */
-#define RAL1 0x06 /* Receive Address Low 1 */
-#define RAL2 0x07 /* Receive Address Low 2 */
-#define IPC 0x08 /* Interrupt Port Configuration */
-#define CCR1 0x09 /* Common Configuration Reg 1 */
-#define CCR3 0x0A /* Common Configuration Reg 3 */
-#define PRE 0x0B /* Preamble Reg */
-#define RTR1 0x0C /* Receive Timeslot Reg 1 */
-#define RTR2 0x0D /* Receive Timeslot Reg 2 */
-#define RTR3 0x0E /* Receive Timeslot Reg 3 */
-#define RTR4 0x0F /* Receive Timeslot Reg 4 */
-#define TTR1 0x10 /* Transmit Timeslot Reg 1 */
-#define TTR2 0x11 /* Transmit Timeslot Reg 2 */
-#define TTR3 0x12 /* Transmit Timeslot Reg 3 */
-#define TTR4 0x13 /* Transmit Timeslot Reg 4 */
-#define IMR0 0x14 /* Interrupt Mask Reg 0 */
-#define IMR1 0x15 /* Interrupt Mask Reg 1 */
-#define IMR2 0x16 /* Interrupt Mask Reg 2 */
-#define IMR3 0x17 /* Interrupt Mask Reg 3 */
-#define IMR4 0x18 /* Interrupt Mask Reg 4 */
-#define IMR5 0x19 /* Interrupt Mask Reg 5 */
-#define FMR0 0x1A /* Framer Mode Reigster 0 */
-#define FMR1 0x1B /* Framer Mode Reigster 1 */
-#define FMR2 0x1C /* Framer Mode Reigster 2 */
-#define LOOP 0x1D /* Channel Loop Back */
-#define XSW 0x1E /* Transmit Service Word */
-#define FMR4 0x1E /* Framer Mode Reg 4 */
-#define XSP 0x1F /* Transmit Spare Bits */
-#define FMR5 0x1F /* Framer Mode Reg 5 */
-#define XC0 0x20 /* Transmit Control 0 */
-#define XC1 0x21 /* Transmit Control 1 */
-#define RC0 0x22 /* Receive Control 0 */
-#define RC1 0x23 /* Receive Control 1 */
-#define XPM0 0x24 /* Transmit Pulse Mask 0 */
-#define XPM1 0x25 /* Transmit Pulse Mask 1 */
-#define XPM2 0x26 /* Transmit Pulse Mask 2 */
-#define TSWM 0x27 /* Transparent Service Word Mask */
-#define TEST1 0x28 /* Manuf. Test Reg 1 */
-#define IDLE 0x29 /* Idle Channel Code */
-#define XSA4 0x2A /* Transmit SA4 Bit Reg */
-#define XDL1 0x2A /* Transmit DL-Bit Reg 2 */
-#define XSA5 0x2B /* Transmit SA4 Bit Reg */
-#define XDL2 0x2B /* Transmit DL-Bit Reg 2 */
-#define XSA6 0x2C /* Transmit SA4 Bit Reg */
-#define XDL3 0x2C /* Transmit DL-Bit Reg 2 */
-#define XSA7 0x2D /* Transmit SA4 Bit Reg */
-#define CCB1 0x2D /* Clear Channel Reg 1 */
-#define XSA8 0x2E /* Transmit SA4 Bit Reg */
-#define CCB2 0x2E /* Clear Channel Reg 2 */
-#define FMR3 0x2F /* Framer Mode Reg. 3 */
-#define CCB3 0x2F /* Clear Channel Reg 3 */
-#define ICB1 0x30 /* Idle Channel Reg 1 */
-#define ICB2 0x31 /* Idle Channel Reg 2 */
-#define ICB3 0x32 /* Idle Channel Reg 3 */
-#define ICB4 0x33 /* Idle Channel Reg 4 */
-#define LIM0 0x34 /* Line Interface Mode 0 */
-#define LIM1 0x35 /* Line Interface Mode 1 */
-#define PCDR 0x36 /* Pulse Count Detection */
-#define PCRR 0x37 /* Pulse Count Recovery */
-#define LIM2 0x38 /* Line Interface Mode Reg 2 */
-#define LCR1 0x39 /* Loop Code Reg 1 */
-#define LCR2 0x3A /* Loop Code Reg 2 */
-#define LCR3 0x3B /* Loop Code Reg 3 */
-#define SIC1 0x3C /* System Interface Control 1 */
-
-/* Read-only Registers (E1/T1 control mode read registers) */
-#define RFIFOH 0x00 /* Receive FIFO */
-#define RFIFOL 0x01 /* Receive FIFO */
-#define FRS0 0x4C /* Framer Receive Status 0 */
-#define FRS1 0x4D /* Framer Receive Status 1 */
-#define RSW 0x4E /* Receive Service Word */
-#define FRS2 0x4E /* Framer Receive Status 2 */
-#define RSP 0x4F /* Receive Spare Bits */
-#define FRS3 0x4F /* Framer Receive Status 3 */
-#define FECL 0x50 /* Framing Error Counter */
-#define FECH 0x51 /* Framing Error Counter */
-#define CVCL 0x52 /* Code Violation Counter */
-#define CVCH 0x53 /* Code Violation Counter */
-#define CECL 0x54 /* CRC Error Counter 1 */
-#define CECH 0x55 /* CRC Error Counter 1 */
-#define EBCL 0x56 /* E-Bit Error Counter */
-#define EBCH 0x57 /* E-Bit Error Counter */
-#define BECL 0x58 /* Bit Error Counter Low */
-#define BECH 0x59 /* Bit Error Counter Low */
-#define CEC3 0x5A /* CRC Error Counter 3 (16-bit) */
-#define RSA4 0x5C /* Receive SA4 Bit Reg */
-#define RDL1 0x5C /* Receive DL-Bit Reg 1 */
-#define RSA5 0x5D /* Receive SA5 Bit Reg */
-#define RDL2 0x5D /* Receive DL-Bit Reg 2 */
-#define RSA6 0x5E /* Receive SA6 Bit Reg */
-#define RDL3 0x5E /* Receive DL-Bit Reg 3 */
-#define RSA7 0x5F /* Receive SA7 Bit Reg */
-#define RSA8 0x60 /* Receive SA8 Bit Reg */
-#define RSA6S 0x61 /* Receive SA6 Bit Status Reg */
-#define TSR0 0x62 /* Manuf. Test Reg 0 */
-#define TSR1 0x63 /* Manuf. Test Reg 1 */
-#define SIS 0x64 /* Signaling Status Reg */
-#define RSIS 0x65 /* Receive Signaling Status Reg */
-#define RBCL 0x66 /* Receive Byte Control */
-#define RBCH 0x67 /* Receive Byte Control */
-#define FISR0 0x68 /* Interrupt Status Reg 0 */
-#define FISR1 0x69 /* Interrupt Status Reg 1 */
-#define FISR2 0x6A /* Interrupt Status Reg 2 */
-#define FISR3 0x6B /* Interrupt Status Reg 3 */
-#define GIS 0x6E /* Global Interrupt Status */
-#define VSTR 0x6F /* Version Status */
-#define RS(nbr) (0x70 + (nbr)) /* Rx CAS Reg (0 to 15) */
-
-#endif /* _FALC_LH_H */
-
diff --git a/drivers/staging/net/pc300.h b/drivers/staging/net/pc300.h
deleted file mode 100644
index 2e4f84f6cad4..000000000000
--- a/drivers/staging/net/pc300.h
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * pc300.h Cyclades-PC300(tm) Kernel API Definitions.
- *
- * Author: Ivan Passos <ivan@cyclades.com>
- *
- * Copyright: (c) 1999-2002 Cyclades Corp.
- *
- * 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.
- *
- * $Log: pc300.h,v $
- * Revision 3.12 2002/03/07 14:17:09 henrique
- * License data fixed
- *
- * Revision 3.11 2002/01/28 21:09:39 daniela
- * Included ';' after pc300hw.bus.
- *
- * Revision 3.10 2002/01/17 17:58:52 ivan
- * Support for PC300-TE/M (PMC).
- *
- * Revision 3.9 2001/09/28 13:30:53 daniela
- * Renamed dma_start routine to rx_dma_start.
- *
- * Revision 3.8 2001/09/24 13:03:45 daniela
- * Fixed BOF interrupt treatment. Created dma_start routine.
- *
- * Revision 3.7 2001/08/10 17:19:58 daniela
- * Fixed IOCTLs defines.
- *
- * Revision 3.6 2001/07/18 19:24:42 daniela
- * Included kernel version.
- *
- * Revision 3.5 2001/07/05 18:38:08 daniela
- * DMA transmission bug fix.
- *
- * Revision 3.4 2001/06/26 17:10:40 daniela
- * New configuration parameters (line code, CRC calculation and clock).
- *
- * Revision 3.3 2001/06/22 13:13:02 regina
- * MLPPP implementation
- *
- * Revision 3.2 2001/06/18 17:56:09 daniela
- * Increased DEF_MTU and TX_QUEUE_LEN.
- *
- * Revision 3.1 2001/06/15 12:41:10 regina
- * upping major version number
- *
- * Revision 1.1.1.1 2001/06/13 20:25:06 daniela
- * PC300 initial CVS version (3.4.0-pre1)
- *
- * Revision 2.3 2001/03/05 daniela
- * Created struct pc300conf, to provide the hardware information to pc300util.
- * Inclusion of 'alloc_ramsize' field on structure 'pc300hw'.
- *
- * Revision 2.2 2000/12/22 daniela
- * Structures and defines to support pc300util: statistics, status,
- * loopback tests, trace.
- *
- * Revision 2.1 2000/09/28 ivan
- * Inclusion of 'iophys' and 'iosize' fields on structure 'pc300hw', to
- * allow release of I/O region at module unload.
- * Changed location of include files.
- *
- * Revision 2.0 2000/03/27 ivan
- * Added support for the PC300/TE cards.
- *
- * Revision 1.1 2000/01/31 ivan
- * Replaced 'pc300[drv|sca].h' former PC300 driver include files.
- *
- * Revision 1.0 1999/12/16 ivan
- * First official release.
- * Inclusion of 'nchan' field on structure 'pc300hw', to allow variable
- * number of ports per card.
- * Inclusion of 'if_ptr' field on structure 'pc300dev'.
- *
- * Revision 0.6 1999/11/17 ivan
- * Changed X.25-specific function names to comply with adopted convention.
- *
- * Revision 0.5 1999/11/16 Daniela Squassoni
- * X.25 support.
- *
- * Revision 0.4 1999/11/15 ivan
- * Inclusion of 'clock' field on structure 'pc300hw'.
- *
- * Revision 0.3 1999/11/10 ivan
- * IOCTL name changing.
- * Inclusion of driver function prototypes.
- *
- * Revision 0.2 1999/11/03 ivan
- * Inclusion of 'tx_skb' and union 'ifu' on structure 'pc300dev'.
- *
- * Revision 0.1 1999/01/15 ivan
- * Initial version.
- *
- */
-
-#ifndef _PC300_H
-#define _PC300_H
-
-#include <linux/hdlc.h>
-#include "hd64572.h"
-#include "pc300-falc-lh.h"
-
-#define PC300_PROTO_MLPPP 1
-
-#define PC300_MAXCHAN 2 /* Number of channels per card */
-
-#define PC300_RAMSIZE 0x40000 /* RAM window size (256Kb) */
-#define PC300_FALCSIZE 0x400 /* FALC window size (1Kb) */
-
-#define PC300_OSC_CLOCK 24576000
-#define PC300_PCI_CLOCK 33000000
-
-#define BD_DEF_LEN 0x0800 /* DMA buffer length (2KB) */
-#define DMA_TX_MEMSZ 0x8000 /* Total DMA Tx memory size (32KB/ch) */
-#define DMA_RX_MEMSZ 0x10000 /* Total DMA Rx memory size (64KB/ch) */
-
-#define N_DMA_TX_BUF (DMA_TX_MEMSZ / BD_DEF_LEN) /* DMA Tx buffers */
-#define N_DMA_RX_BUF (DMA_RX_MEMSZ / BD_DEF_LEN) /* DMA Rx buffers */
-
-/* DMA Buffer Offsets */
-#define DMA_TX_BASE ((N_DMA_TX_BUF + N_DMA_RX_BUF) * \
- PC300_MAXCHAN * sizeof(pcsca_bd_t))
-#define DMA_RX_BASE (DMA_TX_BASE + PC300_MAXCHAN*DMA_TX_MEMSZ)
-
-/* DMA Descriptor Offsets */
-#define DMA_TX_BD_BASE 0x0000
-#define DMA_RX_BD_BASE (DMA_TX_BD_BASE + ((PC300_MAXCHAN*DMA_TX_MEMSZ / \
- BD_DEF_LEN) * sizeof(pcsca_bd_t)))
-
-/* DMA Descriptor Macros */
-#define TX_BD_ADDR(chan, n) (DMA_TX_BD_BASE + \
- ((N_DMA_TX_BUF*chan) + n) * sizeof(pcsca_bd_t))
-#define RX_BD_ADDR(chan, n) (DMA_RX_BD_BASE + \
- ((N_DMA_RX_BUF*chan) + n) * sizeof(pcsca_bd_t))
-
-/* Macro to access the FALC registers (TE only) */
-#define F_REG(reg, chan) (0x200*(chan) + ((reg)<<2))
-
-/***************************************
- * Memory access functions/macros *
- * (required to support Alpha systems) *
- ***************************************/
-#define cpc_writeb(port,val) {writeb((u8)(val),(port)); mb();}
-#define cpc_writew(port,val) {writew((ushort)(val),(port)); mb();}
-#define cpc_writel(port,val) {writel((u32)(val),(port)); mb();}
-
-#define cpc_readb(port) readb(port)
-#define cpc_readw(port) readw(port)
-#define cpc_readl(port) readl(port)
-
-/****** Data Structures *****************************************************/
-
-/*
- * RUNTIME_9050 - PLX PCI9050-1 local configuration and shared runtime
- * registers. This structure can be used to access the 9050 registers
- * (memory mapped).
- */
-struct RUNTIME_9050 {
- u32 loc_addr_range[4]; /* 00-0Ch : Local Address Ranges */
- u32 loc_rom_range; /* 10h : Local ROM Range */
- u32 loc_addr_base[4]; /* 14-20h : Local Address Base Addrs */
- u32 loc_rom_base; /* 24h : Local ROM Base */
- u32 loc_bus_descr[4]; /* 28-34h : Local Bus Descriptors */
- u32 rom_bus_descr; /* 38h : ROM Bus Descriptor */
- u32 cs_base[4]; /* 3C-48h : Chip Select Base Addrs */
- u32 intr_ctrl_stat; /* 4Ch : Interrupt Control/Status */
- u32 init_ctrl; /* 50h : EEPROM ctrl, Init Ctrl, etc */
-};
-
-#define PLX_9050_LINT1_ENABLE 0x01
-#define PLX_9050_LINT1_POL 0x02
-#define PLX_9050_LINT1_STATUS 0x04
-#define PLX_9050_LINT2_ENABLE 0x08
-#define PLX_9050_LINT2_POL 0x10
-#define PLX_9050_LINT2_STATUS 0x20
-#define PLX_9050_INTR_ENABLE 0x40
-#define PLX_9050_SW_INTR 0x80
-
-/* Masks to access the init_ctrl PLX register */
-#define PC300_CLKSEL_MASK (0x00000004UL)
-#define PC300_CHMEDIA_MASK(chan) (0x00000020UL<<(chan*3))
-#define PC300_CTYPE_MASK (0x00000800UL)
-
-/* CPLD Registers (base addr = falcbase, TE only) */
-/* CPLD v. 0 */
-#define CPLD_REG1 0x140 /* Chip resets, DCD/CTS status */
-#define CPLD_REG2 0x144 /* Clock enable , LED control */
-/* CPLD v. 2 or higher */
-#define CPLD_V2_REG1 0x100 /* Chip resets, DCD/CTS status */
-#define CPLD_V2_REG2 0x104 /* Clock enable , LED control */
-#define CPLD_ID_REG 0x108 /* CPLD version */
-
-/* CPLD Register bit description: for the FALC bits, they should always be
- set based on the channel (use (bit<<(2*ch)) to access the correct bit for
- that channel) */
-#define CPLD_REG1_FALC_RESET 0x01
-#define CPLD_REG1_SCA_RESET 0x02
-#define CPLD_REG1_GLOBAL_CLK 0x08
-#define CPLD_REG1_FALC_DCD 0x10
-#define CPLD_REG1_FALC_CTS 0x20
-
-#define CPLD_REG2_FALC_TX_CLK 0x01
-#define CPLD_REG2_FALC_RX_CLK 0x02
-#define CPLD_REG2_FALC_LED1 0x10
-#define CPLD_REG2_FALC_LED2 0x20
-
-/* Structure with FALC-related fields (TE only) */
-#define PC300_FALC_MAXLOOP 0x0000ffff /* for falc_issue_cmd() */
-
-typedef struct falc {
- u8 sync; /* If true FALC is synchronized */
- u8 active; /* if TRUE then already active */
- u8 loop_active; /* if TRUE a line loopback UP was received */
- u8 loop_gen; /* if TRUE a line loopback UP was issued */
-
- u8 num_channels;
- u8 offset; /* 1 for T1, 0 for E1 */
- u8 full_bandwidth;
-
- u8 xmb_cause;
- u8 multiframe_mode;
-
- /* Statistics */
- u16 pden; /* Pulse Density violation count */
- u16 los; /* Loss of Signal count */
- u16 losr; /* Loss of Signal recovery count */
- u16 lfa; /* Loss of frame alignment count */
- u16 farec; /* Frame Alignment Recovery count */
- u16 lmfa; /* Loss of multiframe alignment count */
- u16 ais; /* Remote Alarm indication Signal count */
- u16 sec; /* One-second timer */
- u16 es; /* Errored second */
- u16 rai; /* remote alarm received */
- u16 bec;
- u16 fec;
- u16 cvc;
- u16 cec;
- u16 ebc;
-
- /* Status */
- u8 red_alarm;
- u8 blue_alarm;
- u8 loss_fa;
- u8 yellow_alarm;
- u8 loss_mfa;
- u8 prbs;
-} falc_t;
-
-typedef struct falc_status {
- u8 sync; /* If true FALC is synchronized */
- u8 red_alarm;
- u8 blue_alarm;
- u8 loss_fa;
- u8 yellow_alarm;
- u8 loss_mfa;
- u8 prbs;
-} falc_status_t;
-
-typedef struct rsv_x21_status {
- u8 dcd;
- u8 dsr;
- u8 cts;
- u8 rts;
- u8 dtr;
-} rsv_x21_status_t;
-
-typedef struct pc300stats {
- int hw_type;
- u32 line_on;
- u32 line_off;
- struct net_device_stats gen_stats;
- falc_t te_stats;
-} pc300stats_t;
-
-typedef struct pc300status {
- int hw_type;
- rsv_x21_status_t gen_status;
- falc_status_t te_status;
-} pc300status_t;
-
-typedef struct pc300loopback {
- char loop_type;
- char loop_on;
-} pc300loopback_t;
-
-typedef struct pc300patterntst {
- char patrntst_on; /* 0 - off; 1 - on; 2 - read num_errors */
- u16 num_errors;
-} pc300patterntst_t;
-
-typedef struct pc300dev {
- struct pc300ch *chan;
- u8 trace_on;
- u32 line_on; /* DCD(X.21, RSV) / sync(TE) change counters */
- u32 line_off;
- char name[16];
- struct net_device *dev;
-#ifdef CONFIG_PC300_MLPPP
- void *cpc_tty; /* information to PC300 TTY driver */
-#endif
-}pc300dev_t;
-
-typedef struct pc300hw {
- int type; /* RSV, X21, etc. */
- int bus; /* Bus (PCI, PMC, etc.) */
- int nchan; /* number of channels */
- int irq; /* interrupt request level */
- u32 clock; /* Board clock */
- u8 cpld_id; /* CPLD ID (TE only) */
- u16 cpld_reg1; /* CPLD reg 1 (TE only) */
- u16 cpld_reg2; /* CPLD reg 2 (TE only) */
- u16 gpioc_reg; /* PLX GPIOC reg */
- u16 intctl_reg; /* PLX Int Ctrl/Status reg */
- u32 iophys; /* PLX registers I/O base */
- u32 iosize; /* PLX registers I/O size */
- u32 plxphys; /* PLX registers MMIO base (physical) */
- void __iomem * plxbase; /* PLX registers MMIO base (virtual) */
- u32 plxsize; /* PLX registers MMIO size */
- u32 scaphys; /* SCA registers MMIO base (physical) */
- void __iomem * scabase; /* SCA registers MMIO base (virtual) */
- u32 scasize; /* SCA registers MMIO size */
- u32 ramphys; /* On-board RAM MMIO base (physical) */
- void __iomem * rambase; /* On-board RAM MMIO base (virtual) */
- u32 alloc_ramsize; /* RAM MMIO size allocated by the PCI bridge */
- u32 ramsize; /* On-board RAM MMIO size */
- u32 falcphys; /* FALC registers MMIO base (physical) */
- void __iomem * falcbase;/* FALC registers MMIO base (virtual) */
- u32 falcsize; /* FALC registers MMIO size */
-} pc300hw_t;
-
-typedef struct pc300chconf {
- sync_serial_settings phys_settings; /* Clock type/rate (in bps),
- loopback mode */
- raw_hdlc_proto proto_settings; /* Encoding, parity (CRC) */
- u32 media; /* HW media (RS232, V.35, etc.) */
- u32 proto; /* Protocol (PPP, X.25, etc.) */
-
- /* TE-specific parameters */
- u8 lcode; /* Line Code (AMI, B8ZS, etc.) */
- u8 fr_mode; /* Frame Mode (ESF, D4, etc.) */
- u8 lbo; /* Line Build Out */
- u8 rx_sens; /* Rx Sensitivity (long- or short-haul) */
- u32 tslot_bitmap; /* bit[i]=1 => timeslot _i_ is active */
-} pc300chconf_t;
-
-typedef struct pc300ch {
- struct pc300 *card;
- int channel;
- pc300dev_t d;
- pc300chconf_t conf;
- u8 tx_first_bd; /* First TX DMA block descr. w/ data */
- u8 tx_next_bd; /* Next free TX DMA block descriptor */
- u8 rx_first_bd; /* First free RX DMA block descriptor */
- u8 rx_last_bd; /* Last free RX DMA block descriptor */
- u8 nfree_tx_bd; /* Number of free TX DMA block descriptors */
- falc_t falc; /* FALC structure (TE only) */
-} pc300ch_t;
-
-typedef struct pc300 {
- pc300hw_t hw; /* hardware config. */
- pc300ch_t chan[PC300_MAXCHAN];
- spinlock_t card_lock;
-} pc300_t;
-
-typedef struct pc300conf {
- pc300hw_t hw;
- pc300chconf_t conf;
-} pc300conf_t;
-
-/* DEV ioctl() commands */
-#define N_SPPP_IOCTLS 2
-
-enum pc300_ioctl_cmds {
- SIOCCPCRESERVED = (SIOCDEVPRIVATE + N_SPPP_IOCTLS),
- SIOCGPC300CONF,
- SIOCSPC300CONF,
- SIOCGPC300STATUS,
- SIOCGPC300FALCSTATUS,
- SIOCGPC300UTILSTATS,
- SIOCGPC300UTILSTATUS,
- SIOCSPC300TRACE,
- SIOCSPC300LOOPBACK,
- SIOCSPC300PATTERNTEST,
-};
-
-/* Loopback types - PC300/TE boards */
-enum pc300_loopback_cmds {
- PC300LOCLOOP = 1,
- PC300REMLOOP,
- PC300PAYLOADLOOP,
- PC300GENLOOPUP,
- PC300GENLOOPDOWN,
-};
-
-/* Control Constant Definitions */
-#define PC300_RSV 0x01
-#define PC300_X21 0x02
-#define PC300_TE 0x03
-
-#define PC300_PCI 0x00
-#define PC300_PMC 0x01
-
-#define PC300_LC_AMI 0x01
-#define PC300_LC_B8ZS 0x02
-#define PC300_LC_NRZ 0x03
-#define PC300_LC_HDB3 0x04
-
-/* Framing (T1) */
-#define PC300_FR_ESF 0x01
-#define PC300_FR_D4 0x02
-#define PC300_FR_ESF_JAPAN 0x03
-
-/* Framing (E1) */
-#define PC300_FR_MF_CRC4 0x04
-#define PC300_FR_MF_NON_CRC4 0x05
-#define PC300_FR_UNFRAMED 0x06
-
-#define PC300_LBO_0_DB 0x00
-#define PC300_LBO_7_5_DB 0x01
-#define PC300_LBO_15_DB 0x02
-#define PC300_LBO_22_5_DB 0x03
-
-#define PC300_RX_SENS_SH 0x01
-#define PC300_RX_SENS_LH 0x02
-
-#define PC300_TX_TIMEOUT (2*HZ)
-#define PC300_TX_QUEUE_LEN 100
-#define PC300_DEF_MTU 1600
-
-/* Function Prototypes */
-int cpc_open(struct net_device *dev);
-
-#endif /* _PC300_H */
diff --git a/drivers/staging/net/pc300_drv.c b/drivers/staging/net/pc300_drv.c
deleted file mode 100644
index 7281797ffe9d..000000000000
--- a/drivers/staging/net/pc300_drv.c
+++ /dev/null
@@ -1,3670 +0,0 @@
-#define USE_PCI_CLOCK
-static const char rcsid[] =
-"Revision: 3.4.5 Date: 2002/03/07 ";
-
-/*
- * pc300.c Cyclades-PC300(tm) Driver.
- *
- * Author: Ivan Passos <ivan@cyclades.com>
- * Maintainer: PC300 Maintainer <pc300@cyclades.com>
- *
- * Copyright: (c) 1999-2003 Cyclades Corp.
- *
- * 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.
- *
- * Using tabstop = 4.
- *
- * $Log: pc300_drv.c,v $
- * Revision 3.23 2002/03/20 13:58:40 henrique
- * Fixed ortographic mistakes
- *
- * Revision 3.22 2002/03/13 16:56:56 henrique
- * Take out the debug messages
- *
- * Revision 3.21 2002/03/07 14:17:09 henrique
- * License data fixed
- *
- * Revision 3.20 2002/01/17 17:58:52 ivan
- * Support for PC300-TE/M (PMC).
- *
- * Revision 3.19 2002/01/03 17:08:47 daniela
- * Enables DMA reception when the SCA-II disables it improperly.
- *
- * Revision 3.18 2001/12/03 18:47:50 daniela
- * Esthetic changes.
- *
- * Revision 3.17 2001/10/19 16:50:13 henrique
- * Patch to kernel 2.4.12 and new generic hdlc.
- *
- * Revision 3.16 2001/10/16 15:12:31 regina
- * clear statistics
- *
- * Revision 3.11 to 3.15 2001/10/11 20:26:04 daniela
- * More DMA fixes for noisy lines.
- * Return the size of bad frames in dma_get_rx_frame_size, so that the Rx buffer
- * descriptors can be cleaned by dma_buf_read (called in cpc_net_rx).
- * Renamed dma_start routine to rx_dma_start. Improved Rx statistics.
- * Fixed BOF interrupt treatment. Created dma_start routine.
- * Changed min and max to cpc_min and cpc_max.
- *
- * Revision 3.10 2001/08/06 12:01:51 regina
- * Fixed problem in DSR_DE bit.
- *
- * Revision 3.9 2001/07/18 19:27:26 daniela
- * Added some history comments.
- *
- * Revision 3.8 2001/07/12 13:11:19 regina
- * bug fix - DCD-OFF in pc300 tty driver
- *
- * Revision 3.3 to 3.7 2001/07/06 15:00:20 daniela
- * Removing kernel 2.4.3 and previous support.
- * DMA transmission bug fix.
- * MTU check in cpc_net_rx fixed.
- * Boot messages reviewed.
- * New configuration parameters (line code, CRC calculation and clock).
- *
- * Revision 3.2 2001/06/22 13:13:02 regina
- * MLPPP implementation. Changed the header of message trace to include
- * the device name. New format : "hdlcX[R/T]: ".
- * Default configuration changed.
- *
- * Revision 3.1 2001/06/15 regina
- * in cpc_queue_xmit, netif_stop_queue is called if don't have free descriptor
- * upping major version number
- *
- * Revision 1.1.1.1 2001/06/13 20:25:04 daniela
- * PC300 initial CVS version (3.4.0-pre1)
- *
- * Revision 3.0.1.2 2001/06/08 daniela
- * Did some changes in the DMA programming implementation to avoid the
- * occurrence of a SCA-II bug when CDA is accessed during a DMA transfer.
- *
- * Revision 3.0.1.1 2001/05/02 daniela
- * Added kernel 2.4.3 support.
- *
- * Revision 3.0.1.0 2001/03/13 daniela, henrique
- * Added Frame Relay Support.
- * Driver now uses HDLC generic driver to provide protocol support.
- *
- * Revision 3.0.0.8 2001/03/02 daniela
- * Fixed ram size detection.
- * Changed SIOCGPC300CONF ioctl, to give hw information to pc300util.
- *
- * Revision 3.0.0.7 2001/02/23 daniela
- * netif_stop_queue called before the SCA-II transmition commands in
- * cpc_queue_xmit, and with interrupts disabled to avoid race conditions with
- * transmition interrupts.
- * Fixed falc_check_status for Unframed E1.
- *
- * Revision 3.0.0.6 2000/12/13 daniela
- * Implemented pc300util support: trace, statistics, status and loopback
- * tests for the PC300 TE boards.
- *
- * Revision 3.0.0.5 2000/12/12 ivan
- * Added support for Unframed E1.
- * Implemented monitor mode.
- * Fixed DCD sensitivity on the second channel.
- * Driver now complies with new PCI kernel architecture.
- *
- * Revision 3.0.0.4 2000/09/28 ivan
- * Implemented DCD sensitivity.
- * Moved hardware-specific open to the end of cpc_open, to avoid race
- * conditions with early reception interrupts.
- * Included code for [request|release]_mem_region().
- * Changed location of pc300.h .
- * Minor code revision (contrib. of Jeff Garzik).
- *
- * Revision 3.0.0.3 2000/07/03 ivan
- * Previous bugfix for the framing errors with external clock made X21
- * boards stop working. This version fixes it.
- *
- * Revision 3.0.0.2 2000/06/23 ivan
- * Revisited cpc_queue_xmit to prevent race conditions on Tx DMA buffer
- * handling when Tx timeouts occur.
- * Revisited Rx statistics.
- * Fixed a bug in the SCA-II programming that would cause framing errors
- * when external clock was configured.
- *
- * Revision 3.0.0.1 2000/05/26 ivan
- * Added logic in the SCA interrupt handler so that no board can monopolize
- * the driver.
- * Request PLX I/O region, although driver doesn't use it, to avoid
- * problems with other drivers accessing it.
- *
- * Revision 3.0.0.0 2000/05/15 ivan
- * Did some changes in the DMA programming implementation to avoid the
- * occurrence of a SCA-II bug in the second channel.
- * Implemented workaround for PLX9050 bug that would cause a system lockup
- * in certain systems, depending on the MMIO addresses allocated to the
- * board.
- * Fixed the FALC chip programming to avoid synchronization problems in the
- * second channel (TE only).
- * Implemented a cleaner and faster Tx DMA descriptor cleanup procedure in
- * cpc_queue_xmit().
- * Changed the built-in driver implementation so that the driver can use the
- * general 'hdlcN' naming convention instead of proprietary device names.
- * Driver load messages are now device-centric, instead of board-centric.
- * Dynamic allocation of net_device structures.
- * Code is now compliant with the new module interface (module_[init|exit]).
- * Make use of the PCI helper functions to access PCI resources.
- *
- * Revision 2.0.0.0 2000/04/15 ivan
- * Added support for the PC300/TE boards (T1/FT1/E1/FE1).
- *
- * Revision 1.1.0.0 2000/02/28 ivan
- * Major changes in the driver architecture.
- * Softnet compliancy implemented.
- * Driver now reports physical instead of virtual memory addresses.
- * Added cpc_change_mtu function.
- *
- * Revision 1.0.0.0 1999/12/16 ivan
- * First official release.
- * Support for 1- and 2-channel boards (which use distinct PCI Device ID's).
- * Support for monolythic installation (i.e., drv built into the kernel).
- * X.25 additional checking when lapb_[dis]connect_request returns an error.
- * SCA programming now covers X.21 as well.
- *
- * Revision 0.3.1.0 1999/11/18 ivan
- * Made X.25 support configuration-dependent (as it depends on external
- * modules to work).
- * Changed X.25-specific function names to comply with adopted convention.
- * Fixed typos in X.25 functions that would cause compile errors (Daniela).
- * Fixed bug in ch_config that would disable interrupts on a previously
- * enabled channel if the other channel on the same board was enabled later.
- *
- * Revision 0.3.0.0 1999/11/16 daniela
- * X.25 support.
- *
- * Revision 0.2.3.0 1999/11/15 ivan
- * Function cpc_ch_status now provides more detailed information.
- * Added support for X.21 clock configuration.
- * Changed TNR1 setting in order to prevent Tx FIFO overaccesses by the SCA.
- * Now using PCI clock instead of internal oscillator clock for the SCA.
- *
- * Revision 0.2.2.0 1999/11/10 ivan
- * Changed the *_dma_buf_check functions so that they would print only
- * the useful info instead of the whole buffer descriptor bank.
- * Fixed bug in cpc_queue_xmit that would eventually crash the system
- * in case of a packet drop.
- * Implemented TX underrun handling.
- * Improved SCA fine tuning to boost up its performance.
- *
- * Revision 0.2.1.0 1999/11/03 ivan
- * Added functions *dma_buf_pt_init to allow independent initialization
- * of the next-descr. and DMA buffer pointers on the DMA descriptors.
- * Kernel buffer release and tbusy clearing is now done in the interrupt
- * handler.
- * Fixed bug in cpc_open that would cause an interface reopen to fail.
- * Added a protocol-specific code section in cpc_net_rx.
- * Removed printk level defs (they might be added back after the beta phase).
- *
- * Revision 0.2.0.0 1999/10/28 ivan
- * Revisited the code so that new protocols can be easily added / supported.
- *
- * Revision 0.1.0.1 1999/10/20 ivan
- * Mostly "esthetic" changes.
- *
- * Revision 0.1.0.0 1999/10/11 ivan
- * Initial version.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/net.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/spinlock.h>
-#include <linux/if.h>
-#include <linux/slab.h>
-#include <net/arp.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "pc300.h"
-
-#define CPC_LOCK(card,flags) \
- do { \
- spin_lock_irqsave(&card->card_lock, flags); \
- } while (0)
-
-#define CPC_UNLOCK(card,flags) \
- do { \
- spin_unlock_irqrestore(&card->card_lock, flags); \
- } while (0)
-
-#undef PC300_DEBUG_PCI
-#undef PC300_DEBUG_INTR
-#undef PC300_DEBUG_TX
-#undef PC300_DEBUG_RX
-#undef PC300_DEBUG_OTHER
-
-static DEFINE_PCI_DEVICE_TABLE(cpc_pci_dev_id) = {
- /* PC300/RSV or PC300/X21, 2 chan */
- {0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300},
- /* PC300/RSV or PC300/X21, 1 chan */
- {0x120e, 0x301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x301},
- /* PC300/TE, 2 chan */
- {0x120e, 0x310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x310},
- /* PC300/TE, 1 chan */
- {0x120e, 0x311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x311},
- /* PC300/TE-M, 2 chan */
- {0x120e, 0x320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x320},
- /* PC300/TE-M, 1 chan */
- {0x120e, 0x321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x321},
- /* End of table */
- {0,},
-};
-MODULE_DEVICE_TABLE(pci, cpc_pci_dev_id);
-
-#ifndef cpc_min
-#define cpc_min(a,b) (((a)<(b))?(a):(b))
-#endif
-#ifndef cpc_max
-#define cpc_max(a,b) (((a)>(b))?(a):(b))
-#endif
-
-/* prototypes */
-static void tx_dma_buf_pt_init(pc300_t *, int);
-static void tx_dma_buf_init(pc300_t *, int);
-static void rx_dma_buf_pt_init(pc300_t *, int);
-static void rx_dma_buf_init(pc300_t *, int);
-static void tx_dma_buf_check(pc300_t *, int);
-static void rx_dma_buf_check(pc300_t *, int);
-static irqreturn_t cpc_intr(int, void *);
-static int clock_rate_calc(u32, u32, int *);
-static u32 detect_ram(pc300_t *);
-static void plx_init(pc300_t *);
-static void cpc_trace(struct net_device *, struct sk_buff *, char);
-static int cpc_attach(struct net_device *, unsigned short, unsigned short);
-static int cpc_close(struct net_device *dev);
-
-#ifdef CONFIG_PC300_MLPPP
-void cpc_tty_init(pc300dev_t * dev);
-void cpc_tty_unregister_service(pc300dev_t * pc300dev);
-void cpc_tty_receive(pc300dev_t * pc300dev);
-void cpc_tty_trigger_poll(pc300dev_t * pc300dev);
-#endif
-
-/************************/
-/*** DMA Routines ***/
-/************************/
-static void tx_dma_buf_pt_init(pc300_t * card, int ch)
-{
- int i;
- int ch_factor = ch * N_DMA_TX_BUF;
- volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase
- + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
-
- for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) {
- cpc_writel(&ptdescr->next, (u32)(DMA_TX_BD_BASE +
- (ch_factor + ((i + 1) & (N_DMA_TX_BUF - 1))) * sizeof(pcsca_bd_t)));
- cpc_writel(&ptdescr->ptbuf,
- (u32)(DMA_TX_BASE + (ch_factor + i) * BD_DEF_LEN));
- }
-}
-
-static void tx_dma_buf_init(pc300_t * card, int ch)
-{
- int i;
- int ch_factor = ch * N_DMA_TX_BUF;
- volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase
- + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
-
- for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) {
- memset_io(ptdescr, 0, sizeof(pcsca_bd_t));
- cpc_writew(&ptdescr->len, 0);
- cpc_writeb(&ptdescr->status, DST_OSB);
- }
- tx_dma_buf_pt_init(card, ch);
-}
-
-static void rx_dma_buf_pt_init(pc300_t * card, int ch)
-{
- int i;
- int ch_factor = ch * N_DMA_RX_BUF;
- volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase
- + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
-
- for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) {
- cpc_writel(&ptdescr->next, (u32)(DMA_RX_BD_BASE +
- (ch_factor + ((i + 1) & (N_DMA_RX_BUF - 1))) * sizeof(pcsca_bd_t)));
- cpc_writel(&ptdescr->ptbuf,
- (u32)(DMA_RX_BASE + (ch_factor + i) * BD_DEF_LEN));
- }
-}
-
-static void rx_dma_buf_init(pc300_t * card, int ch)
-{
- int i;
- int ch_factor = ch * N_DMA_RX_BUF;
- volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase
- + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
-
- for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) {
- memset_io(ptdescr, 0, sizeof(pcsca_bd_t));
- cpc_writew(&ptdescr->len, 0);
- cpc_writeb(&ptdescr->status, 0);
- }
- rx_dma_buf_pt_init(card, ch);
-}
-
-static void tx_dma_buf_check(pc300_t * card, int ch)
-{
- volatile pcsca_bd_t __iomem *ptdescr;
- int i;
- u16 first_bd = card->chan[ch].tx_first_bd;
- u16 next_bd = card->chan[ch].tx_next_bd;
-
- printk("#CH%d: f_bd = %d(0x%08zx), n_bd = %d(0x%08zx)\n", ch,
- first_bd, TX_BD_ADDR(ch, first_bd),
- next_bd, TX_BD_ADDR(ch, next_bd));
- for (i = first_bd,
- ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, first_bd));
- i != ((next_bd + 1) & (N_DMA_TX_BUF - 1));
- i = (i + 1) & (N_DMA_TX_BUF - 1),
- ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i))) {
- printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
- ch, i, cpc_readl(&ptdescr->next),
- cpc_readl(&ptdescr->ptbuf),
- cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
- }
- printk("\n");
-}
-
-#ifdef PC300_DEBUG_OTHER
-/* Show all TX buffer descriptors */
-static void tx1_dma_buf_check(pc300_t * card, int ch)
-{
- volatile pcsca_bd_t __iomem *ptdescr;
- int i;
- u16 first_bd = card->chan[ch].tx_first_bd;
- u16 next_bd = card->chan[ch].tx_next_bd;
- u32 scabase = card->hw.scabase;
-
- printk ("\nnfree_tx_bd = %d\n", card->chan[ch].nfree_tx_bd);
- printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch,
- first_bd, TX_BD_ADDR(ch, first_bd),
- next_bd, TX_BD_ADDR(ch, next_bd));
- printk("TX_CDA=0x%08x, TX_EDA=0x%08x\n",
- cpc_readl(scabase + DTX_REG(CDAL, ch)),
- cpc_readl(scabase + DTX_REG(EDAL, ch)));
- for (i = 0; i < N_DMA_TX_BUF; i++) {
- ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i));
- printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
- ch, i, cpc_readl(&ptdescr->next),
- cpc_readl(&ptdescr->ptbuf),
- cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len));
- }
- printk("\n");
-}
-#endif
-
-static void rx_dma_buf_check(pc300_t * card, int ch)
-{
- volatile pcsca_bd_t __iomem *ptdescr;
- int i;
- u16 first_bd = card->chan[ch].rx_first_bd;
- u16 last_bd = card->chan[ch].rx_last_bd;
- int ch_factor;
-
- ch_factor = ch * N_DMA_RX_BUF;
- printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd);
- for (i = 0, ptdescr = (card->hw.rambase +
- DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t));
- i < N_DMA_RX_BUF; i++, ptdescr++) {
- if (cpc_readb(&ptdescr->status) & DST_OSB)
- printk ("\n CH%d RX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d",
- ch, i, cpc_readl(&ptdescr->next),
- cpc_readl(&ptdescr->ptbuf),
- cpc_readb(&ptdescr->status),
- cpc_readw(&ptdescr->len));
- }
- printk("\n");
-}
-
-static int dma_get_rx_frame_size(pc300_t * card, int ch)
-{
- volatile pcsca_bd_t __iomem *ptdescr;
- u16 first_bd = card->chan[ch].rx_first_bd;
- int rcvd = 0;
- volatile u8 status;
-
- ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, first_bd));
- while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
- rcvd += cpc_readw(&ptdescr->len);
- first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);
- if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) {
- /* Return the size of a good frame or incomplete bad frame
- * (dma_buf_read will clean the buffer descriptors in this case). */
- return rcvd;
- }
- ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next));
- }
- return -1;
-}
-
-/*
- * dma_buf_write: writes a frame to the Tx DMA buffers
- * NOTE: this function writes one frame at a time.
- */
-static int dma_buf_write(pc300_t *card, int ch, u8 *ptdata, int len)
-{
- int i, nchar;
- volatile pcsca_bd_t __iomem *ptdescr;
- int tosend = len;
- u8 nbuf = ((len - 1) / BD_DEF_LEN) + 1;
-
- if (nbuf >= card->chan[ch].nfree_tx_bd) {
- return -ENOMEM;
- }
-
- for (i = 0; i < nbuf; i++) {
- ptdescr = (card->hw.rambase +
- TX_BD_ADDR(ch, card->chan[ch].tx_next_bd));
- nchar = cpc_min(BD_DEF_LEN, tosend);
- if (cpc_readb(&ptdescr->status) & DST_OSB) {
- memcpy_toio((card->hw.rambase + cpc_readl(&ptdescr->ptbuf)),
- &ptdata[len - tosend], nchar);
- cpc_writew(&ptdescr->len, nchar);
- card->chan[ch].nfree_tx_bd--;
- if ((i + 1) == nbuf) {
- /* This must be the last BD to be used */
- cpc_writeb(&ptdescr->status, DST_EOM);
- } else {
- cpc_writeb(&ptdescr->status, 0);
- }
- } else {
- return -ENOMEM;
- }
- tosend -= nchar;
- card->chan[ch].tx_next_bd =
- (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1);
- }
- /* If it gets to here, it means we have sent the whole frame */
- return 0;
-}
-
-/*
- * dma_buf_read: reads a frame from the Rx DMA buffers
- * NOTE: this function reads one frame at a time.
- */
-static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb)
-{
- int nchar;
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- volatile pcsca_bd_t __iomem *ptdescr;
- int rcvd = 0;
- volatile u8 status;
-
- ptdescr = (card->hw.rambase +
- RX_BD_ADDR(ch, chan->rx_first_bd));
- while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
- nchar = cpc_readw(&ptdescr->len);
- if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) ||
- (nchar > BD_DEF_LEN)) {
-
- if (nchar > BD_DEF_LEN)
- status |= DST_RBIT;
- rcvd = -status;
- /* Discard remaining descriptors used by the bad frame */
- while (chan->rx_first_bd != chan->rx_last_bd) {
- cpc_writeb(&ptdescr->status, 0);
- chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1);
- if (status & DST_EOM)
- break;
- ptdescr = (card->hw.rambase +
- cpc_readl(&ptdescr->next));
- status = cpc_readb(&ptdescr->status);
- }
- break;
- }
- if (nchar != 0) {
- if (skb) {
- memcpy_fromio(skb_put(skb, nchar),
- (card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar);
- }
- rcvd += nchar;
- }
- cpc_writeb(&ptdescr->status, 0);
- cpc_writeb(&ptdescr->len, 0);
- chan->rx_first_bd = (chan->rx_first_bd + 1) & (N_DMA_RX_BUF - 1);
-
- if (status & DST_EOM)
- break;
-
- ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next));
- }
-
- if (rcvd != 0) {
- /* Update pointer */
- chan->rx_last_bd = (chan->rx_first_bd - 1) & (N_DMA_RX_BUF - 1);
- /* Update EDA */
- cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch),
- RX_BD_ADDR(ch, chan->rx_last_bd));
- }
- return rcvd;
-}
-
-static void tx_dma_stop(pc300_t * card, int ch)
-{
- void __iomem *scabase = card->hw.scabase;
- u8 drr_ena_bit = 1 << (5 + 2 * ch);
- u8 drr_rst_bit = 1 << (1 + 2 * ch);
-
- /* Disable DMA */
- cpc_writeb(scabase + DRR, drr_ena_bit);
- cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
-}
-
-static void rx_dma_stop(pc300_t * card, int ch)
-{
- void __iomem *scabase = card->hw.scabase;
- u8 drr_ena_bit = 1 << (4 + 2 * ch);
- u8 drr_rst_bit = 1 << (2 * ch);
-
- /* Disable DMA */
- cpc_writeb(scabase + DRR, drr_ena_bit);
- cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit);
-}
-
-static void rx_dma_start(pc300_t * card, int ch)
-{
- void __iomem *scabase = card->hw.scabase;
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
-
- /* Start DMA */
- cpc_writel(scabase + DRX_REG(CDAL, ch),
- RX_BD_ADDR(ch, chan->rx_first_bd));
- if (cpc_readl(scabase + DRX_REG(CDAL,ch)) !=
- RX_BD_ADDR(ch, chan->rx_first_bd)) {
- cpc_writel(scabase + DRX_REG(CDAL, ch),
- RX_BD_ADDR(ch, chan->rx_first_bd));
- }
- cpc_writel(scabase + DRX_REG(EDAL, ch),
- RX_BD_ADDR(ch, chan->rx_last_bd));
- cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN);
- cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
- if (!(cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
- cpc_writeb(scabase + DSR_RX(ch), DSR_DE);
- }
-}
-
-/*************************/
-/*** FALC Routines ***/
-/*************************/
-static void falc_issue_cmd(pc300_t *card, int ch, u8 cmd)
-{
- void __iomem *falcbase = card->hw.falcbase;
- unsigned long i = 0;
-
- while (cpc_readb(falcbase + F_REG(SIS, ch)) & SIS_CEC) {
- if (i++ >= PC300_FALC_MAXLOOP) {
- printk("%s: FALC command locked(cmd=0x%x).\n",
- card->chan[ch].d.name, cmd);
- break;
- }
- }
- cpc_writeb(falcbase + F_REG(CMDR, ch), cmd);
-}
-
-static void falc_intr_enable(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- /* Interrupt pins are open-drain */
- cpc_writeb(falcbase + F_REG(IPC, ch),
- cpc_readb(falcbase + F_REG(IPC, ch)) & ~IPC_IC0);
- /* Conters updated each second */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_ECM);
- /* Enable SEC and ES interrupts */
- cpc_writeb(falcbase + F_REG(IMR3, ch),
- cpc_readb(falcbase + F_REG(IMR3, ch)) & ~(IMR3_SEC | IMR3_ES));
- if (conf->fr_mode == PC300_FR_UNFRAMED) {
- cpc_writeb(falcbase + F_REG(IMR4, ch),
- cpc_readb(falcbase + F_REG(IMR4, ch)) & ~(IMR4_LOS));
- } else {
- cpc_writeb(falcbase + F_REG(IMR4, ch),
- cpc_readb(falcbase + F_REG(IMR4, ch)) &
- ~(IMR4_LFA | IMR4_AIS | IMR4_LOS | IMR4_SLIP));
- }
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(IMR3, ch),
- cpc_readb(falcbase + F_REG(IMR3, ch)) & ~IMR3_LLBSC);
- } else {
- cpc_writeb(falcbase + F_REG(IPC, ch),
- cpc_readb(falcbase + F_REG(IPC, ch)) | IPC_SCI);
- if (conf->fr_mode == PC300_FR_UNFRAMED) {
- cpc_writeb(falcbase + F_REG(IMR2, ch),
- cpc_readb(falcbase + F_REG(IMR2, ch)) & ~(IMR2_LOS));
- } else {
- cpc_writeb(falcbase + F_REG(IMR2, ch),
- cpc_readb(falcbase + F_REG(IMR2, ch)) &
- ~(IMR2_FAR | IMR2_LFA | IMR2_AIS | IMR2_LOS));
- if (pfalc->multiframe_mode) {
- cpc_writeb(falcbase + F_REG(IMR2, ch),
- cpc_readb(falcbase + F_REG(IMR2, ch)) &
- ~(IMR2_T400MS | IMR2_MFAR));
- } else {
- cpc_writeb(falcbase + F_REG(IMR2, ch),
- cpc_readb(falcbase + F_REG(IMR2, ch)) |
- IMR2_T400MS | IMR2_MFAR);
- }
- }
- }
-}
-
-static void falc_open_timeslot(pc300_t * card, int ch, int timeslot)
-{
- void __iomem *falcbase = card->hw.falcbase;
- u8 tshf = card->chan[ch].falc.offset;
-
- cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch),
- cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) &
- ~(0x80 >> ((timeslot - tshf) & 0x07)));
- cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch),
- cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) |
- (0x80 >> (timeslot & 0x07)));
- cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch),
- cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) |
- (0x80 >> (timeslot & 0x07)));
-}
-
-static void falc_close_timeslot(pc300_t * card, int ch, int timeslot)
-{
- void __iomem *falcbase = card->hw.falcbase;
- u8 tshf = card->chan[ch].falc.offset;
-
- cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch),
- cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) |
- (0x80 >> ((timeslot - tshf) & 0x07)));
- cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch),
- cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) &
- ~(0x80 >> (timeslot & 0x07)));
- cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch),
- cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) &
- ~(0x80 >> (timeslot & 0x07)));
-}
-
-static void falc_close_all_timeslots(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- void __iomem *falcbase = card->hw.falcbase;
-
- cpc_writeb(falcbase + F_REG(ICB1, ch), 0xff);
- cpc_writeb(falcbase + F_REG(TTR1, ch), 0);
- cpc_writeb(falcbase + F_REG(RTR1, ch), 0);
- cpc_writeb(falcbase + F_REG(ICB2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(TTR2, ch), 0);
- cpc_writeb(falcbase + F_REG(RTR2, ch), 0);
- cpc_writeb(falcbase + F_REG(ICB3, ch), 0xff);
- cpc_writeb(falcbase + F_REG(TTR3, ch), 0);
- cpc_writeb(falcbase + F_REG(RTR3, ch), 0);
- if (conf->media == IF_IFACE_E1) {
- cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff);
- cpc_writeb(falcbase + F_REG(TTR4, ch), 0);
- cpc_writeb(falcbase + F_REG(RTR4, ch), 0);
- }
-}
-
-static void falc_open_all_timeslots(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- void __iomem *falcbase = card->hw.falcbase;
-
- cpc_writeb(falcbase + F_REG(ICB1, ch), 0);
- if (conf->fr_mode == PC300_FR_UNFRAMED) {
- cpc_writeb(falcbase + F_REG(TTR1, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RTR1, ch), 0xff);
- } else {
- /* Timeslot 0 is never enabled */
- cpc_writeb(falcbase + F_REG(TTR1, ch), 0x7f);
- cpc_writeb(falcbase + F_REG(RTR1, ch), 0x7f);
- }
- cpc_writeb(falcbase + F_REG(ICB2, ch), 0);
- cpc_writeb(falcbase + F_REG(TTR2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RTR2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(ICB3, ch), 0);
- cpc_writeb(falcbase + F_REG(TTR3, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RTR3, ch), 0xff);
- if (conf->media == IF_IFACE_E1) {
- cpc_writeb(falcbase + F_REG(ICB4, ch), 0);
- cpc_writeb(falcbase + F_REG(TTR4, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RTR4, ch), 0xff);
- } else {
- cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff);
- cpc_writeb(falcbase + F_REG(TTR4, ch), 0x80);
- cpc_writeb(falcbase + F_REG(RTR4, ch), 0x80);
- }
-}
-
-static void falc_init_timeslot(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- int tslot;
-
- for (tslot = 0; tslot < pfalc->num_channels; tslot++) {
- if (conf->tslot_bitmap & (1 << tslot)) {
- // Channel enabled
- falc_open_timeslot(card, ch, tslot + 1);
- } else {
- // Channel disabled
- falc_close_timeslot(card, ch, tslot + 1);
- }
- }
-}
-
-static void falc_enable_comm(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
-
- if (pfalc->full_bandwidth) {
- falc_open_all_timeslots(card, ch);
- } else {
- falc_init_timeslot(card, ch);
- }
- // CTS/DCD ON
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
- ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
-}
-
-static void falc_disable_comm(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
-
- if (pfalc->loop_active != 2) {
- falc_close_all_timeslots(card, ch);
- }
- // CTS/DCD OFF
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
- ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch)));
-}
-
-static void falc_init_t1(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u8 dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0);
-
- /* Switch to T1 mode (PCM 24) */
- cpc_writeb(falcbase + F_REG(FMR1, ch), FMR1_PMOD);
-
- /* Wait 20 us for setup */
- udelay(20);
-
- /* Transmit Buffer Size (1 frame) */
- cpc_writeb(falcbase + F_REG(SIC1, ch), SIC1_XBS0);
-
- /* Clock mode */
- if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS);
- } else { /* Slave mode */
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS);
- cpc_writeb(falcbase + F_REG(LOOP, ch),
- cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_RTM);
- }
-
- cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI);
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) &
- ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1));
-
- switch (conf->lcode) {
- case PC300_LC_AMI:
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) |
- FMR0_XC1 | FMR0_RC1);
- /* Clear Channel register to ON for all channels */
- cpc_writeb(falcbase + F_REG(CCB1, ch), 0xff);
- cpc_writeb(falcbase + F_REG(CCB2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(CCB3, ch), 0xff);
- break;
-
- case PC300_LC_B8ZS:
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) |
- FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1);
- break;
-
- case PC300_LC_NRZ:
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) | 0x00);
- break;
- }
-
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_ELOS);
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0));
- /* Set interface mode to 2 MBPS */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD);
-
- switch (conf->fr_mode) {
- case PC300_FR_ESF:
- pfalc->multiframe_mode = 0;
- cpc_writeb(falcbase + F_REG(FMR4, ch),
- cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_FM1);
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) |
- FMR1_CRC | FMR1_EDL);
- cpc_writeb(falcbase + F_REG(XDL1, ch), 0);
- cpc_writeb(falcbase + F_REG(XDL2, ch), 0);
- cpc_writeb(falcbase + F_REG(XDL3, ch), 0);
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) & ~FMR0_SRAF);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2,ch)) | FMR2_MCSP | FMR2_SSP);
- break;
-
- case PC300_FR_D4:
- pfalc->multiframe_mode = 1;
- cpc_writeb(falcbase + F_REG(FMR4, ch),
- cpc_readb(falcbase + F_REG(FMR4, ch)) &
- ~(FMR4_FM1 | FMR4_FM0));
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) | FMR0_SRAF);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_SSP);
- break;
- }
-
- /* Enable Automatic Resynchronization */
- cpc_writeb(falcbase + F_REG(FMR4, ch),
- cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_AUTO);
-
- /* Transmit Automatic Remote Alarm */
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
-
- /* Channel translation mode 1 : one to one */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_CTM);
-
- /* No signaling */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_SIGM);
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) &
- ~(FMR5_EIBR | FMR5_SRS));
- cpc_writeb(falcbase + F_REG(CCR1, ch), 0);
-
- cpc_writeb(falcbase + F_REG(LIM1, ch),
- cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RIL0 | LIM1_RIL1);
-
- switch (conf->lbo) {
- /* Provides proper Line Build Out */
- case PC300_LBO_0_DB:
- cpc_writeb(falcbase + F_REG(LIM2, ch), (LIM2_LOS1 | dja));
- cpc_writeb(falcbase + F_REG(XPM0, ch), 0x5a);
- cpc_writeb(falcbase + F_REG(XPM1, ch), 0x8f);
- cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
- break;
- case PC300_LBO_7_5_DB:
- cpc_writeb(falcbase + F_REG(LIM2, ch), (0x40 | LIM2_LOS1 | dja));
- cpc_writeb(falcbase + F_REG(XPM0, ch), 0x11);
- cpc_writeb(falcbase + F_REG(XPM1, ch), 0x02);
- cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
- break;
- case PC300_LBO_15_DB:
- cpc_writeb(falcbase + F_REG(LIM2, ch), (0x80 | LIM2_LOS1 | dja));
- cpc_writeb(falcbase + F_REG(XPM0, ch), 0x8e);
- cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01);
- cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
- break;
- case PC300_LBO_22_5_DB:
- cpc_writeb(falcbase + F_REG(LIM2, ch), (0xc0 | LIM2_LOS1 | dja));
- cpc_writeb(falcbase + F_REG(XPM0, ch), 0x09);
- cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01);
- cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20);
- break;
- }
-
- /* Transmit Clock-Slot Offset */
- cpc_writeb(falcbase + F_REG(XC0, ch),
- cpc_readb(falcbase + F_REG(XC0, ch)) | 0x01);
- /* Transmit Time-slot Offset */
- cpc_writeb(falcbase + F_REG(XC1, ch), 0x3e);
- /* Receive Clock-Slot offset */
- cpc_writeb(falcbase + F_REG(RC0, ch), 0x05);
- /* Receive Time-slot offset */
- cpc_writeb(falcbase + F_REG(RC1, ch), 0x00);
-
- /* LOS Detection after 176 consecutive 0s */
- cpc_writeb(falcbase + F_REG(PCDR, ch), 0x0a);
- /* LOS Recovery after 22 ones in the time window of PCD */
- cpc_writeb(falcbase + F_REG(PCRR, ch), 0x15);
-
- cpc_writeb(falcbase + F_REG(IDLE, ch), 0x7f);
-
- if (conf->fr_mode == PC300_FR_ESF_JAPAN) {
- cpc_writeb(falcbase + F_REG(RC1, ch),
- cpc_readb(falcbase + F_REG(RC1, ch)) | 0x80);
- }
-
- falc_close_all_timeslots(card, ch);
-}
-
-static void falc_init_e1(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u8 dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0);
-
- /* Switch to E1 mode (PCM 30) */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_PMOD);
-
- /* Clock mode */
- if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS);
- } else { /* Slave mode */
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS);
- }
- cpc_writeb(falcbase + F_REG(LOOP, ch),
- cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_SFM);
-
- cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI);
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) &
- ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1));
-
- switch (conf->lcode) {
- case PC300_LC_AMI:
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) |
- FMR0_XC1 | FMR0_RC1);
- break;
-
- case PC300_LC_HDB3:
- cpc_writeb(falcbase + F_REG(FMR0, ch),
- cpc_readb(falcbase + F_REG(FMR0, ch)) |
- FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1);
- break;
-
- case PC300_LC_NRZ:
- break;
- }
-
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0));
- /* Set interface mode to 2 MBPS */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD);
-
- cpc_writeb(falcbase + F_REG(XPM0, ch), 0x18);
- cpc_writeb(falcbase + F_REG(XPM1, ch), 0x03);
- cpc_writeb(falcbase + F_REG(XPM2, ch), 0x00);
-
- switch (conf->fr_mode) {
- case PC300_FR_MF_CRC4:
- pfalc->multiframe_mode = 1;
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_XFS);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_RFS1);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_RFS0);
- cpc_writeb(falcbase + F_REG(FMR3, ch),
- cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_EXTIW);
-
- /* MultiFrame Resynchronization */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_MFCS);
-
- /* Automatic Loss of Multiframe > 914 CRC errors */
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_ALMF);
-
- /* S1 and SI1/SI2 spare Bits set to 1 */
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) & ~XSP_AXS);
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_EBP);
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_XS13 | XSP_XS15);
-
- /* Automatic Force Resynchronization */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_AFR);
-
- /* Transmit Automatic Remote Alarm */
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
-
- /* Transmit Spare Bits for National Use (Y, Sn, Sa) */
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) |
- XSW_XY0 | XSW_XY1 | XSW_XY2 | XSW_XY3 | XSW_XY4);
- break;
-
- case PC300_FR_MF_NON_CRC4:
- case PC300_FR_D4:
- pfalc->multiframe_mode = 0;
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_XFS);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) &
- ~(FMR2_RFS1 | FMR2_RFS0));
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) | XSW_XSIS);
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_XSIF);
-
- /* Automatic Force Resynchronization */
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_AFR);
-
- /* Transmit Automatic Remote Alarm */
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA);
-
- /* Transmit Spare Bits for National Use (Y, Sn, Sa) */
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) |
- XSW_XY0 | XSW_XY1 | XSW_XY2 | XSW_XY3 | XSW_XY4);
- break;
-
- case PC300_FR_UNFRAMED:
- pfalc->multiframe_mode = 0;
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_XFS);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) &
- ~(FMR2_RFS1 | FMR2_RFS0));
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) | XSP_TT0);
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) &
- ~(XSW_XTM|XSW_XY0|XSW_XY1|XSW_XY2|XSW_XY3|XSW_XY4));
- cpc_writeb(falcbase + F_REG(TSWM, ch), 0xff);
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) |
- (FMR2_RTM | FMR2_DAIS));
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_AXRA);
- cpc_writeb(falcbase + F_REG(FMR1, ch),
- cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_AFR);
- pfalc->sync = 1;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) |
- (CPLD_REG2_FALC_LED2 << (2 * ch)));
- break;
- }
-
- /* No signaling */
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch)) & ~XSP_CASEN);
- cpc_writeb(falcbase + F_REG(CCR1, ch), 0);
-
- cpc_writeb(falcbase + F_REG(LIM1, ch),
- cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RIL0 | LIM1_RIL1);
- cpc_writeb(falcbase + F_REG(LIM2, ch), (LIM2_LOS1 | dja));
-
- /* Transmit Clock-Slot Offset */
- cpc_writeb(falcbase + F_REG(XC0, ch),
- cpc_readb(falcbase + F_REG(XC0, ch)) | 0x01);
- /* Transmit Time-slot Offset */
- cpc_writeb(falcbase + F_REG(XC1, ch), 0x3e);
- /* Receive Clock-Slot offset */
- cpc_writeb(falcbase + F_REG(RC0, ch), 0x05);
- /* Receive Time-slot offset */
- cpc_writeb(falcbase + F_REG(RC1, ch), 0x00);
-
- /* LOS Detection after 176 consecutive 0s */
- cpc_writeb(falcbase + F_REG(PCDR, ch), 0x0a);
- /* LOS Recovery after 22 ones in the time window of PCD */
- cpc_writeb(falcbase + F_REG(PCRR, ch), 0x15);
-
- cpc_writeb(falcbase + F_REG(IDLE, ch), 0x7f);
-
- falc_close_all_timeslots(card, ch);
-}
-
-static void falc_init_hdlc(pc300_t * card, int ch)
-{
- void __iomem *falcbase = card->hw.falcbase;
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
-
- /* Enable transparent data transfer */
- if (conf->fr_mode == PC300_FR_UNFRAMED) {
- cpc_writeb(falcbase + F_REG(MODE, ch), 0);
- } else {
- cpc_writeb(falcbase + F_REG(MODE, ch),
- cpc_readb(falcbase + F_REG(MODE, ch)) |
- (MODE_HRAC | MODE_MDS2));
- cpc_writeb(falcbase + F_REG(RAH2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RAH1, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RAL2, ch), 0xff);
- cpc_writeb(falcbase + F_REG(RAL1, ch), 0xff);
- }
-
- /* Tx/Rx reset */
- falc_issue_cmd(card, ch, CMDR_RRES | CMDR_XRES | CMDR_SRES);
-
- /* Enable interrupt sources */
- falc_intr_enable(card, ch);
-}
-
-static void te_config(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u8 dummy;
- unsigned long flags;
-
- memset(pfalc, 0, sizeof(falc_t));
- switch (conf->media) {
- case IF_IFACE_T1:
- pfalc->num_channels = NUM_OF_T1_CHANNELS;
- pfalc->offset = 1;
- break;
- case IF_IFACE_E1:
- pfalc->num_channels = NUM_OF_E1_CHANNELS;
- pfalc->offset = 0;
- break;
- }
- if (conf->tslot_bitmap == 0xffffffffUL)
- pfalc->full_bandwidth = 1;
- else
- pfalc->full_bandwidth = 0;
-
- CPC_LOCK(card, flags);
- /* Reset the FALC chip */
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
- (CPLD_REG1_FALC_RESET << (2 * ch)));
- udelay(10000);
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
- ~(CPLD_REG1_FALC_RESET << (2 * ch)));
-
- if (conf->media == IF_IFACE_T1) {
- falc_init_t1(card, ch);
- } else {
- falc_init_e1(card, ch);
- }
- falc_init_hdlc(card, ch);
- if (conf->rx_sens == PC300_RX_SENS_SH) {
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_EQON);
- } else {
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_EQON);
- }
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
- ((CPLD_REG2_FALC_TX_CLK | CPLD_REG2_FALC_RX_CLK) << (2 * ch)));
-
- /* Clear all interrupt registers */
- dummy = cpc_readb(falcbase + F_REG(FISR0, ch)) +
- cpc_readb(falcbase + F_REG(FISR1, ch)) +
- cpc_readb(falcbase + F_REG(FISR2, ch)) +
- cpc_readb(falcbase + F_REG(FISR3, ch));
- CPC_UNLOCK(card, flags);
-}
-
-static void falc_check_status(pc300_t * card, int ch, unsigned char frs0)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- /* Verify LOS */
- if (frs0 & FRS0_LOS) {
- if (!pfalc->red_alarm) {
- pfalc->red_alarm = 1;
- pfalc->los++;
- if (!pfalc->blue_alarm) {
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise interfere
- * with other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch))
- | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- }
- }
- } else {
- if (pfalc->red_alarm) {
- pfalc->red_alarm = 0;
- pfalc->losr++;
- }
- }
-
- if (conf->fr_mode != PC300_FR_UNFRAMED) {
- /* Verify AIS alarm */
- if (frs0 & FRS0_AIS) {
- if (!pfalc->blue_alarm) {
- pfalc->blue_alarm = 1;
- pfalc->ais++;
- // EVENT_AIS
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise interfere with other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_AIS
- }
- } else {
- pfalc->blue_alarm = 0;
- }
-
- /* Verify LFA */
- if (frs0 & FRS0_LFA) {
- if (!pfalc->loss_fa) {
- pfalc->loss_fa = 1;
- pfalc->lfa++;
- if (!pfalc->blue_alarm && !pfalc->red_alarm) {
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise
- * interfere with other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch))
- | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- }
- }
- } else {
- if (pfalc->loss_fa) {
- pfalc->loss_fa = 0;
- pfalc->farec++;
- }
- }
-
- /* Verify LMFA */
- if (pfalc->multiframe_mode && (frs0 & FRS0_LMFA)) {
- /* D4 or CRC4 frame mode */
- if (!pfalc->loss_mfa) {
- pfalc->loss_mfa = 1;
- pfalc->lmfa++;
- if (!pfalc->blue_alarm && !pfalc->red_alarm &&
- !pfalc->loss_fa) {
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise
- * interfere with other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch))
- | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- }
- }
- } else {
- pfalc->loss_mfa = 0;
- }
-
- /* Verify Remote Alarm */
- if (frs0 & FRS0_RRA) {
- if (!pfalc->yellow_alarm) {
- pfalc->yellow_alarm = 1;
- pfalc->rai++;
- if (pfalc->sync) {
- // EVENT_RAI
- falc_disable_comm(card, ch);
- // EVENT_RAI
- }
- }
- } else {
- pfalc->yellow_alarm = 0;
- }
- } /* if !PC300_UNFRAMED */
-
- if (pfalc->red_alarm || pfalc->loss_fa ||
- pfalc->loss_mfa || pfalc->blue_alarm) {
- if (pfalc->sync) {
- pfalc->sync = 0;
- chan->d.line_off++;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
- }
- } else {
- if (!pfalc->sync) {
- pfalc->sync = 1;
- chan->d.line_on++;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) |
- (CPLD_REG2_FALC_LED2 << (2 * ch)));
- }
- }
-
- if (pfalc->sync && !pfalc->yellow_alarm) {
- if (!pfalc->active) {
- // EVENT_FALC_NORMAL
- if (pfalc->loop_active) {
- return;
- }
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch)) & ~IMR0_PDEN);
- }
- falc_enable_comm(card, ch);
- // EVENT_FALC_NORMAL
- pfalc->active = 1;
- }
- } else {
- if (pfalc->active) {
- pfalc->active = 0;
- }
- }
-}
-
-static void falc_update_stats(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u16 counter;
-
- counter = cpc_readb(falcbase + F_REG(FECL, ch));
- counter |= cpc_readb(falcbase + F_REG(FECH, ch)) << 8;
- pfalc->fec += counter;
-
- counter = cpc_readb(falcbase + F_REG(CVCL, ch));
- counter |= cpc_readb(falcbase + F_REG(CVCH, ch)) << 8;
- pfalc->cvc += counter;
-
- counter = cpc_readb(falcbase + F_REG(CECL, ch));
- counter |= cpc_readb(falcbase + F_REG(CECH, ch)) << 8;
- pfalc->cec += counter;
-
- counter = cpc_readb(falcbase + F_REG(EBCL, ch));
- counter |= cpc_readb(falcbase + F_REG(EBCH, ch)) << 8;
- pfalc->ebc += counter;
-
- if (cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) {
- mdelay(10);
- counter = cpc_readb(falcbase + F_REG(BECL, ch));
- counter |= cpc_readb(falcbase + F_REG(BECH, ch)) << 8;
- pfalc->bec += counter;
-
- if (((conf->media == IF_IFACE_T1) &&
- (cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_LLBAD) &&
- (!(cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_PDEN))) ||
- ((conf->media == IF_IFACE_E1) &&
- (cpc_readb(falcbase + F_REG(RSP, ch)) & RSP_LLBAD))) {
- pfalc->prbs = 2;
- } else {
- pfalc->prbs = 1;
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * falc_remote_loop
- *----------------------------------------------------------------------------
- * Description: In the remote loopback mode the clock and data recovered
- * from the line inputs RL1/2 or RDIP/RDIN are routed back
- * to the line outputs XL1/2 or XDOP/XDON via the analog
- * transmitter. As in normal mode they are processed by
- * the synchronizer and then sent to the system interface.
- *----------------------------------------------------------------------------
- */
-static void falc_remote_loop(pc300_t * card, int ch, int loop_on)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (loop_on) {
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise interfere with
- * other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- cpc_writeb(falcbase + F_REG(LIM1, ch),
- cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RL);
- pfalc->loop_active = 1;
- } else {
- cpc_writeb(falcbase + F_REG(LIM1, ch),
- cpc_readb(falcbase + F_REG(LIM1, ch)) & ~LIM1_RL);
- pfalc->sync = 0;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
- pfalc->active = 0;
- falc_issue_cmd(card, ch, CMDR_XRES);
- pfalc->loop_active = 0;
- }
-}
-
-/*----------------------------------------------------------------------------
- * falc_local_loop
- *----------------------------------------------------------------------------
- * Description: The local loopback mode disconnects the receive lines
- * RL1/RL2 resp. RDIP/RDIN from the receiver. Instead of the
- * signals coming from the line the data provided by system
- * interface are routed through the analog receiver back to
- * the system interface. The unipolar bit stream will be
- * undisturbed transmitted on the line. Receiver and transmitter
- * coding must be identical.
- *----------------------------------------------------------------------------
- */
-static void falc_local_loop(pc300_t * card, int ch, int loop_on)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (loop_on) {
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_LL);
- pfalc->loop_active = 1;
- } else {
- cpc_writeb(falcbase + F_REG(LIM0, ch),
- cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_LL);
- pfalc->loop_active = 0;
- }
-}
-
-/*----------------------------------------------------------------------------
- * falc_payload_loop
- *----------------------------------------------------------------------------
- * Description: This routine allows to enable/disable payload loopback.
- * When the payload loop is activated, the received 192 bits
- * of payload data will be looped back to the transmit
- * direction. The framing bits, CRC6 and DL bits are not
- * looped. They are originated by the FALC-LH transmitter.
- *----------------------------------------------------------------------------
- */
-static void falc_payload_loop(pc300_t * card, int ch, int loop_on)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (loop_on) {
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise interfere with
- * other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_PLB);
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR4, ch),
- cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_TM);
- } else {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) | XSP_TT0);
- }
- falc_open_all_timeslots(card, ch);
- pfalc->loop_active = 2;
- } else {
- cpc_writeb(falcbase + F_REG(FMR2, ch),
- cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_PLB);
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR4, ch),
- cpc_readb(falcbase + F_REG(FMR4, ch)) & ~FMR4_TM);
- } else {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) & ~XSP_TT0);
- }
- pfalc->sync = 0;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
- pfalc->active = 0;
- falc_issue_cmd(card, ch, CMDR_XRES);
- pfalc->loop_active = 0;
- }
-}
-
-/*----------------------------------------------------------------------------
- * turn_off_xlu
- *----------------------------------------------------------------------------
- * Description: Turns XLU bit off in the proper register
- *----------------------------------------------------------------------------
- */
-static void turn_off_xlu(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) & ~FMR5_XLU);
- } else {
- cpc_writeb(falcbase + F_REG(FMR3, ch),
- cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_XLU);
- }
-}
-
-/*----------------------------------------------------------------------------
- * turn_off_xld
- *----------------------------------------------------------------------------
- * Description: Turns XLD bit off in the proper register
- *----------------------------------------------------------------------------
- */
-static void turn_off_xld(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) & ~FMR5_XLD);
- } else {
- cpc_writeb(falcbase + F_REG(FMR3, ch),
- cpc_readb(falcbase + F_REG(FMR3, ch)) & ~FMR3_XLD);
- }
-}
-
-/*----------------------------------------------------------------------------
- * falc_generate_loop_up_code
- *----------------------------------------------------------------------------
- * Description: This routine writes the proper FALC chip register in order
- * to generate a LOOP activation code over a T1/E1 line.
- *----------------------------------------------------------------------------
- */
-static void falc_generate_loop_up_code(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) | FMR5_XLU);
- } else {
- cpc_writeb(falcbase + F_REG(FMR3, ch),
- cpc_readb(falcbase + F_REG(FMR3, ch)) | FMR3_XLU);
- }
- // EVENT_FALC_ABNORMAL
- if (conf->media == IF_IFACE_T1) {
- /* Disable this interrupt as it may otherwise interfere with
- * other working boards. */
- cpc_writeb(falcbase + F_REG(IMR0, ch),
- cpc_readb(falcbase + F_REG(IMR0, ch)) | IMR0_PDEN);
- }
- falc_disable_comm(card, ch);
- // EVENT_FALC_ABNORMAL
- pfalc->loop_gen = 1;
-}
-
-/*----------------------------------------------------------------------------
- * falc_generate_loop_down_code
- *----------------------------------------------------------------------------
- * Description: This routine writes the proper FALC chip register in order
- * to generate a LOOP deactivation code over a T1/E1 line.
- *----------------------------------------------------------------------------
- */
-static void falc_generate_loop_down_code(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (conf->media == IF_IFACE_T1) {
- cpc_writeb(falcbase + F_REG(FMR5, ch),
- cpc_readb(falcbase + F_REG(FMR5, ch)) | FMR5_XLD);
- } else {
- cpc_writeb(falcbase + F_REG(FMR3, ch),
- cpc_readb(falcbase + F_REG(FMR3, ch)) | FMR3_XLD);
- }
- pfalc->sync = 0;
- cpc_writeb(falcbase + card->hw.cpld_reg2,
- cpc_readb(falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED2 << (2 * ch)));
- pfalc->active = 0;
-//? falc_issue_cmd(card, ch, CMDR_XRES);
- pfalc->loop_gen = 0;
-}
-
-/*----------------------------------------------------------------------------
- * falc_pattern_test
- *----------------------------------------------------------------------------
- * Description: This routine generates a pattern code and checks
- * it on the reception side.
- *----------------------------------------------------------------------------
- */
-static void falc_pattern_test(pc300_t * card, int ch, unsigned int activate)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (activate) {
- pfalc->prbs = 1;
- pfalc->bec = 0;
- if (conf->media == IF_IFACE_T1) {
- /* Disable local loop activation/deactivation detect */
- cpc_writeb(falcbase + F_REG(IMR3, ch),
- cpc_readb(falcbase + F_REG(IMR3, ch)) | IMR3_LLBSC);
- } else {
- /* Disable local loop activation/deactivation detect */
- cpc_writeb(falcbase + F_REG(IMR1, ch),
- cpc_readb(falcbase + F_REG(IMR1, ch)) | IMR1_LLBSC);
- }
- /* Activates generation and monitoring of PRBS
- * (Pseudo Random Bit Sequence) */
- cpc_writeb(falcbase + F_REG(LCR1, ch),
- cpc_readb(falcbase + F_REG(LCR1, ch)) | LCR1_EPRM | LCR1_XPRBS);
- } else {
- pfalc->prbs = 0;
- /* Deactivates generation and monitoring of PRBS
- * (Pseudo Random Bit Sequence) */
- cpc_writeb(falcbase + F_REG(LCR1, ch),
- cpc_readb(falcbase+F_REG(LCR1,ch)) & ~(LCR1_EPRM | LCR1_XPRBS));
- if (conf->media == IF_IFACE_T1) {
- /* Enable local loop activation/deactivation detect */
- cpc_writeb(falcbase + F_REG(IMR3, ch),
- cpc_readb(falcbase + F_REG(IMR3, ch)) & ~IMR3_LLBSC);
- } else {
- /* Enable local loop activation/deactivation detect */
- cpc_writeb(falcbase + F_REG(IMR1, ch),
- cpc_readb(falcbase + F_REG(IMR1, ch)) & ~IMR1_LLBSC);
- }
- }
-}
-
-/*----------------------------------------------------------------------------
- * falc_pattern_test_error
- *----------------------------------------------------------------------------
- * Description: This routine returns the bit error counter value
- *----------------------------------------------------------------------------
- */
-static u16 falc_pattern_test_error(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
-
- return pfalc->bec;
-}
-
-/**********************************/
-/*** Net Interface Routines ***/
-/**********************************/
-
-static void
-cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx)
-{
- struct sk_buff *skb;
-
- if ((skb = dev_alloc_skb(10 + skb_main->len)) == NULL) {
- printk("%s: out of memory\n", dev->name);
- return;
- }
- skb_put(skb, 10 + skb_main->len);
-
- skb->dev = dev;
- skb->protocol = htons(ETH_P_CUST);
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_HOST;
- skb->len = 10 + skb_main->len;
-
- skb_copy_to_linear_data(skb, dev->name, 5);
- skb->data[5] = '[';
- skb->data[6] = rx_tx;
- skb->data[7] = ']';
- skb->data[8] = ':';
- skb->data[9] = ' ';
- skb_copy_from_linear_data(skb_main, &skb->data[10], skb_main->len);
-
- netif_rx(skb);
-}
-
-static void cpc_tx_timeout(struct net_device *dev)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- int ch = chan->channel;
- unsigned long flags;
- u8 ilar;
-
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
- CPC_LOCK(card, flags);
- if ((ilar = cpc_readb(card->hw.scabase + ILAR)) != 0) {
- printk("%s: ILAR=0x%x\n", dev->name, ilar);
- cpc_writeb(card->hw.scabase + ILAR, ilar);
- cpc_writeb(card->hw.scabase + DMER, 0x80);
- }
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- dev->trans_start = jiffies; /* prevent tx timeout */
- CPC_UNLOCK(card, flags);
- netif_wake_queue(dev);
-}
-
-static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- int ch = chan->channel;
- unsigned long flags;
-#ifdef PC300_DEBUG_TX
- int i;
-#endif
-
- if (!netif_carrier_ok(dev)) {
- /* DCD must be OFF: drop packet */
- dev_kfree_skb(skb);
- dev->stats.tx_errors++;
- dev->stats.tx_carrier_errors++;
- return 0;
- } else if (cpc_readb(card->hw.scabase + M_REG(ST3, ch)) & ST3_DCD) {
- printk("%s: DCD is OFF. Going administrative down.\n", dev->name);
- dev->stats.tx_errors++;
- dev->stats.tx_carrier_errors++;
- dev_kfree_skb(skb);
- netif_carrier_off(dev);
- CPC_LOCK(card, flags);
- cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR);
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- CPC_UNLOCK(card, flags);
- netif_wake_queue(dev);
- return 0;
- }
-
- /* Write buffer to DMA buffers */
- if (dma_buf_write(card, ch, (u8 *)skb->data, skb->len) != 0) {
-// printk("%s: write error. Dropping TX packet.\n", dev->name);
- netif_stop_queue(dev);
- dev_kfree_skb(skb);
- dev->stats.tx_errors++;
- dev->stats.tx_dropped++;
- return 0;
- }
-#ifdef PC300_DEBUG_TX
- printk("%s T:", dev->name);
- for (i = 0; i < skb->len; i++)
- printk(" %02x", *(skb->data + i));
- printk("\n");
-#endif
-
- if (d->trace_on) {
- cpc_trace(dev, skb, 'T');
- }
-
- /* Start transmission */
- CPC_LOCK(card, flags);
- /* verify if it has more than one free descriptor */
- if (card->chan[ch].nfree_tx_bd <= 1) {
- /* don't have so stop the queue */
- netif_stop_queue(dev);
- }
- cpc_writel(card->hw.scabase + DTX_REG(EDAL, ch),
- TX_BD_ADDR(ch, chan->tx_next_bd));
- cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA);
- cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE);
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
- (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- CPC_UNLOCK(card, flags);
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-static void cpc_net_rx(struct net_device *dev)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- int ch = chan->channel;
-#ifdef PC300_DEBUG_RX
- int i;
-#endif
- int rxb;
- struct sk_buff *skb;
-
- while (1) {
- if ((rxb = dma_get_rx_frame_size(card, ch)) == -1)
- return;
-
- if (!netif_carrier_ok(dev)) {
- /* DCD must be OFF: drop packet */
- printk("%s : DCD is OFF - drop %d rx bytes\n", dev->name, rxb);
- skb = NULL;
- } else {
- if (rxb > (dev->mtu + 40)) { /* add headers */
- printk("%s : MTU exceeded %d\n", dev->name, rxb);
- skb = NULL;
- } else {
- skb = dev_alloc_skb(rxb);
- if (skb == NULL) {
- printk("%s: Memory squeeze!!\n", dev->name);
- return;
- }
- skb->dev = dev;
- }
- }
-
- if (((rxb = dma_buf_read(card, ch, skb)) <= 0) || (skb == NULL)) {
-#ifdef PC300_DEBUG_RX
- printk("%s: rxb = %x\n", dev->name, rxb);
-#endif
- if ((skb == NULL) && (rxb > 0)) {
- /* rxb > dev->mtu */
- dev->stats.rx_errors++;
- dev->stats.rx_length_errors++;
- continue;
- }
-
- if (rxb < 0) { /* Invalid frame */
- rxb = -rxb;
- if (rxb & DST_OVR) {
- dev->stats.rx_errors++;
- dev->stats.rx_fifo_errors++;
- }
- if (rxb & DST_CRC) {
- dev->stats.rx_errors++;
- dev->stats.rx_crc_errors++;
- }
- if (rxb & (DST_RBIT | DST_SHRT | DST_ABT)) {
- dev->stats.rx_errors++;
- dev->stats.rx_frame_errors++;
- }
- }
- if (skb) {
- dev_kfree_skb_irq(skb);
- }
- continue;
- }
-
- dev->stats.rx_bytes += rxb;
-
-#ifdef PC300_DEBUG_RX
- printk("%s R:", dev->name);
- for (i = 0; i < skb->len; i++)
- printk(" %02x", *(skb->data + i));
- printk("\n");
-#endif
- if (d->trace_on) {
- cpc_trace(dev, skb, 'R');
- }
- dev->stats.rx_packets++;
- skb->protocol = hdlc_type_trans(skb, dev);
- netif_rx(skb);
- }
-}
-
-/************************************/
-/*** PC300 Interrupt Routines ***/
-/************************************/
-static void sca_tx_intr(pc300dev_t *dev)
-{
- pc300ch_t *chan = (pc300ch_t *)dev->chan;
- pc300_t *card = (pc300_t *)chan->card;
- int ch = chan->channel;
- volatile pcsca_bd_t __iomem * ptdescr;
-
- /* Clean up descriptors from previous transmission */
- ptdescr = (card->hw.rambase +
- TX_BD_ADDR(ch,chan->tx_first_bd));
- while ((cpc_readl(card->hw.scabase + DTX_REG(CDAL,ch)) !=
- TX_BD_ADDR(ch,chan->tx_first_bd)) &&
- (cpc_readb(&ptdescr->status) & DST_OSB)) {
- dev->dev->stats.tx_packets++;
- dev->dev->stats.tx_bytes += cpc_readw(&ptdescr->len);
- cpc_writeb(&ptdescr->status, DST_OSB);
- cpc_writew(&ptdescr->len, 0);
- chan->nfree_tx_bd++;
- chan->tx_first_bd = (chan->tx_first_bd + 1) & (N_DMA_TX_BUF - 1);
- ptdescr = (card->hw.rambase + TX_BD_ADDR(ch,chan->tx_first_bd));
- }
-
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto == PC300_PROTO_MLPPP) {
- cpc_tty_trigger_poll(dev);
- } else {
-#endif
- /* Tell the upper layer we are ready to transmit more packets */
- netif_wake_queue(dev->dev);
-#ifdef CONFIG_PC300_MLPPP
- }
-#endif
-}
-
-static void sca_intr(pc300_t * card)
-{
- void __iomem *scabase = card->hw.scabase;
- volatile u32 status;
- int ch;
- int intr_count = 0;
- unsigned char dsr_rx;
-
- while ((status = cpc_readl(scabase + ISR0)) != 0) {
- for (ch = 0; ch < card->hw.nchan; ch++) {
- pc300ch_t *chan = &card->chan[ch];
- pc300dev_t *d = &chan->d;
- struct net_device *dev = d->dev;
-
- spin_lock(&card->card_lock);
-
- /**** Reception ****/
- if (status & IR0_DRX((IR0_DMIA | IR0_DMIB), ch)) {
- u8 drx_stat = cpc_readb(scabase + DSR_RX(ch));
-
- /* Clear RX interrupts */
- cpc_writeb(scabase + DSR_RX(ch), drx_stat | DSR_DWE);
-
-#ifdef PC300_DEBUG_INTR
- printk ("sca_intr: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n",
- ch, status, drx_stat);
-#endif
- if (status & IR0_DRX(IR0_DMIA, ch)) {
- if (drx_stat & DSR_BOF) {
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto == PC300_PROTO_MLPPP) {
- /* verify if driver is TTY */
- if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
- rx_dma_stop(card, ch);
- }
- cpc_tty_receive(d);
- rx_dma_start(card, ch);
- } else
-#endif
- {
- if ((cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
- rx_dma_stop(card, ch);
- }
- cpc_net_rx(dev);
- /* Discard invalid frames */
- dev->stats.rx_errors++;
- dev->stats.rx_over_errors++;
- chan->rx_first_bd = 0;
- chan->rx_last_bd = N_DMA_RX_BUF - 1;
- rx_dma_start(card, ch);
- }
- }
- }
- if (status & IR0_DRX(IR0_DMIB, ch)) {
- if (drx_stat & DSR_EOM) {
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase +
- card->hw.cpld_reg2,
- cpc_readb (card->hw.falcbase +
- card->hw.cpld_reg2) |
- (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto == PC300_PROTO_MLPPP) {
- /* verify if driver is TTY */
- cpc_tty_receive(d);
- } else {
- cpc_net_rx(dev);
- }
-#else
- cpc_net_rx(dev);
-#endif
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase +
- card->hw.cpld_reg2,
- cpc_readb (card->hw.falcbase +
- card->hw.cpld_reg2) &
- ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- }
- }
- if (!(dsr_rx = cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) {
-#ifdef PC300_DEBUG_INTR
- printk("%s: RX intr chan[%d] (st=0x%08lx, dsr=0x%02x, dsr2=0x%02x)\n",
- dev->name, ch, status, drx_stat, dsr_rx);
-#endif
- cpc_writeb(scabase + DSR_RX(ch), (dsr_rx | DSR_DE) & 0xfe);
- }
- }
-
- /**** Transmission ****/
- if (status & IR0_DTX((IR0_EFT | IR0_DMIA | IR0_DMIB), ch)) {
- u8 dtx_stat = cpc_readb(scabase + DSR_TX(ch));
-
- /* Clear TX interrupts */
- cpc_writeb(scabase + DSR_TX(ch), dtx_stat | DSR_DWE);
-
-#ifdef PC300_DEBUG_INTR
- printk ("sca_intr: TX intr chan[%d] (st=0x%08lx, dsr=0x%02x)\n",
- ch, status, dtx_stat);
-#endif
- if (status & IR0_DTX(IR0_EFT, ch)) {
- if (dtx_stat & DSR_UDRF) {
- if (cpc_readb (scabase + M_REG(TBN, ch)) != 0) {
- cpc_writeb(scabase + M_REG(CMD,ch), CMD_TX_BUF_CLR);
- }
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb (card->hw.falcbase +
- card->hw.cpld_reg2) &
- ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- dev->stats.tx_errors++;
- dev->stats.tx_fifo_errors++;
- sca_tx_intr(d);
- }
- }
- if (status & IR0_DTX(IR0_DMIA, ch)) {
- if (dtx_stat & DSR_BOF) {
- }
- }
- if (status & IR0_DTX(IR0_DMIB, ch)) {
- if (dtx_stat & DSR_EOM) {
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb (card->hw.falcbase +
- card->hw.cpld_reg2) &
- ~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- sca_tx_intr(d);
- }
- }
- }
-
- /**** MSCI ****/
- if (status & IR0_M(IR0_RXINTA, ch)) {
- u8 st1 = cpc_readb(scabase + M_REG(ST1, ch));
-
- /* Clear MSCI interrupts */
- cpc_writeb(scabase + M_REG(ST1, ch), st1);
-
-#ifdef PC300_DEBUG_INTR
- printk("sca_intr: MSCI intr chan[%d] (st=0x%08lx, st1=0x%02x)\n",
- ch, status, st1);
-#endif
- if (st1 & ST1_CDCD) { /* DCD changed */
- if (cpc_readb(scabase + M_REG(ST3, ch)) & ST3_DCD) {
- printk ("%s: DCD is OFF. Going administrative down.\n",
- dev->name);
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto != PC300_PROTO_MLPPP) {
- netif_carrier_off(dev);
- }
-#else
- netif_carrier_off(dev);
-
-#endif
- card->chan[ch].d.line_off++;
- } else { /* DCD = 1 */
- printk ("%s: DCD is ON. Going administrative up.\n",
- dev->name);
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto != PC300_PROTO_MLPPP)
- /* verify if driver is not TTY */
-#endif
- netif_carrier_on(dev);
- card->chan[ch].d.line_on++;
- }
- }
- }
- spin_unlock(&card->card_lock);
- }
- if (++intr_count == 10)
- /* Too much work at this board. Force exit */
- break;
- }
-}
-
-static void falc_t1_loop_detection(pc300_t *card, int ch, u8 frs1)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) &&
- !pfalc->loop_gen) {
- if (frs1 & FRS1_LLBDD) {
- // A Line Loop Back Deactivation signal detected
- if (pfalc->loop_active) {
- falc_remote_loop(card, ch, 0);
- }
- } else {
- if ((frs1 & FRS1_LLBAD) &&
- ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) {
- // A Line Loop Back Activation signal detected
- if (!pfalc->loop_active) {
- falc_remote_loop(card, ch, 1);
- }
- }
- }
- }
-}
-
-static void falc_e1_loop_detection(pc300_t *card, int ch, u8 rsp)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
-
- if (((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_XPRBS) == 0) &&
- !pfalc->loop_gen) {
- if (rsp & RSP_LLBDD) {
- // A Line Loop Back Deactivation signal detected
- if (pfalc->loop_active) {
- falc_remote_loop(card, ch, 0);
- }
- } else {
- if ((rsp & RSP_LLBAD) &&
- ((cpc_readb(falcbase + F_REG(LCR1, ch)) & LCR1_EPRM) == 0)) {
- // A Line Loop Back Activation signal detected
- if (!pfalc->loop_active) {
- falc_remote_loop(card, ch, 1);
- }
- }
- }
- }
-}
-
-static void falc_t1_intr(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u8 isr0, isr3, gis;
- u8 dummy;
-
- while ((gis = cpc_readb(falcbase + F_REG(GIS, ch))) != 0) {
- if (gis & GIS_ISR0) {
- isr0 = cpc_readb(falcbase + F_REG(FISR0, ch));
- if (isr0 & FISR0_PDEN) {
- /* Read the bit to clear the situation */
- if (cpc_readb(falcbase + F_REG(FRS1, ch)) &
- FRS1_PDEN) {
- pfalc->pden++;
- }
- }
- }
-
- if (gis & GIS_ISR1) {
- dummy = cpc_readb(falcbase + F_REG(FISR1, ch));
- }
-
- if (gis & GIS_ISR2) {
- dummy = cpc_readb(falcbase + F_REG(FISR2, ch));
- }
-
- if (gis & GIS_ISR3) {
- isr3 = cpc_readb(falcbase + F_REG(FISR3, ch));
- if (isr3 & FISR3_SEC) {
- pfalc->sec++;
- falc_update_stats(card, ch);
- falc_check_status(card, ch,
- cpc_readb(falcbase + F_REG(FRS0, ch)));
- }
- if (isr3 & FISR3_ES) {
- pfalc->es++;
- }
- if (isr3 & FISR3_LLBSC) {
- falc_t1_loop_detection(card, ch,
- cpc_readb(falcbase + F_REG(FRS1, ch)));
- }
- }
- }
-}
-
-static void falc_e1_intr(pc300_t * card, int ch)
-{
- pc300ch_t *chan = (pc300ch_t *) & card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- void __iomem *falcbase = card->hw.falcbase;
- u8 isr1, isr2, isr3, gis, rsp;
- u8 dummy;
-
- while ((gis = cpc_readb(falcbase + F_REG(GIS, ch))) != 0) {
- rsp = cpc_readb(falcbase + F_REG(RSP, ch));
-
- if (gis & GIS_ISR0) {
- dummy = cpc_readb(falcbase + F_REG(FISR0, ch));
- }
- if (gis & GIS_ISR1) {
- isr1 = cpc_readb(falcbase + F_REG(FISR1, ch));
- if (isr1 & FISR1_XMB) {
- if ((pfalc->xmb_cause & 2) &&
- pfalc->multiframe_mode) {
- if (cpc_readb (falcbase + F_REG(FRS0, ch)) &
- (FRS0_LOS | FRS0_AIS | FRS0_LFA)) {
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch))
- & ~XSP_AXS);
- } else {
- cpc_writeb(falcbase + F_REG(XSP, ch),
- cpc_readb(falcbase + F_REG(XSP, ch))
- | XSP_AXS);
- }
- }
- pfalc->xmb_cause = 0;
- cpc_writeb(falcbase + F_REG(IMR1, ch),
- cpc_readb(falcbase + F_REG(IMR1, ch)) | IMR1_XMB);
- }
- if (isr1 & FISR1_LLBSC) {
- falc_e1_loop_detection(card, ch, rsp);
- }
- }
- if (gis & GIS_ISR2) {
- isr2 = cpc_readb(falcbase + F_REG(FISR2, ch));
- if (isr2 & FISR2_T400MS) {
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) | XSW_XRA);
- }
- if (isr2 & FISR2_MFAR) {
- cpc_writeb(falcbase + F_REG(XSW, ch),
- cpc_readb(falcbase + F_REG(XSW, ch)) & ~XSW_XRA);
- }
- if (isr2 & (FISR2_FAR | FISR2_LFA | FISR2_AIS | FISR2_LOS)) {
- pfalc->xmb_cause |= 2;
- cpc_writeb(falcbase + F_REG(IMR1, ch),
- cpc_readb(falcbase + F_REG(IMR1, ch)) & ~IMR1_XMB);
- }
- }
- if (gis & GIS_ISR3) {
- isr3 = cpc_readb(falcbase + F_REG(FISR3, ch));
- if (isr3 & FISR3_SEC) {
- pfalc->sec++;
- falc_update_stats(card, ch);
- falc_check_status(card, ch,
- cpc_readb(falcbase + F_REG(FRS0, ch)));
- }
- if (isr3 & FISR3_ES) {
- pfalc->es++;
- }
- }
- }
-}
-
-static void falc_intr(pc300_t * card)
-{
- int ch;
-
- for (ch = 0; ch < card->hw.nchan; ch++) {
- pc300ch_t *chan = &card->chan[ch];
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
-
- if (conf->media == IF_IFACE_T1) {
- falc_t1_intr(card, ch);
- } else {
- falc_e1_intr(card, ch);
- }
- }
-}
-
-static irqreturn_t cpc_intr(int irq, void *dev_id)
-{
- pc300_t *card = dev_id;
- volatile u8 plx_status;
-
- if (!card) {
-#ifdef PC300_DEBUG_INTR
- printk("cpc_intr: spurious intr %d\n", irq);
-#endif
- return IRQ_NONE; /* spurious intr */
- }
-
- if (!card->hw.rambase) {
-#ifdef PC300_DEBUG_INTR
- printk("cpc_intr: spurious intr2 %d\n", irq);
-#endif
- return IRQ_NONE; /* spurious intr */
- }
-
- switch (card->hw.type) {
- case PC300_RSV:
- case PC300_X21:
- sca_intr(card);
- break;
-
- case PC300_TE:
- while ( (plx_status = (cpc_readb(card->hw.plxbase + card->hw.intctl_reg) &
- (PLX_9050_LINT1_STATUS | PLX_9050_LINT2_STATUS))) != 0) {
- if (plx_status & PLX_9050_LINT1_STATUS) { /* SCA Interrupt */
- sca_intr(card);
- }
- if (plx_status & PLX_9050_LINT2_STATUS) { /* FALC Interrupt */
- falc_intr(card);
- }
- }
- break;
- }
- return IRQ_HANDLED;
-}
-
-static void cpc_sca_status(pc300_t * card, int ch)
-{
- u8 ilar;
- void __iomem *scabase = card->hw.scabase;
- unsigned long flags;
-
- tx_dma_buf_check(card, ch);
- rx_dma_buf_check(card, ch);
- ilar = cpc_readb(scabase + ILAR);
- printk ("ILAR=0x%02x, WCRL=0x%02x, PCR=0x%02x, BTCR=0x%02x, BOLR=0x%02x\n",
- ilar, cpc_readb(scabase + WCRL), cpc_readb(scabase + PCR),
- cpc_readb(scabase + BTCR), cpc_readb(scabase + BOLR));
- printk("TX_CDA=0x%08x, TX_EDA=0x%08x\n",
- cpc_readl(scabase + DTX_REG(CDAL, ch)),
- cpc_readl(scabase + DTX_REG(EDAL, ch)));
- printk("RX_CDA=0x%08x, RX_EDA=0x%08x, BFL=0x%04x\n",
- cpc_readl(scabase + DRX_REG(CDAL, ch)),
- cpc_readl(scabase + DRX_REG(EDAL, ch)),
- cpc_readw(scabase + DRX_REG(BFLL, ch)));
- printk("DMER=0x%02x, DSR_TX=0x%02x, DSR_RX=0x%02x\n",
- cpc_readb(scabase + DMER), cpc_readb(scabase + DSR_TX(ch)),
- cpc_readb(scabase + DSR_RX(ch)));
- printk("DMR_TX=0x%02x, DMR_RX=0x%02x, DIR_TX=0x%02x, DIR_RX=0x%02x\n",
- cpc_readb(scabase + DMR_TX(ch)), cpc_readb(scabase + DMR_RX(ch)),
- cpc_readb(scabase + DIR_TX(ch)),
- cpc_readb(scabase + DIR_RX(ch)));
- printk("DCR_TX=0x%02x, DCR_RX=0x%02x, FCT_TX=0x%02x, FCT_RX=0x%02x\n",
- cpc_readb(scabase + DCR_TX(ch)), cpc_readb(scabase + DCR_RX(ch)),
- cpc_readb(scabase + FCT_TX(ch)),
- cpc_readb(scabase + FCT_RX(ch)));
- printk("MD0=0x%02x, MD1=0x%02x, MD2=0x%02x, MD3=0x%02x, IDL=0x%02x\n",
- cpc_readb(scabase + M_REG(MD0, ch)),
- cpc_readb(scabase + M_REG(MD1, ch)),
- cpc_readb(scabase + M_REG(MD2, ch)),
- cpc_readb(scabase + M_REG(MD3, ch)),
- cpc_readb(scabase + M_REG(IDL, ch)));
- printk("CMD=0x%02x, SA0=0x%02x, SA1=0x%02x, TFN=0x%02x, CTL=0x%02x\n",
- cpc_readb(scabase + M_REG(CMD, ch)),
- cpc_readb(scabase + M_REG(SA0, ch)),
- cpc_readb(scabase + M_REG(SA1, ch)),
- cpc_readb(scabase + M_REG(TFN, ch)),
- cpc_readb(scabase + M_REG(CTL, ch)));
- printk("ST0=0x%02x, ST1=0x%02x, ST2=0x%02x, ST3=0x%02x, ST4=0x%02x\n",
- cpc_readb(scabase + M_REG(ST0, ch)),
- cpc_readb(scabase + M_REG(ST1, ch)),
- cpc_readb(scabase + M_REG(ST2, ch)),
- cpc_readb(scabase + M_REG(ST3, ch)),
- cpc_readb(scabase + M_REG(ST4, ch)));
- printk ("CST0=0x%02x, CST1=0x%02x, CST2=0x%02x, CST3=0x%02x, FST=0x%02x\n",
- cpc_readb(scabase + M_REG(CST0, ch)),
- cpc_readb(scabase + M_REG(CST1, ch)),
- cpc_readb(scabase + M_REG(CST2, ch)),
- cpc_readb(scabase + M_REG(CST3, ch)),
- cpc_readb(scabase + M_REG(FST, ch)));
- printk("TRC0=0x%02x, TRC1=0x%02x, RRC=0x%02x, TBN=0x%02x, RBN=0x%02x\n",
- cpc_readb(scabase + M_REG(TRC0, ch)),
- cpc_readb(scabase + M_REG(TRC1, ch)),
- cpc_readb(scabase + M_REG(RRC, ch)),
- cpc_readb(scabase + M_REG(TBN, ch)),
- cpc_readb(scabase + M_REG(RBN, ch)));
- printk("TFS=0x%02x, TNR0=0x%02x, TNR1=0x%02x, RNR=0x%02x\n",
- cpc_readb(scabase + M_REG(TFS, ch)),
- cpc_readb(scabase + M_REG(TNR0, ch)),
- cpc_readb(scabase + M_REG(TNR1, ch)),
- cpc_readb(scabase + M_REG(RNR, ch)));
- printk("TCR=0x%02x, RCR=0x%02x, TNR1=0x%02x, RNR=0x%02x\n",
- cpc_readb(scabase + M_REG(TCR, ch)),
- cpc_readb(scabase + M_REG(RCR, ch)),
- cpc_readb(scabase + M_REG(TNR1, ch)),
- cpc_readb(scabase + M_REG(RNR, ch)));
- printk("TXS=0x%02x, RXS=0x%02x, EXS=0x%02x, TMCT=0x%02x, TMCR=0x%02x\n",
- cpc_readb(scabase + M_REG(TXS, ch)),
- cpc_readb(scabase + M_REG(RXS, ch)),
- cpc_readb(scabase + M_REG(EXS, ch)),
- cpc_readb(scabase + M_REG(TMCT, ch)),
- cpc_readb(scabase + M_REG(TMCR, ch)));
- printk("IE0=0x%02x, IE1=0x%02x, IE2=0x%02x, IE4=0x%02x, FIE=0x%02x\n",
- cpc_readb(scabase + M_REG(IE0, ch)),
- cpc_readb(scabase + M_REG(IE1, ch)),
- cpc_readb(scabase + M_REG(IE2, ch)),
- cpc_readb(scabase + M_REG(IE4, ch)),
- cpc_readb(scabase + M_REG(FIE, ch)));
- printk("IER0=0x%08x\n", cpc_readl(scabase + IER0));
-
- if (ilar != 0) {
- CPC_LOCK(card, flags);
- cpc_writeb(scabase + ILAR, ilar);
- cpc_writeb(scabase + DMER, 0x80);
- CPC_UNLOCK(card, flags);
- }
-}
-
-static void cpc_falc_status(pc300_t * card, int ch)
-{
- pc300ch_t *chan = &card->chan[ch];
- falc_t *pfalc = (falc_t *) & chan->falc;
- unsigned long flags;
-
- CPC_LOCK(card, flags);
- printk("CH%d: %s %s %d channels\n",
- ch, (pfalc->sync ? "SYNC" : ""), (pfalc->active ? "ACTIVE" : ""),
- pfalc->num_channels);
-
- printk(" pden=%d, los=%d, losr=%d, lfa=%d, farec=%d\n",
- pfalc->pden, pfalc->los, pfalc->losr, pfalc->lfa, pfalc->farec);
- printk(" lmfa=%d, ais=%d, sec=%d, es=%d, rai=%d\n",
- pfalc->lmfa, pfalc->ais, pfalc->sec, pfalc->es, pfalc->rai);
- printk(" bec=%d, fec=%d, cvc=%d, cec=%d, ebc=%d\n",
- pfalc->bec, pfalc->fec, pfalc->cvc, pfalc->cec, pfalc->ebc);
-
- printk("\n");
- printk(" STATUS: %s %s %s %s %s %s\n",
- (pfalc->red_alarm ? "RED" : ""),
- (pfalc->blue_alarm ? "BLU" : ""),
- (pfalc->yellow_alarm ? "YEL" : ""),
- (pfalc->loss_fa ? "LFA" : ""),
- (pfalc->loss_mfa ? "LMF" : ""), (pfalc->prbs ? "PRB" : ""));
- CPC_UNLOCK(card, flags);
-}
-
-static int cpc_change_mtu(struct net_device *dev, int new_mtu)
-{
- if ((new_mtu < 128) || (new_mtu > PC300_DEF_MTU))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
-}
-
-static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- pc300conf_t conf_aux;
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- int ch = chan->channel;
- void __user *arg = ifr->ifr_data;
- struct if_settings *settings = &ifr->ifr_settings;
- void __iomem *scabase = card->hw.scabase;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch (cmd) {
- case SIOCGPC300CONF:
-#ifdef CONFIG_PC300_MLPPP
- if (conf->proto != PC300_PROTO_MLPPP) {
- conf->proto = /* FIXME hdlc->proto.id */ 0;
- }
-#else
- conf->proto = /* FIXME hdlc->proto.id */ 0;
-#endif
- memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
- memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
- if (!arg ||
- copy_to_user(arg, &conf_aux, sizeof(pc300conf_t)))
- return -EINVAL;
- return 0;
- case SIOCSPC300CONF:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (!arg ||
- copy_from_user(&conf_aux.conf, arg, sizeof(pc300chconf_t)))
- return -EINVAL;
- if (card->hw.cpld_id < 0x02 &&
- conf_aux.conf.fr_mode == PC300_FR_UNFRAMED) {
- /* CPLD_ID < 0x02 doesn't support Unframed E1 */
- return -EINVAL;
- }
-#ifdef CONFIG_PC300_MLPPP
- if (conf_aux.conf.proto == PC300_PROTO_MLPPP) {
- if (conf->proto != PC300_PROTO_MLPPP) {
- memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- cpc_tty_init(d); /* init TTY driver */
- }
- } else {
- if (conf_aux.conf.proto == 0xffff) {
- if (conf->proto == PC300_PROTO_MLPPP){
- /* ifdown interface */
- cpc_close(dev);
- }
- } else {
- memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- /* FIXME hdlc->proto.id = conf->proto; */
- }
- }
-#else
- memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- /* FIXME hdlc->proto.id = conf->proto; */
-#endif
- return 0;
- case SIOCGPC300STATUS:
- cpc_sca_status(card, ch);
- return 0;
- case SIOCGPC300FALCSTATUS:
- cpc_falc_status(card, ch);
- return 0;
-
- case SIOCGPC300UTILSTATS:
- {
- if (!arg) { /* clear statistics */
- memset(&dev->stats, 0, sizeof(dev->stats));
- if (card->hw.type == PC300_TE) {
- memset(&chan->falc, 0, sizeof(falc_t));
- }
- } else {
- pc300stats_t pc300stats;
-
- memset(&pc300stats, 0, sizeof(pc300stats_t));
- pc300stats.hw_type = card->hw.type;
- pc300stats.line_on = card->chan[ch].d.line_on;
- pc300stats.line_off = card->chan[ch].d.line_off;
- memcpy(&pc300stats.gen_stats, &dev->stats,
- sizeof(dev->stats));
- if (card->hw.type == PC300_TE)
- memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
- if (copy_to_user(arg, &pc300stats, sizeof(pc300stats_t)))
- return -EFAULT;
- }
- return 0;
- }
-
- case SIOCGPC300UTILSTATUS:
- {
- struct pc300status pc300status;
-
- pc300status.hw_type = card->hw.type;
- if (card->hw.type == PC300_TE) {
- pc300status.te_status.sync = chan->falc.sync;
- pc300status.te_status.red_alarm = chan->falc.red_alarm;
- pc300status.te_status.blue_alarm = chan->falc.blue_alarm;
- pc300status.te_status.loss_fa = chan->falc.loss_fa;
- pc300status.te_status.yellow_alarm =chan->falc.yellow_alarm;
- pc300status.te_status.loss_mfa = chan->falc.loss_mfa;
- pc300status.te_status.prbs = chan->falc.prbs;
- } else {
- pc300status.gen_status.dcd =
- !(cpc_readb (scabase + M_REG(ST3, ch)) & ST3_DCD);
- pc300status.gen_status.cts =
- !(cpc_readb (scabase + M_REG(ST3, ch)) & ST3_CTS);
- pc300status.gen_status.rts =
- !(cpc_readb (scabase + M_REG(CTL, ch)) & CTL_RTS);
- pc300status.gen_status.dtr =
- !(cpc_readb (scabase + M_REG(CTL, ch)) & CTL_DTR);
- /* There is no DSR in HD64572 */
- }
- if (!arg ||
- copy_to_user(arg, &pc300status, sizeof(pc300status_t)))
- return -EINVAL;
- return 0;
- }
-
- case SIOCSPC300TRACE:
- /* Sets/resets a trace_flag for the respective device */
- if (!arg || copy_from_user(&d->trace_on, arg,sizeof(unsigned char)))
- return -EINVAL;
- return 0;
-
- case SIOCSPC300LOOPBACK:
- {
- struct pc300loopback pc300loop;
-
- /* TE boards only */
- if (card->hw.type != PC300_TE)
- return -EINVAL;
-
- if (!arg ||
- copy_from_user(&pc300loop, arg, sizeof(pc300loopback_t)))
- return -EINVAL;
- switch (pc300loop.loop_type) {
- case PC300LOCLOOP: /* Turn the local loop on/off */
- falc_local_loop(card, ch, pc300loop.loop_on);
- return 0;
-
- case PC300REMLOOP: /* Turn the remote loop on/off */
- falc_remote_loop(card, ch, pc300loop.loop_on);
- return 0;
-
- case PC300PAYLOADLOOP: /* Turn the payload loop on/off */
- falc_payload_loop(card, ch, pc300loop.loop_on);
- return 0;
-
- case PC300GENLOOPUP: /* Generate loop UP */
- if (pc300loop.loop_on) {
- falc_generate_loop_up_code (card, ch);
- } else {
- turn_off_xlu(card, ch);
- }
- return 0;
-
- case PC300GENLOOPDOWN: /* Generate loop DOWN */
- if (pc300loop.loop_on) {
- falc_generate_loop_down_code (card, ch);
- } else {
- turn_off_xld(card, ch);
- }
- return 0;
-
- default:
- return -EINVAL;
- }
- }
-
- case SIOCSPC300PATTERNTEST:
- /* Turn the pattern test on/off and show the errors counter */
- {
- struct pc300patterntst pc300patrntst;
-
- /* TE boards only */
- if (card->hw.type != PC300_TE)
- return -EINVAL;
-
- if (card->hw.cpld_id < 0x02) {
- /* CPLD_ID < 0x02 doesn't support pattern test */
- return -EINVAL;
- }
-
- if (!arg ||
- copy_from_user(&pc300patrntst,arg,sizeof(pc300patterntst_t)))
- return -EINVAL;
- if (pc300patrntst.patrntst_on == 2) {
- if (chan->falc.prbs == 0) {
- falc_pattern_test(card, ch, 1);
- }
- pc300patrntst.num_errors =
- falc_pattern_test_error(card, ch);
- if (copy_to_user(arg, &pc300patrntst,
- sizeof(pc300patterntst_t)))
- return -EINVAL;
- } else {
- falc_pattern_test(card, ch, pc300patrntst.patrntst_on);
- }
- return 0;
- }
-
- case SIOCWANDEV:
- switch (ifr->ifr_settings.type) {
- case IF_GET_IFACE:
- {
- const size_t size = sizeof(sync_serial_settings);
- ifr->ifr_settings.type = conf->media;
- if (ifr->ifr_settings.size < size) {
- /* data size wanted */
- ifr->ifr_settings.size = size;
- return -ENOBUFS;
- }
-
- if (copy_to_user(settings->ifs_ifsu.sync,
- &conf->phys_settings, size)) {
- return -EFAULT;
- }
- return 0;
- }
-
- case IF_IFACE_V35:
- case IF_IFACE_V24:
- case IF_IFACE_X21:
- {
- const size_t size = sizeof(sync_serial_settings);
-
- if (!capable(CAP_NET_ADMIN)) {
- return -EPERM;
- }
- /* incorrect data len? */
- if (ifr->ifr_settings.size != size) {
- return -ENOBUFS;
- }
-
- if (copy_from_user(&conf->phys_settings,
- settings->ifs_ifsu.sync, size)) {
- return -EFAULT;
- }
-
- if (conf->phys_settings.loopback) {
- cpc_writeb(card->hw.scabase + M_REG(MD2, ch),
- cpc_readb(card->hw.scabase + M_REG(MD2, ch)) |
- MD2_LOOP_MIR);
- }
- conf->media = ifr->ifr_settings.type;
- return 0;
- }
-
- case IF_IFACE_T1:
- case IF_IFACE_E1:
- {
- const size_t te_size = sizeof(te1_settings);
- const size_t size = sizeof(sync_serial_settings);
-
- if (!capable(CAP_NET_ADMIN)) {
- return -EPERM;
- }
-
- /* incorrect data len? */
- if (ifr->ifr_settings.size != te_size) {
- return -ENOBUFS;
- }
-
- if (copy_from_user(&conf->phys_settings,
- settings->ifs_ifsu.te1, size)) {
- return -EFAULT;
- }/* Ignoring HDLC slot_map for a while */
-
- if (conf->phys_settings.loopback) {
- cpc_writeb(card->hw.scabase + M_REG(MD2, ch),
- cpc_readb(card->hw.scabase + M_REG(MD2, ch)) |
- MD2_LOOP_MIR);
- }
- conf->media = ifr->ifr_settings.type;
- return 0;
- }
- default:
- return hdlc_ioctl(dev, ifr, cmd);
- }
-
- default:
- return hdlc_ioctl(dev, ifr, cmd);
- }
-}
-
-static int clock_rate_calc(u32 rate, u32 clock, int *br_io)
-{
- int br, tc;
- int br_pwr, error;
-
- *br_io = 0;
-
- if (rate == 0)
- return 0;
-
- for (br = 0, br_pwr = 1; br <= 9; br++, br_pwr <<= 1) {
- if ((tc = clock / br_pwr / rate) <= 0xff) {
- *br_io = br;
- break;
- }
- }
-
- if (tc <= 0xff) {
- error = ((rate - (clock / br_pwr / rate)) / rate) * 1000;
- /* Errors bigger than +/- 1% won't be tolerated */
- if (error < -10 || error > 10)
- return -1;
- else
- return tc;
- } else {
- return -1;
- }
-}
-
-static int ch_config(pc300dev_t * d)
-{
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300chconf_t *conf = (pc300chconf_t *) & chan->conf;
- pc300_t *card = (pc300_t *) chan->card;
- void __iomem *scabase = card->hw.scabase;
- void __iomem *plxbase = card->hw.plxbase;
- int ch = chan->channel;
- u32 clkrate = chan->conf.phys_settings.clock_rate;
- u32 clktype = chan->conf.phys_settings.clock_type;
- u16 encoding = chan->conf.proto_settings.encoding;
- u16 parity = chan->conf.proto_settings.parity;
- u8 md0, md2;
-
- /* Reset the channel */
- cpc_writeb(scabase + M_REG(CMD, ch), CMD_CH_RST);
-
- /* Configure the SCA registers */
- switch (parity) {
- case PARITY_NONE:
- md0 = MD0_BIT_SYNC;
- break;
- case PARITY_CRC16_PR0:
- md0 = MD0_CRC16_0|MD0_CRCC0|MD0_BIT_SYNC;
- break;
- case PARITY_CRC16_PR1:
- md0 = MD0_CRC16_1|MD0_CRCC0|MD0_BIT_SYNC;
- break;
- case PARITY_CRC32_PR1_CCITT:
- md0 = MD0_CRC32|MD0_CRCC0|MD0_BIT_SYNC;
- break;
- case PARITY_CRC16_PR1_CCITT:
- default:
- md0 = MD0_CRC_CCITT|MD0_CRCC0|MD0_BIT_SYNC;
- break;
- }
- switch (encoding) {
- case ENCODING_NRZI:
- md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_NRZI;
- break;
- case ENCODING_FM_MARK: /* FM1 */
- md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_FM1;
- break;
- case ENCODING_FM_SPACE: /* FM0 */
- md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_FM0;
- break;
- case ENCODING_MANCHESTER: /* It's not working... */
- md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_FM|MD2_MANCH;
- break;
- case ENCODING_NRZ:
- default:
- md2 = MD2_F_DUPLEX|MD2_ADPLL_X8|MD2_NRZ;
- break;
- }
- cpc_writeb(scabase + M_REG(MD0, ch), md0);
- cpc_writeb(scabase + M_REG(MD1, ch), 0);
- cpc_writeb(scabase + M_REG(MD2, ch), md2);
- cpc_writeb(scabase + M_REG(IDL, ch), 0x7e);
- cpc_writeb(scabase + M_REG(CTL, ch), CTL_URSKP | CTL_IDLC);
-
- /* Configure HW media */
- switch (card->hw.type) {
- case PC300_RSV:
- if (conf->media == IF_IFACE_V35) {
- cpc_writel((plxbase + card->hw.gpioc_reg),
- cpc_readl(plxbase + card->hw.gpioc_reg) | PC300_CHMEDIA_MASK(ch));
- } else {
- cpc_writel((plxbase + card->hw.gpioc_reg),
- cpc_readl(plxbase + card->hw.gpioc_reg) & ~PC300_CHMEDIA_MASK(ch));
- }
- break;
-
- case PC300_X21:
- break;
-
- case PC300_TE:
- te_config(card, ch);
- break;
- }
-
- switch (card->hw.type) {
- case PC300_RSV:
- case PC300_X21:
- if (clktype == CLOCK_INT || clktype == CLOCK_TXINT) {
- int tmc, br;
-
- /* Calculate the clkrate parameters */
- tmc = clock_rate_calc(clkrate, card->hw.clock, &br);
- if (tmc < 0)
- return -EIO;
- cpc_writeb(scabase + M_REG(TMCT, ch), tmc);
- cpc_writeb(scabase + M_REG(TXS, ch),
- (TXS_DTRXC | TXS_IBRG | br));
- if (clktype == CLOCK_INT) {
- cpc_writeb(scabase + M_REG(TMCR, ch), tmc);
- cpc_writeb(scabase + M_REG(RXS, ch),
- (RXS_IBRG | br));
- } else {
- cpc_writeb(scabase + M_REG(TMCR, ch), 1);
- cpc_writeb(scabase + M_REG(RXS, ch), 0);
- }
- if (card->hw.type == PC300_X21) {
- cpc_writeb(scabase + M_REG(GPO, ch), 1);
- cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1 | EXS_RES1);
- } else {
- cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1);
- }
- } else {
- cpc_writeb(scabase + M_REG(TMCT, ch), 1);
- if (clktype == CLOCK_EXT) {
- cpc_writeb(scabase + M_REG(TXS, ch),
- TXS_DTRXC);
- } else {
- cpc_writeb(scabase + M_REG(TXS, ch),
- TXS_DTRXC|TXS_RCLK);
- }
- cpc_writeb(scabase + M_REG(TMCR, ch), 1);
- cpc_writeb(scabase + M_REG(RXS, ch), 0);
- if (card->hw.type == PC300_X21) {
- cpc_writeb(scabase + M_REG(GPO, ch), 0);
- cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1 | EXS_RES1);
- } else {
- cpc_writeb(scabase + M_REG(EXS, ch), EXS_TES1);
- }
- }
- break;
-
- case PC300_TE:
- /* SCA always receives clock from the FALC chip */
- cpc_writeb(scabase + M_REG(TMCT, ch), 1);
- cpc_writeb(scabase + M_REG(TXS, ch), 0);
- cpc_writeb(scabase + M_REG(TMCR, ch), 1);
- cpc_writeb(scabase + M_REG(RXS, ch), 0);
- cpc_writeb(scabase + M_REG(EXS, ch), 0);
- break;
- }
-
- /* Enable Interrupts */
- cpc_writel(scabase + IER0,
- cpc_readl(scabase + IER0) |
- IR0_M(IR0_RXINTA, ch) |
- IR0_DRX(IR0_EFT | IR0_DMIA | IR0_DMIB, ch) |
- IR0_DTX(IR0_EFT | IR0_DMIA | IR0_DMIB, ch));
- cpc_writeb(scabase + M_REG(IE0, ch),
- cpc_readl(scabase + M_REG(IE0, ch)) | IE0_RXINTA);
- cpc_writeb(scabase + M_REG(IE1, ch),
- cpc_readl(scabase + M_REG(IE1, ch)) | IE1_CDCD);
-
- return 0;
-}
-
-static int rx_config(pc300dev_t * d)
-{
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- void __iomem *scabase = card->hw.scabase;
- int ch = chan->channel;
-
- cpc_writeb(scabase + DSR_RX(ch), 0);
-
- /* General RX settings */
- cpc_writeb(scabase + M_REG(RRC, ch), 0);
- cpc_writeb(scabase + M_REG(RNR, ch), 16);
-
- /* Enable reception */
- cpc_writeb(scabase + M_REG(CMD, ch), CMD_RX_CRC_INIT);
- cpc_writeb(scabase + M_REG(CMD, ch), CMD_RX_ENA);
-
- /* Initialize DMA stuff */
- chan->rx_first_bd = 0;
- chan->rx_last_bd = N_DMA_RX_BUF - 1;
- rx_dma_buf_init(card, ch);
- cpc_writeb(scabase + DCR_RX(ch), DCR_FCT_CLR);
- cpc_writeb(scabase + DMR_RX(ch), (DMR_TMOD | DMR_NF));
- cpc_writeb(scabase + DIR_RX(ch), (DIR_EOM | DIR_BOF));
-
- /* Start DMA */
- rx_dma_start(card, ch);
-
- return 0;
-}
-
-static int tx_config(pc300dev_t * d)
-{
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- void __iomem *scabase = card->hw.scabase;
- int ch = chan->channel;
-
- cpc_writeb(scabase + DSR_TX(ch), 0);
-
- /* General TX settings */
- cpc_writeb(scabase + M_REG(TRC0, ch), 0);
- cpc_writeb(scabase + M_REG(TFS, ch), 32);
- cpc_writeb(scabase + M_REG(TNR0, ch), 20);
- cpc_writeb(scabase + M_REG(TNR1, ch), 48);
- cpc_writeb(scabase + M_REG(TCR, ch), 8);
-
- /* Enable transmission */
- cpc_writeb(scabase + M_REG(CMD, ch), CMD_TX_CRC_INIT);
-
- /* Initialize DMA stuff */
- chan->tx_first_bd = 0;
- chan->tx_next_bd = 0;
- tx_dma_buf_init(card, ch);
- cpc_writeb(scabase + DCR_TX(ch), DCR_FCT_CLR);
- cpc_writeb(scabase + DMR_TX(ch), (DMR_TMOD | DMR_NF));
- cpc_writeb(scabase + DIR_TX(ch), (DIR_EOM | DIR_BOF | DIR_UDRF));
- cpc_writel(scabase + DTX_REG(CDAL, ch), TX_BD_ADDR(ch, chan->tx_first_bd));
- cpc_writel(scabase + DTX_REG(EDAL, ch), TX_BD_ADDR(ch, chan->tx_next_bd));
-
- return 0;
-}
-
-static int cpc_attach(struct net_device *dev, unsigned short encoding,
- unsigned short parity)
-{
- pc300dev_t *d = (pc300dev_t *)dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *)d->chan;
- pc300_t *card = (pc300_t *)chan->card;
- pc300chconf_t *conf = (pc300chconf_t *)&chan->conf;
-
- if (card->hw.type == PC300_TE) {
- if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI) {
- return -EINVAL;
- }
- } else {
- if (encoding != ENCODING_NRZ && encoding != ENCODING_NRZI &&
- encoding != ENCODING_FM_MARK && encoding != ENCODING_FM_SPACE) {
- /* Driver doesn't support ENCODING_MANCHESTER yet */
- return -EINVAL;
- }
- }
-
- if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0 &&
- parity != PARITY_CRC16_PR1 && parity != PARITY_CRC32_PR1_CCITT &&
- parity != PARITY_CRC16_PR1_CCITT) {
- return -EINVAL;
- }
-
- conf->proto_settings.encoding = encoding;
- conf->proto_settings.parity = parity;
- return 0;
-}
-
-static int cpc_opench(pc300dev_t * d)
-{
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- int ch = chan->channel, rc;
- void __iomem *scabase = card->hw.scabase;
-
- rc = ch_config(d);
- if (rc)
- return rc;
-
- rx_config(d);
-
- tx_config(d);
-
- /* Assert RTS and DTR */
- cpc_writeb(scabase + M_REG(CTL, ch),
- cpc_readb(scabase + M_REG(CTL, ch)) & ~(CTL_RTS | CTL_DTR));
-
- return 0;
-}
-
-static void cpc_closech(pc300dev_t * d)
-{
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- falc_t *pfalc = (falc_t *) & chan->falc;
- int ch = chan->channel;
-
- cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_CH_RST);
- rx_dma_stop(card, ch);
- tx_dma_stop(card, ch);
-
- if (card->hw.type == PC300_TE) {
- memset(pfalc, 0, sizeof(falc_t));
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
- ~((CPLD_REG2_FALC_TX_CLK | CPLD_REG2_FALC_RX_CLK |
- CPLD_REG2_FALC_LED2) << (2 * ch)));
- /* Reset the FALC chip */
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
- (CPLD_REG1_FALC_RESET << (2 * ch)));
- udelay(10000);
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) &
- ~(CPLD_REG1_FALC_RESET << (2 * ch)));
- }
-}
-
-int cpc_open(struct net_device *dev)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- struct ifreq ifr;
- int result;
-
-#ifdef PC300_DEBUG_OTHER
- printk("pc300: cpc_open");
-#endif
-
- result = hdlc_open(dev);
-
- if (result)
- return result;
-
- sprintf(ifr.ifr_name, "%s", dev->name);
- result = cpc_opench(d);
- if (result)
- goto err_out;
-
- netif_start_queue(dev);
- return 0;
-
-err_out:
- hdlc_close(dev);
- return result;
-}
-
-static int cpc_close(struct net_device *dev)
-{
- pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv;
- pc300ch_t *chan = (pc300ch_t *) d->chan;
- pc300_t *card = (pc300_t *) chan->card;
- unsigned long flags;
-
-#ifdef PC300_DEBUG_OTHER
- printk("pc300: cpc_close");
-#endif
-
- netif_stop_queue(dev);
-
- CPC_LOCK(card, flags);
- cpc_closech(d);
- CPC_UNLOCK(card, flags);
-
- hdlc_close(dev);
-
-#ifdef CONFIG_PC300_MLPPP
- if (chan->conf.proto == PC300_PROTO_MLPPP) {
- cpc_tty_unregister_service(d);
- chan->conf.proto = 0xffff;
- }
-#endif
-
- return 0;
-}
-
-static u32 detect_ram(pc300_t * card)
-{
- u32 i;
- u8 data;
- void __iomem *rambase = card->hw.rambase;
-
- card->hw.ramsize = PC300_RAMSIZE;
- /* Let's find out how much RAM is present on this board */
- for (i = 0; i < card->hw.ramsize; i++) {
- data = (u8)(i & 0xff);
- cpc_writeb(rambase + i, data);
- if (cpc_readb(rambase + i) != data) {
- break;
- }
- }
- return i;
-}
-
-static void plx_init(pc300_t * card)
-{
- struct RUNTIME_9050 __iomem *plx_ctl = card->hw.plxbase;
-
- /* Reset PLX */
- cpc_writel(&plx_ctl->init_ctrl,
- cpc_readl(&plx_ctl->init_ctrl) | 0x40000000);
- udelay(10000L);
- cpc_writel(&plx_ctl->init_ctrl,
- cpc_readl(&plx_ctl->init_ctrl) & ~0x40000000);
-
- /* Reload Config. Registers from EEPROM */
- cpc_writel(&plx_ctl->init_ctrl,
- cpc_readl(&plx_ctl->init_ctrl) | 0x20000000);
- udelay(10000L);
- cpc_writel(&plx_ctl->init_ctrl,
- cpc_readl(&plx_ctl->init_ctrl) & ~0x20000000);
-
-}
-
-static void show_version(void)
-{
- char *rcsvers, *rcsdate, *tmp;
-
- rcsvers = strchr(rcsid, ' ');
- rcsvers++;
- tmp = strchr(rcsvers, ' ');
- *tmp++ = '\0';
- rcsdate = strchr(tmp, ' ');
- rcsdate++;
- tmp = strrchr(rcsdate, ' ');
- *tmp = '\0';
- pr_info("Cyclades-PC300 driver %s %s\n", rcsvers, rcsdate);
-} /* show_version */
-
-static const struct net_device_ops cpc_netdev_ops = {
- .ndo_open = cpc_open,
- .ndo_stop = cpc_close,
- .ndo_tx_timeout = cpc_tx_timeout,
- .ndo_set_mac_address = NULL,
- .ndo_change_mtu = cpc_change_mtu,
- .ndo_do_ioctl = cpc_ioctl,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static void cpc_init_card(pc300_t * card)
-{
- int i, devcount = 0;
- static int board_nbr = 1;
-
- /* Enable interrupts on the PCI bridge */
- plx_init(card);
- cpc_writew(card->hw.plxbase + card->hw.intctl_reg,
- cpc_readw(card->hw.plxbase + card->hw.intctl_reg) | 0x0040);
-
-#ifdef USE_PCI_CLOCK
- /* Set board clock to PCI clock */
- cpc_writel(card->hw.plxbase + card->hw.gpioc_reg,
- cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) | 0x00000004UL);
- card->hw.clock = PC300_PCI_CLOCK;
-#else
- /* Set board clock to internal oscillator clock */
- cpc_writel(card->hw.plxbase + card->hw.gpioc_reg,
- cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) & ~0x00000004UL);
- card->hw.clock = PC300_OSC_CLOCK;
-#endif
-
- /* Detect actual on-board RAM size */
- card->hw.ramsize = detect_ram(card);
-
- /* Set Global SCA-II registers */
- cpc_writeb(card->hw.scabase + PCR, PCR_PR2);
- cpc_writeb(card->hw.scabase + BTCR, 0x10);
- cpc_writeb(card->hw.scabase + WCRL, 0);
- cpc_writeb(card->hw.scabase + DMER, 0x80);
-
- if (card->hw.type == PC300_TE) {
- u8 reg1;
-
- /* Check CPLD version */
- reg1 = cpc_readb(card->hw.falcbase + CPLD_REG1);
- cpc_writeb(card->hw.falcbase + CPLD_REG1, (reg1 + 0x5a));
- if (cpc_readb(card->hw.falcbase + CPLD_REG1) == reg1) {
- /* New CPLD */
- card->hw.cpld_id = cpc_readb(card->hw.falcbase + CPLD_ID_REG);
- card->hw.cpld_reg1 = CPLD_V2_REG1;
- card->hw.cpld_reg2 = CPLD_V2_REG2;
- } else {
- /* old CPLD */
- card->hw.cpld_id = 0;
- card->hw.cpld_reg1 = CPLD_REG1;
- card->hw.cpld_reg2 = CPLD_REG2;
- cpc_writeb(card->hw.falcbase + CPLD_REG1, reg1);
- }
-
- /* Enable the board's global clock */
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) |
- CPLD_REG1_GLOBAL_CLK);
-
- }
-
- for (i = 0; i < card->hw.nchan; i++) {
- pc300ch_t *chan = &card->chan[i];
- pc300dev_t *d = &chan->d;
- hdlc_device *hdlc;
- struct net_device *dev;
-
- chan->card = card;
- chan->channel = i;
- chan->conf.phys_settings.clock_rate = 0;
- chan->conf.phys_settings.clock_type = CLOCK_EXT;
- chan->conf.proto_settings.encoding = ENCODING_NRZ;
- chan->conf.proto_settings.parity = PARITY_CRC16_PR1_CCITT;
- switch (card->hw.type) {
- case PC300_TE:
- chan->conf.media = IF_IFACE_T1;
- chan->conf.lcode = PC300_LC_B8ZS;
- chan->conf.fr_mode = PC300_FR_ESF;
- chan->conf.lbo = PC300_LBO_0_DB;
- chan->conf.rx_sens = PC300_RX_SENS_SH;
- chan->conf.tslot_bitmap = 0xffffffffUL;
- break;
-
- case PC300_X21:
- chan->conf.media = IF_IFACE_X21;
- break;
-
- case PC300_RSV:
- default:
- chan->conf.media = IF_IFACE_V35;
- break;
- }
- chan->conf.proto = IF_PROTO_PPP;
- chan->tx_first_bd = 0;
- chan->tx_next_bd = 0;
- chan->rx_first_bd = 0;
- chan->rx_last_bd = N_DMA_RX_BUF - 1;
- chan->nfree_tx_bd = N_DMA_TX_BUF;
-
- d->chan = chan;
- d->trace_on = 0;
- d->line_on = 0;
- d->line_off = 0;
-
- dev = alloc_hdlcdev(d);
- if (dev == NULL)
- continue;
-
- hdlc = dev_to_hdlc(dev);
- hdlc->xmit = cpc_queue_xmit;
- hdlc->attach = cpc_attach;
- d->dev = dev;
- dev->mem_start = card->hw.ramphys;
- dev->mem_end = card->hw.ramphys + card->hw.ramsize - 1;
- dev->irq = card->hw.irq;
- dev->tx_queue_len = PC300_TX_QUEUE_LEN;
- dev->mtu = PC300_DEF_MTU;
-
- dev->netdev_ops = &cpc_netdev_ops;
- dev->watchdog_timeo = PC300_TX_TIMEOUT;
-
- if (register_hdlc_device(dev) == 0) {
- printk("%s: Cyclades-PC300/", dev->name);
- switch (card->hw.type) {
- case PC300_TE:
- if (card->hw.bus == PC300_PMC) {
- printk("TE-M");
- } else {
- printk("TE ");
- }
- break;
-
- case PC300_X21:
- printk("X21 ");
- break;
-
- case PC300_RSV:
- default:
- printk("RSV ");
- break;
- }
- printk (" #%d, %dKB of RAM at 0x%08x, IRQ%d, channel %d.\n",
- board_nbr, card->hw.ramsize / 1024,
- card->hw.ramphys, card->hw.irq, i + 1);
- devcount++;
- } else {
- printk ("Dev%d on card(0x%08x): unable to allocate i/f name.\n",
- i + 1, card->hw.ramphys);
- free_netdev(dev);
- continue;
- }
- }
- spin_lock_init(&card->card_lock);
-
- board_nbr++;
-}
-
-static int
-cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int err, eeprom_outdated = 0;
- u16 device_id;
- pc300_t *card;
-
- if ((err = pci_enable_device(pdev)) < 0)
- return err;
-
- card = kzalloc(sizeof(pc300_t), GFP_KERNEL);
- if (card == NULL) {
- printk("PC300 found at RAM 0x%016llx, "
- "but could not allocate card structure.\n",
- (unsigned long long)pci_resource_start(pdev, 3));
- err = -ENOMEM;
- goto err_disable_dev;
- }
-
- err = -ENODEV;
-
- /* read PCI configuration area */
- device_id = ent->device;
- card->hw.irq = pdev->irq;
- card->hw.iophys = pci_resource_start(pdev, 1);
- card->hw.iosize = pci_resource_len(pdev, 1);
- card->hw.scaphys = pci_resource_start(pdev, 2);
- card->hw.scasize = pci_resource_len(pdev, 2);
- card->hw.ramphys = pci_resource_start(pdev, 3);
- card->hw.alloc_ramsize = pci_resource_len(pdev, 3);
- card->hw.falcphys = pci_resource_start(pdev, 4);
- card->hw.falcsize = pci_resource_len(pdev, 4);
- card->hw.plxphys = pci_resource_start(pdev, 5);
- card->hw.plxsize = pci_resource_len(pdev, 5);
-
- switch (device_id) {
- case PCI_DEVICE_ID_PC300_RX_1:
- case PCI_DEVICE_ID_PC300_TE_1:
- case PCI_DEVICE_ID_PC300_TE_M_1:
- card->hw.nchan = 1;
- break;
-
- case PCI_DEVICE_ID_PC300_RX_2:
- case PCI_DEVICE_ID_PC300_TE_2:
- case PCI_DEVICE_ID_PC300_TE_M_2:
- default:
- card->hw.nchan = PC300_MAXCHAN;
- break;
- }
-#ifdef PC300_DEBUG_PCI
- printk("cpc (bus=0x0%x,pci_id=0x%x,", pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n", pdev->revision, card->hw.irq);
- printk("cpc:found ramaddr=0x%08lx plxaddr=0x%08lx "
- "ctladdr=0x%08lx falcaddr=0x%08lx\n",
- card->hw.ramphys, card->hw.plxphys, card->hw.scaphys,
- card->hw.falcphys);
-#endif
- /* Although we don't use this I/O region, we should
- * request it from the kernel anyway, to avoid problems
- * with other drivers accessing it. */
- if (!request_region(card->hw.iophys, card->hw.iosize, "PLX Registers")) {
- /* In case we can't allocate it, warn user */
- printk("WARNING: couldn't allocate I/O region for PC300 board "
- "at 0x%08x!\n", card->hw.ramphys);
- }
-
- if (card->hw.plxphys) {
- pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, card->hw.plxphys);
- } else {
- eeprom_outdated = 1;
- card->hw.plxphys = pci_resource_start(pdev, 0);
- card->hw.plxsize = pci_resource_len(pdev, 0);
- }
-
- if (!request_mem_region(card->hw.plxphys, card->hw.plxsize,
- "PLX Registers")) {
- printk("PC300 found at RAM 0x%08x, "
- "but could not allocate PLX mem region.\n",
- card->hw.ramphys);
- goto err_release_io;
- }
- if (!request_mem_region(card->hw.ramphys, card->hw.alloc_ramsize,
- "On-board RAM")) {
- printk("PC300 found at RAM 0x%08x, "
- "but could not allocate RAM mem region.\n",
- card->hw.ramphys);
- goto err_release_plx;
- }
- if (!request_mem_region(card->hw.scaphys, card->hw.scasize,
- "SCA-II Registers")) {
- printk("PC300 found at RAM 0x%08x, "
- "but could not allocate SCA mem region.\n",
- card->hw.ramphys);
- goto err_release_ram;
- }
-
- card->hw.plxbase = ioremap(card->hw.plxphys, card->hw.plxsize);
- card->hw.rambase = ioremap(card->hw.ramphys, card->hw.alloc_ramsize);
- card->hw.scabase = ioremap(card->hw.scaphys, card->hw.scasize);
- switch (device_id) {
- case PCI_DEVICE_ID_PC300_TE_1:
- case PCI_DEVICE_ID_PC300_TE_2:
- case PCI_DEVICE_ID_PC300_TE_M_1:
- case PCI_DEVICE_ID_PC300_TE_M_2:
- request_mem_region(card->hw.falcphys, card->hw.falcsize,
- "FALC Registers");
- card->hw.falcbase = ioremap(card->hw.falcphys, card->hw.falcsize);
- break;
-
- case PCI_DEVICE_ID_PC300_RX_1:
- case PCI_DEVICE_ID_PC300_RX_2:
- default:
- card->hw.falcbase = NULL;
- break;
- }
-
-#ifdef PC300_DEBUG_PCI
- printk("cpc: relocate ramaddr=0x%08lx plxaddr=0x%08lx "
- "ctladdr=0x%08lx falcaddr=0x%08lx\n",
- card->hw.rambase, card->hw.plxbase, card->hw.scabase,
- card->hw.falcbase);
-#endif
-
- /* Set PCI drv pointer to the card structure */
- pci_set_drvdata(pdev, card);
-
- /* Set board type */
- switch (device_id) {
- case PCI_DEVICE_ID_PC300_TE_1:
- case PCI_DEVICE_ID_PC300_TE_2:
- case PCI_DEVICE_ID_PC300_TE_M_1:
- case PCI_DEVICE_ID_PC300_TE_M_2:
- card->hw.type = PC300_TE;
-
- if ((device_id == PCI_DEVICE_ID_PC300_TE_M_1) ||
- (device_id == PCI_DEVICE_ID_PC300_TE_M_2)) {
- card->hw.bus = PC300_PMC;
- /* Set PLX register offsets */
- card->hw.gpioc_reg = 0x54;
- card->hw.intctl_reg = 0x4c;
- } else {
- card->hw.bus = PC300_PCI;
- /* Set PLX register offsets */
- card->hw.gpioc_reg = 0x50;
- card->hw.intctl_reg = 0x4c;
- }
- break;
-
- case PCI_DEVICE_ID_PC300_RX_1:
- case PCI_DEVICE_ID_PC300_RX_2:
- default:
- card->hw.bus = PC300_PCI;
- /* Set PLX register offsets */
- card->hw.gpioc_reg = 0x50;
- card->hw.intctl_reg = 0x4c;
-
- if ((cpc_readl(card->hw.plxbase + card->hw.gpioc_reg) & PC300_CTYPE_MASK)) {
- card->hw.type = PC300_X21;
- } else {
- card->hw.type = PC300_RSV;
- }
- break;
- }
-
- /* Allocate IRQ */
- if (request_irq(card->hw.irq, cpc_intr, IRQF_SHARED, "Cyclades-PC300", card)) {
- printk ("PC300 found at RAM 0x%08x, but could not allocate IRQ%d.\n",
- card->hw.ramphys, card->hw.irq);
- goto err_io_unmap;
- }
-
- cpc_init_card(card);
-
- if (eeprom_outdated)
- printk("WARNING: PC300 with outdated EEPROM.\n");
- return 0;
-
-err_io_unmap:
- iounmap(card->hw.plxbase);
- iounmap(card->hw.scabase);
- iounmap(card->hw.rambase);
- if (card->hw.type == PC300_TE) {
- iounmap(card->hw.falcbase);
- release_mem_region(card->hw.falcphys, card->hw.falcsize);
- }
- release_mem_region(card->hw.scaphys, card->hw.scasize);
-err_release_ram:
- release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize);
-err_release_plx:
- release_mem_region(card->hw.plxphys, card->hw.plxsize);
-err_release_io:
- release_region(card->hw.iophys, card->hw.iosize);
- kfree(card);
-err_disable_dev:
- pci_disable_device(pdev);
- return err;
-}
-
-static void cpc_remove_one(struct pci_dev *pdev)
-{
- pc300_t *card = pci_get_drvdata(pdev);
-
- if (card->hw.rambase) {
- int i;
-
- /* Disable interrupts on the PCI bridge */
- cpc_writew(card->hw.plxbase + card->hw.intctl_reg,
- cpc_readw(card->hw.plxbase + card->hw.intctl_reg) & ~(0x0040));
-
- for (i = 0; i < card->hw.nchan; i++) {
- unregister_hdlc_device(card->chan[i].d.dev);
- }
- iounmap(card->hw.plxbase);
- iounmap(card->hw.scabase);
- iounmap(card->hw.rambase);
- release_mem_region(card->hw.plxphys, card->hw.plxsize);
- release_mem_region(card->hw.ramphys, card->hw.alloc_ramsize);
- release_mem_region(card->hw.scaphys, card->hw.scasize);
- release_region(card->hw.iophys, card->hw.iosize);
- if (card->hw.type == PC300_TE) {
- iounmap(card->hw.falcbase);
- release_mem_region(card->hw.falcphys, card->hw.falcsize);
- }
- for (i = 0; i < card->hw.nchan; i++)
- if (card->chan[i].d.dev)
- free_netdev(card->chan[i].d.dev);
- if (card->hw.irq)
- free_irq(card->hw.irq, card);
- kfree(card);
- pci_disable_device(pdev);
- }
-}
-
-static struct pci_driver cpc_driver = {
- .name = "pc300",
- .id_table = cpc_pci_dev_id,
- .probe = cpc_init_one,
- .remove = cpc_remove_one,
-};
-
-static int __init cpc_init(void)
-{
- show_version();
- return pci_register_driver(&cpc_driver);
-}
-
-static void __exit cpc_cleanup_module(void)
-{
- pci_unregister_driver(&cpc_driver);
-}
-
-module_init(cpc_init);
-module_exit(cpc_cleanup_module);
-
-MODULE_DESCRIPTION("Cyclades-PC300 cards driver");
-MODULE_AUTHOR( "Author: Ivan Passos <ivan@cyclades.com>\r\n"
- "Maintainer: PC300 Maintainer <pc300@cyclades.com");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/staging/net/pc300_tty.c b/drivers/staging/net/pc300_tty.c
deleted file mode 100644
index 4709f4228561..000000000000
--- a/drivers/staging/net/pc300_tty.c
+++ /dev/null
@@ -1,1079 +0,0 @@
-/*
- * pc300_tty.c Cyclades-PC300(tm) TTY Driver.
- *
- * Author: Regina Kodato <reginak@cyclades.com>
- *
- * Copyright: (c) 1999-2002 Cyclades Corp.
- *
- * 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.
- *
- * $Log: pc300_tty.c,v $
- * Revision 3.7 2002/03/07 14:17:09 henrique
- * License data fixed
- *
- * Revision 3.6 2001/12/10 12:29:42 regina
- * Fix the MLPPP bug
- *
- * Revision 3.5 2001/10/31 11:20:05 regina
- * automatic pppd starts
- *
- * Revision 3.4 2001/08/06 12:01:51 regina
- * problem in DSR_DE bit
- *
- * Revision 3.3 2001/07/26 22:58:41 regina
- * update EDA value
- *
- * Revision 3.2 2001/07/12 13:11:20 regina
- * bug fix - DCD-OFF in pc300 tty driver
- *
- * DMA transmission bug fix
- *
- * Revision 3.1 2001/06/22 13:13:02 regina
- * MLPPP implementation
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-/* TTY includes */
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "pc300.h"
-
-/* defines and macros */
-/* TTY Global definitions */
-#define CPC_TTY_NPORTS 8 /* maximum number of the sync tty connections */
-#define CPC_TTY_MAJOR CYCLADES_MAJOR
-#define CPC_TTY_MINOR_START 240 /* minor of the first PC300 interface */
-
-#define CPC_TTY_MAX_MTU 2000
-
-/* tty interface state */
-#define CPC_TTY_ST_IDLE 0
-#define CPC_TTY_ST_INIT 1 /* configured with MLPPP and up */
-#define CPC_TTY_ST_OPEN 2 /* opened by application */
-
-#define CPC_TTY_LOCK(card,flags)\
- do {\
- spin_lock_irqsave(&card->card_lock, flags); \
- } while (0)
-
-#define CPC_TTY_UNLOCK(card,flags) \
- do {\
- spin_unlock_irqrestore(&card->card_lock, flags); \
- } while (0)
-
-//#define CPC_TTY_DBG(format,a...) printk(format,##a)
-#define CPC_TTY_DBG(format,a...)
-
-/* data structures */
-typedef struct _st_cpc_rx_buf {
- struct _st_cpc_rx_buf *next;
- int size;
- unsigned char data[1];
-} st_cpc_rx_buf;
-
-struct st_cpc_rx_list {
- st_cpc_rx_buf *first;
- st_cpc_rx_buf *last;
-};
-
-typedef struct _st_cpc_tty_area {
- int state; /* state of the TTY interface */
- int num_open;
- unsigned int tty_minor; /* minor this interface */
- volatile struct st_cpc_rx_list buf_rx; /* ptr. to reception buffer */
- unsigned char* buf_tx; /* ptr. to transmission buffer */
- pc300dev_t* pc300dev; /* ptr. to info struct in PC300 driver */
- unsigned char name[20]; /* interf. name + "-tty" */
- struct tty_struct *tty;
- struct work_struct tty_tx_work; /* tx work - tx interrupt */
- struct work_struct tty_rx_work; /* rx work - rx interrupt */
- } st_cpc_tty_area;
-
-/* TTY data structures */
-static struct tty_driver serial_drv;
-
-/* local variables */
-static st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS];
-
-static int cpc_tty_cnt = 0; /* number of intrfaces configured with MLPPP */
-static int cpc_tty_unreg_flag = 0;
-
-/* TTY functions prototype */
-static int cpc_tty_open(struct tty_struct *tty, struct file *flip);
-static void cpc_tty_close(struct tty_struct *tty, struct file *flip);
-static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
-static int cpc_tty_write_room(struct tty_struct *tty);
-static int cpc_tty_chars_in_buffer(struct tty_struct *tty);
-static void cpc_tty_flush_buffer(struct tty_struct *tty);
-static void cpc_tty_hangup(struct tty_struct *tty);
-static void cpc_tty_rx_work(struct work_struct *work);
-static void cpc_tty_tx_work(struct work_struct *work);
-static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len);
-static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx);
-static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char);
-static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char);
-
-static int pc300_tiocmset(struct tty_struct *, unsigned int, unsigned int);
-static int pc300_tiocmget(struct tty_struct *);
-
-/* functions called by PC300 driver */
-void cpc_tty_init(pc300dev_t *dev);
-void cpc_tty_unregister_service(pc300dev_t *pc300dev);
-void cpc_tty_receive(pc300dev_t *pc300dev);
-void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
-
-/*
- * PC300 TTY clear "signal"
- */
-static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char signal)
-{
- pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan;
- pc300_t *card = (pc300_t *) pc300chan->card;
- int ch = pc300chan->channel;
- unsigned long flags;
-
- CPC_TTY_DBG("%s-tty: Clear signal %x\n",
- pc300dev->dev->name, signal);
- CPC_TTY_LOCK(card, flags);
- cpc_writeb(card->hw.scabase + M_REG(CTL,ch),
- cpc_readb(card->hw.scabase+M_REG(CTL,ch))& signal);
- CPC_TTY_UNLOCK(card,flags);
-}
-
-/*
- * PC300 TTY set "signal" to ON
- */
-static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal)
-{
- pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan;
- pc300_t *card = (pc300_t *) pc300chan->card;
- int ch = pc300chan->channel;
- unsigned long flags;
-
- CPC_TTY_DBG("%s-tty: Set signal %x\n",
- pc300dev->dev->name, signal);
- CPC_TTY_LOCK(card, flags);
- cpc_writeb(card->hw.scabase + M_REG(CTL,ch),
- cpc_readb(card->hw.scabase+M_REG(CTL,ch))& ~signal);
- CPC_TTY_UNLOCK(card,flags);
-}
-
-
-static const struct tty_operations pc300_ops = {
- .open = cpc_tty_open,
- .close = cpc_tty_close,
- .write = cpc_tty_write,
- .write_room = cpc_tty_write_room,
- .chars_in_buffer = cpc_tty_chars_in_buffer,
- .tiocmset = pc300_tiocmset,
- .tiocmget = pc300_tiocmget,
- .flush_buffer = cpc_tty_flush_buffer,
- .hangup = cpc_tty_hangup,
-};
-
-
-/*
- * PC300 TTY initialization routine
- *
- * This routine is called by the PC300 driver during board configuration
- * (ioctl=SIOCSP300CONF). At this point the adapter is completely
- * initialized.
- * o verify kernel version (only 2.4.x)
- * o register TTY driver
- * o init cpc_tty_area struct
- */
-void cpc_tty_init(pc300dev_t *pc300dev)
-{
- unsigned long port;
- int aux;
- st_cpc_tty_area * cpc_tty;
-
- /* hdlcX - X=interface number */
- port = pc300dev->dev->name[4] - '0';
- if (port >= CPC_TTY_NPORTS) {
- printk("%s-tty: invalid interface selected (0-%i): %li",
- pc300dev->dev->name,
- CPC_TTY_NPORTS-1,port);
- return;
- }
-
- if (cpc_tty_cnt == 0) { /* first TTY connection -> register driver */
- CPC_TTY_DBG("%s-tty: driver init, major:%i, minor range:%i=%i\n",
- pc300dev->dev->name,
- CPC_TTY_MAJOR, CPC_TTY_MINOR_START,
- CPC_TTY_MINOR_START+CPC_TTY_NPORTS);
- /* initialize tty driver struct */
- memset(&serial_drv,0,sizeof(struct tty_driver));
- serial_drv.magic = TTY_DRIVER_MAGIC;
- serial_drv.owner = THIS_MODULE;
- serial_drv.driver_name = "pc300_tty";
- serial_drv.name = "ttyCP";
- serial_drv.major = CPC_TTY_MAJOR;
- serial_drv.minor_start = CPC_TTY_MINOR_START;
- serial_drv.num = CPC_TTY_NPORTS;
- serial_drv.type = TTY_DRIVER_TYPE_SERIAL;
- serial_drv.subtype = SERIAL_TYPE_NORMAL;
-
- serial_drv.init_termios = tty_std_termios;
- serial_drv.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- serial_drv.flags = TTY_DRIVER_REAL_RAW;
-
- /* interface routines from the upper tty layer to the tty driver */
- tty_set_operations(&serial_drv, &pc300_ops);
-
- /* register the TTY driver */
- if (tty_register_driver(&serial_drv)) {
- printk("%s-tty: Failed to register serial driver! ",
- pc300dev->dev->name);
- return;
- }
-
- memset((void *)cpc_tty_area, 0,
- sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS);
- }
-
- cpc_tty = &cpc_tty_area[port];
-
- if (cpc_tty->state != CPC_TTY_ST_IDLE) {
- CPC_TTY_DBG("%s-tty: TTY port %i, already in use.\n",
- pc300dev->dev->name, port);
- return;
- }
-
- cpc_tty_cnt++;
- cpc_tty->state = CPC_TTY_ST_INIT;
- cpc_tty->num_open= 0;
- cpc_tty->tty_minor = port + CPC_TTY_MINOR_START;
- cpc_tty->pc300dev = pc300dev;
-
- INIT_WORK(&cpc_tty->tty_tx_work, cpc_tty_tx_work);
- INIT_WORK(&cpc_tty->tty_rx_work, cpc_tty_rx_work);
-
- cpc_tty->buf_rx.first = cpc_tty->buf_rx.last = NULL;
-
- pc300dev->cpc_tty = (void *)cpc_tty;
-
- aux = strlen(pc300dev->dev->name);
- memcpy(cpc_tty->name, pc300dev->dev->name, aux);
- memcpy(&cpc_tty->name[aux], "-tty", 5);
-
- cpc_open(pc300dev->dev);
- cpc_tty_signal_off(pc300dev, CTL_DTR);
-
- CPC_TTY_DBG("%s: Initializing TTY Sync Driver, tty major#%d minor#%i\n",
- cpc_tty->name,CPC_TTY_MAJOR,cpc_tty->tty_minor);
- return;
-}
-
-/*
- * PC300 TTY OPEN routine
- *
- * This routine is called by the tty driver to open the interface
- * o verify minor
- * o allocate buffer to Rx and Tx
- */
-static int cpc_tty_open(struct tty_struct *tty, struct file *flip)
-{
- int port ;
- st_cpc_tty_area *cpc_tty;
-
- if (!tty) {
- return -ENODEV;
- }
-
- port = tty->index;
-
- if ((port < 0) || (port >= CPC_TTY_NPORTS)){
- CPC_TTY_DBG("pc300_tty: open invalid port %d\n", port);
- return -ENODEV;
- }
-
- cpc_tty = &cpc_tty_area[port];
-
- if (cpc_tty->state == CPC_TTY_ST_IDLE){
- CPC_TTY_DBG("%s: open - invalid interface, port=%d\n",
- cpc_tty->name, tty->index);
- return -ENODEV;
- }
-
- if (cpc_tty->num_open == 0) { /* first open of this tty */
- if (!cpc_tty_area[port].buf_tx){
- cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL);
- if (!cpc_tty_area[port].buf_tx) {
- CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name);
- return -ENOMEM;
- }
- }
-
- if (cpc_tty_area[port].buf_rx.first) {
- unsigned char * aux;
- while (cpc_tty_area[port].buf_rx.first) {
- aux = (unsigned char *)cpc_tty_area[port].buf_rx.first;
- cpc_tty_area[port].buf_rx.first = cpc_tty_area[port].buf_rx.first->next;
- kfree(aux);
- }
- cpc_tty_area[port].buf_rx.first = NULL;
- cpc_tty_area[port].buf_rx.last = NULL;
- }
-
- cpc_tty_area[port].state = CPC_TTY_ST_OPEN;
- cpc_tty_area[port].tty = tty;
- tty->driver_data = &cpc_tty_area[port];
-
- cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR);
- }
-
- cpc_tty->num_open++;
-
- CPC_TTY_DBG("%s: opening TTY driver\n", cpc_tty->name);
-
- /* avisar driver PC300 */
- return 0;
-}
-
-/*
- * PC300 TTY CLOSE routine
- *
- * This routine is called by the tty driver to close the interface
- * o call close channel in PC300 driver (cpc_closech)
- * o free Rx and Tx buffers
- */
-
-static void cpc_tty_close(struct tty_struct *tty, struct file *flip)
-{
- st_cpc_tty_area *cpc_tty;
- unsigned long flags;
- int res;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlx-tty: no TTY in close\n");
- return;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty)|| (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
- return;
- }
-
- if (!cpc_tty->num_open) {
- CPC_TTY_DBG("%s: TTY is closed\n",cpc_tty->name);
- return;
- }
-
- if (--cpc_tty->num_open > 0) {
- CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);
- return;
- }
-
- cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR);
-
- CPC_TTY_LOCK(cpc_tty->pc300dev->chan->card, flags); /* lock irq */
- cpc_tty->tty = NULL;
- cpc_tty->state = CPC_TTY_ST_INIT;
- CPC_TTY_UNLOCK(cpc_tty->pc300dev->chan->card, flags); /* unlock irq */
-
- if (cpc_tty->buf_rx.first) {
- unsigned char * aux;
- while (cpc_tty->buf_rx.first) {
- aux = (unsigned char *)cpc_tty->buf_rx.first;
- cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
- kfree(aux);
- }
- cpc_tty->buf_rx.first = NULL;
- cpc_tty->buf_rx.last = NULL;
- }
-
- kfree(cpc_tty->buf_tx);
- cpc_tty->buf_tx = NULL;
-
- CPC_TTY_DBG("%s: TTY closed\n",cpc_tty->name);
-
- if (!serial_drv.refcount && cpc_tty_unreg_flag) {
- cpc_tty_unreg_flag = 0;
- CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
- if ((res=tty_unregister_driver(&serial_drv))) {
- CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
- cpc_tty->name,res);
- }
- }
- return;
-}
-
-/*
- * PC300 TTY WRITE routine
- *
- * This routine is called by the tty driver to write a series of characters
- * to the tty device. The characters may come from user or kernel space.
- * o verify the DCD signal
- * o send characters to board and start the transmission
- */
-static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
- st_cpc_tty_area *cpc_tty;
- pc300ch_t *pc300chan;
- pc300_t *card;
- int ch;
- unsigned long flags;
- struct net_device_stats *stats;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY in write\n");
- return -ENODEV;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n", cpc_tty->name);
- return -ENODEV;
- }
-
- if (count > CPC_TTY_MAX_MTU) {
- CPC_TTY_DBG("%s: count is invalid\n",cpc_tty->name);
- return -EINVAL; /* frame too big */
- }
-
- CPC_TTY_DBG("%s: cpc_tty_write data len=%i\n",cpc_tty->name,count);
-
- pc300chan = (pc300ch_t *)((pc300dev_t*)cpc_tty->pc300dev)->chan;
- stats = &cpc_tty->pc300dev->dev->stats;
- card = (pc300_t *) pc300chan->card;
- ch = pc300chan->channel;
-
- /* verify DCD signal*/
- if (cpc_readb(card->hw.scabase + M_REG(ST3,ch)) & ST3_DCD) {
- /* DCD is OFF */
- CPC_TTY_DBG("%s : DCD is OFF\n", cpc_tty->name);
- stats->tx_errors++;
- stats->tx_carrier_errors++;
- CPC_TTY_LOCK(card, flags);
- cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_BUF_CLR);
-
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
- ~(CPLD_REG2_FALC_LED1 << (2 *ch)));
- }
-
- CPC_TTY_UNLOCK(card, flags);
-
- return -EINVAL;
- }
-
- if (cpc_tty_send_to_card(cpc_tty->pc300dev, (void*)buf, count)) {
- /* failed to send */
- CPC_TTY_DBG("%s: trasmition error\n", cpc_tty->name);
- return 0;
- }
- return count;
-}
-
-/*
- * PC300 TTY Write Room routine
- *
- * This routine returns the numbers of characteres the tty driver will accept
- * for queuing to be written.
- * o return MTU
- */
-static int cpc_tty_write_room(struct tty_struct *tty)
-{
- st_cpc_tty_area *cpc_tty;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY to write room\n");
- return -ENODEV;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
- return -ENODEV;
- }
-
- CPC_TTY_DBG("%s: write room\n",cpc_tty->name);
-
- return CPC_TTY_MAX_MTU;
-}
-
-/*
- * PC300 TTY chars in buffer routine
- *
- * This routine returns the chars number in the transmission buffer
- * o returns 0
- */
-static int cpc_tty_chars_in_buffer(struct tty_struct *tty)
-{
- st_cpc_tty_area *cpc_tty;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");
- return -ENODEV;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int pc300_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- st_cpc_tty_area *cpc_tty;
-
- CPC_TTY_DBG("%s: set:%x clear:%x\n", __func__, set, clear);
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY to chars in buffer\n");
- return -ENODEV;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if (set & TIOCM_RTS)
- cpc_tty_signal_on(cpc_tty->pc300dev, CTL_RTS);
- if (set & TIOCM_DTR)
- cpc_tty_signal_on(cpc_tty->pc300dev, CTL_DTR);
-
- if (clear & TIOCM_RTS)
- cpc_tty_signal_off(cpc_tty->pc300dev, CTL_RTS);
- if (clear & TIOCM_DTR)
- cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR);
-
- return 0;
-}
-
-static int pc300_tiocmget(struct tty_struct *tty)
-{
- unsigned int result;
- unsigned char status;
- unsigned long flags;
- st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *) tty->driver_data;
- pc300dev_t *pc300dev = cpc_tty->pc300dev;
- pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan;
- pc300_t *card = (pc300_t *) pc300chan->card;
- int ch = pc300chan->channel;
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- CPC_TTY_DBG("%s-tty: tiocmget\n",
- ((struct net_device*)(pc300dev->hdlc))->name);
-
- CPC_TTY_LOCK(card, flags);
- status = cpc_readb(card->hw.scabase+M_REG(CTL,ch));
- CPC_TTY_UNLOCK(card,flags);
-
- result = ((status & CTL_DTR) ? TIOCM_DTR : 0) |
- ((status & CTL_RTS) ? TIOCM_RTS : 0);
-
- return result;
-}
-
-/*
- * PC300 TTY Flush Buffer routine
- *
- * This routine resets the transmission buffer
- */
-static void cpc_tty_flush_buffer(struct tty_struct *tty)
-{
- st_cpc_tty_area *cpc_tty;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY to flush buffer\n");
- return;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
- return;
- }
-
- CPC_TTY_DBG("%s: call wake_up_interruptible\n",cpc_tty->name);
-
- tty_wakeup(tty);
- return;
-}
-
-/*
- * PC300 TTY Hangup routine
- *
- * This routine is called by the tty driver to hangup the interface
- * o clear DTR signal
- */
-
-static void cpc_tty_hangup(struct tty_struct *tty)
-{
- st_cpc_tty_area *cpc_tty;
- int res;
-
- if (!tty || !tty->driver_data ) {
- CPC_TTY_DBG("hdlcX-tty: no TTY to hangup\n");
- return ;
- }
-
- cpc_tty = (st_cpc_tty_area *) tty->driver_data;
-
- if ((cpc_tty->tty != tty) || (cpc_tty->state != CPC_TTY_ST_OPEN)) {
- CPC_TTY_DBG("%s: TTY is not opened\n",cpc_tty->name);
- return ;
- }
- if (!serial_drv.refcount && cpc_tty_unreg_flag) {
- cpc_tty_unreg_flag = 0;
- CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
- if ((res=tty_unregister_driver(&serial_drv))) {
- CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
- cpc_tty->name,res);
- }
- }
- cpc_tty_signal_off(cpc_tty->pc300dev, CTL_DTR);
-}
-
-/*
- * PC300 TTY RX work routine
- * This routine treats RX work
- * o verify read buffer
- * o call the line disc. read
- * o free memory
- */
-static void cpc_tty_rx_work(struct work_struct *work)
-{
- st_cpc_tty_area *cpc_tty;
- unsigned long port;
- int i, j;
- volatile st_cpc_rx_buf *buf;
- char flags=0,flg_rx=1;
- struct tty_ldisc *ld;
-
- if (cpc_tty_cnt == 0) return;
-
- for (i=0; (i < 4) && flg_rx ; i++) {
- flg_rx = 0;
-
- cpc_tty = container_of(work, st_cpc_tty_area, tty_rx_work);
- port = cpc_tty - cpc_tty_area;
-
- for (j=0; j < CPC_TTY_NPORTS; j++) {
- cpc_tty = &cpc_tty_area[port];
-
- if ((buf=cpc_tty->buf_rx.first) != NULL) {
- if (cpc_tty->tty) {
- ld = tty_ldisc_ref(cpc_tty->tty);
- if (ld) {
- if (ld->ops->receive_buf) {
- CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name);
- ld->ops->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size);
- }
- tty_ldisc_deref(ld);
- }
- }
- cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next;
- kfree((void *)buf);
- buf = cpc_tty->buf_rx.first;
- flg_rx = 1;
- }
- if (++port == CPC_TTY_NPORTS) port = 0;
- }
- }
-}
-
-/*
- * PC300 TTY RX work routine
- *
- * This routine treats RX interrupt.
- * o read all frames in card
- * o verify the frame size
- * o read the frame in rx buffer
- */
-static void cpc_tty_rx_disc_frame(pc300ch_t *pc300chan)
-{
- volatile pcsca_bd_t __iomem * ptdescr;
- volatile unsigned char status;
- pc300_t *card = (pc300_t *)pc300chan->card;
- int ch = pc300chan->channel;
-
- /* dma buf read */
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase +
- RX_BD_ADDR(ch, pc300chan->rx_first_bd));
- while (pc300chan->rx_first_bd != pc300chan->rx_last_bd) {
- status = cpc_readb(&ptdescr->status);
- cpc_writeb(&ptdescr->status, 0);
- cpc_writeb(&ptdescr->len, 0);
- pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) &
- (N_DMA_RX_BUF - 1);
- if (status & DST_EOM) {
- break; /* end of message */
- }
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + cpc_readl(&ptdescr->next));
- }
-}
-
-void cpc_tty_receive(pc300dev_t *pc300dev)
-{
- st_cpc_tty_area *cpc_tty;
- pc300ch_t *pc300chan = (pc300ch_t *)pc300dev->chan;
- pc300_t *card = (pc300_t *)pc300chan->card;
- int ch = pc300chan->channel;
- volatile pcsca_bd_t __iomem * ptdescr;
- struct net_device_stats *stats = &pc300dev->dev->stats;
- int rx_len, rx_aux;
- volatile unsigned char status;
- unsigned short first_bd = pc300chan->rx_first_bd;
- st_cpc_rx_buf *new = NULL;
- unsigned char dsr_rx;
-
- if (pc300dev->cpc_tty == NULL) {
- return;
- }
-
- dsr_rx = cpc_readb(card->hw.scabase + DSR_RX(ch));
-
- cpc_tty = pc300dev->cpc_tty;
-
- while (1) {
- rx_len = 0;
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase + RX_BD_ADDR(ch, first_bd));
- while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
- rx_len += cpc_readw(&ptdescr->len);
- first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1);
- if (status & DST_EOM) {
- break;
- }
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase+cpc_readl(&ptdescr->next));
- }
-
- if (!rx_len) {
- if (dsr_rx & DSR_BOF) {
- /* update EDA */
- cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch),
- RX_BD_ADDR(ch, pc300chan->rx_last_bd));
- }
- kfree(new);
- return;
- }
-
- if (rx_len > CPC_TTY_MAX_MTU) {
- /* Free RX descriptors */
- CPC_TTY_DBG("%s: frame size is invalid.\n",cpc_tty->name);
- stats->rx_errors++;
- stats->rx_frame_errors++;
- cpc_tty_rx_disc_frame(pc300chan);
- continue;
- }
-
- new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC);
- if (!new) {
- cpc_tty_rx_disc_frame(pc300chan);
- continue;
- }
-
- /* dma buf read */
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase +
- RX_BD_ADDR(ch, pc300chan->rx_first_bd));
-
- rx_len = 0; /* counter frame size */
-
- while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) {
- rx_aux = cpc_readw(&ptdescr->len);
- if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT))
- || (rx_aux > BD_DEF_LEN)) {
- CPC_TTY_DBG("%s: reception error\n", cpc_tty->name);
- stats->rx_errors++;
- if (status & DST_OVR) {
- stats->rx_fifo_errors++;
- }
- if (status & DST_CRC) {
- stats->rx_crc_errors++;
- }
- if ((status & (DST_RBIT | DST_SHRT | DST_ABT)) ||
- (rx_aux > BD_DEF_LEN)) {
- stats->rx_frame_errors++;
- }
- /* discard remainig descriptors used by the bad frame */
- CPC_TTY_DBG("%s: reception error - discard descriptors",
- cpc_tty->name);
- cpc_tty_rx_disc_frame(pc300chan);
- rx_len = 0;
- kfree(new);
- new = NULL;
- break; /* read next frame - while(1) */
- }
-
- if (cpc_tty->state != CPC_TTY_ST_OPEN) {
- /* Free RX descriptors */
- cpc_tty_rx_disc_frame(pc300chan);
- stats->rx_dropped++;
- rx_len = 0;
- kfree(new);
- new = NULL;
- break; /* read next frame - while(1) */
- }
-
- /* read the segment of the frame */
- if (rx_aux != 0) {
- memcpy_fromio((new->data + rx_len),
- (void __iomem *)(card->hw.rambase +
- cpc_readl(&ptdescr->ptbuf)), rx_aux);
- rx_len += rx_aux;
- }
- cpc_writeb(&ptdescr->status,0);
- cpc_writeb(&ptdescr->len, 0);
- pc300chan->rx_first_bd = (pc300chan->rx_first_bd + 1) &
- (N_DMA_RX_BUF -1);
- if (status & DST_EOM)break;
-
- ptdescr = (pcsca_bd_t __iomem *) (card->hw.rambase +
- cpc_readl(&ptdescr->next));
- }
- /* update pointer */
- pc300chan->rx_last_bd = (pc300chan->rx_first_bd - 1) &
- (N_DMA_RX_BUF - 1) ;
- if (!(dsr_rx & DSR_BOF)) {
- /* update EDA */
- cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch),
- RX_BD_ADDR(ch, pc300chan->rx_last_bd));
- }
- if (rx_len != 0) {
- stats->rx_bytes += rx_len;
-
- if (pc300dev->trace_on) {
- cpc_tty_trace(pc300dev, new->data,rx_len, 'R');
- }
- new->size = rx_len;
- new->next = NULL;
- if (cpc_tty->buf_rx.first == NULL) {
- cpc_tty->buf_rx.first = new;
- cpc_tty->buf_rx.last = new;
- } else {
- cpc_tty->buf_rx.last->next = new;
- cpc_tty->buf_rx.last = new;
- }
- schedule_work(&(cpc_tty->tty_rx_work));
- stats->rx_packets++;
- }
- }
-}
-
-/*
- * PC300 TTY TX work routine
- *
- * This routine treats TX interrupt.
- * o if need call line discipline wakeup
- * o call wake_up_interruptible
- */
-static void cpc_tty_tx_work(struct work_struct *work)
-{
- st_cpc_tty_area *cpc_tty =
- container_of(work, st_cpc_tty_area, tty_tx_work);
- struct tty_struct *tty;
-
- CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name);
-
- if ((tty = cpc_tty->tty) == NULL) {
- CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name);
- return;
- }
- tty_wakeup(tty);
-}
-
-/*
- * PC300 TTY send to card routine
- *
- * This routine send data to card.
- * o clear descriptors
- * o write data to DMA buffers
- * o start the transmission
- */
-static int cpc_tty_send_to_card(pc300dev_t *dev,void* buf, int len)
-{
- pc300ch_t *chan = (pc300ch_t *)dev->chan;
- pc300_t *card = (pc300_t *)chan->card;
- int ch = chan->channel;
- struct net_device_stats *stats = &dev->dev->stats;
- unsigned long flags;
- volatile pcsca_bd_t __iomem *ptdescr;
- int i, nchar;
- int tosend = len;
- int nbuf = ((len - 1)/BD_DEF_LEN) + 1;
- unsigned char *pdata=buf;
-
- CPC_TTY_DBG("%s:cpc_tty_send_to_cars len=%i",
- (st_cpc_tty_area *)dev->cpc_tty->name,len);
-
- if (nbuf >= card->chan[ch].nfree_tx_bd) {
- return 1;
- }
-
- /* write buffer to DMA buffers */
- CPC_TTY_DBG("%s: call dma_buf_write\n",
- (st_cpc_tty_area *)dev->cpc_tty->name);
- for (i = 0 ; i < nbuf ; i++) {
- ptdescr = (pcsca_bd_t __iomem *)(card->hw.rambase +
- TX_BD_ADDR(ch, card->chan[ch].tx_next_bd));
- nchar = (BD_DEF_LEN > tosend) ? tosend : BD_DEF_LEN;
- if (cpc_readb(&ptdescr->status) & DST_OSB) {
- memcpy_toio((void __iomem *)(card->hw.rambase +
- cpc_readl(&ptdescr->ptbuf)),
- &pdata[len - tosend],
- nchar);
- card->chan[ch].nfree_tx_bd--;
- if ((i + 1) == nbuf) {
- /* This must be the last BD to be used */
- cpc_writeb(&ptdescr->status, DST_EOM);
- } else {
- cpc_writeb(&ptdescr->status, 0);
- }
- cpc_writew(&ptdescr->len, nchar);
- } else {
- CPC_TTY_DBG("%s: error in dma_buf_write\n",
- (st_cpc_tty_area *)dev->cpc_tty->name);
- stats->tx_dropped++;
- return 1;
- }
- tosend -= nchar;
- card->chan[ch].tx_next_bd =
- (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1);
- }
-
- if (dev->trace_on) {
- cpc_tty_trace(dev, buf, len,'T');
- }
-
- /* start transmission */
- CPC_TTY_DBG("%s: start transmission\n",
- (st_cpc_tty_area *)dev->cpc_tty->name);
-
- CPC_TTY_LOCK(card, flags);
- cpc_writeb(card->hw.scabase + DTX_REG(EDAL, ch),
- TX_BD_ADDR(ch, chan->tx_next_bd));
- cpc_writeb(card->hw.scabase + M_REG(CMD, ch), CMD_TX_ENA);
- cpc_writeb(card->hw.scabase + DSR_TX(ch), DSR_DE);
-
- if (card->hw.type == PC300_TE) {
- cpc_writeb(card->hw.falcbase + card->hw.cpld_reg2,
- cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) |
- (CPLD_REG2_FALC_LED1 << (2 * ch)));
- }
- CPC_TTY_UNLOCK(card, flags);
- return 0;
-}
-
-/*
- * PC300 TTY trace routine
- *
- * This routine send trace of connection to application.
- * o clear descriptors
- * o write data to DMA buffers
- * o start the transmission
- */
-
-static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx)
-{
- struct sk_buff *skb;
-
- if ((skb = dev_alloc_skb(10 + len)) == NULL) {
- /* out of memory */
- CPC_TTY_DBG("%s: tty_trace - out of memory\n", dev->dev->name);
- return;
- }
-
- skb_put (skb, 10 + len);
- skb->dev = dev->dev;
- skb->protocol = htons(ETH_P_CUST);
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_HOST;
- skb->len = 10 + len;
-
- skb_copy_to_linear_data(skb, dev->dev->name, 5);
- skb->data[5] = '[';
- skb->data[6] = rxtx;
- skb->data[7] = ']';
- skb->data[8] = ':';
- skb->data[9] = ' ';
- skb_copy_to_linear_data_offset(skb, 10, buf, len);
- netif_rx(skb);
-}
-
-/*
- * PC300 TTY unregister service routine
- *
- * This routine unregister one interface.
- */
-void cpc_tty_unregister_service(pc300dev_t *pc300dev)
-{
- st_cpc_tty_area *cpc_tty;
- ulong flags;
- int res;
-
- if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) {
- CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name);
- return;
- }
- CPC_TTY_DBG("%s: cpc_tty_unregister_service", cpc_tty->name);
-
- if (cpc_tty->pc300dev != pc300dev) {
- CPC_TTY_DBG("%s: invalid tty ptr=%s\n",
- pc300dev->dev->name, cpc_tty->name);
- return;
- }
-
- if (--cpc_tty_cnt == 0) {
- if (serial_drv.refcount) {
- CPC_TTY_DBG("%s: unregister is not possible, refcount=%d",
- cpc_tty->name, serial_drv.refcount);
- cpc_tty_cnt++;
- cpc_tty_unreg_flag = 1;
- return;
- } else {
- CPC_TTY_DBG("%s: unregister the tty driver\n", cpc_tty->name);
- if ((res=tty_unregister_driver(&serial_drv))) {
- CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
- cpc_tty->name,res);
- }
- }
- }
- CPC_TTY_LOCK(pc300dev->chan->card,flags);
- cpc_tty->tty = NULL;
- CPC_TTY_UNLOCK(pc300dev->chan->card, flags);
- cpc_tty->tty_minor = 0;
- cpc_tty->state = CPC_TTY_ST_IDLE;
-}
-
-/*
- * PC300 TTY trigger poll routine
- * This routine is called by pc300driver to treats Tx interrupt.
- */
-void cpc_tty_trigger_poll(pc300dev_t *pc300dev)
-{
- st_cpc_tty_area *cpc_tty = (st_cpc_tty_area *)pc300dev->cpc_tty;
- if (!cpc_tty) {
- return;
- }
- schedule_work(&(cpc_tty->tty_tx_work));
-}
diff --git a/drivers/staging/netlogic/Kconfig b/drivers/staging/netlogic/Kconfig
new file mode 100644
index 000000000000..d660de51b541
--- /dev/null
+++ b/drivers/staging/netlogic/Kconfig
@@ -0,0 +1,7 @@
+config NETLOGIC_XLR_NET
+ tristate "Netlogic XLR/XLS network device"
+ depends on CPU_XLR
+ select PHYLIB
+ ---help---
+ This driver support Netlogic XLR/XLS on chip gigabit
+ Ethernet.
diff --git a/drivers/staging/netlogic/Makefile b/drivers/staging/netlogic/Makefile
new file mode 100644
index 000000000000..f7355e3e9c4c
--- /dev/null
+++ b/drivers/staging/netlogic/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_NETLOGIC_XLR_NET) += xlr_net.o platform_net.o
diff --git a/drivers/staging/netlogic/TODO b/drivers/staging/netlogic/TODO
new file mode 100644
index 000000000000..08e6d5218b3b
--- /dev/null
+++ b/drivers/staging/netlogic/TODO
@@ -0,0 +1,12 @@
+* Implementing 64bit stat counter in software
+* All memory allocation should be changed to DMA allocations
+* All the netdev should be linked to single pdev as parent
+* Changing comments in to linux standred format
+
+Please send patches
+To:
+Ganesan Ramalingam <ganesanr@broadcom.com>
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc:
+Jayachandran Chandrashekaran Nair <jchandra@broadcom.com>
+
diff --git a/drivers/staging/netlogic/platform_net.c b/drivers/staging/netlogic/platform_net.c
new file mode 100644
index 000000000000..61f20e10d636
--- /dev/null
+++ b/drivers/staging/netlogic/platform_net.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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
+ * 1. Redistributions of source code must retain the above copyright
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/resource.h>
+#include <linux/phy.h>
+
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+#include <asm/netlogic/xlr/fmn.h>
+#include <asm/netlogic/xlr/xlr.h>
+#include <asm/netlogic/psb-bootinfo.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/iomap.h>
+
+#include "platform_net.h"
+
+/* Linux Net */
+#define MAX_NUM_GMAC 8
+#define MAX_NUM_XLS_GMAC 8
+#define MAX_NUM_XLR_GMAC 4
+
+
+static u32 xlr_gmac_offsets[] = {
+ NETLOGIC_IO_GMAC_0_OFFSET, NETLOGIC_IO_GMAC_1_OFFSET,
+ NETLOGIC_IO_GMAC_2_OFFSET, NETLOGIC_IO_GMAC_3_OFFSET,
+ NETLOGIC_IO_GMAC_4_OFFSET, NETLOGIC_IO_GMAC_5_OFFSET,
+ NETLOGIC_IO_GMAC_6_OFFSET, NETLOGIC_IO_GMAC_7_OFFSET
+};
+
+static u32 xlr_gmac_irqs[] = { PIC_GMAC_0_IRQ, PIC_GMAC_1_IRQ,
+ PIC_GMAC_2_IRQ, PIC_GMAC_3_IRQ,
+ PIC_GMAC_4_IRQ, PIC_GMAC_5_IRQ,
+ PIC_GMAC_6_IRQ, PIC_GMAC_7_IRQ
+};
+
+static struct xlr_net_data ndata[MAX_NUM_GMAC];
+static struct resource xlr_net_res[8][2];
+static struct platform_device xlr_net_dev[8];
+static u32 __iomem *gmac0_addr;
+static u32 __iomem *gmac4_addr;
+static u32 __iomem *gpio_addr;
+
+static void config_mac(struct xlr_net_data *nd, int phy, u32 __iomem *serdes,
+ u32 __iomem *pcs, int rfr, int tx, int *bkt_size,
+ struct xlr_fmn_info *gmac_fmn_info, int phy_addr)
+{
+ nd->cpu_mask = nlm_current_node()->coremask;
+ nd->phy_interface = phy;
+ nd->rfr_station = rfr;
+ nd->tx_stnid = tx;
+ nd->mii_addr = gmac0_addr;
+ nd->serdes_addr = serdes;
+ nd->pcs_addr = pcs;
+ nd->gpio_addr = gpio_addr;
+
+ nd->bucket_size = bkt_size;
+ nd->gmac_fmn_info = gmac_fmn_info;
+ nd->phy_addr = phy_addr;
+}
+
+static void net_device_init(int id, struct resource *res, int offset, int irq)
+{
+ res[0].name = "gmac";
+ res[0].start = CPHYSADDR(nlm_mmio_base(offset));
+ res[0].end = res[0].start + 0xfff;
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].name = "gmac";
+ res[1].start = irq;
+ res[1].end = irq;
+ res[1].flags = IORESOURCE_IRQ;
+
+ xlr_net_dev[id].name = "xlr-net";
+ xlr_net_dev[id].id = id;
+ xlr_net_dev[id].num_resources = 2;
+ xlr_net_dev[id].resource = res;
+ xlr_net_dev[id].dev.platform_data = &ndata[id];
+}
+
+static void xls_gmac_init(void)
+{
+ int mac;
+
+ gmac4_addr = ioremap(CPHYSADDR(
+ nlm_mmio_base(NETLOGIC_IO_GMAC_4_OFFSET)), 0xfff);
+ /* Passing GPIO base for serdes init. Only needed on sgmii ports*/
+ gpio_addr = ioremap(CPHYSADDR(
+ nlm_mmio_base(NETLOGIC_IO_GPIO_OFFSET)), 0xfff);
+
+ switch (nlm_prom_info.board_major_version) {
+ case 12:
+ /* first block RGMII or XAUI, use RGMII */
+ config_mac(&ndata[0],
+ PHY_INTERFACE_MODE_RGMII,
+ gmac0_addr, /* serdes */
+ gmac0_addr, /* pcs */
+ FMN_STNID_GMACRFR_0,
+ FMN_STNID_GMAC0_TX0,
+ xlr_board_fmn_config.bucket_size,
+ &xlr_board_fmn_config.gmac[0],
+ 0);
+
+ net_device_init(0, xlr_net_res[0], xlr_gmac_offsets[0],
+ xlr_gmac_irqs[0]);
+ platform_device_register(&xlr_net_dev[0]);
+
+ /* second block is XAUI, not supported yet */
+ break;
+ default:
+ /* default XLS config, all ports SGMII */
+ for (mac = 0; mac < 4; mac++) {
+ config_mac(&ndata[mac],
+ PHY_INTERFACE_MODE_SGMII,
+ gmac0_addr, /* serdes */
+ gmac0_addr, /* pcs */
+ FMN_STNID_GMACRFR_0,
+ FMN_STNID_GMAC0_TX0 + mac,
+ xlr_board_fmn_config.bucket_size,
+ &xlr_board_fmn_config.gmac[0],
+ /* PHY address according to chip/board */
+ mac + 0x10);
+
+ net_device_init(mac, xlr_net_res[mac],
+ xlr_gmac_offsets[mac],
+ xlr_gmac_irqs[mac]);
+ platform_device_register(&xlr_net_dev[mac]);
+ }
+
+ for (mac = 4; mac < MAX_NUM_XLS_GMAC; mac++) {
+ config_mac(&ndata[mac],
+ PHY_INTERFACE_MODE_SGMII,
+ gmac4_addr, /* serdes */
+ gmac4_addr, /* pcs */
+ FMN_STNID_GMAC1_FR_0,
+ FMN_STNID_GMAC1_TX0 + mac - 4,
+ xlr_board_fmn_config.bucket_size,
+ &xlr_board_fmn_config.gmac[1],
+ /* PHY address according to chip/board */
+ mac + 0x10);
+
+ net_device_init(mac, xlr_net_res[mac],
+ xlr_gmac_offsets[mac],
+ xlr_gmac_irqs[mac]);
+ platform_device_register(&xlr_net_dev[mac]);
+ }
+ }
+}
+
+static void xlr_gmac_init(void)
+{
+ int mac;
+
+ /* assume all GMACs for now */
+ for (mac = 0; mac < MAX_NUM_XLR_GMAC; mac++) {
+ config_mac(&ndata[mac],
+ PHY_INTERFACE_MODE_RGMII,
+ 0,
+ 0,
+ FMN_STNID_GMACRFR_0,
+ FMN_STNID_GMAC0_TX0,
+ xlr_board_fmn_config.bucket_size,
+ &xlr_board_fmn_config.gmac[0],
+ mac);
+
+ net_device_init(mac, xlr_net_res[mac], xlr_gmac_offsets[mac],
+ xlr_gmac_irqs[mac]);
+ platform_device_register(&xlr_net_dev[mac]);
+ }
+}
+
+static int __init xlr_net_init(void)
+{
+ gmac0_addr = ioremap(CPHYSADDR(
+ nlm_mmio_base(NETLOGIC_IO_GMAC_0_OFFSET)), 0xfff);
+
+ if (nlm_chip_is_xls())
+ xls_gmac_init();
+ else
+ xlr_gmac_init();
+
+ return 0;
+}
+
+arch_initcall(xlr_net_init);
diff --git a/drivers/staging/netlogic/platform_net.h b/drivers/staging/netlogic/platform_net.h
new file mode 100644
index 000000000000..29deeea72ca1
--- /dev/null
+++ b/drivers/staging/netlogic/platform_net.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+struct xlr_net_data {
+ int cpu_mask;
+ u32 __iomem *mii_addr;
+ u32 __iomem *serdes_addr;
+ u32 __iomem *pcs_addr;
+ u32 __iomem *gpio_addr;
+ int phy_interface;
+ int rfr_station;
+ int tx_stnid;
+ int *bucket_size;
+ int phy_addr;
+ struct xlr_fmn_info *gmac_fmn_info;
+};
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
new file mode 100644
index 000000000000..dd98cb1468a4
--- /dev/null
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -0,0 +1,1114 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/smp.h>
+#include <linux/ethtool.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/mipsregs.h>
+
+/* fmn.h - For FMN credit configuration and registering fmn_handler.
+ * FMN is communication mechanism that allows processing agents within
+ * XLR/XLS to communicate each other.
+ */
+#include <asm/netlogic/xlr/fmn.h>
+
+#include "platform_net.h"
+#include "xlr_net.h"
+
+/*
+ * The readl/writel implementation byteswaps on XLR/XLS, so
+ * we need to use __raw_ IO to read the NAE registers
+ * because they are in the big-endian MMIO area on the SoC.
+ */
+static inline void xlr_nae_wreg(u32 __iomem *base, unsigned int reg, u32 val)
+{
+ __raw_writel(val, base + reg);
+}
+
+static inline u32 xlr_nae_rdreg(u32 __iomem *base, unsigned int reg)
+{
+ return __raw_readl(base + reg);
+}
+
+static inline void xlr_reg_update(u32 *base_addr,
+ u32 off, u32 val, u32 mask)
+{
+ u32 tmp;
+
+ tmp = xlr_nae_rdreg(base_addr, off);
+ xlr_nae_wreg(base_addr, off, (tmp & ~mask) | (val & mask));
+}
+
+/*
+ * Table of net_device pointers indexed by port, this will be used to
+ * lookup the net_device corresponding to a port by the message ring handler.
+ *
+ * Maximum ports in XLR/XLS is 8(8 GMAC on XLS, 4 GMAC + 2 XGMAC on XLR)
+ */
+static struct net_device *mac_to_ndev[8];
+
+static inline struct sk_buff *mac_get_skb_back_ptr(void *addr)
+{
+ struct sk_buff **back_ptr;
+
+ /* this function should be used only for newly allocated packets.
+ * It assumes the first cacheline is for the back pointer related
+ * book keeping info.
+ */
+ back_ptr = (struct sk_buff **)(addr - MAC_SKB_BACK_PTR_SIZE);
+ return *back_ptr;
+}
+
+static inline void mac_put_skb_back_ptr(struct sk_buff *skb)
+{
+ struct sk_buff **back_ptr = (struct sk_buff **)skb->data;
+
+ /* this function should be used only for newly allocated packets.
+ * It assumes the first cacheline is for the back pointer related
+ * book keeping info.
+ */
+ skb_reserve(skb, MAC_SKB_BACK_PTR_SIZE);
+ *back_ptr = skb;
+}
+
+static int send_to_rfr_fifo(struct xlr_net_priv *priv, void *addr)
+{
+ struct nlm_fmn_msg msg;
+ int ret = 0, num_try = 0, stnid;
+ unsigned long paddr, mflags;
+
+ paddr = virt_to_bus(addr);
+ msg.msg0 = (u64)paddr & 0xffffffffe0ULL;
+ msg.msg1 = 0;
+ msg.msg2 = 0;
+ msg.msg3 = 0;
+ stnid = priv->nd->rfr_station;
+ do {
+ mflags = nlm_cop2_enable();
+ ret = nlm_fmn_send(1, 0, stnid, &msg);
+ nlm_cop2_restore(mflags);
+ if (ret == 0)
+ return 0;
+ } while (++num_try < 10000);
+
+ pr_err("Send to RFR failed in RX path\n");
+ return ret;
+}
+
+static inline struct sk_buff *xlr_alloc_skb(void)
+{
+ struct sk_buff *skb;
+
+ /* skb->data is cache aligned */
+ skb = alloc_skb(XLR_RX_BUF_SIZE, GFP_ATOMIC);
+ if (!skb) {
+ pr_err("SKB allocation failed\n");
+ return NULL;
+ }
+ mac_put_skb_back_ptr(skb);
+ return skb;
+}
+
+static void xlr_net_fmn_handler(int bkt, int src_stnid, int size,
+ int code, struct nlm_fmn_msg *msg, void *arg)
+{
+ struct sk_buff *skb, *skb_new = NULL;
+ struct net_device *ndev;
+ struct xlr_net_priv *priv;
+ u64 length, port;
+ void *addr;
+
+ length = (msg->msg0 >> 40) & 0x3fff;
+ if (length == 0) {
+ addr = bus_to_virt(msg->msg0 & 0xffffffffffULL);
+ dev_kfree_skb_any(addr);
+ } else if (length) {
+ addr = bus_to_virt(msg->msg0 & 0xffffffffe0ULL);
+ length = length - BYTE_OFFSET - MAC_CRC_LEN;
+ port = msg->msg0 & 0x0f;
+ if (src_stnid == FMN_STNID_GMAC1)
+ port = port + 4;
+ skb = mac_get_skb_back_ptr(addr);
+ skb->dev = mac_to_ndev[port];
+ ndev = skb->dev;
+ priv = netdev_priv(ndev);
+
+ /* 16 byte IP header align */
+ skb_reserve(skb, BYTE_OFFSET);
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ skb->dev->last_rx = jiffies;
+ netif_rx(skb);
+ /* Fill rx ring */
+ skb_new = xlr_alloc_skb();
+ if (skb_new)
+ send_to_rfr_fifo(priv, skb_new->data);
+ }
+ return;
+}
+
+/* Ethtool operation */
+static int xlr_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ if (!phydev)
+ return -ENODEV;
+ return phy_ethtool_gset(phydev, ecmd);
+}
+
+static int xlr_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ if (!phydev)
+ return -ENODEV;
+ return phy_ethtool_sset(phydev, ecmd);
+}
+
+static struct ethtool_ops xlr_ethtool_ops = {
+ .get_settings = xlr_get_settings,
+ .set_settings = xlr_set_settings,
+};
+
+/* Net operations */
+static int xlr_net_fill_rx_ring(struct net_device *ndev)
+{
+ struct sk_buff *skb;
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < MAX_FRIN_SPILL/2; i++) {
+ skb = xlr_alloc_skb();
+ if (!skb)
+ return -ENOMEM;
+ send_to_rfr_fifo(priv, skb->data);
+ }
+ pr_info("Rx ring setup done\n");
+ return 0;
+}
+
+static int xlr_net_open(struct net_device *ndev)
+{
+ u32 err;
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ /* schedule a link state check */
+ phy_start(phydev);
+
+ err = phy_start_aneg(phydev);
+ if (err) {
+ pr_err("Autoneg failed\n");
+ return err;
+ }
+
+ /* Setup the speed from PHY to internal reg*/
+ xlr_set_gmac_speed(priv);
+ netif_tx_start_all_queues(ndev);
+ return 0;
+}
+
+static int xlr_net_stop(struct net_device *ndev)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ phy_stop(phydev);
+ netif_tx_stop_all_queues(ndev);
+ return 0;
+}
+
+static void xlr_make_tx_desc(struct nlm_fmn_msg *msg, unsigned long addr,
+ struct sk_buff *skb)
+{
+ unsigned long physkb = virt_to_phys(skb);
+ int cpu_core = nlm_core_id();
+ int fr_stn_id = cpu_core * 8 + XLR_FB_STN; /* FB to 6th bucket */
+ msg->msg0 = (((u64)1 << 63) | /* End of packet descriptor */
+ ((u64)127 << 54) | /* No Free back */
+ (u64)skb->len << 40 | /* Length of data */
+ ((u64)addr));
+ msg->msg1 = (((u64)1 << 63) |
+ ((u64)fr_stn_id << 54) | /* Free back id */
+ (u64)0 << 40 | /* Set len to 0 */
+ ((u64)physkb & 0xffffffff)); /* 32bit address */
+ msg->msg2 = msg->msg3 = 0;
+}
+
+static void __maybe_unused xlr_wakeup_queue(unsigned long dev)
+{
+ struct net_device *ndev = (struct net_device *) dev;
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ if (phydev->link)
+ netif_tx_wake_queue(netdev_get_tx_queue(ndev, priv->wakeup_q));
+}
+
+static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ struct nlm_fmn_msg msg;
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ int ret;
+ u32 flags;
+
+ xlr_make_tx_desc(&msg, virt_to_phys(skb->data), skb);
+ flags = nlm_cop2_enable();
+ ret = nlm_fmn_send(2, 0, priv->nd->tx_stnid, &msg);
+ nlm_cop2_restore(flags);
+ if (ret)
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb)
+{
+ return (u16)smp_processor_id();
+}
+
+static void xlr_hw_set_mac_addr(struct net_device *ndev)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+
+ /* set mac station address */
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR0,
+ ((ndev->dev_addr[5] << 24) | (ndev->dev_addr[4] << 16) |
+ (ndev->dev_addr[3] << 8) | (ndev->dev_addr[2])));
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR0 + 1,
+ ((ndev->dev_addr[1] << 24) | (ndev->dev_addr[0] << 16)));
+
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR_MASK2, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR_MASK2 + 1, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR_MASK3, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_MAC_ADDR_MASK3 + 1, 0xffffffff);
+
+ xlr_nae_wreg(priv->base_addr, R_MAC_FILTER_CONFIG,
+ (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__MAC_ADDR0_VALID));
+
+ if (priv->nd->phy_interface == PHY_INTERFACE_MODE_RGMII ||
+ priv->nd->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ xlr_reg_update(priv->base_addr, R_IPG_IFG, MAC_B2B_IPG, 0x7f);
+}
+
+static int xlr_net_set_mac_addr(struct net_device *ndev, void *data)
+{
+ int err;
+
+ err = eth_mac_addr(ndev, data);
+ if (err)
+ return err;
+ xlr_hw_set_mac_addr(ndev);
+ return 0;
+}
+
+static void xlr_set_rx_mode(struct net_device *ndev)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ u32 regval;
+
+ regval = xlr_nae_rdreg(priv->base_addr, R_MAC_FILTER_CONFIG);
+
+ if (ndev->flags & IFF_PROMISC) {
+ regval |= (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN);
+ } else {
+ regval &= ~((1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN));
+ }
+
+ xlr_nae_wreg(priv->base_addr, R_MAC_FILTER_CONFIG, regval);
+}
+
+static void xlr_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+
+ stats->rx_packets = xlr_nae_rdreg(priv->base_addr, RX_PACKET_COUNTER);
+ stats->tx_packets = xlr_nae_rdreg(priv->base_addr, TX_PACKET_COUNTER);
+ stats->rx_bytes = xlr_nae_rdreg(priv->base_addr, RX_BYTE_COUNTER);
+ stats->tx_bytes = xlr_nae_rdreg(priv->base_addr, TX_BYTE_COUNTER);
+ stats->tx_errors = xlr_nae_rdreg(priv->base_addr, TX_FCS_ERROR_COUNTER);
+ stats->rx_dropped = xlr_nae_rdreg(priv->base_addr,
+ RX_DROP_PACKET_COUNTER);
+ stats->tx_dropped = xlr_nae_rdreg(priv->base_addr,
+ TX_DROP_FRAME_COUNTER);
+
+ stats->multicast = xlr_nae_rdreg(priv->base_addr,
+ RX_MULTICAST_PACKET_COUNTER);
+ stats->collisions = xlr_nae_rdreg(priv->base_addr,
+ TX_TOTAL_COLLISION_COUNTER);
+
+ stats->rx_length_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_FRAME_LENGTH_ERROR_COUNTER);
+ stats->rx_over_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_DROP_PACKET_COUNTER);
+ stats->rx_crc_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_FCS_ERROR_COUNTER);
+ stats->rx_frame_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_ALIGNMENT_ERROR_COUNTER);
+
+ stats->rx_fifo_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_DROP_PACKET_COUNTER);
+ stats->rx_missed_errors = xlr_nae_rdreg(priv->base_addr,
+ RX_CARRIER_SENSE_ERROR_COUNTER);
+
+ stats->rx_errors = (stats->rx_over_errors + stats->rx_crc_errors +
+ stats->rx_frame_errors + stats->rx_fifo_errors +
+ stats->rx_missed_errors);
+
+ stats->tx_aborted_errors = xlr_nae_rdreg(priv->base_addr,
+ TX_EXCESSIVE_COLLISION_PACKET_COUNTER);
+ stats->tx_carrier_errors = xlr_nae_rdreg(priv->base_addr,
+ TX_DROP_FRAME_COUNTER);
+ stats->tx_fifo_errors = xlr_nae_rdreg(priv->base_addr,
+ TX_DROP_FRAME_COUNTER);
+}
+
+static struct rtnl_link_stats64 *xlr_get_stats64(struct net_device *ndev,
+ struct rtnl_link_stats64 *stats)
+{
+ xlr_stats(ndev, stats);
+ return stats;
+}
+
+static struct net_device_ops xlr_netdev_ops = {
+ .ndo_open = xlr_net_open,
+ .ndo_stop = xlr_net_stop,
+ .ndo_start_xmit = xlr_net_start_xmit,
+ .ndo_select_queue = xlr_net_select_queue,
+ .ndo_set_mac_address = xlr_net_set_mac_addr,
+ .ndo_set_rx_mode = xlr_set_rx_mode,
+ .ndo_get_stats64 = xlr_get_stats64,
+};
+
+/* Gmac init */
+static void *xlr_config_spill(struct xlr_net_priv *priv, int reg_start_0,
+ int reg_start_1, int reg_size, int size)
+{
+ void *spill;
+ u32 *base;
+ unsigned long phys_addr;
+ u32 spill_size;
+
+ base = priv->base_addr;
+ spill_size = size;
+ spill = kmalloc(spill_size + SMP_CACHE_BYTES, GFP_ATOMIC);
+ if (!spill)
+ pr_err("Unable to allocate memory for spill area!\n");
+
+ spill = PTR_ALIGN(spill, SMP_CACHE_BYTES);
+ phys_addr = virt_to_phys(spill);
+ dev_dbg(&priv->ndev->dev, "Allocated spill %d bytes at %lx\n",
+ size, phys_addr);
+ xlr_nae_wreg(base, reg_start_0, (phys_addr >> 5) & 0xffffffff);
+ xlr_nae_wreg(base, reg_start_1, ((u64)phys_addr >> 37) & 0x07);
+ xlr_nae_wreg(base, reg_size, spill_size);
+
+ return spill;
+}
+
+/*
+ * Configure the 6 FIFO's that are used by the network accelarator to
+ * communicate with the rest of the XLx device. 4 of the FIFO's are for
+ * packets from NA --> cpu (called Class FIFO's) and 2 are for feeding
+ * the NA with free descriptors.
+ */
+static void xlr_config_fifo_spill_area(struct xlr_net_priv *priv)
+{
+ priv->frin_spill = xlr_config_spill(priv,
+ R_REG_FRIN_SPILL_MEM_START_0,
+ R_REG_FRIN_SPILL_MEM_START_1,
+ R_REG_FRIN_SPILL_MEM_SIZE,
+ MAX_FRIN_SPILL *
+ sizeof(u64));
+ priv->frout_spill = xlr_config_spill(priv,
+ R_FROUT_SPILL_MEM_START_0,
+ R_FROUT_SPILL_MEM_START_1,
+ R_FROUT_SPILL_MEM_SIZE,
+ MAX_FROUT_SPILL *
+ sizeof(u64));
+ priv->class_0_spill = xlr_config_spill(priv,
+ R_CLASS0_SPILL_MEM_START_0,
+ R_CLASS0_SPILL_MEM_START_1,
+ R_CLASS0_SPILL_MEM_SIZE,
+ MAX_CLASS_0_SPILL *
+ sizeof(u64));
+ priv->class_1_spill = xlr_config_spill(priv,
+ R_CLASS1_SPILL_MEM_START_0,
+ R_CLASS1_SPILL_MEM_START_1,
+ R_CLASS1_SPILL_MEM_SIZE,
+ MAX_CLASS_1_SPILL *
+ sizeof(u64));
+ priv->class_2_spill = xlr_config_spill(priv,
+ R_CLASS2_SPILL_MEM_START_0,
+ R_CLASS2_SPILL_MEM_START_1,
+ R_CLASS2_SPILL_MEM_SIZE,
+ MAX_CLASS_2_SPILL *
+ sizeof(u64));
+ priv->class_3_spill = xlr_config_spill(priv,
+ R_CLASS3_SPILL_MEM_START_0,
+ R_CLASS3_SPILL_MEM_START_1,
+ R_CLASS3_SPILL_MEM_SIZE,
+ MAX_CLASS_3_SPILL *
+ sizeof(u64));
+}
+
+/* Configure PDE to Round-Robin distribution of packets to the
+ * available cpu */
+static void xlr_config_pde(struct xlr_net_priv *priv)
+{
+ int i = 0;
+ u64 bkt_map = 0;
+
+ /* Each core has 8 buckets(station) */
+ for (i = 0; i < hweight32(priv->nd->cpu_mask); i++)
+ bkt_map |= (0xff << (i * 8));
+
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_0, (bkt_map & 0xffffffff));
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_0 + 1,
+ ((bkt_map >> 32) & 0xffffffff));
+
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_1, (bkt_map & 0xffffffff));
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_1 + 1,
+ ((bkt_map >> 32) & 0xffffffff));
+
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_2, (bkt_map & 0xffffffff));
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_2 + 1,
+ ((bkt_map >> 32) & 0xffffffff));
+
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_3, (bkt_map & 0xffffffff));
+ xlr_nae_wreg(priv->base_addr, R_PDE_CLASS_3 + 1,
+ ((bkt_map >> 32) & 0xffffffff));
+}
+
+/* Setup the Message ring credits, bucket size and other
+ * common configuration */
+static void xlr_config_common(struct xlr_net_priv *priv)
+{
+ struct xlr_fmn_info *gmac = priv->nd->gmac_fmn_info;
+ int start_stn_id = gmac->start_stn_id;
+ int end_stn_id = gmac->end_stn_id;
+ int *bucket_size = priv->nd->bucket_size;
+ int i, j;
+
+ /* Setting non-core MsgBktSize(0x321 - 0x325) */
+ for (i = start_stn_id; i <= end_stn_id; i++) {
+ xlr_nae_wreg(priv->base_addr,
+ R_GMAC_RFR0_BUCKET_SIZE + i - start_stn_id,
+ bucket_size[i]);
+ }
+
+ /* Setting non-core Credit counter register
+ * Distributing Gmac's credit to CPU's*/
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 8; j++)
+ xlr_nae_wreg(priv->base_addr,
+ (R_CC_CPU0_0 + (i * 8)) + j,
+ gmac->credit_config[(i * 8) + j]);
+ }
+
+ xlr_nae_wreg(priv->base_addr, R_MSG_TX_THRESHOLD, 3);
+ xlr_nae_wreg(priv->base_addr, R_DMACR0, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_DMACR1, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_DMACR2, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_DMACR3, 0xffffffff);
+ xlr_nae_wreg(priv->base_addr, R_FREEQCARVE, 0);
+
+ xlr_net_fill_rx_ring(priv->ndev);
+ nlm_register_fmn_handler(start_stn_id, end_stn_id, xlr_net_fmn_handler,
+ NULL);
+}
+
+static void xlr_config_translate_table(struct xlr_net_priv *priv)
+{
+ u32 cpu_mask;
+ u32 val;
+ int bkts[32]; /* one bucket is assumed for each cpu */
+ int b1, b2, c1, c2, i, j, k;
+ int use_bkt;
+
+ use_bkt = 0;
+ cpu_mask = priv->nd->cpu_mask;
+
+ pr_info("Using %s-based distribution\n",
+ (use_bkt) ? "bucket" : "class");
+ j = 0;
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) & cpu_mask) {
+ /* for each cpu, mark the 4+threadid bucket */
+ bkts[j] = ((i / 4) * 8) + (i % 4);
+ j++;
+ }
+ }
+
+ /*configure the 128 * 9 Translation table to send to available buckets*/
+ k = 0;
+ c1 = 3;
+ c2 = 0;
+ for (i = 0; i < 64; i++) {
+ /* On use_bkt set the b0, b1 are used, else
+ * the 4 classes are used, here implemented
+ * a logic to distribute the packets to the
+ * buckets equally or based on the class
+ */
+ c1 = (c1 + 1) & 3;
+ c2 = (c1 + 1) & 3;
+ b1 = bkts[k];
+ k = (k + 1) % j;
+ b2 = bkts[k];
+ k = (k + 1) % j;
+ val = ((c1 << 23) | (b1 << 17) | (use_bkt << 16) |
+ (c2 << 7) | (b2 << 1) | (use_bkt << 0));
+
+ val = ((c1 << 23) | (b1 << 17) | (use_bkt << 16) |
+ (c2 << 7) | (b2 << 1) | (use_bkt << 0));
+ dev_dbg(&priv->ndev->dev, "Table[%d] b1=%d b2=%d c1=%d c2=%d\n",
+ i, b1, b2, c1, c2);
+ xlr_nae_wreg(priv->base_addr, R_TRANSLATETABLE + i, val);
+ c1 = c2;
+ }
+}
+
+static void xlr_config_parser(struct xlr_net_priv *priv)
+{
+ u32 val;
+
+ /* Mark it as ETHERNET type */
+ xlr_nae_wreg(priv->base_addr, R_L2TYPE_0, 0x01);
+
+ /* Use 7bit CRChash for flow classification with 127 as CRC polynomial*/
+ xlr_nae_wreg(priv->base_addr, R_PARSERCONFIGREG,
+ ((0x7f << 8) | (1 << 1)));
+
+ /* configure the parser : L2 Type is configured in the bootloader */
+ /* extract IP: src, dest protocol */
+ xlr_nae_wreg(priv->base_addr, R_L3CTABLE,
+ (9 << 20) | (1 << 19) | (1 << 18) | (0x01 << 16) |
+ (0x0800 << 0));
+ xlr_nae_wreg(priv->base_addr, R_L3CTABLE + 1,
+ (9 << 25) | (1 << 21) | (12 << 14) | (4 << 10) |
+ (16 << 4) | 4);
+
+ /* Configure to extract SRC port and Dest port for TCP and UDP pkts */
+ xlr_nae_wreg(priv->base_addr, R_L4CTABLE, 6);
+ xlr_nae_wreg(priv->base_addr, R_L4CTABLE + 2, 17);
+ val = ((0 << 21) | (2 << 17) | (2 << 11) | (2 << 7));
+ xlr_nae_wreg(priv->base_addr, R_L4CTABLE + 1, val);
+ xlr_nae_wreg(priv->base_addr, R_L4CTABLE + 3, val);
+
+ xlr_config_translate_table(priv);
+}
+
+static int xlr_phy_write(u32 *base_addr, int phy_addr, int regnum, u16 val)
+{
+ unsigned long timeout, stoptime, checktime;
+ int timedout;
+
+ /* 100ms timeout*/
+ timeout = msecs_to_jiffies(100);
+ stoptime = jiffies + timeout;
+ timedout = 0;
+
+ xlr_nae_wreg(base_addr, R_MII_MGMT_ADDRESS, (phy_addr << 8) | regnum);
+
+ /* Write the data which starts the write cycle */
+ xlr_nae_wreg(base_addr, R_MII_MGMT_WRITE_DATA, (u32) val);
+
+ /* poll for the read cycle to complete */
+ while (!timedout) {
+ checktime = jiffies;
+ if (xlr_nae_rdreg(base_addr, R_MII_MGMT_INDICATORS) == 0)
+ break;
+ timedout = time_after(checktime, stoptime);
+ }
+ if (timedout) {
+ pr_info("Phy device write err: device busy");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int xlr_phy_read(u32 *base_addr, int phy_addr, int regnum)
+{
+ unsigned long timeout, stoptime, checktime;
+ int timedout;
+
+ /* 100ms timeout*/
+ timeout = msecs_to_jiffies(100);
+ stoptime = jiffies + timeout;
+ timedout = 0;
+
+ /* setup the phy reg to be used */
+ xlr_nae_wreg(base_addr, R_MII_MGMT_ADDRESS,
+ (phy_addr << 8) | (regnum << 0));
+
+ /* Issue the read command */
+ xlr_nae_wreg(base_addr, R_MII_MGMT_COMMAND,
+ (1 << O_MII_MGMT_COMMAND__rstat));
+
+
+ /* poll for the read cycle to complete */
+ while (!timedout) {
+ checktime = jiffies;
+ if (xlr_nae_rdreg(base_addr, R_MII_MGMT_INDICATORS) == 0)
+ break;
+ timedout = time_after(checktime, stoptime);
+ }
+ if (timedout) {
+ pr_info("Phy device read err: device busy");
+ return -EBUSY;
+ }
+
+ /* clear the read cycle */
+ xlr_nae_wreg(base_addr, R_MII_MGMT_COMMAND, 0);
+
+ /* Read the data */
+ return xlr_nae_rdreg(base_addr, R_MII_MGMT_STATUS);
+}
+
+static int xlr_mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 val)
+{
+ struct xlr_net_priv *priv = bus->priv;
+ int ret;
+
+ ret = xlr_phy_write(priv->mii_addr, phy_addr, regnum, val);
+ dev_dbg(&priv->ndev->dev, "mii_write phy %d : %d <- %x [%x]\n",
+ phy_addr, regnum, val, ret);
+ return ret;
+}
+
+static int xlr_mii_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+ struct xlr_net_priv *priv = bus->priv;
+ int ret;
+
+ ret = xlr_phy_read(priv->mii_addr, phy_addr, regnum);
+ dev_dbg(&priv->ndev->dev, "mii_read phy %d : %d [%x]\n",
+ phy_addr, regnum, ret);
+ return ret;
+}
+
+/* XLR ports are RGMII. XLS ports are SGMII mostly except the port0,
+ * which can be configured either SGMII or RGMII, considered SGMII
+ * by default, if board setup to RGMII the port_type need to set
+ * accordingly.Serdes and PCS layer need to configured for SGMII
+ */
+static void xlr_sgmii_init(struct xlr_net_priv *priv)
+{
+ int phy;
+
+ xlr_phy_write(priv->serdes_addr, 26, 0, 0x6DB0);
+ xlr_phy_write(priv->serdes_addr, 26, 1, 0xFFFF);
+ xlr_phy_write(priv->serdes_addr, 26, 2, 0xB6D0);
+ xlr_phy_write(priv->serdes_addr, 26, 3, 0x00FF);
+ xlr_phy_write(priv->serdes_addr, 26, 4, 0x0000);
+ xlr_phy_write(priv->serdes_addr, 26, 5, 0x0000);
+ xlr_phy_write(priv->serdes_addr, 26, 6, 0x0005);
+ xlr_phy_write(priv->serdes_addr, 26, 7, 0x0001);
+ xlr_phy_write(priv->serdes_addr, 26, 8, 0x0000);
+ xlr_phy_write(priv->serdes_addr, 26, 9, 0x0000);
+ xlr_phy_write(priv->serdes_addr, 26, 10, 0x0000);
+
+ /* program GPIO values for serdes init parameters */
+ xlr_nae_wreg(priv->gpio_addr, 0x20, 0x7e6802);
+ xlr_nae_wreg(priv->gpio_addr, 0x10, 0x7104);
+
+ xlr_nae_wreg(priv->gpio_addr, 0x22, 0x7e6802);
+ xlr_nae_wreg(priv->gpio_addr, 0x21, 0x7104);
+
+ /* enable autoneg - more magic */
+ phy = priv->port_id % 4 + 27;
+ xlr_phy_write(priv->pcs_addr, phy, 0, 0x1000);
+ xlr_phy_write(priv->pcs_addr, phy, 0, 0x0200);
+}
+
+void xlr_set_gmac_speed(struct xlr_net_priv *priv)
+{
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+ int speed;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
+ xlr_sgmii_init(priv);
+
+ if (phydev->speed != priv->phy_speed) {
+ pr_info("change %d to %d\n", priv->phy_speed, phydev->speed);
+ speed = phydev->speed;
+ if (speed == SPEED_1000) {
+ /* Set interface to Byte mode */
+ xlr_nae_wreg(priv->base_addr, R_MAC_CONFIG_2, 0x7217);
+ priv->phy_speed = speed;
+ } else if (speed == SPEED_100 || speed == SPEED_10) {
+ /* Set interface to Nibble mode */
+ xlr_nae_wreg(priv->base_addr, R_MAC_CONFIG_2, 0x7117);
+ priv->phy_speed = speed;
+ }
+ /* Set SGMII speed in Interface controll reg */
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ if (speed == SPEED_10)
+ xlr_nae_wreg(priv->base_addr,
+ R_INTERFACE_CONTROL, SGMII_SPEED_10);
+ if (speed == SPEED_100)
+ xlr_nae_wreg(priv->base_addr,
+ R_INTERFACE_CONTROL, SGMII_SPEED_100);
+ if (speed == SPEED_1000)
+ xlr_nae_wreg(priv->base_addr,
+ R_INTERFACE_CONTROL, SGMII_SPEED_1000);
+ }
+ if (speed == SPEED_10)
+ xlr_nae_wreg(priv->base_addr, R_CORECONTROL, 0x2);
+ if (speed == SPEED_100)
+ xlr_nae_wreg(priv->base_addr, R_CORECONTROL, 0x1);
+ if (speed == SPEED_1000)
+ xlr_nae_wreg(priv->base_addr, R_CORECONTROL, 0x0);
+ }
+ pr_info("gmac%d : %dMbps\n", priv->port_id, priv->phy_speed);
+}
+
+static void xlr_gmac_link_adjust(struct net_device *ndev)
+{
+ struct xlr_net_priv *priv = netdev_priv(ndev);
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+ u32 intreg;
+
+ intreg = xlr_nae_rdreg(priv->base_addr, R_INTREG);
+ if (phydev->link) {
+ if (phydev->speed != priv->phy_speed) {
+ pr_info("gmac%d : Link up\n", priv->port_id);
+ xlr_set_gmac_speed(priv);
+ }
+ } else {
+ pr_info("gmac%d : Link down\n", priv->port_id);
+ xlr_set_gmac_speed(priv);
+ }
+}
+
+static int xlr_mii_probe(struct xlr_net_priv *priv)
+{
+ struct phy_device *phydev = priv->mii_bus->phy_map[priv->phy_addr];
+
+ if (!phydev) {
+ pr_err("no PHY found on phy_addr %d\n", priv->phy_addr);
+ return -ENODEV;
+ }
+
+ /* Attach MAC to PHY */
+ phydev = phy_connect(priv->ndev, dev_name(&phydev->dev),
+ &xlr_gmac_link_adjust, priv->nd->phy_interface);
+
+ if (IS_ERR(phydev)) {
+ pr_err("could not attach PHY\n");
+ return PTR_ERR(phydev);
+ }
+ phydev->supported &= (ADVERTISED_10baseT_Full
+ | ADVERTISED_10baseT_Half
+ | ADVERTISED_100baseT_Full
+ | ADVERTISED_100baseT_Half
+ | ADVERTISED_1000baseT_Full
+ | ADVERTISED_Autoneg
+ | ADVERTISED_MII);
+
+ phydev->advertising = phydev->supported;
+ pr_info("attached PHY driver [%s] (mii_bus:phy_addr=%s\n",
+ phydev->drv->name, dev_name(&phydev->dev));
+ return 0;
+}
+
+static int xlr_setup_mdio(struct xlr_net_priv *priv,
+ struct platform_device *pdev)
+{
+ int err;
+
+ priv->phy_addr = priv->nd->phy_addr;
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ pr_err("mdiobus alloc failed\n");
+ return -ENOMEM;
+ }
+
+ priv->mii_bus->priv = priv;
+ priv->mii_bus->name = "xlr-mdio";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%d",
+ priv->mii_bus->name, priv->port_id);
+ priv->mii_bus->read = xlr_mii_read;
+ priv->mii_bus->write = xlr_mii_write;
+ priv->mii_bus->parent = &pdev->dev;
+ priv->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ priv->mii_bus->irq[priv->phy_addr] = priv->ndev->irq;
+
+ /* Scan only the enabled address */
+ priv->mii_bus->phy_mask = ~(1 << priv->phy_addr);
+
+ /* setting clock divisor to 54 */
+ xlr_nae_wreg(priv->base_addr, R_MII_MGMT_CONFIG, 0x7);
+
+ err = mdiobus_register(priv->mii_bus);
+ if (err) {
+ mdiobus_free(priv->mii_bus);
+ pr_err("mdio bus registration failed\n");
+ return err;
+ }
+
+ pr_info("Registerd mdio bus id : %s\n", priv->mii_bus->id);
+ err = xlr_mii_probe(priv);
+ if (err) {
+ mdiobus_free(priv->mii_bus);
+ return err;
+ }
+ return 0;
+}
+
+static void xlr_port_enable(struct xlr_net_priv *priv)
+{
+ u32 prid = (read_c0_prid() & 0xf000);
+
+ /* Setup MAC_CONFIG reg if (xls & rgmii) */
+ if ((prid == 0x8000 || prid == 0x4000 || prid == 0xc000) &&
+ priv->nd->phy_interface == PHY_INTERFACE_MODE_RGMII)
+ xlr_reg_update(priv->base_addr, R_RX_CONTROL,
+ (1 << O_RX_CONTROL__RGMII), (1 << O_RX_CONTROL__RGMII));
+
+ /* Rx Tx enable */
+ xlr_reg_update(priv->base_addr, R_MAC_CONFIG_1,
+ ((1 << O_MAC_CONFIG_1__rxen) | (1 << O_MAC_CONFIG_1__txen) |
+ (1 << O_MAC_CONFIG_1__rxfc) | (1 << O_MAC_CONFIG_1__txfc)),
+ ((1 << O_MAC_CONFIG_1__rxen) | (1 << O_MAC_CONFIG_1__txen) |
+ (1 << O_MAC_CONFIG_1__rxfc) | (1 << O_MAC_CONFIG_1__txfc)));
+
+ /* Setup tx control reg */
+ xlr_reg_update(priv->base_addr, R_TX_CONTROL,
+ ((1 << O_TX_CONTROL__TxEnable) |
+ (512 << O_TX_CONTROL__TxThreshold)), 0x3fff);
+
+ /* Setup rx control reg */
+ xlr_reg_update(priv->base_addr, R_RX_CONTROL,
+ 1 << O_RX_CONTROL__RxEnable, 1 << O_RX_CONTROL__RxEnable);
+}
+
+static void xlr_port_disable(struct xlr_net_priv *priv)
+{
+ /* Setup MAC_CONFIG reg */
+ /* Rx Tx disable*/
+ xlr_reg_update(priv->base_addr, R_MAC_CONFIG_1,
+ ((1 << O_MAC_CONFIG_1__rxen) | (1 << O_MAC_CONFIG_1__txen) |
+ (1 << O_MAC_CONFIG_1__rxfc) | (1 << O_MAC_CONFIG_1__txfc)),
+ 0x0);
+
+ /* Setup tx control reg */
+ xlr_reg_update(priv->base_addr, R_TX_CONTROL,
+ ((1 << O_TX_CONTROL__TxEnable) |
+ (512 << O_TX_CONTROL__TxThreshold)), 0);
+
+ /* Setup rx control reg */
+ xlr_reg_update(priv->base_addr, R_RX_CONTROL,
+ 1 << O_RX_CONTROL__RxEnable, 0);
+}
+
+/* Initialization of gmac */
+static int xlr_gmac_init(struct xlr_net_priv *priv,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ pr_info("Initializing the gmac%d\n", priv->port_id);
+
+ xlr_port_disable(priv);
+ xlr_nae_wreg(priv->base_addr, R_DESC_PACK_CTRL,
+ (1 << O_DESC_PACK_CTRL__MaxEntry)
+ | (BYTE_OFFSET << O_DESC_PACK_CTRL__ByteOffset)
+ | (1600 << O_DESC_PACK_CTRL__RegularSize));
+
+ ret = xlr_setup_mdio(priv, pdev);
+ if (ret)
+ return ret;
+ xlr_port_enable(priv);
+
+ /* Enable Full-duplex/1000Mbps/CRC */
+ xlr_nae_wreg(priv->base_addr, R_MAC_CONFIG_2, 0x7217);
+ /* speed 2.5Mhz */
+ xlr_nae_wreg(priv->base_addr, R_CORECONTROL, 0x02);
+ /* Setup Interrupt mask reg */
+ xlr_nae_wreg(priv->base_addr, R_INTMASK,
+ (1 << O_INTMASK__TxIllegal) |
+ (1 << O_INTMASK__MDInt) |
+ (1 << O_INTMASK__TxFetchError) |
+ (1 << O_INTMASK__P2PSpillEcc) |
+ (1 << O_INTMASK__TagFull) |
+ (1 << O_INTMASK__Underrun) |
+ (1 << O_INTMASK__Abort)
+ );
+
+ /* Clear all stats */
+ xlr_reg_update(priv->base_addr, R_STATCTRL,
+ 0, 1 << O_STATCTRL__ClrCnt);
+ xlr_reg_update(priv->base_addr, R_STATCTRL,
+ 1 << O_STATCTRL__ClrCnt, 1 << O_STATCTRL__ClrCnt);
+ return 0;
+}
+
+static int xlr_net_probe(struct platform_device *pdev)
+{
+ struct xlr_net_priv *priv = NULL;
+ struct net_device *ndev;
+ struct resource *res;
+ int mac, err;
+
+ mac = pdev->id;
+ ndev = alloc_etherdev_mq(sizeof(struct xlr_net_priv), 32);
+ if (!ndev) {
+ pr_err("Allocation of Ethernet device failed\n");
+ return -ENOMEM;
+ }
+
+ priv = netdev_priv(ndev);
+ priv->pdev = pdev;
+ priv->ndev = ndev;
+ priv->port_id = mac;
+ priv->nd = (struct xlr_net_data *)pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ pr_err("No memory resource for MAC %d\n", mac);
+ err = -ENODEV;
+ goto err_gmac;
+ }
+
+ ndev->base_addr = (unsigned long) devm_request_and_ioremap
+ (&pdev->dev, res);
+ if (!ndev->base_addr) {
+ dev_err(&pdev->dev,
+ "devm_request_and_ioremap failed\n");
+ return -EBUSY;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ pr_err("No irq resource for MAC %d\n", mac);
+ err = -ENODEV;
+ goto err_gmac;
+ }
+ ndev->irq = res->start;
+
+ priv->mii_addr = priv->nd->mii_addr;
+ priv->serdes_addr = priv->nd->serdes_addr;
+ priv->pcs_addr = priv->nd->pcs_addr;
+ priv->gpio_addr = priv->nd->gpio_addr;
+ priv->base_addr = (u32 *) ndev->base_addr;
+
+ mac_to_ndev[mac] = ndev;
+ ndev->netdev_ops = &xlr_netdev_ops;
+ ndev->watchdog_timeo = HZ;
+
+ /* Setup Mac address and Rx mode */
+ eth_hw_addr_random(ndev);
+ xlr_hw_set_mac_addr(ndev);
+ xlr_set_rx_mode(ndev);
+
+ priv->num_rx_desc += MAX_NUM_DESC_SPILL;
+ SET_ETHTOOL_OPS(ndev, &xlr_ethtool_ops);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ /* Common registers, do one time initialization */
+ if (mac == 0 || mac == 4) {
+ xlr_config_fifo_spill_area(priv);
+ /* Configure PDE to Round-Robin pkt distribution */
+ xlr_config_pde(priv);
+ xlr_config_parser(priv);
+ }
+ /* Call init with respect to port */
+ if (strcmp(res->name, "gmac") == 0) {
+ err = xlr_gmac_init(priv, pdev);
+ if (err) {
+ pr_err("gmac%d init failed\n", mac);
+ goto err_gmac;
+ }
+ }
+
+ if (mac == 0 || mac == 4)
+ xlr_config_common(priv);
+
+ err = register_netdev(ndev);
+ if (err)
+ goto err_netdev;
+ platform_set_drvdata(pdev, priv);
+ return 0;
+
+err_netdev:
+ mdiobus_free(priv->mii_bus);
+err_gmac:
+ free_netdev(ndev);
+ return err;
+}
+
+static int xlr_net_remove(struct platform_device *pdev)
+{
+ struct xlr_net_priv *priv = platform_get_drvdata(pdev);
+ unregister_netdev(priv->ndev);
+ mdiobus_unregister(priv->mii_bus);
+ mdiobus_free(priv->mii_bus);
+ free_netdev(priv->ndev);
+ return 0;
+}
+
+static struct platform_driver xlr_net_driver = {
+ .probe = xlr_net_probe,
+ .remove = xlr_net_remove,
+ .driver = {
+ .name = "xlr-net",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(xlr_net_driver);
+
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>");
+MODULE_DESCRIPTION("Ethernet driver for Netlogic XLR/XLS");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:xlr-net");
diff --git a/drivers/staging/netlogic/xlr_net.h b/drivers/staging/netlogic/xlr_net.h
new file mode 100644
index 000000000000..f91d27e9d7c4
--- /dev/null
+++ b/drivers/staging/netlogic/xlr_net.h
@@ -0,0 +1,1099 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/* #define MAC_SPLIT_MODE */
+
+#define MAC_SPACING 0x400
+#define XGMAC_SPACING 0x400
+
+/* PE-MCXMAC register and bit field definitions */
+#define R_MAC_CONFIG_1 0x00
+#define O_MAC_CONFIG_1__srst 31
+#define O_MAC_CONFIG_1__simr 30
+#define O_MAC_CONFIG_1__hrrmc 18
+#define W_MAC_CONFIG_1__hrtmc 2
+#define O_MAC_CONFIG_1__hrrfn 16
+#define W_MAC_CONFIG_1__hrtfn 2
+#define O_MAC_CONFIG_1__intlb 8
+#define O_MAC_CONFIG_1__rxfc 5
+#define O_MAC_CONFIG_1__txfc 4
+#define O_MAC_CONFIG_1__srxen 3
+#define O_MAC_CONFIG_1__rxen 2
+#define O_MAC_CONFIG_1__stxen 1
+#define O_MAC_CONFIG_1__txen 0
+#define R_MAC_CONFIG_2 0x01
+#define O_MAC_CONFIG_2__prlen 12
+#define W_MAC_CONFIG_2__prlen 4
+#define O_MAC_CONFIG_2__speed 8
+#define W_MAC_CONFIG_2__speed 2
+#define O_MAC_CONFIG_2__hugen 5
+#define O_MAC_CONFIG_2__flchk 4
+#define O_MAC_CONFIG_2__crce 1
+#define O_MAC_CONFIG_2__fulld 0
+#define R_IPG_IFG 0x02
+#define O_IPG_IFG__ipgr1 24
+#define W_IPG_IFG__ipgr1 7
+#define O_IPG_IFG__ipgr2 16
+#define W_IPG_IFG__ipgr2 7
+#define O_IPG_IFG__mifg 8
+#define W_IPG_IFG__mifg 8
+#define O_IPG_IFG__ipgt 0
+#define W_IPG_IFG__ipgt 7
+#define R_HALF_DUPLEX 0x03
+#define O_HALF_DUPLEX__abebt 24
+#define W_HALF_DUPLEX__abebt 4
+#define O_HALF_DUPLEX__abebe 19
+#define O_HALF_DUPLEX__bpnb 18
+#define O_HALF_DUPLEX__nobo 17
+#define O_HALF_DUPLEX__edxsdfr 16
+#define O_HALF_DUPLEX__retry 12
+#define W_HALF_DUPLEX__retry 4
+#define O_HALF_DUPLEX__lcol 0
+#define W_HALF_DUPLEX__lcol 10
+#define R_MAXIMUM_FRAME_LENGTH 0x04
+#define O_MAXIMUM_FRAME_LENGTH__maxf 0
+#define W_MAXIMUM_FRAME_LENGTH__maxf 16
+#define R_TEST 0x07
+#define O_TEST__mbof 3
+#define O_TEST__rthdf 2
+#define O_TEST__tpause 1
+#define O_TEST__sstct 0
+#define R_MII_MGMT_CONFIG 0x08
+#define O_MII_MGMT_CONFIG__scinc 5
+#define O_MII_MGMT_CONFIG__spre 4
+#define O_MII_MGMT_CONFIG__clks 3
+#define W_MII_MGMT_CONFIG__clks 3
+#define R_MII_MGMT_COMMAND 0x09
+#define O_MII_MGMT_COMMAND__scan 1
+#define O_MII_MGMT_COMMAND__rstat 0
+#define R_MII_MGMT_ADDRESS 0x0A
+#define O_MII_MGMT_ADDRESS__fiad 8
+#define W_MII_MGMT_ADDRESS__fiad 5
+#define O_MII_MGMT_ADDRESS__fgad 5
+#define W_MII_MGMT_ADDRESS__fgad 0
+#define R_MII_MGMT_WRITE_DATA 0x0B
+#define O_MII_MGMT_WRITE_DATA__ctld 0
+#define W_MII_MGMT_WRITE_DATA__ctld 16
+#define R_MII_MGMT_STATUS 0x0C
+#define R_MII_MGMT_INDICATORS 0x0D
+#define O_MII_MGMT_INDICATORS__nvalid 2
+#define O_MII_MGMT_INDICATORS__scan 1
+#define O_MII_MGMT_INDICATORS__busy 0
+#define R_INTERFACE_CONTROL 0x0E
+#define O_INTERFACE_CONTROL__hrstint 31
+#define O_INTERFACE_CONTROL__tbimode 27
+#define O_INTERFACE_CONTROL__ghdmode 26
+#define O_INTERFACE_CONTROL__lhdmode 25
+#define O_INTERFACE_CONTROL__phymod 24
+#define O_INTERFACE_CONTROL__hrrmi 23
+#define O_INTERFACE_CONTROL__rspd 16
+#define O_INTERFACE_CONTROL__hr100 15
+#define O_INTERFACE_CONTROL__frcq 10
+#define O_INTERFACE_CONTROL__nocfr 9
+#define O_INTERFACE_CONTROL__dlfct 8
+#define O_INTERFACE_CONTROL__enjab 0
+#define R_INTERFACE_STATUS 0x0F
+#define O_INTERFACE_STATUS__xsdfr 9
+#define O_INTERFACE_STATUS__ssrr 8
+#define W_INTERFACE_STATUS__ssrr 5
+#define O_INTERFACE_STATUS__miilf 3
+#define O_INTERFACE_STATUS__locar 2
+#define O_INTERFACE_STATUS__sqerr 1
+#define O_INTERFACE_STATUS__jabber 0
+#define R_STATION_ADDRESS_LS 0x10
+#define R_STATION_ADDRESS_MS 0x11
+
+/* A-XGMAC register and bit field definitions */
+#define R_XGMAC_CONFIG_0 0x00
+#define O_XGMAC_CONFIG_0__hstmacrst 31
+#define O_XGMAC_CONFIG_0__hstrstrctl 23
+#define O_XGMAC_CONFIG_0__hstrstrfn 22
+#define O_XGMAC_CONFIG_0__hstrsttctl 18
+#define O_XGMAC_CONFIG_0__hstrsttfn 17
+#define O_XGMAC_CONFIG_0__hstrstmiim 16
+#define O_XGMAC_CONFIG_0__hstloopback 8
+#define R_XGMAC_CONFIG_1 0x01
+#define O_XGMAC_CONFIG_1__hsttctlen 31
+#define O_XGMAC_CONFIG_1__hsttfen 30
+#define O_XGMAC_CONFIG_1__hstrctlen 29
+#define O_XGMAC_CONFIG_1__hstrfen 28
+#define O_XGMAC_CONFIG_1__tfen 26
+#define O_XGMAC_CONFIG_1__rfen 24
+#define O_XGMAC_CONFIG_1__hstrctlshrtp 12
+#define O_XGMAC_CONFIG_1__hstdlyfcstx 10
+#define W_XGMAC_CONFIG_1__hstdlyfcstx 2
+#define O_XGMAC_CONFIG_1__hstdlyfcsrx 8
+#define W_XGMAC_CONFIG_1__hstdlyfcsrx 2
+#define O_XGMAC_CONFIG_1__hstppen 7
+#define O_XGMAC_CONFIG_1__hstbytswp 6
+#define O_XGMAC_CONFIG_1__hstdrplt64 5
+#define O_XGMAC_CONFIG_1__hstprmscrx 4
+#define O_XGMAC_CONFIG_1__hstlenchk 3
+#define O_XGMAC_CONFIG_1__hstgenfcs 2
+#define O_XGMAC_CONFIG_1__hstpadmode 0
+#define W_XGMAC_CONFIG_1__hstpadmode 2
+#define R_XGMAC_CONFIG_2 0x02
+#define O_XGMAC_CONFIG_2__hsttctlfrcp 31
+#define O_XGMAC_CONFIG_2__hstmlnkflth 27
+#define O_XGMAC_CONFIG_2__hstalnkflth 26
+#define O_XGMAC_CONFIG_2__rflnkflt 24
+#define W_XGMAC_CONFIG_2__rflnkflt 2
+#define O_XGMAC_CONFIG_2__hstipgextmod 16
+#define W_XGMAC_CONFIG_2__hstipgextmod 5
+#define O_XGMAC_CONFIG_2__hstrctlfrcp 15
+#define O_XGMAC_CONFIG_2__hstipgexten 5
+#define O_XGMAC_CONFIG_2__hstmipgext 0
+#define W_XGMAC_CONFIG_2__hstmipgext 5
+#define R_XGMAC_CONFIG_3 0x03
+#define O_XGMAC_CONFIG_3__hstfltrfrm 31
+#define W_XGMAC_CONFIG_3__hstfltrfrm 16
+#define O_XGMAC_CONFIG_3__hstfltrfrmdc 15
+#define W_XGMAC_CONFIG_3__hstfltrfrmdc 16
+#define R_XGMAC_STATION_ADDRESS_LS 0x04
+#define O_XGMAC_STATION_ADDRESS_LS__hstmacadr0 0
+#define W_XGMAC_STATION_ADDRESS_LS__hstmacadr0 32
+#define R_XGMAC_STATION_ADDRESS_MS 0x05
+#define R_XGMAC_MAX_FRAME_LEN 0x08
+#define O_XGMAC_MAX_FRAME_LEN__hstmxfrmwctx 16
+#define W_XGMAC_MAX_FRAME_LEN__hstmxfrmwctx 14
+#define O_XGMAC_MAX_FRAME_LEN__hstmxfrmbcrx 0
+#define W_XGMAC_MAX_FRAME_LEN__hstmxfrmbcrx 16
+#define R_XGMAC_REV_LEVEL 0x0B
+#define O_XGMAC_REV_LEVEL__revlvl 0
+#define W_XGMAC_REV_LEVEL__revlvl 15
+#define R_XGMAC_MIIM_COMMAND 0x10
+#define O_XGMAC_MIIM_COMMAND__hstldcmd 3
+#define O_XGMAC_MIIM_COMMAND__hstmiimcmd 0
+#define W_XGMAC_MIIM_COMMAND__hstmiimcmd 3
+#define R_XGMAC_MIIM_FILED 0x11
+#define O_XGMAC_MIIM_FILED__hststfield 30
+#define W_XGMAC_MIIM_FILED__hststfield 2
+#define O_XGMAC_MIIM_FILED__hstopfield 28
+#define W_XGMAC_MIIM_FILED__hstopfield 2
+#define O_XGMAC_MIIM_FILED__hstphyadx 23
+#define W_XGMAC_MIIM_FILED__hstphyadx 5
+#define O_XGMAC_MIIM_FILED__hstregadx 18
+#define W_XGMAC_MIIM_FILED__hstregadx 5
+#define O_XGMAC_MIIM_FILED__hsttafield 16
+#define W_XGMAC_MIIM_FILED__hsttafield 2
+#define O_XGMAC_MIIM_FILED__miimrddat 0
+#define W_XGMAC_MIIM_FILED__miimrddat 16
+#define R_XGMAC_MIIM_CONFIG 0x12
+#define O_XGMAC_MIIM_CONFIG__hstnopram 7
+#define O_XGMAC_MIIM_CONFIG__hstclkdiv 0
+#define W_XGMAC_MIIM_CONFIG__hstclkdiv 7
+#define R_XGMAC_MIIM_LINK_FAIL_VECTOR 0x13
+#define O_XGMAC_MIIM_LINK_FAIL_VECTOR__miimlfvec 0
+#define W_XGMAC_MIIM_LINK_FAIL_VECTOR__miimlfvec 32
+#define R_XGMAC_MIIM_INDICATOR 0x14
+#define O_XGMAC_MIIM_INDICATOR__miimphylf 4
+#define O_XGMAC_MIIM_INDICATOR__miimmoncplt 3
+#define O_XGMAC_MIIM_INDICATOR__miimmonvld 2
+#define O_XGMAC_MIIM_INDICATOR__miimmon 1
+#define O_XGMAC_MIIM_INDICATOR__miimbusy 0
+
+/* GMAC stats registers */
+#define R_RBYT 0x27
+#define R_RPKT 0x28
+#define R_RFCS 0x29
+#define R_RMCA 0x2A
+#define R_RBCA 0x2B
+#define R_RXCF 0x2C
+#define R_RXPF 0x2D
+#define R_RXUO 0x2E
+#define R_RALN 0x2F
+#define R_RFLR 0x30
+#define R_RCDE 0x31
+#define R_RCSE 0x32
+#define R_RUND 0x33
+#define R_ROVR 0x34
+#define R_TBYT 0x38
+#define R_TPKT 0x39
+#define R_TMCA 0x3A
+#define R_TBCA 0x3B
+#define R_TXPF 0x3C
+#define R_TDFR 0x3D
+#define R_TEDF 0x3E
+#define R_TSCL 0x3F
+#define R_TMCL 0x40
+#define R_TLCL 0x41
+#define R_TXCL 0x42
+#define R_TNCL 0x43
+#define R_TJBR 0x46
+#define R_TFCS 0x47
+#define R_TXCF 0x48
+#define R_TOVR 0x49
+#define R_TUND 0x4A
+#define R_TFRG 0x4B
+
+/* Glue logic register and bit field definitions */
+#define R_MAC_ADDR0 0x50
+#define R_MAC_ADDR1 0x52
+#define R_MAC_ADDR2 0x54
+#define R_MAC_ADDR3 0x56
+#define R_MAC_ADDR_MASK2 0x58
+#define R_MAC_ADDR_MASK3 0x5A
+#define R_MAC_FILTER_CONFIG 0x5C
+#define O_MAC_FILTER_CONFIG__BROADCAST_EN 10
+#define O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN 9
+#define O_MAC_FILTER_CONFIG__ALL_MCAST_EN 8
+#define O_MAC_FILTER_CONFIG__ALL_UCAST_EN 7
+#define O_MAC_FILTER_CONFIG__HASH_MCAST_EN 6
+#define O_MAC_FILTER_CONFIG__HASH_UCAST_EN 5
+#define O_MAC_FILTER_CONFIG__ADDR_MATCH_DISC 4
+#define O_MAC_FILTER_CONFIG__MAC_ADDR3_VALID 3
+#define O_MAC_FILTER_CONFIG__MAC_ADDR2_VALID 2
+#define O_MAC_FILTER_CONFIG__MAC_ADDR1_VALID 1
+#define O_MAC_FILTER_CONFIG__MAC_ADDR0_VALID 0
+#define R_HASH_TABLE_VECTOR 0x30
+#define R_TX_CONTROL 0x0A0
+#define O_TX_CONTROL__Tx15Halt 31
+#define O_TX_CONTROL__Tx14Halt 30
+#define O_TX_CONTROL__Tx13Halt 29
+#define O_TX_CONTROL__Tx12Halt 28
+#define O_TX_CONTROL__Tx11Halt 27
+#define O_TX_CONTROL__Tx10Halt 26
+#define O_TX_CONTROL__Tx9Halt 25
+#define O_TX_CONTROL__Tx8Halt 24
+#define O_TX_CONTROL__Tx7Halt 23
+#define O_TX_CONTROL__Tx6Halt 22
+#define O_TX_CONTROL__Tx5Halt 21
+#define O_TX_CONTROL__Tx4Halt 20
+#define O_TX_CONTROL__Tx3Halt 19
+#define O_TX_CONTROL__Tx2Halt 18
+#define O_TX_CONTROL__Tx1Halt 17
+#define O_TX_CONTROL__Tx0Halt 16
+#define O_TX_CONTROL__TxIdle 15
+#define O_TX_CONTROL__TxEnable 14
+#define O_TX_CONTROL__TxThreshold 0
+#define W_TX_CONTROL__TxThreshold 14
+#define R_RX_CONTROL 0x0A1
+#define O_RX_CONTROL__RGMII 10
+#define O_RX_CONTROL__SoftReset 2
+#define O_RX_CONTROL__RxHalt 1
+#define O_RX_CONTROL__RxEnable 0
+#define R_DESC_PACK_CTRL 0x0A2
+#define O_DESC_PACK_CTRL__ByteOffset 17
+#define W_DESC_PACK_CTRL__ByteOffset 3
+#define O_DESC_PACK_CTRL__PrePadEnable 16
+#define O_DESC_PACK_CTRL__MaxEntry 14
+#define W_DESC_PACK_CTRL__MaxEntry 2
+#define O_DESC_PACK_CTRL__RegularSize 0
+#define W_DESC_PACK_CTRL__RegularSize 14
+#define R_STATCTRL 0x0A3
+#define O_STATCTRL__OverFlowEn 4
+#define O_STATCTRL__GIG 3
+#define O_STATCTRL__Sten 2
+#define O_STATCTRL__ClrCnt 1
+#define O_STATCTRL__AutoZ 0
+#define R_L2ALLOCCTRL 0x0A4
+#define O_L2ALLOCCTRL__TxL2Allocate 9
+#define W_L2ALLOCCTRL__TxL2Allocate 9
+#define O_L2ALLOCCTRL__RxL2Allocate 0
+#define W_L2ALLOCCTRL__RxL2Allocate 9
+#define R_INTMASK 0x0A5
+#define O_INTMASK__Spi4TxError 28
+#define O_INTMASK__Spi4RxError 27
+#define O_INTMASK__RGMIIHalfDupCollision 27
+#define O_INTMASK__Abort 26
+#define O_INTMASK__Underrun 25
+#define O_INTMASK__DiscardPacket 24
+#define O_INTMASK__AsyncFifoFull 23
+#define O_INTMASK__TagFull 22
+#define O_INTMASK__Class3Full 21
+#define O_INTMASK__C3EarlyFull 20
+#define O_INTMASK__Class2Full 19
+#define O_INTMASK__C2EarlyFull 18
+#define O_INTMASK__Class1Full 17
+#define O_INTMASK__C1EarlyFull 16
+#define O_INTMASK__Class0Full 15
+#define O_INTMASK__C0EarlyFull 14
+#define O_INTMASK__RxDataFull 13
+#define O_INTMASK__RxEarlyFull 12
+#define O_INTMASK__RFreeEmpty 9
+#define O_INTMASK__RFEarlyEmpty 8
+#define O_INTMASK__P2PSpillEcc 7
+#define O_INTMASK__FreeDescFull 5
+#define O_INTMASK__FreeEarlyFull 4
+#define O_INTMASK__TxFetchError 3
+#define O_INTMASK__StatCarry 2
+#define O_INTMASK__MDInt 1
+#define O_INTMASK__TxIllegal 0
+#define R_INTREG 0x0A6
+#define O_INTREG__Spi4TxError 28
+#define O_INTREG__Spi4RxError 27
+#define O_INTREG__RGMIIHalfDupCollision 27
+#define O_INTREG__Abort 26
+#define O_INTREG__Underrun 25
+#define O_INTREG__DiscardPacket 24
+#define O_INTREG__AsyncFifoFull 23
+#define O_INTREG__TagFull 22
+#define O_INTREG__Class3Full 21
+#define O_INTREG__C3EarlyFull 20
+#define O_INTREG__Class2Full 19
+#define O_INTREG__C2EarlyFull 18
+#define O_INTREG__Class1Full 17
+#define O_INTREG__C1EarlyFull 16
+#define O_INTREG__Class0Full 15
+#define O_INTREG__C0EarlyFull 14
+#define O_INTREG__RxDataFull 13
+#define O_INTREG__RxEarlyFull 12
+#define O_INTREG__RFreeEmpty 9
+#define O_INTREG__RFEarlyEmpty 8
+#define O_INTREG__P2PSpillEcc 7
+#define O_INTREG__FreeDescFull 5
+#define O_INTREG__FreeEarlyFull 4
+#define O_INTREG__TxFetchError 3
+#define O_INTREG__StatCarry 2
+#define O_INTREG__MDInt 1
+#define O_INTREG__TxIllegal 0
+#define R_TXRETRY 0x0A7
+#define O_TXRETRY__CollisionRetry 6
+#define O_TXRETRY__BusErrorRetry 5
+#define O_TXRETRY__UnderRunRetry 4
+#define O_TXRETRY__Retries 0
+#define W_TXRETRY__Retries 4
+#define R_CORECONTROL 0x0A8
+#define O_CORECONTROL__ErrorThread 4
+#define W_CORECONTROL__ErrorThread 7
+#define O_CORECONTROL__Shutdown 2
+#define O_CORECONTROL__Speed 0
+#define W_CORECONTROL__Speed 2
+#define R_BYTEOFFSET0 0x0A9
+#define R_BYTEOFFSET1 0x0AA
+#define R_L2TYPE_0 0x0F0
+#define O_L2TYPE__ExtraHdrProtoSize 26
+#define W_L2TYPE__ExtraHdrProtoSize 5
+#define O_L2TYPE__ExtraHdrProtoOffset 20
+#define W_L2TYPE__ExtraHdrProtoOffset 6
+#define O_L2TYPE__ExtraHeaderSize 14
+#define W_L2TYPE__ExtraHeaderSize 6
+#define O_L2TYPE__ProtoOffset 8
+#define W_L2TYPE__ProtoOffset 6
+#define O_L2TYPE__L2HdrOffset 2
+#define W_L2TYPE__L2HdrOffset 6
+#define O_L2TYPE__L2Proto 0
+#define W_L2TYPE__L2Proto 2
+#define R_L2TYPE_1 0xF0
+#define R_L2TYPE_2 0xF0
+#define R_L2TYPE_3 0xF0
+#define R_PARSERCONFIGREG 0x100
+#define O_PARSERCONFIGREG__CRCHashPoly 8
+#define W_PARSERCONFIGREG__CRCHashPoly 7
+#define O_PARSERCONFIGREG__PrePadOffset 4
+#define W_PARSERCONFIGREG__PrePadOffset 4
+#define O_PARSERCONFIGREG__UseCAM 2
+#define O_PARSERCONFIGREG__UseHASH 1
+#define O_PARSERCONFIGREG__UseProto 0
+#define R_L3CTABLE 0x140
+#define O_L3CTABLE__Offset0 25
+#define W_L3CTABLE__Offset0 7
+#define O_L3CTABLE__Len0 21
+#define W_L3CTABLE__Len0 4
+#define O_L3CTABLE__Offset1 14
+#define W_L3CTABLE__Offset1 7
+#define O_L3CTABLE__Len1 10
+#define W_L3CTABLE__Len1 4
+#define O_L3CTABLE__Offset2 4
+#define W_L3CTABLE__Offset2 6
+#define O_L3CTABLE__Len2 0
+#define W_L3CTABLE__Len2 4
+#define O_L3CTABLE__L3HdrOffset 26
+#define W_L3CTABLE__L3HdrOffset 6
+#define O_L3CTABLE__L4ProtoOffset 20
+#define W_L3CTABLE__L4ProtoOffset 6
+#define O_L3CTABLE__IPChksumCompute 19
+#define O_L3CTABLE__L4Classify 18
+#define O_L3CTABLE__L2Proto 16
+#define W_L3CTABLE__L2Proto 2
+#define O_L3CTABLE__L3ProtoKey 0
+#define W_L3CTABLE__L3ProtoKey 16
+#define R_L4CTABLE 0x160
+#define O_L4CTABLE__Offset0 21
+#define W_L4CTABLE__Offset0 6
+#define O_L4CTABLE__Len0 17
+#define W_L4CTABLE__Len0 4
+#define O_L4CTABLE__Offset1 11
+#define W_L4CTABLE__Offset1 6
+#define O_L4CTABLE__Len1 7
+#define W_L4CTABLE__Len1 4
+#define O_L4CTABLE__TCPChksumEnable 0
+#define R_CAM4X128TABLE 0x172
+#define O_CAM4X128TABLE__ClassId 7
+#define W_CAM4X128TABLE__ClassId 2
+#define O_CAM4X128TABLE__BucketId 1
+#define W_CAM4X128TABLE__BucketId 6
+#define O_CAM4X128TABLE__UseBucket 0
+#define R_CAM4X128KEY 0x180
+#define R_TRANSLATETABLE 0x1A0
+#define R_DMACR0 0x200
+#define O_DMACR0__Data0WrMaxCr 27
+#define W_DMACR0__Data0WrMaxCr 3
+#define O_DMACR0__Data0RdMaxCr 24
+#define W_DMACR0__Data0RdMaxCr 3
+#define O_DMACR0__Data1WrMaxCr 21
+#define W_DMACR0__Data1WrMaxCr 3
+#define O_DMACR0__Data1RdMaxCr 18
+#define W_DMACR0__Data1RdMaxCr 3
+#define O_DMACR0__Data2WrMaxCr 15
+#define W_DMACR0__Data2WrMaxCr 3
+#define O_DMACR0__Data2RdMaxCr 12
+#define W_DMACR0__Data2RdMaxCr 3
+#define O_DMACR0__Data3WrMaxCr 9
+#define W_DMACR0__Data3WrMaxCr 3
+#define O_DMACR0__Data3RdMaxCr 6
+#define W_DMACR0__Data3RdMaxCr 3
+#define O_DMACR0__Data4WrMaxCr 3
+#define W_DMACR0__Data4WrMaxCr 3
+#define O_DMACR0__Data4RdMaxCr 0
+#define W_DMACR0__Data4RdMaxCr 3
+#define R_DMACR1 0x201
+#define O_DMACR1__Data5WrMaxCr 27
+#define W_DMACR1__Data5WrMaxCr 3
+#define O_DMACR1__Data5RdMaxCr 24
+#define W_DMACR1__Data5RdMaxCr 3
+#define O_DMACR1__Data6WrMaxCr 21
+#define W_DMACR1__Data6WrMaxCr 3
+#define O_DMACR1__Data6RdMaxCr 18
+#define W_DMACR1__Data6RdMaxCr 3
+#define O_DMACR1__Data7WrMaxCr 15
+#define W_DMACR1__Data7WrMaxCr 3
+#define O_DMACR1__Data7RdMaxCr 12
+#define W_DMACR1__Data7RdMaxCr 3
+#define O_DMACR1__Data8WrMaxCr 9
+#define W_DMACR1__Data8WrMaxCr 3
+#define O_DMACR1__Data8RdMaxCr 6
+#define W_DMACR1__Data8RdMaxCr 3
+#define O_DMACR1__Data9WrMaxCr 3
+#define W_DMACR1__Data9WrMaxCr 3
+#define O_DMACR1__Data9RdMaxCr 0
+#define W_DMACR1__Data9RdMaxCr 3
+#define R_DMACR2 0x202
+#define O_DMACR2__Data10WrMaxCr 27
+#define W_DMACR2__Data10WrMaxCr 3
+#define O_DMACR2__Data10RdMaxCr 24
+#define W_DMACR2__Data10RdMaxCr 3
+#define O_DMACR2__Data11WrMaxCr 21
+#define W_DMACR2__Data11WrMaxCr 3
+#define O_DMACR2__Data11RdMaxCr 18
+#define W_DMACR2__Data11RdMaxCr 3
+#define O_DMACR2__Data12WrMaxCr 15
+#define W_DMACR2__Data12WrMaxCr 3
+#define O_DMACR2__Data12RdMaxCr 12
+#define W_DMACR2__Data12RdMaxCr 3
+#define O_DMACR2__Data13WrMaxCr 9
+#define W_DMACR2__Data13WrMaxCr 3
+#define O_DMACR2__Data13RdMaxCr 6
+#define W_DMACR2__Data13RdMaxCr 3
+#define O_DMACR2__Data14WrMaxCr 3
+#define W_DMACR2__Data14WrMaxCr 3
+#define O_DMACR2__Data14RdMaxCr 0
+#define W_DMACR2__Data14RdMaxCr 3
+#define R_DMACR3 0x203
+#define O_DMACR3__Data15WrMaxCr 27
+#define W_DMACR3__Data15WrMaxCr 3
+#define O_DMACR3__Data15RdMaxCr 24
+#define W_DMACR3__Data15RdMaxCr 3
+#define O_DMACR3__SpClassWrMaxCr 21
+#define W_DMACR3__SpClassWrMaxCr 3
+#define O_DMACR3__SpClassRdMaxCr 18
+#define W_DMACR3__SpClassRdMaxCr 3
+#define O_DMACR3__JumFrInWrMaxCr 15
+#define W_DMACR3__JumFrInWrMaxCr 3
+#define O_DMACR3__JumFrInRdMaxCr 12
+#define W_DMACR3__JumFrInRdMaxCr 3
+#define O_DMACR3__RegFrInWrMaxCr 9
+#define W_DMACR3__RegFrInWrMaxCr 3
+#define O_DMACR3__RegFrInRdMaxCr 6
+#define W_DMACR3__RegFrInRdMaxCr 3
+#define O_DMACR3__FrOutWrMaxCr 3
+#define W_DMACR3__FrOutWrMaxCr 3
+#define O_DMACR3__FrOutRdMaxCr 0
+#define W_DMACR3__FrOutRdMaxCr 3
+#define R_REG_FRIN_SPILL_MEM_START_0 0x204
+#define O_REG_FRIN_SPILL_MEM_START_0__RegFrInSpillMemStart0 0
+#define W_REG_FRIN_SPILL_MEM_START_0__RegFrInSpillMemStart0 32
+#define R_REG_FRIN_SPILL_MEM_START_1 0x205
+#define O_REG_FRIN_SPILL_MEM_START_1__RegFrInSpillMemStart1 0
+#define W_REG_FRIN_SPILL_MEM_START_1__RegFrInSpillMemStart1 3
+#define R_REG_FRIN_SPILL_MEM_SIZE 0x206
+#define O_REG_FRIN_SPILL_MEM_SIZE__RegFrInSpillMemSize 0
+#define W_REG_FRIN_SPILL_MEM_SIZE__RegFrInSpillMemSize 32
+#define R_FROUT_SPILL_MEM_START_0 0x207
+#define O_FROUT_SPILL_MEM_START_0__FrOutSpillMemStart0 0
+#define W_FROUT_SPILL_MEM_START_0__FrOutSpillMemStart0 32
+#define R_FROUT_SPILL_MEM_START_1 0x208
+#define O_FROUT_SPILL_MEM_START_1__FrOutSpillMemStart1 0
+#define W_FROUT_SPILL_MEM_START_1__FrOutSpillMemStart1 3
+#define R_FROUT_SPILL_MEM_SIZE 0x209
+#define O_FROUT_SPILL_MEM_SIZE__FrOutSpillMemSize 0
+#define W_FROUT_SPILL_MEM_SIZE__FrOutSpillMemSize 32
+#define R_CLASS0_SPILL_MEM_START_0 0x20A
+#define O_CLASS0_SPILL_MEM_START_0__Class0SpillMemStart0 0
+#define W_CLASS0_SPILL_MEM_START_0__Class0SpillMemStart0 32
+#define R_CLASS0_SPILL_MEM_START_1 0x20B
+#define O_CLASS0_SPILL_MEM_START_1__Class0SpillMemStart1 0
+#define W_CLASS0_SPILL_MEM_START_1__Class0SpillMemStart1 3
+#define R_CLASS0_SPILL_MEM_SIZE 0x20C
+#define O_CLASS0_SPILL_MEM_SIZE__Class0SpillMemSize 0
+#define W_CLASS0_SPILL_MEM_SIZE__Class0SpillMemSize 32
+#define R_JUMFRIN_SPILL_MEM_START_0 0x20D
+#define O_JUMFRIN_SPILL_MEM_START_0__JumFrInSpillMemStar0 0
+#define W_JUMFRIN_SPILL_MEM_START_0__JumFrInSpillMemStar0 32
+#define R_JUMFRIN_SPILL_MEM_START_1 0x20E
+#define O_JUMFRIN_SPILL_MEM_START_1__JumFrInSpillMemStart1 0
+#define W_JUMFRIN_SPILL_MEM_START_1__JumFrInSpillMemStart1 3
+#define R_JUMFRIN_SPILL_MEM_SIZE 0x20F
+#define O_JUMFRIN_SPILL_MEM_SIZE__JumFrInSpillMemSize 0
+#define W_JUMFRIN_SPILL_MEM_SIZE__JumFrInSpillMemSize 32
+#define R_CLASS1_SPILL_MEM_START_0 0x210
+#define O_CLASS1_SPILL_MEM_START_0__Class1SpillMemStart0 0
+#define W_CLASS1_SPILL_MEM_START_0__Class1SpillMemStart0 32
+#define R_CLASS1_SPILL_MEM_START_1 0x211
+#define O_CLASS1_SPILL_MEM_START_1__Class1SpillMemStart1 0
+#define W_CLASS1_SPILL_MEM_START_1__Class1SpillMemStart1 3
+#define R_CLASS1_SPILL_MEM_SIZE 0x212
+#define O_CLASS1_SPILL_MEM_SIZE__Class1SpillMemSize 0
+#define W_CLASS1_SPILL_MEM_SIZE__Class1SpillMemSize 32
+#define R_CLASS2_SPILL_MEM_START_0 0x213
+#define O_CLASS2_SPILL_MEM_START_0__Class2SpillMemStart0 0
+#define W_CLASS2_SPILL_MEM_START_0__Class2SpillMemStart0 32
+#define R_CLASS2_SPILL_MEM_START_1 0x214
+#define O_CLASS2_SPILL_MEM_START_1__Class2SpillMemStart1 0
+#define W_CLASS2_SPILL_MEM_START_1__Class2SpillMemStart1 3
+#define R_CLASS2_SPILL_MEM_SIZE 0x215
+#define O_CLASS2_SPILL_MEM_SIZE__Class2SpillMemSize 0
+#define W_CLASS2_SPILL_MEM_SIZE__Class2SpillMemSize 32
+#define R_CLASS3_SPILL_MEM_START_0 0x216
+#define O_CLASS3_SPILL_MEM_START_0__Class3SpillMemStart0 0
+#define W_CLASS3_SPILL_MEM_START_0__Class3SpillMemStart0 32
+#define R_CLASS3_SPILL_MEM_START_1 0x217
+#define O_CLASS3_SPILL_MEM_START_1__Class3SpillMemStart1 0
+#define W_CLASS3_SPILL_MEM_START_1__Class3SpillMemStart1 3
+#define R_CLASS3_SPILL_MEM_SIZE 0x218
+#define O_CLASS3_SPILL_MEM_SIZE__Class3SpillMemSize 0
+#define W_CLASS3_SPILL_MEM_SIZE__Class3SpillMemSize 32
+#define R_REG_FRIN1_SPILL_MEM_START_0 0x219
+#define R_REG_FRIN1_SPILL_MEM_START_1 0x21a
+#define R_REG_FRIN1_SPILL_MEM_SIZE 0x21b
+#define R_SPIHNGY0 0x219
+#define O_SPIHNGY0__EG_HNGY_THRESH_0 24
+#define W_SPIHNGY0__EG_HNGY_THRESH_0 7
+#define O_SPIHNGY0__EG_HNGY_THRESH_1 16
+#define W_SPIHNGY0__EG_HNGY_THRESH_1 7
+#define O_SPIHNGY0__EG_HNGY_THRESH_2 8
+#define W_SPIHNGY0__EG_HNGY_THRESH_2 7
+#define O_SPIHNGY0__EG_HNGY_THRESH_3 0
+#define W_SPIHNGY0__EG_HNGY_THRESH_3 7
+#define R_SPIHNGY1 0x21A
+#define O_SPIHNGY1__EG_HNGY_THRESH_4 24
+#define W_SPIHNGY1__EG_HNGY_THRESH_4 7
+#define O_SPIHNGY1__EG_HNGY_THRESH_5 16
+#define W_SPIHNGY1__EG_HNGY_THRESH_5 7
+#define O_SPIHNGY1__EG_HNGY_THRESH_6 8
+#define W_SPIHNGY1__EG_HNGY_THRESH_6 7
+#define O_SPIHNGY1__EG_HNGY_THRESH_7 0
+#define W_SPIHNGY1__EG_HNGY_THRESH_7 7
+#define R_SPIHNGY2 0x21B
+#define O_SPIHNGY2__EG_HNGY_THRESH_8 24
+#define W_SPIHNGY2__EG_HNGY_THRESH_8 7
+#define O_SPIHNGY2__EG_HNGY_THRESH_9 16
+#define W_SPIHNGY2__EG_HNGY_THRESH_9 7
+#define O_SPIHNGY2__EG_HNGY_THRESH_10 8
+#define W_SPIHNGY2__EG_HNGY_THRESH_10 7
+#define O_SPIHNGY2__EG_HNGY_THRESH_11 0
+#define W_SPIHNGY2__EG_HNGY_THRESH_11 7
+#define R_SPIHNGY3 0x21C
+#define O_SPIHNGY3__EG_HNGY_THRESH_12 24
+#define W_SPIHNGY3__EG_HNGY_THRESH_12 7
+#define O_SPIHNGY3__EG_HNGY_THRESH_13 16
+#define W_SPIHNGY3__EG_HNGY_THRESH_13 7
+#define O_SPIHNGY3__EG_HNGY_THRESH_14 8
+#define W_SPIHNGY3__EG_HNGY_THRESH_14 7
+#define O_SPIHNGY3__EG_HNGY_THRESH_15 0
+#define W_SPIHNGY3__EG_HNGY_THRESH_15 7
+#define R_SPISTRV0 0x21D
+#define O_SPISTRV0__EG_STRV_THRESH_0 24
+#define W_SPISTRV0__EG_STRV_THRESH_0 7
+#define O_SPISTRV0__EG_STRV_THRESH_1 16
+#define W_SPISTRV0__EG_STRV_THRESH_1 7
+#define O_SPISTRV0__EG_STRV_THRESH_2 8
+#define W_SPISTRV0__EG_STRV_THRESH_2 7
+#define O_SPISTRV0__EG_STRV_THRESH_3 0
+#define W_SPISTRV0__EG_STRV_THRESH_3 7
+#define R_SPISTRV1 0x21E
+#define O_SPISTRV1__EG_STRV_THRESH_4 24
+#define W_SPISTRV1__EG_STRV_THRESH_4 7
+#define O_SPISTRV1__EG_STRV_THRESH_5 16
+#define W_SPISTRV1__EG_STRV_THRESH_5 7
+#define O_SPISTRV1__EG_STRV_THRESH_6 8
+#define W_SPISTRV1__EG_STRV_THRESH_6 7
+#define O_SPISTRV1__EG_STRV_THRESH_7 0
+#define W_SPISTRV1__EG_STRV_THRESH_7 7
+#define R_SPISTRV2 0x21F
+#define O_SPISTRV2__EG_STRV_THRESH_8 24
+#define W_SPISTRV2__EG_STRV_THRESH_8 7
+#define O_SPISTRV2__EG_STRV_THRESH_9 16
+#define W_SPISTRV2__EG_STRV_THRESH_9 7
+#define O_SPISTRV2__EG_STRV_THRESH_10 8
+#define W_SPISTRV2__EG_STRV_THRESH_10 7
+#define O_SPISTRV2__EG_STRV_THRESH_11 0
+#define W_SPISTRV2__EG_STRV_THRESH_11 7
+#define R_SPISTRV3 0x220
+#define O_SPISTRV3__EG_STRV_THRESH_12 24
+#define W_SPISTRV3__EG_STRV_THRESH_12 7
+#define O_SPISTRV3__EG_STRV_THRESH_13 16
+#define W_SPISTRV3__EG_STRV_THRESH_13 7
+#define O_SPISTRV3__EG_STRV_THRESH_14 8
+#define W_SPISTRV3__EG_STRV_THRESH_14 7
+#define O_SPISTRV3__EG_STRV_THRESH_15 0
+#define W_SPISTRV3__EG_STRV_THRESH_15 7
+#define R_TXDATAFIFO0 0x221
+#define O_TXDATAFIFO0__Tx0DataFifoStart 24
+#define W_TXDATAFIFO0__Tx0DataFifoStart 7
+#define O_TXDATAFIFO0__Tx0DataFifoSize 16
+#define W_TXDATAFIFO0__Tx0DataFifoSize 7
+#define O_TXDATAFIFO0__Tx1DataFifoStart 8
+#define W_TXDATAFIFO0__Tx1DataFifoStart 7
+#define O_TXDATAFIFO0__Tx1DataFifoSize 0
+#define W_TXDATAFIFO0__Tx1DataFifoSize 7
+#define R_TXDATAFIFO1 0x222
+#define O_TXDATAFIFO1__Tx2DataFifoStart 24
+#define W_TXDATAFIFO1__Tx2DataFifoStart 7
+#define O_TXDATAFIFO1__Tx2DataFifoSize 16
+#define W_TXDATAFIFO1__Tx2DataFifoSize 7
+#define O_TXDATAFIFO1__Tx3DataFifoStart 8
+#define W_TXDATAFIFO1__Tx3DataFifoStart 7
+#define O_TXDATAFIFO1__Tx3DataFifoSize 0
+#define W_TXDATAFIFO1__Tx3DataFifoSize 7
+#define R_TXDATAFIFO2 0x223
+#define O_TXDATAFIFO2__Tx4DataFifoStart 24
+#define W_TXDATAFIFO2__Tx4DataFifoStart 7
+#define O_TXDATAFIFO2__Tx4DataFifoSize 16
+#define W_TXDATAFIFO2__Tx4DataFifoSize 7
+#define O_TXDATAFIFO2__Tx5DataFifoStart 8
+#define W_TXDATAFIFO2__Tx5DataFifoStart 7
+#define O_TXDATAFIFO2__Tx5DataFifoSize 0
+#define W_TXDATAFIFO2__Tx5DataFifoSize 7
+#define R_TXDATAFIFO3 0x224
+#define O_TXDATAFIFO3__Tx6DataFifoStart 24
+#define W_TXDATAFIFO3__Tx6DataFifoStart 7
+#define O_TXDATAFIFO3__Tx6DataFifoSize 16
+#define W_TXDATAFIFO3__Tx6DataFifoSize 7
+#define O_TXDATAFIFO3__Tx7DataFifoStart 8
+#define W_TXDATAFIFO3__Tx7DataFifoStart 7
+#define O_TXDATAFIFO3__Tx7DataFifoSize 0
+#define W_TXDATAFIFO3__Tx7DataFifoSize 7
+#define R_TXDATAFIFO4 0x225
+#define O_TXDATAFIFO4__Tx8DataFifoStart 24
+#define W_TXDATAFIFO4__Tx8DataFifoStart 7
+#define O_TXDATAFIFO4__Tx8DataFifoSize 16
+#define W_TXDATAFIFO4__Tx8DataFifoSize 7
+#define O_TXDATAFIFO4__Tx9DataFifoStart 8
+#define W_TXDATAFIFO4__Tx9DataFifoStart 7
+#define O_TXDATAFIFO4__Tx9DataFifoSize 0
+#define W_TXDATAFIFO4__Tx9DataFifoSize 7
+#define R_TXDATAFIFO5 0x226
+#define O_TXDATAFIFO5__Tx10DataFifoStart 24
+#define W_TXDATAFIFO5__Tx10DataFifoStart 7
+#define O_TXDATAFIFO5__Tx10DataFifoSize 16
+#define W_TXDATAFIFO5__Tx10DataFifoSize 7
+#define O_TXDATAFIFO5__Tx11DataFifoStart 8
+#define W_TXDATAFIFO5__Tx11DataFifoStart 7
+#define O_TXDATAFIFO5__Tx11DataFifoSize 0
+#define W_TXDATAFIFO5__Tx11DataFifoSize 7
+#define R_TXDATAFIFO6 0x227
+#define O_TXDATAFIFO6__Tx12DataFifoStart 24
+#define W_TXDATAFIFO6__Tx12DataFifoStart 7
+#define O_TXDATAFIFO6__Tx12DataFifoSize 16
+#define W_TXDATAFIFO6__Tx12DataFifoSize 7
+#define O_TXDATAFIFO6__Tx13DataFifoStart 8
+#define W_TXDATAFIFO6__Tx13DataFifoStart 7
+#define O_TXDATAFIFO6__Tx13DataFifoSize 0
+#define W_TXDATAFIFO6__Tx13DataFifoSize 7
+#define R_TXDATAFIFO7 0x228
+#define O_TXDATAFIFO7__Tx14DataFifoStart 24
+#define W_TXDATAFIFO7__Tx14DataFifoStart 7
+#define O_TXDATAFIFO7__Tx14DataFifoSize 16
+#define W_TXDATAFIFO7__Tx14DataFifoSize 7
+#define O_TXDATAFIFO7__Tx15DataFifoStart 8
+#define W_TXDATAFIFO7__Tx15DataFifoStart 7
+#define O_TXDATAFIFO7__Tx15DataFifoSize 0
+#define W_TXDATAFIFO7__Tx15DataFifoSize 7
+#define R_RXDATAFIFO0 0x229
+#define O_RXDATAFIFO0__Rx0DataFifoStart 24
+#define W_RXDATAFIFO0__Rx0DataFifoStart 7
+#define O_RXDATAFIFO0__Rx0DataFifoSize 16
+#define W_RXDATAFIFO0__Rx0DataFifoSize 7
+#define O_RXDATAFIFO0__Rx1DataFifoStart 8
+#define W_RXDATAFIFO0__Rx1DataFifoStart 7
+#define O_RXDATAFIFO0__Rx1DataFifoSize 0
+#define W_RXDATAFIFO0__Rx1DataFifoSize 7
+#define R_RXDATAFIFO1 0x22A
+#define O_RXDATAFIFO1__Rx2DataFifoStart 24
+#define W_RXDATAFIFO1__Rx2DataFifoStart 7
+#define O_RXDATAFIFO1__Rx2DataFifoSize 16
+#define W_RXDATAFIFO1__Rx2DataFifoSize 7
+#define O_RXDATAFIFO1__Rx3DataFifoStart 8
+#define W_RXDATAFIFO1__Rx3DataFifoStart 7
+#define O_RXDATAFIFO1__Rx3DataFifoSize 0
+#define W_RXDATAFIFO1__Rx3DataFifoSize 7
+#define R_RXDATAFIFO2 0x22B
+#define O_RXDATAFIFO2__Rx4DataFifoStart 24
+#define W_RXDATAFIFO2__Rx4DataFifoStart 7
+#define O_RXDATAFIFO2__Rx4DataFifoSize 16
+#define W_RXDATAFIFO2__Rx4DataFifoSize 7
+#define O_RXDATAFIFO2__Rx5DataFifoStart 8
+#define W_RXDATAFIFO2__Rx5DataFifoStart 7
+#define O_RXDATAFIFO2__Rx5DataFifoSize 0
+#define W_RXDATAFIFO2__Rx5DataFifoSize 7
+#define R_RXDATAFIFO3 0x22C
+#define O_RXDATAFIFO3__Rx6DataFifoStart 24
+#define W_RXDATAFIFO3__Rx6DataFifoStart 7
+#define O_RXDATAFIFO3__Rx6DataFifoSize 16
+#define W_RXDATAFIFO3__Rx6DataFifoSize 7
+#define O_RXDATAFIFO3__Rx7DataFifoStart 8
+#define W_RXDATAFIFO3__Rx7DataFifoStart 7
+#define O_RXDATAFIFO3__Rx7DataFifoSize 0
+#define W_RXDATAFIFO3__Rx7DataFifoSize 7
+#define R_RXDATAFIFO4 0x22D
+#define O_RXDATAFIFO4__Rx8DataFifoStart 24
+#define W_RXDATAFIFO4__Rx8DataFifoStart 7
+#define O_RXDATAFIFO4__Rx8DataFifoSize 16
+#define W_RXDATAFIFO4__Rx8DataFifoSize 7
+#define O_RXDATAFIFO4__Rx9DataFifoStart 8
+#define W_RXDATAFIFO4__Rx9DataFifoStart 7
+#define O_RXDATAFIFO4__Rx9DataFifoSize 0
+#define W_RXDATAFIFO4__Rx9DataFifoSize 7
+#define R_RXDATAFIFO5 0x22E
+#define O_RXDATAFIFO5__Rx10DataFifoStart 24
+#define W_RXDATAFIFO5__Rx10DataFifoStart 7
+#define O_RXDATAFIFO5__Rx10DataFifoSize 16
+#define W_RXDATAFIFO5__Rx10DataFifoSize 7
+#define O_RXDATAFIFO5__Rx11DataFifoStart 8
+#define W_RXDATAFIFO5__Rx11DataFifoStart 7
+#define O_RXDATAFIFO5__Rx11DataFifoSize 0
+#define W_RXDATAFIFO5__Rx11DataFifoSize 7
+#define R_RXDATAFIFO6 0x22F
+#define O_RXDATAFIFO6__Rx12DataFifoStart 24
+#define W_RXDATAFIFO6__Rx12DataFifoStart 7
+#define O_RXDATAFIFO6__Rx12DataFifoSize 16
+#define W_RXDATAFIFO6__Rx12DataFifoSize 7
+#define O_RXDATAFIFO6__Rx13DataFifoStart 8
+#define W_RXDATAFIFO6__Rx13DataFifoStart 7
+#define O_RXDATAFIFO6__Rx13DataFifoSize 0
+#define W_RXDATAFIFO6__Rx13DataFifoSize 7
+#define R_RXDATAFIFO7 0x230
+#define O_RXDATAFIFO7__Rx14DataFifoStart 24
+#define W_RXDATAFIFO7__Rx14DataFifoStart 7
+#define O_RXDATAFIFO7__Rx14DataFifoSize 16
+#define W_RXDATAFIFO7__Rx14DataFifoSize 7
+#define O_RXDATAFIFO7__Rx15DataFifoStart 8
+#define W_RXDATAFIFO7__Rx15DataFifoStart 7
+#define O_RXDATAFIFO7__Rx15DataFifoSize 0
+#define W_RXDATAFIFO7__Rx15DataFifoSize 7
+#define R_XGMACPADCALIBRATION 0x231
+#define R_FREEQCARVE 0x233
+#define R_SPI4STATICDELAY0 0x240
+#define O_SPI4STATICDELAY0__DataLine7 28
+#define W_SPI4STATICDELAY0__DataLine7 4
+#define O_SPI4STATICDELAY0__DataLine6 24
+#define W_SPI4STATICDELAY0__DataLine6 4
+#define O_SPI4STATICDELAY0__DataLine5 20
+#define W_SPI4STATICDELAY0__DataLine5 4
+#define O_SPI4STATICDELAY0__DataLine4 16
+#define W_SPI4STATICDELAY0__DataLine4 4
+#define O_SPI4STATICDELAY0__DataLine3 12
+#define W_SPI4STATICDELAY0__DataLine3 4
+#define O_SPI4STATICDELAY0__DataLine2 8
+#define W_SPI4STATICDELAY0__DataLine2 4
+#define O_SPI4STATICDELAY0__DataLine1 4
+#define W_SPI4STATICDELAY0__DataLine1 4
+#define O_SPI4STATICDELAY0__DataLine0 0
+#define W_SPI4STATICDELAY0__DataLine0 4
+#define R_SPI4STATICDELAY1 0x241
+#define O_SPI4STATICDELAY1__DataLine15 28
+#define W_SPI4STATICDELAY1__DataLine15 4
+#define O_SPI4STATICDELAY1__DataLine14 24
+#define W_SPI4STATICDELAY1__DataLine14 4
+#define O_SPI4STATICDELAY1__DataLine13 20
+#define W_SPI4STATICDELAY1__DataLine13 4
+#define O_SPI4STATICDELAY1__DataLine12 16
+#define W_SPI4STATICDELAY1__DataLine12 4
+#define O_SPI4STATICDELAY1__DataLine11 12
+#define W_SPI4STATICDELAY1__DataLine11 4
+#define O_SPI4STATICDELAY1__DataLine10 8
+#define W_SPI4STATICDELAY1__DataLine10 4
+#define O_SPI4STATICDELAY1__DataLine9 4
+#define W_SPI4STATICDELAY1__DataLine9 4
+#define O_SPI4STATICDELAY1__DataLine8 0
+#define W_SPI4STATICDELAY1__DataLine8 4
+#define R_SPI4STATICDELAY2 0x242
+#define O_SPI4STATICDELAY0__TxStat1 8
+#define W_SPI4STATICDELAY0__TxStat1 4
+#define O_SPI4STATICDELAY0__TxStat0 4
+#define W_SPI4STATICDELAY0__TxStat0 4
+#define O_SPI4STATICDELAY0__RxControl 0
+#define W_SPI4STATICDELAY0__RxControl 4
+#define R_SPI4CONTROL 0x243
+#define O_SPI4CONTROL__StaticDelay 2
+#define O_SPI4CONTROL__LVDS_LVTTL 1
+#define O_SPI4CONTROL__SPI4Enable 0
+#define R_CLASSWATERMARKS 0x244
+#define O_CLASSWATERMARKS__Class0Watermark 24
+#define W_CLASSWATERMARKS__Class0Watermark 5
+#define O_CLASSWATERMARKS__Class1Watermark 16
+#define W_CLASSWATERMARKS__Class1Watermark 5
+#define O_CLASSWATERMARKS__Class3Watermark 0
+#define W_CLASSWATERMARKS__Class3Watermark 5
+#define R_RXWATERMARKS1 0x245
+#define O_RXWATERMARKS__Rx0DataWatermark 24
+#define W_RXWATERMARKS__Rx0DataWatermark 7
+#define O_RXWATERMARKS__Rx1DataWatermark 16
+#define W_RXWATERMARKS__Rx1DataWatermark 7
+#define O_RXWATERMARKS__Rx3DataWatermark 0
+#define W_RXWATERMARKS__Rx3DataWatermark 7
+#define R_RXWATERMARKS2 0x246
+#define O_RXWATERMARKS__Rx4DataWatermark 24
+#define W_RXWATERMARKS__Rx4DataWatermark 7
+#define O_RXWATERMARKS__Rx5DataWatermark 16
+#define W_RXWATERMARKS__Rx5DataWatermark 7
+#define O_RXWATERMARKS__Rx6DataWatermark 8
+#define W_RXWATERMARKS__Rx6DataWatermark 7
+#define O_RXWATERMARKS__Rx7DataWatermark 0
+#define W_RXWATERMARKS__Rx7DataWatermark 7
+#define R_RXWATERMARKS3 0x247
+#define O_RXWATERMARKS__Rx8DataWatermark 24
+#define W_RXWATERMARKS__Rx8DataWatermark 7
+#define O_RXWATERMARKS__Rx9DataWatermark 16
+#define W_RXWATERMARKS__Rx9DataWatermark 7
+#define O_RXWATERMARKS__Rx10DataWatermark 8
+#define W_RXWATERMARKS__Rx10DataWatermark 7
+#define O_RXWATERMARKS__Rx11DataWatermark 0
+#define W_RXWATERMARKS__Rx11DataWatermark 7
+#define R_RXWATERMARKS4 0x248
+#define O_RXWATERMARKS__Rx12DataWatermark 24
+#define W_RXWATERMARKS__Rx12DataWatermark 7
+#define O_RXWATERMARKS__Rx13DataWatermark 16
+#define W_RXWATERMARKS__Rx13DataWatermark 7
+#define O_RXWATERMARKS__Rx14DataWatermark 8
+#define W_RXWATERMARKS__Rx14DataWatermark 7
+#define O_RXWATERMARKS__Rx15DataWatermark 0
+#define W_RXWATERMARKS__Rx15DataWatermark 7
+#define R_FREEWATERMARKS 0x249
+#define O_FREEWATERMARKS__FreeOutWatermark 16
+#define W_FREEWATERMARKS__FreeOutWatermark 16
+#define O_FREEWATERMARKS__JumFrWatermark 8
+#define W_FREEWATERMARKS__JumFrWatermark 7
+#define O_FREEWATERMARKS__RegFrWatermark 0
+#define W_FREEWATERMARKS__RegFrWatermark 7
+#define R_EGRESSFIFOCARVINGSLOTS 0x24a
+
+#define CTRL_RES0 0
+#define CTRL_RES1 1
+#define CTRL_REG_FREE 2
+#define CTRL_JUMBO_FREE 3
+#define CTRL_CONT 4
+#define CTRL_EOP 5
+#define CTRL_START 6
+#define CTRL_SNGL 7
+
+#define CTRL_B0_NOT_EOP 0
+#define CTRL_B0_EOP 1
+
+#define R_ROUND_ROBIN_TABLE 0
+#define R_PDE_CLASS_0 0x300
+#define R_PDE_CLASS_1 0x302
+#define R_PDE_CLASS_2 0x304
+#define R_PDE_CLASS_3 0x306
+
+#define R_MSG_TX_THRESHOLD 0x308
+
+#define R_GMAC_JFR0_BUCKET_SIZE 0x320
+#define R_GMAC_RFR0_BUCKET_SIZE 0x321
+#define R_GMAC_TX0_BUCKET_SIZE 0x322
+#define R_GMAC_TX1_BUCKET_SIZE 0x323
+#define R_GMAC_TX2_BUCKET_SIZE 0x324
+#define R_GMAC_TX3_BUCKET_SIZE 0x325
+#define R_GMAC_JFR1_BUCKET_SIZE 0x326
+#define R_GMAC_RFR1_BUCKET_SIZE 0x327
+
+#define R_XGS_TX0_BUCKET_SIZE 0x320
+#define R_XGS_TX1_BUCKET_SIZE 0x321
+#define R_XGS_TX2_BUCKET_SIZE 0x322
+#define R_XGS_TX3_BUCKET_SIZE 0x323
+#define R_XGS_TX4_BUCKET_SIZE 0x324
+#define R_XGS_TX5_BUCKET_SIZE 0x325
+#define R_XGS_TX6_BUCKET_SIZE 0x326
+#define R_XGS_TX7_BUCKET_SIZE 0x327
+#define R_XGS_TX8_BUCKET_SIZE 0x328
+#define R_XGS_TX9_BUCKET_SIZE 0x329
+#define R_XGS_TX10_BUCKET_SIZE 0x32A
+#define R_XGS_TX11_BUCKET_SIZE 0x32B
+#define R_XGS_TX12_BUCKET_SIZE 0x32C
+#define R_XGS_TX13_BUCKET_SIZE 0x32D
+#define R_XGS_TX14_BUCKET_SIZE 0x32E
+#define R_XGS_TX15_BUCKET_SIZE 0x32F
+#define R_XGS_JFR_BUCKET_SIZE 0x330
+#define R_XGS_RFR_BUCKET_SIZE 0x331
+
+#define R_CC_CPU0_0 0x380
+#define R_CC_CPU1_0 0x388
+#define R_CC_CPU2_0 0x390
+#define R_CC_CPU3_0 0x398
+#define R_CC_CPU4_0 0x3a0
+#define R_CC_CPU5_0 0x3a8
+#define R_CC_CPU6_0 0x3b0
+#define R_CC_CPU7_0 0x3b8
+
+#define XLR_GMAC_BLK_SZ (XLR_IO_GMAC_1_OFFSET - \
+ XLR_IO_GMAC_0_OFFSET)
+
+/* Constants used for configuring the devices */
+
+#define XLR_FB_STN 6 /* Bucket used for Tx freeback */
+
+#define MAC_B2B_IPG 88
+
+#define XLR_NET_PREPAD_LEN 32
+
+/* frame sizes need to be cacheline aligned */
+#define MAX_FRAME_SIZE (1536 + XLR_NET_PREPAD_LEN)
+#define MAX_FRAME_SIZE_JUMBO 9216
+
+#define MAC_SKB_BACK_PTR_SIZE SMP_CACHE_BYTES
+#define MAC_PREPAD 0
+#define BYTE_OFFSET 2
+#define XLR_RX_BUF_SIZE (MAX_FRAME_SIZE + BYTE_OFFSET + \
+ MAC_PREPAD + MAC_SKB_BACK_PTR_SIZE + SMP_CACHE_BYTES)
+#define MAC_CRC_LEN 4
+#define MAX_NUM_MSGRNG_STN_CC 128
+#define MAX_MSG_SND_ATTEMPTS 100 /* 13 stns x 4 entry msg/stn +
+ headroom */
+
+#define MAC_FRIN_TO_BE_SENT_THRESHOLD 16
+
+#define MAX_NUM_DESC_SPILL 1024
+#define MAX_FRIN_SPILL (MAX_NUM_DESC_SPILL << 2)
+#define MAX_FROUT_SPILL (MAX_NUM_DESC_SPILL << 2)
+#define MAX_CLASS_0_SPILL (MAX_NUM_DESC_SPILL << 2)
+#define MAX_CLASS_1_SPILL (MAX_NUM_DESC_SPILL << 2)
+#define MAX_CLASS_2_SPILL (MAX_NUM_DESC_SPILL << 2)
+#define MAX_CLASS_3_SPILL (MAX_NUM_DESC_SPILL << 2)
+
+enum {
+ SGMII_SPEED_10 = 0x00000000,
+ SGMII_SPEED_100 = 0x02000000,
+ SGMII_SPEED_1000 = 0x04000000,
+};
+
+enum tsv_rsv_reg {
+ TX_RX_64_BYTE_FRAME = 0x20,
+ TX_RX_64_127_BYTE_FRAME,
+ TX_RX_128_255_BYTE_FRAME,
+ TX_RX_256_511_BYTE_FRAME,
+ TX_RX_512_1023_BYTE_FRAME,
+ TX_RX_1024_1518_BYTE_FRAME,
+ TX_RX_1519_1522_VLAN_BYTE_FRAME,
+
+ RX_BYTE_COUNTER = 0x27,
+ RX_PACKET_COUNTER,
+ RX_FCS_ERROR_COUNTER,
+ RX_MULTICAST_PACKET_COUNTER,
+ RX_BROADCAST_PACKET_COUNTER,
+ RX_CONTROL_FRAME_PACKET_COUNTER,
+ RX_PAUSE_FRAME_PACKET_COUNTER,
+ RX_UNKNOWN_OP_CODE_COUNTER,
+ RX_ALIGNMENT_ERROR_COUNTER,
+ RX_FRAME_LENGTH_ERROR_COUNTER,
+ RX_CODE_ERROR_COUNTER,
+ RX_CARRIER_SENSE_ERROR_COUNTER,
+ RX_UNDERSIZE_PACKET_COUNTER,
+ RX_OVERSIZE_PACKET_COUNTER,
+ RX_FRAGMENTS_COUNTER,
+ RX_JABBER_COUNTER,
+ RX_DROP_PACKET_COUNTER,
+
+ TX_BYTE_COUNTER = 0x38,
+ TX_PACKET_COUNTER,
+ TX_MULTICAST_PACKET_COUNTER,
+ TX_BROADCAST_PACKET_COUNTER,
+ TX_PAUSE_CONTROL_FRAME_COUNTER,
+ TX_DEFERRAL_PACKET_COUNTER,
+ TX_EXCESSIVE_DEFERRAL_PACKET_COUNTER,
+ TX_SINGLE_COLLISION_PACKET_COUNTER,
+ TX_MULTI_COLLISION_PACKET_COUNTER,
+ TX_LATE_COLLISION_PACKET_COUNTER,
+ TX_EXCESSIVE_COLLISION_PACKET_COUNTER,
+ TX_TOTAL_COLLISION_COUNTER,
+ TX_PAUSE_FRAME_HONERED_COUNTER,
+ TX_DROP_FRAME_COUNTER,
+ TX_JABBER_FRAME_COUNTER,
+ TX_FCS_ERROR_COUNTER,
+ TX_CONTROL_FRAME_COUNTER,
+ TX_OVERSIZE_FRAME_COUNTER,
+ TX_UNDERSIZE_FRAME_COUNTER,
+ TX_FRAGMENT_FRAME_COUNTER,
+
+ CARRY_REG_1 = 0x4c,
+ CARRY_REG_2 = 0x4d,
+};
+
+struct xlr_net_priv {
+ u32 __iomem *base_addr;
+ struct net_device *ndev;
+ struct mii_bus *mii_bus;
+ int num_rx_desc;
+ int phy_addr; /* PHY addr on MDIO bus */
+ int pcs_id; /* PCS id on MDIO bus */
+ int port_id; /* Port(gmac/xgmac) number, i.e 0-7 */
+ u32 __iomem *mii_addr;
+ u32 __iomem *serdes_addr;
+ u32 __iomem *pcs_addr;
+ u32 __iomem *gpio_addr;
+ int phy_speed;
+ int port_type;
+ struct timer_list queue_timer;
+ int wakeup_q;
+ struct platform_device *pdev;
+ struct xlr_net_data *nd;
+
+ u64 *frin_spill;
+ u64 *frout_spill;
+ u64 *class_0_spill;
+ u64 *class_1_spill;
+ u64 *class_2_spill;
+ u64 *class_3_spill;
+};
+
+extern void xlr_set_gmac_speed(struct xlr_net_priv *priv);
diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig
index f779fdc34279..7e61adacd15d 100644
--- a/drivers/staging/nvec/Kconfig
+++ b/drivers/staging/nvec/Kconfig
@@ -1,5 +1,5 @@
config MFD_NVEC
- bool "NV Tegra Embedded Controller SMBus Interface"
+ tristate "NV Tegra Embedded Controller SMBus Interface"
depends on I2C && GPIOLIB && ARCH_TEGRA
select MFD_CORE
help
@@ -7,28 +7,28 @@ config MFD_NVEC
controller.
config KEYBOARD_NVEC
- bool "Keyboard on nVidia compliant EC"
+ tristate "Keyboard on nVidia compliant EC"
depends on MFD_NVEC && INPUT
help
Say Y here to enable support for a keyboard connected to
a nVidia compliant embedded controller.
config SERIO_NVEC_PS2
- bool "PS2 on nVidia EC"
+ tristate "PS2 on nVidia EC"
depends on MFD_NVEC && SERIO
help
Say Y here to enable support for a Touchpad / Mouse connected
to a nVidia compliant embedded controller.
config NVEC_POWER
- bool "NVEC charger and battery"
+ tristate "NVEC charger and battery"
depends on MFD_NVEC && POWER_SUPPLY
help
Say Y to enable support for battery and charger interface for
nVidia compliant embedded controllers.
config NVEC_PAZ00
- bool "Support for OEM specific functions on Compal PAZ00 based devices"
+ tristate "Support for OEM specific functions on Compal PAZ00 based devices"
depends on MFD_NVEC && LEDS_CLASS
help
Say Y to enable control of the yellow side leds on Compal PAZ00 based
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index cf159365b0ee..a88959f9a07a 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -352,10 +352,10 @@ static void nvec_toggle_global_events(struct nvec_chip *nvec, bool state)
*/
static void nvec_event_mask(char *ev, u32 mask)
{
- ev[3] = mask >> 16 && 0xff;
- ev[4] = mask >> 24 && 0xff;
- ev[5] = mask >> 0 && 0xff;
- ev[6] = mask >> 8 && 0xff;
+ ev[3] = mask >> 16 & 0xff;
+ ev[4] = mask >> 24 & 0xff;
+ ev[5] = mask >> 0 & 0xff;
+ ev[6] = mask >> 8 & 0xff;
}
/**
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 54ed6f69e3d4..193e1c68bb45 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -550,12 +550,12 @@ static int dcon_reboot_notify(struct notifier_block *nb,
struct dcon_priv *dcon = container_of(nb, struct dcon_priv, reboot_nb);
if (!dcon || !dcon->client)
- return 0;
+ return NOTIFY_DONE;
/* Turn off the DCON. Entirely. */
dcon_write(dcon, DCON_REG_MODE, 0x39);
dcon_write(dcon, DCON_REG_MODE, 0x32);
- return 0;
+ return NOTIFY_DONE;
}
static int unfreeze_on_panic(struct notifier_block *nb,
diff --git a/drivers/staging/omap-thermal/Makefile b/drivers/staging/omap-thermal/Makefile
deleted file mode 100644
index 091c4d20b14d..000000000000
--- a/drivers/staging/omap-thermal/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_OMAP_BANDGAP) += omap-thermal.o
-omap-thermal-y := omap-bandgap.o
-omap-thermal-$(CONFIG_OMAP_THERMAL) += omap-thermal-common.o
-omap-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal.o
-omap-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal.o
diff --git a/drivers/staging/omap-thermal/TODO b/drivers/staging/omap-thermal/TODO
deleted file mode 100644
index 9e23cc4d551b..000000000000
--- a/drivers/staging/omap-thermal/TODO
+++ /dev/null
@@ -1,28 +0,0 @@
-List of TODOs (by Eduardo Valentin)
-
-on omap-bandgap.c:
-- Rework locking
-- Improve driver code by adding usage of regmap-mmio
-- Test every exposed API to userland
-- Add support to hwmon
-- Review and revisit all API exposed
-- Revisit PM support
-- Revisit data structures and simplify them
-- Once SCM-core api settles, update this driver accordingly
-
-on omap-thermal-common.c/omap-thermal.h:
-- Revisit extrapolation constants for O4/O5
-- Revisit need for locking
-- Revisit trips and its definitions
-- Revisit trending
-
-on omap5-thermal.c
-- Add support for GPU cooling
-
-generally:
-- write Kconfig dependencies so that omap variants are covered
-- make checkpatch.pl and sparse happy
-- make sure this code works on OMAP4430, OMAP4460 and OMAP5430
-- update documentation
-
-Copy patches to Eduardo Valentin <eduardo.valentin@ti.com>
diff --git a/drivers/staging/omap-thermal/omap-bandgap.c b/drivers/staging/omap-thermal/omap-bandgap.c
deleted file mode 100644
index dcc1448dbf8e..000000000000
--- a/drivers/staging/omap-thermal/omap-bandgap.c
+++ /dev/null
@@ -1,1174 +0,0 @@
-/*
- * OMAP4 Bandgap temperature sensor driver
- *
- * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
- * Author: J Keerthy <j-keerthy@ti.com>
- * Author: Moiz Sonasath <m-sonasath@ti.com>
- * Couple of fixes, DT and MFD adaptation:
- * Eduardo Valentin <eduardo.valentin@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 <linux/export.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/types.h>
-#include <linux/mutex.h>
-#include <linux/reboot.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/of_irq.h>
-#include <linux/io.h>
-
-#include "omap-bandgap.h"
-
-static u32 omap_bandgap_readl(struct omap_bandgap *bg_ptr, u32 reg)
-{
- return readl(bg_ptr->base + reg);
-}
-
-static void omap_bandgap_writel(struct omap_bandgap *bg_ptr, u32 val, u32 reg)
-{
- writel(val, bg_ptr->base + reg);
-}
-
-static int omap_bandgap_power(struct omap_bandgap *bg_ptr, bool on)
-{
- struct temp_sensor_registers *tsr;
- int i;
- u32 ctrl;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, POWER_SWITCH))
- return 0;
-
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- tsr = bg_ptr->conf->sensors[i].registers;
- ctrl = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- ctrl &= ~tsr->bgap_tempsoff_mask;
- /* active on 0 */
- ctrl |= !on << __ffs(tsr->bgap_tempsoff_mask);
-
- /* write BGAP_TEMPSOFF should be reset to 0 */
- omap_bandgap_writel(bg_ptr, ctrl, tsr->temp_sensor_ctrl);
- }
-
- return 0;
-}
-
-/* This is the Talert handler. Call it only if HAS(TALERT) is set */
-static irqreturn_t talert_irq_handler(int irq, void *data)
-{
- struct omap_bandgap *bg_ptr = data;
- struct temp_sensor_registers *tsr;
- u32 t_hot = 0, t_cold = 0, temp, ctrl;
- int i;
-
- bg_ptr = data;
- /* Read the status of t_hot */
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- tsr = bg_ptr->conf->sensors[i].registers;
- t_hot = omap_bandgap_readl(bg_ptr, tsr->bgap_status);
- t_hot &= tsr->status_hot_mask;
-
- /* Read the status of t_cold */
- t_cold = omap_bandgap_readl(bg_ptr, tsr->bgap_status);
- t_cold &= tsr->status_cold_mask;
-
- if (!t_cold && !t_hot)
- continue;
-
- ctrl = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
- /*
- * One TALERT interrupt: Two sources
- * If the interrupt is due to t_hot then mask t_hot and
- * and unmask t_cold else mask t_cold and unmask t_hot
- */
- if (t_hot) {
- ctrl &= ~tsr->mask_hot_mask;
- ctrl |= tsr->mask_cold_mask;
- } else if (t_cold) {
- ctrl &= ~tsr->mask_cold_mask;
- ctrl |= tsr->mask_hot_mask;
- }
-
- omap_bandgap_writel(bg_ptr, ctrl, tsr->bgap_mask_ctrl);
-
- dev_dbg(bg_ptr->dev,
- "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
- __func__, bg_ptr->conf->sensors[i].domain,
- t_hot, t_cold);
-
- /* read temperature */
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= tsr->bgap_dtemp_mask;
-
- /* report temperature to whom may concern */
- if (bg_ptr->conf->report_temperature)
- bg_ptr->conf->report_temperature(bg_ptr, i);
- }
-
- return IRQ_HANDLED;
-}
-
-/* This is the Tshut handler. Call it only if HAS(TSHUT) is set */
-static irqreturn_t omap_bandgap_tshut_irq_handler(int irq, void *data)
-{
- orderly_poweroff(true);
-
- return IRQ_HANDLED;
-}
-
-static
-int adc_to_temp_conversion(struct omap_bandgap *bg_ptr, int id, int adc_val,
- int *t)
-{
- struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
-
- /* look up for temperature in the table and return the temperature */
- if (adc_val < ts_data->adc_start_val || adc_val > ts_data->adc_end_val)
- return -ERANGE;
-
- *t = bg_ptr->conv_table[adc_val - ts_data->adc_start_val];
-
- return 0;
-}
-
-static int temp_to_adc_conversion(long temp, struct omap_bandgap *bg_ptr, int i,
- int *adc)
-{
- struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[i].ts_data;
- int high, low, mid;
-
- low = 0;
- high = ts_data->adc_end_val - ts_data->adc_start_val;
- mid = (high + low) / 2;
-
- if (temp < bg_ptr->conv_table[low] || temp > bg_ptr->conv_table[high])
- return -EINVAL;
-
- while (low < high) {
- if (temp < bg_ptr->conv_table[mid])
- high = mid - 1;
- else
- low = mid + 1;
- mid = (low + high) / 2;
- }
-
- *adc = ts_data->adc_start_val + low;
-
- return 0;
-}
-
-/* Talert masks. Call it only if HAS(TALERT) is set */
-static int temp_sensor_unmask_interrupts(struct omap_bandgap *bg_ptr, int id,
- u32 t_hot, u32 t_cold)
-{
- struct temp_sensor_registers *tsr;
- u32 temp, reg_val;
-
- /* Read the current on die temperature */
- tsr = bg_ptr->conf->sensors[id].registers;
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= tsr->bgap_dtemp_mask;
-
- reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
- if (temp < t_hot)
- reg_val |= tsr->mask_hot_mask;
- else
- reg_val &= ~tsr->mask_hot_mask;
-
- if (t_cold < temp)
- reg_val |= tsr->mask_cold_mask;
- else
- reg_val &= ~tsr->mask_cold_mask;
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl);
-
- return 0;
-}
-
-static
-int add_hyst(int adc_val, int hyst_val, struct omap_bandgap *bg_ptr, int i,
- u32 *sum)
-{
- int temp, ret;
-
- ret = adc_to_temp_conversion(bg_ptr, i, adc_val, &temp);
- if (ret < 0)
- return ret;
-
- temp += hyst_val;
-
- return temp_to_adc_conversion(temp, bg_ptr, i, sum);
-}
-
-/* Talert Thot threshold. Call it only if HAS(TALERT) is set */
-static
-int temp_sensor_configure_thot(struct omap_bandgap *bg_ptr, int id, int t_hot)
-{
- struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
- struct temp_sensor_registers *tsr;
- u32 thresh_val, reg_val;
- int cold, err = 0;
-
- tsr = bg_ptr->conf->sensors[id].registers;
-
- /* obtain the T cold value */
- thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
- cold = (thresh_val & tsr->threshold_tcold_mask) >>
- __ffs(tsr->threshold_tcold_mask);
- if (t_hot <= cold) {
- /* change the t_cold to t_hot - 5000 millidegrees */
- err |= add_hyst(t_hot, -ts_data->hyst_val, bg_ptr, id, &cold);
- /* write the new t_cold value */
- reg_val = thresh_val & (~tsr->threshold_tcold_mask);
- reg_val |= cold << __ffs(tsr->threshold_tcold_mask);
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
- thresh_val = reg_val;
- }
-
- /* write the new t_hot value */
- reg_val = thresh_val & ~tsr->threshold_thot_mask;
- reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask));
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
- if (err) {
- dev_err(bg_ptr->dev, "failed to reprogram thot threshold\n");
- return -EIO;
- }
-
- return temp_sensor_unmask_interrupts(bg_ptr, id, t_hot, cold);
-}
-
-/* Talert Thot and Tcold thresholds. Call it only if HAS(TALERT) is set */
-static
-int temp_sensor_init_talert_thresholds(struct omap_bandgap *bg_ptr, int id,
- int t_hot, int t_cold)
-{
- struct temp_sensor_registers *tsr;
- u32 reg_val, thresh_val;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
-
- /* write the new t_cold value */
- reg_val = thresh_val & ~tsr->threshold_tcold_mask;
- reg_val |= (t_cold << __ffs(tsr->threshold_tcold_mask));
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
-
- thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
-
- /* write the new t_hot value */
- reg_val = thresh_val & ~tsr->threshold_thot_mask;
- reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask));
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
-
- reg_val = omap_bandgap_readl(bg_ptr, tsr->bgap_mask_ctrl);
- reg_val |= tsr->mask_hot_mask;
- reg_val |= tsr->mask_cold_mask;
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_mask_ctrl);
-
- return 0;
-}
-
-/* Talert Tcold threshold. Call it only if HAS(TALERT) is set */
-static
-int temp_sensor_configure_tcold(struct omap_bandgap *bg_ptr, int id,
- int t_cold)
-{
- struct temp_sensor_data *ts_data = bg_ptr->conf->sensors[id].ts_data;
- struct temp_sensor_registers *tsr;
- u32 thresh_val, reg_val;
- int hot, err = 0;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- /* obtain the T cold value */
- thresh_val = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
- hot = (thresh_val & tsr->threshold_thot_mask) >>
- __ffs(tsr->threshold_thot_mask);
-
- if (t_cold >= hot) {
- /* change the t_hot to t_cold + 5000 millidegrees */
- err |= add_hyst(t_cold, ts_data->hyst_val, bg_ptr, id, &hot);
- /* write the new t_hot value */
- reg_val = thresh_val & (~tsr->threshold_thot_mask);
- reg_val |= hot << __ffs(tsr->threshold_thot_mask);
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
- thresh_val = reg_val;
- }
-
- /* write the new t_cold value */
- reg_val = thresh_val & ~tsr->threshold_tcold_mask;
- reg_val |= (t_cold << __ffs(tsr->threshold_tcold_mask));
- omap_bandgap_writel(bg_ptr, reg_val, tsr->bgap_threshold);
- if (err) {
- dev_err(bg_ptr->dev, "failed to reprogram tcold threshold\n");
- return -EIO;
- }
-
- return temp_sensor_unmask_interrupts(bg_ptr, id, hot, t_cold);
-}
-
-/* This is Tshut Thot config. Call it only if HAS(TSHUT_CONFIG) is set */
-static int temp_sensor_configure_tshut_hot(struct omap_bandgap *bg_ptr,
- int id, int tshut_hot)
-{
- struct temp_sensor_registers *tsr;
- u32 reg_val;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- reg_val = omap_bandgap_readl(bg_ptr, tsr->tshut_threshold);
- reg_val &= ~tsr->tshut_hot_mask;
- reg_val |= tshut_hot << __ffs(tsr->tshut_hot_mask);
- omap_bandgap_writel(bg_ptr, reg_val, tsr->tshut_threshold);
-
- return 0;
-}
-
-/* This is Tshut Tcold config. Call it only if HAS(TSHUT_CONFIG) is set */
-static int temp_sensor_configure_tshut_cold(struct omap_bandgap *bg_ptr,
- int id, int tshut_cold)
-{
- struct temp_sensor_registers *tsr;
- u32 reg_val;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- reg_val = omap_bandgap_readl(bg_ptr, tsr->tshut_threshold);
- reg_val &= ~tsr->tshut_cold_mask;
- reg_val |= tshut_cold << __ffs(tsr->tshut_cold_mask);
- omap_bandgap_writel(bg_ptr, reg_val, tsr->tshut_threshold);
-
- return 0;
-}
-
-/* This is counter config. Call it only if HAS(COUNTER) is set */
-static int configure_temp_sensor_counter(struct omap_bandgap *bg_ptr, int id,
- u32 counter)
-{
- struct temp_sensor_registers *tsr;
- u32 val;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
- val &= ~tsr->counter_mask;
- val |= counter << __ffs(tsr->counter_mask);
- omap_bandgap_writel(bg_ptr, val, tsr->bgap_counter);
-
- return 0;
-}
-
-#define bandgap_is_valid(b) \
- (!IS_ERR_OR_NULL(b))
-#define bandgap_is_valid_sensor_id(b, i) \
- ((i) >= 0 && (i) < (b)->conf->sensor_count)
-static inline int omap_bandgap_validate(struct omap_bandgap *bg_ptr, int id)
-{
- if (!bandgap_is_valid(bg_ptr)) {
- pr_err("%s: invalid bandgap pointer\n", __func__);
- return -EINVAL;
- }
-
- if (!bandgap_is_valid_sensor_id(bg_ptr, id)) {
- dev_err(bg_ptr->dev, "%s: sensor id out of range (%d)\n",
- __func__, id);
- return -ERANGE;
- }
-
- return 0;
-}
-
-/* Exposed APIs */
-/**
- * omap_bandgap_read_thot() - reads sensor current thot
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @thot - resulting current thot value
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_read_thot(struct omap_bandgap *bg_ptr, int id,
- int *thot)
-{
- struct temp_sensor_registers *tsr;
- u32 temp;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- return -ENOTSUPP;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
- temp = (temp & tsr->threshold_thot_mask) >>
- __ffs(tsr->threshold_thot_mask);
- ret |= adc_to_temp_conversion(bg_ptr, id, temp, &temp);
- if (ret) {
- dev_err(bg_ptr->dev, "failed to read thot\n");
- return -EIO;
- }
-
- *thot = temp;
-
- return 0;
-}
-
-/**
- * omap_bandgap_write_thot() - sets sensor current thot
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @val - desired thot value
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_write_thot(struct omap_bandgap *bg_ptr, int id, int val)
-{
- struct temp_sensor_data *ts_data;
- struct temp_sensor_registers *tsr;
- u32 t_hot;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- return -ENOTSUPP;
-
- ts_data = bg_ptr->conf->sensors[id].ts_data;
- tsr = bg_ptr->conf->sensors[id].registers;
-
- if (val < ts_data->min_temp + ts_data->hyst_val)
- return -EINVAL;
- ret = temp_to_adc_conversion(val, bg_ptr, id, &t_hot);
- if (ret < 0)
- return ret;
-
- mutex_lock(&bg_ptr->bg_mutex);
- temp_sensor_configure_thot(bg_ptr, id, t_hot);
- mutex_unlock(&bg_ptr->bg_mutex);
-
- return 0;
-}
-
-/**
- * omap_bandgap_read_tcold() - reads sensor current tcold
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @tcold - resulting current tcold value
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id,
- int *tcold)
-{
- struct temp_sensor_registers *tsr;
- u32 temp;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- return -ENOTSUPP;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- temp = omap_bandgap_readl(bg_ptr, tsr->bgap_threshold);
- temp = (temp & tsr->threshold_tcold_mask)
- >> __ffs(tsr->threshold_tcold_mask);
- ret |= adc_to_temp_conversion(bg_ptr, id, temp, &temp);
- if (ret)
- return -EIO;
-
- *tcold = temp;
-
- return 0;
-}
-
-/**
- * omap_bandgap_write_tcold() - sets the sensor tcold
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @val - desired tcold value
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_write_tcold(struct omap_bandgap *bg_ptr, int id, int val)
-{
- struct temp_sensor_data *ts_data;
- struct temp_sensor_registers *tsr;
- u32 t_cold;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- return -ENOTSUPP;
-
- ts_data = bg_ptr->conf->sensors[id].ts_data;
- tsr = bg_ptr->conf->sensors[id].registers;
- if (val > ts_data->max_temp + ts_data->hyst_val)
- return -EINVAL;
-
- ret = temp_to_adc_conversion(val, bg_ptr, id, &t_cold);
- if (ret < 0)
- return ret;
-
- mutex_lock(&bg_ptr->bg_mutex);
- temp_sensor_configure_tcold(bg_ptr, id, t_cold);
- mutex_unlock(&bg_ptr->bg_mutex);
-
- return 0;
-}
-
-/**
- * omap_bandgap_read_update_interval() - read the sensor update interval
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @interval - resulting update interval in miliseconds
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id,
- int *interval)
-{
- struct temp_sensor_registers *tsr;
- u32 time;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- return -ENOTSUPP;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- time = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
- time = (time & tsr->counter_mask) >> __ffs(tsr->counter_mask);
- time = time * 1000 / bg_ptr->clk_rate;
-
- *interval = time;
-
- return 0;
-}
-
-/**
- * omap_bandgap_write_update_interval() - set the update interval
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @interval - desired update interval in miliseconds
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_write_update_interval(struct omap_bandgap *bg_ptr,
- int id, u32 interval)
-{
- int ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- if (!OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- return -ENOTSUPP;
-
- interval = interval * bg_ptr->clk_rate / 1000;
- mutex_lock(&bg_ptr->bg_mutex);
- configure_temp_sensor_counter(bg_ptr, id, interval);
- mutex_unlock(&bg_ptr->bg_mutex);
-
- return 0;
-}
-
-/**
- * omap_bandgap_read_temperature() - report current temperature
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @temperature - resulting temperature
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id,
- int *temperature)
-{
- struct temp_sensor_registers *tsr;
- u32 temp;
- int ret;
-
- ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= tsr->bgap_dtemp_mask;
-
- ret |= adc_to_temp_conversion(bg_ptr, id, temp, &temp);
- if (ret)
- return -EIO;
-
- *temperature = temp;
-
- return 0;
-}
-
-/**
- * omap_bandgap_set_sensor_data() - helper function to store thermal
- * framework related data.
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- * @data - thermal framework related data to be stored
- *
- * returns 0 on success or the proper error code
- */
-int omap_bandgap_set_sensor_data(struct omap_bandgap *bg_ptr, int id,
- void *data)
-{
- int ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ret;
-
- bg_ptr->conf->sensors[id].data = data;
-
- return 0;
-}
-
-/**
- * omap_bandgap_get_sensor_data() - helper function to get thermal
- * framework related data.
- * @bg_ptr - pointer to bandgap instance
- * @id - sensor id
- *
- * returns data stored by set function with sensor id on success or NULL
- */
-void *omap_bandgap_get_sensor_data(struct omap_bandgap *bg_ptr, int id)
-{
- int ret = omap_bandgap_validate(bg_ptr, id);
- if (ret)
- return ERR_PTR(ret);
-
- return bg_ptr->conf->sensors[id].data;
-}
-
-static int
-omap_bandgap_force_single_read(struct omap_bandgap *bg_ptr, int id)
-{
- struct temp_sensor_registers *tsr;
- u32 temp = 0, counter = 1000;
-
- tsr = bg_ptr->conf->sensors[id].registers;
- /* Select single conversion mode */
- if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) {
- temp = omap_bandgap_readl(bg_ptr, tsr->bgap_mode_ctrl);
- temp &= ~(1 << __ffs(tsr->mode_ctrl_mask));
- omap_bandgap_writel(bg_ptr, temp, tsr->bgap_mode_ctrl);
- }
-
- /* Start of Conversion = 1 */
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp |= 1 << __ffs(tsr->bgap_soc_mask);
- omap_bandgap_writel(bg_ptr, temp, tsr->temp_sensor_ctrl);
- /* Wait until DTEMP is updated */
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= (tsr->bgap_dtemp_mask);
- while ((temp == 0) && --counter) {
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= (tsr->bgap_dtemp_mask);
- }
- /* Start of Conversion = 0 */
- temp = omap_bandgap_readl(bg_ptr, tsr->temp_sensor_ctrl);
- temp &= ~(1 << __ffs(tsr->bgap_soc_mask));
- omap_bandgap_writel(bg_ptr, temp, tsr->temp_sensor_ctrl);
-
- return 0;
-}
-
-/**
- * enable_continuous_mode() - One time enabling of continuous conversion mode
- * @bg_ptr - pointer to scm instance
- *
- * Call this function only if HAS(MODE_CONFIG) is set
- */
-static int enable_continuous_mode(struct omap_bandgap *bg_ptr)
-{
- struct temp_sensor_registers *tsr;
- int i;
- u32 val;
-
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- /* Perform a single read just before enabling continuous */
- omap_bandgap_force_single_read(bg_ptr, i);
- tsr = bg_ptr->conf->sensors[i].registers;
- val = omap_bandgap_readl(bg_ptr, tsr->bgap_mode_ctrl);
- val |= 1 << __ffs(tsr->mode_ctrl_mask);
- omap_bandgap_writel(bg_ptr, val, tsr->bgap_mode_ctrl);
- }
-
- return 0;
-}
-
-static int omap_bandgap_tshut_init(struct omap_bandgap *bg_ptr,
- struct platform_device *pdev)
-{
- int gpio_nr = bg_ptr->tshut_gpio;
- int status;
-
- /* Request for gpio_86 line */
- status = gpio_request(gpio_nr, "tshut");
- if (status < 0) {
- dev_err(bg_ptr->dev,
- "Could not request for TSHUT GPIO:%i\n", 86);
- return status;
- }
- status = gpio_direction_input(gpio_nr);
- if (status) {
- dev_err(bg_ptr->dev,
- "Cannot set input TSHUT GPIO %d\n", gpio_nr);
- return status;
- }
-
- status = request_irq(gpio_to_irq(gpio_nr),
- omap_bandgap_tshut_irq_handler,
- IRQF_TRIGGER_RISING, "tshut",
- NULL);
- if (status) {
- gpio_free(gpio_nr);
- dev_err(bg_ptr->dev, "request irq failed for TSHUT");
- }
-
- return 0;
-}
-
-/* Initialization of Talert. Call it only if HAS(TALERT) is set */
-static int omap_bandgap_talert_init(struct omap_bandgap *bg_ptr,
- struct platform_device *pdev)
-{
- int ret;
-
- bg_ptr->irq = platform_get_irq(pdev, 0);
- if (bg_ptr->irq < 0) {
- dev_err(&pdev->dev, "get_irq failed\n");
- return bg_ptr->irq;
- }
- ret = request_threaded_irq(bg_ptr->irq, NULL,
- talert_irq_handler,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "talert", bg_ptr);
- if (ret) {
- dev_err(&pdev->dev, "Request threaded irq failed.\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct of_device_id of_omap_bandgap_match[];
-static struct omap_bandgap *omap_bandgap_build(struct platform_device *pdev)
-{
- struct device_node *node = pdev->dev.of_node;
- const struct of_device_id *of_id;
- struct omap_bandgap *bg_ptr;
- struct resource *res;
- u32 prop;
- int i;
-
- /* just for the sake */
- if (!node) {
- dev_err(&pdev->dev, "no platform information available\n");
- return ERR_PTR(-EINVAL);
- }
-
- bg_ptr = devm_kzalloc(&pdev->dev, sizeof(struct omap_bandgap),
- GFP_KERNEL);
- if (!bg_ptr) {
- dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
- return ERR_PTR(-ENOMEM);
- }
-
- of_id = of_match_device(of_omap_bandgap_match, &pdev->dev);
- if (of_id)
- bg_ptr->conf = of_id->data;
-
- i = 0;
- do {
- void __iomem *chunk;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res)
- break;
- chunk = devm_ioremap_resource(&pdev->dev, res);
- if (i == 0)
- bg_ptr->base = chunk;
- if (IS_ERR(chunk))
- return ERR_CAST(chunk);
-
- i++;
- } while (res);
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
- if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
- dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
- return ERR_PTR(-EINVAL);
- }
- bg_ptr->tshut_gpio = prop;
- if (!gpio_is_valid(bg_ptr->tshut_gpio)) {
- dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
- bg_ptr->tshut_gpio);
- return ERR_PTR(-EINVAL);
- }
- }
-
- return bg_ptr;
-}
-
-static
-int omap_bandgap_probe(struct platform_device *pdev)
-{
- struct omap_bandgap *bg_ptr;
- int clk_rate, ret = 0, i;
-
- bg_ptr = omap_bandgap_build(pdev);
- if (IS_ERR_OR_NULL(bg_ptr)) {
- dev_err(&pdev->dev, "failed to fetch platform data\n");
- return PTR_ERR(bg_ptr);
- }
- bg_ptr->dev = &pdev->dev;
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
- ret = omap_bandgap_tshut_init(bg_ptr, pdev);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to initialize system tshut IRQ\n");
- return ret;
- }
- }
-
- bg_ptr->fclock = clk_get(NULL, bg_ptr->conf->fclock_name);
- ret = IS_ERR_OR_NULL(bg_ptr->fclock);
- if (ret) {
- dev_err(&pdev->dev, "failed to request fclock reference\n");
- goto free_irqs;
- }
-
- bg_ptr->div_clk = clk_get(NULL, bg_ptr->conf->div_ck_name);
- ret = IS_ERR_OR_NULL(bg_ptr->div_clk);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to request div_ts_ck clock ref\n");
- goto free_irqs;
- }
-
- bg_ptr->conv_table = bg_ptr->conf->conv_table;
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- struct temp_sensor_registers *tsr;
- u32 val;
-
- tsr = bg_ptr->conf->sensors[i].registers;
- /*
- * check if the efuse has a non-zero value if not
- * it is an untrimmed sample and the temperatures
- * may not be accurate
- */
- val = omap_bandgap_readl(bg_ptr, tsr->bgap_efuse);
- if (ret || !val)
- dev_info(&pdev->dev,
- "Non-trimmed BGAP, Temp not accurate\n");
- }
-
- clk_rate = clk_round_rate(bg_ptr->div_clk,
- bg_ptr->conf->sensors[0].ts_data->max_freq);
- if (clk_rate < bg_ptr->conf->sensors[0].ts_data->min_freq ||
- clk_rate == 0xffffffff) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
- goto put_clks;
- }
-
- ret = clk_set_rate(bg_ptr->div_clk, clk_rate);
- if (ret)
- dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
-
- bg_ptr->clk_rate = clk_rate;
- clk_enable(bg_ptr->fclock);
-
- mutex_init(&bg_ptr->bg_mutex);
- bg_ptr->dev = &pdev->dev;
- platform_set_drvdata(pdev, bg_ptr);
-
- omap_bandgap_power(bg_ptr, true);
-
- /* Set default counter to 1 for now */
- if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- for (i = 0; i < bg_ptr->conf->sensor_count; i++)
- configure_temp_sensor_counter(bg_ptr, i, 1);
-
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- struct temp_sensor_data *ts_data;
-
- ts_data = bg_ptr->conf->sensors[i].ts_data;
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- temp_sensor_init_talert_thresholds(bg_ptr, i,
- ts_data->t_hot,
- ts_data->t_cold);
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) {
- temp_sensor_configure_tshut_hot(bg_ptr, i,
- ts_data->tshut_hot);
- temp_sensor_configure_tshut_cold(bg_ptr, i,
- ts_data->tshut_cold);
- }
- }
-
- if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
- enable_continuous_mode(bg_ptr);
-
- /* Set .250 seconds time as default counter */
- if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- for (i = 0; i < bg_ptr->conf->sensor_count; i++)
- configure_temp_sensor_counter(bg_ptr, i,
- bg_ptr->clk_rate / 4);
-
- /* Every thing is good? Then expose the sensors */
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- char *domain;
-
- if (bg_ptr->conf->sensors[i].register_cooling)
- bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i);
-
- domain = bg_ptr->conf->sensors[i].domain;
- if (bg_ptr->conf->expose_sensor)
- bg_ptr->conf->expose_sensor(bg_ptr, i, domain);
- }
-
- /*
- * Enable the Interrupts once everything is set. Otherwise irq handler
- * might be called as soon as it is enabled where as rest of framework
- * is still getting initialised.
- */
- if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
- ret = omap_bandgap_talert_init(bg_ptr, pdev);
- if (ret) {
- dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
- i = bg_ptr->conf->sensor_count;
- goto disable_clk;
- }
- }
-
- return 0;
-
-disable_clk:
- clk_disable(bg_ptr->fclock);
-put_clks:
- clk_put(bg_ptr->fclock);
- clk_put(bg_ptr->div_clk);
-free_irqs:
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
- free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
- gpio_free(bg_ptr->tshut_gpio);
- }
-
- return ret;
-}
-
-static
-int omap_bandgap_remove(struct platform_device *pdev)
-{
- struct omap_bandgap *bg_ptr = platform_get_drvdata(pdev);
- int i;
-
- /* First thing is to remove sensor interfaces */
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- if (bg_ptr->conf->sensors[i].register_cooling)
- bg_ptr->conf->sensors[i].unregister_cooling(bg_ptr, i);
-
- if (bg_ptr->conf->remove_sensor)
- bg_ptr->conf->remove_sensor(bg_ptr, i);
- }
-
- omap_bandgap_power(bg_ptr, false);
-
- clk_disable(bg_ptr->fclock);
- clk_put(bg_ptr->fclock);
- clk_put(bg_ptr->div_clk);
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TALERT))
- free_irq(bg_ptr->irq, bg_ptr);
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT)) {
- free_irq(gpio_to_irq(bg_ptr->tshut_gpio), NULL);
- gpio_free(bg_ptr->tshut_gpio);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr)
-{
- int i;
-
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- struct temp_sensor_registers *tsr;
- struct temp_sensor_regval *rval;
-
- rval = &bg_ptr->conf->sensors[i].regval;
- tsr = bg_ptr->conf->sensors[i].registers;
-
- if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
- rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr,
- tsr->bgap_mode_ctrl);
- if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- rval->bg_counter = omap_bandgap_readl(bg_ptr,
- tsr->bgap_counter);
- if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
- rval->bg_threshold = omap_bandgap_readl(bg_ptr,
- tsr->bgap_threshold);
- rval->bg_ctrl = omap_bandgap_readl(bg_ptr,
- tsr->bgap_mask_ctrl);
- }
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
- rval->tshut_threshold = omap_bandgap_readl(bg_ptr,
- tsr->tshut_threshold);
- }
-
- return 0;
-}
-
-static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr)
-{
- int i;
-
- for (i = 0; i < bg_ptr->conf->sensor_count; i++) {
- struct temp_sensor_registers *tsr;
- struct temp_sensor_regval *rval;
- u32 val = 0;
-
- rval = &bg_ptr->conf->sensors[i].regval;
- tsr = bg_ptr->conf->sensors[i].registers;
-
- if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- val = omap_bandgap_readl(bg_ptr, tsr->bgap_counter);
-
- if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG))
- omap_bandgap_writel(bg_ptr,
- rval->tshut_threshold,
- tsr->tshut_threshold);
- /* Force immediate temperature measurement and update
- * of the DTEMP field
- */
- omap_bandgap_force_single_read(bg_ptr, i);
-
- if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER))
- omap_bandgap_writel(bg_ptr, rval->bg_counter,
- tsr->bgap_counter);
- if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG))
- omap_bandgap_writel(bg_ptr, rval->bg_mode_ctrl,
- tsr->bgap_mode_ctrl);
- if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) {
- omap_bandgap_writel(bg_ptr,
- rval->bg_threshold,
- tsr->bgap_threshold);
- omap_bandgap_writel(bg_ptr, rval->bg_ctrl,
- tsr->bgap_mask_ctrl);
- }
- }
-
- return 0;
-}
-
-static int omap_bandgap_suspend(struct device *dev)
-{
- struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
- int err;
-
- err = omap_bandgap_save_ctxt(bg_ptr);
- omap_bandgap_power(bg_ptr, false);
- clk_disable(bg_ptr->fclock);
-
- return err;
-}
-
-static int omap_bandgap_resume(struct device *dev)
-{
- struct omap_bandgap *bg_ptr = dev_get_drvdata(dev);
-
- clk_enable(bg_ptr->fclock);
- omap_bandgap_power(bg_ptr, true);
-
- return omap_bandgap_restore_ctxt(bg_ptr);
-}
-static const struct dev_pm_ops omap_bandgap_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(omap_bandgap_suspend,
- omap_bandgap_resume)
-};
-
-#define DEV_PM_OPS (&omap_bandgap_dev_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif
-
-static const struct of_device_id of_omap_bandgap_match[] = {
-#ifdef CONFIG_OMAP4_THERMAL
- {
- .compatible = "ti,omap4430-bandgap",
- .data = (void *)&omap4430_data,
- },
- {
- .compatible = "ti,omap4460-bandgap",
- .data = (void *)&omap4460_data,
- },
- {
- .compatible = "ti,omap4470-bandgap",
- .data = (void *)&omap4470_data,
- },
-#endif
-#ifdef CONFIG_OMAP5_THERMAL
- {
- .compatible = "ti,omap5430-bandgap",
- .data = (void *)&omap5430_data,
- },
-#endif
- /* Sentinel */
- { },
-};
-MODULE_DEVICE_TABLE(of, of_omap_bandgap_match);
-
-static struct platform_driver omap_bandgap_sensor_driver = {
- .probe = omap_bandgap_probe,
- .remove = omap_bandgap_remove,
- .driver = {
- .name = "omap-bandgap",
- .pm = DEV_PM_OPS,
- .of_match_table = of_omap_bandgap_match,
- },
-};
-
-module_platform_driver(omap_bandgap_sensor_driver);
-
-MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:omap-bandgap");
-MODULE_AUTHOR("Texas Instrument Inc.");
diff --git a/drivers/staging/omap-thermal/omap-bandgap.h b/drivers/staging/omap-thermal/omap-bandgap.h
deleted file mode 100644
index 2bb14bd7c6d9..000000000000
--- a/drivers/staging/omap-thermal/omap-bandgap.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * OMAP4 Bandgap temperature sensor driver
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- * Eduardo Valentin <eduardo.valentin@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
- *
- */
-#ifndef __OMAP_BANDGAP_H
-#define __OMAP_BANDGAP_H
-
-#include <linux/mutex.h>
-#include <linux/types.h>
-#include <linux/err.h>
-
-/* TEMP_SENSOR OMAP4430 */
-#define OMAP4430_BGAP_TSHUT_SHIFT 11
-#define OMAP4430_BGAP_TSHUT_MASK (1 << 11)
-
-/* TEMP_SENSOR OMAP4430 */
-#define OMAP4430_BGAP_TEMPSOFF_SHIFT 12
-#define OMAP4430_BGAP_TEMPSOFF_MASK (1 << 12)
-#define OMAP4430_SINGLE_MODE_SHIFT 10
-#define OMAP4430_SINGLE_MODE_MASK (1 << 10)
-#define OMAP4430_BGAP_TEMP_SENSOR_SOC_SHIFT 9
-#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 9)
-#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 8
-#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 8)
-#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
-#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
-
-#define OMAP4430_ADC_START_VALUE 0
-#define OMAP4430_ADC_END_VALUE 127
-#define OMAP4430_MAX_FREQ 32768
-#define OMAP4430_MIN_FREQ 32768
-#define OMAP4430_MIN_TEMP -40000
-#define OMAP4430_MAX_TEMP 125000
-#define OMAP4430_HYST_VAL 5000
-
-/* TEMP_SENSOR OMAP4460 */
-#define OMAP4460_BGAP_TEMPSOFF_SHIFT 13
-#define OMAP4460_BGAP_TEMPSOFF_MASK (1 << 13)
-#define OMAP4460_BGAP_TEMP_SENSOR_SOC_SHIFT 11
-#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK (1 << 11)
-#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
-#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
-#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
-#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
-
-/* BANDGAP_CTRL */
-#define OMAP4460_SINGLE_MODE_SHIFT 31
-#define OMAP4460_SINGLE_MODE_MASK (1 << 31)
-#define OMAP4460_MASK_HOT_SHIFT 1
-#define OMAP4460_MASK_HOT_MASK (1 << 1)
-#define OMAP4460_MASK_COLD_SHIFT 0
-#define OMAP4460_MASK_COLD_MASK (1 << 0)
-
-/* BANDGAP_COUNTER */
-#define OMAP4460_COUNTER_SHIFT 0
-#define OMAP4460_COUNTER_MASK (0xffffff << 0)
-
-/* BANDGAP_THRESHOLD */
-#define OMAP4460_T_HOT_SHIFT 16
-#define OMAP4460_T_HOT_MASK (0x3ff << 16)
-#define OMAP4460_T_COLD_SHIFT 0
-#define OMAP4460_T_COLD_MASK (0x3ff << 0)
-
-/* TSHUT_THRESHOLD */
-#define OMAP4460_TSHUT_HOT_SHIFT 16
-#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
-#define OMAP4460_TSHUT_COLD_SHIFT 0
-#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
-
-/* BANDGAP_STATUS */
-#define OMAP4460_CLEAN_STOP_SHIFT 3
-#define OMAP4460_CLEAN_STOP_MASK (1 << 3)
-#define OMAP4460_BGAP_ALERT_SHIFT 2
-#define OMAP4460_BGAP_ALERT_MASK (1 << 2)
-#define OMAP4460_HOT_FLAG_SHIFT 1
-#define OMAP4460_HOT_FLAG_MASK (1 << 1)
-#define OMAP4460_COLD_FLAG_SHIFT 0
-#define OMAP4460_COLD_FLAG_MASK (1 << 0)
-
-/* TEMP_SENSOR OMAP5430 */
-#define OMAP5430_BGAP_TEMP_SENSOR_SOC_SHIFT 12
-#define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK (1 << 12)
-#define OMAP5430_BGAP_TEMPSOFF_SHIFT 11
-#define OMAP5430_BGAP_TEMPSOFF_MASK (1 << 11)
-#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_SHIFT 10
-#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK (1 << 10)
-#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_SHIFT 0
-#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
-
-/* BANDGAP_CTRL */
-#define OMAP5430_MASK_HOT_CORE_SHIFT 5
-#define OMAP5430_MASK_HOT_CORE_MASK (1 << 5)
-#define OMAP5430_MASK_COLD_CORE_SHIFT 4
-#define OMAP5430_MASK_COLD_CORE_MASK (1 << 4)
-#define OMAP5430_MASK_HOT_MM_SHIFT 3
-#define OMAP5430_MASK_HOT_MM_MASK (1 << 3)
-#define OMAP5430_MASK_COLD_MM_SHIFT 2
-#define OMAP5430_MASK_COLD_MM_MASK (1 << 2)
-#define OMAP5430_MASK_HOT_MPU_SHIFT 1
-#define OMAP5430_MASK_HOT_MPU_MASK (1 << 1)
-#define OMAP5430_MASK_COLD_MPU_SHIFT 0
-#define OMAP5430_MASK_COLD_MPU_MASK (1 << 0)
-
-/* BANDGAP_COUNTER */
-#define OMAP5430_REPEAT_MODE_SHIFT 31
-#define OMAP5430_REPEAT_MODE_MASK (1 << 31)
-#define OMAP5430_COUNTER_SHIFT 0
-#define OMAP5430_COUNTER_MASK (0xffffff << 0)
-
-/* BANDGAP_THRESHOLD */
-#define OMAP5430_T_HOT_SHIFT 16
-#define OMAP5430_T_HOT_MASK (0x3ff << 16)
-#define OMAP5430_T_COLD_SHIFT 0
-#define OMAP5430_T_COLD_MASK (0x3ff << 0)
-
-/* TSHUT_THRESHOLD */
-#define OMAP5430_TSHUT_HOT_SHIFT 16
-#define OMAP5430_TSHUT_HOT_MASK (0x3ff << 16)
-#define OMAP5430_TSHUT_COLD_SHIFT 0
-#define OMAP5430_TSHUT_COLD_MASK (0x3ff << 0)
-
-/* BANDGAP_STATUS */
-#define OMAP5430_BGAP_ALERT_SHIFT 31
-#define OMAP5430_BGAP_ALERT_MASK (1 << 31)
-#define OMAP5430_HOT_CORE_FLAG_SHIFT 5
-#define OMAP5430_HOT_CORE_FLAG_MASK (1 << 5)
-#define OMAP5430_COLD_CORE_FLAG_SHIFT 4
-#define OMAP5430_COLD_CORE_FLAG_MASK (1 << 4)
-#define OMAP5430_HOT_MM_FLAG_SHIFT 3
-#define OMAP5430_HOT_MM_FLAG_MASK (1 << 3)
-#define OMAP5430_COLD_MM_FLAG_SHIFT 2
-#define OMAP5430_COLD_MM_FLAG_MASK (1 << 2)
-#define OMAP5430_HOT_MPU_FLAG_SHIFT 1
-#define OMAP5430_HOT_MPU_FLAG_MASK (1 << 1)
-#define OMAP5430_COLD_MPU_FLAG_SHIFT 0
-#define OMAP5430_COLD_MPU_FLAG_MASK (1 << 0)
-
-/* Offsets from the base of temperature sensor registers */
-
-/* 4430 - All goes relative to OPP_BGAP */
-#define OMAP4430_FUSE_OPP_BGAP 0x0
-#define OMAP4430_TEMP_SENSOR_CTRL_OFFSET 0xCC
-
-/* 4460 - All goes relative to OPP_BGAP */
-#define OMAP4460_FUSE_OPP_BGAP 0x0
-#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET 0xCC
-#define OMAP4460_BGAP_CTRL_OFFSET 0x118
-#define OMAP4460_BGAP_COUNTER_OFFSET 0x11C
-#define OMAP4460_BGAP_THRESHOLD_OFFSET 0x120
-#define OMAP4460_BGAP_TSHUT_OFFSET 0x124
-#define OMAP4460_BGAP_STATUS_OFFSET 0x128
-
-/* 5430 - All goes relative to OPP_BGAP_GPU */
-#define OMAP5430_FUSE_OPP_BGAP_GPU 0x0
-#define OMAP5430_TEMP_SENSOR_GPU_OFFSET 0x150
-#define OMAP5430_BGAP_COUNTER_GPU_OFFSET 0x1C0
-#define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET 0x1A8
-#define OMAP5430_BGAP_TSHUT_GPU_OFFSET 0x1B4
-
-#define OMAP5430_FUSE_OPP_BGAP_MPU 0x4
-#define OMAP5430_TEMP_SENSOR_MPU_OFFSET 0x14C
-#define OMAP5430_BGAP_CTRL_OFFSET 0x1A0
-#define OMAP5430_BGAP_COUNTER_MPU_OFFSET 0x1BC
-#define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET 0x1A4
-#define OMAP5430_BGAP_TSHUT_MPU_OFFSET 0x1B0
-#define OMAP5430_BGAP_STATUS_OFFSET 0x1C8
-
-#define OMAP5430_FUSE_OPP_BGAP_CORE 0x8
-#define OMAP5430_TEMP_SENSOR_CORE_OFFSET 0x154
-#define OMAP5430_BGAP_COUNTER_CORE_OFFSET 0x1C4
-#define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET 0x1AC
-#define OMAP5430_BGAP_TSHUT_CORE_OFFSET 0x1B8
-
-#define OMAP4460_TSHUT_HOT 900 /* 122 deg C */
-#define OMAP4460_TSHUT_COLD 895 /* 100 deg C */
-#define OMAP4460_T_HOT 800 /* 73 deg C */
-#define OMAP4460_T_COLD 795 /* 71 deg C */
-#define OMAP4460_MAX_FREQ 1500000
-#define OMAP4460_MIN_FREQ 1000000
-#define OMAP4460_MIN_TEMP -40000
-#define OMAP4460_MAX_TEMP 123000
-#define OMAP4460_HYST_VAL 5000
-#define OMAP4460_ADC_START_VALUE 530
-#define OMAP4460_ADC_END_VALUE 932
-
-#define OMAP5430_MPU_TSHUT_HOT 915
-#define OMAP5430_MPU_TSHUT_COLD 900
-#define OMAP5430_MPU_T_HOT 800
-#define OMAP5430_MPU_T_COLD 795
-#define OMAP5430_MPU_MAX_FREQ 1500000
-#define OMAP5430_MPU_MIN_FREQ 1000000
-#define OMAP5430_MPU_MIN_TEMP -40000
-#define OMAP5430_MPU_MAX_TEMP 125000
-#define OMAP5430_MPU_HYST_VAL 5000
-#define OMAP5430_ADC_START_VALUE 532
-#define OMAP5430_ADC_END_VALUE 934
-
-
-#define OMAP5430_GPU_TSHUT_HOT 915
-#define OMAP5430_GPU_TSHUT_COLD 900
-#define OMAP5430_GPU_T_HOT 800
-#define OMAP5430_GPU_T_COLD 795
-#define OMAP5430_GPU_MAX_FREQ 1500000
-#define OMAP5430_GPU_MIN_FREQ 1000000
-#define OMAP5430_GPU_MIN_TEMP -40000
-#define OMAP5430_GPU_MAX_TEMP 125000
-#define OMAP5430_GPU_HYST_VAL 5000
-
-#define OMAP5430_CORE_TSHUT_HOT 915
-#define OMAP5430_CORE_TSHUT_COLD 900
-#define OMAP5430_CORE_T_HOT 800
-#define OMAP5430_CORE_T_COLD 795
-#define OMAP5430_CORE_MAX_FREQ 1500000
-#define OMAP5430_CORE_MIN_FREQ 1000000
-#define OMAP5430_CORE_MIN_TEMP -40000
-#define OMAP5430_CORE_MAX_TEMP 125000
-#define OMAP5430_CORE_HYST_VAL 5000
-
-/**
- * The register offsets and bit fields might change across
- * OMAP versions hence populating them in this structure.
- */
-
-struct temp_sensor_registers {
- u32 temp_sensor_ctrl;
- u32 bgap_tempsoff_mask;
- u32 bgap_soc_mask;
- u32 bgap_eocz_mask;
- u32 bgap_dtemp_mask;
-
- u32 bgap_mask_ctrl;
- u32 mask_hot_mask;
- u32 mask_cold_mask;
-
- u32 bgap_mode_ctrl;
- u32 mode_ctrl_mask;
-
- u32 bgap_counter;
- u32 counter_mask;
-
- u32 bgap_threshold;
- u32 threshold_thot_mask;
- u32 threshold_tcold_mask;
-
- u32 tshut_threshold;
- u32 tshut_hot_mask;
- u32 tshut_cold_mask;
-
- u32 bgap_status;
- u32 status_clean_stop_mask;
- u32 status_bgap_alert_mask;
- u32 status_hot_mask;
- u32 status_cold_mask;
-
- u32 bgap_efuse;
-};
-
-/**
- * The thresholds and limits for temperature sensors.
- */
-struct temp_sensor_data {
- u32 tshut_hot;
- u32 tshut_cold;
- u32 t_hot;
- u32 t_cold;
- u32 min_freq;
- u32 max_freq;
- int max_temp;
- int min_temp;
- int hyst_val;
- u32 adc_start_val;
- u32 adc_end_val;
- u32 update_int1;
- u32 update_int2;
-};
-
-struct omap_bandgap_data;
-
-/**
- * struct omap_bandgap - bandgap device structure
- * @dev: device pointer
- * @conf: platform data with sensor data
- * @fclock: pointer to functional clock of temperature sensor
- * @div_clk: pointer to parent clock of temperature sensor fclk
- * @conv_table: Pointer to adc to temperature conversion table
- * @bg_mutex: Mutex for sysfs, irq and PM
- * @irq: MPU Irq number for thermal alert
- * @tshut_gpio: GPIO where Tshut signal is routed
- * @clk_rate: Holds current clock rate
- */
-struct omap_bandgap {
- struct device *dev;
- void __iomem *base;
- struct omap_bandgap_data *conf;
- struct clk *fclock;
- struct clk *div_clk;
- const int *conv_table;
- struct mutex bg_mutex; /* Mutex for irq and PM */
- int irq;
- int tshut_gpio;
- u32 clk_rate;
-};
-
-/**
- * struct temp_sensor_regval - temperature sensor register values
- * @bg_mode_ctrl: temp sensor control register value
- * @bg_ctrl: bandgap ctrl register value
- * @bg_counter: bandgap counter value
- * @bg_threshold: bandgap threshold register value
- * @tshut_threshold: bandgap tshut register value
- */
-struct temp_sensor_regval {
- u32 bg_mode_ctrl;
- u32 bg_ctrl;
- u32 bg_counter;
- u32 bg_threshold;
- u32 tshut_threshold;
-};
-
-/**
- * struct omap_temp_sensor - bandgap temperature sensor platform data
- * @ts_data: pointer to struct with thresholds, limits of temperature sensor
- * @registers: pointer to the list of register offsets and bitfields
- * @regval: temperature sensor register values
- * @domain: the name of the domain where the sensor is located
- * @cooling_data: description on how the zone should be cooled off.
- * @slope: sensor gradient slope info for hotspot extrapolation
- * @const: sensor gradient const info for hotspot extrapolation
- * @slope_pcb: sensor gradient slope info for hotspot extrapolation
- * with no external influence
- * @const_pcb: sensor gradient const info for hotspot extrapolation
- * with no external influence
- * @data: private data
- * @register_cooling: function to describe how this sensor is going to be cooled
- * @unregister_cooling: function to release cooling data
- */
-struct omap_temp_sensor {
- struct temp_sensor_data *ts_data;
- struct temp_sensor_registers *registers;
- struct temp_sensor_regval regval;
- char *domain;
- /* for hotspot extrapolation */
- const int slope;
- const int constant;
- const int slope_pcb;
- const int constant_pcb;
- void *data;
- int (*register_cooling)(struct omap_bandgap *bg_ptr, int id);
- int (*unregister_cooling)(struct omap_bandgap *bg_ptr, int id);
-};
-
-/**
- * struct omap_bandgap_data - bandgap platform data structure
- * @features: a bitwise flag set to describe the device features
- * @conv_table: Pointer to adc to temperature conversion table
- * @fclock_name: clock name of the functional clock
- * @div_ck_nme: clock name of the clock divisor
- * @sensor_count: count of temperature sensor device in scm
- * @sensors: array of sensors present in this bandgap instance
- * @expose_sensor: callback to export sensor to thermal API
- */
-struct omap_bandgap_data {
-#define OMAP_BANDGAP_FEATURE_TSHUT (1 << 0)
-#define OMAP_BANDGAP_FEATURE_TSHUT_CONFIG (1 << 1)
-#define OMAP_BANDGAP_FEATURE_TALERT (1 << 2)
-#define OMAP_BANDGAP_FEATURE_MODE_CONFIG (1 << 3)
-#define OMAP_BANDGAP_FEATURE_COUNTER (1 << 4)
-#define OMAP_BANDGAP_FEATURE_POWER_SWITCH (1 << 5)
-#define OMAP_BANDGAP_HAS(b, f) \
- ((b)->conf->features & OMAP_BANDGAP_FEATURE_ ## f)
- unsigned int features;
- const int *conv_table;
- char *fclock_name;
- char *div_ck_name;
- int sensor_count;
- int (*report_temperature)(struct omap_bandgap *bg_ptr, int id);
- int (*expose_sensor)(struct omap_bandgap *bg_ptr, int id, char *domain);
- int (*remove_sensor)(struct omap_bandgap *bg_ptr, int id);
-
- /* this needs to be at the end */
- struct omap_temp_sensor sensors[];
-};
-
-int omap_bandgap_read_thot(struct omap_bandgap *bg_ptr, int id, int *thot);
-int omap_bandgap_write_thot(struct omap_bandgap *bg_ptr, int id, int val);
-int omap_bandgap_read_tcold(struct omap_bandgap *bg_ptr, int id, int *tcold);
-int omap_bandgap_write_tcold(struct omap_bandgap *bg_ptr, int id, int val);
-int omap_bandgap_read_update_interval(struct omap_bandgap *bg_ptr, int id,
- int *interval);
-int omap_bandgap_write_update_interval(struct omap_bandgap *bg_ptr, int id,
- u32 interval);
-int omap_bandgap_read_temperature(struct omap_bandgap *bg_ptr, int id,
- int *temperature);
-int omap_bandgap_set_sensor_data(struct omap_bandgap *bg_ptr, int id,
- void *data);
-void *omap_bandgap_get_sensor_data(struct omap_bandgap *bg_ptr, int id);
-
-#ifdef CONFIG_OMAP4_THERMAL
-extern const struct omap_bandgap_data omap4430_data;
-extern const struct omap_bandgap_data omap4460_data;
-extern const struct omap_bandgap_data omap4470_data;
-#else
-#define omap4430_data NULL
-#define omap4460_data NULL
-#define omap4470_data NULL
-#endif
-
-#ifdef CONFIG_OMAP5_THERMAL
-extern const struct omap_bandgap_data omap5430_data;
-#else
-#define omap5430_data NULL
-#endif
-
-#endif
diff --git a/drivers/staging/omap-thermal/omap-thermal-common.c b/drivers/staging/omap-thermal/omap-thermal-common.c
deleted file mode 100644
index 79a55aaae5a3..000000000000
--- a/drivers/staging/omap-thermal/omap-thermal-common.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * OMAP thermal driver interface
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Contact:
- * Eduardo Valentin <eduardo.valentin@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/device.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/workqueue.h>
-#include <linux/thermal.h>
-#include <linux/cpufreq.h>
-#include <linux/cpumask.h>
-#include <linux/cpu_cooling.h>
-
-#include "omap-thermal.h"
-#include "omap-bandgap.h"
-
-/* common data structures */
-struct omap_thermal_data {
- struct thermal_zone_device *omap_thermal;
- struct thermal_cooling_device *cool_dev;
- struct omap_bandgap *bg_ptr;
- enum thermal_device_mode mode;
- struct work_struct thermal_wq;
- int sensor_id;
-};
-
-static void omap_thermal_work(struct work_struct *work)
-{
- struct omap_thermal_data *data = container_of(work,
- struct omap_thermal_data, thermal_wq);
-
- thermal_zone_device_update(data->omap_thermal);
-
- dev_dbg(&data->omap_thermal->device, "updated thermal zone %s\n",
- data->omap_thermal->type);
-}
-
-/**
- * omap_thermal_hotspot_temperature - returns sensor extrapolated temperature
- * @t: omap sensor temperature
- * @s: omap sensor slope value
- * @c: omap sensor const value
- */
-static inline int omap_thermal_hotspot_temperature(int t, int s, int c)
-{
- int delta = t * s / 1000 + c;
-
- if (delta < 0)
- delta = 0;
-
- return t + delta;
-}
-
-/* thermal zone ops */
-/* Get temperature callback function for thermal zone*/
-static inline int omap_thermal_get_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct omap_thermal_data *data = thermal->devdata;
- struct omap_bandgap *bg_ptr;
- struct omap_temp_sensor *s;
- int ret, tmp, pcb_temp, slope, constant;
-
- if (!data)
- return 0;
-
- bg_ptr = data->bg_ptr;
- s = &bg_ptr->conf->sensors[data->sensor_id];
-
- ret = omap_bandgap_read_temperature(bg_ptr, data->sensor_id, &tmp);
- if (ret)
- return ret;
-
- pcb_temp = 0;
- /* TODO: Introduce pcb temperature lookup */
- /* In case pcb zone is available, use the extrapolation rule with it */
- if (pcb_temp) {
- tmp -= pcb_temp;
- slope = s->slope_pcb;
- constant = s->constant_pcb;
- } else {
- slope = s->slope;
- constant = s->constant;
- }
- *temp = omap_thermal_hotspot_temperature(tmp, slope, constant);
-
- return ret;
-}
-
-/* Bind callback functions for thermal zone */
-static int omap_thermal_bind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- struct omap_thermal_data *data = thermal->devdata;
- int id;
-
- if (IS_ERR_OR_NULL(data))
- return -ENODEV;
-
- /* check if this is the cooling device we registered */
- if (data->cool_dev != cdev)
- return 0;
-
- id = data->sensor_id;
-
- /* TODO: bind with min and max states */
- /* Simple thing, two trips, one passive another critical */
- return thermal_zone_bind_cooling_device(thermal, 0, cdev,
- THERMAL_NO_LIMIT,
- THERMAL_NO_LIMIT);
-}
-
-/* Unbind callback functions for thermal zone */
-static int omap_thermal_unbind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- struct omap_thermal_data *data = thermal->devdata;
-
- if (IS_ERR_OR_NULL(data))
- return -ENODEV;
-
- /* check if this is the cooling device we registered */
- if (data->cool_dev != cdev)
- return 0;
-
- /* Simple thing, two trips, one passive another critical */
- return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
-}
-
-/* Get mode callback functions for thermal zone */
-static int omap_thermal_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- struct omap_thermal_data *data = thermal->devdata;
-
- if (data)
- *mode = data->mode;
-
- return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int omap_thermal_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct omap_thermal_data *data = thermal->devdata;
-
- if (!data->omap_thermal) {
- dev_notice(&thermal->device, "thermal zone not registered\n");
- return 0;
- }
-
- mutex_lock(&data->omap_thermal->lock);
-
- if (mode == THERMAL_DEVICE_ENABLED)
- data->omap_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
- else
- data->omap_thermal->polling_delay = 0;
-
- mutex_unlock(&data->omap_thermal->lock);
-
- data->mode = mode;
- thermal_zone_device_update(data->omap_thermal);
- dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
- data->omap_thermal->polling_delay);
-
- return 0;
-}
-
-/* Get trip type callback functions for thermal zone */
-static int omap_thermal_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
-{
- if (!omap_thermal_is_valid_trip(trip))
- return -EINVAL;
-
- if (trip + 1 == OMAP_TRIP_NUMBER)
- *type = THERMAL_TRIP_CRITICAL;
- else
- *type = THERMAL_TRIP_PASSIVE;
-
- return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int omap_thermal_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, unsigned long *temp)
-{
- if (!omap_thermal_is_valid_trip(trip))
- return -EINVAL;
-
- *temp = omap_thermal_get_trip_value(trip);
-
- return 0;
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int omap_thermal_get_crit_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- /* shutdown zone */
- return omap_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
-}
-
-static struct thermal_zone_device_ops omap_thermal_ops = {
- .get_temp = omap_thermal_get_temp,
- /* TODO: add .get_trend */
- .bind = omap_thermal_bind,
- .unbind = omap_thermal_unbind,
- .get_mode = omap_thermal_get_mode,
- .set_mode = omap_thermal_set_mode,
- .get_trip_type = omap_thermal_get_trip_type,
- .get_trip_temp = omap_thermal_get_trip_temp,
- .get_crit_temp = omap_thermal_get_crit_temp,
-};
-
-static struct omap_thermal_data
-*omap_thermal_build_data(struct omap_bandgap *bg_ptr, int id)
-{
- struct omap_thermal_data *data;
-
- data = devm_kzalloc(bg_ptr->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(bg_ptr->dev, "kzalloc fail\n");
- return NULL;
- }
- data->sensor_id = id;
- data->bg_ptr = bg_ptr;
- data->mode = THERMAL_DEVICE_ENABLED;
- INIT_WORK(&data->thermal_wq, omap_thermal_work);
-
- return data;
-}
-
-int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
- char *domain)
-{
- struct omap_thermal_data *data;
-
- data = omap_bandgap_get_sensor_data(bg_ptr, id);
-
- if (IS_ERR(data))
- data = omap_thermal_build_data(bg_ptr, id);
-
- if (!data)
- return -EINVAL;
-
- /* TODO: remove TC1 TC2 */
- /* Create thermal zone */
- data->omap_thermal = thermal_zone_device_register(domain,
- OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
- NULL, FAST_TEMP_MONITORING_RATE,
- FAST_TEMP_MONITORING_RATE);
- if (IS_ERR_OR_NULL(data->omap_thermal)) {
- dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
- return PTR_ERR(data->omap_thermal);
- }
- data->omap_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
- omap_bandgap_set_sensor_data(bg_ptr, id, data);
-
- return 0;
-}
-
-int omap_thermal_remove_sensor(struct omap_bandgap *bg_ptr, int id)
-{
- struct omap_thermal_data *data;
-
- data = omap_bandgap_get_sensor_data(bg_ptr, id);
-
- thermal_zone_device_unregister(data->omap_thermal);
-
- return 0;
-}
-
-int omap_thermal_report_sensor_temperature(struct omap_bandgap *bg_ptr, int id)
-{
- struct omap_thermal_data *data;
-
- data = omap_bandgap_get_sensor_data(bg_ptr, id);
-
- schedule_work(&data->thermal_wq);
-
- return 0;
-}
-
-int omap_thermal_register_cpu_cooling(struct omap_bandgap *bg_ptr, int id)
-{
- struct omap_thermal_data *data;
-
- data = omap_bandgap_get_sensor_data(bg_ptr, id);
- if (IS_ERR(data))
- data = omap_thermal_build_data(bg_ptr, id);
-
- if (!data)
- return -EINVAL;
-
- /* Register cooling device */
- data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
- if (IS_ERR_OR_NULL(data->cool_dev)) {
- dev_err(bg_ptr->dev,
- "Failed to register cpufreq cooling device\n");
- return PTR_ERR(data->cool_dev);
- }
- omap_bandgap_set_sensor_data(bg_ptr, id, data);
-
- return 0;
-}
-
-int omap_thermal_unregister_cpu_cooling(struct omap_bandgap *bg_ptr, int id)
-{
- struct omap_thermal_data *data;
-
- data = omap_bandgap_get_sensor_data(bg_ptr, id);
- cpufreq_cooling_unregister(data->cool_dev);
-
- return 0;
-}
diff --git a/drivers/staging/omap-thermal/omap5-thermal.c b/drivers/staging/omap-thermal/omap5-thermal.c
deleted file mode 100644
index 2f3a498dacd1..000000000000
--- a/drivers/staging/omap-thermal/omap5-thermal.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * OMAP5 thermal driver.
- *
- * Copyright (C) 2011-2012 Texas Instruments Inc.
- * Contact:
- * Eduardo Valentin <eduardo.valentin@ti.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include "omap-bandgap.h"
-#include "omap-thermal.h"
-
-/*
- * omap5430 has one instance of thermal sensor for MPU
- * need to describe the individual bit fields
- */
-static struct temp_sensor_registers
-omap5430_mpu_temp_sensor_registers = {
- .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET,
- .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
- .bgap_soc_mask = OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK,
- .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
- .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
- .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
- .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK,
- .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK,
-
- .bgap_mode_ctrl = OMAP5430_BGAP_COUNTER_MPU_OFFSET,
- .mode_ctrl_mask = OMAP5430_REPEAT_MODE_MASK,
-
- .bgap_counter = OMAP5430_BGAP_COUNTER_MPU_OFFSET,
- .counter_mask = OMAP5430_COUNTER_MASK,
-
- .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET,
- .threshold_thot_mask = OMAP5430_T_HOT_MASK,
- .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
- .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET,
- .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
- .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
- .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
- .status_clean_stop_mask = 0x0,
- .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
- .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK,
- .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK,
-
- .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU,
-};
-
-/*
- * omap5430 has one instance of thermal sensor for GPU
- * need to describe the individual bit fields
- */
-static struct temp_sensor_registers
-omap5430_gpu_temp_sensor_registers = {
- .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET,
- .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
- .bgap_soc_mask = OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK,
- .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
- .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
- .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
- .mask_hot_mask = OMAP5430_MASK_HOT_MM_MASK,
- .mask_cold_mask = OMAP5430_MASK_COLD_MM_MASK,
-
- .bgap_mode_ctrl = OMAP5430_BGAP_COUNTER_GPU_OFFSET,
- .mode_ctrl_mask = OMAP5430_REPEAT_MODE_MASK,
-
- .bgap_counter = OMAP5430_BGAP_COUNTER_GPU_OFFSET,
- .counter_mask = OMAP5430_COUNTER_MASK,
-
- .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET,
- .threshold_thot_mask = OMAP5430_T_HOT_MASK,
- .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
- .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET,
- .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
- .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
- .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
- .status_clean_stop_mask = 0x0,
- .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
- .status_hot_mask = OMAP5430_HOT_MM_FLAG_MASK,
- .status_cold_mask = OMAP5430_COLD_MM_FLAG_MASK,
-
- .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU,
-};
-
-/*
- * omap5430 has one instance of thermal sensor for CORE
- * need to describe the individual bit fields
- */
-static struct temp_sensor_registers
-omap5430_core_temp_sensor_registers = {
- .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET,
- .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
- .bgap_soc_mask = OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK,
- .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
- .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
-
- .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
- .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK,
- .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK,
-
- .bgap_mode_ctrl = OMAP5430_BGAP_COUNTER_CORE_OFFSET,
- .mode_ctrl_mask = OMAP5430_REPEAT_MODE_MASK,
-
- .bgap_counter = OMAP5430_BGAP_COUNTER_CORE_OFFSET,
- .counter_mask = OMAP5430_COUNTER_MASK,
-
- .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET,
- .threshold_thot_mask = OMAP5430_T_HOT_MASK,
- .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
-
- .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET,
- .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
- .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
-
- .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
- .status_clean_stop_mask = 0x0,
- .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
- .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK,
- .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK,
-
- .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE,
-};
-
-/* Thresholds and limits for OMAP5430 MPU temperature sensor */
-static struct temp_sensor_data omap5430_mpu_temp_sensor_data = {
- .tshut_hot = OMAP5430_MPU_TSHUT_HOT,
- .tshut_cold = OMAP5430_MPU_TSHUT_COLD,
- .t_hot = OMAP5430_MPU_T_HOT,
- .t_cold = OMAP5430_MPU_T_COLD,
- .min_freq = OMAP5430_MPU_MIN_FREQ,
- .max_freq = OMAP5430_MPU_MAX_FREQ,
- .max_temp = OMAP5430_MPU_MAX_TEMP,
- .min_temp = OMAP5430_MPU_MIN_TEMP,
- .hyst_val = OMAP5430_MPU_HYST_VAL,
- .adc_start_val = OMAP5430_ADC_START_VALUE,
- .adc_end_val = OMAP5430_ADC_END_VALUE,
- .update_int1 = 1000,
- .update_int2 = 2000,
-};
-
-/* Thresholds and limits for OMAP5430 GPU temperature sensor */
-static struct temp_sensor_data omap5430_gpu_temp_sensor_data = {
- .tshut_hot = OMAP5430_GPU_TSHUT_HOT,
- .tshut_cold = OMAP5430_GPU_TSHUT_COLD,
- .t_hot = OMAP5430_GPU_T_HOT,
- .t_cold = OMAP5430_GPU_T_COLD,
- .min_freq = OMAP5430_GPU_MIN_FREQ,
- .max_freq = OMAP5430_GPU_MAX_FREQ,
- .max_temp = OMAP5430_GPU_MAX_TEMP,
- .min_temp = OMAP5430_GPU_MIN_TEMP,
- .hyst_val = OMAP5430_GPU_HYST_VAL,
- .adc_start_val = OMAP5430_ADC_START_VALUE,
- .adc_end_val = OMAP5430_ADC_END_VALUE,
- .update_int1 = 1000,
- .update_int2 = 2000,
-};
-
-/* Thresholds and limits for OMAP5430 CORE temperature sensor */
-static struct temp_sensor_data omap5430_core_temp_sensor_data = {
- .tshut_hot = OMAP5430_CORE_TSHUT_HOT,
- .tshut_cold = OMAP5430_CORE_TSHUT_COLD,
- .t_hot = OMAP5430_CORE_T_HOT,
- .t_cold = OMAP5430_CORE_T_COLD,
- .min_freq = OMAP5430_CORE_MIN_FREQ,
- .max_freq = OMAP5430_CORE_MAX_FREQ,
- .max_temp = OMAP5430_CORE_MAX_TEMP,
- .min_temp = OMAP5430_CORE_MIN_TEMP,
- .hyst_val = OMAP5430_CORE_HYST_VAL,
- .adc_start_val = OMAP5430_ADC_START_VALUE,
- .adc_end_val = OMAP5430_ADC_END_VALUE,
- .update_int1 = 1000,
- .update_int2 = 2000,
-};
-
-static const int
-omap5430_adc_to_temp[OMAP5430_ADC_END_VALUE - OMAP5430_ADC_START_VALUE + 1] = {
- -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600,
- -38200, -37800, -37300, -36800,
- -36400, -36000, -35600, -35200, -34800, -34300, -33800, -33400, -33000,
- -32600,
- -32200, -31800, -31300, -30800, -30400, -30000, -29600, -29200, -28700,
- -28200, -27800, -27400, -27000, -26600, -26200, -25700, -25200, -24800,
- -24400, -24000, -23600, -23200, -22700, -22200, -21800, -21400, -21000,
- -20600, -20200, -19700, -19200, -9300, -18400, -18000, -17600, -17200,
- -16700, -16200, -15800, -15400, -15000, -14600, -14200, -13700, -13200,
- -12800, -12400, -12000, -11600, -11200, -10700, -10200, -9800, -9400,
- -9000,
- -8600, -8200, -7700, -7200, -6800, -6400, -6000, -5600, -5200, -4800,
- -4300,
- -3800, -3400, -3000, -2600, -2200, -1800, -1300, -800, -400, 0, 400,
- 800,
- 1200, 1600, 2100, 2600, 3000, 3400, 3800, 4200, 4600, 5100, 5600, 6000,
- 6400, 6800, 7200, 7600, 8000, 8500, 9000, 9400, 9800, 10200, 10800,
- 11100,
- 11400, 11900, 12400, 12800, 13200, 13600, 14000, 14400, 14800, 15300,
- 15800,
- 16200, 16600, 17000, 17400, 17800, 18200, 18700, 19200, 19600, 20000,
- 20400,
- 20800, 21200, 21600, 22100, 22600, 23000, 23400, 23800, 24200, 24600,
- 25000,
- 25400, 25900, 26400, 26800, 27200, 27600, 28000, 28400, 28800, 29300,
- 29800,
- 30200, 30600, 31000, 31400, 31800, 32200, 32600, 33100, 33600, 34000,
- 34400,
- 34800, 35200, 35600, 36000, 36400, 36800, 37300, 37800, 38200, 38600,
- 39000,
- 39400, 39800, 40200, 40600, 41100, 41600, 42000, 42400, 42800, 43200,
- 43600,
- 44000, 44400, 44800, 45300, 45800, 46200, 46600, 47000, 47400, 47800,
- 48200,
- 48600, 49000, 49500, 50000, 50400, 50800, 51200, 51600, 52000, 52400,
- 52800,
- 53200, 53700, 54200, 54600, 55000, 55400, 55800, 56200, 56600, 57000,
- 57400,
- 57800, 58200, 58700, 59200, 59600, 60000, 60400, 60800, 61200, 61600,
- 62000,
- 62400, 62800, 63300, 63800, 64200, 64600, 65000, 65400, 65800, 66200,
- 66600,
- 67000, 67400, 67800, 68200, 68700, 69200, 69600, 70000, 70400, 70800,
- 71200,
- 71600, 72000, 72400, 72800, 73200, 73600, 74100, 74600, 75000, 75400,
- 75800,
- 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000, 79400, 79800,
- 80300,
- 80800, 81200, 81600, 82000, 82400, 82800, 83200, 83600, 84000, 84400,
- 84800,
- 85200, 85600, 86000, 86400, 86800, 87300, 87800, 88200, 88600, 89000,
- 89400,
- 89800, 90200, 90600, 91000, 91400, 91800, 92200, 92600, 93000, 93400,
- 93800,
- 94200, 94600, 95000, 95500, 96000, 96400, 96800, 97200, 97600, 98000,
- 98400,
- 98800, 99200, 99600, 100000, 100400, 100800, 101200, 101600, 102000,
- 102400,
- 102800, 103200, 103600, 104000, 104400, 104800, 105200, 105600, 106100,
- 106600, 107000, 107400, 107800, 108200, 108600, 109000, 109400, 109800,
- 110200, 110600, 111000, 111400, 111800, 112200, 112600, 113000, 113400,
- 113800, 114200, 114600, 115000, 115400, 115800, 116200, 116600, 117000,
- 117400, 117800, 118200, 118600, 119000, 119400, 119800, 120200, 120600,
- 121000, 121400, 121800, 122200, 122600, 123000, 123400, 123800, 124200,
- 124600, 124900, 125000, 125000, 125000, 125000,
-};
-
-const struct omap_bandgap_data omap5430_data = {
- .features = OMAP_BANDGAP_FEATURE_TSHUT_CONFIG |
- OMAP_BANDGAP_FEATURE_TALERT |
- OMAP_BANDGAP_FEATURE_MODE_CONFIG |
- OMAP_BANDGAP_FEATURE_COUNTER,
- .fclock_name = "ts_clk_div_ck",
- .div_ck_name = "ts_clk_div_ck",
- .conv_table = omap5430_adc_to_temp,
- .expose_sensor = omap_thermal_expose_sensor,
- .remove_sensor = omap_thermal_remove_sensor,
- .sensors = {
- {
- .registers = &omap5430_mpu_temp_sensor_registers,
- .ts_data = &omap5430_mpu_temp_sensor_data,
- .domain = "cpu",
- .register_cooling = omap_thermal_register_cpu_cooling,
- .unregister_cooling = omap_thermal_unregister_cpu_cooling,
- .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
- .constant = OMAP_GRADIENT_CONST_5430_CPU,
- .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
- .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
- },
- {
- .registers = &omap5430_gpu_temp_sensor_registers,
- .ts_data = &omap5430_gpu_temp_sensor_data,
- .domain = "gpu",
- .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
- .constant = OMAP_GRADIENT_CONST_5430_GPU,
- .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
- .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
- },
- {
- .registers = &omap5430_core_temp_sensor_registers,
- .ts_data = &omap5430_core_temp_sensor_data,
- .domain = "core",
- },
- },
- .sensor_count = 3,
-};
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index ba15aeb70672..27d06666c81a 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -253,6 +253,7 @@ static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
case OZ_IOCTL_GET_PD_LIST: {
struct oz_pd_list list;
oz_trace("OZ_IOCTL_GET_PD_LIST\n");
+ memset(&list, 0, sizeof(list));
list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
if (copy_to_user((void __user *)arg, &list,
sizeof(list)))
diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h
index ffb083c958ad..ae550520311b 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.h
+++ b/drivers/staging/rtl8192u/r8192U_dm.h
@@ -48,16 +48,16 @@
#define VeryLowRSSI 15
#define CTSToSelfTHVal 30
-//defined by vivi, for tx power track
+/* defined by vivi, for tx power track */
#define E_FOR_TX_POWER_TRACK 300
-//Dynamic Tx Power Control Threshold
+/* Dynamic Tx Power Control Threshold */
#define TX_POWER_NEAR_FIELD_THRESH_HIGH 68
#define TX_POWER_NEAR_FIELD_THRESH_LOW 62
-//added by amy for atheros AP
+/* added by amy for atheros AP */
#define TX_POWER_ATHEROAP_THRESH_HIGH 78
#define TX_POWER_ATHEROAP_THRESH_LOW 72
-//defined by vivi, for showing on UI
+/* defined by vivi, for showing on UI */
#define Current_Tx_Rate_Reg 0x1b8
#define Initial_Tx_Rate_Reg 0x1b9
#define Tx_Retry_Count_Reg 0x1ac
@@ -98,28 +98,25 @@ typedef struct _dynamic_initial_gain_threshold_ {
bool initialgain_lowerbound_state;
long rssi_val;
-}dig_t;
+} dig_t;
-typedef enum tag_dynamic_init_gain_state_definition
-{
+typedef enum tag_dynamic_init_gain_state_definition {
DM_STA_DIG_OFF = 0,
DM_STA_DIG_ON,
DM_STA_DIG_MAX
-}dm_dig_sta_e;
+} dm_dig_sta_e;
/* 2007/10/08 MH Define RATR state. */
-typedef enum tag_dynamic_ratr_state_definition
-{
+typedef enum tag_dynamic_ratr_state_definition {
DM_RATR_STA_HIGH = 0,
DM_RATR_STA_MIDDLE = 1,
DM_RATR_STA_LOW = 2,
DM_RATR_STA_MAX
-}dm_ratr_sta_e;
+} dm_ratr_sta_e;
/* 2007/10/11 MH Define DIG operation type. */
-typedef enum tag_dynamic_init_gain_operation_type_definition
-{
+typedef enum tag_dynamic_init_gain_operation_type_definition {
DIG_TYPE_THRESH_HIGH = 0,
DIG_TYPE_THRESH_LOW = 1,
DIG_TYPE_THRESH_HIGHPWR_HIGH = 2,
@@ -134,43 +131,38 @@ typedef enum tag_dynamic_init_gain_operation_type_definition
DIG_TYPE_ENABLE = 20,
DIG_TYPE_DISABLE = 30,
DIG_OP_TYPE_MAX
-}dm_dig_op_e;
+} dm_dig_op_e;
-typedef enum tag_dig_algorithm_definition
-{
+typedef enum tag_dig_algorithm_definition {
DIG_ALGO_BY_FALSE_ALARM = 0,
DIG_ALGO_BY_RSSI = 1,
DIG_ALGO_MAX
-}dm_dig_alg_e;
+} dm_dig_alg_e;
-typedef enum tag_dig_dbgmode_definition
-{
+typedef enum tag_dig_dbgmode_definition {
DIG_DBG_OFF = 0,
DIG_DBG_ON = 1,
DIG_DBG_MAX
-}dm_dig_dbg_e;
+} dm_dig_dbg_e;
-typedef enum tag_dig_connect_definition
-{
+typedef enum tag_dig_connect_definition {
DIG_DISCONNECT = 0,
DIG_CONNECT = 1,
DIG_CONNECT_MAX
-}dm_dig_connect_e;
+} dm_dig_connect_e;
-typedef enum tag_dig_packetdetection_threshold_definition
-{
+typedef enum tag_dig_packetdetection_threshold_definition {
DIG_PD_AT_LOW_POWER = 0,
DIG_PD_AT_NORMAL_POWER = 1,
DIG_PD_AT_HIGH_POWER = 2,
DIG_PD_MAX
-}dm_dig_pd_th_e;
+} dm_dig_pd_th_e;
-typedef enum tag_dig_cck_cs_ratio_state_definition
-{
+typedef enum tag_dig_cck_cs_ratio_state_definition {
DIG_CS_RATIO_LOWER = 0,
DIG_CS_RATIO_HIGHER = 1,
DIG_CS_MAX
-}dm_dig_cs_ratio_e;
+} dm_dig_cs_ratio_e;
typedef struct _Dynamic_Rx_Path_Selection_ {
u8 Enable;
u8 DbgMode;
@@ -185,27 +177,25 @@ typedef struct _Dynamic_Rx_Path_Selection_ {
u8 rf_rssi[4];
u8 rf_enable_rssi_th[4];
long cck_pwdb_sta[4];
-}DRxPathSel;
+} DRxPathSel;
-typedef enum tag_CCK_Rx_Path_Method_Definition
-{
+typedef enum tag_CCK_Rx_Path_Method_Definition {
CCK_Rx_Version_1 = 0,
- CCK_Rx_Version_2= 1,
+ CCK_Rx_Version_2 = 1,
CCK_Rx_Version_MAX
-}DM_CCK_Rx_Path_Method;
+} DM_CCK_Rx_Path_Method;
-typedef enum tag_DM_DbgMode_Definition
-{
+typedef enum tag_DM_DbgMode_Definition {
DM_DBG_OFF = 0,
DM_DBG_ON = 1,
DM_DBG_MAX
-}DM_DBG_E;
+} DM_DBG_E;
typedef struct tag_Tx_Config_Cmd_Format {
- u32 Op; /* Command packet type. */
- u32 Length; /* Command packet length. */
+ u32 Op; /* Command packet type. */
+ u32 Length; /* Command packet length. */
u32 Value;
-}DCMD_TXCMD_T, *PDCMD_TXCMD_T;
+} DCMD_TXCMD_T, *PDCMD_TXCMD_T;
/*------------------------------Define structure----------------------------*/
@@ -232,13 +222,14 @@ extern void dm_txpower_trackingcallback(struct work_struct *work);
extern void dm_restore_dynamic_mechanism_state(struct net_device *dev);
extern void dm_backup_dynamic_mechanism_state(struct net_device *dev);
extern void dm_change_dynamic_initgain_thresh(struct net_device *dev,
- u32 dm_type, u32 dm_value);
-extern void dm_force_tx_fw_info(struct net_device *dev,u32 force_type, u32 force_value);
+ u32 dm_type, u32 dm_value);
+extern void dm_force_tx_fw_info(struct net_device *dev,
+ u32 force_type, u32 force_value);
extern void dm_init_edca_turbo(struct net_device *dev);
extern void dm_rf_operation_test_callback(unsigned long data);
extern void dm_rf_pathcheck_workitemcallback(struct work_struct *work);
extern void dm_fsync_timer_callback(unsigned long data);
-extern void dm_cck_txpower_adjust(struct net_device *dev,bool binch14);
+extern void dm_cck_txpower_adjust(struct net_device *dev, bool binch14);
extern void dm_shadow_init(struct net_device *dev);
extern void dm_initialize_txpower_tracking(struct net_device *dev);
/*--------------------------Exported Function prototype---------------------*/
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index c9eb4b74799b..6cb1a0af5177 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -267,12 +267,8 @@ static void SwLedBlink(struct LED_871x *pLed)
LED_BLINK_SLOWLY_INTERVAL);
break;
case LED_BLINK_WPS:
- if (pLed->BlinkingLedState == LED_ON)
- _set_timer(&(pLed->BlinkTimer),
- LED_BLINK_LONG_INTERVAL);
- else
- _set_timer(&(pLed->BlinkTimer),
- LED_BLINK_LONG_INTERVAL);
+ _set_timer(&(pLed->BlinkTimer),
+ LED_BLINK_LONG_INTERVAL);
break;
default:
_set_timer(&(pLed->BlinkTimer),
diff --git a/drivers/staging/rtl8712/rtl871x_recv.h b/drivers/staging/rtl8712/rtl871x_recv.h
index e42e6f0a15e6..92ca8997e5bc 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.h
+++ b/drivers/staging/rtl8712/rtl871x_recv.h
@@ -9,9 +9,6 @@
#define RXFRAME_ALIGN 8
#define RXFRAME_ALIGN_SZ (1 << RXFRAME_ALIGN)
-#define MAX_RXFRAME_CNT 512
-#define MAX_RX_NUMBLKS (32)
-#define RECVFRAME_HDR_ALIGN 128
#define MAX_SUBFRAME_COUNT 64
#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
@@ -130,15 +127,10 @@ struct sta_recv_priv {
/* get a free recv_frame from pfree_recv_queue */
union recv_frame *r8712_alloc_recvframe(struct __queue *pfree_recv_queue);
-union recv_frame *r8712_dequeue_recvframe(struct __queue *queue);
-int r8712_enqueue_recvframe(union recv_frame *precvframe,
- struct __queue *queue);
int r8712_free_recvframe(union recv_frame *precvframe,
struct __queue *pfree_recv_queue);
void r8712_free_recvframe_queue(struct __queue *pframequeue,
struct __queue *pfree_recv_queue);
-void r8712_init_recvframe(union recv_frame *precvframe,
- struct recv_priv *precvpriv);
int r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe);
int recv_func(struct _adapter *padapter, void *pcontext);
@@ -150,11 +142,6 @@ static inline u8 *get_rxmem(union recv_frame *precvframe)
return precvframe->u.hdr.rx_head;
}
-static inline u8 *get_rx_status(union recv_frame *precvframe)
-{
- return get_rxmem(precvframe);
-}
-
static inline u8 *get_recvframe_data(union recv_frame *precvframe)
{
/* always return rx_data */
@@ -163,28 +150,6 @@ static inline u8 *get_recvframe_data(union recv_frame *precvframe)
return precvframe->u.hdr.rx_data;
}
-static inline u8 *recvframe_push(union recv_frame *precvframe, sint sz)
-{
- /* append data before rx_data */
-
- /* add data to the start of recv_frame
- *
- * This function extends the used data area of the recv_frame at the
- * buffer start. rx_data must be still larger than rx_head, after
- * pushing.
- */
-
- if (precvframe == NULL)
- return NULL;
- precvframe->u.hdr.rx_data -= sz ;
- if (precvframe->u.hdr.rx_data < precvframe->u.hdr.rx_head) {
- precvframe->u.hdr.rx_data += sz ;
- return NULL;
- }
- precvframe->u.hdr.len += sz;
- return precvframe->u.hdr.rx_data;
-}
-
static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz)
{
/* used for extract sz bytes from rx_data, update rx_data and return
@@ -236,53 +201,6 @@ static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz)
return precvframe->u.hdr.rx_tail;
}
-static inline _buffer *get_rxbuf_desc(union recv_frame *precvframe)
-{
- _buffer *buf_desc;
- if (precvframe == NULL)
- return NULL;
- return buf_desc;
-}
-
-static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem)
-{
- /* due to the design of 2048 bytes alignment of recv_frame, we can
- * reference the union recv_frame from any given member of recv_frame.
- * rxmem indicates the any member/address in recv_frame */
- return (union recv_frame *)(((addr_t)rxmem >> RXFRAME_ALIGN) <<
- RXFRAME_ALIGN);
-}
-
-static inline union recv_frame *pkt_to_recvframe(_pkt *pkt)
-{
- u8 *buf_star;
- union recv_frame *precv_frame;
-
- precv_frame = rxmem_to_recvframe((unsigned char *)buf_star);
- return precv_frame;
-}
-
-static inline u8 *pkt_to_recvmem(_pkt *pkt)
-{
- /* return the rx_head */
- union recv_frame *precv_frame = pkt_to_recvframe(pkt);
-
- return precv_frame->u.hdr.rx_head;
-}
-
-static inline u8 *pkt_to_recvdata(_pkt *pkt)
-{
- /* return the rx_data */
- union recv_frame *precv_frame = pkt_to_recvframe(pkt);
-
- return precv_frame->u.hdr.rx_data;
-}
-
-static inline sint get_recvframe_len(union recv_frame *precvframe)
-{
- return precvframe->u.hdr.len;
-}
-
struct sta_info;
void _r8712_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv);
@@ -292,36 +210,10 @@ union recv_frame *r8712_decryptor(struct _adapter *adapter,
union recv_frame *precv_frame);
union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *adapter,
union recv_frame *precv_frame);
-union recv_frame *r8712_recvframe_defrag(struct _adapter *adapter,
- struct __queue *defrag_q);
-union recv_frame *r8712_recvframe_chk_defrag_new(struct _adapter *adapter,
- union recv_frame *precv_frame);
-union recv_frame *r8712_recvframe_defrag_new(struct _adapter *adapter,
- struct __queue *defrag_q,
- union recv_frame *precv_frame);
-int r8712_recv_decache(union recv_frame *precv_frame, u8 bretry,
- struct stainfo_rxcache *prxcache);
-int r8712_sta2sta_data_frame(struct _adapter *adapter,
- union recv_frame *precv_frame,
- struct sta_info **psta);
-int r8712_ap2sta_data_frame(struct _adapter *adapter,
- union recv_frame *precv_frame,
- struct sta_info **psta);
-int r8712_sta2ap_data_frame(struct _adapter *adapter,
- union recv_frame *precv_frame,
- struct sta_info **psta);
-int r8712_validate_recv_ctrl_frame(struct _adapter *adapter,
- union recv_frame *precv_frame);
-int r8712_validate_recv_mgnt_frame(struct _adapter *adapter,
- union recv_frame *precv_frame);
-int r8712_validate_recv_data_frame(struct _adapter *adapter,
- union recv_frame *precv_frame);
int r8712_validate_recv_frame(struct _adapter *adapter,
union recv_frame *precv_frame);
union recv_frame *r8712_portctrl(struct _adapter *adapter,
union recv_frame *precv_frame);
-void r8712_mgt_dispatcher(struct _adapter *padapter, u8 *pframe, uint len);
-int r8712_amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe);
#endif
diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c
index 2ac3fe647ee6..610870546406 100644
--- a/drivers/staging/rts5139/rts51x_scsi.c
+++ b/drivers/staging/rts5139/rts51x_scsi.c
@@ -2059,7 +2059,7 @@ int command_abort(struct scsi_cmnd *srb)
/* This invokes the transport reset mechanism to reset the state of the
* device */
-int device_reset(struct scsi_cmnd *srb)
+static int device_reset(struct scsi_cmnd *srb)
{
int result = 0;
diff --git a/drivers/staging/rts5139/rts51x_scsi.h b/drivers/staging/rts5139/rts51x_scsi.h
index c2446d02d328..1a0d70566186 100644
--- a/drivers/staging/rts5139/rts51x_scsi.h
+++ b/drivers/staging/rts5139/rts51x_scsi.h
@@ -149,7 +149,6 @@ int slave_alloc(struct scsi_device *sdev);
int slave_configure(struct scsi_device *sdev);
int queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
int command_abort(struct scsi_cmnd *srb);
-int device_reset(struct scsi_cmnd *srb);
int bus_reset(struct scsi_cmnd *srb);
#endif /* __RTS51X_SCSI_H */
diff --git a/drivers/staging/rts5139/trace.h b/drivers/staging/rts5139/trace.h
index c9dfb1ea4115..ac58b452ecb8 100644
--- a/drivers/staging/rts5139/trace.h
+++ b/drivers/staging/rts5139/trace.h
@@ -27,32 +27,16 @@
#ifndef __RTS51X_TRACE_H
#define __RTS51X_TRACE_H
+#include <linux/string.h>
+
#include "debug.h"
#define _MSG_TRACE
#ifdef _MSG_TRACE
-static inline char *filename(char *path)
-{
- char *ptr;
-
- if (path == NULL)
- return NULL;
-
- ptr = path;
-
- while (*ptr != '\0') {
- if ((*ptr == '\\') || (*ptr == '/'))
- path = ptr + 1;
- ptr++;
- }
-
- return path;
-}
-
#define TRACE_RET(chip, ret) \
do { \
- char *_file = filename((char *)__FILE__); \
+ const char *_file = kbasename(__FILE__); \
RTS51X_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, \
@@ -71,7 +55,7 @@ do { \
#define TRACE_GOTO(chip, label) \
do { \
- char *_file = filename((char *)__FILE__); \
+ const char *_file = kbasename(__FILE__); \
RTS51X_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, \
diff --git a/drivers/staging/sb105x/sb_mp_register.h b/drivers/staging/sb105x/sb_mp_register.h
index a2087f5b0d1a..304e1bcd1e3b 100644
--- a/drivers/staging/sb105x/sb_mp_register.h
+++ b/drivers/staging/sb105x/sb_mp_register.h
@@ -19,7 +19,7 @@
* option register
*/
-/* Device Infomation Register */
+/* Device Information Register */
#define MP_OPTR_DIR0 0x04 /* port0 ~ port8 */
#define MP_OPTR_DIR1 0x05 /* port8 ~ port15 */
#define MP_OPTR_DIR2 0x06 /* port16 ~ port23 */
@@ -47,7 +47,7 @@
#define IIR_RS485 0x20 /* RS485 type */
#define IIR_TYPE_MASK 0x30
-/* Interrrupt Mask Register */
+/* Interrupt Mask Register */
#define MP_OPTR_IMR0 0x0C /* port0 ~ port8 */
#define MP_OPTR_IMR1 0x0D /* port8 ~ port15 */
#define MP_OPTR_IMR2 0x0E /* port16 ~ port23 */
diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c
index f75ee1dd475c..cd94f6c27723 100644
--- a/drivers/staging/sb105x/sb_pci_mp.c
+++ b/drivers/staging/sb105x/sb_pci_mp.c
@@ -2248,7 +2248,7 @@ static irqreturn_t multi_interrupt(int irq, void *dev_id)
mtpt = list_entry(lhead, struct mp_port, list);
iir = serial_in(mtpt, UART_IIR);
- printk("intrrupt! port %d, iir 0x%x\n", mtpt->port.line, iir); //wlee
+ printk("interrupt! port %d, iir 0x%x\n", mtpt->port.line, iir); //wlee
if (!(iir & UART_IIR_NO_INT))
{
printk("interrupt handle\n");
@@ -2830,7 +2830,7 @@ static void __init multi_init_ports(void)
mtpt->port.uartclk = BASE_BAUD * 16;
- /* get input clock infomation */
+ /* get input clock information */
osc = inb(sbdev->option_reg_addr + MP_OPTR_DIR0 + i/8) & 0x0F;
if (osc==0x0f)
osc = 0;
diff --git a/drivers/staging/sb105x/sb_pci_mp.h b/drivers/staging/sb105x/sb_pci_mp.h
index f33efde07b97..a15f470a1728 100644
--- a/drivers/staging/sb105x/sb_pci_mp.h
+++ b/drivers/staging/sb105x/sb_pci_mp.h
@@ -174,7 +174,7 @@ static DEFINE_MUTEX(mp_mutex);
#define DEBUG_INTR(fmt...) do { } while (0)
#endif
-#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+#if defined(__i386__) && defined(CONFIG_M486)
#define SERIAL_INLINE
#endif
#ifdef SERIAL_INLINE
diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c
index cd3bb39e4255..490a31e0fd43 100644
--- a/drivers/staging/sep/sep_crypto.c
+++ b/drivers/staging/sep/sep_crypto.c
@@ -1206,7 +1206,7 @@ static int sep_crypto_block_data(struct ablkcipher_request *req)
if (copy_result != crypto_ablkcipher_blocksize(tfm)) {
dev_warn(&ta_ctx->sep_used->pdev->dev,
- "des block copy faild\n");
+ "des block copy failed\n");
return -ENOMEM;
}
@@ -1637,7 +1637,7 @@ static u32 crypto_post_op(struct sep_device *sep)
crypto_ablkcipher_blocksize(tfm)) {
dev_warn(&ta_ctx->sep_used->pdev->dev,
- "des block copy faild\n");
+ "des block copy failed\n");
sep_crypto_release(sctx, ta_ctx,
-ENOMEM);
return -ENOMEM;
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index 7d7c7ab610b7..4b6e30743634 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -219,7 +219,7 @@ held by the process (struct file) */
/* maximum number of entries in the caller id table */
#define SEP_CALLER_ID_TABLE_NUM_ENTRIES 20
-/* maximum number of symetric operation (that require DMA resource)
+/* maximum number of symmetric operation (that require DMA resource)
per one message */
#define SEP_MAX_NUM_SYNC_DMA_OPS 16
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index 30e8d25113e4..6a98a208bbf2 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -1986,7 +1986,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep,
dma_ctx,
sep_lli_entries);
if (error)
- return error;
+ goto end_function_error;
lli_table_alloc_addr = *dmatables_region;
}
@@ -2276,7 +2276,7 @@ static int sep_construct_dma_tables_from_lli(
table_data_size);
/* If info entry is null - this is the first table built */
- if (info_in_entry_ptr == NULL) {
+ if (info_in_entry_ptr == NULL || info_out_entry_ptr == NULL) {
/* Set the output parameters to physical addresses */
*lli_table_in_ptr =
sep_shared_area_virt_to_bus(sep, dma_in_lli_table_ptr);
@@ -2880,6 +2880,8 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
dev_dbg(&sep->pdev->dev, "[PID%d] sep_free_dma_tables_and_dcb\n",
current->pid);
+ if (!dma_ctx || !*dma_ctx) /* nothing to be done here*/
+ return 0;
if (((*dma_ctx)->secure_dma == false) && (isapplet == true)) {
dev_dbg(&sep->pdev->dev, "[PID%d] handling applet\n",
@@ -2895,8 +2897,7 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet,
* Go over each DCB and see if
* tail pointer must be updated
*/
- for (i = 0; dma_ctx && *dma_ctx &&
- i < (*dma_ctx)->nr_dcb_creat; i++, dcb_table_ptr++) {
+ for (i = 0; i < (*dma_ctx)->nr_dcb_creat; i++, dcb_table_ptr++) {
if (dcb_table_ptr->out_vr_tail_pt) {
pt_hold = (unsigned long)dcb_table_ptr->
out_vr_tail_pt;
diff --git a/drivers/staging/sep/sep_trace_events.h b/drivers/staging/sep/sep_trace_events.h
index 2b053a93afe6..74f4c9a2b5be 100644
--- a/drivers/staging/sep/sep_trace_events.h
+++ b/drivers/staging/sep/sep_trace_events.h
@@ -53,6 +53,11 @@
#include <linux/tracepoint.h>
/*
+ * Since use str*cpy in header file, better to include string.h, directly.
+ */
+#include <linux/string.h>
+
+/*
* The TRACE_EVENT macro is broken up into 5 parts.
*
* name: name of the trace point. This is also how to enable the tracepoint.
@@ -97,7 +102,7 @@ TRACE_EVENT(sep_func_start,
),
TP_fast_assign(
- strncpy(__entry->name, name, 20);
+ strlcpy(__entry->name, name, 20);
__entry->branch = branch;
),
@@ -116,7 +121,7 @@ TRACE_EVENT(sep_func_end,
),
TP_fast_assign(
- strncpy(__entry->name, name, 20);
+ strlcpy(__entry->name, name, 20);
__entry->branch = branch;
),
@@ -135,7 +140,7 @@ TRACE_EVENT(sep_misc_event,
),
TP_fast_assign(
- strncpy(__entry->name, name, 20);
+ strlcpy(__entry->name, name, 20);
__entry->branch = branch;
),
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index b1bb1a6abe81..8a6e5ea476e1 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -264,7 +264,6 @@ static void ProcessRxChar(struct usb_serial_port *port, unsigned char data)
static void qt_write_bulk_callback(struct urb *urb)
{
- struct tty_struct *tty;
int status;
struct quatech_port *quatech_port;
@@ -278,11 +277,7 @@ static void qt_write_bulk_callback(struct urb *urb)
quatech_port = urb->context;
- tty = tty_port_tty_get(&quatech_port->port->port);
-
- if (tty)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ tty_port_tty_wakeup(&quatech_port->port->port);
}
static void qt_interrupt_callback(struct urb *urb)
diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c
index 3117559c041b..b7e570ccb759 100644
--- a/drivers/staging/silicom/bpctl_mod.c
+++ b/drivers/staging/silicom/bpctl_mod.c
@@ -6845,7 +6845,7 @@ static void __exit bypass_cleanup_module(void)
/* spin_lock_irqsave(&bpvm_lock, flags);
rcu_read_lock(); */
bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]);
-/* spin_unlock_irqrestore(&bpvm_lock, flags);
+/* spin_unlock_irqrestore(&bpvm_lock, flags);
rcu_read_unlock(); */
#endif
remove_bypass_wd_auto(&bpctl_dev_arr[i]);
@@ -6857,18 +6857,16 @@ static void __exit bypass_cleanup_module(void)
/* unmap all devices */
for (i = 0; i < device_num; i++) {
#ifdef BP_SELF_TEST
- if (bpctl_dev_arr[i].bp_tx_data)
- kfree(bpctl_dev_arr[i].bp_tx_data);
+ kfree(bpctl_dev_arr[i].bp_tx_data);
#endif
iounmap((void *)(bpctl_dev_arr[i].mem_map));
}
/* free all devices space */
- if (bpctl_dev_arr)
- kfree(bpctl_dev_arr);
+ kfree(bpctl_dev_arr);
/*
-* Unregister the device
+* Unregister the device
*/
unregister_chrdev(major_num, DEVICE_NAME);
}
diff --git a/drivers/staging/silicom/bypasslib/bypass.c b/drivers/staging/silicom/bypasslib/bypass.c
index 95a1f1815d90..9ed250848e81 100644
--- a/drivers/staging/silicom/bypasslib/bypass.c
+++ b/drivers/staging/silicom/bypasslib/bypass.c
@@ -134,7 +134,7 @@ static int is_dev_sd(int if_index)
return (ret >= 0 ? 1 : 0);
}
-int is_bypass_dev(int if_index)
+static int is_bypass_dev(int if_index)
{
struct pci_dev *pdev = NULL;
struct net_device *dev = NULL;
@@ -179,7 +179,7 @@ int is_bypass_dev(int if_index)
return (ret < 0 ? -1 : ret);
}
-int is_bypass(int if_index)
+static int is_bypass(int if_index)
{
int ret = 0;
SET_BPLIB_INT_FN(is_bypass, int, if_index, ret);
@@ -189,70 +189,70 @@ int is_bypass(int if_index)
return ret;
}
-int get_bypass_slave(int if_index)
+static int get_bypass_slave(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index);
}
-int get_bypass_caps(int if_index)
+static int get_bypass_caps(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index);
}
-int get_wd_set_caps(int if_index)
+static int get_wd_set_caps(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index);
}
-int set_bypass(int if_index, int bypass_mode)
+static int set_bypass(int if_index, int bypass_mode)
{
DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode);
}
-int get_bypass(int if_index)
+static int get_bypass(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index);
}
-int get_bypass_change(int if_index)
+static int get_bypass_change(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index);
}
-int set_dis_bypass(int if_index, int dis_bypass)
+static int set_dis_bypass(int if_index, int dis_bypass)
{
DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index,
dis_bypass);
}
-int get_dis_bypass(int if_index)
+static int get_dis_bypass(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index);
}
-int set_bypass_pwoff(int if_index, int bypass_mode)
+static int set_bypass_pwoff(int if_index, int bypass_mode)
{
DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index,
bypass_mode);
}
-int get_bypass_pwoff(int if_index)
+static int get_bypass_pwoff(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index);
}
-int set_bypass_pwup(int if_index, int bypass_mode)
+static int set_bypass_pwup(int if_index, int bypass_mode)
{
DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index,
bypass_mode);
}
-int get_bypass_pwup(int if_index)
+static int get_bypass_pwup(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index);
}
-int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
+static int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
{
int data = ms_timeout, ret = 0;
if (is_dev_sd(if_index))
@@ -268,7 +268,7 @@ int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set)
return ret;
}
-int get_bypass_wd(int if_index, int *ms_timeout_set)
+static int get_bypass_wd(int if_index, int *ms_timeout_set)
{
int *data = ms_timeout_set, ret = 0;
if (is_dev_sd(if_index))
@@ -279,7 +279,7 @@ int get_bypass_wd(int if_index, int *ms_timeout_set)
return ret;
}
-int get_wd_expire_time(int if_index, int *ms_time_left)
+static int get_wd_expire_time(int if_index, int *ms_time_left)
{
int *data = ms_time_left, ret = 0;
if (is_dev_sd(if_index))
@@ -293,144 +293,144 @@ int get_wd_expire_time(int if_index, int *ms_time_left)
return ret;
}
-int reset_bypass_wd_timer(int if_index)
+static int reset_bypass_wd_timer(int if_index)
{
DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER,
if_index);
}
-int set_std_nic(int if_index, int bypass_mode)
+static int set_std_nic(int if_index, int bypass_mode)
{
DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode);
}
-int get_std_nic(int if_index)
+static int get_std_nic(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index);
}
-int set_tx(int if_index, int tx_state)
+static int set_tx(int if_index, int tx_state)
{
DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state);
}
-int get_tx(int if_index)
+static int get_tx(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index);
}
-int set_tap(int if_index, int tap_mode)
+static int set_tap(int if_index, int tap_mode)
{
DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode);
}
-int get_tap(int if_index)
+static int get_tap(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index);
}
-int get_tap_change(int if_index)
+static int get_tap_change(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index);
}
-int set_dis_tap(int if_index, int dis_tap)
+static int set_dis_tap(int if_index, int dis_tap)
{
DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap);
}
-int get_dis_tap(int if_index)
+static int get_dis_tap(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index);
}
-int set_tap_pwup(int if_index, int tap_mode)
+static int set_tap_pwup(int if_index, int tap_mode)
{
DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode);
}
-int get_tap_pwup(int if_index)
+static int get_tap_pwup(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index);
}
-int set_bp_disc(int if_index, int disc_mode)
+static int set_bp_disc(int if_index, int disc_mode)
{
DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode);
}
-int get_bp_disc(int if_index)
+static int get_bp_disc(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index);
}
-int get_bp_disc_change(int if_index)
+static int get_bp_disc_change(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index);
}
-int set_bp_dis_disc(int if_index, int dis_disc)
+static int set_bp_dis_disc(int if_index, int dis_disc)
{
DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc);
}
-int get_bp_dis_disc(int if_index)
+static int get_bp_dis_disc(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index);
}
-int set_bp_disc_pwup(int if_index, int disc_mode)
+static int set_bp_disc_pwup(int if_index, int disc_mode)
{
DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index,
disc_mode);
}
-int get_bp_disc_pwup(int if_index)
+static int get_bp_disc_pwup(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index);
}
-int set_wd_exp_mode(int if_index, int mode)
+static int set_wd_exp_mode(int if_index, int mode)
{
DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode);
}
-int get_wd_exp_mode(int if_index)
+static int get_wd_exp_mode(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index);
}
-int set_wd_autoreset(int if_index, int time)
+static int set_wd_autoreset(int if_index, int time)
{
DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time);
}
-int get_wd_autoreset(int if_index)
+static int get_wd_autoreset(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index);
}
-int set_tpl(int if_index, int tpl_mode)
+static int set_tpl(int if_index, int tpl_mode)
{
DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode);
}
-int get_tpl(int if_index)
+static int get_tpl(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index);
}
-int set_bp_hw_reset(int if_index, int mode)
+static int set_bp_hw_reset(int if_index, int mode)
{
DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode);
}
-int get_bp_hw_reset(int if_index)
+static int get_bp_hw_reset(int if_index)
{
DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index);
}
-int get_bypass_info(int if_index, struct bp_info *bp_info)
+static int get_bypass_info(int if_index, struct bp_info *bp_info)
{
int ret = 0;
if (is_dev_sd(if_index)) {
@@ -468,14 +468,14 @@ int get_bypass_info(int if_index, struct bp_info *bp_info)
return ret;
}
-int init_lib_module()
+int init_lib_module(void)
{
printk(VERSION);
return 0;
}
-void cleanup_lib_module()
+void cleanup_lib_module(void)
{
}
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index 76fc2e554f35..e4b82770ed39 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -76,6 +76,7 @@
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/netdevice.h>
+#include <linux/crc32.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
@@ -189,76 +190,14 @@ static inline void slic_reg64_write(struct adapter *adapter, void __iomem *reg,
adapter->bit64reglock.flags);
}
-/*
- * Functions to obtain the CRC corresponding to the destination mac address.
- * This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using
- * the polynomial:
- * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 +
- * x^4 + x^2 + x^1.
- *
- * After the CRC for the 6 bytes is generated (but before the value is
- * complemented),
- * we must then transpose the value and return bits 30-23.
- *
- */
-static u32 slic_crc_table[256]; /* Table of CRCs for all possible byte values */
-static u32 slic_crc_init; /* Is table initialized */
-
-/*
- * Contruct the CRC32 table
- */
-static void slic_mcast_init_crc32(void)
-{
- u32 c; /* CRC reg */
- u32 e = 0; /* Poly X-or pattern */
- int i; /* counter */
- int k; /* byte being shifted into crc */
-
- static int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 };
-
- for (i = 0; i < ARRAY_SIZE(p); i++)
- e |= 1L << (31 - p[i]);
-
- for (i = 1; i < 256; i++) {
- c = i;
- for (k = 8; k; k--)
- c = c & 1 ? (c >> 1) ^ e : c >> 1;
- slic_crc_table[i] = c;
- }
-}
-
-/*
- * Return the MAC hast as described above.
- */
-static unsigned char slic_mcast_get_mac_hash(char *macaddr)
-{
- u32 crc;
- char *p;
- int i;
- unsigned char machash = 0;
-
- if (!slic_crc_init) {
- slic_mcast_init_crc32();
- slic_crc_init = 1;
- }
-
- crc = 0xFFFFFFFF; /* Preload shift register, per crc-32 spec */
- for (i = 0, p = macaddr; i < 6; ++p, ++i)
- crc = (crc >> 8) ^ slic_crc_table[(crc ^ *p) & 0xFF];
-
- /* Return bits 1-8, transposed */
- for (i = 1; i < 9; i++)
- machash |= (((crc >> i) & 1) << (8 - i));
-
- return machash;
-}
-
static void slic_mcast_set_bit(struct adapter *adapter, char *address)
{
unsigned char crcpoly;
/* Get the CRC polynomial for the mac address */
- crcpoly = slic_mcast_get_mac_hash(address);
+ /* we use bits 1-8 (lsb), bitwise reversed,
+ * msb (= lsb bit 0 before bitrev) is automatically discarded */
+ crcpoly = (ether_crc(ETH_ALEN, address)>>23);
/* We only have space on the SLIC for 64 entries. Lop
* off the top two bits. (2^6 = 64)
@@ -901,10 +840,9 @@ static void slic_timer_load_check(ulong cardaddr)
u32 load = card->events;
u32 level = 0;
- intagg = &adapter->slic_regs->slic_intagg;
-
if ((adapter) && (adapter->state == ADAPT_UP) &&
(card->state == CARD_UP) && (slic_global.dynamic_intagg)) {
+ intagg = &adapter->slic_regs->slic_intagg;
if (adapter->devid == SLIC_1GB_DEVICE_ID) {
if (adapter->linkspeed == LINK_1000MB)
level = 100;
@@ -1061,7 +999,8 @@ static void slic_link_upr_complete(struct adapter *adapter, u32 isr)
if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
struct slic_shmem *pshmem;
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)(unsigned long)
+ adapter->phys_shmem;
#if BITS_PER_LONG == 64
slic_upr_queue_request(adapter,
SLIC_UPR_RLSR,
@@ -1415,7 +1354,7 @@ static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter)
slic_reg64_write(adapter, &adapter->slic_regs->slic_rbar64,
(rspq->paddr[rspq->pageindex] | SLIC_RSPQ_BUFSINPAGE),
&adapter->slic_regs->slic_addr_upper, 0, DONT_FLUSH);
- rspq->pageindex = (++rspq->pageindex) % rspq->num_pages;
+ rspq->pageindex = (rspq->pageindex + 1) % rspq->num_pages;
rspq->offset = 0;
rspq->rspbuf = (struct slic_rspbuf *)
rspq->vaddr[rspq->pageindex];
@@ -1693,10 +1632,11 @@ retry_rcvqfill:
#endif
skb = alloc_skb(SLIC_RCVQ_RCVBUFSIZE, GFP_ATOMIC);
if (skb) {
- paddr = (void *)pci_map_single(adapter->pcidev,
- skb->data,
- SLIC_RCVQ_RCVBUFSIZE,
- PCI_DMA_FROMDEVICE);
+ paddr = (void *)(unsigned long)
+ pci_map_single(adapter->pcidev,
+ skb->data,
+ SLIC_RCVQ_RCVBUFSIZE,
+ PCI_DMA_FROMDEVICE);
paddrl = SLIC_GET_ADDR_LOW(paddr);
paddrh = SLIC_GET_ADDR_HIGH(paddr);
@@ -1843,8 +1783,9 @@ static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb)
struct slic_rcvbuf *rcvbuf = (struct slic_rcvbuf *)skb->head;
struct device *dev;
- paddr = (void *)pci_map_single(adapter->pcidev, skb->head,
- SLIC_RCVQ_RCVBUFSIZE, PCI_DMA_FROMDEVICE);
+ paddr = (void *)(unsigned long)
+ pci_map_single(adapter->pcidev, skb->head,
+ SLIC_RCVQ_RCVBUFSIZE, PCI_DMA_FROMDEVICE);
rcvbuf->status = 0;
skb->next = NULL;
@@ -2341,7 +2282,7 @@ static void slic_link_event_handler(struct adapter *adapter)
return;
}
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)(unsigned long)adapter->phys_shmem;
#if BITS_PER_LONG == 64
status = slic_upr_request(adapter,
@@ -2368,7 +2309,7 @@ static void slic_init_cleanup(struct adapter *adapter)
sizeof(struct slic_shmem),
adapter->pshmem, adapter->phys_shmem);
adapter->pshmem = NULL;
- adapter->phys_shmem = (dma_addr_t) NULL;
+ adapter->phys_shmem = (dma_addr_t)(unsigned long)NULL;
}
if (adapter->pingtimerset) {
@@ -2787,7 +2728,6 @@ static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
struct adapter *adapter = netdev_priv(dev);
struct slic_hostcmd *hcmd = NULL;
u32 status = 0;
- u32 skbtype = NORMAL_ETHFRAME;
void *offloadcmd = NULL;
card = adapter->card;
@@ -2801,19 +2741,16 @@ static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
goto xmit_fail;
}
- if (skbtype == NORMAL_ETHFRAME) {
- hcmd = slic_cmdq_getfree(adapter);
- if (!hcmd) {
- adapter->xmitq_full = 1;
- status = XMIT_FAIL_HOSTCMD_FAIL;
- goto xmit_fail;
- }
- hcmd->skb = skb;
- hcmd->busy = 1;
- hcmd->type = SLIC_CMD_DUMB;
- if (skbtype == NORMAL_ETHFRAME)
- slic_xmit_build_request(adapter, hcmd, skb);
+ hcmd = slic_cmdq_getfree(adapter);
+ if (!hcmd) {
+ adapter->xmitq_full = 1;
+ status = XMIT_FAIL_HOSTCMD_FAIL;
+ goto xmit_fail;
}
+ hcmd->skb = skb;
+ hcmd->busy = 1;
+ hcmd->type = SLIC_CMD_DUMB;
+ slic_xmit_build_request(adapter, hcmd, skb);
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -2839,7 +2776,7 @@ static netdev_tx_t slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
xmit_done:
return NETDEV_TX_OK;
xmit_fail:
- slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
+ slic_xmit_fail(adapter, skb, offloadcmd, NORMAL_ETHFRAME, status);
goto xmit_done;
}
@@ -2946,7 +2883,8 @@ static int slic_if_init(struct adapter *adapter)
mdelay(1);
if (!adapter->isp_initialized) {
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)(unsigned long)
+ adapter->phys_shmem;
spin_lock_irqsave(&adapter->bit64reglock.lock,
adapter->bit64reglock.flags);
@@ -3211,6 +3149,7 @@ static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EFAULT;
if (ecmd.cmd == ETHTOOL_GSET) {
+ memset(&edata, 0, sizeof(edata));
edata.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -3348,7 +3287,8 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter)
}
slic_reg32_write(&slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
mdelay(1);
- pshmem = (struct slic_shmem *)adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)(unsigned long)
+ adapter->phys_shmem;
spin_lock_irqsave(&adapter->bit64reglock.lock,
adapter->bit64reglock.flags);
@@ -3648,11 +3588,12 @@ static u32 slic_card_locate(struct adapter *adapter)
while (physcard) {
for (i = 0; i < SLIC_MAX_PORTS; i++) {
- if (!physcard->adapter[i])
- continue;
- else
+ if (physcard->adapter[i])
break;
}
+ if (i == SLIC_MAX_PORTS)
+ break;
+
if (physcard->adapter[i]->slotnumber == adapter->slotnumber)
break;
physcard = physcard->next;
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
index 0764bbbfd497..8add64b1cb09 100644
--- a/drivers/staging/sm7xxfb/sm7xxfb.c
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -1006,15 +1006,7 @@ static int smtcfb_pci_resume(struct device *device)
return 0;
}
-static const struct dev_pm_ops sm7xx_pm_ops = {
- .suspend = smtcfb_pci_suspend,
- .resume = smtcfb_pci_resume,
- .freeze = smtcfb_pci_suspend,
- .thaw = smtcfb_pci_resume,
- .poweroff = smtcfb_pci_suspend,
- .restore = smtcfb_pci_resume,
-};
-
+static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
#define SM7XX_PM_OPS (&sm7xx_pm_ops)
#else /* !CONFIG_PM */
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
index 35f647ce1f1e..943b6c134a22 100644
--- a/drivers/staging/speakup/kobjects.c
+++ b/drivers/staging/speakup/kobjects.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
@@ -417,7 +418,7 @@ static ssize_t synth_direct_store(struct kobject *kobj,
bytes = min_t(size_t, len, 250);
strncpy(tmp, ptr, bytes);
tmp[bytes] = '\0';
- spk_xlate(tmp);
+ string_unescape_any_inplace(tmp);
synth_printf("%s", tmp);
ptr += bytes;
len -= bytes;
@@ -605,7 +606,8 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
if (param->data == NULL)
return 0;
ret = 0;
- cp = spk_xlate((char *) buf);
+ cp = (char *)buf;
+ string_unescape_any_inplace(cp);
spk_lock(flags);
switch (param->var_type) {
@@ -617,9 +619,9 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
len = E_INC;
else
len = E_SET;
- speakup_s2i(cp, &value);
+ value = simple_strtol(cp, NULL, 10);
ret = spk_set_num_var(value, param, len);
- if (ret == E_RANGE) {
+ if (ret == -ERANGE) {
var_data = param->data;
pr_warn("value for %s out of range, expect %d to %d\n",
attr->attr.name,
@@ -637,7 +639,7 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
cp = (char *) buf;
cp[len] = '\0';
ret = spk_set_string_var(buf, param, len);
- if (ret == E_TOOLONG)
+ if (ret == -E2BIG)
pr_warn("value too long for %s\n",
attr->attr.name);
break;
@@ -670,7 +672,7 @@ ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr,
}
spk_unlock(flags);
- if (ret == SET_DEFAULT)
+ if (ret == -ERESTART)
pr_info("%s reset to default value\n", attr->attr.name);
return count;
}
diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c
index 9916e94aa361..6c7b55c2947d 100644
--- a/drivers/staging/speakup/main.c
+++ b/drivers/staging/speakup/main.c
@@ -1892,7 +1892,7 @@ oops:
spk_special_handler = NULL;
return 1;
}
- cp = speakup_s2i(goto_buf, &go_pos);
+ go_pos = simple_strtol(goto_buf, &cp, 10);
goto_pos = (u_long) go_pos;
if (*cp == 'x') {
if (*goto_buf < '0')
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
index 775af26b9914..f0fb00392d6b 100644
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -14,7 +14,7 @@
unsigned short spk_xs, spk_ys, spk_xe, spk_ye; /* our region points */
/* Variables for selection control. */
-/* must not be disallocated */
+/* must not be deallocated */
struct vc_data *spk_sel_cons;
/* cleared by clear_selection */
static int sel_start = -1;
diff --git a/drivers/staging/speakup/speakup.h b/drivers/staging/speakup/speakup.h
index 22f0fbb85f42..0126f714821a 100644
--- a/drivers/staging/speakup/speakup.h
+++ b/drivers/staging/speakup/speakup.h
@@ -44,11 +44,6 @@
#define IS_CHAR(x, type) (spk_chartab[((u_char)x)]&type)
#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)]&type) == type)
-#define SET_DEFAULT -4
-#define E_RANGE -3
-#define E_TOOLONG -2
-#define E_UNDEF -1
-
extern int speakup_thread(void *data);
extern void spk_reset_default_chars(void);
extern void spk_reset_default_chartab(void);
@@ -58,9 +53,7 @@ void spk_reset_index_count(int sc);
void spk_get_index_count(int *linecount, int *sentcount);
extern int spk_set_key_info(const u_char *key_info, u_char *k_buffer);
extern char *spk_strlwr(char *s);
-extern char *speakup_s2i(char *start, int *dest);
extern char *spk_s2uchar(char *start, char *dest);
-extern char *spk_xlate(char *s);
extern int speakup_kobj_init(void);
extern void speakup_kobj_exit(void);
extern int spk_chartab_get_value(char *keyword);
diff --git a/drivers/staging/speakup/varhandlers.c b/drivers/staging/speakup/varhandlers.c
index f8c1e457d389..7f6288fc2299 100644
--- a/drivers/staging/speakup/varhandlers.c
+++ b/drivers/staging/speakup/varhandlers.c
@@ -184,19 +184,19 @@ int spk_set_num_var(int input, struct st_var_header *var, int how)
char buf[32];
char *cp;
struct var_t *var_data = var->data;
+
if (var_data == NULL)
- return E_UNDEF;
+ return -ENODATA;
if (how == E_NEW_DEFAULT) {
if (input < var_data->u.n.low || input > var_data->u.n.high)
- ret = E_RANGE;
- else
- var_data->u.n.default_val = input;
- return ret;
+ return -ERANGE;
+ var_data->u.n.default_val = input;
+ return 0;
}
if (how == E_DEFAULT) {
val = var_data->u.n.default_val;
- ret = SET_DEFAULT;
+ ret = -ERESTART;
} else {
if (how == E_SET)
val = input;
@@ -207,7 +207,7 @@ int spk_set_num_var(int input, struct st_var_header *var, int how)
else if (how == E_DEC)
val -= input;
if (val < var_data->u.n.low || val > var_data->u.n.high)
- return E_RANGE;
+ return -ERANGE;
}
var_data->u.n.value = val;
if (var->var_type == VAR_TIME && p_val != NULL) {
@@ -246,25 +246,25 @@ int spk_set_num_var(int input, struct st_var_header *var, int how)
int spk_set_string_var(const char *page, struct st_var_header *var, int len)
{
- int ret = 0;
struct var_t *var_data = var->data;
+
if (var_data == NULL)
- return E_UNDEF;
+ return -ENODATA;
if (len > MAXVARLEN)
- return -E_TOOLONG;
+ return -E2BIG;
if (!len) {
if (!var_data->u.s.default_val)
return 0;
- ret = SET_DEFAULT;
if (!var->p_val)
var->p_val = var_data->u.s.default_val;
if (var->p_val != var_data->u.s.default_val)
strcpy((char *)var->p_val, var_data->u.s.default_val);
+ return -ERESTART;
} else if (var->p_val)
strcpy((char *)var->p_val, page);
else
- return -E_TOOLONG;
- return ret;
+ return -E2BIG;
+ return 0;
}
/* spk_set_mask_bits sets or clears the punc/delim/repeat bits,
@@ -319,86 +319,12 @@ char *spk_strlwr(char *s)
return s;
}
-char *speakup_s2i(char *start, int *dest)
-{
- int val;
- char ch = *start;
- if (ch == '-' || ch == '+')
- start++;
- if (*start < '0' || *start > '9')
- return start;
- val = (*start) - '0';
- start++;
- while (*start >= '0' && *start <= '9') {
- val *= 10;
- val += (*start) - '0';
- start++;
- }
- if (ch == '-')
- *dest = -val;
- else
- *dest = val;
- return start;
-}
-
char *spk_s2uchar(char *start, char *dest)
{
int val = 0;
- while (*start && *start <= SPACE)
- start++;
- while (*start >= '0' && *start <= '9') {
- val *= 10;
- val += (*start) - '0';
- start++;
- }
+ val = simple_strtoul(skip_spaces(start), &start, 10);
if (*start == ',')
start++;
*dest = (u_char)val;
return start;
}
-
-char *spk_xlate(char *s)
-{
- static const char finds[] = "nrtvafe";
- static const char subs[] = "\n\r\t\013\001\014\033";
- static const char hx[] = "0123456789abcdefABCDEF";
- char *p = s, *p1, *p2, c;
- int num;
- while ((p = strchr(p, '\\'))) {
- p1 = p+1;
- p2 = strchr(finds, *p1);
- if (p2) {
- *p++ = subs[p2-finds];
- p1++;
- } else if (*p1 >= '0' && *p1 <= '7') {
- num = (*p1++)&7;
- while (num < 256 && *p1 >= '0' && *p1 <= '7') {
- num <<= 3;
- num = (*p1++)&7;
- }
- *p++ = num;
- } else if (*p1 == 'x' &&
- strchr(hx, p1[1]) && strchr(hx, p1[2])) {
- p1++;
- c = *p1++;
- if (c > '9')
- c = (c - '7') & 0x0f;
- else
- c -= '0';
- num = c << 4;
- c = *p1++;
- if (c > '9')
- c = (c-'7')&0x0f;
- else
- c -= '0';
- num += c;
- *p++ = num;
- } else
- *p++ = *p1++;
- p2 = p;
- while (*p1)
- *p2++ = *p1++;
- *p2 = '\0';
- }
- return s;
-}
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
index 6a21f67af086..a126b25c82d5 100644
--- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
+++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
@@ -649,7 +649,7 @@ static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
*
* This function calls to configures the rmi4 touchpad device
*/
-int synaptics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+static int synaptics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
struct synaptics_rmi4_fn *rfi)
{
/*
diff --git a/drivers/staging/omap-thermal/Kconfig b/drivers/staging/ti-soc-thermal/Kconfig
index 30cbc3bc8dfa..e81375fb2155 100644
--- a/drivers/staging/omap-thermal/Kconfig
+++ b/drivers/staging/ti-soc-thermal/Kconfig
@@ -1,7 +1,7 @@
-config OMAP_BANDGAP
- tristate "Texas Instruments OMAP4+ temperature sensor driver"
+config TI_SOC_THERMAL
+ tristate "Texas Instruments SoCs temperature sensor driver"
depends on THERMAL
- depends on ARCH_OMAP4 || SOC_OMAP5
+ depends on ARCH_HAS_BANDGAP
help
If you say yes here you get support for the Texas Instruments
OMAP4460+ on die bandgap temperature sensor support. The register
@@ -10,18 +10,20 @@ config OMAP_BANDGAP
This includes alert interrupts generation and also the TSHUT
support.
-config OMAP_THERMAL
- bool "Texas Instruments OMAP4+ thermal framework support"
- depends on OMAP_BANDGAP
+config TI_THERMAL
+ bool "Texas Instruments SoCs thermal framework support"
+ depends on TI_SOC_THERMAL
depends on CPU_THERMAL
help
If you say yes here you want to get support for generic thermal
- framework for the Texas Instruments OMAP4460+ on die bandgap
- temperature sensor.
+ framework for the Texas Instruments on die bandgap temperature sensor.
+
+ This includes trip points definitions, extrapolation rules and
+ CPU cooling device bindings.
config OMAP4_THERMAL
bool "Texas Instruments OMAP4 thermal support"
- depends on OMAP_BANDGAP
+ depends on TI_SOC_THERMAL
depends on ARCH_OMAP4
help
If you say yes here you get thermal support for the Texas Instruments
@@ -35,7 +37,7 @@ config OMAP4_THERMAL
config OMAP5_THERMAL
bool "Texas Instruments OMAP5 thermal support"
- depends on OMAP_BANDGAP
+ depends on TI_SOC_THERMAL
depends on SOC_OMAP5
help
If you say yes here you get thermal support for the Texas Instruments
diff --git a/drivers/staging/ti-soc-thermal/Makefile b/drivers/staging/ti-soc-thermal/Makefile
new file mode 100644
index 000000000000..0ca034fb419d
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o
+ti-soc-thermal-y := ti-bandgap.o
+ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o
+ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
+ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/staging/ti-soc-thermal/TODO b/drivers/staging/ti-soc-thermal/TODO
new file mode 100644
index 000000000000..7da787d19241
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/TODO
@@ -0,0 +1,12 @@
+List of TODOs (by Eduardo Valentin)
+
+on ti-bandgap.c:
+- Revisit PM support
+
+on ti-thermal-common.c/ti-thermal.h:
+- Revisit need for locking
+
+generally:
+- make sure this code works on OMAP4430, OMAP4460 and OMAP5430
+
+Copy patches to Eduardo Valentin <eduardo.valentin@ti.com>
diff --git a/drivers/staging/omap-thermal/omap4-thermal.c b/drivers/staging/ti-soc-thermal/omap4-thermal-data.c
index 04c02b6c0077..d255d33da9eb 100644
--- a/drivers/staging/omap-thermal/omap4-thermal.c
+++ b/drivers/staging/ti-soc-thermal/omap4-thermal-data.c
@@ -16,8 +16,9 @@
*
*/
-#include "omap-thermal.h"
-#include "omap-bandgap.h"
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+#include "omap4xxx-bandgap.h"
/*
* OMAP4430 has one instance of thermal sensor for MPU
@@ -44,8 +45,6 @@ static struct temp_sensor_data omap4430_mpu_temp_sensor_data = {
.max_temp = OMAP4430_MAX_TEMP,
.min_temp = OMAP4430_MIN_TEMP,
.hyst_val = OMAP4430_HYST_VAL,
- .adc_start_val = OMAP4430_ADC_START_VALUE,
- .adc_end_val = OMAP4430_ADC_END_VALUE,
};
/*
@@ -67,25 +66,28 @@ omap4430_adc_to_temp[OMAP4430_ADC_END_VALUE - OMAP4430_ADC_START_VALUE + 1] = {
};
/* OMAP4430 data */
-const struct omap_bandgap_data omap4430_data = {
- .features = OMAP_BANDGAP_FEATURE_MODE_CONFIG |
- OMAP_BANDGAP_FEATURE_POWER_SWITCH,
+const struct ti_bandgap_data omap4430_data = {
+ .features = TI_BANDGAP_FEATURE_MODE_CONFIG |
+ TI_BANDGAP_FEATURE_CLK_CTRL |
+ TI_BANDGAP_FEATURE_POWER_SWITCH,
.fclock_name = "bandgap_fclk",
.div_ck_name = "bandgap_fclk",
.conv_table = omap4430_adc_to_temp,
- .expose_sensor = omap_thermal_expose_sensor,
- .remove_sensor = omap_thermal_remove_sensor,
+ .adc_start_val = OMAP4430_ADC_START_VALUE,
+ .adc_end_val = OMAP4430_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
.sensors = {
{
.registers = &omap4430_mpu_temp_sensor_registers,
.ts_data = &omap4430_mpu_temp_sensor_data,
.domain = "cpu",
- .slope = 0,
- .constant = 20000,
- .slope_pcb = 0,
- .constant_pcb = 20000,
- .register_cooling = omap_thermal_register_cpu_cooling,
- .unregister_cooling = omap_thermal_unregister_cpu_cooling,
+ .slope = OMAP_GRADIENT_SLOPE_4430,
+ .constant = OMAP_GRADIENT_CONST_4430,
+ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4430,
+ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4430,
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
},
},
.sensor_count = 1,
@@ -140,8 +142,6 @@ static struct temp_sensor_data omap4460_mpu_temp_sensor_data = {
.max_temp = OMAP4460_MAX_TEMP,
.min_temp = OMAP4460_MIN_TEMP,
.hyst_val = OMAP4460_HYST_VAL,
- .adc_start_val = OMAP4460_ADC_START_VALUE,
- .adc_end_val = OMAP4460_ADC_END_VALUE,
.update_int1 = 1000,
.update_int2 = 2000,
};
@@ -201,18 +201,22 @@ omap4460_adc_to_temp[OMAP4460_ADC_END_VALUE - OMAP4460_ADC_START_VALUE + 1] = {
};
/* OMAP4460 data */
-const struct omap_bandgap_data omap4460_data = {
- .features = OMAP_BANDGAP_FEATURE_TSHUT |
- OMAP_BANDGAP_FEATURE_TSHUT_CONFIG |
- OMAP_BANDGAP_FEATURE_TALERT |
- OMAP_BANDGAP_FEATURE_MODE_CONFIG |
- OMAP_BANDGAP_FEATURE_POWER_SWITCH |
- OMAP_BANDGAP_FEATURE_COUNTER,
+const struct ti_bandgap_data omap4460_data = {
+ .features = TI_BANDGAP_FEATURE_TSHUT |
+ TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+ TI_BANDGAP_FEATURE_TALERT |
+ TI_BANDGAP_FEATURE_MODE_CONFIG |
+ TI_BANDGAP_FEATURE_POWER_SWITCH |
+ TI_BANDGAP_FEATURE_CLK_CTRL |
+ TI_BANDGAP_FEATURE_COUNTER,
.fclock_name = "bandgap_ts_fclk",
.div_ck_name = "div_ts_ck",
.conv_table = omap4460_adc_to_temp,
- .expose_sensor = omap_thermal_expose_sensor,
- .remove_sensor = omap_thermal_remove_sensor,
+ .adc_start_val = OMAP4460_ADC_START_VALUE,
+ .adc_end_val = OMAP4460_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+ .report_temperature = ti_thermal_report_sensor_temperature,
.sensors = {
{
.registers = &omap4460_mpu_temp_sensor_registers,
@@ -222,26 +226,30 @@ const struct omap_bandgap_data omap4460_data = {
.constant = OMAP_GRADIENT_CONST_4460,
.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460,
.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460,
- .register_cooling = omap_thermal_register_cpu_cooling,
- .unregister_cooling = omap_thermal_unregister_cpu_cooling,
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
},
},
.sensor_count = 1,
};
/* OMAP4470 data */
-const struct omap_bandgap_data omap4470_data = {
- .features = OMAP_BANDGAP_FEATURE_TSHUT |
- OMAP_BANDGAP_FEATURE_TSHUT_CONFIG |
- OMAP_BANDGAP_FEATURE_TALERT |
- OMAP_BANDGAP_FEATURE_MODE_CONFIG |
- OMAP_BANDGAP_FEATURE_POWER_SWITCH |
- OMAP_BANDGAP_FEATURE_COUNTER,
+const struct ti_bandgap_data omap4470_data = {
+ .features = TI_BANDGAP_FEATURE_TSHUT |
+ TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+ TI_BANDGAP_FEATURE_TALERT |
+ TI_BANDGAP_FEATURE_MODE_CONFIG |
+ TI_BANDGAP_FEATURE_POWER_SWITCH |
+ TI_BANDGAP_FEATURE_CLK_CTRL |
+ TI_BANDGAP_FEATURE_COUNTER,
.fclock_name = "bandgap_ts_fclk",
.div_ck_name = "div_ts_ck",
.conv_table = omap4460_adc_to_temp,
- .expose_sensor = omap_thermal_expose_sensor,
- .remove_sensor = omap_thermal_remove_sensor,
+ .adc_start_val = OMAP4460_ADC_START_VALUE,
+ .adc_end_val = OMAP4460_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+ .report_temperature = ti_thermal_report_sensor_temperature,
.sensors = {
{
.registers = &omap4460_mpu_temp_sensor_registers,
@@ -251,8 +259,8 @@ const struct omap_bandgap_data omap4470_data = {
.constant = OMAP_GRADIENT_CONST_4470,
.slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470,
.constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470,
- .register_cooling = omap_thermal_register_cpu_cooling,
- .unregister_cooling = omap_thermal_unregister_cpu_cooling,
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
},
},
.sensor_count = 1,
diff --git a/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h b/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h
new file mode 100644
index 000000000000..6f2de3a3356d
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h
@@ -0,0 +1,175 @@
+/*
+ * OMAP4xxx bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@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
+ *
+ */
+#ifndef __OMAP4XXX_BANDGAP_H
+#define __OMAP4XXX_BANDGAP_H
+
+/**
+ * *** OMAP4430 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP4430.
+ */
+
+/**
+ * OMAP4430 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP on 4430.
+ */
+
+/* OMAP4430.FUSE_OPP_BGAP */
+#define OMAP4430_FUSE_OPP_BGAP 0x0
+
+/* OMAP4430.TEMP_SENSOR */
+#define OMAP4430_TEMP_SENSOR_CTRL_OFFSET 0xCC
+
+/**
+ * Register and bit definitions for OMAP4430
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP4430. Bit defines are
+ * grouped by register.
+ */
+
+/* OMAP4430.TEMP_SENSOR bits */
+#define OMAP4430_BGAP_TEMPSOFF_MASK BIT(12)
+#define OMAP4430_BGAP_TSHUT_MASK BIT(11)
+#define OMAP4430_SINGLE_MODE_MASK BIT(10)
+#define OMAP4430_BGAP_TEMP_SENSOR_SOC_MASK BIT(9)
+#define OMAP4430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(8)
+#define OMAP4430_BGAP_TEMP_SENSOR_DTEMP_MASK (0xff << 0)
+
+/**
+ * Temperature limits and thresholds for OMAP4430
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP4430.
+ */
+
+/* ADC conversion table limits */
+#define OMAP4430_ADC_START_VALUE 0
+#define OMAP4430_ADC_END_VALUE 127
+/* bandgap clock limits (no control on 4430) */
+#define OMAP4430_MAX_FREQ 32768
+#define OMAP4430_MIN_FREQ 32768
+/* sensor limits */
+#define OMAP4430_MIN_TEMP -40000
+#define OMAP4430_MAX_TEMP 125000
+#define OMAP4430_HYST_VAL 5000
+
+/**
+ * *** OMAP4460 *** Applicable for OMAP4470
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP4460.
+ */
+
+/**
+ * OMAP4460 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP on 4460.
+ */
+
+/* OMAP4460.FUSE_OPP_BGAP */
+#define OMAP4460_FUSE_OPP_BGAP 0x0
+
+/* OMAP4460.TEMP_SENSOR */
+#define OMAP4460_TEMP_SENSOR_CTRL_OFFSET 0xCC
+
+/* OMAP4460.BANDGAP_CTRL */
+#define OMAP4460_BGAP_CTRL_OFFSET 0x118
+
+/* OMAP4460.BANDGAP_COUNTER */
+#define OMAP4460_BGAP_COUNTER_OFFSET 0x11C
+
+/* OMAP4460.BANDGAP_THRESHOLD */
+#define OMAP4460_BGAP_THRESHOLD_OFFSET 0x120
+
+/* OMAP4460.TSHUT_THRESHOLD */
+#define OMAP4460_BGAP_TSHUT_OFFSET 0x124
+
+/* OMAP4460.BANDGAP_STATUS */
+#define OMAP4460_BGAP_STATUS_OFFSET 0x128
+
+/**
+ * Register bitfields for OMAP4460
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP4460. Bit defines are
+ * grouped by register.
+ */
+/* OMAP4460.TEMP_SENSOR bits */
+#define OMAP4460_BGAP_TEMPSOFF_MASK BIT(13)
+#define OMAP4460_BGAP_TEMP_SENSOR_SOC_MASK BIT(11)
+#define OMAP4460_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10)
+#define OMAP4460_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* OMAP4460.BANDGAP_CTRL bits */
+#define OMAP4460_SINGLE_MODE_MASK BIT(31)
+#define OMAP4460_MASK_HOT_MASK BIT(1)
+#define OMAP4460_MASK_COLD_MASK BIT(0)
+
+/* OMAP4460.BANDGAP_COUNTER bits */
+#define OMAP4460_COUNTER_MASK (0xffffff << 0)
+
+/* OMAP4460.BANDGAP_THRESHOLD bits */
+#define OMAP4460_T_HOT_MASK (0x3ff << 16)
+#define OMAP4460_T_COLD_MASK (0x3ff << 0)
+
+/* OMAP4460.TSHUT_THRESHOLD bits */
+#define OMAP4460_TSHUT_HOT_MASK (0x3ff << 16)
+#define OMAP4460_TSHUT_COLD_MASK (0x3ff << 0)
+
+/* OMAP4460.BANDGAP_STATUS bits */
+#define OMAP4460_CLEAN_STOP_MASK BIT(3)
+#define OMAP4460_BGAP_ALERT_MASK BIT(2)
+#define OMAP4460_HOT_FLAG_MASK BIT(1)
+#define OMAP4460_COLD_FLAG_MASK BIT(0)
+
+/**
+ * Temperature limits and thresholds for OMAP4460
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP4460.
+ */
+
+/* ADC conversion table limits */
+#define OMAP4460_ADC_START_VALUE 530
+#define OMAP4460_ADC_END_VALUE 932
+/* bandgap clock limits */
+#define OMAP4460_MAX_FREQ 1500000
+#define OMAP4460_MIN_FREQ 1000000
+/* sensor limits */
+#define OMAP4460_MIN_TEMP -40000
+#define OMAP4460_MAX_TEMP 123000
+#define OMAP4460_HYST_VAL 5000
+/* interrupts thresholds */
+#define OMAP4460_TSHUT_HOT 900 /* 122 deg C */
+#define OMAP4460_TSHUT_COLD 895 /* 100 deg C */
+#define OMAP4460_T_HOT 800 /* 73 deg C */
+#define OMAP4460_T_COLD 795 /* 71 deg C */
+
+#endif /* __OMAP4XXX_BANDGAP_H */
diff --git a/drivers/staging/ti-soc-thermal/omap5-thermal-data.c b/drivers/staging/ti-soc-thermal/omap5-thermal-data.c
new file mode 100644
index 000000000000..eff0c80fd4af
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/omap5-thermal-data.c
@@ -0,0 +1,359 @@
+/*
+ * OMAP5 thermal driver.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Inc.
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@ti.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+#include "omap5xxx-bandgap.h"
+
+/*
+ * OMAP5430 has three instances of thermal sensor for MPU, GPU & CORE,
+ * need to describe the individual registers and bit fields.
+ */
+
+/*
+ * OMAP5430 MPU thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_mpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_MPU_OFFSET,
+ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+ .mask_hot_mask = OMAP5430_MASK_HOT_MPU_MASK,
+ .mask_cold_mask = OMAP5430_MASK_COLD_MPU_MASK,
+ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+ .mask_freeze_mask = OMAP5430_MASK_FREEZE_MPU_MASK,
+ .mask_clear_mask = OMAP5430_MASK_CLEAR_MPU_MASK,
+ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK,
+
+
+ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+ .counter_mask = OMAP5430_COUNTER_MASK,
+
+ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_MPU_OFFSET,
+ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+ .tshut_threshold = OMAP5430_BGAP_TSHUT_MPU_OFFSET,
+ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+ .status_clean_stop_mask = 0x0,
+ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+ .status_hot_mask = OMAP5430_HOT_MPU_FLAG_MASK,
+ .status_cold_mask = OMAP5430_COLD_MPU_FLAG_MASK,
+
+ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET,
+ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_MPU_0_OFFSET,
+ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_MPU_1_OFFSET,
+ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_MPU_2_OFFSET,
+ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_MPU_3_OFFSET,
+ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_MPU_4_OFFSET,
+ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_MPU,
+};
+
+/*
+ * OMAP5430 GPU thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_gpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_GPU_OFFSET,
+ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+ .mask_hot_mask = OMAP5430_MASK_HOT_GPU_MASK,
+ .mask_cold_mask = OMAP5430_MASK_COLD_GPU_MASK,
+ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+ .mask_freeze_mask = OMAP5430_MASK_FREEZE_GPU_MASK,
+ .mask_clear_mask = OMAP5430_MASK_CLEAR_GPU_MASK,
+ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK,
+
+ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+ .counter_mask = OMAP5430_COUNTER_MASK,
+
+ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_GPU_OFFSET,
+ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+ .tshut_threshold = OMAP5430_BGAP_TSHUT_GPU_OFFSET,
+ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+ .status_clean_stop_mask = 0x0,
+ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+ .status_hot_mask = OMAP5430_HOT_GPU_FLAG_MASK,
+ .status_cold_mask = OMAP5430_COLD_GPU_FLAG_MASK,
+
+ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET,
+ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_GPU_0_OFFSET,
+ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_GPU_1_OFFSET,
+ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_GPU_2_OFFSET,
+ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_GPU_3_OFFSET,
+ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_GPU_4_OFFSET,
+
+ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_GPU,
+};
+
+/*
+ * OMAP5430 CORE thermal sensor register offset and bit-fields
+ */
+static struct temp_sensor_registers
+omap5430_core_temp_sensor_registers = {
+ .temp_sensor_ctrl = OMAP5430_TEMP_SENSOR_CORE_OFFSET,
+ .bgap_tempsoff_mask = OMAP5430_BGAP_TEMPSOFF_MASK,
+ .bgap_eocz_mask = OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK,
+ .bgap_dtemp_mask = OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK,
+
+ .bgap_mask_ctrl = OMAP5430_BGAP_CTRL_OFFSET,
+ .mask_hot_mask = OMAP5430_MASK_HOT_CORE_MASK,
+ .mask_cold_mask = OMAP5430_MASK_COLD_CORE_MASK,
+ .mask_sidlemode_mask = OMAP5430_MASK_SIDLEMODE_MASK,
+ .mask_counter_delay_mask = OMAP5430_MASK_COUNTER_DELAY_MASK,
+ .mask_freeze_mask = OMAP5430_MASK_FREEZE_CORE_MASK,
+ .mask_clear_mask = OMAP5430_MASK_CLEAR_CORE_MASK,
+ .mask_clear_accum_mask = OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK,
+
+ .bgap_counter = OMAP5430_BGAP_CTRL_OFFSET,
+ .counter_mask = OMAP5430_COUNTER_MASK,
+
+ .bgap_threshold = OMAP5430_BGAP_THRESHOLD_CORE_OFFSET,
+ .threshold_thot_mask = OMAP5430_T_HOT_MASK,
+ .threshold_tcold_mask = OMAP5430_T_COLD_MASK,
+
+ .tshut_threshold = OMAP5430_BGAP_TSHUT_CORE_OFFSET,
+ .tshut_hot_mask = OMAP5430_TSHUT_HOT_MASK,
+ .tshut_cold_mask = OMAP5430_TSHUT_COLD_MASK,
+
+ .bgap_status = OMAP5430_BGAP_STATUS_OFFSET,
+ .status_clean_stop_mask = 0x0,
+ .status_bgap_alert_mask = OMAP5430_BGAP_ALERT_MASK,
+ .status_hot_mask = OMAP5430_HOT_CORE_FLAG_MASK,
+ .status_cold_mask = OMAP5430_COLD_CORE_FLAG_MASK,
+
+ .bgap_cumul_dtemp = OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET,
+ .ctrl_dtemp_0 = OMAP5430_BGAP_DTEMP_CORE_0_OFFSET,
+ .ctrl_dtemp_1 = OMAP5430_BGAP_DTEMP_CORE_1_OFFSET,
+ .ctrl_dtemp_2 = OMAP5430_BGAP_DTEMP_CORE_2_OFFSET,
+ .ctrl_dtemp_3 = OMAP5430_BGAP_DTEMP_CORE_3_OFFSET,
+ .ctrl_dtemp_4 = OMAP5430_BGAP_DTEMP_CORE_4_OFFSET,
+
+ .bgap_efuse = OMAP5430_FUSE_OPP_BGAP_CORE,
+};
+
+/* Thresholds and limits for OMAP5430 MPU temperature sensor */
+static struct temp_sensor_data omap5430_mpu_temp_sensor_data = {
+ .tshut_hot = OMAP5430_MPU_TSHUT_HOT,
+ .tshut_cold = OMAP5430_MPU_TSHUT_COLD,
+ .t_hot = OMAP5430_MPU_T_HOT,
+ .t_cold = OMAP5430_MPU_T_COLD,
+ .min_freq = OMAP5430_MPU_MIN_FREQ,
+ .max_freq = OMAP5430_MPU_MAX_FREQ,
+ .max_temp = OMAP5430_MPU_MAX_TEMP,
+ .min_temp = OMAP5430_MPU_MIN_TEMP,
+ .hyst_val = OMAP5430_MPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for OMAP5430 GPU temperature sensor */
+static struct temp_sensor_data omap5430_gpu_temp_sensor_data = {
+ .tshut_hot = OMAP5430_GPU_TSHUT_HOT,
+ .tshut_cold = OMAP5430_GPU_TSHUT_COLD,
+ .t_hot = OMAP5430_GPU_T_HOT,
+ .t_cold = OMAP5430_GPU_T_COLD,
+ .min_freq = OMAP5430_GPU_MIN_FREQ,
+ .max_freq = OMAP5430_GPU_MAX_FREQ,
+ .max_temp = OMAP5430_GPU_MAX_TEMP,
+ .min_temp = OMAP5430_GPU_MIN_TEMP,
+ .hyst_val = OMAP5430_GPU_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/* Thresholds and limits for OMAP5430 CORE temperature sensor */
+static struct temp_sensor_data omap5430_core_temp_sensor_data = {
+ .tshut_hot = OMAP5430_CORE_TSHUT_HOT,
+ .tshut_cold = OMAP5430_CORE_TSHUT_COLD,
+ .t_hot = OMAP5430_CORE_T_HOT,
+ .t_cold = OMAP5430_CORE_T_COLD,
+ .min_freq = OMAP5430_CORE_MIN_FREQ,
+ .max_freq = OMAP5430_CORE_MAX_FREQ,
+ .max_temp = OMAP5430_CORE_MAX_TEMP,
+ .min_temp = OMAP5430_CORE_MIN_TEMP,
+ .hyst_val = OMAP5430_CORE_HYST_VAL,
+ .update_int1 = 1000,
+ .update_int2 = 2000,
+};
+
+/*
+ * OMAP54xx ES2.0 : Temperature values in milli degree celsius
+ * ADC code values from 540 to 945
+ */
+static int
+omap5430_adc_to_temp[
+ OMAP5430_ADC_END_VALUE - OMAP5430_ADC_START_VALUE + 1] = {
+ /* Index 540 - 549 */
+ -40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
+ -37800,
+ /* Index 550 - 559 */
+ -37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
+ -33400,
+ /* Index 560 - 569 */
+ -33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
+ -29400,
+ /* Index 570 - 579 */
+ -29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
+ -25000,
+ /* Index 580 - 589 */
+ -24600, -24200, -23800, -23400, -23000, -22600, -22200, -21600, -21400,
+ -21000,
+ /* Index 590 - 599 */
+ -20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
+ -16600,
+ /* Index 600 - 609 */
+ -16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
+ -12500,
+ /* Index 610 - 619 */
+ -11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
+ -8200,
+ /* Index 620 - 629 */
+ -7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500, -3900,
+ /* Index 630 - 639 */
+ -3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200, 200,
+ /* Index 640 - 649 */
+ 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900, 4500,
+ /* Index 650 - 659 */
+ 5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200, 8600,
+ /* Index 660 - 669 */
+ 9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200, 12700,
+ /* Index 670 - 679 */
+ 13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600, 17000,
+ /* Index 680 - 689 */
+ 17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600, 21100,
+ /* Index 690 - 699 */
+ 21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000, 25400,
+ /* Index 700 - 709 */
+ 25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000, 29400,
+ /* Index 710 - 719 */
+ 29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400, 33800,
+ /* Index 720 - 729 */
+ 34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400, 37800,
+ /* Index 730 - 739 */
+ 38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400, 41800,
+ /* Index 740 - 749 */
+ 42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800, 46200,
+ /* Index 750 - 759 */
+ 46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800, 50200,
+ /* Index 760 - 769 */
+ 50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800, 54200,
+ /* Index 770 - 779 */
+ 54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200, 58600,
+ /* Index 780 - 789 */
+ 59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200, 62600,
+ /* Index 790 - 799 */
+ 63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200, 66600,
+ /* Index 800 - 809 */
+ 67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200, 70600,
+ /* Index 810 - 819 */
+ 71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600, 75000,
+ /* Index 820 - 829 */
+ 75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600, 79000,
+ /* Index 830 - 839 */
+ 79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600, 83000,
+ /* Index 840 - 849 */
+ 83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600, 87000,
+ /* Index 850 - 859 */
+ 87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600, 91000,
+ /* Index 860 - 869 */
+ 91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600, 95000,
+ /* Index 870 - 879 */
+ 95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000, 99400,
+ /* Index 880 - 889 */
+ 99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
+ 103400,
+ /* Index 890 - 899 */
+ 103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
+ 107400,
+ /* Index 900 - 909 */
+ 107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
+ 111400,
+ /* Index 910 - 919 */
+ 111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
+ 115400,
+ /* Index 920 - 929 */
+ 115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
+ 119400,
+ /* Index 930 - 939 */
+ 119800, 120200, 120600, 121000, 121400, 121800, 122400, 122600, 123000,
+ 123400,
+ /* Index 940 - 945 */
+ 123800, 1242000, 124600, 124900, 125000, 125000,
+};
+
+/* OMAP54xx ES2.0 data */
+const struct ti_bandgap_data omap5430_data = {
+ .features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
+ TI_BANDGAP_FEATURE_FREEZE_BIT |
+ TI_BANDGAP_FEATURE_TALERT |
+ TI_BANDGAP_FEATURE_COUNTER_DELAY |
+ TI_BANDGAP_FEATURE_HISTORY_BUFFER,
+ .fclock_name = "l3instr_ts_gclk_div",
+ .div_ck_name = "l3instr_ts_gclk_div",
+ .conv_table = omap5430_adc_to_temp,
+ .adc_start_val = OMAP5430_ADC_START_VALUE,
+ .adc_end_val = OMAP5430_ADC_END_VALUE,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+ .report_temperature = ti_thermal_report_sensor_temperature,
+ .sensors = {
+ {
+ .registers = &omap5430_mpu_temp_sensor_registers,
+ .ts_data = &omap5430_mpu_temp_sensor_data,
+ .domain = "cpu",
+ .register_cooling = ti_thermal_register_cpu_cooling,
+ .unregister_cooling = ti_thermal_unregister_cpu_cooling,
+ .slope = OMAP_GRADIENT_SLOPE_5430_CPU,
+ .constant = OMAP_GRADIENT_CONST_5430_CPU,
+ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU,
+ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU,
+ },
+ {
+ .registers = &omap5430_gpu_temp_sensor_registers,
+ .ts_data = &omap5430_gpu_temp_sensor_data,
+ .domain = "gpu",
+ .slope = OMAP_GRADIENT_SLOPE_5430_GPU,
+ .constant = OMAP_GRADIENT_CONST_5430_GPU,
+ .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU,
+ .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU,
+ },
+ {
+ .registers = &omap5430_core_temp_sensor_registers,
+ .ts_data = &omap5430_core_temp_sensor_data,
+ .domain = "core",
+ },
+ },
+ .sensor_count = 3,
+};
diff --git a/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h b/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h
new file mode 100644
index 000000000000..400b55dffadd
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h
@@ -0,0 +1,200 @@
+/*
+ * OMAP5xxx bandgap registers, bitfields and temperature definitions
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@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
+ *
+ */
+#ifndef __OMAP5XXX_BANDGAP_H
+#define __OMAP5XXX_BANDGAP_H
+
+/**
+ * *** OMAP5430 ***
+ *
+ * Below, in sequence, are the Register definitions,
+ * the bitfields and the temperature definitions for OMAP5430.
+ */
+
+/**
+ * OMAP5430 register definitions
+ *
+ * Registers are defined as offsets. The offsets are
+ * relative to FUSE_OPP_BGAP_GPU on 5430.
+ *
+ * Register below are grouped by domain (not necessarily in offset order)
+ */
+
+/* OMAP5430.GPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_GPU 0x0
+#define OMAP5430_TEMP_SENSOR_GPU_OFFSET 0x150
+#define OMAP5430_BGAP_THRESHOLD_GPU_OFFSET 0x1A8
+#define OMAP5430_BGAP_TSHUT_GPU_OFFSET 0x1B4
+#define OMAP5430_BGAP_CUMUL_DTEMP_GPU_OFFSET 0x1C0
+#define OMAP5430_BGAP_DTEMP_GPU_0_OFFSET 0x1F4
+#define OMAP5430_BGAP_DTEMP_GPU_1_OFFSET 0x1F8
+#define OMAP5430_BGAP_DTEMP_GPU_2_OFFSET 0x1FC
+#define OMAP5430_BGAP_DTEMP_GPU_3_OFFSET 0x200
+#define OMAP5430_BGAP_DTEMP_GPU_4_OFFSET 0x204
+
+/* OMAP5430.MPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_MPU 0x4
+#define OMAP5430_TEMP_SENSOR_MPU_OFFSET 0x14C
+#define OMAP5430_BGAP_THRESHOLD_MPU_OFFSET 0x1A4
+#define OMAP5430_BGAP_TSHUT_MPU_OFFSET 0x1B0
+#define OMAP5430_BGAP_CUMUL_DTEMP_MPU_OFFSET 0x1BC
+#define OMAP5430_BGAP_DTEMP_MPU_0_OFFSET 0x1E0
+#define OMAP5430_BGAP_DTEMP_MPU_1_OFFSET 0x1E4
+#define OMAP5430_BGAP_DTEMP_MPU_2_OFFSET 0x1E8
+#define OMAP5430_BGAP_DTEMP_MPU_3_OFFSET 0x1EC
+#define OMAP5430_BGAP_DTEMP_MPU_4_OFFSET 0x1F0
+
+/* OMAP5430.MPU register offsets */
+#define OMAP5430_FUSE_OPP_BGAP_CORE 0x8
+#define OMAP5430_TEMP_SENSOR_CORE_OFFSET 0x154
+#define OMAP5430_BGAP_THRESHOLD_CORE_OFFSET 0x1AC
+#define OMAP5430_BGAP_TSHUT_CORE_OFFSET 0x1B8
+#define OMAP5430_BGAP_CUMUL_DTEMP_CORE_OFFSET 0x1C4
+#define OMAP5430_BGAP_DTEMP_CORE_0_OFFSET 0x208
+#define OMAP5430_BGAP_DTEMP_CORE_1_OFFSET 0x20C
+#define OMAP5430_BGAP_DTEMP_CORE_2_OFFSET 0x210
+#define OMAP5430_BGAP_DTEMP_CORE_3_OFFSET 0x214
+#define OMAP5430_BGAP_DTEMP_CORE_4_OFFSET 0x218
+
+/* OMAP5430.common register offsets */
+#define OMAP5430_BGAP_CTRL_OFFSET 0x1A0
+#define OMAP5430_BGAP_STATUS_OFFSET 0x1C8
+
+/**
+ * Register bitfields for OMAP5430
+ *
+ * All the macros bellow define the required bits for
+ * controlling temperature on OMAP5430. Bit defines are
+ * grouped by register.
+ */
+
+/* OMAP5430.TEMP_SENSOR */
+#define OMAP5430_BGAP_TEMP_SENSOR_SOC_MASK BIT(12)
+#define OMAP5430_BGAP_TEMPSOFF_MASK BIT(11)
+#define OMAP5430_BGAP_TEMP_SENSOR_EOCZ_MASK BIT(10)
+#define OMAP5430_BGAP_TEMP_SENSOR_DTEMP_MASK (0x3ff << 0)
+
+/* OMAP5430.BANDGAP_CTRL */
+#define OMAP5430_MASK_SIDLEMODE_MASK (0x3 << 30)
+#define OMAP5430_MASK_COUNTER_DELAY_MASK (0x7 << 27)
+#define OMAP5430_MASK_FREEZE_CORE_MASK BIT(23)
+#define OMAP5430_MASK_FREEZE_GPU_MASK BIT(22)
+#define OMAP5430_MASK_FREEZE_MPU_MASK BIT(21)
+#define OMAP5430_MASK_CLEAR_CORE_MASK BIT(20)
+#define OMAP5430_MASK_CLEAR_GPU_MASK BIT(19)
+#define OMAP5430_MASK_CLEAR_MPU_MASK BIT(18)
+#define OMAP5430_MASK_CLEAR_ACCUM_CORE_MASK BIT(17)
+#define OMAP5430_MASK_CLEAR_ACCUM_GPU_MASK BIT(16)
+#define OMAP5430_MASK_CLEAR_ACCUM_MPU_MASK BIT(15)
+#define OMAP5430_MASK_HOT_CORE_MASK BIT(5)
+#define OMAP5430_MASK_COLD_CORE_MASK BIT(4)
+#define OMAP5430_MASK_HOT_GPU_MASK BIT(3)
+#define OMAP5430_MASK_COLD_GPU_MASK BIT(2)
+#define OMAP5430_MASK_HOT_MPU_MASK BIT(1)
+#define OMAP5430_MASK_COLD_MPU_MASK BIT(0)
+
+/* OMAP5430.BANDGAP_COUNTER */
+#define OMAP5430_COUNTER_MASK (0xffffff << 0)
+
+/* OMAP5430.BANDGAP_THRESHOLD */
+#define OMAP5430_T_HOT_MASK (0x3ff << 16)
+#define OMAP5430_T_COLD_MASK (0x3ff << 0)
+
+/* OMAP5430.TSHUT_THRESHOLD */
+#define OMAP5430_TSHUT_HOT_MASK (0x3ff << 16)
+#define OMAP5430_TSHUT_COLD_MASK (0x3ff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_MPU */
+#define OMAP5430_CUMUL_DTEMP_MPU_MASK (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_GPU */
+#define OMAP5430_CUMUL_DTEMP_GPU_MASK (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_CUMUL_DTEMP_CORE */
+#define OMAP5430_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
+
+/* OMAP5430.BANDGAP_STATUS */
+#define OMAP5430_BGAP_ALERT_MASK BIT(31)
+#define OMAP5430_HOT_CORE_FLAG_MASK BIT(5)
+#define OMAP5430_COLD_CORE_FLAG_MASK BIT(4)
+#define OMAP5430_HOT_GPU_FLAG_MASK BIT(3)
+#define OMAP5430_COLD_GPU_FLAG_MASK BIT(2)
+#define OMAP5430_HOT_MPU_FLAG_MASK BIT(1)
+#define OMAP5430_COLD_MPU_FLAG_MASK BIT(0)
+
+/**
+ * Temperature limits and thresholds for OMAP5430
+ *
+ * All the macros bellow are definitions for handling the
+ * ADC conversions and representation of temperature limits
+ * and thresholds for OMAP5430. Definitions are grouped
+ * by temperature domain.
+ */
+
+/* OMAP5430.common temperature definitions */
+/* ADC conversion table limits */
+#define OMAP5430_ADC_START_VALUE 540
+#define OMAP5430_ADC_END_VALUE 945
+
+/* OMAP5430.GPU temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_GPU_MAX_FREQ 1500000
+#define OMAP5430_GPU_MIN_FREQ 1000000
+/* sensor limits */
+#define OMAP5430_GPU_MIN_TEMP -40000
+#define OMAP5430_GPU_MAX_TEMP 125000
+#define OMAP5430_GPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define OMAP5430_GPU_TSHUT_HOT 915
+#define OMAP5430_GPU_TSHUT_COLD 900
+#define OMAP5430_GPU_T_HOT 800
+#define OMAP5430_GPU_T_COLD 795
+
+/* OMAP5430.MPU temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_MPU_MAX_FREQ 1500000
+#define OMAP5430_MPU_MIN_FREQ 1000000
+/* sensor limits */
+#define OMAP5430_MPU_MIN_TEMP -40000
+#define OMAP5430_MPU_MAX_TEMP 125000
+#define OMAP5430_MPU_HYST_VAL 5000
+/* interrupts thresholds */
+#define OMAP5430_MPU_TSHUT_HOT 915
+#define OMAP5430_MPU_TSHUT_COLD 900
+#define OMAP5430_MPU_T_HOT 800
+#define OMAP5430_MPU_T_COLD 795
+
+/* OMAP5430.CORE temperature definitions */
+/* bandgap clock limits */
+#define OMAP5430_CORE_MAX_FREQ 1500000
+#define OMAP5430_CORE_MIN_FREQ 1000000
+/* sensor limits */
+#define OMAP5430_CORE_MIN_TEMP -40000
+#define OMAP5430_CORE_MAX_TEMP 125000
+#define OMAP5430_CORE_HYST_VAL 5000
+/* interrupts thresholds */
+#define OMAP5430_CORE_TSHUT_HOT 915
+#define OMAP5430_CORE_TSHUT_COLD 900
+#define OMAP5430_CORE_T_HOT 800
+#define OMAP5430_CORE_T_COLD 795
+
+#endif /* __OMAP5XXX_BANDGAP_H */
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.c b/drivers/staging/ti-soc-thermal/ti-bandgap.c
new file mode 100644
index 000000000000..f20c1cfe9800
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/ti-bandgap.c
@@ -0,0 +1,1546 @@
+/*
+ * TI Bandgap temperature sensor driver
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: J Keerthy <j-keerthy@ti.com>
+ * Author: Moiz Sonasath <m-sonasath@ti.com>
+ * Couple of fixes, DT and MFD adaptation:
+ * Eduardo Valentin <eduardo.valentin@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 <linux/export.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/reboot.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+
+#include "ti-bandgap.h"
+
+/*** Helper functions to access registers and their bitfields ***/
+
+/**
+ * ti_bandgap_readl() - simple read helper function
+ * @bgp: pointer to ti_bandgap structure
+ * @reg: desired register (offset) to be read
+ *
+ * Helper function to read bandgap registers. It uses the io remapped area.
+ * Return: the register value.
+ */
+static u32 ti_bandgap_readl(struct ti_bandgap *bgp, u32 reg)
+{
+ return readl(bgp->base + reg);
+}
+
+/**
+ * ti_bandgap_writel() - simple write helper function
+ * @bgp: pointer to ti_bandgap structure
+ * @val: desired register value to be written
+ * @reg: desired register (offset) to be written
+ *
+ * Helper function to write bandgap registers. It uses the io remapped area.
+ */
+static void ti_bandgap_writel(struct ti_bandgap *bgp, u32 val, u32 reg)
+{
+ writel(val, bgp->base + reg);
+}
+
+/**
+ * DOC: macro to update bits.
+ *
+ * RMW_BITS() - used to read, modify and update bandgap bitfields.
+ * The value passed will be shifted.
+ */
+#define RMW_BITS(bgp, id, reg, mask, val) \
+do { \
+ struct temp_sensor_registers *t; \
+ u32 r; \
+ \
+ t = bgp->conf->sensors[(id)].registers; \
+ r = ti_bandgap_readl(bgp, t->reg); \
+ r &= ~t->mask; \
+ r |= (val) << __ffs(t->mask); \
+ ti_bandgap_writel(bgp, r, t->reg); \
+} while (0)
+
+/*** Basic helper functions ***/
+
+/**
+ * ti_bandgap_power() - controls the power state of a bandgap device
+ * @bgp: pointer to ti_bandgap structure
+ * @on: desired power state (1 - on, 0 - off)
+ *
+ * Used to power on/off a bandgap device instance. Only used on those
+ * that features tempsoff bit.
+ *
+ * Return: 0 on success, -ENOTSUPP if tempsoff is not supported.
+ */
+static int ti_bandgap_power(struct ti_bandgap *bgp, bool on)
+{
+ int i, ret = 0;
+
+ if (!TI_BANDGAP_HAS(bgp, POWER_SWITCH)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ for (i = 0; i < bgp->conf->sensor_count; i++)
+ /* active on 0 */
+ RMW_BITS(bgp, i, temp_sensor_ctrl, bgap_tempsoff_mask, !on);
+
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_read_temp() - helper function to read sensor temperature
+ * @bgp: pointer to ti_bandgap structure
+ * @id: bandgap sensor id
+ *
+ * Function to concentrate the steps to read sensor temperature register.
+ * This function is desired because, depending on bandgap device version,
+ * it might be needed to freeze the bandgap state machine, before fetching
+ * the register value.
+ *
+ * Return: temperature in ADC values.
+ */
+static u32 ti_bandgap_read_temp(struct ti_bandgap *bgp, int id)
+{
+ struct temp_sensor_registers *tsr;
+ u32 temp, reg;
+
+ tsr = bgp->conf->sensors[id].registers;
+ reg = tsr->temp_sensor_ctrl;
+
+ if (TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 1);
+ /*
+ * In case we cannot read from cur_dtemp / dtemp_0,
+ * then we read from the last valid temp read
+ */
+ reg = tsr->ctrl_dtemp_1;
+ }
+
+ /* read temperature */
+ temp = ti_bandgap_readl(bgp, reg);
+ temp &= tsr->bgap_dtemp_mask;
+
+ if (TI_BANDGAP_HAS(bgp, FREEZE_BIT))
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_freeze_mask, 0);
+
+ return temp;
+}
+
+/*** IRQ handlers ***/
+
+/**
+ * ti_bandgap_talert_irq_handler() - handles Temperature alert IRQs
+ * @irq: IRQ number
+ * @data: private data (struct ti_bandgap *)
+ *
+ * This is the Talert handler. Use it only if bandgap device features
+ * HAS(TALERT). This handler goes over all sensors and checks their
+ * conditions and acts accordingly. In case there are events pending,
+ * it will reset the event mask to wait for the opposite event (next event).
+ * Every time there is a new event, it will be reported to thermal layer.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t ti_bandgap_talert_irq_handler(int irq, void *data)
+{
+ struct ti_bandgap *bgp = data;
+ struct temp_sensor_registers *tsr;
+ u32 t_hot = 0, t_cold = 0, ctrl;
+ int i;
+
+ spin_lock(&bgp->lock);
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ tsr = bgp->conf->sensors[i].registers;
+ ctrl = ti_bandgap_readl(bgp, tsr->bgap_status);
+
+ /* Read the status of t_hot */
+ t_hot = ctrl & tsr->status_hot_mask;
+
+ /* Read the status of t_cold */
+ t_cold = ctrl & tsr->status_cold_mask;
+
+ if (!t_cold && !t_hot)
+ continue;
+
+ ctrl = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+ /*
+ * One TALERT interrupt: Two sources
+ * If the interrupt is due to t_hot then mask t_hot and
+ * and unmask t_cold else mask t_cold and unmask t_hot
+ */
+ if (t_hot) {
+ ctrl &= ~tsr->mask_hot_mask;
+ ctrl |= tsr->mask_cold_mask;
+ } else if (t_cold) {
+ ctrl &= ~tsr->mask_cold_mask;
+ ctrl |= tsr->mask_hot_mask;
+ }
+
+ ti_bandgap_writel(bgp, ctrl, tsr->bgap_mask_ctrl);
+
+ dev_dbg(bgp->dev,
+ "%s: IRQ from %s sensor: hotevent %d coldevent %d\n",
+ __func__, bgp->conf->sensors[i].domain,
+ t_hot, t_cold);
+
+ /* report temperature to whom may concern */
+ if (bgp->conf->report_temperature)
+ bgp->conf->report_temperature(bgp, i);
+ }
+ spin_unlock(&bgp->lock);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ti_bandgap_tshut_irq_handler() - handles Temperature shutdown signal
+ * @irq: IRQ number
+ * @data: private data (unused)
+ *
+ * This is the Tshut handler. Use it only if bandgap device features
+ * HAS(TSHUT). If any sensor fires the Tshut signal, we simply shutdown
+ * the system.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t ti_bandgap_tshut_irq_handler(int irq, void *data)
+{
+ pr_emerg("%s: TSHUT temperature reached. Needs shut down...\n",
+ __func__);
+
+ orderly_poweroff(true);
+
+ return IRQ_HANDLED;
+}
+
+/*** Helper functions which manipulate conversion ADC <-> mi Celsius ***/
+
+/**
+ * ti_bandgap_adc_to_mcelsius() - converts an ADC value to mCelsius scale
+ * @bgp: struct ti_bandgap pointer
+ * @adc_val: value in ADC representation
+ * @t: address where to write the resulting temperature in mCelsius
+ *
+ * Simple conversion from ADC representation to mCelsius. In case the ADC value
+ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
+ * The conversion table is indexed by the ADC values.
+ *
+ * Return: 0 if conversion was successful, else -ERANGE in case the @adc_val
+ * argument is out of the ADC conv table range.
+ */
+static
+int ti_bandgap_adc_to_mcelsius(struct ti_bandgap *bgp, int adc_val, int *t)
+{
+ const struct ti_bandgap_data *conf = bgp->conf;
+ int ret = 0;
+
+ /* look up for temperature in the table and return the temperature */
+ if (adc_val < conf->adc_start_val || adc_val > conf->adc_end_val) {
+ ret = -ERANGE;
+ goto exit;
+ }
+
+ *t = bgp->conf->conv_table[adc_val - conf->adc_start_val];
+
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_mcelsius_to_adc() - converts a mCelsius value to ADC scale
+ * @bgp: struct ti_bandgap pointer
+ * @temp: value in mCelsius
+ * @adc: address where to write the resulting temperature in ADC representation
+ *
+ * Simple conversion from mCelsius to ADC values. In case the temp value
+ * is out of the ADC conv table range, it returns -ERANGE, 0 on success.
+ * The conversion table is indexed by the ADC values.
+ *
+ * Return: 0 if conversion was successful, else -ERANGE in case the @temp
+ * argument is out of the ADC conv table range.
+ */
+static
+int ti_bandgap_mcelsius_to_adc(struct ti_bandgap *bgp, long temp, int *adc)
+{
+ const struct ti_bandgap_data *conf = bgp->conf;
+ const int *conv_table = bgp->conf->conv_table;
+ int high, low, mid, ret = 0;
+
+ low = 0;
+ high = conf->adc_end_val - conf->adc_start_val;
+ mid = (high + low) / 2;
+
+ if (temp < conv_table[low] || temp > conv_table[high]) {
+ ret = -ERANGE;
+ goto exit;
+ }
+
+ while (low < high) {
+ if (temp < conv_table[mid])
+ high = mid - 1;
+ else
+ low = mid + 1;
+ mid = (low + high) / 2;
+ }
+
+ *adc = conf->adc_start_val + low;
+
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_add_hyst() - add hysteresis (in mCelsius) to an ADC value
+ * @bgp: struct ti_bandgap pointer
+ * @adc_val: temperature value in ADC representation
+ * @hyst_val: hysteresis value in mCelsius
+ * @sum: address where to write the resulting temperature (in ADC scale)
+ *
+ * Adds an hysteresis value (in mCelsius) to a ADC temperature value.
+ *
+ * Return: 0 on success, -ERANGE otherwise.
+ */
+static
+int ti_bandgap_add_hyst(struct ti_bandgap *bgp, int adc_val, int hyst_val,
+ u32 *sum)
+{
+ int temp, ret;
+
+ /*
+ * Need to add in the mcelsius domain, so we have a temperature
+ * the conv_table range
+ */
+ ret = ti_bandgap_adc_to_mcelsius(bgp, adc_val, &temp);
+ if (ret < 0)
+ goto exit;
+
+ temp += hyst_val;
+
+ ret = ti_bandgap_mcelsius_to_adc(bgp, temp, sum);
+
+exit:
+ return ret;
+}
+
+/*** Helper functions handling device Alert/Shutdown signals ***/
+
+/**
+ * ti_bandgap_unmask_interrupts() - unmasks the events of thot & tcold
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @t_hot: hot temperature value to trigger alert signal
+ * @t_cold: cold temperature value to trigger alert signal
+ *
+ * Checks the requested t_hot and t_cold values and configures the IRQ event
+ * masks accordingly. Call this function only if bandgap features HAS(TALERT).
+ */
+static void ti_bandgap_unmask_interrupts(struct ti_bandgap *bgp, int id,
+ u32 t_hot, u32 t_cold)
+{
+ struct temp_sensor_registers *tsr;
+ u32 temp, reg_val;
+
+ /* Read the current on die temperature */
+ temp = ti_bandgap_read_temp(bgp, id);
+
+ tsr = bgp->conf->sensors[id].registers;
+ reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+
+ if (temp < t_hot)
+ reg_val |= tsr->mask_hot_mask;
+ else
+ reg_val &= ~tsr->mask_hot_mask;
+
+ if (t_cold < temp)
+ reg_val |= tsr->mask_cold_mask;
+ else
+ reg_val &= ~tsr->mask_cold_mask;
+ ti_bandgap_writel(bgp, reg_val, tsr->bgap_mask_ctrl);
+}
+
+/**
+ * ti_bandgap_update_alert_threshold() - sequence to update thresholds
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (ADC) of a new threshold
+ * @hot: desired threshold to be updated. true if threshold hot, false if
+ * threshold cold
+ *
+ * It will program the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to update t_hot or t_cold, depending on @hot value.
+ * It checks the resulting t_hot and t_cold values, based on the new passed @val
+ * and configures the thresholds so that t_hot is always greater than t_cold.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, else corresponding error
+ */
+static int ti_bandgap_update_alert_threshold(struct ti_bandgap *bgp, int id,
+ int val, bool hot)
+{
+ struct temp_sensor_data *ts_data = bgp->conf->sensors[id].ts_data;
+ struct temp_sensor_registers *tsr;
+ u32 thresh_val, reg_val, t_hot, t_cold;
+ int err = 0;
+
+ tsr = bgp->conf->sensors[id].registers;
+
+ /* obtain the current value */
+ thresh_val = ti_bandgap_readl(bgp, tsr->bgap_threshold);
+ t_cold = (thresh_val & tsr->threshold_tcold_mask) >>
+ __ffs(tsr->threshold_tcold_mask);
+ t_hot = (thresh_val & tsr->threshold_thot_mask) >>
+ __ffs(tsr->threshold_thot_mask);
+ if (hot)
+ t_hot = val;
+ else
+ t_cold = val;
+
+ if (t_cold > t_hot) {
+ if (hot)
+ err = ti_bandgap_add_hyst(bgp, t_hot,
+ -ts_data->hyst_val,
+ &t_cold);
+ else
+ err = ti_bandgap_add_hyst(bgp, t_cold,
+ ts_data->hyst_val,
+ &t_hot);
+ }
+
+ /* write the new threshold values */
+ reg_val = thresh_val &
+ ~(tsr->threshold_thot_mask | tsr->threshold_tcold_mask);
+ reg_val |= (t_hot << __ffs(tsr->threshold_thot_mask)) |
+ (t_cold << __ffs(tsr->threshold_tcold_mask));
+ ti_bandgap_writel(bgp, reg_val, tsr->bgap_threshold);
+
+ if (err) {
+ dev_err(bgp->dev, "failed to reprogram thot threshold\n");
+ err = -EIO;
+ goto exit;
+ }
+
+ ti_bandgap_unmask_interrupts(bgp, id, t_hot, t_cold);
+exit:
+ return err;
+}
+
+/**
+ * ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ *
+ * Checks if the bandgap pointer is valid and if the sensor id is also
+ * applicable.
+ *
+ * Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
+ * @id cannot index @bgp sensors.
+ */
+static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
+{
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(bgp)) {
+ pr_err("%s: invalid bandgap pointer\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if ((id < 0) || (id >= bgp->conf->sensor_count)) {
+ dev_err(bgp->dev, "%s: sensor id out of range (%d)\n",
+ __func__, id);
+ ret = -ERANGE;
+ }
+
+exit:
+ return ret;
+}
+
+/**
+ * _ti_bandgap_write_threshold() - helper to update TALERT t_cold or t_hot
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (mCelsius) of a new threshold
+ * @hot: desired threshold to be updated. true if threshold hot, false if
+ * threshold cold
+ *
+ * It will update the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to update t_hot or t_cold, depending on @hot value.
+ * Validates the mCelsius range and update the requested threshold.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, else corresponding error value.
+ */
+static int _ti_bandgap_write_threshold(struct ti_bandgap *bgp, int id, int val,
+ bool hot)
+{
+ struct temp_sensor_data *ts_data;
+ struct temp_sensor_registers *tsr;
+ u32 adc_val;
+ int ret;
+
+ ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ goto exit;
+
+ if (!TI_BANDGAP_HAS(bgp, TALERT)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ ts_data = bgp->conf->sensors[id].ts_data;
+ tsr = bgp->conf->sensors[id].registers;
+ if (hot) {
+ if (val < ts_data->min_temp + ts_data->hyst_val)
+ ret = -EINVAL;
+ } else {
+ if (val > ts_data->max_temp + ts_data->hyst_val)
+ ret = -EINVAL;
+ }
+
+ if (ret)
+ goto exit;
+
+ ret = ti_bandgap_mcelsius_to_adc(bgp, val, &adc_val);
+ if (ret < 0)
+ goto exit;
+
+ spin_lock(&bgp->lock);
+ ret = ti_bandgap_update_alert_threshold(bgp, id, adc_val, hot);
+ spin_unlock(&bgp->lock);
+
+exit:
+ return ret;
+}
+
+/**
+ * _ti_bandgap_read_threshold() - helper to read TALERT t_cold or t_hot
+ * @bgp: struct ti_bandgap pointer
+ * @id: bandgap sensor id
+ * @val: value (mCelsius) of a threshold
+ * @hot: desired threshold to be read. true if threshold hot, false if
+ * threshold cold
+ *
+ * It will fetch the required thresholds (hot and cold) for TALERT signal.
+ * This function can be used to read t_hot or t_cold, depending on @hot value.
+ * Call this function only if bandgap features HAS(TALERT).
+ *
+ * Return: 0 if no error, -ENOTSUPP if it has no TALERT support, or the
+ * corresponding error value if some operation fails.
+ */
+static int _ti_bandgap_read_threshold(struct ti_bandgap *bgp, int id,
+ int *val, bool hot)
+{
+ struct temp_sensor_registers *tsr;
+ u32 temp, mask;
+ int ret = 0;
+
+ ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ goto exit;
+
+ if (!TI_BANDGAP_HAS(bgp, TALERT)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ tsr = bgp->conf->sensors[id].registers;
+ if (hot)
+ mask = tsr->threshold_thot_mask;
+ else
+ mask = tsr->threshold_tcold_mask;
+
+ temp = ti_bandgap_readl(bgp, tsr->bgap_threshold);
+ temp = (temp & mask) >> __ffs(mask);
+ ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
+ if (ret) {
+ dev_err(bgp->dev, "failed to read thot\n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ *val = temp;
+
+exit:
+ return ret;
+}
+
+/*** Exposed APIs ***/
+
+/**
+ * ti_bandgap_read_thot() - reads sensor current thot
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @thot: resulting current thot value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot)
+{
+ return _ti_bandgap_read_threshold(bgp, id, thot, true);
+}
+
+/**
+ * ti_bandgap_write_thot() - sets sensor current thot
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @val: desired thot value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val)
+{
+ return _ti_bandgap_write_threshold(bgp, id, val, true);
+}
+
+/**
+ * ti_bandgap_read_tcold() - reads sensor current tcold
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @tcold: resulting current tcold value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold)
+{
+ return _ti_bandgap_read_threshold(bgp, id, tcold, false);
+}
+
+/**
+ * ti_bandgap_write_tcold() - sets the sensor tcold
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @val: desired tcold value
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val)
+{
+ return _ti_bandgap_write_threshold(bgp, id, val, false);
+}
+
+/**
+ * ti_bandgap_read_counter() - read the sensor counter
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ */
+static void ti_bandgap_read_counter(struct ti_bandgap *bgp, int id,
+ int *interval)
+{
+ struct temp_sensor_registers *tsr;
+ int time;
+
+ tsr = bgp->conf->sensors[id].registers;
+ time = ti_bandgap_readl(bgp, tsr->bgap_counter);
+ time = (time & tsr->counter_mask) >>
+ __ffs(tsr->counter_mask);
+ time = time * 1000 / bgp->clk_rate;
+ *interval = time;
+}
+
+/**
+ * ti_bandgap_read_counter_delay() - read the sensor counter delay
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ */
+static void ti_bandgap_read_counter_delay(struct ti_bandgap *bgp, int id,
+ int *interval)
+{
+ struct temp_sensor_registers *tsr;
+ int reg_val;
+
+ tsr = bgp->conf->sensors[id].registers;
+
+ reg_val = ti_bandgap_readl(bgp, tsr->bgap_mask_ctrl);
+ reg_val = (reg_val & tsr->mask_counter_delay_mask) >>
+ __ffs(tsr->mask_counter_delay_mask);
+ switch (reg_val) {
+ case 0:
+ *interval = 0;
+ break;
+ case 1:
+ *interval = 1;
+ break;
+ case 2:
+ *interval = 10;
+ break;
+ case 3:
+ *interval = 100;
+ break;
+ case 4:
+ *interval = 250;
+ break;
+ case 5:
+ *interval = 500;
+ break;
+ default:
+ dev_warn(bgp->dev, "Wrong counter delay value read from register %X",
+ reg_val);
+ }
+}
+
+/**
+ * ti_bandgap_read_update_interval() - read the sensor update interval
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: resulting update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
+ int *interval)
+{
+ int ret = 0;
+
+ ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ goto exit;
+
+ if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
+ !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ if (TI_BANDGAP_HAS(bgp, COUNTER)) {
+ ti_bandgap_read_counter(bgp, id, interval);
+ goto exit;
+ }
+
+ ti_bandgap_read_counter_delay(bgp, id, interval);
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_write_counter_delay() - set the counter_delay
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+static int ti_bandgap_write_counter_delay(struct ti_bandgap *bgp, int id,
+ u32 interval)
+{
+ int rval;
+
+ switch (interval) {
+ case 0: /* Immediate conversion */
+ rval = 0x0;
+ break;
+ case 1: /* Conversion after ever 1ms */
+ rval = 0x1;
+ break;
+ case 10: /* Conversion after ever 10ms */
+ rval = 0x2;
+ break;
+ case 100: /* Conversion after ever 100ms */
+ rval = 0x3;
+ break;
+ case 250: /* Conversion after ever 250ms */
+ rval = 0x4;
+ break;
+ case 500: /* Conversion after ever 500ms */
+ rval = 0x5;
+ break;
+ default:
+ dev_warn(bgp->dev, "Delay %d ms is not supported\n", interval);
+ return -EINVAL;
+ }
+
+ spin_lock(&bgp->lock);
+ RMW_BITS(bgp, id, bgap_mask_ctrl, mask_counter_delay_mask, rval);
+ spin_unlock(&bgp->lock);
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_write_counter() - set the bandgap sensor counter
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ */
+static void ti_bandgap_write_counter(struct ti_bandgap *bgp, int id,
+ u32 interval)
+{
+ interval = interval * bgp->clk_rate / 1000;
+ spin_lock(&bgp->lock);
+ RMW_BITS(bgp, id, bgap_counter, counter_mask, interval);
+ spin_unlock(&bgp->lock);
+}
+
+/**
+ * ti_bandgap_write_update_interval() - set the update interval
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @interval: desired update interval in miliseconds
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_write_update_interval(struct ti_bandgap *bgp,
+ int id, u32 interval)
+{
+ int ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ goto exit;
+
+ if (!TI_BANDGAP_HAS(bgp, COUNTER) &&
+ !TI_BANDGAP_HAS(bgp, COUNTER_DELAY)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ if (TI_BANDGAP_HAS(bgp, COUNTER)) {
+ ti_bandgap_write_counter(bgp, id, interval);
+ goto exit;
+ }
+
+ ret = ti_bandgap_write_counter_delay(bgp, id, interval);
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_read_temperature() - report current temperature
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @temperature: resulting temperature
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
+ int *temperature)
+{
+ u32 temp;
+ int ret;
+
+ ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ return ret;
+
+ spin_lock(&bgp->lock);
+ temp = ti_bandgap_read_temp(bgp, id);
+ spin_unlock(&bgp->lock);
+
+ ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
+ if (ret)
+ return -EIO;
+
+ *temperature = temp;
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_set_sensor_data() - helper function to store thermal
+ * framework related data.
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ * @data: thermal framework related data to be stored
+ *
+ * Return: 0 on success or the proper error code
+ */
+int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data)
+{
+ int ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ return ret;
+
+ bgp->regval[id].data = data;
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_get_sensor_data() - helper function to get thermal
+ * framework related data.
+ * @bgp: pointer to bandgap instance
+ * @id: sensor id
+ *
+ * Return: data stored by set function with sensor id on success or NULL
+ */
+void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id)
+{
+ int ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return bgp->regval[id].data;
+}
+
+/*** Helper functions used during device initialization ***/
+
+/**
+ * ti_bandgap_force_single_read() - executes 1 single ADC conversion
+ * @bgp: pointer to struct ti_bandgap
+ * @id: sensor id which it is desired to read 1 temperature
+ *
+ * Used to initialize the conversion state machine and set it to a valid
+ * state. Called during device initialization and context restore events.
+ *
+ * Return: 0
+ */
+static int
+ti_bandgap_force_single_read(struct ti_bandgap *bgp, int id)
+{
+ u32 temp = 0, counter = 1000;
+
+ /* Select single conversion mode */
+ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+ RMW_BITS(bgp, id, bgap_mode_ctrl, mode_ctrl_mask, 0);
+
+ /* Start of Conversion = 1 */
+ RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 1);
+ /* Wait until DTEMP is updated */
+ temp = ti_bandgap_read_temp(bgp, id);
+
+ while ((temp == 0) && --counter)
+ temp = ti_bandgap_read_temp(bgp, id);
+ /* REVISIT: Check correct condition for end of conversion */
+
+ /* Start of Conversion = 0 */
+ RMW_BITS(bgp, id, temp_sensor_ctrl, bgap_soc_mask, 0);
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_set_continous_mode() - One time enabling of continuous mode
+ * @bgp: pointer to struct ti_bandgap
+ *
+ * Call this function only if HAS(MODE_CONFIG) is set. As this driver may
+ * be used for junction temperature monitoring, it is desirable that the
+ * sensors are operational all the time, so that alerts are generated
+ * properly.
+ *
+ * Return: 0
+ */
+static int ti_bandgap_set_continuous_mode(struct ti_bandgap *bgp)
+{
+ int i;
+
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ /* Perform a single read just before enabling continuous */
+ ti_bandgap_force_single_read(bgp, i);
+ RMW_BITS(bgp, i, bgap_mode_ctrl, mode_ctrl_mask, 1);
+ }
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_get_trend() - To fetch the temperature trend of a sensor
+ * @bgp: pointer to struct ti_bandgap
+ * @id: id of the individual sensor
+ * @trend: Pointer to trend.
+ *
+ * This function needs to be called to fetch the temperature trend of a
+ * Particular sensor. The function computes the difference in temperature
+ * w.r.t time. For the bandgaps with built in history buffer the temperatures
+ * are read from the buffer and for those without the Buffer -ENOTSUPP is
+ * returned.
+ *
+ * Return: 0 if no error, else return corresponding error. If no
+ * error then the trend value is passed on to trend parameter
+ */
+int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
+{
+ struct temp_sensor_registers *tsr;
+ u32 temp1, temp2, reg1, reg2;
+ int t1, t2, interval, ret = 0;
+
+ ret = ti_bandgap_validate(bgp, id);
+ if (ret)
+ goto exit;
+
+ if (!TI_BANDGAP_HAS(bgp, HISTORY_BUFFER) ||
+ !TI_BANDGAP_HAS(bgp, FREEZE_BIT)) {
+ ret = -ENOTSUPP;
+ goto exit;
+ }
+
+ tsr = bgp->conf->sensors[id].registers;
+
+ /* Freeze and read the last 2 valid readings */
+ reg1 = tsr->ctrl_dtemp_1;
+ reg2 = tsr->ctrl_dtemp_2;
+
+ /* read temperature from history buffer */
+ temp1 = ti_bandgap_readl(bgp, reg1);
+ temp1 &= tsr->bgap_dtemp_mask;
+
+ temp2 = ti_bandgap_readl(bgp, reg2);
+ temp2 &= tsr->bgap_dtemp_mask;
+
+ /* Convert from adc values to mCelsius temperature */
+ ret = ti_bandgap_adc_to_mcelsius(bgp, temp1, &t1);
+ if (ret)
+ goto exit;
+
+ ret = ti_bandgap_adc_to_mcelsius(bgp, temp2, &t2);
+ if (ret)
+ goto exit;
+
+ /* Fetch the update interval */
+ ret = ti_bandgap_read_update_interval(bgp, id, &interval);
+ if (ret || !interval)
+ goto exit;
+
+ *trend = (t1 - t2) / interval;
+
+ dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
+ t1, t2, *trend);
+
+exit:
+ return ret;
+}
+
+/**
+ * ti_bandgap_tshut_init() - setup and initialize tshut handling
+ * @bgp: pointer to struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Call this function only in case the bandgap features HAS(TSHUT).
+ * In this case, the driver needs to handle the TSHUT signal as an IRQ.
+ * The IRQ is wired as a GPIO, and for this purpose, it is required
+ * to specify which GPIO line is used. TSHUT IRQ is fired anytime
+ * one of the bandgap sensors violates the TSHUT high/hot threshold.
+ * And in that case, the system must go off.
+ *
+ * Return: 0 if no error, else error status
+ */
+static int ti_bandgap_tshut_init(struct ti_bandgap *bgp,
+ struct platform_device *pdev)
+{
+ int gpio_nr = bgp->tshut_gpio;
+ int status;
+
+ /* Request for gpio_86 line */
+ status = gpio_request(gpio_nr, "tshut");
+ if (status < 0) {
+ dev_err(bgp->dev, "Could not request for TSHUT GPIO:%i\n", 86);
+ return status;
+ }
+ status = gpio_direction_input(gpio_nr);
+ if (status) {
+ dev_err(bgp->dev, "Cannot set input TSHUT GPIO %d\n", gpio_nr);
+ return status;
+ }
+
+ status = request_irq(gpio_to_irq(gpio_nr), ti_bandgap_tshut_irq_handler,
+ IRQF_TRIGGER_RISING, "tshut", NULL);
+ if (status) {
+ gpio_free(gpio_nr);
+ dev_err(bgp->dev, "request irq failed for TSHUT");
+ }
+
+ return 0;
+}
+
+/**
+ * ti_bandgap_alert_init() - setup and initialize talert handling
+ * @bgp: pointer to struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Call this function only in case the bandgap features HAS(TALERT).
+ * In this case, the driver needs to handle the TALERT signals as an IRQs.
+ * TALERT is a normal IRQ and it is fired any time thresholds (hot or cold)
+ * are violated. In these situation, the driver must reprogram the thresholds,
+ * accordingly to specified policy.
+ *
+ * Return: 0 if no error, else return corresponding error.
+ */
+static int ti_bandgap_talert_init(struct ti_bandgap *bgp,
+ struct platform_device *pdev)
+{
+ int ret;
+
+ bgp->irq = platform_get_irq(pdev, 0);
+ if (bgp->irq < 0) {
+ dev_err(&pdev->dev, "get_irq failed\n");
+ return bgp->irq;
+ }
+ ret = request_threaded_irq(bgp->irq, NULL,
+ ti_bandgap_talert_irq_handler,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "talert", bgp);
+ if (ret) {
+ dev_err(&pdev->dev, "Request threaded irq failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_ti_bandgap_match[];
+/**
+ * ti_bandgap_build() - parse DT and setup a struct ti_bandgap
+ * @pdev: pointer to device struct platform_device
+ *
+ * Used to read the device tree properties accordingly to the bandgap
+ * matching version. Based on bandgap version and its capabilities it
+ * will build a struct ti_bandgap out of the required DT entries.
+ *
+ * Return: valid bandgap structure if successful, else returns ERR_PTR
+ * return value must be verified with IS_ERR.
+ */
+static struct ti_bandgap *ti_bandgap_build(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ const struct of_device_id *of_id;
+ struct ti_bandgap *bgp;
+ struct resource *res;
+ u32 prop;
+ int i;
+
+ /* just for the sake */
+ if (!node) {
+ dev_err(&pdev->dev, "no platform information available\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ bgp = devm_kzalloc(&pdev->dev, sizeof(*bgp), GFP_KERNEL);
+ if (!bgp) {
+ dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ of_id = of_match_device(of_ti_bandgap_match, &pdev->dev);
+ if (of_id)
+ bgp->conf = of_id->data;
+
+ /* register shadow for context save and restore */
+ bgp->regval = devm_kzalloc(&pdev->dev, sizeof(*bgp->regval) *
+ bgp->conf->sensor_count, GFP_KERNEL);
+ if (!bgp) {
+ dev_err(&pdev->dev, "Unable to allocate mem for driver ref\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ i = 0;
+ do {
+ void __iomem *chunk;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ break;
+ chunk = devm_ioremap_resource(&pdev->dev, res);
+ if (i == 0)
+ bgp->base = chunk;
+ if (IS_ERR(chunk))
+ return ERR_CAST(chunk);
+
+ i++;
+ } while (res);
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+ if (of_property_read_u32(node, "ti,tshut-gpio", &prop) < 0) {
+ dev_err(&pdev->dev, "missing tshut gpio in device tree\n");
+ return ERR_PTR(-EINVAL);
+ }
+ bgp->tshut_gpio = prop;
+ if (!gpio_is_valid(bgp->tshut_gpio)) {
+ dev_err(&pdev->dev, "invalid gpio for tshut (%d)\n",
+ bgp->tshut_gpio);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ return bgp;
+}
+
+/*** Device driver call backs ***/
+
+static
+int ti_bandgap_probe(struct platform_device *pdev)
+{
+ struct ti_bandgap *bgp;
+ int clk_rate, ret = 0, i;
+
+ bgp = ti_bandgap_build(pdev);
+ if (IS_ERR_OR_NULL(bgp)) {
+ dev_err(&pdev->dev, "failed to fetch platform data\n");
+ return PTR_ERR(bgp);
+ }
+ bgp->dev = &pdev->dev;
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+ ret = ti_bandgap_tshut_init(bgp, pdev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to initialize system tshut IRQ\n");
+ return ret;
+ }
+ }
+
+ bgp->fclock = clk_get(NULL, bgp->conf->fclock_name);
+ ret = IS_ERR_OR_NULL(bgp->fclock);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request fclock reference\n");
+ goto free_irqs;
+ }
+
+ bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name);
+ ret = IS_ERR_OR_NULL(bgp->div_clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to request div_ts_ck clock ref\n");
+ goto free_irqs;
+ }
+
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ struct temp_sensor_registers *tsr;
+ u32 val;
+
+ tsr = bgp->conf->sensors[i].registers;
+ /*
+ * check if the efuse has a non-zero value if not
+ * it is an untrimmed sample and the temperatures
+ * may not be accurate
+ */
+ val = ti_bandgap_readl(bgp, tsr->bgap_efuse);
+ if (ret || !val)
+ dev_info(&pdev->dev,
+ "Non-trimmed BGAP, Temp not accurate\n");
+ }
+
+ clk_rate = clk_round_rate(bgp->div_clk,
+ bgp->conf->sensors[0].ts_data->max_freq);
+ if (clk_rate < bgp->conf->sensors[0].ts_data->min_freq ||
+ clk_rate == 0xffffffff) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "wrong clock rate (%d)\n", clk_rate);
+ goto put_clks;
+ }
+
+ ret = clk_set_rate(bgp->div_clk, clk_rate);
+ if (ret)
+ dev_err(&pdev->dev, "Cannot re-set clock rate. Continuing\n");
+
+ bgp->clk_rate = clk_rate;
+ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+ clk_prepare_enable(bgp->fclock);
+
+
+ spin_lock_init(&bgp->lock);
+ bgp->dev = &pdev->dev;
+ platform_set_drvdata(pdev, bgp);
+
+ ti_bandgap_power(bgp, true);
+
+ /* Set default counter to 1 for now */
+ if (TI_BANDGAP_HAS(bgp, COUNTER))
+ for (i = 0; i < bgp->conf->sensor_count; i++)
+ RMW_BITS(bgp, i, bgap_counter, counter_mask, 1);
+
+ /* Set default thresholds for alert and shutdown */
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ struct temp_sensor_data *ts_data;
+
+ ts_data = bgp->conf->sensors[i].ts_data;
+
+ if (TI_BANDGAP_HAS(bgp, TALERT)) {
+ /* Set initial Talert thresholds */
+ RMW_BITS(bgp, i, bgap_threshold,
+ threshold_tcold_mask, ts_data->t_cold);
+ RMW_BITS(bgp, i, bgap_threshold,
+ threshold_thot_mask, ts_data->t_hot);
+ /* Enable the alert events */
+ RMW_BITS(bgp, i, bgap_mask_ctrl, mask_hot_mask, 1);
+ RMW_BITS(bgp, i, bgap_mask_ctrl, mask_cold_mask, 1);
+ }
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG)) {
+ /* Set initial Tshut thresholds */
+ RMW_BITS(bgp, i, tshut_threshold,
+ tshut_hot_mask, ts_data->tshut_hot);
+ RMW_BITS(bgp, i, tshut_threshold,
+ tshut_cold_mask, ts_data->tshut_cold);
+ }
+ }
+
+ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+ ti_bandgap_set_continuous_mode(bgp);
+
+ /* Set .250 seconds time as default counter */
+ if (TI_BANDGAP_HAS(bgp, COUNTER))
+ for (i = 0; i < bgp->conf->sensor_count; i++)
+ RMW_BITS(bgp, i, bgap_counter, counter_mask,
+ bgp->clk_rate / 4);
+
+ /* Every thing is good? Then expose the sensors */
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ char *domain;
+
+ if (bgp->conf->sensors[i].register_cooling) {
+ ret = bgp->conf->sensors[i].register_cooling(bgp, i);
+ if (ret)
+ goto remove_sensors;
+ }
+
+ if (bgp->conf->expose_sensor) {
+ domain = bgp->conf->sensors[i].domain;
+ ret = bgp->conf->expose_sensor(bgp, i, domain);
+ if (ret)
+ goto remove_last_cooling;
+ }
+ }
+
+ /*
+ * Enable the Interrupts once everything is set. Otherwise irq handler
+ * might be called as soon as it is enabled where as rest of framework
+ * is still getting initialised.
+ */
+ if (TI_BANDGAP_HAS(bgp, TALERT)) {
+ ret = ti_bandgap_talert_init(bgp, pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize Talert IRQ\n");
+ i = bgp->conf->sensor_count;
+ goto disable_clk;
+ }
+ }
+
+ return 0;
+
+remove_last_cooling:
+ if (bgp->conf->sensors[i].unregister_cooling)
+ bgp->conf->sensors[i].unregister_cooling(bgp, i);
+remove_sensors:
+ for (i--; i >= 0; i--) {
+ if (bgp->conf->sensors[i].unregister_cooling)
+ bgp->conf->sensors[i].unregister_cooling(bgp, i);
+ if (bgp->conf->remove_sensor)
+ bgp->conf->remove_sensor(bgp, i);
+ }
+ ti_bandgap_power(bgp, false);
+disable_clk:
+ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+ clk_disable_unprepare(bgp->fclock);
+put_clks:
+ clk_put(bgp->fclock);
+ clk_put(bgp->div_clk);
+free_irqs:
+ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+ free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
+ gpio_free(bgp->tshut_gpio);
+ }
+
+ return ret;
+}
+
+static
+int ti_bandgap_remove(struct platform_device *pdev)
+{
+ struct ti_bandgap *bgp = platform_get_drvdata(pdev);
+ int i;
+
+ /* First thing is to remove sensor interfaces */
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ if (bgp->conf->sensors[i].unregister_cooling)
+ bgp->conf->sensors[i].unregister_cooling(bgp, i);
+
+ if (bgp->conf->remove_sensor)
+ bgp->conf->remove_sensor(bgp, i);
+ }
+
+ ti_bandgap_power(bgp, false);
+
+ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+ clk_disable_unprepare(bgp->fclock);
+ clk_put(bgp->fclock);
+ clk_put(bgp->div_clk);
+
+ if (TI_BANDGAP_HAS(bgp, TALERT))
+ free_irq(bgp->irq, bgp);
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT)) {
+ free_irq(gpio_to_irq(bgp->tshut_gpio), NULL);
+ gpio_free(bgp->tshut_gpio);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ti_bandgap_save_ctxt(struct ti_bandgap *bgp)
+{
+ int i;
+
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ struct temp_sensor_registers *tsr;
+ struct temp_sensor_regval *rval;
+
+ rval = &bgp->regval[i];
+ tsr = bgp->conf->sensors[i].registers;
+
+ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+ rval->bg_mode_ctrl = ti_bandgap_readl(bgp,
+ tsr->bgap_mode_ctrl);
+ if (TI_BANDGAP_HAS(bgp, COUNTER))
+ rval->bg_counter = ti_bandgap_readl(bgp,
+ tsr->bgap_counter);
+ if (TI_BANDGAP_HAS(bgp, TALERT)) {
+ rval->bg_threshold = ti_bandgap_readl(bgp,
+ tsr->bgap_threshold);
+ rval->bg_ctrl = ti_bandgap_readl(bgp,
+ tsr->bgap_mask_ctrl);
+ }
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
+ rval->tshut_threshold = ti_bandgap_readl(bgp,
+ tsr->tshut_threshold);
+ }
+
+ return 0;
+}
+
+static int ti_bandgap_restore_ctxt(struct ti_bandgap *bgp)
+{
+ int i;
+
+ for (i = 0; i < bgp->conf->sensor_count; i++) {
+ struct temp_sensor_registers *tsr;
+ struct temp_sensor_regval *rval;
+ u32 val = 0;
+
+ rval = &bgp->regval[i];
+ tsr = bgp->conf->sensors[i].registers;
+
+ if (TI_BANDGAP_HAS(bgp, COUNTER))
+ val = ti_bandgap_readl(bgp, tsr->bgap_counter);
+
+ if (TI_BANDGAP_HAS(bgp, TSHUT_CONFIG))
+ ti_bandgap_writel(bgp, rval->tshut_threshold,
+ tsr->tshut_threshold);
+ /* Force immediate temperature measurement and update
+ * of the DTEMP field
+ */
+ ti_bandgap_force_single_read(bgp, i);
+
+ if (TI_BANDGAP_HAS(bgp, COUNTER))
+ ti_bandgap_writel(bgp, rval->bg_counter,
+ tsr->bgap_counter);
+ if (TI_BANDGAP_HAS(bgp, MODE_CONFIG))
+ ti_bandgap_writel(bgp, rval->bg_mode_ctrl,
+ tsr->bgap_mode_ctrl);
+ if (TI_BANDGAP_HAS(bgp, TALERT)) {
+ ti_bandgap_writel(bgp, rval->bg_threshold,
+ tsr->bgap_threshold);
+ ti_bandgap_writel(bgp, rval->bg_ctrl,
+ tsr->bgap_mask_ctrl);
+ }
+ }
+
+ return 0;
+}
+
+static int ti_bandgap_suspend(struct device *dev)
+{
+ struct ti_bandgap *bgp = dev_get_drvdata(dev);
+ int err;
+
+ err = ti_bandgap_save_ctxt(bgp);
+ ti_bandgap_power(bgp, false);
+
+ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+ clk_disable_unprepare(bgp->fclock);
+
+ return err;
+}
+
+static int ti_bandgap_resume(struct device *dev)
+{
+ struct ti_bandgap *bgp = dev_get_drvdata(dev);
+
+ if (TI_BANDGAP_HAS(bgp, CLK_CTRL))
+ clk_prepare_enable(bgp->fclock);
+
+ ti_bandgap_power(bgp, true);
+
+ return ti_bandgap_restore_ctxt(bgp);
+}
+static const struct dev_pm_ops ti_bandgap_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend,
+ ti_bandgap_resume)
+};
+
+#define DEV_PM_OPS (&ti_bandgap_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif
+
+static const struct of_device_id of_ti_bandgap_match[] = {
+#ifdef CONFIG_OMAP4_THERMAL
+ {
+ .compatible = "ti,omap4430-bandgap",
+ .data = (void *)&omap4430_data,
+ },
+ {
+ .compatible = "ti,omap4460-bandgap",
+ .data = (void *)&omap4460_data,
+ },
+ {
+ .compatible = "ti,omap4470-bandgap",
+ .data = (void *)&omap4470_data,
+ },
+#endif
+#ifdef CONFIG_OMAP5_THERMAL
+ {
+ .compatible = "ti,omap5430-bandgap",
+ .data = (void *)&omap5430_data,
+ },
+#endif
+ /* Sentinel */
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
+
+static struct platform_driver ti_bandgap_sensor_driver = {
+ .probe = ti_bandgap_probe,
+ .remove = ti_bandgap_remove,
+ .driver = {
+ .name = "ti-soc-thermal",
+ .pm = DEV_PM_OPS,
+ .of_match_table = of_ti_bandgap_match,
+ },
+};
+
+module_platform_driver(ti_bandgap_sensor_driver);
+
+MODULE_DESCRIPTION("OMAP4+ bandgap temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ti-soc-thermal");
+MODULE_AUTHOR("Texas Instrument Inc.");
diff --git a/drivers/staging/ti-soc-thermal/ti-bandgap.h b/drivers/staging/ti-soc-thermal/ti-bandgap.h
new file mode 100644
index 000000000000..5f4794abf583
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/ti-bandgap.h
@@ -0,0 +1,403 @@
+/*
+ * OMAP4 Bandgap temperature sensor driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@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
+ *
+ */
+#ifndef __TI_BANDGAP_H
+#define __TI_BANDGAP_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/err.h>
+
+/**
+ * DOC: bandgap driver data structure
+ * ==================================
+ *
+ * +----------+----------------+
+ * | struct temp_sensor_regval |
+ * +---------------------------+
+ * * (Array of)
+ * |
+ * |
+ * +-------------------+ +-----------------+
+ * | struct ti_bandgap |-->| struct device * |
+ * +----------+--------+ +-----------------+
+ * |
+ * |
+ * V
+ * +------------------------+
+ * | struct ti_bandgap_data |
+ * +------------------------+
+ * |
+ * |
+ * * (Array of)
+ * +------------+------------------------------------------------------+
+ * | +----------+------------+ +-------------------------+ |
+ * | | struct ti_temp_sensor |-->| struct temp_sensor_data | |
+ * | +-----------------------+ +------------+------------+ |
+ * | | |
+ * | + |
+ * | V |
+ * | +----------+-------------------+ |
+ * | | struct temp_sensor_registers | |
+ * | +------------------------------+ |
+ * | |
+ * +-------------------------------------------------------------------+
+ *
+ * Above is a simple diagram describing how the data structure below
+ * are organized. For each bandgap device there should be a ti_bandgap_data
+ * containing the device instance configuration, as well as, an array of
+ * sensors, representing every sensor instance present in this bandgap.
+ */
+
+/**
+ * struct temp_sensor_registers - descriptor to access registers and bitfields
+ * @temp_sensor_ctrl: TEMP_SENSOR_CTRL register offset
+ * @bgap_tempsoff_mask: mask to temp_sensor_ctrl.tempsoff
+ * @bgap_soc_mask: mask to temp_sensor_ctrl.soc
+ * @bgap_eocz_mask: mask to temp_sensor_ctrl.eocz
+ * @bgap_dtemp_mask: mask to temp_sensor_ctrl.dtemp
+ * @bgap_mask_ctrl: BANDGAP_MASK_CTRL register offset
+ * @mask_hot_mask: mask to bandgap_mask_ctrl.mask_hot
+ * @mask_cold_mask: mask to bandgap_mask_ctrl.mask_cold
+ * @mask_sidlemode_mask: mask to bandgap_mask_ctrl.mask_sidlemode
+ * @mask_counter_delay_mask: mask to bandgap_mask_ctrl.mask_counter_delay
+ * @mask_freeze_mask: mask to bandgap_mask_ctrl.mask_free
+ * @mask_clear_mask: mask to bandgap_mask_ctrl.mask_clear
+ * @mask_clear_accum_mask: mask to bandgap_mask_ctrl.mask_clear_accum
+ * @bgap_mode_ctrl: BANDGAP_MODE_CTRL register offset
+ * @mode_ctrl_mask: mask to bandgap_mode_ctrl.mode_ctrl
+ * @bgap_counter: BANDGAP_COUNTER register offset
+ * @counter_mask: mask to bandgap_counter.counter
+ * @bgap_threshold: BANDGAP_THRESHOLD register offset (TALERT thresholds)
+ * @threshold_thot_mask: mask to bandgap_threhold.thot
+ * @threshold_tcold_mask: mask to bandgap_threhold.tcold
+ * @tshut_threshold: TSHUT_THRESHOLD register offset (TSHUT thresholds)
+ * @tshut_efuse_mask: mask to tshut_threshold.tshut_efuse
+ * @tshut_efuse_shift: shift to tshut_threshold.tshut_efuse
+ * @tshut_hot_mask: mask to tshut_threhold.thot
+ * @tshut_cold_mask: mask to tshut_threhold.thot
+ * @bgap_status: BANDGAP_STATUS register offset
+ * @status_clean_stop_mask: mask to bandgap_status.clean_stop
+ * @status_bgap_alert_mask: mask to bandgap_status.bandgap_alert
+ * @status_hot_mask: mask to bandgap_status.hot
+ * @status_cold_mask: mask to bandgap_status.cold
+ * @bgap_cumul_dtemp: BANDGAP_CUMUL_DTEMP register offset
+ * @ctrl_dtemp_0: CTRL_DTEMP0 register offset
+ * @ctrl_dtemp_1: CTRL_DTEMP1 register offset
+ * @ctrl_dtemp_2: CTRL_DTEMP2 register offset
+ * @ctrl_dtemp_3: CTRL_DTEMP3 register offset
+ * @ctrl_dtemp_4: CTRL_DTEMP4 register offset
+ * @bgap_efuse: BANDGAP_EFUSE register offset
+ *
+ * The register offsets and bitfields might change across
+ * OMAP and variants versions. Hence this struct serves as a
+ * descriptor map on how to access the registers and the bitfields.
+ *
+ * This descriptor contains registers of all versions of bandgap chips.
+ * Not all versions will use all registers, depending on the available
+ * features. Please read TRMs for descriptive explanation on each bitfield.
+ */
+
+struct temp_sensor_registers {
+ u32 temp_sensor_ctrl;
+ u32 bgap_tempsoff_mask;
+ u32 bgap_soc_mask;
+ u32 bgap_eocz_mask; /* not used: but needs revisit */
+ u32 bgap_dtemp_mask;
+
+ u32 bgap_mask_ctrl;
+ u32 mask_hot_mask;
+ u32 mask_cold_mask;
+ u32 mask_sidlemode_mask; /* not used: but may be needed for pm */
+ u32 mask_counter_delay_mask;
+ u32 mask_freeze_mask;
+ u32 mask_clear_mask; /* not used: but needed for trending */
+ u32 mask_clear_accum_mask; /* not used: but needed for trending */
+
+ u32 bgap_mode_ctrl;
+ u32 mode_ctrl_mask;
+
+ u32 bgap_counter;
+ u32 counter_mask;
+
+ u32 bgap_threshold;
+ u32 threshold_thot_mask;
+ u32 threshold_tcold_mask;
+
+ u32 tshut_threshold;
+ u32 tshut_efuse_mask; /* not used */
+ u32 tshut_efuse_shift; /* not used */
+ u32 tshut_hot_mask;
+ u32 tshut_cold_mask;
+
+ u32 bgap_status;
+ u32 status_clean_stop_mask; /* not used: but needed for trending */
+ u32 status_bgap_alert_mask; /* not used */
+ u32 status_hot_mask;
+ u32 status_cold_mask;
+
+ u32 bgap_cumul_dtemp; /* not used: but needed for trending */
+ u32 ctrl_dtemp_0; /* not used: but needed for trending */
+ u32 ctrl_dtemp_1; /* not used: but needed for trending */
+ u32 ctrl_dtemp_2; /* not used: but needed for trending */
+ u32 ctrl_dtemp_3; /* not used: but needed for trending */
+ u32 ctrl_dtemp_4; /* not used: but needed for trending */
+ u32 bgap_efuse;
+};
+
+/**
+ * struct temp_sensor_data - The thresholds and limits for temperature sensors.
+ * @tshut_hot: temperature to trigger a thermal reset (initial value)
+ * @tshut_cold: temp to get the plat out of reset due to thermal (init val)
+ * @t_hot: temperature to trigger a thermal alert (high initial value)
+ * @t_cold: temperature to trigger a thermal alert (low initial value)
+ * @min_freq: sensor minimum clock rate
+ * @max_freq: sensor maximum clock rate
+ * @max_temp: sensor maximum temperature
+ * @min_temp: sensor minimum temperature
+ * @hyst_val: temperature hysteresis considered while converting ADC values
+ * @update_int1: update interval
+ * @update_int2: update interval
+ *
+ * This data structure will hold the required thresholds and temperature limits
+ * for a specific temperature sensor, like shutdown temperature, alert
+ * temperature, clock / rate used, ADC conversion limits and update intervals
+ */
+struct temp_sensor_data {
+ u32 tshut_hot;
+ u32 tshut_cold;
+ u32 t_hot;
+ u32 t_cold;
+ u32 min_freq;
+ u32 max_freq;
+ int max_temp;
+ int min_temp;
+ int hyst_val;
+ u32 update_int1; /* not used */
+ u32 update_int2; /* not used */
+};
+
+struct ti_bandgap_data;
+
+/**
+ * struct temp_sensor_regval - temperature sensor register values and priv data
+ * @bg_mode_ctrl: temp sensor control register value
+ * @bg_ctrl: bandgap ctrl register value
+ * @bg_counter: bandgap counter value
+ * @bg_threshold: bandgap threshold register value
+ * @tshut_threshold: bandgap tshut register value
+ * @data: private data
+ *
+ * Data structure to save and restore bandgap register set context. Only
+ * required registers are shadowed, when needed.
+ */
+struct temp_sensor_regval {
+ u32 bg_mode_ctrl;
+ u32 bg_ctrl;
+ u32 bg_counter;
+ u32 bg_threshold;
+ u32 tshut_threshold;
+ void *data;
+};
+
+/**
+ * struct ti_bandgap - bandgap device structure
+ * @dev: struct device pointer
+ * @base: io memory base address
+ * @conf: struct with bandgap configuration set (# sensors, conv_table, etc)
+ * @regval: temperature sensor register values
+ * @fclock: pointer to functional clock of temperature sensor
+ * @div_clk: pointer to divider clock of temperature sensor fclk
+ * @lock: spinlock for ti_bandgap structure
+ * @irq: MPU IRQ number for thermal alert
+ * @tshut_gpio: GPIO where Tshut signal is routed
+ * @clk_rate: Holds current clock rate
+ *
+ * The bandgap device structure representing the bandgap device instance.
+ * It holds most of the dynamic stuff. Configurations and sensor specific
+ * entries are inside the @conf structure.
+ */
+struct ti_bandgap {
+ struct device *dev;
+ void __iomem *base;
+ const struct ti_bandgap_data *conf;
+ struct temp_sensor_regval *regval;
+ struct clk *fclock;
+ struct clk *div_clk;
+ spinlock_t lock; /* shields this struct */
+ int irq;
+ int tshut_gpio;
+ u32 clk_rate;
+};
+
+/**
+ * struct ti_temp_sensor - bandgap temperature sensor configuration data
+ * @ts_data: pointer to struct with thresholds, limits of temperature sensor
+ * @registers: pointer to the list of register offsets and bitfields
+ * @domain: the name of the domain where the sensor is located
+ * @slope: sensor gradient slope info for hotspot extrapolation equation
+ * @constant: sensor gradient const info for hotspot extrapolation equation
+ * @slope_pcb: sensor gradient slope info for hotspot extrapolation equation
+ * with no external influence
+ * @constant_pcb: sensor gradient const info for hotspot extrapolation equation
+ * with no external influence
+ * @register_cooling: function to describe how this sensor is going to be cooled
+ * @unregister_cooling: function to release cooling data
+ *
+ * Data structure to describe a temperature sensor handled by a bandgap device.
+ * It should provide configuration details on this sensor, such as how to
+ * access the registers affecting this sensor, shadow register buffer, how to
+ * assess the gradient from hotspot, how to cooldown the domain when sensor
+ * reports too hot temperature.
+ */
+struct ti_temp_sensor {
+ struct temp_sensor_data *ts_data;
+ struct temp_sensor_registers *registers;
+ char *domain;
+ /* for hotspot extrapolation */
+ const int slope;
+ const int constant;
+ const int slope_pcb;
+ const int constant_pcb;
+ int (*register_cooling)(struct ti_bandgap *bgp, int id);
+ int (*unregister_cooling)(struct ti_bandgap *bgp, int id);
+};
+
+/**
+ * DOC: ti bandgap feature types
+ *
+ * TI_BANDGAP_FEATURE_TSHUT - used when the thermal shutdown signal output
+ * of a bandgap device instance is routed to the processor. This means
+ * the system must react and perform the shutdown by itself (handle an
+ * IRQ, for instance).
+ *
+ * TI_BANDGAP_FEATURE_TSHUT_CONFIG - used when the bandgap device has control
+ * over the thermal shutdown configuration. This means that the thermal
+ * shutdown thresholds are programmable, for instance.
+ *
+ * TI_BANDGAP_FEATURE_TALERT - used when the bandgap device instance outputs
+ * a signal representing violation of programmable alert thresholds.
+ *
+ * TI_BANDGAP_FEATURE_MODE_CONFIG - used when it is possible to choose which
+ * mode, continuous or one shot, the bandgap device instance will operate.
+ *
+ * TI_BANDGAP_FEATURE_COUNTER - used when the bandgap device instance allows
+ * programming the update interval of its internal state machine.
+ *
+ * TI_BANDGAP_FEATURE_POWER_SWITCH - used when the bandgap device allows
+ * itself to be switched on/off.
+ *
+ * TI_BANDGAP_FEATURE_CLK_CTRL - used when the clocks feeding the bandgap
+ * device are gateable or not.
+ *
+ * TI_BANDGAP_FEATURE_FREEZE_BIT - used when the bandgap device features
+ * a history buffer that its update can be freezed/unfreezed.
+ *
+ * TI_BANDGAP_FEATURE_COUNTER_DELAY - used when the bandgap device features
+ * a delay programming based on distinct values.
+ *
+ * TI_BANDGAP_FEATURE_HISTORY_BUFFER - used when the bandgap device features
+ * a history buffer of temperatures.
+ *
+ * TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a
+ * specific feature (above) or not. Return non-zero, if yes.
+ */
+#define TI_BANDGAP_FEATURE_TSHUT BIT(0)
+#define TI_BANDGAP_FEATURE_TSHUT_CONFIG BIT(1)
+#define TI_BANDGAP_FEATURE_TALERT BIT(2)
+#define TI_BANDGAP_FEATURE_MODE_CONFIG BIT(3)
+#define TI_BANDGAP_FEATURE_COUNTER BIT(4)
+#define TI_BANDGAP_FEATURE_POWER_SWITCH BIT(5)
+#define TI_BANDGAP_FEATURE_CLK_CTRL BIT(6)
+#define TI_BANDGAP_FEATURE_FREEZE_BIT BIT(7)
+#define TI_BANDGAP_FEATURE_COUNTER_DELAY BIT(8)
+#define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9)
+#define TI_BANDGAP_HAS(b, f) \
+ ((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
+
+/**
+ * struct ti_bandgap_data - ti bandgap data configuration structure
+ * @features: a bitwise flag set to describe the device features
+ * @conv_table: Pointer to ADC to temperature conversion table
+ * @adc_start_val: ADC conversion table starting value
+ * @adc_end_val: ADC conversion table ending value
+ * @fclock_name: clock name of the functional clock
+ * @div_ck_name: clock name of the clock divisor
+ * @sensor_count: count of temperature sensor within this bandgap device
+ * @report_temperature: callback to report thermal alert to thermal API
+ * @expose_sensor: callback to export sensor to thermal API
+ * @remove_sensor: callback to destroy sensor from thermal API
+ * @sensors: array of sensors present in this bandgap instance
+ *
+ * This is a data structure which should hold most of the static configuration
+ * of a bandgap device instance. It should describe which features this instance
+ * is capable of, the clock names to feed this device, the amount of sensors and
+ * their configuration representation, and how to export and unexport them to
+ * a thermal API.
+ */
+struct ti_bandgap_data {
+ unsigned int features;
+ const int *conv_table;
+ u32 adc_start_val;
+ u32 adc_end_val;
+ char *fclock_name;
+ char *div_ck_name;
+ int sensor_count;
+ int (*report_temperature)(struct ti_bandgap *bgp, int id);
+ int (*expose_sensor)(struct ti_bandgap *bgp, int id, char *domain);
+ int (*remove_sensor)(struct ti_bandgap *bgp, int id);
+
+ /* this needs to be at the end */
+ struct ti_temp_sensor sensors[];
+};
+
+int ti_bandgap_read_thot(struct ti_bandgap *bgp, int id, int *thot);
+int ti_bandgap_write_thot(struct ti_bandgap *bgp, int id, int val);
+int ti_bandgap_read_tcold(struct ti_bandgap *bgp, int id, int *tcold);
+int ti_bandgap_write_tcold(struct ti_bandgap *bgp, int id, int val);
+int ti_bandgap_read_update_interval(struct ti_bandgap *bgp, int id,
+ int *interval);
+int ti_bandgap_write_update_interval(struct ti_bandgap *bgp, int id,
+ u32 interval);
+int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
+ int *temperature);
+int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data);
+void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id);
+int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend);
+
+#ifdef CONFIG_OMAP4_THERMAL
+extern const struct ti_bandgap_data omap4430_data;
+extern const struct ti_bandgap_data omap4460_data;
+extern const struct ti_bandgap_data omap4470_data;
+#else
+#define omap4430_data NULL
+#define omap4460_data NULL
+#define omap4470_data NULL
+#endif
+
+#ifdef CONFIG_OMAP5_THERMAL
+extern const struct ti_bandgap_data omap5430_data;
+#else
+#define omap5430_data NULL
+#endif
+
+#endif
diff --git a/drivers/staging/ti-soc-thermal/ti-thermal-common.c b/drivers/staging/ti-soc-thermal/ti-thermal-common.c
new file mode 100644
index 000000000000..e3c5e677eaa5
--- /dev/null
+++ b/drivers/staging/ti-soc-thermal/ti-thermal-common.c
@@ -0,0 +1,367 @@
+/*
+ * OMAP thermal driver interface
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Contact:
+ * Eduardo Valentin <eduardo.valentin@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/device.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+#include <linux/thermal.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_cooling.h>
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+
+/* common data structures */
+struct ti_thermal_data {
+ struct thermal_zone_device *ti_thermal;
+ struct thermal_cooling_device *cool_dev;
+ struct ti_bandgap *bgp;
+ enum thermal_device_mode mode;
+ struct work_struct thermal_wq;
+ int sensor_id;
+};
+
+static void ti_thermal_work(struct work_struct *work)
+{
+ struct ti_thermal_data *data = container_of(work,
+ struct ti_thermal_data, thermal_wq);
+
+ thermal_zone_device_update(data->ti_thermal);
+
+ dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n",
+ data->ti_thermal->type);
+}
+
+/**
+ * ti_thermal_hotspot_temperature - returns sensor extrapolated temperature
+ * @t: omap sensor temperature
+ * @s: omap sensor slope value
+ * @c: omap sensor const value
+ */
+static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
+{
+ int delta = t * s / 1000 + c;
+
+ if (delta < 0)
+ delta = 0;
+
+ return t + delta;
+}
+
+/* thermal zone ops */
+/* Get temperature callback function for thermal zone*/
+static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+ struct ti_bandgap *bgp;
+ const struct ti_temp_sensor *s;
+ int ret, tmp, pcb_temp, slope, constant;
+
+ if (!data)
+ return 0;
+
+ bgp = data->bgp;
+ s = &bgp->conf->sensors[data->sensor_id];
+
+ ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp);
+ if (ret)
+ return ret;
+
+ pcb_temp = 0;
+ /* TODO: Introduce pcb temperature lookup */
+ /* In case pcb zone is available, use the extrapolation rule with it */
+ if (pcb_temp) {
+ tmp -= pcb_temp;
+ slope = s->slope_pcb;
+ constant = s->constant_pcb;
+ } else {
+ slope = s->slope;
+ constant = s->constant;
+ }
+ *temp = ti_thermal_hotspot_temperature(tmp, slope, constant);
+
+ return ret;
+}
+
+/* Bind callback functions for thermal zone */
+static int ti_thermal_bind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+ int id;
+
+ if (IS_ERR_OR_NULL(data))
+ return -ENODEV;
+
+ /* check if this is the cooling device we registered */
+ if (data->cool_dev != cdev)
+ return 0;
+
+ id = data->sensor_id;
+
+ /* Simple thing, two trips, one passive another critical */
+ return thermal_zone_bind_cooling_device(thermal, 0, cdev,
+ /* bind with min and max states defined by cpu_cooling */
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT);
+}
+
+/* Unbind callback functions for thermal zone */
+static int ti_thermal_unbind(struct thermal_zone_device *thermal,
+ struct thermal_cooling_device *cdev)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+
+ if (IS_ERR_OR_NULL(data))
+ return -ENODEV;
+
+ /* check if this is the cooling device we registered */
+ if (data->cool_dev != cdev)
+ return 0;
+
+ /* Simple thing, two trips, one passive another critical */
+ return thermal_zone_unbind_cooling_device(thermal, 0, cdev);
+}
+
+/* Get mode callback functions for thermal zone */
+static int ti_thermal_get_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode *mode)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+
+ if (data)
+ *mode = data->mode;
+
+ return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
+ enum thermal_device_mode mode)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+
+ if (!data->ti_thermal) {
+ dev_notice(&thermal->device, "thermal zone not registered\n");
+ return 0;
+ }
+
+ mutex_lock(&data->ti_thermal->lock);
+
+ if (mode == THERMAL_DEVICE_ENABLED)
+ data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
+ else
+ data->ti_thermal->polling_delay = 0;
+
+ mutex_unlock(&data->ti_thermal->lock);
+
+ data->mode = mode;
+ thermal_zone_device_update(data->ti_thermal);
+ dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
+ data->ti_thermal->polling_delay);
+
+ return 0;
+}
+
+/* Get trip type callback functions for thermal zone */
+static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trip_type *type)
+{
+ if (!ti_thermal_is_valid_trip(trip))
+ return -EINVAL;
+
+ if (trip + 1 == OMAP_TRIP_NUMBER)
+ *type = THERMAL_TRIP_CRITICAL;
+ else
+ *type = THERMAL_TRIP_PASSIVE;
+
+ return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
+ int trip, unsigned long *temp)
+{
+ if (!ti_thermal_is_valid_trip(trip))
+ return -EINVAL;
+
+ *temp = ti_thermal_get_trip_value(trip);
+
+ return 0;
+}
+
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+ int trip, enum thermal_trend *trend)
+{
+ struct ti_thermal_data *data = thermal->devdata;
+ struct ti_bandgap *bgp;
+ int id, tr, ret = 0;
+
+ bgp = data->bgp;
+ id = data->sensor_id;
+
+ ret = ti_bandgap_get_trend(bgp, id, &tr);
+ if (ret)
+ return ret;
+
+ if (tr > 0)
+ *trend = THERMAL_TREND_RAISING;
+ else if (tr < 0)
+ *trend = THERMAL_TREND_DROPPING;
+ else
+ *trend = THERMAL_TREND_STABLE;
+
+ return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
+{
+ /* shutdown zone */
+ return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp);
+}
+
+static struct thermal_zone_device_ops ti_thermal_ops = {
+ .get_temp = ti_thermal_get_temp,
+ .get_trend = ti_thermal_get_trend,
+ .bind = ti_thermal_bind,
+ .unbind = ti_thermal_unbind,
+ .get_mode = ti_thermal_get_mode,
+ .set_mode = ti_thermal_set_mode,
+ .get_trip_type = ti_thermal_get_trip_type,
+ .get_trip_temp = ti_thermal_get_trip_temp,
+ .get_crit_temp = ti_thermal_get_crit_temp,
+};
+
+static struct ti_thermal_data
+*ti_thermal_build_data(struct ti_bandgap *bgp, int id)
+{
+ struct ti_thermal_data *data;
+
+ data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(bgp->dev, "kzalloc fail\n");
+ return NULL;
+ }
+ data->sensor_id = id;
+ data->bgp = bgp;
+ data->mode = THERMAL_DEVICE_ENABLED;
+ INIT_WORK(&data->thermal_wq, ti_thermal_work);
+
+ return data;
+}
+
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
+ char *domain)
+{
+ struct ti_thermal_data *data;
+
+ data = ti_bandgap_get_sensor_data(bgp, id);
+
+ if (IS_ERR_OR_NULL(data))
+ data = ti_thermal_build_data(bgp, id);
+
+ if (!data)
+ return -EINVAL;
+
+ /* Create thermal zone */
+ data->ti_thermal = thermal_zone_device_register(domain,
+ OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
+ NULL, FAST_TEMP_MONITORING_RATE,
+ FAST_TEMP_MONITORING_RATE);
+ if (IS_ERR_OR_NULL(data->ti_thermal)) {
+ dev_err(bgp->dev, "thermal zone device is NULL\n");
+ return PTR_ERR(data->ti_thermal);
+ }
+ data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
+ ti_bandgap_set_sensor_data(bgp, id, data);
+
+ return 0;
+}
+
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
+{
+ struct ti_thermal_data *data;
+
+ data = ti_bandgap_get_sensor_data(bgp, id);
+
+ thermal_zone_device_unregister(data->ti_thermal);
+
+ return 0;
+}
+
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
+{
+ struct ti_thermal_data *data;
+
+ data = ti_bandgap_get_sensor_data(bgp, id);
+
+ schedule_work(&data->thermal_wq);
+
+ return 0;
+}
+
+int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+ struct ti_thermal_data *data;
+
+ data = ti_bandgap_get_sensor_data(bgp, id);
+ if (IS_ERR_OR_NULL(data))
+ data = ti_thermal_build_data(bgp, id);
+
+ if (!data)
+ return -EINVAL;
+
+ if (!cpufreq_get_current_driver()) {
+ dev_dbg(bgp->dev, "no cpufreq driver yet\n");
+ return -EPROBE_DEFER;
+ }
+
+ /* Register cooling device */
+ data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
+ if (IS_ERR_OR_NULL(data->cool_dev)) {
+ dev_err(bgp->dev,
+ "Failed to register cpufreq cooling device\n");
+ return PTR_ERR(data->cool_dev);
+ }
+ ti_bandgap_set_sensor_data(bgp, id, data);
+
+ return 0;
+}
+
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+ struct ti_thermal_data *data;
+
+ data = ti_bandgap_get_sensor_data(bgp, id);
+ cpufreq_cooling_unregister(data->cool_dev);
+
+ return 0;
+}
diff --git a/drivers/staging/omap-thermal/omap-thermal.h b/drivers/staging/ti-soc-thermal/ti-thermal.h
index 0dd2184b9663..5055777727cc 100644
--- a/drivers/staging/omap-thermal/omap-thermal.h
+++ b/drivers/staging/ti-soc-thermal/ti-thermal.h
@@ -20,32 +20,36 @@
* 02110-1301 USA
*
*/
-#ifndef __OMAP_THERMAL_H
-#define __OMAP_THERMAL_H
+#ifndef __TI_THERMAL_H
+#define __TI_THERMAL_H
-#include "omap-bandgap.h"
+#include "ti-bandgap.h"
/* sensors gradient and offsets */
+#define OMAP_GRADIENT_SLOPE_4430 0
+#define OMAP_GRADIENT_CONST_4430 20000
#define OMAP_GRADIENT_SLOPE_4460 348
#define OMAP_GRADIENT_CONST_4460 -9301
#define OMAP_GRADIENT_SLOPE_4470 308
#define OMAP_GRADIENT_CONST_4470 -7896
-#define OMAP_GRADIENT_SLOPE_5430_CPU 196
-#define OMAP_GRADIENT_CONST_5430_CPU -6822
-#define OMAP_GRADIENT_SLOPE_5430_GPU 64
-#define OMAP_GRADIENT_CONST_5430_GPU 978
+#define OMAP_GRADIENT_SLOPE_5430_CPU 65
+#define OMAP_GRADIENT_CONST_5430_CPU -1791
+#define OMAP_GRADIENT_SLOPE_5430_GPU 117
+#define OMAP_GRADIENT_CONST_5430_GPU -2992
/* PCB sensor calculation constants */
+#define OMAP_GRADIENT_SLOPE_W_PCB_4430 0
+#define OMAP_GRADIENT_CONST_W_PCB_4430 20000
#define OMAP_GRADIENT_SLOPE_W_PCB_4460 1142
#define OMAP_GRADIENT_CONST_W_PCB_4460 -393
#define OMAP_GRADIENT_SLOPE_W_PCB_4470 1063
#define OMAP_GRADIENT_CONST_W_PCB_4470 -477
-#define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU 469
-#define OMAP_GRADIENT_CONST_W_PCB_5430_CPU -1272
-#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 378
-#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU 154
+#define OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU 100
+#define OMAP_GRADIENT_CONST_W_PCB_5430_CPU 484
+#define OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU 464
+#define OMAP_GRADIENT_CONST_W_PCB_5430_GPU -5102
/* trip points of interest in milicelsius (at hotspot level) */
#define OMAP_TRIP_COLD 100000
@@ -60,47 +64,52 @@
/* helper macros */
/**
- * omap_thermal_get_trip_value - returns trip temperature based on index
+ * ti_thermal_get_trip_value - returns trip temperature based on index
* @i: trip index
*/
-#define omap_thermal_get_trip_value(i) \
+#define ti_thermal_get_trip_value(i) \
(OMAP_TRIP_HOT + ((i) * OMAP_TRIP_STEP))
/**
- * omap_thermal_is_valid_trip - check for trip index
+ * ti_thermal_is_valid_trip - check for trip index
* @i: trip index
*/
-#define omap_thermal_is_valid_trip(trip) \
+#define ti_thermal_is_valid_trip(trip) \
((trip) >= 0 && (trip) < OMAP_TRIP_NUMBER)
-#ifdef CONFIG_OMAP_THERMAL
-int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
- char *domain);
-int omap_thermal_remove_sensor(struct omap_bandgap *bg_ptr, int id);
-int omap_thermal_register_cpu_cooling(struct omap_bandgap *bg_ptr, int id);
-int omap_thermal_unregister_cpu_cooling(struct omap_bandgap *bg_ptr, int id);
+#ifdef CONFIG_TI_THERMAL
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain);
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id);
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id);
+int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id);
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id);
#else
static inline
-int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
- char *domain)
+int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain)
{
return 0;
}
static inline
-int omap_thermal_remove_sensor(struct omap_bandgap *bg_ptr, int id)
+int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
{
return 0;
}
static inline
-int omap_thermal_register_cpu_cooling(struct omap_bandgap *bg_ptr, int id)
+int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
{
return 0;
}
static inline
-int omap_thermal_unregister_cpu_cooling(struct omap_bandgap *bg_ptr, int id)
+int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
+{
+ return 0;
+}
+
+static inline
+int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
{
return 0;
}
diff --git a/drivers/staging/omap-thermal/omap_bandgap.txt b/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
index 6008a1452fde..a4a33d1a0746 100644
--- a/drivers/staging/omap-thermal/omap_bandgap.txt
+++ b/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
@@ -10,21 +10,51 @@ to the silicon temperature.
Required properties:
- compatible : Should be:
- - "ti,omap4460-control-bandgap" : for OMAP4460 bandgap
- - "ti,omap5430-control-bandgap" : for OMAP5430 bandgap
+ - "ti,omap4430-bandgap" : for OMAP4430 bandgap
+ - "ti,omap4460-bandgap" : for OMAP4460 bandgap
+ - "ti,omap4470-bandgap" : for OMAP4470 bandgap
+ - "ti,omap5430-bandgap" : for OMAP5430 bandgap
- interrupts : this entry should indicate which interrupt line
the talert signal is routed to;
Specific:
- ti,tshut-gpio : this entry should be used to inform which GPIO
line the tshut signal is routed to;
+- regs : this entry must also be specified and it is specific
+to each bandgap version, because the mapping may change from
+soc to soc, apart of depending on available features.
Example:
+OMAP4430:
+bandgap {
+ reg = <0x4a002260 0x4 0x4a00232C 0x4>;
+ compatible = "ti,omap4430-bandgap";
+};
+OMAP4460:
bandgap {
reg = <0x4a002260 0x4
0x4a00232C 0x4
0x4a002378 0x18>;
- compatible = "ti,omap4460-control-bandgap";
+ compatible = "ti,omap4460-bandgap";
interrupts = <0 126 4>; /* talert */
ti,tshut-gpio = <86>;
};
+
+OMAP4470:
+bandgap {
+ reg = <0x4a002260 0x4
+ 0x4a00232C 0x4
+ 0x4a002378 0x18>;
+ compatible = "ti,omap4470-bandgap";
+ interrupts = <0 126 4>; /* talert */
+ ti,tshut-gpio = <86>;
+};
+
+OMAP5430:
+bandgap {
+ reg = <0x4a0021e0 0xc
+ 0x4a00232c 0xc
+ 0x4a002380 0x2c
+ 0x4a0023C0 0x3c>;
+ compatible = "ti,omap5430-bandgap";
+};
diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c
index 0df55bd5bde4..cd5235a4f77c 100644
--- a/drivers/staging/tidspbridge/rmgr/proc.c
+++ b/drivers/staging/tidspbridge/rmgr/proc.c
@@ -488,7 +488,7 @@ func_end:
* Call the bridge_dev_ctrl fxn with the Argument. This is a Synchronous
* Operation. arg can be null.
*/
-int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata * arg)
+int proc_ctrl(void *hprocessor, u32 dw_cmd, struct dsp_cbdata *arg)
{
int status = 0;
struct proc_object *p_proc_object = hprocessor;
@@ -982,7 +982,7 @@ int proc_get_state(void *hprocessor,
* This call is destructive, meaning the processor is placed in the monitor
* state as a result of this function.
*/
-int proc_get_trace(void *hprocessor, u8 * pbuf, u32 max_size)
+int proc_get_trace(void *hprocessor, u8 *pbuf, u32 max_size)
{
int status;
status = -ENOSYS;
@@ -1338,7 +1338,7 @@ func_end:
*/
int proc_register_notify(void *hprocessor, u32 event_mask,
u32 notify_type, struct dsp_notification
- * hnotification)
+ *hnotification)
{
int status = 0;
struct proc_object *p_proc_object = (struct proc_object *)hprocessor;
@@ -1549,8 +1549,8 @@ int proc_stop(void *hprocessor)
status = node_enum_nodes(hnode_mgr, &hnode, node_tab_size,
&num_nodes, &nodes_allocated);
if ((status == -EINVAL) || (nodes_allocated > 0)) {
- pr_err("%s: Can't stop device, active nodes = %d \n",
- __func__, nodes_allocated);
+ pr_err("%s: Can't stop device, active nodes = %d\n",
+ __func__, nodes_allocated);
return -EBADR;
}
}
@@ -1819,7 +1819,7 @@ func_end:
* Purpose:
* Retrieves the processor ID.
*/
-int proc_get_processor_id(void *proc, u32 * proc_id)
+int proc_get_processor_id(void *proc, u32 *proc_id)
{
int status = 0;
struct proc_object *p_proc_object = (struct proc_object *)proc;
diff --git a/drivers/staging/tidspbridge/rmgr/strm.c b/drivers/staging/tidspbridge/rmgr/strm.c
index 34cc934e0c3d..b88b27bbe2e7 100644
--- a/drivers/staging/tidspbridge/rmgr/strm.c
+++ b/drivers/staging/tidspbridge/rmgr/strm.c
@@ -223,7 +223,7 @@ void strm_delete(struct strm_mgr *strm_mgr_obj)
* Purpose:
* Frees the buffers allocated for a stream.
*/
-int strm_free_buffer(struct strm_res_object *strmres, u8 ** ap_buffer,
+int strm_free_buffer(struct strm_res_object *strmres, u8 **ap_buffer,
u32 num_bufs, struct process_context *pr_ctxt)
{
int status = 0;
@@ -523,7 +523,7 @@ func_cont:
* Purpose:
* Relcaims a buffer from a stream.
*/
-int strm_reclaim(struct strm_object *stream_obj, u8 ** buf_ptr,
+int strm_reclaim(struct strm_object *stream_obj, u8 **buf_ptr,
u32 *nbytes, u32 *buff_size, u32 *pdw_arg)
{
struct bridge_drv_interface *intf_fxns;
@@ -599,7 +599,7 @@ func_end:
*/
int strm_register_notify(struct strm_object *stream_obj, u32 event_mask,
u32 notify_type, struct dsp_notification
- * hnotification)
+ *hnotification)
{
struct bridge_drv_interface *intf_fxns;
int status = 0;
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index 67556acd1514..83d629afdfe1 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -86,6 +86,7 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
struct stub_device *sdev = dev_get_drvdata(dev);
int sockfd = 0;
struct socket *socket;
+ ssize_t err = -EINVAL;
if (!sdev) {
dev_err(dev, "sdev is null\n");
@@ -101,21 +102,21 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
if (sdev->ud.status != SDEV_ST_AVAILABLE) {
dev_err(dev, "not ready\n");
- spin_unlock_irq(&sdev->ud.lock);
- return -EINVAL;
+ goto err;
}
socket = sockfd_to_socket(sockfd);
- if (!socket) {
- spin_unlock_irq(&sdev->ud.lock);
- return -EINVAL;
- }
+ if (!socket)
+ goto err;
+
sdev->ud.tcp_socket = socket;
spin_unlock_irq(&sdev->ud.lock);
- sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx");
- sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx");
+ sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
+ "stub_rx");
+ sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
+ "stub_tx");
spin_lock_irq(&sdev->ud.lock);
sdev->ud.status = SDEV_ST_USED;
@@ -125,16 +126,19 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
dev_info(dev, "stub down\n");
spin_lock_irq(&sdev->ud.lock);
- if (sdev->ud.status != SDEV_ST_USED) {
- spin_unlock_irq(&sdev->ud.lock);
- return -EINVAL;
- }
+ if (sdev->ud.status != SDEV_ST_USED)
+ goto err;
+
spin_unlock_irq(&sdev->ud.lock);
usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
}
return count;
+
+err:
+ spin_unlock_irq(&sdev->ud.lock);
+ return err;
}
static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
@@ -323,15 +327,9 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev,
return sdev;
}
-static int stub_device_free(struct stub_device *sdev)
+static void stub_device_free(struct stub_device *sdev)
{
- if (!sdev)
- return -EINVAL;
-
kfree(sdev);
- pr_debug("kfree udev ok\n");
-
- return 0;
}
/*
@@ -450,7 +448,7 @@ static void shutdown_busid(struct bus_id_priv *busid_priv)
busid_priv->shutdown_busid = 1;
usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
- /* 2. wait for the stop of the event handler */
+ /* wait for the stop of the event handler */
usbip_stop_eh(&busid_priv->sdev->ud);
}
}
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
index 705a9e530a19..33027cce6700 100644
--- a/drivers/staging/usbip/stub_main.c
+++ b/drivers/staging/usbip/stub_main.c
@@ -38,11 +38,11 @@ static spinlock_t busid_table_lock;
static void init_busid_table(void)
{
- int i;
-
+ /*
+ * This also sets the bus_table[i].status to
+ * STUB_BUSID_OTHER, which is 0.
+ */
memset(busid_table, 0, sizeof(busid_table));
- for (i = 0; i < MAX_BUSID; i++)
- busid_table[i].status = STUB_BUSID_OTHER;
spin_lock_init(&busid_table_lock);
}
@@ -167,22 +167,22 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
strncpy(busid, buf + 4, BUSID_SIZE);
if (!strncmp(buf, "add ", 4)) {
- if (add_match_busid(busid) < 0) {
+ if (add_match_busid(busid) < 0)
return -ENOMEM;
- } else {
- pr_debug("add busid %s\n", busid);
- return count;
- }
- } else if (!strncmp(buf, "del ", 4)) {
- if (del_match_busid(busid) < 0) {
+
+ pr_debug("add busid %s\n", busid);
+ return count;
+ }
+
+ if (!strncmp(buf, "del ", 4)) {
+ if (del_match_busid(busid) < 0)
return -ENODEV;
- } else {
- pr_debug("del busid %s\n", busid);
- return count;
- }
- } else {
- return -EINVAL;
+
+ pr_debug("del busid %s\n", busid);
+ return count;
}
+
+ return -EINVAL;
}
static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
store_match_busid);
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
index 715e8a79fb4e..db48a789d308 100644
--- a/drivers/staging/usbip/stub_rx.c
+++ b/drivers/staging/usbip/stub_rx.c
@@ -228,61 +228,61 @@ static void tweak_special_requests(struct urb *urb)
static int stub_recv_cmd_unlink(struct stub_device *sdev,
struct usbip_header *pdu)
{
+ int ret;
unsigned long flags;
-
struct stub_priv *priv;
spin_lock_irqsave(&sdev->priv_lock, flags);
list_for_each_entry(priv, &sdev->priv_init, list) {
- if (priv->seqnum == pdu->u.cmd_unlink.seqnum) {
- int ret;
-
- dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
- priv->urb);
-
- /*
- * This matched urb is not completed yet (i.e., be in
- * flight in usb hcd hardware/driver). Now we are
- * cancelling it. The unlinking flag means that we are
- * now not going to return the normal result pdu of a
- * submission request, but going to return a result pdu
- * of the unlink request.
- */
- priv->unlinking = 1;
-
- /*
- * In the case that unlinking flag is on, prev->seqnum
- * is changed from the seqnum of the cancelling urb to
- * the seqnum of the unlink request. This will be used
- * to make the result pdu of the unlink request.
- */
- priv->seqnum = pdu->base.seqnum;
-
- spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
- /*
- * usb_unlink_urb() is now out of spinlocking to avoid
- * spinlock recursion since stub_complete() is
- * sometimes called in this context but not in the
- * interrupt context. If stub_complete() is executed
- * before we call usb_unlink_urb(), usb_unlink_urb()
- * will return an error value. In this case, stub_tx
- * will return the result pdu of this unlink request
- * though submission is completed and actual unlinking
- * is not executed. OK?
- */
- /* In the above case, urb->status is not -ECONNRESET,
- * so a driver in a client host will know the failure
- * of the unlink request ?
- */
- ret = usb_unlink_urb(priv->urb);
- if (ret != -EINPROGRESS)
- dev_err(&priv->urb->dev->dev,
- "failed to unlink a urb %p, ret %d\n",
- priv->urb, ret);
- return 0;
- }
+ if (priv->seqnum != pdu->u.cmd_unlink.seqnum)
+ continue;
+
+ dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
+ priv->urb);
+
+ /*
+ * This matched urb is not completed yet (i.e., be in
+ * flight in usb hcd hardware/driver). Now we are
+ * cancelling it. The unlinking flag means that we are
+ * now not going to return the normal result pdu of a
+ * submission request, but going to return a result pdu
+ * of the unlink request.
+ */
+ priv->unlinking = 1;
+
+ /*
+ * In the case that unlinking flag is on, prev->seqnum
+ * is changed from the seqnum of the cancelling urb to
+ * the seqnum of the unlink request. This will be used
+ * to make the result pdu of the unlink request.
+ */
+ priv->seqnum = pdu->base.seqnum;
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ /*
+ * usb_unlink_urb() is now out of spinlocking to avoid
+ * spinlock recursion since stub_complete() is
+ * sometimes called in this context but not in the
+ * interrupt context. If stub_complete() is executed
+ * before we call usb_unlink_urb(), usb_unlink_urb()
+ * will return an error value. In this case, stub_tx
+ * will return the result pdu of this unlink request
+ * though submission is completed and actual unlinking
+ * is not executed. OK?
+ */
+ /* In the above case, urb->status is not -ECONNRESET,
+ * so a driver in a client host will know the failure
+ * of the unlink request ?
+ */
+ ret = usb_unlink_urb(priv->urb);
+ if (ret != -EINPROGRESS)
+ dev_err(&priv->urb->dev->dev,
+ "failed to unlink a urb %p, ret %d\n",
+ priv->urb, ret);
+
+ return 0;
}
usbip_dbg_stub_rx("seqnum %d is not pending\n",
@@ -552,7 +552,7 @@ static void stub_rx_pdu(struct usbip_device *ud)
memset(&pdu, 0, sizeof(pdu));
- /* 1. receive a pdu header */
+ /* receive a pdu header */
ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
if (ret != sizeof(pdu)) {
dev_err(dev, "recv a header, %d\n", ret);
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 539fa5785afe..7b97df6f2a42 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -389,7 +389,7 @@ int usbip_recv(struct socket *sock, void *buf, int size)
pr_debug("receiving....\n");
usbip_dump_buffer(bp, osize);
pr_debug("received, osize %d ret %d size %d total %d\n",
- osize, result, size, total);
+ osize, result, size, total);
}
return total;
diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README
index 233d1d7aef92..00a1658b272b 100644
--- a/drivers/staging/usbip/userspace/README
+++ b/drivers/staging/usbip/userspace/README
@@ -54,7 +54,7 @@
client:# usbip list --remote <host>
- List exported USB devices on the <host>.
- client:# usbip attach --host <host> --busid 1-2
+ client:# usbip attach --remote <host> --busid 1-2
- Connect the remote USB device.
client:# usbip port
@@ -163,7 +163,7 @@ exportable on the host.
Attach a remote USB device:
- deux:# usbip attach --host 10.0.0.3 --busid 1-1
+ deux:# usbip attach --remote 10.0.0.3 --busid 1-1
port 0 attached
Show the devices attached to this client:
diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8
index 6e0d74503792..ccdadc87c478 100644
--- a/drivers/staging/usbip/userspace/doc/usbip.8
+++ b/drivers/staging/usbip/userspace/doc/usbip.8
@@ -38,7 +38,7 @@ then exit.
.PP
.HP
-\fBattach\fR \-\-host=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
+\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
.IP
Attach a remote USB device.
.PP
@@ -79,7 +79,7 @@ List local USB devices.
client:# usbip list --remote=server
- List exportable usb devices on the server.
- client:# usbip attach --host=server --busid=1-2
+ client:# usbip attach --remote=server --busid=1-2
- Connect the remote USB device.
client:# usbip detach --port=0
diff --git a/drivers/staging/usbip/userspace/libsrc/names.c b/drivers/staging/usbip/userspace/libsrc/names.c
index b4de18b4bb9c..3c8d28b771e0 100644
--- a/drivers/staging/usbip/userspace/libsrc/names.c
+++ b/drivers/staging/usbip/userspace/libsrc/names.c
@@ -1,4 +1,3 @@
-/*****************************************************************************/
/*
* names.c -- USB name database manipulation routines
*
@@ -19,15 +18,14 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
+ *
+ *
+ *
+ * Copyright (C) 2005 Takahiro Hirofuchi
+ * - names_deinit() is added.
+ *
*/
-/*
- * Copyright (C) 2005 Takahiro Hirofuchi
- * - names_deinit() is added.
- */
-
-/*****************************************************************************/
-
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -39,11 +37,8 @@
#include <stdio.h>
#include <ctype.h>
-
#include "names.h"
-
-
-/* ---------------------------------------------------------------------- */
+#include "usbip_common.h"
struct vendor {
struct vendor *next;
@@ -75,19 +70,12 @@ struct protocol {
char name[1];
};
-struct audioterminal {
- struct audioterminal *next;
- u_int16_t termt;
- char name[1];
-};
-
struct genericstrtable {
- struct genericstrtable *next;
- unsigned int num;
- char name[1];
+ struct genericstrtable *next;
+ unsigned int num;
+ char name[1];
};
-/* ---------------------------------------------------------------------- */
#define HASH1 0x10
#define HASH2 0x02
@@ -103,74 +91,12 @@ static unsigned int hashnum(unsigned int num)
return num & (HASHSZ-1);
}
-/* ---------------------------------------------------------------------- */
static struct vendor *vendors[HASHSZ] = { NULL, };
static struct product *products[HASHSZ] = { NULL, };
static struct class *classes[HASHSZ] = { NULL, };
static struct subclass *subclasses[HASHSZ] = { NULL, };
static struct protocol *protocols[HASHSZ] = { NULL, };
-static struct audioterminal *audioterminals[HASHSZ] = { NULL, };
-static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, };
-static struct genericstrtable *reports[HASHSZ] = { NULL, };
-static struct genericstrtable *huts[HASHSZ] = { NULL, };
-static struct genericstrtable *biass[HASHSZ] = { NULL, };
-static struct genericstrtable *physdess[HASHSZ] = { NULL, };
-static struct genericstrtable *hutus[HASHSZ] = { NULL, };
-static struct genericstrtable *langids[HASHSZ] = { NULL, };
-static struct genericstrtable *countrycodes[HASHSZ] = { NULL, };
-
-/* ---------------------------------------------------------------------- */
-
-static const char *names_genericstrtable(struct genericstrtable *t[HASHSZ], unsigned int index)
-{
- struct genericstrtable *h;
-
- for (h = t[hashnum(index)]; h; h = h->next)
- if (h->num == index)
- return h->name;
- return NULL;
-}
-
-const char *names_hid(u_int8_t hidd)
-{
- return names_genericstrtable(hiddescriptors, hidd);
-}
-
-const char *names_reporttag(u_int8_t rt)
-{
- return names_genericstrtable(reports, rt);
-}
-
-const char *names_huts(unsigned int data)
-{
- return names_genericstrtable(huts, data);
-}
-
-const char *names_hutus(unsigned int data)
-{
- return names_genericstrtable(hutus, data);
-}
-
-const char *names_langid(u_int16_t langid)
-{
- return names_genericstrtable(langids, langid);
-}
-
-const char *names_physdes(u_int8_t ph)
-{
- return names_genericstrtable(physdess, ph);
-}
-
-const char *names_bias(u_int8_t b)
-{
- return names_genericstrtable(biass, b);
-}
-
-const char *names_countrycode(unsigned int countrycode)
-{
- return names_genericstrtable(countrycodes, countrycode);
-}
const char *names_vendor(u_int16_t vendorid)
{
@@ -216,37 +142,27 @@ const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
return NULL;
}
-const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid)
+const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid)
{
struct protocol *p;
- p = protocols[hashnum((classid << 16) | (subclassid << 8) | protocolid)];
+ p = protocols[hashnum((classid << 16) | (subclassid << 8)
+ | protocolid)];
for (; p; p = p->next)
- if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
+ if (p->classid == classid && p->subclassid == subclassid &&
+ p->protocolid == protocolid)
return p->name;
return NULL;
}
-const char *names_audioterminal(u_int16_t termt)
-{
- struct audioterminal *at;
-
- at = audioterminals[hashnum(termt)];
- for (; at; at = at->next)
- if (at->termt == termt)
- return at->name;
- return NULL;
-}
-
-/* ---------------------------------------------------------------------- */
/* add a cleanup function by takahiro */
-
struct pool {
struct pool *next;
void *mem;
};
-static struct pool *pool_head = NULL;
+static struct pool *pool_head;
static void *my_malloc(size_t size)
{
@@ -287,8 +203,6 @@ void names_free(void)
}
}
-/* ---------------------------------------------------------------------- */
-
static int new_vendor(const char *name, u_int16_t vendorid)
{
struct vendor *v;
@@ -308,7 +222,8 @@ static int new_vendor(const char *name, u_int16_t vendorid)
return 0;
}
-static int new_product(const char *name, u_int16_t vendorid, u_int16_t productid)
+static int new_product(const char *name, u_int16_t vendorid,
+ u_int16_t productid)
{
struct product *p;
unsigned int h = hashnum((vendorid << 16) | productid);
@@ -367,14 +282,17 @@ static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
return 0;
}
-static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid)
+static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid)
{
struct protocol *p;
- unsigned int h = hashnum((classid << 16) | (subclassid << 8) | protocolid);
+ unsigned int h = hashnum((classid << 16) | (subclassid << 8)
+ | protocolid);
p = protocols[h];
for (; p; p = p->next)
- if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid)
+ if (p->classid == classid && p->subclassid == subclassid
+ && p->protocolid == protocolid)
return -1;
p = my_malloc(sizeof(struct protocol) + strlen(name));
if (!p)
@@ -388,253 +306,84 @@ static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
return 0;
}
-static int new_audioterminal(const char *name, u_int16_t termt)
-{
- struct audioterminal *at;
- unsigned int h = hashnum(termt);
-
- at = audioterminals[h];
- for (; at; at = at->next)
- if (at->termt == termt)
- return -1;
- at = my_malloc(sizeof(struct audioterminal) + strlen(name));
- if (!at)
- return -1;
- strcpy(at->name, name);
- at->termt = termt;
- at->next = audioterminals[h];
- audioterminals[h] = at;
- return 0;
-}
-
-static int new_genericstrtable(struct genericstrtable *t[HASHSZ], const char *name, unsigned int index)
-{
- struct genericstrtable *g;
- unsigned int h = hashnum(index);
-
- for (g = t[h]; g; g = g->next)
- if (g->num == index)
- return -1;
- g = my_malloc(sizeof(struct genericstrtable) + strlen(name));
- if (!g)
- return -1;
- strcpy(g->name, name);
- g->num = index;
- g->next = t[h];
- t[h] = g;
- return 0;
-}
-
-static int new_hid(const char *name, u_int8_t hidd)
-{
- return new_genericstrtable(hiddescriptors, name, hidd);
-}
-
-static int new_reporttag(const char *name, u_int8_t rt)
-{
- return new_genericstrtable(reports, name, rt);
-}
-
-static int new_huts(const char *name, unsigned int data)
-{
- return new_genericstrtable(huts, name, data);
-}
-
-static int new_hutus(const char *name, unsigned int data)
-{
- return new_genericstrtable(hutus, name, data);
-}
-
-static int new_langid(const char *name, u_int16_t langid)
-{
- return new_genericstrtable(langids, name, langid);
-}
-
-static int new_physdes(const char *name, u_int8_t ph)
-{
- return new_genericstrtable(physdess, name, ph);
-}
-static int new_bias(const char *name, u_int8_t b)
-{
- return new_genericstrtable(biass, name, b);
-}
-
-static int new_countrycode(const char *name, unsigned int countrycode)
-{
- return new_genericstrtable(countrycodes, name, countrycode);
-}
-
-/* ---------------------------------------------------------------------- */
-
-#define DBG(x)
-
static void parse(FILE *f)
{
char buf[512], *cp;
unsigned int linectr = 0;
- int lastvendor = -1, lastclass = -1, lastsubclass = -1, lasthut=-1, lastlang=-1;
+ int lastvendor = -1;
+ int lastclass = -1;
+ int lastsubclass = -1;
+ int lasthut = -1;
+ int lastlang = -1;
unsigned int u;
while (fgets(buf, sizeof(buf), f)) {
linectr++;
/* remove line ends */
- if ((cp = strchr(buf, 13)))
+ cp = strchr(buf, '\r');
+ if (cp)
*cp = 0;
- if ((cp = strchr(buf, 10)))
+ cp = strchr(buf, '\n');
+ if (cp)
*cp = 0;
if (buf[0] == '#' || !buf[0])
continue;
cp = buf;
- if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && buf[3] == 'S' && buf[4] == 'D' &&
- buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ buf[7] == ' ') {
- cp = buf + 8;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid Physdes type at line %u\n", linectr);
- continue;
- }
- if (new_physdes(cp, u))
- fprintf(stderr, "Duplicate Physdes type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u physdes type %02x %s\n", linectr, u, cp));
- continue;
-
- }
- if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
- cp = buf + 4;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid PHY type at line %u\n", linectr);
- continue;
- }
- if (new_physdes(cp, u))
- fprintf(stderr, "Duplicate PHY type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u PHY type %02x %s\n", linectr, u, cp));
- continue;
-
- }
- if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
- cp = buf + 5;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid BIAS type at line %u\n", linectr);
- continue;
- }
- if (new_bias(cp, u))
- fprintf(stderr, "Duplicate BIAS type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u BIAS type %02x %s\n", linectr, u, cp));
- continue;
-
- }
- if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
- cp = buf+2;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr);
- continue;
- }
- if (new_langid(cp, u))
- fprintf(stderr, "Duplicate LANGID spec at line %u language-id %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u LANGID %02x %s\n", linectr, u, cp));
- lasthut = lastclass = lastvendor = lastsubclass = -1;
- lastlang = u;
- continue;
- }
+ if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
+ buf[3] == 'S' && buf[4] == 'D' &&
+ buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
+ buf[7] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'P' && buf[1] == 'H' &&
+ buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
+ buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
+ continue;
+ }
+ if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
+ lasthut = lastclass = lastvendor = lastsubclass = -1;
+ /*
+ * set 1 as pseudo-id to indicate that the parser is
+ * in a `L' section.
+ */
+ lastlang = 1;
+ continue;
+ }
if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
/* class spec */
cp = buf+2;
while (isspace(*cp))
cp++;
if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid class spec at line %u\n", linectr);
+ err("Invalid class spec at line %u", linectr);
continue;
}
u = strtoul(cp, &cp, 16);
while (isspace(*cp))
cp++;
if (!*cp) {
- fprintf(stderr, "Invalid class spec at line %u\n", linectr);
+ err("Invalid class spec at line %u", linectr);
continue;
}
if (new_class(cp, u))
- fprintf(stderr, "Duplicate class spec at line %u class %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u class %02x %s\n", linectr, u, cp));
+ err("Duplicate class spec at line %u class %04x %s",
+ linectr, u, cp);
+ dbg("line %5u class %02x %s", linectr, u, cp);
lasthut = lastlang = lastvendor = lastsubclass = -1;
lastclass = u;
continue;
}
if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
/* audio terminal type spec */
- cp = buf+3;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr);
- continue;
- }
- if (new_audioterminal(cp, u))
- fprintf(stderr, "Duplicate audio terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u audio terminal type %02x %s\n", linectr, u, cp));
continue;
}
- if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' && isspace(buf[3])) {
+ if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
+ && isspace(buf[3])) {
/* HID Descriptor bCountryCode */
- cp = buf+3;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 10);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid HID country code at line %u\n", linectr);
- continue;
- }
- if (new_countrycode(cp, u))
- fprintf(stderr, "Duplicate HID country code at line %u country %02u %s\n", linectr, u, cp);
- DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp));
- continue;
+ continue;
}
if (isxdigit(*cp)) {
/* vendor */
@@ -642,12 +391,13 @@ static void parse(FILE *f)
while (isspace(*cp))
cp++;
if (!*cp) {
- fprintf(stderr, "Invalid vendor spec at line %u\n", linectr);
+ err("Invalid vendor spec at line %u", linectr);
continue;
}
if (new_vendor(cp, u))
- fprintf(stderr, "Duplicate vendor spec at line %u vendor %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u vendor %04x %s\n", linectr, u, cp));
+ err("Duplicate vendor spec at line %u vendor %04x %s",
+ linectr, u, cp);
+ dbg("line %5u vendor %04x %s", linectr, u, cp);
lastvendor = u;
lasthut = lastlang = lastclass = lastsubclass = -1;
continue;
@@ -658,33 +408,37 @@ static void parse(FILE *f)
while (isspace(*cp))
cp++;
if (!*cp) {
- fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr);
+ err("Invalid product/subclass spec at line %u",
+ linectr);
continue;
}
if (lastvendor != -1) {
if (new_product(cp, lastvendor, u))
- fprintf(stderr, "Duplicate product spec at line %u product %04x:%04x %s\n", linectr, lastvendor, u, cp);
- DBG(printf("line %5u product %04x:%04x %s\n", linectr, lastvendor, u, cp));
+ err("Duplicate product spec at line %u product %04x:%04x %s",
+ linectr, lastvendor, u, cp);
+ dbg("line %5u product %04x:%04x %s", linectr,
+ lastvendor, u, cp);
continue;
}
if (lastclass != -1) {
if (new_subclass(cp, lastclass, u))
- fprintf(stderr, "Duplicate subclass spec at line %u class %02x:%02x %s\n", linectr, lastclass, u, cp);
- DBG(printf("line %5u subclass %02x:%02x %s\n", linectr, lastclass, u, cp));
+ err("Duplicate subclass spec at line %u class %02x:%02x %s",
+ linectr, lastclass, u, cp);
+ dbg("line %5u subclass %02x:%02x %s", linectr,
+ lastclass, u, cp);
lastsubclass = u;
continue;
}
if (lasthut != -1) {
- if (new_hutus(cp, (lasthut << 16)+u))
- fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr);
+ /* do not store hut */
continue;
}
if (lastlang != -1) {
- if (new_langid(cp, lastlang+(u<<10)))
- fprintf(stderr, "Duplicate LANGID Usage Spec at line %u\n", linectr);
- continue;
- }
- fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr);
+ /* do not store langid */
+ continue;
+ }
+ err("Product/Subclass spec without prior Vendor/Class spec at line %u",
+ linectr);
continue;
}
if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
@@ -693,100 +447,57 @@ static void parse(FILE *f)
while (isspace(*cp))
cp++;
if (!*cp) {
- fprintf(stderr, "Invalid protocol spec at line %u\n", linectr);
+ err("Invalid protocol spec at line %u",
+ linectr);
continue;
}
if (lastclass != -1 && lastsubclass != -1) {
- if (new_protocol(cp, lastclass, lastsubclass, u))
- fprintf(stderr, "Duplicate protocol spec at line %u class %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp);
- DBG(printf("line %5u protocol %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp));
+ if (new_protocol(cp, lastclass, lastsubclass,
+ u))
+ err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
+ linectr, lastclass, lastsubclass,
+ u, cp);
+ dbg("line %5u protocol %02x:%02x:%02x %s",
+ linectr, lastclass, lastsubclass, u, cp);
continue;
}
- fprintf(stderr, "Protocol spec without prior Class and Subclass spec at line %u\n", linectr);
+ err("Protocol spec without prior Class and Subclass spec at line %u",
+ linectr);
continue;
}
- if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
- cp = buf + 4;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid HID type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid HID type at line %u\n", linectr);
- continue;
- }
- if (new_hid(cp, u))
- fprintf(stderr, "Duplicate HID type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u HID type %02x %s\n", linectr, u, cp));
- continue;
-
+ if (buf[0] == 'H' && buf[1] == 'I' &&
+ buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
+ continue;
}
- if (buf[0] == 'H' && buf[1] == 'U' && buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
- cp = buf + 4;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid HUT type at line %u\n", linectr);
- continue;
- }
- if (new_huts(cp, u))
- fprintf(stderr, "Duplicate HUT type spec at line %u terminal type %04x %s\n", linectr, u, cp);
+ if (buf[0] == 'H' && buf[1] == 'U' &&
+ buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
lastlang = lastclass = lastvendor = lastsubclass = -1;
- lasthut = u;
- DBG(printf("line %5u HUT type %02x %s\n", linectr, u, cp));
- continue;
-
- }
- if (buf[0] == 'R' && buf[1] == ' ') {
- cp = buf + 2;
- while (isspace(*cp))
- cp++;
- if (!isxdigit(*cp)) {
- fprintf(stderr, "Invalid Report type at line %u\n", linectr);
- continue;
- }
- u = strtoul(cp, &cp, 16);
- while (isspace(*cp))
- cp++;
- if (!*cp) {
- fprintf(stderr, "Invalid Report type at line %u\n", linectr);
- continue;
- }
- if (new_reporttag(cp, u))
- fprintf(stderr, "Duplicate Report type spec at line %u terminal type %04x %s\n", linectr, u, cp);
- DBG(printf("line %5u Report type %02x %s\n", linectr, u, cp));
- continue;
-
- }
- if (buf[0] == 'V' && buf[1] == 'T') {
- /* add here */
+ /*
+ * set 1 as pseudo-id to indicate that the parser is
+ * in a `HUT' section.
+ */
+ lasthut = 1;
continue;
}
- fprintf(stderr, "Unknown line at line %u\n", linectr);
+ if (buf[0] == 'R' && buf[1] == ' ')
+ continue;
+
+ if (buf[0] == 'V' && buf[1] == 'T')
+ continue;
+
+ err("Unknown line at line %u", linectr);
}
}
-/* ---------------------------------------------------------------------- */
int names_init(char *n)
{
FILE *f;
- if (!(f = fopen(n, "r"))) {
+ f = fopen(n, "r");
+ if (!f)
return errno;
- }
+
parse(f);
fclose(f);
return 0;
diff --git a/drivers/staging/usbip/userspace/libsrc/names.h b/drivers/staging/usbip/userspace/libsrc/names.h
index 3a269fecc02a..680926512de2 100644
--- a/drivers/staging/usbip/userspace/libsrc/names.h
+++ b/drivers/staging/usbip/userspace/libsrc/names.h
@@ -1,5 +1,3 @@
-/*****************************************************************************/
-
/*
* names.h -- USB name database manipulation routines
*
@@ -20,38 +18,24 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
- */
-
-/*
+ *
* Copyright (C) 2005 Takahiro Hirofuchi
* - names_free() is added.
*/
-/*****************************************************************************/
-
#ifndef _NAMES_H
#define _NAMES_H
#include <sys/types.h>
-/* ---------------------------------------------------------------------- */
-
+/* used by usbip_common.c */
extern const char *names_vendor(u_int16_t vendorid);
extern const char *names_product(u_int16_t vendorid, u_int16_t productid);
extern const char *names_class(u_int8_t classid);
extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid);
-extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid);
-extern const char *names_audioterminal(u_int16_t termt);
-extern const char *names_hid(u_int8_t hidd);
-extern const char *names_reporttag(u_int8_t rt);
-extern const char *names_huts(unsigned int data);
-extern const char *names_hutus(unsigned int data);
-extern const char *names_langid(u_int16_t langid);
-extern const char *names_physdes(u_int8_t ph);
-extern const char *names_bias(u_int8_t b);
-extern const char *names_countrycode(unsigned int countrycode);
+extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+ u_int8_t protocolid);
extern int names_init(char *n);
extern void names_free(void);
-/* ---------------------------------------------------------------------- */
#endif /* _NAMES_H */
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.c b/drivers/staging/usbip/userspace/libsrc/usbip_common.c
index 154b4b1103ec..17e08e022c00 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_common.c
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.c
@@ -8,9 +8,9 @@
#undef PROGNAME
#define PROGNAME "libusbip"
-int usbip_use_syslog = 0;
-int usbip_use_stderr = 0;
-int usbip_use_debug = 0;
+int usbip_use_syslog;
+int usbip_use_stderr;
+int usbip_use_debug;
struct speed_string {
int num;
@@ -44,7 +44,7 @@ static struct portst_string portst_strings[] = {
const char *usbip_status_string(int32_t status)
{
- for (int i=0; portst_strings[i].desc != NULL; i++)
+ for (int i = 0; portst_strings[i].desc != NULL; i++)
if (portst_strings[i].num == status)
return portst_strings[i].desc;
@@ -53,7 +53,7 @@ const char *usbip_status_string(int32_t status)
const char *usbip_speed_string(int num)
{
- for (int i=0; speed_strings[i].speed != NULL; i++)
+ for (int i = 0; speed_strings[i].speed != NULL; i++)
if (speed_strings[i].num == num)
return speed_strings[i].desc;
@@ -109,7 +109,8 @@ void dump_usb_device(struct usbip_usb_device *udev)
}
-int read_attr_value(struct sysfs_device *dev, const char *name, const char *format)
+int read_attr_value(struct sysfs_device *dev, const char *name,
+ const char *format)
{
char attrpath[SYSFS_PATH_MAX];
struct sysfs_attribute *attr;
@@ -172,7 +173,7 @@ int read_attr_speed(struct sysfs_device *dev)
err:
sysfs_close_attribute(attr);
- for (int i=0; speed_strings[i].speed != NULL; i++) {
+ for (int i = 0; speed_strings[i].speed != NULL; i++) {
if (!strcmp(speed, speed_strings[i].speed))
return speed_strings[i].num;
}
@@ -180,8 +181,11 @@ err:
return USB_SPEED_UNKNOWN;
}
-#define READ_ATTR(object, type, dev, name, format)\
- do { (object)->name = (type) read_attr_value(dev, to_string(name), format); } while (0)
+#define READ_ATTR(object, type, dev, name, format) \
+ do { \
+ (object)->name = (type) read_attr_value(dev, to_string(name), \
+ format); \
+ } while (0)
int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev)
@@ -245,7 +249,8 @@ void usbip_names_free()
names_free();
}
-void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product)
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+ uint16_t product)
{
const char *prod, *vend;
@@ -261,7 +266,8 @@ void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t
snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
}
-void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol)
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+ uint8_t subclass, uint8_t protocol)
{
const char *c, *s, *p;
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h
index eedefbd12ea6..938ad1c36947 100644
--- a/drivers/staging/usbip/userspace/libsrc/usbip_common.h
+++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.h
@@ -84,7 +84,7 @@ enum usb_device_speed {
};
/* FIXME: how to sync with drivers/usbip_common.h ? */
-enum usbip_device_status{
+enum usbip_device_status {
/* sdev is available. */
SDEV_ST_AVAILABLE = 0x01,
/* sdev is now used. */
@@ -132,7 +132,8 @@ struct usbip_usb_device {
void dump_usb_interface(struct usbip_usb_interface *);
void dump_usb_device(struct usbip_usb_device *);
int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev);
-int read_attr_value(struct sysfs_device *dev, const char *name, const char *format);
+int read_attr_value(struct sysfs_device *dev, const char *name,
+ const char *format);
int read_usb_interface(struct usbip_usb_device *udev, int i,
struct usbip_usb_interface *uinf);
@@ -141,7 +142,9 @@ const char *usbip_status_string(int32_t status);
int usbip_names_init(char *);
void usbip_names_free(void);
-void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product);
-void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol);
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+ uint16_t product);
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+ uint8_t subclass, uint8_t protocol);
#endif /* __USBIP_COMMON_H */
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 0958ba53e94a..25e62e9f0a33 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -10,7 +10,8 @@
struct usbip_vhci_driver *vhci_driver;
-static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid)
+static struct usbip_imported_device *
+imported_device_init(struct usbip_imported_device *idev, char *busid)
{
struct sysfs_device *sudev;
@@ -29,14 +30,16 @@ static struct usbip_imported_device *imported_device_init(struct usbip_imported_
if (!strncmp(cdev->dev_path, idev->udev.path,
strlen(idev->udev.path))) {
struct usbip_class_device *new_cdev;
-
- /* alloc and copy because dlist is linked from only one list */
+ /*
+ * alloc and copy because dlist is linked
+ * from only one list
+ */
new_cdev = calloc(1, sizeof(*new_cdev));
if (!new_cdev)
goto err;
memcpy(new_cdev, cdev, sizeof(*new_cdev));
- dlist_unshift(idev->cdev_list, (void*) new_cdev);
+ dlist_unshift(idev->cdev_list, (void *) new_cdev);
}
}
@@ -101,7 +104,8 @@ static int parse_status(char *value)
return -1;
}
- if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {
+ if (idev->status != VDEV_ST_NULL
+ && idev->status != VDEV_ST_NOTASSIGNED) {
idev = imported_device_init(idev, lbusid);
if (!idev) {
dbg("imported_device_init failed");
@@ -126,8 +130,10 @@ static int parse_status(char *value)
static int check_usbip_device(struct sysfs_class_device *cdev)
{
- char class_path[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */
- char dev_path[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
+ /* /sys/class/video4linux/video0/device */
+ char class_path[SYSFS_PATH_MAX];
+ /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
+ char dev_path[SYSFS_PATH_MAX];
int ret;
struct usbip_class_device *usbip_cdev;
@@ -289,25 +295,25 @@ static int get_nports(void)
static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
{
- struct sysfs_driver *sdriver;
- char sdriver_path[SYSFS_PATH_MAX];
+ struct sysfs_driver *sdriver;
+ char sdriver_path[SYSFS_PATH_MAX];
struct sysfs_device *hc_dev;
struct dlist *hc_devs;
int found = 0;
- snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
- SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
- USBIP_VHCI_DRV_NAME);
+ snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
+ SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
+ USBIP_VHCI_DRV_NAME);
- sdriver = sysfs_open_driver_path(sdriver_path);
- if (!sdriver) {
+ sdriver = sysfs_open_driver_path(sdriver_path);
+ if (!sdriver) {
dbg("sysfs_open_driver_path failed: %s", sdriver_path);
- dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
+ dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
USBIP_VHCI_DRV_NAME ".ko are loaded!");
- return -1;
- }
+ return -1;
+ }
hc_devs = sysfs_get_driver_devices(sdriver);
if (!hc_devs) {
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
index 2da4e44e1633..0ec16e54fb02 100644
--- a/drivers/staging/usbip/userspace/src/usbip_attach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_attach.c
@@ -36,7 +36,7 @@
static const char usbip_attach_usage_string[] =
"usbip attach <args>\n"
- " -h, --host=<host> The machine with exported USB devices\n"
+ " -r, --remote=<host> The machine with exported USB devices\n"
" -b, --busid=<busid> Busid of the device on <host>\n";
void usbip_attach_usage(void)
@@ -201,9 +201,9 @@ static int attach_device(char *host, char *busid)
int usbip_attach(int argc, char *argv[])
{
static const struct option opts[] = {
- { "host", required_argument, NULL, 'h' },
- { "busid", required_argument, NULL, 'b' },
- { NULL, 0, NULL, 0 }
+ { "remote", required_argument, NULL, 'r' },
+ { "busid", required_argument, NULL, 'b' },
+ { NULL, 0, NULL, 0 }
};
char *host = NULL;
char *busid = NULL;
@@ -211,13 +211,13 @@ int usbip_attach(int argc, char *argv[])
int ret = -1;
for (;;) {
- opt = getopt_long(argc, argv, "h:b:", opts, NULL);
+ opt = getopt_long(argc, argv, "r:b:", opts, NULL);
if (opt == -1)
break;
switch (opt) {
- case 'h':
+ case 'r':
host = optarg;
break;
case 'b':
diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c
index dac5f065755a..13308df613a2 100644
--- a/drivers/staging/usbip/userspace/src/usbip_detach.c
+++ b/drivers/staging/usbip/userspace/src/usbip_detach.c
@@ -49,7 +49,7 @@ static int detach_port(char *port)
uint8_t portnum;
char path[PATH_MAX+1];
- for (unsigned int i=0; i < strlen(port); i++)
+ for (unsigned int i = 0; i < strlen(port); i++)
if (!isdigit(port[i])) {
err("invalid port %s", port);
return -1;
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
index ed30d910e037..ff56255f497a 100644
--- a/drivers/staging/usbip/userspace/src/usbip_list.c
+++ b/drivers/staging/usbip/userspace/src/usbip_list.c
@@ -159,6 +159,12 @@ static void print_device(char *busid, char *vendor, char *product,
printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
}
+static void print_product_name(char *product_name, bool parsable)
+{
+ if (!parsable)
+ printf(" %s\n", product_name);
+}
+
static void print_interface(char *busid, char *driver, bool parsable)
{
if (parsable)
@@ -189,6 +195,7 @@ static int list_devices(bool parsable)
{
char bus_type[] = "usb";
char busid[SYSFS_BUS_ID_SIZE];
+ char product_name[128];
struct sysfs_bus *ubus;
struct sysfs_device *dev;
struct sysfs_device *intf;
@@ -231,8 +238,13 @@ static int list_devices(bool parsable)
goto err_out;
}
+ /* get product name */
+ usbip_names_get_product(product_name, sizeof(product_name),
+ strtol(idVendor->value, NULL, 16),
+ strtol(idProduct->value, NULL, 16));
print_device(dev->bus_id, idVendor->value, idProduct->value,
parsable);
+ print_product_name(product_name, parsable);
for (i = 0; i < atoi(bNumIntfs->value); i++) {
snprintf(busid, sizeof(busid), "%s:%.1s.%d",
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c
index 1a84dd37e125..b12448ec69ab 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.c
+++ b/drivers/staging/usbip/userspace/src/usbip_network.c
@@ -56,7 +56,7 @@ void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
{
usbip_net_pack_uint32_t(pack, &udev->busnum);
usbip_net_pack_uint32_t(pack, &udev->devnum);
- usbip_net_pack_uint32_t(pack, &udev->speed );
+ usbip_net_pack_uint32_t(pack, &udev->speed);
usbip_net_pack_uint16_t(pack, &udev->idVendor);
usbip_net_pack_uint16_t(pack, &udev->idProduct);
@@ -248,10 +248,10 @@ int usbip_net_tcp_connect(char *hostname, char *service)
close(sockfd);
}
+ freeaddrinfo(res);
+
if (!rp)
return EAI_SYSTEM;
- freeaddrinfo(res);
-
return sockfd;
}
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h
index 2d1e070fb7b8..1bbefc993fb1 100644
--- a/drivers/staging/usbip/userspace/src/usbip_network.h
+++ b/drivers/staging/usbip/userspace/src/usbip_network.h
@@ -35,8 +35,8 @@ struct op_common {
#define PACK_OP_COMMON(pack, op_common) do {\
usbip_net_pack_uint16_t(pack, &(op_common)->version);\
- usbip_net_pack_uint16_t(pack, &(op_common)->code );\
- usbip_net_pack_uint32_t(pack, &(op_common)->status );\
+ usbip_net_pack_uint16_t(pack, &(op_common)->code);\
+ usbip_net_pack_uint32_t(pack, &(op_common)->status);\
} while (0)
/* ---------------------------------------------------------------------- */
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
index 34760cc1d10e..3e913b861dc2 100644
--- a/drivers/staging/usbip/userspace/src/usbipd.c
+++ b/drivers/staging/usbip/userspace/src/usbipd.c
@@ -60,7 +60,7 @@ static const char usbipd_help_string[] =
" -d, --debug \n"
" Print debugging information. \n"
" \n"
- " -h, --help \n"
+ " -h, --help \n"
" Print this help. \n"
" \n"
" -v, --version \n"
@@ -436,9 +436,6 @@ static int do_standalone_mode(int daemonize)
struct timespec timeout;
sigset_t sigmask;
- if (usbip_names_init(USBIDS_FILE))
- err("failed to open %s", USBIDS_FILE);
-
if (usbip_host_driver_open()) {
err("please load " USBIP_CORE_MOD_NAME ".ko and "
USBIP_HOST_DRV_NAME ".ko!");
@@ -446,8 +443,9 @@ static int do_standalone_mode(int daemonize)
}
if (daemonize) {
- if (daemon(0,0) < 0) {
+ if (daemon(0, 0) < 0) {
err("daemonizing failed: %s", strerror(errno));
+ usbip_host_driver_close();
return -1;
}
umask(0);
@@ -456,14 +454,18 @@ static int do_standalone_mode(int daemonize)
set_signal();
ai_head = do_getaddrinfo(NULL, PF_UNSPEC);
- if (!ai_head)
+ if (!ai_head) {
+ usbip_host_driver_close();
return -1;
+ }
info("starting " PROGNAME " (%s)", usbip_version_string);
nsockfd = listen_all_addrinfo(ai_head, sockfdlist);
if (nsockfd <= 0) {
err("failed to open a listening socket");
+ freeaddrinfo(ai_head);
+ usbip_host_driver_close();
return -1;
}
fds = calloc(nsockfd, sizeof(struct pollfd));
@@ -502,7 +504,6 @@ static int do_standalone_mode(int daemonize)
free(fds);
freeaddrinfo(ai_head);
usbip_host_driver_close();
- usbip_names_free();
return 0;
}
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
index 5dddc4d4b6a5..a863a98a91ce 100644
--- a/drivers/staging/usbip/vhci.h
+++ b/drivers/staging/usbip/vhci.h
@@ -95,7 +95,6 @@ struct vhci_hcd {
extern struct vhci_hcd *the_controller;
extern const struct attribute_group dev_attr_group;
-#define hardware (&the_controller->pdev.dev)
/* vhci_hcd.c */
void rh_port_connect(int rhport, enum usb_device_speed speed);
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index f1ca08478da8..d7974cb2cc6f 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -956,11 +956,10 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock(&vhci->lock);
- if (!HCD_HW_ACCESSIBLE(hcd)) {
+ if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN;
- } else {
+ else
hcd->state = HC_STATE_RUNNING;
- }
spin_unlock(&vhci->lock);
return rc;
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index faf8e607c5c6..d07fcb5ee93a 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -31,33 +31,37 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
int status;
list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
- if (priv->seqnum == seqnum) {
- urb = priv->urb;
- status = urb->status;
-
- usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
- urb, priv, seqnum);
-
- /* TODO: fix logic here to improve indent situtation */
- if (status != -EINPROGRESS) {
- if (status == -ENOENT ||
- status == -ECONNRESET)
- dev_info(&urb->dev->dev,
- "urb %p was unlinked "
- "%ssynchronuously.\n", urb,
- status == -ENOENT ? "" : "a");
- else
- dev_info(&urb->dev->dev,
- "urb %p may be in a error, "
- "status %d\n", urb, status);
- }
-
- list_del(&priv->list);
- kfree(priv);
- urb->hcpriv = NULL;
-
+ if (priv->seqnum != seqnum)
+ continue;
+
+ urb = priv->urb;
+ status = urb->status;
+
+ usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
+ urb, priv, seqnum);
+
+ switch (status) {
+ case -ENOENT:
+ /* fall through */
+ case -ECONNRESET:
+ dev_info(&urb->dev->dev,
+ "urb %p was unlinked %ssynchronuously.\n", urb,
+ status == -ENOENT ? "" : "a");
+ break;
+ case -EINPROGRESS:
+ /* no info output */
break;
+ default:
+ dev_info(&urb->dev->dev,
+ "urb %p may be in a error, status %d\n", urb,
+ status);
}
+
+ list_del(&priv->list);
+ kfree(priv);
+ urb->hcpriv = NULL;
+
+ break;
}
return urb;
@@ -202,7 +206,7 @@ static void vhci_rx_pdu(struct usbip_device *ud)
memset(&pdu, 0, sizeof(pdu));
- /* 1. receive a pdu header */
+ /* receive a pdu header */
ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
if (ret < 0) {
if (ret == -ECONNRESET)
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index d074b1ecb41a..da7f75984979 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -710,6 +710,10 @@ static int vme_user_probe(struct vme_dev *vdev)
/* Register the driver as a char device */
vme_user_cdev = cdev_alloc();
+ if (!vme_user_cdev) {
+ err = -ENOMEM;
+ goto err_char;
+ }
vme_user_cdev->ops = &vme_user_fops;
vme_user_cdev->owner = THIS_MODULE;
err = cdev_add(vme_user_cdev, MKDEV(VME_MAJOR, 0), VME_DEVS);
diff --git a/drivers/staging/vt6655/80211hdr.h b/drivers/staging/vt6655/80211hdr.h
index c4d2349260ea..28078a114d4f 100644
--- a/drivers/staging/vt6655/80211hdr.h
+++ b/drivers/staging/vt6655/80211hdr.h
@@ -86,7 +86,6 @@
#define WLAN_DATA_MAXLEN 2312
#define WLAN_A3FR_MAXLEN (WLAN_HDR_ADDR3_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)
-
#define WLAN_BEACON_FR_MAXLEN WLAN_A3FR_MAXLEN
#define WLAN_ATIM_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 0)
#define WLAN_NULLDATA_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 0)
@@ -100,7 +99,6 @@
#define WLAN_AUTHEN_FR_MAXLEN WLAN_A3FR_MAXLEN
#define WLAN_DEAUTHEN_FR_MAXLEN (WLAN_HDR_ADDR3_LEN + 2)
-
#define WLAN_WEP_NKEYS 4
#define WLAN_WEP40_KEYLEN 5
#define WLAN_WEP104_KEYLEN 13
@@ -122,7 +120,6 @@
#define WLAN_FTYPE_CTL 0x01
#define WLAN_FTYPE_DATA 0x02
-
/* Frame Subtypes */
#define WLAN_FSTYPE_ASSOCREQ 0x00
#define WLAN_FSTYPE_ASSOCRESP 0x01
@@ -155,7 +152,6 @@
#define WLAN_FSTYPE_CFPOLL 0x06
#define WLAN_FSTYPE_CFACK_CFPOLL 0x07
-
#ifdef __BIG_ENDIAN
/* GET & SET Frame Control bit */
@@ -175,7 +171,6 @@
#define WLAN_GET_SEQ_FRGNUM(n) (((unsigned short)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3))
#define WLAN_GET_SEQ_SEQNUM(n) ((((unsigned short)(n) >> 8) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
-
/* Capability Field bit */
#define WLAN_GET_CAP_INFO_ESS(n) (((n) >> 8) & BIT0)
#define WLAN_GET_CAP_INFO_IBSS(n) ((((n) >> 8) & BIT1) >> 1)
@@ -190,7 +185,6 @@
#define WLAN_GET_CAP_INFO_DSSSOFDM(n) ((((n)) & BIT13) >> 13)
#define WLAN_GET_CAP_INFO_GRPACK(n) ((((n)) & BIT14) >> 14)
-
#else
/* GET & SET Frame Control bit */
@@ -206,12 +200,10 @@
#define WLAN_GET_FC_ISWEP(n) ((((unsigned short)(n)) & (BIT14)) >> 14)
#define WLAN_GET_FC_ORDER(n) ((((unsigned short)(n)) & (BIT15)) >> 15)
-
/* Sequence Field bit */
#define WLAN_GET_SEQ_FRGNUM(n) (((unsigned short)(n)) & (BIT0|BIT1|BIT2|BIT3))
#define WLAN_GET_SEQ_SEQNUM(n) ((((unsigned short)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
-
/* Capability Field bit */
#define WLAN_GET_CAP_INFO_ESS(n) ((n) & BIT0)
#define WLAN_GET_CAP_INFO_IBSS(n) (((n) & BIT1) >> 1)
@@ -226,10 +218,8 @@
#define WLAN_GET_CAP_INFO_DSSSOFDM(n) (((n) & BIT13) >> 13)
#define WLAN_GET_CAP_INFO_GRPACK(n) (((n) & BIT14) >> 14)
-
#endif /*#ifdef __BIG_ENDIAN */
-
#define WLAN_SET_CAP_INFO_ESS(n) (n)
#define WLAN_SET_CAP_INFO_IBSS(n) ((n) << 1)
#define WLAN_SET_CAP_INFO_CFPOLLABLE(n) ((n) << 2)
@@ -243,7 +233,6 @@
#define WLAN_SET_CAP_INFO_DSSSOFDM(n) ((n) << 13)
#define WLAN_SET_CAP_INFO_GRPACK(n) ((n) << 14)
-
#define WLAN_SET_FC_PRVER(n) ((unsigned short)(n))
#define WLAN_SET_FC_FTYPE(n) (((unsigned short)(n)) << 2)
#define WLAN_SET_FC_FSTYPE(n) (((unsigned short)(n)) << 4)
@@ -269,8 +258,6 @@
#define WLAN_SET_ERP_USE_PROTECTION(n) ((n) << 1)
#define WLAN_SET_ERP_BARKER_MODE(n) ((n) << 2)
-
-
/* Support & Basic Rates field */
#define WLAN_MGMT_IS_BASICRATE(b) ((b) & BIT7)
#define WLAN_MGMT_GET_RATE(b) ((b) & ~BIT7)
@@ -288,64 +275,50 @@
#define IEEE_ADDR_GROUP 0x01
typedef struct {
- unsigned char abyAddr[6];
+ unsigned char abyAddr[6];
} IEEE_ADDR, *PIEEE_ADDR;
/* 802.11 Header Format */
typedef struct tagWLAN_80211HDR_A2 {
-
- unsigned short wFrameCtl;
- unsigned short wDurationID;
- unsigned char abyAddr1[WLAN_ADDR_LEN];
- unsigned char abyAddr2[WLAN_ADDR_LEN];
-
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A2, *PWLAN_80211HDR_A2;
typedef struct tagWLAN_80211HDR_A3 {
-
- unsigned short wFrameCtl;
- unsigned short wDurationID;
- unsigned char abyAddr1[WLAN_ADDR_LEN];
- unsigned char abyAddr2[WLAN_ADDR_LEN];
- unsigned char abyAddr3[WLAN_ADDR_LEN];
- unsigned short wSeqCtl;
-
-}__attribute__ ((__packed__))
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
+ unsigned char abyAddr3[WLAN_ADDR_LEN];
+ unsigned short wSeqCtl;
+} __attribute__ ((__packed__))
WLAN_80211HDR_A3, *PWLAN_80211HDR_A3;
typedef struct tagWLAN_80211HDR_A4 {
-
- unsigned short wFrameCtl;
- unsigned short wDurationID;
- unsigned char abyAddr1[WLAN_ADDR_LEN];
- unsigned char abyAddr2[WLAN_ADDR_LEN];
- unsigned char abyAddr3[WLAN_ADDR_LEN];
- unsigned short wSeqCtl;
- unsigned char abyAddr4[WLAN_ADDR_LEN];
-
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[WLAN_ADDR_LEN];
+ unsigned char abyAddr2[WLAN_ADDR_LEN];
+ unsigned char abyAddr3[WLAN_ADDR_LEN];
+ unsigned short wSeqCtl;
+ unsigned char abyAddr4[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A4, *PWLAN_80211HDR_A4;
-
typedef union tagUWLAN_80211HDR {
-
- WLAN_80211HDR_A2 sA2;
- WLAN_80211HDR_A3 sA3;
- WLAN_80211HDR_A4 sA4;
-
+ WLAN_80211HDR_A2 sA2;
+ WLAN_80211HDR_A3 sA3;
+ WLAN_80211HDR_A4 sA4;
} UWLAN_80211HDR, *PUWLAN_80211HDR;
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-
-
#endif /* __80211HDR_H__ */
-
-
diff --git a/drivers/staging/vt6655/80211mgr.c b/drivers/staging/vt6655/80211mgr.c
index 1ed0f260b162..4cb26f3faf26 100644
--- a/drivers/staging/vt6655/80211mgr.c
+++ b/drivers/staging/vt6655/80211mgr.c
@@ -61,24 +61,18 @@
/*--------------------- Static Definitions -------------------------*/
-
-
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Functions --------------------------*/
-
-
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Routine Description:
@@ -87,26 +81,26 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeBeacon(
- PWLAN_FR_BEACON pFrame
- )
+ PWLAN_FR_BEACON pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_CAPINFO);
+ // Fixed Fields
+ pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_CAPINFO);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID;
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID;
- return;
+ return;
}
/*+
@@ -118,118 +112,115 @@ vMgrEncodeBeacon(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrDecodeBeacon(
- PWLAN_FR_BEACON pFrame
- )
+ PWLAN_FR_BEACON pFrame
+)
{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_BEACON_OFF_CAPINFO);
-
- // Information elements
- pItem = (PWLAN_IE)((unsigned char *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
- + WLAN_BEACON_OFF_SSID);
- while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ){
-
- switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- case WLAN_EID_FH_PARMS:
- //pFrame->pFHParms = (PWLAN_IE_FH_PARMS)pItem;
- break;
- case WLAN_EID_DS_PARMS:
- if (pFrame->pDSParms == NULL)
- pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
- break;
- case WLAN_EID_CF_PARMS:
- if (pFrame->pCFParms == NULL)
- pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
- break;
- case WLAN_EID_IBSS_PARMS:
- if (pFrame->pIBSSParms == NULL)
- pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
- break;
- case WLAN_EID_TIM:
- if (pFrame->pTIM == NULL)
- pFrame->pTIM = (PWLAN_IE_TIM)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
-
- case WLAN_EID_ERP:
- if (pFrame->pERP == NULL)
- pFrame->pERP = (PWLAN_IE_ERP)pItem;
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_COUNTRY: //7
- if (pFrame->pIE_Country == NULL)
- pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
- break;
-
- case WLAN_EID_PWR_CONSTRAINT: //32
- if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
- break;
-
- case WLAN_EID_CH_SWITCH: //37
- if (pFrame->pIE_CHSW == NULL)
- pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
- break;
-
- case WLAN_EID_QUIET: //40
- if (pFrame->pIE_Quiet == NULL)
- pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
- break;
-
- case WLAN_EID_IBSS_DFS:
- if (pFrame->pIE_IBSSDFS == NULL)
- pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID);
- break;
-
- }
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- }
-
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_BEACON_OFF_CAPINFO);
+
+ // Information elements
+ pItem = (PWLAN_IE)((unsigned char *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ + WLAN_BEACON_OFF_SSID);
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+ case WLAN_EID_FH_PARMS:
+ //pFrame->pFHParms = (PWLAN_IE_FH_PARMS)pItem;
+ break;
+ case WLAN_EID_DS_PARMS:
+ if (pFrame->pDSParms == NULL)
+ pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
+ break;
+ case WLAN_EID_CF_PARMS:
+ if (pFrame->pCFParms == NULL)
+ pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
+ break;
+ case WLAN_EID_IBSS_PARMS:
+ if (pFrame->pIBSSParms == NULL)
+ pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
+ break;
+ case WLAN_EID_TIM:
+ if (pFrame->pTIM == NULL)
+ pFrame->pTIM = (PWLAN_IE_TIM)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL) {
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ }
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+
+ case WLAN_EID_ERP:
+ if (pFrame->pERP == NULL)
+ pFrame->pERP = (PWLAN_IE_ERP)pItem;
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_COUNTRY: //7
+ if (pFrame->pIE_Country == NULL)
+ pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
+ break;
+
+ case WLAN_EID_PWR_CONSTRAINT: //32
+ if (pFrame->pIE_PowerConstraint == NULL)
+ pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ break;
+
+ case WLAN_EID_CH_SWITCH: //37
+ if (pFrame->pIE_CHSW == NULL)
+ pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
+ break;
+
+ case WLAN_EID_QUIET: //40
+ if (pFrame->pIE_Quiet == NULL)
+ pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
+ break;
+
+ case WLAN_EID_IBSS_DFS:
+ if (pFrame->pIE_IBSSDFS == NULL)
+ pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in beacon decode.\n", pItem->byElementID);
+ break;
+
+ }
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+ }
+
+ return;
}
-
/*+
*
* Routine Description:
@@ -239,21 +230,19 @@ vMgrDecodeBeacon(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrEncodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- )
+ PWLAN_FR_IBSSATIM pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- pFrame->len = WLAN_HDR_ADDR3_LEN;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->len = WLAN_HDR_ADDR3_LEN;
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -263,19 +252,18 @@ vMgrEncodeIBSSATIM(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- )
+ PWLAN_FR_IBSSATIM pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -285,25 +273,23 @@ vMgrDecodeIBSSATIM(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeDisassociation(
- PWLAN_FR_DISASSOC pFrame
- )
+ PWLAN_FR_DISASSOC pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ // Fixed Fields
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_DISASSOC_OFF_REASON);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
- // Fixed Fields
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DISASSOC_OFF_REASON);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
-
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -313,20 +299,20 @@ vMgrEncodeDisassociation(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeDisassociation(
- PWLAN_FR_DISASSOC pFrame
- )
+ PWLAN_FR_DISASSOC pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DISASSOC_OFF_REASON);
+ // Fixed Fields
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_DISASSOC_OFF_REASON);
- return;
+ return;
}
/*+
@@ -338,25 +324,23 @@ vMgrDecodeDisassociation(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrEncodeAssocRequest(
- PWLAN_FR_ASSOCREQ pFrame
- )
+ PWLAN_FR_ASSOCREQ pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_LISTEN_INT);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval));
- return;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCREQ_OFF_LISTEN_INT);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval));
+ return;
}
-
/*+
*
* Routine Description: (AP)
@@ -366,61 +350,61 @@ vMgrEncodeAssocRequest(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeAssocRequest(
- PWLAN_FR_ASSOCREQ pFrame
- )
+ PWLAN_FR_ASSOCREQ pFrame
+)
{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_LISTEN_INT);
-
- // Information elements
- pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCREQ_OFF_SSID);
-
- while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
- switch (pItem->byElementID){
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
- pItem->byElementID);
- break;
- }
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- }
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCREQ_OFF_LISTEN_INT);
+
+ // Information elements
+ pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCREQ_OFF_SSID);
+
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL) {
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ }
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in assocreq decode.\n",
+ pItem->byElementID);
+ break;
+ }
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+ }
+ return;
}
/*+
@@ -432,29 +416,28 @@ vMgrDecodeAssocRequest(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeAssocResponse(
- PWLAN_FR_ASSOCRESP pFrame
- )
+ PWLAN_FR_ASSOCRESP pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_AID);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID
- + sizeof(*(pFrame->pwAid));
-
- return;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_AID);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID
+ + sizeof(*(pFrame->pwAid));
+
+ return;
}
-
/*+
*
* Routine Description:
@@ -464,44 +447,42 @@ vMgrEncodeAssocResponse(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeAssocResponse(
- PWLAN_FR_ASSOCRESP pFrame
- )
+ PWLAN_FR_ASSOCRESP pFrame
+)
{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_AID);
-
- // Information elements
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_ASSOCRESP_OFF_SUPP_RATES);
-
- pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
-
- if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
- (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
- }
- else {
- pFrame->pExtSuppRates = NULL;
- }
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_AID);
+
+ // Information elements
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_ASSOCRESP_OFF_SUPP_RATES);
+
+ pItem = (PWLAN_IE)(pFrame->pSuppRates);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
+ (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
+ } else {
+ pFrame->pExtSuppRates = NULL;
+ }
+ return;
}
-
/*+
*
* Routine Description:
@@ -511,28 +492,27 @@ vMgrDecodeAssocResponse(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeReassocRequest(
- PWLAN_FR_REASSOCREQ pFrame
- )
+ PWLAN_FR_REASSOCREQ pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_LISTEN_INT);
- pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CURR_AP);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP));
-
- return;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_LISTEN_INT);
+ pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_CURR_AP);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP));
+
+ return;
}
-
/*+
*
* Routine Description: (AP)
@@ -542,69 +522,65 @@ vMgrEncodeReassocRequest(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrDecodeReassocRequest(
- PWLAN_FR_REASSOCREQ pFrame
- )
+ PWLAN_FR_REASSOCREQ pFrame
+)
{
- PWLAN_IE pItem;
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_LISTEN_INT);
- pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_CURR_AP);
-
- // Information elements
- pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCREQ_OFF_SSID);
-
- while(((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
-
- switch (pItem->byElementID){
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
-
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
- pItem->byElementID);
- break;
- }
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- }
- return;
+ PWLAN_IE pItem;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_CAP_INFO);
+ pFrame->pwListenInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_LISTEN_INT);
+ pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_CURR_AP);
+
+ // Information elements
+ pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCREQ_OFF_SSID);
+
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL) {
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ }
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unrecognized EID=%dd in reassocreq decode.\n",
+ pItem->byElementID);
+ break;
+ }
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+ }
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -614,17 +590,16 @@ vMgrDecodeReassocRequest(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrEncodeProbeRequest(
- PWLAN_FR_PROBEREQ pFrame
- )
+ PWLAN_FR_PROBEREQ pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- pFrame->len = WLAN_HDR_ADDR3_LEN;
- return;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->len = WLAN_HDR_ADDR3_LEN;
+ return;
}
/*+
@@ -636,49 +611,47 @@ vMgrEncodeProbeRequest(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeProbeRequest(
- PWLAN_FR_PROBEREQ pFrame
- )
+ PWLAN_FR_PROBEREQ pFrame
+)
{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Information elements
- pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)));
-
- while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ) {
-
- switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
-
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID);
- break;
- }
-
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- }
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Information elements
+ pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)));
+
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in probereq\n", pItem->byElementID);
+ break;
+ }
+
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+ }
+ return;
}
-
/*+
*
* Routine Description:
@@ -688,32 +661,29 @@ vMgrDecodeProbeRequest(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrEncodeProbeResponse(
- PWLAN_FR_PROBERESP pFrame
- )
+ PWLAN_FR_PROBERESP pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_CAP_INFO);
+ // Fixed Fields
+ pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_CAP_INFO);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO +
- sizeof(*(pFrame->pwCapInfo));
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO +
+ sizeof(*(pFrame->pwCapInfo));
- return;
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -723,111 +693,109 @@ vMgrEncodeProbeResponse(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeProbeResponse(
- PWLAN_FR_PROBERESP pFrame
- )
+ PWLAN_FR_PROBERESP pFrame
+)
{
- PWLAN_IE pItem;
-
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_CAP_INFO);
-
- // Information elements
- pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_PROBERESP_OFF_SSID);
-
- while( ((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len) ) {
- switch (pItem->byElementID) {
- case WLAN_EID_SSID:
- if (pFrame->pSSID == NULL)
- pFrame->pSSID = (PWLAN_IE_SSID)pItem;
- break;
- case WLAN_EID_SUPP_RATES:
- if (pFrame->pSuppRates == NULL)
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
- case WLAN_EID_FH_PARMS:
- break;
- case WLAN_EID_DS_PARMS:
- if (pFrame->pDSParms == NULL)
- pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
- break;
- case WLAN_EID_CF_PARMS:
- if (pFrame->pCFParms == NULL)
- pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
- break;
- case WLAN_EID_IBSS_PARMS:
- if (pFrame->pIBSSParms == NULL)
- pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
- break;
-
- case WLAN_EID_RSN:
- if (pFrame->pRSN == NULL) {
- pFrame->pRSN = (PWLAN_IE_RSN)pItem;
- }
- break;
- case WLAN_EID_RSN_WPA:
- if (pFrame->pRSNWPA == NULL) {
- if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
- pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
- }
- break;
- case WLAN_EID_ERP:
- if (pFrame->pERP == NULL)
- pFrame->pERP = (PWLAN_IE_ERP)pItem;
- break;
- case WLAN_EID_EXTSUPP_RATES:
- if (pFrame->pExtSuppRates == NULL)
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- break;
-
- case WLAN_EID_COUNTRY: //7
- if (pFrame->pIE_Country == NULL)
- pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
- break;
-
- case WLAN_EID_PWR_CONSTRAINT: //32
- if (pFrame->pIE_PowerConstraint == NULL)
- pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
- break;
-
- case WLAN_EID_CH_SWITCH: //37
- if (pFrame->pIE_CHSW == NULL)
- pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
- break;
-
- case WLAN_EID_QUIET: //40
- if (pFrame->pIE_Quiet == NULL)
- pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
- break;
-
- case WLAN_EID_IBSS_DFS:
- if (pFrame->pIE_IBSSDFS == NULL)
- pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID);
- break;
- }
-
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
- }
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pqwTimestamp = (PQWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_TS);
+ pFrame->pwBeaconInterval = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_BCN_INT);
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_CAP_INFO);
+
+ // Information elements
+ pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_PROBERESP_OFF_SSID);
+
+ while (((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) {
+ switch (pItem->byElementID) {
+ case WLAN_EID_SSID:
+ if (pFrame->pSSID == NULL)
+ pFrame->pSSID = (PWLAN_IE_SSID)pItem;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ if (pFrame->pSuppRates == NULL)
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+ case WLAN_EID_FH_PARMS:
+ break;
+ case WLAN_EID_DS_PARMS:
+ if (pFrame->pDSParms == NULL)
+ pFrame->pDSParms = (PWLAN_IE_DS_PARMS)pItem;
+ break;
+ case WLAN_EID_CF_PARMS:
+ if (pFrame->pCFParms == NULL)
+ pFrame->pCFParms = (PWLAN_IE_CF_PARMS)pItem;
+ break;
+ case WLAN_EID_IBSS_PARMS:
+ if (pFrame->pIBSSParms == NULL)
+ pFrame->pIBSSParms = (PWLAN_IE_IBSS_PARMS)pItem;
+ break;
+
+ case WLAN_EID_RSN:
+ if (pFrame->pRSN == NULL) {
+ pFrame->pRSN = (PWLAN_IE_RSN)pItem;
+ }
+ break;
+ case WLAN_EID_RSN_WPA:
+ if (pFrame->pRSNWPA == NULL) {
+ if (WPAb_Is_RSN((PWLAN_IE_RSN_EXT)pItem) == true)
+ pFrame->pRSNWPA = (PWLAN_IE_RSN_EXT)pItem;
+ }
+ break;
+ case WLAN_EID_ERP:
+ if (pFrame->pERP == NULL)
+ pFrame->pERP = (PWLAN_IE_ERP)pItem;
+ break;
+ case WLAN_EID_EXTSUPP_RATES:
+ if (pFrame->pExtSuppRates == NULL)
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ break;
+
+ case WLAN_EID_COUNTRY: //7
+ if (pFrame->pIE_Country == NULL)
+ pFrame->pIE_Country = (PWLAN_IE_COUNTRY)pItem;
+ break;
+
+ case WLAN_EID_PWR_CONSTRAINT: //32
+ if (pFrame->pIE_PowerConstraint == NULL)
+ pFrame->pIE_PowerConstraint = (PWLAN_IE_PW_CONST)pItem;
+ break;
+
+ case WLAN_EID_CH_SWITCH: //37
+ if (pFrame->pIE_CHSW == NULL)
+ pFrame->pIE_CHSW = (PWLAN_IE_CH_SW)pItem;
+ break;
+
+ case WLAN_EID_QUIET: //40
+ if (pFrame->pIE_Quiet == NULL)
+ pFrame->pIE_Quiet = (PWLAN_IE_QUIET)pItem;
+ break;
+
+ case WLAN_EID_IBSS_DFS:
+ if (pFrame->pIE_IBSSDFS == NULL)
+ pFrame->pIE_IBSSDFS = (PWLAN_IE_IBSS_DFS)pItem;
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Bad EID=%dd in proberesp\n", pItem->byElementID);
+ break;
+ }
+
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+ }
+ return;
}
-
/*+
*
* Routine Description:
@@ -837,28 +805,27 @@ vMgrDecodeProbeResponse(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeAuthen(
- PWLAN_FR_AUTHEN pFrame
- )
+ PWLAN_FR_AUTHEN pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_STATUS);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
-
- return;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_AUTH_ALG);
+ pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_AUTH_SEQ);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_STATUS);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
+
+ return;
}
-
/*+
*
* Routine Description:
@@ -868,37 +835,36 @@ vMgrEncodeAuthen(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeAuthen(
- PWLAN_FR_AUTHEN pFrame
- )
+ PWLAN_FR_AUTHEN pFrame
+)
{
- PWLAN_IE pItem;
+ PWLAN_IE pItem;
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_STATUS);
+ // Fixed Fields
+ pFrame->pwAuthAlgorithm = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_AUTH_ALG);
+ pFrame->pwAuthSequence = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_AUTH_SEQ);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_STATUS);
- // Information elements
- pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_AUTHEN_OFF_CHALLENGE);
+ // Information elements
+ pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_AUTHEN_OFF_CHALLENGE);
- if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) {
- pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem;
- }
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE)) {
+ pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem;
+ }
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -908,24 +874,23 @@ vMgrDecodeAuthen(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeDeauthen(
- PWLAN_FR_DEAUTHEN pFrame
- )
+ PWLAN_FR_DEAUTHEN pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DEAUTHEN_OFF_REASON);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
+ // Fixed Fields
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_DEAUTHEN_OFF_REASON);
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -935,23 +900,22 @@ vMgrEncodeDeauthen(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDecodeDeauthen(
- PWLAN_FR_DEAUTHEN pFrame
- )
+ PWLAN_FR_DEAUTHEN pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_DEAUTHEN_OFF_REASON);
+ // Fixed Fields
+ pFrame->pwReason = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_DEAUTHEN_OFF_REASON);
- return;
+ return;
}
-
/*+
*
* Routine Description: (AP)
@@ -961,29 +925,28 @@ vMgrDecodeDeauthen(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrEncodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- )
+ PWLAN_FR_REASSOCRESP pFrame
+)
{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_AID);
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_AID);
- pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
+ pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -993,36 +956,35 @@ vMgrEncodeReassocResponse(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrDecodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- )
+ PWLAN_FR_REASSOCRESP pFrame
+)
{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- // Fixed Fields
- pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_AID);
-
- //Information elements
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_SUPP_RATES);
-
- pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
-
- if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
- (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
- }
- return;
+ PWLAN_IE pItem;
+
+ pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
+
+ // Fixed Fields
+ pFrame->pwCapInfo = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_CAP_INFO);
+ pFrame->pwStatus = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_STATUS);
+ pFrame->pwAid = (unsigned short *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_AID);
+
+ //Information elements
+ pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ + WLAN_REASSOCRESP_OFF_SUPP_RATES);
+
+ pItem = (PWLAN_IE)(pFrame->pSuppRates);
+ pItem = (PWLAN_IE)(((unsigned char *)pItem) + 2 + pItem->len);
+
+ if ((((unsigned char *)pItem) < (pFrame->pBuf + pFrame->len)) &&
+ (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
+ }
+ return;
}
diff --git a/drivers/staging/vt6655/80211mgr.h b/drivers/staging/vt6655/80211mgr.h
index 65780f28db41..16402cf5d25e 100644
--- a/drivers/staging/vt6655/80211mgr.h
+++ b/drivers/staging/vt6655/80211mgr.h
@@ -65,7 +65,6 @@
// reference WiFi WPA spec.
#define WLAN_EID_RSN_WPA 221
-
#define WLAN_EID_ERP_NONERP_PRESENT 0x01
#define WLAN_EID_ERP_USE_PROTECTION 0x02
#define WLAN_EID_ERP_BARKER_MODE 0x04
@@ -132,14 +131,10 @@
#define WLAN_MGMT_STATUS_INVALID_RSN_IE_CAP 45
#define WLAN_MGMT_STATUS_CIPHER_REJECT 46
-
-
// Auth Algorithm
#define WLAN_AUTH_ALG_OPENSYSTEM 0
#define WLAN_AUTH_ALG_SHAREDKEY 1
-
-
// Management Frame Field Offsets
// Note: Not all fields are listed because of variable lengths.
// Note: These offsets are from the start of the frame data
@@ -184,7 +179,6 @@
#define WLAN_DEAUTHEN_OFF_REASON 0
-
//
// Cipher Suite Selectors defined in 802.11i
//
@@ -217,611 +211,567 @@
#define MEASURE_MODE_INCAPABLE 0x02
#define MEASURE_MODE_REFUSED 0x04
-
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Types ------------------------------*/
-
// Information Element Types
#pragma pack(1)
typedef struct tagWLAN_IE {
- unsigned char byElementID;
- unsigned char len;
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+} __attribute__ ((__packed__))
WLAN_IE, *PWLAN_IE;
-
// Service Set Identity (SSID)
#pragma pack(1)
typedef struct tagWLAN_IE_SSID {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abySSID[1];
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abySSID[1];
+} __attribute__ ((__packed__))
WLAN_IE_SSID, *PWLAN_IE_SSID;
-
// Supported Rates
#pragma pack(1)
typedef struct tagWLAN_IE_SUPP_RATES {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyRates[1];
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyRates[1];
+} __attribute__ ((__packed__))
WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES;
-
-
// FH Parameter Set
#pragma pack(1)
typedef struct _WLAN_IE_FH_PARMS {
- unsigned char byElementID;
- unsigned char len;
- unsigned short wDwellTime;
- unsigned char byHopSet;
- unsigned char byHopPattern;
- unsigned char byHopIndex;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wDwellTime;
+ unsigned char byHopSet;
+ unsigned char byHopPattern;
+ unsigned char byHopIndex;
} WLAN_IE_FH_PARMS, *PWLAN_IE_FH_PARMS;
// DS Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_DS_PARMS {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byCurrChannel;
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byCurrChannel;
+} __attribute__ ((__packed__))
WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS;
-
// CF Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_CF_PARMS {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byCFPCount;
- unsigned char byCFPPeriod;
- unsigned short wCFPMaxDuration;
- unsigned short wCFPDurRemaining;
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byCFPCount;
+ unsigned char byCFPPeriod;
+ unsigned short wCFPMaxDuration;
+ unsigned short wCFPDurRemaining;
+} __attribute__ ((__packed__))
WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS;
-
// TIM
#pragma pack(1)
typedef struct tagWLAN_IE_TIM {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byDTIMCount;
- unsigned char byDTIMPeriod;
- unsigned char byBitMapCtl;
- unsigned char byVirtBitMap[1];
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byDTIMCount;
+ unsigned char byDTIMPeriod;
+ unsigned char byBitMapCtl;
+ unsigned char byVirtBitMap[1];
+} __attribute__ ((__packed__))
WLAN_IE_TIM, *PWLAN_IE_TIM;
-
// IBSS Parameter Set
#pragma pack(1)
typedef struct tagWLAN_IE_IBSS_PARMS {
- unsigned char byElementID;
- unsigned char len;
- unsigned short wATIMWindow;
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wATIMWindow;
+} __attribute__ ((__packed__))
WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS;
-
// Challenge Text
#pragma pack(1)
typedef struct tagWLAN_IE_CHALLENGE {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyChallenge[1];
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyChallenge[1];
+} __attribute__ ((__packed__))
WLAN_IE_CHALLENGE, *PWLAN_IE_CHALLENGE;
-
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_EXT {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyOUI[4];
- unsigned short wVersion;
- unsigned char abyMulticast[4];
- unsigned short wPKCount;
- struct {
- unsigned char abyOUI[4];
- } PKSList[1]; // the rest is variable so need to
- // overlay ieauth structure
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyOUI[4];
+ unsigned short wVersion;
+ unsigned char abyMulticast[4];
+ unsigned short wPKCount;
+ struct {
+ unsigned char abyOUI[4];
+ } PKSList[1]; // the rest is variable so need to
+ // overlay ieauth structure
} WLAN_IE_RSN_EXT, *PWLAN_IE_RSN_EXT;
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_AUTH {
- unsigned short wAuthCount;
- struct {
- unsigned char abyOUI[4];
- } AuthKSList[1];
+ unsigned short wAuthCount;
+ struct {
+ unsigned char abyOUI[4];
+ } AuthKSList[1];
} WLAN_IE_RSN_AUTH, *PWLAN_IE_RSN_AUTH;
// RSN Identity
#pragma pack(1)
typedef struct tagWLAN_IE_RSN {
- unsigned char byElementID;
- unsigned char len;
- unsigned short wVersion;
- unsigned char abyRSN[WLAN_MIN_ARRAY];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned short wVersion;
+ unsigned char abyRSN[WLAN_MIN_ARRAY];
} WLAN_IE_RSN, *PWLAN_IE_RSN;
-
// ERP
#pragma pack(1)
typedef struct tagWLAN_IE_ERP {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byContext;
-}__attribute__ ((__packed__))
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byContext;
+} __attribute__ ((__packed__))
WLAN_IE_ERP, *PWLAN_IE_ERP;
-
#pragma pack(1)
typedef struct _MEASEURE_REQ {
- unsigned char byChannel;
- unsigned char abyStartTime[8];
- unsigned char abyDuration[2];
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
} MEASEURE_REQ, *PMEASEURE_REQ,
- MEASEURE_REQ_BASIC, *PMEASEURE_REQ_BASIC,
- MEASEURE_REQ_CCA, *PMEASEURE_REQ_CCA,
- MEASEURE_REQ_RPI, *PMEASEURE_REQ_RPI;
+ MEASEURE_REQ_BASIC, *PMEASEURE_REQ_BASIC,
+ MEASEURE_REQ_CCA, *PMEASEURE_REQ_CCA,
+ MEASEURE_REQ_RPI, *PMEASEURE_REQ_RPI;
typedef struct _MEASEURE_REP_BASIC {
- unsigned char byChannel;
- unsigned char abyStartTime[8];
- unsigned char abyDuration[2];
- unsigned char byMap;
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char byMap;
} MEASEURE_REP_BASIC, *PMEASEURE_REP_BASIC;
typedef struct _MEASEURE_REP_CCA {
- unsigned char byChannel;
- unsigned char abyStartTime[8];
- unsigned char abyDuration[2];
- unsigned char byCCABusyFraction;
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char byCCABusyFraction;
} MEASEURE_REP_CCA, *PMEASEURE_REP_CCA;
typedef struct _MEASEURE_REP_RPI {
- unsigned char byChannel;
- unsigned char abyStartTime[8];
- unsigned char abyDuration[2];
- unsigned char abyRPIdensity[8];
+ unsigned char byChannel;
+ unsigned char abyStartTime[8];
+ unsigned char abyDuration[2];
+ unsigned char abyRPIdensity[8];
} MEASEURE_REP_RPI, *PMEASEURE_REP_RPI;
typedef union _MEASEURE_REP {
-
- MEASEURE_REP_BASIC sBasic;
- MEASEURE_REP_CCA sCCA;
- MEASEURE_REP_RPI sRPI;
-
+ MEASEURE_REP_BASIC sBasic;
+ MEASEURE_REP_CCA sCCA;
+ MEASEURE_REP_RPI sRPI;
} MEASEURE_REP, *PMEASEURE_REP;
typedef struct _WLAN_IE_MEASURE_REQ {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byToken;
- unsigned char byMode;
- unsigned char byType;
- MEASEURE_REQ sReq;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byToken;
+ unsigned char byMode;
+ unsigned char byType;
+ MEASEURE_REQ sReq;
} WLAN_IE_MEASURE_REQ, *PWLAN_IE_MEASURE_REQ;
typedef struct _WLAN_IE_MEASURE_REP {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byToken;
- unsigned char byMode;
- unsigned char byType;
- MEASEURE_REP sRep;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byToken;
+ unsigned char byMode;
+ unsigned char byType;
+ MEASEURE_REP sRep;
} WLAN_IE_MEASURE_REP, *PWLAN_IE_MEASURE_REP;
typedef struct _WLAN_IE_CH_SW {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byMode;
- unsigned char byChannel;
- unsigned char byCount;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byMode;
+ unsigned char byChannel;
+ unsigned char byCount;
} WLAN_IE_CH_SW, *PWLAN_IE_CH_SW;
typedef struct _WLAN_IE_QUIET {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byQuietCount;
- unsigned char byQuietPeriod;
- unsigned char abyQuietDuration[2];
- unsigned char abyQuietOffset[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byQuietCount;
+ unsigned char byQuietPeriod;
+ unsigned char abyQuietDuration[2];
+ unsigned char abyQuietOffset[2];
} WLAN_IE_QUIET, *PWLAN_IE_QUIET;
typedef struct _WLAN_IE_COUNTRY {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyCountryString[3];
- unsigned char abyCountryInfo[3];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyCountryString[3];
+ unsigned char abyCountryInfo[3];
} WLAN_IE_COUNTRY, *PWLAN_IE_COUNTRY;
typedef struct _WLAN_IE_PW_CONST {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byPower;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byPower;
} WLAN_IE_PW_CONST, *PWLAN_IE_PW_CONST;
typedef struct _WLAN_IE_PW_CAP {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byMinPower;
- unsigned char byMaxPower;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byMinPower;
+ unsigned char byMaxPower;
} WLAN_IE_PW_CAP, *PWLAN_IE_PW_CAP;
typedef struct _WLAN_IE_SUPP_CH {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyChannelTuple[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyChannelTuple[2];
} WLAN_IE_SUPP_CH, *PWLAN_IE_SUPP_CH;
typedef struct _WLAN_IE_TPC_REQ {
- unsigned char byElementID;
- unsigned char len;
+ unsigned char byElementID;
+ unsigned char len;
} WLAN_IE_TPC_REQ, *PWLAN_IE_TPC_REQ;
typedef struct _WLAN_IE_TPC_REP {
- unsigned char byElementID;
- unsigned char len;
- unsigned char byTxPower;
- unsigned char byLinkMargin;
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char byTxPower;
+ unsigned char byLinkMargin;
} WLAN_IE_TPC_REP, *PWLAN_IE_TPC_REP;
-
typedef struct _WLAN_IE_IBSS_DFS {
- unsigned char byElementID;
- unsigned char len;
- unsigned char abyDFSOwner[6];
- unsigned char byDFSRecovery;
- unsigned char abyChannelMap[2];
+ unsigned char byElementID;
+ unsigned char len;
+ unsigned char abyDFSOwner[6];
+ unsigned char byDFSRecovery;
+ unsigned char abyChannelMap[2];
} WLAN_IE_IBSS_DFS, *PWLAN_IE_IBSS_DFS;
#pragma pack()
-
-
// Frame Types
// prototype structure, all mgmt frame types will start with these members
typedef struct tagWLAN_FR_MGMT {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
} WLAN_FR_MGMT, *PWLAN_FR_MGMT;
// Beacon frame
typedef struct tagWLAN_FR_BEACON {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- // fixed fields
- PQWORD pqwTimestamp;
- unsigned short *pwBeaconInterval;
- unsigned short *pwCapInfo;
- /*-- info elements ----------*/
- PWLAN_IE_SSID pSSID;
- PWLAN_IE_SUPP_RATES pSuppRates;
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ // fixed fields
+ PQWORD pqwTimestamp;
+ unsigned short *pwBeaconInterval;
+ unsigned short *pwCapInfo;
+ /*-- info elements ----------*/
+ PWLAN_IE_SSID pSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates;
// PWLAN_IE_FH_PARMS pFHParms;
- PWLAN_IE_DS_PARMS pDSParms;
- PWLAN_IE_CF_PARMS pCFParms;
- PWLAN_IE_TIM pTIM;
- PWLAN_IE_IBSS_PARMS pIBSSParms;
- PWLAN_IE_RSN pRSN;
- PWLAN_IE_RSN_EXT pRSNWPA;
- PWLAN_IE_ERP pERP;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
- PWLAN_IE_COUNTRY pIE_Country;
- PWLAN_IE_PW_CONST pIE_PowerConstraint;
- PWLAN_IE_CH_SW pIE_CHSW;
- PWLAN_IE_IBSS_DFS pIE_IBSSDFS;
- PWLAN_IE_QUIET pIE_Quiet;
-
+ PWLAN_IE_DS_PARMS pDSParms;
+ PWLAN_IE_CF_PARMS pCFParms;
+ PWLAN_IE_TIM pTIM;
+ PWLAN_IE_IBSS_PARMS pIBSSParms;
+ PWLAN_IE_RSN pRSN;
+ PWLAN_IE_RSN_EXT pRSNWPA;
+ PWLAN_IE_ERP pERP;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
+ PWLAN_IE_COUNTRY pIE_Country;
+ PWLAN_IE_PW_CONST pIE_PowerConstraint;
+ PWLAN_IE_CH_SW pIE_CHSW;
+ PWLAN_IE_IBSS_DFS pIE_IBSSDFS;
+ PWLAN_IE_QUIET pIE_Quiet;
} WLAN_FR_BEACON, *PWLAN_FR_BEACON;
-
// IBSS ATIM frame
typedef struct tagWLAN_FR_IBSSATIM {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
-
- // fixed fields
- // info elements
- // this frame type has a null body
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+
+ // fixed fields
+ // info elements
+ // this frame type has a null body
} WLAN_FR_IBSSATIM, *PWLAN_FR_IBSSATIM;
// Disassociation
typedef struct tagWLAN_FR_DISASSOC {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwReason;
- /*-- info elements ----------*/
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwReason;
+ /*-- info elements ----------*/
} WLAN_FR_DISASSOC, *PWLAN_FR_DISASSOC;
// Association Request
typedef struct tagWLAN_FR_ASSOCREQ {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwCapInfo;
- unsigned short *pwListenInterval;
- /*-- info elements ----------*/
- PWLAN_IE_SSID pSSID;
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_RSN pRSN;
- PWLAN_IE_RSN_EXT pRSNWPA;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
- PWLAN_IE_PW_CAP pCurrPowerCap;
- PWLAN_IE_SUPP_CH pCurrSuppCh;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwCapInfo;
+ unsigned short *pwListenInterval;
+ /*-- info elements ----------*/
+ PWLAN_IE_SSID pSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_RSN pRSN;
+ PWLAN_IE_RSN_EXT pRSNWPA;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
+ PWLAN_IE_PW_CAP pCurrPowerCap;
+ PWLAN_IE_SUPP_CH pCurrSuppCh;
} WLAN_FR_ASSOCREQ, *PWLAN_FR_ASSOCREQ;
// Association Response
typedef struct tagWLAN_FR_ASSOCRESP {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwCapInfo;
- unsigned short *pwStatus;
- unsigned short *pwAid;
- /*-- info elements ----------*/
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwCapInfo;
+ unsigned short *pwStatus;
+ unsigned short *pwAid;
+ /*-- info elements ----------*/
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
} WLAN_FR_ASSOCRESP, *PWLAN_FR_ASSOCRESP;
// Reassociation Request
typedef struct tagWLAN_FR_REASSOCREQ {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
-
- /*-- fixed fields -----------*/
- unsigned short *pwCapInfo;
- unsigned short *pwListenInterval;
- PIEEE_ADDR pAddrCurrAP;
-
- /*-- info elements ----------*/
- PWLAN_IE_SSID pSSID;
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_RSN pRSN;
- PWLAN_IE_RSN_EXT pRSNWPA;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+
+ /*-- fixed fields -----------*/
+ unsigned short *pwCapInfo;
+ unsigned short *pwListenInterval;
+ PIEEE_ADDR pAddrCurrAP;
+
+ /*-- info elements ----------*/
+ PWLAN_IE_SSID pSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_RSN pRSN;
+ PWLAN_IE_RSN_EXT pRSNWPA;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
} WLAN_FR_REASSOCREQ, *PWLAN_FR_REASSOCREQ;
// Reassociation Response
typedef struct tagWLAN_FR_REASSOCRESP {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwCapInfo;
- unsigned short *pwStatus;
- unsigned short *pwAid;
- /*-- info elements ----------*/
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwCapInfo;
+ unsigned short *pwStatus;
+ unsigned short *pwAid;
+ /*-- info elements ----------*/
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
} WLAN_FR_REASSOCRESP, *PWLAN_FR_REASSOCRESP;
// Probe Request
typedef struct tagWLAN_FR_PROBEREQ {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- /*-- info elements ----------*/
- PWLAN_IE_SSID pSSID;
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ /*-- info elements ----------*/
+ PWLAN_IE_SSID pSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
} WLAN_FR_PROBEREQ, *PWLAN_FR_PROBEREQ;
// Probe Response
typedef struct tagWLAN_FR_PROBERESP {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- PQWORD pqwTimestamp;
- unsigned short *pwBeaconInterval;
- unsigned short *pwCapInfo;
- /*-- info elements ----------*/
- PWLAN_IE_SSID pSSID;
- PWLAN_IE_SUPP_RATES pSuppRates;
- PWLAN_IE_DS_PARMS pDSParms;
- PWLAN_IE_CF_PARMS pCFParms;
- PWLAN_IE_IBSS_PARMS pIBSSParms;
- PWLAN_IE_RSN pRSN;
- PWLAN_IE_RSN_EXT pRSNWPA;
- PWLAN_IE_ERP pERP;
- PWLAN_IE_SUPP_RATES pExtSuppRates;
- PWLAN_IE_COUNTRY pIE_Country;
- PWLAN_IE_PW_CONST pIE_PowerConstraint;
- PWLAN_IE_CH_SW pIE_CHSW;
- PWLAN_IE_IBSS_DFS pIE_IBSSDFS;
- PWLAN_IE_QUIET pIE_Quiet;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ PQWORD pqwTimestamp;
+ unsigned short *pwBeaconInterval;
+ unsigned short *pwCapInfo;
+ /*-- info elements ----------*/
+ PWLAN_IE_SSID pSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates;
+ PWLAN_IE_DS_PARMS pDSParms;
+ PWLAN_IE_CF_PARMS pCFParms;
+ PWLAN_IE_IBSS_PARMS pIBSSParms;
+ PWLAN_IE_RSN pRSN;
+ PWLAN_IE_RSN_EXT pRSNWPA;
+ PWLAN_IE_ERP pERP;
+ PWLAN_IE_SUPP_RATES pExtSuppRates;
+ PWLAN_IE_COUNTRY pIE_Country;
+ PWLAN_IE_PW_CONST pIE_PowerConstraint;
+ PWLAN_IE_CH_SW pIE_CHSW;
+ PWLAN_IE_IBSS_DFS pIE_IBSSDFS;
+ PWLAN_IE_QUIET pIE_Quiet;
} WLAN_FR_PROBERESP, *PWLAN_FR_PROBERESP;
// Authentication
typedef struct tagWLAN_FR_AUTHEN {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwAuthAlgorithm;
- unsigned short *pwAuthSequence;
- unsigned short *pwStatus;
- /*-- info elements ----------*/
- PWLAN_IE_CHALLENGE pChallenge;
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwAuthAlgorithm;
+ unsigned short *pwAuthSequence;
+ unsigned short *pwStatus;
+ /*-- info elements ----------*/
+ PWLAN_IE_CHALLENGE pChallenge;
} WLAN_FR_AUTHEN, *PWLAN_FR_AUTHEN;
// Deauthenication
typedef struct tagWLAN_FR_DEAUTHEN {
-
- unsigned int uType;
- unsigned int len;
- unsigned char *pBuf;
- PUWLAN_80211HDR pHdr;
- /*-- fixed fields -----------*/
- unsigned short *pwReason;
-
- /*-- info elements ----------*/
-
+ unsigned int uType;
+ unsigned int len;
+ unsigned char *pBuf;
+ PUWLAN_80211HDR pHdr;
+ /*-- fixed fields -----------*/
+ unsigned short *pwReason;
+
+ /*-- info elements ----------*/
} WLAN_FR_DEAUTHEN, *PWLAN_FR_DEAUTHEN;
/*--------------------- Export Functions --------------------------*/
void
vMgrEncodeBeacon(
- PWLAN_FR_BEACON pFrame
- );
+ PWLAN_FR_BEACON pFrame
+);
void
vMgrDecodeBeacon(
- PWLAN_FR_BEACON pFrame
- );
+ PWLAN_FR_BEACON pFrame
+);
void
vMgrEncodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- );
+ PWLAN_FR_IBSSATIM pFrame
+);
void
vMgrDecodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- );
+ PWLAN_FR_IBSSATIM pFrame
+);
void
vMgrEncodeDisassociation(
- PWLAN_FR_DISASSOC pFrame
- );
+ PWLAN_FR_DISASSOC pFrame
+);
void
vMgrDecodeDisassociation(
- PWLAN_FR_DISASSOC pFrame
- );
+ PWLAN_FR_DISASSOC pFrame
+);
void
vMgrEncodeAssocRequest(
- PWLAN_FR_ASSOCREQ pFrame
- );
+ PWLAN_FR_ASSOCREQ pFrame
+);
void
vMgrDecodeAssocRequest(
- PWLAN_FR_ASSOCREQ pFrame
- );
+ PWLAN_FR_ASSOCREQ pFrame
+);
void
vMgrEncodeAssocResponse(
- PWLAN_FR_ASSOCRESP pFrame
- );
+ PWLAN_FR_ASSOCRESP pFrame
+);
void
vMgrDecodeAssocResponse(
- PWLAN_FR_ASSOCRESP pFrame
- );
+ PWLAN_FR_ASSOCRESP pFrame
+);
void
vMgrEncodeReassocRequest(
- PWLAN_FR_REASSOCREQ pFrame
- );
+ PWLAN_FR_REASSOCREQ pFrame
+);
void
vMgrDecodeReassocRequest(
- PWLAN_FR_REASSOCREQ pFrame
- );
+ PWLAN_FR_REASSOCREQ pFrame
+);
void
vMgrEncodeProbeRequest(
- PWLAN_FR_PROBEREQ pFrame
- );
+ PWLAN_FR_PROBEREQ pFrame
+);
void
vMgrDecodeProbeRequest(
- PWLAN_FR_PROBEREQ pFrame
- );
+ PWLAN_FR_PROBEREQ pFrame
+);
void
vMgrEncodeProbeResponse(
- PWLAN_FR_PROBERESP pFrame
- );
+ PWLAN_FR_PROBERESP pFrame
+);
void
vMgrDecodeProbeResponse(
- PWLAN_FR_PROBERESP pFrame
- );
+ PWLAN_FR_PROBERESP pFrame
+);
void
vMgrEncodeAuthen(
- PWLAN_FR_AUTHEN pFrame
- );
+ PWLAN_FR_AUTHEN pFrame
+);
void
vMgrDecodeAuthen(
- PWLAN_FR_AUTHEN pFrame
- );
+ PWLAN_FR_AUTHEN pFrame
+);
void
vMgrEncodeDeauthen(
- PWLAN_FR_DEAUTHEN pFrame
- );
+ PWLAN_FR_DEAUTHEN pFrame
+);
void
vMgrDecodeDeauthen(
- PWLAN_FR_DEAUTHEN pFrame
- );
+ PWLAN_FR_DEAUTHEN pFrame
+);
void
vMgrEncodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- );
+ PWLAN_FR_REASSOCRESP pFrame
+);
void
vMgrDecodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- );
+ PWLAN_FR_REASSOCRESP pFrame
+);
#endif// __80211MGR_H__
diff --git a/drivers/staging/vt6655/IEEE11h.c b/drivers/staging/vt6655/IEEE11h.c
index cf7364d65263..dfda3c82906c 100644
--- a/drivers/staging/vt6655/IEEE11h.c
+++ b/drivers/staging/vt6655/IEEE11h.c
@@ -99,7 +99,7 @@ typedef struct _WLAN_FRAME_TPCREP {
/*--------------------- Static Functions --------------------------*/
static bool s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq,
- unsigned int uLength)
+ unsigned int uLength)
{
size_t uNumOfEIDs = 0;
bool bResult = true;
@@ -107,20 +107,19 @@ static bool s_bRxMSRReq(PSMgmtObject pMgmt, PWLAN_FRAME_MSRREQ pMSRReq,
if (uLength <= WLAN_A3FR_MAXLEN)
memcpy(pMgmt->abyCurrentMSRReq, pMSRReq, uLength);
uNumOfEIDs = ((uLength - offsetof(WLAN_FRAME_MSRREQ,
- sMSRReqEIDs))/
- (sizeof(WLAN_IE_MEASURE_REQ)));
+ sMSRReqEIDs))/
+ (sizeof(WLAN_IE_MEASURE_REQ)));
pMgmt->pCurrMeasureEIDRep = &(((PWLAN_FRAME_MSRREP)
- (pMgmt->abyCurrentMSRRep))->sMSRRepEIDs[0]);
+ (pMgmt->abyCurrentMSRRep))->sMSRRepEIDs[0]);
pMgmt->uLengthOfRepEIDs = 0;
bResult = CARDbStartMeasure(pMgmt->pAdapter,
- ((PWLAN_FRAME_MSRREQ)
- (pMgmt->abyCurrentMSRReq))->sMSRReqEIDs,
- uNumOfEIDs
- );
+ ((PWLAN_FRAME_MSRREQ)
+ (pMgmt->abyCurrentMSRReq))->sMSRReqEIDs,
+ uNumOfEIDs
+);
return bResult;
}
-
static bool s_bRxTPCReq(PSMgmtObject pMgmt,
PWLAN_FRAME_TPCREQ pTPCReq,
unsigned char byRate,
@@ -132,29 +131,29 @@ static bool s_bRxTPCReq(PSMgmtObject pMgmt,
pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket +
-sizeof(STxMgmtPacket));
+ sizeof(STxMgmtPacket));
pFrame = (PWLAN_FRAME_TPCREP)((unsigned char *)pTxPacket +
-sizeof(STxMgmtPacket));
+ sizeof(STxMgmtPacket));
pFrame->Header.wFrameCtl = (WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
- );
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
+);
memcpy(pFrame->Header.abyAddr1,
- pTPCReq->Header.abyAddr2,
- WLAN_ADDR_LEN);
+ pTPCReq->Header.abyAddr2,
+ WLAN_ADDR_LEN);
memcpy(pFrame->Header.abyAddr2,
- CARDpGetCurrentAddress(pMgmt->pAdapter),
- WLAN_ADDR_LEN);
+ CARDpGetCurrentAddress(pMgmt->pAdapter),
+ WLAN_ADDR_LEN);
memcpy(pFrame->Header.abyAddr3,
- pMgmt->abyCurrBSSID,
- WLAN_BSSID_LEN);
+ pMgmt->abyCurrBSSID,
+ WLAN_BSSID_LEN);
pFrame->byCategory = 0;
pFrame->byAction = 3;
pFrame->byDialogToken = ((PWLAN_FRAME_MSRREQ)
-(pMgmt->abyCurrentMSRReq))->byDialogToken;
+ (pMgmt->abyCurrentMSRReq))->byDialogToken;
pFrame->sTPCRepEIDs.byElementID = WLAN_EID_TPC_REP;
pFrame->sTPCRepEIDs.len = 2;
@@ -185,25 +184,22 @@ sizeof(STxMgmtPacket));
default:
pFrame->sTPCRepEIDs.byLinkMargin = 82 - byRSSI;
break;
-}
+ }
pTxPacket->cbMPDULen = sizeof(WLAN_FRAME_TPCREP);
pTxPacket->cbPayloadLen = sizeof(WLAN_FRAME_TPCREP) -
-WLAN_HDR_ADDR3_LEN;
+ WLAN_HDR_ADDR3_LEN;
if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
return false;
return true;
-/* return (CARDbSendPacket(pMgmt->pAdapter, pFrame, PKT_TYPE_802_11_MNG,
-sizeof(WLAN_FRAME_TPCREP))); */
-
+/* return CARDbSendPacket(pMgmt->pAdapter, pFrame, PKT_TYPE_802_11_MNG,
+ sizeof(WLAN_FRAME_TPCREP)); */
}
-
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Description:
@@ -218,7 +214,7 @@ sizeof(WLAN_FRAME_TPCREP))); */
*
* Return Value: None.
*
--*/
+ -*/
bool
IEEE11hbMgrRxAction(void *pMgmtHandle, void *pRxPacket)
{
@@ -233,86 +229,85 @@ IEEE11hbMgrRxAction(void *pMgmtHandle, void *pRxPacket)
return false;
pAction = (PWLAN_FRAME_ACTION)
-(((PSRxMgmtPacket)pRxPacket)->p80211Header);
+ (((PSRxMgmtPacket)pRxPacket)->p80211Header);
if (pAction->byCategory == 0) {
switch (pAction->byAction) {
case ACTION_MSRREQ:
return s_bRxMSRReq(pMgmt,
- (PWLAN_FRAME_MSRREQ)
- pAction,
- uLength);
+ (PWLAN_FRAME_MSRREQ)
+ pAction,
+ uLength);
break;
case ACTION_MSRREP:
break;
case ACTION_TPCREQ:
return s_bRxTPCReq(pMgmt,
- (PWLAN_FRAME_TPCREQ) pAction,
- ((PSRxMgmtPacket)pRxPacket)->byRxRate,
- (unsigned char)
- ((PSRxMgmtPacket)pRxPacket)->uRSSI);
+ (PWLAN_FRAME_TPCREQ) pAction,
+ ((PSRxMgmtPacket)pRxPacket)->byRxRate,
+ (unsigned char)
+ ((PSRxMgmtPacket)pRxPacket)->uRSSI);
break;
case ACTION_TPCREP:
break;
case ACTION_CHSW:
pChannelSwitch = (PWLAN_IE_CH_SW) (pAction->abyVars);
if ((pChannelSwitch->byElementID == WLAN_EID_CH_SWITCH)
- && (pChannelSwitch->len == 3)) {
+ && (pChannelSwitch->len == 3)) {
/* valid element id */
CARDbChannelSwitch(pMgmt->pAdapter,
- pChannelSwitch->byMode,
- get_channel_mapping(pMgmt->pAdapter,
- pChannelSwitch->byChannel,
- pMgmt->eCurrentPHYMode),
- pChannelSwitch->byCount);
+ pChannelSwitch->byMode,
+ get_channel_mapping(pMgmt->pAdapter,
+ pChannelSwitch->byChannel,
+ pMgmt->eCurrentPHYMode),
+ pChannelSwitch->byCount);
}
break;
default:
DBG_PRT(MSG_LEVEL_DEBUG,
- KERN_INFO"Unknown Action = %d\n",
+ KERN_INFO "Unknown Action = %d\n",
pAction->byAction);
break;
}
} else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown Category = %d\n",
-pAction->byCategory);
- pAction->byCategory |= 0x80;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unknown Category = %d\n",
+ pAction->byCategory);
+ pAction->byCategory |= 0x80;
- /*return (CARDbSendPacket(pMgmt->pAdapter, pAction, PKT_TYPE_802_11_MNG,
-uLength));*/
- return true;
+ /*return CARDbSendPacket(pMgmt->pAdapter, pAction, PKT_TYPE_802_11_MNG,
+ uLength);*/
+ return true;
}
return true;
}
-
bool IEEE11hbMSRRepTx(void *pMgmtHandle)
{
PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle;
PWLAN_FRAME_MSRREP pMSRRep = (PWLAN_FRAME_MSRREP)
-(pMgmt->abyCurrentMSRRep + sizeof(STxMgmtPacket));
+ (pMgmt->abyCurrentMSRRep + sizeof(STxMgmtPacket));
size_t uLength = 0;
PSTxMgmtPacket pTxPacket = NULL;
pTxPacket = (PSTxMgmtPacket)pMgmt->abyCurrentMSRRep;
memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket +
-sizeof(STxMgmtPacket));
+ sizeof(STxMgmtPacket));
pMSRRep->Header.wFrameCtl = (WLAN_SET_FC_FTYPE(WLAN_FTYPE_MGMT) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
- );
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ACTION)
+);
memcpy(pMSRRep->Header.abyAddr1, ((PWLAN_FRAME_MSRREQ)
- (pMgmt->abyCurrentMSRReq))->Header.abyAddr2, WLAN_ADDR_LEN);
+ (pMgmt->abyCurrentMSRReq))->Header.abyAddr2, WLAN_ADDR_LEN);
memcpy(pMSRRep->Header.abyAddr2,
- CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN);
+ CARDpGetCurrentAddress(pMgmt->pAdapter), WLAN_ADDR_LEN);
memcpy(pMSRRep->Header.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
pMSRRep->byCategory = 0;
pMSRRep->byAction = 1;
pMSRRep->byDialogToken = ((PWLAN_FRAME_MSRREQ)
- (pMgmt->abyCurrentMSRReq))->byDialogToken;
+ (pMgmt->abyCurrentMSRReq))->byDialogToken;
uLength = pMgmt->uLengthOfRepEIDs + offsetof(WLAN_FRAME_MSRREP,
sMSRRepEIDs);
@@ -322,8 +317,6 @@ sizeof(STxMgmtPacket));
if (csMgmt_xmit(pMgmt->pAdapter, pTxPacket) != CMD_STATUS_PENDING)
return false;
return true;
-/* return (CARDbSendPacket(pMgmt->pAdapter, pMSRRep, PKT_TYPE_802_11_MNG,
-uLength)); */
-
+/* return CARDbSendPacket(pMgmt->pAdapter, pMSRRep, PKT_TYPE_802_11_MNG,
+ uLength); */
}
-
diff --git a/drivers/staging/vt6655/IEEE11h.h b/drivers/staging/vt6655/IEEE11h.h
index 542340b96e38..8819fa1563b7 100644
--- a/drivers/staging/vt6655/IEEE11h.h
+++ b/drivers/staging/vt6655/IEEE11h.h
@@ -45,8 +45,8 @@
/*--------------------- Export Functions --------------------------*/
-bool IEEE11hbMSRRepTx (
- void *pMgmtHandle
- );
+bool IEEE11hbMSRRepTx(
+ void *pMgmtHandle
+);
#endif // __IEEE11h_H__
diff --git a/drivers/staging/vt6655/aes_ccmp.c b/drivers/staging/vt6655/aes_ccmp.c
index e30168f2da2f..36081481c6d1 100644
--- a/drivers/staging/vt6655/aes_ccmp.c
+++ b/drivers/staging/vt6655/aes_ccmp.c
@@ -48,60 +48,60 @@
unsigned char sbox_table[256] =
{
-0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
-0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
-0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
-0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
-0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
-0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
-0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
-0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
-0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
-0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
-0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
-0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
-0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
-0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
-0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
-0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
unsigned char dot2_table[256] = {
-0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
-0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
-0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
-0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
-0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
-0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
-0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
-0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
-0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
-0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
-0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
-0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
-0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
-0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
-0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
-0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
+ 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
+ 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
+ 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+ 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
+ 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
+ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
+ 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
+ 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
+ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
+ 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
+ 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
+ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
};
unsigned char dot3_table[256] = {
-0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
-0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
-0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
-0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
-0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
-0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
-0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
-0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
-0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
-0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
-0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
-0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
-0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
-0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
-0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
-0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
+ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
+ 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
+ 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
+ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
+ 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
+ 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
+ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
+ 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
+ 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
+ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
+ 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
+ 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
+ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
+ 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
+ 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
+ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
};
/*--------------------- Static Functions --------------------------*/
@@ -112,121 +112,111 @@ unsigned char dot3_table[256] = {
void xor_128(unsigned char *a, unsigned char *b, unsigned char *out)
{
-unsigned long *dwPtrA = (unsigned long *) a;
-unsigned long *dwPtrB = (unsigned long *) b;
-unsigned long *dwPtrOut =(unsigned long *) out;
-
- (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
- (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
- (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
- (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
+ unsigned long *dwPtrA = (unsigned long *)a;
+ unsigned long *dwPtrB = (unsigned long *)b;
+ unsigned long *dwPtrOut = (unsigned long *)out;
+
+ (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
+ (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
+ (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
+ (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
}
-
void xor_32(unsigned char *a, unsigned char *b, unsigned char *out)
{
-unsigned long *dwPtrA = (unsigned long *) a;
-unsigned long *dwPtrB = (unsigned long *) b;
-unsigned long *dwPtrOut =(unsigned long *) out;
+ unsigned long *dwPtrA = (unsigned long *)a;
+ unsigned long *dwPtrB = (unsigned long *)b;
+ unsigned long *dwPtrOut = (unsigned long *)out;
- (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
+ (*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
}
void AddRoundKey(unsigned char *key, int round)
{
-unsigned char sbox_key[4];
-unsigned char rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
+ unsigned char sbox_key[4];
+ unsigned char rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
- sbox_key[0] = sbox_table[key[13]];
- sbox_key[1] = sbox_table[key[14]];
- sbox_key[2] = sbox_table[key[15]];
- sbox_key[3] = sbox_table[key[12]];
+ sbox_key[0] = sbox_table[key[13]];
+ sbox_key[1] = sbox_table[key[14]];
+ sbox_key[2] = sbox_table[key[15]];
+ sbox_key[3] = sbox_table[key[12]];
- key[0] = key[0] ^ rcon_table[round];
- xor_32(&key[0], sbox_key, &key[0]);
+ key[0] = key[0] ^ rcon_table[round];
+ xor_32(&key[0], sbox_key, &key[0]);
- xor_32(&key[4], &key[0], &key[4]);
- xor_32(&key[8], &key[4], &key[8]);
- xor_32(&key[12], &key[8], &key[12]);
+ xor_32(&key[4], &key[0], &key[4]);
+ xor_32(&key[8], &key[4], &key[8]);
+ xor_32(&key[12], &key[8], &key[12]);
}
void SubBytes(unsigned char *in, unsigned char *out)
{
-int i;
+ int i;
- for (i=0; i< 16; i++)
- {
- out[i] = sbox_table[in[i]];
- }
+ for (i = 0; i < 16; i++) {
+ out[i] = sbox_table[in[i]];
+ }
}
void ShiftRows(unsigned char *in, unsigned char *out)
{
- out[0] = in[0];
- out[1] = in[5];
- out[2] = in[10];
- out[3] = in[15];
- out[4] = in[4];
- out[5] = in[9];
- out[6] = in[14];
- out[7] = in[3];
- out[8] = in[8];
- out[9] = in[13];
- out[10] = in[2];
- out[11] = in[7];
- out[12] = in[12];
- out[13] = in[1];
- out[14] = in[6];
- out[15] = in[11];
+ out[0] = in[0];
+ out[1] = in[5];
+ out[2] = in[10];
+ out[3] = in[15];
+ out[4] = in[4];
+ out[5] = in[9];
+ out[6] = in[14];
+ out[7] = in[3];
+ out[8] = in[8];
+ out[9] = in[13];
+ out[10] = in[2];
+ out[11] = in[7];
+ out[12] = in[12];
+ out[13] = in[1];
+ out[14] = in[6];
+ out[15] = in[11];
}
void MixColumns(unsigned char *in, unsigned char *out)
{
-
- out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3];
- out[1] = in[0] ^ dot2_table[in[1]] ^ dot3_table[in[2]] ^ in[3];
- out[2] = in[0] ^ in[1] ^ dot2_table[in[2]] ^ dot3_table[in[3]];
- out[3] = dot3_table[in[0]] ^ in[1] ^ in[2] ^ dot2_table[in[3]];
+ out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3];
+ out[1] = in[0] ^ dot2_table[in[1]] ^ dot3_table[in[2]] ^ in[3];
+ out[2] = in[0] ^ in[1] ^ dot2_table[in[2]] ^ dot3_table[in[3]];
+ out[3] = dot3_table[in[0]] ^ in[1] ^ in[2] ^ dot2_table[in[3]];
}
-
void AESv128(unsigned char *key, unsigned char *data, unsigned char *ciphertext)
{
-int i;
-int round;
-unsigned char TmpdataA[16];
-unsigned char TmpdataB[16];
-unsigned char abyRoundKey[16];
-
- for(i=0; i<16; i++)
- abyRoundKey[i] = key[i];
-
- for (round = 0; round < 11; round++)
- {
- if (round == 0)
- {
- xor_128(abyRoundKey, data, ciphertext);
- AddRoundKey(abyRoundKey, round);
- }
- else if (round == 10)
- {
- SubBytes(ciphertext, TmpdataA);
- ShiftRows(TmpdataA, TmpdataB);
- xor_128(TmpdataB, abyRoundKey, ciphertext);
- }
- else // round 1 ~ 9
- {
- SubBytes(ciphertext, TmpdataA);
- ShiftRows(TmpdataA, TmpdataB);
- MixColumns(&TmpdataB[0], &TmpdataA[0]);
- MixColumns(&TmpdataB[4], &TmpdataA[4]);
- MixColumns(&TmpdataB[8], &TmpdataA[8]);
- MixColumns(&TmpdataB[12], &TmpdataA[12]);
- xor_128(TmpdataA, abyRoundKey, ciphertext);
- AddRoundKey(abyRoundKey, round);
- }
- }
-
+ int i;
+ int round;
+ unsigned char TmpdataA[16];
+ unsigned char TmpdataB[16];
+ unsigned char abyRoundKey[16];
+
+ for (i = 0; i < 16; i++)
+ abyRoundKey[i] = key[i];
+
+ for (round = 0; round < 11; round++) {
+ if (round == 0) {
+ xor_128(abyRoundKey, data, ciphertext);
+ AddRoundKey(abyRoundKey, round);
+ } else if (round == 10) {
+ SubBytes(ciphertext, TmpdataA);
+ ShiftRows(TmpdataA, TmpdataB);
+ xor_128(TmpdataB, abyRoundKey, ciphertext);
+ } else // round 1 ~ 9
+ {
+ SubBytes(ciphertext, TmpdataA);
+ ShiftRows(TmpdataA, TmpdataB);
+ MixColumns(&TmpdataB[0], &TmpdataA[0]);
+ MixColumns(&TmpdataB[4], &TmpdataA[4]);
+ MixColumns(&TmpdataB[8], &TmpdataA[8]);
+ MixColumns(&TmpdataB[12], &TmpdataA[12]);
+ xor_128(TmpdataA, abyRoundKey, ciphertext);
+ AddRoundKey(abyRoundKey, round);
+ }
+ }
}
/*
@@ -245,158 +235,155 @@ unsigned char abyRoundKey[16];
*/
bool AESbGenCCMP(unsigned char *pbyRxKey, unsigned char *pbyFrame, unsigned short wFrameSize)
{
-unsigned char abyNonce[13];
-unsigned char MIC_IV[16];
-unsigned char MIC_HDR1[16];
-unsigned char MIC_HDR2[16];
-unsigned char abyMIC[16];
-unsigned char abyCTRPLD[16];
-unsigned char abyTmp[16];
-unsigned char abyPlainText[16];
-unsigned char abyLastCipher[16];
-
-PS802_11Header pMACHeader = (PS802_11Header) pbyFrame;
-unsigned char *pbyIV;
-unsigned char *pbyPayload;
-unsigned short wHLen = 22;
-unsigned short wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;//8 is IV, 8 is MIC, 4 is CRC
-bool bA4 = false;
-unsigned char byTmp;
-unsigned short wCnt;
-int ii,jj,kk;
-
-
- pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
- bA4 = true;
- pbyIV += 6; // 6 is 802.11 address4
- wHLen += 6;
- wPayloadSize -= 6;
- }
- pbyPayload = pbyIV + 8; //IV-length
-
- abyNonce[0] = 0x00; //now is 0, if Qos here will be priority
- memcpy(&(abyNonce[1]), pMACHeader->abyAddr2, ETH_ALEN);
- abyNonce[7] = pbyIV[7];
- abyNonce[8] = pbyIV[6];
- abyNonce[9] = pbyIV[5];
- abyNonce[10] = pbyIV[4];
- abyNonce[11] = pbyIV[1];
- abyNonce[12] = pbyIV[0];
-
- //MIC_IV
- MIC_IV[0] = 0x59;
- memcpy(&(MIC_IV[1]), &(abyNonce[0]), 13);
- MIC_IV[14] = (unsigned char)(wPayloadSize >> 8);
- MIC_IV[15] = (unsigned char)(wPayloadSize & 0xff);
-
- //MIC_HDR1
- MIC_HDR1[0] = (unsigned char)(wHLen >> 8);
- MIC_HDR1[1] = (unsigned char)(wHLen & 0xff);
- byTmp = (unsigned char)(pMACHeader->wFrameCtl & 0xff);
- MIC_HDR1[2] = byTmp & 0x8f;
- byTmp = (unsigned char)(pMACHeader->wFrameCtl >> 8);
- byTmp &= 0x87;
- MIC_HDR1[3] = byTmp | 0x40;
- memcpy(&(MIC_HDR1[4]), pMACHeader->abyAddr1, ETH_ALEN);
- memcpy(&(MIC_HDR1[10]), pMACHeader->abyAddr2, ETH_ALEN);
-
- //MIC_HDR2
- memcpy(&(MIC_HDR2[0]), pMACHeader->abyAddr3, ETH_ALEN);
- byTmp = (unsigned char)(pMACHeader->wSeqCtl & 0xff);
- MIC_HDR2[6] = byTmp & 0x0f;
- MIC_HDR2[7] = 0;
- if ( bA4 ) {
- memcpy(&(MIC_HDR2[8]), pMACHeader->abyAddr4, ETH_ALEN);
- } else {
- MIC_HDR2[8] = 0x00;
- MIC_HDR2[9] = 0x00;
- MIC_HDR2[10] = 0x00;
- MIC_HDR2[11] = 0x00;
- MIC_HDR2[12] = 0x00;
- MIC_HDR2[13] = 0x00;
- }
- MIC_HDR2[14] = 0x00;
- MIC_HDR2[15] = 0x00;
-
- //CCMP
- AESv128(pbyRxKey,MIC_IV,abyMIC);
- for ( kk=0; kk<16; kk++ ) {
- abyTmp[kk] = MIC_HDR1[kk] ^ abyMIC[kk];
- }
- AESv128(pbyRxKey,abyTmp,abyMIC);
- for ( kk=0; kk<16; kk++ ) {
- abyTmp[kk] = MIC_HDR2[kk] ^ abyMIC[kk];
- }
- AESv128(pbyRxKey,abyTmp,abyMIC);
-
- wCnt = 1;
- abyCTRPLD[0] = 0x01;
- memcpy(&(abyCTRPLD[1]), &(abyNonce[0]), 13);
-
- for(jj=wPayloadSize; jj>16; jj=jj-16) {
-
- abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
- abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
-
- AESv128(pbyRxKey,abyCTRPLD,abyTmp);
-
- for ( kk=0; kk<16; kk++ ) {
- abyPlainText[kk] = abyTmp[kk] ^ pbyPayload[kk];
- }
- for ( kk=0; kk<16; kk++ ) {
- abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
- }
- AESv128(pbyRxKey,abyTmp,abyMIC);
-
- memcpy(pbyPayload, abyPlainText, 16);
- wCnt++;
- pbyPayload += 16;
- } //for wPayloadSize
-
- //last payload
- memcpy(&(abyLastCipher[0]), pbyPayload, jj);
- for ( ii=jj; ii<16; ii++ ) {
- abyLastCipher[ii] = 0x00;
- }
-
- abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
- abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
-
- AESv128(pbyRxKey,abyCTRPLD,abyTmp);
- for ( kk=0; kk<16; kk++ ) {
- abyPlainText[kk] = abyTmp[kk] ^ abyLastCipher[kk];
- }
- memcpy(pbyPayload, abyPlainText, jj);
- pbyPayload += jj;
-
- //for MIC calculation
- for ( ii=jj; ii<16; ii++ ) {
- abyPlainText[ii] = 0x00;
- }
- for ( kk=0; kk<16; kk++ ) {
- abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
- }
- AESv128(pbyRxKey,abyTmp,abyMIC);
-
- //=>above is the calculate MIC
- //--------------------------------------------
-
- wCnt = 0;
- abyCTRPLD[14] = (unsigned char) (wCnt >> 8);
- abyCTRPLD[15] = (unsigned char) (wCnt & 0xff);
- AESv128(pbyRxKey,abyCTRPLD,abyTmp);
- for ( kk=0; kk<8; kk++ ) {
- abyTmp[kk] = abyTmp[kk] ^ pbyPayload[kk];
- }
- //=>above is the dec-MIC from packet
- //--------------------------------------------
-
- if ( !memcmp(abyMIC,abyTmp,8) ) {
- return true;
- } else {
- return false;
- }
-
+ unsigned char abyNonce[13];
+ unsigned char MIC_IV[16];
+ unsigned char MIC_HDR1[16];
+ unsigned char MIC_HDR2[16];
+ unsigned char abyMIC[16];
+ unsigned char abyCTRPLD[16];
+ unsigned char abyTmp[16];
+ unsigned char abyPlainText[16];
+ unsigned char abyLastCipher[16];
+
+ PS802_11Header pMACHeader = (PS802_11Header) pbyFrame;
+ unsigned char *pbyIV;
+ unsigned char *pbyPayload;
+ unsigned short wHLen = 22;
+ unsigned short wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;//8 is IV, 8 is MIC, 4 is CRC
+ bool bA4 = false;
+ unsigned char byTmp;
+ unsigned short wCnt;
+ int ii, jj, kk;
+
+ pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
+ if (WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame)) {
+ bA4 = true;
+ pbyIV += 6; // 6 is 802.11 address4
+ wHLen += 6;
+ wPayloadSize -= 6;
+ }
+ pbyPayload = pbyIV + 8; //IV-length
+
+ abyNonce[0] = 0x00; //now is 0, if Qos here will be priority
+ memcpy(&(abyNonce[1]), pMACHeader->abyAddr2, ETH_ALEN);
+ abyNonce[7] = pbyIV[7];
+ abyNonce[8] = pbyIV[6];
+ abyNonce[9] = pbyIV[5];
+ abyNonce[10] = pbyIV[4];
+ abyNonce[11] = pbyIV[1];
+ abyNonce[12] = pbyIV[0];
+
+ //MIC_IV
+ MIC_IV[0] = 0x59;
+ memcpy(&(MIC_IV[1]), &(abyNonce[0]), 13);
+ MIC_IV[14] = (unsigned char)(wPayloadSize >> 8);
+ MIC_IV[15] = (unsigned char)(wPayloadSize & 0xff);
+
+ //MIC_HDR1
+ MIC_HDR1[0] = (unsigned char)(wHLen >> 8);
+ MIC_HDR1[1] = (unsigned char)(wHLen & 0xff);
+ byTmp = (unsigned char)(pMACHeader->wFrameCtl & 0xff);
+ MIC_HDR1[2] = byTmp & 0x8f;
+ byTmp = (unsigned char)(pMACHeader->wFrameCtl >> 8);
+ byTmp &= 0x87;
+ MIC_HDR1[3] = byTmp | 0x40;
+ memcpy(&(MIC_HDR1[4]), pMACHeader->abyAddr1, ETH_ALEN);
+ memcpy(&(MIC_HDR1[10]), pMACHeader->abyAddr2, ETH_ALEN);
+
+ //MIC_HDR2
+ memcpy(&(MIC_HDR2[0]), pMACHeader->abyAddr3, ETH_ALEN);
+ byTmp = (unsigned char)(pMACHeader->wSeqCtl & 0xff);
+ MIC_HDR2[6] = byTmp & 0x0f;
+ MIC_HDR2[7] = 0;
+ if (bA4) {
+ memcpy(&(MIC_HDR2[8]), pMACHeader->abyAddr4, ETH_ALEN);
+ } else {
+ MIC_HDR2[8] = 0x00;
+ MIC_HDR2[9] = 0x00;
+ MIC_HDR2[10] = 0x00;
+ MIC_HDR2[11] = 0x00;
+ MIC_HDR2[12] = 0x00;
+ MIC_HDR2[13] = 0x00;
+ }
+ MIC_HDR2[14] = 0x00;
+ MIC_HDR2[15] = 0x00;
+
+ //CCMP
+ AESv128(pbyRxKey, MIC_IV, abyMIC);
+ for (kk = 0; kk < 16; kk++) {
+ abyTmp[kk] = MIC_HDR1[kk] ^ abyMIC[kk];
+ }
+ AESv128(pbyRxKey, abyTmp, abyMIC);
+ for (kk = 0; kk < 16; kk++) {
+ abyTmp[kk] = MIC_HDR2[kk] ^ abyMIC[kk];
+ }
+ AESv128(pbyRxKey, abyTmp, abyMIC);
+
+ wCnt = 1;
+ abyCTRPLD[0] = 0x01;
+ memcpy(&(abyCTRPLD[1]), &(abyNonce[0]), 13);
+
+ for (jj = wPayloadSize; jj > 16; jj = jj - 16) {
+ abyCTRPLD[14] = (unsigned char)(wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char)(wCnt & 0xff);
+
+ AESv128(pbyRxKey, abyCTRPLD, abyTmp);
+
+ for (kk = 0; kk < 16; kk++) {
+ abyPlainText[kk] = abyTmp[kk] ^ pbyPayload[kk];
+ }
+ for (kk = 0; kk < 16; kk++) {
+ abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
+ }
+ AESv128(pbyRxKey, abyTmp, abyMIC);
+
+ memcpy(pbyPayload, abyPlainText, 16);
+ wCnt++;
+ pbyPayload += 16;
+ } //for wPayloadSize
+
+ //last payload
+ memcpy(&(abyLastCipher[0]), pbyPayload, jj);
+ for (ii = jj; ii < 16; ii++) {
+ abyLastCipher[ii] = 0x00;
+ }
+
+ abyCTRPLD[14] = (unsigned char)(wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char)(wCnt & 0xff);
+
+ AESv128(pbyRxKey, abyCTRPLD, abyTmp);
+ for (kk = 0; kk < 16; kk++) {
+ abyPlainText[kk] = abyTmp[kk] ^ abyLastCipher[kk];
+ }
+ memcpy(pbyPayload, abyPlainText, jj);
+ pbyPayload += jj;
+
+ //for MIC calculation
+ for (ii = jj; ii < 16; ii++) {
+ abyPlainText[ii] = 0x00;
+ }
+ for (kk = 0; kk < 16; kk++) {
+ abyTmp[kk] = abyMIC[kk] ^ abyPlainText[kk];
+ }
+ AESv128(pbyRxKey, abyTmp, abyMIC);
+
+ //=>above is the calculate MIC
+ //--------------------------------------------
+
+ wCnt = 0;
+ abyCTRPLD[14] = (unsigned char)(wCnt >> 8);
+ abyCTRPLD[15] = (unsigned char)(wCnt & 0xff);
+ AESv128(pbyRxKey, abyCTRPLD, abyTmp);
+ for (kk = 0; kk < 8; kk++) {
+ abyTmp[kk] = abyTmp[kk] ^ pbyPayload[kk];
+ }
+ //=>above is the dec-MIC from packet
+ //--------------------------------------------
+
+ if (!memcmp(abyMIC, abyTmp, 8)) {
+ return true;
+ } else {
+ return false;
+ }
}
diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c
index 8d2c6a789ab2..c26418d806fb 100644
--- a/drivers/staging/vt6655/baseband.c
+++ b/drivers/staging/vt6655/baseband.c
@@ -58,7 +58,7 @@
/*--------------------- Static Definitions -------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Classes ----------------------------*/
@@ -74,1646 +74,1641 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Static Variables --------------------------*/
-
-
#define CB_VT3253_INIT_FOR_RFMD 446
unsigned char byVT3253InitTab_RFMD[CB_VT3253_INIT_FOR_RFMD][2] = {
- {0x00, 0x30},
- {0x01, 0x00},
- {0x02, 0x00},
- {0x03, 0x00},
- {0x04, 0x00},
- {0x05, 0x00},
- {0x06, 0x00},
- {0x07, 0x00},
- {0x08, 0x70},
- {0x09, 0x45},
- {0x0a, 0x2a},
- {0x0b, 0x76},
- {0x0c, 0x00},
- {0x0d, 0x01},
- {0x0e, 0x80},
- {0x0f, 0x00},
- {0x10, 0x00},
- {0x11, 0x00},
- {0x12, 0x00},
- {0x13, 0x00},
- {0x14, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x17, 0x00},
- {0x18, 0x00},
- {0x19, 0x00},
- {0x1a, 0x00},
- {0x1b, 0x9d},
- {0x1c, 0x05},
- {0x1d, 0x00},
- {0x1e, 0x00},
- {0x1f, 0x00},
- {0x20, 0x00},
- {0x21, 0x00},
- {0x22, 0x00},
- {0x23, 0x00},
- {0x24, 0x00},
- {0x25, 0x4a},
- {0x26, 0x00},
- {0x27, 0x00},
- {0x28, 0x00},
- {0x29, 0x00},
- {0x2a, 0x00},
- {0x2b, 0x00},
- {0x2c, 0x00},
- {0x2d, 0xa8},
- {0x2e, 0x1a},
- {0x2f, 0x0c},
- {0x30, 0x26},
- {0x31, 0x5b},
- {0x32, 0x00},
- {0x33, 0x00},
- {0x34, 0x00},
- {0x35, 0x00},
- {0x36, 0xaa},
- {0x37, 0xaa},
- {0x38, 0xff},
- {0x39, 0xff},
- {0x3a, 0x00},
- {0x3b, 0x00},
- {0x3c, 0x00},
- {0x3d, 0x0d},
- {0x3e, 0x51},
- {0x3f, 0x04},
- {0x40, 0x00},
- {0x41, 0x08},
- {0x42, 0x00},
- {0x43, 0x08},
- {0x44, 0x06},
- {0x45, 0x14},
- {0x46, 0x05},
- {0x47, 0x08},
- {0x48, 0x00},
- {0x49, 0x00},
- {0x4a, 0x00},
- {0x4b, 0x00},
- {0x4c, 0x09},
- {0x4d, 0x80},
- {0x4e, 0x00},
- {0x4f, 0xc5},
- {0x50, 0x14},
- {0x51, 0x19},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x56, 0x00},
- {0x57, 0x00},
- {0x58, 0x00},
- {0x59, 0xb0},
- {0x5a, 0x00},
- {0x5b, 0x00},
- {0x5c, 0x00},
- {0x5d, 0x00},
- {0x5e, 0x00},
- {0x5f, 0x00},
- {0x60, 0x44},
- {0x61, 0x04},
- {0x62, 0x00},
- {0x63, 0x00},
- {0x64, 0x00},
- {0x65, 0x00},
- {0x66, 0x04},
- {0x67, 0xb7},
- {0x68, 0x00},
- {0x69, 0x00},
- {0x6a, 0x00},
- {0x6b, 0x00},
- {0x6c, 0x00},
- {0x6d, 0x03},
- {0x6e, 0x01},
- {0x6f, 0x00},
- {0x70, 0x00},
- {0x71, 0x00},
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x00},
- {0x75, 0x00},
- {0x76, 0x00},
- {0x77, 0x00},
- {0x78, 0x00},
- {0x79, 0x00},
- {0x7a, 0x00},
- {0x7b, 0x00},
- {0x7c, 0x00},
- {0x7d, 0x00},
- {0x7e, 0x00},
- {0x7f, 0x00},
- {0x80, 0x0b},
- {0x81, 0x00},
- {0x82, 0x3c},
- {0x83, 0x00},
- {0x84, 0x00},
- {0x85, 0x00},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x08},
- {0x89, 0x00},
- {0x8a, 0x08},
- {0x8b, 0xa6},
- {0x8c, 0x84},
- {0x8d, 0x47},
- {0x8e, 0xbb},
- {0x8f, 0x02},
- {0x90, 0x21},
- {0x91, 0x0c},
- {0x92, 0x04},
- {0x93, 0x22},
- {0x94, 0x00},
- {0x95, 0x00},
- {0x96, 0x00},
- {0x97, 0xeb},
- {0x98, 0x00},
- {0x99, 0x00},
- {0x9a, 0x00},
- {0x9b, 0x00},
- {0x9c, 0x00},
- {0x9d, 0x00},
- {0x9e, 0x00},
- {0x9f, 0x00},
- {0xa0, 0x00},
- {0xa1, 0x00},
- {0xa2, 0x00},
- {0xa3, 0x00},
- {0xa4, 0x00},
- {0xa5, 0x00},
- {0xa6, 0x10},
- {0xa7, 0x04},
- {0xa8, 0x10},
- {0xa9, 0x00},
- {0xaa, 0x8f},
- {0xab, 0x00},
- {0xac, 0x00},
- {0xad, 0x00},
- {0xae, 0x00},
- {0xaf, 0x80},
- {0xb0, 0x38},
- {0xb1, 0x00},
- {0xb2, 0x00},
- {0xb3, 0x00},
- {0xb4, 0xee},
- {0xb5, 0xff},
- {0xb6, 0x10},
- {0xb7, 0x00},
- {0xb8, 0x00},
- {0xb9, 0x00},
- {0xba, 0x00},
- {0xbb, 0x03},
- {0xbc, 0x00},
- {0xbd, 0x00},
- {0xbe, 0x00},
- {0xbf, 0x00},
- {0xc0, 0x10},
- {0xc1, 0x10},
- {0xc2, 0x18},
- {0xc3, 0x20},
- {0xc4, 0x10},
- {0xc5, 0x00},
- {0xc6, 0x22},
- {0xc7, 0x14},
- {0xc8, 0x0f},
- {0xc9, 0x08},
- {0xca, 0xa4},
- {0xcb, 0xa7},
- {0xcc, 0x3c},
- {0xcd, 0x10},
- {0xce, 0x20},
- {0xcf, 0x00},
- {0xd0, 0x00},
- {0xd1, 0x10},
- {0xd2, 0x00},
- {0xd3, 0x00},
- {0xd4, 0x10},
- {0xd5, 0x33},
- {0xd6, 0x70},
- {0xd7, 0x01},
- {0xd8, 0x00},
- {0xd9, 0x00},
- {0xda, 0x00},
- {0xdb, 0x00},
- {0xdc, 0x00},
- {0xdd, 0x00},
- {0xde, 0x00},
- {0xdf, 0x00},
- {0xe0, 0x00},
- {0xe1, 0x00},
- {0xe2, 0xcc},
- {0xe3, 0x04},
- {0xe4, 0x08},
- {0xe5, 0x10},
- {0xe6, 0x00},
- {0xe7, 0x0e},
- {0xe8, 0x88},
- {0xe9, 0xd4},
- {0xea, 0x05},
- {0xeb, 0xf0},
- {0xec, 0x79},
- {0xed, 0x0f},
- {0xee, 0x04},
- {0xef, 0x04},
- {0xf0, 0x00},
- {0xf1, 0x00},
- {0xf2, 0x00},
- {0xf3, 0x00},
- {0xf4, 0x00},
- {0xf5, 0x00},
- {0xf6, 0x00},
- {0xf7, 0x00},
- {0xf8, 0x00},
- {0xf9, 0x00},
- {0xF0, 0x00},
- {0xF1, 0xF8},
- {0xF0, 0x80},
- {0xF0, 0x00},
- {0xF1, 0xF4},
- {0xF0, 0x81},
- {0xF0, 0x01},
- {0xF1, 0xF0},
- {0xF0, 0x82},
- {0xF0, 0x02},
- {0xF1, 0xEC},
- {0xF0, 0x83},
- {0xF0, 0x03},
- {0xF1, 0xE8},
- {0xF0, 0x84},
- {0xF0, 0x04},
- {0xF1, 0xE4},
- {0xF0, 0x85},
- {0xF0, 0x05},
- {0xF1, 0xE0},
- {0xF0, 0x86},
- {0xF0, 0x06},
- {0xF1, 0xDC},
- {0xF0, 0x87},
- {0xF0, 0x07},
- {0xF1, 0xD8},
- {0xF0, 0x88},
- {0xF0, 0x08},
- {0xF1, 0xD4},
- {0xF0, 0x89},
- {0xF0, 0x09},
- {0xF1, 0xD0},
- {0xF0, 0x8A},
- {0xF0, 0x0A},
- {0xF1, 0xCC},
- {0xF0, 0x8B},
- {0xF0, 0x0B},
- {0xF1, 0xC8},
- {0xF0, 0x8C},
- {0xF0, 0x0C},
- {0xF1, 0xC4},
- {0xF0, 0x8D},
- {0xF0, 0x0D},
- {0xF1, 0xC0},
- {0xF0, 0x8E},
- {0xF0, 0x0E},
- {0xF1, 0xBC},
- {0xF0, 0x8F},
- {0xF0, 0x0F},
- {0xF1, 0xB8},
- {0xF0, 0x90},
- {0xF0, 0x10},
- {0xF1, 0xB4},
- {0xF0, 0x91},
- {0xF0, 0x11},
- {0xF1, 0xB0},
- {0xF0, 0x92},
- {0xF0, 0x12},
- {0xF1, 0xAC},
- {0xF0, 0x93},
- {0xF0, 0x13},
- {0xF1, 0xA8},
- {0xF0, 0x94},
- {0xF0, 0x14},
- {0xF1, 0xA4},
- {0xF0, 0x95},
- {0xF0, 0x15},
- {0xF1, 0xA0},
- {0xF0, 0x96},
- {0xF0, 0x16},
- {0xF1, 0x9C},
- {0xF0, 0x97},
- {0xF0, 0x17},
- {0xF1, 0x98},
- {0xF0, 0x98},
- {0xF0, 0x18},
- {0xF1, 0x94},
- {0xF0, 0x99},
- {0xF0, 0x19},
- {0xF1, 0x90},
- {0xF0, 0x9A},
- {0xF0, 0x1A},
- {0xF1, 0x8C},
- {0xF0, 0x9B},
- {0xF0, 0x1B},
- {0xF1, 0x88},
- {0xF0, 0x9C},
- {0xF0, 0x1C},
- {0xF1, 0x84},
- {0xF0, 0x9D},
- {0xF0, 0x1D},
- {0xF1, 0x80},
- {0xF0, 0x9E},
- {0xF0, 0x1E},
- {0xF1, 0x7C},
- {0xF0, 0x9F},
- {0xF0, 0x1F},
- {0xF1, 0x78},
- {0xF0, 0xA0},
- {0xF0, 0x20},
- {0xF1, 0x74},
- {0xF0, 0xA1},
- {0xF0, 0x21},
- {0xF1, 0x70},
- {0xF0, 0xA2},
- {0xF0, 0x22},
- {0xF1, 0x6C},
- {0xF0, 0xA3},
- {0xF0, 0x23},
- {0xF1, 0x68},
- {0xF0, 0xA4},
- {0xF0, 0x24},
- {0xF1, 0x64},
- {0xF0, 0xA5},
- {0xF0, 0x25},
- {0xF1, 0x60},
- {0xF0, 0xA6},
- {0xF0, 0x26},
- {0xF1, 0x5C},
- {0xF0, 0xA7},
- {0xF0, 0x27},
- {0xF1, 0x58},
- {0xF0, 0xA8},
- {0xF0, 0x28},
- {0xF1, 0x54},
- {0xF0, 0xA9},
- {0xF0, 0x29},
- {0xF1, 0x50},
- {0xF0, 0xAA},
- {0xF0, 0x2A},
- {0xF1, 0x4C},
- {0xF0, 0xAB},
- {0xF0, 0x2B},
- {0xF1, 0x48},
- {0xF0, 0xAC},
- {0xF0, 0x2C},
- {0xF1, 0x44},
- {0xF0, 0xAD},
- {0xF0, 0x2D},
- {0xF1, 0x40},
- {0xF0, 0xAE},
- {0xF0, 0x2E},
- {0xF1, 0x3C},
- {0xF0, 0xAF},
- {0xF0, 0x2F},
- {0xF1, 0x38},
- {0xF0, 0xB0},
- {0xF0, 0x30},
- {0xF1, 0x34},
- {0xF0, 0xB1},
- {0xF0, 0x31},
- {0xF1, 0x30},
- {0xF0, 0xB2},
- {0xF0, 0x32},
- {0xF1, 0x2C},
- {0xF0, 0xB3},
- {0xF0, 0x33},
- {0xF1, 0x28},
- {0xF0, 0xB4},
- {0xF0, 0x34},
- {0xF1, 0x24},
- {0xF0, 0xB5},
- {0xF0, 0x35},
- {0xF1, 0x20},
- {0xF0, 0xB6},
- {0xF0, 0x36},
- {0xF1, 0x1C},
- {0xF0, 0xB7},
- {0xF0, 0x37},
- {0xF1, 0x18},
- {0xF0, 0xB8},
- {0xF0, 0x38},
- {0xF1, 0x14},
- {0xF0, 0xB9},
- {0xF0, 0x39},
- {0xF1, 0x10},
- {0xF0, 0xBA},
- {0xF0, 0x3A},
- {0xF1, 0x0C},
- {0xF0, 0xBB},
- {0xF0, 0x3B},
- {0xF1, 0x08},
- {0xF0, 0x00},
- {0xF0, 0x3C},
- {0xF1, 0x04},
- {0xF0, 0xBD},
- {0xF0, 0x3D},
- {0xF1, 0x00},
- {0xF0, 0xBE},
- {0xF0, 0x3E},
- {0xF1, 0x00},
- {0xF0, 0xBF},
- {0xF0, 0x3F},
- {0xF1, 0x00},
- {0xF0, 0xC0},
- {0xF0, 0x00},
+ {0x00, 0x30},
+ {0x01, 0x00},
+ {0x02, 0x00},
+ {0x03, 0x00},
+ {0x04, 0x00},
+ {0x05, 0x00},
+ {0x06, 0x00},
+ {0x07, 0x00},
+ {0x08, 0x70},
+ {0x09, 0x45},
+ {0x0a, 0x2a},
+ {0x0b, 0x76},
+ {0x0c, 0x00},
+ {0x0d, 0x01},
+ {0x0e, 0x80},
+ {0x0f, 0x00},
+ {0x10, 0x00},
+ {0x11, 0x00},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x17, 0x00},
+ {0x18, 0x00},
+ {0x19, 0x00},
+ {0x1a, 0x00},
+ {0x1b, 0x9d},
+ {0x1c, 0x05},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x1f, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x4a},
+ {0x26, 0x00},
+ {0x27, 0x00},
+ {0x28, 0x00},
+ {0x29, 0x00},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x2c, 0x00},
+ {0x2d, 0xa8},
+ {0x2e, 0x1a},
+ {0x2f, 0x0c},
+ {0x30, 0x26},
+ {0x31, 0x5b},
+ {0x32, 0x00},
+ {0x33, 0x00},
+ {0x34, 0x00},
+ {0x35, 0x00},
+ {0x36, 0xaa},
+ {0x37, 0xaa},
+ {0x38, 0xff},
+ {0x39, 0xff},
+ {0x3a, 0x00},
+ {0x3b, 0x00},
+ {0x3c, 0x00},
+ {0x3d, 0x0d},
+ {0x3e, 0x51},
+ {0x3f, 0x04},
+ {0x40, 0x00},
+ {0x41, 0x08},
+ {0x42, 0x00},
+ {0x43, 0x08},
+ {0x44, 0x06},
+ {0x45, 0x14},
+ {0x46, 0x05},
+ {0x47, 0x08},
+ {0x48, 0x00},
+ {0x49, 0x00},
+ {0x4a, 0x00},
+ {0x4b, 0x00},
+ {0x4c, 0x09},
+ {0x4d, 0x80},
+ {0x4e, 0x00},
+ {0x4f, 0xc5},
+ {0x50, 0x14},
+ {0x51, 0x19},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x56, 0x00},
+ {0x57, 0x00},
+ {0x58, 0x00},
+ {0x59, 0xb0},
+ {0x5a, 0x00},
+ {0x5b, 0x00},
+ {0x5c, 0x00},
+ {0x5d, 0x00},
+ {0x5e, 0x00},
+ {0x5f, 0x00},
+ {0x60, 0x44},
+ {0x61, 0x04},
+ {0x62, 0x00},
+ {0x63, 0x00},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x04},
+ {0x67, 0xb7},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ {0x6c, 0x00},
+ {0x6d, 0x03},
+ {0x6e, 0x01},
+ {0x6f, 0x00},
+ {0x70, 0x00},
+ {0x71, 0x00},
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x00},
+ {0x75, 0x00},
+ {0x76, 0x00},
+ {0x77, 0x00},
+ {0x78, 0x00},
+ {0x79, 0x00},
+ {0x7a, 0x00},
+ {0x7b, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x00},
+ {0x7e, 0x00},
+ {0x7f, 0x00},
+ {0x80, 0x0b},
+ {0x81, 0x00},
+ {0x82, 0x3c},
+ {0x83, 0x00},
+ {0x84, 0x00},
+ {0x85, 0x00},
+ {0x86, 0x00},
+ {0x87, 0x00},
+ {0x88, 0x08},
+ {0x89, 0x00},
+ {0x8a, 0x08},
+ {0x8b, 0xa6},
+ {0x8c, 0x84},
+ {0x8d, 0x47},
+ {0x8e, 0xbb},
+ {0x8f, 0x02},
+ {0x90, 0x21},
+ {0x91, 0x0c},
+ {0x92, 0x04},
+ {0x93, 0x22},
+ {0x94, 0x00},
+ {0x95, 0x00},
+ {0x96, 0x00},
+ {0x97, 0xeb},
+ {0x98, 0x00},
+ {0x99, 0x00},
+ {0x9a, 0x00},
+ {0x9b, 0x00},
+ {0x9c, 0x00},
+ {0x9d, 0x00},
+ {0x9e, 0x00},
+ {0x9f, 0x00},
+ {0xa0, 0x00},
+ {0xa1, 0x00},
+ {0xa2, 0x00},
+ {0xa3, 0x00},
+ {0xa4, 0x00},
+ {0xa5, 0x00},
+ {0xa6, 0x10},
+ {0xa7, 0x04},
+ {0xa8, 0x10},
+ {0xa9, 0x00},
+ {0xaa, 0x8f},
+ {0xab, 0x00},
+ {0xac, 0x00},
+ {0xad, 0x00},
+ {0xae, 0x00},
+ {0xaf, 0x80},
+ {0xb0, 0x38},
+ {0xb1, 0x00},
+ {0xb2, 0x00},
+ {0xb3, 0x00},
+ {0xb4, 0xee},
+ {0xb5, 0xff},
+ {0xb6, 0x10},
+ {0xb7, 0x00},
+ {0xb8, 0x00},
+ {0xb9, 0x00},
+ {0xba, 0x00},
+ {0xbb, 0x03},
+ {0xbc, 0x00},
+ {0xbd, 0x00},
+ {0xbe, 0x00},
+ {0xbf, 0x00},
+ {0xc0, 0x10},
+ {0xc1, 0x10},
+ {0xc2, 0x18},
+ {0xc3, 0x20},
+ {0xc4, 0x10},
+ {0xc5, 0x00},
+ {0xc6, 0x22},
+ {0xc7, 0x14},
+ {0xc8, 0x0f},
+ {0xc9, 0x08},
+ {0xca, 0xa4},
+ {0xcb, 0xa7},
+ {0xcc, 0x3c},
+ {0xcd, 0x10},
+ {0xce, 0x20},
+ {0xcf, 0x00},
+ {0xd0, 0x00},
+ {0xd1, 0x10},
+ {0xd2, 0x00},
+ {0xd3, 0x00},
+ {0xd4, 0x10},
+ {0xd5, 0x33},
+ {0xd6, 0x70},
+ {0xd7, 0x01},
+ {0xd8, 0x00},
+ {0xd9, 0x00},
+ {0xda, 0x00},
+ {0xdb, 0x00},
+ {0xdc, 0x00},
+ {0xdd, 0x00},
+ {0xde, 0x00},
+ {0xdf, 0x00},
+ {0xe0, 0x00},
+ {0xe1, 0x00},
+ {0xe2, 0xcc},
+ {0xe3, 0x04},
+ {0xe4, 0x08},
+ {0xe5, 0x10},
+ {0xe6, 0x00},
+ {0xe7, 0x0e},
+ {0xe8, 0x88},
+ {0xe9, 0xd4},
+ {0xea, 0x05},
+ {0xeb, 0xf0},
+ {0xec, 0x79},
+ {0xed, 0x0f},
+ {0xee, 0x04},
+ {0xef, 0x04},
+ {0xf0, 0x00},
+ {0xf1, 0x00},
+ {0xf2, 0x00},
+ {0xf3, 0x00},
+ {0xf4, 0x00},
+ {0xf5, 0x00},
+ {0xf6, 0x00},
+ {0xf7, 0x00},
+ {0xf8, 0x00},
+ {0xf9, 0x00},
+ {0xF0, 0x00},
+ {0xF1, 0xF8},
+ {0xF0, 0x80},
+ {0xF0, 0x00},
+ {0xF1, 0xF4},
+ {0xF0, 0x81},
+ {0xF0, 0x01},
+ {0xF1, 0xF0},
+ {0xF0, 0x82},
+ {0xF0, 0x02},
+ {0xF1, 0xEC},
+ {0xF0, 0x83},
+ {0xF0, 0x03},
+ {0xF1, 0xE8},
+ {0xF0, 0x84},
+ {0xF0, 0x04},
+ {0xF1, 0xE4},
+ {0xF0, 0x85},
+ {0xF0, 0x05},
+ {0xF1, 0xE0},
+ {0xF0, 0x86},
+ {0xF0, 0x06},
+ {0xF1, 0xDC},
+ {0xF0, 0x87},
+ {0xF0, 0x07},
+ {0xF1, 0xD8},
+ {0xF0, 0x88},
+ {0xF0, 0x08},
+ {0xF1, 0xD4},
+ {0xF0, 0x89},
+ {0xF0, 0x09},
+ {0xF1, 0xD0},
+ {0xF0, 0x8A},
+ {0xF0, 0x0A},
+ {0xF1, 0xCC},
+ {0xF0, 0x8B},
+ {0xF0, 0x0B},
+ {0xF1, 0xC8},
+ {0xF0, 0x8C},
+ {0xF0, 0x0C},
+ {0xF1, 0xC4},
+ {0xF0, 0x8D},
+ {0xF0, 0x0D},
+ {0xF1, 0xC0},
+ {0xF0, 0x8E},
+ {0xF0, 0x0E},
+ {0xF1, 0xBC},
+ {0xF0, 0x8F},
+ {0xF0, 0x0F},
+ {0xF1, 0xB8},
+ {0xF0, 0x90},
+ {0xF0, 0x10},
+ {0xF1, 0xB4},
+ {0xF0, 0x91},
+ {0xF0, 0x11},
+ {0xF1, 0xB0},
+ {0xF0, 0x92},
+ {0xF0, 0x12},
+ {0xF1, 0xAC},
+ {0xF0, 0x93},
+ {0xF0, 0x13},
+ {0xF1, 0xA8},
+ {0xF0, 0x94},
+ {0xF0, 0x14},
+ {0xF1, 0xA4},
+ {0xF0, 0x95},
+ {0xF0, 0x15},
+ {0xF1, 0xA0},
+ {0xF0, 0x96},
+ {0xF0, 0x16},
+ {0xF1, 0x9C},
+ {0xF0, 0x97},
+ {0xF0, 0x17},
+ {0xF1, 0x98},
+ {0xF0, 0x98},
+ {0xF0, 0x18},
+ {0xF1, 0x94},
+ {0xF0, 0x99},
+ {0xF0, 0x19},
+ {0xF1, 0x90},
+ {0xF0, 0x9A},
+ {0xF0, 0x1A},
+ {0xF1, 0x8C},
+ {0xF0, 0x9B},
+ {0xF0, 0x1B},
+ {0xF1, 0x88},
+ {0xF0, 0x9C},
+ {0xF0, 0x1C},
+ {0xF1, 0x84},
+ {0xF0, 0x9D},
+ {0xF0, 0x1D},
+ {0xF1, 0x80},
+ {0xF0, 0x9E},
+ {0xF0, 0x1E},
+ {0xF1, 0x7C},
+ {0xF0, 0x9F},
+ {0xF0, 0x1F},
+ {0xF1, 0x78},
+ {0xF0, 0xA0},
+ {0xF0, 0x20},
+ {0xF1, 0x74},
+ {0xF0, 0xA1},
+ {0xF0, 0x21},
+ {0xF1, 0x70},
+ {0xF0, 0xA2},
+ {0xF0, 0x22},
+ {0xF1, 0x6C},
+ {0xF0, 0xA3},
+ {0xF0, 0x23},
+ {0xF1, 0x68},
+ {0xF0, 0xA4},
+ {0xF0, 0x24},
+ {0xF1, 0x64},
+ {0xF0, 0xA5},
+ {0xF0, 0x25},
+ {0xF1, 0x60},
+ {0xF0, 0xA6},
+ {0xF0, 0x26},
+ {0xF1, 0x5C},
+ {0xF0, 0xA7},
+ {0xF0, 0x27},
+ {0xF1, 0x58},
+ {0xF0, 0xA8},
+ {0xF0, 0x28},
+ {0xF1, 0x54},
+ {0xF0, 0xA9},
+ {0xF0, 0x29},
+ {0xF1, 0x50},
+ {0xF0, 0xAA},
+ {0xF0, 0x2A},
+ {0xF1, 0x4C},
+ {0xF0, 0xAB},
+ {0xF0, 0x2B},
+ {0xF1, 0x48},
+ {0xF0, 0xAC},
+ {0xF0, 0x2C},
+ {0xF1, 0x44},
+ {0xF0, 0xAD},
+ {0xF0, 0x2D},
+ {0xF1, 0x40},
+ {0xF0, 0xAE},
+ {0xF0, 0x2E},
+ {0xF1, 0x3C},
+ {0xF0, 0xAF},
+ {0xF0, 0x2F},
+ {0xF1, 0x38},
+ {0xF0, 0xB0},
+ {0xF0, 0x30},
+ {0xF1, 0x34},
+ {0xF0, 0xB1},
+ {0xF0, 0x31},
+ {0xF1, 0x30},
+ {0xF0, 0xB2},
+ {0xF0, 0x32},
+ {0xF1, 0x2C},
+ {0xF0, 0xB3},
+ {0xF0, 0x33},
+ {0xF1, 0x28},
+ {0xF0, 0xB4},
+ {0xF0, 0x34},
+ {0xF1, 0x24},
+ {0xF0, 0xB5},
+ {0xF0, 0x35},
+ {0xF1, 0x20},
+ {0xF0, 0xB6},
+ {0xF0, 0x36},
+ {0xF1, 0x1C},
+ {0xF0, 0xB7},
+ {0xF0, 0x37},
+ {0xF1, 0x18},
+ {0xF0, 0xB8},
+ {0xF0, 0x38},
+ {0xF1, 0x14},
+ {0xF0, 0xB9},
+ {0xF0, 0x39},
+ {0xF1, 0x10},
+ {0xF0, 0xBA},
+ {0xF0, 0x3A},
+ {0xF1, 0x0C},
+ {0xF0, 0xBB},
+ {0xF0, 0x3B},
+ {0xF1, 0x08},
+ {0xF0, 0x00},
+ {0xF0, 0x3C},
+ {0xF1, 0x04},
+ {0xF0, 0xBD},
+ {0xF0, 0x3D},
+ {0xF1, 0x00},
+ {0xF0, 0xBE},
+ {0xF0, 0x3E},
+ {0xF1, 0x00},
+ {0xF0, 0xBF},
+ {0xF0, 0x3F},
+ {0xF1, 0x00},
+ {0xF0, 0xC0},
+ {0xF0, 0x00},
};
#define CB_VT3253B0_INIT_FOR_RFMD 256
unsigned char byVT3253B0_RFMD[CB_VT3253B0_INIT_FOR_RFMD][2] = {
- {0x00, 0x31},
- {0x01, 0x00},
- {0x02, 0x00},
- {0x03, 0x00},
- {0x04, 0x00},
- {0x05, 0x81},
- {0x06, 0x00},
- {0x07, 0x00},
- {0x08, 0x38},
- {0x09, 0x45},
- {0x0a, 0x2a},
- {0x0b, 0x76},
- {0x0c, 0x00},
- {0x0d, 0x00},
- {0x0e, 0x80},
- {0x0f, 0x00},
- {0x10, 0x00},
- {0x11, 0x00},
- {0x12, 0x00},
- {0x13, 0x00},
- {0x14, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x17, 0x00},
- {0x18, 0x00},
- {0x19, 0x00},
- {0x1a, 0x00},
- {0x1b, 0x8e},
- {0x1c, 0x06},
- {0x1d, 0x00},
- {0x1e, 0x00},
- {0x1f, 0x00},
- {0x20, 0x00},
- {0x21, 0x00},
- {0x22, 0x00},
- {0x23, 0x00},
- {0x24, 0x00},
- {0x25, 0x4a},
- {0x26, 0x00},
- {0x27, 0x00},
- {0x28, 0x00},
- {0x29, 0x00},
- {0x2a, 0x00},
- {0x2b, 0x00},
- {0x2c, 0x00},
- {0x2d, 0x34},
- {0x2e, 0x18},
- {0x2f, 0x0c},
- {0x30, 0x26},
- {0x31, 0x5b},
- {0x32, 0x00},
- {0x33, 0x00},
- {0x34, 0x00},
- {0x35, 0x00},
- {0x36, 0xaa},
- {0x37, 0xaa},
- {0x38, 0xff},
- {0x39, 0xff},
- {0x3a, 0xf8},
- {0x3b, 0x00},
- {0x3c, 0x00},
- {0x3d, 0x09},
- {0x3e, 0x0d},
- {0x3f, 0x04},
- {0x40, 0x00},
- {0x41, 0x08},
- {0x42, 0x00},
- {0x43, 0x08},
- {0x44, 0x08},
- {0x45, 0x14},
- {0x46, 0x05},
- {0x47, 0x08},
- {0x48, 0x00},
- {0x49, 0x00},
- {0x4a, 0x00},
- {0x4b, 0x00},
- {0x4c, 0x09},
- {0x4d, 0x80},
- {0x4e, 0x00},
- {0x4f, 0xc5},
- {0x50, 0x14},
- {0x51, 0x19},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x56, 0x00},
- {0x57, 0x00},
- {0x58, 0x00},
- {0x59, 0xb0},
- {0x5a, 0x00},
- {0x5b, 0x00},
- {0x5c, 0x00},
- {0x5d, 0x00},
- {0x5e, 0x00},
- {0x5f, 0x00},
- {0x60, 0x39},
- {0x61, 0x83},
- {0x62, 0x00},
- {0x63, 0x00},
- {0x64, 0x00},
- {0x65, 0x00},
- {0x66, 0xc0},
- {0x67, 0x49},
- {0x68, 0x00},
- {0x69, 0x00},
- {0x6a, 0x00},
- {0x6b, 0x00},
- {0x6c, 0x00},
- {0x6d, 0x03},
- {0x6e, 0x01},
- {0x6f, 0x00},
- {0x70, 0x00},
- {0x71, 0x00},
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x00},
- {0x75, 0x00},
- {0x76, 0x00},
- {0x77, 0x00},
- {0x78, 0x00},
- {0x79, 0x00},
- {0x7a, 0x00},
- {0x7b, 0x00},
- {0x7c, 0x00},
- {0x7d, 0x00},
- {0x7e, 0x00},
- {0x7f, 0x00},
- {0x80, 0x89},
- {0x81, 0x00},
- {0x82, 0x0e},
- {0x83, 0x00},
- {0x84, 0x00},
- {0x85, 0x00},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x08},
- {0x89, 0x00},
- {0x8a, 0x0e},
- {0x8b, 0xa7},
- {0x8c, 0x88},
- {0x8d, 0x47},
- {0x8e, 0xaa},
- {0x8f, 0x02},
- {0x90, 0x23},
- {0x91, 0x0c},
- {0x92, 0x06},
- {0x93, 0x08},
- {0x94, 0x00},
- {0x95, 0x00},
- {0x96, 0x00},
- {0x97, 0xeb},
- {0x98, 0x00},
- {0x99, 0x00},
- {0x9a, 0x00},
- {0x9b, 0x00},
- {0x9c, 0x00},
- {0x9d, 0x00},
- {0x9e, 0x00},
- {0x9f, 0x00},
- {0xa0, 0x00},
- {0xa1, 0x00},
- {0xa2, 0x00},
- {0xa3, 0xcd},
- {0xa4, 0x07},
- {0xa5, 0x33},
- {0xa6, 0x18},
- {0xa7, 0x00},
- {0xa8, 0x18},
- {0xa9, 0x00},
- {0xaa, 0x28},
- {0xab, 0x00},
- {0xac, 0x00},
- {0xad, 0x00},
- {0xae, 0x00},
- {0xaf, 0x18},
- {0xb0, 0x38},
- {0xb1, 0x30},
- {0xb2, 0x00},
- {0xb3, 0x00},
- {0xb4, 0x00},
- {0xb5, 0x00},
- {0xb6, 0x84},
- {0xb7, 0xfd},
- {0xb8, 0x00},
- {0xb9, 0x00},
- {0xba, 0x00},
- {0xbb, 0x03},
- {0xbc, 0x00},
- {0xbd, 0x00},
- {0xbe, 0x00},
- {0xbf, 0x00},
- {0xc0, 0x10},
- {0xc1, 0x20},
- {0xc2, 0x18},
- {0xc3, 0x20},
- {0xc4, 0x10},
- {0xc5, 0x2c},
- {0xc6, 0x1e},
- {0xc7, 0x10},
- {0xc8, 0x12},
- {0xc9, 0x01},
- {0xca, 0x6f},
- {0xcb, 0xa7},
- {0xcc, 0x3c},
- {0xcd, 0x10},
- {0xce, 0x00},
- {0xcf, 0x22},
- {0xd0, 0x00},
- {0xd1, 0x10},
- {0xd2, 0x00},
- {0xd3, 0x00},
- {0xd4, 0x10},
- {0xd5, 0x33},
- {0xd6, 0x80},
- {0xd7, 0x21},
- {0xd8, 0x00},
- {0xd9, 0x00},
- {0xda, 0x00},
- {0xdb, 0x00},
- {0xdc, 0x00},
- {0xdd, 0x00},
- {0xde, 0x00},
- {0xdf, 0x00},
- {0xe0, 0x00},
- {0xe1, 0xB3},
- {0xe2, 0x00},
- {0xe3, 0x00},
- {0xe4, 0x00},
- {0xe5, 0x10},
- {0xe6, 0x00},
- {0xe7, 0x18},
- {0xe8, 0x08},
- {0xe9, 0xd4},
- {0xea, 0x00},
- {0xeb, 0xff},
- {0xec, 0x79},
- {0xed, 0x10},
- {0xee, 0x30},
- {0xef, 0x02},
- {0xf0, 0x00},
- {0xf1, 0x09},
- {0xf2, 0x00},
- {0xf3, 0x00},
- {0xf4, 0x00},
- {0xf5, 0x00},
- {0xf6, 0x00},
- {0xf7, 0x00},
- {0xf8, 0x00},
- {0xf9, 0x00},
- {0xfa, 0x00},
- {0xfb, 0x00},
- {0xfc, 0x00},
- {0xfd, 0x00},
- {0xfe, 0x00},
- {0xff, 0x00},
+ {0x00, 0x31},
+ {0x01, 0x00},
+ {0x02, 0x00},
+ {0x03, 0x00},
+ {0x04, 0x00},
+ {0x05, 0x81},
+ {0x06, 0x00},
+ {0x07, 0x00},
+ {0x08, 0x38},
+ {0x09, 0x45},
+ {0x0a, 0x2a},
+ {0x0b, 0x76},
+ {0x0c, 0x00},
+ {0x0d, 0x00},
+ {0x0e, 0x80},
+ {0x0f, 0x00},
+ {0x10, 0x00},
+ {0x11, 0x00},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x17, 0x00},
+ {0x18, 0x00},
+ {0x19, 0x00},
+ {0x1a, 0x00},
+ {0x1b, 0x8e},
+ {0x1c, 0x06},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x1f, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x4a},
+ {0x26, 0x00},
+ {0x27, 0x00},
+ {0x28, 0x00},
+ {0x29, 0x00},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x2c, 0x00},
+ {0x2d, 0x34},
+ {0x2e, 0x18},
+ {0x2f, 0x0c},
+ {0x30, 0x26},
+ {0x31, 0x5b},
+ {0x32, 0x00},
+ {0x33, 0x00},
+ {0x34, 0x00},
+ {0x35, 0x00},
+ {0x36, 0xaa},
+ {0x37, 0xaa},
+ {0x38, 0xff},
+ {0x39, 0xff},
+ {0x3a, 0xf8},
+ {0x3b, 0x00},
+ {0x3c, 0x00},
+ {0x3d, 0x09},
+ {0x3e, 0x0d},
+ {0x3f, 0x04},
+ {0x40, 0x00},
+ {0x41, 0x08},
+ {0x42, 0x00},
+ {0x43, 0x08},
+ {0x44, 0x08},
+ {0x45, 0x14},
+ {0x46, 0x05},
+ {0x47, 0x08},
+ {0x48, 0x00},
+ {0x49, 0x00},
+ {0x4a, 0x00},
+ {0x4b, 0x00},
+ {0x4c, 0x09},
+ {0x4d, 0x80},
+ {0x4e, 0x00},
+ {0x4f, 0xc5},
+ {0x50, 0x14},
+ {0x51, 0x19},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x56, 0x00},
+ {0x57, 0x00},
+ {0x58, 0x00},
+ {0x59, 0xb0},
+ {0x5a, 0x00},
+ {0x5b, 0x00},
+ {0x5c, 0x00},
+ {0x5d, 0x00},
+ {0x5e, 0x00},
+ {0x5f, 0x00},
+ {0x60, 0x39},
+ {0x61, 0x83},
+ {0x62, 0x00},
+ {0x63, 0x00},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0xc0},
+ {0x67, 0x49},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ {0x6c, 0x00},
+ {0x6d, 0x03},
+ {0x6e, 0x01},
+ {0x6f, 0x00},
+ {0x70, 0x00},
+ {0x71, 0x00},
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x00},
+ {0x75, 0x00},
+ {0x76, 0x00},
+ {0x77, 0x00},
+ {0x78, 0x00},
+ {0x79, 0x00},
+ {0x7a, 0x00},
+ {0x7b, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x00},
+ {0x7e, 0x00},
+ {0x7f, 0x00},
+ {0x80, 0x89},
+ {0x81, 0x00},
+ {0x82, 0x0e},
+ {0x83, 0x00},
+ {0x84, 0x00},
+ {0x85, 0x00},
+ {0x86, 0x00},
+ {0x87, 0x00},
+ {0x88, 0x08},
+ {0x89, 0x00},
+ {0x8a, 0x0e},
+ {0x8b, 0xa7},
+ {0x8c, 0x88},
+ {0x8d, 0x47},
+ {0x8e, 0xaa},
+ {0x8f, 0x02},
+ {0x90, 0x23},
+ {0x91, 0x0c},
+ {0x92, 0x06},
+ {0x93, 0x08},
+ {0x94, 0x00},
+ {0x95, 0x00},
+ {0x96, 0x00},
+ {0x97, 0xeb},
+ {0x98, 0x00},
+ {0x99, 0x00},
+ {0x9a, 0x00},
+ {0x9b, 0x00},
+ {0x9c, 0x00},
+ {0x9d, 0x00},
+ {0x9e, 0x00},
+ {0x9f, 0x00},
+ {0xa0, 0x00},
+ {0xa1, 0x00},
+ {0xa2, 0x00},
+ {0xa3, 0xcd},
+ {0xa4, 0x07},
+ {0xa5, 0x33},
+ {0xa6, 0x18},
+ {0xa7, 0x00},
+ {0xa8, 0x18},
+ {0xa9, 0x00},
+ {0xaa, 0x28},
+ {0xab, 0x00},
+ {0xac, 0x00},
+ {0xad, 0x00},
+ {0xae, 0x00},
+ {0xaf, 0x18},
+ {0xb0, 0x38},
+ {0xb1, 0x30},
+ {0xb2, 0x00},
+ {0xb3, 0x00},
+ {0xb4, 0x00},
+ {0xb5, 0x00},
+ {0xb6, 0x84},
+ {0xb7, 0xfd},
+ {0xb8, 0x00},
+ {0xb9, 0x00},
+ {0xba, 0x00},
+ {0xbb, 0x03},
+ {0xbc, 0x00},
+ {0xbd, 0x00},
+ {0xbe, 0x00},
+ {0xbf, 0x00},
+ {0xc0, 0x10},
+ {0xc1, 0x20},
+ {0xc2, 0x18},
+ {0xc3, 0x20},
+ {0xc4, 0x10},
+ {0xc5, 0x2c},
+ {0xc6, 0x1e},
+ {0xc7, 0x10},
+ {0xc8, 0x12},
+ {0xc9, 0x01},
+ {0xca, 0x6f},
+ {0xcb, 0xa7},
+ {0xcc, 0x3c},
+ {0xcd, 0x10},
+ {0xce, 0x00},
+ {0xcf, 0x22},
+ {0xd0, 0x00},
+ {0xd1, 0x10},
+ {0xd2, 0x00},
+ {0xd3, 0x00},
+ {0xd4, 0x10},
+ {0xd5, 0x33},
+ {0xd6, 0x80},
+ {0xd7, 0x21},
+ {0xd8, 0x00},
+ {0xd9, 0x00},
+ {0xda, 0x00},
+ {0xdb, 0x00},
+ {0xdc, 0x00},
+ {0xdd, 0x00},
+ {0xde, 0x00},
+ {0xdf, 0x00},
+ {0xe0, 0x00},
+ {0xe1, 0xB3},
+ {0xe2, 0x00},
+ {0xe3, 0x00},
+ {0xe4, 0x00},
+ {0xe5, 0x10},
+ {0xe6, 0x00},
+ {0xe7, 0x18},
+ {0xe8, 0x08},
+ {0xe9, 0xd4},
+ {0xea, 0x00},
+ {0xeb, 0xff},
+ {0xec, 0x79},
+ {0xed, 0x10},
+ {0xee, 0x30},
+ {0xef, 0x02},
+ {0xf0, 0x00},
+ {0xf1, 0x09},
+ {0xf2, 0x00},
+ {0xf3, 0x00},
+ {0xf4, 0x00},
+ {0xf5, 0x00},
+ {0xf6, 0x00},
+ {0xf7, 0x00},
+ {0xf8, 0x00},
+ {0xf9, 0x00},
+ {0xfa, 0x00},
+ {0xfb, 0x00},
+ {0xfc, 0x00},
+ {0xfd, 0x00},
+ {0xfe, 0x00},
+ {0xff, 0x00},
};
#define CB_VT3253B0_AGC_FOR_RFMD2959 195
// For RFMD2959
unsigned char byVT3253B0_AGC4_RFMD2959[CB_VT3253B0_AGC_FOR_RFMD2959][2] = {
- {0xF0, 0x00},
- {0xF1, 0x3E},
- {0xF0, 0x80},
- {0xF0, 0x00},
- {0xF1, 0x3E},
- {0xF0, 0x81},
- {0xF0, 0x01},
- {0xF1, 0x3E},
- {0xF0, 0x82},
- {0xF0, 0x02},
- {0xF1, 0x3E},
- {0xF0, 0x83},
- {0xF0, 0x03},
- {0xF1, 0x3B},
- {0xF0, 0x84},
- {0xF0, 0x04},
- {0xF1, 0x39},
- {0xF0, 0x85},
- {0xF0, 0x05},
- {0xF1, 0x38},
- {0xF0, 0x86},
- {0xF0, 0x06},
- {0xF1, 0x37},
- {0xF0, 0x87},
- {0xF0, 0x07},
- {0xF1, 0x36},
- {0xF0, 0x88},
- {0xF0, 0x08},
- {0xF1, 0x35},
- {0xF0, 0x89},
- {0xF0, 0x09},
- {0xF1, 0x35},
- {0xF0, 0x8A},
- {0xF0, 0x0A},
- {0xF1, 0x34},
- {0xF0, 0x8B},
- {0xF0, 0x0B},
- {0xF1, 0x34},
- {0xF0, 0x8C},
- {0xF0, 0x0C},
- {0xF1, 0x33},
- {0xF0, 0x8D},
- {0xF0, 0x0D},
- {0xF1, 0x32},
- {0xF0, 0x8E},
- {0xF0, 0x0E},
- {0xF1, 0x31},
- {0xF0, 0x8F},
- {0xF0, 0x0F},
- {0xF1, 0x30},
- {0xF0, 0x90},
- {0xF0, 0x10},
- {0xF1, 0x2F},
- {0xF0, 0x91},
- {0xF0, 0x11},
- {0xF1, 0x2F},
- {0xF0, 0x92},
- {0xF0, 0x12},
- {0xF1, 0x2E},
- {0xF0, 0x93},
- {0xF0, 0x13},
- {0xF1, 0x2D},
- {0xF0, 0x94},
- {0xF0, 0x14},
- {0xF1, 0x2C},
- {0xF0, 0x95},
- {0xF0, 0x15},
- {0xF1, 0x2B},
- {0xF0, 0x96},
- {0xF0, 0x16},
- {0xF1, 0x2B},
- {0xF0, 0x97},
- {0xF0, 0x17},
- {0xF1, 0x2A},
- {0xF0, 0x98},
- {0xF0, 0x18},
- {0xF1, 0x29},
- {0xF0, 0x99},
- {0xF0, 0x19},
- {0xF1, 0x28},
- {0xF0, 0x9A},
- {0xF0, 0x1A},
- {0xF1, 0x27},
- {0xF0, 0x9B},
- {0xF0, 0x1B},
- {0xF1, 0x26},
- {0xF0, 0x9C},
- {0xF0, 0x1C},
- {0xF1, 0x25},
- {0xF0, 0x9D},
- {0xF0, 0x1D},
- {0xF1, 0x24},
- {0xF0, 0x9E},
- {0xF0, 0x1E},
- {0xF1, 0x24},
- {0xF0, 0x9F},
- {0xF0, 0x1F},
- {0xF1, 0x23},
- {0xF0, 0xA0},
- {0xF0, 0x20},
- {0xF1, 0x22},
- {0xF0, 0xA1},
- {0xF0, 0x21},
- {0xF1, 0x21},
- {0xF0, 0xA2},
- {0xF0, 0x22},
- {0xF1, 0x20},
- {0xF0, 0xA3},
- {0xF0, 0x23},
- {0xF1, 0x20},
- {0xF0, 0xA4},
- {0xF0, 0x24},
- {0xF1, 0x1F},
- {0xF0, 0xA5},
- {0xF0, 0x25},
- {0xF1, 0x1E},
- {0xF0, 0xA6},
- {0xF0, 0x26},
- {0xF1, 0x1D},
- {0xF0, 0xA7},
- {0xF0, 0x27},
- {0xF1, 0x1C},
- {0xF0, 0xA8},
- {0xF0, 0x28},
- {0xF1, 0x1B},
- {0xF0, 0xA9},
- {0xF0, 0x29},
- {0xF1, 0x1B},
- {0xF0, 0xAA},
- {0xF0, 0x2A},
- {0xF1, 0x1A},
- {0xF0, 0xAB},
- {0xF0, 0x2B},
- {0xF1, 0x1A},
- {0xF0, 0xAC},
- {0xF0, 0x2C},
- {0xF1, 0x19},
- {0xF0, 0xAD},
- {0xF0, 0x2D},
- {0xF1, 0x18},
- {0xF0, 0xAE},
- {0xF0, 0x2E},
- {0xF1, 0x17},
- {0xF0, 0xAF},
- {0xF0, 0x2F},
- {0xF1, 0x16},
- {0xF0, 0xB0},
- {0xF0, 0x30},
- {0xF1, 0x15},
- {0xF0, 0xB1},
- {0xF0, 0x31},
- {0xF1, 0x15},
- {0xF0, 0xB2},
- {0xF0, 0x32},
- {0xF1, 0x15},
- {0xF0, 0xB3},
- {0xF0, 0x33},
- {0xF1, 0x14},
- {0xF0, 0xB4},
- {0xF0, 0x34},
- {0xF1, 0x13},
- {0xF0, 0xB5},
- {0xF0, 0x35},
- {0xF1, 0x12},
- {0xF0, 0xB6},
- {0xF0, 0x36},
- {0xF1, 0x11},
- {0xF0, 0xB7},
- {0xF0, 0x37},
- {0xF1, 0x10},
- {0xF0, 0xB8},
- {0xF0, 0x38},
- {0xF1, 0x0F},
- {0xF0, 0xB9},
- {0xF0, 0x39},
- {0xF1, 0x0E},
- {0xF0, 0xBA},
- {0xF0, 0x3A},
- {0xF1, 0x0D},
- {0xF0, 0xBB},
- {0xF0, 0x3B},
- {0xF1, 0x0C},
- {0xF0, 0xBC},
- {0xF0, 0x3C},
- {0xF1, 0x0B},
- {0xF0, 0xBD},
- {0xF0, 0x3D},
- {0xF1, 0x0B},
- {0xF0, 0xBE},
- {0xF0, 0x3E},
- {0xF1, 0x0A},
- {0xF0, 0xBF},
- {0xF0, 0x3F},
- {0xF1, 0x09},
- {0xF0, 0x00},
+ {0xF0, 0x00},
+ {0xF1, 0x3E},
+ {0xF0, 0x80},
+ {0xF0, 0x00},
+ {0xF1, 0x3E},
+ {0xF0, 0x81},
+ {0xF0, 0x01},
+ {0xF1, 0x3E},
+ {0xF0, 0x82},
+ {0xF0, 0x02},
+ {0xF1, 0x3E},
+ {0xF0, 0x83},
+ {0xF0, 0x03},
+ {0xF1, 0x3B},
+ {0xF0, 0x84},
+ {0xF0, 0x04},
+ {0xF1, 0x39},
+ {0xF0, 0x85},
+ {0xF0, 0x05},
+ {0xF1, 0x38},
+ {0xF0, 0x86},
+ {0xF0, 0x06},
+ {0xF1, 0x37},
+ {0xF0, 0x87},
+ {0xF0, 0x07},
+ {0xF1, 0x36},
+ {0xF0, 0x88},
+ {0xF0, 0x08},
+ {0xF1, 0x35},
+ {0xF0, 0x89},
+ {0xF0, 0x09},
+ {0xF1, 0x35},
+ {0xF0, 0x8A},
+ {0xF0, 0x0A},
+ {0xF1, 0x34},
+ {0xF0, 0x8B},
+ {0xF0, 0x0B},
+ {0xF1, 0x34},
+ {0xF0, 0x8C},
+ {0xF0, 0x0C},
+ {0xF1, 0x33},
+ {0xF0, 0x8D},
+ {0xF0, 0x0D},
+ {0xF1, 0x32},
+ {0xF0, 0x8E},
+ {0xF0, 0x0E},
+ {0xF1, 0x31},
+ {0xF0, 0x8F},
+ {0xF0, 0x0F},
+ {0xF1, 0x30},
+ {0xF0, 0x90},
+ {0xF0, 0x10},
+ {0xF1, 0x2F},
+ {0xF0, 0x91},
+ {0xF0, 0x11},
+ {0xF1, 0x2F},
+ {0xF0, 0x92},
+ {0xF0, 0x12},
+ {0xF1, 0x2E},
+ {0xF0, 0x93},
+ {0xF0, 0x13},
+ {0xF1, 0x2D},
+ {0xF0, 0x94},
+ {0xF0, 0x14},
+ {0xF1, 0x2C},
+ {0xF0, 0x95},
+ {0xF0, 0x15},
+ {0xF1, 0x2B},
+ {0xF0, 0x96},
+ {0xF0, 0x16},
+ {0xF1, 0x2B},
+ {0xF0, 0x97},
+ {0xF0, 0x17},
+ {0xF1, 0x2A},
+ {0xF0, 0x98},
+ {0xF0, 0x18},
+ {0xF1, 0x29},
+ {0xF0, 0x99},
+ {0xF0, 0x19},
+ {0xF1, 0x28},
+ {0xF0, 0x9A},
+ {0xF0, 0x1A},
+ {0xF1, 0x27},
+ {0xF0, 0x9B},
+ {0xF0, 0x1B},
+ {0xF1, 0x26},
+ {0xF0, 0x9C},
+ {0xF0, 0x1C},
+ {0xF1, 0x25},
+ {0xF0, 0x9D},
+ {0xF0, 0x1D},
+ {0xF1, 0x24},
+ {0xF0, 0x9E},
+ {0xF0, 0x1E},
+ {0xF1, 0x24},
+ {0xF0, 0x9F},
+ {0xF0, 0x1F},
+ {0xF1, 0x23},
+ {0xF0, 0xA0},
+ {0xF0, 0x20},
+ {0xF1, 0x22},
+ {0xF0, 0xA1},
+ {0xF0, 0x21},
+ {0xF1, 0x21},
+ {0xF0, 0xA2},
+ {0xF0, 0x22},
+ {0xF1, 0x20},
+ {0xF0, 0xA3},
+ {0xF0, 0x23},
+ {0xF1, 0x20},
+ {0xF0, 0xA4},
+ {0xF0, 0x24},
+ {0xF1, 0x1F},
+ {0xF0, 0xA5},
+ {0xF0, 0x25},
+ {0xF1, 0x1E},
+ {0xF0, 0xA6},
+ {0xF0, 0x26},
+ {0xF1, 0x1D},
+ {0xF0, 0xA7},
+ {0xF0, 0x27},
+ {0xF1, 0x1C},
+ {0xF0, 0xA8},
+ {0xF0, 0x28},
+ {0xF1, 0x1B},
+ {0xF0, 0xA9},
+ {0xF0, 0x29},
+ {0xF1, 0x1B},
+ {0xF0, 0xAA},
+ {0xF0, 0x2A},
+ {0xF1, 0x1A},
+ {0xF0, 0xAB},
+ {0xF0, 0x2B},
+ {0xF1, 0x1A},
+ {0xF0, 0xAC},
+ {0xF0, 0x2C},
+ {0xF1, 0x19},
+ {0xF0, 0xAD},
+ {0xF0, 0x2D},
+ {0xF1, 0x18},
+ {0xF0, 0xAE},
+ {0xF0, 0x2E},
+ {0xF1, 0x17},
+ {0xF0, 0xAF},
+ {0xF0, 0x2F},
+ {0xF1, 0x16},
+ {0xF0, 0xB0},
+ {0xF0, 0x30},
+ {0xF1, 0x15},
+ {0xF0, 0xB1},
+ {0xF0, 0x31},
+ {0xF1, 0x15},
+ {0xF0, 0xB2},
+ {0xF0, 0x32},
+ {0xF1, 0x15},
+ {0xF0, 0xB3},
+ {0xF0, 0x33},
+ {0xF1, 0x14},
+ {0xF0, 0xB4},
+ {0xF0, 0x34},
+ {0xF1, 0x13},
+ {0xF0, 0xB5},
+ {0xF0, 0x35},
+ {0xF1, 0x12},
+ {0xF0, 0xB6},
+ {0xF0, 0x36},
+ {0xF1, 0x11},
+ {0xF0, 0xB7},
+ {0xF0, 0x37},
+ {0xF1, 0x10},
+ {0xF0, 0xB8},
+ {0xF0, 0x38},
+ {0xF1, 0x0F},
+ {0xF0, 0xB9},
+ {0xF0, 0x39},
+ {0xF1, 0x0E},
+ {0xF0, 0xBA},
+ {0xF0, 0x3A},
+ {0xF1, 0x0D},
+ {0xF0, 0xBB},
+ {0xF0, 0x3B},
+ {0xF1, 0x0C},
+ {0xF0, 0xBC},
+ {0xF0, 0x3C},
+ {0xF1, 0x0B},
+ {0xF0, 0xBD},
+ {0xF0, 0x3D},
+ {0xF1, 0x0B},
+ {0xF0, 0xBE},
+ {0xF0, 0x3E},
+ {0xF1, 0x0A},
+ {0xF0, 0xBF},
+ {0xF0, 0x3F},
+ {0xF1, 0x09},
+ {0xF0, 0x00},
};
#define CB_VT3253B0_INIT_FOR_AIROHA2230 256
// For AIROHA
unsigned char byVT3253B0_AIROHA2230[CB_VT3253B0_INIT_FOR_AIROHA2230][2] = {
- {0x00, 0x31},
- {0x01, 0x00},
- {0x02, 0x00},
- {0x03, 0x00},
- {0x04, 0x00},
- {0x05, 0x80},
- {0x06, 0x00},
- {0x07, 0x00},
- {0x08, 0x70},
- {0x09, 0x41},
- {0x0a, 0x2A},
- {0x0b, 0x76},
- {0x0c, 0x00},
- {0x0d, 0x00},
- {0x0e, 0x80},
- {0x0f, 0x00},
- {0x10, 0x00},
- {0x11, 0x00},
- {0x12, 0x00},
- {0x13, 0x00},
- {0x14, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x17, 0x00},
- {0x18, 0x00},
- {0x19, 0x00},
- {0x1a, 0x00},
- {0x1b, 0x8f},
- {0x1c, 0x09},
- {0x1d, 0x00},
- {0x1e, 0x00},
- {0x1f, 0x00},
- {0x20, 0x00},
- {0x21, 0x00},
- {0x22, 0x00},
- {0x23, 0x00},
- {0x24, 0x00},
- {0x25, 0x4a},
- {0x26, 0x00},
- {0x27, 0x00},
- {0x28, 0x00},
- {0x29, 0x00},
- {0x2a, 0x00},
- {0x2b, 0x00},
- {0x2c, 0x00},
- {0x2d, 0x4a},
- {0x2e, 0x00},
- {0x2f, 0x0a},
- {0x30, 0x26},
- {0x31, 0x5b},
- {0x32, 0x00},
- {0x33, 0x00},
- {0x34, 0x00},
- {0x35, 0x00},
- {0x36, 0xaa},
- {0x37, 0xaa},
- {0x38, 0xff},
- {0x39, 0xff},
- {0x3a, 0x79},
- {0x3b, 0x00},
- {0x3c, 0x00},
- {0x3d, 0x0b},
- {0x3e, 0x48},
- {0x3f, 0x04},
- {0x40, 0x00},
- {0x41, 0x08},
- {0x42, 0x00},
- {0x43, 0x08},
- {0x44, 0x08},
- {0x45, 0x14},
- {0x46, 0x05},
- {0x47, 0x09},
- {0x48, 0x00},
- {0x49, 0x00},
- {0x4a, 0x00},
- {0x4b, 0x00},
- {0x4c, 0x09},
- {0x4d, 0x73},
- {0x4e, 0x00},
- {0x4f, 0xc5},
- {0x50, 0x15},
- {0x51, 0x19},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x56, 0x00},
- {0x57, 0x00},
- {0x58, 0x00},
- {0x59, 0xb0},
- {0x5a, 0x00},
- {0x5b, 0x00},
- {0x5c, 0x00},
- {0x5d, 0x00},
- {0x5e, 0x00},
- {0x5f, 0x00},
- {0x60, 0xe4},
- {0x61, 0x80},
- {0x62, 0x00},
- {0x63, 0x00},
- {0x64, 0x00},
- {0x65, 0x00},
- {0x66, 0x98},
- {0x67, 0x0a},
- {0x68, 0x00},
- {0x69, 0x00},
- {0x6a, 0x00},
- {0x6b, 0x00},
- //{0x6c, 0x80},
- {0x6c, 0x00}, //RobertYu:20050125, request by JJSue
- {0x6d, 0x03},
- {0x6e, 0x01},
- {0x6f, 0x00},
- {0x70, 0x00},
- {0x71, 0x00},
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x00},
- {0x75, 0x00},
- {0x76, 0x00},
- {0x77, 0x00},
- {0x78, 0x00},
- {0x79, 0x00},
- {0x7a, 0x00},
- {0x7b, 0x00},
- {0x7c, 0x00},
- {0x7d, 0x00},
- {0x7e, 0x00},
- {0x7f, 0x00},
- {0x80, 0x8c},
- {0x81, 0x01},
- {0x82, 0x09},
- {0x83, 0x00},
- {0x84, 0x00},
- {0x85, 0x00},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x08},
- {0x89, 0x00},
- {0x8a, 0x0f},
- {0x8b, 0xb7},
- {0x8c, 0x88},
- {0x8d, 0x47},
- {0x8e, 0xaa},
- {0x8f, 0x02},
- {0x90, 0x22},
- {0x91, 0x00},
- {0x92, 0x00},
- {0x93, 0x00},
- {0x94, 0x00},
- {0x95, 0x00},
- {0x96, 0x00},
- {0x97, 0xeb},
- {0x98, 0x00},
- {0x99, 0x00},
- {0x9a, 0x00},
- {0x9b, 0x00},
- {0x9c, 0x00},
- {0x9d, 0x00},
- {0x9e, 0x00},
- {0x9f, 0x01},
- {0xa0, 0x00},
- {0xa1, 0x00},
- {0xa2, 0x00},
- {0xa3, 0x00},
- {0xa4, 0x00},
- {0xa5, 0x00},
- {0xa6, 0x10},
- {0xa7, 0x00},
- {0xa8, 0x18},
- {0xa9, 0x00},
- {0xaa, 0x00},
- {0xab, 0x00},
- {0xac, 0x00},
- {0xad, 0x00},
- {0xae, 0x00},
- {0xaf, 0x18},
- {0xb0, 0x38},
- {0xb1, 0x30},
- {0xb2, 0x00},
- {0xb3, 0x00},
- {0xb4, 0xff},
- {0xb5, 0x0f},
- {0xb6, 0xe4},
- {0xb7, 0xe2},
- {0xb8, 0x00},
- {0xb9, 0x00},
- {0xba, 0x00},
- {0xbb, 0x03},
- {0xbc, 0x01},
- {0xbd, 0x00},
- {0xbe, 0x00},
- {0xbf, 0x00},
- {0xc0, 0x18},
- {0xc1, 0x20},
- {0xc2, 0x07},
- {0xc3, 0x18},
- {0xc4, 0xff},
- {0xc5, 0x2c},
- {0xc6, 0x0c},
- {0xc7, 0x0a},
- {0xc8, 0x0e},
- {0xc9, 0x01},
- {0xca, 0x68},
- {0xcb, 0xa7},
- {0xcc, 0x3c},
- {0xcd, 0x10},
- {0xce, 0x00},
- {0xcf, 0x25},
- {0xd0, 0x40},
- {0xd1, 0x12},
- {0xd2, 0x00},
- {0xd3, 0x00},
- {0xd4, 0x10},
- {0xd5, 0x28},
- {0xd6, 0x80},
- {0xd7, 0x2A},
- {0xd8, 0x00},
- {0xd9, 0x00},
- {0xda, 0x00},
- {0xdb, 0x00},
- {0xdc, 0x00},
- {0xdd, 0x00},
- {0xde, 0x00},
- {0xdf, 0x00},
- {0xe0, 0x00},
- {0xe1, 0xB3},
- {0xe2, 0x00},
- {0xe3, 0x00},
- {0xe4, 0x00},
- {0xe5, 0x10},
- {0xe6, 0x00},
- {0xe7, 0x1C},
- {0xe8, 0x00},
- {0xe9, 0xf4},
- {0xea, 0x00},
- {0xeb, 0xff},
- {0xec, 0x79},
- {0xed, 0x20},
- {0xee, 0x30},
- {0xef, 0x01},
- {0xf0, 0x00},
- {0xf1, 0x3e},
- {0xf2, 0x00},
- {0xf3, 0x00},
- {0xf4, 0x00},
- {0xf5, 0x00},
- {0xf6, 0x00},
- {0xf7, 0x00},
- {0xf8, 0x00},
- {0xf9, 0x00},
- {0xfa, 0x00},
- {0xfb, 0x00},
- {0xfc, 0x00},
- {0xfd, 0x00},
- {0xfe, 0x00},
- {0xff, 0x00},
+ {0x00, 0x31},
+ {0x01, 0x00},
+ {0x02, 0x00},
+ {0x03, 0x00},
+ {0x04, 0x00},
+ {0x05, 0x80},
+ {0x06, 0x00},
+ {0x07, 0x00},
+ {0x08, 0x70},
+ {0x09, 0x41},
+ {0x0a, 0x2A},
+ {0x0b, 0x76},
+ {0x0c, 0x00},
+ {0x0d, 0x00},
+ {0x0e, 0x80},
+ {0x0f, 0x00},
+ {0x10, 0x00},
+ {0x11, 0x00},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x17, 0x00},
+ {0x18, 0x00},
+ {0x19, 0x00},
+ {0x1a, 0x00},
+ {0x1b, 0x8f},
+ {0x1c, 0x09},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x1f, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x4a},
+ {0x26, 0x00},
+ {0x27, 0x00},
+ {0x28, 0x00},
+ {0x29, 0x00},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x2c, 0x00},
+ {0x2d, 0x4a},
+ {0x2e, 0x00},
+ {0x2f, 0x0a},
+ {0x30, 0x26},
+ {0x31, 0x5b},
+ {0x32, 0x00},
+ {0x33, 0x00},
+ {0x34, 0x00},
+ {0x35, 0x00},
+ {0x36, 0xaa},
+ {0x37, 0xaa},
+ {0x38, 0xff},
+ {0x39, 0xff},
+ {0x3a, 0x79},
+ {0x3b, 0x00},
+ {0x3c, 0x00},
+ {0x3d, 0x0b},
+ {0x3e, 0x48},
+ {0x3f, 0x04},
+ {0x40, 0x00},
+ {0x41, 0x08},
+ {0x42, 0x00},
+ {0x43, 0x08},
+ {0x44, 0x08},
+ {0x45, 0x14},
+ {0x46, 0x05},
+ {0x47, 0x09},
+ {0x48, 0x00},
+ {0x49, 0x00},
+ {0x4a, 0x00},
+ {0x4b, 0x00},
+ {0x4c, 0x09},
+ {0x4d, 0x73},
+ {0x4e, 0x00},
+ {0x4f, 0xc5},
+ {0x50, 0x15},
+ {0x51, 0x19},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x56, 0x00},
+ {0x57, 0x00},
+ {0x58, 0x00},
+ {0x59, 0xb0},
+ {0x5a, 0x00},
+ {0x5b, 0x00},
+ {0x5c, 0x00},
+ {0x5d, 0x00},
+ {0x5e, 0x00},
+ {0x5f, 0x00},
+ {0x60, 0xe4},
+ {0x61, 0x80},
+ {0x62, 0x00},
+ {0x63, 0x00},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x98},
+ {0x67, 0x0a},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ //{0x6c, 0x80},
+ {0x6c, 0x00}, //RobertYu:20050125, request by JJSue
+ {0x6d, 0x03},
+ {0x6e, 0x01},
+ {0x6f, 0x00},
+ {0x70, 0x00},
+ {0x71, 0x00},
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x00},
+ {0x75, 0x00},
+ {0x76, 0x00},
+ {0x77, 0x00},
+ {0x78, 0x00},
+ {0x79, 0x00},
+ {0x7a, 0x00},
+ {0x7b, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x00},
+ {0x7e, 0x00},
+ {0x7f, 0x00},
+ {0x80, 0x8c},
+ {0x81, 0x01},
+ {0x82, 0x09},
+ {0x83, 0x00},
+ {0x84, 0x00},
+ {0x85, 0x00},
+ {0x86, 0x00},
+ {0x87, 0x00},
+ {0x88, 0x08},
+ {0x89, 0x00},
+ {0x8a, 0x0f},
+ {0x8b, 0xb7},
+ {0x8c, 0x88},
+ {0x8d, 0x47},
+ {0x8e, 0xaa},
+ {0x8f, 0x02},
+ {0x90, 0x22},
+ {0x91, 0x00},
+ {0x92, 0x00},
+ {0x93, 0x00},
+ {0x94, 0x00},
+ {0x95, 0x00},
+ {0x96, 0x00},
+ {0x97, 0xeb},
+ {0x98, 0x00},
+ {0x99, 0x00},
+ {0x9a, 0x00},
+ {0x9b, 0x00},
+ {0x9c, 0x00},
+ {0x9d, 0x00},
+ {0x9e, 0x00},
+ {0x9f, 0x01},
+ {0xa0, 0x00},
+ {0xa1, 0x00},
+ {0xa2, 0x00},
+ {0xa3, 0x00},
+ {0xa4, 0x00},
+ {0xa5, 0x00},
+ {0xa6, 0x10},
+ {0xa7, 0x00},
+ {0xa8, 0x18},
+ {0xa9, 0x00},
+ {0xaa, 0x00},
+ {0xab, 0x00},
+ {0xac, 0x00},
+ {0xad, 0x00},
+ {0xae, 0x00},
+ {0xaf, 0x18},
+ {0xb0, 0x38},
+ {0xb1, 0x30},
+ {0xb2, 0x00},
+ {0xb3, 0x00},
+ {0xb4, 0xff},
+ {0xb5, 0x0f},
+ {0xb6, 0xe4},
+ {0xb7, 0xe2},
+ {0xb8, 0x00},
+ {0xb9, 0x00},
+ {0xba, 0x00},
+ {0xbb, 0x03},
+ {0xbc, 0x01},
+ {0xbd, 0x00},
+ {0xbe, 0x00},
+ {0xbf, 0x00},
+ {0xc0, 0x18},
+ {0xc1, 0x20},
+ {0xc2, 0x07},
+ {0xc3, 0x18},
+ {0xc4, 0xff},
+ {0xc5, 0x2c},
+ {0xc6, 0x0c},
+ {0xc7, 0x0a},
+ {0xc8, 0x0e},
+ {0xc9, 0x01},
+ {0xca, 0x68},
+ {0xcb, 0xa7},
+ {0xcc, 0x3c},
+ {0xcd, 0x10},
+ {0xce, 0x00},
+ {0xcf, 0x25},
+ {0xd0, 0x40},
+ {0xd1, 0x12},
+ {0xd2, 0x00},
+ {0xd3, 0x00},
+ {0xd4, 0x10},
+ {0xd5, 0x28},
+ {0xd6, 0x80},
+ {0xd7, 0x2A},
+ {0xd8, 0x00},
+ {0xd9, 0x00},
+ {0xda, 0x00},
+ {0xdb, 0x00},
+ {0xdc, 0x00},
+ {0xdd, 0x00},
+ {0xde, 0x00},
+ {0xdf, 0x00},
+ {0xe0, 0x00},
+ {0xe1, 0xB3},
+ {0xe2, 0x00},
+ {0xe3, 0x00},
+ {0xe4, 0x00},
+ {0xe5, 0x10},
+ {0xe6, 0x00},
+ {0xe7, 0x1C},
+ {0xe8, 0x00},
+ {0xe9, 0xf4},
+ {0xea, 0x00},
+ {0xeb, 0xff},
+ {0xec, 0x79},
+ {0xed, 0x20},
+ {0xee, 0x30},
+ {0xef, 0x01},
+ {0xf0, 0x00},
+ {0xf1, 0x3e},
+ {0xf2, 0x00},
+ {0xf3, 0x00},
+ {0xf4, 0x00},
+ {0xf5, 0x00},
+ {0xf6, 0x00},
+ {0xf7, 0x00},
+ {0xf8, 0x00},
+ {0xf9, 0x00},
+ {0xfa, 0x00},
+ {0xfb, 0x00},
+ {0xfc, 0x00},
+ {0xfd, 0x00},
+ {0xfe, 0x00},
+ {0xff, 0x00},
};
-
-
#define CB_VT3253B0_INIT_FOR_UW2451 256
//For UW2451
unsigned char byVT3253B0_UW2451[CB_VT3253B0_INIT_FOR_UW2451][2] = {
- {0x00, 0x31},
- {0x01, 0x00},
- {0x02, 0x00},
- {0x03, 0x00},
- {0x04, 0x00},
- {0x05, 0x81},
- {0x06, 0x00},
- {0x07, 0x00},
- {0x08, 0x38},
- {0x09, 0x45},
- {0x0a, 0x28},
- {0x0b, 0x76},
- {0x0c, 0x00},
- {0x0d, 0x00},
- {0x0e, 0x80},
- {0x0f, 0x00},
- {0x10, 0x00},
- {0x11, 0x00},
- {0x12, 0x00},
- {0x13, 0x00},
- {0x14, 0x00},
- {0x15, 0x00},
- {0x16, 0x00},
- {0x17, 0x00},
- {0x18, 0x00},
- {0x19, 0x00},
- {0x1a, 0x00},
- {0x1b, 0x8f},
- {0x1c, 0x0f},
- {0x1d, 0x00},
- {0x1e, 0x00},
- {0x1f, 0x00},
- {0x20, 0x00},
- {0x21, 0x00},
- {0x22, 0x00},
- {0x23, 0x00},
- {0x24, 0x00},
- {0x25, 0x4a},
- {0x26, 0x00},
- {0x27, 0x00},
- {0x28, 0x00},
- {0x29, 0x00},
- {0x2a, 0x00},
- {0x2b, 0x00},
- {0x2c, 0x00},
- {0x2d, 0x18},
- {0x2e, 0x00},
- {0x2f, 0x0a},
- {0x30, 0x26},
- {0x31, 0x5b},
- {0x32, 0x00},
- {0x33, 0x00},
- {0x34, 0x00},
- {0x35, 0x00},
- {0x36, 0xaa},
- {0x37, 0xaa},
- {0x38, 0xff},
- {0x39, 0xff},
- {0x3a, 0x00},
- {0x3b, 0x00},
- {0x3c, 0x00},
- {0x3d, 0x03},
- {0x3e, 0x1d},
- {0x3f, 0x04},
- {0x40, 0x00},
- {0x41, 0x08},
- {0x42, 0x00},
- {0x43, 0x08},
- {0x44, 0x08},
- {0x45, 0x14},
- {0x46, 0x05},
- {0x47, 0x09},
- {0x48, 0x00},
- {0x49, 0x00},
- {0x4a, 0x00},
- {0x4b, 0x00},
- {0x4c, 0x09},
- {0x4d, 0x90},
- {0x4e, 0x00},
- {0x4f, 0xc5},
- {0x50, 0x15},
- {0x51, 0x19},
- {0x52, 0x00},
- {0x53, 0x00},
- {0x54, 0x00},
- {0x55, 0x00},
- {0x56, 0x00},
- {0x57, 0x00},
- {0x58, 0x00},
- {0x59, 0xb0},
- {0x5a, 0x00},
- {0x5b, 0x00},
- {0x5c, 0x00},
- {0x5d, 0x00},
- {0x5e, 0x00},
- {0x5f, 0x00},
- {0x60, 0xb3},
- {0x61, 0x81},
- {0x62, 0x00},
- {0x63, 0x00},
- {0x64, 0x00},
- {0x65, 0x00},
- {0x66, 0x57},
- {0x67, 0x6c},
- {0x68, 0x00},
- {0x69, 0x00},
- {0x6a, 0x00},
- {0x6b, 0x00},
- //{0x6c, 0x80},
- {0x6c, 0x00}, //RobertYu:20050125, request by JJSue
- {0x6d, 0x03},
- {0x6e, 0x01},
- {0x6f, 0x00},
- {0x70, 0x00},
- {0x71, 0x00},
- {0x72, 0x00},
- {0x73, 0x00},
- {0x74, 0x00},
- {0x75, 0x00},
- {0x76, 0x00},
- {0x77, 0x00},
- {0x78, 0x00},
- {0x79, 0x00},
- {0x7a, 0x00},
- {0x7b, 0x00},
- {0x7c, 0x00},
- {0x7d, 0x00},
- {0x7e, 0x00},
- {0x7f, 0x00},
- {0x80, 0x8c},
- {0x81, 0x00},
- {0x82, 0x0e},
- {0x83, 0x00},
- {0x84, 0x00},
- {0x85, 0x00},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x08},
- {0x89, 0x00},
- {0x8a, 0x0e},
- {0x8b, 0xa7},
- {0x8c, 0x88},
- {0x8d, 0x47},
- {0x8e, 0xaa},
- {0x8f, 0x02},
- {0x90, 0x00},
- {0x91, 0x00},
- {0x92, 0x00},
- {0x93, 0x00},
- {0x94, 0x00},
- {0x95, 0x00},
- {0x96, 0x00},
- {0x97, 0xe3},
- {0x98, 0x00},
- {0x99, 0x00},
- {0x9a, 0x00},
- {0x9b, 0x00},
- {0x9c, 0x00},
- {0x9d, 0x00},
- {0x9e, 0x00},
- {0x9f, 0x00},
- {0xa0, 0x00},
- {0xa1, 0x00},
- {0xa2, 0x00},
- {0xa3, 0x00},
- {0xa4, 0x00},
- {0xa5, 0x00},
- {0xa6, 0x10},
- {0xa7, 0x00},
- {0xa8, 0x18},
- {0xa9, 0x00},
- {0xaa, 0x00},
- {0xab, 0x00},
- {0xac, 0x00},
- {0xad, 0x00},
- {0xae, 0x00},
- {0xaf, 0x18},
- {0xb0, 0x18},
- {0xb1, 0x30},
- {0xb2, 0x00},
- {0xb3, 0x00},
- {0xb4, 0x00},
- {0xb5, 0x00},
- {0xb6, 0x00},
- {0xb7, 0x00},
- {0xb8, 0x00},
- {0xb9, 0x00},
- {0xba, 0x00},
- {0xbb, 0x03},
- {0xbc, 0x01},
- {0xbd, 0x00},
- {0xbe, 0x00},
- {0xbf, 0x00},
- {0xc0, 0x10},
- {0xc1, 0x20},
- {0xc2, 0x00},
- {0xc3, 0x20},
- {0xc4, 0x00},
- {0xc5, 0x2c},
- {0xc6, 0x1c},
- {0xc7, 0x10},
- {0xc8, 0x10},
- {0xc9, 0x01},
- {0xca, 0x68},
- {0xcb, 0xa7},
- {0xcc, 0x3c},
- {0xcd, 0x09},
- {0xce, 0x00},
- {0xcf, 0x20},
- {0xd0, 0x40},
- {0xd1, 0x10},
- {0xd2, 0x00},
- {0xd3, 0x00},
- {0xd4, 0x20},
- {0xd5, 0x28},
- {0xd6, 0xa0},
- {0xd7, 0x2a},
- {0xd8, 0x00},
- {0xd9, 0x00},
- {0xda, 0x00},
- {0xdb, 0x00},
- {0xdc, 0x00},
- {0xdd, 0x00},
- {0xde, 0x00},
- {0xdf, 0x00},
- {0xe0, 0x00},
- {0xe1, 0xd3},
- {0xe2, 0xc0},
- {0xe3, 0x00},
- {0xe4, 0x00},
- {0xe5, 0x10},
- {0xe6, 0x00},
- {0xe7, 0x12},
- {0xe8, 0x12},
- {0xe9, 0x34},
- {0xea, 0x00},
- {0xeb, 0xff},
- {0xec, 0x79},
- {0xed, 0x20},
- {0xee, 0x30},
- {0xef, 0x01},
- {0xf0, 0x00},
- {0xf1, 0x3e},
- {0xf2, 0x00},
- {0xf3, 0x00},
- {0xf4, 0x00},
- {0xf5, 0x00},
- {0xf6, 0x00},
- {0xf7, 0x00},
- {0xf8, 0x00},
- {0xf9, 0x00},
- {0xfa, 0x00},
- {0xfb, 0x00},
- {0xfc, 0x00},
- {0xfd, 0x00},
- {0xfe, 0x00},
- {0xff, 0x00},
+ {0x00, 0x31},
+ {0x01, 0x00},
+ {0x02, 0x00},
+ {0x03, 0x00},
+ {0x04, 0x00},
+ {0x05, 0x81},
+ {0x06, 0x00},
+ {0x07, 0x00},
+ {0x08, 0x38},
+ {0x09, 0x45},
+ {0x0a, 0x28},
+ {0x0b, 0x76},
+ {0x0c, 0x00},
+ {0x0d, 0x00},
+ {0x0e, 0x80},
+ {0x0f, 0x00},
+ {0x10, 0x00},
+ {0x11, 0x00},
+ {0x12, 0x00},
+ {0x13, 0x00},
+ {0x14, 0x00},
+ {0x15, 0x00},
+ {0x16, 0x00},
+ {0x17, 0x00},
+ {0x18, 0x00},
+ {0x19, 0x00},
+ {0x1a, 0x00},
+ {0x1b, 0x8f},
+ {0x1c, 0x0f},
+ {0x1d, 0x00},
+ {0x1e, 0x00},
+ {0x1f, 0x00},
+ {0x20, 0x00},
+ {0x21, 0x00},
+ {0x22, 0x00},
+ {0x23, 0x00},
+ {0x24, 0x00},
+ {0x25, 0x4a},
+ {0x26, 0x00},
+ {0x27, 0x00},
+ {0x28, 0x00},
+ {0x29, 0x00},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x2c, 0x00},
+ {0x2d, 0x18},
+ {0x2e, 0x00},
+ {0x2f, 0x0a},
+ {0x30, 0x26},
+ {0x31, 0x5b},
+ {0x32, 0x00},
+ {0x33, 0x00},
+ {0x34, 0x00},
+ {0x35, 0x00},
+ {0x36, 0xaa},
+ {0x37, 0xaa},
+ {0x38, 0xff},
+ {0x39, 0xff},
+ {0x3a, 0x00},
+ {0x3b, 0x00},
+ {0x3c, 0x00},
+ {0x3d, 0x03},
+ {0x3e, 0x1d},
+ {0x3f, 0x04},
+ {0x40, 0x00},
+ {0x41, 0x08},
+ {0x42, 0x00},
+ {0x43, 0x08},
+ {0x44, 0x08},
+ {0x45, 0x14},
+ {0x46, 0x05},
+ {0x47, 0x09},
+ {0x48, 0x00},
+ {0x49, 0x00},
+ {0x4a, 0x00},
+ {0x4b, 0x00},
+ {0x4c, 0x09},
+ {0x4d, 0x90},
+ {0x4e, 0x00},
+ {0x4f, 0xc5},
+ {0x50, 0x15},
+ {0x51, 0x19},
+ {0x52, 0x00},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x56, 0x00},
+ {0x57, 0x00},
+ {0x58, 0x00},
+ {0x59, 0xb0},
+ {0x5a, 0x00},
+ {0x5b, 0x00},
+ {0x5c, 0x00},
+ {0x5d, 0x00},
+ {0x5e, 0x00},
+ {0x5f, 0x00},
+ {0x60, 0xb3},
+ {0x61, 0x81},
+ {0x62, 0x00},
+ {0x63, 0x00},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x57},
+ {0x67, 0x6c},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ //{0x6c, 0x80},
+ {0x6c, 0x00}, //RobertYu:20050125, request by JJSue
+ {0x6d, 0x03},
+ {0x6e, 0x01},
+ {0x6f, 0x00},
+ {0x70, 0x00},
+ {0x71, 0x00},
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x00},
+ {0x75, 0x00},
+ {0x76, 0x00},
+ {0x77, 0x00},
+ {0x78, 0x00},
+ {0x79, 0x00},
+ {0x7a, 0x00},
+ {0x7b, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x00},
+ {0x7e, 0x00},
+ {0x7f, 0x00},
+ {0x80, 0x8c},
+ {0x81, 0x00},
+ {0x82, 0x0e},
+ {0x83, 0x00},
+ {0x84, 0x00},
+ {0x85, 0x00},
+ {0x86, 0x00},
+ {0x87, 0x00},
+ {0x88, 0x08},
+ {0x89, 0x00},
+ {0x8a, 0x0e},
+ {0x8b, 0xa7},
+ {0x8c, 0x88},
+ {0x8d, 0x47},
+ {0x8e, 0xaa},
+ {0x8f, 0x02},
+ {0x90, 0x00},
+ {0x91, 0x00},
+ {0x92, 0x00},
+ {0x93, 0x00},
+ {0x94, 0x00},
+ {0x95, 0x00},
+ {0x96, 0x00},
+ {0x97, 0xe3},
+ {0x98, 0x00},
+ {0x99, 0x00},
+ {0x9a, 0x00},
+ {0x9b, 0x00},
+ {0x9c, 0x00},
+ {0x9d, 0x00},
+ {0x9e, 0x00},
+ {0x9f, 0x00},
+ {0xa0, 0x00},
+ {0xa1, 0x00},
+ {0xa2, 0x00},
+ {0xa3, 0x00},
+ {0xa4, 0x00},
+ {0xa5, 0x00},
+ {0xa6, 0x10},
+ {0xa7, 0x00},
+ {0xa8, 0x18},
+ {0xa9, 0x00},
+ {0xaa, 0x00},
+ {0xab, 0x00},
+ {0xac, 0x00},
+ {0xad, 0x00},
+ {0xae, 0x00},
+ {0xaf, 0x18},
+ {0xb0, 0x18},
+ {0xb1, 0x30},
+ {0xb2, 0x00},
+ {0xb3, 0x00},
+ {0xb4, 0x00},
+ {0xb5, 0x00},
+ {0xb6, 0x00},
+ {0xb7, 0x00},
+ {0xb8, 0x00},
+ {0xb9, 0x00},
+ {0xba, 0x00},
+ {0xbb, 0x03},
+ {0xbc, 0x01},
+ {0xbd, 0x00},
+ {0xbe, 0x00},
+ {0xbf, 0x00},
+ {0xc0, 0x10},
+ {0xc1, 0x20},
+ {0xc2, 0x00},
+ {0xc3, 0x20},
+ {0xc4, 0x00},
+ {0xc5, 0x2c},
+ {0xc6, 0x1c},
+ {0xc7, 0x10},
+ {0xc8, 0x10},
+ {0xc9, 0x01},
+ {0xca, 0x68},
+ {0xcb, 0xa7},
+ {0xcc, 0x3c},
+ {0xcd, 0x09},
+ {0xce, 0x00},
+ {0xcf, 0x20},
+ {0xd0, 0x40},
+ {0xd1, 0x10},
+ {0xd2, 0x00},
+ {0xd3, 0x00},
+ {0xd4, 0x20},
+ {0xd5, 0x28},
+ {0xd6, 0xa0},
+ {0xd7, 0x2a},
+ {0xd8, 0x00},
+ {0xd9, 0x00},
+ {0xda, 0x00},
+ {0xdb, 0x00},
+ {0xdc, 0x00},
+ {0xdd, 0x00},
+ {0xde, 0x00},
+ {0xdf, 0x00},
+ {0xe0, 0x00},
+ {0xe1, 0xd3},
+ {0xe2, 0xc0},
+ {0xe3, 0x00},
+ {0xe4, 0x00},
+ {0xe5, 0x10},
+ {0xe6, 0x00},
+ {0xe7, 0x12},
+ {0xe8, 0x12},
+ {0xe9, 0x34},
+ {0xea, 0x00},
+ {0xeb, 0xff},
+ {0xec, 0x79},
+ {0xed, 0x20},
+ {0xee, 0x30},
+ {0xef, 0x01},
+ {0xf0, 0x00},
+ {0xf1, 0x3e},
+ {0xf2, 0x00},
+ {0xf3, 0x00},
+ {0xf4, 0x00},
+ {0xf5, 0x00},
+ {0xf6, 0x00},
+ {0xf7, 0x00},
+ {0xf8, 0x00},
+ {0xf9, 0x00},
+ {0xfa, 0x00},
+ {0xfb, 0x00},
+ {0xfc, 0x00},
+ {0xfd, 0x00},
+ {0xfe, 0x00},
+ {0xff, 0x00},
};
#define CB_VT3253B0_AGC 193
// For AIROHA
unsigned char byVT3253B0_AGC[CB_VT3253B0_AGC][2] = {
- {0xF0, 0x00},
- {0xF1, 0x00},
- {0xF0, 0x80},
- {0xF0, 0x01},
- {0xF1, 0x00},
- {0xF0, 0x81},
- {0xF0, 0x02},
- {0xF1, 0x02},
- {0xF0, 0x82},
- {0xF0, 0x03},
- {0xF1, 0x04},
- {0xF0, 0x83},
- {0xF0, 0x03},
- {0xF1, 0x04},
- {0xF0, 0x84},
- {0xF0, 0x04},
- {0xF1, 0x06},
- {0xF0, 0x85},
- {0xF0, 0x05},
- {0xF1, 0x06},
- {0xF0, 0x86},
- {0xF0, 0x06},
- {0xF1, 0x06},
- {0xF0, 0x87},
- {0xF0, 0x07},
- {0xF1, 0x08},
- {0xF0, 0x88},
- {0xF0, 0x08},
- {0xF1, 0x08},
- {0xF0, 0x89},
- {0xF0, 0x09},
- {0xF1, 0x0A},
- {0xF0, 0x8A},
- {0xF0, 0x0A},
- {0xF1, 0x0A},
- {0xF0, 0x8B},
- {0xF0, 0x0B},
- {0xF1, 0x0C},
- {0xF0, 0x8C},
- {0xF0, 0x0C},
- {0xF1, 0x0C},
- {0xF0, 0x8D},
- {0xF0, 0x0D},
- {0xF1, 0x0E},
- {0xF0, 0x8E},
- {0xF0, 0x0E},
- {0xF1, 0x0E},
- {0xF0, 0x8F},
- {0xF0, 0x0F},
- {0xF1, 0x10},
- {0xF0, 0x90},
- {0xF0, 0x10},
- {0xF1, 0x10},
- {0xF0, 0x91},
- {0xF0, 0x11},
- {0xF1, 0x12},
- {0xF0, 0x92},
- {0xF0, 0x12},
- {0xF1, 0x12},
- {0xF0, 0x93},
- {0xF0, 0x13},
- {0xF1, 0x14},
- {0xF0, 0x94},
- {0xF0, 0x14},
- {0xF1, 0x14},
- {0xF0, 0x95},
- {0xF0, 0x15},
- {0xF1, 0x16},
- {0xF0, 0x96},
- {0xF0, 0x16},
- {0xF1, 0x16},
- {0xF0, 0x97},
- {0xF0, 0x17},
- {0xF1, 0x18},
- {0xF0, 0x98},
- {0xF0, 0x18},
- {0xF1, 0x18},
- {0xF0, 0x99},
- {0xF0, 0x19},
- {0xF1, 0x1A},
- {0xF0, 0x9A},
- {0xF0, 0x1A},
- {0xF1, 0x1A},
- {0xF0, 0x9B},
- {0xF0, 0x1B},
- {0xF1, 0x1C},
- {0xF0, 0x9C},
- {0xF0, 0x1C},
- {0xF1, 0x1C},
- {0xF0, 0x9D},
- {0xF0, 0x1D},
- {0xF1, 0x1E},
- {0xF0, 0x9E},
- {0xF0, 0x1E},
- {0xF1, 0x1E},
- {0xF0, 0x9F},
- {0xF0, 0x1F},
- {0xF1, 0x20},
- {0xF0, 0xA0},
- {0xF0, 0x20},
- {0xF1, 0x20},
- {0xF0, 0xA1},
- {0xF0, 0x21},
- {0xF1, 0x22},
- {0xF0, 0xA2},
- {0xF0, 0x22},
- {0xF1, 0x22},
- {0xF0, 0xA3},
- {0xF0, 0x23},
- {0xF1, 0x24},
- {0xF0, 0xA4},
- {0xF0, 0x24},
- {0xF1, 0x24},
- {0xF0, 0xA5},
- {0xF0, 0x25},
- {0xF1, 0x26},
- {0xF0, 0xA6},
- {0xF0, 0x26},
- {0xF1, 0x26},
- {0xF0, 0xA7},
- {0xF0, 0x27},
- {0xF1, 0x28},
- {0xF0, 0xA8},
- {0xF0, 0x28},
- {0xF1, 0x28},
- {0xF0, 0xA9},
- {0xF0, 0x29},
- {0xF1, 0x2A},
- {0xF0, 0xAA},
- {0xF0, 0x2A},
- {0xF1, 0x2A},
- {0xF0, 0xAB},
- {0xF0, 0x2B},
- {0xF1, 0x2C},
- {0xF0, 0xAC},
- {0xF0, 0x2C},
- {0xF1, 0x2C},
- {0xF0, 0xAD},
- {0xF0, 0x2D},
- {0xF1, 0x2E},
- {0xF0, 0xAE},
- {0xF0, 0x2E},
- {0xF1, 0x2E},
- {0xF0, 0xAF},
- {0xF0, 0x2F},
- {0xF1, 0x30},
- {0xF0, 0xB0},
- {0xF0, 0x30},
- {0xF1, 0x30},
- {0xF0, 0xB1},
- {0xF0, 0x31},
- {0xF1, 0x32},
- {0xF0, 0xB2},
- {0xF0, 0x32},
- {0xF1, 0x32},
- {0xF0, 0xB3},
- {0xF0, 0x33},
- {0xF1, 0x34},
- {0xF0, 0xB4},
- {0xF0, 0x34},
- {0xF1, 0x34},
- {0xF0, 0xB5},
- {0xF0, 0x35},
- {0xF1, 0x36},
- {0xF0, 0xB6},
- {0xF0, 0x36},
- {0xF1, 0x36},
- {0xF0, 0xB7},
- {0xF0, 0x37},
- {0xF1, 0x38},
- {0xF0, 0xB8},
- {0xF0, 0x38},
- {0xF1, 0x38},
- {0xF0, 0xB9},
- {0xF0, 0x39},
- {0xF1, 0x3A},
- {0xF0, 0xBA},
- {0xF0, 0x3A},
- {0xF1, 0x3A},
- {0xF0, 0xBB},
- {0xF0, 0x3B},
- {0xF1, 0x3C},
- {0xF0, 0xBC},
- {0xF0, 0x3C},
- {0xF1, 0x3C},
- {0xF0, 0xBD},
- {0xF0, 0x3D},
- {0xF1, 0x3E},
- {0xF0, 0xBE},
- {0xF0, 0x3E},
- {0xF1, 0x3E},
- {0xF0, 0xBF},
- {0xF0, 0x00},
+ {0xF0, 0x00},
+ {0xF1, 0x00},
+ {0xF0, 0x80},
+ {0xF0, 0x01},
+ {0xF1, 0x00},
+ {0xF0, 0x81},
+ {0xF0, 0x02},
+ {0xF1, 0x02},
+ {0xF0, 0x82},
+ {0xF0, 0x03},
+ {0xF1, 0x04},
+ {0xF0, 0x83},
+ {0xF0, 0x03},
+ {0xF1, 0x04},
+ {0xF0, 0x84},
+ {0xF0, 0x04},
+ {0xF1, 0x06},
+ {0xF0, 0x85},
+ {0xF0, 0x05},
+ {0xF1, 0x06},
+ {0xF0, 0x86},
+ {0xF0, 0x06},
+ {0xF1, 0x06},
+ {0xF0, 0x87},
+ {0xF0, 0x07},
+ {0xF1, 0x08},
+ {0xF0, 0x88},
+ {0xF0, 0x08},
+ {0xF1, 0x08},
+ {0xF0, 0x89},
+ {0xF0, 0x09},
+ {0xF1, 0x0A},
+ {0xF0, 0x8A},
+ {0xF0, 0x0A},
+ {0xF1, 0x0A},
+ {0xF0, 0x8B},
+ {0xF0, 0x0B},
+ {0xF1, 0x0C},
+ {0xF0, 0x8C},
+ {0xF0, 0x0C},
+ {0xF1, 0x0C},
+ {0xF0, 0x8D},
+ {0xF0, 0x0D},
+ {0xF1, 0x0E},
+ {0xF0, 0x8E},
+ {0xF0, 0x0E},
+ {0xF1, 0x0E},
+ {0xF0, 0x8F},
+ {0xF0, 0x0F},
+ {0xF1, 0x10},
+ {0xF0, 0x90},
+ {0xF0, 0x10},
+ {0xF1, 0x10},
+ {0xF0, 0x91},
+ {0xF0, 0x11},
+ {0xF1, 0x12},
+ {0xF0, 0x92},
+ {0xF0, 0x12},
+ {0xF1, 0x12},
+ {0xF0, 0x93},
+ {0xF0, 0x13},
+ {0xF1, 0x14},
+ {0xF0, 0x94},
+ {0xF0, 0x14},
+ {0xF1, 0x14},
+ {0xF0, 0x95},
+ {0xF0, 0x15},
+ {0xF1, 0x16},
+ {0xF0, 0x96},
+ {0xF0, 0x16},
+ {0xF1, 0x16},
+ {0xF0, 0x97},
+ {0xF0, 0x17},
+ {0xF1, 0x18},
+ {0xF0, 0x98},
+ {0xF0, 0x18},
+ {0xF1, 0x18},
+ {0xF0, 0x99},
+ {0xF0, 0x19},
+ {0xF1, 0x1A},
+ {0xF0, 0x9A},
+ {0xF0, 0x1A},
+ {0xF1, 0x1A},
+ {0xF0, 0x9B},
+ {0xF0, 0x1B},
+ {0xF1, 0x1C},
+ {0xF0, 0x9C},
+ {0xF0, 0x1C},
+ {0xF1, 0x1C},
+ {0xF0, 0x9D},
+ {0xF0, 0x1D},
+ {0xF1, 0x1E},
+ {0xF0, 0x9E},
+ {0xF0, 0x1E},
+ {0xF1, 0x1E},
+ {0xF0, 0x9F},
+ {0xF0, 0x1F},
+ {0xF1, 0x20},
+ {0xF0, 0xA0},
+ {0xF0, 0x20},
+ {0xF1, 0x20},
+ {0xF0, 0xA1},
+ {0xF0, 0x21},
+ {0xF1, 0x22},
+ {0xF0, 0xA2},
+ {0xF0, 0x22},
+ {0xF1, 0x22},
+ {0xF0, 0xA3},
+ {0xF0, 0x23},
+ {0xF1, 0x24},
+ {0xF0, 0xA4},
+ {0xF0, 0x24},
+ {0xF1, 0x24},
+ {0xF0, 0xA5},
+ {0xF0, 0x25},
+ {0xF1, 0x26},
+ {0xF0, 0xA6},
+ {0xF0, 0x26},
+ {0xF1, 0x26},
+ {0xF0, 0xA7},
+ {0xF0, 0x27},
+ {0xF1, 0x28},
+ {0xF0, 0xA8},
+ {0xF0, 0x28},
+ {0xF1, 0x28},
+ {0xF0, 0xA9},
+ {0xF0, 0x29},
+ {0xF1, 0x2A},
+ {0xF0, 0xAA},
+ {0xF0, 0x2A},
+ {0xF1, 0x2A},
+ {0xF0, 0xAB},
+ {0xF0, 0x2B},
+ {0xF1, 0x2C},
+ {0xF0, 0xAC},
+ {0xF0, 0x2C},
+ {0xF1, 0x2C},
+ {0xF0, 0xAD},
+ {0xF0, 0x2D},
+ {0xF1, 0x2E},
+ {0xF0, 0xAE},
+ {0xF0, 0x2E},
+ {0xF1, 0x2E},
+ {0xF0, 0xAF},
+ {0xF0, 0x2F},
+ {0xF1, 0x30},
+ {0xF0, 0xB0},
+ {0xF0, 0x30},
+ {0xF1, 0x30},
+ {0xF0, 0xB1},
+ {0xF0, 0x31},
+ {0xF1, 0x32},
+ {0xF0, 0xB2},
+ {0xF0, 0x32},
+ {0xF1, 0x32},
+ {0xF0, 0xB3},
+ {0xF0, 0x33},
+ {0xF1, 0x34},
+ {0xF0, 0xB4},
+ {0xF0, 0x34},
+ {0xF1, 0x34},
+ {0xF0, 0xB5},
+ {0xF0, 0x35},
+ {0xF1, 0x36},
+ {0xF0, 0xB6},
+ {0xF0, 0x36},
+ {0xF1, 0x36},
+ {0xF0, 0xB7},
+ {0xF0, 0x37},
+ {0xF1, 0x38},
+ {0xF0, 0xB8},
+ {0xF0, 0x38},
+ {0xF1, 0x38},
+ {0xF0, 0xB9},
+ {0xF0, 0x39},
+ {0xF1, 0x3A},
+ {0xF0, 0xBA},
+ {0xF0, 0x3A},
+ {0xF1, 0x3A},
+ {0xF0, 0xBB},
+ {0xF0, 0x3B},
+ {0xF1, 0x3C},
+ {0xF0, 0xBC},
+ {0xF0, 0x3C},
+ {0xF1, 0x3C},
+ {0xF0, 0xBD},
+ {0xF0, 0x3D},
+ {0xF1, 0x3E},
+ {0xF0, 0xBE},
+ {0xF0, 0x3E},
+ {0xF1, 0x3E},
+ {0xF0, 0xBF},
+ {0xF0, 0x00},
};
const unsigned short awcFrameTime[MAX_RATE] =
{10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216};
-
/*--------------------- Static Functions --------------------------*/
static
@@ -1723,42 +1718,37 @@ s_ulGetRatio(PSDevice pDevice);
static
void
s_vChangeAntenna(
- PSDevice pDevice
- );
+ PSDevice pDevice
+);
static
void
-s_vChangeAntenna (
- PSDevice pDevice
- )
+s_vChangeAntenna(
+ PSDevice pDevice
+)
{
-
-#ifdef PLICE_DEBUG
- //printk("Enter s_vChangeAntenna:original RxMode is %d,TxMode is %d\n",pDevice->byRxAntennaMode,pDevice->byTxAntennaMode);
-#endif
- if ( pDevice->dwRxAntennaSel == 0) {
- pDevice->dwRxAntennaSel=1;
- if (pDevice->bTxRxAntInv == true)
- BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
- else
- BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
- } else {
- pDevice->dwRxAntennaSel=0;
- if (pDevice->bTxRxAntInv == true)
- BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
- else
- BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
- }
- if ( pDevice->dwTxAntennaSel == 0) {
- pDevice->dwTxAntennaSel=1;
- BBvSetTxAntennaMode(pDevice->PortOffset, ANT_B);
- } else {
- pDevice->dwTxAntennaSel=0;
- BBvSetTxAntennaMode(pDevice->PortOffset, ANT_A);
- }
+ if (pDevice->dwRxAntennaSel == 0) {
+ pDevice->dwRxAntennaSel = 1;
+ if (pDevice->bTxRxAntInv == true)
+ BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
+ else
+ BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
+ } else {
+ pDevice->dwRxAntennaSel = 0;
+ if (pDevice->bTxRxAntInv == true)
+ BBvSetRxAntennaMode(pDevice->PortOffset, ANT_B);
+ else
+ BBvSetRxAntennaMode(pDevice->PortOffset, ANT_A);
+ }
+ if (pDevice->dwTxAntennaSel == 0) {
+ pDevice->dwTxAntennaSel = 1;
+ BBvSetTxAntennaMode(pDevice->PortOffset, ANT_B);
+ } else {
+ pDevice->dwTxAntennaSel = 0;
+ BBvSetTxAntennaMode(pDevice->PortOffset, ANT_A);
+ }
}
-
/*--------------------- Export Variables --------------------------*/
/*
* Description: Calculate data frame transmitting time
@@ -1775,54 +1765,52 @@ s_vChangeAntenna (
*
*/
unsigned int
-BBuGetFrameTime (
- unsigned char byPreambleType,
- unsigned char byPktType,
- unsigned int cbFrameLength,
- unsigned short wRate
- )
+BBuGetFrameTime(
+ unsigned char byPreambleType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate
+)
{
- unsigned int uFrameTime;
- unsigned int uPreamble;
- unsigned int uTmp;
- unsigned int uRateIdx = (unsigned int) wRate;
- unsigned int uRate = 0;
-
-
- if (uRateIdx > RATE_54M) {
- ASSERT(0);
- return 0;
- }
-
- uRate = (unsigned int) awcFrameTime[uRateIdx];
-
- if (uRateIdx <= 3) { //CCK mode
-
- if (byPreambleType == 1) {//Short
- uPreamble = 96;
- } else {
- uPreamble = 192;
- }
- uFrameTime = (cbFrameLength * 80) / uRate; //?????
- uTmp = (uFrameTime * uRate) / 80;
- if (cbFrameLength != uTmp) {
- uFrameTime ++;
- }
-
- return (uPreamble + uFrameTime);
- }
- else {
- uFrameTime = (cbFrameLength * 8 + 22) / uRate; //????????
- uTmp = ((uFrameTime * uRate) - 22) / 8;
- if(cbFrameLength != uTmp) {
- uFrameTime ++;
- }
- uFrameTime = uFrameTime * 4; //???????
- if(byPktType != PK_TYPE_11A) {
- uFrameTime += 6; //??????
- }
- return (20 + uFrameTime); //??????
- }
+ unsigned int uFrameTime;
+ unsigned int uPreamble;
+ unsigned int uTmp;
+ unsigned int uRateIdx = (unsigned int) wRate;
+ unsigned int uRate = 0;
+
+ if (uRateIdx > RATE_54M) {
+ ASSERT(0);
+ return 0;
+ }
+
+ uRate = (unsigned int)awcFrameTime[uRateIdx];
+
+ if (uRateIdx <= 3) { //CCK mode
+
+ if (byPreambleType == 1) {//Short
+ uPreamble = 96;
+ } else {
+ uPreamble = 192;
+ }
+ uFrameTime = (cbFrameLength * 80) / uRate; //?????
+ uTmp = (uFrameTime * uRate) / 80;
+ if (cbFrameLength != uTmp) {
+ uFrameTime++;
+ }
+
+ return uPreamble + uFrameTime;
+ } else {
+ uFrameTime = (cbFrameLength * 8 + 22) / uRate; //????????
+ uTmp = ((uFrameTime * uRate) - 22) / 8;
+ if (cbFrameLength != uTmp) {
+ uFrameTime++;
+ }
+ uFrameTime = uFrameTime * 4; //???????
+ if (byPktType != PK_TYPE_11A) {
+ uFrameTime += 6; //??????
+ }
+ return 20 + uFrameTime; //??????
+ }
}
/*
@@ -1842,162 +1830,152 @@ BBuGetFrameTime (
*
*/
void
-BBvCalculateParameter (
- PSDevice pDevice,
- unsigned int cbFrameLength,
- unsigned short wRate,
- unsigned char byPacketType,
- unsigned short *pwPhyLen,
- unsigned char *pbyPhySrv,
- unsigned char *pbyPhySgn
- )
+BBvCalculateParameter(
+ PSDevice pDevice,
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ unsigned char byPacketType,
+ unsigned short *pwPhyLen,
+ unsigned char *pbyPhySrv,
+ unsigned char *pbyPhySgn
+)
{
- unsigned int cbBitCount;
- unsigned int cbUsCount = 0;
- unsigned int cbTmp;
- bool bExtBit;
- unsigned char byPreambleType = pDevice->byPreambleType;
- bool bCCK = pDevice->bCCK;
-
- cbBitCount = cbFrameLength * 8;
- bExtBit = false;
-
- switch (wRate) {
- case RATE_1M :
- cbUsCount = cbBitCount;
- *pbyPhySgn = 0x00;
- break;
-
- case RATE_2M :
- cbUsCount = cbBitCount / 2;
- if (byPreambleType == 1)
- *pbyPhySgn = 0x09;
- else // long preamble
- *pbyPhySgn = 0x01;
- break;
-
- case RATE_5M :
- if (bCCK == false)
- cbBitCount ++;
- cbUsCount = (cbBitCount * 10) / 55;
- cbTmp = (cbUsCount * 55) / 10;
- if (cbTmp != cbBitCount)
- cbUsCount ++;
- if (byPreambleType == 1)
- *pbyPhySgn = 0x0a;
- else // long preamble
- *pbyPhySgn = 0x02;
- break;
-
- case RATE_11M :
-
- if (bCCK == false)
- cbBitCount ++;
- cbUsCount = cbBitCount / 11;
- cbTmp = cbUsCount * 11;
- if (cbTmp != cbBitCount) {
- cbUsCount ++;
- if ((cbBitCount - cbTmp) <= 3)
- bExtBit = true;
- }
- if (byPreambleType == 1)
- *pbyPhySgn = 0x0b;
- else // long preamble
- *pbyPhySgn = 0x03;
- break;
-
- case RATE_6M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9B; //1001 1011
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8B; //1000 1011
- }
- break;
-
- case RATE_9M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9F; //1001 1111
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8F; //1000 1111
- }
- break;
-
- case RATE_12M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9A; //1001 1010
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8A; //1000 1010
- }
- break;
-
- case RATE_18M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9E; //1001 1110
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8E; //1000 1110
- }
- break;
-
- case RATE_24M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x99; //1001 1001
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x89; //1000 1001
- }
- break;
-
- case RATE_36M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9D; //1001 1101
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8D; //1000 1101
- }
- break;
-
- case RATE_48M :
- if(byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x98; //1001 1000
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x88; //1000 1000
- }
- break;
-
- case RATE_54M :
- if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9C; //1001 1100
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8C; //1000 1100
- }
- break;
-
- default :
- if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
- *pbyPhySgn = 0x9C; //1001 1100
- }
- else {//11g, 2.4GHZ
- *pbyPhySgn = 0x8C; //1000 1100
- }
- break;
- }
-
- if (byPacketType == PK_TYPE_11B) {
- *pbyPhySrv = 0x00;
- if (bExtBit)
- *pbyPhySrv = *pbyPhySrv | 0x80;
- *pwPhyLen = (unsigned short)cbUsCount;
- }
- else {
- *pbyPhySrv = 0x00;
- *pwPhyLen = (unsigned short)cbFrameLength;
- }
+ unsigned int cbBitCount;
+ unsigned int cbUsCount = 0;
+ unsigned int cbTmp;
+ bool bExtBit;
+ unsigned char byPreambleType = pDevice->byPreambleType;
+ bool bCCK = pDevice->bCCK;
+
+ cbBitCount = cbFrameLength * 8;
+ bExtBit = false;
+
+ switch (wRate) {
+ case RATE_1M:
+ cbUsCount = cbBitCount;
+ *pbyPhySgn = 0x00;
+ break;
+
+ case RATE_2M:
+ cbUsCount = cbBitCount / 2;
+ if (byPreambleType == 1)
+ *pbyPhySgn = 0x09;
+ else // long preamble
+ *pbyPhySgn = 0x01;
+ break;
+
+ case RATE_5M:
+ if (bCCK == false)
+ cbBitCount++;
+ cbUsCount = (cbBitCount * 10) / 55;
+ cbTmp = (cbUsCount * 55) / 10;
+ if (cbTmp != cbBitCount)
+ cbUsCount++;
+ if (byPreambleType == 1)
+ *pbyPhySgn = 0x0a;
+ else // long preamble
+ *pbyPhySgn = 0x02;
+ break;
+
+ case RATE_11M:
+
+ if (bCCK == false)
+ cbBitCount++;
+ cbUsCount = cbBitCount / 11;
+ cbTmp = cbUsCount * 11;
+ if (cbTmp != cbBitCount) {
+ cbUsCount++;
+ if ((cbBitCount - cbTmp) <= 3)
+ bExtBit = true;
+ }
+ if (byPreambleType == 1)
+ *pbyPhySgn = 0x0b;
+ else // long preamble
+ *pbyPhySgn = 0x03;
+ break;
+
+ case RATE_6M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9B; //1001 1011
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8B; //1000 1011
+ }
+ break;
+
+ case RATE_9M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9F; //1001 1111
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8F; //1000 1111
+ }
+ break;
+
+ case RATE_12M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9A; //1001 1010
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8A; //1000 1010
+ }
+ break;
+
+ case RATE_18M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9E; //1001 1110
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8E; //1000 1110
+ }
+ break;
+
+ case RATE_24M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x99; //1001 1001
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x89; //1000 1001
+ }
+ break;
+
+ case RATE_36M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9D; //1001 1101
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8D; //1000 1101
+ }
+ break;
+
+ case RATE_48M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x98; //1001 1000
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x88; //1000 1000
+ }
+ break;
+
+ case RATE_54M:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9C; //1001 1100
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8C; //1000 1100
+ }
+ break;
+
+ default:
+ if (byPacketType == PK_TYPE_11A) {//11a, 5GHZ
+ *pbyPhySgn = 0x9C; //1001 1100
+ } else {//11g, 2.4GHZ
+ *pbyPhySgn = 0x8C; //1000 1100
+ }
+ break;
+ }
+
+ if (byPacketType == PK_TYPE_11B) {
+ *pbyPhySrv = 0x00;
+ if (bExtBit)
+ *pbyPhySrv = *pbyPhySrv | 0x80;
+ *pwPhyLen = (unsigned short)cbUsCount;
+ } else {
+ *pbyPhySrv = 0x00;
+ *pwPhyLen = (unsigned short)cbFrameLength;
+ }
}
/*
@@ -2013,35 +1991,34 @@ BBvCalculateParameter (
* Return Value: true if succeeded; false if failed.
*
*/
-bool BBbReadEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData)
+bool BBbReadEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData)
{
- unsigned short ww;
- unsigned char byValue;
-
- // BB reg offset
- VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
-
- // turn on REGR
- MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGR);
- // W_MAX_TIMEOUT is the timeout period
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue);
- if (byValue & BBREGCTL_DONE)
- break;
- }
-
- // get BB data
- VNSvInPortB(dwIoBase + MAC_REG_BBREGDATA, pbyData);
-
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x30);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x30)\n");
- return false;
- }
- return true;
+ unsigned short ww;
+ unsigned char byValue;
+
+ // BB reg offset
+ VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
+
+ // turn on REGR
+ MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGR);
+ // W_MAX_TIMEOUT is the timeout period
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue);
+ if (byValue & BBREGCTL_DONE)
+ break;
+ }
+
+ // get BB data
+ VNSvInPortB(dwIoBase + MAC_REG_BBREGDATA, pbyData);
+
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x30);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x30)\n");
+ return false;
+ }
+ return true;
}
-
/*
* Description: Write a Byte to BASEBAND, by embedded programming
*
@@ -2056,34 +2033,33 @@ bool BBbReadEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned c
* Return Value: true if succeeded; false if failed.
*
*/
-bool BBbWriteEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData)
+bool BBbWriteEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData)
{
- unsigned short ww;
- unsigned char byValue;
-
- // BB reg offset
- VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
- // set BB data
- VNSvOutPortB(dwIoBase + MAC_REG_BBREGDATA, byData);
-
- // turn on BBREGCTL_REGW
- MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGW);
- // W_MAX_TIMEOUT is the timeout period
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue);
- if (byValue & BBREGCTL_DONE)
- break;
- }
-
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x31);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x31)\n");
- return false;
- }
- return true;
+ unsigned short ww;
+ unsigned char byValue;
+
+ // BB reg offset
+ VNSvOutPortB(dwIoBase + MAC_REG_BBREGADR, byBBAddr);
+ // set BB data
+ VNSvOutPortB(dwIoBase + MAC_REG_BBREGDATA, byData);
+
+ // turn on BBREGCTL_REGW
+ MACvRegBitsOn(dwIoBase, MAC_REG_BBREGCTL, BBREGCTL_REGW);
+ // W_MAX_TIMEOUT is the timeout period
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_BBREGCTL, &byValue);
+ if (byValue & BBREGCTL_DONE)
+ break;
+ }
+
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x31);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x31)\n");
+ return false;
+ }
+ return true;
}
-
/*
* Description: Test if all bits are set for the Baseband register
*
@@ -2098,15 +2074,14 @@ bool BBbWriteEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned
* Return Value: true if all TestBits are set; false otherwise.
*
*/
-bool BBbIsRegBitsOn (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
+bool BBbIsRegBitsOn(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
- return (byOrgData & byTestBits) == byTestBits;
+ BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
+ return (byOrgData & byTestBits) == byTestBits;
}
-
/*
* Description: Test if all bits are clear for the Baseband register
*
@@ -2121,12 +2096,12 @@ bool BBbIsRegBitsOn (unsigned long dwIoBase, unsigned char byBBAddr, unsigned ch
* Return Value: true if all TestBits are clear; false otherwise.
*
*/
-bool BBbIsRegBitsOff (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
+bool BBbIsRegBitsOff(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byTestBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
- return (byOrgData & byTestBits) == 0;
+ BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData);
+ return (byOrgData & byTestBits) == 0;
}
/*
@@ -2144,168 +2119,166 @@ bool BBbIsRegBitsOff (unsigned long dwIoBase, unsigned char byBBAddr, unsigned c
*
*/
-bool BBbVT3253Init (PSDevice pDevice)
+bool BBbVT3253Init(PSDevice pDevice)
{
- bool bResult = true;
- int ii;
- unsigned long dwIoBase = pDevice->PortOffset;
- unsigned char byRFType = pDevice->byRFType;
- unsigned char byLocalID = pDevice->byLocalID;
-
- if (byRFType == RF_RFMD2959) {
- if (byLocalID <= REV_ID_VT3253_A1) {
- for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]);
- }
- } else {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]);
- }
- for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]);
- }
- VNSvOutPortD(dwIoBase + MAC_REG_ITRTMSET, 0x23);
- MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
- }
- pDevice->abyBBVGA[0] = 0x18;
- pDevice->abyBBVGA[1] = 0x0A;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -70;
- pDevice->ldBmThreshold[1] = -50;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- } else if ((byRFType == RF_AIROHA) || (byRFType == RF_AL2230S) ) {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
- }
- for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
- }
- pDevice->abyBBVGA[0] = 0x1C;
- pDevice->abyBBVGA[1] = 0x10;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -70;
- pDevice->ldBmThreshold[1] = -48;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- } else if (byRFType == RF_UW2451) {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
- }
- for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
- }
- VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23);
- MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
-
- pDevice->abyBBVGA[0] = 0x14;
- pDevice->abyBBVGA[1] = 0x0A;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -60;
- pDevice->ldBmThreshold[1] = -50;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- } else if (byRFType == RF_UW2452) {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]);
- }
- // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
- //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
- // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
- //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
- // Select VC1/VC2, CR215 = 0x02->0x06
- bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06);
-
- //{{RobertYu:20050125, request by Jack
- bResult &= BBbWriteEmbedded(dwIoBase,0x90,0x20);
- bResult &= BBbWriteEmbedded(dwIoBase,0x97,0xeb);
- //}}
-
- //{{RobertYu:20050221, request by Jack
- bResult &= BBbWriteEmbedded(dwIoBase,0xa6,0x00);
- bResult &= BBbWriteEmbedded(dwIoBase,0xa8,0x30);
- //}}
- bResult &= BBbWriteEmbedded(dwIoBase,0xb0,0x58);
-
- for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
- }
- //VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); // RobertYu: 20050104, 20050131 disable PA_Delay
- //MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); // RobertYu: 20050104, 20050131 disable PA_Delay
-
- pDevice->abyBBVGA[0] = 0x14;
- pDevice->abyBBVGA[1] = 0x0A;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -60;
- pDevice->ldBmThreshold[1] = -50;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- //}} RobertYu
-
- } else if (byRFType == RF_VT3226) {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
- }
- for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
- }
- pDevice->abyBBVGA[0] = 0x1C;
- pDevice->abyBBVGA[1] = 0x10;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -70;
- pDevice->ldBmThreshold[1] = -48;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- // Fix VT3226 DFC system timing issue
- MACvSetRFLE_LatchBase(dwIoBase);
- //{{ RobertYu: 20050104
- } else if (byRFType == RF_AIROHA7230) {
- for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]);
- }
-
- //{{ RobertYu:20050223, request by JerryChung
- // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
- //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
- // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
- //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
- // Select VC1/VC2, CR215 = 0x02->0x06
- bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06);
- //}}
-
- for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
- bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]);
- }
- pDevice->abyBBVGA[0] = 0x1C;
- pDevice->abyBBVGA[1] = 0x10;
- pDevice->abyBBVGA[2] = 0x0;
- pDevice->abyBBVGA[3] = 0x0;
- pDevice->ldBmThreshold[0] = -70;
- pDevice->ldBmThreshold[1] = -48;
- pDevice->ldBmThreshold[2] = 0;
- pDevice->ldBmThreshold[3] = 0;
- //}} RobertYu
- } else {
- // No VGA Table now
- pDevice->bUpdateBBVGA = false;
- pDevice->abyBBVGA[0] = 0x1C;
- }
-
- if (byLocalID > REV_ID_VT3253_A1) {
- BBbWriteEmbedded(dwIoBase, 0x04, 0x7F);
- BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);
- }
-
- return bResult;
+ bool bResult = true;
+ int ii;
+ unsigned long dwIoBase = pDevice->PortOffset;
+ unsigned char byRFType = pDevice->byRFType;
+ unsigned char byLocalID = pDevice->byLocalID;
+
+ if (byRFType == RF_RFMD2959) {
+ if (byLocalID <= REV_ID_VT3253_A1) {
+ for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253InitTab_RFMD[ii][0], byVT3253InitTab_RFMD[ii][1]);
+ }
+ } else {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_RFMD[ii][0], byVT3253B0_RFMD[ii][1]);
+ }
+ for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC4_RFMD2959[ii][0], byVT3253B0_AGC4_RFMD2959[ii][1]);
+ }
+ VNSvOutPortD(dwIoBase + MAC_REG_ITRTMSET, 0x23);
+ MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
+ }
+ pDevice->abyBBVGA[0] = 0x18;
+ pDevice->abyBBVGA[1] = 0x0A;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -70;
+ pDevice->ldBmThreshold[1] = -50;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ } else if ((byRFType == RF_AIROHA) || (byRFType == RF_AL2230S)) {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AIROHA2230[ii][0], byVT3253B0_AIROHA2230[ii][1]);
+ }
+ for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC[ii][0], byVT3253B0_AGC[ii][1]);
+ }
+ pDevice->abyBBVGA[0] = 0x1C;
+ pDevice->abyBBVGA[1] = 0x10;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -70;
+ pDevice->ldBmThreshold[1] = -48;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ } else if (byRFType == RF_UW2451) {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_UW2451[ii][0], byVT3253B0_UW2451[ii][1]);
+ }
+ for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC[ii][0], byVT3253B0_AGC[ii][1]);
+ }
+ VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23);
+ MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0);
+
+ pDevice->abyBBVGA[0] = 0x14;
+ pDevice->abyBBVGA[1] = 0x0A;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -60;
+ pDevice->ldBmThreshold[1] = -50;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ } else if (byRFType == RF_UW2452) {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_UW2451[ii][0], byVT3253B0_UW2451[ii][1]);
+ }
+ // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
+ //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
+ // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
+ //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
+ // Select VC1/VC2, CR215 = 0x02->0x06
+ bResult &= BBbWriteEmbedded(dwIoBase, 0xd7, 0x06);
+
+ //{{RobertYu:20050125, request by Jack
+ bResult &= BBbWriteEmbedded(dwIoBase, 0x90, 0x20);
+ bResult &= BBbWriteEmbedded(dwIoBase, 0x97, 0xeb);
+ //}}
+
+ //{{RobertYu:20050221, request by Jack
+ bResult &= BBbWriteEmbedded(dwIoBase, 0xa6, 0x00);
+ bResult &= BBbWriteEmbedded(dwIoBase, 0xa8, 0x30);
+ //}}
+ bResult &= BBbWriteEmbedded(dwIoBase, 0xb0, 0x58);
+
+ for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC[ii][0], byVT3253B0_AGC[ii][1]);
+ }
+ //VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); // RobertYu: 20050104, 20050131 disable PA_Delay
+ //MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); // RobertYu: 20050104, 20050131 disable PA_Delay
+
+ pDevice->abyBBVGA[0] = 0x14;
+ pDevice->abyBBVGA[1] = 0x0A;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -60;
+ pDevice->ldBmThreshold[1] = -50;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ //}} RobertYu
+
+ } else if (byRFType == RF_VT3226) {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AIROHA2230[ii][0], byVT3253B0_AIROHA2230[ii][1]);
+ }
+ for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC[ii][0], byVT3253B0_AGC[ii][1]);
+ }
+ pDevice->abyBBVGA[0] = 0x1C;
+ pDevice->abyBBVGA[1] = 0x10;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -70;
+ pDevice->ldBmThreshold[1] = -48;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ // Fix VT3226 DFC system timing issue
+ MACvSetRFLE_LatchBase(dwIoBase);
+ //{{ RobertYu: 20050104
+ } else if (byRFType == RF_AIROHA7230) {
+ for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AIROHA2230[ii][0], byVT3253B0_AIROHA2230[ii][1]);
+ }
+
+ //{{ RobertYu:20050223, request by JerryChung
+ // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted)
+ //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41);
+ // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted)
+ //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);
+ // Select VC1/VC2, CR215 = 0x02->0x06
+ bResult &= BBbWriteEmbedded(dwIoBase, 0xd7, 0x06);
+ //}}
+
+ for (ii = 0; ii < CB_VT3253B0_AGC; ii++) {
+ bResult &= BBbWriteEmbedded(dwIoBase, byVT3253B0_AGC[ii][0], byVT3253B0_AGC[ii][1]);
+ }
+ pDevice->abyBBVGA[0] = 0x1C;
+ pDevice->abyBBVGA[1] = 0x10;
+ pDevice->abyBBVGA[2] = 0x0;
+ pDevice->abyBBVGA[3] = 0x0;
+ pDevice->ldBmThreshold[0] = -70;
+ pDevice->ldBmThreshold[1] = -48;
+ pDevice->ldBmThreshold[2] = 0;
+ pDevice->ldBmThreshold[3] = 0;
+ //}} RobertYu
+ } else {
+ // No VGA Table now
+ pDevice->bUpdateBBVGA = false;
+ pDevice->abyBBVGA[0] = 0x1C;
+ }
+
+ if (byLocalID > REV_ID_VT3253_A1) {
+ BBbWriteEmbedded(dwIoBase, 0x04, 0x7F);
+ BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);
+ }
+
+ return bResult;
}
-
-
/*
* Description: Read All Baseband Registers
*
@@ -2319,14 +2292,14 @@ bool BBbVT3253Init (PSDevice pDevice)
* Return Value: none
*
*/
-void BBvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyBBRegs)
+void BBvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyBBRegs)
{
- int ii;
- unsigned char byBase = 1;
- for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) {
- BBbReadEmbedded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs);
- pbyBBRegs += byBase;
- }
+ int ii;
+ unsigned char byBase = 1;
+ for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) {
+ BBbReadEmbedded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs);
+ pbyBBRegs += byBase;
+ }
}
/*
@@ -2343,46 +2316,44 @@ void BBvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyBBRegs)
*
*/
-
-void BBvLoopbackOn (PSDevice pDevice)
+void BBvLoopbackOn(PSDevice pDevice)
{
- unsigned char byData;
- unsigned long dwIoBase = pDevice->PortOffset;
-
- //CR C9 = 0x00
- BBbReadEmbedded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201
- BBbWriteEmbedded(dwIoBase, 0xC9, 0);
- BBbReadEmbedded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77
- BBbWriteEmbedded(dwIoBase, 0x4D, 0x90);
-
- //CR 88 = 0x02(CCK), 0x03(OFDM)
- BBbReadEmbedded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136
-
- if (pDevice->uConnectionRate <= RATE_11M) { //CCK
- // Enable internal digital loopback: CR33 |= 0000 0001
- BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
- BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33
- // CR154 = 0x00
- BBbWriteEmbedded(dwIoBase, 0x9A, 0); //CR154
-
- BBbWriteEmbedded(dwIoBase, 0x88, 0x02);//CR239
- }
- else { //OFDM
- // Enable internal digital loopback:CR154 |= 0000 0001
- BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
- BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154
- // CR33 = 0x00
- BBbWriteEmbedded(dwIoBase, 0x21, 0); //CR33
-
- BBbWriteEmbedded(dwIoBase, 0x88, 0x03);//CR239
- }
-
- //CR14 = 0x00
- BBbWriteEmbedded(dwIoBase, 0x0E, 0);//CR14
-
- // Disable TX_IQUN
- BBbReadEmbedded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09);
- BBbWriteEmbedded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE));
+ unsigned char byData;
+ unsigned long dwIoBase = pDevice->PortOffset;
+
+ //CR C9 = 0x00
+ BBbReadEmbedded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201
+ BBbWriteEmbedded(dwIoBase, 0xC9, 0);
+ BBbReadEmbedded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77
+ BBbWriteEmbedded(dwIoBase, 0x4D, 0x90);
+
+ //CR 88 = 0x02(CCK), 0x03(OFDM)
+ BBbReadEmbedded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136
+
+ if (pDevice->uConnectionRate <= RATE_11M) { //CCK
+ // Enable internal digital loopback: CR33 |= 0000 0001
+ BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
+ BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33
+ // CR154 = 0x00
+ BBbWriteEmbedded(dwIoBase, 0x9A, 0); //CR154
+
+ BBbWriteEmbedded(dwIoBase, 0x88, 0x02);//CR239
+ } else { //OFDM
+ // Enable internal digital loopback:CR154 |= 0000 0001
+ BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
+ BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154
+ // CR33 = 0x00
+ BBbWriteEmbedded(dwIoBase, 0x21, 0); //CR33
+
+ BBbWriteEmbedded(dwIoBase, 0x88, 0x03);//CR239
+ }
+
+ //CR14 = 0x00
+ BBbWriteEmbedded(dwIoBase, 0x0E, 0);//CR14
+
+ // Disable TX_IQUN
+ BBbReadEmbedded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09);
+ BBbWriteEmbedded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE));
}
/*
@@ -2398,32 +2369,28 @@ void BBvLoopbackOn (PSDevice pDevice)
* Return Value: none
*
*/
-void BBvLoopbackOff (PSDevice pDevice)
+void BBvLoopbackOff(PSDevice pDevice)
{
- unsigned char byData;
- unsigned long dwIoBase = pDevice->PortOffset;
-
- BBbWriteEmbedded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201
- BBbWriteEmbedded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136
- BBbWriteEmbedded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136
- BBbWriteEmbedded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77
-
- if (pDevice->uConnectionRate <= RATE_11M) { // CCK
- // Set the CR33 Bit2 to disable internal Loopback.
- BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
- BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33
- }
- else { // OFDM
- BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
- BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154
- }
- BBbReadEmbedded(dwIoBase, 0x0E, &byData);//CR14
- BBbWriteEmbedded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14
-
+ unsigned char byData;
+ unsigned long dwIoBase = pDevice->PortOffset;
+
+ BBbWriteEmbedded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201
+ BBbWriteEmbedded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136
+ BBbWriteEmbedded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136
+ BBbWriteEmbedded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77
+
+ if (pDevice->uConnectionRate <= RATE_11M) { // CCK
+ // Set the CR33 Bit2 to disable internal Loopback.
+ BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33
+ BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33
+ } else { // OFDM
+ BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154
+ BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154
+ }
+ BBbReadEmbedded(dwIoBase, 0x0E, &byData);//CR14
+ BBbWriteEmbedded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14
}
-
-
/*
* Description: Set ShortSlotTime mode
*
@@ -2437,49 +2404,47 @@ void BBvLoopbackOff (PSDevice pDevice)
*
*/
void
-BBvSetShortSlotTime (PSDevice pDevice)
+BBvSetShortSlotTime(PSDevice pDevice)
{
- unsigned char byBBRxConf=0;
- unsigned char byBBVGA=0;
+ unsigned char byBBRxConf = 0;
+ unsigned char byBBVGA = 0;
- BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
+ BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
- if (pDevice->bShortSlotTime) {
- byBBRxConf &= 0xDF;//1101 1111
- } else {
- byBBRxConf |= 0x20;//0010 0000
- }
+ if (pDevice->bShortSlotTime) {
+ byBBRxConf &= 0xDF;//1101 1111
+ } else {
+ byBBRxConf |= 0x20;//0010 0000
+ }
- // patch for 3253B0 Baseband with Cardbus module
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byBBVGA);
- if (byBBVGA == pDevice->abyBBVGA[0]) {
- byBBRxConf |= 0x20;//0010 0000
- }
-
- BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
+ // patch for 3253B0 Baseband with Cardbus module
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byBBVGA);
+ if (byBBVGA == pDevice->abyBBVGA[0]) {
+ byBBRxConf |= 0x20;//0010 0000
+ }
+ BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
}
void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData)
{
- unsigned char byBBRxConf=0;
-
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, byData);
-
- BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
- // patch for 3253B0 Baseband with Cardbus module
- if (byData == pDevice->abyBBVGA[0]) {
- byBBRxConf |= 0x20;//0010 0000
- } else if (pDevice->bShortSlotTime) {
- byBBRxConf &= 0xDF;//1101 1111
- } else {
- byBBRxConf |= 0x20;//0010 0000
- }
- pDevice->byBBVGACurrent = byData;
- BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
+ unsigned char byBBRxConf = 0;
+
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, byData);
+
+ BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10
+ // patch for 3253B0 Baseband with Cardbus module
+ if (byData == pDevice->abyBBVGA[0]) {
+ byBBRxConf |= 0x20;//0010 0000
+ } else if (pDevice->bShortSlotTime) {
+ byBBRxConf &= 0xDF;//1101 1111
+ } else {
+ byBBRxConf |= 0x20;//0010 0000
+ }
+ pDevice->byBBVGACurrent = byData;
+ BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10
}
-
/*
* Description: Baseband SoftwareReset
*
@@ -2493,12 +2458,12 @@ void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData)
*
*/
void
-BBvSoftwareReset (unsigned long dwIoBase)
+BBvSoftwareReset(unsigned long dwIoBase)
{
- BBbWriteEmbedded(dwIoBase, 0x50, 0x40);
- BBbWriteEmbedded(dwIoBase, 0x50, 0);
- BBbWriteEmbedded(dwIoBase, 0x9C, 0x01);
- BBbWriteEmbedded(dwIoBase, 0x9C, 0);
+ BBbWriteEmbedded(dwIoBase, 0x50, 0x40);
+ BBbWriteEmbedded(dwIoBase, 0x50, 0);
+ BBbWriteEmbedded(dwIoBase, 0x9C, 0x01);
+ BBbWriteEmbedded(dwIoBase, 0x9C, 0);
}
/*
@@ -2514,13 +2479,13 @@ BBvSoftwareReset (unsigned long dwIoBase)
*
*/
void
-BBvPowerSaveModeON (unsigned long dwIoBase)
+BBvPowerSaveModeON(unsigned long dwIoBase)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
- byOrgData |= BIT0;
- BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
+ BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
+ byOrgData |= BIT0;
+ BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
}
/*
@@ -2536,13 +2501,13 @@ BBvPowerSaveModeON (unsigned long dwIoBase)
*
*/
void
-BBvPowerSaveModeOFF (unsigned long dwIoBase)
+BBvPowerSaveModeOFF(unsigned long dwIoBase)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
- byOrgData &= ~(BIT0);
- BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
+ BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData);
+ byOrgData &= ~(BIT0);
+ BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData);
}
/*
@@ -2560,33 +2525,24 @@ BBvPowerSaveModeOFF (unsigned long dwIoBase)
*/
void
-BBvSetTxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
+BBvSetTxAntennaMode(unsigned long dwIoBase, unsigned char byAntennaMode)
{
- unsigned char byBBTxConf;
-
-#ifdef PLICE_DEBUG
- //printk("Enter BBvSetTxAntennaMode\n");
-#endif
- BBbReadEmbedded(dwIoBase, 0x09, &byBBTxConf);//CR09
- if (byAntennaMode == ANT_DIVERSITY) {
- // bit 1 is diversity
- byBBTxConf |= 0x02;
- } else if (byAntennaMode == ANT_A) {
- // bit 2 is ANTSEL
- byBBTxConf &= 0xF9; // 1111 1001
- } else if (byAntennaMode == ANT_B) {
-#ifdef PLICE_DEBUG
- //printk("BBvSetTxAntennaMode:ANT_B\n");
-#endif
- byBBTxConf &= 0xFD; // 1111 1101
- byBBTxConf |= 0x04;
- }
- BBbWriteEmbedded(dwIoBase, 0x09, byBBTxConf);//CR09
+ unsigned char byBBTxConf;
+
+ BBbReadEmbedded(dwIoBase, 0x09, &byBBTxConf);//CR09
+ if (byAntennaMode == ANT_DIVERSITY) {
+ // bit 1 is diversity
+ byBBTxConf |= 0x02;
+ } else if (byAntennaMode == ANT_A) {
+ // bit 2 is ANTSEL
+ byBBTxConf &= 0xF9; // 1111 1001
+ } else if (byAntennaMode == ANT_B) {
+ byBBTxConf &= 0xFD; // 1111 1101
+ byBBTxConf |= 0x04;
+ }
+ BBbWriteEmbedded(dwIoBase, 0x09, byBBTxConf);//CR09
}
-
-
-
/*
* Description: Set Rx Antenna mode
*
@@ -2602,24 +2558,23 @@ BBvSetTxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
*/
void
-BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
+BBvSetRxAntennaMode(unsigned long dwIoBase, unsigned char byAntennaMode)
{
- unsigned char byBBRxConf;
-
- BBbReadEmbedded(dwIoBase, 0x0A, &byBBRxConf);//CR10
- if (byAntennaMode == ANT_DIVERSITY) {
- byBBRxConf |= 0x01;
-
- } else if (byAntennaMode == ANT_A) {
- byBBRxConf &= 0xFC; // 1111 1100
- } else if (byAntennaMode == ANT_B) {
- byBBRxConf &= 0xFE; // 1111 1110
- byBBRxConf |= 0x02;
- }
- BBbWriteEmbedded(dwIoBase, 0x0A, byBBRxConf);//CR10
+ unsigned char byBBRxConf;
+
+ BBbReadEmbedded(dwIoBase, 0x0A, &byBBRxConf);//CR10
+ if (byAntennaMode == ANT_DIVERSITY) {
+ byBBRxConf |= 0x01;
+
+ } else if (byAntennaMode == ANT_A) {
+ byBBRxConf &= 0xFC; // 1111 1100
+ } else if (byAntennaMode == ANT_B) {
+ byBBRxConf &= 0xFE; // 1111 1110
+ byBBRxConf |= 0x02;
+ }
+ BBbWriteEmbedded(dwIoBase, 0x0A, byBBRxConf);//CR10
}
-
/*
* Description: BBvSetDeepSleep
*
@@ -2633,142 +2588,138 @@ BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode)
*
*/
void
-BBvSetDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
+BBvSetDeepSleep(unsigned long dwIoBase, unsigned char byLocalID)
{
- BBbWriteEmbedded(dwIoBase, 0x0C, 0x17);//CR12
- BBbWriteEmbedded(dwIoBase, 0x0D, 0xB9);//CR13
+ BBbWriteEmbedded(dwIoBase, 0x0C, 0x17);//CR12
+ BBbWriteEmbedded(dwIoBase, 0x0D, 0xB9);//CR13
}
void
-BBvExitDeepSleep (unsigned long dwIoBase, unsigned char byLocalID)
+BBvExitDeepSleep(unsigned long dwIoBase, unsigned char byLocalID)
{
- BBbWriteEmbedded(dwIoBase, 0x0C, 0x00);//CR12
- BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);//CR13
+ BBbWriteEmbedded(dwIoBase, 0x0C, 0x00);//CR12
+ BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);//CR13
}
-
-
static
unsigned long
-s_ulGetRatio (PSDevice pDevice)
+s_ulGetRatio(PSDevice pDevice)
{
-unsigned long ulRatio = 0;
-unsigned long ulMaxPacket;
-unsigned long ulPacketNum;
-
- //This is a thousand-ratio
- ulMaxPacket = pDevice->uNumSQ3[RATE_54M];
- if ( pDevice->uNumSQ3[RATE_54M] != 0 ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_54M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_54M;
- }
- if ( pDevice->uNumSQ3[RATE_48M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_48M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_48M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_48M];
- }
- if ( pDevice->uNumSQ3[RATE_36M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
- pDevice->uNumSQ3[RATE_36M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_36M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_36M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_36M];
- }
- if ( pDevice->uNumSQ3[RATE_24M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
- pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_24M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_24M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_24M];
- }
- if ( pDevice->uNumSQ3[RATE_18M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
- pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] +
- pDevice->uNumSQ3[RATE_18M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_18M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_18M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_18M];
- }
- if ( pDevice->uNumSQ3[RATE_12M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
- pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] +
- pDevice->uNumSQ3[RATE_18M] + pDevice->uNumSQ3[RATE_12M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_12M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_12M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_12M];
- }
- if ( pDevice->uNumSQ3[RATE_11M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
- pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] -
- pDevice->uNumSQ3[RATE_6M] - pDevice->uNumSQ3[RATE_9M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_11M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_11M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_11M];
- }
- if ( pDevice->uNumSQ3[RATE_9M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
- pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] -
- pDevice->uNumSQ3[RATE_6M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_9M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_9M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_9M];
- }
- if ( pDevice->uNumSQ3[RATE_6M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
- pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_6M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_6M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_6M];
- }
- if ( pDevice->uNumSQ3[RATE_5M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
- pDevice->uNumSQ3[RATE_2M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_5M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_55M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_5M];
- }
- if ( pDevice->uNumSQ3[RATE_2M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M];
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_2M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_2M;
- ulMaxPacket = pDevice->uNumSQ3[RATE_2M];
- }
- if ( pDevice->uNumSQ3[RATE_1M] > ulMaxPacket ) {
- ulPacketNum = pDevice->uDiversityCnt;
- ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
- //ulRatio = (pDevice->uNumSQ3[RATE_1M] * 1000 / pDevice->uDiversityCnt);
- ulRatio += TOP_RATE_1M;
- }
-
- return ulRatio;
+ unsigned long ulRatio = 0;
+ unsigned long ulMaxPacket;
+ unsigned long ulPacketNum;
+
+ //This is a thousand-ratio
+ ulMaxPacket = pDevice->uNumSQ3[RATE_54M];
+ if (pDevice->uNumSQ3[RATE_54M] != 0) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_54M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_54M;
+ }
+ if (pDevice->uNumSQ3[RATE_48M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_48M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_48M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_48M];
+ }
+ if (pDevice->uNumSQ3[RATE_36M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
+ pDevice->uNumSQ3[RATE_36M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_36M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_36M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_36M];
+ }
+ if (pDevice->uNumSQ3[RATE_24M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
+ pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_24M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_24M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_24M];
+ }
+ if (pDevice->uNumSQ3[RATE_18M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
+ pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] +
+ pDevice->uNumSQ3[RATE_18M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_18M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_18M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_18M];
+ }
+ if (pDevice->uNumSQ3[RATE_12M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uNumSQ3[RATE_54M] + pDevice->uNumSQ3[RATE_48M] +
+ pDevice->uNumSQ3[RATE_36M] + pDevice->uNumSQ3[RATE_24M] +
+ pDevice->uNumSQ3[RATE_18M] + pDevice->uNumSQ3[RATE_12M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_12M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_12M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_12M];
+ }
+ if (pDevice->uNumSQ3[RATE_11M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
+ pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] -
+ pDevice->uNumSQ3[RATE_6M] - pDevice->uNumSQ3[RATE_9M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_11M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_11M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_11M];
+ }
+ if (pDevice->uNumSQ3[RATE_9M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
+ pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M] -
+ pDevice->uNumSQ3[RATE_6M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_9M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_9M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_9M];
+ }
+ if (pDevice->uNumSQ3[RATE_6M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
+ pDevice->uNumSQ3[RATE_2M] - pDevice->uNumSQ3[RATE_5M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_6M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_6M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_6M];
+ }
+ if (pDevice->uNumSQ3[RATE_5M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M] -
+ pDevice->uNumSQ3[RATE_2M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_5M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_55M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_5M];
+ }
+ if (pDevice->uNumSQ3[RATE_2M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt - pDevice->uNumSQ3[RATE_1M];
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_2M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_2M;
+ ulMaxPacket = pDevice->uNumSQ3[RATE_2M];
+ }
+ if (pDevice->uNumSQ3[RATE_1M] > ulMaxPacket) {
+ ulPacketNum = pDevice->uDiversityCnt;
+ ulRatio = (ulPacketNum * 1000 / pDevice->uDiversityCnt);
+ //ulRatio = (pDevice->uNumSQ3[RATE_1M] * 1000 / pDevice->uDiversityCnt);
+ ulRatio += TOP_RATE_1M;
+ }
+
+ return ulRatio;
}
-
void
-BBvClearAntDivSQ3Value (PSDevice pDevice)
+BBvClearAntDivSQ3Value(PSDevice pDevice)
{
- unsigned int ii;
+ unsigned int ii;
- pDevice->uDiversityCnt = 0;
- for (ii = 0; ii < MAX_RATE; ii++) {
- pDevice->uNumSQ3[ii] = 0;
- }
+ pDevice->uDiversityCnt = 0;
+ for (ii = 0; ii < MAX_RATE; ii++) {
+ pDevice->uNumSQ3[ii] = 0;
+ }
}
-
/*
* Description: Antenna Diversity
*
@@ -2785,79 +2736,70 @@ BBvClearAntDivSQ3Value (PSDevice pDevice)
*/
void
-BBvAntennaDiversity (PSDevice pDevice, unsigned char byRxRate, unsigned char bySQ3)
+BBvAntennaDiversity(PSDevice pDevice, unsigned char byRxRate, unsigned char bySQ3)
{
+ if ((byRxRate >= MAX_RATE) || (pDevice->wAntDiversityMaxRate >= MAX_RATE)) {
+ return;
+ }
+ pDevice->uDiversityCnt++;
+ // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->uDiversityCnt = %d\n", (int)pDevice->uDiversityCnt);
- if ((byRxRate >= MAX_RATE) || (pDevice->wAntDiversityMaxRate >= MAX_RATE)) {
- return;
- }
- pDevice->uDiversityCnt++;
- // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->uDiversityCnt = %d\n", (int)pDevice->uDiversityCnt);
-
- pDevice->uNumSQ3[byRxRate]++;
+ pDevice->uNumSQ3[byRxRate]++;
- if (pDevice->byAntennaState == 0) {
+ if (pDevice->byAntennaState == 0) {
+ if (pDevice->uDiversityCnt > pDevice->ulDiversityNValue) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ulDiversityNValue=[%d],54M-[%d]\n",
+ (int)pDevice->ulDiversityNValue, (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate]);
- if (pDevice->uDiversityCnt > pDevice->ulDiversityNValue) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ulDiversityNValue=[%d],54M-[%d]\n",
- (int)pDevice->ulDiversityNValue, (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate]);
+ if (pDevice->uNumSQ3[pDevice->wAntDiversityMaxRate] < pDevice->uDiversityCnt/2) {
+ pDevice->ulRatio_State0 = s_ulGetRatio(pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SQ3_State0, rate = [%08x]\n", (int)pDevice->ulRatio_State0);
- if (pDevice->uNumSQ3[pDevice->wAntDiversityMaxRate] < pDevice->uDiversityCnt/2) {
+ if (pDevice->byTMax == 0)
+ return;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1.[%08x], uNumSQ3[%d]=%d, %d\n",
+ (int)pDevice->ulRatio_State0, (int)pDevice->wAntDiversityMaxRate,
+ (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
- pDevice->ulRatio_State0 = s_ulGetRatio(pDevice);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SQ3_State0, rate = [%08x]\n", (int)pDevice->ulRatio_State0);
+ s_vChangeAntenna(pDevice);
+ pDevice->byAntennaState = 1;
+ del_timer(&pDevice->TimerSQ3Tmax3);
+ del_timer(&pDevice->TimerSQ3Tmax2);
+ pDevice->TimerSQ3Tmax1.expires = RUN_AT(pDevice->byTMax * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax1);
+
+ } else {
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax3);
+ }
+ BBvClearAntDivSQ3Value(pDevice);
+
+ }
+ } else { //byAntennaState == 1
+
+ if (pDevice->uDiversityCnt > pDevice->ulDiversityMValue) {
+ del_timer(&pDevice->TimerSQ3Tmax1);
+
+ pDevice->ulRatio_State1 = s_ulGetRatio(pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "RX:SQ3_State1, rate0 = %08x,rate1 = %08x\n",
+ (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1);
+
+ if (pDevice->ulRatio_State1 < pDevice->ulRatio_State0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
+ (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1,
+ (int)pDevice->wAntDiversityMaxRate,
+ (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
- if ( pDevice->byTMax == 0 )
- return;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1.[%08x], uNumSQ3[%d]=%d, %d\n",
- (int)pDevice->ulRatio_State0, (int)pDevice->wAntDiversityMaxRate,
- (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
-#ifdef PLICE_DEBUG
- //printk("BBvAntennaDiversity1:call s_vChangeAntenna\n");
-#endif
- s_vChangeAntenna(pDevice);
- pDevice->byAntennaState = 1;
- del_timer(&pDevice->TimerSQ3Tmax3);
- del_timer(&pDevice->TimerSQ3Tmax2);
- pDevice->TimerSQ3Tmax1.expires = RUN_AT(pDevice->byTMax * HZ);
- add_timer(&pDevice->TimerSQ3Tmax1);
-
- } else {
-
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
- add_timer(&pDevice->TimerSQ3Tmax3);
- }
- BBvClearAntDivSQ3Value(pDevice);
-
- }
- } else { //byAntennaState == 1
-
- if (pDevice->uDiversityCnt > pDevice->ulDiversityMValue) {
-
- del_timer(&pDevice->TimerSQ3Tmax1);
-
- pDevice->ulRatio_State1 = s_ulGetRatio(pDevice);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RX:SQ3_State1, rate0 = %08x,rate1 = %08x\n",
- (int)pDevice->ulRatio_State0,(int)pDevice->ulRatio_State1);
-
- if (pDevice->ulRatio_State1 < pDevice->ulRatio_State0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
- (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1,
- (int)pDevice->wAntDiversityMaxRate,
- (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
-#ifdef PLICE_DEBUG
- //printk("BBvAntennaDiversity2:call s_vChangeAntenna\n");
-#endif
s_vChangeAntenna(pDevice);
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
- add_timer(&pDevice->TimerSQ3Tmax3);
- add_timer(&pDevice->TimerSQ3Tmax2);
- }
- pDevice->byAntennaState = 0;
- BBvClearAntDivSQ3Value(pDevice);
- }
- } //byAntennaState
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
+ pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax3);
+ add_timer(&pDevice->TimerSQ3Tmax2);
+ }
+ pDevice->byAntennaState = 0;
+ BBvClearAntDivSQ3Value(pDevice);
+ }
+ } //byAntennaState
}
/*+
@@ -2872,38 +2814,33 @@ BBvAntennaDiversity (PSDevice pDevice, unsigned char byRxRate, unsigned char byS
*
* Return Value: none
*
--*/
+ -*/
void
-TimerSQ3CallBack (
- void *hDeviceContext
- )
+TimerSQ3CallBack(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TimerSQ3CallBack...");
- spin_lock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "TimerSQ3CallBack...");
+ spin_lock_irq(&pDevice->lock);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.[%08x][%08x], %d\n",(int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1, (int)pDevice->uDiversityCnt);
-#ifdef PLICE_DEBUG
- //printk("TimerSQ3CallBack1:call s_vChangeAntenna\n");
-#endif
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "3.[%08x][%08x], %d\n", (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1, (int)pDevice->uDiversityCnt);
- s_vChangeAntenna(pDevice);
- pDevice->byAntennaState = 0;
- BBvClearAntDivSQ3Value(pDevice);
+ s_vChangeAntenna(pDevice);
+ pDevice->byAntennaState = 0;
+ BBvClearAntDivSQ3Value(pDevice);
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
- add_timer(&pDevice->TimerSQ3Tmax3);
- add_timer(&pDevice->TimerSQ3Tmax2);
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
+ pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax3);
+ add_timer(&pDevice->TimerSQ3Tmax2);
-
- spin_unlock_irq(&pDevice->lock);
- return;
+ spin_unlock_irq(&pDevice->lock);
+ return;
}
-
/*+
*
* Description:
@@ -2920,54 +2857,46 @@ TimerSQ3CallBack (
*
* Return Value: none
*
--*/
+ -*/
void
-TimerState1CallBack (
- void *hDeviceContext
- )
+TimerState1CallBack(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TimerState1CallBack...");
-
- spin_lock_irq(&pDevice->lock);
- if (pDevice->uDiversityCnt < pDevice->ulDiversityMValue/100) {
-#ifdef PLICE_DEBUG
- //printk("TimerSQ3CallBack2:call s_vChangeAntenna\n");
-#endif
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "TimerState1CallBack...");
+ spin_lock_irq(&pDevice->lock);
+ if (pDevice->uDiversityCnt < pDevice->ulDiversityMValue/100) {
s_vChangeAntenna(pDevice);
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
- add_timer(&pDevice->TimerSQ3Tmax3);
- add_timer(&pDevice->TimerSQ3Tmax2);
- } else {
- pDevice->ulRatio_State1 = s_ulGetRatio(pDevice);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SQ3_State1, rate0 = %08x,rate1 = %08x\n",
- (int)pDevice->ulRatio_State0,(int)pDevice->ulRatio_State1);
-
- if ( pDevice->ulRatio_State1 < pDevice->ulRatio_State0 ) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
- (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1,
- (int)pDevice->wAntDiversityMaxRate,
- (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
-#ifdef PLICE_DEBUG
- //printk("TimerSQ3CallBack3:call s_vChangeAntenna\n");
-#endif
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
+ pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax3);
+ add_timer(&pDevice->TimerSQ3Tmax2);
+ } else {
+ pDevice->ulRatio_State1 = s_ulGetRatio(pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SQ3_State1, rate0 = %08x,rate1 = %08x\n",
+ (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1);
+
+ if (pDevice->ulRatio_State1 < pDevice->ulRatio_State0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
+ (int)pDevice->ulRatio_State0, (int)pDevice->ulRatio_State1,
+ (int)pDevice->wAntDiversityMaxRate,
+ (int)pDevice->uNumSQ3[(int)pDevice->wAntDiversityMaxRate], (int)pDevice->uDiversityCnt);
s_vChangeAntenna(pDevice);
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
- add_timer(&pDevice->TimerSQ3Tmax3);
- add_timer(&pDevice->TimerSQ3Tmax2);
- }
- }
- pDevice->byAntennaState = 0;
- BBvClearAntDivSQ3Value(pDevice);
- spin_unlock_irq(&pDevice->lock);
-
- return;
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(pDevice->byTMax3 * HZ);
+ pDevice->TimerSQ3Tmax2.expires = RUN_AT(pDevice->byTMax2 * HZ);
+ add_timer(&pDevice->TimerSQ3Tmax3);
+ add_timer(&pDevice->TimerSQ3Tmax2);
+ }
+ }
+ pDevice->byAntennaState = 0;
+ BBvClearAntDivSQ3Value(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+
+ return;
}
-
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index 9b5bc9c58d9f..e31bb7600673 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -41,7 +41,6 @@
//
#define BB_MAX_CONTEXT_SIZE 256
-
//
// Baseband RF pair definition in eeprom (Bits 6..0)
//
@@ -49,7 +48,6 @@
#define PREAMBLE_LONG 0
#define PREAMBLE_SHORT 1
-
#define F5G 0
#define F2_4G 1
@@ -66,21 +64,15 @@
#define TOP_RATE_2M 0x00200000
#define TOP_RATE_1M 0x00100000
-
/*--------------------- Export Types ------------------------------*/
/*--------------------- Export Macros ------------------------------*/
-#define BBvClearFOE(dwIoBase) \
-{ \
- BBbWriteEmbedded(dwIoBase, 0xB1, 0); \
-}
-
-#define BBvSetFOE(dwIoBase) \
-{ \
- BBbWriteEmbedded(dwIoBase, 0xB1, 0x0C); \
-}
+#define BBvClearFOE(dwIoBase) \
+ BBbWriteEmbedded(dwIoBase, 0xB1, 0)
+#define BBvSetFOE(dwIoBase) \
+ BBbWriteEmbedded(dwIoBase, 0xB1, 0x0C)
/*--------------------- Export Classes ----------------------------*/
@@ -90,22 +82,22 @@
unsigned int
BBuGetFrameTime(
- unsigned char byPreambleType,
- unsigned char byPktType,
- unsigned int cbFrameLength,
- unsigned short wRate
- );
+ unsigned char byPreambleType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate
+);
void
-BBvCalculateParameter (
- PSDevice pDevice,
- unsigned int cbFrameLength,
- unsigned short wRate,
- unsigned char byPacketType,
- unsigned short *pwPhyLen,
- unsigned char *pbyPhySrv,
- unsigned char *pbyPhySgn
- );
+BBvCalculateParameter(
+ PSDevice pDevice,
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ unsigned char byPacketType,
+ unsigned short *pwPhyLen,
+ unsigned char *pbyPhySrv,
+ unsigned char *pbyPhySgn
+);
bool BBbReadEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData);
bool BBbWriteEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData);
@@ -131,17 +123,17 @@ void BBvExitDeepSleep(unsigned long dwIoBase, unsigned char byLocalID);
// timer for antenna diversity
void
-TimerSQ3CallBack (
- void *hDeviceContext
- );
+TimerSQ3CallBack(
+ void *hDeviceContext
+);
void
TimerState1CallBack(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void BBvAntennaDiversity(PSDevice pDevice, unsigned char byRxRate, unsigned char bySQ3);
void
-BBvClearAntDivSQ3Value (PSDevice pDevice);
+BBvClearAntDivSQ3Value(PSDevice pDevice);
#endif // __BASEBAND_H__
diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c
index fe57fb880a8f..f983915168b7 100644
--- a/drivers/staging/vt6655/bssdb.c
+++ b/drivers/staging/vt6655/bssdb.c
@@ -60,59 +60,46 @@
/*--------------------- Static Definitions -------------------------*/
-
-
-
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-
-
const unsigned short awHWRetry0[5][5] = {
- {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
- {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
- {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
- {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
- {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
- };
+ {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
+ {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
+ {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
+ {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
+ {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
+};
const unsigned short awHWRetry1[5][5] = {
- {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
- {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
- {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
- {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M},
- {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
- };
-
-
+ {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
+ {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
+ {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
+ {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M},
+ {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
+};
/*--------------------- Static Functions --------------------------*/
void s_vCheckSensitivity(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
#ifdef Calcu_LinkQual
void s_uCalculateLinkQual(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
#endif
-
void s_vCheckPreEDThreshold(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-
-
-
/*+
*
* Routine Description:
@@ -121,153 +108,150 @@ void s_vCheckPreEDThreshold(
* Return Value:
* PTR to KnownBSS or NULL
*
--*/
+ -*/
PKnownBSS
BSSpSearchBSSList(
- void *hDeviceContext,
- unsigned char *pbyDesireBSSID,
- unsigned char *pbyDesireSSID,
- CARD_PHY_TYPE ePhyType
- )
+ void *hDeviceContext,
+ unsigned char *pbyDesireBSSID,
+ unsigned char *pbyDesireSSID,
+ CARD_PHY_TYPE ePhyType
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned char *pbyBSSID = NULL;
- PWLAN_IE_SSID pSSID = NULL;
- PKnownBSS pCurrBSS = NULL;
- PKnownBSS pSelect = NULL;
- unsigned char ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
- unsigned int ii = 0;
-
- if (pbyDesireBSSID != NULL) {
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned char *pbyBSSID = NULL;
+ PWLAN_IE_SSID pSSID = NULL;
+ PKnownBSS pCurrBSS = NULL;
+ PKnownBSS pSelect = NULL;
+ unsigned char ZeroBSSID[WLAN_BSSID_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned int ii = 0;
+
+ if (pbyDesireBSSID != NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
"BSSpSearchBSSList BSSID[%pM]\n", pbyDesireBSSID);
- if ((!is_broadcast_ether_addr(pbyDesireBSSID)) &&
- (memcmp(pbyDesireBSSID, ZeroBSSID, 6)!= 0)){
- pbyBSSID = pbyDesireBSSID;
- }
- }
- if (pbyDesireSSID != NULL) {
- if (((PWLAN_IE_SSID)pbyDesireSSID)->len != 0) {
- pSSID = (PWLAN_IE_SSID) pbyDesireSSID;
- }
- }
-
- if (pbyBSSID != NULL) {
- // match BSSID first
- for (ii = 0; ii <MAX_BSS_NUM; ii++) {
- pCurrBSS = &(pMgmt->sBSSList[ii]);
-if(pDevice->bLinkPass==false) pCurrBSS->bSelected = false;
- if ((pCurrBSS->bActive) &&
- (pCurrBSS->bSelected == false)) {
- if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) {
- if (pSSID != NULL) {
- // compare ssid
- if ( !memcmp(pSSID->abySSID,
- ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID,
- pSSID->len)) {
- if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) ||
- ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
- ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
- ) {
- pCurrBSS->bSelected = true;
- return(pCurrBSS);
- }
- }
- } else {
- if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) ||
- ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
- ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
- ) {
- pCurrBSS->bSelected = true;
- return(pCurrBSS);
- }
- }
- }
- }
- }
- } else {
- // ignore BSSID
- for (ii = 0; ii <MAX_BSS_NUM; ii++) {
- pCurrBSS = &(pMgmt->sBSSList[ii]);
- //2007-0721-01<Add>by MikeLiu
- pCurrBSS->bSelected = false;
- if (pCurrBSS->bActive) {
-
- if (pSSID != NULL) {
- // matched SSID
- if (! !memcmp(pSSID->abySSID,
- ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID,
- pSSID->len) ||
- (pSSID->len != ((PWLAN_IE_SSID)pCurrBSS->abySSID)->len)) {
- // SSID not match skip this BSS
- continue;
- }
- }
- if (((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo)) ||
- ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo))
- ){
- // Type not match skip this BSS
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSS type mismatch.... Config[%d] BSS[0x%04x]\n", pMgmt->eConfigMode, pCurrBSS->wCapInfo);
- continue;
- }
-
- if (ePhyType != PHY_TYPE_AUTO) {
- if (((ePhyType == PHY_TYPE_11A) && (PHY_TYPE_11A != pCurrBSS->eNetworkTypeInUse)) ||
- ((ePhyType != PHY_TYPE_11A) && (PHY_TYPE_11A == pCurrBSS->eNetworkTypeInUse))) {
- // PhyType not match skip this BSS
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Physical type mismatch.... ePhyType[%d] BSS[%d]\n", ePhyType, pCurrBSS->eNetworkTypeInUse);
- continue;
- }
- }
+ if ((!is_broadcast_ether_addr(pbyDesireBSSID)) &&
+ (memcmp(pbyDesireBSSID, ZeroBSSID, 6) != 0)) {
+ pbyBSSID = pbyDesireBSSID;
+ }
+ }
+ if (pbyDesireSSID != NULL) {
+ if (((PWLAN_IE_SSID)pbyDesireSSID)->len != 0) {
+ pSSID = (PWLAN_IE_SSID) pbyDesireSSID;
+ }
+ }
+
+ if (pbyBSSID != NULL) {
+ // match BSSID first
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pCurrBSS = &(pMgmt->sBSSList[ii]);
+ if (pDevice->bLinkPass == false) pCurrBSS->bSelected = false;
+ if ((pCurrBSS->bActive) &&
+ (pCurrBSS->bSelected == false)) {
+ if (!compare_ether_addr(pCurrBSS->abyBSSID, pbyBSSID)) {
+ if (pSSID != NULL) {
+ // compare ssid
+ if (!memcmp(pSSID->abySSID,
+ ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID,
+ pSSID->len)) {
+ if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) ||
+ ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
+ ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
+) {
+ pCurrBSS->bSelected = true;
+ return pCurrBSS;
+ }
+ }
+ } else {
+ if ((pMgmt->eConfigMode == WMAC_CONFIG_AUTO) ||
+ ((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo)) ||
+ ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo))
+) {
+ pCurrBSS->bSelected = true;
+ return pCurrBSS;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // ignore BSSID
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pCurrBSS = &(pMgmt->sBSSList[ii]);
+ //2007-0721-01<Add>by MikeLiu
+ pCurrBSS->bSelected = false;
+ if (pCurrBSS->bActive) {
+ if (pSSID != NULL) {
+ // matched SSID
+ if (!!memcmp(pSSID->abySSID,
+ ((PWLAN_IE_SSID)pCurrBSS->abySSID)->abySSID,
+ pSSID->len) ||
+ (pSSID->len != ((PWLAN_IE_SSID)pCurrBSS->abySSID)->len)) {
+ // SSID not match skip this BSS
+ continue;
+ }
+ }
+ if (((pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) && WLAN_GET_CAP_INFO_ESS(pCurrBSS->wCapInfo)) ||
+ ((pMgmt->eConfigMode == WMAC_CONFIG_ESS_STA) && WLAN_GET_CAP_INFO_IBSS(pCurrBSS->wCapInfo))
+) {
+ // Type not match skip this BSS
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSS type mismatch.... Config[%d] BSS[0x%04x]\n", pMgmt->eConfigMode, pCurrBSS->wCapInfo);
+ continue;
+ }
+
+ if (ePhyType != PHY_TYPE_AUTO) {
+ if (((ePhyType == PHY_TYPE_11A) && (PHY_TYPE_11A != pCurrBSS->eNetworkTypeInUse)) ||
+ ((ePhyType != PHY_TYPE_11A) && (PHY_TYPE_11A == pCurrBSS->eNetworkTypeInUse))) {
+ // PhyType not match skip this BSS
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Physical type mismatch.... ePhyType[%d] BSS[%d]\n", ePhyType, pCurrBSS->eNetworkTypeInUse);
+ continue;
+ }
+ }
/*
- if (pMgmt->eAuthenMode < WMAC_AUTH_WPA) {
- if (pCurrBSS->bWPAValid == true) {
- // WPA AP will reject connection of station without WPA enable.
- continue;
- }
- } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) {
- if (pCurrBSS->bWPAValid == false) {
- // station with WPA enable can't join NonWPA AP.
- continue;
- }
- } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
- if (pCurrBSS->bWPA2Valid == false) {
- // station with WPA2 enable can't join NonWPA2 AP.
- continue;
- }
- }
+ if (pMgmt->eAuthenMode < WMAC_AUTH_WPA) {
+ if (pCurrBSS->bWPAValid == true) {
+ // WPA AP will reject connection of station without WPA enable.
+ continue;
+ }
+ } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) {
+ if (pCurrBSS->bWPAValid == false) {
+ // station with WPA enable can't join NonWPA AP.
+ continue;
+ }
+ } else if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
+ if (pCurrBSS->bWPA2Valid == false) {
+ // station with WPA2 enable can't join NonWPA2 AP.
+ continue;
+ }
+ }
*/
- if (pSelect == NULL) {
- pSelect = pCurrBSS;
- } else {
- // compare RSSI, select signal strong one
- if (pCurrBSS->uRSSI < pSelect->uRSSI) {
- pSelect = pCurrBSS;
- }
- }
- }
- }
- if (pSelect != NULL) {
- pSelect->bSelected = true;
+ if (pSelect == NULL) {
+ pSelect = pCurrBSS;
+ } else {
+ // compare RSSI, select signal strong one
+ if (pCurrBSS->uRSSI < pSelect->uRSSI) {
+ pSelect = pCurrBSS;
+ }
+ }
+ }
+ }
+ if (pSelect != NULL) {
+ pSelect->bSelected = true;
/*
- if (pDevice->bRoaming == false) {
- // Einsn Add @20070907
- memset(pbyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- memcpy(pbyDesireSSID,pCurrBSS->abySSID,WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1) ;
- }*/
-
- return(pSelect);
- }
- }
- return(NULL);
+ if (pDevice->bRoaming == false) {
+ // Einsn Add @20070907
+ memset(pbyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ memcpy(pbyDesireSSID,pCurrBSS->abySSID,WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ }*/
+ return pSelect;
+ }
+ }
+ return NULL;
}
-
/*+
*
* Routine Description:
@@ -276,42 +260,39 @@ if(pDevice->bLinkPass==false) pCurrBSS->bSelected = false;
* Return Value:
* None.
*
--*/
-
+ -*/
void
BSSvClearBSSList(
- void *hDeviceContext,
- bool bKeepCurrBSSID
- )
+ void *hDeviceContext,
+ bool bKeepCurrBSSID
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int ii;
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (bKeepCurrBSSID) {
- if (pMgmt->sBSSList[ii].bActive &&
- !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) {
- // bKeepCurrBSSID = false;
- continue;
- }
- }
-
- if ((pMgmt->sBSSList[ii].bActive) && (pMgmt->sBSSList[ii].uClearCount < BSS_CLEAR_COUNT)) {
- pMgmt->sBSSList[ii].uClearCount ++;
- continue;
- }
-
- pMgmt->sBSSList[ii].bActive = false;
- memset(&pMgmt->sBSSList[ii], 0, sizeof(KnownBSS));
- }
- BSSvClearAnyBSSJoinRecord(pDevice);
-
- return;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int ii;
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ if (bKeepCurrBSSID) {
+ if (pMgmt->sBSSList[ii].bActive &&
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) {
+ // bKeepCurrBSSID = false;
+ continue;
+ }
+ }
+ if ((pMgmt->sBSSList[ii].bActive) && (pMgmt->sBSSList[ii].uClearCount < BSS_CLEAR_COUNT)) {
+ pMgmt->sBSSList[ii].uClearCount++;
+ continue;
+ }
+ pMgmt->sBSSList[ii].bActive = false;
+ memset(&pMgmt->sBSSList[ii], 0, sizeof(KnownBSS));
+ }
+ BSSvClearAnyBSSJoinRecord(pDevice);
+
+ return;
+}
/*+
*
@@ -321,39 +302,35 @@ BSSvClearBSSList(
* Return Value:
* true if found.
*
--*/
+ -*/
PKnownBSS
BSSpAddrIsInBSSList(
- void *hDeviceContext,
- unsigned char *abyBSSID,
- PWLAN_IE_SSID pSSID
- )
+ void *hDeviceContext,
+ unsigned char *abyBSSID,
+ PWLAN_IE_SSID pSSID
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PKnownBSS pBSSList = NULL;
- unsigned int ii;
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pBSSList = &(pMgmt->sBSSList[ii]);
- if (pBSSList->bActive) {
- if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) {
-// if (pSSID == NULL)
-// return pBSSList;
- if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len){
- if (memcmp(pSSID->abySSID,
- ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID,
- pSSID->len) == 0)
- return pBSSList;
- }
- }
- }
- }
-
- return NULL;
-};
-
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PKnownBSS pBSSList = NULL;
+ unsigned int ii;
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSSList = &(pMgmt->sBSSList[ii]);
+ if (pBSSList->bActive) {
+ if (!compare_ether_addr(pBSSList->abyBSSID, abyBSSID)) {
+ if (pSSID->len == ((PWLAN_IE_SSID)pBSSList->abySSID)->len) {
+ if (memcmp(pSSID->abySSID,
+ ((PWLAN_IE_SSID)pBSSList->abySSID)->abySSID,
+ pSSID->len) == 0)
+ return pBSSList;
+ }
+ }
+ }
+ }
+ return NULL;
+};
/*+
*
@@ -363,212 +340,206 @@ BSSpAddrIsInBSSList(
* Return Value:
* true if success.
*
--*/
+ -*/
bool
-BSSbInsertToBSSList (
- void *hDeviceContext,
- unsigned char *abyBSSIDAddr,
- QWORD qwTimestamp,
- unsigned short wBeaconInterval,
- unsigned short wCapInfo,
- unsigned char byCurrChannel,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pSuppRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates,
- PERPObject psERP,
- PWLAN_IE_RSN pRSN,
- PWLAN_IE_RSN_EXT pRSNWPA,
- PWLAN_IE_COUNTRY pIE_Country,
- PWLAN_IE_QUIET pIE_Quiet,
- unsigned int uIELength,
- unsigned char *pbyIEs,
- void *pRxPacketContext
- )
+BSSbInsertToBSSList(
+ void *hDeviceContext,
+ unsigned char *abyBSSIDAddr,
+ QWORD qwTimestamp,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pSuppRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates,
+ PERPObject psERP,
+ PWLAN_IE_RSN pRSN,
+ PWLAN_IE_RSN_EXT pRSNWPA,
+ PWLAN_IE_COUNTRY pIE_Country,
+ PWLAN_IE_QUIET pIE_Quiet,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
+ void *pRxPacketContext
+)
{
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
+ PKnownBSS pBSSList = NULL;
+ unsigned int ii;
+ bool bParsingQuiet = false;
+ PWLAN_IE_QUIET pQuiet = NULL;
+
+ pBSSList = (PKnownBSS)&(pMgmt->sBSSList[0]);
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSSList = (PKnownBSS)&(pMgmt->sBSSList[ii]);
+ if (!pBSSList->bActive)
+ break;
+ }
+
+ if (ii == MAX_BSS_NUM) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get free KnowBSS node failed.\n");
+ return false;
+ }
+ // save the BSS info
+ pBSSList->bActive = true;
+ memcpy(pBSSList->abyBSSID, abyBSSIDAddr, WLAN_BSSID_LEN);
+ HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
+ LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp));
+ pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval);
+ pBSSList->wCapInfo = cpu_to_le16(wCapInfo);
+ pBSSList->uClearCount = 0;
+
+ if (pSSID->len > WLAN_SSID_MAXLEN)
+ pSSID->len = WLAN_SSID_MAXLEN;
+ memcpy(pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
+
+ pBSSList->uChannel = byCurrChannel;
+
+ if (pSuppRates->len > WLAN_RATES_MAXLEN)
+ pSuppRates->len = WLAN_RATES_MAXLEN;
+ memcpy(pBSSList->abySuppRates, pSuppRates, pSuppRates->len + WLAN_IEHDR_LEN);
+
+ if (pExtSuppRates != NULL) {
+ if (pExtSuppRates->len > WLAN_RATES_MAXLEN)
+ pExtSuppRates->len = WLAN_RATES_MAXLEN;
+ memcpy(pBSSList->abyExtSuppRates, pExtSuppRates, pExtSuppRates->len + WLAN_IEHDR_LEN);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSbInsertToBSSList: pExtSuppRates->len = %d\n", pExtSuppRates->len);
+
+ } else {
+ memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+ }
+ pBSSList->sERP.byERP = psERP->byERP;
+ pBSSList->sERP.bERPExist = psERP->bERPExist;
+
+ // Check if BSS is 802.11a/b/g
+ if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
+ } else {
+ if (pBSSList->sERP.bERPExist == true) {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
+ } else {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
+ }
+ }
+
+ pBSSList->byRxRate = pRxPacket->byRxRate;
+ pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF;
+ pBSSList->uRSSI = pRxPacket->uRSSI;
+ pBSSList->bySQ = pRxPacket->bySQ;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ // assoc with BSS
+ if (pBSSList == pMgmt->pCurrBSS) {
+ bParsingQuiet = true;
+ }
+ }
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
- PKnownBSS pBSSList = NULL;
- unsigned int ii;
- bool bParsingQuiet = false;
- PWLAN_IE_QUIET pQuiet = NULL;
-
-
-
- pBSSList = (PKnownBSS)&(pMgmt->sBSSList[0]);
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pBSSList = (PKnownBSS)&(pMgmt->sBSSList[ii]);
- if (!pBSSList->bActive)
- break;
- }
-
- if (ii == MAX_BSS_NUM){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get free KnowBSS node failed.\n");
- return false;
- }
- // save the BSS info
- pBSSList->bActive = true;
- memcpy( pBSSList->abyBSSID, abyBSSIDAddr, WLAN_BSSID_LEN);
- HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
- LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp));
- pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval);
- pBSSList->wCapInfo = cpu_to_le16(wCapInfo);
- pBSSList->uClearCount = 0;
-
- if (pSSID->len > WLAN_SSID_MAXLEN)
- pSSID->len = WLAN_SSID_MAXLEN;
- memcpy( pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
-
- pBSSList->uChannel = byCurrChannel;
-
- if (pSuppRates->len > WLAN_RATES_MAXLEN)
- pSuppRates->len = WLAN_RATES_MAXLEN;
- memcpy( pBSSList->abySuppRates, pSuppRates, pSuppRates->len + WLAN_IEHDR_LEN);
-
- if (pExtSuppRates != NULL) {
- if (pExtSuppRates->len > WLAN_RATES_MAXLEN)
- pExtSuppRates->len = WLAN_RATES_MAXLEN;
- memcpy(pBSSList->abyExtSuppRates, pExtSuppRates, pExtSuppRates->len + WLAN_IEHDR_LEN);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSbInsertToBSSList: pExtSuppRates->len = %d\n", pExtSuppRates->len);
-
- } else {
- memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
- }
- pBSSList->sERP.byERP = psERP->byERP;
- pBSSList->sERP.bERPExist = psERP->bERPExist;
-
- // Check if BSS is 802.11a/b/g
- if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
- } else {
- if (pBSSList->sERP.bERPExist == true) {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
- } else {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
- }
- }
-
- pBSSList->byRxRate = pRxPacket->byRxRate;
- pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF;
- pBSSList->uRSSI = pRxPacket->uRSSI;
- pBSSList->bySQ = pRxPacket->bySQ;
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- // assoc with BSS
- if (pBSSList == pMgmt->pCurrBSS) {
- bParsingQuiet = true;
- }
- }
-
- WPA_ClearRSN(pBSSList);
-
- if (pRSNWPA != NULL) {
- unsigned int uLen = pRSNWPA->len + 2;
-
- if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
- pBSSList->wWPALen = uLen;
- memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
- WPA_ParseRSN(pBSSList, pRSNWPA);
- }
- }
-
- WPA2_ClearRSN(pBSSList);
-
- if (pRSN != NULL) {
- unsigned int uLen = pRSN->len + 2;
- if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
- pBSSList->wRSNLen = uLen;
- memcpy(pBSSList->byRSNIE, pRSN, uLen);
- WPA2vParseRSN(pBSSList, pRSN);
- }
- }
-
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || (pBSSList->bWPA2Valid == true)) {
-
- PSKeyItem pTransmitKey = NULL;
- bool bIs802_1x = false;
-
- for (ii = 0; ii < pBSSList->wAKMSSAuthCount; ii ++) {
- if (pBSSList->abyAKMSSAuthType[ii] == WLAN_11i_AKMSS_802_1X) {
- bIs802_1x = true;
- break;
- }
- }
- if ((bIs802_1x == true) && (pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len) &&
- ( !memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID, pSSID->len))) {
-
- bAdd_PMKID_Candidate((void *)pDevice, pBSSList->abyBSSID, &pBSSList->sRSNCapObj);
-
- if ((pDevice->bLinkPass == true) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- if ((KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, PAIRWISE_KEY, &pTransmitKey) == true) ||
- (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, GROUP_KEY, &pTransmitKey) == true)) {
- pDevice->gsPMKIDCandidate.StatusType = Ndis802_11StatusType_PMKID_CandidateList;
- pDevice->gsPMKIDCandidate.Version = 1;
-
- }
-
- }
- }
- }
-
- if (pDevice->bUpdateBBVGA) {
- // Moniter if RSSI is too strong.
- pBSSList->byRSSIStatCnt = 0;
- RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
- pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX;
- for (ii = 1; ii < RSSI_STAT_COUNT; ii++)
- pBSSList->ldBmAverage[ii] = 0;
- }
-
- if ((pIE_Country != NULL) &&
- (pMgmt->b11hEnable == true)) {
- set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
- pIE_Country);
- }
-
- if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
- if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
- (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
- // valid EID
- if (pQuiet == NULL) {
- pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
- CARDbSetQuiet( pMgmt->pAdapter,
- true,
- pQuiet->byQuietCount,
- pQuiet->byQuietPeriod,
- *((unsigned short *)pQuiet->abyQuietDuration),
- *((unsigned short *)pQuiet->abyQuietOffset)
- );
- } else {
- pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
- CARDbSetQuiet( pMgmt->pAdapter,
- false,
- pQuiet->byQuietCount,
- pQuiet->byQuietPeriod,
- *((unsigned short *)pQuiet->abyQuietDuration),
- *((unsigned short *)pQuiet->abyQuietOffset)
- );
- }
- }
- }
-
- if ((bParsingQuiet == true) &&
- (pQuiet != NULL)) {
- CARDbStartQuiet(pMgmt->pAdapter);
- }
-
- pBSSList->uIELength = uIELength;
- if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN)
- pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
- memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
-
- return true;
-}
+ WPA_ClearRSN(pBSSList);
+ if (pRSNWPA != NULL) {
+ unsigned int uLen = pRSNWPA->len + 2;
+
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
+ pBSSList->wWPALen = uLen;
+ memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
+ WPA_ParseRSN(pBSSList, pRSNWPA);
+ }
+ }
+
+ WPA2_ClearRSN(pBSSList);
+
+ if (pRSN != NULL) {
+ unsigned int uLen = pRSN->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
+ pBSSList->wRSNLen = uLen;
+ memcpy(pBSSList->byRSNIE, pRSN, uLen);
+ WPA2vParseRSN(pBSSList, pRSN);
+ }
+ }
+
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) || (pBSSList->bWPA2Valid == true)) {
+ PSKeyItem pTransmitKey = NULL;
+ bool bIs802_1x = false;
+
+ for (ii = 0; ii < pBSSList->wAKMSSAuthCount; ii++) {
+ if (pBSSList->abyAKMSSAuthType[ii] == WLAN_11i_AKMSS_802_1X) {
+ bIs802_1x = true;
+ break;
+ }
+ }
+ if ((bIs802_1x == true) && (pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len) &&
+ (!memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID, pSSID->len))) {
+ bAdd_PMKID_Candidate((void *)pDevice, pBSSList->abyBSSID, &pBSSList->sRSNCapObj);
+
+ if ((pDevice->bLinkPass == true) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ if ((KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, PAIRWISE_KEY, &pTransmitKey) == true) ||
+ (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBSSID, GROUP_KEY, &pTransmitKey) == true)) {
+ pDevice->gsPMKIDCandidate.StatusType = Ndis802_11StatusType_PMKID_CandidateList;
+ pDevice->gsPMKIDCandidate.Version = 1;
+
+ }
+
+ }
+ }
+ }
+
+ if (pDevice->bUpdateBBVGA) {
+ // Moniter if RSSI is too strong.
+ pBSSList->byRSSIStatCnt = 0;
+ RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
+ pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX;
+ for (ii = 1; ii < RSSI_STAT_COUNT; ii++)
+ pBSSList->ldBmAverage[ii] = 0;
+ }
+
+ if ((pIE_Country != NULL) &&
+ (pMgmt->b11hEnable == true)) {
+ set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
+ pIE_Country);
+ }
+
+ if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
+ if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
+ (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
+ // valid EID
+ if (pQuiet == NULL) {
+ pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
+ CARDbSetQuiet(pMgmt->pAdapter,
+ true,
+ pQuiet->byQuietCount,
+ pQuiet->byQuietPeriod,
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
+);
+ } else {
+ pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
+ CARDbSetQuiet(pMgmt->pAdapter,
+ false,
+ pQuiet->byQuietCount,
+ pQuiet->byQuietPeriod,
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
+ );
+ }
+ }
+ }
+
+ if ((bParsingQuiet == true) &&
+ (pQuiet != NULL)) {
+ CARDbStartQuiet(pMgmt->pAdapter);
+ }
+
+ pBSSList->uIELength = uIELength;
+ if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN)
+ pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
+ memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
+
+ return true;
+}
/*+
*
@@ -578,176 +549,169 @@ BSSbInsertToBSSList (
* Return Value:
* true if success.
*
--*/
+ -*/
// TODO: input structure modify
bool
-BSSbUpdateToBSSList (
- void *hDeviceContext,
- QWORD qwTimestamp,
- unsigned short wBeaconInterval,
- unsigned short wCapInfo,
- unsigned char byCurrChannel,
- bool bChannelHit,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pSuppRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates,
- PERPObject psERP,
- PWLAN_IE_RSN pRSN,
- PWLAN_IE_RSN_EXT pRSNWPA,
- PWLAN_IE_COUNTRY pIE_Country,
- PWLAN_IE_QUIET pIE_Quiet,
- PKnownBSS pBSSList,
- unsigned int uIELength,
- unsigned char *pbyIEs,
- void *pRxPacketContext
- )
+BSSbUpdateToBSSList(
+ void *hDeviceContext,
+ QWORD qwTimestamp,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ bool bChannelHit,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pSuppRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates,
+ PERPObject psERP,
+ PWLAN_IE_RSN pRSN,
+ PWLAN_IE_RSN_EXT pRSNWPA,
+ PWLAN_IE_COUNTRY pIE_Country,
+ PWLAN_IE_QUIET pIE_Quiet,
+ PKnownBSS pBSSList,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
+ void *pRxPacketContext
+)
{
- int ii;
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
- long ldBm;
- bool bParsingQuiet = false;
- PWLAN_IE_QUIET pQuiet = NULL;
-
-
-
- if (pBSSList == NULL)
- return false;
-
-
- HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
- LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp));
- pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval);
- pBSSList->wCapInfo = cpu_to_le16(wCapInfo);
- pBSSList->uClearCount = 0;
- pBSSList->uChannel = byCurrChannel;
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BSSbUpdateToBSSList: pBSSList->uChannel: %d\n", pBSSList->uChannel);
-
- if (pSSID->len > WLAN_SSID_MAXLEN)
- pSSID->len = WLAN_SSID_MAXLEN;
-
- if ((pSSID->len != 0) && (pSSID->abySSID[0] != 0))
- memcpy(pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
- memcpy(pBSSList->abySuppRates, pSuppRates,pSuppRates->len + WLAN_IEHDR_LEN);
-
- if (pExtSuppRates != NULL) {
- memcpy(pBSSList->abyExtSuppRates, pExtSuppRates,pExtSuppRates->len + WLAN_IEHDR_LEN);
- } else {
- memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
- }
- pBSSList->sERP.byERP = psERP->byERP;
- pBSSList->sERP.bERPExist = psERP->bERPExist;
-
- // Check if BSS is 802.11a/b/g
- if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
- } else {
- if (pBSSList->sERP.bERPExist == true) {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
- } else {
- pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
- }
- }
-
- pBSSList->byRxRate = pRxPacket->byRxRate;
- pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF;
- if(bChannelHit)
- pBSSList->uRSSI = pRxPacket->uRSSI;
- pBSSList->bySQ = pRxPacket->bySQ;
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- // assoc with BSS
- if (pBSSList == pMgmt->pCurrBSS) {
- bParsingQuiet = true;
- }
- }
-
- WPA_ClearRSN(pBSSList); //mike update
-
- if (pRSNWPA != NULL) {
- unsigned int uLen = pRSNWPA->len + 2;
- if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
- pBSSList->wWPALen = uLen;
- memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
- WPA_ParseRSN(pBSSList, pRSNWPA);
- }
- }
-
- WPA2_ClearRSN(pBSSList); //mike update
-
- if (pRSN != NULL) {
- unsigned int uLen = pRSN->len + 2;
- if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
- pBSSList->wRSNLen = uLen;
- memcpy(pBSSList->byRSNIE, pRSN, uLen);
- WPA2vParseRSN(pBSSList, pRSN);
- }
- }
-
- if (pRxPacket->uRSSI != 0) {
- RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &ldBm);
- // Moniter if RSSI is too strong.
- pBSSList->byRSSIStatCnt++;
- pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
- pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm;
- for(ii=0;ii<RSSI_STAT_COUNT;ii++) {
- if (pBSSList->ldBmAverage[ii] != 0) {
- pBSSList->ldBmMAX = max(pBSSList->ldBmAverage[ii], ldBm);
- }
- }
- }
-
- if ((pIE_Country != NULL) &&
- (pMgmt->b11hEnable == true)) {
- set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
- pIE_Country);
- }
-
- if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
- if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
- (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
- // valid EID
- if (pQuiet == NULL) {
- pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
- CARDbSetQuiet( pMgmt->pAdapter,
- true,
- pQuiet->byQuietCount,
- pQuiet->byQuietPeriod,
- *((unsigned short *)pQuiet->abyQuietDuration),
- *((unsigned short *)pQuiet->abyQuietOffset)
- );
- } else {
- pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
- CARDbSetQuiet( pMgmt->pAdapter,
- false,
- pQuiet->byQuietCount,
- pQuiet->byQuietPeriod,
- *((unsigned short *)pQuiet->abyQuietDuration),
- *((unsigned short *)pQuiet->abyQuietOffset)
- );
- }
- }
- }
-
- if ((bParsingQuiet == true) &&
- (pQuiet != NULL)) {
- CARDbStartQuiet(pMgmt->pAdapter);
- }
-
- pBSSList->uIELength = uIELength;
- if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN)
- pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
- memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
-
- return true;
-}
+ int ii;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSRxMgmtPacket pRxPacket = (PSRxMgmtPacket)pRxPacketContext;
+ long ldBm;
+ bool bParsingQuiet = false;
+ PWLAN_IE_QUIET pQuiet = NULL;
+
+ if (pBSSList == NULL)
+ return false;
+
+ HIDWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(HIDWORD(qwTimestamp));
+ LODWORD(pBSSList->qwBSSTimestamp) = cpu_to_le32(LODWORD(qwTimestamp));
+ pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval);
+ pBSSList->wCapInfo = cpu_to_le16(wCapInfo);
+ pBSSList->uClearCount = 0;
+ pBSSList->uChannel = byCurrChannel;
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSbUpdateToBSSList: pBSSList->uChannel: %d\n", pBSSList->uChannel);
+
+ if (pSSID->len > WLAN_SSID_MAXLEN)
+ pSSID->len = WLAN_SSID_MAXLEN;
+
+ if ((pSSID->len != 0) && (pSSID->abySSID[0] != 0))
+ memcpy(pBSSList->abySSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
+ memcpy(pBSSList->abySuppRates, pSuppRates, pSuppRates->len + WLAN_IEHDR_LEN);
+
+ if (pExtSuppRates != NULL) {
+ memcpy(pBSSList->abyExtSuppRates, pExtSuppRates, pExtSuppRates->len + WLAN_IEHDR_LEN);
+ } else {
+ memset(pBSSList->abyExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+ }
+ pBSSList->sERP.byERP = psERP->byERP;
+ pBSSList->sERP.bERPExist = psERP->bERPExist;
+
+ // Check if BSS is 802.11a/b/g
+ if (pBSSList->uChannel > CB_MAX_CHANNEL_24G) {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11A;
+ } else {
+ if (pBSSList->sERP.bERPExist == true) {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11G;
+ } else {
+ pBSSList->eNetworkTypeInUse = PHY_TYPE_11B;
+ }
+ }
+
+ pBSSList->byRxRate = pRxPacket->byRxRate;
+ pBSSList->qwLocalTSF = pRxPacket->qwLocalTSF;
+ if (bChannelHit)
+ pBSSList->uRSSI = pRxPacket->uRSSI;
+ pBSSList->bySQ = pRxPacket->bySQ;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ // assoc with BSS
+ if (pBSSList == pMgmt->pCurrBSS) {
+ bParsingQuiet = true;
+ }
+ }
+ WPA_ClearRSN(pBSSList); //mike update
+ if (pRSNWPA != NULL) {
+ unsigned int uLen = pRSNWPA->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSNWPA - pbyIEs))) {
+ pBSSList->wWPALen = uLen;
+ memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
+ WPA_ParseRSN(pBSSList, pRSNWPA);
+ }
+ }
+
+ WPA2_ClearRSN(pBSSList); //mike update
+
+ if (pRSN != NULL) {
+ unsigned int uLen = pRSN->len + 2;
+ if (uLen <= (uIELength - (unsigned int)((unsigned char *)pRSN - pbyIEs))) {
+ pBSSList->wRSNLen = uLen;
+ memcpy(pBSSList->byRSNIE, pRSN, uLen);
+ WPA2vParseRSN(pBSSList, pRSN);
+ }
+ }
+
+ if (pRxPacket->uRSSI != 0) {
+ RFvRSSITodBm(pDevice, (unsigned char)(pRxPacket->uRSSI), &ldBm);
+ // Moniter if RSSI is too strong.
+ pBSSList->byRSSIStatCnt++;
+ pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
+ pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm;
+ for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
+ if (pBSSList->ldBmAverage[ii] != 0) {
+ pBSSList->ldBmMAX = max(pBSSList->ldBmAverage[ii], ldBm);
+ }
+ }
+ }
+
+ if ((pIE_Country != NULL) &&
+ (pMgmt->b11hEnable == true)) {
+ set_country_info(pMgmt->pAdapter, pBSSList->eNetworkTypeInUse,
+ pIE_Country);
+ }
+
+ if ((bParsingQuiet == true) && (pIE_Quiet != NULL)) {
+ if ((((PWLAN_IE_QUIET)pIE_Quiet)->len == 8) &&
+ (((PWLAN_IE_QUIET)pIE_Quiet)->byQuietCount != 0)) {
+ // valid EID
+ if (pQuiet == NULL) {
+ pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
+ CARDbSetQuiet(pMgmt->pAdapter,
+ true,
+ pQuiet->byQuietCount,
+ pQuiet->byQuietPeriod,
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
+);
+ } else {
+ pQuiet = (PWLAN_IE_QUIET)pIE_Quiet;
+ CARDbSetQuiet(pMgmt->pAdapter,
+ false,
+ pQuiet->byQuietCount,
+ pQuiet->byQuietPeriod,
+ *((unsigned short *)pQuiet->abyQuietDuration),
+ *((unsigned short *)pQuiet->abyQuietOffset)
+ );
+ }
+ }
+ }
+ if ((bParsingQuiet == true) &&
+ (pQuiet != NULL)) {
+ CARDbStartQuiet(pMgmt->pAdapter);
+ }
+ pBSSList->uIELength = uIELength;
+ if (pBSSList->uIELength > WLAN_BEACON_FR_MAXLEN)
+ pBSSList->uIELength = WLAN_BEACON_FR_MAXLEN;
+ memcpy(pBSSList->abyIEs, pbyIEs, pBSSList->uIELength);
+
+ return true;
+}
/*+
*
@@ -757,29 +721,27 @@ BSSbUpdateToBSSList (
* Return Value:
* None
*
--*/
+ -*/
bool
BSSDBbIsSTAInNodeDB(void *pMgmtObject, unsigned char *abyDstAddr,
- unsigned int *puNodeIndex)
+ unsigned int *puNodeIndex)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- unsigned int ii;
-
- // Index = 0 reserved for AP Node
- for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
- if (pMgmt->sNodeDBTable[ii].bActive) {
- if (!compare_ether_addr(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) {
- *puNodeIndex = ii;
- return true;
- }
- }
- }
-
- return false;
-};
-
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+ unsigned int ii;
+
+ // Index = 0 reserved for AP Node
+ for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
+ if (pMgmt->sNodeDBTable[ii].bActive) {
+ if (!compare_ether_addr(abyDstAddr, pMgmt->sNodeDBTable[ii].abyMACAddr)) {
+ *puNodeIndex = ii;
+ return true;
+ }
+ }
+ }
+ return false;
+};
/*+
*
@@ -790,59 +752,54 @@ BSSDBbIsSTAInNodeDB(void *pMgmtObject, unsigned char *abyDstAddr,
* Return Value:
* None
*
--*/
+ -*/
void
BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex)
{
-
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int ii;
- unsigned int BigestCount = 0;
- unsigned int SelectIndex;
- struct sk_buff *skb;
- // Index = 0 reserved for AP Node (In STA mode)
- // Index = 0 reserved for Broadcast/MultiCast (In AP mode)
- SelectIndex = 1;
- for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
- if (pMgmt->sNodeDBTable[ii].bActive) {
- if (pMgmt->sNodeDBTable[ii].uInActiveCount > BigestCount) {
- BigestCount = pMgmt->sNodeDBTable[ii].uInActiveCount;
- SelectIndex = ii;
- }
- }
- else {
- break;
- }
- }
-
- // if not found replace uInActiveCount is largest one.
- if ( ii == (MAX_NODE_NUM + 1)) {
- *puNodeIndex = SelectIndex;
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Replace inactive node = %d\n", SelectIndex);
- // clear ps buffer
- if (pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue.next != NULL) {
- while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue)) != NULL)
- dev_kfree_skb(skb);
- }
- }
- else {
- *puNodeIndex = ii;
- }
-
- memset(&pMgmt->sNodeDBTable[*puNodeIndex], 0, sizeof(KnownNodeDB));
- pMgmt->sNodeDBTable[*puNodeIndex].bActive = true;
- pMgmt->sNodeDBTable[*puNodeIndex].uRatePollTimeout = FALLBACK_POLL_SECOND;
- // for AP mode PS queue
- skb_queue_head_init(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue);
- pMgmt->sNodeDBTable[*puNodeIndex].byAuthSequence = 0;
- pMgmt->sNodeDBTable[*puNodeIndex].wEnQueueCnt = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create node index = %d\n", ii);
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int ii;
+ unsigned int BigestCount = 0;
+ unsigned int SelectIndex;
+ struct sk_buff *skb;
+ // Index = 0 reserved for AP Node (In STA mode)
+ // Index = 0 reserved for Broadcast/MultiCast (In AP mode)
+ SelectIndex = 1;
+ for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
+ if (pMgmt->sNodeDBTable[ii].bActive) {
+ if (pMgmt->sNodeDBTable[ii].uInActiveCount > BigestCount) {
+ BigestCount = pMgmt->sNodeDBTable[ii].uInActiveCount;
+ SelectIndex = ii;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // if not found replace uInActiveCount is largest one.
+ if (ii == (MAX_NODE_NUM + 1)) {
+ *puNodeIndex = SelectIndex;
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Replace inactive node = %d\n", SelectIndex);
+ // clear ps buffer
+ if (pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue.next != NULL) {
+ while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue)) != NULL)
+ dev_kfree_skb(skb);
+ }
+ } else {
+ *puNodeIndex = ii;
+ }
+
+ memset(&pMgmt->sNodeDBTable[*puNodeIndex], 0, sizeof(KnownNodeDB));
+ pMgmt->sNodeDBTable[*puNodeIndex].bActive = true;
+ pMgmt->sNodeDBTable[*puNodeIndex].uRatePollTimeout = FALLBACK_POLL_SECOND;
+ // for AP mode PS queue
+ skb_queue_head_init(&pMgmt->sNodeDBTable[*puNodeIndex].sTxPSQueue);
+ pMgmt->sNodeDBTable[*puNodeIndex].byAuthSequence = 0;
+ pMgmt->sNodeDBTable[*puNodeIndex].wEnQueueCnt = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create node index = %d\n", ii);
+ return;
};
-
-
/*+
*
* Routine Description:
@@ -852,28 +809,26 @@ BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex)
* Return Value:
* None
*
--*/
+ -*/
void
BSSvRemoveOneNode(
- void *hDeviceContext,
- unsigned int uNodeIndex
- )
+ void *hDeviceContext,
+ unsigned int uNodeIndex
+)
{
-
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- struct sk_buff *skb;
-
-
- while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue)) != NULL)
- dev_kfree_skb(skb);
- // clear context
- memset(&pMgmt->sNodeDBTable[uNodeIndex], 0, sizeof(KnownNodeDB));
- // clear tx bit map
- pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[uNodeIndex].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[uNodeIndex].wAID & 7];
-
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue)) != NULL)
+ dev_kfree_skb(skb);
+ // clear context
+ memset(&pMgmt->sNodeDBTable[uNodeIndex], 0, sizeof(KnownNodeDB));
+ // clear tx bit map
+ pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[uNodeIndex].wAID >> 3] &= ~byMask[pMgmt->sNodeDBTable[uNodeIndex].wAID & 7];
+
+ return;
};
/*+
*
@@ -884,59 +839,54 @@ BSSvRemoveOneNode(
* Return Value:
* None
*
--*/
+ -*/
void
BSSvUpdateAPNode(
- void *hDeviceContext,
- unsigned short *pwCapInfo,
- PWLAN_IE_SUPP_RATES pSuppRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates
- )
+ void *hDeviceContext,
+ unsigned short *pwCapInfo,
+ PWLAN_IE_SUPP_RATES pSuppRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int uRateLen = WLAN_RATES_MAXLEN;
-
- memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
-
- pMgmt->sNodeDBTable[0].bActive = true;
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- uRateLen);
- pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pExtSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- uRateLen);
- RATEvParseMaxRate((void *)pDevice,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- true,
- &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[0].wSuppRate),
- &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
- );
- memcpy(pMgmt->sNodeDBTable[0].abyMACAddr, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxSuppRate;
- pMgmt->sNodeDBTable[0].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*pwCapInfo);
- pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+
+ memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
+
+ pMgmt->sNodeDBTable[0].bActive = true;
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ uRateLen);
+ pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pExtSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ uRateLen);
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ true,
+ &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[0].wSuppRate),
+ &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
+);
+ memcpy(pMgmt->sNodeDBTable[0].abyMACAddr, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
+ pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxSuppRate;
+ pMgmt->sNodeDBTable[0].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*pwCapInfo);
+ pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND;
#ifdef PLICE_DEBUG
- printk("BSSvUpdateAPNode:MaxSuppRate is %d\n",pMgmt->sNodeDBTable[0].wMaxSuppRate);
+ printk("BSSvUpdateAPNode:MaxSuppRate is %d\n", pMgmt->sNodeDBTable[0].wMaxSuppRate);
#endif
- // Auto rate fallback function initiation.
- // RATEbInit(pDevice);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pMgmt->sNodeDBTable[0].wTxDataRate = %d \n", pMgmt->sNodeDBTable[0].wTxDataRate);
-
+ // Auto rate fallback function initiation.
+ // RATEbInit(pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->sNodeDBTable[0].wTxDataRate = %d \n", pMgmt->sNodeDBTable[0].wTxDataRate);
};
-
-
-
-
/*+
*
* Routine Description:
@@ -946,45 +896,39 @@ BSSvUpdateAPNode(
* Return Value:
* None
*
--*/
-
+ -*/
void
BSSvAddMulticastNode(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
- if (!pDevice->bEnableHostWEP)
- memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
- memset(pMgmt->sNodeDBTable[0].abyMACAddr, 0xff, WLAN_ADDR_LEN);
- pMgmt->sNodeDBTable[0].bActive = true;
- pMgmt->sNodeDBTable[0].bPSEnable = false;
- skb_queue_head_init(&pMgmt->sNodeDBTable[0].sTxPSQueue);
- RATEvParseMaxRate((void *)pDevice,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- true,
- &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[0].wSuppRate),
- &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
- );
- pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxBasicRate;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ if (!pDevice->bEnableHostWEP)
+ memset(&pMgmt->sNodeDBTable[0], 0, sizeof(KnownNodeDB));
+ memset(pMgmt->sNodeDBTable[0].abyMACAddr, 0xff, WLAN_ADDR_LEN);
+ pMgmt->sNodeDBTable[0].bActive = true;
+ pMgmt->sNodeDBTable[0].bPSEnable = false;
+ skb_queue_head_init(&pMgmt->sNodeDBTable[0].sTxPSQueue);
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ true,
+ &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[0].wSuppRate),
+ &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
+);
+ pMgmt->sNodeDBTable[0].wTxDataRate = pMgmt->sNodeDBTable[0].wMaxBasicRate;
#ifdef PLICE_DEBUG
- printk("BSSvAddMultiCastNode:pMgmt->sNodeDBTable[0].wTxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate);
+ printk("BSSvAddMultiCastNode:pMgmt->sNodeDBTable[0].wTxDataRate is %d\n", pMgmt->sNodeDBTable[0].wTxDataRate);
#endif
- pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND;
-
+ pMgmt->sNodeDBTable[0].uRatePollTimeout = FALLBACK_POLL_SECOND;
};
-
-
-
-
/*+
*
* Routine Description:
@@ -996,373 +940,348 @@ BSSvAddMulticastNode(
* Return Value:
* none.
*
--*/
- //2008-4-14 <add> by chester for led issue
- #ifdef FOR_LED_ON_NOTEBOOK
-bool cc=false;
+ -*/
+//2008-4-14 <add> by chester for led issue
+#ifdef FOR_LED_ON_NOTEBOOK
+bool cc = false;
unsigned int status;
#endif
void
BSSvSecondCallBack(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int ii;
- PWLAN_IE_SSID pItemSSID, pCurrSSID;
- unsigned int uSleepySTACnt = 0;
- unsigned int uNonShortSlotSTACnt = 0;
- unsigned int uLongPreambleSTACnt = 0;
- viawget_wpa_header* wpahdr; //DavidWang
-
- spin_lock_irq(&pDevice->lock);
-
- pDevice->uAssocCount = 0;
-
- pDevice->byERPFlag &=
- ~(WLAN_SET_ERP_BARKER_MODE(1) | WLAN_SET_ERP_NONERP_PRESENT(1));
- //2008-4-14 <add> by chester for led issue
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int ii;
+ PWLAN_IE_SSID pItemSSID, pCurrSSID;
+ unsigned int uSleepySTACnt = 0;
+ unsigned int uNonShortSlotSTACnt = 0;
+ unsigned int uLongPreambleSTACnt = 0;
+ viawget_wpa_header *wpahdr; //DavidWang
+
+ spin_lock_irq(&pDevice->lock);
+
+ pDevice->uAssocCount = 0;
+
+ pDevice->byERPFlag &=
+ ~(WLAN_SET_ERP_BARKER_MODE(1) | WLAN_SET_ERP_NONERP_PRESENT(1));
+ //2008-4-14 <add> by chester for led issue
#ifdef FOR_LED_ON_NOTEBOOK
-MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
-if ((( !(pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == false))||((pDevice->byGPIO & GPIO0_DATA)&&(pDevice->bHWRadioOff == true)))&&(cc==false)){
-cc=true;
-}
-else if(cc==true){
-
-if(pDevice->bHWRadioOff == true){
- if ( !(pDevice->byGPIO & GPIO0_DATA))
-//||( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
-{if(status==1) goto start;
-status=1;
-CARDbRadioPowerOff(pDevice);
- pMgmt->sNodeDBTable[0].bActive = false;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- //netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
-
-}
- if (pDevice->byGPIO &GPIO0_DATA)
-//||( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
-{if(status==2) goto start;
-status=2;
-CARDbRadioPowerOn(pDevice);
-} }
-else{
- if (pDevice->byGPIO & GPIO0_DATA)
-//||( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
-{if(status==3) goto start;
-status=3;
-CARDbRadioPowerOff(pDevice);
- pMgmt->sNodeDBTable[0].bActive = false;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- //netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
-
-}
- if ( !(pDevice->byGPIO & GPIO0_DATA))
-//||( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
-{if(status==4) goto start;
-status=4;
-CARDbRadioPowerOn(pDevice);
-} }
-}
+ MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
+ if (((!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->bHWRadioOff == false)) || ((pDevice->byGPIO & GPIO0_DATA) && (pDevice->bHWRadioOff == true))) && (cc == false)) {
+ cc = true;
+ } else if (cc == true) {
+ if (pDevice->bHWRadioOff == true) {
+ if (!(pDevice->byGPIO & GPIO0_DATA))
+//||(!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
+ {
+ if (status == 1) goto start;
+ status = 1;
+ CARDbRadioPowerOff(pDevice);
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ //netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+
+ }
+ if (pDevice->byGPIO & GPIO0_DATA)
+//||(!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
+ {
+ if (status == 2) goto start;
+ status = 2;
+ CARDbRadioPowerOn(pDevice);
+ }
+ } else {
+ if (pDevice->byGPIO & GPIO0_DATA)
+//||(!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
+ {
+ if (status == 3) goto start;
+ status = 3;
+ CARDbRadioPowerOff(pDevice);
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ //netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+
+ }
+ if (!(pDevice->byGPIO & GPIO0_DATA))
+//||(!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV)))
+ {
+ if (status == 4) goto start;
+ status = 4;
+ CARDbRadioPowerOn(pDevice);
+ }
+ }
+ }
start:
#endif
-
- if (pDevice->wUseProtectCntDown > 0) {
- pDevice->wUseProtectCntDown --;
- }
- else {
- // disable protect mode
- pDevice->byERPFlag &= ~(WLAN_SET_ERP_USE_PROTECTION(1));
- }
-
-{
- pDevice->byReAssocCount++;
- if((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != true)) { //10 sec timeout
- printk("Re-association timeout!!!\n");
- pDevice->byReAssocCount = 0;
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == true)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- PRINT_K("wireless_send_event--->SIOCGIWAP(disassociated)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
- }
- else if(pDevice->bLinkPass == true)
- pDevice->byReAssocCount = 0;
-}
+ if (pDevice->wUseProtectCntDown > 0) {
+ pDevice->wUseProtectCntDown--;
+ } else {
+ // disable protect mode
+ pDevice->byERPFlag &= ~(WLAN_SET_ERP_USE_PROTECTION(1));
+ }
+
+ {
+ pDevice->byReAssocCount++;
+ if ((pDevice->byReAssocCount > 10) && (pDevice->bLinkPass != true)) { //10 sec timeout
+ printk("Re-association timeout!!!\n");
+ pDevice->byReAssocCount = 0;
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ PRINT_K("wireless_send_event--->SIOCGIWAP(disassociated)\n");
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ } else if (pDevice->bLinkPass == true)
+ pDevice->byReAssocCount = 0;
+ }
#ifdef Calcu_LinkQual
- s_uCalculateLinkQual((void *)pDevice);
+ s_uCalculateLinkQual((void *)pDevice);
#endif
- for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
-
- if (pMgmt->sNodeDBTable[ii].bActive) {
- // Increase in-activity counter
- pMgmt->sNodeDBTable[ii].uInActiveCount++;
-
- if (ii > 0) {
- if (pMgmt->sNodeDBTable[ii].uInActiveCount > MAX_INACTIVE_COUNT) {
- BSSvRemoveOneNode(pDevice, ii);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
- "Inactive timeout [%d] sec, STA index = [%d] remove\n", MAX_INACTIVE_COUNT, ii);
- continue;
- }
-
- if (pMgmt->sNodeDBTable[ii].eNodeState >= NODE_ASSOC) {
-
- pDevice->uAssocCount++;
-
- // check if Non ERP exist
- if (pMgmt->sNodeDBTable[ii].uInActiveCount < ERP_RECOVER_COUNT) {
- if (!pMgmt->sNodeDBTable[ii].bShortPreamble) {
- pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1);
- uLongPreambleSTACnt ++;
- }
- if (!pMgmt->sNodeDBTable[ii].bERPExist) {
- pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1);
- pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
- }
- if (!pMgmt->sNodeDBTable[ii].bShortSlotTime)
- uNonShortSlotSTACnt++;
- }
- }
+ for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
+ if (pMgmt->sNodeDBTable[ii].bActive) {
+ // Increase in-activity counter
+ pMgmt->sNodeDBTable[ii].uInActiveCount++;
+
+ if (ii > 0) {
+ if (pMgmt->sNodeDBTable[ii].uInActiveCount > MAX_INACTIVE_COUNT) {
+ BSSvRemoveOneNode(pDevice, ii);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
+ "Inactive timeout [%d] sec, STA index = [%d] remove\n", MAX_INACTIVE_COUNT, ii);
+ continue;
+ }
- // check if any STA in PS mode
- if (pMgmt->sNodeDBTable[ii].bPSEnable)
- uSleepySTACnt++;
+ if (pMgmt->sNodeDBTable[ii].eNodeState >= NODE_ASSOC) {
+ pDevice->uAssocCount++;
+
+ // check if Non ERP exist
+ if (pMgmt->sNodeDBTable[ii].uInActiveCount < ERP_RECOVER_COUNT) {
+ if (!pMgmt->sNodeDBTable[ii].bShortPreamble) {
+ pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1);
+ uLongPreambleSTACnt++;
+ }
+ if (!pMgmt->sNodeDBTable[ii].bERPExist) {
+ pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1);
+ pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
+ }
+ if (!pMgmt->sNodeDBTable[ii].bShortSlotTime)
+ uNonShortSlotSTACnt++;
+ }
+ }
+ // check if any STA in PS mode
+ if (pMgmt->sNodeDBTable[ii].bPSEnable)
+ uSleepySTACnt++;
- }
+ }
- // Rate fallback check
- if (!pDevice->bFixRate) {
+ // Rate fallback check
+ if (!pDevice->bFixRate) {
/*
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (ii == 0))
- RATEvTxRateFallBack(pDevice, &(pMgmt->sNodeDBTable[ii]));
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (ii == 0))
+ RATEvTxRateFallBack(pDevice, &(pMgmt->sNodeDBTable[ii]));
*/
- if (ii > 0) {
- // ii = 0 for multicast node (AP & Adhoc)
- RATEvTxRateFallBack((void *)pDevice, &(pMgmt->sNodeDBTable[ii]));
- }
- else {
- // ii = 0 reserved for unicast AP node (Infra STA)
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)
+ if (ii > 0) {
+ // ii = 0 for multicast node (AP & Adhoc)
+ RATEvTxRateFallBack((void *)pDevice, &(pMgmt->sNodeDBTable[ii]));
+ } else {
+ // ii = 0 reserved for unicast AP node (Infra STA)
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)
#ifdef PLICE_DEBUG
- printk("SecondCallback:Before:TxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate);
+ printk("SecondCallback:Before:TxDataRate is %d\n", pMgmt->sNodeDBTable[0].wTxDataRate);
#endif
- RATEvTxRateFallBack((void *)pDevice, &(pMgmt->sNodeDBTable[ii]));
+ RATEvTxRateFallBack((void *)pDevice, &(pMgmt->sNodeDBTable[ii]));
#ifdef PLICE_DEBUG
- printk("SecondCallback:After:TxDataRate is %d\n",pMgmt->sNodeDBTable[0].wTxDataRate);
+ printk("SecondCallback:After:TxDataRate is %d\n", pMgmt->sNodeDBTable[0].wTxDataRate);
#endif
+ }
+
+ }
+
+ // check if pending PS queue
+ if (pMgmt->sNodeDBTable[ii].wEnQueueCnt != 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index= %d, Queue = %d pending \n",
+ ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt);
+ if ((ii > 0) && (pMgmt->sNodeDBTable[ii].wEnQueueCnt > 15)) {
+ BSSvRemoveOneNode(pDevice, ii);
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Pending many queues PS STA Index = %d remove \n", ii);
+ continue;
+ }
+ }
}
- }
-
- // check if pending PS queue
- if (pMgmt->sNodeDBTable[ii].wEnQueueCnt != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index= %d, Queue = %d pending \n",
- ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt);
- if ((ii >0) && (pMgmt->sNodeDBTable[ii].wEnQueueCnt > 15)) {
- BSSvRemoveOneNode(pDevice, ii);
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Pending many queues PS STA Index = %d remove \n", ii);
- continue;
- }
- }
- }
-
- }
-
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->eCurrentPHYType == PHY_TYPE_11G)) {
-
- // on/off protect mode
- if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)) {
- if (!pDevice->bProtectMode) {
- MACvEnableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = true;
- }
- }
- else {
- if (pDevice->bProtectMode) {
- MACvDisableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = false;
- }
- }
- // on/off short slot time
-
- if (uNonShortSlotSTACnt > 0) {
- if (pDevice->bShortSlotTime) {
- pDevice->bShortSlotTime = false;
- BBvSetShortSlotTime(pDevice);
- vUpdateIFS((void *)pDevice);
- }
- }
- else {
- if (!pDevice->bShortSlotTime) {
- pDevice->bShortSlotTime = true;
- BBvSetShortSlotTime(pDevice);
- vUpdateIFS((void *)pDevice);
- }
- }
-
- // on/off barker long preamble mode
-
- if (uLongPreambleSTACnt > 0) {
- if (!pDevice->bBarkerPreambleMd) {
- MACvEnableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = true;
- }
- }
- else {
- if (pDevice->bBarkerPreambleMd) {
- MACvDisableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = false;
- }
- }
-
- }
-
-
- // Check if any STA in PS mode, enable DTIM multicast deliver
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (uSleepySTACnt > 0)
- pMgmt->sNodeDBTable[0].bPSEnable = true;
- else
- pMgmt->sNodeDBTable[0].bPSEnable = false;
- }
-
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
- pCurrSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
-
- if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) ||
- (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) {
-
- if (pMgmt->sNodeDBTable[0].bActive) { // Assoc with BSS
- // DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Callback inactive Count = [%d]\n", pMgmt->sNodeDBTable[0].uInActiveCount);
- //if (pDevice->bUpdateBBVGA) {
- // s_vCheckSensitivity((void *) pDevice);
- //}
-
- if (pDevice->bUpdateBBVGA) {
- // s_vCheckSensitivity((void *) pDevice);
- s_vCheckPreEDThreshold((void *)pDevice);
- }
-
- if ((pMgmt->sNodeDBTable[0].uInActiveCount >= (LOST_BEACON_COUNT/2)) &&
- (pDevice->byBBVGACurrent != pDevice->abyBBVGA[0]) ) {
- pDevice->byBBVGANew = pDevice->abyBBVGA[0];
- bScheduleCommand((void *) pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL);
- }
-
- if (pMgmt->sNodeDBTable[0].uInActiveCount >= LOST_BEACON_COUNT) {
- pMgmt->sNodeDBTable[0].bActive = false;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
- pDevice->bRoaming = true;
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost AP beacon [%d] sec, disconnected !\n", pMgmt->sNodeDBTable[0].uInActiveCount);
- if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- wpahdr->type = VIAWGET_DISASSOC_MSG;
- wpahdr->resp_ie_len = 0;
- wpahdr->req_ie_len = 0;
- skb_put(pDevice->skb, sizeof(viawget_wpa_header));
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == true)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- PRINT_K("wireless_send_event--->SIOCGIWAP(disassociated)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
- }
- }
- else if (pItemSSID->len != 0) {
- if (pDevice->uAutoReConnectTime < 10) {
- pDevice->uAutoReConnectTime++;
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //network manager support need not do Roaming scan???
- if(pDevice->bWPASuppWextEnabled ==true)
- pDevice->uAutoReConnectTime = 0;
- #endif
- }
- else {
- //mike use old encryption status for wpa reauthen
- if(pDevice->bWPADEVUp)
- pDevice->eEncryptionStatus = pDevice->eOldEncryptionStatus;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Roaming ...\n");
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
- pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
- pDevice->uAutoReConnectTime = 0;
- }
- }
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- // if adhoc started which essid is NULL string, rescanning.
- if ((pMgmt->eCurrState == WMAC_STATE_STARTED) && (pCurrSSID->len == 0)) {
- if (pDevice->uAutoReConnectTime < 10) {
- pDevice->uAutoReConnectTime++;
- }
- else {
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scanning ...\n");
- pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
- pDevice->uAutoReConnectTime = 0;
- };
- }
- if (pMgmt->eCurrState == WMAC_STATE_JOINTED) {
-
- if (pDevice->bUpdateBBVGA) {
- //s_vCheckSensitivity((void *) pDevice);
- s_vCheckPreEDThreshold((void *)pDevice);
- }
- if (pMgmt->sNodeDBTable[0].uInActiveCount >=ADHOC_LOST_BEACON_COUNT) {
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost other STA beacon [%d] sec, started !\n", pMgmt->sNodeDBTable[0].uInActiveCount);
- pMgmt->sNodeDBTable[0].uInActiveCount = 0;
- pMgmt->eCurrState = WMAC_STATE_STARTED;
- netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
- }
- }
- }
-
- spin_unlock_irq(&pDevice->lock);
-
- pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ);
- add_timer(&pMgmt->sTimerSecondCallback);
- return;
-}
+ }
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->eCurrentPHYType == PHY_TYPE_11G)) {
+ // on/off protect mode
+ if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)) {
+ if (!pDevice->bProtectMode) {
+ MACvEnableProtectMD(pDevice->PortOffset);
+ pDevice->bProtectMode = true;
+ }
+ } else {
+ if (pDevice->bProtectMode) {
+ MACvDisableProtectMD(pDevice->PortOffset);
+ pDevice->bProtectMode = false;
+ }
+ }
+ // on/off short slot time
+
+ if (uNonShortSlotSTACnt > 0) {
+ if (pDevice->bShortSlotTime) {
+ pDevice->bShortSlotTime = false;
+ BBvSetShortSlotTime(pDevice);
+ vUpdateIFS((void *)pDevice);
+ }
+ } else {
+ if (!pDevice->bShortSlotTime) {
+ pDevice->bShortSlotTime = true;
+ BBvSetShortSlotTime(pDevice);
+ vUpdateIFS((void *)pDevice);
+ }
+ }
+
+ // on/off barker long preamble mode
+
+ if (uLongPreambleSTACnt > 0) {
+ if (!pDevice->bBarkerPreambleMd) {
+ MACvEnableBarkerPreambleMd(pDevice->PortOffset);
+ pDevice->bBarkerPreambleMd = true;
+ }
+ } else {
+ if (pDevice->bBarkerPreambleMd) {
+ MACvDisableBarkerPreambleMd(pDevice->PortOffset);
+ pDevice->bBarkerPreambleMd = false;
+ }
+ }
+ }
+
+ // Check if any STA in PS mode, enable DTIM multicast deliver
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (uSleepySTACnt > 0)
+ pMgmt->sNodeDBTable[0].bPSEnable = true;
+ else
+ pMgmt->sNodeDBTable[0].bPSEnable = false;
+ }
+
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+ pCurrSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) ||
+ (pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) {
+ if (pMgmt->sNodeDBTable[0].bActive) { // Assoc with BSS
+ if (pDevice->bUpdateBBVGA) {
+ // s_vCheckSensitivity((void *) pDevice);
+ s_vCheckPreEDThreshold((void *)pDevice);
+ }
+
+ if ((pMgmt->sNodeDBTable[0].uInActiveCount >= (LOST_BEACON_COUNT/2)) &&
+ (pDevice->byBBVGACurrent != pDevice->abyBBVGA[0])) {
+ pDevice->byBBVGANew = pDevice->abyBBVGA[0];
+ bScheduleCommand((void *)pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL);
+ }
+
+ if (pMgmt->sNodeDBTable[0].uInActiveCount >= LOST_BEACON_COUNT) {
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+ pDevice->bRoaming = true;
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost AP beacon [%d] sec, disconnected !\n", pMgmt->sNodeDBTable[0].uInActiveCount);
+ if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ wpahdr->type = VIAWGET_DISASSOC_MSG;
+ wpahdr->resp_ie_len = 0;
+ wpahdr->req_ie_len = 0;
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header));
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ PRINT_K("wireless_send_event--->SIOCGIWAP(disassociated)\n");
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ }
+ } else if (pItemSSID->len != 0) {
+ if (pDevice->uAutoReConnectTime < 10) {
+ pDevice->uAutoReConnectTime++;
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ //network manager support need not do Roaming scan???
+ if (pDevice->bWPASuppWextEnabled == true)
+ pDevice->uAutoReConnectTime = 0;
+#endif
+ } else {
+ //mike use old encryption status for wpa reauthen
+ if (pDevice->bWPADEVUp)
+ pDevice->eEncryptionStatus = pDevice->eOldEncryptionStatus;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Roaming ...\n");
+ BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
+ pDevice->uAutoReConnectTime = 0;
+ }
+ }
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ // if adhoc started which essid is NULL string, rescanning.
+ if ((pMgmt->eCurrState == WMAC_STATE_STARTED) && (pCurrSSID->len == 0)) {
+ if (pDevice->uAutoReConnectTime < 10) {
+ pDevice->uAutoReConnectTime++;
+ } else {
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Adhoc re-scanning ...\n");
+ pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
+ pDevice->uAutoReConnectTime = 0;
+ };
+ }
+ if (pMgmt->eCurrState == WMAC_STATE_JOINTED) {
+ if (pDevice->bUpdateBBVGA) {
+ //s_vCheckSensitivity((void *) pDevice);
+ s_vCheckPreEDThreshold((void *)pDevice);
+ }
+ if (pMgmt->sNodeDBTable[0].uInActiveCount >= ADHOC_LOST_BEACON_COUNT) {
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Lost other STA beacon [%d] sec, started !\n", pMgmt->sNodeDBTable[0].uInActiveCount);
+ pMgmt->sNodeDBTable[0].uInActiveCount = 0;
+ pMgmt->eCurrState = WMAC_STATE_STARTED;
+ netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+ }
+ }
+ }
+ spin_unlock_irq(&pDevice->lock);
+ pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ);
+ add_timer(&pMgmt->sTimerSecondCallback);
+ return;
+}
/*+
*
@@ -1375,184 +1294,162 @@ start:
* Return Value:
* none.
*
--*/
-
-
+ -*/
void
BSSvUpdateNodeTxCounter(
- void *hDeviceContext,
- unsigned char byTsr0,
- unsigned char byTsr1,
- unsigned char *pbyBuffer,
- unsigned int uFIFOHeaderSize
- )
+ void *hDeviceContext,
+ unsigned char byTsr0,
+ unsigned char byTsr1,
+ unsigned char *pbyBuffer,
+ unsigned int uFIFOHeaderSize
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int uNodeIndex = 0;
- unsigned char byTxRetry = (byTsr0 & TSR0_NCR);
- PSTxBufHead pTxBufHead;
- PS802_11Header pMACHeader;
- unsigned short wRate;
- unsigned short wFallBackRate = RATE_1M;
- unsigned char byFallBack;
- unsigned int ii;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int uNodeIndex = 0;
+ unsigned char byTxRetry = (byTsr0 & TSR0_NCR);
+ PSTxBufHead pTxBufHead;
+ PS802_11Header pMACHeader;
+ unsigned short wRate;
+ unsigned short wFallBackRate = RATE_1M;
+ unsigned char byFallBack;
+ unsigned int ii;
// unsigned int txRetryTemp;
//PLICE_DEBUG->
//txRetryTemp = byTxRetry;
- //if (txRetryTemp== 8)
- //txRetryTemp -=3;
//PLICE_DEBUG <-
- pTxBufHead = (PSTxBufHead) pbyBuffer;
- if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_0) {
- byFallBack = AUTO_FB_0;
- } else if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_1) {
- byFallBack = AUTO_FB_1;
- } else {
- byFallBack = AUTO_FB_NONE;
- }
- wRate = pTxBufHead->wReserved; //?wRate
- //printk("BSSvUpdateNodeTxCounter:byTxRetry is %d\n",byTxRetry);
-
-//printk("BSSvUpdateNodeTx:wRate is %d,byFallback is %d\n",wRate,byFallBack);
-//#ifdef PLICE_DEBUG
- //printk("BSSvUpdateNodeTx: wRate is %d\n",wRate);
-////#endif
- // Only Unicast using support rates
- if (pTxBufHead->wFIFOCtl & FIFOCTL_NEEDACK) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wRate %04X, byTsr0 %02X, byTsr1 %02X\n", wRate, byTsr0, byTsr1);
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) {
- pMgmt->sNodeDBTable[0].uTxAttempts += 1;
- if ((byTsr1 & TSR1_TERR) == 0) {
- // transmit success, TxAttempts at least plus one
- pMgmt->sNodeDBTable[0].uTxOk[MAX_RATE]++;
- if ( (byFallBack == AUTO_FB_NONE) ||
- (wRate < RATE_18M) ) {
- wFallBackRate = wRate;
- } else if (byFallBack == AUTO_FB_0) {
+ pTxBufHead = (PSTxBufHead) pbyBuffer;
+ if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_0) {
+ byFallBack = AUTO_FB_0;
+ } else if (pTxBufHead->wFIFOCtl & FIFOCTL_AUTO_FB_1) {
+ byFallBack = AUTO_FB_1;
+ } else {
+ byFallBack = AUTO_FB_NONE;
+ }
+ wRate = pTxBufHead->wReserved; //?wRate
+
+ // Only Unicast using support rates
+ if (pTxBufHead->wFIFOCtl & FIFOCTL_NEEDACK) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wRate %04X, byTsr0 %02X, byTsr1 %02X\n", wRate, byTsr0, byTsr1);
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) {
+ pMgmt->sNodeDBTable[0].uTxAttempts += 1;
+ if ((byTsr1 & TSR1_TERR) == 0) {
+ // transmit success, TxAttempts at least plus one
+ pMgmt->sNodeDBTable[0].uTxOk[MAX_RATE]++;
+ if ((byFallBack == AUTO_FB_NONE) ||
+ (wRate < RATE_18M)) {
+ wFallBackRate = wRate;
+ } else if (byFallBack == AUTO_FB_0) {
//PLICE_DEBUG
- if (byTxRetry < 5)
- //if (txRetryTemp < 5)
- wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry];
- //wFallBackRate = awHWRetry0[wRate-RATE_12M][byTxRetry];
- //wFallBackRate = awHWRetry0[wRate-RATE_18M][txRetryTemp] +1;
- else
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- //wFallBackRate = awHWRetry0[wRate-RATE_12M][4];
- } else if (byFallBack == AUTO_FB_1) {
- if (byTxRetry < 5)
- wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry];
- else
- wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- }
- pMgmt->sNodeDBTable[0].uTxOk[wFallBackRate]++;
- } else {
- pMgmt->sNodeDBTable[0].uTxFailures ++;
- }
- pMgmt->sNodeDBTable[0].uTxRetry += byTxRetry;
- if (byTxRetry != 0) {
- pMgmt->sNodeDBTable[0].uTxFail[MAX_RATE]+=byTxRetry;
- if ( (byFallBack == AUTO_FB_NONE) ||
- (wRate < RATE_18M) ) {
- pMgmt->sNodeDBTable[0].uTxFail[wRate]+=byTxRetry;
- } else if (byFallBack == AUTO_FB_0) {
+ if (byTxRetry < 5)
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry];
+ //wFallBackRate = awHWRetry0[wRate-RATE_12M][byTxRetry];
+ //wFallBackRate = awHWRetry0[wRate-RATE_18M][txRetryTemp] +1;
+ else
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
+ //wFallBackRate = awHWRetry0[wRate-RATE_12M][4];
+ } else if (byFallBack == AUTO_FB_1) {
+ if (byTxRetry < 5)
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry];
+ else
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
+ }
+ pMgmt->sNodeDBTable[0].uTxOk[wFallBackRate]++;
+ } else {
+ pMgmt->sNodeDBTable[0].uTxFailures++;
+ }
+ pMgmt->sNodeDBTable[0].uTxRetry += byTxRetry;
+ if (byTxRetry != 0) {
+ pMgmt->sNodeDBTable[0].uTxFail[MAX_RATE] += byTxRetry;
+ if ((byFallBack == AUTO_FB_NONE) ||
+ (wRate < RATE_18M)) {
+ pMgmt->sNodeDBTable[0].uTxFail[wRate] += byTxRetry;
+ } else if (byFallBack == AUTO_FB_0) {
//PLICE_DEBUG
- for(ii=0;ii<byTxRetry;ii++)
- //for (ii=0;ii<txRetryTemp;ii++)
- {
- if (ii < 5)
- {
-
+ for (ii = 0; ii < byTxRetry; ii++)
+ //for (ii=0;ii<txRetryTemp;ii++)
+ {
+ if (ii < 5) {
//PLICE_DEBUG
- wFallBackRate = awHWRetry0[wRate-RATE_18M][ii];
- //printk(" II is %d:BSSvUpdateNodeTx:wFallBackRate is %d\n",ii,wFallBackRate);
- //wFallBackRate = awHWRetry0[wRate-RATE_12M][ii];
- }
- else
- {
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- //printk("ii is %d BSSvUpdateNodeTx:wFallBackRate is %d\n",ii,wFallBackRate);
- //wFallBackRate = awHWRetry0[wRate-RATE_12M][4];
- }
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][ii];
+ //wFallBackRate = awHWRetry0[wRate-RATE_12M][ii];
+ } else {
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
+ //wFallBackRate = awHWRetry0[wRate-RATE_12M][4];
+ }
pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
- }
- } else if (byFallBack == AUTO_FB_1) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
- }
- }
- }
- }
-
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
- (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
-
- pMACHeader = (PS802_11Header)(pbyBuffer + uFIFOHeaderSize);
-
- if (BSSDBbIsSTAInNodeDB((void *)pMgmt, &(pMACHeader->abyAddr1[0]), &uNodeIndex)){
- pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts += 1;
- if ((byTsr1 & TSR1_TERR) == 0) {
- // transmit success, TxAttempts at least plus one
- pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++;
- if ( (byFallBack == AUTO_FB_NONE) ||
- (wRate < RATE_18M) ) {
- wFallBackRate = wRate;
- } else if (byFallBack == AUTO_FB_0) {
- if (byTxRetry < 5)
- wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry];
- else
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- } else if (byFallBack == AUTO_FB_1) {
- if (byTxRetry < 5)
- wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry];
- else
- wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- }
- pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wFallBackRate]++;
- } else {
- pMgmt->sNodeDBTable[uNodeIndex].uTxFailures ++;
- }
- pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += byTxRetry;
- if (byTxRetry != 0) {
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[MAX_RATE]+=byTxRetry;
- if ( (byFallBack == AUTO_FB_NONE) ||
- (wRate < RATE_18M) ) {
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wRate]+=byTxRetry;
- } else if (byFallBack == AUTO_FB_0) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry0[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
- }
- } else if (byFallBack == AUTO_FB_1) {
- for(ii=0;ii<byTxRetry;ii++) {
- if (ii < 5)
- wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
- else
- wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
- }
- }
- }
- }
- }
- }
-
- return;
+ }
+ } else if (byFallBack == AUTO_FB_1) {
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
+ else
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
+ pMgmt->sNodeDBTable[0].uTxFail[wFallBackRate]++;
+ }
+ }
+ }
+ }
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
+ (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
+ pMACHeader = (PS802_11Header)(pbyBuffer + uFIFOHeaderSize);
+
+ if (BSSDBbIsSTAInNodeDB((void *)pMgmt, &(pMACHeader->abyAddr1[0]), &uNodeIndex)) {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts += 1;
+ if ((byTsr1 & TSR1_TERR) == 0) {
+ // transmit success, TxAttempts at least plus one
+ pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++;
+ if ((byFallBack == AUTO_FB_NONE) ||
+ (wRate < RATE_18M)) {
+ wFallBackRate = wRate;
+ } else if (byFallBack == AUTO_FB_0) {
+ if (byTxRetry < 5)
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][byTxRetry];
+ else
+ wFallBackRate = awHWRetry0[wRate-RATE_18M][4];
+ } else if (byFallBack == AUTO_FB_1) {
+ if (byTxRetry < 5)
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][byTxRetry];
+ else
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
+ }
+ pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wFallBackRate]++;
+ } else {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFailures++;
+ }
+ pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += byTxRetry;
+ if (byTxRetry != 0) {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[MAX_RATE] += byTxRetry;
+ if ((byFallBack == AUTO_FB_NONE) ||
+ (wRate < RATE_18M)) {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wRate] += byTxRetry;
+ } else if (byFallBack == AUTO_FB_0) {
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate = awHWRetry0[wRate - RATE_18M][ii];
+ else
+ wFallBackRate = awHWRetry0[wRate - RATE_18M][4];
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
+ }
+ } else if (byFallBack == AUTO_FB_1) {
+ for (ii = 0; ii < byTxRetry; ii++) {
+ if (ii < 5)
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][ii];
+ else
+ wFallBackRate = awHWRetry1[wRate-RATE_18M][4];
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[wFallBackRate]++;
+ }
+ }
+ }
+ }
+ }
+ }
+ return;
}
-
-
-
/*+
*
* Routine Description:
@@ -1569,167 +1466,157 @@ BSSvUpdateNodeTxCounter(
* Return Value:
* None.
*
--*/
-
+ -*/
void
BSSvClearNodeDBTable(
- void *hDeviceContext,
- unsigned int uStartIndex
- )
+ void *hDeviceContext,
+ unsigned int uStartIndex
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- struct sk_buff *skb;
- unsigned int ii;
-
- for (ii = uStartIndex; ii < (MAX_NODE_NUM + 1); ii++) {
- if (pMgmt->sNodeDBTable[ii].bActive) {
- // check if sTxPSQueue has been initial
- if (pMgmt->sNodeDBTable[ii].sTxPSQueue.next != NULL) {
- while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS skb != NULL %d\n", ii);
- dev_kfree_skb(skb);
- }
- }
- memset(&pMgmt->sNodeDBTable[ii], 0, sizeof(KnownNodeDB));
- }
- }
-
- return;
-};
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ struct sk_buff *skb;
+ unsigned int ii;
+
+ for (ii = uStartIndex; ii < (MAX_NODE_NUM + 1); ii++) {
+ if (pMgmt->sNodeDBTable[ii].bActive) {
+ // check if sTxPSQueue has been initial
+ if (pMgmt->sNodeDBTable[ii].sTxPSQueue.next != NULL) {
+ while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS skb != NULL %d\n", ii);
+ dev_kfree_skb(skb);
+ }
+ }
+ memset(&pMgmt->sNodeDBTable[ii], 0, sizeof(KnownNodeDB));
+ }
+ }
+ return;
+};
void s_vCheckSensitivity(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PKnownBSS pBSSList = NULL;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- int ii;
-
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1) && (pDevice->byRFType == RF_RFMD2959) &&
- (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
- return;
- }
-
- if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
- ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
- pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
- if (pBSSList != NULL) {
- // Updata BB Reg if RSSI is too strong.
- long LocalldBmAverage = 0;
- long uNumofdBm = 0;
- for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
- if (pBSSList->ldBmAverage[ii] != 0) {
- uNumofdBm ++;
- LocalldBmAverage += pBSSList->ldBmAverage[ii];
- }
- }
- if (uNumofdBm > 0) {
- LocalldBmAverage = LocalldBmAverage/uNumofdBm;
- for (ii=0;ii<BB_VGA_LEVEL;ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LocalldBmAverage:%ld, %ld %02x\n", LocalldBmAverage, pDevice->ldBmThreshold[ii], pDevice->abyBBVGA[ii]);
- if (LocalldBmAverage < pDevice->ldBmThreshold[ii]) {
- pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
- break;
- }
- }
- if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
- pDevice->uBBVGADiffCount++;
- if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD)
- bScheduleCommand((void *) pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL);
- } else {
- pDevice->uBBVGADiffCount = 0;
- }
- }
- }
- }
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PKnownBSS pBSSList = NULL;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ int ii;
+
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1) && (pDevice->byRFType == RF_RFMD2959) &&
+ (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
+ return;
+ }
+
+ if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
+ ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
+ pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
+ if (pBSSList != NULL) {
+ // Updata BB Reg if RSSI is too strong.
+ long LocalldBmAverage = 0;
+ long uNumofdBm = 0;
+ for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
+ if (pBSSList->ldBmAverage[ii] != 0) {
+ uNumofdBm++;
+ LocalldBmAverage += pBSSList->ldBmAverage[ii];
+ }
+ }
+ if (uNumofdBm > 0) {
+ LocalldBmAverage = LocalldBmAverage/uNumofdBm;
+ for (ii = 0; ii < BB_VGA_LEVEL; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "LocalldBmAverage:%ld, %ld %02x\n", LocalldBmAverage, pDevice->ldBmThreshold[ii], pDevice->abyBBVGA[ii]);
+ if (LocalldBmAverage < pDevice->ldBmThreshold[ii]) {
+ pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
+ break;
+ }
+ }
+ if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
+ pDevice->uBBVGADiffCount++;
+ if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD)
+ bScheduleCommand((void *)pDevice, WLAN_CMD_CHANGE_BBSENSITIVITY, NULL);
+ } else {
+ pDevice->uBBVGADiffCount = 0;
+ }
+ }
+ }
+ }
}
-
void
-BSSvClearAnyBSSJoinRecord (
- void *hDeviceContext
- )
+BSSvClearAnyBSSJoinRecord(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int ii;
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pMgmt->sBSSList[ii].bSelected = false;
- }
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int ii;
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pMgmt->sBSSList[ii].bSelected = false;
+ }
+ return;
}
#ifdef Calcu_LinkQual
void s_uCalculateLinkQual(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- unsigned long TxOkRatio, TxCnt;
- unsigned long RxOkRatio,RxCnt;
- unsigned long RssiRatio;
- long ldBm;
-
-TxCnt = pDevice->scStatistic.TxNoRetryOkCount +
- pDevice->scStatistic.TxRetryOkCount +
- pDevice->scStatistic.TxFailCount;
-RxCnt = pDevice->scStatistic.RxFcsErrCnt +
- pDevice->scStatistic.RxOkCnt;
-TxOkRatio = (TxCnt < 6) ? 4000:((pDevice->scStatistic.TxNoRetryOkCount * 4000) / TxCnt);
-RxOkRatio = (RxCnt < 6) ? 2000:((pDevice->scStatistic.RxOkCnt * 2000) / RxCnt);
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ unsigned long TxOkRatio, TxCnt;
+ unsigned long RxOkRatio, RxCnt;
+ unsigned long RssiRatio;
+ long ldBm;
+
+ TxCnt = pDevice->scStatistic.TxNoRetryOkCount +
+ pDevice->scStatistic.TxRetryOkCount +
+ pDevice->scStatistic.TxFailCount;
+ RxCnt = pDevice->scStatistic.RxFcsErrCnt +
+ pDevice->scStatistic.RxOkCnt;
+ TxOkRatio = (TxCnt < 6) ? 4000 : ((pDevice->scStatistic.TxNoRetryOkCount * 4000) / TxCnt);
+ RxOkRatio = (RxCnt < 6) ? 2000 : ((pDevice->scStatistic.RxOkCnt * 2000) / RxCnt);
//decide link quality
-if(pDevice->bLinkPass !=true)
-{
- // printk("s_uCalculateLinkQual-->Link disconnect and Poor quality**\n");
- pDevice->scStatistic.LinkQuality = 0;
- pDevice->scStatistic.SignalStren = 0;
-}
-else
-{
- RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
- if(-ldBm < 50) {
- RssiRatio = 4000;
- }
- else if(-ldBm > 90) {
- RssiRatio = 0;
- }
- else {
- RssiRatio = (40-(-ldBm-50))*4000/40;
- }
- pDevice->scStatistic.SignalStren = RssiRatio/40;
- pDevice->scStatistic.LinkQuality = (RssiRatio+TxOkRatio+RxOkRatio)/100;
-}
- pDevice->scStatistic.RxFcsErrCnt = 0;
- pDevice->scStatistic.RxOkCnt = 0;
- pDevice->scStatistic.TxFailCount = 0;
- pDevice->scStatistic.TxNoRetryOkCount = 0;
- pDevice->scStatistic.TxRetryOkCount = 0;
- return;
+ if (pDevice->bLinkPass != true) {
+ pDevice->scStatistic.LinkQuality = 0;
+ pDevice->scStatistic.SignalStren = 0;
+ } else {
+ RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
+ if (-ldBm < 50) {
+ RssiRatio = 4000;
+ } else if (-ldBm > 90) {
+ RssiRatio = 0;
+ } else {
+ RssiRatio = (40-(-ldBm-50))*4000/40;
+ }
+ pDevice->scStatistic.SignalStren = RssiRatio/40;
+ pDevice->scStatistic.LinkQuality = (RssiRatio+TxOkRatio+RxOkRatio)/100;
+ }
+ pDevice->scStatistic.RxFcsErrCnt = 0;
+ pDevice->scStatistic.RxOkCnt = 0;
+ pDevice->scStatistic.TxFailCount = 0;
+ pDevice->scStatistic.TxNoRetryOkCount = 0;
+ pDevice->scStatistic.TxRetryOkCount = 0;
+ return;
}
#endif
void s_vCheckPreEDThreshold(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PKnownBSS pBSSList = NULL;
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-
- if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
- ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
- pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
- if (pBSSList != NULL) {
- pDevice->byBBPreEDRSSI = (unsigned char) (~(pBSSList->ldBmAverRange) + 1);
- //BBvUpdatePreEDThreshold(pDevice, false);
- }
- }
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PKnownBSS pBSSList = NULL;
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+
+ if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
+ ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
+ pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
+ if (pBSSList != NULL) {
+ pDevice->byBBPreEDRSSI = (unsigned char) (~(pBSSList->ldBmAverRange) + 1);
+ //BBvUpdatePreEDThreshold(pDevice, false);
+ }
+ }
+ return;
}
-
diff --git a/drivers/staging/vt6655/bssdb.h b/drivers/staging/vt6655/bssdb.h
index 0af421186122..5c77677251ed 100644
--- a/drivers/staging/vt6655/bssdb.h
+++ b/drivers/staging/vt6655/bssdb.h
@@ -39,7 +39,7 @@
#define MAX_NODE_NUM 64
#define MAX_BSS_NUM 42
-#define LOST_BEACON_COUNT 10 // 10 sec, XP defined
+#define LOST_BEACON_COUNT 10 // 10 sec, XP defined
#define MAX_PS_TX_BUF 32 // sta max power saving tx buf
#define ADHOC_LOST_BEACON_COUNT 30 // 30 sec, beacon lost for adhoc only
#define MAX_INACTIVE_COUNT 300 // 300 sec, inactive STA node refresh
@@ -67,12 +67,10 @@
#define MAX_WPA_IE_LEN 64
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
//
@@ -81,285 +79,272 @@
typedef enum _NDIS_802_11_NETWORK_TYPE
{
- Ndis802_11FH,
- Ndis802_11DS,
- Ndis802_11OFDM5,
- Ndis802_11OFDM24,
- Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
+ Ndis802_11FH,
+ Ndis802_11DS,
+ Ndis802_11OFDM5,
+ Ndis802_11OFDM24,
+ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
typedef struct tagSERPObject {
- bool bERPExist;
- unsigned char byERP;
-}ERPObject, *PERPObject;
-
+ bool bERPExist;
+ unsigned char byERP;
+} ERPObject, *PERPObject;
typedef struct tagSRSNCapObject {
- bool bRSNCapExist;
- unsigned short wRSNCap;
-}SRSNCapObject, *PSRSNCapObject;
+ bool bRSNCapExist;
+ unsigned short wRSNCap;
+} SRSNCapObject, *PSRSNCapObject;
// BSS info(AP)
#pragma pack(1)
typedef struct tagKnownBSS {
- // BSS info
- bool bActive;
- unsigned char abyBSSID[WLAN_BSSID_LEN];
- unsigned int uChannel;
- unsigned char abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned int uRSSI;
- unsigned char bySQ;
- unsigned short wBeaconInterval;
- unsigned short wCapInfo;
- unsigned char abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned char byRxRate;
+ // BSS info
+ bool bActive;
+ unsigned char abyBSSID[WLAN_BSSID_LEN];
+ unsigned int uChannel;
+ unsigned char abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned int uRSSI;
+ unsigned char bySQ;
+ unsigned short wBeaconInterval;
+ unsigned short wCapInfo;
+ unsigned char abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char byRxRate;
// unsigned short wATIMWindow;
- unsigned char byRSSIStatCnt;
- long ldBmMAX;
- long ldBmAverage[RSSI_STAT_COUNT];
- long ldBmAverRange;
- //For any BSSID selection improvment
- bool bSelected;
-
- //++ WPA informations
- bool bWPAValid;
- unsigned char byGKType;
- unsigned char abyPKType[4];
- unsigned short wPKCount;
- unsigned char abyAuthType[4];
- unsigned short wAuthCount;
- unsigned char byDefaultK_as_PK;
- unsigned char byReplayIdx;
- //--
-
- //++ WPA2 informations
- bool bWPA2Valid;
- unsigned char byCSSGK;
- unsigned short wCSSPKCount;
- unsigned char abyCSSPK[4];
- unsigned short wAKMSSAuthCount;
- unsigned char abyAKMSSAuthType[4];
-
- //++ wpactl
- unsigned char byWPAIE[MAX_WPA_IE_LEN];
- unsigned char byRSNIE[MAX_WPA_IE_LEN];
- unsigned short wWPALen;
- unsigned short wRSNLen;
-
- // Clear count
- unsigned int uClearCount;
+ unsigned char byRSSIStatCnt;
+ long ldBmMAX;
+ long ldBmAverage[RSSI_STAT_COUNT];
+ long ldBmAverRange;
+ //For any BSSID selection improvment
+ bool bSelected;
+
+ //++ WPA informations
+ bool bWPAValid;
+ unsigned char byGKType;
+ unsigned char abyPKType[4];
+ unsigned short wPKCount;
+ unsigned char abyAuthType[4];
+ unsigned short wAuthCount;
+ unsigned char byDefaultK_as_PK;
+ unsigned char byReplayIdx;
+ //--
+
+ //++ WPA2 informations
+ bool bWPA2Valid;
+ unsigned char byCSSGK;
+ unsigned short wCSSPKCount;
+ unsigned char abyCSSPK[4];
+ unsigned short wAKMSSAuthCount;
+ unsigned char abyAKMSSAuthType[4];
+
+ //++ wpactl
+ unsigned char byWPAIE[MAX_WPA_IE_LEN];
+ unsigned char byRSNIE[MAX_WPA_IE_LEN];
+ unsigned short wWPALen;
+ unsigned short wRSNLen;
+
+ // Clear count
+ unsigned int uClearCount;
// unsigned char abyIEs[WLAN_BEACON_FR_MAXLEN];
- unsigned int uIELength;
- QWORD qwBSSTimestamp;
- QWORD qwLocalTSF; // local TSF timer
+ unsigned int uIELength;
+ QWORD qwBSSTimestamp;
+ QWORD qwLocalTSF; // local TSF timer
// NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
- CARD_PHY_TYPE eNetworkTypeInUse;
+ CARD_PHY_TYPE eNetworkTypeInUse;
- ERPObject sERP;
- SRSNCapObject sRSNCapObj;
- unsigned char abyIEs[1024]; // don't move this field !!
-
-}__attribute__ ((__packed__))
+ ERPObject sERP;
+ SRSNCapObject sRSNCapObj;
+ unsigned char abyIEs[1024]; // don't move this field !!
+} __attribute__ ((__packed__))
KnownBSS , *PKnownBSS;
//2006-1116-01,<Add> by NomadZhao
#pragma pack()
typedef enum tagNODE_STATE {
- NODE_FREE,
- NODE_AGED,
- NODE_KNOWN,
- NODE_AUTH,
- NODE_ASSOC
+ NODE_FREE,
+ NODE_AGED,
+ NODE_KNOWN,
+ NODE_AUTH,
+ NODE_ASSOC
} NODE_STATE, *PNODE_STATE;
-
// STA node info
typedef struct tagKnownNodeDB {
- // STA info
- bool bActive;
- unsigned char abyMACAddr[WLAN_ADDR_LEN];
- unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- unsigned short wTxDataRate;
- bool bShortPreamble;
- bool bERPExist;
- bool bShortSlotTime;
- unsigned int uInActiveCount;
- unsigned short wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
- unsigned short wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
- unsigned short wSuppRate;
- unsigned char byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
- unsigned char byTopCCKBasicRate; //Records the highest basic rate in CCK mode
-
- // For AP mode
- struct sk_buff_head sTxPSQueue;
- unsigned short wCapInfo;
- unsigned short wListenInterval;
- unsigned short wAID;
- NODE_STATE eNodeState;
- bool bPSEnable;
- bool bRxPSPoll;
- unsigned char byAuthSequence;
- unsigned long ulLastRxJiffer;
- unsigned char bySuppRate;
- unsigned long dwFlags;
- unsigned short wEnQueueCnt;
-
- bool bOnFly;
- unsigned long long KeyRSC;
- unsigned char byKeyIndex;
- unsigned long dwKeyIndex;
- unsigned char byCipherSuite;
- unsigned long dwTSC47_16;
- unsigned short wTSC15_0;
- unsigned int uWepKeyLength;
- unsigned char abyWepKey[WLAN_WEPMAX_KEYLEN];
- //
- // Auto rate fallback vars
- bool bIsInFallback;
- unsigned int uAverageRSSI;
- unsigned int uRateRecoveryTimeout;
- unsigned int uRatePollTimeout;
- unsigned int uTxFailures;
- unsigned int uTxAttempts;
-
- unsigned int uTxRetry;
- unsigned int uFailureRatio;
- unsigned int uRetryRatio;
- unsigned int uTxOk[MAX_RATE+1];
- unsigned int uTxFail[MAX_RATE+1];
- unsigned int uTimeCount;
-
+ // STA info
+ bool bActive;
+ unsigned char abyMACAddr[WLAN_ADDR_LEN];
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ unsigned short wTxDataRate;
+ bool bShortPreamble;
+ bool bERPExist;
+ bool bShortSlotTime;
+ unsigned int uInActiveCount;
+ unsigned short wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
+ unsigned short wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
+ unsigned short wSuppRate;
+ unsigned char byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
+ unsigned char byTopCCKBasicRate; //Records the highest basic rate in CCK mode
+
+ // For AP mode
+ struct sk_buff_head sTxPSQueue;
+ unsigned short wCapInfo;
+ unsigned short wListenInterval;
+ unsigned short wAID;
+ NODE_STATE eNodeState;
+ bool bPSEnable;
+ bool bRxPSPoll;
+ unsigned char byAuthSequence;
+ unsigned long ulLastRxJiffer;
+ unsigned char bySuppRate;
+ unsigned long dwFlags;
+ unsigned short wEnQueueCnt;
+
+ bool bOnFly;
+ unsigned long long KeyRSC;
+ unsigned char byKeyIndex;
+ unsigned long dwKeyIndex;
+ unsigned char byCipherSuite;
+ unsigned long dwTSC47_16;
+ unsigned short wTSC15_0;
+ unsigned int uWepKeyLength;
+ unsigned char abyWepKey[WLAN_WEPMAX_KEYLEN];
+ //
+ // Auto rate fallback vars
+ bool bIsInFallback;
+ unsigned int uAverageRSSI;
+ unsigned int uRateRecoveryTimeout;
+ unsigned int uRatePollTimeout;
+ unsigned int uTxFailures;
+ unsigned int uTxAttempts;
+
+ unsigned int uTxRetry;
+ unsigned int uFailureRatio;
+ unsigned int uRetryRatio;
+ unsigned int uTxOk[MAX_RATE+1];
+ unsigned int uTxFail[MAX_RATE+1];
+ unsigned int uTimeCount;
} KnownNodeDB, *PKnownNodeDB;
-
/*--------------------- Export Functions --------------------------*/
-
-
PKnownBSS
BSSpSearchBSSList(
- void *hDeviceContext,
- unsigned char *pbyDesireBSSID,
- unsigned char *pbyDesireSSID,
- CARD_PHY_TYPE ePhyType
- );
+ void *hDeviceContext,
+ unsigned char *pbyDesireBSSID,
+ unsigned char *pbyDesireSSID,
+ CARD_PHY_TYPE ePhyType
+);
PKnownBSS
BSSpAddrIsInBSSList(
- void *hDeviceContext,
- unsigned char *abyBSSID,
- PWLAN_IE_SSID pSSID
- );
+ void *hDeviceContext,
+ unsigned char *abyBSSID,
+ PWLAN_IE_SSID pSSID
+);
void
BSSvClearBSSList(
- void *hDeviceContext,
- bool bKeepCurrBSSID
- );
+ void *hDeviceContext,
+ bool bKeepCurrBSSID
+);
bool
BSSbInsertToBSSList(
- void *hDeviceContext,
- unsigned char *abyBSSIDAddr,
- QWORD qwTimestamp,
- unsigned short wBeaconInterval,
- unsigned short wCapInfo,
- unsigned char byCurrChannel,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pSuppRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates,
- PERPObject psERP,
- PWLAN_IE_RSN pRSN,
- PWLAN_IE_RSN_EXT pRSNWPA,
- PWLAN_IE_COUNTRY pIE_Country,
- PWLAN_IE_QUIET pIE_Quiet,
- unsigned int uIELength,
- unsigned char *pbyIEs,
- void *pRxPacketContext
- );
-
+ void *hDeviceContext,
+ unsigned char *abyBSSIDAddr,
+ QWORD qwTimestamp,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pSuppRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates,
+ PERPObject psERP,
+ PWLAN_IE_RSN pRSN,
+ PWLAN_IE_RSN_EXT pRSNWPA,
+ PWLAN_IE_COUNTRY pIE_Country,
+ PWLAN_IE_QUIET pIE_Quiet,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
+ void *pRxPacketContext
+);
bool
BSSbUpdateToBSSList(
- void *hDeviceContext,
- QWORD qwTimestamp,
- unsigned short wBeaconInterval,
- unsigned short wCapInfo,
- unsigned char byCurrChannel,
- bool bChannelHit,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pSuppRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates,
- PERPObject psERP,
- PWLAN_IE_RSN pRSN,
- PWLAN_IE_RSN_EXT pRSNWPA,
- PWLAN_IE_COUNTRY pIE_Country,
- PWLAN_IE_QUIET pIE_Quiet,
- PKnownBSS pBSSList,
- unsigned int uIELength,
- unsigned char *pbyIEs,
- void *pRxPacketContext
- );
-
+ void *hDeviceContext,
+ QWORD qwTimestamp,
+ unsigned short wBeaconInterval,
+ unsigned short wCapInfo,
+ unsigned char byCurrChannel,
+ bool bChannelHit,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pSuppRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates,
+ PERPObject psERP,
+ PWLAN_IE_RSN pRSN,
+ PWLAN_IE_RSN_EXT pRSNWPA,
+ PWLAN_IE_COUNTRY pIE_Country,
+ PWLAN_IE_QUIET pIE_Quiet,
+ PKnownBSS pBSSList,
+ unsigned int uIELength,
+ unsigned char *pbyIEs,
+ void *pRxPacketContext
+);
bool
BSSDBbIsSTAInNodeDB(void *hDeviceContext, unsigned char *abyDstAddr,
- unsigned int *puNodeIndex);
+ unsigned int *puNodeIndex);
void
BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex);
void
BSSvUpdateAPNode(
- void *hDeviceContext,
- unsigned short *pwCapInfo,
- PWLAN_IE_SUPP_RATES pItemRates,
- PWLAN_IE_SUPP_RATES pExtSuppRates
- );
-
+ void *hDeviceContext,
+ unsigned short *pwCapInfo,
+ PWLAN_IE_SUPP_RATES pItemRates,
+ PWLAN_IE_SUPP_RATES pExtSuppRates
+);
void
BSSvSecondCallBack(
- void *hDeviceContext
- );
-
+ void *hDeviceContext
+);
void
BSSvUpdateNodeTxCounter(
- void *hDeviceContext,
- unsigned char byTsr0,
- unsigned char byTsr1,
- unsigned char *pbyBuffer,
- unsigned int uFIFOHeaderSize
- );
+ void *hDeviceContext,
+ unsigned char byTsr0,
+ unsigned char byTsr1,
+ unsigned char *pbyBuffer,
+ unsigned int uFIFOHeaderSize
+);
void
BSSvRemoveOneNode(
- void *hDeviceContext,
- unsigned int uNodeIndex
- );
+ void *hDeviceContext,
+ unsigned int uNodeIndex
+);
void
BSSvAddMulticastNode(
- void *hDeviceContext
- );
-
+ void *hDeviceContext
+);
void
BSSvClearNodeDBTable(
- void *hDeviceContext,
- unsigned int uStartIndex
- );
+ void *hDeviceContext,
+ unsigned int uStartIndex
+);
void
BSSvClearAnyBSSJoinRecord(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
#endif //__BSSDB_H__
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 319ca482f003..fbf18e23e78e 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -61,14 +61,13 @@
/*--------------------- Static Definitions -------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
#define C_SIFS_A 16 // micro sec.
#define C_SIFS_BG 10
#define C_EIFS 80 // micro sec.
-
#define C_SLOT_SHORT 9 // micro sec.
#define C_SLOT_LONG 20
@@ -79,34 +78,30 @@ static int msglevel =MSG_LEVEL_INFO;
#define WAIT_BEACON_TX_DOWN_TMO 3 // Times
- //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
+//1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
static unsigned char abyDefaultSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
- //6M, 9M, 12M, 48M
+//6M, 9M, 12M, 48M
static unsigned char abyDefaultExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
- //6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M
+//6M, 9M, 12M, 18M, 24M, 36M, 48M, 54M
static unsigned char abyDefaultSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- //1M, 2M, 5M, 11M,
+//1M, 2M, 5M, 11M,
static unsigned char abyDefaultSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
-
/*--------------------- Static Variables --------------------------*/
-
const unsigned short cwRXBCNTSFOff[MAX_RATE] =
{17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
-
/*--------------------- Static Functions --------------------------*/
static
void
s_vCalculateOFDMRParameter(
- unsigned char byRate,
- CARD_PHY_TYPE ePHYType,
- unsigned char *pbyTxRate,
- unsigned char *pbyRsvTime
- );
-
+ unsigned char byRate,
+ CARD_PHY_TYPE ePHYType,
+ unsigned char *pbyTxRate,
+ unsigned char *pbyRsvTime
+);
/*--------------------- Export Functions --------------------------*/
@@ -126,107 +121,97 @@ s_vCalculateOFDMRParameter(
*/
static
void
-s_vCalculateOFDMRParameter (
- unsigned char byRate,
- CARD_PHY_TYPE ePHYType,
- unsigned char *pbyTxRate,
- unsigned char *pbyRsvTime
- )
+s_vCalculateOFDMRParameter(
+ unsigned char byRate,
+ CARD_PHY_TYPE ePHYType,
+ unsigned char *pbyTxRate,
+ unsigned char *pbyRsvTime
+)
{
- switch (byRate) {
- case RATE_6M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9B;
- *pbyRsvTime = 44;
- }
- else {
- *pbyTxRate = 0x8B;
- *pbyRsvTime = 50;
- }
- break;
-
- case RATE_9M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9F;
- *pbyRsvTime = 36;
- }
- else {
- *pbyTxRate = 0x8F;
- *pbyRsvTime = 42;
- }
- break;
-
- case RATE_12M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9A;
- *pbyRsvTime = 32;
- }
- else {
- *pbyTxRate = 0x8A;
- *pbyRsvTime = 38;
- }
- break;
-
- case RATE_18M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9E;
- *pbyRsvTime = 28;
- }
- else {
- *pbyTxRate = 0x8E;
- *pbyRsvTime = 34;
- }
- break;
-
- case RATE_36M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9D;
- *pbyRsvTime = 24;
- }
- else {
- *pbyTxRate = 0x8D;
- *pbyRsvTime = 30;
- }
- break;
-
- case RATE_48M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x98;
- *pbyRsvTime = 24;
- }
- else {
- *pbyTxRate = 0x88;
- *pbyRsvTime = 30;
- }
- break;
-
- case RATE_54M :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x9C;
- *pbyRsvTime = 24;
- }
- else {
- *pbyTxRate = 0x8C;
- *pbyRsvTime = 30;
- }
- break;
-
- case RATE_24M :
- default :
- if (ePHYType == PHY_TYPE_11A) {//5GHZ
- *pbyTxRate = 0x99;
- *pbyRsvTime = 28;
- }
- else {
- *pbyTxRate = 0x89;
- *pbyRsvTime = 34;
- }
- break;
- }
+ switch (byRate) {
+ case RATE_6M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9B;
+ *pbyRsvTime = 44;
+ } else {
+ *pbyTxRate = 0x8B;
+ *pbyRsvTime = 50;
+ }
+ break;
+
+ case RATE_9M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9F;
+ *pbyRsvTime = 36;
+ } else {
+ *pbyTxRate = 0x8F;
+ *pbyRsvTime = 42;
+ }
+ break;
+
+ case RATE_12M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9A;
+ *pbyRsvTime = 32;
+ } else {
+ *pbyTxRate = 0x8A;
+ *pbyRsvTime = 38;
+ }
+ break;
+
+ case RATE_18M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9E;
+ *pbyRsvTime = 28;
+ } else {
+ *pbyTxRate = 0x8E;
+ *pbyRsvTime = 34;
+ }
+ break;
+
+ case RATE_36M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9D;
+ *pbyRsvTime = 24;
+ } else {
+ *pbyTxRate = 0x8D;
+ *pbyRsvTime = 30;
+ }
+ break;
+
+ case RATE_48M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x98;
+ *pbyRsvTime = 24;
+ } else {
+ *pbyTxRate = 0x88;
+ *pbyRsvTime = 30;
+ }
+ break;
+
+ case RATE_54M:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x9C;
+ *pbyRsvTime = 24;
+ } else {
+ *pbyTxRate = 0x8C;
+ *pbyRsvTime = 30;
+ }
+ break;
+
+ case RATE_24M:
+ default:
+ if (ePHYType == PHY_TYPE_11A) {//5GHZ
+ *pbyTxRate = 0x99;
+ *pbyRsvTime = 28;
+ } else {
+ *pbyTxRate = 0x89;
+ *pbyRsvTime = 34;
+ }
+ break;
+ }
}
-
-
/*
* Description: Set RSPINF
*
@@ -241,114 +226,114 @@ s_vCalculateOFDMRParameter (
*/
static
void
-s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
+s_vSetRSPINF(PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
{
- unsigned char byServ = 0, bySignal = 0; // For CCK
- unsigned short wLen = 0;
- unsigned char byTxRate = 0, byRsvTime = 0; // For OFDM
-
- //Set to Page1
- MACvSelectPage1(pDevice->PortOffset);
-
- //RSPINF_b_1
- BBvCalculateParameter(pDevice,
- 14,
- VNTWIFIbyGetACKTxRate(RATE_1M, pvSupportRateIEs, pvExtSupportRateIEs),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- ///RSPINF_b_2
- BBvCalculateParameter(pDevice,
- 14,
- VNTWIFIbyGetACKTxRate(RATE_2M, pvSupportRateIEs, pvExtSupportRateIEs),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_b_5
- BBvCalculateParameter(pDevice,
- 14,
- VNTWIFIbyGetACKTxRate(RATE_5M, pvSupportRateIEs, pvExtSupportRateIEs),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_b_11
- BBvCalculateParameter(pDevice,
- 14,
- VNTWIFIbyGetACKTxRate(RATE_11M, pvSupportRateIEs, pvExtSupportRateIEs),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_a_6
- s_vCalculateOFDMRParameter(RATE_6M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_9
- s_vCalculateOFDMRParameter(RATE_9M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_12
- s_vCalculateOFDMRParameter(RATE_12M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_18
- s_vCalculateOFDMRParameter(RATE_18M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_24
- s_vCalculateOFDMRParameter(RATE_24M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_36
- s_vCalculateOFDMRParameter(
- VNTWIFIbyGetACKTxRate(RATE_36M, pvSupportRateIEs, pvExtSupportRateIEs),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_48
- s_vCalculateOFDMRParameter(
- VNTWIFIbyGetACKTxRate(RATE_48M, pvSupportRateIEs, pvExtSupportRateIEs),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_54
- s_vCalculateOFDMRParameter(
- VNTWIFIbyGetACKTxRate(RATE_54M, pvSupportRateIEs, pvExtSupportRateIEs),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_72
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate,byRsvTime));
- //Set to Page0
- MACvSelectPage0(pDevice->PortOffset);
+ unsigned char byServ = 0, bySignal = 0; // For CCK
+ unsigned short wLen = 0;
+ unsigned char byTxRate = 0, byRsvTime = 0; // For OFDM
+
+ //Set to Page1
+ MACvSelectPage1(pDevice->PortOffset);
+
+ //RSPINF_b_1
+ BBvCalculateParameter(pDevice,
+ 14,
+ VNTWIFIbyGetACKTxRate(RATE_1M, pvSupportRateIEs, pvExtSupportRateIEs),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ ///RSPINF_b_2
+ BBvCalculateParameter(pDevice,
+ 14,
+ VNTWIFIbyGetACKTxRate(RATE_2M, pvSupportRateIEs, pvExtSupportRateIEs),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_b_5
+ BBvCalculateParameter(pDevice,
+ 14,
+ VNTWIFIbyGetACKTxRate(RATE_5M, pvSupportRateIEs, pvExtSupportRateIEs),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_b_11
+ BBvCalculateParameter(pDevice,
+ 14,
+ VNTWIFIbyGetACKTxRate(RATE_11M, pvSupportRateIEs, pvExtSupportRateIEs),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_a_6
+ s_vCalculateOFDMRParameter(RATE_6M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_9
+ s_vCalculateOFDMRParameter(RATE_9M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_12
+ s_vCalculateOFDMRParameter(RATE_12M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_18
+ s_vCalculateOFDMRParameter(RATE_18M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_24
+ s_vCalculateOFDMRParameter(RATE_24M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_36
+ s_vCalculateOFDMRParameter(
+ VNTWIFIbyGetACKTxRate(RATE_36M, pvSupportRateIEs, pvExtSupportRateIEs),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_48
+ s_vCalculateOFDMRParameter(
+ VNTWIFIbyGetACKTxRate(RATE_48M, pvSupportRateIEs, pvExtSupportRateIEs),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_54
+ s_vCalculateOFDMRParameter(
+ VNTWIFIbyGetACKTxRate(RATE_54M, pvSupportRateIEs, pvExtSupportRateIEs),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_72
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate, byRsvTime));
+ //Set to Page0
+ MACvSelectPage0(pDevice->PortOffset);
}
/*--------------------- Export Functions --------------------------*/
@@ -369,22 +354,20 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs,
*
*/
/*
-bool CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, unsigned int uLength)
-{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- if (ePktType == PKT_TYPE_802_11_MNG) {
- return TXbTD0Send(pDevice, pPacket, uLength);
- } else if (ePktType == PKT_TYPE_802_11_BCN) {
- return TXbBeaconSend(pDevice, pPacket, uLength);
- } if (ePktType == PKT_TYPE_802_11_DATA) {
- return TXbTD1Send(pDevice, pPacket, uLength);
- }
-
- return (true);
-}
+ bool CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktType, unsigned int uLength) {
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ if (ePktType == PKT_TYPE_802_11_MNG) {
+ return TXbTD0Send(pDevice, pPacket, uLength);
+ } else if (ePktType == PKT_TYPE_802_11_BCN) {
+ return TXbBeaconSend(pDevice, pPacket, uLength);
+ } if (ePktType == PKT_TYPE_802_11_DATA) {
+ return TXbTD1Send(pDevice, pPacket, uLength);
+ }
+
+ return true;
+ }
*/
-
/*
* Description: Get Card short preamble option value
*
@@ -397,13 +380,13 @@ bool CARDbSendPacket (void *pDeviceHandler, void *pPacket, CARD_PKT_TYPE ePktTyp
* Return Value: true if short preamble; otherwise false
*
*/
-bool CARDbIsShortPreamble (void *pDeviceHandler)
+bool CARDbIsShortPreamble(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- if (pDevice->byPreambleType == 0) {
- return(false);
- }
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ if (pDevice->byPreambleType == 0) {
+ return false;
+ }
+ return true;
}
/*
@@ -418,13 +401,12 @@ bool CARDbIsShortPreamble (void *pDeviceHandler)
* Return Value: true if short slot time; otherwise false
*
*/
-bool CARDbIsShorSlotTime (void *pDeviceHandler)
+bool CARDbIsShorSlotTime(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- return(pDevice->bShortSlotTime);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ return pDevice->bShortSlotTime;
}
-
/*
* Description: Update IFS
*
@@ -437,175 +419,174 @@ bool CARDbIsShorSlotTime (void *pDeviceHandler)
* Return Value: None.
*
*/
-bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigned short wCapInfo, unsigned char byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
+bool CARDbSetPhyParameter(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigned short wCapInfo, unsigned char byERPField, void *pvSupportRateIEs, void *pvExtSupportRateIEs)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned char byCWMaxMin = 0;
- unsigned char bySlot = 0;
- unsigned char bySIFS = 0;
- unsigned char byDIFS = 0;
- unsigned char byData;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned char byCWMaxMin = 0;
+ unsigned char bySlot = 0;
+ unsigned char bySIFS = 0;
+ unsigned char byDIFS = 0;
+ unsigned char byData;
// PWLAN_IE_SUPP_RATES pRates = NULL;
- PWLAN_IE_SUPP_RATES pSupportRates = (PWLAN_IE_SUPP_RATES) pvSupportRateIEs;
- PWLAN_IE_SUPP_RATES pExtSupportRates = (PWLAN_IE_SUPP_RATES) pvExtSupportRateIEs;
-
-
- //Set SIFS, DIFS, EIFS, SlotTime, CwMin
- if (ePHYType == PHY_TYPE_11A) {
- if (pSupportRates == NULL) {
- pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesA;
- }
- if (pDevice->byRFType == RF_AIROHA7230) {
- // AL7230 use single PAPE and connect to PAPE_2.4G
- MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G);
- pDevice->abyBBVGA[0] = 0x20;
- pDevice->abyBBVGA[2] = 0x10;
- pDevice->abyBBVGA[3] = 0x10;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x1C) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- }
- } else if (pDevice->byRFType == RF_UW2452) {
- MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
- pDevice->abyBBVGA[0] = 0x18;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x14) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0x57);
- }
- } else {
- MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
- }
- BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x03);
- bySlot = C_SLOT_SHORT;
- bySIFS = C_SIFS_A;
- byDIFS = C_SIFS_A + 2*C_SLOT_SHORT;
- byCWMaxMin = 0xA4;
- } else if (ePHYType == PHY_TYPE_11B) {
- if (pSupportRates == NULL) {
- pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesB;
- }
- MACvSetBBType(pDevice->PortOffset, BB_TYPE_11B);
- if (pDevice->byRFType == RF_AIROHA7230) {
- pDevice->abyBBVGA[0] = 0x1C;
- pDevice->abyBBVGA[2] = 0x00;
- pDevice->abyBBVGA[3] = 0x00;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x20) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- }
- } else if (pDevice->byRFType == RF_UW2452) {
- pDevice->abyBBVGA[0] = 0x14;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x18) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
- }
- }
- BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x02);
- bySlot = C_SLOT_LONG;
- bySIFS = C_SIFS_BG;
- byDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
- byCWMaxMin = 0xA5;
- } else {// PK_TYPE_11GA & PK_TYPE_11GB
- if (pSupportRates == NULL) {
- pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesG;
- pExtSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultExtSuppRatesG;
- }
- MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G);
- if (pDevice->byRFType == RF_AIROHA7230) {
- pDevice->abyBBVGA[0] = 0x1C;
- pDevice->abyBBVGA[2] = 0x00;
- pDevice->abyBBVGA[3] = 0x00;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x20) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- }
- } else if (pDevice->byRFType == RF_UW2452) {
- pDevice->abyBBVGA[0] = 0x14;
- BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
- if (byData == 0x18) {
- BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
- BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
- }
- }
- BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x08);
- bySIFS = C_SIFS_BG;
- if(VNTWIFIbIsShortSlotTime(wCapInfo)) {
- bySlot = C_SLOT_SHORT;
- byDIFS = C_SIFS_BG + 2*C_SLOT_SHORT;
- } else {
- bySlot = C_SLOT_LONG;
- byDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
- }
- if (VNTWIFIbyGetMaxSupportRate(pSupportRates, pExtSupportRates) > RATE_11M) {
- byCWMaxMin = 0xA4;
- } else {
- byCWMaxMin = 0xA5;
- }
- if (pDevice->bProtectMode != VNTWIFIbIsProtectMode(byERPField)) {
- pDevice->bProtectMode = VNTWIFIbIsProtectMode(byERPField);
- if (pDevice->bProtectMode) {
- MACvEnableProtectMD(pDevice->PortOffset);
- } else {
- MACvDisableProtectMD(pDevice->PortOffset);
- }
- }
- if (pDevice->bBarkerPreambleMd != VNTWIFIbIsBarkerMode(byERPField)) {
- pDevice->bBarkerPreambleMd = VNTWIFIbIsBarkerMode(byERPField);
- if (pDevice->bBarkerPreambleMd) {
- MACvEnableBarkerPreambleMd(pDevice->PortOffset);
- } else {
- MACvDisableBarkerPreambleMd(pDevice->PortOffset);
- }
- }
- }
-
- if (pDevice->byRFType == RF_RFMD2959) {
- // bcs TX_PE will reserve 3 us
- // hardware's processing time here is 2 us.
- bySIFS -= 3;
- byDIFS -= 3;
- //{{ RobertYu: 20041202
- //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput
- //// MAC will need 2 us to process, so the SIFS, DIFS can be shorter by 2 us.
- }
-
- if (pDevice->bySIFS != bySIFS) {
- pDevice->bySIFS = bySIFS;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, pDevice->bySIFS);
- }
- if (pDevice->byDIFS != byDIFS) {
- pDevice->byDIFS = byDIFS;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, pDevice->byDIFS);
- }
- if (pDevice->byEIFS != C_EIFS) {
- pDevice->byEIFS = C_EIFS;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, pDevice->byEIFS);
- }
- if (pDevice->bySlot != bySlot) {
- pDevice->bySlot = bySlot;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, pDevice->bySlot);
- if (pDevice->bySlot == C_SLOT_SHORT) {
- pDevice->bShortSlotTime = true;
- } else {
- pDevice->bShortSlotTime = false;
- }
- BBvSetShortSlotTime(pDevice);
- }
- if (pDevice->byCWMaxMin != byCWMaxMin) {
- pDevice->byCWMaxMin = byCWMaxMin;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, pDevice->byCWMaxMin);
- }
- if (VNTWIFIbIsShortPreamble(wCapInfo)) {
- pDevice->byPreambleType = pDevice->byShortPreamble;
- } else {
- pDevice->byPreambleType = 0;
- }
- s_vSetRSPINF(pDevice, ePHYType, pSupportRates, pExtSupportRates);
- pDevice->eCurrentPHYType = ePHYType;
- // set for NDIS OID_802_11SUPPORTED_RATES
- return (true);
+ PWLAN_IE_SUPP_RATES pSupportRates = (PWLAN_IE_SUPP_RATES) pvSupportRateIEs;
+ PWLAN_IE_SUPP_RATES pExtSupportRates = (PWLAN_IE_SUPP_RATES) pvExtSupportRateIEs;
+
+ //Set SIFS, DIFS, EIFS, SlotTime, CwMin
+ if (ePHYType == PHY_TYPE_11A) {
+ if (pSupportRates == NULL) {
+ pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesA;
+ }
+ if (pDevice->byRFType == RF_AIROHA7230) {
+ // AL7230 use single PAPE and connect to PAPE_2.4G
+ MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G);
+ pDevice->abyBBVGA[0] = 0x20;
+ pDevice->abyBBVGA[2] = 0x10;
+ pDevice->abyBBVGA[3] = 0x10;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x1C) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ }
+ } else if (pDevice->byRFType == RF_UW2452) {
+ MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
+ pDevice->abyBBVGA[0] = 0x18;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x14) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0x57);
+ }
+ } else {
+ MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A);
+ }
+ BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x03);
+ bySlot = C_SLOT_SHORT;
+ bySIFS = C_SIFS_A;
+ byDIFS = C_SIFS_A + 2*C_SLOT_SHORT;
+ byCWMaxMin = 0xA4;
+ } else if (ePHYType == PHY_TYPE_11B) {
+ if (pSupportRates == NULL) {
+ pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesB;
+ }
+ MACvSetBBType(pDevice->PortOffset, BB_TYPE_11B);
+ if (pDevice->byRFType == RF_AIROHA7230) {
+ pDevice->abyBBVGA[0] = 0x1C;
+ pDevice->abyBBVGA[2] = 0x00;
+ pDevice->abyBBVGA[3] = 0x00;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x20) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ }
+ } else if (pDevice->byRFType == RF_UW2452) {
+ pDevice->abyBBVGA[0] = 0x14;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x18) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
+ }
+ }
+ BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x02);
+ bySlot = C_SLOT_LONG;
+ bySIFS = C_SIFS_BG;
+ byDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
+ byCWMaxMin = 0xA5;
+ } else {// PK_TYPE_11GA & PK_TYPE_11GB
+ if (pSupportRates == NULL) {
+ pSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultSuppRatesG;
+ pExtSupportRates = (PWLAN_IE_SUPP_RATES) abyDefaultExtSuppRatesG;
+ }
+ MACvSetBBType(pDevice->PortOffset, BB_TYPE_11G);
+ if (pDevice->byRFType == RF_AIROHA7230) {
+ pDevice->abyBBVGA[0] = 0x1C;
+ pDevice->abyBBVGA[2] = 0x00;
+ pDevice->abyBBVGA[3] = 0x00;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x20) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ }
+ } else if (pDevice->byRFType == RF_UW2452) {
+ pDevice->abyBBVGA[0] = 0x14;
+ BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData);
+ if (byData == 0x18) {
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]);
+ BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3);
+ }
+ }
+ BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x08);
+ bySIFS = C_SIFS_BG;
+ if (VNTWIFIbIsShortSlotTime(wCapInfo)) {
+ bySlot = C_SLOT_SHORT;
+ byDIFS = C_SIFS_BG + 2*C_SLOT_SHORT;
+ } else {
+ bySlot = C_SLOT_LONG;
+ byDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
+ }
+ if (VNTWIFIbyGetMaxSupportRate(pSupportRates, pExtSupportRates) > RATE_11M) {
+ byCWMaxMin = 0xA4;
+ } else {
+ byCWMaxMin = 0xA5;
+ }
+ if (pDevice->bProtectMode != VNTWIFIbIsProtectMode(byERPField)) {
+ pDevice->bProtectMode = VNTWIFIbIsProtectMode(byERPField);
+ if (pDevice->bProtectMode) {
+ MACvEnableProtectMD(pDevice->PortOffset);
+ } else {
+ MACvDisableProtectMD(pDevice->PortOffset);
+ }
+ }
+ if (pDevice->bBarkerPreambleMd != VNTWIFIbIsBarkerMode(byERPField)) {
+ pDevice->bBarkerPreambleMd = VNTWIFIbIsBarkerMode(byERPField);
+ if (pDevice->bBarkerPreambleMd) {
+ MACvEnableBarkerPreambleMd(pDevice->PortOffset);
+ } else {
+ MACvDisableBarkerPreambleMd(pDevice->PortOffset);
+ }
+ }
+ }
+
+ if (pDevice->byRFType == RF_RFMD2959) {
+ // bcs TX_PE will reserve 3 us
+ // hardware's processing time here is 2 us.
+ bySIFS -= 3;
+ byDIFS -= 3;
+ //{{ RobertYu: 20041202
+ //// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput
+ //// MAC will need 2 us to process, so the SIFS, DIFS can be shorter by 2 us.
+ }
+
+ if (pDevice->bySIFS != bySIFS) {
+ pDevice->bySIFS = bySIFS;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, pDevice->bySIFS);
+ }
+ if (pDevice->byDIFS != byDIFS) {
+ pDevice->byDIFS = byDIFS;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, pDevice->byDIFS);
+ }
+ if (pDevice->byEIFS != C_EIFS) {
+ pDevice->byEIFS = C_EIFS;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, pDevice->byEIFS);
+ }
+ if (pDevice->bySlot != bySlot) {
+ pDevice->bySlot = bySlot;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, pDevice->bySlot);
+ if (pDevice->bySlot == C_SLOT_SHORT) {
+ pDevice->bShortSlotTime = true;
+ } else {
+ pDevice->bShortSlotTime = false;
+ }
+ BBvSetShortSlotTime(pDevice);
+ }
+ if (pDevice->byCWMaxMin != byCWMaxMin) {
+ pDevice->byCWMaxMin = byCWMaxMin;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, pDevice->byCWMaxMin);
+ }
+ if (VNTWIFIbIsShortPreamble(wCapInfo)) {
+ pDevice->byPreambleType = pDevice->byShortPreamble;
+ } else {
+ pDevice->byPreambleType = 0;
+ }
+ s_vSetRSPINF(pDevice, ePHYType, pSupportRates, pExtSupportRates);
+ pDevice->eCurrentPHYType = ePHYType;
+ // set for NDIS OID_802_11SUPPORTED_RATES
+ return true;
}
/*
@@ -624,27 +605,26 @@ bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigne
* Return Value: none
*
*/
-bool CARDbUpdateTSF (void *pDeviceHandler, unsigned char byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF)
+bool CARDbUpdateTSF(void *pDeviceHandler, unsigned char byRxRate, QWORD qwBSSTimestamp, QWORD qwLocalTSF)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- QWORD qwTSFOffset;
-
- HIDWORD(qwTSFOffset) = 0;
- LODWORD(qwTSFOffset) = 0;
-
- if ((HIDWORD(qwBSSTimestamp) != HIDWORD(qwLocalTSF)) ||
- (LODWORD(qwBSSTimestamp) != LODWORD(qwLocalTSF))) {
- qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF);
- // adjust TSF
- // HW's TSF add TSF Offset reg
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST, LODWORD(qwTSFOffset));
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, HIDWORD(qwTSFOffset));
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN);
- }
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ QWORD qwTSFOffset;
+
+ HIDWORD(qwTSFOffset) = 0;
+ LODWORD(qwTSFOffset) = 0;
+
+ if ((HIDWORD(qwBSSTimestamp) != HIDWORD(qwLocalTSF)) ||
+ (LODWORD(qwBSSTimestamp) != LODWORD(qwLocalTSF))) {
+ qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF);
+ // adjust TSF
+ // HW's TSF add TSF Offset reg
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST, LODWORD(qwTSFOffset));
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_TSFOFST + 4, HIDWORD(qwTSFOffset));
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN);
+ }
+ return true;
}
-
/*
* Description: Set NIC TSF counter for first Beacon time
* Get NEXTTBTT from adjusted TSF and Beacon Interval
@@ -659,47 +639,45 @@ bool CARDbUpdateTSF (void *pDeviceHandler, unsigned char byRxRate, QWORD qwBSSTi
* Return Value: true if succeed; otherwise false
*
*/
-bool CARDbSetBeaconPeriod (void *pDeviceHandler, unsigned short wBeaconInterval)
+bool CARDbSetBeaconPeriod(void *pDeviceHandler, unsigned short wBeaconInterval)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int uBeaconInterval = 0;
- unsigned int uLowNextTBTT = 0;
- unsigned int uHighRemain = 0;
- unsigned int uLowRemain = 0;
- QWORD qwNextTBTT;
-
- HIDWORD(qwNextTBTT) = 0;
- LODWORD(qwNextTBTT) = 0;
- CARDbGetCurrentTSF(pDevice->PortOffset, &qwNextTBTT); //Get Local TSF counter
- uBeaconInterval = wBeaconInterval * 1024;
- // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval
- uLowNextTBTT = (LODWORD(qwNextTBTT) >> 10) << 10;
- uLowRemain = (uLowNextTBTT) % uBeaconInterval;
- // high dword (mod) bcn
- uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwNextTBTT))
- % uBeaconInterval;
- uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval;
- uLowRemain = uBeaconInterval - uLowRemain;
-
- // check if carry when add one beacon interval
- if ((~uLowNextTBTT) < uLowRemain) {
- HIDWORD(qwNextTBTT) ++ ;
- }
- LODWORD(qwNextTBTT) = uLowNextTBTT + uLowRemain;
-
- // set HW beacon interval
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, wBeaconInterval);
- pDevice->wBeaconInterval = wBeaconInterval;
- // Set NextTBTT
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT));
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT));
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
-
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int uBeaconInterval = 0;
+ unsigned int uLowNextTBTT = 0;
+ unsigned int uHighRemain = 0;
+ unsigned int uLowRemain = 0;
+ QWORD qwNextTBTT;
+
+ HIDWORD(qwNextTBTT) = 0;
+ LODWORD(qwNextTBTT) = 0;
+ CARDbGetCurrentTSF(pDevice->PortOffset, &qwNextTBTT); //Get Local TSF counter
+ uBeaconInterval = wBeaconInterval * 1024;
+ // Next TBTT = ((local_current_TSF / beacon_interval) + 1) * beacon_interval
+ uLowNextTBTT = (LODWORD(qwNextTBTT) >> 10) << 10;
+ uLowRemain = (uLowNextTBTT) % uBeaconInterval;
+ // high dword (mod) bcn
+ uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwNextTBTT))
+ % uBeaconInterval;
+ uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval;
+ uLowRemain = uBeaconInterval - uLowRemain;
+
+ // check if carry when add one beacon interval
+ if ((~uLowNextTBTT) < uLowRemain) {
+ HIDWORD(qwNextTBTT)++;
+ }
+ LODWORD(qwNextTBTT) = uLowNextTBTT + uLowRemain;
+
+ // set HW beacon interval
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, wBeaconInterval);
+ pDevice->wBeaconInterval = wBeaconInterval;
+ // Set NextTBTT
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT));
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT));
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
+
+ return true;
}
-
-
/*
* Description: Card Stop Hardware Tx
*
@@ -713,51 +691,49 @@ bool CARDbSetBeaconPeriod (void *pDeviceHandler, unsigned short wBeaconInterval)
* Return Value: true if all data packet complete; otherwise false.
*
*/
-bool CARDbStopTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
+bool CARDbStopTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
-
- if (ePktType == PKT_TYPE_802_11_ALL) {
- pDevice->bStopBeacon = true;
- pDevice->bStopTx0Pkt = true;
- pDevice->bStopDataPkt = true;
- } else if (ePktType == PKT_TYPE_802_11_BCN) {
- pDevice->bStopBeacon = true;
- } else if (ePktType == PKT_TYPE_802_11_MNG) {
- pDevice->bStopTx0Pkt = true;
- } else if (ePktType == PKT_TYPE_802_11_DATA) {
- pDevice->bStopDataPkt = true;
- }
-
- if (pDevice->bStopBeacon == true) {
- if (pDevice->bIsBeaconBufReadySet == true) {
- if (pDevice->cbBeaconBufReadySetCnt < WAIT_BEACON_TX_DOWN_TMO) {
- pDevice->cbBeaconBufReadySetCnt ++;
- return(false);
- }
- }
- pDevice->bIsBeaconBufReadySet = false;
- pDevice->cbBeaconBufReadySetCnt = 0;
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- }
- // wait all TD0 complete
- if (pDevice->bStopTx0Pkt == true) {
- if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){
- return(false);
- }
- }
- // wait all Data TD complete
- if (pDevice->bStopDataPkt == true) {
- if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){
- return(false);
- }
- }
-
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ if (ePktType == PKT_TYPE_802_11_ALL) {
+ pDevice->bStopBeacon = true;
+ pDevice->bStopTx0Pkt = true;
+ pDevice->bStopDataPkt = true;
+ } else if (ePktType == PKT_TYPE_802_11_BCN) {
+ pDevice->bStopBeacon = true;
+ } else if (ePktType == PKT_TYPE_802_11_MNG) {
+ pDevice->bStopTx0Pkt = true;
+ } else if (ePktType == PKT_TYPE_802_11_DATA) {
+ pDevice->bStopDataPkt = true;
+ }
+
+ if (pDevice->bStopBeacon == true) {
+ if (pDevice->bIsBeaconBufReadySet == true) {
+ if (pDevice->cbBeaconBufReadySetCnt < WAIT_BEACON_TX_DOWN_TMO) {
+ pDevice->cbBeaconBufReadySetCnt++;
+ return false;
+ }
+ }
+ pDevice->bIsBeaconBufReadySet = false;
+ pDevice->cbBeaconBufReadySetCnt = 0;
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ }
+ // wait all TD0 complete
+ if (pDevice->bStopTx0Pkt == true) {
+ if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) {
+ return false;
+ }
+ }
+ // wait all Data TD complete
+ if (pDevice->bStopDataPkt == true) {
+ if (pDevice->iTDUsed[TYPE_AC0DMA] != 0) {
+ return false;
+ }
+ }
+
+ return true;
}
-
/*
* Description: Card Start Hardware Tx
*
@@ -771,34 +747,31 @@ bool CARDbStopTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
* Return Value: true if success; false if failed.
*
*/
-bool CARDbStartTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
+bool CARDbStartTxPacket(void *pDeviceHandler, CARD_PKT_TYPE ePktType)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
-
- if (ePktType == PKT_TYPE_802_11_ALL) {
- pDevice->bStopBeacon = false;
- pDevice->bStopTx0Pkt = false;
- pDevice->bStopDataPkt = false;
- } else if (ePktType == PKT_TYPE_802_11_BCN) {
- pDevice->bStopBeacon = false;
- } else if (ePktType == PKT_TYPE_802_11_MNG) {
- pDevice->bStopTx0Pkt = false;
- } else if (ePktType == PKT_TYPE_802_11_DATA) {
- pDevice->bStopDataPkt = false;
- }
-
- if ((pDevice->bStopBeacon == false) &&
- (pDevice->bBeaconBufReady == true) &&
- (pDevice->eOPMode == OP_MODE_ADHOC)) {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- }
-
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ if (ePktType == PKT_TYPE_802_11_ALL) {
+ pDevice->bStopBeacon = false;
+ pDevice->bStopTx0Pkt = false;
+ pDevice->bStopDataPkt = false;
+ } else if (ePktType == PKT_TYPE_802_11_BCN) {
+ pDevice->bStopBeacon = false;
+ } else if (ePktType == PKT_TYPE_802_11_MNG) {
+ pDevice->bStopTx0Pkt = false;
+ } else if (ePktType == PKT_TYPE_802_11_DATA) {
+ pDevice->bStopDataPkt = false;
+ }
+
+ if ((pDevice->bStopBeacon == false) &&
+ (pDevice->bBeaconBufReady == true) &&
+ (pDevice->eOPMode == OP_MODE_ADHOC)) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ }
+
+ return true;
}
-
-
/*
* Description: Card Set BSSID value
*
@@ -815,39 +788,38 @@ bool CARDbStartTxPacket (void *pDeviceHandler, CARD_PKT_TYPE ePktType)
*/
bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE eOPMode)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- MACvWriteBSSIDAddress(pDevice->PortOffset, pbyBSSID);
- memcpy(pDevice->abyBSSID, pbyBSSID, WLAN_BSSID_LEN);
- if (eOPMode == OP_MODE_ADHOC) {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);
- } else {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);
- }
- if (eOPMode == OP_MODE_AP) {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);
- } else {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);
- }
- if (eOPMode == OP_MODE_UNKNOWN) {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
- pDevice->bBSSIDFilter = false;
- pDevice->byRxMode &= ~RCR_BSSID;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode );
- } else {
- if (is_zero_ether_addr(pDevice->abyBSSID) == false) {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
- pDevice->bBSSIDFilter = true;
- pDevice->byRxMode |= RCR_BSSID;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: rx_mode = %x\n", pDevice->byRxMode );
- }
- // Adopt BSS state in Adapter Device Object
- pDevice->eOPMode = eOPMode;
- return(true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ MACvWriteBSSIDAddress(pDevice->PortOffset, pbyBSSID);
+ memcpy(pDevice->abyBSSID, pbyBSSID, WLAN_BSSID_LEN);
+ if (eOPMode == OP_MODE_ADHOC) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);
+ } else {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_ADHOC);
+ }
+ if (eOPMode == OP_MODE_AP) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);
+ } else {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_AP);
+ }
+ if (eOPMode == OP_MODE_UNKNOWN) {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
+ pDevice->bBSSIDFilter = false;
+ pDevice->byRxMode &= ~RCR_BSSID;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode);
+ } else {
+ if (is_zero_ether_addr(pDevice->abyBSSID) == false) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
+ pDevice->bBSSIDFilter = true;
+ pDevice->byRxMode |= RCR_BSSID;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: rx_mode = %x\n", pDevice->byRxMode);
+ }
+ // Adopt BSS state in Adapter Device Object
+ pDevice->eOPMode = eOPMode;
+ return true;
}
-
/*
* Description: Card indicate status
*
@@ -862,9 +834,6 @@ bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE e
*
*/
-
-
-
/*
* Description: Save Assoc info. contain in assoc. response frame
*
@@ -883,14 +852,14 @@ bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE e
*
*/
bool CARDbSetTxDataRate(
- void *pDeviceHandler,
- unsigned short wDataRate
- )
+ void *pDeviceHandler,
+ unsigned short wDataRate
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
- pDevice->wCurrentRate = wDataRate;
- return(true);
+ pDevice->wCurrentRate = wDataRate;
+ return true;
}
/*+
@@ -906,32 +875,32 @@ bool CARDbSetTxDataRate(
*
* Return Value: true if power down success; otherwise false
*
--*/
+ -*/
bool
CARDbPowerDown(
- void *pDeviceHandler
- )
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice)pDeviceHandler;
- unsigned int uIdx;
+ PSDevice pDevice = (PSDevice)pDeviceHandler;
+ unsigned int uIdx;
- // check if already in Doze mode
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
- return true;
+ // check if already in Doze mode
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
+ return true;
- // Froce PSEN on
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
+ // Froce PSEN on
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
- // check if all TD are empty,
+ // check if all TD are empty,
- for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
- if (pDevice->iTDUsed[uIdx] != 0)
- return false;
- }
+ for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
+ if (pDevice->iTDUsed[uIdx] != 0)
+ return false;
+ }
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Go to Doze ZZZZZZZZZZZZZZZ\n");
- return true;
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
+ return true;
}
/*
@@ -946,43 +915,40 @@ CARDbPowerDown(
* Return Value: true if success; otherwise false
*
*/
-bool CARDbRadioPowerOff (void *pDeviceHandler)
+bool CARDbRadioPowerOff(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- bool bResult = true;
-
- if (pDevice->bRadioOff == true)
- return true;
+ PSDevice pDevice = (PSDevice)pDeviceHandler;
+ bool bResult = true;
+ if (pDevice->bRadioOff == true)
+ return true;
- switch (pDevice->byRFType) {
+ switch (pDevice->byRFType) {
+ case RF_RFMD2959:
+ MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV);
+ MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1);
+ break;
- case RF_RFMD2959:
- MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV);
- MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1);
- break;
+ case RF_AIROHA:
+ case RF_AL2230S:
+ case RF_AIROHA7230: //RobertYu:20050104
+ MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE2);
+ MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
+ break;
- case RF_AIROHA:
- case RF_AL2230S:
- case RF_AIROHA7230: //RobertYu:20050104
- MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE2);
- MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- break;
+ }
- }
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON);
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON);
+ BBvSetDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
- BBvSetDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
-
- pDevice->bRadioOff = true;
- //2007-0409-03,<Add> by chester
-printk("chester power off\n");
-MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
- return bResult;
+ pDevice->bRadioOff = true;
+ //2007-0409-03,<Add> by chester
+ printk("chester power off\n");
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
+ return bResult;
}
-
/*
* Description: Turn on Radio power
*
@@ -995,59 +961,54 @@ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
* Return Value: true if success; otherwise false
*
*/
-bool CARDbRadioPowerOn (void *pDeviceHandler)
+bool CARDbRadioPowerOn(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- bool bResult = true;
-printk("chester power on\n");
- if (pDevice->bRadioControlOff == true){
-if (pDevice->bHWRadioOff == true) printk("chester bHWRadioOff\n");
-if (pDevice->bRadioControlOff == true) printk("chester bRadioControlOff\n");
- return false;}
-
- if (pDevice->bRadioOff == false)
- {
-printk("chester pbRadioOff\n");
-return true;}
-
- BBvExitDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
-
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON);
-
- switch (pDevice->byRFType) {
-
- case RF_RFMD2959:
- MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV);
- MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1);
- break;
-
- case RF_AIROHA:
- case RF_AL2230S:
- case RF_AIROHA7230: //RobertYu:20050104
- MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE2 |
- SOFTPWRCTL_SWPE3));
- break;
-
- }
-
- pDevice->bRadioOff = false;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ bool bResult = true;
+ printk("chester power on\n");
+ if (pDevice->bRadioControlOff == true) {
+ if (pDevice->bHWRadioOff == true) printk("chester bHWRadioOff\n");
+ if (pDevice->bRadioControlOff == true) printk("chester bRadioControlOff\n");
+ return false; }
+
+ if (pDevice->bRadioOff == false) {
+ printk("chester pbRadioOff\n");
+ return true; }
+
+ BBvExitDeepSleep(pDevice->PortOffset, pDevice->byLocalID);
+
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_HOSTCR, HOSTCR_RXON);
+
+ switch (pDevice->byRFType) {
+ case RF_RFMD2959:
+ MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV);
+ MACvWordRegBitsOff(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1);
+ break;
+
+ case RF_AIROHA:
+ case RF_AL2230S:
+ case RF_AIROHA7230: //RobertYu:20050104
+ MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE2 |
+ SOFTPWRCTL_SWPE3));
+ break;
+
+ }
+
+ pDevice->bRadioOff = false;
// 2007-0409-03,<Add> by chester
-printk("chester power on\n");
-MACvRegBitsOff(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
- return bResult;
+ printk("chester power on\n");
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_GPIOCTL0, LED_ACTSET); //LED issue
+ return bResult;
}
-
-
-bool CARDbRemoveKey (void *pDeviceHandler, unsigned char *pbyBSSID)
+bool CARDbRemoveKey(void *pDeviceHandler, unsigned char *pbyBSSID)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
- KeybRemoveAllKey(&(pDevice->sKey), pbyBSSID, pDevice->PortOffset);
- return (true);
+ KeybRemoveAllKey(&(pDevice->sKey), pbyBSSID, pDevice->PortOffset);
+ return true;
}
-
/*
*
* Description:
@@ -1063,66 +1024,65 @@ bool CARDbRemoveKey (void *pDeviceHandler, unsigned char *pbyBSSID)
*
* Return Value: none.
*
--*/
+ -*/
bool
-CARDbAdd_PMKID_Candidate (
- void *pDeviceHandler,
- unsigned char *pbyBSSID,
- bool bRSNCapExist,
- unsigned short wRSNCap
- )
+CARDbAdd_PMKID_Candidate(
+ void *pDeviceHandler,
+ unsigned char *pbyBSSID,
+ bool bRSNCapExist,
+ unsigned short wRSNCap
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- PPMKID_CANDIDATE pCandidateList;
- unsigned int ii = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
-
- if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFlush_PMKID_Candidate: 3\n");
- memset(&pDevice->gsPMKIDCandidate, 0, sizeof(SPMKIDCandidateEvent));
- }
-
- for (ii = 0; ii < 6; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02X ", *(pbyBSSID + ii));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
-
- // Update Old Candidate
- for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
- pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
- if ( !memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
- if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
- pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
- } else {
- pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
- }
- return true;
- }
- }
-
- // New Candidate
- pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
- if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
- pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
- } else {
- pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
- }
- memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
- pDevice->gsPMKIDCandidate.NumCandidates++;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
- return true;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PPMKID_CANDIDATE pCandidateList;
+ unsigned int ii = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
+
+ if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vFlush_PMKID_Candidate: 3\n");
+ memset(&pDevice->gsPMKIDCandidate, 0, sizeof(SPMKIDCandidateEvent));
+ }
+
+ for (ii = 0; ii < 6; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02X ", *(pbyBSSID + ii));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ // Update Old Candidate
+ for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
+ pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
+ if (!memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
+ if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
+ pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ } else {
+ pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
+ }
+ return true;
+ }
+ }
+
+ // New Candidate
+ pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
+ if ((bRSNCapExist == true) && (wRSNCap & BIT0)) {
+ pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ } else {
+ pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
+ }
+ memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
+ pDevice->gsPMKIDCandidate.NumCandidates++;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
+ return true;
}
void *
-CARDpGetCurrentAddress (
- void *pDeviceHandler
- )
+CARDpGetCurrentAddress(
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
- return (pDevice->abyCurrentNetAddr);
+ return pDevice->abyCurrentNetAddr;
}
/*
@@ -1138,120 +1098,119 @@ CARDpGetCurrentAddress (
*
* Return Value: none.
*
--*/
+ -*/
bool
-CARDbStartMeasure (
- void *pDeviceHandler,
- void *pvMeasureEIDs,
- unsigned int uNumOfMeasureEIDs
- )
+CARDbStartMeasure(
+ void *pDeviceHandler,
+ void *pvMeasureEIDs,
+ unsigned int uNumOfMeasureEIDs
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- PWLAN_IE_MEASURE_REQ pEID = (PWLAN_IE_MEASURE_REQ) pvMeasureEIDs;
- QWORD qwCurrTSF;
- QWORD qwStartTSF;
- bool bExpired = true;
- unsigned short wDuration = 0;
-
- if ((pEID == NULL) ||
- (uNumOfMeasureEIDs == 0)) {
- return (true);
- }
- CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
- if (pDevice->bMeasureInProgress == true) {
- pDevice->bMeasureInProgress = false;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4);
- // clear measure control
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
- MACvSelectPage0(pDevice->PortOffset);
- set_channel(pDevice, pDevice->byOrgChannel);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- }
- pDevice->uNumOfMeasureEIDs = uNumOfMeasureEIDs;
-
- do {
- pDevice->pCurrMeasureEID = pEID;
- pEID++;
- pDevice->uNumOfMeasureEIDs--;
-
- if (pDevice->byLocalID > REV_ID_VT3253_B1) {
- HIDWORD(qwStartTSF) = HIDWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime)));
- LODWORD(qwStartTSF) = LODWORD(*((PQWORD) (pDevice->pCurrMeasureEID->sReq.abyStartTime)));
- wDuration = *((unsigned short *) (pDevice->pCurrMeasureEID->sReq.abyDuration));
- wDuration += 1; // 1 TU for channel switching
-
- if ((LODWORD(qwStartTSF) == 0) && (HIDWORD(qwStartTSF) == 0)) {
- // start immediately by setting start TSF == current TSF + 2 TU
- LODWORD(qwStartTSF) = LODWORD(qwCurrTSF) + 2048;
- HIDWORD(qwStartTSF) = HIDWORD(qwCurrTSF);
- if (LODWORD(qwCurrTSF) > LODWORD(qwStartTSF)) {
- HIDWORD(qwStartTSF)++;
- }
- bExpired = false;
- break;
- } else {
- // start at setting start TSF - 1TU(for channel switching)
- if (LODWORD(qwStartTSF) < 1024) {
- HIDWORD(qwStartTSF)--;
- }
- LODWORD(qwStartTSF) -= 1024;
- }
-
- if ((HIDWORD(qwCurrTSF) < HIDWORD(qwStartTSF)) ||
- ((HIDWORD(qwCurrTSF) == HIDWORD(qwStartTSF)) &&
- (LODWORD(qwCurrTSF) < LODWORD(qwStartTSF)))
- ) {
- bExpired = false;
- break;
- }
- VNTWIFIbMeasureReport( pDevice->pMgmt,
- false,
- pDevice->pCurrMeasureEID,
- MEASURE_MODE_LATE,
- pDevice->byBasicMap,
- pDevice->byCCAFraction,
- pDevice->abyRPIs
- );
- } else {
- // hardware do not support measure
- VNTWIFIbMeasureReport( pDevice->pMgmt,
- false,
- pDevice->pCurrMeasureEID,
- MEASURE_MODE_INCAPABLE,
- pDevice->byBasicMap,
- pDevice->byCCAFraction,
- pDevice->abyRPIs
- );
- }
- } while (pDevice->uNumOfMeasureEIDs != 0);
-
- if (bExpired == false) {
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART, LODWORD(qwStartTSF));
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART + 4, HIDWORD(qwStartTSF));
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_MSRDURATION, wDuration);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
- MACvSelectPage0(pDevice->PortOffset);
- } else {
- // all measure start time expired we should complete action
- VNTWIFIbMeasureReport( pDevice->pMgmt,
- true,
- NULL,
- 0,
- pDevice->byBasicMap,
- pDevice->byCCAFraction,
- pDevice->abyRPIs
- );
- }
- return (true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PWLAN_IE_MEASURE_REQ pEID = (PWLAN_IE_MEASURE_REQ) pvMeasureEIDs;
+ QWORD qwCurrTSF;
+ QWORD qwStartTSF;
+ bool bExpired = true;
+ unsigned short wDuration = 0;
+
+ if ((pEID == NULL) ||
+ (uNumOfMeasureEIDs == 0)) {
+ return true;
+ }
+ CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
+ if (pDevice->bMeasureInProgress == true) {
+ pDevice->bMeasureInProgress = false;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4);
+ // clear measure control
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
+ MACvSelectPage0(pDevice->PortOffset);
+ set_channel(pDevice, pDevice->byOrgChannel);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ }
+ pDevice->uNumOfMeasureEIDs = uNumOfMeasureEIDs;
+
+ do {
+ pDevice->pCurrMeasureEID = pEID;
+ pEID++;
+ pDevice->uNumOfMeasureEIDs--;
+
+ if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+ HIDWORD(qwStartTSF) = HIDWORD(*((PQWORD)(pDevice->pCurrMeasureEID->sReq.abyStartTime)));
+ LODWORD(qwStartTSF) = LODWORD(*((PQWORD)(pDevice->pCurrMeasureEID->sReq.abyStartTime)));
+ wDuration = *((unsigned short *)(pDevice->pCurrMeasureEID->sReq.abyDuration));
+ wDuration += 1; // 1 TU for channel switching
+
+ if ((LODWORD(qwStartTSF) == 0) && (HIDWORD(qwStartTSF) == 0)) {
+ // start immediately by setting start TSF == current TSF + 2 TU
+ LODWORD(qwStartTSF) = LODWORD(qwCurrTSF) + 2048;
+ HIDWORD(qwStartTSF) = HIDWORD(qwCurrTSF);
+ if (LODWORD(qwCurrTSF) > LODWORD(qwStartTSF)) {
+ HIDWORD(qwStartTSF)++;
+ }
+ bExpired = false;
+ break;
+ } else {
+ // start at setting start TSF - 1TU(for channel switching)
+ if (LODWORD(qwStartTSF) < 1024) {
+ HIDWORD(qwStartTSF)--;
+ }
+ LODWORD(qwStartTSF) -= 1024;
+ }
+
+ if ((HIDWORD(qwCurrTSF) < HIDWORD(qwStartTSF)) ||
+ ((HIDWORD(qwCurrTSF) == HIDWORD(qwStartTSF)) &&
+ (LODWORD(qwCurrTSF) < LODWORD(qwStartTSF)))
+) {
+ bExpired = false;
+ break;
+ }
+ VNTWIFIbMeasureReport(pDevice->pMgmt,
+ false,
+ pDevice->pCurrMeasureEID,
+ MEASURE_MODE_LATE,
+ pDevice->byBasicMap,
+ pDevice->byCCAFraction,
+ pDevice->abyRPIs
+ );
+ } else {
+ // hardware do not support measure
+ VNTWIFIbMeasureReport(pDevice->pMgmt,
+ false,
+ pDevice->pCurrMeasureEID,
+ MEASURE_MODE_INCAPABLE,
+ pDevice->byBasicMap,
+ pDevice->byCCAFraction,
+ pDevice->abyRPIs
+ );
+ }
+ } while (pDevice->uNumOfMeasureEIDs != 0);
+
+ if (bExpired == false) {
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART, LODWORD(qwStartTSF));
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MSRSTART + 4, HIDWORD(qwStartTSF));
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_MSRDURATION, wDuration);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
+ MACvSelectPage0(pDevice->PortOffset);
+ } else {
+ // all measure start time expired we should complete action
+ VNTWIFIbMeasureReport(pDevice->pMgmt,
+ true,
+ NULL,
+ 0,
+ pDevice->byBasicMap,
+ pDevice->byCCAFraction,
+ pDevice->abyRPIs
+ );
+ }
+ return true;
}
-
/*
*
* Description:
@@ -1265,36 +1224,35 @@ CARDbStartMeasure (
*
* Return Value: none.
*
--*/
+ -*/
bool
-CARDbChannelSwitch (
- void *pDeviceHandler,
- unsigned char byMode,
- unsigned char byNewChannel,
- unsigned char byCount
- )
+CARDbChannelSwitch(
+ void *pDeviceHandler,
+ unsigned char byMode,
+ unsigned char byNewChannel,
+ unsigned char byCount
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- bool bResult = true;
-
- if (byCount == 0) {
- bResult = set_channel(pDevice, byNewChannel);
- VNTWIFIbChannelSwitch(pDevice->pMgmt, byNewChannel);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- return(bResult);
- }
- pDevice->byChannelSwitchCount = byCount;
- pDevice->byNewChannel = byNewChannel;
- pDevice->bChannelSwitch = true;
- if (byMode == 1) {
- bResult=CARDbStopTxPacket(pDevice, PKT_TYPE_802_11_ALL);
- }
- return (bResult);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ bool bResult = true;
+
+ if (byCount == 0) {
+ bResult = set_channel(pDevice, byNewChannel);
+ VNTWIFIbChannelSwitch(pDevice->pMgmt, byNewChannel);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ return bResult;
+ }
+ pDevice->byChannelSwitchCount = byCount;
+ pDevice->byNewChannel = byNewChannel;
+ pDevice->bChannelSwitch = true;
+ if (byMode == 1) {
+ bResult = CARDbStopTxPacket(pDevice, PKT_TYPE_802_11_ALL);
+ }
+ return bResult;
}
-
/*
*
* Description:
@@ -1308,53 +1266,52 @@ CARDbChannelSwitch (
*
* Return Value: none.
*
--*/
+ -*/
bool
-CARDbSetQuiet (
- void *pDeviceHandler,
- bool bResetQuiet,
- unsigned char byQuietCount,
- unsigned char byQuietPeriod,
- unsigned short wQuietDuration,
- unsigned short wQuietOffset
- )
+CARDbSetQuiet(
+ void *pDeviceHandler,
+ bool bResetQuiet,
+ unsigned char byQuietCount,
+ unsigned char byQuietPeriod,
+ unsigned short wQuietDuration,
+ unsigned short wQuietOffset
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int ii = 0;
-
- if (bResetQuiet == true) {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
- for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- pDevice->sQuiet[ii].bEnable = false;
- }
- pDevice->uQuietEnqueue = 0;
- pDevice->bEnableFirstQuiet = false;
- pDevice->bQuietEnable = false;
- pDevice->byQuietStartCount = byQuietCount;
- }
- if (pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable == false) {
- pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable = true;
- pDevice->sQuiet[pDevice->uQuietEnqueue].byPeriod = byQuietPeriod;
- pDevice->sQuiet[pDevice->uQuietEnqueue].wDuration = wQuietDuration;
- pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime = (unsigned long) byQuietCount;
- pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime *= pDevice->wBeaconInterval;
- pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime += wQuietOffset;
- pDevice->uQuietEnqueue++;
- pDevice->uQuietEnqueue %= MAX_QUIET_COUNT;
- if (pDevice->byQuietStartCount < byQuietCount) {
- pDevice->byQuietStartCount = byQuietCount;
- }
- } else {
- // we can not handle Quiet EID more
- }
- return (true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii = 0;
+
+ if (bResetQuiet == true) {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
+ for (ii = 0; ii < MAX_QUIET_COUNT; ii++) {
+ pDevice->sQuiet[ii].bEnable = false;
+ }
+ pDevice->uQuietEnqueue = 0;
+ pDevice->bEnableFirstQuiet = false;
+ pDevice->bQuietEnable = false;
+ pDevice->byQuietStartCount = byQuietCount;
+ }
+ if (pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable == false) {
+ pDevice->sQuiet[pDevice->uQuietEnqueue].bEnable = true;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].byPeriod = byQuietPeriod;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].wDuration = wQuietDuration;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime = (unsigned long) byQuietCount;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime *= pDevice->wBeaconInterval;
+ pDevice->sQuiet[pDevice->uQuietEnqueue].dwStartTime += wQuietOffset;
+ pDevice->uQuietEnqueue++;
+ pDevice->uQuietEnqueue %= MAX_QUIET_COUNT;
+ if (pDevice->byQuietStartCount < byQuietCount) {
+ pDevice->byQuietStartCount = byQuietCount;
+ }
+ } else {
+ // we can not handle Quiet EID more
+ }
+ return true;
}
-
/*
*
* Description:
- * Do Quiet, It will be called by either ISR(after start)
+ * Do Quiet, It will be called by either ISR(after start)
* or VNTWIFI(before start) so we do not need a SPINLOCK
*
* Parameters:
@@ -1365,91 +1322,91 @@ CARDbSetQuiet (
*
* Return Value: none.
*
--*/
+ -*/
bool
-CARDbStartQuiet (
- void *pDeviceHandler
- )
+CARDbStartQuiet(
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int ii = 0;
- unsigned long dwStartTime = 0xFFFFFFFF;
- unsigned int uCurrentQuietIndex = 0;
- unsigned long dwNextTime = 0;
- unsigned long dwGap = 0;
- unsigned long dwDuration = 0;
-
- for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- if ((pDevice->sQuiet[ii].bEnable == true) &&
- (dwStartTime > pDevice->sQuiet[ii].dwStartTime)) {
- dwStartTime = pDevice->sQuiet[ii].dwStartTime;
- uCurrentQuietIndex = ii;
- }
- }
- if (dwStartTime == 0xFFFFFFFF) {
- // no more quiet
- pDevice->bQuietEnable = false;
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
- } else {
- if (pDevice->bQuietEnable == false) {
- // first quiet
- pDevice->byQuietStartCount--;
- dwNextTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
- dwNextTime %= pDevice->wBeaconInterval;
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETINIT, (unsigned short) dwNextTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) pDevice->sQuiet[uCurrentQuietIndex].wDuration);
- if (pDevice->byQuietStartCount == 0) {
- pDevice->bEnableFirstQuiet = false;
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
- } else {
- pDevice->bEnableFirstQuiet = true;
- }
- MACvSelectPage0(pDevice->PortOffset);
- } else {
- if (pDevice->dwCurrentQuietEndTime > pDevice->sQuiet[uCurrentQuietIndex].dwStartTime) {
- // overlap with previous Quiet
- dwGap = pDevice->dwCurrentQuietEndTime - pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
- if (dwGap >= pDevice->sQuiet[uCurrentQuietIndex].wDuration) {
- // return false to indicate next quiet expired, should call this function again
- return (false);
- }
- dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration - dwGap;
- dwGap = 0;
- } else {
- dwGap = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime - pDevice->dwCurrentQuietEndTime;
- dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration;
- }
- // set GAP and Next duration
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETGAP, (unsigned short) dwGap);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) dwDuration);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_QUIETRPT);
- MACvSelectPage0(pDevice->PortOffset);
- }
- pDevice->bQuietEnable = true;
- pDevice->dwCurrentQuietEndTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
- pDevice->dwCurrentQuietEndTime += pDevice->sQuiet[uCurrentQuietIndex].wDuration;
- if (pDevice->sQuiet[uCurrentQuietIndex].byPeriod == 0) {
- // not period disable current quiet element
- pDevice->sQuiet[uCurrentQuietIndex].bEnable = false;
- } else {
- // set next period start time
- dwNextTime = (unsigned long) pDevice->sQuiet[uCurrentQuietIndex].byPeriod;
- dwNextTime *= pDevice->wBeaconInterval;
- pDevice->sQuiet[uCurrentQuietIndex].dwStartTime = dwNextTime;
- }
- if (pDevice->dwCurrentQuietEndTime > 0x80010000) {
- // decreament all time to avoid wrap around
- for(ii=0;ii<MAX_QUIET_COUNT;ii++) {
- if (pDevice->sQuiet[ii].bEnable == true) {
- pDevice->sQuiet[ii].dwStartTime -= 0x80000000;
- }
- }
- pDevice->dwCurrentQuietEndTime -= 0x80000000;
- }
- }
- return (true);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii = 0;
+ unsigned long dwStartTime = 0xFFFFFFFF;
+ unsigned int uCurrentQuietIndex = 0;
+ unsigned long dwNextTime = 0;
+ unsigned long dwGap = 0;
+ unsigned long dwDuration = 0;
+
+ for (ii = 0; ii < MAX_QUIET_COUNT; ii++) {
+ if ((pDevice->sQuiet[ii].bEnable == true) &&
+ (dwStartTime > pDevice->sQuiet[ii].dwStartTime)) {
+ dwStartTime = pDevice->sQuiet[ii].dwStartTime;
+ uCurrentQuietIndex = ii;
+ }
+ }
+ if (dwStartTime == 0xFFFFFFFF) {
+ // no more quiet
+ pDevice->bQuietEnable = false;
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
+ } else {
+ if (pDevice->bQuietEnable == false) {
+ // first quiet
+ pDevice->byQuietStartCount--;
+ dwNextTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
+ dwNextTime %= pDevice->wBeaconInterval;
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETINIT, (unsigned short) dwNextTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) pDevice->sQuiet[uCurrentQuietIndex].wDuration);
+ if (pDevice->byQuietStartCount == 0) {
+ pDevice->bEnableFirstQuiet = false;
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
+ } else {
+ pDevice->bEnableFirstQuiet = true;
+ }
+ MACvSelectPage0(pDevice->PortOffset);
+ } else {
+ if (pDevice->dwCurrentQuietEndTime > pDevice->sQuiet[uCurrentQuietIndex].dwStartTime) {
+ // overlap with previous Quiet
+ dwGap = pDevice->dwCurrentQuietEndTime - pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
+ if (dwGap >= pDevice->sQuiet[uCurrentQuietIndex].wDuration) {
+ // return false to indicate next quiet expired, should call this function again
+ return false;
+ }
+ dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration - dwGap;
+ dwGap = 0;
+ } else {
+ dwGap = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime - pDevice->dwCurrentQuietEndTime;
+ dwDuration = pDevice->sQuiet[uCurrentQuietIndex].wDuration;
+ }
+ // set GAP and Next duration
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETGAP, (unsigned short) dwGap);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_QUIETDUR, (unsigned short) dwDuration);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_QUIETRPT);
+ MACvSelectPage0(pDevice->PortOffset);
+ }
+ pDevice->bQuietEnable = true;
+ pDevice->dwCurrentQuietEndTime = pDevice->sQuiet[uCurrentQuietIndex].dwStartTime;
+ pDevice->dwCurrentQuietEndTime += pDevice->sQuiet[uCurrentQuietIndex].wDuration;
+ if (pDevice->sQuiet[uCurrentQuietIndex].byPeriod == 0) {
+ // not period disable current quiet element
+ pDevice->sQuiet[uCurrentQuietIndex].bEnable = false;
+ } else {
+ // set next period start time
+ dwNextTime = (unsigned long) pDevice->sQuiet[uCurrentQuietIndex].byPeriod;
+ dwNextTime *= pDevice->wBeaconInterval;
+ pDevice->sQuiet[uCurrentQuietIndex].dwStartTime = dwNextTime;
+ }
+ if (pDevice->dwCurrentQuietEndTime > 0x80010000) {
+ // decreament all time to avoid wrap around
+ for (ii = 0; ii < MAX_QUIET_COUNT; ii++) {
+ if (pDevice->sQuiet[ii].bEnable == true) {
+ pDevice->sQuiet[ii].dwStartTime -= 0x80000000;
+ }
+ }
+ pDevice->dwCurrentQuietEndTime -= 0x80000000;
+ }
+ }
+ return true;
}
/*
@@ -1465,28 +1422,27 @@ CARDbStartQuiet (
*
* Return Value: none.
*
--*/
+ -*/
void
-CARDvSetPowerConstraint (
- void *pDeviceHandler,
- unsigned char byChannel,
- char byPower
- )
+CARDvSetPowerConstraint(
+ void *pDeviceHandler,
+ unsigned char byChannel,
+ char byPower
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- if (byChannel > CB_MAX_CHANNEL_24G) {
- if (pDevice->bCountryInfo5G == true) {
- pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
- }
- } else {
- if (pDevice->bCountryInfo24G == true) {
- pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
- }
- }
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ if (byChannel > CB_MAX_CHANNEL_24G) {
+ if (pDevice->bCountryInfo5G == true) {
+ pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
+ }
+ } else {
+ if (pDevice->bCountryInfo24G == true) {
+ pDevice->abyLocalPwr[byChannel] = pDevice->abyRegPwr[byChannel] - byPower;
+ }
+ }
}
-
/*
*
* Description:
@@ -1500,26 +1456,26 @@ CARDvSetPowerConstraint (
*
* Return Value: none.
*
--*/
+ -*/
void
-CARDvGetPowerCapability (
- void *pDeviceHandler,
- unsigned char *pbyMinPower,
- unsigned char *pbyMaxPower
- )
+CARDvGetPowerCapability(
+ void *pDeviceHandler,
+ unsigned char *pbyMinPower,
+ unsigned char *pbyMaxPower
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned char byDec = 0;
-
- *pbyMaxPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh];
- byDec = pDevice->abyOFDMPwrTbl[pDevice->byCurrentCh];
- if (pDevice->byRFType == RF_UW2452) {
- byDec *= 3;
- byDec >>= 1;
- } else {
- byDec <<= 1;
- }
- *pbyMinPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh] - byDec;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned char byDec = 0;
+
+ *pbyMaxPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh];
+ byDec = pDevice->abyOFDMPwrTbl[pDevice->byCurrentCh];
+ if (pDevice->byRFType == RF_UW2452) {
+ byDec *= 3;
+ byDec >>= 1;
+ } else {
+ byDec <<= 1;
+ }
+ *pbyMinPower = pDevice->abyOFDMDefaultPwr[pDevice->byCurrentCh] - byDec;
}
/*
@@ -1537,58 +1493,55 @@ CARDvGetPowerCapability (
*
*/
char
-CARDbyGetTransmitPower (
- void *pDeviceHandler
- )
+CARDbyGetTransmitPower(
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
- return (pDevice->byCurPwrdBm);
+ return pDevice->byCurPwrdBm;
}
//xxx
void
-CARDvSafeResetTx (
- void *pDeviceHandler
- )
+CARDvSafeResetTx(
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int uu;
- PSTxDesc pCurrTD;
-
- // initialize TD index
- pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]);
- pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]);
-
- for (uu = 0; uu < TYPE_MAXTD; uu ++)
- pDevice->iTDUsed[uu] = 0;
-
- for (uu = 0; uu < pDevice->sOpts.nTxDescs[0]; uu++) {
- pCurrTD = &(pDevice->apTD0Rings[uu]);
- pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST;
- // init all Tx Packet pointer to NULL
- }
- for (uu = 0; uu < pDevice->sOpts.nTxDescs[1]; uu++) {
- pCurrTD = &(pDevice->apTD1Rings[uu]);
- pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST;
- // init all Tx Packet pointer to NULL
- }
-
- // set MAC TD pointer
- MACvSetCurrTXDescAddr(TYPE_TXDMA0, pDevice->PortOffset,
- (pDevice->td0_pool_dma));
-
- MACvSetCurrTXDescAddr(TYPE_AC0DMA, pDevice->PortOffset,
- (pDevice->td1_pool_dma));
-
- // set MAC Beacon TX pointer
- MACvSetCurrBCNTxDescAddr(pDevice->PortOffset,
- (pDevice->tx_beacon_dma));
-
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int uu;
+ PSTxDesc pCurrTD;
+
+ // initialize TD index
+ pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]);
+ pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]);
+
+ for (uu = 0; uu < TYPE_MAXTD; uu++)
+ pDevice->iTDUsed[uu] = 0;
+
+ for (uu = 0; uu < pDevice->sOpts.nTxDescs[0]; uu++) {
+ pCurrTD = &(pDevice->apTD0Rings[uu]);
+ pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST;
+ // init all Tx Packet pointer to NULL
+ }
+ for (uu = 0; uu < pDevice->sOpts.nTxDescs[1]; uu++) {
+ pCurrTD = &(pDevice->apTD1Rings[uu]);
+ pCurrTD->m_td0TD0.f1Owner = OWNED_BY_HOST;
+ // init all Tx Packet pointer to NULL
+ }
+
+ // set MAC TD pointer
+ MACvSetCurrTXDescAddr(TYPE_TXDMA0, pDevice->PortOffset,
+ (pDevice->td0_pool_dma));
+
+ MACvSetCurrTXDescAddr(TYPE_AC0DMA, pDevice->PortOffset,
+ (pDevice->td1_pool_dma));
+
+ // set MAC Beacon TX pointer
+ MACvSetCurrBCNTxDescAddr(pDevice->PortOffset,
+ (pDevice->tx_beacon_dma));
}
-
-
/*+
*
* Description:
@@ -1602,55 +1555,50 @@ CARDvSafeResetTx (
*
* Return Value: none
*
--*/
+ -*/
void
-CARDvSafeResetRx (
- void *pDeviceHandler
- )
+CARDvSafeResetRx(
+ void *pDeviceHandler
+)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int uu;
- PSRxDesc pDesc;
-
-
-
- // initialize RD index
- pDevice->pCurrRD[0]=&(pDevice->aRD0Ring[0]);
- pDevice->pCurrRD[1]=&(pDevice->aRD1Ring[0]);
-
- // init state, all RD is chip's
- for (uu = 0; uu < pDevice->sOpts.nRxDescs0; uu++) {
- pDesc =&(pDevice->aRD0Ring[uu]);
- pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
- pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC;
- pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
- }
-
- // init state, all RD is chip's
- for (uu = 0; uu < pDevice->sOpts.nRxDescs1; uu++) {
- pDesc =&(pDevice->aRD1Ring[uu]);
- pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
- pDesc->m_rd0RD0.f1Owner=OWNED_BY_NIC;
- pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
- }
-
- pDevice->cbDFCB = CB_MAX_RX_FRAG;
- pDevice->cbFreeDFCB = pDevice->cbDFCB;
-
- // set perPkt mode
- MACvRx0PerPktMode(pDevice->PortOffset);
- MACvRx1PerPktMode(pDevice->PortOffset);
- // set MAC RD pointer
- MACvSetCurrRx0DescAddr(pDevice->PortOffset,
- pDevice->rd0_pool_dma);
-
- MACvSetCurrRx1DescAddr(pDevice->PortOffset,
- pDevice->rd1_pool_dma);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int uu;
+ PSRxDesc pDesc;
+
+ // initialize RD index
+ pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]);
+ pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]);
+
+ // init state, all RD is chip's
+ for (uu = 0; uu < pDevice->sOpts.nRxDescs0; uu++) {
+ pDesc = &(pDevice->aRD0Ring[uu]);
+ pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
+ pDesc->m_rd0RD0.f1Owner = OWNED_BY_NIC;
+ pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
+ }
+
+ // init state, all RD is chip's
+ for (uu = 0; uu < pDevice->sOpts.nRxDescs1; uu++) {
+ pDesc = &(pDevice->aRD1Ring[uu]);
+ pDesc->m_rd0RD0.wResCount = (unsigned short)(pDevice->rx_buf_sz);
+ pDesc->m_rd0RD0.f1Owner = OWNED_BY_NIC;
+ pDesc->m_rd1RD1.wReqCount = (unsigned short)(pDevice->rx_buf_sz);
+ }
+
+ pDevice->cbDFCB = CB_MAX_RX_FRAG;
+ pDevice->cbFreeDFCB = pDevice->cbDFCB;
+
+ // set perPkt mode
+ MACvRx0PerPktMode(pDevice->PortOffset);
+ MACvRx1PerPktMode(pDevice->PortOffset);
+ // set MAC RD pointer
+ MACvSetCurrRx0DescAddr(pDevice->PortOffset,
+ pDevice->rd0_pool_dma);
+
+ MACvSetCurrRx1DescAddr(pDevice->PortOffset,
+ pDevice->rd1_pool_dma);
}
-
-
-
/*
* Description: Get response Control frame rate in CCK mode
*
@@ -1666,16 +1614,16 @@ CARDvSafeResetRx (
*/
unsigned short CARDwGetCCKControlRate(void *pDeviceHandler, unsigned short wRateIdx)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int ui = (unsigned int) wRateIdx;
-
- while (ui > RATE_1M) {
- if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
- return (unsigned short)ui;
- }
- ui --;
- }
- return (unsigned short)RATE_1M;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ui = (unsigned int) wRateIdx;
+
+ while (ui > RATE_1M) {
+ if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
+ return (unsigned short)ui;
+ }
+ ui--;
+ }
+ return (unsigned short)RATE_1M;
}
/*
@@ -1691,31 +1639,30 @@ unsigned short CARDwGetCCKControlRate(void *pDeviceHandler, unsigned short wRate
* Return Value: response Control frame rate
*
*/
-unsigned short CARDwGetOFDMControlRate (void *pDeviceHandler, unsigned short wRateIdx)
+unsigned short CARDwGetOFDMControlRate(void *pDeviceHandler, unsigned short wRateIdx)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned int ui = (unsigned int) wRateIdx;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BASIC RATE: %X\n", pDevice->wBasicRate);
-
- if (!CARDbIsOFDMinBasicRate((void *)pDevice)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate:(NO OFDM) %d\n", wRateIdx);
- if (wRateIdx > RATE_24M)
- wRateIdx = RATE_24M;
- return wRateIdx;
- }
- while (ui > RATE_11M) {
- if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate : %d\n", ui);
- return (unsigned short)ui;
- }
- ui --;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDwGetOFDMControlRate: 6M\n");
- return (unsigned short)RATE_24M;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ui = (unsigned int) wRateIdx;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BASIC RATE: %X\n", pDevice->wBasicRate);
+
+ if (!CARDbIsOFDMinBasicRate((void *)pDevice)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CARDwGetOFDMControlRate:(NO OFDM) %d\n", wRateIdx);
+ if (wRateIdx > RATE_24M)
+ wRateIdx = RATE_24M;
+ return wRateIdx;
+ }
+ while (ui > RATE_11M) {
+ if (pDevice->wBasicRate & ((unsigned short)1 << ui)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CARDwGetOFDMControlRate : %d\n", ui);
+ return (unsigned short)ui;
+ }
+ ui--;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CARDwGetOFDMControlRate: 6M\n");
+ return (unsigned short)RATE_24M;
}
-
/*
* Description: Set RSPINF
*
@@ -1728,117 +1675,117 @@ unsigned short CARDwGetOFDMControlRate (void *pDeviceHandler, unsigned short wRa
* Return Value: None.
*
*/
-void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
+void CARDvSetRSPINF(void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned char byServ = 0x00, bySignal = 0x00; //For CCK
- unsigned short wLen = 0x0000;
- unsigned char byTxRate, byRsvTime; //For OFDM
-
- //Set to Page1
- MACvSelectPage1(pDevice->PortOffset);
-
- //RSPINF_b_1
- BBvCalculateParameter(pDevice,
- 14,
- CARDwGetCCKControlRate((void *)pDevice, RATE_1M),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- ///RSPINF_b_2
- BBvCalculateParameter(pDevice,
- 14,
- CARDwGetCCKControlRate((void *)pDevice, RATE_2M),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_b_5
- BBvCalculateParameter(pDevice,
- 14,
- CARDwGetCCKControlRate((void *)pDevice, RATE_5M),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_b_11
- BBvCalculateParameter(pDevice,
- 14,
- CARDwGetCCKControlRate((void *)pDevice, RATE_11M),
- PK_TYPE_11B,
- &wLen,
- &byServ,
- &bySignal
- );
-
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ)));
- //RSPINF_a_6
- s_vCalculateOFDMRParameter(RATE_6M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_9
- s_vCalculateOFDMRParameter(RATE_9M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_12
- s_vCalculateOFDMRParameter(RATE_12M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_18
- s_vCalculateOFDMRParameter(RATE_18M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_24
- s_vCalculateOFDMRParameter(RATE_24M,
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_36
- s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_48
- s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime));
- //RSPINF_a_54
- s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime));
-
- //RSPINF_a_72
- s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
- ePHYType,
- &byTxRate,
- &byRsvTime);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate,byRsvTime));
- //Set to Page0
- MACvSelectPage0(pDevice->PortOffset);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned char byServ = 0x00, bySignal = 0x00; //For CCK
+ unsigned short wLen = 0x0000;
+ unsigned char byTxRate, byRsvTime; //For OFDM
+
+ //Set to Page1
+ MACvSelectPage1(pDevice->PortOffset);
+
+ //RSPINF_b_1
+ BBvCalculateParameter(pDevice,
+ 14,
+ CARDwGetCCKControlRate((void *)pDevice, RATE_1M),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ ///RSPINF_b_2
+ BBvCalculateParameter(pDevice,
+ 14,
+ CARDwGetCCKControlRate((void *)pDevice, RATE_2M),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_b_5
+ BBvCalculateParameter(pDevice,
+ 14,
+ CARDwGetCCKControlRate((void *)pDevice, RATE_5M),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_b_11
+ BBvCalculateParameter(pDevice,
+ 14,
+ CARDwGetCCKControlRate((void *)pDevice, RATE_11M),
+ PK_TYPE_11B,
+ &wLen,
+ &byServ,
+ &bySignal
+);
+
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen, MAKEWORD(bySignal, byServ)));
+ //RSPINF_a_6
+ s_vCalculateOFDMRParameter(RATE_6M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_9
+ s_vCalculateOFDMRParameter(RATE_9M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_12
+ s_vCalculateOFDMRParameter(RATE_12M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_18
+ s_vCalculateOFDMRParameter(RATE_18M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_24
+ s_vCalculateOFDMRParameter(RATE_24M,
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_36
+ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_48
+ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate, byRsvTime));
+ //RSPINF_a_54
+ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate, byRsvTime));
+
+ //RSPINF_a_72
+ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M),
+ ePHYType,
+ &byTxRate,
+ &byRsvTime);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate, byRsvTime));
+ //Set to Page0
+ MACvSelectPage0(pDevice->PortOffset);
}
/*
@@ -1853,87 +1800,83 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
* Return Value: None.
*
*/
-void vUpdateIFS (void *pDeviceHandler)
+void vUpdateIFS(void *pDeviceHandler)
{
- //Set SIFS, DIFS, EIFS, SlotTime, CwMin
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- unsigned char byMaxMin = 0;
- if (pDevice->byPacketType==PK_TYPE_11A) {//0000 0000 0000 0000,11a
- pDevice->uSlot = C_SLOT_SHORT;
- pDevice->uSIFS = C_SIFS_A;
- pDevice->uDIFS = C_SIFS_A + 2*C_SLOT_SHORT;
- pDevice->uCwMin = C_CWMIN_A;
- byMaxMin = 4;
- }
- else if (pDevice->byPacketType==PK_TYPE_11B) {//0000 0001 0000 0000,11b
- pDevice->uSlot = C_SLOT_LONG;
- pDevice->uSIFS = C_SIFS_BG;
- pDevice->uDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
- pDevice->uCwMin = C_CWMIN_B;
- byMaxMin = 5;
- }
- else { // PK_TYPE_11GA & PK_TYPE_11GB
- pDevice->uSIFS = C_SIFS_BG;
- if (pDevice->bShortSlotTime) {
- pDevice->uSlot = C_SLOT_SHORT;
- } else {
- pDevice->uSlot = C_SLOT_LONG;
- }
- pDevice->uDIFS = C_SIFS_BG + 2*pDevice->uSlot;
- if (pDevice->wBasicRate & 0x0150) { //0000 0001 0101 0000,24M,12M,6M
- pDevice->uCwMin = C_CWMIN_A;
- byMaxMin = 4;
- }
- else {
- pDevice->uCwMin = C_CWMIN_B;
- byMaxMin = 5;
- }
- }
-
- pDevice->uCwMax = C_CWMAX;
- pDevice->uEIFS = C_EIFS;
- if (pDevice->byRFType == RF_RFMD2959) {
- // bcs TX_PE will reserve 3 us
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)(pDevice->uSIFS - 3));
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)(pDevice->uDIFS - 3));
- } else {
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)pDevice->uSIFS);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)pDevice->uDIFS);
- }
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, (unsigned char)pDevice->uEIFS);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, (unsigned char)pDevice->uSlot);
- byMaxMin |= 0xA0;//1010 1111,C_CWMAX = 1023
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, (unsigned char)byMaxMin);
+ //Set SIFS, DIFS, EIFS, SlotTime, CwMin
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ unsigned char byMaxMin = 0;
+ if (pDevice->byPacketType == PK_TYPE_11A) {//0000 0000 0000 0000,11a
+ pDevice->uSlot = C_SLOT_SHORT;
+ pDevice->uSIFS = C_SIFS_A;
+ pDevice->uDIFS = C_SIFS_A + 2*C_SLOT_SHORT;
+ pDevice->uCwMin = C_CWMIN_A;
+ byMaxMin = 4;
+ } else if (pDevice->byPacketType == PK_TYPE_11B) {//0000 0001 0000 0000,11b
+ pDevice->uSlot = C_SLOT_LONG;
+ pDevice->uSIFS = C_SIFS_BG;
+ pDevice->uDIFS = C_SIFS_BG + 2*C_SLOT_LONG;
+ pDevice->uCwMin = C_CWMIN_B;
+ byMaxMin = 5;
+ } else { // PK_TYPE_11GA & PK_TYPE_11GB
+ pDevice->uSIFS = C_SIFS_BG;
+ if (pDevice->bShortSlotTime) {
+ pDevice->uSlot = C_SLOT_SHORT;
+ } else {
+ pDevice->uSlot = C_SLOT_LONG;
+ }
+ pDevice->uDIFS = C_SIFS_BG + 2*pDevice->uSlot;
+ if (pDevice->wBasicRate & 0x0150) { //0000 0001 0101 0000,24M,12M,6M
+ pDevice->uCwMin = C_CWMIN_A;
+ byMaxMin = 4;
+ } else {
+ pDevice->uCwMin = C_CWMIN_B;
+ byMaxMin = 5;
+ }
+ }
+
+ pDevice->uCwMax = C_CWMAX;
+ pDevice->uEIFS = C_EIFS;
+ if (pDevice->byRFType == RF_RFMD2959) {
+ // bcs TX_PE will reserve 3 us
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)(pDevice->uSIFS - 3));
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)(pDevice->uDIFS - 3));
+ } else {
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SIFS, (unsigned char)pDevice->uSIFS);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_DIFS, (unsigned char)pDevice->uDIFS);
+ }
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_EIFS, (unsigned char)pDevice->uEIFS);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SLOT, (unsigned char)pDevice->uSlot);
+ byMaxMin |= 0xA0;//1010 1111,C_CWMAX = 1023
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_CWMAXMIN0, (unsigned char)byMaxMin);
}
-void CARDvUpdateBasicTopRate (void *pDeviceHandler)
+void CARDvUpdateBasicTopRate(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned char byTopOFDM = RATE_24M, byTopCCK = RATE_1M;
- unsigned char ii;
-
- //Determines the highest basic rate.
- for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ( (pDevice->wBasicRate) & ((unsigned short)(1<<ii)) ) {
- byTopOFDM = ii;
- break;
- }
- }
- pDevice->byTopOFDMBasicRate = byTopOFDM;
-
- for (ii = RATE_11M;; ii --) {
- if ( (pDevice->wBasicRate) & ((unsigned short)(1<<ii)) ) {
- byTopCCK = ii;
- break;
- }
- if (ii == RATE_1M)
- break;
- }
- pDevice->byTopCCKBasicRate = byTopCCK;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned char byTopOFDM = RATE_24M, byTopCCK = RATE_1M;
+ unsigned char ii;
+
+ //Determines the highest basic rate.
+ for (ii = RATE_54M; ii >= RATE_6M; ii--) {
+ if ((pDevice->wBasicRate) & ((unsigned short)(1<<ii))) {
+ byTopOFDM = ii;
+ break;
+ }
+ }
+ pDevice->byTopOFDMBasicRate = byTopOFDM;
+
+ for (ii = RATE_11M;; ii--) {
+ if ((pDevice->wBasicRate) & ((unsigned short)(1<<ii))) {
+ byTopCCK = ii;
+ break;
+ }
+ if (ii == RATE_1M)
+ break;
+ }
+ pDevice->byTopCCKBasicRate = byTopCCK;
}
-
/*
* Description: Set NIC Tx Basic Rate
*
@@ -1947,44 +1890,42 @@ void CARDvUpdateBasicTopRate (void *pDeviceHandler)
* Return Value: true if succeeded; false if failed.
*
*/
-bool CARDbAddBasicRate (void *pDeviceHandler, unsigned short wRateIdx)
+bool CARDbAddBasicRate(void *pDeviceHandler, unsigned short wRateIdx)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- unsigned short wRate = (unsigned short)(1<<wRateIdx);
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned short wRate = (unsigned short)(1<<wRateIdx);
- pDevice->wBasicRate |= wRate;
+ pDevice->wBasicRate |= wRate;
- //Determines the highest basic rate.
- CARDvUpdateBasicTopRate((void *)pDevice);
+ //Determines the highest basic rate.
+ CARDvUpdateBasicTopRate((void *)pDevice);
- return(true);
+ return true;
}
-bool CARDbIsOFDMinBasicRate (void *pDeviceHandler)
+bool CARDbIsOFDMinBasicRate(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
- int ii;
-
- for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ((pDevice->wBasicRate) & ((unsigned short)(1<<ii)))
- return true;
- }
- return false;
+ PSDevice pDevice = (PSDevice)pDeviceHandler;
+ int ii;
+
+ for (ii = RATE_54M; ii >= RATE_6M; ii--) {
+ if ((pDevice->wBasicRate) & ((unsigned short)(1 << ii)))
+ return true;
+ }
+ return false;
}
-unsigned char CARDbyGetPktType (void *pDeviceHandler)
+unsigned char CARDbyGetPktType(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
-
- if (pDevice->byBBType == BB_TYPE_11A || pDevice->byBBType == BB_TYPE_11B) {
- return (unsigned char)pDevice->byBBType;
- }
- else if (CARDbIsOFDMinBasicRate((void *)pDevice)) {
- return PK_TYPE_11GA;
- }
- else {
- return PK_TYPE_11GB;
- }
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+
+ if (pDevice->byBBType == BB_TYPE_11A || pDevice->byBBType == BB_TYPE_11B) {
+ return (unsigned char)pDevice->byBBType;
+ } else if (CARDbIsOFDMinBasicRate((void *)pDevice)) {
+ return PK_TYPE_11GA;
+ } else {
+ return PK_TYPE_11GB;
+ }
}
/*
@@ -2000,23 +1941,22 @@ unsigned char CARDbyGetPktType (void *pDeviceHandler)
* Return Value: none
*
*/
-void CARDvSetLoopbackMode (unsigned long dwIoBase, unsigned short wLoopbackMode)
+void CARDvSetLoopbackMode(unsigned long dwIoBase, unsigned short wLoopbackMode)
{
- switch(wLoopbackMode) {
- case CARD_LB_NONE:
- case CARD_LB_MAC:
- case CARD_LB_PHY:
- break;
- default:
- ASSERT(false);
- break;
- }
- // set MAC loopback
- MACvSetLoopbackMode(dwIoBase, LOBYTE(wLoopbackMode));
- // set Baseband loopback
+ switch (wLoopbackMode) {
+ case CARD_LB_NONE:
+ case CARD_LB_MAC:
+ case CARD_LB_PHY:
+ break;
+ default:
+ ASSERT(false);
+ break;
+ }
+ // set MAC loopback
+ MACvSetLoopbackMode(dwIoBase, LOBYTE(wLoopbackMode));
+ // set Baseband loopback
}
-
/*
* Description: Software Reset NIC
*
@@ -2029,18 +1969,17 @@ void CARDvSetLoopbackMode (unsigned long dwIoBase, unsigned short wLoopbackMode)
* Return Value: none
*
*/
-bool CARDbSoftwareReset (void *pDeviceHandler)
+bool CARDbSoftwareReset(void *pDeviceHandler)
{
- PSDevice pDevice = (PSDevice) pDeviceHandler;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
- // reset MAC
- if (!MACbSafeSoftwareReset(pDevice->PortOffset))
- return false;
+ // reset MAC
+ if (!MACbSafeSoftwareReset(pDevice->PortOffset))
+ return false;
- return true;
+ return true;
}
-
/*
* Description: Calculate TSF offset of two TSF input
* Get TSF Offset from RxBCN's TSF and local TSF
@@ -2056,30 +1995,28 @@ bool CARDbSoftwareReset (void *pDeviceHandler)
* Return Value: TSF Offset value
*
*/
-QWORD CARDqGetTSFOffset (unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2)
+QWORD CARDqGetTSFOffset(unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2)
{
- QWORD qwTSFOffset;
- unsigned short wRxBcnTSFOffst= 0;
-
- HIDWORD(qwTSFOffset) = 0;
- LODWORD(qwTSFOffset) = 0;
- wRxBcnTSFOffst = cwRXBCNTSFOff[byRxRate%MAX_RATE];
- (qwTSF2).u.dwLowDword += (unsigned long)(wRxBcnTSFOffst);
- if ((qwTSF2).u.dwLowDword < (unsigned long)(wRxBcnTSFOffst)) {
- (qwTSF2).u.dwHighDword++;
- }
- LODWORD(qwTSFOffset) = LODWORD(qwTSF1) - LODWORD(qwTSF2);
- if (LODWORD(qwTSF1) < LODWORD(qwTSF2)) {
- // if borrow needed
- HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2) - 1 ;
- }
- else {
- HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2);
- };
- return (qwTSFOffset);
+ QWORD qwTSFOffset;
+ unsigned short wRxBcnTSFOffst = 0;
+
+ HIDWORD(qwTSFOffset) = 0;
+ LODWORD(qwTSFOffset) = 0;
+ wRxBcnTSFOffst = cwRXBCNTSFOff[byRxRate%MAX_RATE];
+ (qwTSF2).u.dwLowDword += (unsigned long)(wRxBcnTSFOffst);
+ if ((qwTSF2).u.dwLowDword < (unsigned long)(wRxBcnTSFOffst)) {
+ (qwTSF2).u.dwHighDword++;
+ }
+ LODWORD(qwTSFOffset) = LODWORD(qwTSF1) - LODWORD(qwTSF2);
+ if (LODWORD(qwTSF1) < LODWORD(qwTSF2)) {
+ // if borrow needed
+ HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2) - 1;
+ } else {
+ HIDWORD(qwTSFOffset) = HIDWORD(qwTSF1) - HIDWORD(qwTSF2);
+ };
+ return qwTSFOffset;
}
-
/*
* Description: Read NIC TSF counter
* Get local TSF counter
@@ -2093,26 +2030,25 @@ QWORD CARDqGetTSFOffset (unsigned char byRxRate, QWORD qwTSF1, QWORD qwTSF2)
* Return Value: true if success; otherwise false
*
*/
-bool CARDbGetCurrentTSF (unsigned long dwIoBase, PQWORD pqwCurrTSF)
+bool CARDbGetCurrentTSF(unsigned long dwIoBase, PQWORD pqwCurrTSF)
{
- unsigned short ww;
- unsigned char byData;
-
- MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_TFTCTL, &byData);
- if ( !(byData & TFTCTL_TSFCNTRRD))
- break;
- }
- if (ww == W_MAX_TIMEOUT)
- return(false);
- VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR, &LODWORD(*pqwCurrTSF));
- VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR + 4, &HIDWORD(*pqwCurrTSF));
-
- return(true);
+ unsigned short ww;
+ unsigned char byData;
+
+ MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_TFTCTL, &byData);
+ if (!(byData & TFTCTL_TSFCNTRRD))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT)
+ return false;
+ VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR, &LODWORD(*pqwCurrTSF));
+ VNSvInPortD(dwIoBase + MAC_REG_TSFCNTR + 4, &HIDWORD(*pqwCurrTSF));
+
+ return true;
}
-
/*
* Description: Read NIC TSF counter
* Get NEXTTBTT from adjusted TSF and Beacon Interval
@@ -2127,36 +2063,34 @@ bool CARDbGetCurrentTSF (unsigned long dwIoBase, PQWORD pqwCurrTSF)
* Return Value: TSF value of next Beacon
*
*/
-QWORD CARDqGetNextTBTT (QWORD qwTSF, unsigned short wBeaconInterval)
+QWORD CARDqGetNextTBTT(QWORD qwTSF, unsigned short wBeaconInterval)
{
-
- unsigned int uLowNextTBTT;
- unsigned int uHighRemain, uLowRemain;
- unsigned int uBeaconInterval;
-
- uBeaconInterval = wBeaconInterval * 1024;
- // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval
- uLowNextTBTT = (LODWORD(qwTSF) >> 10) << 10;
- // low dword (mod) bcn
- uLowRemain = (uLowNextTBTT) % uBeaconInterval;
+ unsigned int uLowNextTBTT;
+ unsigned int uHighRemain, uLowRemain;
+ unsigned int uBeaconInterval;
+
+ uBeaconInterval = wBeaconInterval * 1024;
+ // Next TBTT = ((local_current_TSF / beacon_interval) + 1) * beacon_interval
+ uLowNextTBTT = (LODWORD(qwTSF) >> 10) << 10;
+ // low dword (mod) bcn
+ uLowRemain = (uLowNextTBTT) % uBeaconInterval;
// uHighRemain = ((0x80000000 % uBeaconInterval)* 2 * HIDWORD(qwTSF))
// % uBeaconInterval;
- // high dword (mod) bcn
- uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwTSF))
- % uBeaconInterval;
- uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval;
- uLowRemain = uBeaconInterval - uLowRemain;
+ // high dword (mod) bcn
+ uHighRemain = (((0xffffffff % uBeaconInterval) + 1) * HIDWORD(qwTSF))
+ % uBeaconInterval;
+ uLowRemain = (uHighRemain + uLowRemain) % uBeaconInterval;
+ uLowRemain = uBeaconInterval - uLowRemain;
- // check if carry when add one beacon interval
- if ((~uLowNextTBTT) < uLowRemain)
- HIDWORD(qwTSF) ++ ;
+ // check if carry when add one beacon interval
+ if ((~uLowNextTBTT) < uLowRemain)
+ HIDWORD(qwTSF)++;
- LODWORD(qwTSF) = uLowNextTBTT + uLowRemain;
+ LODWORD(qwTSF) = uLowNextTBTT + uLowRemain;
- return (qwTSF);
+ return qwTSF;
}
-
/*
* Description: Set NIC TSF counter for first Beacon time
* Get NEXTTBTT from adjusted TSF and Beacon Interval
@@ -2171,24 +2105,22 @@ QWORD CARDqGetNextTBTT (QWORD qwTSF, unsigned short wBeaconInterval)
* Return Value: none
*
*/
-void CARDvSetFirstNextTBTT (unsigned long dwIoBase, unsigned short wBeaconInterval)
+void CARDvSetFirstNextTBTT(unsigned long dwIoBase, unsigned short wBeaconInterval)
{
-
- QWORD qwNextTBTT;
-
- HIDWORD(qwNextTBTT) = 0;
- LODWORD(qwNextTBTT) = 0;
- CARDbGetCurrentTSF(dwIoBase, &qwNextTBTT); //Get Local TSF counter
- qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval);
- // Set NextTBTT
- VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT));
- VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT));
- MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:First Next TBTT[%8xh:%8xh] \n", HIDWORD(qwNextTBTT), LODWORD(qwNextTBTT));
- return;
+ QWORD qwNextTBTT;
+
+ HIDWORD(qwNextTBTT) = 0;
+ LODWORD(qwNextTBTT) = 0;
+ CARDbGetCurrentTSF(dwIoBase, &qwNextTBTT); //Get Local TSF counter
+ qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval);
+ // Set NextTBTT
+ VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwNextTBTT));
+ VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwNextTBTT));
+ MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Card:First Next TBTT[%8xh:%8xh] \n", HIDWORD(qwNextTBTT), LODWORD(qwNextTBTT));
+ return;
}
-
/*
* Description: Sync NIC TSF counter for Beacon time
* Get NEXTTBTT and write to HW
@@ -2204,23 +2136,15 @@ void CARDvSetFirstNextTBTT (unsigned long dwIoBase, unsigned short wBeaconInterv
* Return Value: none
*
*/
-void CARDvUpdateNextTBTT (unsigned long dwIoBase, QWORD qwTSF, unsigned short wBeaconInterval)
+void CARDvUpdateNextTBTT(unsigned long dwIoBase, QWORD qwTSF, unsigned short wBeaconInterval)
{
-
- qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval);
- // Set NextTBTT
- VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwTSF));
- VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwTSF));
- MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Card:Update Next TBTT[%8xh:%8xh] \n",
- (unsigned int) HIDWORD(qwTSF), (unsigned int) LODWORD(qwTSF));
-
- return;
+ qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval);
+ // Set NextTBTT
+ VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT, LODWORD(qwTSF));
+ VNSvOutPortD(dwIoBase + MAC_REG_NEXTTBTT + 4, HIDWORD(qwTSF));
+ MACvRegBitsOn(dwIoBase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Card:Update Next TBTT[%8xh:%8xh] \n",
+ (unsigned int) HIDWORD(qwTSF), (unsigned int) LODWORD(qwTSF));
+
+ return;
}
-
-
-
-
-
-
-
diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h
index e0836e1d5116..ac6e2b4d0fd0 100644
--- a/drivers/staging/vt6655/card.h
+++ b/drivers/staging/vt6655/card.h
@@ -41,7 +41,6 @@
#define CARD_LB_MAC MAKEWORD(MAC_LB_INTERNAL, 0) // PHY must ISO, avoid MAC loopback packet go out
#define CARD_LB_PHY MAKEWORD(MAC_LB_EXT, 0)
-
#define DEFAULT_MSDU_LIFETIME 512 // ms
#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 // 64us
@@ -53,34 +52,32 @@
#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G+CB_MAX_CHANNEL_5G)
typedef enum _CARD_PHY_TYPE {
- PHY_TYPE_AUTO,
- PHY_TYPE_11B,
- PHY_TYPE_11G,
- PHY_TYPE_11A
+ PHY_TYPE_AUTO,
+ PHY_TYPE_11B,
+ PHY_TYPE_11G,
+ PHY_TYPE_11A
} CARD_PHY_TYPE, *PCARD_PHY_TYPE;
typedef enum _CARD_PKT_TYPE {
- PKT_TYPE_802_11_BCN,
- PKT_TYPE_802_11_MNG,
- PKT_TYPE_802_11_DATA,
- PKT_TYPE_802_11_ALL
+ PKT_TYPE_802_11_BCN,
+ PKT_TYPE_802_11_MNG,
+ PKT_TYPE_802_11_DATA,
+ PKT_TYPE_802_11_ALL
} CARD_PKT_TYPE, *PCARD_PKT_TYPE;
typedef enum _CARD_STATUS_TYPE {
- CARD_STATUS_MEDIA_CONNECT,
- CARD_STATUS_MEDIA_DISCONNECT,
- CARD_STATUS_PMKID
+ CARD_STATUS_MEDIA_CONNECT,
+ CARD_STATUS_MEDIA_DISCONNECT,
+ CARD_STATUS_PMKID
} CARD_STATUS_TYPE, *PCARD_STATUS_TYPE;
typedef enum _CARD_OP_MODE {
- OP_MODE_INFRASTRUCTURE,
- OP_MODE_ADHOC,
- OP_MODE_AP,
- OP_MODE_UNKNOWN
+ OP_MODE_INFRASTRUCTURE,
+ OP_MODE_ADHOC,
+ OP_MODE_AP,
+ OP_MODE_UNKNOWN
} CARD_OP_MODE, *PCARD_OP_MODE;
-
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -119,80 +116,76 @@ bool CARDbSetBSSID(void *pDeviceHandler, unsigned char *pbyBSSID, CARD_OP_MODE e
bool
CARDbPowerDown(
- void *pDeviceHandler
- );
+ void *pDeviceHandler
+);
bool CARDbSetTxDataRate(
- void *pDeviceHandler,
- unsigned short wDataRate
- );
-
+ void *pDeviceHandler,
+ unsigned short wDataRate
+);
-bool CARDbRemoveKey (void *pDeviceHandler, unsigned char *pbyBSSID);
+bool CARDbRemoveKey(void *pDeviceHandler, unsigned char *pbyBSSID);
bool
-CARDbAdd_PMKID_Candidate (
- void *pDeviceHandler,
- unsigned char *pbyBSSID,
- bool bRSNCapExist,
- unsigned short wRSNCap
- );
+CARDbAdd_PMKID_Candidate(
+ void *pDeviceHandler,
+ unsigned char *pbyBSSID,
+ bool bRSNCapExist,
+ unsigned short wRSNCap
+);
void *
-CARDpGetCurrentAddress (
- void *pDeviceHandler
- );
+CARDpGetCurrentAddress(
+ void *pDeviceHandler
+);
bool
-CARDbStartMeasure (
- void *pDeviceHandler,
- void *pvMeasureEIDs,
- unsigned int uNumOfMeasureEIDs
- );
+CARDbStartMeasure(
+ void *pDeviceHandler,
+ void *pvMeasureEIDs,
+ unsigned int uNumOfMeasureEIDs
+);
bool
-CARDbChannelSwitch (
- void *pDeviceHandler,
- unsigned char byMode,
- unsigned char byNewChannel,
- unsigned char byCount
- );
+CARDbChannelSwitch(
+ void *pDeviceHandler,
+ unsigned char byMode,
+ unsigned char byNewChannel,
+ unsigned char byCount
+);
bool
-CARDbSetQuiet (
- void *pDeviceHandler,
- bool bResetQuiet,
- unsigned char byQuietCount,
- unsigned char byQuietPeriod,
- unsigned short wQuietDuration,
- unsigned short wQuietOffset
- );
+CARDbSetQuiet(
+ void *pDeviceHandler,
+ bool bResetQuiet,
+ unsigned char byQuietCount,
+ unsigned char byQuietPeriod,
+ unsigned short wQuietDuration,
+ unsigned short wQuietOffset
+);
bool
-CARDbStartQuiet (
- void *pDeviceHandler
- );
+CARDbStartQuiet(
+ void *pDeviceHandler
+);
void
-CARDvSetPowerConstraint (
- void *pDeviceHandler,
- unsigned char byChannel,
- char byPower
- );
+CARDvSetPowerConstraint(
+ void *pDeviceHandler,
+ unsigned char byChannel,
+ char byPower
+);
void
-CARDvGetPowerCapability (
- void *pDeviceHandler,
- unsigned char *pbyMinPower,
- unsigned char *pbyMaxPower
- );
+CARDvGetPowerCapability(
+ void *pDeviceHandler,
+ unsigned char *pbyMinPower,
+ unsigned char *pbyMaxPower
+);
char
-CARDbyGetTransmitPower (
- void *pDeviceHandler
- );
+CARDbyGetTransmitPower(
+ void *pDeviceHandler
+);
#endif // __CARD_H__
-
-
-
diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c
index aa76e39a46f4..ba9481fa654f 100644
--- a/drivers/staging/vt6655/channel.c
+++ b/drivers/staging/vt6655/channel.c
@@ -37,63 +37,63 @@ static int msglevel = MSG_LEVEL_INFO;
static SChannelTblElement sChannelTbl[CARD_MAX_CHANNEL_TBL + 1] =
{
- {0, 0, false, 0},
- {1, 2412, true, 0},
- {2, 2417, true, 0},
- {3, 2422, true, 0},
- {4, 2427, true, 0},
- {5, 2432, true, 0},
- {6, 2437, true, 0},
- {7, 2442, true, 0},
- {8, 2447, true, 0},
- {9, 2452, true, 0},
- {10, 2457, true, 0},
- {11, 2462, true, 0},
- {12, 2467, true, 0},
- {13, 2472, true, 0},
- {14, 2484, true, 0},
- {183, 4915, true, 0},
- {184, 4920, true, 0},
- {185, 4925, true, 0},
- {187, 4935, true, 0},
- {188, 4940, true, 0},
- {189, 4945, true, 0},
- {192, 4960, true, 0},
- {196, 4980, true, 0},
- {7, 5035, true, 0},
- {8, 5040, true, 0},
- {9, 5045, true, 0},
- {11, 5055, true, 0},
- {12, 5060, true, 0},
- {16, 5080, true, 0},
- {34, 5170, true, 0},
- {36, 5180, true, 0},
- {38, 5190, true, 0},
- {40, 5200, true, 0},
- {42, 5210, true, 0},
- {44, 5220, true, 0},
- {46, 5230, true, 0},
- {48, 5240, true, 0},
- {52, 5260, true, 0},
- {56, 5280, true, 0},
- {60, 5300, true, 0},
- {64, 5320, true, 0},
- {100, 5500, true, 0},
- {104, 5520, true, 0},
- {108, 5540, true, 0},
- {112, 5560, true, 0},
- {116, 5580, true, 0},
- {120, 5600, true, 0},
- {124, 5620, true, 0},
- {128, 5640, true, 0},
- {132, 5660, true, 0},
- {136, 5680, true, 0},
- {140, 5700, true, 0},
- {149, 5745, true, 0},
- {153, 5765, true, 0},
- {157, 5785, true, 0},
- {161, 5805, true, 0},
- {165, 5825, true, 0}
+ {0, 0, false, 0},
+ {1, 2412, true, 0},
+ {2, 2417, true, 0},
+ {3, 2422, true, 0},
+ {4, 2427, true, 0},
+ {5, 2432, true, 0},
+ {6, 2437, true, 0},
+ {7, 2442, true, 0},
+ {8, 2447, true, 0},
+ {9, 2452, true, 0},
+ {10, 2457, true, 0},
+ {11, 2462, true, 0},
+ {12, 2467, true, 0},
+ {13, 2472, true, 0},
+ {14, 2484, true, 0},
+ {183, 4915, true, 0},
+ {184, 4920, true, 0},
+ {185, 4925, true, 0},
+ {187, 4935, true, 0},
+ {188, 4940, true, 0},
+ {189, 4945, true, 0},
+ {192, 4960, true, 0},
+ {196, 4980, true, 0},
+ {7, 5035, true, 0},
+ {8, 5040, true, 0},
+ {9, 5045, true, 0},
+ {11, 5055, true, 0},
+ {12, 5060, true, 0},
+ {16, 5080, true, 0},
+ {34, 5170, true, 0},
+ {36, 5180, true, 0},
+ {38, 5190, true, 0},
+ {40, 5200, true, 0},
+ {42, 5210, true, 0},
+ {44, 5220, true, 0},
+ {46, 5230, true, 0},
+ {48, 5240, true, 0},
+ {52, 5260, true, 0},
+ {56, 5280, true, 0},
+ {60, 5300, true, 0},
+ {64, 5320, true, 0},
+ {100, 5500, true, 0},
+ {104, 5520, true, 0},
+ {108, 5540, true, 0},
+ {112, 5560, true, 0},
+ {116, 5580, true, 0},
+ {120, 5600, true, 0},
+ {124, 5620, true, 0},
+ {128, 5640, true, 0},
+ {132, 5660, true, 0},
+ {136, 5680, true, 0},
+ {140, 5700, true, 0},
+ {149, 5745, true, 0},
+ {153, 5765, true, 0},
+ {157, 5785, true, 0},
+ {161, 5805, true, 0},
+ {165, 5825, true, 0}
};
/************************************************************************
@@ -112,244 +112,244 @@ static struct
************************************************************************/
/* Country Available channels, ended with 0 */
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 */
-{CCODE_FCC, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_TELEC, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 23, 0, 0, 23, 0, 23, 23, 0, 23, 0, 0, 23, 23, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ETSI, {'E','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_RESV3, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV4, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV5, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV6, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV7, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV8, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESV9, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVa, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVb, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVc, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVd, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RESVe, {' ',' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALLBAND, {' ',' '}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALBANIA, {'A','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ALGERIA, {'D','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ARGENTINA, {'A','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
-{CCODE_ARMENIA, {'A','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_AUSTRALIA, {'A','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_AUSTRIA, {'A','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_AZERBAIJAN, {'A','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BAHRAIN, {'B','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELARUS, {'B','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELGIUM, {'B','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BELIZE, {'B','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_BOLIVIA, {'B','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_BRAZIL, {'B','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_BRUNEI_DARUSSALAM, {'B','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_BULGARIA, {'B','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0} },
-{CCODE_CANADA, {'C','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_CHILE, {'C','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17} },
-{CCODE_CHINA, {'C','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_COLOMBIA, {'C','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_COSTA_RICA, {'C','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_CROATIA, {'H','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_CYPRUS, {'C','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_CZECH, {'C','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_DENMARK, {'D','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_DOMINICAN_REPUBLIC, {'D','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_ECUADOR, {'E','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_EGYPT, {'E','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_EL_SALVADOR, {'S','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ESTONIA, {'E','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_FINLAND, {'F','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_FRANCE, {'F','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GERMANY, {'D','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_GREECE, {'G','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GEORGIA, {'G','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_GUATEMALA, {'G','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_HONDURAS, {'H','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_HONG_KONG, {'H','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_HUNGARY, {'H','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ICELAND, {'I','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_INDIA, {'I','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_INDONESIA, {'I','D'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_IRAN, {'I','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_IRELAND, {'I','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_ITALY, {'I','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_ISRAEL, {'I','L'}, { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JAPAN, {'J','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JORDAN, {'J','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_KAZAKHSTAN, {'K','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_KUWAIT, {'K','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LATVIA, {'L','V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LEBANON, {'L','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LEICHTENSTEIN, {'L','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_LITHUANIA, {'L','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_LUXEMBURG, {'L','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_MACAU, {'M','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_MACEDONIA, {'M','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MALTA, {'M','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_MALAYSIA, {'M','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MEXICO, {'M','X'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_MONACO, {'M','C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MOROCCO, {'M','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_NETHERLANDS, {'N','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_NEW_ZEALAND, {'N','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_NORTH_KOREA, {'K','P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
-{CCODE_NORWAY, {'N','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_OMAN, {'O','M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PAKISTAN, {'P','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PANAMA, {'P','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_PERU, {'P','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_PHILIPPINES, {'P','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_POLAND, {'P','L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_PORTUGAL, {'P','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_PUERTO_RICO, {'P','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_QATAR, {'Q','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ROMANIA, {'R','O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_RUSSIA, {'R','U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SAUDI_ARABIA, {'S','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SINGAPORE, {'S','G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20} },
-{CCODE_SLOVAKIA, {'S','K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_SLOVENIA, {'S','I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SOUTH_AFRICA, {'Z','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SOUTH_KOREA, {'K','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
-{CCODE_SPAIN, {'E','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
-{CCODE_SWEDEN, {'S','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_SWITZERLAND, {'C','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_SYRIA, {'S','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TAIWAN, {'T','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
-{CCODE_THAILAND, {'T','H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
-{CCODE_TRINIDAD_TOBAGO, {'T','T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TUNISIA, {'T','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_TURKEY, {'T','R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UK, {'G','B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
-{CCODE_UKRAINE, {'U','A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UNITED_ARAB_EMIRATES, {'A','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_UNITED_STATES, {'U','S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
- , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
-{CCODE_URUGUAY, {'U','Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
-{CCODE_UZBEKISTAN, {'U','Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_VENEZUELA, {'V','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
- , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
-{CCODE_VIETNAM, {'V','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_YEMEN, {'Y','E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_ZIMBABWE, {'Z','W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_JAPAN_W52_W53, {'J','J'}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
-{CCODE_MAX, {'U','N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
+ {CCODE_FCC, {'U' , 'S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_TELEC, {'J' , 'P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 23, 0, 0, 23, 0, 23, 23, 0, 23, 0, 0, 23, 23, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ETSI, {'E' , 'U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_RESV3, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV4, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV5, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV6, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV7, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV8, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESV9, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESVa, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESVb, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESVc, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESVd, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RESVe, {' ' , ' '}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ALLBAND, {' ' , ' '}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ALBANIA, {'A' , 'L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ALGERIA, {'D' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ARGENTINA, {'A' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
+ {CCODE_ARMENIA, {'A' , 'M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_AUSTRALIA, {'A' , 'U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_AUSTRIA, {'A' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 15, 0, 15, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_AZERBAIJAN, {'A' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_BAHRAIN, {'B' , 'H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_BELARUS, {'B' , 'Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_BELGIUM, {'B' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_BELIZE, {'B' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_BOLIVIA, {'B' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_BRAZIL, {'B' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_BRUNEI_DARUSSALAM, {'B' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_BULGARIA, {'B' , 'G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 0, 0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0} },
+ {CCODE_CANADA, {'C' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_CHILE, {'C' , 'L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17} },
+ {CCODE_CHINA, {'C' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_COLOMBIA, {'C' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_COSTA_RICA, {'C' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_CROATIA, {'H' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_CYPRUS, {'C' , 'Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_CZECH, {'C' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_DENMARK, {'D' , 'K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_DOMINICAN_REPUBLIC, {'D' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_ECUADOR, {'E' , 'C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_EGYPT, {'E' , 'G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_EL_SALVADOR, {'S' , 'V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ESTONIA, {'E' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_FINLAND, {'F' , 'I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_FRANCE, {'F' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_GERMANY, {'D' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_GREECE, {'G' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_GEORGIA, {'G' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_GUATEMALA, {'G' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_HONDURAS, {'H' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_HONG_KONG, {'H' , 'K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_HUNGARY, {'H' , 'U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ICELAND, {'I' , 'S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_INDIA, {'I' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_INDONESIA, {'I' , 'D'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_IRAN, {'I' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_IRELAND, {'I' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_ITALY, {'I' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_ISRAEL, {'I' , 'L'}, { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_JAPAN, {'J' , 'P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_JORDAN, {'J' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_KAZAKHSTAN, {'K' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_KUWAIT, {'K' , 'W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_LATVIA, {'L' , 'V'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_LEBANON, {'L' , 'B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_LEICHTENSTEIN, {'L' , 'I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_LITHUANIA, {'L' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_LUXEMBURG, {'L' , 'U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_MACAU, {'M' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_MACEDONIA, {'M' , 'K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_MALTA, {'M' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+ {CCODE_MALAYSIA, {'M' , 'Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_MEXICO, {'M' , 'X'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_MONACO, {'M' , 'C'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_MOROCCO, {'M' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_NETHERLANDS, {'N' , 'L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_NEW_ZEALAND, {'N' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 23, 0, 23, 0, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_NORTH_KOREA, {'K' , 'P'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
+ {CCODE_NORWAY, {'N' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_OMAN, {'O' , 'M'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_PAKISTAN, {'P' , 'K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_PANAMA, {'P' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_PERU, {'P' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_PHILIPPINES, {'P' , 'H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_POLAND, {'P' , 'L'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_PORTUGAL, {'P' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_PUERTO_RICO, {'P' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_QATAR, {'Q' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ROMANIA, {'R' , 'O'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_RUSSIA, {'R' , 'U'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_SAUDI_ARABIA, {'S' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_SINGAPORE, {'S' , 'G'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20} },
+ {CCODE_SLOVAKIA, {'S' , 'K'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+ {CCODE_SLOVENIA, {'S' , 'I'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_SOUTH_AFRICA, {'Z' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_SOUTH_KOREA, {'K' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
+ {CCODE_SPAIN, {'E' , 'S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 16, 0, 16, 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 0} },
+ {CCODE_SWEDEN, {'S' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_SWITZERLAND, {'C' , 'H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_SYRIA, {'S' , 'Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_TAIWAN, {'T' , 'W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 0} },
+ {CCODE_THAILAND, {'T' , 'H'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
+ {CCODE_TRINIDAD_TOBAGO, {'T' , 'T'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 18, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_TUNISIA, {'T' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_TURKEY, {'T' , 'R'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_UK, {'G' , 'B'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 20, 0, 20, 0, 20, 20, 20, 20, 20, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0} },
+ {CCODE_UKRAINE, {'U' , 'A'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_UNITED_ARAB_EMIRATES, {'A' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_UNITED_STATES, {'U' , 'S'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}
+ , { 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 17, 0, 17, 0, 17, 23, 23, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 30, 30, 30, 30} },
+ {CCODE_URUGUAY, {'U' , 'Y'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
+ {CCODE_UZBEKISTAN, {'U' , 'Z'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_VENEZUELA, {'V' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0}
+ , { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23, 0} },
+ {CCODE_VIETNAM, {'V' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_YEMEN, {'Y' , 'E'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_ZIMBABWE, {'Z' , 'W'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_JAPAN_W52_W53, {'J' , 'J'}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {CCODE_MAX, {'U' , 'N'}, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+ , { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 */
};
@@ -382,8 +382,7 @@ bool is_channel_valid(unsigned int ChannelIndex)
* If Channel Index is invalid, return invalid
*/
if ((ChannelIndex > CB_MAX_CHANNEL) ||
- (ChannelIndex == 0))
- {
+ (ChannelIndex == 0)) {
bValid = false;
goto exit;
}
@@ -391,8 +390,7 @@ bool is_channel_valid(unsigned int ChannelIndex)
bValid = sChannelTbl[ChannelIndex].bValid;
exit:
- return (bValid);
-
+ return bValid;
}
/**
@@ -410,11 +408,11 @@ exit:
bool channel_get_list(unsigned int uCountryCodeIdx, unsigned char *pbyChannelTable)
{
if (uCountryCodeIdx >= CCODE_MAX)
- return (false);
+ return false;
memcpy(pbyChannelTable, ChannelRuleTab[uCountryCodeIdx].bChannelIdxList, CB_MAX_CHANNEL);
- return (true);
+ return true;
}
void init_channel_table(void *pDeviceHandler)
@@ -423,75 +421,74 @@ void init_channel_table(void *pDeviceHandler)
bool bMultiBand = false;
unsigned int ii;
- for(ii = 1 ; ii<=CARD_MAX_CHANNEL_TBL ; ii++) {
+ for (ii = 1; ii <= CARD_MAX_CHANNEL_TBL; ii++) {
sChannelTbl[ii].bValid = false;
}
switch (pDevice->byRFType) {
- case RF_RFMD2959 :
- case RF_AIROHA :
- case RF_AL2230S:
- case RF_UW2451 :
- case RF_VT3226 :
- //printk("chester-false\n");
- bMultiBand = false;
- break;
- case RF_AIROHA7230 :
- case RF_UW2452 :
- case RF_NOTHING :
- default :
- bMultiBand = true;
- break;
+ case RF_RFMD2959:
+ case RF_AIROHA:
+ case RF_AL2230S:
+ case RF_UW2451:
+ case RF_VT3226:
+ bMultiBand = false;
+ break;
+ case RF_AIROHA7230:
+ case RF_UW2452:
+ case RF_NOTHING:
+ default:
+ bMultiBand = true;
+ break;
}
if ((pDevice->dwDiagRefCount != 0) || (pDevice->b11hEnable == true)) {
if (bMultiBand == true) {
- for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
- sChannelTbl[ii+1].bValid = true;
- pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ for (ii = 0; ii < CARD_MAX_CHANNEL_TBL; ii++) {
+ sChannelTbl[ii + 1].bValid = true;
+ pDevice->abyRegPwr[ii + 1] = pDevice->abyOFDMDefaultPwr[ii + 1];
+ pDevice->abyLocalPwr[ii + 1] = pDevice->abyOFDMDefaultPwr[ii + 1];
}
- for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
- pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ for (ii = 0; ii < CHANNEL_MAX_24G; ii++) {
+ pDevice->abyRegPwr[ii + 1] = pDevice->abyCCKDefaultPwr[ii + 1];
+ pDevice->abyLocalPwr[ii + 1] = pDevice->abyCCKDefaultPwr[ii + 1];
}
} else {
- for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
+ for (ii = 0; ii < CHANNEL_MAX_24G; ii++) {
//2008-8-4 <add> by chester
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = true;
- pDevice->abyRegPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
- pDevice->abyLocalPwr[ii+1] = pDevice->abyCCKDefaultPwr[ii+1];
+ sChannelTbl[ii + 1].bValid = true;
+ pDevice->abyRegPwr[ii + 1] = pDevice->abyCCKDefaultPwr[ii + 1];
+ pDevice->abyLocalPwr[ii + 1] = pDevice->abyCCKDefaultPwr[ii + 1];
}
}
}
} else if (pDevice->byZoneType <= CCODE_MAX) {
if (bMultiBand == true) {
- for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
+ for (ii = 0; ii < CARD_MAX_CHANNEL_TBL; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = true;
- pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ sChannelTbl[ii + 1].bValid = true;
+ pDevice->abyRegPwr[ii + 1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ pDevice->abyLocalPwr[ii + 1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
}
}
} else {
- for(ii = 0 ; ii<CHANNEL_MAX_24G ; ii++) {
+ for (ii = 0; ii < CHANNEL_MAX_24G; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- sChannelTbl[ii+1].bValid = true;
- pDevice->abyRegPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
- pDevice->abyLocalPwr[ii+1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ sChannelTbl[ii + 1].bValid = true;
+ pDevice->abyRegPwr[ii + 1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
+ pDevice->abyLocalPwr[ii + 1] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
}
}
}
}
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO"Zone=[%d][%c][%c]!!\n",pDevice->byZoneType,ChannelRuleTab[pDevice->byZoneType].chCountryCode[0],ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]);
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Zone=[%d][%c][%c]!!\n", pDevice->byZoneType, ChannelRuleTab[pDevice->byZoneType].chCountryCode[0], ChannelRuleTab[pDevice->byZoneType].chCountryCode[1]);
- for(ii = 0 ; ii<CARD_MAX_CHANNEL_TBL ; ii++) {
- if (pDevice->abyRegPwr[ii+1] == 0)
- pDevice->abyRegPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
- if (pDevice->abyLocalPwr[ii+1] == 0)
- pDevice->abyLocalPwr[ii+1] = pDevice->abyOFDMDefaultPwr[ii+1];
+ for (ii = 0; ii < CARD_MAX_CHANNEL_TBL; ii++) {
+ if (pDevice->abyRegPwr[ii + 1] == 0)
+ pDevice->abyRegPwr[ii + 1] = pDevice->abyOFDMDefaultPwr[ii + 1];
+ if (pDevice->abyLocalPwr[ii + 1] == 0)
+ pDevice->abyLocalPwr[ii + 1] = pDevice->abyOFDMDefaultPwr[ii + 1];
}
}
@@ -500,11 +497,11 @@ unsigned char get_channel_mapping(void *pDeviceHandler, unsigned char byChannelN
unsigned int ii;
if ((ePhyType == PHY_TYPE_11B) || (ePhyType == PHY_TYPE_11G))
- return (byChannelNumber);
+ return byChannelNumber;
- for(ii = (CB_MAX_CHANNEL_24G + 1); ii <= CB_MAX_CHANNEL; ) {
+ for (ii = (CB_MAX_CHANNEL_24G + 1); ii <= CB_MAX_CHANNEL;) {
if (sChannelTbl[ii].byChannelNumber == byChannelNumber)
- return ((unsigned char) ii);
+ return (unsigned char) ii;
ii++;
}
return 0;
@@ -513,7 +510,7 @@ unsigned char get_channel_mapping(void *pDeviceHandler, unsigned char byChannelN
unsigned char get_channel_number(void *pDeviceHandler, unsigned char byChannelIndex)
{
//PSDevice pDevice = (PSDevice) pDeviceHandler;
- return(sChannelTbl[byChannelIndex].byChannelNumber);
+ return sChannelTbl[byChannelIndex].byChannelNumber;
}
/**
@@ -525,25 +522,24 @@ unsigned char get_channel_number(void *pDeviceHandler, unsigned char byChannelIn
* Return Value: true if succeeded; false if failed.
*
*/
-bool set_channel (void *pDeviceHandler, unsigned int uConnectionChannel)
+bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
{
PSDevice pDevice = (PSDevice) pDeviceHandler;
bool bResult = true;
-
if (pDevice->byCurrentCh == uConnectionChannel) {
return bResult;
}
if (sChannelTbl[uConnectionChannel].bValid == false) {
- return (false);
+ return false;
}
if ((uConnectionChannel > CB_MAX_CHANNEL_24G) &&
- (pDevice->eCurrentPHYType != PHY_TYPE_11A)) {
+ (pDevice->eCurrentPHYType != PHY_TYPE_11A)) {
CARDbSetPhyParameter(pDevice, PHY_TYPE_11A, 0, 0, NULL, NULL);
} else if ((uConnectionChannel <= CB_MAX_CHANNEL_24G) &&
- (pDevice->eCurrentPHYType == PHY_TYPE_11A)) {
+ (pDevice->eCurrentPHYType == PHY_TYPE_11A)) {
CARDbSetPhyParameter(pDevice, PHY_TYPE_11G, 0, 0, NULL, NULL);
}
// clear NAV
@@ -552,13 +548,11 @@ bool set_channel (void *pDeviceHandler, unsigned int uConnectionChannel)
//{{ RobertYu: 20041202
//// TX_PE will reserve 3 us for MAX2829 A mode only, it is for better TX throughput
- if ( pDevice->byRFType == RF_AIROHA7230 )
- {
+ if (pDevice->byRFType == RF_AIROHA7230) {
RFbAL7230SelectChannelPostProcess(pDevice->PortOffset, pDevice->byCurrentCh, (unsigned char)uConnectionChannel);
}
//}} RobertYu
-
pDevice->byCurrentCh = (unsigned char)uConnectionChannel;
bResult &= RFbSelectChannel(pDevice->PortOffset, pDevice->byRFType, (unsigned char)uConnectionChannel);
@@ -566,8 +560,7 @@ bool set_channel (void *pDeviceHandler, unsigned int uConnectionChannel)
if (pDevice->bEnablePSMode == true)
RFvWriteWakeProgSyn(pDevice->PortOffset, pDevice->byRFType, uConnectionChannel);
-
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CARDbSetMediaChannel: %d\n", (unsigned char)uConnectionChannel);
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CARDbSetMediaChannel: %d\n", (unsigned char)uConnectionChannel);
BBvSoftwareReset(pDevice->PortOffset);
if (pDevice->byLocalID > REV_ID_VT3253_B1) {
@@ -581,18 +574,12 @@ bool set_channel (void *pDeviceHandler, unsigned int uConnectionChannel)
}
if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
-#ifdef PLICE_DEBUG
- //printk("Func:ChbSetChannel:call RFbSetPower:11B\n");
-#endif
RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
} else {
-#ifdef PLICE_DEBUG
- //printk("Func:ChbSetChannel:call RFbSetPower\n");
-#endif
RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
}
- return(bResult);
+ return bResult;
}
/**
@@ -612,19 +599,18 @@ void set_country_info(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, void *pIE)
unsigned char byCh = 0;
PWLAN_IE_COUNTRY pIE_Country = (PWLAN_IE_COUNTRY) pIE;
-
uNumOfCountryInfo = (pIE_Country->len - 3);
uNumOfCountryInfo /= 3;
if (ePHYType == PHY_TYPE_11A) {
pDevice->bCountryInfo5G = true;
- for(ii = CB_MAX_CHANNEL_24G + 1 ; ii <= CARD_MAX_CHANNEL_TBL ; ii++) {
+ for (ii = CB_MAX_CHANNEL_24G + 1; ii <= CARD_MAX_CHANNEL_TBL; ii++) {
sChannelTbl[ii].bValid = false;
}
step = 4;
} else {
pDevice->bCountryInfo24G = true;
- for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ for (ii = 1; ii <= CB_MAX_CHANNEL_24G; ii++) {
sChannelTbl[ii].bValid = false;
}
step = 1;
@@ -633,8 +619,8 @@ void set_country_info(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, void *pIE)
pDevice->abyCountryCode[1] = pIE_Country->abyCountryString[1];
pDevice->abyCountryCode[2] = pIE_Country->abyCountryString[2];
- for(ii = 0 ; ii < uNumOfCountryInfo ; ii++) {
- for(uu = 0 ; uu < pIE_Country->abyCountryInfo[ii*3+1] ; uu++) {
+ for (ii = 0; ii < uNumOfCountryInfo; ii++) {
+ for (uu = 0; uu < pIE_Country->abyCountryInfo[ii*3+1]; uu++) {
byCh = get_channel_mapping(pDevice, (unsigned char)(pIE_Country->abyCountryInfo[ii*3]+step*uu), ePHYType);
sChannelTbl[byCh].bValid = true;
pDevice->abyRegPwr[byCh] = pIE_Country->abyCountryInfo[ii*3+2];
@@ -661,7 +647,6 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
unsigned char *pbyChTupple;
unsigned char byLen = 0;
-
pIE->byElementID = WLAN_EID_SUPP_CH;
pIE->len = 0;
pbyChTupple = pIE->abyChannelTuple;
@@ -669,7 +654,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
// lower band
byCount = 0;
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[28] == true) {
- for (ii = 28 ; ii < 36 ; ii+= 2) {
+ for (ii = 28; ii < 36; ii += 2) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
byCount++;
}
@@ -678,7 +663,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
*pbyChTupple++ = byCount;
byLen += 2;
} else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[29] == true) {
- for (ii = 29 ; ii < 36 ; ii+= 2) {
+ for (ii = 29; ii < 36; ii += 2) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
byCount++;
}
@@ -690,7 +675,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
// middle band
byCount = 0;
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[36] == true) {
- for (ii = 36 ; ii < 40 ; ii++) {
+ for (ii = 36; ii < 40; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
byCount++;
}
@@ -702,7 +687,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
// higher band
byCount = 0;
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[40] == true) {
- for (ii = 40 ; ii < 51 ; ii++) {
+ for (ii = 40; ii < 51; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
byCount++;
}
@@ -711,7 +696,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
*pbyChTupple++ = byCount;
byLen += 2;
} else if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[51] == true) {
- for (ii = 51 ; ii < 56 ; ii++) {
+ for (ii = 51; ii < 56; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] == true) {
byCount++;
}
@@ -721,7 +706,7 @@ unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs)
byLen += 2;
}
pIE->len += (byLen - 2);
- return (byLen);
+ return byLen;
}
void set_country_IE(void *pDeviceHandler, void *pIE)
@@ -735,9 +720,9 @@ void set_country_IE(void *pDeviceHandler, void *pIE)
pIECountry->abyCountryString[0] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[0];
pIECountry->abyCountryString[1] = ChannelRuleTab[pDevice->byZoneType].chCountryCode[1];
pIECountry->abyCountryString[2] = ' ';
- for (ii = CB_MAX_CHANNEL_24G; ii < CB_MAX_CHANNEL; ii++ ) {
+ for (ii = CB_MAX_CHANNEL_24G; ii < CB_MAX_CHANNEL; ii++) {
if (ChannelRuleTab[pDevice->byZoneType].bChannelIdxList[ii] != 0) {
- pIECountry->abyCountryInfo[pIECountry->len++] = sChannelTbl[ii+1].byChannelNumber;
+ pIECountry->abyCountryInfo[pIECountry->len++] = sChannelTbl[ii + 1].byChannelNumber;
pIECountry->abyCountryInfo[pIECountry->len++] = 1;
pIECountry->abyCountryInfo[pIECountry->len++] = ChannelRuleTab[pDevice->byZoneType].byPower[ii];
}
@@ -746,9 +731,8 @@ void set_country_IE(void *pDeviceHandler, void *pIE)
}
bool get_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
- unsigned char *pbyChannelNumber, unsigned char *pbyMap)
+ unsigned char *pbyChannelNumber, unsigned char *pbyMap)
{
-
if (uChannelIndex > CB_MAX_CHANNEL)
return false;
@@ -758,9 +742,8 @@ bool get_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
}
void set_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
- unsigned char byMap)
+ unsigned char byMap)
{
-
if (uChannelIndex > CB_MAX_CHANNEL)
return;
@@ -779,40 +762,40 @@ unsigned char auto_channel_select(void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
{
unsigned int ii = 0;
unsigned char byOptionChannel = 0;
- int aiWeight[CB_MAX_CHANNEL_24G+1] = {-1000,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ int aiWeight[CB_MAX_CHANNEL_24G + 1] = {-1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
if (ePHYType == PHY_TYPE_11A) {
- for(ii = CB_MAX_CHANNEL_24G + 1 ; ii <= CB_MAX_CHANNEL ; ii++) {
+ for (ii = CB_MAX_CHANNEL_24G + 1; ii <= CB_MAX_CHANNEL; ii++) {
if (sChannelTbl[ii].bValid == true) {
if (byOptionChannel == 0) {
byOptionChannel = (unsigned char) ii;
}
if (sChannelTbl[ii].byMAP == 0) {
- return ((unsigned char) ii);
- } else if ( !(sChannelTbl[ii].byMAP & 0x08)) {
+ return (unsigned char) ii;
+ } else if (!(sChannelTbl[ii].byMAP & 0x08)) {
byOptionChannel = (unsigned char) ii;
}
}
}
} else {
byOptionChannel = 0;
- for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ for (ii = 1; ii <= CB_MAX_CHANNEL_24G; ii++) {
if (sChannelTbl[ii].bValid == true) {
if (sChannelTbl[ii].byMAP == 0) {
aiWeight[ii] += 100;
} else if (sChannelTbl[ii].byMAP & 0x01) {
if (ii > 3) {
- aiWeight[ii-3] -= 10;
+ aiWeight[ii - 3] -= 10;
}
if (ii > 2) {
- aiWeight[ii-2] -= 20;
+ aiWeight[ii - 2] -= 20;
}
if (ii > 1) {
- aiWeight[ii-1] -= 40;
+ aiWeight[ii - 1] -= 40;
}
aiWeight[ii] -= 80;
if (ii < CB_MAX_CHANNEL_24G) {
- aiWeight[ii+1] -= 40;
+ aiWeight[ii + 1] -= 40;
}
if (ii < (CB_MAX_CHANNEL_24G - 1)) {
aiWeight[ii+2] -= 20;
@@ -823,12 +806,12 @@ unsigned char auto_channel_select(void *pDeviceHandler, CARD_PHY_TYPE ePHYType)
}
}
}
- for(ii = 1 ; ii <= CB_MAX_CHANNEL_24G ; ii++) {
+ for (ii = 1; ii <= CB_MAX_CHANNEL_24G; ii++) {
if ((sChannelTbl[ii].bValid == true) &&
- (aiWeight[ii] > aiWeight[byOptionChannel])) {
+ (aiWeight[ii] > aiWeight[byOptionChannel])) {
byOptionChannel = (unsigned char) ii;
}
}
}
- return (byOptionChannel);
+ return byOptionChannel;
}
diff --git a/drivers/staging/vt6655/channel.h b/drivers/staging/vt6655/channel.h
index 7038f0d3bde9..c9931d7f6653 100644
--- a/drivers/staging/vt6655/channel.h
+++ b/drivers/staging/vt6655/channel.h
@@ -29,12 +29,11 @@
/*--------------------- Export Classes ----------------------------*/
typedef struct tagSChannelTblElement {
- unsigned char byChannelNumber;
- unsigned int uFrequency;
- bool bValid;
- unsigned char byMAP;
-}SChannelTblElement, *PSChannelTblElement;
-
+ unsigned char byChannelNumber;
+ unsigned int uFrequency;
+ bool bValid;
+ unsigned char byMAP;
+} SChannelTblElement, *PSChannelTblElement;
/*--------------------- Export Functions --------------------------*/
@@ -48,11 +47,10 @@ void set_country_info(void *pDeviceHandler, CARD_PHY_TYPE ePHYType, void *pIE);
unsigned char set_support_channels(void *pDeviceHandler, unsigned char *pbyIEs);
void set_country_IE(void *pDeviceHandler, void *pIE);
bool get_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
- unsigned char *pbyChannelNumber, unsigned char *pbyMap);
+ unsigned char *pbyChannelNumber, unsigned char *pbyMap);
void set_channel_map_info(void *pDeviceHandler, unsigned int uChannelIndex,
- unsigned char byMap);
+ unsigned char byMap);
void clear_channel_map_info(void *pDeviceHandler);
unsigned char auto_channel_select(void *pDeviceHandler, CARD_PHY_TYPE ePHYType);
-
#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6655/country.h b/drivers/staging/vt6655/country.h
index 05fda4104200..415e7672aa32 100644
--- a/drivers/staging/vt6655/country.h
+++ b/drivers/staging/vt6655/country.h
@@ -38,125 +38,125 @@
* Please check with VNWL.inf/VNWL64.inf/VNWL*.inf
************************************************************************/
typedef enum _COUNTRY_CODE {
- CCODE_FCC = 0,
- CCODE_TELEC,
- CCODE_ETSI,
- CCODE_RESV3,
- CCODE_RESV4,
- CCODE_RESV5,
- CCODE_RESV6,
- CCODE_RESV7,
- CCODE_RESV8,
- CCODE_RESV9,
- CCODE_RESVa,
- CCODE_RESVb,
- CCODE_RESVc,
- CCODE_RESVd,
- CCODE_RESVe,
- CCODE_ALLBAND,
- CCODE_ALBANIA,
- CCODE_ALGERIA,
- CCODE_ARGENTINA,
- CCODE_ARMENIA,
- CCODE_AUSTRALIA,
- CCODE_AUSTRIA,
- CCODE_AZERBAIJAN,
- CCODE_BAHRAIN,
- CCODE_BELARUS,
- CCODE_BELGIUM,
- CCODE_BELIZE,
- CCODE_BOLIVIA,
- CCODE_BRAZIL,
- CCODE_BRUNEI_DARUSSALAM,
- CCODE_BULGARIA,
- CCODE_CANADA,
- CCODE_CHILE,
- CCODE_CHINA,
- CCODE_COLOMBIA,
- CCODE_COSTA_RICA,
- CCODE_CROATIA,
- CCODE_CYPRUS,
- CCODE_CZECH,
- CCODE_DENMARK,
- CCODE_DOMINICAN_REPUBLIC,
- CCODE_ECUADOR,
- CCODE_EGYPT,
- CCODE_EL_SALVADOR,
- CCODE_ESTONIA,
- CCODE_FINLAND,
- CCODE_FRANCE,
- CCODE_GERMANY,
- CCODE_GREECE,
- CCODE_GEORGIA,
- CCODE_GUATEMALA,
- CCODE_HONDURAS,
- CCODE_HONG_KONG,
- CCODE_HUNGARY,
- CCODE_ICELAND,
- CCODE_INDIA,
- CCODE_INDONESIA,
- CCODE_IRAN,
- CCODE_IRELAND,
- CCODE_ITALY,
- CCODE_ISRAEL,
- CCODE_JAPAN,
- CCODE_JORDAN,
- CCODE_KAZAKHSTAN,
- CCODE_KUWAIT,
- CCODE_LATVIA,
- CCODE_LEBANON,
- CCODE_LEICHTENSTEIN,
- CCODE_LITHUANIA,
- CCODE_LUXEMBURG,
- CCODE_MACAU,
- CCODE_MACEDONIA,
- CCODE_MALTA,
- CCODE_MALAYSIA,
- CCODE_MEXICO,
- CCODE_MONACO,
- CCODE_MOROCCO,
- CCODE_NETHERLANDS,
- CCODE_NEW_ZEALAND,
- CCODE_NORTH_KOREA,
- CCODE_NORWAY,
- CCODE_OMAN,
- CCODE_PAKISTAN,
- CCODE_PANAMA,
- CCODE_PERU,
- CCODE_PHILIPPINES,
- CCODE_POLAND,
- CCODE_PORTUGAL,
- CCODE_PUERTO_RICO,
- CCODE_QATAR,
- CCODE_ROMANIA,
- CCODE_RUSSIA,
- CCODE_SAUDI_ARABIA,
- CCODE_SINGAPORE,
- CCODE_SLOVAKIA,
- CCODE_SLOVENIA,
- CCODE_SOUTH_AFRICA,
- CCODE_SOUTH_KOREA,
- CCODE_SPAIN,
- CCODE_SWEDEN,
- CCODE_SWITZERLAND,
- CCODE_SYRIA,
- CCODE_TAIWAN,
- CCODE_THAILAND,
- CCODE_TRINIDAD_TOBAGO,
- CCODE_TUNISIA,
- CCODE_TURKEY,
- CCODE_UK,
- CCODE_UKRAINE,
- CCODE_UNITED_ARAB_EMIRATES,
- CCODE_UNITED_STATES,
- CCODE_URUGUAY,
- CCODE_UZBEKISTAN,
- CCODE_VENEZUELA,
- CCODE_VIETNAM,
- CCODE_YEMEN,
- CCODE_ZIMBABWE,
- CCODE_JAPAN_W52_W53,
- CCODE_MAX
+ CCODE_FCC = 0,
+ CCODE_TELEC,
+ CCODE_ETSI,
+ CCODE_RESV3,
+ CCODE_RESV4,
+ CCODE_RESV5,
+ CCODE_RESV6,
+ CCODE_RESV7,
+ CCODE_RESV8,
+ CCODE_RESV9,
+ CCODE_RESVa,
+ CCODE_RESVb,
+ CCODE_RESVc,
+ CCODE_RESVd,
+ CCODE_RESVe,
+ CCODE_ALLBAND,
+ CCODE_ALBANIA,
+ CCODE_ALGERIA,
+ CCODE_ARGENTINA,
+ CCODE_ARMENIA,
+ CCODE_AUSTRALIA,
+ CCODE_AUSTRIA,
+ CCODE_AZERBAIJAN,
+ CCODE_BAHRAIN,
+ CCODE_BELARUS,
+ CCODE_BELGIUM,
+ CCODE_BELIZE,
+ CCODE_BOLIVIA,
+ CCODE_BRAZIL,
+ CCODE_BRUNEI_DARUSSALAM,
+ CCODE_BULGARIA,
+ CCODE_CANADA,
+ CCODE_CHILE,
+ CCODE_CHINA,
+ CCODE_COLOMBIA,
+ CCODE_COSTA_RICA,
+ CCODE_CROATIA,
+ CCODE_CYPRUS,
+ CCODE_CZECH,
+ CCODE_DENMARK,
+ CCODE_DOMINICAN_REPUBLIC,
+ CCODE_ECUADOR,
+ CCODE_EGYPT,
+ CCODE_EL_SALVADOR,
+ CCODE_ESTONIA,
+ CCODE_FINLAND,
+ CCODE_FRANCE,
+ CCODE_GERMANY,
+ CCODE_GREECE,
+ CCODE_GEORGIA,
+ CCODE_GUATEMALA,
+ CCODE_HONDURAS,
+ CCODE_HONG_KONG,
+ CCODE_HUNGARY,
+ CCODE_ICELAND,
+ CCODE_INDIA,
+ CCODE_INDONESIA,
+ CCODE_IRAN,
+ CCODE_IRELAND,
+ CCODE_ITALY,
+ CCODE_ISRAEL,
+ CCODE_JAPAN,
+ CCODE_JORDAN,
+ CCODE_KAZAKHSTAN,
+ CCODE_KUWAIT,
+ CCODE_LATVIA,
+ CCODE_LEBANON,
+ CCODE_LEICHTENSTEIN,
+ CCODE_LITHUANIA,
+ CCODE_LUXEMBURG,
+ CCODE_MACAU,
+ CCODE_MACEDONIA,
+ CCODE_MALTA,
+ CCODE_MALAYSIA,
+ CCODE_MEXICO,
+ CCODE_MONACO,
+ CCODE_MOROCCO,
+ CCODE_NETHERLANDS,
+ CCODE_NEW_ZEALAND,
+ CCODE_NORTH_KOREA,
+ CCODE_NORWAY,
+ CCODE_OMAN,
+ CCODE_PAKISTAN,
+ CCODE_PANAMA,
+ CCODE_PERU,
+ CCODE_PHILIPPINES,
+ CCODE_POLAND,
+ CCODE_PORTUGAL,
+ CCODE_PUERTO_RICO,
+ CCODE_QATAR,
+ CCODE_ROMANIA,
+ CCODE_RUSSIA,
+ CCODE_SAUDI_ARABIA,
+ CCODE_SINGAPORE,
+ CCODE_SLOVAKIA,
+ CCODE_SLOVENIA,
+ CCODE_SOUTH_AFRICA,
+ CCODE_SOUTH_KOREA,
+ CCODE_SPAIN,
+ CCODE_SWEDEN,
+ CCODE_SWITZERLAND,
+ CCODE_SYRIA,
+ CCODE_TAIWAN,
+ CCODE_THAILAND,
+ CCODE_TRINIDAD_TOBAGO,
+ CCODE_TUNISIA,
+ CCODE_TURKEY,
+ CCODE_UK,
+ CCODE_UKRAINE,
+ CCODE_UNITED_ARAB_EMIRATES,
+ CCODE_UNITED_STATES,
+ CCODE_URUGUAY,
+ CCODE_UZBEKISTAN,
+ CCODE_VENEZUELA,
+ CCODE_VIETNAM,
+ CCODE_YEMEN,
+ CCODE_ZIMBABWE,
+ CCODE_JAPAN_W52_W53,
+ CCODE_MAX
} COUNTRY_CODE;
#endif /* __COUNTRY_H__ */
diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c
index b86ec1b6d187..e7b6bc7de4ac 100644
--- a/drivers/staging/vt6655/datarate.c
+++ b/drivers/staging/vt6655/datarate.c
@@ -45,16 +45,12 @@
/*--------------------- Static Definitions -------------------------*/
-
-
-
/*--------------------- Static Classes ----------------------------*/
-
- extern unsigned short TxRate_iwconfig; //2008-5-8 <add> by chester
+extern unsigned short TxRate_iwconfig; //2008-5-8 <add> by chester
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
const unsigned char acbyIERate[MAX_RATE] =
{0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
@@ -64,32 +60,28 @@ const unsigned char acbyIERate[MAX_RATE] =
/*--------------------- Static Functions --------------------------*/
-void s_vResetCounter (
- PKnownNodeDB psNodeDBTable
- );
-
-
+void s_vResetCounter(
+ PKnownNodeDB psNodeDBTable
+);
void
-s_vResetCounter (
- PKnownNodeDB psNodeDBTable
- )
+s_vResetCounter(
+ PKnownNodeDB psNodeDBTable
+)
{
- unsigned char ii;
+ unsigned char ii;
- // clear statistic counter for auto_rate
- for(ii=0;ii<=MAX_RATE;ii++) {
- psNodeDBTable->uTxOk[ii] = 0;
- psNodeDBTable->uTxFail[ii] = 0;
- }
+ // clear statistic counter for auto_rate
+ for (ii = 0; ii <= MAX_RATE; ii++) {
+ psNodeDBTable->uTxOk[ii] = 0;
+ psNodeDBTable->uTxFail[ii] = 0;
+ }
}
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Description:
@@ -103,26 +95,24 @@ s_vResetCounter (
*
* Return Value: RateIdx
*
--*/
+ -*/
unsigned char
-DATARATEbyGetRateIdx (
- unsigned char byRate
- )
+DATARATEbyGetRateIdx(
+ unsigned char byRate
+)
{
- unsigned char ii;
+ unsigned char ii;
- //Erase basicRate flag.
- byRate = byRate & 0x7F;//0111 1111
+ //Erase basicRate flag.
+ byRate = byRate & 0x7F;//0111 1111
- for (ii = 0; ii < MAX_RATE; ii ++) {
- if (acbyIERate[ii] == byRate)
- return ii;
- }
- return 0;
+ for (ii = 0; ii < MAX_RATE; ii++) {
+ if (acbyIERate[ii] == byRate)
+ return ii;
+ }
+ return 0;
}
-
-
/*+
*
* Routine Description:
@@ -137,13 +127,10 @@ DATARATEbyGetRateIdx (
*
* Return Value: none
*
--*/
+ -*/
#define AUTORATE_TXCNT_THRESHOLD 20
#define AUTORATE_INC_THRESHOLD 30
-
-
-
/*+
*
* Description:
@@ -157,22 +144,22 @@ DATARATEbyGetRateIdx (
*
* Return Value: RateIdx
*
--*/
+ -*/
unsigned short
wGetRateIdx(
- unsigned char byRate
- )
+ unsigned char byRate
+)
{
- unsigned short ii;
+ unsigned short ii;
- //Erase basicRate flag.
- byRate = byRate & 0x7F;//0111 1111
+ //Erase basicRate flag.
+ byRate = byRate & 0x7F;//0111 1111
- for (ii = 0; ii < MAX_RATE; ii ++) {
- if (acbyIERate[ii] == byRate)
- return ii;
- }
- return 0;
+ for (ii = 0; ii < MAX_RATE; ii++) {
+ if (acbyIERate[ii] == byRate)
+ return ii;
+ }
+ return 0;
}
/*+
@@ -193,102 +180,99 @@ wGetRateIdx(
*
* Return Value: none
*
--*/
+ -*/
void
-RATEvParseMaxRate (
- void *pDeviceHandler,
- PWLAN_IE_SUPP_RATES pItemRates,
- PWLAN_IE_SUPP_RATES pItemExtRates,
- bool bUpdateBasicRate,
- unsigned short *pwMaxBasicRate,
- unsigned short *pwMaxSuppRate,
- unsigned short *pwSuppRate,
- unsigned char *pbyTopCCKRate,
- unsigned char *pbyTopOFDMRate
- )
+RATEvParseMaxRate(
+ void *pDeviceHandler,
+ PWLAN_IE_SUPP_RATES pItemRates,
+ PWLAN_IE_SUPP_RATES pItemExtRates,
+ bool bUpdateBasicRate,
+ unsigned short *pwMaxBasicRate,
+ unsigned short *pwMaxSuppRate,
+ unsigned short *pwSuppRate,
+ unsigned char *pbyTopCCKRate,
+ unsigned char *pbyTopOFDMRate
+)
{
-PSDevice pDevice = (PSDevice) pDeviceHandler;
-unsigned int ii;
-unsigned char byHighSuppRate = 0;
-unsigned char byRate = 0;
-unsigned short wOldBasicRate = pDevice->wBasicRate;
-unsigned int uRateLen;
-
-
- if (pItemRates == NULL)
- return;
-
- *pwSuppRate = 0;
- uRateLen = pItemRates->len;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate Len: %d\n", uRateLen);
- if (pDevice->eCurrentPHYType != PHY_TYPE_11B) {
- if (uRateLen > WLAN_RATES_MAXLEN)
- uRateLen = WLAN_RATES_MAXLEN;
- } else {
- if (uRateLen > WLAN_RATES_MAXLEN_11B)
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
-
- for (ii = 0; ii < uRateLen; ii++) {
- byRate = (unsigned char)(pItemRates->abyRates[ii]);
- if (WLAN_MGMT_IS_BASICRATE(byRate) &&
- (bUpdateBasicRate == true)) {
- // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
- CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
- }
- byRate = (unsigned char)(pItemRates->abyRates[ii]&0x7F);
- if (byHighSuppRate == 0)
- byHighSuppRate = byRate;
- if (byRate > byHighSuppRate)
- byHighSuppRate = byRate;
- *pwSuppRate |= (1<<wGetRateIdx(byRate));
- }
- if ((pItemExtRates != NULL) && (pItemExtRates->byElementID == WLAN_EID_EXTSUPP_RATES) &&
- (pDevice->eCurrentPHYType != PHY_TYPE_11B)) {
-
- unsigned int uExtRateLen = pItemExtRates->len;
-
- if (uExtRateLen > WLAN_RATES_MAXLEN)
- uExtRateLen = WLAN_RATES_MAXLEN;
-
- for (ii = 0; ii < uExtRateLen ; ii++) {
- byRate = (unsigned char)(pItemExtRates->abyRates[ii]);
- // select highest basic rate
- if (WLAN_MGMT_IS_BASICRATE(pItemExtRates->abyRates[ii])) {
- // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
- CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
- }
- byRate = (unsigned char)(pItemExtRates->abyRates[ii]&0x7F);
- if (byHighSuppRate == 0)
- byHighSuppRate = byRate;
- if (byRate > byHighSuppRate)
- byHighSuppRate = byRate;
- *pwSuppRate |= (1<<wGetRateIdx(byRate));
- //DBG_PRN_GRP09(("ParseMaxRate : HighSuppRate: %d, %X\n", wGetRateIdx(byRate), byRate));
- }
- } //if(pItemExtRates != NULL)
-
- if ((pDevice->byPacketType == PK_TYPE_11GB) && CARDbIsOFDMinBasicRate((void *)pDevice)) {
- pDevice->byPacketType = PK_TYPE_11GA;
- }
-
- *pbyTopCCKRate = pDevice->byTopCCKBasicRate;
- *pbyTopOFDMRate = pDevice->byTopOFDMBasicRate;
- *pwMaxSuppRate = wGetRateIdx(byHighSuppRate);
- if ((pDevice->byPacketType==PK_TYPE_11B) || (pDevice->byPacketType==PK_TYPE_11GB))
- *pwMaxBasicRate = pDevice->byTopCCKBasicRate;
- else
- *pwMaxBasicRate = pDevice->byTopOFDMBasicRate;
- if (wOldBasicRate != pDevice->wBasicRate)
- CARDvSetRSPINF((void *)pDevice, pDevice->eCurrentPHYType);
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Exit ParseMaxRate\n");
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned int ii;
+ unsigned char byHighSuppRate = 0;
+ unsigned char byRate = 0;
+ unsigned short wOldBasicRate = pDevice->wBasicRate;
+ unsigned int uRateLen;
+
+ if (pItemRates == NULL)
+ return;
+
+ *pwSuppRate = 0;
+ uRateLen = pItemRates->len;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ParseMaxRate Len: %d\n", uRateLen);
+ if (pDevice->eCurrentPHYType != PHY_TYPE_11B) {
+ if (uRateLen > WLAN_RATES_MAXLEN)
+ uRateLen = WLAN_RATES_MAXLEN;
+ } else {
+ if (uRateLen > WLAN_RATES_MAXLEN_11B)
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+
+ for (ii = 0; ii < uRateLen; ii++) {
+ byRate = (unsigned char)(pItemRates->abyRates[ii]);
+ if (WLAN_MGMT_IS_BASICRATE(byRate) &&
+ (bUpdateBasicRate == true)) {
+ // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
+ CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
+ }
+ byRate = (unsigned char)(pItemRates->abyRates[ii]&0x7F);
+ if (byHighSuppRate == 0)
+ byHighSuppRate = byRate;
+ if (byRate > byHighSuppRate)
+ byHighSuppRate = byRate;
+ *pwSuppRate |= (1<<wGetRateIdx(byRate));
+ }
+ if ((pItemExtRates != NULL) && (pItemExtRates->byElementID == WLAN_EID_EXTSUPP_RATES) &&
+ (pDevice->eCurrentPHYType != PHY_TYPE_11B)) {
+ unsigned int uExtRateLen = pItemExtRates->len;
+
+ if (uExtRateLen > WLAN_RATES_MAXLEN)
+ uExtRateLen = WLAN_RATES_MAXLEN;
+
+ for (ii = 0; ii < uExtRateLen; ii++) {
+ byRate = (unsigned char)(pItemExtRates->abyRates[ii]);
+ // select highest basic rate
+ if (WLAN_MGMT_IS_BASICRATE(pItemExtRates->abyRates[ii])) {
+ // Add to basic rate set, update pDevice->byTopCCKBasicRate and pDevice->byTopOFDMBasicRate
+ CARDbAddBasicRate((void *)pDevice, wGetRateIdx(byRate));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ParseMaxRate AddBasicRate: %d\n", wGetRateIdx(byRate));
+ }
+ byRate = (unsigned char)(pItemExtRates->abyRates[ii]&0x7F);
+ if (byHighSuppRate == 0)
+ byHighSuppRate = byRate;
+ if (byRate > byHighSuppRate)
+ byHighSuppRate = byRate;
+ *pwSuppRate |= (1<<wGetRateIdx(byRate));
+ //DBG_PRN_GRP09(("ParseMaxRate : HighSuppRate: %d, %X\n", wGetRateIdx(byRate), byRate));
+ }
+ } //if (pItemExtRates != NULL)
+
+ if ((pDevice->byPacketType == PK_TYPE_11GB) && CARDbIsOFDMinBasicRate((void *)pDevice)) {
+ pDevice->byPacketType = PK_TYPE_11GA;
+ }
+
+ *pbyTopCCKRate = pDevice->byTopCCKBasicRate;
+ *pbyTopOFDMRate = pDevice->byTopOFDMBasicRate;
+ *pwMaxSuppRate = wGetRateIdx(byHighSuppRate);
+ if ((pDevice->byPacketType == PK_TYPE_11B) || (pDevice->byPacketType == PK_TYPE_11GB))
+ *pwMaxBasicRate = pDevice->byTopCCKBasicRate;
+ else
+ *pwMaxBasicRate = pDevice->byTopOFDMBasicRate;
+ if (wOldBasicRate != pDevice->wBasicRate)
+ CARDvSetRSPINF((void *)pDevice, pDevice->eCurrentPHYType);
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Exit ParseMaxRate\n");
}
-
/*+
*
* Routine Description:
@@ -303,97 +287,95 @@ unsigned int uRateLen;
*
* Return Value: none
*
--*/
+ -*/
#define AUTORATE_TXCNT_THRESHOLD 20
#define AUTORATE_INC_THRESHOLD 30
void
-RATEvTxRateFallBack (
- void *pDeviceHandler,
- PKnownNodeDB psNodeDBTable
- )
+RATEvTxRateFallBack(
+ void *pDeviceHandler,
+ PKnownNodeDB psNodeDBTable
+)
{
-PSDevice pDevice = (PSDevice) pDeviceHandler;
-unsigned short wIdxDownRate = 0;
-unsigned int ii;
+ PSDevice pDevice = (PSDevice) pDeviceHandler;
+ unsigned short wIdxDownRate = 0;
+ unsigned int ii;
//unsigned long dwRateTable[MAX_RATE] = {1, 2, 5, 11, 6, 9, 12, 18, 24, 36, 48, 54};
-bool bAutoRate[MAX_RATE] = {true,true,true,true,false,false,true,true,true,true,true,true};
+ bool bAutoRate[MAX_RATE] = {true, true, true, true, false, false, true, true, true, true, true, true};
unsigned long dwThroughputTbl[MAX_RATE] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540};
unsigned long dwThroughput = 0;
unsigned short wIdxUpRate = 0;
unsigned long dwTxDiff = 0;
- if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
- // Don't do Fallback when scanning Channel
- return;
- }
-
- psNodeDBTable->uTimeCount ++;
-
- if (psNodeDBTable->uTxFail[MAX_RATE] > psNodeDBTable->uTxOk[MAX_RATE])
- dwTxDiff = psNodeDBTable->uTxFail[MAX_RATE] - psNodeDBTable->uTxOk[MAX_RATE];
-
- if ((psNodeDBTable->uTxOk[MAX_RATE] < AUTORATE_TXOK_CNT) &&
- (dwTxDiff < AUTORATE_TXFAIL_CNT) &&
- (psNodeDBTable->uTimeCount < AUTORATE_TIMEOUT)) {
- return;
- }
-
- if (psNodeDBTable->uTimeCount >= AUTORATE_TIMEOUT) {
- psNodeDBTable->uTimeCount = 0;
- }
-
-
- for(ii=0;ii<MAX_RATE;ii++) {
- if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
- if (bAutoRate[ii] == true) {
- wIdxUpRate = (unsigned short) ii;
- }
- } else {
- bAutoRate[ii] = false;
- }
- }
-
- for(ii=0;ii<=psNodeDBTable->wTxDataRate;ii++) {
- if ( (psNodeDBTable->uTxOk[ii] != 0) ||
- (psNodeDBTable->uTxFail[ii] != 0) ) {
- dwThroughputTbl[ii] *= psNodeDBTable->uTxOk[ii];
- if (ii < RATE_11M) {
- psNodeDBTable->uTxFail[ii] *= 4;
- }
- dwThroughputTbl[ii] /= (psNodeDBTable->uTxOk[ii] + psNodeDBTable->uTxFail[ii]);
- }
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Rate %d,Ok: %d, Fail:%d, Throughput:%d\n",
+ if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
+ // Don't do Fallback when scanning Channel
+ return;
+ }
+
+ psNodeDBTable->uTimeCount++;
+
+ if (psNodeDBTable->uTxFail[MAX_RATE] > psNodeDBTable->uTxOk[MAX_RATE])
+ dwTxDiff = psNodeDBTable->uTxFail[MAX_RATE] - psNodeDBTable->uTxOk[MAX_RATE];
+
+ if ((psNodeDBTable->uTxOk[MAX_RATE] < AUTORATE_TXOK_CNT) &&
+ (dwTxDiff < AUTORATE_TXFAIL_CNT) &&
+ (psNodeDBTable->uTimeCount < AUTORATE_TIMEOUT)) {
+ return;
+ }
+
+ if (psNodeDBTable->uTimeCount >= AUTORATE_TIMEOUT) {
+ psNodeDBTable->uTimeCount = 0;
+ }
+
+ for (ii = 0; ii < MAX_RATE; ii++) {
+ if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
+ if (bAutoRate[ii] == true) {
+ wIdxUpRate = (unsigned short) ii;
+ }
+ } else {
+ bAutoRate[ii] = false;
+ }
+ }
+
+ for (ii = 0; ii <= psNodeDBTable->wTxDataRate; ii++) {
+ if ((psNodeDBTable->uTxOk[ii] != 0) ||
+ (psNodeDBTable->uTxFail[ii] != 0)) {
+ dwThroughputTbl[ii] *= psNodeDBTable->uTxOk[ii];
+ if (ii < RATE_11M) {
+ psNodeDBTable->uTxFail[ii] *= 4;
+ }
+ dwThroughputTbl[ii] /= (psNodeDBTable->uTxOk[ii] + psNodeDBTable->uTxFail[ii]);
+ }
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rate %d,Ok: %d, Fail:%d, Throughput:%d\n",
// ii, psNodeDBTable->uTxOk[ii], psNodeDBTable->uTxFail[ii], dwThroughputTbl[ii]);
- }
- dwThroughput = dwThroughputTbl[psNodeDBTable->wTxDataRate];
-
- wIdxDownRate = psNodeDBTable->wTxDataRate;
- for(ii = psNodeDBTable->wTxDataRate; ii > 0;) {
- ii--;
- if ( (dwThroughputTbl[ii] > dwThroughput) &&
- (bAutoRate[ii]==true) ) {
- dwThroughput = dwThroughputTbl[ii];
- wIdxDownRate = (unsigned short) ii;
- }
- }
- psNodeDBTable->wTxDataRate = wIdxDownRate;
- if (psNodeDBTable->uTxOk[MAX_RATE]) {
- if (psNodeDBTable->uTxOk[MAX_RATE] >
- (psNodeDBTable->uTxFail[MAX_RATE] * 4) ) {
- psNodeDBTable->wTxDataRate = wIdxUpRate;
- }
- }else { // adhoc, if uTxOk =0 & uTxFail = 0
- if (psNodeDBTable->uTxFail[MAX_RATE] == 0)
- psNodeDBTable->wTxDataRate = wIdxUpRate;
- }
+ }
+ dwThroughput = dwThroughputTbl[psNodeDBTable->wTxDataRate];
+
+ wIdxDownRate = psNodeDBTable->wTxDataRate;
+ for (ii = psNodeDBTable->wTxDataRate; ii > 0;) {
+ ii--;
+ if ((dwThroughputTbl[ii] > dwThroughput) &&
+ (bAutoRate[ii] == true)) {
+ dwThroughput = dwThroughputTbl[ii];
+ wIdxDownRate = (unsigned short) ii;
+ }
+ }
+ psNodeDBTable->wTxDataRate = wIdxDownRate;
+ if (psNodeDBTable->uTxOk[MAX_RATE]) {
+ if (psNodeDBTable->uTxOk[MAX_RATE] >
+ (psNodeDBTable->uTxFail[MAX_RATE] * 4)) {
+ psNodeDBTable->wTxDataRate = wIdxUpRate;
+ }
+ } else { // adhoc, if uTxOk =0 & uTxFail = 0
+ if (psNodeDBTable->uTxFail[MAX_RATE] == 0)
+ psNodeDBTable->wTxDataRate = wIdxUpRate;
+ }
//2008-5-8 <add> by chester
-TxRate_iwconfig=psNodeDBTable->wTxDataRate;
- s_vResetCounter(psNodeDBTable);
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Rate: %d, U:%d, D:%d\n", psNodeDBTable->wTxDataRate, wIdxUpRate, wIdxDownRate);
-
- return;
+ TxRate_iwconfig = psNodeDBTable->wTxDataRate;
+ s_vResetCounter(psNodeDBTable);
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rate: %d, U:%d, D:%d\n", psNodeDBTable->wTxDataRate, wIdxUpRate, wIdxDownRate);
+ return;
}
/*+
@@ -408,30 +390,29 @@ TxRate_iwconfig=psNodeDBTable->wTxDataRate;
*
* Return Value: None
*
--*/
+ -*/
unsigned char
-RATEuSetIE (
- PWLAN_IE_SUPP_RATES pSrcRates,
- PWLAN_IE_SUPP_RATES pDstRates,
- unsigned int uRateLen
- )
+RATEuSetIE(
+ PWLAN_IE_SUPP_RATES pSrcRates,
+ PWLAN_IE_SUPP_RATES pDstRates,
+ unsigned int uRateLen
+)
{
- unsigned int ii, uu, uRateCnt = 0;
-
- if ((pSrcRates == NULL) || (pDstRates == NULL))
- return 0;
-
- if (pSrcRates->len == 0)
- return 0;
-
- for (ii = 0; ii < uRateLen; ii++) {
- for (uu = 0; uu < pSrcRates->len; uu++) {
- if ((pSrcRates->abyRates[uu] & 0x7F) == acbyIERate[ii]) {
- pDstRates->abyRates[uRateCnt ++] = pSrcRates->abyRates[uu];
- break;
- }
- }
- }
- return (unsigned char)uRateCnt;
+ unsigned int ii, uu, uRateCnt = 0;
+
+ if ((pSrcRates == NULL) || (pDstRates == NULL))
+ return 0;
+
+ if (pSrcRates->len == 0)
+ return 0;
+
+ for (ii = 0; ii < uRateLen; ii++) {
+ for (uu = 0; uu < pSrcRates->len; uu++) {
+ if ((pSrcRates->abyRates[uu] & 0x7F) == acbyIERate[ii]) {
+ pDstRates->abyRates[uRateCnt++] = pSrcRates->abyRates[uu];
+ break;
+ }
+ }
+ }
+ return (unsigned char)uRateCnt;
}
-
diff --git a/drivers/staging/vt6655/datarate.h b/drivers/staging/vt6655/datarate.h
index 4f8ea0b0532d..e4fad05ad859 100644
--- a/drivers/staging/vt6655/datarate.h
+++ b/drivers/staging/vt6655/datarate.h
@@ -41,55 +41,48 @@
#define RETRY_TIMES_THRD_H 2 // times
#define RETRY_TIMES_THRD_L 1 // times
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-
void
RATEvParseMaxRate(
- void *pDeviceHandler,
- PWLAN_IE_SUPP_RATES pItemRates,
- PWLAN_IE_SUPP_RATES pItemExtRates,
- bool bUpdateBasicRate,
- unsigned short *pwMaxBasicRate,
- unsigned short *pwMaxSuppRate,
- unsigned short *pwSuppRate,
- unsigned char *pbyTopCCKRate,
- unsigned char *pbyTopOFDMRate
- );
+ void *pDeviceHandler,
+ PWLAN_IE_SUPP_RATES pItemRates,
+ PWLAN_IE_SUPP_RATES pItemExtRates,
+ bool bUpdateBasicRate,
+ unsigned short *pwMaxBasicRate,
+ unsigned short *pwMaxSuppRate,
+ unsigned short *pwSuppRate,
+ unsigned char *pbyTopCCKRate,
+ unsigned char *pbyTopOFDMRate
+);
void
RATEvTxRateFallBack(
- void *pDeviceHandler,
- PKnownNodeDB psNodeDBTable
- );
+ void *pDeviceHandler,
+ PKnownNodeDB psNodeDBTable
+);
unsigned char
RATEuSetIE(
- PWLAN_IE_SUPP_RATES pSrcRates,
- PWLAN_IE_SUPP_RATES pDstRates,
- unsigned int uRateLen
- );
+ PWLAN_IE_SUPP_RATES pSrcRates,
+ PWLAN_IE_SUPP_RATES pDstRates,
+ unsigned int uRateLen
+);
unsigned short
wGetRateIdx(
- unsigned char byRate
- );
-
+ unsigned char byRate
+);
unsigned char
DATARATEbyGetRateIdx(
- unsigned char byRate
- );
-
+ unsigned char byRate
+);
#endif //__DATARATE_H__
diff --git a/drivers/staging/vt6655/desc.h b/drivers/staging/vt6655/desc.h
index 084a1a5566ad..32d808ec502a 100644
--- a/drivers/staging/vt6655/desc.h
+++ b/drivers/staging/vt6655/desc.h
@@ -89,7 +89,7 @@
// max transmit or receive buffer size
#define CB_MAX_BUF_SIZE 2900U // max buffer size
- // NOTE: must be multiple of 4
+ // NOTE: must be multiple of 4
#define CB_MAX_TX_BUF_SIZE CB_MAX_BUF_SIZE // max Tx buffer size
#define CB_MAX_RX_BUF_SIZE_NORMAL CB_MAX_BUF_SIZE // max Rx buffer size when not use Multi-RD
@@ -101,16 +101,15 @@
#define CB_MIN_TX_DESC 16 // min # of tx descriptor
#define CB_MAX_RECEIVED_PACKETS 16 // max # of received packets at one time
- // limit our receive routine to indicating
- // this many at a time for 2 reasons:
- // 1. driver flow control to protocol layer
- // 2. limit the time used in ISR routine
+ // limit our receive routine to indicating
+ // this many at a time for 2 reasons:
+ // 1. driver flow control to protocol layer
+ // 2. limit the time used in ISR routine
#define CB_EXTRA_RD_NUM 32 // default # of Extra RD
#define CB_RD_NUM 32 // default # of RD
#define CB_TD_NUM 32 // default # of TD
-
// max number of physical segments
// in a single NDIS packet. Above this threshold, the packet
// is copied into a single physically contiguous buffer
@@ -121,8 +120,6 @@
#define CB_PROTOCOL_RESERVED_SECTION 16
-
-
// if retrys excess 15 times , tx will abort, and
// if tx fifo underflow, tx will fail
// we should try to resend it
@@ -199,8 +196,6 @@
#define TYPE_RXDMA1 1
#define TYPE_MAXRD 2
-
-
// TD_INFO flags control bit
#define TD_FLAGS_NETIF_SKB 0x01 // check if need release skb
#define TD_FLAGS_PRIV_SKB 0x02 // check if called from private skb(hostap)
@@ -213,28 +208,28 @@
// may link to older skb that leads error.
typedef struct tagDEVICE_RD_INFO {
- struct sk_buff* skb;
- dma_addr_t skb_dma;
- dma_addr_t curr_desc;
+ struct sk_buff *skb;
+ dma_addr_t skb_dma;
+ dma_addr_t curr_desc;
} DEVICE_RD_INFO, *PDEVICE_RD_INFO;
/*
-static inline PDEVICE_RD_INFO alloc_rd_info(void) {
- PDEVICE_RD_INFO ptr;
- ptr = kmalloc(sizeof(DEVICE_RD_INFO), GFP_ATOMIC);
- if (ptr == NULL)
- return NULL;
- else {
- memset(ptr,0,sizeof(DEVICE_RD_INFO));
- return ptr;
- }
-}
+ static inline PDEVICE_RD_INFO alloc_rd_info(void) {
+ PDEVICE_RD_INFO ptr;
+ ptr = kmalloc(sizeof(DEVICE_RD_INFO), GFP_ATOMIC);
+ if (ptr == NULL)
+ return NULL;
+ else {
+ memset(ptr,0,sizeof(DEVICE_RD_INFO));
+ return ptr;
+ }
+ }
*/
/*
-typedef struct tagRDES0 {
- unsigned short wResCount;
- unsigned short wf1Owner ;
+ typedef struct tagRDES0 {
+ unsigned short wResCount;
+ unsigned short wf1Owner;
// unsigned short f15Reserved : 15;
// unsigned short f1Owner : 1;
} __attribute__ ((__packed__))
@@ -244,11 +239,11 @@ SRDES0;
#ifdef __BIG_ENDIAN
typedef struct tagRDES0 {
- volatile unsigned short wResCount;
+ volatile unsigned short wResCount;
union {
volatile u16 f15Reserved;
struct {
- volatile u8 f8Reserved1;
+ volatile u8 f8Reserved1;
volatile u8 f1Owner:1;
volatile u8 f7Reserved:7;
} __attribute__ ((__packed__));
@@ -259,18 +254,17 @@ SRDES0, *PSRDES0;
#else
typedef struct tagRDES0 {
- unsigned short wResCount;
- unsigned short f15Reserved : 15;
- unsigned short f1Owner : 1;
+ unsigned short wResCount;
+ unsigned short f15Reserved:15;
+ unsigned short f1Owner:1;
} __attribute__ ((__packed__))
SRDES0;
-
#endif
typedef struct tagRDES1 {
- unsigned short wReqCount;
- unsigned short wReserved;
+ unsigned short wReqCount;
+ unsigned short wReserved;
} __attribute__ ((__packed__))
SRDES1;
@@ -278,13 +272,13 @@ SRDES1;
// Rx descriptor
//
typedef struct tagSRxDesc {
- volatile SRDES0 m_rd0RD0;
- volatile SRDES1 m_rd1RD1;
- volatile u32 buff_addr;
- volatile u32 next_desc;
- struct tagSRxDesc *next;//4 bytes
- volatile PDEVICE_RD_INFO pRDInfo;//4 bytes
- volatile u32 Reserved[2];//8 bytes
+ volatile SRDES0 m_rd0RD0;
+ volatile SRDES1 m_rd1RD1;
+ volatile u32 buff_addr;
+ volatile u32 next_desc;
+ struct tagSRxDesc *next;//4 bytes
+ volatile PDEVICE_RD_INFO pRDInfo;//4 bytes
+ volatile u32 Reserved[2];//8 bytes
} __attribute__ ((__packed__))
SRxDesc, *PSRxDesc;
typedef const SRxDesc *PCSRxDesc;
@@ -292,10 +286,10 @@ typedef const SRxDesc *PCSRxDesc;
#ifdef __BIG_ENDIAN
/*
-typedef struct tagTDES0 {
- volatile unsigned char byTSR0;
- volatile unsigned char byTSR1;
- volatile unsigned short wOwner_Txtime;
+ typedef struct tagTDES0 {
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
+ volatile unsigned short wOwner_Txtime;
// volatile unsigned short f15Txtime : 15;
// volatile unsigned short f1Owner:1;
} __attribute__ ((__packed__))
@@ -303,12 +297,12 @@ STDES0;
*/
typedef struct tagTDES0 {
- volatile unsigned char byTSR0;
- volatile unsigned char byTSR1;
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
union {
volatile u16 f15Txtime;
struct {
- volatile u8 f8Reserved1;
+ volatile u8 f8Reserved1;
volatile u8 f1Owner:1;
volatile u8 f7Reserved:7;
} __attribute__ ((__packed__));
@@ -319,113 +313,109 @@ STDES0, PSTDES0;
#else
typedef struct tagTDES0 {
- volatile unsigned char byTSR0;
- volatile unsigned char byTSR1;
- volatile unsigned short f15Txtime : 15;
- volatile unsigned short f1Owner:1;
+ volatile unsigned char byTSR0;
+ volatile unsigned char byTSR1;
+ volatile unsigned short f15Txtime:15;
+ volatile unsigned short f1Owner:1;
} __attribute__ ((__packed__))
STDES0;
#endif
-
typedef struct tagTDES1 {
- volatile unsigned short wReqCount;
- volatile unsigned char byTCR;
- volatile unsigned char byReserved;
+ volatile unsigned short wReqCount;
+ volatile unsigned char byTCR;
+ volatile unsigned char byReserved;
} __attribute__ ((__packed__))
STDES1;
-
-typedef struct tagDEVICE_TD_INFO{
- struct sk_buff* skb;
- unsigned char *buf;
- dma_addr_t skb_dma;
- dma_addr_t buf_dma;
- dma_addr_t curr_desc;
- unsigned long dwReqCount;
- unsigned long dwHeaderLength;
- unsigned char byFlags;
+typedef struct tagDEVICE_TD_INFO {
+ struct sk_buff *skb;
+ unsigned char *buf;
+ dma_addr_t skb_dma;
+ dma_addr_t buf_dma;
+ dma_addr_t curr_desc;
+ unsigned long dwReqCount;
+ unsigned long dwHeaderLength;
+ unsigned char byFlags;
} DEVICE_TD_INFO, *PDEVICE_TD_INFO;
/*
-static inline PDEVICE_TD_INFO alloc_td_info(void) {
- PDEVICE_TD_INFO ptr;
- ptr = kmalloc(sizeof(DEVICE_TD_INFO),GFP_ATOMIC);
- if (ptr == NULL)
- return NULL;
- else {
- memset(ptr,0,sizeof(DEVICE_TD_INFO));
- return ptr;
- }
-}
+ static inline PDEVICE_TD_INFO alloc_td_info(void) {
+ PDEVICE_TD_INFO ptr;
+ ptr = kmalloc(sizeof(DEVICE_TD_INFO),GFP_ATOMIC);
+ if (ptr == NULL)
+ return NULL;
+ else {
+ memset(ptr,0,sizeof(DEVICE_TD_INFO));
+ return ptr;
+ }
+ }
*/
//
// transmit descriptor
//
typedef struct tagSTxDesc {
- volatile STDES0 m_td0TD0;
- volatile STDES1 m_td1TD1;
- volatile u32 buff_addr;
- volatile u32 next_desc;
- struct tagSTxDesc* next; //4 bytes
- volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile u32 Reserved[2];//8 bytes
+ volatile STDES0 m_td0TD0;
+ volatile STDES1 m_td1TD1;
+ volatile u32 buff_addr;
+ volatile u32 next_desc;
+ struct tagSTxDesc *next; //4 bytes
+ volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
+ volatile u32 Reserved[2];//8 bytes
} __attribute__ ((__packed__))
STxDesc, *PSTxDesc;
typedef const STxDesc *PCSTxDesc;
-
typedef struct tagSTxSyncDesc {
- volatile STDES0 m_td0TD0;
- volatile STDES1 m_td1TD1;
- volatile u32 buff_addr; // pointer to logical buffer
- volatile u32 next_desc; // pointer to next logical descriptor
- volatile unsigned short m_wFIFOCtl;
- volatile unsigned short m_wTimeStamp;
- struct tagSTxSyncDesc* next; //4 bytes
- volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
- volatile u32 m_dwReserved2;
+ volatile STDES0 m_td0TD0;
+ volatile STDES1 m_td1TD1;
+ volatile u32 buff_addr; // pointer to logical buffer
+ volatile u32 next_desc; // pointer to next logical descriptor
+ volatile unsigned short m_wFIFOCtl;
+ volatile unsigned short m_wTimeStamp;
+ struct tagSTxSyncDesc *next; //4 bytes
+ volatile PDEVICE_TD_INFO pTDInfo;//4 bytes
+ volatile u32 m_dwReserved2;
} __attribute__ ((__packed__))
STxSyncDesc, *PSTxSyncDesc;
typedef const STxSyncDesc *PCSTxSyncDesc;
-
//
// RsvTime buffer header
//
typedef struct tagSRrvTime_gRTS {
- unsigned short wRTSTxRrvTime_ba;
- unsigned short wRTSTxRrvTime_aa;
- unsigned short wRTSTxRrvTime_bb;
- unsigned short wReserved;
- unsigned short wTxRrvTime_b;
- unsigned short wTxRrvTime_a;
-}__attribute__ ((__packed__))
+ unsigned short wRTSTxRrvTime_ba;
+ unsigned short wRTSTxRrvTime_aa;
+ unsigned short wRTSTxRrvTime_bb;
+ unsigned short wReserved;
+ unsigned short wTxRrvTime_b;
+ unsigned short wTxRrvTime_a;
+} __attribute__ ((__packed__))
SRrvTime_gRTS, *PSRrvTime_gRTS;
typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
typedef struct tagSRrvTime_gCTS {
- unsigned short wCTSTxRrvTime_ba;
- unsigned short wReserved;
- unsigned short wTxRrvTime_b;
- unsigned short wTxRrvTime_a;
-}__attribute__ ((__packed__))
+ unsigned short wCTSTxRrvTime_ba;
+ unsigned short wReserved;
+ unsigned short wTxRrvTime_b;
+ unsigned short wTxRrvTime_a;
+} __attribute__ ((__packed__))
SRrvTime_gCTS, *PSRrvTime_gCTS;
typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
typedef struct tagSRrvTime_ab {
- unsigned short wRTSTxRrvTime;
- unsigned short wTxRrvTime;
-}__attribute__ ((__packed__))
+ unsigned short wRTSTxRrvTime;
+ unsigned short wTxRrvTime;
+} __attribute__ ((__packed__))
SRrvTime_ab, *PSRrvTime_ab;
typedef const SRrvTime_ab *PCSRrvTime_ab;
typedef struct tagSRrvTime_atim {
- unsigned short wCTSTxRrvTime_ba;
- unsigned short wTxRrvTime_a;
-}__attribute__ ((__packed__))
+ unsigned short wCTSTxRrvTime_ba;
+ unsigned short wTxRrvTime_a;
+} __attribute__ ((__packed__))
SRrvTime_atim, *PSRrvTime_atim;
typedef const SRrvTime_atim *PCSRrvTime_atim;
@@ -433,132 +423,127 @@ typedef const SRrvTime_atim *PCSRrvTime_atim;
// RTS buffer header
//
typedef struct tagSRTSData {
- unsigned short wFrameControl;
- unsigned short wDurationID;
- unsigned char abyRA[ETH_ALEN];
- unsigned char abyTA[ETH_ALEN];
-}__attribute__ ((__packed__))
+ unsigned short wFrameControl;
+ unsigned short wDurationID;
+ unsigned char abyRA[ETH_ALEN];
+ unsigned char abyTA[ETH_ALEN];
+} __attribute__ ((__packed__))
SRTSData, *PSRTSData;
typedef const SRTSData *PCSRTSData;
typedef struct tagSRTS_g {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned char bySignalField_a;
- unsigned char byServiceField_a;
- unsigned short wTransmitLength_a;
- unsigned short wDuration_ba;
- unsigned short wDuration_aa;
- unsigned short wDuration_bb;
- unsigned short wReserved;
- SRTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_ba;
+ unsigned short wDuration_aa;
+ unsigned short wDuration_bb;
+ unsigned short wReserved;
+ SRTSData Data;
+} __attribute__ ((__packed__))
SRTS_g, *PSRTS_g;
typedef const SRTS_g *PCSRTS_g;
-
typedef struct tagSRTS_g_FB {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned char bySignalField_a;
- unsigned char byServiceField_a;
- unsigned short wTransmitLength_a;
- unsigned short wDuration_ba;
- unsigned short wDuration_aa;
- unsigned short wDuration_bb;
- unsigned short wReserved;
- unsigned short wRTSDuration_ba_f0;
- unsigned short wRTSDuration_aa_f0;
- unsigned short wRTSDuration_ba_f1;
- unsigned short wRTSDuration_aa_f1;
- SRTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_ba;
+ unsigned short wDuration_aa;
+ unsigned short wDuration_bb;
+ unsigned short wReserved;
+ unsigned short wRTSDuration_ba_f0;
+ unsigned short wRTSDuration_aa_f0;
+ unsigned short wRTSDuration_ba_f1;
+ unsigned short wRTSDuration_aa_f1;
+ SRTSData Data;
+} __attribute__ ((__packed__))
SRTS_g_FB, *PSRTS_g_FB;
typedef const SRTS_g_FB *PCSRTS_g_FB;
-
typedef struct tagSRTS_ab {
- unsigned char bySignalField;
- unsigned char byServiceField;
- unsigned short wTransmitLength;
- unsigned short wDuration;
- unsigned short wReserved;
- SRTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wReserved;
+ SRTSData Data;
+} __attribute__ ((__packed__))
SRTS_ab, *PSRTS_ab;
typedef const SRTS_ab *PCSRTS_ab;
-
typedef struct tagSRTS_a_FB {
- unsigned char bySignalField;
- unsigned char byServiceField;
- unsigned short wTransmitLength;
- unsigned short wDuration;
- unsigned short wReserved;
- unsigned short wRTSDuration_f0;
- unsigned short wRTSDuration_f1;
- SRTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wReserved;
+ unsigned short wRTSDuration_f0;
+ unsigned short wRTSDuration_f1;
+ SRTSData Data;
+} __attribute__ ((__packed__))
SRTS_a_FB, *PSRTS_a_FB;
typedef const SRTS_a_FB *PCSRTS_a_FB;
-
//
// CTS buffer header
//
typedef struct tagSCTSData {
- unsigned short wFrameControl;
- unsigned short wDurationID;
- unsigned char abyRA[ETH_ALEN];
- unsigned short wReserved;
-}__attribute__ ((__packed__))
+ unsigned short wFrameControl;
+ unsigned short wDurationID;
+ unsigned char abyRA[ETH_ALEN];
+ unsigned short wReserved;
+} __attribute__ ((__packed__))
SCTSData, *PSCTSData;
typedef struct tagSCTS {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned short wDuration_ba;
- unsigned short wReserved;
- SCTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned short wDuration_ba;
+ unsigned short wReserved;
+ SCTSData Data;
+} __attribute__ ((__packed__))
SCTS, *PSCTS;
typedef const SCTS *PCSCTS;
typedef struct tagSCTS_FB {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned short wDuration_ba;
- unsigned short wReserved;
- unsigned short wCTSDuration_ba_f0;
- unsigned short wCTSDuration_ba_f1;
- SCTSData Data;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned short wDuration_ba;
+ unsigned short wReserved;
+ unsigned short wCTSDuration_ba_f0;
+ unsigned short wCTSDuration_ba_f1;
+ SCTSData Data;
+} __attribute__ ((__packed__))
SCTS_FB, *PSCTS_FB;
typedef const SCTS_FB *PCSCTS_FB;
-
//
// Tx FIFO header
//
typedef struct tagSTxBufHead {
- u32 adwTxKey[4];
- unsigned short wFIFOCtl;
- unsigned short wTimeStamp;
- unsigned short wFragCtl;
- unsigned char byTxPower;
- unsigned char wReserved;
-}__attribute__ ((__packed__))
+ u32 adwTxKey[4];
+ unsigned short wFIFOCtl;
+ unsigned short wTimeStamp;
+ unsigned short wFragCtl;
+ unsigned char byTxPower;
+ unsigned char wReserved;
+} __attribute__ ((__packed__))
STxBufHead, *PSTxBufHead;
typedef const STxBufHead *PCSTxBufHead;
typedef struct tagSTxShortBufHead {
- unsigned short wFIFOCtl;
- unsigned short wTimeStamp;
-}__attribute__ ((__packed__))
+ unsigned short wFIFOCtl;
+ unsigned short wTimeStamp;
+} __attribute__ ((__packed__))
STxShortBufHead, *PSTxShortBufHead;
typedef const STxShortBufHead *PCSTxShortBufHead;
@@ -566,58 +551,56 @@ typedef const STxShortBufHead *PCSTxShortBufHead;
// Tx data header
//
typedef struct tagSTxDataHead_g {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned char bySignalField_a;
- unsigned char byServiceField_a;
- unsigned short wTransmitLength_a;
- unsigned short wDuration_b;
- unsigned short wDuration_a;
- unsigned short wTimeStampOff_b;
- unsigned short wTimeStampOff_a;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_b;
+ unsigned short wDuration_a;
+ unsigned short wTimeStampOff_b;
+ unsigned short wTimeStampOff_a;
+} __attribute__ ((__packed__))
STxDataHead_g, *PSTxDataHead_g;
typedef const STxDataHead_g *PCSTxDataHead_g;
typedef struct tagSTxDataHead_g_FB {
- unsigned char bySignalField_b;
- unsigned char byServiceField_b;
- unsigned short wTransmitLength_b;
- unsigned char bySignalField_a;
- unsigned char byServiceField_a;
- unsigned short wTransmitLength_a;
- unsigned short wDuration_b;
- unsigned short wDuration_a;
- unsigned short wDuration_a_f0;
- unsigned short wDuration_a_f1;
- unsigned short wTimeStampOff_b;
- unsigned short wTimeStampOff_a;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField_b;
+ unsigned char byServiceField_b;
+ unsigned short wTransmitLength_b;
+ unsigned char bySignalField_a;
+ unsigned char byServiceField_a;
+ unsigned short wTransmitLength_a;
+ unsigned short wDuration_b;
+ unsigned short wDuration_a;
+ unsigned short wDuration_a_f0;
+ unsigned short wDuration_a_f1;
+ unsigned short wTimeStampOff_b;
+ unsigned short wTimeStampOff_a;
+} __attribute__ ((__packed__))
STxDataHead_g_FB, *PSTxDataHead_g_FB;
typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
-
typedef struct tagSTxDataHead_ab {
- unsigned char bySignalField;
- unsigned char byServiceField;
- unsigned short wTransmitLength;
- unsigned short wDuration;
- unsigned short wTimeStampOff;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wTimeStampOff;
+} __attribute__ ((__packed__))
STxDataHead_ab, *PSTxDataHead_ab;
typedef const STxDataHead_ab *PCSTxDataHead_ab;
-
typedef struct tagSTxDataHead_a_FB {
- unsigned char bySignalField;
- unsigned char byServiceField;
- unsigned short wTransmitLength;
- unsigned short wDuration;
- unsigned short wTimeStampOff;
- unsigned short wDuration_f0;
- unsigned short wDuration_f1;
-}__attribute__ ((__packed__))
+ unsigned char bySignalField;
+ unsigned char byServiceField;
+ unsigned short wTransmitLength;
+ unsigned short wDuration;
+ unsigned short wTimeStampOff;
+ unsigned short wDuration_f0;
+ unsigned short wDuration_f1;
+} __attribute__ ((__packed__))
STxDataHead_a_FB, *PSTxDataHead_a_FB;
typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
@@ -625,38 +608,37 @@ typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
// MICHDR data header
//
typedef struct tagSMICHDRHead {
- u32 adwHDR0[4];
- u32 adwHDR1[4];
- u32 adwHDR2[4];
-}__attribute__ ((__packed__))
+ u32 adwHDR0[4];
+ u32 adwHDR1[4];
+ u32 adwHDR2[4];
+} __attribute__ ((__packed__))
SMICHDRHead, *PSMICHDRHead;
typedef const SMICHDRHead *PCSMICHDRHead;
typedef struct tagSBEACONCtl {
- u32 BufReady : 1;
- u32 TSF : 15;
- u32 BufLen : 11;
- u32 Reserved : 5;
-}__attribute__ ((__packed__))
+ u32 BufReady:1;
+ u32 TSF:15;
+ u32 BufLen:11;
+ u32 Reserved:5;
+} __attribute__ ((__packed__))
SBEACONCtl;
-
typedef struct tagSSecretKey {
- u32 dwLowDword;
- unsigned char byHighByte;
-}__attribute__ ((__packed__))
+ u32 dwLowDword;
+ unsigned char byHighByte;
+} __attribute__ ((__packed__))
SSecretKey;
typedef struct tagSKeyEntry {
- unsigned char abyAddrHi[2];
- unsigned short wKCTL;
- unsigned char abyAddrLo[4];
- u32 dwKey0[4];
- u32 dwKey1[4];
- u32 dwKey2[4];
- u32 dwKey3[4];
- u32 dwKey4[4];
-}__attribute__ ((__packed__))
+ unsigned char abyAddrHi[2];
+ unsigned short wKCTL;
+ unsigned char abyAddrLo[4];
+ u32 dwKey0[4];
+ u32 dwKey1[4];
+ u32 dwKey2[4];
+ u32 dwKey3[4];
+ u32 dwKey4[4];
+} __attribute__ ((__packed__))
SKeyEntry;
/*--------------------- Export Macros ------------------------------*/
@@ -666,8 +648,4 @@ SKeyEntry;
/*--------------------- Export Functions --------------------------*/
-
-
-
#endif // __DESC_H__
-
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index e27244ce383e..ca1b8578cf79 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -87,7 +87,6 @@
#include "key.h"
#include "mac.h"
-
/*--------------------- Export Definitions -------------------------*/
#define MAC_MAX_CONTEXT_REG (256+128)
@@ -111,8 +110,6 @@
#define KEYSEL_TKIP 2
#define KEYSEL_CCMP 3
-
-
#define AUTO_FB_NONE 0
#define AUTO_FB_0 1
#define AUTO_FB_1 2
@@ -133,8 +130,6 @@
#define BB_VGA_LEVEL 4
#define BB_VGA_CHANGE_THRESHOLD 16
-
-
#ifndef RUN_AT
#define RUN_AT(x) (jiffies+(x))
#endif
@@ -142,59 +137,52 @@
// DMA related
#define RESERV_AC0DMA 4
-
// BUILD OBJ mode
-
-#define AVAIL_TD(p,q) ((p)->sOpts.nTxDescs[(q)]-((p)->iTDUsed[(q)]))
+#define AVAIL_TD(p, q) ((p)->sOpts.nTxDescs[(q)] - ((p)->iTDUsed[(q)]))
//PLICE_DEBUG ->
#define NUM 64
//PLICE_DEUBG <-
-
-
#define PRIVATE_Message 0
/*--------------------- Export Types ------------------------------*/
-
-#define DBG_PRT(l, p, args...) {if (l<=msglevel) printk( p ,##args);}
-#define PRINT_K(p, args...) {if (PRIVATE_Message) printk( p ,##args);}
+#define DBG_PRT(l, p, args...) { if (l <= msglevel) printk(p, ##args); }
+#define PRINT_K(p, args...) { if (PRIVATE_Message) printk(p, ##args); }
//0:11A 1:11B 2:11G
typedef enum _VIA_BB_TYPE
{
- BB_TYPE_11A=0,
- BB_TYPE_11B,
- BB_TYPE_11G
+ BB_TYPE_11A = 0,
+ BB_TYPE_11B,
+ BB_TYPE_11G
} VIA_BB_TYPE, *PVIA_BB_TYPE;
//0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate)
typedef enum _VIA_PKT_TYPE
{
- PK_TYPE_11A=0,
- PK_TYPE_11B,
- PK_TYPE_11GB,
- PK_TYPE_11GA
+ PK_TYPE_11A = 0,
+ PK_TYPE_11B,
+ PK_TYPE_11GB,
+ PK_TYPE_11GA
} VIA_PKT_TYPE, *PVIA_PKT_TYPE;
-
typedef enum __device_msg_level {
- MSG_LEVEL_ERR=0, //Errors that will cause abnormal operation.
- MSG_LEVEL_NOTICE=1, //Some errors need users to be notified.
- MSG_LEVEL_INFO=2, //Normal message.
- MSG_LEVEL_VERBOSE=3, //Will report all trival errors.
- MSG_LEVEL_DEBUG=4 //Only for debug purpose.
+ MSG_LEVEL_ERR = 0, //Errors that will cause abnormal operation.
+ MSG_LEVEL_NOTICE = 1, //Some errors need users to be notified.
+ MSG_LEVEL_INFO = 2, //Normal message.
+ MSG_LEVEL_VERBOSE = 3, //Will report all trival errors.
+ MSG_LEVEL_DEBUG = 4 //Only for debug purpose.
} DEVICE_MSG_LEVEL, *PDEVICE_MSG_LEVEL;
typedef enum __device_init_type {
- DEVICE_INIT_COLD=0, // cold init
- DEVICE_INIT_RESET, // reset init or Dx to D0 power remain init
- DEVICE_INIT_DXPL // Dx to D0 power lost init
+ DEVICE_INIT_COLD = 0, // cold init
+ DEVICE_INIT_RESET, // reset init or Dx to D0 power remain init
+ DEVICE_INIT_DXPL // Dx to D0 power lost init
} DEVICE_INIT_TYPE, *PDEVICE_INIT_TYPE;
-
//++ NDIS related
#define MAX_BSSIDINFO_4_PMKID 16
@@ -205,57 +193,54 @@ typedef enum __device_init_type {
// PMKID Structures
typedef unsigned char NDIS_802_11_PMKID_VALUE[16];
-
typedef enum _NDIS_802_11_WEP_STATUS
{
- Ndis802_11WEPEnabled,
- Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
- Ndis802_11WEPDisabled,
- Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
- Ndis802_11WEPKeyAbsent,
- Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
- Ndis802_11WEPNotSupported,
- Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
- Ndis802_11Encryption2Enabled,
- Ndis802_11Encryption2KeyAbsent,
- Ndis802_11Encryption3Enabled,
- Ndis802_11Encryption3KeyAbsent
+ Ndis802_11WEPEnabled,
+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported,
+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+ Ndis802_11Encryption2Enabled,
+ Ndis802_11Encryption2KeyAbsent,
+ Ndis802_11Encryption3Enabled,
+ Ndis802_11Encryption3KeyAbsent
} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
- NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
+ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
typedef enum _NDIS_802_11_STATUS_TYPE
{
- Ndis802_11StatusType_Authentication,
- Ndis802_11StatusType_MediaStreamMode,
- Ndis802_11StatusType_PMKID_CandidateList,
- Ndis802_11StatusTypeMax // not a real type, defined as an upper bound
+ Ndis802_11StatusType_Authentication,
+ Ndis802_11StatusType_MediaStreamMode,
+ Ndis802_11StatusType_PMKID_CandidateList,
+ Ndis802_11StatusTypeMax // not a real type, defined as an upper bound
} NDIS_802_11_STATUS_TYPE, *PNDIS_802_11_STATUS_TYPE;
//Added new types for PMKID Candidate lists.
typedef struct _PMKID_CANDIDATE {
- NDIS_802_11_MAC_ADDRESS BSSID;
- unsigned long Flags;
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ unsigned long Flags;
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
typedef struct _BSSID_INFO
{
- NDIS_802_11_MAC_ADDRESS BSSID;
- NDIS_802_11_PMKID_VALUE PMKID;
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_PMKID_VALUE PMKID;
} BSSID_INFO, *PBSSID_INFO;
typedef struct tagSPMKID {
- unsigned long Length;
- unsigned long BSSIDInfoCount;
- BSSID_INFO BSSIDInfo[MAX_BSSIDINFO_4_PMKID];
+ unsigned long Length;
+ unsigned long BSSIDInfoCount;
+ BSSID_INFO BSSIDInfo[MAX_BSSIDINFO_4_PMKID];
} SPMKID, *PSPMKID;
typedef struct tagSPMKIDCandidateEvent {
- NDIS_802_11_STATUS_TYPE StatusType;
- unsigned long Version; // Version of the structure
- unsigned long NumCandidates; // No. of pmkid candidates
- PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST];
+ NDIS_802_11_STATUS_TYPE StatusType;
+ unsigned long Version; // Version of the structure
+ unsigned long NumCandidates; // No. of pmkid candidates
+ PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST];
} SPMKIDCandidateEvent, *PSPMKIDCandidateEvent;
//--
@@ -264,58 +249,54 @@ typedef struct tagSPMKIDCandidateEvent {
#define MAX_QUIET_COUNT 8
typedef struct tagSQuietControl {
- bool bEnable;
- unsigned long dwStartTime;
- unsigned char byPeriod;
- unsigned short wDuration;
+ bool bEnable;
+ unsigned long dwStartTime;
+ unsigned char byPeriod;
+ unsigned short wDuration;
} SQuietControl, *PSQuietControl;
//--
-typedef struct __chip_info_tbl{
- CHIP_TYPE chip_id;
- char* name;
- int io_size;
- int nTxQueue;
- u32 flags;
+typedef struct __chip_info_tbl {
+ CHIP_TYPE chip_id;
+ char *name;
+ int io_size;
+ int nTxQueue;
+ u32 flags;
} CHIP_INFO, *PCHIP_INFO;
-
typedef enum {
- OWNED_BY_HOST=0,
- OWNED_BY_NIC=1
+ OWNED_BY_HOST = 0,
+ OWNED_BY_NIC = 1
} DEVICE_OWNER_TYPE, *PDEVICE_OWNER_TYPE;
-
// The receive duplicate detection cache entry
-typedef struct tagSCacheEntry{
- unsigned short wFmSequence;
- unsigned char abyAddr2[ETH_ALEN];
+typedef struct tagSCacheEntry {
+ unsigned short wFmSequence;
+ unsigned char abyAddr2[ETH_ALEN];
} SCacheEntry, *PSCacheEntry;
-typedef struct tagSCache{
+typedef struct tagSCache {
/* The receive cache is updated circularly. The next entry to be written is
* indexed by the "InPtr".
-*/
- unsigned int uInPtr; // Place to use next
- SCacheEntry asCacheEntry[DUPLICATE_RX_CACHE_LENGTH];
+ */
+ unsigned int uInPtr; // Place to use next
+ SCacheEntry asCacheEntry[DUPLICATE_RX_CACHE_LENGTH];
} SCache, *PSCache;
#define CB_MAX_RX_FRAG 64
// DeFragment Control Block, used for collecting fragments prior to reassembly
typedef struct tagSDeFragControlBlock
{
- unsigned short wSequence;
- unsigned short wFragNum;
- unsigned char abyAddr2[ETH_ALEN];
- unsigned int uLifetime;
- struct sk_buff* skb;
- unsigned char *pbyRxBuffer;
- unsigned int cbFrameLength;
- bool bInUse;
+ unsigned short wSequence;
+ unsigned short wFragNum;
+ unsigned char abyAddr2[ETH_ALEN];
+ unsigned int uLifetime;
+ struct sk_buff *skb;
+ unsigned char *pbyRxBuffer;
+ unsigned int cbFrameLength;
+ bool bInUse;
} SDeFragControlBlock, *PSDeFragControlBlock;
-
-
//flags for options
#define DEVICE_FLAGS_IP_ALIGN 0x00000001UL
#define DEVICE_FLAGS_PREAMBLE_TYPE 0x00000002UL
@@ -343,511 +324,474 @@ typedef struct tagSDeFragControlBlock
//for device_set_media_duplex
#define DEVICE_LINK_CHANGE 0x00000001UL
-
//PLICE_DEBUG->
-
typedef struct _RxManagementQueue
{
int packet_num;
- int head,tail;
+ int head, tail;
PSRxMgmtPacket Q[NUM];
-} RxManagementQueue,*PSRxManagementQueue;
-
-
+} RxManagementQueue, *PSRxManagementQueue;
//PLICE_DEBUG<-
-
typedef struct __device_opt {
- int nRxDescs0; //Number of RX descriptors0
- int nRxDescs1; //Number of RX descriptors1
- int nTxDescs[2]; //Number of TX descriptors 0, 1
- int int_works; //interrupt limits
- int rts_thresh; //rts threshold
- int frag_thresh;
- int data_rate;
- int channel_num;
- int short_retry;
- int long_retry;
- int bbp_type;
- u32 flags;
+ int nRxDescs0; //Number of RX descriptors0
+ int nRxDescs1; //Number of RX descriptors1
+ int nTxDescs[2]; //Number of TX descriptors 0, 1
+ int int_works; //interrupt limits
+ int rts_thresh; //rts threshold
+ int frag_thresh;
+ int data_rate;
+ int channel_num;
+ int short_retry;
+ int long_retry;
+ int bbp_type;
+ u32 flags;
} OPTIONS, *POPTIONS;
-
typedef struct __device_info {
- struct __device_info* next;
- struct __device_info* prev;
+ struct __device_info *next;
+ struct __device_info *prev;
- struct pci_dev* pcid;
+ struct pci_dev *pcid;
#ifdef CONFIG_PM
- u32 pci_state[16];
+ u32 pci_state[16];
#endif
// netdev
- struct net_device* dev;
- struct net_device* next_module;
- struct net_device_stats stats;
+ struct net_device *dev;
+ struct net_device *next_module;
+ struct net_device_stats stats;
//dma addr, rx/tx pool
- dma_addr_t pool_dma;
- dma_addr_t rd0_pool_dma;
- dma_addr_t rd1_pool_dma;
+ dma_addr_t pool_dma;
+ dma_addr_t rd0_pool_dma;
+ dma_addr_t rd1_pool_dma;
- dma_addr_t td0_pool_dma;
- dma_addr_t td1_pool_dma;
+ dma_addr_t td0_pool_dma;
+ dma_addr_t td1_pool_dma;
- dma_addr_t tx_bufs_dma0;
- dma_addr_t tx_bufs_dma1;
- dma_addr_t tx_beacon_dma;
+ dma_addr_t tx_bufs_dma0;
+ dma_addr_t tx_bufs_dma1;
+ dma_addr_t tx_beacon_dma;
- unsigned char *tx0_bufs;
- unsigned char *tx1_bufs;
- unsigned char *tx_beacon_bufs;
+ unsigned char *tx0_bufs;
+ unsigned char *tx1_bufs;
+ unsigned char *tx_beacon_bufs;
- CHIP_TYPE chip_id;
+ CHIP_TYPE chip_id;
- unsigned long PortOffset;
- unsigned long dwIsr;
- u32 memaddr;
- u32 ioaddr;
- u32 io_size;
+ unsigned long PortOffset;
+ unsigned long dwIsr;
+ u32 memaddr;
+ u32 ioaddr;
+ u32 io_size;
- unsigned char byRevId;
- unsigned short SubSystemID;
- unsigned short SubVendorID;
+ unsigned char byRevId;
+ unsigned short SubSystemID;
+ unsigned short SubVendorID;
- int nTxQueues;
- volatile int iTDUsed[TYPE_MAXTD];
+ int nTxQueues;
+ volatile int iTDUsed[TYPE_MAXTD];
- volatile PSTxDesc apCurrTD[TYPE_MAXTD];
- volatile PSTxDesc apTailTD[TYPE_MAXTD];
+ volatile PSTxDesc apCurrTD[TYPE_MAXTD];
+ volatile PSTxDesc apTailTD[TYPE_MAXTD];
- volatile PSTxDesc apTD0Rings;
- volatile PSTxDesc apTD1Rings;
+ volatile PSTxDesc apTD0Rings;
+ volatile PSTxDesc apTD1Rings;
- volatile PSRxDesc aRD0Ring;
- volatile PSRxDesc aRD1Ring;
- volatile PSRxDesc pCurrRD[TYPE_MAXRD];
- SCache sDupRxCache;
+ volatile PSRxDesc aRD0Ring;
+ volatile PSRxDesc aRD1Ring;
+ volatile PSRxDesc pCurrRD[TYPE_MAXRD];
+ SCache sDupRxCache;
- SDeFragControlBlock sRxDFCB[CB_MAX_RX_FRAG];
- unsigned int cbDFCB;
- unsigned int cbFreeDFCB;
- unsigned int uCurrentDFCBIdx;
+ SDeFragControlBlock sRxDFCB[CB_MAX_RX_FRAG];
+ unsigned int cbDFCB;
+ unsigned int cbFreeDFCB;
+ unsigned int uCurrentDFCBIdx;
- OPTIONS sOpts;
+ OPTIONS sOpts;
- u32 flags;
+ u32 flags;
- u32 rx_buf_sz;
- int multicast_limit;
- unsigned char byRxMode;
+ u32 rx_buf_sz;
+ int multicast_limit;
+ unsigned char byRxMode;
- spinlock_t lock;
+ spinlock_t lock;
//PLICE_DEBUG->
- struct tasklet_struct RxMngWorkItem;
+ struct tasklet_struct RxMngWorkItem;
RxManagementQueue rxManeQueue;
//PLICE_DEBUG<-
//PLICE_DEBUG ->
- pid_t MLMEThr_pid;
- struct completion notify;
- struct semaphore mlme_semaphore;
+ pid_t MLMEThr_pid;
+ struct completion notify;
+ struct semaphore mlme_semaphore;
//PLICE_DEBUG <-
-
- u32 rx_bytes;
-
- // Version control
- unsigned char byLocalID;
- unsigned char byRFType;
-
- unsigned char byMaxPwrLevel;
- unsigned char byZoneType;
- bool bZoneRegExist;
- unsigned char byOriginalZonetype;
- unsigned char abyMacContext[MAC_MAX_CONTEXT_REG];
- bool bLinkPass; // link status: OK or fail
- unsigned char abyCurrentNetAddr[ETH_ALEN];
-
- // Adapter statistics
- SStatCounter scStatistic;
- // 802.11 counter
- SDot11Counters s802_11Counter;
-
-
- // 802.11 management
- PSMgmtObject pMgmt;
- SMgmtObject sMgmtObj;
-
- // 802.11 MAC specific
- unsigned int uCurrRSSI;
- unsigned char byCurrSQ;
-
- unsigned long dwTxAntennaSel;
- unsigned long dwRxAntennaSel;
- unsigned char byAntennaCount;
- unsigned char byRxAntennaMode;
- unsigned char byTxAntennaMode;
- bool bTxRxAntInv;
-
- unsigned char *pbyTmpBuff;
- unsigned int uSIFS; //Current SIFS
- unsigned int uDIFS; //Current DIFS
- unsigned int uEIFS; //Current EIFS
- unsigned int uSlot; //Current SlotTime
- unsigned int uCwMin; //Current CwMin
- unsigned int uCwMax; //CwMax is fixed on 1023.
- // PHY parameter
- unsigned char bySIFS;
- unsigned char byDIFS;
- unsigned char byEIFS;
- unsigned char bySlot;
- unsigned char byCWMaxMin;
- CARD_PHY_TYPE eCurrentPHYType;
-
-
- VIA_BB_TYPE byBBType; //0: 11A, 1:11B, 2:11G
- VIA_PKT_TYPE byPacketType; //0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate)
- unsigned short wBasicRate;
- unsigned char byACKRate;
- unsigned char byTopOFDMBasicRate;
- unsigned char byTopCCKBasicRate;
-
- unsigned char byMinChannel;
- unsigned char byMaxChannel;
- unsigned int uConnectionRate;
-
- unsigned char byPreambleType;
- unsigned char byShortPreamble;
-
- unsigned short wCurrentRate;
- unsigned short wRTSThreshold;
- unsigned short wFragmentationThreshold;
- unsigned char byShortRetryLimit;
- unsigned char byLongRetryLimit;
- CARD_OP_MODE eOPMode;
- unsigned char byOpMode;
- bool bBSSIDFilter;
- unsigned short wMaxTransmitMSDULifetime;
- unsigned char abyBSSID[ETH_ALEN];
- unsigned char abyDesireBSSID[ETH_ALEN];
- unsigned short wCTSDuration; // update while speed change
- unsigned short wACKDuration; // update while speed change
- unsigned short wRTSTransmitLen; // update while speed change
- unsigned char byRTSServiceField; // update while speed change
- unsigned char byRTSSignalField; // update while speed change
-
- unsigned long dwMaxReceiveLifetime; // dot11MaxReceiveLifetime
-
- bool bCCK;
- bool bEncryptionEnable;
- bool bLongHeader;
- bool bShortSlotTime;
- bool bProtectMode;
- bool bNonERPPresent;
- bool bBarkerPreambleMd;
-
- unsigned char byERPFlag;
- unsigned short wUseProtectCntDown;
-
- bool bRadioControlOff;
- bool bRadioOff;
- bool bEnablePSMode;
- unsigned short wListenInterval;
- bool bPWBitOn;
- WMAC_POWER_MODE ePSMode;
-
-
- // GPIO Radio Control
- unsigned char byRadioCtl;
- unsigned char byGPIO;
- bool bHWRadioOff;
- bool bPrvActive4RadioOFF;
- bool bGPIOBlockRead;
-
- // Beacon related
- unsigned short wSeqCounter;
- unsigned short wBCNBufLen;
- bool bBeaconBufReady;
- bool bBeaconSent;
- bool bIsBeaconBufReadySet;
- unsigned int cbBeaconBufReadySetCnt;
- bool bFixRate;
- unsigned char byCurrentCh;
- unsigned int uScanTime;
-
- CMD_STATE eCommandState;
-
- CMD_CODE eCommand;
- bool bBeaconTx;
-
- bool bStopBeacon;
- bool bStopDataPkt;
- bool bStopTx0Pkt;
- unsigned int uAutoReConnectTime;
-
- // 802.11 counter
-
- CMD_ITEM eCmdQueue[CMD_Q_SIZE];
- unsigned int uCmdDequeueIdx;
- unsigned int uCmdEnqueueIdx;
- unsigned int cbFreeCmdQueue;
- bool bCmdRunning;
- bool bCmdClear;
-
-
-
- bool bRoaming;
- //WOW
- unsigned char abyIPAddr[4];
-
- unsigned long ulTxPower;
- NDIS_802_11_WEP_STATUS eEncryptionStatus;
- bool bTransmitKey;
+ u32 rx_bytes;
+
+ // Version control
+ unsigned char byLocalID;
+ unsigned char byRFType;
+
+ unsigned char byMaxPwrLevel;
+ unsigned char byZoneType;
+ bool bZoneRegExist;
+ unsigned char byOriginalZonetype;
+ unsigned char abyMacContext[MAC_MAX_CONTEXT_REG];
+ bool bLinkPass; // link status: OK or fail
+ unsigned char abyCurrentNetAddr[ETH_ALEN];
+
+ // Adapter statistics
+ SStatCounter scStatistic;
+ // 802.11 counter
+ SDot11Counters s802_11Counter;
+
+ // 802.11 management
+ PSMgmtObject pMgmt;
+ SMgmtObject sMgmtObj;
+
+ // 802.11 MAC specific
+ unsigned int uCurrRSSI;
+ unsigned char byCurrSQ;
+
+ unsigned long dwTxAntennaSel;
+ unsigned long dwRxAntennaSel;
+ unsigned char byAntennaCount;
+ unsigned char byRxAntennaMode;
+ unsigned char byTxAntennaMode;
+ bool bTxRxAntInv;
+
+ unsigned char *pbyTmpBuff;
+ unsigned int uSIFS; //Current SIFS
+ unsigned int uDIFS; //Current DIFS
+ unsigned int uEIFS; //Current EIFS
+ unsigned int uSlot; //Current SlotTime
+ unsigned int uCwMin; //Current CwMin
+ unsigned int uCwMax; //CwMax is fixed on 1023.
+ // PHY parameter
+ unsigned char bySIFS;
+ unsigned char byDIFS;
+ unsigned char byEIFS;
+ unsigned char bySlot;
+ unsigned char byCWMaxMin;
+ CARD_PHY_TYPE eCurrentPHYType;
+
+ VIA_BB_TYPE byBBType; //0: 11A, 1:11B, 2:11G
+ VIA_PKT_TYPE byPacketType; //0:11a,1:11b,2:11gb(only CCK in BasicRate),3:11ga(OFDM in Basic Rate)
+ unsigned short wBasicRate;
+ unsigned char byACKRate;
+ unsigned char byTopOFDMBasicRate;
+ unsigned char byTopCCKBasicRate;
+
+ unsigned char byMinChannel;
+ unsigned char byMaxChannel;
+ unsigned int uConnectionRate;
+
+ unsigned char byPreambleType;
+ unsigned char byShortPreamble;
+
+ unsigned short wCurrentRate;
+ unsigned short wRTSThreshold;
+ unsigned short wFragmentationThreshold;
+ unsigned char byShortRetryLimit;
+ unsigned char byLongRetryLimit;
+ CARD_OP_MODE eOPMode;
+ unsigned char byOpMode;
+ bool bBSSIDFilter;
+ unsigned short wMaxTransmitMSDULifetime;
+ unsigned char abyBSSID[ETH_ALEN];
+ unsigned char abyDesireBSSID[ETH_ALEN];
+ unsigned short wCTSDuration; // update while speed change
+ unsigned short wACKDuration; // update while speed change
+ unsigned short wRTSTransmitLen; // update while speed change
+ unsigned char byRTSServiceField; // update while speed change
+ unsigned char byRTSSignalField; // update while speed change
+
+ unsigned long dwMaxReceiveLifetime; // dot11MaxReceiveLifetime
+
+ bool bCCK;
+ bool bEncryptionEnable;
+ bool bLongHeader;
+ bool bShortSlotTime;
+ bool bProtectMode;
+ bool bNonERPPresent;
+ bool bBarkerPreambleMd;
+
+ unsigned char byERPFlag;
+ unsigned short wUseProtectCntDown;
+
+ bool bRadioControlOff;
+ bool bRadioOff;
+ bool bEnablePSMode;
+ unsigned short wListenInterval;
+ bool bPWBitOn;
+ WMAC_POWER_MODE ePSMode;
+
+ // GPIO Radio Control
+ unsigned char byRadioCtl;
+ unsigned char byGPIO;
+ bool bHWRadioOff;
+ bool bPrvActive4RadioOFF;
+ bool bGPIOBlockRead;
+
+ // Beacon related
+ unsigned short wSeqCounter;
+ unsigned short wBCNBufLen;
+ bool bBeaconBufReady;
+ bool bBeaconSent;
+ bool bIsBeaconBufReadySet;
+ unsigned int cbBeaconBufReadySetCnt;
+ bool bFixRate;
+ unsigned char byCurrentCh;
+ unsigned int uScanTime;
+
+ CMD_STATE eCommandState;
+
+ CMD_CODE eCommand;
+ bool bBeaconTx;
+
+ bool bStopBeacon;
+ bool bStopDataPkt;
+ bool bStopTx0Pkt;
+ unsigned int uAutoReConnectTime;
+
+ // 802.11 counter
+
+ CMD_ITEM eCmdQueue[CMD_Q_SIZE];
+ unsigned int uCmdDequeueIdx;
+ unsigned int uCmdEnqueueIdx;
+ unsigned int cbFreeCmdQueue;
+ bool bCmdRunning;
+ bool bCmdClear;
+
+ bool bRoaming;
+ //WOW
+ unsigned char abyIPAddr[4];
+
+ unsigned long ulTxPower;
+ NDIS_802_11_WEP_STATUS eEncryptionStatus;
+ bool bTransmitKey;
//2007-0925-01<Add>by MikeLiu
//mike add :save old Encryption
- NDIS_802_11_WEP_STATUS eOldEncryptionStatus;
-
- SKeyManagement sKey;
- unsigned long dwIVCounter;
-
- QWORD qwPacketNumber; //For CCMP and TKIP as TSC(6 bytes)
- unsigned int uCurrentWEPMode;
-
- RC4Ext SBox;
- unsigned char abyPRNG[WLAN_WEPMAX_KEYLEN+3];
- unsigned char byKeyIndex;
- unsigned int uKeyLength;
- unsigned char abyKey[WLAN_WEP232_KEYLEN];
-
- bool bAES;
- unsigned char byCntMeasure;
-
- // for AP mode
- unsigned int uAssocCount;
- bool bMoreData;
-
- // QoS
- bool bGrpAckPolicy;
-
- // for OID_802_11_ASSOCIATION_INFORMATION
- bool bAssocInfoSet;
-
-
- unsigned char byAutoFBCtrl;
-
- bool bTxMICFail;
- bool bRxMICFail;
-
-
- unsigned int uRATEIdx;
-
-
- // For Update BaseBand VGA Gain Offset
- bool bUpdateBBVGA;
- unsigned int uBBVGADiffCount;
- unsigned char byBBVGANew;
- unsigned char byBBVGACurrent;
- unsigned char abyBBVGA[BB_VGA_LEVEL];
- long ldBmThreshold[BB_VGA_LEVEL];
-
- unsigned char byBBPreEDRSSI;
- unsigned char byBBPreEDIndex;
-
-
- bool bRadioCmd;
- unsigned long dwDiagRefCount;
-
- // For FOE Tuning
- unsigned char byFOETuning;
-
- // For Auto Power Tunning
-
- unsigned char byAutoPwrTunning;
- short sPSetPointCCK;
- short sPSetPointOFDMG;
- short sPSetPointOFDMA;
- long lPFormulaOffset;
- short sPThreshold;
- char cAdjustStep;
- char cMinTxAGC;
-
- // For RF Power table
- unsigned char byCCKPwr;
- unsigned char byOFDMPwrG;
- unsigned char byCurPwr;
- char byCurPwrdBm;
- unsigned char abyCCKPwrTbl[CB_MAX_CHANNEL_24G+1];
- unsigned char abyOFDMPwrTbl[CB_MAX_CHANNEL+1];
- char abyCCKDefaultPwr[CB_MAX_CHANNEL_24G+1];
- char abyOFDMDefaultPwr[CB_MAX_CHANNEL+1];
- char abyRegPwr[CB_MAX_CHANNEL+1];
- char abyLocalPwr[CB_MAX_CHANNEL+1];
-
-
- // BaseBand Loopback Use
- unsigned char byBBCR4d;
- unsigned char byBBCRc9;
- unsigned char byBBCR88;
- unsigned char byBBCR09;
-
- // command timer
- struct timer_list sTimerCommand;
+ NDIS_802_11_WEP_STATUS eOldEncryptionStatus;
+
+ SKeyManagement sKey;
+ unsigned long dwIVCounter;
+
+ QWORD qwPacketNumber; //For CCMP and TKIP as TSC(6 bytes)
+ unsigned int uCurrentWEPMode;
+
+ RC4Ext SBox;
+ unsigned char abyPRNG[WLAN_WEPMAX_KEYLEN+3];
+ unsigned char byKeyIndex;
+ unsigned int uKeyLength;
+ unsigned char abyKey[WLAN_WEP232_KEYLEN];
+
+ bool bAES;
+ unsigned char byCntMeasure;
+
+ // for AP mode
+ unsigned int uAssocCount;
+ bool bMoreData;
+
+ // QoS
+ bool bGrpAckPolicy;
+
+ // for OID_802_11_ASSOCIATION_INFORMATION
+ bool bAssocInfoSet;
+
+ unsigned char byAutoFBCtrl;
+
+ bool bTxMICFail;
+ bool bRxMICFail;
+
+ unsigned int uRATEIdx;
+
+ // For Update BaseBand VGA Gain Offset
+ bool bUpdateBBVGA;
+ unsigned int uBBVGADiffCount;
+ unsigned char byBBVGANew;
+ unsigned char byBBVGACurrent;
+ unsigned char abyBBVGA[BB_VGA_LEVEL];
+ long ldBmThreshold[BB_VGA_LEVEL];
+
+ unsigned char byBBPreEDRSSI;
+ unsigned char byBBPreEDIndex;
+
+ bool bRadioCmd;
+ unsigned long dwDiagRefCount;
+
+ // For FOE Tuning
+ unsigned char byFOETuning;
+
+ // For Auto Power Tunning
+
+ unsigned char byAutoPwrTunning;
+ short sPSetPointCCK;
+ short sPSetPointOFDMG;
+ short sPSetPointOFDMA;
+ long lPFormulaOffset;
+ short sPThreshold;
+ char cAdjustStep;
+ char cMinTxAGC;
+
+ // For RF Power table
+ unsigned char byCCKPwr;
+ unsigned char byOFDMPwrG;
+ unsigned char byCurPwr;
+ char byCurPwrdBm;
+ unsigned char abyCCKPwrTbl[CB_MAX_CHANNEL_24G+1];
+ unsigned char abyOFDMPwrTbl[CB_MAX_CHANNEL+1];
+ char abyCCKDefaultPwr[CB_MAX_CHANNEL_24G+1];
+ char abyOFDMDefaultPwr[CB_MAX_CHANNEL+1];
+ char abyRegPwr[CB_MAX_CHANNEL+1];
+ char abyLocalPwr[CB_MAX_CHANNEL+1];
+
+ // BaseBand Loopback Use
+ unsigned char byBBCR4d;
+ unsigned char byBBCRc9;
+ unsigned char byBBCR88;
+ unsigned char byBBCR09;
+
+ // command timer
+ struct timer_list sTimerCommand;
#ifdef TxInSleep
- struct timer_list sTimerTxData;
- unsigned long nTxDataTimeCout;
- bool fTxDataInSleep;
- bool IsTxDataTrigger;
+ struct timer_list sTimerTxData;
+ unsigned long nTxDataTimeCout;
+ bool fTxDataInSleep;
+ bool IsTxDataTrigger;
#endif
#ifdef WPA_SM_Transtatus
- bool fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen??
+ bool fWPA_Authened; //is WPA/WPA-PSK or WPA2/WPA2-PSK authen??
#endif
- unsigned char byReAssocCount; //mike add:re-association retry times!
- unsigned char byLinkWaitCount;
+ unsigned char byReAssocCount; //mike add:re-association retry times!
+ unsigned char byLinkWaitCount;
+ unsigned char abyNodeName[17];
- unsigned char abyNodeName[17];
-
- bool bDiversityRegCtlON;
- bool bDiversityEnable;
- unsigned long ulDiversityNValue;
- unsigned long ulDiversityMValue;
- unsigned char byTMax;
- unsigned char byTMax2;
- unsigned char byTMax3;
- unsigned long ulSQ3TH;
+ bool bDiversityRegCtlON;
+ bool bDiversityEnable;
+ unsigned long ulDiversityNValue;
+ unsigned long ulDiversityMValue;
+ unsigned char byTMax;
+ unsigned char byTMax2;
+ unsigned char byTMax3;
+ unsigned long ulSQ3TH;
// ANT diversity
- unsigned long uDiversityCnt;
- unsigned char byAntennaState;
- unsigned long ulRatio_State0;
- unsigned long ulRatio_State1;
-
- //SQ3 functions for antenna diversity
- struct timer_list TimerSQ3Tmax1;
- struct timer_list TimerSQ3Tmax2;
- struct timer_list TimerSQ3Tmax3;
-
-
- unsigned long uNumSQ3[MAX_RATE];
- unsigned short wAntDiversityMaxRate;
-
-
- SEthernetHeader sTxEthHeader;
- SEthernetHeader sRxEthHeader;
- unsigned char abyBroadcastAddr[ETH_ALEN];
- unsigned char abySNAP_RFC1042[ETH_ALEN];
- unsigned char abySNAP_Bridgetunnel[ETH_ALEN];
- unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; //unsigned long alignment
- // Pre-Authentication & PMK cache
- SPMKID gsPMKID;
- SPMKIDCandidateEvent gsPMKIDCandidate;
-
-
- // for 802.11h
- bool b11hEnable;
- unsigned char abyCountryCode[3];
- // for 802.11h DFS
- unsigned int uNumOfMeasureEIDs;
- PWLAN_IE_MEASURE_REQ pCurrMeasureEID;
- bool bMeasureInProgress;
- unsigned char byOrgChannel;
- unsigned char byOrgRCR;
- unsigned long dwOrgMAR0;
- unsigned long dwOrgMAR4;
- unsigned char byBasicMap;
- unsigned char byCCAFraction;
- unsigned char abyRPIs[8];
- unsigned long dwRPIs[8];
- bool bChannelSwitch;
- unsigned char byNewChannel;
- unsigned char byChannelSwitchCount;
- bool bQuietEnable;
- bool bEnableFirstQuiet;
- unsigned char byQuietStartCount;
- unsigned int uQuietEnqueue;
- unsigned long dwCurrentQuietEndTime;
- SQuietControl sQuiet[MAX_QUIET_COUNT];
- // for 802.11h TPC
- bool bCountryInfo5G;
- bool bCountryInfo24G;
-
- unsigned short wBeaconInterval;
-
- //WPA supplicant deamon
+ unsigned long uDiversityCnt;
+ unsigned char byAntennaState;
+ unsigned long ulRatio_State0;
+ unsigned long ulRatio_State1;
+
+ //SQ3 functions for antenna diversity
+ struct timer_list TimerSQ3Tmax1;
+ struct timer_list TimerSQ3Tmax2;
+ struct timer_list TimerSQ3Tmax3;
+
+ unsigned long uNumSQ3[MAX_RATE];
+ unsigned short wAntDiversityMaxRate;
+
+ SEthernetHeader sTxEthHeader;
+ SEthernetHeader sRxEthHeader;
+ unsigned char abyBroadcastAddr[ETH_ALEN];
+ unsigned char abySNAP_RFC1042[ETH_ALEN];
+ unsigned char abySNAP_Bridgetunnel[ETH_ALEN];
+ unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; //unsigned long alignment
+ // Pre-Authentication & PMK cache
+ SPMKID gsPMKID;
+ SPMKIDCandidateEvent gsPMKIDCandidate;
+
+ // for 802.11h
+ bool b11hEnable;
+ unsigned char abyCountryCode[3];
+ // for 802.11h DFS
+ unsigned int uNumOfMeasureEIDs;
+ PWLAN_IE_MEASURE_REQ pCurrMeasureEID;
+ bool bMeasureInProgress;
+ unsigned char byOrgChannel;
+ unsigned char byOrgRCR;
+ unsigned long dwOrgMAR0;
+ unsigned long dwOrgMAR4;
+ unsigned char byBasicMap;
+ unsigned char byCCAFraction;
+ unsigned char abyRPIs[8];
+ unsigned long dwRPIs[8];
+ bool bChannelSwitch;
+ unsigned char byNewChannel;
+ unsigned char byChannelSwitchCount;
+ bool bQuietEnable;
+ bool bEnableFirstQuiet;
+ unsigned char byQuietStartCount;
+ unsigned int uQuietEnqueue;
+ unsigned long dwCurrentQuietEndTime;
+ SQuietControl sQuiet[MAX_QUIET_COUNT];
+ // for 802.11h TPC
+ bool bCountryInfo5G;
+ bool bCountryInfo24G;
+
+ unsigned short wBeaconInterval;
+
+ //WPA supplicant deamon
struct net_device *wpadev;
bool bWPADEVUp;
- struct sk_buff *skb;
+ struct sk_buff *skb;
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
/*
- bool bwextstep0;
- bool bwextstep1;
- bool bwextstep2;
- bool bwextstep3;
- */
- unsigned int bwextcount;
- bool bWPASuppWextEnabled;
+ bool bwextstep0;
+ bool bwextstep1;
+ bool bwextstep2;
+ bool bwextstep3;
+*/
+ unsigned int bwextcount;
+ bool bWPASuppWextEnabled;
#endif
- //--
+ //--
#ifdef HOSTAP
- // user space daemon: hostapd, is used for HOSTAP
+ // user space daemon: hostapd, is used for HOSTAP
bool bEnableHostapd;
bool bEnable8021x;
bool bEnableHostWEP;
struct net_device *apdev;
int (*tx_80211)(struct sk_buff *skb, struct net_device *dev);
#endif
- unsigned int uChannel;
- bool bMACSuspend;
+ unsigned int uChannel;
+ bool bMACSuspend;
struct iw_statistics wstats; // wireless stats
- bool bCommit;
-
+ bool bCommit;
} DEVICE_INFO, *PSDevice;
-
//PLICE_DEBUG->
-
- inline static void EnQueue (PSDevice pDevice,PSRxMgmtPacket pRxMgmtPacket)
+inline static void EnQueue(PSDevice pDevice, PSRxMgmtPacket pRxMgmtPacket)
{
- //printk("Enter EnQueue:tail is %d\n",pDevice->rxManeQueue.tail);
- if ((pDevice->rxManeQueue.tail+1) % NUM == pDevice->rxManeQueue.head)
- {
- //printk("Queue is Full,tail is %d\n",pDevice->rxManeQueue.tail);
- return ;
- }
- else
- {
- pDevice->rxManeQueue.tail = (pDevice->rxManeQueue.tail+1)% NUM;
+ if ((pDevice->rxManeQueue.tail+1) % NUM == pDevice->rxManeQueue.head) {
+ return;
+ } else {
+ pDevice->rxManeQueue.tail = (pDevice->rxManeQueue.tail + 1) % NUM;
pDevice->rxManeQueue.Q[pDevice->rxManeQueue.tail] = pRxMgmtPacket;
pDevice->rxManeQueue.packet_num++;
- //printk("packet num is %d\n",pDevice->rxManeQueue.packet_num);
}
}
-
-
-
- inline static PSRxMgmtPacket DeQueue (PSDevice pDevice)
+inline static PSRxMgmtPacket DeQueue(PSDevice pDevice)
{
PSRxMgmtPacket pRxMgmtPacket;
- if (pDevice->rxManeQueue.tail == pDevice->rxManeQueue.head)
- {
+ if (pDevice->rxManeQueue.tail == pDevice->rxManeQueue.head) {
printk("Queue is Empty\n");
return NULL;
- }
- else
- {
+ } else {
int x;
//x=pDevice->rxManeQueue.head = (pDevice->rxManeQueue.head+1)%NUM;
pDevice->rxManeQueue.head = (pDevice->rxManeQueue.head+1)%NUM;
x = pDevice->rxManeQueue.head;
- //printk("Enter DeQueue:head is %d\n",x);
pRxMgmtPacket = pDevice->rxManeQueue.Q[x];
pDevice->rxManeQueue.packet_num--;
return pRxMgmtPacket;
@@ -856,31 +800,22 @@ typedef struct __device_info {
void InitRxManagementQueue(PSDevice pDevice);
-
-
//PLICE_DEBUG<-
-
-
-
-
-
inline static bool device_get_ip(PSDevice pInfo) {
- struct in_device* in_dev=(struct in_device*) pInfo->dev->ip_ptr;
- struct in_ifaddr* ifa;
-
- if (in_dev!=NULL) {
- ifa=(struct in_ifaddr*) in_dev->ifa_list;
- if (ifa!=NULL) {
- memcpy(pInfo->abyIPAddr,&ifa->ifa_address,4);
- return true;
- }
- }
- return false;
+ struct in_device *in_dev = (struct in_device *)pInfo->dev->ip_ptr;
+ struct in_ifaddr *ifa;
+
+ if (in_dev != NULL) {
+ ifa = (struct in_ifaddr *)in_dev->ifa_list;
+ if (ifa != NULL) {
+ memcpy(pInfo->abyIPAddr, &ifa->ifa_address, 4);
+ return true;
+ }
+ }
+ return false;
}
-
-
static inline PDEVICE_RD_INFO alloc_rd_info(void)
{
return kzalloc(sizeof(DEVICE_RD_INFO), GFP_ATOMIC);
@@ -897,5 +832,3 @@ bool device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, unsigned int uNodeI
bool device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF);
int Config_FileOperation(PSDevice pDevice, bool fwrite, unsigned char *Parameter);
#endif
-
-
diff --git a/drivers/staging/vt6655/device_cfg.h b/drivers/staging/vt6655/device_cfg.h
index 408edc27075f..1137adede9ee 100644
--- a/drivers/staging/vt6655/device_cfg.h
+++ b/drivers/staging/vt6655/device_cfg.h
@@ -34,9 +34,9 @@
typedef
struct _version {
- unsigned char major;
- unsigned char minor;
- unsigned char build;
+ unsigned char major;
+ unsigned char minor;
+ unsigned char build;
} version_t, *pversion_t;
#define VID_TABLE_SIZE 64
@@ -70,31 +70,26 @@ struct _version {
//Max: 2378=2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
#define PKT_BUF_SZ 2390
-
#define MAX_UINTS 8
#define OPTION_DEFAULT { [0 ... MAX_UINTS-1] = -1}
-
-
-typedef enum _chip_type{
- VT3253=1
+typedef enum _chip_type {
+ VT3253 = 1
} CHIP_TYPE, *PCHIP_TYPE;
-
-
#ifdef VIAWET_DEBUG
-#define ASSERT(x) { \
- if (!(x)) { \
- printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
- __FUNCTION__, __LINE__);\
- *(int*) 0=0;\
- }\
-}
+#define ASSERT(x) \
+do { \
+ if (!(x)) { \
+ printk(KERN_ERR "assertion %s failed: file %s line %d\n", \
+ #x, __func__, __LINE__); \
+ *(int *)0 = 0; \
+ } \
+} while (0)
#define DBG_PORT80(value) outb(value, 0x80)
#else
#define ASSERT(x)
#define DBG_PORT80(value)
#endif
-
#endif
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index a89ab9bf38e4..08b250f01dae 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -99,52 +99,50 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc., <lyndonchen@vntek.com.tw>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Solomon-A/B/G Wireless LAN Adapter Driver");
- static int mlme_kill;
- //static struct task_struct * mlme_task;
+static int mlme_kill;
+//static struct task_struct * mlme_task;
-#define DEVICE_PARAM(N,D)
+#define DEVICE_PARAM(N, D)
/*
- static const int N[MAX_UINTS]=OPTION_DEFAULT;\
- MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UINTS) "i");\
- MODULE_PARM_DESC(N, D);
+ static const int N[MAX_UINTS]=OPTION_DEFAULT;\
+ MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UINTS) "i");\
+ MODULE_PARM_DESC(N, D);
*/
#define RX_DESC_MIN0 16
#define RX_DESC_MAX0 128
#define RX_DESC_DEF0 32
-DEVICE_PARAM(RxDescriptors0,"Number of receive descriptors0");
+DEVICE_PARAM(RxDescriptors0, "Number of receive descriptors0");
#define RX_DESC_MIN1 16
#define RX_DESC_MAX1 128
#define RX_DESC_DEF1 32
-DEVICE_PARAM(RxDescriptors1,"Number of receive descriptors1");
+DEVICE_PARAM(RxDescriptors1, "Number of receive descriptors1");
#define TX_DESC_MIN0 16
#define TX_DESC_MAX0 128
#define TX_DESC_DEF0 32
-DEVICE_PARAM(TxDescriptors0,"Number of transmit descriptors0");
+DEVICE_PARAM(TxDescriptors0, "Number of transmit descriptors0");
#define TX_DESC_MIN1 16
#define TX_DESC_MAX1 128
#define TX_DESC_DEF1 64
-DEVICE_PARAM(TxDescriptors1,"Number of transmit descriptors1");
-
+DEVICE_PARAM(TxDescriptors1, "Number of transmit descriptors1");
#define IP_ALIG_DEF 0
/* IP_byte_align[] is used for IP header unsigned long byte aligned
0: indicate the IP header won't be unsigned long byte aligned.(Default) .
1: indicate the IP header will be unsigned long byte aligned.
- In some environment, the IP header should be unsigned long byte aligned,
- or the packet will be droped when we receive it. (eg: IPVS)
+ In some environment, the IP header should be unsigned long byte aligned,
+ or the packet will be droped when we receive it. (eg: IPVS)
*/
-DEVICE_PARAM(IP_byte_align,"Enable IP header dword aligned");
-
+DEVICE_PARAM(IP_byte_align, "Enable IP header dword aligned");
#define INT_WORKS_DEF 20
#define INT_WORKS_MIN 10
#define INT_WORKS_MAX 64
-DEVICE_PARAM(int_works,"Number of packets per interrupt services");
+DEVICE_PARAM(int_works, "Number of packets per interrupt services");
#define CHANNEL_MIN 1
#define CHANNEL_MAX 14
@@ -152,7 +150,6 @@ DEVICE_PARAM(int_works,"Number of packets per interrupt services");
DEVICE_PARAM(Channel, "Channel number");
-
/* PreambleType[] is the preamble length used for transmit.
0: indicate allows long preamble type
1: indicate allows short preamble type
@@ -162,21 +159,18 @@ DEVICE_PARAM(Channel, "Channel number");
DEVICE_PARAM(PreambleType, "Preamble Type");
-
#define RTS_THRESH_MIN 512
#define RTS_THRESH_MAX 2347
#define RTS_THRESH_DEF 2347
DEVICE_PARAM(RTSThreshold, "RTS threshold");
-
#define FRAG_THRESH_MIN 256
#define FRAG_THRESH_MAX 2346
#define FRAG_THRESH_DEF 2346
DEVICE_PARAM(FragThreshold, "Fragmentation threshold");
-
#define DATA_RATE_MIN 0
#define DATA_RATE_MAX 13
#define DATA_RATE_DEF 13
@@ -191,10 +185,10 @@ DEVICE_PARAM(FragThreshold, "Fragmentation threshold");
7: indicate 18 Mbps 0x24
8: indicate 24 Mbps 0x30
9: indicate 36 Mbps 0x48
- 10: indicate 48 Mbps 0x60
- 11: indicate 54 Mbps 0x6c
- 12: indicate 72 Mbps 0x90
- 13: indicate auto rate
+ 10: indicate 48 Mbps 0x60
+ 11: indicate 54 Mbps 0x6c
+ 12: indicate 72 Mbps 0x90
+ 13: indicate auto rate
*/
DEVICE_PARAM(ConnectionRate, "Connection data rate");
@@ -209,7 +203,6 @@ DEVICE_PARAM(OPMode, "Infrastruct, adhoc, AP mode ");
2: indicate AP mode used
*/
-
/* PSMode[]
0: indicate disable power saving mode
1: indicate enable power saving mode
@@ -219,22 +212,18 @@ DEVICE_PARAM(OPMode, "Infrastruct, adhoc, AP mode ");
DEVICE_PARAM(PSMode, "Power saving mode");
-
#define SHORT_RETRY_MIN 0
#define SHORT_RETRY_MAX 31
#define SHORT_RETRY_DEF 8
-
DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits");
#define LONG_RETRY_MIN 0
#define LONG_RETRY_MAX 15
#define LONG_RETRY_DEF 4
-
DEVICE_PARAM(LongRetryLimit, "long frame retry limits");
-
/* BasebandType[] baseband type selected
0: indicate 802.11a type
1: indicate 802.11b type
@@ -246,8 +235,6 @@ DEVICE_PARAM(LongRetryLimit, "long frame retry limits");
DEVICE_PARAM(BasebandType, "baseband type");
-
-
/* 80211hEnable[]
0: indicate disable 802.11h
1: indicate enable 802.11h
@@ -266,20 +253,18 @@ DEVICE_PARAM(b80211hEnable, "802.11h mode");
DEVICE_PARAM(bDiversityANTEnable, "ANT diversity mode");
-
//
// Static vars definitions
//
-
-static int device_nics =0;
-static PSDevice pDevice_Infos =NULL;
+static int device_nics = 0;
+static PSDevice pDevice_Infos = NULL;
static struct net_device *root_device_dev = NULL;
-static CHIP_INFO chip_info_table[]= {
- { VT3253, "VIA Networking Solomon-A/B/G Wireless LAN Adapter ",
- 256, 1, DEVICE_FLAGS_IP_ALIGN|DEVICE_FLAGS_TX_ALIGN },
- {0,NULL}
+static CHIP_INFO chip_info_table[] = {
+ { VT3253, "VIA Networking Solomon-A/B/G Wireless LAN Adapter ",
+ 256, 1, DEVICE_FLAGS_IP_ALIGN|DEVICE_FLAGS_TX_ALIGN },
+ {0, NULL}
};
DEFINE_PCI_DEVICE_TABLE(vt6655_pci_id_table) = {
@@ -289,17 +274,16 @@ DEFINE_PCI_DEVICE_TABLE(vt6655_pci_id_table) = {
/*--------------------- Static Functions --------------------------*/
-
static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent);
-static void vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO);
+static void vt6655_init_info(struct pci_dev *pcid, PSDevice *ppDevice, PCHIP_INFO);
static void device_free_info(PSDevice pDevice);
-static bool device_get_pci_info(PSDevice, struct pci_dev* pcid);
+static bool device_get_pci_info(PSDevice, struct pci_dev *pcid);
static void device_print_info(PSDevice pDevice);
static struct net_device_stats *device_get_stats(struct net_device *dev);
static void device_init_diversity_timer(PSDevice pDevice);
static int device_open(struct net_device *dev);
static int device_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t device_intr(int irq, void*dev_instance);
+static irqreturn_t device_intr(int irq, void *dev_instance);
static void device_set_multi(struct net_device *dev);
static int device_close(struct net_device *dev);
static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -315,7 +299,6 @@ struct notifier_block device_notifier = {
};
#endif
-
static void device_init_rd0_ring(PSDevice pDevice);
static void device_init_rd1_ring(PSDevice pDevice);
static void device_init_defrag_cb(PSDevice pDevice);
@@ -339,16 +322,13 @@ static void device_free_rd1_ring(PSDevice pDevice);
static void device_free_rings(PSDevice pDevice);
static void device_free_frag_buf(PSDevice pDevice);
static int Config_FileGetParameter(unsigned char *string,
- unsigned char *dest, unsigned char *source);
-
+ unsigned char *dest, unsigned char *source);
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-
-
-static char* get_chip_name(int chip_id)
+static char *get_chip_name(int chip_id)
{
int i;
for (i = 0; chip_info_table[i].name != NULL; i++)
@@ -364,42 +344,41 @@ static void vt6655_remove(struct pci_dev *pcid)
if (pDevice == NULL)
return;
device_free_info(pDevice);
-
}
/*
-static void
-device_set_int_opt(int *opt, int val, int min, int max, int def,char* name,char* devname) {
- if (val==-1)
- *opt=def;
- else if (val<min || val>max) {
- DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n" ,
- devname,name, min,max);
- *opt=def;
- } else {
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n",
- devname, name, val);
- *opt=val;
- }
-}
+ static void
+ device_set_int_opt(int *opt, int val, int min, int max, int def,char* name,char* devname) {
+ if (val==-1)
+ *opt=def;
+ else if (val<min || val>max) {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n" ,
+ devname,name, min,max);
+ *opt=def;
+ } else {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n",
+ devname, name, val);
+ *opt=val;
+ }
+ }
-static void
-device_set_bool_opt(unsigned int *opt, int val,bool def,u32 flag, char* name,char* devname) {
- (*opt)&=(~flag);
- if (val==-1)
- *opt|=(def ? flag : 0);
- else if (val<0 || val>1) {
- DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE
- "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",devname,name);
- *opt|=(def ? flag : 0);
- } else {
- DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: set parameter %s to %s\n",
- devname,name , val ? "true" : "false");
- *opt|=(val ? flag : 0);
- }
-}
+ static void
+ device_set_bool_opt(unsigned int *opt, int val,bool def,u32 flag, char* name,char* devname) {
+ (*opt)&=(~flag);
+ if (val==-1)
+ *opt|=(def ? flag : 0);
+ else if (val<0 || val>1) {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE
+ "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",devname,name);
+ *opt|=(def ? flag : 0);
+ } else {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: set parameter %s to %s\n",
+ devname,name , val ? "true" : "false");
+ *opt|=(val ? flag : 0);
+ }
+ }
*/
-static void device_get_options(PSDevice pDevice, int index, char* devname)
+static void device_get_options(PSDevice pDevice, int index, char *devname)
{
POPTIONS pOpts = &(pDevice->sOpts);
@@ -426,472 +405,436 @@ static void device_get_options(PSDevice pDevice, int index, char* devname)
static void
device_set_options(PSDevice pDevice) {
-
- unsigned char abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- unsigned char abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
- unsigned char abySNAP_Bridgetunnel[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8};
-
-
- memcpy(pDevice->abyBroadcastAddr, abyBroadcastAddr, ETH_ALEN);
- memcpy(pDevice->abySNAP_RFC1042, abySNAP_RFC1042, ETH_ALEN);
- memcpy(pDevice->abySNAP_Bridgetunnel, abySNAP_Bridgetunnel, ETH_ALEN);
-
- pDevice->uChannel = pDevice->sOpts.channel_num;
- pDevice->wRTSThreshold = pDevice->sOpts.rts_thresh;
- pDevice->wFragmentationThreshold = pDevice->sOpts.frag_thresh;
- pDevice->byShortRetryLimit = pDevice->sOpts.short_retry;
- pDevice->byLongRetryLimit = pDevice->sOpts.long_retry;
- pDevice->wMaxTransmitMSDULifetime = DEFAULT_MSDU_LIFETIME;
- pDevice->byShortPreamble = (pDevice->sOpts.flags & DEVICE_FLAGS_PREAMBLE_TYPE) ? 1 : 0;
- pDevice->byOpMode = (pDevice->sOpts.flags & DEVICE_FLAGS_OP_MODE) ? 1 : 0;
- pDevice->ePSMode = (pDevice->sOpts.flags & DEVICE_FLAGS_PS_MODE) ? 1 : 0;
- pDevice->b11hEnable = (pDevice->sOpts.flags & DEVICE_FLAGS_80211h_MODE) ? 1 : 0;
- pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0;
- pDevice->uConnectionRate = pDevice->sOpts.data_rate;
- if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = true;
- pDevice->byBBType = pDevice->sOpts.bbp_type;
- pDevice->byPacketType = pDevice->byBBType;
+ unsigned char abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned char abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
+ unsigned char abySNAP_Bridgetunnel[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8};
+
+ memcpy(pDevice->abyBroadcastAddr, abyBroadcastAddr, ETH_ALEN);
+ memcpy(pDevice->abySNAP_RFC1042, abySNAP_RFC1042, ETH_ALEN);
+ memcpy(pDevice->abySNAP_Bridgetunnel, abySNAP_Bridgetunnel, ETH_ALEN);
+
+ pDevice->uChannel = pDevice->sOpts.channel_num;
+ pDevice->wRTSThreshold = pDevice->sOpts.rts_thresh;
+ pDevice->wFragmentationThreshold = pDevice->sOpts.frag_thresh;
+ pDevice->byShortRetryLimit = pDevice->sOpts.short_retry;
+ pDevice->byLongRetryLimit = pDevice->sOpts.long_retry;
+ pDevice->wMaxTransmitMSDULifetime = DEFAULT_MSDU_LIFETIME;
+ pDevice->byShortPreamble = (pDevice->sOpts.flags & DEVICE_FLAGS_PREAMBLE_TYPE) ? 1 : 0;
+ pDevice->byOpMode = (pDevice->sOpts.flags & DEVICE_FLAGS_OP_MODE) ? 1 : 0;
+ pDevice->ePSMode = (pDevice->sOpts.flags & DEVICE_FLAGS_PS_MODE) ? 1 : 0;
+ pDevice->b11hEnable = (pDevice->sOpts.flags & DEVICE_FLAGS_80211h_MODE) ? 1 : 0;
+ pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0;
+ pDevice->uConnectionRate = pDevice->sOpts.data_rate;
+ if (pDevice->uConnectionRate < RATE_AUTO) pDevice->bFixRate = true;
+ pDevice->byBBType = pDevice->sOpts.bbp_type;
+ pDevice->byPacketType = pDevice->byBBType;
//PLICE_DEBUG->
pDevice->byAutoFBCtrl = AUTO_FB_0;
//pDevice->byAutoFBCtrl = AUTO_FB_1;
//PLICE_DEBUG<-
-pDevice->bUpdateBBVGA = true;
- pDevice->byFOETuning = 0;
- pDevice->wCTSDuration = 0;
- pDevice->byPreambleType = 0;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uChannel= %d\n",(int)pDevice->uChannel);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byOpMode= %d\n",(int)pDevice->byOpMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ePSMode= %d\n",(int)pDevice->ePSMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" wRTSThreshold= %d\n",(int)pDevice->wRTSThreshold);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortRetryLimit= %d\n",(int)pDevice->byShortRetryLimit);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byLongRetryLimit= %d\n",(int)pDevice->byLongRetryLimit);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byPreambleType= %d\n",(int)pDevice->byPreambleType);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byShortPreamble= %d\n",(int)pDevice->byShortPreamble);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" uConnectionRate= %d\n",(int)pDevice->uConnectionRate);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" byBBType= %d\n",(int)pDevice->byBBType);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->b11hEnable= %d\n",(int)pDevice->b11hEnable);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pDevice->bDiversityRegCtlON= %d\n",(int)pDevice->bDiversityRegCtlON);
+ pDevice->bUpdateBBVGA = true;
+ pDevice->byFOETuning = 0;
+ pDevice->wCTSDuration = 0;
+ pDevice->byPreambleType = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " uChannel= %d\n", (int)pDevice->uChannel);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byOpMode= %d\n", (int)pDevice->byOpMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " ePSMode= %d\n", (int)pDevice->ePSMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " wRTSThreshold= %d\n", (int)pDevice->wRTSThreshold);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byShortRetryLimit= %d\n", (int)pDevice->byShortRetryLimit);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byLongRetryLimit= %d\n", (int)pDevice->byLongRetryLimit);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byPreambleType= %d\n", (int)pDevice->byPreambleType);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byShortPreamble= %d\n", (int)pDevice->byShortPreamble);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " uConnectionRate= %d\n", (int)pDevice->uConnectionRate);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " byBBType= %d\n", (int)pDevice->byBBType);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pDevice->b11hEnable= %d\n", (int)pDevice->b11hEnable);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pDevice->bDiversityRegCtlON= %d\n", (int)pDevice->bDiversityRegCtlON);
}
-static void s_vCompleteCurrentMeasure (PSDevice pDevice, unsigned char byResult)
+static void s_vCompleteCurrentMeasure(PSDevice pDevice, unsigned char byResult)
{
- unsigned int ii;
- unsigned long dwDuration = 0;
- unsigned char byRPI0 = 0;
-
- for(ii=1;ii<8;ii++) {
- pDevice->dwRPIs[ii] *= 255;
- dwDuration |= *((unsigned short *) (pDevice->pCurrMeasureEID->sReq.abyDuration));
- dwDuration <<= 10;
- pDevice->dwRPIs[ii] /= dwDuration;
- pDevice->abyRPIs[ii] = (unsigned char) pDevice->dwRPIs[ii];
- byRPI0 += pDevice->abyRPIs[ii];
- }
- pDevice->abyRPIs[0] = (0xFF - byRPI0);
-
- if (pDevice->uNumOfMeasureEIDs == 0) {
- VNTWIFIbMeasureReport( pDevice->pMgmt,
- true,
- pDevice->pCurrMeasureEID,
- byResult,
- pDevice->byBasicMap,
- pDevice->byCCAFraction,
- pDevice->abyRPIs
- );
- } else {
- VNTWIFIbMeasureReport( pDevice->pMgmt,
- false,
- pDevice->pCurrMeasureEID,
- byResult,
- pDevice->byBasicMap,
- pDevice->byCCAFraction,
- pDevice->abyRPIs
- );
- CARDbStartMeasure (pDevice, pDevice->pCurrMeasureEID++, pDevice->uNumOfMeasureEIDs);
- }
-
+ unsigned int ii;
+ unsigned long dwDuration = 0;
+ unsigned char byRPI0 = 0;
+
+ for (ii = 1; ii < 8; ii++) {
+ pDevice->dwRPIs[ii] *= 255;
+ dwDuration |= *((unsigned short *)(pDevice->pCurrMeasureEID->sReq.abyDuration));
+ dwDuration <<= 10;
+ pDevice->dwRPIs[ii] /= dwDuration;
+ pDevice->abyRPIs[ii] = (unsigned char)pDevice->dwRPIs[ii];
+ byRPI0 += pDevice->abyRPIs[ii];
+ }
+ pDevice->abyRPIs[0] = (0xFF - byRPI0);
+
+ if (pDevice->uNumOfMeasureEIDs == 0) {
+ VNTWIFIbMeasureReport(pDevice->pMgmt,
+ true,
+ pDevice->pCurrMeasureEID,
+ byResult,
+ pDevice->byBasicMap,
+ pDevice->byCCAFraction,
+ pDevice->abyRPIs
+ );
+ } else {
+ VNTWIFIbMeasureReport(pDevice->pMgmt,
+ false,
+ pDevice->pCurrMeasureEID,
+ byResult,
+ pDevice->byBasicMap,
+ pDevice->byCCAFraction,
+ pDevice->abyRPIs
+ );
+ CARDbStartMeasure(pDevice, pDevice->pCurrMeasureEID++, pDevice->uNumOfMeasureEIDs);
+ }
}
-
-
//
// Initialisation of MAC & BBP registers
//
static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType)
{
- unsigned int ii;
- unsigned char byValue;
- unsigned char byValue1;
- unsigned char byCCKPwrdBm = 0;
- unsigned char byOFDMPwrdBm = 0;
- int zonetype=0;
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- MACbShutdown(pDevice->PortOffset);
- BBvSoftwareReset(pDevice->PortOffset);
-
- if ((InitType == DEVICE_INIT_COLD) ||
- (InitType == DEVICE_INIT_DXPL)) {
- // Do MACbSoftwareReset in MACvInitialize
- MACbSoftwareReset(pDevice->PortOffset);
- // force CCK
- pDevice->bCCK = true;
- pDevice->bAES = false;
- pDevice->bProtectMode = false; //Only used in 11g type, sync with ERP IE
- pDevice->bNonERPPresent = false;
- pDevice->bBarkerPreambleMd = false;
- pDevice->wCurrentRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_24M;
- pDevice->byTopCCKBasicRate = RATE_1M;
-
- pDevice->byRevId = 0; //Target to IF pin while programming to RF chip.
-
- // init MAC
- MACvInitialize(pDevice->PortOffset);
-
- // Get Local ID
- VNSvInPortB(pDevice->PortOffset + MAC_REG_LOCALID, &(pDevice->byLocalID));
-
- spin_lock_irq(&pDevice->lock);
- SROMvReadAllContents(pDevice->PortOffset,pDevice->abyEEPROM);
-
- spin_unlock_irq(&pDevice->lock);
-
- // Get Channel range
-
- pDevice->byMinChannel = 1;
- pDevice->byMaxChannel = CB_MAX_CHANNEL;
-
- // Get Antena
- byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
- if (byValue & EEP_ANTINV)
- pDevice->bTxRxAntInv = true;
- else
- pDevice->bTxRxAntInv = false;
-#ifdef PLICE_DEBUG
- //printk("init_register:TxRxAntInv is %d,byValue is %d\n",pDevice->bTxRxAntInv,byValue);
-#endif
-
- byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
- if (byValue == 0) // if not set default is All
- byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
-#ifdef PLICE_DEBUG
- //printk("init_register:byValue is %d\n",byValue);
-#endif
- pDevice->ulDiversityNValue = 100*260;//100*SROMbyReadEmbedded(pDevice->PortOffset, 0x51);
- pDevice->ulDiversityMValue = 100*16;//SROMbyReadEmbedded(pDevice->PortOffset, 0x52);
- pDevice->byTMax = 1;//SROMbyReadEmbedded(pDevice->PortOffset, 0x53);
- pDevice->byTMax2 = 4;//SROMbyReadEmbedded(pDevice->PortOffset, 0x54);
- pDevice->ulSQ3TH = 0;//(unsigned long) SROMbyReadEmbedded(pDevice->PortOffset, 0x55);
- pDevice->byTMax3 = 64;//SROMbyReadEmbedded(pDevice->PortOffset, 0x56);
-
- if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
- pDevice->byAntennaCount = 2;
- pDevice->byTxAntennaMode = ANT_B;
- pDevice->dwTxAntennaSel = 1;
- pDevice->dwRxAntennaSel = 1;
- if (pDevice->bTxRxAntInv == true)
- pDevice->byRxAntennaMode = ANT_A;
- else
- pDevice->byRxAntennaMode = ANT_B;
- // chester for antenna
-byValue1 = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
- // if (pDevice->bDiversityRegCtlON)
- if((byValue1&0x08)==0)
- pDevice->bDiversityEnable = false;//SROMbyReadEmbedded(pDevice->PortOffset, 0x50);
- else
- pDevice->bDiversityEnable = true;
-#ifdef PLICE_DEBUG
- //printk("aux |main antenna: RxAntennaMode is %d\n",pDevice->byRxAntennaMode);
-#endif
- } else {
- pDevice->bDiversityEnable = false;
- pDevice->byAntennaCount = 1;
- pDevice->dwTxAntennaSel = 0;
- pDevice->dwRxAntennaSel = 0;
- if (byValue & EEP_ANTENNA_AUX) {
- pDevice->byTxAntennaMode = ANT_A;
- if (pDevice->bTxRxAntInv == true)
- pDevice->byRxAntennaMode = ANT_B;
- else
- pDevice->byRxAntennaMode = ANT_A;
- } else {
- pDevice->byTxAntennaMode = ANT_B;
- if (pDevice->bTxRxAntInv == true)
- pDevice->byRxAntennaMode = ANT_A;
- else
- pDevice->byRxAntennaMode = ANT_B;
- }
- }
-#ifdef PLICE_DEBUG
- //printk("init registers: TxAntennaMode is %d\n",pDevice->byTxAntennaMode);
-#endif
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bDiversityEnable=[%d],NValue=[%d],MValue=[%d],TMax=[%d],TMax2=[%d]\n",
- pDevice->bDiversityEnable,(int)pDevice->ulDiversityNValue,(int)pDevice->ulDiversityMValue,pDevice->byTMax,pDevice->byTMax2);
-
-//#ifdef ZoneType_DefaultSetting
-//2008-8-4 <add> by chester
-//zonetype initial
- pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
- zonetype = Config_FileOperation(pDevice,false,NULL);
- if (zonetype >= 0) { //read zonetype file ok!
- if ((zonetype == 0)&&
- (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] !=0x00)){ //for USA
- pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0;
- pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0B;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Init Zone Type :USA\n");
- }
- else if((zonetype == 1)&&
- (pDevice->abyEEPROM[EEP_OFS_ZONETYPE]!=0x01)){ //for Japan
- pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x01;
- pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D;
- }
- else if((zonetype == 2)&&
- (pDevice->abyEEPROM[EEP_OFS_ZONETYPE]!=0x02)){ //for Europe
- pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x02;
- pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Init Zone Type :Europe\n");
- }
+ unsigned int ii;
+ unsigned char byValue;
+ unsigned char byValue1;
+ unsigned char byCCKPwrdBm = 0;
+ unsigned char byOFDMPwrdBm = 0;
+ int zonetype = 0;
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ MACbShutdown(pDevice->PortOffset);
+ BBvSoftwareReset(pDevice->PortOffset);
+
+ if ((InitType == DEVICE_INIT_COLD) ||
+ (InitType == DEVICE_INIT_DXPL)) {
+ // Do MACbSoftwareReset in MACvInitialize
+ MACbSoftwareReset(pDevice->PortOffset);
+ // force CCK
+ pDevice->bCCK = true;
+ pDevice->bAES = false;
+ pDevice->bProtectMode = false; //Only used in 11g type, sync with ERP IE
+ pDevice->bNonERPPresent = false;
+ pDevice->bBarkerPreambleMd = false;
+ pDevice->wCurrentRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_24M;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+
+ pDevice->byRevId = 0; //Target to IF pin while programming to RF chip.
+
+ // init MAC
+ MACvInitialize(pDevice->PortOffset);
+
+ // Get Local ID
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_LOCALID, &(pDevice->byLocalID));
-else
-{
- if(zonetype!=pDevice->abyEEPROM[EEP_OFS_ZONETYPE])
- printk("zonetype in file[%02x] mismatch with in EEPROM[%02x]\n",zonetype,pDevice->abyEEPROM[EEP_OFS_ZONETYPE]);
- else
- printk("Read Zonetype file success,use default zonetype setting[%02x]\n",zonetype);
- }
- }
- else
- printk("Read Zonetype file fail,use default zonetype setting[%02x]\n",SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ZONETYPE));
-
- // Get RFType
- pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
-
- if ((pDevice->byRFType & RF_EMU) != 0) {
- // force change RevID for VT3253 emu
- pDevice->byRevId = 0x80;
- }
-
- pDevice->byRFType &= RF_MASK;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRFType = %x\n", pDevice->byRFType);
-
- if (pDevice->bZoneRegExist == false) {
- pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byZoneType = %x\n", pDevice->byZoneType);
-
- //Init RF module
- RFbInit(pDevice);
-
- //Get Desire Power Value
- pDevice->byCurPwr = 0xFF;
- pDevice->byCCKPwr = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_CCK);
- pDevice->byOFDMPwrG = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_OFDMG);
- //byCCKPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_CCK_PWR_dBm);
-
- //byOFDMPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_OFDM_PWR_dBm);
-//printk("CCKPwrdBm is 0x%x,byOFDMPwrdBm is 0x%x\n",byCCKPwrdBm,byOFDMPwrdBm);
- // Load power Table
+ spin_lock_irq(&pDevice->lock);
+ SROMvReadAllContents(pDevice->PortOffset, pDevice->abyEEPROM);
+ spin_unlock_irq(&pDevice->lock);
- for (ii=0;ii<CB_MAX_CHANNEL_24G;ii++) {
- pDevice->abyCCKPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL));
- if (pDevice->abyCCKPwrTbl[ii+1] == 0) {
- pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr;
- }
- pDevice->abyOFDMPwrTbl[ii+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL));
- if (pDevice->abyOFDMPwrTbl[ii+1] == 0) {
- pDevice->abyOFDMPwrTbl[ii+1] = pDevice->byOFDMPwrG;
- }
- pDevice->abyCCKDefaultPwr[ii+1] = byCCKPwrdBm;
- pDevice->abyOFDMDefaultPwr[ii+1] = byOFDMPwrdBm;
- }
- //2008-8-4 <add> by chester
- //recover 12,13 ,14channel for EUROPE by 11 channel
- if(((pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Japan) ||
- (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Europe))&&
- (pDevice->byOriginalZonetype == ZoneType_USA)) {
- for(ii=11;ii<14;ii++) {
- pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10];
- pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10];
+ // Get Channel range
- }
- }
+ pDevice->byMinChannel = 1;
+ pDevice->byMaxChannel = CB_MAX_CHANNEL;
+ // Get Antena
+ byValue = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
+ if (byValue & EEP_ANTINV)
+ pDevice->bTxRxAntInv = true;
+ else
+ pDevice->bTxRxAntInv = false;
+
+ byValue &= (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
+ if (byValue == 0) // if not set default is All
+ byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
+
+ pDevice->ulDiversityNValue = 100*260;//100*SROMbyReadEmbedded(pDevice->PortOffset, 0x51);
+ pDevice->ulDiversityMValue = 100*16;//SROMbyReadEmbedded(pDevice->PortOffset, 0x52);
+ pDevice->byTMax = 1;//SROMbyReadEmbedded(pDevice->PortOffset, 0x53);
+ pDevice->byTMax2 = 4;//SROMbyReadEmbedded(pDevice->PortOffset, 0x54);
+ pDevice->ulSQ3TH = 0;//(unsigned long) SROMbyReadEmbedded(pDevice->PortOffset, 0x55);
+ pDevice->byTMax3 = 64;//SROMbyReadEmbedded(pDevice->PortOffset, 0x56);
+
+ if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
+ pDevice->byAntennaCount = 2;
+ pDevice->byTxAntennaMode = ANT_B;
+ pDevice->dwTxAntennaSel = 1;
+ pDevice->dwRxAntennaSel = 1;
+ if (pDevice->bTxRxAntInv == true)
+ pDevice->byRxAntennaMode = ANT_A;
+ else
+ pDevice->byRxAntennaMode = ANT_B;
+ // chester for antenna
+ byValue1 = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ANTENNA);
+ if ((byValue1 & 0x08) == 0)
+ pDevice->bDiversityEnable = false;//SROMbyReadEmbedded(pDevice->PortOffset, 0x50);
+ else
+ pDevice->bDiversityEnable = true;
+ } else {
+ pDevice->bDiversityEnable = false;
+ pDevice->byAntennaCount = 1;
+ pDevice->dwTxAntennaSel = 0;
+ pDevice->dwRxAntennaSel = 0;
+ if (byValue & EEP_ANTENNA_AUX) {
+ pDevice->byTxAntennaMode = ANT_A;
+ if (pDevice->bTxRxAntInv == true)
+ pDevice->byRxAntennaMode = ANT_B;
+ else
+ pDevice->byRxAntennaMode = ANT_A;
+ } else {
+ pDevice->byTxAntennaMode = ANT_B;
+ if (pDevice->bTxRxAntInv == true)
+ pDevice->byRxAntennaMode = ANT_A;
+ else
+ pDevice->byRxAntennaMode = ANT_B;
+ }
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bDiversityEnable=[%d],NValue=[%d],MValue=[%d],TMax=[%d],TMax2=[%d]\n",
+ pDevice->bDiversityEnable, (int)pDevice->ulDiversityNValue, (int)pDevice->ulDiversityMValue, pDevice->byTMax, pDevice->byTMax2);
- // Load OFDM A Power Table
- for (ii=0;ii<CB_MAX_CHANNEL_5G;ii++) { //RobertYu:20041224, bug using CB_MAX_CHANNEL
- pDevice->abyOFDMPwrTbl[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL));
- pDevice->abyOFDMDefaultPwr[ii+CB_MAX_CHANNEL_24G+1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm));
- }
- init_channel_table((void *)pDevice);
+//#ifdef ZoneType_DefaultSetting
+//2008-8-4 <add> by chester
+//zonetype initial
+ pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
+ zonetype = Config_FileOperation(pDevice, false, NULL);
+ if (zonetype >= 0) { //read zonetype file ok!
+ if ((zonetype == 0) &&
+ (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] != 0x00)) { //for USA
+ pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0;
+ pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0B;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Init Zone Type :USA\n");
+ } else if ((zonetype == 1) &&
+ (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] != 0x01)) { //for Japan
+ pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x01;
+ pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D;
+ } else if ((zonetype == 2) &&
+ (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] != 0x02)) { //for Europe
+ pDevice->abyEEPROM[EEP_OFS_ZONETYPE] = 0x02;
+ pDevice->abyEEPROM[EEP_OFS_MAXCHANNEL] = 0x0D;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Init Zone Type :Europe\n");
+ }
+ else {
+ if (zonetype != pDevice->abyEEPROM[EEP_OFS_ZONETYPE])
+ printk("zonetype in file[%02x] mismatch with in EEPROM[%02x]\n", zonetype, pDevice->abyEEPROM[EEP_OFS_ZONETYPE]);
+ else
+ printk("Read Zonetype file success,use default zonetype setting[%02x]\n", zonetype);
+ }
+ } else
+ printk("Read Zonetype file fail,use default zonetype setting[%02x]\n", SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_ZONETYPE));
- if (pDevice->byLocalID > REV_ID_VT3253_B1) {
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_MSRCTL + 1, (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN));
- MACvSelectPage0(pDevice->PortOffset);
- }
+ // Get RFType
+ pDevice->byRFType = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RFTYPE);
+ if ((pDevice->byRFType & RF_EMU) != 0) {
+ // force change RevID for VT3253 emu
+ pDevice->byRevId = 0x80;
+ }
- // use relative tx timeout and 802.11i D4
- MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT));
+ pDevice->byRFType &= RF_MASK;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRFType = %x\n", pDevice->byRFType);
- // set performance parameter by registry
- MACvSetShortRetryLimit(pDevice->PortOffset, pDevice->byShortRetryLimit);
- MACvSetLongRetryLimit(pDevice->PortOffset, pDevice->byLongRetryLimit);
+ if (pDevice->bZoneRegExist == false) {
+ pDevice->byZoneType = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byZoneType = %x\n", pDevice->byZoneType);
- // reset TSF counter
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
- // enable TSF counter
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
+ //Init RF module
+ RFbInit(pDevice);
- // initialize BBP registers
- BBbVT3253Init(pDevice);
+ //Get Desire Power Value
+ pDevice->byCurPwr = 0xFF;
+ pDevice->byCCKPwr = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_CCK);
+ pDevice->byOFDMPwrG = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_PWR_OFDMG);
+ //byCCKPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_CCK_PWR_dBm);
- if (pDevice->bUpdateBBVGA) {
- pDevice->byBBVGACurrent = pDevice->abyBBVGA[0];
- pDevice->byBBVGANew = pDevice->byBBVGACurrent;
- BBvSetVGAGainOffset(pDevice, pDevice->abyBBVGA[0]);
- }
-#ifdef PLICE_DEBUG
- //printk("init registers:RxAntennaMode is %x,TxAntennaMode is %x\n",pDevice->byRxAntennaMode,pDevice->byTxAntennaMode);
-#endif
- BBvSetRxAntennaMode(pDevice->PortOffset, pDevice->byRxAntennaMode);
- BBvSetTxAntennaMode(pDevice->PortOffset, pDevice->byTxAntennaMode);
+ //byOFDMPwrdBm = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_OFDM_PWR_dBm);
- pDevice->byCurrentCh = 0;
+ // Load power Table
- //pDevice->NetworkType = Ndis802_11Automode;
- // Set BB and packet type at the same time.
- // Set Short Slot Time, xIFS, and RSPINF.
- if (pDevice->uConnectionRate == RATE_AUTO) {
- pDevice->wCurrentRate = RATE_54M;
- } else {
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
+ for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) {
+ pDevice->abyCCKPwrTbl[ii + 1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_CCK_PWR_TBL));
+ if (pDevice->abyCCKPwrTbl[ii + 1] == 0) {
+ pDevice->abyCCKPwrTbl[ii+1] = pDevice->byCCKPwr;
+ }
+ pDevice->abyOFDMPwrTbl[ii + 1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDM_PWR_TBL));
+ if (pDevice->abyOFDMPwrTbl[ii + 1] == 0) {
+ pDevice->abyOFDMPwrTbl[ii + 1] = pDevice->byOFDMPwrG;
+ }
+ pDevice->abyCCKDefaultPwr[ii + 1] = byCCKPwrdBm;
+ pDevice->abyOFDMDefaultPwr[ii + 1] = byOFDMPwrdBm;
+ }
+ //2008-8-4 <add> by chester
+ //recover 12,13 ,14channel for EUROPE by 11 channel
+ if (((pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Japan) ||
+ (pDevice->abyEEPROM[EEP_OFS_ZONETYPE] == ZoneType_Europe)) &&
+ (pDevice->byOriginalZonetype == ZoneType_USA)) {
+ for (ii = 11; ii < 14; ii++) {
+ pDevice->abyCCKPwrTbl[ii] = pDevice->abyCCKPwrTbl[10];
+ pDevice->abyOFDMPwrTbl[ii] = pDevice->abyOFDMPwrTbl[10];
- // default G Mode
- VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_11G);
- VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_AUTO);
+ }
+ }
- pDevice->bRadioOff = false;
+ // Load OFDM A Power Table
+ for (ii = 0; ii < CB_MAX_CHANNEL_5G; ii++) { //RobertYu:20041224, bug using CB_MAX_CHANNEL
+ pDevice->abyOFDMPwrTbl[ii + CB_MAX_CHANNEL_24G + 1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_TBL));
+ pDevice->abyOFDMDefaultPwr[ii + CB_MAX_CHANNEL_24G + 1] = SROMbyReadEmbedded(pDevice->PortOffset, (unsigned char)(ii + EEP_OFS_OFDMA_PWR_dBm));
+ }
+ init_channel_table((void *)pDevice);
- pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL);
- pDevice->bHWRadioOff = false;
+ if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_MSRCTL + 1, (MSRCTL1_TXPWR | MSRCTL1_CSAPAREN));
+ MACvSelectPage0(pDevice->PortOffset);
+ }
- if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) {
- // Get GPIO
- MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
-//2008-4-14 <add> by chester for led issue
- #ifdef FOR_LED_ON_NOTEBOOK
-if (pDevice->byGPIO & GPIO0_DATA){pDevice->bHWRadioOff = true;}
-if ( !(pDevice->byGPIO & GPIO0_DATA)){pDevice->bHWRadioOff = false;}
-
- }
- if ( (pDevice->bRadioControlOff == true)) {
- CARDbRadioPowerOff(pDevice);
- }
-else CARDbRadioPowerOn(pDevice);
-#else
- if (((pDevice->byGPIO & GPIO0_DATA) && !(pDevice->byRadioCtl & EEP_RADIOCTL_INV)) ||
- ( !(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV))) {
- pDevice->bHWRadioOff = true;
- }
- }
- if ((pDevice->bHWRadioOff == true) || (pDevice->bRadioControlOff == true)) {
- CARDbRadioPowerOff(pDevice);
- }
+ // use relative tx timeout and 802.11i D4
+ MACvWordRegBitsOn(pDevice->PortOffset, MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT));
-#endif
- }
- pMgmt->eScanType = WMAC_SCAN_PASSIVE;
- // get Permanent network address
- SROMvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Network address = %pM\n",
- pDevice->abyCurrentNetAddr);
+ // set performance parameter by registry
+ MACvSetShortRetryLimit(pDevice->PortOffset, pDevice->byShortRetryLimit);
+ MACvSetLongRetryLimit(pDevice->PortOffset, pDevice->byLongRetryLimit);
- // reset Tx pointer
- CARDvSafeResetRx(pDevice);
- // reset Rx pointer
- CARDvSafeResetTx(pDevice);
+ // reset TSF counter
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
+ // enable TSF counter
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
- if (pDevice->byLocalID <= REV_ID_VT3253_A1) {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_WPAERR);
- }
+ // initialize BBP registers
+ BBbVT3253Init(pDevice);
- pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ if (pDevice->bUpdateBBVGA) {
+ pDevice->byBBVGACurrent = pDevice->abyBBVGA[0];
+ pDevice->byBBVGANew = pDevice->byBBVGACurrent;
+ BBvSetVGAGainOffset(pDevice, pDevice->abyBBVGA[0]);
+ }
+ BBvSetRxAntennaMode(pDevice->PortOffset, pDevice->byRxAntennaMode);
+ BBvSetTxAntennaMode(pDevice->PortOffset, pDevice->byTxAntennaMode);
- // Turn On Rx DMA
- MACvReceive0(pDevice->PortOffset);
- MACvReceive1(pDevice->PortOffset);
+ pDevice->byCurrentCh = 0;
- // start the adapter
- MACvStart(pDevice->PortOffset);
+ //pDevice->NetworkType = Ndis802_11Automode;
+ // Set BB and packet type at the same time.
+ // Set Short Slot Time, xIFS, and RSPINF.
+ if (pDevice->uConnectionRate == RATE_AUTO) {
+ pDevice->wCurrentRate = RATE_54M;
+ } else {
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
- netif_stop_queue(pDevice->dev);
+ // default G Mode
+ VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_11G);
+ VNTWIFIbConfigPhyMode(pDevice->pMgmt, PHY_TYPE_AUTO);
+ pDevice->bRadioOff = false;
-}
+ pDevice->byRadioCtl = SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL);
+ pDevice->bHWRadioOff = false;
+ if (pDevice->byRadioCtl & EEP_RADIOCTL_ENABLE) {
+ // Get GPIO
+ MACvGPIOIn(pDevice->PortOffset, &pDevice->byGPIO);
+//2008-4-14 <add> by chester for led issue
+#ifdef FOR_LED_ON_NOTEBOOK
+ if (pDevice->byGPIO & GPIO0_DATA) { pDevice->bHWRadioOff = true; }
+ if (!(pDevice->byGPIO & GPIO0_DATA)) { pDevice->bHWRadioOff = false; }
+ }
+ if ((pDevice->bRadioControlOff == true)) {
+ CARDbRadioPowerOff(pDevice);
+ } else CARDbRadioPowerOn(pDevice);
+#else
+ if (((pDevice->byGPIO & GPIO0_DATA) && !(pDevice->byRadioCtl & EEP_RADIOCTL_INV)) ||
+ (!(pDevice->byGPIO & GPIO0_DATA) && (pDevice->byRadioCtl & EEP_RADIOCTL_INV))) {
+ pDevice->bHWRadioOff = true;
+ }
+ }
+ if ((pDevice->bHWRadioOff == true) || (pDevice->bRadioControlOff == true)) {
+ CARDbRadioPowerOff(pDevice);
+ }
-static void device_init_diversity_timer(PSDevice pDevice) {
+#endif
+}
+pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+// get Permanent network address
+SROMvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr);
+DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Network address = %pM\n",
+ pDevice->abyCurrentNetAddr);
+
+// reset Tx pointer
+CARDvSafeResetRx(pDevice);
+// reset Rx pointer
+CARDvSafeResetTx(pDevice);
+
+if (pDevice->byLocalID <= REV_ID_VT3253_A1) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_RCR, RCR_WPAERR);
+}
- init_timer(&pDevice->TimerSQ3Tmax1);
- pDevice->TimerSQ3Tmax1.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax1.function = (TimerFunction)TimerSQ3CallBack;
- pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ);
+pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- init_timer(&pDevice->TimerSQ3Tmax2);
- pDevice->TimerSQ3Tmax2.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax2.function = (TimerFunction)TimerSQ3CallBack;
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ);
+// Turn On Rx DMA
+MACvReceive0(pDevice->PortOffset);
+MACvReceive1(pDevice->PortOffset);
- init_timer(&pDevice->TimerSQ3Tmax3);
- pDevice->TimerSQ3Tmax3.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax3.function = (TimerFunction)TimerState1CallBack;
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ);
+// start the adapter
+MACvStart(pDevice->PortOffset);
- return;
+netif_stop_queue(pDevice->dev);
}
+static void device_init_diversity_timer(PSDevice pDevice) {
+ init_timer(&pDevice->TimerSQ3Tmax1);
+ pDevice->TimerSQ3Tmax1.data = (unsigned long) pDevice;
+ pDevice->TimerSQ3Tmax1.function = (TimerFunction)TimerSQ3CallBack;
+ pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ);
+
+ init_timer(&pDevice->TimerSQ3Tmax2);
+ pDevice->TimerSQ3Tmax2.data = (unsigned long) pDevice;
+ pDevice->TimerSQ3Tmax2.function = (TimerFunction)TimerSQ3CallBack;
+ pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ);
+
+ init_timer(&pDevice->TimerSQ3Tmax3);
+ pDevice->TimerSQ3Tmax3.data = (unsigned long) pDevice;
+ pDevice->TimerSQ3Tmax3.function = (TimerFunction)TimerState1CallBack;
+ pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ);
+
+ return;
+}
static bool device_release_WPADEV(PSDevice pDevice)
{
- viawget_wpa_header *wpahdr;
- int ii=0;
- // wait_queue_head_t Set_wait;
- //send device close to wpa_supplicnat layer
- if (pDevice->bWPADEVUp==true) {
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- wpahdr->type = VIAWGET_DEVICECLOSE_MSG;
- wpahdr->resp_ie_len = 0;
- wpahdr->req_ie_len = 0;
- skb_put(pDevice->skb, sizeof(viawget_wpa_header));
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
-
- //wait release WPADEV
- // init_waitqueue_head(&Set_wait);
- // wait_event_timeout(Set_wait, ((pDevice->wpadev==NULL)&&(pDevice->skb == NULL)),5*HZ); //1s wait
- while((pDevice->bWPADEVUp==true)) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout (HZ/20); //wait 50ms
- ii++;
- if(ii>20)
- break;
- }
- }
- return true;
+ viawget_wpa_header *wpahdr;
+ int ii = 0;
+ // wait_queue_head_t Set_wait;
+ //send device close to wpa_supplicnat layer
+ if (pDevice->bWPADEVUp == true) {
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ wpahdr->type = VIAWGET_DEVICECLOSE_MSG;
+ wpahdr->resp_ie_len = 0;
+ wpahdr->req_ie_len = 0;
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header));
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+
+ //wait release WPADEV
+ // init_waitqueue_head(&Set_wait);
+ // wait_event_timeout(Set_wait, ((pDevice->wpadev==NULL)&&(pDevice->skb == NULL)),5*HZ); //1s wait
+ while ((pDevice->bWPADEVUp == true)) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ / 20); //wait 50ms
+ ii++;
+ if (ii > 20)
+ break;
+ }
+ }
+ return true;
}
static const struct net_device_ops device_netdev_ops = {
@@ -906,93 +849,88 @@ static const struct net_device_ops device_netdev_ops = {
static int
vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
{
- static bool bFirst = true;
- struct net_device* dev = NULL;
- PCHIP_INFO pChip_info = (PCHIP_INFO)ent->driver_data;
- PSDevice pDevice;
- int rc;
- if (device_nics ++>= MAX_UINTS) {
- printk(KERN_NOTICE DEVICE_NAME ": already found %d NICs\n", device_nics);
- return -ENODEV;
- }
-
-
- dev = alloc_etherdev(sizeof(DEVICE_INFO));
-
- pDevice = (PSDevice) netdev_priv(dev);
-
- if (dev == NULL) {
- printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n");
- return -ENOMEM;
- }
-
- // Chain it all together
- // SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pcid->dev);
-
- if (bFirst) {
- printk(KERN_NOTICE "%s Ver. %s\n",DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
- printk(KERN_NOTICE "Copyright (c) 2003 VIA Networking Technologies, Inc.\n");
- bFirst=false;
- }
-
- vt6655_init_info(pcid, &pDevice, pChip_info);
- pDevice->dev = dev;
- pDevice->next_module = root_device_dev;
- root_device_dev = dev;
-
- if (pci_enable_device(pcid)) {
- device_free_info(pDevice);
- return -ENODEV;
- }
- dev->irq = pcid->irq;
+ static bool bFirst = true;
+ struct net_device *dev = NULL;
+ PCHIP_INFO pChip_info = (PCHIP_INFO)ent->driver_data;
+ PSDevice pDevice;
+ int rc;
+ if (device_nics++ >= MAX_UINTS) {
+ printk(KERN_NOTICE DEVICE_NAME ": already found %d NICs\n", device_nics);
+ return -ENODEV;
+ }
+
+ dev = alloc_etherdev(sizeof(DEVICE_INFO));
+
+ pDevice = (PSDevice) netdev_priv(dev);
+
+ if (dev == NULL) {
+ printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n");
+ return -ENOMEM;
+ }
+
+ // Chain it all together
+ // SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pcid->dev);
+
+ if (bFirst) {
+ printk(KERN_NOTICE "%s Ver. %s\n", DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
+ printk(KERN_NOTICE "Copyright (c) 2003 VIA Networking Technologies, Inc.\n");
+ bFirst = false;
+ }
+
+ vt6655_init_info(pcid, &pDevice, pChip_info);
+ pDevice->dev = dev;
+ pDevice->next_module = root_device_dev;
+ root_device_dev = dev;
+
+ if (pci_enable_device(pcid)) {
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
+ dev->irq = pcid->irq;
#ifdef DEBUG
- printk("Before get pci_info memaddr is %x\n",pDevice->memaddr);
+ printk("Before get pci_info memaddr is %x\n", pDevice->memaddr);
#endif
- if (device_get_pci_info(pDevice,pcid) == false) {
- printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device.\n");
- device_free_info(pDevice);
- return -ENODEV;
- }
+ if (device_get_pci_info(pDevice, pcid) == false) {
+ printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device.\n");
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
#if 1
#ifdef DEBUG
//pci_read_config_byte(pcid, PCI_BASE_ADDRESS_0, &pDevice->byRevId);
- printk("after get pci_info memaddr is %x, io addr is %x,io_size is %d\n",pDevice->memaddr,pDevice->ioaddr,pDevice->io_size);
+ printk("after get pci_info memaddr is %x, io addr is %x,io_size is %d\n", pDevice->memaddr, pDevice->ioaddr, pDevice->io_size);
{
int i;
- u32 bar,len;
+ u32 bar, len;
u32 address[] = {
- PCI_BASE_ADDRESS_0,
- PCI_BASE_ADDRESS_1,
- PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3,
- PCI_BASE_ADDRESS_4,
- PCI_BASE_ADDRESS_5,
- 0};
- for (i=0;address[i];i++)
- {
+ PCI_BASE_ADDRESS_0,
+ PCI_BASE_ADDRESS_1,
+ PCI_BASE_ADDRESS_2,
+ PCI_BASE_ADDRESS_3,
+ PCI_BASE_ADDRESS_4,
+ PCI_BASE_ADDRESS_5,
+ 0};
+ for (i = 0; address[i]; i++) {
//pci_write_config_dword(pcid,address[i], 0xFFFFFFFF);
pci_read_config_dword(pcid, address[i], &bar);
- printk("bar %d is %x\n",i,bar);
- if (!bar)
- {
- printk("bar %d not implemented\n",i);
+ printk("bar %d is %x\n", i, bar);
+ if (!bar) {
+ printk("bar %d not implemented\n", i);
continue;
}
if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
- /* This is IO */
+ /* This is IO */
- len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
- len = len & ~(len - 1);
+ len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+ len = len & ~(len - 1);
- printk("IO space: len in IO %x, BAR %d\n", len, i);
- }
- else
- {
+ printk("IO space: len in IO %x, BAR %d\n", len, i);
+ } else {
len = bar & 0xFFFFFFF0;
len = ~len + 1;
@@ -1002,813 +940,745 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent)
}
#endif
-
#endif
#ifdef DEBUG
- //return 0 ;
+ //return 0;
#endif
- pDevice->PortOffset = (unsigned long)ioremap(pDevice->memaddr & PCI_BASE_ADDRESS_MEM_MASK, pDevice->io_size);
+ pDevice->PortOffset = (unsigned long)ioremap(pDevice->memaddr & PCI_BASE_ADDRESS_MEM_MASK, pDevice->io_size);
//pDevice->PortOffset = (unsigned long)ioremap(pDevice->ioaddr & PCI_BASE_ADDRESS_IO_MASK, pDevice->io_size);
- if(pDevice->PortOffset == 0) {
- printk(KERN_ERR DEVICE_NAME ": Failed to IO remapping ..\n");
- device_free_info(pDevice);
- return -ENODEV;
- }
-
-
-
+ if (pDevice->PortOffset == 0) {
+ printk(KERN_ERR DEVICE_NAME ": Failed to IO remapping ..\n");
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
- rc = pci_request_regions(pcid, DEVICE_NAME);
- if (rc) {
- printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device\n");
- device_free_info(pDevice);
- return -ENODEV;
- }
+ rc = pci_request_regions(pcid, DEVICE_NAME);
+ if (rc) {
+ printk(KERN_ERR DEVICE_NAME ": Failed to find PCI device\n");
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
- dev->base_addr = pDevice->ioaddr;
+ dev->base_addr = pDevice->ioaddr;
#ifdef PLICE_DEBUG
- unsigned char value;
+ unsigned char value;
VNSvInPortB(pDevice->PortOffset+0x4F, &value);
- printk("Before write: value is %x\n",value);
+ printk("Before write: value is %x\n", value);
//VNSvInPortB(pDevice->PortOffset+0x3F, 0x00);
- VNSvOutPortB(pDevice->PortOffset,value);
+ VNSvOutPortB(pDevice->PortOffset, value);
VNSvInPortB(pDevice->PortOffset+0x4F, &value);
- printk("After write: value is %x\n",value);
+ printk("After write: value is %x\n", value);
#endif
-
-
#ifdef IO_MAP
- pDevice->PortOffset = pDevice->ioaddr;
+ pDevice->PortOffset = pDevice->ioaddr;
#endif
- // do reset
- if (!MACbSoftwareReset(pDevice->PortOffset)) {
- printk(KERN_ERR DEVICE_NAME ": Failed to access MAC hardware..\n");
- device_free_info(pDevice);
- return -ENODEV;
- }
- // initial to reload eeprom
- MACvInitialize(pDevice->PortOffset);
- MACvReadEtherAddress(pDevice->PortOffset, dev->dev_addr);
-
- device_get_options(pDevice, device_nics-1, dev->name);
- device_set_options(pDevice);
- //Mask out the options cannot be set to the chip
- pDevice->sOpts.flags &= pChip_info->flags;
-
- //Enable the chip specified capabilities
- pDevice->flags = pDevice->sOpts.flags | (pChip_info->flags & 0xFF000000UL);
- pDevice->tx_80211 = device_dma0_tx_80211;
- pDevice->sMgmtObj.pAdapter = (void *)pDevice;
- pDevice->pMgmt = &(pDevice->sMgmtObj);
-
- dev->irq = pcid->irq;
- dev->netdev_ops = &device_netdev_ops;
+ // do reset
+ if (!MACbSoftwareReset(pDevice->PortOffset)) {
+ printk(KERN_ERR DEVICE_NAME ": Failed to access MAC hardware..\n");
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
+ // initial to reload eeprom
+ MACvInitialize(pDevice->PortOffset);
+ MACvReadEtherAddress(pDevice->PortOffset, dev->dev_addr);
- dev->wireless_handlers = (struct iw_handler_def *)&iwctl_handler_def;
+ device_get_options(pDevice, device_nics-1, dev->name);
+ device_set_options(pDevice);
+ //Mask out the options cannot be set to the chip
+ pDevice->sOpts.flags &= pChip_info->flags;
+
+ //Enable the chip specified capabilities
+ pDevice->flags = pDevice->sOpts.flags | (pChip_info->flags & 0xFF000000UL);
+ pDevice->tx_80211 = device_dma0_tx_80211;
+ pDevice->sMgmtObj.pAdapter = (void *)pDevice;
+ pDevice->pMgmt = &(pDevice->sMgmtObj);
- rc = register_netdev(dev);
- if (rc)
- {
- printk(KERN_ERR DEVICE_NAME " Failed to register netdev\n");
- device_free_info(pDevice);
- return -ENODEV;
- }
- device_print_info(pDevice);
- pci_set_drvdata(pcid, pDevice);
- return 0;
+ dev->irq = pcid->irq;
+ dev->netdev_ops = &device_netdev_ops;
+
+ dev->wireless_handlers = (struct iw_handler_def *)&iwctl_handler_def;
+ rc = register_netdev(dev);
+ if (rc) {
+ printk(KERN_ERR DEVICE_NAME " Failed to register netdev\n");
+ device_free_info(pDevice);
+ return -ENODEV;
+ }
+ device_print_info(pDevice);
+ pci_set_drvdata(pcid, pDevice);
+ return 0;
}
static void device_print_info(PSDevice pDevice)
{
- struct net_device* dev=pDevice->dev;
+ struct net_device *dev = pDevice->dev;
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: %s\n",dev->name, get_chip_name(pDevice->chip_id));
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%pM", dev->name, dev->dev_addr);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: %s\n", dev->name, get_chip_name(pDevice->chip_id));
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: MAC=%pM", dev->name, dev->dev_addr);
#ifdef IO_MAP
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx ",(unsigned long) pDevice->ioaddr);
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO " IO=0x%lx ", (unsigned long)pDevice->ioaddr);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO " IRQ=%d \n", pDevice->dev->irq);
#else
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IO=0x%lx Mem=0x%lx ",
- (unsigned long) pDevice->ioaddr,(unsigned long) pDevice->PortOffset);
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO" IRQ=%d \n", pDevice->dev->irq);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO " IO=0x%lx Mem=0x%lx ",
+ (unsigned long)pDevice->ioaddr, (unsigned long)pDevice->PortOffset);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO " IRQ=%d \n", pDevice->dev->irq);
#endif
-
}
-static void vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice,
- PCHIP_INFO pChip_info) {
-
- PSDevice p;
+static void vt6655_init_info(struct pci_dev *pcid, PSDevice *ppDevice,
+ PCHIP_INFO pChip_info) {
+ PSDevice p;
- memset(*ppDevice,0,sizeof(DEVICE_INFO));
+ memset(*ppDevice, 0, sizeof(DEVICE_INFO));
- if (pDevice_Infos == NULL) {
- pDevice_Infos =*ppDevice;
- }
- else {
- for (p=pDevice_Infos;p->next!=NULL;p=p->next)
- do {} while (0);
- p->next = *ppDevice;
- (*ppDevice)->prev = p;
- }
+ if (pDevice_Infos == NULL) {
+ pDevice_Infos = *ppDevice;
+ } else {
+ for (p = pDevice_Infos; p->next != NULL; p = p->next)
+ do {} while (0);
+ p->next = *ppDevice;
+ (*ppDevice)->prev = p;
+ }
- (*ppDevice)->pcid = pcid;
- (*ppDevice)->chip_id = pChip_info->chip_id;
- (*ppDevice)->io_size = pChip_info->io_size;
- (*ppDevice)->nTxQueues = pChip_info->nTxQueue;
- (*ppDevice)->multicast_limit =32;
+ (*ppDevice)->pcid = pcid;
+ (*ppDevice)->chip_id = pChip_info->chip_id;
+ (*ppDevice)->io_size = pChip_info->io_size;
+ (*ppDevice)->nTxQueues = pChip_info->nTxQueue;
+ (*ppDevice)->multicast_limit = 32;
- spin_lock_init(&((*ppDevice)->lock));
+ spin_lock_init(&((*ppDevice)->lock));
}
-static bool device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) {
-
- u16 pci_cmd;
- u8 b;
- unsigned int cis_addr;
+static bool device_get_pci_info(PSDevice pDevice, struct pci_dev *pcid) {
+ u16 pci_cmd;
+ u8 b;
+ unsigned int cis_addr;
#ifdef PLICE_DEBUG
unsigned char pci_config[256];
- unsigned char value =0x00;
- int ii,j;
- u16 max_lat=0x0000;
- memset(pci_config,0x00,256);
+ unsigned char value = 0x00;
+ int ii, j;
+ u16 max_lat = 0x0000;
+ memset(pci_config, 0x00, 256);
#endif
- pci_read_config_byte(pcid, PCI_REVISION_ID, &pDevice->byRevId);
- pci_read_config_word(pcid, PCI_SUBSYSTEM_ID,&pDevice->SubSystemID);
- pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, &pDevice->SubVendorID);
- pci_read_config_word(pcid, PCI_COMMAND, (u16 *) & (pci_cmd));
+ pci_read_config_byte(pcid, PCI_REVISION_ID, &pDevice->byRevId);
+ pci_read_config_word(pcid, PCI_SUBSYSTEM_ID, &pDevice->SubSystemID);
+ pci_read_config_word(pcid, PCI_SUBSYSTEM_VENDOR_ID, &pDevice->SubVendorID);
+ pci_read_config_word(pcid, PCI_COMMAND, (u16 *)&(pci_cmd));
- pci_set_master(pcid);
+ pci_set_master(pcid);
- pDevice->memaddr = pci_resource_start(pcid,0);
- pDevice->ioaddr = pci_resource_start(pcid,1);
+ pDevice->memaddr = pci_resource_start(pcid, 0);
+ pDevice->ioaddr = pci_resource_start(pcid, 1);
#ifdef DEBUG
// pDevice->ioaddr = pci_resource_start(pcid, 0);
// pDevice->memaddr = pci_resource_start(pcid,1);
#endif
- cis_addr = pci_resource_start(pcid,2);
+ cis_addr = pci_resource_start(pcid, 2);
- pDevice->pcid = pcid;
+ pDevice->pcid = pcid;
- pci_read_config_byte(pcid, PCI_COMMAND, &b);
- pci_write_config_byte(pcid, PCI_COMMAND, (b|PCI_COMMAND_MASTER));
+ pci_read_config_byte(pcid, PCI_COMMAND, &b);
+ pci_write_config_byte(pcid, PCI_COMMAND, (b|PCI_COMMAND_MASTER));
#ifdef PLICE_DEBUG
- //pci_read_config_word(pcid,PCI_MAX_LAT,&max_lat);
- //printk("max lat is %x,SubSystemID is %x\n",max_lat,pDevice->SubSystemID);
+ //pci_read_config_word(pcid,PCI_MAX_LAT,&max_lat);
//for (ii=0;ii<0xFF;ii++)
//pci_read_config_word(pcid,PCI_MAX_LAT,&max_lat);
//max_lat = 0x20;
//pci_write_config_word(pcid,PCI_MAX_LAT,max_lat);
//pci_read_config_word(pcid,PCI_MAX_LAT,&max_lat);
- //printk("max lat is %x\n",max_lat);
- for (ii=0;ii<0xFF;ii++)
- {
- pci_read_config_byte(pcid,ii,&value);
+ for (ii = 0; ii < 0xFF; ii++) {
+ pci_read_config_byte(pcid, ii, &value);
pci_config[ii] = value;
}
- for (ii=0,j=1;ii<0x100;ii++,j++)
- {
- if (j %16 == 0)
- {
- printk("%x:",pci_config[ii]);
+ for (ii = 0, j = 1; ii < 0x100; ii++, j++) {
+ if (j % 16 == 0) {
+ printk("%x:", pci_config[ii]);
printk("\n");
- }
- else
- {
- printk("%x:",pci_config[ii]);
+ } else {
+ printk("%x:", pci_config[ii]);
}
}
#endif
- return true;
+ return true;
}
static void device_free_info(PSDevice pDevice) {
- PSDevice ptr;
- struct net_device* dev=pDevice->dev;
+ PSDevice ptr;
+ struct net_device *dev = pDevice->dev;
- ASSERT(pDevice);
+ ASSERT(pDevice);
//2008-0714-01<Add>by chester
-device_release_WPADEV(pDevice);
+ device_release_WPADEV(pDevice);
//2008-07-21-01<Add>by MikeLiu
//unregister wpadev
- if(wpa_set_wpadev(pDevice, 0)!=0)
- printk("unregister wpadev fail?\n");
-
- if (pDevice_Infos==NULL)
- return;
-
- for (ptr=pDevice_Infos;ptr && (ptr!=pDevice);ptr=ptr->next)
- do {} while (0);
-
- if (ptr==pDevice) {
- if (ptr==pDevice_Infos)
- pDevice_Infos=ptr->next;
- else
- ptr->prev->next=ptr->next;
- }
- else {
- DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "info struct not found\n");
- return;
- }
+ if (wpa_set_wpadev(pDevice, 0) != 0)
+ printk("unregister wpadev fail?\n");
+
+ if (pDevice_Infos == NULL)
+ return;
+
+ for (ptr = pDevice_Infos; ptr && (ptr != pDevice); ptr = ptr->next)
+ do {} while (0);
+
+ if (ptr == pDevice) {
+ if (ptr == pDevice_Infos)
+ pDevice_Infos = ptr->next;
+ else
+ ptr->prev->next = ptr->next;
+ } else {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "info struct not found\n");
+ return;
+ }
#ifdef HOSTAP
- if (dev)
- vt6655_hostap_set_hostapd(pDevice, 0, 0);
+ if (dev)
+ vt6655_hostap_set_hostapd(pDevice, 0, 0);
#endif
- if (dev)
- unregister_netdev(dev);
+ if (dev)
+ unregister_netdev(dev);
- if (pDevice->PortOffset)
- iounmap((void *)pDevice->PortOffset);
+ if (pDevice->PortOffset)
+ iounmap((void *)pDevice->PortOffset);
- if (pDevice->pcid)
- pci_release_regions(pDevice->pcid);
- if (dev)
- free_netdev(dev);
+ if (pDevice->pcid)
+ pci_release_regions(pDevice->pcid);
+ if (dev)
+ free_netdev(dev);
- if (pDevice->pcid) {
- pci_set_drvdata(pDevice->pcid,NULL);
- }
+ if (pDevice->pcid) {
+ pci_set_drvdata(pDevice->pcid, NULL);
+ }
}
static bool device_init_rings(PSDevice pDevice) {
- void* vir_pool;
-
-
- /*allocate all RD/TD rings a single pool*/
- vir_pool = pci_alloc_consistent(pDevice->pcid,
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
- pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
- pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
- pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
- &pDevice->pool_dma);
-
- if (vir_pool == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate desc dma memory failed\n", pDevice->dev->name);
- return false;
- }
-
- memset(vir_pool, 0,
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
- pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
- pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
- pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc)
- );
-
- pDevice->aRD0Ring = vir_pool;
- pDevice->aRD1Ring = vir_pool +
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);
-
-
- pDevice->rd0_pool_dma = pDevice->pool_dma;
- pDevice->rd1_pool_dma = pDevice->rd0_pool_dma +
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);
-
- pDevice->tx0_bufs = pci_alloc_consistent(pDevice->pcid,
- pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
- pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
- CB_BEACON_BUF_SIZE +
- CB_MAX_BUF_SIZE,
- &pDevice->tx_bufs_dma0);
-
- if (pDevice->tx0_bufs == NULL) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: allocate buf dma memory failed\n", pDevice->dev->name);
- pci_free_consistent(pDevice->pcid,
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
- pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
- pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
- pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
- vir_pool, pDevice->pool_dma
- );
- return false;
- }
-
- memset(pDevice->tx0_bufs, 0,
- pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
- pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
- CB_BEACON_BUF_SIZE +
- CB_MAX_BUF_SIZE
- );
-
- pDevice->td0_pool_dma = pDevice->rd1_pool_dma +
- pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);
-
- pDevice->td1_pool_dma = pDevice->td0_pool_dma +
- pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);
-
+ void *vir_pool;
+
+ /*allocate all RD/TD rings a single pool*/
+ vir_pool = pci_alloc_consistent(pDevice->pcid,
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
+ pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
+ &pDevice->pool_dma);
+
+ if (vir_pool == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s : allocate desc dma memory failed\n", pDevice->dev->name);
+ return false;
+ }
- // vir_pool: pvoid type
- pDevice->apTD0Rings = vir_pool
- + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
- + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);
+ memset(vir_pool, 0,
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
+ pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc)
+ );
+
+ pDevice->aRD0Ring = vir_pool;
+ pDevice->aRD1Ring = vir_pool +
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);
+
+ pDevice->rd0_pool_dma = pDevice->pool_dma;
+ pDevice->rd1_pool_dma = pDevice->rd0_pool_dma +
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc);
+
+ pDevice->tx0_bufs = pci_alloc_consistent(pDevice->pcid,
+ pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
+ pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
+ CB_BEACON_BUF_SIZE +
+ CB_MAX_BUF_SIZE,
+ &pDevice->tx_bufs_dma0);
+
+ if (pDevice->tx0_bufs == NULL) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: allocate buf dma memory failed\n", pDevice->dev->name);
+ pci_free_consistent(pDevice->pcid,
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
+ pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc),
+ vir_pool, pDevice->pool_dma
+ );
+ return false;
+ }
- pDevice->apTD1Rings = vir_pool
- + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
- + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc)
- + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);
+ memset(pDevice->tx0_bufs, 0,
+ pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
+ pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
+ CB_BEACON_BUF_SIZE +
+ CB_MAX_BUF_SIZE
+ );
+ pDevice->td0_pool_dma = pDevice->rd1_pool_dma +
+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);
- pDevice->tx1_bufs = pDevice->tx0_bufs +
- pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;
+ pDevice->td1_pool_dma = pDevice->td0_pool_dma +
+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);
+ // vir_pool: pvoid type
+ pDevice->apTD0Rings = vir_pool
+ + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
+ + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc);
- pDevice->tx_beacon_bufs = pDevice->tx1_bufs +
- pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;
+ pDevice->apTD1Rings = vir_pool
+ + pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc)
+ + pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc)
+ + pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc);
- pDevice->pbyTmpBuff = pDevice->tx_beacon_bufs +
- CB_BEACON_BUF_SIZE;
+ pDevice->tx1_bufs = pDevice->tx0_bufs +
+ pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;
- pDevice->tx_bufs_dma1 = pDevice->tx_bufs_dma0 +
- pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;
+ pDevice->tx_beacon_bufs = pDevice->tx1_bufs +
+ pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;
+ pDevice->pbyTmpBuff = pDevice->tx_beacon_bufs +
+ CB_BEACON_BUF_SIZE;
- pDevice->tx_beacon_dma = pDevice->tx_bufs_dma1 +
- pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;
+ pDevice->tx_bufs_dma1 = pDevice->tx_bufs_dma0 +
+ pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ;
+ pDevice->tx_beacon_dma = pDevice->tx_bufs_dma1 +
+ pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ;
- return true;
+ return true;
}
static void device_free_rings(PSDevice pDevice) {
-
- pci_free_consistent(pDevice->pcid,
- pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
- pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
- pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
- pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc)
- ,
- pDevice->aRD0Ring, pDevice->pool_dma
- );
-
- if (pDevice->tx0_bufs)
- pci_free_consistent(pDevice->pcid,
- pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
- pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
- CB_BEACON_BUF_SIZE +
- CB_MAX_BUF_SIZE,
- pDevice->tx0_bufs, pDevice->tx_bufs_dma0
- );
+ pci_free_consistent(pDevice->pcid,
+ pDevice->sOpts.nRxDescs0 * sizeof(SRxDesc) +
+ pDevice->sOpts.nRxDescs1 * sizeof(SRxDesc) +
+ pDevice->sOpts.nTxDescs[0] * sizeof(STxDesc) +
+ pDevice->sOpts.nTxDescs[1] * sizeof(STxDesc)
+ ,
+ pDevice->aRD0Ring, pDevice->pool_dma
+ );
+
+ if (pDevice->tx0_bufs)
+ pci_free_consistent(pDevice->pcid,
+ pDevice->sOpts.nTxDescs[0] * PKT_BUF_SZ +
+ pDevice->sOpts.nTxDescs[1] * PKT_BUF_SZ +
+ CB_BEACON_BUF_SIZE +
+ CB_MAX_BUF_SIZE,
+ pDevice->tx0_bufs, pDevice->tx_bufs_dma0
+ );
}
static void device_init_rd0_ring(PSDevice pDevice) {
- int i;
- dma_addr_t curr = pDevice->rd0_pool_dma;
- PSRxDesc pDesc;
-
- /* Init the RD0 ring entries */
- for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) {
- pDesc = &(pDevice->aRD0Ring[i]);
- pDesc->pRDInfo = alloc_rd_info();
- ASSERT(pDesc->pRDInfo);
- if (!device_alloc_rx_buf(pDevice, pDesc)) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc rx bufs\n",
- pDevice->dev->name);
- }
- pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]);
- pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
- pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
- }
-
- if (i > 0)
- pDevice->aRD0Ring[i-1].next_desc = cpu_to_le32(pDevice->rd0_pool_dma);
- pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]);
-}
+ int i;
+ dma_addr_t curr = pDevice->rd0_pool_dma;
+ PSRxDesc pDesc;
+
+ /* Init the RD0 ring entries */
+ for (i = 0; i < pDevice->sOpts.nRxDescs0; i ++, curr += sizeof(SRxDesc)) {
+ pDesc = &(pDevice->aRD0Ring[i]);
+ pDesc->pRDInfo = alloc_rd_info();
+ ASSERT(pDesc->pRDInfo);
+ if (!device_alloc_rx_buf(pDevice, pDesc)) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc rx bufs\n",
+ pDevice->dev->name);
+ }
+ pDesc->next = &(pDevice->aRD0Ring[(i+1) % pDevice->sOpts.nRxDescs0]);
+ pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
+ pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
+ }
+ if (i > 0)
+ pDevice->aRD0Ring[i-1].next_desc = cpu_to_le32(pDevice->rd0_pool_dma);
+ pDevice->pCurrRD[0] = &(pDevice->aRD0Ring[0]);
+}
static void device_init_rd1_ring(PSDevice pDevice) {
- int i;
- dma_addr_t curr = pDevice->rd1_pool_dma;
- PSRxDesc pDesc;
-
- /* Init the RD1 ring entries */
- for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) {
- pDesc = &(pDevice->aRD1Ring[i]);
- pDesc->pRDInfo = alloc_rd_info();
- ASSERT(pDesc->pRDInfo);
- if (!device_alloc_rx_buf(pDevice, pDesc)) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc rx bufs\n",
- pDevice->dev->name);
- }
- pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]);
- pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
- pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
- }
-
- if (i > 0)
- pDevice->aRD1Ring[i-1].next_desc = cpu_to_le32(pDevice->rd1_pool_dma);
- pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]);
-}
+ int i;
+ dma_addr_t curr = pDevice->rd1_pool_dma;
+ PSRxDesc pDesc;
+
+ /* Init the RD1 ring entries */
+ for (i = 0; i < pDevice->sOpts.nRxDescs1; i ++, curr += sizeof(SRxDesc)) {
+ pDesc = &(pDevice->aRD1Ring[i]);
+ pDesc->pRDInfo = alloc_rd_info();
+ ASSERT(pDesc->pRDInfo);
+ if (!device_alloc_rx_buf(pDevice, pDesc)) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc rx bufs\n",
+ pDevice->dev->name);
+ }
+ pDesc->next = &(pDevice->aRD1Ring[(i+1) % pDevice->sOpts.nRxDescs1]);
+ pDesc->pRDInfo->curr_desc = cpu_to_le32(curr);
+ pDesc->next_desc = cpu_to_le32(curr + sizeof(SRxDesc));
+ }
+ if (i > 0)
+ pDevice->aRD1Ring[i-1].next_desc = cpu_to_le32(pDevice->rd1_pool_dma);
+ pDevice->pCurrRD[1] = &(pDevice->aRD1Ring[0]);
+}
static void device_init_defrag_cb(PSDevice pDevice) {
- int i;
- PSDeFragControlBlock pDeF;
-
- /* Init the fragment ctl entries */
- for (i = 0; i < CB_MAX_RX_FRAG; i++) {
- pDeF = &(pDevice->sRxDFCB[i]);
- if (!device_alloc_frag_buf(pDevice, pDeF)) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc frag bufs\n",
- pDevice->dev->name);
- }
- }
- pDevice->cbDFCB = CB_MAX_RX_FRAG;
- pDevice->cbFreeDFCB = pDevice->cbDFCB;
+ int i;
+ PSDeFragControlBlock pDeF;
+
+ /* Init the fragment ctl entries */
+ for (i = 0; i < CB_MAX_RX_FRAG; i++) {
+ pDeF = &(pDevice->sRxDFCB[i]);
+ if (!device_alloc_frag_buf(pDevice, pDeF)) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ pDevice->cbDFCB = CB_MAX_RX_FRAG;
+ pDevice->cbFreeDFCB = pDevice->cbDFCB;
}
-
-
-
static void device_free_rd0_ring(PSDevice pDevice) {
- int i;
-
- for (i = 0; i < pDevice->sOpts.nRxDescs0; i++) {
- PSRxDesc pDesc =&(pDevice->aRD0Ring[i]);
- PDEVICE_RD_INFO pRDInfo =pDesc->pRDInfo;
+ int i;
- pci_unmap_single(pDevice->pcid,pRDInfo->skb_dma,
- pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ for (i = 0; i < pDevice->sOpts.nRxDescs0; i++) {
+ PSRxDesc pDesc = &(pDevice->aRD0Ring[i]);
+ PDEVICE_RD_INFO pRDInfo = pDesc->pRDInfo;
- dev_kfree_skb(pRDInfo->skb);
+ pci_unmap_single(pDevice->pcid, pRDInfo->skb_dma,
+ pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
- kfree((void *)pDesc->pRDInfo);
- }
+ dev_kfree_skb(pRDInfo->skb);
+ kfree((void *)pDesc->pRDInfo);
+ }
}
static void device_free_rd1_ring(PSDevice pDevice) {
- int i;
-
-
- for (i = 0; i < pDevice->sOpts.nRxDescs1; i++) {
- PSRxDesc pDesc=&(pDevice->aRD1Ring[i]);
- PDEVICE_RD_INFO pRDInfo=pDesc->pRDInfo;
+ int i;
- pci_unmap_single(pDevice->pcid,pRDInfo->skb_dma,
- pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ for (i = 0; i < pDevice->sOpts.nRxDescs1; i++) {
+ PSRxDesc pDesc = &(pDevice->aRD1Ring[i]);
+ PDEVICE_RD_INFO pRDInfo = pDesc->pRDInfo;
- dev_kfree_skb(pRDInfo->skb);
+ pci_unmap_single(pDevice->pcid, pRDInfo->skb_dma,
+ pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
- kfree((void *)pDesc->pRDInfo);
- }
+ dev_kfree_skb(pRDInfo->skb);
+ kfree((void *)pDesc->pRDInfo);
+ }
}
static void device_free_frag_buf(PSDevice pDevice) {
- PSDeFragControlBlock pDeF;
- int i;
-
- for (i = 0; i < CB_MAX_RX_FRAG; i++) {
-
- pDeF = &(pDevice->sRxDFCB[i]);
+ PSDeFragControlBlock pDeF;
+ int i;
- if (pDeF->skb)
- dev_kfree_skb(pDeF->skb);
+ for (i = 0; i < CB_MAX_RX_FRAG; i++) {
+ pDeF = &(pDevice->sRxDFCB[i]);
- }
+ if (pDeF->skb)
+ dev_kfree_skb(pDeF->skb);
+ }
}
static void device_init_td0_ring(PSDevice pDevice) {
- int i;
- dma_addr_t curr;
- PSTxDesc pDesc;
-
- curr = pDevice->td0_pool_dma;
- for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) {
- pDesc = &(pDevice->apTD0Rings[i]);
- pDesc->pTDInfo = alloc_td_info();
- ASSERT(pDesc->pTDInfo);
- if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
- pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ;
- pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ;
- }
- pDesc->next =&(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]);
- pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
- pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
- }
-
- if (i > 0)
- pDevice->apTD0Rings[i-1].next_desc = cpu_to_le32(pDevice->td0_pool_dma);
- pDevice->apTailTD[0] = pDevice->apCurrTD[0] =&(pDevice->apTD0Rings[0]);
+ int i;
+ dma_addr_t curr;
+ PSTxDesc pDesc;
+
+ curr = pDevice->td0_pool_dma;
+ for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++, curr += sizeof(STxDesc)) {
+ pDesc = &(pDevice->apTD0Rings[i]);
+ pDesc->pTDInfo = alloc_td_info();
+ ASSERT(pDesc->pTDInfo);
+ if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
+ pDesc->pTDInfo->buf = pDevice->tx0_bufs + (i)*PKT_BUF_SZ;
+ pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma0 + (i)*PKT_BUF_SZ;
+ }
+ pDesc->next = &(pDevice->apTD0Rings[(i+1) % pDevice->sOpts.nTxDescs[0]]);
+ pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
+ pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
+ }
+ if (i > 0)
+ pDevice->apTD0Rings[i-1].next_desc = cpu_to_le32(pDevice->td0_pool_dma);
+ pDevice->apTailTD[0] = pDevice->apCurrTD[0] = &(pDevice->apTD0Rings[0]);
}
static void device_init_td1_ring(PSDevice pDevice) {
- int i;
- dma_addr_t curr;
- PSTxDesc pDesc;
-
- /* Init the TD ring entries */
- curr=pDevice->td1_pool_dma;
- for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr+=sizeof(STxDesc)) {
- pDesc=&(pDevice->apTD1Rings[i]);
- pDesc->pTDInfo = alloc_td_info();
- ASSERT(pDesc->pTDInfo);
- if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
- pDesc->pTDInfo->buf=pDevice->tx1_bufs+(i)*PKT_BUF_SZ;
- pDesc->pTDInfo->buf_dma=pDevice->tx_bufs_dma1+(i)*PKT_BUF_SZ;
- }
- pDesc->next=&(pDevice->apTD1Rings[(i+1) % pDevice->sOpts.nTxDescs[1]]);
- pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
- pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
- }
-
- if (i > 0)
- pDevice->apTD1Rings[i-1].next_desc = cpu_to_le32(pDevice->td1_pool_dma);
- pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]);
-}
-
+ int i;
+ dma_addr_t curr;
+ PSTxDesc pDesc;
+
+ /* Init the TD ring entries */
+ curr = pDevice->td1_pool_dma;
+ for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++, curr += sizeof(STxDesc)) {
+ pDesc = &(pDevice->apTD1Rings[i]);
+ pDesc->pTDInfo = alloc_td_info();
+ ASSERT(pDesc->pTDInfo);
+ if (pDevice->flags & DEVICE_FLAGS_TX_ALIGN) {
+ pDesc->pTDInfo->buf = pDevice->tx1_bufs + (i) * PKT_BUF_SZ;
+ pDesc->pTDInfo->buf_dma = pDevice->tx_bufs_dma1 + (i) * PKT_BUF_SZ;
+ }
+ pDesc->next = &(pDevice->apTD1Rings[(i + 1) % pDevice->sOpts.nTxDescs[1]]);
+ pDesc->pTDInfo->curr_desc = cpu_to_le32(curr);
+ pDesc->next_desc = cpu_to_le32(curr+sizeof(STxDesc));
+ }
+ if (i > 0)
+ pDevice->apTD1Rings[i-1].next_desc = cpu_to_le32(pDevice->td1_pool_dma);
+ pDevice->apTailTD[1] = pDevice->apCurrTD[1] = &(pDevice->apTD1Rings[0]);
+}
static void device_free_td0_ring(PSDevice pDevice) {
- int i;
- for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++) {
- PSTxDesc pDesc=&(pDevice->apTD0Rings[i]);
- PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo;
+ int i;
+ for (i = 0; i < pDevice->sOpts.nTxDescs[0]; i++) {
+ PSTxDesc pDesc = &(pDevice->apTD0Rings[i]);
+ PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo;
- if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
- pci_unmap_single(pDevice->pcid,pTDInfo->skb_dma,
- pTDInfo->skb->len, PCI_DMA_TODEVICE);
+ if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
+ pci_unmap_single(pDevice->pcid, pTDInfo->skb_dma,
+ pTDInfo->skb->len, PCI_DMA_TODEVICE);
- if (pTDInfo->skb)
- dev_kfree_skb(pTDInfo->skb);
+ if (pTDInfo->skb)
+ dev_kfree_skb(pTDInfo->skb);
- kfree((void *)pDesc->pTDInfo);
- }
+ kfree((void *)pDesc->pTDInfo);
+ }
}
static void device_free_td1_ring(PSDevice pDevice) {
- int i;
-
- for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++) {
- PSTxDesc pDesc=&(pDevice->apTD1Rings[i]);
- PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo;
+ int i;
- if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
- pci_unmap_single(pDevice->pcid, pTDInfo->skb_dma,
- pTDInfo->skb->len, PCI_DMA_TODEVICE);
+ for (i = 0; i < pDevice->sOpts.nTxDescs[1]; i++) {
+ PSTxDesc pDesc = &(pDevice->apTD1Rings[i]);
+ PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo;
- if (pTDInfo->skb)
- dev_kfree_skb(pTDInfo->skb);
+ if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma))
+ pci_unmap_single(pDevice->pcid, pTDInfo->skb_dma,
+ pTDInfo->skb->len, PCI_DMA_TODEVICE);
- kfree((void *)pDesc->pTDInfo);
- }
+ if (pTDInfo->skb)
+ dev_kfree_skb(pTDInfo->skb);
+ kfree((void *)pDesc->pTDInfo);
+ }
}
-
-
/*-----------------------------------------------------------------*/
static int device_rx_srv(PSDevice pDevice, unsigned int uIdx) {
- PSRxDesc pRD;
- int works = 0;
-
+ PSRxDesc pRD;
+ int works = 0;
- for (pRD = pDevice->pCurrRD[uIdx];
- pRD->m_rd0RD0.f1Owner == OWNED_BY_HOST;
- pRD = pRD->next) {
+ for (pRD = pDevice->pCurrRD[uIdx];
+ pRD->m_rd0RD0.f1Owner == OWNED_BY_HOST;
+ pRD = pRD->next) {
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->pCurrRD = %x, works = %d\n", pRD, works);
- if (works++>15)
- break;
- if (device_receive_frame(pDevice, pRD)) {
- if (!device_alloc_rx_buf(pDevice,pRD)) {
- DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
- "%s: can not allocate rx buf\n", pDevice->dev->name);
- break;
- }
- }
- pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
- pDevice->dev->last_rx = jiffies;
- }
-
- pDevice->pCurrRD[uIdx]=pRD;
-
- return works;
-}
+ if (works++ > 15)
+ break;
+ if (device_receive_frame(pDevice, pRD)) {
+ if (!device_alloc_rx_buf(pDevice, pRD)) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s: can not allocate rx buf\n", pDevice->dev->name);
+ break;
+ }
+ }
+ pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
+ pDevice->dev->last_rx = jiffies;
+ }
+ pDevice->pCurrRD[uIdx] = pRD;
-static bool device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
+ return works;
+}
- PDEVICE_RD_INFO pRDInfo=pRD->pRDInfo;
+static bool device_alloc_rx_buf(PSDevice pDevice, PSRxDesc pRD) {
+ PDEVICE_RD_INFO pRDInfo = pRD->pRDInfo;
+
+ pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ if (pRDInfo->skb == NULL)
+ return false;
+ ASSERT(pRDInfo->skb);
+ pRDInfo->skb->dev = pDevice->dev;
+ pRDInfo->skb_dma = pci_map_single(pDevice->pcid, skb_tail_pointer(pRDInfo->skb),
+ pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ *((unsigned int *)&(pRD->m_rd0RD0)) = 0; /* FIX cast */
+
+ pRD->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz);
+ pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
+ pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz);
+ pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma);
+
+ return true;
+}
+bool device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) {
+ pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ if (pDeF->skb == NULL)
+ return false;
+ ASSERT(pDeF->skb);
+ pDeF->skb->dev = pDevice->dev;
- pRDInfo->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
-#ifdef PLICE_DEBUG
- //printk("device_alloc_rx_buf:skb is %x\n",pRDInfo->skb);
-#endif
- if (pRDInfo->skb==NULL)
- return false;
- ASSERT(pRDInfo->skb);
- pRDInfo->skb->dev = pDevice->dev;
- pRDInfo->skb_dma = pci_map_single(pDevice->pcid, skb_tail_pointer(pRDInfo->skb),
- pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
- *((unsigned int *) &(pRD->m_rd0RD0)) = 0; /* FIX cast */
-
- pRD->m_rd0RD0.wResCount = cpu_to_le16(pDevice->rx_buf_sz);
- pRD->m_rd0RD0.f1Owner = OWNED_BY_NIC;
- pRD->m_rd1RD1.wReqCount = cpu_to_le16(pDevice->rx_buf_sz);
- pRD->buff_addr = cpu_to_le32(pRDInfo->skb_dma);
-
- return true;
+ return true;
}
+static int device_tx_srv(PSDevice pDevice, unsigned int uIdx) {
+ PSTxDesc pTD;
+ bool bFull = false;
+ int works = 0;
+ unsigned char byTsr0;
+ unsigned char byTsr1;
+ unsigned int uFrameSize, uFIFOHeaderSize;
+ PSTxBufHead pTxBufHead;
+ struct net_device_stats *pStats = &pDevice->stats;
+ struct sk_buff *skb;
+ unsigned int uNodeIndex;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ for (pTD = pDevice->apTailTD[uIdx]; pDevice->iTDUsed[uIdx] > 0; pTD = pTD->next) {
+ if (pTD->m_td0TD0.f1Owner == OWNED_BY_NIC)
+ break;
+ if (works++ > 15)
+ break;
+
+ byTsr0 = pTD->m_td0TD0.byTSR0;
+ byTsr1 = pTD->m_td0TD0.byTSR1;
+
+ //Only the status of first TD in the chain is correct
+ if (pTD->m_td1TD1.byTCR & TCR_STP) {
+ if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) {
+ uFIFOHeaderSize = pTD->pTDInfo->dwHeaderLength;
+ uFrameSize = pTD->pTDInfo->dwReqCount - uFIFOHeaderSize;
+ pTxBufHead = (PSTxBufHead) (pTD->pTDInfo->buf);
+ // Update the statistics based on the Transmit status
+ // now, we DONT check TSR0_CDH
+
+ STAvUpdateTDStatCounter(&pDevice->scStatistic,
+ byTsr0, byTsr1,
+ (unsigned char *)(pTD->pTDInfo->buf + uFIFOHeaderSize),
+ uFrameSize, uIdx);
+
+ BSSvUpdateNodeTxCounter(pDevice,
+ byTsr0, byTsr1,
+ (unsigned char *)(pTD->pTDInfo->buf),
+ uFIFOHeaderSize
+ );
+
+ if (!(byTsr1 & TSR1_TERR)) {
+ if (byTsr0 != 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X].\n",
+ (int)uIdx, byTsr1, byTsr0);
+ }
+ if ((pTxBufHead->wFragCtl & FRAGCTL_ENDFRAG) != FRAGCTL_NONFRAG) {
+ pDevice->s802_11Counter.TransmittedFragmentCount++;
+ }
+ pStats->tx_packets++;
+ pStats->tx_bytes += pTD->pTDInfo->skb->len;
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Tx[%d] dropped & tsr1[%02X] tsr0[%02X].\n",
+ (int)uIdx, byTsr1, byTsr0);
+ pStats->tx_errors++;
+ pStats->tx_dropped++;
+ }
+ }
+ if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
+ if (pDevice->bEnableHostapd) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx call back netif.. \n");
+ skb = pTD->pTDInfo->skb;
+ skb->dev = pDevice->apdev;
+ skb_reset_mac_header(skb);
+ skb->pkt_type = PACKET_OTHERHOST;
+ //skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ }
+ }
-bool device_alloc_frag_buf(PSDevice pDevice, PSDeFragControlBlock pDeF) {
+ if (byTsr1 & TSR1_TERR) {
+ if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
+ (int)uIdx, byTsr1, byTsr0);
+ }
- pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- if (pDeF->skb == NULL)
- return false;
- ASSERT(pDeF->skb);
- pDeF->skb->dev = pDevice->dev;
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
+// (int)uIdx, byTsr1, byTsr0);
- return true;
-}
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) &&
+ (pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)) {
+ unsigned short wAID;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+
+ skb = pTD->pTDInfo->skb;
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
+ if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
+ skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
+ pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
+ // set tx map
+ wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID;
+ pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
+ pTD->pTDInfo->byFlags &= ~(TD_FLAGS_NETIF_SKB);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx_srv:tx fail re-queue sta index= %d, QueCnt= %d\n"
+ , (int)uNodeIndex, pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt);
+ pStats->tx_errors--;
+ pStats->tx_dropped--;
+ }
+ }
+ }
+ }
+ device_free_tx_buf(pDevice, pTD);
+ pDevice->iTDUsed[uIdx]--;
+ }
+ }
+ if (uIdx == TYPE_AC0DMA) {
+ // RESERV_AC0DMA reserved for relay
+ if (AVAIL_TD(pDevice, uIdx) < RESERV_AC0DMA) {
+ bFull = true;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " AC0DMA is Full = %d\n", pDevice->iTDUsed[uIdx]);
+ }
+ if (netif_queue_stopped(pDevice->dev) && (bFull == false)) {
+ netif_wake_queue(pDevice->dev);
+ }
+ }
-static int device_tx_srv(PSDevice pDevice, unsigned int uIdx) {
- PSTxDesc pTD;
- bool bFull=false;
- int works = 0;
- unsigned char byTsr0;
- unsigned char byTsr1;
- unsigned int uFrameSize, uFIFOHeaderSize;
- PSTxBufHead pTxBufHead;
- struct net_device_stats* pStats = &pDevice->stats;
- struct sk_buff* skb;
- unsigned int uNodeIndex;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- for (pTD = pDevice->apTailTD[uIdx]; pDevice->iTDUsed[uIdx] >0; pTD = pTD->next) {
-
- if (pTD->m_td0TD0.f1Owner == OWNED_BY_NIC)
- break;
- if (works++>15)
- break;
-
- byTsr0 = pTD->m_td0TD0.byTSR0;
- byTsr1 = pTD->m_td0TD0.byTSR1;
-
- //Only the status of first TD in the chain is correct
- if (pTD->m_td1TD1.byTCR & TCR_STP) {
-
- if ((pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0) {
- uFIFOHeaderSize = pTD->pTDInfo->dwHeaderLength;
- uFrameSize = pTD->pTDInfo->dwReqCount - uFIFOHeaderSize;
- pTxBufHead = (PSTxBufHead) (pTD->pTDInfo->buf);
- // Update the statistics based on the Transmit status
- // now, we DONT check TSR0_CDH
-
- STAvUpdateTDStatCounter(&pDevice->scStatistic,
- byTsr0, byTsr1,
- (unsigned char *)(pTD->pTDInfo->buf + uFIFOHeaderSize),
- uFrameSize, uIdx);
-
-
- BSSvUpdateNodeTxCounter(pDevice,
- byTsr0, byTsr1,
- (unsigned char *)(pTD->pTDInfo->buf),
- uFIFOHeaderSize
- );
-
- if ( !(byTsr1 & TSR1_TERR)) {
- if (byTsr0 != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] OK but has error. tsr1[%02X] tsr0[%02X].\n",
- (int)uIdx, byTsr1, byTsr0);
- }
- if ((pTxBufHead->wFragCtl & FRAGCTL_ENDFRAG) != FRAGCTL_NONFRAG) {
- pDevice->s802_11Counter.TransmittedFragmentCount ++;
- }
- pStats->tx_packets++;
- pStats->tx_bytes += pTD->pTDInfo->skb->len;
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] dropped & tsr1[%02X] tsr0[%02X].\n",
- (int)uIdx, byTsr1, byTsr0);
- pStats->tx_errors++;
- pStats->tx_dropped++;
- }
- }
-
- if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
- if (pDevice->bEnableHostapd) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx call back netif.. \n");
- skb = pTD->pTDInfo->skb;
- skb->dev = pDevice->apdev;
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- //skb->protocol = htons(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- }
- }
-
- if (byTsr1 & TSR1_TERR) {
- if ((pTD->pTDInfo->byFlags & TD_FLAGS_PRIV_SKB) != 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
- (int)uIdx, byTsr1, byTsr0);
- }
-
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Tx[%d] fail has error. tsr1[%02X] tsr0[%02X].\n",
-// (int)uIdx, byTsr1, byTsr0);
+ pDevice->apTailTD[uIdx] = pTD;
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) &&
- (pTD->pTDInfo->byFlags & TD_FLAGS_NETIF_SKB)) {
- unsigned short wAID;
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
-
- skb = pTD->pTDInfo->skb;
- if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
- if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
- skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
- pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
- // set tx map
- wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID;
- pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
- pTD->pTDInfo->byFlags &= ~(TD_FLAGS_NETIF_SKB);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "tx_srv:tx fail re-queue sta index= %d, QueCnt= %d\n"
- ,(int)uNodeIndex, pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt);
- pStats->tx_errors--;
- pStats->tx_dropped--;
- }
- }
- }
- }
- device_free_tx_buf(pDevice,pTD);
- pDevice->iTDUsed[uIdx]--;
- }
- }
-
-
- if (uIdx == TYPE_AC0DMA) {
- // RESERV_AC0DMA reserved for relay
-
- if (AVAIL_TD(pDevice, uIdx) < RESERV_AC0DMA) {
- bFull = true;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " AC0DMA is Full = %d\n", pDevice->iTDUsed[uIdx]);
- }
- if (netif_queue_stopped(pDevice->dev) && (bFull==false)){
- netif_wake_queue(pDevice->dev);
- }
- }
-
-
- pDevice->apTailTD[uIdx] = pTD;
-
- return works;
+ return works;
}
-
static void device_error(PSDevice pDevice, unsigned short status) {
-
- if (status & ISR_FETALERR) {
- DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
- "%s: Hardware fatal error.\n",
- pDevice->dev->name);
- netif_stop_queue(pDevice->dev);
- del_timer(&pDevice->sTimerCommand);
- del_timer(&(pDevice->pMgmt->sTimerSecondCallback));
- pDevice->bCmdRunning = false;
- MACbShutdown(pDevice->PortOffset);
- return;
- }
-
+ if (status & ISR_FETALERR) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR
+ "%s: Hardware fatal error.\n",
+ pDevice->dev->name);
+ netif_stop_queue(pDevice->dev);
+ del_timer(&pDevice->sTimerCommand);
+ del_timer(&(pDevice->pMgmt->sTimerSecondCallback));
+ pDevice->bCmdRunning = false;
+ MACbShutdown(pDevice->PortOffset);
+ return;
+ }
}
static void device_free_tx_buf(PSDevice pDevice, PSTxDesc pDesc) {
- PDEVICE_TD_INFO pTDInfo=pDesc->pTDInfo;
- struct sk_buff* skb=pTDInfo->skb;
+ PDEVICE_TD_INFO pTDInfo = pDesc->pTDInfo;
+ struct sk_buff *skb = pTDInfo->skb;
- // pre-allocated buf_dma can't be unmapped.
- if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) {
- pci_unmap_single(pDevice->pcid,pTDInfo->skb_dma,skb->len,
- PCI_DMA_TODEVICE);
- }
+ // pre-allocated buf_dma can't be unmapped.
+ if (pTDInfo->skb_dma && (pTDInfo->skb_dma != pTDInfo->buf_dma)) {
+ pci_unmap_single(pDevice->pcid, pTDInfo->skb_dma, skb->len,
+ PCI_DMA_TODEVICE);
+ }
- if ((pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0)
- dev_kfree_skb_irq(skb);
+ if ((pTDInfo->byFlags & TD_FLAGS_NETIF_SKB) != 0)
+ dev_kfree_skb_irq(skb);
- pTDInfo->skb_dma = 0;
- pTDInfo->skb = 0;
- pTDInfo->byFlags = 0;
+ pTDInfo->skb_dma = 0;
+ pTDInfo->skb = 0;
+ pTDInfo->byFlags = 0;
}
-
-
//PLICE_DEBUG ->
void InitRxManagementQueue(PSDevice pDevice)
{
@@ -1817,107 +1687,88 @@ void InitRxManagementQueue(PSDevice pDevice)
}
//PLICE_DEBUG<-
-
-
-
-
//PLICE_DEBUG ->
int MlmeThread(
- void * Context)
+ void *Context)
{
PSDevice pDevice = (PSDevice) Context;
PSRxMgmtPacket pRxMgmtPacket;
- // int i ;
+ // int i;
//complete(&pDevice->notify);
-//printk("Enter MngWorkItem,Queue packet num is %d\n",pDevice->rxManeQueue.packet_num);
- //printk("Enter MlmeThread,packet _num is %d\n",pDevice->rxManeQueue.packet_num);
//i = 0;
#if 1
- while (1)
- {
-
- //printk("DDDD\n");
- //down(&pDevice->mlme_semaphore);
- // pRxMgmtPacket = DeQueue(pDevice);
+ while (1) {
+ //down(&pDevice->mlme_semaphore);
+ // pRxMgmtPacket = DeQueue(pDevice);
#if 1
spin_lock_irq(&pDevice->lock);
- while(pDevice->rxManeQueue.packet_num != 0)
- {
- pRxMgmtPacket = DeQueue(pDevice);
- //pDevice;
- //DequeueManageObject(pDevice->FirstRecvMngList, pDevice->LastRecvMngList);
+ while (pDevice->rxManeQueue.packet_num != 0) {
+ pRxMgmtPacket = DeQueue(pDevice);
+ //pDevice;
+ //DequeueManageObject(pDevice->FirstRecvMngList, pDevice->LastRecvMngList);
vMgrRxManagePacket(pDevice, pDevice->pMgmt, pRxMgmtPacket);
- //printk("packet_num is %d\n",pDevice->rxManeQueue.packet_num);
-
- }
+ }
spin_unlock_irq(&pDevice->lock);
if (mlme_kill == 0)
- break;
+ break;
//udelay(200);
#endif
- //printk("Before schedule thread jiffies is %x\n",jiffies);
- schedule();
- //printk("after schedule thread jiffies is %x\n",jiffies);
- if (mlme_kill == 0)
- break;
- //printk("i is %d\n",i);
+ schedule();
+ if (mlme_kill == 0)
+ break;
}
#endif
return 0;
-
}
-
-
static int device_open(struct net_device *dev) {
- PSDevice pDevice=(PSDevice) netdev_priv(dev);
- int i;
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ int i;
#ifdef WPA_SM_Transtatus
- extern SWPAResult wpa_Result;
+ extern SWPAResult wpa_Result;
#endif
- pDevice->rx_buf_sz = PKT_BUF_SZ;
- if (!device_init_rings(pDevice)) {
- return -ENOMEM;
- }
+ pDevice->rx_buf_sz = PKT_BUF_SZ;
+ if (!device_init_rings(pDevice)) {
+ return -ENOMEM;
+ }
//2008-5-13 <add> by chester
- i=request_irq(pDevice->pcid->irq, &device_intr, IRQF_SHARED, dev->name, dev);
- if (i)
- return i;
- //printk("DEBUG1\n");
+ i = request_irq(pDevice->pcid->irq, &device_intr, IRQF_SHARED, dev->name, dev);
+ if (i)
+ return i;
+
#ifdef WPA_SM_Transtatus
- memset(wpa_Result.ifname,0,sizeof(wpa_Result.ifname));
- wpa_Result.proto = 0;
- wpa_Result.key_mgmt = 0;
- wpa_Result.eap_type = 0;
- wpa_Result.authenticated = false;
- pDevice->fWPA_Authened = false;
+ memset(wpa_Result.ifname, 0, sizeof(wpa_Result.ifname));
+ wpa_Result.proto = 0;
+ wpa_Result.key_mgmt = 0;
+ wpa_Result.eap_type = 0;
+ wpa_Result.authenticated = false;
+ pDevice->fWPA_Authened = false;
#endif
-DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device init rd0 ring\n");
-device_init_rd0_ring(pDevice);
- device_init_rd1_ring(pDevice);
- device_init_defrag_cb(pDevice);
- device_init_td0_ring(pDevice);
- device_init_td1_ring(pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device init rd0 ring\n");
+ device_init_rd0_ring(pDevice);
+ device_init_rd1_ring(pDevice);
+ device_init_defrag_cb(pDevice);
+ device_init_td0_ring(pDevice);
+ device_init_td1_ring(pDevice);
// VNTWIFIvSet11h(pDevice->pMgmt, pDevice->b11hEnable);
-
- if (pDevice->bDiversityRegCtlON) {
- device_init_diversity_timer(pDevice);
- }
- vMgrObjectInit(pDevice);
- vMgrTimerInit(pDevice);
+ if (pDevice->bDiversityRegCtlON) {
+ device_init_diversity_timer(pDevice);
+ }
+ vMgrObjectInit(pDevice);
+ vMgrTimerInit(pDevice);
//PLICE_DEBUG->
#ifdef TASK_LET
- tasklet_init (&pDevice->RxMngWorkItem,(void *)MngWorkItem,(unsigned long )pDevice);
+ tasklet_init(&pDevice->RxMngWorkItem, (void *)MngWorkItem, (unsigned long)pDevice);
#endif
#ifdef THREAD
InitRxManagementQueue(pDevice);
mlme_kill = 0;
- mlme_task = kthread_run(MlmeThread,(void *) pDevice, "MLME");
+ mlme_task = kthread_run(MlmeThread, (void *)pDevice, "MLME");
if (IS_ERR(mlme_task)) {
printk("thread create fail\n");
return -1;
@@ -1926,1025 +1777,965 @@ device_init_rd0_ring(pDevice);
mlme_kill = 1;
#endif
-
-
- //printk("thread id is %d\n",pDevice->MLMEThr_pid);
- //printk("Create thread time is %x\n",jiffies);
//wait_for_completion(&pDevice->notify);
-
-
-
- // if (( SROMbyReadEmbedded(pDevice->PortOffset, EEP_OFS_RADIOCTL)&0x06)==0x04)
- // return -ENOMEM;
-DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device_init_registers\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call device_init_registers\n");
device_init_registers(pDevice, DEVICE_INIT_COLD);
- MACvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr);
- memcpy(pDevice->pMgmt->abyMACAddr, pDevice->abyCurrentNetAddr, ETH_ALEN);
- device_set_multi(pDevice->dev);
+ MACvReadEtherAddress(pDevice->PortOffset, pDevice->abyCurrentNetAddr);
+ memcpy(pDevice->pMgmt->abyMACAddr, pDevice->abyCurrentNetAddr, ETH_ALEN);
+ device_set_multi(pDevice->dev);
- // Init for Key Management
- KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
- add_timer(&(pDevice->pMgmt->sTimerSecondCallback));
+ // Init for Key Management
+ KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
+ add_timer(&(pDevice->pMgmt->sTimerSecondCallback));
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
/*
- pDevice->bwextstep0 = false;
- pDevice->bwextstep1 = false;
- pDevice->bwextstep2 = false;
- pDevice->bwextstep3 = false;
- */
- pDevice->bwextcount=0;
- pDevice->bWPASuppWextEnabled = false;
+ pDevice->bwextstep0 = false;
+ pDevice->bwextstep1 = false;
+ pDevice->bwextstep2 = false;
+ pDevice->bwextstep3 = false;
+ */
+ pDevice->bwextcount = 0;
+ pDevice->bWPASuppWextEnabled = false;
#endif
- pDevice->byReAssocCount = 0;
- pDevice->bWPADEVUp = false;
- // Patch: if WEP key already set by iwconfig but device not yet open
- if ((pDevice->bEncryptionEnable == true) && (pDevice->bTransmitKey == true)) {
- KeybSetDefaultKey(&(pDevice->sKey),
- (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
- pDevice->uKeyLength,
- NULL,
- pDevice->abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID
- );
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- }
-
-//printk("DEBUG2\n");
-
-
-DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call MACvIntEnable\n");
+ pDevice->byReAssocCount = 0;
+ pDevice->bWPADEVUp = false;
+ // Patch: if WEP key already set by iwconfig but device not yet open
+ if ((pDevice->bEncryptionEnable == true) && (pDevice->bTransmitKey == true)) {
+ KeybSetDefaultKey(&(pDevice->sKey),
+ (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
+ pDevice->uKeyLength,
+ NULL,
+ pDevice->abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID
+ );
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "call MACvIntEnable\n");
MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
- if (pDevice->pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+ if (pDevice->pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+ } else {
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
}
- else {
- bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
- bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
- }
- pDevice->flags |=DEVICE_FLAGS_OPENED;
+ pDevice->flags |= DEVICE_FLAGS_OPENED;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_open success.. \n");
- return 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_open success.. \n");
+ return 0;
}
-
static int device_close(struct net_device *dev) {
- PSDevice pDevice=(PSDevice) netdev_priv(dev);
- PSMgmtObject pMgmt = pDevice->pMgmt;
- //PLICE_DEBUG->
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ //PLICE_DEBUG->
#ifdef THREAD
mlme_kill = 0;
#endif
//PLICE_DEBUG<-
//2007-1121-02<Add>by EinsnLiu
- if (pDevice->bLinkPass) {
- bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
- mdelay(30);
- }
+ if (pDevice->bLinkPass) {
+ bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
+ mdelay(30);
+ }
#ifdef TxInSleep
- del_timer(&pDevice->sTimerTxData);
+ del_timer(&pDevice->sTimerTxData);
#endif
- del_timer(&pDevice->sTimerCommand);
- del_timer(&pMgmt->sTimerSecondCallback);
- if (pDevice->bDiversityRegCtlON) {
- del_timer(&pDevice->TimerSQ3Tmax1);
- del_timer(&pDevice->TimerSQ3Tmax2);
- del_timer(&pDevice->TimerSQ3Tmax3);
- }
+ del_timer(&pDevice->sTimerCommand);
+ del_timer(&pMgmt->sTimerSecondCallback);
+ if (pDevice->bDiversityRegCtlON) {
+ del_timer(&pDevice->TimerSQ3Tmax1);
+ del_timer(&pDevice->TimerSQ3Tmax2);
+ del_timer(&pDevice->TimerSQ3Tmax3);
+ }
#ifdef TASK_LET
tasklet_kill(&pDevice->RxMngWorkItem);
#endif
- netif_stop_queue(dev);
- pDevice->bCmdRunning = false;
- MACbShutdown(pDevice->PortOffset);
- MACbSoftwareReset(pDevice->PortOffset);
- CARDbRadioPowerOff(pDevice);
-
- pDevice->bLinkPass = false;
- memset(pMgmt->abyCurrBSSID, 0, 6);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- device_free_td0_ring(pDevice);
- device_free_td1_ring(pDevice);
- device_free_rd0_ring(pDevice);
- device_free_rd1_ring(pDevice);
- device_free_frag_buf(pDevice);
- device_free_rings(pDevice);
- BSSvClearNodeDBTable(pDevice, 0);
- free_irq(dev->irq, dev);
- pDevice->flags &=(~DEVICE_FLAGS_OPENED);
+ netif_stop_queue(dev);
+ pDevice->bCmdRunning = false;
+ MACbShutdown(pDevice->PortOffset);
+ MACbSoftwareReset(pDevice->PortOffset);
+ CARDbRadioPowerOff(pDevice);
+
+ pDevice->bLinkPass = false;
+ memset(pMgmt->abyCurrBSSID, 0, 6);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ device_free_td0_ring(pDevice);
+ device_free_td1_ring(pDevice);
+ device_free_rd0_ring(pDevice);
+ device_free_rd1_ring(pDevice);
+ device_free_frag_buf(pDevice);
+ device_free_rings(pDevice);
+ BSSvClearNodeDBTable(pDevice, 0);
+ free_irq(dev->irq, dev);
+ pDevice->flags &= (~DEVICE_FLAGS_OPENED);
//2008-0714-01<Add>by chester
-device_release_WPADEV(pDevice);
+ device_release_WPADEV(pDevice);
//PLICE_DEBUG->
//tasklet_kill(&pDevice->RxMngWorkItem);
//PLICE_DEBUG<-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_close.. \n");
- return 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_close.. \n");
+ return 0;
}
+static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
+ PSDevice pDevice = netdev_priv(dev);
+ unsigned char *pbMPDU;
+ unsigned int cbMPDULen = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211\n");
+ spin_lock_irq(&pDevice->lock);
-static int device_dma0_tx_80211(struct sk_buff *skb, struct net_device *dev) {
- PSDevice pDevice=netdev_priv(dev);
- unsigned char *pbMPDU;
- unsigned int cbMPDULen = 0;
+ if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211, td0 <=0\n");
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+ if (pDevice->bStopTx0Pkt == true) {
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211\n");
- spin_lock_irq(&pDevice->lock);
+ cbMPDULen = skb->len;
+ pbMPDU = skb->data;
- if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_tx_80211, td0 <=0\n");
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
+ vDMA0_tx_80211(pDevice, skb, pbMPDU, cbMPDULen);
- if (pDevice->bStopTx0Pkt == true) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
+ spin_unlock_irq(&pDevice->lock);
- cbMPDULen = skb->len;
- pbMPDU = skb->data;
+ return 0;
+}
- vDMA0_tx_80211(pDevice, skb, pbMPDU, cbMPDULen);
+bool device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, unsigned int uNodeIndex) {
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSTxDesc pHeadTD, pLastTD;
+ unsigned int cbFrameBodySize;
+ unsigned int uMACfragNum;
+ unsigned char byPktType;
+ bool bNeedEncryption = false;
+ PSKeyItem pTransmitKey = NULL;
+ unsigned int cbHeaderSize;
+ unsigned int ii;
+ SKeyItem STempKey;
+// unsigned char byKeyIndex = 0;
- spin_unlock_irq(&pDevice->lock);
+ if (pDevice->bStopTx0Pkt == true) {
+ dev_kfree_skb_irq(skb);
+ return false;
+ }
- return 0;
+ if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
+ dev_kfree_skb_irq(skb);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, td0 <=0\n");
+ return false;
+ }
-}
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (pDevice->uAssocCount == 0) {
+ dev_kfree_skb_irq(skb);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, assocCount = 0\n");
+ return false;
+ }
+ }
+ pHeadTD = pDevice->apCurrTD[TYPE_TXDMA0];
+ pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
-bool device_dma0_xmit(PSDevice pDevice, struct sk_buff *skb, unsigned int uNodeIndex) {
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSTxDesc pHeadTD, pLastTD;
- unsigned int cbFrameBodySize;
- unsigned int uMACfragNum;
- unsigned char byPktType;
- bool bNeedEncryption = false;
- PSKeyItem pTransmitKey = NULL;
- unsigned int cbHeaderSize;
- unsigned int ii;
- SKeyItem STempKey;
-// unsigned char byKeyIndex = 0;
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
+ cbFrameBodySize = skb->len - ETH_HLEN;
+
+ // 802.1H
+ if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
+ cbFrameBodySize += 8;
+ }
+ uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
+
+ if (uMACfragNum > AVAIL_TD(pDevice, TYPE_TXDMA0)) {
+ dev_kfree_skb_irq(skb);
+ return false;
+ }
+ byPktType = (unsigned char)pDevice->byPacketType;
+
+ if (pDevice->bFixRate) {
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ if (pDevice->uConnectionRate >= RATE_11M) {
+ pDevice->wCurrentRate = RATE_11M;
+ } else {
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ } else {
+ if (pDevice->uConnectionRate >= RATE_54M)
+ pDevice->wCurrentRate = RATE_54M;
+ else
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ } else {
+ pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate;
+ }
+
+ //preamble type
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) {
+ pDevice->byPreambleType = pDevice->byShortPreamble;
+ } else {
+ pDevice->byPreambleType = PREAMBLE_LONG;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dma0: pDevice->wCurrentRate = %d \n", pDevice->wCurrentRate);
+
+ if (pDevice->wCurrentRate <= RATE_11M) {
+ byPktType = PK_TYPE_11B;
+ } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ byPktType = PK_TYPE_11A;
+ } else {
+ if (pDevice->bProtectMode == true) {
+ byPktType = PK_TYPE_11GB;
+ } else {
+ byPktType = PK_TYPE_11GA;
+ }
+ }
- if (pDevice->bStopTx0Pkt == true) {
- dev_kfree_skb_irq(skb);
- return false;
- }
-
- if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
- dev_kfree_skb_irq(skb);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, td0 <=0\n");
- return false;
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (pDevice->uAssocCount == 0) {
- dev_kfree_skb_irq(skb);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "device_dma0_xmit, assocCount = 0\n");
- return false;
- }
- }
-
- pHeadTD = pDevice->apCurrTD[TYPE_TXDMA0];
-
- pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
-
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
- cbFrameBodySize = skb->len - ETH_HLEN;
-
- // 802.1H
- if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
- cbFrameBodySize += 8;
- }
- uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
-
- if ( uMACfragNum > AVAIL_TD(pDevice, TYPE_TXDMA0)) {
- dev_kfree_skb_irq(skb);
- return false;
- }
- byPktType = (unsigned char)pDevice->byPacketType;
-
-
- if (pDevice->bFixRate) {
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- if (pDevice->uConnectionRate >= RATE_11M) {
- pDevice->wCurrentRate = RATE_11M;
- } else {
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
- } else {
- if (pDevice->uConnectionRate >= RATE_54M)
- pDevice->wCurrentRate = RATE_54M;
- else
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
- }
- else {
- pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate;
- }
-
- //preamble type
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) {
- pDevice->byPreambleType = pDevice->byShortPreamble;
- }
- else {
- pDevice->byPreambleType = PREAMBLE_LONG;
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dma0: pDevice->wCurrentRate = %d \n", pDevice->wCurrentRate);
-
-
- if (pDevice->wCurrentRate <= RATE_11M) {
- byPktType = PK_TYPE_11B;
- } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- byPktType = PK_TYPE_11A;
- } else {
- if (pDevice->bProtectMode == true) {
- byPktType = PK_TYPE_11GB;
- } else {
- byPktType = PK_TYPE_11GA;
- }
- }
-
- if (pDevice->bEncryptionEnable == true)
- bNeedEncryption = true;
-
- if (pDevice->bEnableHostWEP) {
- pTransmitKey = &STempKey;
- pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
- pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
- pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
- pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
- pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
- memcpy(pTransmitKey->abyKey,
- &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
- pTransmitKey->uKeyLength
- );
- }
- vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
- cbFrameBodySize, TYPE_TXDMA0, pHeadTD,
- &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
- &uMACfragNum,
- &cbHeaderSize
- );
-
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
- // Disable PS
- MACbPSWakeup(pDevice->PortOffset);
- }
-
- pDevice->bPWBitOn = false;
-
- pLastTD = pHeadTD;
- for (ii = 0; ii < uMACfragNum; ii++) {
- // Poll Transmit the adapter
- wmb();
- pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC;
- wmb();
- if (ii == (uMACfragNum - 1))
- pLastTD = pHeadTD;
- pHeadTD = pHeadTD->next;
- }
-
- // Save the information needed by the tx interrupt handler
- // to complete the Send request
- pLastTD->pTDInfo->skb = skb;
- pLastTD->pTDInfo->byFlags = 0;
- pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB;
-
- pDevice->apCurrTD[TYPE_TXDMA0] = pHeadTD;
-
- MACvTransmit0(pDevice->PortOffset);
-
-
- return true;
+ if (pDevice->bEncryptionEnable == true)
+ bNeedEncryption = true;
+
+ if (pDevice->bEnableHostWEP) {
+ pTransmitKey = &STempKey;
+ pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
+ pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
+ pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
+ pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
+ pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
+ memcpy(pTransmitKey->abyKey,
+ &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
+ pTransmitKey->uKeyLength
+ );
+ }
+ vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
+ cbFrameBodySize, TYPE_TXDMA0, pHeadTD,
+ &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
+ &uMACfragNum,
+ &cbHeaderSize
+ );
+
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
+ // Disable PS
+ MACbPSWakeup(pDevice->PortOffset);
+ }
+
+ pDevice->bPWBitOn = false;
+
+ pLastTD = pHeadTD;
+ for (ii = 0; ii < uMACfragNum; ii++) {
+ // Poll Transmit the adapter
+ wmb();
+ pHeadTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
+ wmb();
+ if (ii == (uMACfragNum - 1))
+ pLastTD = pHeadTD;
+ pHeadTD = pHeadTD->next;
+ }
+
+ // Save the information needed by the tx interrupt handler
+ // to complete the Send request
+ pLastTD->pTDInfo->skb = skb;
+ pLastTD->pTDInfo->byFlags = 0;
+ pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB;
+
+ pDevice->apCurrTD[TYPE_TXDMA0] = pHeadTD;
+
+ MACvTransmit0(pDevice->PortOffset);
+
+ return true;
}
//TYPE_AC0DMA data tx
static int device_xmit(struct sk_buff *skb, struct net_device *dev) {
- PSDevice pDevice=netdev_priv(dev);
-
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSTxDesc pHeadTD, pLastTD;
- unsigned int uNodeIndex = 0;
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- unsigned short wAID;
- unsigned int uMACfragNum = 1;
- unsigned int cbFrameBodySize;
- unsigned char byPktType;
- unsigned int cbHeaderSize;
- bool bNeedEncryption = false;
- PSKeyItem pTransmitKey = NULL;
- SKeyItem STempKey;
- unsigned int ii;
- bool bTKIP_UseGTK = false;
- bool bNeedDeAuth = false;
- unsigned char *pbyBSSID;
- bool bNodeExist = false;
-
-
-
- spin_lock_irq(&pDevice->lock);
- if (pDevice->bLinkPass == false) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
-
- if (pDevice->bStopDataPkt) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
-
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (pDevice->uAssocCount == 0) {
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
- if (is_multicast_ether_addr((unsigned char *)(skb->data))) {
- uNodeIndex = 0;
- bNodeExist = true;
- if (pMgmt->sNodeDBTable[0].bPSEnable) {
- skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skb);
- pMgmt->sNodeDBTable[0].wEnQueueCnt++;
- // set tx map
- pMgmt->abyPSTxMap[0] |= byMask[0];
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
-}else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
- if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
- skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
- pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
- // set tx map
- wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID;
- pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set:pMgmt->abyPSTxMap[%d]= %d\n",
- (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
-
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) {
- pDevice->byPreambleType = pDevice->byShortPreamble;
-
- }else {
- pDevice->byPreambleType = PREAMBLE_LONG;
- }
- bNodeExist = true;
-
- }
- }
-
- if (bNodeExist == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Unknown STA not found in node DB \n");
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
- }
-
- pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA];
-
- pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
-
-
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
- cbFrameBodySize = skb->len - ETH_HLEN;
- // 802.1H
- if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
- cbFrameBodySize += 8;
- }
-
-
- if (pDevice->bEncryptionEnable == true) {
- bNeedEncryption = true;
- // get Transmit key
- do {
- if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- pbyBSSID = pDevice->abyBSSID;
- // get pairwise key
- if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
- // get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
- bTKIP_UseGTK = true;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n");
- break;
- }
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get PTK.\n");
- break;
- }
- }else if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-
- pbyBSSID = pDevice->sTxEthHeader.abyDstAddr; //TO_DS = 0 and FROM_DS = 0 --> 802.11 MAC Address1
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS Serach Key: \n");
- for (ii = 0; ii< 6; ii++)
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"%x \n", *(pbyBSSID+ii));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"\n");
-
- // get pairwise key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == true)
- break;
- }
- // get group key
- pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
- pTransmitKey = NULL;
- if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
- }
- else
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"NOT IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
- } else {
- bTKIP_UseGTK = true;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n");
- }
- } while(false);
- }
-
- if (pDevice->bEnableHostWEP) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"acdma0: STA index %d\n", uNodeIndex);
- if (pDevice->bEncryptionEnable == true) {
- pTransmitKey = &STempKey;
- pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
- pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
- pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
- pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
- pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
- memcpy(pTransmitKey->abyKey,
- &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
- pTransmitKey->uKeyLength
- );
- }
- }
-
- uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
-
- if (uMACfragNum > AVAIL_TD(pDevice, TYPE_AC0DMA)) {
- DBG_PRT(MSG_LEVEL_ERR, KERN_DEBUG "uMACfragNum > AVAIL_TD(TYPE_AC0DMA) = %d\n", uMACfragNum);
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
-
- if (pTransmitKey != NULL) {
- if ((pTransmitKey->byCipherSuite == KEY_CTL_WEP) &&
- (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN)) {
- uMACfragNum = 1; //WEP256 doesn't support fragment
- }
- }
-
- byPktType = (unsigned char)pDevice->byPacketType;
-
- if (pDevice->bFixRate) {
+ PSDevice pDevice = netdev_priv(dev);
+
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSTxDesc pHeadTD, pLastTD;
+ unsigned int uNodeIndex = 0;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned short wAID;
+ unsigned int uMACfragNum = 1;
+ unsigned int cbFrameBodySize;
+ unsigned char byPktType;
+ unsigned int cbHeaderSize;
+ bool bNeedEncryption = false;
+ PSKeyItem pTransmitKey = NULL;
+ SKeyItem STempKey;
+ unsigned int ii;
+ bool bTKIP_UseGTK = false;
+ bool bNeedDeAuth = false;
+ unsigned char *pbyBSSID;
+ bool bNodeExist = false;
+
+ spin_lock_irq(&pDevice->lock);
+ if (pDevice->bLinkPass == false) {
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+
+ if (pDevice->bStopDataPkt) {
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (pDevice->uAssocCount == 0) {
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+ if (is_multicast_ether_addr((unsigned char *)(skb->data))) {
+ uNodeIndex = 0;
+ bNodeExist = true;
+ if (pMgmt->sNodeDBTable[0].bPSEnable) {
+ skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skb);
+ pMgmt->sNodeDBTable[0].wEnQueueCnt++;
+ // set tx map
+ pMgmt->abyPSTxMap[0] |= byMask[0];
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+ } else {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data), &uNodeIndex)) {
+ if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
+ skb_queue_tail(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue, skb);
+ pMgmt->sNodeDBTable[uNodeIndex].wEnQueueCnt++;
+ // set tx map
+ wAID = pMgmt->sNodeDBTable[uNodeIndex].wAID;
+ pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set:pMgmt->abyPSTxMap[%d]= %d\n",
+ (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) {
+ pDevice->byPreambleType = pDevice->byShortPreamble;
+
+ } else {
+ pDevice->byPreambleType = PREAMBLE_LONG;
+ }
+ bNodeExist = true;
+
+ }
+ }
+
+ if (bNodeExist == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "Unknown STA not found in node DB \n");
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+ }
+
+ pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA];
+
+ pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
+
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)(skb->data), ETH_HLEN);
+ cbFrameBodySize = skb->len - ETH_HLEN;
+ // 802.1H
+ if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
+ cbFrameBodySize += 8;
+ }
+
+ if (pDevice->bEncryptionEnable == true) {
+ bNeedEncryption = true;
+ // get Transmit key
+ do {
+ if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ pbyBSSID = pDevice->abyBSSID;
+ // get pairwise key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
+ // get group key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
+ bTKIP_UseGTK = true;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "Get GTK.\n");
+ break;
+ }
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "Get PTK.\n");
+ break;
+ }
+ } else if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ pbyBSSID = pDevice->sTxEthHeader.abyDstAddr; //TO_DS = 0 and FROM_DS = 0 --> 802.11 MAC Address1
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "IBSS Serach Key: \n");
+ for (ii = 0; ii < 6; ii++)
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "%x \n", *(pbyBSSID+ii));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "\n");
+
+ // get pairwise key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == true)
+ break;
+ }
+ // get group key
+ pbyBSSID = pDevice->abyBroadcastAddr;
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
+ pTransmitKey = NULL;
+ if (pDevice->pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
+ } else
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "NOT IBSS and KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
+ } else {
+ bTKIP_UseGTK = true;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "Get GTK.\n");
+ }
+ } while (false);
+ }
+
+ if (pDevice->bEnableHostWEP) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "acdma0: STA index %d\n", uNodeIndex);
+ if (pDevice->bEncryptionEnable == true) {
+ pTransmitKey = &STempKey;
+ pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
+ pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
+ pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
+ pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
+ pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
+ memcpy(pTransmitKey->abyKey,
+ &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
+ pTransmitKey->uKeyLength
+ );
+ }
+ }
+
+ uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
+
+ if (uMACfragNum > AVAIL_TD(pDevice, TYPE_AC0DMA)) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_DEBUG "uMACfragNum > AVAIL_TD(TYPE_AC0DMA) = %d\n", uMACfragNum);
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+
+ if (pTransmitKey != NULL) {
+ if ((pTransmitKey->byCipherSuite == KEY_CTL_WEP) &&
+ (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN)) {
+ uMACfragNum = 1; //WEP256 doesn't support fragment
+ }
+ }
+
+ byPktType = (unsigned char)pDevice->byPacketType;
+
+ if (pDevice->bFixRate) {
#ifdef PLICE_DEBUG
- printk("Fix Rate: PhyType is %d,ConnectionRate is %d\n",pDevice->eCurrentPHYType,pDevice->uConnectionRate);
+ printk("Fix Rate: PhyType is %d,ConnectionRate is %d\n", pDevice->eCurrentPHYType, pDevice->uConnectionRate);
#endif
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- if (pDevice->uConnectionRate >= RATE_11M) {
- pDevice->wCurrentRate = RATE_11M;
- } else {
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
- } else {
- if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
- (pDevice->uConnectionRate <= RATE_6M)) {
- pDevice->wCurrentRate = RATE_6M;
- } else {
- if (pDevice->uConnectionRate >= RATE_54M)
- pDevice->wCurrentRate = RATE_54M;
- else
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
-
- }
- }
- pDevice->byACKRate = (unsigned char) pDevice->wCurrentRate;
- pDevice->byTopCCKBasicRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_6M;
- }
- else {
- //auto rate
- if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) {
- if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
- pDevice->wCurrentRate = RATE_1M;
- pDevice->byACKRate = RATE_1M;
- pDevice->byTopCCKBasicRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_6M;
- } else {
- pDevice->wCurrentRate = RATE_6M;
- pDevice->byACKRate = RATE_6M;
- pDevice->byTopCCKBasicRate = RATE_1M;
- pDevice->byTopOFDMBasicRate = RATE_6M;
- }
- }
- else {
- VNTWIFIvGetTxRate( pDevice->pMgmt,
- pDevice->sTxEthHeader.abyDstAddr,
- &(pDevice->wCurrentRate),
- &(pDevice->byACKRate),
- &(pDevice->byTopCCKBasicRate),
- &(pDevice->byTopOFDMBasicRate));
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ if (pDevice->uConnectionRate >= RATE_11M) {
+ pDevice->wCurrentRate = RATE_11M;
+ } else {
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ } else {
+ if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
+ (pDevice->uConnectionRate <= RATE_6M)) {
+ pDevice->wCurrentRate = RATE_6M;
+ } else {
+ if (pDevice->uConnectionRate >= RATE_54M)
+ pDevice->wCurrentRate = RATE_54M;
+ else
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ }
+ pDevice->byACKRate = (unsigned char) pDevice->wCurrentRate;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_6M;
+ } else {
+ //auto rate
+ if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) {
+ if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
+ pDevice->wCurrentRate = RATE_1M;
+ pDevice->byACKRate = RATE_1M;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_6M;
+ } else {
+ pDevice->wCurrentRate = RATE_6M;
+ pDevice->byACKRate = RATE_6M;
+ pDevice->byTopCCKBasicRate = RATE_1M;
+ pDevice->byTopOFDMBasicRate = RATE_6M;
+ }
+ } else {
+ VNTWIFIvGetTxRate(pDevice->pMgmt,
+ pDevice->sTxEthHeader.abyDstAddr,
+ &(pDevice->wCurrentRate),
+ &(pDevice->byACKRate),
+ &(pDevice->byTopCCKBasicRate),
+ &(pDevice->byTopOFDMBasicRate));
}
- }
+ }
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "acdma0: pDevice->wCurrentRate = %d \n", pDevice->wCurrentRate);
- if (pDevice->wCurrentRate <= RATE_11M) {
- byPktType = PK_TYPE_11B;
- } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- byPktType = PK_TYPE_11A;
- } else {
- if (pDevice->bProtectMode == true) {
- byPktType = PK_TYPE_11GB;
- } else {
- byPktType = PK_TYPE_11GA;
- }
- }
+ if (pDevice->wCurrentRate <= RATE_11M) {
+ byPktType = PK_TYPE_11B;
+ } else if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ byPktType = PK_TYPE_11A;
+ } else {
+ if (pDevice->bProtectMode == true) {
+ byPktType = PK_TYPE_11GB;
+ } else {
+ byPktType = PK_TYPE_11GA;
+ }
+ }
//#ifdef PLICE_DEBUG
// printk("FIX RATE:CurrentRate is %d");
//#endif
- if (bNeedEncryption == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType));
- if ((pDevice->sTxEthHeader.wType) == TYPE_PKT_802_1x) {
- bNeedEncryption = false;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType));
- if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- if (pTransmitKey == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Don't Find TX KEY\n");
- }
- else {
- if (bTKIP_UseGTK == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"error: KEY is GTK!!~~\n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
- bNeedEncryption = true;
- }
- }
- }
-
- if (pDevice->byCntMeasure == 2) {
- bNeedDeAuth = true;
- pDevice->s802_11Counter.TKIPCounterMeasuresInvoked++;
- }
-
- if (pDevice->bEnableHostWEP) {
- if ((uNodeIndex != 0) &&
- (pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex & PAIRWISE_KEY)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
- bNeedEncryption = true;
- }
- }
- }
- else {
- if (pTransmitKey == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"return no tx key\n");
- dev_kfree_skb_irq(skb);
- spin_unlock_irq(&pDevice->lock);
- return 0;
- }
- }
- }
+ if (bNeedEncryption == true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType));
+ if ((pDevice->sTxEthHeader.wType) == TYPE_PKT_802_1x) {
+ bNeedEncryption = false;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType));
+ if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ if (pTransmitKey == NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Don't Find TX KEY\n");
+ } else {
+ if (bTKIP_UseGTK == true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "error: KEY is GTK!!~~\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
+ bNeedEncryption = true;
+ }
+ }
+ }
+
+ if (pDevice->byCntMeasure == 2) {
+ bNeedDeAuth = true;
+ pDevice->s802_11Counter.TKIPCounterMeasuresInvoked++;
+ }
+ if (pDevice->bEnableHostWEP) {
+ if ((uNodeIndex != 0) &&
+ (pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex & PAIRWISE_KEY)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Find PTK [%lX]\n", pTransmitKey->dwKeyIndex);
+ bNeedEncryption = true;
+ }
+ }
+ } else {
+ if (pTransmitKey == NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return no tx key\n");
+ dev_kfree_skb_irq(skb);
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
+ }
+ }
+ }
-#ifdef PLICE_DEBUG
- //if (skb->len == 98)
- //{
- // printk("ping:len is %d\n");
- //}
-#endif
- vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
- cbFrameBodySize, TYPE_AC0DMA, pHeadTD,
- &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
- &uMACfragNum,
- &cbHeaderSize
- );
-
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
- // Disable PS
- MACbPSWakeup(pDevice->PortOffset);
- }
- pDevice->bPWBitOn = false;
-
- pLastTD = pHeadTD;
- for (ii = 0; ii < uMACfragNum; ii++) {
- // Poll Transmit the adapter
- wmb();
- pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC;
- wmb();
- if (ii == uMACfragNum - 1)
- pLastTD = pHeadTD;
- pHeadTD = pHeadTD->next;
- }
-
- // Save the information needed by the tx interrupt handler
- // to complete the Send request
- pLastTD->pTDInfo->skb = skb;
- pLastTD->pTDInfo->byFlags = 0;
- pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB;
+ vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
+ cbFrameBodySize, TYPE_AC0DMA, pHeadTD,
+ &pDevice->sTxEthHeader, (unsigned char *)skb->data, pTransmitKey, uNodeIndex,
+ &uMACfragNum,
+ &cbHeaderSize
+ );
+
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
+ // Disable PS
+ MACbPSWakeup(pDevice->PortOffset);
+ }
+ pDevice->bPWBitOn = false;
+
+ pLastTD = pHeadTD;
+ for (ii = 0; ii < uMACfragNum; ii++) {
+ // Poll Transmit the adapter
+ wmb();
+ pHeadTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
+ wmb();
+ if (ii == uMACfragNum - 1)
+ pLastTD = pHeadTD;
+ pHeadTD = pHeadTD->next;
+ }
+
+ // Save the information needed by the tx interrupt handler
+ // to complete the Send request
+ pLastTD->pTDInfo->skb = skb;
+ pLastTD->pTDInfo->byFlags = 0;
+ pLastTD->pTDInfo->byFlags |= TD_FLAGS_NETIF_SKB;
#ifdef TxInSleep
- pDevice->nTxDataTimeCout=0; //2008-8-21 chester <add> for send null packet
- #endif
- if (AVAIL_TD(pDevice, TYPE_AC0DMA) <= 1) {
- netif_stop_queue(dev);
- }
+ pDevice->nTxDataTimeCout = 0; //2008-8-21 chester <add> for send null packet
+#endif
+ if (AVAIL_TD(pDevice, TYPE_AC0DMA) <= 1) {
+ netif_stop_queue(dev);
+ }
- pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD;
+ pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD;
//#ifdef PLICE_DEBUG
- if (pDevice->bFixRate)
- {
- printk("FixRate:Rate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr);
- }
- else
- {
- //printk("Auto Rate:Rate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr);
+ if (pDevice->bFixRate) {
+ printk("FixRate:Rate is %d,TxPower is %d\n", pDevice->wCurrentRate, pDevice->byCurPwr);
+ } else {
}
//#endif
-{
- unsigned char Protocol_Version; //802.1x Authentication
- unsigned char Packet_Type; //802.1x Authentication
- unsigned char Descriptor_type;
- unsigned short Key_info;
-bool bTxeapol_key = false;
- Protocol_Version = skb->data[ETH_HLEN];
- Packet_Type = skb->data[ETH_HLEN+1];
- Descriptor_type = skb->data[ETH_HLEN+1+1+2];
- Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]);
- if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) {
- if(((Protocol_Version==1) ||(Protocol_Version==2)) &&
- (Packet_Type==3)) { //802.1x OR eapol-key challenge frame transfer
- bTxeapol_key = true;
- if((Descriptor_type==254)||(Descriptor_type==2)) { //WPA or RSN
- if(!(Key_info & BIT3) && //group-key challenge
- (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key
- pDevice->fWPA_Authened = true;
- if(Descriptor_type==254)
- printk("WPA ");
- else
- printk("WPA2 ");
- printk("Authentication completed!!\n");
- }
- }
- }
- }
-}
+ {
+ unsigned char Protocol_Version; //802.1x Authentication
+ unsigned char Packet_Type; //802.1x Authentication
+ unsigned char Descriptor_type;
+ unsigned short Key_info;
+ bool bTxeapol_key = false;
+ Protocol_Version = skb->data[ETH_HLEN];
+ Packet_Type = skb->data[ETH_HLEN+1];
+ Descriptor_type = skb->data[ETH_HLEN+1+1+2];
+ Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]);
+ if (pDevice->sTxEthHeader.wType == TYPE_PKT_802_1x) {
+ if (((Protocol_Version == 1) || (Protocol_Version == 2)) &&
+ (Packet_Type == 3)) { //802.1x OR eapol-key challenge frame transfer
+ bTxeapol_key = true;
+ if ((Descriptor_type == 254) || (Descriptor_type == 2)) { //WPA or RSN
+ if (!(Key_info & BIT3) && //group-key challenge
+ (Key_info & BIT8) && (Key_info & BIT9)) { //send 2/2 key
+ pDevice->fWPA_Authened = true;
+ if (Descriptor_type == 254)
+ printk("WPA ");
+ else
+ printk("WPA2 ");
+ printk("Authentication completed!!\n");
+ }
+ }
+ }
+ }
+ }
- MACvTransmitAC0(pDevice->PortOffset);
+ MACvTransmitAC0(pDevice->PortOffset);
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "acdma0:pDevice->apCurrTD= %p\n", pHeadTD);
- dev->trans_start = jiffies;
-
- spin_unlock_irq(&pDevice->lock);
- return 0;
+ dev->trans_start = jiffies;
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
}
static irqreturn_t device_intr(int irq, void *dev_instance) {
- struct net_device* dev=dev_instance;
- PSDevice pDevice=(PSDevice) netdev_priv(dev);
-
- int max_count=0;
- unsigned long dwMIBCounter=0;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned char byOrgPageSel=0;
- int handled = 0;
- unsigned char byData = 0;
- int ii= 0;
+ struct net_device *dev = dev_instance;
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+
+ int max_count = 0;
+ unsigned long dwMIBCounter = 0;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned char byOrgPageSel = 0;
+ int handled = 0;
+ unsigned char byData = 0;
+ int ii = 0;
// unsigned char byRSSI;
+ MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
- MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
-
- if (pDevice->dwIsr == 0)
- return IRQ_RETVAL(handled);
-
- if (pDevice->dwIsr == 0xffffffff) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwIsr = 0xffff\n");
- return IRQ_RETVAL(handled);
- }
- /*
- // 2008-05-21 <mark> by Richardtai, we can't read RSSI here, because no packet bound with RSSI
-
- if ((pDevice->dwIsr & ISR_RXDMA0) &&
- (pDevice->byLocalID != REV_ID_VT3253_B0) &&
- (pDevice->bBSSIDFilter == true)) {
- // update RSSI
- //BBbReadEmbedded(pDevice->PortOffset, 0x3E, &byRSSI);
- //pDevice->uCurrRSSI = byRSSI;
- }
- */
-
- handled = 1;
- MACvIntDisable(pDevice->PortOffset);
- spin_lock_irq(&pDevice->lock);
-
- //Make sure current page is 0
- VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel);
- if (byOrgPageSel == 1) {
- MACvSelectPage0(pDevice->PortOffset);
- }
- else
- byOrgPageSel = 0;
-
- MACvReadMIBCounter(pDevice->PortOffset, &dwMIBCounter);
- // TBD....
- // Must do this after doing rx/tx, cause ISR bit is slow
- // than RD/TD write back
- // update ISR counter
- STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic , dwMIBCounter);
- while (pDevice->dwIsr != 0) {
-
- STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr);
- MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr);
-
- if (pDevice->dwIsr & ISR_FETALERR){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " ISR_FETALERR \n");
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, 0);
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI);
- device_error(pDevice, pDevice->dwIsr);
- }
-
- if (pDevice->byLocalID > REV_ID_VT3253_B1) {
-
- if (pDevice->dwIsr & ISR_MEASURESTART) {
- // 802.11h measure start
- pDevice->byOrgChannel = pDevice->byCurrentCh;
- VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byOrgRCR));
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, (RCR_RXALLTYPE | RCR_UNICAST | RCR_BROADCAST | RCR_MULTICAST | RCR_WPAERR));
- MACvSelectPage1(pDevice->PortOffset);
- VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR0, &(pDevice->dwOrgMAR0));
- VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR4, &(pDevice->dwOrgMAR4));
- MACvSelectPage0(pDevice->PortOffset);
- //xxxx
- // WCMDbFlushCommandQueue(pDevice->pMgmt, true);
- if (set_channel(pDevice, pDevice->pCurrMeasureEID->sReq.byChannel) == true) {
- pDevice->bMeasureInProgress = true;
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_READY);
- MACvSelectPage0(pDevice->PortOffset);
- pDevice->byBasicMap = 0;
- pDevice->byCCAFraction = 0;
- for(ii=0;ii<8;ii++) {
- pDevice->dwRPIs[ii] = 0;
- }
- } else {
- // can not measure because set channel fail
- // WCMDbResetCommandQueue(pDevice->pMgmt);
- // clear measure control
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
- s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_INCAPABLE);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- }
- }
- if (pDevice->dwIsr & ISR_MEASUREEND) {
- // 802.11h measure end
- pDevice->bMeasureInProgress = false;
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4);
- VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRBBSTS, &byData);
- pDevice->byBasicMap |= (byData >> 4);
- VNSvInPortB(pDevice->PortOffset + MAC_REG_CCAFRACTION, &pDevice->byCCAFraction);
- VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRCTL, &byData);
- // clear measure control
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
- MACvSelectPage0(pDevice->PortOffset);
- set_channel(pDevice, pDevice->byOrgChannel);
- // WCMDbResetCommandQueue(pDevice->pMgmt);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- if (byData & MSRCTL_FINISH) {
- // measure success
- s_vCompleteCurrentMeasure(pDevice, 0);
- } else {
- // can not measure because not ready before end of measure time
- s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_LATE);
- }
- }
- if (pDevice->dwIsr & ISR_QUIETSTART) {
- do {
- ;
- } while (CARDbStartQuiet(pDevice) == false);
- }
- }
-
- if (pDevice->dwIsr & ISR_TBTT) {
- if (pDevice->bEnableFirstQuiet == true) {
- pDevice->byQuietStartCount--;
- if (pDevice->byQuietStartCount == 0) {
- pDevice->bEnableFirstQuiet = false;
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
- MACvSelectPage0(pDevice->PortOffset);
- }
- }
- if ((pDevice->bChannelSwitch == true) &&
- (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)) {
- pDevice->byChannelSwitchCount--;
- if (pDevice->byChannelSwitchCount == 0) {
- pDevice->bChannelSwitch = false;
- set_channel(pDevice, pDevice->byNewChannel);
- VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL);
-
- }
- }
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
- //pDevice->bBeaconSent = false;
- } else {
- if ((pDevice->bUpdateBBVGA) && (pDevice->bLinkPass == true) && (pDevice->uCurrRSSI != 0)) {
- long ldBm;
-
- RFvRSSITodBm(pDevice, (unsigned char) pDevice->uCurrRSSI, &ldBm);
- for (ii=0;ii<BB_VGA_LEVEL;ii++) {
- if (ldBm < pDevice->ldBmThreshold[ii]) {
- pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
- break;
- }
- }
- if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
- pDevice->uBBVGADiffCount++;
- if (pDevice->uBBVGADiffCount == 1) {
- // first VGA diff gain
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
- (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount);
- }
- if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
- (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount);
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
- }
- } else {
- pDevice->uBBVGADiffCount = 1;
- }
- }
- }
-
- pDevice->bBeaconSent = false;
- if (pDevice->bEnablePSMode) {
- PSbIsNextTBTTWakeUp((void *)pDevice);
- }
-
- if ((pDevice->eOPMode == OP_MODE_AP) ||
- (pDevice->eOPMode == OP_MODE_ADHOC)) {
-
- MACvOneShotTimer1MicroSec(pDevice->PortOffset,
- (pMgmt->wIBSSBeaconPeriod - MAKE_BEACON_RESERVED) << 10);
- }
-
- if (pDevice->eOPMode == OP_MODE_ADHOC && pDevice->pMgmt->wCurrATIMWindow > 0) {
- // todo adhoc PS mode
- }
-
- }
-
- if (pDevice->dwIsr & ISR_BNTX) {
-
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
- pDevice->bIsBeaconBufReadySet = false;
- pDevice->cbBeaconBufReadySetCnt = 0;
- }
-
- if (pDevice->eOPMode == OP_MODE_AP) {
- if(pMgmt->byDTIMCount > 0) {
- pMgmt->byDTIMCount --;
- pMgmt->sNodeDBTable[0].bRxPSPoll = false;
- }
- else {
- if(pMgmt->byDTIMCount == 0) {
- // check if mutltcast tx bufferring
- pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
- pMgmt->sNodeDBTable[0].bRxPSPoll = true;
- bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
- }
- }
- }
- pDevice->bBeaconSent = true;
-
- if (pDevice->bChannelSwitch == true) {
- pDevice->byChannelSwitchCount--;
- if (pDevice->byChannelSwitchCount == 0) {
- pDevice->bChannelSwitch = false;
- set_channel(pDevice, pDevice->byNewChannel);
- VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
- MACvSelectPage1(pDevice->PortOffset);
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
- MACvSelectPage0(pDevice->PortOffset);
- //VNTWIFIbSendBeacon(pDevice->pMgmt);
- CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL);
- }
- }
-
- }
-
- if (pDevice->dwIsr & ISR_RXDMA0) {
- max_count += device_rx_srv(pDevice, TYPE_RXDMA0);
- }
- if (pDevice->dwIsr & ISR_RXDMA1) {
- max_count += device_rx_srv(pDevice, TYPE_RXDMA1);
- }
- if (pDevice->dwIsr & ISR_TXDMA0){
- max_count += device_tx_srv(pDevice, TYPE_TXDMA0);
- }
- if (pDevice->dwIsr & ISR_AC0DMA){
- max_count += device_tx_srv(pDevice, TYPE_AC0DMA);
- }
- if (pDevice->dwIsr & ISR_SOFTTIMER) {
-
- }
- if (pDevice->dwIsr & ISR_SOFTTIMER1) {
- if (pDevice->eOPMode == OP_MODE_AP) {
- if (pDevice->bShortSlotTime)
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
- else
- pMgmt->wCurrCapInfo &= ~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1));
- }
- bMgrPrepareBeaconToSend(pDevice, pMgmt);
- pDevice->byCntMeasure = 0;
- }
-
- MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
-
- MACvReceive0(pDevice->PortOffset);
- MACvReceive1(pDevice->PortOffset);
-
- if (max_count>pDevice->sOpts.int_works)
- break;
- }
-
- if (byOrgPageSel == 1) {
- MACvSelectPage1(pDevice->PortOffset);
- }
-
- spin_unlock_irq(&pDevice->lock);
- MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
-
- return IRQ_RETVAL(handled);
-}
+ if (pDevice->dwIsr == 0)
+ return IRQ_RETVAL(handled);
+
+ if (pDevice->dwIsr == 0xffffffff) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwIsr = 0xffff\n");
+ return IRQ_RETVAL(handled);
+ }
+ /*
+ // 2008-05-21 <mark> by Richardtai, we can't read RSSI here, because no packet bound with RSSI
+
+ if ((pDevice->dwIsr & ISR_RXDMA0) &&
+ (pDevice->byLocalID != REV_ID_VT3253_B0) &&
+ (pDevice->bBSSIDFilter == true)) {
+ // update RSSI
+ //BBbReadEmbedded(pDevice->PortOffset, 0x3E, &byRSSI);
+ //pDevice->uCurrRSSI = byRSSI;
+ }
+ */
+
+ handled = 1;
+ MACvIntDisable(pDevice->PortOffset);
+ spin_lock_irq(&pDevice->lock);
+
+ //Make sure current page is 0
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_PAGE1SEL, &byOrgPageSel);
+ if (byOrgPageSel == 1) {
+ MACvSelectPage0(pDevice->PortOffset);
+ } else
+ byOrgPageSel = 0;
+
+ MACvReadMIBCounter(pDevice->PortOffset, &dwMIBCounter);
+ // TBD....
+ // Must do this after doing rx/tx, cause ISR bit is slow
+ // than RD/TD write back
+ // update ISR counter
+ STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic , dwMIBCounter);
+ while (pDevice->dwIsr != 0) {
+ STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr);
+ MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr);
+
+ if (pDevice->dwIsr & ISR_FETALERR) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " ISR_FETALERR \n");
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, 0);
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI);
+ device_error(pDevice, pDevice->dwIsr);
+ }
+
+ if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+ if (pDevice->dwIsr & ISR_MEASURESTART) {
+ // 802.11h measure start
+ pDevice->byOrgChannel = pDevice->byCurrentCh;
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byOrgRCR));
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, (RCR_RXALLTYPE | RCR_UNICAST | RCR_BROADCAST | RCR_MULTICAST | RCR_WPAERR));
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR0, &(pDevice->dwOrgMAR0));
+ VNSvInPortD(pDevice->PortOffset + MAC_REG_MAR4, &(pDevice->dwOrgMAR4));
+ MACvSelectPage0(pDevice->PortOffset);
+ //xxxx
+ // WCMDbFlushCommandQueue(pDevice->pMgmt, true);
+ if (set_channel(pDevice, pDevice->pCurrMeasureEID->sReq.byChannel) == true) {
+ pDevice->bMeasureInProgress = true;
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_READY);
+ MACvSelectPage0(pDevice->PortOffset);
+ pDevice->byBasicMap = 0;
+ pDevice->byCCAFraction = 0;
+ for (ii = 0; ii < 8; ii++) {
+ pDevice->dwRPIs[ii] = 0;
+ }
+ } else {
+ // can not measure because set channel fail
+ // WCMDbResetCommandQueue(pDevice->pMgmt);
+ // clear measure control
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
+ s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_INCAPABLE);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ }
+ }
+ if (pDevice->dwIsr & ISR_MEASUREEND) {
+ // 802.11h measure end
+ pDevice->bMeasureInProgress = false;
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byOrgRCR);
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, pDevice->dwOrgMAR0);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR4, pDevice->dwOrgMAR4);
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRBBSTS, &byData);
+ pDevice->byBasicMap |= (byData >> 4);
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_CCAFRACTION, &pDevice->byCCAFraction);
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_MSRCTL, &byData);
+ // clear measure control
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_MSRCTL, MSRCTL_EN);
+ MACvSelectPage0(pDevice->PortOffset);
+ set_channel(pDevice, pDevice->byOrgChannel);
+ // WCMDbResetCommandQueue(pDevice->pMgmt);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ if (byData & MSRCTL_FINISH) {
+ // measure success
+ s_vCompleteCurrentMeasure(pDevice, 0);
+ } else {
+ // can not measure because not ready before end of measure time
+ s_vCompleteCurrentMeasure(pDevice, MEASURE_MODE_LATE);
+ }
+ }
+ if (pDevice->dwIsr & ISR_QUIETSTART) {
+ do {
+ ;
+ } while (CARDbStartQuiet(pDevice) == false);
+ }
+ }
+
+ if (pDevice->dwIsr & ISR_TBTT) {
+ if (pDevice->bEnableFirstQuiet == true) {
+ pDevice->byQuietStartCount--;
+ if (pDevice->byQuietStartCount == 0) {
+ pDevice->bEnableFirstQuiet = false;
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL, (MSRCTL_QUIETTXCHK | MSRCTL_QUIETEN));
+ MACvSelectPage0(pDevice->PortOffset);
+ }
+ }
+ if ((pDevice->bChannelSwitch == true) &&
+ (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)) {
+ pDevice->byChannelSwitchCount--;
+ if (pDevice->byChannelSwitchCount == 0) {
+ pDevice->bChannelSwitch = false;
+ set_channel(pDevice, pDevice->byNewChannel);
+ VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL);
+
+ }
+ }
+ if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ //pDevice->bBeaconSent = false;
+ } else {
+ if ((pDevice->bUpdateBBVGA) && (pDevice->bLinkPass == true) && (pDevice->uCurrRSSI != 0)) {
+ long ldBm;
+
+ RFvRSSITodBm(pDevice, (unsigned char) pDevice->uCurrRSSI, &ldBm);
+ for (ii = 0; ii < BB_VGA_LEVEL; ii++) {
+ if (ldBm < pDevice->ldBmThreshold[ii]) {
+ pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
+ break;
+ }
+ }
+ if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
+ pDevice->uBBVGADiffCount++;
+ if (pDevice->uBBVGADiffCount == 1) {
+ // first VGA diff gain
+ BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+ (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount);
+ }
+ if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+ (int)ldBm, pDevice->byBBVGANew, pDevice->byBBVGACurrent, (int)pDevice->uBBVGADiffCount);
+ BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
+ }
+ } else {
+ pDevice->uBBVGADiffCount = 1;
+ }
+ }
+ }
+
+ pDevice->bBeaconSent = false;
+ if (pDevice->bEnablePSMode) {
+ PSbIsNextTBTTWakeUp((void *)pDevice);
+ }
+
+ if ((pDevice->eOPMode == OP_MODE_AP) ||
+ (pDevice->eOPMode == OP_MODE_ADHOC)) {
+ MACvOneShotTimer1MicroSec(pDevice->PortOffset,
+ (pMgmt->wIBSSBeaconPeriod - MAKE_BEACON_RESERVED) << 10);
+ }
+
+ if (pDevice->eOPMode == OP_MODE_ADHOC && pDevice->pMgmt->wCurrATIMWindow > 0) {
+ // todo adhoc PS mode
+ }
+
+ }
+
+ if (pDevice->dwIsr & ISR_BNTX) {
+ if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ pDevice->bIsBeaconBufReadySet = false;
+ pDevice->cbBeaconBufReadySetCnt = 0;
+ }
+
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ if (pMgmt->byDTIMCount > 0) {
+ pMgmt->byDTIMCount--;
+ pMgmt->sNodeDBTable[0].bRxPSPoll = false;
+ } else {
+ if (pMgmt->byDTIMCount == 0) {
+ // check if mutltcast tx bufferring
+ pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
+ pMgmt->sNodeDBTable[0].bRxPSPoll = true;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
+ }
+ }
+ }
+ pDevice->bBeaconSent = true;
+
+ if (pDevice->bChannelSwitch == true) {
+ pDevice->byChannelSwitchCount--;
+ if (pDevice->byChannelSwitchCount == 0) {
+ pDevice->bChannelSwitch = false;
+ set_channel(pDevice, pDevice->byNewChannel);
+ VNTWIFIbChannelSwitch(pDevice->pMgmt, pDevice->byNewChannel);
+ MACvSelectPage1(pDevice->PortOffset);
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MSRCTL+1, MSRCTL1_TXPAUSE);
+ MACvSelectPage0(pDevice->PortOffset);
+ //VNTWIFIbSendBeacon(pDevice->pMgmt);
+ CARDbStartTxPacket(pDevice, PKT_TYPE_802_11_ALL);
+ }
+ }
+
+ }
+ if (pDevice->dwIsr & ISR_RXDMA0) {
+ max_count += device_rx_srv(pDevice, TYPE_RXDMA0);
+ }
+ if (pDevice->dwIsr & ISR_RXDMA1) {
+ max_count += device_rx_srv(pDevice, TYPE_RXDMA1);
+ }
+ if (pDevice->dwIsr & ISR_TXDMA0) {
+ max_count += device_tx_srv(pDevice, TYPE_TXDMA0);
+ }
+ if (pDevice->dwIsr & ISR_AC0DMA) {
+ max_count += device_tx_srv(pDevice, TYPE_AC0DMA);
+ }
+ if (pDevice->dwIsr & ISR_SOFTTIMER) {
+ }
+ if (pDevice->dwIsr & ISR_SOFTTIMER1) {
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ if (pDevice->bShortSlotTime)
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
+ else
+ pMgmt->wCurrCapInfo &= ~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1));
+ }
+ bMgrPrepareBeaconToSend(pDevice, pMgmt);
+ pDevice->byCntMeasure = 0;
+ }
+
+ MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
+
+ MACvReceive0(pDevice->PortOffset);
+ MACvReceive1(pDevice->PortOffset);
+
+ if (max_count > pDevice->sOpts.int_works)
+ break;
+ }
+
+ if (byOrgPageSel == 1) {
+ MACvSelectPage1(pDevice->PortOffset);
+ }
+
+ spin_unlock_irq(&pDevice->lock);
+ MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
+
+ return IRQ_RETVAL(handled);
+}
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc(int length, unsigned char *data)
{
- int crc = -1;
-
- while(--length >= 0) {
- unsigned char current_octet = *data++;
- int bit;
- for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
- crc = (crc << 1) ^
- ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
- }
- }
- return crc;
+ int crc = -1;
+
+ while (--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+ crc = (crc << 1) ^
+ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+ }
+ }
+ return crc;
}
//2008-8-4 <add> by chester
static int Config_FileGetParameter(unsigned char *string,
- unsigned char *dest, unsigned char *source)
+ unsigned char *dest, unsigned char *source)
{
- unsigned char buf1[100];
- int source_len = strlen(source);
+ unsigned char buf1[100];
+ int source_len = strlen(source);
- memset(buf1,0,100);
- strcat(buf1, string);
- strcat(buf1, "=");
- source+=strlen(buf1);
+ memset(buf1, 0, 100);
+ strcat(buf1, string);
+ strcat(buf1, "=");
+ source += strlen(buf1);
- memcpy(dest,source,source_len-strlen(buf1));
- return true;
+ memcpy(dest, source, source_len - strlen(buf1));
+ return true;
}
int Config_FileOperation(PSDevice pDevice,bool fwrite,unsigned char *Parameter)
@@ -2994,80 +2785,70 @@ error1:
return result;
}
+static void device_set_multi(struct net_device *dev) {
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ u32 mc_filter[2];
+ struct netdev_hw_addr *ha;
+
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ DBG_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+ /* Unconditionally log net taps. */
+ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
+ } else if ((netdev_mc_count(dev) > pDevice->multicast_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, 0xffffffff);
+ MACvSelectPage0(pDevice->PortOffset);
+ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ } else {
+ memset(mc_filter, 0, sizeof(mc_filter));
+ netdev_for_each_mc_addr(ha, dev) {
+ int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
+ }
+ MACvSelectPage1(pDevice->PortOffset);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, mc_filter[0]);
+ VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, mc_filter[1]);
+ MACvSelectPage0(pDevice->PortOffset);
+ pDevice->byRxMode &= ~(RCR_UNICAST);
+ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ }
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ // If AP mode, don't enable RCR_UNICAST. Since hw only compare addr1 with local mac.
+ pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
+ pDevice->byRxMode &= ~(RCR_UNICAST);
+ }
-static void device_set_multi(struct net_device *dev) {
- PSDevice pDevice = (PSDevice) netdev_priv(dev);
-
- PSMgmtObject pMgmt = pDevice->pMgmt;
- u32 mc_filter[2];
- struct netdev_hw_addr *ha;
-
-
- VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
-
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- DBG_PRT(MSG_LEVEL_ERR,KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
- /* Unconditionally log net taps. */
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST|RCR_UNICAST);
- }
- else if ((netdev_mc_count(dev) > pDevice->multicast_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, 0xffffffff);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, 0xffffffff);
- MACvSelectPage0(pDevice->PortOffset);
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- }
- else {
- memset(mc_filter, 0, sizeof(mc_filter));
- netdev_for_each_mc_addr(ha, dev) {
- int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
- mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
- }
- MACvSelectPage1(pDevice->PortOffset);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0, mc_filter[0]);
- VNSvOutPortD(pDevice->PortOffset + MAC_REG_MAR0 + 4, mc_filter[1]);
- MACvSelectPage0(pDevice->PortOffset);
- pDevice->byRxMode &= ~(RCR_UNICAST);
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- }
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- // If AP mode, don't enable RCR_UNICAST. Since hw only compare addr1 with local mac.
- pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
- pDevice->byRxMode &= ~(RCR_UNICAST);
- }
-
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byRxMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRxMode = %x\n", pDevice->byRxMode );
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_RCR, pDevice->byRxMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->byRxMode = %x\n", pDevice->byRxMode);
}
-
static struct net_device_stats *device_get_stats(struct net_device *dev) {
- PSDevice pDevice=(PSDevice) netdev_priv(dev);
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
- return &pDevice->stats;
+ return &pDevice->stats;
}
-
-
static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- struct iwreq *wrq = (struct iwreq *) rq;
- int rc =0;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSCmdRequest pReq;
-
+ struct iwreq *wrq = (struct iwreq *)rq;
+ int rc = 0;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSCmdRequest pReq;
- if (pMgmt == NULL) {
- rc = -EFAULT;
- return rc;
- }
-
- switch(cmd) {
+ if (pMgmt == NULL) {
+ rc = -EFAULT;
+ return rc;
+ }
+ switch (cmd) {
case SIOCGIWNAME:
rc = iwctl_giwname(dev, NULL, (char *)&(wrq->u.name), NULL);
break;
@@ -3078,7 +2859,7 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
// Set frequency/channel
case SIOCSIWFREQ:
- rc = iwctl_siwfreq(dev, NULL, &(wrq->u.freq), NULL);
+ rc = iwctl_siwfreq(dev, NULL, &(wrq->u.freq), NULL);
break;
// Get frequency/channel
@@ -3089,60 +2870,57 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
// Set desired network name (ESSID)
case SIOCSIWESSID:
- {
- char essid[IW_ESSID_MAX_SIZE+1];
- if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
- rc = -E2BIG;
- break;
- }
- if (copy_from_user(essid, wrq->u.essid.pointer,
- wrq->u.essid.length)) {
- rc = -EFAULT;
- break;
- }
- rc = iwctl_siwessid(dev, NULL,
- &(wrq->u.essid), essid);
+ {
+ char essid[IW_ESSID_MAX_SIZE+1];
+ if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
+ rc = -E2BIG;
+ break;
}
- break;
-
+ if (copy_from_user(essid, wrq->u.essid.pointer,
+ wrq->u.essid.length)) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = iwctl_siwessid(dev, NULL,
+ &(wrq->u.essid), essid);
+ }
+ break;
- // Get current network name (ESSID)
+ // Get current network name (ESSID)
case SIOCGIWESSID:
- {
- char essid[IW_ESSID_MAX_SIZE+1];
- if (wrq->u.essid.pointer)
- rc = iwctl_giwessid(dev, NULL,
- &(wrq->u.essid), essid);
- if (copy_to_user(wrq->u.essid.pointer,
- essid,
- wrq->u.essid.length) )
- rc = -EFAULT;
- }
- break;
+ {
+ char essid[IW_ESSID_MAX_SIZE+1];
+ if (wrq->u.essid.pointer)
+ rc = iwctl_giwessid(dev, NULL,
+ &(wrq->u.essid), essid);
+ if (copy_to_user(wrq->u.essid.pointer,
+ essid,
+ wrq->u.essid.length))
+ rc = -EFAULT;
+ }
+ break;
case SIOCSIWAP:
rc = iwctl_siwap(dev, NULL, &(wrq->u.ap_addr), NULL);
break;
-
// Get current Access Point (BSSID)
case SIOCGIWAP:
rc = iwctl_giwap(dev, NULL, &(wrq->u.ap_addr), NULL);
break;
-
// Set desired station name
case SIOCSIWNICKN:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWNICKN \n");
- rc = -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWNICKN \n");
+ rc = -EOPNOTSUPP;
break;
// Get current station name
case SIOCGIWNICKN:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWNICKN \n");
- rc = -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWNICKN \n");
+ rc = -EOPNOTSUPP;
break;
// Set the desired bit-rate
@@ -3150,19 +2928,19 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
rc = iwctl_siwrate(dev, NULL, &(wrq->u.bitrate), NULL);
break;
- // Get the current bit-rate
+ // Get the current bit-rate
case SIOCGIWRATE:
rc = iwctl_giwrate(dev, NULL, &(wrq->u.bitrate), NULL);
break;
- // Set the desired RTS threshold
+ // Set the desired RTS threshold
case SIOCSIWRTS:
rc = iwctl_siwrts(dev, NULL, &(wrq->u.rts), NULL);
break;
- // Get the current RTS threshold
+ // Get the current RTS threshold
case SIOCGIWRTS:
rc = iwctl_giwrts(dev, NULL, &(wrq->u.rts), NULL);
@@ -3172,9 +2950,9 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
case SIOCSIWFRAG:
rc = iwctl_siwfrag(dev, NULL, &(wrq->u.frag), NULL);
- break;
+ break;
- // Get the current fragmentation threshold
+ // Get the current fragmentation threshold
case SIOCGIWFRAG:
rc = iwctl_giwfrag(dev, NULL, &(wrq->u.frag), NULL);
@@ -3182,7 +2960,7 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
// Set mode of operation
case SIOCSIWMODE:
- rc = iwctl_siwmode(dev, NULL, &(wrq->u.mode), NULL);
+ rc = iwctl_siwmode(dev, NULL, &(wrq->u.mode), NULL);
break;
// Get mode of operation
@@ -3191,33 +2969,30 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
break;
// Set WEP keys and mode
- case SIOCSIWENCODE:
- {
- char abyKey[WLAN_WEP232_KEYLEN];
-
- if (wrq->u.encoding.pointer) {
-
+ case SIOCSIWENCODE: {
+ char abyKey[WLAN_WEP232_KEYLEN];
- if (wrq->u.encoding.length > WLAN_WEP232_KEYLEN) {
- rc = -E2BIG;
- break;
- }
- memset(abyKey, 0, WLAN_WEP232_KEYLEN);
- if (copy_from_user(abyKey,
- wrq->u.encoding.pointer,
- wrq->u.encoding.length)) {
- rc = -EFAULT;
- break;
- }
- } else if (wrq->u.encoding.length != 0) {
- rc = -EINVAL;
+ if (wrq->u.encoding.pointer) {
+ if (wrq->u.encoding.length > WLAN_WEP232_KEYLEN) {
+ rc = -E2BIG;
break;
}
- rc = iwctl_siwencode(dev, NULL, &(wrq->u.encoding), abyKey);
+ memset(abyKey, 0, WLAN_WEP232_KEYLEN);
+ if (copy_from_user(abyKey,
+ wrq->u.encoding.pointer,
+ wrq->u.encoding.length)) {
+ rc = -EFAULT;
+ break;
+ }
+ } else if (wrq->u.encoding.length != 0) {
+ rc = -EINVAL;
+ break;
}
- break;
+ rc = iwctl_siwencode(dev, NULL, &(wrq->u.encoding), abyKey);
+ }
+ break;
- // Get the WEP keys and mode
+ // Get the WEP keys and mode
case SIOCGIWENCODE:
if (!capable(CAP_NET_ADMIN)) {
@@ -3225,14 +3000,14 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
break;
}
{
- char abyKey[WLAN_WEP232_KEYLEN];
+ char abyKey[WLAN_WEP232_KEYLEN];
- rc = iwctl_giwencode(dev, NULL, &(wrq->u.encoding), abyKey);
- if (rc != 0) break;
+ rc = iwctl_giwencode(dev, NULL, &(wrq->u.encoding), abyKey);
+ if (rc != 0) break;
if (wrq->u.encoding.pointer) {
if (copy_to_user(wrq->u.encoding.pointer,
- abyKey,
- wrq->u.encoding.length))
+ abyKey,
+ wrq->u.encoding.length))
rc = -EFAULT;
}
}
@@ -3240,13 +3015,13 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
// Get the current Tx-Power
case SIOCGIWTXPOW:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWTXPOW \n");
- rc = -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWTXPOW \n");
+ rc = -EOPNOTSUPP;
break;
case SIOCSIWTXPOW:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWTXPOW \n");
- rc = -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWTXPOW \n");
+ rc = -EOPNOTSUPP;
break;
case SIOCSIWRETRY:
@@ -3262,91 +3037,86 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
// Get range of parameters
case SIOCGIWRANGE:
- {
- struct iw_range range;
+ {
+ struct iw_range range;
- rc = iwctl_giwrange(dev, NULL, &(wrq->u.data), (char *) &range);
- if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
- rc = -EFAULT;
- }
+ rc = iwctl_giwrange(dev, NULL, &(wrq->u.data), (char *)&range);
+ if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
+ rc = -EFAULT;
+ }
- break;
+ break;
case SIOCGIWPOWER:
rc = iwctl_giwpower(dev, NULL, &(wrq->u.power), NULL);
break;
-
case SIOCSIWPOWER:
rc = iwctl_siwpower(dev, NULL, &(wrq->u.power), NULL);
break;
-
case SIOCGIWSENS:
- rc = iwctl_giwsens(dev, NULL, &(wrq->u.sens), NULL);
+ rc = iwctl_giwsens(dev, NULL, &(wrq->u.sens), NULL);
break;
case SIOCSIWSENS:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSENS \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSENS \n");
rc = -EOPNOTSUPP;
break;
- case SIOCGIWAPLIST:
- {
- char buffer[IW_MAX_AP * (sizeof(struct sockaddr) + sizeof(struct iw_quality))];
-
- if (wrq->u.data.pointer) {
- rc = iwctl_giwaplist(dev, NULL, &(wrq->u.data), buffer);
- if (rc == 0) {
- if (copy_to_user(wrq->u.data.pointer,
- buffer,
- (wrq->u.data.length * (sizeof(struct sockaddr) + sizeof(struct iw_quality)))
- ))
- rc = -EFAULT;
- }
- }
- }
- break;
+ case SIOCGIWAPLIST: {
+ char buffer[IW_MAX_AP * (sizeof(struct sockaddr) + sizeof(struct iw_quality))];
+ if (wrq->u.data.pointer) {
+ rc = iwctl_giwaplist(dev, NULL, &(wrq->u.data), buffer);
+ if (rc == 0) {
+ if (copy_to_user(wrq->u.data.pointer,
+ buffer,
+ (wrq->u.data.length * (sizeof(struct sockaddr) + sizeof(struct iw_quality)))
+ ))
+ rc = -EFAULT;
+ }
+ }
+ }
+ break;
#ifdef WIRELESS_SPY
- // Set the spy list
+ // Set the spy list
case SIOCSIWSPY:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSPY \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSPY \n");
rc = -EOPNOTSUPP;
break;
// Get the spy list
case SIOCGIWSPY:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSPY \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSPY \n");
rc = -EOPNOTSUPP;
break;
#endif // WIRELESS_SPY
case SIOCGIWPRIV:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPRIV \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPRIV \n");
rc = -EOPNOTSUPP;
/*
- if(wrq->u.data.pointer) {
- wrq->u.data.length = sizeof(iwctl_private_args) / sizeof( iwctl_private_args[0]);
+ if (wrq->u.data.pointer) {
+ wrq->u.data.length = sizeof(iwctl_private_args) / sizeof(iwctl_private_args[0]);
- if(copy_to_user(wrq->u.data.pointer,
- (u_char *) iwctl_private_args,
- sizeof(iwctl_private_args)))
- rc = -EFAULT;
- }
+ if (copy_to_user(wrq->u.data.pointer,
+ (u_char *) iwctl_private_args,
+ sizeof(iwctl_private_args)))
+ rc = -EFAULT;
+ }
*/
break;
-
//2008-0409-07, <Add> by Einsn Liu
-#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
case SIOCSIWAUTH:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n");
rc = iwctl_siwauth(dev, NULL, &(wrq->u.param), NULL);
@@ -3367,27 +3137,26 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
rc = iwctl_giwgenie(dev, NULL, &(wrq->u.data), wrq->u.data.pointer);
break;
- case SIOCSIWENCODEEXT:
- {
- char extra[sizeof(struct iw_encode_ext)+MAX_KEY_LEN+1];
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODEEXT \n");
- if(wrq->u.encoding.pointer){
- memset(extra, 0, sizeof(struct iw_encode_ext)+MAX_KEY_LEN+1);
- if(wrq->u.encoding.length > (sizeof(struct iw_encode_ext)+ MAX_KEY_LEN)){
- rc = -E2BIG;
- break;
- }
- if(copy_from_user(extra, wrq->u.encoding.pointer,wrq->u.encoding.length)){
- rc = -EFAULT;
- break;
- }
- }else if(wrq->u.encoding.length != 0){
- rc = -EINVAL;
+ case SIOCSIWENCODEEXT: {
+ char extra[sizeof(struct iw_encode_ext)+MAX_KEY_LEN+1];
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODEEXT \n");
+ if (wrq->u.encoding.pointer) {
+ memset(extra, 0, sizeof(struct iw_encode_ext)+MAX_KEY_LEN + 1);
+ if (wrq->u.encoding.length > (sizeof(struct iw_encode_ext) + MAX_KEY_LEN)) {
+ rc = -E2BIG;
+ break;
+ }
+ if (copy_from_user(extra, wrq->u.encoding.pointer, wrq->u.encoding.length)) {
+ rc = -EFAULT;
break;
}
- rc = iwctl_siwencodeext(dev, NULL, &(wrq->u.encoding), extra);
+ } else if (wrq->u.encoding.length != 0) {
+ rc = -EINVAL;
+ break;
}
- break;
+ rc = iwctl_siwencodeext(dev, NULL, &(wrq->u.encoding), extra);
+ }
+ break;
case SIOCGIWENCODEEXT:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODEEXT \n");
@@ -3402,91 +3171,87 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
#endif // #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//End Add -- //2008-0409-07, <Add> by Einsn Liu
- case IOCTL_CMD_TEST:
+ case IOCTL_CMD_TEST:
if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
- rc = -EFAULT;
- break;
- } else {
- rc = 0;
- }
- pReq = (PSCmdRequest)rq;
- pReq->wResult = MAGIC_CODE;
- break;
-
- case IOCTL_CMD_SET:
-
- #ifdef SndEvt_ToAPI
- if((((PSCmdRequest)rq)->wCmdCode !=WLAN_CMD_SET_EVT) &&
- !(pDevice->flags & DEVICE_FLAGS_OPENED))
- #else
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED) &&
- (((PSCmdRequest)rq)->wCmdCode !=WLAN_CMD_SET_WPA))
- #endif
- {
- rc = -EFAULT;
- break;
+ rc = -EFAULT;
+ break;
} else {
- rc = 0;
+ rc = 0;
}
+ pReq = (PSCmdRequest)rq;
+ pReq->wResult = MAGIC_CODE;
+ break;
- if (test_and_set_bit( 0, (void*)&(pMgmt->uCmdBusy))) {
- return -EBUSY;
- }
- rc = private_ioctl(pDevice, rq);
- clear_bit( 0, (void*)&(pMgmt->uCmdBusy));
- break;
+ case IOCTL_CMD_SET:
- case IOCTL_CMD_HOSTAPD:
+#ifdef SndEvt_ToAPI
+ if ((((PSCmdRequest)rq)->wCmdCode != WLAN_CMD_SET_EVT) &&
+ !(pDevice->flags & DEVICE_FLAGS_OPENED))
+#else
+ if (!(pDevice->flags & DEVICE_FLAGS_OPENED) &&
+ (((PSCmdRequest)rq)->wCmdCode != WLAN_CMD_SET_WPA))
+#endif
+ {
+ rc = -EFAULT;
+ break;
+ } else {
+ rc = 0;
+ }
+
+ if (test_and_set_bit(0, (void *)&(pMgmt->uCmdBusy))) {
+ return -EBUSY;
+ }
+ rc = private_ioctl(pDevice, rq);
+ clear_bit(0, (void *)&(pMgmt->uCmdBusy));
+ break;
+ case IOCTL_CMD_HOSTAPD:
- rc = vt6655_hostap_ioctl(pDevice, &wrq->u.data);
- break;
+ rc = vt6655_hostap_ioctl(pDevice, &wrq->u.data);
+ break;
- case IOCTL_CMD_WPA:
+ case IOCTL_CMD_WPA:
- rc = wpa_ioctl(pDevice, &wrq->u.data);
- break;
+ rc = wpa_ioctl(pDevice, &wrq->u.data);
+ break;
case SIOCETHTOOL:
- return ethtool_ioctl(dev, (void *) rq->ifr_data);
- // All other calls are currently unsupported
+ return ethtool_ioctl(dev, (void *)rq->ifr_data);
+ // All other calls are currently unsupported
default:
rc = -EOPNOTSUPP;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not support..%x\n", cmd);
-
-
- }
-
- if (pDevice->bCommit) {
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- netif_stop_queue(pDevice->dev);
- spin_lock_irq(&pDevice->lock);
- bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
- spin_unlock_irq(&pDevice->lock);
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Commit the settings\n");
- spin_lock_irq(&pDevice->lock);
- pDevice->bLinkPass = false;
- memset(pMgmt->abyCurrBSSID, 0, 6);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- netif_stop_queue(pDevice->dev);
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- if(pDevice->bWPASuppWextEnabled !=true)
- #endif
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
- spin_unlock_irq(&pDevice->lock);
- }
- pDevice->bCommit = false;
- }
-
- return rc;
-}
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not support..%x\n", cmd);
+ }
+
+ if (pDevice->bCommit) {
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ netif_stop_queue(pDevice->dev);
+ spin_lock_irq(&pDevice->lock);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+ spin_unlock_irq(&pDevice->lock);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Commit the settings\n");
+ spin_lock_irq(&pDevice->lock);
+ pDevice->bLinkPass = false;
+ memset(pMgmt->abyCurrBSSID, 0, 6);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ netif_stop_queue(pDevice->dev);
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ if (pDevice->bWPASuppWextEnabled != true)
+#endif
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
+ spin_unlock_irq(&pDevice->lock);
+ }
+ pDevice->bCommit = false;
+ }
+
+ return rc;
+}
static int ethtool_ioctl(struct net_device *dev, void *useraddr)
{
@@ -3495,7 +3260,7 @@ static int ethtool_ioctl(struct net_device *dev, void *useraddr)
if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
return -EFAULT;
- switch (ethcmd) {
+ switch (ethcmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, DEVICE_NAME, sizeof(info.driver)-1);
@@ -3505,7 +3270,7 @@ static int ethtool_ioctl(struct net_device *dev, void *useraddr)
return 0;
}
- }
+ }
return -EOPNOTSUPP;
}
@@ -3527,122 +3292,111 @@ static struct pci_driver device_driver = {
static int __init vt6655_init_module(void)
{
- int ret;
-
+ int ret;
// ret=pci_module_init(&device_driver);
//ret = pcie_port_service_register(&device_driver);
ret = pci_register_driver(&device_driver);
#ifdef CONFIG_PM
- if(ret >= 0)
- register_reboot_notifier(&device_notifier);
+ if (ret >= 0)
+ register_reboot_notifier(&device_notifier);
#endif
- return ret;
+ return ret;
}
static void __exit vt6655_cleanup_module(void)
{
-
-
#ifdef CONFIG_PM
- unregister_reboot_notifier(&device_notifier);
+ unregister_reboot_notifier(&device_notifier);
#endif
- pci_unregister_driver(&device_driver);
-
+ pci_unregister_driver(&device_driver);
}
module_init(vt6655_init_module);
module_exit(vt6655_cleanup_module);
-
#ifdef CONFIG_PM
static int
device_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
{
- struct pci_dev *pdev = NULL;
- switch(event) {
- case SYS_DOWN:
- case SYS_HALT:
- case SYS_POWER_OFF:
- for_each_pci_dev(pdev) {
- if(pci_dev_driver(pdev) == &device_driver) {
- if (pci_get_drvdata(pdev))
- viawget_suspend(pdev, PMSG_HIBERNATE);
- }
- }
- }
- return NOTIFY_DONE;
+ struct pci_dev *pdev = NULL;
+ switch (event) {
+ case SYS_DOWN:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ for_each_pci_dev(pdev) {
+ if (pci_dev_driver(pdev) == &device_driver) {
+ if (pci_get_drvdata(pdev))
+ viawget_suspend(pdev, PMSG_HIBERNATE);
+ }
+ }
+ }
+ return NOTIFY_DONE;
}
static int
viawget_suspend(struct pci_dev *pcid, pm_message_t state)
{
- int power_status; // to silence the compiler
-
- PSDevice pDevice=pci_get_drvdata(pcid);
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
- netif_stop_queue(pDevice->dev);
- spin_lock_irq(&pDevice->lock);
- pci_save_state(pcid);
- del_timer(&pDevice->sTimerCommand);
- del_timer(&pMgmt->sTimerSecondCallback);
- pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
- pDevice->uCmdDequeueIdx = 0;
- pDevice->uCmdEnqueueIdx = 0;
- pDevice->bCmdRunning = false;
- MACbShutdown(pDevice->PortOffset);
- MACvSaveContext(pDevice->PortOffset, pDevice->abyMacContext);
- pDevice->bLinkPass = false;
- memset(pMgmt->abyCurrBSSID, 0, 6);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pci_disable_device(pcid);
- power_status = pci_set_power_state(pcid, pci_choose_state(pcid, state));
- spin_unlock_irq(&pDevice->lock);
- return 0;
+ int power_status; // to silence the compiler
+
+ PSDevice pDevice = pci_get_drvdata(pcid);
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ netif_stop_queue(pDevice->dev);
+ spin_lock_irq(&pDevice->lock);
+ pci_save_state(pcid);
+ del_timer(&pDevice->sTimerCommand);
+ del_timer(&pMgmt->sTimerSecondCallback);
+ pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
+ pDevice->uCmdDequeueIdx = 0;
+ pDevice->uCmdEnqueueIdx = 0;
+ pDevice->bCmdRunning = false;
+ MACbShutdown(pDevice->PortOffset);
+ MACvSaveContext(pDevice->PortOffset, pDevice->abyMacContext);
+ pDevice->bLinkPass = false;
+ memset(pMgmt->abyCurrBSSID, 0, 6);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pci_disable_device(pcid);
+ power_status = pci_set_power_state(pcid, pci_choose_state(pcid, state));
+ spin_unlock_irq(&pDevice->lock);
+ return 0;
}
static int
viawget_resume(struct pci_dev *pcid)
{
- PSDevice pDevice=pci_get_drvdata(pcid);
- PSMgmtObject pMgmt = pDevice->pMgmt;
- int power_status; // to silence the compiler
-
-
- power_status = pci_set_power_state(pcid, 0);
- power_status = pci_enable_wake(pcid, 0, 0);
- pci_restore_state(pcid);
- if (netif_running(pDevice->dev)) {
- spin_lock_irq(&pDevice->lock);
- MACvRestoreContext(pDevice->PortOffset, pDevice->abyMacContext);
- device_init_registers(pDevice, DEVICE_INIT_DXPL);
- if (pMgmt->sNodeDBTable[0].bActive == true) { // Assoc with BSS
- pMgmt->sNodeDBTable[0].bActive = false;
- pDevice->bLinkPass = false;
- if(pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- // In Adhoc, BSS state set back to started.
- pMgmt->eCurrState = WMAC_STATE_STARTED;
- }
- else {
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- }
- }
- init_timer(&pMgmt->sTimerSecondCallback);
- init_timer(&pDevice->sTimerCommand);
- MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
- spin_unlock_irq(&pDevice->lock);
- }
- return 0;
+ PSDevice pDevice = pci_get_drvdata(pcid);
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ int power_status; // to silence the compiler
+
+ power_status = pci_set_power_state(pcid, 0);
+ power_status = pci_enable_wake(pcid, 0, 0);
+ pci_restore_state(pcid);
+ if (netif_running(pDevice->dev)) {
+ spin_lock_irq(&pDevice->lock);
+ MACvRestoreContext(pDevice->PortOffset, pDevice->abyMacContext);
+ device_init_registers(pDevice, DEVICE_INIT_DXPL);
+ if (pMgmt->sNodeDBTable[0].bActive == true) { // Assoc with BSS
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pDevice->bLinkPass = false;
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ // In Adhoc, BSS state set back to started.
+ pMgmt->eCurrState = WMAC_STATE_STARTED;
+ } else {
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ }
+ }
+ init_timer(&pMgmt->sTimerSecondCallback);
+ init_timer(&pDevice->sTimerCommand);
+ MACvIntEnable(pDevice->PortOffset, IMR_MASK_VALUE);
+ BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
+ spin_unlock_irq(&pDevice->lock);
+ }
+ return 0;
}
#endif
-
-
-
-
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index 373e9e4fc87d..a9533f3f2529 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -55,20 +55,17 @@
#include "iowpa.h"
#include "aes_ccmp.h"
-
-
/*--------------------- Static Definitions -------------------------*/
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
const unsigned char acbyRxRate[MAX_RATE] =
{2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108};
-
/*--------------------- Static Functions --------------------------*/
/*--------------------- Static Definitions -------------------------*/
@@ -77,60 +74,56 @@ const unsigned char acbyRxRate[MAX_RATE] =
static unsigned char s_byGetRateIdx(unsigned char byRate);
-
static void
s_vGetDASA(unsigned char *pbyRxBufferAddr, unsigned int *pcbHeaderSize,
- PSEthernetHeader psEthHeader);
+ PSEthernetHeader psEthHeader);
static void
s_vProcessRxMACHeader(PSDevice pDevice, unsigned char *pbyRxBufferAddr,
- unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
- unsigned int *pcbHeadSize);
+ unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
+ unsigned int *pcbHeadSize);
static bool s_bAPModeRxCtl(
- PSDevice pDevice,
- unsigned char *pbyFrame,
- int iSANodeIndex
- );
-
-
-
-static bool s_bAPModeRxData (
- PSDevice pDevice,
- struct sk_buff* skb,
- unsigned int FrameSize,
- unsigned int cbHeaderOffset,
- int iSANodeIndex,
- int iDANodeIndex
- );
-
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ int iSANodeIndex
+);
+
+static bool s_bAPModeRxData(
+ PSDevice pDevice,
+ struct sk_buff *skb,
+ unsigned int FrameSize,
+ unsigned int cbHeaderOffset,
+ int iSANodeIndex,
+ int iDANodeIndex
+);
static bool s_bHandleRxEncryption(
- PSDevice pDevice,
- unsigned char *pbyFrame,
- unsigned int FrameSize,
- unsigned char *pbyRsr,
- unsigned char *pbyNewRsr,
- PSKeyItem *pKeyOut,
- bool *pbExtIV,
- unsigned short *pwRxTSC15_0,
- unsigned long *pdwRxTSC47_16
- );
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ unsigned char *pbyNewRsr,
+ PSKeyItem *pKeyOut,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
+);
static bool s_bHostWepRxEncryption(
- PSDevice pDevice,
- unsigned char *pbyFrame,
- unsigned int FrameSize,
- unsigned char *pbyRsr,
- bool bOnFly,
- PSKeyItem pKey,
- unsigned char *pbyNewRsr,
- bool *pbExtIV,
- unsigned short *pwRxTSC15_0,
- unsigned long *pdwRxTSC47_16
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ bool bOnFly,
+ PSKeyItem pKey,
+ unsigned char *pbyNewRsr,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
- );
+);
/*--------------------- Export Variables --------------------------*/
@@ -150,694 +143,647 @@ static bool s_bHostWepRxEncryption(
*
* Return Value: None
*
--*/
+ -*/
static void
s_vProcessRxMACHeader(PSDevice pDevice, unsigned char *pbyRxBufferAddr,
- unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
- unsigned int *pcbHeadSize)
+ unsigned int cbPacketSize, bool bIsWEP, bool bExtIV,
+ unsigned int *pcbHeadSize)
{
- unsigned char *pbyRxBuffer;
- unsigned int cbHeaderSize = 0;
- unsigned short *pwType;
- PS802_11Header pMACHeader;
- int ii;
-
-
- pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
-
- s_vGetDASA((unsigned char *)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
-
- if (bIsWEP) {
- if (bExtIV) {
- // strip IV&ExtIV , add 8 byte
- cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 8);
- } else {
- // strip IV , add 4 byte
- cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 4);
- }
- }
- else {
- cbHeaderSize += WLAN_HDR_ADDR3_LEN;
- };
-
- pbyRxBuffer = (unsigned char *) (pbyRxBufferAddr + cbHeaderSize);
- if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
- cbHeaderSize += 6;
- }
- else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
- cbHeaderSize += 6;
- pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
- if ((*pwType!= TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) {
- }
- else {
- cbHeaderSize -= 8;
- pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
- if (bIsWEP) {
- if (bExtIV) {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
- } else {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV
- }
- }
- else {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN);
- }
- }
- }
- else {
- cbHeaderSize -= 2;
- pwType = (unsigned short *) (pbyRxBufferAddr + cbHeaderSize);
- if (bIsWEP) {
- if (bExtIV) {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
- } else {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV
- }
- }
- else {
- *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN);
- }
- }
-
- cbHeaderSize -= (ETH_ALEN * 2);
- pbyRxBuffer = (unsigned char *) (pbyRxBufferAddr + cbHeaderSize);
- for(ii=0;ii<ETH_ALEN;ii++)
- *pbyRxBuffer++ = pDevice->sRxEthHeader.abyDstAddr[ii];
- for(ii=0;ii<ETH_ALEN;ii++)
- *pbyRxBuffer++ = pDevice->sRxEthHeader.abySrcAddr[ii];
-
- *pcbHeadSize = cbHeaderSize;
-}
-
+ unsigned char *pbyRxBuffer;
+ unsigned int cbHeaderSize = 0;
+ unsigned short *pwType;
+ PS802_11Header pMACHeader;
+ int ii;
+
+ pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
+
+ s_vGetDASA((unsigned char *)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
+
+ if (bIsWEP) {
+ if (bExtIV) {
+ // strip IV&ExtIV , add 8 byte
+ cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 8);
+ } else {
+ // strip IV , add 4 byte
+ cbHeaderSize += (WLAN_HDR_ADDR3_LEN + 4);
+ }
+ } else {
+ cbHeaderSize += WLAN_HDR_ADDR3_LEN;
+ };
+
+ pbyRxBuffer = (unsigned char *)(pbyRxBufferAddr + cbHeaderSize);
+ if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
+ cbHeaderSize += 6;
+ } else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
+ cbHeaderSize += 6;
+ pwType = (unsigned short *)(pbyRxBufferAddr + cbHeaderSize);
+ if ((*pwType != TYPE_PKT_IPX) && (*pwType != cpu_to_le16(0xF380))) {
+ } else {
+ cbHeaderSize -= 8;
+ pwType = (unsigned short *)(pbyRxBufferAddr + cbHeaderSize);
+ if (bIsWEP) {
+ if (bExtIV) {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
+ } else {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV
+ }
+ } else {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN);
+ }
+ }
+ } else {
+ cbHeaderSize -= 2;
+ pwType = (unsigned short *)(pbyRxBufferAddr + cbHeaderSize);
+ if (bIsWEP) {
+ if (bExtIV) {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
+ } else {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 4); // 4 is IV
+ }
+ } else {
+ *pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN);
+ }
+ }
+ cbHeaderSize -= (ETH_ALEN * 2);
+ pbyRxBuffer = (unsigned char *)(pbyRxBufferAddr + cbHeaderSize);
+ for (ii = 0; ii < ETH_ALEN; ii++)
+ *pbyRxBuffer++ = pDevice->sRxEthHeader.abyDstAddr[ii];
+ for (ii = 0; ii < ETH_ALEN; ii++)
+ *pbyRxBuffer++ = pDevice->sRxEthHeader.abySrcAddr[ii];
+ *pcbHeadSize = cbHeaderSize;
+}
-static unsigned char s_byGetRateIdx (unsigned char byRate)
+static unsigned char s_byGetRateIdx(unsigned char byRate)
{
- unsigned char byRateIdx;
+ unsigned char byRateIdx;
- for (byRateIdx = 0; byRateIdx <MAX_RATE ; byRateIdx++) {
- if (acbyRxRate[byRateIdx%MAX_RATE] == byRate)
- return byRateIdx;
- }
- return 0;
+ for (byRateIdx = 0; byRateIdx < MAX_RATE; byRateIdx++) {
+ if (acbyRxRate[byRateIdx % MAX_RATE] == byRate)
+ return byRateIdx;
+ }
+ return 0;
}
-
static void
s_vGetDASA(unsigned char *pbyRxBufferAddr, unsigned int *pcbHeaderSize,
- PSEthernetHeader psEthHeader)
+ PSEthernetHeader psEthHeader)
{
- unsigned int cbHeaderSize = 0;
- PS802_11Header pMACHeader;
- int ii;
-
- pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
-
- if ((pMACHeader->wFrameCtl & FC_TODS) == 0) {
- if (pMACHeader->wFrameCtl & FC_FROMDS) {
- for(ii=0;ii<ETH_ALEN;ii++) {
- psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr1[ii];
- psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr3[ii];
- }
- }
- else {
- // IBSS mode
- for(ii=0;ii<ETH_ALEN;ii++) {
- psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr1[ii];
- psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii];
- }
- }
- }
- else {
- // Is AP mode..
- if (pMACHeader->wFrameCtl & FC_FROMDS) {
- for(ii=0;ii<ETH_ALEN;ii++) {
- psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr3[ii];
- psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr4[ii];
- cbHeaderSize += 6;
- }
- }
- else {
- for(ii=0;ii<ETH_ALEN;ii++) {
- psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr3[ii];
- psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii];
- }
- }
- };
- *pcbHeaderSize = cbHeaderSize;
+ unsigned int cbHeaderSize = 0;
+ PS802_11Header pMACHeader;
+ int ii;
+
+ pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
+
+ if ((pMACHeader->wFrameCtl & FC_TODS) == 0) {
+ if (pMACHeader->wFrameCtl & FC_FROMDS) {
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr1[ii];
+ psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr3[ii];
+ }
+ } else {
+ // IBSS mode
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr1[ii];
+ psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii];
+ }
+ }
+ } else {
+ // Is AP mode..
+ if (pMACHeader->wFrameCtl & FC_FROMDS) {
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr3[ii];
+ psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr4[ii];
+ cbHeaderSize += 6;
+ }
+ } else {
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ psEthHeader->abyDstAddr[ii] = pMACHeader->abyAddr3[ii];
+ psEthHeader->abySrcAddr[ii] = pMACHeader->abyAddr2[ii];
+ }
+ }
+ };
+ *pcbHeaderSize = cbHeaderSize;
}
-
-
-
//PLICE_DEBUG ->
void MngWorkItem(void *Context)
{
PSRxMgmtPacket pRxMgmtPacket;
PSDevice pDevice = (PSDevice) Context;
- //printk("Enter MngWorkItem,Queue packet num is %d\n",pDevice->rxManeQueue.packet_num);
+
spin_lock_irq(&pDevice->lock);
- while(pDevice->rxManeQueue.packet_num != 0)
- {
- pRxMgmtPacket = DeQueue(pDevice);
- vMgrRxManagePacket(pDevice, pDevice->pMgmt, pRxMgmtPacket);
+ while (pDevice->rxManeQueue.packet_num != 0) {
+ pRxMgmtPacket = DeQueue(pDevice);
+ vMgrRxManagePacket(pDevice, pDevice->pMgmt, pRxMgmtPacket);
}
spin_unlock_irq(&pDevice->lock);
}
-
//PLICE_DEBUG<-
-
-
bool
-device_receive_frame (
- PSDevice pDevice,
- PSRxDesc pCurrRD
- )
+device_receive_frame(
+ PSDevice pDevice,
+ PSRxDesc pCurrRD
+)
{
-
- PDEVICE_RD_INFO pRDInfo = pCurrRD->pRDInfo;
-#ifdef PLICE_DEBUG
- //printk("device_receive_frame:pCurrRD is %x,pRDInfo is %x\n",pCurrRD,pCurrRD->pRDInfo);
-#endif
- struct net_device_stats* pStats=&pDevice->stats;
- struct sk_buff* skb;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSRxMgmtPacket pRxPacket = &(pDevice->pMgmt->sRxPacket);
- PS802_11Header p802_11Header;
- unsigned char *pbyRsr;
- unsigned char *pbyNewRsr;
- unsigned char *pbyRSSI;
- PQWORD pqwTSFTime;
- unsigned short *pwFrameSize;
- unsigned char *pbyFrame;
- bool bDeFragRx = false;
- bool bIsWEP = false;
- unsigned int cbHeaderOffset;
- unsigned int FrameSize;
- unsigned short wEtherType = 0;
- int iSANodeIndex = -1;
- int iDANodeIndex = -1;
- unsigned int ii;
- unsigned int cbIVOffset;
- bool bExtIV = false;
- unsigned char *pbyRxSts;
- unsigned char *pbyRxRate;
- unsigned char *pbySQ;
- unsigned int cbHeaderSize;
- PSKeyItem pKey = NULL;
- unsigned short wRxTSC15_0 = 0;
- unsigned long dwRxTSC47_16 = 0;
- SKeyItem STempKey;
- // 802.11h RPI
- unsigned long dwDuration = 0;
- long ldBm = 0;
- long ldBmThreshold = 0;
- PS802_11Header pMACHeader;
- bool bRxeapol_key = false;
-
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- device_receive_frame---\n");
-
- skb = pRDInfo->skb;
-
+ PDEVICE_RD_INFO pRDInfo = pCurrRD->pRDInfo;
+ struct net_device_stats *pStats = &pDevice->stats;
+ struct sk_buff *skb;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSRxMgmtPacket pRxPacket = &(pDevice->pMgmt->sRxPacket);
+ PS802_11Header p802_11Header;
+ unsigned char *pbyRsr;
+ unsigned char *pbyNewRsr;
+ unsigned char *pbyRSSI;
+ PQWORD pqwTSFTime;
+ unsigned short *pwFrameSize;
+ unsigned char *pbyFrame;
+ bool bDeFragRx = false;
+ bool bIsWEP = false;
+ unsigned int cbHeaderOffset;
+ unsigned int FrameSize;
+ unsigned short wEtherType = 0;
+ int iSANodeIndex = -1;
+ int iDANodeIndex = -1;
+ unsigned int ii;
+ unsigned int cbIVOffset;
+ bool bExtIV = false;
+ unsigned char *pbyRxSts;
+ unsigned char *pbyRxRate;
+ unsigned char *pbySQ;
+ unsigned int cbHeaderSize;
+ PSKeyItem pKey = NULL;
+ unsigned short wRxTSC15_0 = 0;
+ unsigned long dwRxTSC47_16 = 0;
+ SKeyItem STempKey;
+ // 802.11h RPI
+ unsigned long dwDuration = 0;
+ long ldBm = 0;
+ long ldBmThreshold = 0;
+ PS802_11Header pMACHeader;
+ bool bRxeapol_key = false;
+
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "---------- device_receive_frame---\n");
+
+ skb = pRDInfo->skb;
//PLICE_DEBUG->
#if 1
pci_unmap_single(pDevice->pcid, pRDInfo->skb_dma,
- pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ pDevice->rx_buf_sz, PCI_DMA_FROMDEVICE);
#endif
//PLICE_DEBUG<-
- pwFrameSize = (unsigned short *)(skb->data + 2);
- FrameSize = cpu_to_le16(pCurrRD->m_rd1RD1.wReqCount) - cpu_to_le16(pCurrRD->m_rd0RD0.wResCount);
-
- // Max: 2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
- // Min (ACK): 10HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
- if ((FrameSize > 2364)||(FrameSize <= 32)) {
- // Frame Size error drop this packet.
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 1 \n");
- return false;
- }
-
- pbyRxSts = (unsigned char *) (skb->data);
- pbyRxRate = (unsigned char *) (skb->data + 1);
- pbyRsr = (unsigned char *) (skb->data + FrameSize - 1);
- pbyRSSI = (unsigned char *) (skb->data + FrameSize - 2);
- pbyNewRsr = (unsigned char *) (skb->data + FrameSize - 3);
- pbySQ = (unsigned char *) (skb->data + FrameSize - 4);
- pqwTSFTime = (PQWORD) (skb->data + FrameSize - 12);
- pbyFrame = (unsigned char *)(skb->data + 4);
-
- // get packet size
- FrameSize = cpu_to_le16(*pwFrameSize);
-
- if ((FrameSize > 2346)|(FrameSize < 14)) { // Max: 2312Payload + 30HD +4CRC
- // Min: 14 bytes ACK
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- WRONG Length 2 \n");
- return false;
- }
+ pwFrameSize = (unsigned short *)(skb->data + 2);
+ FrameSize = cpu_to_le16(pCurrRD->m_rd1RD1.wReqCount) - cpu_to_le16(pCurrRD->m_rd0RD0.wResCount);
+
+ // Max: 2312Payload + 30HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
+ // Min (ACK): 10HD +4CRC + 2Padding + 4Len + 8TSF + 4RSR
+ if ((FrameSize > 2364) || (FrameSize <= 32)) {
+ // Frame Size error drop this packet.
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "---------- WRONG Length 1 \n");
+ return false;
+ }
+
+ pbyRxSts = (unsigned char *)(skb->data);
+ pbyRxRate = (unsigned char *)(skb->data + 1);
+ pbyRsr = (unsigned char *)(skb->data + FrameSize - 1);
+ pbyRSSI = (unsigned char *)(skb->data + FrameSize - 2);
+ pbyNewRsr = (unsigned char *)(skb->data + FrameSize - 3);
+ pbySQ = (unsigned char *)(skb->data + FrameSize - 4);
+ pqwTSFTime = (PQWORD)(skb->data + FrameSize - 12);
+ pbyFrame = (unsigned char *)(skb->data + 4);
+
+ // get packet size
+ FrameSize = cpu_to_le16(*pwFrameSize);
+
+ if ((FrameSize > 2346)|(FrameSize < 14)) { // Max: 2312Payload + 30HD +4CRC
+ // Min: 14 bytes ACK
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "---------- WRONG Length 2 \n");
+ return false;
+ }
//PLICE_DEBUG->
#if 1
// update receive statistic counter
- STAvUpdateRDStatCounter(&pDevice->scStatistic,
- *pbyRsr,
- *pbyNewRsr,
- *pbyRxRate,
- pbyFrame,
- FrameSize);
+ STAvUpdateRDStatCounter(&pDevice->scStatistic,
+ *pbyRsr,
+ *pbyNewRsr,
+ *pbyRxRate,
+ pbyFrame,
+ FrameSize);
#endif
- pMACHeader=(PS802_11Header)((unsigned char *) (skb->data)+8);
+ pMACHeader = (PS802_11Header)((unsigned char *)(skb->data) + 8);
//PLICE_DEBUG<-
if (pDevice->bMeasureInProgress == true) {
- if ((*pbyRsr & RSR_CRCOK) != 0) {
- pDevice->byBasicMap |= 0x01;
- }
- dwDuration = (FrameSize << 4);
- dwDuration /= acbyRxRate[*pbyRxRate%MAX_RATE];
- if (*pbyRxRate <= RATE_11M) {
- if (*pbyRxSts & 0x01) {
- // long preamble
- dwDuration += 192;
- } else {
- // short preamble
- dwDuration += 96;
- }
- } else {
- dwDuration += 16;
- }
- RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
- ldBmThreshold = -57;
- for (ii = 7; ii > 0;) {
- if (ldBm > ldBmThreshold) {
- break;
- }
- ldBmThreshold -= 5;
- ii--;
- }
- pDevice->dwRPIs[ii] += dwDuration;
- return false;
- }
-
- if (!is_multicast_ether_addr(pbyFrame)) {
- if (WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) (skb->data + 4))) {
- pDevice->s802_11Counter.FrameDuplicateCount++;
- return false;
- }
- }
-
-
- // Use for TKIP MIC
- s_vGetDASA(skb->data+4, &cbHeaderSize, &pDevice->sRxEthHeader);
-
- // filter packet send from myself
- if (!compare_ether_addr((unsigned char *)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr))
- return false;
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
- if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
- p802_11Header = (PS802_11Header) (pbyFrame);
- // get SA NodeIndex
- if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(p802_11Header->abyAddr2), &iSANodeIndex)) {
- pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = jiffies;
- pMgmt->sNodeDBTable[iSANodeIndex].uInActiveCount = 0;
- }
- }
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (s_bAPModeRxCtl(pDevice, pbyFrame, iSANodeIndex) == true) {
- return false;
- }
- }
-
-
- if (IS_FC_WEP(pbyFrame)) {
- bool bRxDecryOK = false;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"rx WEP pkt\n");
- bIsWEP = true;
- if ((pDevice->bEnableHostWEP) && (iSANodeIndex >= 0)) {
- pKey = &STempKey;
- pKey->byCipherSuite = pMgmt->sNodeDBTable[iSANodeIndex].byCipherSuite;
- pKey->dwKeyIndex = pMgmt->sNodeDBTable[iSANodeIndex].dwKeyIndex;
- pKey->uKeyLength = pMgmt->sNodeDBTable[iSANodeIndex].uWepKeyLength;
- pKey->dwTSC47_16 = pMgmt->sNodeDBTable[iSANodeIndex].dwTSC47_16;
- pKey->wTSC15_0 = pMgmt->sNodeDBTable[iSANodeIndex].wTSC15_0;
- memcpy(pKey->abyKey,
- &pMgmt->sNodeDBTable[iSANodeIndex].abyWepKey[0],
- pKey->uKeyLength
- );
-
- bRxDecryOK = s_bHostWepRxEncryption(pDevice,
- pbyFrame,
- FrameSize,
- pbyRsr,
- pMgmt->sNodeDBTable[iSANodeIndex].bOnFly,
- pKey,
- pbyNewRsr,
- &bExtIV,
- &wRxTSC15_0,
- &dwRxTSC47_16);
- } else {
- bRxDecryOK = s_bHandleRxEncryption(pDevice,
- pbyFrame,
- FrameSize,
- pbyRsr,
- pbyNewRsr,
- &pKey,
- &bExtIV,
- &wRxTSC15_0,
- &dwRxTSC47_16);
- }
-
- if (bRxDecryOK) {
- if ((*pbyNewRsr & NEWRSR_DECRYPTOK) == 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV Fail\n");
- if ( (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
- (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
- (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) ||
- (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
-
- if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
- pDevice->s802_11Counter.TKIPICVErrors++;
- } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP)) {
- pDevice->s802_11Counter.CCMPDecryptErrors++;
- } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_WEP)) {
+ if ((*pbyRsr & RSR_CRCOK) != 0) {
+ pDevice->byBasicMap |= 0x01;
+ }
+ dwDuration = (FrameSize << 4);
+ dwDuration /= acbyRxRate[*pbyRxRate%MAX_RATE];
+ if (*pbyRxRate <= RATE_11M) {
+ if (*pbyRxSts & 0x01) {
+ // long preamble
+ dwDuration += 192;
+ } else {
+ // short preamble
+ dwDuration += 96;
+ }
+ } else {
+ dwDuration += 16;
+ }
+ RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
+ ldBmThreshold = -57;
+ for (ii = 7; ii > 0;) {
+ if (ldBm > ldBmThreshold) {
+ break;
+ }
+ ldBmThreshold -= 5;
+ ii--;
+ }
+ pDevice->dwRPIs[ii] += dwDuration;
+ return false;
+ }
+
+ if (!is_multicast_ether_addr(pbyFrame)) {
+ if (WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header)(skb->data + 4))) {
+ pDevice->s802_11Counter.FrameDuplicateCount++;
+ return false;
+ }
+ }
+
+ // Use for TKIP MIC
+ s_vGetDASA(skb->data+4, &cbHeaderSize, &pDevice->sRxEthHeader);
+
+ // filter packet send from myself
+ if (!compare_ether_addr((unsigned char *)&(pDevice->sRxEthHeader.abySrcAddr[0]), pDevice->abyCurrentNetAddr))
+ return false;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
+ if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
+ p802_11Header = (PS802_11Header)(pbyFrame);
+ // get SA NodeIndex
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(p802_11Header->abyAddr2), &iSANodeIndex)) {
+ pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = jiffies;
+ pMgmt->sNodeDBTable[iSANodeIndex].uInActiveCount = 0;
+ }
+ }
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (s_bAPModeRxCtl(pDevice, pbyFrame, iSANodeIndex) == true) {
+ return false;
+ }
+ }
+
+ if (IS_FC_WEP(pbyFrame)) {
+ bool bRxDecryOK = false;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx WEP pkt\n");
+ bIsWEP = true;
+ if ((pDevice->bEnableHostWEP) && (iSANodeIndex >= 0)) {
+ pKey = &STempKey;
+ pKey->byCipherSuite = pMgmt->sNodeDBTable[iSANodeIndex].byCipherSuite;
+ pKey->dwKeyIndex = pMgmt->sNodeDBTable[iSANodeIndex].dwKeyIndex;
+ pKey->uKeyLength = pMgmt->sNodeDBTable[iSANodeIndex].uWepKeyLength;
+ pKey->dwTSC47_16 = pMgmt->sNodeDBTable[iSANodeIndex].dwTSC47_16;
+ pKey->wTSC15_0 = pMgmt->sNodeDBTable[iSANodeIndex].wTSC15_0;
+ memcpy(pKey->abyKey,
+ &pMgmt->sNodeDBTable[iSANodeIndex].abyWepKey[0],
+ pKey->uKeyLength
+);
+
+ bRxDecryOK = s_bHostWepRxEncryption(pDevice,
+ pbyFrame,
+ FrameSize,
+ pbyRsr,
+ pMgmt->sNodeDBTable[iSANodeIndex].bOnFly,
+ pKey,
+ pbyNewRsr,
+ &bExtIV,
+ &wRxTSC15_0,
+ &dwRxTSC47_16);
+ } else {
+ bRxDecryOK = s_bHandleRxEncryption(pDevice,
+ pbyFrame,
+ FrameSize,
+ pbyRsr,
+ pbyNewRsr,
+ &pKey,
+ &bExtIV,
+ &wRxTSC15_0,
+ &dwRxTSC47_16);
+ }
+
+ if (bRxDecryOK) {
+ if ((*pbyNewRsr & NEWRSR_DECRYPTOK) == 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ICV Fail\n");
+ if ((pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
+ (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
+ (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) ||
+ (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
+ if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
+ pDevice->s802_11Counter.TKIPICVErrors++;
+ } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP)) {
+ pDevice->s802_11Counter.CCMPDecryptErrors++;
+ } else if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_WEP)) {
// pDevice->s802_11Counter.WEPICVErrorCount.QuadPart++;
- }
- }
- return false;
- }
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WEP Func Fail\n");
- return false;
- }
- if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP))
- FrameSize -= 8; // Message Integrity Code
- else
- FrameSize -= 4; // 4 is ICV
- }
-
-
- //
- // RX OK
- //
- //remove the CRC length
- FrameSize -= ETH_FCS_LEN;
-
- if (( !(*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI))) && // unicast address
- (IS_FRAGMENT_PKT((skb->data+4)))
- ) {
- // defragment
- bDeFragRx = WCTLbHandleFragment(pDevice, (PS802_11Header) (skb->data+4), FrameSize, bIsWEP, bExtIV);
- pDevice->s802_11Counter.ReceivedFragmentCount++;
- if (bDeFragRx) {
- // defrag complete
- skb = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb;
- FrameSize = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength;
-
- }
- else {
- return false;
- }
- }
+ }
+ }
+ return false;
+ }
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WEP Func Fail\n");
+ return false;
+ }
+ if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_CCMP))
+ FrameSize -= 8; // Message Integrity Code
+ else
+ FrameSize -= 4; // 4 is ICV
+ }
+ //
+ // RX OK
+ //
+ //remove the CRC length
+ FrameSize -= ETH_FCS_LEN;
+
+ if ((!(*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI))) && // unicast address
+ (IS_FRAGMENT_PKT((skb->data+4)))
+) {
+ // defragment
+ bDeFragRx = WCTLbHandleFragment(pDevice, (PS802_11Header)(skb->data+4), FrameSize, bIsWEP, bExtIV);
+ pDevice->s802_11Counter.ReceivedFragmentCount++;
+ if (bDeFragRx) {
+ // defrag complete
+ skb = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb;
+ FrameSize = pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength;
+
+ } else {
+ return false;
+ }
+ }
// Management & Control frame Handle
- if ((IS_TYPE_DATA((skb->data+4))) == false) {
- // Handle Control & Manage Frame
-
- if (IS_TYPE_MGMT((skb->data+4))) {
- unsigned char *pbyData1;
- unsigned char *pbyData2;
-
- pRxPacket->p80211Header = (PUWLAN_80211HDR)(skb->data+4);
- pRxPacket->cbMPDULen = FrameSize;
- pRxPacket->uRSSI = *pbyRSSI;
- pRxPacket->bySQ = *pbySQ;
- HIDWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(HIDWORD(*pqwTSFTime));
- LODWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(LODWORD(*pqwTSFTime));
- if (bIsWEP) {
- // strip IV
- pbyData1 = WLAN_HDR_A3_DATA_PTR(skb->data+4);
- pbyData2 = WLAN_HDR_A3_DATA_PTR(skb->data+4) + 4;
- for (ii = 0; ii < (FrameSize - 4); ii++) {
- *pbyData1 = *pbyData2;
- pbyData1++;
- pbyData2++;
- }
- }
- pRxPacket->byRxRate = s_byGetRateIdx(*pbyRxRate);
- pRxPacket->byRxChannel = (*pbyRxSts) >> 2;
+ if ((IS_TYPE_DATA((skb->data+4))) == false) {
+ // Handle Control & Manage Frame
+
+ if (IS_TYPE_MGMT((skb->data+4))) {
+ unsigned char *pbyData1;
+ unsigned char *pbyData2;
+
+ pRxPacket->p80211Header = (PUWLAN_80211HDR)(skb->data+4);
+ pRxPacket->cbMPDULen = FrameSize;
+ pRxPacket->uRSSI = *pbyRSSI;
+ pRxPacket->bySQ = *pbySQ;
+ HIDWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(HIDWORD(*pqwTSFTime));
+ LODWORD(pRxPacket->qwLocalTSF) = cpu_to_le32(LODWORD(*pqwTSFTime));
+ if (bIsWEP) {
+ // strip IV
+ pbyData1 = WLAN_HDR_A3_DATA_PTR(skb->data+4);
+ pbyData2 = WLAN_HDR_A3_DATA_PTR(skb->data+4) + 4;
+ for (ii = 0; ii < (FrameSize - 4); ii++) {
+ *pbyData1 = *pbyData2;
+ pbyData1++;
+ pbyData2++;
+ }
+ }
+ pRxPacket->byRxRate = s_byGetRateIdx(*pbyRxRate);
+ pRxPacket->byRxChannel = (*pbyRxSts) >> 2;
//PLICE_DEBUG->
//EnQueue(pDevice,pRxPacket);
#ifdef THREAD
- EnQueue(pDevice,pRxPacket);
+ EnQueue(pDevice, pRxPacket);
- //printk("enque time is %x\n",jiffies);
- //up(&pDevice->mlme_semaphore);
+ //up(&pDevice->mlme_semaphore);
//Enque (pDevice->FirstRecvMngList,pDevice->LastRecvMngList,pMgmt);
#else
#ifdef TASK_LET
- EnQueue(pDevice,pRxPacket);
- tasklet_schedule(&pDevice->RxMngWorkItem);
+ EnQueue(pDevice, pRxPacket);
+ tasklet_schedule(&pDevice->RxMngWorkItem);
#else
-//printk("RxMan\n");
- vMgrRxManagePacket((void *)pDevice, pDevice->pMgmt, pRxPacket);
- //tasklet_schedule(&pDevice->RxMngWorkItem);
+ vMgrRxManagePacket((void *)pDevice, pDevice->pMgmt, pRxPacket);
+ //tasklet_schedule(&pDevice->RxMngWorkItem);
#endif
#endif
//PLICE_DEBUG<-
//vMgrRxManagePacket((void *)pDevice, pDevice->pMgmt, pRxPacket);
- // hostap Deamon handle 802.11 management
- if (pDevice->bEnableHostapd) {
- skb->dev = pDevice->apdev;
- skb->data += 4;
- skb->tail += 4;
- skb_put(skb, FrameSize);
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- return true;
- }
- }
- else {
- // Control Frame
- };
- return false;
- }
- else {
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- //In AP mode, hw only check addr1(BSSID or RA) if equal to local MAC.
- if ( !(*pbyRsr & RSR_BSSIDOK)) {
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- return false;
- }
- }
- else {
- // discard DATA packet while not associate || BSSID error
- if ((pDevice->bLinkPass == false) ||
- !(*pbyRsr & RSR_BSSIDOK)) {
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- return false;
- }
- //mike add:station mode check eapol-key challenge--->
- {
- unsigned char Protocol_Version; //802.1x Authentication
- unsigned char Packet_Type; //802.1x Authentication
- if (bIsWEP)
- cbIVOffset = 8;
- else
- cbIVOffset = 0;
- wEtherType = (skb->data[cbIVOffset + 8 + 24 + 6] << 8) |
- skb->data[cbIVOffset + 8 + 24 + 6 + 1];
- Protocol_Version = skb->data[cbIVOffset + 8 + 24 + 6 + 1 +1];
- Packet_Type = skb->data[cbIVOffset + 8 + 24 + 6 + 1 +1+1];
- if (wEtherType == ETH_P_PAE) { //Protocol Type in LLC-Header
- if(((Protocol_Version==1) ||(Protocol_Version==2)) &&
- (Packet_Type==3)) { //802.1x OR eapol-key challenge frame receive
- bRxeapol_key = true;
- }
- }
- }
- //mike add:station mode check eapol-key challenge<---
- }
- }
-
+ // hostap Deamon handle 802.11 management
+ if (pDevice->bEnableHostapd) {
+ skb->dev = pDevice->apdev;
+ skb->data += 4;
+ skb->tail += 4;
+ skb_put(skb, FrameSize);
+ skb_reset_mac_header(skb);
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ return true;
+ }
+ } else {
+ // Control Frame
+ };
+ return false;
+ } else {
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ //In AP mode, hw only check addr1(BSSID or RA) if equal to local MAC.
+ if (!(*pbyRsr & RSR_BSSIDOK)) {
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ return false;
+ }
+ } else {
+ // discard DATA packet while not associate || BSSID error
+ if ((pDevice->bLinkPass == false) ||
+ !(*pbyRsr & RSR_BSSIDOK)) {
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ return false;
+ }
+ //mike add:station mode check eapol-key challenge--->
+ {
+ unsigned char Protocol_Version; //802.1x Authentication
+ unsigned char Packet_Type; //802.1x Authentication
+ if (bIsWEP)
+ cbIVOffset = 8;
+ else
+ cbIVOffset = 0;
+ wEtherType = (skb->data[cbIVOffset + 8 + 24 + 6] << 8) |
+ skb->data[cbIVOffset + 8 + 24 + 6 + 1];
+ Protocol_Version = skb->data[cbIVOffset + 8 + 24 + 6 + 1 + 1];
+ Packet_Type = skb->data[cbIVOffset + 8 + 24 + 6 + 1 + 1 + 1];
+ if (wEtherType == ETH_P_PAE) { //Protocol Type in LLC-Header
+ if (((Protocol_Version == 1) || (Protocol_Version == 2)) &&
+ (Packet_Type == 3)) { //802.1x OR eapol-key challenge frame receive
+ bRxeapol_key = true;
+ }
+ }
+ }
+ //mike add:station mode check eapol-key challenge<---
+ }
+ }
// Data frame Handle
+ if (pDevice->bEnablePSMode) {
+ if (IS_FC_MOREDATA((skb->data+4))) {
+ if (*pbyRsr & RSR_ADDROK) {
+ //PSbSendPSPOLL((PSDevice)pDevice);
+ }
+ } else {
+ if (pDevice->pMgmt->bInTIMWake == true) {
+ pDevice->pMgmt->bInTIMWake = false;
+ }
+ }
+ }
- if (pDevice->bEnablePSMode) {
- if (IS_FC_MOREDATA((skb->data+4))) {
- if (*pbyRsr & RSR_ADDROK) {
- //PSbSendPSPOLL((PSDevice)pDevice);
- }
- }
- else {
- if (pDevice->pMgmt->bInTIMWake == true) {
- pDevice->pMgmt->bInTIMWake = false;
- }
- }
- }
-
- // Now it only supports 802.11g Infrastructure Mode, and support rate must up to 54 Mbps
- if (pDevice->bDiversityEnable && (FrameSize>50) &&
- (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
- (pDevice->bLinkPass == true)) {
- //printk("device_receive_frame: RxRate is %d\n",*pbyRxRate);
+ // Now it only supports 802.11g Infrastructure Mode, and support rate must up to 54 Mbps
+ if (pDevice->bDiversityEnable && (FrameSize > 50) &&
+ (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
+ (pDevice->bLinkPass == true)) {
BBvAntennaDiversity(pDevice, s_byGetRateIdx(*pbyRxRate), 0);
- }
-
-
- if (pDevice->byLocalID != REV_ID_VT3253_B1) {
- pDevice->uCurrRSSI = *pbyRSSI;
- }
- pDevice->byCurrSQ = *pbySQ;
-
- if ((*pbyRSSI != 0) &&
- (pMgmt->pCurrBSS!=NULL)) {
- RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
- // Monitor if RSSI is too strong.
- pMgmt->pCurrBSS->byRSSIStatCnt++;
- pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT;
- pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm;
- for(ii=0;ii<RSSI_STAT_COUNT;ii++) {
- if (pMgmt->pCurrBSS->ldBmAverage[ii] != 0) {
- pMgmt->pCurrBSS->ldBmMAX = max(pMgmt->pCurrBSS->ldBmAverage[ii], ldBm);
- }
- }
- }
-
- // -----------------------------------------------
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == true)){
- unsigned char abyMacHdr[24];
-
- // Only 802.1x packet incoming allowed
- if (bIsWEP)
- cbIVOffset = 8;
- else
- cbIVOffset = 0;
- wEtherType = (skb->data[cbIVOffset + 4 + 24 + 6] << 8) |
- skb->data[cbIVOffset + 4 + 24 + 6 + 1];
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wEtherType = %04x \n", wEtherType);
- if (wEtherType == ETH_P_PAE) {
- skb->dev = pDevice->apdev;
-
- if (bIsWEP == true) {
- // strip IV header(8)
- memcpy(&abyMacHdr[0], (skb->data + 4), 24);
- memcpy((skb->data + 4 + cbIVOffset), &abyMacHdr[0], 24);
- }
- skb->data += (cbIVOffset + 4);
- skb->tail += (cbIVOffset + 4);
- skb_put(skb, FrameSize);
- skb_reset_mac_header(skb);
-
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- return true;
+ }
-}
- // check if 802.1x authorized
- if (!(pMgmt->sNodeDBTable[iSANodeIndex].dwFlags & WLAN_STA_AUTHORIZED))
- return false;
- }
-
-
- if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
- if (bIsWEP) {
- FrameSize -= 8; //MIC
- }
- }
-
- //--------------------------------------------------------------------------------
- // Soft MIC
- if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
- if (bIsWEP) {
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
- unsigned long dwMIC_Priority;
- unsigned long dwMICKey0 = 0, dwMICKey1 = 0;
- unsigned long dwLocalMIC_L = 0;
- unsigned long dwLocalMIC_R = 0;
- viawget_wpa_header *wpahdr;
-
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
- }
- else {
- if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
- } else if ((pKey->dwKeyIndex & BIT28) == 0) {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
- } else {
- dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
- }
- }
-
- MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((unsigned char *)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12);
- dwMIC_Priority = 0;
- MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
- // 4 is Rcv buffer header, 24 is MAC Header, and 8 is IV and Ext IV.
- MIC_vAppend((unsigned char *)(skb->data + 4 + WLAN_HDR_ADDR3_LEN + 8),
- FrameSize - WLAN_HDR_ADDR3_LEN - 8);
- MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R);
- MIC_vUnInit();
-
- pdwMIC_L = (unsigned long *)(skb->data + 4 + FrameSize);
- pdwMIC_R = (unsigned long *)(skb->data + 4 + FrameSize + 4);
- //DBG_PRN_GRP12(("RxL: %lx, RxR: %lx\n", *pdwMIC_L, *pdwMIC_R));
- //DBG_PRN_GRP12(("LocalL: %lx, LocalR: %lx\n", dwLocalMIC_L, dwLocalMIC_R));
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwMICKey0= %lx,dwMICKey1= %lx \n", dwMICKey0, dwMICKey1);
-
-
- if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) || (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) ||
- (pDevice->bRxMICFail == true)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC comparison is fail!\n");
- pDevice->bRxMICFail = false;
- //pDevice->s802_11Counter.TKIPLocalMICFailures.QuadPart++;
- pDevice->s802_11Counter.TKIPLocalMICFailures++;
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- //2008-0409-07, <Add> by Einsn Liu
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ if (pDevice->byLocalID != REV_ID_VT3253_B1) {
+ pDevice->uCurrRSSI = *pbyRSSI;
+ }
+ pDevice->byCurrSQ = *pbySQ;
+
+ if ((*pbyRSSI != 0) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm);
+ // Monitor if RSSI is too strong.
+ pMgmt->pCurrBSS->byRSSIStatCnt++;
+ pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT;
+ pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm;
+ for (ii = 0; ii < RSSI_STAT_COUNT; ii++) {
+ if (pMgmt->pCurrBSS->ldBmAverage[ii] != 0) {
+ pMgmt->pCurrBSS->ldBmMAX = max(pMgmt->pCurrBSS->ldBmAverage[ii], ldBm);
+ }
+ }
+ }
+
+ // -----------------------------------------------
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == true)) {
+ unsigned char abyMacHdr[24];
+
+ // Only 802.1x packet incoming allowed
+ if (bIsWEP)
+ cbIVOffset = 8;
+ else
+ cbIVOffset = 0;
+ wEtherType = (skb->data[cbIVOffset + 4 + 24 + 6] << 8) |
+ skb->data[cbIVOffset + 4 + 24 + 6 + 1];
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wEtherType = %04x \n", wEtherType);
+ if (wEtherType == ETH_P_PAE) {
+ skb->dev = pDevice->apdev;
+
+ if (bIsWEP == true) {
+ // strip IV header(8)
+ memcpy(&abyMacHdr[0], (skb->data + 4), 24);
+ memcpy((skb->data + 4 + cbIVOffset), &abyMacHdr[0], 24);
+ }
+ skb->data += (cbIVOffset + 4);
+ skb->tail += (cbIVOffset + 4);
+ skb_put(skb, FrameSize);
+ skb_reset_mac_header(skb);
+
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ return true;
+
+ }
+ // check if 802.1x authorized
+ if (!(pMgmt->sNodeDBTable[iSANodeIndex].dwFlags & WLAN_STA_AUTHORIZED))
+ return false;
+ }
+
+ if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if (bIsWEP) {
+ FrameSize -= 8; //MIC
+ }
+ }
+
+ //--------------------------------------------------------------------------------
+ // Soft MIC
+ if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if (bIsWEP) {
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned long dwMIC_Priority;
+ unsigned long dwMICKey0 = 0, dwMICKey1 = 0;
+ unsigned long dwLocalMIC_L = 0;
+ unsigned long dwLocalMIC_R = 0;
+ viawget_wpa_header *wpahdr;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
+ } else {
+ if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
+ } else if ((pKey->dwKeyIndex & BIT28) == 0) {
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[20]));
+ } else {
+ dwMICKey0 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(unsigned long *)(&pKey->abyKey[28]));
+ }
+ }
+
+ MIC_vInit(dwMICKey0, dwMICKey1);
+ MIC_vAppend((unsigned char *)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12);
+ dwMIC_Priority = 0;
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
+ // 4 is Rcv buffer header, 24 is MAC Header, and 8 is IV and Ext IV.
+ MIC_vAppend((unsigned char *)(skb->data + 4 + WLAN_HDR_ADDR3_LEN + 8),
+ FrameSize - WLAN_HDR_ADDR3_LEN - 8);
+ MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R);
+ MIC_vUnInit();
+
+ pdwMIC_L = (unsigned long *)(skb->data + 4 + FrameSize);
+ pdwMIC_R = (unsigned long *)(skb->data + 4 + FrameSize + 4);
+ //DBG_PRN_GRP12(("RxL: %lx, RxR: %lx\n", *pdwMIC_L, *pdwMIC_R));
+ //DBG_PRN_GRP12(("LocalL: %lx, LocalR: %lx\n", dwLocalMIC_L, dwLocalMIC_R));
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwMICKey0= %lx,dwMICKey1= %lx \n", dwMICKey0, dwMICKey1);
+
+ if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) || (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) ||
+ (pDevice->bRxMICFail == true)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC comparison is fail!\n");
+ pDevice->bRxMICFail = false;
+ //pDevice->s802_11Counter.TKIPLocalMICFailures.QuadPart++;
+ pDevice->s802_11Counter.TKIPLocalMICFailures++;
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ //2008-0409-07, <Add> by Einsn Liu
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//send event to wpa_supplicant
- //if(pDevice->bWPADevEnable == true)
{
union iwreq_data wrqu;
struct iw_michaelmicfailure ev;
@@ -845,8 +791,8 @@ device_receive_frame (
memset(&ev, 0, sizeof(ev));
ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pMgmt->eCurrState == WMAC_STATE_ASSOC) &&
- (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) {
+ (pMgmt->eCurrState == WMAC_STATE_ASSOC) &&
+ (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) {
ev.flags |= IW_MICFAILURE_PAIRWISE;
} else {
ev.flags |= IW_MICFAILURE_GROUP;
@@ -859,633 +805,596 @@ device_receive_frame (
wireless_send_event(pDevice->dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
}
- #endif
-
-
- if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC) &&
- (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) {
- //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR;
- wpahdr->type = VIAWGET_PTK_MIC_MSG;
- } else {
- //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_GROUP_ERROR;
- wpahdr->type = VIAWGET_GTK_MIC_MSG;
- }
- wpahdr->resp_ie_len = 0;
- wpahdr->req_ie_len = 0;
- skb_put(pDevice->skb, sizeof(viawget_wpa_header));
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
-
- return false;
-
- }
- }
- } //---end of SOFT MIC-----------------------------------------------------------------------
-
- // ++++++++++ Reply Counter Check +++++++++++++
-
- if ((pKey != NULL) && ((pKey->byCipherSuite == KEY_CTL_TKIP) ||
- (pKey->byCipherSuite == KEY_CTL_CCMP))) {
- if (bIsWEP) {
- unsigned short wLocalTSC15_0 = 0;
- unsigned long dwLocalTSC47_16 = 0;
- unsigned long long RSC = 0;
- // endian issues
- RSC = *((unsigned long long *) &(pKey->KeyRSC));
- wLocalTSC15_0 = (unsigned short) RSC;
- dwLocalTSC47_16 = (unsigned long) (RSC>>16);
-
- RSC = dwRxTSC47_16;
- RSC <<= 16;
- RSC += wRxTSC15_0;
- memcpy(&(pKey->KeyRSC), &RSC, sizeof(QWORD));
-
- if ( (pDevice->sMgmtObj.eCurrMode == WMAC_MODE_ESS_STA) &&
- (pDevice->sMgmtObj.eCurrState == WMAC_STATE_ASSOC)) {
- // check RSC
- if ( (wRxTSC15_0 < wLocalTSC15_0) &&
- (dwRxTSC47_16 <= dwLocalTSC47_16) &&
- !((dwRxTSC47_16 == 0) && (dwLocalTSC47_16 == 0xFFFFFFFF))) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC is illegal~~!\n ");
- if (pKey->byCipherSuite == KEY_CTL_TKIP)
- //pDevice->s802_11Counter.TKIPReplays.QuadPart++;
- pDevice->s802_11Counter.TKIPReplays++;
- else
- //pDevice->s802_11Counter.CCMPReplays.QuadPart++;
- pDevice->s802_11Counter.CCMPReplays++;
-
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- return false;
- }
- }
- }
- } // ----- End of Reply Counter Check --------------------------
-
-
-
- if ((pKey != NULL) && (bIsWEP)) {
+#endif
+
+ if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ if ((pDevice->pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pDevice->pMgmt->eCurrState == WMAC_STATE_ASSOC) &&
+ (*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) {
+ //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR;
+ wpahdr->type = VIAWGET_PTK_MIC_MSG;
+ } else {
+ //s802_11_Status.Flags = NDIS_802_11_AUTH_REQUEST_GROUP_ERROR;
+ wpahdr->type = VIAWGET_GTK_MIC_MSG;
+ }
+ wpahdr->resp_ie_len = 0;
+ wpahdr->req_ie_len = 0;
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header));
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
+
+ return false;
+
+ }
+ }
+ } //---end of SOFT MIC-----------------------------------------------------------------------
+
+ // ++++++++++ Reply Counter Check +++++++++++++
+
+ if ((pKey != NULL) && ((pKey->byCipherSuite == KEY_CTL_TKIP) ||
+ (pKey->byCipherSuite == KEY_CTL_CCMP))) {
+ if (bIsWEP) {
+ unsigned short wLocalTSC15_0 = 0;
+ unsigned long dwLocalTSC47_16 = 0;
+ unsigned long long RSC = 0;
+ // endian issues
+ RSC = *((unsigned long long *)&(pKey->KeyRSC));
+ wLocalTSC15_0 = (unsigned short)RSC;
+ dwLocalTSC47_16 = (unsigned long)(RSC>>16);
+
+ RSC = dwRxTSC47_16;
+ RSC <<= 16;
+ RSC += wRxTSC15_0;
+ memcpy(&(pKey->KeyRSC), &RSC, sizeof(QWORD));
+
+ if ((pDevice->sMgmtObj.eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pDevice->sMgmtObj.eCurrState == WMAC_STATE_ASSOC)) {
+ // check RSC
+ if ((wRxTSC15_0 < wLocalTSC15_0) &&
+ (dwRxTSC47_16 <= dwLocalTSC47_16) &&
+ !((dwRxTSC47_16 == 0) && (dwLocalTSC47_16 == 0xFFFFFFFF))) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "TSC is illegal~~!\n ");
+ if (pKey->byCipherSuite == KEY_CTL_TKIP)
+ //pDevice->s802_11Counter.TKIPReplays.QuadPart++;
+ pDevice->s802_11Counter.TKIPReplays++;
+ else
+ //pDevice->s802_11Counter.CCMPReplays.QuadPart++;
+ pDevice->s802_11Counter.CCMPReplays++;
+
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ return false;
+ }
+ }
+ }
+ } // ----- End of Reply Counter Check --------------------------
+
+ if ((pKey != NULL) && (bIsWEP)) {
// pDevice->s802_11Counter.DecryptSuccessCount.QuadPart++;
- }
-
-
- s_vProcessRxMACHeader(pDevice, (unsigned char *)(skb->data+4), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
- FrameSize -= cbHeaderOffset;
- cbHeaderOffset += 4; // 4 is Rcv buffer header
-
- // Null data, framesize = 14
- if (FrameSize < 15)
- return false;
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (s_bAPModeRxData(pDevice,
- skb,
- FrameSize,
- cbHeaderOffset,
- iSANodeIndex,
- iDANodeIndex
- ) == false) {
-
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- return false;
- }
-
-// if(pDevice->bRxMICFail == false) {
-// for (ii =0; ii < 100; ii++)
-// printk(" %02x", *(skb->data + ii));
-// printk("\n");
-// }
-
- }
+ }
+
+ s_vProcessRxMACHeader(pDevice, (unsigned char *)(skb->data+4), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
+ FrameSize -= cbHeaderOffset;
+ cbHeaderOffset += 4; // 4 is Rcv buffer header
+
+ // Null data, framesize = 14
+ if (FrameSize < 15)
+ return false;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (s_bAPModeRxData(pDevice,
+ skb,
+ FrameSize,
+ cbHeaderOffset,
+ iSANodeIndex,
+ iDANodeIndex
+) == false) {
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ return false;
+ }
+ }
skb->data += cbHeaderOffset;
skb->tail += cbHeaderOffset;
- skb_put(skb, FrameSize);
- skb->protocol=eth_type_trans(skb, skb->dev);
-
+ skb_put(skb, FrameSize);
+ skb->protocol = eth_type_trans(skb, skb->dev);
//drop frame not met IEEE 802.3
/*
- if (pDevice->flags & DEVICE_FLAGS_VAL_PKT_LEN) {
- if ((skb->protocol==htons(ETH_P_802_3)) &&
- (skb->len!=htons(skb->mac.ethernet->h_proto))) {
- pStats->rx_length_errors++;
- pStats->rx_dropped++;
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- }
- return false;
- }
- }
+ if (pDevice->flags & DEVICE_FLAGS_VAL_PKT_LEN) {
+ if ((skb->protocol==htons(ETH_P_802_3)) &&
+ (skb->len!=htons(skb->mac.ethernet->h_proto))) {
+ pStats->rx_length_errors++;
+ pStats->rx_dropped++;
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ }
+ return false;
+ }
+ }
*/
- skb->ip_summed=CHECKSUM_NONE;
- pStats->rx_bytes +=skb->len;
- pStats->rx_packets++;
- netif_rx(skb);
+ skb->ip_summed = CHECKSUM_NONE;
+ pStats->rx_bytes += skb->len;
+ pStats->rx_packets++;
+ netif_rx(skb);
- if (bDeFragRx) {
- if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
- DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s: can not alloc more frag bufs\n",
- pDevice->dev->name);
- }
- return false;
- }
+ if (bDeFragRx) {
+ if (!device_alloc_frag_buf(pDevice, &pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx])) {
+ DBG_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not alloc more frag bufs\n",
+ pDevice->dev->name);
+ }
+ return false;
+ }
- return true;
+ return true;
}
-
-static bool s_bAPModeRxCtl (
- PSDevice pDevice,
- unsigned char *pbyFrame,
- int iSANodeIndex
- )
+static bool s_bAPModeRxCtl(
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ int iSANodeIndex
+)
{
- PS802_11Header p802_11Header;
- CMD_STATUS Status;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
-
- p802_11Header = (PS802_11Header) (pbyFrame);
- if (!IS_TYPE_MGMT(pbyFrame)) {
-
- // Data & PS-Poll packet
- // check frame class
- if (iSANodeIndex > 0) {
- // frame class 3 fliter & checking
- if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_AUTH) {
- // send deauth notification
- // reason = (6) class 2 received from nonauth sta
- vMgrDeAuthenBeginSta(pDevice,
- pMgmt,
- (unsigned char *)(p802_11Header->abyAddr2),
- (WLAN_MGMT_REASON_CLASS2_NONAUTH),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 1\n");
- return true;
- }
- if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_ASSOC) {
- // send deassoc notification
- // reason = (7) class 3 received from nonassoc sta
- vMgrDisassocBeginSta(pDevice,
- pMgmt,
- (unsigned char *)(p802_11Header->abyAddr2),
- (WLAN_MGMT_REASON_CLASS3_NONASSOC),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDisassocBeginSta 2\n");
- return true;
- }
-
- if (pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable) {
- // delcare received ps-poll event
- if (IS_CTL_PSPOLL(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
- bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 1\n");
- }
- else {
- // check Data PS state
- // if PW bit off, send out all PS bufferring packets.
- if (!IS_FC_POWERMGT(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
- bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 2\n");
- }
- }
- }
- else {
- if (IS_FC_POWERMGT(pbyFrame)) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = true;
- // Once if STA in PS state, enable multicast bufferring
- pMgmt->sNodeDBTable[0].bPSEnable = true;
- }
- else {
- // clear all pending PS frame.
- if (pMgmt->sNodeDBTable[iSANodeIndex].wEnQueueCnt > 0) {
- pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
- pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
- bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 3\n");
-
- }
- }
- }
- }
- else {
- vMgrDeAuthenBeginSta(pDevice,
- pMgmt,
- (unsigned char *)(p802_11Header->abyAddr2),
- (WLAN_MGMT_REASON_CLASS2_NONAUTH),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 3\n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSID:%pM\n",
- p802_11Header->abyAddr3);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR2:%pM\n",
- p802_11Header->abyAddr2);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR1:%pM\n",
- p802_11Header->abyAddr1);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: wFrameCtl= %x\n", p802_11Header->wFrameCtl );
- VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc:pDevice->byRxMode = %x\n", pDevice->byRxMode );
- return true;
- }
- }
- }
- return false;
+ PS802_11Header p802_11Header;
+ CMD_STATUS Status;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
+ p802_11Header = (PS802_11Header)(pbyFrame);
+ if (!IS_TYPE_MGMT(pbyFrame)) {
+ // Data & PS-Poll packet
+ // check frame class
+ if (iSANodeIndex > 0) {
+ // frame class 3 fliter & checking
+ if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_AUTH) {
+ // send deauth notification
+ // reason = (6) class 2 received from nonauth sta
+ vMgrDeAuthenBeginSta(pDevice,
+ pMgmt,
+ (unsigned char *)(p802_11Header->abyAddr2),
+ (WLAN_MGMT_REASON_CLASS2_NONAUTH),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 1\n");
+ return true;
+ }
+ if (pMgmt->sNodeDBTable[iSANodeIndex].eNodeState < NODE_ASSOC) {
+ // send deassoc notification
+ // reason = (7) class 3 received from nonassoc sta
+ vMgrDisassocBeginSta(pDevice,
+ pMgmt,
+ (unsigned char *)(p802_11Header->abyAddr2),
+ (WLAN_MGMT_REASON_CLASS3_NONASSOC),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDisassocBeginSta 2\n");
+ return true;
+ }
+ if (pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable) {
+ // delcare received ps-poll event
+ if (IS_CTL_PSPOLL(pbyFrame)) {
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 1\n");
+ } else {
+ // check Data PS state
+ // if PW bit off, send out all PS bufferring packets.
+ if (!IS_FC_POWERMGT(pbyFrame)) {
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 2\n");
+ }
+ }
+ } else {
+ if (IS_FC_POWERMGT(pbyFrame)) {
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = true;
+ // Once if STA in PS state, enable multicast bufferring
+ pMgmt->sNodeDBTable[0].bPSEnable = true;
+ } else {
+ // clear all pending PS frame.
+ if (pMgmt->sNodeDBTable[iSANodeIndex].wEnQueueCnt > 0) {
+ pMgmt->sNodeDBTable[iSANodeIndex].bPSEnable = false;
+ pMgmt->sNodeDBTable[iSANodeIndex].bRxPSPoll = true;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_RX_PSPOLL, NULL);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: WLAN_CMD_RX_PSPOLL 3\n");
+
+ }
+ }
+ }
+ } else {
+ vMgrDeAuthenBeginSta(pDevice,
+ pMgmt,
+ (unsigned char *)(p802_11Header->abyAddr2),
+ (WLAN_MGMT_REASON_CLASS2_NONAUTH),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 3\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSID:%pM\n",
+ p802_11Header->abyAddr3);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR2:%pM\n",
+ p802_11Header->abyAddr2);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR1:%pM\n",
+ p802_11Header->abyAddr1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: wFrameCtl= %x\n", p802_11Header->wFrameCtl);
+ VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc:pDevice->byRxMode = %x\n", pDevice->byRxMode);
+ return true;
+ }
+ }
+ }
+ return false;
}
-static bool s_bHandleRxEncryption (
- PSDevice pDevice,
- unsigned char *pbyFrame,
- unsigned int FrameSize,
- unsigned char *pbyRsr,
- unsigned char *pbyNewRsr,
- PSKeyItem *pKeyOut,
- bool *pbExtIV,
- unsigned short *pwRxTSC15_0,
- unsigned long *pdwRxTSC47_16
- )
+static bool s_bHandleRxEncryption(
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ unsigned char *pbyNewRsr,
+ PSKeyItem *pKeyOut,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
+)
{
- unsigned int PayloadLen = FrameSize;
- unsigned char *pbyIV;
- unsigned char byKeyIdx;
- PSKeyItem pKey = NULL;
- unsigned char byDecMode = KEY_CTL_WEP;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- *pwRxTSC15_0 = 0;
- *pdwRxTSC47_16 = 0;
-
- pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
- pbyIV += 6; // 6 is 802.11 address4
- PayloadLen -= 6;
- }
- byKeyIdx = (*(pbyIV+3) & 0xc0);
- byKeyIdx >>= 6;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\nKeyIdx: %d\n", byKeyIdx);
-
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
- if (((*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) &&
- (pDevice->pMgmt->byCSSPK != KEY_CTL_NONE)) {
- // unicast pkt use pairwise key
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"unicast pkt\n");
- if (KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, 0xFFFFFFFF, &pKey) == true) {
- if (pDevice->pMgmt->byCSSPK == KEY_CTL_TKIP)
- byDecMode = KEY_CTL_TKIP;
- else if (pDevice->pMgmt->byCSSPK == KEY_CTL_CCMP)
- byDecMode = KEY_CTL_CCMP;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"unicast pkt: %d, %p\n", byDecMode, pKey);
- } else {
- // use group key
- KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, byKeyIdx, &pKey);
- if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
- byDecMode = KEY_CTL_TKIP;
- else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
- byDecMode = KEY_CTL_CCMP;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"group pkt: %d, %d, %p\n", byKeyIdx, byDecMode, pKey);
- }
- }
- // our WEP only support Default Key
- if (pKey == NULL) {
- // use default group key
- KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, byKeyIdx, &pKey);
- if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
- byDecMode = KEY_CTL_TKIP;
- else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
- byDecMode = KEY_CTL_CCMP;
- }
- *pKeyOut = pKey;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode);
-
- if (pKey == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey == NULL\n");
- if (byDecMode == KEY_CTL_WEP) {
+ unsigned int PayloadLen = FrameSize;
+ unsigned char *pbyIV;
+ unsigned char byKeyIdx;
+ PSKeyItem pKey = NULL;
+ unsigned char byDecMode = KEY_CTL_WEP;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ *pwRxTSC15_0 = 0;
+ *pdwRxTSC47_16 = 0;
+
+ pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
+ if (WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame)) {
+ pbyIV += 6; // 6 is 802.11 address4
+ PayloadLen -= 6;
+ }
+ byKeyIdx = (*(pbyIV+3) & 0xc0);
+ byKeyIdx >>= 6;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\nKeyIdx: %d\n", byKeyIdx);
+
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) {
+ if (((*pbyRsr & (RSR_ADDRBROAD | RSR_ADDRMULTI)) == 0) &&
+ (pDevice->pMgmt->byCSSPK != KEY_CTL_NONE)) {
+ // unicast pkt use pairwise key
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "unicast pkt\n");
+ if (KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, 0xFFFFFFFF, &pKey) == true) {
+ if (pDevice->pMgmt->byCSSPK == KEY_CTL_TKIP)
+ byDecMode = KEY_CTL_TKIP;
+ else if (pDevice->pMgmt->byCSSPK == KEY_CTL_CCMP)
+ byDecMode = KEY_CTL_CCMP;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "unicast pkt: %d, %p\n", byDecMode, pKey);
+ } else {
+ // use group key
+ KeybGetKey(&(pDevice->sKey), pDevice->abyBSSID, byKeyIdx, &pKey);
+ if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
+ byDecMode = KEY_CTL_TKIP;
+ else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
+ byDecMode = KEY_CTL_CCMP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group pkt: %d, %d, %p\n", byKeyIdx, byDecMode, pKey);
+ }
+ }
+ // our WEP only support Default Key
+ if (pKey == NULL) {
+ // use default group key
+ KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, byKeyIdx, &pKey);
+ if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
+ byDecMode = KEY_CTL_TKIP;
+ else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
+ byDecMode = KEY_CTL_CCMP;
+ }
+ *pKeyOut = pKey;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode);
+
+ if (pKey == NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey == NULL\n");
+ if (byDecMode == KEY_CTL_WEP) {
// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == true) {
+ } else if (pDevice->bLinkPass == true) {
// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
- }
- return false;
- }
- if (byDecMode != pKey->byCipherSuite) {
- if (byDecMode == KEY_CTL_WEP) {
+ }
+ return false;
+ }
+ if (byDecMode != pKey->byCipherSuite) {
+ if (byDecMode == KEY_CTL_WEP) {
// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == true) {
+ } else if (pDevice->bLinkPass == true) {
// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
- }
- *pKeyOut = NULL;
- return false;
- }
- if (byDecMode == KEY_CTL_WEP) {
- // handle WEP
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
- (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true)) {
- // Software WEP
- // 1. 3253A
- // 2. WEP 256
-
- PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc
- memcpy(pDevice->abyPRNG, pbyIV, 3);
- memcpy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength);
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3);
- rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen);
-
- if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) {
- *pbyNewRsr |= NEWRSR_DECRYPTOK;
- }
- }
- } else if ((byDecMode == KEY_CTL_TKIP) ||
- (byDecMode == KEY_CTL_CCMP)) {
- // TKIP/AES
-
- PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16);
- if (byDecMode == KEY_CTL_TKIP) {
- *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
- } else {
- *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
-
- if ((byDecMode == KEY_CTL_TKIP) &&
- (pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- // Software TKIP
- // 1. 3253 A
- PS802_11Header pMACHeader = (PS802_11Header) (pbyFrame);
- TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
- rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
- if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
- *pbyNewRsr |= NEWRSR_DECRYPTOK;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV OK!\n");
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV FAIL!!!\n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PayloadLen = %d\n", PayloadLen);
- }
- }
- }// end of TKIP/AES
-
- if ((*(pbyIV+3) & 0x20) != 0)
- *pbExtIV = true;
- return true;
-}
+ }
+ *pKeyOut = NULL;
+ return false;
+ }
+ if (byDecMode == KEY_CTL_WEP) {
+ // handle WEP
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
+ (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true)) {
+ // Software WEP
+ // 1. 3253A
+ // 2. WEP 256
+
+ PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc
+ memcpy(pDevice->abyPRNG, pbyIV, 3);
+ memcpy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength);
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3);
+ rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen);
+
+ if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) {
+ *pbyNewRsr |= NEWRSR_DECRYPTOK;
+ }
+ }
+ } else if ((byDecMode == KEY_CTL_TKIP) ||
+ (byDecMode == KEY_CTL_CCMP)) {
+ // TKIP/AES
+
+ PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
+ *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ExtIV: %lx\n", *pdwRxTSC47_16);
+ if (byDecMode == KEY_CTL_TKIP) {
+ *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV + 2), *pbyIV));
+ } else {
+ *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "TSC0_15: %x\n", *pwRxTSC15_0);
+
+ if ((byDecMode == KEY_CTL_TKIP) &&
+ (pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ // Software TKIP
+ // 1. 3253 A
+ PS802_11Header pMACHeader = (PS802_11Header)(pbyFrame);
+ TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
+ rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
+ if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
+ *pbyNewRsr |= NEWRSR_DECRYPTOK;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ICV OK!\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ICV FAIL!!!\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PayloadLen = %d\n", PayloadLen);
+ }
+ }
+ }// end of TKIP/AES
+ if ((*(pbyIV+3) & 0x20) != 0)
+ *pbExtIV = true;
+ return true;
+}
-static bool s_bHostWepRxEncryption (
- PSDevice pDevice,
- unsigned char *pbyFrame,
- unsigned int FrameSize,
- unsigned char *pbyRsr,
- bool bOnFly,
- PSKeyItem pKey,
- unsigned char *pbyNewRsr,
- bool *pbExtIV,
- unsigned short *pwRxTSC15_0,
- unsigned long *pdwRxTSC47_16
- )
+static bool s_bHostWepRxEncryption(
+ PSDevice pDevice,
+ unsigned char *pbyFrame,
+ unsigned int FrameSize,
+ unsigned char *pbyRsr,
+ bool bOnFly,
+ PSKeyItem pKey,
+ unsigned char *pbyNewRsr,
+ bool *pbExtIV,
+ unsigned short *pwRxTSC15_0,
+ unsigned long *pdwRxTSC47_16
+)
{
- unsigned int PayloadLen = FrameSize;
- unsigned char *pbyIV;
- unsigned char byKeyIdx;
- unsigned char byDecMode = KEY_CTL_WEP;
- PS802_11Header pMACHeader;
-
+ unsigned int PayloadLen = FrameSize;
+ unsigned char *pbyIV;
+ unsigned char byKeyIdx;
+ unsigned char byDecMode = KEY_CTL_WEP;
+ PS802_11Header pMACHeader;
+
+ *pwRxTSC15_0 = 0;
+ *pdwRxTSC47_16 = 0;
+
+ pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
+ if (WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame)) {
+ pbyIV += 6; // 6 is 802.11 address4
+ PayloadLen -= 6;
+ }
+ byKeyIdx = (*(pbyIV+3) & 0xc0);
+ byKeyIdx >>= 6;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\nKeyIdx: %d\n", byKeyIdx);
+ if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
+ byDecMode = KEY_CTL_TKIP;
+ else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
+ byDecMode = KEY_CTL_CCMP;
- *pwRxTSC15_0 = 0;
- *pdwRxTSC47_16 = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode);
- pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(unsigned short *)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(unsigned short *)pbyFrame) ) {
- pbyIV += 6; // 6 is 802.11 address4
- PayloadLen -= 6;
- }
- byKeyIdx = (*(pbyIV+3) & 0xc0);
- byKeyIdx >>= 6;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\nKeyIdx: %d\n", byKeyIdx);
+ if (byDecMode != pKey->byCipherSuite) {
+ if (byDecMode == KEY_CTL_WEP) {
+// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
+ } else if (pDevice->bLinkPass == true) {
+// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
+ }
+ return false;
+ }
+ if (byDecMode == KEY_CTL_WEP) {
+ // handle WEP
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "byDecMode == KEY_CTL_WEP \n");
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
+ (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true) ||
+ (bOnFly == false)) {
+ // Software WEP
+ // 1. 3253A
+ // 2. WEP 256
+ // 3. NotOnFly
+
+ PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc
+ memcpy(pDevice->abyPRNG, pbyIV, 3);
+ memcpy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength);
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3);
+ rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen);
+
+ if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) {
+ *pbyNewRsr |= NEWRSR_DECRYPTOK;
+ }
+ }
+ } else if ((byDecMode == KEY_CTL_TKIP) ||
+ (byDecMode == KEY_CTL_CCMP)) {
+ // TKIP/AES
+
+ PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
+ *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ExtIV: %lx\n", *pdwRxTSC47_16);
+
+ if (byDecMode == KEY_CTL_TKIP) {
+ *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
+ } else {
+ *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "TSC0_15: %x\n", *pwRxTSC15_0);
+
+ if (byDecMode == KEY_CTL_TKIP) {
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || (bOnFly == false)) {
+ // Software TKIP
+ // 1. 3253 A
+ // 2. NotOnFly
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "soft KEY_CTL_TKIP \n");
+ pMACHeader = (PS802_11Header)(pbyFrame);
+ TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
+ rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
+ if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
+ *pbyNewRsr |= NEWRSR_DECRYPTOK;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ICV OK!\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ICV FAIL!!!\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PayloadLen = %d\n", PayloadLen);
+ }
+ }
+ }
- if (pDevice->pMgmt->byCSSGK == KEY_CTL_TKIP)
- byDecMode = KEY_CTL_TKIP;
- else if (pDevice->pMgmt->byCSSGK == KEY_CTL_CCMP)
- byDecMode = KEY_CTL_CCMP;
+ if (byDecMode == KEY_CTL_CCMP) {
+ if (bOnFly == false) {
+ // Software CCMP
+ // NotOnFly
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "soft KEY_CTL_CCMP\n");
+ if (AESbGenCCMP(pKey->abyKey, pbyFrame, FrameSize)) {
+ *pbyNewRsr |= NEWRSR_DECRYPTOK;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CCMP MIC compare OK!\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "CCMP MIC fail!\n");
+ }
+ }
+ }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"AES:%d %d %d\n", pDevice->pMgmt->byCSSPK, pDevice->pMgmt->byCSSGK, byDecMode);
+ }// end of TKIP/AES
- if (byDecMode != pKey->byCipherSuite) {
- if (byDecMode == KEY_CTL_WEP) {
-// pDevice->s802_11Counter.WEPUndecryptableCount.QuadPart++;
- } else if (pDevice->bLinkPass == true) {
-// pDevice->s802_11Counter.DecryptFailureCount.QuadPart++;
- }
- return false;
- }
-
- if (byDecMode == KEY_CTL_WEP) {
- // handle WEP
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"byDecMode == KEY_CTL_WEP \n");
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1) ||
- (((PSKeyTable)(pKey->pvKeyTable))->bSoftWEP == true) ||
- (bOnFly == false)) {
- // Software WEP
- // 1. 3253A
- // 2. WEP 256
- // 3. NotOnFly
-
- PayloadLen -= (WLAN_HDR_ADDR3_LEN + 4 + 4); // 24 is 802.11 header,4 is IV, 4 is crc
- memcpy(pDevice->abyPRNG, pbyIV, 3);
- memcpy(pDevice->abyPRNG + 3, pKey->abyKey, pKey->uKeyLength);
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, pKey->uKeyLength + 3);
- rc4_encrypt(&pDevice->SBox, pbyIV+4, pbyIV+4, PayloadLen);
-
- if (ETHbIsBufferCrc32Ok(pbyIV+4, PayloadLen)) {
- *pbyNewRsr |= NEWRSR_DECRYPTOK;
- }
- }
- } else if ((byDecMode == KEY_CTL_TKIP) ||
- (byDecMode == KEY_CTL_CCMP)) {
- // TKIP/AES
-
- PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(unsigned long *)(pbyIV + 4));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %lx\n",*pdwRxTSC47_16);
-
- if (byDecMode == KEY_CTL_TKIP) {
- *pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
- } else {
- *pwRxTSC15_0 = cpu_to_le16(*(unsigned short *)pbyIV);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
-
- if (byDecMode == KEY_CTL_TKIP) {
-
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1) || (bOnFly == false)) {
- // Software TKIP
- // 1. 3253 A
- // 2. NotOnFly
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_TKIP \n");
- pMACHeader = (PS802_11Header) (pbyFrame);
- TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
- rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
- if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
- *pbyNewRsr |= NEWRSR_DECRYPTOK;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV OK!\n");
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ICV FAIL!!!\n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PayloadLen = %d\n", PayloadLen);
- }
- }
- }
-
- if (byDecMode == KEY_CTL_CCMP) {
- if (bOnFly == false) {
- // Software CCMP
- // NotOnFly
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_CCMP\n");
- if (AESbGenCCMP(pKey->abyKey, pbyFrame, FrameSize)) {
- *pbyNewRsr |= NEWRSR_DECRYPTOK;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CCMP MIC compare OK!\n");
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"CCMP MIC fail!\n");
- }
- }
- }
-
- }// end of TKIP/AES
-
- if ((*(pbyIV+3) & 0x20) != 0)
- *pbExtIV = true;
- return true;
+ if ((*(pbyIV+3) & 0x20) != 0)
+ *pbExtIV = true;
+ return true;
}
+static bool s_bAPModeRxData(
+ PSDevice pDevice,
+ struct sk_buff *skb,
+ unsigned int FrameSize,
+ unsigned int cbHeaderOffset,
+ int iSANodeIndex,
+ int iDANodeIndex
+)
+{
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ bool bRelayAndForward = false;
+ bool bRelayOnly = false;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned short wAID;
+
+ struct sk_buff *skbcpy = NULL;
+
+ if (FrameSize > CB_MAX_BUF_SIZE)
+ return false;
+ // check DA
+ if (is_multicast_ether_addr((unsigned char *)(skb->data+cbHeaderOffset))) {
+ if (pMgmt->sNodeDBTable[0].bPSEnable) {
+ skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
+
+ // if any node in PS mode, buffer packet until DTIM.
+ if (skbcpy == NULL) {
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "relay multicast no skb available \n");
+ } else {
+ skbcpy->dev = pDevice->dev;
+ skbcpy->len = FrameSize;
+ memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize);
+ skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy);
+
+ pMgmt->sNodeDBTable[0].wEnQueueCnt++;
+ // set tx map
+ pMgmt->abyPSTxMap[0] |= byMask[0];
+ }
+ } else {
+ bRelayAndForward = true;
+ }
+ } else {
+ // check if relay
+ if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
+ if (pMgmt->sNodeDBTable[iDANodeIndex].eNodeState >= NODE_ASSOC) {
+ if (pMgmt->sNodeDBTable[iDANodeIndex].bPSEnable) {
+ // queue this skb until next PS tx, and then release.
+
+ skb->data += cbHeaderOffset;
+ skb->tail += cbHeaderOffset;
+ skb_put(skb, FrameSize);
+ skb_queue_tail(&pMgmt->sNodeDBTable[iDANodeIndex].sTxPSQueue, skb);
+ pMgmt->sNodeDBTable[iDANodeIndex].wEnQueueCnt++;
+ wAID = pMgmt->sNodeDBTable[iDANodeIndex].wAID;
+ pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "relay: index= %d, pMgmt->abyPSTxMap[%d]= %d\n",
+ iDANodeIndex, (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]);
+ return true;
+ } else {
+ bRelayOnly = true;
+ }
+ }
+ }
+ }
+
+ if (bRelayOnly || bRelayAndForward) {
+ // relay this packet right now
+ if (bRelayAndForward)
+ iDANodeIndex = 0;
+
+ if ((pDevice->uAssocCount > 1) && (iDANodeIndex >= 0)) {
+ ROUTEbRelay(pDevice, (unsigned char *)(skb->data + cbHeaderOffset), FrameSize, (unsigned int)iDANodeIndex);
+ }
+ if (bRelayOnly)
+ return false;
+ }
+ // none associate, don't forward
+ if (pDevice->uAssocCount == 0)
+ return false;
-static bool s_bAPModeRxData (
- PSDevice pDevice,
- struct sk_buff* skb,
- unsigned int FrameSize,
- unsigned int cbHeaderOffset,
- int iSANodeIndex,
- int iDANodeIndex
- )
-{
- PSMgmtObject pMgmt = pDevice->pMgmt;
- bool bRelayAndForward = false;
- bool bRelayOnly = false;
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- unsigned short wAID;
-
-
- struct sk_buff* skbcpy = NULL;
-
- if (FrameSize > CB_MAX_BUF_SIZE)
- return false;
- // check DA
- if(is_multicast_ether_addr((unsigned char *)(skb->data+cbHeaderOffset))) {
- if (pMgmt->sNodeDBTable[0].bPSEnable) {
-
- skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
-
- // if any node in PS mode, buffer packet until DTIM.
- if (skbcpy == NULL) {
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "relay multicast no skb available \n");
- }
- else {
- skbcpy->dev = pDevice->dev;
- skbcpy->len = FrameSize;
- memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize);
- skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy);
-
- pMgmt->sNodeDBTable[0].wEnQueueCnt++;
- // set tx map
- pMgmt->abyPSTxMap[0] |= byMask[0];
- }
- }
- else {
- bRelayAndForward = true;
- }
- }
- else {
- // check if relay
- if (BSSDBbIsSTAInNodeDB(pMgmt, (unsigned char *)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
- if (pMgmt->sNodeDBTable[iDANodeIndex].eNodeState >= NODE_ASSOC) {
- if (pMgmt->sNodeDBTable[iDANodeIndex].bPSEnable) {
- // queue this skb until next PS tx, and then release.
-
- skb->data += cbHeaderOffset;
- skb->tail += cbHeaderOffset;
- skb_put(skb, FrameSize);
- skb_queue_tail(&pMgmt->sNodeDBTable[iDANodeIndex].sTxPSQueue, skb);
- pMgmt->sNodeDBTable[iDANodeIndex].wEnQueueCnt++;
- wAID = pMgmt->sNodeDBTable[iDANodeIndex].wAID;
- pMgmt->abyPSTxMap[wAID >> 3] |= byMask[wAID & 7];
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "relay: index= %d, pMgmt->abyPSTxMap[%d]= %d\n",
- iDANodeIndex, (wAID >> 3), pMgmt->abyPSTxMap[wAID >> 3]);
- return true;
- }
- else {
- bRelayOnly = true;
- }
- }
- }
- }
-
- if (bRelayOnly || bRelayAndForward) {
- // relay this packet right now
- if (bRelayAndForward)
- iDANodeIndex = 0;
-
- if ((pDevice->uAssocCount > 1) && (iDANodeIndex >= 0)) {
- ROUTEbRelay(pDevice, (unsigned char *)(skb->data + cbHeaderOffset), FrameSize, (unsigned int)iDANodeIndex);
- }
-
- if (bRelayOnly)
- return false;
- }
- // none associate, don't forward
- if (pDevice->uAssocCount == 0)
- return false;
-
- return true;
+ return true;
}
-
diff --git a/drivers/staging/vt6655/dpc.h b/drivers/staging/vt6655/dpc.h
index c1b6e76a421f..0ce31557d5da 100644
--- a/drivers/staging/vt6655/dpc.h
+++ b/drivers/staging/vt6655/dpc.h
@@ -42,14 +42,11 @@
/*--------------------- Export Functions --------------------------*/
bool
-device_receive_frame (
- PSDevice pDevice,
- PSRxDesc pCurrRD
- );
+device_receive_frame(
+ PSDevice pDevice,
+ PSRxDesc pCurrRD
+);
void MngWorkItem(void *Context);
#endif // __RXTX_H__
-
-
-
diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c
index 5f13890cf124..8417c2f2c6cf 100644
--- a/drivers/staging/vt6655/hostap.c
+++ b/drivers/staging/vt6655/hostap.c
@@ -49,16 +49,12 @@
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
-
-
-
/*--------------------- Export Variables --------------------------*/
-
/*
* Description:
* register net_device (AP) for hostap deamon
@@ -75,21 +71,21 @@ static int msglevel =MSG_LEVEL_INFO;
static int hostap_enable_hostapd(PSDevice pDevice, int rtnl_locked)
{
- PSDevice apdev_priv;
+ PSDevice apdev_priv;
struct net_device *dev = pDevice->dev;
int ret;
const struct net_device_ops apdev_netdev_ops = {
.ndo_start_xmit = pDevice->tx_80211,
};
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Enabling hostapd mode\n", dev->name);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Enabling hostapd mode\n", dev->name);
pDevice->apdev = kzalloc(sizeof(struct net_device), GFP_KERNEL);
if (pDevice->apdev == NULL)
return -ENOMEM;
- apdev_priv = netdev_priv(pDevice->apdev);
- *apdev_priv = *pDevice;
+ apdev_priv = netdev_priv(pDevice->apdev);
+ *apdev_priv = *pDevice;
memcpy(pDevice->apdev->dev_addr, dev->dev_addr, ETH_ALEN);
pDevice->apdev->netdev_ops = &apdev_netdev_ops;
@@ -107,14 +103,14 @@ static int hostap_enable_hostapd(PSDevice pDevice, int rtnl_locked)
ret = register_netdev(pDevice->apdev);
if (ret) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdevice(AP) failed!\n",
- dev->name);
+ dev->name);
return -1;
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdevice %s for AP management\n",
- dev->name, pDevice->apdev->name);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdevice %s for AP management\n",
+ dev->name, pDevice->apdev->name);
- KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
+ KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
return 0;
}
@@ -135,33 +131,31 @@ static int hostap_enable_hostapd(PSDevice pDevice, int rtnl_locked)
static int hostap_disable_hostapd(PSDevice pDevice, int rtnl_locked)
{
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: disabling hostapd mode\n", pDevice->dev->name);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: disabling hostapd mode\n", pDevice->dev->name);
-
- if (pDevice->apdev && pDevice->apdev->name && pDevice->apdev->name[0]) {
+ if (pDevice->apdev && pDevice->apdev->name && pDevice->apdev->name[0]) {
if (rtnl_locked)
unregister_netdevice(pDevice->apdev);
else
unregister_netdev(pDevice->apdev);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
- pDevice->dev->name, pDevice->apdev->name);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
+ pDevice->dev->name, pDevice->apdev->name);
}
kfree(pDevice->apdev);
pDevice->apdev = NULL;
- pDevice->bEnable8021x = false;
- pDevice->bEnableHostWEP = false;
- pDevice->bEncryptionEnable = false;
+ pDevice->bEnable8021x = false;
+ pDevice->bEnableHostWEP = false;
+ pDevice->bEncryptionEnable = false;
//4.2007-0118-03,<Add> by EinsnLiu
//execute some clear work
-pDevice->pMgmt->byCSSPK=KEY_CTL_NONE;
-pDevice->pMgmt->byCSSGK=KEY_CTL_NONE;
-KeyvInitTable(&pDevice->sKey,pDevice->PortOffset);
+ pDevice->pMgmt->byCSSPK = KEY_CTL_NONE;
+ pDevice->pMgmt->byCSSGK = KEY_CTL_NONE;
+ KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
return 0;
}
-
/*
* Description:
* Set enable/disable hostapd mode
@@ -192,7 +186,6 @@ int vt6655_hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked)
return hostap_disable_hostapd(pDevice, rtnl_locked);
}
-
/*
* Description:
* remove station function supported for hostap deamon
@@ -207,17 +200,15 @@ int vt6655_hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked)
*
*/
static int hostap_remove_sta(PSDevice pDevice,
- struct viawget_hostapd_param *param)
+ struct viawget_hostapd_param *param)
{
unsigned int uNodeIndex;
-
- if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, param->sta_addr, &uNodeIndex)) {
- BSSvRemoveOneNode(pDevice, uNodeIndex);
- }
- else {
- return -ENOENT;
- }
+ if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, param->sta_addr, &uNodeIndex)) {
+ BSSvRemoveOneNode(pDevice, uNodeIndex);
+ } else {
+ return -ENOENT;
+ }
return 0;
}
@@ -235,47 +226,46 @@ static int hostap_remove_sta(PSDevice pDevice,
*
*/
static int hostap_add_sta(PSDevice pDevice,
- struct viawget_hostapd_param *param)
+ struct viawget_hostapd_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
unsigned int uNodeIndex;
-
- if (!BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
- BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
- }
- memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, param->sta_addr, WLAN_ADDR_LEN);
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
- pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = param->u.add_sta.capability;
+ if (!BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
+ BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
+ }
+ memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, param->sta_addr, WLAN_ADDR_LEN);
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
+ pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = param->u.add_sta.capability;
// TODO listenInterval
// pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = 1;
- pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = false;
- pMgmt->sNodeDBTable[uNodeIndex].bySuppRate = param->u.add_sta.tx_supp_rates;
-
- // set max tx rate
- pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
- // set max basic rate
- pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate = RATE_2M;
- // Todo: check sta preamble, if ap can't support, set status code
- pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
- WLAN_GET_CAP_INFO_SHORTPREAMBLE(pMgmt->sNodeDBTable[uNodeIndex].wCapInfo);
-
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)param->u.add_sta.aid;
-
- pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = jiffies;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Add STA AID= %d \n", pMgmt->sNodeDBTable[uNodeIndex].wAID);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
- param->sta_addr[0],
- param->sta_addr[1],
- param->sta_addr[2],
- param->sta_addr[3],
- param->sta_addr[4],
- param->sta_addr[5]
- ) ;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Max Support rate = %d \n",
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
+ pMgmt->sNodeDBTable[uNodeIndex].bPSEnable = false;
+ pMgmt->sNodeDBTable[uNodeIndex].bySuppRate = param->u.add_sta.tx_supp_rates;
+
+ // set max tx rate
+ pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
+ // set max basic rate
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate = RATE_2M;
+ // Todo: check sta preamble, if ap can't support, set status code
+ pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
+ WLAN_GET_CAP_INFO_SHORTPREAMBLE(pMgmt->sNodeDBTable[uNodeIndex].wCapInfo);
+
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)param->u.add_sta.aid;
+
+ pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = jiffies;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Add STA AID= %d \n", pMgmt->sNodeDBTable[uNodeIndex].wAID);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
+ param->sta_addr[0],
+ param->sta_addr[1],
+ param->sta_addr[2],
+ param->sta_addr[3],
+ param->sta_addr[4],
+ param->sta_addr[5]
+ );
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Max Support rate = %d \n",
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
return 0;
}
@@ -295,19 +285,18 @@ static int hostap_add_sta(PSDevice pDevice,
*/
static int hostap_get_info_sta(PSDevice pDevice,
- struct viawget_hostapd_param *param)
+ struct viawget_hostapd_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
unsigned int uNodeIndex;
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
- param->u.get_info_sta.inactive_sec =
- (jiffies - pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer) / HZ;
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
+ param->u.get_info_sta.inactive_sec =
+ (jiffies - pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer) / HZ;
- //param->u.get_info_sta.txexc = pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts;
- }
- else {
- return -ENOENT;
+ //param->u.get_info_sta.txexc = pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts;
+ } else {
+ return -ENOENT;
}
return 0;
@@ -328,21 +317,20 @@ static int hostap_get_info_sta(PSDevice pDevice,
*
*/
/*
-static int hostap_reset_txexc_sta(PSDevice pDevice,
- struct viawget_hostapd_param *param)
-{
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int uNodeIndex;
-
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
- pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts = 0;
- }
- else {
- return -ENOENT;
- }
-
- return 0;
-}
+ static int hostap_reset_txexc_sta(PSDevice pDevice,
+ struct viawget_hostapd_param *param)
+ {
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int uNodeIndex;
+
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts = 0;
+ } else {
+ return -ENOENT;
+ }
+
+ return 0;
+ }
*/
/*
@@ -359,26 +347,23 @@ static int hostap_reset_txexc_sta(PSDevice pDevice,
*
*/
static int hostap_set_flags_sta(PSDevice pDevice,
- struct viawget_hostapd_param *param)
+ struct viawget_hostapd_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
unsigned int uNodeIndex;
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &uNodeIndex)) {
pMgmt->sNodeDBTable[uNodeIndex].dwFlags |= param->u.set_flags_sta.flags_or;
pMgmt->sNodeDBTable[uNodeIndex].dwFlags &= param->u.set_flags_sta.flags_and;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " dwFlags = %x \n",
- (unsigned int)pMgmt->sNodeDBTable[uNodeIndex].dwFlags);
- }
- else {
- return -ENOENT;
+ (unsigned int)pMgmt->sNodeDBTable[uNodeIndex].dwFlags);
+ } else {
+ return -ENOENT;
}
return 0;
}
-
-
/*
* Description:
* set generic element (wpa ie)
@@ -393,34 +378,32 @@ static int hostap_set_flags_sta(PSDevice pDevice,
*
*/
static int hostap_set_generic_element(PSDevice pDevice,
- struct viawget_hostapd_param *param)
+ struct viawget_hostapd_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
+ PSMgmtObject pMgmt = pDevice->pMgmt;
- memcpy( pMgmt->abyWPAIE,
- param->u.generic_elem.data,
- param->u.generic_elem.len
- );
+ memcpy(pMgmt->abyWPAIE,
+ param->u.generic_elem.data,
+ param->u.generic_elem.len
+ );
- pMgmt->wWPAIELen = param->u.generic_elem.len;
+ pMgmt->wWPAIELen = param->u.generic_elem.len;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pMgmt->wWPAIELen = %d\n", pMgmt->wWPAIELen);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->wWPAIELen = %d\n", pMgmt->wWPAIELen);
- // disable wpa
- if (pMgmt->wWPAIELen == 0) {
- pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+ // disable wpa
+ if (pMgmt->wWPAIELen == 0) {
+ pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " No WPAIE, Disable WPA \n");
- } else {
- // enable wpa
- if ((pMgmt->abyWPAIE[0] == WLAN_EID_RSN_WPA) ||
- (pMgmt->abyWPAIE[0] == WLAN_EID_RSN)) {
- pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set WPAIE enable WPA\n");
- } else
- return -EINVAL;
- }
+ } else {
+ // enable wpa
+ if ((pMgmt->abyWPAIE[0] == WLAN_EID_RSN_WPA) ||
+ (pMgmt->abyWPAIE[0] == WLAN_EID_RSN)) {
+ pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set WPAIE enable WPA\n");
+ } else
+ return -EINVAL;
+ }
return 0;
}
@@ -440,11 +423,11 @@ static int hostap_set_generic_element(PSDevice pDevice,
static void hostap_flush_sta(PSDevice pDevice)
{
- // reserved node index =0 for multicast node.
- BSSvClearNodeDBTable(pDevice, 1);
- pDevice->uAssocCount = 0;
+ // reserved node index =0 for multicast node.
+ BSSvClearNodeDBTable(pDevice, 1);
+ pDevice->uAssocCount = 0;
- return;
+ return;
}
/*
@@ -461,34 +444,32 @@ static void hostap_flush_sta(PSDevice pDevice)
*
*/
static int hostap_set_encryption(PSDevice pDevice,
- struct viawget_hostapd_param *param,
- int param_len)
+ struct viawget_hostapd_param *param,
+ int param_len)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned long dwKeyIndex = 0;
- unsigned char abyKey[MAX_KEY_LEN];
- unsigned char abySeq[MAX_KEY_LEN];
- NDIS_802_11_KEY_RSC KeyRSC;
- unsigned char byKeyDecMode = KEY_CTL_WEP;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned long dwKeyIndex = 0;
+ unsigned char abyKey[MAX_KEY_LEN];
+ unsigned char abySeq[MAX_KEY_LEN];
+ NDIS_802_11_KEY_RSC KeyRSC;
+ unsigned char byKeyDecMode = KEY_CTL_WEP;
int ret = 0;
int iNodeIndex = -1;
int ii;
bool bKeyTableFull = false;
unsigned short wKeyCtl = 0;
-
param->u.crypt.err = 0;
/*
- if (param_len !=
- (int) ((char *) param->u.crypt.key - (char *) param) +
- param->u.crypt.key_len)
- return -EINVAL;
+ if (param_len !=
+ (int) ((char *) param->u.crypt.key - (char *) param) +
+ param->u.crypt.key_len)
+ return -EINVAL;
*/
if (param->u.crypt.alg > WPA_ALG_CCMP)
return -EINVAL;
-
if ((param->u.crypt.idx > 3) || (param->u.crypt.key_len > MAX_KEY_LEN)) {
param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_KEY_SET_FAILED\n");
@@ -498,105 +479,102 @@ static int hostap_set_encryption(PSDevice pDevice,
if (is_broadcast_ether_addr(param->sta_addr)) {
if (param->u.crypt.idx >= MAX_GROUP_KEY)
return -EINVAL;
- iNodeIndex = 0;
+ iNodeIndex = 0;
} else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
- return -EINVAL;
- }
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
+ return -EINVAL;
+ }
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: sta_index %d \n", iNodeIndex);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: alg %d \n", param->u.crypt.alg);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: sta_index %d \n", iNodeIndex);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " hostap_set_encryption: alg %d \n", param->u.crypt.alg);
if (param->u.crypt.alg == WPA_ALG_NONE) {
-
- if (pMgmt->sNodeDBTable[iNodeIndex].bOnFly == true) {
- if (KeybRemoveKey(&(pDevice->sKey),
- param->sta_addr,
- pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex,
- pDevice->PortOffset) == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybRemoveKey fail \n");
- }
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
- }
- pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = 0;
- pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = 0;
- pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = 0;
- pMgmt->sNodeDBTable[iNodeIndex].KeyRSC = 0;
- pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0;
- pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0;
- pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = 0;
- memset(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
- 0,
- MAX_KEY_LEN
- );
-
- return ret;
+ if (pMgmt->sNodeDBTable[iNodeIndex].bOnFly == true) {
+ if (KeybRemoveKey(&(pDevice->sKey),
+ param->sta_addr,
+ pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex,
+ pDevice->PortOffset) == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybRemoveKey fail \n");
+ }
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
+ }
+ pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].KeyRSC = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = 0;
+ memset(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
+ 0,
+ MAX_KEY_LEN
+);
+
+ return ret;
}
- memcpy(abyKey, param->u.crypt.key, param->u.crypt.key_len);
- // copy to node key tbl
- pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = param->u.crypt.idx;
- pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = param->u.crypt.key_len;
- memcpy(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
- param->u.crypt.key,
- param->u.crypt.key_len
- );
-
- dwKeyIndex = (unsigned long)(param->u.crypt.idx);
- if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
- pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
- pDevice->bTransmitKey = true;
- dwKeyIndex |= (1 << 31);
- }
+ memcpy(abyKey, param->u.crypt.key, param->u.crypt.key_len);
+ // copy to node key tbl
+ pMgmt->sNodeDBTable[iNodeIndex].byKeyIndex = param->u.crypt.idx;
+ pMgmt->sNodeDBTable[iNodeIndex].uWepKeyLength = param->u.crypt.key_len;
+ memcpy(&pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
+ param->u.crypt.key,
+ param->u.crypt.key_len
+);
+
+ dwKeyIndex = (unsigned long)(param->u.crypt.idx);
+ if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->bTransmitKey = true;
+ dwKeyIndex |= (1 << 31);
+ }
if (param->u.crypt.alg == WPA_ALG_WEP) {
-
- if ((pDevice->bEnable8021x == false) || (iNodeIndex == 0)) {
- KeybSetDefaultKey(&(pDevice->sKey),
- dwKeyIndex & ~(BIT30 | USE_KEYRSC),
- param->u.crypt.key_len,
- NULL,
- abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID);
-
- } else {
- // 8021x enable, individual key
- dwKeyIndex |= (1 << 30); // set pairwise key
- if (KeybSetKey(&(pDevice->sKey),
- &param->sta_addr[0],
- dwKeyIndex & ~(USE_KEYRSC),
- param->u.crypt.key_len,
- (PQWORD) &(KeyRSC),
- (unsigned char *)abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID) == true) {
-
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
-
- } else {
- // Key Table Full
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
- bKeyTableFull = true;
- }
- }
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- pDevice->bEncryptionEnable = true;
- pMgmt->byCSSPK = KEY_CTL_WEP;
- pMgmt->byCSSGK = KEY_CTL_WEP;
- pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = KEY_CTL_WEP;
- pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex;
- return ret;
+ if ((pDevice->bEnable8021x == false) || (iNodeIndex == 0)) {
+ KeybSetDefaultKey(&(pDevice->sKey),
+ dwKeyIndex & ~(BIT30 | USE_KEYRSC),
+ param->u.crypt.key_len,
+ NULL,
+ abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID);
+
+ } else {
+ // 8021x enable, individual key
+ dwKeyIndex |= (1 << 30); // set pairwise key
+ if (KeybSetKey(&(pDevice->sKey),
+ &param->sta_addr[0],
+ dwKeyIndex & ~(USE_KEYRSC),
+ param->u.crypt.key_len,
+ (PQWORD) &(KeyRSC),
+ (unsigned char *)abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID) == true) {
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
+
+ } else {
+ // Key Table Full
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
+ bKeyTableFull = true;
+ }
+ }
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+ pDevice->bEncryptionEnable = true;
+ pMgmt->byCSSPK = KEY_CTL_WEP;
+ pMgmt->byCSSGK = KEY_CTL_WEP;
+ pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = KEY_CTL_WEP;
+ pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex;
+ return ret;
}
if (param->u.crypt.seq) {
- memcpy(&abySeq, param->u.crypt.seq, 8);
- for (ii = 0 ; ii < 8 ; ii++)
+ memcpy(&abySeq, param->u.crypt.seq, 8);
+ for (ii = 0; ii < 8; ii++)
KeyRSC |= (unsigned long)abySeq[ii] << (ii * 8);
dwKeyIndex |= 1 << 29;
@@ -604,91 +582,87 @@ static int hostap_set_encryption(PSDevice pDevice,
}
if (param->u.crypt.alg == WPA_ALG_TKIP) {
- if (param->u.crypt.key_len != MAX_KEY_LEN)
- return -EINVAL;
- pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
- byKeyDecMode = KEY_CTL_TKIP;
- pMgmt->byCSSPK = KEY_CTL_TKIP;
- pMgmt->byCSSGK = KEY_CTL_TKIP;
+ if (param->u.crypt.key_len != MAX_KEY_LEN)
+ return -EINVAL;
+ pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
+ byKeyDecMode = KEY_CTL_TKIP;
+ pMgmt->byCSSPK = KEY_CTL_TKIP;
+ pMgmt->byCSSGK = KEY_CTL_TKIP;
}
if (param->u.crypt.alg == WPA_ALG_CCMP) {
- if ((param->u.crypt.key_len != AES_KEY_LEN) ||
- (pDevice->byLocalID <= REV_ID_VT3253_A1))
- return -EINVAL;
- pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
- byKeyDecMode = KEY_CTL_CCMP;
- pMgmt->byCSSPK = KEY_CTL_CCMP;
- pMgmt->byCSSGK = KEY_CTL_CCMP;
- }
-
-
- if (iNodeIndex == 0) {
- KeybSetDefaultKey(&(pDevice->sKey),
- dwKeyIndex,
- param->u.crypt.key_len,
- (PQWORD) &(KeyRSC),
- abyKey,
- byKeyDecMode,
- pDevice->PortOffset,
- pDevice->byLocalID);
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
-
- } else {
- dwKeyIndex |= (1 << 30); // set pairwise key
- if (KeybSetKey(&(pDevice->sKey),
- &param->sta_addr[0],
- dwKeyIndex,
- param->u.crypt.key_len,
- (PQWORD) &(KeyRSC),
- (unsigned char *)abyKey,
- byKeyDecMode,
- pDevice->PortOffset,
- pDevice->byLocalID) == true) {
-
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
-
- } else {
- // Key Table Full
- pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
- bKeyTableFull = true;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Key Table Full\n");
- }
-
- }
-
- if (bKeyTableFull == true) {
- wKeyCtl &= 0x7F00; // clear all key control filed
- wKeyCtl |= (byKeyDecMode << 4);
- wKeyCtl |= (byKeyDecMode);
- wKeyCtl |= 0x0044; // use group key for all address
- wKeyCtl |= 0x4000; // disable KeyTable[MAX_KEY_TABLE-1] on-fly to genernate rx int
- MACvSetDefaultKeyCtl(pDevice->PortOffset, wKeyCtl, MAX_KEY_TABLE-1, pDevice->byLocalID);
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set key sta_index= %d \n", iNodeIndex);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " tx_index=%d len=%d \n", param->u.crypt.idx,
- param->u.crypt.key_len );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n",
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[1],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[2],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[3],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[4]
- );
+ if ((param->u.crypt.key_len != AES_KEY_LEN) ||
+ (pDevice->byLocalID <= REV_ID_VT3253_A1))
+ return -EINVAL;
+ pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
+ byKeyDecMode = KEY_CTL_CCMP;
+ pMgmt->byCSSPK = KEY_CTL_CCMP;
+ pMgmt->byCSSGK = KEY_CTL_CCMP;
+ }
+
+ if (iNodeIndex == 0) {
+ KeybSetDefaultKey(&(pDevice->sKey),
+ dwKeyIndex,
+ param->u.crypt.key_len,
+ (PQWORD) &(KeyRSC),
+ abyKey,
+ byKeyDecMode,
+ pDevice->PortOffset,
+ pDevice->byLocalID);
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
+
+ } else {
+ dwKeyIndex |= (1 << 30); // set pairwise key
+ if (KeybSetKey(&(pDevice->sKey),
+ &param->sta_addr[0],
+ dwKeyIndex,
+ param->u.crypt.key_len,
+ (PQWORD) &(KeyRSC),
+ (unsigned char *)abyKey,
+ byKeyDecMode,
+ pDevice->PortOffset,
+ pDevice->byLocalID) == true) {
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
+
+ } else {
+ // Key Table Full
+ pMgmt->sNodeDBTable[iNodeIndex].bOnFly = false;
+ bKeyTableFull = true;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Key Table Full\n");
+ }
+
+ }
+
+ if (bKeyTableFull == true) {
+ wKeyCtl &= 0x7F00; // clear all key control filed
+ wKeyCtl |= (byKeyDecMode << 4);
+ wKeyCtl |= (byKeyDecMode);
+ wKeyCtl |= 0x0044; // use group key for all address
+ wKeyCtl |= 0x4000; // disable KeyTable[MAX_KEY_TABLE-1] on-fly to genernate rx int
+ MACvSetDefaultKeyCtl(pDevice->PortOffset, wKeyCtl, MAX_KEY_TABLE-1, pDevice->byLocalID);
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set key sta_index= %d \n", iNodeIndex);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " tx_index=%d len=%d \n", param->u.crypt.idx,
+ param->u.crypt.key_len);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n",
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[0],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[1],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[2],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[3],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[4]
+);
// set wep key
- pDevice->bEncryptionEnable = true;
- pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = byKeyDecMode;
- pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex;
- pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0;
- pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0;
+ pDevice->bEncryptionEnable = true;
+ pMgmt->sNodeDBTable[iNodeIndex].byCipherSuite = byKeyDecMode;
+ pMgmt->sNodeDBTable[iNodeIndex].dwKeyIndex = dwKeyIndex;
+ pMgmt->sNodeDBTable[iNodeIndex].dwTSC47_16 = 0;
+ pMgmt->sNodeDBTable[iNodeIndex].wTSC15_0 = 0;
return ret;
}
-
-
/*
* Description:
* get each stations encryption key
@@ -703,36 +677,34 @@ static int hostap_set_encryption(PSDevice pDevice,
*
*/
static int hostap_get_encryption(PSDevice pDevice,
- struct viawget_hostapd_param *param,
- int param_len)
+ struct viawget_hostapd_param *param,
+ int param_len)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
int ret = 0;
int ii;
- int iNodeIndex =0;
-
+ int iNodeIndex = 0;
param->u.crypt.err = 0;
if (is_broadcast_ether_addr(param->sta_addr)) {
- iNodeIndex = 0;
+ iNodeIndex = 0;
} else {
- if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
- return -EINVAL;
- }
+ if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) {
+ param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: HOSTAP_CRYPT_ERR_UNKNOWN_ADDR\n");
+ return -EINVAL;
+ }
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: %d\n", iNodeIndex);
- memset(param->u.crypt.seq, 0, 8);
- for (ii = 0 ; ii < 8 ; ii++) {
- param->u.crypt.seq[ii] = (unsigned char)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
- }
+ memset(param->u.crypt.seq, 0, 8);
+ for (ii = 0; ii < 8; ii++) {
+ param->u.crypt.seq[ii] = (unsigned char)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
+ }
return ret;
}
-
/*
* Description:
* vt6655_hostap_ioctl main function supported for hostap deamon.
@@ -768,80 +740,79 @@ int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p)
switch (param->cmd) {
case VIAWGET_HOSTAPD_SET_ENCRYPTION:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ENCRYPTION \n");
- spin_lock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ENCRYPTION \n");
+ spin_lock_irq(&pDevice->lock);
ret = hostap_set_encryption(pDevice, param, p->length);
- spin_unlock_irq(&pDevice->lock);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_HOSTAPD_GET_ENCRYPTION:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_ENCRYPTION \n");
- spin_lock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_ENCRYPTION \n");
+ spin_lock_irq(&pDevice->lock);
ret = hostap_get_encryption(pDevice, param, p->length);
- spin_unlock_irq(&pDevice->lock);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n");
return -EOPNOTSUPP;
break;
case VIAWGET_HOSTAPD_FLUSH:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n");
- spin_lock_irq(&pDevice->lock);
- hostap_flush_sta(pDevice);
- spin_unlock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n");
+ spin_lock_irq(&pDevice->lock);
+ hostap_flush_sta(pDevice);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_HOSTAPD_ADD_STA:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_ADD_STA \n");
- spin_lock_irq(&pDevice->lock);
- ret = hostap_add_sta(pDevice, param);
- spin_unlock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_ADD_STA \n");
+ spin_lock_irq(&pDevice->lock);
+ ret = hostap_add_sta(pDevice, param);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_HOSTAPD_REMOVE_STA:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_REMOVE_STA \n");
- spin_lock_irq(&pDevice->lock);
- ret = hostap_remove_sta(pDevice, param);
- spin_unlock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_REMOVE_STA \n");
+ spin_lock_irq(&pDevice->lock);
+ ret = hostap_remove_sta(pDevice, param);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_HOSTAPD_GET_INFO_STA:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_INFO_STA \n");
- ret = hostap_get_info_sta(pDevice, param);
- ap_ioctl = 1;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_GET_INFO_STA \n");
+ ret = hostap_get_info_sta(pDevice, param);
+ ap_ioctl = 1;
break;
/*
case VIAWGET_HOSTAPD_RESET_TXEXC_STA:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_RESET_TXEXC_STA \n");
- ret = hostap_reset_txexc_sta(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_RESET_TXEXC_STA \n");
+ ret = hostap_reset_txexc_sta(pDevice, param);
break;
*/
case VIAWGET_HOSTAPD_SET_FLAGS_STA:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_FLAGS_STA \n");
- ret = hostap_set_flags_sta(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_FLAGS_STA \n");
+ ret = hostap_set_flags_sta(pDevice, param);
break;
case VIAWGET_HOSTAPD_MLME:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_MLME \n");
- return -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_MLME \n");
+ return -EOPNOTSUPP;
case VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_GENERIC_ELEMENT \n");
ret = hostap_set_generic_element(pDevice, param);
break;
case VIAWGET_HOSTAPD_SCAN_REQ:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SCAN_REQ \n");
- return -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SCAN_REQ \n");
+ return -EOPNOTSUPP;
case VIAWGET_HOSTAPD_STA_CLEAR_STATS:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n");
- return -EOPNOTSUPP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n");
+ return -EOPNOTSUPP;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6655_hostap_ioctl: unknown cmd=%d\n",
- (int)param->cmd);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6655_hostap_ioctl: unknown cmd=%d\n",
+ (int)param->cmd);
return -EOPNOTSUPP;
break;
}
-
if ((ret == 0) && ap_ioctl) {
if (copy_to_user(p->pointer, param, p->length)) {
ret = -EFAULT;
@@ -849,9 +820,8 @@ int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p)
}
}
- out:
+out:
kfree(param);
return ret;
}
-
diff --git a/drivers/staging/vt6655/hostap.h b/drivers/staging/vt6655/hostap.h
index 55db55524d96..f1a4f2eff058 100644
--- a/drivers/staging/vt6655/hostap.h
+++ b/drivers/staging/vt6655/hostap.h
@@ -46,7 +46,6 @@
#define WLAN_RATE_48M BIT10
#define WLAN_RATE_54M BIT11
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -65,6 +64,3 @@ int vt6655_hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked);
int vt6655_hostap_ioctl(PSDevice pDevice, struct iw_point *p);
#endif // __HOSTAP_H__
-
-
-
diff --git a/drivers/staging/vt6655/iocmd.h b/drivers/staging/vt6655/iocmd.h
index 166351bb71a6..e499f1b6f531 100644
--- a/drivers/staging/vt6655/iocmd.h
+++ b/drivers/staging/vt6655/iocmd.h
@@ -37,7 +37,6 @@
//typedef uint16_t u16;
//typedef uint8_t u8;
-
// ioctl Command code
#define MAGIC_CODE 0x3142
#define IOCTL_CMD_TEST (SIOCDEVPRIVATE + 0)
@@ -45,37 +44,34 @@
#define IOCTL_CMD_HOSTAPD (SIOCDEVPRIVATE + 2)
#define IOCTL_CMD_WPA (SIOCDEVPRIVATE + 3)
-
typedef enum tagWMAC_CMD {
-
- WLAN_CMD_BSS_SCAN,
- WLAN_CMD_BSS_JOIN,
- WLAN_CMD_DISASSOC,
- WLAN_CMD_SET_WEP,
- WLAN_CMD_GET_LINK,
- WLAN_CMD_GET_LISTLEN,
- WLAN_CMD_GET_LIST,
- WLAN_CMD_GET_MIB,
- WLAN_CMD_GET_STAT,
- WLAN_CMD_STOP_MAC,
- WLAN_CMD_START_MAC,
- WLAN_CMD_AP_START,
- WLAN_CMD_SET_HOSTAPD,
- WLAN_CMD_SET_HOSTAPD_STA,
- WLAN_CMD_SET_802_1X,
- WLAN_CMD_SET_HOST_WEP,
- WLAN_CMD_SET_WPA,
- WLAN_CMD_GET_NODE_CNT,
- WLAN_CMD_ZONETYPE_SET,
- WLAN_CMD_GET_NODE_LIST
-
+ WLAN_CMD_BSS_SCAN,
+ WLAN_CMD_BSS_JOIN,
+ WLAN_CMD_DISASSOC,
+ WLAN_CMD_SET_WEP,
+ WLAN_CMD_GET_LINK,
+ WLAN_CMD_GET_LISTLEN,
+ WLAN_CMD_GET_LIST,
+ WLAN_CMD_GET_MIB,
+ WLAN_CMD_GET_STAT,
+ WLAN_CMD_STOP_MAC,
+ WLAN_CMD_START_MAC,
+ WLAN_CMD_AP_START,
+ WLAN_CMD_SET_HOSTAPD,
+ WLAN_CMD_SET_HOSTAPD_STA,
+ WLAN_CMD_SET_802_1X,
+ WLAN_CMD_SET_HOST_WEP,
+ WLAN_CMD_SET_WPA,
+ WLAN_CMD_GET_NODE_CNT,
+ WLAN_CMD_ZONETYPE_SET,
+ WLAN_CMD_GET_NODE_LIST
} WMAC_CMD, *PWMAC_CMD;
typedef enum tagWZONETYPE {
- ZoneType_USA=0,
- ZoneType_Japan=1,
- ZoneType_Europe=2
-}WZONETYPE;
+ ZoneType_USA = 0,
+ ZoneType_Japan = 1,
+ ZoneType_Europe = 2
+} WZONETYPE;
#define ADHOC 0
#define INFRA 1
@@ -85,8 +81,7 @@ typedef enum tagWZONETYPE {
#define ADHOC_STARTED 1
#define ADHOC_JOINTED 2
-
-#define PHY80211a 0
+#define PHY80211a 0
#define PHY80211b 1
#define PHY80211g 2
@@ -115,25 +110,20 @@ typedef struct tagSCmdRequest {
//
typedef struct tagSCmdScan {
-
u8 ssid[SSID_MAXLEN + 2];
-
} SCmdScan, *PSCmdScan;
-
//
// BSS Join
//
typedef struct tagSCmdBSSJoin {
-
- u16 wBSSType;
- u16 wBBPType;
- u8 ssid[SSID_MAXLEN + 2];
- u32 uChannel;
- bool bPSEnable;
- bool bShareKeyAuth;
-
+ u16 wBSSType;
+ u16 wBBPType;
+ u8 ssid[SSID_MAXLEN + 2];
+ u32 uChannel;
+ bool bPSEnable;
+ bool bShareKeyAuth;
} SCmdBSSJoin, *PSCmdBSSJoin;
//
@@ -141,83 +131,67 @@ typedef struct tagSCmdBSSJoin {
//
typedef struct tagSCmdZoneTypeSet {
-
- bool bWrite;
- WZONETYPE ZoneType;
-
+ bool bWrite;
+ WZONETYPE ZoneType;
} SCmdZoneTypeSet, *PSCmdZoneTypeSet;
#ifdef WPA_SM_Transtatus
typedef struct tagSWPAResult {
- char ifname[100];
- u8 proto;
- u8 key_mgmt;
- u8 eap_type;
- bool authenticated;
+ char ifname[100];
+ u8 proto;
+ u8 key_mgmt;
+ u8 eap_type;
+ bool authenticated;
} SWPAResult, *PSWPAResult;
#endif
typedef struct tagSCmdStartAP {
-
- u16 wBSSType;
- u16 wBBPType;
- u8 ssid[SSID_MAXLEN + 2];
- u32 uChannel;
- u32 uBeaconInt;
- bool bShareKeyAuth;
- u8 byBasicRate;
-
+ u16 wBSSType;
+ u16 wBBPType;
+ u8 ssid[SSID_MAXLEN + 2];
+ u32 uChannel;
+ u32 uBeaconInt;
+ bool bShareKeyAuth;
+ u8 byBasicRate;
} SCmdStartAP, *PSCmdStartAP;
-
typedef struct tagSCmdSetWEP {
-
- bool bEnableWep;
- u8 byKeyIndex;
- u8 abyWepKey[WEP_NKEYS][WEP_KEYMAXLEN];
- bool bWepKeyAvailable[WEP_NKEYS];
- u32 auWepKeyLength[WEP_NKEYS];
-
+ bool bEnableWep;
+ u8 byKeyIndex;
+ u8 abyWepKey[WEP_NKEYS][WEP_KEYMAXLEN];
+ bool bWepKeyAvailable[WEP_NKEYS];
+ u32 auWepKeyLength[WEP_NKEYS];
} SCmdSetWEP, *PSCmdSetWEP;
-
-
typedef struct tagSBSSIDItem {
-
u32 uChannel;
- u8 abyBSSID[BSSID_LEN];
- u8 abySSID[SSID_MAXLEN + 1];
- //2006-1116-01,<Modify> by NomadZhao
- //u16 wBeaconInterval;
- //u16 wCapInfo;
- //u8 byNetType;
- u8 byNetType;
- u16 wBeaconInterval;
- u16 wCapInfo; // for address of byNetType at align 4
-
- bool bWEPOn;
- u32 uRSSI;
-
+ u8 abyBSSID[BSSID_LEN];
+ u8 abySSID[SSID_MAXLEN + 1];
+ //2006-1116-01,<Modify> by NomadZhao
+ //u16 wBeaconInterval;
+ //u16 wCapInfo;
+ //u8 byNetType;
+ u8 byNetType;
+ u16 wBeaconInterval;
+ u16 wCapInfo; // for address of byNetType at align 4
+
+ bool bWEPOn;
+ u32 uRSSI;
} SBSSIDItem;
-
typedef struct tagSBSSIDList {
-
u32 uItem;
SBSSIDItem sBSSIDList[0];
} SBSSIDList, *PSBSSIDList;
-
typedef struct tagSCmdLinkStatus {
-
- bool bLink;
+ bool bLink;
u16 wBSSType;
u8 byState;
- u8 abyBSSID[BSSID_LEN];
- u8 abySSID[SSID_MAXLEN + 2];
- u32 uChannel;
- u32 uLinkRate;
-
+ u8 abyBSSID[BSSID_LEN];
+ u8 abySSID[SSID_MAXLEN + 2];
+ u32 uChannel;
+ u32 uLinkRate;
} SCmdLinkStatus, *PSCmdLinkStatus;
//
@@ -238,15 +212,13 @@ typedef struct tagSDot11MIBCount {
u32 FCSErrorCount;
} SDot11MIBCount, *PSDot11MIBCount;
-
-
//
// statistic counter
//
typedef struct tagSStatMIBCount {
- //
- // ISR status count
- //
+ //
+ // ISR status count
+ //
u32 dwIsrTx0OK;
u32 dwIsrTx1OK;
u32 dwIsrBeaconTxOK;
@@ -256,12 +228,12 @@ typedef struct tagSStatMIBCount {
u32 dwIsrUnrecoverableError;
u32 dwIsrSoftInterrupt;
u32 dwIsrRxNoBuf;
- /////////////////////////////////////
+ /////////////////////////////////////
u32 dwIsrUnknown; // unknown interrupt count
- // RSR status count
- //
+ // RSR status count
+ //
u32 dwRsrFrmAlgnErr;
u32 dwRsrErr;
u32 dwRsrCRCErr;
@@ -282,10 +254,10 @@ typedef struct tagSStatMIBCount {
u32 dwRsrBroadcast;
u32 dwRsrMulticast;
u32 dwRsrDirected;
- // 64-bit OID
+ // 64-bit OID
u32 ullRsrOK;
- // for some optional OIDs (64 bits) and DMI support
+ // for some optional OIDs (64 bits) and DMI support
u32 ullRxBroadcastBytes;
u32 ullRxMulticastBytes;
u32 ullRxDirectedBytes;
@@ -301,13 +273,13 @@ typedef struct tagSStatMIBCount {
u32 dwRsrRxFrmLen512_1023;
u32 dwRsrRxFrmLen1024_1518;
- // TSR0,1 status count
- //
+ // TSR0,1 status count
+ //
u32 dwTsrTotalRetry[2]; // total collision retry count
u32 dwTsrOnceRetry[2]; // this packet only occur one collision
u32 dwTsrMoreThanOnceRetry[2]; // this packet occur more than one collision
u32 dwTsrRetry[2]; // this packet has ever occur collision,
- // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
+ // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
u32 dwTsrACKData[2];
u32 dwTsrErr[2];
u32 dwAllTsrOK[2];
@@ -320,23 +292,23 @@ typedef struct tagSStatMIBCount {
u32 dwTsrMulticast[2];
u32 dwTsrDirected[2];
- // RD/TD count
+ // RD/TD count
u32 dwCntRxFrmLength;
u32 dwCntTxBufLength;
u8 abyCntRxPattern[16];
u8 abyCntTxPattern[16];
- // Software check....
+ // Software check....
u32 dwCntRxDataErr; // rx buffer data software compare CRC err count
u32 dwCntDecryptErr; // rx buffer data software compare CRC err count
u32 dwCntRxICVErr; // rx buffer data software compare CRC err count
u32 idxRxErrorDesc; // index for rx data error RD
- // 64-bit OID
+ // 64-bit OID
u32 ullTsrOK[2];
- // for some optional OIDs (64 bits) and DMI support
+ // for some optional OIDs (64 bits) and DMI support
u32 ullTxBroadcastFrames[2];
u32 ullTxMulticastFrames[2];
u32 ullTxDirectedFrames[2];
@@ -345,49 +317,38 @@ typedef struct tagSStatMIBCount {
u32 ullTxDirectedBytes[2];
} SStatMIBCount, *PSStatMIBCount;
-
typedef struct tagSNodeItem {
- // STA info
- u16 wAID;
- u8 abyMACAddr[6];
- u16 wTxDataRate;
- u16 wInActiveCount;
- u16 wEnQueueCnt;
- u16 wFlags;
- bool bPWBitOn;
- u8 byKeyIndex;
- u16 wWepKeyLength;
- u8 abyWepKey[WEP_KEYMAXLEN];
- // Auto rate fallback vars
- bool bIsInFallback;
- u32 uTxFailures;
- u32 uTxAttempts;
- u16 wFailureRatio;
-
+ // STA info
+ u16 wAID;
+ u8 abyMACAddr[6];
+ u16 wTxDataRate;
+ u16 wInActiveCount;
+ u16 wEnQueueCnt;
+ u16 wFlags;
+ bool bPWBitOn;
+ u8 byKeyIndex;
+ u16 wWepKeyLength;
+ u8 abyWepKey[WEP_KEYMAXLEN];
+ // Auto rate fallback vars
+ bool bIsInFallback;
+ u32 uTxFailures;
+ u32 uTxAttempts;
+ u16 wFailureRatio;
} SNodeItem;
-
typedef struct tagSNodeList {
-
u32 uItem;
SNodeItem sNodeList[0];
-
} SNodeList, *PSNodeList;
-
-
typedef struct tagSCmdValue {
-
u32 dwValue;
-
} SCmdValue, *PSCmdValue;
-
//
// hostapd & viawget ioctl related
//
-
// VIAGWET_IOCTL_HOSTAPD ioctl() cmd:
enum {
VIAWGET_HOSTAPD_FLUSH = 1,
@@ -404,14 +365,11 @@ enum {
VIAWGET_HOSTAPD_STA_CLEAR_STATS = 12,
};
-
-#define VIAWGET_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct viawget_hostapd_param *) 0)->u.generic_elem.data))
+#define VIAWGET_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+ ((int)(&((struct viawget_hostapd_param *)0)->u.generic_elem.data))
// Maximum length for algorithm names (-1 for nul termination) used in ioctl()
-
-
struct viawget_hostapd_param {
u32 cmd;
u8 sta_addr[6];
@@ -464,12 +422,8 @@ struct viawget_hostapd_param {
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-
#endif //__IOCMD_H__
diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c
index afed6e33dfc7..2ae8116869eb 100644
--- a/drivers/staging/vt6655/ioctl.c
+++ b/drivers/staging/vt6655/ioctl.c
@@ -41,7 +41,7 @@
static int msglevel = MSG_LEVEL_INFO;
#ifdef WPA_SM_Transtatus
- SWPAResult wpa_Result;
+SWPAResult wpa_Result;
#endif
int private_ioctl(PSDevice pDevice, struct ifreq *rq)
@@ -104,9 +104,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
if (pItemSSID->len != 0)
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
else
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -202,8 +202,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
pMgmt->eCurrState = WMAC_STATE_IDLE;
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -267,7 +267,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
memcpy(sLinkStatus.abySSID, pItemSSID->abySSID, pItemSSID->len);
memcpy(sLinkStatus.abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
sLinkStatus.uLinkRate = pMgmt->sNodeDBTable[0].wTxDataRate;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Link Success!\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Link Success!\n");
} else {
sLinkStatus.bLink = false;
sLinkStatus.uLinkRate = 0;
@@ -311,7 +311,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
}
pList->uItem = sList.uItem;
pBSS = &(pMgmt->sBSSList[0]);
- for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) {
+ for (ii = 0, jj = 0; jj < MAX_BSS_NUM; jj++) {
pBSS = &(pMgmt->sBSSList[jj]);
if (pBSS->bActive) {
pList->sBSSIDList[ii].uChannel = pBSS->uChannel;
@@ -540,7 +540,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n",
- 4, pMgmt->abyIBSSSuppRates + 2);
+ 4, pMgmt->abyIBSSSuppRates + 2);
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
diff --git a/drivers/staging/vt6655/ioctl.h b/drivers/staging/vt6655/ioctl.h
index ba85015c11b6..ae240fd71a15 100644
--- a/drivers/staging/vt6655/ioctl.h
+++ b/drivers/staging/vt6655/ioctl.h
@@ -33,7 +33,6 @@
/*--------------------- Export Definitions -------------------------*/
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -43,15 +42,12 @@
int private_ioctl(PSDevice pDevice, struct ifreq *rq);
/*
-void vConfigWEPKey (
- PSDevice pDevice,
- unsigned long dwKeyIndex,
- unsigned char *pbyKey,
- unsigned long uKeyLength
- );
+ void vConfigWEPKey(
+ PSDevice pDevice,
+ unsigned long dwKeyIndex,
+ unsigned char *pbyKey,
+ unsigned long uKeyLength
+);
*/
#endif // __IOCTL_H__
-
-
-
diff --git a/drivers/staging/vt6655/iowpa.h b/drivers/staging/vt6655/iowpa.h
index 33ae054478dc..bfea01f5e00a 100644
--- a/drivers/staging/vt6655/iowpa.h
+++ b/drivers/staging/vt6655/iowpa.h
@@ -31,17 +31,15 @@
/*--------------------- Export Definitions -------------------------*/
-
#define WPA_IE_LEN 64
-
//WPA related
/*
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
-typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
- CIPHER_WEP104 } wpa_cipher;
-typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
- KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+ typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+ typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
+ CIPHER_WEP104 } wpa_cipher;
+ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
*/
enum {
@@ -54,10 +52,9 @@ enum {
VIAWGET_SET_DROP_UNENCRYPT = 7,
VIAWGET_SET_DEAUTHENTICATE = 8,
VIAWGET_SET_ASSOCIATE = 9,
- VIAWGET_SET_DISASSOCIATE= 10
+ VIAWGET_SET_DISASSOCIATE = 10
};
-
enum {
VIAWGET_ASSOC_MSG = 1,
VIAWGET_DISASSOC_MSG = 2,
@@ -67,8 +64,6 @@ enum {
VIAWGET_DEVICECLOSE_MSG = 6
};
-
-
#pragma pack(1)
typedef struct viawget_wpa_header {
u8 type;
@@ -76,8 +71,6 @@ typedef struct viawget_wpa_header {
u16 resp_ie_len;
} viawget_wpa_header;
-
-
struct viawget_wpa_param {
u32 cmd;
u8 addr[6];
@@ -88,27 +81,27 @@ struct viawget_wpa_param {
} generic_elem;
struct {
- u8 bssid[6];
+ u8 bssid[6];
u8 ssid[32];
u8 ssid_len;
- u8 *wpa_ie;
- u16 wpa_ie_len;
- int pairwise_suite;
- int group_suite;
- int key_mgmt_suite;
- int auth_alg;
- int mode;
+ u8 *wpa_ie;
+ u16 wpa_ie_len;
+ int pairwise_suite;
+ int group_suite;
+ int key_mgmt_suite;
+ int auth_alg;
+ int mode;
} wpa_associate;
struct {
- int alg_name;
- u16 key_index;
- u16 set_tx;
- u8 *seq;
- u16 seq_len;
- u8 *key;
- u16 key_len;
+ int alg_name;
+ u16 key_index;
+ u16 set_tx;
+ u8 *seq;
+ u16 seq_len;
+ u8 *key;
+ u16 key_len;
} wpa_key;
struct {
@@ -122,7 +115,6 @@ struct viawget_wpa_param {
} scan_results;
} u;
-
};
#pragma pack(1)
@@ -148,12 +140,8 @@ struct viawget_scan_result {
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-
#endif //__IOWPA_H__
diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c
index 5cdda8dab854..9de698ef25f5 100644
--- a/drivers/staging/vt6655/iwctl.c
+++ b/drivers/staging/vt6655/iwctl.c
@@ -57,20 +57,17 @@ extern unsigned short TxRate_iwconfig;//2008-5-8 <add> by chester
#endif
static const long frequency_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
- 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
- 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240,
- 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
- 5700, 5745, 5765, 5785, 5805, 5825
- };
-
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
+ 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
+ 5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240,
+ 5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680,
+ 5700, 5745, 5765, 5785, 5805, 5825
+};
/*--------------------- Static Classes ----------------------------*/
-
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
-
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Variables --------------------------*/
/*--------------------- Static Functions --------------------------*/
@@ -83,13 +80,13 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
long ldBm;
pDevice->wstats.status = pDevice->eOPMode;
- #ifdef Calcu_LinkQual
- if(pDevice->scStatistic.LinkQuality > 100)
- pDevice->scStatistic.LinkQuality = 100;
- pDevice->wstats.qual.qual =(unsigned char) pDevice->scStatistic.LinkQuality;
- #else
+#ifdef Calcu_LinkQual
+ if (pDevice->scStatistic.LinkQuality > 100)
+ pDevice->scStatistic.LinkQuality = 100;
+ pDevice->wstats.qual.qual = (unsigned char)pDevice->scStatistic.LinkQuality;
+#else
pDevice->wstats.qual.qual = pDevice->byCurrSQ;
- #endif
+#endif
RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
pDevice->wstats.qual.level = ldBm;
//pDevice->wstats.qual.level = 0x100 - pDevice->uCurrRSSI;
@@ -105,29 +102,25 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
return &pDevice->wstats;
}
-
-
/*------------------------------------------------------------------*/
-
static int iwctl_commit(struct net_device *dev,
- struct iw_request_info *info,
- void *wrq,
- char *extra)
+ struct iw_request_info *info,
+ void *wrq,
+ char *extra)
{
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWCOMMIT \n");
return 0;
-
}
/*
* Wireless Handler : get protocol name
*/
int iwctl_giwname(struct net_device *dev,
- struct iw_request_info *info,
- char *wrq,
- char *extra)
+ struct iw_request_info *info,
+ char *wrq,
+ char *extra)
{
strcpy(wrq, "802.11-a/b/g");
return 0;
@@ -138,83 +131,77 @@ int iwctl_giwname(struct net_device *dev,
*/
int iwctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- PWLAN_IE_SSID pItemSSID=NULL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSCAN \n");
+ PWLAN_IE_SSID pItemSSID = NULL;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWSCAN \n");
-
-if(pDevice->byReAssocCount > 0) { //reject scan when re-associating!
+ if (pDevice->byReAssocCount > 0) { //reject scan when re-associating!
//send scan event to wpa_Supplicant
- union iwreq_data wrqu;
- PRINT_K("wireless_send_event--->SIOCGIWSCAN(scan done)\n");
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
- return 0;
-}
+ union iwreq_data wrqu;
+ PRINT_K("wireless_send_event--->SIOCGIWSCAN(scan done)\n");
+ memset(&wrqu, 0, sizeof(wrqu));
+ wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
+ return 0;
+ }
spin_lock_irq(&pDevice->lock);
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
//mike add: active scan OR passive scan OR desire_ssid scan
- if(wrq->length == sizeof(struct iw_scan_req)) {
- if (wrq->flags & IW_SCAN_THIS_ESSID) { //desire_ssid scan
- memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- pItemSSID = (PWLAN_IE_SSID)abyScanSSID;
- pItemSSID->byElementID = WLAN_EID_SSID;
- memcpy(pItemSSID->abySSID, req->essid, (int)req->essid_len);
- if (pItemSSID->abySSID[req->essid_len - 1] == '\0') {
- if(req->essid_len>0)
- pItemSSID->len = req->essid_len - 1;
- }
- else
- pItemSSID->len = req->essid_len;
- pMgmt->eScanType = WMAC_SCAN_PASSIVE;
- PRINT_K("SIOCSIWSCAN:[desired_ssid=%s,len=%d]\n",((PWLAN_IE_SSID)abyScanSSID)->abySSID,
- ((PWLAN_IE_SSID)abyScanSSID)->len);
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
- spin_unlock_irq(&pDevice->lock);
+ if (wrq->length == sizeof(struct iw_scan_req)) {
+ if (wrq->flags & IW_SCAN_THIS_ESSID) { //desire_ssid scan
+ memset(abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ pItemSSID = (PWLAN_IE_SSID)abyScanSSID;
+ pItemSSID->byElementID = WLAN_EID_SSID;
+ memcpy(pItemSSID->abySSID, req->essid, (int)req->essid_len);
+ if (pItemSSID->abySSID[req->essid_len - 1] == '\0') {
+ if (req->essid_len > 0)
+ pItemSSID->len = req->essid_len - 1;
+ } else
+ pItemSSID->len = req->essid_len;
+ pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+ PRINT_K("SIOCSIWSCAN:[desired_ssid=%s,len=%d]\n", ((PWLAN_IE_SSID)abyScanSSID)->abySSID,
+ ((PWLAN_IE_SSID)abyScanSSID)->len);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, abyScanSSID);
+ spin_unlock_irq(&pDevice->lock);
+
+ return 0;
+ } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { //passive scan
+ pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+ }
+ } else { //active scan
+ pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ }
- return 0;
- }
- else if(req->scan_type == IW_SCAN_TYPE_PASSIVE) { //passive scan
- pMgmt->eScanType = WMAC_SCAN_PASSIVE;
- }
- }
- else { //active scan
- pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- }
-
- pMgmt->eScanType = WMAC_SCAN_PASSIVE;
- //printk("SIOCSIWSCAN:WLAN_CMD_BSSID_SCAN\n");
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ pMgmt->eScanType = WMAC_SCAN_PASSIVE;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
spin_unlock_irq(&pDevice->lock);
return 0;
}
-
/*
* Wireless Handler : get scan results
*/
int iwctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- int ii, jj, kk;
+ int ii, jj, kk;
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- PKnownBSS pBSS;
- PWLAN_IE_SSID pItemSSID;
- PWLAN_IE_SUPP_RATES pSuppRates, pExtSuppRates;
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PKnownBSS pBSS;
+ PWLAN_IE_SSID pItemSSID;
+ PWLAN_IE_SUPP_RATES pSuppRates, pExtSuppRates;
char *current_ev = extra;
char *end_buf = extra + IW_SCAN_MAX_DATA;
char *current_val = NULL;
@@ -222,181 +209,177 @@ int iwctl_giwscan(struct net_device *dev,
long ldBm;
char buf[MAX_WPA_IE_LEN * 2 + 30];
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSCAN \n");
-
- if (pMgmt->eScanState == WMAC_IS_SCANNING) {
- // In scanning..
+ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
+ // In scanning..
return -EAGAIN;
}
pBSS = &(pMgmt->sBSSList[0]);
- for (ii = 0, jj = 0; jj < MAX_BSS_NUM ; jj++) {
+ for (ii = 0, jj = 0; jj < MAX_BSS_NUM; jj++) {
if (current_ev >= end_buf)
break;
- pBSS = &(pMgmt->sBSSList[jj]);
- if (pBSS->bActive) {
- //ADD mac address
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ pBSS = &(pMgmt->sBSSList[jj]);
+ if (pBSS->bActive) {
+ //ADD mac address
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(iwe.u.ap_addr.sa_data, pBSS->abyBSSID, WLAN_BSSID_LEN);
- current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_ADDR_LEN);
- //ADD ssid
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
- iwe.u.data.length = pItemSSID->len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID);
- //ADD mode
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) {
- iwe.u.mode = IW_MODE_INFRA;
- }
- else {
- iwe.u.mode = IW_MODE_ADHOC;
- }
- iwe.len = IW_EV_UINT_LEN;
- current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
- //ADD frequency
- pSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abySuppRates;
- pExtSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abyExtSuppRates;
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = pBSS->uChannel;
- iwe.u.freq.e = 0;
- iwe.u.freq.i = 0;
- current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN);
- //2008-0409-04, <Add> by Einsn Liu
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+ //ADD ssid
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
+ iwe.u.data.length = pItemSSID->len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pItemSSID->abySSID);
+ //ADD mode
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (WLAN_GET_CAP_INFO_ESS(pBSS->wCapInfo)) {
+ iwe.u.mode = IW_MODE_INFRA;
+ } else {
+ iwe.u.mode = IW_MODE_ADHOC;
+ }
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+ //ADD frequency
+ pSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abySuppRates;
+ pExtSuppRates = (PWLAN_IE_SUPP_RATES)pBSS->abyExtSuppRates;
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = pBSS->uChannel;
+ iwe.u.freq.e = 0;
+ iwe.u.freq.i = 0;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+ //2008-0409-04, <Add> by Einsn Liu
{
- int f = (int)pBSS->uChannel - 1;
- if(f < 0)f = 0;
- iwe.u.freq.m = frequency_list[f] * 100000;
- iwe.u.freq.e = 1;
+ int f = (int)pBSS->uChannel - 1;
+ if (f < 0)f = 0;
+ iwe.u.freq.m = frequency_list[f] * 100000;
+ iwe.u.freq.e = 1;
}
- current_ev = iwe_stream_add_event(info,current_ev,end_buf, &iwe, IW_EV_FREQ_LEN);
- //ADD quality
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- RFvRSSITodBm(pDevice, (unsigned char)(pBSS->uRSSI), &ldBm);
- iwe.u.qual.level = ldBm;
- iwe.u.qual.noise = 0;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
+ //ADD quality
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ RFvRSSITodBm(pDevice, (unsigned char)(pBSS->uRSSI), &ldBm);
+ iwe.u.qual.level = ldBm;
+ iwe.u.qual.noise = 0;
//2008-0409-01, <Add> by Einsn Liu
- if(-ldBm<50){
+ if (-ldBm < 50) {
iwe.u.qual.qual = 100;
- }else if(-ldBm > 90) {
- iwe.u.qual.qual = 0;
- }else {
- iwe.u.qual.qual=(40-(-ldBm-50))*100/40;
+ } else if (-ldBm > 90) {
+ iwe.u.qual.qual = 0;
+ } else {
+ iwe.u.qual.qual = (40 - (-ldBm - 50)) * 100 / 40;
+ }
+ iwe.u.qual.updated = 7;
+
+ // iwe.u.qual.qual = 0;
+ current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ iwe.u.data.length = 0;
+ if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pItemSSID->abySSID);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWRATE;
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ for (kk = 0; kk < 12; kk++) {
+ if (pSuppRates->abyRates[kk] == 0)
+ break;
+ // Bit rate given in 500 kb/s units (+ 0x80)
+ iwe.u.bitrate.value = ((pSuppRates->abyRates[kk] & 0x7f) * 500000);
+ current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
}
- iwe.u.qual.updated=7;
-
- // iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info,current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- iwe.u.data.length = 0;
- if (WLAN_GET_CAP_INFO_PRIVACY(pBSS->wCapInfo)) {
- iwe.u.data.flags =IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- }else {
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- }
- current_ev = iwe_stream_add_point(info,current_ev,end_buf, &iwe, pItemSSID->abySSID);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWRATE;
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- current_val = current_ev + IW_EV_LCP_LEN;
-
- for (kk = 0 ; kk < 12 ; kk++) {
- if (pSuppRates->abyRates[kk] == 0)
- break;
- // Bit rate given in 500 kb/s units (+ 0x80)
- iwe.u.bitrate.value = ((pSuppRates->abyRates[kk] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+ for (kk = 0; kk < 8; kk++) {
+ if (pExtSuppRates->abyRates[kk] == 0)
+ break;
+ // Bit rate given in 500 kb/s units (+ 0x80)
+ iwe.u.bitrate.value = ((pExtSuppRates->abyRates[kk] & 0x7f) * 500000);
+ current_val = iwe_stream_add_value(info, current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
+ }
+
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "bcn_int=%d", pBSS->wBeaconInterval);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf);
+
+ if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = pBSS->wWPALen;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pBSS->byWPAIE);
+ }
+
+ if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = pBSS->wRSNLen;
+ current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, pBSS->byRSNIE);
+ }
+
}
- for (kk = 0 ; kk < 8 ; kk++) {
- if (pExtSuppRates->abyRates[kk] == 0)
- break;
- // Bit rate given in 500 kb/s units (+ 0x80)
- iwe.u.bitrate.value = ((pExtSuppRates->abyRates[kk] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info,current_ev, current_val, end_buf, &iwe, IW_EV_PARAM_LEN);
- }
-
- if((current_val - current_ev) > IW_EV_LCP_LEN)
- current_ev = current_val;
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "bcn_int=%d", pBSS->wBeaconInterval);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, buf);
-
- if ((pBSS->wWPALen > 0) && (pBSS->wWPALen <= MAX_WPA_IE_LEN)) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = pBSS->wWPALen;
- current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byWPAIE);
- }
-
- if ((pBSS->wRSNLen > 0) && (pBSS->wRSNLen <= MAX_WPA_IE_LEN)) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = pBSS->wRSNLen;
- current_ev = iwe_stream_add_point(info,current_ev, end_buf, &iwe, pBSS->byRSNIE);
- }
-
- }
- }// for
+ }// for
wrq->length = current_ev - extra;
return 0;
-
}
-
/*
* Wireless Handler : set frequency or channel
*/
int iwctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_freq *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
int rc = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFREQ \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFREQ \n");
// If setting by frequency, convert to a channel
- if((wrq->e == 1) &&
- (wrq->m >= (int) 2.412e8) &&
- (wrq->m <= (int) 2.487e8)) {
+ if ((wrq->e == 1) &&
+ (wrq->m >= (int) 2.412e8) &&
+ (wrq->m <= (int) 2.487e8)) {
int f = wrq->m / 100000;
int c = 0;
- while((c < 14) && (f != frequency_list[c]))
+ while ((c < 14) && (f != frequency_list[c]))
c++;
wrq->e = 0;
wrq->m = c + 1;
}
// Setting by channel number
- if((wrq->m > 14) || (wrq->e > 0))
+ if ((wrq->m > 14) || (wrq->e > 0))
rc = -EOPNOTSUPP;
else {
int channel = wrq->m;
- if((channel < 1) || (channel > 14)) {
+ if ((channel < 1) || (channel > 14)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: New channel value of %d is invalid!\n", dev->name, wrq->m);
rc = -EINVAL;
} else {
- // Yes ! We can set it !!!
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set to channel = %d\n", channel);
- pDevice->uChannel = channel;
- //2007-0207-04,<Add> by EinsnLiu
- //Make change effect at once
- pDevice->bCommit = true;
+ // Yes ! We can set it !!!
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set to channel = %d\n", channel);
+ pDevice->uChannel = channel;
+ //2007-0207-04,<Add> by EinsnLiu
+ //Make change effect at once
+ pDevice->bCommit = true;
}
}
@@ -408,14 +391,14 @@ int iwctl_siwfreq(struct net_device *dev,
*/
int iwctl_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_freq *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFREQ \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFREQ \n");
#ifdef WEXT_USECHANNELS
wrq->m = (int)pMgmt->uCurrChannel;
@@ -423,8 +406,8 @@ int iwctl_giwfreq(struct net_device *dev,
#else
{
int f = (int)pMgmt->uCurrChannel - 1;
- if(f < 0)
- f = 0;
+ if (f < 0)
+ f = 0;
wrq->m = frequency_list[f] * 100000;
wrq->e = 1;
}
@@ -438,59 +421,58 @@ int iwctl_giwfreq(struct net_device *dev,
*/
int iwctl_siwmode(struct net_device *dev,
- struct iw_request_info *info,
- __u32 *wmode,
- char *extra)
+ struct iw_request_info *info,
+ __u32 *wmode,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int rc = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMODE \n");
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ int rc = 0;
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP && pDevice->bEnableHostapd) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Can't set operation mode, hostapd is running \n");
- return rc;
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWMODE \n");
- switch(*wmode) {
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP && pDevice->bEnableHostapd) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Can't set operation mode, hostapd is running \n");
+ return rc;
+ }
+ switch (*wmode) {
case IW_MODE_ADHOC:
- if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) {
- pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = true;
- }
+ if (pMgmt->eConfigMode != WMAC_CONFIG_IBSS_STA) {
+ pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ pDevice->bCommit = true;
+ }
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to ad-hoc \n");
break;
case IW_MODE_AUTO:
case IW_MODE_INFRA:
- if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) {
- pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = true;
- }
+ if (pMgmt->eConfigMode != WMAC_CONFIG_ESS_STA) {
+ pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ pDevice->bCommit = true;
+ }
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to infrastructure \n");
break;
case IW_MODE_MASTER:
- pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+ pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
rc = -EOPNOTSUPP;
break;
- if (pMgmt->eConfigMode != WMAC_CONFIG_AP) {
- pMgmt->eConfigMode = WMAC_CONFIG_AP;
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = true;
- }
+ if (pMgmt->eConfigMode != WMAC_CONFIG_AP) {
+ pMgmt->eConfigMode = WMAC_CONFIG_AP;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ pDevice->bCommit = true;
+ }
}
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set mode to Access Point \n");
break;
case IW_MODE_REPEAT:
- pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+ pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
rc = -EOPNOTSUPP;
break;
default:
@@ -505,22 +487,21 @@ int iwctl_siwmode(struct net_device *dev,
*/
int iwctl_giwmode(struct net_device *dev,
- struct iw_request_info *info,
- __u32 *wmode,
- char *extra)
+ struct iw_request_info *info,
+ __u32 *wmode,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWMODE \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWMODE \n");
// If not managed, assume it's ad-hoc
switch (pMgmt->eConfigMode) {
case WMAC_CONFIG_ESS_STA:
*wmode = IW_MODE_INFRA;
break;
case WMAC_CONFIG_IBSS_STA:
- *wmode = IW_MODE_ADHOC;
+ *wmode = IW_MODE_ADHOC;
break;
case WMAC_CONFIG_AUTO:
*wmode = IW_MODE_INFRA;
@@ -535,22 +516,20 @@ int iwctl_giwmode(struct net_device *dev,
return 0;
}
-
/*
* Wireless Handler : get capability range
*/
int iwctl_giwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- struct iw_range *range = (struct iw_range *) extra;
- int i,k;
- unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
-
+ struct iw_range *range = (struct iw_range *)extra;
+ int i, k;
+ unsigned char abySupportedRates[13] = {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRANGE \n");
if (wrq->pointer) {
wrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -560,25 +539,25 @@ int iwctl_giwrange(struct net_device *dev,
// Should be based on cap_rid.country to give only
// what the current card support
k = 0;
- for(i = 0; i < 14; i++) {
+ for (i = 0; i < 14; i++) {
range->freq[k].i = i + 1; // List index
range->freq[k].m = frequency_list[i] * 100000;
range->freq[k++].e = 1; // Values in table in MHz -> * 10^5 * 10
}
range->num_frequency = k;
// Hum... Should put the right values there
- #ifdef Calcu_LinkQual
- range->max_qual.qual = 100;
- #else
+#ifdef Calcu_LinkQual
+ range->max_qual.qual = 100;
+#else
range->max_qual.qual = 255;
- #endif
+#endif
range->max_qual.level = 0;
range->max_qual.noise = 0;
range->sensitivity = 255;
- for(i = 0 ; i < 13 ; i++) {
+ for (i = 0; i < 13; i++) {
range->bitrate[i] = abySupportedRates[i] * 500000;
- if(range->bitrate[i] == 0)
+ if (range->bitrate[i] == 0)
break;
}
range->num_bitrates = i;
@@ -586,7 +565,7 @@ int iwctl_giwrange(struct net_device *dev,
// Set an indication of the max TCP throughput
// in bit/s that we can expect using this interface.
// May be use for QoS stuff... Jean II
- if(i > 2)
+ if (i > 2)
range->throughput = 5 * 1000 * 1000;
else
range->throughput = 1.5 * 1000 * 1000;
@@ -596,20 +575,19 @@ int iwctl_giwrange(struct net_device *dev,
range->min_frag = 256;
range->max_frag = 2312;
+ // the encoding capabilities
+ range->num_encoding_sizes = 3;
+ // 64(40) bits WEP
+ range->encoding_size[0] = 5;
+ // 128(104) bits WEP
+ range->encoding_size[1] = 13;
+ // 256 bits for WPA-PSK
+ range->encoding_size[2] = 32;
+ // 4 keys are allowed
+ range->max_encoding_tokens = 4;
- // the encoding capabilities
- range->num_encoding_sizes = 3;
- // 64(40) bits WEP
- range->encoding_size[0] = 5;
- // 128(104) bits WEP
- range->encoding_size[1] = 13;
- // 256 bits for WPA-PSK
- range->encoding_size[2] = 32;
- // 4 keys are allowed
- range->max_encoding_tokens = 4;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
range->min_pmp = 0;
range->max_pmp = 1000000;// 1 secs
@@ -621,7 +599,7 @@ int iwctl_giwrange(struct net_device *dev,
// Transmit Power - values are in mW
- range->txpower[0] = 100;
+ range->txpower[0] = 100;
range->num_txpower = 1;
range->txpower_capa = IW_TXPOW_MWATT;
range->we_version_source = SUPPORTED_WIRELESS_EXT;
@@ -641,65 +619,63 @@ int iwctl_giwrange(struct net_device *dev,
range->avg_qual.noise = 0;
}
-
return 0;
}
-
/*
* Wireless Handler : set ap mac address
*/
int iwctl_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct sockaddr *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int rc = 0;
- unsigned char ZeroBSSID[WLAN_BSSID_LEN]={0x00,0x00,0x00,0x00,0x00,0x00};
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAP \n");
-if (pMgmt->eScanState == WMAC_IS_SCANNING) {
- // In scanning..
- printk("SIOCSIWAP(??)-->In scanning...\n");
- // return -EAGAIN;
- }
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ int rc = 0;
+ unsigned char ZeroBSSID[WLAN_BSSID_LEN] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAP \n");
+ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
+ // In scanning..
+ printk("SIOCSIWAP(??)-->In scanning...\n");
+ // return -EAGAIN;
+ }
if (wrq->sa_family != ARPHRD_ETHER)
rc = -EINVAL;
else {
memcpy(pMgmt->abyDesireBSSID, wrq->sa_data, 6);
- //2008-0409-05, <Add> by Einsn Liu
- if((pDevice->bLinkPass == true) &&
- (memcmp(pMgmt->abyDesireBSSID, pMgmt->abyCurrBSSID, 6)== 0)){
+ //2008-0409-05, <Add> by Einsn Liu
+ if ((pDevice->bLinkPass == true) &&
+ (memcmp(pMgmt->abyDesireBSSID, pMgmt->abyCurrBSSID, 6) == 0)) {
return rc;
+ }
+ //mike :add
+ if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
+ (memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)) {
+ PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
+ return rc;
+ }
+ //mike add: if desired AP is hidden ssid(there are two same BSSID in list),
+ // then ignore,because you don't known which one to be connect with??
+ {
+ unsigned int ii, uSameBssidNum = 0;
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ if (pMgmt->sBSSList[ii].bActive &&
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyDesireBSSID)) {
+ uSameBssidNum++;
+ }
+ }
+ if (uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!!
+ PRINT_K("SIOCSIWAP:ignore for desired AP in hidden mode\n");
+ return rc;
}
- //mike :add
- if ((is_broadcast_ether_addr(pMgmt->abyDesireBSSID)) ||
- (memcmp(pMgmt->abyDesireBSSID, ZeroBSSID, 6) == 0)){
- PRINT_K("SIOCSIWAP:invalid desired BSSID return!\n");
- return rc;
- }
- //mike add: if desired AP is hidden ssid(there are two same BSSID in list),
- // then ignore,because you don't known which one to be connect with??
- {
- unsigned int ii , uSameBssidNum=0;
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (pMgmt->sBSSList[ii].bActive &&
- !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyDesireBSSID)) {
- uSameBssidNum++;
- }
- }
- if(uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!!
- PRINT_K("SIOCSIWAP:ignore for desired AP in hidden mode\n");
- return rc;
- }
- }
-
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = true;
- }
+ }
+
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ pDevice->bCommit = true;
+ }
}
return rc;
}
@@ -709,49 +685,45 @@ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
*/
int iwctl_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct sockaddr *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAP \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAP \n");
+ memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
+ //2008-0410,<Modify> by Einsn Liu
+ if ((pDevice->bLinkPass == false) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
+ memset(wrq->sa_data, 0, 6);
- memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
- //2008-0410,<Modify> by Einsn Liu
- if ((pDevice->bLinkPass == false) && (pMgmt->eCurrMode != WMAC_MODE_ESS_AP))
- memset(wrq->sa_data, 0, 6);
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
- }
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ memcpy(wrq->sa_data, pMgmt->abyCurrBSSID, 6);
+ }
wrq->sa_family = ARPHRD_ETHER;
return 0;
-
}
-
/*
* Wireless Handler : get ap list
*/
int iwctl_giwaplist(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- int ii,jj, rc = 0;
+ int ii, jj, rc = 0;
struct sockaddr sock[IW_MAX_AP];
struct iw_quality qual[IW_MAX_AP];
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAPLIST \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWAPLIST \n");
// Only super-user can see AP list
if (!capable(CAP_NET_ADMIN)) {
@@ -760,15 +732,14 @@ int iwctl_giwaplist(struct net_device *dev,
}
if (wrq->pointer) {
-
PKnownBSS pBSS = &(pMgmt->sBSSList[0]);
- for (ii = 0, jj= 0; ii < MAX_BSS_NUM; ii++) {
- pBSS = &(pMgmt->sBSSList[ii]);
- if (!pBSS->bActive)
- continue;
- if ( jj >= IW_MAX_AP)
- break;
+ for (ii = 0, jj = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSS = &(pMgmt->sBSSList[ii]);
+ if (!pBSS->bActive)
+ continue;
+ if (jj >= IW_MAX_AP)
+ break;
memcpy(sock[jj].sa_data, pBSS->abyBSSID, 6);
sock[jj].sa_family = ARPHRD_ETHER;
qual[jj].level = pBSS->uRSSI;
@@ -786,155 +757,144 @@ int iwctl_giwaplist(struct net_device *dev,
return rc;
}
-
/*
* Wireless Handler : set essid
*/
int iwctl_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- PWLAN_IE_SSID pItemSSID;
- //2008-0409-05, <Add> by Einsn Liu
- unsigned char len;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID \n");
- pDevice->fWPA_Authened = false;
-if (pMgmt->eScanState == WMAC_IS_SCANNING) {
- // In scanning..
- printk("SIOCSIWESSID(??)-->In scanning...\n");
- // return -EAGAIN;
- }
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PWLAN_IE_SSID pItemSSID;
+ //2008-0409-05, <Add> by Einsn Liu
+ unsigned char len;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWESSID \n");
+ pDevice->fWPA_Authened = false;
+ if (pMgmt->eScanState == WMAC_IS_SCANNING) {
+ // In scanning..
+ printk("SIOCSIWESSID(??)-->In scanning...\n");
+ // return -EAGAIN;
+ }
// Check if we asked for `any'
- if(wrq->flags == 0) {
+ if (wrq->flags == 0) {
// Just send an empty SSID list
memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- memset(pMgmt->abyDesireBSSID, 0xFF,6);
- PRINT_K("set essid to 'any' \n");
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //Unknown desired AP,so here need not associate??
- //if(pDevice->bWPASuppWextEnabled == true) {
- return 0;
- // }
- #endif
+ memset(pMgmt->abyDesireBSSID, 0xFF, 6);
+ PRINT_K("set essid to 'any' \n");
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ return 0;
+#endif
} else {
// Set the SSID
memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
- pItemSSID->byElementID = WLAN_EID_SSID;
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+ pItemSSID->byElementID = WLAN_EID_SSID;
memcpy(pItemSSID->abySSID, extra, wrq->length);
- if (pItemSSID->abySSID[wrq->length - 1] == '\0') {
- if(wrq->length>0)
- pItemSSID->len = wrq->length - 1;
- }
- else
- pItemSSID->len = wrq->length;
- printk("set essid to %s \n",pItemSSID->abySSID);
+ if (pItemSSID->abySSID[wrq->length - 1] == '\0') {
+ if (wrq->length > 0)
+ pItemSSID->len = wrq->length - 1;
+ } else
+ pItemSSID->len = wrq->length;
+ printk("set essid to %s \n", pItemSSID->abySSID);
//2008-0409-05, <Add> by Einsn Liu
- len=(pItemSSID->len > ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len)?pItemSSID->len:((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len;
- if((pDevice->bLinkPass == true) &&
- (memcmp(pItemSSID->abySSID,((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,len)==0))
- return 0;
-
- //mike:need clear desiredBSSID
- if(pItemSSID->len==0) {
- memset(pMgmt->abyDesireBSSID, 0xFF,6);
- return 0;
- }
+ len = (pItemSSID->len > ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) ? pItemSSID->len : ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len;
+ if ((pDevice->bLinkPass == true) &&
+ (memcmp(pItemSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, len) == 0))
+ return 0;
+
+ //mike:need clear desiredBSSID
+ if (pItemSSID->len == 0) {
+ memset(pMgmt->abyDesireBSSID, 0xFF, 6);
+ return 0;
+ }
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //Wext wil order another command of siwap to link with desired AP,
- //so here need not associate??
- if(pDevice->bWPASuppWextEnabled == true) {
- /*******search if in hidden ssid mode ****/
- {
- PKnownBSS pCurr = NULL;
- unsigned char abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned int ii , uSameBssidNum=0;
-
- memcpy(abyTmpDesireSSID,pMgmt->abyDesireSSID,sizeof(abyTmpDesireSSID));
- pCurr = BSSpSearchBSSList(pDevice,
- NULL,
- abyTmpDesireSSID,
- pMgmt->eConfigPHYMode
- );
-
- if (pCurr == NULL){
- PRINT_K("SIOCSIWESSID:hidden ssid site survey before associate.......\n");
- vResetCommandTimer((void *) pDevice);
- pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
- }
- else { //mike:to find out if that desired SSID is a hidden-ssid AP ,
- // by means of judging if there are two same BSSID exist in list ?
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (pMgmt->sBSSList[ii].bActive &&
- !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
- uSameBssidNum++;
- }
- }
- if(uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!!
- printk("SIOCSIWESSID:hidden ssid directly associate.......\n");
- vResetCommandTimer((void *) pDevice);
- pMgmt->eScanType = WMAC_SCAN_PASSIVE; //this scan type,you'll submit scan result!
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
- }
- }
- }
- return 0;
- }
- #endif
+ //Wext wil order another command of siwap to link with desired AP,
+ //so here need not associate??
+ if (pDevice->bWPASuppWextEnabled == true) {
+ /*******search if in hidden ssid mode ****/
+ {
+ PKnownBSS pCurr = NULL;
+ unsigned char abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned int ii, uSameBssidNum = 0;
+
+ memcpy(abyTmpDesireSSID, pMgmt->abyDesireSSID, sizeof(abyTmpDesireSSID));
+ pCurr = BSSpSearchBSSList(pDevice,
+ NULL,
+ abyTmpDesireSSID,
+ pMgmt->eConfigPHYMode
+);
+
+ if (pCurr == NULL) {
+ PRINT_K("SIOCSIWESSID:hidden ssid site survey before associate.......\n");
+ vResetCommandTimer((void *)pDevice);
+ pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
+ } else { //mike:to find out if that desired SSID is a hidden-ssid AP ,
+ // by means of judging if there are two same BSSID exist in list ?
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ if (pMgmt->sBSSList[ii].bActive &&
+ !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
+ uSameBssidNum++;
+ }
+ }
+ if (uSameBssidNum >= 2) { //hit: desired AP is in hidden ssid mode!!!
+ printk("SIOCSIWESSID:hidden ssid directly associate.......\n");
+ vResetCommandTimer((void *)pDevice);
+ pMgmt->eScanType = WMAC_SCAN_PASSIVE; //this scan type,you'll submit scan result!
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, pMgmt->abyDesireSSID);
+ }
+ }
+ }
+ return 0;
+ }
+#endif
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "set essid = %s \n", pItemSSID->abySSID);
}
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- pDevice->bCommit = true;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ pDevice->bCommit = true;
}
-
return 0;
}
-
/*
* Wireless Handler : get essid
*/
int iwctl_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
-
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
PWLAN_IE_SSID pItemSSID;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWESSID \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWESSID \n");
// Note : if wrq->u.data.flags != 0, we should
// get the relevant SSID from the SSID list...
// Get the current SSID
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
//pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
memcpy(extra, pItemSSID->abySSID , pItemSSID->len);
extra[pItemSSID->len] = '\0';
wrq->length = pItemSSID->len + 1;
- //2008-0409-03, <Add> by Einsn Liu
- wrq->length = pItemSSID->len;
+ //2008-0409-03, <Add> by Einsn Liu
+ wrq->length = pItemSSID->len;
wrq->flags = 1; // active
-
return 0;
}
@@ -943,28 +903,27 @@ int iwctl_giwessid(struct net_device *dev,
*/
int iwctl_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- int rc = 0;
+ int rc = 0;
u8 brate = 0;
int i;
- unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
-
+ unsigned char abySupportedRates[13] = {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n");
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
- rc = -EINVAL;
- return rc;
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRATE \n");
+ if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
+ rc = -EINVAL;
+ return rc;
+ }
// First : get a valid bit rate value
// Which type of value
- if((wrq->value < 13) &&
- (wrq->value >= 0)) {
+ if ((wrq->value < 13) &&
+ (wrq->value >= 0)) {
// Setting by rate index
// Find value in the magic rate table
brate = wrq->value;
@@ -973,51 +932,49 @@ int iwctl_siwrate(struct net_device *dev,
u8 normvalue = (u8) (wrq->value/500000);
// Check if rate is valid
- for(i = 0 ; i < 13 ; i++) {
- if(normvalue == abySupportedRates[i]) {
+ for (i = 0; i < 13; i++) {
+ if (normvalue == abySupportedRates[i]) {
brate = i;
break;
}
}
}
// -1 designed the max rate (mostly auto mode)
- if(wrq->value == -1) {
+ if (wrq->value == -1) {
// Get the highest available rate
- for(i = 0 ; i < 13 ; i++) {
- if(abySupportedRates[i] == 0)
+ for (i = 0; i < 13; i++) {
+ if (abySupportedRates[i] == 0)
break;
}
- if(i != 0)
+ if (i != 0)
brate = i - 1;
}
// Check that it is valid
// brate is index of abySupportedRates[]
- if(brate > 13 ) {
+ if (brate > 13) {
rc = -EINVAL;
return rc;
}
// Now, check if we want a fixed or auto value
- if(wrq->fixed != 0) {
+ if (wrq->fixed != 0) {
// Fixed mode
// One rate, fixed
- printk("Rate Fix\n");
+ printk("Rate Fix\n");
pDevice->bFixRate = true;
- if ((pDevice->byBBType == BB_TYPE_11B)&& (brate > 3)) {
- pDevice->uConnectionRate = 3;
- }
- else {
- pDevice->uConnectionRate = brate;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate);
- }
+ if ((pDevice->byBBType == BB_TYPE_11B) && (brate > 3)) {
+ pDevice->uConnectionRate = 3;
+ } else {
+ pDevice->uConnectionRate = brate;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fixed to Rate %d \n", pDevice->uConnectionRate);
+ }
+ } else {
+ pDevice->bFixRate = false;
+ pDevice->uConnectionRate = 13;
+ printk("auto rate:connection_rate is 13\n");
}
- else {
- pDevice->bFixRate = false;
- pDevice->uConnectionRate = 13;
- printk("auto rate:connection_rate is 13\n");
- }
return rc;
}
@@ -1027,91 +984,84 @@ int iwctl_siwrate(struct net_device *dev,
*/
int iwctl_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
//2007-0118-05,<Mark> by EinsnLiu
//Mark the unnecessary sentences.
// PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n");
- {
- unsigned char abySupportedRates[13]= {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
- int brate = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRATE \n");
+ {
+ unsigned char abySupportedRates[13] = {0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90};
+ int brate = 0;
//2008-5-8 <modify> by chester
-if(pDevice->bLinkPass){
-if(pDevice->bFixRate == true){
- if (pDevice->uConnectionRate < 13) {
- brate = abySupportedRates[pDevice->uConnectionRate];
- }else {
- if (pDevice->byBBType == BB_TYPE_11B)
- brate = 0x16;
- if (pDevice->byBBType == BB_TYPE_11G)
- brate = 0x6C;
- if (pDevice->byBBType == BB_TYPE_11A)
- brate = 0x6C;
- }
-}
-else
-{
-
- brate = abySupportedRates[TxRate_iwconfig];
-}
-}
-else brate =0;
+ if (pDevice->bLinkPass) {
+ if (pDevice->bFixRate == true) {
+ if (pDevice->uConnectionRate < 13) {
+ brate = abySupportedRates[pDevice->uConnectionRate];
+ } else {
+ if (pDevice->byBBType == BB_TYPE_11B)
+ brate = 0x16;
+ if (pDevice->byBBType == BB_TYPE_11G)
+ brate = 0x6C;
+ if (pDevice->byBBType == BB_TYPE_11A)
+ brate = 0x6C;
+ }
+ } else {
+ brate = abySupportedRates[TxRate_iwconfig];
+ }
+ } else brate = 0;
//2007-0118-05,<Mark> by EinsnLiu
//Mark the unnecessary sentences.
/*
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (pDevice->byBBType == BB_TYPE_11B)
- brate = 0x16;
- if (pDevice->byBBType == BB_TYPE_11G)
- brate = 0x6C;
- if (pDevice->byBBType == BB_TYPE_11A)
- brate = 0x6C;
- }
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (pDevice->byBBType == BB_TYPE_11B)
+ brate = 0x16;
+ if (pDevice->byBBType == BB_TYPE_11G)
+ brate = 0x6C;
+ if (pDevice->byBBType == BB_TYPE_11A)
+ brate = 0x6C;
+ }
*/
-// if (pDevice->uConnectionRate == 13)
+// if (pDevice->uConnectionRate == 13)
// brate = abySupportedRates[pDevice->wCurrentRate];
- wrq->value = brate * 500000;
- // If more than one rate, set auto
- if (pDevice->bFixRate == true)
- wrq->fixed = true;
- }
-
+ wrq->value = brate * 500000;
+ // If more than one rate, set auto
+ if (pDevice->bFixRate == true)
+ wrq->fixed = true;
+ }
return 0;
}
-
-
/*
* Wireless Handler : set rts threshold
*/
int iwctl_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
int rc = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRTS \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRTS \n");
{
- int rthr = wrq->value;
- if(wrq->disabled)
+ int rthr = wrq->value;
+ if (wrq->disabled)
rthr = 2312;
- if((rthr < 0) || (rthr > 2312)) {
+ if ((rthr < 0) || (rthr > 2312)) {
rc = -EINVAL;
- }else {
- pDevice->wRTSThreshold = rthr;
- }
- }
+ } else {
+ pDevice->wRTSThreshold = rthr;
+ }
+ }
return 0;
}
@@ -1121,13 +1071,13 @@ int iwctl_siwrts(struct net_device *dev,
*/
int iwctl_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRTS \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRTS \n");
wrq->value = pDevice->wRTSThreshold;
wrq->disabled = (wrq->value >= 2312);
wrq->fixed = 1;
@@ -1140,26 +1090,24 @@ int iwctl_giwrts(struct net_device *dev,
*/
int iwctl_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- int rc = 0;
- int fthr = wrq->value;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFRAG \n");
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ int rc = 0;
+ int fthr = wrq->value;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWFRAG \n");
- if (wrq->disabled)
+ if (wrq->disabled)
fthr = 2312;
- if((fthr < 256) || (fthr > 2312)) {
+ if ((fthr < 256) || (fthr > 2312)) {
rc = -EINVAL;
- }else {
- fthr &= ~0x1; // Get an even value
- pDevice->wFragmentationThreshold = (u16)fthr;
- }
+ } else {
+ fthr &= ~0x1; // Get an even value
+ pDevice->wFragmentationThreshold = (u16)fthr;
+ }
return rc;
}
@@ -1169,13 +1117,13 @@ int iwctl_siwfrag(struct net_device *dev,
*/
int iwctl_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFRAG \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWFRAG \n");
wrq->value = pDevice->wFragmentationThreshold;
wrq->disabled = (wrq->value >= 2312);
wrq->fixed = 1;
@@ -1183,21 +1131,18 @@ int iwctl_giwfrag(struct net_device *dev,
return 0;
}
-
-
/*
* Wireless Handler : set retry threshold
*/
int iwctl_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- int rc = 0;
-
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ int rc = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRETRY \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWRETRY \n");
if (wrq->disabled) {
rc = -EINVAL;
@@ -1205,7 +1150,7 @@ int iwctl_siwretry(struct net_device *dev,
}
if (wrq->flags & IW_RETRY_LIMIT) {
- if(wrq->flags & IW_RETRY_MAX)
+ if (wrq->flags & IW_RETRY_MAX)
pDevice->byLongRetryLimit = wrq->value;
else if (wrq->flags & IW_RETRY_MIN)
pDevice->byShortRetryLimit = wrq->value;
@@ -1219,7 +1164,6 @@ int iwctl_siwretry(struct net_device *dev,
pDevice->wMaxTransmitMSDULifetime = wrq->value;
}
-
return rc;
}
@@ -1227,45 +1171,43 @@ int iwctl_siwretry(struct net_device *dev,
* Wireless Handler : get retry threshold
*/
int iwctl_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRETRY \n");
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWRETRY \n");
wrq->disabled = 0; // Can't be disabled
// Note : by default, display the min retry number
- if((wrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+ if ((wrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
wrq->flags = IW_RETRY_LIFETIME;
wrq->value = (int)pDevice->wMaxTransmitMSDULifetime; //ms
- } else if((wrq->flags & IW_RETRY_MAX)) {
+ } else if ((wrq->flags & IW_RETRY_MAX)) {
wrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
wrq->value = (int)pDevice->byLongRetryLimit;
} else {
wrq->flags = IW_RETRY_LIMIT;
wrq->value = (int)pDevice->byShortRetryLimit;
- if((int)pDevice->byShortRetryLimit != (int)pDevice->byLongRetryLimit)
+ if ((int)pDevice->byShortRetryLimit != (int)pDevice->byLongRetryLimit)
wrq->flags |= IW_RETRY_MIN;
}
-
return 0;
}
-
/*
* Wireless Handler : set encode mode
*/
int iwctl_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
unsigned long dwKeyIndex = (unsigned long)(wrq->flags & IW_ENCODE_INDEX);
- int ii,uu, rc = 0;
+ int ii, uu, rc = 0;
int index = (wrq->flags & IW_ENCODE_INDEX);
//2007-0207-07,<Modify> by EinsnLiu
@@ -1281,192 +1223,182 @@ int iwctl_siwencode(struct net_device *dev,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n");
-if((wrq->flags & IW_ENCODE_DISABLED)==0){
- //Not disable encryption
+ if ((wrq->flags & IW_ENCODE_DISABLED) == 0) {
+ //Not disable encryption
- if (dwKeyIndex > WLAN_WEP_NKEYS) {
- rc = -EINVAL;
- return rc;
- }
+ if (dwKeyIndex > WLAN_WEP_NKEYS) {
+ rc = -EINVAL;
+ return rc;
+ }
- if(dwKeyIndex<1&&((wrq->flags&IW_ENCODE_NOKEY)==0)){//set default key
- if(pDevice->byKeyIndex<WLAN_WEP_NKEYS){
- dwKeyIndex=pDevice->byKeyIndex;
+ if (dwKeyIndex < 1 && ((wrq->flags & IW_ENCODE_NOKEY) == 0)) {//set default key
+ if (pDevice->byKeyIndex < WLAN_WEP_NKEYS) {
+ dwKeyIndex = pDevice->byKeyIndex;
+ } else dwKeyIndex = 0;
+ } else dwKeyIndex--;
+
+ // Check the size of the key
+ if (wrq->length > WLAN_WEP232_KEYLEN) {
+ rc = -EINVAL;
+ return rc;
+ }
+
+ if (wrq->length > 0) {//have key
+
+ if (wrq->length == WLAN_WEP232_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
+ } else if (wrq->length == WLAN_WEP104_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
+ } else if (wrq->length == WLAN_WEP40_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
+ } else {//no support length
+ rc = -EINVAL;
+ return rc;
}
- else dwKeyIndex=0;
- }else dwKeyIndex--;
+ memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
+ memcpy(pDevice->abyKey, extra, wrq->length);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyKey: ");
+ for (ii = 0; ii < wrq->length; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
+ }
- // Check the size of the key
- if (wrq->length > WLAN_WEP232_KEYLEN) {
- rc = -EINVAL;
- return rc;
- }
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ spin_lock_irq(&pDevice->lock);
+ KeybSetDefaultKey(&(pDevice->sKey),
+ (unsigned long)(dwKeyIndex | (1 << 31)),
+ wrq->length,
+ NULL,
+ pDevice->abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID
+);
+ spin_unlock_irq(&pDevice->lock);
+ }
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->uKeyLength = wrq->length;
+ pDevice->bTransmitKey = true;
+ pDevice->bEncryptionEnable = true;
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- if(wrq->length>0){//have key
-
- if (wrq->length == WLAN_WEP232_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
- }
- else if (wrq->length == WLAN_WEP104_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
- }
- else if (wrq->length == WLAN_WEP40_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
- }else {//no support length
- rc = -EINVAL;
- return rc;
+ } else if (index > 0) {
+ //when the length is 0 the request only changes the default transmit key index
+ //check the new key if it has a non zero length
+ if (pDevice->bEncryptionEnable == false) {
+ rc = -EINVAL;
+ return rc;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Just set Default key Index:\n");
+ pkeytab = &(pDevice->sKey.KeyTable[MAX_KEY_TABLE - 1]);
+ if (pkeytab->GroupKey[(unsigned char)dwKeyIndex].uKeyLength == 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Default key len is 0\n");
+ rc = -EINVAL;
+ return rc;
+ }
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pkeytab->dwGTKeyIndex = dwKeyIndex | (1 << 31);
+ pkeytab->GroupKey[(unsigned char)dwKeyIndex].dwKeyIndex = dwKeyIndex | (1 << 31);
}
- memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
- memcpy(pDevice->abyKey, extra, wrq->length);
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: ");
- for (ii = 0; ii < wrq->length; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
- }
-
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- spin_lock_irq(&pDevice->lock);
- KeybSetDefaultKey(&(pDevice->sKey),
- (unsigned long)(dwKeyIndex | (1 << 31)),
- wrq->length,
- NULL,
- pDevice->abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID
- );
- spin_unlock_irq(&pDevice->lock);
- }
- pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
- pDevice->uKeyLength = wrq->length;
- pDevice->bTransmitKey = true;
- pDevice->bEncryptionEnable = true;
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-
- }else if(index>0){
- //when the length is 0 the request only changes the default transmit key index
- //check the new key if it has a non zero length
- if(pDevice->bEncryptionEnable==false)
- {
- rc = -EINVAL;
- return rc;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Just set Default key Index:\n");
- pkeytab=&(pDevice->sKey.KeyTable[MAX_KEY_TABLE-1]);
- if(pkeytab->GroupKey[(unsigned char)dwKeyIndex].uKeyLength==0){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Default key len is 0\n");
- rc = -EINVAL;
- return rc;
+
+ } else {//disable the key
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
+ if (pDevice->bEncryptionEnable == false)
+ return 0;
+ pMgmt->bShareKeyAlgorithm = false;
+ pDevice->bEncryptionEnable = false;
+ pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ spin_lock_irq(&pDevice->lock);
+ for (uu = 0; uu < MAX_KEY_TABLE; uu++)
+ MACvDisableKeyEntry(pDevice->PortOffset, uu);
+ spin_unlock_irq(&pDevice->lock);
}
- pDevice->byKeyIndex =(unsigned char)dwKeyIndex;
- pkeytab->dwGTKeyIndex =dwKeyIndex | (1 << 31);
- pkeytab->GroupKey[(unsigned char)dwKeyIndex].dwKeyIndex=dwKeyIndex | (1 << 31);
}
-
-}else {//disable the key
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
- if(pDevice->bEncryptionEnable==false)
- return 0;
- pMgmt->bShareKeyAlgorithm = false;
- pDevice->bEncryptionEnable = false;
- pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- spin_lock_irq(&pDevice->lock);
- for(uu=0;uu<MAX_KEY_TABLE;uu++)
- MACvDisableKeyEntry(pDevice->PortOffset, uu);
- spin_unlock_irq(&pDevice->lock);
- }
-}
//End Modify,Einsn
/*
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWENCODE \n");
- // Check the size of the key
- if (wrq->length > WLAN_WEP232_KEYLEN) {
- rc = -EINVAL;
- return rc;
- }
+ // Check the size of the key
+ if (wrq->length > WLAN_WEP232_KEYLEN) {
+ rc = -EINVAL;
+ return rc;
+ }
- if (dwKeyIndex > WLAN_WEP_NKEYS) {
- rc = -EINVAL;
- return rc;
- }
-
- if (dwKeyIndex > 0)
- dwKeyIndex--;
-
- // Send the key to the card
- if (wrq->length > 0) {
-
- if (wrq->length == WLAN_WEP232_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
- }
- else if (wrq->length == WLAN_WEP104_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
- }
- else if (wrq->length == WLAN_WEP40_KEYLEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
- }
- memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
- memcpy(pDevice->abyKey, extra, wrq->length);
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyKey: ");
- for (ii = 0; ii < wrq->length; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
- }
-
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- spin_lock_irq(&pDevice->lock);
- KeybSetDefaultKey(&(pDevice->sKey),
- (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
- pDevice->uKeyLength,
- NULL,
- pDevice->abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID
- );
- spin_unlock_irq(&pDevice->lock);
- }
- pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
- pDevice->uKeyLength = wrq->length;
- pDevice->bTransmitKey = true;
- pDevice->bEncryptionEnable = true;
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
-
- // Do we want to just set the transmit key index ?
- if ( index < 4 ) {
- pDevice->byKeyIndex = index;
- }
- else if(!(wrq->flags & IW_ENCODE_MODE)) {
- rc = -EINVAL;
- return rc;
- }
- }
- // Read the flags
- if(wrq->flags & IW_ENCODE_DISABLED){
+ if (dwKeyIndex > WLAN_WEP_NKEYS) {
+ rc = -EINVAL;
+ return rc;
+ }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
- pMgmt->bShareKeyAlgorithm = false;
- pDevice->bEncryptionEnable = false;
- pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- if (pDevice->flags & DEVICE_FLAGS_OPENED) {
- spin_lock_irq(&pDevice->lock);
- for(uu=0;uu<MAX_KEY_TABLE;uu++)
- MACvDisableKeyEntry(pDevice->PortOffset, uu);
- spin_unlock_irq(&pDevice->lock);
- }
- }
+ if (dwKeyIndex > 0)
+ dwKeyIndex--;
+
+ // Send the key to the card
+ if (wrq->length > 0) {
+ if (wrq->length == WLAN_WEP232_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 232 bit wep key\n");
+ } else if (wrq->length == WLAN_WEP104_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 104 bit wep key\n");
+ } else if (wrq->length == WLAN_WEP40_KEYLEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Set 40 bit wep key, index= %d\n", (int)dwKeyIndex);
+ }
+ memset(pDevice->abyKey, 0, WLAN_WEP232_KEYLEN);
+ memcpy(pDevice->abyKey, extra, wrq->length);
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyKey: ");
+ for (ii = 0; ii < wrq->length; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pDevice->abyKey[ii]);
+ }
+
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ spin_lock_irq(&pDevice->lock);
+ KeybSetDefaultKey(&(pDevice->sKey),
+ (unsigned long)(pDevice->byKeyIndex | (1 << 31)),
+ pDevice->uKeyLength,
+ NULL,
+ pDevice->abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID
+);
+ spin_unlock_irq(&pDevice->lock);
+ }
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->uKeyLength = wrq->length;
+ pDevice->bTransmitKey = true;
+ pDevice->bEncryptionEnable = true;
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+
+ // Do we want to just set the transmit key index ?
+ if (index < 4) {
+ pDevice->byKeyIndex = index;
+ } else if (!(wrq->flags & IW_ENCODE_MODE)) {
+ rc = -EINVAL;
+ return rc;
+ }
+ }
+ // Read the flags
+ if (wrq->flags & IW_ENCODE_DISABLED) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disable WEP function\n");
+ pMgmt->bShareKeyAlgorithm = false;
+ pDevice->bEncryptionEnable = false;
+ pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ if (pDevice->flags & DEVICE_FLAGS_OPENED) {
+ spin_lock_irq(&pDevice->lock);
+ for (uu=0; uu<MAX_KEY_TABLE; uu++)
+ MACvDisableKeyEntry(pDevice->PortOffset, uu);
+ spin_unlock_irq(&pDevice->lock);
+ }
+ }
*/
- if(wrq->flags & IW_ENCODE_RESTRICTED) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n");
+ if (wrq->flags & IW_ENCODE_RESTRICTED) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & ShareKey System\n");
pMgmt->bShareKeyAlgorithm = true;
}
- if(wrq->flags & IW_ENCODE_OPEN) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n");
+ if (wrq->flags & IW_ENCODE_OPEN) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enable WEP & Open System\n");
pMgmt->bShareKeyAlgorithm = false;
}
return rc;
@@ -1475,80 +1407,78 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){
/*
* Wireless Handler : get encode mode
*/
- /*
-int iwctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
-{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int rc = 0;
- char abyKey[WLAN_WEP232_KEYLEN];
- unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
- PSKeyItem pKey = NULL;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
+/*
+ int iwctl_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra) {
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ int rc = 0;
+ char abyKey[WLAN_WEP232_KEYLEN];
+ unsigned int index = (unsigned int)(wrq->flags & IW_ENCODE_INDEX);
+ PSKeyItem pKey = NULL;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWENCODE\n");
//2007-0207-06,<Add> by EinsnLiu
//the key index in iwconfig is 1-4 when our driver is 0-3
//so it can't be used directly.
//if the index is 0,we should used the index set by driver.
- if (index > WLAN_WEP_NKEYS) {
- rc = -EINVAL;
- return rc;
- }
- if(index<1){//set default key
- if(pDevice->byKeyIndex<WLAN_WEP_NKEYS){
- index=pDevice->byKeyIndex;
- }
- else index=0;
- }else index--;
+if (index > WLAN_WEP_NKEYS) {
+rc = -EINVAL;
+return rc;
+}
+if (index<1) {//set default key
+if (pDevice->byKeyIndex<WLAN_WEP_NKEYS) {
+index=pDevice->byKeyIndex;
+}
+else index=0;
+} else index--;
//End Add,Einsn
- memset(abyKey, 0, sizeof(abyKey));
- // Check encryption mode
- wrq->flags = IW_ENCODE_NOKEY;
- // Is WEP enabled ???
- if (pDevice->bEncryptionEnable)
- wrq->flags |= IW_ENCODE_ENABLED;
- else
- wrq->flags |= IW_ENCODE_DISABLED;
+memset(abyKey, 0, sizeof(abyKey));
+// Check encryption mode
+wrq->flags = IW_ENCODE_NOKEY;
+// Is WEP enabled ???
+if (pDevice->bEncryptionEnable)
+wrq->flags |= IW_ENCODE_ENABLED;
+else
+wrq->flags |= IW_ENCODE_DISABLED;
- if (pMgmt->bShareKeyAlgorithm)
- wrq->flags |= IW_ENCODE_RESTRICTED;
- else
- wrq->flags |= IW_ENCODE_OPEN;
+if (pMgmt->bShareKeyAlgorithm)
+wrq->flags |= IW_ENCODE_RESTRICTED;
+else
+wrq->flags |= IW_ENCODE_OPEN;
- if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)){
- wrq->length = pKey->uKeyLength;
- memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
+if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)) {
+wrq->length = pKey->uKeyLength;
+memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
//2007-0207-06,<Modify> by EinsnLiu
//only get key success need to copy data
//index should +1.
//there is not necessary to return -EINVAL when get key failed
//if return -EINVAL,the encryption item can't be display by the command "iwconfig".
- wrq->flags |= index+1;
- memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
- }
-
- //else {
- // rc = -EINVAL;
- // return rc;
- // }
+wrq->flags |= index+1;
+memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
+}
+//else {
+// rc = -EINVAL;
+// return rc;
+// }
//End Modify,Einsn
- return 0;
+return 0;
}
*/
//2008-0409-06, <Add> by Einsn Liu
int iwctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
@@ -1562,13 +1492,13 @@ int iwctl_giwencode(struct net_device *dev,
if (index > WLAN_WEP_NKEYS) {
return -EINVAL;
}
- if(index<1){//get default key
- if(pDevice->byKeyIndex<WLAN_WEP_NKEYS){
- index=pDevice->byKeyIndex;
- } else
- index=0;
- }else
- index--;
+ if (index < 1) {//get default key
+ if (pDevice->byKeyIndex < WLAN_WEP_NKEYS) {
+ index = pDevice->byKeyIndex;
+ } else
+ index = 0;
+ } else
+ index--;
memset(abyKey, 0, WLAN_WEP232_KEYLEN);
// Check encryption mode
@@ -1583,18 +1513,18 @@ int iwctl_giwencode(struct net_device *dev,
wrq->flags |= IW_ENCODE_RESTRICTED;
else
wrq->flags |= IW_ENCODE_OPEN;
- wrq->length=0;
-
- if((index==0)&&(pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled||
- pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)){//get wpa pairwise key
- if (KeybGetKey(&(pDevice->sKey),pMgmt->abyCurrBSSID, 0xffffffff, &pKey)){
- wrq->length = pKey->uKeyLength;
- memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
- memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
- }
- }else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)){
+ wrq->length = 0;
+
+ if ((index == 0) && (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled ||
+ pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)) {//get wpa pairwise key
+ if (KeybGetKey(&(pDevice->sKey), pMgmt->abyCurrBSSID, 0xffffffff, &pKey)) {
wrq->length = pKey->uKeyLength;
- memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
+ memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
+ memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
+ }
+ } else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (unsigned char)index , &pKey)) {
+ wrq->length = pKey->uKeyLength;
+ memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
}
@@ -1603,24 +1533,23 @@ int iwctl_giwencode(struct net_device *dev,
return 0;
}
-
/*
* Wireless Handler : set power mode
*/
int iwctl_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int rc = 0;
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ int rc = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER \n");
- if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
- rc = -EINVAL;
- return rc;
+ if (!(pDevice->flags & DEVICE_FLAGS_OPENED)) {
+ rc = -EINVAL;
+ return rc;
}
if (wrq->disabled) {
@@ -1629,23 +1558,23 @@ int iwctl_siwpower(struct net_device *dev,
return rc;
}
if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- pDevice->ePSMode = WMAC_POWER_FAST;
- PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
+ pDevice->ePSMode = WMAC_POWER_FAST;
+ PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
} else if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- pDevice->ePSMode = WMAC_POWER_FAST;
- PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
+ pDevice->ePSMode = WMAC_POWER_FAST;
+ PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
}
switch (wrq->flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n");
rc = -EINVAL;
break;
case IW_POWER_ALL_R:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ALL_R \n");
rc = -EINVAL;
case IW_POWER_ON:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_ON \n");
break;
default:
rc = -EINVAL;
@@ -1658,21 +1587,19 @@ int iwctl_siwpower(struct net_device *dev,
* Wireless Handler : get power mode
*/
int iwctl_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int mode = pDevice->ePSMode;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPOWER \n");
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ int mode = pDevice->ePSMode;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWPOWER \n");
wrq->disabled = (mode == WMAC_POWER_CAM);
if (wrq->disabled)
- return 0;
+ return 0;
if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
wrq->value = (int)((pMgmt->wListenInterval * pMgmt->wCurrBeaconPeriod) << 10);
@@ -1686,30 +1613,27 @@ int iwctl_giwpower(struct net_device *dev,
return 0;
}
-
/*
* Wireless Handler : get Sensitivity
*/
int iwctl_giwsens(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- long ldBm;
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ long ldBm;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n");
- if (pDevice->bLinkPass == true) {
- RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
- wrq->value = ldBm;
- }
- else {
- wrq->value = 0;
- };
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS \n");
+ if (pDevice->bLinkPass == true) {
+ RFvRSSITodBm(pDevice, (unsigned char)(pDevice->uCurrRSSI), &ldBm);
+ wrq->value = ldBm;
+ } else {
+ wrq->value = 0;
+ };
wrq->disabled = (wrq->value == 0);
wrq->fixed = 1;
-
return 0;
}
@@ -1717,66 +1641,64 @@ int iwctl_giwsens(struct net_device *dev,
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
int iwctl_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int ret=0;
- static int wpa_version=0; //must be static to save the last value,einsn liu
- static int pairwise=0;
+ int ret = 0;
+ static int wpa_version = 0; //must be static to save the last value,einsn liu
+ static int pairwise = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWAUTH \n");
switch (wrq->flags & IW_AUTH_INDEX) {
case IW_AUTH_WPA_VERSION:
wpa_version = wrq->value;
- if(wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
- PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
+ if (wrq->value == IW_AUTH_WPA_VERSION_DISABLED) {
+ PRINT_K("iwctl_siwauth:set WPADEV to disable at 1??????\n");
//pDevice->bWPADevEnable = false;
- }
- else if(wrq->value == IW_AUTH_WPA_VERSION_WPA) {
- PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
- }
- else {
- PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
+ } else if (wrq->value == IW_AUTH_WPA_VERSION_WPA) {
+ PRINT_K("iwctl_siwauth:set WPADEV to WPA1******\n");
+ } else {
+ PRINT_K("iwctl_siwauth:set WPADEV to WPA2******\n");
}
//pDevice->bWPASuppWextEnabled =true;
break;
case IW_AUTH_CIPHER_PAIRWISE:
pairwise = wrq->value;
- if(pairwise == IW_AUTH_CIPHER_CCMP){
+ if (pairwise == IW_AUTH_CIPHER_CCMP) {
pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
- }else if(pairwise == IW_AUTH_CIPHER_TKIP){
+ } else if (pairwise == IW_AUTH_CIPHER_TKIP) {
pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
- }else if(pairwise == IW_AUTH_CIPHER_WEP40||pairwise == IW_AUTH_CIPHER_WEP104){
+ } else if (pairwise == IW_AUTH_CIPHER_WEP40 || pairwise == IW_AUTH_CIPHER_WEP104) {
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- }else if(pairwise == IW_AUTH_CIPHER_NONE){
+ } else if (pairwise == IW_AUTH_CIPHER_NONE) {
//do nothing,einsn liu
- }else pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ } else pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
break;
case IW_AUTH_CIPHER_GROUP:
- if(wpa_version == IW_AUTH_WPA_VERSION_DISABLED)
+ if (wpa_version == IW_AUTH_WPA_VERSION_DISABLED)
break;
- if(pairwise == IW_AUTH_CIPHER_NONE){
- if(wrq->value == IW_AUTH_CIPHER_CCMP){
+ if (pairwise == IW_AUTH_CIPHER_NONE) {
+ if (wrq->value == IW_AUTH_CIPHER_CCMP) {
pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
- }else {
+ } else {
pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
}
}
break;
case IW_AUTH_KEY_MGMT:
- if(wpa_version == IW_AUTH_WPA_VERSION_WPA2){
- if(wrq->value == IW_AUTH_KEY_MGMT_PSK)
+ if (wpa_version == IW_AUTH_WPA_VERSION_WPA2) {
+ if (wrq->value == IW_AUTH_KEY_MGMT_PSK)
pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
else pMgmt->eAuthenMode = WMAC_AUTH_WPA2;
- }else if(wpa_version == IW_AUTH_WPA_VERSION_WPA){
- if(wrq->value == 0){
+ } else if (wpa_version == IW_AUTH_WPA_VERSION_WPA) {
+ if (wrq->value == 0) {
pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
- }else if(wrq->value == IW_AUTH_KEY_MGMT_PSK)
+ } else if (wrq->value == IW_AUTH_KEY_MGMT_PSK)
pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
else pMgmt->eAuthenMode = WMAC_AUTH_WPA;
}
@@ -1787,10 +1709,10 @@ int iwctl_siwauth(struct net_device *dev,
case IW_AUTH_DROP_UNENCRYPTED:
break;
case IW_AUTH_80211_AUTH_ALG:
- if(wrq->value==IW_AUTH_ALG_OPEN_SYSTEM){
- pMgmt->bShareKeyAlgorithm=false;
- }else if(wrq->value==IW_AUTH_ALG_SHARED_KEY){
- pMgmt->bShareKeyAlgorithm=true;
+ if (wrq->value == IW_AUTH_ALG_OPEN_SYSTEM) {
+ pMgmt->bShareKeyAlgorithm = false;
+ } else if (wrq->value == IW_AUTH_ALG_SHARED_KEY) {
+ pMgmt->bShareKeyAlgorithm = true;
}
break;
case IW_AUTH_WPA_ENABLED:
@@ -1803,7 +1725,7 @@ int iwctl_siwauth(struct net_device *dev,
break;
case IW_AUTH_PRIVACY_INVOKED:
pDevice->bEncryptionEnable = !!wrq->value;
- if(pDevice->bEncryptionEnable == false){
+ if (pDevice->bEncryptionEnable == false) {
wpa_version = 0;
pairwise = 0;
pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
@@ -1818,220 +1740,214 @@ int iwctl_siwauth(struct net_device *dev,
break;
}
/*
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_version = %d\n",wpa_version);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise = %d\n",pairwise);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->eEncryptionStatus = %d\n",pDevice->eEncryptionStatus);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->eAuthenMode = %d\n",pMgmt->eAuthenMode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"true":"false");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"true":"false");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADevEnable = %s\n",pDevice->bWPADevEnable?"true":"false");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_version = %d\n",wpa_version);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise = %d\n",pairwise);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->eEncryptionStatus = %d\n",pDevice->eEncryptionStatus);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->eAuthenMode = %d\n",pMgmt->eAuthenMode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pMgmt->bShareKeyAlgorithm = %s\n",pMgmt->bShareKeyAlgorithm?"true":"false");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bEncryptionEnable = %s\n",pDevice->bEncryptionEnable?"true":"false");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pDevice->bWPADevEnable = %s\n",pDevice->bWPADevEnable?"true":"false");
*/
- return ret;
+ return ret;
}
-
int iwctl_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra)
{
return -EOPNOTSUPP;
}
-
-
int iwctl_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int ret=0;
+ int ret = 0;
- if(wrq->length){
+ if (wrq->length) {
if ((wrq->length < 2) || (extra[1]+2 != wrq->length)) {
ret = -EINVAL;
goto out;
}
- if(wrq->length > MAX_WPA_IE_LEN){
+ if (wrq->length > MAX_WPA_IE_LEN) {
ret = -ENOMEM;
goto out;
}
memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN);
- if(copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)){
+ if (copy_from_user(pMgmt->abyWPAIE, extra, wrq->length)) {
ret = -EFAULT;
goto out;
}
pMgmt->wWPAIELen = wrq->length;
- }else {
+ } else {
memset(pMgmt->abyWPAIE, 0, MAX_WPA_IE_LEN);
pMgmt->wWPAIELen = 0;
}
- out://not completely ...not necessary in wpa_supplicant 0.5.8
+out://not completely ...not necessary in wpa_supplicant 0.5.8
return ret;
}
int iwctl_giwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- int ret=0;
+ int ret = 0;
int space = wrq->length;
wrq->length = 0;
- if(pMgmt->wWPAIELen > 0){
+ if (pMgmt->wWPAIELen > 0) {
wrq->length = pMgmt->wWPAIELen;
- if(pMgmt->wWPAIELen <= space){
- if(copy_to_user(extra, pMgmt->abyWPAIE, pMgmt->wWPAIELen)){
+ if (pMgmt->wWPAIELen <= space) {
+ if (copy_to_user(extra, pMgmt->abyWPAIE, pMgmt->wWPAIELen)) {
ret = -EFAULT;
}
- }else
+ } else
ret = -E2BIG;
}
return ret;
}
-
int iwctl_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- PSDevice pDevice = (PSDevice)netdev_priv(dev);
- struct iw_encode_ext *ext = (struct iw_encode_ext*)extra;
- struct viawget_wpa_param *param=NULL;
+ PSDevice pDevice = (PSDevice)netdev_priv(dev);
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ struct viawget_wpa_param *param = NULL;
//original member
- wpa_alg alg_name;
- u8 addr[6];
- int key_idx, set_tx=0;
- u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 key[64];
- size_t seq_len=0,key_len=0;
+ wpa_alg alg_name;
+ u8 addr[6];
+ int key_idx, set_tx = 0;
+ u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+ u8 key[64];
+ size_t seq_len = 0, key_len = 0;
//
- // int ii;
- u8 *buf;
- size_t blen;
- u8 key_array[64];
- int ret=0;
+ // int ii;
+ u8 *buf;
+ size_t blen;
+ u8 key_array[64];
+ int ret = 0;
-PRINT_K("SIOCSIWENCODEEXT...... \n");
+ PRINT_K("SIOCSIWENCODEEXT...... \n");
-blen = sizeof(*param);
-buf = kmalloc((int)blen, (int)GFP_KERNEL);
-if (buf == NULL)
- return -ENOMEM;
-memset(buf, 0, blen);
-param = (struct viawget_wpa_param *) buf;
+ blen = sizeof(*param);
+ buf = kmalloc((int)blen, (int)GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+ memset(buf, 0, blen);
+ param = (struct viawget_wpa_param *)buf;
//recover alg_name
-switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- alg_name = WPA_ALG_NONE;
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ alg_name = WPA_ALG_NONE;
break;
- case IW_ENCODE_ALG_WEP:
- alg_name = WPA_ALG_WEP;
+ case IW_ENCODE_ALG_WEP:
+ alg_name = WPA_ALG_WEP;
break;
- case IW_ENCODE_ALG_TKIP:
- alg_name = WPA_ALG_TKIP;
+ case IW_ENCODE_ALG_TKIP:
+ alg_name = WPA_ALG_TKIP;
break;
- case IW_ENCODE_ALG_CCMP:
- alg_name = WPA_ALG_CCMP;
+ case IW_ENCODE_ALG_CCMP:
+ alg_name = WPA_ALG_CCMP;
break;
- default:
- PRINT_K("Unknown alg = %d\n",ext->alg);
- ret= -ENOMEM;
+ default:
+ PRINT_K("Unknown alg = %d\n", ext->alg);
+ ret = -ENOMEM;
goto error;
- }
+ }
//recover addr
- memcpy(addr, ext->addr.sa_data, ETH_ALEN);
+ memcpy(addr, ext->addr.sa_data, ETH_ALEN);
//recover key_idx
- key_idx = (wrq->flags&IW_ENCODE_INDEX) - 1;
+ key_idx = (wrq->flags&IW_ENCODE_INDEX) - 1;
//recover set_tx
-if(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
- set_tx = 1;
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
+ set_tx = 1;
//recover seq,seq_len
- if(ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
- seq_len=IW_ENCODE_SEQ_MAX_SIZE;
- memcpy(seq, ext->rx_seq, seq_len);
- }
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ seq_len = IW_ENCODE_SEQ_MAX_SIZE;
+ memcpy(seq, ext->rx_seq, seq_len);
+ }
//recover key,key_len
-if(ext->key_len) {
- key_len=ext->key_len;
- memcpy(key, &ext->key[0], key_len);
+ if (ext->key_len) {
+ key_len = ext->key_len;
+ memcpy(key, &ext->key[0], key_len);
}
-memset(key_array, 0, 64);
-if ( key_len > 0) {
- memcpy(key_array, key, key_len);
- if (key_len == 32) {
- // notice ! the oder
- memcpy(&key_array[16], &key[24], 8);
- memcpy(&key_array[24], &key[16], 8);
- }
+ memset(key_array, 0, 64);
+ if (key_len > 0) {
+ memcpy(key_array, key, key_len);
+ if (key_len == 32) {
+ // notice ! the oder
+ memcpy(&key_array[16], &key[24], 8);
+ memcpy(&key_array[24], &key[16], 8);
+ }
}
/**************Translate iw_encode_ext to viawget_wpa_param****************/
-memcpy(param->addr, addr, ETH_ALEN);
-param->u.wpa_key.alg_name = (int)alg_name;
-param->u.wpa_key.set_tx = set_tx;
-param->u.wpa_key.key_index = key_idx;
-param->u.wpa_key.key_len = key_len;
-param->u.wpa_key.key = (u8 *)key_array;
-param->u.wpa_key.seq = (u8 *)seq;
-param->u.wpa_key.seq_len = seq_len;
+ memcpy(param->addr, addr, ETH_ALEN);
+ param->u.wpa_key.alg_name = (int)alg_name;
+ param->u.wpa_key.set_tx = set_tx;
+ param->u.wpa_key.key_index = key_idx;
+ param->u.wpa_key.key_len = key_len;
+ param->u.wpa_key.key = (u8 *)key_array;
+ param->u.wpa_key.seq = (u8 *)seq;
+ param->u.wpa_key.seq_len = seq_len;
//****set if current action is Network Manager count??
//****this method is so foolish,but there is no other way???
-if(param->u.wpa_key.alg_name == WPA_ALG_NONE) {
- if(param->u.wpa_key.key_index ==0) {
- pDevice->bwextcount++;
- }
- if((pDevice->bwextcount == 1)&&(param->u.wpa_key.key_index ==1)) {
- pDevice->bwextcount++;
- }
- if((pDevice->bwextcount ==2)&&(param->u.wpa_key.key_index ==2)) {
- pDevice->bwextcount++;
+ if (param->u.wpa_key.alg_name == WPA_ALG_NONE) {
+ if (param->u.wpa_key.key_index == 0) {
+ pDevice->bwextcount++;
+ }
+ if ((pDevice->bwextcount == 1) && (param->u.wpa_key.key_index == 1)) {
+ pDevice->bwextcount++;
+ }
+ if ((pDevice->bwextcount == 2) && (param->u.wpa_key.key_index == 2)) {
+ pDevice->bwextcount++;
+ }
+ if ((pDevice->bwextcount == 3) && (param->u.wpa_key.key_index == 3)) {
+ pDevice->bwextcount++;
+ }
+ }
+ if (pDevice->bwextcount == 4) {
+ printk("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n");
+ pDevice->bwextcount = 0;
+ pDevice->bWPASuppWextEnabled = true;
}
- if((pDevice->bwextcount ==3)&&(param->u.wpa_key.key_index ==3)) {
- pDevice->bwextcount++;
- }
- }
-if( pDevice->bwextcount == 4) {
- printk("SIOCSIWENCODEEXT:Enable WPA WEXT SUPPORT!!!!!\n");
- pDevice->bwextcount=0;
- pDevice->bWPASuppWextEnabled = true;
- }
//******
- spin_lock_irq(&pDevice->lock);
- ret = wpa_set_keys(pDevice, param, true);
- spin_unlock_irq(&pDevice->lock);
+ spin_lock_irq(&pDevice->lock);
+ ret = wpa_set_keys(pDevice, param, true);
+ spin_unlock_irq(&pDevice->lock);
error:
-kfree(param);
+ kfree(param);
return ret;
}
-
-
int iwctl_giwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
- return -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
int iwctl_siwmlme(struct net_device *dev,
- struct iw_request_info * info,
- struct iw_point *wrq,
- char *extra)
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra)
{
PSDevice pDevice = (PSDevice)netdev_priv(dev);
PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
@@ -2039,21 +1955,21 @@ int iwctl_siwmlme(struct net_device *dev,
//u16 reason = cpu_to_le16(mlme->reason_code);
int ret = 0;
- if(memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)){
+ if (memcmp(pMgmt->abyCurrBSSID, mlme->addr.sa_data, ETH_ALEN)) {
ret = -EINVAL;
return ret;
}
- switch(mlme->cmd){
+ switch (mlme->cmd) {
case IW_MLME_DEAUTH:
//this command seems to be not complete,please test it --einsnliu
//bScheduleCommand((void *) pDevice, WLAN_CMD_DEAUTH, (unsigned char *)&reason);
break;
case IW_MLME_DISASSOC:
- if(pDevice->bLinkPass == true){
- printk("iwctl_siwmlme--->send DISASSOCIATE\n");
- //clear related flags
- memset(pMgmt->abyDesireBSSID, 0xFF,6);
- KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
+ if (pDevice->bLinkPass == true) {
+ printk("iwctl_siwmlme--->send DISASSOCIATE\n");
+ //clear related flags
+ memset(pMgmt->abyDesireBSSID, 0xFF, 6);
+ KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
}
break;
@@ -2062,109 +1978,106 @@ int iwctl_siwmlme(struct net_device *dev,
}
return ret;
-
}
#endif
-
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
-
/*
-static const iw_handler iwctl_handler[] =
-{
- (iw_handler) iwctl_commit, // SIOCSIWCOMMIT
- (iw_handler) iwctl_giwname, // SIOCGIWNAME
- (iw_handler) NULL, // SIOCSIWNWID
- (iw_handler) NULL, // SIOCGIWNWID
- (iw_handler) iwctl_siwfreq, // SIOCSIWFREQ
- (iw_handler) iwctl_giwfreq, // SIOCGIWFREQ
- (iw_handler) iwctl_siwmode, // SIOCSIWMODE
- (iw_handler) iwctl_giwmode, // SIOCGIWMODE
- (iw_handler) NULL, // SIOCSIWSENS
- (iw_handler) iwctl_giwsens, // SIOCGIWSENS
- (iw_handler) NULL, // SIOCSIWRANGE
- (iw_handler) iwctl_giwrange, // SIOCGIWRANGE
- (iw_handler) NULL, // SIOCSIWPRIV
- (iw_handler) NULL, // SIOCGIWPRIV
- (iw_handler) NULL, // SIOCSIWSTATS
- (iw_handler) NULL, // SIOCGIWSTATS
- (iw_handler) NULL, // SIOCSIWSPY
- (iw_handler) NULL, // SIOCGIWSPY
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // -- hole --
- (iw_handler) iwctl_siwap, // SIOCSIWAP
- (iw_handler) iwctl_giwap, // SIOCGIWAP
- (iw_handler) NULL, // -- hole -- 0x16
- (iw_handler) iwctl_giwaplist, // SIOCGIWAPLIST
- (iw_handler) iwctl_siwscan, // SIOCSIWSCAN
- (iw_handler) iwctl_giwscan, // SIOCGIWSCAN
- (iw_handler) iwctl_siwessid, // SIOCSIWESSID
- (iw_handler) iwctl_giwessid, // SIOCGIWESSID
- (iw_handler) NULL, // SIOCSIWNICKN
- (iw_handler) NULL, // SIOCGIWNICKN
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // -- hole --
- (iw_handler) iwctl_siwrate, // SIOCSIWRATE 0x20
- (iw_handler) iwctl_giwrate, // SIOCGIWRATE
- (iw_handler) iwctl_siwrts, // SIOCSIWRTS
- (iw_handler) iwctl_giwrts, // SIOCGIWRTS
- (iw_handler) iwctl_siwfrag, // SIOCSIWFRAG
- (iw_handler) iwctl_giwfrag, // SIOCGIWFRAG
- (iw_handler) NULL, // SIOCSIWTXPOW
- (iw_handler) NULL, // SIOCGIWTXPOW
- (iw_handler) iwctl_siwretry, // SIOCSIWRETRY
- (iw_handler) iwctl_giwretry, // SIOCGIWRETRY
- (iw_handler) iwctl_siwencode, // SIOCSIWENCODE
- (iw_handler) iwctl_giwencode, // SIOCGIWENCODE
- (iw_handler) iwctl_siwpower, // SIOCSIWPOWER
- (iw_handler) iwctl_giwpower, // SIOCGIWPOWER
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // -- hole --
- (iw_handler) iwctl_siwgenie, // SIOCSIWGENIE
- (iw_handler) iwctl_giwgenie, // SIOCGIWGENIE
- (iw_handler) iwctl_siwauth, // SIOCSIWAUTH
- (iw_handler) iwctl_giwauth, // SIOCGIWAUTH
- (iw_handler) iwctl_siwencodeext, // SIOCSIWENCODEEXT
- (iw_handler) iwctl_giwencodeext, // SIOCGIWENCODEEXT
- (iw_handler) NULL, // SIOCSIWPMKSA
- (iw_handler) NULL, // -- hole --
-
-};
+ static const iw_handler iwctl_handler[] =
+ {
+ (iw_handler) iwctl_commit, // SIOCSIWCOMMIT
+ (iw_handler) iwctl_giwname, // SIOCGIWNAME
+ (iw_handler) NULL, // SIOCSIWNWID
+ (iw_handler) NULL, // SIOCGIWNWID
+ (iw_handler) iwctl_siwfreq, // SIOCSIWFREQ
+ (iw_handler) iwctl_giwfreq, // SIOCGIWFREQ
+ (iw_handler) iwctl_siwmode, // SIOCSIWMODE
+ (iw_handler) iwctl_giwmode, // SIOCGIWMODE
+ (iw_handler) NULL, // SIOCSIWSENS
+ (iw_handler) iwctl_giwsens, // SIOCGIWSENS
+ (iw_handler) NULL, // SIOCSIWRANGE
+ (iw_handler) iwctl_giwrange, // SIOCGIWRANGE
+ (iw_handler) NULL, // SIOCSIWPRIV
+ (iw_handler) NULL, // SIOCGIWPRIV
+ (iw_handler) NULL, // SIOCSIWSTATS
+ (iw_handler) NULL, // SIOCGIWSTATS
+ (iw_handler) NULL, // SIOCSIWSPY
+ (iw_handler) NULL, // SIOCGIWSPY
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) iwctl_siwap, // SIOCSIWAP
+ (iw_handler) iwctl_giwap, // SIOCGIWAP
+ (iw_handler) NULL, // -- hole -- 0x16
+ (iw_handler) iwctl_giwaplist, // SIOCGIWAPLIST
+ (iw_handler) iwctl_siwscan, // SIOCSIWSCAN
+ (iw_handler) iwctl_giwscan, // SIOCGIWSCAN
+ (iw_handler) iwctl_siwessid, // SIOCSIWESSID
+ (iw_handler) iwctl_giwessid, // SIOCGIWESSID
+ (iw_handler) NULL, // SIOCSIWNICKN
+ (iw_handler) NULL, // SIOCGIWNICKN
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) iwctl_siwrate, // SIOCSIWRATE 0x20
+ (iw_handler) iwctl_giwrate, // SIOCGIWRATE
+ (iw_handler) iwctl_siwrts, // SIOCSIWRTS
+ (iw_handler) iwctl_giwrts, // SIOCGIWRTS
+ (iw_handler) iwctl_siwfrag, // SIOCSIWFRAG
+ (iw_handler) iwctl_giwfrag, // SIOCGIWFRAG
+ (iw_handler) NULL, // SIOCSIWTXPOW
+ (iw_handler) NULL, // SIOCGIWTXPOW
+ (iw_handler) iwctl_siwretry, // SIOCSIWRETRY
+ (iw_handler) iwctl_giwretry, // SIOCGIWRETRY
+ (iw_handler) iwctl_siwencode, // SIOCSIWENCODE
+ (iw_handler) iwctl_giwencode, // SIOCGIWENCODE
+ (iw_handler) iwctl_siwpower, // SIOCSIWPOWER
+ (iw_handler) iwctl_giwpower, // SIOCGIWPOWER
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) iwctl_siwgenie, // SIOCSIWGENIE
+ (iw_handler) iwctl_giwgenie, // SIOCGIWGENIE
+ (iw_handler) iwctl_siwauth, // SIOCSIWAUTH
+ (iw_handler) iwctl_giwauth, // SIOCGIWAUTH
+ (iw_handler) iwctl_siwencodeext, // SIOCSIWENCODEEXT
+ (iw_handler) iwctl_giwencodeext, // SIOCGIWENCODEEXT
+ (iw_handler) NULL, // SIOCSIWPMKSA
+ (iw_handler) NULL, // -- hole --
+
+ };
*/
static const iw_handler iwctl_handler[] =
{
(iw_handler) iwctl_commit, // SIOCSIWCOMMIT
- (iw_handler) NULL, // SIOCGIWNAME
- (iw_handler) NULL, // SIOCSIWNWID
- (iw_handler) NULL, // SIOCGIWNWID
+ (iw_handler) NULL, // SIOCGIWNAME
+ (iw_handler) NULL, // SIOCSIWNWID
+ (iw_handler) NULL, // SIOCGIWNWID
(iw_handler) NULL, // SIOCSIWFREQ
(iw_handler) NULL, // SIOCGIWFREQ
(iw_handler) NULL, // SIOCSIWMODE
(iw_handler) NULL, // SIOCGIWMODE
- (iw_handler) NULL, // SIOCSIWSENS
- (iw_handler) NULL, // SIOCGIWSENS
- (iw_handler) NULL, // SIOCSIWRANGE
- (iw_handler) iwctl_giwrange, // SIOCGIWRANGE
- (iw_handler) NULL, // SIOCSIWPRIV
- (iw_handler) NULL, // SIOCGIWPRIV
- (iw_handler) NULL, // SIOCSIWSTATS
- (iw_handler) NULL, // SIOCGIWSTATS
- (iw_handler) NULL, // SIOCSIWSPY
- (iw_handler) NULL, // SIOCGIWSPY
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // SIOCSIWAP
- (iw_handler) NULL, // SIOCGIWAP
- (iw_handler) NULL, // -- hole -- 0x16
- (iw_handler) NULL, // SIOCGIWAPLIST
- (iw_handler) iwctl_siwscan, // SIOCSIWSCAN
- (iw_handler) iwctl_giwscan, // SIOCGIWSCAN
+ (iw_handler) NULL, // SIOCSIWSENS
+ (iw_handler) NULL, // SIOCGIWSENS
+ (iw_handler) NULL, // SIOCSIWRANGE
+ (iw_handler) iwctl_giwrange, // SIOCGIWRANGE
+ (iw_handler) NULL, // SIOCSIWPRIV
+ (iw_handler) NULL, // SIOCGIWPRIV
+ (iw_handler) NULL, // SIOCSIWSTATS
+ (iw_handler) NULL, // SIOCGIWSTATS
+ (iw_handler) NULL, // SIOCSIWSPY
+ (iw_handler) NULL, // SIOCGIWSPY
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // SIOCSIWAP
+ (iw_handler) NULL, // SIOCGIWAP
+ (iw_handler) NULL, // -- hole -- 0x16
+ (iw_handler) NULL, // SIOCGIWAPLIST
+ (iw_handler) iwctl_siwscan, // SIOCSIWSCAN
+ (iw_handler) iwctl_giwscan, // SIOCGIWSCAN
(iw_handler) NULL, // SIOCSIWESSID
(iw_handler) NULL, // SIOCGIWESSID
(iw_handler) NULL, // SIOCSIWNICKN
@@ -2187,33 +2100,29 @@ static const iw_handler iwctl_handler[] =
(iw_handler) NULL, // SIOCGIWPOWER
//2008-0409-07, <Add> by Einsn Liu
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // -- hole --
- (iw_handler) NULL, // SIOCSIWGENIE
- (iw_handler) NULL, // SIOCGIWGENIE
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // SIOCSIWGENIE
+ (iw_handler) NULL, // SIOCGIWGENIE
(iw_handler) NULL, // SIOCSIWAUTH
(iw_handler) NULL, // SIOCGIWAUTH
(iw_handler) NULL, // SIOCSIWENCODEEXT
(iw_handler) NULL, // SIOCGIWENCODEEXT
- (iw_handler) NULL, // SIOCSIWPMKSA
- (iw_handler) NULL, // -- hole --
+ (iw_handler) NULL, // SIOCSIWPMKSA
+ (iw_handler) NULL, // -- hole --
};
-
static const iw_handler iwctl_private_handler[] =
{
NULL, // SIOCIWFIRSTPRIV
};
-
struct iw_priv_args iwctl_private_args[] = {
-{ IOCTL_CMD_SET,
- IW_PRIV_TYPE_CHAR | 1024, 0,
- "set"},
+ { IOCTL_CMD_SET,
+ IW_PRIV_TYPE_CHAR | 1024, 0,
+ "set"},
};
-
-
const struct iw_handler_def iwctl_handler_def =
{
.get_wireless_stats = &iwctl_get_wireless_stats,
@@ -2222,7 +2131,7 @@ const struct iw_handler_def iwctl_handler_def =
// .num_private_args = sizeof(iwctl_private_args)/sizeof(struct iw_priv_args),
.num_private = 0,
.num_private_args = 0,
- .standard = (iw_handler *) iwctl_handler,
+ .standard = (iw_handler *)iwctl_handler,
// .private = (iw_handler *) iwctl_private_handler,
// .private_args = (struct iw_priv_args *)iwctl_private_args,
.private = NULL,
diff --git a/drivers/staging/vt6655/iwctl.h b/drivers/staging/vt6655/iwctl.h
index d224f913a624..871bd7c4e716 100644
--- a/drivers/staging/vt6655/iwctl.h
+++ b/drivers/staging/vt6655/iwctl.h
@@ -33,192 +33,184 @@
/*--------------------- Export Definitions -------------------------*/
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
-struct iw_statistics *iwctl_get_wireless_stats (struct net_device *dev);
-
+struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev);
int iwctl_siwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct sockaddr *wrq,
+ char *extra);
int iwctl_giwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
-
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_giwmode(struct net_device *dev,
- struct iw_request_info *info,
- __u32 *wmode,
- char *extra);
+ struct iw_request_info *info,
+ __u32 *wmode,
+ char *extra);
int iwctl_siwmode(struct net_device *dev,
- struct iw_request_info *info,
- __u32 *wmode,
- char *extra);
+ struct iw_request_info *info,
+ __u32 *wmode,
+ char *extra);
int iwctl_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_freq *wrq,
+ char *extra);
int iwctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_freq *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_freq *wrq,
+ char *extra);
int iwctl_giwname(struct net_device *dev,
- struct iw_request_info *info,
- char *wrq,
- char *extra);
+ struct iw_request_info *info,
+ char *wrq,
+ char *extra);
int iwctl_giwsens(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwap(struct net_device *dev,
- struct iw_request_info *info,
- struct sockaddr *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct sockaddr *wrq,
+ char *extra);
int iwctl_giwaplist(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
-
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
//2008-0409-07, <Add> by Einsn Liu
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
int iwctl_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_param *wrq,
+ char *extra);
int iwctl_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_giwgenie(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_giwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
int iwctl_siwmlme(struct net_device *dev,
- struct iw_request_info * info,
- struct iw_point *wrq,
- char *extra);
+ struct iw_request_info *info,
+ struct iw_point *wrq,
+ char *extra);
#endif // #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//End Add -- //2008-0409-07, <Add> by Einsn Liu
-
extern const struct iw_handler_def iwctl_handler_def;
extern const struct iw_priv_args iwctl_private_args;
#endif // __IWCTL_H__
-
-
-
diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c
index 194fedc715fa..92b84b5ea115 100644
--- a/drivers/staging/vt6655/key.c
+++ b/drivers/staging/vt6655/key.c
@@ -45,7 +45,7 @@
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Functions --------------------------*/
@@ -59,31 +59,28 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
static void
-s_vCheckKeyTableValid (PSKeyManagement pTable, unsigned long dwIoBase)
+s_vCheckKeyTableValid(PSKeyManagement pTable, unsigned long dwIoBase)
{
- int i;
-
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- (pTable->KeyTable[i].PairwiseKey.bKeyValid == false) &&
- (pTable->KeyTable[i].GroupKey[0].bKeyValid == false) &&
- (pTable->KeyTable[i].GroupKey[1].bKeyValid == false) &&
- (pTable->KeyTable[i].GroupKey[2].bKeyValid == false) &&
- (pTable->KeyTable[i].GroupKey[3].bKeyValid == false)
- ) {
-
- pTable->KeyTable[i].bInUse = false;
- pTable->KeyTable[i].wKeyCtl = 0;
- pTable->KeyTable[i].bSoftWEP = false;
- MACvDisableKeyEntry(dwIoBase, i);
- }
- }
+ int i;
+
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ (pTable->KeyTable[i].PairwiseKey.bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[0].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[1].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[2].bKeyValid == false) &&
+ (pTable->KeyTable[i].GroupKey[3].bKeyValid == false)
+) {
+ pTable->KeyTable[i].bInUse = false;
+ pTable->KeyTable[i].wKeyCtl = 0;
+ pTable->KeyTable[i].bSoftWEP = false;
+ MACvDisableKeyEntry(dwIoBase, i);
+ }
+ }
}
-
/*--------------------- Export Functions --------------------------*/
-
/*
* Description: Init Key management table
*
@@ -96,27 +93,26 @@ s_vCheckKeyTableValid (PSKeyManagement pTable, unsigned long dwIoBase)
* Return Value: none
*
*/
-void KeyvInitTable (PSKeyManagement pTable, unsigned long dwIoBase)
+void KeyvInitTable(PSKeyManagement pTable, unsigned long dwIoBase)
{
- int i;
- int jj;
-
- for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].bInUse = false;
- pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
- pTable->KeyTable[i].PairwiseKey.pvKeyTable = (void *)&pTable->KeyTable[i];
- for (jj=0; jj < MAX_GROUP_KEY; jj++) {
- pTable->KeyTable[i].GroupKey[jj].bKeyValid = false;
- pTable->KeyTable[i].GroupKey[jj].pvKeyTable = (void *)&pTable->KeyTable[i];
- }
- pTable->KeyTable[i].wKeyCtl = 0;
- pTable->KeyTable[i].dwGTKeyIndex = 0;
- pTable->KeyTable[i].bSoftWEP = false;
- MACvDisableKeyEntry(dwIoBase, i);
- }
+ int i;
+ int jj;
+
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ pTable->KeyTable[i].bInUse = false;
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
+ pTable->KeyTable[i].PairwiseKey.pvKeyTable = (void *)&pTable->KeyTable[i];
+ for (jj = 0; jj < MAX_GROUP_KEY; jj++) {
+ pTable->KeyTable[i].GroupKey[jj].bKeyValid = false;
+ pTable->KeyTable[i].GroupKey[jj].pvKeyTable = (void *)&pTable->KeyTable[i];
+ }
+ pTable->KeyTable[i].wKeyCtl = 0;
+ pTable->KeyTable[i].dwGTKeyIndex = 0;
+ pTable->KeyTable[i].bSoftWEP = false;
+ MACvDisableKeyEntry(dwIoBase, i);
+ }
}
-
/*
* Description: Get Key from table
*
@@ -131,47 +127,43 @@ void KeyvInitTable (PSKeyManagement pTable, unsigned long dwIoBase)
* Return Value: true if found otherwise false
*
*/
-bool KeybGetKey (
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- PSKeyItem *pKey
- )
+bool KeybGetKey(
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ PSKeyItem *pKey
+)
{
- int i;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetKey() \n");
-
- *pKey = NULL;
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
- if (dwKeyIndex == 0xFFFFFFFF) {
- if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
- *pKey = &(pTable->KeyTable[i].PairwiseKey);
- return (true);
- }
- else {
- return (false);
- }
- } else if (dwKeyIndex < MAX_GROUP_KEY) {
- if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == true) {
- *pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex]);
- return (true);
- }
- else {
- return (false);
- }
- }
- else {
- return (false);
- }
- }
- }
- return (false);
+ int i;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybGetKey() \n");
+
+ *pKey = NULL;
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ if (dwKeyIndex == 0xFFFFFFFF) {
+ if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
+ *pKey = &(pTable->KeyTable[i].PairwiseKey);
+ return true;
+ } else {
+ return false;
+ }
+ } else if (dwKeyIndex < MAX_GROUP_KEY) {
+ if (pTable->KeyTable[i].GroupKey[dwKeyIndex].bKeyValid == true) {
+ *pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex]);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
}
-
/*
* Description: Set Key to table
*
@@ -189,165 +181,162 @@ bool KeybGetKey (
* Return Value: true if success otherwise false
*
*/
-bool KeybSetKey (
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- )
+bool KeybSetKey(
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+)
{
- int i,j;
- unsigned int ii;
- PSKeyItem pKey;
- unsigned int uKeyIdx;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetKey: %lX\n", dwKeyIndex);
-
- j = (MAX_KEY_TABLE-1);
- for (i=0;i<(MAX_KEY_TABLE-1);i++) {
- if ((pTable->KeyTable[i].bInUse == false) &&
- (j == (MAX_KEY_TABLE-1))) {
- // found empty table
- j = i;
- }
- if ((pTable->KeyTable[i].bInUse == true) &&
- !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
- // found table already exist
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
- // Pairwise key
- pKey = &(pTable->KeyTable[i].PairwiseKey);
- pTable->KeyTable[i].wKeyCtl &= 0xFFF0; // clear pairwise key control filed
- pTable->KeyTable[i].wKeyCtl |= byKeyDecMode;
- uKeyIdx = 4; // use HW key entry 4 for pairwise key
- } else {
- // Group key
- if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
- return (false);
- pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
- if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
- // Group transmit key
- pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
- }
- pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed
- pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
- pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address
- uKeyIdx = (dwKeyIndex & 0x000000FF);
- }
- pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
-
- pKey->bKeyValid = true;
- pKey->uKeyLength = uKeyLength;
- pKey->dwKeyIndex = dwKeyIndex;
- pKey->byCipherSuite = byKeyDecMode;
- memcpy(pKey->abyKey, pbyKey, uKeyLength);
- if (byKeyDecMode == KEY_CTL_WEP) {
- if (uKeyLength == WLAN_WEP40_KEYLEN)
- pKey->abyKey[15] &= 0x7F;
- if (uKeyLength == WLAN_WEP104_KEYLEN)
- pKey->abyKey[15] |= 0x80;
- }
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
-
- if ((dwKeyIndex & USE_KEYRSC) == 0) {
- // RSC set by NIC
- memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
- }
- else {
- memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
- }
- pKey->dwTSC47_16 = 0;
- pKey->wTSC15_0 = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", pKey->uKeyLength);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
- for (ii = 0; ii < pKey->uKeyLength; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
-
- return (true);
- }
- }
- if (j < (MAX_KEY_TABLE-1)) {
- memcpy(pTable->KeyTable[j].abyBSSID,pbyBSSID,ETH_ALEN);
- pTable->KeyTable[j].bInUse = true;
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
- // Pairwise key
- pKey = &(pTable->KeyTable[j].PairwiseKey);
- pTable->KeyTable[j].wKeyCtl &= 0xFFF0; // clear pairwise key control filed
- pTable->KeyTable[j].wKeyCtl |= byKeyDecMode;
- uKeyIdx = 4; // use HW key entry 4 for pairwise key
- } else {
- // Group key
- if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
- return (false);
- pKey = &(pTable->KeyTable[j].GroupKey[dwKeyIndex & 0x000000FF]);
- if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
- // Group transmit key
- pTable->KeyTable[j].dwGTKeyIndex = dwKeyIndex;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(N)[%lX]: %d\n", pTable->KeyTable[j].dwGTKeyIndex, j);
- }
- pTable->KeyTable[j].wKeyCtl &= 0xFF0F; // clear group key control filed
- pTable->KeyTable[j].wKeyCtl |= (byKeyDecMode << 4);
- pTable->KeyTable[j].wKeyCtl |= 0x0040; // use group key for group address
- uKeyIdx = (dwKeyIndex & 0x000000FF);
- }
- pTable->KeyTable[j].wKeyCtl |= 0x8000; // enable on-fly
-
- pKey->bKeyValid = true;
- pKey->uKeyLength = uKeyLength;
- pKey->dwKeyIndex = dwKeyIndex;
- pKey->byCipherSuite = byKeyDecMode;
- memcpy(pKey->abyKey, pbyKey, uKeyLength);
- if (byKeyDecMode == KEY_CTL_WEP) {
- if (uKeyLength == WLAN_WEP40_KEYLEN)
- pKey->abyKey[15] &= 0x7F;
- if (uKeyLength == WLAN_WEP104_KEYLEN)
- pKey->abyKey[15] |= 0x80;
- }
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
-
- if ((dwKeyIndex & USE_KEYRSC) == 0) {
- // RSC set by NIC
- memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
- }
- else {
- memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
- }
- pKey->dwTSC47_16 = 0;
- pKey->wTSC15_0 = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(N): \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
- for (ii = 0; ii < pKey->uKeyLength; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
-
- return (true);
- }
- return (false);
+ int i, j;
+ unsigned int ii;
+ PSKeyItem pKey;
+ unsigned int uKeyIdx;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enter KeybSetKey: %lX\n", dwKeyIndex);
+
+ j = (MAX_KEY_TABLE-1);
+ for (i = 0; i < (MAX_KEY_TABLE - 1); i++) {
+ if ((pTable->KeyTable[i].bInUse == false) &&
+ (j == (MAX_KEY_TABLE-1))) {
+ // found empty table
+ j = i;
+ }
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ // found table already exist
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
+ // Pairwise key
+ pKey = &(pTable->KeyTable[i].PairwiseKey);
+ pTable->KeyTable[i].wKeyCtl &= 0xFFF0; // clear pairwise key control filed
+ pTable->KeyTable[i].wKeyCtl |= byKeyDecMode;
+ uKeyIdx = 4; // use HW key entry 4 for pairwise key
+ } else {
+ // Group key
+ if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
+ return false;
+ pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
+ if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
+ // Group transmit key
+ pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
+ }
+ pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed
+ pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
+ pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address
+ uKeyIdx = (dwKeyIndex & 0x000000FF);
+ }
+ pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
+
+ pKey->bKeyValid = true;
+ pKey->uKeyLength = uKeyLength;
+ pKey->dwKeyIndex = dwKeyIndex;
+ pKey->byCipherSuite = byKeyDecMode;
+ memcpy(pKey->abyKey, pbyKey, uKeyLength);
+ if (byKeyDecMode == KEY_CTL_WEP) {
+ if (uKeyLength == WLAN_WEP40_KEYLEN)
+ pKey->abyKey[15] &= 0x7F;
+ if (uKeyLength == WLAN_WEP104_KEYLEN)
+ pKey->abyKey[15] |= 0x80;
+ }
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+
+ if ((dwKeyIndex & USE_KEYRSC) == 0) {
+ // RSC set by NIC
+ memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
+ } else {
+ memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
+ }
+ pKey->dwTSC47_16 = 0;
+ pKey->wTSC15_0 = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybSetKey(R): \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->bKeyValid: %d\n ", pKey->bKeyValid);
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->uKeyLength: %d\n ", pKey->uKeyLength);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->abyKey: ");
+ for (ii = 0; ii < pKey->uKeyLength; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
+
+ return true;
+ }
+ }
+ if (j < (MAX_KEY_TABLE-1)) {
+ memcpy(pTable->KeyTable[j].abyBSSID, pbyBSSID, ETH_ALEN);
+ pTable->KeyTable[j].bInUse = true;
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
+ // Pairwise key
+ pKey = &(pTable->KeyTable[j].PairwiseKey);
+ pTable->KeyTable[j].wKeyCtl &= 0xFFF0; // clear pairwise key control filed
+ pTable->KeyTable[j].wKeyCtl |= byKeyDecMode;
+ uKeyIdx = 4; // use HW key entry 4 for pairwise key
+ } else {
+ // Group key
+ if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY)
+ return false;
+ pKey = &(pTable->KeyTable[j].GroupKey[dwKeyIndex & 0x000000FF]);
+ if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
+ // Group transmit key
+ pTable->KeyTable[j].dwGTKeyIndex = dwKeyIndex;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Group transmit key(N)[%lX]: %d\n", pTable->KeyTable[j].dwGTKeyIndex, j);
+ }
+ pTable->KeyTable[j].wKeyCtl &= 0xFF0F; // clear group key control filed
+ pTable->KeyTable[j].wKeyCtl |= (byKeyDecMode << 4);
+ pTable->KeyTable[j].wKeyCtl |= 0x0040; // use group key for group address
+ uKeyIdx = (dwKeyIndex & 0x000000FF);
+ }
+ pTable->KeyTable[j].wKeyCtl |= 0x8000; // enable on-fly
+
+ pKey->bKeyValid = true;
+ pKey->uKeyLength = uKeyLength;
+ pKey->dwKeyIndex = dwKeyIndex;
+ pKey->byCipherSuite = byKeyDecMode;
+ memcpy(pKey->abyKey, pbyKey, uKeyLength);
+ if (byKeyDecMode == KEY_CTL_WEP) {
+ if (uKeyLength == WLAN_WEP40_KEYLEN)
+ pKey->abyKey[15] &= 0x7F;
+ if (uKeyLength == WLAN_WEP104_KEYLEN)
+ pKey->abyKey[15] |= 0x80;
+ }
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+
+ if ((dwKeyIndex & USE_KEYRSC) == 0) {
+ // RSC set by NIC
+ memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
+ } else {
+ memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
+ }
+ pKey->dwTSC47_16 = 0;
+ pKey->wTSC15_0 = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybSetKey(N): \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->bKeyValid: %d\n ", pKey->bKeyValid);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->abyKey: ");
+ for (ii = 0; ii < pKey->uKeyLength; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwTSC47_16: %lx\n ", pKey->dwTSC47_16);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->wTSC15_0: %x\n ", pKey->wTSC15_0);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwKeyIndex: %lx\n ", pKey->dwKeyIndex);
+
+ return true;
+ }
+ return false;
}
-
/*
* Description: Remove Key from table
*
@@ -362,66 +351,61 @@ bool KeybSetKey (
* Return Value: true if success otherwise false
*
*/
-bool KeybRemoveKey (
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- unsigned long dwIoBase
- )
+bool KeybRemoveKey(
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
+)
{
- int i;
-
- if (is_broadcast_ether_addr(pbyBSSID)) {
- // delete all keys
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
- for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
- }
- s_vCheckKeyTableValid(pTable, dwIoBase);
- return true;
- }
- else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- for (i=0;i<MAX_KEY_TABLE;i++) {
- pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
- if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
- // remove Group transmit key
- pTable->KeyTable[i].dwGTKeyIndex = 0;
- }
- }
- s_vCheckKeyTableValid(pTable, dwIoBase);
- return true;
- }
- else {
- return false;
- }
- }
-
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
- s_vCheckKeyTableValid(pTable, dwIoBase);
- return (true);
- }
- else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
- if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
- // remove Group transmit key
- pTable->KeyTable[i].dwGTKeyIndex = 0;
- }
- s_vCheckKeyTableValid(pTable, dwIoBase);
- return (true);
- }
- else {
- return (false);
- }
- }
- }
- return (false);
+ int i;
+
+ if (is_broadcast_ether_addr(pbyBSSID)) {
+ // delete all keys
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
+ }
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ return true;
+ } else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
+ if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
+ // remove Group transmit key
+ pTable->KeyTable[i].dwGTKeyIndex = 0;
+ }
+ }
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) {
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ return true;
+ } else if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
+ pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
+ if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[i].dwGTKeyIndex & 0x7FFFFFFF)) {
+ // remove Group transmit key
+ pTable->KeyTable[i].dwGTKeyIndex = 0;
+ }
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
}
-
/*
* Description: Remove Key from table
*
@@ -435,27 +419,27 @@ bool KeybRemoveKey (
* Return Value: true if success otherwise false
*
*/
-bool KeybRemoveAllKey (
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwIoBase
- )
+bool KeybRemoveAllKey(
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwIoBase
+)
{
- int i,u;
-
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
- pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
- for(u=0;u<MAX_GROUP_KEY;u++) {
- pTable->KeyTable[i].GroupKey[u].bKeyValid = false;
- }
- pTable->KeyTable[i].dwGTKeyIndex = 0;
- s_vCheckKeyTableValid(pTable, dwIoBase);
- return (true);
- }
- }
- return (false);
+ int i, u;
+
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ pTable->KeyTable[i].PairwiseKey.bKeyValid = false;
+ for (u = 0; u < MAX_GROUP_KEY; u++) {
+ pTable->KeyTable[i].GroupKey[u].bKeyValid = false;
+ }
+ pTable->KeyTable[i].dwGTKeyIndex = 0;
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ return true;
+ }
+ }
+ return false;
}
/*
@@ -470,38 +454,37 @@ bool KeybRemoveAllKey (
* Return Value: true if success otherwise false
*
*/
-void KeyvRemoveWEPKey (
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long dwIoBase
- )
+void KeyvRemoveWEPKey(
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
+)
{
-
- if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == true) {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) {
- pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
- if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) {
- // remove Group transmit key
- pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0;
- }
- }
- }
- s_vCheckKeyTableValid(pTable, dwIoBase);
- }
- return;
+ if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
+ if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == true) {
+ if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) {
+ pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
+ if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) {
+ // remove Group transmit key
+ pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0;
+ }
+ }
+ }
+ s_vCheckKeyTableValid(pTable, dwIoBase);
+ }
+ return;
}
-void KeyvRemoveAllWEPKey (
- PSKeyManagement pTable,
- unsigned long dwIoBase
- )
+void KeyvRemoveAllWEPKey(
+ PSKeyManagement pTable,
+ unsigned long dwIoBase
+)
{
- int i;
+ int i;
- for(i=0;i<MAX_GROUP_KEY;i++) {
- KeyvRemoveWEPKey(pTable, i, dwIoBase);
- }
+ for (i = 0; i < MAX_GROUP_KEY; i++) {
+ KeyvRemoveWEPKey(pTable, i, dwIoBase);
+ }
}
/*
@@ -517,74 +500,68 @@ void KeyvRemoveAllWEPKey (
* Return Value: true if found otherwise false
*
*/
-bool KeybGetTransmitKey (
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyType,
- PSKeyItem *pKey
- )
+bool KeybGetTransmitKey(
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyType,
+ PSKeyItem *pKey
+)
{
- int i, ii;
-
- *pKey = NULL;
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
-
- if (dwKeyType == PAIRWISE_KEY) {
-
- if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
- *pKey = &(pTable->KeyTable[i].PairwiseKey);
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PAIRWISE_KEY: KeyTable.abyBSSID: ");
- for (ii = 0; ii < 6; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
-
- return (true);
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"PairwiseKey.bKeyValid == false\n");
- return (false);
- }
- } // End of Type == PAIRWISE
- else {
- if (pTable->KeyTable[i].dwGTKeyIndex == 0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: dwGTKeyIndex == 0 !!!\n");
- return false;
- }
- if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == true) {
- *pKey = &(pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)]);
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybGetTransmitKey:");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GROUP_KEY: KeyTable.abyBSSID\n");
- for (ii = 0; ii < 6; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x ", pTable->KeyTable[i].abyBSSID[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex);
-
- return (true);
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"GroupKey.bKeyValid == false\n");
- return (false);
- }
- } // End of Type = GROUP
- } // BSSID match
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ERROR: NO Match BSSID !!! ");
- for (ii = 0; ii < 6; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(pbyBSSID+ii));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- return (false);
+ int i, ii;
+
+ *pKey = NULL;
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ !compare_ether_addr(pTable->KeyTable[i].abyBSSID, pbyBSSID)) {
+ if (dwKeyType == PAIRWISE_KEY) {
+ if (pTable->KeyTable[i].PairwiseKey.bKeyValid == true) {
+ *pKey = &(pTable->KeyTable[i].PairwiseKey);
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybGetTransmitKey:");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PAIRWISE_KEY: KeyTable.abyBSSID: ");
+ for (ii = 0; ii < 6; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%x ", pTable->KeyTable[i].abyBSSID[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ return true;
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PairwiseKey.bKeyValid == false\n");
+ return false;
+ }
+ } // End of Type == PAIRWISE
+ else {
+ if (pTable->KeyTable[i].dwGTKeyIndex == 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ERROR: dwGTKeyIndex == 0 !!!\n");
+ return false;
+ }
+ if (pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)].bKeyValid == true) {
+ *pKey = &(pTable->KeyTable[i].GroupKey[(pTable->KeyTable[i].dwGTKeyIndex&0x000000FF)]);
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybGetTransmitKey:");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP_KEY: KeyTable.abyBSSID\n");
+ for (ii = 0; ii < 6; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%x ", pTable->KeyTable[i].abyBSSID[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dwGTKeyIndex: %lX\n", pTable->KeyTable[i].dwGTKeyIndex);
+
+ return true;
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GroupKey.bKeyValid == false\n");
+ return false;
+ }
+ } // End of Type = GROUP
+ } // BSSID match
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ERROR: NO Match BSSID !!! ");
+ for (ii = 0; ii < 6; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *(pbyBSSID+ii));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+ return false;
}
-
/*
* Description: Check Pairewise Key
*
@@ -597,22 +574,22 @@ bool KeybGetTransmitKey (
* Return Value: true if found otherwise false
*
*/
-bool KeybCheckPairewiseKey (
- PSKeyManagement pTable,
- PSKeyItem *pKey
- )
+bool KeybCheckPairewiseKey(
+ PSKeyManagement pTable,
+ PSKeyItem *pKey
+)
{
- int i;
-
- *pKey = NULL;
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- (pTable->KeyTable[i].PairwiseKey.bKeyValid == true)) {
- *pKey = &(pTable->KeyTable[i].PairwiseKey);
- return (true);
- }
- }
- return (false);
+ int i;
+
+ *pKey = NULL;
+ for (i = 0; i < MAX_KEY_TABLE; i++) {
+ if ((pTable->KeyTable[i].bInUse == true) &&
+ (pTable->KeyTable[i].PairwiseKey.bKeyValid == true)) {
+ *pKey = &(pTable->KeyTable[i].PairwiseKey);
+ return true;
+ }
+ }
+ return false;
}
/*
@@ -631,100 +608,97 @@ bool KeybCheckPairewiseKey (
* Return Value: true if success otherwise false
*
*/
-bool KeybSetDefaultKey (
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- )
+bool KeybSetDefaultKey(
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+)
{
- unsigned int ii;
- PSKeyItem pKey;
- unsigned int uKeyIdx;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetDefaultKey: %1x, %d \n", (int)dwKeyIndex, (int)uKeyLength);
-
-
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
- return (false);
- } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
- return (false);
- }
-
- if (uKeyLength > MAX_KEY_LEN)
- return false;
-
- pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = true;
- for(ii=0;ii<ETH_ALEN;ii++)
- pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF;
-
- // Group key
- pKey = &(pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF]);
- if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
- // Group transmit key
- pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = dwKeyIndex;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, MAX_KEY_TABLE-1);
-
- }
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl &= 0x7F00; // clear all key control filed
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode << 4);
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode);
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x0044; // use group key for all address
- uKeyIdx = (dwKeyIndex & 0x000000FF);
-
- if ((uKeyLength == WLAN_WEP232_KEYLEN) &&
- (byKeyDecMode == KEY_CTL_WEP)) {
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x4000; // disable on-fly disable address match
- pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = true;
- } else {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == false)
- pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0xC000; // enable on-fly disable address match
- }
-
- pKey->bKeyValid = true;
- pKey->uKeyLength = uKeyLength;
- pKey->dwKeyIndex = dwKeyIndex;
- pKey->byCipherSuite = byKeyDecMode;
- memcpy(pKey->abyKey, pbyKey, uKeyLength);
- if (byKeyDecMode == KEY_CTL_WEP) {
- if (uKeyLength == WLAN_WEP40_KEYLEN)
- pKey->abyKey[15] &= 0x7F;
- if (uKeyLength == WLAN_WEP104_KEYLEN)
- pKey->abyKey[15] |= 0x80;
- }
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
-
- if ((dwKeyIndex & USE_KEYRSC) == 0) {
- // RSC set by NIC
- memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
- } else {
- memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
- }
- pKey->dwTSC47_16 = 0;
- pKey->wTSC15_0 = 0;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n", pKey->bKeyValid);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n", (int)pKey->uKeyLength);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: \n");
- for (ii = 0; ii < pKey->uKeyLength; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%x", pKey->abyKey[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwTSC47_16: %lx\n", pKey->dwTSC47_16);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->wTSC15_0: %x\n", pKey->wTSC15_0);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex);
-
- return (true);
+ unsigned int ii;
+ PSKeyItem pKey;
+ unsigned int uKeyIdx;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enter KeybSetDefaultKey: %1x, %d \n", (int)dwKeyIndex, (int)uKeyLength);
+
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
+ return false;
+ } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
+ return false;
+ }
+
+ if (uKeyLength > MAX_KEY_LEN)
+ return false;
+
+ pTable->KeyTable[MAX_KEY_TABLE - 1].bInUse = true;
+ for (ii = 0; ii < ETH_ALEN; ii++)
+ pTable->KeyTable[MAX_KEY_TABLE - 1].abyBSSID[ii] = 0xFF;
+
+ // Group key
+ pKey = &(pTable->KeyTable[MAX_KEY_TABLE - 1].GroupKey[dwKeyIndex & 0x000000FF]);
+ if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
+ // Group transmit key
+ pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = dwKeyIndex;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex, MAX_KEY_TABLE-1);
+
+ }
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl &= 0x7F00; // clear all key control filed
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode << 4);
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= (byKeyDecMode);
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x0044; // use group key for all address
+ uKeyIdx = (dwKeyIndex & 0x000000FF);
+
+ if ((uKeyLength == WLAN_WEP232_KEYLEN) &&
+ (byKeyDecMode == KEY_CTL_WEP)) {
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0x4000; // disable on-fly disable address match
+ pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP = true;
+ } else {
+ if (pTable->KeyTable[MAX_KEY_TABLE-1].bSoftWEP == false)
+ pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl |= 0xC000; // enable on-fly disable address match
+ }
+
+ pKey->bKeyValid = true;
+ pKey->uKeyLength = uKeyLength;
+ pKey->dwKeyIndex = dwKeyIndex;
+ pKey->byCipherSuite = byKeyDecMode;
+ memcpy(pKey->abyKey, pbyKey, uKeyLength);
+ if (byKeyDecMode == KEY_CTL_WEP) {
+ if (uKeyLength == WLAN_WEP40_KEYLEN)
+ pKey->abyKey[15] &= 0x7F;
+ if (uKeyLength == WLAN_WEP104_KEYLEN)
+ pKey->abyKey[15] |= 0x80;
+ }
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+
+ if ((dwKeyIndex & USE_KEYRSC) == 0) {
+ // RSC set by NIC
+ memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
+ } else {
+ memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
+ }
+ pKey->dwTSC47_16 = 0;
+ pKey->wTSC15_0 = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybSetKey(R): \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->bKeyValid: %d\n", pKey->bKeyValid);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->uKeyLength: %d\n", (int)pKey->uKeyLength);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->abyKey: \n");
+ for (ii = 0; ii < pKey->uKeyLength; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%x", pKey->abyKey[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwTSC47_16: %lx\n", pKey->dwTSC47_16);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->wTSC15_0: %x\n", pKey->wTSC15_0);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->dwKeyIndex: %lx\n", pKey->dwKeyIndex);
+
+ return true;
}
-
/*
* Description: Set Key to table
*
@@ -741,86 +715,84 @@ bool KeybSetDefaultKey (
* Return Value: true if success otherwise false
*
*/
-bool KeybSetAllGroupKey (
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- )
+bool KeybSetAllGroupKey(
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+)
{
- int i;
- unsigned int ii;
- PSKeyItem pKey;
- unsigned int uKeyIdx;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex);
-
-
- if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
- return (false);
- } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
- return (false);
- }
-
- for (i=0; i < MAX_KEY_TABLE-1; i++) {
- if (pTable->KeyTable[i].bInUse == true) {
- // found table already exist
- // Group key
- pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
- if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
- // Group transmit key
- pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
-
- }
- pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed
- pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
- pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address
- uKeyIdx = (dwKeyIndex & 0x000000FF);
-
- pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
-
- pKey->bKeyValid = true;
- pKey->uKeyLength = uKeyLength;
- pKey->dwKeyIndex = dwKeyIndex;
- pKey->byCipherSuite = byKeyDecMode;
- memcpy(pKey->abyKey, pbyKey, uKeyLength);
- if (byKeyDecMode == KEY_CTL_WEP) {
- if (uKeyLength == WLAN_WEP40_KEYLEN)
- pKey->abyKey[15] &= 0x7F;
- if (uKeyLength == WLAN_WEP104_KEYLEN)
- pKey->abyKey[15] |= 0x80;
- }
- MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
-
- if ((dwKeyIndex & USE_KEYRSC) == 0) {
- // RSC set by NIC
- memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
- }
- else {
- memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
- }
- pKey->dwTSC47_16 = 0;
- pKey->wTSC15_0 = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n ", pKey->bKeyValid);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->abyKey: ");
- for (ii = 0; ii < pKey->uKeyLength; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", pKey->abyKey[ii]);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
- //DBG_PRN_GRP12(("pKey->dwTSC47_16: %lX\n ", pKey->dwTSC47_16));
- //DBG_PRN_GRP12(("pKey->wTSC15_0: %X\n ", pKey->wTSC15_0));
- //DBG_PRN_GRP12(("pKey->dwKeyIndex: %lX\n ", pKey->dwKeyIndex));
-
- } // (pTable->KeyTable[i].bInUse == true)
- }
- return (true);
+ int i;
+ unsigned int ii;
+ PSKeyItem pKey;
+ unsigned int uKeyIdx;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Enter KeybSetAllGroupKey: %lX\n", dwKeyIndex);
+
+ if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
+ return false;
+ } else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
+ return false;
+ }
+
+ for (i = 0; i < MAX_KEY_TABLE - 1; i++) {
+ if (pTable->KeyTable[i].bInUse == true) {
+ // found table already exist
+ // Group key
+ pKey = &(pTable->KeyTable[i].GroupKey[dwKeyIndex & 0x000000FF]);
+ if ((dwKeyIndex & TRANSMIT_KEY) != 0) {
+ // Group transmit key
+ pTable->KeyTable[i].dwGTKeyIndex = dwKeyIndex;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Group transmit key(R)[%lX]: %d\n", pTable->KeyTable[i].dwGTKeyIndex, i);
+
+ }
+ pTable->KeyTable[i].wKeyCtl &= 0xFF0F; // clear group key control filed
+ pTable->KeyTable[i].wKeyCtl |= (byKeyDecMode << 4);
+ pTable->KeyTable[i].wKeyCtl |= 0x0040; // use group key for group address
+ uKeyIdx = (dwKeyIndex & 0x000000FF);
+
+ pTable->KeyTable[i].wKeyCtl |= 0x8000; // enable on-fly
+
+ pKey->bKeyValid = true;
+ pKey->uKeyLength = uKeyLength;
+ pKey->dwKeyIndex = dwKeyIndex;
+ pKey->byCipherSuite = byKeyDecMode;
+ memcpy(pKey->abyKey, pbyKey, uKeyLength);
+ if (byKeyDecMode == KEY_CTL_WEP) {
+ if (uKeyLength == WLAN_WEP40_KEYLEN)
+ pKey->abyKey[15] &= 0x7F;
+ if (uKeyLength == WLAN_WEP104_KEYLEN)
+ pKey->abyKey[15] |= 0x80;
+ }
+ MACvSetKeyEntry(dwIoBase, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (unsigned long *)pKey->abyKey, byLocalID);
+
+ if ((dwKeyIndex & USE_KEYRSC) == 0) {
+ // RSC set by NIC
+ memset(&(pKey->KeyRSC), 0, sizeof(QWORD));
+ } else {
+ memcpy(&(pKey->KeyRSC), pKeyRSC, sizeof(QWORD));
+ }
+ pKey->dwTSC47_16 = 0;
+ pKey->wTSC15_0 = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KeybSetKey(R): \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->bKeyValid: %d\n ", pKey->bKeyValid);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->uKeyLength: %d\n ", (int)pKey->uKeyLength);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pKey->abyKey: ");
+ for (ii = 0; ii < pKey->uKeyLength; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", pKey->abyKey[ii]);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+
+ //DBG_PRN_GRP12(("pKey->dwTSC47_16: %lX\n ", pKey->dwTSC47_16));
+ //DBG_PRN_GRP12(("pKey->wTSC15_0: %X\n ", pKey->wTSC15_0));
+ //DBG_PRN_GRP12(("pKey->dwKeyIndex: %lX\n ", pKey->dwKeyIndex));
+
+ } // (pTable->KeyTable[i].bInUse == true)
+ }
+ return true;
}
diff --git a/drivers/staging/vt6655/key.h b/drivers/staging/vt6655/key.h
index 6b2dad331a5b..356e6de8f87f 100644
--- a/drivers/staging/vt6655/key.h
+++ b/drivers/staging/vt6655/key.h
@@ -40,7 +40,6 @@
#define MAX_KEY_LEN 32
#define AES_KEY_LEN 16
-
#define AUTHENTICATOR_KEY 0x10000000
#define USE_KEYRSC 0x20000000
#define PAIRWISE_KEY 0x40000000
@@ -54,42 +53,41 @@
#define KEY_CTL_CCMP 0x03
#define KEY_CTL_INVALID 0xFF
-
typedef struct tagSKeyItem
{
- bool bKeyValid;
- unsigned long uKeyLength;
- unsigned char abyKey[MAX_KEY_LEN];
- QWORD KeyRSC;
- unsigned long dwTSC47_16;
- unsigned short wTSC15_0;
- unsigned char byCipherSuite;
- unsigned char byReserved0;
- unsigned long dwKeyIndex;
- void *pvKeyTable;
+ bool bKeyValid;
+ unsigned long uKeyLength;
+ unsigned char abyKey[MAX_KEY_LEN];
+ QWORD KeyRSC;
+ unsigned long dwTSC47_16;
+ unsigned short wTSC15_0;
+ unsigned char byCipherSuite;
+ unsigned char byReserved0;
+ unsigned long dwKeyIndex;
+ void *pvKeyTable;
} SKeyItem, *PSKeyItem; //64
typedef struct tagSKeyTable
{
- unsigned char abyBSSID[ETH_ALEN]; //6
- unsigned char byReserved0[2]; //8
- SKeyItem PairwiseKey;
- SKeyItem GroupKey[MAX_GROUP_KEY]; //64*5 = 320, 320+8=328
- unsigned long dwGTKeyIndex; // GroupTransmitKey Index
- bool bInUse;
- //2006-1116-01,<Modify> by NomadZhao
- //unsigned short wKeyCtl;
- //bool bSoftWEP;
- bool bSoftWEP;
- unsigned short wKeyCtl; // for address of wKeyCtl at align 4
-
- unsigned char byReserved1[6];
+ unsigned char abyBSSID[ETH_ALEN]; //6
+ unsigned char byReserved0[2]; //8
+ SKeyItem PairwiseKey;
+ SKeyItem GroupKey[MAX_GROUP_KEY]; //64*5 = 320, 320+8=328
+ unsigned long dwGTKeyIndex; // GroupTransmitKey Index
+ bool bInUse;
+ //2006-1116-01,<Modify> by NomadZhao
+ //unsigned short wKeyCtl;
+ //bool bSoftWEP;
+ bool bSoftWEP;
+ unsigned short wKeyCtl; // for address of wKeyCtl at align 4
+
+ unsigned char byReserved1[6];
} SKeyTable, *PSKeyTable; //348
typedef struct tagSKeyManagement
{
- SKeyTable KeyTable[MAX_KEY_TABLE];
-} SKeyManagement, * PSKeyManagement;
+ SKeyTable KeyTable[MAX_KEY_TABLE];
+} SKeyManagement, *PSKeyManagement;
/*--------------------- Export Types ------------------------------*/
@@ -104,81 +102,80 @@ typedef struct tagSKeyManagement
void KeyvInitTable(PSKeyManagement pTable, unsigned long dwIoBase);
bool KeybGetKey(
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- PSKeyItem *pKey
- );
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ PSKeyItem *pKey
+);
bool KeybSetKey(
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- );
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+);
bool KeybSetDefaultKey(
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- );
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+);
bool KeybRemoveKey(
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyIndex,
- unsigned long dwIoBase
- );
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
+);
bool KeybGetTransmitKey(
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwKeyType,
- PSKeyItem *pKey
- );
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwKeyType,
+ PSKeyItem *pKey
+);
bool KeybCheckPairewiseKey(
- PSKeyManagement pTable,
- PSKeyItem *pKey
- );
+ PSKeyManagement pTable,
+ PSKeyItem *pKey
+);
bool KeybRemoveAllKey(
- PSKeyManagement pTable,
- unsigned char *pbyBSSID,
- unsigned long dwIoBase
- );
+ PSKeyManagement pTable,
+ unsigned char *pbyBSSID,
+ unsigned long dwIoBase
+);
void KeyvRemoveWEPKey(
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long dwIoBase
- );
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long dwIoBase
+);
void KeyvRemoveAllWEPKey(
- PSKeyManagement pTable,
- unsigned long dwIoBase
- );
-
-bool KeybSetAllGroupKey (
- PSKeyManagement pTable,
- unsigned long dwKeyIndex,
- unsigned long uKeyLength,
- PQWORD pKeyRSC,
- unsigned char *pbyKey,
- unsigned char byKeyDecMode,
- unsigned long dwIoBase,
- unsigned char byLocalID
- );
+ PSKeyManagement pTable,
+ unsigned long dwIoBase
+);
+
+bool KeybSetAllGroupKey(
+ PSKeyManagement pTable,
+ unsigned long dwKeyIndex,
+ unsigned long uKeyLength,
+ PQWORD pKeyRSC,
+ unsigned char *pbyKey,
+ unsigned char byKeyDecMode,
+ unsigned long dwIoBase,
+ unsigned char byLocalID
+);
#endif // __KEY_H__
-
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index 30c261579412..001d15c0fa40 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -75,7 +75,7 @@
unsigned short TxRate_iwconfig;//2008-5-8 <add> by chester
/*--------------------- Static Definitions -------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
@@ -86,10 +86,6 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Export Functions --------------------------*/
-
-
-
-
/*
* Description:
* Read All MAC Registers to buffer
@@ -103,26 +99,25 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value: none
*
*/
-void MACvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyMacRegs)
+void MACvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyMacRegs)
{
- int ii;
-
- // read page0 register
- for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) {
- VNSvInPortB(dwIoBase + ii, pbyMacRegs);
- pbyMacRegs++;
- }
+ int ii;
- MACvSelectPage1(dwIoBase);
+ // read page0 register
+ for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) {
+ VNSvInPortB(dwIoBase + ii, pbyMacRegs);
+ pbyMacRegs++;
+ }
- // read page1 register
- for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
- VNSvInPortB(dwIoBase + ii, pbyMacRegs);
- pbyMacRegs++;
- }
+ MACvSelectPage1(dwIoBase);
- MACvSelectPage0(dwIoBase);
+ // read page1 register
+ for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
+ VNSvInPortB(dwIoBase + ii, pbyMacRegs);
+ pbyMacRegs++;
+ }
+ MACvSelectPage0(dwIoBase);
}
/*
@@ -140,12 +135,12 @@ void MACvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyMacRegs)
* Return Value: true if all test bits On; otherwise false
*
*/
-bool MACbIsRegBitsOn (unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
+bool MACbIsRegBitsOn(unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
{
- unsigned char byData;
+ unsigned char byData;
- VNSvInPortB(dwIoBase + byRegOfs, &byData);
- return (byData & byTestBits) == byTestBits;
+ VNSvInPortB(dwIoBase + byRegOfs, &byData);
+ return (byData & byTestBits) == byTestBits;
}
/*
@@ -163,12 +158,12 @@ bool MACbIsRegBitsOn (unsigned long dwIoBase, unsigned char byRegOfs, unsigned c
* Return Value: true if all test bits Off; otherwise false
*
*/
-bool MACbIsRegBitsOff (unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
+bool MACbIsRegBitsOff(unsigned long dwIoBase, unsigned char byRegOfs, unsigned char byTestBits)
{
- unsigned char byData;
+ unsigned char byData;
- VNSvInPortB(dwIoBase + byRegOfs, &byData);
- return !(byData & byTestBits);
+ VNSvInPortB(dwIoBase + byRegOfs, &byData);
+ return !(byData & byTestBits);
}
/*
@@ -184,15 +179,15 @@ bool MACbIsRegBitsOff (unsigned long dwIoBase, unsigned char byRegOfs, unsigned
* Return Value: true if interrupt is disable; otherwise false
*
*/
-bool MACbIsIntDisable (unsigned long dwIoBase)
+bool MACbIsIntDisable(unsigned long dwIoBase)
{
- unsigned long dwData;
+ unsigned long dwData;
- VNSvInPortD(dwIoBase + MAC_REG_IMR, &dwData);
- if (dwData != 0)
- return false;
+ VNSvInPortD(dwIoBase + MAC_REG_IMR, &dwData);
+ if (dwData != 0)
+ return false;
- return true;
+ return true;
}
/*
@@ -209,14 +204,14 @@ bool MACbIsIntDisable (unsigned long dwIoBase)
* Return Value: Mask Value read
*
*/
-unsigned char MACbyReadMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx)
+unsigned char MACbyReadMultiAddr(unsigned long dwIoBase, unsigned int uByteIdx)
{
- unsigned char byData;
+ unsigned char byData;
- MACvSelectPage1(dwIoBase);
- VNSvInPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, &byData);
- MACvSelectPage0(dwIoBase);
- return byData;
+ MACvSelectPage1(dwIoBase);
+ VNSvInPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, &byData);
+ MACvSelectPage0(dwIoBase);
+ return byData;
}
/*
@@ -234,11 +229,11 @@ unsigned char MACbyReadMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx)
* Return Value: none
*
*/
-void MACvWriteMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx, unsigned char byData)
+void MACvWriteMultiAddr(unsigned long dwIoBase, unsigned int uByteIdx, unsigned char byData)
{
- MACvSelectPage1(dwIoBase);
- VNSvOutPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, byData);
- MACvSelectPage0(dwIoBase);
+ MACvSelectPage1(dwIoBase);
+ VNSvOutPortB(dwIoBase + MAC_REG_MAR0 + uByteIdx, byData);
+ MACvSelectPage0(dwIoBase);
}
/*
@@ -255,21 +250,21 @@ void MACvWriteMultiAddr (unsigned long dwIoBase, unsigned int uByteIdx, unsigned
* Return Value: none
*
*/
-void MACvSetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
+void MACvSetMultiAddrByHash(unsigned long dwIoBase, unsigned char byHashIdx)
{
- unsigned int uByteIdx;
- unsigned char byBitMask;
- unsigned char byOrgValue;
-
- // calculate byte position
- uByteIdx = byHashIdx / 8;
- ASSERT(uByteIdx < 8);
- // calculate bit position
- byBitMask = 1;
- byBitMask <<= (byHashIdx % 8);
- // turn on the bit
- byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
- MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue | byBitMask));
+ unsigned int uByteIdx;
+ unsigned char byBitMask;
+ unsigned char byOrgValue;
+
+ // calculate byte position
+ uByteIdx = byHashIdx / 8;
+ ASSERT(uByteIdx < 8);
+ // calculate bit position
+ byBitMask = 1;
+ byBitMask <<= (byHashIdx % 8);
+ // turn on the bit
+ byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
+ MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue | byBitMask));
}
/*
@@ -286,21 +281,21 @@ void MACvSetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
* Return Value: none
*
*/
-void MACvResetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
+void MACvResetMultiAddrByHash(unsigned long dwIoBase, unsigned char byHashIdx)
{
- unsigned int uByteIdx;
- unsigned char byBitMask;
- unsigned char byOrgValue;
-
- // calculate byte position
- uByteIdx = byHashIdx / 8;
- ASSERT(uByteIdx < 8);
- // calculate bit position
- byBitMask = 1;
- byBitMask <<= (byHashIdx % 8);
- // turn off the bit
- byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
- MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue & (~byBitMask)));
+ unsigned int uByteIdx;
+ unsigned char byBitMask;
+ unsigned char byOrgValue;
+
+ // calculate byte position
+ uByteIdx = byHashIdx / 8;
+ ASSERT(uByteIdx < 8);
+ // calculate bit position
+ byBitMask = 1;
+ byBitMask <<= (byHashIdx % 8);
+ // turn off the bit
+ byOrgValue = MACbyReadMultiAddr(dwIoBase, uByteIdx);
+ MACvWriteMultiAddr(dwIoBase, uByteIdx, (unsigned char)(byOrgValue & (~byBitMask)));
}
/*
@@ -317,16 +312,16 @@ void MACvResetMultiAddrByHash (unsigned long dwIoBase, unsigned char byHashIdx)
* Return Value: none
*
*/
-void MACvSetRxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
+void MACvSetRxThreshold(unsigned long dwIoBase, unsigned char byThreshold)
{
- unsigned char byOrgValue;
+ unsigned char byOrgValue;
- ASSERT(byThreshold < 4);
+ ASSERT(byThreshold < 4);
- // set FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
- byOrgValue = (byOrgValue & 0xCF) | (byThreshold << 4);
- VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
+ // set FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
+ byOrgValue = (byOrgValue & 0xCF) | (byThreshold << 4);
+ VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
}
/*
@@ -342,11 +337,11 @@ void MACvSetRxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
* Return Value: none
*
*/
-void MACvGetRxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
+void MACvGetRxThreshold(unsigned long dwIoBase, unsigned char *pbyThreshold)
{
- // get FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
- *pbyThreshold = (*pbyThreshold >> 4) & 0x03;
+ // get FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
+ *pbyThreshold = (*pbyThreshold >> 4) & 0x03;
}
/*
@@ -363,16 +358,16 @@ void MACvGetRxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
* Return Value: none
*
*/
-void MACvSetTxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
+void MACvSetTxThreshold(unsigned long dwIoBase, unsigned char byThreshold)
{
- unsigned char byOrgValue;
+ unsigned char byOrgValue;
- ASSERT(byThreshold < 4);
+ ASSERT(byThreshold < 4);
- // set FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
- byOrgValue = (byOrgValue & 0xF3) | (byThreshold << 2);
- VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
+ // set FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
+ byOrgValue = (byOrgValue & 0xF3) | (byThreshold << 2);
+ VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
}
/*
@@ -388,11 +383,11 @@ void MACvSetTxThreshold (unsigned long dwIoBase, unsigned char byThreshold)
* Return Value: none
*
*/
-void MACvGetTxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
+void MACvGetTxThreshold(unsigned long dwIoBase, unsigned char *pbyThreshold)
{
- // get FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
- *pbyThreshold = (*pbyThreshold >> 2) & 0x03;
+ // get FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyThreshold);
+ *pbyThreshold = (*pbyThreshold >> 2) & 0x03;
}
/*
@@ -409,16 +404,16 @@ void MACvGetTxThreshold (unsigned long dwIoBase, unsigned char *pbyThreshold)
* Return Value: none
*
*/
-void MACvSetDmaLength (unsigned long dwIoBase, unsigned char byDmaLength)
+void MACvSetDmaLength(unsigned long dwIoBase, unsigned char byDmaLength)
{
- unsigned char byOrgValue;
+ unsigned char byOrgValue;
- ASSERT(byDmaLength < 4);
+ ASSERT(byDmaLength < 4);
- // set FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
- byOrgValue = (byOrgValue & 0xFC) | byDmaLength;
- VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
+ // set FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, &byOrgValue);
+ byOrgValue = (byOrgValue & 0xFC) | byDmaLength;
+ VNSvOutPortB(dwIoBase + MAC_REG_FCR0, byOrgValue);
}
/*
@@ -434,11 +429,11 @@ void MACvSetDmaLength (unsigned long dwIoBase, unsigned char byDmaLength)
* Return Value: none
*
*/
-void MACvGetDmaLength (unsigned long dwIoBase, unsigned char *pbyDmaLength)
+void MACvGetDmaLength(unsigned long dwIoBase, unsigned char *pbyDmaLength)
{
- // get FCR0
- VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyDmaLength);
- *pbyDmaLength &= 0x03;
+ // get FCR0
+ VNSvInPortB(dwIoBase + MAC_REG_FCR0, pbyDmaLength);
+ *pbyDmaLength &= 0x03;
}
/*
@@ -455,10 +450,10 @@ void MACvGetDmaLength (unsigned long dwIoBase, unsigned char *pbyDmaLength)
* Return Value: none
*
*/
-void MACvSetShortRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
+void MACvSetShortRetryLimit(unsigned long dwIoBase, unsigned char byRetryLimit)
{
- // set SRT
- VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit);
+ // set SRT
+ VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit);
}
/*
@@ -474,10 +469,10 @@ void MACvSetShortRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
* Return Value: none
*
*/
-void MACvGetShortRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimit)
+void MACvGetShortRetryLimit(unsigned long dwIoBase, unsigned char *pbyRetryLimit)
{
- // get SRT
- VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit);
+ // get SRT
+ VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit);
}
/*
@@ -494,10 +489,10 @@ void MACvGetShortRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimi
* Return Value: none
*
*/
-void MACvSetLongRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
+void MACvSetLongRetryLimit(unsigned long dwIoBase, unsigned char byRetryLimit)
{
- // set LRT
- VNSvOutPortB(dwIoBase + MAC_REG_LRT, byRetryLimit);
+ // set LRT
+ VNSvOutPortB(dwIoBase + MAC_REG_LRT, byRetryLimit);
}
/*
@@ -513,10 +508,10 @@ void MACvSetLongRetryLimit (unsigned long dwIoBase, unsigned char byRetryLimit)
* Return Value: none
*
*/
-void MACvGetLongRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimit)
+void MACvGetLongRetryLimit(unsigned long dwIoBase, unsigned char *pbyRetryLimit)
{
- // get LRT
- VNSvInPortB(dwIoBase + MAC_REG_LRT, pbyRetryLimit);
+ // get LRT
+ VNSvInPortB(dwIoBase + MAC_REG_LRT, pbyRetryLimit);
}
/*
@@ -533,17 +528,17 @@ void MACvGetLongRetryLimit (unsigned long dwIoBase, unsigned char *pbyRetryLimit
* Return Value: none
*
*/
-void MACvSetLoopbackMode (unsigned long dwIoBase, unsigned char byLoopbackMode)
+void MACvSetLoopbackMode(unsigned long dwIoBase, unsigned char byLoopbackMode)
{
- unsigned char byOrgValue;
-
- ASSERT(byLoopbackMode < 3);
- byLoopbackMode <<= 6;
- // set TCR
- VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue);
- byOrgValue = byOrgValue & 0x3F;
- byOrgValue = byOrgValue | byLoopbackMode;
- VNSvOutPortB(dwIoBase + MAC_REG_TEST, byOrgValue);
+ unsigned char byOrgValue;
+
+ ASSERT(byLoopbackMode < 3);
+ byLoopbackMode <<= 6;
+ // set TCR
+ VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue);
+ byOrgValue = byOrgValue & 0x3F;
+ byOrgValue = byOrgValue | byLoopbackMode;
+ VNSvOutPortB(dwIoBase + MAC_REG_TEST, byOrgValue);
}
/*
@@ -559,14 +554,14 @@ void MACvSetLoopbackMode (unsigned long dwIoBase, unsigned char byLoopbackMode)
* Return Value: true if in Loopback mode; otherwise false
*
*/
-bool MACbIsInLoopbackMode (unsigned long dwIoBase)
+bool MACbIsInLoopbackMode(unsigned long dwIoBase)
{
- unsigned char byOrgValue;
+ unsigned char byOrgValue;
- VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue);
- if (byOrgValue & (TEST_LBINT | TEST_LBEXT))
- return true;
- return false;
+ VNSvInPortB(dwIoBase + MAC_REG_TEST, &byOrgValue);
+ if (byOrgValue & (TEST_LBINT | TEST_LBEXT))
+ return true;
+ return false;
}
/*
@@ -583,51 +578,50 @@ bool MACbIsInLoopbackMode (unsigned long dwIoBase)
* Return Value: none
*
*/
-void MACvSetPacketFilter (unsigned long dwIoBase, unsigned short wFilterType)
+void MACvSetPacketFilter(unsigned long dwIoBase, unsigned short wFilterType)
{
- unsigned char byOldRCR;
- unsigned char byNewRCR = 0;
-
- // if only in DIRECTED mode, multicast-address will set to zero,
- // but if other mode exist (e.g. PROMISCUOUS), multicast-address
- // will be open
- if (wFilterType & PKT_TYPE_DIRECTED) {
- // set multicast address to accept none
- MACvSelectPage1(dwIoBase);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0L);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0L);
- MACvSelectPage0(dwIoBase);
- }
-
- if (wFilterType & (PKT_TYPE_PROMISCUOUS | PKT_TYPE_ALL_MULTICAST)) {
- // set multicast address to accept all
- MACvSelectPage1(dwIoBase);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0xFFFFFFFFL);
- VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0xFFFFFFFFL);
- MACvSelectPage0(dwIoBase);
- }
-
- if (wFilterType & PKT_TYPE_PROMISCUOUS) {
-
- byNewRCR |= (RCR_RXALLTYPE | RCR_UNICAST | RCR_MULTICAST | RCR_BROADCAST);
-
- byNewRCR &= ~RCR_BSSID;
- }
-
- if (wFilterType & (PKT_TYPE_ALL_MULTICAST | PKT_TYPE_MULTICAST))
- byNewRCR |= RCR_MULTICAST;
-
- if (wFilterType & PKT_TYPE_BROADCAST)
- byNewRCR |= RCR_BROADCAST;
-
- if (wFilterType & PKT_TYPE_ERROR_CRC)
- byNewRCR |= RCR_ERRCRC;
-
- VNSvInPortB(dwIoBase + MAC_REG_RCR, &byOldRCR);
- if (byNewRCR != byOldRCR) {
- // Modify the Receive Command Register
- VNSvOutPortB(dwIoBase + MAC_REG_RCR, byNewRCR);
- }
+ unsigned char byOldRCR;
+ unsigned char byNewRCR = 0;
+
+ // if only in DIRECTED mode, multicast-address will set to zero,
+ // but if other mode exist (e.g. PROMISCUOUS), multicast-address
+ // will be open
+ if (wFilterType & PKT_TYPE_DIRECTED) {
+ // set multicast address to accept none
+ MACvSelectPage1(dwIoBase);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0L);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0L);
+ MACvSelectPage0(dwIoBase);
+ }
+
+ if (wFilterType & (PKT_TYPE_PROMISCUOUS | PKT_TYPE_ALL_MULTICAST)) {
+ // set multicast address to accept all
+ MACvSelectPage1(dwIoBase);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0, 0xFFFFFFFFL);
+ VNSvOutPortD(dwIoBase + MAC_REG_MAR0 + sizeof(unsigned long), 0xFFFFFFFFL);
+ MACvSelectPage0(dwIoBase);
+ }
+
+ if (wFilterType & PKT_TYPE_PROMISCUOUS) {
+ byNewRCR |= (RCR_RXALLTYPE | RCR_UNICAST | RCR_MULTICAST | RCR_BROADCAST);
+
+ byNewRCR &= ~RCR_BSSID;
+ }
+
+ if (wFilterType & (PKT_TYPE_ALL_MULTICAST | PKT_TYPE_MULTICAST))
+ byNewRCR |= RCR_MULTICAST;
+
+ if (wFilterType & PKT_TYPE_BROADCAST)
+ byNewRCR |= RCR_BROADCAST;
+
+ if (wFilterType & PKT_TYPE_ERROR_CRC)
+ byNewRCR |= RCR_ERRCRC;
+
+ VNSvInPortB(dwIoBase + MAC_REG_RCR, &byOldRCR);
+ if (byNewRCR != byOldRCR) {
+ // Modify the Receive Command Register
+ VNSvOutPortB(dwIoBase + MAC_REG_RCR, byNewRCR);
+ }
}
/*
@@ -643,23 +637,23 @@ void MACvSetPacketFilter (unsigned long dwIoBase, unsigned short wFilterType)
* Return Value: none
*
*/
-void MACvSaveContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
+void MACvSaveContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
- int ii;
+ int ii;
- // read page0 register
- for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) {
- VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + ii));
- }
+ // read page0 register
+ for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE0; ii++) {
+ VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + ii));
+ }
- MACvSelectPage1(dwIoBase);
+ MACvSelectPage1(dwIoBase);
- // read page1 register
- for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
- VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii));
- }
+ // read page1 register
+ for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
+ VNSvInPortB((dwIoBase + ii), (pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii));
+ }
- MACvSelectPage0(dwIoBase);
+ MACvSelectPage0(dwIoBase);
}
/*
@@ -676,42 +670,40 @@ void MACvSaveContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
* Return Value: none
*
*/
-void MACvRestoreContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
+void MACvRestoreContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
- int ii;
-
- MACvSelectPage1(dwIoBase);
- // restore page1
- for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
- VNSvOutPortB((dwIoBase + ii), *(pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii));
- }
- MACvSelectPage0(dwIoBase);
-
- // restore RCR,TCR,IMR...
- for (ii = MAC_REG_RCR; ii < MAC_REG_ISR; ii++) {
- VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
- }
- // restore MAC Config.
- for (ii = MAC_REG_LRT; ii < MAC_REG_PAGE1SEL; ii++) {
- VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
- }
- VNSvOutPortB(dwIoBase + MAC_REG_CFG, *(pbyCxtBuf + MAC_REG_CFG));
-
- // restore PS Config.
- for (ii = MAC_REG_PSCFG; ii < MAC_REG_BBREGCTL; ii++) {
- VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
- }
-
- // restore CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0));
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR));
- VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_BCNDMAPTR));
-
-
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0));
-
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1));
-
+ int ii;
+
+ MACvSelectPage1(dwIoBase);
+ // restore page1
+ for (ii = 0; ii < MAC_MAX_CONTEXT_SIZE_PAGE1; ii++) {
+ VNSvOutPortB((dwIoBase + ii), *(pbyCxtBuf + MAC_MAX_CONTEXT_SIZE_PAGE0 + ii));
+ }
+ MACvSelectPage0(dwIoBase);
+
+ // restore RCR,TCR,IMR...
+ for (ii = MAC_REG_RCR; ii < MAC_REG_ISR; ii++) {
+ VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
+ }
+ // restore MAC Config.
+ for (ii = MAC_REG_LRT; ii < MAC_REG_PAGE1SEL; ii++) {
+ VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
+ }
+ VNSvOutPortB(dwIoBase + MAC_REG_CFG, *(pbyCxtBuf + MAC_REG_CFG));
+
+ // restore PS Config.
+ for (ii = MAC_REG_PSCFG; ii < MAC_REG_BBREGCTL; ii++) {
+ VNSvOutPortB(dwIoBase + ii, *(pbyCxtBuf + ii));
+ }
+
+ // restore CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0));
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR));
+ VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, *(unsigned long *)(pbyCxtBuf + MAC_REG_BCNDMAPTR));
+
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0));
+
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1));
}
/*
@@ -728,36 +720,35 @@ void MACvRestoreContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
* Return Value: true if all values are the same; otherwise false
*
*/
-bool MACbCompareContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
+bool MACbCompareContext(unsigned long dwIoBase, unsigned char *pbyCxtBuf)
{
- unsigned long dwData;
-
- // compare MAC context to determine if this is a power lost init,
- // return true for power remaining init, return false for power lost init
+ unsigned long dwData;
- // compare CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
- VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, &dwData);
- if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0)) {
- return false;
- }
+ // compare MAC context to determine if this is a power lost init,
+ // return true for power remaining init, return false for power lost init
- VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, &dwData);
- if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR)) {
- return false;
- }
+ // compare CURR_RX_DESC_ADDR, CURR_TX_DESC_ADDR
+ VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, &dwData);
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_TXDMAPTR0)) {
+ return false;
+ }
- VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, &dwData);
- if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0)) {
- return false;
- }
+ VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, &dwData);
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_AC0DMAPTR)) {
+ return false;
+ }
- VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, &dwData);
- if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1)) {
- return false;
- }
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, &dwData);
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR0)) {
+ return false;
+ }
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, &dwData);
+ if (dwData != *(unsigned long *)(pbyCxtBuf + MAC_REG_RXDMAPTR1)) {
+ return false;
+ }
- return true;
+ return true;
}
/*
@@ -773,24 +764,23 @@ bool MACbCompareContext (unsigned long dwIoBase, unsigned char *pbyCxtBuf)
* Return Value: true if Reset Success; otherwise false
*
*/
-bool MACbSoftwareReset (unsigned long dwIoBase)
+bool MACbSoftwareReset(unsigned long dwIoBase)
{
- unsigned char byData;
- unsigned short ww;
-
- // turn on HOSTCR_SOFTRST, just write 0x01 to reset
- //MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_SOFTRST);
- VNSvOutPortB(dwIoBase+ MAC_REG_HOSTCR, 0x01);
-
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
- if ( !(byData & HOSTCR_SOFTRST))
- break;
- }
- if (ww == W_MAX_TIMEOUT)
- return false;
- return true;
-
+ unsigned char byData;
+ unsigned short ww;
+
+ // turn on HOSTCR_SOFTRST, just write 0x01 to reset
+ //MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_SOFTRST);
+ VNSvOutPortB(dwIoBase + MAC_REG_HOSTCR, 0x01);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
+ if (!(byData & HOSTCR_SOFTRST))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT)
+ return false;
+ return true;
}
/*
@@ -806,24 +796,24 @@ bool MACbSoftwareReset (unsigned long dwIoBase)
* Return Value: true if success; otherwise false
*
*/
-bool MACbSafeSoftwareReset (unsigned long dwIoBase)
+bool MACbSafeSoftwareReset(unsigned long dwIoBase)
{
- unsigned char abyTmpRegData[MAC_MAX_CONTEXT_SIZE_PAGE0+MAC_MAX_CONTEXT_SIZE_PAGE1];
- bool bRetVal;
-
- // PATCH....
- // save some important register's value, then do
- // reset, then restore register's value
-
- // save MAC context
- MACvSaveContext(dwIoBase, abyTmpRegData);
- // do reset
- bRetVal = MACbSoftwareReset(dwIoBase);
- //BBvSoftwareReset(pDevice->PortOffset);
- // restore MAC context, except CR0
- MACvRestoreContext(dwIoBase, abyTmpRegData);
-
- return bRetVal;
+ unsigned char abyTmpRegData[MAC_MAX_CONTEXT_SIZE_PAGE0+MAC_MAX_CONTEXT_SIZE_PAGE1];
+ bool bRetVal;
+
+ // PATCH....
+ // save some important register's value, then do
+ // reset, then restore register's value
+
+ // save MAC context
+ MACvSaveContext(dwIoBase, abyTmpRegData);
+ // do reset
+ bRetVal = MACbSoftwareReset(dwIoBase);
+ //BBvSoftwareReset(pDevice->PortOffset);
+ // restore MAC context, except CR0
+ MACvRestoreContext(dwIoBase, abyTmpRegData);
+
+ return bRetVal;
}
/*
@@ -839,52 +829,52 @@ bool MACbSafeSoftwareReset (unsigned long dwIoBase)
* Return Value: true if success; otherwise false
*
*/
-bool MACbSafeRxOff (unsigned long dwIoBase)
+bool MACbSafeRxOff(unsigned long dwIoBase)
{
- unsigned short ww;
- unsigned long dwData;
- unsigned char byData;
-
- // turn off wow temp for turn off Rx safely
-
- // Clear RX DMA0,1
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_CLRRUN);
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_CLRRUN);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData);
- if (!(dwData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x10);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x10)\n");
- return(false);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData);
- if ( !(dwData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x11);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x11)\n");
- return(false);
- }
-
- // try to safe shutdown RX
- MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON);
- // W_MAX_TIMEOUT is the timeout period
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
- if ( !(byData & HOSTCR_RXONST))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x12);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x12)\n");
- return(false);
- }
- return true;
+ unsigned short ww;
+ unsigned long dwData;
+ unsigned char byData;
+
+ // turn off wow temp for turn off Rx safely
+
+ // Clear RX DMA0,1
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_CLRRUN);
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_CLRRUN);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData);
+ if (!(dwData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x10);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x10)\n");
+ return false;
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData);
+ if (!(dwData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x11);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x11)\n");
+ return false;
+ }
+
+ // try to safe shutdown RX
+ MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON);
+ // W_MAX_TIMEOUT is the timeout period
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
+ if (!(byData & HOSTCR_RXONST))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x12);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x12)\n");
+ return false;
+ }
+ return true;
}
/*
@@ -900,55 +890,54 @@ bool MACbSafeRxOff (unsigned long dwIoBase)
* Return Value: true if success; otherwise false
*
*/
-bool MACbSafeTxOff (unsigned long dwIoBase)
+bool MACbSafeTxOff(unsigned long dwIoBase)
{
- unsigned short ww;
- unsigned long dwData;
- unsigned char byData;
-
- // Clear TX DMA
- //Tx0
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_CLRRUN);
- //AC0
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_CLRRUN);
-
-
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData);
- if ( !(dwData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x20);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x20)\n");
- return(false);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData);
- if ( !(dwData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x21);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x21)\n");
- return(false);
- }
-
- // try to safe shutdown TX
- MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON);
-
- // W_MAX_TIMEOUT is the timeout period
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
- if ( !(byData & HOSTCR_TXONST))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x24);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x24)\n");
- return(false);
- }
- return true;
+ unsigned short ww;
+ unsigned long dwData;
+ unsigned char byData;
+
+ // Clear TX DMA
+ //Tx0
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_CLRRUN);
+ //AC0
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_CLRRUN);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData);
+ if (!(dwData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x20);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x20)\n");
+ return false;
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData);
+ if (!(dwData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x21);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x21)\n");
+ return false;
+ }
+
+ // try to safe shutdown TX
+ MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON);
+
+ // W_MAX_TIMEOUT is the timeout period
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_HOSTCR, &byData);
+ if (!(byData & HOSTCR_TXONST))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x24);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x24)\n");
+ return false;
+ }
+ return true;
}
/*
@@ -964,26 +953,26 @@ bool MACbSafeTxOff (unsigned long dwIoBase)
* Return Value: true if success; otherwise false
*
*/
-bool MACbSafeStop (unsigned long dwIoBase)
+bool MACbSafeStop(unsigned long dwIoBase)
{
- MACvRegBitsOff(dwIoBase, MAC_REG_TCR, TCR_AUTOBCNTX);
-
- if (MACbSafeRxOff(dwIoBase) == false) {
- DBG_PORT80(0xA1);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeRxOff == false)\n");
- MACbSafeSoftwareReset(dwIoBase);
- return false;
- }
- if (MACbSafeTxOff(dwIoBase) == false) {
- DBG_PORT80(0xA2);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" MACbSafeTxOff == false)\n");
- MACbSafeSoftwareReset(dwIoBase);
- return false;
- }
-
- MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_MACEN);
-
- return true;
+ MACvRegBitsOff(dwIoBase, MAC_REG_TCR, TCR_AUTOBCNTX);
+
+ if (MACbSafeRxOff(dwIoBase) == false) {
+ DBG_PORT80(0xA1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " MACbSafeRxOff == false)\n");
+ MACbSafeSoftwareReset(dwIoBase);
+ return false;
+ }
+ if (MACbSafeTxOff(dwIoBase) == false) {
+ DBG_PORT80(0xA2);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " MACbSafeTxOff == false)\n");
+ MACbSafeSoftwareReset(dwIoBase);
+ return false;
+ }
+
+ MACvRegBitsOff(dwIoBase, MAC_REG_HOSTCR, HOSTCR_MACEN);
+
+ return true;
}
/*
@@ -999,18 +988,18 @@ bool MACbSafeStop (unsigned long dwIoBase)
* Return Value: true if success; otherwise false
*
*/
-bool MACbShutdown (unsigned long dwIoBase)
+bool MACbShutdown(unsigned long dwIoBase)
{
- // disable MAC IMR
- MACvIntDisable(dwIoBase);
- MACvSetLoopbackMode(dwIoBase, MAC_LB_INTERNAL);
- // stop the adapter
- if (!MACbSafeStop(dwIoBase)) {
- MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
- return false;
- }
- MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
- return true;
+ // disable MAC IMR
+ MACvIntDisable(dwIoBase);
+ MACvSetLoopbackMode(dwIoBase, MAC_LB_INTERNAL);
+ // stop the adapter
+ if (!MACbSafeStop(dwIoBase)) {
+ MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
+ return false;
+ }
+ MACvSetLoopbackMode(dwIoBase, MAC_LB_NONE);
+ return true;
}
/*
@@ -1026,43 +1015,31 @@ bool MACbShutdown (unsigned long dwIoBase)
* Return Value: none
*
*/
-void MACvInitialize (unsigned long dwIoBase)
+void MACvInitialize(unsigned long dwIoBase)
{
- // clear sticky bits
- MACvClearStckDS(dwIoBase);
- // disable force PME-enable
- VNSvOutPortB(dwIoBase + MAC_REG_PMC1, PME_OVR);
- // only 3253 A
- /*
- MACvPwrEvntDisable(dwIoBase);
- // clear power status
- VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPSR0, 0x0F0F);
- */
-
- // do reset
- MACbSoftwareReset(dwIoBase);
-
- // issue AUTOLD in EECSR to reload eeprom
- //MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD);
- // wait until EEPROM loading complete
- //while (true) {
- // u8 u8Data;
- // VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &u8Data);
- // if ( !(u8Data & I2MCSR_AUTOLD))
- // break;
- //}
-
- // reset TSF counter
- VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
- // enable TSF counter
- VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
-
-
- // set packet filter
- // receive directed and broadcast address
-
- MACvSetPacketFilter(dwIoBase, PKT_TYPE_DIRECTED | PKT_TYPE_BROADCAST);
-
+ // clear sticky bits
+ MACvClearStckDS(dwIoBase);
+ // disable force PME-enable
+ VNSvOutPortB(dwIoBase + MAC_REG_PMC1, PME_OVR);
+ // only 3253 A
+ /*
+ MACvPwrEvntDisable(dwIoBase);
+ // clear power status
+ VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPSR0, 0x0F0F);
+ */
+
+ // do reset
+ MACbSoftwareReset(dwIoBase);
+
+ // reset TSF counter
+ VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
+ // enable TSF counter
+ VNSvOutPortB(dwIoBase + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
+
+ // set packet filter
+ // receive directed and broadcast address
+
+ MACvSetPacketFilter(dwIoBase, PKT_TYPE_DIRECTED | PKT_TYPE_BROADCAST);
}
/*
@@ -1079,28 +1056,28 @@ void MACvInitialize (unsigned long dwIoBase)
* Return Value: none
*
*/
-void MACvSetCurrRx0DescAddr (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
+void MACvSetCurrRx0DescAddr(unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-unsigned short ww;
-unsigned char byData;
-unsigned char byOrgDMACtl;
-
- VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byOrgDMACtl);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0+2, DMACTL_RUN);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byData);
- if ( !(byData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x13);
- }
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, dwCurrDescAddr);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN);
- }
+ unsigned short ww;
+ unsigned char byData;
+ unsigned char byOrgDMACtl;
+
+ VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byOrgDMACtl);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0+2, DMACTL_RUN);
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL0, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x13);
+ }
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR0, dwCurrDescAddr);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN);
+ }
}
/*
@@ -1117,28 +1094,28 @@ unsigned char byOrgDMACtl;
* Return Value: none
*
*/
-void MACvSetCurrRx1DescAddr (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
+void MACvSetCurrRx1DescAddr(unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-unsigned short ww;
-unsigned char byData;
-unsigned char byOrgDMACtl;
-
- VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byOrgDMACtl);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1+2, DMACTL_RUN);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byData);
- if ( !(byData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x14);
- }
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, dwCurrDescAddr);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN);
- }
+ unsigned short ww;
+ unsigned char byData;
+ unsigned char byOrgDMACtl;
+
+ VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byOrgDMACtl);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1+2, DMACTL_RUN);
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_RXDMACTL1, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x14);
+ }
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMAPTR1, dwCurrDescAddr);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN);
+ }
}
/*
@@ -1155,28 +1132,28 @@ unsigned char byOrgDMACtl;
* Return Value: none
*
*/
-void MACvSetCurrTx0DescAddrEx (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
+void MACvSetCurrTx0DescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-unsigned short ww;
-unsigned char byData;
-unsigned char byOrgDMACtl;
-
- VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byOrgDMACtl);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData);
- if ( !(byData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x25);
- }
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, dwCurrDescAddr);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN);
- }
+ unsigned short ww;
+ unsigned char byData;
+ unsigned char byOrgDMACtl;
+
+ VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byOrgDMACtl);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN);
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x25);
+ }
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMAPTR0, dwCurrDescAddr);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN);
+ }
}
/*
@@ -1193,41 +1170,39 @@ unsigned char byOrgDMACtl;
* Return Value: none
*
*/
- //TxDMA1 = AC0DMA
-void MACvSetCurrAC0DescAddrEx (unsigned long dwIoBase, unsigned long dwCurrDescAddr)
+//TxDMA1 = AC0DMA
+void MACvSetCurrAC0DescAddrEx(unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
-unsigned short ww;
-unsigned char byData;
-unsigned char byOrgDMACtl;
-
- VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byOrgDMACtl);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN);
- }
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData);
- if (!(byData & DMACTL_RUN))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x26);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x26)\n");
- }
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, dwCurrDescAddr);
- if (byOrgDMACtl & DMACTL_RUN) {
- VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN);
- }
+ unsigned short ww;
+ unsigned char byData;
+ unsigned char byOrgDMACtl;
+
+ VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byOrgDMACtl);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN);
+ }
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x26);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x26)\n");
+ }
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMAPTR, dwCurrDescAddr);
+ if (byOrgDMACtl & DMACTL_RUN) {
+ VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN);
+ }
}
-
-
-void MACvSetCurrTXDescAddr (int iTxType, unsigned long dwIoBase, unsigned long dwCurrDescAddr)
+void MACvSetCurrTXDescAddr(int iTxType, unsigned long dwIoBase, unsigned long dwCurrDescAddr)
{
- if(iTxType == TYPE_AC0DMA){
- MACvSetCurrAC0DescAddrEx(dwIoBase, dwCurrDescAddr);
- }else if(iTxType == TYPE_TXDMA0){
- MACvSetCurrTx0DescAddrEx(dwIoBase, dwCurrDescAddr);
- }
+ if (iTxType == TYPE_AC0DMA) {
+ MACvSetCurrAC0DescAddrEx(dwIoBase, dwCurrDescAddr);
+ } else if (iTxType == TYPE_TXDMA0) {
+ MACvSetCurrTx0DescAddrEx(dwIoBase, dwCurrDescAddr);
+ }
}
/*
@@ -1244,26 +1219,25 @@ void MACvSetCurrTXDescAddr (int iTxType, unsigned long dwIoBase, unsigned long d
* Return Value: none
*
*/
-void MACvTimer0MicroSDelay (unsigned long dwIoBase, unsigned int uDelay)
+void MACvTimer0MicroSDelay(unsigned long dwIoBase, unsigned int uDelay)
{
-unsigned char byValue;
-unsigned int uu,ii;
-
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
- VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelay);
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE));
- for(ii=0;ii<66;ii++) { // assume max PCI clock is 66Mhz
- for (uu = 0; uu < uDelay; uu++) {
- VNSvInPortB(dwIoBase + MAC_REG_TMCTL0, &byValue);
- if ((byValue == 0) ||
- (byValue & TMCTL_TSUSP)) {
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
- return;
- }
- }
- }
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
-
+ unsigned char byValue;
+ unsigned int uu, ii;
+
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
+ VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelay);
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE));
+ for (ii = 0; ii < 66; ii++) { // assume max PCI clock is 66Mhz
+ for (uu = 0; uu < uDelay; uu++) {
+ VNSvInPortB(dwIoBase + MAC_REG_TMCTL0, &byValue);
+ if ((byValue == 0) ||
+ (byValue & TMCTL_TSUSP)) {
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
+ return;
+ }
+ }
+ }
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
}
/*
@@ -1280,11 +1254,11 @@ unsigned int uu,ii;
* Return Value: none
*
*/
-void MACvOneShotTimer0MicroSec (unsigned long dwIoBase, unsigned int uDelayTime)
+void MACvOneShotTimer0MicroSec(unsigned long dwIoBase, unsigned int uDelayTime)
{
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
- VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelayTime);
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE));
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, 0);
+ VNSvOutPortD(dwIoBase + MAC_REG_TMDATA0, uDelayTime);
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL0, (TMCTL_TMD | TMCTL_TE));
}
/*
@@ -1301,143 +1275,141 @@ void MACvOneShotTimer0MicroSec (unsigned long dwIoBase, unsigned int uDelayTime)
* Return Value: none
*
*/
-void MACvOneShotTimer1MicroSec (unsigned long dwIoBase, unsigned int uDelayTime)
+void MACvOneShotTimer1MicroSec(unsigned long dwIoBase, unsigned int uDelayTime)
{
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, 0);
- VNSvOutPortD(dwIoBase + MAC_REG_TMDATA1, uDelayTime);
- VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, (TMCTL_TMD | TMCTL_TE));
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, 0);
+ VNSvOutPortD(dwIoBase + MAC_REG_TMDATA1, uDelayTime);
+ VNSvOutPortB(dwIoBase + MAC_REG_TMCTL1, (TMCTL_TMD | TMCTL_TE));
}
-
-void MACvSetMISCFifo (unsigned long dwIoBase, unsigned short wOffset, unsigned long dwData)
+void MACvSetMISCFifo(unsigned long dwIoBase, unsigned short wOffset, unsigned long dwData)
{
- if (wOffset > 273)
- return;
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ if (wOffset > 273)
+ return;
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
}
-
-bool MACbTxDMAOff (unsigned long dwIoBase, unsigned int idx)
+bool MACbTxDMAOff(unsigned long dwIoBase, unsigned int idx)
{
-unsigned char byData;
-unsigned int ww = 0;
-
- if (idx == TYPE_TXDMA0) {
- VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData);
- if ( !(byData & DMACTL_RUN))
- break;
- }
- } else if (idx == TYPE_AC0DMA) {
- VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData);
- if ( !(byData & DMACTL_RUN))
- break;
- }
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x29);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x29)\n");
- return false;
- }
- return true;
+ unsigned char byData;
+ unsigned int ww = 0;
+
+ if (idx == TYPE_TXDMA0) {
+ VNSvOutPortB(dwIoBase + MAC_REG_TXDMACTL0+2, DMACTL_RUN);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_TXDMACTL0, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ } else if (idx == TYPE_AC0DMA) {
+ VNSvOutPortB(dwIoBase + MAC_REG_AC0DMACTL+2, DMACTL_RUN);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_AC0DMACTL, &byData);
+ if (!(byData & DMACTL_RUN))
+ break;
+ }
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x29);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x29)\n");
+ return false;
+ }
+ return true;
}
-void MACvClearBusSusInd (unsigned long dwIoBase)
+void MACvClearBusSusInd(unsigned long dwIoBase)
{
- unsigned long dwOrgValue;
- unsigned int ww;
- // check if BcnSusInd enabled
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
- if( !(dwOrgValue & EnCFG_BcnSusInd))
- return;
- //Set BcnSusClr
- dwOrgValue = dwOrgValue | EnCFG_BcnSusClr;
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
- if( !(dwOrgValue & EnCFG_BcnSusInd))
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x33);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n");
- }
+ unsigned long dwOrgValue;
+ unsigned int ww;
+ // check if BcnSusInd enabled
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
+ if (!(dwOrgValue & EnCFG_BcnSusInd))
+ return;
+ //Set BcnSusClr
+ dwOrgValue = dwOrgValue | EnCFG_BcnSusClr;
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
+ if (!(dwOrgValue & EnCFG_BcnSusInd))
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x33);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x33)\n");
+ }
}
-void MACvEnableBusSusEn (unsigned long dwIoBase)
+void MACvEnableBusSusEn(unsigned long dwIoBase)
{
- unsigned char byOrgValue;
- unsigned long dwOrgValue;
- unsigned int ww;
- // check if BcnSusInd enabled
- VNSvInPortB(dwIoBase + MAC_REG_CFG , &byOrgValue);
-
- //Set BcnSusEn
- byOrgValue = byOrgValue | CFG_BCNSUSEN;
- VNSvOutPortB(dwIoBase + MAC_REG_ENCFG, byOrgValue);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
- if(dwOrgValue & EnCFG_BcnSusInd)
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x34);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x34)\n");
- }
+ unsigned char byOrgValue;
+ unsigned long dwOrgValue;
+ unsigned int ww;
+ // check if BcnSusInd enabled
+ VNSvInPortB(dwIoBase + MAC_REG_CFG , &byOrgValue);
+
+ //Set BcnSusEn
+ byOrgValue = byOrgValue | CFG_BCNSUSEN;
+ VNSvOutPortB(dwIoBase + MAC_REG_ENCFG, byOrgValue);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue);
+ if (dwOrgValue & EnCFG_BcnSusInd)
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x34);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x34)\n");
+ }
}
-bool MACbFlushSYNCFifo (unsigned long dwIoBase)
+bool MACbFlushSYNCFifo(unsigned long dwIoBase)
{
- unsigned char byOrgValue;
- unsigned int ww;
- // Read MACCR
- VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue);
-
- // Set SYNCFLUSH
- byOrgValue = byOrgValue | MACCR_SYNCFLUSH;
- VNSvOutPortB(dwIoBase + MAC_REG_MACCR, byOrgValue);
-
- // Check if SyncFlushOK
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue);
- if(byOrgValue & MACCR_SYNCFLUSHOK)
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x35);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n");
- }
- return true;
+ unsigned char byOrgValue;
+ unsigned int ww;
+ // Read MACCR
+ VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue);
+
+ // Set SYNCFLUSH
+ byOrgValue = byOrgValue | MACCR_SYNCFLUSH;
+ VNSvOutPortB(dwIoBase + MAC_REG_MACCR, byOrgValue);
+
+ // Check if SyncFlushOK
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_MACCR , &byOrgValue);
+ if (byOrgValue & MACCR_SYNCFLUSHOK)
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x35);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x33)\n");
+ }
+ return true;
}
-bool MACbPSWakeup (unsigned long dwIoBase)
+bool MACbPSWakeup(unsigned long dwIoBase)
{
- unsigned char byOrgValue;
- unsigned int ww;
- // Read PSCTL
- if (MACbIsRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PS)) {
- return true;
- }
- // Disable PS
- MACvRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PSEN);
-
- // Check if SyncFlushOK
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_PSCTL , &byOrgValue);
- if(byOrgValue & PSCTL_WAKEDONE)
- break;
- }
- if (ww == W_MAX_TIMEOUT) {
- DBG_PORT80(0x36);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" DBG_PORT80(0x33)\n");
- return false;
- }
- return true;
+ unsigned char byOrgValue;
+ unsigned int ww;
+ // Read PSCTL
+ if (MACbIsRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PS)) {
+ return true;
+ }
+ // Disable PS
+ MACvRegBitsOff(dwIoBase, MAC_REG_PSCTL, PSCTL_PSEN);
+
+ // Check if SyncFlushOK
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortB(dwIoBase + MAC_REG_PSCTL , &byOrgValue);
+ if (byOrgValue & PSCTL_WAKEDONE)
+ break;
+ }
+ if (ww == W_MAX_TIMEOUT) {
+ DBG_PORT80(0x36);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " DBG_PORT80(0x33)\n");
+ return false;
+ }
+ return true;
}
/*
@@ -1455,59 +1427,56 @@ bool MACbPSWakeup (unsigned long dwIoBase)
*
*/
-void MACvSetKeyEntry (unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
- unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID)
+void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
+ unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID)
{
-unsigned short wOffset;
-unsigned long dwData;
-int ii;
-
- if (byLocalID <= 1)
- return;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetKeyEntry\n");
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
-
- dwData = 0;
- dwData |= wKeyCtl;
- dwData <<= 16;
- dwData |= MAKEWORD(*(pbyAddr+4), *(pbyAddr+5));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
-
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- wOffset++;
-
- dwData = 0;
- dwData |= *(pbyAddr+3);
- dwData <<= 8;
- dwData |= *(pbyAddr+2);
- dwData <<= 8;
- dwData |= *(pbyAddr+1);
- dwData <<= 8;
- dwData |= *(pbyAddr+0);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2. wOffset: %d, Data: %lX\n", wOffset, dwData);
-
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- wOffset++;
-
- wOffset += (uKeyIdx * 4);
- for (ii=0;ii<4;ii++) {
- // always push 128 bits
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- }
+ unsigned short wOffset;
+ unsigned long dwData;
+ int ii;
+
+ if (byLocalID <= 1)
+ return;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvSetKeyEntry\n");
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
+
+ dwData = 0;
+ dwData |= wKeyCtl;
+ dwData <<= 16;
+ dwData |= MAKEWORD(*(pbyAddr+4), *(pbyAddr+5));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
+
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ wOffset++;
+
+ dwData = 0;
+ dwData |= *(pbyAddr+3);
+ dwData <<= 8;
+ dwData |= *(pbyAddr+2);
+ dwData <<= 8;
+ dwData |= *(pbyAddr+1);
+ dwData <<= 8;
+ dwData |= *(pbyAddr+0);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2. wOffset: %d, Data: %lX\n", wOffset, dwData);
+
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ wOffset++;
+
+ wOffset += (uKeyIdx * 4);
+ for (ii = 0; ii < 4; ii++) {
+ // always push 128 bits
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ }
}
-
-
/*
* Description:
* Disable the Key Entry by MISCFIFO
@@ -1522,19 +1491,18 @@ int ii;
* Return Value: none
*
*/
-void MACvDisableKeyEntry (unsigned long dwIoBase, unsigned int uEntryIdx)
+void MACvDisableKeyEntry(unsigned long dwIoBase, unsigned int uEntryIdx)
{
-unsigned short wOffset;
+ unsigned short wOffset;
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, 0);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, 0);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
}
-
/*
* Description:
* Set the default Key (KeyEntry[10]) by MISCFIFO
@@ -1550,42 +1518,40 @@ unsigned short wOffset;
*
*/
-void MACvSetDefaultKeyEntry (unsigned long dwIoBase, unsigned int uKeyLen,
- unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
+void MACvSetDefaultKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
{
-unsigned short wOffset;
-unsigned long dwData;
-int ii;
-
- if (byLocalID <= 1)
- return;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetDefaultKeyEntry\n");
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
-
- wOffset++;
- wOffset++;
- wOffset += (uKeyIdx * 4);
- // always push 128 bits
- for (ii=0; ii<3; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- }
- dwData = *pdwKey;
- if (uKeyLen == WLAN_WEP104_KEYLEN) {
- dwData |= 0x80000000;
- }
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+3);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"End. wOffset: %d, Data: %lX\n", wOffset+3, dwData);
-
+ unsigned short wOffset;
+ unsigned long dwData;
+ int ii;
+
+ if (byLocalID <= 1)
+ return;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvSetDefaultKeyEntry\n");
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
+
+ wOffset++;
+ wOffset++;
+ wOffset += (uKeyIdx * 4);
+ // always push 128 bits
+ for (ii = 0; ii < 3; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ }
+ dwData = *pdwKey;
+ if (uKeyLen == WLAN_WEP104_KEYLEN) {
+ dwData |= 0x80000000;
+ }
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+3);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "End. wOffset: %d, Data: %lX\n", wOffset+3, dwData);
}
-
/*
* Description:
* Enable default Key (KeyEntry[10]) by MISCFIFO
@@ -1601,25 +1567,24 @@ int ii;
*
*/
/*
-void MACvEnableDefaultKey (unsigned long dwIoBase, unsigned char byLocalID)
-{
-unsigned short wOffset;
-unsigned long dwData;
+ void MACvEnableDefaultKey(unsigned long dwIoBase, unsigned char byLocalID)
+ {
+ unsigned short wOffset;
+ unsigned long dwData;
+ if (byLocalID <= 1)
+ return;
- if (byLocalID <= 1)
- return;
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
+ dwData = 0xC0440000;
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvEnableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData);
- dwData = 0xC0440000;
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvEnableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData);
-
-}
+ }
*/
/*
@@ -1636,20 +1601,19 @@ unsigned long dwData;
* Return Value: none
*
*/
-void MACvDisableDefaultKey (unsigned long dwIoBase)
+void MACvDisableDefaultKey(unsigned long dwIoBase)
{
-unsigned short wOffset;
-unsigned long dwData;
-
+ unsigned short wOffset;
+ unsigned long dwData;
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
- dwData = 0x0;
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvDisableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData);
+ dwData = 0x0;
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvDisableDefaultKey: wOffset: %d, Data: %lX\n", wOffset, dwData);
}
/*
@@ -1666,48 +1630,44 @@ unsigned long dwData;
* Return Value: none
*
*/
-void MACvSetDefaultTKIPKeyEntry (unsigned long dwIoBase, unsigned int uKeyLen,
- unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
+void MACvSetDefaultTKIPKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID)
{
-unsigned short wOffset;
-unsigned long dwData;
-int ii;
-
- if (byLocalID <= 1)
- return;
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetDefaultTKIPKeyEntry\n");
- wOffset = MISCFIFO_KEYETRY0;
- // Kyle test : change offset from 10 -> 0
- wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
-
- dwData = 0xC0660000;
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- wOffset++;
-
- dwData = 0;
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- wOffset++;
-
- wOffset += (uKeyIdx * 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, idx:%d\n", wOffset, *pdwKey, uKeyIdx);
- // always push 128 bits
- for (ii=0; ii<4; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
- }
-
+ unsigned short wOffset;
+ unsigned long dwData;
+ int ii;
+
+ if (byLocalID <= 1)
+ return;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvSetDefaultTKIPKeyEntry\n");
+ wOffset = MISCFIFO_KEYETRY0;
+ // Kyle test : change offset from 10 -> 0
+ wOffset += (10 * MISCFIFO_KEYENTRYSIZE);
+
+ dwData = 0xC0660000;
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ wOffset++;
+
+ dwData = 0;
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ wOffset++;
+
+ wOffset += (uKeyIdx * 4);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1. wOffset: %d, Data: %lX, idx:%d\n", wOffset, *pdwKey, uKeyIdx);
+ // always push 128 bits
+ for (ii = 0; ii < 4; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "2.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ }
}
-
-
/*
* Description:
* Set the Key Control by MISCFIFO
@@ -1723,28 +1683,25 @@ int ii;
*
*/
-void MACvSetDefaultKeyCtl (unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx, unsigned char byLocalID)
+void MACvSetDefaultKeyCtl(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx, unsigned char byLocalID)
{
-unsigned short wOffset;
-unsigned long dwData;
-
- if (byLocalID <= 1)
- return;
+ unsigned short wOffset;
+ unsigned long dwData;
+ if (byLocalID <= 1)
+ return;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MACvSetKeyEntry\n");
- wOffset = MISCFIFO_KEYETRY0;
- wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MACvSetKeyEntry\n");
+ wOffset = MISCFIFO_KEYETRY0;
+ wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
- dwData = 0;
- dwData |= wKeyCtl;
- dwData <<= 16;
- dwData |= 0xffff;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
-
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
- VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
+ dwData = 0;
+ dwData |= wKeyCtl;
+ dwData <<= 16;
+ dwData |= 0xffff;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "1. wOffset: %d, Data: %lX, KeyCtl:%X\n", wOffset, dwData, wKeyCtl);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset);
+ VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, dwData);
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
}
-
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index adfb366f4901..3f177f7c581c 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -197,7 +197,6 @@
#define MAC_REG_PWRCCK 0x73
#define MAC_REG_PWROFDM 0x7C
-
//
// Bits in the BCFG0 register
//
@@ -398,7 +397,6 @@
#define IMR_AC0DMA 0x00000002 //
#define IMR_TXDMA0 0x00000001 //
-
//
// Bits in the ISR register
//
@@ -422,7 +420,6 @@
#define ISR_AC0DMA 0x00000002 //
#define ISR_TXDMA0 0x00000001 //
-
//
// Bits in the PSCFG register
//
@@ -513,7 +510,6 @@
//
#define MISCFFCTL_WRITE 0x0001 //
-
//
// Bits in WAKEUPEN0
//
@@ -557,7 +553,6 @@
#define GPIO1_MD 0x10 //
#define GPIO1_DATA 0x20 //
-
//
// Bits in the MSRCTL register
//
@@ -576,7 +571,6 @@
#define MSRCTL1_CSAPAREN 0x04
#define MSRCTL1_TXPAUSE 0x01
-
// Loopback mode
#define MAC_LB_EXT 0x02 //
#define MAC_LB_INTERNAL 0x01 //
@@ -595,7 +589,6 @@
#define Default_BI 0x200
-
// MiscFIFO Offset
#define MISCFIFO_KEYETRY0 32
#define MISCFIFO_KEYENTRYSIZE 22
@@ -604,20 +597,20 @@
#define MISCFIFO_SYNDATASIZE 21
// enabled mask value of irq
-#define IMR_MASK_VALUE (IMR_SOFTTIMER1 | \
- IMR_RXDMA1 | \
- IMR_RXNOBUF | \
- IMR_MIBNEARFULL | \
- IMR_SOFTINT | \
- IMR_FETALERR | \
- IMR_WATCHDOG | \
- IMR_SOFTTIMER | \
- IMR_GPIO | \
- IMR_TBTT | \
- IMR_RXDMA0 | \
- IMR_BNTX | \
- IMR_AC0DMA | \
- IMR_TXDMA0)
+#define IMR_MASK_VALUE (IMR_SOFTTIMER1 | \
+ IMR_RXDMA1 | \
+ IMR_RXNOBUF | \
+ IMR_MIBNEARFULL | \
+ IMR_SOFTINT | \
+ IMR_FETALERR | \
+ IMR_WATCHDOG | \
+ IMR_SOFTTIMER | \
+ IMR_GPIO | \
+ IMR_TBTT | \
+ IMR_RXDMA0 | \
+ IMR_BNTX | \
+ IMR_AC0DMA | \
+ IMR_TXDMA0)
// max time out delay time
#define W_MAX_TIMEOUT 0xFFF0U //
@@ -637,412 +630,341 @@
/*--------------------- Export Macros ------------------------------*/
-#define MACvRegBitsOn(dwIoBase, byRegOfs, byBits) \
-{ \
- unsigned char byData; \
- VNSvInPortB(dwIoBase + byRegOfs, &byData); \
- VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
-}
-
-#define MACvWordRegBitsOn(dwIoBase, byRegOfs, wBits) \
-{ \
- unsigned short wData; \
- VNSvInPortW(dwIoBase + byRegOfs, &wData); \
- VNSvOutPortW(dwIoBase + byRegOfs, wData | (wBits)); \
-}
-
-#define MACvDWordRegBitsOn(dwIoBase, byRegOfs, dwBits) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
- VNSvOutPortD(dwIoBase + byRegOfs, dwData | (dwBits)); \
-}
-
-#define MACvRegBitsOnEx(dwIoBase, byRegOfs, byMask, byBits) \
-{ \
- unsigned char byData; \
- VNSvInPortB(dwIoBase + byRegOfs, &byData); \
- byData &= byMask; \
- VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
-}
-
-#define MACvRegBitsOff(dwIoBase, byRegOfs, byBits) \
-{ \
- unsigned char byData; \
- VNSvInPortB(dwIoBase + byRegOfs, &byData); \
- VNSvOutPortB(dwIoBase + byRegOfs, byData & ~(byBits)); \
-}
-
-#define MACvWordRegBitsOff(dwIoBase, byRegOfs, wBits) \
-{ \
- unsigned short wData; \
- VNSvInPortW(dwIoBase + byRegOfs, &wData); \
- VNSvOutPortW(dwIoBase + byRegOfs, wData & ~(wBits)); \
-}
-
-#define MACvDWordRegBitsOff(dwIoBase, byRegOfs, dwBits) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
- VNSvOutPortD(dwIoBase + byRegOfs, dwData & ~(dwBits)); \
-}
-
-#define MACvGetCurrRx0DescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, \
- (unsigned long *)pdwCurrDescAddr); \
-}
-
-#define MACvGetCurrRx1DescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, \
- (unsigned long *)pdwCurrDescAddr); \
-}
-
-#define MACvGetCurrTx0DescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, \
- (unsigned long *)pdwCurrDescAddr); \
-}
-
-#define MACvGetCurrAC0DescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, \
- (unsigned long *)pdwCurrDescAddr); \
-}
-
-#define MACvGetCurrSyncDescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_SYNCDMAPTR, \
- (unsigned long *)pdwCurrDescAddr); \
-}
-
-#define MACvGetCurrATIMDescAddr(dwIoBase, pdwCurrDescAddr) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR, \
- (unsigned long *)pdwCurrDescAddr); \
-} \
+#define MACvRegBitsOn(dwIoBase, byRegOfs, byBits) \
+do { \
+ unsigned char byData; \
+ VNSvInPortB(dwIoBase + byRegOfs, &byData); \
+ VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
+} while (0)
+
+#define MACvWordRegBitsOn(dwIoBase, byRegOfs, wBits) \
+do { \
+ unsigned short wData; \
+ VNSvInPortW(dwIoBase + byRegOfs, &wData); \
+ VNSvOutPortW(dwIoBase + byRegOfs, wData | (wBits)); \
+} while (0)
+
+#define MACvDWordRegBitsOn(dwIoBase, byRegOfs, dwBits) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
+ VNSvOutPortD(dwIoBase + byRegOfs, dwData | (dwBits)); \
+} while (0)
+
+#define MACvRegBitsOnEx(dwIoBase, byRegOfs, byMask, byBits) \
+do { \
+ unsigned char byData; \
+ VNSvInPortB(dwIoBase + byRegOfs, &byData); \
+ byData &= byMask; \
+ VNSvOutPortB(dwIoBase + byRegOfs, byData | (byBits)); \
+} while (0)
+
+#define MACvRegBitsOff(dwIoBase, byRegOfs, byBits) \
+do { \
+ unsigned char byData; \
+ VNSvInPortB(dwIoBase + byRegOfs, &byData); \
+ VNSvOutPortB(dwIoBase + byRegOfs, byData & ~(byBits)); \
+} while (0)
+
+#define MACvWordRegBitsOff(dwIoBase, byRegOfs, wBits) \
+do { \
+ unsigned short wData; \
+ VNSvInPortW(dwIoBase + byRegOfs, &wData); \
+ VNSvOutPortW(dwIoBase + byRegOfs, wData & ~(wBits)); \
+} while (0)
+
+#define MACvDWordRegBitsOff(dwIoBase, byRegOfs, dwBits) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + byRegOfs, &dwData); \
+ VNSvOutPortD(dwIoBase + byRegOfs, dwData & ~(dwBits)); \
+} while (0)
+
+#define MACvGetCurrRx0DescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR0, \
+ (unsigned long *)pdwCurrDescAddr)
+
+#define MACvGetCurrRx1DescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMAPTR1, \
+ (unsigned long *)pdwCurrDescAddr)
+
+#define MACvGetCurrTx0DescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_TXDMAPTR0, \
+ (unsigned long *)pdwCurrDescAddr)
+
+#define MACvGetCurrAC0DescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_AC0DMAPTR, \
+ (unsigned long *)pdwCurrDescAddr)
+
+#define MACvGetCurrSyncDescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_SYNCDMAPTR, \
+ (unsigned long *)pdwCurrDescAddr)
+
+#define MACvGetCurrATIMDescAddr(dwIoBase, pdwCurrDescAddr) \
+ VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR, \
+ (unsigned long *)pdwCurrDescAddr)
// set the chip with current BCN tx descriptor address
-#define MACvSetCurrBCNTxDescAddr(dwIoBase, dwCurrDescAddr) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, \
- dwCurrDescAddr); \
-}
+#define MACvSetCurrBCNTxDescAddr(dwIoBase, dwCurrDescAddr) \
+ VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, \
+ dwCurrDescAddr)
// set the chip with current BCN length
-#define MACvSetCurrBCNLength(dwIoBase, wCurrBCNLength) \
-{ \
- VNSvOutPortW(dwIoBase + MAC_REG_BCNDMACTL+2, \
- wCurrBCNLength); \
-}
-
-#define MACvReadBSSIDAddress(dwIoBase, pbyEtherAddr) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0, \
- (unsigned char *)pbyEtherAddr); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 1, \
- pbyEtherAddr + 1); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 2, \
- pbyEtherAddr + 2); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 3, \
- pbyEtherAddr + 3); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 4, \
- pbyEtherAddr + 4); \
- VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 5, \
- pbyEtherAddr + 5); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-
-#define MACvWriteBSSIDAddress(dwIoBase, pbyEtherAddr) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0, \
- *(pbyEtherAddr)); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 1, \
- *(pbyEtherAddr + 1)); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 2, \
- *(pbyEtherAddr + 2)); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 3, \
- *(pbyEtherAddr + 3)); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 4, \
- *(pbyEtherAddr + 4)); \
- VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 5, \
- *(pbyEtherAddr + 5)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-
-#define MACvReadEtherAddress(dwIoBase, pbyEtherAddr) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0, \
- (unsigned char *)pbyEtherAddr); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 1, \
- pbyEtherAddr + 1); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 2, \
- pbyEtherAddr + 2); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 3, \
- pbyEtherAddr + 3); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 4, \
- pbyEtherAddr + 4); \
- VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 5, \
- pbyEtherAddr + 5); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-
-
-#define MACvWriteEtherAddress(dwIoBase, pbyEtherAddr) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0, \
- *pbyEtherAddr); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 1, \
- *(pbyEtherAddr + 1)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 2, \
- *(pbyEtherAddr + 2)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 3, \
- *(pbyEtherAddr + 3)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 4, \
- *(pbyEtherAddr + 4)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 5, \
- *(pbyEtherAddr + 5)); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-
-
-#define MACvClearISR(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_ISR, IMR_MASK_VALUE); \
-}
-
-#define MACvStart(dwIoBase) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_HOSTCR, \
- (HOSTCR_MACEN | HOSTCR_RXON | HOSTCR_TXON)); \
-}
-
-#define MACvRx0PerPktMode(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKT); \
-}
-
-#define MACvRx0BufferFillMode(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKTCLR); \
-}
-
-#define MACvRx1PerPktMode(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKT); \
-}
-
-#define MACvRx1BufferFillMode(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKTCLR); \
-}
-
-#define MACvRxOn(dwIoBase) \
-{ \
- MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON); \
-}
-
-#define MACvReceive0(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN); \
- } \
-}
-
-#define MACvReceive1(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN); \
- } \
-}
-
-#define MACvTxOn(dwIoBase) \
-{ \
- MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON); \
-}
-
-#define MACvTransmit0(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN); \
- } \
-}
-
-#define MACvTransmitAC0(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN); \
- } \
-}
-
-#define MACvTransmitSYNC(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_SYNCDMACTL, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_RUN); \
- } \
-}
-
-#define MACvTransmitATIM(dwIoBase) \
-{ \
- unsigned long dwData; \
- VNSvInPortD(dwIoBase + MAC_REG_ATIMDMACTL, &dwData); \
- if (dwData & DMACTL_RUN) { \
- VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_WAKE);\
- } \
- else { \
- VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_RUN); \
- } \
-}
-
-#define MACvTransmitBCN(dwIoBase) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_BCNDMACTL, BEACON_READY); \
-}
-
-#define MACvClearStckDS(dwIoBase) \
-{ \
- unsigned char byOrgValue; \
- VNSvInPortB(dwIoBase + MAC_REG_STICKHW, &byOrgValue); \
- byOrgValue = byOrgValue & 0xFC; \
- VNSvOutPortB(dwIoBase + MAC_REG_STICKHW, byOrgValue); \
-}
-
-#define MACvReadISR(dwIoBase, pdwValue) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_ISR, pdwValue); \
-}
-
-#define MACvWriteISR(dwIoBase, dwValue) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_ISR, dwValue); \
-}
-
-#define MACvIntEnable(dwIoBase, dwMask) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_IMR, dwMask); \
-}
-
-#define MACvIntDisable(dwIoBase) \
-{ \
- VNSvOutPortD(dwIoBase + MAC_REG_IMR, 0); \
-}
-
-#define MACvSelectPage0(dwIoBase) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-#define MACvSelectPage1(dwIoBase) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
-}
-
-#define MACvReadMIBCounter(dwIoBase, pdwCounter) \
-{ \
- VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR , pdwCounter); \
-}
-
-#define MACvPwrEvntDisable(dwIoBase) \
-{ \
- VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPEN0, 0x0000); \
-}
-
-#define MACvEnableProtectMD(dwIoBase) \
-{ \
- unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
- dwOrgValue = dwOrgValue | EnCFG_ProtectMd; \
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
-}
-
-#define MACvDisableProtectMD(dwIoBase) \
-{ \
- unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
- dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd; \
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
-}
-
-#define MACvEnableBarkerPreambleMd(dwIoBase) \
-{ \
- unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
- dwOrgValue = dwOrgValue | EnCFG_BarkerPream; \
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
-}
-
-#define MACvDisableBarkerPreambleMd(dwIoBase) \
-{ \
- unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
- dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream; \
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
-}
-
-#define MACvSetBBType(dwIoBase, byTyp) \
-{ \
- unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
- dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK; \
- dwOrgValue = dwOrgValue | (unsigned long) byTyp; \
- VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
-}
-
-#define MACvReadATIMW(dwIoBase, pwCounter) \
-{ \
- VNSvInPortW(dwIoBase + MAC_REG_AIDATIM , pwCounter); \
-}
-
-#define MACvWriteATIMW(dwIoBase, wCounter) \
-{ \
- VNSvOutPortW(dwIoBase + MAC_REG_AIDATIM , wCounter); \
-}
-
-#define MACvWriteCRC16_128(dwIoBase, byRegOfs, wCRC) \
-{ \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
- VNSvOutPortW(dwIoBase + byRegOfs, wCRC); \
- VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
-}
-
-#define MACvGPIOIn(dwIoBase, pbyValue) \
-{ \
- VNSvInPortB(dwIoBase + MAC_REG_GPIOCTL1, pbyValue); \
-}
+#define MACvSetCurrBCNLength(dwIoBase, wCurrBCNLength) \
+ VNSvOutPortW(dwIoBase + MAC_REG_BCNDMACTL+2, \
+ wCurrBCNLength)
+
+#define MACvReadBSSIDAddress(dwIoBase, pbyEtherAddr) \
+do { \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0, \
+ (unsigned char *)pbyEtherAddr); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 1, \
+ pbyEtherAddr + 1); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 2, \
+ pbyEtherAddr + 2); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 3, \
+ pbyEtherAddr + 3); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 4, \
+ pbyEtherAddr + 4); \
+ VNSvInPortB(dwIoBase + MAC_REG_BSSID0 + 5, \
+ pbyEtherAddr + 5); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
+} while (0)
+
+#define MACvWriteBSSIDAddress(dwIoBase, pbyEtherAddr) \
+do { \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0, \
+ *(pbyEtherAddr)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 1, \
+ *(pbyEtherAddr + 1)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 2, \
+ *(pbyEtherAddr + 2)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 3, \
+ *(pbyEtherAddr + 3)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 4, \
+ *(pbyEtherAddr + 4)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_BSSID0 + 5, \
+ *(pbyEtherAddr + 5)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
+} while (0)
+
+#define MACvReadEtherAddress(dwIoBase, pbyEtherAddr) \
+do { \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0, \
+ (unsigned char *)pbyEtherAddr); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 1, \
+ pbyEtherAddr + 1); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 2, \
+ pbyEtherAddr + 2); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 3, \
+ pbyEtherAddr + 3); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 4, \
+ pbyEtherAddr + 4); \
+ VNSvInPortB(dwIoBase + MAC_REG_PAR0 + 5, \
+ pbyEtherAddr + 5); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
+} while (0)
+
+#define MACvWriteEtherAddress(dwIoBase, pbyEtherAddr) \
+do { \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0, \
+ *pbyEtherAddr); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 1, \
+ *(pbyEtherAddr + 1)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 2, \
+ *(pbyEtherAddr + 2)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 3, \
+ *(pbyEtherAddr + 3)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 4, \
+ *(pbyEtherAddr + 4)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAR0 + 5, \
+ *(pbyEtherAddr + 5)); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
+} while (0)
+
+#define MACvClearISR(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_ISR, IMR_MASK_VALUE)
+
+#define MACvStart(dwIoBase) \
+ VNSvOutPortB(dwIoBase + MAC_REG_HOSTCR, \
+ (HOSTCR_MACEN | HOSTCR_RXON | HOSTCR_TXON))
+
+#define MACvRx0PerPktMode(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKT)
+
+#define MACvRx0BufferFillMode(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, RX_PERPKTCLR)
+
+#define MACvRx1PerPktMode(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKT)
+
+#define MACvRx1BufferFillMode(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, RX_PERPKTCLR)
+
+#define MACvRxOn(dwIoBase) \
+ MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_RXON)
+
+#define MACvReceive0(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL0, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL0, DMACTL_RUN); \
+} while (0)
+
+#define MACvReceive1(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_RXDMACTL1, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_RXDMACTL1, DMACTL_RUN); \
+} while (0)
+
+#define MACvTxOn(dwIoBase) \
+ MACvRegBitsOn(dwIoBase, MAC_REG_HOSTCR, HOSTCR_TXON)
+
+#define MACvTransmit0(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_TXDMACTL0, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_TXDMACTL0, DMACTL_RUN); \
+} while (0)
+
+#define MACvTransmitAC0(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_AC0DMACTL, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_AC0DMACTL, DMACTL_RUN); \
+} while (0)
+
+#define MACvTransmitSYNC(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_SYNCDMACTL, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_SYNCDMACTL, DMACTL_RUN); \
+} while (0)
+
+#define MACvTransmitATIM(dwIoBase) \
+do { \
+ unsigned long dwData; \
+ VNSvInPortD(dwIoBase + MAC_REG_ATIMDMACTL, &dwData); \
+ if (dwData & DMACTL_RUN) \
+ VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_WAKE); \
+ else \
+ VNSvOutPortD(dwIoBase + MAC_REG_ATIMDMACTL, DMACTL_RUN); \
+} while (0)
+
+#define MACvTransmitBCN(dwIoBase) \
+ VNSvOutPortB(dwIoBase + MAC_REG_BCNDMACTL, BEACON_READY)
+
+#define MACvClearStckDS(dwIoBase) \
+do { \
+ unsigned char byOrgValue; \
+ VNSvInPortB(dwIoBase + MAC_REG_STICKHW, &byOrgValue); \
+ byOrgValue = byOrgValue & 0xFC; \
+ VNSvOutPortB(dwIoBase + MAC_REG_STICKHW, byOrgValue); \
+} while (0)
+
+#define MACvReadISR(dwIoBase, pdwValue) \
+ VNSvInPortD(dwIoBase + MAC_REG_ISR, pdwValue)
+
+#define MACvWriteISR(dwIoBase, dwValue) \
+ VNSvOutPortD(dwIoBase + MAC_REG_ISR, dwValue)
+
+#define MACvIntEnable(dwIoBase, dwMask) \
+ VNSvOutPortD(dwIoBase + MAC_REG_IMR, dwMask)
+
+#define MACvIntDisable(dwIoBase) \
+ VNSvOutPortD(dwIoBase + MAC_REG_IMR, 0)
+
+#define MACvSelectPage0(dwIoBase) \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0)
+
+#define MACvSelectPage1(dwIoBase) \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1)
+
+#define MACvReadMIBCounter(dwIoBase, pdwCounter) \
+ VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR , pdwCounter)
+
+#define MACvPwrEvntDisable(dwIoBase) \
+ VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPEN0, 0x0000)
+
+#define MACvEnableProtectMD(dwIoBase) \
+do { \
+ unsigned long dwOrgValue; \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ dwOrgValue = dwOrgValue | EnCFG_ProtectMd; \
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
+} while (0)
+
+#define MACvDisableProtectMD(dwIoBase) \
+do { \
+ unsigned long dwOrgValue; \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd; \
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
+} while (0)
+
+#define MACvEnableBarkerPreambleMd(dwIoBase) \
+do { \
+ unsigned long dwOrgValue; \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ dwOrgValue = dwOrgValue | EnCFG_BarkerPream; \
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
+} while (0)
+
+#define MACvDisableBarkerPreambleMd(dwIoBase) \
+do { \
+ unsigned long dwOrgValue; \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream; \
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
+} while (0)
+
+#define MACvSetBBType(dwIoBase, byTyp) \
+do { \
+ unsigned long dwOrgValue; \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK; \
+ dwOrgValue = dwOrgValue | (unsigned long)byTyp; \
+ VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
+} while (0)
+
+#define MACvReadATIMW(dwIoBase, pwCounter) \
+ VNSvInPortW(dwIoBase + MAC_REG_AIDATIM, pwCounter)
+
+#define MACvWriteATIMW(dwIoBase, wCounter) \
+ VNSvOutPortW(dwIoBase + MAC_REG_AIDATIM, wCounter)
+
+#define MACvWriteCRC16_128(dwIoBase, byRegOfs, wCRC) \
+do { \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1); \
+ VNSvOutPortW(dwIoBase + byRegOfs, wCRC); \
+ VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 0); \
+} while (0)
+
+#define MACvGPIOIn(dwIoBase, pbyValue) \
+ VNSvInPortB(dwIoBase + MAC_REG_GPIOCTL1, pbyValue)
#define MACvSetRFLE_LatchBase(dwIoBase) \
-{ \
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT); \
-}
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT)
/*--------------------- Export Classes ----------------------------*/
@@ -1107,7 +1029,7 @@ void MACvOneShotTimer1MicroSec(unsigned long dwIoBase, unsigned int uDelayTime);
void MACvSetMISCFifo(unsigned long dwIoBase, unsigned short wOffset, unsigned long dwData);
-bool MACbTxDMAOff (unsigned long dwIoBase, unsigned int idx);
+bool MACbTxDMAOff(unsigned long dwIoBase, unsigned int idx);
void MACvClearBusSusInd(unsigned long dwIoBase);
void MACvEnableBusSusEn(unsigned long dwIoBase);
@@ -1116,15 +1038,14 @@ bool MACbFlushSYNCFifo(unsigned long dwIoBase);
bool MACbPSWakeup(unsigned long dwIoBase);
void MACvSetKeyEntry(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
- unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID);
+ unsigned int uKeyIdx, unsigned char *pbyAddr, unsigned long *pdwKey, unsigned char byLocalID);
void MACvDisableKeyEntry(unsigned long dwIoBase, unsigned int uEntryIdx);
void MACvSetDefaultKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
- unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
//void MACvEnableDefaultKey(unsigned long dwIoBase, unsigned char byLocalID);
void MACvDisableDefaultKey(unsigned long dwIoBase);
void MACvSetDefaultTKIPKeyEntry(unsigned long dwIoBase, unsigned int uKeyLen,
- unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
+ unsigned int uKeyIdx, unsigned long *pdwKey, unsigned char byLocalID);
void MACvSetDefaultKeyCtl(unsigned long dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx, unsigned char byLocalID);
#endif // __MAC_H__
-
diff --git a/drivers/staging/vt6655/mib.c b/drivers/staging/vt6655/mib.c
index 63ae4adddf2f..6a59652052b6 100644
--- a/drivers/staging/vt6655/mib.c
+++ b/drivers/staging/vt6655/mib.c
@@ -45,7 +45,7 @@
#include "baseband.h"
/*--------------------- Static Definitions -------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
@@ -56,8 +56,6 @@ static int msglevel =MSG_LEVEL_INFO;
/*--------------------- Export Functions --------------------------*/
-
-
/*
* Description: Clear All Statistic Counter
*
@@ -70,13 +68,12 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value: none
*
*/
-void STAvClearAllCounter (PSStatCounter pStatistic)
+void STAvClearAllCounter(PSStatCounter pStatistic)
{
- // set memory to zero
+ // set memory to zero
memset(pStatistic, 0, sizeof(SStatCounter));
}
-
/*
* Description: Update Isr Statistic Counter
*
@@ -90,76 +87,59 @@ void STAvClearAllCounter (PSStatCounter pStatistic)
* Return Value: none
*
*/
-void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, unsigned long dwIsr)
+void STAvUpdateIsrStatCounter(PSStatCounter pStatistic, unsigned long dwIsr)
{
- /**********************/
- /* ABNORMAL interrupt */
- /**********************/
- // not any IMR bit invoke irq
+ /**********************/
+ /* ABNORMAL interrupt */
+ /**********************/
+ // not any IMR bit invoke irq
- if (dwIsr == 0) {
- pStatistic->ISRStat.dwIsrUnknown++;
- return;
- }
+ if (dwIsr == 0) {
+ pStatistic->ISRStat.dwIsrUnknown++;
+ return;
+ }
//Added by Kyle
- if (dwIsr & ISR_TXDMA0) // ISR, bit0
- pStatistic->ISRStat.dwIsrTx0OK++; // TXDMA0 successful
-
- if (dwIsr & ISR_AC0DMA) // ISR, bit1
- pStatistic->ISRStat.dwIsrAC0TxOK++; // AC0DMA successful
-
- if (dwIsr & ISR_BNTX) // ISR, bit2
- pStatistic->ISRStat.dwIsrBeaconTxOK++; // BeaconTx successful
-
- if (dwIsr & ISR_RXDMA0) // ISR, bit3
- pStatistic->ISRStat.dwIsrRx0OK++; // Rx0 successful
-
- if (dwIsr & ISR_TBTT) // ISR, bit4
- pStatistic->ISRStat.dwIsrTBTTInt++; // TBTT successful
-
- if (dwIsr & ISR_SOFTTIMER) // ISR, bit6
- pStatistic->ISRStat.dwIsrSTIMERInt++;
-
- if (dwIsr & ISR_WATCHDOG) // ISR, bit7
- pStatistic->ISRStat.dwIsrWatchDog++;
+ if (dwIsr & ISR_TXDMA0) // ISR, bit0
+ pStatistic->ISRStat.dwIsrTx0OK++; // TXDMA0 successful
- if (dwIsr & ISR_FETALERR) // ISR, bit8
- pStatistic->ISRStat.dwIsrUnrecoverableError++;
+ if (dwIsr & ISR_AC0DMA) // ISR, bit1
+ pStatistic->ISRStat.dwIsrAC0TxOK++; // AC0DMA successful
- if (dwIsr & ISR_SOFTINT) // ISR, bit9
- pStatistic->ISRStat.dwIsrSoftInterrupt++; // software interrupt
+ if (dwIsr & ISR_BNTX) // ISR, bit2
+ pStatistic->ISRStat.dwIsrBeaconTxOK++; // BeaconTx successful
- if (dwIsr & ISR_MIBNEARFULL) // ISR, bit10
- pStatistic->ISRStat.dwIsrMIBNearfull++;
+ if (dwIsr & ISR_RXDMA0) // ISR, bit3
+ pStatistic->ISRStat.dwIsrRx0OK++; // Rx0 successful
- if (dwIsr & ISR_RXNOBUF) // ISR, bit11
- pStatistic->ISRStat.dwIsrRxNoBuf++; // Rx No Buff
+ if (dwIsr & ISR_TBTT) // ISR, bit4
+ pStatistic->ISRStat.dwIsrTBTTInt++; // TBTT successful
- if (dwIsr & ISR_RXDMA1) // ISR, bit12
- pStatistic->ISRStat.dwIsrRx1OK++; // Rx1 successful
+ if (dwIsr & ISR_SOFTTIMER) // ISR, bit6
+ pStatistic->ISRStat.dwIsrSTIMERInt++;
-// if (dwIsr & ISR_ATIMTX) // ISR, bit13
-// pStatistic->ISRStat.dwIsrATIMTxOK++; // ATIMTX successful
+ if (dwIsr & ISR_WATCHDOG) // ISR, bit7
+ pStatistic->ISRStat.dwIsrWatchDog++;
-// if (dwIsr & ISR_SYNCTX) // ISR, bit14
-// pStatistic->ISRStat.dwIsrSYNCTxOK++; // SYNCTX successful
+ if (dwIsr & ISR_FETALERR) // ISR, bit8
+ pStatistic->ISRStat.dwIsrUnrecoverableError++;
-// if (dwIsr & ISR_CFPEND) // ISR, bit18
-// pStatistic->ISRStat.dwIsrCFPEnd++;
+ if (dwIsr & ISR_SOFTINT) // ISR, bit9
+ pStatistic->ISRStat.dwIsrSoftInterrupt++; // software interrupt
-// if (dwIsr & ISR_ATIMEND) // ISR, bit19
-// pStatistic->ISRStat.dwIsrATIMEnd++;
+ if (dwIsr & ISR_MIBNEARFULL) // ISR, bit10
+ pStatistic->ISRStat.dwIsrMIBNearfull++;
-// if (dwIsr & ISR_SYNCFLUSHOK) // ISR, bit20
-// pStatistic->ISRStat.dwIsrSYNCFlushOK++;
+ if (dwIsr & ISR_RXNOBUF) // ISR, bit11
+ pStatistic->ISRStat.dwIsrRxNoBuf++; // Rx No Buff
- if (dwIsr & ISR_SOFTTIMER1) // ISR, bit21
- pStatistic->ISRStat.dwIsrSTIMER1Int++;
+ if (dwIsr & ISR_RXDMA1) // ISR, bit12
+ pStatistic->ISRStat.dwIsrRx1OK++; // Rx1 successful
+ if (dwIsr & ISR_SOFTTIMER1) // ISR, bit21
+ pStatistic->ISRStat.dwIsrSTIMER1Int++;
}
-
/*
* Description: Update Rx Statistic Counter
*
@@ -176,199 +156,175 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, unsigned long dwIsr)
* Return Value: none
*
*/
-void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
- unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
- unsigned char *pbyBuffer, unsigned int cbFrameLength)
+void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
+ unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength)
{
- //need change
- PS802_11Header pHeader = (PS802_11Header)pbyBuffer;
-
- if (byRSR & RSR_ADDROK)
- pStatistic->dwRsrADDROk++;
- if (byRSR & RSR_CRCOK) {
- pStatistic->dwRsrCRCOk++;
-
- pStatistic->ullRsrOK++;
-
- if (cbFrameLength >= ETH_ALEN) {
- // update counters in case of successful transmit
- if (byRSR & RSR_ADDRBROAD) {
- pStatistic->ullRxBroadcastFrames++;
- pStatistic->ullRxBroadcastBytes += (unsigned long long) cbFrameLength;
- }
- else if (byRSR & RSR_ADDRMULTI) {
- pStatistic->ullRxMulticastFrames++;
- pStatistic->ullRxMulticastBytes += (unsigned long long) cbFrameLength;
- }
- else {
- pStatistic->ullRxDirectedFrames++;
- pStatistic->ullRxDirectedBytes += (unsigned long long) cbFrameLength;
- }
- }
- }
-
- if(byRxRate==22) {
- pStatistic->CustomStat.ullRsr11M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr11MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"11M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr11M, (int)pStatistic->CustomStat.ullRsr11MCRCOk, byRSR);
- }
- else if(byRxRate==11) {
- pStatistic->CustomStat.ullRsr5M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr5MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 5M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr5M, (int)pStatistic->CustomStat.ullRsr5MCRCOk, byRSR);
- }
- else if(byRxRate==4) {
- pStatistic->CustomStat.ullRsr2M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr2MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 2M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr2M, (int)pStatistic->CustomStat.ullRsr2MCRCOk, byRSR);
- }
- else if(byRxRate==2){
- pStatistic->CustomStat.ullRsr1M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr1MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 1M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr1M, (int)pStatistic->CustomStat.ullRsr1MCRCOk, byRSR);
- }
- else if(byRxRate==12){
- pStatistic->CustomStat.ullRsr6M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr6MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 6M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr6M, (int)pStatistic->CustomStat.ullRsr6MCRCOk);
- }
- else if(byRxRate==18){
- pStatistic->CustomStat.ullRsr9M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr9MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" 9M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr9M, (int)pStatistic->CustomStat.ullRsr9MCRCOk);
- }
- else if(byRxRate==24){
- pStatistic->CustomStat.ullRsr12M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr12MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"12M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr12M, (int)pStatistic->CustomStat.ullRsr12MCRCOk);
- }
- else if(byRxRate==36){
- pStatistic->CustomStat.ullRsr18M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr18MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"18M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr18M, (int)pStatistic->CustomStat.ullRsr18MCRCOk);
- }
- else if(byRxRate==48){
- pStatistic->CustomStat.ullRsr24M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr24MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"24M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr24M, (int)pStatistic->CustomStat.ullRsr24MCRCOk);
- }
- else if(byRxRate==72){
- pStatistic->CustomStat.ullRsr36M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr36MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"36M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr36M, (int)pStatistic->CustomStat.ullRsr36MCRCOk);
- }
- else if(byRxRate==96){
- pStatistic->CustomStat.ullRsr48M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr48MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"48M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr48M, (int)pStatistic->CustomStat.ullRsr48MCRCOk);
- }
- else if(byRxRate==108){
- pStatistic->CustomStat.ullRsr54M++;
- if(byRSR & RSR_CRCOK) {
- pStatistic->CustomStat.ullRsr54MCRCOk++;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"54M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr54M, (int)pStatistic->CustomStat.ullRsr54MCRCOk);
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Unknown: Total[%d], CRCOK[%d]\n", (int)pStatistic->dwRsrRxPacket+1, (int)pStatistic->dwRsrCRCOk);
- }
-
- if (byRSR & RSR_BSSIDOK)
- pStatistic->dwRsrBSSIDOk++;
-
- if (byRSR & RSR_BCNSSIDOK)
- pStatistic->dwRsrBCNSSIDOk++;
- if (byRSR & RSR_IVLDLEN) //invalid len (> 2312 byte)
- pStatistic->dwRsrLENErr++;
- if (byRSR & RSR_IVLDTYP) //invalid packet type
- pStatistic->dwRsrTYPErr++;
- if (byRSR & (RSR_IVLDTYP | RSR_IVLDLEN))
- pStatistic->dwRsrErr++;
-
- if (byNewRSR & NEWRSR_DECRYPTOK)
- pStatistic->dwNewRsrDECRYPTOK++;
- if (byNewRSR & NEWRSR_CFPIND)
- pStatistic->dwNewRsrCFP++;
- if (byNewRSR & NEWRSR_HWUTSF)
- pStatistic->dwNewRsrUTSF++;
- if (byNewRSR & NEWRSR_BCNHITAID)
- pStatistic->dwNewRsrHITAID++;
- if (byNewRSR & NEWRSR_BCNHITAID0)
- pStatistic->dwNewRsrHITAID0++;
-
- // increase rx packet count
- pStatistic->dwRsrRxPacket++;
- pStatistic->dwRsrRxOctet += cbFrameLength;
-
-
- if (IS_TYPE_DATA(pbyBuffer)) {
- pStatistic->dwRsrRxData++;
- } else if (IS_TYPE_MGMT(pbyBuffer)){
- pStatistic->dwRsrRxManage++;
- } else if (IS_TYPE_CONTROL(pbyBuffer)){
- pStatistic->dwRsrRxControl++;
- }
-
- if (byRSR & RSR_ADDRBROAD)
- pStatistic->dwRsrBroadcast++;
- else if (byRSR & RSR_ADDRMULTI)
- pStatistic->dwRsrMulticast++;
- else
- pStatistic->dwRsrDirected++;
-
- if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl))
- pStatistic->dwRsrRxFragment++;
-
- if (cbFrameLength < ETH_ZLEN + 4) {
- pStatistic->dwRsrRunt++;
- }
- else if (cbFrameLength == ETH_ZLEN + 4) {
- pStatistic->dwRsrRxFrmLen64++;
- }
- else if ((65 <= cbFrameLength) && (cbFrameLength <= 127)) {
- pStatistic->dwRsrRxFrmLen65_127++;
- }
- else if ((128 <= cbFrameLength) && (cbFrameLength <= 255)) {
- pStatistic->dwRsrRxFrmLen128_255++;
- }
- else if ((256 <= cbFrameLength) && (cbFrameLength <= 511)) {
- pStatistic->dwRsrRxFrmLen256_511++;
- }
- else if ((512 <= cbFrameLength) && (cbFrameLength <= 1023)) {
- pStatistic->dwRsrRxFrmLen512_1023++;
- }
- else if ((1024 <= cbFrameLength) && (cbFrameLength <= ETH_FRAME_LEN + 4)) {
- pStatistic->dwRsrRxFrmLen1024_1518++;
- } else if (cbFrameLength > ETH_FRAME_LEN + 4) {
- pStatistic->dwRsrLong++;
- }
-
+ //need change
+ PS802_11Header pHeader = (PS802_11Header)pbyBuffer;
+
+ if (byRSR & RSR_ADDROK)
+ pStatistic->dwRsrADDROk++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->dwRsrCRCOk++;
+
+ pStatistic->ullRsrOK++;
+
+ if (cbFrameLength >= ETH_ALEN) {
+ // update counters in case of successful transmit
+ if (byRSR & RSR_ADDRBROAD) {
+ pStatistic->ullRxBroadcastFrames++;
+ pStatistic->ullRxBroadcastBytes += (unsigned long long) cbFrameLength;
+ } else if (byRSR & RSR_ADDRMULTI) {
+ pStatistic->ullRxMulticastFrames++;
+ pStatistic->ullRxMulticastBytes += (unsigned long long) cbFrameLength;
+ } else {
+ pStatistic->ullRxDirectedFrames++;
+ pStatistic->ullRxDirectedBytes += (unsigned long long) cbFrameLength;
+ }
+ }
+ }
+
+ if (byRxRate == 22) {
+ pStatistic->CustomStat.ullRsr11M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr11MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "11M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr11M, (int)pStatistic->CustomStat.ullRsr11MCRCOk, byRSR);
+ } else if (byRxRate == 11) {
+ pStatistic->CustomStat.ullRsr5M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr5MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " 5M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr5M, (int)pStatistic->CustomStat.ullRsr5MCRCOk, byRSR);
+ } else if (byRxRate == 4) {
+ pStatistic->CustomStat.ullRsr2M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr2MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " 2M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr2M, (int)pStatistic->CustomStat.ullRsr2MCRCOk, byRSR);
+ } else if (byRxRate == 2) {
+ pStatistic->CustomStat.ullRsr1M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr1MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " 1M: ALL[%d], OK[%d]:[%02x]\n", (int)pStatistic->CustomStat.ullRsr1M, (int)pStatistic->CustomStat.ullRsr1MCRCOk, byRSR);
+ } else if (byRxRate == 12) {
+ pStatistic->CustomStat.ullRsr6M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr6MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " 6M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr6M, (int)pStatistic->CustomStat.ullRsr6MCRCOk);
+ } else if (byRxRate == 18) {
+ pStatistic->CustomStat.ullRsr9M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr9MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " 9M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr9M, (int)pStatistic->CustomStat.ullRsr9MCRCOk);
+ } else if (byRxRate == 24) {
+ pStatistic->CustomStat.ullRsr12M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr12MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "12M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr12M, (int)pStatistic->CustomStat.ullRsr12MCRCOk);
+ } else if (byRxRate == 36) {
+ pStatistic->CustomStat.ullRsr18M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr18MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "18M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr18M, (int)pStatistic->CustomStat.ullRsr18MCRCOk);
+ } else if (byRxRate == 48) {
+ pStatistic->CustomStat.ullRsr24M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr24MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "24M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr24M, (int)pStatistic->CustomStat.ullRsr24MCRCOk);
+ } else if (byRxRate == 72) {
+ pStatistic->CustomStat.ullRsr36M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr36MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "36M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr36M, (int)pStatistic->CustomStat.ullRsr36MCRCOk);
+ } else if (byRxRate == 96) {
+ pStatistic->CustomStat.ullRsr48M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr48MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "48M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr48M, (int)pStatistic->CustomStat.ullRsr48MCRCOk);
+ } else if (byRxRate == 108) {
+ pStatistic->CustomStat.ullRsr54M++;
+ if (byRSR & RSR_CRCOK) {
+ pStatistic->CustomStat.ullRsr54MCRCOk++;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "54M: ALL[%d], OK[%d]\n", (int)pStatistic->CustomStat.ullRsr54M, (int)pStatistic->CustomStat.ullRsr54MCRCOk);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Unknown: Total[%d], CRCOK[%d]\n", (int)pStatistic->dwRsrRxPacket+1, (int)pStatistic->dwRsrCRCOk);
+ }
+
+ if (byRSR & RSR_BSSIDOK)
+ pStatistic->dwRsrBSSIDOk++;
+
+ if (byRSR & RSR_BCNSSIDOK)
+ pStatistic->dwRsrBCNSSIDOk++;
+ if (byRSR & RSR_IVLDLEN) //invalid len (> 2312 byte)
+ pStatistic->dwRsrLENErr++;
+ if (byRSR & RSR_IVLDTYP) //invalid packet type
+ pStatistic->dwRsrTYPErr++;
+ if (byRSR & (RSR_IVLDTYP | RSR_IVLDLEN))
+ pStatistic->dwRsrErr++;
+
+ if (byNewRSR & NEWRSR_DECRYPTOK)
+ pStatistic->dwNewRsrDECRYPTOK++;
+ if (byNewRSR & NEWRSR_CFPIND)
+ pStatistic->dwNewRsrCFP++;
+ if (byNewRSR & NEWRSR_HWUTSF)
+ pStatistic->dwNewRsrUTSF++;
+ if (byNewRSR & NEWRSR_BCNHITAID)
+ pStatistic->dwNewRsrHITAID++;
+ if (byNewRSR & NEWRSR_BCNHITAID0)
+ pStatistic->dwNewRsrHITAID0++;
+
+ // increase rx packet count
+ pStatistic->dwRsrRxPacket++;
+ pStatistic->dwRsrRxOctet += cbFrameLength;
+
+ if (IS_TYPE_DATA(pbyBuffer)) {
+ pStatistic->dwRsrRxData++;
+ } else if (IS_TYPE_MGMT(pbyBuffer)) {
+ pStatistic->dwRsrRxManage++;
+ } else if (IS_TYPE_CONTROL(pbyBuffer)) {
+ pStatistic->dwRsrRxControl++;
+ }
+
+ if (byRSR & RSR_ADDRBROAD)
+ pStatistic->dwRsrBroadcast++;
+ else if (byRSR & RSR_ADDRMULTI)
+ pStatistic->dwRsrMulticast++;
+ else
+ pStatistic->dwRsrDirected++;
+
+ if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl))
+ pStatistic->dwRsrRxFragment++;
+
+ if (cbFrameLength < ETH_ZLEN + 4) {
+ pStatistic->dwRsrRunt++;
+ } else if (cbFrameLength == ETH_ZLEN + 4) {
+ pStatistic->dwRsrRxFrmLen64++;
+ } else if ((65 <= cbFrameLength) && (cbFrameLength <= 127)) {
+ pStatistic->dwRsrRxFrmLen65_127++;
+ } else if ((128 <= cbFrameLength) && (cbFrameLength <= 255)) {
+ pStatistic->dwRsrRxFrmLen128_255++;
+ } else if ((256 <= cbFrameLength) && (cbFrameLength <= 511)) {
+ pStatistic->dwRsrRxFrmLen256_511++;
+ } else if ((512 <= cbFrameLength) && (cbFrameLength <= 1023)) {
+ pStatistic->dwRsrRxFrmLen512_1023++;
+ } else if ((1024 <= cbFrameLength) && (cbFrameLength <= ETH_FRAME_LEN + 4)) {
+ pStatistic->dwRsrRxFrmLen1024_1518++;
+ } else if (cbFrameLength > ETH_FRAME_LEN + 4) {
+ pStatistic->dwRsrLong++;
+ }
}
-
-
/*
* Description: Update Rx Statistic Counter and copy Rx buffer
*
@@ -387,31 +343,30 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic,
*/
void
-STAvUpdateRDStatCounterEx (
- PSStatCounter pStatistic,
- unsigned char byRSR,
- unsigned char byNewRSR,
- unsigned char byRxRate,
- unsigned char *pbyBuffer,
- unsigned int cbFrameLength
- )
+STAvUpdateRDStatCounterEx(
+ PSStatCounter pStatistic,
+ unsigned char byRSR,
+ unsigned char byNewRSR,
+ unsigned char byRxRate,
+ unsigned char *pbyBuffer,
+ unsigned int cbFrameLength
+)
{
- STAvUpdateRDStatCounter(
- pStatistic,
- byRSR,
- byNewRSR,
- byRxRate,
- pbyBuffer,
- cbFrameLength
- );
-
- // rx length
- pStatistic->dwCntRxFrmLength = cbFrameLength;
- // rx pattern, we just see 10 bytes for sample
- memcpy(pStatistic->abyCntRxPattern, (unsigned char *)pbyBuffer, 10);
+ STAvUpdateRDStatCounter(
+ pStatistic,
+ byRSR,
+ byNewRSR,
+ byRxRate,
+ pbyBuffer,
+ cbFrameLength
+);
+
+ // rx length
+ pStatistic->dwCntRxFrmLength = cbFrameLength;
+ // rx pattern, we just see 10 bytes for sample
+ memcpy(pStatistic->abyCntRxPattern, (unsigned char *)pbyBuffer, 10);
}
-
/*
* Description: Update Tx Statistic Counter
*
@@ -430,81 +385,73 @@ STAvUpdateRDStatCounterEx (
*
*/
void
-STAvUpdateTDStatCounter (
- PSStatCounter pStatistic,
- unsigned char byTSR0,
- unsigned char byTSR1,
- unsigned char *pbyBuffer,
- unsigned int cbFrameLength,
- unsigned int uIdx
- )
+STAvUpdateTDStatCounter(
+ PSStatCounter pStatistic,
+ unsigned char byTSR0,
+ unsigned char byTSR1,
+ unsigned char *pbyBuffer,
+ unsigned int cbFrameLength,
+ unsigned int uIdx
+)
{
- PWLAN_80211HDR_A4 pHeader;
- unsigned char *pbyDestAddr;
- unsigned char byTSR0_NCR = byTSR0 & TSR0_NCR;
-
-
-
- pHeader = (PWLAN_80211HDR_A4) pbyBuffer;
- if (WLAN_GET_FC_TODS(pHeader->wFrameCtl) == 0) {
- pbyDestAddr = &(pHeader->abyAddr1[0]);
- }
- else {
- pbyDestAddr = &(pHeader->abyAddr3[0]);
- }
- // increase tx packet count
- pStatistic->dwTsrTxPacket[uIdx]++;
- pStatistic->dwTsrTxOctet[uIdx] += cbFrameLength;
-
- if (byTSR0_NCR != 0) {
- pStatistic->dwTsrRetry[uIdx]++;
- pStatistic->dwTsrTotalRetry[uIdx] += byTSR0_NCR;
-
- if (byTSR0_NCR == 1)
- pStatistic->dwTsrOnceRetry[uIdx]++;
- else
- pStatistic->dwTsrMoreThanOnceRetry[uIdx]++;
- }
-
- if ((byTSR1&(TSR1_TERR|TSR1_RETRYTMO|TSR1_TMO|ACK_DATA)) == 0) {
- pStatistic->ullTsrOK[uIdx]++;
- pStatistic->CustomStat.ullTsrAllOK =
- (pStatistic->ullTsrOK[TYPE_AC0DMA] + pStatistic->ullTsrOK[TYPE_TXDMA0]);
- // update counters in case that successful transmit
- if (is_broadcast_ether_addr(pbyDestAddr)) {
- pStatistic->ullTxBroadcastFrames[uIdx]++;
- pStatistic->ullTxBroadcastBytes[uIdx] += (unsigned long long) cbFrameLength;
- }
- else if (is_multicast_ether_addr(pbyDestAddr)) {
- pStatistic->ullTxMulticastFrames[uIdx]++;
- pStatistic->ullTxMulticastBytes[uIdx] += (unsigned long long) cbFrameLength;
- }
- else {
- pStatistic->ullTxDirectedFrames[uIdx]++;
- pStatistic->ullTxDirectedBytes[uIdx] += (unsigned long long) cbFrameLength;
- }
- }
- else {
- if (byTSR1 & TSR1_TERR)
- pStatistic->dwTsrErr[uIdx]++;
- if (byTSR1 & TSR1_RETRYTMO)
- pStatistic->dwTsrRetryTimeout[uIdx]++;
- if (byTSR1 & TSR1_TMO)
- pStatistic->dwTsrTransmitTimeout[uIdx]++;
- if (byTSR1 & ACK_DATA)
- pStatistic->dwTsrACKData[uIdx]++;
- }
-
- if (is_broadcast_ether_addr(pbyDestAddr))
- pStatistic->dwTsrBroadcast[uIdx]++;
- else if (is_multicast_ether_addr(pbyDestAddr))
- pStatistic->dwTsrMulticast[uIdx]++;
- else
- pStatistic->dwTsrDirected[uIdx]++;
-
+ PWLAN_80211HDR_A4 pHeader;
+ unsigned char *pbyDestAddr;
+ unsigned char byTSR0_NCR = byTSR0 & TSR0_NCR;
+
+ pHeader = (PWLAN_80211HDR_A4) pbyBuffer;
+ if (WLAN_GET_FC_TODS(pHeader->wFrameCtl) == 0) {
+ pbyDestAddr = &(pHeader->abyAddr1[0]);
+ } else {
+ pbyDestAddr = &(pHeader->abyAddr3[0]);
+ }
+ // increase tx packet count
+ pStatistic->dwTsrTxPacket[uIdx]++;
+ pStatistic->dwTsrTxOctet[uIdx] += cbFrameLength;
+
+ if (byTSR0_NCR != 0) {
+ pStatistic->dwTsrRetry[uIdx]++;
+ pStatistic->dwTsrTotalRetry[uIdx] += byTSR0_NCR;
+
+ if (byTSR0_NCR == 1)
+ pStatistic->dwTsrOnceRetry[uIdx]++;
+ else
+ pStatistic->dwTsrMoreThanOnceRetry[uIdx]++;
+ }
+
+ if ((byTSR1&(TSR1_TERR|TSR1_RETRYTMO|TSR1_TMO|ACK_DATA)) == 0) {
+ pStatistic->ullTsrOK[uIdx]++;
+ pStatistic->CustomStat.ullTsrAllOK =
+ (pStatistic->ullTsrOK[TYPE_AC0DMA] + pStatistic->ullTsrOK[TYPE_TXDMA0]);
+ // update counters in case that successful transmit
+ if (is_broadcast_ether_addr(pbyDestAddr)) {
+ pStatistic->ullTxBroadcastFrames[uIdx]++;
+ pStatistic->ullTxBroadcastBytes[uIdx] += (unsigned long long) cbFrameLength;
+ } else if (is_multicast_ether_addr(pbyDestAddr)) {
+ pStatistic->ullTxMulticastFrames[uIdx]++;
+ pStatistic->ullTxMulticastBytes[uIdx] += (unsigned long long) cbFrameLength;
+ } else {
+ pStatistic->ullTxDirectedFrames[uIdx]++;
+ pStatistic->ullTxDirectedBytes[uIdx] += (unsigned long long) cbFrameLength;
+ }
+ } else {
+ if (byTSR1 & TSR1_TERR)
+ pStatistic->dwTsrErr[uIdx]++;
+ if (byTSR1 & TSR1_RETRYTMO)
+ pStatistic->dwTsrRetryTimeout[uIdx]++;
+ if (byTSR1 & TSR1_TMO)
+ pStatistic->dwTsrTransmitTimeout[uIdx]++;
+ if (byTSR1 & ACK_DATA)
+ pStatistic->dwTsrACKData[uIdx]++;
+ }
+
+ if (is_broadcast_ether_addr(pbyDestAddr))
+ pStatistic->dwTsrBroadcast[uIdx]++;
+ else if (is_multicast_ether_addr(pbyDestAddr))
+ pStatistic->dwTsrMulticast[uIdx]++;
+ else
+ pStatistic->dwTsrDirected[uIdx]++;
}
-
/*
* Description: Update Tx Statistic Counter and copy Tx buffer
*
@@ -520,23 +467,22 @@ STAvUpdateTDStatCounter (
*
*/
void
-STAvUpdateTDStatCounterEx (
- PSStatCounter pStatistic,
- unsigned char *pbyBuffer,
- unsigned long cbFrameLength
- )
+STAvUpdateTDStatCounterEx(
+ PSStatCounter pStatistic,
+ unsigned char *pbyBuffer,
+ unsigned long cbFrameLength
+)
{
- unsigned int uPktLength;
+ unsigned int uPktLength;
- uPktLength = (unsigned int)cbFrameLength;
+ uPktLength = (unsigned int)cbFrameLength;
- // tx length
- pStatistic->dwCntTxBufLength = uPktLength;
- // tx pattern, we just see 16 bytes for sample
- memcpy(pStatistic->abyCntTxPattern, pbyBuffer, 16);
+ // tx length
+ pStatistic->dwCntTxBufLength = uPktLength;
+ // tx pattern, we just see 16 bytes for sample
+ memcpy(pStatistic->abyCntTxPattern, pbyBuffer, 16);
}
-
/*
* Description: Update 802.11 mib counter
*
@@ -553,28 +499,28 @@ STAvUpdateTDStatCounterEx (
*/
void
STAvUpdate802_11Counter(
- PSDot11Counters p802_11Counter,
- PSStatCounter pStatistic,
- unsigned long dwCounter
- )
+ PSDot11Counters p802_11Counter,
+ PSStatCounter pStatistic,
+ unsigned long dwCounter
+)
{
- //p802_11Counter->TransmittedFragmentCount
- p802_11Counter->MulticastTransmittedFrameCount = (unsigned long long) (pStatistic->dwTsrBroadcast[TYPE_AC0DMA] +
- pStatistic->dwTsrBroadcast[TYPE_TXDMA0] +
- pStatistic->dwTsrMulticast[TYPE_AC0DMA] +
- pStatistic->dwTsrMulticast[TYPE_TXDMA0]);
- p802_11Counter->FailedCount = (unsigned long long) (pStatistic->dwTsrErr[TYPE_AC0DMA] + pStatistic->dwTsrErr[TYPE_TXDMA0]);
- p802_11Counter->RetryCount = (unsigned long long) (pStatistic->dwTsrRetry[TYPE_AC0DMA] + pStatistic->dwTsrRetry[TYPE_TXDMA0]);
- p802_11Counter->MultipleRetryCount = (unsigned long long) (pStatistic->dwTsrMoreThanOnceRetry[TYPE_AC0DMA] +
- pStatistic->dwTsrMoreThanOnceRetry[TYPE_TXDMA0]);
- //p802_11Counter->FrameDuplicateCount
- p802_11Counter->RTSSuccessCount += (unsigned long long) (dwCounter & 0x000000ff);
- p802_11Counter->RTSFailureCount += (unsigned long long) ((dwCounter & 0x0000ff00) >> 8);
- p802_11Counter->ACKFailureCount += (unsigned long long) ((dwCounter & 0x00ff0000) >> 16);
- p802_11Counter->FCSErrorCount += (unsigned long long) ((dwCounter & 0xff000000) >> 24);
- //p802_11Counter->ReceivedFragmentCount
- p802_11Counter->MulticastReceivedFrameCount = (unsigned long long) (pStatistic->dwRsrBroadcast +
- pStatistic->dwRsrMulticast);
+ //p802_11Counter->TransmittedFragmentCount
+ p802_11Counter->MulticastTransmittedFrameCount = (unsigned long long) (pStatistic->dwTsrBroadcast[TYPE_AC0DMA] +
+ pStatistic->dwTsrBroadcast[TYPE_TXDMA0] +
+ pStatistic->dwTsrMulticast[TYPE_AC0DMA] +
+ pStatistic->dwTsrMulticast[TYPE_TXDMA0]);
+ p802_11Counter->FailedCount = (unsigned long long) (pStatistic->dwTsrErr[TYPE_AC0DMA] + pStatistic->dwTsrErr[TYPE_TXDMA0]);
+ p802_11Counter->RetryCount = (unsigned long long) (pStatistic->dwTsrRetry[TYPE_AC0DMA] + pStatistic->dwTsrRetry[TYPE_TXDMA0]);
+ p802_11Counter->MultipleRetryCount = (unsigned long long) (pStatistic->dwTsrMoreThanOnceRetry[TYPE_AC0DMA] +
+ pStatistic->dwTsrMoreThanOnceRetry[TYPE_TXDMA0]);
+ //p802_11Counter->FrameDuplicateCount
+ p802_11Counter->RTSSuccessCount += (unsigned long long) (dwCounter & 0x000000ff);
+ p802_11Counter->RTSFailureCount += (unsigned long long) ((dwCounter & 0x0000ff00) >> 8);
+ p802_11Counter->ACKFailureCount += (unsigned long long) ((dwCounter & 0x00ff0000) >> 16);
+ p802_11Counter->FCSErrorCount += (unsigned long long) ((dwCounter & 0xff000000) >> 24);
+ //p802_11Counter->ReceivedFragmentCount
+ p802_11Counter->MulticastReceivedFrameCount = (unsigned long long) (pStatistic->dwRsrBroadcast +
+ pStatistic->dwRsrMulticast);
}
/*
@@ -592,6 +538,6 @@ STAvUpdate802_11Counter(
void
STAvClear802_11Counter(PSDot11Counters p802_11Counter)
{
- // set memory to zero
+ // set memory to zero
memset(p802_11Counter, 0, sizeof(SDot11Counters));
}
diff --git a/drivers/staging/vt6655/mib.h b/drivers/staging/vt6655/mib.h
index 5cd697a2bc77..6b99c119b78f 100644
--- a/drivers/staging/vt6655/mib.h
+++ b/drivers/staging/vt6655/mib.h
@@ -39,62 +39,61 @@
//
typedef struct tagSDot11Counters {
- unsigned long Length; // Length of structure
- unsigned long long TransmittedFragmentCount;
- unsigned long long MulticastTransmittedFrameCount;
- unsigned long long FailedCount;
- unsigned long long RetryCount;
- unsigned long long MultipleRetryCount;
- unsigned long long RTSSuccessCount;
- unsigned long long RTSFailureCount;
- unsigned long long ACKFailureCount;
- unsigned long long FrameDuplicateCount;
- unsigned long long ReceivedFragmentCount;
- unsigned long long MulticastReceivedFrameCount;
- unsigned long long FCSErrorCount;
- unsigned long long TKIPLocalMICFailures;
- unsigned long long TKIPRemoteMICFailures;
- unsigned long long TKIPICVErrors;
- unsigned long long TKIPCounterMeasuresInvoked;
- unsigned long long TKIPReplays;
- unsigned long long CCMPFormatErrors;
- unsigned long long CCMPReplays;
- unsigned long long CCMPDecryptErrors;
- unsigned long long FourWayHandshakeFailures;
+ unsigned long Length; // Length of structure
+ unsigned long long TransmittedFragmentCount;
+ unsigned long long MulticastTransmittedFrameCount;
+ unsigned long long FailedCount;
+ unsigned long long RetryCount;
+ unsigned long long MultipleRetryCount;
+ unsigned long long RTSSuccessCount;
+ unsigned long long RTSFailureCount;
+ unsigned long long ACKFailureCount;
+ unsigned long long FrameDuplicateCount;
+ unsigned long long ReceivedFragmentCount;
+ unsigned long long MulticastReceivedFrameCount;
+ unsigned long long FCSErrorCount;
+ unsigned long long TKIPLocalMICFailures;
+ unsigned long long TKIPRemoteMICFailures;
+ unsigned long long TKIPICVErrors;
+ unsigned long long TKIPCounterMeasuresInvoked;
+ unsigned long long TKIPReplays;
+ unsigned long long CCMPFormatErrors;
+ unsigned long long CCMPReplays;
+ unsigned long long CCMPDecryptErrors;
+ unsigned long long FourWayHandshakeFailures;
// unsigned long long WEPUndecryptableCount;
// unsigned long long WEPICVErrorCount;
// unsigned long long DecryptSuccessCount;
// unsigned long long DecryptFailureCount;
} SDot11Counters, *PSDot11Counters;
-
//
// MIB2 counter
//
typedef struct tagSMib2Counter {
- long ifIndex;
- char ifDescr[256]; // max size 255 plus zero ending
- // e.g. "interface 1"
- long ifType;
- long ifMtu;
- unsigned long ifSpeed;
- unsigned char ifPhysAddress[ETH_ALEN];
- long ifAdminStatus;
- long ifOperStatus;
- unsigned long ifLastChange;
- unsigned long ifInOctets;
- unsigned long ifInUcastPkts;
- unsigned long ifInNUcastPkts;
- unsigned long ifInDiscards;
- unsigned long ifInErrors;
- unsigned long ifInUnknownProtos;
- unsigned long ifOutOctets;
- unsigned long ifOutUcastPkts;
- unsigned long ifOutNUcastPkts;
- unsigned long ifOutDiscards;
- unsigned long ifOutErrors;
- unsigned long ifOutQLen;
- unsigned long ifSpecific;
+ long ifIndex;
+ char ifDescr[256]; // max size 255 plus zero ending
+ // e.g. "interface 1"
+ long ifType;
+ long ifMtu;
+ unsigned long ifSpeed;
+ unsigned char ifPhysAddress[ETH_ALEN];
+ long ifAdminStatus;
+ long ifOperStatus;
+ unsigned long ifLastChange;
+ unsigned long ifInOctets;
+ unsigned long ifInUcastPkts;
+ unsigned long ifInNUcastPkts;
+ unsigned long ifInDiscards;
+ unsigned long ifInErrors;
+ unsigned long ifInUnknownProtos;
+ unsigned long ifOutOctets;
+ unsigned long ifOutUcastPkts;
+ unsigned long ifOutNUcastPkts;
+ unsigned long ifOutDiscards;
+ unsigned long ifOutErrors;
+ unsigned long ifOutQLen;
+ unsigned long ifSpecific;
} SMib2Counter, *PSMib2Counter;
// Value in the ifType entry
@@ -105,104 +104,100 @@ typedef struct tagSMib2Counter {
#define DOWN 2 //
#define TESTING 3 //
-
//
// RMON counter
//
typedef struct tagSRmonCounter {
- long etherStatsIndex;
- unsigned long etherStatsDataSource;
- unsigned long etherStatsDropEvents;
- unsigned long etherStatsOctets;
- unsigned long etherStatsPkts;
- unsigned long etherStatsBroadcastPkts;
- unsigned long etherStatsMulticastPkts;
- unsigned long etherStatsCRCAlignErrors;
- unsigned long etherStatsUndersizePkts;
- unsigned long etherStatsOversizePkts;
- unsigned long etherStatsFragments;
- unsigned long etherStatsJabbers;
- unsigned long etherStatsCollisions;
- unsigned long etherStatsPkt64Octets;
- unsigned long etherStatsPkt65to127Octets;
- unsigned long etherStatsPkt128to255Octets;
- unsigned long etherStatsPkt256to511Octets;
- unsigned long etherStatsPkt512to1023Octets;
- unsigned long etherStatsPkt1024to1518Octets;
- unsigned long etherStatsOwners;
- unsigned long etherStatsStatus;
+ long etherStatsIndex;
+ unsigned long etherStatsDataSource;
+ unsigned long etherStatsDropEvents;
+ unsigned long etherStatsOctets;
+ unsigned long etherStatsPkts;
+ unsigned long etherStatsBroadcastPkts;
+ unsigned long etherStatsMulticastPkts;
+ unsigned long etherStatsCRCAlignErrors;
+ unsigned long etherStatsUndersizePkts;
+ unsigned long etherStatsOversizePkts;
+ unsigned long etherStatsFragments;
+ unsigned long etherStatsJabbers;
+ unsigned long etherStatsCollisions;
+ unsigned long etherStatsPkt64Octets;
+ unsigned long etherStatsPkt65to127Octets;
+ unsigned long etherStatsPkt128to255Octets;
+ unsigned long etherStatsPkt256to511Octets;
+ unsigned long etherStatsPkt512to1023Octets;
+ unsigned long etherStatsPkt1024to1518Octets;
+ unsigned long etherStatsOwners;
+ unsigned long etherStatsStatus;
} SRmonCounter, *PSRmonCounter;
//
// Custom counter
//
typedef struct tagSCustomCounters {
- unsigned long Length;
-
- unsigned long long ullTsrAllOK;
-
- unsigned long long ullRsr11M;
- unsigned long long ullRsr5M;
- unsigned long long ullRsr2M;
- unsigned long long ullRsr1M;
-
- unsigned long long ullRsr11MCRCOk;
- unsigned long long ullRsr5MCRCOk;
- unsigned long long ullRsr2MCRCOk;
- unsigned long long ullRsr1MCRCOk;
-
- unsigned long long ullRsr54M;
- unsigned long long ullRsr48M;
- unsigned long long ullRsr36M;
- unsigned long long ullRsr24M;
- unsigned long long ullRsr18M;
- unsigned long long ullRsr12M;
- unsigned long long ullRsr9M;
- unsigned long long ullRsr6M;
-
- unsigned long long ullRsr54MCRCOk;
- unsigned long long ullRsr48MCRCOk;
- unsigned long long ullRsr36MCRCOk;
- unsigned long long ullRsr24MCRCOk;
- unsigned long long ullRsr18MCRCOk;
- unsigned long long ullRsr12MCRCOk;
- unsigned long long ullRsr9MCRCOk;
- unsigned long long ullRsr6MCRCOk;
-
+ unsigned long Length;
+
+ unsigned long long ullTsrAllOK;
+
+ unsigned long long ullRsr11M;
+ unsigned long long ullRsr5M;
+ unsigned long long ullRsr2M;
+ unsigned long long ullRsr1M;
+
+ unsigned long long ullRsr11MCRCOk;
+ unsigned long long ullRsr5MCRCOk;
+ unsigned long long ullRsr2MCRCOk;
+ unsigned long long ullRsr1MCRCOk;
+
+ unsigned long long ullRsr54M;
+ unsigned long long ullRsr48M;
+ unsigned long long ullRsr36M;
+ unsigned long long ullRsr24M;
+ unsigned long long ullRsr18M;
+ unsigned long long ullRsr12M;
+ unsigned long long ullRsr9M;
+ unsigned long long ullRsr6M;
+
+ unsigned long long ullRsr54MCRCOk;
+ unsigned long long ullRsr48MCRCOk;
+ unsigned long long ullRsr36MCRCOk;
+ unsigned long long ullRsr24MCRCOk;
+ unsigned long long ullRsr18MCRCOk;
+ unsigned long long ullRsr12MCRCOk;
+ unsigned long long ullRsr9MCRCOk;
+ unsigned long long ullRsr6MCRCOk;
} SCustomCounters, *PSCustomCounters;
-
//
// Custom counter
//
typedef struct tagSISRCounters {
- unsigned long Length;
-
- unsigned long dwIsrTx0OK;
- unsigned long dwIsrAC0TxOK;
- unsigned long dwIsrBeaconTxOK;
- unsigned long dwIsrRx0OK;
- unsigned long dwIsrTBTTInt;
- unsigned long dwIsrSTIMERInt;
- unsigned long dwIsrWatchDog;
- unsigned long dwIsrUnrecoverableError;
- unsigned long dwIsrSoftInterrupt;
- unsigned long dwIsrMIBNearfull;
- unsigned long dwIsrRxNoBuf;
-
- unsigned long dwIsrUnknown; // unknown interrupt count
-
- unsigned long dwIsrRx1OK;
- unsigned long dwIsrATIMTxOK;
- unsigned long dwIsrSYNCTxOK;
- unsigned long dwIsrCFPEnd;
- unsigned long dwIsrATIMEnd;
- unsigned long dwIsrSYNCFlushOK;
- unsigned long dwIsrSTIMER1Int;
- /////////////////////////////////////
+ unsigned long Length;
+
+ unsigned long dwIsrTx0OK;
+ unsigned long dwIsrAC0TxOK;
+ unsigned long dwIsrBeaconTxOK;
+ unsigned long dwIsrRx0OK;
+ unsigned long dwIsrTBTTInt;
+ unsigned long dwIsrSTIMERInt;
+ unsigned long dwIsrWatchDog;
+ unsigned long dwIsrUnrecoverableError;
+ unsigned long dwIsrSoftInterrupt;
+ unsigned long dwIsrMIBNearfull;
+ unsigned long dwIsrRxNoBuf;
+
+ unsigned long dwIsrUnknown; // unknown interrupt count
+
+ unsigned long dwIsrRx1OK;
+ unsigned long dwIsrATIMTxOK;
+ unsigned long dwIsrSYNCTxOK;
+ unsigned long dwIsrCFPEnd;
+ unsigned long dwIsrATIMEnd;
+ unsigned long dwIsrSYNCFlushOK;
+ unsigned long dwIsrSTIMER1Int;
+ /////////////////////////////////////
} SISRCounters, *PSISRCounters;
-
// Value in the etherStatsStatus entry
#define VALID 1 //
#define CREATE_REQUEST 2 //
@@ -213,125 +208,122 @@ typedef struct tagSISRCounters {
// statistic counter
//
typedef struct tagSStatCounter {
- //
- // ISR status count
- //
-
-
- // RSR status count
- //
- unsigned long dwRsrFrmAlgnErr;
- unsigned long dwRsrErr;
- unsigned long dwRsrCRCErr;
- unsigned long dwRsrCRCOk;
- unsigned long dwRsrBSSIDOk;
- unsigned long dwRsrADDROk;
- unsigned long dwRsrBCNSSIDOk;
- unsigned long dwRsrLENErr;
- unsigned long dwRsrTYPErr;
-
- unsigned long dwNewRsrDECRYPTOK;
- unsigned long dwNewRsrCFP;
- unsigned long dwNewRsrUTSF;
- unsigned long dwNewRsrHITAID;
- unsigned long dwNewRsrHITAID0;
-
- unsigned long dwRsrLong;
- unsigned long dwRsrRunt;
-
- unsigned long dwRsrRxControl;
- unsigned long dwRsrRxData;
- unsigned long dwRsrRxManage;
-
- unsigned long dwRsrRxPacket;
- unsigned long dwRsrRxOctet;
- unsigned long dwRsrBroadcast;
- unsigned long dwRsrMulticast;
- unsigned long dwRsrDirected;
- // 64-bit OID
- unsigned long long ullRsrOK;
-
- // for some optional OIDs (64 bits) and DMI support
- unsigned long long ullRxBroadcastBytes;
- unsigned long long ullRxMulticastBytes;
- unsigned long long ullRxDirectedBytes;
- unsigned long long ullRxBroadcastFrames;
- unsigned long long ullRxMulticastFrames;
- unsigned long long ullRxDirectedFrames;
-
- unsigned long dwRsrRxFragment;
- unsigned long dwRsrRxFrmLen64;
- unsigned long dwRsrRxFrmLen65_127;
- unsigned long dwRsrRxFrmLen128_255;
- unsigned long dwRsrRxFrmLen256_511;
- unsigned long dwRsrRxFrmLen512_1023;
- unsigned long dwRsrRxFrmLen1024_1518;
-
- // TSR status count
- //
- unsigned long dwTsrTotalRetry[TYPE_MAXTD]; // total collision retry count
- unsigned long dwTsrOnceRetry[TYPE_MAXTD]; // this packet only occur one collision
- unsigned long dwTsrMoreThanOnceRetry[TYPE_MAXTD]; // this packet occur more than one collision
- unsigned long dwTsrRetry[TYPE_MAXTD]; // this packet has ever occur collision,
- // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
- unsigned long dwTsrACKData[TYPE_MAXTD];
- unsigned long dwTsrErr[TYPE_MAXTD];
- unsigned long dwAllTsrOK[TYPE_MAXTD];
- unsigned long dwTsrRetryTimeout[TYPE_MAXTD];
- unsigned long dwTsrTransmitTimeout[TYPE_MAXTD];
-
- unsigned long dwTsrTxPacket[TYPE_MAXTD];
- unsigned long dwTsrTxOctet[TYPE_MAXTD];
- unsigned long dwTsrBroadcast[TYPE_MAXTD];
- unsigned long dwTsrMulticast[TYPE_MAXTD];
- unsigned long dwTsrDirected[TYPE_MAXTD];
-
- // RD/TD count
- unsigned long dwCntRxFrmLength;
- unsigned long dwCntTxBufLength;
-
- unsigned char abyCntRxPattern[16];
- unsigned char abyCntTxPattern[16];
-
-
-
- // Software check....
- unsigned long dwCntRxDataErr; // rx buffer data software compare CRC err count
- unsigned long dwCntDecryptErr; // rx buffer data software compare CRC err count
- unsigned long dwCntRxICVErr; // rx buffer data software compare CRC err count
- unsigned int idxRxErrorDesc[TYPE_MAXRD]; // index for rx data error RD
-
- // 64-bit OID
- unsigned long long ullTsrOK[TYPE_MAXTD];
-
- // for some optional OIDs (64 bits) and DMI support
- unsigned long long ullTxBroadcastFrames[TYPE_MAXTD];
- unsigned long long ullTxMulticastFrames[TYPE_MAXTD];
- unsigned long long ullTxDirectedFrames[TYPE_MAXTD];
- unsigned long long ullTxBroadcastBytes[TYPE_MAXTD];
- unsigned long long ullTxMulticastBytes[TYPE_MAXTD];
- unsigned long long ullTxDirectedBytes[TYPE_MAXTD];
+ //
+ // ISR status count
+ //
+
+ // RSR status count
+ //
+ unsigned long dwRsrFrmAlgnErr;
+ unsigned long dwRsrErr;
+ unsigned long dwRsrCRCErr;
+ unsigned long dwRsrCRCOk;
+ unsigned long dwRsrBSSIDOk;
+ unsigned long dwRsrADDROk;
+ unsigned long dwRsrBCNSSIDOk;
+ unsigned long dwRsrLENErr;
+ unsigned long dwRsrTYPErr;
+
+ unsigned long dwNewRsrDECRYPTOK;
+ unsigned long dwNewRsrCFP;
+ unsigned long dwNewRsrUTSF;
+ unsigned long dwNewRsrHITAID;
+ unsigned long dwNewRsrHITAID0;
+
+ unsigned long dwRsrLong;
+ unsigned long dwRsrRunt;
+
+ unsigned long dwRsrRxControl;
+ unsigned long dwRsrRxData;
+ unsigned long dwRsrRxManage;
+
+ unsigned long dwRsrRxPacket;
+ unsigned long dwRsrRxOctet;
+ unsigned long dwRsrBroadcast;
+ unsigned long dwRsrMulticast;
+ unsigned long dwRsrDirected;
+ // 64-bit OID
+ unsigned long long ullRsrOK;
+
+ // for some optional OIDs (64 bits) and DMI support
+ unsigned long long ullRxBroadcastBytes;
+ unsigned long long ullRxMulticastBytes;
+ unsigned long long ullRxDirectedBytes;
+ unsigned long long ullRxBroadcastFrames;
+ unsigned long long ullRxMulticastFrames;
+ unsigned long long ullRxDirectedFrames;
+
+ unsigned long dwRsrRxFragment;
+ unsigned long dwRsrRxFrmLen64;
+ unsigned long dwRsrRxFrmLen65_127;
+ unsigned long dwRsrRxFrmLen128_255;
+ unsigned long dwRsrRxFrmLen256_511;
+ unsigned long dwRsrRxFrmLen512_1023;
+ unsigned long dwRsrRxFrmLen1024_1518;
+
+ // TSR status count
+ //
+ unsigned long dwTsrTotalRetry[TYPE_MAXTD]; // total collision retry count
+ unsigned long dwTsrOnceRetry[TYPE_MAXTD]; // this packet only occur one collision
+ unsigned long dwTsrMoreThanOnceRetry[TYPE_MAXTD]; // this packet occur more than one collision
+ unsigned long dwTsrRetry[TYPE_MAXTD]; // this packet has ever occur collision,
+ // that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
+ unsigned long dwTsrACKData[TYPE_MAXTD];
+ unsigned long dwTsrErr[TYPE_MAXTD];
+ unsigned long dwAllTsrOK[TYPE_MAXTD];
+ unsigned long dwTsrRetryTimeout[TYPE_MAXTD];
+ unsigned long dwTsrTransmitTimeout[TYPE_MAXTD];
+
+ unsigned long dwTsrTxPacket[TYPE_MAXTD];
+ unsigned long dwTsrTxOctet[TYPE_MAXTD];
+ unsigned long dwTsrBroadcast[TYPE_MAXTD];
+ unsigned long dwTsrMulticast[TYPE_MAXTD];
+ unsigned long dwTsrDirected[TYPE_MAXTD];
+
+ // RD/TD count
+ unsigned long dwCntRxFrmLength;
+ unsigned long dwCntTxBufLength;
+
+ unsigned char abyCntRxPattern[16];
+ unsigned char abyCntTxPattern[16];
+
+ // Software check....
+ unsigned long dwCntRxDataErr; // rx buffer data software compare CRC err count
+ unsigned long dwCntDecryptErr; // rx buffer data software compare CRC err count
+ unsigned long dwCntRxICVErr; // rx buffer data software compare CRC err count
+ unsigned int idxRxErrorDesc[TYPE_MAXRD]; // index for rx data error RD
+
+ // 64-bit OID
+ unsigned long long ullTsrOK[TYPE_MAXTD];
+
+ // for some optional OIDs (64 bits) and DMI support
+ unsigned long long ullTxBroadcastFrames[TYPE_MAXTD];
+ unsigned long long ullTxMulticastFrames[TYPE_MAXTD];
+ unsigned long long ullTxDirectedFrames[TYPE_MAXTD];
+ unsigned long long ullTxBroadcastBytes[TYPE_MAXTD];
+ unsigned long long ullTxMulticastBytes[TYPE_MAXTD];
+ unsigned long long ullTxDirectedBytes[TYPE_MAXTD];
// unsigned long dwTxRetryCount[8];
- //
- // ISR status count
- //
- SISRCounters ISRStat;
-
- SCustomCounters CustomStat;
-
- #ifdef Calcu_LinkQual
- //Tx count:
- unsigned long TxNoRetryOkCount; //success tx no retry !
- unsigned long TxRetryOkCount; //success tx but retry !
- unsigned long TxFailCount; //fail tx ?
- //Rx count:
- unsigned long RxOkCnt; //success rx !
- unsigned long RxFcsErrCnt; //fail rx ?
- //statistic
- unsigned long SignalStren;
- unsigned long LinkQuality;
- #endif
+ //
+ // ISR status count
+ //
+ SISRCounters ISRStat;
+
+ SCustomCounters CustomStat;
+
+#ifdef Calcu_LinkQual
+ //Tx count:
+ unsigned long TxNoRetryOkCount; //success tx no retry !
+ unsigned long TxRetryOkCount; //success tx but retry !
+ unsigned long TxFailCount; //fail tx ?
+ //Rx count:
+ unsigned long RxOkCnt; //success rx !
+ unsigned long RxFcsErrCnt; //fail rx ?
+ //statistic
+ unsigned long SignalStren;
+ unsigned long LinkQuality;
+#endif
} SStatCounter, *PSStatCounter;
/*--------------------- Export Classes ----------------------------*/
@@ -345,31 +337,28 @@ void STAvClearAllCounter(PSStatCounter pStatistic);
void STAvUpdateIsrStatCounter(PSStatCounter pStatistic, unsigned long dwIsr);
void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
- unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
- unsigned char *pbyBuffer, unsigned int cbFrameLength);
+ unsigned char byRSR, unsigned char byNewRSR, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength);
void STAvUpdateRDStatCounterEx(PSStatCounter pStatistic,
- unsigned char byRSR, unsigned char byNewRsr, unsigned char byRxRate,
- unsigned char *pbyBuffer, unsigned int cbFrameLength);
+ unsigned char byRSR, unsigned char byNewRsr, unsigned char byRxRate,
+ unsigned char *pbyBuffer, unsigned int cbFrameLength);
void STAvUpdateTDStatCounter(PSStatCounter pStatistic, unsigned char byTSR0, unsigned char byTSR1,
- unsigned char *pbyBuffer, unsigned int cbFrameLength, unsigned int uIdx);
+ unsigned char *pbyBuffer, unsigned int cbFrameLength, unsigned int uIdx);
void STAvUpdateTDStatCounterEx(
- PSStatCounter pStatistic,
- unsigned char *pbyBuffer,
- unsigned long cbFrameLength
- );
+ PSStatCounter pStatistic,
+ unsigned char *pbyBuffer,
+ unsigned long cbFrameLength
+);
void STAvUpdate802_11Counter(
- PSDot11Counters p802_11Counter,
- PSStatCounter pStatistic,
- unsigned long dwCounter
- );
+ PSDot11Counters p802_11Counter,
+ PSStatCounter pStatistic,
+ unsigned long dwCounter
+);
void STAvClear802_11Counter(PSDot11Counters p802_11Counter);
#endif // __MIB_H__
-
-
-
diff --git a/drivers/staging/vt6655/michael.c b/drivers/staging/vt6655/michael.c
index 67618f069d0d..7ea5f7f82f43 100644
--- a/drivers/staging/vt6655/michael.c
+++ b/drivers/staging/vt6655/michael.c
@@ -48,11 +48,11 @@
/*--------------------- Static Functions --------------------------*/
/*
-static unsigned long s_dwGetUINT32(unsigned char *p); // Get unsigned long from 4 bytes LSByte first
-static void s_vPutUINT32(unsigned char *p, unsigned long val); // Put unsigned long into 4 bytes LSByte first
+ static unsigned long s_dwGetUINT32(unsigned char *p); // Get unsigned long from 4 bytes LSByte first
+ static void s_vPutUINT32(unsigned char *p, unsigned long val); // Put unsigned long into 4 bytes LSByte first
*/
static void s_vClear(void); // Clear the internal message,
- // resets the object to the state just after construction.
+// resets the object to the state just after construction.
static void s_vSetKey(unsigned long dwK0, unsigned long dwK1);
static void s_vAppendByte(unsigned char b); // Add a single byte to the internal message
@@ -66,116 +66,110 @@ static unsigned int nBytesInM; // # bytes in M
/*--------------------- Export Functions --------------------------*/
/*
-static unsigned long s_dwGetUINT32 (unsigned char *p)
+ static unsigned long s_dwGetUINT32 (unsigned char *p)
// Convert from unsigned char [] to unsigned long in a portable way
{
- unsigned long res = 0;
- unsigned int i;
- for(i=0; i<4; i++ )
- {
- res |= (*p++) << (8*i);
- }
- return res;
+unsigned long res = 0;
+unsigned int i;
+for (i=0; i<4; i++)
+{
+ res |= (*p++) << (8 * i);
+}
+return res;
}
static void s_vPutUINT32 (unsigned char *p, unsigned long val)
// Convert from unsigned long to unsigned char [] in a portable way
{
- unsigned int i;
- for(i=0; i<4; i++ )
- {
- *p++ = (unsigned char) (val & 0xff);
- val >>= 8;
- }
+ unsigned int i;
+ for (i=0; i<4; i++) {
+ *p++ = (unsigned char) (val & 0xff);
+ val >>= 8;
+ }
}
*/
-static void s_vClear (void)
+static void s_vClear(void)
{
- // Reset the state to the empty message.
- L = K0;
- R = K1;
- nBytesInM = 0;
- M = 0;
+ // Reset the state to the empty message.
+ L = K0;
+ R = K1;
+ nBytesInM = 0;
+ M = 0;
}
-static void s_vSetKey (unsigned long dwK0, unsigned long dwK1)
+static void s_vSetKey(unsigned long dwK0, unsigned long dwK1)
{
- // Set the key
- K0 = dwK0;
- K1 = dwK1;
- // and reset the message
- s_vClear();
+ // Set the key
+ K0 = dwK0;
+ K1 = dwK1;
+ // and reset the message
+ s_vClear();
}
-static void s_vAppendByte (unsigned char b)
+static void s_vAppendByte(unsigned char b)
{
- // Append the byte to our word-sized buffer
- M |= b << (8*nBytesInM);
- nBytesInM++;
- // Process the word if it is full.
- if( nBytesInM >= 4 )
- {
- L ^= M;
- R ^= ROL32( L, 17 );
- L += R;
- R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8);
- L += R;
- R ^= ROL32( L, 3 );
- L += R;
- R ^= ROR32( L, 2 );
- L += R;
- // Clear the buffer
- M = 0;
- nBytesInM = 0;
- }
+ // Append the byte to our word-sized buffer
+ M |= b << (8*nBytesInM);
+ nBytesInM++;
+ // Process the word if it is full.
+ if (nBytesInM >= 4) {
+ L ^= M;
+ R ^= ROL32(L, 17);
+ L += R;
+ R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8);
+ L += R;
+ R ^= ROL32(L, 3);
+ L += R;
+ R ^= ROR32(L, 2);
+ L += R;
+ // Clear the buffer
+ M = 0;
+ nBytesInM = 0;
+ }
}
-void MIC_vInit (unsigned long dwK0, unsigned long dwK1)
+void MIC_vInit(unsigned long dwK0, unsigned long dwK1)
{
- // Set the key
- s_vSetKey(dwK0, dwK1);
+ // Set the key
+ s_vSetKey(dwK0, dwK1);
}
-
-void MIC_vUnInit (void)
+void MIC_vUnInit(void)
{
- // Wipe the key material
- K0 = 0;
- K1 = 0;
+ // Wipe the key material
+ K0 = 0;
+ K1 = 0;
- // And the other fields as well.
- //Note that this sets (L,R) to (K0,K1) which is just fine.
- s_vClear();
+ // And the other fields as well.
+ //Note that this sets (L,R) to (K0,K1) which is just fine.
+ s_vClear();
}
-void MIC_vAppend (unsigned char *src, unsigned int nBytes)
+void MIC_vAppend(unsigned char *src, unsigned int nBytes)
{
- // This is simple
- while (nBytes > 0)
- {
- s_vAppendByte(*src++);
- nBytes--;
- }
+ // This is simple
+ while (nBytes > 0) {
+ s_vAppendByte(*src++);
+ nBytes--;
+ }
}
-void MIC_vGetMIC (unsigned long *pdwL, unsigned long *pdwR)
+void MIC_vGetMIC(unsigned long *pdwL, unsigned long *pdwR)
{
- // Append the minimum padding
- s_vAppendByte(0x5a);
- s_vAppendByte(0);
- s_vAppendByte(0);
- s_vAppendByte(0);
- s_vAppendByte(0);
- // and then zeroes until the length is a multiple of 4
- while( nBytesInM != 0 )
- {
- s_vAppendByte(0);
- }
- // The s_vAppendByte function has already computed the result.
- *pdwL = L;
- *pdwR = R;
- // Reset to the empty message.
- s_vClear();
+ // Append the minimum padding
+ s_vAppendByte(0x5a);
+ s_vAppendByte(0);
+ s_vAppendByte(0);
+ s_vAppendByte(0);
+ s_vAppendByte(0);
+ // and then zeroes until the length is a multiple of 4
+ while (nBytesInM != 0) {
+ s_vAppendByte(0);
+ }
+ // The s_vAppendByte function has already computed the result.
+ *pdwL = L;
+ *pdwR = R;
+ // Reset to the empty message.
+ s_vClear();
}
-
diff --git a/drivers/staging/vt6655/michael.h b/drivers/staging/vt6655/michael.h
index 3131b161d6a9..0828d18ad528 100644
--- a/drivers/staging/vt6655/michael.h
+++ b/drivers/staging/vt6655/michael.h
@@ -49,10 +49,8 @@ void MIC_vGetMIC(unsigned long *pdwL, unsigned long *pdwR);
/*--------------------- Export Macros ------------------------------*/
// Rotation functions on 32 bit values
-#define ROL32( A, n ) \
- ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) )
-#define ROR32( A, n ) ROL32( (A), 32-(n) )
+#define ROL32(A, n) \
+ (((A) << (n)) | (((A)>>(32-(n))) & ((1UL << (n)) - 1)))
+#define ROR32(A, n) ROL32((A), 32-(n))
#endif //__MICHAEL_H__
-
-
diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c
index 661d534304cc..2340d2f0399b 100644
--- a/drivers/staging/vt6655/power.c
+++ b/drivers/staging/vt6655/power.c
@@ -48,19 +48,14 @@
/*--------------------- Static Definitions -------------------------*/
-
-
-
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
-
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
/*+
@@ -71,69 +66,62 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value:
* None.
*
--*/
-
+ -*/
void
PSvEnablePowerSaving(
- void *hDeviceContext,
- unsigned short wListenInterval
- )
+ void *hDeviceContext,
+ unsigned short wListenInterval
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
-
- // set period of power up before TBTT
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
- if (pDevice->eOPMode != OP_MODE_ADHOC) {
- // set AID
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
- } else {
- // set ATIM Window
- MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
- }
- // Set AutoSleep
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
- // Set HWUTSF
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
-
- if (wListenInterval >= 2) {
- // clear always listen beacon
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
- //pDevice->wCFG &= ~CFG_ALB;
- // first time set listen next beacon
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
- pMgmt->wCountToWakeUp = wListenInterval;
- }
- else {
- // always listen beacon
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
- //pDevice->wCFG |= CFG_ALB;
- pMgmt->wCountToWakeUp = 0;
- }
-
- // enable power saving hw function
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
- pDevice->bEnablePSMode = true;
-
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned short wAID = pMgmt->wCurrAID | BIT14 | BIT15;
+
+ // set period of power up before TBTT
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
+ if (pDevice->eOPMode != OP_MODE_ADHOC) {
+ // set AID
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
+ } else {
+ // set ATIM Window
+ MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
+ }
+ // Set AutoSleep
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
+ // Set HWUTSF
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
+
+ if (wListenInterval >= 2) {
+ // clear always listen beacon
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
+ //pDevice->wCFG &= ~CFG_ALB;
+ // first time set listen next beacon
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
+ pMgmt->wCountToWakeUp = wListenInterval;
+ } else {
+ // always listen beacon
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
+ //pDevice->wCFG |= CFG_ALB;
+ pMgmt->wCountToWakeUp = 0;
+ }
+
+ // enable power saving hw function
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
+ pDevice->bEnablePSMode = true;
+
+ if (pDevice->eOPMode == OP_MODE_ADHOC) {
// bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
- }
- // We don't send null pkt in ad hoc mode since beacon will handle this.
- else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
- PSbSendNullPacket(pDevice);
- }
- pDevice->bPWBitOn = true;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n");
- return;
+ }
+ // We don't send null pkt in ad hoc mode since beacon will handle this.
+ else if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
+ PSbSendNullPacket(pDevice);
+ }
+ pDevice->bPWBitOn = true;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable... \n");
+ return;
}
-
-
-
-
-
/*+
*
* Routine Description:
@@ -142,35 +130,34 @@ PSvEnablePowerSaving(
* Return Value:
* None.
*
--*/
+ -*/
void
PSvDisablePowerSaving(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
// PSMgmtObject pMgmt = pDevice->pMgmt;
- // disable power saving hw function
- MACbPSWakeup(pDevice->PortOffset);
- //clear AutoSleep
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
- //clear HWUTSF
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
- // set always listen beacon
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
-
- pDevice->bEnablePSMode = false;
-
- if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
- PSbSendNullPacket(pDevice);
- }
- pDevice->bPWBitOn = false;
- return;
+ // disable power saving hw function
+ MACbPSWakeup(pDevice->PortOffset);
+ //clear AutoSleep
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
+ //clear HWUTSF
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
+ // set always listen beacon
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
+
+ pDevice->bEnablePSMode = false;
+
+ if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) {
+ PSbSendNullPacket(pDevice);
+ }
+ pDevice->bPWBitOn = false;
+ return;
}
-
/*+
*
* Routine Description:
@@ -179,65 +166,62 @@ PSvDisablePowerSaving(
* Return Value:
* true, if power down success
* false, if fail
--*/
-
+ -*/
bool
PSbConsiderPowerDown(
- void *hDeviceContext,
- bool bCheckRxDMA,
- bool bCheckCountToWakeUp
- )
+ void *hDeviceContext,
+ bool bCheckRxDMA,
+ bool bCheckCountToWakeUp
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int uIdx;
-
- // check if already in Doze mode
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
- return true;
-
- if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
- // check if in TIM wake period
- if (pMgmt->bInTIMWake)
- return false;
- }
-
- // check scan state
- if (pDevice->bCmdRunning)
- return false;
-
- // Force PSEN on
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
-
- // check if all TD are empty,
- for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
- if (pDevice->iTDUsed[uIdx] != 0)
- return false;
- }
-
- // check if rx isr is clear
- if (bCheckRxDMA &&
- ((pDevice->dwIsr& ISR_RXDMA0) != 0) &&
- ((pDevice->dwIsr & ISR_RXDMA1) != 0)){
- return false;
- }
-
- if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
- if (bCheckCountToWakeUp &&
- (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
- return false;
- }
- }
-
- // no Tx, no Rx isr, now go to Doze
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
- return true;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int uIdx;
+
+ // check if already in Doze mode
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS))
+ return true;
+
+ if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
+ // check if in TIM wake period
+ if (pMgmt->bInTIMWake)
+ return false;
+ }
+
+ // check scan state
+ if (pDevice->bCmdRunning)
+ return false;
+
+ // Force PSEN on
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
+
+ // check if all TD are empty,
+ for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
+ if (pDevice->iTDUsed[uIdx] != 0)
+ return false;
+ }
+
+ // check if rx isr is clear
+ if (bCheckRxDMA &&
+ ((pDevice->dwIsr & ISR_RXDMA0) != 0) &&
+ ((pDevice->dwIsr & ISR_RXDMA1) != 0)) {
+ return false;
+ }
+
+ if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
+ if (bCheckCountToWakeUp &&
+ (pMgmt->wCountToWakeUp == 0 || pMgmt->wCountToWakeUp == 1)) {
+ return false;
+ }
+ }
+
+ // no Tx, no Rx isr, now go to Doze
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_GO2DOZE);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
+ return true;
}
-
-
/*+
*
* Routine Description:
@@ -246,47 +230,41 @@ PSbConsiderPowerDown(
* Return Value:
* None.
*
--*/
-
-
+ -*/
void
PSvSendPSPOLL(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSTxMgmtPacket pTxPacket = NULL;
-
-
- memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
- WLAN_SET_FC_PWRMGT(0)
- ));
- pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
- memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
- pTxPacket->cbPayloadLen = 0;
- // send the frame
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
- }
- else {
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSTxMgmtPacket pTxPacket = NULL;
+
+ memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_HDR_ADDR2_LEN);
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
+ WLAN_SET_FC_PWRMGT(0)
+));
+ pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
+ memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
+ pTxPacket->cbPayloadLen = 0;
+ // send the frame
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
+ } else {
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet success..\n");
- };
+ };
- return;
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -295,81 +273,75 @@ PSvSendPSPOLL(
* Return Value:
* None.
*
--*/
+ -*/
bool
PSbSendNullPacket(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSTxMgmtPacket pTxPacket = NULL;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int uIdx;
-
-
- if (pDevice->bLinkPass == false) {
- return false;
- }
- #ifdef TxInSleep
- if ((pDevice->bEnablePSMode == false) &&
- (pDevice->fTxDataInSleep == false)){
- return false;
- }
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSTxMgmtPacket pTxPacket = NULL;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int uIdx;
+
+ if (pDevice->bLinkPass == false) {
+ return false;
+ }
+#ifdef TxInSleep
+ if ((pDevice->bEnablePSMode == false) &&
+ (pDevice->fTxDataInSleep == false)) {
+ return false;
+ }
#else
- if (pDevice->bEnablePSMode == false) {
- return false;
- }
+ if (pDevice->bEnablePSMode == false) {
+ return false;
+ }
#endif
- if (pDevice->bEnablePSMode) {
- for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx ++) {
- if (pDevice->iTDUsed[uIdx] != 0)
- return false;
- }
- }
-
- memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
-
- if (pDevice->bEnablePSMode) {
-
- pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
- WLAN_SET_FC_PWRMGT(1)
- ));
- }
- else {
- pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
- WLAN_SET_FC_PWRMGT(0)
- ));
- }
-
- if(pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
- pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
- }
-
- memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
- pTxPacket->cbPayloadLen = 0;
- // send the frame
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
- return false;
- }
- else {
-
+ if (pDevice->bEnablePSMode) {
+ for (uIdx = 0; uIdx < TYPE_MAXTD; uIdx++) {
+ if (pDevice->iTDUsed[uIdx] != 0)
+ return false;
+ }
+ }
+
+ memset(pMgmt->pbyPSPacketPool, 0, sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN);
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyPSPacketPool;
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+
+ if (pDevice->bEnablePSMode) {
+ pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
+ WLAN_SET_FC_PWRMGT(1)
+));
+ } else {
+ pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL) |
+ WLAN_SET_FC_PWRMGT(0)
+));
+ }
+
+ if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
+ pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_TODS(1));
+ }
+
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
+ pTxPacket->cbPayloadLen = 0;
+ // send the frame
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
+ return false;
+ } else {
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet success....\n");
- }
-
+ }
- return true ;
+ return true;
}
/*+
@@ -380,33 +352,31 @@ PSbSendNullPacket(
* Return Value:
* None.
*
--*/
+ -*/
bool
PSbIsNextTBTTWakeUp(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ bool bWakeUp = false;
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- bool bWakeUp = false;
+ if (pMgmt->wListenInterval >= 2) {
+ if (pMgmt->wCountToWakeUp == 0) {
+ pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
+ }
- if (pMgmt->wListenInterval >= 2) {
- if (pMgmt->wCountToWakeUp == 0) {
- pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
- }
+ pMgmt->wCountToWakeUp--;
- pMgmt->wCountToWakeUp --;
+ if (pMgmt->wCountToWakeUp == 1) {
+ // Turn on wake up to listen next beacon
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
+ bWakeUp = true;
+ }
- if (pMgmt->wCountToWakeUp == 1) {
- // Turn on wake up to listen next beacon
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
- bWakeUp = true;
- }
+ }
- }
-
- return bWakeUp;
+ return bWakeUp;
}
-
diff --git a/drivers/staging/vt6655/power.h b/drivers/staging/vt6655/power.h
index 01013b592285..337dd659f12f 100644
--- a/drivers/staging/vt6655/power.h
+++ b/drivers/staging/vt6655/power.h
@@ -29,7 +29,6 @@
#ifndef __POWER_H__
#define __POWER_H__
-
/*--------------------- Export Definitions -------------------------*/
#define C_PWBT 1000 // micro sec. power up before TBTT
#define PS_FAST_INTERVAL 1 // Fast power saving listen interval
@@ -39,10 +38,8 @@
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
// PSDevice pDevice
@@ -50,35 +47,35 @@
bool
PSbConsiderPowerDown(
- void *hDeviceContext,
- bool bCheckRxDMA,
- bool bCheckCountToWakeUp
- );
+ void *hDeviceContext,
+ bool bCheckRxDMA,
+ bool bCheckCountToWakeUp
+);
void
PSvDisablePowerSaving(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void
PSvEnablePowerSaving(
- void *hDeviceContext,
- unsigned short wListenInterval
- );
+ void *hDeviceContext,
+ unsigned short wListenInterval
+);
void
PSvSendPSPOLL(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
bool
PSbSendNullPacket(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
bool
PSbIsNextTBTTWakeUp(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
#endif //__POWER_H__
diff --git a/drivers/staging/vt6655/rc4.c b/drivers/staging/vt6655/rc4.c
index 9856c08b3d77..343b815c0a9e 100644
--- a/drivers/staging/vt6655/rc4.c
+++ b/drivers/staging/vt6655/rc4.c
@@ -34,54 +34,54 @@
void rc4_init(PRC4Ext pRC4, unsigned char *pbyKey, unsigned int cbKey_len)
{
- unsigned int ust1, ust2;
- unsigned int keyindex;
- unsigned int stateindex;
- unsigned char *pbyst;
- unsigned int idx;
+ unsigned int ust1, ust2;
+ unsigned int keyindex;
+ unsigned int stateindex;
+ unsigned char *pbyst;
+ unsigned int idx;
- pbyst = pRC4->abystate;
- pRC4->ux = 0;
- pRC4->uy = 0;
- for (idx = 0; idx < 256; idx++)
- pbyst[idx] = (unsigned char)idx;
- keyindex = 0;
- stateindex = 0;
- for (idx = 0; idx < 256; idx++) {
- ust1 = pbyst[idx];
- stateindex = (stateindex + pbyKey[keyindex] + ust1) & 0xff;
- ust2 = pbyst[stateindex];
- pbyst[stateindex] = (unsigned char)ust1;
- pbyst[idx] = (unsigned char)ust2;
- if (++keyindex >= cbKey_len)
- keyindex = 0;
- }
+ pbyst = pRC4->abystate;
+ pRC4->ux = 0;
+ pRC4->uy = 0;
+ for (idx = 0; idx < 256; idx++)
+ pbyst[idx] = (unsigned char)idx;
+ keyindex = 0;
+ stateindex = 0;
+ for (idx = 0; idx < 256; idx++) {
+ ust1 = pbyst[idx];
+ stateindex = (stateindex + pbyKey[keyindex] + ust1) & 0xff;
+ ust2 = pbyst[stateindex];
+ pbyst[stateindex] = (unsigned char)ust1;
+ pbyst[idx] = (unsigned char)ust2;
+ if (++keyindex >= cbKey_len)
+ keyindex = 0;
+ }
}
unsigned int rc4_byte(PRC4Ext pRC4)
{
- unsigned int ux;
- unsigned int uy;
- unsigned int ustx, usty;
- unsigned char *pbyst;
+ unsigned int ux;
+ unsigned int uy;
+ unsigned int ustx, usty;
+ unsigned char *pbyst;
- pbyst = pRC4->abystate;
- ux = (pRC4->ux + 1) & 0xff;
- ustx = pbyst[ux];
- uy = (ustx + pRC4->uy) & 0xff;
- usty = pbyst[uy];
- pRC4->ux = ux;
- pRC4->uy = uy;
- pbyst[uy] = (unsigned char)ustx;
- pbyst[ux] = (unsigned char)usty;
+ pbyst = pRC4->abystate;
+ ux = (pRC4->ux + 1) & 0xff;
+ ustx = pbyst[ux];
+ uy = (ustx + pRC4->uy) & 0xff;
+ usty = pbyst[uy];
+ pRC4->ux = ux;
+ pRC4->uy = uy;
+ pbyst[uy] = (unsigned char)ustx;
+ pbyst[ux] = (unsigned char)usty;
- return pbyst[(ustx + usty) & 0xff];
+ return pbyst[(ustx + usty) & 0xff];
}
void rc4_encrypt(PRC4Ext pRC4, unsigned char *pbyDest,
- unsigned char *pbySrc, unsigned int cbData_len)
+ unsigned char *pbySrc, unsigned int cbData_len)
{
- unsigned int ii;
- for (ii = 0; ii < cbData_len; ii++)
- pbyDest[ii] = (unsigned char)(pbySrc[ii] ^ rc4_byte(pRC4));
+ unsigned int ii;
+ for (ii = 0; ii < cbData_len; ii++)
+ pbyDest[ii] = (unsigned char)(pbySrc[ii] ^ rc4_byte(pRC4));
}
diff --git a/drivers/staging/vt6655/rc4.h b/drivers/staging/vt6655/rc4.h
index ad04e351365e..74b2eed9bce3 100644
--- a/drivers/staging/vt6655/rc4.h
+++ b/drivers/staging/vt6655/rc4.h
@@ -35,9 +35,9 @@
/*--------------------- Export Definitions -------------------------*/
/*--------------------- Export Types ------------------------------*/
typedef struct {
- unsigned int ux;
- unsigned int uy;
- unsigned char abystate[256];
+ unsigned int ux;
+ unsigned int uy;
+ unsigned char abystate[256];
} RC4Ext, *PRC4Ext;
void rc4_init(PRC4Ext pRC4, unsigned char *pbyKey, unsigned int cbKey_len);
diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c
index aaa231aaf4e9..6948984a25ab 100644
--- a/drivers/staging/vt6655/rf.c
+++ b/drivers/staging/vt6655/rf.c
@@ -46,7 +46,6 @@
#define SWITCH_CHANNEL_DELAY_AL2230 200 //us
#define AL2230_PWR_IDX_LEN 64
-
#define BY_AL7230_REG_LEN 23 //24bit
#define CB_AL7230_INIT_SEQ 16
#define SWITCH_CHANNEL_DELAY_AL7230 200 //us
@@ -56,376 +55,367 @@
/*--------------------- Static Variables --------------------------*/
-
-
const unsigned long dwAL2230InitTable[CB_AL2230_INIT_SEQ] = {
- 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x00FFF300+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0F4DC500+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0805B600+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0146C700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x00068800+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0403B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x00DBBA00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
- 0x0BDFFC00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x00000D00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
- };
+ 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x01A00200+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x00FFF300+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0F4DC500+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0805B600+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0146C700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x00068800+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0403B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x00DBBA00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, //
+ 0x0BDFFC00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x00000D00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x00580F00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
+};
const unsigned long dwAL2230ChannelTable0[CB_MAX_CHANNEL] = {
- 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
- 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
- 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
- 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
- 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
- 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
- 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
- 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
- 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
- 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
- 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
- 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
- 0x03F7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
- 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
- };
+ 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
+ 0x03F79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
+ 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
+ 0x03E79000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
+ 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
+ 0x03F7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
+ 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
+ 0x03E7A000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
+ 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
+ 0x03F7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
+ 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
+ 0x03E7B000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
+ 0x03F7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
+ 0x03E7C000+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
+};
const unsigned long dwAL2230ChannelTable1[CB_MAX_CHANNEL] = {
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
- 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
- 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
- 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
- };
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
+ 0x0B333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
+ 0x03333100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
+ 0x06666100+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW // channel = 14, Tf = 2412M
+};
unsigned long dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = {
- 0x04040900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04041900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04042900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04043900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04044900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04045900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04046900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04047900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04048900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04049900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0404F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04050900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04051900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04052900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04053900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04054900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04055900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04056900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04057900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04058900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04059900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0405F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04060900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04061900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04062900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04063900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04064900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04065900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04066900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04067900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04068900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04069900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0406F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04070900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04071900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04072900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04073900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04074900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04075900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04076900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04077900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04078900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x04079900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x0407F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
- };
+ 0x04040900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04041900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04042900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04043900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04044900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04045900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04046900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04047900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04048900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04049900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0404F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04050900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04051900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04052900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04053900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04054900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04055900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04056900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04057900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04058900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04059900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0405F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04060900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04061900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04062900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04063900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04064900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04065900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04066900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04067900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04068900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04069900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0406F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04070900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04071900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04072900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04073900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04074900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04075900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04076900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04077900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04078900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x04079900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407A900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407B900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407C900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407D900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407E900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x0407F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
+};
//{{ RobertYu:20050104
// 40MHz reference frequency
// Need to Pull PLLON(PE3) low when writing channel registers through 3-wire.
const unsigned long dwAL7230InitTable[CB_AL7230_INIT_SEQ] = {
- 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
- 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
- 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2
- 0x3FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 5FDFA3
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11b/g // Need modify for 11a
- //0x802B4500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B45
- // RoberYu:20050113, Rev0.47 Regsiter Setting Guide
- 0x802B5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B55
- 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 860207
- 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0xE0000A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: E0600A
- 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10)
- //0x00093C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C
- // RoberYu:20050113, Rev0.47 Regsiter Setting Guide
- 0x000A3C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C
- 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF
- };
+ 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
+ 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel1 // Need modify for 11a
+ 0x841FF200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 451FE2
+ 0x3FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 5FDFA3
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11b/g // Need modify for 11a
+ //0x802B4500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B45
+ // RoberYu:20050113, Rev0.47 Regsiter Setting Guide
+ 0x802B5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 8D1B55
+ 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 860207
+ 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0xE0000A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: E0600A
+ 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10)
+ //0x00093C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C
+ // RoberYu:20050113, Rev0.47 Regsiter Setting Guide
+ 0x000A3C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11a: 00143C
+ 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x1ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11a: 12BACF
+};
const unsigned long dwAL7230InitTableAMode[CB_AL7230_INIT_SEQ] = {
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
- 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
- 0x5FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
- 0x67F78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11a // Need modify for 11b/g
- 0x853F5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g, RoberYu:20050113
- 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
- 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0xE0600A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
- 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10)
- 0x00147C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
- 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
- 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11b/g
- };
-
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Channel184 // Need modify for 11b/g
+ 0x451FE200+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
+ 0x5FDFA300+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
+ 0x67F78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // 11a // Need modify for 11b/g
+ 0x853F5500+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g, RoberYu:20050113
+ 0x56AF3600+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0xCE020700+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
+ 0x6EBC0800+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0xE0600A00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
+ 0x08031B00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // init 0x080B1B00 => 0x080F1B00 for 3 wire control TxGain(D10)
+ 0x00147C00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // Need modify for 11b/g
+ 0xFFFFFD00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x00000E00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW,
+ 0x12BACF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // Need modify for 11b/g
+};
const unsigned long dwAL7230ChannelTable0[CB_MAX_CHANNEL] = {
- 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
- 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
- 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
- 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
- 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
- 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
- 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
- 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz //RobertYu: 20050218, update for APNode 0.49
- 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
-
- // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
- 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
- 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
- 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
-
- // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
- // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
-
- 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
- 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
- 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
- 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
- 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
- 0x0FF55000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
- 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
- 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) //RobertYu: 20050218, update for APNode 0.49
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
- 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
- 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
- 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
- 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
- 0x0FF59000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
-
- 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
- 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
- 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
- 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
- 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
- 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
- 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
- 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
- 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
- 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
- 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
- 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
- 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
- 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
- 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
- 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
- };
+ 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
+ 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
+ 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
+ 0x00379000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
+ 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
+ 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
+ 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
+ 0x0037A000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037B000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz //RobertYu: 20050218, update for APNode 0.49
+ 0x0037C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
+
+ // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
+ 0x0FF52000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
+ 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
+ 0x0FF53000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
+
+ // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
+ // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
+
+ 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
+ 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
+ 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
+ 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
+ 0x0FF54000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
+ 0x0FF55000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
+ 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
+ 0x0FF56000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31) //RobertYu: 20050218, update for APNode 0.49
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
+ 0x0FF57000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
+ 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
+ 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
+ 0x0FF58000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
+ 0x0FF59000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
+
+ 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
+ 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
+ 0x0FF5C000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
+ 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
+ 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
+ 0x0FF5D000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
+ 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
+ 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
+ 0x0FF5E000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
+ 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
+ 0x0FF5F000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
+ 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
+ 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
+ 0x0FF60000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
+ 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
+ 0x0FF61000+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
+};
const unsigned long dwAL7230ChannelTable1[CB_MAX_CHANNEL] = {
- 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
- 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
- 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
- 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
- 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
- 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
- 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
- 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
- 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
- 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
- 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
- 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
- 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
- 0x06666100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
-
- // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
- 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
- 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
- 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
- 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
-
- // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
- // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
- 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
- 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
- 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
- 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
- 0x10000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
- 0x1AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
- 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
- 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
- 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
- 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
- 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
- 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
- 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
- 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
- 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
- };
+ 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
+ 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
+ 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
+ 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
+ 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
+ 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
+ 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
+ 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
+ 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
+ 0x1B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
+ 0x03333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
+ 0x0B333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
+ 0x13333100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
+ 0x06666100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
+
+ // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
+ 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
+ 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
+ 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
+ 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
+
+ // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
+ // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
+ 0x1D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
+ 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
+ 0x08000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
+ 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
+ 0x10000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
+ 0x1AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
+ 0x05555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
+ 0x0AAAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
+ 0x15555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
+ 0x00000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
+ 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
+ 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
+ 0x0D555100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
+ 0x18000100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
+ 0x02AAA100+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
+};
const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = {
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
- 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
-
- // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
-
- // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
- // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
- 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
- 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
- };
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 2, Tf = 2417MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 3, Tf = 2422MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 4, Tf = 2427MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 5, Tf = 2432MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 6, Tf = 2437MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 2442MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 2447MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 2452MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 10, Tf = 2457MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 2462MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 2467MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 13, Tf = 2472MHz
+ 0x7FD78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 14, Tf = 2484MHz
+
+ // 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 183, Tf = 4915MHz (15)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 184, Tf = 4920MHz (16)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 185, Tf = 4925MHz (17)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 187, Tf = 4935MHz (18)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 188, Tf = 4940MHz (19)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 189, Tf = 4945MHz (20)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 192, Tf = 4960MHz (21)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 196, Tf = 4980MHz (22)
+
+ // 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
+ // 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165 (Value 23 ~ 56)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 7, Tf = 5035MHz (23)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 8, Tf = 5040MHz (24)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 9, Tf = 5045MHz (25)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 11, Tf = 5055MHz (26)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 12, Tf = 5060MHz (27)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 16, Tf = 5080MHz (28)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 34, Tf = 5170MHz (29)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 36, Tf = 5180MHz (30)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 38, Tf = 5190MHz (31)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 40, Tf = 5200MHz (32)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 42, Tf = 5210MHz (33)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 44, Tf = 5220MHz (34)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 46, Tf = 5230MHz (35)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 48, Tf = 5240MHz (36)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 52, Tf = 5260MHz (37)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 56, Tf = 5280MHz (38)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 60, Tf = 5300MHz (39)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 64, Tf = 5320MHz (40)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 100, Tf = 5500MHz (41)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 104, Tf = 5520MHz (42)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 108, Tf = 5540MHz (43)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 112, Tf = 5560MHz (44)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 116, Tf = 5580MHz (45)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 120, Tf = 5600MHz (46)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 124, Tf = 5620MHz (47)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 128, Tf = 5640MHz (48)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 132, Tf = 5660MHz (49)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 136, Tf = 5680MHz (50)
+ 0x67D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 140, Tf = 5700MHz (51)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 149, Tf = 5745MHz (52)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 153, Tf = 5765MHz (53)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 157, Tf = 5785MHz (54)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW, // channel = 161, Tf = 5805MHz (55)
+ 0x77D78400+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW // channel = 165, Tf = 5825MHz (56)
+};
//}} RobertYu
-
-
-
/*--------------------- Static Functions --------------------------*/
-
-
-
/*
* Description: AIROHA IFRF chip init function
*
@@ -438,72 +428,72 @@ const unsigned long dwAL7230ChannelTable2[CB_MAX_CHANNEL] = {
* Return Value: true if succeeded; false if failed.
*
*/
-bool s_bAL7230Init (unsigned long dwIoBase)
+bool s_bAL7230Init(unsigned long dwIoBase)
{
- int ii;
- bool bResult;
+ int ii;
+ bool bResult;
- bResult = true;
+ bResult = true;
- //3-wire control for normal mode
- VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
+ //3-wire control for normal mode
+ VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI |
- SOFTPWRCTL_TXPEINV));
- BBvPowerSaveModeOFF(dwIoBase); //RobertYu:20050106, have DC value for Calibration
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI |
+ SOFTPWRCTL_TXPEINV));
+ BBvPowerSaveModeOFF(dwIoBase); //RobertYu:20050106, have DC value for Calibration
- for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++)
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[ii]);
+ for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++)
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[ii]);
- // PLL On
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
+ // PLL On
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- //Calibration
- MACvTimer0MicroSDelay(dwIoBase, 150);//150us
- bResult &= IFRFbWriteEmbedded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:disable
- MACvTimer0MicroSDelay(dwIoBase, 30);//30us
- bResult &= IFRFbWriteEmbedded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:disable, RCK:active
- MACvTimer0MicroSDelay(dwIoBase, 30);//30us
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:disable, RCK:disable
+ //Calibration
+ MACvTimer0MicroSDelay(dwIoBase, 150);//150us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:disable
+ MACvTimer0MicroSDelay(dwIoBase, 30);//30us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:disable, RCK:active
+ MACvTimer0MicroSDelay(dwIoBase, 30);//30us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:disable, RCK:disable
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 |
- SOFTPWRCTL_SWPE2 |
- SOFTPWRCTL_SWPECTI |
- SOFTPWRCTL_TXPEINV));
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 |
+ SOFTPWRCTL_SWPE2 |
+ SOFTPWRCTL_SWPECTI |
+ SOFTPWRCTL_TXPEINV));
- BBvPowerSaveModeON(dwIoBase); // RobertYu:20050106
+ BBvPowerSaveModeON(dwIoBase); // RobertYu:20050106
- // PE1: TX_ON, PE2: RX_ON, PE3: PLLON
- //3-wire control for power saving mode
- VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000
+ // PE1: TX_ON, PE2: RX_ON, PE3: PLLON
+ //3-wire control for power saving mode
+ VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000
- return bResult;
+ return bResult;
}
// Need to Pull PLLON low when writing channel registers through 3-wire interface
-bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
+bool s_bAL7230SelectChannel(unsigned long dwIoBase, unsigned char byChannel)
{
- bool bResult;
+ bool bResult;
- bResult = true;
+ bResult = true;
- // PLLON Off
- MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
+ // PLLON Off
+ MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0
- bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1
- bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230ChannelTable0[byChannel - 1]); //Reg0
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230ChannelTable1[byChannel - 1]); //Reg1
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230ChannelTable2[byChannel - 1]); //Reg4
- // PLLOn On
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
+ // PLLOn On
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- // Set Channel[7] = 0 to tell H/W channel is changing now.
- VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F));
- MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL7230);
- // Set Channel[7] = 1 to tell H/W channel change is done.
- VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80));
+ // Set Channel[7] = 0 to tell H/W channel is changing now.
+ VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F));
+ MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL7230);
+ // Set Channel[7] = 1 to tell H/W channel change is done.
+ VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80));
- return bResult;
+ return bResult;
}
/*
@@ -520,7 +510,6 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
*
*/
-
//{{ RobertYu: 20041210
/*
* Description: UW2452 IFRF chip init function
@@ -535,8 +524,6 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
*
*/
-
-
//}} RobertYu
////////////////////////////////////////////////////////////////////////////////
@@ -567,8 +554,6 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
*
*/
-
-
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Functions --------------------------*/
@@ -586,29 +571,27 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
* Return Value: true if succeeded; false if failed.
*
*/
-bool IFRFbWriteEmbedded (unsigned long dwIoBase, unsigned long dwData)
+bool IFRFbWriteEmbedded(unsigned long dwIoBase, unsigned long dwData)
{
- unsigned short ww;
- unsigned long dwValue;
+ unsigned short ww;
+ unsigned long dwValue;
- VNSvOutPortD(dwIoBase + MAC_REG_IFREGCTL, dwData);
+ VNSvOutPortD(dwIoBase + MAC_REG_IFREGCTL, dwData);
- // W_MAX_TIMEOUT is the timeout period
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortD(dwIoBase + MAC_REG_IFREGCTL, &dwValue);
- if (dwValue & IFREGCTL_DONE)
- break;
- }
+ // W_MAX_TIMEOUT is the timeout period
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ VNSvInPortD(dwIoBase + MAC_REG_IFREGCTL, &dwValue);
+ if (dwValue & IFREGCTL_DONE)
+ break;
+ }
- if (ww == W_MAX_TIMEOUT) {
+ if (ww == W_MAX_TIMEOUT) {
// DBG_PORT80_ALWAYS(0x32);
- return false;
- }
- return true;
+ return false;
+ }
+ return true;
}
-
-
/*
* Description: RFMD RF2959 IFRF chip init function
*
@@ -648,72 +631,69 @@ bool IFRFbWriteEmbedded (unsigned long dwIoBase, unsigned long dwData)
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbAL2230Init (unsigned long dwIoBase)
+bool RFbAL2230Init(unsigned long dwIoBase)
{
- int ii;
- bool bResult;
+ int ii;
+ bool bResult;
- bResult = true;
+ bResult = true;
- //3-wire control for normal mode
- VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
+ //3-wire control for normal mode
+ VNSvOutPortB(dwIoBase + MAC_REG_SOFTPWRCTL, 0);
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI |
- SOFTPWRCTL_TXPEINV));
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI |
+ SOFTPWRCTL_TXPEINV));
//2008-8-21 chester <add>
- // PLL Off
-
- MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
-
+ // PLL Off
+ MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- //patch abnormal AL2230 frequency output
+ //patch abnormal AL2230 frequency output
//2008-8-21 chester <add>
- IFRFbWriteEmbedded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+ IFRFbWriteEmbedded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
-
- for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++)
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[ii]);
+ for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++)
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[ii]);
//2008-8-21 chester <add>
-MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us
+ MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us
- // PLL On
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
+ // PLL On
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3);
- MACvTimer0MicroSDelay(dwIoBase, 150);//150us
- bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
- MACvTimer0MicroSDelay(dwIoBase, 30);//30us
- bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
- MACvTimer0MicroSDelay(dwIoBase, 30);//30us
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]);
+ MACvTimer0MicroSDelay(dwIoBase, 150);//150us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+ MACvTimer0MicroSDelay(dwIoBase, 30);//30us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW));
+ MACvTimer0MicroSDelay(dwIoBase, 30);//30us
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]);
- MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 |
- SOFTPWRCTL_SWPE2 |
- SOFTPWRCTL_SWPECTI |
- SOFTPWRCTL_TXPEINV));
+ MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 |
+ SOFTPWRCTL_SWPE2 |
+ SOFTPWRCTL_SWPECTI |
+ SOFTPWRCTL_TXPEINV));
- //3-wire control for power saving mode
- VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000
+ //3-wire control for power saving mode
+ VNSvOutPortB(dwIoBase + MAC_REG_PSPWRSIG, (PSSIG_WPE3 | PSSIG_WPE2)); //1100 0000
- return bResult;
+ return bResult;
}
-bool RFbAL2230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
+bool RFbAL2230SelectChannel(unsigned long dwIoBase, unsigned char byChannel)
{
- bool bResult;
+ bool bResult;
- bResult = true;
+ bResult = true;
- bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]);
- bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]);
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230ChannelTable0[byChannel - 1]);
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230ChannelTable1[byChannel - 1]);
- // Set Channel[7] = 0 to tell H/W channel is changing now.
- VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F));
- MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL2230);
- // Set Channel[7] = 1 to tell H/W channel change is done.
- VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80));
+ // Set Channel[7] = 0 to tell H/W channel is changing now.
+ VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F));
+ MACvTimer0MicroSDelay(dwIoBase, SWITCH_CHANNEL_DELAY_AL2230);
+ // Set Channel[7] = 1 to tell H/W channel change is done.
+ VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel | 0x80));
- return bResult;
+ return bResult;
}
/*
@@ -729,7 +709,6 @@ bool RFbAL2230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
*
*/
-
/*
* Description: Select channel with UW2451 chip
*
@@ -771,29 +750,29 @@ bool RFbAL2230SelectChannel (unsigned long dwIoBase, unsigned char byChannel)
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbInit (
- PSDevice pDevice
- )
+bool RFbInit(
+ PSDevice pDevice
+)
{
-bool bResult = true;
- switch (pDevice->byRFType) {
- case RF_AIROHA :
- case RF_AL2230S:
- pDevice->byMaxPwrLevel = AL2230_PWR_IDX_LEN;
- bResult = RFbAL2230Init(pDevice->PortOffset);
- break;
- case RF_AIROHA7230 :
- pDevice->byMaxPwrLevel = AL7230_PWR_IDX_LEN;
- bResult = s_bAL7230Init(pDevice->PortOffset);
- break;
- case RF_NOTHING :
- bResult = true;
- break;
- default :
- bResult = false;
- break;
- }
- return bResult;
+ bool bResult = true;
+ switch (pDevice->byRFType) {
+ case RF_AIROHA:
+ case RF_AL2230S:
+ pDevice->byMaxPwrLevel = AL2230_PWR_IDX_LEN;
+ bResult = RFbAL2230Init(pDevice->PortOffset);
+ break;
+ case RF_AIROHA7230:
+ pDevice->byMaxPwrLevel = AL7230_PWR_IDX_LEN;
+ bResult = s_bAL7230Init(pDevice->PortOffset);
+ break;
+ case RF_NOTHING:
+ bResult = true;
+ break;
+ default:
+ bResult = false;
+ break;
+ }
+ return bResult;
}
/*
@@ -809,21 +788,21 @@ bool bResult = true;
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbShutDown (
- PSDevice pDevice
- )
+bool RFbShutDown(
+ PSDevice pDevice
+)
{
-bool bResult = true;
-
- switch (pDevice->byRFType) {
- case RF_AIROHA7230 :
- bResult = IFRFbWriteEmbedded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
- break;
- default :
- bResult = true;
- break;
- }
- return bResult;
+ bool bResult = true;
+
+ switch (pDevice->byRFType) {
+ case RF_AIROHA7230:
+ bResult = IFRFbWriteEmbedded(pDevice->PortOffset, 0x1ABAEF00 + (BY_AL7230_REG_LEN << 3) + IFREGCTL_REGW);
+ break;
+ default:
+ bResult = true;
+ break;
+ }
+ return bResult;
}
/*
@@ -839,28 +818,27 @@ bool bResult = true;
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbSelectChannel (unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel)
+bool RFbSelectChannel(unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel)
{
-bool bResult = true;
- switch (byRFType) {
-
- case RF_AIROHA :
- case RF_AL2230S:
- bResult = RFbAL2230SelectChannel(dwIoBase, byChannel);
- break;
- //{{ RobertYu: 20050104
- case RF_AIROHA7230 :
- bResult = s_bAL7230SelectChannel(dwIoBase, byChannel);
- break;
- //}} RobertYu
- case RF_NOTHING :
- bResult = true;
- break;
- default:
- bResult = false;
- break;
- }
- return bResult;
+ bool bResult = true;
+ switch (byRFType) {
+ case RF_AIROHA:
+ case RF_AL2230S:
+ bResult = RFbAL2230SelectChannel(dwIoBase, byChannel);
+ break;
+ //{{ RobertYu: 20050104
+ case RF_AIROHA7230:
+ bResult = s_bAL7230SelectChannel(dwIoBase, byChannel);
+ break;
+ //}} RobertYu
+ case RF_NOTHING:
+ bResult = true;
+ break;
+ default:
+ bResult = false;
+ break;
+ }
+ return bResult;
}
/*
@@ -875,76 +853,73 @@ bool bResult = true;
* Return Value: None.
*
*/
-bool RFvWriteWakeProgSyn (unsigned long dwIoBase, unsigned char byRFType, unsigned int uChannel)
+bool RFvWriteWakeProgSyn(unsigned long dwIoBase, unsigned char byRFType, unsigned int uChannel)
{
- int ii;
- unsigned char byInitCount = 0;
- unsigned char bySleepCount = 0;
-
- VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, 0);
- switch (byRFType) {
- case RF_AIROHA:
- case RF_AL2230S:
-
- if (uChannel > CB_MAX_CHANNEL_24G)
- return false;
-
- byInitCount = CB_AL2230_INIT_SEQ + 2; // Init Reg + Channel Reg (2)
- bySleepCount = 0;
- if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
- return false;
- }
-
- for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230InitTable[ii]);
- }
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable0[uChannel-1]);
- ii ++;
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable1[uChannel-1]);
- break;
-
- //{{ RobertYu: 20050104
- // Need to check, PLLON need to be low for channel setting
- case RF_AIROHA7230:
- byInitCount = CB_AL7230_INIT_SEQ + 3; // Init Reg + Channel Reg (3)
- bySleepCount = 0;
- if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
- return false;
- }
-
- if (uChannel <= CB_MAX_CHANNEL_24G)
- {
- for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTable[ii]);
- }
- }
- else
- {
- for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++ ) {
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTableAMode[ii]);
- }
- }
-
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable0[uChannel-1]);
- ii ++;
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable1[uChannel-1]);
- ii ++;
- MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable2[uChannel-1]);
- break;
- //}} RobertYu
-
- case RF_NOTHING :
- return true;
- break;
-
- default:
- return false;
- break;
- }
-
- MACvSetMISCFifo(dwIoBase, MISCFIFO_SYNINFO_IDX, (unsigned long )MAKEWORD(bySleepCount, byInitCount));
-
- return true;
+ int ii;
+ unsigned char byInitCount = 0;
+ unsigned char bySleepCount = 0;
+
+ VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, 0);
+ switch (byRFType) {
+ case RF_AIROHA:
+ case RF_AL2230S:
+
+ if (uChannel > CB_MAX_CHANNEL_24G)
+ return false;
+
+ byInitCount = CB_AL2230_INIT_SEQ + 2; // Init Reg + Channel Reg (2)
+ bySleepCount = 0;
+ if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
+ return false;
+ }
+
+ for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++) {
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230InitTable[ii]);
+ }
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable0[uChannel-1]);
+ ii++;
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL2230ChannelTable1[uChannel-1]);
+ break;
+
+ //{{ RobertYu: 20050104
+ // Need to check, PLLON need to be low for channel setting
+ case RF_AIROHA7230:
+ byInitCount = CB_AL7230_INIT_SEQ + 3; // Init Reg + Channel Reg (3)
+ bySleepCount = 0;
+ if (byInitCount > (MISCFIFO_SYNDATASIZE - bySleepCount)) {
+ return false;
+ }
+
+ if (uChannel <= CB_MAX_CHANNEL_24G) {
+ for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++) {
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTable[ii]);
+ }
+ } else {
+ for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++) {
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230InitTableAMode[ii]);
+ }
+ }
+
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable0[uChannel-1]);
+ ii++;
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable1[uChannel-1]);
+ ii++;
+ MACvSetMISCFifo(dwIoBase, (unsigned short)(MISCFIFO_SYNDATA_IDX + ii), dwAL7230ChannelTable2[uChannel-1]);
+ break;
+ //}} RobertYu
+
+ case RF_NOTHING:
+ return true;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ MACvSetMISCFifo(dwIoBase, MISCFIFO_SYNINFO_IDX, (unsigned long)MAKEWORD(bySleepCount, byInitCount));
+
+ return true;
}
/*
@@ -960,87 +935,81 @@ bool RFvWriteWakeProgSyn (unsigned long dwIoBase, unsigned char byRFType, unsign
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbSetPower (
- PSDevice pDevice,
- unsigned int uRATE,
- unsigned int uCH
- )
+bool RFbSetPower(
+ PSDevice pDevice,
+ unsigned int uRATE,
+ unsigned int uCH
+)
{
-bool bResult = true;
-unsigned char byPwr = 0;
-unsigned char byDec = 0;
-unsigned char byPwrdBm = 0;
-
- if (pDevice->dwDiagRefCount != 0) {
- return true;
- }
- if ((uCH < 1) || (uCH > CB_MAX_CHANNEL)) {
- return false;
- }
-
- switch (uRATE) {
- case RATE_1M:
- case RATE_2M:
- case RATE_5M:
- case RATE_11M:
- byPwr = pDevice->abyCCKPwrTbl[uCH];
- byPwrdBm = pDevice->abyCCKDefaultPwr[uCH];
+ bool bResult = true;
+ unsigned char byPwr = 0;
+ unsigned char byDec = 0;
+ unsigned char byPwrdBm = 0;
+
+ if (pDevice->dwDiagRefCount != 0) {
+ return true;
+ }
+ if ((uCH < 1) || (uCH > CB_MAX_CHANNEL)) {
+ return false;
+ }
+
+ switch (uRATE) {
+ case RATE_1M:
+ case RATE_2M:
+ case RATE_5M:
+ case RATE_11M:
+ byPwr = pDevice->abyCCKPwrTbl[uCH];
+ byPwrdBm = pDevice->abyCCKDefaultPwr[uCH];
//PLICE_DEBUG->
- //byPwr+=5;
+ //byPwr+=5;
//PLICE_DEBUG <-
-
-//printk("Rate <11:byPwr is %d\n",byPwr);
break;
- case RATE_6M:
- case RATE_9M:
- case RATE_18M:
- byPwr = pDevice->abyOFDMPwrTbl[uCH];
- if (pDevice->byRFType == RF_UW2452) {
- byDec = byPwr + 14;
- } else {
- byDec = byPwr + 10;
- }
- if (byDec >= pDevice->byMaxPwrLevel) {
- byDec = pDevice->byMaxPwrLevel-1;
- }
- if (pDevice->byRFType == RF_UW2452) {
- byPwrdBm = byDec - byPwr;
- byPwrdBm /= 3;
- } else {
- byPwrdBm = byDec - byPwr;
- byPwrdBm >>= 1;
- }
- byPwrdBm += pDevice->abyOFDMDefaultPwr[uCH];
- byPwr = byDec;
+ case RATE_6M:
+ case RATE_9M:
+ case RATE_18M:
+ byPwr = pDevice->abyOFDMPwrTbl[uCH];
+ if (pDevice->byRFType == RF_UW2452) {
+ byDec = byPwr + 14;
+ } else {
+ byDec = byPwr + 10;
+ }
+ if (byDec >= pDevice->byMaxPwrLevel) {
+ byDec = pDevice->byMaxPwrLevel-1;
+ }
+ if (pDevice->byRFType == RF_UW2452) {
+ byPwrdBm = byDec - byPwr;
+ byPwrdBm /= 3;
+ } else {
+ byPwrdBm = byDec - byPwr;
+ byPwrdBm >>= 1;
+ }
+ byPwrdBm += pDevice->abyOFDMDefaultPwr[uCH];
+ byPwr = byDec;
//PLICE_DEBUG->
- //byPwr+=5;
+ //byPwr+=5;
//PLICE_DEBUG<-
-
-//printk("Rate <24:byPwr is %d\n",byPwr);
break;
- case RATE_24M:
- case RATE_36M:
- case RATE_48M:
- case RATE_54M:
- byPwr = pDevice->abyOFDMPwrTbl[uCH];
- byPwrdBm = pDevice->abyOFDMDefaultPwr[uCH];
+ case RATE_24M:
+ case RATE_36M:
+ case RATE_48M:
+ case RATE_54M:
+ byPwr = pDevice->abyOFDMPwrTbl[uCH];
+ byPwrdBm = pDevice->abyOFDMDefaultPwr[uCH];
//PLICE_DEBUG->
- //byPwr+=5;
+ //byPwr+=5;
//PLICE_DEBUG<-
-//printk("Rate < 54:byPwr is %d\n",byPwr);
break;
- }
-
-// if (pDevice->byLocalID <= REV_ID_VT3253_B1) {
- if (pDevice->byCurPwr == byPwr) {
- return true;
- }
- bResult = RFbRawSetPower(pDevice, byPwr, uRATE);
-// }
- if (bResult == true) {
- pDevice->byCurPwr = byPwr;
- }
- return bResult;
+ }
+
+ if (pDevice->byCurPwr == byPwr) {
+ return true;
+ }
+
+ bResult = RFbRawSetPower(pDevice, byPwr, uRATE);
+ if (bResult == true) {
+ pDevice->byCurPwr = byPwr;
+ }
+ return bResult;
}
/*
@@ -1057,55 +1026,52 @@ unsigned char byPwrdBm = 0;
*
*/
-bool RFbRawSetPower (
- PSDevice pDevice,
- unsigned char byPwr,
- unsigned int uRATE
- )
+bool RFbRawSetPower(
+ PSDevice pDevice,
+ unsigned char byPwr,
+ unsigned int uRATE
+)
{
-bool bResult = true;
-unsigned long dwMax7230Pwr = 0;
-
- if (byPwr >= pDevice->byMaxPwrLevel) {
- return (false);
- }
- switch (pDevice->byRFType) {
-
- case RF_AIROHA :
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
- if (uRATE <= RATE_11M) {
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- } else {
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- }
- break;
-
-
- case RF_AL2230S :
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
- if (uRATE <= RATE_11M) {
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- }else {
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
- }
-
- break;
-
- case RF_AIROHA7230:
- // 0x080F1B00 for 3 wire control TxGain(D10) and 0x31 as TX Gain value
- dwMax7230Pwr = 0x080C0B00 | ( (byPwr) << 12 ) |
- (BY_AL7230_REG_LEN << 3 ) | IFREGCTL_REGW;
-
- bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwMax7230Pwr);
- break;
-
-
- default :
- break;
- }
- return bResult;
+ bool bResult = true;
+ unsigned long dwMax7230Pwr = 0;
+
+ if (byPwr >= pDevice->byMaxPwrLevel) {
+ return false;
+ }
+ switch (pDevice->byRFType) {
+ case RF_AIROHA:
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
+ if (uRATE <= RATE_11M) {
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ } else {
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ }
+ break;
+
+ case RF_AL2230S:
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]);
+ if (uRATE <= RATE_11M) {
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ } else {
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW);
+ }
+
+ break;
+
+ case RF_AIROHA7230:
+ // 0x080F1B00 for 3 wire control TxGain(D10) and 0x31 as TX Gain value
+ dwMax7230Pwr = 0x080C0B00 | ((byPwr) << 12) |
+ (BY_AL7230_REG_LEN << 3) | IFREGCTL_REGW;
+
+ bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwMax7230Pwr);
+ break;
+
+ default:
+ break;
+ }
+ return bResult;
}
/*+
@@ -1122,74 +1088,68 @@ unsigned long dwMax7230Pwr = 0;
*
* Return Value: none
*
--*/
+ -*/
void
-RFvRSSITodBm (
- PSDevice pDevice,
- unsigned char byCurrRSSI,
- long * pldBm
- )
+RFvRSSITodBm(
+ PSDevice pDevice,
+ unsigned char byCurrRSSI,
+ long *pldBm
+ )
{
- unsigned char byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03);
- long b = (byCurrRSSI & 0x3F);
- long a = 0;
- unsigned char abyAIROHARF[4] = {0, 18, 0, 40};
-
- switch (pDevice->byRFType) {
- case RF_AIROHA:
- case RF_AL2230S:
- case RF_AIROHA7230: //RobertYu: 20040104
- a = abyAIROHARF[byIdx];
- break;
- default:
- break;
- }
-
- *pldBm = -1 * (a + b * 2);
+ unsigned char byIdx = (((byCurrRSSI & 0xC0) >> 6) & 0x03);
+ long b = (byCurrRSSI & 0x3F);
+ long a = 0;
+ unsigned char abyAIROHARF[4] = {0, 18, 0, 40};
+
+ switch (pDevice->byRFType) {
+ case RF_AIROHA:
+ case RF_AL2230S:
+ case RF_AIROHA7230: //RobertYu: 20040104
+ a = abyAIROHARF[byIdx];
+ break;
+ default:
+ break;
+ }
+
+ *pldBm = -1 * (a + b * 2);
}
////////////////////////////////////////////////////////////////////////////////
//{{ RobertYu: 20050104
-
// Post processing for the 11b/g and 11a.
// for save time on changing Reg2,3,5,7,10,12,15
-bool RFbAL7230SelectChannelPostProcess (unsigned long dwIoBase, unsigned char byOldChannel, unsigned char byNewChannel)
+bool RFbAL7230SelectChannelPostProcess(unsigned long dwIoBase, unsigned char byOldChannel, unsigned char byNewChannel)
{
- bool bResult;
-
- bResult = true;
-
- // if change between 11 b/g and 11a need to update the following register
- // Channel Index 1~14
-
- if( (byOldChannel <= CB_MAX_CHANNEL_24G) && (byNewChannel > CB_MAX_CHANNEL_24G) )
- {
- // Change from 2.4G to 5G
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15
- }
- else if( (byOldChannel > CB_MAX_CHANNEL_24G) && (byNewChannel <= CB_MAX_CHANNEL_24G) )
- {
- // change from 5G to 2.4G
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[2]); //Reg2
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[3]); //Reg3
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[5]); //Reg5
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[7]); //Reg7
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[10]);//Reg10
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[12]);//Reg12
- bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[15]);//Reg15
- }
-
- return bResult;
+ bool bResult;
+
+ bResult = true;
+
+ // if change between 11 b/g and 11a need to update the following register
+ // Channel Index 1~14
+
+ if ((byOldChannel <= CB_MAX_CHANNEL_24G) && (byNewChannel > CB_MAX_CHANNEL_24G)) {
+ // Change from 2.4G to 5G
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15
+ } else if ((byOldChannel > CB_MAX_CHANNEL_24G) && (byNewChannel <= CB_MAX_CHANNEL_24G)) {
+ // change from 5G to 2.4G
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[2]); //Reg2
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[3]); //Reg3
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[5]); //Reg5
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[7]); //Reg7
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[10]);//Reg10
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[12]);//Reg12
+ bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[15]);//Reg15
+ }
+
+ return bResult;
}
-
//}} RobertYu
////////////////////////////////////////////////////////////////////////////////
-
diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h
index 1da0fdeb2e1c..ef3c6de09fec 100644
--- a/drivers/staging/vt6655/rf.h
+++ b/drivers/staging/vt6655/rf.h
@@ -68,7 +68,6 @@
#define CB_MAXIM2829_CHANNEL_5G_HIGH 41 //Index41: channel = 100, Tf = 5500MHz, set the (A3:A0=0101) D6=1
#define CB_UW2452_CHANNEL_5G_HIGH 41 //[20041210] Index41: channel = 100, Tf = 5500MHz, change VCO2->VCO3
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -77,29 +76,26 @@
bool IFRFbWriteEmbedded(unsigned long dwIoBase, unsigned long dwData);
bool RFbSelectChannel(unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel);
-bool RFbInit (
- PSDevice pDevice
- );
+bool RFbInit(
+ PSDevice pDevice
+);
bool RFvWriteWakeProgSyn(unsigned long dwIoBase, unsigned char byRFType, unsigned int uChannel);
bool RFbSetPower(PSDevice pDevice, unsigned int uRATE, unsigned int uCH);
bool RFbRawSetPower(
- PSDevice pDevice,
- unsigned char byPwr,
- unsigned int uRATE
- );
+ PSDevice pDevice,
+ unsigned char byPwr,
+ unsigned int uRATE
+);
void
RFvRSSITodBm(
- PSDevice pDevice,
- unsigned char byCurrRSSI,
- long *pldBm
- );
+ PSDevice pDevice,
+ unsigned char byCurrRSSI,
+ long *pldBm
+);
//{{ RobertYu: 20050104
bool RFbAL7230SelectChannelPostProcess(unsigned long dwIoBase, unsigned char byOldChannel, unsigned char byNewChannel);
//}} RobertYu
#endif // __RF_H__
-
-
-
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index d66854f5b304..3a2661e2b27c 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -69,11 +69,10 @@
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
#define PLICE_DEBUG
-
/*--------------------- Static Functions --------------------------*/
/*--------------------- Static Definitions -------------------------*/
@@ -81,19 +80,18 @@ static int msglevel =MSG_LEVEL_INFO;
// packet size >= 256 -> direct send
const unsigned short wTimeStampOff[2][MAX_RATE] = {
- {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, // Long Preamble
- {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, // Short Preamble
- };
+ {384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, // Long Preamble
+ {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, // Short Preamble
+};
const unsigned short wFB_Opt0[2][5] = {
- {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, // fallback_rate0
- {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, // fallback_rate1
- };
+ {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, // fallback_rate0
+ {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, // fallback_rate1
+};
const unsigned short wFB_Opt1[2][5] = {
- {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, // fallback_rate0
- {RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, // fallback_rate1
- };
-
+ {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, // fallback_rate0
+ {RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, // fallback_rate1
+};
#define RTSDUR_BB 0
#define RTSDUR_BA 1
@@ -112,1009 +110,946 @@ const unsigned short wFB_Opt1[2][5] = {
/*--------------------- Static Functions --------------------------*/
-
-
static
void
s_vFillTxKey(
- PSDevice pDevice,
- unsigned char *pbyBuf,
- unsigned char *pbyIVHead,
- PSKeyItem pTransmitKey,
- unsigned char *pbyHdrBuf,
- unsigned short wPayloadLen,
- unsigned char *pMICHDR
- );
-
-
+ PSDevice pDevice,
+ unsigned char *pbyBuf,
+ unsigned char *pbyIVHead,
+ PSKeyItem pTransmitKey,
+ unsigned char *pbyHdrBuf,
+ unsigned short wPayloadLen,
+ unsigned char *pMICHDR
+);
static
void
s_vFillRTSHead(
- PSDevice pDevice,
- unsigned char byPktType,
- void * pvRTS,
- unsigned int cbFrameLength,
- bool bNeedAck,
- bool bDisCRC,
- PSEthernetHeader psEthHeader,
- unsigned short wCurrentRate,
- unsigned char byFBOption
- );
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pvRTS,
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
+ PSEthernetHeader psEthHeader,
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
+);
static
void
s_vGenerateTxParameter(
- PSDevice pDevice,
- unsigned char byPktType,
- void * pTxBufHead,
- void * pvRrvTime,
- void * pvRTS,
- void * pvCTS,
- unsigned int cbFrameSize,
- bool bNeedACK,
- unsigned int uDMAIdx,
- PSEthernetHeader psEthHeader,
- unsigned short wCurrentRate
- );
-
-
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pTxBufHead,
+ void *pvRrvTime,
+ void *pvRTS,
+ void *pvCTS,
+ unsigned int cbFrameSize,
+ bool bNeedACK,
+ unsigned int uDMAIdx,
+ PSEthernetHeader psEthHeader,
+ unsigned short wCurrentRate
+);
static void s_vFillFragParameter(
- PSDevice pDevice,
- unsigned char *pbyBuffer,
- unsigned int uTxType,
- void * pvtdCurr,
- unsigned short wFragType,
- unsigned int cbReqCount
- );
-
+ PSDevice pDevice,
+ unsigned char *pbyBuffer,
+ unsigned int uTxType,
+ void *pvtdCurr,
+ unsigned short wFragType,
+ unsigned int cbReqCount
+);
static unsigned int
s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
- unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
- PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum);
-
+ unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum);
static
unsigned int
-s_uFillDataHead (
- PSDevice pDevice,
- unsigned char byPktType,
- void * pTxDataHead,
- unsigned int cbFrameLength,
- unsigned int uDMAIdx,
- bool bNeedAck,
- unsigned int uFragIdx,
- unsigned int cbLastFragmentSize,
- unsigned int uMACfragNum,
- unsigned char byFBOption,
- unsigned short wCurrentRate
- );
-
+s_uFillDataHead(
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pTxDataHead,
+ unsigned int cbFrameLength,
+ unsigned int uDMAIdx,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption,
+ unsigned short wCurrentRate
+);
/*--------------------- Export Variables --------------------------*/
-
-
static
void
-s_vFillTxKey (
- PSDevice pDevice,
- unsigned char *pbyBuf,
- unsigned char *pbyIVHead,
- PSKeyItem pTransmitKey,
- unsigned char *pbyHdrBuf,
- unsigned short wPayloadLen,
- unsigned char *pMICHDR
- )
+s_vFillTxKey(
+ PSDevice pDevice,
+ unsigned char *pbyBuf,
+ unsigned char *pbyIVHead,
+ PSKeyItem pTransmitKey,
+ unsigned char *pbyHdrBuf,
+ unsigned short wPayloadLen,
+ unsigned char *pMICHDR
+)
{
- unsigned long *pdwIV = (unsigned long *) pbyIVHead;
- unsigned long *pdwExtIV = (unsigned long *) ((unsigned char *)pbyIVHead+4);
- unsigned short wValue;
- PS802_11Header pMACHeader = (PS802_11Header)pbyHdrBuf;
- unsigned long dwRevIVCounter;
- unsigned char byKeyIndex = 0;
-
-
-
- //Fill TXKEY
- if (pTransmitKey == NULL)
- return;
-
- dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
- *pdwIV = pDevice->dwIVCounter;
- byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
-
- if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
- if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){
- memcpy(pDevice->abyPRNG, (unsigned char *)&(dwRevIVCounter), 3);
- memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- } else {
- memcpy(pbyBuf, (unsigned char *)&(dwRevIVCounter), 3);
- memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
- memcpy(pbyBuf+8, (unsigned char *)&(dwRevIVCounter), 3);
- memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
- }
- memcpy(pDevice->abyPRNG, pbyBuf, 16);
- }
- // Append IV after Mac Header
- *pdwIV &= WEP_IV_MASK;//00000000 11111111 11111111 11111111
- *pdwIV |= (unsigned long)byKeyIndex << 30;
- *pdwIV = cpu_to_le32(*pdwIV);
- pDevice->dwIVCounter++;
- if (pDevice->dwIVCounter > WEP_IV_MASK) {
- pDevice->dwIVCounter = 0;
- }
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- pTransmitKey->wTSC15_0++;
- if (pTransmitKey->wTSC15_0 == 0) {
- pTransmitKey->dwTSC47_16++;
- }
- TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
- pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
- memcpy(pbyBuf, pDevice->abyPRNG, 16);
- // Make IV
- memcpy(pdwIV, pDevice->abyPRNG, 3);
-
- *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- // Append IV&ExtIV after Mac Header
- *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %lx\n", *pdwExtIV);
-
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
- pTransmitKey->wTSC15_0++;
- if (pTransmitKey->wTSC15_0 == 0) {
- pTransmitKey->dwTSC47_16++;
- }
- memcpy(pbyBuf, pTransmitKey->abyKey, 16);
-
- // Make IV
- *pdwIV = 0;
- *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- *pdwIV |= cpu_to_le16((unsigned short)(pTransmitKey->wTSC15_0));
- //Append IV&ExtIV after Mac Header
- *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
-
- //Fill MICHDR0
- *pMICHDR = 0x59;
- *((unsigned char *)(pMICHDR+1)) = 0; // TxPriority
- memcpy(pMICHDR+2, &(pMACHeader->abyAddr2[0]), 6);
- *((unsigned char *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((unsigned char *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((unsigned char *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((unsigned char *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((unsigned char *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
- *((unsigned char *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
- *((unsigned char *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
- *((unsigned char *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
-
- //Fill MICHDR1
- *((unsigned char *)(pMICHDR+16)) = 0; // HLEN[15:8]
- if (pDevice->bLongHeader) {
- *((unsigned char *)(pMICHDR+17)) = 28; // HLEN[7:0]
- } else {
- *((unsigned char *)(pMICHDR+17)) = 22; // HLEN[7:0]
- }
- wValue = cpu_to_le16(pMACHeader->wFrameCtl & 0xC78F);
- memcpy(pMICHDR+18, (unsigned char *)&wValue, 2); // MSKFRACTL
- memcpy(pMICHDR+20, &(pMACHeader->abyAddr1[0]), 6);
- memcpy(pMICHDR+26, &(pMACHeader->abyAddr2[0]), 6);
-
- //Fill MICHDR2
- memcpy(pMICHDR+32, &(pMACHeader->abyAddr3[0]), 6);
- wValue = pMACHeader->wSeqCtl;
- wValue &= 0x000F;
- wValue = cpu_to_le16(wValue);
- memcpy(pMICHDR+38, (unsigned char *)&wValue, 2); // MSKSEQCTL
- if (pDevice->bLongHeader) {
- memcpy(pMICHDR+40, &(pMACHeader->abyAddr4[0]), 6);
- }
- }
+ unsigned long *pdwIV = (unsigned long *)pbyIVHead;
+ unsigned long *pdwExtIV = (unsigned long *)((unsigned char *)pbyIVHead+4);
+ unsigned short wValue;
+ PS802_11Header pMACHeader = (PS802_11Header)pbyHdrBuf;
+ unsigned long dwRevIVCounter;
+ unsigned char byKeyIndex = 0;
+
+ //Fill TXKEY
+ if (pTransmitKey == NULL)
+ return;
+
+ dwRevIVCounter = cpu_to_le32(pDevice->dwIVCounter);
+ *pdwIV = pDevice->dwIVCounter;
+ byKeyIndex = pTransmitKey->dwKeyIndex & 0xf;
+
+ if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
+ if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
+ memcpy(pDevice->abyPRNG, (unsigned char *)&(dwRevIVCounter), 3);
+ memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
+ } else {
+ memcpy(pbyBuf, (unsigned char *)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
+ if (pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
+ memcpy(pbyBuf+8, (unsigned char *)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
+ }
+ memcpy(pDevice->abyPRNG, pbyBuf, 16);
+ }
+ // Append IV after Mac Header
+ *pdwIV &= WEP_IV_MASK;//00000000 11111111 11111111 11111111
+ *pdwIV |= (unsigned long)byKeyIndex << 30;
+ *pdwIV = cpu_to_le32(*pdwIV);
+ pDevice->dwIVCounter++;
+ if (pDevice->dwIVCounter > WEP_IV_MASK) {
+ pDevice->dwIVCounter = 0;
+ }
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
+ pTransmitKey->wTSC15_0++;
+ if (pTransmitKey->wTSC15_0 == 0) {
+ pTransmitKey->dwTSC47_16++;
+ }
+ TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
+ pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
+ memcpy(pbyBuf, pDevice->abyPRNG, 16);
+ // Make IV
+ memcpy(pdwIV, pDevice->abyPRNG, 3);
+
+ *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ // Append IV&ExtIV after Mac Header
+ *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vFillTxKey()---- pdwExtIV: %lx\n", *pdwExtIV);
+
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
+ pTransmitKey->wTSC15_0++;
+ if (pTransmitKey->wTSC15_0 == 0) {
+ pTransmitKey->dwTSC47_16++;
+ }
+ memcpy(pbyBuf, pTransmitKey->abyKey, 16);
+
+ // Make IV
+ *pdwIV = 0;
+ *(pbyIVHead+3) = (unsigned char)(((byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ *pdwIV |= cpu_to_le16((unsigned short)(pTransmitKey->wTSC15_0));
+ //Append IV&ExtIV after Mac Header
+ *pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
+
+ //Fill MICHDR0
+ *pMICHDR = 0x59;
+ *((unsigned char *)(pMICHDR+1)) = 0; // TxPriority
+ memcpy(pMICHDR+2, &(pMACHeader->abyAddr2[0]), 6);
+ *((unsigned char *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((unsigned char *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
+ *((unsigned char *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
+ *((unsigned char *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
+ *((unsigned char *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
+
+ //Fill MICHDR1
+ *((unsigned char *)(pMICHDR+16)) = 0; // HLEN[15:8]
+ if (pDevice->bLongHeader) {
+ *((unsigned char *)(pMICHDR+17)) = 28; // HLEN[7:0]
+ } else {
+ *((unsigned char *)(pMICHDR+17)) = 22; // HLEN[7:0]
+ }
+ wValue = cpu_to_le16(pMACHeader->wFrameCtl & 0xC78F);
+ memcpy(pMICHDR+18, (unsigned char *)&wValue, 2); // MSKFRACTL
+ memcpy(pMICHDR+20, &(pMACHeader->abyAddr1[0]), 6);
+ memcpy(pMICHDR+26, &(pMACHeader->abyAddr2[0]), 6);
+
+ //Fill MICHDR2
+ memcpy(pMICHDR+32, &(pMACHeader->abyAddr3[0]), 6);
+ wValue = pMACHeader->wSeqCtl;
+ wValue &= 0x000F;
+ wValue = cpu_to_le16(wValue);
+ memcpy(pMICHDR+38, (unsigned char *)&wValue, 2); // MSKSEQCTL
+ if (pDevice->bLongHeader) {
+ memcpy(pMICHDR+40, &(pMACHeader->abyAddr4[0]), 6);
+ }
+ }
}
-
static
void
-s_vSWencryption (
- PSDevice pDevice,
- PSKeyItem pTransmitKey,
- unsigned char *pbyPayloadHead,
- unsigned short wPayloadSize
- )
+s_vSWencryption(
+ PSDevice pDevice,
+ PSKeyItem pTransmitKey,
+ unsigned char *pbyPayloadHead,
+ unsigned short wPayloadSize
+)
{
- unsigned int cbICVlen = 4;
- unsigned long dwICV = 0xFFFFFFFFL;
- unsigned long *pdwICV;
-
- if (pTransmitKey == NULL)
- return;
-
- if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
- //=======================================================================
- // Append ICV after payload
- dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
- // finally, we must invert dwCRC to get the correct answer
- *pdwICV = cpu_to_le32(~dwICV);
- // RC4 encryption
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength + 3);
- rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen);
- //=======================================================================
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- //=======================================================================
- //Append ICV after payload
- dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
- // finally, we must invert dwCRC to get the correct answer
- *pdwICV = cpu_to_le32(~dwICV);
- // RC4 encryption
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
- rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen);
- //=======================================================================
- }
+ unsigned int cbICVlen = 4;
+ unsigned long dwICV = 0xFFFFFFFFL;
+ unsigned long *pdwICV;
+
+ if (pTransmitKey == NULL)
+ return;
+
+ if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
+ //=======================================================================
+ // Append ICV after payload
+ dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
+ pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
+ // finally, we must invert dwCRC to get the correct answer
+ *pdwICV = cpu_to_le32(~dwICV);
+ // RC4 encryption
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength + 3);
+ rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen);
+ //=======================================================================
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
+ //=======================================================================
+ //Append ICV after payload
+ dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
+ pdwICV = (unsigned long *)(pbyPayloadHead + wPayloadSize);
+ // finally, we must invert dwCRC to get the correct answer
+ *pdwICV = cpu_to_le32(~dwICV);
+ // RC4 encryption
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
+ rc4_encrypt(&pDevice->SBox, pbyPayloadHead, pbyPayloadHead, wPayloadSize+cbICVlen);
+ //=======================================================================
+ }
}
-
-
-
/*byPktType : PK_TYPE_11A 0
- PK_TYPE_11B 1
- PK_TYPE_11GB 2
- PK_TYPE_11GA 3
+ PK_TYPE_11B 1
+ PK_TYPE_11GB 2
+ PK_TYPE_11GA 3
*/
static
unsigned int
-s_uGetTxRsvTime (
- PSDevice pDevice,
- unsigned char byPktType,
- unsigned int cbFrameLength,
- unsigned short wRate,
- bool bNeedAck
- )
+s_uGetTxRsvTime(
+ PSDevice pDevice,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wRate,
+ bool bNeedAck
+)
{
- unsigned int uDataTime, uAckTime;
-
- uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wRate);
-#ifdef PLICE_DEBUG
- //printk("s_uGetTxRsvTime is %d\n",uDataTime);
-#endif
- if (byPktType == PK_TYPE_11B) {//llb,CCK mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopCCKBasicRate);
- } else {//11g 2.4G OFDM mode & 11a 5G OFDM mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopOFDMBasicRate);
- }
-
- if (bNeedAck) {
- return (uDataTime + pDevice->uSIFS + uAckTime);
- }
- else {
- return uDataTime;
- }
+ unsigned int uDataTime, uAckTime;
+
+ uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wRate);
+ if (byPktType == PK_TYPE_11B) {//llb,CCK mode
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopCCKBasicRate);
+ } else {//11g 2.4G OFDM mode & 11a 5G OFDM mode
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (unsigned short)pDevice->byTopOFDMBasicRate);
+ }
+
+ if (bNeedAck) {
+ return uDataTime + pDevice->uSIFS + uAckTime;
+ } else {
+ return uDataTime;
+ }
}
//byFreqType: 0=>5GHZ 1=>2.4GHZ
static
unsigned int
-s_uGetRTSCTSRsvTime (
- PSDevice pDevice,
- unsigned char byRTSRsvType,
- unsigned char byPktType,
- unsigned int cbFrameLength,
- unsigned short wCurrentRate
- )
+s_uGetRTSCTSRsvTime(
+ PSDevice pDevice,
+ unsigned char byRTSRsvType,
+ unsigned char byPktType,
+ unsigned int cbFrameLength,
+ unsigned short wCurrentRate
+)
{
- unsigned int uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime;
-
- uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
-
-
- uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wCurrentRate);
- if (byRTSRsvType == 0) { //RTSTxRrvTime_bb
- uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopCCKBasicRate);
- uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- }
- else if (byRTSRsvType == 1){ //RTSTxRrvTime_ba, only in 2.4GHZ
- uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopCCKBasicRate);
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- }
- else if (byRTSRsvType == 2) { //RTSTxRrvTime_aa
- uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopOFDMBasicRate);
- uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- }
- else if (byRTSRsvType == 3) { //CTSTxRrvTime_ba, only in 2.4GHZ
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- uRrvTime = uCTSTime + uAckTime + uDataTime + 2*pDevice->uSIFS;
- return uRrvTime;
- }
-
- //RTSRrvTime
- uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS;
- return uRrvTime;
+ unsigned int uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime;
+
+ uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
+
+ uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wCurrentRate);
+ if (byRTSRsvType == 0) { //RTSTxRrvTime_bb
+ uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopCCKBasicRate);
+ uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ } else if (byRTSRsvType == 1) { //RTSTxRrvTime_ba, only in 2.4GHZ
+ uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopCCKBasicRate);
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ } else if (byRTSRsvType == 2) { //RTSTxRrvTime_aa
+ uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopOFDMBasicRate);
+ uCTSTime = uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ } else if (byRTSRsvType == 3) { //CTSTxRrvTime_ba, only in 2.4GHZ
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ uRrvTime = uCTSTime + uAckTime + uDataTime + 2*pDevice->uSIFS;
+ return uRrvTime;
+ }
+
+ //RTSRrvTime
+ uRrvTime = uRTSTime + uCTSTime + uAckTime + uDataTime + 3*pDevice->uSIFS;
+ return uRrvTime;
}
//byFreqType 0: 5GHz, 1:2.4Ghz
static
unsigned int
-s_uGetDataDuration (
- PSDevice pDevice,
- unsigned char byDurType,
- unsigned int cbFrameLength,
- unsigned char byPktType,
- unsigned short wRate,
- bool bNeedAck,
- unsigned int uFragIdx,
- unsigned int cbLastFragmentSize,
- unsigned int uMACfragNum,
- unsigned char byFBOption
- )
+s_uGetDataDuration(
+ PSDevice pDevice,
+ unsigned char byDurType,
+ unsigned int cbFrameLength,
+ unsigned char byPktType,
+ unsigned short wRate,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption
+)
{
- bool bLastFrag = 0;
- unsigned int uAckTime =0, uNextPktTime = 0;
-
-
-
- if (uFragIdx == (uMACfragNum-1)) {
- bLastFrag = 1;
- }
-
-
- switch (byDurType) {
-
- case DATADUR_B: //DATADUR_B
- if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
- if (bNeedAck) {
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else {//First Frag or Mid Frag
- if (uFragIdx == (uMACfragNum-2)) {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- }
- if (bNeedAck) {
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A: //DATADUR_A
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else {//First Frag or Mid Frag
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- }
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A_F0: //DATADUR_A_F0
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else { //First Frag or Mid Frag
- if (byFBOption == AUTO_FB_0) {
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- } else { // (byFBOption == AUTO_FB_1)
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- }
-
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- case DATADUR_A_F1: //DATADUR_A_F1
- if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime);
- } else {
- return 0;
- }
- }
- else { //First Frag or Mid Frag
- if (byFBOption == AUTO_FB_0) {
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
-
- } else { // (byFBOption == AUTO_FB_1)
- if (wRate < RATE_18M)
- wRate = RATE_18M;
- else if (wRate > RATE_54M)
- wRate = RATE_54M;
-
- if(uFragIdx == (uMACfragNum-2)){
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else {
- uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
- }
- if(bNeedAck){
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- return (pDevice->uSIFS + uAckTime + uNextPktTime);
- } else {
- return (pDevice->uSIFS + uNextPktTime);
- }
- }
- break;
-
- default:
- break;
- }
+ bool bLastFrag = 0;
+ unsigned int uAckTime = 0, uNextPktTime = 0;
+
+ if (uFragIdx == (uMACfragNum-1)) {
+ bLastFrag = 1;
+ }
+
+ switch (byDurType) {
+ case DATADUR_B: //DATADUR_B
+ if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ return pDevice->uSIFS + uAckTime;
+ } else {
+ return 0;
+ }
+ } else {//First Frag or Mid Frag
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ }
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ return pDevice->uSIFS + uAckTime + uNextPktTime;
+ } else {
+ return pDevice->uSIFS + uNextPktTime;
+ }
+ }
+ break;
+
+ case DATADUR_A: //DATADUR_A
+ if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime;
+ } else {
+ return 0;
+ }
+ } else {//First Frag or Mid Frag
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wRate, bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ }
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime + uNextPktTime;
+ } else {
+ return pDevice->uSIFS + uNextPktTime;
+ }
+ }
+ break;
+
+ case DATADUR_A_F0: //DATADUR_A_F0
+ if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime;
+ } else {
+ return 0;
+ }
+ } else { //First Frag or Mid Frag
+ if (byFBOption == AUTO_FB_0) {
+ if (wRate < RATE_18M)
+ wRate = RATE_18M;
+ else if (wRate > RATE_54M)
+ wRate = RATE_54M;
+
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ }
+ } else { // (byFBOption == AUTO_FB_1)
+ if (wRate < RATE_18M)
+ wRate = RATE_18M;
+ else if (wRate > RATE_54M)
+ wRate = RATE_54M;
+
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ }
+ }
+
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime + uNextPktTime;
+ } else {
+ return pDevice->uSIFS + uNextPktTime;
+ }
+ }
+ break;
+
+ case DATADUR_A_F1: //DATADUR_A_F1
+ if (((uMACfragNum == 1)) || (bLastFrag == 1)) {//Non Frag or Last Frag
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime;
+ } else {
+ return 0;
+ }
+ } else { //First Frag or Mid Frag
+ if (byFBOption == AUTO_FB_0) {
+ if (wRate < RATE_18M)
+ wRate = RATE_18M;
+ else if (wRate > RATE_54M)
+ wRate = RATE_54M;
+
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ }
+
+ } else { // (byFBOption == AUTO_FB_1)
+ if (wRate < RATE_18M)
+ wRate = RATE_18M;
+ else if (wRate > RATE_54M)
+ wRate = RATE_54M;
+
+ if (uFragIdx == (uMACfragNum-2)) {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbLastFragmentSize, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ } else {
+ uNextPktTime = s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ }
+ }
+ if (bNeedAck) {
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ return pDevice->uSIFS + uAckTime + uNextPktTime;
+ } else {
+ return pDevice->uSIFS + uNextPktTime;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
ASSERT(false);
return 0;
}
-
//byFreqType: 0=>5GHZ 1=>2.4GHZ
static
unsigned int
-s_uGetRTSCTSDuration (
- PSDevice pDevice,
- unsigned char byDurType,
- unsigned int cbFrameLength,
- unsigned char byPktType,
- unsigned short wRate,
- bool bNeedAck,
- unsigned char byFBOption
- )
+s_uGetRTSCTSDuration(
+ PSDevice pDevice,
+ unsigned char byDurType,
+ unsigned int cbFrameLength,
+ unsigned char byPktType,
+ unsigned short wRate,
+ bool bNeedAck,
+ unsigned char byFBOption
+)
{
- unsigned int uCTSTime = 0, uDurTime = 0;
-
-
- switch (byDurType) {
-
- case RTSDUR_BB: //RTSDuration_bb
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- break;
-
- case RTSDUR_BA: //RTSDuration_ba
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- break;
-
- case RTSDUR_AA: //RTSDuration_aa
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- break;
-
- case CTSDUR_BA: //CTSDuration_ba
- uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
- break;
-
- case RTSDUR_BA_F0: //RTSDuration_ba_f0
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- case RTSDUR_AA_F0: //RTSDuration_aa_f0
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- case RTSDUR_BA_F1: //RTSDuration_ba_f1
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- case RTSDUR_AA_F1: //RTSDuration_aa_f1
- uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- case CTSDUR_BA_F0: //CTSDuration_ba_f0
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- case CTSDUR_BA_F1: //CTSDuration_ba_f1
- if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
- } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <=RATE_54M)) {
- uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
- }
- break;
-
- default:
- break;
- }
-
- return uDurTime;
-
+ unsigned int uCTSTime = 0, uDurTime = 0;
+
+ switch (byDurType) {
+ case RTSDUR_BB: //RTSDuration_bb
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ break;
+
+ case RTSDUR_BA: //RTSDuration_ba
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ break;
+
+ case RTSDUR_AA: //RTSDuration_aa
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ break;
+
+ case CTSDUR_BA: //CTSDuration_ba
+ uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wRate, bNeedAck);
+ break;
+
+ case RTSDUR_BA_F0: //RTSDuration_ba_f0
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2 * pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ case RTSDUR_AA_F0: //RTSDuration_aa_f0
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ case RTSDUR_BA_F1: //RTSDuration_ba_f1
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopCCKBasicRate);
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ case RTSDUR_AA_F1: //RTSDuration_aa_f1
+ uCTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, pDevice->byTopOFDMBasicRate);
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = uCTSTime + 2*pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ case CTSDUR_BA_F0: //CTSDuration_ba_f0
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE0][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ case CTSDUR_BA_F1: //CTSDuration_ba_f1
+ if ((byFBOption == AUTO_FB_0) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt0[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ } else if ((byFBOption == AUTO_FB_1) && (wRate >= RATE_18M) && (wRate <= RATE_54M)) {
+ uDurTime = pDevice->uSIFS + s_uGetTxRsvTime(pDevice, byPktType, cbFrameLength, wFB_Opt1[FB_RATE1][wRate-RATE_18M], bNeedAck);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return uDurTime;
}
-
-
static
unsigned int
-s_uFillDataHead (
- PSDevice pDevice,
- unsigned char byPktType,
- void * pTxDataHead,
- unsigned int cbFrameLength,
- unsigned int uDMAIdx,
- bool bNeedAck,
- unsigned int uFragIdx,
- unsigned int cbLastFragmentSize,
- unsigned int uMACfragNum,
- unsigned char byFBOption,
- unsigned short wCurrentRate
- )
+s_uFillDataHead(
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pTxDataHead,
+ unsigned int cbFrameLength,
+ unsigned int uDMAIdx,
+ bool bNeedAck,
+ unsigned int uFragIdx,
+ unsigned int cbLastFragmentSize,
+ unsigned int uMACfragNum,
+ unsigned char byFBOption,
+ unsigned short wCurrentRate
+)
{
- unsigned short wLen = 0x0000;
-
- if (pTxDataHead == NULL) {
- return 0;
- }
-
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (byFBOption == AUTO_FB_NONE) {
- PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- //Get Duration and TimeStamp
- pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
- byPktType, wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption)); //1: 2.4GHz
- pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
- PK_TYPE_11B, pDevice->byTopCCKBasicRate,
- bNeedAck, uFragIdx, cbLastFragmentSize,
- uMACfragNum, byFBOption)); //1: 2.4
-
- pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]);
-
- return (pBuf->wDuration_a);
- } else {
- // Auto Fallback
- PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- //Get Duration and TimeStamp
- pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
- pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_a_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
- pBuf->wDuration_a_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
-
- pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]);
-
- return (pBuf->wDuration_a);
- } //if (byFBOption == AUTO_FB_NONE)
- }
- else if (byPktType == PK_TYPE_11A) {
- if ((byFBOption != AUTO_FB_NONE)) {
- // Auto Fallback
- PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration and TimeStampOff
-
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
- pBuf->wDuration_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
- pBuf->wDuration_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
- pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- return (pBuf->wDuration);
- } else {
- PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration and TimeStampOff
-
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption));
-
- pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- return (pBuf->wDuration);
- }
- }
- else {
- PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration and TimeStampOff
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
- wCurrentRate, bNeedAck, uFragIdx,
- cbLastFragmentSize, uMACfragNum,
- byFBOption));
- pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- return (pBuf->wDuration);
- }
- return 0;
+ unsigned short wLen = 0x0000;
+
+ if (pTxDataHead == NULL) {
+ return 0;
+ }
+
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ if (byFBOption == AUTO_FB_NONE) {
+ PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
+);
+ pBuf->wTransmitLength_a = cpu_to_le16(wLen);
+ BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+ //Get Duration and TimeStamp
+ pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
+ byPktType, wCurrentRate, bNeedAck, uFragIdx,
+ cbLastFragmentSize, uMACfragNum,
+ byFBOption)); //1: 2.4GHz
+ pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
+ PK_TYPE_11B, pDevice->byTopCCKBasicRate,
+ bNeedAck, uFragIdx, cbLastFragmentSize,
+ uMACfragNum, byFBOption)); //1: 2.4
+
+ pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]);
+
+ return pBuf->wDuration_a;
+ } else {
+ // Auto Fallback
+ PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
+);
+ pBuf->wTransmitLength_a = cpu_to_le16(wLen);
+ BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+ //Get Duration and TimeStamp
+ pBuf->wDuration_a = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
+ pBuf->wDuration_b = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
+ pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
+ pBuf->wDuration_a_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
+ pBuf->wDuration_a_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //1: 2.4GHz
+
+ pBuf->wTimeStampOff_a = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ pBuf->wTimeStampOff_b = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE]);
+
+ return pBuf->wDuration_a;
+ } //if (byFBOption == AUTO_FB_NONE)
+ } else if (byPktType == PK_TYPE_11A) {
+ if ((byFBOption != AUTO_FB_NONE)) {
+ // Auto Fallback
+ PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration and TimeStampOff
+
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
+ pBuf->wDuration_f0 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
+ pBuf->wDuration_f1 = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption)); //0: 5GHz
+ pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ return pBuf->wDuration;
+ } else {
+ PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration and TimeStampOff
+
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx,
+ cbLastFragmentSize, uMACfragNum,
+ byFBOption));
+
+ pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ return pBuf->wDuration;
+ }
+ } else {
+ PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration and TimeStampOff
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
+ wCurrentRate, bNeedAck, uFragIdx,
+ cbLastFragmentSize, uMACfragNum,
+ byFBOption));
+ pBuf->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ return pBuf->wDuration;
+ }
+ return 0;
}
-
static
void
-s_vFillRTSHead (
- PSDevice pDevice,
- unsigned char byPktType,
- void * pvRTS,
- unsigned int cbFrameLength,
- bool bNeedAck,
- bool bDisCRC,
- PSEthernetHeader psEthHeader,
- unsigned short wCurrentRate,
- unsigned char byFBOption
- )
+s_vFillRTSHead(
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pvRTS,
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
+ PSEthernetHeader psEthHeader,
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
+)
{
- unsigned int uRTSFrameLen = 20;
- unsigned short wLen = 0x0000;
-
- if (pvRTS == NULL)
- return;
-
- if (bDisCRC) {
- // When CRCDIS bit is on, H/W forgot to generate FCS for RTS frame,
- // in this case we need to decrease its length by 4.
- uRTSFrameLen -= 4;
- }
-
- // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account.
- // Otherwise, we need to modify codes for them.
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (byFBOption == AUTO_FB_NONE) {
- PSRTS_g pBuf = (PSRTS_g)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
-
- pBuf->Data.wDurationID = pBuf->wDuration_aa;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- }
- }
- else {
- PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
- );
- pBuf->wTransmitLength_a = cpu_to_le16(wLen);
-
- //Get Duration
- pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wRTSDuration_ba_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_ba_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
- pBuf->Data.wDurationID = pBuf->wDuration_aa;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
-
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- }
-
- } // if (byFBOption == AUTO_FB_NONE)
- }
- else if (byPktType == PK_TYPE_11A) {
- if (byFBOption == AUTO_FB_NONE) {
- PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
-
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- }
-
- }
- else {
- PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- }
- }
- }
- else if (byPktType == PK_TYPE_11B) {
- PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
- );
- pBuf->wTransmitLength = cpu_to_le16(wLen);
- //Get Duration
- pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->Data.wDurationID = pBuf->wDuration;
- //Get RTS Frame body
- pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
-
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
-
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- }
- }
+ unsigned int uRTSFrameLen = 20;
+ unsigned short wLen = 0x0000;
+
+ if (pvRTS == NULL)
+ return;
+
+ if (bDisCRC) {
+ // When CRCDIS bit is on, H/W forgot to generate FCS for RTS frame,
+ // in this case we need to decrease its length by 4.
+ uRTSFrameLen -= 4;
+ }
+
+ // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account.
+ // Otherwise, we need to modify codes for them.
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ if (byFBOption == AUTO_FB_NONE) {
+ PSRTS_g pBuf = (PSRTS_g)pvRTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
+);
+ pBuf->wTransmitLength_a = cpu_to_le16(wLen);
+ //Get Duration
+ pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+
+ pBuf->Data.wDurationID = pBuf->wDuration_aa;
+ //Get RTS Frame body
+ pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ }
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ }
+ } else {
+ PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a)
+);
+ pBuf->wTransmitLength_a = cpu_to_le16(wLen);
+
+ //Get Duration
+ pBuf->wDuration_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wRTSDuration_ba_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_ba_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
+ pBuf->Data.wDurationID = pBuf->wDuration_aa;
+ //Get RTS Frame body
+ pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ }
+
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ }
+
+ } // if (byFBOption == AUTO_FB_NONE)
+ } else if (byPktType == PK_TYPE_11A) {
+ if (byFBOption == AUTO_FB_NONE) {
+ PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->Data.wDurationID = pBuf->wDuration;
+ //Get RTS Frame body
+ pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ }
+
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ }
+
+ } else {
+ PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f0 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f1 = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
+ pBuf->Data.wDurationID = pBuf->wDuration;
+ //Get RTS Frame body
+ pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ }
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ }
+ }
+ } else if (byPktType == PK_TYPE_11B) {
+ PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField)
+);
+ pBuf->wTransmitLength = cpu_to_le16(wLen);
+ //Get Duration
+ pBuf->wDuration = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->Data.wDurationID = pBuf->wDuration;
+ //Get RTS Frame body
+ pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ memcpy(&(pBuf->Data.abyRA[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ }
+
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pBuf->Data.abyTA[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pBuf->Data.abyTA[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ }
+ }
}
static
void
-s_vFillCTSHead (
- PSDevice pDevice,
- unsigned int uDMAIdx,
- unsigned char byPktType,
- void * pvCTS,
- unsigned int cbFrameLength,
- bool bNeedAck,
- bool bDisCRC,
- unsigned short wCurrentRate,
- unsigned char byFBOption
- )
+s_vFillCTSHead(
+ PSDevice pDevice,
+ unsigned int uDMAIdx,
+ unsigned char byPktType,
+ void *pvCTS,
+ unsigned int cbFrameLength,
+ bool bNeedAck,
+ bool bDisCRC,
+ unsigned short wCurrentRate,
+ unsigned char byFBOption
+)
{
- unsigned int uCTSFrameLen = 14;
- unsigned short wLen = 0x0000;
-
- if (pvCTS == NULL) {
- return;
- }
-
- if (bDisCRC) {
- // When CRCDIS bit is on, H/W forgot to generate FCS for CTS frame,
- // in this case we need to decrease its length by 4.
- uCTSFrameLen -= 4;
- }
-
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) {
- // Auto Fall back
- PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
-
-
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
-
- pBuf->wDuration_ba = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wDuration_ba += pDevice->wCTSDuration;
- pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
- //Get CTSDuration_ba_f0
- pBuf->wCTSDuration_ba_f0 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
- pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
- //Get CTSDuration_ba_f1
- pBuf->wCTSDuration_ba_f1 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
- pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
- //Get CTS Frame body
- pBuf->Data.wDurationID = pBuf->wDuration_ba;
- pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
- pBuf->Data.wReserved = 0x0000;
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), ETH_ALEN);
-
- } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
- PSCTS pBuf = (PSCTS)pvCTS;
- //Get SignalField,ServiceField,Length
- BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
- );
- pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- //Get CTSDuration_ba
- pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
- pBuf->wDuration_ba += pDevice->wCTSDuration;
- pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
-
- //Get CTS Frame body
- pBuf->Data.wDurationID = pBuf->wDuration_ba;
- pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
- pBuf->Data.wReserved = 0x0000;
- memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), ETH_ALEN);
- }
- }
+ unsigned int uCTSFrameLen = 14;
+ unsigned short wLen = 0x0000;
+
+ if (pvCTS == NULL) {
+ return;
+ }
+
+ if (bDisCRC) {
+ // When CRCDIS bit is on, H/W forgot to generate FCS for CTS frame,
+ // in this case we need to decrease its length by 4.
+ uCTSFrameLen -= 4;
+ }
+
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) {
+ // Auto Fall back
+ PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+
+ pBuf->wDuration_ba = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba += pDevice->wCTSDuration;
+ pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
+ //Get CTSDuration_ba_f0
+ pBuf->wCTSDuration_ba_f0 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
+ pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
+ //Get CTSDuration_ba_f1
+ pBuf->wCTSDuration_ba_f1 = (unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
+ pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
+ //Get CTS Frame body
+ pBuf->Data.wDurationID = pBuf->wDuration_ba;
+ pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
+ pBuf->Data.wReserved = 0x0000;
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), ETH_ALEN);
+
+ } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA)
+ PSCTS pBuf = (PSCTS)pvCTS;
+ //Get SignalField,ServiceField,Length
+ BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
+ (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b)
+);
+ pBuf->wTransmitLength_b = cpu_to_le16(wLen);
+ //Get CTSDuration_ba
+ pBuf->wDuration_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba += pDevice->wCTSDuration;
+ pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
+
+ //Get CTS Frame body
+ pBuf->Data.wDurationID = pBuf->wDuration_ba;
+ pBuf->Data.wFrameControl = TYPE_CTL_CTS;//0x00C4
+ pBuf->Data.wReserved = 0x0000;
+ memcpy(&(pBuf->Data.abyRA[0]), &(pDevice->abyCurrentNetAddr[0]), ETH_ALEN);
+ }
+ }
}
-
-
-
-
-
/*+
*
* Description:
@@ -1136,1079 +1071,977 @@ s_vFillCTSHead (
*
* Return Value: none
*
--*/
+ -*/
// unsigned int cbFrameSize,//Hdr+Payload+FCS
static
void
-s_vGenerateTxParameter (
- PSDevice pDevice,
- unsigned char byPktType,
- void * pTxBufHead,
- void * pvRrvTime,
- void * pvRTS,
- void * pvCTS,
- unsigned int cbFrameSize,
- bool bNeedACK,
- unsigned int uDMAIdx,
- PSEthernetHeader psEthHeader,
- unsigned short wCurrentRate
- )
+s_vGenerateTxParameter(
+ PSDevice pDevice,
+ unsigned char byPktType,
+ void *pTxBufHead,
+ void *pvRrvTime,
+ void *pvRTS,
+ void *pvCTS,
+ unsigned int cbFrameSize,
+ bool bNeedACK,
+ unsigned int uDMAIdx,
+ PSEthernetHeader psEthHeader,
+ unsigned short wCurrentRate
+)
{
- unsigned int cbMACHdLen = WLAN_HDR_ADDR3_LEN; //24
- unsigned short wFifoCtl;
- bool bDisCRC = false;
- unsigned char byFBOption = AUTO_FB_NONE;
+ unsigned int cbMACHdLen = WLAN_HDR_ADDR3_LEN; //24
+ unsigned short wFifoCtl;
+ bool bDisCRC = false;
+ unsigned char byFBOption = AUTO_FB_NONE;
// unsigned short wCurrentRate = pDevice->wCurrentRate;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter...\n");
- PSTxBufHead pFifoHead = (PSTxBufHead)pTxBufHead;
- pFifoHead->wReserved = wCurrentRate;
- wFifoCtl = pFifoHead->wFIFOCtl;
-
- if (wFifoCtl & FIFOCTL_CRCDIS) {
- bDisCRC = true;
- }
-
- if (wFifoCtl & FIFOCTL_AUTO_FB_0) {
- byFBOption = AUTO_FB_0;
- }
- else if (wFifoCtl & FIFOCTL_AUTO_FB_1) {
- byFBOption = AUTO_FB_1;
- }
-
- if (pDevice->bLongHeader)
- cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
-
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
-
- if (pvRTS != NULL) { //RTS_need
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
- pBuf->wRTSTxRrvTime_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
- pBuf->wRTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
- pBuf->wRTSTxRrvTime_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
- }
- else {//RTS_needless, PCF mode
-
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
- pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- pBuf->wCTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
- }
-
-
- //Fill CTS
- s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
- }
- }
- else if (byPktType == PK_TYPE_11A) {
-
- if (pvRTS != NULL) {//RTS_need, non PCF mode
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
- pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
- }
- else if (pvRTS == NULL) {//RTS_needless, non PCF mode
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
- }
- }
- }
- else if (byPktType == PK_TYPE_11B) {
-
- if ((pvRTS != NULL)) {//RTS_need, non PCF mode
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
- }
- //Fill RTS
- s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
- }
- else { //RTS_needless, non PCF mode
- //Fill RsvTime
- if (pvRrvTime) {
- PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
- }
- }
- }
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n");
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_vGenerateTxParameter...\n");
+ PSTxBufHead pFifoHead = (PSTxBufHead)pTxBufHead;
+ pFifoHead->wReserved = wCurrentRate;
+ wFifoCtl = pFifoHead->wFIFOCtl;
+
+ if (wFifoCtl & FIFOCTL_CRCDIS) {
+ bDisCRC = true;
+ }
+
+ if (wFifoCtl & FIFOCTL_AUTO_FB_0) {
+ byFBOption = AUTO_FB_0;
+ } else if (wFifoCtl & FIFOCTL_AUTO_FB_1) {
+ byFBOption = AUTO_FB_1;
+ }
+
+ if (pDevice->bLongHeader)
+ cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
+
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ if (pvRTS != NULL) { //RTS_need
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
+ pBuf->wRTSTxRrvTime_aa = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_bb = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ }
+ //Fill RTS
+ s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+ } else {//RTS_needless, PCF mode
+
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
+ pBuf->wTxRrvTime_a = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ pBuf->wCTSTxRrvTime_ba = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
+ }
+
+ //Fill CTS
+ s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
+ }
+ } else if (byPktType == PK_TYPE_11A) {
+ if (pvRTS != NULL) {//RTS_need, non PCF mode
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
+ pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
+ }
+ //Fill RTS
+ s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+ } else if (pvRTS == NULL) {//RTS_needless, non PCF mode
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
+ }
+ }
+ } else if (byPktType == PK_TYPE_11B) {
+ if ((pvRTS != NULL)) {//RTS_need, non PCF mode
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
+ pBuf->wRTSTxRrvTime = cpu_to_le16((unsigned short)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
+ }
+ //Fill RTS
+ s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
+ } else { //RTS_needless, non PCF mode
+ //Fill RsvTime
+ if (pvRrvTime) {
+ PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
+ pBuf->wTxRrvTime = cpu_to_le16((unsigned short)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
+ }
+ }
+ }
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_vGenerateTxParameter END.\n");
}
/*
- unsigned char *pbyBuffer,//point to pTxBufHead
- unsigned short wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
- unsigned int cbFragmentSize,//Hdr+payoad+FCS
+ unsigned char *pbyBuffer,//point to pTxBufHead
+ unsigned short wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
+ unsigned int cbFragmentSize,//Hdr+payoad+FCS
*/
static
void
s_vFillFragParameter(
- PSDevice pDevice,
- unsigned char *pbyBuffer,
- unsigned int uTxType,
- void * pvtdCurr,
- unsigned short wFragType,
- unsigned int cbReqCount
- )
+ PSDevice pDevice,
+ unsigned char *pbyBuffer,
+ unsigned int uTxType,
+ void *pvtdCurr,
+ unsigned short wFragType,
+ unsigned int cbReqCount
+)
{
- PSTxBufHead pTxBufHead = (PSTxBufHead) pbyBuffer;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vFillFragParameter...\n");
-
- if (uTxType == TYPE_SYNCDMA) {
- //PSTxSyncDesc ptdCurr = (PSTxSyncDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx);
- PSTxSyncDesc ptdCurr = (PSTxSyncDesc)pvtdCurr;
-
- //Set FIFOCtl & TimeStamp in TxSyncDesc
- ptdCurr->m_wFIFOCtl = pTxBufHead->wFIFOCtl;
- ptdCurr->m_wTimeStamp = pTxBufHead->wTimeStamp;
- //Set TSR1 & ReqCount in TxDescHead
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
- if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
- ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
- }
- else {
- ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP);
- }
- }
- else {
- //PSTxDesc ptdCurr = (PSTxDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx);
- PSTxDesc ptdCurr = (PSTxDesc)pvtdCurr;
- //Set TSR1 & ReqCount in TxDescHead
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
- if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
- ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
- }
- else {
- ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP);
- }
- }
-
- pTxBufHead->wFragCtl |= (unsigned short)wFragType;//0x0001; //0000 0000 0000 0001
-
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vFillFragParameter END\n");
+ PSTxBufHead pTxBufHead = (PSTxBufHead) pbyBuffer;
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_vFillFragParameter...\n");
+
+ if (uTxType == TYPE_SYNCDMA) {
+ //PSTxSyncDesc ptdCurr = (PSTxSyncDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx);
+ PSTxSyncDesc ptdCurr = (PSTxSyncDesc)pvtdCurr;
+
+ //Set FIFOCtl & TimeStamp in TxSyncDesc
+ ptdCurr->m_wFIFOCtl = pTxBufHead->wFIFOCtl;
+ ptdCurr->m_wTimeStamp = pTxBufHead->wTimeStamp;
+ //Set TSR1 & ReqCount in TxDescHead
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
+ if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
+ ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
+ } else {
+ ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP);
+ }
+ } else {
+ //PSTxDesc ptdCurr = (PSTxDesc)s_pvGetTxDescHead(pDevice, uTxType, uCurIdx);
+ PSTxDesc ptdCurr = (PSTxDesc)pvtdCurr;
+ //Set TSR1 & ReqCount in TxDescHead
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
+ if (wFragType == FRAGCTL_ENDFRAG) { //Last Fragmentation
+ ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
+ } else {
+ ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP);
+ }
+ }
+
+ pTxBufHead->wFragCtl |= (unsigned short)wFragType;//0x0001; //0000 0000 0000 0001
+
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_vFillFragParameter END\n");
}
static unsigned int
s_cbFillTxBufHead(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
- unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
- PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum)
+ unsigned int cbFrameBodySize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, bool bNeedEncrypt,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum)
{
- unsigned int cbMACHdLen;
- unsigned int cbFrameSize;
- unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- unsigned int cbFragPayloadSize;
- unsigned int cbLastFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- unsigned int cbLastFragPayloadSize;
- unsigned int uFragIdx;
- unsigned char *pbyPayloadHead;
- unsigned char *pbyIVHead;
- unsigned char *pbyMacHdr;
- unsigned short wFragType; //00:Non-Frag, 01:Start, 10:Mid, 11:Last
- unsigned int uDuration;
- unsigned char *pbyBuffer;
+ unsigned int cbMACHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbFragPayloadSize;
+ unsigned int cbLastFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbLastFragPayloadSize;
+ unsigned int uFragIdx;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyIVHead;
+ unsigned char *pbyMacHdr;
+ unsigned short wFragType; //00:Non-Frag, 01:Start, 10:Mid, 11:Last
+ unsigned int uDuration;
+ unsigned char *pbyBuffer;
// unsigned int uKeyEntryIdx = NUM_KEY_ENTRY+1;
// unsigned char byKeySel = 0xFF;
- unsigned int cbIVlen = 0;
- unsigned int cbICVlen = 0;
- unsigned int cbMIClen = 0;
- unsigned int cbFCSlen = 4;
- unsigned int cb802_1_H_len = 0;
- unsigned int uLength = 0;
- unsigned int uTmpLen = 0;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int cb802_1_H_len = 0;
+ unsigned int uLength = 0;
+ unsigned int uTmpLen = 0;
// unsigned char abyTmp[8];
// unsigned long dwCRC;
- unsigned int cbMICHDR = 0;
- unsigned long dwMICKey0, dwMICKey1;
- unsigned long dwMIC_Priority;
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
- unsigned long dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length".
- bool bMIC2Frag = false;
- unsigned int uMICFragLen = 0;
- unsigned int uMACfragNum = 1;
- unsigned int uPadding = 0;
- unsigned int cbReqCount = 0;
-
- bool bNeedACK;
- bool bRTS;
- bool bIsAdhoc;
- unsigned char *pbyType;
- PSTxDesc ptdCurr;
- PSTxBufHead psTxBufHd = (PSTxBufHead) pbyTxBufferAddr;
+ unsigned int cbMICHDR = 0;
+ unsigned long dwMICKey0, dwMICKey1;
+ unsigned long dwMIC_Priority;
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned long dwSafeMIC_L, dwSafeMIC_R; //Fix "Last Frag Size" < "MIC length".
+ bool bMIC2Frag = false;
+ unsigned int uMICFragLen = 0;
+ unsigned int uMACfragNum = 1;
+ unsigned int uPadding = 0;
+ unsigned int cbReqCount = 0;
+
+ bool bNeedACK;
+ bool bRTS;
+ bool bIsAdhoc;
+ unsigned char *pbyType;
+ PSTxDesc ptdCurr;
+ PSTxBufHead psTxBufHd = (PSTxBufHead) pbyTxBufferAddr;
// unsigned int tmpDescIdx;
- unsigned int cbHeaderLength = 0;
- void * pvRrvTime;
- PSMICHDRHead pMICHDR;
- void * pvRTS;
- void * pvCTS;
- void * pvTxDataHd;
- unsigned short wTxBufSize; // FFinfo size
- unsigned int uTotalCopyLength = 0;
- unsigned char byFBOption = AUTO_FB_NONE;
- bool bIsWEP256 = false;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
-
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_cbFillTxBufHead...\n");
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
-
- if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
- bNeedACK = false;
- else
- bNeedACK = true;
- bIsAdhoc = true;
- }
- else {
- // MSDUs in Infra mode always need ACK
- bNeedACK = true;
- bIsAdhoc = false;
- }
-
- if (pDevice->bLongHeader)
- cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
- else
- cbMACHdLen = WLAN_HDR_ADDR3_LEN;
-
-
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL)) {
- if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
- cbIVlen = 4;
- cbICVlen = 4;
- if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
- bIsWEP256 = true;
- }
- }
- if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- cbIVlen = 8;//IV+ExtIV
- cbMIClen = 8;
- cbICVlen = 4;
- }
- if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
- cbIVlen = 8;//RSN Header
- cbICVlen = 8;//MIC
- cbMICHDR = sizeof(SMICHDRHead);
- }
- if (pDevice->byLocalID > REV_ID_VT3253_A1) {
- //MAC Header should be padding 0 to DW alignment.
- uPadding = 4 - (cbMACHdLen%4);
- uPadding %= 4;
- }
- }
-
-
- cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
-
- if ((bNeedACK == false) ||
- (cbFrameSize < pDevice->wRTSThreshold) ||
- ((cbFrameSize >= pDevice->wFragmentationThreshold) && (pDevice->wFragmentationThreshold <= pDevice->wRTSThreshold))
- ) {
- bRTS = false;
- }
- else {
- bRTS = true;
- psTxBufHd->wFIFOCtl |= (FIFOCTL_RTS | FIFOCTL_LRETRY);
- }
- //
- // Use for AUTO FALL BACK
- //
- if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_0) {
- byFBOption = AUTO_FB_0;
- }
- else if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_1) {
- byFBOption = AUTO_FB_1;
- }
-
- //////////////////////////////////////////////////////
- //Set RrvTime/RTS/CTS Buffer
- wTxBufSize = sizeof(STxBufHead);
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
-
- if (byFBOption == AUTO_FB_NONE) {
- if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
- pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g) + sizeof(STxDataHead_g);
- }
- else { //RTS_needless
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
- }
- } else {
- // Auto Fall Back
- if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
- pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB) + sizeof(STxDataHead_g_FB);
- }
- else { //RTS_needless
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB));
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB) + sizeof(STxDataHead_g_FB);
- }
- } // Auto Fall Back
- }
- else {//802.11a/b packet
-
- if (byFBOption == AUTO_FB_NONE) {
- if (bRTS == true) {
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab));
- cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab) + sizeof(STxDataHead_ab);
- }
- else { //RTS_needless, need MICHDR
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
- }
- } else {
- // Auto Fall Back
- if (bRTS == true) {//RTS_need
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB));
- cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB) + sizeof(STxDataHead_a_FB);
- }
- else { //RTS_needless
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_a_FB);
- }
- } // Auto Fall Back
- }
- memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderLength - wTxBufSize));
+ unsigned int cbHeaderLength = 0;
+ void *pvRrvTime;
+ PSMICHDRHead pMICHDR;
+ void *pvRTS;
+ void *pvCTS;
+ void *pvTxDataHd;
+ unsigned short wTxBufSize; // FFinfo size
+ unsigned int uTotalCopyLength = 0;
+ unsigned char byFBOption = AUTO_FB_NONE;
+ bool bIsWEP256 = false;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_cbFillTxBufHead...\n");
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
+ bNeedACK = false;
+ else
+ bNeedACK = true;
+ bIsAdhoc = true;
+ } else {
+ // MSDUs in Infra mode always need ACK
+ bNeedACK = true;
+ bIsAdhoc = false;
+ }
+
+ if (pDevice->bLongHeader)
+ cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
+ else
+ cbMACHdLen = WLAN_HDR_ADDR3_LEN;
+
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL)) {
+ if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
+ cbIVlen = 4;
+ cbICVlen = 4;
+ if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN) {
+ bIsWEP256 = true;
+ }
+ }
+ if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
+ cbIVlen = 8;//IV+ExtIV
+ cbMIClen = 8;
+ cbICVlen = 4;
+ }
+ if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
+ cbIVlen = 8;//RSN Header
+ cbICVlen = 8;//MIC
+ cbMICHDR = sizeof(SMICHDRHead);
+ }
+ if (pDevice->byLocalID > REV_ID_VT3253_A1) {
+ //MAC Header should be padding 0 to DW alignment.
+ uPadding = 4 - (cbMACHdLen%4);
+ uPadding %= 4;
+ }
+ }
+
+ cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
+
+ if ((bNeedACK == false) ||
+ (cbFrameSize < pDevice->wRTSThreshold) ||
+ ((cbFrameSize >= pDevice->wFragmentationThreshold) && (pDevice->wFragmentationThreshold <= pDevice->wRTSThreshold))
+) {
+ bRTS = false;
+ } else {
+ bRTS = true;
+ psTxBufHd->wFIFOCtl |= (FIFOCTL_RTS | FIFOCTL_LRETRY);
+ }
+ //
+ // Use for AUTO FALL BACK
+ //
+ if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_0) {
+ byFBOption = AUTO_FB_0;
+ } else if (psTxBufHd->wFIFOCtl & FIFOCTL_AUTO_FB_1) {
+ byFBOption = AUTO_FB_1;
+ }
+
+ //////////////////////////////////////////////////////
+ //Set RrvTime/RTS/CTS Buffer
+ wTxBufSize = sizeof(STxBufHead);
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
+
+ if (byFBOption == AUTO_FB_NONE) {
+ if (bRTS == true) {//RTS_need
+ pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
+ pvRTS = (PSRTS_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g));
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g) + sizeof(STxDataHead_g);
+ } else { //RTS_needless
+ pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
+ pvRTS = NULL;
+ pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
+ pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+ }
+ } else {
+ // Auto Fall Back
+ if (bRTS == true) {//RTS_need
+ pvRrvTime = (PSRrvTime_gRTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS));
+ pvRTS = (PSRTS_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR);
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB));
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gRTS) + cbMICHDR + sizeof(SRTS_g_FB) + sizeof(STxDataHead_g_FB);
+ } else { //RTS_needless
+ pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
+ pvRTS = NULL;
+ pvCTS = (PSCTS_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
+ pvTxDataHd = (PSTxDataHead_g_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB));
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS_FB) + sizeof(STxDataHead_g_FB);
+ }
+ } // Auto Fall Back
+ } else {//802.11a/b packet
+
+ if (byFBOption == AUTO_FB_NONE) {
+ if (bRTS == true) {
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ pvRTS = (PSRTS_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab));
+ cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_ab) + sizeof(STxDataHead_ab);
+ } else { //RTS_needless, need MICHDR
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ pvRTS = NULL;
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+ }
+ } else {
+ // Auto Fall Back
+ if (bRTS == true) {//RTS_need
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ pvRTS = (PSRTS_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB));
+ cbHeaderLength = wTxBufSize + sizeof(PSRrvTime_ab) + cbMICHDR + sizeof(SRTS_a_FB) + sizeof(STxDataHead_a_FB);
+ } else { //RTS_needless
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ pvRTS = NULL;
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_a_FB) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
+ cbHeaderLength = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_a_FB);
+ }
+ } // Auto Fall Back
+ }
+ memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderLength - wTxBufSize));
//////////////////////////////////////////////////////////////////
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
- }
- else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
- }
- else {
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[24]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[28]);
- }
- // DO Software Michael
- MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((unsigned char *)&(psEthHeader->abyDstAddr[0]), 12);
- dwMIC_Priority = 0;
- MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
- }
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ if (pDevice->pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+ } else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) {
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+ } else {
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[24]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[28]);
+ }
+ // DO Software Michael
+ MIC_vInit(dwMICKey0, dwMICKey1);
+ MIC_vAppend((unsigned char *)&(psEthHeader->abyDstAddr[0]), 12);
+ dwMIC_Priority = 0;
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
+ }
///////////////////////////////////////////////////////////////////
- pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderLength);
- pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
- pbyIVHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding);
-
- if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true) && (bIsWEP256 == false)) {
- // Fragmentation
- // FragThreshold = Fragment size(Hdr+(IV)+fragment payload+(MIC)+(ICV)+FCS)
- cbFragmentSize = pDevice->wFragmentationThreshold;
- cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
- //FragNum = (FrameSize-(Hdr+FCS))/(Fragment Size -(Hrd+FCS)))
- uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
- cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
- if (cbLastFragPayloadSize == 0) {
- cbLastFragPayloadSize = cbFragPayloadSize;
- } else {
- uMACfragNum++;
- }
- //[Hdr+(IV)+last fragment payload+(MIC)+(ICV)+FCS]
- cbLastFragmentSize = cbMACHdLen + cbLastFragPayloadSize + cbIVlen + cbICVlen + cbFCSlen;
-
- for (uFragIdx = 0; uFragIdx < uMACfragNum; uFragIdx ++) {
- if (uFragIdx == 0) {
- //=========================
- // Start Fragmentation
- //=========================
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Start Fragmentation...\n");
- wFragType = FRAGCTL_STAFRAG;
-
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
- cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK,
- uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
- // Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
- wFragType, uDMAIdx, uFragIdx);
-
- if (bNeedEncrypt == true) {
- //Fill TXKEY
- s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
- //Fill IV(ExtIV,RSNHDR)
- if (pDevice->bEnableHostWEP) {
- pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
- pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
- }
- }
-
-
- // 802.1H
- if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
- if ((psEthHeader->wType == TYPE_PKT_IPX) ||
- (psEthHeader->wType == cpu_to_le16(0xF380))) {
- memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
- }
- else {
- memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
- }
- pbyType = (unsigned char *) (pbyPayloadHead + 6);
- memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
- cb802_1_H_len = 8;
- }
-
- cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize;
- //---------------------------
- // S/W or H/W Encryption
- //---------------------------
- //Fill MICHDR
- //if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFragPayloadSize);
- //}
- //cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (void *)psTxBufHd, byKeySel,
- // pbyPayloadHead, (unsigned short)cbFragPayloadSize, uDMAIdx);
-
-
-
- //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
- pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
-
- uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
- //copy TxBufferHeader + MacHeader to desc
- memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
-
- // Copy the Packet into a tx Buffer
- memcpy((pbyBuffer + uLength), (pPacket + 14), (cbFragPayloadSize - cb802_1_H_len));
-
-
- uTotalCopyLength += cbFragPayloadSize - cb802_1_H_len;
-
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Start MIC: %d\n", cbFragPayloadSize);
- MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFragPayloadSize);
-
- }
-
- //---------------------------
- // S/W Encryption
- //---------------------------
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), (unsigned short)cbFragPayloadSize);
- cbReqCount += cbICVlen;
- }
- }
-
- ptdCurr = (PSTxDesc)pHeadTD;
- //--------------------
- //1.Set TSR1 & ReqCount in TxDescHead
- //2.Set FragCtl in TxBufferHead
- //3.Set Frame Control
- //4.Set Sequence Control
- //5.Get S/W generate FCS
- //--------------------
- s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
-
- ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
- ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
- ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
- ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
- pDevice->iTDUsed[uDMAIdx]++;
- pHeadTD = ptdCurr->next;
- }
- else if (uFragIdx == (uMACfragNum-1)) {
- //=========================
- // Last Fragmentation
- //=========================
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Last Fragmentation...\n");
- //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx];
-
- wFragType = FRAGCTL_ENDFRAG;
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
- cbLastFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbLastFragmentSize, uDMAIdx, bNeedACK,
- uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
-
- // Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
- wFragType, uDMAIdx, uFragIdx);
-
- if (bNeedEncrypt == true) {
- //Fill TXKEY
- s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (unsigned short)cbLastFragPayloadSize, (unsigned char *)pMICHDR);
-
- if (pDevice->bEnableHostWEP) {
- pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
- pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
- }
-
- }
-
-
- cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbLastFragPayloadSize;
- //---------------------------
- // S/W or H/W Encryption
- //---------------------------
-
-
-
- pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
-
- uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
-
- //copy TxBufferHeader + MacHeader to desc
- memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
-
- // Copy the Packet into a tx Buffer
- if (bMIC2Frag == false) {
-
- memcpy((pbyBuffer + uLength),
- (pPacket + 14 + uTotalCopyLength),
- (cbLastFragPayloadSize - cbMIClen)
- );
- //TODO check uTmpLen !
- uTmpLen = cbLastFragPayloadSize - cbMIClen;
-
- }
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen:%d, cbLastFragPayloadSize:%d, uTmpLen:%d\n",
- uMICFragLen, cbLastFragPayloadSize, uTmpLen);
-
- if (bMIC2Frag == false) {
- if (uTmpLen != 0)
- MIC_vAppend((pbyBuffer + uLength), uTmpLen);
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
- MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Last MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
- } else {
- if (uMICFragLen >= 4) {
- memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
- (cbMIClen - uMICFragLen));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen >= 4: %X, %d\n",
- *(unsigned char *)((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
- (cbMIClen - uMICFragLen));
-
- } else {
- memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_L + uMICFragLen),
- (4 - uMICFragLen));
- memcpy((pbyBuffer + uLength + (4 - uMICFragLen)), &dwSafeMIC_R, 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"LAST: uMICFragLen < 4: %X, %d\n",
- *(unsigned char *)((unsigned char *)&dwSafeMIC_R + uMICFragLen - 4),
- (cbMIClen - uMICFragLen));
- }
- /*
- for (ii = 0; ii < cbLastFragPayloadSize + 8 + 24; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii - 8 - 24)));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n");
- */
- }
- MIC_vUnInit();
- } else {
- ASSERT(uTmpLen == (cbLastFragPayloadSize - cbMIClen));
- }
-
-
- //---------------------------
- // S/W Encryption
- //---------------------------
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbLastFragPayloadSize);
- cbReqCount += cbICVlen;
- }
- }
-
- ptdCurr = (PSTxDesc)pHeadTD;
-
- //--------------------
- //1.Set TSR1 & ReqCount in TxDescHead
- //2.Set FragCtl in TxBufferHead
- //3.Set Frame Control
- //4.Set Sequence Control
- //5.Get S/W generate FCS
- //--------------------
-
-
- s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
-
- ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
- ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
- ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
- ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
- pDevice->iTDUsed[uDMAIdx]++;
- pHeadTD = ptdCurr->next;
-
- }
- else {
- //=========================
- // Middle Fragmentation
- //=========================
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Middle Fragmentation...\n");
- //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx];
-
- wFragType = FRAGCTL_MIDFRAG;
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
- cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK,
- uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
-
- // Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
- wFragType, uDMAIdx, uFragIdx);
-
-
- if (bNeedEncrypt == true) {
- //Fill TXKEY
- s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
-
- if (pDevice->bEnableHostWEP) {
- pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
- pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
- }
- }
-
- cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize;
- //---------------------------
- // S/W or H/W Encryption
- //---------------------------
- //Fill MICHDR
- //if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFragPayloadSize);
- //}
- //cbReqCount += s_uDoEncryption(pDevice, psEthHeader, (void *)psTxBufHd, byKeySel,
- // pbyPayloadHead, (unsigned short)cbFragPayloadSize, uDMAIdx);
-
-
- pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
-
-
- uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
-
- //copy TxBufferHeader + MacHeader to desc
- memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
-
- // Copy the Packet into a tx Buffer
- memcpy((pbyBuffer + uLength),
- (pPacket + 14 + uTotalCopyLength),
- cbFragPayloadSize
- );
- uTmpLen = cbFragPayloadSize;
-
- uTotalCopyLength += uTmpLen;
-
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
-
- MIC_vAppend((pbyBuffer + uLength), uTmpLen);
-
- if (uTmpLen < cbFragPayloadSize) {
- bMIC2Frag = true;
- uMICFragLen = cbFragPayloadSize - uTmpLen;
- ASSERT(uMICFragLen < cbMIClen);
-
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
- MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
- dwSafeMIC_L = *pdwMIC_L;
- dwSafeMIC_R = *pdwMIC_R;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIDDLE: uMICFragLen:%d, cbFragPayloadSize:%d, uTmpLen:%d\n",
- uMICFragLen, cbFragPayloadSize, uTmpLen);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MIC in Middle frag [%d]\n", uMICFragLen);
- /*
- for (ii = 0; ii < uMICFragLen; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength + uTmpLen) + ii)));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- */
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Middle frag len: %d\n", uTmpLen);
- /*
- for (ii = 0; ii < uTmpLen; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n\n");
- */
-
- } else {
- ASSERT(uTmpLen == (cbFragPayloadSize));
- }
-
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbFragPayloadSize);
- cbReqCount += cbICVlen;
- }
- }
-
- ptdCurr = (PSTxDesc)pHeadTD;
-
- //--------------------
- //1.Set TSR1 & ReqCount in TxDescHead
- //2.Set FragCtl in TxBufferHead
- //3.Set Frame Control
- //4.Set Sequence Control
- //5.Get S/W generate FCS
- //--------------------
-
- s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
-
- ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
- ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
- ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
- ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
- pDevice->iTDUsed[uDMAIdx]++;
- pHeadTD = ptdCurr->next;
- }
- } // for (uMACfragNum)
- }
- else {
- //=========================
- // No Fragmentation
- //=========================
- //DBG_PRTGRP03(("No Fragmentation...\n"));
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No Fragmentation...\n");
- wFragType = FRAGCTL_NONFRAG;
-
- //Set FragCtl in TxBufferHead
- psTxBufHd->wFragCtl |= (unsigned short)wFragType;
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
- cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK,
- 0, 0, uMACfragNum, byFBOption, pDevice->wCurrentRate);
-
- // Generate TX MAC Header
- vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
- wFragType, uDMAIdx, 0);
-
- if (bNeedEncrypt == true) {
- //Fill TXKEY
- s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
-
- if (pDevice->bEnableHostWEP) {
- pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
- pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
- }
- }
-
- // 802.1H
- if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
- if ((psEthHeader->wType == TYPE_PKT_IPX) ||
- (psEthHeader->wType == cpu_to_le16(0xF380))) {
- memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
- }
- else {
- memcpy((unsigned char *) (pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
- }
- pbyType = (unsigned char *) (pbyPayloadHead + 6);
- memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
- cb802_1_H_len = 8;
- }
-
- cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen);
- //---------------------------
- // S/W or H/W Encryption
- //---------------------------
- //Fill MICHDR
- //if (pDevice->bAES) {
- // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Fill MICHDR...\n");
- // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, pbyMacHdr, (unsigned short)cbFrameBodySize);
- //}
-
- pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
- //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][uDescIdx].pbyVAddr;
-
- uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
-
- //copy TxBufferHeader + MacHeader to desc
- memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
-
- // Copy the Packet into a tx Buffer
- memcpy((pbyBuffer + uLength),
- (pPacket + 14),
- cbFrameBodySize - cb802_1_H_len
- );
-
- if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)){
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Length:%d, %d\n", cbFrameBodySize - cb802_1_H_len, uLength);
- /*
- for (ii = 0; ii < (cbFrameBodySize - cb802_1_H_len); ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
- */
-
- MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFrameBodySize);
-
- pdwMIC_L = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
- pdwMIC_R = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
-
- MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
- MIC_vUnInit();
-
-
- if (pDevice->bTxMICFail == true) {
- *pdwMIC_L = 0;
- *pdwMIC_R = 0;
- pDevice->bTxMICFail = false;
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderLength, uPadding, cbIVlen);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
+ pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderLength);
+ pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
+ pbyIVHead = (unsigned char *)(pbyMacHdr + cbMACHdLen + uPadding);
+
+ if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true) && (bIsWEP256 == false)) {
+ // Fragmentation
+ // FragThreshold = Fragment size(Hdr+(IV)+fragment payload+(MIC)+(ICV)+FCS)
+ cbFragmentSize = pDevice->wFragmentationThreshold;
+ cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
+ //FragNum = (FrameSize-(Hdr+FCS))/(Fragment Size -(Hrd+FCS)))
+ uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
+ cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
+ if (cbLastFragPayloadSize == 0) {
+ cbLastFragPayloadSize = cbFragPayloadSize;
+ } else {
+ uMACfragNum++;
+ }
+ //[Hdr+(IV)+last fragment payload+(MIC)+(ICV)+FCS]
+ cbLastFragmentSize = cbMACHdLen + cbLastFragPayloadSize + cbIVlen + cbICVlen + cbFCSlen;
+
+ for (uFragIdx = 0; uFragIdx < uMACfragNum; uFragIdx++) {
+ if (uFragIdx == 0) {
+ //=========================
+ // Start Fragmentation
+ //=========================
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Start Fragmentation...\n");
+ wFragType = FRAGCTL_STAFRAG;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
+ cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK,
+ uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
+ // Generate TX MAC Header
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
+ wFragType, uDMAIdx, uFragIdx);
+
+ if (bNeedEncrypt == true) {
+ //Fill TXKEY
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
+ //Fill IV(ExtIV,RSNHDR)
+ if (pDevice->bEnableHostWEP) {
+ pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
+ pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
+ }
+ }
+
+ // 802.1H
+ if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
+ if ((psEthHeader->wType == TYPE_PKT_IPX) ||
+ (psEthHeader->wType == cpu_to_le16(0xF380))) {
+ memcpy((unsigned char *)(pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
+ } else {
+ memcpy((unsigned char *)(pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
+ }
+ pbyType = (unsigned char *)(pbyPayloadHead + 6);
+ memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
+ cb802_1_H_len = 8;
+ }
+
+ cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize;
+ //---------------------------
+ // S/W or H/W Encryption
+ //---------------------------
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+
+ uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
+ //copy TxBufferHeader + MacHeader to desc
+ memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
+
+ // Copy the Packet into a tx Buffer
+ memcpy((pbyBuffer + uLength), (pPacket + 14), (cbFragPayloadSize - cb802_1_H_len));
+
+ uTotalCopyLength += cbFragPayloadSize - cb802_1_H_len;
+
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Start MIC: %d\n", cbFragPayloadSize);
+ MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFragPayloadSize);
+
+ }
+
+ //---------------------------
+ // S/W Encryption
+ //---------------------------
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ if (bNeedEncrypt) {
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len), (unsigned short)cbFragPayloadSize);
+ cbReqCount += cbICVlen;
+ }
+ }
+
+ ptdCurr = (PSTxDesc)pHeadTD;
+ //--------------------
+ //1.Set TSR1 & ReqCount in TxDescHead
+ //2.Set FragCtl in TxBufferHead
+ //3.Set Frame Control
+ //4.Set Sequence Control
+ //5.Get S/W generate FCS
+ //--------------------
+ s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
+
+ ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
+ ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
+ ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
+ ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
+ pDevice->iTDUsed[uDMAIdx]++;
+ pHeadTD = ptdCurr->next;
+ } else if (uFragIdx == (uMACfragNum-1)) {
+ //=========================
+ // Last Fragmentation
+ //=========================
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last Fragmentation...\n");
+ //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx];
+
+ wFragType = FRAGCTL_ENDFRAG;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
+ cbLastFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbLastFragmentSize, uDMAIdx, bNeedACK,
+ uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
+
+ // Generate TX MAC Header
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
+ wFragType, uDMAIdx, uFragIdx);
+
+ if (bNeedEncrypt == true) {
+ //Fill TXKEY
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbLastFragPayloadSize, (unsigned char *)pMICHDR);
+
+ if (pDevice->bEnableHostWEP) {
+ pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
+ pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
+ }
+
+ }
+
+ cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbLastFragPayloadSize;
+ //---------------------------
+ // S/W or H/W Encryption
+ //---------------------------
+
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ //pbyBuffer = (unsigned char *)pDevice->aamTxBuf[uDMAIdx][tmpDescIdx].pbyVAddr;
+
+ uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
+
+ //copy TxBufferHeader + MacHeader to desc
+ memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
+
+ // Copy the Packet into a tx Buffer
+ if (bMIC2Frag == false) {
+ memcpy((pbyBuffer + uLength),
+ (pPacket + 14 + uTotalCopyLength),
+ (cbLastFragPayloadSize - cbMIClen)
+);
+ //TODO check uTmpLen !
+ uTmpLen = cbLastFragPayloadSize - cbMIClen;
+
+ }
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "LAST: uMICFragLen:%d, cbLastFragPayloadSize:%d, uTmpLen:%d\n",
+ uMICFragLen, cbLastFragPayloadSize, uTmpLen);
+
+ if (bMIC2Frag == false) {
+ if (uTmpLen != 0)
+ MIC_vAppend((pbyBuffer + uLength), uTmpLen);
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
+ MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
+ } else {
+ if (uMICFragLen >= 4) {
+ memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
+ (cbMIClen - uMICFragLen));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "LAST: uMICFragLen >= 4: %X, %d\n",
+ *(unsigned char *)((unsigned char *)&dwSafeMIC_R + (uMICFragLen - 4)),
+ (cbMIClen - uMICFragLen));
+
+ } else {
+ memcpy((pbyBuffer + uLength), ((unsigned char *)&dwSafeMIC_L + uMICFragLen),
+ (4 - uMICFragLen));
+ memcpy((pbyBuffer + uLength + (4 - uMICFragLen)), &dwSafeMIC_R, 4);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "LAST: uMICFragLen < 4: %X, %d\n",
+ *(unsigned char *)((unsigned char *)&dwSafeMIC_R + uMICFragLen - 4),
+ (cbMIClen - uMICFragLen));
+ }
+ /*
+ for (ii = 0; ii < cbLastFragPayloadSize + 8 + 24; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii - 8 - 24)));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n\n");
+ */
+ }
+ MIC_vUnInit();
+ } else {
+ ASSERT(uTmpLen == (cbLastFragPayloadSize - cbMIClen));
+ }
+
+ //---------------------------
+ // S/W Encryption
+ //---------------------------
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ if (bNeedEncrypt) {
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbLastFragPayloadSize);
+ cbReqCount += cbICVlen;
+ }
+ }
+
+ ptdCurr = (PSTxDesc)pHeadTD;
+
+ //--------------------
+ //1.Set TSR1 & ReqCount in TxDescHead
+ //2.Set FragCtl in TxBufferHead
+ //3.Set Frame Control
+ //4.Set Sequence Control
+ //5.Get S/W generate FCS
+ //--------------------
+
+ s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
+
+ ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
+ ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
+ ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
+ ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
+ pDevice->iTDUsed[uDMAIdx]++;
+ pHeadTD = ptdCurr->next;
+
+ } else {
+ //=========================
+ // Middle Fragmentation
+ //=========================
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Middle Fragmentation...\n");
+ //tmpDescIdx = (uDescIdx + uFragIdx) % pDevice->cbTD[uDMAIdx];
+
+ wFragType = FRAGCTL_MIDFRAG;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
+ cbFragmentSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFragmentSize, uDMAIdx, bNeedACK,
+ uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption, pDevice->wCurrentRate);
+
+ // Generate TX MAC Header
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
+ wFragType, uDMAIdx, uFragIdx);
+
+ if (bNeedEncrypt == true) {
+ //Fill TXKEY
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFragPayloadSize, (unsigned char *)pMICHDR);
+
+ if (pDevice->bEnableHostWEP) {
+ pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
+ pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
+ }
+ }
+
+ cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cbFragPayloadSize;
+ //---------------------------
+ // S/W or H/W Encryption
+ //---------------------------
+
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen;
+
+ //copy TxBufferHeader + MacHeader to desc
+ memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
+
+ // Copy the Packet into a tx Buffer
+ memcpy((pbyBuffer + uLength),
+ (pPacket + 14 + uTotalCopyLength),
+ cbFragPayloadSize
+);
+ uTmpLen = cbFragPayloadSize;
+
+ uTotalCopyLength += uTmpLen;
+
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ MIC_vAppend((pbyBuffer + uLength), uTmpLen);
+
+ if (uTmpLen < cbFragPayloadSize) {
+ bMIC2Frag = true;
+ uMICFragLen = cbFragPayloadSize - uTmpLen;
+ ASSERT(uMICFragLen < cbMIClen);
+
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength + uTmpLen);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength + uTmpLen + 4);
+ MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
+ dwSafeMIC_L = *pdwMIC_L;
+ dwSafeMIC_R = *pdwMIC_R;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIDDLE: uMICFragLen:%d, cbFragPayloadSize:%d, uTmpLen:%d\n",
+ uMICFragLen, cbFragPayloadSize, uTmpLen);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Fill MIC in Middle frag [%d]\n", uMICFragLen);
+ /*
+ for (ii = 0; ii < uMICFragLen; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *((unsigned char *)((pbyBuffer + uLength + uTmpLen) + ii)));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+ */
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Middle frag len: %d\n", uTmpLen);
+ /*
+ for (ii = 0; ii < uTmpLen; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n\n");
+ */
+
+ } else {
+ ASSERT(uTmpLen == (cbFragPayloadSize));
+ }
+
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ if (bNeedEncrypt) {
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength), (unsigned short)cbFragPayloadSize);
+ cbReqCount += cbICVlen;
+ }
+ }
+
+ ptdCurr = (PSTxDesc)pHeadTD;
+
+ //--------------------
+ //1.Set TSR1 & ReqCount in TxDescHead
+ //2.Set FragCtl in TxBufferHead
+ //3.Set Frame Control
+ //4.Set Sequence Control
+ //5.Get S/W generate FCS
+ //--------------------
+
+ s_vFillFragParameter(pDevice, pbyBuffer, uDMAIdx, (void *)ptdCurr, wFragType, cbReqCount);
+
+ ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
+ ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
+ ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
+ ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
+ pDevice->iTDUsed[uDMAIdx]++;
+ pHeadTD = ptdCurr->next;
+ }
+ } // for (uMACfragNum)
+ } else {
+ //=========================
+ // No Fragmentation
+ //=========================
+ //DBG_PRTGRP03(("No Fragmentation...\n"));
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "No Fragmentation...\n");
+ wFragType = FRAGCTL_NONFRAG;
+
+ //Set FragCtl in TxBufferHead
+ psTxBufHd->wFragCtl |= (unsigned short)wFragType;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, (void *)psTxBufHd, pvRrvTime, pvRTS, pvCTS,
+ cbFrameSize, bNeedACK, uDMAIdx, psEthHeader, pDevice->wCurrentRate);
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK,
+ 0, 0, uMACfragNum, byFBOption, pDevice->wCurrentRate);
+
+ // Generate TX MAC Header
+ vGenerateMACHeader(pDevice, pbyMacHdr, (unsigned short)uDuration, psEthHeader, bNeedEncrypt,
+ wFragType, uDMAIdx, 0);
+
+ if (bNeedEncrypt == true) {
+ //Fill TXKEY
+ s_vFillTxKey(pDevice, (unsigned char *)(psTxBufHd->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
+
+ if (pDevice->bEnableHostWEP) {
+ pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
+ pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
+ }
+ }
+
+ // 802.1H
+ if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
+ if ((psEthHeader->wType == TYPE_PKT_IPX) ||
+ (psEthHeader->wType == cpu_to_le16(0xF380))) {
+ memcpy((unsigned char *)(pbyPayloadHead), &pDevice->abySNAP_Bridgetunnel[0], 6);
+ } else {
+ memcpy((unsigned char *)(pbyPayloadHead), &pDevice->abySNAP_RFC1042[0], 6);
+ }
+ pbyType = (unsigned char *)(pbyPayloadHead + 6);
+ memcpy(pbyType, &(psEthHeader->wType), sizeof(unsigned short));
+ cb802_1_H_len = 8;
+ }
+
+ cbReqCount = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen);
+ //---------------------------
+ // S/W or H/W Encryption
+ //---------------------------
+ pbyBuffer = (unsigned char *)pHeadTD->pTDInfo->buf;
+ uLength = cbHeaderLength + cbMACHdLen + uPadding + cbIVlen + cb802_1_H_len;
+
+ //copy TxBufferHeader + MacHeader to desc
+ memcpy(pbyBuffer, (void *)psTxBufHd, uLength);
+
+ // Copy the Packet into a tx Buffer
+ memcpy((pbyBuffer + uLength),
+ (pPacket + 14),
+ cbFrameBodySize - cb802_1_H_len
+);
+
+ if ((bNeedEncrypt == true) && (pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Length:%d, %d\n", cbFrameBodySize - cb802_1_H_len, uLength);
+ /*
+ for (ii = 0; ii < (cbFrameBodySize - cb802_1_H_len); ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *((unsigned char *)((pbyBuffer + uLength) + ii)));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
+ */
+
+ MIC_vAppend((pbyBuffer + uLength - cb802_1_H_len), cbFrameBodySize);
+
+ pdwMIC_L = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize);
+ pdwMIC_R = (unsigned long *)(pbyBuffer + uLength - cb802_1_H_len + cbFrameBodySize + 4);
+
+ MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
+ MIC_vUnInit();
+
+ if (pDevice->bTxMICFail == true) {
+ *pdwMIC_L = 0;
+ *pdwMIC_R = 0;
+ pDevice->bTxMICFail = false;
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "uLength: %d, %d\n", uLength, cbFrameBodySize);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderLength, uPadding, cbIVlen);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
/*
- for (ii = 0; ii < 8; ii++) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%02x ", *(((unsigned char *)(pdwMIC_L) + ii)));
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
+ for (ii = 0; ii < 8; ii++) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%02x ", *(((unsigned char *)(pdwMIC_L) + ii)));
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "\n");
*/
- }
-
-
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1)){
- if (bNeedEncrypt) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len),
- (unsigned short)(cbFrameBodySize + cbMIClen));
- cbReqCount += cbICVlen;
- }
- }
+ }
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ if (bNeedEncrypt) {
+ s_vSWencryption(pDevice, pTransmitKey, (pbyBuffer + uLength - cb802_1_H_len),
+ (unsigned short)(cbFrameBodySize + cbMIClen));
+ cbReqCount += cbICVlen;
+ }
+ }
- ptdCurr = (PSTxDesc)pHeadTD;
+ ptdCurr = (PSTxDesc)pHeadTD;
- ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
- ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
- ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
- ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
- //Set TSR1 & ReqCount in TxDescHead
- ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
- ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
+ ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
+ ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
+ ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
+ ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
+ //Set TSR1 & ReqCount in TxDescHead
+ ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
+ ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
- pDevice->iTDUsed[uDMAIdx]++;
+ pDevice->iTDUsed[uDMAIdx]++;
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " ptdCurr->m_dwReserved0[%d] ptdCurr->m_dwReserved1[%d].\n", ptdCurr->pTDInfo->dwReqCount, ptdCurr->pTDInfo->dwHeaderLength);
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " cbHeaderLength[%d]\n", cbHeaderLength);
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" ptdCurr->m_dwReserved0[%d] ptdCurr->m_dwReserved1[%d].\n", ptdCurr->pTDInfo->dwReqCount, ptdCurr->pTDInfo->dwHeaderLength);
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cbHeaderLength[%d]\n", cbHeaderLength);
-
- }
- *puMACfragNum = uMACfragNum;
- //DBG_PRTGRP03(("s_cbFillTxBufHead END\n"));
- return cbHeaderLength;
+ }
+ *puMACfragNum = uMACfragNum;
+ //DBG_PRTGRP03(("s_cbFillTxBufHead END\n"));
+ return cbHeaderLength;
}
-
void
vGenerateFIFOHeader(PSDevice pDevice, unsigned char byPktType, unsigned char *pbyTxBufferAddr,
- bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx,
- PSTxDesc pHeadTD, PSEthernetHeader psEthHeader, unsigned char *pPacket,
- PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum,
- unsigned int *pcbHeaderSize)
+ bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx,
+ PSTxDesc pHeadTD, PSEthernetHeader psEthHeader, unsigned char *pPacket,
+ PSKeyItem pTransmitKey, unsigned int uNodeIndex, unsigned int *puMACfragNum,
+ unsigned int *pcbHeaderSize)
{
- unsigned int wTxBufSize; // FFinfo size
- bool bNeedACK;
- bool bIsAdhoc;
- unsigned short cbMacHdLen;
- PSTxBufHead pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
-
- wTxBufSize = sizeof(STxBufHead);
-
- memset(pTxBufHead, 0, wTxBufSize);
- //Set FIFOCTL_NEEDACK
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0]))) {
- bNeedACK = false;
- pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
- }
- else {
- bNeedACK = true;
- pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- }
- bIsAdhoc = true;
- }
- else {
- // MSDUs in Infra mode always need ACK
- bNeedACK = true;
- pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- bIsAdhoc = false;
- }
-
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
- pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us);
-
- //Set FIFOCTL_LHEAD
- if (pDevice->bLongHeader)
- pTxBufHead->wFIFOCtl |= FIFOCTL_LHEAD;
-
- //Set FIFOCTL_GENINT
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT;
-
-
- //Set FIFOCTL_ISDMA0
- if (TYPE_TXDMA0 == uDMAIdx) {
- pTxBufHead->wFIFOCtl |= FIFOCTL_ISDMA0;
- }
-
- //Set FRAGCTL_MACHDCNT
- if (pDevice->bLongHeader) {
- cbMacHdLen = WLAN_HDR_ADDR3_LEN + 6;
- } else {
- cbMacHdLen = WLAN_HDR_ADDR3_LEN;
- }
- pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
-
- //Set packet type
- if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
- ;
- }
- else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- }
- else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
- }
- else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
- }
- //Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
- }
-
- //Set Auto Fallback Ctl
- if (pDevice->wCurrentRate >= RATE_18M) {
- if (pDevice->byAutoFBCtrl == AUTO_FB_0) {
- pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_0;
- } else if (pDevice->byAutoFBCtrl == AUTO_FB_1) {
- pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_1;
- }
- }
-
- //Set FRAGCTL_WEPTYP
- pDevice->bAES = false;
-
- //Set FRAGCTL_WEPTYP
- if (pDevice->byLocalID > REV_ID_VT3253_A1) {
- if ((bNeedEncrypt) && (pTransmitKey != NULL)) { //WEP enabled
- if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
- }
- else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { //WEP40 or WEP104
- if (pTransmitKey->uKeyLength != WLAN_WEP232_KEYLEN)
- pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
- }
- else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { //CCMP
- pTxBufHead->wFragCtl |= FRAGCTL_AES;
- }
- }
- }
+ unsigned int wTxBufSize; // FFinfo size
+ bool bNeedACK;
+ bool bIsAdhoc;
+ unsigned short cbMacHdLen;
+ PSTxBufHead pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
+
+ wTxBufSize = sizeof(STxBufHead);
+
+ memset(pTxBufHead, 0, wTxBufSize);
+ //Set FIFOCTL_NEEDACK
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0]))) {
+ bNeedACK = false;
+ pTxBufHead->wFIFOCtl = pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
+ } else {
+ bNeedACK = true;
+ pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
+ }
+ bIsAdhoc = true;
+ } else {
+ // MSDUs in Infra mode always need ACK
+ bNeedACK = true;
+ pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
+ bIsAdhoc = false;
+ }
+
+ pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
+ pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MSDU_LIFETIME_RES_64us);
+
+ //Set FIFOCTL_LHEAD
+ if (pDevice->bLongHeader)
+ pTxBufHead->wFIFOCtl |= FIFOCTL_LHEAD;
+
+ //Set FIFOCTL_GENINT
+
+ pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT;
+
+ //Set FIFOCTL_ISDMA0
+ if (TYPE_TXDMA0 == uDMAIdx) {
+ pTxBufHead->wFIFOCtl |= FIFOCTL_ISDMA0;
+ }
+
+ //Set FRAGCTL_MACHDCNT
+ if (pDevice->bLongHeader) {
+ cbMacHdLen = WLAN_HDR_ADDR3_LEN + 6;
+ } else {
+ cbMacHdLen = WLAN_HDR_ADDR3_LEN;
+ }
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
+
+ //Set packet type
+ if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
+ ;
+ } else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
+ } else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
+ } else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
+ }
+ //Set FIFOCTL_GrpAckPolicy
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
+ }
+
+ //Set Auto Fallback Ctl
+ if (pDevice->wCurrentRate >= RATE_18M) {
+ if (pDevice->byAutoFBCtrl == AUTO_FB_0) {
+ pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_0;
+ } else if (pDevice->byAutoFBCtrl == AUTO_FB_1) {
+ pTxBufHead->wFIFOCtl |= FIFOCTL_AUTO_FB_1;
+ }
+ }
+
+ //Set FRAGCTL_WEPTYP
+ pDevice->bAES = false;
+
+ //Set FRAGCTL_WEPTYP
+ if (pDevice->byLocalID > REV_ID_VT3253_A1) {
+ if ((bNeedEncrypt) && (pTransmitKey != NULL)) { //WEP enabled
+ if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
+ pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) { //WEP40 or WEP104
+ if (pTransmitKey->uKeyLength != WLAN_WEP232_KEYLEN)
+ pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) { //CCMP
+ pTxBufHead->wFragCtl |= FRAGCTL_AES;
+ }
+ }
+ }
#ifdef PLICE_DEBUG
- //printk("Func:vGenerateFIFOHeader:TxDataRate is %d,TxPower is %d\n",pDevice->wCurrentRate,pDevice->byCurPwr);
-
- //if (pDevice->wCurrentRate <= 3)
- //{
- // RFbRawSetPower(pDevice,36,pDevice->wCurrentRate);
- //}
- //else
-
RFbSetPower(pDevice, pDevice->wCurrentRate, pDevice->byCurrentCh);
#endif
- //if (pDevice->wCurrentRate == 3)
- //pDevice->byCurPwr = 46;
- pTxBufHead->byTxPower = pDevice->byCurPwr;
-
-
-
+ pTxBufHead->byTxPower = pDevice->byCurPwr;
/*
- if(pDevice->bEnableHostWEP)
- pTxBufHead->wFragCtl &= ~(FRAGCTL_TKIP | FRAGCTL_LEGACY |FRAGCTL_AES);
+ if (pDevice->bEnableHostWEP)
+ pTxBufHead->wFragCtl &= ~(FRAGCTL_TKIP | FRAGCTL_LEGACY |FRAGCTL_AES);
*/
- *pcbHeaderSize = s_cbFillTxBufHead(pDevice, byPktType, pbyTxBufferAddr, cbPayloadSize,
- uDMAIdx, pHeadTD, psEthHeader, pPacket, bNeedEncrypt,
- pTransmitKey, uNodeIndex, puMACfragNum);
+ *pcbHeaderSize = s_cbFillTxBufHead(pDevice, byPktType, pbyTxBufferAddr, cbPayloadSize,
+ uDMAIdx, pHeadTD, psEthHeader, pPacket, bNeedEncrypt,
+ pTransmitKey, uNodeIndex, puMACfragNum);
- return;
+ return;
}
-
-
-
/*+
*
* Description:
@@ -2226,964 +2059,882 @@ vGenerateFIFOHeader(PSDevice pDevice, unsigned char byPktType, unsigned char *pb
*
* Return Value: none
*
--*/
+ -*/
void
-vGenerateMACHeader (
- PSDevice pDevice,
- unsigned char *pbyBufferAddr,
- unsigned short wDuration,
- PSEthernetHeader psEthHeader,
- bool bNeedEncrypt,
- unsigned short wFragType,
- unsigned int uDMAIdx,
- unsigned int uFragIdx
- )
+vGenerateMACHeader(
+ PSDevice pDevice,
+ unsigned char *pbyBufferAddr,
+ unsigned short wDuration,
+ PSEthernetHeader psEthHeader,
+ bool bNeedEncrypt,
+ unsigned short wFragType,
+ unsigned int uDMAIdx,
+ unsigned int uFragIdx
+)
{
- PS802_11Header pMACHeader = (PS802_11Header)pbyBufferAddr;
-
- memset(pMACHeader, 0, (sizeof(S802_11Header))); //- sizeof(pMACHeader->dwIV)));
-
- if (uDMAIdx == TYPE_ATIMDMA) {
- pMACHeader->wFrameCtl = TYPE_802_11_ATIM;
- } else {
- pMACHeader->wFrameCtl = TYPE_802_11_DATA;
- }
-
- if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- pMACHeader->wFrameCtl |= FC_FROMDS;
- }
- else {
- if (pDevice->eOPMode == OP_MODE_ADHOC) {
- memcpy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr3[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- }
- else {
- memcpy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr1[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- pMACHeader->wFrameCtl |= FC_TODS;
- }
- }
-
- if (bNeedEncrypt)
- pMACHeader->wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_ISWEP(1));
-
- pMACHeader->wDurationID = cpu_to_le16(wDuration);
-
- if (pDevice->bLongHeader) {
- PWLAN_80211HDR_A4 pMACA4Header = (PWLAN_80211HDR_A4) pbyBufferAddr;
- pMACHeader->wFrameCtl |= (FC_TODS | FC_FROMDS);
- memcpy(pMACA4Header->abyAddr4, pDevice->abyBSSID, WLAN_ADDR_LEN);
- }
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
-
- //Set FragNumber in Sequence Control
- pMACHeader->wSeqCtl |= cpu_to_le16((unsigned short)uFragIdx);
-
- if ((wFragType == FRAGCTL_ENDFRAG) || (wFragType == FRAGCTL_NONFRAG)) {
- pDevice->wSeqCounter++;
- if (pDevice->wSeqCounter > 0x0fff)
- pDevice->wSeqCounter = 0;
- }
-
- if ((wFragType == FRAGCTL_STAFRAG) || (wFragType == FRAGCTL_MIDFRAG)) { //StartFrag or MidFrag
- pMACHeader->wFrameCtl |= FC_MOREFRAG;
- }
+ PS802_11Header pMACHeader = (PS802_11Header)pbyBufferAddr;
+
+ memset(pMACHeader, 0, (sizeof(S802_11Header))); //- sizeof(pMACHeader->dwIV)));
+
+ if (uDMAIdx == TYPE_ATIMDMA) {
+ pMACHeader->wFrameCtl = TYPE_802_11_ATIM;
+ } else {
+ pMACHeader->wFrameCtl = TYPE_802_11_DATA;
+ }
+
+ if (pDevice->eOPMode == OP_MODE_AP) {
+ memcpy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr2[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ pMACHeader->wFrameCtl |= FC_FROMDS;
+ } else {
+ if (pDevice->eOPMode == OP_MODE_ADHOC) {
+ memcpy(&(pMACHeader->abyAddr1[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr3[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ } else {
+ memcpy(&(pMACHeader->abyAddr3[0]), &(psEthHeader->abyDstAddr[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr2[0]), &(psEthHeader->abySrcAddr[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->abyAddr1[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ pMACHeader->wFrameCtl |= FC_TODS;
+ }
+ }
+
+ if (bNeedEncrypt)
+ pMACHeader->wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_ISWEP(1));
+
+ pMACHeader->wDurationID = cpu_to_le16(wDuration);
+
+ if (pDevice->bLongHeader) {
+ PWLAN_80211HDR_A4 pMACA4Header = (PWLAN_80211HDR_A4) pbyBufferAddr;
+ pMACHeader->wFrameCtl |= (FC_TODS | FC_FROMDS);
+ memcpy(pMACA4Header->abyAddr4, pDevice->abyBSSID, WLAN_ADDR_LEN);
+ }
+ pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+
+ //Set FragNumber in Sequence Control
+ pMACHeader->wSeqCtl |= cpu_to_le16((unsigned short)uFragIdx);
+
+ if ((wFragType == FRAGCTL_ENDFRAG) || (wFragType == FRAGCTL_NONFRAG)) {
+ pDevice->wSeqCounter++;
+ if (pDevice->wSeqCounter > 0x0fff)
+ pDevice->wSeqCounter = 0;
+ }
+
+ if ((wFragType == FRAGCTL_STAFRAG) || (wFragType == FRAGCTL_MIDFRAG)) { //StartFrag or MidFrag
+ pMACHeader->wFrameCtl |= FC_MOREFRAG;
+ }
}
-
-
-
-
-
CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
-
- PSTxDesc pFrstTD;
- unsigned char byPktType;
- unsigned char *pbyTxBufferAddr;
- void * pvRTS;
- PSCTS pCTS;
- void * pvTxDataHd;
- unsigned int uDuration;
- unsigned int cbReqCount;
- PS802_11Header pMACHeader;
- unsigned int cbHeaderSize;
- unsigned int cbFrameBodySize;
- bool bNeedACK;
- bool bIsPSPOLL = false;
- PSTxBufHead pTxBufHead;
- unsigned int cbFrameSize;
- unsigned int cbIVlen = 0;
- unsigned int cbICVlen = 0;
- unsigned int cbMIClen = 0;
- unsigned int cbFCSlen = 4;
- unsigned int uPadding = 0;
- unsigned short wTxBufSize;
- unsigned int cbMacHdLen;
- SEthernetHeader sEthHeader;
- void * pvRrvTime;
- void * pMICHDR;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned short wCurrentRate = RATE_1M;
-
-
- if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
- return CMD_STATUS_RESOURCES;
- }
-
- pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
- pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
- cbFrameBodySize = pPacket->cbPayloadLen;
- pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
- wTxBufSize = sizeof(STxBufHead);
- memset(pTxBufHead, 0, wTxBufSize);
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- wCurrentRate = RATE_6M;
- byPktType = PK_TYPE_11A;
- } else {
- wCurrentRate = RATE_1M;
- byPktType = PK_TYPE_11B;
- }
-
- // SetPower will cause error power TX state for OFDM Date packet in TX buffer.
- // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability.
- // And cmd timer will wait data pkt TX finish before scanning so it's OK
- // to set power here.
- if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
-
+ PSTxDesc pFrstTD;
+ unsigned char byPktType;
+ unsigned char *pbyTxBufferAddr;
+ void *pvRTS;
+ PSCTS pCTS;
+ void *pvTxDataHd;
+ unsigned int uDuration;
+ unsigned int cbReqCount;
+ PS802_11Header pMACHeader;
+ unsigned int cbHeaderSize;
+ unsigned int cbFrameBodySize;
+ bool bNeedACK;
+ bool bIsPSPOLL = false;
+ PSTxBufHead pTxBufHead;
+ unsigned int cbFrameSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uPadding = 0;
+ unsigned short wTxBufSize;
+ unsigned int cbMacHdLen;
+ SEthernetHeader sEthHeader;
+ void *pvRrvTime;
+ void *pMICHDR;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned short wCurrentRate = RATE_1M;
+
+ if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 0) {
+ return CMD_STATUS_RESOURCES;
+ }
+
+ pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
+ pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
+ cbFrameBodySize = pPacket->cbPayloadLen;
+ pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
+ wTxBufSize = sizeof(STxBufHead);
+ memset(pTxBufHead, 0, wTxBufSize);
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ wCurrentRate = RATE_6M;
+ byPktType = PK_TYPE_11A;
+ } else {
+ wCurrentRate = RATE_1M;
+ byPktType = PK_TYPE_11B;
+ }
+
+ // SetPower will cause error power TX state for OFDM Date packet in TX buffer.
+ // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability.
+ // And cmd timer will wait data pkt TX finish before scanning so it's OK
+ // to set power here.
+ if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh);
- } else {
- RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel);
- }
- pTxBufHead->byTxPower = pDevice->byCurPwr;
- //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++
- if (pDevice->byFOETuning) {
- if ((pPacket->p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) {
- wCurrentRate = RATE_24M;
- byPktType = PK_TYPE_11GA;
- }
- }
-
- //Set packet type
- if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
- pTxBufHead->wFIFOCtl = 0;
- }
- else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- }
- else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
- }
- else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
- }
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
- pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
-
-
- if (is_multicast_ether_addr(&(pPacket->p80211Header->sA3.abyAddr1[0])))
- bNeedACK = false;
- else {
- bNeedACK = true;
- pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- };
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
- (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ) {
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY;
- //Set Preamble type always long
- //pDevice->byPreambleType = PREAMBLE_LONG;
- // probe-response don't retry
- //if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) {
- // bNeedACK = false;
- // pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK);
- //}
- }
-
- pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
-
- if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
- bIsPSPOLL = true;
- cbMacHdLen = WLAN_HDR_ADDR2_LEN;
- } else {
- cbMacHdLen = WLAN_HDR_ADDR3_LEN;
- }
-
- //Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
-
- // Notes:
- // Although spec says MMPDU can be fragmented; In most cases,
- // no one will send a MMPDU under fragmentation. With RTS may occur.
- pDevice->bAES = false; //Set FRAGCTL_WEPTYP
-
- if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
- cbIVlen = 4;
- cbICVlen = 4;
- pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
- }
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- cbIVlen = 8;//IV+ExtIV
- cbMIClen = 8;
- cbICVlen = 4;
- pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
- //We need to get seed here for filling TxKey entry.
- //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
- // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
- }
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- cbIVlen = 8;//RSN Header
- cbICVlen = 8;//MIC
- pTxBufHead->wFragCtl |= FRAGCTL_AES;
- pDevice->bAES = true;
- }
- //MAC Header should be padding 0 to DW alignment.
- uPadding = 4 - (cbMacHdLen%4);
- uPadding %= 4;
- }
-
- cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen;
-
- //Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
- }
- //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
-
- //Set RrvTime/RTS/CTS Buffer
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
-
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = NULL;
- pvRTS = NULL;
- pCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS) + sizeof(STxDataHead_g);
- }
- else { // 802.11a/b packet
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = NULL;
- pvRTS = NULL;
- pCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + sizeof(STxDataHead_ab);
- }
-
- memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderSize - wTxBufSize));
-
- memcpy(&(sEthHeader.abyDstAddr[0]), &(pPacket->p80211Header->sA3.abyAddr1[0]), ETH_ALEN);
- memcpy(&(sEthHeader.abySrcAddr[0]), &(pPacket->p80211Header->sA3.abyAddr2[0]), ETH_ALEN);
- //=========================
- // No Fragmentation
- //=========================
- pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
-
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS,
- cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate);
-
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
- 0, 0, 1, AUTO_FB_NONE, wCurrentRate);
-
- pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
-
- cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize;
-
- if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
- unsigned char *pbyIVHead;
- unsigned char *pbyPayloadHead;
- unsigned char *pbyBSSID;
- PSKeyItem pTransmitKey = NULL;
-
- pbyIVHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
- pbyPayloadHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
-
- //Fill TXKEY
- //Kyle: Need fix: TKIP and AES did't encrypt Mnt Packet.
- //s_vFillTxKey(pDevice, (unsigned char *)pTxBufHead->adwTxKey, NULL);
-
- //Fill IV(ExtIV,RSNHDR)
- //s_vFillPrePayload(pDevice, pbyIVHead, NULL);
- //---------------------------
- // S/W or H/W Encryption
- //---------------------------
- //Fill MICHDR
- //if (pDevice->bAES) {
- // s_vFillMICHDR(pDevice, (unsigned char *)pMICHDR, (unsigned char *)pMACHeader, (unsigned short)cbFrameBodySize);
- //}
- do {
- if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
- (pDevice->bLinkPass == true)) {
- pbyBSSID = pDevice->abyBSSID;
- // get pairwise key
- if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
- // get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n");
- break;
- }
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get PTK.\n");
- break;
- }
- }
- // get group key
- pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
- pTransmitKey = NULL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KEY is NULL. OP Mode[%d]\n", pDevice->eOPMode);
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Get GTK.\n");
- }
- } while(false);
- //Fill TXKEY
- s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- (unsigned char *)pMACHeader, (unsigned short)cbFrameBodySize, NULL);
-
- memcpy(pMACHeader, pPacket->p80211Header, cbMacHdLen);
- memcpy(pbyPayloadHead, ((unsigned char *)(pPacket->p80211Header) + cbMacHdLen),
- cbFrameBodySize);
- }
- else {
- // Copy the Packet into a tx Buffer
- memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
- }
-
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
- pDevice->wSeqCounter++ ;
- if (pDevice->wSeqCounter > 0x0fff)
- pDevice->wSeqCounter = 0;
-
- if (bIsPSPOLL) {
- // The MAC will automatically replace the Duration-field of MAC header by Duration-field
- // of FIFO control header.
- // This will cause AID-field of PS-POLL packet to be incorrect (Because PS-POLL's AID field is
- // in the same place of other packet's Duration-field).
- // And it will cause Cisco-AP to issue Disassociation-packet
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- } else {
- ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
- }
- }
-
-
- // first TD is the only TD
- //Set TSR1 & ReqCount in TxDescHead
- pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU);
- pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma;
- pFrstTD->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
- pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma);
- pFrstTD->pTDInfo->byFlags = 0;
-
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
- // Disable PS
- MACbPSWakeup(pDevice->PortOffset);
- }
- pDevice->bPWBitOn = false;
-
- wmb();
- pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
- wmb();
-
- pDevice->iTDUsed[TYPE_TXDMA0]++;
-
- if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n");
- }
-
- pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next;
-#ifdef PLICE_DEBUG
- //printk("SCAN:CurrentRate is %d,TxPower is %d\n",wCurrentRate,pTxBufHead->byTxPower);
-#endif
+ } else {
+ RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel);
+ }
+ pTxBufHead->byTxPower = pDevice->byCurPwr;
+ //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++
+ if (pDevice->byFOETuning) {
+ if ((pPacket->p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) {
+ wCurrentRate = RATE_24M;
+ byPktType = PK_TYPE_11GA;
+ }
+ }
+
+ //Set packet type
+ if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
+ pTxBufHead->wFIFOCtl = 0;
+ } else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
+ } else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
+ } else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
+ }
+
+ pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
+ pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
+
+ if (is_multicast_ether_addr(&(pPacket->p80211Header->sA3.abyAddr1[0])))
+ bNeedACK = false;
+ else {
+ bNeedACK = true;
+ pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
+ };
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
+ (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
+ pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY;
+ }
+
+ pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
+
+ if ((pPacket->p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
+ bIsPSPOLL = true;
+ cbMacHdLen = WLAN_HDR_ADDR2_LEN;
+ } else {
+ cbMacHdLen = WLAN_HDR_ADDR3_LEN;
+ }
+
+ //Set FRAGCTL_MACHDCNT
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)(cbMacHdLen << 10));
+
+ // Notes:
+ // Although spec says MMPDU can be fragmented; In most cases,
+ // no one will send a MMPDU under fragmentation. With RTS may occur.
+ pDevice->bAES = false; //Set FRAGCTL_WEPTYP
+
+ if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
+ cbIVlen = 4;
+ cbICVlen = 4;
+ pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ cbIVlen = 8;//IV+ExtIV
+ cbMIClen = 8;
+ cbICVlen = 4;
+ pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
+ //We need to get seed here for filling TxKey entry.
+ //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
+ // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ cbIVlen = 8;//RSN Header
+ cbICVlen = 8;//MIC
+ pTxBufHead->wFragCtl |= FRAGCTL_AES;
+ pDevice->bAES = true;
+ }
+ //MAC Header should be padding 0 to DW alignment.
+ uPadding = 4 - (cbMacHdLen%4);
+ uPadding %= 4;
+ }
+
+ cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen;
+
+ //Set FIFOCTL_GrpAckPolicy
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
+ }
+ //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
+
+ //Set RrvTime/RTS/CTS Buffer
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
+
+ pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = NULL;
+ pvRTS = NULL;
+ pCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
+ pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS));
+ cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + sizeof(SCTS) + sizeof(STxDataHead_g);
+ } else { // 802.11a/b packet
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = NULL;
+ pvRTS = NULL;
+ pCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + sizeof(STxDataHead_ab);
+ }
+
+ memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderSize - wTxBufSize));
+
+ memcpy(&(sEthHeader.abyDstAddr[0]), &(pPacket->p80211Header->sA3.abyAddr1[0]), ETH_ALEN);
+ memcpy(&(sEthHeader.abySrcAddr[0]), &(pPacket->p80211Header->sA3.abyAddr2[0]), ETH_ALEN);
+ //=========================
+ // No Fragmentation
+ //=========================
+ pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS,
+ cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate);
+
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
+ 0, 0, 1, AUTO_FB_NONE, wCurrentRate);
+
+ pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
+
+ cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize;
+
+ if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
+ unsigned char *pbyIVHead;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyBSSID;
+ PSKeyItem pTransmitKey = NULL;
+
+ pbyIVHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
+ pbyPayloadHead = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
+
+ //Fill TXKEY
+ //Kyle: Need fix: TKIP and AES did't encrypt Mnt Packet.
+ //s_vFillTxKey(pDevice, (unsigned char *)pTxBufHead->adwTxKey, NULL);
+
+ //Fill IV(ExtIV,RSNHDR)
+ //s_vFillPrePayload(pDevice, pbyIVHead, NULL);
+ //---------------------------
+ // S/W or H/W Encryption
+ //---------------------------
+ do {
+ if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
+ (pDevice->bLinkPass == true)) {
+ pbyBSSID = pDevice->abyBSSID;
+ // get pairwise key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, PAIRWISE_KEY, &pTransmitKey) == false) {
+ // get group key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get GTK.\n");
+ break;
+ }
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get PTK.\n");
+ break;
+ }
+ }
+ // get group key
+ pbyBSSID = pDevice->abyBroadcastAddr;
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
+ pTransmitKey = NULL;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "KEY is NULL. OP Mode[%d]\n", pDevice->eOPMode);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Get GTK.\n");
+ }
+ } while (false);
+ //Fill TXKEY
+ s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ (unsigned char *)pMACHeader, (unsigned short)cbFrameBodySize, NULL);
+
+ memcpy(pMACHeader, pPacket->p80211Header, cbMacHdLen);
+ memcpy(pbyPayloadHead, ((unsigned char *)(pPacket->p80211Header) + cbMacHdLen),
+ cbFrameBodySize);
+ } else {
+ // Copy the Packet into a tx Buffer
+ memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
+ }
+
+ pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pDevice->wSeqCounter++;
+ if (pDevice->wSeqCounter > 0x0fff)
+ pDevice->wSeqCounter = 0;
+
+ if (bIsPSPOLL) {
+ // The MAC will automatically replace the Duration-field of MAC header by Duration-field
+ // of FIFO control header.
+ // This will cause AID-field of PS-POLL packet to be incorrect (Because PS-POLL's AID field is
+ // in the same place of other packet's Duration-field).
+ // And it will cause Cisco-AP to issue Disassociation-packet
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ } else {
+ ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(pPacket->p80211Header->sA2.wDurationID);
+ }
+ }
+
+ // first TD is the only TD
+ //Set TSR1 & ReqCount in TxDescHead
+ pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU);
+ pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma;
+ pFrstTD->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
+ pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma);
+ pFrstTD->pTDInfo->byFlags = 0;
+
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
+ // Disable PS
+ MACbPSWakeup(pDevice->PortOffset);
+ }
+ pDevice->bPWBitOn = false;
+
+ wmb();
+ pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
+ wmb();
+
+ pDevice->iTDUsed[TYPE_TXDMA0]++;
+
+ if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n");
+ }
+
+ pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next;
#ifdef TxInSleep
- pDevice->nTxDataTimeCout=0; //2008-8-21 chester <add> for send null packet
- #endif
-
- // Poll Transmit the adapter
- MACvTransmit0(pDevice->PortOffset);
+ pDevice->nTxDataTimeCout = 0; //2008-8-21 chester <add> for send null packet
+#endif
- return CMD_STATUS_PENDING;
+ // Poll Transmit the adapter
+ MACvTransmit0(pDevice->PortOffset);
+ return CMD_STATUS_PENDING;
}
-
CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) {
-
- unsigned char byPktType;
- unsigned char *pbyBuffer = (unsigned char *)pDevice->tx_beacon_bufs;
- unsigned int cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
- unsigned int cbHeaderSize = 0;
- unsigned short wTxBufSize = sizeof(STxShortBufHead);
- PSTxShortBufHead pTxBufHead = (PSTxShortBufHead) pbyBuffer;
- PSTxDataHead_ab pTxDataHead = (PSTxDataHead_ab) (pbyBuffer + wTxBufSize);
- PS802_11Header pMACHeader;
- unsigned short wCurrentRate;
- unsigned short wLen = 0x0000;
-
-
- memset(pTxBufHead, 0, wTxBufSize);
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- wCurrentRate = RATE_6M;
- byPktType = PK_TYPE_11A;
- } else {
- wCurrentRate = RATE_2M;
- byPktType = PK_TYPE_11B;
- }
-
- //Set Preamble type always long
- pDevice->byPreambleType = PREAMBLE_LONG;
-
- //Set FIFOCTL_GENINT
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT;
-
-
- //Set packet type & Get Duration
- if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
- pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, byPktType,
- wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
- }
- else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, byPktType,
- wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
- }
-
- BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType,
- (unsigned short *)&(wLen), (unsigned char *)&(pTxDataHead->byServiceField), (unsigned char *)&(pTxDataHead->bySignalField)
- );
- pTxDataHead->wTransmitLength = cpu_to_le16(wLen);
- //Get TimeStampOff
- pTxDataHead->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
- cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
-
- //Generate Beacon Header
- pMACHeader = (PS802_11Header)(pbyBuffer + cbHeaderSize);
- memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
-
- pMACHeader->wDurationID = 0;
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
- pDevice->wSeqCounter++ ;
- if (pDevice->wSeqCounter > 0x0fff)
- pDevice->wSeqCounter = 0;
-
- // Set Beacon buffer length
- pDevice->wBCNBufLen = pPacket->cbMPDULen + cbHeaderSize;
-
- MACvSetCurrBCNTxDescAddr(pDevice->PortOffset, (pDevice->tx_beacon_dma));
-
- MACvSetCurrBCNLength(pDevice->PortOffset, pDevice->wBCNBufLen);
- // Set auto Transmit on
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- // Poll Transmit the adapter
- MACvTransmitBCN(pDevice->PortOffset);
-
- return CMD_STATUS_PENDING;
+ unsigned char byPktType;
+ unsigned char *pbyBuffer = (unsigned char *)pDevice->tx_beacon_bufs;
+ unsigned int cbFrameSize = pPacket->cbMPDULen + WLAN_FCS_LEN;
+ unsigned int cbHeaderSize = 0;
+ unsigned short wTxBufSize = sizeof(STxShortBufHead);
+ PSTxShortBufHead pTxBufHead = (PSTxShortBufHead) pbyBuffer;
+ PSTxDataHead_ab pTxDataHead = (PSTxDataHead_ab) (pbyBuffer + wTxBufSize);
+ PS802_11Header pMACHeader;
+ unsigned short wCurrentRate;
+ unsigned short wLen = 0x0000;
+
+ memset(pTxBufHead, 0, wTxBufSize);
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ wCurrentRate = RATE_6M;
+ byPktType = PK_TYPE_11A;
+ } else {
+ wCurrentRate = RATE_2M;
+ byPktType = PK_TYPE_11B;
+ }
+
+ //Set Preamble type always long
+ pDevice->byPreambleType = PREAMBLE_LONG;
+
+ //Set FIFOCTL_GENINT
+
+ pTxBufHead->wFIFOCtl |= FIFOCTL_GENINT;
+
+ //Set packet type & Get Duration
+ if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
+ pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, byPktType,
+ wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
+ } else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
+ pTxDataHead->wDuration = cpu_to_le16((unsigned short)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, byPktType,
+ wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
+ }
+
+ BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType,
+ (unsigned short *)&(wLen), (unsigned char *)&(pTxDataHead->byServiceField), (unsigned char *)&(pTxDataHead->bySignalField)
+);
+ pTxDataHead->wTransmitLength = cpu_to_le16(wLen);
+ //Get TimeStampOff
+ pTxDataHead->wTimeStampOff = cpu_to_le16(wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE]);
+ cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
+
+ //Generate Beacon Header
+ pMACHeader = (PS802_11Header)(pbyBuffer + cbHeaderSize);
+ memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
+
+ pMACHeader->wDurationID = 0;
+ pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pDevice->wSeqCounter++;
+ if (pDevice->wSeqCounter > 0x0fff)
+ pDevice->wSeqCounter = 0;
+
+ // Set Beacon buffer length
+ pDevice->wBCNBufLen = pPacket->cbMPDULen + cbHeaderSize;
+
+ MACvSetCurrBCNTxDescAddr(pDevice->PortOffset, (pDevice->tx_beacon_dma));
+
+ MACvSetCurrBCNLength(pDevice->PortOffset, pDevice->wBCNBufLen);
+ // Set auto Transmit on
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ // Poll Transmit the adapter
+ MACvTransmitBCN(pDevice->PortOffset);
+
+ return CMD_STATUS_PENDING;
}
-
-
unsigned int
-cbGetFragCount (
- PSDevice pDevice,
- PSKeyItem pTransmitKey,
- unsigned int cbFrameBodySize,
- PSEthernetHeader psEthHeader
- )
+cbGetFragCount(
+ PSDevice pDevice,
+ PSKeyItem pTransmitKey,
+ unsigned int cbFrameBodySize,
+ PSEthernetHeader psEthHeader
+)
{
- unsigned int cbMACHdLen;
- unsigned int cbFrameSize;
- unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
- unsigned int cbFragPayloadSize;
- unsigned int cbLastFragPayloadSize;
- unsigned int cbIVlen = 0;
- unsigned int cbICVlen = 0;
- unsigned int cbMIClen = 0;
- unsigned int cbFCSlen = 4;
- unsigned int uMACfragNum = 1;
- bool bNeedACK;
-
-
-
- if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
- (pDevice->eOPMode == OP_MODE_AP)) {
- if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
- bNeedACK = false;
- else
- bNeedACK = true;
- }
- else {
- // MSDUs in Infra mode always need ACK
- bNeedACK = true;
- }
-
- if (pDevice->bLongHeader)
- cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
- else
- cbMACHdLen = WLAN_HDR_ADDR3_LEN;
-
-
- if (pDevice->bEncryptionEnable == true) {
-
- if (pTransmitKey == NULL) {
- if ((pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) ||
- (pDevice->pMgmt->eAuthenMode < WMAC_AUTH_WPA)) {
- cbIVlen = 4;
- cbICVlen = 4;
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- cbIVlen = 8;//IV+ExtIV
- cbMIClen = 8;
- cbICVlen = 4;
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- cbIVlen = 8;//RSN Header
- cbICVlen = 8;//MIC
- }
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
- cbIVlen = 4;
- cbICVlen = 4;
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
- cbIVlen = 8;//IV+ExtIV
- cbMIClen = 8;
- cbICVlen = 4;
- } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
- cbIVlen = 8;//RSN Header
- cbICVlen = 8;//MIC
- }
- }
-
- cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
-
- if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true)) {
- // Fragmentation
- cbFragmentSize = pDevice->wFragmentationThreshold;
- cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
- uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
- cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
- if (cbLastFragPayloadSize == 0) {
- cbLastFragPayloadSize = cbFragPayloadSize;
- } else {
- uMACfragNum++;
- }
- }
- return uMACfragNum;
+ unsigned int cbMACHdLen;
+ unsigned int cbFrameSize;
+ unsigned int cbFragmentSize; //Hdr+(IV)+payoad+(MIC)+(ICV)+FCS
+ unsigned int cbFragPayloadSize;
+ unsigned int cbLastFragPayloadSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uMACfragNum = 1;
+ bool bNeedACK;
+
+ if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
+ (pDevice->eOPMode == OP_MODE_AP)) {
+ if (is_multicast_ether_addr(&(psEthHeader->abyDstAddr[0])))
+ bNeedACK = false;
+ else
+ bNeedACK = true;
+ } else {
+ // MSDUs in Infra mode always need ACK
+ bNeedACK = true;
+ }
+
+ if (pDevice->bLongHeader)
+ cbMACHdLen = WLAN_HDR_ADDR3_LEN + 6;
+ else
+ cbMACHdLen = WLAN_HDR_ADDR3_LEN;
+
+ if (pDevice->bEncryptionEnable == true) {
+ if (pTransmitKey == NULL) {
+ if ((pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) ||
+ (pDevice->pMgmt->eAuthenMode < WMAC_AUTH_WPA)) {
+ cbIVlen = 4;
+ cbICVlen = 4;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ cbIVlen = 8;//IV+ExtIV
+ cbMIClen = 8;
+ cbICVlen = 4;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ cbIVlen = 8;//RSN Header
+ cbICVlen = 8;//MIC
+ }
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
+ cbIVlen = 4;
+ cbICVlen = 4;
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_TKIP) {
+ cbIVlen = 8;//IV+ExtIV
+ cbMIClen = 8;
+ cbICVlen = 4;
+ } else if (pTransmitKey->byCipherSuite == KEY_CTL_CCMP) {
+ cbIVlen = 8;//RSN Header
+ cbICVlen = 8;//MIC
+ }
+ }
+
+ cbFrameSize = cbMACHdLen + cbIVlen + (cbFrameBodySize + cbMIClen) + cbICVlen + cbFCSlen;
+
+ if ((cbFrameSize > pDevice->wFragmentationThreshold) && (bNeedACK == true)) {
+ // Fragmentation
+ cbFragmentSize = pDevice->wFragmentationThreshold;
+ cbFragPayloadSize = cbFragmentSize - cbMACHdLen - cbIVlen - cbICVlen - cbFCSlen;
+ uMACfragNum = (unsigned short) ((cbFrameBodySize + cbMIClen) / cbFragPayloadSize);
+ cbLastFragPayloadSize = (cbFrameBodySize + cbMIClen) % cbFragPayloadSize;
+ if (cbLastFragPayloadSize == 0) {
+ cbLastFragPayloadSize = cbFragPayloadSize;
+ } else {
+ uMACfragNum++;
+ }
+ }
+ return uMACfragNum;
}
-
void
vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, unsigned int cbMPDULen) {
-
- PSTxDesc pFrstTD;
- unsigned char byPktType;
- unsigned char *pbyTxBufferAddr;
- void * pvRTS;
- void * pvCTS;
- void * pvTxDataHd;
- unsigned int uDuration;
- unsigned int cbReqCount;
- PS802_11Header pMACHeader;
- unsigned int cbHeaderSize;
- unsigned int cbFrameBodySize;
- bool bNeedACK;
- bool bIsPSPOLL = false;
- PSTxBufHead pTxBufHead;
- unsigned int cbFrameSize;
- unsigned int cbIVlen = 0;
- unsigned int cbICVlen = 0;
- unsigned int cbMIClen = 0;
- unsigned int cbFCSlen = 4;
- unsigned int uPadding = 0;
- unsigned int cbMICHDR = 0;
- unsigned int uLength = 0;
- unsigned long dwMICKey0, dwMICKey1;
- unsigned long dwMIC_Priority;
- unsigned long *pdwMIC_L;
- unsigned long *pdwMIC_R;
- unsigned short wTxBufSize;
- unsigned int cbMacHdLen;
- SEthernetHeader sEthHeader;
- void * pvRrvTime;
- void * pMICHDR;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned short wCurrentRate = RATE_1M;
- PUWLAN_80211HDR p80211Header;
- unsigned int uNodeIndex = 0;
- bool bNodeExist = false;
- SKeyItem STempKey;
- PSKeyItem pTransmitKey = NULL;
- unsigned char *pbyIVHead;
- unsigned char *pbyPayloadHead;
- unsigned char *pbyMacHdr;
-
- unsigned int cbExtSuppRate = 0;
+ PSTxDesc pFrstTD;
+ unsigned char byPktType;
+ unsigned char *pbyTxBufferAddr;
+ void *pvRTS;
+ void *pvCTS;
+ void *pvTxDataHd;
+ unsigned int uDuration;
+ unsigned int cbReqCount;
+ PS802_11Header pMACHeader;
+ unsigned int cbHeaderSize;
+ unsigned int cbFrameBodySize;
+ bool bNeedACK;
+ bool bIsPSPOLL = false;
+ PSTxBufHead pTxBufHead;
+ unsigned int cbFrameSize;
+ unsigned int cbIVlen = 0;
+ unsigned int cbICVlen = 0;
+ unsigned int cbMIClen = 0;
+ unsigned int cbFCSlen = 4;
+ unsigned int uPadding = 0;
+ unsigned int cbMICHDR = 0;
+ unsigned int uLength = 0;
+ unsigned long dwMICKey0, dwMICKey1;
+ unsigned long dwMIC_Priority;
+ unsigned long *pdwMIC_L;
+ unsigned long *pdwMIC_R;
+ unsigned short wTxBufSize;
+ unsigned int cbMacHdLen;
+ SEthernetHeader sEthHeader;
+ void *pvRrvTime;
+ void *pMICHDR;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned short wCurrentRate = RATE_1M;
+ PUWLAN_80211HDR p80211Header;
+ unsigned int uNodeIndex = 0;
+ bool bNodeExist = false;
+ SKeyItem STempKey;
+ PSKeyItem pTransmitKey = NULL;
+ unsigned char *pbyIVHead;
+ unsigned char *pbyPayloadHead;
+ unsigned char *pbyMacHdr;
+
+ unsigned int cbExtSuppRate = 0;
// PWLAN_IE pItem;
-
- pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
-
- if(cbMPDULen <= WLAN_HDR_ADDR3_LEN) {
- cbFrameBodySize = 0;
- }
- else {
- cbFrameBodySize = cbMPDULen - WLAN_HDR_ADDR3_LEN;
- }
- p80211Header = (PUWLAN_80211HDR)pbMPDU;
-
-
- pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
- pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
- pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
- wTxBufSize = sizeof(STxBufHead);
- memset(pTxBufHead, 0, wTxBufSize);
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- wCurrentRate = RATE_6M;
- byPktType = PK_TYPE_11A;
- } else {
- wCurrentRate = RATE_1M;
- byPktType = PK_TYPE_11B;
- }
-
- // SetPower will cause error power TX state for OFDM Date packet in TX buffer.
- // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability.
- // And cmd timer will wait data pkt TX to finish before scanning so it's OK
- // to set power here.
- if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
- RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh);
- } else {
- RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel);
- }
- pTxBufHead->byTxPower = pDevice->byCurPwr;
-
- //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++
- if (pDevice->byFOETuning) {
- if ((p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) {
- wCurrentRate = RATE_24M;
- byPktType = PK_TYPE_11GA;
- }
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vDMA0_tx_80211: p80211Header->sA3.wFrameCtl = %x \n", p80211Header->sA3.wFrameCtl);
-
- //Set packet type
- if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
- pTxBufHead->wFIFOCtl = 0;
- }
- else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
- }
- else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
- }
- else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
- }
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
- pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
-
-
- if (is_multicast_ether_addr(&(p80211Header->sA3.abyAddr1[0]))) {
- bNeedACK = false;
- if (pDevice->bEnableHostWEP) {
- uNodeIndex = 0;
- bNodeExist = true;
- }
- }
- else {
- if (pDevice->bEnableHostWEP) {
- if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, (unsigned char *)(p80211Header->sA3.abyAddr1), &uNodeIndex))
- bNodeExist = true;
- }
- bNeedACK = true;
- pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
- };
-
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
- (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ) {
-
- pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY;
- //Set Preamble type always long
- //pDevice->byPreambleType = PREAMBLE_LONG;
-
- // probe-response don't retry
- //if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_MGMT_PROBE_RSP) {
- // bNeedACK = false;
- // pTxBufHead->wFIFOCtl &= (~FIFOCTL_NEEDACK);
- //}
- }
-
- pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
-
- if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
- bIsPSPOLL = true;
- cbMacHdLen = WLAN_HDR_ADDR2_LEN;
- } else {
- cbMacHdLen = WLAN_HDR_ADDR3_LEN;
- }
-
- // hostapd deamon ext support rate patch
- if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
-
- if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) {
- cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN;
- }
-
- if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0) {
- cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
- }
-
- if (cbExtSuppRate >0) {
- cbFrameBodySize = WLAN_ASSOCRESP_OFF_SUPP_RATES;
- }
- }
-
-
- //Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)cbMacHdLen << 10);
-
- // Notes:
- // Although spec says MMPDU can be fragmented; In most cases,
- // no one will send a MMPDU under fragmentation. With RTS may occur.
- pDevice->bAES = false; //Set FRAGCTL_WEPTYP
-
-
- if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
- cbIVlen = 4;
- cbICVlen = 4;
- pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
- }
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- cbIVlen = 8;//IV+ExtIV
- cbMIClen = 8;
- cbICVlen = 4;
- pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
- //We need to get seed here for filling TxKey entry.
- //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
- // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
- }
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- cbIVlen = 8;//RSN Header
- cbICVlen = 8;//MIC
- cbMICHDR = sizeof(SMICHDRHead);
- pTxBufHead->wFragCtl |= FRAGCTL_AES;
- pDevice->bAES = true;
- }
- //MAC Header should be padding 0 to DW alignment.
- uPadding = 4 - (cbMacHdLen%4);
- uPadding %= 4;
- }
-
- cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen + cbExtSuppRate;
-
- //Set FIFOCTL_GrpAckPolicy
- if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
- pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
- }
- //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
-
-
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
-
- pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
- pvRTS = NULL;
- pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
- pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
-
- }
- else {//802.11a/b packet
-
- pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
- pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
- pvRTS = NULL;
- pvCTS = NULL;
- pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
- cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
-
- }
-
- memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderSize - wTxBufSize));
- memcpy(&(sEthHeader.abyDstAddr[0]), &(p80211Header->sA3.abyAddr1[0]), ETH_ALEN);
- memcpy(&(sEthHeader.abySrcAddr[0]), &(p80211Header->sA3.abyAddr2[0]), ETH_ALEN);
- //=========================
- // No Fragmentation
- //=========================
- pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
-
-
- //Fill FIFO,RrvTime,RTS,and CTS
- s_vGenerateTxParameter(pDevice, byPktType, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
- cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate);
-
- //Fill DataHead
- uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
- 0, 0, 1, AUTO_FB_NONE, wCurrentRate);
-
- pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
-
- cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate;
-
- pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize);
- pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
- pbyIVHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding);
-
- // Copy the Packet into a tx Buffer
- memcpy(pbyMacHdr, pbMPDU, cbMacHdLen);
-
- // version set to 0, patch for hostapd deamon
- pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc);
- memcpy(pbyPayloadHead, (pbMPDU + cbMacHdLen), cbFrameBodySize);
-
- // replace support rate, patch for hostapd deamon( only support 11M)
- if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
- if (cbExtSuppRate != 0) {
- if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0)
- memcpy((pbyPayloadHead + cbFrameBodySize),
- pMgmt->abyCurrSuppRates,
- ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN
- );
- if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0)
- memcpy((pbyPayloadHead + cbFrameBodySize) + ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN,
- pMgmt->abyCurrExtSuppRates,
- ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN
- );
- }
- }
-
- // Set wep
- if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
-
- if (pDevice->bEnableHostWEP) {
- pTransmitKey = &STempKey;
- pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
- pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
- pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
- pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
- pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
- memcpy(pTransmitKey->abyKey,
- &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
- pTransmitKey->uKeyLength
- );
- }
-
- if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
-
- dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
-
- // DO Software Michael
- MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((unsigned char *)&(sEthHeader.abyDstAddr[0]), 12);
- dwMIC_Priority = 0;
- MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
-
- uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen;
-
- MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize);
-
- pdwMIC_L = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
- pdwMIC_R = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
-
- MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
- MIC_vUnInit();
-
- if (pDevice->bTxMICFail == true) {
- *pdwMIC_L = 0;
- *pdwMIC_R = 0;
- pDevice->bTxMICFail = false;
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"uLength: %d, %d\n", uLength, cbFrameBodySize);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderSize, uPadding, cbIVlen);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
-
- }
-
-
- s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
-
- if (pDevice->bEnableHostWEP) {
- pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
- pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
- }
-
- if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (unsigned short)(cbFrameBodySize + cbMIClen));
- }
- }
-
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
- pDevice->wSeqCounter++ ;
- if (pDevice->wSeqCounter > 0x0fff)
- pDevice->wSeqCounter = 0;
-
-
- if (bIsPSPOLL) {
- // The MAC will automatically replace the Duration-field of MAC header by Duration-field
- // of FIFO control header.
- // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
- // in the same place of other packet's Duration-field).
- // And it will cause Cisco-AP to issue Disassociation-packet
- if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID);
- ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID);
- } else {
- ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID);
- }
- }
-
-
- // first TD is the only TD
- //Set TSR1 & ReqCount in TxDescHead
- pFrstTD->pTDInfo->skb = skb;
- pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU);
- pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma;
- pFrstTD->m_td1TD1.wReqCount = cpu_to_le16(cbReqCount);
- pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma);
- pFrstTD->pTDInfo->byFlags = 0;
- pFrstTD->pTDInfo->byFlags |= TD_FLAGS_PRIV_SKB;
-
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
- // Disable PS
- MACbPSWakeup(pDevice->PortOffset);
- }
- pDevice->bPWBitOn = false;
-
- wmb();
- pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
- wmb();
-
- pDevice->iTDUsed[TYPE_TXDMA0]++;
-
- if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n");
- }
-
- pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next;
-
- // Poll Transmit the adapter
- MACvTransmit0(pDevice->PortOffset);
-
- return;
+ pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
+
+ if (cbMPDULen <= WLAN_HDR_ADDR3_LEN) {
+ cbFrameBodySize = 0;
+ } else {
+ cbFrameBodySize = cbMPDULen - WLAN_HDR_ADDR3_LEN;
+ }
+ p80211Header = (PUWLAN_80211HDR)pbMPDU;
+
+ pFrstTD = pDevice->apCurrTD[TYPE_TXDMA0];
+ pbyTxBufferAddr = (unsigned char *)pFrstTD->pTDInfo->buf;
+ pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
+ wTxBufSize = sizeof(STxBufHead);
+ memset(pTxBufHead, 0, wTxBufSize);
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ wCurrentRate = RATE_6M;
+ byPktType = PK_TYPE_11A;
+ } else {
+ wCurrentRate = RATE_1M;
+ byPktType = PK_TYPE_11B;
+ }
+
+ // SetPower will cause error power TX state for OFDM Date packet in TX buffer.
+ // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability.
+ // And cmd timer will wait data pkt TX to finish before scanning so it's OK
+ // to set power here.
+ if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) {
+ RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh);
+ } else {
+ RFbSetPower(pDevice, wCurrentRate, pMgmt->uCurrChannel);
+ }
+ pTxBufHead->byTxPower = pDevice->byCurPwr;
+
+ //+++++++++++++++++++++ Patch VT3253 A1 performance +++++++++++++++++++++++++++
+ if (pDevice->byFOETuning) {
+ if ((p80211Header->sA3.wFrameCtl & TYPE_DATE_NULL) == TYPE_DATE_NULL) {
+ wCurrentRate = RATE_24M;
+ byPktType = PK_TYPE_11GA;
+ }
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vDMA0_tx_80211: p80211Header->sA3.wFrameCtl = %x \n", p80211Header->sA3.wFrameCtl);
+
+ //Set packet type
+ if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
+ pTxBufHead->wFIFOCtl = 0;
+ } else if (byPktType == PK_TYPE_11B) {//0000 0001 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11B;
+ } else if (byPktType == PK_TYPE_11GB) {//0000 0010 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GB;
+ } else if (byPktType == PK_TYPE_11GA) {//0000 0011 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_11GA;
+ }
+
+ pTxBufHead->wFIFOCtl |= FIFOCTL_TMOEN;
+ pTxBufHead->wTimeStamp = cpu_to_le16(DEFAULT_MGN_LIFETIME_RES_64us);
+
+ if (is_multicast_ether_addr(&(p80211Header->sA3.abyAddr1[0]))) {
+ bNeedACK = false;
+ if (pDevice->bEnableHostWEP) {
+ uNodeIndex = 0;
+ bNodeExist = true;
+ }
+ } else {
+ if (pDevice->bEnableHostWEP) {
+ if (BSSDBbIsSTAInNodeDB(pDevice->pMgmt, (unsigned char *)(p80211Header->sA3.abyAddr1), &uNodeIndex))
+ bNodeExist = true;
+ }
+ bNeedACK = true;
+ pTxBufHead->wFIFOCtl |= FIFOCTL_NEEDACK;
+ };
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
+ (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
+ pTxBufHead->wFIFOCtl |= FIFOCTL_LRETRY;
+ }
+
+ pTxBufHead->wFIFOCtl |= (FIFOCTL_GENINT | FIFOCTL_ISDMA0);
+
+ if ((p80211Header->sA4.wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL) {
+ bIsPSPOLL = true;
+ cbMacHdLen = WLAN_HDR_ADDR2_LEN;
+ } else {
+ cbMacHdLen = WLAN_HDR_ADDR3_LEN;
+ }
+
+ // hostapd deamon ext support rate patch
+ if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
+ if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) {
+ cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN;
+ }
+
+ if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0) {
+ cbExtSuppRate += ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
+ }
+
+ if (cbExtSuppRate > 0) {
+ cbFrameBodySize = WLAN_ASSOCRESP_OFF_SUPP_RATES;
+ }
+ }
+
+ //Set FRAGCTL_MACHDCNT
+ pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)cbMacHdLen << 10);
+
+ // Notes:
+ // Although spec says MMPDU can be fragmented; In most cases,
+ // no one will send a MMPDU under fragmentation. With RTS may occur.
+ pDevice->bAES = false; //Set FRAGCTL_WEPTYP
+
+ if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
+ cbIVlen = 4;
+ cbICVlen = 4;
+ pTxBufHead->wFragCtl |= FRAGCTL_LEGACY;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ cbIVlen = 8;//IV+ExtIV
+ cbMIClen = 8;
+ cbICVlen = 4;
+ pTxBufHead->wFragCtl |= FRAGCTL_TKIP;
+ //We need to get seed here for filling TxKey entry.
+ //TKIPvMixKey(pTransmitKey->abyKey, pDevice->abyCurrentNetAddr,
+ // pTransmitKey->wTSC15_0, pTransmitKey->dwTSC47_16, pDevice->abyPRNG);
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ cbIVlen = 8;//RSN Header
+ cbICVlen = 8;//MIC
+ cbMICHDR = sizeof(SMICHDRHead);
+ pTxBufHead->wFragCtl |= FRAGCTL_AES;
+ pDevice->bAES = true;
+ }
+ //MAC Header should be padding 0 to DW alignment.
+ uPadding = 4 - (cbMacHdLen%4);
+ uPadding %= 4;
+ }
+
+ cbFrameSize = cbMacHdLen + cbFrameBodySize + cbIVlen + cbMIClen + cbICVlen + cbFCSlen + cbExtSuppRate;
+
+ //Set FIFOCTL_GrpAckPolicy
+ if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
+ pTxBufHead->wFIFOCtl |= FIFOCTL_GRPACK;
+ }
+ //the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
+
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
+
+ pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS));
+ pvRTS = NULL;
+ pvCTS = (PSCTS) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR);
+ pvTxDataHd = (PSTxDataHead_g) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS));
+ cbHeaderSize = wTxBufSize + sizeof(SRrvTime_gCTS) + cbMICHDR + sizeof(SCTS) + sizeof(STxDataHead_g);
+
+ } else {//802.11a/b packet
+
+ pvRrvTime = (PSRrvTime_ab) (pbyTxBufferAddr + wTxBufSize);
+ pMICHDR = (PSMICHDRHead) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab));
+ pvRTS = NULL;
+ pvCTS = NULL;
+ pvTxDataHd = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR);
+ cbHeaderSize = wTxBufSize + sizeof(SRrvTime_ab) + cbMICHDR + sizeof(STxDataHead_ab);
+
+ }
+
+ memset((void *)(pbyTxBufferAddr + wTxBufSize), 0, (cbHeaderSize - wTxBufSize));
+ memcpy(&(sEthHeader.abyDstAddr[0]), &(p80211Header->sA3.abyAddr1[0]), ETH_ALEN);
+ memcpy(&(sEthHeader.abySrcAddr[0]), &(p80211Header->sA3.abyAddr2[0]), ETH_ALEN);
+ //=========================
+ // No Fragmentation
+ //=========================
+ pTxBufHead->wFragCtl |= (unsigned short)FRAGCTL_NONFRAG;
+
+ //Fill FIFO,RrvTime,RTS,and CTS
+ s_vGenerateTxParameter(pDevice, byPktType, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
+ cbFrameSize, bNeedACK, TYPE_TXDMA0, &sEthHeader, wCurrentRate);
+
+ //Fill DataHead
+ uDuration = s_uFillDataHead(pDevice, byPktType, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
+ 0, 0, 1, AUTO_FB_NONE, wCurrentRate);
+
+ pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
+
+ cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate;
+
+ pbyMacHdr = (unsigned char *)(pbyTxBufferAddr + cbHeaderSize);
+ pbyPayloadHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
+ pbyIVHead = (unsigned char *)(pbyMacHdr + cbMacHdLen + uPadding);
+
+ // Copy the Packet into a tx Buffer
+ memcpy(pbyMacHdr, pbMPDU, cbMacHdLen);
+
+ // version set to 0, patch for hostapd deamon
+ pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc);
+ memcpy(pbyPayloadHead, (pbMPDU + cbMacHdLen), cbFrameBodySize);
+
+ // replace support rate, patch for hostapd deamon(only support 11M)
+ if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) {
+ if (cbExtSuppRate != 0) {
+ if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0)
+ memcpy((pbyPayloadHead + cbFrameBodySize),
+ pMgmt->abyCurrSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN
+);
+ if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len != 0)
+ memcpy((pbyPayloadHead + cbFrameBodySize) + ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len + WLAN_IEHDR_LEN,
+ pMgmt->abyCurrExtSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates)->len + WLAN_IEHDR_LEN
+);
+ }
+ }
+
+ // Set wep
+ if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
+ if (pDevice->bEnableHostWEP) {
+ pTransmitKey = &STempKey;
+ pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
+ pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
+ pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
+ pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
+ pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
+ memcpy(pTransmitKey->abyKey,
+ &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
+ pTransmitKey->uKeyLength
+);
+ }
+
+ if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
+ dwMICKey0 = *(unsigned long *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(unsigned long *)(&pTransmitKey->abyKey[20]);
+
+ // DO Software Michael
+ MIC_vInit(dwMICKey0, dwMICKey1);
+ MIC_vAppend((unsigned char *)&(sEthHeader.abyDstAddr[0]), 12);
+ dwMIC_Priority = 0;
+ MIC_vAppend((unsigned char *)&dwMIC_Priority, 4);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "DMA0_tx_8021:MIC KEY: %lX, %lX\n", dwMICKey0, dwMICKey1);
+
+ uLength = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen;
+
+ MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize);
+
+ pdwMIC_L = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
+ pdwMIC_R = (unsigned long *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
+
+ MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
+ MIC_vUnInit();
+
+ if (pDevice->bTxMICFail == true) {
+ *pdwMIC_L = 0;
+ *pdwMIC_R = 0;
+ pDevice->bTxMICFail = false;
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "uLength: %d, %d\n", uLength, cbFrameBodySize);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "cbReqCount:%d, %d, %d, %d\n", cbReqCount, cbHeaderSize, uPadding, cbIVlen);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "MIC:%lx, %lx\n", *pdwMIC_L, *pdwMIC_R);
+
+ }
+
+ s_vFillTxKey(pDevice, (unsigned char *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (unsigned short)cbFrameBodySize, (unsigned char *)pMICHDR);
+
+ if (pDevice->bEnableHostWEP) {
+ pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
+ pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0 = pTransmitKey->wTSC15_0;
+ }
+
+ if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
+ s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (unsigned short)(cbFrameBodySize + cbMIClen));
+ }
+ }
+
+ pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pDevice->wSeqCounter++;
+ if (pDevice->wSeqCounter > 0x0fff)
+ pDevice->wSeqCounter = 0;
+
+ if (bIsPSPOLL) {
+ // The MAC will automatically replace the Duration-field of MAC header by Duration-field
+ // of FIFO control header.
+ // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is
+ // in the same place of other packet's Duration-field).
+ // And it will cause Cisco-AP to issue Disassociation-packet
+ if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
+ ((PSTxDataHead_g)pvTxDataHd)->wDuration_a = cpu_to_le16(p80211Header->sA2.wDurationID);
+ ((PSTxDataHead_g)pvTxDataHd)->wDuration_b = cpu_to_le16(p80211Header->sA2.wDurationID);
+ } else {
+ ((PSTxDataHead_ab)pvTxDataHd)->wDuration = cpu_to_le16(p80211Header->sA2.wDurationID);
+ }
+ }
+
+ // first TD is the only TD
+ //Set TSR1 & ReqCount in TxDescHead
+ pFrstTD->pTDInfo->skb = skb;
+ pFrstTD->m_td1TD1.byTCR = (TCR_STP | TCR_EDP | EDMSDU);
+ pFrstTD->pTDInfo->skb_dma = pFrstTD->pTDInfo->buf_dma;
+ pFrstTD->m_td1TD1.wReqCount = cpu_to_le16(cbReqCount);
+ pFrstTD->buff_addr = cpu_to_le32(pFrstTD->pTDInfo->skb_dma);
+ pFrstTD->pTDInfo->byFlags = 0;
+ pFrstTD->pTDInfo->byFlags |= TD_FLAGS_PRIV_SKB;
+
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
+ // Disable PS
+ MACbPSWakeup(pDevice->PortOffset);
+ }
+ pDevice->bPWBitOn = false;
+
+ wmb();
+ pFrstTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
+ wmb();
+
+ pDevice->iTDUsed[TYPE_TXDMA0]++;
+
+ if (AVAIL_TD(pDevice, TYPE_TXDMA0) <= 1) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " available td0 <= 1\n");
+ }
+
+ pDevice->apCurrTD[TYPE_TXDMA0] = pFrstTD->next;
+
+ // Poll Transmit the adapter
+ MACvTransmit0(pDevice->PortOffset);
+
+ return;
}
-
-
diff --git a/drivers/staging/vt6655/rxtx.h b/drivers/staging/vt6655/rxtx.h
index fa827b828a30..4f2cf34dc39f 100644
--- a/drivers/staging/vt6655/rxtx.h
+++ b/drivers/staging/vt6655/rxtx.h
@@ -40,45 +40,41 @@
/*--------------------- Export Functions --------------------------*/
/*
-void
-vGenerateMACHeader(PSDevice pDevice, unsigned long dwTxBufferAddr, unsigned char *pbySkbData,
- unsigned int cbPacketSize, bool bDMA0Used, unsigned int *pcbHeadSize,
- unsigned int *pcbAppendPayload);
-
-void
-vProcessRxMACHeader(PSDevice pDevice, unsigned long dwRxBufferAddr, unsigned int cbPacketSize,
- bool bIsWEP, unsigned int *pcbHeadSize);
+ void
+ vGenerateMACHeader(PSDevice pDevice, unsigned long dwTxBufferAddr, unsigned char *pbySkbData,
+ unsigned int cbPacketSize, bool bDMA0Used, unsigned int *pcbHeadSize,
+ unsigned int *pcbAppendPayload);
+
+ void
+ vProcessRxMACHeader(PSDevice pDevice, unsigned long dwRxBufferAddr, unsigned int cbPacketSize,
+ bool bIsWEP, unsigned int *pcbHeadSize);
*/
-
void
-vGenerateMACHeader (
- PSDevice pDevice,
- unsigned char *pbyBufferAddr,
- unsigned short wDuration,
- PSEthernetHeader psEthHeader,
- bool bNeedEncrypt,
- unsigned short wFragType,
- unsigned int uDMAIdx,
- unsigned int uFragIdx
- );
-
+vGenerateMACHeader(
+ PSDevice pDevice,
+ unsigned char *pbyBufferAddr,
+ unsigned short wDuration,
+ PSEthernetHeader psEthHeader,
+ bool bNeedEncrypt,
+ unsigned short wFragType,
+ unsigned int uDMAIdx,
+ unsigned int uFragIdx
+);
unsigned int
cbGetFragCount(
- PSDevice pDevice,
- PSKeyItem pTransmitKey,
- unsigned int cbFrameBodySize,
- PSEthernetHeader psEthHeader
- );
-
+ PSDevice pDevice,
+ PSKeyItem pTransmitKey,
+ unsigned int cbFrameBodySize,
+ PSEthernetHeader psEthHeader
+);
void
vGenerateFIFOHeader(PSDevice pDevice, unsigned char byPktTyp, unsigned char *pbyTxBufferAddr,
- bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
- PSEthernetHeader psEthHeader, unsigned char *pPacket, PSKeyItem pTransmitKey,
- unsigned int uNodeIndex, unsigned int *puMACfragNum, unsigned int *pcbHeaderSize);
-
+ bool bNeedEncrypt, unsigned int cbPayloadSize, unsigned int uDMAIdx, PSTxDesc pHeadTD,
+ PSEthernetHeader psEthHeader, unsigned char *pPacket, PSKeyItem pTransmitKey,
+ unsigned int uNodeIndex, unsigned int *puMACfragNum, unsigned int *pcbHeaderSize);
void vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, unsigned int cbMPDULen);
CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket);
diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c
index 6a0a232d1a0c..eaddc33c9d2d 100644
--- a/drivers/staging/vt6655/srom.c
+++ b/drivers/staging/vt6655/srom.c
@@ -60,9 +60,6 @@
/*--------------------- Export Functions --------------------------*/
-
-
-
/*
* Description: Read a byte from EEPROM, by MAC I2C
*
@@ -78,39 +75,38 @@
*/
unsigned char SROMbyReadEmbedded(unsigned long dwIoBase, unsigned char byContntOffset)
{
- unsigned short wDelay, wNoACK;
- unsigned char byWait;
- unsigned char byData;
- unsigned char byOrg;
-
- byData = 0xFF;
- VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
- /* turn off hardware retry for getting NACK */
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY)));
- for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) {
- VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID);
- VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset);
-
- /* issue read command */
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMR);
- /* wait DONE be set */
- for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) {
- VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
- if (byWait & (I2MCSR_DONE | I2MCSR_NACK))
- break;
- PCAvDelayByIO(CB_DELAY_LOOP_WAIT);
- }
- if ((wDelay < W_MAX_TIMEOUT) &&
- ( !(byWait & I2MCSR_NACK))) {
- break;
- }
- }
- VNSvInPortB(dwIoBase + MAC_REG_I2MDIPT, &byData);
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- return byData;
+ unsigned short wDelay, wNoACK;
+ unsigned char byWait;
+ unsigned char byData;
+ unsigned char byOrg;
+
+ byData = 0xFF;
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
+ /* turn off hardware retry for getting NACK */
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY)));
+ for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) {
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID);
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset);
+
+ /* issue read command */
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMR);
+ /* wait DONE be set */
+ for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) {
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
+ if (byWait & (I2MCSR_DONE | I2MCSR_NACK))
+ break;
+ PCAvDelayByIO(CB_DELAY_LOOP_WAIT);
+ }
+ if ((wDelay < W_MAX_TIMEOUT) &&
+ (!(byWait & I2MCSR_NACK))) {
+ break;
+ }
+ }
+ VNSvInPortB(dwIoBase + MAC_REG_I2MDIPT, &byData);
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
+ return byData;
}
-
/*
* Description: Write a byte to EEPROM, by MAC I2C
*
@@ -127,43 +123,42 @@ unsigned char SROMbyReadEmbedded(unsigned long dwIoBase, unsigned char byContntO
*/
bool SROMbWriteEmbedded(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byData)
{
- unsigned short wDelay, wNoACK;
- unsigned char byWait;
-
- unsigned char byOrg;
-
- VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
- /* turn off hardware retry for getting NACK */
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY)));
- for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) {
- VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID);
- VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset);
- VNSvOutPortB(dwIoBase + MAC_REG_I2MDOPT, byData);
-
- /* issue write command */
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMW);
- /* wait DONE be set */
- for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) {
- VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
- if (byWait & (I2MCSR_DONE | I2MCSR_NACK))
- break;
- PCAvDelayByIO(CB_DELAY_LOOP_WAIT);
- }
-
- if ((wDelay < W_MAX_TIMEOUT) &&
- ( !(byWait & I2MCSR_NACK))) {
- break;
- }
- }
- if (wNoACK == W_MAX_I2CRETRY) {
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- return false;
- }
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- return true;
+ unsigned short wDelay, wNoACK;
+ unsigned char byWait;
+
+ unsigned char byOrg;
+
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
+ /* turn off hardware retry for getting NACK */
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg & (~I2MCFG_NORETRY)));
+ for (wNoACK = 0; wNoACK < W_MAX_I2CRETRY; wNoACK++) {
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MTGID, EEP_I2C_DEV_ID);
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MTGAD, byContntOffset);
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MDOPT, byData);
+
+ /* issue write command */
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCSR, I2MCSR_EEMW);
+ /* wait DONE be set */
+ for (wDelay = 0; wDelay < W_MAX_TIMEOUT; wDelay++) {
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
+ if (byWait & (I2MCSR_DONE | I2MCSR_NACK))
+ break;
+ PCAvDelayByIO(CB_DELAY_LOOP_WAIT);
+ }
+
+ if ((wDelay < W_MAX_TIMEOUT) &&
+ (!(byWait & I2MCSR_NACK))) {
+ break;
+ }
+ }
+ if (wNoACK == W_MAX_I2CRETRY) {
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
+ return false;
+ }
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
+ return true;
}
-
/*
* Description: Turn bits on in eeprom
*
@@ -180,13 +175,12 @@ bool SROMbWriteEmbedded(unsigned long dwIoBase, unsigned char byContntOffset, un
*/
void SROMvRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- SROMbWriteEmbedded(dwIoBase, byContntOffset,(unsigned char)(byOrgData | byBits));
+ byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
+ SROMbWriteEmbedded(dwIoBase, byContntOffset, (unsigned char)(byOrgData | byBits));
}
-
/*
* Description: Turn bits off in eeprom
*
@@ -201,13 +195,12 @@ void SROMvRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsign
*/
void SROMvRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- SROMbWriteEmbedded(dwIoBase, byContntOffset,(unsigned char)(byOrgData & (~byBits)));
+ byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
+ SROMbWriteEmbedded(dwIoBase, byContntOffset, (unsigned char)(byOrgData & (~byBits)));
}
-
/*
* Description: Test if bits on in eeprom
*
@@ -224,13 +217,12 @@ void SROMvRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsig
*/
bool SROMbIsRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- return (byOrgData & byTestBits) == byTestBits;
+ byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
+ return (byOrgData & byTestBits) == byTestBits;
}
-
/*
* Description: Test if bits off in eeprom
*
@@ -247,13 +239,12 @@ bool SROMbIsRegBitsOn(unsigned long dwIoBase, unsigned char byContntOffset, unsi
*/
bool SROMbIsRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, unsigned char byTestBits)
{
- unsigned char byOrgData;
+ unsigned char byOrgData;
- byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
- return !(byOrgData & byTestBits);
+ byOrgData = SROMbyReadEmbedded(dwIoBase, byContntOffset);
+ return !(byOrgData & byTestBits);
}
-
/*
* Description: Read all contents of eeprom to buffer
*
@@ -268,16 +259,15 @@ bool SROMbIsRegBitsOff(unsigned long dwIoBase, unsigned char byContntOffset, uns
*/
void SROMvReadAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
{
- int ii;
+ int ii;
- /* ii = Rom Address */
- for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
- *pbyEepromRegs = SROMbyReadEmbedded(dwIoBase,(unsigned char) ii);
- pbyEepromRegs++;
- }
+ /* ii = Rom Address */
+ for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
+ *pbyEepromRegs = SROMbyReadEmbedded(dwIoBase, (unsigned char)ii);
+ pbyEepromRegs++;
+ }
}
-
/*
* Description: Write all contents of buffer to eeprom
*
@@ -293,16 +283,15 @@ void SROMvReadAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
*/
void SROMvWriteAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
{
- int ii;
+ int ii;
- /* ii = Rom Address */
- for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
- SROMbWriteEmbedded(dwIoBase,(unsigned char) ii, *pbyEepromRegs);
- pbyEepromRegs++;
- }
+ /* ii = Rom Address */
+ for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
+ SROMbWriteEmbedded(dwIoBase, (unsigned char)ii, *pbyEepromRegs);
+ pbyEepromRegs++;
+ }
}
-
/*
* Description: Read Ethernet Address from eeprom to buffer
*
@@ -317,16 +306,15 @@ void SROMvWriteAllContents(unsigned long dwIoBase, unsigned char *pbyEepromRegs)
*/
void SROMvReadEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress)
{
- unsigned char ii;
+ unsigned char ii;
- /* ii = Rom Address */
- for (ii = 0; ii < ETH_ALEN; ii++) {
- *pbyEtherAddress = SROMbyReadEmbedded(dwIoBase, ii);
- pbyEtherAddress++;
- }
+ /* ii = Rom Address */
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ *pbyEtherAddress = SROMbyReadEmbedded(dwIoBase, ii);
+ pbyEtherAddress++;
+ }
}
-
/*
* Description: Write Ethernet Address from buffer to eeprom
*
@@ -342,16 +330,15 @@ void SROMvReadEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddres
*/
void SROMvWriteEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddress)
{
- unsigned char ii;
+ unsigned char ii;
- /* ii = Rom Address */
- for (ii = 0; ii < ETH_ALEN; ii++) {
- SROMbWriteEmbedded(dwIoBase, ii, *pbyEtherAddress);
- pbyEtherAddress++;
- }
+ /* ii = Rom Address */
+ for (ii = 0; ii < ETH_ALEN; ii++) {
+ SROMbWriteEmbedded(dwIoBase, ii, *pbyEtherAddress);
+ pbyEtherAddress++;
+ }
}
-
/*
* Description: Read Sub_VID and Sub_SysId from eeprom to buffer
*
@@ -366,15 +353,15 @@ void SROMvWriteEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddre
*/
void SROMvReadSubSysVenId(unsigned long dwIoBase, unsigned long *pdwSubSysVenId)
{
- unsigned char *pbyData;
-
- pbyData = (unsigned char *)pdwSubSysVenId;
- /* sub vendor */
- *pbyData = SROMbyReadEmbedded(dwIoBase, 6);
- *(pbyData+1) = SROMbyReadEmbedded(dwIoBase, 7);
- /* sub system */
- *(pbyData+2) = SROMbyReadEmbedded(dwIoBase, 8);
- *(pbyData+3) = SROMbyReadEmbedded(dwIoBase, 9);
+ unsigned char *pbyData;
+
+ pbyData = (unsigned char *)pdwSubSysVenId;
+ /* sub vendor */
+ *pbyData = SROMbyReadEmbedded(dwIoBase, 6);
+ *(pbyData+1) = SROMbyReadEmbedded(dwIoBase, 7);
+ /* sub system */
+ *(pbyData+2) = SROMbyReadEmbedded(dwIoBase, 8);
+ *(pbyData+3) = SROMbyReadEmbedded(dwIoBase, 9);
}
/*
@@ -391,30 +378,28 @@ void SROMvReadSubSysVenId(unsigned long dwIoBase, unsigned long *pdwSubSysVenId)
*/
bool SROMbAutoLoad(unsigned long dwIoBase)
{
- unsigned char byWait;
- int ii;
+ unsigned char byWait;
+ int ii;
- unsigned char byOrg;
+ unsigned char byOrg;
- VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
- /* turn on hardware retry */
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg | I2MCFG_NORETRY));
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCFG, &byOrg);
+ /* turn on hardware retry */
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, (byOrg | I2MCFG_NORETRY));
- MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD);
+ MACvRegBitsOn(dwIoBase, MAC_REG_I2MCSR, I2MCSR_AUTOLD);
- /* ii = Rom Address */
- for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
- MACvTimer0MicroSDelay(dwIoBase, CB_EEPROM_READBYTE_WAIT);
- VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
- if ( !(byWait & I2MCSR_AUTOLD))
- break;
- }
+ /* ii = Rom Address */
+ for (ii = 0; ii < EEP_MAX_CONTEXT_SIZE; ii++) {
+ MACvTimer0MicroSDelay(dwIoBase, CB_EEPROM_READBYTE_WAIT);
+ VNSvInPortB(dwIoBase + MAC_REG_I2MCSR, &byWait);
+ if (!(byWait & I2MCSR_AUTOLD))
+ break;
+ }
- VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
+ VNSvOutPortB(dwIoBase + MAC_REG_I2MCFG, byOrg);
- if (ii == EEP_MAX_CONTEXT_SIZE)
- return false;
- return true;
+ if (ii == EEP_MAX_CONTEXT_SIZE)
+ return false;
+ return true;
}
-
-
diff --git a/drivers/staging/vt6655/srom.h b/drivers/staging/vt6655/srom.h
index 4c261dac01b5..1df58c516ddc 100644
--- a/drivers/staging/vt6655/srom.h
+++ b/drivers/staging/vt6655/srom.h
@@ -69,7 +69,6 @@
//}}
#define EEP_OFS_OFDMA_PWR_dBm 0xD2
-
//----------need to remove --------------------
#define EEP_OFS_BBTAB_LEN 0x70 // BB Table Length
#define EEP_OFS_BBTAB_ADR 0x71 // BB Table Offset
@@ -77,7 +76,6 @@
#define EEP_I2C_DEV_ID 0x50 // EEPROM device address on the I2C bus
-
//
// Bits in EEP_OFS_ANTENNA
//
@@ -97,34 +95,34 @@
// 2048 bits = 256 bytes = 128 words
//
typedef struct tagSSromReg {
- unsigned char abyPAR[6]; // 0x00 (unsigned short)
-
- unsigned short wSUB_VID; // 0x03 (unsigned short)
- unsigned short wSUB_SID;
-
- unsigned char byBCFG0; // 0x05 (unsigned short)
- unsigned char byBCFG1;
-
- unsigned char byFCR0; // 0x06 (unsigned short)
- unsigned char byFCR1;
- unsigned char byPMC0; // 0x07 (unsigned short)
- unsigned char byPMC1;
- unsigned char byMAXLAT; // 0x08 (unsigned short)
- unsigned char byMINGNT;
- unsigned char byCFG0; // 0x09 (unsigned short)
- unsigned char byCFG1;
- unsigned short wCISPTR; // 0x0A (unsigned short)
- unsigned short wRsv0; // 0x0B (unsigned short)
- unsigned short wRsv1; // 0x0C (unsigned short)
- unsigned char byBBPAIR; // 0x0D (unsigned short)
- unsigned char byRFTYPE;
- unsigned char byMinChannel; // 0x0E (unsigned short)
- unsigned char byMaxChannel;
- unsigned char bySignature; // 0x0F (unsigned short)
- unsigned char byCheckSum;
-
- unsigned char abyReserved0[96]; // 0x10 (unsigned short)
- unsigned char abyCIS[128]; // 0x80 (unsigned short)
+ unsigned char abyPAR[6]; // 0x00 (unsigned short)
+
+ unsigned short wSUB_VID; // 0x03 (unsigned short)
+ unsigned short wSUB_SID;
+
+ unsigned char byBCFG0; // 0x05 (unsigned short)
+ unsigned char byBCFG1;
+
+ unsigned char byFCR0; // 0x06 (unsigned short)
+ unsigned char byFCR1;
+ unsigned char byPMC0; // 0x07 (unsigned short)
+ unsigned char byPMC1;
+ unsigned char byMAXLAT; // 0x08 (unsigned short)
+ unsigned char byMINGNT;
+ unsigned char byCFG0; // 0x09 (unsigned short)
+ unsigned char byCFG1;
+ unsigned short wCISPTR; // 0x0A (unsigned short)
+ unsigned short wRsv0; // 0x0B (unsigned short)
+ unsigned short wRsv1; // 0x0C (unsigned short)
+ unsigned char byBBPAIR; // 0x0D (unsigned short)
+ unsigned char byRFTYPE;
+ unsigned char byMinChannel; // 0x0E (unsigned short)
+ unsigned char byMaxChannel;
+ unsigned char bySignature; // 0x0F (unsigned short)
+ unsigned char byCheckSum;
+
+ unsigned char abyReserved0[96]; // 0x10 (unsigned short)
+ unsigned char abyCIS[128]; // 0x80 (unsigned short)
} SSromReg, *PSSromReg;
/*--------------------- Export Macros ------------------------------*/
@@ -152,6 +150,6 @@ void SROMvWriteEtherAddress(unsigned long dwIoBase, unsigned char *pbyEtherAddre
void SROMvReadSubSysVenId(unsigned long dwIoBase, unsigned long *pdwSubSysVenId);
-bool SROMbAutoLoad (unsigned long dwIoBase);
+bool SROMbAutoLoad(unsigned long dwIoBase);
#endif // __EEPROM_H__
diff --git a/drivers/staging/vt6655/tcrc.c b/drivers/staging/vt6655/tcrc.c
index 1313c4cd0860..ed6868a9c16e 100644
--- a/drivers/staging/vt6655/tcrc.c
+++ b/drivers/staging/vt6655/tcrc.c
@@ -43,79 +43,76 @@
// 32-bit CRC table
static const unsigned long s_adwCrc32Table[256] = {
- 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
- 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
- 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
- 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
- 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
- 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
- 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
- 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
- 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
- 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
- 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
- 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
- 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
- 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
- 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
- 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
- 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
- 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
- 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
- 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
- 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
- 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
- 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
- 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
- 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
- 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
- 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
- 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
- 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
- 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
- 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
- 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
- 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
- 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
- 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
- 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
- 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
- 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
- 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
- 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
- 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
- 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
- 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
- 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
- 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
- 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
- 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
- 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
- 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
- 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
- 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
- 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
- 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
- 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
- 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
- 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
- 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
- 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
- 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
- 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
- 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
- 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
- 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
- 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
+ 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
+ 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
+ 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
+ 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
+ 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
+ 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
+ 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
+ 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
+ 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
+ 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
+ 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
+ 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
+ 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
+ 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
+ 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
+ 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
+ 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
+ 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
+ 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
+ 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
+ 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
+ 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
+ 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
+ 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
+ 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
+ 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
+ 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
+ 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
+ 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
+ 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
+ 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
+ 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
+ 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
+ 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
+ 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
+ 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
+ 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
+ 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
+ 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
+ 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
+ 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
+ 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
+ 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
+ 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
+ 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
+ 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
+ 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
+ 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
+ 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
+ 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
+ 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
+ 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
+ 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
+ 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
+ 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
+ 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
+ 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
+ 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
+ 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
+ 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
+ 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
+ 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
+ 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
+ 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
};
/*--------------------- Static Functions --------------------------*/
/*--------------------- Export Variables --------------------------*/
-
-
-
/*+
*
* Description:
@@ -131,21 +128,20 @@ static const unsigned long s_adwCrc32Table[256] = {
*
* Return Value: CRC-32
*
--*/
-unsigned long CRCdwCrc32 (unsigned char *pbyData, unsigned int cbByte, unsigned long dwCrcSeed)
+ -*/
+unsigned long CRCdwCrc32(unsigned char *pbyData, unsigned int cbByte, unsigned long dwCrcSeed)
{
- unsigned long dwCrc;
+ unsigned long dwCrc;
- dwCrc = dwCrcSeed;
- while (cbByte--) {
- dwCrc = s_adwCrc32Table[(unsigned char)((dwCrc ^ (*pbyData)) & 0xFF)] ^ (dwCrc >> 8);
- pbyData++;
- }
+ dwCrc = dwCrcSeed;
+ while (cbByte--) {
+ dwCrc = s_adwCrc32Table[(unsigned char)((dwCrc ^ (*pbyData)) & 0xFF)] ^ (dwCrc >> 8);
+ pbyData++;
+ }
- return dwCrc;
+ return dwCrc;
}
-
/*+
*
* Description:
@@ -163,13 +159,12 @@ unsigned long CRCdwCrc32 (unsigned char *pbyData, unsigned int cbByte, unsigned
*
* Return Value: CRC-32
*
--*/
-unsigned long CRCdwGetCrc32 (unsigned char *pbyData, unsigned int cbByte)
+ -*/
+unsigned long CRCdwGetCrc32(unsigned char *pbyData, unsigned int cbByte)
{
- return ~CRCdwCrc32(pbyData, cbByte, 0xFFFFFFFFL);
+ return ~CRCdwCrc32(pbyData, cbByte, 0xFFFFFFFFL);
}
-
/*+
*
* Description:
@@ -189,10 +184,8 @@ unsigned long CRCdwGetCrc32 (unsigned char *pbyData, unsigned int cbByte)
*
* Return Value: CRC-32
*
--*/
+ -*/
unsigned long CRCdwGetCrc32Ex(unsigned char *pbyData, unsigned int cbByte, unsigned long dwPreCRC)
{
- return CRCdwCrc32(pbyData, cbByte, dwPreCRC);
+ return CRCdwCrc32(pbyData, cbByte, dwPreCRC);
}
-
-
diff --git a/drivers/staging/vt6655/tcrc.h b/drivers/staging/vt6655/tcrc.h
index a2044212d1c9..82b5ddafae55 100644
--- a/drivers/staging/vt6655/tcrc.h
+++ b/drivers/staging/vt6655/tcrc.h
@@ -48,6 +48,3 @@ unsigned long CRCdwGetCrc32(unsigned char *pbyData, unsigned int cbByte);
unsigned long CRCdwGetCrc32Ex(unsigned char *pbyData, unsigned int cbByte, unsigned long dwPreCRC);
#endif // __TCRC_H__
-
-
-
diff --git a/drivers/staging/vt6655/tether.c b/drivers/staging/vt6655/tether.c
index 28554bf75549..a5dc3c09cfd7 100644
--- a/drivers/staging/vt6655/tether.c
+++ b/drivers/staging/vt6655/tether.c
@@ -47,8 +47,6 @@
/*--------------------- Export Variables --------------------------*/
-
-
/*
* Description: Calculate multicast hash value by CRC32
*
@@ -61,28 +59,27 @@
* Return Value: Hash value
*
*/
-unsigned char ETHbyGetHashIndexByCrc32 (unsigned char *pbyMultiAddr)
+unsigned char ETHbyGetHashIndexByCrc32(unsigned char *pbyMultiAddr)
{
- int ii;
- unsigned char byTmpHash;
- unsigned char byHash = 0;
+ int ii;
+ unsigned char byTmpHash;
+ unsigned char byHash = 0;
- // get the least 6-bits from CRC generator
- byTmpHash = (unsigned char)(CRCdwCrc32(pbyMultiAddr, ETH_ALEN,
- 0xFFFFFFFFL) & 0x3F);
- // reverse most bit to least bit
- for (ii = 0; ii < (sizeof(byTmpHash) * 8); ii++) {
- byHash <<= 1;
- if (byTmpHash & 0x01)
- byHash |= 1;
- byTmpHash >>= 1;
- }
+ // get the least 6-bits from CRC generator
+ byTmpHash = (unsigned char)(CRCdwCrc32(pbyMultiAddr, ETH_ALEN,
+ 0xFFFFFFFFL) & 0x3F);
+ // reverse most bit to least bit
+ for (ii = 0; ii < (sizeof(byTmpHash) * 8); ii++) {
+ byHash <<= 1;
+ if (byTmpHash & 0x01)
+ byHash |= 1;
+ byTmpHash >>= 1;
+ }
- // adjust 6-bits to the right most
- return (byHash >> 2);
+ // adjust 6-bits to the right most
+ return byHash >> 2;
}
-
/*
* Description: Check CRC value of the buffer if Ok or not
*
@@ -96,14 +93,13 @@ unsigned char ETHbyGetHashIndexByCrc32 (unsigned char *pbyMultiAddr)
* Return Value: true if ok; false if error.
*
*/
-bool ETHbIsBufferCrc32Ok (unsigned char *pbyBuffer, unsigned int cbFrameLength)
+bool ETHbIsBufferCrc32Ok(unsigned char *pbyBuffer, unsigned int cbFrameLength)
{
- unsigned long dwCRC;
+ unsigned long dwCRC;
- dwCRC = CRCdwGetCrc32(pbyBuffer, cbFrameLength - 4);
- if (cpu_to_le32(*((unsigned long *)(pbyBuffer + cbFrameLength - 4))) != dwCRC) {
- return false;
- }
- return true;
+ dwCRC = CRCdwGetCrc32(pbyBuffer, cbFrameLength - 4);
+ if (cpu_to_le32(*((unsigned long *)(pbyBuffer + cbFrameLength - 4))) != dwCRC) {
+ return false;
+ }
+ return true;
}
-
diff --git a/drivers/staging/vt6655/tether.h b/drivers/staging/vt6655/tether.h
index 6a68f97d9a32..94cc8830d8cc 100644
--- a/drivers/staging/vt6655/tether.h
+++ b/drivers/staging/vt6655/tether.h
@@ -37,13 +37,12 @@
// constants
//
#define U_ETHER_ADDR_STR_LEN (ETH_ALEN * 2 + 1)
- // Ethernet address string length
+// Ethernet address string length
#define MAX_LOOKAHEAD_SIZE ETH_FRAME_LEN
#define U_MULTI_ADDR_LEN 8 // multicast address length
-
#ifdef __BIG_ENDIAN
#define TYPE_PKT_IP 0x0800 //
@@ -89,7 +88,6 @@
#define TYPE_CTL_CTS 0xc400
#define TYPE_CTL_ACK 0xd400
-
#else //if LITTLE_ENDIAN
//
// wType field in the SEthernetHeader
@@ -140,8 +138,6 @@
#define TYPE_CTL_CTS 0x00c4
#define TYPE_CTL_ACK 0x00d4
-
-
#endif //#ifdef __BIG_ENDIAN
#define WEP_IV_MASK 0x00FFFFFF
@@ -151,35 +147,34 @@
// Ethernet packet
//
typedef struct tagSEthernetHeader {
- unsigned char abyDstAddr[ETH_ALEN];
- unsigned char abySrcAddr[ETH_ALEN];
- unsigned short wType;
-}__attribute__ ((__packed__))
+ unsigned char abyDstAddr[ETH_ALEN];
+ unsigned char abySrcAddr[ETH_ALEN];
+ unsigned short wType;
+} __attribute__ ((__packed__))
SEthernetHeader, *PSEthernetHeader;
-
//
// 802_3 packet
//
typedef struct tagS802_3Header {
- unsigned char abyDstAddr[ETH_ALEN];
- unsigned char abySrcAddr[ETH_ALEN];
- unsigned short wLen;
-}__attribute__ ((__packed__))
+ unsigned char abyDstAddr[ETH_ALEN];
+ unsigned char abySrcAddr[ETH_ALEN];
+ unsigned short wLen;
+} __attribute__ ((__packed__))
S802_3Header, *PS802_3Header;
//
// 802_11 packet
//
typedef struct tagS802_11Header {
- unsigned short wFrameCtl;
- unsigned short wDurationID;
- unsigned char abyAddr1[ETH_ALEN];
- unsigned char abyAddr2[ETH_ALEN];
- unsigned char abyAddr3[ETH_ALEN];
- unsigned short wSeqCtl;
- unsigned char abyAddr4[ETH_ALEN];
-}__attribute__ ((__packed__))
+ unsigned short wFrameCtl;
+ unsigned short wDurationID;
+ unsigned char abyAddr1[ETH_ALEN];
+ unsigned char abyAddr2[ETH_ALEN];
+ unsigned char abyAddr3[ETH_ALEN];
+ unsigned short wSeqCtl;
+ unsigned char abyAddr4[ETH_ALEN];
+} __attribute__ ((__packed__))
S802_11Header, *PS802_11Header;
/*--------------------- Export Macros ------------------------------*/
@@ -195,6 +190,3 @@ unsigned char ETHbyGetHashIndexByCrc32(unsigned char *pbyMultiAddr);
bool ETHbIsBufferCrc32Ok(unsigned char *pbyBuffer, unsigned int cbFrameLength);
#endif // __TETHER_H__
-
-
-
diff --git a/drivers/staging/vt6655/tkip.c b/drivers/staging/vt6655/tkip.c
index f141ba1cbb9b..b3e087e19034 100644
--- a/drivers/staging/vt6655/tkip.c
+++ b/drivers/staging/vt6655/tkip.c
@@ -56,76 +56,75 @@
/* bytes swapped. To allow an endian tolerant implementation, the byte */
/* halves have been expressed independently here. */
const unsigned char TKIP_Sbox_Lower[256] = {
- 0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54,
- 0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A,
- 0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B,
- 0xEC,0x67,0xFD,0xEA,0xBF,0xF7,0x96,0x5B,
- 0xC2,0x1C,0xAE,0x6A,0x5A,0x41,0x02,0x4F,
- 0x5C,0xF4,0x34,0x08,0x93,0x73,0x53,0x3F,
- 0x0C,0x52,0x65,0x5E,0x28,0xA1,0x0F,0xB5,
- 0x09,0x36,0x9B,0x3D,0x26,0x69,0xCD,0x9F,
- 0x1B,0x9E,0x74,0x2E,0x2D,0xB2,0xEE,0xFB,
- 0xF6,0x4D,0x61,0xCE,0x7B,0x3E,0x71,0x97,
- 0xF5,0x68,0x00,0x2C,0x60,0x1F,0xC8,0xED,
- 0xBE,0x46,0xD9,0x4B,0xDE,0xD4,0xE8,0x4A,
- 0x6B,0x2A,0xE5,0x16,0xC5,0xD7,0x55,0x94,
- 0xCF,0x10,0x06,0x81,0xF0,0x44,0xBA,0xE3,
- 0xF3,0xFE,0xC0,0x8A,0xAD,0xBC,0x48,0x04,
- 0xDF,0xC1,0x75,0x63,0x30,0x1A,0x0E,0x6D,
- 0x4C,0x14,0x35,0x2F,0xE1,0xA2,0xCC,0x39,
- 0x57,0xF2,0x82,0x47,0xAC,0xE7,0x2B,0x95,
- 0xA0,0x98,0xD1,0x7F,0x66,0x7E,0xAB,0x83,
- 0xCA,0x29,0xD3,0x3C,0x79,0xE2,0x1D,0x76,
- 0x3B,0x56,0x4E,0x1E,0xDB,0x0A,0x6C,0xE4,
- 0x5D,0x6E,0xEF,0xA6,0xA8,0xA4,0x37,0x8B,
- 0x32,0x43,0x59,0xB7,0x8C,0x64,0xD2,0xE0,
- 0xB4,0xFA,0x07,0x25,0xAF,0x8E,0xE9,0x18,
- 0xD5,0x88,0x6F,0x72,0x24,0xF1,0xC7,0x51,
- 0x23,0x7C,0x9C,0x21,0xDD,0xDC,0x86,0x85,
- 0x90,0x42,0xC4,0xAA,0xD8,0x05,0x01,0x12,
- 0xA3,0x5F,0xF9,0xD0,0x91,0x58,0x27,0xB9,
- 0x38,0x13,0xB3,0x33,0xBB,0x70,0x89,0xA7,
- 0xB6,0x22,0x92,0x20,0x49,0xFF,0x78,0x7A,
- 0x8F,0xF8,0x80,0x17,0xDA,0x31,0xC6,0xB8,
- 0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A
+ 0xA5, 0x84, 0x99, 0x8D, 0x0D, 0xBD, 0xB1, 0x54,
+ 0x50, 0x03, 0xA9, 0x7D, 0x19, 0x62, 0xE6, 0x9A,
+ 0x45, 0x9D, 0x40, 0x87, 0x15, 0xEB, 0xC9, 0x0B,
+ 0xEC, 0x67, 0xFD, 0xEA, 0xBF, 0xF7, 0x96, 0x5B,
+ 0xC2, 0x1C, 0xAE, 0x6A, 0x5A, 0x41, 0x02, 0x4F,
+ 0x5C, 0xF4, 0x34, 0x08, 0x93, 0x73, 0x53, 0x3F,
+ 0x0C, 0x52, 0x65, 0x5E, 0x28, 0xA1, 0x0F, 0xB5,
+ 0x09, 0x36, 0x9B, 0x3D, 0x26, 0x69, 0xCD, 0x9F,
+ 0x1B, 0x9E, 0x74, 0x2E, 0x2D, 0xB2, 0xEE, 0xFB,
+ 0xF6, 0x4D, 0x61, 0xCE, 0x7B, 0x3E, 0x71, 0x97,
+ 0xF5, 0x68, 0x00, 0x2C, 0x60, 0x1F, 0xC8, 0xED,
+ 0xBE, 0x46, 0xD9, 0x4B, 0xDE, 0xD4, 0xE8, 0x4A,
+ 0x6B, 0x2A, 0xE5, 0x16, 0xC5, 0xD7, 0x55, 0x94,
+ 0xCF, 0x10, 0x06, 0x81, 0xF0, 0x44, 0xBA, 0xE3,
+ 0xF3, 0xFE, 0xC0, 0x8A, 0xAD, 0xBC, 0x48, 0x04,
+ 0xDF, 0xC1, 0x75, 0x63, 0x30, 0x1A, 0x0E, 0x6D,
+ 0x4C, 0x14, 0x35, 0x2F, 0xE1, 0xA2, 0xCC, 0x39,
+ 0x57, 0xF2, 0x82, 0x47, 0xAC, 0xE7, 0x2B, 0x95,
+ 0xA0, 0x98, 0xD1, 0x7F, 0x66, 0x7E, 0xAB, 0x83,
+ 0xCA, 0x29, 0xD3, 0x3C, 0x79, 0xE2, 0x1D, 0x76,
+ 0x3B, 0x56, 0x4E, 0x1E, 0xDB, 0x0A, 0x6C, 0xE4,
+ 0x5D, 0x6E, 0xEF, 0xA6, 0xA8, 0xA4, 0x37, 0x8B,
+ 0x32, 0x43, 0x59, 0xB7, 0x8C, 0x64, 0xD2, 0xE0,
+ 0xB4, 0xFA, 0x07, 0x25, 0xAF, 0x8E, 0xE9, 0x18,
+ 0xD5, 0x88, 0x6F, 0x72, 0x24, 0xF1, 0xC7, 0x51,
+ 0x23, 0x7C, 0x9C, 0x21, 0xDD, 0xDC, 0x86, 0x85,
+ 0x90, 0x42, 0xC4, 0xAA, 0xD8, 0x05, 0x01, 0x12,
+ 0xA3, 0x5F, 0xF9, 0xD0, 0x91, 0x58, 0x27, 0xB9,
+ 0x38, 0x13, 0xB3, 0x33, 0xBB, 0x70, 0x89, 0xA7,
+ 0xB6, 0x22, 0x92, 0x20, 0x49, 0xFF, 0x78, 0x7A,
+ 0x8F, 0xF8, 0x80, 0x17, 0xDA, 0x31, 0xC6, 0xB8,
+ 0xC3, 0xB0, 0x77, 0x11, 0xCB, 0xFC, 0xD6, 0x3A
};
const unsigned char TKIP_Sbox_Upper[256] = {
- 0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91,
- 0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC,
- 0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB,
- 0x41,0xB3,0x5F,0x45,0x23,0x53,0xE4,0x9B,
- 0x75,0xE1,0x3D,0x4C,0x6C,0x7E,0xF5,0x83,
- 0x68,0x51,0xD1,0xF9,0xE2,0xAB,0x62,0x2A,
- 0x08,0x95,0x46,0x9D,0x30,0x37,0x0A,0x2F,
- 0x0E,0x24,0x1B,0xDF,0xCD,0x4E,0x7F,0xEA,
- 0x12,0x1D,0x58,0x34,0x36,0xDC,0xB4,0x5B,
- 0xA4,0x76,0xB7,0x7D,0x52,0xDD,0x5E,0x13,
- 0xA6,0xB9,0x00,0xC1,0x40,0xE3,0x79,0xB6,
- 0xD4,0x8D,0x67,0x72,0x94,0x98,0xB0,0x85,
- 0xBB,0xC5,0x4F,0xED,0x86,0x9A,0x66,0x11,
- 0x8A,0xE9,0x04,0xFE,0xA0,0x78,0x25,0x4B,
- 0xA2,0x5D,0x80,0x05,0x3F,0x21,0x70,0xF1,
- 0x63,0x77,0xAF,0x42,0x20,0xE5,0xFD,0xBF,
- 0x81,0x18,0x26,0xC3,0xBE,0x35,0x88,0x2E,
- 0x93,0x55,0xFC,0x7A,0xC8,0xBA,0x32,0xE6,
- 0xC0,0x19,0x9E,0xA3,0x44,0x54,0x3B,0x0B,
- 0x8C,0xC7,0x6B,0x28,0xA7,0xBC,0x16,0xAD,
- 0xDB,0x64,0x74,0x14,0x92,0x0C,0x48,0xB8,
- 0x9F,0xBD,0x43,0xC4,0x39,0x31,0xD3,0xF2,
- 0xD5,0x8B,0x6E,0xDA,0x01,0xB1,0x9C,0x49,
- 0xD8,0xAC,0xF3,0xCF,0xCA,0xF4,0x47,0x10,
- 0x6F,0xF0,0x4A,0x5C,0x38,0x57,0x73,0x97,
- 0xCB,0xA1,0xE8,0x3E,0x96,0x61,0x0D,0x0F,
- 0xE0,0x7C,0x71,0xCC,0x90,0x06,0xF7,0x1C,
- 0xC2,0x6A,0xAE,0x69,0x17,0x99,0x3A,0x27,
- 0xD9,0xEB,0x2B,0x22,0xD2,0xA9,0x07,0x33,
- 0x2D,0x3C,0x15,0xC9,0x87,0xAA,0x50,0xA5,
- 0x03,0x59,0x09,0x1A,0x65,0xD7,0x84,0xD0,
- 0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C
+ 0xC6, 0xF8, 0xEE, 0xF6, 0xFF, 0xD6, 0xDE, 0x91,
+ 0x60, 0x02, 0xCE, 0x56, 0xE7, 0xB5, 0x4D, 0xEC,
+ 0x8F, 0x1F, 0x89, 0xFA, 0xEF, 0xB2, 0x8E, 0xFB,
+ 0x41, 0xB3, 0x5F, 0x45, 0x23, 0x53, 0xE4, 0x9B,
+ 0x75, 0xE1, 0x3D, 0x4C, 0x6C, 0x7E, 0xF5, 0x83,
+ 0x68, 0x51, 0xD1, 0xF9, 0xE2, 0xAB, 0x62, 0x2A,
+ 0x08, 0x95, 0x46, 0x9D, 0x30, 0x37, 0x0A, 0x2F,
+ 0x0E, 0x24, 0x1B, 0xDF, 0xCD, 0x4E, 0x7F, 0xEA,
+ 0x12, 0x1D, 0x58, 0x34, 0x36, 0xDC, 0xB4, 0x5B,
+ 0xA4, 0x76, 0xB7, 0x7D, 0x52, 0xDD, 0x5E, 0x13,
+ 0xA6, 0xB9, 0x00, 0xC1, 0x40, 0xE3, 0x79, 0xB6,
+ 0xD4, 0x8D, 0x67, 0x72, 0x94, 0x98, 0xB0, 0x85,
+ 0xBB, 0xC5, 0x4F, 0xED, 0x86, 0x9A, 0x66, 0x11,
+ 0x8A, 0xE9, 0x04, 0xFE, 0xA0, 0x78, 0x25, 0x4B,
+ 0xA2, 0x5D, 0x80, 0x05, 0x3F, 0x21, 0x70, 0xF1,
+ 0x63, 0x77, 0xAF, 0x42, 0x20, 0xE5, 0xFD, 0xBF,
+ 0x81, 0x18, 0x26, 0xC3, 0xBE, 0x35, 0x88, 0x2E,
+ 0x93, 0x55, 0xFC, 0x7A, 0xC8, 0xBA, 0x32, 0xE6,
+ 0xC0, 0x19, 0x9E, 0xA3, 0x44, 0x54, 0x3B, 0x0B,
+ 0x8C, 0xC7, 0x6B, 0x28, 0xA7, 0xBC, 0x16, 0xAD,
+ 0xDB, 0x64, 0x74, 0x14, 0x92, 0x0C, 0x48, 0xB8,
+ 0x9F, 0xBD, 0x43, 0xC4, 0x39, 0x31, 0xD3, 0xF2,
+ 0xD5, 0x8B, 0x6E, 0xDA, 0x01, 0xB1, 0x9C, 0x49,
+ 0xD8, 0xAC, 0xF3, 0xCF, 0xCA, 0xF4, 0x47, 0x10,
+ 0x6F, 0xF0, 0x4A, 0x5C, 0x38, 0x57, 0x73, 0x97,
+ 0xCB, 0xA1, 0xE8, 0x3E, 0x96, 0x61, 0x0D, 0x0F,
+ 0xE0, 0x7C, 0x71, 0xCC, 0x90, 0x06, 0xF7, 0x1C,
+ 0xC2, 0x6A, 0xAE, 0x69, 0x17, 0x99, 0x3A, 0x27,
+ 0xD9, 0xEB, 0x2B, 0x22, 0xD2, 0xA9, 0x07, 0x33,
+ 0x2D, 0x3C, 0x15, 0xC9, 0x87, 0xAA, 0x50, 0xA5,
+ 0x03, 0x59, 0x09, 0x1A, 0x65, 0xD7, 0x84, 0xD0,
+ 0x82, 0x29, 0x5A, 0x1E, 0x7B, 0xA8, 0x6D, 0x2C
};
-
//STKIPKeyManagement sTKIPKeyTable[MAX_TKIP_KEY];
/*--------------------- Static Functions --------------------------*/
@@ -141,34 +140,32 @@ unsigned int rotr1(unsigned int a);
/************************************************************/
unsigned int tkip_sbox(unsigned int index)
{
- unsigned int index_low;
- unsigned int index_high;
- unsigned int left, right;
+ unsigned int index_low;
+ unsigned int index_high;
+ unsigned int left, right;
- index_low = (index % 256);
- index_high = ((index >> 8) % 256);
+ index_low = (index % 256);
+ index_high = ((index >> 8) % 256);
- left = TKIP_Sbox_Lower[index_low] + (TKIP_Sbox_Upper[index_low] * 256);
- right = TKIP_Sbox_Upper[index_high] + (TKIP_Sbox_Lower[index_high] * 256);
+ left = TKIP_Sbox_Lower[index_low] + (TKIP_Sbox_Upper[index_low] * 256);
+ right = TKIP_Sbox_Upper[index_high] + (TKIP_Sbox_Lower[index_high] * 256);
- return (left ^ right);
+ return left ^ right;
};
-
unsigned int rotr1(unsigned int a)
{
- unsigned int b;
-
- if ((a & 0x01) == 0x01) {
- b = (a >> 1) | 0x8000;
- } else {
- b = (a >> 1) & 0x7fff;
- }
- b = b % 65536;
- return b;
+ unsigned int b;
+
+ if ((a & 0x01) == 0x01) {
+ b = (a >> 1) | 0x8000;
+ } else {
+ b = (a >> 1) & 0x7fff;
+ }
+ b = b % 65536;
+ return b;
}
-
/*
* Description: Calculate RC4Key fom TK, TA, and TSC
*
@@ -184,89 +181,89 @@ unsigned int rotr1(unsigned int a)
*
*/
void TKIPvMixKey(
- unsigned char *pbyTKey,
- unsigned char *pbyTA,
- unsigned short wTSC15_0,
- unsigned long dwTSC47_16,
- unsigned char *pbyRC4Key
- )
+ unsigned char *pbyTKey,
+ unsigned char *pbyTA,
+ unsigned short wTSC15_0,
+ unsigned long dwTSC47_16,
+ unsigned char *pbyRC4Key
+)
{
- unsigned int p1k[5];
+ unsigned int p1k[5];
// unsigned int ttak0, ttak1, ttak2, ttak3, ttak4;
- unsigned int tsc0, tsc1, tsc2;
- unsigned int ppk0, ppk1, ppk2, ppk3, ppk4, ppk5;
- unsigned long int pnl,pnh;
-
- int i, j;
-
- pnl = wTSC15_0;
- pnh = dwTSC47_16;
-
- tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */
- tsc1 = (unsigned int)(pnh % 65536);
- tsc2 = (unsigned int)(pnl % 65536); /* lsb */
-
- /* Phase 1, step 1 */
- p1k[0] = tsc1;
- p1k[1] = tsc0;
- p1k[2] = (unsigned int)(pbyTA[0] + (pbyTA[1]*256));
- p1k[3] = (unsigned int)(pbyTA[2] + (pbyTA[3]*256));
- p1k[4] = (unsigned int)(pbyTA[4] + (pbyTA[5]*256));
-
- /* Phase 1, step 2 */
- for (i=0; i<8; i++) {
- j = 2*(i & 1);
- p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536 )) % 65536;
- p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536 )) % 65536;
- p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536 )) % 65536;
- p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536 )) % 65536;
- p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536 )) % 65536;
- p1k[4] = (p1k[4] + i) % 65536;
- }
- /* Phase 2, Step 1 */
- ppk0 = p1k[0];
- ppk1 = p1k[1];
- ppk2 = p1k[2];
- ppk3 = p1k[3];
- ppk4 = p1k[4];
- ppk5 = (p1k[4] + tsc2) % 65536;
-
- /* Phase2, Step 2 */
- ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
- ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
- ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
- ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
- ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
- ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
-
- ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
- ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
- ppk2 = ppk2 + rotr1(ppk1);
- ppk3 = ppk3 + rotr1(ppk2);
- ppk4 = ppk4 + rotr1(ppk3);
- ppk5 = ppk5 + rotr1(ppk4);
-
- /* Phase 2, Step 3 */
- pbyRC4Key[0] = (tsc2 >> 8) % 256;
- pbyRC4Key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f;
- pbyRC4Key[2] = tsc2 % 256;
- pbyRC4Key[3] = ((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) >> 1) % 256;
-
- pbyRC4Key[4] = ppk0 % 256;
- pbyRC4Key[5] = (ppk0 >> 8) % 256;
-
- pbyRC4Key[6] = ppk1 % 256;
- pbyRC4Key[7] = (ppk1 >> 8) % 256;
-
- pbyRC4Key[8] = ppk2 % 256;
- pbyRC4Key[9] = (ppk2 >> 8) % 256;
-
- pbyRC4Key[10] = ppk3 % 256;
- pbyRC4Key[11] = (ppk3 >> 8) % 256;
-
- pbyRC4Key[12] = ppk4 % 256;
- pbyRC4Key[13] = (ppk4 >> 8) % 256;
-
- pbyRC4Key[14] = ppk5 % 256;
- pbyRC4Key[15] = (ppk5 >> 8) % 256;
+ unsigned int tsc0, tsc1, tsc2;
+ unsigned int ppk0, ppk1, ppk2, ppk3, ppk4, ppk5;
+ unsigned long int pnl, pnh;
+
+ int i, j;
+
+ pnl = wTSC15_0;
+ pnh = dwTSC47_16;
+
+ tsc0 = (unsigned int)((pnh >> 16) % 65536); /* msb */
+ tsc1 = (unsigned int)(pnh % 65536);
+ tsc2 = (unsigned int)(pnl % 65536); /* lsb */
+
+ /* Phase 1, step 1 */
+ p1k[0] = tsc1;
+ p1k[1] = tsc0;
+ p1k[2] = (unsigned int)(pbyTA[0] + (pbyTA[1]*256));
+ p1k[3] = (unsigned int)(pbyTA[2] + (pbyTA[3]*256));
+ p1k[4] = (unsigned int)(pbyTA[4] + (pbyTA[5]*256));
+
+ /* Phase 1, step 2 */
+ for (i = 0; i < 8; i++) {
+ j = 2 * (i & 1);
+ p1k[0] = (p1k[0] + tkip_sbox((p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536)) % 65536;
+ p1k[1] = (p1k[1] + tkip_sbox((p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536)) % 65536;
+ p1k[2] = (p1k[2] + tkip_sbox((p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536)) % 65536;
+ p1k[3] = (p1k[3] + tkip_sbox((p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536)) % 65536;
+ p1k[4] = (p1k[4] + tkip_sbox((p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536)) % 65536;
+ p1k[4] = (p1k[4] + i) % 65536;
+ }
+ /* Phase 2, Step 1 */
+ ppk0 = p1k[0];
+ ppk1 = p1k[1];
+ ppk2 = p1k[2];
+ ppk3 = p1k[3];
+ ppk4 = p1k[4];
+ ppk5 = (p1k[4] + tsc2) % 65536;
+
+ /* Phase2, Step 2 */
+ ppk0 = ppk0 + tkip_sbox((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
+ ppk1 = ppk1 + tkip_sbox((ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
+ ppk2 = ppk2 + tkip_sbox((ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
+ ppk3 = ppk3 + tkip_sbox((ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
+ ppk4 = ppk4 + tkip_sbox((ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
+ ppk5 = ppk5 + tkip_sbox((ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
+
+ ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
+ ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
+ ppk2 = ppk2 + rotr1(ppk1);
+ ppk3 = ppk3 + rotr1(ppk2);
+ ppk4 = ppk4 + rotr1(ppk3);
+ ppk5 = ppk5 + rotr1(ppk4);
+
+ /* Phase 2, Step 3 */
+ pbyRC4Key[0] = (tsc2 >> 8) % 256;
+ pbyRC4Key[1] = (((tsc2 >> 8) % 256) | 0x20) & 0x7f;
+ pbyRC4Key[2] = tsc2 % 256;
+ pbyRC4Key[3] = ((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) >> 1) % 256;
+
+ pbyRC4Key[4] = ppk0 % 256;
+ pbyRC4Key[5] = (ppk0 >> 8) % 256;
+
+ pbyRC4Key[6] = ppk1 % 256;
+ pbyRC4Key[7] = (ppk1 >> 8) % 256;
+
+ pbyRC4Key[8] = ppk2 % 256;
+ pbyRC4Key[9] = (ppk2 >> 8) % 256;
+
+ pbyRC4Key[10] = ppk3 % 256;
+ pbyRC4Key[11] = (ppk3 >> 8) % 256;
+
+ pbyRC4Key[12] = ppk4 % 256;
+ pbyRC4Key[13] = (ppk4 >> 8) % 256;
+
+ pbyRC4Key[14] = ppk5 % 256;
+ pbyRC4Key[15] = (ppk5 >> 8) % 256;
}
diff --git a/drivers/staging/vt6655/tkip.h b/drivers/staging/vt6655/tkip.h
index eb5951d726e0..3b6357ac6dee 100644
--- a/drivers/staging/vt6655/tkip.h
+++ b/drivers/staging/vt6655/tkip.h
@@ -47,14 +47,11 @@
/*--------------------- Export Functions --------------------------*/
void TKIPvMixKey(
- unsigned char *pbyTKey,
- unsigned char *pbyTA,
- unsigned short wTSC15_0,
- unsigned long dwTSC47_16,
- unsigned char *pbyRC4Key
- );
+ unsigned char *pbyTKey,
+ unsigned char *pbyTA,
+ unsigned short wTSC15_0,
+ unsigned long dwTSC47_16,
+ unsigned char *pbyRC4Key
+);
#endif // __TKIP_H__
-
-
-
diff --git a/drivers/staging/vt6655/tmacro.h b/drivers/staging/vt6655/tmacro.h
index e8b177d4128b..59c6e72f993a 100644
--- a/drivers/staging/vt6655/tmacro.h
+++ b/drivers/staging/vt6655/tmacro.h
@@ -58,5 +58,3 @@
#endif
#endif // __TMACRO_H__
-
-
diff --git a/drivers/staging/vt6655/ttype.h b/drivers/staging/vt6655/ttype.h
index be223bd25d2c..b1d8ae732774 100644
--- a/drivers/staging/vt6655/ttype.h
+++ b/drivers/staging/vt6655/ttype.h
@@ -26,11 +26,9 @@
*
*/
-
#ifndef __TTYPE_H__
#define __TTYPE_H__
-
/******* Common definitions and typedefs ***********************************/
#ifndef TxInSleep
@@ -56,16 +54,16 @@
// an 8-byte-aligned 8 byte long structure
// which is NOT really a floating point number.
typedef union tagUQuadWord {
- struct {
- unsigned int dwLowDword;
- unsigned int dwHighDword;
- } u;
- double DoNotUseThisField;
+ struct {
+ unsigned int dwLowDword;
+ unsigned int dwHighDword;
+ } u;
+ double DoNotUseThisField;
} UQuadWord;
typedef UQuadWord QWORD; // 64-bit
/****** Common pointer types ***********************************************/
-typedef QWORD * PQWORD;
+typedef QWORD *PQWORD;
#endif // __TTYPE_H__
diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h
index 9596fdef0e3c..155e66439073 100644
--- a/drivers/staging/vt6655/upc.h
+++ b/drivers/staging/vt6655/upc.h
@@ -34,39 +34,35 @@
/*--------------------- Export Definitions -------------------------*/
-
//
// For IO mapped
//
#ifdef IO_MAP
-#define VNSvInPortB(dwIOAddress, pbyData) { \
- *(pbyData) = inb(dwIOAddress); \
-}
-
-
-#define VNSvInPortW(dwIOAddress, pwData) { \
- *(pwData) = inw(dwIOAddress); \
-}
-
-#define VNSvInPortD(dwIOAddress, pdwData) { \
- *(pdwData) = inl(dwIOAddress); \
-}
+#define VNSvInPortB(dwIOAddress, pbyData) \
+do { \
+ *(pbyData) = inb(dwIOAddress); \
+} while (0)
+#define VNSvInPortW(dwIOAddress, pwData) \
+do { \
+ *(pwData) = inw(dwIOAddress); \
+} while (0)
-#define VNSvOutPortB(dwIOAddress, byData) { \
- outb(byData, dwIOAddress); \
-}
+#define VNSvInPortD(dwIOAddress, pdwData) \
+do { \
+ *(pdwData) = inl(dwIOAddress); \
+} while (0)
+#define VNSvOutPortB(dwIOAddress, byData) \
+ outb(byData, dwIOAddress)
-#define VNSvOutPortW(dwIOAddress, wData) { \
- outw(wData, dwIOAddress); \
-}
+#define VNSvOutPortW(dwIOAddress, wData) \
+ outw(wData, dwIOAddress)
-#define VNSvOutPortD(dwIOAddress, dwData) { \
- outl(dwData, dwIOAddress); \
-}
+#define VNSvOutPortD(dwIOAddress, dwData) \
+ outl(dwData, dwIOAddress)
#else
@@ -74,84 +70,83 @@
// For memory mapped IO
//
-
-#define VNSvInPortB(dwIOAddress, pbyData) { \
- volatile unsigned char * pbyAddr = ((unsigned char *)(dwIOAddress)); \
- *(pbyData) = readb(pbyAddr); \
-}
-
-
-#define VNSvInPortW(dwIOAddress, pwData) { \
- volatile unsigned short *pwAddr = ((unsigned short *)(dwIOAddress)); \
- *(pwData) = readw(pwAddr); \
-}
-
-#define VNSvInPortD(dwIOAddress, pdwData) { \
- volatile unsigned long *pdwAddr = ((unsigned long *)(dwIOAddress)); \
- *(pdwData) = readl(pdwAddr); \
-}
-
-
-#define VNSvOutPortB(dwIOAddress, byData) { \
- volatile unsigned char * pbyAddr = ((unsigned char *)(dwIOAddress)); \
- writeb((unsigned char)byData, pbyAddr); \
-}
-
-
-#define VNSvOutPortW(dwIOAddress, wData) { \
- volatile unsigned short *pwAddr = ((unsigned short *)(dwIOAddress)); \
- writew((unsigned short)wData, pwAddr); \
-}
-
-#define VNSvOutPortD(dwIOAddress, dwData) { \
- volatile unsigned long *pdwAddr = ((unsigned long *)(dwIOAddress)); \
- writel((unsigned long)dwData, pdwAddr); \
-}
+#define VNSvInPortB(dwIOAddress, pbyData) \
+do { \
+ volatile unsigned char *pbyAddr = (unsigned char *)(dwIOAddress); \
+ *(pbyData) = readb(pbyAddr); \
+} while (0)
+
+#define VNSvInPortW(dwIOAddress, pwData) \
+do { \
+ volatile unsigned short *pwAddr = (unsigned short *)(dwIOAddress); \
+ *(pwData) = readw(pwAddr); \
+} while (0)
+
+#define VNSvInPortD(dwIOAddress, pdwData) \
+do { \
+ volatile unsigned long *pdwAddr = (unsigned long *)(dwIOAddress); \
+ *(pdwData) = readl(pdwAddr); \
+} while (0)
+
+#define VNSvOutPortB(dwIOAddress, byData) \
+do { \
+ volatile unsigned char *pbyAddr = (unsigned char *)(dwIOAddress); \
+ writeb((unsigned char)byData, pbyAddr); \
+} while (0)
+
+#define VNSvOutPortW(dwIOAddress, wData) \
+do { \
+ volatile unsigned short *pwAddr = ((unsigned short *)(dwIOAddress)); \
+ writew((unsigned short)wData, pwAddr); \
+} while (0)
+
+#define VNSvOutPortD(dwIOAddress, dwData) \
+do { \
+ volatile unsigned long *pdwAddr = (unsigned long *)(dwIOAddress); \
+ writel((unsigned long)dwData, pdwAddr); \
+} while (0)
#endif
-
//
// ALWAYS IO-Mapped IO when in 16-bit/32-bit environment
//
-#define PCBvInPortB(dwIOAddress, pbyData) { \
- *(pbyData) = inb(dwIOAddress); \
-}
-
-#define PCBvInPortW(dwIOAddress, pwData) { \
- *(pwData) = inw(dwIOAddress); \
-}
-
-#define PCBvInPortD(dwIOAddress, pdwData) { \
- *(pdwData) = inl(dwIOAddress); \
-}
-
-#define PCBvOutPortB(dwIOAddress, byData) { \
- outb(byData, dwIOAddress); \
-}
-
-#define PCBvOutPortW(dwIOAddress, wData) { \
- outw(wData, dwIOAddress); \
-}
-
-#define PCBvOutPortD(dwIOAddress, dwData) { \
- outl(dwData, dwIOAddress); \
-}
-
-
-#define PCAvDelayByIO(uDelayUnit) { \
- unsigned char byData; \
- unsigned long ii; \
- \
- if (uDelayUnit <= 50) { \
- udelay(uDelayUnit); \
- } \
- else { \
- for (ii = 0; ii < (uDelayUnit); ii++) \
- byData = inb(0x61); \
- } \
-}
-
+#define PCBvInPortB(dwIOAddress, pbyData) \
+do { \
+ *(pbyData) = inb(dwIOAddress); \
+} while (0)
+
+#define PCBvInPortW(dwIOAddress, pwData) \
+do { \
+ *(pwData) = inw(dwIOAddress); \
+} while (0)
+
+#define PCBvInPortD(dwIOAddress, pdwData) \
+do { \
+ *(pdwData) = inl(dwIOAddress); \
+} while (0)
+
+#define PCBvOutPortB(dwIOAddress, byData) \
+ outb(byData, dwIOAddress)
+
+#define PCBvOutPortW(dwIOAddress, wData) \
+ outw(wData, dwIOAddress)
+
+#define PCBvOutPortD(dwIOAddress, dwData) \
+ outl(dwData, dwIOAddress)
+
+#define PCAvDelayByIO(uDelayUnit) \
+do { \
+ unsigned char byData; \
+ unsigned long ii; \
+ \
+ if (uDelayUnit <= 50) { \
+ udelay(uDelayUnit); \
+ } else { \
+ for (ii = 0; ii < (uDelayUnit); ii++) \
+ byData = inb(0x61); \
+ } \
+} while (0)
/*--------------------- Export Classes ----------------------------*/
@@ -159,8 +154,4 @@
/*--------------------- Export Functions --------------------------*/
-
-
-
#endif // __UPC_H__
-
diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c
index 62c44b87d310..d8f4f8e7d05e 100644
--- a/drivers/staging/vt6655/vntwifi.c
+++ b/drivers/staging/vt6655/vntwifi.c
@@ -66,19 +66,18 @@
*
* Return Value: none
*
--*/
+ -*/
void
-VNTWIFIvSetOPMode (
- void *pMgmtHandle,
- WMAC_CONFIG_MODE eOPMode
- )
+VNTWIFIvSetOPMode(
+ void *pMgmtHandle,
+ WMAC_CONFIG_MODE eOPMode
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- pMgmt->eConfigMode = eOPMode;
+ pMgmt->eConfigMode = eOPMode;
}
-
/*+
*
* Description:
@@ -95,20 +94,20 @@ VNTWIFIvSetOPMode (
*
* Return Value: none
*
--*/
+ -*/
void
-VNTWIFIvSetIBSSParameter (
- void *pMgmtHandle,
- unsigned short wBeaconPeriod,
- unsigned short wATIMWindow,
- unsigned int uChannel
- )
+VNTWIFIvSetIBSSParameter(
+ void *pMgmtHandle,
+ unsigned short wBeaconPeriod,
+ unsigned short wATIMWindow,
+ unsigned int uChannel
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- pMgmt->wIBSSBeaconPeriod = wBeaconPeriod;
- pMgmt->wIBSSATIMWindow = wATIMWindow;
- pMgmt->uIBSSChannel = uChannel;
+ pMgmt->wIBSSBeaconPeriod = wBeaconPeriod;
+ pMgmt->wIBSSATIMWindow = wATIMWindow;
+ pMgmt->uIBSSChannel = uChannel;
}
/*+
@@ -124,14 +123,14 @@ VNTWIFIvSetIBSSParameter (
*
* Return Value: current SSID pointer.
*
--*/
+ -*/
PWLAN_IE_SSID
-VNTWIFIpGetCurrentSSID (
- void *pMgmtHandle
- )
+VNTWIFIpGetCurrentSSID(
+ void *pMgmtHandle
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- return((PWLAN_IE_SSID) pMgmt->abyCurrSSID);
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ return (PWLAN_IE_SSID) pMgmt->abyCurrSSID;
}
/*+
@@ -147,17 +146,17 @@ VNTWIFIpGetCurrentSSID (
*
* Return Value: current Channel.
*
--*/
+ -*/
unsigned int
-VNTWIFIpGetCurrentChannel (
- void *pMgmtHandle
- )
+VNTWIFIpGetCurrentChannel(
+ void *pMgmtHandle
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- if (pMgmtHandle != NULL) {
- return (pMgmt->uCurrChannel);
- }
- return 0;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ if (pMgmtHandle != NULL) {
+ return pMgmt->uCurrChannel;
+ }
+ return 0;
}
/*+
@@ -173,18 +172,16 @@ VNTWIFIpGetCurrentChannel (
*
* Return Value: current Assoc ID
*
--*/
+ -*/
unsigned short
-VNTWIFIwGetAssocID (
- void *pMgmtHandle
- )
+VNTWIFIwGetAssocID(
+ void *pMgmtHandle
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- return(pMgmt->wCurrAID);
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ return pMgmt->wCurrAID;
}
-
-
/*+
*
* Description:
@@ -199,35 +196,35 @@ VNTWIFIwGetAssocID (
*
* Return Value: max support rate
*
--*/
+ -*/
unsigned char
-VNTWIFIbyGetMaxSupportRate (
- PWLAN_IE_SUPP_RATES pSupportRateIEs,
- PWLAN_IE_SUPP_RATES pExtSupportRateIEs
- )
+VNTWIFIbyGetMaxSupportRate(
+ PWLAN_IE_SUPP_RATES pSupportRateIEs,
+ PWLAN_IE_SUPP_RATES pExtSupportRateIEs
+)
{
- unsigned char byMaxSupportRate = RATE_1M;
- unsigned char bySupportRate = RATE_1M;
- unsigned int ii = 0;
-
- if (pSupportRateIEs) {
- for (ii = 0; ii < pSupportRateIEs->len; ii++) {
- bySupportRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]);
- if (bySupportRate > byMaxSupportRate) {
- byMaxSupportRate = bySupportRate;
- }
- }
- }
- if (pExtSupportRateIEs) {
- for (ii = 0; ii < pExtSupportRateIEs->len; ii++) {
- bySupportRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]);
- if (bySupportRate > byMaxSupportRate) {
- byMaxSupportRate = bySupportRate;
- }
- }
- }
-
- return byMaxSupportRate;
+ unsigned char byMaxSupportRate = RATE_1M;
+ unsigned char bySupportRate = RATE_1M;
+ unsigned int ii = 0;
+
+ if (pSupportRateIEs) {
+ for (ii = 0; ii < pSupportRateIEs->len; ii++) {
+ bySupportRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]);
+ if (bySupportRate > byMaxSupportRate) {
+ byMaxSupportRate = bySupportRate;
+ }
+ }
+ }
+ if (pExtSupportRateIEs) {
+ for (ii = 0; ii < pExtSupportRateIEs->len; ii++) {
+ bySupportRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]);
+ if (bySupportRate > byMaxSupportRate) {
+ byMaxSupportRate = bySupportRate;
+ }
+ }
+ }
+
+ return byMaxSupportRate;
}
/*+
@@ -245,48 +242,48 @@ VNTWIFIbyGetMaxSupportRate (
*
* Return Value: max support rate
*
--*/
+ -*/
unsigned char
-VNTWIFIbyGetACKTxRate (
- unsigned char byRxDataRate,
- PWLAN_IE_SUPP_RATES pSupportRateIEs,
- PWLAN_IE_SUPP_RATES pExtSupportRateIEs
- )
+VNTWIFIbyGetACKTxRate(
+ unsigned char byRxDataRate,
+ PWLAN_IE_SUPP_RATES pSupportRateIEs,
+ PWLAN_IE_SUPP_RATES pExtSupportRateIEs
+)
{
- unsigned char byMaxAckRate;
- unsigned char byBasicRate;
- unsigned int ii;
-
- if (byRxDataRate <= RATE_11M) {
- byMaxAckRate = RATE_1M;
- } else {
- // 24M is mandatory for 802.11a and 802.11g
- byMaxAckRate = RATE_24M;
- }
- if (pSupportRateIEs) {
- for (ii = 0; ii < pSupportRateIEs->len; ii++) {
- if (pSupportRateIEs->abyRates[ii] & 0x80) {
- byBasicRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]);
- if ((byBasicRate <= byRxDataRate) &&
- (byBasicRate > byMaxAckRate)) {
- byMaxAckRate = byBasicRate;
- }
- }
- }
- }
- if (pExtSupportRateIEs) {
- for (ii = 0; ii < pExtSupportRateIEs->len; ii++) {
- if (pExtSupportRateIEs->abyRates[ii] & 0x80) {
- byBasicRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]);
- if ((byBasicRate <= byRxDataRate) &&
- (byBasicRate > byMaxAckRate)) {
- byMaxAckRate = byBasicRate;
- }
- }
- }
- }
-
- return byMaxAckRate;
+ unsigned char byMaxAckRate;
+ unsigned char byBasicRate;
+ unsigned int ii;
+
+ if (byRxDataRate <= RATE_11M) {
+ byMaxAckRate = RATE_1M;
+ } else {
+ // 24M is mandatory for 802.11a and 802.11g
+ byMaxAckRate = RATE_24M;
+ }
+ if (pSupportRateIEs) {
+ for (ii = 0; ii < pSupportRateIEs->len; ii++) {
+ if (pSupportRateIEs->abyRates[ii] & 0x80) {
+ byBasicRate = DATARATEbyGetRateIdx(pSupportRateIEs->abyRates[ii]);
+ if ((byBasicRate <= byRxDataRate) &&
+ (byBasicRate > byMaxAckRate)) {
+ byMaxAckRate = byBasicRate;
+ }
+ }
+ }
+ }
+ if (pExtSupportRateIEs) {
+ for (ii = 0; ii < pExtSupportRateIEs->len; ii++) {
+ if (pExtSupportRateIEs->abyRates[ii] & 0x80) {
+ byBasicRate = DATARATEbyGetRateIdx(pExtSupportRateIEs->abyRates[ii]);
+ if ((byBasicRate <= byRxDataRate) &&
+ (byBasicRate > byMaxAckRate)) {
+ byMaxAckRate = byBasicRate;
+ }
+ }
+ }
+ }
+
+ return byMaxAckRate;
}
/*+
@@ -303,22 +300,22 @@ VNTWIFIbyGetACKTxRate (
*
* Return Value: none
*
--*/
+ -*/
void
-VNTWIFIvSetAuthenticationMode (
- void *pMgmtHandle,
- WMAC_AUTHENTICATION_MODE eAuthMode
- )
+VNTWIFIvSetAuthenticationMode(
+ void *pMgmtHandle,
+ WMAC_AUTHENTICATION_MODE eAuthMode
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
-
- pMgmt->eAuthenMode = eAuthMode;
- if ((eAuthMode == WMAC_AUTH_SHAREKEY) ||
- (eAuthMode == WMAC_AUTH_AUTO)) {
- pMgmt->bShareKeyAlgorithm = true;
- } else {
- pMgmt->bShareKeyAlgorithm = false;
- }
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+
+ pMgmt->eAuthenMode = eAuthMode;
+ if ((eAuthMode == WMAC_AUTH_SHAREKEY) ||
+ (eAuthMode == WMAC_AUTH_AUTO)) {
+ pMgmt->bShareKeyAlgorithm = true;
+ } else {
+ pMgmt->bShareKeyAlgorithm = false;
+ }
}
/*+
@@ -335,59 +332,56 @@ VNTWIFIvSetAuthenticationMode (
*
* Return Value: none
*
--*/
+ -*/
void
-VNTWIFIvSetEncryptionMode (
- void *pMgmtHandle,
- WMAC_ENCRYPTION_MODE eEncryptionMode
- )
+VNTWIFIvSetEncryptionMode(
+ void *pMgmtHandle,
+ WMAC_ENCRYPTION_MODE eEncryptionMode
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
-
- pMgmt->eEncryptionMode = eEncryptionMode;
- if ((eEncryptionMode == WMAC_ENCRYPTION_WEPEnabled) ||
- (eEncryptionMode == WMAC_ENCRYPTION_TKIPEnabled) ||
- (eEncryptionMode == WMAC_ENCRYPTION_AESEnabled) ) {
- pMgmt->bPrivacyInvoked = true;
- } else {
- pMgmt->bPrivacyInvoked = false;
- }
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+
+ pMgmt->eEncryptionMode = eEncryptionMode;
+ if ((eEncryptionMode == WMAC_ENCRYPTION_WEPEnabled) ||
+ (eEncryptionMode == WMAC_ENCRYPTION_TKIPEnabled) ||
+ (eEncryptionMode == WMAC_ENCRYPTION_AESEnabled)) {
+ pMgmt->bPrivacyInvoked = true;
+ } else {
+ pMgmt->bPrivacyInvoked = false;
+ }
}
-
-
bool
-VNTWIFIbConfigPhyMode (
- void *pMgmtHandle,
- CARD_PHY_TYPE ePhyType
- )
+VNTWIFIbConfigPhyMode(
+ void *pMgmtHandle,
+ CARD_PHY_TYPE ePhyType
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
-
- if ((ePhyType != PHY_TYPE_AUTO) &&
- (ePhyType != pMgmt->eCurrentPHYMode)) {
- if (CARDbSetPhyParameter(pMgmt->pAdapter, ePhyType, 0, 0, NULL, NULL)==true) {
- pMgmt->eCurrentPHYMode = ePhyType;
- } else {
- return(false);
- }
- }
- pMgmt->eConfigPHYMode = ePhyType;
- return(true);
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+
+ if ((ePhyType != PHY_TYPE_AUTO) &&
+ (ePhyType != pMgmt->eCurrentPHYMode)) {
+ if (CARDbSetPhyParameter(pMgmt->pAdapter, ePhyType, 0, 0, NULL, NULL) == true) {
+ pMgmt->eCurrentPHYMode = ePhyType;
+ } else {
+ return false;
+ }
+ }
+ pMgmt->eConfigPHYMode = ePhyType;
+ return true;
}
-
void
-VNTWIFIbGetConfigPhyMode (
- void *pMgmtHandle,
- void *pePhyType
- )
+VNTWIFIbGetConfigPhyMode(
+ void *pMgmtHandle,
+ void *pePhyType
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- if ((pMgmt != NULL) && (pePhyType != NULL)) {
- *(PCARD_PHY_TYPE)pePhyType = pMgmt->eConfigPHYMode;
- }
+ if ((pMgmt != NULL) && (pePhyType != NULL)) {
+ *(PCARD_PHY_TYPE)pePhyType = pMgmt->eConfigPHYMode;
+ }
}
/*+
@@ -403,8 +397,7 @@ VNTWIFIbGetConfigPhyMode (
*
* Return Value: None.
*
--*/
-
+ -*/
/*+
*
@@ -420,62 +413,55 @@ VNTWIFIbGetConfigPhyMode (
*
* Return Value: None.
*
--*/
+ -*/
void
VNTWIFIvQueryBSSList(void *pMgmtHandle, unsigned int *puBSSCount, void **pvFirstBSS)
{
- unsigned int ii = 0;
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- PKnownBSS pBSS = NULL;
- unsigned int uCount = 0;
-
- *pvFirstBSS = NULL;
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pBSS = &(pMgmt->sBSSList[ii]);
- if (!pBSS->bActive) {
- continue;
- }
- if (*pvFirstBSS == NULL) {
- *pvFirstBSS = &(pMgmt->sBSSList[ii]);
- }
- uCount++;
- }
- *puBSSCount = uCount;
+ unsigned int ii = 0;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ PKnownBSS pBSS = NULL;
+ unsigned int uCount = 0;
+
+ *pvFirstBSS = NULL;
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSS = &(pMgmt->sBSSList[ii]);
+ if (!pBSS->bActive) {
+ continue;
+ }
+ if (*pvFirstBSS == NULL) {
+ *pvFirstBSS = &(pMgmt->sBSSList[ii]);
+ }
+ uCount++;
+ }
+ *puBSSCount = uCount;
}
-
-
-
void
-VNTWIFIvGetNextBSS (
- void *pMgmtHandle,
- void *pvCurrentBSS,
- void **pvNextBSS
- )
+VNTWIFIvGetNextBSS(
+ void *pMgmtHandle,
+ void *pvCurrentBSS,
+ void **pvNextBSS
+)
{
- PKnownBSS pBSS = (PKnownBSS) pvCurrentBSS;
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
-
- *pvNextBSS = NULL;
-
- while (*pvNextBSS == NULL) {
- pBSS++;
- if (pBSS > &(pMgmt->sBSSList[MAX_BSS_NUM])) {
- return;
- }
- if (pBSS->bActive == true) {
- *pvNextBSS = pBSS;
- return;
- }
- }
+ PKnownBSS pBSS = (PKnownBSS) pvCurrentBSS;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+
+ *pvNextBSS = NULL;
+
+ while (*pvNextBSS == NULL) {
+ pBSS++;
+ if (pBSS > &(pMgmt->sBSSList[MAX_BSS_NUM])) {
+ return;
+ }
+ if (pBSS->bActive == true) {
+ *pvNextBSS = pBSS;
+ return;
+ }
+ }
}
-
-
-
-
/*+
*
* Description:
@@ -487,319 +473,304 @@ VNTWIFIvGetNextBSS (
*
* Return Value: none
*
--*/
+ -*/
void
VNTWIFIvUpdateNodeTxCounter(
- void *pMgmtHandle,
- unsigned char *pbyDestAddress,
- bool bTxOk,
- unsigned short wRate,
- unsigned char *pbyTxFailCount
- )
+ void *pMgmtHandle,
+ unsigned char *pbyDestAddress,
+ bool bTxOk,
+ unsigned short wRate,
+ unsigned char *pbyTxFailCount
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- unsigned int uNodeIndex = 0;
- unsigned int ii;
-
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
- (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
- if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex) == false) {
- return;
- }
- }
- pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts++;
- if (bTxOk == true) {
- // transmit success, TxAttempts at least plus one
- pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++;
- pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wRate]++;
- } else {
- pMgmt->sNodeDBTable[uNodeIndex].uTxFailures++;
- }
- pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += pbyTxFailCount[MAX_RATE];
- for(ii=0;ii<MAX_RATE;ii++) {
- pMgmt->sNodeDBTable[uNodeIndex].uTxFail[ii] += pbyTxFailCount[ii];
- }
- return;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ unsigned int uNodeIndex = 0;
+ unsigned int ii;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
+ (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex) == false) {
+ return;
+ }
+ }
+ pMgmt->sNodeDBTable[uNodeIndex].uTxAttempts++;
+ if (bTxOk == true) {
+ // transmit success, TxAttempts at least plus one
+ pMgmt->sNodeDBTable[uNodeIndex].uTxOk[MAX_RATE]++;
+ pMgmt->sNodeDBTable[uNodeIndex].uTxOk[wRate]++;
+ } else {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFailures++;
+ }
+ pMgmt->sNodeDBTable[uNodeIndex].uTxRetry += pbyTxFailCount[MAX_RATE];
+ for (ii = 0; ii < MAX_RATE; ii++) {
+ pMgmt->sNodeDBTable[uNodeIndex].uTxFail[ii] += pbyTxFailCount[ii];
+ }
+ return;
}
-
void
VNTWIFIvGetTxRate(
- void *pMgmtHandle,
- unsigned char *pbyDestAddress,
- unsigned short *pwTxDataRate,
- unsigned char *pbyACKRate,
- unsigned char *pbyCCKBasicRate,
- unsigned char *pbyOFDMBasicRate
- )
+ void *pMgmtHandle,
+ unsigned char *pbyDestAddress,
+ unsigned short *pwTxDataRate,
+ unsigned char *pbyACKRate,
+ unsigned char *pbyCCKBasicRate,
+ unsigned char *pbyOFDMBasicRate
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- unsigned int uNodeIndex = 0;
- unsigned short wTxDataRate = RATE_1M;
- unsigned char byACKRate = RATE_1M;
- unsigned char byCCKBasicRate = RATE_1M;
- unsigned char byOFDMBasicRate = RATE_24M;
- PWLAN_IE_SUPP_RATES pSupportRateIEs = NULL;
- PWLAN_IE_SUPP_RATES pExtSupportRateIEs = NULL;
-
-
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
- (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
- // Adhoc Tx rate decided from node DB
- if(BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex)) {
- wTxDataRate = (pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
- pSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrSuppRates);
- pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrExtSuppRates);
- } else {
- if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) {
- wTxDataRate = RATE_2M;
- } else {
- wTxDataRate = RATE_24M;
- }
- pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates;
- pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates;
- }
- } else { // Infrastructure: rate decided from AP Node, index = 0
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ unsigned int uNodeIndex = 0;
+ unsigned short wTxDataRate = RATE_1M;
+ unsigned char byACKRate = RATE_1M;
+ unsigned char byCCKBasicRate = RATE_1M;
+ unsigned char byOFDMBasicRate = RATE_24M;
+ PWLAN_IE_SUPP_RATES pSupportRateIEs = NULL;
+ PWLAN_IE_SUPP_RATES pExtSupportRateIEs = NULL;
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) ||
+ (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
+ // Adhoc Tx rate decided from node DB
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pbyDestAddress, &uNodeIndex)) {
+ wTxDataRate = (pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
+ pSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrSuppRates);
+ pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) (pMgmt->sNodeDBTable[uNodeIndex].abyCurrExtSuppRates);
+ } else {
+ if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) {
+ wTxDataRate = RATE_2M;
+ } else {
+ wTxDataRate = RATE_24M;
+ }
+ pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates;
+ pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates;
+ }
+ } else { // Infrastructure: rate decided from AP Node, index = 0
wTxDataRate = (pMgmt->sNodeDBTable[0].wTxDataRate);
#ifdef PLICE_DEBUG
printk(KERN_DEBUG "GetTxRate:AP MAC is %pM,TxRate is %d\n",
- pMgmt->sNodeDBTable[0].abyMACAddr, wTxDataRate);
+ pMgmt->sNodeDBTable[0].abyMACAddr, wTxDataRate);
#endif
-
- pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates;
- pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates;
- }
- byACKRate = VNTWIFIbyGetACKTxRate( (unsigned char) wTxDataRate,
- pSupportRateIEs,
- pExtSupportRateIEs
- );
- if (byACKRate > (unsigned char) wTxDataRate) {
- byACKRate = (unsigned char) wTxDataRate;
- }
- byCCKBasicRate = VNTWIFIbyGetACKTxRate( RATE_11M,
- pSupportRateIEs,
- pExtSupportRateIEs
- );
- byOFDMBasicRate = VNTWIFIbyGetACKTxRate(RATE_54M,
- pSupportRateIEs,
- pExtSupportRateIEs
- );
- *pwTxDataRate = wTxDataRate;
- *pbyACKRate = byACKRate;
- *pbyCCKBasicRate = byCCKBasicRate;
- *pbyOFDMBasicRate = byOFDMBasicRate;
- return;
+ pSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrSuppRates;
+ pExtSupportRateIEs = (PWLAN_IE_SUPP_RATES) pMgmt->abyCurrExtSuppRates;
+ }
+ byACKRate = VNTWIFIbyGetACKTxRate((unsigned char) wTxDataRate,
+ pSupportRateIEs,
+ pExtSupportRateIEs
+);
+ if (byACKRate > (unsigned char) wTxDataRate) {
+ byACKRate = (unsigned char) wTxDataRate;
+ }
+ byCCKBasicRate = VNTWIFIbyGetACKTxRate(RATE_11M,
+ pSupportRateIEs,
+ pExtSupportRateIEs
+);
+ byOFDMBasicRate = VNTWIFIbyGetACKTxRate(RATE_54M,
+ pSupportRateIEs,
+ pExtSupportRateIEs
+);
+ *pwTxDataRate = wTxDataRate;
+ *pbyACKRate = byACKRate;
+ *pbyCCKBasicRate = byCCKBasicRate;
+ *pbyOFDMBasicRate = byOFDMBasicRate;
+ return;
}
unsigned char
VNTWIFIbyGetKeyCypher(
- void *pMgmtHandle,
- bool bGroupKey
- )
+ void *pMgmtHandle,
+ bool bGroupKey
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
+ PSMgmtObject pMgmt = (PSMgmtObject)pMgmtHandle;
- if (bGroupKey == true) {
- return (pMgmt->byCSSGK);
- } else {
- return (pMgmt->byCSSPK);
- }
+ if (bGroupKey == true) {
+ return pMgmt->byCSSGK;
+ } else {
+ return pMgmt->byCSSPK;
+ }
}
-
/*
-bool
-VNTWIFIbInit(
- void *pAdapterHandler,
- void **pMgmtHandler
- )
-{
-
- PSMgmtObject pMgmt = NULL;
- unsigned int ii;
-
-
- pMgmt = (PSMgmtObject)kmalloc(sizeof(SMgmtObject), (int)GFP_ATOMIC);
- if (pMgmt == NULL) {
- *pMgmtHandler = NULL;
- return false;
- }
-
- memset(pMgmt, 0, sizeof(SMgmtObject));
- pMgmt->pAdapter = (void *) pAdapterHandler;
-
- // should initial MAC address abyMACAddr
- for(ii=0;ii<WLAN_BSSID_LEN;ii++) {
- pMgmt->abyDesireBSSID[ii] = 0xFF;
- }
- pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
- pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
- pMgmt->byCSSPK = KEY_CTL_NONE;
- pMgmt->byCSSGK = KEY_CTL_NONE;
- pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
-
- pMgmt->cbFreeCmdQueue = CMD_Q_SIZE;
- pMgmt->uCmdDequeueIdx = 0;
- pMgmt->uCmdEnqueueIdx = 0;
- pMgmt->eCommandState = WLAN_CMD_STATE_IDLE;
- pMgmt->bCmdStop = false;
- pMgmt->bCmdRunning = false;
-
- *pMgmtHandler = pMgmt;
- return true;
-}
+ bool
+ VNTWIFIbInit(
+ void *pAdapterHandler,
+ void **pMgmtHandler
+) {
+ PSMgmtObject pMgmt = NULL;
+ unsigned int ii;
+
+ pMgmt = (PSMgmtObject)kmalloc(sizeof(SMgmtObject), (int)GFP_ATOMIC);
+ if (pMgmt == NULL) {
+ *pMgmtHandler = NULL;
+ return false;
+ }
+
+ memset(pMgmt, 0, sizeof(SMgmtObject));
+ pMgmt->pAdapter = (void *) pAdapterHandler;
+
+ // should initial MAC address abyMACAddr
+ for (ii=0; ii<WLAN_BSSID_LEN; ii++) {
+ pMgmt->abyDesireBSSID[ii] = 0xFF;
+ }
+ pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
+ pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
+ pMgmt->byCSSPK = KEY_CTL_NONE;
+ pMgmt->byCSSGK = KEY_CTL_NONE;
+ pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
+
+ pMgmt->cbFreeCmdQueue = CMD_Q_SIZE;
+ pMgmt->uCmdDequeueIdx = 0;
+ pMgmt->uCmdEnqueueIdx = 0;
+ pMgmt->eCommandState = WLAN_CMD_STATE_IDLE;
+ pMgmt->bCmdStop = false;
+ pMgmt->bCmdRunning = false;
+
+ *pMgmtHandler = pMgmt;
+ return true;
+ }
*/
-
-
bool
-VNTWIFIbSetPMKIDCache (
- void *pMgmtObject,
- unsigned long ulCount,
- void *pPMKIDInfo
- )
+VNTWIFIbSetPMKIDCache(
+ void *pMgmtObject,
+ unsigned long ulCount,
+ void *pPMKIDInfo
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
-
- if (ulCount > MAX_PMKID_CACHE) {
- return (false);
- }
- pMgmt->gsPMKIDCache.BSSIDInfoCount = ulCount;
- memcpy(pMgmt->gsPMKIDCache.BSSIDInfo, pPMKIDInfo, (ulCount*sizeof(PMKIDInfo)));
- return (true);
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+
+ if (ulCount > MAX_PMKID_CACHE) {
+ return false;
+ }
+ pMgmt->gsPMKIDCache.BSSIDInfoCount = ulCount;
+ memcpy(pMgmt->gsPMKIDCache.BSSIDInfo, pPMKIDInfo, (ulCount*sizeof(PMKIDInfo)));
+ return true;
}
-
-
unsigned short
VNTWIFIwGetMaxSupportRate(
- void *pMgmtObject
- )
+ void *pMgmtObject
+)
{
- unsigned short wRate = RATE_54M;
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
-
- for(wRate = RATE_54M; wRate > RATE_1M; wRate--) {
- if (pMgmt->sNodeDBTable[0].wSuppRate & (1<<wRate)) {
- return (wRate);
- }
- }
- if (pMgmt->eCurrentPHYMode == PHY_TYPE_11A) {
- return (RATE_6M);
- } else {
- return (RATE_1M);
- }
+ unsigned short wRate = RATE_54M;
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+
+ for (wRate = RATE_54M; wRate > RATE_1M; wRate--) {
+ if (pMgmt->sNodeDBTable[0].wSuppRate & (1<<wRate)) {
+ return wRate;
+ }
+ }
+ if (pMgmt->eCurrentPHYMode == PHY_TYPE_11A) {
+ return RATE_6M;
+ } else {
+ return RATE_1M;
+ }
}
-
void
-VNTWIFIvSet11h (
- void *pMgmtObject,
- bool b11hEnable
- )
+VNTWIFIvSet11h(
+ void *pMgmtObject,
+ bool b11hEnable
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- pMgmt->b11hEnable = b11hEnable;
+ pMgmt->b11hEnable = b11hEnable;
}
bool
VNTWIFIbMeasureReport(
- void *pMgmtObject,
- bool bEndOfReport,
- void *pvMeasureEID,
- unsigned char byReportMode,
- unsigned char byBasicMap,
- unsigned char byCCAFraction,
- unsigned char *pbyRPIs
- )
+ void *pMgmtObject,
+ bool bEndOfReport,
+ void *pvMeasureEID,
+ unsigned char byReportMode,
+ unsigned char byBasicMap,
+ unsigned char byCCAFraction,
+ unsigned char *pbyRPIs
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- unsigned char *pbyCurrentEID = (unsigned char *) (pMgmt->pCurrMeasureEIDRep);
-
- //spin_lock_irq(&pDevice->lock);
- if ((pvMeasureEID != NULL) &&
- (pMgmt->uLengthOfRepEIDs < (WLAN_A3FR_MAXLEN - sizeof(MEASEURE_REP) - sizeof(WLAN_80211HDR_A3) - 3))
- ) {
- pMgmt->pCurrMeasureEIDRep->byElementID = WLAN_EID_MEASURE_REP;
- pMgmt->pCurrMeasureEIDRep->len = 3;
- pMgmt->pCurrMeasureEIDRep->byToken = ((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->byToken;
- pMgmt->pCurrMeasureEIDRep->byMode = byReportMode;
- pMgmt->pCurrMeasureEIDRep->byType = ((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->byType;
- switch (pMgmt->pCurrMeasureEIDRep->byType) {
- case MEASURE_TYPE_BASIC :
- pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_BASIC);
- memcpy( &(pMgmt->pCurrMeasureEIDRep->sRep.sBasic),
- &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
- sizeof(MEASEURE_REQ));
- pMgmt->pCurrMeasureEIDRep->sRep.sBasic.byMap = byBasicMap;
- break;
- case MEASURE_TYPE_CCA :
- pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_CCA);
- memcpy( &(pMgmt->pCurrMeasureEIDRep->sRep.sCCA),
- &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
- sizeof(MEASEURE_REQ));
- pMgmt->pCurrMeasureEIDRep->sRep.sCCA.byCCABusyFraction = byCCAFraction;
- break;
- case MEASURE_TYPE_RPI :
- pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_RPI);
- memcpy( &(pMgmt->pCurrMeasureEIDRep->sRep.sRPI),
- &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
- sizeof(MEASEURE_REQ));
- memcpy(pMgmt->pCurrMeasureEIDRep->sRep.sRPI.abyRPIdensity, pbyRPIs, 8);
- break;
- default :
- break;
- }
- pbyCurrentEID += (2 + pMgmt->pCurrMeasureEIDRep->len);
- pMgmt->uLengthOfRepEIDs += (2 + pMgmt->pCurrMeasureEIDRep->len);
- pMgmt->pCurrMeasureEIDRep = (PWLAN_IE_MEASURE_REP) pbyCurrentEID;
- }
- if (bEndOfReport == true) {
- IEEE11hbMSRRepTx(pMgmt);
- }
- //spin_unlock_irq(&pDevice->lock);
- return (true);
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+ unsigned char *pbyCurrentEID = (unsigned char *)(pMgmt->pCurrMeasureEIDRep);
+
+ //spin_lock_irq(&pDevice->lock);
+ if ((pvMeasureEID != NULL) &&
+ (pMgmt->uLengthOfRepEIDs < (WLAN_A3FR_MAXLEN - sizeof(MEASEURE_REP) - sizeof(WLAN_80211HDR_A3) - 3))
+) {
+ pMgmt->pCurrMeasureEIDRep->byElementID = WLAN_EID_MEASURE_REP;
+ pMgmt->pCurrMeasureEIDRep->len = 3;
+ pMgmt->pCurrMeasureEIDRep->byToken = ((PWLAN_IE_MEASURE_REQ)pvMeasureEID)->byToken;
+ pMgmt->pCurrMeasureEIDRep->byMode = byReportMode;
+ pMgmt->pCurrMeasureEIDRep->byType = ((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->byType;
+ switch (pMgmt->pCurrMeasureEIDRep->byType) {
+ case MEASURE_TYPE_BASIC:
+ pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_BASIC);
+ memcpy(&(pMgmt->pCurrMeasureEIDRep->sRep.sBasic),
+ &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
+ sizeof(MEASEURE_REQ));
+ pMgmt->pCurrMeasureEIDRep->sRep.sBasic.byMap = byBasicMap;
+ break;
+ case MEASURE_TYPE_CCA:
+ pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_CCA);
+ memcpy(&(pMgmt->pCurrMeasureEIDRep->sRep.sCCA),
+ &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
+ sizeof(MEASEURE_REQ));
+ pMgmt->pCurrMeasureEIDRep->sRep.sCCA.byCCABusyFraction = byCCAFraction;
+ break;
+ case MEASURE_TYPE_RPI:
+ pMgmt->pCurrMeasureEIDRep->len += sizeof(MEASEURE_REP_RPI);
+ memcpy(&(pMgmt->pCurrMeasureEIDRep->sRep.sRPI),
+ &(((PWLAN_IE_MEASURE_REQ) pvMeasureEID)->sReq),
+ sizeof(MEASEURE_REQ));
+ memcpy(pMgmt->pCurrMeasureEIDRep->sRep.sRPI.abyRPIdensity, pbyRPIs, 8);
+ break;
+ default:
+ break;
+ }
+ pbyCurrentEID += (2 + pMgmt->pCurrMeasureEIDRep->len);
+ pMgmt->uLengthOfRepEIDs += (2 + pMgmt->pCurrMeasureEIDRep->len);
+ pMgmt->pCurrMeasureEIDRep = (PWLAN_IE_MEASURE_REP) pbyCurrentEID;
+ }
+ if (bEndOfReport == true) {
+ IEEE11hbMSRRepTx(pMgmt);
+ }
+ //spin_unlock_irq(&pDevice->lock);
+ return true;
}
-
bool
VNTWIFIbChannelSwitch(
- void *pMgmtObject,
- unsigned char byNewChannel
- )
+ void *pMgmtObject,
+ unsigned char byNewChannel
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- //spin_lock_irq(&pDevice->lock);
- pMgmt->uCurrChannel = byNewChannel;
- pMgmt->bSwitchChannel = false;
- //spin_unlock_irq(&pDevice->lock);
- return true;
+ //spin_lock_irq(&pDevice->lock);
+ pMgmt->uCurrChannel = byNewChannel;
+ pMgmt->bSwitchChannel = false;
+ //spin_unlock_irq(&pDevice->lock);
+ return true;
}
/*
-bool
-VNTWIFIbRadarPresent(
- void *pMgmtObject,
- unsigned char byChannel
- )
-{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
- (byChannel == (unsigned char) pMgmt->uCurrChannel) &&
- (pMgmt->bSwitchChannel != true) &&
- (pMgmt->b11hEnable == true)) {
- if (!compare_ether_addr(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) {
- pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(unsigned char) pMgmt->uCurrChannel);
- pMgmt->bSwitchChannel = true;
- }
- BEACONbSendBeacon(pMgmt);
- CARDbChannelSwitch(pMgmt->pAdapter, 0, pMgmt->byNewChannel, 10);
- }
- return true;
-}
+ bool
+ VNTWIFIbRadarPresent(
+ void *pMgmtObject,
+ unsigned char byChannel
+) {
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtObject;
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
+ (byChannel == (unsigned char) pMgmt->uCurrChannel) &&
+ (pMgmt->bSwitchChannel != true) &&
+ (pMgmt->b11hEnable == true)) {
+ if (!compare_ether_addr(pMgmt->abyIBSSDFSOwner, CARDpGetCurrentAddress(pMgmt->pAdapter))) {
+ pMgmt->byNewChannel = CARDbyAutoChannelSelect(pMgmt->pAdapter,(unsigned char) pMgmt->uCurrChannel);
+ pMgmt->bSwitchChannel = true;
+ }
+ BEACONbSendBeacon(pMgmt);
+ CARDbChannelSwitch(pMgmt->pAdapter, 0, pMgmt->byNewChannel, 10);
+ }
+ return true;
+ }
*/
-
diff --git a/drivers/staging/vt6655/vntwifi.h b/drivers/staging/vt6655/vntwifi.h
index f4327abaa773..4b01ebd7299a 100644
--- a/drivers/staging/vt6655/vntwifi.h
+++ b/drivers/staging/vt6655/vntwifi.h
@@ -64,244 +64,224 @@
// Pre-configured Authenticaiton Mode (from XP)
typedef enum tagWMAC_AUTHENTICATION_MODE {
-
- WMAC_AUTH_OPEN,
- WMAC_AUTH_SHAREKEY,
- WMAC_AUTH_AUTO,
- WMAC_AUTH_WPA,
- WMAC_AUTH_WPAPSK,
- WMAC_AUTH_WPANONE,
- WMAC_AUTH_WPA2,
- WMAC_AUTH_WPA2PSK,
- WMAC_AUTH_MAX // Not a real mode, defined as upper bound
-
+ WMAC_AUTH_OPEN,
+ WMAC_AUTH_SHAREKEY,
+ WMAC_AUTH_AUTO,
+ WMAC_AUTH_WPA,
+ WMAC_AUTH_WPAPSK,
+ WMAC_AUTH_WPANONE,
+ WMAC_AUTH_WPA2,
+ WMAC_AUTH_WPA2PSK,
+ WMAC_AUTH_MAX // Not a real mode, defined as upper bound
} WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE;
typedef enum tagWMAC_ENCRYPTION_MODE {
-
- WMAC_ENCRYPTION_WEPEnabled,
- WMAC_ENCRYPTION_WEPDisabled,
- WMAC_ENCRYPTION_WEPKeyAbsent,
- WMAC_ENCRYPTION_WEPNotSupported,
- WMAC_ENCRYPTION_TKIPEnabled,
- WMAC_ENCRYPTION_TKIPKeyAbsent,
- WMAC_ENCRYPTION_AESEnabled,
- WMAC_ENCRYPTION_AESKeyAbsent
-
+ WMAC_ENCRYPTION_WEPEnabled,
+ WMAC_ENCRYPTION_WEPDisabled,
+ WMAC_ENCRYPTION_WEPKeyAbsent,
+ WMAC_ENCRYPTION_WEPNotSupported,
+ WMAC_ENCRYPTION_TKIPEnabled,
+ WMAC_ENCRYPTION_TKIPKeyAbsent,
+ WMAC_ENCRYPTION_AESEnabled,
+ WMAC_ENCRYPTION_AESKeyAbsent
} WMAC_ENCRYPTION_MODE, *PWMAC_ENCRYPTION_MODE;
// Pre-configured Mode (from XP)
typedef enum tagWMAC_CONFIG_MODE {
-
- WMAC_CONFIG_ESS_STA = 0,
- WMAC_CONFIG_IBSS_STA,
- WMAC_CONFIG_AUTO,
- WMAC_CONFIG_AP
-
+ WMAC_CONFIG_ESS_STA = 0,
+ WMAC_CONFIG_IBSS_STA,
+ WMAC_CONFIG_AUTO,
+ WMAC_CONFIG_AP
} WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE;
-
-
typedef enum tagWMAC_POWER_MODE {
-
- WMAC_POWER_CAM,
- WMAC_POWER_FAST,
- WMAC_POWER_MAX
-
+ WMAC_POWER_CAM,
+ WMAC_POWER_FAST,
+ WMAC_POWER_MAX
} WMAC_POWER_MODE, *PWMAC_POWER_MODE;
#define VNTWIFIbIsShortSlotTime(wCapInfo) \
- WLAN_GET_CAP_INFO_SHORTSLOTTIME(wCapInfo) \
+ WLAN_GET_CAP_INFO_SHORTSLOTTIME(wCapInfo) \
#define VNTWIFIbIsProtectMode(byERP) \
- ((byERP & WLAN_EID_ERP_USE_PROTECTION) != 0) \
+ ((byERP & WLAN_EID_ERP_USE_PROTECTION) != 0) \
#define VNTWIFIbIsBarkerMode(byERP) \
- ((byERP & WLAN_EID_ERP_BARKER_MODE) != 0) \
+ ((byERP & WLAN_EID_ERP_BARKER_MODE) != 0) \
#define VNTWIFIbIsShortPreamble(wCapInfo) \
- WLAN_GET_CAP_INFO_SHORTPREAMBLE(wCapInfo) \
-
-#define VNTWIFIbIsEncryption(wCapInfo) \
- WLAN_GET_CAP_INFO_PRIVACY(wCapInfo) \
+ WLAN_GET_CAP_INFO_SHORTPREAMBLE(wCapInfo) \
-#define VNTWIFIbIsESS(wCapInfo) \
- WLAN_GET_CAP_INFO_ESS(wCapInfo) \
+#define VNTWIFIbIsEncryption(wCapInfo) \
+ WLAN_GET_CAP_INFO_PRIVACY(wCapInfo) \
+#define VNTWIFIbIsESS(wCapInfo) \
+ WLAN_GET_CAP_INFO_ESS(wCapInfo) \
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
void
-VNTWIFIvSetIBSSParameter (
- void *pMgmtHandle,
- unsigned short wBeaconPeriod,
- unsigned short wATIMWindow,
- unsigned int uChannel
- );
+VNTWIFIvSetIBSSParameter(
+ void *pMgmtHandle,
+ unsigned short wBeaconPeriod,
+ unsigned short wATIMWindow,
+ unsigned int uChannel
+);
void
-VNTWIFIvSetOPMode (
- void *pMgmtHandle,
- WMAC_CONFIG_MODE eOPMode
- );
+VNTWIFIvSetOPMode(
+ void *pMgmtHandle,
+ WMAC_CONFIG_MODE eOPMode
+);
PWLAN_IE_SSID
VNTWIFIpGetCurrentSSID(
- void *pMgmtHandle
- );
+ void *pMgmtHandle
+);
unsigned int
VNTWIFIpGetCurrentChannel(
- void *pMgmtHandle
- );
+ void *pMgmtHandle
+);
unsigned short
-VNTWIFIwGetAssocID (
- void *pMgmtHandle
- );
+VNTWIFIwGetAssocID(
+ void *pMgmtHandle
+);
unsigned char
-VNTWIFIbyGetMaxSupportRate (
- PWLAN_IE_SUPP_RATES pSupportRateIEs,
- PWLAN_IE_SUPP_RATES pExtSupportRateIEs
- );
+VNTWIFIbyGetMaxSupportRate(
+ PWLAN_IE_SUPP_RATES pSupportRateIEs,
+ PWLAN_IE_SUPP_RATES pExtSupportRateIEs
+);
unsigned char
-VNTWIFIbyGetACKTxRate (
- unsigned char byRxDataRate,
- PWLAN_IE_SUPP_RATES pSupportRateIEs,
- PWLAN_IE_SUPP_RATES pExtSupportRateIEs
- );
+VNTWIFIbyGetACKTxRate(
+ unsigned char byRxDataRate,
+ PWLAN_IE_SUPP_RATES pSupportRateIEs,
+ PWLAN_IE_SUPP_RATES pExtSupportRateIEs
+);
void
-VNTWIFIvSetAuthenticationMode (
- void *pMgmtHandle,
- WMAC_AUTHENTICATION_MODE eAuthMode
- );
+VNTWIFIvSetAuthenticationMode(
+ void *pMgmtHandle,
+ WMAC_AUTHENTICATION_MODE eAuthMode
+);
void
-VNTWIFIvSetEncryptionMode (
- void *pMgmtHandle,
- WMAC_ENCRYPTION_MODE eEncryptionMode
- );
-
+VNTWIFIvSetEncryptionMode(
+ void *pMgmtHandle,
+ WMAC_ENCRYPTION_MODE eEncryptionMode
+);
bool
VNTWIFIbConfigPhyMode(
- void *pMgmtHandle,
- CARD_PHY_TYPE ePhyType
- );
+ void *pMgmtHandle,
+ CARD_PHY_TYPE ePhyType
+);
void
VNTWIFIbGetConfigPhyMode(
- void *pMgmtHandle,
- void *pePhyType
- );
+ void *pMgmtHandle,
+ void *pePhyType
+);
void
VNTWIFIvQueryBSSList(void *pMgmtHandle, unsigned int *puBSSCount,
- void **pvFirstBSS);
+ void **pvFirstBSS);
void
-VNTWIFIvGetNextBSS (
- void *pMgmtHandle,
- void *pvCurrentBSS,
- void **pvNextBSS
- );
-
-
+VNTWIFIvGetNextBSS(
+ void *pMgmtHandle,
+ void *pvCurrentBSS,
+ void **pvNextBSS
+);
void
VNTWIFIvUpdateNodeTxCounter(
- void *pMgmtHandle,
- unsigned char *pbyDestAddress,
- bool bTxOk,
- unsigned short wRate,
- unsigned char *pbyTxFailCount
- );
-
+ void *pMgmtHandle,
+ unsigned char *pbyDestAddress,
+ bool bTxOk,
+ unsigned short wRate,
+ unsigned char *pbyTxFailCount
+);
void
VNTWIFIvGetTxRate(
- void *pMgmtHandle,
- unsigned char *pbyDestAddress,
- unsigned short *pwTxDataRate,
- unsigned char *pbyACKRate,
- unsigned char *pbyCCKBasicRate,
- unsigned char *pbyOFDMBasicRate
- );
+ void *pMgmtHandle,
+ unsigned char *pbyDestAddress,
+ unsigned short *pwTxDataRate,
+ unsigned char *pbyACKRate,
+ unsigned char *pbyCCKBasicRate,
+ unsigned char *pbyOFDMBasicRate
+);
/*
-bool
-VNTWIFIbInit(
- void *pAdapterHandler,
- void **pMgmtHandler
- );
+ bool
+ VNTWIFIbInit(
+ void *pAdapterHandler,
+ void **pMgmtHandler
+);
*/
unsigned char
VNTWIFIbyGetKeyCypher(
- void *pMgmtHandle,
- bool bGroupKey
- );
-
-
-
+ void *pMgmtHandle,
+ bool bGroupKey
+);
bool
-VNTWIFIbSetPMKIDCache (
- void *pMgmtObject,
- unsigned long ulCount,
- void *pPMKIDInfo
- );
+VNTWIFIbSetPMKIDCache(
+ void *pMgmtObject,
+ unsigned long ulCount,
+ void *pPMKIDInfo
+);
bool
-VNTWIFIbCommandRunning (
- void *pMgmtObject
- );
+VNTWIFIbCommandRunning(
+ void *pMgmtObject
+);
unsigned short
VNTWIFIwGetMaxSupportRate(
- void *pMgmtObject
- );
+ void *pMgmtObject
+);
// for 802.11h
void
-VNTWIFIvSet11h (
- void *pMgmtObject,
- bool b11hEnable
- );
+VNTWIFIvSet11h(
+ void *pMgmtObject,
+ bool b11hEnable
+);
bool
VNTWIFIbMeasureReport(
- void *pMgmtObject,
- bool bEndOfReport,
- void *pvMeasureEID,
- unsigned char byReportMode,
- unsigned char byBasicMap,
- unsigned char byCCAFraction,
- unsigned char *pbyRPIs
- );
+ void *pMgmtObject,
+ bool bEndOfReport,
+ void *pvMeasureEID,
+ unsigned char byReportMode,
+ unsigned char byBasicMap,
+ unsigned char byCCAFraction,
+ unsigned char *pbyRPIs
+);
bool
VNTWIFIbChannelSwitch(
- void *pMgmtObject,
- unsigned char byNewChannel
- );
+ void *pMgmtObject,
+ unsigned char byNewChannel
+);
/*
-bool
-VNTWIFIbRadarPresent(
- void *pMgmtObject,
- unsigned char byChannel
- );
+ bool
+ VNTWIFIbRadarPresent(
+ void *pMgmtObject,
+ unsigned char byChannel
+);
*/
#endif //__VNTWIFI_H__
diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c
index 101c7359f414..d551653537b4 100644
--- a/drivers/staging/vt6655/wcmd.c
+++ b/drivers/staging/vt6655/wcmd.c
@@ -56,48 +56,40 @@
/*--------------------- Static Definitions -------------------------*/
-
-
-
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Functions --------------------------*/
static
void
s_vProbeChannel(
- PSDevice pDevice
- );
-
+ PSDevice pDevice
+);
static
PSTxMgmtPacket
s_MgrMakeProbeRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pScanBSSID,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
-
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pScanBSSID,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
static
bool
-s_bCommandComplete (
- PSDevice pDevice
- );
+s_bCommandComplete(
+ PSDevice pDevice
+);
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
-
/*
* Description:
* Stop AdHoc beacon during scan process
@@ -115,44 +107,37 @@ static
void
vAdHocBeaconStop(PSDevice pDevice)
{
-
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- bool bStop;
-
- /*
- * temporarily stop Beacon packet for AdHoc Server
- * if all of the following conditions are met:
- * (1) STA is in AdHoc mode
- * (2) VT3253 is programmed as automatic Beacon Transmitting
- * (3) One of the following conditions is met
- * (3.1) AdHoc channel is in B/G band and the
- * current scan channel is in A band
- * or
- * (3.2) AdHoc channel is in A mode
- */
- bStop = false;
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
- (pMgmt->eCurrState >= WMAC_STATE_STARTED))
- {
- if ((pMgmt->uIBSSChannel <= CB_MAX_CHANNEL_24G) &&
- (pMgmt->uScanChannel > CB_MAX_CHANNEL_24G))
- {
- bStop = true;
- }
- if (pMgmt->uIBSSChannel > CB_MAX_CHANNEL_24G)
- {
- bStop = true;
- }
- }
-
- if (bStop)
- {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- }
-
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ bool bStop;
+
+ /*
+ * temporarily stop Beacon packet for AdHoc Server
+ * if all of the following conditions are met:
+ * (1) STA is in AdHoc mode
+ * (2) VT3253 is programmed as automatic Beacon Transmitting
+ * (3) One of the following conditions is met
+ * (3.1) AdHoc channel is in B/G band and the
+ * current scan channel is in A band
+ * or
+ * (3.2) AdHoc channel is in A mode
+ */
+ bStop = false;
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
+ (pMgmt->eCurrState >= WMAC_STATE_STARTED)) {
+ if ((pMgmt->uIBSSChannel <= CB_MAX_CHANNEL_24G) &&
+ (pMgmt->uScanChannel > CB_MAX_CHANNEL_24G)) {
+ bStop = true;
+ }
+ if (pMgmt->uIBSSChannel > CB_MAX_CHANNEL_24G) {
+ bStop = true;
+ }
+ }
+
+ if (bStop) {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ }
} /* vAdHocBeaconStop */
-
/*
* Description:
* Restart AdHoc beacon after scan process complete
@@ -170,27 +155,20 @@ static
void
vAdHocBeaconRestart(PSDevice pDevice)
{
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
-
- /*
- * Restart Beacon packet for AdHoc Server
- * if all of the following coditions are met:
- * (1) STA is in AdHoc mode
- * (2) VT3253 is programmed as automatic Beacon Transmitting
- */
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
- (pMgmt->eCurrState >= WMAC_STATE_STARTED))
- {
- MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- }
-
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+
+ /*
+ * Restart Beacon packet for AdHoc Server
+ * if all of the following coditions are met:
+ * (1) STA is in AdHoc mode
+ * (2) VT3253 is programmed as automatic Beacon Transmitting
+ */
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
+ (pMgmt->eCurrState >= WMAC_STATE_STARTED)) {
+ MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ }
}
-
-
-
-
-
/*+
*
* Routine Description:
@@ -200,60 +178,54 @@ vAdHocBeaconRestart(PSDevice pDevice)
* Return Value:
* none.
*
--*/
+ -*/
static
void
s_vProbeChannel(
- PSDevice pDevice
- )
+ PSDevice pDevice
+)
{
- //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
- unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
- unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
- //6M, 9M, 12M, 48M
- unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
- unsigned char *pbyRate;
- PSTxMgmtPacket pTxPacket;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned int ii;
-
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
- pbyRate = &abyCurrSuppRatesA[0];
- } else if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- pbyRate = &abyCurrSuppRatesB[0];
- } else {
- pbyRate = &abyCurrSuppRatesG[0];
- }
- // build an assocreq frame and send it
- pTxPacket = s_MgrMakeProbeRequest
- (
- pDevice,
- pMgmt,
- pMgmt->abyScanBSSID,
- (PWLAN_IE_SSID)pMgmt->abyScanSSID,
- (PWLAN_IE_SUPP_RATES)pbyRate,
- (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRatesG
- );
-
- if (pTxPacket != NULL ){
- for (ii = 0; ii < 2 ; ii++) {
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request sending fail.. \n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request is sending.. \n");
- }
- }
- }
-
+ //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
+ unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
+ unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
+ //6M, 9M, 12M, 48M
+ unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
+ unsigned char *pbyRate;
+ PSTxMgmtPacket pTxPacket;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned int ii;
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11A) {
+ pbyRate = &abyCurrSuppRatesA[0];
+ } else if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ pbyRate = &abyCurrSuppRatesB[0];
+ } else {
+ pbyRate = &abyCurrSuppRatesG[0];
+ }
+ // build an assocreq frame and send it
+ pTxPacket = s_MgrMakeProbeRequest
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->abyScanBSSID,
+ (PWLAN_IE_SSID)pMgmt->abyScanSSID,
+ (PWLAN_IE_SUPP_RATES)pbyRate,
+ (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRatesG
+ );
+
+ if (pTxPacket != NULL) {
+ for (ii = 0; ii < 2; ii++) {
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request sending fail.. \n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request is sending.. \n");
+ }
+ }
+ }
}
-
-
-
/*+
*
* Routine Description:
@@ -263,765 +235,724 @@ s_vProbeChannel(
* Return Value:
* A ptr to Tx frame or NULL on allocation failue
*
--*/
-
+ -*/
PSTxMgmtPacket
s_MgrMakeProbeRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pScanBSSID,
- PWLAN_IE_SSID pSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
-
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pScanBSSID,
+ PWLAN_IE_SSID pSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_PROBEREQ sFrame;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBEREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_PROBEREQ_FR_MAXLEN;
- vMgrEncodeProbeRequest(&sFrame);
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBEREQ)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pScanBSSID, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pScanBSSID, WLAN_BSSID_LEN);
- // Copy the SSID, pSSID->len=0 indicate broadcast SSID
- sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
- sFrame.len += pSSID->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
- // Copy the extension rate set
- if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
- }
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_PROBEREQ sFrame;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBEREQ_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_PROBEREQ_FR_MAXLEN;
+ vMgrEncodeProbeRequest(&sFrame);
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBEREQ)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pScanBSSID, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pScanBSSID, WLAN_BSSID_LEN);
+ // Copy the SSID, pSSID->len=0 indicate broadcast SSID
+ sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pSSID->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSSID, pSSID, pSSID->len + WLAN_IEHDR_LEN);
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
+ // Copy the extension rate set
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
+ }
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ return pTxPacket;
}
-
-
-
-
void
vCommandTimerWait(
- void *hDeviceContext,
- unsigned int MSecond
- )
+ void *hDeviceContext,
+ unsigned int MSecond
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
-
- init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (unsigned long) pDevice;
- pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
- // RUN_AT :1 msec ~= (HZ/1024)
- pDevice->sTimerCommand.expires = (unsigned int)RUN_AT((MSecond * HZ) >> 10);
- add_timer(&pDevice->sTimerCommand);
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+
+ init_timer(&pDevice->sTimerCommand);
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
+ pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
+ // RUN_AT :1 msec ~= (HZ/1024)
+ pDevice->sTimerCommand.expires = (unsigned int)RUN_AT((MSecond * HZ) >> 10);
+ add_timer(&pDevice->sTimerCommand);
+ return;
}
-
-
-
void
-vCommandTimer (
- void *hDeviceContext
- )
+vCommandTimer(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PWLAN_IE_SSID pItemSSID;
- PWLAN_IE_SSID pItemSSIDCurr;
- CMD_STATUS Status;
- unsigned int ii;
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- struct sk_buff *skb;
-
-
- if (pDevice->dwDiagRefCount != 0)
- return;
- if (pDevice->bCmdRunning != true)
- return;
-
- spin_lock_irq(&pDevice->lock);
-
- switch ( pDevice->eCommandState ) {
-
- case WLAN_CMD_SCAN_START:
-
- pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == true) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- s_bCommandComplete(pDevice);
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_SCAN_START\n");
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID;
- // wait all Data TD complete
- if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){
- spin_unlock_irq(&pDevice->lock);
- vCommandTimerWait((void *)pDevice, 10);
- return;
- }
-
- if (pMgmt->uScanChannel == 0 ) {
- pMgmt->uScanChannel = pDevice->byMinChannel;
- // Set Baseband to be more sensitive.
-
- }
- if (pMgmt->uScanChannel > pDevice->byMaxChannel) {
- pMgmt->eScanState = WMAC_NO_SCANNING;
-
- // Set Baseband's sensitivity back.
- // Set channel back
- set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
- } else {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE);
- }
- vAdHocBeaconRestart(pDevice);
- s_bCommandComplete(pDevice);
-
- } else {
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PWLAN_IE_SSID pItemSSID;
+ PWLAN_IE_SSID pItemSSIDCurr;
+ CMD_STATUS Status;
+ unsigned int ii;
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ struct sk_buff *skb;
+
+ if (pDevice->dwDiagRefCount != 0)
+ return;
+ if (pDevice->bCmdRunning != true)
+ return;
+
+ spin_lock_irq(&pDevice->lock);
+
+ switch (pDevice->eCommandState) {
+ case WLAN_CMD_SCAN_START:
+
+ pDevice->byReAssocCount = 0;
+ if (pDevice->bRadioOff == true) {
+ s_bCommandComplete(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ s_bCommandComplete(pDevice);
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_SCAN_START\n");
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID;
+ // wait all Data TD complete
+ if (pDevice->iTDUsed[TYPE_AC0DMA] != 0) {
+ spin_unlock_irq(&pDevice->lock);
+ vCommandTimerWait((void *)pDevice, 10);
+ return;
+ }
+
+ if (pMgmt->uScanChannel == 0) {
+ pMgmt->uScanChannel = pDevice->byMinChannel;
+ // Set Baseband to be more sensitive.
+
+ }
+ if (pMgmt->uScanChannel > pDevice->byMaxChannel) {
+ pMgmt->eScanState = WMAC_NO_SCANNING;
+
+ // Set Baseband's sensitivity back.
+ // Set channel back
+ set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
+ } else {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE);
+ }
+ vAdHocBeaconRestart(pDevice);
+ s_bCommandComplete(pDevice);
+
+ } else {
//2008-8-4 <add> by chester
- if (!is_channel_valid(pMgmt->uScanChannel)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n",pMgmt->uScanChannel);
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
-//printk("chester-pMgmt->uScanChannel=%d,pDevice->byMaxChannel=%d\n",pMgmt->uScanChannel,pDevice->byMaxChannel);
- if (pMgmt->uScanChannel == pDevice->byMinChannel) {
- //pMgmt->eScanType = WMAC_SCAN_ACTIVE;
- pMgmt->abyScanBSSID[0] = 0xFF;
- pMgmt->abyScanBSSID[1] = 0xFF;
- pMgmt->abyScanBSSID[2] = 0xFF;
- pMgmt->abyScanBSSID[3] = 0xFF;
- pMgmt->abyScanBSSID[4] = 0xFF;
- pMgmt->abyScanBSSID[5] = 0xFF;
- pItemSSID->byElementID = WLAN_EID_SSID;
- // clear bssid list
- // BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
- pMgmt->eScanState = WMAC_IS_SCANNING;
-
- }
-
- vAdHocBeaconStop(pDevice);
-
- if (set_channel(pMgmt->pAdapter, pMgmt->uScanChannel) == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SCAN Channel: %d\n", pMgmt->uScanChannel);
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SET SCAN Channel Fail: %d\n", pMgmt->uScanChannel);
- }
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_UNKNOWN);
-// printk("chester-mxch=%d\n",pDevice->byMaxChannel);
- // printk("chester-ch=%d\n",pMgmt->uScanChannel);
- pMgmt->uScanChannel++;
+ if (!is_channel_valid(pMgmt->uScanChannel)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n", pMgmt->uScanChannel);
+ s_bCommandComplete(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ if (pMgmt->uScanChannel == pDevice->byMinChannel) {
+ //pMgmt->eScanType = WMAC_SCAN_ACTIVE;
+ pMgmt->abyScanBSSID[0] = 0xFF;
+ pMgmt->abyScanBSSID[1] = 0xFF;
+ pMgmt->abyScanBSSID[2] = 0xFF;
+ pMgmt->abyScanBSSID[3] = 0xFF;
+ pMgmt->abyScanBSSID[4] = 0xFF;
+ pMgmt->abyScanBSSID[5] = 0xFF;
+ pItemSSID->byElementID = WLAN_EID_SSID;
+ // clear bssid list
+ // BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ pMgmt->eScanState = WMAC_IS_SCANNING;
+
+ }
+
+ vAdHocBeaconStop(pDevice);
+
+ if (set_channel(pMgmt->pAdapter, pMgmt->uScanChannel) == true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SCAN Channel: %d\n", pMgmt->uScanChannel);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SET SCAN Channel Fail: %d\n", pMgmt->uScanChannel);
+ }
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_UNKNOWN);
+ pMgmt->uScanChannel++;
//2008-8-4 <modify> by chester
- if (!is_channel_valid(pMgmt->uScanChannel) &&
- pMgmt->uScanChannel <= pDevice->byMaxChannel ){
- pMgmt->uScanChannel=pDevice->byMaxChannel+1;
- pMgmt->eCommandState = WLAN_CMD_SCAN_END;
-
- }
-
-
- if ((pMgmt->b11hEnable == false) ||
- (pMgmt->uScanChannel < CB_MAX_CHANNEL_24G)) {
- s_vProbeChannel(pDevice);
- spin_unlock_irq(&pDevice->lock);
- vCommandTimerWait((void *)pDevice, WCMD_ACTIVE_SCAN_TIME);
- return;
- } else {
- spin_unlock_irq(&pDevice->lock);
- vCommandTimerWait((void *)pDevice, WCMD_PASSIVE_SCAN_TIME);
- return;
- }
-
- }
-
- break;
-
- case WLAN_CMD_SCAN_END:
-
- // Set Baseband's sensitivity back.
- // Set channel back
- set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
- } else {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE);
- }
-
- pMgmt->eScanState = WMAC_NO_SCANNING;
- vAdHocBeaconRestart(pDevice);
+ if (!is_channel_valid(pMgmt->uScanChannel) &&
+ pMgmt->uScanChannel <= pDevice->byMaxChannel) {
+ pMgmt->uScanChannel = pDevice->byMaxChannel + 1;
+ pMgmt->eCommandState = WLAN_CMD_SCAN_END;
+
+ }
+
+ if ((pMgmt->b11hEnable == false) ||
+ (pMgmt->uScanChannel < CB_MAX_CHANNEL_24G)) {
+ s_vProbeChannel(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ vCommandTimerWait((void *)pDevice, WCMD_ACTIVE_SCAN_TIME);
+ return;
+ } else {
+ spin_unlock_irq(&pDevice->lock);
+ vCommandTimerWait((void *)pDevice, WCMD_PASSIVE_SCAN_TIME);
+ return;
+ }
+
+ }
+
+ break;
+
+ case WLAN_CMD_SCAN_END:
+
+ // Set Baseband's sensitivity back.
+ // Set channel back
+ set_channel(pMgmt->pAdapter, pMgmt->uCurrChannel);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
+ } else {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_INFRASTRUCTURE);
+ }
+
+ pMgmt->eScanState = WMAC_NO_SCANNING;
+ vAdHocBeaconRestart(pDevice);
//2008-0409-07, <Add> by Einsn Liu
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- if(pMgmt->eScanType == WMAC_SCAN_PASSIVE)
- {//send scan event to wpa_Supplicant
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
- }
+ if (pMgmt->eScanType == WMAC_SCAN_PASSIVE)
+ {//send scan event to wpa_Supplicant
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
#endif
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_CMD_DISASSOCIATE_START :
- pDevice->byReAssocCount = 0;
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pMgmt->eCurrState != WMAC_STATE_ASSOC)) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send Disassociation Packet..\n");
- // reason = 8 : disassoc because sta has left
- vMgrDisassocBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (8), &Status);
- pDevice->bLinkPass = false;
- // unlock command busy
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
- pItemSSID->len = 0;
- memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pMgmt->sNodeDBTable[0].bActive = false;
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_DISASSOCIATE_START:
+ pDevice->byReAssocCount = 0;
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pMgmt->eCurrState != WMAC_STATE_ASSOC)) {
+ s_bCommandComplete(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Disassociation Packet..\n");
+ // reason = 8 : disassoc because sta has left
+ vMgrDisassocBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (8), &Status);
+ pDevice->bLinkPass = false;
+ // unlock command busy
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+ pItemSSID->len = 0;
+ memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pMgmt->sNodeDBTable[0].bActive = false;
// pDevice->bBeaconBufReady = false;
- }
- netif_stop_queue(pDevice->dev);
- pDevice->eCommandState = WLAN_DISASSOCIATE_WAIT;
- // wait all Control TD complete
- if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){
- vCommandTimerWait((void *)pDevice, 10);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" CARDbRadioPowerOff\n");
- //2008-09-02 <mark> by chester
- // CARDbRadioPowerOff(pDevice);
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_DISASSOCIATE_WAIT :
- // wait all Control TD complete
- if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){
- vCommandTimerWait((void *)pDevice, 10);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
+ }
+ netif_stop_queue(pDevice->dev);
+ pDevice->eCommandState = WLAN_DISASSOCIATE_WAIT;
+ // wait all Control TD complete
+ if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) {
+ vCommandTimerWait((void *)pDevice, 10);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " CARDbRadioPowerOff\n");
+ //2008-09-02 <mark> by chester
+ // CARDbRadioPowerOff(pDevice);
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_DISASSOCIATE_WAIT:
+ // wait all Control TD complete
+ if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) {
+ vCommandTimerWait((void *)pDevice, 10);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
//2008-09-02 <mark> by chester
- // CARDbRadioPowerOff(pDevice);
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_CMD_SSID_START:
- pDevice->byReAssocCount = 0;
- if (pDevice->bRadioOff == true) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
-//printk("chester-currmode=%d\n",pMgmt->eCurrMode);
-printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID);
- //memcpy(pMgmt->abyAdHocSSID,pMgmt->abyDesireSSID,
- //((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN);
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
- pItemSSIDCurr = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cmd: desire ssid = %s\n", pItemSSID->abySSID);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" cmd: curr ssid = %s\n", pItemSSIDCurr->abySSID);
-
- if (pMgmt->eCurrState == WMAC_STATE_ASSOC) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Cmd pMgmt->eCurrState == WMAC_STATE_ASSOC\n");
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pItemSSID->len =%d\n",pItemSSID->len);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" pItemSSIDCurr->len = %d\n",pItemSSIDCurr->len);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" desire ssid = %s\n", pItemSSID->abySSID);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" curr ssid = %s\n", pItemSSIDCurr->abySSID);
- }
-
- if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
- ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)&& (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
-
- if (pItemSSID->len == pItemSSIDCurr->len) {
- if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) {
- s_bCommandComplete(pDevice);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
- }
-
- netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
- }
- // set initial state
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- PSvDisablePowerSaving((void *)pDevice);
- BSSvClearNodeDBTable(pDevice, 0);
-
- vMgrJoinBSSBegin((void *)pDevice, &Status);
- // if Infra mode
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) {
-
- // Call mgr to begin the deauthentication
- // reason = (3) because sta has left ESS
- if (pMgmt->eCurrState>= WMAC_STATE_AUTH) {
- vMgrDeAuthenBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (3), &Status);
- }
- // Call mgr to begin the authentication
- vMgrAuthenBeginSta((void *)pDevice, pMgmt, &Status);
- if (Status == CMD_STATUS_SUCCESS) {
+ // CARDbRadioPowerOff(pDevice);
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_SSID_START:
+ pDevice->byReAssocCount = 0;
+ if (pDevice->bRadioOff == true) {
+ s_bCommandComplete(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ printk("chester-abyDesireSSID=%s\n", ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySSID);
+ //memcpy(pMgmt->abyAdHocSSID,pMgmt->abyDesireSSID,
+ //((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN);
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+ pItemSSIDCurr = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " cmd: desire ssid = %s\n", pItemSSID->abySSID);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " cmd: curr ssid = %s\n", pItemSSIDCurr->abySSID);
+
+ if (pMgmt->eCurrState == WMAC_STATE_ASSOC) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Cmd pMgmt->eCurrState == WMAC_STATE_ASSOC\n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pItemSSID->len =%d\n", pItemSSID->len);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " pItemSSIDCurr->len = %d\n", pItemSSIDCurr->len);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " desire ssid = %s\n", pItemSSID->abySSID);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " curr ssid = %s\n", pItemSSIDCurr->abySSID);
+ }
+
+ if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) ||
+ ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
+ if (pItemSSID->len == pItemSSIDCurr->len) {
+ if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) {
+ s_bCommandComplete(pDevice);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ }
+
+ netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+ }
+ // set initial state
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ PSvDisablePowerSaving((void *)pDevice);
+ BSSvClearNodeDBTable(pDevice, 0);
+
+ vMgrJoinBSSBegin((void *)pDevice, &Status);
+ // if Infra mode
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) {
+ // Call mgr to begin the deauthentication
+ // reason = (3) because sta has left ESS
+ if (pMgmt->eCurrState >= WMAC_STATE_AUTH) {
+ vMgrDeAuthenBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (3), &Status);
+ }
+ // Call mgr to begin the authentication
+ vMgrAuthenBeginSta((void *)pDevice, pMgmt, &Status);
+ if (Status == CMD_STATUS_SUCCESS) {
+ pDevice->byLinkWaitCount = 0;
+ pDevice->eCommandState = WLAN_AUTHENTICATE_WAIT;
+ vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT);
+ spin_unlock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Set eCommandState = WLAN_AUTHENTICATE_WAIT\n");
+ return;
+ }
+ }
+ // if Adhoc mode
+ else if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ if (pMgmt->eCurrState == WMAC_STATE_JOINTED) {
+ if (netif_queue_stopped(pDevice->dev)) {
+ netif_wake_queue(pDevice->dev);
+ }
+ pDevice->bLinkPass = true;
+
+ pMgmt->sNodeDBTable[0].bActive = true;
+ pMgmt->sNodeDBTable[0].uInActiveCount = 0;
+ bClearBSSID_SCAN(pDevice);
+ } else {
+ // start own IBSS
+ vMgrCreateOwnIBSS((void *)pDevice, &Status);
+ if (Status != CMD_STATUS_SUCCESS) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n");
+ }
+ BSSvAddMulticastNode(pDevice);
+ }
+ }
+ // if SSID not found
+ else if (pMgmt->eCurrMode == WMAC_MODE_STANDBY) {
+ if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA ||
+ pMgmt->eConfigMode == WMAC_CONFIG_AUTO) {
+ // start own IBSS
+ vMgrCreateOwnIBSS((void *)pDevice, &Status);
+ if (Status != CMD_STATUS_SUCCESS) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n");
+ }
+ BSSvAddMulticastNode(pDevice);
+ if (netif_queue_stopped(pDevice->dev)) {
+ netif_wake_queue(pDevice->dev);
+ }
+ pDevice->bLinkPass = true;
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disconnect SSID none\n");
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ printk("wireless_send_event--->SIOCGIWAP(disassociated:vMgrJoinBSSBegin Fail !!)\n");
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+
+ }
+ }
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_AUTHENTICATE_WAIT:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_AUTHENTICATE_WAIT\n");
+ if (pMgmt->eCurrState == WMAC_STATE_AUTH) {
+ // Call mgr to begin the association
+ pDevice->byLinkWaitCount = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCurrState == WMAC_STATE_AUTH\n");
+ vMgrAssocBeginSta((void *)pDevice, pMgmt, &Status);
+ if (Status == CMD_STATUS_SUCCESS) {
+ pDevice->byLinkWaitCount = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState = WLAN_ASSOCIATE_WAIT\n");
+ pDevice->eCommandState = WLAN_ASSOCIATE_WAIT;
+ vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ }
+
+ else if (pMgmt->eCurrState < WMAC_STATE_AUTHPENDING) {
+ printk("WLAN_AUTHENTICATE_WAIT:Authen Fail???\n");
+ } else if (pDevice->byLinkWaitCount <= 4) { //mike add:wait another 2 sec if authenticated_frame delay!
+ pDevice->byLinkWaitCount++;
+ printk("WLAN_AUTHENTICATE_WAIT:wait %d times!!\n", pDevice->byLinkWaitCount);
+ spin_unlock_irq(&pDevice->lock);
+ vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT/2);
+ return;
+ }
pDevice->byLinkWaitCount = 0;
- pDevice->eCommandState = WLAN_AUTHENTICATE_WAIT;
- vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT);
- spin_unlock_irq(&pDevice->lock);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Set eCommandState = WLAN_AUTHENTICATE_WAIT\n");
- return;
- }
- }
- // if Adhoc mode
- else if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- if (pMgmt->eCurrState == WMAC_STATE_JOINTED) {
- if (netif_queue_stopped(pDevice->dev)){
- netif_wake_queue(pDevice->dev);
- }
- pDevice->bLinkPass = true;
-
- pMgmt->sNodeDBTable[0].bActive = true;
- pMgmt->sNodeDBTable[0].uInActiveCount = 0;
- bClearBSSID_SCAN(pDevice);
- }
- else {
- // start own IBSS
- vMgrCreateOwnIBSS((void *)pDevice, &Status);
- if (Status != CMD_STATUS_SUCCESS){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " WLAN_CMD_IBSS_CREATE fail ! \n");
- }
- BSSvAddMulticastNode(pDevice);
- }
- }
- // if SSID not found
- else if (pMgmt->eCurrMode == WMAC_MODE_STANDBY) {
- if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA ||
- pMgmt->eConfigMode == WMAC_CONFIG_AUTO) {
- // start own IBSS
- vMgrCreateOwnIBSS((void *)pDevice, &Status);
- if (Status != CMD_STATUS_SUCCESS){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" WLAN_CMD_IBSS_CREATE fail ! \n");
- }
- BSSvAddMulticastNode(pDevice);
- if (netif_queue_stopped(pDevice->dev)){
- netif_wake_queue(pDevice->dev);
- }
- pDevice->bLinkPass = true;
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Disconnect SSID none\n");
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == true)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- printk("wireless_send_event--->SIOCGIWAP(disassociated:vMgrJoinBSSBegin Fail !!)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
-
- }
- }
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_AUTHENTICATE_WAIT :
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_AUTHENTICATE_WAIT\n");
- if (pMgmt->eCurrState == WMAC_STATE_AUTH) {
- // Call mgr to begin the association
- pDevice->byLinkWaitCount = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCurrState == WMAC_STATE_AUTH\n");
- vMgrAssocBeginSta((void *)pDevice, pMgmt, &Status);
- if (Status == CMD_STATUS_SUCCESS) {
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_ASSOCIATE_WAIT:
+ if (pMgmt->eCurrState == WMAC_STATE_ASSOC) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCurrState == WMAC_STATE_ASSOC\n");
+ if (pDevice->ePSMode != WMAC_POWER_CAM) {
+ PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
+ }
+ if (pMgmt->eAuthenMode >= WMAC_AUTH_WPA) {
+ KeybRemoveAllKey(&(pDevice->sKey), pDevice->abyBSSID, pDevice->PortOffset);
+ }
+ pDevice->bLinkPass = true;
+ pDevice->byLinkWaitCount = 0;
+ pDevice->byReAssocCount = 0;
+ bClearBSSID_SCAN(pDevice);
+ if (pDevice->byFOETuning) {
+ BBvSetFOE(pDevice->PortOffset);
+ PSbSendNullPacket(pDevice);
+ }
+ if (netif_queue_stopped(pDevice->dev)) {
+ netif_wake_queue(pDevice->dev);
+ }
+#ifdef TxInSleep
+ if (pDevice->IsTxDataTrigger != false) { //TxDataTimer is not triggered at the first time
+ del_timer(&pDevice->sTimerTxData);
+ init_timer(&pDevice->sTimerTxData);
+ pDevice->sTimerTxData.data = (unsigned long) pDevice;
+ pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
+ pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
+ pDevice->fTxDataInSleep = false;
+ pDevice->nTxDataTimeCout = 0;
+ } else {
+ }
+ pDevice->IsTxDataTrigger = true;
+ add_timer(&pDevice->sTimerTxData);
+#endif
+ } else if (pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) {
+ printk("WLAN_ASSOCIATE_WAIT:Association Fail???\n");
+ } else if (pDevice->byLinkWaitCount <= 4) { //mike add:wait another 2 sec if associated_frame delay!
+ pDevice->byLinkWaitCount++;
+ printk("WLAN_ASSOCIATE_WAIT:wait %d times!!\n", pDevice->byLinkWaitCount);
+ spin_unlock_irq(&pDevice->lock);
+ vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT/2);
+ return;
+ }
pDevice->byLinkWaitCount = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState = WLAN_ASSOCIATE_WAIT\n");
- pDevice->eCommandState = WLAN_ASSOCIATE_WAIT;
- vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
- }
-
- else if(pMgmt->eCurrState < WMAC_STATE_AUTHPENDING) {
- printk("WLAN_AUTHENTICATE_WAIT:Authen Fail???\n");
- }
- else if(pDevice->byLinkWaitCount <= 4){ //mike add:wait another 2 sec if authenticated_frame delay!
- pDevice->byLinkWaitCount ++;
- printk("WLAN_AUTHENTICATE_WAIT:wait %d times!!\n",pDevice->byLinkWaitCount);
- spin_unlock_irq(&pDevice->lock);
- vCommandTimerWait((void *)pDevice, AUTHENTICATE_TIMEOUT/2);
- return;
- }
- pDevice->byLinkWaitCount = 0;
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_ASSOCIATE_WAIT :
- if (pMgmt->eCurrState == WMAC_STATE_ASSOC) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCurrState == WMAC_STATE_ASSOC\n");
- if (pDevice->ePSMode != WMAC_POWER_CAM) {
- PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
- }
- if (pMgmt->eAuthenMode >= WMAC_AUTH_WPA) {
- KeybRemoveAllKey(&(pDevice->sKey), pDevice->abyBSSID, pDevice->PortOffset);
- }
- pDevice->bLinkPass = true;
- pDevice->byLinkWaitCount = 0;
- pDevice->byReAssocCount = 0;
- bClearBSSID_SCAN(pDevice);
- if (pDevice->byFOETuning) {
- BBvSetFOE(pDevice->PortOffset);
- PSbSendNullPacket(pDevice);
- }
- if (netif_queue_stopped(pDevice->dev)){
- netif_wake_queue(pDevice->dev);
- }
- #ifdef TxInSleep
- if(pDevice->IsTxDataTrigger != false) { //TxDataTimer is not triggered at the first time
- // printk("Re-initial TxDataTimer****\n");
- del_timer(&pDevice->sTimerTxData);
- init_timer(&pDevice->sTimerTxData);
- pDevice->sTimerTxData.data = (unsigned long) pDevice;
- pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
- pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- pDevice->fTxDataInSleep = false;
- pDevice->nTxDataTimeCout = 0;
- }
- else {
- // printk("mike:-->First time trigger TimerTxData InSleep\n");
- }
- pDevice->IsTxDataTrigger = true;
- add_timer(&pDevice->sTimerTxData);
- #endif
- }
- else if(pMgmt->eCurrState < WMAC_STATE_ASSOCPENDING) {
- printk("WLAN_ASSOCIATE_WAIT:Association Fail???\n");
- }
- else if(pDevice->byLinkWaitCount <= 4){ //mike add:wait another 2 sec if associated_frame delay!
- pDevice->byLinkWaitCount ++;
- printk("WLAN_ASSOCIATE_WAIT:wait %d times!!\n",pDevice->byLinkWaitCount);
- spin_unlock_irq(&pDevice->lock);
- vCommandTimerWait((void *)pDevice, ASSOCIATE_TIMEOUT/2);
- return;
- }
- pDevice->byLinkWaitCount = 0;
-
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_CMD_AP_MODE_START :
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_AP_MODE_START\n");
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- del_timer(&pMgmt->sTimerSecondCallback);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pDevice->bLinkPass = false;
- if (pDevice->bEnableHostWEP == true)
- BSSvClearNodeDBTable(pDevice, 1);
- else
- BSSvClearNodeDBTable(pDevice, 0);
- pDevice->uAssocCount = 0;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pDevice->bFixRate = false;
-
- vMgrCreateOwnIBSS((void *)pDevice, &Status);
- if (Status != CMD_STATUS_SUCCESS){
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " vMgrCreateOwnIBSS fail ! \n");
- }
- // alway turn off unicast bit
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_UNICAST);
- pDevice->byRxMode &= ~RCR_UNICAST;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode );
- BSSvAddMulticastNode(pDevice);
- if (netif_queue_stopped(pDevice->dev)){
- netif_wake_queue(pDevice->dev);
- }
- pDevice->bLinkPass = true;
- add_timer(&pMgmt->sTimerSecondCallback);
- }
- s_bCommandComplete(pDevice);
- break;
-
- case WLAN_CMD_TX_PSPACKET_START :
- // DTIM Multicast tx
- if (pMgmt->sNodeDBTable[0].bRxPSPoll) {
- while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[0].sTxPSQueue)) != NULL) {
- if (skb_queue_empty(&pMgmt->sNodeDBTable[0].sTxPSQueue)) {
- pMgmt->abyPSTxMap[0] &= ~byMask[0];
- pDevice->bMoreData = false;
- }
- else {
- pDevice->bMoreData = true;
- }
- if (!device_dma0_xmit(pDevice, skb, 0)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Multicast ps tx fail \n");
- }
- pMgmt->sNodeDBTable[0].wEnQueueCnt--;
- }
- }
-
- // PS nodes tx
- for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
- if (pMgmt->sNodeDBTable[ii].bActive &&
- pMgmt->sNodeDBTable[ii].bRxPSPoll) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d Enqueu Cnt= %d\n",
- ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt);
- while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL) {
- if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) {
- // clear tx map
- pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &=
- ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
- pDevice->bMoreData = false;
- }
- else {
- pDevice->bMoreData = true;
- }
- if (!device_dma0_xmit(pDevice, skb, ii)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n");
- }
- pMgmt->sNodeDBTable[ii].wEnQueueCnt--;
- // check if sta ps enabled, and wait next pspoll.
- // if sta ps disable, then send all pending buffers.
- if (pMgmt->sNodeDBTable[ii].bPSEnable)
- break;
- }
- if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) {
- // clear tx map
- pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &=
- ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d PS queue clear \n", ii);
- }
- pMgmt->sNodeDBTable[ii].bRxPSPoll = false;
- }
- }
-
- s_bCommandComplete(pDevice);
- break;
-
-
- case WLAN_CMD_RADIO_START :
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_RADIO_START\n");
- if (pDevice->bRadioCmd == true)
- CARDbRadioPowerOn(pDevice);
- else
- CARDbRadioPowerOff(pDevice);
-
- s_bCommandComplete(pDevice);
- break;
-
-
- case WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE :
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState == WLAN_CMD_CHECK_BBSENSITIVITY_START\n");
- // wait all TD complete
- if (pDevice->iTDUsed[TYPE_AC0DMA] != 0){
- vCommandTimerWait((void *)pDevice, 10);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
- if (pDevice->iTDUsed[TYPE_TXDMA0] != 0){
- vCommandTimerWait((void *)pDevice, 10);
- spin_unlock_irq(&pDevice->lock);
- return;
- }
- pDevice->byBBVGACurrent = pDevice->byBBVGANew;
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"SetVGAGainOffset %02X\n", pDevice->byBBVGACurrent);
- s_bCommandComplete(pDevice);
- break;
-
- default :
- s_bCommandComplete(pDevice);
- break;
-
- } //switch
- spin_unlock_irq(&pDevice->lock);
- return;
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_AP_MODE_START:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_AP_MODE_START\n");
+
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ del_timer(&pMgmt->sTimerSecondCallback);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pDevice->bLinkPass = false;
+ if (pDevice->bEnableHostWEP == true)
+ BSSvClearNodeDBTable(pDevice, 1);
+ else
+ BSSvClearNodeDBTable(pDevice, 0);
+ pDevice->uAssocCount = 0;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pDevice->bFixRate = false;
+
+ vMgrCreateOwnIBSS((void *)pDevice, &Status);
+ if (Status != CMD_STATUS_SUCCESS) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " vMgrCreateOwnIBSS fail ! \n");
+ }
+ // alway turn off unicast bit
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_UNICAST);
+ pDevice->byRxMode &= ~RCR_UNICAST;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode);
+ BSSvAddMulticastNode(pDevice);
+ if (netif_queue_stopped(pDevice->dev)) {
+ netif_wake_queue(pDevice->dev);
+ }
+ pDevice->bLinkPass = true;
+ add_timer(&pMgmt->sTimerSecondCallback);
+ }
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_TX_PSPACKET_START:
+ // DTIM Multicast tx
+ if (pMgmt->sNodeDBTable[0].bRxPSPoll) {
+ while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[0].sTxPSQueue)) != NULL) {
+ if (skb_queue_empty(&pMgmt->sNodeDBTable[0].sTxPSQueue)) {
+ pMgmt->abyPSTxMap[0] &= ~byMask[0];
+ pDevice->bMoreData = false;
+ } else {
+ pDevice->bMoreData = true;
+ }
+ if (!device_dma0_xmit(pDevice, skb, 0)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Multicast ps tx fail \n");
+ }
+ pMgmt->sNodeDBTable[0].wEnQueueCnt--;
+ }
+ }
+
+ // PS nodes tx
+ for (ii = 1; ii < (MAX_NODE_NUM + 1); ii++) {
+ if (pMgmt->sNodeDBTable[ii].bActive &&
+ pMgmt->sNodeDBTable[ii].bRxPSPoll) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d Enqueu Cnt= %d\n",
+ ii, pMgmt->sNodeDBTable[ii].wEnQueueCnt);
+ while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) != NULL) {
+ if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) {
+ // clear tx map
+ pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &=
+ ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
+ pDevice->bMoreData = false;
+ } else {
+ pDevice->bMoreData = true;
+ }
+ if (!device_dma0_xmit(pDevice, skb, ii)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n");
+ }
+ pMgmt->sNodeDBTable[ii].wEnQueueCnt--;
+ // check if sta ps enabled, and wait next pspoll.
+ // if sta ps disable, then send all pending buffers.
+ if (pMgmt->sNodeDBTable[ii].bPSEnable)
+ break;
+ }
+ if (skb_queue_empty(&pMgmt->sNodeDBTable[ii].sTxPSQueue)) {
+ // clear tx map
+ pMgmt->abyPSTxMap[pMgmt->sNodeDBTable[ii].wAID >> 3] &=
+ ~byMask[pMgmt->sNodeDBTable[ii].wAID & 7];
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Index=%d PS queue clear \n", ii);
+ }
+ pMgmt->sNodeDBTable[ii].bRxPSPoll = false;
+ }
+ }
+
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_RADIO_START:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_RADIO_START\n");
+ if (pDevice->bRadioCmd == true)
+ CARDbRadioPowerOn(pDevice);
+ else
+ CARDbRadioPowerOff(pDevice);
+
+ s_bCommandComplete(pDevice);
+ break;
+
+ case WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE:
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState == WLAN_CMD_CHECK_BBSENSITIVITY_START\n");
+ // wait all TD complete
+ if (pDevice->iTDUsed[TYPE_AC0DMA] != 0) {
+ vCommandTimerWait((void *)pDevice, 10);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ if (pDevice->iTDUsed[TYPE_TXDMA0] != 0) {
+ vCommandTimerWait((void *)pDevice, 10);
+ spin_unlock_irq(&pDevice->lock);
+ return;
+ }
+ pDevice->byBBVGACurrent = pDevice->byBBVGANew;
+ BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "SetVGAGainOffset %02X\n", pDevice->byBBVGACurrent);
+ s_bCommandComplete(pDevice);
+ break;
+
+ default:
+ s_bCommandComplete(pDevice);
+ break;
+
+ } //switch
+ spin_unlock_irq(&pDevice->lock);
+ return;
}
-
static
bool
-s_bCommandComplete (
- PSDevice pDevice
- )
+s_bCommandComplete(
+ PSDevice pDevice
+)
{
- PWLAN_IE_SSID pSSID;
- bool bRadioCmd = false;
- //unsigned short wDeAuthenReason = 0;
- bool bForceSCAN = true;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- pDevice->eCommandState = WLAN_CMD_IDLE;
- if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) {
- //Command Queue Empty
- pDevice->bCmdRunning = false;
- return true;
- }
- else {
- pDevice->eCommand = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].eCmd;
- pSSID = (PWLAN_IE_SSID)pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].abyCmdDesireSSID;
- bRadioCmd = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bRadioCmd;
- bForceSCAN = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bForceSCAN;
- ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdDequeueIdx, CMD_Q_SIZE);
- pDevice->cbFreeCmdQueue++;
- pDevice->bCmdRunning = true;
- switch ( pDevice->eCommand ) {
- case WLAN_CMD_BSSID_SCAN:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_BSSID_SCAN\n");
- pDevice->eCommandState = WLAN_CMD_SCAN_START;
- pMgmt->uScanChannel = 0;
- if (pSSID->len != 0) {
- memcpy(pMgmt->abyScanSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- } else {
- memset(pMgmt->abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- }
+ PWLAN_IE_SSID pSSID;
+ bool bRadioCmd = false;
+ //unsigned short wDeAuthenReason = 0;
+ bool bForceSCAN = true;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ pDevice->eCommandState = WLAN_CMD_IDLE;
+ if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) {
+ //Command Queue Empty
+ pDevice->bCmdRunning = false;
+ return true;
+ } else {
+ pDevice->eCommand = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].eCmd;
+ pSSID = (PWLAN_IE_SSID)pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].abyCmdDesireSSID;
+ bRadioCmd = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bRadioCmd;
+ bForceSCAN = pDevice->eCmdQueue[pDevice->uCmdDequeueIdx].bForceSCAN;
+ ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdDequeueIdx, CMD_Q_SIZE);
+ pDevice->cbFreeCmdQueue++;
+ pDevice->bCmdRunning = true;
+ switch (pDevice->eCommand) {
+ case WLAN_CMD_BSSID_SCAN:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_BSSID_SCAN\n");
+ pDevice->eCommandState = WLAN_CMD_SCAN_START;
+ pMgmt->uScanChannel = 0;
+ if (pSSID->len != 0) {
+ memcpy(pMgmt->abyScanSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ } else {
+ memset(pMgmt->abyScanSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ }
/*
- if ((bForceSCAN == false) && (pDevice->bLinkPass == true)) {
- if ((pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) &&
- ( !memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, pSSID->len))) {
- pDevice->eCommandState = WLAN_CMD_IDLE;
- }
- }
+ if ((bForceSCAN == false) && (pDevice->bLinkPass == true)) {
+ if ((pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) &&
+ (!memcmp(pSSID->abySSID, ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID, pSSID->len))) {
+ pDevice->eCommandState = WLAN_CMD_IDLE;
+ }
+ }
*/
- break;
- case WLAN_CMD_SSID:
- pDevice->eCommandState = WLAN_CMD_SSID_START;
- if (pSSID->len > WLAN_SSID_MAXLEN)
- pSSID->len = WLAN_SSID_MAXLEN;
- if (pSSID->len != 0)
- memcpy(pDevice->pMgmt->abyDesireSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"eCommandState= WLAN_CMD_SSID_START\n");
- break;
- case WLAN_CMD_DISASSOCIATE:
- pDevice->eCommandState = WLAN_CMD_DISASSOCIATE_START;
- break;
- case WLAN_CMD_RX_PSPOLL:
- pDevice->eCommandState = WLAN_CMD_TX_PSPACKET_START;
- break;
- case WLAN_CMD_RUN_AP:
- pDevice->eCommandState = WLAN_CMD_AP_MODE_START;
- break;
- case WLAN_CMD_RADIO:
- pDevice->eCommandState = WLAN_CMD_RADIO_START;
- pDevice->bRadioCmd = bRadioCmd;
- break;
- case WLAN_CMD_CHANGE_BBSENSITIVITY:
- pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE;
- break;
-
- default:
- break;
-
- }
-
- vCommandTimerWait((void *)pDevice, 0);
- }
-
- return true;
+ break;
+ case WLAN_CMD_SSID:
+ pDevice->eCommandState = WLAN_CMD_SSID_START;
+ if (pSSID->len > WLAN_SSID_MAXLEN)
+ pSSID->len = WLAN_SSID_MAXLEN;
+ if (pSSID->len != 0)
+ memcpy(pDevice->pMgmt->abyDesireSSID, pSSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "eCommandState= WLAN_CMD_SSID_START\n");
+ break;
+ case WLAN_CMD_DISASSOCIATE:
+ pDevice->eCommandState = WLAN_CMD_DISASSOCIATE_START;
+ break;
+ case WLAN_CMD_RX_PSPOLL:
+ pDevice->eCommandState = WLAN_CMD_TX_PSPACKET_START;
+ break;
+ case WLAN_CMD_RUN_AP:
+ pDevice->eCommandState = WLAN_CMD_AP_MODE_START;
+ break;
+ case WLAN_CMD_RADIO:
+ pDevice->eCommandState = WLAN_CMD_RADIO_START;
+ pDevice->bRadioCmd = bRadioCmd;
+ break;
+ case WLAN_CMD_CHANGE_BBSENSITIVITY:
+ pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE;
+ break;
+
+ default:
+ break;
+
+ }
+
+ vCommandTimerWait((void *)pDevice, 0);
+ }
+
+ return true;
}
-
-
-bool bScheduleCommand (
- void *hDeviceContext,
- CMD_CODE eCommand,
- unsigned char *pbyItem0
- )
+bool bScheduleCommand(
+ void *hDeviceContext,
+ CMD_CODE eCommand,
+ unsigned char *pbyItem0
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
-
-
- if (pDevice->cbFreeCmdQueue == 0) {
- return (false);
- }
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].eCmd = eCommand;
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = true;
- memset(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, 0 , WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-
- if (pbyItem0 != NULL) {
- switch (eCommand) {
-
- case WLAN_CMD_BSSID_SCAN:
- memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID,
- pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = false;
- break;
-
- case WLAN_CMD_SSID:
- memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID,
- pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- break;
-
- case WLAN_CMD_DISASSOCIATE:
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bNeedRadioOFF = *((int *)pbyItem0);
- break;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+
+ if (pDevice->cbFreeCmdQueue == 0) {
+ return false;
+ }
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].eCmd = eCommand;
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = true;
+ memset(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID, 0 , WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+
+ if (pbyItem0 != NULL) {
+ switch (eCommand) {
+ case WLAN_CMD_BSSID_SCAN:
+ memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID,
+ pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bForceSCAN = false;
+ break;
+
+ case WLAN_CMD_SSID:
+ memcpy(pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].abyCmdDesireSSID,
+ pbyItem0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ break;
+
+ case WLAN_CMD_DISASSOCIATE:
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bNeedRadioOFF = *((int *)pbyItem0);
+ break;
/*
- case WLAN_CMD_DEAUTH:
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((unsigned short *)pbyItem0);
- break;
+ case WLAN_CMD_DEAUTH:
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((unsigned short *)pbyItem0);
+ break;
*/
- case WLAN_CMD_RX_PSPOLL:
- break;
+ case WLAN_CMD_RX_PSPOLL:
+ break;
- case WLAN_CMD_RADIO:
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bRadioCmd = *((int *)pbyItem0);
- break;
+ case WLAN_CMD_RADIO:
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].bRadioCmd = *((int *)pbyItem0);
+ break;
- case WLAN_CMD_CHANGE_BBSENSITIVITY:
- pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE;
- break;
+ case WLAN_CMD_CHANGE_BBSENSITIVITY:
+ pDevice->eCommandState = WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE;
+ break;
- default:
- break;
- }
- }
+ default:
+ break;
+ }
+ }
- ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdEnqueueIdx, CMD_Q_SIZE);
- pDevice->cbFreeCmdQueue--;
-
- if (pDevice->bCmdRunning == false) {
- s_bCommandComplete(pDevice);
- }
- else {
- }
- return (true);
+ ADD_ONE_WITH_WRAP_AROUND(pDevice->uCmdEnqueueIdx, CMD_Q_SIZE);
+ pDevice->cbFreeCmdQueue--;
+ if (pDevice->bCmdRunning == false) {
+ s_bCommandComplete(pDevice);
+ } else {
+ }
+ return true;
}
/*
@@ -1038,87 +969,81 @@ bool bScheduleCommand (
* Return Value: true if success; otherwise false
*
*/
-bool bClearBSSID_SCAN (
- void *hDeviceContext
- )
+bool bClearBSSID_SCAN(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- unsigned int uCmdDequeueIdx = pDevice->uCmdDequeueIdx;
- unsigned int ii;
-
- if ((pDevice->cbFreeCmdQueue < CMD_Q_SIZE) && (uCmdDequeueIdx != pDevice->uCmdEnqueueIdx)) {
- for (ii = 0; ii < (CMD_Q_SIZE - pDevice->cbFreeCmdQueue); ii ++) {
- if (pDevice->eCmdQueue[uCmdDequeueIdx].eCmd == WLAN_CMD_BSSID_SCAN)
- pDevice->eCmdQueue[uCmdDequeueIdx].eCmd = WLAN_CMD_IDLE;
- ADD_ONE_WITH_WRAP_AROUND(uCmdDequeueIdx, CMD_Q_SIZE);
- if (uCmdDequeueIdx == pDevice->uCmdEnqueueIdx)
- break;
- }
- }
- return true;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ unsigned int uCmdDequeueIdx = pDevice->uCmdDequeueIdx;
+ unsigned int ii;
+
+ if ((pDevice->cbFreeCmdQueue < CMD_Q_SIZE) && (uCmdDequeueIdx != pDevice->uCmdEnqueueIdx)) {
+ for (ii = 0; ii < (CMD_Q_SIZE - pDevice->cbFreeCmdQueue); ii++) {
+ if (pDevice->eCmdQueue[uCmdDequeueIdx].eCmd == WLAN_CMD_BSSID_SCAN)
+ pDevice->eCmdQueue[uCmdDequeueIdx].eCmd = WLAN_CMD_IDLE;
+ ADD_ONE_WITH_WRAP_AROUND(uCmdDequeueIdx, CMD_Q_SIZE);
+ if (uCmdDequeueIdx == pDevice->uCmdEnqueueIdx)
+ break;
+ }
+ }
+ return true;
}
//mike add:reset command timer
void
vResetCommandTimer(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
-
- //delete timer
- del_timer(&pDevice->sTimerCommand);
- //init timer
- init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (unsigned long) pDevice;
- pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
- pDevice->sTimerCommand.expires = RUN_AT(HZ);
- pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
- pDevice->uCmdDequeueIdx = 0;
- pDevice->uCmdEnqueueIdx = 0;
- pDevice->eCommandState = WLAN_CMD_IDLE;
- pDevice->bCmdRunning = false;
- pDevice->bCmdClear = false;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+
+ //delete timer
+ del_timer(&pDevice->sTimerCommand);
+ //init timer
+ init_timer(&pDevice->sTimerCommand);
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
+ pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
+ pDevice->sTimerCommand.expires = RUN_AT(HZ);
+ pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
+ pDevice->uCmdDequeueIdx = 0;
+ pDevice->uCmdEnqueueIdx = 0;
+ pDevice->eCommandState = WLAN_CMD_IDLE;
+ pDevice->bCmdRunning = false;
+ pDevice->bCmdClear = false;
}
-
#ifdef TxInSleep
void
BSSvSecondTxData(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- pDevice->nTxDataTimeCout++;
-
- if(pDevice->nTxDataTimeCout<4) //don't tx data if timer less than 40s
- {
- // printk("mike:%s-->no data Tx not exceed the desired Time as %d\n",__FUNCTION__,
- // (int)pDevice->nTxDataTimeCout);
- pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- add_timer(&pDevice->sTimerTxData);
- return;
- }
-
- spin_lock_irq(&pDevice->lock);
- #if 1
- if(((pDevice->bLinkPass ==true)&&(pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking
- (pDevice->fWPA_Authened == true)) { //wpa linking
- #else
- if(pDevice->bLinkPass ==true) {
- #endif
-
- // printk("mike:%s-->InSleep Tx Data Procedure\n",__FUNCTION__);
- pDevice->fTxDataInSleep = true;
- PSbSendNullPacket(pDevice); //send null packet
- pDevice->fTxDataInSleep = false;
- }
- spin_unlock_irq(&pDevice->lock);
-
- pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- add_timer(&pDevice->sTimerTxData);
- return;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+ pDevice->nTxDataTimeCout++;
+
+ if (pDevice->nTxDataTimeCout < 4) //don't tx data if timer less than 40s
+ {
+ pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
+ add_timer(&pDevice->sTimerTxData);
+ return;
+ }
+
+ spin_lock_irq(&pDevice->lock);
+#if 1
+ if (((pDevice->bLinkPass == true) && (pMgmt->eAuthenMode < WMAC_AUTH_WPA)) || //open && sharekey linking
+ (pDevice->fWPA_Authened == true)) { //wpa linking
+#else
+ if (pDevice->bLinkPass == true) {
+#endif
+ pDevice->fTxDataInSleep = true;
+ PSbSendNullPacket(pDevice); //send null packet
+ pDevice->fTxDataInSleep = false;
+ }
+ spin_unlock_irq(&pDevice->lock);
+
+ pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
+ add_timer(&pDevice->sTimerTxData);
+ return;
+ }
#endif
-
diff --git a/drivers/staging/vt6655/wcmd.h b/drivers/staging/vt6655/wcmd.h
index 69d4fc55b843..2844476d5dc9 100644
--- a/drivers/staging/vt6655/wcmd.h
+++ b/drivers/staging/vt6655/wcmd.h
@@ -35,111 +35,101 @@
/*--------------------- Export Definitions -------------------------*/
-
-
#define AUTHENTICATE_TIMEOUT 1000 //ms
#define ASSOCIATE_TIMEOUT 1000 //ms
-
// Command code
typedef enum tagCMD_CODE {
- WLAN_CMD_BSSID_SCAN,
- WLAN_CMD_SSID,
- WLAN_CMD_DISASSOCIATE,
- WLAN_CMD_DEAUTH,
- WLAN_CMD_RX_PSPOLL,
- WLAN_CMD_RADIO,
- WLAN_CMD_CHANGE_BBSENSITIVITY,
- WLAN_CMD_SETPOWER,
- WLAN_CMD_TBTT_WAKEUP,
- WLAN_CMD_BECON_SEND,
- WLAN_CMD_CHANGE_ANTENNA,
- WLAN_CMD_REMOVE_ALLKEY,
- WLAN_CMD_MAC_DISPOWERSAVING,
- WLAN_CMD_11H_CHSW,
- WLAN_CMD_RUN_AP
+ WLAN_CMD_BSSID_SCAN,
+ WLAN_CMD_SSID,
+ WLAN_CMD_DISASSOCIATE,
+ WLAN_CMD_DEAUTH,
+ WLAN_CMD_RX_PSPOLL,
+ WLAN_CMD_RADIO,
+ WLAN_CMD_CHANGE_BBSENSITIVITY,
+ WLAN_CMD_SETPOWER,
+ WLAN_CMD_TBTT_WAKEUP,
+ WLAN_CMD_BECON_SEND,
+ WLAN_CMD_CHANGE_ANTENNA,
+ WLAN_CMD_REMOVE_ALLKEY,
+ WLAN_CMD_MAC_DISPOWERSAVING,
+ WLAN_CMD_11H_CHSW,
+ WLAN_CMD_RUN_AP
} CMD_CODE, *PCMD_CODE;
#define CMD_Q_SIZE 32
typedef enum tagCMD_STATUS {
-
- CMD_STATUS_SUCCESS = 0,
- CMD_STATUS_FAILURE,
- CMD_STATUS_RESOURCES,
- CMD_STATUS_TIMEOUT,
- CMD_STATUS_PENDING
-
+ CMD_STATUS_SUCCESS = 0,
+ CMD_STATUS_FAILURE,
+ CMD_STATUS_RESOURCES,
+ CMD_STATUS_TIMEOUT,
+ CMD_STATUS_PENDING
} CMD_STATUS, *PCMD_STATUS;
-
typedef struct tagCMD_ITEM {
- CMD_CODE eCmd;
- unsigned char abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- bool bNeedRadioOFF;
- unsigned short wDeAuthenReason;
- bool bRadioCmd;
- bool bForceSCAN;
+ CMD_CODE eCmd;
+ unsigned char abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ bool bNeedRadioOFF;
+ unsigned short wDeAuthenReason;
+ bool bRadioCmd;
+ bool bForceSCAN;
} CMD_ITEM, *PCMD_ITEM;
// Command state
typedef enum tagCMD_STATE {
- WLAN_CMD_SCAN_START,
- WLAN_CMD_SCAN_END,
- WLAN_CMD_DISASSOCIATE_START,
- WLAN_CMD_SSID_START,
- WLAN_AUTHENTICATE_WAIT,
- WLAN_ASSOCIATE_WAIT,
- WLAN_DISASSOCIATE_WAIT,
- WLAN_CMD_TX_PSPACKET_START,
- WLAN_CMD_AP_MODE_START,
- WLAN_CMD_RADIO_START,
- WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE,
- WLAN_CMD_IDLE
+ WLAN_CMD_SCAN_START,
+ WLAN_CMD_SCAN_END,
+ WLAN_CMD_DISASSOCIATE_START,
+ WLAN_CMD_SSID_START,
+ WLAN_AUTHENTICATE_WAIT,
+ WLAN_ASSOCIATE_WAIT,
+ WLAN_DISASSOCIATE_WAIT,
+ WLAN_CMD_TX_PSPACKET_START,
+ WLAN_CMD_AP_MODE_START,
+ WLAN_CMD_RADIO_START,
+ WLAN_CMD_CHECK_BBSENSITIVITY_CHANGE,
+ WLAN_CMD_IDLE
} CMD_STATE, *PCMD_STATE;
-
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
void
vResetCommandTimer(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void
-vCommandTimer (
- void *hDeviceContext
- );
+vCommandTimer(
+ void *hDeviceContext
+);
bool bClearBSSID_SCAN(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
bool
bScheduleCommand(
- void *hDeviceContext,
- CMD_CODE eCommand,
- unsigned char *pbyItem0
- );
+ void *hDeviceContext,
+ CMD_CODE eCommand,
+ unsigned char *pbyItem0
+);
void
vCommandTimerWait(
- void *hDeviceContext,
- unsigned int MSecond
- );
+ void *hDeviceContext,
+ unsigned int MSecond
+);
#ifdef TxInSleep
void
BSSvSecondTxData(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
#endif
#endif //__WCMD_H__
diff --git a/drivers/staging/vt6655/wctl.c b/drivers/staging/vt6655/wctl.c
index c096583a7726..9eb81b4eee80 100644
--- a/drivers/staging/vt6655/wctl.c
+++ b/drivers/staging/vt6655/wctl.c
@@ -48,8 +48,6 @@
/*--------------------- Export Variables --------------------------*/
-
-
/*
* Description:
* Scan Rx cache. Return true if packet is duplicate, else
@@ -66,32 +64,31 @@
*
*/
-bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
+bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader)
{
- unsigned int uIndex;
- unsigned int ii;
- PSCacheEntry pCacheEntry;
-
- if (IS_FC_RETRY(pMACHeader)) {
-
- uIndex = pCache->uInPtr;
- for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
- pCacheEntry = &(pCache->asCacheEntry[uIndex]);
- if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
- (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
- ) {
- /* Duplicate match */
- return true;
- }
- ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH);
- }
- }
- /* Not fount in cache - insert */
- pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr];
- pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
- memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
- ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH);
- return false;
+ unsigned int uIndex;
+ unsigned int ii;
+ PSCacheEntry pCacheEntry;
+
+ if (IS_FC_RETRY(pMACHeader)) {
+ uIndex = pCache->uInPtr;
+ for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
+ pCacheEntry = &(pCache->asCacheEntry[uIndex]);
+ if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
+ (!compare_ether_addr(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
+) {
+ /* Duplicate match */
+ return true;
+ }
+ ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH);
+ }
+ }
+ /* Not fount in cache - insert */
+ pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr];
+ pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
+ memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
+ ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH);
+ return false;
}
/*
@@ -108,22 +105,21 @@ bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
* Return Value: index number in Defragment Database
*
*/
-unsigned int WCTLuSearchDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
+unsigned int WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader)
{
-unsigned int ii;
-
- for(ii=0;ii<pDevice->cbDFCB;ii++) {
- if ((pDevice->sRxDFCB[ii].bInUse == true) &&
- (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
- ) {
- //
- return(ii);
- }
- }
- return(pDevice->cbDFCB);
+ unsigned int ii;
+
+ for (ii = 0; ii < pDevice->cbDFCB; ii++) {
+ if ((pDevice->sRxDFCB[ii].bInUse == true) &&
+ (!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0])))
+) {
+ //
+ return ii;
+ }
+ }
+ return pDevice->cbDFCB;
}
-
/*
* Description:
* Insert received fragment packet in Defragment Database
@@ -138,27 +134,26 @@ unsigned int ii;
* Return Value: index number in Defragment Database
*
*/
-unsigned int WCTLuInsertDFCB (PSDevice pDevice, PS802_11Header pMACHeader)
+unsigned int WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader)
{
-unsigned int ii;
-
- if (pDevice->cbFreeDFCB == 0)
- return(pDevice->cbDFCB);
- for(ii=0;ii<pDevice->cbDFCB;ii++) {
- if (pDevice->sRxDFCB[ii].bInUse == false) {
- pDevice->cbFreeDFCB--;
- pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
- pDevice->sRxDFCB[ii].bInUse = true;
- pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4);
- pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
- memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
- return(ii);
- }
- }
- return(pDevice->cbDFCB);
+ unsigned int ii;
+
+ if (pDevice->cbFreeDFCB == 0)
+ return pDevice->cbDFCB;
+ for (ii = 0; ii < pDevice->cbDFCB; ii++) {
+ if (pDevice->sRxDFCB[ii].bInUse == false) {
+ pDevice->cbFreeDFCB--;
+ pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
+ pDevice->sRxDFCB[ii].bInUse = true;
+ pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4);
+ pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
+ memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
+ return ii;
+ }
+ }
+ return pDevice->cbDFCB;
}
-
/*
* Description:
* Handle received fragment packet
@@ -175,76 +170,67 @@ unsigned int ii;
* Return Value: true if it is valid fragment packet and we have resource to defragment; otherwise false
*
*/
-bool WCTLbHandleFragment (PSDevice pDevice, PS802_11Header pMACHeader, unsigned int cbFrameLength, bool bWEP, bool bExtIV)
+bool WCTLbHandleFragment(PSDevice pDevice, PS802_11Header pMACHeader, unsigned int cbFrameLength, bool bWEP, bool bExtIV)
{
-unsigned int uHeaderSize;
-
-
- if (bWEP == true) {
- uHeaderSize = 28;
- if (bExtIV)
- // ExtIV
- uHeaderSize +=4;
- }
- else {
- uHeaderSize = 24;
- }
-
- if (IS_FIRST_FRAGMENT_PKT(pMACHeader)) {
- pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
- if (pDevice->uCurrentDFCBIdx < pDevice->cbDFCB) {
- // duplicate, we must flush previous DCB
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].uLifetime = pDevice->dwMaxReceiveLifetime;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->wSeqCtl >> 4);
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
- }
- else {
- pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader);
- if (pDevice->uCurrentDFCBIdx == pDevice->cbDFCB) {
- return(false);
- }
- }
- // reserve 4 byte to match MAC RX Buffer
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (unsigned char *) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
- memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength);
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "First pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
- return(false);
- }
- else {
- pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
- if (pDevice->uCurrentDFCBIdx != pDevice->cbDFCB) {
- if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->wSeqCtl >> 4)) &&
- (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) &&
- ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) {
-
- memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((unsigned char *) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize);
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize);
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Second pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
- }
- else {
- // seq error or frag # error flush DFCB
- pDevice->cbFreeDFCB++;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
- return(false);
- }
- }
- else {
- return(false);
- }
- if (IS_LAST_FRAGMENT_PKT(pMACHeader)) {
- //enq defragcontrolblock
- pDevice->cbFreeDFCB++;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
- return(true);
- }
- return(false);
- }
+ unsigned int uHeaderSize;
+
+ if (bWEP == true) {
+ uHeaderSize = 28;
+ if (bExtIV)
+ // ExtIV
+ uHeaderSize += 4;
+ } else {
+ uHeaderSize = 24;
+ }
+
+ if (IS_FIRST_FRAGMENT_PKT(pMACHeader)) {
+ pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
+ if (pDevice->uCurrentDFCBIdx < pDevice->cbDFCB) {
+ // duplicate, we must flush previous DCB
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].uLifetime = pDevice->dwMaxReceiveLifetime;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->wSeqCtl >> 4);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
+ } else {
+ pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader);
+ if (pDevice->uCurrentDFCBIdx == pDevice->cbDFCB) {
+ return false;
+ }
+ }
+ // reserve 4 byte to match MAC RX Buffer
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (unsigned char *)(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
+ memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "First pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
+ return false;
+ } else {
+ pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
+ if (pDevice->uCurrentDFCBIdx != pDevice->cbDFCB) {
+ if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->wSeqCtl >> 4)) &&
+ (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) &&
+ ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) {
+ memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((unsigned char *)(pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Second pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
+ } else {
+ // seq error or frag # error flush DFCB
+ pDevice->cbFreeDFCB++;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
+ return false;
+ }
+ } else {
+ return false;
+ }
+ if (IS_LAST_FRAGMENT_PKT(pMACHeader)) {
+ //enq defragcontrolblock
+ pDevice->cbFreeDFCB++;
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].bInUse = false;
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Last pDevice->uCurrentDFCBIdx= %d\n", pDevice->uCurrentDFCBIdx);
+ return true;
+ }
+ return false;
+ }
}
-
-
diff --git a/drivers/staging/vt6655/wctl.h b/drivers/staging/vt6655/wctl.h
index a92bb6d2b3f0..1ffb2734cfae 100644
--- a/drivers/staging/vt6655/wctl.h
+++ b/drivers/staging/vt6655/wctl.h
@@ -35,61 +35,60 @@
/*--------------------- Export Definitions -------------------------*/
-#define IS_TYPE_DATA(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_DATA)
+#define IS_TYPE_DATA(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_DATA)
-#define IS_TYPE_MGMT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_MGMT)
+#define IS_TYPE_MGMT(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_MGMT)
-#define IS_TYPE_CONTROL(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_CTL)
+#define IS_TYPE_CONTROL(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_CTL)
-#define IS_FC_MOREDATA(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREDATA) == FC_MOREDATA)
+#define IS_FC_MOREDATA(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREDATA) == FC_MOREDATA)
-#define IS_FC_POWERMGT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_POWERMGT) == FC_POWERMGT)
+#define IS_FC_POWERMGT(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_POWERMGT) == FC_POWERMGT)
-#define IS_FC_RETRY(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_RETRY) == FC_RETRY)
+#define IS_FC_RETRY(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_RETRY) == FC_RETRY)
-#define IS_FC_WEP(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_WEP) == FC_WEP)
+#define IS_FC_WEP(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_WEP) == FC_WEP)
#ifdef __BIG_ENDIAN
-#define IS_FRAGMENT_PKT(pMACHeader) \
- (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) != 0))
+#define IS_FRAGMENT_PKT(pMACHeader) \
+ (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
+ ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) != 0))
-#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) == 0)
+#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) == 0)
#else
-#define IS_FRAGMENT_PKT(pMACHeader) \
- (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) != 0))
+#define IS_FRAGMENT_PKT(pMACHeader) \
+ (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
+ ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) != 0))
-#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) == 0)
+#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) == 0)
#endif//#ifdef __BIG_ENDIAN
-#define IS_LAST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) == 0)
+#define IS_LAST_FRAGMENT_PKT(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) == 0)
-#define IS_CTL_PSPOLL(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL)
-
-
-#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) { \
- if ((uVar) >= ((uModulo) - 1)) \
- (uVar) = 0; \
- else \
- (uVar)++; \
-}
+#define IS_CTL_PSPOLL(pMACHeader) \
+ ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL)
+#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) \
+do { \
+ if ((uVar) >= ((uModulo) - 1)) \
+ (uVar) = 0; \
+ else \
+ (uVar)++; \
+} while (0)
/*--------------------- Export Classes ----------------------------*/
@@ -99,11 +98,8 @@
bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader);
bool WCTLbHandleFragment(PSDevice pDevice, PS802_11Header pMACHeader,
- unsigned int cbFrameLength, bool bWEP, bool bExtIV);
+ unsigned int cbFrameLength, bool bWEP, bool bExtIV);
unsigned int WCTLuSearchDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
unsigned int WCTLuInsertDFCB(PSDevice pDevice, PS802_11Header pMACHeader);
#endif // __WCTL_H__
-
-
-
diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c
index b08a611a184a..9938813f997a 100644
--- a/drivers/staging/vt6655/wmgr.c
+++ b/drivers/staging/vt6655/wmgr.c
@@ -84,260 +84,251 @@
/*--------------------- Static Definitions -------------------------*/
-
-
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Functions --------------------------*/
//2008-8-4 <add> by chester
static bool ChannelExceedZoneType(
- PSDevice pDevice,
- unsigned char byCurrChannel
- );
+ PSDevice pDevice,
+ unsigned char byCurrChannel
+);
// Association/diassociation functions
static
PSTxMgmtPacket
s_MgrMakeAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pDAddr,
- unsigned short wCurrCapInfo,
- unsigned short wListenInterval,
- PWLAN_IE_SSID pCurrSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
+ PWLAN_IE_SSID pCurrSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
static
void
s_vMgrRxAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- unsigned int uNodeIndex
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ unsigned int uNodeIndex
+);
static
PSTxMgmtPacket
s_MgrMakeReAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pDAddr,
- unsigned short wCurrCapInfo,
- unsigned short wListenInterval,
- PWLAN_IE_SSID pCurrSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
+ PWLAN_IE_SSID pCurrSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
static
void
s_vMgrRxAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- bool bReAssocType
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ bool bReAssocType
+);
static
void
s_vMgrRxDisassociation(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
// Authentication/deauthen functions
static
void
s_vMgrRxAuthenSequence_1(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+);
static
void
s_vMgrRxAuthenSequence_2(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+);
static
void
s_vMgrRxAuthenSequence_3(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+);
static
void
s_vMgrRxAuthenSequence_4(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+);
static
void
s_vMgrRxAuthentication(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
static
void
s_vMgrRxDeauthentication(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
// Scan functions
// probe request/response functions
static
void
s_vMgrRxProbeRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
static
void
s_vMgrRxProbeResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
// beacon functions
static
void
s_vMgrRxBeacon(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- bool bInScan
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ bool bInScan
+);
static
void
s_vMgrFormatTIM(
- PSMgmtObject pMgmt,
- PWLAN_IE_TIM pTIM
- );
+ PSMgmtObject pMgmt,
+ PWLAN_IE_TIM pTIM
+);
static
PSTxMgmtPacket
s_MgrMakeBeacon(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wCurrBeaconPeriod,
- unsigned int uCurrChannel,
- unsigned short wCurrATIMWinodw,
- PWLAN_IE_SSID pCurrSSID,
- unsigned char *pCurrBSSID,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
-
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ PWLAN_IE_SSID pCurrSSID,
+ unsigned char *pCurrBSSID,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
// Association response
static
PSTxMgmtPacket
s_MgrMakeAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wAssocStatus,
- unsigned short wAssocAID,
- unsigned char *pDstAddr,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
// ReAssociation response
static
PSTxMgmtPacket
s_MgrMakeReAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wAssocStatus,
- unsigned short wAssocAID,
- unsigned char *pDstAddr,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+);
// Probe response
static
PSTxMgmtPacket
s_MgrMakeProbeResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wCurrBeaconPeriod,
- unsigned int uCurrChannel,
- unsigned short wCurrATIMWinodw,
- unsigned char *pDstAddr,
- PWLAN_IE_SSID pCurrSSID,
- unsigned char *pCurrBSSID,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
- unsigned char byPHYType
- );
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SSID pCurrSSID,
+ unsigned char *pCurrBSSID,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
+ unsigned char byPHYType
+);
// received status
static
void
s_vMgrLogStatus(
- PSMgmtObject pMgmt,
- unsigned short wStatus
- );
-
+ PSMgmtObject pMgmt,
+ unsigned short wStatus
+);
static
void
-s_vMgrSynchBSS (
- PSDevice pDevice,
- unsigned int uBSSMode,
- PKnownBSS pCurr,
- PCMD_STATUS pStatus
- );
-
+s_vMgrSynchBSS(
+ PSDevice pDevice,
+ unsigned int uBSSMode,
+ PKnownBSS pCurr,
+ PCMD_STATUS pStatus
+);
static bool
-s_bCipherMatch (
- PKnownBSS pBSSNode,
- NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- unsigned char *pbyCCSPK,
- unsigned char *pbyCCSGK
- );
-
- static void Encyption_Rebuild(
- PSDevice pDevice,
- PKnownBSS pCurr
- );
-
-
+s_bCipherMatch(
+ PKnownBSS pBSSNode,
+ NDIS_802_11_ENCRYPTION_STATUS EncStatus,
+ unsigned char *pbyCCSPK,
+ unsigned char *pbyCCSGK
+);
+
+static void Encyption_Rebuild(
+ PSDevice pDevice,
+ PKnownBSS pCurr
+);
/*--------------------- Export Variables --------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Routine Description:
@@ -346,32 +337,31 @@ s_bCipherMatch (
* Return Value:
* Ndis_staus.
*
--*/
+ -*/
void
vMgrObjectInit(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- int ii;
-
-
- pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
- pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
- pMgmt->uCurrChannel = pDevice->uChannel;
- for(ii=0;ii<WLAN_BSSID_LEN;ii++) {
- pMgmt->abyDesireBSSID[ii] = 0xFF;
- }
- pMgmt->sAssocInfo.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
- //memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN +1);
- pMgmt->byCSSPK = KEY_CTL_NONE;
- pMgmt->byCSSGK = KEY_CTL_NONE;
- pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
- BSSvClearBSSList((void *)pDevice, false);
-
- return;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ int ii;
+
+ pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
+ pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
+ pMgmt->uCurrChannel = pDevice->uChannel;
+ for (ii = 0; ii < WLAN_BSSID_LEN; ii++) {
+ pMgmt->abyDesireBSSID[ii] = 0xFF;
+ }
+ pMgmt->sAssocInfo.AssocInfo.Length = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
+ //memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN +1);
+ pMgmt->byCSSPK = KEY_CTL_NONE;
+ pMgmt->byCSSGK = KEY_CTL_NONE;
+ pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
+ BSSvClearBSSList((void *)pDevice, false);
+
+ return;
}
/*+
@@ -382,45 +372,42 @@ vMgrObjectInit(
* Return Value:
* Ndis_staus.
*
--*/
+ -*/
void
vMgrTimerInit(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
-
-
- init_timer(&pMgmt->sTimerSecondCallback);
- pMgmt->sTimerSecondCallback.data = (unsigned long) pDevice;
- pMgmt->sTimerSecondCallback.function = (TimerFunction)BSSvSecondCallBack;
- pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ);
-
- init_timer(&pDevice->sTimerCommand);
- pDevice->sTimerCommand.data = (unsigned long) pDevice;
- pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
- pDevice->sTimerCommand.expires = RUN_AT(HZ);
-
- #ifdef TxInSleep
- init_timer(&pDevice->sTimerTxData);
- pDevice->sTimerTxData.data = (unsigned long) pDevice;
- pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
- pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
- pDevice->fTxDataInSleep = false;
- pDevice->IsTxDataTrigger = false;
- pDevice->nTxDataTimeCout = 0;
- #endif
-
- pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
- pDevice->uCmdDequeueIdx = 0;
- pDevice->uCmdEnqueueIdx = 0;
-
- return;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+
+ init_timer(&pMgmt->sTimerSecondCallback);
+ pMgmt->sTimerSecondCallback.data = (unsigned long) pDevice;
+ pMgmt->sTimerSecondCallback.function = (TimerFunction)BSSvSecondCallBack;
+ pMgmt->sTimerSecondCallback.expires = RUN_AT(HZ);
+
+ init_timer(&pDevice->sTimerCommand);
+ pDevice->sTimerCommand.data = (unsigned long) pDevice;
+ pDevice->sTimerCommand.function = (TimerFunction)vCommandTimer;
+ pDevice->sTimerCommand.expires = RUN_AT(HZ);
+
+#ifdef TxInSleep
+ init_timer(&pDevice->sTimerTxData);
+ pDevice->sTimerTxData.data = (unsigned long) pDevice;
+ pDevice->sTimerTxData.function = (TimerFunction)BSSvSecondTxData;
+ pDevice->sTimerTxData.expires = RUN_AT(10*HZ); //10s callback
+ pDevice->fTxDataInSleep = false;
+ pDevice->IsTxDataTrigger = false;
+ pDevice->nTxDataTimeCout = 0;
+#endif
+ pDevice->cbFreeCmdQueue = CMD_Q_SIZE;
+ pDevice->uCmdDequeueIdx = 0;
+ pDevice->uCmdEnqueueIdx = 0;
+ return;
+}
/*+
*
@@ -430,25 +417,24 @@ vMgrTimerInit(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrObjectReset(
- void *hDeviceContext
- )
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- pDevice->bEnablePSMode = false;
- // TODO: timer
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ pDevice->bEnablePSMode = false;
+ // TODO: timer
- return;
+ return;
}
-
/*+
*
* Routine Description:
@@ -458,74 +444,66 @@ vMgrObjectReset(
* Return Value:
* None.
*
--*/
-
+ -*/
void
vMgrAssocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSTxMgmtPacket pTxPacket;
-
-
- pMgmt->wCurrCapInfo = 0;
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
- if (pDevice->bEncryptionEnable) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
- }
- // always allow receive short preamble
- //if (pDevice->byPreambleType == 1) {
- // pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- //}
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- if (pMgmt->wListenInterval == 0)
- pMgmt->wListenInterval = 1; // at least one.
-
- // ERP Phy (802.11g) should support short preamble.
- if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
- }
- } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
- if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- }
- }
- if (pMgmt->b11hEnable == true)
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
-
- /* build an assocreq frame and send it */
- pTxPacket = s_MgrMakeAssocRequest
- (
- pDevice,
- pMgmt,
- pMgmt->abyCurrBSSID,
- pMgmt->wCurrCapInfo,
- pMgmt->wListenInterval,
- (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
- );
-
- if (pTxPacket != NULL ){
- /* send the frame */
- *pStatus = csMgmt_xmit(pDevice, pTxPacket);
- if (*pStatus == CMD_STATUS_PENDING) {
- pMgmt->eCurrState = WMAC_STATE_ASSOCPENDING;
- *pStatus = CMD_STATUS_SUCCESS;
- }
- }
- else
- *pStatus = CMD_STATUS_RESOURCES;
-
- return ;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSTxMgmtPacket pTxPacket;
+
+ pMgmt->wCurrCapInfo = 0;
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
+ if (pDevice->bEncryptionEnable) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
+ }
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ if (pMgmt->wListenInterval == 0)
+ pMgmt->wListenInterval = 1; // at least one.
+
+ // ERP Phy (802.11g) should support short preamble.
+ if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
+ }
+ } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
+ if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ }
+ }
+ if (pMgmt->b11hEnable == true)
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
+
+ /* build an assocreq frame and send it */
+ pTxPacket = s_MgrMakeAssocRequest
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->abyCurrBSSID,
+ pMgmt->wCurrCapInfo,
+ pMgmt->wListenInterval,
+ (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
+);
+
+ if (pTxPacket != NULL) {
+ /* send the frame */
+ *pStatus = csMgmt_xmit(pDevice, pTxPacket);
+ if (*pStatus == CMD_STATUS_PENDING) {
+ pMgmt->eCurrState = WMAC_STATE_ASSOCPENDING;
+ *pStatus = CMD_STATUS_SUCCESS;
+ }
+ } else
+ *pStatus = CMD_STATUS_RESOURCES;
+ return;
+}
/*+
*
@@ -535,75 +513,66 @@ vMgrAssocBeginSta(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrReAssocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSTxMgmtPacket pTxPacket;
-
-
-
- pMgmt->wCurrCapInfo = 0;
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
- if (pDevice->bEncryptionEnable) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
- }
-
- //if (pDevice->byPreambleType == 1) {
- // pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- //}
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
-
- if (pMgmt->wListenInterval == 0)
- pMgmt->wListenInterval = 1; // at least one.
-
-
- // ERP Phy (802.11g) should support short preamble.
- if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
- }
- } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
- if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- }
- }
- if (pMgmt->b11hEnable == true)
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
-
-
- pTxPacket = s_MgrMakeReAssocRequest
- (
- pDevice,
- pMgmt,
- pMgmt->abyCurrBSSID,
- pMgmt->wCurrCapInfo,
- pMgmt->wListenInterval,
- (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
- );
-
- if (pTxPacket != NULL ){
- /* send the frame */
- *pStatus = csMgmt_xmit(pDevice, pTxPacket);
- if (*pStatus != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx failed.\n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx sending.\n");
- }
- }
-
-
- return ;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSTxMgmtPacket pTxPacket;
+
+ pMgmt->wCurrCapInfo = 0;
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
+ if (pDevice->bEncryptionEnable) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
+ }
+
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+
+ if (pMgmt->wListenInterval == 0)
+ pMgmt->wListenInterval = 1; // at least one.
+
+ // ERP Phy (802.11g) should support short preamble.
+ if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ if (CARDbIsShorSlotTime(pMgmt->pAdapter) == true) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTSLOTTIME(1);
+ }
+ } else if (pMgmt->eCurrentPHYMode == PHY_TYPE_11B) {
+ if (CARDbIsShortPreamble(pMgmt->pAdapter) == true) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ }
+ }
+ if (pMgmt->b11hEnable == true)
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
+
+ pTxPacket = s_MgrMakeReAssocRequest
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->abyCurrBSSID,
+ pMgmt->wCurrCapInfo,
+ pMgmt->wListenInterval,
+ (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
+);
+
+ if (pTxPacket != NULL) {
+ /* send the frame */
+ *pStatus = csMgmt_xmit(pDevice, pTxPacket);
+ if (*pStatus != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx failed.\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Reassociation tx sending.\n");
+ }
+ }
+
+ return;
}
/*+
@@ -614,59 +583,57 @@ vMgrReAssocBeginSta(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDisassocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- unsigned char *abyDestAddress,
- unsigned short wReason,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_DISASSOC sFrame;
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DISASSOC_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
-
- // Setup the sFrame structure
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_DISASSOC_FR_MAXLEN;
-
- // format fixed field frame structure
- vMgrEncodeDisassociation(&sFrame);
-
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DISASSOC)
- ));
-
- memcpy( sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- // Set reason code
- *(sFrame.pwReason) = cpu_to_le16(wReason);
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- // send the frame
- *pStatus = csMgmt_xmit(pDevice, pTxPacket);
- if (*pStatus == CMD_STATUS_PENDING) {
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- *pStatus = CMD_STATUS_SUCCESS;
- }
-
- return;
-}
-
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_DISASSOC sFrame;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DISASSOC_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+
+ // Setup the sFrame structure
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_DISASSOC_FR_MAXLEN;
+
+ // format fixed field frame structure
+ vMgrEncodeDisassociation(&sFrame);
+
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DISASSOC)
+));
+
+ memcpy(sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ // Set reason code
+ *(sFrame.pwReason) = cpu_to_le16(wReason);
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ // send the frame
+ *pStatus = csMgmt_xmit(pDevice, pTxPacket);
+ if (*pStatus == CMD_STATUS_PENDING) {
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ *pStatus = CMD_STATUS_SUCCESS;
+ }
+ return;
+}
/*+
*
@@ -676,153 +643,147 @@ vMgrDisassocBeginSta(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- unsigned int uNodeIndex
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ unsigned int uNodeIndex
+)
{
- WLAN_FR_ASSOCREQ sFrame;
- CMD_STATUS Status;
- PSTxMgmtPacket pTxPacket;
- unsigned short wAssocStatus = 0;
- unsigned short wAssocAID = 0;
- unsigned int uRateLen = WLAN_RATES_MAXLEN;
- unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
-
-
- if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
- return;
- // node index not found
- if (!uNodeIndex)
- return;
-
- //check if node is authenticated
- //decode the frame
- memset(&sFrame, 0, sizeof(WLAN_FR_ASSOCREQ));
- memset(abyCurrSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
- memset(abyCurrExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
-
- vMgrDecodeAssocRequest(&sFrame);
-
- if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
- pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
- pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
- WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
- // Todo: check sta basic rate, if ap can't support, set status code
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
- abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
- abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
- uRateLen);
- abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
- if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
- abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- uRateLen);
- } else {
- abyCurrExtSuppRates[1] = 0;
- }
-
-
- RATEvParseMaxRate((void *)pDevice,
- (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- false, // do not change our basic rate
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
- );
-
- // set max tx rate
- pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
+ WLAN_FR_ASSOCREQ sFrame;
+ CMD_STATUS Status;
+ PSTxMgmtPacket pTxPacket;
+ unsigned short wAssocStatus = 0;
+ unsigned short wAssocAID = 0;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+
+ if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
+ return;
+ // node index not found
+ if (!uNodeIndex)
+ return;
+
+ //check if node is authenticated
+ //decode the frame
+ memset(&sFrame, 0, sizeof(WLAN_FR_ASSOCREQ));
+ memset(abyCurrSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+ memset(abyCurrExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+
+ vMgrDecodeAssocRequest(&sFrame);
+
+ if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
+ pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
+ pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
+ WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
+ // Todo: check sta basic rate, if ap can't support, set status code
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+ abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
+ abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
+ uRateLen);
+ abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
+ abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
+ uRateLen);
+ } else {
+ abyCurrExtSuppRates[1] = 0;
+ }
+
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
+ false, // do not change our basic rate
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
+);
+
+ // set max tx rate
+ pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
#ifdef PLICE_DEBUG
- printk("RxAssocRequest:wTxDataRate is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
+ printk("RxAssocRequest:wTxDataRate is %d\n", pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
#endif
// Todo: check sta preamble, if ap can't support, set status code
- pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
- WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
- WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
- wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (unsigned short)uNodeIndex;
- // check if ERP support
- if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
-
- if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
- // B only STA join
- pDevice->bProtectMode = true;
- pDevice->bNonERPPresent = true;
- }
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
- pDevice->bBarkerPreambleMd = true;
- }
-
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Associate AID= %d \n", wAssocAID);
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
- sFrame.pHdr->sA3.abyAddr2[0],
- sFrame.pHdr->sA3.abyAddr2[1],
- sFrame.pHdr->sA3.abyAddr2[2],
- sFrame.pHdr->sA3.abyAddr2[3],
- sFrame.pHdr->sA3.abyAddr2[4],
- sFrame.pHdr->sA3.abyAddr2[5]
- ) ;
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n",
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
- }//else { TODO: received STA under state1 handle }
- else {
- return;
- }
-
-
- // assoc response reply..
- pTxPacket = s_MgrMakeAssocResponse
- (
- pDevice,
- pMgmt,
- pMgmt->wCurrCapInfo,
- wAssocStatus,
- wAssocAID,
- sFrame.pHdr->sA3.abyAddr2,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
- );
- if (pTxPacket != NULL ){
-
- if (pDevice->bEnableHostapd) {
- return;
- }
- /* send the frame */
- Status = csMgmt_xmit(pDevice, pTxPacket);
- if (Status != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx failed\n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx sending..\n");
- }
-
- }
-
- return;
-}
+ pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
+ WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
+ WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
+ wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
+ wAssocAID = (unsigned short)uNodeIndex;
+ // check if ERP support
+ if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
+
+ if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
+ // B only STA join
+ pDevice->bProtectMode = true;
+ pDevice->bNonERPPresent = true;
+ }
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
+ pDevice->bBarkerPreambleMd = true;
+ }
+
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Associate AID= %d \n", wAssocAID);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
+ sFrame.pHdr->sA3.abyAddr2[0],
+ sFrame.pHdr->sA3.abyAddr2[1],
+ sFrame.pHdr->sA3.abyAddr2[2],
+ sFrame.pHdr->sA3.abyAddr2[3],
+ sFrame.pHdr->sA3.abyAddr2[4],
+ sFrame.pHdr->sA3.abyAddr2[5]
+ );
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n",
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
+ }//else { TODO: received STA under state1 handle }
+ else {
+ return;
+ }
+
+ // assoc response reply..
+ pTxPacket = s_MgrMakeAssocResponse
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->wCurrCapInfo,
+ wAssocStatus,
+ wAssocAID,
+ sFrame.pHdr->sA3.abyAddr2,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
+);
+ if (pTxPacket != NULL) {
+ if (pDevice->bEnableHostapd) {
+ return;
+ }
+ /* send the frame */
+ Status = csMgmt_xmit(pDevice, pTxPacket);
+ if (Status != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx failed\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Assoc response tx sending..\n");
+ }
+ }
+
+ return;
+}
/*+
*
@@ -838,147 +799,143 @@ s_vMgrRxAssocRequest(
*
* Return Value: None.
*
--*/
+ -*/
static
void
s_vMgrRxReAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- unsigned int uNodeIndex
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ unsigned int uNodeIndex
+)
{
- WLAN_FR_REASSOCREQ sFrame;
- CMD_STATUS Status;
- PSTxMgmtPacket pTxPacket;
- unsigned short wAssocStatus = 0;
- unsigned short wAssocAID = 0;
- unsigned int uRateLen = WLAN_RATES_MAXLEN;
- unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
-
- if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
- return;
- // node index not found
- if (!uNodeIndex)
- return;
- //check if node is authenticated
- //decode the frame
- memset(&sFrame, 0, sizeof(WLAN_FR_REASSOCREQ));
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeReassocRequest(&sFrame);
-
- if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
- pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
- pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
- WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
- // Todo: check sta basic rate, if ap can't support, set status code
-
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
-
- abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
- abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
- uRateLen);
- abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
- if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
- abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- uRateLen);
- } else {
- abyCurrExtSuppRates[1] = 0;
- }
-
-
- RATEvParseMaxRate((void *)pDevice,
- (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
- false, // do not change our basic rate
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
- );
-
- // set max tx rate
- pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
+ WLAN_FR_REASSOCREQ sFrame;
+ CMD_STATUS Status;
+ PSTxMgmtPacket pTxPacket;
+ unsigned short wAssocStatus = 0;
+ unsigned short wAssocAID = 0;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+
+ if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
+ return;
+ // node index not found
+ if (!uNodeIndex)
+ return;
+ //check if node is authenticated
+ //decode the frame
+ memset(&sFrame, 0, sizeof(WLAN_FR_REASSOCREQ));
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeReassocRequest(&sFrame);
+
+ if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_ASSOC;
+ pMgmt->sNodeDBTable[uNodeIndex].wCapInfo = cpu_to_le16(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].wListenInterval = cpu_to_le16(*sFrame.pwListenInterval);
+ pMgmt->sNodeDBTable[uNodeIndex].bPSEnable =
+ WLAN_GET_FC_PWRMGT(sFrame.pHdr->sA3.wFrameCtl) ? true : false;
+ // Todo: check sta basic rate, if ap can't support, set status code
+
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+
+ abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
+ abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
+ uRateLen);
+ abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
+ abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pExtSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
+ uRateLen);
+ } else {
+ abyCurrExtSuppRates[1] = 0;
+ }
+
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
+ false, // do not change our basic rate
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
+);
+
+ // set max tx rate
+ pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate =
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
#ifdef PLICE_DEBUG
- printk("RxReAssocRequest:TxDataRate is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
+ printk("RxReAssocRequest:TxDataRate is %d\n", pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate);
#endif
// Todo: check sta preamble, if ap can't support, set status code
- pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
- WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
- WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
- wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (unsigned short)uNodeIndex;
-
- // if suppurt ERP
- if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
-
- if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
- // B only STA join
- pDevice->bProtectMode = true;
- pDevice->bNonERPPresent = true;
- }
- if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
- pDevice->bBarkerPreambleMd = true;
- }
-
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Rx ReAssociate AID= %d \n", wAssocAID);
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
- sFrame.pHdr->sA3.abyAddr2[0],
- sFrame.pHdr->sA3.abyAddr2[1],
- sFrame.pHdr->sA3.abyAddr2[2],
- sFrame.pHdr->sA3.abyAddr2[3],
- sFrame.pHdr->sA3.abyAddr2[4],
- sFrame.pHdr->sA3.abyAddr2[5]
- ) ;
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n",
- pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
-
- }
-
-
- // assoc response reply..
- pTxPacket = s_MgrMakeReAssocResponse
- (
- pDevice,
- pMgmt,
- pMgmt->wCurrCapInfo,
- wAssocStatus,
- wAssocAID,
- sFrame.pHdr->sA3.abyAddr2,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
- );
-
- if (pTxPacket != NULL ){
- /* send the frame */
- if (pDevice->bEnableHostapd) {
- return;
- }
- Status = csMgmt_xmit(pDevice, pTxPacket);
- if (Status != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx failed\n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx sending..\n");
- }
- }
- return;
-}
+ pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
+ WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
+ WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (unsigned short)uNodeIndex;
+ wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
+ wAssocAID = (unsigned short)uNodeIndex;
+
+ // if suppurt ERP
+ if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
+
+ if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate <= RATE_11M) {
+ // B only STA join
+ pDevice->bProtectMode = true;
+ pDevice->bNonERPPresent = true;
+ }
+ if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble == false) {
+ pDevice->bBarkerPreambleMd = true;
+ }
+
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Rx ReAssociate AID= %d \n", wAssocAID);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "MAC=%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X \n",
+ sFrame.pHdr->sA3.abyAddr2[0],
+ sFrame.pHdr->sA3.abyAddr2[1],
+ sFrame.pHdr->sA3.abyAddr2[2],
+ sFrame.pHdr->sA3.abyAddr2[3],
+ sFrame.pHdr->sA3.abyAddr2[4],
+ sFrame.pHdr->sA3.abyAddr2[5]
+ );
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Max Support rate = %d \n",
+ pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
+ }
+
+ // assoc response reply..
+ pTxPacket = s_MgrMakeReAssocResponse
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->wCurrCapInfo,
+ wAssocStatus,
+ wAssocAID,
+ sFrame.pHdr->sA3.abyAddr2,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
+ );
+
+ if (pTxPacket != NULL) {
+ /* send the frame */
+ if (pDevice->bEnableHostapd) {
+ return;
+ }
+ Status = csMgmt_xmit(pDevice, pTxPacket);
+ if (Status != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx failed\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:ReAssoc response tx sending..\n");
+ }
+ }
+ return;
+}
/*+
*
@@ -988,158 +945,147 @@ s_vMgrRxReAssocRequest(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- bool bReAssocType
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ bool bReAssocType
+)
{
- WLAN_FR_ASSOCRESP sFrame;
- PWLAN_IE_SSID pItemSSID;
- unsigned char *pbyIEs;
- viawget_wpa_header *wpahdr;
-
-
-
- if (pMgmt->eCurrState == WMAC_STATE_ASSOCPENDING ||
- pMgmt->eCurrState == WMAC_STATE_ASSOC) {
-
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- // decode the frame
- vMgrDecodeAssocResponse(&sFrame);
- if ((sFrame.pwCapInfo == 0) ||
- (sFrame.pwStatus == 0) ||
- (sFrame.pwAid == 0) ||
- (sFrame.pSuppRates == 0)){
- DBG_PORT80(0xCC);
- return;
- }
-
- pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.Capabilities = *(sFrame.pwCapInfo);
- pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.StatusCode = *(sFrame.pwStatus);
- pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.AssociationId = *(sFrame.pwAid);
- pMgmt->sAssocInfo.AssocInfo.AvailableResponseFixedIEs |= 0x07;
-
- pMgmt->sAssocInfo.AssocInfo.ResponseIELength = sFrame.len - 24 - 6;
- pMgmt->sAssocInfo.AssocInfo.OffsetResponseIEs = pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs + pMgmt->sAssocInfo.AssocInfo.RequestIELength;
- pbyIEs = pMgmt->sAssocInfo.abyIEs;
- pbyIEs += pMgmt->sAssocInfo.AssocInfo.RequestIELength;
- memcpy(pbyIEs, (sFrame.pBuf + 24 +6), pMgmt->sAssocInfo.AssocInfo.ResponseIELength);
-
- // save values and set current BSS state
- if (cpu_to_le16((*(sFrame.pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){
- // set AID
- pMgmt->wCurrAID = cpu_to_le16((*(sFrame.pwAid)));
- if ( (pMgmt->wCurrAID >> 14) != (BIT0 | BIT1) )
- {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "AID from AP, has two msb clear.\n");
- }
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Association Successful, AID=%d.\n", pMgmt->wCurrAID & ~(BIT14|BIT15));
- pMgmt->eCurrState = WMAC_STATE_ASSOC;
- BSSvUpdateAPNode((void *)pDevice, sFrame.pwCapInfo, sFrame.pSuppRates, sFrame.pExtSuppRates);
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Link with AP(SSID): %s\n", pItemSSID->abySSID);
- pDevice->bLinkPass = true;
- pDevice->uBBVGADiffCount = 0;
- if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
- if(skb_tailroom(pDevice->skb) <(sizeof(viawget_wpa_header)+pMgmt->sAssocInfo.AssocInfo.ResponseIELength+
- pMgmt->sAssocInfo.AssocInfo.RequestIELength)) { //data room not enough
- dev_kfree_skb(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- wpahdr->type = VIAWGET_ASSOC_MSG;
- wpahdr->resp_ie_len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength;
- wpahdr->req_ie_len = pMgmt->sAssocInfo.AssocInfo.RequestIELength;
- memcpy(pDevice->skb->data + sizeof(viawget_wpa_header), pMgmt->sAssocInfo.abyIEs, wpahdr->req_ie_len);
- memcpy(pDevice->skb->data + sizeof(viawget_wpa_header) + wpahdr->req_ie_len,
- pbyIEs,
- wpahdr->resp_ie_len
- );
- skb_put(pDevice->skb, sizeof(viawget_wpa_header) + wpahdr->resp_ie_len + wpahdr->req_ie_len);
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
-
-//2008-0409-07, <Add> by Einsn Liu
-#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //if(pDevice->bWPADevEnable == true)
- {
- unsigned char buf[512];
- size_t len;
- union iwreq_data wrqu;
- int we_event;
-
- memset(buf, 0, 512);
-
- len = pMgmt->sAssocInfo.AssocInfo.RequestIELength;
- if(len) {
- memcpy(buf, pMgmt->sAssocInfo.abyIEs, len);
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.data.length = len;
- we_event = IWEVASSOCREQIE;
- wireless_send_event(pDevice->dev, we_event, &wrqu, buf);
- }
-
- memset(buf, 0, 512);
- len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength;
-
- if(len) {
- memcpy(buf, pbyIEs, len);
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.data.length = len;
- we_event = IWEVASSOCRESPIE;
- wireless_send_event(pDevice->dev, we_event, &wrqu, buf);
+ WLAN_FR_ASSOCRESP sFrame;
+ PWLAN_IE_SSID pItemSSID;
+ unsigned char *pbyIEs;
+ viawget_wpa_header *wpahdr;
+
+ if (pMgmt->eCurrState == WMAC_STATE_ASSOCPENDING ||
+ pMgmt->eCurrState == WMAC_STATE_ASSOC) {
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ // decode the frame
+ vMgrDecodeAssocResponse(&sFrame);
+ if ((sFrame.pwCapInfo == 0) ||
+ (sFrame.pwStatus == 0) ||
+ (sFrame.pwAid == 0) ||
+ (sFrame.pSuppRates == 0)) {
+ DBG_PORT80(0xCC);
+ return;
}
+ pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.Capabilities = *(sFrame.pwCapInfo);
+ pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.StatusCode = *(sFrame.pwStatus);
+ pMgmt->sAssocInfo.AssocInfo.ResponseFixedIEs.AssociationId = *(sFrame.pwAid);
+ pMgmt->sAssocInfo.AssocInfo.AvailableResponseFixedIEs |= 0x07;
+
+ pMgmt->sAssocInfo.AssocInfo.ResponseIELength = sFrame.len - 24 - 6;
+ pMgmt->sAssocInfo.AssocInfo.OffsetResponseIEs = pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs + pMgmt->sAssocInfo.AssocInfo.RequestIELength;
+ pbyIEs = pMgmt->sAssocInfo.abyIEs;
+ pbyIEs += pMgmt->sAssocInfo.AssocInfo.RequestIELength;
+ memcpy(pbyIEs, (sFrame.pBuf + 24 + 6), pMgmt->sAssocInfo.AssocInfo.ResponseIELength);
+
+ // save values and set current BSS state
+ if (cpu_to_le16((*(sFrame.pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
+ // set AID
+ pMgmt->wCurrAID = cpu_to_le16((*(sFrame.pwAid)));
+ if ((pMgmt->wCurrAID >> 14) != (BIT0 | BIT1)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "AID from AP, has two msb clear.\n");
+ }
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Association Successful, AID=%d.\n", pMgmt->wCurrAID & ~(BIT14 | BIT15));
+ pMgmt->eCurrState = WMAC_STATE_ASSOC;
+ BSSvUpdateAPNode((void *)pDevice, sFrame.pwCapInfo, sFrame.pSuppRates, sFrame.pExtSuppRates);
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Link with AP(SSID): %s\n", pItemSSID->abySSID);
+ pDevice->bLinkPass = true;
+ pDevice->uBBVGADiffCount = 0;
+ if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
+ if (skb_tailroom(pDevice->skb) < (sizeof(viawget_wpa_header) + pMgmt->sAssocInfo.AssocInfo.ResponseIELength +
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength)) { //data room not enough
+ dev_kfree_skb(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ wpahdr->type = VIAWGET_ASSOC_MSG;
+ wpahdr->resp_ie_len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength;
+ wpahdr->req_ie_len = pMgmt->sAssocInfo.AssocInfo.RequestIELength;
+ memcpy(pDevice->skb->data + sizeof(viawget_wpa_header), pMgmt->sAssocInfo.abyIEs, wpahdr->req_ie_len);
+ memcpy(pDevice->skb->data + sizeof(viawget_wpa_header) + wpahdr->req_ie_len,
+ pbyIEs,
+ wpahdr->resp_ie_len
+);
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header) + wpahdr->resp_ie_len + wpahdr->req_ie_len);
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
- memset(&wrqu, 0, sizeof (wrqu));
- memcpy(wrqu.ap_addr.sa_data, &pMgmt->abyCurrBSSID[0], ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
+//2008-0409-07, <Add> by Einsn Liu
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ unsigned char buf[512];
+ size_t len;
+ union iwreq_data wrqu;
+ int we_event;
+
+ memset(buf, 0, 512);
+
+ len = pMgmt->sAssocInfo.AssocInfo.RequestIELength;
+ if (len) {
+ memcpy(buf, pMgmt->sAssocInfo.abyIEs, len);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = len;
+ we_event = IWEVASSOCREQIE;
+ wireless_send_event(pDevice->dev, we_event, &wrqu, buf);
+ }
+
+ memset(buf, 0, 512);
+ len = pMgmt->sAssocInfo.AssocInfo.ResponseIELength;
+
+ if (len) {
+ memcpy(buf, pbyIEs, len);
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = len;
+ we_event = IWEVASSOCRESPIE;
+ wireless_send_event(pDevice->dev, we_event, &wrqu, buf);
+ }
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, &pMgmt->abyCurrBSSID[0], ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
#endif //#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//End Add -- //2008-0409-07, <Add> by Einsn Liu
+ } else {
+ if (bReAssocType) {
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ } else {
+ // jump back to the auth state and indicate the error
+ pMgmt->eCurrState = WMAC_STATE_AUTH;
+ }
+ s_vMgrLogStatus(pMgmt, cpu_to_le16((*(sFrame.pwStatus))));
}
- else {
- if (bReAssocType) {
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- }
- else {
- // jump back to the auth state and indicate the error
- pMgmt->eCurrState = WMAC_STATE_AUTH;
- }
- s_vMgrLogStatus(pMgmt,cpu_to_le16((*(sFrame.pwStatus))));
- }
-
- }
+
+ }
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
//need clear flags related to Networkmanager
- pDevice->bwextcount = 0;
- pDevice->bWPASuppWextEnabled = false;
+ pDevice->bwextcount = 0;
+ pDevice->bWPASuppWextEnabled = false;
#endif
-
-if(pMgmt->eCurrState == WMAC_STATE_ASSOC)
- timer_expire(pDevice->sTimerCommand, 0);
- return;
+ if (pMgmt->eCurrState == WMAC_STATE_ASSOC)
+ timer_expire(pDevice->sTimerCommand, 0);
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -1149,54 +1095,52 @@ if(pMgmt->eCurrState == WMAC_STATE_ASSOC)
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrAuthenBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- WLAN_FR_AUTHEN sFrame;
- PSTxMgmtPacket pTxPacket = NULL;
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
- vMgrEncodeAuthen(&sFrame);
- /* insert values */
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- if (pMgmt->bShareKeyAlgorithm)
- *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_SHAREDKEY);
- else
- *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_OPENSYSTEM);
-
- *(sFrame.pwAuthSequence) = cpu_to_le16(1);
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- *pStatus = csMgmt_xmit(pDevice, pTxPacket);
- if (*pStatus == CMD_STATUS_PENDING){
- pMgmt->eCurrState = WMAC_STATE_AUTHPENDING;
- *pStatus = CMD_STATUS_SUCCESS;
- }
-
- return ;
-}
-
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ WLAN_FR_AUTHEN sFrame;
+ PSTxMgmtPacket pTxPacket = NULL;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
+ vMgrEncodeAuthen(&sFrame);
+ /* insert values */
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ if (pMgmt->bShareKeyAlgorithm)
+ *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_SHAREDKEY);
+ else
+ *(sFrame.pwAuthAlgorithm) = cpu_to_le16(WLAN_AUTH_ALG_OPENSYSTEM);
+
+ *(sFrame.pwAuthSequence) = cpu_to_le16(1);
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ *pStatus = csMgmt_xmit(pDevice, pTxPacket);
+ if (*pStatus == CMD_STATUS_PENDING) {
+ pMgmt->eCurrState = WMAC_STATE_AUTHPENDING;
+ *pStatus = CMD_STATUS_SUCCESS;
+ }
+ return;
+}
/*+
*
@@ -1207,53 +1151,50 @@ vMgrAuthenBeginSta(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrDeAuthenBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- unsigned char *abyDestAddress,
- unsigned short wReason,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- WLAN_FR_DEAUTHEN sFrame;
- PSTxMgmtPacket pTxPacket = NULL;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DEAUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_DEAUTHEN_FR_MAXLEN;
- vMgrEncodeDeauthen(&sFrame);
- /* insert values */
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DEAUTHEN)
- ));
-
- memcpy( sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- *(sFrame.pwReason) = cpu_to_le16(wReason); // deauthen. bcs left BSS
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- *pStatus = csMgmt_xmit(pDevice, pTxPacket);
- if (*pStatus == CMD_STATUS_PENDING){
- *pStatus = CMD_STATUS_SUCCESS;
- }
-
-
- return ;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ WLAN_FR_DEAUTHEN sFrame;
+ PSTxMgmtPacket pTxPacket = NULL;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_DEAUTHEN_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_DEAUTHEN_FR_MAXLEN;
+ vMgrEncodeDeauthen(&sFrame);
+ /* insert values */
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DEAUTHEN)
+));
+
+ memcpy(sFrame.pHdr->sA3.abyAddr1, abyDestAddress, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ *(sFrame.pwReason) = cpu_to_le16(wReason); // deauthen. bcs left BSS
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ *pStatus = csMgmt_xmit(pDevice, pTxPacket);
+ if (*pStatus == CMD_STATUS_PENDING) {
+ *pStatus = CMD_STATUS_SUCCESS;
+ }
+ return;
+}
/*+
*
@@ -1263,52 +1204,50 @@ vMgrDeAuthenBeginSta(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAuthentication(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- WLAN_FR_AUTHEN sFrame;
-
- // we better be an AP or a STA in AUTHPENDING otherwise ignore
- if (!(pMgmt->eCurrMode == WMAC_MODE_ESS_AP ||
- pMgmt->eCurrState == WMAC_STATE_AUTHPENDING)) {
- return;
- }
-
- // decode the frame
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeAuthen(&sFrame);
- switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){
- case 1:
- //AP function
- s_vMgrRxAuthenSequence_1(pDevice,pMgmt, &sFrame);
- break;
- case 2:
- s_vMgrRxAuthenSequence_2(pDevice, pMgmt, &sFrame);
- break;
- case 3:
- //AP function
- s_vMgrRxAuthenSequence_3(pDevice, pMgmt, &sFrame);
- break;
- case 4:
- s_vMgrRxAuthenSequence_4(pDevice, pMgmt, &sFrame);
- break;
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Auth Sequence error, seq = %d\n",
- cpu_to_le16((*(sFrame.pwAuthSequence))));
- break;
- }
- return;
-}
+ WLAN_FR_AUTHEN sFrame;
+ // we better be an AP or a STA in AUTHPENDING otherwise ignore
+ if (!(pMgmt->eCurrMode == WMAC_MODE_ESS_AP ||
+ pMgmt->eCurrState == WMAC_STATE_AUTHPENDING)) {
+ return;
+ }
+ // decode the frame
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeAuthen(&sFrame);
+ switch (cpu_to_le16((*(sFrame.pwAuthSequence)))) {
+ case 1:
+ //AP function
+ s_vMgrRxAuthenSequence_1(pDevice, pMgmt, &sFrame);
+ break;
+ case 2:
+ s_vMgrRxAuthenSequence_2(pDevice, pMgmt, &sFrame);
+ break;
+ case 3:
+ //AP function
+ s_vMgrRxAuthenSequence_3(pDevice, pMgmt, &sFrame);
+ break;
+ case 4:
+ s_vMgrRxAuthenSequence_4(pDevice, pMgmt, &sFrame);
+ break;
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Auth Sequence error, seq = %d\n",
+ cpu_to_le16((*(sFrame.pwAuthSequence))));
+ break;
+ }
+ return;
+}
/*+
*
@@ -1320,102 +1259,96 @@ s_vMgrRxAuthentication(
* Return Value:
* None.
*
--*/
-
+ -*/
static
void
s_vMgrRxAuthenSequence_1(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- unsigned int uNodeIndex;
- WLAN_FR_AUTHEN sFrame;
- PSKeyItem pTransmitKey;
-
- // Insert a Node entry
- if (!BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) {
- BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
- memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, pFrame->pHdr->sA3.abyAddr2,
- WLAN_ADDR_LEN);
- }
-
- if (pMgmt->bShareKeyAlgorithm) {
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_KNOWN;
- pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 1;
- }
- else {
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH;
- }
-
- // send auth reply
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
- // format buffer structure
- vMgrEncodeAuthen(&sFrame);
- // insert values
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
- WLAN_SET_FC_ISWEP(0)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
- *(sFrame.pwAuthSequence) = cpu_to_le16(2);
-
- if (cpu_to_le16(*(pFrame->pwAuthAlgorithm)) == WLAN_AUTH_ALG_SHAREDKEY) {
- if (pMgmt->bShareKeyAlgorithm)
- *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
- else
- *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG);
- }
- else {
- if (pMgmt->bShareKeyAlgorithm)
- *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG);
- else
- *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
- }
-
- if (pMgmt->bShareKeyAlgorithm &&
- (cpu_to_le16(*(sFrame.pwStatus)) == WLAN_MGMT_STATUS_SUCCESS)) {
-
- sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len);
- sFrame.len += WLAN_CHALLENGE_IE_LEN;
- sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE;
- sFrame.pChallenge->len = WLAN_CHALLENGE_LEN;
- memset(pMgmt->abyChallenge, 0, WLAN_CHALLENGE_LEN);
- // get group key
- if(KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, GROUP_KEY, &pTransmitKey) == true) {
- rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength+3);
- rc4_encrypt(&pDevice->SBox, pMgmt->abyChallenge, pMgmt->abyChallenge, WLAN_CHALLENGE_LEN);
- }
- memcpy(sFrame.pChallenge->abyChallenge, pMgmt->abyChallenge , WLAN_CHALLENGE_LEN);
- }
-
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
- // send the frame
- if (pDevice->bEnableHostapd) {
- return;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx.. \n");
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx failed.\n");
- }
- return;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ unsigned int uNodeIndex;
+ WLAN_FR_AUTHEN sFrame;
+ PSKeyItem pTransmitKey;
+
+ // Insert a Node entry
+ if (!BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) {
+ BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
+ memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, pFrame->pHdr->sA3.abyAddr2,
+ WLAN_ADDR_LEN);
+ }
+
+ if (pMgmt->bShareKeyAlgorithm) {
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_KNOWN;
+ pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 1;
+ } else {
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH;
+ }
+ // send auth reply
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
+ // format buffer structure
+ vMgrEncodeAuthen(&sFrame);
+ // insert values
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
+ WLAN_SET_FC_ISWEP(0)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
+ *(sFrame.pwAuthSequence) = cpu_to_le16(2);
+
+ if (cpu_to_le16(*(pFrame->pwAuthAlgorithm)) == WLAN_AUTH_ALG_SHAREDKEY) {
+ if (pMgmt->bShareKeyAlgorithm)
+ *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
+ else
+ *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG);
+ } else {
+ if (pMgmt->bShareKeyAlgorithm)
+ *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG);
+ else
+ *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
+ }
+
+ if (pMgmt->bShareKeyAlgorithm &&
+ (cpu_to_le16(*(sFrame.pwStatus)) == WLAN_MGMT_STATUS_SUCCESS)) {
+ sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len);
+ sFrame.len += WLAN_CHALLENGE_IE_LEN;
+ sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE;
+ sFrame.pChallenge->len = WLAN_CHALLENGE_LEN;
+ memset(pMgmt->abyChallenge, 0, WLAN_CHALLENGE_LEN);
+ // get group key
+ if (KeybGetTransmitKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, GROUP_KEY, &pTransmitKey) == true) {
+ rc4_init(&pDevice->SBox, pDevice->abyPRNG, pTransmitKey->uKeyLength+3);
+ rc4_encrypt(&pDevice->SBox, pMgmt->abyChallenge, pMgmt->abyChallenge, WLAN_CHALLENGE_LEN);
+ }
+ memcpy(sFrame.pChallenge->abyChallenge, pMgmt->abyChallenge , WLAN_CHALLENGE_LEN);
+ }
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ // send the frame
+ if (pDevice->bEnableHostapd) {
+ return;
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx.. \n");
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_1 tx failed.\n");
+ }
+ return;
+}
/*+
*
@@ -1427,97 +1360,91 @@ s_vMgrRxAuthenSequence_1(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAuthenSequence_2(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+)
{
- WLAN_FR_AUTHEN sFrame;
- PSTxMgmtPacket pTxPacket = NULL;
-
-
- switch (cpu_to_le16((*(pFrame->pwAuthAlgorithm))))
- {
- case WLAN_AUTH_ALG_OPENSYSTEM:
- if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Successful.\n");
- pMgmt->eCurrState = WMAC_STATE_AUTH;
- timer_expire(pDevice->sTimerCommand, 0);
- }
- else {
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Failed.\n");
- s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))));
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- }
- if (pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) {
+ WLAN_FR_AUTHEN sFrame;
+ PSTxMgmtPacket pTxPacket = NULL;
+
+ switch (cpu_to_le16((*(pFrame->pwAuthAlgorithm)))) {
+ case WLAN_AUTH_ALG_OPENSYSTEM:
+ if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Successful.\n");
+ pMgmt->eCurrState = WMAC_STATE_AUTH;
+ timer_expire(pDevice->sTimerCommand, 0);
+ } else {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (OPEN) Failed.\n");
+ s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))));
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ }
+ if (pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT) {
// spin_unlock_irq(&pDevice->lock);
// vCommandTimerWait((void *)pDevice, 0);
// spin_lock_irq(&pDevice->lock);
- }
-
- break;
-
- case WLAN_AUTH_ALG_SHAREDKEY:
-
- if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
- // format buffer structure
- vMgrEncodeAuthen(&sFrame);
- // insert values
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
- WLAN_SET_FC_ISWEP(1)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
- *(sFrame.pwAuthSequence) = cpu_to_le16(3);
- *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
- sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len);
- sFrame.len += WLAN_CHALLENGE_IE_LEN;
- sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE;
- sFrame.pChallenge->len = WLAN_CHALLENGE_LEN;
- memcpy( sFrame.pChallenge->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN);
- // Adjust the length fields
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
- // send the frame
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx failed.\n");
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx ...\n");
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:rx Auth_reply sequence_2 status error ...\n");
- if ( pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) {
+ }
+
+ break;
+
+ case WLAN_AUTH_ALG_SHAREDKEY:
+
+ if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
+ // format buffer structure
+ vMgrEncodeAuthen(&sFrame);
+ // insert values
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
+ WLAN_SET_FC_ISWEP(1)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
+ *(sFrame.pwAuthSequence) = cpu_to_le16(3);
+ *(sFrame.pwStatus) = cpu_to_le16(WLAN_MGMT_STATUS_SUCCESS);
+ sFrame.pChallenge = (PWLAN_IE_CHALLENGE)(sFrame.pBuf + sFrame.len);
+ sFrame.len += WLAN_CHALLENGE_IE_LEN;
+ sFrame.pChallenge->byElementID = WLAN_EID_CHALLENGE;
+ sFrame.pChallenge->len = WLAN_CHALLENGE_LEN;
+ memcpy(sFrame.pChallenge->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN);
+ // Adjust the length fields
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ // send the frame
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx failed.\n");
+ }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Auth_reply sequence_2 tx ...\n");
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:rx Auth_reply sequence_2 status error ...\n");
+ if (pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT) {
// spin_unlock_irq(&pDevice->lock);
// vCommandTimerWait((void *)pDevice, 0);
// spin_lock_irq(&pDevice->lock);
- }
- s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))));
- }
- break;
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt: rx auth.seq = 2 unknown AuthAlgorithm=%d\n", cpu_to_le16((*(pFrame->pwAuthAlgorithm))));
- break;
- }
- return;
+ }
+ s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))));
+ }
+ break;
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt: rx auth.seq = 2 unknown AuthAlgorithm=%d\n", cpu_to_le16((*(pFrame->pwAuthAlgorithm))));
+ break;
+ }
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -1529,86 +1456,82 @@ s_vMgrRxAuthenSequence_2(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAuthenSequence_3(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- unsigned int uStatusCode = 0 ;
- unsigned int uNodeIndex = 0;
- WLAN_FR_AUTHEN sFrame;
-
- if (!WLAN_GET_FC_ISWEP(pFrame->pHdr->sA3.wFrameCtl)) {
- uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL;
- goto reply;
- }
- if (BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) {
- if (pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence != 1) {
- uStatusCode = WLAN_MGMT_STATUS_RX_AUTH_NOSEQ;
- goto reply;
- }
- if (memcmp(pMgmt->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN) != 0) {
- uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL;
- goto reply;
- }
- }
- else {
- uStatusCode = WLAN_MGMT_STATUS_UNSPEC_FAILURE;
- goto reply;
- }
-
- if (uNodeIndex) {
- pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH;
- pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 0;
- }
- uStatusCode = WLAN_MGMT_STATUS_SUCCESS;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Challenge text check ok..\n");
+ PSTxMgmtPacket pTxPacket = NULL;
+ unsigned int uStatusCode = 0;
+ unsigned int uNodeIndex = 0;
+ WLAN_FR_AUTHEN sFrame;
+
+ if (!WLAN_GET_FC_ISWEP(pFrame->pHdr->sA3.wFrameCtl)) {
+ uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL;
+ goto reply;
+ }
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pFrame->pHdr->sA3.abyAddr2, &uNodeIndex)) {
+ if (pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence != 1) {
+ uStatusCode = WLAN_MGMT_STATUS_RX_AUTH_NOSEQ;
+ goto reply;
+ }
+ if (memcmp(pMgmt->abyChallenge, pFrame->pChallenge->abyChallenge, WLAN_CHALLENGE_LEN) != 0) {
+ uStatusCode = WLAN_MGMT_STATUS_CHALLENGE_FAIL;
+ goto reply;
+ }
+ } else {
+ uStatusCode = WLAN_MGMT_STATUS_UNSPEC_FAILURE;
+ goto reply;
+ }
-reply:
- // send auth reply
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
- // format buffer structure
- vMgrEncodeAuthen(&sFrame);
- /* insert values */
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
- WLAN_SET_FC_ISWEP(0)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
- *(sFrame.pwAuthSequence) = cpu_to_le16(4);
- *(sFrame.pwStatus) = cpu_to_le16(uStatusCode);
-
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
- // send the frame
- if (pDevice->bEnableHostapd) {
- return;
- }
- if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_4 tx failed.\n");
- }
- return;
+ if (uNodeIndex) {
+ pMgmt->sNodeDBTable[uNodeIndex].eNodeState = NODE_AUTH;
+ pMgmt->sNodeDBTable[uNodeIndex].byAuthSequence = 0;
+ }
+ uStatusCode = WLAN_MGMT_STATUS_SUCCESS;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Challenge text check ok..\n");
+reply:
+ // send auth reply
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_AUTHEN_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
+ // format buffer structure
+ vMgrEncodeAuthen(&sFrame);
+ /* insert values */
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_AUTHEN)|
+ WLAN_SET_FC_ISWEP(0)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pFrame->pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ *(sFrame.pwAuthAlgorithm) = *(pFrame->pwAuthAlgorithm);
+ *(sFrame.pwAuthSequence) = cpu_to_le16(4);
+ *(sFrame.pwStatus) = cpu_to_le16(uStatusCode);
+
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ // send the frame
+ if (pDevice->bEnableHostapd) {
+ return;
+ }
+ if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Authreq_reply sequence_4 tx failed.\n");
+ }
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -1618,33 +1541,30 @@ reply:
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxAuthenSequence_4(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PWLAN_FR_AUTHEN pFrame
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PWLAN_FR_AUTHEN pFrame
+)
{
+ if (cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS) {
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Successful.\n");
+ pMgmt->eCurrState = WMAC_STATE_AUTH;
+ timer_expire(pDevice->sTimerCommand, 0);
+ } else{
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Failed.\n");
+ s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))));
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ }
- if ( cpu_to_le16((*(pFrame->pwStatus))) == WLAN_MGMT_STATUS_SUCCESS ){
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Successful.\n");
- pMgmt->eCurrState = WMAC_STATE_AUTH;
- timer_expire(pDevice->sTimerCommand, 0);
- }
- else{
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "802.11 Authen (SHAREDKEY) Failed.\n");
- s_vMgrLogStatus(pMgmt, cpu_to_le16((*(pFrame->pwStatus))) );
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- }
-
- if ( pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT ) {
+ if (pDevice->eCommandState == WLAN_AUTHENTICATE_WAIT) {
// spin_unlock_irq(&pDevice->lock);
// vCommandTimerWait((void *)pDevice, 0);
// spin_lock_irq(&pDevice->lock);
- }
-
+ }
}
/*+
@@ -1656,75 +1576,68 @@ s_vMgrRxAuthenSequence_4(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxDisassociation(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- WLAN_FR_DISASSOC sFrame;
- unsigned int uNodeIndex = 0;
+ WLAN_FR_DISASSOC sFrame;
+ unsigned int uNodeIndex = 0;
// CMD_STATUS CmdStatus;
- viawget_wpa_header *wpahdr;
-
- if ( pMgmt->eCurrMode == WMAC_MODE_ESS_AP ){
- // if is acting an AP..
- // a STA is leaving this BSS..
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
- BSSvRemoveOneNode(pDevice, uNodeIndex);
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx disassoc, sta not found\n");
- }
- }
- else if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ){
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeDisassociation(&sFrame);
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP disassociated me, reason=%d.\n", cpu_to_le16(*(sFrame.pwReason)));
- //TODO: do something let upper layer know or
- //try to send associate packet again because of inactivity timeout
- // if (pMgmt->eCurrState == WMAC_STATE_ASSOC) {
- // vMgrReAssocBeginSta((PSDevice)pDevice, pMgmt, &CmdStatus);
- // }
- if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- wpahdr->type = VIAWGET_DISASSOC_MSG;
- wpahdr->resp_ie_len = 0;
- wpahdr->req_ie_len = 0;
- skb_put(pDevice->skb, sizeof(viawget_wpa_header));
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
-
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
-
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == true)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- printk("wireless_send_event--->SIOCGIWAP(disassociated)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
- }
- /* else, ignore it */
-
- return;
-}
+ viawget_wpa_header *wpahdr;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ // if is acting an AP..
+ // a STA is leaving this BSS..
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
+ BSSvRemoveOneNode(pDevice, uNodeIndex);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx disassoc, sta not found\n");
+ }
+ } else if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) {
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeDisassociation(&sFrame);
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP disassociated me, reason=%d.\n", cpu_to_le16(*(sFrame.pwReason)));
+ //TODO: do something let upper layer know or
+ //try to send associate packet again because of inactivity timeout
+ if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ wpahdr->type = VIAWGET_DISASSOC_MSG;
+ wpahdr->resp_ie_len = 0;
+ wpahdr->req_ie_len = 0;
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header));
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ printk("wireless_send_event--->SIOCGIWAP(disassociated)\n");
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+ }
+ /* else, ignore it */
+
+ return;
+}
/*+
*
@@ -1735,84 +1648,79 @@ s_vMgrRxDisassociation(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxDeauthentication(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- WLAN_FR_DEAUTHEN sFrame;
- unsigned int uNodeIndex = 0;
- viawget_wpa_header *wpahdr;
-
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP ){
- //Todo:
- // if is acting an AP..
- // a STA is leaving this BSS..
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
- BSSvRemoveOneNode(pDevice, uNodeIndex);
- }
- else {
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Rx deauth, sta not found\n");
- }
- }
- else {
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ) {
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeDeauthen(&sFrame);
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason))));
- // TODO: update BSS list for specific BSSID if pre-authentication case
- if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) {
- if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) {
- pMgmt->sNodeDBTable[0].bActive = false;
- pMgmt->eCurrMode = WMAC_MODE_STANDBY;
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- netif_stop_queue(pDevice->dev);
- pDevice->bLinkPass = false;
- }
- }
-
- if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
- wpahdr = (viawget_wpa_header *)pDevice->skb->data;
- wpahdr->type = VIAWGET_DISASSOC_MSG;
- wpahdr->resp_ie_len = 0;
- wpahdr->req_ie_len = 0;
- skb_put(pDevice->skb, sizeof(viawget_wpa_header));
- pDevice->skb->dev = pDevice->wpadev;
- skb_reset_mac_header(pDevice->skb);
- pDevice->skb->pkt_type = PACKET_HOST;
- pDevice->skb->protocol = htons(ETH_P_802_2);
- memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
- netif_rx(pDevice->skb);
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- }
-
- #ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- // if(pDevice->bWPASuppWextEnabled == true)
- {
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof (wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- PRINT_K("wireless_send_event--->SIOCGIWAP(disauthen)\n");
- wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
- }
- #endif
-
- }
- /* else, ignore it. TODO: IBSS authentication service
- would be implemented here */
- };
- return;
-}
+ WLAN_FR_DEAUTHEN sFrame;
+ unsigned int uNodeIndex = 0;
+ viawget_wpa_header *wpahdr;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ //Todo:
+ // if is acting an AP..
+ // a STA is leaving this BSS..
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
+ BSSvRemoveOneNode(pDevice, uNodeIndex);
+ } else {
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Rx deauth, sta not found\n");
+ }
+ } else {
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) {
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeDeauthen(&sFrame);
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason))));
+ // TODO: update BSS list for specific BSSID if pre-authentication case
+ if (!compare_ether_addr(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID)) {
+ if (pMgmt->eCurrState >= WMAC_STATE_AUTHPENDING) {
+ pMgmt->sNodeDBTable[0].bActive = false;
+ pMgmt->eCurrMode = WMAC_MODE_STANDBY;
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ netif_stop_queue(pDevice->dev);
+ pDevice->bLinkPass = false;
+ }
+ }
+
+ if ((pDevice->bWPADEVUp) && (pDevice->skb != NULL)) {
+ wpahdr = (viawget_wpa_header *)pDevice->skb->data;
+ wpahdr->type = VIAWGET_DISASSOC_MSG;
+ wpahdr->resp_ie_len = 0;
+ wpahdr->req_ie_len = 0;
+ skb_put(pDevice->skb, sizeof(viawget_wpa_header));
+ pDevice->skb->dev = pDevice->wpadev;
+ skb_reset_mac_header(pDevice->skb);
+ pDevice->skb->pkt_type = PACKET_HOST;
+ pDevice->skb->protocol = htons(ETH_P_802_2);
+ memset(pDevice->skb->cb, 0, sizeof(pDevice->skb->cb));
+ netif_rx(pDevice->skb);
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ }
+#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ PRINT_K("wireless_send_event--->SIOCGIWAP(disauthen)\n");
+ wireless_send_event(pDevice->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+#endif
+
+ }
+ /* else, ignore it. TODO: IBSS authentication service
+ would be implemented here */
+ };
+ return;
+}
//2008-8-4 <add> by chester
/*+
@@ -1825,33 +1733,32 @@ s_vMgrRxDeauthentication(
* Return Value:
* True:exceed;
* False:normal case
--*/
+ -*/
static bool
ChannelExceedZoneType(
- PSDevice pDevice,
- unsigned char byCurrChannel
- )
+ PSDevice pDevice,
+ unsigned char byCurrChannel
+)
{
- bool exceed=false;
+ bool exceed = false;
- switch(pDevice->byZoneType) {
- case 0x00: //USA:1~11
- if((byCurrChannel<1) ||(byCurrChannel>11))
- exceed = true;
- break;
+ switch (pDevice->byZoneType) {
+ case 0x00: //USA:1~11
+ if ((byCurrChannel < 1) || (byCurrChannel > 11))
+ exceed = true;
+ break;
case 0x01: //Japan:1~13
case 0x02: //Europe:1~13
- if((byCurrChannel<1) ||(byCurrChannel>13))
- exceed = true;
- break;
+ if ((byCurrChannel < 1) || (byCurrChannel > 13))
+ exceed = true;
+ break;
default: //reserve for other zonetype
break;
- }
+ }
- return exceed;
+ return exceed;
}
-
/*+
*
* Routine Description:
@@ -1861,517 +1768,487 @@ ChannelExceedZoneType(
* Return Value:
* None.
*
--*/
+ -*/
static
void
s_vMgrRxBeacon(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket,
- bool bInScan
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket,
+ bool bInScan
+)
{
+ PKnownBSS pBSSList;
+ WLAN_FR_BEACON sFrame;
+ QWORD qwTSFOffset;
+ bool bIsBSSIDEqual = false;
+ bool bIsSSIDEqual = false;
+ bool bTSFLargeDiff = false;
+ bool bTSFOffsetPostive = false;
+ bool bUpdateTSF = false;
+ bool bIsAPBeacon = false;
+ bool bIsChannelEqual = false;
+ unsigned int uLocateByteIndex;
+ unsigned char byTIMBitOn = 0;
+ unsigned short wAIDNumber = 0;
+ unsigned int uNodeIndex;
+ QWORD qwTimestamp, qwLocalTSF;
+ QWORD qwCurrTSF;
+ unsigned short wStartIndex = 0;
+ unsigned short wAIDIndex = 0;
+ unsigned char byCurrChannel = pRxPacket->byRxChannel;
+ ERPObject sERP;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ bool bChannelHit = false;
+ bool bUpdatePhyParameter = false;
+ unsigned char byIEChannel = 0;
+
+ memset(&sFrame, 0, sizeof(WLAN_FR_BEACON));
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+
+ // decode the beacon frame
+ vMgrDecodeBeacon(&sFrame);
+
+ if ((sFrame.pwBeaconInterval == 0) ||
+ (sFrame.pwCapInfo == 0) ||
+ (sFrame.pSSID == 0) ||
+ (sFrame.pSuppRates == 0)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx beacon frame error\n");
+ return;
+ }
- PKnownBSS pBSSList;
- WLAN_FR_BEACON sFrame;
- QWORD qwTSFOffset;
- bool bIsBSSIDEqual = false;
- bool bIsSSIDEqual = false;
- bool bTSFLargeDiff = false;
- bool bTSFOffsetPostive = false;
- bool bUpdateTSF = false;
- bool bIsAPBeacon = false;
- bool bIsChannelEqual = false;
- unsigned int uLocateByteIndex;
- unsigned char byTIMBitOn = 0;
- unsigned short wAIDNumber = 0;
- unsigned int uNodeIndex;
- QWORD qwTimestamp, qwLocalTSF;
- QWORD qwCurrTSF;
- unsigned short wStartIndex = 0;
- unsigned short wAIDIndex = 0;
- unsigned char byCurrChannel = pRxPacket->byRxChannel;
- ERPObject sERP;
- unsigned int uRateLen = WLAN_RATES_MAXLEN;
- bool bChannelHit = false;
- bool bUpdatePhyParameter = false;
- unsigned char byIEChannel = 0;
-
-
- memset(&sFrame, 0, sizeof(WLAN_FR_BEACON));
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
-
- // decode the beacon frame
- vMgrDecodeBeacon(&sFrame);
-
- if ((sFrame.pwBeaconInterval == 0) ||
- (sFrame.pwCapInfo == 0) ||
- (sFrame.pSSID == 0) ||
- (sFrame.pSuppRates == 0) ) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx beacon frame error\n");
- return;
- }
-
-
- if (sFrame.pDSParms != NULL) {
- if (byCurrChannel > CB_MAX_CHANNEL_24G) {
- // channel remapping to
- byIEChannel = get_channel_mapping(pDevice, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
- } else {
- byIEChannel = sFrame.pDSParms->byCurrChannel;
- }
- if (byCurrChannel != byIEChannel) {
- // adjust channel info. bcs we rcv adjacent channel packets
- bChannelHit = false;
- byCurrChannel = byIEChannel;
- }
- } else {
- // no DS channel info
- bChannelHit = true;
- }
+ if (sFrame.pDSParms != NULL) {
+ if (byCurrChannel > CB_MAX_CHANNEL_24G) {
+ // channel remapping to
+ byIEChannel = get_channel_mapping(pDevice, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
+ } else {
+ byIEChannel = sFrame.pDSParms->byCurrChannel;
+ }
+ if (byCurrChannel != byIEChannel) {
+ // adjust channel info. bcs we rcv adjacent channel packets
+ bChannelHit = false;
+ byCurrChannel = byIEChannel;
+ }
+ } else {
+ // no DS channel info
+ bChannelHit = true;
+ }
//2008-0730-01<Add>by MikeLiu
-if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
- return;
-
- if (sFrame.pERP != NULL) {
- sERP.byERP = sFrame.pERP->byContext;
- sERP.bERPExist = true;
-
- } else {
- sERP.bERPExist = false;
- sERP.byERP = 0;
- }
-
- pBSSList = BSSpAddrIsInBSSList((void *)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID);
- if (pBSSList == NULL) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon/insert: RxChannel = : %d\n", byCurrChannel);
- BSSbInsertToBSSList((void *)pDevice,
- sFrame.pHdr->sA3.abyAddr3,
- *sFrame.pqwTimestamp,
- *sFrame.pwBeaconInterval,
- *sFrame.pwCapInfo,
- byCurrChannel,
- sFrame.pSSID,
- sFrame.pSuppRates,
- sFrame.pExtSuppRates,
- &sERP,
- sFrame.pRSN,
- sFrame.pRSNWPA,
- sFrame.pIE_Country,
- sFrame.pIE_Quiet,
- sFrame.len - WLAN_HDR_ADDR3_LEN,
- sFrame.pHdr->sA4.abyAddr4, // payload of beacon
- (void *)pRxPacket
- );
- }
- else {
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"update bcn: RxChannel = : %d\n", byCurrChannel);
- BSSbUpdateToBSSList((void *)pDevice,
- *sFrame.pqwTimestamp,
- *sFrame.pwBeaconInterval,
- *sFrame.pwCapInfo,
- byCurrChannel,
- bChannelHit,
- sFrame.pSSID,
- sFrame.pSuppRates,
- sFrame.pExtSuppRates,
- &sERP,
- sFrame.pRSN,
- sFrame.pRSNWPA,
- sFrame.pIE_Country,
- sFrame.pIE_Quiet,
- pBSSList,
- sFrame.len - WLAN_HDR_ADDR3_LEN,
- sFrame.pHdr->sA4.abyAddr4, // payload of probresponse
- (void *)pRxPacket
- );
-
- }
-
- if (bInScan) {
- return;
- }
-
- if(byCurrChannel == (unsigned char)pMgmt->uCurrChannel)
- bIsChannelEqual = true;
-
- if (bIsChannelEqual && (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
-
- // if rx beacon without ERP field
- if (sERP.bERPExist) {
- if (WLAN_GET_ERP_USE_PROTECTION(sERP.byERP)){
- pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
- pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD;
- }
- }
- else {
- pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
- pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD;
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- if(!WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo))
- pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1);
- if(!sERP.bERPExist)
- pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1);
- }
-
- // set to MAC&BBP
- if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)){
- if (!pDevice->bProtectMode) {
- MACvEnableProtectMD(pDevice->PortOffset);
- pDevice->bProtectMode = true;
- }
- }
- }
-
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)
- return;
-
- // check if BSSID the same
- if (memcmp(sFrame.pHdr->sA3.abyAddr3,
- pMgmt->abyCurrBSSID,
- WLAN_BSSID_LEN) == 0) {
-
- bIsBSSIDEqual = true;
+ if (ChannelExceedZoneType(pDevice, byCurrChannel) == true)
+ return;
+
+ if (sFrame.pERP != NULL) {
+ sERP.byERP = sFrame.pERP->byContext;
+ sERP.bERPExist = true;
+
+ } else {
+ sERP.bERPExist = false;
+ sERP.byERP = 0;
+ }
+
+ pBSSList = BSSpAddrIsInBSSList((void *)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID);
+ if (pBSSList == NULL) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Beacon/insert: RxChannel = : %d\n", byCurrChannel);
+ BSSbInsertToBSSList((void *)pDevice,
+ sFrame.pHdr->sA3.abyAddr3,
+ *sFrame.pqwTimestamp,
+ *sFrame.pwBeaconInterval,
+ *sFrame.pwCapInfo,
+ byCurrChannel,
+ sFrame.pSSID,
+ sFrame.pSuppRates,
+ sFrame.pExtSuppRates,
+ &sERP,
+ sFrame.pRSN,
+ sFrame.pRSNWPA,
+ sFrame.pIE_Country,
+ sFrame.pIE_Quiet,
+ sFrame.len - WLAN_HDR_ADDR3_LEN,
+ sFrame.pHdr->sA4.abyAddr4, // payload of beacon
+ (void *)pRxPacket
+);
+ } else {
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "update bcn: RxChannel = : %d\n", byCurrChannel);
+ BSSbUpdateToBSSList((void *)pDevice,
+ *sFrame.pqwTimestamp,
+ *sFrame.pwBeaconInterval,
+ *sFrame.pwCapInfo,
+ byCurrChannel,
+ bChannelHit,
+ sFrame.pSSID,
+ sFrame.pSuppRates,
+ sFrame.pExtSuppRates,
+ &sERP,
+ sFrame.pRSN,
+ sFrame.pRSNWPA,
+ sFrame.pIE_Country,
+ sFrame.pIE_Quiet,
+ pBSSList,
+ sFrame.len - WLAN_HDR_ADDR3_LEN,
+ sFrame.pHdr->sA4.abyAddr4, // payload of probresponse
+ (void *)pRxPacket
+);
+
+ }
+
+ if (bInScan) {
+ return;
+ }
+
+ if (byCurrChannel == (unsigned char)pMgmt->uCurrChannel)
+ bIsChannelEqual = true;
+
+ if (bIsChannelEqual && (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
+ // if rx beacon without ERP field
+ if (sERP.bERPExist) {
+ if (WLAN_GET_ERP_USE_PROTECTION(sERP.byERP)) {
+ pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
+ pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD;
+ }
+ } else {
+ pDevice->byERPFlag |= WLAN_SET_ERP_USE_PROTECTION(1);
+ pDevice->wUseProtectCntDown = USE_PROTECT_PERIOD;
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ if (!WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo))
+ pDevice->byERPFlag |= WLAN_SET_ERP_BARKER_MODE(1);
+ if (!sERP.bERPExist)
+ pDevice->byERPFlag |= WLAN_SET_ERP_NONERP_PRESENT(1);
+ }
+
+ // set to MAC&BBP
+ if (WLAN_GET_ERP_USE_PROTECTION(pDevice->byERPFlag)) {
+ if (!pDevice->bProtectMode) {
+ MACvEnableProtectMD(pDevice->PortOffset);
+ pDevice->bProtectMode = true;
+ }
+ }
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)
+ return;
+
+ // check if BSSID the same
+ if (memcmp(sFrame.pHdr->sA3.abyAddr3,
+ pMgmt->abyCurrBSSID,
+ WLAN_BSSID_LEN) == 0) {
+ bIsBSSIDEqual = true;
// 2008-05-21 <add> by Richardtai
- pDevice->uCurrRSSI = pRxPacket->uRSSI;
- pDevice->byCurrSQ = pRxPacket->bySQ;
-
- if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) {
- pMgmt->sNodeDBTable[0].uInActiveCount = 0;
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BCN:Wake Count= [%d]\n", pMgmt->wCountToWakeUp);
- }
- }
- // check if SSID the same
- if (sFrame.pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) {
- if (memcmp(sFrame.pSSID->abySSID,
- ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,
- sFrame.pSSID->len
- ) == 0) {
- bIsSSIDEqual = true;
- }
- }
-
- if ((WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)== true) &&
- (bIsBSSIDEqual == true) &&
- (bIsSSIDEqual == true) &&
- (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
- (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
- // add state check to prevent reconnect fail since we'll receive Beacon
-
- bIsAPBeacon = true;
-
- if (pBSSList != NULL) {
-
- // Compare PHY parameter setting
- if (pMgmt->wCurrCapInfo != pBSSList->wCapInfo) {
- bUpdatePhyParameter = true;
- pMgmt->wCurrCapInfo = pBSSList->wCapInfo;
- }
- if (sFrame.pERP != NULL) {
- if ((sFrame.pERP->byElementID == WLAN_EID_ERP) &&
- (pMgmt->byERPContext != sFrame.pERP->byContext)) {
- bUpdatePhyParameter = true;
- pMgmt->byERPContext = sFrame.pERP->byContext;
- }
- }
- //
- // Basic Rate Set may change dynamically
- //
- if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) {
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abySuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- uRateLen);
- pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abyExtSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- uRateLen);
- RATEvParseMaxRate( (void *)pDevice,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- true,
- &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[0].wSuppRate),
- &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
- );
-#ifdef PLICE_DEBUG
- //printk("RxBeacon:MaxSuppRate is %d\n",pMgmt->sNodeDBTable[0].wMaxSuppRate);
-#endif
+ pDevice->uCurrRSSI = pRxPacket->uRSSI;
+ pDevice->byCurrSQ = pRxPacket->bySQ;
+
+ if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) {
+ pMgmt->sNodeDBTable[0].uInActiveCount = 0;
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:Wake Count= [%d]\n", pMgmt->wCountToWakeUp);
+ }
+ }
+ // check if SSID the same
+ if (sFrame.pSSID->len == ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) {
+ if (memcmp(sFrame.pSSID->abySSID,
+ ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,
+ sFrame.pSSID->len
+) == 0) {
+ bIsSSIDEqual = true;
+ }
+ }
+
+ if ((WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo) == true) &&
+ (bIsBSSIDEqual == true) &&
+ (bIsSSIDEqual == true) &&
+ (pMgmt->eCurrMode == WMAC_MODE_ESS_STA) &&
+ (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
+ // add state check to prevent reconnect fail since we'll receive Beacon
+
+ bIsAPBeacon = true;
+
+ if (pBSSList != NULL) {
+ // Compare PHY parameter setting
+ if (pMgmt->wCurrCapInfo != pBSSList->wCapInfo) {
+ bUpdatePhyParameter = true;
+ pMgmt->wCurrCapInfo = pBSSList->wCapInfo;
+ }
+ if (sFrame.pERP != NULL) {
+ if ((sFrame.pERP->byElementID == WLAN_EID_ERP) &&
+ (pMgmt->byERPContext != sFrame.pERP->byContext)) {
+ bUpdatePhyParameter = true;
+ pMgmt->byERPContext = sFrame.pERP->byContext;
+ }
+ }
+ //
+ // Basic Rate Set may change dynamically
+ //
+ if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) {
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abySuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ uRateLen);
+ pMgmt->abyCurrExtSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pBSSList->abyExtSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ uRateLen);
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ true,
+ &(pMgmt->sNodeDBTable[0].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[0].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[0].wSuppRate),
+ &(pMgmt->sNodeDBTable[0].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[0].byTopOFDMBasicRate)
+ );
if (bUpdatePhyParameter == true) {
- CARDbSetPhyParameter( pMgmt->pAdapter,
- pMgmt->eCurrentPHYMode,
- pMgmt->wCurrCapInfo,
- pMgmt->byERPContext,
- pMgmt->abyCurrSuppRates,
- pMgmt->abyCurrExtSuppRates
- );
- }
- if (sFrame.pIE_PowerConstraint != NULL) {
- CARDvSetPowerConstraint(pMgmt->pAdapter,
- (unsigned char) pBSSList->uChannel,
- sFrame.pIE_PowerConstraint->byPower
- );
- }
- if (sFrame.pIE_CHSW != NULL) {
- CARDbChannelSwitch( pMgmt->pAdapter,
- sFrame.pIE_CHSW->byMode,
- get_channel_mapping(pMgmt->pAdapter, sFrame.pIE_CHSW->byMode, pMgmt->eCurrentPHYMode),
- sFrame.pIE_CHSW->byCount
- );
-
- } else if (bIsChannelEqual == false) {
- set_channel(pMgmt->pAdapter, pBSSList->uChannel);
- }
- }
- }
-
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon 2 \n");
- // check if CF field exists
- if (WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)) {
- if (sFrame.pCFParms->wCFPDurRemaining > 0) {
- // TODO: deal with CFP period to set NAV
- }
- }
-
- HIDWORD(qwTimestamp) = cpu_to_le32(HIDWORD(*sFrame.pqwTimestamp));
- LODWORD(qwTimestamp) = cpu_to_le32(LODWORD(*sFrame.pqwTimestamp));
- HIDWORD(qwLocalTSF) = HIDWORD(pRxPacket->qwLocalTSF);
- LODWORD(qwLocalTSF) = LODWORD(pRxPacket->qwLocalTSF);
-
- // check if beacon TSF larger or small than our local TSF
- if (HIDWORD(qwTimestamp) == HIDWORD(qwLocalTSF)) {
- if (LODWORD(qwTimestamp) >= LODWORD(qwLocalTSF)) {
- bTSFOffsetPostive = true;
- }
- else {
- bTSFOffsetPostive = false;
- }
- }
- else if (HIDWORD(qwTimestamp) > HIDWORD(qwLocalTSF)) {
- bTSFOffsetPostive = true;
- }
- else if (HIDWORD(qwTimestamp) < HIDWORD(qwLocalTSF)) {
- bTSFOffsetPostive = false;
- }
-
- if (bTSFOffsetPostive) {
- qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwTimestamp), (qwLocalTSF));
- }
- else {
- qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwLocalTSF), (qwTimestamp));
- }
-
- if (HIDWORD(qwTSFOffset) != 0 ||
- (LODWORD(qwTSFOffset) > TRIVIAL_SYNC_DIFFERENCE )) {
- bTSFLargeDiff = true;
- }
-
-
- // if infra mode
- if (bIsAPBeacon == true) {
-
- // Infra mode: Local TSF always follow AP's TSF if Difference huge.
- if (bTSFLargeDiff)
- bUpdateTSF = true;
-
- if ((pDevice->bEnablePSMode == true) &&(sFrame.pTIM != 0)) {
-
- // deal with DTIM, analysis TIM
- pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? true : false ;
- pMgmt->byDTIMCount = sFrame.pTIM->byDTIMCount;
- pMgmt->byDTIMPeriod = sFrame.pTIM->byDTIMPeriod;
- wAIDNumber = pMgmt->wCurrAID & ~(BIT14|BIT15);
-
- // check if AID in TIM field bit on
- // wStartIndex = N1
- wStartIndex = WLAN_MGMT_GET_TIM_OFFSET(sFrame.pTIM->byBitMapCtl) << 1;
- // AIDIndex = N2
- wAIDIndex = (wAIDNumber >> 3);
- if ((wAIDNumber > 0) && (wAIDIndex >= wStartIndex)) {
- uLocateByteIndex = wAIDIndex - wStartIndex;
- // len = byDTIMCount + byDTIMPeriod + byDTIMPeriod + byVirtBitMap[0~250]
- if (sFrame.pTIM->len >= (uLocateByteIndex + 4)) {
- byTIMBitOn = (0x01) << ((wAIDNumber) % 8);
- pMgmt->bInTIM = sFrame.pTIM->byVirtBitMap[uLocateByteIndex] & byTIMBitOn ? true : false;
- }
- else {
- pMgmt->bInTIM = false;
- };
- }
- else {
- pMgmt->bInTIM = false;
- };
-
- if (pMgmt->bInTIM ||
- (pMgmt->bMulticastTIM && (pMgmt->byDTIMCount == 0))) {
- pMgmt->bInTIMWake = true;
- // send out ps-poll packet
+ CARDbSetPhyParameter(pMgmt->pAdapter,
+ pMgmt->eCurrentPHYMode,
+ pMgmt->wCurrCapInfo,
+ pMgmt->byERPContext,
+ pMgmt->abyCurrSuppRates,
+ pMgmt->abyCurrExtSuppRates
+ );
+ }
+ if (sFrame.pIE_PowerConstraint != NULL) {
+ CARDvSetPowerConstraint(pMgmt->pAdapter,
+ (unsigned char) pBSSList->uChannel,
+ sFrame.pIE_PowerConstraint->byPower
+);
+ }
+ if (sFrame.pIE_CHSW != NULL) {
+ CARDbChannelSwitch(pMgmt->pAdapter,
+ sFrame.pIE_CHSW->byMode,
+ get_channel_mapping(pMgmt->pAdapter, sFrame.pIE_CHSW->byMode, pMgmt->eCurrentPHYMode),
+ sFrame.pIE_CHSW->byCount
+ );
+
+ } else if (bIsChannelEqual == false) {
+ set_channel(pMgmt->pAdapter, pBSSList->uChannel);
+ }
+ }
+ }
+
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Beacon 2 \n");
+ // check if CF field exists
+ if (WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)) {
+ if (sFrame.pCFParms->wCFPDurRemaining > 0) {
+ // TODO: deal with CFP period to set NAV
+ }
+ }
+
+ HIDWORD(qwTimestamp) = cpu_to_le32(HIDWORD(*sFrame.pqwTimestamp));
+ LODWORD(qwTimestamp) = cpu_to_le32(LODWORD(*sFrame.pqwTimestamp));
+ HIDWORD(qwLocalTSF) = HIDWORD(pRxPacket->qwLocalTSF);
+ LODWORD(qwLocalTSF) = LODWORD(pRxPacket->qwLocalTSF);
+
+ // check if beacon TSF larger or small than our local TSF
+ if (HIDWORD(qwTimestamp) == HIDWORD(qwLocalTSF)) {
+ if (LODWORD(qwTimestamp) >= LODWORD(qwLocalTSF)) {
+ bTSFOffsetPostive = true;
+ } else {
+ bTSFOffsetPostive = false;
+ }
+ } else if (HIDWORD(qwTimestamp) > HIDWORD(qwLocalTSF)) {
+ bTSFOffsetPostive = true;
+ } else if (HIDWORD(qwTimestamp) < HIDWORD(qwLocalTSF)) {
+ bTSFOffsetPostive = false;
+ }
+
+ if (bTSFOffsetPostive) {
+ qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwTimestamp), (qwLocalTSF));
+ } else {
+ qwTSFOffset = CARDqGetTSFOffset(pRxPacket->byRxRate, (qwLocalTSF), (qwTimestamp));
+ }
+
+ if (HIDWORD(qwTSFOffset) != 0 ||
+ (LODWORD(qwTSFOffset) > TRIVIAL_SYNC_DIFFERENCE)) {
+ bTSFLargeDiff = true;
+ }
+
+ // if infra mode
+ if (bIsAPBeacon == true) {
+ // Infra mode: Local TSF always follow AP's TSF if Difference huge.
+ if (bTSFLargeDiff)
+ bUpdateTSF = true;
+
+ if ((pDevice->bEnablePSMode == true) && (sFrame.pTIM != 0)) {
+ // deal with DTIM, analysis TIM
+ pMgmt->bMulticastTIM = WLAN_MGMT_IS_MULTICAST_TIM(sFrame.pTIM->byBitMapCtl) ? true : false;
+ pMgmt->byDTIMCount = sFrame.pTIM->byDTIMCount;
+ pMgmt->byDTIMPeriod = sFrame.pTIM->byDTIMPeriod;
+ wAIDNumber = pMgmt->wCurrAID & ~(BIT14|BIT15);
+
+ // check if AID in TIM field bit on
+ // wStartIndex = N1
+ wStartIndex = WLAN_MGMT_GET_TIM_OFFSET(sFrame.pTIM->byBitMapCtl) << 1;
+ // AIDIndex = N2
+ wAIDIndex = (wAIDNumber >> 3);
+ if ((wAIDNumber > 0) && (wAIDIndex >= wStartIndex)) {
+ uLocateByteIndex = wAIDIndex - wStartIndex;
+ // len = byDTIMCount + byDTIMPeriod + byDTIMPeriod + byVirtBitMap[0~250]
+ if (sFrame.pTIM->len >= (uLocateByteIndex + 4)) {
+ byTIMBitOn = (0x01) << ((wAIDNumber) % 8);
+ pMgmt->bInTIM = sFrame.pTIM->byVirtBitMap[uLocateByteIndex] & byTIMBitOn ? true : false;
+ } else {
+ pMgmt->bInTIM = false;
+ };
+ } else {
+ pMgmt->bInTIM = false;
+ };
+
+ if (pMgmt->bInTIM ||
+ (pMgmt->bMulticastTIM && (pMgmt->byDTIMCount == 0))) {
+ pMgmt->bInTIMWake = true;
+ // send out ps-poll packet
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:In TIM\n");
- if (pMgmt->bInTIM) {
- PSvSendPSPOLL((PSDevice)pDevice);
+ if (pMgmt->bInTIM) {
+ PSvSendPSPOLL((PSDevice)pDevice);
// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN:PS-POLL sent..\n");
- }
-
- }
- else {
- pMgmt->bInTIMWake = false;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Not In TIM..\n");
- if (pDevice->bPWBitOn == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Send Null Packet\n");
- if (PSbSendNullPacket(pDevice))
- pDevice->bPWBitOn = true;
- }
- if(PSbConsiderPowerDown(pDevice, false, false)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Power down now...\n");
- }
- }
-
- }
-
- }
- // if adhoc mode
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && !bIsAPBeacon && bIsChannelEqual) {
- if (bIsBSSIDEqual) {
- // Use sNodeDBTable[0].uInActiveCount as IBSS beacons received count.
- if (pMgmt->sNodeDBTable[0].uInActiveCount != 0)
- pMgmt->sNodeDBTable[0].uInActiveCount = 0;
-
- // adhoc mode:TSF updated only when beacon larger than local TSF
- if (bTSFLargeDiff && bTSFOffsetPostive &&
- (pMgmt->eCurrState == WMAC_STATE_JOINTED))
- bUpdateTSF = true;
-
- // During dpc, already in spinlocked.
- if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) {
-
- // Update the STA, (Technically the Beacons of all the IBSS nodes
- // should be identical, but that's not happening in practice.
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- WLAN_RATES_MAXLEN_11B);
- RATEvParseMaxRate( (void *)pDevice,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- NULL,
- true,
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
- );
- pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].uInActiveCount = 0;
- }
- else {
- // Todo, initial Node content
- BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
-
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- WLAN_RATES_MAXLEN_11B);
- RATEvParseMaxRate( (void *)pDevice,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- NULL,
- true,
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
- &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
- );
-
- memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, sFrame.pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
- pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
-#ifdef PLICE_DEBUG
- //if (uNodeIndex == 0)
- {
- printk("s_vMgrRxBeacon:TxDataRate is %d,Index is %d\n",pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate,uNodeIndex);
+ }
+
+ } else {
+ pMgmt->bInTIMWake = false;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Not In TIM..\n");
+ if (pDevice->bPWBitOn == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Send Null Packet\n");
+ if (PSbSendNullPacket(pDevice))
+ pDevice->bPWBitOn = true;
+ }
+ if (PSbConsiderPowerDown(pDevice, false, false)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BCN: Power down now...\n");
+ }
+ }
+
}
+
+ }
+ // if adhoc mode
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && !bIsAPBeacon && bIsChannelEqual) {
+ if (bIsBSSIDEqual) {
+ // Use sNodeDBTable[0].uInActiveCount as IBSS beacons received count.
+ if (pMgmt->sNodeDBTable[0].uInActiveCount != 0)
+ pMgmt->sNodeDBTable[0].uInActiveCount = 0;
+
+ // adhoc mode:TSF updated only when beacon larger than local TSF
+ if (bTSFLargeDiff && bTSFOffsetPostive &&
+ (pMgmt->eCurrState == WMAC_STATE_JOINTED))
+ bUpdateTSF = true;
+
+ // During dpc, already in spinlocked.
+ if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) {
+ // Update the STA, (Technically the Beacons of all the IBSS nodes
+ // should be identical, but that's not happening in practice.
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ WLAN_RATES_MAXLEN_11B);
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ NULL,
+ true,
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
+ );
+ pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].uInActiveCount = 0;
+ } else {
+ // Todo, initial Node content
+ BSSvCreateOneNode((PSDevice)pDevice, &uNodeIndex);
+
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ WLAN_RATES_MAXLEN_11B);
+ RATEvParseMaxRate((void *)pDevice,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ NULL,
+ true,
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].wSuppRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopCCKBasicRate),
+ &(pMgmt->sNodeDBTable[uNodeIndex].byTopOFDMBasicRate)
+ );
+
+ memcpy(pMgmt->sNodeDBTable[uNodeIndex].abyMACAddr, sFrame.pHdr->sA3.abyAddr2, WLAN_ADDR_LEN);
+ pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble = WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
+ pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate = pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate;
+#ifdef PLICE_DEBUG
+ {
+ printk("s_vMgrRxBeacon:TxDataRate is %d,Index is %d\n", pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate, uNodeIndex);
+ }
#endif
/*
- pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
- pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
+ pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime = WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
+ if (pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
+ pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
*/
- }
-
- // if other stations joined, indicate connection to upper layer..
- if (pMgmt->eCurrState == WMAC_STATE_STARTED) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n");
- pMgmt->eCurrState = WMAC_STATE_JOINTED;
- pDevice->bLinkPass = true;
- if (netif_queue_stopped(pDevice->dev)){
- netif_wake_queue(pDevice->dev);
- }
- pMgmt->sNodeDBTable[0].bActive = true;
- pMgmt->sNodeDBTable[0].uInActiveCount = 0;
-
- }
- }
- else if (bIsSSIDEqual) {
-
- // See other adhoc sta with the same SSID but BSSID is different.
- // adpot this vars only when TSF larger then us.
- if (bTSFLargeDiff && bTSFOffsetPostive) {
- // we don't support ATIM under adhoc mode
- // if ( sFrame.pIBSSParms->wATIMWindow == 0) {
- // adpot this vars
- // TODO: check sFrame cap if privacy on, and support rate syn
- memcpy(pMgmt->abyCurrBSSID, sFrame.pHdr->sA3.abyAddr3, WLAN_BSSID_LEN);
- memcpy(pDevice->abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- pMgmt->wCurrATIMWindow = cpu_to_le16(sFrame.pIBSSParms->wATIMWindow);
- pMgmt->wCurrBeaconPeriod = cpu_to_le16(*sFrame.pwBeaconInterval);
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- WLAN_RATES_MAXLEN_11B);
- // set HW beacon interval and re-synchronizing....
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rejoining to Other Adhoc group with same SSID........\n");
- VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, pMgmt->wCurrBeaconPeriod);
- CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, qwLocalTSF);
- CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod);
- // Turn off bssid filter to avoid filter others adhoc station which bssid is different.
- MACvWriteBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID);
-
- CARDbSetPhyParameter ( pMgmt->pAdapter,
- pMgmt->eCurrentPHYMode,
- pMgmt->wCurrCapInfo,
- pMgmt->byERPContext,
- pMgmt->abyCurrSuppRates,
- pMgmt->abyCurrExtSuppRates);
-
-
- // MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
- // set highest basic rate
- // s_vSetHighestBasicRate(pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates);
- // Prepare beacon frame
- bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
- // }
- }
- }
- }
- // endian issue ???
- // Update TSF
- if (bUpdateTSF) {
- CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
- CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, pRxPacket->qwLocalTSF);
- CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
- CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod);
- }
-
- return;
-}
-
+ }
+
+ // if other stations joined, indicate connection to upper layer..
+ if (pMgmt->eCurrState == WMAC_STATE_STARTED) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n");
+ pMgmt->eCurrState = WMAC_STATE_JOINTED;
+ pDevice->bLinkPass = true;
+ if (netif_queue_stopped(pDevice->dev)) {
+ netif_wake_queue(pDevice->dev);
+ }
+ pMgmt->sNodeDBTable[0].bActive = true;
+ pMgmt->sNodeDBTable[0].uInActiveCount = 0;
+
+ }
+ } else if (bIsSSIDEqual) {
+ // See other adhoc sta with the same SSID but BSSID is different.
+ // adpot this vars only when TSF larger then us.
+ if (bTSFLargeDiff && bTSFOffsetPostive) {
+ // we don't support ATIM under adhoc mode
+ // if (sFrame.pIBSSParms->wATIMWindow == 0) {
+ // adpot this vars
+ // TODO: check sFrame cap if privacy on, and support rate syn
+ memcpy(pMgmt->abyCurrBSSID, sFrame.pHdr->sA3.abyAddr3, WLAN_BSSID_LEN);
+ memcpy(pDevice->abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ pMgmt->wCurrATIMWindow = cpu_to_le16(sFrame.pIBSSParms->wATIMWindow);
+ pMgmt->wCurrBeaconPeriod = cpu_to_le16(*sFrame.pwBeaconInterval);
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ WLAN_RATES_MAXLEN_11B);
+ // set HW beacon interval and re-synchronizing....
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rejoining to Other Adhoc group with same SSID........\n");
+ VNSvOutPortW(pDevice->PortOffset + MAC_REG_BI, pMgmt->wCurrBeaconPeriod);
+ CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, qwLocalTSF);
+ CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod);
+ // Turn off bssid filter to avoid filter others adhoc station which bssid is different.
+ MACvWriteBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID);
+
+ CARDbSetPhyParameter(pMgmt->pAdapter,
+ pMgmt->eCurrentPHYMode,
+ pMgmt->wCurrCapInfo,
+ pMgmt->byERPContext,
+ pMgmt->abyCurrSuppRates,
+ pMgmt->abyCurrExtSuppRates);
+
+ // MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
+ // set highest basic rate
+ // s_vSetHighestBasicRate(pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates);
+ // Prepare beacon frame
+ bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
+ // }
+ }
+ }
+ }
+ // endian issue ???
+ // Update TSF
+if (bUpdateTSF) {
+ CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
+ CARDbUpdateTSF(pDevice, pRxPacket->byRxRate, qwTimestamp, pRxPacket->qwLocalTSF);
+ CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
+ CARDvUpdateNextTBTT(pDevice->PortOffset, qwTimestamp, pMgmt->wCurrBeaconPeriod);
+ }
+ return;
+}
/*+
*
@@ -2384,248 +2261,239 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
* Return Value:
* CMD_STATUS
*
--*/
+ -*/
void
vMgrCreateOwnIBSS(
- void *hDeviceContext,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PCMD_STATUS pStatus
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned short wMaxBasicRate;
- unsigned short wMaxSuppRate;
- unsigned char byTopCCKBasicRate;
- unsigned char byTopOFDMBasicRate;
- QWORD qwCurrTSF;
- unsigned int ii;
- unsigned char abyRATE[] = {0x82, 0x84, 0x8B, 0x96, 0x24, 0x30, 0x48, 0x6C, 0x0C, 0x12, 0x18, 0x60};
- unsigned char abyCCK_RATE[] = {0x82, 0x84, 0x8B, 0x96};
- unsigned char abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- unsigned short wSuppRate;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create Basic Service Set .......\n");
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) &&
- (pDevice->eEncryptionStatus != Ndis802_11Encryption2Enabled) &&
- (pDevice->eEncryptionStatus != Ndis802_11Encryption3Enabled)) {
- // encryption mode error
- *pStatus = CMD_STATUS_FAILURE;
- return;
- }
- }
-
- pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
- pMgmt->abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- pMgmt->eCurrentPHYMode = pMgmt->byAPBBType;
- } else {
- if (pDevice->byBBType == BB_TYPE_11G)
- pMgmt->eCurrentPHYMode = PHY_TYPE_11G;
- if (pDevice->byBBType == BB_TYPE_11B)
- pMgmt->eCurrentPHYMode = PHY_TYPE_11B;
- if (pDevice->byBBType == BB_TYPE_11A)
- pMgmt->eCurrentPHYMode = PHY_TYPE_11A;
- }
-
- if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) {
- pMgmt->abyCurrSuppRates[1] = WLAN_RATES_MAXLEN_11B;
- pMgmt->abyCurrExtSuppRates[1] = 0;
- for (ii = 0; ii < 4; ii++)
- pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii];
- } else {
- pMgmt->abyCurrSuppRates[1] = 8;
- pMgmt->abyCurrExtSuppRates[1] = 0;
- for (ii = 0; ii < 8; ii++)
- pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii];
- }
-
-
- if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
- pMgmt->abyCurrSuppRates[1] = 8;
- pMgmt->abyCurrExtSuppRates[1] = 4;
- for (ii = 0; ii < 4; ii++)
- pMgmt->abyCurrSuppRates[2+ii] = abyCCK_RATE[ii];
- for (ii = 4; ii < 8; ii++)
- pMgmt->abyCurrSuppRates[2+ii] = abyOFDM_RATE[ii-4];
- for (ii = 0; ii < 4; ii++)
- pMgmt->abyCurrExtSuppRates[2+ii] = abyOFDM_RATE[ii+4];
- }
-
-
- // Disable Protect Mode
- pDevice->bProtectMode = 0;
- MACvDisableProtectMD(pDevice->PortOffset);
-
- pDevice->bBarkerPreambleMd = 0;
- MACvDisableBarkerPreambleMd(pDevice->PortOffset);
-
- // Kyle Test 2003.11.04
-
- // set HW beacon interval
- if (pMgmt->wIBSSBeaconPeriod == 0)
- pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
-
-
- CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
- // clear TSF counter
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
- // enable TSF counter
- VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
-
- // set Next TBTT
- CARDvSetFirstNextTBTT(pDevice->PortOffset, pMgmt->wIBSSBeaconPeriod);
-
- pMgmt->uIBSSChannel = pDevice->uChannel;
-
- if (pMgmt->uIBSSChannel == 0)
- pMgmt->uIBSSChannel = DEFAULT_IBSS_CHANNEL;
-
-
- // set basic rate
-
- RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, true,
- &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
- &byTopCCKBasicRate, &byTopOFDMBasicRate);
-
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- pMgmt->eCurrMode = WMAC_MODE_ESS_AP;
- }
-
- if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
- memcpy(pMgmt->abyIBSSDFSOwner, pDevice->abyCurrentNetAddr, 6);
- pMgmt->byIBSSDFSRecovery = 10;
- pMgmt->eCurrMode = WMAC_MODE_IBSS_STA;
- }
-
- // Adopt pre-configured IBSS vars to current vars
- pMgmt->eCurrState = WMAC_STATE_STARTED;
- pMgmt->wCurrBeaconPeriod = pMgmt->wIBSSBeaconPeriod;
- pMgmt->uCurrChannel = pMgmt->uIBSSChannel;
- pMgmt->wCurrATIMWindow = pMgmt->wIBSSATIMWindow;
- MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
- pDevice->uCurrRSSI = 0;
- pDevice->byCurrSQ = 0;
- //memcpy(pMgmt->abyDesireSSID,pMgmt->abyAdHocSSID,
- // ((PWLAN_IE_SSID)pMgmt->abyAdHocSSID)->len + WLAN_IEHDR_LEN);
- memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- memcpy(pMgmt->abyCurrSSID,
- pMgmt->abyDesireSSID,
- ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN
- );
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- // AP mode BSSID = MAC addr
- memcpy(pMgmt->abyCurrBSSID, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO"AP beacon created BSSID:%pM\n",
- pMgmt->abyCurrBSSID);
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-
- // BSSID selected must be randomized as spec 11.1.3
- pMgmt->abyCurrBSSID[5] = (unsigned char) (LODWORD(qwCurrTSF)& 0x000000ff);
- pMgmt->abyCurrBSSID[4] = (unsigned char)((LODWORD(qwCurrTSF)& 0x0000ff00) >> 8);
- pMgmt->abyCurrBSSID[3] = (unsigned char)((LODWORD(qwCurrTSF)& 0x00ff0000) >> 16);
- pMgmt->abyCurrBSSID[2] = (unsigned char)((LODWORD(qwCurrTSF)& 0x00000ff0) >> 4);
- pMgmt->abyCurrBSSID[1] = (unsigned char)((LODWORD(qwCurrTSF)& 0x000ff000) >> 12);
- pMgmt->abyCurrBSSID[0] = (unsigned char)((LODWORD(qwCurrTSF)& 0x0ff00000) >> 20);
- pMgmt->abyCurrBSSID[5] ^= pMgmt->abyMACAddr[0];
- pMgmt->abyCurrBSSID[4] ^= pMgmt->abyMACAddr[1];
- pMgmt->abyCurrBSSID[3] ^= pMgmt->abyMACAddr[2];
- pMgmt->abyCurrBSSID[2] ^= pMgmt->abyMACAddr[3];
- pMgmt->abyCurrBSSID[1] ^= pMgmt->abyMACAddr[4];
- pMgmt->abyCurrBSSID[0] ^= pMgmt->abyMACAddr[5];
- pMgmt->abyCurrBSSID[0] &= ~IEEE_ADDR_GROUP;
- pMgmt->abyCurrBSSID[0] |= IEEE_ADDR_UNIVERSAL;
-
-
- DBG_PRT(MSG_LEVEL_INFO, KERN_INFO"Adhoc beacon created bssid:%pM\n",
- pMgmt->abyCurrBSSID);
- }
-
- // Set Capability Info
- pMgmt->wCurrCapInfo = 0;
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
- pMgmt->byDTIMPeriod = DEFAULT_DTIM_PERIOD;
- pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_IBSS(1);
- }
-
- if (pDevice->bEncryptionEnable) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- pMgmt->byCSSPK = KEY_CTL_CCMP;
- pMgmt->byCSSGK = KEY_CTL_CCMP;
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- pMgmt->byCSSPK = KEY_CTL_TKIP;
- pMgmt->byCSSGK = KEY_CTL_TKIP;
- } else {
- pMgmt->byCSSPK = KEY_CTL_NONE;
- pMgmt->byCSSGK = KEY_CTL_WEP;
- }
- } else {
- pMgmt->byCSSPK = KEY_CTL_WEP;
- pMgmt->byCSSGK = KEY_CTL_WEP;
- }
- }
-
- pMgmt->byERPContext = 0;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned short wMaxBasicRate;
+ unsigned short wMaxSuppRate;
+ unsigned char byTopCCKBasicRate;
+ unsigned char byTopOFDMBasicRate;
+ QWORD qwCurrTSF;
+ unsigned int ii;
+ unsigned char abyRATE[] = {0x82, 0x84, 0x8B, 0x96, 0x24, 0x30, 0x48, 0x6C, 0x0C, 0x12, 0x18, 0x60};
+ unsigned char abyCCK_RATE[] = {0x82, 0x84, 0x8B, 0x96};
+ unsigned char abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned short wSuppRate;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create Basic Service Set .......\n");
+
+ if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) &&
+ (pDevice->eEncryptionStatus != Ndis802_11Encryption2Enabled) &&
+ (pDevice->eEncryptionStatus != Ndis802_11Encryption3Enabled)) {
+ // encryption mode error
+ *pStatus = CMD_STATUS_FAILURE;
+ return;
+ }
+ }
+
+ pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
+ pMgmt->abyCurrExtSuppRates[0] = WLAN_EID_EXTSUPP_RATES;
+
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ pMgmt->eCurrentPHYMode = pMgmt->byAPBBType;
+ } else {
+ if (pDevice->byBBType == BB_TYPE_11G)
+ pMgmt->eCurrentPHYMode = PHY_TYPE_11G;
+ if (pDevice->byBBType == BB_TYPE_11B)
+ pMgmt->eCurrentPHYMode = PHY_TYPE_11B;
+ if (pDevice->byBBType == BB_TYPE_11A)
+ pMgmt->eCurrentPHYMode = PHY_TYPE_11A;
+ }
+
+ if (pMgmt->eCurrentPHYMode != PHY_TYPE_11A) {
+ pMgmt->abyCurrSuppRates[1] = WLAN_RATES_MAXLEN_11B;
+ pMgmt->abyCurrExtSuppRates[1] = 0;
+ for (ii = 0; ii < 4; ii++)
+ pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii];
+ } else {
+ pMgmt->abyCurrSuppRates[1] = 8;
+ pMgmt->abyCurrExtSuppRates[1] = 0;
+ for (ii = 0; ii < 8; ii++)
+ pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii];
+ }
+
+ if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
+ pMgmt->abyCurrSuppRates[1] = 8;
+ pMgmt->abyCurrExtSuppRates[1] = 4;
+ for (ii = 0; ii < 4; ii++)
+ pMgmt->abyCurrSuppRates[2+ii] = abyCCK_RATE[ii];
+ for (ii = 4; ii < 8; ii++)
+ pMgmt->abyCurrSuppRates[2+ii] = abyOFDM_RATE[ii-4];
+ for (ii = 0; ii < 4; ii++)
+ pMgmt->abyCurrExtSuppRates[2+ii] = abyOFDM_RATE[ii+4];
+ }
+
+ // Disable Protect Mode
+ pDevice->bProtectMode = 0;
+ MACvDisableProtectMD(pDevice->PortOffset);
+
+ pDevice->bBarkerPreambleMd = 0;
+ MACvDisableBarkerPreambleMd(pDevice->PortOffset);
+
+ // Kyle Test 2003.11.04
+
+ // set HW beacon interval
+ if (pMgmt->wIBSSBeaconPeriod == 0)
+ pMgmt->wIBSSBeaconPeriod = DEFAULT_IBSS_BI;
+
+ CARDbGetCurrentTSF(pDevice->PortOffset, &qwCurrTSF);
+ // clear TSF counter
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTRST);
+ // enable TSF counter
+ VNSvOutPortB(pDevice->PortOffset + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN);
+
+ // set Next TBTT
+ CARDvSetFirstNextTBTT(pDevice->PortOffset, pMgmt->wIBSSBeaconPeriod);
+
+ pMgmt->uIBSSChannel = pDevice->uChannel;
+
+ if (pMgmt->uIBSSChannel == 0)
+ pMgmt->uIBSSChannel = DEFAULT_IBSS_CHANNEL;
+
+ // set basic rate
+
+ RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates, true,
+ &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
+ &byTopCCKBasicRate, &byTopOFDMBasicRate);
+
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ pMgmt->eCurrMode = WMAC_MODE_ESS_AP;
+ }
+
+ if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
+ memcpy(pMgmt->abyIBSSDFSOwner, pDevice->abyCurrentNetAddr, 6);
+ pMgmt->byIBSSDFSRecovery = 10;
+ pMgmt->eCurrMode = WMAC_MODE_IBSS_STA;
+ }
+
+ // Adopt pre-configured IBSS vars to current vars
+ pMgmt->eCurrState = WMAC_STATE_STARTED;
+ pMgmt->wCurrBeaconPeriod = pMgmt->wIBSSBeaconPeriod;
+ pMgmt->uCurrChannel = pMgmt->uIBSSChannel;
+ pMgmt->wCurrATIMWindow = pMgmt->wIBSSATIMWindow;
+ MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
+ pDevice->uCurrRSSI = 0;
+ pDevice->byCurrSQ = 0;
+ //memcpy(pMgmt->abyDesireSSID,pMgmt->abyAdHocSSID,
+ // ((PWLAN_IE_SSID)pMgmt->abyAdHocSSID)->len + WLAN_IEHDR_LEN);
+ memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ memcpy(pMgmt->abyCurrSSID,
+ pMgmt->abyDesireSSID,
+ ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN
+);
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ // AP mode BSSID = MAC addr
+ memcpy(pMgmt->abyCurrBSSID, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "AP beacon created BSSID:%pM\n",
+ pMgmt->abyCurrBSSID);
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ // BSSID selected must be randomized as spec 11.1.3
+ pMgmt->abyCurrBSSID[5] = (unsigned char) (LODWORD(qwCurrTSF) & 0x000000ff);
+ pMgmt->abyCurrBSSID[4] = (unsigned char)((LODWORD(qwCurrTSF) & 0x0000ff00) >> 8);
+ pMgmt->abyCurrBSSID[3] = (unsigned char)((LODWORD(qwCurrTSF) & 0x00ff0000) >> 16);
+ pMgmt->abyCurrBSSID[2] = (unsigned char)((LODWORD(qwCurrTSF) & 0x00000ff0) >> 4);
+ pMgmt->abyCurrBSSID[1] = (unsigned char)((LODWORD(qwCurrTSF) & 0x000ff000) >> 12);
+ pMgmt->abyCurrBSSID[0] = (unsigned char)((LODWORD(qwCurrTSF) & 0x0ff00000) >> 20);
+ pMgmt->abyCurrBSSID[5] ^= pMgmt->abyMACAddr[0];
+ pMgmt->abyCurrBSSID[4] ^= pMgmt->abyMACAddr[1];
+ pMgmt->abyCurrBSSID[3] ^= pMgmt->abyMACAddr[2];
+ pMgmt->abyCurrBSSID[2] ^= pMgmt->abyMACAddr[3];
+ pMgmt->abyCurrBSSID[1] ^= pMgmt->abyMACAddr[4];
+ pMgmt->abyCurrBSSID[0] ^= pMgmt->abyMACAddr[5];
+ pMgmt->abyCurrBSSID[0] &= ~IEEE_ADDR_GROUP;
+ pMgmt->abyCurrBSSID[0] |= IEEE_ADDR_UNIVERSAL;
+
+ DBG_PRT(MSG_LEVEL_INFO, KERN_INFO "Adhoc beacon created bssid:%pM\n",
+ pMgmt->abyCurrBSSID);
+ }
+
+ // Set Capability Info
+ pMgmt->wCurrCapInfo = 0;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
+ pMgmt->byDTIMPeriod = DEFAULT_DTIM_PERIOD;
+ pMgmt->byDTIMCount = pMgmt->byDTIMPeriod - 1;
+ }
+
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_IBSS(1);
+ }
+
+ if (pDevice->bEncryptionEnable) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ pMgmt->byCSSPK = KEY_CTL_CCMP;
+ pMgmt->byCSSGK = KEY_CTL_CCMP;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ pMgmt->byCSSPK = KEY_CTL_TKIP;
+ pMgmt->byCSSGK = KEY_CTL_TKIP;
+ } else {
+ pMgmt->byCSSPK = KEY_CTL_NONE;
+ pMgmt->byCSSGK = KEY_CTL_WEP;
+ }
+ } else {
+ pMgmt->byCSSPK = KEY_CTL_WEP;
+ pMgmt->byCSSGK = KEY_CTL_WEP;
+ }
+ }
+
+ pMgmt->byERPContext = 0;
// memcpy(pDevice->abyBSSID, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP);
- } else {
- CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
- }
-
- CARDbSetPhyParameter( pMgmt->pAdapter,
- pMgmt->eCurrentPHYMode,
- pMgmt->wCurrCapInfo,
- pMgmt->byERPContext,
- pMgmt->abyCurrSuppRates,
- pMgmt->abyCurrExtSuppRates
- );
-
- CARDbSetBeaconPeriod(pMgmt->pAdapter, pMgmt->wIBSSBeaconPeriod);
- // set channel and clear NAV
- set_channel(pMgmt->pAdapter, pMgmt->uIBSSChannel);
- pMgmt->uCurrChannel = pMgmt->uIBSSChannel;
-
- if (CARDbIsShortPreamble(pMgmt->pAdapter)) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
- } else {
- pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SHORTPREAMBLE(1));
- }
-
- if ((pMgmt->b11hEnable == true) &&
- (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
- } else {
- pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SPECTRUMMNG(1));
- }
-
- pMgmt->eCurrState = WMAC_STATE_STARTED;
- // Prepare beacon to send
- if (bMgrPrepareBeaconToSend((void *)pDevice, pMgmt)) {
- *pStatus = CMD_STATUS_SUCCESS;
- }
-
- return ;
-}
+ if (pMgmt->eConfigMode == WMAC_CONFIG_AP) {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_AP);
+ } else {
+ CARDbSetBSSID(pMgmt->pAdapter, pMgmt->abyCurrBSSID, OP_MODE_ADHOC);
+ }
+
+ CARDbSetPhyParameter(pMgmt->pAdapter,
+ pMgmt->eCurrentPHYMode,
+ pMgmt->wCurrCapInfo,
+ pMgmt->byERPContext,
+ pMgmt->abyCurrSuppRates,
+ pMgmt->abyCurrExtSuppRates
+ );
+
+ CARDbSetBeaconPeriod(pMgmt->pAdapter, pMgmt->wIBSSBeaconPeriod);
+ // set channel and clear NAV
+ set_channel(pMgmt->pAdapter, pMgmt->uIBSSChannel);
+ pMgmt->uCurrChannel = pMgmt->uIBSSChannel;
+
+ if (CARDbIsShortPreamble(pMgmt->pAdapter)) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
+ } else {
+ pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SHORTPREAMBLE(1));
+ }
+ if ((pMgmt->b11hEnable == true) &&
+ (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
+ } else {
+ pMgmt->wCurrCapInfo &= (~WLAN_SET_CAP_INFO_SPECTRUMMNG(1));
+ }
+
+ pMgmt->eCurrState = WMAC_STATE_STARTED;
+ // Prepare beacon to send
+ if (bMgrPrepareBeaconToSend((void *)pDevice, pMgmt)) {
+ *pStatus = CMD_STATUS_SUCCESS;
+ }
+ return;
+}
/*+
*
@@ -2638,260 +2506,244 @@ vMgrCreateOwnIBSS(
* Return Value:
* None.
*
--*/
+ -*/
void
vMgrJoinBSSBegin(
- void *hDeviceContext,
- PCMD_STATUS pStatus
- )
+ void *hDeviceContext,
+ PCMD_STATUS pStatus
+)
{
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PKnownBSS pCurr = NULL;
+ unsigned int ii, uu;
+ PWLAN_IE_SUPP_RATES pItemRates = NULL;
+ PWLAN_IE_SUPP_RATES pItemExtRates = NULL;
+ PWLAN_IE_SSID pItemSSID;
+ unsigned int uRateLen = WLAN_RATES_MAXLEN;
+ unsigned short wMaxBasicRate = RATE_1M;
+ unsigned short wMaxSuppRate = RATE_1M;
+ unsigned short wSuppRate;
+ unsigned char byTopCCKBasicRate = RATE_1M;
+ unsigned char byTopOFDMBasicRate = RATE_1M;
+
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ if (pMgmt->sBSSList[ii].bActive == true)
+ break;
+ }
+
+ if (ii == MAX_BSS_NUM) {
+ *pStatus = CMD_STATUS_RESOURCES;
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "BSS finding:BSS list is empty.\n");
+ return;
+ }
+
+ // memset(pMgmt->abyDesireBSSID, 0, WLAN_BSSID_LEN);
+ // Search known BSS list for prefer BSSID or SSID
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PKnownBSS pCurr = NULL;
- unsigned int ii, uu;
- PWLAN_IE_SUPP_RATES pItemRates = NULL;
- PWLAN_IE_SUPP_RATES pItemExtRates = NULL;
- PWLAN_IE_SSID pItemSSID;
- unsigned int uRateLen = WLAN_RATES_MAXLEN;
- unsigned short wMaxBasicRate = RATE_1M;
- unsigned short wMaxSuppRate = RATE_1M;
- unsigned short wSuppRate;
- unsigned char byTopCCKBasicRate = RATE_1M;
- unsigned char byTopOFDMBasicRate = RATE_1M;
-
-
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- if (pMgmt->sBSSList[ii].bActive == true)
- break;
- }
-
- if (ii == MAX_BSS_NUM) {
- *pStatus = CMD_STATUS_RESOURCES;
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "BSS finding:BSS list is empty.\n");
- return;
- }
-
- // memset(pMgmt->abyDesireBSSID, 0, WLAN_BSSID_LEN);
- // Search known BSS list for prefer BSSID or SSID
-
- pCurr = BSSpSearchBSSList(pDevice,
- pMgmt->abyDesireBSSID,
- pMgmt->abyDesireSSID,
- pMgmt->eConfigPHYMode
- );
-
- if (pCurr == NULL){
- *pStatus = CMD_STATUS_RESOURCES;
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Scanning [%s] not found, disconnected !\n", pItemSSID->abySSID);
- return;
- }
-
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP(BSS) finding:Found a AP(BSS)..\n");
- if (WLAN_GET_CAP_INFO_ESS(cpu_to_le16(pCurr->wCapInfo))){
-
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA)||(pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) {
-
- // patch for CISCO migration mode
+ pCurr = BSSpSearchBSSList(pDevice,
+ pMgmt->abyDesireBSSID,
+ pMgmt->abyDesireSSID,
+ pMgmt->eConfigPHYMode
+);
+
+ if (pCurr == NULL) {
+ *pStatus = CMD_STATUS_RESOURCES;
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Scanning [%s] not found, disconnected !\n", pItemSSID->abySSID);
+ return;
+ }
+
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP(BSS) finding:Found a AP(BSS)..\n");
+ if (WLAN_GET_CAP_INFO_ESS(cpu_to_le16(pCurr->wCapInfo))) {
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPA) || (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK)) {
+ // patch for CISCO migration mode
/*
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- // encryption mode error
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- return;
- }
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- // encryption mode error
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- return;
- }
- }
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ // encryption mode error
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ return;
+ }
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "No match RSN info. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ // encryption mode error
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ return;
+ }
+ }
*/
- }
+ }
#ifdef WPA_SUPPLICANT_DRIVER_WEXT_SUPPORT
- //if(pDevice->bWPASuppWextEnabled == true)
- Encyption_Rebuild(pDevice, pCurr);
+ Encyption_Rebuild(pDevice, pCurr);
#endif
- // Infrastructure BSS
- s_vMgrSynchBSS(pDevice,
- WMAC_MODE_ESS_STA,
- pCurr,
- pStatus
- );
-
- if (*pStatus == CMD_STATUS_SUCCESS){
-
- // Adopt this BSS state vars in Mgmt Object
- pMgmt->uCurrChannel = pCurr->uChannel;
-
- memset(pMgmt->abyCurrSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
- memset(pMgmt->abyCurrExtSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
-
- if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) {
- uRateLen = WLAN_RATES_MAXLEN_11B;
- }
-
- pItemRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates;
- pItemExtRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates;
-
- // Parse Support Rate IE
- pItemRates->byElementID = WLAN_EID_SUPP_RATES;
- pItemRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates,
- pItemRates,
- uRateLen);
-
- // Parse Extension Support Rate IE
- pItemExtRates->byElementID = WLAN_EID_EXTSUPP_RATES;
- pItemExtRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abyExtSuppRates,
- pItemExtRates,
- uRateLen);
- // Stuffing Rate IE
- if ((pItemExtRates->len > 0) && (pItemRates->len < 8)) {
- for (ii = 0; ii < (unsigned int)(8 - pItemRates->len); ) {
- pItemRates->abyRates[pItemRates->len + ii] = pItemExtRates->abyRates[ii];
- ii ++;
- if (pItemExtRates->len <= ii)
- break;
- }
- pItemRates->len += (unsigned char)ii;
- if (pItemExtRates->len - ii > 0) {
- pItemExtRates->len -= (unsigned char)ii;
- for (uu = 0; uu < pItemExtRates->len; uu ++) {
- pItemExtRates->abyRates[uu] = pItemExtRates->abyRates[uu + ii];
- }
- } else {
- pItemExtRates->len = 0;
- }
- }
-
- RATEvParseMaxRate((void *)pDevice, pItemRates, pItemExtRates, true,
- &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
- &byTopCCKBasicRate, &byTopOFDMBasicRate);
-
- // TODO: deal with if wCapInfo the privacy is on, but station WEP is off
- // TODO: deal with if wCapInfo the PS-Pollable is on.
- pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval;
- memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
- memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
-
- pMgmt->eCurrMode = WMAC_MODE_ESS_STA;
-
- pMgmt->eCurrState = WMAC_STATE_JOINTED;
- // Adopt BSS state in Adapter Device Object
- //pDevice->byOpMode = OP_MODE_INFRASTRUCTURE;
+ // Infrastructure BSS
+ s_vMgrSynchBSS(pDevice,
+ WMAC_MODE_ESS_STA,
+ pCurr,
+ pStatus
+);
+
+ if (*pStatus == CMD_STATUS_SUCCESS) {
+ // Adopt this BSS state vars in Mgmt Object
+ pMgmt->uCurrChannel = pCurr->uChannel;
+
+ memset(pMgmt->abyCurrSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+ memset(pMgmt->abyCurrExtSuppRates, 0 , WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
+
+ if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) {
+ uRateLen = WLAN_RATES_MAXLEN_11B;
+ }
+
+ pItemRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates;
+ pItemExtRates = (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates;
+
+ // Parse Support Rate IE
+ pItemRates->byElementID = WLAN_EID_SUPP_RATES;
+ pItemRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates,
+ pItemRates,
+ uRateLen);
+
+ // Parse Extension Support Rate IE
+ pItemExtRates->byElementID = WLAN_EID_EXTSUPP_RATES;
+ pItemExtRates->len = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abyExtSuppRates,
+ pItemExtRates,
+ uRateLen);
+ // Stuffing Rate IE
+ if ((pItemExtRates->len > 0) && (pItemRates->len < 8)) {
+ for (ii = 0; ii < (unsigned int)(8 - pItemRates->len);) {
+ pItemRates->abyRates[pItemRates->len + ii] = pItemExtRates->abyRates[ii];
+ ii++;
+ if (pItemExtRates->len <= ii)
+ break;
+ }
+ pItemRates->len += (unsigned char)ii;
+ if (pItemExtRates->len - ii > 0) {
+ pItemExtRates->len -= (unsigned char)ii;
+ for (uu = 0; uu < pItemExtRates->len; uu++) {
+ pItemExtRates->abyRates[uu] = pItemExtRates->abyRates[uu + ii];
+ }
+ } else {
+ pItemExtRates->len = 0;
+ }
+ }
+
+ RATEvParseMaxRate((void *)pDevice, pItemRates, pItemExtRates, true,
+ &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
+ &byTopCCKBasicRate, &byTopOFDMBasicRate);
+
+ // TODO: deal with if wCapInfo the privacy is on, but station WEP is off
+ // TODO: deal with if wCapInfo the PS-Pollable is on.
+ pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval;
+ memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+ memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
+ memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
+
+ pMgmt->eCurrMode = WMAC_MODE_ESS_STA;
+
+ pMgmt->eCurrState = WMAC_STATE_JOINTED;
+ // Adopt BSS state in Adapter Device Object
+ //pDevice->byOpMode = OP_MODE_INFRASTRUCTURE;
// memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
- // Add current BSS to Candidate list
- // This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- bool bResult = bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate: 1(%d)\n", bResult);
- if (bResult == false) {
- vFlush_PMKID_Candidate((void *)pDevice);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFlush_PMKID_Candidate: 4\n");
- bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
- }
- }
-
- // Preamble type auto-switch: if AP can receive short-preamble cap,
- // we can turn on too.
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join ESS\n");
-
-
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"End of Join AP -- A/B/G Action\n");
- }
- else {
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- };
-
-
- }
- else {
- // ad-hoc mode BSS
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
-
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
- // encryption mode error
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- return;
- }
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
- // encryption mode error
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- return;
- }
- } else {
- // encryption mode error
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- return;
- }
- }
-
- s_vMgrSynchBSS(pDevice,
- WMAC_MODE_IBSS_STA,
- pCurr,
- pStatus
- );
-
- if (*pStatus == CMD_STATUS_SUCCESS){
- // Adopt this BSS state vars in Mgmt Object
- // TODO: check if CapInfo privacy on, but we don't..
- pMgmt->uCurrChannel = pCurr->uChannel;
-
-
- // Parse Support Rate IE
- pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
- pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- WLAN_RATES_MAXLEN_11B);
- // set basic rate
- RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- NULL, true, &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
- &byTopCCKBasicRate, &byTopOFDMBasicRate);
-
- pMgmt->wCurrCapInfo = pCurr->wCapInfo;
- pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval;
- memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN);
- memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
- memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN);
+ // Add current BSS to Candidate list
+ // This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
+ bool bResult = bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bAdd_PMKID_Candidate: 1(%d)\n", bResult);
+ if (bResult == false) {
+ vFlush_PMKID_Candidate((void *)pDevice);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vFlush_PMKID_Candidate: 4\n");
+ bAdd_PMKID_Candidate((void *)pDevice, pMgmt->abyCurrBSSID, &pCurr->sRSNCapObj);
+ }
+ }
+
+ // Preamble type auto-switch: if AP can receive short-preamble cap,
+ // we can turn on too.
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Join ESS\n");
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "End of Join AP -- A/B/G Action\n");
+ } else {
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ };
+
+ } else {
+ // ad-hoc mode BSS
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ if (WPA_SearchRSN(0, WPA_TKIP, pCurr) == false) {
+ // encryption mode error
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ return;
+ }
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ if (WPA_SearchRSN(0, WPA_AESCCMP, pCurr) == false) {
+ // encryption mode error
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ return;
+ }
+ } else {
+ // encryption mode error
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ return;
+ }
+ }
+
+ s_vMgrSynchBSS(pDevice,
+ WMAC_MODE_IBSS_STA,
+ pCurr,
+ pStatus
+);
+
+ if (*pStatus == CMD_STATUS_SUCCESS) {
+ // Adopt this BSS state vars in Mgmt Object
+ // TODO: check if CapInfo privacy on, but we don't..
+ pMgmt->uCurrChannel = pCurr->uChannel;
+
+ // Parse Support Rate IE
+ pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
+ pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ WLAN_RATES_MAXLEN_11B);
+ // set basic rate
+ RATEvParseMaxRate((void *)pDevice, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ NULL, true, &wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
+ &byTopCCKBasicRate, &byTopOFDMBasicRate);
+
+ pMgmt->wCurrCapInfo = pCurr->wCapInfo;
+ pMgmt->wCurrBeaconPeriod = pCurr->wBeaconInterval;
+ memset(pMgmt->abyCurrSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN);
+ memcpy(pMgmt->abyCurrBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
+ memcpy(pMgmt->abyCurrSSID, pCurr->abySSID, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN);
// pMgmt->wCurrATIMWindow = pCurr->wATIMWindow;
- MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
- pMgmt->eCurrMode = WMAC_MODE_IBSS_STA;
+ MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
+ pMgmt->eCurrMode = WMAC_MODE_IBSS_STA;
- pMgmt->eCurrState = WMAC_STATE_STARTED;
- // Adopt BSS state in Adapter Device Object
- //pDevice->byOpMode = OP_MODE_ADHOC;
+ pMgmt->eCurrState = WMAC_STATE_STARTED;
+ // Adopt BSS state in Adapter Device Object
+ //pDevice->byOpMode = OP_MODE_ADHOC;
// pDevice->bLinkPass = true;
// memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join IBSS ok:%pM\n",
- pMgmt->abyCurrBSSID);
- // Preamble type auto-switch: if AP can receive short-preamble cap,
- // and if registry setting is short preamble we can turn on too.
-
- // Prepare beacon
- bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
- }
- else {
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- };
- };
- return;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Join IBSS ok:%pM\n",
+ pMgmt->abyCurrBSSID);
+ // Preamble type auto-switch: if AP can receive short-preamble cap,
+ // and if registry setting is short preamble we can turn on too.
+
+ // Prepare beacon
+ bMgrPrepareBeaconToSend((void *)pDevice, pMgmt);
+ } else {
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ };
+ };
+ return;
}
-
-
/*+
*
* Routine Description:
@@ -2901,215 +2753,199 @@ vMgrJoinBSSBegin(
* Return Value:
* PCM_STATUS
*
--*/
+ -*/
static
void
-s_vMgrSynchBSS (
- PSDevice pDevice,
- unsigned int uBSSMode,
- PKnownBSS pCurr,
- PCMD_STATUS pStatus
- )
+s_vMgrSynchBSS(
+ PSDevice pDevice,
+ unsigned int uBSSMode,
+ PKnownBSS pCurr,
+ PCMD_STATUS pStatus
+)
{
- CARD_PHY_TYPE ePhyType = PHY_TYPE_11B;
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ CARD_PHY_TYPE ePhyType = PHY_TYPE_11B;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
// int ii;
- //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
- unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
- unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
- //6M, 9M, 12M, 48M
- unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
- unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
-
-
- *pStatus = CMD_STATUS_FAILURE;
-
- if (s_bCipherMatch(pCurr,
- pDevice->eEncryptionStatus,
- &(pMgmt->byCSSPK),
- &(pMgmt->byCSSGK)) == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_bCipherMatch Fail .......\n");
- return;
- }
-
- pMgmt->pCurrBSS = pCurr;
-
- // if previous mode is IBSS.
- if(pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_BCNDMACTL, BEACON_READY);
- MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
- }
-
- // Init the BSS informations
- pDevice->bCCK = true;
- pDevice->bProtectMode = false;
- MACvDisableProtectMD(pDevice->PortOffset);
- pDevice->bBarkerPreambleMd = false;
- MACvDisableBarkerPreambleMd(pDevice->PortOffset);
- pDevice->bNonERPPresent = false;
- pDevice->byPreambleType = 0;
- pDevice->wBasicRate = 0;
- // Set Basic Rate
- CARDbAddBasicRate((void *)pDevice, RATE_1M);
- // calculate TSF offset
- // TSF Offset = Received Timestamp TSF - Marked Local's TSF
- CARDbUpdateTSF(pDevice, pCurr->byRxRate, pCurr->qwBSSTimestamp, pCurr->qwLocalTSF);
-
- CARDbSetBeaconPeriod(pDevice, pCurr->wBeaconInterval);
-
- // set Next TBTT
- // Next TBTT = ((local_current_TSF / beacon_interval) + 1 ) * beacon_interval
- CARDvSetFirstNextTBTT(pDevice->PortOffset, pCurr->wBeaconInterval);
-
- // set BSSID
- MACvWriteBSSIDAddress(pDevice->PortOffset, pCurr->abyBSSID);
-
- MACvReadBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID);
+ //1M, 2M, 5M, 11M, 18M, 24M, 36M, 54M
+ unsigned char abyCurrSuppRatesG[] = {WLAN_EID_SUPP_RATES, 8, 0x02, 0x04, 0x0B, 0x16, 0x24, 0x30, 0x48, 0x6C};
+ unsigned char abyCurrExtSuppRatesG[] = {WLAN_EID_EXTSUPP_RATES, 4, 0x0C, 0x12, 0x18, 0x60};
+ //6M, 9M, 12M, 48M
+ unsigned char abyCurrSuppRatesA[] = {WLAN_EID_SUPP_RATES, 8, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
+ unsigned char abyCurrSuppRatesB[] = {WLAN_EID_SUPP_RATES, 4, 0x02, 0x04, 0x0B, 0x16};
+
+ *pStatus = CMD_STATUS_FAILURE;
+
+ if (s_bCipherMatch(pCurr,
+ pDevice->eEncryptionStatus,
+ &(pMgmt->byCSSPK),
+ &(pMgmt->byCSSGK)) == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "s_bCipherMatch Fail .......\n");
+ return;
+ }
+
+ pMgmt->pCurrBSS = pCurr;
+
+ // if previous mode is IBSS.
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_BCNDMACTL, BEACON_READY);
+ MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
+ }
+
+ // Init the BSS informations
+ pDevice->bCCK = true;
+ pDevice->bProtectMode = false;
+ MACvDisableProtectMD(pDevice->PortOffset);
+ pDevice->bBarkerPreambleMd = false;
+ MACvDisableBarkerPreambleMd(pDevice->PortOffset);
+ pDevice->bNonERPPresent = false;
+ pDevice->byPreambleType = 0;
+ pDevice->wBasicRate = 0;
+ // Set Basic Rate
+ CARDbAddBasicRate((void *)pDevice, RATE_1M);
+ // calculate TSF offset
+ // TSF Offset = Received Timestamp TSF - Marked Local's TSF
+ CARDbUpdateTSF(pDevice, pCurr->byRxRate, pCurr->qwBSSTimestamp, pCurr->qwLocalTSF);
+
+ CARDbSetBeaconPeriod(pDevice, pCurr->wBeaconInterval);
+
+ // set Next TBTT
+ // Next TBTT = ((local_current_TSF / beacon_interval) + 1) * beacon_interval
+ CARDvSetFirstNextTBTT(pDevice->PortOffset, pCurr->wBeaconInterval);
+
+ // set BSSID
+ MACvWriteBSSIDAddress(pDevice->PortOffset, pCurr->abyBSSID);
+
+ MACvReadBSSIDAddress(pDevice->PortOffset, pMgmt->abyCurrBSSID);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:set CurrBSSID address = "
"%pM\n", pMgmt->abyCurrBSSID);
- if (pCurr->eNetworkTypeInUse == PHY_TYPE_11A) {
- if ((pMgmt->eConfigPHYMode == PHY_TYPE_11A) ||
- (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
- ePhyType = PHY_TYPE_11A;
- } else {
- return;
- }
- } else if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) {
- if ((pMgmt->eConfigPHYMode == PHY_TYPE_11B) ||
- (pMgmt->eConfigPHYMode == PHY_TYPE_11G) ||
- (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
- ePhyType = PHY_TYPE_11B;
- } else {
- return;
- }
- } else {
- if ((pMgmt->eConfigPHYMode == PHY_TYPE_11G) ||
- (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
- ePhyType = PHY_TYPE_11G;
- } else if (pMgmt->eConfigPHYMode == PHY_TYPE_11B) {
- ePhyType = PHY_TYPE_11B;
- } else {
- return;
- }
- }
-
- if (ePhyType == PHY_TYPE_11A) {
- memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesA[0], sizeof(abyCurrSuppRatesA));
- pMgmt->abyCurrExtSuppRates[1] = 0;
- } else if (ePhyType == PHY_TYPE_11B) {
- memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesB[0], sizeof(abyCurrSuppRatesB));
- pMgmt->abyCurrExtSuppRates[1] = 0;
- } else {
- memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesG[0], sizeof(abyCurrSuppRatesG));
- memcpy(pMgmt->abyCurrExtSuppRates, &abyCurrExtSuppRatesG[0], sizeof(abyCurrExtSuppRatesG));
- }
-
-
- if (WLAN_GET_CAP_INFO_ESS(pCurr->wCapInfo)) {
- CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_INFRASTRUCTURE);
- // Add current BSS to Candidate list
- // This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- CARDbAdd_PMKID_Candidate(pMgmt->pAdapter, pMgmt->abyCurrBSSID, pCurr->sRSNCapObj.bRSNCapExist, pCurr->sRSNCapObj.wRSNCap);
- }
- } else {
- CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_ADHOC);
- }
-
- if (CARDbSetPhyParameter( pMgmt->pAdapter,
- ePhyType,
- pCurr->wCapInfo,
- pCurr->sERP.byERP,
- pMgmt->abyCurrSuppRates,
- pMgmt->abyCurrExtSuppRates
- ) != true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Phy Mode Fail [%d]\n", ePhyType);
- return;
- }
- // set channel and clear NAV
- if (set_channel(pMgmt->pAdapter, pCurr->uChannel) == false) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Channel [%d]\n", pCurr->uChannel);
- return;
- }
+ if (pCurr->eNetworkTypeInUse == PHY_TYPE_11A) {
+ if ((pMgmt->eConfigPHYMode == PHY_TYPE_11A) ||
+ (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
+ ePhyType = PHY_TYPE_11A;
+ } else {
+ return;
+ }
+ } else if (pCurr->eNetworkTypeInUse == PHY_TYPE_11B) {
+ if ((pMgmt->eConfigPHYMode == PHY_TYPE_11B) ||
+ (pMgmt->eConfigPHYMode == PHY_TYPE_11G) ||
+ (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
+ ePhyType = PHY_TYPE_11B;
+ } else {
+ return;
+ }
+ } else {
+ if ((pMgmt->eConfigPHYMode == PHY_TYPE_11G) ||
+ (pMgmt->eConfigPHYMode == PHY_TYPE_AUTO)) {
+ ePhyType = PHY_TYPE_11G;
+ } else if (pMgmt->eConfigPHYMode == PHY_TYPE_11B) {
+ ePhyType = PHY_TYPE_11B;
+ } else {
+ return;
+ }
+ }
-/*
- for (ii=0;ii<BB_VGA_LEVEL;ii++) {
- if (pCurr->ldBmMAX< pDevice->ldBmThreshold[ii]) {
- pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
- break;
- }
- }
-
- if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RSSI[%d] NewGain[%d] OldGain[%d] \n",
- (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
- printk("RSSI[%d] NewGain[%d] OldGain[%d] \n",
- (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
- }
- printk("ldBmMAX[%d] NewGain[%d] OldGain[%d] \n",
- (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
-*/
- pMgmt->uCurrChannel = pCurr->uChannel;
- pMgmt->eCurrentPHYMode = ePhyType;
- pMgmt->byERPContext = pCurr->sERP.byERP;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:Set to channel = [%d]\n", (int)pCurr->uChannel);
+ if (ePhyType == PHY_TYPE_11A) {
+ memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesA[0], sizeof(abyCurrSuppRatesA));
+ pMgmt->abyCurrExtSuppRates[1] = 0;
+ } else if (ePhyType == PHY_TYPE_11B) {
+ memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesB[0], sizeof(abyCurrSuppRatesB));
+ pMgmt->abyCurrExtSuppRates[1] = 0;
+ } else {
+ memcpy(pMgmt->abyCurrSuppRates, &abyCurrSuppRatesG[0], sizeof(abyCurrSuppRatesG));
+ memcpy(pMgmt->abyCurrExtSuppRates, &abyCurrExtSuppRatesG[0], sizeof(abyCurrExtSuppRatesG));
+ }
+
+ if (WLAN_GET_CAP_INFO_ESS(pCurr->wCapInfo)) {
+ CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_INFRASTRUCTURE);
+ // Add current BSS to Candidate list
+ // This should only works for WPA2 BSS, and WPA2 BSS check must be done before.
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
+ CARDbAdd_PMKID_Candidate(pMgmt->pAdapter, pMgmt->abyCurrBSSID, pCurr->sRSNCapObj.bRSNCapExist, pCurr->sRSNCapObj.wRSNCap);
+ }
+ } else {
+ CARDbSetBSSID(pMgmt->pAdapter, pCurr->abyBSSID, OP_MODE_ADHOC);
+ }
+ if (CARDbSetPhyParameter(pMgmt->pAdapter,
+ ePhyType,
+ pCurr->wCapInfo,
+ pCurr->sERP.byERP,
+ pMgmt->abyCurrSuppRates,
+ pMgmt->abyCurrExtSuppRates
+ ) != true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Phy Mode Fail [%d]\n", ePhyType);
+ return;
+ }
+ // set channel and clear NAV
+ if (set_channel(pMgmt->pAdapter, pCurr->uChannel) == false) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "<----s_bSynchBSS Set Channel [%d]\n", pCurr->uChannel);
+ return;
+ }
- *pStatus = CMD_STATUS_SUCCESS;
+/*
+ for (ii=0; ii<BB_VGA_LEVEL; ii++) {
+ if (pCurr->ldBmMAX< pDevice->ldBmThreshold[ii]) {
+ pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
+ break;
+ }
+ }
+ if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "RSSI[%d] NewGain[%d] OldGain[%d] \n",
+ (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
+ printk("RSSI[%d] NewGain[%d] OldGain[%d] \n",
+ (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
+ BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
+ }
+ printk("ldBmMAX[%d] NewGain[%d] OldGain[%d] \n",
+ (int)pCurr->ldBmMAX, pDevice->byBBVGANew, pDevice->byBBVGACurrent);
+*/
+ pMgmt->uCurrChannel = pCurr->uChannel;
+ pMgmt->eCurrentPHYMode = ePhyType;
+ pMgmt->byERPContext = pCurr->sERP.byERP;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Sync:Set to channel = [%d]\n", (int)pCurr->uChannel);
- return;
+ *pStatus = CMD_STATUS_SUCCESS;
+
+ return;
};
//mike add: fix NetworkManager 0.7.0 hidden ssid mode in WPA encryption
// ,need reset eAuthenMode and eEncryptionStatus
- static void Encyption_Rebuild(
- PSDevice pDevice,
- PKnownBSS pCurr
- )
- {
- PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
- // unsigned int ii , uSameBssidNum=0;
-
- // for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- // if (pMgmt->sBSSList[ii].bActive &&
- // !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pCurr->abyBSSID)) {
- // uSameBssidNum++;
- // }
- // }
- // if( uSameBssidNum>=2) { //we only check AP in hidden sssid mode
- if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selection,
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-select it according to real pairwise-key info.
- if(pCurr->bWPAValid == true) { //WPA-PSK
- pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
- if(pCurr->abyPKType[0] == WPA_TKIP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
- PRINT_K("Encyption_Rebuild--->ssid reset config to [WPAPSK-TKIP]\n");
- }
- else if(pCurr->abyPKType[0] == WPA_AESCCMP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES
- PRINT_K("Encyption_Rebuild--->ssid reset config to [WPAPSK-AES]\n");
- }
- }
- else if(pCurr->bWPA2Valid == true) { //WPA2-PSK
- pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
- if(pCurr->abyCSSPK[0] == WLAN_11i_CSS_TKIP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
- PRINT_K("Encyption_Rebuild--->ssid reset config to [WPA2PSK-TKIP]\n");
- }
- else if(pCurr->abyCSSPK[0] == WLAN_11i_CSS_CCMP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES
- PRINT_K("Encyption_Rebuild--->ssid reset config to [WPA2PSK-AES]\n");
- }
- }
- }
- // }
- return;
- }
-
+static void Encyption_Rebuild(
+ PSDevice pDevice,
+ PKnownBSS pCurr
+)
+{
+ PSMgmtObject pMgmt = &(pDevice->sMgmtObj);
+
+ if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selection,
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-select it according to real pairwise-key info.
+ if (pCurr->bWPAValid == true) { //WPA-PSK
+ pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
+ if (pCurr->abyPKType[0] == WPA_TKIP) {
+ pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
+ PRINT_K("Encyption_Rebuild--->ssid reset config to [WPAPSK-TKIP]\n");
+ } else if (pCurr->abyPKType[0] == WPA_AESCCMP) {
+ pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES
+ PRINT_K("Encyption_Rebuild--->ssid reset config to [WPAPSK-AES]\n");
+ }
+ } else if (pCurr->bWPA2Valid == true) { //WPA2-PSK
+ pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
+ if (pCurr->abyCSSPK[0] == WLAN_11i_CSS_TKIP) {
+ pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled; //TKIP
+ PRINT_K("Encyption_Rebuild--->ssid reset config to [WPA2PSK-TKIP]\n");
+ } else if (pCurr->abyCSSPK[0] == WLAN_11i_CSS_CCMP) {
+ pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled; //AES
+ PRINT_K("Encyption_Rebuild--->ssid reset config to [WPA2PSK-AES]\n");
+ }
+ }
+ }
+ // }
+ return;
+}
/*+
*
@@ -3120,298 +2956,290 @@ s_vMgrSynchBSS (
* Return Value:
* void
*
--*/
+ -*/
static
void
s_vMgrFormatTIM(
- PSMgmtObject pMgmt,
- PWLAN_IE_TIM pTIM
- )
+ PSMgmtObject pMgmt,
+ PWLAN_IE_TIM pTIM
+)
{
- unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
- unsigned char byMap;
- unsigned int ii, jj;
- bool bStartFound = false;
- bool bMulticast = false;
- unsigned short wStartIndex = 0;
- unsigned short wEndIndex = 0;
-
-
- // Find size of partial virtual bitmap
- for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
- byMap = pMgmt->abyPSTxMap[ii];
- if (!ii) {
- // Mask out the broadcast bit which is indicated separately.
- bMulticast = (byMap & byMask[0]) != 0;
- if(bMulticast) {
- pMgmt->sNodeDBTable[0].bRxPSPoll = true;
- }
- byMap = 0;
- }
- if (byMap) {
- if (!bStartFound) {
- bStartFound = true;
- wStartIndex = ii;
- }
- wEndIndex = ii;
- }
- }
-
-
- // Round start index down to nearest even number
- wStartIndex &= ~BIT0;
-
- // Round end index up to nearest even number
- wEndIndex = ((wEndIndex + 1) & ~BIT0);
-
- // Size of element payload
-
- pTIM->len = 3 + (wEndIndex - wStartIndex) + 1;
-
- // Fill in the Fixed parts of the TIM
- pTIM->byDTIMCount = pMgmt->byDTIMCount;
- pTIM->byDTIMPeriod = pMgmt->byDTIMPeriod;
- pTIM->byBitMapCtl = (bMulticast ? TIM_MULTICAST_MASK : 0) |
- (((wStartIndex >> 1) << 1) & TIM_BITMAPOFFSET_MASK);
-
- // Append variable part of TIM
-
- for (ii = wStartIndex, jj =0 ; ii <= wEndIndex; ii++, jj++) {
- pTIM->byVirtBitMap[jj] = pMgmt->abyPSTxMap[ii];
- }
-
- // Aid = 0 don't used.
- pTIM->byVirtBitMap[0] &= ~BIT0;
-}
+ unsigned char byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
+ unsigned char byMap;
+ unsigned int ii, jj;
+ bool bStartFound = false;
+ bool bMulticast = false;
+ unsigned short wStartIndex = 0;
+ unsigned short wEndIndex = 0;
+
+ // Find size of partial virtual bitmap
+ for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
+ byMap = pMgmt->abyPSTxMap[ii];
+ if (!ii) {
+ // Mask out the broadcast bit which is indicated separately.
+ bMulticast = (byMap & byMask[0]) != 0;
+ if (bMulticast) {
+ pMgmt->sNodeDBTable[0].bRxPSPoll = true;
+ }
+ byMap = 0;
+ }
+ if (byMap) {
+ if (!bStartFound) {
+ bStartFound = true;
+ wStartIndex = ii;
+ }
+ wEndIndex = ii;
+ }
+ }
+
+ // Round start index down to nearest even number
+ wStartIndex &= ~BIT0;
+
+ // Round end index up to nearest even number
+ wEndIndex = ((wEndIndex + 1) & ~BIT0);
+
+ // Size of element payload
+
+ pTIM->len = 3 + (wEndIndex - wStartIndex) + 1;
+
+ // Fill in the Fixed parts of the TIM
+ pTIM->byDTIMCount = pMgmt->byDTIMCount;
+ pTIM->byDTIMPeriod = pMgmt->byDTIMPeriod;
+ pTIM->byBitMapCtl = (bMulticast ? TIM_MULTICAST_MASK : 0) |
+ (((wStartIndex >> 1) << 1) & TIM_BITMAPOFFSET_MASK);
+ // Append variable part of TIM
+
+ for (ii = wStartIndex, jj = 0; ii <= wEndIndex; ii++, jj++) {
+ pTIM->byVirtBitMap[jj] = pMgmt->abyPSTxMap[ii];
+ }
+
+ // Aid = 0 don't used.
+ pTIM->byVirtBitMap[0] &= ~BIT0;
+}
/*+
*
* Routine Description:
- * Constructs an Beacon frame( Ad-hoc mode)
+ * Constructs an Beacon frame(Ad-hoc mode)
*
*
* Return Value:
* PTR to frame; or NULL on allocation failure
*
--*/
+ -*/
static
PSTxMgmtPacket
s_MgrMakeBeacon(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wCurrBeaconPeriod,
- unsigned int uCurrChannel,
- unsigned short wCurrATIMWinodw,
- PWLAN_IE_SSID pCurrSSID,
- unsigned char *pCurrBSSID,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ PWLAN_IE_SSID pCurrSSID,
+ unsigned char *pCurrBSSID,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_BEACON sFrame;
- unsigned char abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- unsigned char *pbyBuffer;
- unsigned int uLength = 0;
- PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
- unsigned int ii;
-
- // prepare beacon frame
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_BEACON_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- // Setup the sFrame structure.
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_BEACON_FR_MAXLEN;
- vMgrEncodeBeacon(&sFrame);
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_BEACON)
- ));
-
- if (pDevice->bEnablePSMode) {
- sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_PWRMGT(1));
- }
-
- memcpy( sFrame.pHdr->sA3.abyAddr1, abyBroadcastAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN);
- *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod);
- *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
- // Copy SSID
- sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSSID,
- pCurrSSID,
- ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN
- );
- // Copy the rate set
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates,
- pCurrSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
- );
- // DS parameter
- if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
- sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len);
- sFrame.len += (1) + WLAN_IEHDR_LEN;
- sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
- sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
- }
- // TIM field
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- sFrame.pTIM = (PWLAN_IE_TIM)(sFrame.pBuf + sFrame.len);
- sFrame.pTIM->byElementID = WLAN_EID_TIM;
- s_vMgrFormatTIM(pMgmt, sFrame.pTIM);
- sFrame.len += (WLAN_IEHDR_LEN + sFrame.pTIM->len);
- }
-
- if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-
- // IBSS parameter
- sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len);
- sFrame.len += (2) + WLAN_IEHDR_LEN;
- sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS;
- sFrame.pIBSSParms->len = 2;
- sFrame.pIBSSParms->wATIMWindow = wCurrATIMWinodw;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- /* RSN parameter */
- sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
- sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
- sFrame.pRSNWPA->len = 12;
- sFrame.pRSNWPA->abyOUI[0] = 0x00;
- sFrame.pRSNWPA->abyOUI[1] = 0x50;
- sFrame.pRSNWPA->abyOUI[2] = 0xf2;
- sFrame.pRSNWPA->abyOUI[3] = 0x01;
- sFrame.pRSNWPA->wVersion = 1;
- sFrame.pRSNWPA->abyMulticast[0] = 0x00;
- sFrame.pRSNWPA->abyMulticast[1] = 0x50;
- sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
- sFrame.pRSNWPA->abyMulticast[3] = 0x04;//AES
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
- sFrame.pRSNWPA->abyMulticast[3] = 0x02;//TKIP
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled)
- sFrame.pRSNWPA->abyMulticast[3] = 0x01;//WEP40
- else
- sFrame.pRSNWPA->abyMulticast[3] = 0x00;//NONE
-
- // Pairwise Key Cipher Suite
- sFrame.pRSNWPA->wPKCount = 0;
- // Auth Key Management Suite
- *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
- sFrame.pRSNWPA->len +=2;
-
- // RSN Capabilities
- *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
- sFrame.pRSNWPA->len +=2;
- sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
- }
- }
-
- if ((pMgmt->b11hEnable == true) &&
- (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
- // Country IE
- pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
- set_country_IE(pMgmt->pAdapter, pbyBuffer);
- set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
- uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
- pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
- // Power Constrain IE
- ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT;
- ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1;
- ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
- pbyBuffer += (1) + WLAN_IEHDR_LEN;
- uLength += (1) + WLAN_IEHDR_LEN;
- if (pMgmt->bSwitchChannel == true) {
- // Channel Switch IE
- ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
- ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
- ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
- pbyBuffer += (3) + WLAN_IEHDR_LEN;
- uLength += (3) + WLAN_IEHDR_LEN;
- }
- // TPC report
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP;
- ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2;
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter);
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0;
- pbyBuffer += (2) + WLAN_IEHDR_LEN;
- uLength += (2) + WLAN_IEHDR_LEN;
- // IBSS DFS
- if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
- pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer;
- pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS;
- pIBSSDFS->len = 7;
- memcpy( pIBSSDFS->abyDFSOwner,
- pMgmt->abyIBSSDFSOwner,
- 6);
- pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery;
- pbyBuffer += (7) + WLAN_IEHDR_LEN;
- uLength += (7) + WLAN_IEHDR_LEN;
- for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) {
- if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
- pbyBuffer += 2;
- uLength += 2;
- pIBSSDFS->len += 2;
- }
- }
- }
- sFrame.len += uLength;
- }
-
- if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
- sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len);
- sFrame.len += 1 + WLAN_IEHDR_LEN;
- sFrame.pERP->byElementID = WLAN_EID_ERP;
- sFrame.pERP->len = 1;
- sFrame.pERP->byContext = 0;
- if (pDevice->bProtectMode == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
- if (pDevice->bNonERPPresent == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
- if (pDevice->bBarkerPreambleMd == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
- }
- if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates,
- pCurrExtSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
- );
- }
- // hostapd wpa/wpa2 IE
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- if (pMgmt->wWPAIELen != 0) {
- sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
- memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen);
- sFrame.len += pMgmt->wWPAIELen;
- }
- }
- }
-
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_BEACON sFrame;
+ unsigned char abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ unsigned char *pbyBuffer;
+ unsigned int uLength = 0;
+ PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
+ unsigned int ii;
+
+ // prepare beacon frame
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_BEACON_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ // Setup the sFrame structure.
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_BEACON_FR_MAXLEN;
+ vMgrEncodeBeacon(&sFrame);
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_BEACON)
+));
+
+ if (pDevice->bEnablePSMode) {
+ sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((unsigned short)WLAN_SET_FC_PWRMGT(1));
+ }
+ memcpy(sFrame.pHdr->sA3.abyAddr1, abyBroadcastAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN);
+ *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod);
+ *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
+ // Copy SSID
+ sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSSID,
+ pCurrSSID,
+ ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN
+);
+ // Copy the rate set
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates,
+ pCurrSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
+);
+ // DS parameter
+ if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
+ sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len);
+ sFrame.len += (1) + WLAN_IEHDR_LEN;
+ sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
+ sFrame.pDSParms->len = 1;
+ sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
+ }
+ // TIM field
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ sFrame.pTIM = (PWLAN_IE_TIM)(sFrame.pBuf + sFrame.len);
+ sFrame.pTIM->byElementID = WLAN_EID_TIM;
+ s_vMgrFormatTIM(pMgmt, sFrame.pTIM);
+ sFrame.len += (WLAN_IEHDR_LEN + sFrame.pTIM->len);
+ }
+ if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
+ // IBSS parameter
+ sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len);
+ sFrame.len += (2) + WLAN_IEHDR_LEN;
+ sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS;
+ sFrame.pIBSSParms->len = 2;
+ sFrame.pIBSSParms->wATIMWindow = wCurrATIMWinodw;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ /* RSN parameter */
+ sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
+ sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
+ sFrame.pRSNWPA->len = 12;
+ sFrame.pRSNWPA->abyOUI[0] = 0x00;
+ sFrame.pRSNWPA->abyOUI[1] = 0x50;
+ sFrame.pRSNWPA->abyOUI[2] = 0xf2;
+ sFrame.pRSNWPA->abyOUI[3] = 0x01;
+ sFrame.pRSNWPA->wVersion = 1;
+ sFrame.pRSNWPA->abyMulticast[0] = 0x00;
+ sFrame.pRSNWPA->abyMulticast[1] = 0x50;
+ sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
+ sFrame.pRSNWPA->abyMulticast[3] = 0x04;//AES
+ else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
+ sFrame.pRSNWPA->abyMulticast[3] = 0x02;//TKIP
+ else if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled)
+ sFrame.pRSNWPA->abyMulticast[3] = 0x01;//WEP40
+ else
+ sFrame.pRSNWPA->abyMulticast[3] = 0x00;//NONE
+
+ // Pairwise Key Cipher Suite
+ sFrame.pRSNWPA->wPKCount = 0;
+ // Auth Key Management Suite
+ *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len)) = 0;
+ sFrame.pRSNWPA->len += 2;
+
+ // RSN Capabilities
+ *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len)) = 0;
+ sFrame.pRSNWPA->len += 2;
+ sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+ }
+ }
+ if ((pMgmt->b11hEnable == true) &&
+ (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
+ // Country IE
+ pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
+ set_country_IE(pMgmt->pAdapter, pbyBuffer);
+ set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
+ uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
+ pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
+ // Power Constrain IE
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT;
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1;
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
+ pbyBuffer += (1) + WLAN_IEHDR_LEN;
+ uLength += (1) + WLAN_IEHDR_LEN;
+ if (pMgmt->bSwitchChannel == true) {
+ // Channel Switch IE
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
+ pbyBuffer += (3) + WLAN_IEHDR_LEN;
+ uLength += (3) + WLAN_IEHDR_LEN;
+ }
+ // TPC report
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP;
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2;
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter);
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0;
+ pbyBuffer += (2) + WLAN_IEHDR_LEN;
+ uLength += (2) + WLAN_IEHDR_LEN;
+ // IBSS DFS
+ if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
+ pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer;
+ pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS;
+ pIBSSDFS->len = 7;
+ memcpy(pIBSSDFS->abyDFSOwner,
+ pMgmt->abyIBSSDFSOwner,
+ 6);
+ pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery;
+ pbyBuffer += (7) + WLAN_IEHDR_LEN;
+ uLength += (7) + WLAN_IEHDR_LEN;
+ for (ii = CB_MAX_CHANNEL_24G+1; ii <= CB_MAX_CHANNEL; ii++) {
+ if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
+ pbyBuffer += 2;
+ uLength += 2;
+ pIBSSDFS->len += 2;
+ }
+ }
+ }
+ sFrame.len += uLength;
+ }
+ if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
+ sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len);
+ sFrame.len += 1 + WLAN_IEHDR_LEN;
+ sFrame.pERP->byElementID = WLAN_EID_ERP;
+ sFrame.pERP->len = 1;
+ sFrame.pERP->byContext = 0;
+ if (pDevice->bProtectMode == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
+ if (pDevice->bNonERPPresent == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
+ if (pDevice->bBarkerPreambleMd == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
+ }
+ if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates,
+ pCurrExtSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
+);
+ }
+ // hostapd wpa/wpa2 IE
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ if (pMgmt->wWPAIELen != 0) {
+ sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
+ memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen);
+ sFrame.len += pMgmt->wWPAIELen;
+ }
+ }
+ }
+
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ return pTxPacket;
+}
/*+
*
@@ -3422,187 +3250,180 @@ s_MgrMakeBeacon(
* Return Value:
* PTR to frame; or NULL on allocation failure
*
--*/
-
-
-
+ -*/
PSTxMgmtPacket
s_MgrMakeProbeResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wCurrBeaconPeriod,
- unsigned int uCurrChannel,
- unsigned short wCurrATIMWinodw,
- unsigned char *pDstAddr,
- PWLAN_IE_SSID pCurrSSID,
- unsigned char *pCurrBSSID,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
- unsigned char byPHYType
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wCurrBeaconPeriod,
+ unsigned int uCurrChannel,
+ unsigned short wCurrATIMWinodw,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SSID pCurrSSID,
+ unsigned char *pCurrBSSID,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates,
+ unsigned char byPHYType
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_PROBERESP sFrame;
- unsigned char *pbyBuffer;
- unsigned int uLength = 0;
- PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
- unsigned int ii;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBERESP_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- // Setup the sFrame structure.
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_PROBERESP_FR_MAXLEN;
- vMgrEncodeProbeResponse(&sFrame);
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBERESP)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN);
- *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod);
- *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
-
- if (byPHYType == BB_TYPE_11B) {
- *sFrame.pwCapInfo &= cpu_to_le16((unsigned short)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
- }
-
- // Copy SSID
- sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSSID,
- pCurrSSID,
- ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN
- );
- // Copy the rate set
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
-
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates,
- pCurrSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
- );
-
- // DS parameter
- if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
- sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len);
- sFrame.len += (1) + WLAN_IEHDR_LEN;
- sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
- sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
- }
-
- if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
- // IBSS parameter
- sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len);
- sFrame.len += (2) + WLAN_IEHDR_LEN;
- sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS;
- sFrame.pIBSSParms->len = 2;
- sFrame.pIBSSParms->wATIMWindow = 0;
- }
- if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
- sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len);
- sFrame.len += 1 + WLAN_IEHDR_LEN;
- sFrame.pERP->byElementID = WLAN_EID_ERP;
- sFrame.pERP->len = 1;
- sFrame.pERP->byContext = 0;
- if (pDevice->bProtectMode == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
- if (pDevice->bNonERPPresent == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
- if (pDevice->bBarkerPreambleMd == true)
- sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
- }
-
- if ((pMgmt->b11hEnable == true) &&
- (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
- // Country IE
- pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
- set_country_IE(pMgmt->pAdapter, pbyBuffer);
- set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
- uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
- pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
- // Power Constrain IE
- ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT;
- ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1;
- ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
- pbyBuffer += (1) + WLAN_IEHDR_LEN;
- uLength += (1) + WLAN_IEHDR_LEN;
- if (pMgmt->bSwitchChannel == true) {
- // Channel Switch IE
- ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
- ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
- ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
- ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
- pbyBuffer += (3) + WLAN_IEHDR_LEN;
- uLength += (3) + WLAN_IEHDR_LEN;
- }
- // TPC report
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP;
- ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2;
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter);
- ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0;
- pbyBuffer += (2) + WLAN_IEHDR_LEN;
- uLength += (2) + WLAN_IEHDR_LEN;
- // IBSS DFS
- if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
- pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer;
- pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS;
- pIBSSDFS->len = 7;
- memcpy( pIBSSDFS->abyDFSOwner,
- pMgmt->abyIBSSDFSOwner,
- 6);
- pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery;
- pbyBuffer += (7) + WLAN_IEHDR_LEN;
- uLength += (7) + WLAN_IEHDR_LEN;
- for(ii=CB_MAX_CHANNEL_24G+1; ii<=CB_MAX_CHANNEL; ii++ ) {
- if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
- pbyBuffer += 2;
- uLength += 2;
- pIBSSDFS->len += 2;
- }
- }
- }
- sFrame.len += uLength;
- }
-
-
- if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates,
- pCurrExtSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
- );
- }
-
- // hostapd wpa/wpa2 IE
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- if (pMgmt->wWPAIELen != 0) {
- sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
- memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen);
- sFrame.len += pMgmt->wWPAIELen;
- }
- }
- }
-
- // Adjust the length fields
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_PROBERESP sFrame;
+ unsigned char *pbyBuffer;
+ unsigned int uLength = 0;
+ PWLAN_IE_IBSS_DFS pIBSSDFS = NULL;
+ unsigned int ii;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_PROBERESP_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ // Setup the sFrame structure.
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_PROBERESP_FR_MAXLEN;
+ vMgrEncodeProbeResponse(&sFrame);
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PROBERESP)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pCurrBSSID, WLAN_BSSID_LEN);
+ *sFrame.pwBeaconInterval = cpu_to_le16(wCurrBeaconPeriod);
+ *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
+
+ if (byPHYType == BB_TYPE_11B) {
+ *sFrame.pwCapInfo &= cpu_to_le16((unsigned short)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
+ }
+
+ // Copy SSID
+ sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSSID,
+ pCurrSSID,
+ ((PWLAN_IE_SSID)pCurrSSID)->len + WLAN_IEHDR_LEN
+);
+ // Copy the rate set
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates,
+ pCurrSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
+);
+
+ // DS parameter
+ if (pDevice->eCurrentPHYType != PHY_TYPE_11A) {
+ sFrame.pDSParms = (PWLAN_IE_DS_PARMS)(sFrame.pBuf + sFrame.len);
+ sFrame.len += (1) + WLAN_IEHDR_LEN;
+ sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
+ sFrame.pDSParms->len = 1;
+ sFrame.pDSParms->byCurrChannel = (unsigned char)uCurrChannel;
+ }
+
+ if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
+ // IBSS parameter
+ sFrame.pIBSSParms = (PWLAN_IE_IBSS_PARMS)(sFrame.pBuf + sFrame.len);
+ sFrame.len += (2) + WLAN_IEHDR_LEN;
+ sFrame.pIBSSParms->byElementID = WLAN_EID_IBSS_PARMS;
+ sFrame.pIBSSParms->len = 2;
+ sFrame.pIBSSParms->wATIMWindow = 0;
+ }
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11G) {
+ sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len);
+ sFrame.len += 1 + WLAN_IEHDR_LEN;
+ sFrame.pERP->byElementID = WLAN_EID_ERP;
+ sFrame.pERP->len = 1;
+ sFrame.pERP->byContext = 0;
+ if (pDevice->bProtectMode == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_USE_PROTECTION;
+ if (pDevice->bNonERPPresent == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_NONERP_PRESENT;
+ if (pDevice->bBarkerPreambleMd == true)
+ sFrame.pERP->byContext |= WLAN_EID_ERP_BARKER_MODE;
+ }
+
+ if ((pMgmt->b11hEnable == true) &&
+ (pMgmt->eCurrentPHYMode == PHY_TYPE_11A)) {
+ // Country IE
+ pbyBuffer = (unsigned char *)(sFrame.pBuf + sFrame.len);
+ set_country_IE(pMgmt->pAdapter, pbyBuffer);
+ set_country_info(pMgmt->pAdapter, PHY_TYPE_11A, pbyBuffer);
+ uLength += ((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN;
+ pbyBuffer += (((PWLAN_IE_COUNTRY) pbyBuffer)->len + WLAN_IEHDR_LEN);
+ // Power Constrain IE
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->byElementID = WLAN_EID_PWR_CONSTRAINT;
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->len = 1;
+ ((PWLAN_IE_PW_CONST) pbyBuffer)->byPower = 0;
+ pbyBuffer += (1) + WLAN_IEHDR_LEN;
+ uLength += (1) + WLAN_IEHDR_LEN;
+ if (pMgmt->bSwitchChannel == true) {
+ // Channel Switch IE
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byElementID = WLAN_EID_CH_SWITCH;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->len = 3;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byMode = 1;
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byChannel = get_channel_number(pMgmt->pAdapter, pMgmt->byNewChannel);
+ ((PWLAN_IE_CH_SW) pbyBuffer)->byCount = 0;
+ pbyBuffer += (3) + WLAN_IEHDR_LEN;
+ uLength += (3) + WLAN_IEHDR_LEN;
+ }
+ // TPC report
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byElementID = WLAN_EID_TPC_REP;
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->len = 2;
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byTxPower = CARDbyGetTransmitPower(pMgmt->pAdapter);
+ ((PWLAN_IE_TPC_REP) pbyBuffer)->byLinkMargin = 0;
+ pbyBuffer += (2) + WLAN_IEHDR_LEN;
+ uLength += (2) + WLAN_IEHDR_LEN;
+ // IBSS DFS
+ if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
+ pIBSSDFS = (PWLAN_IE_IBSS_DFS) pbyBuffer;
+ pIBSSDFS->byElementID = WLAN_EID_IBSS_DFS;
+ pIBSSDFS->len = 7;
+ memcpy(pIBSSDFS->abyDFSOwner,
+ pMgmt->abyIBSSDFSOwner,
+ 6);
+ pIBSSDFS->byDFSRecovery = pMgmt->byIBSSDFSRecovery;
+ pbyBuffer += (7) + WLAN_IEHDR_LEN;
+ uLength += (7) + WLAN_IEHDR_LEN;
+ for (ii = CB_MAX_CHANNEL_24G + 1; ii <= CB_MAX_CHANNEL; ii++) {
+ if (get_channel_map_info(pMgmt->pAdapter, ii, pbyBuffer, pbyBuffer+1) == true) {
+ pbyBuffer += 2;
+ uLength += 2;
+ pIBSSDFS->len += 2;
+ }
+ }
+ }
+ sFrame.len += uLength;
+ }
+
+ if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates,
+ pCurrExtSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
+);
+ }
+
+ // hostapd wpa/wpa2 IE
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnableHostapd == true)) {
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
+ if (pMgmt->wWPAIELen != 0) {
+ sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
+ memcpy(sFrame.pRSN, pMgmt->abyWPAIE, pMgmt->wWPAIELen);
+ sFrame.len += pMgmt->wWPAIELen;
+ }
+ }
+ }
+ // Adjust the length fields
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ return pTxPacket;
+}
/*+
*
@@ -3613,271 +3434,259 @@ s_MgrMakeProbeResponse(
* Return Value:
* A ptr to frame or NULL on allocation failure
*
--*/
-
+ -*/
PSTxMgmtPacket
s_MgrMakeAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pDAddr,
- unsigned short wCurrCapInfo,
- unsigned short wListenInterval,
- PWLAN_IE_SSID pCurrSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
+ PWLAN_IE_SSID pCurrSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_ASSOCREQ sFrame;
- unsigned char *pbyIEs;
- unsigned char *pbyRSN;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- // Setup the sFrame structure.
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_ASSOCREQ_FR_MAXLEN;
- // format fixed field frame structure
- vMgrEncodeAssocRequest(&sFrame);
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCREQ)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- // Set the capability and listen interval
- *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
- *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
-
- // sFrame.len point to end of fixed field
- sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
-
- pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN;
- pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
- pbyIEs = pMgmt->sAssocInfo.abyIEs;
- memcpy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
- pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN;
-
- // Copy the rate set
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- if ((pDevice->eCurrentPHYType == PHY_TYPE_11B) && (pCurrRates->len > 4))
- sFrame.len += 4 + WLAN_IEHDR_LEN;
- else
- sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
-
- // Copy the extension rate set
- if ((pDevice->eCurrentPHYType == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
- }
-
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
- pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
-
- // for 802.11h
- if (pMgmt->b11hEnable == true) {
- if (sFrame.pCurrPowerCap == NULL) {
- sFrame.pCurrPowerCap = (PWLAN_IE_PW_CAP)(sFrame.pBuf + sFrame.len);
- sFrame.len += (2 + WLAN_IEHDR_LEN);
- sFrame.pCurrPowerCap->byElementID = WLAN_EID_PWR_CAPABILITY;
- sFrame.pCurrPowerCap->len = 2;
- CARDvGetPowerCapability(pMgmt->pAdapter,
- &(sFrame.pCurrPowerCap->byMinPower),
- &(sFrame.pCurrPowerCap->byMaxPower)
- );
- }
- if (sFrame.pCurrSuppCh == NULL) {
- sFrame.pCurrSuppCh = (PWLAN_IE_SUPP_CH)(sFrame.pBuf + sFrame.len);
- sFrame.len += set_support_channels(pMgmt->pAdapter,(unsigned char *)sFrame.pCurrSuppCh);
- }
- }
-
- if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) &&
- (pMgmt->pCurrBSS != NULL)) {
- /* WPA IE */
- sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
- sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
- sFrame.pRSNWPA->len = 16;
- sFrame.pRSNWPA->abyOUI[0] = 0x00;
- sFrame.pRSNWPA->abyOUI[1] = 0x50;
- sFrame.pRSNWPA->abyOUI[2] = 0xf2;
- sFrame.pRSNWPA->abyOUI[3] = 0x01;
- sFrame.pRSNWPA->wVersion = 1;
- //Group Key Cipher Suite
- sFrame.pRSNWPA->abyMulticast[0] = 0x00;
- sFrame.pRSNWPA->abyMulticast[1] = 0x50;
- sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP;
- } else {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE;
- }
- // Pairwise Key Cipher Suite
- sFrame.pRSNWPA->wPKCount = 1;
- sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00;
- sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50;
- sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP;
- } else {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
- }
- // Auth Key Management Suite
- pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
- *pbyRSN++=0x01;
- *pbyRSN++=0x00;
- *pbyRSN++=0x00;
-
- *pbyRSN++=0x50;
- *pbyRSN++=0xf2;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) {
- *pbyRSN++=WPA_AUTH_PSK;
- }
- else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) {
- *pbyRSN++=WPA_AUTH_IEEE802_1X;
- }
- else {
- *pbyRSN++=WPA_NONE;
- }
-
- sFrame.pRSNWPA->len +=6;
-
- // RSN Capabilities
-
- *pbyRSN++=0x00;
- *pbyRSN++=0x00;
- sFrame.pRSNWPA->len +=2;
-
- sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
- // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN);
- pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
-
- } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
- (pMgmt->pCurrBSS != NULL)) {
- unsigned int ii;
- unsigned short *pwPMKID;
-
- // WPA IE
- sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
- sFrame.pRSN->byElementID = WLAN_EID_RSN;
- sFrame.pRSN->len = 6; //Version(2)+GK(4)
- sFrame.pRSN->wVersion = 1;
- //Group Key Cipher Suite
- sFrame.pRSN->abyRSN[0] = 0x00;
- sFrame.pRSN->abyRSN[1] = 0x0F;
- sFrame.pRSN->abyRSN[2] = 0xAC;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP;
- } else {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
- }
-
- // Pairwise Key Cipher Suite
- sFrame.pRSN->abyRSN[4] = 1;
- sFrame.pRSN->abyRSN[5] = 0;
- sFrame.pRSN->abyRSN[6] = 0x00;
- sFrame.pRSN->abyRSN[7] = 0x0F;
- sFrame.pRSN->abyRSN[8] = 0xAC;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP;
- } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
- } else {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
- }
- sFrame.pRSN->len += 6;
-
- // Auth Key Management Suite
- sFrame.pRSN->abyRSN[10] = 1;
- sFrame.pRSN->abyRSN[11] = 0;
- sFrame.pRSN->abyRSN[12] = 0x00;
- sFrame.pRSN->abyRSN[13] = 0x0F;
- sFrame.pRSN->abyRSN[14] = 0xAC;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK;
- } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
- } else {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
- }
- sFrame.pRSN->len +=6;
-
- // RSN Capabilities
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
- memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
- } else {
- sFrame.pRSN->abyRSN[16] = 0;
- sFrame.pRSN->abyRSN[17] = 0;
- }
- sFrame.pRSN->len +=2;
-
- if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
- // RSN PMKID
- pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
- *pwPMKID = 0; // Initialize PMKID count
- pbyRSN += 2; // Point to PMKID list
- for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
- if ( !memcmp(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
- (*pwPMKID) ++;
- memcpy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16);
- pbyRSN += 16;
- }
- }
- if (*pwPMKID != 0) {
- sFrame.pRSN->len += (2 + (*pwPMKID)*16);
- }
- }
-
- sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN);
- pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- }
-
-
- // Adjust the length fields
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
- return pTxPacket;
-}
-
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_ASSOCREQ sFrame;
+ unsigned char *pbyIEs;
+ unsigned char *pbyRSN;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ // Setup the sFrame structure.
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_ASSOCREQ_FR_MAXLEN;
+ // format fixed field frame structure
+ vMgrEncodeAssocRequest(&sFrame);
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCREQ)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ // Set the capability and listen interval
+ *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
+ *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
+
+ // sFrame.len point to end of fixed field
+ sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
+
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN;
+ pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
+ pbyIEs = pMgmt->sAssocInfo.abyIEs;
+ memcpy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
+ pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN;
+
+ // Copy the rate set
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ if ((pDevice->eCurrentPHYType == PHY_TYPE_11B) && (pCurrRates->len > 4))
+ sFrame.len += 4 + WLAN_IEHDR_LEN;
+ else
+ sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
+
+ // Copy the extension rate set
+ if ((pDevice->eCurrentPHYType == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
+ }
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
+ pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
+
+ // for 802.11h
+ if (pMgmt->b11hEnable == true) {
+ if (sFrame.pCurrPowerCap == NULL) {
+ sFrame.pCurrPowerCap = (PWLAN_IE_PW_CAP)(sFrame.pBuf + sFrame.len);
+ sFrame.len += (2 + WLAN_IEHDR_LEN);
+ sFrame.pCurrPowerCap->byElementID = WLAN_EID_PWR_CAPABILITY;
+ sFrame.pCurrPowerCap->len = 2;
+ CARDvGetPowerCapability(pMgmt->pAdapter,
+ &(sFrame.pCurrPowerCap->byMinPower),
+ &(sFrame.pCurrPowerCap->byMaxPower)
+);
+ }
+ if (sFrame.pCurrSuppCh == NULL) {
+ sFrame.pCurrSuppCh = (PWLAN_IE_SUPP_CH)(sFrame.pBuf + sFrame.len);
+ sFrame.len += set_support_channels(pMgmt->pAdapter, (unsigned char *)sFrame.pCurrSuppCh);
+ }
+ }
+ if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ /* WPA IE */
+ sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
+ sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
+ sFrame.pRSNWPA->len = 16;
+ sFrame.pRSNWPA->abyOUI[0] = 0x00;
+ sFrame.pRSNWPA->abyOUI[1] = 0x50;
+ sFrame.pRSNWPA->abyOUI[2] = 0xf2;
+ sFrame.pRSNWPA->abyOUI[3] = 0x01;
+ sFrame.pRSNWPA->wVersion = 1;
+ //Group Key Cipher Suite
+ sFrame.pRSNWPA->abyMulticast[0] = 0x00;
+ sFrame.pRSNWPA->abyMulticast[1] = 0x50;
+ sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
+ if (pMgmt->byCSSGK == KEY_CTL_WEP) {
+ sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType;
+ } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP;
+ } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP;
+ } else {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE;
+ }
+ // Pairwise Key Cipher Suite
+ sFrame.pRSNWPA->wPKCount = 1;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2;
+ if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP;
+ } else {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
+ }
+ // Auth Key Management Suite
+ pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ *pbyRSN++ = 0x01;
+ *pbyRSN++ = 0x00;
+ *pbyRSN++ = 0x00;
+
+ *pbyRSN++ = 0x50;
+ *pbyRSN++ = 0xf2;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) {
+ *pbyRSN++ = WPA_AUTH_PSK;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) {
+ *pbyRSN++ = WPA_AUTH_IEEE802_1X;
+ } else {
+ *pbyRSN++ = WPA_NONE;
+ }
+ sFrame.pRSNWPA->len += 6;
+
+ // RSN Capabilities
+
+ *pbyRSN++ = 0x00;
+ *pbyRSN++ = 0x00;
+ sFrame.pRSNWPA->len += 2;
+
+ sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+ // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN);
+ pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+
+ } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ unsigned int ii;
+ unsigned short *pwPMKID;
+
+ // WPA IE
+ sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
+ sFrame.pRSN->byElementID = WLAN_EID_RSN;
+ sFrame.pRSN->len = 6; //Version(2)+GK(4)
+ sFrame.pRSN->wVersion = 1;
+ //Group Key Cipher Suite
+ sFrame.pRSN->abyRSN[0] = 0x00;
+ sFrame.pRSN->abyRSN[1] = 0x0F;
+ sFrame.pRSN->abyRSN[2] = 0xAC;
+ if (pMgmt->byCSSGK == KEY_CTL_WEP) {
+ sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
+ } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP;
+ } else {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
+ }
+ // Pairwise Key Cipher Suite
+ sFrame.pRSN->abyRSN[4] = 1;
+ sFrame.pRSN->abyRSN[5] = 0;
+ sFrame.pRSN->abyRSN[6] = 0x00;
+ sFrame.pRSN->abyRSN[7] = 0x0F;
+ sFrame.pRSN->abyRSN[8] = 0xAC;
+ if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
+ } else {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
+ }
+ sFrame.pRSN->len += 6;
+
+ // Auth Key Management Suite
+ sFrame.pRSN->abyRSN[10] = 1;
+ sFrame.pRSN->abyRSN[11] = 0;
+ sFrame.pRSN->abyRSN[12] = 0x00;
+ sFrame.pRSN->abyRSN[13] = 0x0F;
+ sFrame.pRSN->abyRSN[14] = 0xAC;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
+ } else {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
+ }
+ sFrame.pRSN->len += 6;
+
+ // RSN Capabilities
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
+ memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
+ } else {
+ sFrame.pRSN->abyRSN[16] = 0;
+ sFrame.pRSN->abyRSN[17] = 0;
+ }
+ sFrame.pRSN->len += 2;
+
+ if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
+ // RSN PMKID
+ pbyRSN = &sFrame.pRSN->abyRSN[18];
+ pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
+ *pwPMKID = 0; // Initialize PMKID count
+ pbyRSN += 2; // Point to PMKID list
+ for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
+ if (!memcmp(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
+ (*pwPMKID)++;
+ memcpy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16);
+ pbyRSN += 16;
+ }
+ }
+ if (*pwPMKID != 0) {
+ sFrame.pRSN->len += (2 + (*pwPMKID)*16);
+ }
+ }
+ sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN);
+ pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ }
+ // Adjust the length fields
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ return pTxPacket;
+}
/*+
*
@@ -3888,248 +3697,243 @@ s_MgrMakeAssocRequest(
* Return Value:
* A ptr to frame or NULL on allocation failure
*
--*/
-
+ -*/
PSTxMgmtPacket
s_MgrMakeReAssocRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned char *pDAddr,
- unsigned short wCurrCapInfo,
- unsigned short wListenInterval,
- PWLAN_IE_SSID pCurrSSID,
- PWLAN_IE_SUPP_RATES pCurrRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned char *pDAddr,
+ unsigned short wCurrCapInfo,
+ unsigned short wListenInterval,
+ PWLAN_IE_SSID pCurrSSID,
+ PWLAN_IE_SUPP_RATES pCurrRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_REASSOCREQ sFrame;
- unsigned char *pbyIEs;
- unsigned char *pbyRSN;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset( pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_REASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- /* Setup the sFrame structure. */
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_REASSOCREQ_FR_MAXLEN;
-
- // format fixed field frame structure
- vMgrEncodeReassocRequest(&sFrame);
-
- /* Setup the header */
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCREQ)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- /* Set the capability and listen interval */
- *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
- *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
-
- memcpy(sFrame.pAddrCurrAP, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
- /* Copy the SSID */
- /* sFrame.len point to end of fixed field */
- sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
-
- pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN;
- pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
- pbyIEs = pMgmt->sAssocInfo.abyIEs;
- memcpy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
- pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN;
-
- /* Copy the rate set */
- /* sFrame.len point to end of SSID */
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
-
- // Copy the extension rate set
- if ((pMgmt->eCurrentPHYMode == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
- }
-
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
- pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
-
- if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) &&
- (pMgmt->pCurrBSS != NULL)) {
- /* WPA IE */
- sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
- sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
- sFrame.pRSNWPA->len = 16;
- sFrame.pRSNWPA->abyOUI[0] = 0x00;
- sFrame.pRSNWPA->abyOUI[1] = 0x50;
- sFrame.pRSNWPA->abyOUI[2] = 0xf2;
- sFrame.pRSNWPA->abyOUI[3] = 0x01;
- sFrame.pRSNWPA->wVersion = 1;
- //Group Key Cipher Suite
- sFrame.pRSNWPA->abyMulticast[0] = 0x00;
- sFrame.pRSNWPA->abyMulticast[1] = 0x50;
- sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP;
- } else {
- sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE;
- }
- // Pairwise Key Cipher Suite
- sFrame.pRSNWPA->wPKCount = 1;
- sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00;
- sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50;
- sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP;
- } else {
- sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
- }
- // Auth Key Management Suite
- pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
- *pbyRSN++=0x01;
- *pbyRSN++=0x00;
- *pbyRSN++=0x00;
-
- *pbyRSN++=0x50;
- *pbyRSN++=0xf2;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) {
- *pbyRSN++=WPA_AUTH_PSK;
- } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) {
- *pbyRSN++=WPA_AUTH_IEEE802_1X;
- } else {
- *pbyRSN++=WPA_NONE;
- }
-
- sFrame.pRSNWPA->len +=6;
-
- // RSN Capabilities
- *pbyRSN++=0x00;
- *pbyRSN++=0x00;
- sFrame.pRSNWPA->len +=2;
-
- sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
- // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN);
- pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
-
- } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
- (pMgmt->pCurrBSS != NULL)) {
- unsigned int ii;
- unsigned short *pwPMKID;
-
- /* WPA IE */
- sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
- sFrame.pRSN->byElementID = WLAN_EID_RSN;
- sFrame.pRSN->len = 6; //Version(2)+GK(4)
- sFrame.pRSN->wVersion = 1;
- //Group Key Cipher Suite
- sFrame.pRSN->abyRSN[0] = 0x00;
- sFrame.pRSN->abyRSN[1] = 0x0F;
- sFrame.pRSN->abyRSN[2] = 0xAC;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP;
- } else {
- sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
- }
-
- // Pairwise Key Cipher Suite
- sFrame.pRSN->abyRSN[4] = 1;
- sFrame.pRSN->abyRSN[5] = 0;
- sFrame.pRSN->abyRSN[6] = 0x00;
- sFrame.pRSN->abyRSN[7] = 0x0F;
- sFrame.pRSN->abyRSN[8] = 0xAC;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP;
- } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
- } else {
- sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
- }
- sFrame.pRSN->len += 6;
-
- // Auth Key Management Suite
- sFrame.pRSN->abyRSN[10] = 1;
- sFrame.pRSN->abyRSN[11] = 0;
- sFrame.pRSN->abyRSN[12] = 0x00;
- sFrame.pRSN->abyRSN[13] = 0x0F;
- sFrame.pRSN->abyRSN[14] = 0xAC;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK;
- } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
- } else {
- sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
- }
- sFrame.pRSN->len +=6;
-
- // RSN Capabilities
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
- memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
- } else {
- sFrame.pRSN->abyRSN[16] = 0;
- sFrame.pRSN->abyRSN[17] = 0;
- }
- sFrame.pRSN->len +=2;
-
- if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
- // RSN PMKID
- pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
- *pwPMKID = 0; // Initialize PMKID count
- pbyRSN += 2; // Point to PMKID list
- for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
- if ( !memcmp(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
- (*pwPMKID) ++;
- memcpy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16);
- pbyRSN += 16;
- }
- }
- if (*pwPMKID != 0) {
- sFrame.pRSN->len += (2 + (*pwPMKID)*16);
- }
- }
-
- sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
- pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- memcpy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN);
- pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
- }
-
-
- /* Adjust the length fields */
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_REASSOCREQ sFrame;
+ unsigned char *pbyIEs;
+ unsigned char *pbyRSN;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_REASSOCREQ_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ /* Setup the sFrame structure. */
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_REASSOCREQ_FR_MAXLEN;
+
+ // format fixed field frame structure
+ vMgrEncodeReassocRequest(&sFrame);
+
+ /* Setup the header */
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCREQ)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pDAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ /* Set the capability and listen interval */
+ *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo);
+ *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval);
+
+ memcpy(sFrame.pAddrCurrAP, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+ /* Copy the SSID */
+ /* sFrame.len point to end of fixed field */
+ sFrame.pSSID = (PWLAN_IE_SSID)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrSSID->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSSID, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
+
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength = pCurrSSID->len + WLAN_IEHDR_LEN;
+ pMgmt->sAssocInfo.AssocInfo.OffsetRequestIEs = sizeof(NDIS_802_11_ASSOCIATION_INFORMATION);
+ pbyIEs = pMgmt->sAssocInfo.abyIEs;
+ memcpy(pbyIEs, pCurrSSID, pCurrSSID->len + WLAN_IEHDR_LEN);
+ pbyIEs += pCurrSSID->len + WLAN_IEHDR_LEN;
+
+ /* Copy the rate set */
+ /* sFrame.len point to end of SSID */
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
+
+ // Copy the extension rate set
+ if ((pMgmt->eCurrentPHYMode == PHY_TYPE_11G) && (pCurrExtSuppRates->len > 0)) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += pCurrExtSuppRates->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates, pCurrExtSuppRates, pCurrExtSuppRates->len + WLAN_IEHDR_LEN);
+ }
+
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += pCurrRates->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
+ pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
+
+ if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ /* WPA IE */
+ sFrame.pRSNWPA = (PWLAN_IE_RSN_EXT)(sFrame.pBuf + sFrame.len);
+ sFrame.pRSNWPA->byElementID = WLAN_EID_RSN_WPA;
+ sFrame.pRSNWPA->len = 16;
+ sFrame.pRSNWPA->abyOUI[0] = 0x00;
+ sFrame.pRSNWPA->abyOUI[1] = 0x50;
+ sFrame.pRSNWPA->abyOUI[2] = 0xf2;
+ sFrame.pRSNWPA->abyOUI[3] = 0x01;
+ sFrame.pRSNWPA->wVersion = 1;
+ //Group Key Cipher Suite
+ sFrame.pRSNWPA->abyMulticast[0] = 0x00;
+ sFrame.pRSNWPA->abyMulticast[1] = 0x50;
+ sFrame.pRSNWPA->abyMulticast[2] = 0xf2;
+ if (pMgmt->byCSSGK == KEY_CTL_WEP) {
+ sFrame.pRSNWPA->abyMulticast[3] = pMgmt->pCurrBSS->byGKType;
+ } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_TKIP;
+ } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_AESCCMP;
+ } else {
+ sFrame.pRSNWPA->abyMulticast[3] = WPA_NONE;
+ }
+ // Pairwise Key Cipher Suite
+ sFrame.pRSNWPA->wPKCount = 1;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[0] = 0x00;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[1] = 0x50;
+ sFrame.pRSNWPA->PKSList[0].abyOUI[2] = 0xf2;
+ if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_TKIP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_AESCCMP;
+ } else {
+ sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
+ }
+ // Auth Key Management Suite
+ pbyRSN = (unsigned char *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ *pbyRSN++ = 0x01;
+ *pbyRSN++ = 0x00;
+ *pbyRSN++ = 0x00;
+
+ *pbyRSN++ = 0x50;
+ *pbyRSN++ = 0xf2;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) {
+ *pbyRSN++ = WPA_AUTH_PSK;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA) {
+ *pbyRSN++ = WPA_AUTH_IEEE802_1X;
+ } else {
+ *pbyRSN++ = WPA_NONE;
+ }
+ sFrame.pRSNWPA->len += 6;
+
+ // RSN Capabilities
+ *pbyRSN++ = 0x00;
+ *pbyRSN++ = 0x00;
+ sFrame.pRSNWPA->len += 2;
+
+ sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+ // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, sFrame.pRSNWPA, sFrame.pRSNWPA->len + WLAN_IEHDR_LEN);
+ pbyIEs += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
+
+ } else if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ unsigned int ii;
+ unsigned short *pwPMKID;
+
+ /* WPA IE */
+ sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
+ sFrame.pRSN->byElementID = WLAN_EID_RSN;
+ sFrame.pRSN->len = 6; //Version(2)+GK(4)
+ sFrame.pRSN->wVersion = 1;
+ //Group Key Cipher Suite
+ sFrame.pRSN->abyRSN[0] = 0x00;
+ sFrame.pRSN->abyRSN[1] = 0x0F;
+ sFrame.pRSN->abyRSN[2] = 0xAC;
+ if (pMgmt->byCSSGK == KEY_CTL_WEP) {
+ sFrame.pRSN->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
+ } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_CCMP;
+ } else {
+ sFrame.pRSN->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
+ }
+ // Pairwise Key Cipher Suite
+ sFrame.pRSN->abyRSN[4] = 1;
+ sFrame.pRSN->abyRSN[5] = 0;
+ sFrame.pRSN->abyRSN[6] = 0x00;
+ sFrame.pRSN->abyRSN[7] = 0x0F;
+ sFrame.pRSN->abyRSN[8] = 0xAC;
+ if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_CCMP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
+ } else {
+ sFrame.pRSN->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
+ }
+ sFrame.pRSN->len += 6;
+
+ // Auth Key Management Suite
+ sFrame.pRSN->abyRSN[10] = 1;
+ sFrame.pRSN->abyRSN[11] = 0;
+ sFrame.pRSN->abyRSN[12] = 0x00;
+ sFrame.pRSN->abyRSN[13] = 0x0F;
+ sFrame.pRSN->abyRSN[14] = 0xAC;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_PSK;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
+ } else {
+ sFrame.pRSN->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
+ }
+ sFrame.pRSN->len += 6;
+
+ // RSN Capabilities
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
+ memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
+ } else {
+ sFrame.pRSN->abyRSN[16] = 0;
+ sFrame.pRSN->abyRSN[17] = 0;
+ }
+ sFrame.pRSN->len += 2;
+
+ if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
+ // RSN PMKID
+ pbyRSN = &sFrame.pRSN->abyRSN[18];
+ pwPMKID = (unsigned short *)pbyRSN; // Point to PMKID count
+ *pwPMKID = 0; // Initialize PMKID count
+ pbyRSN += 2; // Point to PMKID list
+ for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
+ if (!memcmp(&pDevice->gsPMKID.BSSIDInfo[ii].BSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
+ (*pwPMKID)++;
+ memcpy(pbyRSN, pDevice->gsPMKID.BSSIDInfo[ii].PMKID, 16);
+ pbyRSN += 16;
+ }
+ }
+ if (*pwPMKID != 0) {
+ sFrame.pRSN->len += (2 + (*pwPMKID) * 16);
+ }
+ }
+
+ sFrame.len += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ // copy to AssocInfo. for OID_802_11_ASSOCIATION_INFORMATION
+ pMgmt->sAssocInfo.AssocInfo.RequestIELength += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ memcpy(pbyIEs, sFrame.pRSN, sFrame.pRSN->len + WLAN_IEHDR_LEN);
+ pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
+ }
+
+ /* Adjust the length fields */
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ return pTxPacket;
+}
/*+
*
@@ -4140,70 +3944,67 @@ s_MgrMakeReAssocRequest(
* Return Value:
* PTR to frame; or NULL on allocation failure
*
--*/
-
+ -*/
PSTxMgmtPacket
s_MgrMakeAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wAssocStatus,
- unsigned short wAssocAID,
- unsigned char *pDstAddr,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_ASSOCRESP sFrame;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- // Setup the sFrame structure
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
- vMgrEncodeAssocResponse(&sFrame);
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCRESP)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
- *sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
-
- // Copy the rate set
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates,
- pCurrSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
- );
-
- if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates,
- pCurrExtSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
- );
- }
-
- // Adjust the length fields
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_ASSOCRESP sFrame;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ // Setup the sFrame structure
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
+ vMgrEncodeAssocResponse(&sFrame);
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_ASSOCRESP)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
+ *sFrame.pwStatus = cpu_to_le16(wAssocStatus);
+ *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
+
+ // Copy the rate set
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates,
+ pCurrSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
+);
+
+ if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates,
+ pCurrExtSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
+);
+ }
+ // Adjust the length fields
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+
+ return pTxPacket;
+}
/*+
*
@@ -4214,70 +4015,67 @@ s_MgrMakeAssocResponse(
* Return Value:
* PTR to frame; or NULL on allocation failure
*
--*/
-
+ -*/
PSTxMgmtPacket
s_MgrMakeReAssocResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- unsigned short wCurrCapInfo,
- unsigned short wAssocStatus,
- unsigned short wAssocAID,
- unsigned char *pDstAddr,
- PWLAN_IE_SUPP_RATES pCurrSuppRates,
- PWLAN_IE_SUPP_RATES pCurrExtSuppRates
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ unsigned short wCurrCapInfo,
+ unsigned short wAssocStatus,
+ unsigned short wAssocAID,
+ unsigned char *pDstAddr,
+ PWLAN_IE_SUPP_RATES pCurrSuppRates,
+ PWLAN_IE_SUPP_RATES pCurrExtSuppRates
+)
{
- PSTxMgmtPacket pTxPacket = NULL;
- WLAN_FR_REASSOCRESP sFrame;
-
-
- pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
- memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
- pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
- // Setup the sFrame structure
- sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
- sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
- vMgrEncodeReassocResponse(&sFrame);
- // Setup the header
- sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
- (
- WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
- WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCRESP)
- ));
- memcpy( sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
- memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
-
- *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
- *sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
-
- // Copy the rate set
- sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pSuppRates,
- pCurrSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
- );
-
- if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
- sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
- sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
- memcpy(sFrame.pExtSuppRates,
- pCurrExtSuppRates,
- ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
- );
- }
-
- // Adjust the length fields
- pTxPacket->cbMPDULen = sFrame.len;
- pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
-
- return pTxPacket;
-}
+ PSTxMgmtPacket pTxPacket = NULL;
+ WLAN_FR_REASSOCRESP sFrame;
+
+ pTxPacket = (PSTxMgmtPacket)pMgmt->pbyMgmtPacketPool;
+ memset(pTxPacket, 0, sizeof(STxMgmtPacket) + WLAN_ASSOCREQ_FR_MAXLEN);
+ pTxPacket->p80211Header = (PUWLAN_80211HDR)((unsigned char *)pTxPacket + sizeof(STxMgmtPacket));
+ // Setup the sFrame structure
+ sFrame.pBuf = (unsigned char *)pTxPacket->p80211Header;
+ sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
+ vMgrEncodeReassocResponse(&sFrame);
+ // Setup the header
+ sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
+ (
+ WLAN_SET_FC_FTYPE(WLAN_TYPE_MGR) |
+ WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_REASSOCRESP)
+));
+ memcpy(sFrame.pHdr->sA3.abyAddr1, pDstAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
+ memcpy(sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
+
+ *sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
+ *sFrame.pwStatus = cpu_to_le16(wAssocStatus);
+ *sFrame.pwAid = cpu_to_le16((unsigned short)(wAssocAID | BIT14 | BIT15));
+
+ // Copy the rate set
+ sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pSuppRates,
+ pCurrSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrSuppRates)->len + WLAN_IEHDR_LEN
+);
+
+ if (((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len != 0) {
+ sFrame.pExtSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
+ sFrame.len += ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN;
+ memcpy(sFrame.pExtSuppRates,
+ pCurrExtSuppRates,
+ ((PWLAN_IE_SUPP_RATES)pCurrExtSuppRates)->len + WLAN_IEHDR_LEN
+);
+ }
+
+ // Adjust the length fields
+ pTxPacket->cbMPDULen = sFrame.len;
+ pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
+ return pTxPacket;
+}
/*+
*
@@ -4288,119 +4086,115 @@ s_MgrMakeReAssocResponse(
* Return Value:
* none.
*
--*/
+ -*/
static
void
s_vMgrRxProbeResponse(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- PKnownBSS pBSSList = NULL;
- WLAN_FR_PROBERESP sFrame;
- unsigned char byCurrChannel = pRxPacket->byRxChannel;
- ERPObject sERP;
- unsigned char byIEChannel = 0;
- bool bChannelHit = true;
-
-
- memset(&sFrame, 0, sizeof(WLAN_FR_PROBERESP));
- // decode the frame
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeProbeResponse(&sFrame);
-
- if ((sFrame.pqwTimestamp == 0) ||
- (sFrame.pwBeaconInterval == 0) ||
- (sFrame.pwCapInfo == 0) ||
- (sFrame.pSSID == 0) ||
- (sFrame.pSuppRates == 0)) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p] \n", pRxPacket->p80211Header);
- DBG_PORT80(0xCC);
- return;
- }
-
- if(sFrame.pSSID->len == 0)
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx Probe resp: SSID len = 0 \n");
-
- if (sFrame.pDSParms != 0) {
- if (byCurrChannel > CB_MAX_CHANNEL_24G) {
- // channel remapping to
- byIEChannel = get_channel_mapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
- } else {
- byIEChannel = sFrame.pDSParms->byCurrChannel;
- }
- if (byCurrChannel != byIEChannel) {
- // adjust channel info. bcs we rcv adjacent channel packets
- bChannelHit = false;
- byCurrChannel = byIEChannel;
- }
- } else {
- // no DS channel info
- bChannelHit = true;
- }
+ PKnownBSS pBSSList = NULL;
+ WLAN_FR_PROBERESP sFrame;
+ unsigned char byCurrChannel = pRxPacket->byRxChannel;
+ ERPObject sERP;
+ unsigned char byIEChannel = 0;
+ bool bChannelHit = true;
+
+ memset(&sFrame, 0, sizeof(WLAN_FR_PROBERESP));
+ // decode the frame
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeProbeResponse(&sFrame);
+
+ if ((sFrame.pqwTimestamp == 0) ||
+ (sFrame.pwBeaconInterval == 0) ||
+ (sFrame.pwCapInfo == 0) ||
+ (sFrame.pSSID == 0) ||
+ (sFrame.pSuppRates == 0)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp:Fail addr:[%p] \n", pRxPacket->p80211Header);
+ DBG_PORT80(0xCC);
+ return;
+ }
+
+ if (sFrame.pSSID->len == 0)
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx Probe resp: SSID len = 0 \n");
+
+ if (sFrame.pDSParms != 0) {
+ if (byCurrChannel > CB_MAX_CHANNEL_24G) {
+ // channel remapping to
+ byIEChannel = get_channel_mapping(pMgmt->pAdapter, sFrame.pDSParms->byCurrChannel, PHY_TYPE_11A);
+ } else {
+ byIEChannel = sFrame.pDSParms->byCurrChannel;
+ }
+ if (byCurrChannel != byIEChannel) {
+ // adjust channel info. bcs we rcv adjacent channel packets
+ bChannelHit = false;
+ byCurrChannel = byIEChannel;
+ }
+ } else {
+ // no DS channel info
+ bChannelHit = true;
+ }
//2008-0730-01<Add>by MikeLiu
-if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
- return;
-
- if (sFrame.pERP != NULL) {
- sERP.byERP = sFrame.pERP->byContext;
- sERP.bERPExist = true;
- } else {
- sERP.bERPExist = false;
- sERP.byERP = 0;
- }
-
-
- // update or insert the bss
- pBSSList = BSSpAddrIsInBSSList((void *)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID);
- if (pBSSList) {
- BSSbUpdateToBSSList((void *)pDevice,
- *sFrame.pqwTimestamp,
- *sFrame.pwBeaconInterval,
- *sFrame.pwCapInfo,
- byCurrChannel,
- bChannelHit,
- sFrame.pSSID,
- sFrame.pSuppRates,
- sFrame.pExtSuppRates,
- &sERP,
- sFrame.pRSN,
- sFrame.pRSNWPA,
- sFrame.pIE_Country,
- sFrame.pIE_Quiet,
- pBSSList,
- sFrame.len - WLAN_HDR_ADDR3_LEN,
- sFrame.pHdr->sA4.abyAddr4, // payload of probresponse
- (void *)pRxPacket
- );
- }
- else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Probe resp/insert: RxChannel = : %d\n", byCurrChannel);
- BSSbInsertToBSSList((void *)pDevice,
- sFrame.pHdr->sA3.abyAddr3,
- *sFrame.pqwTimestamp,
- *sFrame.pwBeaconInterval,
- *sFrame.pwCapInfo,
- byCurrChannel,
- sFrame.pSSID,
- sFrame.pSuppRates,
- sFrame.pExtSuppRates,
- &sERP,
- sFrame.pRSN,
- sFrame.pRSNWPA,
- sFrame.pIE_Country,
- sFrame.pIE_Quiet,
- sFrame.len - WLAN_HDR_ADDR3_LEN,
- sFrame.pHdr->sA4.abyAddr4, // payload of beacon
- (void *)pRxPacket
- );
- }
- return;
+ if (ChannelExceedZoneType(pDevice, byCurrChannel) == true)
+ return;
+
+ if (sFrame.pERP != NULL) {
+ sERP.byERP = sFrame.pERP->byContext;
+ sERP.bERPExist = true;
+ } else {
+ sERP.bERPExist = false;
+ sERP.byERP = 0;
+ }
+ // update or insert the bss
+ pBSSList = BSSpAddrIsInBSSList((void *)pDevice, sFrame.pHdr->sA3.abyAddr3, sFrame.pSSID);
+ if (pBSSList) {
+ BSSbUpdateToBSSList((void *)pDevice,
+ *sFrame.pqwTimestamp,
+ *sFrame.pwBeaconInterval,
+ *sFrame.pwCapInfo,
+ byCurrChannel,
+ bChannelHit,
+ sFrame.pSSID,
+ sFrame.pSuppRates,
+ sFrame.pExtSuppRates,
+ &sERP,
+ sFrame.pRSN,
+ sFrame.pRSNWPA,
+ sFrame.pIE_Country,
+ sFrame.pIE_Quiet,
+ pBSSList,
+ sFrame.len - WLAN_HDR_ADDR3_LEN,
+ sFrame.pHdr->sA4.abyAddr4, // payload of probresponse
+ (void *)pRxPacket
+);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe resp/insert: RxChannel = : %d\n", byCurrChannel);
+ BSSbInsertToBSSList((void *)pDevice,
+ sFrame.pHdr->sA3.abyAddr3,
+ *sFrame.pqwTimestamp,
+ *sFrame.pwBeaconInterval,
+ *sFrame.pwCapInfo,
+ byCurrChannel,
+ sFrame.pSSID,
+ sFrame.pSuppRates,
+ sFrame.pExtSuppRates,
+ &sERP,
+ sFrame.pRSN,
+ sFrame.pRSNWPA,
+ sFrame.pIE_Country,
+ sFrame.pIE_Quiet,
+ sFrame.len - WLAN_HDR_ADDR3_LEN,
+ sFrame.pHdr->sA4.abyAddr4, // payload of beacon
+ (void *)pRxPacket
+);
+ }
+ return;
}
/*+
@@ -4412,84 +4206,77 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
* Return Value:
* none.
*
--*/
-
+ -*/
static
void
s_vMgrRxProbeRequest(
- PSDevice pDevice,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ PSDevice pDevice,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- WLAN_FR_PROBEREQ sFrame;
- CMD_STATUS Status;
- PSTxMgmtPacket pTxPacket;
- unsigned char byPHYType = BB_TYPE_11B;
-
- // STA in Ad-hoc mode: when latest TBTT beacon transmit success,
- // STA have to response this request.
- if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
- ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && pDevice->bBeaconSent)) {
-
- memset(&sFrame, 0, sizeof(WLAN_FR_PROBEREQ));
- // decode the frame
- sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
- vMgrDecodeProbeRequest(&sFrame);
+ WLAN_FR_PROBEREQ sFrame;
+ CMD_STATUS Status;
+ PSTxMgmtPacket pTxPacket;
+ unsigned char byPHYType = BB_TYPE_11B;
+
+ // STA in Ad-hoc mode: when latest TBTT beacon transmit success,
+ // STA have to response this request.
+ if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) ||
+ ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && pDevice->bBeaconSent)) {
+ memset(&sFrame, 0, sizeof(WLAN_FR_PROBEREQ));
+ // decode the frame
+ sFrame.len = pRxPacket->cbMPDULen;
+ sFrame.pBuf = (unsigned char *)pRxPacket->p80211Header;
+ vMgrDecodeProbeRequest(&sFrame);
/*
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request rx:MAC addr:%pM\n",
- sFrame.pHdr->sA3.abyAddr2);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request rx:MAC addr:%pM\n",
+ sFrame.pHdr->sA3.abyAddr2);
*/
- if (sFrame.pSSID->len != 0) {
- if (sFrame.pSSID->len != ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len)
- return;
- if (memcmp(sFrame.pSSID->abySSID,
- ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,
- ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) != 0) {
- return;
- }
- }
-
- if ((sFrame.pSuppRates->len > 4) || (sFrame.pExtSuppRates != NULL)) {
- byPHYType = BB_TYPE_11G;
- }
-
- // Probe response reply..
- pTxPacket = s_MgrMakeProbeResponse
- (
- pDevice,
- pMgmt,
- pMgmt->wCurrCapInfo,
- pMgmt->wCurrBeaconPeriod,
- pMgmt->uCurrChannel,
- 0,
- sFrame.pHdr->sA3.abyAddr2,
- (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (unsigned char *)pMgmt->abyCurrBSSID,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
- byPHYType
- );
- if (pTxPacket != NULL ){
- /* send the frame */
- Status = csMgmt_xmit(pDevice, pTxPacket);
- if (Status != CMD_STATUS_PENDING) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx failed\n");
- }
- else {
-// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx sending..\n");
- }
- }
- }
-
- return;
-}
-
+ if (sFrame.pSSID->len != 0) {
+ if (sFrame.pSSID->len != ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len)
+ return;
+ if (memcmp(sFrame.pSSID->abySSID,
+ ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->abySSID,
+ ((PWLAN_IE_SSID)pMgmt->abyCurrSSID)->len) != 0) {
+ return;
+ }
+ }
+ if ((sFrame.pSuppRates->len > 4) || (sFrame.pExtSuppRates != NULL)) {
+ byPHYType = BB_TYPE_11G;
+ }
+ // Probe response reply..
+ pTxPacket = s_MgrMakeProbeResponse
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->wCurrCapInfo,
+ pMgmt->wCurrBeaconPeriod,
+ pMgmt->uCurrChannel,
+ 0,
+ sFrame.pHdr->sA3.abyAddr2,
+ (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
+ (unsigned char *)pMgmt->abyCurrBSSID,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
+ byPHYType
+);
+ if (pTxPacket != NULL) {
+ /* send the frame */
+ Status = csMgmt_xmit(pDevice, pTxPacket);
+ if (Status != CMD_STATUS_PENDING) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx failed\n");
+ } else {
+// DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Mgt:Probe response tx sending..\n");
+ }
+ }
+ }
+ return;
+}
/*+
*
@@ -4503,146 +4290,139 @@ s_vMgrRxProbeRequest(
* Return Value:
* none.
*
--*/
-
+ -*/
void
vMgrRxManagePacket(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- bool bInScan = false;
- unsigned int uNodeIndex = 0;
- NODE_STATE eNodeState = 0;
- CMD_STATUS Status;
-
-
- if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex))
- eNodeState = pMgmt->sNodeDBTable[uNodeIndex].eNodeState;
- }
-
- switch( WLAN_GET_FC_FSTYPE((pRxPacket->p80211Header->sA3.wFrameCtl)) ){
-
- case WLAN_FSTYPE_ASSOCREQ:
- // Frame Clase = 2
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocreq\n");
- if (eNodeState < NODE_AUTH) {
- // send deauth notification
- // reason = (6) class 2 received from nonauth sta
- vMgrDeAuthenBeginSta(pDevice,
- pMgmt,
- pRxPacket->p80211Header->sA3.abyAddr2,
- (6),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 1\n");
- }
- else {
- s_vMgrRxAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex);
- }
- break;
-
- case WLAN_FSTYPE_ASSOCRESP:
- // Frame Clase = 2
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp1\n");
- s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, false);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp2\n");
- break;
-
- case WLAN_FSTYPE_REASSOCREQ:
- // Frame Clase = 2
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocreq\n");
- // Todo: reassoc
- if (eNodeState < NODE_AUTH) {
- // send deauth notification
- // reason = (6) class 2 received from nonauth sta
- vMgrDeAuthenBeginSta(pDevice,
- pMgmt,
- pRxPacket->p80211Header->sA3.abyAddr2,
- (6),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 2\n");
-
- }
- s_vMgrRxReAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex);
- break;
-
- case WLAN_FSTYPE_REASSOCRESP:
- // Frame Clase = 2
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocresp\n");
- s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, true);
- break;
-
- case WLAN_FSTYPE_PROBEREQ:
- // Frame Clase = 0
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx probereq\n");
- s_vMgrRxProbeRequest(pDevice, pMgmt, pRxPacket);
- break;
-
- case WLAN_FSTYPE_PROBERESP:
- // Frame Clase = 0
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx proberesp\n");
-
- s_vMgrRxProbeResponse(pDevice, pMgmt, pRxPacket);
- break;
-
- case WLAN_FSTYPE_BEACON:
- // Frame Clase = 0
- //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx beacon\n");
- if (pMgmt->eScanState != WMAC_NO_SCANNING) {
- bInScan = true;
- }
- s_vMgrRxBeacon(pDevice, pMgmt, pRxPacket, bInScan);
- break;
-
- case WLAN_FSTYPE_ATIM:
- // Frame Clase = 1
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx atim\n");
- break;
-
- case WLAN_FSTYPE_DISASSOC:
- // Frame Clase = 2
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx disassoc\n");
- if (eNodeState < NODE_AUTH) {
- // send deauth notification
- // reason = (6) class 2 received from nonauth sta
- vMgrDeAuthenBeginSta(pDevice,
- pMgmt,
- pRxPacket->p80211Header->sA3.abyAddr2,
- (6),
- &Status
- );
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 3\n");
- }
- s_vMgrRxDisassociation(pDevice, pMgmt, pRxPacket);
- break;
-
- case WLAN_FSTYPE_AUTHEN:
- // Frame Clase = 1
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx authen\n");
- s_vMgrRxAuthentication(pDevice, pMgmt, pRxPacket);
- break;
-
- case WLAN_FSTYPE_DEAUTHEN:
- // Frame Clase = 1
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx deauthen\n");
- s_vMgrRxDeauthentication(pDevice, pMgmt, pRxPacket);
- break;
-
- default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx unknown mgmt\n");
- }
-
- return;
-}
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ bool bInScan = false;
+ unsigned int uNodeIndex = 0;
+ NODE_STATE eNodeState = 0;
+ CMD_STATUS Status;
+
+ if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
+ if (BSSDBbIsSTAInNodeDB(pMgmt, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex))
+ eNodeState = pMgmt->sNodeDBTable[uNodeIndex].eNodeState;
+ }
+
+ switch (WLAN_GET_FC_FSTYPE((pRxPacket->p80211Header->sA3.wFrameCtl))) {
+ case WLAN_FSTYPE_ASSOCREQ:
+ // Frame Clase = 2
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocreq\n");
+ if (eNodeState < NODE_AUTH) {
+ // send deauth notification
+ // reason = (6) class 2 received from nonauth sta
+ vMgrDeAuthenBeginSta(pDevice,
+ pMgmt,
+ pRxPacket->p80211Header->sA3.abyAddr2,
+ (6),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 1\n");
+ } else {
+ s_vMgrRxAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex);
+ }
+ break;
+
+ case WLAN_FSTYPE_ASSOCRESP:
+ // Frame Clase = 2
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp1\n");
+ s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, false);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx assocresp2\n");
+ break;
+
+ case WLAN_FSTYPE_REASSOCREQ:
+ // Frame Clase = 2
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocreq\n");
+ // Todo: reassoc
+ if (eNodeState < NODE_AUTH) {
+ // send deauth notification
+ // reason = (6) class 2 received from nonauth sta
+ vMgrDeAuthenBeginSta(pDevice,
+ pMgmt,
+ pRxPacket->p80211Header->sA3.abyAddr2,
+ (6),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 2\n");
+
+ }
+ s_vMgrRxReAssocRequest(pDevice, pMgmt, pRxPacket, uNodeIndex);
+ break;
+
+ case WLAN_FSTYPE_REASSOCRESP:
+ // Frame Clase = 2
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx reassocresp\n");
+ s_vMgrRxAssocResponse(pDevice, pMgmt, pRxPacket, true);
+ break;
+
+ case WLAN_FSTYPE_PROBEREQ:
+ // Frame Clase = 0
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx probereq\n");
+ s_vMgrRxProbeRequest(pDevice, pMgmt, pRxPacket);
+ break;
+
+ case WLAN_FSTYPE_PROBERESP:
+ // Frame Clase = 0
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx proberesp\n");
+
+ s_vMgrRxProbeResponse(pDevice, pMgmt, pRxPacket);
+ break;
+ case WLAN_FSTYPE_BEACON:
+ // Frame Clase = 0
+ //DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx beacon\n");
+ if (pMgmt->eScanState != WMAC_NO_SCANNING) {
+ bInScan = true;
+ }
+ s_vMgrRxBeacon(pDevice, pMgmt, pRxPacket, bInScan);
+ break;
+
+ case WLAN_FSTYPE_ATIM:
+ // Frame Clase = 1
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx atim\n");
+ break;
+ case WLAN_FSTYPE_DISASSOC:
+ // Frame Clase = 2
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx disassoc\n");
+ if (eNodeState < NODE_AUTH) {
+ // send deauth notification
+ // reason = (6) class 2 received from nonauth sta
+ vMgrDeAuthenBeginSta(pDevice,
+ pMgmt,
+ pRxPacket->p80211Header->sA3.abyAddr2,
+ (6),
+ &Status
+);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wmgr: send vMgrDeAuthenBeginSta 3\n");
+ }
+ s_vMgrRxDisassociation(pDevice, pMgmt, pRxPacket);
+ break;
+ case WLAN_FSTYPE_AUTHEN:
+ // Frame Clase = 1
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx authen\n");
+ s_vMgrRxAuthentication(pDevice, pMgmt, pRxPacket);
+ break;
+
+ case WLAN_FSTYPE_DEAUTHEN:
+ // Frame Clase = 1
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx deauthen\n");
+ s_vMgrRxDeauthentication(pDevice, pMgmt, pRxPacket);
+ break;
+
+ default:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "rx unknown mgmt\n");
+ }
+
+ return;
+}
/*+
*
@@ -4654,49 +4434,45 @@ vMgrRxManagePacket(
* Return Value:
* true if success; false if failed.
*
--*/
+ -*/
bool
bMgrPrepareBeaconToSend(
- void *hDeviceContext,
- PSMgmtObject pMgmt
- )
+ void *hDeviceContext,
+ PSMgmtObject pMgmt
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PSTxMgmtPacket pTxPacket;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSTxMgmtPacket pTxPacket;
// pDevice->bBeaconBufReady = false;
- if (pDevice->bEncryptionEnable || pDevice->bEnable8021x){
- pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
- }
- else {
- pMgmt->wCurrCapInfo &= ~WLAN_SET_CAP_INFO_PRIVACY(1);
- }
- pTxPacket = s_MgrMakeBeacon
- (
- pDevice,
- pMgmt,
- pMgmt->wCurrCapInfo,
- pMgmt->wCurrBeaconPeriod,
- pMgmt->uCurrChannel,
- pMgmt->wCurrATIMWindow, //0,
- (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (unsigned char *)pMgmt->abyCurrBSSID,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
- (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
- );
-
- if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
- (pMgmt->abyCurrBSSID[0] == 0))
- return false;
-
- csBeacon_xmit(pDevice, pTxPacket);
-
- return true;
+ if (pDevice->bEncryptionEnable || pDevice->bEnable8021x) {
+ pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_PRIVACY(1);
+ } else {
+ pMgmt->wCurrCapInfo &= ~WLAN_SET_CAP_INFO_PRIVACY(1);
+ }
+ pTxPacket = s_MgrMakeBeacon
+ (
+ pDevice,
+ pMgmt,
+ pMgmt->wCurrCapInfo,
+ pMgmt->wCurrBeaconPeriod,
+ pMgmt->uCurrChannel,
+ pMgmt->wCurrATIMWindow, //0,
+ (PWLAN_IE_SSID)pMgmt->abyCurrSSID,
+ (unsigned char *)pMgmt->abyCurrBSSID,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
+ (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
+);
+
+ if ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) &&
+ (pMgmt->abyCurrBSSID[0] == 0))
+ return false;
+
+ csBeacon_xmit(pDevice, pTxPacket);
+
+ return true;
}
-
-
-
/*+
*
* Routine Description:
@@ -4708,61 +4484,60 @@ bMgrPrepareBeaconToSend(
* Return Value:
* none.
*
--*/
+ -*/
static
void
s_vMgrLogStatus(
- PSMgmtObject pMgmt,
- unsigned short wStatus
- )
+ PSMgmtObject pMgmt,
+ unsigned short wStatus
+)
{
- switch( wStatus ){
- case WLAN_MGMT_STATUS_UNSPEC_FAILURE:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Unspecified error.\n");
- break;
- case WLAN_MGMT_STATUS_CAPS_UNSUPPORTED:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Can't support all requested capabilities.\n");
- break;
- case WLAN_MGMT_STATUS_REASSOC_NO_ASSOC:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Reassoc denied, can't confirm original Association.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, undefine in spec\n");
- break;
- case WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Peer doesn't support authen algorithm.\n");
- break;
- case WLAN_MGMT_STATUS_RX_AUTH_NOSEQ:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen frame received out of sequence.\n");
- break;
- case WLAN_MGMT_STATUS_CHALLENGE_FAIL:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, challenge failure.\n");
- break;
- case WLAN_MGMT_STATUS_AUTH_TIMEOUT:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, timeout waiting for next frame.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, AP too busy.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_RATES:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we haven't enough basic rates.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_SHORTPREAMBLE:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support short preamble.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_PBCC:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support PBCC.\n");
- break;
- case WLAN_MGMT_STATUS_ASSOC_DENIED_AGILITY:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support channel agility.\n");
- break;
- default:
- DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Unknown status code %d.\n", wStatus);
- break;
- }
+ switch (wStatus) {
+ case WLAN_MGMT_STATUS_UNSPEC_FAILURE:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Unspecified error.\n");
+ break;
+ case WLAN_MGMT_STATUS_CAPS_UNSUPPORTED:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Can't support all requested capabilities.\n");
+ break;
+ case WLAN_MGMT_STATUS_REASSOC_NO_ASSOC:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Reassoc denied, can't confirm original Association.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_UNSPEC:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, undefine in spec\n");
+ break;
+ case WLAN_MGMT_STATUS_UNSUPPORTED_AUTHALG:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Peer doesn't support authen algorithm.\n");
+ break;
+ case WLAN_MGMT_STATUS_RX_AUTH_NOSEQ:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen frame received out of sequence.\n");
+ break;
+ case WLAN_MGMT_STATUS_CHALLENGE_FAIL:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, challenge failure.\n");
+ break;
+ case WLAN_MGMT_STATUS_AUTH_TIMEOUT:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Authen rejected, timeout waiting for next frame.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_BUSY:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, AP too busy.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_RATES:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we haven't enough basic rates.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_SHORTPREAMBLE:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support short preamble.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_PBCC:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support PBCC.\n");
+ break;
+ case WLAN_MGMT_STATUS_ASSOC_DENIED_AGILITY:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Status code == Assoc denied, we do not support channel agility.\n");
+ break;
+ default:
+ DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "Unknown status code %d.\n", wStatus);
+ break;
+ }
}
-
/*
*
* Description:
@@ -4778,52 +4553,50 @@ s_vMgrLogStatus(
*
* Return Value: none.
*
--*/
+ -*/
bool
-bAdd_PMKID_Candidate (
- void *hDeviceContext,
- unsigned char *pbyBSSID,
- PSRSNCapObject psRSNCapObj
- )
+bAdd_PMKID_Candidate(
+ void *hDeviceContext,
+ unsigned char *pbyBSSID,
+ PSRSNCapObject psRSNCapObj
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
- PPMKID_CANDIDATE pCandidateList;
- unsigned int ii = 0;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
-
- if ((pDevice == NULL) || (pbyBSSID == NULL) || (psRSNCapObj == NULL))
- return false;
-
- if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST)
- return false;
-
-
-
- // Update Old Candidate
- for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
- pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
- if ( !memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
- if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
- pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
- } else {
- pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
- }
- return true;
- }
- }
-
- // New Candidate
- pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
- if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
- pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
- } else {
- pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
- }
- memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
- pDevice->gsPMKIDCandidate.NumCandidates++;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
- return true;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
+ PPMKID_CANDIDATE pCandidateList;
+ unsigned int ii = 0;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "bAdd_PMKID_Candidate START: (%d)\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
+
+ if ((pDevice == NULL) || (pbyBSSID == NULL) || (psRSNCapObj == NULL))
+ return false;
+
+ if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST)
+ return false;
+
+ // Update Old Candidate
+ for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
+ pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
+ if (!memcmp(pCandidateList->BSSID, pbyBSSID, ETH_ALEN)) {
+ if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
+ pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ } else {
+ pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
+ }
+ return true;
+ }
+ }
+
+ // New Candidate
+ pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[pDevice->gsPMKIDCandidate.NumCandidates];
+ if ((psRSNCapObj->bRSNCapExist == true) && (psRSNCapObj->wRSNCap & BIT0)) {
+ pCandidateList->Flags |= NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ } else {
+ pCandidateList->Flags &= ~(NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED);
+ }
+ memcpy(pCandidateList->BSSID, pbyBSSID, ETH_ALEN);
+ pDevice->gsPMKIDCandidate.NumCandidates++;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "NumCandidates:%d\n", (int)pDevice->gsPMKIDCandidate.NumCandidates);
+ return true;
}
/*
@@ -4839,166 +4612,163 @@ bAdd_PMKID_Candidate (
*
* Return Value: none.
*
--*/
+ -*/
void
-vFlush_PMKID_Candidate (
- void *hDeviceContext
- )
+vFlush_PMKID_Candidate(
+ void *hDeviceContext
+)
{
- PSDevice pDevice = (PSDevice)hDeviceContext;
+ PSDevice pDevice = (PSDevice)hDeviceContext;
- if (pDevice == NULL)
- return;
+ if (pDevice == NULL)
+ return;
- memset(&pDevice->gsPMKIDCandidate, 0, sizeof(SPMKIDCandidateEvent));
+ memset(&pDevice->gsPMKIDCandidate, 0, sizeof(SPMKIDCandidateEvent));
}
static bool
-s_bCipherMatch (
- PKnownBSS pBSSNode,
- NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- unsigned char *pbyCCSPK,
- unsigned char *pbyCCSGK
- )
+s_bCipherMatch(
+ PKnownBSS pBSSNode,
+ NDIS_802_11_ENCRYPTION_STATUS EncStatus,
+ unsigned char *pbyCCSPK,
+ unsigned char *pbyCCSGK
+)
{
- unsigned char byMulticastCipher = KEY_CTL_INVALID;
- unsigned char byCipherMask = 0x00;
- int i;
-
- if (pBSSNode == NULL)
- return false;
-
- // check cap. of BSS
- if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
- (EncStatus == Ndis802_11Encryption1Enabled)) {
- // default is WEP only
- byMulticastCipher = KEY_CTL_WEP;
- }
-
- if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
- (pBSSNode->bWPA2Valid == true) &&
- //20080123-01,<Add> by Einsn Liu
- ((EncStatus == Ndis802_11Encryption3Enabled)||(EncStatus == Ndis802_11Encryption2Enabled))) {
- //WPA2
- // check Group Key Cipher
- if ((pBSSNode->byCSSGK == WLAN_11i_CSS_WEP40) ||
- (pBSSNode->byCSSGK == WLAN_11i_CSS_WEP104)) {
- byMulticastCipher = KEY_CTL_WEP;
- } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_TKIP) {
- byMulticastCipher = KEY_CTL_TKIP;
- } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
- byMulticastCipher = KEY_CTL_CCMP;
- } else {
- byMulticastCipher = KEY_CTL_INVALID;
- }
-
- // check Pairwise Key Cipher
- for(i=0;i<pBSSNode->wCSSPKCount;i++) {
- if ((pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP40) ||
- (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP104)) {
- // this should not happen as defined 802.11i
- byCipherMask |= 0x01;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_TKIP) {
- byCipherMask |= 0x02;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_CCMP) {
- byCipherMask |= 0x04;
- } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_USE_GROUP) {
- // use group key only ignore all others
- byCipherMask = 0;
- i = pBSSNode->wCSSPKCount;
- }
- }
-
- } else if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
- (pBSSNode->bWPAValid == true) &&
- ((EncStatus == Ndis802_11Encryption3Enabled) || (EncStatus == Ndis802_11Encryption2Enabled))) {
- //WPA
- // check Group Key Cipher
- if ((pBSSNode->byGKType == WPA_WEP40) ||
- (pBSSNode->byGKType == WPA_WEP104)) {
- byMulticastCipher = KEY_CTL_WEP;
- } else if (pBSSNode->byGKType == WPA_TKIP) {
- byMulticastCipher = KEY_CTL_TKIP;
- } else if (pBSSNode->byGKType == WPA_AESCCMP) {
- byMulticastCipher = KEY_CTL_CCMP;
- } else {
- byMulticastCipher = KEY_CTL_INVALID;
- }
-
- // check Pairwise Key Cipher
- for(i=0;i<pBSSNode->wPKCount;i++) {
- if (pBSSNode->abyPKType[i] == WPA_TKIP) {
- byCipherMask |= 0x02;
- } else if (pBSSNode->abyPKType[i] == WPA_AESCCMP) {
- byCipherMask |= 0x04;
- } else if (pBSSNode->abyPKType[i] == WPA_NONE) {
- // use group key only ignore all others
- byCipherMask = 0;
- i = pBSSNode->wPKCount;
- }
- }
- }
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"%d, %d, %d, %d, EncStatus:%d\n",
- byMulticastCipher, byCipherMask, pBSSNode->bWPAValid, pBSSNode->bWPA2Valid, EncStatus);
-
- // mask our cap. with BSS
- if (EncStatus == Ndis802_11Encryption1Enabled) {
-
- // For supporting Cisco migration mode, don't care pairwise key cipher
- if ((byMulticastCipher == KEY_CTL_WEP) &&
- (byCipherMask == 0)) {
- *pbyCCSGK = KEY_CTL_WEP;
- *pbyCCSPK = KEY_CTL_NONE;
- return true;
- } else {
- return false;
- }
-
- } else if (EncStatus == Ndis802_11Encryption2Enabled) {
- if ((byMulticastCipher == KEY_CTL_TKIP) &&
- (byCipherMask == 0)) {
- *pbyCCSGK = KEY_CTL_TKIP;
- *pbyCCSPK = KEY_CTL_NONE;
- return true;
- } else if ((byMulticastCipher == KEY_CTL_WEP) &&
- ((byCipherMask & 0x02) != 0)) {
- *pbyCCSGK = KEY_CTL_WEP;
- *pbyCCSPK = KEY_CTL_TKIP;
- return true;
- } else if ((byMulticastCipher == KEY_CTL_TKIP) &&
- ((byCipherMask & 0x02) != 0)) {
- *pbyCCSGK = KEY_CTL_TKIP;
- *pbyCCSPK = KEY_CTL_TKIP;
- return true;
- } else {
- return false;
- }
- } else if (EncStatus == Ndis802_11Encryption3Enabled) {
- if ((byMulticastCipher == KEY_CTL_CCMP) &&
- (byCipherMask == 0)) {
- // When CCMP is enable, "Use group cipher suite" shall not be a valid option.
- return false;
- } else if ((byMulticastCipher == KEY_CTL_WEP) &&
- ((byCipherMask & 0x04) != 0)) {
- *pbyCCSGK = KEY_CTL_WEP;
- *pbyCCSPK = KEY_CTL_CCMP;
- return true;
- } else if ((byMulticastCipher == KEY_CTL_TKIP) &&
- ((byCipherMask & 0x04) != 0)) {
- *pbyCCSGK = KEY_CTL_TKIP;
- *pbyCCSPK = KEY_CTL_CCMP;
- return true;
- } else if ((byMulticastCipher == KEY_CTL_CCMP) &&
- ((byCipherMask & 0x04) != 0)) {
- *pbyCCSGK = KEY_CTL_CCMP;
- *pbyCCSPK = KEY_CTL_CCMP;
- return true;
- } else {
- return false;
- }
- }
- return true;
-}
+ unsigned char byMulticastCipher = KEY_CTL_INVALID;
+ unsigned char byCipherMask = 0x00;
+ int i;
+
+ if (pBSSNode == NULL)
+ return false;
+
+ // check cap. of BSS
+ if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
+ (EncStatus == Ndis802_11Encryption1Enabled)) {
+ // default is WEP only
+ byMulticastCipher = KEY_CTL_WEP;
+ }
+
+ if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
+ (pBSSNode->bWPA2Valid == true) &&
+ //20080123-01,<Add> by Einsn Liu
+ ((EncStatus == Ndis802_11Encryption3Enabled) || (EncStatus == Ndis802_11Encryption2Enabled))) {
+ //WPA2
+ // check Group Key Cipher
+ if ((pBSSNode->byCSSGK == WLAN_11i_CSS_WEP40) ||
+ (pBSSNode->byCSSGK == WLAN_11i_CSS_WEP104)) {
+ byMulticastCipher = KEY_CTL_WEP;
+ } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_TKIP) {
+ byMulticastCipher = KEY_CTL_TKIP;
+ } else if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
+ byMulticastCipher = KEY_CTL_CCMP;
+ } else {
+ byMulticastCipher = KEY_CTL_INVALID;
+ }
+
+ // check Pairwise Key Cipher
+ for (i = 0; i < pBSSNode->wCSSPKCount; i++) {
+ if ((pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP40) ||
+ (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_WEP104)) {
+ // this should not happen as defined 802.11i
+ byCipherMask |= 0x01;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_TKIP) {
+ byCipherMask |= 0x02;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_CCMP) {
+ byCipherMask |= 0x04;
+ } else if (pBSSNode->abyCSSPK[i] == WLAN_11i_CSS_USE_GROUP) {
+ // use group key only ignore all others
+ byCipherMask = 0;
+ i = pBSSNode->wCSSPKCount;
+ }
+ }
+ } else if ((WLAN_GET_CAP_INFO_PRIVACY(pBSSNode->wCapInfo) != 0) &&
+ (pBSSNode->bWPAValid == true) &&
+ ((EncStatus == Ndis802_11Encryption3Enabled) || (EncStatus == Ndis802_11Encryption2Enabled))) {
+ //WPA
+ // check Group Key Cipher
+ if ((pBSSNode->byGKType == WPA_WEP40) ||
+ (pBSSNode->byGKType == WPA_WEP104)) {
+ byMulticastCipher = KEY_CTL_WEP;
+ } else if (pBSSNode->byGKType == WPA_TKIP) {
+ byMulticastCipher = KEY_CTL_TKIP;
+ } else if (pBSSNode->byGKType == WPA_AESCCMP) {
+ byMulticastCipher = KEY_CTL_CCMP;
+ } else {
+ byMulticastCipher = KEY_CTL_INVALID;
+ }
+ // check Pairwise Key Cipher
+ for (i = 0; i < pBSSNode->wPKCount; i++) {
+ if (pBSSNode->abyPKType[i] == WPA_TKIP) {
+ byCipherMask |= 0x02;
+ } else if (pBSSNode->abyPKType[i] == WPA_AESCCMP) {
+ byCipherMask |= 0x04;
+ } else if (pBSSNode->abyPKType[i] == WPA_NONE) {
+ // use group key only ignore all others
+ byCipherMask = 0;
+ i = pBSSNode->wPKCount;
+ }
+ }
+ }
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%d, %d, %d, %d, EncStatus:%d\n",
+ byMulticastCipher, byCipherMask, pBSSNode->bWPAValid, pBSSNode->bWPA2Valid, EncStatus);
+
+ // mask our cap. with BSS
+ if (EncStatus == Ndis802_11Encryption1Enabled) {
+ // For supporting Cisco migration mode, don't care pairwise key cipher
+ if ((byMulticastCipher == KEY_CTL_WEP) &&
+ (byCipherMask == 0)) {
+ *pbyCCSGK = KEY_CTL_WEP;
+ *pbyCCSPK = KEY_CTL_NONE;
+ return true;
+ } else {
+ return false;
+ }
+
+ } else if (EncStatus == Ndis802_11Encryption2Enabled) {
+ if ((byMulticastCipher == KEY_CTL_TKIP) &&
+ (byCipherMask == 0)) {
+ *pbyCCSGK = KEY_CTL_TKIP;
+ *pbyCCSPK = KEY_CTL_NONE;
+ return true;
+ } else if ((byMulticastCipher == KEY_CTL_WEP) &&
+ ((byCipherMask & 0x02) != 0)) {
+ *pbyCCSGK = KEY_CTL_WEP;
+ *pbyCCSPK = KEY_CTL_TKIP;
+ return true;
+ } else if ((byMulticastCipher == KEY_CTL_TKIP) &&
+ ((byCipherMask & 0x02) != 0)) {
+ *pbyCCSGK = KEY_CTL_TKIP;
+ *pbyCCSPK = KEY_CTL_TKIP;
+ return true;
+ } else {
+ return false;
+ }
+ } else if (EncStatus == Ndis802_11Encryption3Enabled) {
+ if ((byMulticastCipher == KEY_CTL_CCMP) &&
+ (byCipherMask == 0)) {
+ // When CCMP is enable, "Use group cipher suite" shall not be a valid option.
+ return false;
+ } else if ((byMulticastCipher == KEY_CTL_WEP) &&
+ ((byCipherMask & 0x04) != 0)) {
+ *pbyCCSGK = KEY_CTL_WEP;
+ *pbyCCSPK = KEY_CTL_CCMP;
+ return true;
+ } else if ((byMulticastCipher == KEY_CTL_TKIP) &&
+ ((byCipherMask & 0x04) != 0)) {
+ *pbyCCSGK = KEY_CTL_TKIP;
+ *pbyCCSPK = KEY_CTL_CCMP;
+ return true;
+ } else if ((byMulticastCipher == KEY_CTL_CCMP) &&
+ ((byCipherMask & 0x04) != 0)) {
+ *pbyCCSGK = KEY_CTL_CCMP;
+ *pbyCCSPK = KEY_CTL_CCMP;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h
index bfa67ae5d40a..b91f1f89ed05 100644
--- a/drivers/staging/vt6655/wmgr.h
+++ b/drivers/staging/vt6655/wmgr.h
@@ -45,8 +45,6 @@
/*--------------------- Export Definitions -------------------------*/
-
-
// Scan time
#define PROBE_DELAY 100 // (us)
#define SWITCH_CHANNEL_DELAY 200 // (us)
@@ -58,7 +56,6 @@
#define WCMD_ACTIVE_SCAN_TIME 50 //(ms)
#define WCMD_PASSIVE_SCAN_TIME 100 //(ms)
-
#define DEFAULT_MSDU_LIFETIME 512 // ms
#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 // 64us
@@ -67,7 +64,6 @@
#define MAKE_BEACON_RESERVED 10 //(us)
-
#define TIM_MULTICAST_MASK 0x01
#define TIM_BITMAPOFFSET_MASK 0xFE
#define DEFAULT_DTIM_PERIOD 1
@@ -76,107 +72,91 @@
#define DEFAULT_IBSS_CHANNEL 6 //2.4G
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
/*--------------------- Export Types ------------------------------*/
-#define timer_expire(timer,next_tick) mod_timer(&timer, RUN_AT(next_tick))
+#define timer_expire(timer, next_tick) mod_timer(&timer, RUN_AT(next_tick))
typedef void (*TimerFunction)(unsigned long);
-
//+++ NDIS related
typedef unsigned char NDIS_802_11_MAC_ADDRESS[6];
typedef struct _NDIS_802_11_AI_REQFI
{
- unsigned short Capabilities;
- unsigned short ListenInterval;
- NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
+ unsigned short Capabilities;
+ unsigned short ListenInterval;
+ NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
typedef struct _NDIS_802_11_AI_RESFI
{
- unsigned short Capabilities;
- unsigned short StatusCode;
- unsigned short AssociationId;
+ unsigned short Capabilities;
+ unsigned short StatusCode;
+ unsigned short AssociationId;
} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
{
- unsigned long Length;
- unsigned short AvailableRequestFixedIEs;
- NDIS_802_11_AI_REQFI RequestFixedIEs;
- unsigned long RequestIELength;
- unsigned long OffsetRequestIEs;
- unsigned short AvailableResponseFixedIEs;
- NDIS_802_11_AI_RESFI ResponseFixedIEs;
- unsigned long ResponseIELength;
- unsigned long OffsetResponseIEs;
+ unsigned long Length;
+ unsigned short AvailableRequestFixedIEs;
+ NDIS_802_11_AI_REQFI RequestFixedIEs;
+ unsigned long RequestIELength;
+ unsigned long OffsetRequestIEs;
+ unsigned short AvailableResponseFixedIEs;
+ NDIS_802_11_AI_RESFI ResponseFixedIEs;
+ unsigned long ResponseIELength;
+ unsigned long OffsetResponseIEs;
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-
typedef struct tagSAssocInfo {
- NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo;
- unsigned char abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN];
- // store ReqIEs set by OID_802_11_ASSOCIATION_INFORMATION
- unsigned long RequestIELength;
- unsigned char abyReqIEs[WLAN_BEACON_FR_MAXLEN];
+ NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo;
+ unsigned char abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN];
+ // store ReqIEs set by OID_802_11_ASSOCIATION_INFORMATION
+ unsigned long RequestIELength;
+ unsigned char abyReqIEs[WLAN_BEACON_FR_MAXLEN];
} SAssocInfo, *PSAssocInfo;
//---
-
/*
-typedef enum tagWMAC_AUTHENTICATION_MODE {
-
-
- WMAC_AUTH_OPEN,
- WMAC_AUTH_SHAREKEY,
- WMAC_AUTH_AUTO,
- WMAC_AUTH_WPA,
- WMAC_AUTH_WPAPSK,
- WMAC_AUTH_WPANONE,
- WMAC_AUTH_WPA2,
- WMAC_AUTH_WPA2PSK,
- WMAC_AUTH_MAX // Not a real mode, defined as upper bound
-
-
-} WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE;
+ typedef enum tagWMAC_AUTHENTICATION_MODE {
+ WMAC_AUTH_OPEN,
+ WMAC_AUTH_SHAREKEY,
+ WMAC_AUTH_AUTO,
+ WMAC_AUTH_WPA,
+ WMAC_AUTH_WPAPSK,
+ WMAC_AUTH_WPANONE,
+ WMAC_AUTH_WPA2,
+ WMAC_AUTH_WPA2PSK,
+ WMAC_AUTH_MAX // Not a real mode, defined as upper bound
+
+ } WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE;
*/
-
// Pre-configured Mode (from XP)
/*
-typedef enum tagWMAC_CONFIG_MODE {
- WMAC_CONFIG_ESS_STA,
- WMAC_CONFIG_IBSS_STA,
- WMAC_CONFIG_AUTO,
- WMAC_CONFIG_AP
+ typedef enum tagWMAC_CONFIG_MODE {
+ WMAC_CONFIG_ESS_STA,
+ WMAC_CONFIG_IBSS_STA,
+ WMAC_CONFIG_AUTO,
+ WMAC_CONFIG_AP
-} WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE;
+ } WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE;
*/
typedef enum tagWMAC_SCAN_TYPE {
-
- WMAC_SCAN_ACTIVE,
- WMAC_SCAN_PASSIVE,
- WMAC_SCAN_HYBRID
-
+ WMAC_SCAN_ACTIVE,
+ WMAC_SCAN_PASSIVE,
+ WMAC_SCAN_HYBRID
} WMAC_SCAN_TYPE, *PWMAC_SCAN_TYPE;
-
typedef enum tagWMAC_SCAN_STATE {
-
- WMAC_NO_SCANNING,
- WMAC_IS_SCANNING,
- WMAC_IS_PROBEPENDING
-
+ WMAC_NO_SCANNING,
+ WMAC_IS_SCANNING,
+ WMAC_IS_PROBEPENDING
} WMAC_SCAN_STATE, *PWMAC_SCAN_STATE;
-
-
// Notes:
// Basic Service Set state explained as following:
// WMAC_STATE_IDLE : no BSS is selected (Adhoc or Infra)
@@ -188,315 +168,287 @@ typedef enum tagWMAC_SCAN_STATE {
// WMAC_STATE_ASSOC : Associated (Infra)
typedef enum tagWMAC_BSS_STATE {
-
- WMAC_STATE_IDLE,
- WMAC_STATE_STARTED,
- WMAC_STATE_JOINTED,
- WMAC_STATE_AUTHPENDING,
- WMAC_STATE_AUTH,
- WMAC_STATE_ASSOCPENDING,
- WMAC_STATE_ASSOC
-
+ WMAC_STATE_IDLE,
+ WMAC_STATE_STARTED,
+ WMAC_STATE_JOINTED,
+ WMAC_STATE_AUTHPENDING,
+ WMAC_STATE_AUTH,
+ WMAC_STATE_ASSOCPENDING,
+ WMAC_STATE_ASSOC
} WMAC_BSS_STATE, *PWMAC_BSS_STATE;
// WMAC selected running mode
typedef enum tagWMAC_CURRENT_MODE {
-
- WMAC_MODE_STANDBY,
- WMAC_MODE_ESS_STA,
- WMAC_MODE_IBSS_STA,
- WMAC_MODE_ESS_AP
-
+ WMAC_MODE_STANDBY,
+ WMAC_MODE_ESS_STA,
+ WMAC_MODE_IBSS_STA,
+ WMAC_MODE_ESS_AP
} WMAC_CURRENT_MODE, *PWMAC_CURRENT_MODE;
/*
-typedef enum tagWMAC_POWER_MODE {
+ typedef enum tagWMAC_POWER_MODE {
+ WMAC_POWER_CAM,
+ WMAC_POWER_FAST,
+ WMAC_POWER_MAX
- WMAC_POWER_CAM,
- WMAC_POWER_FAST,
- WMAC_POWER_MAX
-
-} WMAC_POWER_MODE, *PWMAC_POWER_MODE;
+ } WMAC_POWER_MODE, *PWMAC_POWER_MODE;
*/
-
// Tx Management Packet descriptor
typedef struct tagSTxMgmtPacket {
-
- PUWLAN_80211HDR p80211Header;
- unsigned int cbMPDULen;
- unsigned int cbPayloadLen;
-
+ PUWLAN_80211HDR p80211Header;
+ unsigned int cbMPDULen;
+ unsigned int cbPayloadLen;
} STxMgmtPacket, *PSTxMgmtPacket;
-
// Rx Management Packet descriptor
typedef struct tagSRxMgmtPacket {
-
- PUWLAN_80211HDR p80211Header;
- QWORD qwLocalTSF;
- unsigned int cbMPDULen;
- unsigned int cbPayloadLen;
- unsigned int uRSSI;
- unsigned char bySQ;
- unsigned char byRxRate;
- unsigned char byRxChannel;
-
+ PUWLAN_80211HDR p80211Header;
+ QWORD qwLocalTSF;
+ unsigned int cbMPDULen;
+ unsigned int cbPayloadLen;
+ unsigned int uRSSI;
+ unsigned char bySQ;
+ unsigned char byRxRate;
+ unsigned char byRxChannel;
} SRxMgmtPacket, *PSRxMgmtPacket;
-
-
typedef struct tagSMgmtObject
{
+ void *pAdapter;
+ // MAC address
+ unsigned char abyMACAddr[WLAN_ADDR_LEN];
- void * pAdapter;
- // MAC address
- unsigned char abyMACAddr[WLAN_ADDR_LEN];
-
- // Configuration Mode
- WMAC_CONFIG_MODE eConfigMode; // MAC pre-configed mode
- CARD_PHY_TYPE eCurrentPHYMode;
- CARD_PHY_TYPE eConfigPHYMode;
-
+ // Configuration Mode
+ WMAC_CONFIG_MODE eConfigMode; // MAC pre-configed mode
+ CARD_PHY_TYPE eCurrentPHYMode;
+ CARD_PHY_TYPE eConfigPHYMode;
- // Operation state variables
- WMAC_CURRENT_MODE eCurrMode; // MAC current connection mode
- WMAC_BSS_STATE eCurrState; // MAC current BSS state
+ // Operation state variables
+ WMAC_CURRENT_MODE eCurrMode; // MAC current connection mode
+ WMAC_BSS_STATE eCurrState; // MAC current BSS state
- PKnownBSS pCurrBSS;
- unsigned char byCSSGK;
- unsigned char byCSSPK;
+ PKnownBSS pCurrBSS;
+ unsigned char byCSSGK;
+ unsigned char byCSSPK;
// unsigned char abyNewSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
// unsigned char abyNewExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- // Current state vars
- unsigned int uCurrChannel;
- unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char abyCurrSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned char abyCurrBSSID[WLAN_BSSID_LEN];
- unsigned short wCurrCapInfo;
- unsigned short wCurrAID;
- unsigned short wCurrATIMWindow;
- unsigned short wCurrBeaconPeriod;
- bool bIsDS;
- unsigned char byERPContext;
-
- CMD_STATE eCommandState;
- unsigned int uScanChannel;
-
- // Desire joining BSS vars
- unsigned char abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned char abyDesireBSSID[WLAN_BSSID_LEN];
-
- // Adhoc or AP configuration vars
- //unsigned char abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned short wIBSSBeaconPeriod;
- unsigned short wIBSSATIMWindow;
- unsigned int uIBSSChannel;
- unsigned char abyIBSSSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- unsigned char byAPBBType;
- unsigned char abyWPAIE[MAX_WPA_IE_LEN];
- unsigned short wWPAIELen;
-
- unsigned int uAssocCount;
- bool bMoreData;
-
- // Scan state vars
- WMAC_SCAN_STATE eScanState;
- WMAC_SCAN_TYPE eScanType;
- unsigned int uScanStartCh;
- unsigned int uScanEndCh;
- unsigned short wScanSteps;
- unsigned int uScanBSSType;
- // Desire scanning vars
- unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- unsigned char abyScanBSSID[WLAN_BSSID_LEN];
-
- // Privacy
- WMAC_AUTHENTICATION_MODE eAuthenMode;
- WMAC_ENCRYPTION_MODE eEncryptionMode;
- bool bShareKeyAlgorithm;
- unsigned char abyChallenge[WLAN_CHALLENGE_LEN];
- bool bPrivacyInvoked;
-
- // Received beacon state vars
- bool bInTIM;
- bool bMulticastTIM;
- unsigned char byDTIMCount;
- unsigned char byDTIMPeriod;
-
- // Power saving state vars
- WMAC_POWER_MODE ePSMode;
- unsigned short wListenInterval;
- unsigned short wCountToWakeUp;
- bool bInTIMWake;
- unsigned char *pbyPSPacketPool;
- unsigned char byPSPacketPool[sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN];
- bool bRxBeaconInTBTTWake;
- unsigned char abyPSTxMap[MAX_NODE_NUM + 1];
-
- // management command related
- unsigned int uCmdBusy;
- unsigned int uCmdHostAPBusy;
-
- // management packet pool
- unsigned char *pbyMgmtPacketPool;
- unsigned char byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
-
-
- // One second callback timer
- struct timer_list sTimerSecondCallback;
-
- // Temporarily Rx Mgmt Packet Descriptor
- SRxMgmtPacket sRxPacket;
-
- // link list of known bss's (scan results)
- KnownBSS sBSSList[MAX_BSS_NUM];
-
-
-
- // table list of known node
- // sNodeDBList[0] is reserved for AP under Infra mode
- // sNodeDBList[0] is reserved for Multicast under adhoc/AP mode
- KnownNodeDB sNodeDBTable[MAX_NODE_NUM + 1];
-
-
-
- // WPA2 PMKID Cache
- SPMKIDCache gsPMKIDCache;
- bool bRoaming;
-
- // rate fall back vars
-
-
-
- // associate info
- SAssocInfo sAssocInfo;
-
-
- // for 802.11h
- bool b11hEnable;
- bool bSwitchChannel;
- unsigned char byNewChannel;
- PWLAN_IE_MEASURE_REP pCurrMeasureEIDRep;
- unsigned int uLengthOfRepEIDs;
- unsigned char abyCurrentMSRReq[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
- unsigned char abyCurrentMSRRep[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
- unsigned char abyIECountry[WLAN_A3FR_MAXLEN];
- unsigned char abyIBSSDFSOwner[6];
- unsigned char byIBSSDFSRecovery;
-
- struct sk_buff skb;
-
+ // Current state vars
+ unsigned int uCurrChannel;
+ unsigned char abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char abyCurrSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyCurrBSSID[WLAN_BSSID_LEN];
+ unsigned short wCurrCapInfo;
+ unsigned short wCurrAID;
+ unsigned short wCurrATIMWindow;
+ unsigned short wCurrBeaconPeriod;
+ bool bIsDS;
+ unsigned char byERPContext;
+
+ CMD_STATE eCommandState;
+ unsigned int uScanChannel;
+
+ // Desire joining BSS vars
+ unsigned char abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyDesireBSSID[WLAN_BSSID_LEN];
+
+ // Adhoc or AP configuration vars
+ //unsigned char abyAdHocSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned short wIBSSBeaconPeriod;
+ unsigned short wIBSSATIMWindow;
+ unsigned int uIBSSChannel;
+ unsigned char abyIBSSSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ unsigned char byAPBBType;
+ unsigned char abyWPAIE[MAX_WPA_IE_LEN];
+ unsigned short wWPAIELen;
+
+ unsigned int uAssocCount;
+ bool bMoreData;
+
+ // Scan state vars
+ WMAC_SCAN_STATE eScanState;
+ WMAC_SCAN_TYPE eScanType;
+ unsigned int uScanStartCh;
+ unsigned int uScanEndCh;
+ unsigned short wScanSteps;
+ unsigned int uScanBSSType;
+ // Desire scanning vars
+ unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ unsigned char abyScanBSSID[WLAN_BSSID_LEN];
+
+ // Privacy
+ WMAC_AUTHENTICATION_MODE eAuthenMode;
+ WMAC_ENCRYPTION_MODE eEncryptionMode;
+ bool bShareKeyAlgorithm;
+ unsigned char abyChallenge[WLAN_CHALLENGE_LEN];
+ bool bPrivacyInvoked;
+
+ // Received beacon state vars
+ bool bInTIM;
+ bool bMulticastTIM;
+ unsigned char byDTIMCount;
+ unsigned char byDTIMPeriod;
+
+ // Power saving state vars
+ WMAC_POWER_MODE ePSMode;
+ unsigned short wListenInterval;
+ unsigned short wCountToWakeUp;
+ bool bInTIMWake;
+ unsigned char *pbyPSPacketPool;
+ unsigned char byPSPacketPool[sizeof(STxMgmtPacket) + WLAN_NULLDATA_FR_MAXLEN];
+ bool bRxBeaconInTBTTWake;
+ unsigned char abyPSTxMap[MAX_NODE_NUM + 1];
+
+ // management command related
+ unsigned int uCmdBusy;
+ unsigned int uCmdHostAPBusy;
+
+ // management packet pool
+ unsigned char *pbyMgmtPacketPool;
+ unsigned char byMgmtPacketPool[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+
+ // One second callback timer
+ struct timer_list sTimerSecondCallback;
+
+ // Temporarily Rx Mgmt Packet Descriptor
+ SRxMgmtPacket sRxPacket;
+
+ // link list of known bss's (scan results)
+ KnownBSS sBSSList[MAX_BSS_NUM];
+
+ // table list of known node
+ // sNodeDBList[0] is reserved for AP under Infra mode
+ // sNodeDBList[0] is reserved for Multicast under adhoc/AP mode
+ KnownNodeDB sNodeDBTable[MAX_NODE_NUM + 1];
+
+ // WPA2 PMKID Cache
+ SPMKIDCache gsPMKIDCache;
+ bool bRoaming;
+
+ // rate fall back vars
+
+ // associate info
+ SAssocInfo sAssocInfo;
+
+ // for 802.11h
+ bool b11hEnable;
+ bool bSwitchChannel;
+ unsigned char byNewChannel;
+ PWLAN_IE_MEASURE_REP pCurrMeasureEIDRep;
+ unsigned int uLengthOfRepEIDs;
+ unsigned char abyCurrentMSRReq[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+ unsigned char abyCurrentMSRRep[sizeof(STxMgmtPacket) + WLAN_A3FR_MAXLEN];
+ unsigned char abyIECountry[WLAN_A3FR_MAXLEN];
+ unsigned char abyIBSSDFSOwner[6];
+ unsigned char byIBSSDFSRecovery;
+
+ struct sk_buff skb;
} SMgmtObject, *PSMgmtObject;
-
/*--------------------- Export Macros ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
-
void
vMgrObjectInit(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void
vMgrTimerInit(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void
vMgrObjectReset(
- void *hDeviceContext
- );
+ void *hDeviceContext
+);
void
vMgrAssocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+);
void
vMgrReAssocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+);
void
vMgrDisassocBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- unsigned char *abyDestAddress,
- unsigned short wReason,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
+ PCMD_STATUS pStatus
+);
void
vMgrAuthenBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PCMD_STATUS pStatus
+);
void
vMgrCreateOwnIBSS(
- void *hDeviceContext,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PCMD_STATUS pStatus
+);
void
vMgrJoinBSSBegin(
- void *hDeviceContext,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PCMD_STATUS pStatus
+);
void
vMgrRxManagePacket(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- PSRxMgmtPacket pRxPacket
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ PSRxMgmtPacket pRxPacket
+);
/*
-void
-vMgrScanBegin(
- void *hDeviceContext,
- PCMD_STATUS pStatus
- );
+ void
+ vMgrScanBegin(
+ void *hDeviceContext,
+ PCMD_STATUS pStatus
+);
*/
void
vMgrDeAuthenBeginSta(
- void *hDeviceContext,
- PSMgmtObject pMgmt,
- unsigned char *abyDestAddress,
- unsigned short wReason,
- PCMD_STATUS pStatus
- );
+ void *hDeviceContext,
+ PSMgmtObject pMgmt,
+ unsigned char *abyDestAddress,
+ unsigned short wReason,
+ PCMD_STATUS pStatus
+);
bool
bMgrPrepareBeaconToSend(
- void *hDeviceContext,
- PSMgmtObject pMgmt
- );
-
+ void *hDeviceContext,
+ PSMgmtObject pMgmt
+);
bool
-bAdd_PMKID_Candidate (
- void *hDeviceContext,
- unsigned char *pbyBSSID,
- PSRSNCapObject psRSNCapObj
- );
+bAdd_PMKID_Candidate(
+ void *hDeviceContext,
+ unsigned char *pbyBSSID,
+ PSRSNCapObject psRSNCapObj
+);
void
-vFlush_PMKID_Candidate (
- void *hDeviceContext
- );
+vFlush_PMKID_Candidate(
+ void *hDeviceContext
+);
#endif // __WMGR_H__
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index 4412fe9396a4..c5293bbcdab5 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -43,7 +43,7 @@
#include "80211mgr.h"
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
const unsigned char abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 };
const unsigned char abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 };
@@ -52,7 +52,6 @@ const unsigned char abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 };
const unsigned char abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 };
const unsigned char abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
-
/*+
*
* Description:
@@ -66,29 +65,28 @@ const unsigned char abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
*
* Return Value: none.
*
--*/
+ -*/
void
-WPA_ClearRSN (
- PKnownBSS pBSSList
- )
+WPA_ClearRSN(
+ PKnownBSS pBSSList
+)
{
- int ii;
- pBSSList->byGKType = WPA_TKIP;
- for (ii=0; ii < 4; ii ++)
- pBSSList->abyPKType[ii] = WPA_TKIP;
- pBSSList->wPKCount = 0;
- for (ii=0; ii < 4; ii ++)
- pBSSList->abyAuthType[ii] = WPA_AUTH_IEEE802_1X;
- pBSSList->wAuthCount = 0;
- pBSSList->byDefaultK_as_PK = 0;
- pBSSList->byReplayIdx = 0;
- pBSSList->sRSNCapObj.bRSNCapExist = false;
- pBSSList->sRSNCapObj.wRSNCap = 0;
- pBSSList->bWPAValid = false;
+ int ii;
+ pBSSList->byGKType = WPA_TKIP;
+ for (ii = 0; ii < 4; ii++)
+ pBSSList->abyPKType[ii] = WPA_TKIP;
+ pBSSList->wPKCount = 0;
+ for (ii = 0; ii < 4; ii++)
+ pBSSList->abyAuthType[ii] = WPA_AUTH_IEEE802_1X;
+ pBSSList->wAuthCount = 0;
+ pBSSList->byDefaultK_as_PK = 0;
+ pBSSList->byReplayIdx = 0;
+ pBSSList->sRSNCapObj.bRSNCapExist = false;
+ pBSSList->sRSNCapObj.wRSNCap = 0;
+ pBSSList->bWPAValid = false;
}
-
/*+
*
* Description:
@@ -103,122 +101,118 @@ WPA_ClearRSN (
*
* Return Value: none.
*
--*/
+ -*/
void
-WPA_ParseRSN (
- PKnownBSS pBSSList,
- PWLAN_IE_RSN_EXT pRSN
- )
+WPA_ParseRSN(
+ PKnownBSS pBSSList,
+ PWLAN_IE_RSN_EXT pRSN
+)
{
- PWLAN_IE_RSN_AUTH pIE_RSN_Auth = NULL;
- int i, j, m, n = 0;
- unsigned char *pbyCaps;
-
- WPA_ClearRSN(pBSSList);
+ PWLAN_IE_RSN_AUTH pIE_RSN_Auth = NULL;
+ int i, j, m, n = 0;
+ unsigned char *pbyCaps;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA_ParseRSN: [%d]\n", pRSN->len);
+ WPA_ClearRSN(pBSSList);
- // information element header makes sense
- if ((pRSN->len >= 6) // oui1(4)+ver(2)
- && (pRSN->byElementID == WLAN_EID_RSN_WPA) && !memcmp(pRSN->abyOUI, abyOUI01, 4)
- && (pRSN->wVersion == 1)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WPA_ParseRSN: [%d]\n", pRSN->len);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Legal RSN\n");
- // update each variable if pRSN is long enough to contain the variable
- if (pRSN->len >= 10) //oui1(4)+ver(2)+GKSuite(4)
- {
- if ( !memcmp(pRSN->abyMulticast, abyOUI01, 4))
- pBSSList->byGKType = WPA_WEP40;
- else if ( !memcmp(pRSN->abyMulticast, abyOUI02, 4))
- pBSSList->byGKType = WPA_TKIP;
- else if ( !memcmp(pRSN->abyMulticast, abyOUI03, 4))
- pBSSList->byGKType = WPA_AESWRAP;
- else if ( !memcmp(pRSN->abyMulticast, abyOUI04, 4))
- pBSSList->byGKType = WPA_AESCCMP;
- else if ( !memcmp(pRSN->abyMulticast, abyOUI05, 4))
- pBSSList->byGKType = WPA_WEP104;
- else
- // any vendor checks here
- pBSSList->byGKType = WPA_NONE;
+ // information element header makes sense
+ if ((pRSN->len >= 6) // oui1(4)+ver(2)
+ && (pRSN->byElementID == WLAN_EID_RSN_WPA) && !memcmp(pRSN->abyOUI, abyOUI01, 4)
+ && (pRSN->wVersion == 1)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Legal RSN\n");
+ // update each variable if pRSN is long enough to contain the variable
+ if (pRSN->len >= 10) //oui1(4)+ver(2)+GKSuite(4)
+ {
+ if (!memcmp(pRSN->abyMulticast, abyOUI01, 4))
+ pBSSList->byGKType = WPA_WEP40;
+ else if (!memcmp(pRSN->abyMulticast, abyOUI02, 4))
+ pBSSList->byGKType = WPA_TKIP;
+ else if (!memcmp(pRSN->abyMulticast, abyOUI03, 4))
+ pBSSList->byGKType = WPA_AESWRAP;
+ else if (!memcmp(pRSN->abyMulticast, abyOUI04, 4))
+ pBSSList->byGKType = WPA_AESCCMP;
+ else if (!memcmp(pRSN->abyMulticast, abyOUI05, 4))
+ pBSSList->byGKType = WPA_WEP104;
+ else
+ // any vendor checks here
+ pBSSList->byGKType = WPA_NONE;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"byGKType: %x\n", pBSSList->byGKType);
- }
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "byGKType: %x\n", pBSSList->byGKType);
+ }
- if (pRSN->len >= 12) //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)
- {
- j = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
- for(i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
- if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
- if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
- pBSSList->abyPKType[j++] = WPA_NONE;
- else if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI02, 4))
- pBSSList->abyPKType[j++] = WPA_TKIP;
- else if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI03, 4))
- pBSSList->abyPKType[j++] = WPA_AESWRAP;
- else if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI04, 4))
- pBSSList->abyPKType[j++] = WPA_AESCCMP;
- else
- // any vendor checks here
- ;
- }
- else
- break;
- //DBG_PRN_GRP14(("abyPKType[%d]: %X\n", j-1, pBSSList->abyPKType[j-1]));
- } //for
- pBSSList->wPKCount = (unsigned short)j;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d\n", pBSSList->wPKCount);
- }
+ if (pRSN->len >= 12) //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)
+ {
+ j = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
+ for (i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
+ if (pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
+ if (!memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
+ pBSSList->abyPKType[j++] = WPA_NONE;
+ else if (!memcmp(pRSN->PKSList[i].abyOUI, abyOUI02, 4))
+ pBSSList->abyPKType[j++] = WPA_TKIP;
+ else if (!memcmp(pRSN->PKSList[i].abyOUI, abyOUI03, 4))
+ pBSSList->abyPKType[j++] = WPA_AESWRAP;
+ else if (!memcmp(pRSN->PKSList[i].abyOUI, abyOUI04, 4))
+ pBSSList->abyPKType[j++] = WPA_AESCCMP;
+ else
+ // any vendor checks here
+ ;
+ } else
+ break;
+ //DBG_PRN_GRP14(("abyPKType[%d]: %X\n", j-1, pBSSList->abyPKType[j-1]));
+ } //for
+ pBSSList->wPKCount = (unsigned short)j;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wPKCount: %d\n", pBSSList->wPKCount);
+ }
- m = pRSN->wPKCount;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"m: %d\n", m);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+m*4: %d\n", 14+m*4);
+ m = pRSN->wPKCount;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "m: %d\n", m);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "14+m*4: %d\n", 14+m*4);
- if (pRSN->len >= 14+m*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)
- // overlay IE_RSN_Auth structure into correct place
- pIE_RSN_Auth = (PWLAN_IE_RSN_AUTH) pRSN->PKSList[m].abyOUI;
- j = 0;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
- pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
- for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
- if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
- if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
- pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
- else if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI02, 4))
- pBSSList->abyAuthType[j++] = WPA_AUTH_PSK;
- else
- // any vendor checks here
- ;
- }
- else
- break;
- //DBG_PRN_GRP14(("abyAuthType[%d]: %X\n", j-1, pBSSList->abyAuthType[j-1]));
- }
- if(j > 0)
- pBSSList->wAuthCount = (unsigned short)j;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d\n", pBSSList->wAuthCount);
- }
+ if (pRSN->len >= 14+m*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)
+ // overlay IE_RSN_Auth structure into correct place
+ pIE_RSN_Auth = (PWLAN_IE_RSN_AUTH) pRSN->PKSList[m].abyOUI;
+ j = 0;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
+ pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
+ for (i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
+ if (pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
+ if (!memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
+ pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
+ else if (!memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI02, 4))
+ pBSSList->abyAuthType[j++] = WPA_AUTH_PSK;
+ else
+ // any vendor checks here
+ ;
+ } else
+ break;
+ //DBG_PRN_GRP14(("abyAuthType[%d]: %X\n", j-1, pBSSList->abyAuthType[j-1]));
+ }
+ if (j > 0)
+ pBSSList->wAuthCount = (unsigned short)j;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wAuthCount: %d\n", pBSSList->wAuthCount);
+ }
- if (pIE_RSN_Auth != NULL) {
+ if (pIE_RSN_Auth != NULL) {
+ n = pIE_RSN_Auth->wAuthCount;
- n = pIE_RSN_Auth->wAuthCount;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "n: %d\n", n);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "14+4+(m+n)*4: %d\n", 14+4+(m+n)*4);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"n: %d\n", n);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+4+(m+n)*4: %d\n", 14+4+(m+n)*4);
-
- if(pRSN->len+2 >= 14+4+(m+n)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*n)+Cap(2)
- pbyCaps = (unsigned char *)pIE_RSN_Auth->AuthKSList[n].abyOUI;
- pBSSList->byDefaultK_as_PK = (*pbyCaps) & WPA_GROUPFLAG;
- pBSSList->byReplayIdx = 2 << ((*pbyCaps >> WPA_REPLAYBITSSHIFT) & WPA_REPLAYBITS);
- pBSSList->sRSNCapObj.bRSNCapExist = true;
- pBSSList->sRSNCapObj.wRSNCap = *(unsigned short *)pbyCaps;
- //DBG_PRN_GRP14(("pbyCaps: %X\n", *pbyCaps));
- //DBG_PRN_GRP14(("byDefaultK_as_PK: %X\n", pBSSList->byDefaultK_as_PK));
- //DBG_PRN_GRP14(("byReplayIdx: %X\n", pBSSList->byReplayIdx));
- }
- }
- pBSSList->bWPAValid = true;
- }
+ if (pRSN->len+2 >= 14+4+(m+n)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*n)+Cap(2)
+ pbyCaps = (unsigned char *)pIE_RSN_Auth->AuthKSList[n].abyOUI;
+ pBSSList->byDefaultK_as_PK = (*pbyCaps) & WPA_GROUPFLAG;
+ pBSSList->byReplayIdx = 2 << ((*pbyCaps >> WPA_REPLAYBITSSHIFT) & WPA_REPLAYBITS);
+ pBSSList->sRSNCapObj.bRSNCapExist = true;
+ pBSSList->sRSNCapObj.wRSNCap = *(unsigned short *)pbyCaps;
+ //DBG_PRN_GRP14(("pbyCaps: %X\n", *pbyCaps));
+ //DBG_PRN_GRP14(("byDefaultK_as_PK: %X\n", pBSSList->byDefaultK_as_PK));
+ //DBG_PRN_GRP14(("byReplayIdx: %X\n", pBSSList->byReplayIdx));
+ }
+ }
+ pBSSList->bWPAValid = true;
+ }
}
/*+
@@ -236,51 +230,47 @@ WPA_ParseRSN (
*
* Return Value: none.
*
--*/
+ -*/
bool
-WPA_SearchRSN (
- unsigned char byCmd,
- unsigned char byEncrypt,
- PKnownBSS pBSSList
- )
+WPA_SearchRSN(
+ unsigned char byCmd,
+ unsigned char byEncrypt,
+ PKnownBSS pBSSList
+)
{
- int ii;
- unsigned char byPKType = WPA_NONE;
+ int ii;
+ unsigned char byPKType = WPA_NONE;
- if (pBSSList->bWPAValid == false)
- return false;
+ if (pBSSList->bWPAValid == false)
+ return false;
- switch(byCmd) {
- case 0:
+ switch (byCmd) {
+ case 0:
- if (byEncrypt != pBSSList->byGKType)
- return false;
+ if (byEncrypt != pBSSList->byGKType)
+ return false;
- if (pBSSList->wPKCount > 0) {
- for (ii = 0; ii < pBSSList->wPKCount; ii ++) {
- if (pBSSList->abyPKType[ii] == WPA_AESCCMP)
- byPKType = WPA_AESCCMP;
- else if ((pBSSList->abyPKType[ii] == WPA_TKIP) && (byPKType != WPA_AESCCMP))
- byPKType = WPA_TKIP;
- else if ((pBSSList->abyPKType[ii] == WPA_WEP40) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP))
- byPKType = WPA_WEP40;
- else if ((pBSSList->abyPKType[ii] == WPA_WEP104) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP))
- byPKType = WPA_WEP104;
- }
- if (byEncrypt != byPKType)
- return false;
- }
- return true;
-// if (pBSSList->wAuthCount > 0)
-// for (ii=0; ii < pBSSList->wAuthCount; ii ++)
-// if (byAuth == pBSSList->abyAuthType[ii])
-// break;
- break;
+ if (pBSSList->wPKCount > 0) {
+ for (ii = 0; ii < pBSSList->wPKCount; ii++) {
+ if (pBSSList->abyPKType[ii] == WPA_AESCCMP)
+ byPKType = WPA_AESCCMP;
+ else if ((pBSSList->abyPKType[ii] == WPA_TKIP) && (byPKType != WPA_AESCCMP))
+ byPKType = WPA_TKIP;
+ else if ((pBSSList->abyPKType[ii] == WPA_WEP40) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP))
+ byPKType = WPA_WEP40;
+ else if ((pBSSList->abyPKType[ii] == WPA_WEP104) && (byPKType != WPA_AESCCMP) && (byPKType != WPA_TKIP))
+ byPKType = WPA_WEP104;
+ }
+ if (byEncrypt != byPKType)
+ return false;
+ }
+ return true;
+ break;
- default:
- break;
- }
- return false;
+ default:
+ break;
+ }
+ return false;
}
/*+
@@ -296,21 +286,19 @@ WPA_SearchRSN (
*
* Return Value: none.
*
--*/
+ -*/
bool
-WPAb_Is_RSN (
- PWLAN_IE_RSN_EXT pRSN
- )
+WPAb_Is_RSN(
+ PWLAN_IE_RSN_EXT pRSN
+)
{
- if (pRSN == NULL)
- return false;
+ if (pRSN == NULL)
+ return false;
- if ((pRSN->len >= 6) && // oui1(4)+ver(2)
- (pRSN->byElementID == WLAN_EID_RSN_WPA) && !memcmp(pRSN->abyOUI, abyOUI01, 4) &&
- (pRSN->wVersion == 1)) {
- return true;
- }
- else
- return false;
+ if ((pRSN->len >= 6) && // oui1(4)+ver(2)
+ (pRSN->byElementID == WLAN_EID_RSN_WPA) && !memcmp(pRSN->abyOUI, abyOUI01, 4) &&
+ (pRSN->wVersion == 1)) {
+ return true;
+ } else
+ return false;
}
-
diff --git a/drivers/staging/vt6655/wpa.h b/drivers/staging/vt6655/wpa.h
index 921fd7ae9d38..1d1918a12641 100644
--- a/drivers/staging/vt6655/wpa.h
+++ b/drivers/staging/vt6655/wpa.h
@@ -55,30 +55,29 @@
/*--------------------- Export Types ------------------------------*/
-
/*--------------------- Export Functions --------------------------*/
void
WPA_ClearRSN(
- PKnownBSS pBSSList
- );
+ PKnownBSS pBSSList
+);
void
WPA_ParseRSN(
- PKnownBSS pBSSList,
- PWLAN_IE_RSN_EXT pRSN
- );
+ PKnownBSS pBSSList,
+ PWLAN_IE_RSN_EXT pRSN
+);
bool
WPA_SearchRSN(
- unsigned char byCmd,
- unsigned char byEncrypt,
- PKnownBSS pBSSList
- );
+ unsigned char byCmd,
+ unsigned char byEncrypt,
+ PKnownBSS pBSSList
+);
bool
WPAb_Is_RSN(
- PWLAN_IE_RSN_EXT pRSN
- );
+ PWLAN_IE_RSN_EXT pRSN
+);
#endif // __WPA_H__
diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c
index 884db1abe123..089788dfba63 100644
--- a/drivers/staging/vt6655/wpa2.c
+++ b/drivers/staging/vt6655/wpa2.c
@@ -36,7 +36,7 @@
#include "wmgr.h"
/*--------------------- Static Definitions -------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Classes ----------------------------*/
@@ -51,7 +51,6 @@ const unsigned char abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
const unsigned char abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 };
const unsigned char abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
-
/*--------------------- Static Functions --------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -71,25 +70,25 @@ const unsigned char abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
*
* Return Value: none.
*
--*/
+ -*/
void
-WPA2_ClearRSN (
- PKnownBSS pBSSNode
- )
+WPA2_ClearRSN(
+ PKnownBSS pBSSNode
+)
{
- int ii;
-
- pBSSNode->bWPA2Valid = false;
-
- pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
- for (ii=0; ii < 4; ii ++)
- pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP;
- pBSSNode->wCSSPKCount = 1;
- for (ii=0; ii < 4; ii ++)
- pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
- pBSSNode->wAKMSSAuthCount = 1;
- pBSSNode->sRSNCapObj.bRSNCapExist = false;
- pBSSNode->sRSNCapObj.wRSNCap = 0;
+ int ii;
+
+ pBSSNode->bWPA2Valid = false;
+
+ pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
+ for (ii = 0; ii < 4; ii++)
+ pBSSNode->abyCSSPK[ii] = WLAN_11i_CSS_CCMP;
+ pBSSNode->wCSSPKCount = 1;
+ for (ii = 0; ii < 4; ii++)
+ pBSSNode->abyAKMSSAuthType[ii] = WLAN_11i_AKMSS_802_1X;
+ pBSSNode->wAKMSSAuthCount = 1;
+ pBSSNode->sRSNCapObj.bRSNCapExist = false;
+ pBSSNode->sRSNCapObj.wRSNCap = 0;
}
/*+
@@ -106,147 +105,144 @@ WPA2_ClearRSN (
*
* Return Value: none.
*
--*/
+ -*/
void
-WPA2vParseRSN (
- PKnownBSS pBSSNode,
- PWLAN_IE_RSN pRSN
- )
+WPA2vParseRSN(
+ PKnownBSS pBSSNode,
+ PWLAN_IE_RSN pRSN
+)
{
- int i, j;
- unsigned short m = 0, n = 0;
- unsigned char *pbyOUI;
- bool bUseGK = false;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA2_ParseRSN: [%d]\n", pRSN->len);
-
- WPA2_ClearRSN(pBSSNode);
-
- if (pRSN->len == 2) { // ver(2)
- if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1)) {
- pBSSNode->bWPA2Valid = true;
- }
- return;
- }
-
- if (pRSN->len < 6) { // ver(2) + GK(4)
- // invalid CSS, P802.11i/D10.0, p31
- return;
- }
-
- // information element header makes sense
- if ((pRSN->byElementID == WLAN_EID_RSN) &&
- (pRSN->wVersion == 1)) {
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Legal 802.11i RSN\n");
-
- pbyOUI = &(pRSN->abyRSN[0]);
- if ( !memcmp(pbyOUI, abyOUIWEP40, 4))
- pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40;
- else if ( !memcmp(pbyOUI, abyOUITKIP, 4))
- pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP;
- else if ( !memcmp(pbyOUI, abyOUICCMP, 4))
- pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
- else if ( !memcmp(pbyOUI, abyOUIWEP104, 4))
- pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104;
- else if ( !memcmp(pbyOUI, abyOUIGK, 4)) {
- // invalid CSS, P802.11i/D10.0, p32
- return;
- } else
- // any vendor checks here
- pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN;
-
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"802.11i CSS: %X\n", pBSSNode->byCSSGK);
-
- if (pRSN->len == 6) {
- pBSSNode->bWPA2Valid = true;
- return;
- }
-
- if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
- pBSSNode->wCSSPKCount = *((unsigned short *) &(pRSN->abyRSN[4]));
- j = 0;
- pbyOUI = &(pRSN->abyRSN[6]);
-
- for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
-
- if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
- if ( !memcmp(pbyOUI, abyOUIGK, 4)) {
- pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
- bUseGK = true;
- } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) {
- // Invalid CSS, continue to parsing
- } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) {
- if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
- pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
- else
- ; // Invalid CSS, continue to parsing
- } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) {
- pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
- } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) {
- // Invalid CSS, continue to parsing
- } else {
- // any vendor checks here
- pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
- }
- pbyOUI += 4;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyCSSPK[%d]: %X\n", j-1, pBSSNode->abyCSSPK[j-1]);
- } else
- break;
- } //for
-
- if (bUseGK == true) {
- if (j != 1) {
- // invalid CSS, This should be only PK CSS.
- return;
- }
- if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
- // invalid CSS, If CCMP is enable , PK can't be CSSGK.
- return;
- }
- }
- if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) {
- // invalid CSS, No valid PK.
- return;
- }
- pBSSNode->wCSSPKCount = (unsigned short)j;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
- }
-
- m = *((unsigned short *) &(pRSN->abyRSN[4]));
-
- if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
- pBSSNode->wAKMSSAuthCount = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));
- j = 0;
- pbyOUI = &(pRSN->abyRSN[8+4*m]);
- for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
- if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
- if ( !memcmp(pbyOUI, abyOUI8021X, 4))
- pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
- else if ( !memcmp(pbyOUI, abyOUIPSK, 4))
- pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK;
- else
- // any vendor checks here
- pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"abyAKMSSAuthType[%d]: %X\n", j-1, pBSSNode->abyAKMSSAuthType[j-1]);
- } else
- break;
- }
- pBSSNode->wAKMSSAuthCount = (unsigned short)j;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
-
- n = *((unsigned short *) &(pRSN->abyRSN[6+4*m]));
- if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
- pBSSNode->sRSNCapObj.bRSNCapExist = true;
- pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *) &(pRSN->abyRSN[8+4*m+4*n]));
- }
- }
- //ignore PMKID lists bcs only (Re)Assocrequest has this field
- pBSSNode->bWPA2Valid = true;
- }
+ int i, j;
+ unsigned short m = 0, n = 0;
+ unsigned char *pbyOUI;
+ bool bUseGK = false;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WPA2_ParseRSN: [%d]\n", pRSN->len);
+
+ WPA2_ClearRSN(pBSSNode);
+
+ if (pRSN->len == 2) { // ver(2)
+ if ((pRSN->byElementID == WLAN_EID_RSN) && (pRSN->wVersion == 1)) {
+ pBSSNode->bWPA2Valid = true;
+ }
+ return;
+ }
+
+ if (pRSN->len < 6) { // ver(2) + GK(4)
+ // invalid CSS, P802.11i/D10.0, p31
+ return;
+ }
+
+ // information element header makes sense
+ if ((pRSN->byElementID == WLAN_EID_RSN) &&
+ (pRSN->wVersion == 1)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Legal 802.11i RSN\n");
+
+ pbyOUI = &(pRSN->abyRSN[0]);
+ if (!memcmp(pbyOUI, abyOUIWEP40, 4))
+ pBSSNode->byCSSGK = WLAN_11i_CSS_WEP40;
+ else if (!memcmp(pbyOUI, abyOUITKIP, 4))
+ pBSSNode->byCSSGK = WLAN_11i_CSS_TKIP;
+ else if (!memcmp(pbyOUI, abyOUICCMP, 4))
+ pBSSNode->byCSSGK = WLAN_11i_CSS_CCMP;
+ else if (!memcmp(pbyOUI, abyOUIWEP104, 4))
+ pBSSNode->byCSSGK = WLAN_11i_CSS_WEP104;
+ else if (!memcmp(pbyOUI, abyOUIGK, 4)) {
+ // invalid CSS, P802.11i/D10.0, p32
+ return;
+ } else
+ // any vendor checks here
+ pBSSNode->byCSSGK = WLAN_11i_CSS_UNKNOWN;
+
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "802.11i CSS: %X\n", pBSSNode->byCSSGK);
+
+ if (pRSN->len == 6) {
+ pBSSNode->bWPA2Valid = true;
+ return;
+ }
+
+ if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
+ pBSSNode->wCSSPKCount = *((unsigned short *)&(pRSN->abyRSN[4]));
+ j = 0;
+ pbyOUI = &(pRSN->abyRSN[6]);
+
+ for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(unsigned char)); i++) {
+ if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
+ if (!memcmp(pbyOUI, abyOUIGK, 4)) {
+ pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP;
+ bUseGK = true;
+ } else if (!memcmp(pbyOUI, abyOUIWEP40, 4)) {
+ // Invalid CSS, continue to parsing
+ } else if (!memcmp(pbyOUI, abyOUITKIP, 4)) {
+ if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP)
+ pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP;
+ else
+ ; // Invalid CSS, continue to parsing
+ } else if (!memcmp(pbyOUI, abyOUICCMP, 4)) {
+ pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP;
+ } else if (!memcmp(pbyOUI, abyOUIWEP104, 4)) {
+ // Invalid CSS, continue to parsing
+ } else {
+ // any vendor checks here
+ pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN;
+ }
+ pbyOUI += 4;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyCSSPK[%d]: %X\n", j-1, pBSSNode->abyCSSPK[j-1]);
+ } else
+ break;
+ } //for
+
+ if (bUseGK == true) {
+ if (j != 1) {
+ // invalid CSS, This should be only PK CSS.
+ return;
+ }
+ if (pBSSNode->byCSSGK == WLAN_11i_CSS_CCMP) {
+ // invalid CSS, If CCMP is enable , PK can't be CSSGK.
+ return;
+ }
+ }
+ if ((pBSSNode->wCSSPKCount != 0) && (j == 0)) {
+ // invalid CSS, No valid PK.
+ return;
+ }
+ pBSSNode->wCSSPKCount = (unsigned short)j;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
+ }
+
+ m = *((unsigned short *)&(pRSN->abyRSN[4]));
+
+ if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
+ pBSSNode->wAKMSSAuthCount = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
+ j = 0;
+ pbyOUI = &(pRSN->abyRSN[8+4*m]);
+ for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(unsigned char)); i++) {
+ if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
+ if (!memcmp(pbyOUI, abyOUI8021X, 4))
+ pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
+ else if (!memcmp(pbyOUI, abyOUIPSK, 4))
+ pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_PSK;
+ else
+ // any vendor checks here
+ pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_UNKNOWN;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "abyAKMSSAuthType[%d]: %X\n", j-1, pBSSNode->abyAKMSSAuthType[j-1]);
+ } else
+ break;
+ }
+ pBSSNode->wAKMSSAuthCount = (unsigned short)j;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
+
+ n = *((unsigned short *)&(pRSN->abyRSN[6+4*m]));
+ if (pRSN->len >= 12 + 4 * m + 4 * n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
+ pBSSNode->sRSNCapObj.bRSNCapExist = true;
+ pBSSNode->sRSNCapObj.wRSNCap = *((unsigned short *)&(pRSN->abyRSN[8+4*m+4*n]));
+ }
+ }
+ //ignore PMKID lists bcs only (Re)Assocrequest has this field
+ pBSSNode->bWPA2Valid = true;
+ }
}
-
/*+
*
* Description:
@@ -260,105 +256,105 @@ WPA2vParseRSN (
*
* Return Value: length of IEs.
*
--*/
+ -*/
unsigned int
WPA2uSetIEs(
- void *pMgmtHandle,
- PWLAN_IE_RSN pRSNIEs
- )
+ void *pMgmtHandle,
+ PWLAN_IE_RSN pRSNIEs
+)
{
- PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle;
- unsigned char *pbyBuffer = NULL;
- unsigned int ii = 0;
- unsigned short *pwPMKID = NULL;
-
- if (pRSNIEs == NULL) {
- return(0);
- }
- if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
- (pMgmt->pCurrBSS != NULL)) {
- /* WPA2 IE */
- pbyBuffer = (unsigned char *) pRSNIEs;
- pRSNIEs->byElementID = WLAN_EID_RSN;
- pRSNIEs->len = 6; //Version(2)+GK(4)
- pRSNIEs->wVersion = 1;
- //Group Key Cipher Suite
- pRSNIEs->abyRSN[0] = 0x00;
- pRSNIEs->abyRSN[1] = 0x0F;
- pRSNIEs->abyRSN[2] = 0xAC;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
- } else {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
- }
-
- // Pairwise Key Cipher Suite
- pRSNIEs->abyRSN[4] = 1;
- pRSNIEs->abyRSN[5] = 0;
- pRSNIEs->abyRSN[6] = 0x00;
- pRSNIEs->abyRSN[7] = 0x0F;
- pRSNIEs->abyRSN[8] = 0xAC;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP;
- } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
- } else {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
- }
- pRSNIEs->len += 6;
-
- // Auth Key Management Suite
- pRSNIEs->abyRSN[10] = 1;
- pRSNIEs->abyRSN[11] = 0;
- pRSNIEs->abyRSN[12] = 0x00;
- pRSNIEs->abyRSN[13] = 0x0F;
- pRSNIEs->abyRSN[14] = 0xAC;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK;
- } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
- } else {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
- }
- pRSNIEs->len +=6;
-
- // RSN Capabilities
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
- memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
- } else {
- pRSNIEs->abyRSN[16] = 0;
- pRSNIEs->abyRSN[17] = 0;
- }
- pRSNIEs->len +=2;
-
- if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
- (pMgmt->bRoaming == true) &&
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
- // RSN PMKID
- pwPMKID = (unsigned short *)(&pRSNIEs->abyRSN[18]); // Point to PMKID count
- *pwPMKID = 0; // Initialize PMKID count
- pbyBuffer = &pRSNIEs->abyRSN[20]; // Point to PMKID list
- for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
- if ( !memcmp(&pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
- (*pwPMKID) ++;
- memcpy(pbyBuffer, pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 16);
- pbyBuffer += 16;
- }
- }
- if (*pwPMKID != 0) {
- pRSNIEs->len += (2 + (*pwPMKID)*16);
- } else {
- pbyBuffer = &pRSNIEs->abyRSN[18];
- }
- }
- return(pRSNIEs->len + WLAN_IEHDR_LEN);
- }
- return(0);
+ PSMgmtObject pMgmt = (PSMgmtObject) pMgmtHandle;
+ unsigned char *pbyBuffer = NULL;
+ unsigned int ii = 0;
+ unsigned short *pwPMKID = NULL;
+
+ if (pRSNIEs == NULL) {
+ return 0;
+ }
+ if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
+ (pMgmt->pCurrBSS != NULL)) {
+ /* WPA2 IE */
+ pbyBuffer = (unsigned char *)pRSNIEs;
+ pRSNIEs->byElementID = WLAN_EID_RSN;
+ pRSNIEs->len = 6; //Version(2)+GK(4)
+ pRSNIEs->wVersion = 1;
+ //Group Key Cipher Suite
+ pRSNIEs->abyRSN[0] = 0x00;
+ pRSNIEs->abyRSN[1] = 0x0F;
+ pRSNIEs->abyRSN[2] = 0xAC;
+ if (pMgmt->byCSSGK == KEY_CTL_WEP) {
+ pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
+ } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
+ pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
+ pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
+ } else {
+ pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
+ }
+
+ // Pairwise Key Cipher Suite
+ pRSNIEs->abyRSN[4] = 1;
+ pRSNIEs->abyRSN[5] = 0;
+ pRSNIEs->abyRSN[6] = 0x00;
+ pRSNIEs->abyRSN[7] = 0x0F;
+ pRSNIEs->abyRSN[8] = 0xAC;
+ if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
+ pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
+ pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP;
+ } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
+ pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
+ } else {
+ pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
+ }
+ pRSNIEs->len += 6;
+
+ // Auth Key Management Suite
+ pRSNIEs->abyRSN[10] = 1;
+ pRSNIEs->abyRSN[11] = 0;
+ pRSNIEs->abyRSN[12] = 0x00;
+ pRSNIEs->abyRSN[13] = 0x0F;
+ pRSNIEs->abyRSN[14] = 0xAC;
+ if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
+ pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
+ pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
+ } else {
+ pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
+ }
+ pRSNIEs->len += 6;
+
+ // RSN Capabilities
+ if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
+ memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
+ } else {
+ pRSNIEs->abyRSN[16] = 0;
+ pRSNIEs->abyRSN[17] = 0;
+ }
+ pRSNIEs->len += 2;
+
+ if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
+ (pMgmt->bRoaming == true) &&
+ (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
+ // RSN PMKID
+ pwPMKID = (unsigned short *)(&pRSNIEs->abyRSN[18]); // Point to PMKID count
+ *pwPMKID = 0; // Initialize PMKID count
+ pbyBuffer = &pRSNIEs->abyRSN[20]; // Point to PMKID list
+ for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
+ if (!memcmp(&pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0], pMgmt->abyCurrBSSID, ETH_ALEN)) {
+ (*pwPMKID)++;
+ memcpy(pbyBuffer, pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID, 16);
+ pbyBuffer += 16;
+ }
+ }
+ if (*pwPMKID != 0) {
+ pRSNIEs->len += (2 + (*pwPMKID)*16);
+ } else {
+ pbyBuffer = &pRSNIEs->abyRSN[18];
+ }
+ }
+ return pRSNIEs->len + WLAN_IEHDR_LEN;
+ }
+ return 0;
}
diff --git a/drivers/staging/vt6655/wpa2.h b/drivers/staging/vt6655/wpa2.h
index 718208beb72f..2d0bd2e515f3 100644
--- a/drivers/staging/vt6655/wpa2.h
+++ b/drivers/staging/vt6655/wpa2.h
@@ -40,16 +40,15 @@
#define MAX_PMKID_CACHE 16
typedef struct tagsPMKIDInfo {
- unsigned char abyBSSID[6];
- unsigned char abyPMKID[16];
+ unsigned char abyBSSID[6];
+ unsigned char abyPMKID[16];
} PMKIDInfo, *PPMKIDInfo;
typedef struct tagSPMKIDCache {
- unsigned long BSSIDInfoCount;
- PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE];
+ unsigned long BSSIDInfoCount;
+ PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE];
} SPMKIDCache, *PSPMKIDCache;
-
/*--------------------- Export Classes ----------------------------*/
/*--------------------- Export Variables --------------------------*/
@@ -59,20 +58,20 @@ typedef struct tagSPMKIDCache {
/*--------------------- Export Functions --------------------------*/
void
-WPA2_ClearRSN (
- PKnownBSS pBSSNode
- );
+WPA2_ClearRSN(
+ PKnownBSS pBSSNode
+);
void
-WPA2vParseRSN (
- PKnownBSS pBSSNode,
- PWLAN_IE_RSN pRSN
- );
+WPA2vParseRSN(
+ PKnownBSS pBSSNode,
+ PWLAN_IE_RSN pRSN
+);
unsigned int
WPA2uSetIEs(
- void *pMgmtHandle,
- PWLAN_IE_RSN pRSNIEs
- );
+ void *pMgmtHandle,
+ PWLAN_IE_RSN pRSNIEs
+);
#endif // __WPA2_H__
diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c
index 2b6ae1e403bf..869f62c678e6 100644
--- a/drivers/staging/vt6655/wpactl.c
+++ b/drivers/staging/vt6655/wpactl.c
@@ -44,8 +44,6 @@
#define VIAWGET_WPA_MAX_BUF_SIZE 1024
-
-
static const int frequency_list[] = {
2412, 2417, 2422, 2427, 2432, 2437, 2442,
2447, 2452, 2457, 2462, 2467, 2472, 2484
@@ -54,13 +52,10 @@ static const int frequency_list[] = {
/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
/*--------------------- Static Functions --------------------------*/
-
-
-
/*--------------------- Export Variables --------------------------*/
static void wpadev_setup(struct net_device *dev)
{
@@ -70,7 +65,7 @@ static void wpadev_setup(struct net_device *dev)
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 1000;
- memset(dev->broadcast,0xFF, ETH_ALEN);
+ memset(dev->broadcast, 0xFF, ETH_ALEN);
dev->flags = IFF_BROADCAST|IFF_MULTICAST;
}
@@ -91,42 +86,41 @@ static void wpadev_setup(struct net_device *dev)
static int wpa_init_wpadev(PSDevice pDevice)
{
- PSDevice wpadev_priv;
+ PSDevice wpadev_priv;
struct net_device *dev = pDevice->dev;
- int ret=0;
+ int ret = 0;
pDevice->wpadev = alloc_netdev(sizeof(PSDevice), "vntwpa", wpadev_setup);
if (pDevice->wpadev == NULL)
return -ENOMEM;
- wpadev_priv = netdev_priv(pDevice->wpadev);
- *wpadev_priv = *pDevice;
+ wpadev_priv = netdev_priv(pDevice->wpadev);
+ *wpadev_priv = *pDevice;
memcpy(pDevice->wpadev->dev_addr, dev->dev_addr, ETH_ALEN);
- pDevice->wpadev->base_addr = dev->base_addr;
+ pDevice->wpadev->base_addr = dev->base_addr;
pDevice->wpadev->irq = dev->irq;
pDevice->wpadev->mem_start = dev->mem_start;
pDevice->wpadev->mem_end = dev->mem_end;
ret = register_netdev(pDevice->wpadev);
if (ret) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: register_netdev(WPA) failed!\n",
- dev->name);
+ dev->name);
free_netdev(pDevice->wpadev);
return -1;
}
if (pDevice->skb == NULL) {
- pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
- if (pDevice->skb == NULL)
- return -ENOMEM;
- }
+ pDevice->skb = dev_alloc_skb((int)pDevice->rx_buf_sz);
+ if (pDevice->skb == NULL)
+ return -ENOMEM;
+ }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdev %s for WPA management\n",
- dev->name, pDevice->wpadev->name);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Registered netdev %s for WPA management\n",
+ dev->name, pDevice->wpadev->name);
return 0;
}
-
/*
* Description:
* unregister net_device (wpadev)
@@ -142,26 +136,22 @@ static int wpa_init_wpadev(PSDevice pDevice)
static int wpa_release_wpadev(PSDevice pDevice)
{
- if (pDevice->skb) {
- dev_kfree_skb(pDevice->skb);
- pDevice->skb = NULL;
- }
-
- if (pDevice->wpadev) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
- pDevice->dev->name, pDevice->wpadev->name);
- unregister_netdev(pDevice->wpadev);
- free_netdev(pDevice->wpadev);
- pDevice->wpadev = NULL;
- }
+ if (pDevice->skb) {
+ dev_kfree_skb(pDevice->skb);
+ pDevice->skb = NULL;
+ }
+
+ if (pDevice->wpadev) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
+ pDevice->dev->name, pDevice->wpadev->name);
+ unregister_netdev(pDevice->wpadev);
+ free_netdev(pDevice->wpadev);
+ pDevice->wpadev = NULL;
+ }
return 0;
}
-
-
-
-
/*
* Description:
* Set enable/disable dev for wpa supplicant daemon
@@ -184,7 +174,6 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
return wpa_release_wpadev(pDevice);
}
-
/*
* Description:
* Set WPA algorithm & keys
@@ -199,252 +188,245 @@ int wpa_set_wpadev(PSDevice pDevice, int val)
*
*/
- int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel)
+int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel)
{
- struct viawget_wpa_param *param=ctx;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- unsigned long dwKeyIndex = 0;
- unsigned char abyKey[MAX_KEY_LEN];
- unsigned char abySeq[MAX_KEY_LEN];
- QWORD KeyRSC;
+ struct viawget_wpa_param *param = ctx;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ unsigned long dwKeyIndex = 0;
+ unsigned char abyKey[MAX_KEY_LEN];
+ unsigned char abySeq[MAX_KEY_LEN];
+ QWORD KeyRSC;
// NDIS_802_11_KEY_RSC KeyRSC;
- unsigned char byKeyDecMode = KEY_CTL_WEP;
+ unsigned char byKeyDecMode = KEY_CTL_WEP;
int ret = 0;
int uu, ii;
-
if (param->u.wpa_key.alg_name > WPA_ALG_CCMP ||
- param->u.wpa_key.key_len >= MAX_KEY_LEN ||
- param->u.wpa_key.seq_len >= MAX_KEY_LEN)
+ param->u.wpa_key.key_len >= MAX_KEY_LEN ||
+ param->u.wpa_key.seq_len >= MAX_KEY_LEN)
return -EINVAL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n", param->u.wpa_key.alg_name);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "param->u.wpa_key.alg_name = %d \n", param->u.wpa_key.alg_name);
if (param->u.wpa_key.alg_name == WPA_ALG_NONE) {
- pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- pDevice->bEncryptionEnable = false;
- pDevice->byKeyIndex = 0;
- pDevice->bTransmitKey = false;
- KeyvRemoveAllWEPKey(&(pDevice->sKey), pDevice->PortOffset);
- for (uu=0; uu<MAX_KEY_TABLE; uu++) {
- MACvDisableKeyEntry(pDevice->PortOffset, uu);
- }
- return ret;
- }
-
- //spin_unlock_irq(&pDevice->lock);
- if(param->u.wpa_key.key && fcpfkernel) {
- memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len);
- }
- else {
- spin_unlock_irq(&pDevice->lock);
- if (param->u.wpa_key.key &&
- copy_from_user(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len)) {
- spin_lock_irq(&pDevice->lock);
- return -EINVAL;
- }
-spin_lock_irq(&pDevice->lock);
- }
+ pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ pDevice->bEncryptionEnable = false;
+ pDevice->byKeyIndex = 0;
+ pDevice->bTransmitKey = false;
+ KeyvRemoveAllWEPKey(&(pDevice->sKey), pDevice->PortOffset);
+ for (uu = 0; uu < MAX_KEY_TABLE; uu++) {
+ MACvDisableKeyEntry(pDevice->PortOffset, uu);
+ }
+ return ret;
+ }
+
+ //spin_unlock_irq(&pDevice->lock);
+ if (param->u.wpa_key.key && fcpfkernel) {
+ memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len);
+ } else {
+ spin_unlock_irq(&pDevice->lock);
+ if (param->u.wpa_key.key &&
+ copy_from_user(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len)) {
+ spin_lock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
+ spin_lock_irq(&pDevice->lock);
+ }
- dwKeyIndex = (unsigned long)(param->u.wpa_key.key_index);
+ dwKeyIndex = (unsigned long)(param->u.wpa_key.key_index);
if (param->u.wpa_key.alg_name == WPA_ALG_WEP) {
- if (dwKeyIndex > 3) {
- return -EINVAL;
- }
- else {
- if (param->u.wpa_key.set_tx) {
- pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
- pDevice->bTransmitKey = true;
- dwKeyIndex |= (1 << 31);
- }
- KeybSetDefaultKey(&(pDevice->sKey),
- dwKeyIndex & ~(BIT30 | USE_KEYRSC),
- param->u.wpa_key.key_len,
- NULL,
- abyKey,
- KEY_CTL_WEP,
- pDevice->PortOffset,
- pDevice->byLocalID);
-
- }
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- pDevice->bEncryptionEnable = true;
- return ret;
- }
-
- //spin_unlock_irq(&pDevice->lock);
- if(param->u.wpa_key.seq && fcpfkernel) {
- memcpy(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len);
- }
- else {
- spin_unlock_irq(&pDevice->lock);
- if (param->u.wpa_key.seq &&
- copy_from_user(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len)) {
- spin_lock_irq(&pDevice->lock);
- return -EINVAL;
- }
-spin_lock_irq(&pDevice->lock);
-}
+ if (dwKeyIndex > 3) {
+ return -EINVAL;
+ } else {
+ if (param->u.wpa_key.set_tx) {
+ pDevice->byKeyIndex = (unsigned char)dwKeyIndex;
+ pDevice->bTransmitKey = true;
+ dwKeyIndex |= (1 << 31);
+ }
+ KeybSetDefaultKey(&(pDevice->sKey),
+ dwKeyIndex & ~(BIT30 | USE_KEYRSC),
+ param->u.wpa_key.key_len,
+ NULL,
+ abyKey,
+ KEY_CTL_WEP,
+ pDevice->PortOffset,
+ pDevice->byLocalID);
+
+ }
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+ pDevice->bEncryptionEnable = true;
+ return ret;
+ }
+
+ //spin_unlock_irq(&pDevice->lock);
+ if (param->u.wpa_key.seq && fcpfkernel) {
+ memcpy(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len);
+ } else {
+ spin_unlock_irq(&pDevice->lock);
+ if (param->u.wpa_key.seq &&
+ copy_from_user(&abySeq[0], param->u.wpa_key.seq, param->u.wpa_key.seq_len)) {
+ spin_lock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
+ spin_lock_irq(&pDevice->lock);
+ }
if (param->u.wpa_key.seq_len > 0) {
- for (ii = 0 ; ii < param->u.wpa_key.seq_len ; ii++) {
- if (ii < 4)
- LODWORD(KeyRSC) |= (abySeq[ii] << (ii * 8));
- else
- HIDWORD(KeyRSC) |= (abySeq[ii] << ((ii-4) * 8));
- //KeyRSC |= (abySeq[ii] << (ii * 8));
+ for (ii = 0; ii < param->u.wpa_key.seq_len; ii++) {
+ if (ii < 4)
+ LODWORD(KeyRSC) |= (abySeq[ii] << (ii * 8));
+ else
+ HIDWORD(KeyRSC) |= (abySeq[ii] << ((ii-4) * 8));
+ //KeyRSC |= (abySeq[ii] << (ii * 8));
}
dwKeyIndex |= 1 << 29;
}
- if (param->u.wpa_key.key_index >= MAX_GROUP_KEY) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return dwKeyIndex > 3\n");
- return -EINVAL;
- }
+ if (param->u.wpa_key.key_index >= MAX_GROUP_KEY) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return dwKeyIndex > 3\n");
+ return -EINVAL;
+ }
if (param->u.wpa_key.alg_name == WPA_ALG_TKIP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
- }
+ pDevice->eEncryptionStatus = Ndis802_11Encryption2Enabled;
+ }
if (param->u.wpa_key.alg_name == WPA_ALG_CCMP) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
- }
+ pDevice->eEncryptionStatus = Ndis802_11Encryption3Enabled;
+ }
if (param->u.wpa_key.set_tx)
dwKeyIndex |= (1 << 31);
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
+ byKeyDecMode = KEY_CTL_CCMP;
+ else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
+ byKeyDecMode = KEY_CTL_TKIP;
+ else
+ byKeyDecMode = KEY_CTL_WEP;
+
+ // Fix HCT test that set 256 bits KEY and Ndis802_11Encryption3Enabled
+ if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
+ if (param->u.wpa_key.key_len == MAX_KEY_LEN)
+ byKeyDecMode = KEY_CTL_TKIP;
+ else if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
+ byKeyDecMode = KEY_CTL_WEP;
+ else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
+ byKeyDecMode = KEY_CTL_WEP;
+ } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
+ if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
+ byKeyDecMode = KEY_CTL_WEP;
+ else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
+ byKeyDecMode = KEY_CTL_WEP;
+ }
+
+ // Check TKIP key length
+ if ((byKeyDecMode == KEY_CTL_TKIP) &&
+ (param->u.wpa_key.key_len != MAX_KEY_LEN)) {
+ // TKIP Key must be 256 bits
+ //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - TKIP Key must be 256 bits\n"));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n");
+ return -EINVAL;
+ }
+ // Check AES key length
+ if ((byKeyDecMode == KEY_CTL_CCMP) &&
+ (param->u.wpa_key.key_len != AES_KEY_LEN)) {
+ // AES Key must be 128 bits
+ //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - AES Key must be 128 bits\n"));
+ return -EINVAL;
+ }
+
+ // spin_lock_irq(&pDevice->lock);
+ if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
+ // If is_broadcast_ether_addr, set the key as every key entry's group key.
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
+
+ if ((KeybSetAllGroupKey(&(pDevice->sKey),
+ dwKeyIndex,
+ param->u.wpa_key.key_len,
+ (PQWORD) &(KeyRSC),
+ (unsigned char *)abyKey,
+ byKeyDecMode,
+ pDevice->PortOffset,
+ pDevice->byLocalID) == true) &&
+ (KeybSetDefaultKey(&(pDevice->sKey),
+ dwKeyIndex,
+ param->u.wpa_key.key_len,
+ (PQWORD) &(KeyRSC),
+ (unsigned char *)abyKey,
+ byKeyDecMode,
+ pDevice->PortOffset,
+ pDevice->byLocalID) == true)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
+
+ } else {
+ //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -KeybSetDefaultKey Fail.0\n"));
+ // spin_unlock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
+
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Assign.\n");
+ // BSSID not 0xffffffffffff
+ // Pairwise Key can't be WEP
+ if (byKeyDecMode == KEY_CTL_WEP) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key can't be WEP\n");
+ //spin_unlock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
- byKeyDecMode = KEY_CTL_CCMP;
- else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
- byKeyDecMode = KEY_CTL_TKIP;
- else
- byKeyDecMode = KEY_CTL_WEP;
-
- // Fix HCT test that set 256 bits KEY and Ndis802_11Encryption3Enabled
- if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled) {
- if (param->u.wpa_key.key_len == MAX_KEY_LEN)
- byKeyDecMode = KEY_CTL_TKIP;
- else if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
- byKeyDecMode = KEY_CTL_WEP;
- else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
- byKeyDecMode = KEY_CTL_WEP;
- } else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) {
- if (param->u.wpa_key.key_len == WLAN_WEP40_KEYLEN)
- byKeyDecMode = KEY_CTL_WEP;
- else if (param->u.wpa_key.key_len == WLAN_WEP104_KEYLEN)
- byKeyDecMode = KEY_CTL_WEP;
- }
-
- // Check TKIP key length
- if ((byKeyDecMode == KEY_CTL_TKIP) &&
- (param->u.wpa_key.key_len != MAX_KEY_LEN)) {
- // TKIP Key must be 256 bits
- //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - TKIP Key must be 256 bits\n"));
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n");
- return -EINVAL;
- }
- // Check AES key length
- if ((byKeyDecMode == KEY_CTL_CCMP) &&
- (param->u.wpa_key.key_len != AES_KEY_LEN)) {
- // AES Key must be 128 bits
- //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - AES Key must be 128 bits\n"));
- return -EINVAL;
- }
-
- // spin_lock_irq(&pDevice->lock);
- if (is_broadcast_ether_addr(&param->addr[0]) || (param->addr == NULL)) {
- // If is_broadcast_ether_addr, set the key as every key entry's group key.
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Groupe Key Assign.\n");
-
- if ((KeybSetAllGroupKey(&(pDevice->sKey),
- dwKeyIndex,
- param->u.wpa_key.key_len,
- (PQWORD) &(KeyRSC),
- (unsigned char *)abyKey,
- byKeyDecMode,
- pDevice->PortOffset,
- pDevice->byLocalID) == true) &&
- (KeybSetDefaultKey(&(pDevice->sKey),
- dwKeyIndex,
- param->u.wpa_key.key_len,
- (PQWORD) &(KeyRSC),
- (unsigned char *)abyKey,
- byKeyDecMode,
- pDevice->PortOffset,
- pDevice->byLocalID) == true) ) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
-
- } else {
- //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -KeybSetDefaultKey Fail.0\n"));
- // spin_unlock_irq(&pDevice->lock);
- return -EINVAL;
- }
-
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Assign.\n");
- // BSSID not 0xffffffffffff
- // Pairwise Key can't be WEP
- if (byKeyDecMode == KEY_CTL_WEP) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key can't be WEP\n");
- //spin_unlock_irq(&pDevice->lock);
- return -EINVAL;
- }
-
- dwKeyIndex |= (1 << 30); // set pairwise key
- if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
- //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - WMAC_CONFIG_IBSS_STA\n"));
- //spin_unlock_irq(&pDevice->lock);
- return -EINVAL;
- }
- if (KeybSetKey(&(pDevice->sKey),
- &param->addr[0],
- dwKeyIndex,
- param->u.wpa_key.key_len,
- (PQWORD) &(KeyRSC),
- (unsigned char *)abyKey,
- byKeyDecMode,
- pDevice->PortOffset,
- pDevice->byLocalID) == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
-
- } else {
- // Key Table Full
- if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
- //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
- //spin_unlock_irq(&pDevice->lock);
- return -EINVAL;
-
- } else {
- // Save Key and configure just before associate/reassociate to BSSID
- // we do not implement now
- //spin_unlock_irq(&pDevice->lock);
- return -EINVAL;
- }
- }
- } // BSSID not 0xffffffffffff
- if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
- pDevice->byKeyIndex = (unsigned char)param->u.wpa_key.key_index;
- pDevice->bTransmitKey = true;
- }
- pDevice->bEncryptionEnable = true;
- //spin_unlock_irq(&pDevice->lock);
+ dwKeyIndex |= (1 << 30); // set pairwise key
+ if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
+ //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA - WMAC_CONFIG_IBSS_STA\n"));
+ //spin_unlock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
+ if (KeybSetKey(&(pDevice->sKey),
+ &param->addr[0],
+ dwKeyIndex,
+ param->u.wpa_key.key_len,
+ (PQWORD) &(KeyRSC),
+ (unsigned char *)abyKey,
+ byKeyDecMode,
+ pDevice->PortOffset,
+ pDevice->byLocalID) == true) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
+
+ } else {
+ // Key Table Full
+ if (!compare_ether_addr(&param->addr[0], pDevice->abyBSSID)) {
+ //DBG_PRN_WLAN03(("return NDIS_STATUS_INVALID_DATA -Key Table Full.2\n"));
+ //spin_unlock_irq(&pDevice->lock);
+ return -EINVAL;
+
+ } else {
+ // Save Key and configure just before associate/reassociate to BSSID
+ // we do not implement now
+ //spin_unlock_irq(&pDevice->lock);
+ return -EINVAL;
+ }
+ }
+ } // BSSID not 0xffffffffffff
+ if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
+ pDevice->byKeyIndex = (unsigned char)param->u.wpa_key.key_index;
+ pDevice->bTransmitKey = true;
+ }
+ pDevice->bEncryptionEnable = true;
+ //spin_unlock_irq(&pDevice->lock);
/*
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n",
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][0],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][1],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][2],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][3],
- pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][4]
- );
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " key=%x-%x-%x-%x-%x-xxxxx \n",
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][0],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][1],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][2],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][3],
+ pMgmt->sNodeDBTable[iNodeIndex].abyWepKey[byKeyIndex][4]
+);
*/
return ret;
-
}
-
/*
* Description:
* enable wpa auth & mode
@@ -460,22 +442,18 @@ spin_lock_irq(&pDevice->lock);
*/
static int wpa_set_wpa(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
-
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
int ret = 0;
- pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
- pMgmt->bShareKeyAlgorithm = false;
+ pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+ pMgmt->bShareKeyAlgorithm = false;
- return ret;
+ return ret;
}
-
-
-
- /*
+/*
* Description:
* set disassociate
*
@@ -490,23 +468,21 @@ static int wpa_set_wpa(PSDevice pDevice,
*/
static int wpa_set_disassociate(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
int ret = 0;
- spin_lock_irq(&pDevice->lock);
- if (pDevice->bLinkPass) {
- if (!memcmp(param->addr, pMgmt->abyCurrBSSID, 6))
- bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
- }
- spin_unlock_irq(&pDevice->lock);
+ spin_lock_irq(&pDevice->lock);
+ if (pDevice->bLinkPass) {
+ if (!memcmp(param->addr, pMgmt->abyCurrBSSID, 6))
+ bScheduleCommand((void *)pDevice, WLAN_CMD_DISASSOCIATE, NULL);
+ }
+ spin_unlock_irq(&pDevice->lock);
- return ret;
+ return ret;
}
-
-
/*
* Description:
* enable scan process
@@ -522,20 +498,18 @@ static int wpa_set_disassociate(PSDevice pDevice,
*/
static int wpa_set_scan(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
int ret = 0;
- spin_lock_irq(&pDevice->lock);
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
- spin_unlock_irq(&pDevice->lock);
+ spin_lock_irq(&pDevice->lock);
+ BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ spin_unlock_irq(&pDevice->lock);
- return ret;
+ return ret;
}
-
-
/*
* Description:
* get bssid
@@ -551,18 +525,16 @@ static int wpa_set_scan(PSDevice pDevice,
*/
static int wpa_get_bssid(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
int ret = 0;
memcpy(param->u.wpa_associate.bssid, pMgmt->abyCurrBSSID , 6);
- return ret;
-
+ return ret;
}
-
/*
* Description:
* get bssid
@@ -578,22 +550,20 @@ static int wpa_get_bssid(PSDevice pDevice,
*/
static int wpa_get_ssid(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
PWLAN_IE_SSID pItemSSID;
int ret = 0;
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID;
memcpy(param->u.wpa_associate.ssid, pItemSSID->abySSID , pItemSSID->len);
param->u.wpa_associate.ssid_len = pItemSSID->len;
- return ret;
+ return ret;
}
-
-
/*
* Description:
* get scan results
@@ -609,132 +579,112 @@ static int wpa_get_ssid(PSDevice pDevice,
*/
static int wpa_get_scan(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
struct viawget_scan_result *scan_buf;
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PWLAN_IE_SSID pItemSSID;
- PKnownBSS pBSS;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PWLAN_IE_SSID pItemSSID;
+ PKnownBSS pBSS;
unsigned char *pBuf;
int ret = 0;
u16 count = 0;
u16 ii, jj;
#if 1
- unsigned char *ptempBSS;
-
-
-
- ptempBSS = kmalloc(sizeof(KnownBSS), (int)GFP_ATOMIC);
-
- if (ptempBSS == NULL) {
-
- printk("bubble sort kmalloc memory fail@@@\n");
+ unsigned char *ptempBSS;
- ret = -ENOMEM;
+ ptempBSS = kmalloc(sizeof(KnownBSS), (int)GFP_ATOMIC);
- return ret;
+ if (ptempBSS == NULL) {
+ printk("bubble sort kmalloc memory fail@@@\n");
- }
+ ret = -ENOMEM;
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ return ret;
- for(jj=0;jj<MAX_BSS_NUM-ii-1;jj++) {
-
- if((pMgmt->sBSSList[jj].bActive!=true) ||
-
- ((pMgmt->sBSSList[jj].uRSSI>pMgmt->sBSSList[jj+1].uRSSI) &&(pMgmt->sBSSList[jj+1].bActive!=false))) {
-
- memcpy(ptempBSS,&pMgmt->sBSSList[jj],sizeof(KnownBSS));
-
- memcpy(&pMgmt->sBSSList[jj],&pMgmt->sBSSList[jj+1],sizeof(KnownBSS));
-
- memcpy(&pMgmt->sBSSList[jj+1],ptempBSS,sizeof(KnownBSS));
-
- }
+ }
- }
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ for (jj = 0; jj < MAX_BSS_NUM - ii - 1; jj++) {
+ if ((pMgmt->sBSSList[jj].bActive != true) ||
- }
+ ((pMgmt->sBSSList[jj].uRSSI > pMgmt->sBSSList[jj + 1].uRSSI) && (pMgmt->sBSSList[jj + 1].bActive != false))) {
+ memcpy(ptempBSS, &pMgmt->sBSSList[jj], sizeof(KnownBSS));
- kfree(ptempBSS);
+ memcpy(&pMgmt->sBSSList[jj], &pMgmt->sBSSList[jj + 1], sizeof(KnownBSS));
- // printk("bubble sort result:\n");
+ memcpy(&pMgmt->sBSSList[jj + 1], ptempBSS, sizeof(KnownBSS));
- //for (ii = 0; ii < MAX_BSS_NUM; ii++)
+ }
- // printk("%d [%s]:RSSI=%d\n",ii,((PWLAN_IE_SSID)(pMgmt->sBSSList[ii].abySSID))->abySSID,
+ }
- // pMgmt->sBSSList[ii].uRSSI);
+ }
- #endif
+ kfree(ptempBSS);
+#endif
//******mike:bubble sort by stronger RSSI*****//
-
-
-
count = 0;
pBSS = &(pMgmt->sBSSList[0]);
- for (ii = 0; ii < MAX_BSS_NUM; ii++) {
- pBSS = &(pMgmt->sBSSList[ii]);
- if (!pBSS->bActive)
- continue;
- count++;
- }
-
- pBuf = kcalloc(count, sizeof(struct viawget_scan_result), (int)GFP_ATOMIC);
-
- if (pBuf == NULL) {
- ret = -ENOMEM;
- return ret;
- }
- scan_buf = (struct viawget_scan_result *)pBuf;
+ for (ii = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSS = &(pMgmt->sBSSList[ii]);
+ if (!pBSS->bActive)
+ continue;
+ count++;
+ }
+
+ pBuf = kcalloc(count, sizeof(struct viawget_scan_result), (int)GFP_ATOMIC);
+
+ if (pBuf == NULL) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ scan_buf = (struct viawget_scan_result *)pBuf;
pBSS = &(pMgmt->sBSSList[0]);
- for (ii = 0, jj = 0; ii < MAX_BSS_NUM ; ii++) {
- pBSS = &(pMgmt->sBSSList[ii]);
- if (pBSS->bActive) {
- if (jj >= count)
- break;
- memcpy(scan_buf->bssid, pBSS->abyBSSID, WLAN_BSSID_LEN);
- pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
- memcpy(scan_buf->ssid, pItemSSID->abySSID, pItemSSID->len);
- scan_buf->ssid_len = pItemSSID->len;
- scan_buf->freq = frequency_list[pBSS->uChannel-1];
- scan_buf->caps = pBSS->wCapInfo;
- //scan_buf->caps = pBSS->wCapInfo;
- //scan_buf->qual =
- //scan_buf->noise =
- //scan_buf->level =
- //scan_buf->maxrate =
- if (pBSS->wWPALen != 0) {
- scan_buf->wpa_ie_len = pBSS->wWPALen;
- memcpy(scan_buf->wpa_ie, pBSS->byWPAIE, pBSS->wWPALen);
- }
- if (pBSS->wRSNLen != 0) {
- scan_buf->rsn_ie_len = pBSS->wRSNLen;
- memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen);
- }
- scan_buf = (struct viawget_scan_result *)((unsigned char *)scan_buf + sizeof(struct viawget_scan_result));
- jj ++;
- }
- }
-
- if (jj < count)
- count = jj;
-
- if (copy_to_user(param->u.scan_results.buf, pBuf, sizeof(struct viawget_scan_result) * count)) {
+ for (ii = 0, jj = 0; ii < MAX_BSS_NUM; ii++) {
+ pBSS = &(pMgmt->sBSSList[ii]);
+ if (pBSS->bActive) {
+ if (jj >= count)
+ break;
+ memcpy(scan_buf->bssid, pBSS->abyBSSID, WLAN_BSSID_LEN);
+ pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
+ memcpy(scan_buf->ssid, pItemSSID->abySSID, pItemSSID->len);
+ scan_buf->ssid_len = pItemSSID->len;
+ scan_buf->freq = frequency_list[pBSS->uChannel-1];
+ scan_buf->caps = pBSS->wCapInfo;
+ //scan_buf->caps = pBSS->wCapInfo;
+ //scan_buf->qual =
+ //scan_buf->noise =
+ //scan_buf->level =
+ //scan_buf->maxrate =
+ if (pBSS->wWPALen != 0) {
+ scan_buf->wpa_ie_len = pBSS->wWPALen;
+ memcpy(scan_buf->wpa_ie, pBSS->byWPAIE, pBSS->wWPALen);
+ }
+ if (pBSS->wRSNLen != 0) {
+ scan_buf->rsn_ie_len = pBSS->wRSNLen;
+ memcpy(scan_buf->rsn_ie, pBSS->byRSNIE, pBSS->wRSNLen);
+ }
+ scan_buf = (struct viawget_scan_result *)((unsigned char *)scan_buf + sizeof(struct viawget_scan_result));
+ jj++;
+ }
+ }
+
+ if (jj < count)
+ count = jj;
+
+ if (copy_to_user(param->u.scan_results.buf, pBuf, sizeof(struct viawget_scan_result) * count)) {
ret = -EFAULT;
}
param->u.scan_results.scan_count = count;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count)
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " param->u.scan_results.scan_count = %d\n", count)
- kfree(pBuf);
- return ret;
+ kfree(pBuf);
+ return ret;
}
-
-
/*
* Description:
* set associate with AP
@@ -750,23 +700,22 @@ static int wpa_get_scan(PSDevice pDevice,
*/
static int wpa_set_associate(PSDevice pDevice,
- struct viawget_wpa_param *param)
+ struct viawget_wpa_param *param)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PWLAN_IE_SSID pItemSSID;
- unsigned char abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char abyWPAIE[64];
- int ret = 0;
- bool bWepEnabled=false;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PWLAN_IE_SSID pItemSSID;
+ unsigned char abyNullAddr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ unsigned char abyWPAIE[64];
+ int ret = 0;
+ bool bWepEnabled = false;
// set key type & algorithm
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group_suite = %d\n", param->u.wpa_associate.group_suite);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key_mgmt_suite = %d\n", param->u.wpa_associate.key_mgmt_suite);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "auth_alg = %d\n", param->u.wpa_associate.auth_alg);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "mode = %d\n", param->u.wpa_associate.mode);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len);
-
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pairwise_suite = %d\n", param->u.wpa_associate.pairwise_suite);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "group_suite = %d\n", param->u.wpa_associate.group_suite);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "key_mgmt_suite = %d\n", param->u.wpa_associate.key_mgmt_suite);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "auth_alg = %d\n", param->u.wpa_associate.auth_alg);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "mode = %d\n", param->u.wpa_associate.mode);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ie_len = %d\n", param->u.wpa_associate.wpa_ie_len);
if (param->u.wpa_associate.wpa_ie_len) {
if (!param->u.wpa_associate.wpa_ie)
@@ -778,28 +727,27 @@ static int wpa_set_associate(PSDevice pDevice,
}
if (param->u.wpa_associate.mode == 1)
- pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
+ pMgmt->eConfigMode = WMAC_CONFIG_IBSS_STA;
else
- pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
- // set ssid
+ pMgmt->eConfigMode = WMAC_CONFIG_ESS_STA;
+ // set ssid
memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
- pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
- pItemSSID->byElementID = WLAN_EID_SSID;
+ pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID;
+ pItemSSID->byElementID = WLAN_EID_SSID;
pItemSSID->len = param->u.wpa_associate.ssid_len;
memcpy(pItemSSID->abySSID, param->u.wpa_associate.ssid, pItemSSID->len);
// set bssid
- if (memcmp(param->u.wpa_associate.bssid, &abyNullAddr[0], 6) != 0)
- memcpy(pMgmt->abyDesireBSSID, param->u.wpa_associate.bssid, 6);
-else
-{
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pItemSSID->abySSID);
-}
+ if (memcmp(param->u.wpa_associate.bssid, &abyNullAddr[0], 6) != 0)
+ memcpy(pMgmt->abyDesireBSSID, param->u.wpa_associate.bssid, 6);
+ else {
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pItemSSID->abySSID);
+ }
- if (param->u.wpa_associate.wpa_ie_len == 0) {
- if (param->u.wpa_associate.auth_alg & AUTH_ALG_SHARED_KEY)
- pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
- else
- pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+ if (param->u.wpa_associate.wpa_ie_len == 0) {
+ if (param->u.wpa_associate.auth_alg & AUTH_ALG_SHARED_KEY)
+ pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
+ else
+ pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
} else if (abyWPAIE[0] == RSN_INFO_ELEM) {
if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK)
pMgmt->eAuthenMode = WMAC_AUTH_WPA2PSK;
@@ -809,9 +757,9 @@ else
if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_WPA_NONE)
pMgmt->eAuthenMode = WMAC_AUTH_WPANONE;
else if (param->u.wpa_associate.key_mgmt_suite == KEY_MGMT_PSK)
- pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
+ pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK;
else
- pMgmt->eAuthenMode = WMAC_AUTH_WPA;
+ pMgmt->eAuthenMode = WMAC_AUTH_WPA;
}
switch (param->u.wpa_associate.pairwise_suite) {
@@ -824,7 +772,7 @@ else
case CIPHER_WEP40:
case CIPHER_WEP104:
pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- bWepEnabled=true;
+ bWepEnabled = true;
break;
case CIPHER_NONE:
if (param->u.wpa_associate.group_suite == CIPHER_CCMP)
@@ -838,55 +786,53 @@ else
//DavidWang add for WPA_supplicant support open/share mode
- if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) {
- pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- //pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
- pMgmt->bShareKeyAlgorithm = true;
- }
- else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) {
- if(!bWepEnabled) pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
- else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
- //pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
- //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encryption
- }
+ if (pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) {
+ pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+ //pMgmt->eAuthenMode = WMAC_AUTH_SHAREKEY;
+ pMgmt->bShareKeyAlgorithm = true;
+ } else if (pMgmt->eAuthenMode == WMAC_AUTH_OPEN) {
+ if (!bWepEnabled) pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled;
+ else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled;
+ //pMgmt->eAuthenMode = WMAC_AUTH_OPEN;
+ //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encryption
+ }
//mike save old encryption status
pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus;
- if (pDevice->eEncryptionStatus != Ndis802_11EncryptionDisabled)
- pDevice->bEncryptionEnable = true;
- else
- pDevice->bEncryptionEnable = false;
-if (!((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) ||
- ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bWepEnabled==true))) ) //DavidWang //20080717-06,<Modify> by chester//Not to initial WEP
- KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
- spin_lock_irq(&pDevice->lock);
- pDevice->bLinkPass = false;
- memset(pMgmt->abyCurrBSSID, 0, 6);
- pMgmt->eCurrState = WMAC_STATE_IDLE;
- netif_stop_queue(pDevice->dev);
+ if (pDevice->eEncryptionStatus != Ndis802_11EncryptionDisabled)
+ pDevice->bEncryptionEnable = true;
+ else
+ pDevice->bEncryptionEnable = false;
+ if (!((pMgmt->eAuthenMode == WMAC_AUTH_SHAREKEY) ||
+ ((pMgmt->eAuthenMode == WMAC_AUTH_OPEN) && (bWepEnabled == true)))) //DavidWang //20080717-06,<Modify> by chester//Not to initial WEP
+ KeyvInitTable(&pDevice->sKey, pDevice->PortOffset);
+ spin_lock_irq(&pDevice->lock);
+ pDevice->bLinkPass = false;
+ memset(pMgmt->abyCurrBSSID, 0, 6);
+ pMgmt->eCurrState = WMAC_STATE_IDLE;
+ netif_stop_queue(pDevice->dev);
//20080701-02,<Add> by Mike Liu
/*******search if ap_scan=2 ,which is associating request in hidden ssid mode ****/
-{
- PKnownBSS pCurr = NULL;
- pCurr = BSSpSearchBSSList(pDevice,
- pMgmt->abyDesireBSSID,
- pMgmt->abyDesireSSID,
- pMgmt->eConfigPHYMode
- );
-
- if (pCurr == NULL){
- printk("wpa_set_associate---->hidden mode site survey before associate.......\n");
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
- }
-}
+ {
+ PKnownBSS pCurr = NULL;
+ pCurr = BSSpSearchBSSList(pDevice,
+ pMgmt->abyDesireBSSID,
+ pMgmt->abyDesireSSID,
+ pMgmt->eConfigPHYMode
+);
+
+ if (pCurr == NULL) {
+ printk("wpa_set_associate---->hidden mode site survey before associate.......\n");
+ bScheduleCommand((void *)pDevice, WLAN_CMD_BSSID_SCAN, pMgmt->abyDesireSSID);
+ }
+ }
/****************************************************************/
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
- spin_unlock_irq(&pDevice->lock);
+ bScheduleCommand((void *)pDevice, WLAN_CMD_SSID, NULL);
+ spin_unlock_irq(&pDevice->lock);
- return ret;
+ return ret;
}
-
/*
* Description:
* wpa_ioctl main function supported for wpa supplicant
@@ -922,61 +868,61 @@ int wpa_ioctl(PSDevice pDevice, struct iw_point *p)
switch (param->cmd) {
case VIAWGET_SET_WPA:
- ret = wpa_set_wpa(pDevice, param);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_WPA \n");
+ ret = wpa_set_wpa(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_WPA \n");
break;
case VIAWGET_SET_KEY:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n");
- spin_lock_irq(&pDevice->lock);
- ret = wpa_set_keys(pDevice, param, false);
- spin_unlock_irq(&pDevice->lock);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_KEY \n");
+ spin_lock_irq(&pDevice->lock);
+ ret = wpa_set_keys(pDevice, param, false);
+ spin_unlock_irq(&pDevice->lock);
break;
case VIAWGET_SET_SCAN:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_SCAN \n");
- ret = wpa_set_scan(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_SCAN \n");
+ ret = wpa_set_scan(pDevice, param);
break;
case VIAWGET_GET_SCAN:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SCAN\n");
- ret = wpa_get_scan(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SCAN\n");
+ ret = wpa_get_scan(pDevice, param);
wpa_ioctl = 1;
break;
case VIAWGET_GET_SSID:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SSID \n");
- ret = wpa_get_ssid(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_SSID \n");
+ ret = wpa_get_ssid(pDevice, param);
wpa_ioctl = 1;
break;
case VIAWGET_GET_BSSID:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_BSSID \n");
- ret = wpa_get_bssid(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_GET_BSSID \n");
+ ret = wpa_get_bssid(pDevice, param);
wpa_ioctl = 1;
break;
case VIAWGET_SET_ASSOCIATE:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_ASSOCIATE \n");
- ret = wpa_set_associate(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_ASSOCIATE \n");
+ ret = wpa_set_associate(pDevice, param);
break;
case VIAWGET_SET_DISASSOCIATE:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DISASSOCIATE \n");
- ret = wpa_set_disassociate(pDevice, param);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DISASSOCIATE \n");
+ ret = wpa_set_disassociate(pDevice, param);
break;
case VIAWGET_SET_DROP_UNENCRYPT:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DROP_UNENCRYPT \n");
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DROP_UNENCRYPT \n");
break;
- case VIAWGET_SET_DEAUTHENTICATE:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DEAUTHENTICATE \n");
+ case VIAWGET_SET_DEAUTHENTICATE:
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_SET_DEAUTHENTICATE \n");
break;
default:
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ioctl: unknown cmd=%d\n",
- param->cmd);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wpa_ioctl: unknown cmd=%d\n",
+ param->cmd);
return -EOPNOTSUPP;
break;
}
@@ -993,4 +939,3 @@ out:
return ret;
}
-
diff --git a/drivers/staging/vt6655/wpactl.h b/drivers/staging/vt6655/wpactl.h
index dbe8e861d991..b9e2ab231f1b 100644
--- a/drivers/staging/vt6655/wpactl.h
+++ b/drivers/staging/vt6655/wpactl.h
@@ -36,13 +36,12 @@
/*--------------------- Export Definitions -------------------------*/
-
//WPA related
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
-typedef enum { KEY_MGMT_802_1X, KEY_MGMT_CCKM,KEY_MGMT_PSK, KEY_MGMT_NONE,
+typedef enum { KEY_MGMT_802_1X, KEY_MGMT_CCKM, KEY_MGMT_PSK, KEY_MGMT_NONE,
KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
#define AUTH_ALG_OPEN_SYSTEM 0x01
@@ -52,8 +51,6 @@ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_CCKM,KEY_MGMT_PSK, KEY_MGMT_NONE,
#define GENERIC_INFO_ELEM 0xdd
#define RSN_INFO_ELEM 0x30
-
-
typedef unsigned long long NDIS_802_11_KEY_RSC;
/*--------------------- Export Classes ----------------------------*/
@@ -67,6 +64,3 @@ int wpa_ioctl(PSDevice pDevice, struct iw_point *p);
int wpa_set_keys(PSDevice pDevice, void *ctx, bool fcpfkernel);
#endif // __WPACL_H__
-
-
-
diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c
index 82e93cb82053..b61328fbee87 100644
--- a/drivers/staging/vt6655/wroute.c
+++ b/drivers/staging/vt6655/wroute.c
@@ -43,14 +43,12 @@
/*--------------------- Static Classes ----------------------------*/
/*--------------------- Static Variables --------------------------*/
-static int msglevel =MSG_LEVEL_INFO;
+static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
/*--------------------- Static Functions --------------------------*/
/*--------------------- Export Variables --------------------------*/
-
-
/*
* Description:
* Relay packet. Return true if packet is copy to DMA1
@@ -65,135 +63,128 @@ static int msglevel =MSG_LEVEL_INFO;
* Return Value: true if packet duplicate; otherwise false
*
*/
-bool ROUTEbRelay (PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex)
+bool ROUTEbRelay(PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex)
{
- PSMgmtObject pMgmt = pDevice->pMgmt;
- PSTxDesc pHeadTD, pLastTD;
- unsigned int cbFrameBodySize;
- unsigned int uMACfragNum;
- unsigned char byPktType;
- bool bNeedEncryption = false;
- SKeyItem STempKey;
- PSKeyItem pTransmitKey = NULL;
- unsigned int cbHeaderSize;
- unsigned int ii;
- unsigned char *pbyBSSID;
-
-
-
-
- if (AVAIL_TD(pDevice, TYPE_AC0DMA)<=0) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Relay can't allocate TD1..\n");
- return false;
- }
-
- pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA];
-
- pHeadTD->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
-
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)pbySkbData, ETH_HLEN);
-
- cbFrameBodySize = uDataLen - ETH_HLEN;
-
- if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
- cbFrameBodySize += 8;
- }
-
- if (pDevice->bEncryptionEnable == true) {
- bNeedEncryption = true;
-
- // get group key
- pbyBSSID = pDevice->abyBroadcastAddr;
- if(KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
- pTransmitKey = NULL;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
- } else {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"Get GTK.\n");
- }
- }
-
- if (pDevice->bEnableHostWEP) {
- if (uNodeIndex < MAX_NODE_NUM + 1) {
- pTransmitKey = &STempKey;
- pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
- pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
- pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
- pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
- pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
- memcpy(pTransmitKey->abyKey,
- &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
- pTransmitKey->uKeyLength
- );
- }
- }
-
- uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
-
- if (uMACfragNum > AVAIL_TD(pDevice,TYPE_AC0DMA)) {
- return false;
- }
- byPktType = (unsigned char)pDevice->byPacketType;
-
- if (pDevice->bFixRate) {
- if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
- if (pDevice->uConnectionRate >= RATE_11M) {
- pDevice->wCurrentRate = RATE_11M;
- } else {
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
- } else {
- if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
- (pDevice->uConnectionRate <= RATE_6M)) {
- pDevice->wCurrentRate = RATE_6M;
- } else {
- if (pDevice->uConnectionRate >= RATE_54M)
- pDevice->wCurrentRate = RATE_54M;
- else
- pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
- }
- }
- }
- else {
- pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate;
- }
-
- if (pDevice->wCurrentRate <= RATE_11M)
- byPktType = PK_TYPE_11B;
-
- vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
- cbFrameBodySize, TYPE_AC0DMA, pHeadTD,
- &pDevice->sTxEthHeader, pbySkbData, pTransmitKey, uNodeIndex,
- &uMACfragNum,
- &cbHeaderSize
- );
-
- if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
- // Disable PS
- MACbPSWakeup(pDevice->PortOffset);
- }
-
- pDevice->bPWBitOn = false;
-
- pLastTD = pHeadTD;
- for (ii = 0; ii < uMACfragNum; ii++) {
- // Poll Transmit the adapter
- wmb();
- pHeadTD->m_td0TD0.f1Owner=OWNED_BY_NIC;
- wmb();
- if (ii == (uMACfragNum - 1))
- pLastTD = pHeadTD;
- pHeadTD = pHeadTD->next;
- }
-
- pLastTD->pTDInfo->skb = 0;
- pLastTD->pTDInfo->byFlags = 0;
-
- pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD;
-
- MACvTransmitAC0(pDevice->PortOffset);
-
- return true;
+ PSMgmtObject pMgmt = pDevice->pMgmt;
+ PSTxDesc pHeadTD, pLastTD;
+ unsigned int cbFrameBodySize;
+ unsigned int uMACfragNum;
+ unsigned char byPktType;
+ bool bNeedEncryption = false;
+ SKeyItem STempKey;
+ PSKeyItem pTransmitKey = NULL;
+ unsigned int cbHeaderSize;
+ unsigned int ii;
+ unsigned char *pbyBSSID;
+
+ if (AVAIL_TD(pDevice, TYPE_AC0DMA) <= 0) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Relay can't allocate TD1..\n");
+ return false;
+ }
+
+ pHeadTD = pDevice->apCurrTD[TYPE_AC0DMA];
+
+ pHeadTD->m_td1TD1.byTCR = (TCR_EDP | TCR_STP);
+
+ memcpy(pDevice->sTxEthHeader.abyDstAddr, (unsigned char *)pbySkbData, ETH_HLEN);
+
+ cbFrameBodySize = uDataLen - ETH_HLEN;
+
+ if (ntohs(pDevice->sTxEthHeader.wType) > ETH_DATA_LEN) {
+ cbFrameBodySize += 8;
+ }
+
+ if (pDevice->bEncryptionEnable == true) {
+ bNeedEncryption = true;
+
+ // get group key
+ pbyBSSID = pDevice->abyBroadcastAddr;
+ if (KeybGetTransmitKey(&(pDevice->sKey), pbyBSSID, GROUP_KEY, &pTransmitKey) == false) {
+ pTransmitKey = NULL;
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "KEY is NULL. [%d]\n", pDevice->pMgmt->eCurrMode);
+ } else {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG "Get GTK.\n");
+ }
+ }
+
+ if (pDevice->bEnableHostWEP) {
+ if (uNodeIndex < MAX_NODE_NUM + 1) {
+ pTransmitKey = &STempKey;
+ pTransmitKey->byCipherSuite = pMgmt->sNodeDBTable[uNodeIndex].byCipherSuite;
+ pTransmitKey->dwKeyIndex = pMgmt->sNodeDBTable[uNodeIndex].dwKeyIndex;
+ pTransmitKey->uKeyLength = pMgmt->sNodeDBTable[uNodeIndex].uWepKeyLength;
+ pTransmitKey->dwTSC47_16 = pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16;
+ pTransmitKey->wTSC15_0 = pMgmt->sNodeDBTable[uNodeIndex].wTSC15_0;
+ memcpy(pTransmitKey->abyKey,
+ &pMgmt->sNodeDBTable[uNodeIndex].abyWepKey[0],
+ pTransmitKey->uKeyLength
+);
+ }
+ }
+
+ uMACfragNum = cbGetFragCount(pDevice, pTransmitKey, cbFrameBodySize, &pDevice->sTxEthHeader);
+
+ if (uMACfragNum > AVAIL_TD(pDevice, TYPE_AC0DMA)) {
+ return false;
+ }
+ byPktType = (unsigned char)pDevice->byPacketType;
+
+ if (pDevice->bFixRate) {
+ if (pDevice->eCurrentPHYType == PHY_TYPE_11B) {
+ if (pDevice->uConnectionRate >= RATE_11M) {
+ pDevice->wCurrentRate = RATE_11M;
+ } else {
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ } else {
+ if ((pDevice->eCurrentPHYType == PHY_TYPE_11A) &&
+ (pDevice->uConnectionRate <= RATE_6M)) {
+ pDevice->wCurrentRate = RATE_6M;
+ } else {
+ if (pDevice->uConnectionRate >= RATE_54M)
+ pDevice->wCurrentRate = RATE_54M;
+ else
+ pDevice->wCurrentRate = (unsigned short)pDevice->uConnectionRate;
+ }
+ }
+ } else {
+ pDevice->wCurrentRate = pDevice->pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate;
+ }
+
+ if (pDevice->wCurrentRate <= RATE_11M)
+ byPktType = PK_TYPE_11B;
+
+ vGenerateFIFOHeader(pDevice, byPktType, pDevice->pbyTmpBuff, bNeedEncryption,
+ cbFrameBodySize, TYPE_AC0DMA, pHeadTD,
+ &pDevice->sTxEthHeader, pbySkbData, pTransmitKey, uNodeIndex,
+ &uMACfragNum,
+ &cbHeaderSize
+);
+
+ if (MACbIsRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PS)) {
+ // Disable PS
+ MACbPSWakeup(pDevice->PortOffset);
+ }
+
+ pDevice->bPWBitOn = false;
+
+ pLastTD = pHeadTD;
+ for (ii = 0; ii < uMACfragNum; ii++) {
+ // Poll Transmit the adapter
+ wmb();
+ pHeadTD->m_td0TD0.f1Owner = OWNED_BY_NIC;
+ wmb();
+ if (ii == (uMACfragNum - 1))
+ pLastTD = pHeadTD;
+ pHeadTD = pHeadTD->next;
+ }
+
+ pLastTD->pTDInfo->skb = 0;
+ pLastTD->pTDInfo->byFlags = 0;
+
+ pDevice->apCurrTD[TYPE_AC0DMA] = pHeadTD;
+
+ MACvTransmitAC0(pDevice->PortOffset);
+
+ return true;
}
-
-
-
diff --git a/drivers/staging/vt6655/wroute.h b/drivers/staging/vt6655/wroute.h
index 34f9e43a6cc4..5ecc190ae775 100644
--- a/drivers/staging/vt6655/wroute.h
+++ b/drivers/staging/vt6655/wroute.h
@@ -39,9 +39,6 @@
/*--------------------- Export Functions --------------------------*/
-bool ROUTEbRelay (PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex);
+bool ROUTEbRelay(PSDevice pDevice, unsigned char *pbySkbData, unsigned int uDataLen, unsigned int uNodeIndex);
#endif // __WROUTE_H__
-
-
-
diff --git a/drivers/staging/vt6656/80211hdr.h b/drivers/staging/vt6656/80211hdr.h
index b87d5434077a..000304ffad6c 100644
--- a/drivers/staging/vt6656/80211hdr.h
+++ b/drivers/staging/vt6656/80211hdr.h
@@ -28,10 +28,6 @@
#ifndef __80211HDR_H__
#define __80211HDR_H__
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
/* bit type */
#define BIT0 0x00000001
#define BIT1 0x00000002
@@ -155,22 +151,22 @@
#ifdef __BIG_ENDIAN
/* GET & SET Frame Control bit */
-#define WLAN_GET_FC_PRVER(n) ((((WORD)(n) >> 8) & (BIT0 | BIT1))
-#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n) >> 8) & (BIT2 | BIT3)) >> 2)
-#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n) >> 8) \
+#define WLAN_GET_FC_PRVER(n) ((((u16)(n) >> 8) & (BIT0 | BIT1))
+#define WLAN_GET_FC_FTYPE(n) ((((u16)(n) >> 8) & (BIT2 | BIT3)) >> 2)
+#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n) >> 8) \
& (BIT4|BIT5|BIT6|BIT7)) >> 4)
-#define WLAN_GET_FC_TODS(n) ((((WORD)(n) << 8) & (BIT8)) >> 8)
-#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n) << 8) & (BIT9)) >> 9)
-#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n) << 8) & (BIT10)) >> 10)
-#define WLAN_GET_FC_RETRY(n) ((((WORD)(n) << 8) & (BIT11)) >> 11)
-#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n) << 8) & (BIT12)) >> 12)
-#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n) << 8) & (BIT13)) >> 13)
-#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n) << 8) & (BIT14)) >> 14)
-#define WLAN_GET_FC_ORDER(n) ((((WORD)(n) << 8) & (BIT15)) >> 15)
+#define WLAN_GET_FC_TODS(n) ((((u16)(n) << 8) & (BIT8)) >> 8)
+#define WLAN_GET_FC_FROMDS(n) ((((u16)(n) << 8) & (BIT9)) >> 9)
+#define WLAN_GET_FC_MOREFRAG(n) ((((u16)(n) << 8) & (BIT10)) >> 10)
+#define WLAN_GET_FC_RETRY(n) ((((u16)(n) << 8) & (BIT11)) >> 11)
+#define WLAN_GET_FC_PWRMGT(n) ((((u16)(n) << 8) & (BIT12)) >> 12)
+#define WLAN_GET_FC_MOREDATA(n) ((((u16)(n) << 8) & (BIT13)) >> 13)
+#define WLAN_GET_FC_ISWEP(n) ((((u16)(n) << 8) & (BIT14)) >> 14)
+#define WLAN_GET_FC_ORDER(n) ((((u16)(n) << 8) & (BIT15)) >> 15)
/* Sequence Field bit */
-#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3))
-#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n) >> 8) \
+#define WLAN_GET_SEQ_FRGNUM(n) (((u16)(n) >> 8) & (BIT0|BIT1|BIT2|BIT3))
+#define WLAN_GET_SEQ_SEQNUM(n) ((((u16)(n) >> 8) \
& (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
/* Capability Field bit */
@@ -190,21 +186,21 @@
#else
/* GET & SET Frame Control bit */
-#define WLAN_GET_FC_PRVER(n) (((WORD)(n)) & (BIT0 | BIT1))
-#define WLAN_GET_FC_FTYPE(n) ((((WORD)(n)) & (BIT2 | BIT3)) >> 2)
-#define WLAN_GET_FC_FSTYPE(n) ((((WORD)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
-#define WLAN_GET_FC_TODS(n) ((((WORD)(n)) & (BIT8)) >> 8)
-#define WLAN_GET_FC_FROMDS(n) ((((WORD)(n)) & (BIT9)) >> 9)
-#define WLAN_GET_FC_MOREFRAG(n) ((((WORD)(n)) & (BIT10)) >> 10)
-#define WLAN_GET_FC_RETRY(n) ((((WORD)(n)) & (BIT11)) >> 11)
-#define WLAN_GET_FC_PWRMGT(n) ((((WORD)(n)) & (BIT12)) >> 12)
-#define WLAN_GET_FC_MOREDATA(n) ((((WORD)(n)) & (BIT13)) >> 13)
-#define WLAN_GET_FC_ISWEP(n) ((((WORD)(n)) & (BIT14)) >> 14)
-#define WLAN_GET_FC_ORDER(n) ((((WORD)(n)) & (BIT15)) >> 15)
+#define WLAN_GET_FC_PRVER(n) (((u16)(n)) & (BIT0 | BIT1))
+#define WLAN_GET_FC_FTYPE(n) ((((u16)(n)) & (BIT2 | BIT3)) >> 2)
+#define WLAN_GET_FC_FSTYPE(n) ((((u16)(n)) & (BIT4|BIT5|BIT6|BIT7)) >> 4)
+#define WLAN_GET_FC_TODS(n) ((((u16)(n)) & (BIT8)) >> 8)
+#define WLAN_GET_FC_FROMDS(n) ((((u16)(n)) & (BIT9)) >> 9)
+#define WLAN_GET_FC_MOREFRAG(n) ((((u16)(n)) & (BIT10)) >> 10)
+#define WLAN_GET_FC_RETRY(n) ((((u16)(n)) & (BIT11)) >> 11)
+#define WLAN_GET_FC_PWRMGT(n) ((((u16)(n)) & (BIT12)) >> 12)
+#define WLAN_GET_FC_MOREDATA(n) ((((u16)(n)) & (BIT13)) >> 13)
+#define WLAN_GET_FC_ISWEP(n) ((((u16)(n)) & (BIT14)) >> 14)
+#define WLAN_GET_FC_ORDER(n) ((((u16)(n)) & (BIT15)) >> 15)
/* Sequence Field bit */
-#define WLAN_GET_SEQ_FRGNUM(n) (((WORD)(n)) & (BIT0|BIT1|BIT2|BIT3))
-#define WLAN_GET_SEQ_SEQNUM(n) ((((WORD)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
+#define WLAN_GET_SEQ_FRGNUM(n) (((u16)(n)) & (BIT0|BIT1|BIT2|BIT3))
+#define WLAN_GET_SEQ_SEQNUM(n) ((((u16)(n)) & (~(BIT0|BIT1|BIT2|BIT3))) >> 4)
/* Capability Field bit */
#define WLAN_GET_CAP_INFO_ESS(n) ((n) & BIT0)
@@ -235,20 +231,20 @@
#define WLAN_SET_CAP_INFO_DSSSOFDM(n) ((n) << 13)
#define WLAN_SET_CAP_INFO_GRPACK(n) ((n) << 14)
-#define WLAN_SET_FC_PRVER(n) ((WORD)(n))
-#define WLAN_SET_FC_FTYPE(n) (((WORD)(n)) << 2)
-#define WLAN_SET_FC_FSTYPE(n) (((WORD)(n)) << 4)
-#define WLAN_SET_FC_TODS(n) (((WORD)(n)) << 8)
-#define WLAN_SET_FC_FROMDS(n) (((WORD)(n)) << 9)
-#define WLAN_SET_FC_MOREFRAG(n) (((WORD)(n)) << 10)
-#define WLAN_SET_FC_RETRY(n) (((WORD)(n)) << 11)
-#define WLAN_SET_FC_PWRMGT(n) (((WORD)(n)) << 12)
-#define WLAN_SET_FC_MOREDATA(n) (((WORD)(n)) << 13)
-#define WLAN_SET_FC_ISWEP(n) (((WORD)(n)) << 14)
-#define WLAN_SET_FC_ORDER(n) (((WORD)(n)) << 15)
-
-#define WLAN_SET_SEQ_FRGNUM(n) ((WORD)(n))
-#define WLAN_SET_SEQ_SEQNUM(n) (((WORD)(n)) << 4)
+#define WLAN_SET_FC_PRVER(n) ((u16)(n))
+#define WLAN_SET_FC_FTYPE(n) (((u16)(n)) << 2)
+#define WLAN_SET_FC_FSTYPE(n) (((u16)(n)) << 4)
+#define WLAN_SET_FC_TODS(n) (((u16)(n)) << 8)
+#define WLAN_SET_FC_FROMDS(n) (((u16)(n)) << 9)
+#define WLAN_SET_FC_MOREFRAG(n) (((u16)(n)) << 10)
+#define WLAN_SET_FC_RETRY(n) (((u16)(n)) << 11)
+#define WLAN_SET_FC_PWRMGT(n) (((u16)(n)) << 12)
+#define WLAN_SET_FC_MOREDATA(n) (((u16)(n)) << 13)
+#define WLAN_SET_FC_ISWEP(n) (((u16)(n)) << 14)
+#define WLAN_SET_FC_ORDER(n) (((u16)(n)) << 15)
+
+#define WLAN_SET_SEQ_FRGNUM(n) ((u16)(n))
+#define WLAN_SET_SEQ_SEQNUM(n) (((u16)(n)) << 4)
/* ERP Field bit */
@@ -269,50 +265,50 @@
#define WLAN_MGMT_GET_TIM_OFFSET(b) (((b) & ~BIT0) >> 1)
/* 3-Addr & 4-Addr */
-#define WLAN_HDR_A3_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR3_LEN)
-#define WLAN_HDR_A4_DATA_PTR(p) (((PBYTE)(p)) + WLAN_HDR_ADDR4_LEN)
+#define WLAN_HDR_A3_DATA_PTR(p) (((u8 *)(p)) + WLAN_HDR_ADDR3_LEN)
+#define WLAN_HDR_A4_DATA_PTR(p) (((u8 *)(p)) + WLAN_HDR_ADDR4_LEN)
/* IEEE ADDR */
#define IEEE_ADDR_UNIVERSAL 0x02
#define IEEE_ADDR_GROUP 0x01
typedef struct {
- BYTE abyAddr[6];
+ u8 abyAddr[6];
} IEEE_ADDR, *PIEEE_ADDR;
/* 802.11 Header Format */
typedef struct tagWLAN_80211HDR_A2 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
+ u16 wFrameCtl;
+ u16 wDurationID;
+ u8 abyAddr1[WLAN_ADDR_LEN];
+ u8 abyAddr2[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A2, *PWLAN_80211HDR_A2;
typedef struct tagWLAN_80211HDR_A3 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
- BYTE abyAddr3[WLAN_ADDR_LEN];
- WORD wSeqCtl;
+ u16 wFrameCtl;
+ u16 wDurationID;
+ u8 abyAddr1[WLAN_ADDR_LEN];
+ u8 abyAddr2[WLAN_ADDR_LEN];
+ u8 abyAddr3[WLAN_ADDR_LEN];
+ u16 wSeqCtl;
} __attribute__ ((__packed__))
WLAN_80211HDR_A3, *PWLAN_80211HDR_A3;
typedef struct tagWLAN_80211HDR_A4 {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[WLAN_ADDR_LEN];
- BYTE abyAddr2[WLAN_ADDR_LEN];
- BYTE abyAddr3[WLAN_ADDR_LEN];
- WORD wSeqCtl;
- BYTE abyAddr4[WLAN_ADDR_LEN];
+ u16 wFrameCtl;
+ u16 wDurationID;
+ u8 abyAddr1[WLAN_ADDR_LEN];
+ u8 abyAddr2[WLAN_ADDR_LEN];
+ u8 abyAddr3[WLAN_ADDR_LEN];
+ u16 wSeqCtl;
+ u8 abyAddr4[WLAN_ADDR_LEN];
} __attribute__ ((__packed__))
WLAN_80211HDR_A4, *PWLAN_80211HDR_A4;
@@ -325,10 +321,4 @@ typedef union tagUWLAN_80211HDR {
} UWLAN_80211HDR, *PUWLAN_80211HDR;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
#endif /* __80211HDR_H__ */
diff --git a/drivers/staging/vt6656/80211mgr.c b/drivers/staging/vt6656/80211mgr.c
index 534d490539b6..61edb51f3836 100644
--- a/drivers/staging/vt6656/80211mgr.c
+++ b/drivers/staging/vt6656/80211mgr.c
@@ -27,8 +27,6 @@
* Functions:
* vMgrEncodeBeacon - Encode the Beacon frame
* vMgrDecodeBeacon - Decode the Beacon frame
- * vMgrEncodeIBSSATIM - Encode the IBSS ATIM frame
- * vMgrDecodeIBSSATIM - Decode the IBSS ATIM frame
* vMgrEncodeDisassociation - Encode the Disassociation frame
* vMgrDecodeDisassociation - Decode the Disassociation frame
* vMgrEncodeAssocRequest - Encode the Association request frame
@@ -46,7 +44,6 @@
* vMgrEncodeDeauthen - Encode the DeAuthentication frame
* vMgrDecodeDeauthen - Decode the DeAuthentication frame
* vMgrEncodeReassocResponse - Encode the Reassociation response frame
- * vMgrDecodeReassocResponse - Decode the Reassociation response frame
*
* Revision History:
*
@@ -59,25 +56,8 @@
#include "80211hdr.h"
#include "wpa.h"
-/*--------------------- Static Definitions -------------------------*/
-
-
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
static int msglevel = MSG_LEVEL_INFO;
/*static int msglevel =MSG_LEVEL_DEBUG;*/
-/*--------------------- Static Functions --------------------------*/
-
-
-
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
/*+
*
@@ -100,9 +80,9 @@ vMgrEncodeBeacon(
pFrame->pqwTimestamp =
(u64 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_CAPINFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_BEACON_OFF_SSID;
@@ -121,7 +101,6 @@ vMgrEncodeBeacon(
*
-*/
-
void
vMgrDecodeBeacon(
PWLAN_FR_BEACON pFrame
@@ -135,15 +114,15 @@ vMgrDecodeBeacon(
pFrame->pqwTimestamp =
(u64 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
WLAN_BEACON_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_BEACON_OFF_CAPINFO);
/* Information elements */
- pItem = (PWLAN_IE)((PBYTE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ pItem = (PWLAN_IE)((u8 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)))
+ WLAN_BEACON_OFF_SSID);
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -224,53 +203,10 @@ vMgrDecodeBeacon(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
}
}
-
-/*+
- *
- * Routine Description:
- * Encode IBSS ATIM
- *
- *
- * Return Value:
- * None.
- *
--*/
-
-
-void
-vMgrEncodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- )
-{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
- pFrame->len = WLAN_HDR_ADDR3_LEN;
-}
-
-
-/*+
- *
- * Routine Description:
- * Decode IBSS ATIM
- *
- *
- * Return Value:
- * None.
- *
--*/
-
-void
-vMgrDecodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- )
-{
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-}
-
-
/*+
*
* Routine Description:
@@ -289,14 +225,12 @@ vMgrEncodeDisassociation(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
/* Fixed Fields */
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DISASSOC_OFF_REASON + sizeof(*(pFrame->pwReason));
}
-
/*+
*
* Routine Description:
@@ -316,7 +250,7 @@ vMgrDecodeDisassociation(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DISASSOC_OFF_REASON);
}
@@ -331,7 +265,6 @@ vMgrDecodeDisassociation(
*
-*/
-
void
vMgrEncodeAssocRequest(
PWLAN_FR_ASSOCREQ pFrame
@@ -339,14 +272,13 @@ vMgrEncodeAssocRequest(
{
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCREQ_OFF_LISTEN_INT + sizeof(*(pFrame->pwListenInterval));
}
-
/*+
*
* Routine Description: (AP)
@@ -367,16 +299,16 @@ vMgrDecodeAssocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_LISTEN_INT);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCREQ_OFF_SSID);
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
if (pFrame->pSSID == NULL)
@@ -407,7 +339,7 @@ vMgrDecodeAssocRequest(
pItem->byElementID);
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
}
}
@@ -430,17 +362,16 @@ vMgrEncodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_AID);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_ASSOCRESP_OFF_AID
+ sizeof(*(pFrame->pwAid));
}
-
/*+
*
* Routine Description:
@@ -462,11 +393,11 @@ vMgrDecodeAssocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_ASSOCRESP_OFF_AID);
/* Information elements */
@@ -474,16 +405,15 @@ vMgrDecodeAssocResponse(
+ WLAN_ASSOCRESP_OFF_SUPP_RATES);
pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
+ if ((((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES)) {
pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "pFrame->pExtSuppRates=[%p].\n", pItem);
} else
pFrame->pExtSuppRates = NULL;
}
-
/*+
*
* Routine Description:
@@ -503,16 +433,15 @@ vMgrEncodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CURR_AP);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCREQ_OFF_CURR_AP + sizeof(*(pFrame->pAddrCurrAP));
}
-
/*+
*
* Routine Description: (AP)
@@ -524,7 +453,6 @@ vMgrEncodeReassocRequest(
*
-*/
-
void
vMgrDecodeReassocRequest(
PWLAN_FR_REASSOCREQ pFrame
@@ -534,9 +462,9 @@ vMgrDecodeReassocRequest(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CAP_INFO);
- pFrame->pwListenInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwListenInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_LISTEN_INT);
pFrame->pAddrCurrAP = (PIEEE_ADDR)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_CURR_AP);
@@ -545,7 +473,7 @@ vMgrDecodeReassocRequest(
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCREQ_OFF_SSID);
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -576,12 +504,10 @@ vMgrDecodeReassocRequest(
pItem->byElementID);
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
}
}
-
-
/*+
*
* Routine Description:
@@ -593,7 +519,6 @@ vMgrDecodeReassocRequest(
*
-*/
-
void
vMgrEncodeProbeRequest(
PWLAN_FR_PROBEREQ pFrame
@@ -626,7 +551,7 @@ vMgrDecodeProbeRequest(
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)));
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
@@ -649,11 +574,10 @@ vMgrDecodeProbeRequest(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
}
}
-
/*+
*
* Routine Description:
@@ -665,7 +589,6 @@ vMgrDecodeProbeRequest(
*
-*/
-
void
vMgrEncodeProbeResponse(
PWLAN_FR_PROBERESP pFrame
@@ -677,17 +600,15 @@ vMgrEncodeProbeResponse(
pFrame->pqwTimestamp =
(u64 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_CAP_INFO);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_PROBERESP_OFF_CAP_INFO +
sizeof(*(pFrame->pwCapInfo));
}
-
-
/*+
*
* Routine Description:
@@ -706,23 +627,22 @@ vMgrDecodeProbeResponse(
{
PWLAN_IE pItem;
-
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
pFrame->pqwTimestamp =
(u64 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3)) +
WLAN_PROBERESP_OFF_TS);
- pFrame->pwBeaconInterval = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwBeaconInterval = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_BCN_INT);
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_CAP_INFO);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_PROBERESP_OFF_SSID);
- while (((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) {
+ while (((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) {
switch (pItem->byElementID) {
case WLAN_EID_SSID:
if (pFrame->pSSID == NULL)
@@ -796,11 +716,10 @@ vMgrDecodeProbeResponse(
break;
}
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
+ pItem = (PWLAN_IE)(((u8 *)pItem) + 2 + pItem->len);
}
}
-
/*+
*
* Routine Description:
@@ -820,16 +739,15 @@ vMgrEncodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthAlgorithm = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthSequence = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_AUTHEN_OFF_STATUS + sizeof(*(pFrame->pwStatus));
}
-
/*+
*
* Routine Description:
@@ -851,22 +769,21 @@ vMgrDecodeAuthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwAuthAlgorithm = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthAlgorithm = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_ALG);
- pFrame->pwAuthSequence = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAuthSequence = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_AUTH_SEQ);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_STATUS);
/* Information elements */
pItem = (PWLAN_IE)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_AUTHEN_OFF_CHALLENGE);
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE))
+ if ((((u8 *)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_CHALLENGE))
pFrame->pChallenge = (PWLAN_IE_CHALLENGE)pItem;
}
-
/*+
*
* Routine Description:
@@ -886,12 +803,11 @@ vMgrEncodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_DEAUTHEN_OFF_REASON + sizeof(*(pFrame->pwReason));
}
-
/*+
*
* Routine Description:
@@ -911,11 +827,10 @@ vMgrDecodeDeauthen(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwReason = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwReason = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_DEAUTHEN_OFF_REASON);
}
-
/*+
*
* Routine Description: (AP)
@@ -935,53 +850,12 @@ vMgrEncodeReassocResponse(
pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
/* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwCapInfo = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwStatus = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ pFrame->pwAid = (u16 *)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
+ WLAN_REASSOCRESP_OFF_AID);
pFrame->len = WLAN_HDR_ADDR3_LEN + WLAN_REASSOCRESP_OFF_AID + sizeof(*(pFrame->pwAid));
}
-
-
-/*+
- *
- * Routine Description:
- * Decode Reassociation Response
- *
- *
- * Return Value:
- * None.
- *
--*/
-
-
-void
-vMgrDecodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- )
-{
- PWLAN_IE pItem;
-
- pFrame->pHdr = (PUWLAN_80211HDR)pFrame->pBuf;
-
- /* Fixed Fields */
- pFrame->pwCapInfo = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_CAP_INFO);
- pFrame->pwStatus = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_STATUS);
- pFrame->pwAid = (PWORD)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_AID);
-
- /* Information elements */
- pFrame->pSuppRates = (PWLAN_IE_SUPP_RATES)(WLAN_HDR_A3_DATA_PTR(&(pFrame->pHdr->sA3))
- + WLAN_REASSOCRESP_OFF_SUPP_RATES);
-
- pItem = (PWLAN_IE)(pFrame->pSuppRates);
- pItem = (PWLAN_IE)(((PBYTE)pItem) + 2 + pItem->len);
-
- if ((((PBYTE)pItem) < (pFrame->pBuf + pFrame->len)) && (pItem->byElementID == WLAN_EID_EXTSUPP_RATES))
- pFrame->pExtSuppRates = (PWLAN_IE_SUPP_RATES)pItem;
-}
diff --git a/drivers/staging/vt6656/80211mgr.h b/drivers/staging/vt6656/80211mgr.h
index f8e16d8989ea..39cde1a0b66c 100644
--- a/drivers/staging/vt6656/80211mgr.h
+++ b/drivers/staging/vt6656/80211mgr.h
@@ -31,11 +31,8 @@
#ifndef __80211MGR_H__
#define __80211MGR_H__
-#include "ttype.h"
#include "80211hdr.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define WLAN_MIN_ARRAY 1
/* Information Element ID value */
@@ -213,192 +210,186 @@
#define MEASURE_MODE_INCAPABLE 0x02
#define MEASURE_MODE_REFUSED 0x04
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
/* Information Element types */
#pragma pack(1)
typedef struct tagWLAN_IE {
- BYTE byElementID;
- BYTE len;
+ u8 byElementID;
+ u8 len;
} __attribute__ ((__packed__))
WLAN_IE, *PWLAN_IE;
/* Service Set IDentity (SSID) */
#pragma pack(1)
typedef struct tagWLAN_IE_SSID {
- BYTE byElementID;
- BYTE len;
- BYTE abySSID[1];
+ u8 byElementID;
+ u8 len;
+ u8 abySSID[1];
} __attribute__ ((__packed__))
WLAN_IE_SSID, *PWLAN_IE_SSID;
/* Supported Rates */
#pragma pack(1)
typedef struct tagWLAN_IE_SUPP_RATES {
- BYTE byElementID;
- BYTE len;
- BYTE abyRates[1];
+ u8 byElementID;
+ u8 len;
+ u8 abyRates[1];
} __attribute__ ((__packed__))
WLAN_IE_SUPP_RATES, *PWLAN_IE_SUPP_RATES;
/* FH Parameter Set */
#pragma pack(1)
typedef struct _WLAN_IE_FH_PARMS {
- BYTE byElementID;
- BYTE len;
- WORD wDwellTime;
- BYTE byHopSet;
- BYTE byHopPattern;
- BYTE byHopIndex;
+ u8 byElementID;
+ u8 len;
+ u16 wDwellTime;
+ u8 byHopSet;
+ u8 byHopPattern;
+ u8 byHopIndex;
} WLAN_IE_FH_PARMS, *PWLAN_IE_FH_PARMS;
/* DS Parameter Set */
#pragma pack(1)
typedef struct tagWLAN_IE_DS_PARMS {
- BYTE byElementID;
- BYTE len;
- BYTE byCurrChannel;
+ u8 byElementID;
+ u8 len;
+ u8 byCurrChannel;
} __attribute__ ((__packed__))
WLAN_IE_DS_PARMS, *PWLAN_IE_DS_PARMS;
/* CF Parameter Set */
#pragma pack(1)
typedef struct tagWLAN_IE_CF_PARMS {
- BYTE byElementID;
- BYTE len;
- BYTE byCFPCount;
- BYTE byCFPPeriod;
- WORD wCFPMaxDuration;
- WORD wCFPDurRemaining;
+ u8 byElementID;
+ u8 len;
+ u8 byCFPCount;
+ u8 byCFPPeriod;
+ u16 wCFPMaxDuration;
+ u16 wCFPDurRemaining;
} __attribute__ ((__packed__))
WLAN_IE_CF_PARMS, *PWLAN_IE_CF_PARMS;
/* TIM */
#pragma pack(1)
typedef struct tagWLAN_IE_TIM {
- BYTE byElementID;
- BYTE len;
- BYTE byDTIMCount;
- BYTE byDTIMPeriod;
- BYTE byBitMapCtl;
- BYTE byVirtBitMap[1];
+ u8 byElementID;
+ u8 len;
+ u8 byDTIMCount;
+ u8 byDTIMPeriod;
+ u8 byBitMapCtl;
+ u8 byVirtBitMap[1];
} __attribute__ ((__packed__))
WLAN_IE_TIM, *PWLAN_IE_TIM;
/* IBSS Parameter Set */
#pragma pack(1)
typedef struct tagWLAN_IE_IBSS_PARMS {
- BYTE byElementID;
- BYTE len;
- WORD wATIMWindow;
+ u8 byElementID;
+ u8 len;
+ u16 wATIMWindow;
} __attribute__ ((__packed__))
WLAN_IE_IBSS_PARMS, *PWLAN_IE_IBSS_PARMS;
/* Challenge Text */
#pragma pack(1)
typedef struct tagWLAN_IE_CHALLENGE {
- BYTE byElementID;
- BYTE len;
- BYTE abyChallenge[1];
+ u8 byElementID;
+ u8 len;
+ u8 abyChallenge[1];
} __attribute__ ((__packed__))
WLAN_IE_CHALLENGE, *PWLAN_IE_CHALLENGE;
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_EXT {
- BYTE byElementID;
- BYTE len;
- BYTE abyOUI[4];
- WORD wVersion;
- BYTE abyMulticast[4];
- WORD wPKCount;
+ u8 byElementID;
+ u8 len;
+ u8 abyOUI[4];
+ u16 wVersion;
+ u8 abyMulticast[4];
+ u16 wPKCount;
struct {
- BYTE abyOUI[4];
+ u8 abyOUI[4];
} PKSList[1];
/* the rest is variable so need to overlay ieauth structure */
} WLAN_IE_RSN_EXT, *PWLAN_IE_RSN_EXT;
#pragma pack(1)
typedef struct tagWLAN_IE_RSN_AUTH {
- WORD wAuthCount;
+ u16 wAuthCount;
struct {
- BYTE abyOUI[4];
+ u8 abyOUI[4];
} AuthKSList[1];
} WLAN_IE_RSN_AUTH, *PWLAN_IE_RSN_AUTH;
/* RSN Identity */
#pragma pack(1)
typedef struct tagWLAN_IE_RSN {
- BYTE byElementID;
- BYTE len;
- WORD wVersion;
- BYTE abyRSN[WLAN_MIN_ARRAY];
+ u8 byElementID;
+ u8 len;
+ u16 wVersion;
+ u8 abyRSN[WLAN_MIN_ARRAY];
} WLAN_IE_RSN, *PWLAN_IE_RSN;
/* CCX Identity DavidWang */
#pragma pack(1)
typedef struct tagWLAN_IE_CCX {
-BYTE byElementID;
-BYTE len;
-BYTE abyCCX[30];
+u8 byElementID;
+u8 len;
+u8 abyCCX[30];
} WLAN_IE_CCX, *PWLAN_IE_CCX;
#pragma pack(1)
typedef struct tagWLAN_IE_CCX_IP {
-BYTE byElementID;
-BYTE len;
-BYTE abyCCXOUI[4];
-BYTE abyCCXIP[4];
-BYTE abyCCXREV[2];
+u8 byElementID;
+u8 len;
+u8 abyCCXOUI[4];
+u8 abyCCXIP[4];
+u8 abyCCXREV[2];
} WLAN_IE_CCX_IP, *PWLAN_IE_CCX_IP;
#pragma pack(1)
typedef struct tagWLAN_IE_CCX_Ver {
-BYTE byElementID;
-BYTE len;
-BYTE abyCCXVer[5];
+u8 byElementID;
+u8 len;
+u8 abyCCXVer[5];
} WLAN_IE_CCX_Ver, *PWLAN_IE_CCX_Ver;
/* ERP */
#pragma pack(1)
typedef struct tagWLAN_IE_ERP {
- BYTE byElementID;
- BYTE len;
- BYTE byContext;
+ u8 byElementID;
+ u8 len;
+ u8 byContext;
} __attribute__ ((__packed__))
WLAN_IE_ERP, *PWLAN_IE_ERP;
#pragma pack(1)
typedef struct _MEASEURE_REQ {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
+ u8 byChannel;
+ u8 abyStartTime[8];
+ u8 abyDuration[2];
} MEASEURE_REQ, *PMEASEURE_REQ,
MEASEURE_REQ_BASIC, *PMEASEURE_REQ_BASIC,
MEASEURE_REQ_CCA, *PMEASEURE_REQ_CCA,
MEASEURE_REQ_RPI, *PMEASEURE_REQ_RPI;
typedef struct _MEASEURE_REP_BASIC {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE byMap;
+ u8 byChannel;
+ u8 abyStartTime[8];
+ u8 abyDuration[2];
+ u8 byMap;
} MEASEURE_REP_BASIC, *PMEASEURE_REP_BASIC;
typedef struct _MEASEURE_REP_CCA {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE byCCABusyFraction;
+ u8 byChannel;
+ u8 abyStartTime[8];
+ u8 abyDuration[2];
+ u8 byCCABusyFraction;
} MEASEURE_REP_CCA, *PMEASEURE_REP_CCA;
typedef struct _MEASEURE_REP_RPI {
- BYTE byChannel;
- BYTE abyStartTime[8];
- BYTE abyDuration[2];
- BYTE abyRPIdensity[8];
+ u8 byChannel;
+ u8 abyStartTime[8];
+ u8 abyDuration[2];
+ u8 abyRPIdensity[8];
} MEASEURE_REP_RPI, *PMEASEURE_REP_RPI;
typedef union _MEASEURE_REP {
@@ -410,85 +401,84 @@ typedef union _MEASEURE_REP {
} MEASEURE_REP, *PMEASEURE_REP;
typedef struct _WLAN_IE_MEASURE_REQ {
- BYTE byElementID;
- BYTE len;
- BYTE byToken;
- BYTE byMode;
- BYTE byType;
+ u8 byElementID;
+ u8 len;
+ u8 byToken;
+ u8 byMode;
+ u8 byType;
MEASEURE_REQ sReq;
} WLAN_IE_MEASURE_REQ, *PWLAN_IE_MEASURE_REQ;
typedef struct _WLAN_IE_MEASURE_REP {
- BYTE byElementID;
- BYTE len;
- BYTE byToken;
- BYTE byMode;
- BYTE byType;
+ u8 byElementID;
+ u8 len;
+ u8 byToken;
+ u8 byMode;
+ u8 byType;
MEASEURE_REP sRep;
} WLAN_IE_MEASURE_REP, *PWLAN_IE_MEASURE_REP;
typedef struct _WLAN_IE_CH_SW {
- BYTE byElementID;
- BYTE len;
- BYTE byMode;
- BYTE byChannel;
- BYTE byCount;
+ u8 byElementID;
+ u8 len;
+ u8 byMode;
+ u8 byChannel;
+ u8 byCount;
} WLAN_IE_CH_SW, *PWLAN_IE_CH_SW;
typedef struct _WLAN_IE_QUIET {
- BYTE byElementID;
- BYTE len;
- BYTE byQuietCount;
- BYTE byQuietPeriod;
- BYTE abyQuietDuration[2];
- BYTE abyQuietOffset[2];
+ u8 byElementID;
+ u8 len;
+ u8 byQuietCount;
+ u8 byQuietPeriod;
+ u8 abyQuietDuration[2];
+ u8 abyQuietOffset[2];
} WLAN_IE_QUIET, *PWLAN_IE_QUIET;
typedef struct _WLAN_IE_COUNTRY {
- BYTE byElementID;
- BYTE len;
- BYTE abyCountryString[3];
- BYTE abyCountryInfo[3];
+ u8 byElementID;
+ u8 len;
+ u8 abyCountryString[3];
+ u8 abyCountryInfo[3];
} WLAN_IE_COUNTRY, *PWLAN_IE_COUNTRY;
typedef struct _WLAN_IE_PW_CONST {
- BYTE byElementID;
- BYTE len;
- BYTE byPower;
+ u8 byElementID;
+ u8 len;
+ u8 byPower;
} WLAN_IE_PW_CONST, *PWLAN_IE_PW_CONST;
typedef struct _WLAN_IE_PW_CAP {
- BYTE byElementID;
- BYTE len;
- BYTE byMinPower;
- BYTE byMaxPower;
+ u8 byElementID;
+ u8 len;
+ u8 byMinPower;
+ u8 byMaxPower;
} WLAN_IE_PW_CAP, *PWLAN_IE_PW_CAP;
typedef struct _WLAN_IE_SUPP_CH {
- BYTE byElementID;
- BYTE len;
- BYTE abyChannelTuple[2];
+ u8 byElementID;
+ u8 len;
+ u8 abyChannelTuple[2];
} WLAN_IE_SUPP_CH, *PWLAN_IE_SUPP_CH;
typedef struct _WLAN_IE_TPC_REQ {
- BYTE byElementID;
- BYTE len;
+ u8 byElementID;
+ u8 len;
} WLAN_IE_TPC_REQ, *PWLAN_IE_TPC_REQ;
typedef struct _WLAN_IE_TPC_REP {
- BYTE byElementID;
- BYTE len;
- BYTE byTxPower;
- BYTE byLinkMargin;
+ u8 byElementID;
+ u8 len;
+ u8 byTxPower;
+ u8 byLinkMargin;
} WLAN_IE_TPC_REP, *PWLAN_IE_TPC_REP;
-
typedef struct _WLAN_IE_IBSS_DFS {
- BYTE byElementID;
- BYTE len;
- BYTE abyDFSOwner[6];
- BYTE byDFSRecovery;
- BYTE abyChannelMap[2];
+ u8 byElementID;
+ u8 len;
+ u8 abyDFSOwner[6];
+ u8 byDFSRecovery;
+ u8 abyChannelMap[2];
} WLAN_IE_IBSS_DFS, *PWLAN_IE_IBSS_DFS;
#pragma pack()
@@ -500,7 +490,7 @@ typedef struct tagWLAN_FR_MGMT {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
} WLAN_FR_MGMT, *PWLAN_FR_MGMT;
@@ -510,12 +500,12 @@ typedef struct tagWLAN_FR_BEACON {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
u64 *pqwTimestamp;
- PWORD pwBeaconInterval;
- PWORD pwCapInfo;
+ u16 * pwBeaconInterval;
+ u16 * pwCapInfo;
/* info elements */
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -541,7 +531,7 @@ typedef struct tagWLAN_FR_IBSSATIM {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
@@ -555,10 +545,10 @@ typedef struct tagWLAN_FR_DISASSOC {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwReason;
+ u16 * pwReason;
/* info elements */
} WLAN_FR_DISASSOC, *PWLAN_FR_DISASSOC;
@@ -568,11 +558,11 @@ typedef struct tagWLAN_FR_ASSOCREQ {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwCapInfo;
- PWORD pwListenInterval;
+ u16 * pwCapInfo;
+ u16 * pwListenInterval;
/* info elements */
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -592,12 +582,12 @@ typedef struct tagWLAN_FR_ASSOCRESP {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwCapInfo;
- PWORD pwStatus;
- PWORD pwAid;
+ u16 * pwCapInfo;
+ u16 * pwStatus;
+ u16 * pwAid;
/* info elements */
PWLAN_IE_SUPP_RATES pSuppRates;
PWLAN_IE_SUPP_RATES pExtSuppRates;
@@ -609,12 +599,12 @@ typedef struct tagWLAN_FR_REASSOCREQ {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwCapInfo;
- PWORD pwListenInterval;
+ u16 * pwCapInfo;
+ u16 * pwListenInterval;
PIEEE_ADDR pAddrCurrAP;
/* info elements */
@@ -634,12 +624,12 @@ typedef struct tagWLAN_FR_REASSOCRESP {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwCapInfo;
- PWORD pwStatus;
- PWORD pwAid;
+ u16 * pwCapInfo;
+ u16 * pwStatus;
+ u16 * pwAid;
/* info elements */
PWLAN_IE_SUPP_RATES pSuppRates;
PWLAN_IE_SUPP_RATES pExtSuppRates;
@@ -651,7 +641,7 @@ typedef struct tagWLAN_FR_PROBEREQ {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
/* info elements */
@@ -666,12 +656,12 @@ typedef struct tagWLAN_FR_PROBERESP {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
u64 *pqwTimestamp;
- PWORD pwBeaconInterval;
- PWORD pwCapInfo;
+ u16 * pwBeaconInterval;
+ u16 * pwCapInfo;
/* info elements */
PWLAN_IE_SSID pSSID;
PWLAN_IE_SUPP_RATES pSuppRates;
@@ -695,12 +685,12 @@ typedef struct tagWLAN_FR_AUTHEN {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwAuthAlgorithm;
- PWORD pwAuthSequence;
- PWORD pwStatus;
+ u16 * pwAuthAlgorithm;
+ u16 * pwAuthSequence;
+ u16 * pwStatus;
/* info elements */
PWLAN_IE_CHALLENGE pChallenge;
@@ -711,17 +701,15 @@ typedef struct tagWLAN_FR_DEAUTHEN {
unsigned int uType;
unsigned int len;
- PBYTE pBuf;
+ u8 * pBuf;
PUWLAN_80211HDR pHdr;
/* fixed fields */
- PWORD pwReason;
+ u16 * pwReason;
/* info elements */
} WLAN_FR_DEAUTHEN, *PWLAN_FR_DEAUTHEN;
-/*--------------------- Export Functions --------------------------*/
-
void
vMgrEncodeBeacon(
PWLAN_FR_BEACON pFrame
@@ -733,16 +721,6 @@ vMgrDecodeBeacon(
);
void
-vMgrEncodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- );
-
-void
-vMgrDecodeIBSSATIM(
- PWLAN_FR_IBSSATIM pFrame
- );
-
-void
vMgrEncodeDisassociation(
PWLAN_FR_DISASSOC pFrame
);
@@ -827,9 +805,4 @@ vMgrEncodeReassocResponse(
PWLAN_FR_REASSOCRESP pFrame
);
-void
-vMgrDecodeReassocResponse(
- PWLAN_FR_REASSOCRESP pFrame
- );
-
#endif /* __80211MGR_H__ */
diff --git a/drivers/staging/vt6656/TODO b/drivers/staging/vt6656/TODO
index a318995ba07f..e154b2f3b247 100644
--- a/drivers/staging/vt6656/TODO
+++ b/drivers/staging/vt6656/TODO
@@ -7,7 +7,7 @@ TODO:
- split rf.c
- abstract VT3184 chipset specific code
- add common vt665x infrastructure
-- kill ttype.h
+- kill ttype.h -- done
- switch to use LIB80211
- switch to use MAC80211
- use kernel coding style
diff --git a/drivers/staging/vt6656/aes_ccmp.c b/drivers/staging/vt6656/aes_ccmp.c
index fb6124d9082a..28a4c4c30416 100644
--- a/drivers/staging/vt6656/aes_ccmp.c
+++ b/drivers/staging/vt6656/aes_ccmp.c
@@ -33,17 +33,11 @@
#include "device.h"
#include "80211hdr.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
/*
* SBOX Table
*/
-BYTE sbox_table[256] = {
+u8 sbox_table[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
@@ -62,7 +56,7 @@ BYTE sbox_table[256] = {
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
};
-BYTE dot2_table[256] = {
+u8 dot2_table[256] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
@@ -81,7 +75,7 @@ BYTE dot2_table[256] = {
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
};
-BYTE dot3_table[256] = {
+u8 dot3_table[256] = {
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
@@ -100,17 +94,11 @@ BYTE dot3_table[256] = {
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
};
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-static void xor_128(BYTE *a, BYTE *b, BYTE *out)
+static void xor_128(u8 *a, u8 *b, u8 *out)
{
- PDWORD dwPtrA = (PDWORD) a;
- PDWORD dwPtrB = (PDWORD) b;
- PDWORD dwPtrOut = (PDWORD) out;
+ u32 * dwPtrA = (u32 *) a;
+ u32 * dwPtrB = (u32 *) b;
+ u32 * dwPtrOut = (u32 *) out;
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
@@ -118,20 +106,19 @@ static void xor_128(BYTE *a, BYTE *b, BYTE *out)
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
}
-
-static void xor_32(BYTE *a, BYTE *b, BYTE *out)
+static void xor_32(u8 *a, u8 *b, u8 *out)
{
- PDWORD dwPtrA = (PDWORD) a;
- PDWORD dwPtrB = (PDWORD) b;
- PDWORD dwPtrOut = (PDWORD) out;
+ u32 * dwPtrA = (u32 *) a;
+ u32 * dwPtrB = (u32 *) b;
+ u32 * dwPtrOut = (u32 *) out;
(*dwPtrOut++) = (*dwPtrA++) ^ (*dwPtrB++);
}
-void AddRoundKey(BYTE *key, int round)
+void AddRoundKey(u8 *key, int round)
{
- BYTE sbox_key[4];
- BYTE rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
+ u8 sbox_key[4];
+ u8 rcon_table[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36};
sbox_key[0] = sbox_table[key[13]];
sbox_key[1] = sbox_table[key[14]];
@@ -146,7 +133,7 @@ void AddRoundKey(BYTE *key, int round)
xor_32(&key[12], &key[8], &key[12]);
}
-void SubBytes(BYTE *in, BYTE *out)
+void SubBytes(u8 *in, u8 *out)
{
int i;
@@ -154,7 +141,7 @@ void SubBytes(BYTE *in, BYTE *out)
out[i] = sbox_table[in[i]];
}
-void ShiftRows(BYTE *in, BYTE *out)
+void ShiftRows(u8 *in, u8 *out)
{
out[0] = in[0];
out[1] = in[5];
@@ -174,7 +161,7 @@ void ShiftRows(BYTE *in, BYTE *out)
out[15] = in[11];
}
-void MixColumns(BYTE *in, BYTE *out)
+void MixColumns(u8 *in, u8 *out)
{
out[0] = dot2_table[in[0]] ^ dot3_table[in[1]] ^ in[2] ^ in[3];
@@ -183,13 +170,13 @@ void MixColumns(BYTE *in, BYTE *out)
out[3] = dot3_table[in[0]] ^ in[1] ^ in[2] ^ dot2_table[in[3]];
}
-void AESv128(BYTE *key, BYTE *data, BYTE *ciphertext)
+void AESv128(u8 *key, u8 *data, u8 *ciphertext)
{
int i;
int round;
- BYTE TmpdataA[16];
- BYTE TmpdataB[16];
- BYTE abyRoundKey[16];
+ u8 TmpdataA[16];
+ u8 TmpdataB[16];
+ u8 abyRoundKey[16];
for (i = 0; i < 16; i++)
abyRoundKey[i] = key[i];
@@ -231,32 +218,32 @@ void AESv128(BYTE *key, BYTE *data, BYTE *ciphertext)
*
*/
-bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
+bool AESbGenCCMP(u8 * pbyRxKey, u8 * pbyFrame, u16 wFrameSize)
{
- BYTE abyNonce[13];
- BYTE MIC_IV[16];
- BYTE MIC_HDR1[16];
- BYTE MIC_HDR2[16];
- BYTE abyMIC[16];
- BYTE abyCTRPLD[16];
- BYTE abyTmp[16];
- BYTE abyPlainText[16];
- BYTE abyLastCipher[16];
-
- PS802_11Header pMACHeader = (PS802_11Header) pbyFrame;
- PBYTE pbyIV;
- PBYTE pbyPayload;
- WORD wHLen = 22;
+ u8 abyNonce[13];
+ u8 MIC_IV[16];
+ u8 MIC_HDR1[16];
+ u8 MIC_HDR2[16];
+ u8 abyMIC[16];
+ u8 abyCTRPLD[16];
+ u8 abyTmp[16];
+ u8 abyPlainText[16];
+ u8 abyLastCipher[16];
+
+ struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *) pbyFrame;
+ u8 * pbyIV;
+ u8 * pbyPayload;
+ u16 wHLen = 22;
/* 8 is IV, 8 is MIC, 4 is CRC */
- WORD wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;
+ u16 wPayloadSize = wFrameSize - 8 - 8 - 4 - WLAN_HDR_ADDR3_LEN;
bool bA4 = false;
- BYTE byTmp;
- WORD wCnt;
+ u8 byTmp;
+ u16 wCnt;
int ii, jj, kk;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if (WLAN_GET_FC_TODS(*(PWORD) pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD) pbyFrame)) {
+ if (WLAN_GET_FC_TODS(*(u16 *) pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(u16 *) pbyFrame)) {
bA4 = true;
pbyIV += 6; /* 6 is 802.11 address4 */
wHLen += 6;
@@ -265,7 +252,7 @@ bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
pbyPayload = pbyIV + 8; /* IV-length */
abyNonce[0] = 0x00; /* now is 0, if Qos here will be priority */
- memcpy(&(abyNonce[1]), pMACHeader->abyAddr2, ETH_ALEN);
+ memcpy(&(abyNonce[1]), pMACHeader->addr2, ETH_ALEN);
abyNonce[7] = pbyIV[7];
abyNonce[8] = pbyIV[6];
abyNonce[9] = pbyIV[5];
@@ -276,28 +263,28 @@ bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
/* MIC_IV */
MIC_IV[0] = 0x59;
memcpy(&(MIC_IV[1]), &(abyNonce[0]), 13);
- MIC_IV[14] = (BYTE)(wPayloadSize >> 8);
- MIC_IV[15] = (BYTE)(wPayloadSize & 0xff);
+ MIC_IV[14] = (u8)(wPayloadSize >> 8);
+ MIC_IV[15] = (u8)(wPayloadSize & 0xff);
/* MIC_HDR1 */
- MIC_HDR1[0] = (BYTE)(wHLen >> 8);
- MIC_HDR1[1] = (BYTE)(wHLen & 0xff);
- byTmp = (BYTE)(pMACHeader->wFrameCtl & 0xff);
+ MIC_HDR1[0] = (u8)(wHLen >> 8);
+ MIC_HDR1[1] = (u8)(wHLen & 0xff);
+ byTmp = (u8)(pMACHeader->frame_control & 0xff);
MIC_HDR1[2] = byTmp & 0x8f;
- byTmp = (BYTE)(pMACHeader->wFrameCtl >> 8);
+ byTmp = (u8)(pMACHeader->frame_control >> 8);
byTmp &= 0x87;
MIC_HDR1[3] = byTmp | 0x40;
- memcpy(&(MIC_HDR1[4]), pMACHeader->abyAddr1, ETH_ALEN);
- memcpy(&(MIC_HDR1[10]), pMACHeader->abyAddr2, ETH_ALEN);
+ memcpy(&(MIC_HDR1[4]), pMACHeader->addr1, ETH_ALEN);
+ memcpy(&(MIC_HDR1[10]), pMACHeader->addr2, ETH_ALEN);
/* MIC_HDR2 */
- memcpy(&(MIC_HDR2[0]), pMACHeader->abyAddr3, ETH_ALEN);
- byTmp = (BYTE)(pMACHeader->wSeqCtl & 0xff);
+ memcpy(&(MIC_HDR2[0]), pMACHeader->addr3, ETH_ALEN);
+ byTmp = (u8)(pMACHeader->seq_ctrl & 0xff);
MIC_HDR2[6] = byTmp & 0x0f;
MIC_HDR2[7] = 0;
if (bA4) {
- memcpy(&(MIC_HDR2[8]), pMACHeader->abyAddr4, ETH_ALEN);
+ memcpy(&(MIC_HDR2[8]), pMACHeader->addr4, ETH_ALEN);
} else {
MIC_HDR2[8] = 0x00;
MIC_HDR2[9] = 0x00;
@@ -326,8 +313,8 @@ bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
for (jj = wPayloadSize; jj > 16; jj = jj-16) {
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (u8) (wCnt >> 8);
+ abyCTRPLD[15] = (u8) (wCnt & 0xff);
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
@@ -349,8 +336,8 @@ bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
for (ii = jj; ii < 16; ii++)
abyLastCipher[ii] = 0x00;
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (u8) (wCnt >> 8);
+ abyCTRPLD[15] = (u8) (wCnt & 0xff);
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
for (kk = 0; kk < 16; kk++)
@@ -370,8 +357,8 @@ bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize)
/* => above is the calculated MIC */
wCnt = 0;
- abyCTRPLD[14] = (BYTE) (wCnt >> 8);
- abyCTRPLD[15] = (BYTE) (wCnt & 0xff);
+ abyCTRPLD[14] = (u8) (wCnt >> 8);
+ abyCTRPLD[15] = (u8) (wCnt & 0xff);
AESv128(pbyRxKey, abyCTRPLD, abyTmp);
for (kk = 0; kk < 8; kk++)
diff --git a/drivers/staging/vt6656/aes_ccmp.h b/drivers/staging/vt6656/aes_ccmp.h
index a2e2c4e9a5c9..ed6a9ae315de 100644
--- a/drivers/staging/vt6656/aes_ccmp.h
+++ b/drivers/staging/vt6656/aes_ccmp.h
@@ -30,17 +30,6 @@
#ifndef __AES_H__
#define __AES_H__
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-bool AESbGenCCMP(PBYTE pbyRxKey, PBYTE pbyFrame, WORD wFrameSize);
+bool AESbGenCCMP(u8 * pbyRxKey, u8 * pbyFrame, u16 wFrameSize);
#endif /* __AES_CCMP_H__ */
diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c
index a9f525e9d16e..33fa76759bf1 100644
--- a/drivers/staging/vt6656/baseband.c
+++ b/drivers/staging/vt6656/baseband.c
@@ -29,8 +29,6 @@
* BBuGetFrameTime - Calculate data frame transmitting time
* BBvCalculateParameter - Calculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
* BBbVT3184Init - VIA VT3184 baseband chip init code
- * BBvLoopbackOn - Turn on BaseBand Loopback mode
- * BBvLoopbackOff - Turn off BaseBand Loopback mode
*
* Revision History:
*
@@ -47,26 +45,10 @@
#include "datarate.h"
#include "rndis.h"
-/*--------------------- Static Definitions -------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-
-BYTE abyVT3184_AGC[] = {
+u8 abyVT3184_AGC[] = {
0x00, //0
0x00, //1
0x02, //2
@@ -133,8 +115,7 @@ BYTE abyVT3184_AGC[] = {
0x3E //3F
};
-
-BYTE abyVT3184_AL2230[] = {
+u8 abyVT3184_AL2230[] = {
0x31,//00
0x00,
0x00,
@@ -393,10 +374,8 @@ BYTE abyVT3184_AL2230[] = {
0x00
};
-
-
//{{RobertYu:20060515, new BB setting for VT3226D0
-BYTE abyVT3184_VT3226D0[] = {
+u8 abyVT3184_VT3226D0[] = {
0x31,//00
0x00,
0x00,
@@ -655,11 +634,9 @@ BYTE abyVT3184_VT3226D0[] = {
0x00,
};
-const WORD awcFrameTime[MAX_RATE] =
+const u16 awcFrameTime[MAX_RATE] =
{10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216};
-/*--------------------- Static Functions --------------------------*/
-
/*
static
unsigned long
@@ -674,7 +651,6 @@ void
s_vClearSQ3Value(PSDevice pDevice);
*/
-/*--------------------- Export Variables --------------------------*/
/*
* Description: Calculate data frame transmitting time
*
@@ -691,10 +667,10 @@ s_vClearSQ3Value(PSDevice pDevice);
*/
unsigned int
BBuGetFrameTime(
- BYTE byPreambleType,
- BYTE byPktType,
+ u8 byPreambleType,
+ u8 byPktType,
unsigned int cbFrameLength,
- WORD wRate
+ u16 wRate
)
{
unsigned int uFrameTime;
@@ -703,7 +679,6 @@ BBuGetFrameTime(
unsigned int uRateIdx = (unsigned int)wRate;
unsigned int uRate = 0;
-
if (uRateIdx > RATE_54M) {
ASSERT(0);
return 0;
@@ -900,15 +875,14 @@ void BBvCalculateParameter(struct vnt_private *pDevice, u32 cbFrameLength,
*pbyPhySrv = 0x00;
if (bExtBit)
*pbyPhySrv = *pbyPhySrv | 0x80;
- *pwPhyLen = (WORD) cbUsCount;
+ *pwPhyLen = (u16) cbUsCount;
}
else {
*pbyPhySrv = 0x00;
- *pwPhyLen = (WORD)cbFrameLength;
+ *pwPhyLen = (u16)cbFrameLength;
}
}
-
/*
* Description: Set Antenna mode
*
@@ -937,10 +911,9 @@ void BBvSetAntennaMode(struct vnt_private *pDevice, u8 byAntennaMode)
break;
}
-
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_SET_ANTMD,
- (WORD) byAntennaMode,
+ (u16) byAntennaMode,
0,
0,
NULL);
@@ -963,11 +936,11 @@ void BBvSetAntennaMode(struct vnt_private *pDevice, u8 byAntennaMode)
int BBbVT3184Init(struct vnt_private *pDevice)
{
int ntStatus;
- WORD wLength;
- PBYTE pbyAddr;
- PBYTE pbyAgc;
- WORD wLengthAgc;
- BYTE abyArray[256];
+ u16 wLength;
+ u8 * pbyAddr;
+ u8 * pbyAgc;
+ u16 wLengthAgc;
+ u8 abyArray[256];
ntStatus = CONTROLnsRequestIn(pDevice,
MESSAGE_TYPE_READ,
@@ -979,7 +952,6 @@ int BBbVT3184Init(struct vnt_private *pDevice)
return false;
}
-
// if ((pDevice->abyEEPROM[EEP_OFS_RADIOCTL]&0x06)==0x04)
// return false;
@@ -1118,7 +1090,6 @@ else {
abyArray
);
-
if ((pDevice->byRFType == RF_VT3226) || //RobertYu:20051116, 20060111 remove VT3226D0
(pDevice->byRFType == RF_VT3342A0) //RobertYu:20060609
) {
@@ -1131,7 +1102,6 @@ else {
MACvRegBitsOn(pDevice,MAC_REG_PAPEDELAY,0x01);
}
-
ControlvWriteByte(pDevice,MESSAGE_REQUEST_BBREG,0x04,0x7F);
ControlvWriteByte(pDevice,MESSAGE_REQUEST_BBREG,0x0D,0x01);
@@ -1139,96 +1109,6 @@ else {
return true;//ntStatus;
}
-
-/*
- * Description: Turn on BaseBand Loopback mode
- *
- * Parameters:
- * In:
- * pDevice - Device Structure
- *
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void BBvLoopbackOn(struct vnt_private *pDevice)
-{
- BYTE byData;
-
- //CR C9 = 0x00
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0xC9, &pDevice->byBBCRc9);//CR201
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, 0);
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x4D, &pDevice->byBBCR4d);//CR77
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x4D, 0x90);
-
- //CR 88 = 0x02(CCK), 0x03(OFDM)
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x88, &pDevice->byBBCR88);//CR136
-
- if (pDevice->wCurrentRate <= RATE_11M) { //CCK
- // Enable internal digital loopback: CR33 |= 0000 0001
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x21, &byData);//CR33
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x21, (BYTE)(byData | 0x01));//CR33
- // CR154 = 0x00
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9A, 0); //CR154
-
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x88, 0x02);//CR239
- }
- else { //OFDM
- // Enable internal digital loopback:CR154 |= 0000 0001
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x9A, &byData);//CR154
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9A, (BYTE)(byData | 0x01));//CR154
- // CR33 = 0x00
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x21, 0); //CR33
-
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x88, 0x03);//CR239
- }
-
- //CR14 = 0x00
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0E, 0);//CR14
-
- // Disable TX_IQUN
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x09, &pDevice->byBBCR09);
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x09, (BYTE)(pDevice->byBBCR09 & 0xDE));
-}
-
-/*
- * Description: Turn off BaseBand Loopback mode
- *
- * Parameters:
- * In:
- * pDevice - Device Structure
- *
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void BBvLoopbackOff(struct vnt_private *pDevice)
-{
- u8 byData;
-
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xC9, pDevice->byBBCRc9);//CR201
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x88, pDevice->byBBCR88);//CR136
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x09, pDevice->byBBCR09);//CR136
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x4D, pDevice->byBBCR4d);//CR77
-
- if (pDevice->wCurrentRate <= RATE_11M) { // CCK
- // Set the CR33 Bit2 to disable internal Loopback.
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x21, &byData);//CR33
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x21, (BYTE)(byData & 0xFE));//CR33
- } else { /* OFDM */
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x9A, &byData);//CR154
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9A, (BYTE)(byData & 0xFE));//CR154
- }
- ControlvReadByte (pDevice, MESSAGE_REQUEST_BBREG, 0x0E, &byData);//CR14
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0E, (BYTE)(byData | 0x80));//CR14
-
-}
-
-
/*
* Description: Set ShortSlotTime mode
*
@@ -1243,7 +1123,7 @@ void BBvLoopbackOff(struct vnt_private *pDevice)
*/
void BBvSetShortSlotTime(struct vnt_private *pDevice)
{
- BYTE byBBVGA=0;
+ u8 byBBVGA=0;
if (pDevice->bShortSlotTime)
pDevice->byBBRxConf &= 0xDF;//1101 1111
@@ -1257,8 +1137,7 @@ void BBvSetShortSlotTime(struct vnt_private *pDevice)
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0A, pDevice->byBBRxConf);
}
-
-void BBvSetVGAGainOffset(struct vnt_private *pDevice, BYTE byData)
+void BBvSetVGAGainOffset(struct vnt_private *pDevice, u8 byData)
{
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0xE7, byData);
@@ -1272,27 +1151,6 @@ void BBvSetVGAGainOffset(struct vnt_private *pDevice, BYTE byData)
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0A, pDevice->byBBRxConf);//CR10
}
-
-/*
- * Description: Baseband SoftwareReset
- *
- * Parameters:
- * In:
- * dwIoBase - I/O base address
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void BBvSoftwareReset(struct vnt_private *pDevice)
-{
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x50, 0x40);
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x50, 0);
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9C, 0x01);
- ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x9C, 0);
-}
-
/*
* Description: BBvSetDeepSleep
*
@@ -1317,7 +1175,6 @@ void BBvExitDeepSleep(struct vnt_private *pDevice)
ControlvWriteByte(pDevice, MESSAGE_REQUEST_BBREG, 0x0D, 0x01);//CR13
}
-
static unsigned long s_ulGetLowSQ3(struct vnt_private *pDevice)
{
int ii;
@@ -1364,7 +1221,6 @@ static unsigned long s_ulGetRatio(struct vnt_private *pDevice)
return ulRatio;
}
-
static void s_vClearSQ3Value(struct vnt_private *pDevice)
{
int ii;
@@ -1376,7 +1232,6 @@ static void s_vClearSQ3Value(struct vnt_private *pDevice)
}
}
-
/*
* Description: Antenna Diversity
*
@@ -1508,7 +1363,6 @@ void BBvAntennaDiversity(struct vnt_private *pDevice,
} //byAntennaState
}
-
/*+
*
* Description:
@@ -1541,11 +1395,9 @@ void TimerSQ3CallBack(struct vnt_private *pDevice)
add_timer(&pDevice->TimerSQ3Tmax3);
add_timer(&pDevice->TimerSQ3Tmax2);
-
spin_unlock_irq(&pDevice->lock);
}
-
/*+
*
* Description:
@@ -1594,7 +1446,6 @@ void TimerSQ3Tmax3CallBack(struct vnt_private *pDevice)
void BBvUpdatePreEDThreshold(struct vnt_private *pDevice, int bScanning)
{
-
switch(pDevice->byRFType)
{
case RF_AL2230:
diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h
index fba61605a692..0a634adabf0e 100644
--- a/drivers/staging/vt6656/baseband.h
+++ b/drivers/staging/vt6656/baseband.h
@@ -33,12 +33,9 @@
#ifndef __BASEBAND_H__
#define __BASEBAND_H__
-#include "ttype.h"
#include "tether.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define PREAMBLE_LONG 0
#define PREAMBLE_SHORT 1
@@ -84,23 +81,12 @@
#define TOP_RATE_2M 0x00200000
#define TOP_RATE_1M 0x00100000
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
unsigned int
BBuGetFrameTime(
- BYTE byPreambleType,
- BYTE byFreqType,
+ u8 byPreambleType,
+ u8 byFreqType,
unsigned int cbFrameLength,
- WORD wRate
+ u16 wRate
);
void BBvCalculateParameter(struct vnt_private *, u32 cbFrameLength,
@@ -113,9 +99,6 @@ void TimerSQ3CallBack(struct vnt_private *);
void TimerSQ3Tmax3CallBack(struct vnt_private *);
void BBvAntennaDiversity(struct vnt_private *, u8 byRxRate, u8 bySQ3);
-void BBvLoopbackOn(struct vnt_private *);
-void BBvLoopbackOff(struct vnt_private *);
-void BBvSoftwareReset(struct vnt_private *);
void BBvSetShortSlotTime(struct vnt_private *);
void BBvSetVGAGainOffset(struct vnt_private *, u8 byData);
diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c
index e214fcf83868..ee79bbdf1a06 100644
--- a/drivers/staging/vt6656/bssdb.c
+++ b/drivers/staging/vt6656/bssdb.c
@@ -39,7 +39,6 @@
*
*/
-#include "ttype.h"
#include "tmacro.h"
#include "tether.h"
#include "device.h"
@@ -59,27 +58,17 @@
#include "rndis.h"
#include "iowpa.h"
-/*--------------------- Static Definitions -------------------------*/
-
-
-
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-
-
-const WORD awHWRetry0[5][5] = {
+const u16 awHWRetry0[5][5] = {
{RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
{RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
{RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
{RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
{RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
};
-const WORD awHWRetry1[5][5] = {
+const u16 awHWRetry1[5][5] = {
{RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
{RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
{RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
@@ -87,23 +76,10 @@ const WORD awHWRetry1[5][5] = {
{RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
};
-
-
-/*--------------------- Static Functions --------------------------*/
-
static void s_vCheckSensitivity(struct vnt_private *pDevice);
static void s_vCheckPreEDThreshold(struct vnt_private *pDevice);
static void s_uCalculateLinkQual(struct vnt_private *pDevice);
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
-
-
-
-
/*+
*
* Routine Description:
@@ -221,7 +197,6 @@ PKnownBSS BSSpSearchBSSList(struct vnt_private *pDevice,
pCurrBSS->abyBSSID);
jj++;
-
if (pSelect == NULL) {
pSelect = pCurrBSS;
} else {
@@ -249,7 +224,6 @@ pDevice->bSameBSSMaxNum = jj;
}
-
/*+
*
* Routine Description:
@@ -260,7 +234,6 @@ pDevice->bSameBSSMaxNum = jj;
*
-*/
-
void BSSvClearBSSList(struct vnt_private *pDevice, int bKeepCurrBSSID)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
@@ -285,8 +258,6 @@ void BSSvClearBSSList(struct vnt_private *pDevice, int bKeepCurrBSSID)
BSSvClearAnyBSSJoinRecord(pDevice);
}
-
-
/*+
*
* Routine Description:
@@ -320,8 +291,6 @@ PKnownBSS BSSpAddrIsInBSSList(struct vnt_private *pDevice,
return NULL;
};
-
-
/*+
*
* Routine Description:
@@ -357,7 +326,6 @@ int BSSbInsertToBSSList(struct vnt_private *pDevice,
unsigned int ii;
bool bParsingQuiet = false;
-
pBSSList = (PKnownBSS)&(pMgmt->sBSSList[0]);
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
@@ -430,7 +398,7 @@ int BSSbInsertToBSSList(struct vnt_private *pDevice,
unsigned int uLen = pRSNWPA->len + 2;
if (uLen <= (uIELength -
- (unsigned int) (ULONG_PTR) ((PBYTE) pRSNWPA - pbyIEs))) {
+ (unsigned int) (u32) ((u8 *) pRSNWPA - pbyIEs))) {
pBSSList->wWPALen = uLen;
memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
WPA_ParseRSN(pBSSList, pRSNWPA);
@@ -443,7 +411,7 @@ int BSSbInsertToBSSList(struct vnt_private *pDevice,
unsigned int uLen = pRSN->len + 2;
if (uLen <= (uIELength -
- (unsigned int) (ULONG_PTR) ((PBYTE) pRSN - pbyIEs))) {
+ (unsigned int) (u32) ((u8 *) pRSN - pbyIEs))) {
pBSSList->wRSNLen = uLen;
memcpy(pBSSList->byRSNIE, pRSN, uLen);
WPA2vParseRSN(pBSSList, pRSN);
@@ -483,7 +451,7 @@ int BSSbInsertToBSSList(struct vnt_private *pDevice,
if (pDevice->bUpdateBBVGA) {
// Monitor if RSSI is too strong.
pBSSList->byRSSIStatCnt = 0;
- RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
+ RFvRSSITodBm(pDevice, (u8)(pRxPacket->uRSSI), &pBSSList->ldBmMAX);
pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX;
pBSSList->ldBmAverRange = pBSSList->ldBmMAX;
for (ii = 1; ii < RSSI_STAT_COUNT; ii++)
@@ -498,7 +466,6 @@ int BSSbInsertToBSSList(struct vnt_private *pDevice,
return true;
}
-
/*+
*
* Routine Description:
@@ -539,7 +506,6 @@ int BSSbUpdateToBSSList(struct vnt_private *pDevice,
if (pBSSList == NULL)
return false;
-
pBSSList->qwBSSTimestamp = cpu_to_le64(qwTimestamp);
pBSSList->wBeaconInterval = cpu_to_le16(wBeaconInterval);
@@ -592,7 +558,7 @@ int BSSbUpdateToBSSList(struct vnt_private *pDevice,
if (pRSNWPA != NULL) {
unsigned int uLen = pRSNWPA->len + 2;
if (uLen <= (uIELength -
- (unsigned int) (ULONG_PTR) ((PBYTE) pRSNWPA - pbyIEs))) {
+ (unsigned int) (u32) ((u8 *) pRSNWPA - pbyIEs))) {
pBSSList->wWPALen = uLen;
memcpy(pBSSList->byWPAIE, pRSNWPA, uLen);
WPA_ParseRSN(pBSSList, pRSNWPA);
@@ -604,7 +570,7 @@ int BSSbUpdateToBSSList(struct vnt_private *pDevice,
if (pRSN != NULL) {
unsigned int uLen = pRSN->len + 2;
if (uLen <= (uIELength -
- (unsigned int) (ULONG_PTR) ((PBYTE) pRSN - pbyIEs))) {
+ (unsigned int) (u32) ((u8 *) pRSN - pbyIEs))) {
pBSSList->wRSNLen = uLen;
memcpy(pBSSList->byRSNIE, pRSN, uLen);
WPA2vParseRSN(pBSSList, pRSN);
@@ -612,7 +578,7 @@ int BSSbUpdateToBSSList(struct vnt_private *pDevice,
}
if (pRxPacket->uRSSI != 0) {
- RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (u8)(pRxPacket->uRSSI), &ldBm);
// Monitor if RSSI is too strong.
pBSSList->byRSSIStatCnt++;
pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT;
@@ -638,10 +604,6 @@ int BSSbUpdateToBSSList(struct vnt_private *pDevice,
return true;
}
-
-
-
-
/*+
*
* Routine Description:
@@ -672,8 +634,6 @@ int BSSbIsSTAInNodeDB(struct vnt_private *pDevice,
return false;
};
-
-
/*+
*
* Routine Description:
@@ -731,8 +691,6 @@ void BSSvCreateOneNode(struct vnt_private *pDevice, u32 *puNodeIndex)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create node index = %d\n", ii);
};
-
-
/*+
*
* Routine Description:
@@ -750,7 +708,6 @@ void BSSvRemoveOneNode(struct vnt_private *pDevice, u32 uNodeIndex)
u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
struct sk_buff *skb;
-
while ((skb = skb_dequeue(&pMgmt->sNodeDBTable[uNodeIndex].sTxPSQueue)) != NULL)
dev_kfree_skb(skb);
// clear context
@@ -948,7 +905,6 @@ if(pDevice->byReAssocCount > 0) {
if (pMgmt->sNodeDBTable[ii].bPSEnable)
uSleepySTACnt++;
-
}
// Rate fallback check
@@ -981,7 +937,6 @@ if(pDevice->byReAssocCount > 0) {
}
-
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->byBBType == BB_TYPE_11G)) {
// on/off protect mode
@@ -1031,7 +986,6 @@ if(pDevice->byReAssocCount > 0) {
}
-
// Check if any STA in PS mode, enable DTIM multicast deliver
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (uSleepySTACnt > 0)
@@ -1205,9 +1159,9 @@ void BSSvUpdateNodeTxCounter(struct vnt_private *pDevice,
byPktNum = (byPktNO & 0x0F) >> 4;
byTxRetry = (byTSR & 0xF0) >> 4;
- wRate = (WORD) (byPktNO & 0xF0) >> 4;
+ wRate = (u16) (byPktNO & 0xF0) >> 4;
wFIFOCtl = pStatistic->abyTxPktInfo[byPktNum].wFIFOCtl;
- pbyDestAddr = (PBYTE) &( pStatistic->abyTxPktInfo[byPktNum].abyDestAddr[0]);
+ pbyDestAddr = (u8 *) &( pStatistic->abyTxPktInfo[byPktNum].abyDestAddr[0]);
if (wFIFOCtl & FIFOCTL_AUTO_FB_0) {
byFallBack = AUTO_FB_0;
@@ -1433,7 +1387,7 @@ if(pDevice->bLinkPass !=true)
}
else
{
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (u8)(pDevice->uCurrRSSI), &ldBm);
if(-ldBm < 50) {
RssiRatio = 4000;
}
@@ -1473,7 +1427,7 @@ static void s_vCheckPreEDThreshold(struct vnt_private *pDevice)
((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) {
pBSSList = BSSpAddrIsInBSSList(pDevice, pMgmt->abyCurrBSSID, (PWLAN_IE_SSID)pMgmt->abyCurrSSID);
if (pBSSList != NULL) {
- pDevice->byBBPreEDRSSI = (BYTE) (~(pBSSList->ldBmAverRange) + 1);
+ pDevice->byBBPreEDRSSI = (u8) (~(pBSSList->ldBmAverRange) + 1);
BBvUpdatePreEDThreshold(pDevice, false);
}
}
diff --git a/drivers/staging/vt6656/bssdb.h b/drivers/staging/vt6656/bssdb.h
index 08091a0a7c40..bce3b4654165 100644
--- a/drivers/staging/vt6656/bssdb.h
+++ b/drivers/staging/vt6656/bssdb.h
@@ -36,8 +36,6 @@
#include "card.h"
#include "mib.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define MAX_NODE_NUM 64
#define MAX_BSS_NUM 42
#define LOST_BEACON_COUNT 10 /* 10 sec, XP defined */
@@ -66,46 +64,37 @@
#define MAX_WPA_IE_LEN 64
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Types ------------------------------*/
-
//
// IEEE 802.11 Structures and definitions
//
typedef struct tagSERPObject {
bool bERPExist;
- BYTE byERP;
+ u8 byERP;
} ERPObject, *PERPObject;
-
typedef struct tagSRSNCapObject {
bool bRSNCapExist;
- WORD wRSNCap;
+ u16 wRSNCap;
} SRSNCapObject, *PSRSNCapObject;
// BSS info(AP)
typedef struct tagKnownBSS {
// BSS info
bool bActive;
- BYTE abyBSSID[WLAN_BSSID_LEN];
+ u8 abyBSSID[WLAN_BSSID_LEN];
unsigned int uChannel;
- BYTE abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
- BYTE abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ u8 abySuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
+ u8 abyExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
unsigned int uRSSI;
- BYTE bySQ;
- WORD wBeaconInterval;
- WORD wCapInfo;
- BYTE abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
- BYTE byRxRate;
-
-// WORD wATIMWindow;
- BYTE byRSSIStatCnt;
+ u8 bySQ;
+ u16 wBeaconInterval;
+ u16 wCapInfo;
+ u8 abySSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ u8 byRxRate;
+
+// u16 wATIMWindow;
+ u8 byRSSIStatCnt;
signed long ldBmMAX;
signed long ldBmAverage[RSSI_STAT_COUNT];
signed long ldBmAverRange;
@@ -114,32 +103,32 @@ typedef struct tagKnownBSS {
//++ WPA informations
bool bWPAValid;
- BYTE byGKType;
- BYTE abyPKType[4];
- WORD wPKCount;
- BYTE abyAuthType[4];
- WORD wAuthCount;
- BYTE byDefaultK_as_PK;
- BYTE byReplayIdx;
+ u8 byGKType;
+ u8 abyPKType[4];
+ u16 wPKCount;
+ u8 abyAuthType[4];
+ u16 wAuthCount;
+ u8 byDefaultK_as_PK;
+ u8 byReplayIdx;
//--
//++ WPA2 informations
bool bWPA2Valid;
- BYTE byCSSGK;
- WORD wCSSPKCount;
- BYTE abyCSSPK[4];
- WORD wAKMSSAuthCount;
- BYTE abyAKMSSAuthType[4];
+ u8 byCSSGK;
+ u16 wCSSPKCount;
+ u8 abyCSSPK[4];
+ u16 wAKMSSAuthCount;
+ u8 abyAKMSSAuthType[4];
//++ wpactl
- BYTE byWPAIE[MAX_WPA_IE_LEN];
- BYTE byRSNIE[MAX_WPA_IE_LEN];
- WORD wWPALen;
- WORD wRSNLen;
+ u8 byWPAIE[MAX_WPA_IE_LEN];
+ u8 byRSNIE[MAX_WPA_IE_LEN];
+ u16 wWPALen;
+ u16 wRSNLen;
// Clear count
unsigned int uClearCount;
-// BYTE abyIEs[WLAN_BEACON_FR_MAXLEN];
+// u8 abyIEs[WLAN_BEACON_FR_MAXLEN];
unsigned int uIELength;
u64 qwBSSTimestamp;
u64 qwLocalTSF;/* local TSF timer */
@@ -148,13 +137,11 @@ typedef struct tagKnownBSS {
ERPObject sERP;
SRSNCapObject sRSNCapObj;
- BYTE abyIEs[1024]; // don't move this field !!
+ u8 abyIEs[1024]; // don't move this field !!
} __attribute__ ((__packed__))
KnownBSS , *PKnownBSS;
-
-
typedef enum tagNODE_STATE {
NODE_FREE,
NODE_AGED,
@@ -163,48 +150,47 @@ typedef enum tagNODE_STATE {
NODE_ASSOC
} NODE_STATE, *PNODE_STATE;
-
// STA node info
typedef struct tagKnownNodeDB {
// STA info
bool bActive;
- BYTE abyMACAddr[WLAN_ADDR_LEN];
- BYTE abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- BYTE abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
- WORD wTxDataRate;
+ u8 abyMACAddr[WLAN_ADDR_LEN];
+ u8 abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ u8 abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN];
+ u16 wTxDataRate;
bool bShortPreamble;
bool bERPExist;
bool bShortSlotTime;
unsigned int uInActiveCount;
- WORD wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
- WORD wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
- WORD wSuppRate;
- BYTE byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
- BYTE byTopCCKBasicRate; //Records the highest basic rate in CCK mode
+ u16 wMaxBasicRate; //Get from byTopOFDMBasicRate or byTopCCKBasicRate which depends on packetTyp.
+ u16 wMaxSuppRate; //Records the highest supported rate getting from SuppRates IE and ExtSuppRates IE in Beacon.
+ u16 wSuppRate;
+ u8 byTopOFDMBasicRate;//Records the highest basic rate in OFDM mode
+ u8 byTopCCKBasicRate; //Records the highest basic rate in CCK mode
// For AP mode
struct sk_buff_head sTxPSQueue;
- WORD wCapInfo;
- WORD wListenInterval;
- WORD wAID;
+ u16 wCapInfo;
+ u16 wListenInterval;
+ u16 wAID;
NODE_STATE eNodeState;
bool bPSEnable;
bool bRxPSPoll;
- BYTE byAuthSequence;
+ u8 byAuthSequence;
unsigned long ulLastRxJiffer;
- BYTE bySuppRate;
- DWORD dwFlags;
- WORD wEnQueueCnt;
+ u8 bySuppRate;
+ u32 dwFlags;
+ u16 wEnQueueCnt;
bool bOnFly;
unsigned long long KeyRSC;
- BYTE byKeyIndex;
- DWORD dwKeyIndex;
- BYTE byCipherSuite;
- DWORD dwTSC47_16;
- WORD wTSC15_0;
+ u8 byKeyIndex;
+ u32 dwKeyIndex;
+ u8 byCipherSuite;
+ u32 dwTSC47_16;
+ u16 wTSC15_0;
unsigned int uWepKeyLength;
- BYTE abyWepKey[WLAN_WEPMAX_KEYLEN];
+ u8 abyWepKey[WLAN_WEPMAX_KEYLEN];
//
// Auto rate fallback vars
bool bIsInFallback;
@@ -223,8 +209,6 @@ typedef struct tagKnownNodeDB {
} KnownNodeDB, *PKnownNodeDB;
-/*--------------------- Export Functions --------------------------*/
-
PKnownBSS BSSpSearchBSSList(struct vnt_private *, u8 *pbyDesireBSSID,
u8 *pbyDesireSSID, CARD_PHY_TYPE ePhyType);
@@ -270,7 +254,7 @@ int BSSbUpdateToBSSList(struct vnt_private *,
u8 *pbyIEs,
void *pRxPacketContext);
-int BSSbIsSTAInNodeDB(struct vnt_private *, PBYTE abyDstAddr,
+int BSSbIsSTAInNodeDB(struct vnt_private *, u8 * abyDstAddr,
u32 *puNodeIndex);
void BSSvCreateOneNode(struct vnt_private *, u32 *puNodeIndex);
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index d2479b766450..24291aee58b5 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -60,28 +60,15 @@
#include "rndis.h"
#include "control.h"
-/*--------------------- Static Definitions -------------------------*/
-
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-//const WORD cwRXBCNTSFOff[MAX_RATE] =
+//const u16 cwRXBCNTSFOff[MAX_RATE] =
//{17, 34, 96, 192, 34, 23, 17, 11, 8, 5, 4, 3};
-const WORD cwRXBCNTSFOff[MAX_RATE] =
+const u16 cwRXBCNTSFOff[MAX_RATE] =
{192, 96, 34, 17, 34, 23, 17, 11, 8, 5, 4, 3};
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
/*
* Description: Set NIC media channel
*
@@ -114,7 +101,7 @@ void CARDbSetMediaChannel(struct vnt_private *pDevice, u32 uConnectionChannel)
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_SELECT_CHANNLE,
- (WORD) uConnectionChannel,
+ (u16) uConnectionChannel,
0,
0,
NULL
@@ -133,7 +120,7 @@ void CARDbSetMediaChannel(struct vnt_private *pDevice, u32 uConnectionChannel)
pDevice->byCurPwr = 0xFF;
RFbRawSetPower(pDevice, pDevice->abyCCKPwrTbl[uConnectionChannel-1], RATE_1M);
}
- ControlvWriteByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_CHANNEL,(BYTE)(uConnectionChannel|0x80));
+ ControlvWriteByte(pDevice,MESSAGE_REQUEST_MACREG,MAC_REG_CHANNEL,(u8)(uConnectionChannel|0x80));
}
/*
@@ -220,10 +207,10 @@ static u16 swGetOFDMControlRate(struct vnt_private *pDevice, u16 wRateIdx)
*/
void
CARDvCalculateOFDMRParameter (
- WORD wRate,
- BYTE byBBType,
- PBYTE pbyTxRate,
- PBYTE pbyRsvTime
+ u16 wRate,
+ u8 byBBType,
+ u8 * pbyTxRate,
+ u8 * pbyRsvTime
)
{
switch (wRate) {
@@ -434,23 +421,23 @@ void CARDvSetRSPINF(struct vnt_private *pDevice, u8 byBBType)
&abyTxRate[8],
&abyRsvTime[8]);
- abyData[0] = (BYTE)(awLen[0]&0xFF);
- abyData[1] = (BYTE)(awLen[0]>>8);
+ abyData[0] = (u8)(awLen[0]&0xFF);
+ abyData[1] = (u8)(awLen[0]>>8);
abyData[2] = abySignal[0];
abyData[3] = abyServ[0];
- abyData[4] = (BYTE)(awLen[1]&0xFF);
- abyData[5] = (BYTE)(awLen[1]>>8);
+ abyData[4] = (u8)(awLen[1]&0xFF);
+ abyData[5] = (u8)(awLen[1]>>8);
abyData[6] = abySignal[1];
abyData[7] = abyServ[1];
- abyData[8] = (BYTE)(awLen[2]&0xFF);
- abyData[9] = (BYTE)(awLen[2]>>8);
+ abyData[8] = (u8)(awLen[2]&0xFF);
+ abyData[9] = (u8)(awLen[2]>>8);
abyData[10] = abySignal[2];
abyData[11] = abyServ[2];
- abyData[12] = (BYTE)(awLen[3]&0xFF);
- abyData[13] = (BYTE)(awLen[3]>>8);
+ abyData[12] = (u8)(awLen[3]&0xFF);
+ abyData[13] = (u8)(awLen[3]>>8);
abyData[14] = abySignal[3];
abyData[15] = abyServ[3];
@@ -500,7 +487,7 @@ void vUpdateIFS(struct vnt_private *pDevice)
byMaxMin = 5;
}
else {// PK_TYPE_11GA & PK_TYPE_11GB
- BYTE byRate = 0;
+ u8 byRate = 0;
bool bOFDMRate = false;
unsigned int ii = 0;
PWLAN_IE_SUPP_RATES pItemRates = NULL;
@@ -515,7 +502,7 @@ void vUpdateIFS(struct vnt_private *pDevice)
pItemRates = (PWLAN_IE_SUPP_RATES)pDevice->vnt_mgmt.abyCurrSuppRates;
for (ii = 0; ii < pItemRates->len; ii++) {
- byRate = (BYTE)(pItemRates->abyRates[ii]&0x7F);
+ byRate = (u8)(pItemRates->abyRates[ii]&0x7F);
if (RATEwGetRateIdx(byRate) > RATE_11M) {
bOFDMRate = true;
break;
@@ -525,7 +512,7 @@ void vUpdateIFS(struct vnt_private *pDevice)
pItemRates = (PWLAN_IE_SUPP_RATES)pDevice->vnt_mgmt
.abyCurrExtSuppRates;
for (ii = 0; ii < pItemRates->len; ii++) {
- byRate = (BYTE)(pItemRates->abyRates[ii]&0x7F);
+ byRate = (u8)(pItemRates->abyRates[ii]&0x7F);
if (RATEwGetRateIdx(byRate) > RATE_11M) {
bOFDMRate = true;
break;
@@ -544,10 +531,10 @@ void vUpdateIFS(struct vnt_private *pDevice)
pDevice->uCwMax = C_CWMAX;
pDevice->uEIFS = C_EIFS;
- byData[0] = (BYTE)pDevice->uSIFS;
- byData[1] = (BYTE)pDevice->uDIFS;
- byData[2] = (BYTE)pDevice->uEIFS;
- byData[3] = (BYTE)pDevice->uSlot;
+ byData[0] = (u8)pDevice->uSIFS;
+ byData[1] = (u8)pDevice->uDIFS;
+ byData[2] = (u8)pDevice->uEIFS;
+ byData[3] = (u8)pDevice->uSlot;
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
MAC_REG_SIFS,
@@ -571,7 +558,7 @@ void CARDvUpdateBasicTopRate(struct vnt_private *pDevice)
//Determines the highest basic rate.
for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
+ if ( (pDevice->wBasicRate) & ((u16)(1<<ii)) ) {
byTopOFDM = ii;
break;
}
@@ -579,7 +566,7 @@ void CARDvUpdateBasicTopRate(struct vnt_private *pDevice)
pDevice->byTopOFDMBasicRate = byTopOFDM;
for (ii = RATE_11M;; ii --) {
- if ( (pDevice->wBasicRate) & ((WORD)(1<<ii)) ) {
+ if ( (pDevice->wBasicRate) & ((u16)(1<<ii)) ) {
byTopCCK = ii;
break;
}
@@ -617,7 +604,7 @@ int CARDbIsOFDMinBasicRate(struct vnt_private *pDevice)
int ii;
for (ii = RATE_54M; ii >= RATE_6M; ii --) {
- if ((pDevice->wBasicRate) & ((WORD)(1<<ii)))
+ if ((pDevice->wBasicRate) & ((u16)(1<<ii)))
return true;
}
return false;
@@ -627,7 +614,7 @@ u8 CARDbyGetPktType(struct vnt_private *pDevice)
{
if (pDevice->byBBType == BB_TYPE_11A || pDevice->byBBType == BB_TYPE_11B) {
- return (BYTE)pDevice->byBBType;
+ return (u8)pDevice->byBBType;
}
else if (CARDbIsOFDMinBasicRate(pDevice)) {
return PK_TYPE_11GA;
@@ -637,7 +624,6 @@ u8 CARDbyGetPktType(struct vnt_private *pDevice)
}
}
-
/*
* Description: Calculate TSF offset of two TSF input
* Get TSF Offset from RxBCN's TSF and local TSF
@@ -653,10 +639,10 @@ u8 CARDbyGetPktType(struct vnt_private *pDevice)
* Return Value: TSF Offset value
*
*/
-u64 CARDqGetTSFOffset(BYTE byRxRate, u64 qwTSF1, u64 qwTSF2)
+u64 CARDqGetTSFOffset(u8 byRxRate, u64 qwTSF1, u64 qwTSF2)
{
u64 qwTSFOffset = 0;
- WORD wRxBcnTSFOffst = 0;
+ u16 wRxBcnTSFOffst = 0;
wRxBcnTSFOffst = cwRXBCNTSFOff[byRxRate % MAX_RATE];
@@ -667,8 +653,6 @@ u64 CARDqGetTSFOffset(BYTE byRxRate, u64 qwTSF1, u64 qwTSF2)
return qwTSFOffset;
}
-
-
/*
* Description: Sync. TSF counter to BSS
* Get TSF offset and write to HW
@@ -690,7 +674,6 @@ void CARDvAdjustTSF(struct vnt_private *pDevice, u8 byRxRate,
u64 qwTSFOffset = 0;
u8 pbyData[8];
-
qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, qwLocalTSF);
// adjust TSF
// HW's TSF add TSF Offset reg
@@ -734,7 +717,6 @@ bool CARDbGetCurrentTSF(struct vnt_private *pDevice, u64 *pqwCurrTSF)
return true;
}
-
/*
* Description: Clear NIC TSF counter
* Clear local TSF counter
@@ -770,7 +752,7 @@ bool CARDbClearCurrentTSF(struct vnt_private *pDevice)
* Return Value: TSF value of next Beacon
*
*/
-u64 CARDqGetNextTBTT(u64 qwTSF, WORD wBeaconInterval)
+u64 CARDqGetNextTBTT(u64 qwTSF, u16 wBeaconInterval)
{
unsigned int uLowNextTBTT;
@@ -796,7 +778,6 @@ u64 CARDqGetNextTBTT(u64 qwTSF, WORD wBeaconInterval)
return (qwTSF);
}
-
/*
* Description: Set NIC TSF counter for first Beacon time
* Get NEXTTBTT from adjusted TSF and Beacon Interval
@@ -811,7 +792,7 @@ u64 CARDqGetNextTBTT(u64 qwTSF, WORD wBeaconInterval)
* Return Value: none
*
*/
-void CARDvSetFirstNextTBTT(struct vnt_private *pDevice, WORD wBeaconInterval)
+void CARDvSetFirstNextTBTT(struct vnt_private *pDevice, u16 wBeaconInterval)
{
u64 qwNextTBTT = 0;
u8 pbyData[8];
@@ -841,7 +822,6 @@ void CARDvSetFirstNextTBTT(struct vnt_private *pDevice, WORD wBeaconInterval)
return;
}
-
/*
* Description: Sync NIC TSF counter for Beacon time
* Get NEXTTBTT and write to HW
@@ -883,7 +863,6 @@ void CARDvUpdateNextTBTT(struct vnt_private *pDevice, u64 qwTSF,
pbyData
);
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO
"Card:Update Next TBTT[%8lx]\n", (unsigned long)qwTSF);
@@ -929,7 +908,6 @@ int CARDbRadioPowerOff(struct vnt_private *pDevice)
return bResult;
}
-
/*
* Description: Turn on Radio power
*
@@ -996,7 +974,7 @@ void CARDvSetBSSMode(struct vnt_private *pDevice)
}
vUpdateIFS(pDevice);
- CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
+ CARDvSetRSPINF(pDevice, (u8)pDevice->byBBType);
if ( pDevice->byBBType == BB_TYPE_11A ) {
//request by Jack 2005-04-26
@@ -1016,44 +994,3 @@ void CARDvSetBSSMode(struct vnt_private *pDevice)
pDevice->abyBBVGA[3] = 0x0;
}
}
-
-/*
- *
- * Description:
- * Do Channel Switch defined in 802.11h
- *
- * Parameters:
- * In:
- * hDeviceContext - device structure point
- * Out:
- * none
- *
- * Return Value: none.
- *
--*/
-int CARDbChannelSwitch(struct vnt_private *pDevice, u8 byMode,
- u8 byNewChannel, u8 byCount)
-{
- int bResult = true;
-
- if (byCount == 0) {
- pDevice->vnt_mgmt.uCurrChannel = byNewChannel;
- CARDbSetMediaChannel(pDevice, byNewChannel);
- return bResult;
- }
- pDevice->byChannelSwitchCount = byCount;
- pDevice->byNewChannel = byNewChannel;
- pDevice->bChannelSwitch = true;
-
- if (byMode == 1) {
- //bResult=CARDbStopTxPacket(pDevice, PKT_TYPE_802_11_ALL);
- pDevice->bStopDataPkt = true;
- }
- return bResult;
-}
-
-
-
-
-
-
diff --git a/drivers/staging/vt6656/card.h b/drivers/staging/vt6656/card.h
index 5123bc7d0dcd..c3017a74fa0f 100644
--- a/drivers/staging/vt6656/card.h
+++ b/drivers/staging/vt6656/card.h
@@ -29,11 +29,6 @@
#ifndef __CARD_H__
#define __CARD_H__
#include "device.h"
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
/* init card type */
@@ -55,9 +50,6 @@ typedef enum _CARD_OP_MODE {
#define CB_MAX_CHANNEL_5G 42 /* add channel9(5045MHz), 41==>42 */
#define CB_MAX_CHANNEL (CB_MAX_CHANNEL_24G+CB_MAX_CHANNEL_5G)
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
struct vnt_private;
void CARDbSetMediaChannel(struct vnt_private *pDevice, u32 uConnectionChannel);
@@ -70,16 +62,14 @@ void CARDvAdjustTSF(struct vnt_private *pDevice, u8 byRxRate,
u64 qwBSSTimestamp, u64 qwLocalTSF);
bool CARDbGetCurrentTSF(struct vnt_private *pDevice, u64 *pqwCurrTSF);
bool CARDbClearCurrentTSF(struct vnt_private *pDevice);
-void CARDvSetFirstNextTBTT(struct vnt_private *pDevice, WORD wBeaconInterval);
+void CARDvSetFirstNextTBTT(struct vnt_private *pDevice, u16 wBeaconInterval);
void CARDvUpdateNextTBTT(struct vnt_private *pDevice, u64 qwTSF,
- WORD wBeaconInterval);
-u64 CARDqGetNextTBTT(u64 qwTSF, WORD wBeaconInterval);
-u64 CARDqGetTSFOffset(BYTE byRxRate, u64 qwTSF1, u64 qwTSF2);
+ u16 wBeaconInterval);
+u64 CARDqGetNextTBTT(u64 qwTSF, u16 wBeaconInterval);
+u64 CARDqGetTSFOffset(u8 byRxRate, u64 qwTSF1, u64 qwTSF2);
int CARDbRadioPowerOff(struct vnt_private *pDevice);
int CARDbRadioPowerOn(struct vnt_private *pDevice);
u8 CARDbyGetPktType(struct vnt_private *pDevice);
void CARDvSetBSSMode(struct vnt_private *pDevice);
-int CARDbChannelSwitch(struct vnt_private *pDevice, u8 byMode,
- u8 byNewChannel, u8 byCount);
#endif /* __CARD_H__ */
diff --git a/drivers/staging/vt6656/channel.c b/drivers/staging/vt6656/channel.c
index 4181e3e12ea9..5158ff4b346a 100644
--- a/drivers/staging/vt6656/channel.c
+++ b/drivers/staging/vt6656/channel.c
@@ -39,15 +39,9 @@
#include "channel.h"
#include "rf.h"
-/*--------------------- Static Definitions -------------------------*/
static int msglevel = MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Export Definitions -------------------------*/
-
-
static SChannelTblElement sChannelTbl[CB_MAX_CHANNEL+1] =
{
{0, 0, false},
@@ -109,17 +103,15 @@ static SChannelTblElement sChannelTbl[CB_MAX_CHANNEL+1] =
{165, 5825, true} //56
};
-
-
/************************************************************************
* The Radar regulation rules for each country
************************************************************************/
static struct
{
- BYTE byChannelCountryCode; /* The country code */
+ u8 byChannelCountryCode; /* The country code */
char chCountryCode[2];
- BYTE bChannelIdxList[CB_MAX_CHANNEL]; /* Available channels Index */
- BYTE byPower[CB_MAX_CHANNEL];
+ u8 bChannelIdxList[CB_MAX_CHANNEL]; /* Available channels Index */
+ u8 byPower[CB_MAX_CHANNEL];
} ChannelRuleTab[] =
{
/************************************************************************
@@ -368,7 +360,6 @@ static struct
/* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 */
};
-/*--------------------- Export function -------------------------*/
/************************************************************************
* Country Channel Valid
* Input: CountryCode, ChannelNum
@@ -410,32 +401,6 @@ exit:
} /* end ChannelValid */
-/************************************************************************
- * CHvChannelGetList
- * Get Available Channel List for a given country
- * Input:
- * CountryCode = The country code defined in country.h
- * Output:
- * ChannelBitMask = (QWORD *) correspondent bit mask
- * of available channels
- * 0x0000000000000001 means channel 1 is supported
- * 0x0000000000000003 means channel 1,2 are supported
- * 0x000000000000000F means channel 1,2,..15 are supported
- ************************************************************************/
-bool
-CHvChannelGetList (
- unsigned int uCountryCodeIdx,
- PBYTE pbyChannelTable
- )
-{
- if (uCountryCodeIdx >= CCODE_MAX) {
- return (false);
- }
- memcpy(pbyChannelTable, ChannelRuleTab[uCountryCodeIdx].bChannelIdxList, CB_MAX_CHANNEL);
- return (true);
-}
-
-
void CHvInitChannelTable(struct vnt_private *pDevice)
{
int bMultiBand = false;
@@ -507,15 +472,3 @@ void CHvInitChannelTable(struct vnt_private *pDevice)
}*/
}
}
-
-BYTE CHbyGetChannelMapping(BYTE byChannelNumber)
-{
-BYTE ii;
-BYTE byCHMapping = 0;
-
- for (ii = 1; ii <= CB_MAX_CHANNEL; ii++) {
- if (sChannelTbl[ii].byChannelNumber == byChannelNumber)
- byCHMapping = ii;
- }
- return byCHMapping;
-}
diff --git a/drivers/staging/vt6656/channel.h b/drivers/staging/vt6656/channel.h
index 9914dba0ba0c..95701e0cbee3 100644
--- a/drivers/staging/vt6656/channel.h
+++ b/drivers/staging/vt6656/channel.h
@@ -31,26 +31,14 @@
#define _CHANNEL_H_
#include "device.h"
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
typedef struct tagSChannelTblElement {
- BYTE byChannelNumber;
+ u8 byChannelNumber;
unsigned int uFrequency;
bool bValid;
} SChannelTblElement, *PSChannelTblElement;
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
bool ChannelValid(unsigned int CountryCode, unsigned int ChannelNum);
void CHvInitChannelTable(struct vnt_private *pDevice);
-BYTE CHbyGetChannelMapping(BYTE byChannelNumber);
-
-bool CHvChannelGetList(unsigned int uCountryCodeIdx, PBYTE pbyChannelTable);
#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6656/control.c b/drivers/staging/vt6656/control.c
index 743ef5fb7fe7..026784fcde82 100644
--- a/drivers/staging/vt6656/control.c
+++ b/drivers/staging/vt6656/control.c
@@ -43,18 +43,8 @@
#include "control.h"
#include "rndis.h"
-/*--------------------- Static Definitions -------------------------*/
/* static int msglevel =MSG_LEVEL_INFO; */
/* static int msglevel =MSG_LEVEL_DEBUG; */
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
void ControlvWriteByte(struct vnt_private *pDevice, u8 reg, u8 reg_off,
u8 data)
diff --git a/drivers/staging/vt6656/control.h b/drivers/staging/vt6656/control.h
index 76ce0244e100..9da9b96add70 100644
--- a/drivers/staging/vt6656/control.h
+++ b/drivers/staging/vt6656/control.h
@@ -30,12 +30,9 @@
#ifndef __CONTROL_H__
#define __CONTROL_H__
-#include "ttype.h"
#include "device.h"
#include "usbpipe.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define CONTROLnsRequestOut(Device, Request, Value, Index, Length, Buffer) \
PIPEnsControlOut(Device, Request, Value, Index, Length, Buffer)
@@ -45,12 +42,6 @@
#define CONTROLnsRequestIn(Device, Request, Value, Index, Length, Buffer) \
PIPEnsControlIn(Device, Request, Value, Index, Length, Buffer)
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void ControlvWriteByte(struct vnt_private *pDevice, u8 reg, u8 reg_off,
u8 data);
@@ -60,5 +51,4 @@ void ControlvReadByte(struct vnt_private *pDevice, u8 reg, u8 reg_off,
void ControlvMaskByte(struct vnt_private *pDevice, u8 reg_type, u8 reg_off,
u8 reg_mask, u8 data);
-
#endif /* __CONTROL_H__ */
diff --git a/drivers/staging/vt6656/country.h b/drivers/staging/vt6656/country.h
index 7bdc8d47aedb..a0320d8f1362 100644
--- a/drivers/staging/vt6656/country.h
+++ b/drivers/staging/vt6656/country.h
@@ -156,7 +156,6 @@ typedef enum _COUNTRY_CODE {
CCODE_MAX
} COUNTRY_CODE;
-
/************************************************************************
* Function prototype
************************************************************************/
diff --git a/drivers/staging/vt6656/datarate.c b/drivers/staging/vt6656/datarate.c
index 77464e819f6d..17fbc35ebcbf 100644
--- a/drivers/staging/vt6656/datarate.c
+++ b/drivers/staging/vt6656/datarate.c
@@ -33,7 +33,6 @@
*
*/
-#include "ttype.h"
#include "tmacro.h"
#include "mac.h"
#include "80211mgr.h"
@@ -44,33 +43,20 @@
#include "srom.h"
#include "rf.h"
-/*--------------------- Static Definitions -------------------------*/
-
-
-
-
-/*--------------------- Static Classes ----------------------------*/
-
-
-
-/*--------------------- Static Variables --------------------------*/
-
/* static int msglevel = MSG_LEVEL_DEBUG; */
static int msglevel =MSG_LEVEL_INFO;
-const BYTE acbyIERate[MAX_RATE] =
+const u8 acbyIERate[MAX_RATE] =
{0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
#define AUTORATE_TXOK_CNT 0x0400
#define AUTORATE_TXFAIL_CNT 0x0064
#define AUTORATE_TIMEOUT 10
-/*--------------------- Static Functions --------------------------*/
-
void s_vResetCounter(PKnownNodeDB psNodeDBTable);
void s_vResetCounter(PKnownNodeDB psNodeDBTable)
{
- BYTE ii;
+ u8 ii;
/* clear statistics counter for auto_rate */
for (ii = 0; ii <= MAX_RATE; ii++) {
@@ -79,45 +65,6 @@ void s_vResetCounter(PKnownNodeDB psNodeDBTable)
}
}
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
-
-/*+
- *
- * Description:
- * Get RateIdx from the value in SuppRates IE or ExtSuppRates IE
- *
- * Parameters:
- * In:
- * BYTE - Rate value in SuppRates IE or ExtSuppRates IE
- * Out:
- * none
- *
- * Return Value: RateIdx
- *
--*/
-BYTE
-DATARATEbyGetRateIdx (
- BYTE byRate
- )
-{
- BYTE ii;
-
- /* erase BasicRate flag */
- byRate = byRate & 0x7F;
-
- for (ii = 0; ii < MAX_RATE; ii ++) {
- if (acbyIERate[ii] == byRate)
- return ii;
- }
- return 0;
-}
-
-
-
/*+
*
* Routine Description:
@@ -136,9 +83,6 @@ DATARATEbyGetRateIdx (
#define AUTORATE_TXCNT_THRESHOLD 20
#define AUTORATE_INC_THRESHOLD 30
-
-
-
/*+
*
* Description:
@@ -146,19 +90,19 @@ DATARATEbyGetRateIdx (
*
* Parameters:
* In:
- * BYTE - Rate value in SuppRates IE or ExtSuppRates IE
+ * u8 - Rate value in SuppRates IE or ExtSuppRates IE
* Out:
* none
*
* Return Value: RateIdx
*
-*/
-WORD
+u16
RATEwGetRateIdx(
- BYTE byRate
+ u8 byRate
)
{
- WORD ii;
+ u16 ii;
/* erase BasicRate flag */
byRate = byRate & 0x7F;
@@ -216,7 +160,7 @@ void RATEvParseMaxRate(struct vnt_private *pDevice,
}
for (ii = 0; ii < uRateLen; ii++) {
- byRate = (BYTE)(pItemRates->abyRates[ii]);
+ byRate = (u8)(pItemRates->abyRates[ii]);
if (WLAN_MGMT_IS_BASICRATE(byRate) &&
(bUpdateBasicRate == true)) {
/*
@@ -226,7 +170,7 @@ void RATEvParseMaxRate(struct vnt_private *pDevice,
CARDbAddBasicRate((void *)pDevice, RATEwGetRateIdx(byRate));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", RATEwGetRateIdx(byRate));
}
- byRate = (BYTE)(pItemRates->abyRates[ii]&0x7F);
+ byRate = (u8)(pItemRates->abyRates[ii]&0x7F);
if (byHighSuppRate == 0)
byHighSuppRate = byRate;
if (byRate > byHighSuppRate)
@@ -242,7 +186,7 @@ void RATEvParseMaxRate(struct vnt_private *pDevice,
uExtRateLen = WLAN_RATES_MAXLEN;
for (ii = 0; ii < uExtRateLen ; ii++) {
- byRate = (BYTE)(pItemExtRates->abyRates[ii]);
+ byRate = (u8)(pItemExtRates->abyRates[ii]);
/* select highest basic rate */
if (WLAN_MGMT_IS_BASICRATE(pItemExtRates->abyRates[ii])) {
/*
@@ -252,7 +196,7 @@ void RATEvParseMaxRate(struct vnt_private *pDevice,
CARDbAddBasicRate((void *)pDevice, RATEwGetRateIdx(byRate));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ParseMaxRate AddBasicRate: %d\n", RATEwGetRateIdx(byRate));
}
- byRate = (BYTE)(pItemExtRates->abyRates[ii]&0x7F);
+ byRate = (u8)(pItemExtRates->abyRates[ii]&0x7F);
if (byHighSuppRate == 0)
byHighSuppRate = byRate;
if (byRate > byHighSuppRate)
@@ -282,7 +226,6 @@ void RATEvParseMaxRate(struct vnt_private *pDevice,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Exit ParseMaxRate\n");
}
-
/*+
*
* Routine Description:
@@ -336,7 +279,7 @@ void RATEvTxRateFallBack(struct vnt_private *pDevice,
for (ii = 0; ii < MAX_RATE; ii++) {
if (psNodeDBTable->wSuppRate & (0x0001<<ii)) {
if (bAutoRate[ii] == true) {
- wIdxUpRate = (WORD) ii;
+ wIdxUpRate = (u16) ii;
}
} else {
bAutoRate[ii] = false;
@@ -363,7 +306,7 @@ void RATEvTxRateFallBack(struct vnt_private *pDevice,
if ( (dwThroughputTbl[ii] > dwThroughput) &&
(bAutoRate[ii]==true) ) {
dwThroughput = dwThroughputTbl[ii];
- wIdxDownRate = (WORD) ii;
+ wIdxDownRate = (u16) ii;
}
}
psNodeDBTable->wTxDataRate = wIdxDownRate;
@@ -400,7 +343,7 @@ void RATEvTxRateFallBack(struct vnt_private *pDevice,
* Return Value: None
*
-*/
-BYTE
+u8
RATEuSetIE (
PWLAN_IE_SUPP_RATES pSrcRates,
PWLAN_IE_SUPP_RATES pDstRates,
@@ -423,6 +366,6 @@ RATEuSetIE (
}
}
}
- return (BYTE)uRateCnt;
+ return (u8)uRateCnt;
}
diff --git a/drivers/staging/vt6656/datarate.h b/drivers/staging/vt6656/datarate.h
index 8dc55bd61669..43cb77894b66 100644
--- a/drivers/staging/vt6656/datarate.h
+++ b/drivers/staging/vt6656/datarate.h
@@ -29,9 +29,6 @@
#ifndef __DATARATE_H__
#define __DATARATE_H__
-
-/*--------------------- Export Definitions -------------------------*/
-
#define FALLBACK_PKT_COLLECT_TR_H 50 /* pkts */
#define FALLBACK_PKT_COLLECT_TR_L 10 /* pkts */
#define FALLBACK_POLL_SECOND 5 /* 5 sec */
@@ -57,18 +54,6 @@
#define RATE_AUTO 12
#define MAX_RATE 12
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Types ------------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
-
-
void RATEvParseMaxRate(struct vnt_private *, PWLAN_IE_SUPP_RATES pItemRates,
PWLAN_IE_SUPP_RATES pItemExtRates, int bUpdateBasicRate,
u16 *pwMaxBasicRate, u16 *pwMaxSuppRate, u16 *pwSuppRate,
@@ -77,22 +62,16 @@ void RATEvParseMaxRate(struct vnt_private *, PWLAN_IE_SUPP_RATES pItemRates,
void RATEvTxRateFallBack(struct vnt_private *pDevice,
PKnownNodeDB psNodeDBTable);
-BYTE
+u8
RATEuSetIE(
PWLAN_IE_SUPP_RATES pSrcRates,
PWLAN_IE_SUPP_RATES pDstRates,
unsigned int uRateLen
);
-WORD
+u16
RATEwGetRateIdx(
- BYTE byRate
- );
-
-
-BYTE
-DATARATEbyGetRateIdx(
- BYTE byRate
+ u8 byRate
);
#endif /* __DATARATE_H__ */
diff --git a/drivers/staging/vt6656/desc.h b/drivers/staging/vt6656/desc.h
index 0c0b614aaa11..64cb046fe988 100644
--- a/drivers/staging/vt6656/desc.h
+++ b/drivers/staging/vt6656/desc.h
@@ -33,7 +33,7 @@
#include <linux/types.h>
#include <linux/mm.h>
-#include "ttype.h"
+
#include "tether.h"
/* max transmit or receive buffer size */
@@ -147,38 +147,38 @@
* RsvTime buffer header
*/
typedef struct tagSRrvTime_gRTS {
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
} __attribute__ ((__packed__))
SRrvTime_gRTS, *PSRrvTime_gRTS;
typedef const SRrvTime_gRTS *PCSRrvTime_gRTS;
typedef struct tagSRrvTime_gCTS {
- WORD wCTSTxRrvTime_ba;
- WORD wReserved;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
} __attribute__ ((__packed__))
SRrvTime_gCTS, *PSRrvTime_gCTS;
typedef const SRrvTime_gCTS *PCSRrvTime_gCTS;
typedef struct tagSRrvTime_ab {
- WORD wRTSTxRrvTime;
- WORD wTxRrvTime;
+ u16 wRTSTxRrvTime;
+ u16 wTxRrvTime;
} __attribute__ ((__packed__))
SRrvTime_ab, *PSRrvTime_ab;
typedef const SRrvTime_ab *PCSRrvTime_ab;
typedef struct tagSRrvTime_atim {
- WORD wCTSTxRrvTime_ba;
- WORD wTxRrvTime_a;
+ u16 wCTSTxRrvTime_ba;
+ u16 wTxRrvTime_a;
} __attribute__ ((__packed__))
SRrvTime_atim, *PSRrvTime_atim;
@@ -188,46 +188,46 @@ typedef const SRrvTime_atim *PCSRrvTime_atim;
* RTS buffer header
*/
typedef struct tagSRTSData {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- BYTE abyTA[ETH_ALEN];
+ u16 wFrameControl;
+ u16 wDurationID;
+ u8 abyRA[ETH_ALEN];
+ u8 abyTA[ETH_ALEN];
} __attribute__ ((__packed__))
SRTSData, *PSRTSData;
typedef const SRTSData *PCSRTSData;
typedef struct tagSRTS_g {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_ba;
- WORD wDuration_aa;
- WORD wDuration_bb;
- WORD wReserved;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_ba;
+ u16 wDuration_aa;
+ u16 wDuration_bb;
+ u16 wReserved;
SRTSData Data;
} __attribute__ ((__packed__))
SRTS_g, *PSRTS_g;
typedef const SRTS_g *PCSRTS_g;
typedef struct tagSRTS_g_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_ba;
- WORD wDuration_aa;
- WORD wDuration_bb;
- WORD wReserved;
- WORD wRTSDuration_ba_f0;
- WORD wRTSDuration_aa_f0;
- WORD wRTSDuration_ba_f1;
- WORD wRTSDuration_aa_f1;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_ba;
+ u16 wDuration_aa;
+ u16 wDuration_bb;
+ u16 wReserved;
+ u16 wRTSDuration_ba_f0;
+ u16 wRTSDuration_aa_f0;
+ u16 wRTSDuration_ba_f1;
+ u16 wRTSDuration_aa_f1;
SRTSData Data;
} __attribute__ ((__packed__))
SRTS_g_FB, *PSRTS_g_FB;
@@ -235,11 +235,11 @@ SRTS_g_FB, *PSRTS_g_FB;
typedef const SRTS_g_FB *PCSRTS_g_FB;
typedef struct tagSRTS_ab {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wReserved;
+ u8 bySignalField;
+ u8 byServiceField;
+ u16 wTransmitLength;
+ u16 wDuration;
+ u16 wReserved;
SRTSData Data;
} __attribute__ ((__packed__))
SRTS_ab, *PSRTS_ab;
@@ -247,13 +247,13 @@ SRTS_ab, *PSRTS_ab;
typedef const SRTS_ab *PCSRTS_ab;
typedef struct tagSRTS_a_FB {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wReserved;
- WORD wRTSDuration_f0;
- WORD wRTSDuration_f1;
+ u8 bySignalField;
+ u8 byServiceField;
+ u16 wTransmitLength;
+ u16 wDuration;
+ u16 wReserved;
+ u16 wRTSDuration_f0;
+ u16 wRTSDuration_f1;
SRTSData Data;
} __attribute__ ((__packed__))
SRTS_a_FB, *PSRTS_a_FB;
@@ -264,19 +264,19 @@ typedef const SRTS_a_FB *PCSRTS_a_FB;
* CTS buffer header
*/
typedef struct tagSCTSData {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- WORD wReserved;
+ u16 wFrameControl;
+ u16 wDurationID;
+ u8 abyRA[ETH_ALEN];
+ u16 wReserved;
} __attribute__ ((__packed__))
SCTSData, *PSCTSData;
typedef struct tagSCTS {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- WORD wDuration_ba;
- WORD wReserved;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u16 wDuration_ba;
+ u16 wReserved;
SCTSData Data;
} __attribute__ ((__packed__))
SCTS, *PSCTS;
@@ -284,13 +284,13 @@ SCTS, *PSCTS;
typedef const SCTS *PCSCTS;
typedef struct tagSCTS_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- WORD wDuration_ba;
- WORD wReserved;
- WORD wCTSDuration_ba_f0;
- WORD wCTSDuration_ba_f1;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u16 wDuration_ba;
+ u16 wReserved;
+ u16 wCTSDuration_ba_f0;
+ u16 wCTSDuration_ba_f1;
SCTSData Data;
} __attribute__ ((__packed__))
SCTS_FB, *PSCTS_FB;
@@ -302,17 +302,17 @@ typedef const SCTS_FB *PCSCTS_FB;
*/
typedef struct tagSTxBufHead {
u32 adwTxKey[4];
- WORD wFIFOCtl;
- WORD wTimeStamp;
- WORD wFragCtl;
- WORD wReserved;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
+ u16 wFragCtl;
+ u16 wReserved;
} __attribute__ ((__packed__))
STxBufHead, *PSTxBufHead;
typedef const STxBufHead *PCSTxBufHead;
typedef struct tagSTxShortBufHead {
- WORD wFIFOCtl;
- WORD wTimeStamp;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
} __attribute__ ((__packed__))
STxShortBufHead, *PSTxShortBufHead;
typedef const STxShortBufHead *PCSTxShortBufHead;
@@ -321,56 +321,56 @@ typedef const STxShortBufHead *PCSTxShortBufHead;
* TX data header
*/
typedef struct tagSTxDataHead_g {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} __attribute__ ((__packed__))
STxDataHead_g, *PSTxDataHead_g;
typedef const STxDataHead_g *PCSTxDataHead_g;
typedef struct tagSTxDataHead_g_FB {
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} __attribute__ ((__packed__))
STxDataHead_g_FB, *PSTxDataHead_g_FB;
typedef const STxDataHead_g_FB *PCSTxDataHead_g_FB;
typedef struct tagSTxDataHead_ab {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wTimeStampOff;
+ u8 bySignalField;
+ u8 byServiceField;
+ u16 wTransmitLength;
+ u16 wDuration;
+ u16 wTimeStampOff;
} __attribute__ ((__packed__))
STxDataHead_ab, *PSTxDataHead_ab;
typedef const STxDataHead_ab *PCSTxDataHead_ab;
typedef struct tagSTxDataHead_a_FB {
- BYTE bySignalField;
- BYTE byServiceField;
- WORD wTransmitLength;
- WORD wDuration;
- WORD wTimeStampOff;
- WORD wDuration_f0;
- WORD wDuration_f1;
+ u8 bySignalField;
+ u8 byServiceField;
+ u16 wTransmitLength;
+ u16 wDuration;
+ u16 wTimeStampOff;
+ u16 wDuration_f0;
+ u16 wDuration_f1;
} __attribute__ ((__packed__))
STxDataHead_a_FB, *PSTxDataHead_a_FB;
typedef const STxDataHead_a_FB *PCSTxDataHead_a_FB;
@@ -397,14 +397,14 @@ SBEACONCtl;
typedef struct tagSSecretKey {
u32 dwLowDword;
- BYTE byHighByte;
+ u8 byHighByte;
} __attribute__ ((__packed__))
SSecretKey;
typedef struct tagSKeyEntry {
- BYTE abyAddrHi[2];
- WORD wKCTL;
- BYTE abyAddrLo[4];
+ u8 abyAddrHi[2];
+ u16 wKCTL;
+ u8 abyAddrLo[4];
u32 dwKey0[4];
u32 dwKey1[4];
u32 dwKey2[4];
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index 6bba2e06fa64..f07ba242811b 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -45,7 +45,6 @@
#include <linux/timer.h>
#include <linux/usb.h>
-
#ifdef SIOCETHTOOL
#define DEVICE_ETHTOOL_IOCTL_SUPPORT
#include <linux/ethtool.h>
@@ -66,7 +65,6 @@
*/
#include "device_cfg.h"
-#include "ttype.h"
#include "80211hdr.h"
#include "tether.h"
#include "wmgr.h"
@@ -78,7 +76,6 @@
#include "key.h"
#include "card.h"
-/*--------------------- Export Definitions -------------------------*/
#define VNT_USB_VENDOR_ID 0x160a
#define VNT_USB_PRODUCT_ID 0x3184
@@ -122,7 +119,6 @@
#define ANT_RXA 2
#define ANT_RXB 3
-
#define MAXCHECKHANGCNT 4
/* Packet type */
@@ -142,8 +138,6 @@
#define PRIVATE_Message 0
-/*--------------------- Export Types ------------------------------*/
-
#define DBG_PRT(l, p, args...) { if (l <= msglevel) printk(p, ##args); }
#define PRINT_K(p, args...) { if (PRIVATE_Message) printk(p, ##args); }
@@ -191,7 +185,7 @@ typedef struct _USB_SEND_CONTEXT {
struct urb *pUrb;
unsigned int uBufLen;
CONTEXT_TYPE Type;
- SEthernetHeader sEthHeader;
+ struct ethhdr sEthHeader;
void *Next;
bool bBoolInUse;
unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
@@ -212,7 +206,7 @@ typedef struct _DEFAULT_CONFIG {
*/
typedef struct {
unsigned int uDataLen;
- PBYTE pDataBuf;
+ u8 * pDataBuf;
/* struct urb *pUrb; */
bool bInUse;
} INT_BUFFER, *PINT_BUFFER;
@@ -251,7 +245,6 @@ typedef enum __DEVICE_NDIS_STATUS {
/* PMKID Structures */
typedef unsigned char NDIS_802_11_PMKID_VALUE[16];
-
typedef enum _NDIS_802_11_WEP_STATUS
{
Ndis802_11WEPEnabled,
@@ -269,7 +262,6 @@ typedef enum _NDIS_802_11_WEP_STATUS
} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
typedef enum _NDIS_802_11_STATUS_TYPE
{
Ndis802_11StatusType_Authentication,
@@ -284,7 +276,6 @@ typedef struct _PMKID_CANDIDATE {
unsigned long Flags;
} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
typedef struct _BSSID_INFO
{
NDIS_802_11_MAC_ADDRESS BSSID;
@@ -309,16 +300,16 @@ typedef struct tagSPMKIDCandidateEvent {
typedef struct tagSQuietControl {
bool bEnable;
- DWORD dwStartTime;
- BYTE byPeriod;
- WORD wDuration;
+ u32 dwStartTime;
+ u8 byPeriod;
+ u16 wDuration;
} SQuietControl, *PSQuietControl;
/* The receive duplicate detection cache entry */
typedef struct tagSCacheEntry{
- WORD wFmSequence;
- BYTE abyAddr2[ETH_ALEN];
- WORD wFrameCtl;
+ u16 wFmSequence;
+ u8 abyAddr2[ETH_ALEN];
+ u16 wFrameCtl;
} SCacheEntry, *PSCacheEntry;
typedef struct tagSCache{
@@ -335,12 +326,12 @@ typedef struct tagSCache{
*/
typedef struct tagSDeFragControlBlock
{
- WORD wSequence;
- WORD wFragNum;
- BYTE abyAddr2[ETH_ALEN];
+ u16 wSequence;
+ u16 wFragNum;
+ u8 abyAddr2[ETH_ALEN];
unsigned int uLifetime;
struct sk_buff* skb;
- PBYTE pbyRxBuffer;
+ u8 * pbyRxBuffer;
unsigned int cbFrameLength;
bool bInUse;
} SDeFragControlBlock, *PSDeFragControlBlock;
@@ -371,7 +362,6 @@ typedef struct tagSDeFragControlBlock
/* for device_set_media_duplex */
#define DEVICE_LINK_CHANGE 0x00000001UL
-
typedef struct __device_opt {
int nRxDescs0; /* number of RX descriptors 0 */
int nTxDescs0; /* number of TX descriptors 0, 1, 2, 3 */
@@ -386,7 +376,6 @@ typedef struct __device_opt {
u32 flags;
} OPTIONS, *POPTIONS;
-
struct vnt_private {
/* netdev */
struct usb_device *usb;
@@ -420,7 +409,6 @@ struct vnt_private {
u32 cbFreeDFCB;
u32 uCurrentDFCBIdx;
-
/* USB */
struct urb *pControlURB;
struct urb *pInterruptURB;
@@ -453,7 +441,6 @@ struct vnt_private {
/* default config from file by user setting */
DEFAULT_CONFIG config_file;
-
/* Statistic for USB */
unsigned long ulBulkInPosted;
unsigned long ulBulkInError;
@@ -470,14 +457,12 @@ struct vnt_private {
unsigned long ulIntInContCRCError;
unsigned long ulIntInBytesRead;
-
/* Version control */
u16 wFirmwareVersion;
u8 byLocalID;
u8 byRFType;
u8 byBBRxConf;
-
u8 byZoneType;
int bZoneRegExist;
@@ -571,7 +556,6 @@ struct vnt_private {
u8 byTopOFDMBasicRate;
u8 byTopCCKBasicRate;
-
u32 dwAotoRateTxOkCnt;
u32 dwAotoRateTxFailCnt;
u32 dwErrorRateThreshold[13];
@@ -684,7 +668,6 @@ struct vnt_private {
SKeyManagement sKey;
u32 dwIVCounter;
-
RC4Ext SBox;
u8 abyPRNG[WLAN_WEPMAX_KEYLEN+3];
u8 byKeyIndex;
@@ -701,13 +684,11 @@ struct vnt_private {
/* QoS */
int bGrpAckPolicy;
-
u8 byAutoFBCtrl;
int bTxMICFail;
int bRxMICFail;
-
/* For Update BaseBand VGA Gain Offset */
int bUpdateBBVGA;
u32 uBBVGADiffCount;
@@ -719,7 +700,6 @@ struct vnt_private {
u8 byBBPreEDRSSI;
u8 byBBPreEDIndex;
-
int bRadioCmd;
u32 dwDiagRefCount;
@@ -747,8 +727,8 @@ struct vnt_private {
u8 byReAssocCount;
u8 byLinkWaitCount;
- SEthernetHeader sTxEthHeader;
- SEthernetHeader sRxEthHeader;
+ struct ethhdr sTxEthHeader;
+ struct ethhdr sRxEthHeader;
u8 abyBroadcastAddr[ETH_ALEN];
u8 abySNAP_RFC1042[ETH_ALEN];
u8 abySNAP_Bridgetunnel[ETH_ALEN];
@@ -757,7 +737,6 @@ struct vnt_private {
SPMKID gsPMKID;
SPMKIDCandidateEvent gsPMKIDCandidate;
-
/* for 802.11h */
int b11hEnable;
@@ -788,9 +767,6 @@ struct vnt_private {
};
-
-
-
#define EnqueueRCB(_Head, _Tail, _RCB) \
{ \
if (!_Head) { \
@@ -812,7 +788,6 @@ struct vnt_private {
Head = RCB->Next; \
}
-
#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) { \
if ((uVar) >= ((uModulo) - 1)) \
(uVar) = 0; \
@@ -820,7 +795,6 @@ struct vnt_private {
(uVar)++; \
}
-
#define fMP_RESET_IN_PROGRESS 0x00000001
#define fMP_DISCONNECTED 0x00000002
#define fMP_HALT_IN_PROGRESS 0x00000004
@@ -841,8 +815,6 @@ struct vnt_private {
#define MP_IS_READY(_M) (((_M)->Flags & \
(fMP_DISCONNECTED | fMP_RESET_IN_PROGRESS | fMP_HALT_IN_PROGRESS | fMP_INIT_IN_PROGRESS | fMP_SURPRISE_REMOVED)) == 0)
-/*--------------------- Export Functions --------------------------*/
-
int device_alloc_frag_buf(struct vnt_private *, PSDeFragControlBlock pDeF);
#endif
diff --git a/drivers/staging/vt6656/device_cfg.h b/drivers/staging/vt6656/device_cfg.h
index 62290d0ac195..ea66b975fa5b 100644
--- a/drivers/staging/vt6656/device_cfg.h
+++ b/drivers/staging/vt6656/device_cfg.h
@@ -29,8 +29,6 @@
#include <linux/types.h>
-#include "ttype.h"
-
typedef
struct _version {
unsigned char major;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index e83f95e1d9a8..7ec166a2ac81 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -56,32 +56,20 @@
#include "datarate.h"
#include "usbpipe.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-const BYTE acbyRxRate[MAX_RATE] =
+const u8 acbyRxRate[MAX_RATE] =
{2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108};
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-static BYTE s_byGetRateIdx(BYTE byRate);
+static u8 s_byGetRateIdx(u8 byRate);
static
void
s_vGetDASA(
- PBYTE pbyRxBufferAddr,
+ u8 * pbyRxBufferAddr,
unsigned int *pcbHeaderSize,
- PSEthernetHeader psEthHeader
+ struct ethhdr *psEthHeader
);
static void s_vProcessRxMACHeader(struct vnt_private *pDevice,
@@ -102,8 +90,6 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
u32 FrameSize, u8 *pbyRsr, int bOnFly, PSKeyItem pKey, u8 *pbyNewRsr,
s32 *pbExtIV, u16 *pwRxTSC15_0, u32 *pdwRxTSC47_16);
-/*--------------------- Export Variables --------------------------*/
-
/*+
*
* Description:
@@ -129,13 +115,12 @@ static void s_vProcessRxMACHeader(struct vnt_private *pDevice,
u8 *pbyRxBuffer;
u32 cbHeaderSize = 0;
u16 *pwType;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
int ii;
+ pMACHeader = (struct ieee80211_hdr *) (pbyRxBufferAddr + cbHeaderSize);
- pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
-
- s_vGetDASA((PBYTE)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
+ s_vGetDASA((u8 *)pMACHeader, &cbHeaderSize, &pDevice->sRxEthHeader);
if (bIsWEP) {
if (bExtIV) {
@@ -150,16 +135,16 @@ static void s_vProcessRxMACHeader(struct vnt_private *pDevice,
cbHeaderSize += WLAN_HDR_ADDR3_LEN;
};
- pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize);
+ pbyRxBuffer = (u8 *) (pbyRxBufferAddr + cbHeaderSize);
if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_Bridgetunnel[0])) {
cbHeaderSize += 6;
} else if (!compare_ether_addr(pbyRxBuffer, &pDevice->abySNAP_RFC1042[0])) {
cbHeaderSize += 6;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (u16 *) (pbyRxBufferAddr + cbHeaderSize);
if ((*pwType == cpu_to_be16(ETH_P_IPX)) ||
(*pwType == cpu_to_le16(0xF380))) {
cbHeaderSize -= 8;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (u16 *) (pbyRxBufferAddr + cbHeaderSize);
if (bIsWEP) {
if (bExtIV) {
*pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
@@ -174,7 +159,7 @@ static void s_vProcessRxMACHeader(struct vnt_private *pDevice,
}
else {
cbHeaderSize -= 2;
- pwType = (PWORD) (pbyRxBufferAddr + cbHeaderSize);
+ pwType = (u16 *) (pbyRxBufferAddr + cbHeaderSize);
if (bIsWEP) {
if (bExtIV) {
*pwType = htons(cbPacketSize - WLAN_HDR_ADDR3_LEN - 8); // 8 is IV&ExtIV
@@ -188,21 +173,18 @@ static void s_vProcessRxMACHeader(struct vnt_private *pDevice,
}
cbHeaderSize -= (ETH_ALEN * 2);
- pbyRxBuffer = (PBYTE) (pbyRxBufferAddr + cbHeaderSize);
+ pbyRxBuffer = (u8 *) (pbyRxBufferAddr + cbHeaderSize);
for (ii = 0; ii < ETH_ALEN; ii++)
- *pbyRxBuffer++ = pDevice->sRxEthHeader.abyDstAddr[ii];
+ *pbyRxBuffer++ = pDevice->sRxEthHeader.h_dest[ii];
for (ii = 0; ii < ETH_ALEN; ii++)
- *pbyRxBuffer++ = pDevice->sRxEthHeader.abySrcAddr[ii];
+ *pbyRxBuffer++ = pDevice->sRxEthHeader.h_source[ii];
*pcbHeadSize = cbHeaderSize;
}
-
-
-
-static BYTE s_byGetRateIdx(BYTE byRate)
+static u8 s_byGetRateIdx(u8 byRate)
{
- BYTE byRateIdx;
+ u8 byRateIdx;
for (byRateIdx = 0; byRateIdx <MAX_RATE ; byRateIdx++) {
if (acbyRxRate[byRateIdx%MAX_RATE] == byRate)
@@ -211,61 +193,59 @@ static BYTE s_byGetRateIdx(BYTE byRate)
return 0;
}
-
static
void
s_vGetDASA (
- PBYTE pbyRxBufferAddr,
+ u8 * pbyRxBufferAddr,
unsigned int *pcbHeaderSize,
- PSEthernetHeader psEthHeader
+ struct ethhdr *psEthHeader
)
{
unsigned int cbHeaderSize = 0;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
int ii;
- pMACHeader = (PS802_11Header) (pbyRxBufferAddr + cbHeaderSize);
+ pMACHeader = (struct ieee80211_hdr *) (pbyRxBufferAddr + cbHeaderSize);
- if ((pMACHeader->wFrameCtl & FC_TODS) == 0) {
- if (pMACHeader->wFrameCtl & FC_FROMDS) {
+ if ((pMACHeader->frame_control & FC_TODS) == 0) {
+ if (pMACHeader->frame_control & FC_FROMDS) {
for (ii = 0; ii < ETH_ALEN; ii++) {
- psEthHeader->abyDstAddr[ii] =
- pMACHeader->abyAddr1[ii];
- psEthHeader->abySrcAddr[ii] =
- pMACHeader->abyAddr3[ii];
+ psEthHeader->h_dest[ii] =
+ pMACHeader->addr1[ii];
+ psEthHeader->h_source[ii] =
+ pMACHeader->addr3[ii];
}
} else {
/* IBSS mode */
for (ii = 0; ii < ETH_ALEN; ii++) {
- psEthHeader->abyDstAddr[ii] =
- pMACHeader->abyAddr1[ii];
- psEthHeader->abySrcAddr[ii] =
- pMACHeader->abyAddr2[ii];
+ psEthHeader->h_dest[ii] =
+ pMACHeader->addr1[ii];
+ psEthHeader->h_source[ii] =
+ pMACHeader->addr2[ii];
}
}
} else {
/* Is AP mode.. */
- if (pMACHeader->wFrameCtl & FC_FROMDS) {
+ if (pMACHeader->frame_control & FC_FROMDS) {
for (ii = 0; ii < ETH_ALEN; ii++) {
- psEthHeader->abyDstAddr[ii] =
- pMACHeader->abyAddr3[ii];
- psEthHeader->abySrcAddr[ii] =
- pMACHeader->abyAddr4[ii];
+ psEthHeader->h_dest[ii] =
+ pMACHeader->addr3[ii];
+ psEthHeader->h_source[ii] =
+ pMACHeader->addr4[ii];
cbHeaderSize += 6;
}
} else {
for (ii = 0; ii < ETH_ALEN; ii++) {
- psEthHeader->abyDstAddr[ii] =
- pMACHeader->abyAddr3[ii];
- psEthHeader->abySrcAddr[ii] =
- pMACHeader->abyAddr2[ii];
+ psEthHeader->h_dest[ii] =
+ pMACHeader->addr3[ii];
+ psEthHeader->h_source[ii] =
+ pMACHeader->addr2[ii];
}
}
};
*pcbHeaderSize = cbHeaderSize;
}
-
int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
unsigned long BytesToIndicate)
{
@@ -273,7 +253,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
struct sk_buff *skb;
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
struct vnt_rx_mgmt *pRxPacket = &pMgmt->sRxPacket;
- PS802_11Header p802_11Header;
+ struct ieee80211_hdr *p802_11Header;
u8 *pbyRsr, *pbyNewRsr, *pbyRSSI, *pbyFrame;
u64 *pqwTSFTime;
u32 bDeFragRx = false;
@@ -297,10 +277,9 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
u8 abyVaildRate[MAX_RATE]
= {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108};
u16 wPLCPwithPadding;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
int bRxeapol_key = false;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---------- RXbBulkInProcessData---\n");
skb = pRCB->skb;
@@ -321,14 +300,14 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
return false;
}
- pbyDAddress = (PBYTE)(skb->data);
+ pbyDAddress = (u8 *)(skb->data);
pbyRxSts = pbyDAddress+4;
pbyRxRate = pbyDAddress+5;
//real Frame Size = USBFrameSize -4WbkStatus - 4RxStatus - 8TSF - 4RSR - 4SQ3 - ?Padding
//if SQ3 the range is 24~27, if no SQ3 the range is 20~23
//real Frame size in PLCPLength field.
- pwPLCP_Length = (PWORD) (pbyDAddress + 6);
+ pwPLCP_Length = (u16 *) (pbyDAddress + 6);
//Fix hardware bug => PLCP_Length error
if ( ((BytesToIndicate - (*pwPLCP_Length)) > 27) ||
((BytesToIndicate - (*pwPLCP_Length)) < 24) ||
@@ -377,45 +356,43 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
FrameSize
);
-
- pMACHeader = (PS802_11Header) pbyFrame;
+ pMACHeader = (struct ieee80211_hdr *) pbyFrame;
//mike add: to judge if current AP is activated?
if ((pMgmt->eCurrMode == WMAC_MODE_STANDBY) ||
(pMgmt->eCurrMode == WMAC_MODE_ESS_STA)) {
if (pMgmt->sNodeDBTable[0].bActive) {
- if (!compare_ether_addr(pMgmt->abyCurrBSSID, pMACHeader->abyAddr2)) {
+ if (!compare_ether_addr(pMgmt->abyCurrBSSID, pMACHeader->addr2)) {
if (pMgmt->sNodeDBTable[0].uInActiveCount != 0)
pMgmt->sNodeDBTable[0].uInActiveCount = 0;
}
}
}
- if (!is_multicast_ether_addr(pMACHeader->abyAddr1)) {
- if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) {
+ if (!is_multicast_ether_addr(pMACHeader->addr1)) {
+ if (WCTLbIsDuplicate(&(pDevice->sDupRxCache), (struct ieee80211_hdr *) pbyFrame)) {
pDevice->s802_11Counter.FrameDuplicateCount++;
return false;
}
if (compare_ether_addr(pDevice->abyCurrentNetAddr,
- pMACHeader->abyAddr1)) {
+ pMACHeader->addr1)) {
return false;
}
}
-
// Use for TKIP MIC
s_vGetDASA(pbyFrame, &cbHeaderSize, &pDevice->sRxEthHeader);
- if (!compare_ether_addr((PBYTE)&(pDevice->sRxEthHeader.abySrcAddr[0]),
+ if (!compare_ether_addr((u8 *)&(pDevice->sRxEthHeader.h_source[0]),
pDevice->abyCurrentNetAddr))
return false;
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) || (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA)) {
if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
- p802_11Header = (PS802_11Header) (pbyFrame);
+ p802_11Header = (struct ieee80211_hdr *) (pbyFrame);
// get SA NodeIndex
- if (BSSbIsSTAInNodeDB(pDevice, (PBYTE)(p802_11Header->abyAddr2), &iSANodeIndex)) {
+ if (BSSbIsSTAInNodeDB(pDevice, (u8 *)(p802_11Header->addr2), &iSANodeIndex)) {
pMgmt->sNodeDBTable[iSANodeIndex].ulLastRxJiffer = jiffies;
pMgmt->sNodeDBTable[iSANodeIndex].uInActiveCount = 0;
}
@@ -428,7 +405,6 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
}
-
if (IS_FC_WEP(pbyFrame)) {
bool bRxDecryOK = false;
@@ -497,7 +473,6 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
FrameSize -= 4; // 4 is ICV
}
-
//
// RX OK
//
@@ -508,7 +483,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
(IS_FRAGMENT_PKT((pbyFrame)))
) {
// defragment
- bDeFragRx = WCTLbHandleFragment(pDevice, (PS802_11Header) (pbyFrame), FrameSize, bIsWEP, bExtIV);
+ bDeFragRx = WCTLbHandleFragment(pDevice, (struct ieee80211_hdr *) (pbyFrame), FrameSize, bIsWEP, bExtIV);
pDevice->s802_11Counter.ReceivedFragmentCount++;
if (bDeFragRx) {
// defrag complete
@@ -529,8 +504,8 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
// Handle Control & Manage Frame
if (IS_TYPE_MGMT((pbyFrame))) {
- PBYTE pbyData1;
- PBYTE pbyData2;
+ u8 * pbyData1;
+ u8 * pbyData2;
pRxPacket = &(pRCB->sMngPacket);
pRxPacket->p80211Header = (PUWLAN_80211HDR)(pbyFrame);
@@ -622,10 +597,10 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
//mike add:station mode check eapol-key challenge--->
{
- BYTE Protocol_Version; //802.1x Authentication
- BYTE Packet_Type; //802.1x Authentication
- BYTE Descriptor_type;
- WORD Key_info;
+ u8 Protocol_Version; //802.1x Authentication
+ u8 Packet_Type; //802.1x Authentication
+ u8 Descriptor_type;
+ u16 Key_info;
if (bIsWEP)
cbIVOffset = 8;
else
@@ -653,10 +628,8 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
}
-
// Data frame Handle
-
if (pDevice->bEnablePSMode) {
if (IS_FC_MOREDATA((pbyFrame))) {
if (*pbyRsr & RSR_ADDROK) {
@@ -699,11 +672,10 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
*/
-
// -----------------------------------------------
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_AP) && (pDevice->bEnable8021x == true)){
- BYTE abyMacHdr[24];
+ u8 abyMacHdr[24];
// Only 802.1x packet incoming allowed
if (bIsWEP)
@@ -739,7 +711,6 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
return false;
}
-
if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
if (bIsWEP) {
FrameSize -= 8; //MIC
@@ -750,44 +721,42 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
// Soft MIC
if ((pKey != NULL) && (pKey->byCipherSuite == KEY_CTL_TKIP)) {
if (bIsWEP) {
- PDWORD pdwMIC_L;
- PDWORD pdwMIC_R;
- DWORD dwMIC_Priority;
- DWORD dwMICKey0 = 0, dwMICKey1 = 0;
- DWORD dwLocalMIC_L = 0;
- DWORD dwLocalMIC_R = 0;
-
+ u32 * pdwMIC_L;
+ u32 * pdwMIC_R;
+ u32 dwMIC_Priority;
+ u32 dwMICKey0 = 0, dwMICKey1 = 0;
+ u32 dwLocalMIC_L = 0;
+ u32 dwLocalMIC_R = 0;
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[28]));
}
else {
if (pMgmt->eAuthenMode == WMAC_AUTH_WPANONE) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[20]));
} else if ((pKey->dwKeyIndex & BIT28) == 0) {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[16]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[20]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[16]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[20]));
} else {
- dwMICKey0 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[24]));
- dwMICKey1 = cpu_to_le32(*(PDWORD)(&pKey->abyKey[28]));
+ dwMICKey0 = cpu_to_le32(*(u32 *)(&pKey->abyKey[24]));
+ dwMICKey1 = cpu_to_le32(*(u32 *)(&pKey->abyKey[28]));
}
}
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(pDevice->sRxEthHeader.abyDstAddr[0]), 12);
+ MIC_vAppend((u8 *)&(pDevice->sRxEthHeader.h_dest[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((u8 *)&dwMIC_Priority, 4);
// 4 is Rcv buffer header, 24 is MAC Header, and 8 is IV and Ext IV.
- MIC_vAppend((PBYTE)(skb->data + 8 + WLAN_HDR_ADDR3_LEN + 8),
+ MIC_vAppend((u8 *)(skb->data + 8 + WLAN_HDR_ADDR3_LEN + 8),
FrameSize - WLAN_HDR_ADDR3_LEN - 8);
MIC_vGetMIC(&dwLocalMIC_L, &dwLocalMIC_R);
MIC_vUnInit();
- pdwMIC_L = (PDWORD)(skb->data + 8 + FrameSize);
- pdwMIC_R = (PDWORD)(skb->data + 8 + FrameSize + 4);
-
+ pdwMIC_L = (u32 *)(skb->data + 8 + FrameSize);
+ pdwMIC_R = (u32 *)(skb->data + 8 + FrameSize + 4);
if ((cpu_to_le32(*pdwMIC_L) != dwLocalMIC_L) || (cpu_to_le32(*pdwMIC_R) != dwLocalMIC_R) ||
(pDevice->bRxMICFail == true)) {
@@ -818,7 +787,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
ev.src_addr.sa_family = ARPHRD_ETHER;
- memcpy(ev.src_addr.sa_data, pMACHeader->abyAddr2, ETH_ALEN);
+ memcpy(ev.src_addr.sa_data, pMACHeader->addr2, ETH_ALEN);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = sizeof(ev);
PRINT_K("wireless_send_event--->IWEVMICHAELMICFAILURE\n");
@@ -837,13 +806,13 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
if ((pKey != NULL) && ((pKey->byCipherSuite == KEY_CTL_TKIP) ||
(pKey->byCipherSuite == KEY_CTL_CCMP))) {
if (bIsWEP) {
- WORD wLocalTSC15_0 = 0;
- DWORD dwLocalTSC47_16 = 0;
+ u16 wLocalTSC15_0 = 0;
+ u32 dwLocalTSC47_16 = 0;
unsigned long long RSC = 0;
// endian issues
RSC = *((unsigned long long *) &(pKey->KeyRSC));
- wLocalTSC15_0 = (WORD) RSC;
- dwLocalTSC47_16 = (DWORD) (RSC>>16);
+ wLocalTSC15_0 = (u16) RSC;
+ dwLocalTSC47_16 = (u32) (RSC>>16);
RSC = dwRxTSC47_16;
RSC <<= 16;
@@ -876,8 +845,7 @@ int RXbBulkInProcessData(struct vnt_private *pDevice, PRCB pRCB,
}
} // ----- End of Reply Counter Check --------------------------
-
- s_vProcessRxMACHeader(pDevice, (PBYTE)(skb->data+8), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
+ s_vProcessRxMACHeader(pDevice, (u8 *)(skb->data+8), FrameSize, bIsWEP, bExtIV, &cbHeaderOffset);
FrameSize -= cbHeaderOffset;
cbHeaderOffset += 8; // 8 is Rcv buffer header
@@ -928,13 +896,12 @@ static int s_bAPModeRxCtl(struct vnt_private *pDevice, u8 *pbyFrame,
s32 iSANodeIndex)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
- PS802_11Header p802_11Header;
+ struct ieee80211_hdr *p802_11Header;
CMD_STATUS Status;
-
if (IS_CTL_PSPOLL(pbyFrame) || !IS_TYPE_CONTROL(pbyFrame)) {
- p802_11Header = (PS802_11Header) (pbyFrame);
+ p802_11Header = (struct ieee80211_hdr *) (pbyFrame);
if (!IS_TYPE_MGMT(pbyFrame)) {
// Data & PS-Poll packet
@@ -946,7 +913,7 @@ static int s_bAPModeRxCtl(struct vnt_private *pDevice, u8 *pbyFrame,
// reason = (6) class 2 received from nonauth sta
vMgrDeAuthenBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (u8 *)(p802_11Header->addr2),
(WLAN_MGMT_REASON_CLASS2_NONAUTH),
&Status
);
@@ -958,7 +925,7 @@ static int s_bAPModeRxCtl(struct vnt_private *pDevice, u8 *pbyFrame,
// reason = (7) class 3 received from nonassoc sta
vMgrDisassocBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (u8 *)(p802_11Header->addr2),
(WLAN_MGMT_REASON_CLASS3_NONASSOC),
&Status
);
@@ -1011,18 +978,18 @@ static int s_bAPModeRxCtl(struct vnt_private *pDevice, u8 *pbyFrame,
else {
vMgrDeAuthenBeginSta(pDevice,
pMgmt,
- (PBYTE)(p802_11Header->abyAddr2),
+ (u8 *)(p802_11Header->addr2),
(WLAN_MGMT_REASON_CLASS2_NONAUTH),
&Status
);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: send vMgrDeAuthenBeginSta 3\n");
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "BSSID:%pM\n",
- p802_11Header->abyAddr3);
+ p802_11Header->addr3);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR2:%pM\n",
- p802_11Header->abyAddr2);
+ p802_11Header->addr2);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "ADDR1:%pM\n",
- p802_11Header->abyAddr1);
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: wFrameCtl= %x\n", p802_11Header->wFrameCtl );
+ p802_11Header->addr1);
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "dpc: frame_control= %x\n", p802_11Header->frame_control);
return true;
}
}
@@ -1042,13 +1009,12 @@ static int s_bHandleRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
PSKeyItem pKey = NULL;
u8 byDecMode = KEY_CTL_WEP;
-
*pwRxTSC15_0 = 0;
*pdwRxTSC47_16 = 0;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) {
+ if ( WLAN_GET_FC_TODS(*(u16 *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(u16 *)pbyFrame) ) {
pbyIV += 6; // 6 is 802.11 address4
PayloadLen -= 6;
}
@@ -1136,12 +1102,12 @@ static int s_bHandleRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
// TKIP/AES
PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4));
+ *pdwRxTSC47_16 = cpu_to_le32(*(u32 *)(pbyIV + 4));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %x\n", *pdwRxTSC47_16);
if (byDecMode == KEY_CTL_TKIP) {
*pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
} else {
- *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV);
+ *pwRxTSC15_0 = cpu_to_le16(*(u16 *)pbyIV);
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
@@ -1149,8 +1115,8 @@ static int s_bHandleRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
(pDevice->byLocalID <= REV_ID_VT3253_A1)) {
// Software TKIP
// 1. 3253 A
- PS802_11Header pMACHeader = (PS802_11Header) (pbyFrame);
- TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
+ struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *) (pbyFrame);
+ TKIPvMixKey(pKey->abyKey, pMACHeader->addr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
@@ -1173,7 +1139,7 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
s32 *pbExtIV, u16 *pwRxTSC15_0, u32 *pdwRxTSC47_16)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
u32 PayloadLen = FrameSize;
u8 *pbyIV;
u8 byKeyIdx;
@@ -1183,8 +1149,8 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
*pdwRxTSC47_16 = 0;
pbyIV = pbyFrame + WLAN_HDR_ADDR3_LEN;
- if ( WLAN_GET_FC_TODS(*(PWORD)pbyFrame) &&
- WLAN_GET_FC_FROMDS(*(PWORD)pbyFrame) ) {
+ if ( WLAN_GET_FC_TODS(*(u16 *)pbyFrame) &&
+ WLAN_GET_FC_FROMDS(*(u16 *)pbyFrame) ) {
pbyIV += 6; // 6 is 802.11 address4
PayloadLen -= 6;
}
@@ -1192,7 +1158,6 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
byKeyIdx >>= 6;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\nKeyIdx: %d\n", byKeyIdx);
-
if (pMgmt->byCSSGK == KEY_CTL_TKIP)
byDecMode = KEY_CTL_TKIP;
else if (pMgmt->byCSSGK == KEY_CTL_CCMP)
@@ -1235,13 +1200,13 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
// TKIP/AES
PayloadLen -= (WLAN_HDR_ADDR3_LEN + 8 + 4); // 24 is 802.11 header, 8 is IV&ExtIV, 4 is crc
- *pdwRxTSC47_16 = cpu_to_le32(*(PDWORD)(pbyIV + 4));
+ *pdwRxTSC47_16 = cpu_to_le32(*(u32 *)(pbyIV + 4));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ExtIV: %x\n", *pdwRxTSC47_16);
if (byDecMode == KEY_CTL_TKIP) {
*pwRxTSC15_0 = cpu_to_le16(MAKEWORD(*(pbyIV+2), *pbyIV));
} else {
- *pwRxTSC15_0 = cpu_to_le16(*(PWORD)pbyIV);
+ *pwRxTSC15_0 = cpu_to_le16(*(u16 *)pbyIV);
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"TSC0_15: %x\n", *pwRxTSC15_0);
@@ -1252,8 +1217,8 @@ static int s_bHostWepRxEncryption(struct vnt_private *pDevice, u8 *pbyFrame,
// 1. 3253 A
// 2. NotOnFly
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"soft KEY_CTL_TKIP \n");
- pMACHeader = (PS802_11Header) (pbyFrame);
- TKIPvMixKey(pKey->abyKey, pMACHeader->abyAddr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
+ pMACHeader = (struct ieee80211_hdr *) (pbyFrame);
+ TKIPvMixKey(pKey->abyKey, pMACHeader->addr2, *pwRxTSC15_0, *pdwRxTSC47_16, pDevice->abyPRNG);
rc4_init(&pDevice->SBox, pDevice->abyPRNG, TKIP_KEY_LEN);
rc4_encrypt(&pDevice->SBox, pbyIV+8, pbyIV+8, PayloadLen);
if (ETHbIsBufferCrc32Ok(pbyIV+8, PayloadLen)) {
@@ -1297,11 +1262,10 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
u16 wAID;
-
if (FrameSize > CB_MAX_BUF_SIZE)
return false;
// check DA
- if (is_multicast_ether_addr((PBYTE)(skb->data+cbHeaderOffset))) {
+ if (is_multicast_ether_addr((u8 *)(skb->data+cbHeaderOffset))) {
if (pMgmt->sNodeDBTable[0].bPSEnable) {
skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz);
@@ -1326,7 +1290,7 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
}
else {
// check if relay
- if (BSSbIsSTAInNodeDB(pDevice, (PBYTE)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
+ if (BSSbIsSTAInNodeDB(pDevice, (u8 *)(skb->data+cbHeaderOffset), &iDANodeIndex)) {
if (pMgmt->sNodeDBTable[iDANodeIndex].eNodeState >= NODE_ASSOC) {
if (pMgmt->sNodeDBTable[iDANodeIndex].bPSEnable) {
// queue this skb until next PS tx, and then release.
@@ -1356,7 +1320,7 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
iDANodeIndex = 0;
if ((pDevice->uAssocCount > 1) && (iDANodeIndex >= 0)) {
- bRelayPacketSend(pDevice, (PBYTE) (skb->data + cbHeaderOffset),
+ bRelayPacketSend(pDevice, (u8 *) (skb->data + cbHeaderOffset),
FrameSize, (unsigned int) iDANodeIndex);
}
@@ -1370,9 +1334,6 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb,
return true;
}
-
-
-
void RXvWorkItem(struct vnt_private *pDevice)
{
int ntStatus;
@@ -1395,12 +1356,10 @@ void RXvWorkItem(struct vnt_private *pDevice)
}
-
void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
{
struct vnt_private *pDevice = pRCB->pDevice;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n");
ASSERT(!pRCB->Ref); // should be 0
@@ -1426,7 +1385,6 @@ void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
EnqueueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList, pRCB);
pDevice->NumRecvFreeList++;
-
if ((pDevice->Flags & fMP_POST_READS) && MP_IS_READY(pDevice) &&
(pDevice->bIsRxWorkItemQueued == false) ) {
@@ -1436,7 +1394,6 @@ void RXvFreeRCB(PRCB pRCB, int bReAllocSkb)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n",pDevice->NumRecvFreeList, pDevice->NumRecvMngList);
}
-
void RXvMngWorkItem(struct vnt_private *pDevice)
{
PRCB pRCB = NULL;
@@ -1471,4 +1428,3 @@ void RXvMngWorkItem(struct vnt_private *pDevice)
}
-
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index 786c523f5479..876468f2c3d2 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -29,18 +29,9 @@
#ifndef __DPC_H__
#define __DPC_H__
-#include "ttype.h"
#include "device.h"
#include "wcmd.h"
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void RXvWorkItem(void *Context);
void RXvMngWorkItem(void *Context);
diff --git a/drivers/staging/vt6656/firmware.c b/drivers/staging/vt6656/firmware.c
index 4371a77e9adc..a1dc3a4cfd9c 100644
--- a/drivers/staging/vt6656/firmware.c
+++ b/drivers/staging/vt6656/firmware.c
@@ -35,8 +35,6 @@
#include "control.h"
#include "rndis.h"
-/*--------------------- Static Definitions -------------------------*/
-
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
@@ -45,17 +43,6 @@ static int msglevel =MSG_LEVEL_INFO;
#define FIRMWARE_CHUNK_SIZE 0x400
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-
int FIRMWAREbDownload(struct vnt_private *pDevice)
{
struct device *dev = &pDevice->usb->dev;
@@ -66,7 +53,6 @@ int FIRMWAREbDownload(struct vnt_private *pDevice)
u16 wLength;
int ii, rc;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Download firmware\n");
spin_unlock_irq(&pDevice->lock);
@@ -132,7 +118,6 @@ int FIRMWAREbBrach2Sram(struct vnt_private *pDevice)
}
}
-
int FIRMWAREbCheckVersion(struct vnt_private *pDevice)
{
int ntStatus;
@@ -142,7 +127,7 @@ int FIRMWAREbCheckVersion(struct vnt_private *pDevice)
0,
MESSAGE_REQUEST_VERSION,
2,
- (PBYTE) &(pDevice->wFirmwareVersion));
+ (u8 *) &(pDevice->wFirmwareVersion));
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Firmware Version [%04x]\n", pDevice->wFirmwareVersion);
if (ntStatus != STATUS_SUCCESS) {
diff --git a/drivers/staging/vt6656/firmware.h b/drivers/staging/vt6656/firmware.h
index ebab3a6351b3..e3b08db6a734 100644
--- a/drivers/staging/vt6656/firmware.h
+++ b/drivers/staging/vt6656/firmware.h
@@ -30,17 +30,8 @@
#ifndef __FIRMWARE_H__
#define __FIRMWARE_H__
-#include "ttype.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
int FIRMWAREbDownload(struct vnt_private *);
int FIRMWAREbBrach2Sram(struct vnt_private *);
int FIRMWAREbCheckVersion(struct vnt_private *);
diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c
index bc5e9da47586..f4f1bf7a30fd 100644
--- a/drivers/staging/vt6656/hostap.c
+++ b/drivers/staging/vt6656/hostap.c
@@ -142,7 +142,6 @@ static int hostap_disable_hostapd(struct vnt_private *pDevice, int rtnl_locked)
return 0;
}
-
/*
* Description:
* Set enable/disable hostapd mode
@@ -174,7 +173,6 @@ int vt6656_hostap_set_hostapd(struct vnt_private *pDevice,
return hostap_disable_hostapd(pDevice, rtnl_locked);
}
-
/*
* Description:
* remove station function supported for hostap daemon
@@ -193,7 +191,6 @@ static int hostap_remove_sta(struct vnt_private *pDevice,
{
unsigned int uNodeIndex;
-
if (BSSbIsSTAInNodeDB(pDevice, param->sta_addr, &uNodeIndex)) {
BSSvRemoveOneNode(pDevice, uNodeIndex);
}
@@ -242,7 +239,7 @@ static int hostap_add_sta(struct vnt_private *pDevice,
pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble =
WLAN_GET_CAP_INFO_SHORTPREAMBLE(pMgmt->sNodeDBTable[uNodeIndex].wCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)param->u.add_sta.aid;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (u16)param->u.add_sta.aid;
pMgmt->sNodeDBTable[uNodeIndex].ulLastRxJiffer = jiffies;
@@ -294,7 +291,6 @@ static int hostap_get_info_sta(struct vnt_private *pDevice,
return 0;
}
-
/*
* Description:
* set station flag
@@ -327,8 +323,6 @@ static int hostap_set_flags_sta(struct vnt_private *pDevice,
return 0;
}
-
-
/*
* Description:
* set generic element (wpa ie)
@@ -347,8 +341,6 @@ static int hostap_set_generic_element(struct vnt_private *pDevice,
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
-
-
memcpy( pMgmt->abyWPAIE,
param->u.generic_elem.data,
param->u.generic_elem.len
@@ -425,13 +417,11 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
int bKeyTableFull = false;
u16 wKeyCtl = 0;
-
param->u.crypt.err = 0;
if (param->u.crypt.alg > WPA_ALG_CCMP)
return -EINVAL;
-
if ((param->u.crypt.idx > 3) || (param->u.crypt.key_len > MAX_KEY_LEN)) {
param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " HOSTAP_CRYPT_ERR_KEY_SET_FAILED\n");
@@ -489,9 +479,9 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
param->u.crypt.key_len
);
- dwKeyIndex = (DWORD)(param->u.crypt.idx);
+ dwKeyIndex = (u32)(param->u.crypt.idx);
if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+ pDevice->byKeyIndex = (u8)dwKeyIndex;
pDevice->bTransmitKey = true;
dwKeyIndex |= (1 << 31);
}
@@ -515,11 +505,10 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
&param->sta_addr[0],
dwKeyIndex & ~(USE_KEYRSC),
param->u.crypt.key_len,
- &KeyRSC, (PBYTE)abyKey,
+ &KeyRSC, (u8 *)abyKey,
KEY_CTL_WEP
) == true) {
-
pMgmt->sNodeDBTable[iNodeIndex].bOnFly = true;
} else {
@@ -565,7 +554,6 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
pMgmt->byCSSGK = KEY_CTL_CCMP;
}
-
if (iNodeIndex == 0) {
KeybSetDefaultKey( pDevice,
&(pDevice->sKey),
@@ -585,7 +573,7 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
dwKeyIndex,
param->u.crypt.key_len,
&KeyRSC,
- (PBYTE)abyKey,
+ (u8 *)abyKey,
byKeyDecMode
) == true) {
@@ -631,8 +619,6 @@ static int hostap_set_encryption(struct vnt_private *pDevice,
return ret;
}
-
-
/*
* Description:
* get each stations encryption key
@@ -655,7 +641,6 @@ static int hostap_get_encryption(struct vnt_private *pDevice,
int ii;
s32 iNodeIndex = 0;
-
param->u.crypt.err = 0;
if (is_broadcast_ether_addr(param->sta_addr)) {
@@ -670,13 +655,12 @@ static int hostap_get_encryption(struct vnt_private *pDevice,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "hostap_get_encryption: %d\n", iNodeIndex);
memset(param->u.crypt.seq, 0, 8);
for (ii = 0 ; ii < 8 ; ii++) {
- param->u.crypt.seq[ii] = (BYTE)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
+ param->u.crypt.seq[ii] = (u8)pMgmt->sNodeDBTable[iNodeIndex].KeyRSC >> (ii * 8);
}
return ret;
}
-
/*
* Description:
* vt6656_hostap_ioctl main function supported for hostap daemon.
@@ -779,7 +763,6 @@ int vt6656_hostap_ioctl(struct vnt_private *pDevice, struct iw_point *p)
goto out;
}
-
if ((ret == 0) && ap_ioctl) {
if (copy_to_user(p->pointer, param, p->length)) {
ret = -EFAULT;
diff --git a/drivers/staging/vt6656/hostap.h b/drivers/staging/vt6656/hostap.h
index f5656cd96a8f..6a68f7e69cff 100644
--- a/drivers/staging/vt6656/hostap.h
+++ b/drivers/staging/vt6656/hostap.h
@@ -31,8 +31,6 @@
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define WLAN_RATE_1M BIT0
#define WLAN_RATE_2M BIT1
#define WLAN_RATE_5M5 BIT2
@@ -46,13 +44,6 @@
#define WLAN_RATE_48M BIT10
#define WLAN_RATE_54M BIT11
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
#ifndef ETH_P_PAE
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#endif /* ETH_P_PAE */
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
index 51990bd3dd45..a2b4ba6d4f01 100644
--- a/drivers/staging/vt6656/int.c
+++ b/drivers/staging/vt6656/int.c
@@ -40,19 +40,8 @@
#include "bssdb.h"
#include "usbpipe.h"
-/*--------------------- Static Definitions -------------------------*/
static int msglevel = MSG_LEVEL_INFO; /* MSG_LEVEL_DEBUG */
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Function: InterruptPollingThread
@@ -98,8 +87,8 @@ void INTnsProcessData(struct vnt_private *pDevice)
pINTData = (PSINTData) pDevice->intBuf.pDataBuf;
if (pINTData->byTSR0 & TSR_VALID) {
STAvUpdateTDStatCounter(&(pDevice->scStatistic),
- (BYTE)(pINTData->byPkt0 & 0x0F),
- (BYTE)(pINTData->byPkt0>>4),
+ (u8)(pINTData->byPkt0 & 0x0F),
+ (u8)(pINTData->byPkt0>>4),
pINTData->byTSR0);
BSSvUpdateNodeTxCounter(pDevice,
&(pDevice->scStatistic),
@@ -109,8 +98,8 @@ void INTnsProcessData(struct vnt_private *pDevice)
}
if (pINTData->byTSR1 & TSR_VALID) {
STAvUpdateTDStatCounter(&(pDevice->scStatistic),
- (BYTE)(pINTData->byPkt1 & 0x0F),
- (BYTE)(pINTData->byPkt1>>4),
+ (u8)(pINTData->byPkt1 & 0x0F),
+ (u8)(pINTData->byPkt1>>4),
pINTData->byTSR1);
BSSvUpdateNodeTxCounter(pDevice,
&(pDevice->scStatistic),
@@ -120,8 +109,8 @@ void INTnsProcessData(struct vnt_private *pDevice)
}
if (pINTData->byTSR2 & TSR_VALID) {
STAvUpdateTDStatCounter(&(pDevice->scStatistic),
- (BYTE)(pINTData->byPkt2 & 0x0F),
- (BYTE)(pINTData->byPkt2>>4),
+ (u8)(pINTData->byPkt2 & 0x0F),
+ (u8)(pINTData->byPkt2>>4),
pINTData->byTSR2);
BSSvUpdateNodeTxCounter(pDevice,
&(pDevice->scStatistic),
@@ -131,8 +120,8 @@ void INTnsProcessData(struct vnt_private *pDevice)
}
if (pINTData->byTSR3 & TSR_VALID) {
STAvUpdateTDStatCounter(&(pDevice->scStatistic),
- (BYTE)(pINTData->byPkt3 & 0x0F),
- (BYTE)(pINTData->byPkt3>>4),
+ (u8)(pINTData->byPkt3 & 0x0F),
+ (u8)(pINTData->byPkt3>>4),
pINTData->byTSR3);
BSSvUpdateNodeTxCounter(pDevice,
&(pDevice->scStatistic),
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
index 27c725f1ce11..8e6e217ba4ff 100644
--- a/drivers/staging/vt6656/int.h
+++ b/drivers/staging/vt6656/int.h
@@ -30,40 +30,32 @@
#ifndef __INT_H__
#define __INT_H__
-#include "ttype.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
typedef struct tagSINTData {
- BYTE byTSR0;
- BYTE byPkt0;
- WORD wTime0;
- BYTE byTSR1;
- BYTE byPkt1;
- WORD wTime1;
- BYTE byTSR2;
- BYTE byPkt2;
- WORD wTime2;
- BYTE byTSR3;
- BYTE byPkt3;
- WORD wTime3;
+ u8 byTSR0;
+ u8 byPkt0;
+ u16 wTime0;
+ u8 byTSR1;
+ u8 byPkt1;
+ u16 wTime1;
+ u8 byTSR2;
+ u8 byPkt2;
+ u16 wTime2;
+ u8 byTSR3;
+ u8 byPkt3;
+ u16 wTime3;
u64 qwTSF;
- BYTE byISR0;
- BYTE byISR1;
- BYTE byRTSSuccess;
- BYTE byRTSFail;
- BYTE byACKFail;
- BYTE byFCSErr;
- BYTE abySW[2];
+ u8 byISR0;
+ u8 byISR1;
+ u8 byRTSSuccess;
+ u8 byRTSFail;
+ u8 byACKFail;
+ u8 byFCSErr;
+ u8 abySW[2];
} __attribute__ ((__packed__))
SINTData, *PSINTData;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void INTvWorkItem(struct vnt_private *);
void INTnsProcessData(struct vnt_private *);
diff --git a/drivers/staging/vt6656/iocmd.h b/drivers/staging/vt6656/iocmd.h
index c354a77964d8..f3406da7336e 100644
--- a/drivers/staging/vt6656/iocmd.h
+++ b/drivers/staging/vt6656/iocmd.h
@@ -29,10 +29,6 @@
#ifndef __IOCMD_H__
#define __IOCMD_H__
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
// ioctl Command code
#define MAGIC_CODE 0x3142
#define IOCTL_CMD_TEST (SIOCDEVPRIVATE + 0)
@@ -181,14 +177,12 @@ typedef struct tagSBSSIDItem {
} __packed SBSSIDItem;
-
typedef struct tagSBSSIDList {
u32 uItem;
SBSSIDItem sBSSIDList[0];
} __packed SBSSIDList, *PSBSSIDList;
-
typedef struct tagSNodeItem {
// STA info
u16 wAID;
@@ -209,7 +203,6 @@ typedef struct tagSNodeItem {
} __packed SNodeItem;
-
typedef struct tagSNodeList {
u32 uItem;
@@ -217,7 +210,6 @@ typedef struct tagSNodeList {
} __packed SNodeList, *PSNodeList;
-
typedef struct tagSCmdLinkStatus {
bool bLink;
@@ -248,8 +240,6 @@ typedef struct tagSDot11MIBCount {
u32 FCSErrorCount;
} __packed SDot11MIBCount, *PSDot11MIBCount;
-
-
//
// statistic counter
//
@@ -432,12 +422,4 @@ struct viawget_hostapd_param {
} u;
} __packed;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
#endif /* __IOCMD_H__ */
diff --git a/drivers/staging/vt6656/iowpa.h b/drivers/staging/vt6656/iowpa.h
index 2522ddec718d..97af32e1fa44 100644
--- a/drivers/staging/vt6656/iowpa.h
+++ b/drivers/staging/vt6656/iowpa.h
@@ -29,8 +29,6 @@
#ifndef __IOWPA_H__
#define __IOWPA_H__
-/*--------------------- Export Definitions -------------------------*/
-
#define WPA_IE_LEN 64
//WPA related
@@ -55,7 +53,6 @@ enum {
VIAWGET_SET_DISASSOCIATE = 10
};
-
enum {
VIAWGET_ASSOC_MSG = 1,
VIAWGET_DISASSOC_MSG = 2,
@@ -65,8 +62,6 @@ enum {
VIAWGET_DEVICECLOSE_MSG = 6
};
-
-
typedef struct viawget_wpa_header {
u8 type;
u16 req_ie_len;
@@ -130,12 +125,4 @@ struct viawget_scan_result {
int maxrate;
} __packed;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
#endif /* __IOWPA_H__ */
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index 69971f35e490..c335808211ee 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -42,7 +42,6 @@
#include "control.h"
#include "rndis.h"
-
static const long frequency_list[] = {
2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, 2484,
4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980,
@@ -61,8 +60,8 @@ struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev)
pDevice->wstats.status = pDevice->eOPMode;
if (pDevice->scStatistic.LinkQuality > 100)
pDevice->scStatistic.LinkQuality = 100;
- pDevice->wstats.qual.qual =(BYTE)pDevice->scStatistic.LinkQuality;
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ pDevice->wstats.qual.qual =(u8)pDevice->scStatistic.LinkQuality;
+ RFvRSSITodBm(pDevice, (u8)(pDevice->uCurrRSSI), &ldBm);
pDevice->wstats.qual.level = ldBm;
pDevice->wstats.qual.noise = 0;
pDevice->wstats.qual.updated = 1;
@@ -95,7 +94,7 @@ int iwctl_siwscan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *wrq = &wrqu->data;
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
struct iw_scan_req *req = (struct iw_scan_req *)extra;
- BYTE abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ u8 abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
PWLAN_IE_SSID pItemSSID = NULL;
if (!(pDevice->flags & DEVICE_FLAGS_OPENED))
@@ -238,7 +237,7 @@ int iwctl_giwscan(struct net_device *dev, struct iw_request_info *info,
// ADD quality
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
- RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (u8)(pBSS->uRSSI), &ldBm);
iwe.u.qual.level = ldBm;
iwe.u.qual.noise = 0;
@@ -357,7 +356,6 @@ int iwctl_giwfreq(struct net_device *dev, struct iw_request_info *info,
if (pMgmt == NULL)
return -EFAULT;
-
#ifdef WEXT_USECHANNELS
wrq->m = (int)pMgmt->uCurrChannel;
wrq->e = 0;
@@ -482,7 +480,6 @@ int iwctl_siwmode(struct net_device *dev, struct iw_request_info *info,
pDevice->bCommit = false;
}
-
return rc;
}
@@ -532,7 +529,7 @@ int iwctl_giwrange(struct net_device *dev, struct iw_request_info *info,
struct iw_range *range = (struct iw_range *)extra;
int i;
int k;
- BYTE abySupportedRates[13] = {
+ u8 abySupportedRates[13] = {
0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
0x60, 0x6C, 0x90
};
@@ -635,7 +632,7 @@ int iwctl_siwap(struct net_device *dev, struct iw_request_info *info,
struct sockaddr *wrq = &wrqu->ap_addr;
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
int rc = 0;
- BYTE ZeroBSSID[WLAN_BSSID_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ u8 ZeroBSSID[WLAN_BSSID_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
PRINT_K(" SIOCSIWAP\n");
@@ -819,7 +816,7 @@ int iwctl_siwessid(struct net_device *dev, struct iw_request_info *info,
if (pDevice->bWPASuppWextEnabled == true) {
/*******search if in hidden ssid mode ****/
PKnownBSS pCurr = NULL;
- BYTE abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ u8 abyTmpDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
unsigned ii;
unsigned uSameBssidNum = 0;
@@ -913,7 +910,7 @@ int iwctl_siwrate(struct net_device *dev, struct iw_request_info *info,
int rc = 0;
u8 brate = 0;
int i;
- BYTE abySupportedRates[13] = {
+ u8 abySupportedRates[13] = {
0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48,
0x60, 0x6C, 0x90
};
@@ -996,7 +993,7 @@ int iwctl_giwrate(struct net_device *dev, struct iw_request_info *info,
return -EFAULT;
{
- BYTE abySupportedRates[13] = {
+ u8 abySupportedRates[13] = {
0x02, 0x04, 0x0B, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30,
0x48, 0x60, 0x6C, 0x90
};
@@ -1227,7 +1224,7 @@ int iwctl_siwencode(struct net_device *dev, struct iw_request_info *info,
KEY_CTL_WEP);
spin_unlock_irq(&pDevice->lock);
}
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+ pDevice->byKeyIndex = (u8)dwKeyIndex;
pDevice->uKeyLength = wrq->length;
pDevice->bTransmitKey = true;
pDevice->bEncryptionEnable = true;
@@ -1317,7 +1314,7 @@ int iwctl_giwencode(struct net_device *dev, struct iw_request_info *info,
memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
}
- } else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (BYTE)index, &pKey)) {
+ } else if (KeybGetKey(&(pDevice->sKey), pDevice->abyBroadcastAddr, (u8)index, &pKey)) {
wrq->length = pKey->uKeyLength;
memcpy(abyKey, pKey->abyKey, pKey->uKeyLength);
memcpy(extra, abyKey, WLAN_WEP232_KEYLEN);
@@ -1424,7 +1421,7 @@ int iwctl_giwsens(struct net_device *dev, struct iw_request_info *info,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCGIWSENS\n");
if (pDevice->bLinkPass == true) {
- RFvRSSITodBm(pDevice, (BYTE)(pDevice->uCurrRSSI), &ldBm);
+ RFvRSSITodBm(pDevice, (u8)(pDevice->uCurrRSSI), &ldBm);
wrq->value = ldBm;
} else {
wrq->value = 0;
diff --git a/drivers/staging/vt6656/iwctl.h b/drivers/staging/vt6656/iwctl.h
index b594a10db318..dceda0dbdfe1 100644
--- a/drivers/staging/vt6656/iwctl.h
+++ b/drivers/staging/vt6656/iwctl.h
@@ -31,14 +31,6 @@
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
struct iw_statistics *iwctl_get_wireless_stats(struct net_device *dev);
int iwctl_siwap(struct net_device *dev, struct iw_request_info *info,
diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c
index 416175e8ba53..205590b0e9c8 100644
--- a/drivers/staging/vt6656/key.c
+++ b/drivers/staging/vt6656/key.c
@@ -42,24 +42,9 @@
#include "rndis.h"
#include "control.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
static void s_vCheckKeyTableValid(struct vnt_private *pDevice,
PSKeyManagement pTable)
{
@@ -79,7 +64,7 @@ static void s_vCheckKeyTableValid(struct vnt_private *pDevice,
pTable->KeyTable[i].bInUse = false;
pTable->KeyTable[i].wKeyCtl = 0;
pTable->KeyTable[i].bSoftWEP = false;
- pbyData[wLength++] = (BYTE) i;
+ pbyData[wLength++] = (u8) i;
//MACvDisableKeyEntry(pDevice, i);
}
}
@@ -95,10 +80,6 @@ static void s_vCheckKeyTableValid(struct vnt_private *pDevice,
}
-
-/*--------------------- Export Functions --------------------------*/
-
-
/*
* Description: Init Key management table
*
@@ -130,9 +111,9 @@ void KeyvInitTable(struct vnt_private *pDevice, PSKeyManagement pTable)
pTable->KeyTable[i].wKeyCtl = 0;
pTable->KeyTable[i].dwGTKeyIndex = 0;
pTable->KeyTable[i].bSoftWEP = false;
- pbyData[i] = (BYTE) i;
+ pbyData[i] = (u8) i;
}
- pbyData[i] = (BYTE) i;
+ pbyData[i] = (u8) i;
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_CLRKEYENTRY,
0,
@@ -146,7 +127,6 @@ void KeyvInitTable(struct vnt_private *pDevice, PSKeyManagement pTable)
return;
}
-
/*
* Description: Get Key from table
*
@@ -197,7 +177,6 @@ int KeybGetKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyIndex,
return (false);
}
-
/*
* Description: Set Key to table
*
@@ -272,7 +251,7 @@ int KeybSetKey(struct vnt_private *pDevice, PSKeyManagement pTable,
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey);
+ MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pbyBSSID, (u32 *)pKey->abyKey);
if ((dwKeyIndex & USE_KEYRSC) == 0)
pKey->KeyRSC = 0; /* RSC set by NIC */
@@ -340,7 +319,7 @@ int KeybSetKey(struct vnt_private *pDevice, PSKeyManagement pTable,
if (uKeyLength == WLAN_WEP104_KEYLEN)
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(pDevice, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (PDWORD)pKey->abyKey);
+ MACvSetKeyEntry(pDevice, pTable->KeyTable[j].wKeyCtl, j, uKeyIdx, pbyBSSID, (u32 *)pKey->abyKey);
if ((dwKeyIndex & USE_KEYRSC) == 0)
pKey->KeyRSC = 0; /* RSC set by NIC */
@@ -370,7 +349,6 @@ int KeybSetKey(struct vnt_private *pDevice, PSKeyManagement pTable,
return (false);
}
-
/*
* Description: Remove Key from table
*
@@ -445,10 +423,8 @@ int KeybRemoveKey(struct vnt_private *pDevice, PSKeyManagement pTable,
s_vCheckKeyTableValid(pDevice,pTable);
return bReturnValue;
-
}
-
/*
* Description: Remove Key from table
*
@@ -483,45 +459,6 @@ int KeybRemoveAllKey(struct vnt_private *pDevice, PSKeyManagement pTable,
}
/*
- * Description: Remove WEP Key from table
- *
- * Parameters:
- * In:
- * pTable - Pointer to Key table
- * Out:
- * none
- *
- * Return Value: true if success otherwise false
- *
- */
-void KeyvRemoveWEPKey(struct vnt_private *pDevice, PSKeyManagement pTable,
- u32 dwKeyIndex)
-{
-
- if ((dwKeyIndex & 0x000000FF) < MAX_GROUP_KEY) {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].bInUse == true) {
- if (pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].byCipherSuite == KEY_CTL_WEP) {
- pTable->KeyTable[MAX_KEY_TABLE-1].GroupKey[dwKeyIndex & 0x000000FF].bKeyValid = false;
- if ((dwKeyIndex & 0x7FFFFFFF) == (pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex & 0x7FFFFFFF)) {
- // remove Group transmit key
- pTable->KeyTable[MAX_KEY_TABLE-1].dwGTKeyIndex = 0;
- }
- }
- }
- s_vCheckKeyTableValid(pDevice, pTable);
- }
- return;
-}
-
-void KeyvRemoveAllWEPKey(struct vnt_private *pDevice, PSKeyManagement pTable)
-{
- int i;
-
- for (i = 0; i < MAX_GROUP_KEY; i++)
- KeyvRemoveWEPKey(pDevice, pTable, i);
-}
-
-/*
* Description: Get Transmit Key from table
*
* Parameters:
@@ -557,7 +494,6 @@ int KeybGetTransmitKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyType,
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"\n");
-
return (true);
}
else {
@@ -599,35 +535,6 @@ int KeybGetTransmitKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyType,
return (false);
}
-
-/*
- * Description: Check Pairwise Key
- *
- * Parameters:
- * In:
- * pTable - Pointer to Key table
- * Out:
- * none
- *
- * Return Value: true if found otherwise false
- *
- */
-int KeybCheckPairewiseKey(PSKeyManagement pTable, PSKeyItem *pKey)
-{
- int i;
-
- *pKey = NULL;
-
- for (i=0;i<MAX_KEY_TABLE;i++) {
- if ((pTable->KeyTable[i].bInUse == true) &&
- (pTable->KeyTable[i].PairwiseKey.bKeyValid == true)) {
- *pKey = &(pTable->KeyTable[i].PairwiseKey);
- return (true);
- }
- }
- return (false);
-}
-
/*
* Description: Set Key to table
*
@@ -707,18 +614,16 @@ int KeybSetDefaultKey(struct vnt_private *pDevice, PSKeyManagement pTable,
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(pDevice, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (PDWORD) pKey->abyKey);
+ MACvSetKeyEntry(pDevice, pTable->KeyTable[MAX_KEY_TABLE-1].wKeyCtl, MAX_KEY_TABLE-1, uKeyIdx, pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID, (u32 *) pKey->abyKey);
if ((dwKeyIndex & USE_KEYRSC) == 0)
pKey->KeyRSC = 0; /* RSC set by NIC */
else
pKey->KeyRSC = *KeyRSC;
-
pKey->dwTSC47_16 = 0;
pKey->wTSC15_0 = 0;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"KeybSetKey(R): \n");
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->bKeyValid: %d\n", pKey->bKeyValid);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pKey->uKeyLength: %d\n", (int)pKey->uKeyLength);
@@ -737,7 +642,6 @@ int KeybSetDefaultKey(struct vnt_private *pDevice, PSKeyManagement pTable,
return (true);
}
-
/*
* Description: Set Key to table
*
@@ -766,7 +670,6 @@ int KeybSetAllGroupKey(struct vnt_private *pDevice, PSKeyManagement pTable,
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Enter KeybSetAllGroupKey: %X\n",
dwKeyIndex);
-
if ((dwKeyIndex & PAIRWISE_KEY) != 0) { // Pairwise key
return (false);
} else if ((dwKeyIndex & 0x000000FF) >= MAX_GROUP_KEY) {
@@ -805,7 +708,7 @@ int KeybSetAllGroupKey(struct vnt_private *pDevice, PSKeyManagement pTable,
pKey->abyKey[15] |= 0x80;
}
- MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (PDWORD) pKey->abyKey);
+ MACvSetKeyEntry(pDevice, pTable->KeyTable[i].wKeyCtl, i, uKeyIdx, pTable->KeyTable[i].abyBSSID, (u32 *) pKey->abyKey);
if ((dwKeyIndex & USE_KEYRSC) == 0)
pKey->KeyRSC = 0; /* RSC set by NIC */
diff --git a/drivers/staging/vt6656/key.h b/drivers/staging/vt6656/key.h
index 7ecddcd6bcfa..23e188d125ba 100644
--- a/drivers/staging/vt6656/key.h
+++ b/drivers/staging/vt6656/key.h
@@ -30,17 +30,14 @@
#ifndef __KEY_H__
#define __KEY_H__
-#include "ttype.h"
#include "tether.h"
#include "80211mgr.h"
-/*--------------------- Export Definitions -------------------------*/
#define MAX_GROUP_KEY 4
#define MAX_KEY_TABLE 11
#define MAX_KEY_LEN 32
#define AES_KEY_LEN 16
-
#define AUTHENTICATOR_KEY 0x10000000
#define USE_KEYRSC 0x20000000
#define PAIRWISE_KEY 0x40000000
@@ -54,32 +51,31 @@
#define KEY_CTL_CCMP 0x03
#define KEY_CTL_INVALID 0xFF
-
typedef struct tagSKeyItem
{
bool bKeyValid;
u32 uKeyLength;
- BYTE abyKey[MAX_KEY_LEN];
+ u8 abyKey[MAX_KEY_LEN];
u64 KeyRSC;
- DWORD dwTSC47_16;
- WORD wTSC15_0;
- BYTE byCipherSuite;
- BYTE byReserved0;
- DWORD dwKeyIndex;
+ u32 dwTSC47_16;
+ u16 wTSC15_0;
+ u8 byCipherSuite;
+ u8 byReserved0;
+ u32 dwKeyIndex;
void *pvKeyTable;
} SKeyItem, *PSKeyItem; //64
typedef struct tagSKeyTable
{
- BYTE abyBSSID[ETH_ALEN]; /* 6 */
- BYTE byReserved0[2]; //8
+ u8 abyBSSID[ETH_ALEN]; /* 6 */
+ u8 byReserved0[2]; //8
SKeyItem PairwiseKey;
SKeyItem GroupKey[MAX_GROUP_KEY]; //64*5 = 320, 320+8=328
- DWORD dwGTKeyIndex; // GroupTransmitKey Index
+ u32 dwGTKeyIndex; // GroupTransmitKey Index
bool bInUse;
- WORD wKeyCtl;
+ u16 wKeyCtl;
bool bSoftWEP;
- BYTE byReserved1[6];
+ u8 byReserved1[6];
} SKeyTable, *PSKeyTable; //352
typedef struct tagSKeyManagement
@@ -87,16 +83,6 @@ typedef struct tagSKeyManagement
SKeyTable KeyTable[MAX_KEY_TABLE];
} SKeyManagement, *PSKeyManagement;
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void KeyvInitTable(struct vnt_private *, PSKeyManagement pTable);
int KeybGetKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyIndex,
@@ -112,16 +98,9 @@ int KeybRemoveKey(struct vnt_private *, PSKeyManagement pTable,
int KeybRemoveAllKey(struct vnt_private *, PSKeyManagement pTable,
u8 *pbyBSSID);
-void KeyvRemoveWEPKey(struct vnt_private *, PSKeyManagement pTable,
- u32 dwKeyIndex);
-
-void KeyvRemoveAllWEPKey(struct vnt_private *, PSKeyManagement pTable);
-
int KeybGetTransmitKey(PSKeyManagement pTable, u8 *pbyBSSID, u32 dwKeyType,
PSKeyItem *pKey);
-int KeybCheckPairewiseKey(PSKeyManagement pTable, PSKeyItem *pKey);
-
int KeybSetDefaultKey(struct vnt_private *, PSKeyManagement pTable,
u32 dwKeyIndex, u32 uKeyLength, u64 *KeyRSC, u8 *pbyKey,
u8 byKeyDecMode);
diff --git a/drivers/staging/vt6656/mac.c b/drivers/staging/vt6656/mac.c
index 76d307b58d52..343db19283a2 100644
--- a/drivers/staging/vt6656/mac.c
+++ b/drivers/staging/vt6656/mac.c
@@ -38,63 +38,8 @@
#include "rndis.h"
#include "control.h"
-/*--------------------- Static Definitions -------------------------*/
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-
-
-
-
-/*
- * Description:
- * Set this hash index into multicast address register bit
- *
- * Parameters:
- * In:
- * byHashIdx - Hash index to set
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void MACvSetMultiAddrByHash(struct vnt_private *pDevice, u8 byHashIdx)
-{
- u8 uByteIdx;
- u8 byBitMask;
- u8 pbyData[2];
-
-
- // calculate byte position
- uByteIdx = byHashIdx / 8;
-
- // calculate bit position
- byBitMask = 1;
- byBitMask <<= (byHashIdx % 8);
- // turn on the bit
-
- pbyData[0] = byBitMask;
- pbyData[1] = byBitMask;
-
- CONTROLnsRequestOut(pDevice,
- MESSAGE_TYPE_WRITE_MASK,
- (WORD) (MAC_REG_MAR0 + uByteIdx),
- MESSAGE_REQUEST_MACREG,
- 2,
- pbyData);
-}
-
-
/*
* Description:
@@ -117,13 +62,12 @@ void MACvWriteMultiAddr(struct vnt_private *pDevice, u32 uByteIdx, u8 byData)
byData1 = byData;
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
- (WORD) (MAC_REG_MAR0 + uByteIdx),
+ (u16) (MAC_REG_MAR0 + uByteIdx),
MESSAGE_REQUEST_MACREG,
1,
&byData1);
}
-
/*
* Description:
* Shut Down MAC
@@ -150,7 +94,6 @@ void MACvSetBBType(struct vnt_private *pDevice, u8 byType)
{
u8 pbyData[2];
-
pbyData[0] = byType;
pbyData[1] = EnCFG_BBType_MASK;
@@ -163,26 +106,6 @@ void MACvSetBBType(struct vnt_private *pDevice, u8 byType)
);
}
-void MACvSetMISCFifo(struct vnt_private *pDevice, u16 wOffset, u32 dwData)
-{
- u8 pbyData[4];
-
- if (wOffset > 273)
- return;
- pbyData[0] = (BYTE)dwData;
- pbyData[1] = (BYTE)(dwData>>8);
- pbyData[2] = (BYTE)(dwData>>16);
- pbyData[3] = (BYTE)(dwData>>24);
-
- CONTROLnsRequestOut(pDevice,
- MESSAGE_TYPE_WRITE_MISCFF,
- wOffset,
- 0,
- 4,
- pbyData
- );
-}
-
/*
* Description:
* Disable the Key Entry by MISCFIFO
@@ -202,8 +125,7 @@ void MACvDisableKeyEntry(struct vnt_private *pDevice, u32 uEntryIdx)
u16 wOffset;
u8 byData;
-
- byData = (BYTE) uEntryIdx;
+ byData = (u8) uEntryIdx;
wOffset = MISCFIFO_KEYETRY0;
wOffset += (uEntryIdx * MISCFIFO_KEYENTRYSIZE);
@@ -222,7 +144,6 @@ void MACvDisableKeyEntry(struct vnt_private *pDevice, u32 uEntryIdx)
);
}
-
/*
* Description:
* Set the Key by MISCFIFO
@@ -294,31 +215,29 @@ void MACvSetKeyEntry(struct vnt_private *pDevice, u16 wKeyCtl, u32 uEntryIdx,
VNSvOutPortW(dwIoBase + MAC_REG_MISCFFCTL, MISCFFCTL_WRITE);
}
*/
- pbyKey = (PBYTE)pdwKey;
-
- pbyData[0] = (BYTE)dwData1;
- pbyData[1] = (BYTE)(dwData1>>8);
- pbyData[2] = (BYTE)(dwData1>>16);
- pbyData[3] = (BYTE)(dwData1>>24);
- pbyData[4] = (BYTE)dwData2;
- pbyData[5] = (BYTE)(dwData2>>8);
- pbyData[6] = (BYTE)(dwData2>>16);
- pbyData[7] = (BYTE)(dwData2>>24);
+ pbyKey = (u8 *)pdwKey;
+
+ pbyData[0] = (u8)dwData1;
+ pbyData[1] = (u8)(dwData1>>8);
+ pbyData[2] = (u8)(dwData1>>16);
+ pbyData[3] = (u8)(dwData1>>24);
+ pbyData[4] = (u8)dwData2;
+ pbyData[5] = (u8)(dwData2>>8);
+ pbyData[6] = (u8)(dwData2>>16);
+ pbyData[7] = (u8)(dwData2>>24);
for (ii = 8; ii < 24; ii++)
pbyData[ii] = *pbyKey++;
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_SETKEY,
wOffset,
- (WORD)uKeyIdx,
+ (u16)uKeyIdx,
24,
pbyData
);
-
}
-
void MACvRegBitsOff(struct vnt_private *pDevice, u8 byRegOfs, u8 byBits)
{
u8 pbyData[2];
@@ -335,12 +254,10 @@ void MACvRegBitsOff(struct vnt_private *pDevice, u8 byRegOfs, u8 byBits)
);
}
-
void MACvRegBitsOn(struct vnt_private *pDevice, u8 byRegOfs, u8 byBits)
{
u8 pbyData[2];
-
pbyData[0] = byBits;
pbyData[1] = byBits;
@@ -357,9 +274,8 @@ void MACvWriteWord(struct vnt_private *pDevice, u8 byRegOfs, u16 wData)
{
u8 pbyData[2];
-
- pbyData[0] = (BYTE)(wData & 0xff);
- pbyData[1] = (BYTE)(wData >> 8);
+ pbyData[0] = (u8)(wData & 0xff);
+ pbyData[1] = (u8)(wData >> 8);
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
@@ -375,13 +291,12 @@ void MACvWriteBSSIDAddress(struct vnt_private *pDevice, u8 *pbyEtherAddr)
{
u8 pbyData[6];
-
- pbyData[0] = *((PBYTE)pbyEtherAddr);
- pbyData[1] = *((PBYTE)pbyEtherAddr+1);
- pbyData[2] = *((PBYTE)pbyEtherAddr+2);
- pbyData[3] = *((PBYTE)pbyEtherAddr+3);
- pbyData[4] = *((PBYTE)pbyEtherAddr+4);
- pbyData[5] = *((PBYTE)pbyEtherAddr+5);
+ pbyData[0] = *((u8 *)pbyEtherAddr);
+ pbyData[1] = *((u8 *)pbyEtherAddr+1);
+ pbyData[2] = *((u8 *)pbyEtherAddr+2);
+ pbyData[3] = *((u8 *)pbyEtherAddr+3);
+ pbyData[4] = *((u8 *)pbyEtherAddr+4);
+ pbyData[5] = *((u8 *)pbyEtherAddr+5);
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE,
@@ -396,7 +311,6 @@ void MACvEnableProtectMD(struct vnt_private *pDevice)
{
u8 pbyData[2];
-
pbyData[0] = EnCFG_ProtectMd;
pbyData[1] = EnCFG_ProtectMd;
@@ -413,7 +327,6 @@ void MACvDisableProtectMD(struct vnt_private *pDevice)
{
u8 pbyData[2];
-
pbyData[0] = 0;
pbyData[1] = EnCFG_ProtectMd;
@@ -430,7 +343,6 @@ void MACvEnableBarkerPreambleMd(struct vnt_private *pDevice)
{
u8 pbyData[2];
-
pbyData[0] = EnCFG_BarkerPream;
pbyData[1] = EnCFG_BarkerPream;
@@ -447,7 +359,6 @@ void MACvDisableBarkerPreambleMd(struct vnt_private *pDevice)
{
u8 pbyData[2];
-
pbyData[0] = 0;
pbyData[1] = EnCFG_BarkerPream;
@@ -460,7 +371,6 @@ void MACvDisableBarkerPreambleMd(struct vnt_private *pDevice)
);
}
-
void MACvWriteBeaconInterval(struct vnt_private *pDevice, u16 wInterval)
{
u8 pbyData[2];
diff --git a/drivers/staging/vt6656/mac.h b/drivers/staging/vt6656/mac.h
index 6e28500ae5f8..0db1be5b01c8 100644
--- a/drivers/staging/vt6656/mac.h
+++ b/drivers/staging/vt6656/mac.h
@@ -34,12 +34,9 @@
#ifndef __MAC_H__
#define __MAC_H__
-#include "ttype.h"
#include "device.h"
#include "tmacro.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define REV_ID_VT3253_A0 0x00
#define REV_ID_VT3253_A1 0x01
#define REV_ID_VT3253_B0 0x08
@@ -156,7 +153,6 @@
#define MAC_REG_RSPINF_A_54 0xFA
#define MAC_REG_RSPINF_A_72 0xFC
-
//
// Bits in the I2MCFG EEPROM register
//
@@ -281,7 +277,6 @@
#define TCR_SYNCDCFOPT 0x02 //
#define TCR_AUTOBCNTX 0x01 // Beacon automatically transmit enable
-
//ISR1
#define ISR_GPIO3 0x40
#define ISR_RXNOBUF 0x08
@@ -377,7 +372,6 @@
//
#define MISCFFCTL_WRITE 0x0001 //
-
// Loopback mode
#define MAC_LB_EXT 0x02 //
#define MAC_LB_INTERNAL 0x01 //
@@ -409,22 +403,9 @@
#define MAC_REVISION_A0 0x00
#define MAC_REVISION_A1 0x01
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-void MACvSetMultiAddrByHash(struct vnt_private *, u8);
void MACvWriteMultiAddr(struct vnt_private *, u32, u8);
void MACbShutdown(struct vnt_private *);
void MACvSetBBType(struct vnt_private *, u8);
-void MACvSetMISCFifo(struct vnt_private *pDevice, u16, u32);
void MACvDisableKeyEntry(struct vnt_private *, u32);
void MACvSetKeyEntry(struct vnt_private *, u16, u32, u32, u8 *, u32 *);
void MACvRegBitsOff(struct vnt_private *, u8, u8);
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 457d91c1325d..3a3fdc58b6da 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -73,7 +73,6 @@
#include "int.h"
#include "iowpa.h"
-/*--------------------- Static Definitions -------------------------*/
/* static int msglevel = MSG_LEVEL_DEBUG; */
static int msglevel =MSG_LEVEL_INFO;
@@ -96,14 +95,12 @@ MODULE_DESCRIPTION(DEVICE_FULL_DRV_NAM);
#define RX_DESC_DEF0 64
DEVICE_PARAM(RxDescriptors0,"Number of receive usb desc buffer");
-
#define TX_DESC_DEF0 64
DEVICE_PARAM(TxDescriptors0,"Number of transmit usb desc buffer");
#define CHANNEL_DEF 6
DEVICE_PARAM(Channel, "Channel number");
-
/* PreambleType[] is the preamble length used for transmit.
0: indicate allows long preamble type
1: indicate allows short preamble type
@@ -119,7 +116,6 @@ DEVICE_PARAM(RTSThreshold, "RTS threshold");
#define FRAG_THRESH_DEF 2346
DEVICE_PARAM(FragThreshold, "Fragmentation threshold");
-
#define DATA_RATE_DEF 13
/* datarate[] index
0: indicate 1 Mbps 0x02
@@ -149,7 +145,6 @@ DEVICE_PARAM(OPMode, "Infrastruct, adhoc, AP mode ");
2: indicate AP mode used
*/
-
/* PSMode[]
0: indicate disable power saving mode
1: indicate enable power saving mode
@@ -158,7 +153,6 @@ DEVICE_PARAM(OPMode, "Infrastruct, adhoc, AP mode ");
#define PS_MODE_DEF 0
DEVICE_PARAM(PSMode, "Power saving mode");
-
#define SHORT_RETRY_DEF 8
DEVICE_PARAM(ShortRetryLimit, "Short frame retry limits");
@@ -174,8 +168,6 @@ DEVICE_PARAM(LongRetryLimit, "long frame retry limits");
#define BBP_TYPE_DEF 2
DEVICE_PARAM(BasebandType, "baseband type");
-
-
/* 80211hEnable[]
0: indicate disable 802.11h
1: indicate enable 802.11h
@@ -185,7 +177,6 @@ DEVICE_PARAM(BasebandType, "baseband type");
DEVICE_PARAM(b80211hEnable, "802.11h mode");
-
/*
* Static vars definitions
*/
@@ -205,12 +196,9 @@ static const long frequency_list[] = {
5700, 5745, 5765, 5785, 5805, 5825
};
-
static const struct iw_handler_def iwctl_handler_def;
*/
-/*--------------------- Static Functions --------------------------*/
-
static int vt6656_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void vt6656_disconnect(struct usb_interface *intf);
@@ -246,21 +234,13 @@ static int Config_FileGetParameter(unsigned char *string,
unsigned char *dest,
unsigned char *source);
-
static void usb_device_reset(struct vnt_private *pDevice);
-
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-
static void
device_set_options(struct vnt_private *pDevice) {
- BYTE abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- BYTE abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
+ u8 abyBroadcastAddr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 abySNAP_RFC1042[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
u8 abySNAP_Bridgetunnel[ETH_ALEN] = {0xAA, 0xAA, 0x03, 0x00, 0x00, 0xF8};
memcpy(pDevice->abyBroadcastAddr, abyBroadcastAddr, ETH_ALEN);
@@ -294,7 +274,6 @@ device_set_options(struct vnt_private *pDevice) {
pDevice->bDiversityRegCtlON = false;
}
-
static void device_init_diversity_timer(struct vnt_private *pDevice)
{
init_timer(&pDevice->TimerSQ3Tmax1);
@@ -315,7 +294,6 @@ static void device_init_diversity_timer(struct vnt_private *pDevice)
return;
}
-
/*
* initialization of MAC & BBP registers
*/
@@ -367,8 +345,8 @@ static int device_init_registers(struct vnt_private *pDevice,
}
}
- sInitCmd.byInitClass = (BYTE)InitType;
- sInitCmd.bExistSWNetAddr = (BYTE) pDevice->bExistSWNetAddr;
+ sInitCmd.byInitClass = (u8)InitType;
+ sInitCmd.bExistSWNetAddr = (u8) pDevice->bExistSWNetAddr;
for (ii = 0; ii < 6; ii++)
sInitCmd.bySWNetAddr[ii] = pDevice->abyCurrentNetAddr[ii];
sInitCmd.byShortRetryLimit = pDevice->byShortRetryLimit;
@@ -380,7 +358,7 @@ static int device_init_registers(struct vnt_private *pDevice,
0,
0,
sizeof(CMD_CARD_INIT),
- (PBYTE) &(sInitCmd));
+ (u8 *) &(sInitCmd));
if ( ntStatus != STATUS_SUCCESS ) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" Issue Card init fail \n");
@@ -389,7 +367,7 @@ static int device_init_registers(struct vnt_private *pDevice,
}
if (InitType == DEVICE_INIT_COLD) {
- ntStatus = CONTROLnsRequestIn(pDevice,MESSAGE_TYPE_INIT_RSP,0,0,sizeof(RSP_CARD_INIT), (PBYTE) &(sInitRsp));
+ ntStatus = CONTROLnsRequestIn(pDevice,MESSAGE_TYPE_INIT_RSP,0,0,sizeof(RSP_CARD_INIT), (u8 *) &(sInitRsp));
if (ntStatus != STATUS_SUCCESS) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Cardinit request in status fail!\n");
@@ -419,7 +397,7 @@ static int device_init_registers(struct vnt_private *pDevice,
pDevice->bNonERPPresent = false;
pDevice->bBarkerPreambleMd = false;
if ( pDevice->bFixRate ) {
- pDevice->wCurrentRate = (WORD) pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (u16) pDevice->uConnectionRate;
} else {
if ( pDevice->byBBType == BB_TYPE_11B )
pDevice->wCurrentRate = RATE_11M;
@@ -772,7 +750,6 @@ static void device_free_tx_bufs(struct vnt_private *pDevice)
return;
}
-
static void device_free_rx_bufs(struct vnt_private *pDevice)
{
PRCB pRCB;
@@ -810,7 +787,6 @@ static void device_free_int_bufs(struct vnt_private *pDevice)
return;
}
-
static bool device_alloc_bufs(struct vnt_private *pDevice)
{
@@ -818,7 +794,6 @@ static bool device_alloc_bufs(struct vnt_private *pDevice)
PRCB pRCB;
int ii;
-
for (ii = 0; ii < pDevice->cbTD; ii++) {
pTxContext = kmalloc(sizeof(USB_SEND_CONTEXT), GFP_KERNEL);
@@ -844,7 +819,6 @@ static bool device_alloc_bufs(struct vnt_private *pDevice)
goto free_tx;
}
-
pDevice->FirstRecvFreeList = NULL;
pDevice->LastRecvFreeList = NULL;
pDevice->FirstRecvMngList = NULL;
@@ -875,7 +849,6 @@ static bool device_alloc_bufs(struct vnt_private *pDevice)
pRCB++;
}
-
pDevice->pControlURB = usb_alloc_urb(0, GFP_ATOMIC);
if (pDevice->pControlURB == NULL) {
DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc control urb\n");
@@ -908,9 +881,6 @@ free_tx:
return false;
}
-
-
-
static bool device_init_defrag_cb(struct vnt_private *pDevice)
{
int i;
@@ -934,8 +904,6 @@ free_frag:
return false;
}
-
-
static void device_free_frag_bufs(struct vnt_private *pDevice)
{
PSDeFragControlBlock pDeF;
@@ -950,8 +918,6 @@ static void device_free_frag_bufs(struct vnt_private *pDevice)
}
}
-
-
int device_alloc_frag_buf(struct vnt_private *pDevice,
PSDeFragControlBlock pDeF)
{
@@ -965,9 +931,6 @@ int device_alloc_frag_buf(struct vnt_private *pDevice,
return true;
}
-
-/*-----------------------------------------------------------------*/
-
static int device_open(struct net_device *dev)
{
struct vnt_private *pDevice = netdev_priv(dev);
@@ -976,7 +939,6 @@ static int device_open(struct net_device *dev)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " device_open...\n");
-
pDevice->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS;
if (device_alloc_bufs(pDevice) == false) {
@@ -1062,7 +1024,6 @@ static int device_open(struct net_device *dev)
else
bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
-
netif_stop_queue(pDevice->dev);
pDevice->flags |= DEVICE_FLAGS_OPENED;
@@ -1084,8 +1045,6 @@ free_rx_tx:
return -ENOMEM;
}
-
-
static int device_close(struct net_device *dev)
{
struct vnt_private *pDevice = netdev_priv(dev);
@@ -1101,7 +1060,6 @@ static int device_close(struct net_device *dev)
mdelay(30);
}
-
memset(pMgmt->abyDesireSSID, 0, WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1);
pMgmt->bShareKeyAlgorithm = false;
pDevice->bEncryptionEnable = false;
@@ -1166,7 +1124,6 @@ static void vt6656_disconnect(struct usb_interface *intf)
if (!device)
return;
-
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
@@ -1407,7 +1364,6 @@ static void device_set_multi(struct net_device *dev)
u8 byTmpMode = 0;
int rc;
-
spin_lock_irq(&pDevice->lock);
rc = CONTROLnsRequestIn(pDevice,
MESSAGE_TYPE_READ,
@@ -1443,8 +1399,8 @@ static void device_set_multi(struct net_device *dev)
mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
}
for (ii = 0; ii < 4; ii++) {
- MACvWriteMultiAddr(pDevice, ii, *((PBYTE)&mc_filter[0] + ii));
- MACvWriteMultiAddr(pDevice, ii+ 4, *((PBYTE)&mc_filter[1] + ii));
+ MACvWriteMultiAddr(pDevice, ii, *((u8 *)&mc_filter[0] + ii));
+ MACvWriteMultiAddr(pDevice, ii+ 4, *((u8 *)&mc_filter[1] + ii));
}
pDevice->byRxMode &= ~(RCR_UNICAST);
pDevice->byRxMode |= (RCR_MULTICAST|RCR_BROADCAST);
@@ -1495,7 +1451,6 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-
static int ethtool_ioctl(struct net_device *dev, void *useraddr)
{
u32 ethcmd;
diff --git a/drivers/staging/vt6656/mib.c b/drivers/staging/vt6656/mib.c
index d4c7b0cc7ecd..12333cdcbc6a 100644
--- a/drivers/staging/vt6656/mib.c
+++ b/drivers/staging/vt6656/mib.c
@@ -25,10 +25,8 @@
* Date: May 21, 1996
*
* Functions:
- * STAvClearAllCounter - Clear All MIB Counter
* STAvUpdateIstStatCounter - Update ISR statistic counter
* STAvUpdateRDStatCounter - Update Rx statistic counter
- * STAvUpdateRDStatCounterEx - Update Rx statistic counter and copy rcv data
* STAvUpdateTDStatCounter - Update Tx statistic counter
* STAvUpdateTDStatCounterEx - Update Tx statistic counter and copy tx data
* STAvUpdate802_11Counter - Update 802.11 mib counter
@@ -43,38 +41,7 @@
#include "wctl.h"
#include "baseband.h"
-/*--------------------- Static Definitions -------------------------*/
static int msglevel =MSG_LEVEL_INFO;
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-
-
-/*
- * Description: Clear All Statistic Counter
- *
- * Parameters:
- * In:
- * pStatistic - Pointer to Statistic Counter Data Structure
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void STAvClearAllCounter (PSStatCounter pStatistic)
-{
- // set memory to zero
- memset(pStatistic, 0, sizeof(SStatCounter));
-}
-
/*
* Description: Update Isr Statistic Counter
@@ -89,7 +56,7 @@ void STAvClearAllCounter (PSStatCounter pStatistic)
* Return Value: none
*
*/
-void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr1)
+void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, u8 byIsr0, u8 byIsr1)
{
/**********************/
/* ABNORMAL interrupt */
@@ -100,7 +67,6 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr
return;
}
-
if (byIsr0 & ISR_ACTX) // ISR, bit0
pStatistic->ISRStat.dwIsrTx0OK++; // TXDMA0 successful
@@ -119,7 +85,6 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr
if (byIsr0 & ISR_WATCHDOG) // ISR, bit7
pStatistic->ISRStat.dwIsrWatchDog++;
-
if (byIsr1 & ISR_FETALERR) // ISR, bit8
pStatistic->ISRStat.dwIsrUnrecoverableError++;
@@ -134,7 +99,6 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr
}
-
/*
* Description: Update Rx Statistic Counter
*
@@ -152,12 +116,12 @@ void STAvUpdateIsrStatCounter (PSStatCounter pStatistic, BYTE byIsr0, BYTE byIsr
*
*/
void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRSR,
- BYTE byRxSts, BYTE byRxRate,
- PBYTE pbyBuffer, unsigned int cbFrameLength)
+ u8 byRSR, u8 byNewRSR,
+ u8 byRxSts, u8 byRxRate,
+ u8 * pbyBuffer, unsigned int cbFrameLength)
{
/* need change */
- PS802_11Header pHeader = (PS802_11Header)pbyBuffer;
+ struct ieee80211_hdr *pHeader = (struct ieee80211_hdr *)pbyBuffer;
if (byRSR & RSR_ADDROK)
pStatistic->dwRsrADDROk++;
@@ -327,7 +291,6 @@ void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
pStatistic->dwRsrRxPacket++;
pStatistic->dwRsrRxOctet += cbFrameLength;
-
if (IS_TYPE_DATA(pbyBuffer)) {
pStatistic->dwRsrRxData++;
} else if (IS_TYPE_MGMT(pbyBuffer)){
@@ -343,7 +306,7 @@ void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
else
pStatistic->dwRsrDirected++;
- if (WLAN_GET_FC_MOREFRAG(pHeader->wFrameCtl))
+ if (WLAN_GET_FC_MOREFRAG(pHeader->frame_control))
pStatistic->dwRsrRxFragment++;
if (cbFrameLength < ETH_ZLEN + 4) {
@@ -371,51 +334,6 @@ void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
}
/*
- * Description: Update Rx Statistic Counter and copy Rx buffer
- *
- * Parameters:
- * In:
- * pStatistic - Pointer to Statistic Counter Data Structure
- * byRSR - Rx Status
- * byNewRSR - Rx Status
- * pbyBuffer - Rx Buffer
- * cbFrameLength - Rx Length
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-
-void
-STAvUpdateRDStatCounterEx (
- PSStatCounter pStatistic,
- BYTE byRSR,
- BYTE byNewRSR,
- BYTE byRxSts,
- BYTE byRxRate,
- PBYTE pbyBuffer,
- unsigned int cbFrameLength
- )
-{
- STAvUpdateRDStatCounter(
- pStatistic,
- byRSR,
- byNewRSR,
- byRxSts,
- byRxRate,
- pbyBuffer,
- cbFrameLength
- );
-
- // rx length
- pStatistic->dwCntRxFrmLength = cbFrameLength;
- // rx pattern, we just see 10 bytes for sample
- memcpy(pStatistic->abyCntRxPattern, (PBYTE)pbyBuffer, 10);
-}
-
-
-/*
* Description: Update Tx Statistic Counter
*
* Parameters:
@@ -435,12 +353,12 @@ STAvUpdateRDStatCounterEx (
void
STAvUpdateTDStatCounter (
PSStatCounter pStatistic,
- BYTE byPktNum,
- BYTE byRate,
- BYTE byTSR
+ u8 byPktNum,
+ u8 byRate,
+ u8 byTSR
)
{
- BYTE byRetyCnt;
+ u8 byRetyCnt;
// increase tx packet count
pStatistic->dwTsrTxPacket++;
@@ -504,8 +422,6 @@ STAvUpdateTDStatCounter (
}
}
-
-
/*
* Description: Update 802.11 mib counter
*
@@ -524,10 +440,10 @@ void
STAvUpdate802_11Counter(
PSDot11Counters p802_11Counter,
PSStatCounter pStatistic,
- BYTE byRTSSuccess,
- BYTE byRTSFail,
- BYTE byACKFail,
- BYTE byFCSErr
+ u8 byRTSSuccess,
+ u8 byRTSFail,
+ u8 byACKFail,
+ u8 byFCSErr
)
{
//p802_11Counter->TransmittedFragmentCount
@@ -554,25 +470,6 @@ STAvUpdate802_11Counter(
*
* Parameters:
* In:
- * p802_11Counter - Pointer to 802.11 mib counter
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-void
-STAvClear802_11Counter(PSDot11Counters p802_11Counter)
-{
- // set memory to zero
- memset(p802_11Counter, 0, sizeof(SDot11Counters));
-}
-
-/*
- * Description: Clear 802.11 mib counter
- *
- * Parameters:
- * In:
* pUsbCounter - Pointer to USB mib counter
* ntStatus - URB status
* Out:
diff --git a/drivers/staging/vt6656/mib.h b/drivers/staging/vt6656/mib.h
index 85c28e923663..35375325a777 100644
--- a/drivers/staging/vt6656/mib.h
+++ b/drivers/staging/vt6656/mib.h
@@ -29,28 +29,21 @@
#ifndef __MIB_H__
#define __MIB_H__
-#include "ttype.h"
#include "tether.h"
#include "desc.h"
-/*--------------------- Export Definitions -------------------------*/
-
-
//
// USB counter
//
typedef struct tagSUSBCounter {
- DWORD dwCrc;
+ u32 dwCrc;
} SUSBCounter, *PSUSBCounter;
-
-
//
// 802.11 counter
//
-
typedef struct tagSDot11Counters {
/* unsigned long Length; // Length of structure */
unsigned long long TransmittedFragmentCount;
@@ -81,7 +74,6 @@ typedef struct tagSDot11Counters {
*/
} SDot11Counters, *PSDot11Counters;
-
//
// MIB2 counter
//
@@ -91,24 +83,24 @@ typedef struct tagSMib2Counter {
// e.g. "interface 1"
signed long ifType;
signed long ifMtu;
- DWORD ifSpeed;
- BYTE ifPhysAddress[ETH_ALEN];
+ u32 ifSpeed;
+ u8 ifPhysAddress[ETH_ALEN];
signed long ifAdminStatus;
signed long ifOperStatus;
- DWORD ifLastChange;
- DWORD ifInOctets;
- DWORD ifInUcastPkts;
- DWORD ifInNUcastPkts;
- DWORD ifInDiscards;
- DWORD ifInErrors;
- DWORD ifInUnknownProtos;
- DWORD ifOutOctets;
- DWORD ifOutUcastPkts;
- DWORD ifOutNUcastPkts;
- DWORD ifOutDiscards;
- DWORD ifOutErrors;
- DWORD ifOutQLen;
- DWORD ifSpecific;
+ u32 ifLastChange;
+ u32 ifInOctets;
+ u32 ifInUcastPkts;
+ u32 ifInNUcastPkts;
+ u32 ifInDiscards;
+ u32 ifInErrors;
+ u32 ifInUnknownProtos;
+ u32 ifOutOctets;
+ u32 ifOutUcastPkts;
+ u32 ifOutNUcastPkts;
+ u32 ifOutDiscards;
+ u32 ifOutErrors;
+ u32 ifOutQLen;
+ u32 ifSpecific;
} SMib2Counter, *PSMib2Counter;
// Value in the ifType entry
@@ -119,32 +111,31 @@ typedef struct tagSMib2Counter {
#define DOWN 2 //
#define TESTING 3 //
-
//
// RMON counter
//
typedef struct tagSRmonCounter {
signed long etherStatsIndex;
- DWORD etherStatsDataSource;
- DWORD etherStatsDropEvents;
- DWORD etherStatsOctets;
- DWORD etherStatsPkts;
- DWORD etherStatsBroadcastPkts;
- DWORD etherStatsMulticastPkts;
- DWORD etherStatsCRCAlignErrors;
- DWORD etherStatsUndersizePkts;
- DWORD etherStatsOversizePkts;
- DWORD etherStatsFragments;
- DWORD etherStatsJabbers;
- DWORD etherStatsCollisions;
- DWORD etherStatsPkt64Octets;
- DWORD etherStatsPkt65to127Octets;
- DWORD etherStatsPkt128to255Octets;
- DWORD etherStatsPkt256to511Octets;
- DWORD etherStatsPkt512to1023Octets;
- DWORD etherStatsPkt1024to1518Octets;
- DWORD etherStatsOwners;
- DWORD etherStatsStatus;
+ u32 etherStatsDataSource;
+ u32 etherStatsDropEvents;
+ u32 etherStatsOctets;
+ u32 etherStatsPkts;
+ u32 etherStatsBroadcastPkts;
+ u32 etherStatsMulticastPkts;
+ u32 etherStatsCRCAlignErrors;
+ u32 etherStatsUndersizePkts;
+ u32 etherStatsOversizePkts;
+ u32 etherStatsFragments;
+ u32 etherStatsJabbers;
+ u32 etherStatsCollisions;
+ u32 etherStatsPkt64Octets;
+ u32 etherStatsPkt65to127Octets;
+ u32 etherStatsPkt128to255Octets;
+ u32 etherStatsPkt256to511Octets;
+ u32 etherStatsPkt512to1023Octets;
+ u32 etherStatsPkt1024to1518Octets;
+ u32 etherStatsOwners;
+ u32 etherStatsStatus;
} SRmonCounter, *PSRmonCounter;
//
@@ -185,56 +176,52 @@ typedef struct tagSCustomCounters {
} SCustomCounters, *PSCustomCounters;
-
//
// Custom counter
//
typedef struct tagSISRCounters {
unsigned long Length;
- DWORD dwIsrTx0OK;
- DWORD dwIsrAC0TxOK;
- DWORD dwIsrBeaconTxOK;
- DWORD dwIsrRx0OK;
- DWORD dwIsrTBTTInt;
- DWORD dwIsrSTIMERInt;
- DWORD dwIsrWatchDog;
- DWORD dwIsrUnrecoverableError;
- DWORD dwIsrSoftInterrupt;
- DWORD dwIsrMIBNearfull;
- DWORD dwIsrRxNoBuf;
-
- DWORD dwIsrUnknown; // unknown interrupt count
-
- DWORD dwIsrRx1OK;
- DWORD dwIsrATIMTxOK;
- DWORD dwIsrSYNCTxOK;
- DWORD dwIsrCFPEnd;
- DWORD dwIsrATIMEnd;
- DWORD dwIsrSYNCFlushOK;
- DWORD dwIsrSTIMER1Int;
+ u32 dwIsrTx0OK;
+ u32 dwIsrAC0TxOK;
+ u32 dwIsrBeaconTxOK;
+ u32 dwIsrRx0OK;
+ u32 dwIsrTBTTInt;
+ u32 dwIsrSTIMERInt;
+ u32 dwIsrWatchDog;
+ u32 dwIsrUnrecoverableError;
+ u32 dwIsrSoftInterrupt;
+ u32 dwIsrMIBNearfull;
+ u32 dwIsrRxNoBuf;
+
+ u32 dwIsrUnknown; // unknown interrupt count
+
+ u32 dwIsrRx1OK;
+ u32 dwIsrATIMTxOK;
+ u32 dwIsrSYNCTxOK;
+ u32 dwIsrCFPEnd;
+ u32 dwIsrATIMEnd;
+ u32 dwIsrSYNCFlushOK;
+ u32 dwIsrSTIMER1Int;
/////////////////////////////////////
} SISRCounters, *PSISRCounters;
-
// Value in the etherStatsStatus entry
#define VALID 1 //
#define CREATE_REQUEST 2 //
#define UNDER_CREATION 3 //
#define INVALID 4 //
-
//
// Tx packet information
//
typedef struct tagSTxPktInfo {
- BYTE byBroadMultiUni;
- WORD wLength;
- WORD wFIFOCtl;
- BYTE abyDestAddr[ETH_ALEN];
+ u8 byBroadMultiUni;
+ u16 wLength;
+ u16 wFIFOCtl;
+ u8 abyDestAddr[ETH_ALEN];
} STxPktInfo, *PSTxPktInfo;
-
#define MAX_RATE 12
//
// statistic counter
@@ -248,34 +235,34 @@ typedef struct tagSStatCounter {
// RSR status count
//
- DWORD dwRsrFrmAlgnErr;
- DWORD dwRsrErr;
- DWORD dwRsrCRCErr;
- DWORD dwRsrCRCOk;
- DWORD dwRsrBSSIDOk;
- DWORD dwRsrADDROk;
- DWORD dwRsrBCNSSIDOk;
- DWORD dwRsrLENErr;
- DWORD dwRsrTYPErr;
-
- DWORD dwNewRsrDECRYPTOK;
- DWORD dwNewRsrCFP;
- DWORD dwNewRsrUTSF;
- DWORD dwNewRsrHITAID;
- DWORD dwNewRsrHITAID0;
-
- DWORD dwRsrLong;
- DWORD dwRsrRunt;
-
- DWORD dwRsrRxControl;
- DWORD dwRsrRxData;
- DWORD dwRsrRxManage;
-
- DWORD dwRsrRxPacket;
- DWORD dwRsrRxOctet;
- DWORD dwRsrBroadcast;
- DWORD dwRsrMulticast;
- DWORD dwRsrDirected;
+ u32 dwRsrFrmAlgnErr;
+ u32 dwRsrErr;
+ u32 dwRsrCRCErr;
+ u32 dwRsrCRCOk;
+ u32 dwRsrBSSIDOk;
+ u32 dwRsrADDROk;
+ u32 dwRsrBCNSSIDOk;
+ u32 dwRsrLENErr;
+ u32 dwRsrTYPErr;
+
+ u32 dwNewRsrDECRYPTOK;
+ u32 dwNewRsrCFP;
+ u32 dwNewRsrUTSF;
+ u32 dwNewRsrHITAID;
+ u32 dwNewRsrHITAID0;
+
+ u32 dwRsrLong;
+ u32 dwRsrRunt;
+
+ u32 dwRsrRxControl;
+ u32 dwRsrRxData;
+ u32 dwRsrRxManage;
+
+ u32 dwRsrRxPacket;
+ u32 dwRsrRxOctet;
+ u32 dwRsrBroadcast;
+ u32 dwRsrMulticast;
+ u32 dwRsrDirected;
// 64-bit OID
unsigned long long ullRsrOK;
@@ -287,47 +274,44 @@ typedef struct tagSStatCounter {
unsigned long long ullRxMulticastFrames;
unsigned long long ullRxDirectedFrames;
- DWORD dwRsrRxFragment;
- DWORD dwRsrRxFrmLen64;
- DWORD dwRsrRxFrmLen65_127;
- DWORD dwRsrRxFrmLen128_255;
- DWORD dwRsrRxFrmLen256_511;
- DWORD dwRsrRxFrmLen512_1023;
- DWORD dwRsrRxFrmLen1024_1518;
+ u32 dwRsrRxFragment;
+ u32 dwRsrRxFrmLen64;
+ u32 dwRsrRxFrmLen65_127;
+ u32 dwRsrRxFrmLen128_255;
+ u32 dwRsrRxFrmLen256_511;
+ u32 dwRsrRxFrmLen512_1023;
+ u32 dwRsrRxFrmLen1024_1518;
// TSR status count
//
- DWORD dwTsrTotalRetry; // total collision retry count
- DWORD dwTsrOnceRetry; // this packet only occur one collision
- DWORD dwTsrMoreThanOnceRetry; // this packet occur more than one collision
- DWORD dwTsrRetry; // this packet has ever occur collision,
+ u32 dwTsrTotalRetry; // total collision retry count
+ u32 dwTsrOnceRetry; // this packet only occur one collision
+ u32 dwTsrMoreThanOnceRetry; // this packet occur more than one collision
+ u32 dwTsrRetry; // this packet has ever occur collision,
// that is (dwTsrOnceCollision0 + dwTsrMoreThanOnceCollision0)
- DWORD dwTsrACKData;
- DWORD dwTsrErr;
- DWORD dwAllTsrOK;
- DWORD dwTsrRetryTimeout;
- DWORD dwTsrTransmitTimeout;
-
- DWORD dwTsrTxPacket;
- DWORD dwTsrTxOctet;
- DWORD dwTsrBroadcast;
- DWORD dwTsrMulticast;
- DWORD dwTsrDirected;
+ u32 dwTsrACKData;
+ u32 dwTsrErr;
+ u32 dwAllTsrOK;
+ u32 dwTsrRetryTimeout;
+ u32 dwTsrTransmitTimeout;
+
+ u32 dwTsrTxPacket;
+ u32 dwTsrTxOctet;
+ u32 dwTsrBroadcast;
+ u32 dwTsrMulticast;
+ u32 dwTsrDirected;
// RD/TD count
- DWORD dwCntRxFrmLength;
- DWORD dwCntTxBufLength;
-
- BYTE abyCntRxPattern[16];
- BYTE abyCntTxPattern[16];
-
+ u32 dwCntRxFrmLength;
+ u32 dwCntTxBufLength;
+ u8 abyCntRxPattern[16];
+ u8 abyCntTxPattern[16];
// Software check....
- DWORD dwCntRxDataErr; // rx buffer data software compare CRC err count
- DWORD dwCntDecryptErr; // rx buffer data software compare CRC err count
- DWORD dwCntRxICVErr; // rx buffer data software compare CRC err count
-
+ u32 dwCntRxDataErr; // rx buffer data software compare CRC err count
+ u32 dwCntDecryptErr; // rx buffer data software compare CRC err count
+ u32 dwCntRxICVErr; // rx buffer data software compare CRC err count
// 64-bit OID
unsigned long long ullTsrOK;
@@ -341,9 +325,9 @@ typedef struct tagSStatCounter {
unsigned long long ullTxDirectedBytes;
// for autorate
- DWORD dwTxOk[MAX_RATE+1];
- DWORD dwTxFail[MAX_RATE+1];
- DWORD dwTxRetryCount[8];
+ u32 dwTxOk[MAX_RATE+1];
+ u32 dwTxFail[MAX_RATE+1];
+ u32 dwTxRetryCount[8];
STxPktInfo abyTxPktInfo[16];
@@ -367,42 +351,28 @@ typedef struct tagSStatCounter {
} SStatCounter, *PSStatCounter;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-void STAvClearAllCounter(PSStatCounter pStatistic);
-
void STAvUpdateIsrStatCounter(PSStatCounter pStatistic,
- BYTE byIsr0,
- BYTE byIsr1);
+ u8 byIsr0,
+ u8 byIsr1);
void STAvUpdateRDStatCounter(PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRSR, BYTE byRxSts,
- BYTE byRxRate, PBYTE pbyBuffer,
+ u8 byRSR, u8 byNewRSR, u8 byRxSts,
+ u8 byRxRate, u8 * pbyBuffer,
unsigned int cbFrameLength);
-void STAvUpdateRDStatCounterEx(PSStatCounter pStatistic,
- BYTE byRSR, BYTE byNewRSR, BYTE byRxSts,
- BYTE byRxRate, PBYTE pbyBuffer,
- unsigned int cbFrameLength);
-
-void STAvUpdateTDStatCounter(PSStatCounter pStatistic, BYTE byPktNum,
- BYTE byRate, BYTE byTSR);
+void STAvUpdateTDStatCounter(PSStatCounter pStatistic, u8 byPktNum,
+ u8 byRate, u8 byTSR);
void
STAvUpdate802_11Counter(
PSDot11Counters p802_11Counter,
PSStatCounter pStatistic,
- BYTE byRTSSuccess,
- BYTE byRTSFail,
- BYTE byACKFail,
- BYTE byFCSErr
+ u8 byRTSSuccess,
+ u8 byRTSFail,
+ u8 byACKFail,
+ u8 byFCSErr
);
-void STAvClear802_11Counter(PSDot11Counters p802_11Counter);
void STAvUpdateUSBCounter(PSUSBCounter pUsbCounter, int ntStatus);
#endif /* __MIB_H__ */
diff --git a/drivers/staging/vt6656/michael.c b/drivers/staging/vt6656/michael.c
index 4d419814f27f..9a5a0b6761ed 100644
--- a/drivers/staging/vt6656/michael.c
+++ b/drivers/staging/vt6656/michael.c
@@ -26,8 +26,8 @@
* Date: Sep 4, 2002
*
* Functions:
- * s_dwGetUINT32 - Convert from BYTE[] to DWORD in a portable way
- * s_vPutUINT32 - Convert from DWORD to BYTE[] in a portable way
+ * s_dwGetUINT32 - Convert from u8[] to u32 in a portable way
+ * s_vPutUINT32 - Convert from u32 to u8[] in a portable way
* s_vClear - Reset the state to the empty message.
* s_vSetKey - Set the key.
* MIC_vInit - Set the key.
@@ -42,49 +42,41 @@
#include "tmacro.h"
#include "michael.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
/*
- * static DWORD s_dwGetUINT32(BYTE * p); Get DWORD from
+ * static u32 s_dwGetUINT32(u8 * p); Get u32 from
* 4 bytes LSByte first
- * static void s_vPutUINT32(BYTE* p, DWORD val); Put DWORD into
+ * static void s_vPutUINT32(u8* p, u32 val); Put u32 into
* 4 bytes LSByte first
*/
static void s_vClear(void); /* Clear the internal message,
* resets the object to the
* state just after construction. */
-static void s_vSetKey(DWORD dwK0, DWORD dwK1);
-static void s_vAppendByte(BYTE b); /* Add a single byte to the internal
+static void s_vSetKey(u32 dwK0, u32 dwK1);
+static void s_vAppendByte(u8 b); /* Add a single byte to the internal
* message */
-/*--------------------- Export Variables --------------------------*/
-static DWORD L, R; /* Current state */
-static DWORD K0, K1; /* Key */
-static DWORD M; /* Message accumulator (single word) */
+static u32 L, R; /* Current state */
+static u32 K0, K1; /* Key */
+static u32 M; /* Message accumulator (single word) */
static unsigned int nBytesInM; /* # bytes in M */
-/*--------------------- Export Functions --------------------------*/
-
/*
-static DWORD s_dwGetUINT32 (BYTE * p)
-// Convert from BYTE[] to DWORD in a portable way
+static u32 s_dwGetUINT32 (u8 * p)
+// Convert from u8[] to u32 in a portable way
{
- DWORD res = 0;
+ u32 res = 0;
unsigned int i;
for (i = 0; i < 4; i++)
res |= (*p++) << (8*i);
return res;
}
-static void s_vPutUINT32(BYTE *p, DWORD val)
-// Convert from DWORD to BYTE[] in a portable way
+static void s_vPutUINT32(u8 *p, u32 val)
+// Convert from u32 to u8[] in a portable way
{
unsigned int i;
for (i = 0; i < 4; i++) {
- *p++ = (BYTE) (val & 0xff);
+ *p++ = (u8) (val & 0xff);
val >>= 8;
}
}
@@ -99,7 +91,7 @@ static void s_vClear(void)
M = 0;
}
-static void s_vSetKey(DWORD dwK0, DWORD dwK1)
+static void s_vSetKey(u32 dwK0, u32 dwK1)
{
/* Set the key */
K0 = dwK0;
@@ -108,7 +100,7 @@ static void s_vSetKey(DWORD dwK0, DWORD dwK1)
s_vClear();
}
-static void s_vAppendByte(BYTE b)
+static void s_vAppendByte(u8 b)
{
/* Append the byte to our word-sized buffer */
M |= b << (8*nBytesInM);
@@ -130,13 +122,12 @@ static void s_vAppendByte(BYTE b)
}
}
-void MIC_vInit(DWORD dwK0, DWORD dwK1)
+void MIC_vInit(u32 dwK0, u32 dwK1)
{
/* Set the key */
s_vSetKey(dwK0, dwK1);
}
-
void MIC_vUnInit(void)
{
/* Wipe the key material */
@@ -148,7 +139,7 @@ void MIC_vUnInit(void)
s_vClear();
}
-void MIC_vAppend(PBYTE src, unsigned int nBytes)
+void MIC_vAppend(u8 * src, unsigned int nBytes)
{
/* This is simple */
while (nBytes > 0) {
@@ -157,7 +148,7 @@ void MIC_vAppend(PBYTE src, unsigned int nBytes)
}
}
-void MIC_vGetMIC(PDWORD pdwL, PDWORD pdwR)
+void MIC_vGetMIC(u32 * pdwL, u32 * pdwR)
{
/* Append the minimum padding */
s_vAppendByte(0x5a);
diff --git a/drivers/staging/vt6656/michael.h b/drivers/staging/vt6656/michael.h
index 81351f506232..9c69a42640a7 100644
--- a/drivers/staging/vt6656/michael.h
+++ b/drivers/staging/vt6656/michael.h
@@ -31,22 +31,18 @@
#ifndef __MICHAEL_H__
#define __MICHAEL_H__
-/*--------------------- Export Definitions -------------------------*/
+#include <linux/types.h>
-/*--------------------- Export Types ------------------------------*/
-
-void MIC_vInit(DWORD dwK0, DWORD dwK1);
+void MIC_vInit(u32 dwK0, u32 dwK1);
void MIC_vUnInit(void);
// Append bytes to the message to be MICed
-void MIC_vAppend(PBYTE src, unsigned int nBytes);
+void MIC_vAppend(u8 * src, unsigned int nBytes);
// Get the MIC result. Destination should accept 8 bytes of result.
// This also resets the message to empty.
-void MIC_vGetMIC(PDWORD pdwL, PDWORD pdwR);
-
-/*--------------------- Export Macros ------------------------------*/
+void MIC_vGetMIC(u32 * pdwL, u32 * pdwR);
// Rotation functions on 32 bit values
#define ROL32(A, n) \
diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c
index 527c259f6758..edc8975b2e2a 100644
--- a/drivers/staging/vt6656/power.c
+++ b/drivers/staging/vt6656/power.c
@@ -37,7 +37,6 @@
*
*/
-#include "ttype.h"
#include "mac.h"
#include "device.h"
#include "wmgr.h"
@@ -48,17 +47,7 @@
#include "control.h"
#include "rndis.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel = MSG_LEVEL_INFO;
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
/*
*
@@ -290,7 +279,7 @@ int PSbSendNullPacket(struct vnt_private *pDevice)
pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags);
if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
- pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_TODS(1));
+ pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_TODS(1));
memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
diff --git a/drivers/staging/vt6656/power.h b/drivers/staging/vt6656/power.h
index 879b10c0d42e..778358239437 100644
--- a/drivers/staging/vt6656/power.h
+++ b/drivers/staging/vt6656/power.h
@@ -29,22 +29,10 @@
#ifndef __POWER_H__
#define __POWER_H__
-
-/*--------------------- Export Definitions -------------------------*/
#define C_PWBT 1000 // micro sec. power up before TBTT
#define PS_FAST_INTERVAL 1 // Fast power saving listen interval
#define PS_MAX_INTERVAL 4 // MAX power saving listen interval
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
-/*--------------------- Export Types ------------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
/* PSDevice pDevice */
/* PSDevice hDeviceContext */
diff --git a/drivers/staging/vt6656/rc4.c b/drivers/staging/vt6656/rc4.c
index 5c3c2d0552b4..2fd836f07536 100644
--- a/drivers/staging/vt6656/rc4.c
+++ b/drivers/staging/vt6656/rc4.c
@@ -32,27 +32,27 @@
#include "rc4.h"
-void rc4_init(PRC4Ext pRC4, PBYTE pbyKey, unsigned int cbKey_len)
+void rc4_init(PRC4Ext pRC4, u8 * pbyKey, unsigned int cbKey_len)
{
unsigned int ust1, ust2;
unsigned int keyindex;
unsigned int stateindex;
- PBYTE pbyst;
+ u8 * pbyst;
unsigned int idx;
pbyst = pRC4->abystate;
pRC4->ux = 0;
pRC4->uy = 0;
for (idx = 0; idx < 256; idx++)
- pbyst[idx] = (BYTE)idx;
+ pbyst[idx] = (u8)idx;
keyindex = 0;
stateindex = 0;
for (idx = 0; idx < 256; idx++) {
ust1 = pbyst[idx];
stateindex = (stateindex + pbyKey[keyindex] + ust1) & 0xff;
ust2 = pbyst[stateindex];
- pbyst[stateindex] = (BYTE)ust1;
- pbyst[idx] = (BYTE)ust2;
+ pbyst[stateindex] = (u8)ust1;
+ pbyst[idx] = (u8)ust2;
if (++keyindex >= cbKey_len)
keyindex = 0;
}
@@ -63,7 +63,7 @@ unsigned int rc4_byte(PRC4Ext pRC4)
unsigned int ux;
unsigned int uy;
unsigned int ustx, usty;
- PBYTE pbyst;
+ u8 * pbyst;
pbyst = pRC4->abystate;
ux = (pRC4->ux + 1) & 0xff;
@@ -72,16 +72,16 @@ unsigned int rc4_byte(PRC4Ext pRC4)
usty = pbyst[uy];
pRC4->ux = ux;
pRC4->uy = uy;
- pbyst[uy] = (BYTE)ustx;
- pbyst[ux] = (BYTE)usty;
+ pbyst[uy] = (u8)ustx;
+ pbyst[ux] = (u8)usty;
return pbyst[(ustx + usty) & 0xff];
}
-void rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest,
- PBYTE pbySrc, unsigned int cbData_len)
+void rc4_encrypt(PRC4Ext pRC4, u8 * pbyDest,
+ u8 * pbySrc, unsigned int cbData_len)
{
unsigned int ii;
for (ii = 0; ii < cbData_len; ii++)
- pbyDest[ii] = (BYTE)(pbySrc[ii] ^ rc4_byte(pRC4));
+ pbyDest[ii] = (u8)(pbySrc[ii] ^ rc4_byte(pRC4));
}
diff --git a/drivers/staging/vt6656/rc4.h b/drivers/staging/vt6656/rc4.h
index d447879c8f99..d376e1adcc1c 100644
--- a/drivers/staging/vt6656/rc4.h
+++ b/drivers/staging/vt6656/rc4.h
@@ -30,19 +30,17 @@
#ifndef __RC4_H__
#define __RC4_H__
-#include "ttype.h"
+#include <linux/types.h>
-/*--------------------- Export Definitions -------------------------*/
-/*--------------------- Export Types ------------------------------*/
typedef struct {
unsigned int ux;
unsigned int uy;
- BYTE abystate[256];
+ u8 abystate[256];
} RC4Ext, *PRC4Ext;
-void rc4_init(PRC4Ext pRC4, PBYTE pbyKey, unsigned int cbKey_len);
+void rc4_init(PRC4Ext pRC4, u8 * pbyKey, unsigned int cbKey_len);
unsigned int rc4_byte(PRC4Ext pRC4);
-void rc4_encrypt(PRC4Ext pRC4, PBYTE pbyDest, PBYTE pbySrc,
+void rc4_encrypt(PRC4Ext pRC4, u8 * pbyDest, u8 * pbySrc,
unsigned int cbData_len);
#endif /* __RC4_H__ */
diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c
index a415705297b2..44cfe0b14180 100644
--- a/drivers/staging/vt6656/rf.c
+++ b/drivers/staging/vt6656/rf.c
@@ -41,7 +41,6 @@
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Definitions -------------------------*/
#define BY_AL2230_REG_LEN 23 //24bit
#define CB_AL2230_INIT_SEQ 15
#define AL2230_PWR_IDX_LEN 64
@@ -62,13 +61,6 @@ static int msglevel =MSG_LEVEL_INFO;
#define VT3342_PWR_IDX_LEN 64
//}}
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-
-
-
u8 abyAL2230InitTable[CB_AL2230_INIT_SEQ][3] = {
{0x03, 0xF7, 0x90},
{0x03, 0x33, 0x31},
@@ -388,7 +380,6 @@ u8 abyVT3226D0_InitTable[CB_VT3226_INIT_SEQ][3] = {
{0x02, 0x01, 0xAA} //RobertYu:20060523
};
-
u8 abyVT3226_ChannelTable0[CB_MAX_CHANNEL_24G][3] = {
{0x01, 0x97, 0x83}, // channel = 1, Tf = 2412MHz
{0x01, 0x97, 0x83}, // channel = 2, Tf = 2417MHz
@@ -424,7 +415,6 @@ u8 abyVT3226_ChannelTable1[CB_MAX_CHANNEL_24G][3] = {
};
///}}RobertYu
-
//{{RobertYu:20060502, TWIF 1.14, LO Current for 11b mode
u32 dwVT3226D0LoCurrentTable[CB_MAX_CHANNEL_24G] = {
0x0135C600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW, // channel = 1, Tf = 2412MHz
@@ -444,7 +434,6 @@ u32 dwVT3226D0LoCurrentTable[CB_MAX_CHANNEL_24G] = {
};
//}}
-
//{{RobertYu:20060609
u8 abyVT3342A0_InitTable[CB_VT3342_INIT_SEQ][3] = { /* 11b/g mode */
{0x03, 0xFF, 0x80}, //update for mode//
@@ -599,7 +588,6 @@ u8 abyVT3342_ChannelTable1[CB_MAX_CHANNEL][3] = {
{0x03, 0x00, 0x04} // channel = 165, Tf = 5825MHz (56), TBD
};
-
/*+
*
* Power Table
@@ -673,10 +661,6 @@ const u32 dwAL2230PowerTable[AL2230_PWR_IDX_LEN] = {
0x0407F900+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW
};
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
//{{ RobertYu:20050103, Channel 11a Number To Index
// 4.9G => Ch 183, 184, 185, 187, 188, 189, 192, 196 (Value:15 ~ 22)
// 5G => Ch 7, 8, 9, 11, 12, 16, 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64,
@@ -708,8 +692,6 @@ const u8 RFaby11aChannelIndex[200] = {
};
//}} RobertYu
-/*--------------------- Export Functions --------------------------*/
-
/*
* Description: Write to IF/RF, by embedded programming
*
@@ -734,11 +716,9 @@ int IFRFbWriteEmbedded(struct vnt_private *pDevice, u32 dwData)
CONTROLnsRequestOut(pDevice,
MESSAGE_TYPE_WRITE_IFRF, 0, 0, 4, pbyData);
-
return true;
}
-
/*
* Description: Set Tx power
*
@@ -790,7 +770,6 @@ int RFbSetPower(struct vnt_private *pDevice, u32 uRATE, u32 uCH)
return bResult;
}
-
/*
* Description: Set Tx power
*
@@ -839,10 +818,9 @@ int RFbRawSetPower(struct vnt_private *pDevice, u8 byPwr, u32 uRATE)
}
break;
-
case RF_AIROHA7230:
{
- DWORD dwMax7230Pwr;
+ u32 dwMax7230Pwr;
if (uRATE <= RATE_11M) { //RobertYu:20060426, for better 11b mask
bResult &= IFRFbWriteEmbedded(pDevice, 0x111BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW);
@@ -864,7 +842,7 @@ int RFbRawSetPower(struct vnt_private *pDevice, u8 byPwr, u32 uRATE)
case RF_VT3226: //RobertYu:20051111, VT3226C0 and before
{
- DWORD dwVT3226Pwr;
+ u32 dwVT3226Pwr;
if (pDevice->byCurPwr >= VT3226_PWR_IDX_LEN)
return false;
@@ -876,7 +854,7 @@ int RFbRawSetPower(struct vnt_private *pDevice, u8 byPwr, u32 uRATE)
case RF_VT3226D0: //RobertYu:20051228
{
- DWORD dwVT3226Pwr;
+ u32 dwVT3226Pwr;
if (pDevice->byCurPwr >= VT3226_PWR_IDX_LEN)
return false;
@@ -921,7 +899,7 @@ int RFbRawSetPower(struct vnt_private *pDevice, u8 byPwr, u32 uRATE)
//{{RobertYu:20060609
case RF_VT3342A0:
{
- DWORD dwVT3342Pwr;
+ u32 dwVT3342Pwr;
if (pDevice->byCurPwr >= VT3342_PWR_IDX_LEN)
return false;
@@ -976,8 +954,6 @@ void RFvRSSITodBm(struct vnt_private *pDevice, u8 byCurrRSSI, long *pldBm)
*pldBm = -1 * (a + b * 2);
}
-
-
void RFbRFTableDownload(struct vnt_private *pDevice)
{
u16 wLength1 = 0, wLength2 = 0, wLength3 = 0;
@@ -1121,20 +1097,3 @@ void RFbRFTableDownload(struct vnt_private *pDevice)
}
}
-
-int s_bVT3226D0_11bLoCurrentAdjust(struct vnt_private *pDevice, u8 byChannel,
- int b11bMode)
-{
- int bResult = true;
-
- if (b11bMode)
- bResult &= IFRFbWriteEmbedded(pDevice,
- dwVT3226D0LoCurrentTable[byChannel-1]);
- else
- bResult &= IFRFbWriteEmbedded(pDevice, 0x016bc600 +
- (BY_VT3226_REG_LEN << 3) + IFREGCTL_REGW);
-
- return bResult;
-}
-
-
diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h
index 9f70cf740bae..de5c613b4ef9 100644
--- a/drivers/staging/vt6656/rf.h
+++ b/drivers/staging/vt6656/rf.h
@@ -30,10 +30,8 @@
#ifndef __RF_H__
#define __RF_H__
-#include "ttype.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
//
// Baseband RF pair definition in eeprom (Bits 6..0)
//
@@ -55,20 +53,12 @@
#define RF_EMU 0x80
#define RF_MASK 0x7F
-
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
extern const u8 RFaby11aChannelIndex[200];
-/*--------------------- Export Functions --------------------------*/
int IFRFbWriteEmbedded(struct vnt_private *, u32 dwData);
int RFbSetPower(struct vnt_private *, u32 uRATE, u32 uCH);
int RFbRawSetPower(struct vnt_private *, u8 byPwr, u32 uRATE);
void RFvRSSITodBm(struct vnt_private *, u8 byCurrRSSI, long *pldBm);
void RFbRFTableDownload(struct vnt_private *pDevice);
-int s_bVT3226D0_11bLoCurrentAdjust(struct vnt_private *, u8 byChannel,
- int b11bMode);
#endif /* __RF_H__ */
diff --git a/drivers/staging/vt6656/rndis.h b/drivers/staging/vt6656/rndis.h
index fccf7e98eb68..5e073062017a 100644
--- a/drivers/staging/vt6656/rndis.h
+++ b/drivers/staging/vt6656/rndis.h
@@ -27,11 +27,9 @@
*
*/
-
#ifndef __RNDIS_H__
#define __RNDIS_H__
-/*--------------------- Export Definitions -------------------------*/
#define MESSAGE_TYPE_READ 0x01
#define MESSAGE_TYPE_WRITE 0x00
#define MESSAGE_TYPE_LOCK_OR 0x02
@@ -66,96 +64,86 @@
#define MESSAGE_REQUEST_RF_CH1 0x0C
#define MESSAGE_REQUEST_RF_CH2 0x0D
-
#define VIAUSB20_PACKET_HEADER 0x04
-
-/*--------------------- Export Classes ----------------------------*/
-
typedef struct _CMD_MESSAGE
{
- BYTE byData[256];
+ u8 byData[256];
} CMD_MESSAGE, *PCMD_MESSAGE;
typedef struct _CMD_WRITE_MASK
{
- BYTE byData;
- BYTE byMask;
+ u8 byData;
+ u8 byMask;
} CMD_WRITE_MASK, *PCMD_WRITE_MASK;
typedef struct _CMD_CARD_INIT
{
- BYTE byInitClass;
- BYTE bExistSWNetAddr;
- BYTE bySWNetAddr[6];
- BYTE byShortRetryLimit;
- BYTE byLongRetryLimit;
+ u8 byInitClass;
+ u8 bExistSWNetAddr;
+ u8 bySWNetAddr[6];
+ u8 byShortRetryLimit;
+ u8 byLongRetryLimit;
} CMD_CARD_INIT, *PCMD_CARD_INIT;
typedef struct _RSP_CARD_INIT
{
- BYTE byStatus;
- BYTE byNetAddr[6];
- BYTE byRFType;
- BYTE byMinChannel;
- BYTE byMaxChannel;
+ u8 byStatus;
+ u8 byNetAddr[6];
+ u8 byRFType;
+ u8 byMinChannel;
+ u8 byMaxChannel;
} RSP_CARD_INIT, *PRSP_CARD_INIT;
typedef struct _CMD_SET_KEY
{
- WORD wKCTL;
- BYTE abyMacAddr[6];
- BYTE abyKey[16];
+ u16 wKCTL;
+ u8 abyMacAddr[6];
+ u8 abyKey[16];
} CMD_SET_KEY, *PCMD_SET_KEY;
typedef struct _CMD_CLRKEY_ENTRY
{
- BYTE abyKeyEntry[11];
+ u8 abyKeyEntry[11];
} CMD_CLRKEY_ENTRY, *PCMD_CLRKEY_ENTRY;
typedef struct _CMD_WRITE_MISCFF
{
- DWORD adwMiscFFData[22][4]; //a key entry has only 22 dwords
+ u32 adwMiscFFData[22][4]; //a key entry has only 22 dwords
} CMD_WRITE_MISCFF, *PCMD_WRITE_MISCFF;
typedef struct _CMD_SET_TSFTBTT
{
- BYTE abyTSF_TBTT[8];
+ u8 abyTSF_TBTT[8];
} CMD_SET_TSFTBTT, *PCMD_SET_TSFTBTT;
typedef struct _CMD_SET_SSTIFS
{
- BYTE bySIFS;
- BYTE byDIFS;
- BYTE byEIFS;
- BYTE bySlotTime;
- BYTE byCwMax_Min;
- BYTE byBBCR10;
+ u8 bySIFS;
+ u8 byDIFS;
+ u8 byEIFS;
+ u8 bySlotTime;
+ u8 byCwMax_Min;
+ u8 byBBCR10;
} CMD_SET_SSTIFS, *PCMD_SET_SSTIFS;
typedef struct _CMD_CHANGE_BBTYPE
{
- BYTE bySIFS;
- BYTE byDIFS;
- BYTE byEIFS;
- BYTE bySlotTime;
- BYTE byCwMax_Min;
- BYTE byBBCR10;
- BYTE byBB_BBType; //CR88
- BYTE byMAC_BBType;
- DWORD dwRSPINF_b_1;
- DWORD dwRSPINF_b_2;
- DWORD dwRSPINF_b_55;
- DWORD dwRSPINF_b_11;
- WORD wRSPINF_a[9];
+ u8 bySIFS;
+ u8 byDIFS;
+ u8 byEIFS;
+ u8 bySlotTime;
+ u8 byCwMax_Min;
+ u8 byBBCR10;
+ u8 byBB_BBType; //CR88
+ u8 byMAC_BBType;
+ u32 dwRSPINF_b_1;
+ u32 dwRSPINF_b_2;
+ u32 dwRSPINF_b_55;
+ u32 dwRSPINF_b_11;
+ u16 wRSPINF_a[9];
} CMD_CHANGE_BBTYPE, *PCMD_CHANGE_BBTYPE;
-/*--------------------- Export Macros -------------------------*/
-
-#define EXCH_WORD(w) ((WORD)((WORD)(w)<<8) | (WORD)((WORD)(w)>>8))
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
+#define EXCH_WORD(w) ((u16)((u16)(w)<<8) | (u16)((u16)(w)>>8))
#endif /* _RNDIS_H_ */
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index b939dcf689d6..9bf2f8d562c3 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -63,32 +63,22 @@
#include "usbpipe.h"
#include "iocmd.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel = MSG_LEVEL_INFO;
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Static Definitions -------------------------*/
-
-const WORD wTimeStampOff[2][MAX_RATE] = {
+const u16 wTimeStampOff[2][MAX_RATE] = {
{384, 288, 226, 209, 54, 43, 37, 31, 28, 25, 24, 23}, // Long Preamble
{384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23}, // Short Preamble
};
-const WORD wFB_Opt0[2][5] = {
+const u16 wFB_Opt0[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, // fallback_rate0
{RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, // fallback_rate1
};
-const WORD wFB_Opt1[2][5] = {
+const u16 wFB_Opt1[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, // fallback_rate0
{RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, // fallback_rate1
};
-
#define RTSDUR_BB 0
#define RTSDUR_BA 1
#define RTSDUR_AA 2
@@ -104,8 +94,6 @@ const WORD wFB_Opt1[2][5] = {
#define DATADUR_A_F0 12
#define DATADUR_A_F1 13
-/*--------------------- Static Functions --------------------------*/
-
static void s_vSaveTxPktInfo(struct vnt_private *pDevice, u8 byPktNum,
u8 *pbyDestAddr, u16 wPktLength, u16 wFIFOCtl);
@@ -114,16 +102,15 @@ static void *s_vGetFreeContext(struct vnt_private *pDevice);
static void s_vGenerateTxParameter(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime,
void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
- PSEthernetHeader psEthHeader);
+ struct ethhdr *psEthHeader);
static u32 s_uFillDataHead(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxDataHead, u32 cbFrameLength,
u32 uDMAIdx, int bNeedAck, u32 uFragIdx, u32 cbLastFragmentSize,
u32 uMACfragNum, u8 byFBOption);
-
static void s_vGenerateMACHeader(struct vnt_private *pDevice,
- u8 *pbyBufferAddr, u16 wDuration, PSEthernetHeader psEthHeader,
+ u8 *pbyBufferAddr, u16 wDuration, struct ethhdr *psEthHeader,
int bNeedEncrypt, u16 wFragType, u32 uDMAIdx, u32 uFragIdx);
static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
@@ -145,7 +132,7 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
- PSEthernetHeader psEthHeader, u16 wCurrentRate, u8 byFBOption);
+ struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption);
static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
@@ -156,9 +143,6 @@ static unsigned int s_uGetRTSCTSDuration(struct vnt_private *pDevice,
u8 byDurType, u32 cbFrameLength, u8 byPktType, u16 wRate,
int bNeedAck, u8 byFBOption);
-
-/*--------------------- Export Variables --------------------------*/
-
static void *s_vGetFreeContext(struct vnt_private *pDevice)
{
PUSB_SEND_CONTEXT pContext = NULL;
@@ -181,7 +165,6 @@ static void *s_vGetFreeContext(struct vnt_private *pDevice)
return (void *) pReturnContext;
}
-
static void s_vSaveTxPktInfo(struct vnt_private *pDevice, u8 byPktNum,
u8 *pbyDestAddr, u16 wPktLength, u16 wFIFOCtl)
{
@@ -208,10 +191,9 @@ static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
u32 *pdwIV = (u32 *)pbyIVHead;
u32 *pdwExtIV = (u32 *)((u8 *)pbyIVHead + 4);
u16 wValue;
- PS802_11Header pMACHeader = (PS802_11Header)pbyHdrBuf;
+ struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyHdrBuf;
u32 dwRevIVCounter;
-
//Fill TXKEY
if (pTransmitKey == NULL)
return;
@@ -222,13 +204,13 @@ static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
if (pTransmitKey->uKeyLength == WLAN_WEP232_KEYLEN ){
- memcpy(pDevice->abyPRNG, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pDevice->abyPRNG, (u8 *)&(dwRevIVCounter), 3);
memcpy(pDevice->abyPRNG+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
} else {
- memcpy(pbyBuf, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf, (u8 *)&(dwRevIVCounter), 3);
memcpy(pbyBuf+3, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
if(pTransmitKey->uKeyLength == WLAN_WEP40_KEYLEN) {
- memcpy(pbyBuf+8, (PBYTE)&(dwRevIVCounter), 3);
+ memcpy(pbyBuf+8, (u8 *)&(dwRevIVCounter), 3);
memcpy(pbyBuf+11, pTransmitKey->abyKey, pTransmitKey->uKeyLength);
}
memcpy(pDevice->abyPRNG, pbyBuf, 16);
@@ -252,7 +234,7 @@ static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
// Make IV
memcpy(pdwIV, pDevice->abyPRNG, 3);
- *(pbyIVHead+3) = (BYTE)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
// Append IV&ExtIV after Mac Header
*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"vFillTxKey()---- pdwExtIV: %x\n",
@@ -267,49 +249,48 @@ static void s_vFillTxKey(struct vnt_private *pDevice, u8 *pbyBuf,
// Make IV
*pdwIV = 0;
- *(pbyIVHead+3) = (BYTE)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
- *pdwIV |= cpu_to_le16((WORD)(pTransmitKey->wTSC15_0));
+ *(pbyIVHead+3) = (u8)(((pDevice->byKeyIndex << 6) & 0xc0) | 0x20); // 0x20 is ExtIV
+ *pdwIV |= cpu_to_le16((u16)(pTransmitKey->wTSC15_0));
//Append IV&ExtIV after Mac Header
*pdwExtIV = cpu_to_le32(pTransmitKey->dwTSC47_16);
//Fill MICHDR0
*pMICHDR = 0x59;
- *((PBYTE)(pMICHDR+1)) = 0; // TxPriority
- memcpy(pMICHDR+2, &(pMACHeader->abyAddr2[0]), 6);
- *((PBYTE)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
- *((PBYTE)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
- *((PBYTE)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
- *((PBYTE)(pMICHDR+14)) = HIBYTE(wPayloadLen);
- *((PBYTE)(pMICHDR+15)) = LOBYTE(wPayloadLen);
+ *((u8 *)(pMICHDR+1)) = 0; // TxPriority
+ memcpy(pMICHDR+2, &(pMACHeader->addr2[0]), 6);
+ *((u8 *)(pMICHDR+8)) = HIBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((u8 *)(pMICHDR+9)) = LOBYTE(HIWORD(pTransmitKey->dwTSC47_16));
+ *((u8 *)(pMICHDR+10)) = HIBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((u8 *)(pMICHDR+11)) = LOBYTE(LOWORD(pTransmitKey->dwTSC47_16));
+ *((u8 *)(pMICHDR+12)) = HIBYTE(pTransmitKey->wTSC15_0);
+ *((u8 *)(pMICHDR+13)) = LOBYTE(pTransmitKey->wTSC15_0);
+ *((u8 *)(pMICHDR+14)) = HIBYTE(wPayloadLen);
+ *((u8 *)(pMICHDR+15)) = LOBYTE(wPayloadLen);
//Fill MICHDR1
- *((PBYTE)(pMICHDR+16)) = 0; // HLEN[15:8]
+ *((u8 *)(pMICHDR+16)) = 0; // HLEN[15:8]
if (pDevice->bLongHeader) {
- *((PBYTE)(pMICHDR+17)) = 28; // HLEN[7:0]
+ *((u8 *)(pMICHDR+17)) = 28; // HLEN[7:0]
} else {
- *((PBYTE)(pMICHDR+17)) = 22; // HLEN[7:0]
+ *((u8 *)(pMICHDR+17)) = 22; // HLEN[7:0]
}
- wValue = cpu_to_le16(pMACHeader->wFrameCtl & 0xC78F);
- memcpy(pMICHDR+18, (PBYTE)&wValue, 2); // MSKFRACTL
- memcpy(pMICHDR+20, &(pMACHeader->abyAddr1[0]), 6);
- memcpy(pMICHDR+26, &(pMACHeader->abyAddr2[0]), 6);
+ wValue = cpu_to_le16(pMACHeader->frame_control & 0xC78F);
+ memcpy(pMICHDR+18, (u8 *)&wValue, 2); // MSKFRACTL
+ memcpy(pMICHDR+20, &(pMACHeader->addr1[0]), 6);
+ memcpy(pMICHDR+26, &(pMACHeader->addr2[0]), 6);
//Fill MICHDR2
- memcpy(pMICHDR+32, &(pMACHeader->abyAddr3[0]), 6);
- wValue = pMACHeader->wSeqCtl;
+ memcpy(pMICHDR+32, &(pMACHeader->addr3[0]), 6);
+ wValue = pMACHeader->seq_ctrl;
wValue &= 0x000F;
wValue = cpu_to_le16(wValue);
- memcpy(pMICHDR+38, (PBYTE)&wValue, 2); // MSKSEQCTL
+ memcpy(pMICHDR+38, (u8 *)&wValue, 2); // MSKSEQCTL
if (pDevice->bLongHeader) {
- memcpy(pMICHDR+40, &(pMACHeader->abyAddr4[0]), 6);
+ memcpy(pMICHDR+40, &(pMACHeader->addr4[0]), 6);
}
}
}
-
static void s_vSWencryption(struct vnt_private *pDevice,
PSKeyItem pTransmitKey, u8 *pbyPayloadHead, u16 wPayloadSize)
{
@@ -324,7 +305,7 @@ static void s_vSWencryption(struct vnt_private *pDevice,
//=======================================================================
// Append ICV after payload
dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize);
+ pdwICV = (u32 *)(pbyPayloadHead + wPayloadSize);
// finally, we must invert dwCRC to get the correct answer
*pdwICV = cpu_to_le32(~dwICV);
// RC4 encryption
@@ -335,7 +316,7 @@ static void s_vSWencryption(struct vnt_private *pDevice,
//=======================================================================
//Append ICV after payload
dwICV = CRCdwGetCrc32Ex(pbyPayloadHead, wPayloadSize, dwICV);//ICV(Payload)
- pdwICV = (PDWORD)(pbyPayloadHead + wPayloadSize);
+ pdwICV = (u32 *)(pbyPayloadHead + wPayloadSize);
// finally, we must invert dwCRC to get the correct answer
*pdwICV = cpu_to_le32(~dwICV);
// RC4 encryption
@@ -345,9 +326,6 @@ static void s_vSWencryption(struct vnt_private *pDevice,
}
}
-
-
-
/*byPktType : PK_TYPE_11A 0
PK_TYPE_11B 1
PK_TYPE_11GB 2
@@ -360,9 +338,9 @@ static u32 s_uGetTxRsvTime(struct vnt_private *pDevice, u8 byPktType,
uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wRate);
if (byPktType == PK_TYPE_11B) {//llb,CCK mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (WORD)pDevice->byTopCCKBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (u16)pDevice->byTopCCKBasicRate);
} else {//11g 2.4G OFDM mode & 11a 5G OFDM mode
- uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (WORD)pDevice->byTopOFDMBasicRate);
+ uAckTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 14, (u16)pDevice->byTopOFDMBasicRate);
}
if (bNeedAck) {
@@ -381,7 +359,6 @@ static u32 s_uGetRTSCTSRsvTime(struct vnt_private *pDevice,
uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
-
uDataTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, cbFrameLength, wCurrentRate);
if (byRTSRsvType == 0) { //RTSTxRrvTime_bb
uRTSTime = BBuGetFrameTime(pDevice->byPreambleType, byPktType, 20, pDevice->byTopCCKBasicRate);
@@ -447,7 +424,6 @@ static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
}
break;
-
case DATADUR_A: //DATADUR_A
if (((uMACfragNum==1)) || (bLastFrag==1)) {//Non Frag or Last Frag
if(bNeedAck){
@@ -566,7 +542,6 @@ static u32 s_uGetDataDuration(struct vnt_private *pDevice, u8 byDurType,
return 0;
}
-
//byFreqType: 0=>5GHZ 1=>2.4GHZ
static u32 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
u32 cbFrameLength, u8 byPktType, u16 wRate, int bNeedAck,
@@ -574,7 +549,6 @@ static u32 s_uGetRTSCTSDuration(struct vnt_private *pDevice, u8 byDurType,
{
u32 uCTSTime = 0, uDurTime = 0;
-
switch (byDurType) {
case RTSDUR_BB: //RTSDuration_bb
@@ -671,10 +645,10 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_ab pBuf = (PSTxDataHead_ab) pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
//Get Duration and TimeStampOff
- pBuf->wDuration = (WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption); //1: 2.4GHz
@@ -688,17 +662,17 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
);
BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
//Get Duration and TimeStamp
- pBuf->wDuration_a = (WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
+ pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength,
byPktType, wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption); //1: 2.4GHz
- pBuf->wDuration_b = (WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
+ pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength,
PK_TYPE_11B, pDevice->byTopCCKBasicRate,
bNeedAck, uFragIdx, cbLastFragmentSize,
uMACfragNum, byFBOption); //1: 2.4GHz
@@ -711,19 +685,19 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (u16 *)&(pBuf->wTransmitLength_a), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
);
BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(pBuf->wTransmitLength_b), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
//Get Duration and TimeStamp
- pBuf->wDuration_a = (WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration_a = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_b = (WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
+ pBuf->wDuration_b = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, PK_TYPE_11B,
pDevice->byTopCCKBasicRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_a_f0 = (WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ pBuf->wDuration_a_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
- pBuf->wDuration_a_f1 = (WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ pBuf->wDuration_a_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //1: 2.4GHz
pBuf->wTimeStampOff_a = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
pBuf->wTimeStampOff_b = wTimeStampOff[pDevice->byPreambleType%2][pDevice->byTopCCKBasicRate%MAX_RATE];
@@ -737,14 +711,14 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
//Get Duration and TimeStampOff
- pBuf->wDuration = (WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
- pBuf->wDuration_f0 = (WORD)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
+ pBuf->wDuration_f0 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F0, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
- pBuf->wDuration_f1 = (WORD)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
+ pBuf->wDuration_f1 = (u16)s_uGetDataDuration(pDevice, DATADUR_A_F1, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx, cbLastFragmentSize, uMACfragNum, byFBOption); //0: 5GHz
if(uDMAIdx!=TYPE_ATIMDMA) {
pBuf->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
@@ -754,10 +728,10 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
//Get Duration and TimeStampOff
- pBuf->wDuration = (WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
+ pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption);
@@ -772,10 +746,10 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType,
- (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(pBuf->wTransmitLength), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
//Get Duration and TimeStampOff
- pBuf->wDuration = (WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
+ pBuf->wDuration = (u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameLength, byPktType,
wCurrentRate, bNeedAck, uFragIdx,
cbLastFragmentSize, uMACfragNum,
byFBOption);
@@ -789,7 +763,7 @@ static u32 s_uFillDataHead(struct vnt_private *pDevice,
static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
void *pvRTS, u32 cbFrameLength, int bNeedAck, int bDisCRC,
- PSEthernetHeader psEthHeader, u16 wCurrentRate, u8 byFBOption)
+ struct ethhdr *psEthHeader, u16 wCurrentRate, u8 byFBOption)
{
u32 uRTSFrameLen = 20;
u16 wLen = 0;
@@ -810,17 +784,17 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
PSRTS_g pBuf = (PSRTS_g)pvRTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3: 2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->Data.wDurationID = pBuf->wDuration_aa;
//Get RTS Frame body
@@ -829,7 +803,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->abyDstAddr[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
}
else {
@@ -844,7 +818,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
}
else {
memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->abySrcAddr[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
}
}
@@ -852,21 +826,21 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_a), (u8 *)&(pBuf->bySignalField_a)
);
pBuf->wTransmitLength_a = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration_bb = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
- pBuf->wDuration_aa = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
- pBuf->wRTSDuration_ba_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_ba_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
- pBuf->wRTSDuration_aa_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
+ pBuf->wDuration_bb = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, PK_TYPE_11B, pDevice->byTopCCKBasicRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration_aa = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //2:RTSDuration_aa, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //1:RTSDuration_ba, 1:2.4G, 2,3:2.4G OFDMData
+ pBuf->wRTSDuration_ba_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //4:wRTSDuration_ba_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:wRTSDuration_aa_f0, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_ba_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //6:wRTSDuration_ba_f1, 1:2.4G, 1:CCKData
+ pBuf->wRTSDuration_aa_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:wRTSDuration_aa_f1, 1:2.4G, 1:CCKData
pBuf->Data.wDurationID = pBuf->wDuration_aa;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -874,7 +848,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->abyDstAddr[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
}
else {
@@ -890,7 +864,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
}
else {
memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->abySrcAddr[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
}
@@ -901,11 +875,11 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -913,7 +887,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->abyDstAddr[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
} else {
memcpy(&(pBuf->Data.abyRA[0]),
@@ -927,7 +901,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
ETH_ALEN);
} else {
memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->abySrcAddr[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
}
@@ -936,13 +910,13 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f0 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
- pBuf->wRTSDuration_f1 = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
+ pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_aa, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f0 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //5:RTSDuration_aa_f0, 0:5G, 0: 5G OFDMData
+ pBuf->wRTSDuration_f1 = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_AA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //7:RTSDuration_aa_f1, 0:5G, 0:
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -950,7 +924,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->abyDstAddr[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
} else {
memcpy(&(pBuf->Data.abyRA[0]),
@@ -963,7 +937,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
ETH_ALEN);
} else {
memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->abySrcAddr[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
}
}
@@ -972,11 +946,11 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
PSRTS_ab pBuf = (PSRTS_ab)pvRTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField), (u8 *)&(pBuf->bySignalField)
);
pBuf->wTransmitLength = cpu_to_le16(wLen);
//Get Duration
- pBuf->wDuration = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
+ pBuf->wDuration = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, RTSDUR_BB, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //0:RTSDuration_bb, 1:2.4G, 1:CCKData
pBuf->Data.wDurationID = pBuf->wDuration;
//Get RTS Frame body
pBuf->Data.wFrameControl = TYPE_CTL_RTS;//0x00B4
@@ -984,7 +958,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
memcpy(&(pBuf->Data.abyRA[0]),
- &(psEthHeader->abyDstAddr[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
}
else {
@@ -999,7 +973,7 @@ static void s_vFillRTSHead(struct vnt_private *pDevice, u8 byPktType,
ETH_ALEN);
} else {
memcpy(&(pBuf->Data.abyTA[0]),
- &(psEthHeader->abySrcAddr[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
}
}
@@ -1028,18 +1002,18 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
PSCTS_FB pBuf = (PSCTS_FB)pvCTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
- pBuf->wDuration_ba = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wDuration_ba += pDevice->wCTSDuration;
pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
//Get CTSDuration_ba_f0
- pBuf->wCTSDuration_ba_f0 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f0 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F0, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //8:CTSDuration_ba_f0, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wCTSDuration_ba_f0 += pDevice->wCTSDuration;
pBuf->wCTSDuration_ba_f0 = cpu_to_le16(pBuf->wCTSDuration_ba_f0);
//Get CTSDuration_ba_f1
- pBuf->wCTSDuration_ba_f1 = (WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wCTSDuration_ba_f1 = (u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA_F1, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption); //9:CTSDuration_ba_f1, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wCTSDuration_ba_f1 += pDevice->wCTSDuration;
pBuf->wCTSDuration_ba_f1 = cpu_to_le16(pBuf->wCTSDuration_ba_f1);
//Get CTS Frame body
@@ -1053,11 +1027,11 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
PSCTS pBuf = (PSCTS)pvCTS;
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B,
- (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b)
+ (u16 *)&(wLen), (u8 *)&(pBuf->byServiceField_b), (u8 *)&(pBuf->bySignalField_b)
);
pBuf->wTransmitLength_b = cpu_to_le16(wLen);
//Get CTSDuration_ba
- pBuf->wDuration_ba = cpu_to_le16((WORD)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
+ pBuf->wDuration_ba = cpu_to_le16((u16)s_uGetRTSCTSDuration(pDevice, CTSDUR_BA, cbFrameLength, byPktType, wCurrentRate, bNeedAck, byFBOption)); //3:CTSDuration_ba, 1:2.4G, 2,3:2.4G OFDM Data
pBuf->wDuration_ba += pDevice->wCTSDuration;
pBuf->wDuration_ba = cpu_to_le16(pBuf->wDuration_ba);
@@ -1098,7 +1072,7 @@ static void s_vFillCTSHead(struct vnt_private *pDevice, u32 uDMAIdx,
static void s_vGenerateTxParameter(struct vnt_private *pDevice,
u8 byPktType, u16 wCurrentRate, void *pTxBufHead, void *pvRrvTime,
void *pvRTS, void *pvCTS, u32 cbFrameSize, int bNeedACK, u32 uDMAIdx,
- PSEthernetHeader psEthHeader)
+ struct ethhdr *psEthHeader)
{
u32 cbMACHdLen = WLAN_HDR_ADDR3_LEN; /* 24 */
u16 wFifoCtl;
@@ -1130,11 +1104,11 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_gRTS pBuf = (PSRrvTime_gRTS)pvRrvTime;
- pBuf->wRTSTxRrvTime_aa = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
- pBuf->wRTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
- pBuf->wRTSTxRrvTime_bb = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime_a = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((WORD) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ pBuf->wRTSTxRrvTime_aa = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 1, byPktType, cbFrameSize, wCurrentRate));//1:RTSTxRrvTime_ba, 1:2.4GHz
+ pBuf->wRTSTxRrvTime_bb = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime_a = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((u16) s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1144,9 +1118,9 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_gCTS pBuf = (PSRrvTime_gCTS)pvRrvTime;
- pBuf->wTxRrvTime_a = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
- pBuf->wTxRrvTime_b = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
- pBuf->wCTSTxRrvTime_ba = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
+ pBuf->wTxRrvTime_a = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//2.4G OFDM
+ pBuf->wTxRrvTime_b = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, pDevice->byTopCCKBasicRate, bNeedACK));//1:CCK
+ pBuf->wCTSTxRrvTime_ba = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 3, byPktType, cbFrameSize, wCurrentRate));//3:CTSTxRrvTime_Ba, 1:2.4GHz
}
//Fill CTS
s_vFillCTSHead(pDevice, uDMAIdx, byPktType, pvCTS, cbFrameSize, bNeedACK, bDisCRC, wCurrentRate, byFBOption);
@@ -1158,8 +1132,8 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
+ pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 2, byPktType, cbFrameSize, wCurrentRate));//2:RTSTxRrvTime_aa, 0:5GHz
+ pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, byPktType, cbFrameSize, wCurrentRate, bNeedACK));//0:OFDM
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1168,7 +1142,7 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
+ pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11A, cbFrameSize, wCurrentRate, bNeedACK)); //0:OFDM
}
}
}
@@ -1178,8 +1152,8 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wRTSTxRrvTime = cpu_to_le16((WORD)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
+ pBuf->wRTSTxRrvTime = cpu_to_le16((u16)s_uGetRTSCTSRsvTime(pDevice, 0, byPktType, cbFrameSize, wCurrentRate));//0:RTSTxRrvTime_bb, 1:2.4GHz
+ pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK));//1:CCK
}
//Fill RTS
s_vFillRTSHead(pDevice, byPktType, pvRTS, cbFrameSize, bNeedACK, bDisCRC, psEthHeader, wCurrentRate, byFBOption);
@@ -1188,21 +1162,21 @@ static void s_vGenerateTxParameter(struct vnt_private *pDevice,
//Fill RsvTime
if (pvRrvTime) {
PSRrvTime_ab pBuf = (PSRrvTime_ab)pvRrvTime;
- pBuf->wTxRrvTime = cpu_to_le16((WORD)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
+ pBuf->wTxRrvTime = cpu_to_le16((u16)s_uGetTxRsvTime(pDevice, PK_TYPE_11B, cbFrameSize, wCurrentRate, bNeedACK)); //1:CCK
}
}
}
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_vGenerateTxParameter END.\n");
}
/*
- PBYTE pbyBuffer,//point to pTxBufHead
- WORD wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
+ u8 * pbyBuffer,//point to pTxBufHead
+ u16 wFragType,//00:Non-Frag, 01:Start, 02:Mid, 03:Last
unsigned int cbFragmentSize,//Hdr+payoad+FCS
*/
static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
u8 *usbPacketBuf, int bNeedEncryption, u32 uSkbPacketLen, u32 uDMAIdx,
- PSEthernetHeader psEthHeader, u8 *pPacket, PSKeyItem pTransmitKey,
+ struct ethhdr *psEthHeader, u8 *pPacket, PSKeyItem pTransmitKey,
u32 uNodeIndex, u16 wCurrentRate, u32 *pcbHeaderLen, u32 *pcbTotalLen)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
@@ -1240,7 +1214,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
memset(pTxBufHead, 0, sizeof(TX_BUFFER));
// Get pkt type
- if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
+ if (ntohs(psEthHeader->h_proto) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
cb802_1_H_len = 8;
} else {
@@ -1253,7 +1227,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
cbFrameBodySize = uSkbPacketLen - ETH_HLEN + cb802_1_H_len;
//Set packet type
- pTxBufHead->wFIFOCtl |= (WORD)(byPktType<<8);
+ pTxBufHead->wFIFOCtl |= (u16)(byPktType<<8);
if (pDevice->dwDiagRefCount != 0) {
bNeedACK = false;
@@ -1261,7 +1235,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
} else { //if (pDevice->dwDiagRefCount != 0) {
if ((pDevice->eOPMode == OP_MODE_ADHOC) ||
(pDevice->eOPMode == OP_MODE_AP)) {
- if (is_multicast_ether_addr(psEthHeader->abyDstAddr)) {
+ if (is_multicast_ether_addr(psEthHeader->h_dest)) {
bNeedACK = false;
pTxBufHead->wFIFOCtl =
pTxBufHead->wFIFOCtl & (~FIFOCTL_NEEDACK);
@@ -1293,7 +1267,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
} else {
cbMACHdLen = WLAN_HDR_ADDR3_LEN;
}
- pTxBufHead->wFragCtl |= (WORD)(cbMACHdLen << 10);
+ pTxBufHead->wFragCtl |= (u16)(cbMACHdLen << 10);
//Set FIFOCTL_GrpAckPolicy
if (pDevice->bGrpAckPolicy == true) {//0000 0100 0000 0000
@@ -1326,7 +1300,6 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
}
}
-
if ((bNeedEncryption) && (pTransmitKey != NULL)) {
if (pTransmitKey->byCipherSuite == KEY_CTL_WEP) {
cbIVlen = 4;
@@ -1358,7 +1331,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
pTxBufHead->wFIFOCtl |= (FIFOCTL_RTS | FIFOCTL_LRETRY);
}
- pbyTxBufferAddr = (PBYTE) &(pTxBufHead->adwTxKey[0]);
+ pbyTxBufferAddr = (u8 *) &(pTxBufHead->adwTxKey[0]);
wTxBufSize = sizeof(STxBufHead);
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
if (byFBOption == AUTO_FB_NONE) {
@@ -1437,10 +1410,9 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
} // Auto Fall Back
}
- pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderLength);
- pbyIVHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding);
- pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
-
+ pbyMacHdr = (u8 *)(pbyTxBufferAddr + cbHeaderLength);
+ pbyIVHead = (u8 *)(pbyMacHdr + cbMACHdLen + uPadding);
+ pbyPayloadHead = (u8 *)(pbyMacHdr + cbMACHdLen + uPadding + cbIVlen);
//=========================
// No Fragmentation
@@ -1450,7 +1422,6 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
//uDMAIdx = TYPE_AC0DMA;
//pTxBufHead = (PSTxBufHead) &(pTxBufHead->adwTxKey[0]);
-
//Fill FIFO,RrvTime,RTS,and CTS
s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate,
(void *)pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
@@ -1459,13 +1430,13 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, uDMAIdx, bNeedACK,
0, 0, 1/*uMACfragNum*/, byFBOption);
// Generate TX MAC Header
- s_vGenerateMACHeader(pDevice, pbyMacHdr, (WORD)uDuration, psEthHeader, bNeedEncryption,
+ s_vGenerateMACHeader(pDevice, pbyMacHdr, (u16)uDuration, psEthHeader, bNeedEncryption,
byFragType, uDMAIdx, 0);
if (bNeedEncryption == true) {
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -1474,25 +1445,24 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
}
// 802.1H
- if (ntohs(psEthHeader->wType) > ETH_DATA_LEN) {
+ if (ntohs(psEthHeader->h_proto) > ETH_DATA_LEN) {
if (pDevice->dwDiagRefCount == 0) {
- if ((psEthHeader->wType == cpu_to_be16(ETH_P_IPX)) ||
- (psEthHeader->wType == cpu_to_le16(0xF380))) {
- memcpy((PBYTE) (pbyPayloadHead),
+ if ((psEthHeader->h_proto == cpu_to_be16(ETH_P_IPX)) ||
+ (psEthHeader->h_proto == cpu_to_le16(0xF380))) {
+ memcpy((u8 *) (pbyPayloadHead),
abySNAP_Bridgetunnel, 6);
} else {
- memcpy((PBYTE) (pbyPayloadHead), &abySNAP_RFC1042[0], 6);
+ memcpy((u8 *) (pbyPayloadHead), &abySNAP_RFC1042[0], 6);
}
- pbyType = (PBYTE) (pbyPayloadHead + 6);
- memcpy(pbyType, &(psEthHeader->wType), sizeof(WORD));
+ pbyType = (u8 *) (pbyPayloadHead + 6);
+ memcpy(pbyType, &(psEthHeader->h_proto), sizeof(u16));
} else {
- memcpy((PBYTE) (pbyPayloadHead), &(psEthHeader->wType), sizeof(WORD));
+ memcpy((u8 *) (pbyPayloadHead), &(psEthHeader->h_proto), sizeof(u16));
}
}
-
if (pPacket != NULL) {
// Copy the Packet into a tx Buffer
memcpy((pbyPayloadHead + cb802_1_H_len),
@@ -1502,7 +1472,7 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
} else {
// while bRelayPacketSend psEthHeader is point to header+payload
- memcpy((pbyPayloadHead + cb802_1_H_len), ((PBYTE)psEthHeader) + ETH_HLEN, uSkbPacketLen - ETH_HLEN);
+ memcpy((pbyPayloadHead + cb802_1_H_len), ((u8 *)psEthHeader) + ETH_HLEN, uSkbPacketLen - ETH_HLEN);
}
ASSERT(uLength == cbNdisBodySize);
@@ -1516,18 +1486,18 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
}
else if ((pTransmitKey->dwKeyIndex & AUTHENTICATOR_KEY) != 0) {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
}
else {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[24]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[28]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[24]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[28]);
}
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(psEthHeader->abyDstAddr[0]), 12);
+ MIC_vAppend((u8 *)&(psEthHeader->h_dest[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((u8 *)&dwMIC_Priority, 4);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC KEY: %X, %X\n",
dwMICKey0, dwMICKey1);
@@ -1535,14 +1505,14 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
//DBG_PRN_GRP12(("Length:%d, %d\n", cbFrameBodySize, uFromHDtoPLDLength));
//for (ii = 0; ii < cbFrameBodySize; ii++) {
- // DBG_PRN_GRP12(("%02x ", *((PBYTE)((pbyPayloadHead + cb802_1_H_len) + ii))));
+ // DBG_PRN_GRP12(("%02x ", *((u8 *)((pbyPayloadHead + cb802_1_H_len) + ii))));
//}
//DBG_PRN_GRP12(("\n\n\n"));
MIC_vAppend(pbyPayloadHead, cbFrameBodySize);
- pdwMIC_L = (PDWORD)(pbyPayloadHead + cbFrameBodySize);
- pdwMIC_R = (PDWORD)(pbyPayloadHead + cbFrameBodySize + 4);
+ pdwMIC_L = (u32 *)(pbyPayloadHead + cbFrameBodySize);
+ pdwMIC_R = (u32 *)(pbyPayloadHead + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
@@ -1557,10 +1527,9 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
//DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"MIC:%lX, %lX\n", *pdwMIC_L, *pdwMIC_R);
}
-
if (bSoftWEP == true) {
- s_vSWencryption(pDevice, pTransmitKey, (pbyPayloadHead), (WORD)(cbFrameBodySize + cbMIClen));
+ s_vSWencryption(pDevice, pTransmitKey, (pbyPayloadHead), (u16)(cbFrameBodySize + cbMIClen));
} else if ( ((pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) && (bNeedEncryption == true)) ||
((pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled) && (bNeedEncryption == true)) ||
@@ -1570,13 +1539,13 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
if (pDevice->bSoftwareGenCrcErr == true) {
unsigned int cbLen;
- PDWORD pdwCRC;
+ u32 * pdwCRC;
dwCRC = 0xFFFFFFFFL;
cbLen = cbFrameSize - cbFCSlen;
// calculate CRC, and wrtie CRC value to end of TD
dwCRC = CRCdwGetCrc32Ex(pbyMacHdr, cbLen, dwCRC);
- pdwCRC = (PDWORD)(pbyMacHdr + cbLen);
+ pdwCRC = (u32 *)(pbyMacHdr + cbLen);
// finally, we must invert dwCRC to get the correct answer
*pdwCRC = ~dwCRC;
// Force Error
@@ -1588,16 +1557,13 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
*pcbHeaderLen = cbHeaderLength;
*pcbTotalLen = cbHeaderLength + cbFrameSize ;
-
//Set FragCtl in TxBufferHead
- pTxBufHead->wFragCtl |= (WORD)byFragType;
-
+ pTxBufHead->wFragCtl |= (u16)byFragType;
return true;
}
-
/*+
*
* Description:
@@ -1618,67 +1584,67 @@ static int s_bPacketToWirelessUsb(struct vnt_private *pDevice, u8 byPktType,
-*/
static void s_vGenerateMACHeader(struct vnt_private *pDevice,
- u8 *pbyBufferAddr, u16 wDuration, PSEthernetHeader psEthHeader,
+ u8 *pbyBufferAddr, u16 wDuration, struct ethhdr *psEthHeader,
int bNeedEncrypt, u16 wFragType, u32 uDMAIdx, u32 uFragIdx)
{
- PS802_11Header pMACHeader = (PS802_11Header)pbyBufferAddr;
+ struct ieee80211_hdr *pMACHeader = (struct ieee80211_hdr *)pbyBufferAddr;
- memset(pMACHeader, 0, (sizeof(S802_11Header))); //- sizeof(pMACHeader->dwIV)));
+ memset(pMACHeader, 0, (sizeof(struct ieee80211_hdr)));
if (uDMAIdx == TYPE_ATIMDMA) {
- pMACHeader->wFrameCtl = TYPE_802_11_ATIM;
+ pMACHeader->frame_control = TYPE_802_11_ATIM;
} else {
- pMACHeader->wFrameCtl = TYPE_802_11_DATA;
+ pMACHeader->frame_control = TYPE_802_11_DATA;
}
if (pDevice->eOPMode == OP_MODE_AP) {
- memcpy(&(pMACHeader->abyAddr1[0]),
- &(psEthHeader->abyDstAddr[0]),
+ memcpy(&(pMACHeader->addr1[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr3[0]),
- &(psEthHeader->abySrcAddr[0]),
+ memcpy(&(pMACHeader->addr2[0]), &(pDevice->abyBSSID[0]), ETH_ALEN);
+ memcpy(&(pMACHeader->addr3[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
- pMACHeader->wFrameCtl |= FC_FROMDS;
+ pMACHeader->frame_control |= FC_FROMDS;
} else {
if (pDevice->eOPMode == OP_MODE_ADHOC) {
- memcpy(&(pMACHeader->abyAddr1[0]),
- &(psEthHeader->abyDstAddr[0]),
+ memcpy(&(pMACHeader->addr1[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]),
- &(psEthHeader->abySrcAddr[0]),
+ memcpy(&(pMACHeader->addr2[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr3[0]),
+ memcpy(&(pMACHeader->addr3[0]),
&(pDevice->abyBSSID[0]),
ETH_ALEN);
} else {
- memcpy(&(pMACHeader->abyAddr3[0]),
- &(psEthHeader->abyDstAddr[0]),
+ memcpy(&(pMACHeader->addr3[0]),
+ &(psEthHeader->h_dest[0]),
ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr2[0]),
- &(psEthHeader->abySrcAddr[0]),
+ memcpy(&(pMACHeader->addr2[0]),
+ &(psEthHeader->h_source[0]),
ETH_ALEN);
- memcpy(&(pMACHeader->abyAddr1[0]),
+ memcpy(&(pMACHeader->addr1[0]),
&(pDevice->abyBSSID[0]),
ETH_ALEN);
- pMACHeader->wFrameCtl |= FC_TODS;
+ pMACHeader->frame_control |= FC_TODS;
}
}
if (bNeedEncrypt)
- pMACHeader->wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_ISWEP(1));
+ pMACHeader->frame_control |= cpu_to_le16((u16)WLAN_SET_FC_ISWEP(1));
- pMACHeader->wDurationID = cpu_to_le16(wDuration);
+ pMACHeader->duration_id = cpu_to_le16(wDuration);
if (pDevice->bLongHeader) {
PWLAN_80211HDR_A4 pMACA4Header = (PWLAN_80211HDR_A4) pbyBufferAddr;
- pMACHeader->wFrameCtl |= (FC_TODS | FC_FROMDS);
+ pMACHeader->frame_control |= (FC_TODS | FC_FROMDS);
memcpy(pMACA4Header->abyAddr4, pDevice->abyBSSID, WLAN_ADDR_LEN);
}
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pMACHeader->seq_ctrl = cpu_to_le16(pDevice->wSeqCounter << 4);
//Set FragNumber in Sequence Control
- pMACHeader->wSeqCtl |= cpu_to_le16((WORD)uFragIdx);
+ pMACHeader->seq_ctrl |= cpu_to_le16((u16)uFragIdx);
if ((wFragType == FRAGCTL_ENDFRAG) || (wFragType == FRAGCTL_NONFRAG)) {
pDevice->wSeqCounter++;
@@ -1687,12 +1653,10 @@ static void s_vGenerateMACHeader(struct vnt_private *pDevice,
}
if ((wFragType == FRAGCTL_STAFRAG) || (wFragType == FRAGCTL_MIDFRAG)) { //StartFrag or MidFrag
- pMACHeader->wFrameCtl |= FC_MOREFRAG;
+ pMACHeader->frame_control |= FC_MOREFRAG;
}
}
-
-
/*+
*
* Description:
@@ -1717,9 +1681,9 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
PTX_BUFFER pTX_Buffer;
PSTxBufHead pTxBufHead;
PUSB_SEND_CONTEXT pContext;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
PSCTS pCTS;
- SEthernetHeader sEthHeader;
+ struct ethhdr sEthHeader;
u8 byPktType, *pbyTxBufferAddr;
void *pvRTS, *pvTxDataHd, *pvRrvTime, *pMICHDR;
u32 uDuration, cbReqCount, cbHeaderSize, cbFrameBodySize, cbFrameSize;
@@ -1730,8 +1694,6 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
u32 cbMacHdLen;
u16 wCurrentRate = RATE_1M;
-
-
pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
@@ -1740,7 +1702,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
}
pTX_Buffer = (PTX_BUFFER) (&pContext->Data[0]);
- pbyTxBufferAddr = (PBYTE)&(pTX_Buffer->adwTxKey[0]);
+ pbyTxBufferAddr = (u8 *)&(pTX_Buffer->adwTxKey[0]);
cbFrameBodySize = pPacket->cbPayloadLen;
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
@@ -1765,7 +1727,6 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
}
pDevice->wCurrentRate = wCurrentRate;
-
//Set packet type
if (byPktType == PK_TYPE_11A) {//0000 0000 0000 0000
pTxBufHead->wFIFOCtl = 0;
@@ -1814,7 +1775,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
}
//Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((WORD)(cbMacHdLen << 10));
+ pTxBufHead->wFragCtl |= cpu_to_le16((u16)(cbMacHdLen << 10));
// Notes:
// Although spec says MMPDU can be fragmented; In most case,
@@ -1877,17 +1838,16 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
(cbHeaderSize - wTxBufSize));
- memcpy(&(sEthHeader.abyDstAddr[0]),
+ memcpy(&(sEthHeader.h_dest[0]),
&(pPacket->p80211Header->sA3.abyAddr1[0]),
ETH_ALEN);
- memcpy(&(sEthHeader.abySrcAddr[0]),
+ memcpy(&(sEthHeader.h_source[0]),
&(pPacket->p80211Header->sA3.abyAddr2[0]),
ETH_ALEN);
//=========================
// No Fragmentation
//=========================
- pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG;
-
+ pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
//Fill FIFO,RrvTime,RTS,and CTS
s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, pbyTxBufferAddr, pvRrvTime, pvRTS, pCTS,
@@ -1897,18 +1857,18 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
0, 0, 1, AUTO_FB_NONE);
- pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
+ pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + cbFrameBodySize;
if (WLAN_GET_FC_ISWEP(pPacket->p80211Header->sA4.wFrameCtl) != 0) {
- PBYTE pbyIVHead;
- PBYTE pbyPayloadHead;
- PBYTE pbyBSSID;
+ u8 * pbyIVHead;
+ u8 * pbyPayloadHead;
+ u8 * pbyBSSID;
PSKeyItem pTransmitKey = NULL;
- pbyIVHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
- pbyPayloadHead = (PBYTE)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
+ pbyIVHead = (u8 *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding);
+ pbyPayloadHead = (u8 *)(pbyTxBufferAddr + cbHeaderSize + cbMacHdLen + uPadding + cbIVlen);
do {
if ((pDevice->eOPMode == OP_MODE_INFRASTRUCTURE) &&
(pDevice->bLinkPass == true)) {
@@ -1935,11 +1895,11 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
}
} while(false);
//Fill TXKEY
- s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- (PBYTE)pMACHeader, (WORD)cbFrameBodySize, NULL);
+ s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ (u8 *)pMACHeader, (u16)cbFrameBodySize, NULL);
memcpy(pMACHeader, pPacket->p80211Header, cbMacHdLen);
- memcpy(pbyPayloadHead, ((PBYTE)(pPacket->p80211Header) + cbMacHdLen),
+ memcpy(pbyPayloadHead, ((u8 *)(pPacket->p80211Header) + cbMacHdLen),
cbFrameBodySize);
}
else {
@@ -1947,7 +1907,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
}
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pMACHeader->seq_ctrl = cpu_to_le16(pDevice->wSeqCounter << 4);
pDevice->wSeqCounter++ ;
if (pDevice->wSeqCounter > 0x0fff)
pDevice->wSeqCounter = 0;
@@ -1966,27 +1926,25 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice,
}
}
-
- pTX_Buffer->wTxByteCount = cpu_to_le16((WORD)(cbReqCount));
- pTX_Buffer->byPKTNO = (BYTE) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
+ pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
+ pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
pTX_Buffer->byType = 0x00;
pContext->pPacket = NULL;
pContext->Type = CONTEXT_MGMT_PACKET;
- pContext->uBufLen = (WORD)cbReqCount + 4; //USB header
+ pContext->uBufLen = (u16)cbReqCount + 4; //USB header
- if (WLAN_GET_FC_TODS(pMACHeader->wFrameCtl) == 0) {
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->abyAddr1[0]),(WORD)cbFrameSize,pTX_Buffer->wFIFOCtl);
+ if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) {
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr1[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl);
}
else {
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->abyAddr3[0]),(WORD)cbFrameSize,pTX_Buffer->wFIFOCtl);
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr3[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl);
}
PIPEnsSendBulkOut(pDevice,pContext);
return CMD_STATUS_PENDING;
}
-
CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pPacket)
{
@@ -1994,7 +1952,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
u32 cbHeaderSize = 0;
u16 wTxBufSize = sizeof(STxShortBufHead);
PSTxShortBufHead pTxBufHead;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
PSTxDataHead_ab pTxDataHead;
u16 wCurrentRate;
u32 cbFrameBodySize;
@@ -2004,7 +1962,6 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
PUSB_SEND_CONTEXT pContext;
CMD_STATUS status;
-
pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
status = CMD_STATUS_RESOURCES;
@@ -2012,7 +1969,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
return status ;
}
pTX_Buffer = (PBEACON_BUFFER) (&pContext->Data[0]);
- pbyTxBufferAddr = (PBYTE)&(pTX_Buffer->wFIFOCtl);
+ pbyTxBufferAddr = (u8 *)&(pTX_Buffer->wFIFOCtl);
cbFrameBodySize = pPacket->cbPayloadLen;
@@ -2025,10 +1982,10 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A,
- (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField)
+ (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
);
//Get Duration and TimeStampOff
- pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, PK_TYPE_11A,
+ pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_A, cbFrameSize, PK_TYPE_11A,
wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
@@ -2038,41 +1995,40 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice,
pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize);
//Get SignalField,ServiceField,Length
BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B,
- (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField)
+ (u16 *)&(pTxDataHead->wTransmitLength), (u8 *)&(pTxDataHead->byServiceField), (u8 *)&(pTxDataHead->bySignalField)
);
//Get Duration and TimeStampOff
- pTxDataHead->wDuration = cpu_to_le16((WORD)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, PK_TYPE_11B,
+ pTxDataHead->wDuration = cpu_to_le16((u16)s_uGetDataDuration(pDevice, DATADUR_B, cbFrameSize, PK_TYPE_11B,
wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE));
pTxDataHead->wTimeStampOff = wTimeStampOff[pDevice->byPreambleType%2][wCurrentRate%MAX_RATE];
cbHeaderSize = wTxBufSize + sizeof(STxDataHead_ab);
}
//Generate Beacon Header
- pMACHeader = (PS802_11Header)(pbyTxBufferAddr + cbHeaderSize);
+ pMACHeader = (struct ieee80211_hdr *)(pbyTxBufferAddr + cbHeaderSize);
memcpy(pMACHeader, pPacket->p80211Header, pPacket->cbMPDULen);
- pMACHeader->wDurationID = 0;
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pMACHeader->duration_id = 0;
+ pMACHeader->seq_ctrl = cpu_to_le16(pDevice->wSeqCounter << 4);
pDevice->wSeqCounter++ ;
if (pDevice->wSeqCounter > 0x0fff)
pDevice->wSeqCounter = 0;
cbReqCount = cbHeaderSize + WLAN_HDR_ADDR3_LEN + cbFrameBodySize;
- pTX_Buffer->wTxByteCount = (WORD)cbReqCount;
- pTX_Buffer->byPKTNO = (BYTE) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
+ pTX_Buffer->wTxByteCount = (u16)cbReqCount;
+ pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
pTX_Buffer->byType = 0x01;
pContext->pPacket = NULL;
pContext->Type = CONTEXT_MGMT_PACKET;
- pContext->uBufLen = (WORD)cbReqCount + 4; //USB header
+ pContext->uBufLen = (u16)cbReqCount + 4; //USB header
PIPEnsSendBulkOut(pDevice,pContext);
return CMD_STATUS_PENDING;
}
-
void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
@@ -2080,7 +2036,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
u8 *pbyTxBufferAddr;
void *pvRTS, *pvCTS, *pvTxDataHd;
u32 uDuration, cbReqCount;
- PS802_11Header pMACHeader;
+ struct ieee80211_hdr *pMACHeader;
u32 cbHeaderSize, cbFrameBodySize;
int bNeedACK, bIsPSPOLL = false;
PSTxBufHead pTxBufHead;
@@ -2093,7 +2049,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
u32 *pdwMIC_L, *pdwMIC_R;
u16 wTxBufSize;
u32 cbMacHdLen;
- SEthernetHeader sEthHeader;
+ struct ethhdr sEthHeader;
void *pvRrvTime, *pMICHDR;
u32 wCurrentRate = RATE_1M;
PUWLAN_80211HDR p80211Header;
@@ -2106,7 +2062,6 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
PTX_BUFFER pTX_Buffer;
PUSB_SEND_CONTEXT pContext;
-
pvRrvTime = pMICHDR = pvRTS = pvCTS = pvTxDataHd = NULL;
if(skb->len <= WLAN_HDR_ADDR3_LEN) {
@@ -2126,7 +2081,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
pTX_Buffer = (PTX_BUFFER)(&pContext->Data[0]);
- pbyTxBufferAddr = (PBYTE)(&pTX_Buffer->adwTxKey[0]);
+ pbyTxBufferAddr = (u8 *)(&pTX_Buffer->adwTxKey[0]);
pTxBufHead = (PSTxBufHead) pbyTxBufferAddr;
wTxBufSize = sizeof(STxBufHead);
memset(pTxBufHead, 0, wTxBufSize);
@@ -2177,7 +2132,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
else {
if (pDevice->bEnableHostWEP) {
- if (BSSbIsSTAInNodeDB(pDevice, (PBYTE)(p80211Header->sA3.abyAddr1), &uNodeIndex))
+ if (BSSbIsSTAInNodeDB(pDevice, (u8 *)(p80211Header->sA3.abyAddr1), &uNodeIndex))
bNodeExist = true;
}
bNeedACK = true;
@@ -2223,16 +2178,14 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
}
-
//Set FRAGCTL_MACHDCNT
- pTxBufHead->wFragCtl |= cpu_to_le16((WORD)cbMacHdLen << 10);
+ pTxBufHead->wFragCtl |= cpu_to_le16((u16)cbMacHdLen << 10);
// Notes:
// Although spec says MMPDU can be fragmented; In most case,
// no one will send a MMPDU under fragmentation. With RTS may occur.
pDevice->bAES = false; //Set FRAGCTL_WEPTYP
-
if (WLAN_GET_FC_ISWEP(p80211Header->sA4.wFrameCtl) != 0) {
if (pDevice->eEncryptionStatus == Ndis802_11Encryption1Enabled) {
cbIVlen = 4;
@@ -2268,7 +2221,6 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
//the rest of pTxBufHead->wFragCtl:FragTyp will be set later in s_vFillFragParameter()
-
if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {//802.11g packet
pvRrvTime = (PSRrvTime_gCTS) (pbyTxBufferAddr + wTxBufSize);
@@ -2290,17 +2242,16 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
memset((void *)(pbyTxBufferAddr + wTxBufSize), 0,
(cbHeaderSize - wTxBufSize));
- memcpy(&(sEthHeader.abyDstAddr[0]),
+ memcpy(&(sEthHeader.h_dest[0]),
&(p80211Header->sA3.abyAddr1[0]),
ETH_ALEN);
- memcpy(&(sEthHeader.abySrcAddr[0]),
+ memcpy(&(sEthHeader.h_source[0]),
&(p80211Header->sA3.abyAddr2[0]),
ETH_ALEN);
//=========================
// No Fragmentation
//=========================
- pTxBufHead->wFragCtl |= (WORD)FRAGCTL_NONFRAG;
-
+ pTxBufHead->wFragCtl |= (u16)FRAGCTL_NONFRAG;
//Fill FIFO,RrvTime,RTS,and CTS
s_vGenerateTxParameter(pDevice, byPktType, wCurrentRate, pbyTxBufferAddr, pvRrvTime, pvRTS, pvCTS,
@@ -2310,19 +2261,19 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
uDuration = s_uFillDataHead(pDevice, byPktType, wCurrentRate, pvTxDataHd, cbFrameSize, TYPE_TXDMA0, bNeedACK,
0, 0, 1, AUTO_FB_NONE);
- pMACHeader = (PS802_11Header) (pbyTxBufferAddr + cbHeaderSize);
+ pMACHeader = (struct ieee80211_hdr *) (pbyTxBufferAddr + cbHeaderSize);
cbReqCount = cbHeaderSize + cbMacHdLen + uPadding + cbIVlen + (cbFrameBodySize + cbMIClen) + cbExtSuppRate;
- pbyMacHdr = (PBYTE)(pbyTxBufferAddr + cbHeaderSize);
- pbyPayloadHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
- pbyIVHead = (PBYTE)(pbyMacHdr + cbMacHdLen + uPadding);
+ pbyMacHdr = (u8 *)(pbyTxBufferAddr + cbHeaderSize);
+ pbyPayloadHead = (u8 *)(pbyMacHdr + cbMacHdLen + uPadding + cbIVlen);
+ pbyIVHead = (u8 *)(pbyMacHdr + cbMacHdLen + uPadding);
// Copy the Packet into a tx Buffer
memcpy(pbyMacHdr, skb->data, cbMacHdLen);
// version set to 0, patch for hostapd deamon
- pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc);
+ pMACHeader->frame_control &= cpu_to_le16(0xfffc);
memcpy(pbyPayloadHead, (skb->data + cbMacHdLen), cbFrameBodySize);
// replace support rate, patch for hostapd daemon( only support 11M)
@@ -2359,14 +2310,14 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
if ((pTransmitKey != NULL) && (pTransmitKey->byCipherSuite == KEY_CTL_TKIP)) {
- dwMICKey0 = *(PDWORD)(&pTransmitKey->abyKey[16]);
- dwMICKey1 = *(PDWORD)(&pTransmitKey->abyKey[20]);
+ dwMICKey0 = *(u32 *)(&pTransmitKey->abyKey[16]);
+ dwMICKey1 = *(u32 *)(&pTransmitKey->abyKey[20]);
// DO Software Michael
MIC_vInit(dwMICKey0, dwMICKey1);
- MIC_vAppend((PBYTE)&(sEthHeader.abyDstAddr[0]), 12);
+ MIC_vAppend((u8 *)&(sEthHeader.h_dest[0]), 12);
dwMIC_Priority = 0;
- MIC_vAppend((PBYTE)&dwMIC_Priority, 4);
+ MIC_vAppend((u8 *)&dwMIC_Priority, 4);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"DMA0_tx_8021:MIC KEY:"\
" %X, %X\n", dwMICKey0, dwMICKey1);
@@ -2374,8 +2325,8 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
MIC_vAppend((pbyTxBufferAddr + uLength), cbFrameBodySize);
- pdwMIC_L = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize);
- pdwMIC_R = (PDWORD)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
+ pdwMIC_L = (u32 *)(pbyTxBufferAddr + uLength + cbFrameBodySize);
+ pdwMIC_R = (u32 *)(pbyTxBufferAddr + uLength + cbFrameBodySize + 4);
MIC_vGetMIC(pdwMIC_L, pdwMIC_R);
MIC_vUnInit();
@@ -2393,8 +2344,8 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
- s_vFillTxKey(pDevice, (PBYTE)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
- pbyMacHdr, (WORD)cbFrameBodySize, (PBYTE)pMICHDR);
+ s_vFillTxKey(pDevice, (u8 *)(pTxBufHead->adwTxKey), pbyIVHead, pTransmitKey,
+ pbyMacHdr, (u16)cbFrameBodySize, (u8 *)pMICHDR);
if (pDevice->bEnableHostWEP) {
pMgmt->sNodeDBTable[uNodeIndex].dwTSC47_16 = pTransmitKey->dwTSC47_16;
@@ -2402,16 +2353,15 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
if ((pDevice->byLocalID <= REV_ID_VT3253_A1)) {
- s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (WORD)(cbFrameBodySize + cbMIClen));
+ s_vSWencryption(pDevice, pTransmitKey, pbyPayloadHead, (u16)(cbFrameBodySize + cbMIClen));
}
}
- pMACHeader->wSeqCtl = cpu_to_le16(pDevice->wSeqCounter << 4);
+ pMACHeader->seq_ctrl = cpu_to_le16(pDevice->wSeqCounter << 4);
pDevice->wSeqCounter++ ;
if (pDevice->wSeqCounter > 0x0fff)
pDevice->wSeqCounter = 0;
-
if (bIsPSPOLL) {
// The MAC will automatically replace the Duration-field of MAC header by Duration-field
// of FIFO control header.
@@ -2426,28 +2376,25 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb)
}
}
- pTX_Buffer->wTxByteCount = cpu_to_le16((WORD)(cbReqCount));
- pTX_Buffer->byPKTNO = (BYTE) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
+ pTX_Buffer->wTxByteCount = cpu_to_le16((u16)(cbReqCount));
+ pTX_Buffer->byPKTNO = (u8) (((wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
pTX_Buffer->byType = 0x00;
pContext->pPacket = skb;
pContext->Type = CONTEXT_MGMT_PACKET;
- pContext->uBufLen = (WORD)cbReqCount + 4; //USB header
+ pContext->uBufLen = (u16)cbReqCount + 4; //USB header
- if (WLAN_GET_FC_TODS(pMACHeader->wFrameCtl) == 0) {
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->abyAddr1[0]),(WORD)cbFrameSize,pTX_Buffer->wFIFOCtl);
+ if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) {
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr1[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl);
}
else {
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->abyAddr3[0]),(WORD)cbFrameSize,pTX_Buffer->wFIFOCtl);
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pMACHeader->addr3[0]), (u16)cbFrameSize, pTX_Buffer->wFIFOCtl);
}
PIPEnsSendBulkOut(pDevice,pContext);
return ;
}
-
-
-
//TYPE_AC0DMA data tx
/*
* Description:
@@ -2488,7 +2435,6 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
u16 wKeepRate = pDevice->wCurrentRate;
int bTxeapol_key = false;
-
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (pDevice->uAssocCount == 0) {
@@ -2496,7 +2442,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
return 0;
}
- if (is_multicast_ether_addr((PBYTE)(skb->data))) {
+ if (is_multicast_ether_addr((u8 *)(skb->data))) {
uNodeIndex = 0;
bNodeExist = true;
if (pMgmt->sNodeDBTable[0].bPSEnable) {
@@ -2518,7 +2464,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}else {
- if (BSSbIsSTAInNodeDB(pDevice, (PBYTE)(skb->data), &uNodeIndex)) {
+ if (BSSbIsSTAInNodeDB(pDevice, (u8 *)(skb->data), &uNodeIndex)) {
if (pMgmt->sNodeDBTable[uNodeIndex].bPSEnable) {
@@ -2562,20 +2508,20 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
return STATUS_RESOURCES;
}
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)(skb->data), ETH_HLEN);
+ memcpy(pDevice->sTxEthHeader.h_dest, (u8 *)(skb->data), ETH_HLEN);
//mike add:station mode check eapol-key challenge--->
{
- BYTE Protocol_Version; //802.1x Authentication
- BYTE Packet_Type; //802.1x Authentication
- BYTE Descriptor_type;
- WORD Key_info;
+ u8 Protocol_Version; //802.1x Authentication
+ u8 Packet_Type; //802.1x Authentication
+ u8 Descriptor_type;
+ u16 Key_info;
Protocol_Version = skb->data[ETH_HLEN];
Packet_Type = skb->data[ETH_HLEN+1];
Descriptor_type = skb->data[ETH_HLEN+1+1+2];
Key_info = (skb->data[ETH_HLEN+1+1+2+1] << 8)|(skb->data[ETH_HLEN+1+1+2+2]);
- if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) {
+ if (pDevice->sTxEthHeader.h_proto == cpu_to_be16(ETH_P_PAE)) {
/* 802.1x OR eapol-key challenge frame transfer */
if (((Protocol_Version == 1) || (Protocol_Version == 2)) &&
(Packet_Type == 3)) {
@@ -2622,8 +2568,8 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
break;
}
}else if (pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) {
-
- pbyBSSID = pDevice->sTxEthHeader.abyDstAddr; //TO_DS = 0 and FROM_DS = 0 --> 802.11 MAC Address1
+ /* TO_DS = 0 and FROM_DS = 0 --> 802.11 MAC Address1 */
+ pbyBSSID = pDevice->sTxEthHeader.h_dest;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"IBSS Serach Key: \n");
for (ii = 0; ii< 6; ii++)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_DEBUG"%x \n", *(pbyBSSID+ii));
@@ -2665,14 +2611,14 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
- byPktType = (BYTE)pDevice->byPacketType;
+ byPktType = (u8)pDevice->byPacketType;
if (pDevice->bFixRate) {
if (pDevice->byBBType == BB_TYPE_11B) {
if (pDevice->uConnectionRate >= RATE_11M) {
pDevice->wCurrentRate = RATE_11M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (u16)pDevice->uConnectionRate;
}
} else {
if ((pDevice->byBBType == BB_TYPE_11A) &&
@@ -2682,21 +2628,21 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
if (pDevice->uConnectionRate >= RATE_54M)
pDevice->wCurrentRate = RATE_54M;
else
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (u16)pDevice->uConnectionRate;
}
}
}
else {
if (pDevice->eOPMode == OP_MODE_ADHOC) {
// Adhoc Tx rate decided from node DB
- if (is_multicast_ether_addr(pDevice->sTxEthHeader.abyDstAddr)) {
+ if (is_multicast_ether_addr(pDevice->sTxEthHeader.h_dest)) {
// Multicast use highest data rate
pDevice->wCurrentRate = pMgmt->sNodeDBTable[0].wTxDataRate;
// preamble type
pDevice->byPreambleType = pDevice->byShortPreamble;
}
else {
- if(BSSbIsSTAInNodeDB(pDevice, &(pDevice->sTxEthHeader.abyDstAddr[0]), &uNodeIndex)) {
+ if (BSSbIsSTAInNodeDB(pDevice, &(pDevice->sTxEthHeader.h_dest[0]), &uNodeIndex)) {
pDevice->wCurrentRate = pMgmt->sNodeDBTable[uNodeIndex].wTxDataRate;
if (pMgmt->sNodeDBTable[uNodeIndex].bShortPreamble) {
pDevice->byPreambleType = pDevice->byShortPreamble;
@@ -2724,7 +2670,7 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
}
- if (pDevice->sTxEthHeader.wType == cpu_to_be16(ETH_P_PAE)) {
+ if (pDevice->sTxEthHeader.h_proto == cpu_to_be16(ETH_P_PAE)) {
if (pDevice->byBBType != BB_TYPE_11A) {
pDevice->wCurrentRate = RATE_1M;
pDevice->byACKRate = RATE_1M;
@@ -2751,10 +2697,10 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
if (bNeedEncryption == true) {
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.wType));
- if ((pDevice->sTxEthHeader.wType) == cpu_to_be16(ETH_P_PAE)) {
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"ntohs Pkt Type=%04x\n", ntohs(pDevice->sTxEthHeader.h_proto));
+ if ((pDevice->sTxEthHeader.h_proto) == cpu_to_be16(ETH_P_PAE)) {
bNeedEncryption = false;
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.wType));
+ DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Pkt Type=%04x\n", (pDevice->sTxEthHeader.h_proto));
if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_ASSOC)) {
if (pTransmitKey == NULL) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Don't Find TX KEY\n");
@@ -2793,9 +2739,9 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
- (PBYTE)(&pContext->Data[0]), bNeedEncryption,
+ (u8 *)(&pContext->Data[0]), bNeedEncryption,
skb->len, uDMAIdx, &pDevice->sTxEthHeader,
- (PBYTE)skb->data, pTransmitKey, uNodeIndex,
+ (u8 *)skb->data, pTransmitKey, uNodeIndex,
pDevice->wCurrentRate,
&uHeaderLen, &BytesToWrite
);
@@ -2816,21 +2762,21 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
- pTX_Buffer->byPKTNO = (BYTE) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
- pTX_Buffer->wTxByteCount = (WORD)BytesToWrite;
+ pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
+ pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
pContext->pPacket = skb;
pContext->Type = CONTEXT_DATA_PACKET;
- pContext->uBufLen = (WORD)BytesToWrite + 4 ; //USB header
+ pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.abyDstAddr[0]),(WORD) (BytesToWrite-uHeaderLen),pTX_Buffer->wFIFOCtl);
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.h_dest[0]), (u16) (BytesToWrite-uHeaderLen), pTX_Buffer->wFIFOCtl);
status = PIPEnsSendBulkOut(pDevice,pContext);
if (bNeedDeAuth == true) {
- WORD wReason = WLAN_MGMT_REASON_MIC_FAILURE;
+ u16 wReason = WLAN_MGMT_REASON_MIC_FAILURE;
- bScheduleCommand((void *) pDevice, WLAN_CMD_DEAUTH, (PBYTE) &wReason);
+ bScheduleCommand((void *) pDevice, WLAN_CMD_DEAUTH, (u8 *) &wReason);
}
if(status!=STATUS_PENDING) {
@@ -2843,8 +2789,6 @@ int nsDMA_tx_packet(struct vnt_private *pDevice,
}
-
-
/*
* Description:
* Relay packet send (AC1DMA) from rx dpc.
@@ -2877,15 +2821,13 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
u32 status;
u16 wKeepRate = pDevice->wCurrentRate;
-
-
pContext = (PUSB_SEND_CONTEXT)s_vGetFreeContext(pDevice);
if (NULL == pContext) {
return false;
}
- memcpy(pDevice->sTxEthHeader.abyDstAddr, (PBYTE)pbySkbData, ETH_HLEN);
+ memcpy(pDevice->sTxEthHeader.h_dest, (u8 *)pbySkbData, ETH_HLEN);
if (pDevice->bEncryptionEnable == true) {
bNeedEncryption = true;
@@ -2919,14 +2861,14 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
return false;
}
- byPktTyp = (BYTE)pDevice->byPacketType;
+ byPktTyp = (u8)pDevice->byPacketType;
if (pDevice->bFixRate) {
if (pDevice->byBBType == BB_TYPE_11B) {
if (pDevice->uConnectionRate >= RATE_11M) {
pDevice->wCurrentRate = RATE_11M;
} else {
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (u16)pDevice->uConnectionRate;
}
} else {
if ((pDevice->byBBType == BB_TYPE_11A) &&
@@ -2936,7 +2878,7 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
if (pDevice->uConnectionRate >= RATE_54M)
pDevice->wCurrentRate = RATE_54M;
else
- pDevice->wCurrentRate = (WORD)pDevice->uConnectionRate;
+ pDevice->wCurrentRate = (u16)pDevice->uConnectionRate;
}
}
}
@@ -2957,7 +2899,7 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
// and send the irp.
fConvertedPacket = s_bPacketToWirelessUsb(pDevice, byPktType,
- (PBYTE)(&pContext->Data[0]), bNeedEncryption,
+ (u8 *)(&pContext->Data[0]), bNeedEncryption,
uDataLen, TYPE_AC0DMA, &pDevice->sTxEthHeader,
pbySkbData, pTransmitKey, uNodeIndex,
pDevice->wCurrentRate,
@@ -2970,14 +2912,14 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen,
}
pTX_Buffer = (PTX_BUFFER)&(pContext->Data[0]);
- pTX_Buffer->byPKTNO = (BYTE) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
- pTX_Buffer->wTxByteCount = (WORD)BytesToWrite;
+ pTX_Buffer->byPKTNO = (u8) (((pDevice->wCurrentRate<<4) &0x00F0) | ((pDevice->wSeqCounter - 1) & 0x000F));
+ pTX_Buffer->wTxByteCount = (u16)BytesToWrite;
pContext->pPacket = NULL;
pContext->Type = CONTEXT_DATA_PACKET;
- pContext->uBufLen = (WORD)BytesToWrite + 4 ; //USB header
+ pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header
- s_vSaveTxPktInfo(pDevice, (BYTE) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.abyDstAddr[0]),(WORD) (BytesToWrite-uHeaderLen),pTX_Buffer->wFIFOCtl);
+ s_vSaveTxPktInfo(pDevice, (u8) (pTX_Buffer->byPKTNO & 0x0F), &(pContext->sEthHeader.h_dest[0]), (u16) (BytesToWrite-uHeaderLen), pTX_Buffer->wFIFOCtl);
status = PIPEnsSendBulkOut(pDevice,pContext);
diff --git a/drivers/staging/vt6656/rxtx.h b/drivers/staging/vt6656/rxtx.h
index 9f537022cdd1..dd7e85dde1a2 100644
--- a/drivers/staging/vt6656/rxtx.h
+++ b/drivers/staging/vt6656/rxtx.h
@@ -29,32 +29,27 @@
#ifndef __RXTX_H__
#define __RXTX_H__
-#include "ttype.h"
#include "device.h"
#include "wcmd.h"
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
//
// RTS buffer header
//
typedef struct tagSRTSDataF {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- BYTE abyTA[ETH_ALEN];
+ u16 wFrameControl;
+ u16 wDurationID;
+ u8 abyRA[ETH_ALEN];
+ u8 abyTA[ETH_ALEN];
} SRTSDataF, *PSRTSDataF;
//
// CTS buffer header
//
typedef struct tagSCTSDataF {
- WORD wFrameControl;
- WORD wDurationID;
- BYTE abyRA[ETH_ALEN];
- WORD wReserved;
+ u16 wFrameControl;
+ u16 wDurationID;
+ u8 abyRA[ETH_ALEN];
+ u16 wReserved;
} SCTSDataF, *PSCTSDataF;
//
@@ -66,534 +61,510 @@ typedef struct tagSMICHDR {
u32 adwHDR2[4];
} SMICHDR, *PSMICHDR;
-
typedef struct tagSTX_NAF_G_RTS
{
//RsvTime
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
//RTS
- BYTE byRTSSignalField_b;
- BYTE byRTSServiceField_b;
- WORD wRTSTransmitLength_b;
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_ba;
- WORD wRTSDuration_aa;
- WORD wRTSDuration_bb;
- WORD wReserved3;
+ u8 byRTSSignalField_b;
+ u8 byRTSServiceField_b;
+ u16 wRTSTransmitLength_b;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_ba;
+ u16 wRTSDuration_aa;
+ u16 wRTSDuration_bb;
+ u16 wReserved3;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_NAF_G_RTS, *PTX_NAF_G_RTS;
typedef struct tagSTX_NAF_G_RTS_MIC
{
//RsvTime
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//RTS
- BYTE byRTSSignalField_b;
- BYTE byRTSServiceField_b;
- WORD wRTSTransmitLength_b;
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_ba;
- WORD wRTSDuration_aa;
- WORD wRTSDuration_bb;
- WORD wReserved3;
+ u8 byRTSSignalField_b;
+ u8 byRTSServiceField_b;
+ u16 wRTSTransmitLength_b;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_ba;
+ u16 wRTSDuration_aa;
+ u16 wRTSDuration_bb;
+ u16 wReserved3;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_NAF_G_RTS_MIC, *PTX_NAF_G_RTS_MIC;
typedef struct tagSTX_NAF_G_CTS
{
//RsvTime
- WORD wCTSTxRrvTime_ba;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
//CTS
- BYTE byCTSSignalField_b;
- BYTE byCTSServiceField_b;
- WORD wCTSTransmitLength_b;
- WORD wCTSDuration_ba;
- WORD wReserved3;
+ u8 byCTSSignalField_b;
+ u8 byCTSServiceField_b;
+ u16 wCTSTransmitLength_b;
+ u16 wCTSDuration_ba;
+ u16 wReserved3;
SCTSDataF sCTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_NAF_G_CTS, *PTX_NAF_G_CTS;
-
typedef struct tagSTX_NAF_G_CTS_MIC
{
//RsvTime
- WORD wCTSTxRrvTime_ba;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
-
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//CTS
- BYTE byCTSSignalField_b;
- BYTE byCTSServiceField_b;
- WORD wCTSTransmitLength_b;
- WORD wCTSDuration_ba;
- WORD wReserved3;
+ u8 byCTSSignalField_b;
+ u8 byCTSServiceField_b;
+ u16 wCTSTransmitLength_b;
+ u16 wCTSDuration_ba;
+ u16 wReserved3;
SCTSDataF sCTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_NAF_G_CTS_MIC, *PTX_NAF_G_CTS_MIC;
-
typedef struct tagSTX_NAF_G_BEACON
{
- WORD wFIFOCtl;
- WORD wTimeStamp;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
//CTS
- BYTE byCTSSignalField_b;
- BYTE byCTSServiceField_b;
- WORD wCTSTransmitLength_b;
- WORD wCTSDuration_ba;
- WORD wReserved1;
+ u8 byCTSSignalField_b;
+ u8 byCTSServiceField_b;
+ u16 wCTSTransmitLength_b;
+ u16 wCTSDuration_ba;
+ u16 wReserved1;
SCTSDataF sCTS;
//Data
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_a;
- WORD wTimeStampOff_a;
-
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_a;
+ u16 wTimeStampOff_a;
} TX_NAF_G_BEACON, *PTX_NAF_G_BEACON;
-
typedef struct tagSTX_NAF_AB_RTS
{
//RsvTime
- WORD wRTSTxRrvTime_ab;
- WORD wTxRrvTime_ab;
+ u16 wRTSTxRrvTime_ab;
+ u16 wTxRrvTime_ab;
//RTS
- BYTE byRTSSignalField_ab;
- BYTE byRTSServiceField_ab;
- WORD wRTSTransmitLength_ab;
- WORD wRTSDuration_ab;
- WORD wReserved2;
+ u8 byRTSSignalField_ab;
+ u8 byRTSServiceField_ab;
+ u16 wRTSTransmitLength_ab;
+ u16 wRTSDuration_ab;
+ u16 wReserved2;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_ab;
- BYTE byServiceField_ab;
- WORD wTransmitLength_ab;
- WORD wDuration_ab;
- WORD wTimeStampOff_ab;
-
+ u8 bySignalField_ab;
+ u8 byServiceField_ab;
+ u16 wTransmitLength_ab;
+ u16 wDuration_ab;
+ u16 wTimeStampOff_ab;
} TX_NAF_AB_RTS, *PTX_NAF_AB_RTS;
-
typedef struct tagSTX_NAF_AB_RTS_MIC
{
//RsvTime
- WORD wRTSTxRrvTime_ab;
- WORD wTxRrvTime_ab;
+ u16 wRTSTxRrvTime_ab;
+ u16 wTxRrvTime_ab;
SMICHDR sMICHDR;
//RTS
- BYTE byRTSSignalField_ab;
- BYTE byRTSServiceField_ab;
- WORD wRTSTransmitLength_ab;
- WORD wRTSDuration_ab;
- WORD wReserved2;
+ u8 byRTSSignalField_ab;
+ u8 byRTSServiceField_ab;
+ u16 wRTSTransmitLength_ab;
+ u16 wRTSDuration_ab;
+ u16 wReserved2;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_ab;
- BYTE byServiceField_ab;
- WORD wTransmitLength_ab;
- WORD wDuration_ab;
- WORD wTimeStampOff_ab;
-
+ u8 bySignalField_ab;
+ u8 byServiceField_ab;
+ u16 wTransmitLength_ab;
+ u16 wDuration_ab;
+ u16 wTimeStampOff_ab;
} TX_NAF_AB_RTS_MIC, *PTX_NAF_AB_RTS_MIC;
-
-
typedef struct tagSTX_NAF_AB_CTS
{
//RsvTime
- WORD wReserved2;
- WORD wTxRrvTime_ab;
+ u16 wReserved2;
+ u16 wTxRrvTime_ab;
//Data
- BYTE bySignalField_ab;
- BYTE byServiceField_ab;
- WORD wTransmitLength_ab;
- WORD wDuration_ab;
- WORD wTimeStampOff_ab;
+ u8 bySignalField_ab;
+ u8 byServiceField_ab;
+ u16 wTransmitLength_ab;
+ u16 wDuration_ab;
+ u16 wTimeStampOff_ab;
} TX_NAF_AB_CTS, *PTX_NAF_AB_CTS;
typedef struct tagSTX_NAF_AB_CTS_MIC
{
//RsvTime
- WORD wReserved2;
- WORD wTxRrvTime_ab;
+ u16 wReserved2;
+ u16 wTxRrvTime_ab;
SMICHDR sMICHDR;
//Data
- BYTE bySignalField_ab;
- BYTE byServiceField_ab;
- WORD wTransmitLength_ab;
- WORD wDuration_ab;
- WORD wTimeStampOff_ab;
+ u8 bySignalField_ab;
+ u8 byServiceField_ab;
+ u16 wTransmitLength_ab;
+ u16 wDuration_ab;
+ u16 wTimeStampOff_ab;
} TX_NAF_AB_CTS_MIC, *PTX_NAF_AB_CTS_MIC;
-
typedef struct tagSTX_NAF_AB_BEACON
{
- WORD wFIFOCtl;
- WORD wTimeStamp;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
//Data
- BYTE bySignalField_ab;
- BYTE byServiceField_ab;
- WORD wTransmitLength_ab;
- WORD wDuration_ab;
- WORD wTimeStampOff_ab;
+ u8 bySignalField_ab;
+ u8 byServiceField_ab;
+ u16 wTransmitLength_ab;
+ u16 wDuration_ab;
+ u16 wTimeStampOff_ab;
} TX_NAF_AB_BEACON, *PTX_NAF_AB_BEACON;
typedef struct tagSTX_AF_G_RTS
{
//RsvTime
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
//RTS
- BYTE byRTSSignalField_b;
- BYTE byRTSServiceField_b;
- WORD wRTSTransmitLength_b;
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_ba;
- WORD wRTSDuration_aa;
- WORD wRTSDuration_bb;
- WORD wReserved3;
- WORD wRTSDuration_ba_f0;
- WORD wRTSDuration_aa_f0;
- WORD wRTSDuration_ba_f1;
- WORD wRTSDuration_aa_f1;
+ u8 byRTSSignalField_b;
+ u8 byRTSServiceField_b;
+ u16 wRTSTransmitLength_b;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_ba;
+ u16 wRTSDuration_aa;
+ u16 wRTSDuration_bb;
+ u16 wReserved3;
+ u16 wRTSDuration_ba_f0;
+ u16 wRTSDuration_aa_f0;
+ u16 wRTSDuration_ba_f1;
+ u16 wRTSDuration_aa_f1;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_AF_G_RTS, *PTX_AF_G_RTS;
-
typedef struct tagSTX_AF_G_RTS_MIC
{
//RsvTime
- WORD wRTSTxRrvTime_ba;
- WORD wRTSTxRrvTime_aa;
- WORD wRTSTxRrvTime_bb;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_ba;
+ u16 wRTSTxRrvTime_aa;
+ u16 wRTSTxRrvTime_bb;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//RTS
- BYTE byRTSSignalField_b;
- BYTE byRTSServiceField_b;
- WORD wRTSTransmitLength_b;
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_ba;
- WORD wRTSDuration_aa;
- WORD wRTSDuration_bb;
- WORD wReserved3;
- WORD wRTSDuration_ba_f0;
- WORD wRTSDuration_aa_f0;
- WORD wRTSDuration_ba_f1;
- WORD wRTSDuration_aa_f1;
+ u8 byRTSSignalField_b;
+ u8 byRTSServiceField_b;
+ u16 wRTSTransmitLength_b;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_ba;
+ u16 wRTSDuration_aa;
+ u16 wRTSDuration_bb;
+ u16 wReserved3;
+ u16 wRTSDuration_ba_f0;
+ u16 wRTSDuration_aa_f0;
+ u16 wRTSDuration_ba_f1;
+ u16 wRTSDuration_aa_f1;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_AF_G_RTS_MIC, *PTX_AF_G_RTS_MIC;
-
-
typedef struct tagSTX_AF_G_CTS
{
//RsvTime
- WORD wCTSTxRrvTime_ba;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
//CTS
- BYTE byCTSSignalField_b;
- BYTE byCTSServiceField_b;
- WORD wCTSTransmitLength_b;
- WORD wCTSDuration_ba;
- WORD wReserved3;
- WORD wCTSDuration_ba_f0;
- WORD wCTSDuration_ba_f1;
+ u8 byCTSSignalField_b;
+ u8 byCTSServiceField_b;
+ u16 wCTSTransmitLength_b;
+ u16 wCTSDuration_ba;
+ u16 wReserved3;
+ u16 wCTSDuration_ba_f0;
+ u16 wCTSDuration_ba_f1;
SCTSDataF sCTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_AF_G_CTS, *PTX_AF_G_CTS;
-
typedef struct tagSTX_AF_G_CTS_MIC
{
//RsvTime
- WORD wCTSTxRrvTime_ba;
- WORD wReserved2;
- WORD wTxRrvTime_b;
- WORD wTxRrvTime_a;
-
+ u16 wCTSTxRrvTime_ba;
+ u16 wReserved2;
+ u16 wTxRrvTime_b;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//CTS
- BYTE byCTSSignalField_b;
- BYTE byCTSServiceField_b;
- WORD wCTSTransmitLength_b;
- WORD wCTSDuration_ba;
- WORD wReserved3;
- WORD wCTSDuration_ba_f0;
- WORD wCTSDuration_ba_f1;
+ u8 byCTSSignalField_b;
+ u8 byCTSServiceField_b;
+ u16 wCTSTransmitLength_b;
+ u16 wCTSDuration_ba;
+ u16 wReserved3;
+ u16 wCTSDuration_ba_f0;
+ u16 wCTSDuration_ba_f1;
SCTSDataF sCTS;
//Data
- BYTE bySignalField_b;
- BYTE byServiceField_b;
- WORD wTransmitLength_b;
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_b;
- WORD wDuration_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
- WORD wTimeStampOff_b;
- WORD wTimeStampOff_a;
+ u8 bySignalField_b;
+ u8 byServiceField_b;
+ u16 wTransmitLength_b;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_b;
+ u16 wDuration_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
+ u16 wTimeStampOff_b;
+ u16 wTimeStampOff_a;
} TX_AF_G_CTS_MIC, *PTX_AF_G_CTS_MIC;
-
-
typedef struct tagSTX_AF_A_RTS
{
//RsvTime
- WORD wRTSTxRrvTime_a;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_a;
+ u16 wTxRrvTime_a;
//RTS
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_a;
- WORD wReserved2;
- WORD wRTSDuration_a_f0;
- WORD wRTSDuration_a_f1;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_a;
+ u16 wReserved2;
+ u16 wRTSDuration_a_f0;
+ u16 wRTSDuration_a_f1;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_a;
- WORD wTimeStampOff_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_a;
+ u16 wTimeStampOff_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
} TX_AF_A_RTS, *PTX_AF_A_RTS;
-
typedef struct tagSTX_AF_A_RTS_MIC
{
//RsvTime
- WORD wRTSTxRrvTime_a;
- WORD wTxRrvTime_a;
+ u16 wRTSTxRrvTime_a;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//RTS
- BYTE byRTSSignalField_a;
- BYTE byRTSServiceField_a;
- WORD wRTSTransmitLength_a;
- WORD wRTSDuration_a;
- WORD wReserved2;
- WORD wRTSDuration_a_f0;
- WORD wRTSDuration_a_f1;
+ u8 byRTSSignalField_a;
+ u8 byRTSServiceField_a;
+ u16 wRTSTransmitLength_a;
+ u16 wRTSDuration_a;
+ u16 wReserved2;
+ u16 wRTSDuration_a_f0;
+ u16 wRTSDuration_a_f1;
SRTSDataF sRTS;
//Data
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_a;
- WORD wTimeStampOff_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_a;
+ u16 wTimeStampOff_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
} TX_AF_A_RTS_MIC, *PTX_AF_A_RTS_MIC;
-
-
typedef struct tagSTX_AF_A_CTS
{
//RsvTime
- WORD wReserved2;
- WORD wTxRrvTime_a;
+ u16 wReserved2;
+ u16 wTxRrvTime_a;
//Data
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_a;
- WORD wTimeStampOff_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_a;
+ u16 wTimeStampOff_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
} TX_AF_A_CTS, *PTX_AF_A_CTS;
-
typedef struct tagSTX_AF_A_CTS_MIC
{
//RsvTime
- WORD wReserved2;
- WORD wTxRrvTime_a;
+ u16 wReserved2;
+ u16 wTxRrvTime_a;
SMICHDR sMICHDR;
//Data
- BYTE bySignalField_a;
- BYTE byServiceField_a;
- WORD wTransmitLength_a;
- WORD wDuration_a;
- WORD wTimeStampOff_a;
- WORD wDuration_a_f0;
- WORD wDuration_a_f1;
+ u8 bySignalField_a;
+ u8 byServiceField_a;
+ u16 wTransmitLength_a;
+ u16 wDuration_a;
+ u16 wTimeStampOff_a;
+ u16 wDuration_a_f0;
+ u16 wDuration_a_f1;
} TX_AF_A_CTS_MIC, *PTX_AF_A_CTS_MIC;
-
//
// union with all of the TX Buffer Type
//
@@ -620,51 +591,43 @@ typedef union tagUTX_BUFFER_CONTAINER
} TX_BUFFER_CONTAINER, *PTX_BUFFER_CONTAINER;
-
//
// Remote NDIS message format
//
typedef struct tagSTX_BUFFER
{
- BYTE byType;
- BYTE byPKTNO;
- WORD wTxByteCount;
+ u8 byType;
+ u8 byPKTNO;
+ u16 wTxByteCount;
u32 adwTxKey[4];
- WORD wFIFOCtl;
- WORD wTimeStamp;
- WORD wFragCtl;
- WORD wReserved;
-
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
+ u16 wFragCtl;
+ u16 wReserved;
// Actual message
TX_BUFFER_CONTAINER BufferHeader;
} TX_BUFFER, *PTX_BUFFER;
-
//
// Remote NDIS message format
//
typedef struct tagSBEACON_BUFFER
{
- BYTE byType;
- BYTE byPKTNO;
- WORD wTxByteCount;
+ u8 byType;
+ u8 byPKTNO;
+ u16 wTxByteCount;
- WORD wFIFOCtl;
- WORD wTimeStamp;
+ u16 wFIFOCtl;
+ u16 wTimeStamp;
// Actual message
TX_BUFFER_CONTAINER BufferHeader;
} BEACON_BUFFER, *PBEACON_BUFFER;
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void vDMA0_tx_80211(struct vnt_private *, struct sk_buff *skb);
int nsDMA_tx_packet(struct vnt_private *, u32 uDMAIdx, struct sk_buff *skb);
CMD_STATUS csMgmt_xmit(struct vnt_private *, struct vnt_tx_mgmt *);
diff --git a/drivers/staging/vt6656/srom.h b/drivers/staging/vt6656/srom.h
index dba21a54414b..488192d79ac9 100644
--- a/drivers/staging/vt6656/srom.h
+++ b/drivers/staging/vt6656/srom.h
@@ -30,10 +30,6 @@
#ifndef __SROM_H__
#define __SROM_H__
-#include "ttype.h"
-
-/*--------------------- Export Definitions -------------------------*/
-
#define EEP_MAX_CONTEXT_SIZE 256
#define CB_EEPROM_READBYTE_WAIT 900 //us
@@ -56,7 +52,6 @@
#define EEP_OFS_SETPT_CCK 0x21
#define EEP_OFS_PWR_OFDMG 0x23
-
#define EEP_OFS_CALIB_TX_IQ 0x24
#define EEP_OFS_CALIB_TX_DC 0x25
#define EEP_OFS_CALIB_RX_IQ 0x26
@@ -80,48 +75,38 @@
//
#define EEP_RADIOCTL_ENABLE 0x80
-/*--------------------- Export Types ------------------------------*/
-
// AT24C02 eeprom contents
// 2048 bits = 256 bytes = 128 words
//
typedef struct tagSSromReg {
- BYTE abyPAR[6]; // 0x00 (WORD)
-
- WORD wSUB_VID; // 0x03 (WORD)
- WORD wSUB_SID;
-
- BYTE byBCFG0; // 0x05 (WORD)
- BYTE byBCFG1;
-
- BYTE byFCR0; // 0x06 (WORD)
- BYTE byFCR1;
- BYTE byPMC0; // 0x07 (WORD)
- BYTE byPMC1;
- BYTE byMAXLAT; // 0x08 (WORD)
- BYTE byMINGNT;
- BYTE byCFG0; // 0x09 (WORD)
- BYTE byCFG1;
- WORD wCISPTR; // 0x0A (WORD)
- WORD wRsv0; // 0x0B (WORD)
- WORD wRsv1; // 0x0C (WORD)
- BYTE byBBPAIR; // 0x0D (WORD)
- BYTE byRFTYPE;
- BYTE byMinChannel; // 0x0E (WORD)
- BYTE byMaxChannel;
- BYTE bySignature; // 0x0F (WORD)
- BYTE byCheckSum;
-
- BYTE abyReserved0[96]; // 0x10 (WORD)
- BYTE abyCIS[128]; // 0x80 (WORD)
+ u8 abyPAR[6]; // 0x00 (u16)
+
+ u16 wSUB_VID; // 0x03 (u16)
+ u16 wSUB_SID;
+
+ u8 byBCFG0; // 0x05 (u16)
+ u8 byBCFG1;
+
+ u8 byFCR0; // 0x06 (u16)
+ u8 byFCR1;
+ u8 byPMC0; // 0x07 (u16)
+ u8 byPMC1;
+ u8 byMAXLAT; // 0x08 (u16)
+ u8 byMINGNT;
+ u8 byCFG0; // 0x09 (u16)
+ u8 byCFG1;
+ u16 wCISPTR; // 0x0A (u16)
+ u16 wRsv0; // 0x0B (u16)
+ u16 wRsv1; // 0x0C (u16)
+ u8 byBBPAIR; // 0x0D (u16)
+ u8 byRFTYPE;
+ u8 byMinChannel; // 0x0E (u16)
+ u8 byMaxChannel;
+ u8 bySignature; // 0x0F (u16)
+ u8 byCheckSum;
+
+ u8 abyReserved0[96]; // 0x10 (u16)
+ u8 abyCIS[128]; // 0x80 (u16)
} SSromReg, *PSSromReg;
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
#endif /* __EEPROM_H__ */
diff --git a/drivers/staging/vt6656/tcrc.c b/drivers/staging/vt6656/tcrc.c
index 2237eeb5ec5b..7229f26c052c 100644
--- a/drivers/staging/vt6656/tcrc.c
+++ b/drivers/staging/vt6656/tcrc.c
@@ -35,14 +35,8 @@
#include "tcrc.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
/* 32-bit CRC table */
-static const DWORD s_adwCrc32Table[256] = {
+static const u32 s_adwCrc32Table[256] = {
0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
@@ -109,13 +103,6 @@ static const DWORD s_adwCrc32Table[256] = {
0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
};
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
-
-
/*+
*
* Description:
@@ -132,13 +119,13 @@ static const DWORD s_adwCrc32Table[256] = {
* Return Value: CRC-32
*
-*/
-DWORD CRCdwCrc32(PBYTE pbyData, unsigned int cbByte, DWORD dwCrcSeed)
+u32 CRCdwCrc32(u8 * pbyData, unsigned int cbByte, u32 dwCrcSeed)
{
- DWORD dwCrc;
+ u32 dwCrc;
dwCrc = dwCrcSeed;
while (cbByte--) {
- dwCrc = s_adwCrc32Table[(BYTE)((dwCrc ^ (*pbyData)) & 0xFF)] ^
+ dwCrc = s_adwCrc32Table[(u8)((dwCrc ^ (*pbyData)) & 0xFF)] ^
(dwCrc >> 8);
pbyData++;
}
@@ -146,7 +133,6 @@ DWORD CRCdwCrc32(PBYTE pbyData, unsigned int cbByte, DWORD dwCrcSeed)
return dwCrc;
}
-
/*+
*
* Description:
@@ -165,12 +151,11 @@ DWORD CRCdwCrc32(PBYTE pbyData, unsigned int cbByte, DWORD dwCrcSeed)
* Return Value: CRC-32
*
-*/
-DWORD CRCdwGetCrc32(PBYTE pbyData, unsigned int cbByte)
+u32 CRCdwGetCrc32(u8 * pbyData, unsigned int cbByte)
{
return ~CRCdwCrc32(pbyData, cbByte, 0xFFFFFFFFL);
}
-
/*+
*
* Description:
@@ -191,9 +176,8 @@ DWORD CRCdwGetCrc32(PBYTE pbyData, unsigned int cbByte)
* Return Value: CRC-32
*
-*/
-DWORD CRCdwGetCrc32Ex(PBYTE pbyData, unsigned int cbByte, DWORD dwPreCRC)
+u32 CRCdwGetCrc32Ex(u8 * pbyData, unsigned int cbByte, u32 dwPreCRC)
{
return CRCdwCrc32(pbyData, cbByte, dwPreCRC);
}
-
diff --git a/drivers/staging/vt6656/tcrc.h b/drivers/staging/vt6656/tcrc.h
index dc54bd8fc4fc..5b1f368964eb 100644
--- a/drivers/staging/vt6656/tcrc.h
+++ b/drivers/staging/vt6656/tcrc.h
@@ -29,22 +29,10 @@
#ifndef __TCRC_H__
#define __TCRC_H__
-#include "ttype.h"
+#include <linux/types.h>
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-DWORD CRCdwCrc32(PBYTE pbyData, unsigned int cbByte, DWORD dwCrcSeed);
-DWORD CRCdwGetCrc32(PBYTE pbyData, unsigned int cbByte);
-DWORD CRCdwGetCrc32Ex(PBYTE pbyData, unsigned int cbByte, DWORD dwPreCRC);
+u32 CRCdwCrc32(u8 * pbyData, unsigned int cbByte, u32 dwCrcSeed);
+u32 CRCdwGetCrc32(u8 * pbyData, unsigned int cbByte);
+u32 CRCdwGetCrc32Ex(u8 * pbyData, unsigned int cbByte, u32 dwPreCRC);
#endif /* __TCRC_H__ */
diff --git a/drivers/staging/vt6656/tether.c b/drivers/staging/vt6656/tether.c
index 95286c4d5572..1db1e8419a9a 100644
--- a/drivers/staging/vt6656/tether.c
+++ b/drivers/staging/vt6656/tether.c
@@ -25,7 +25,6 @@
* Date: May 21, 1996
*
* Functions:
- * ETHbyGetHashIndexByCrc32 - Calculate multicast hash value by CRC32
* ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not
*
* Revision History:
@@ -37,52 +36,6 @@
#include "tcrc.h"
#include "tether.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
-
-/*
- * Description: Calculate multicast hash value by CRC32
- *
- * Parameters:
- * In:
- * pbyMultiAddr - Multicast Address
- * Out:
- * none
- *
- * Return Value: Hash value
- *
- */
-BYTE ETHbyGetHashIndexByCrc32(PBYTE pbyMultiAddr)
-{
- int ii;
- BYTE byTmpHash;
- BYTE byHash = 0;
-
- /* get the least 6-bits from CRC generator */
- byTmpHash = (BYTE)(CRCdwCrc32(pbyMultiAddr, ETH_ALEN,
- 0xFFFFFFFFL) & 0x3F);
- /* reverse most bit to least bit */
- for (ii = 0; ii < (sizeof(byTmpHash) * 8); ii++) {
- byHash <<= 1;
- if (byTmpHash & 0x01)
- byHash |= 1;
- byTmpHash >>= 1;
- }
-
- /* adjust 6-bits to the right most */
- return byHash >> 2;
-}
-
-
/*
* Description: Check CRC value of the buffer if Ok or not
*
@@ -96,12 +49,12 @@ BYTE ETHbyGetHashIndexByCrc32(PBYTE pbyMultiAddr)
* Return Value: true if ok; false if error.
*
*/
-bool ETHbIsBufferCrc32Ok(PBYTE pbyBuffer, unsigned int cbFrameLength)
+bool ETHbIsBufferCrc32Ok(u8 * pbyBuffer, unsigned int cbFrameLength)
{
- DWORD dwCRC;
+ u32 dwCRC;
dwCRC = CRCdwGetCrc32(pbyBuffer, cbFrameLength - 4);
- if (cpu_to_le32(*((PDWORD)(pbyBuffer + cbFrameLength - 4))) != dwCRC)
+ if (cpu_to_le32(*((u32 *)(pbyBuffer + cbFrameLength - 4))) != dwCRC)
return false;
return true;
}
diff --git a/drivers/staging/vt6656/tether.h b/drivers/staging/vt6656/tether.h
index 2f8f4853fd9d..24465cfe3e6d 100644
--- a/drivers/staging/vt6656/tether.h
+++ b/drivers/staging/vt6656/tether.h
@@ -30,9 +30,7 @@
#define __TETHER_H__
#include <linux/if_ether.h>
-#include "ttype.h"
-/*--------------------- Export Definitions -------------------------*/
//
// constants
//
@@ -44,11 +42,6 @@
#define TYPE_MGMT_PROBE_RSP 0x5000
-//
-// wFrameCtl field in the S802_11Header
-//
-// NOTE....
-// in network byte order, high byte is going first
#define FC_TODS 0x0001
#define FC_FROMDS 0x0002
#define FC_MOREFRAG 0x0004
@@ -71,8 +64,6 @@
#define TYPE_CTL_CTS 0xc400
#define TYPE_CTL_ACK 0xd400
-
-
#else //if LITTLE_ENDIAN
//
// wType field in the SEthernetHeader
@@ -82,11 +73,6 @@
#define TYPE_MGMT_PROBE_RSP 0x0050
-//
-// wFrameCtl field in the S802_11Header
-//
-// NOTE....
-// in network byte order, high byte is going first
#define FC_TODS 0x0100
#define FC_FROMDS 0x0200
#define FC_MOREFRAG 0x0400
@@ -109,58 +95,21 @@
#define TYPE_CTL_CTS 0x00c4
#define TYPE_CTL_ACK 0x00d4
-
-
#endif //#ifdef __BIG_ENDIAN
#define WEP_IV_MASK 0x00FFFFFF
-/*--------------------- Export Types ------------------------------*/
-//
-// Ethernet packet
-//
-typedef struct tagSEthernetHeader {
- BYTE abyDstAddr[ETH_ALEN];
- BYTE abySrcAddr[ETH_ALEN];
- WORD wType;
-} __attribute__ ((__packed__))
-SEthernetHeader, *PSEthernetHeader;
-
-
//
// 802_3 packet
//
typedef struct tagS802_3Header {
- BYTE abyDstAddr[ETH_ALEN];
- BYTE abySrcAddr[ETH_ALEN];
- WORD wLen;
+ u8 abyDstAddr[ETH_ALEN];
+ u8 abySrcAddr[ETH_ALEN];
+ u16 wLen;
} __attribute__ ((__packed__))
S802_3Header, *PS802_3Header;
-//
-// 802_11 packet
-//
-typedef struct tagS802_11Header {
- WORD wFrameCtl;
- WORD wDurationID;
- BYTE abyAddr1[ETH_ALEN];
- BYTE abyAddr2[ETH_ALEN];
- BYTE abyAddr3[ETH_ALEN];
- WORD wSeqCtl;
- BYTE abyAddr4[ETH_ALEN];
-} __attribute__ ((__packed__))
-S802_11Header, *PS802_11Header;
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-BYTE ETHbyGetHashIndexByCrc32(PBYTE pbyMultiAddr);
-//BYTE ETHbyGetHashIndexByCrc(PBYTE pbyMultiAddr);
-bool ETHbIsBufferCrc32Ok(PBYTE pbyBuffer, unsigned int cbFrameLength);
+//u8 ETHbyGetHashIndexByCrc(u8 * pbyMultiAddr);
+bool ETHbIsBufferCrc32Ok(u8 * pbyBuffer, unsigned int cbFrameLength);
#endif /* __TETHER_H__ */
diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c
index 282c08d65761..9d643e449ac3 100644
--- a/drivers/staging/vt6656/tkip.c
+++ b/drivers/staging/vt6656/tkip.c
@@ -35,27 +35,11 @@
#include "tmacro.h"
#include "tkip.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
/* The Sbox is reduced to 2 16-bit wide tables, each with 256 entries. */
/* The 2nd table is the same as the 1st but with the upper and lower */
/* bytes swapped. To allow an endian tolerant implementation, the byte */
/* halves have been expressed independently here. */
-const BYTE TKIP_Sbox_Lower[256] = {
+const u8 TKIP_Sbox_Lower[256] = {
0xA5,0x84,0x99,0x8D,0x0D,0xBD,0xB1,0x54,
0x50,0x03,0xA9,0x7D,0x19,0x62,0xE6,0x9A,
0x45,0x9D,0x40,0x87,0x15,0xEB,0xC9,0x0B,
@@ -90,7 +74,7 @@ const BYTE TKIP_Sbox_Lower[256] = {
0xC3,0xB0,0x77,0x11,0xCB,0xFC,0xD6,0x3A
};
-const BYTE TKIP_Sbox_Upper[256] = {
+const u8 TKIP_Sbox_Upper[256] = {
0xC6,0xF8,0xEE,0xF6,0xFF,0xD6,0xDE,0x91,
0x60,0x02,0xCE,0x56,0xE7,0xB5,0x4D,0xEC,
0x8F,0x1F,0x89,0xFA,0xEF,0xB2,0x8E,0xFB,
@@ -125,13 +109,8 @@ const BYTE TKIP_Sbox_Upper[256] = {
0x82,0x29,0x5A,0x1E,0x7B,0xA8,0x6D,0x2C
};
-
//STKIPKeyManagement sTKIPKeyTable[MAX_TKIP_KEY];
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
/************************************************************/
/* tkip_sbox() */
/* Returns a 16 bit value from a 64K entry table. The Table */
@@ -152,7 +131,6 @@ static unsigned int tkip_sbox(unsigned int index)
return (left ^ right);
};
-
static unsigned int rotr1(unsigned int a)
{
unsigned int b;
@@ -166,7 +144,6 @@ static unsigned int rotr1(unsigned int a)
return b;
}
-
/*
* Description: Calculate RC4Key fom TK, TA, and TSC
*
@@ -182,11 +159,11 @@ static unsigned int rotr1(unsigned int a)
*
*/
void TKIPvMixKey(
- PBYTE pbyTKey,
- PBYTE pbyTA,
- WORD wTSC15_0,
- DWORD dwTSC47_16,
- PBYTE pbyRC4Key
+ u8 * pbyTKey,
+ u8 * pbyTA,
+ u16 wTSC15_0,
+ u32 dwTSC47_16,
+ u8 * pbyRC4Key
)
{
u32 p1k[5];
diff --git a/drivers/staging/vt6656/tkip.h b/drivers/staging/vt6656/tkip.h
index 47c3a853b92a..4fba7ef38266 100644
--- a/drivers/staging/vt6656/tkip.h
+++ b/drivers/staging/vt6656/tkip.h
@@ -30,28 +30,16 @@
#ifndef __TKIP_H__
#define __TKIP_H__
-#include "ttype.h"
#include "tether.h"
-/*--------------------- Export Definitions -------------------------*/
#define TKIP_KEY_LEN 16
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void TKIPvMixKey(
- PBYTE pbyTKey,
- PBYTE pbyTA,
- WORD wTSC15_0,
- DWORD dwTSC47_16,
- PBYTE pbyRC4Key
+ u8 * pbyTKey,
+ u8 * pbyTA,
+ u16 wTSC15_0,
+ u32 dwTSC47_16,
+ u8 * pbyRC4Key
);
#endif /* __TKIP_H__ */
diff --git a/drivers/staging/vt6656/tmacro.h b/drivers/staging/vt6656/tmacro.h
index 3c81e2b0791d..15cd5abb8004 100644
--- a/drivers/staging/vt6656/tmacro.h
+++ b/drivers/staging/vt6656/tmacro.h
@@ -29,32 +29,30 @@
#ifndef __TMACRO_H__
#define __TMACRO_H__
-#include "ttype.h"
-
/****** Common helper macros ***********************************************/
#if !defined(LOBYTE)
-#define LOBYTE(w) ((BYTE)(w))
+#define LOBYTE(w) ((u8)(w))
#endif
#if !defined(HIBYTE)
-#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
+#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF))
#endif
#if !defined(LOWORD)
-#define LOWORD(d) ((WORD)(d))
+#define LOWORD(d) ((u16)(d))
#endif
#if !defined(HIWORD)
-#define HIWORD(d) ((WORD)((((DWORD)(d)) >> 16) & 0xFFFF))
+#define HIWORD(d) ((u16)((((u32)(d)) >> 16) & 0xFFFF))
#endif
#define LODWORD(q) ((q).u.dwLowDword)
#define HIDWORD(q) ((q).u.dwHighDword)
#if !defined(MAKEWORD)
-#define MAKEWORD(lb, hb) ((WORD)(((BYTE)(lb)) | (((WORD)((BYTE)(hb))) << 8)))
+#define MAKEWORD(lb, hb) ((u16)(((u8)(lb)) | (((u16)((u8)(hb))) << 8)))
#endif
#if !defined(MAKEDWORD)
-#define MAKEDWORD(lw, hw) ((DWORD)(((WORD)(lw)) | (((DWORD)((WORD)(hw))) << 16)))
+#define MAKEDWORD(lw, hw) ((u32)(((u16)(lw)) | (((u32)((u16)(hw))) << 16)))
#endif
#endif /* __TMACRO_H__ */
diff --git a/drivers/staging/vt6656/ttype.h b/drivers/staging/vt6656/ttype.h
deleted file mode 100644
index d7b648945316..000000000000
--- a/drivers/staging/vt6656/ttype.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * File: ttype.h
- *
- * Purpose: define basic common types and macros
- *
- * Author: Tevin Chen
- *
- * Date: May 21, 1996
- *
- */
-
-#ifndef __TTYPE_H__
-#define __TTYPE_H__
-
-#include <linux/types.h>
-
-/******* Common definitions and typedefs ***********************************/
-
-/****** Simple typedefs ***************************************************/
-
-typedef u8 BYTE;
-typedef u16 WORD;
-typedef u32 DWORD;
-
-/****** Common pointer types ***********************************************/
-
-typedef u32 ULONG_PTR;
-typedef u32 DWORD_PTR;
-
-// boolean pointer
-
-typedef BYTE * PBYTE;
-
-typedef WORD * PWORD;
-
-typedef DWORD * PDWORD;
-
-#endif /* __TTYPE_H__ */
diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 00fd0f8a58c2..098be609107c 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -45,7 +45,6 @@
#include "desc.h"
#include "device.h"
-/*--------------------- Static Definitions -------------------------*/
//endpoint def
//endpoint 0: control
//endpoint 1: interrupt
@@ -55,28 +54,18 @@
//static int msglevel =MSG_LEVEL_DEBUG;
static int msglevel =MSG_LEVEL_INFO;
-
#define USB_CTL_WAIT 500 //ms
#ifndef URB_ASYNC_UNLINK
#define URB_ASYNC_UNLINK 0
#endif
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
-
-/*--------------------- Static Functions --------------------------*/
static void s_nsInterruptUsbIoCompleteRead(struct urb *urb);
static void s_nsBulkInUsbIoCompleteRead(struct urb *urb);
static void s_nsBulkOutIoCompleteWrite(struct urb *urb);
static void s_nsControlInUsbIoCompleteRead(struct urb *urb);
static void s_nsControlInUsbIoCompleteWrite(struct urb *urb);
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
int PIPEnsControlOutAsyn(struct vnt_private *pDevice, u8 byRequest,
u16 wValue, u16 wIndex, u16 wLength, u8 *pbyBuffer)
{
@@ -251,8 +240,6 @@ static void s_nsControlInUsbIoCompleteWrite(struct urb *urb)
MP_CLEAR_FLAG(pDevice, fMP_CONTROL_WRITES);
}
-
-
/*
* Description:
* Complete function of usb Control callback
@@ -288,9 +275,6 @@ static void s_nsControlInUsbIoCompleteRead(struct urb *urb)
MP_CLEAR_FLAG(pDevice, fMP_CONTROL_READS);
}
-
-
-
/*
* Description:
* Allocates an usb interrupt in irp and calls USBD.
@@ -341,7 +325,6 @@ usb_fill_bulk_urb(pDevice->pInterruptURB,
return ntStatus;
}
-
/*
* Description:
* Complete function of usb interrupt in irp.
@@ -403,7 +386,6 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb)
STAvUpdateUSBCounter(&pDevice->scStatistic.USB_InterruptStat, ntStatus);
-
if (pDevice->fKillEventPollingThread != true) {
usb_fill_bulk_urb(pDevice->pInterruptURB,
pDevice->usb,
@@ -444,7 +426,6 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
int ntStatus = 0;
struct urb *pUrb;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n");
if (pDevice->Flags & fMP_DISCONNECTED)
@@ -452,7 +433,6 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
pDevice->ulBulkInPosted++;
-
pUrb = pRCB->pUrb;
//
// Now that we have created the urb, we will send a
@@ -482,9 +462,6 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, PRCB pRCB)
return ntStatus;
}
-
-
-
/*
* Description:
* Complete function of usb BulkIn irp.
@@ -535,7 +512,6 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
pDevice->scStatistic.RxOkCnt ++;
}
-
STAvUpdateUSBCounter(&pDevice->scStatistic.USB_BulkInStat, status);
if (bIndicateReceive) {
@@ -553,7 +529,6 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
spin_unlock(&pDevice->lock);
}
-
return;
}
@@ -576,8 +551,6 @@ int PIPEnsSendBulkOut(struct vnt_private *pDevice, PUSB_SEND_CONTEXT pContext)
int status;
struct urb *pUrb;
-
-
pDevice->bPWBitOn = false;
/*
@@ -657,7 +630,6 @@ static void s_nsBulkOutIoCompleteWrite(struct urb *urb)
unsigned long ulBufLen;
PUSB_SEND_CONTEXT pContext;
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n");
//
// The context given to IoSetCompletionRoutine is an USB_CONTEXT struct
@@ -705,7 +677,6 @@ static void s_nsBulkOutIoCompleteWrite(struct urb *urb)
pDevice->dev->trans_start = jiffies;
-
if (status == STATUS_SUCCESS) {
pDevice->packetsSent++;
}
diff --git a/drivers/staging/vt6656/usbpipe.h b/drivers/staging/vt6656/usbpipe.h
index b3023559c15b..bb7a61111a62 100644
--- a/drivers/staging/vt6656/usbpipe.h
+++ b/drivers/staging/vt6656/usbpipe.h
@@ -30,17 +30,8 @@
#ifndef __USBPIPE_H__
#define __USBPIPE_H__
-#include "ttype.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
int PIPEnsControlOut(struct vnt_private *, u8 byRequest, u16 wValue,
u16 wIndex, u16 wLength, u8 *pbyBuffer);
int PIPEnsControlOutAsyn(struct vnt_private *, u8 byRequest,
diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c
index 4bb652bf7cf6..0013cb73d83b 100644
--- a/drivers/staging/vt6656/wcmd.c
+++ b/drivers/staging/vt6656/wcmd.c
@@ -38,7 +38,6 @@
*
*/
-#include "ttype.h"
#include "tmacro.h"
#include "device.h"
#include "mac.h"
@@ -56,17 +55,8 @@
#include "channel.h"
#include "iowpa.h"
-/*--------------------- Static Definitions -------------------------*/
-
-
-
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Functions --------------------------*/
static void s_vProbeChannel(struct vnt_private *);
@@ -74,16 +64,10 @@ static struct vnt_tx_mgmt *s_MgrMakeProbeRequest(struct vnt_private *,
struct vnt_manager *pMgmt, u8 *pScanBSSID, PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pCurrRates, PWLAN_IE_SUPP_RATES pCurrExtSuppRates);
-
static int s_bCommandComplete(struct vnt_private *);
-
static int s_bClearBSSID_SCAN(struct vnt_private *);
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
/*
* Description:
* Stop AdHoc beacon during scan process
@@ -138,7 +122,6 @@ static void vAdHocBeaconStop(struct vnt_private *pDevice)
} /* vAdHocBeaconStop */
-
/*
* Description:
* Restart AdHoc beacon after scan process complete
@@ -171,7 +154,6 @@ static void vAdHocBeaconRestart(struct vnt_private *pDevice)
}
-
/*+
*
* Routine Description:
@@ -200,7 +182,6 @@ static void s_vProbeChannel(struct vnt_private *pDevice)
u8 *pbyRate;
int ii;
-
if (pDevice->byBBType == BB_TYPE_11A) {
pbyRate = &abyCurrSuppRatesA[0];
} else if (pDevice->byBBType == BB_TYPE_11B) {
@@ -232,9 +213,6 @@ static void s_vProbeChannel(struct vnt_private *pDevice)
}
-
-
-
/*+
*
* Routine Description:
@@ -246,7 +224,6 @@ static void s_vProbeChannel(struct vnt_private *pDevice)
*
-*/
-
struct vnt_tx_mgmt *s_MgrMakeProbeRequest(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, u8 *pScanBSSID, PWLAN_IE_SSID pSSID,
PWLAN_IE_SUPP_RATES pCurrRates, PWLAN_IE_SUPP_RATES pCurrExtSuppRates)
@@ -254,13 +231,12 @@ struct vnt_tx_mgmt *s_MgrMakeProbeRequest(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pTxPacket = NULL;
WLAN_FR_PROBEREQ sFrame;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_PROBEREQ_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_PROBEREQ_FR_MAXLEN;
vMgrEncodeProbeRequest(&sFrame);
sFrame.pHdr->sA3.wFrameCtl = cpu_to_le16(
@@ -316,7 +292,6 @@ void vRunCommand(struct vnt_private *pDevice)
u8 byMask[8] = {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
u8 byData;
-
if (pDevice->dwDiagRefCount != 0)
return;
if (pDevice->bCmdRunning != true)
@@ -347,29 +322,7 @@ void vRunCommand(struct vnt_private *pDevice)
pMgmt->uScanChannel = pDevice->byMinChannel;
}
if (pMgmt->uScanChannel > pDevice->byMaxChannel) {
- pMgmt->eScanState = WMAC_NO_SCANNING;
-
- if (pDevice->byBBType != pDevice->byScanBBType) {
- pDevice->byBBType = pDevice->byScanBBType;
- CARDvSetBSSMode(pDevice);
- }
-
- if (pDevice->bUpdateBBVGA) {
- BBvSetShortSlotTime(pDevice);
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent);
- BBvUpdatePreEDThreshold(pDevice, false);
- }
- // Set channel back
- vAdHocBeaconRestart(pDevice);
- // Set channel back
- CARDbSetMediaChannel(pDevice, pMgmt->uCurrChannel);
- // Set Filter
- if (pMgmt->bCurrBSSIDFilterOn) {
- MACvRegBitsOn(pDevice, MAC_REG_RCR, RCR_BSSID);
- pDevice->byRxMode |= RCR_BSSID;
- }
- DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
- pDevice->bStopDataPkt = false;
+ pDevice->eCommandState = WLAN_CMD_SCAN_END;
s_bCommandComplete(pDevice);
spin_unlock_irq(&pDevice->lock);
return;
@@ -377,6 +330,7 @@ void vRunCommand(struct vnt_private *pDevice)
} else {
if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel)) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d \n",pMgmt->uScanChannel);
+ pMgmt->uScanChannel++;
s_bCommandComplete(pDevice);
spin_unlock_irq(&pDevice->lock);
return;
@@ -473,6 +427,7 @@ void vRunCommand(struct vnt_private *pDevice)
pDevice->byRxMode |= RCR_BSSID;
}
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Scanning, set back to channel: [%d]\n", pMgmt->uCurrChannel);
+ pMgmt->uScanChannel = 0;
pMgmt->eScanState = WMAC_NO_SCANNING;
pDevice->bStopDataPkt = false;
@@ -523,7 +478,6 @@ void vRunCommand(struct vnt_private *pDevice)
s_bCommandComplete(pDevice);
break;
-
case WLAN_CMD_SSID_START:
pDevice->byReAssocCount = 0;
@@ -845,7 +799,7 @@ void vRunCommand(struct vnt_private *pDevice)
{
int ntStatus = STATUS_SUCCESS;
- BYTE byTmp;
+ u8 byTmp;
ntStatus = CONTROLnsRequestIn(pDevice,
MESSAGE_TYPE_READ,
@@ -930,7 +884,6 @@ void vRunCommand(struct vnt_private *pDevice)
s_bCommandComplete(pDevice);
break;
-
case WLAN_CMD_CHANGE_BBSENSITIVITY_START:
pDevice->bStopDataPkt = true;
@@ -981,7 +934,6 @@ void vRunCommand(struct vnt_private *pDevice)
s_bCommandComplete(pDevice);
break;
-
case WLAN_CMD_MAC_DISPOWERSAVING_START:
ControlvReadByte (pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PSCTL, &byData);
if ( (byData & PSCTL_PS) != 0 ) {
@@ -1014,7 +966,6 @@ void vRunCommand(struct vnt_private *pDevice)
return;
}
-
static int s_bCommandComplete(struct vnt_private *pDevice)
{
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
@@ -1022,7 +973,6 @@ static int s_bCommandComplete(struct vnt_private *pDevice)
int bRadioCmd = false;
int bForceSCAN = true;
-
pDevice->eCommandState = WLAN_CMD_IDLE;
if (pDevice->cbFreeCmdQueue == CMD_Q_SIZE) {
//Command Queue Empty
@@ -1147,7 +1097,7 @@ int bScheduleCommand(struct vnt_private *pDevice,
break;
/*
case WLAN_CMD_DEAUTH:
- pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((PWORD)pbyItem0);
+ pDevice->eCmdQueue[pDevice->uCmdEnqueueIdx].wDeAuthenReason = *((u16 *)pbyItem0);
break;
*/
@@ -1203,7 +1153,6 @@ static int s_bClearBSSID_SCAN(struct vnt_private *pDevice)
return true;
}
-
//mike add:reset command timer
void vResetCommandTimer(struct vnt_private *pDevice)
{
diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h
index c40e6baa0b5d..db8b4cf7fd60 100644
--- a/drivers/staging/vt6656/wcmd.h
+++ b/drivers/staging/vt6656/wcmd.h
@@ -28,18 +28,13 @@
#ifndef __WCMD_H__
#define __WCMD_H__
-#include "ttype.h"
+
#include "80211hdr.h"
#include "80211mgr.h"
-/*--------------------- Export Definitions -------------------------*/
-
-
-
#define AUTHENTICATE_TIMEOUT 1000 //ms
#define ASSOCIATE_TIMEOUT 1000 //ms
-
// Command code
typedef enum tagCMD_CODE {
WLAN_CMD_BSSID_SCAN,
@@ -73,11 +68,11 @@ typedef enum tagCMD_STATUS {
typedef struct tagCMD_ITEM {
CMD_CODE eCmd;
- BYTE abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
+ u8 abyCmdDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1];
bool bNeedRadioOFF;
bool bRadioCmd;
bool bForceSCAN;
- WORD wDeAuthenReason;
+ u16 wDeAuthenReason;
} CMD_ITEM, *PCMD_ITEM;
// Command state
@@ -104,13 +99,6 @@ typedef enum tagCMD_STATE {
WLAN_CMD_IDLE
} CMD_STATE, *PCMD_STATE;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
struct vnt_private;
void vResetCommandTimer(struct vnt_private *);
diff --git a/drivers/staging/vt6656/wctl.c b/drivers/staging/vt6656/wctl.c
index baa48a1f0d36..47a655db51ef 100644
--- a/drivers/staging/vt6656/wctl.c
+++ b/drivers/staging/vt6656/wctl.c
@@ -39,17 +39,7 @@
#include "card.h"
#include "tmacro.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
// static int msglevel =MSG_LEVEL_INFO;
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
/*
* Description:
@@ -67,7 +57,7 @@
*
*/
-bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
+bool WCTLbIsDuplicate (PSCache pCache, struct ieee80211_hdr *pMACHeader)
{
unsigned int uIndex;
unsigned int ii;
@@ -78,10 +68,10 @@ bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
uIndex = pCache->uInPtr;
for (ii = 0; ii < DUPLICATE_RX_CACHE_LENGTH; ii++) {
pCacheEntry = &(pCache->asCacheEntry[uIndex]);
- if ((pCacheEntry->wFmSequence == pMACHeader->wSeqCtl) &&
+ if ((pCacheEntry->wFmSequence == pMACHeader->seq_ctrl) &&
(!compare_ether_addr(&(pCacheEntry->abyAddr2[0]),
- &(pMACHeader->abyAddr2[0]))) &&
- (LOBYTE(pCacheEntry->wFrameCtl) == LOBYTE(pMACHeader->wFrameCtl))
+ &(pMACHeader->addr2[0]))) &&
+ (LOBYTE(pCacheEntry->wFrameCtl) == LOBYTE(pMACHeader->frame_control))
) {
/* Duplicate match */
return true;
@@ -91,9 +81,9 @@ bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
}
/* Not found in cache - insert */
pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr];
- pCacheEntry->wFmSequence = pMACHeader->wSeqCtl;
- memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN);
- pCacheEntry->wFrameCtl = pMACHeader->wFrameCtl;
+ pCacheEntry->wFmSequence = pMACHeader->seq_ctrl;
+ memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->addr2[0]), ETH_ALEN);
+ pCacheEntry->wFrameCtl = pMACHeader->frame_control;
ADD_ONE_WITH_WRAP_AROUND(pCache->uInPtr, DUPLICATE_RX_CACHE_LENGTH);
return false;
}
@@ -114,14 +104,14 @@ bool WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader)
*/
unsigned int WCTLuSearchDFCB(struct vnt_private *pDevice,
- PS802_11Header pMACHeader)
+ struct ieee80211_hdr *pMACHeader)
{
unsigned int ii;
for (ii = 0; ii < pDevice->cbDFCB; ii++) {
if ((pDevice->sRxDFCB[ii].bInUse == true) &&
(!compare_ether_addr(&(pDevice->sRxDFCB[ii].abyAddr2[0]),
- &(pMACHeader->abyAddr2[0])))) {
+ &(pMACHeader->addr2[0])))) {
return ii;
}
}
@@ -143,7 +133,7 @@ unsigned int WCTLuSearchDFCB(struct vnt_private *pDevice,
*
*/
unsigned int WCTLuInsertDFCB(struct vnt_private *pDevice,
- PS802_11Header pMACHeader)
+ struct ieee80211_hdr *pMACHeader)
{
unsigned int ii;
@@ -154,10 +144,10 @@ unsigned int WCTLuInsertDFCB(struct vnt_private *pDevice,
pDevice->cbFreeDFCB--;
pDevice->sRxDFCB[ii].uLifetime = pDevice->dwMaxReceiveLifetime;
pDevice->sRxDFCB[ii].bInUse = true;
- pDevice->sRxDFCB[ii].wSequence = (pMACHeader->wSeqCtl >> 4);
- pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
+ pDevice->sRxDFCB[ii].wSequence = (pMACHeader->seq_ctrl >> 4);
+ pDevice->sRxDFCB[ii].wFragNum = (pMACHeader->seq_ctrl & 0x000F);
memcpy(&(pDevice->sRxDFCB[ii].abyAddr2[0]),
- &(pMACHeader->abyAddr2[0]),
+ &(pMACHeader->addr2[0]),
ETH_ALEN);
return(ii);
}
@@ -165,7 +155,6 @@ unsigned int WCTLuInsertDFCB(struct vnt_private *pDevice,
return(pDevice->cbDFCB);
}
-
/*
* Description:
* Handle received fragment packet
@@ -182,12 +171,10 @@ unsigned int WCTLuInsertDFCB(struct vnt_private *pDevice,
* Return Value: true if it is valid fragment packet and we have resource to defragment; otherwise false
*
*/
-bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
- unsigned int cbFrameLength, bool bWEP, bool bExtIV)
+bool WCTLbHandleFragment(struct vnt_private *pDevice, struct ieee80211_hdr *pMACHeader, unsigned int cbFrameLength, bool bWEP, bool bExtIV)
{
unsigned int uHeaderSize;
-
if (bWEP == true) {
uHeaderSize = 28;
if (bExtIV)
@@ -203,8 +190,8 @@ bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
if (pDevice->uCurrentDFCBIdx < pDevice->cbDFCB) {
// duplicate, we must flush previous DCB
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].uLifetime = pDevice->dwMaxReceiveLifetime;
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->wSeqCtl >> 4);
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->wSeqCtl & 0x000F);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence = (pMACHeader->seq_ctrl >> 4);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum = (pMACHeader->seq_ctrl & 0x000F);
}
else {
pDevice->uCurrentDFCBIdx = WCTLuInsertDFCB(pDevice, pMACHeader);
@@ -213,8 +200,8 @@ bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
}
}
// reserve 8 byte to match MAC RX Buffer
- pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (PBYTE) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 8);
-// pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (PBYTE) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
+ pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (u8 *) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 8);
+// pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer = (u8 *) (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].skb->data + 4);
memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, pMACHeader, cbFrameLength);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength = cbFrameLength;
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += cbFrameLength;
@@ -225,11 +212,11 @@ bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
else {
pDevice->uCurrentDFCBIdx = WCTLuSearchDFCB(pDevice, pMACHeader);
if (pDevice->uCurrentDFCBIdx != pDevice->cbDFCB) {
- if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->wSeqCtl >> 4)) &&
- (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->wSeqCtl & 0x000F)) &&
+ if ((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wSequence == (pMACHeader->seq_ctrl >> 4)) &&
+ (pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum == (pMACHeader->seq_ctrl & 0x000F)) &&
((pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength + cbFrameLength - uHeaderSize) < 2346)) {
- memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((PBYTE) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
+ memcpy(pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer, ((u8 *) (pMACHeader) + uHeaderSize), (cbFrameLength - uHeaderSize));
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].cbFrameLength += (cbFrameLength - uHeaderSize);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].pbyRxBuffer += (cbFrameLength - uHeaderSize);
pDevice->sRxDFCB[pDevice->uCurrentDFCBIdx].wFragNum++;
@@ -256,4 +243,3 @@ bool WCTLbHandleFragment(struct vnt_private *pDevice, PS802_11Header pMACHeader,
}
}
-
diff --git a/drivers/staging/vt6656/wctl.h b/drivers/staging/vt6656/wctl.h
index 1b21e32e99e5..14cb41177045 100644
--- a/drivers/staging/vt6656/wctl.h
+++ b/drivers/staging/vt6656/wctl.h
@@ -29,59 +29,55 @@
#ifndef __WCTL_H__
#define __WCTL_H__
-#include "ttype.h"
#include "tether.h"
#include "device.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define IS_TYPE_DATA(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_DATA)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & TYPE_802_11_MASK) == TYPE_802_11_DATA)
#define IS_TYPE_MGMT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_MGMT)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & TYPE_802_11_MASK) == TYPE_802_11_MGMT)
#define IS_TYPE_CONTROL(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_802_11_MASK) == TYPE_802_11_CTL)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & TYPE_802_11_MASK) == TYPE_802_11_CTL)
#define IS_FC_MOREDATA(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREDATA) == FC_MOREDATA)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_MOREDATA) == FC_MOREDATA)
#define IS_FC_POWERMGT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_POWERMGT) == FC_POWERMGT)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_POWERMGT) == FC_POWERMGT)
#define IS_FC_RETRY(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_RETRY) == FC_RETRY)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_RETRY) == FC_RETRY)
#define IS_FC_WEP(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_WEP) == FC_WEP)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_WEP) == FC_WEP)
#ifdef __BIG_ENDIAN
#define IS_FRAGMENT_PKT(pMACHeader) \
- (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) != 0))
+ (((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_MOREFRAG) != 0) | \
+ ((((struct ieee80211_hdr *) pMACHeader)->seq_ctrl & 0x0F00) != 0))
#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x0F00) == 0)
+ ((((struct ieee80211_hdr *) pMACHeader)->seq_ctrl & 0x0F00) == 0)
#else
#define IS_FRAGMENT_PKT(pMACHeader) \
- (((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) != 0) | \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) != 0))
+ (((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_MOREFRAG) != 0) | \
+ ((((struct ieee80211_hdr *) pMACHeader)->seq_ctrl & 0x000F) != 0))
#define IS_FIRST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wSeqCtl & 0x000F) == 0)
+ ((((struct ieee80211_hdr *) pMACHeader)->seq_ctrl & 0x000F) == 0)
#endif//#ifdef __BIG_ENDIAN
#define IS_LAST_FRAGMENT_PKT(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & FC_MOREFRAG) == 0)
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & FC_MOREFRAG) == 0)
#define IS_CTL_PSPOLL(pMACHeader) \
- ((((PS802_11Header) pMACHeader)->wFrameCtl & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL)
-
+ ((((struct ieee80211_hdr *) pMACHeader)->frame_control & TYPE_SUBTYPE_MASK) == TYPE_CTL_PSPOLL)
#define ADD_ONE_WITH_WRAP_AROUND(uVar, uModulo) { \
if ((uVar) >= ((uModulo) - 1)) \
@@ -90,16 +86,9 @@
(uVar)++; \
}
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
-bool WCTLbIsDuplicate(PSCache pCache, PS802_11Header pMACHeader);
-bool WCTLbHandleFragment(struct vnt_private *, PS802_11Header pMACHeader,
- unsigned int cbFrameLength, bool bWEP, bool bExtIV);
-unsigned int WCTLuSearchDFCB(struct vnt_private *, PS802_11Header pMACHeader);
-unsigned int WCTLuInsertDFCB(struct vnt_private *, PS802_11Header pMACHeader);
+bool WCTLbIsDuplicate(PSCache pCache, struct ieee80211_hdr *pMACHeader);
+bool WCTLbHandleFragment(struct vnt_private *, struct ieee80211_hdr *pMACHeader, unsigned int cbFrameLength, bool bWEP, bool bExtIV);
+unsigned int WCTLuSearchDFCB(struct vnt_private *, struct ieee80211_hdr *pMACHeader);
+unsigned int WCTLuInsertDFCB(struct vnt_private *, struct ieee80211_hdr *pMACHeader);
#endif /* __WCTL_H__ */
diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c
index 5dced0a43797..6d1ff5eeafa9 100644
--- a/drivers/staging/vt6656/wmgr.c
+++ b/drivers/staging/vt6656/wmgr.c
@@ -81,18 +81,9 @@
#include "control.h"
#include "rndis.h"
-/*--------------------- Static Definitions -------------------------*/
-
-
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Functions --------------------------*/
-
static int ChannelExceedZoneType(struct vnt_private *, u8 byCurrChannel);
/* Association/diassociation functions */
@@ -158,7 +149,6 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
u8 *pCurrBSSID, PWLAN_IE_SUPP_RATES pCurrSuppRates,
PWLAN_IE_SUPP_RATES pCurrExtSuppRates);
-
/* Association response */
static struct vnt_tx_mgmt *s_MgrMakeAssocResponse(struct vnt_private *,
struct vnt_manager *pMgmt, u16 wCurrCapInfo, u16 wAssocStatus,
@@ -182,25 +172,19 @@ static struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *,
/* received status */
static void s_vMgrLogStatus(struct vnt_manager *pMgmt, u16 wStatus);
-
static void s_vMgrSynchBSS(struct vnt_private *, u32 uBSSMode,
PKnownBSS pCurr, PCMD_STATUS pStatus);
-
static bool
s_bCipherMatch (
PKnownBSS pBSSNode,
NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- PBYTE pbyCCSPK,
- PBYTE pbyCCSGK
+ u8 * pbyCCSPK,
+ u8 * pbyCCSGK
);
static void Encyption_Rebuild(struct vnt_private *, PKnownBSS pCurr);
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
/*+
*
* Routine Description:
@@ -216,7 +200,6 @@ void vMgrObjectInit(struct vnt_private *pDevice)
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
int ii;
-
pMgmt->pbyPSPacketPool = &pMgmt->byPSPacketPool[0];
pMgmt->pbyMgmtPacketPool = &pMgmt->byMgmtPacketPool[0];
pMgmt->uCurrChannel = pDevice->uChannel;
@@ -274,7 +257,6 @@ void vMgrAssocBeginSta(struct vnt_private *pDevice,
{
struct vnt_tx_mgmt *pTxPacket;
-
pMgmt->wCurrCapInfo = 0;
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_ESS(1);
if (pDevice->bEncryptionEnable) {
@@ -329,7 +311,6 @@ void vMgrAssocBeginSta(struct vnt_private *pDevice,
return ;
}
-
/*+
*
* Routine Description:
@@ -359,7 +340,6 @@ void vMgrReAssocBeginSta(struct vnt_private *pDevice,
if (pMgmt->wListenInterval == 0)
pMgmt->wListenInterval = 1; // at least one.
-
// ERP Phy (802.11g) should support short preamble.
if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SHORTPREAMBLE(1);
@@ -374,7 +354,6 @@ void vMgrReAssocBeginSta(struct vnt_private *pDevice,
if (pMgmt->b11hEnable == true)
pMgmt->wCurrCapInfo |= WLAN_SET_CAP_INFO_SPECTRUMMNG(1);
-
pTxPacket = s_MgrMakeReAssocRequest
(
pDevice,
@@ -398,7 +377,6 @@ void vMgrReAssocBeginSta(struct vnt_private *pDevice,
}
}
-
return ;
}
@@ -426,7 +404,7 @@ void vMgrDisassocBeginSta(struct vnt_private *pDevice,
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_DISASSOC_FR_MAXLEN;
// format fixed field frame structure
@@ -458,8 +436,6 @@ void vMgrDisassocBeginSta(struct vnt_private *pDevice,
return;
}
-
-
/*+
*
* Routine Description:(AP function)
@@ -483,7 +459,6 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
u8 abyCurrSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
u8 abyCurrExtSuppRates[WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1];
-
if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP)
return;
// node index not found
@@ -496,7 +471,7 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
memset(abyCurrSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
memset(abyCurrExtSuppRates, 0, WLAN_IEHDR_LEN + WLAN_RATES_MAXLEN + 1);
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeAssocRequest(&sFrame);
@@ -523,7 +498,6 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
abyCurrExtSuppRates[1] = 0;
}
-
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
@@ -543,9 +517,9 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (u16)uNodeIndex;
wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (WORD)uNodeIndex;
+ wAssocAID = (u16)uNodeIndex;
// check if ERP support
if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
pMgmt->sNodeDBTable[uNodeIndex].bERPExist = true;
@@ -572,7 +546,6 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate);
}
-
// assoc response reply..
pTxPacket = s_MgrMakeAssocResponse
(
@@ -604,7 +577,6 @@ static void s_vMgrRxAssocRequest(struct vnt_private *pDevice,
return;
}
-
/*+
*
* Description:(AP function)
@@ -643,7 +615,7 @@ static void s_vMgrRxReAssocRequest(struct vnt_private *pDevice,
//decode the frame
memset(&sFrame, 0, sizeof(WLAN_FR_REASSOCREQ));
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeReassocRequest(&sFrame);
if (pMgmt->sNodeDBTable[uNodeIndex].eNodeState >= NODE_AUTH) {
@@ -671,7 +643,6 @@ static void s_vMgrRxReAssocRequest(struct vnt_private *pDevice,
abyCurrExtSuppRates[1] = 0;
}
-
RATEvParseMaxRate((void *)pDevice,
(PWLAN_IE_SUPP_RATES)abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)abyCurrExtSuppRates,
@@ -691,9 +662,9 @@ static void s_vMgrRxReAssocRequest(struct vnt_private *pDevice,
WLAN_GET_CAP_INFO_SHORTPREAMBLE(*sFrame.pwCapInfo);
pMgmt->sNodeDBTable[uNodeIndex].bShortSlotTime =
WLAN_GET_CAP_INFO_SHORTSLOTTIME(*sFrame.pwCapInfo);
- pMgmt->sNodeDBTable[uNodeIndex].wAID = (WORD)uNodeIndex;
+ pMgmt->sNodeDBTable[uNodeIndex].wAID = (u16)uNodeIndex;
wAssocStatus = WLAN_MGMT_STATUS_SUCCESS;
- wAssocAID = (WORD)uNodeIndex;
+ wAssocAID = (u16)uNodeIndex;
// if suppurt ERP
if(pMgmt->sNodeDBTable[uNodeIndex].wMaxSuppRate > RATE_11M)
@@ -722,7 +693,6 @@ static void s_vMgrRxReAssocRequest(struct vnt_private *pDevice,
}
-
// assoc response reply..
pTxPacket = s_MgrMakeReAssocResponse
(
@@ -752,7 +722,6 @@ static void s_vMgrRxReAssocRequest(struct vnt_private *pDevice,
return;
}
-
/*+
*
* Routine Description:
@@ -771,13 +740,11 @@ static void s_vMgrRxAssocResponse(struct vnt_private *pDevice,
PWLAN_IE_SSID pItemSSID;
u8 *pbyIEs;
-
-
if (pMgmt->eCurrState == WMAC_STATE_ASSOCPENDING ||
pMgmt->eCurrState == WMAC_STATE_ASSOC) {
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
// decode the frame
vMgrDecodeAssocResponse(&sFrame);
if ((sFrame.pwCapInfo == NULL)
@@ -820,7 +787,7 @@ static void s_vMgrRxAssocResponse(struct vnt_private *pDevice,
//if(pDevice->bWPASuppWextEnabled == true)
{
- BYTE buf[512];
+ u8 buf[512];
size_t len;
union iwreq_data wrqu;
int we_event;
@@ -906,7 +873,7 @@ void vMgrAuthenBeginSta(struct vnt_private *pDevice,
+ WLAN_AUTHEN_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
vMgrEncodeAuthen(&sFrame);
/* insert values */
@@ -960,7 +927,7 @@ void vMgrDeAuthenBeginSta(struct vnt_private *pDevice,
+ WLAN_DEAUTHEN_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_DEAUTHEN_FR_MAXLEN;
vMgrEncodeDeauthen(&sFrame);
/* insert values */
@@ -984,11 +951,9 @@ void vMgrDeAuthenBeginSta(struct vnt_private *pDevice,
*pStatus = CMD_STATUS_SUCCESS;
}
-
return ;
}
-
/*+
*
* Routine Description:
@@ -1012,7 +977,7 @@ static void s_vMgrRxAuthentication(struct vnt_private *pDevice,
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeAuthen(&sFrame);
switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){
case 1:
@@ -1037,8 +1002,6 @@ static void s_vMgrRxAuthentication(struct vnt_private *pDevice,
return;
}
-
-
/*+
*
* Routine Description:
@@ -1051,7 +1014,6 @@ static void s_vMgrRxAuthentication(struct vnt_private *pDevice,
*
-*/
-
static void s_vMgrRxAuthenSequence_1(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, PWLAN_FR_AUTHEN pFrame)
{
@@ -1082,7 +1044,7 @@ static void s_vMgrRxAuthenSequence_1(struct vnt_private *pDevice,
+ WLAN_AUTHEN_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1142,8 +1104,6 @@ static void s_vMgrRxAuthenSequence_1(struct vnt_private *pDevice,
return;
}
-
-
/*+
*
* Routine Description:
@@ -1162,7 +1122,6 @@ static void s_vMgrRxAuthenSequence_2(struct vnt_private *pDevice,
WLAN_FR_AUTHEN sFrame;
struct vnt_tx_mgmt *pTxPacket = NULL;
-
switch (cpu_to_le16((*(pFrame->pwAuthAlgorithm))))
{
case WLAN_AUTH_ALG_OPENSYSTEM:
@@ -1193,7 +1152,7 @@ static void s_vMgrRxAuthenSequence_2(struct vnt_private *pDevice,
pTxPacket->p80211Header
= (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1241,8 +1200,6 @@ static void s_vMgrRxAuthenSequence_2(struct vnt_private *pDevice,
return;
}
-
-
/*+
*
* Routine Description:
@@ -1297,7 +1254,7 @@ reply:
+ WLAN_AUTHEN_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_AUTHEN_FR_MAXLEN;
// format buffer structure
vMgrEncodeAuthen(&sFrame);
@@ -1329,8 +1286,6 @@ reply:
}
-
-
/*+
*
* Routine Description:
@@ -1385,7 +1340,7 @@ static void s_vMgrRxDisassociation(struct vnt_private *pDevice,
// if is acting an AP..
// a STA is leaving this BSS..
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
if (BSSbIsSTAInNodeDB(pDevice, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
BSSvRemoveOneNode(pDevice, uNodeIndex);
}
@@ -1395,7 +1350,7 @@ static void s_vMgrRxDisassociation(struct vnt_private *pDevice,
}
else if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ){
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeDisassociation(&sFrame);
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP disassociated me, reason=%d.\n", cpu_to_le16(*(sFrame.pwReason)));
@@ -1430,7 +1385,6 @@ static void s_vMgrRxDisassociation(struct vnt_private *pDevice,
return;
}
-
/*+
*
* Routine Description:
@@ -1448,13 +1402,12 @@ static void s_vMgrRxDeauthentication(struct vnt_private *pDevice,
WLAN_FR_DEAUTHEN sFrame;
u32 uNodeIndex = 0;
-
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP ){
//Todo:
// if is acting an AP..
// a STA is leaving this BSS..
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
if (BSSbIsSTAInNodeDB(pDevice, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex)) {
BSSvRemoveOneNode(pDevice, uNodeIndex);
}
@@ -1465,7 +1418,7 @@ static void s_vMgrRxDeauthentication(struct vnt_private *pDevice,
else {
if (pMgmt->eCurrMode == WMAC_MODE_ESS_STA ) {
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeDeauthen(&sFrame);
pDevice->fWPA_Authened = false;
DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "AP deauthed me, reason=%d.\n", cpu_to_le16((*(sFrame.pwReason))));
@@ -1569,14 +1522,12 @@ static void s_vMgrRxBeacon(struct vnt_private *pDevice,
int bChannelHit = false;
u8 byOldPreambleType;
-
-
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)
return;
memset(&sFrame, 0, sizeof(WLAN_FR_BEACON));
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
// decode the beacon frame
vMgrDecodeBeacon(&sFrame);
@@ -1672,7 +1623,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
return;
}
- if(byCurrChannel == (BYTE)pMgmt->uCurrChannel)
+ if(byCurrChannel == (u8)pMgmt->uCurrChannel)
bIsChannelEqual = true;
if (bIsChannelEqual && (pMgmt->eCurrMode == WMAC_MODE_ESS_AP)) {
@@ -1785,7 +1736,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
pDevice->byPreambleType = 0;
}
if (pDevice->byPreambleType != byOldPreambleType)
- CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
+ CARDvSetRSPINF(pDevice, (u8)pDevice->byBBType);
//
// Basic Rate Set may change dynamically
//
@@ -1839,7 +1790,6 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
if (qwTSFOffset > TRIVIAL_SYNC_DIFFERENCE)
bTSFLargeDiff = true;
-
// if infra mode
if (bIsAPBeacon == true) {
@@ -2009,8 +1959,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
pDevice->byPreambleType = 0;
}
if (pDevice->byPreambleType != byOldPreambleType)
- CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
-
+ CARDvSetRSPINF(pDevice, (u8)pDevice->byBBType);
// MACvRegBitsOff(pDevice->PortOffset, MAC_REG_RCR, RCR_BSSID);
// set highest basic rate
@@ -2061,8 +2010,6 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
u8 abyOFDM_RATE[] = {0x0C, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C};
u16 wSuppRate;
-
-
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Create Basic Service Set .......\n");
if (pMgmt->eConfigMode == WMAC_CONFIG_IBSS_STA) {
@@ -2101,7 +2048,6 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->abyCurrSuppRates[2+ii] = abyRATE[ii];
}
-
if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
pMgmt->abyCurrSuppRates[1] = 8;
pMgmt->abyCurrExtSuppRates[1] = 4;
@@ -2113,7 +2059,6 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->abyCurrExtSuppRates[2+ii] = abyOFDM_RATE[ii+4];
}
-
// Disable Protect Mode
pDevice->bProtectMode = 0;
MACvDisableProtectMD(pDevice);
@@ -2156,8 +2101,6 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
&wMaxBasicRate, &wMaxSuppRate, &wSuppRate,
&byTopCCKBasicRate, &byTopOFDMBasicRate);
-
-
if (pDevice->byBBType == BB_TYPE_11A) {
pDevice->bShortSlotTime = true;
} else {
@@ -2221,7 +2164,6 @@ void vMgrCreateOwnIBSS(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->abyCurrBSSID[0] &= ~IEEE_ADDR_GROUP;
pMgmt->abyCurrBSSID[0] |= IEEE_ADDR_UNIVERSAL;
-
DBG_PRT(MSG_LEVEL_INFO, KERN_INFO"Adhoc beacon created bssid:"
"%pM\n", pMgmt->abyCurrBSSID);
}
@@ -2313,7 +2255,6 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
u8 byTopOFDMBasicRate = RATE_1M;
u8 bShortSlotTime = false;
-
for (ii = 0; ii < MAX_BSS_NUM; ii++) {
if (pMgmt->sBSSList[ii].bActive == true)
break;
@@ -2411,9 +2352,9 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
if (pItemExtRates->len <= ii)
break;
}
- pItemRates->len += (BYTE)ii;
+ pItemRates->len += (u8)ii;
if (pItemExtRates->len - ii > 0) {
- pItemExtRates->len -= (BYTE)ii;
+ pItemExtRates->len -= (u8)ii;
for (uu = 0; uu < pItemExtRates->len; uu ++) {
pItemExtRates->abyRates[uu] = pItemExtRates->abyRates[uu + ii];
}
@@ -2466,7 +2407,7 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pDevice->byPreambleType = 0;
}
// Change PreambleType must set RSPINF again
- CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
+ CARDvSetRSPINF(pDevice, (u8)pDevice->byBBType);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Join ESS\n");
@@ -2519,7 +2460,6 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pMgmt->eCurrState = WMAC_STATE_IDLE;
};
-
}
else {
// ad-hoc mode BSS
@@ -2559,7 +2499,6 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
// TODO: check if CapInfo privacy on, but we don't..
pMgmt->uCurrChannel = pCurr->uChannel;
-
// Parse Support Rate IE
pMgmt->abyCurrSuppRates[0] = WLAN_EID_SUPP_RATES;
pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)pCurr->abySuppRates,
@@ -2597,7 +2536,7 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
pDevice->byPreambleType = 0;
}
// Change PreambleType must set RSPINF again
- CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
+ CARDvSetRSPINF(pDevice, (u8)pDevice->byBBType);
// Prepare beacon
bMgrPrepareBeaconToSend((void *) pDevice, pMgmt);
@@ -2609,8 +2548,6 @@ void vMgrJoinBSSBegin(struct vnt_private *pDevice, PCMD_STATUS pStatus)
return;
}
-
-
/*+
*
* Routine Description:
@@ -2806,7 +2743,6 @@ static void Encyption_Rebuild(struct vnt_private *pDevice, PKnownBSS pCurr)
return;
}
-
/*+
*
* Routine Description:
@@ -2828,7 +2764,6 @@ static void s_vMgrFormatTIM(struct vnt_manager *pMgmt, PWLAN_IE_TIM pTIM)
u16 wStartIndex = 0;
u16 wEndIndex = 0;
-
// Find size of partial virtual bitmap
for (ii = 0; ii < (MAX_NODE_NUM + 1); ii++) {
byMap = pMgmt->abyPSTxMap[ii];
@@ -2843,13 +2778,12 @@ static void s_vMgrFormatTIM(struct vnt_manager *pMgmt, PWLAN_IE_TIM pTIM)
if (byMap) {
if (!bStartFound) {
bStartFound = true;
- wStartIndex = (WORD)ii;
+ wStartIndex = (u16)ii;
}
- wEndIndex = (WORD)ii;
+ wEndIndex = (u16)ii;
}
}
-
// Round start index down to nearest even number
wStartIndex &= ~BIT0;
@@ -2876,7 +2810,6 @@ static void s_vMgrFormatTIM(struct vnt_manager *pMgmt, PWLAN_IE_TIM pTIM)
pTIM->byVirtBitMap[0] &= ~BIT0;
}
-
/*+
*
* Routine Description:
@@ -2898,7 +2831,6 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
WLAN_FR_BEACON sFrame;
u8 abyBroadcastAddr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
/* prepare beacon frame */
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
@@ -2906,7 +2838,7 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_BEACON_FR_MAXLEN;
vMgrEncodeBeacon(&sFrame);
// Setup the header
@@ -2917,7 +2849,7 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
));
if (pDevice->bEnablePSMode) {
- sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((WORD)WLAN_SET_FC_PWRMGT(1));
+ sFrame.pHdr->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_PWRMGT(1));
}
memcpy( sFrame.pHdr->sA3.abyAddr1, abyBroadcastAddr, WLAN_ADDR_LEN);
@@ -2945,7 +2877,7 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
sFrame.len += (1) + WLAN_IEHDR_LEN;
sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel;
+ sFrame.pDSParms->byCurrChannel = (u8)uCurrChannel;
}
// TIM field
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
@@ -2988,17 +2920,16 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
// Pairwise Key Cipher Suite
sFrame.pRSNWPA->wPKCount = 0;
// Auth Key Management Suite
- *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
+ *((u16 *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
sFrame.pRSNWPA->len +=2;
// RSN Capabilites
- *((PWORD)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
+ *((u16 *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0;
sFrame.pRSNWPA->len +=2;
sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN;
}
}
-
if (pMgmt->eCurrentPHYMode == PHY_TYPE_11G) {
sFrame.pERP = (PWLAN_IE_ERP)(sFrame.pBuf + sFrame.len);
sFrame.len += 1 + WLAN_IEHDR_LEN;
@@ -3038,10 +2969,6 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
return pTxPacket;
}
-
-
-
-
/*+
*
* Routine Description:
@@ -3053,9 +2980,6 @@ static struct vnt_tx_mgmt *s_MgrMakeBeacon(struct vnt_private *pDevice,
*
-*/
-
-
-
struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, u16 wCurrCapInfo, u16 wCurrBeaconPeriod,
u32 uCurrChannel, u16 wCurrATIMWinodw, u8 *pDstAddr,
@@ -3066,14 +2990,13 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pTxPacket = NULL;
WLAN_FR_PROBERESP sFrame;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_PROBERESP_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_PROBERESP_FR_MAXLEN;
vMgrEncodeProbeResponse(&sFrame);
// Setup the header
@@ -3089,7 +3012,7 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
if (byPHYType == BB_TYPE_11B) {
- *sFrame.pwCapInfo &= cpu_to_le16((WORD)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
+ *sFrame.pwCapInfo &= cpu_to_le16((u16)~(WLAN_SET_CAP_INFO_SHORTSLOTTIME(1)));
}
// Copy SSID
@@ -3114,7 +3037,7 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
sFrame.len += (1) + WLAN_IEHDR_LEN;
sFrame.pDSParms->byElementID = WLAN_EID_DS_PARMS;
sFrame.pDSParms->len = 1;
- sFrame.pDSParms->byCurrChannel = (BYTE)uCurrChannel;
+ sFrame.pDSParms->byCurrChannel = (u8)uCurrChannel;
}
if (pMgmt->eCurrMode != WMAC_MODE_ESS_AP) {
@@ -3166,8 +3089,6 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
return pTxPacket;
}
-
-
/*+
*
* Routine Description:
@@ -3179,7 +3100,6 @@ struct vnt_tx_mgmt *s_MgrMakeProbeResponse(struct vnt_private *pDevice,
*
-*/
-
struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, u8 *pDAddr, u16 wCurrCapInfo,
u16 wListenInterval,
@@ -3192,14 +3112,13 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
u8 *pbyIEs;
u8 *pbyRSN;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_ASSOCREQ_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure.
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_ASSOCREQ_FR_MAXLEN;
// format fixed field frame structure
vMgrEncodeAssocRequest(&sFrame);
@@ -3247,7 +3166,6 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
memcpy(pbyIEs, pCurrRates, pCurrRates->len + WLAN_IEHDR_LEN);
pbyIEs += pCurrRates->len + WLAN_IEHDR_LEN;
-
if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) ||
(pMgmt->eAuthenMode == WMAC_AUTH_WPANONE)) &&
@@ -3287,7 +3205,7 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
}
// Auth Key Management Suite
- pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ pbyRSN = (u8 *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
*pbyRSN++=0x01;
*pbyRSN++=0x00;
*pbyRSN++=0x00;
@@ -3322,7 +3240,7 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
(pMgmt->pCurrBSS != NULL)) {
unsigned int ii;
- PWORD pwPMKID;
+ u16 * pwPMKID;
// WPA IE
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -3387,7 +3305,7 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
// RSN PMKID
pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (PWORD)pbyRSN; // Point to PMKID count
+ pwPMKID = (u16 *)pbyRSN; // Point to PMKID count
*pwPMKID = 0; // Initialize PMKID count
pbyRSN += 2; // Point to PMKID list
for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
@@ -3413,20 +3331,12 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
}
-
// Adjust the length fields
pTxPacket->cbMPDULen = sFrame.len;
pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
return pTxPacket;
}
-
-
-
-
-
-
-
/*+
*
* Routine Description:
@@ -3438,7 +3348,6 @@ struct vnt_tx_mgmt *s_MgrMakeAssocRequest(struct vnt_private *pDevice,
*
-*/
-
struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, u8 *pDAddr, u16 wCurrCapInfo,
u16 wListenInterval, PWLAN_IE_SSID pCurrSSID,
@@ -3450,14 +3359,13 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
u8 *pbyIEs;
u8 *pbyRSN;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_REASSOCREQ_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
/* Setup the sFrame structure. */
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCREQ_FR_MAXLEN;
// format fixed field frame structure
@@ -3546,7 +3454,7 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
sFrame.pRSNWPA->PKSList[0].abyOUI[3] = WPA_NONE;
}
// Auth Key Management Suite
- pbyRSN = (PBYTE)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
+ pbyRSN = (u8 *)(sFrame.pBuf + sFrame.len + 2 + sFrame.pRSNWPA->len);
*pbyRSN++=0x01;
*pbyRSN++=0x00;
*pbyRSN++=0x00;
@@ -3578,7 +3486,7 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
(pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
(pMgmt->pCurrBSS != NULL)) {
unsigned int ii;
- PWORD pwPMKID;
+ u16 * pwPMKID;
/* WPA IE */
sFrame.pRSN = (PWLAN_IE_RSN)(sFrame.pBuf + sFrame.len);
@@ -3643,7 +3551,7 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
if ((pDevice->gsPMKID.BSSIDInfoCount > 0) && (pDevice->bRoaming == true) && (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
// RSN PMKID
pbyRSN = &sFrame.pRSN->abyRSN[18];
- pwPMKID = (PWORD)pbyRSN; // Point to PMKID count
+ pwPMKID = (u16 *)pbyRSN; // Point to PMKID count
*pwPMKID = 0; // Initialize PMKID count
pbyRSN += 2; // Point to PMKID list
for (ii = 0; ii < pDevice->gsPMKID.BSSIDInfoCount; ii++) {
@@ -3669,8 +3577,6 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocRequest(struct vnt_private *pDevice,
pbyIEs += sFrame.pRSN->len + WLAN_IEHDR_LEN;
}
-
-
/* Adjust the length fields */
pTxPacket->cbMPDULen = sFrame.len;
pTxPacket->cbPayloadLen = sFrame.len - WLAN_HDR_ADDR3_LEN;
@@ -3697,14 +3603,13 @@ struct vnt_tx_mgmt *s_MgrMakeAssocResponse(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pTxPacket = NULL;
WLAN_FR_ASSOCRESP sFrame;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_ASSOCREQ_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
vMgrEncodeAssocResponse(&sFrame);
// Setup the header
@@ -3719,7 +3624,7 @@ struct vnt_tx_mgmt *s_MgrMakeAssocResponse(struct vnt_private *pDevice,
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
*sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15));
+ *sFrame.pwAid = cpu_to_le16((u16)(wAssocAID | BIT14 | BIT15));
// Copy the rate set
sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
@@ -3745,7 +3650,6 @@ struct vnt_tx_mgmt *s_MgrMakeAssocResponse(struct vnt_private *pDevice,
return pTxPacket;
}
-
/*+
*
* Routine Description:
@@ -3757,7 +3661,6 @@ struct vnt_tx_mgmt *s_MgrMakeAssocResponse(struct vnt_private *pDevice,
*
-*/
-
struct vnt_tx_mgmt *s_MgrMakeReAssocResponse(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, u16 wCurrCapInfo, u16 wAssocStatus,
u16 wAssocAID, u8 *pDstAddr, PWLAN_IE_SUPP_RATES pCurrSuppRates,
@@ -3766,14 +3669,13 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocResponse(struct vnt_private *pDevice,
struct vnt_tx_mgmt *pTxPacket = NULL;
WLAN_FR_REASSOCRESP sFrame;
-
pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyMgmtPacketPool;
memset(pTxPacket, 0, sizeof(struct vnt_tx_mgmt)
+ WLAN_ASSOCREQ_FR_MAXLEN);
pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
+ sizeof(struct vnt_tx_mgmt));
// Setup the sFrame structure
- sFrame.pBuf = (PBYTE)pTxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pTxPacket->p80211Header;
sFrame.len = WLAN_REASSOCRESP_FR_MAXLEN;
vMgrEncodeReassocResponse(&sFrame);
// Setup the header
@@ -3788,7 +3690,7 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocResponse(struct vnt_private *pDevice,
*sFrame.pwCapInfo = cpu_to_le16(wCurrCapInfo);
*sFrame.pwStatus = cpu_to_le16(wAssocStatus);
- *sFrame.pwAid = cpu_to_le16((WORD)(wAssocAID | BIT14 | BIT15));
+ *sFrame.pwAid = cpu_to_le16((u16)(wAssocAID | BIT14 | BIT15));
// Copy the rate set
sFrame.pSuppRates = (PWLAN_IE_SUPP_RATES)(sFrame.pBuf + sFrame.len);
@@ -3814,7 +3716,6 @@ struct vnt_tx_mgmt *s_MgrMakeReAssocResponse(struct vnt_private *pDevice,
return pTxPacket;
}
-
/*+
*
* Routine Description:
@@ -3835,11 +3736,10 @@ static void s_vMgrRxProbeResponse(struct vnt_private *pDevice,
ERPObject sERP;
int bChannelHit = true;
-
memset(&sFrame, 0, sizeof(WLAN_FR_PROBERESP));
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeProbeResponse(&sFrame);
if ((sFrame.pqwTimestamp == NULL)
@@ -3857,7 +3757,6 @@ static void s_vMgrRxProbeResponse(struct vnt_private *pDevice,
if(sFrame.pSSID->len == 0)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Rx Probe resp: SSID len = 0 \n");
-
//{{ RobertYu:20050201, 11a byCurrChannel != sFrame.pDSParms->byCurrChannel mapping
if( byCurrChannel > CB_MAX_CHANNEL_24G )
{
@@ -3892,7 +3791,6 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
sERP.byERP = 0;
}
-
// update or insert the bss
pBSSList = BSSpAddrIsInBSSList((void *) pDevice,
sFrame.pHdr->sA3.abyAddr3,
@@ -3952,7 +3850,6 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true)
*
-*/
-
static void s_vMgrRxProbeRequest(struct vnt_private *pDevice,
struct vnt_manager *pMgmt, struct vnt_rx_mgmt *pRxPacket)
{
@@ -3969,7 +3866,7 @@ static void s_vMgrRxProbeRequest(struct vnt_private *pDevice,
memset(&sFrame, 0, sizeof(WLAN_FR_PROBEREQ));
// decode the frame
sFrame.len = pRxPacket->cbMPDULen;
- sFrame.pBuf = (PBYTE)pRxPacket->p80211Header;
+ sFrame.pBuf = (u8 *)pRxPacket->p80211Header;
vMgrDecodeProbeRequest(&sFrame);
/*
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Probe request rx:MAC addr:%pM\n",
@@ -4000,7 +3897,7 @@ static void s_vMgrRxProbeRequest(struct vnt_private *pDevice,
0,
sFrame.pHdr->sA3.abyAddr2,
(PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PBYTE)pMgmt->abyCurrBSSID,
+ (u8 *)pMgmt->abyCurrBSSID,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates,
byPHYType
@@ -4042,7 +3939,6 @@ void vMgrRxManagePacket(struct vnt_private *pDevice, struct vnt_manager *pMgmt,
NODE_STATE eNodeState = 0;
CMD_STATUS Status;
-
if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) {
if (BSSbIsSTAInNodeDB(pDevice, pRxPacket->p80211Header->sA3.abyAddr2, &uNodeIndex))
eNodeState = pMgmt->sNodeDBTable[uNodeIndex].eNodeState;
@@ -4199,7 +4095,7 @@ int bMgrPrepareBeaconToSend(struct vnt_private *pDevice,
pMgmt->uCurrChannel,
pMgmt->wCurrATIMWindow, //0,
(PWLAN_IE_SSID)pMgmt->abyCurrSSID,
- (PBYTE)pMgmt->abyCurrBSSID,
+ (u8 *)pMgmt->abyCurrBSSID,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates,
(PWLAN_IE_SUPP_RATES)pMgmt->abyCurrExtSuppRates
);
@@ -4214,9 +4110,6 @@ int bMgrPrepareBeaconToSend(struct vnt_private *pDevice,
return true;
}
-
-
-
/*+
*
* Routine Description:
@@ -4308,8 +4201,6 @@ int bAdd_PMKID_Candidate(struct vnt_private *pDevice, u8 *pbyBSSID,
if (pDevice->gsPMKIDCandidate.NumCandidates >= MAX_PMKIDLIST)
return false;
-
-
// Update Old Candidate
for (ii = 0; ii < pDevice->gsPMKIDCandidate.NumCandidates; ii++) {
pCandidateList = &pDevice->gsPMKIDCandidate.CandidateList[ii];
@@ -4368,12 +4259,12 @@ static bool
s_bCipherMatch (
PKnownBSS pBSSNode,
NDIS_802_11_ENCRYPTION_STATUS EncStatus,
- PBYTE pbyCCSPK,
- PBYTE pbyCCSGK
+ u8 * pbyCCSPK,
+ u8 * pbyCCSGK
)
{
- BYTE byMulticastCipher = KEY_CTL_INVALID;
- BYTE byCipherMask = 0x00;
+ u8 byMulticastCipher = KEY_CTL_INVALID;
+ u8 byCipherMask = 0x00;
int i;
if (pBSSNode == NULL)
@@ -4515,4 +4406,3 @@ s_bCipherMatch (
return true;
}
-
diff --git a/drivers/staging/vt6656/wmgr.h b/drivers/staging/vt6656/wmgr.h
index 83aed45f68a3..5424c7f820ad 100644
--- a/drivers/staging/vt6656/wmgr.h
+++ b/drivers/staging/vt6656/wmgr.h
@@ -34,7 +34,6 @@
#ifndef __WMGR_H__
#define __WMGR_H__
-#include "ttype.h"
#include "80211mgr.h"
#include "80211hdr.h"
#include "wcmd.h"
@@ -42,10 +41,6 @@
#include "wpa2.h"
#include "card.h"
-/*--------------------- Export Definitions -------------------------*/
-
-
-
// Scan time
#define PROBE_DELAY 100 // (us)
#define SWITCH_CHANNEL_DELAY 200 // (us)
@@ -57,7 +52,6 @@
#define WCMD_ACTIVE_SCAN_TIME 20 //(ms)
#define WCMD_PASSIVE_SCAN_TIME 100 //(ms)
-
#define DEFAULT_MSDU_LIFETIME 512 // ms
#define DEFAULT_MSDU_LIFETIME_RES_64us 8000 // 64us
@@ -66,7 +60,6 @@
#define MAKE_BEACON_RESERVED 10 //(us)
-
#define TIM_MULTICAST_MASK 0x01
#define TIM_BITMAPOFFSET_MASK 0xFE
#define DEFAULT_DTIM_PERIOD 1
@@ -75,18 +68,11 @@
#define DEFAULT_IBSS_CHANNEL 6 //2.4G
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
//mike define: make timer to expire after desired times
#define timer_expire(timer, next_tick) mod_timer(&timer, RUN_AT(next_tick))
typedef void (*TimerFunction)(unsigned long);
-
//+++ NDIS related
typedef u8 NDIS_802_11_MAC_ADDRESS[ETH_ALEN];
@@ -117,8 +103,6 @@ typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
u32 OffsetResponseIEs;
} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-
typedef struct tagSAssocInfo {
NDIS_802_11_ASSOCIATION_INFORMATION AssocInfo;
u8 abyIEs[WLAN_BEACON_FR_MAXLEN+WLAN_BEACON_FR_MAXLEN];
@@ -127,9 +111,6 @@ typedef struct tagSAssocInfo {
u8 abyReqIEs[WLAN_BEACON_FR_MAXLEN];
} SAssocInfo, *PSAssocInfo;
-
-
-
typedef enum tagWMAC_AUTHENTICATION_MODE {
WMAC_AUTH_OPEN,
@@ -143,8 +124,6 @@ typedef enum tagWMAC_AUTHENTICATION_MODE {
WMAC_AUTH_MAX // Not a real mode, defined as upper bound
} WMAC_AUTHENTICATION_MODE, *PWMAC_AUTHENTICATION_MODE;
-
-
// Pre-configured Mode (from XP)
typedef enum tagWMAC_CONFIG_MODE {
@@ -155,7 +134,6 @@ typedef enum tagWMAC_CONFIG_MODE {
} WMAC_CONFIG_MODE, *PWMAC_CONFIG_MODE;
-
typedef enum tagWMAC_SCAN_TYPE {
WMAC_SCAN_ACTIVE,
@@ -164,7 +142,6 @@ typedef enum tagWMAC_SCAN_TYPE {
} WMAC_SCAN_TYPE, *PWMAC_SCAN_TYPE;
-
typedef enum tagWMAC_SCAN_STATE {
WMAC_NO_SCANNING,
@@ -173,8 +150,6 @@ typedef enum tagWMAC_SCAN_STATE {
} WMAC_SCAN_STATE, *PWMAC_SCAN_STATE;
-
-
// Notes:
// Basic Service Set state explained as following:
// WMAC_STATE_IDLE : no BSS is selected (Adhoc or Infra)
@@ -207,7 +182,6 @@ typedef enum tagWMAC_CURRENT_MODE {
} WMAC_CURRENT_MODE, *PWMAC_CURRENT_MODE;
-
typedef enum tagWMAC_POWER_MODE {
WMAC_POWER_CAM,
@@ -216,8 +190,6 @@ typedef enum tagWMAC_POWER_MODE {
} WMAC_POWER_MODE, *PWMAC_POWER_MODE;
-
-
/* Tx Management Packet descriptor */
struct vnt_tx_mgmt {
PUWLAN_80211HDR p80211Header;
@@ -225,7 +197,6 @@ struct vnt_tx_mgmt {
u32 cbPayloadLen;
};
-
/* Rx Management Packet descriptor */
struct vnt_rx_mgmt {
PUWLAN_80211HDR p80211Header;
@@ -238,7 +209,6 @@ struct vnt_rx_mgmt {
u8 byRxChannel;
};
-
struct vnt_manager {
void *pAdapter;
@@ -340,7 +310,6 @@ struct vnt_manager {
u8 byMgmtPacketPool[sizeof(struct vnt_tx_mgmt)
+ WLAN_A3FR_MAXLEN];
-
/* One second callback timer */
struct timer_list sTimerSecondCallback;
@@ -384,10 +353,6 @@ struct vnt_manager {
};
-/*--------------------- Export Macros ------------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void vMgrObjectInit(struct vnt_private *pDevice);
void vMgrAssocBeginSta(struct vnt_private *pDevice,
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index f037be3aa164..01db4e7154da 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -32,7 +32,6 @@
*
*/
-#include "ttype.h"
#include "tmacro.h"
#include "tether.h"
#include "device.h"
@@ -42,16 +41,14 @@
#include "wpa.h"
#include "80211mgr.h"
-/*--------------------- Static Variables --------------------------*/
static int msglevel =MSG_LEVEL_INFO;
-const BYTE abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 };
-const BYTE abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 };
-const BYTE abyOUI02[4] = { 0x00, 0x50, 0xf2, 0x02 };
-const BYTE abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 };
-const BYTE abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 };
-const BYTE abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
-
+const u8 abyOUI00[4] = { 0x00, 0x50, 0xf2, 0x00 };
+const u8 abyOUI01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+const u8 abyOUI02[4] = { 0x00, 0x50, 0xf2, 0x02 };
+const u8 abyOUI03[4] = { 0x00, 0x50, 0xf2, 0x03 };
+const u8 abyOUI04[4] = { 0x00, 0x50, 0xf2, 0x04 };
+const u8 abyOUI05[4] = { 0x00, 0x50, 0xf2, 0x05 };
/*+
*
@@ -88,7 +85,6 @@ WPA_ClearRSN(
pBSSList->bWPAValid = false;
}
-
/*+
*
* Description:
@@ -112,7 +108,7 @@ WPA_ParseRSN(
{
PWLAN_IE_RSN_AUTH pIE_RSN_Auth = NULL;
int i, j, m, n = 0;
- PBYTE pbyCaps;
+ u8 * pbyCaps;
WPA_ClearRSN(pBSSList);
@@ -167,7 +163,7 @@ WPA_ParseRSN(
break;
//DBG_PRN_GRP14(("abyPKType[%d]: %X\n", j-1, pBSSList->abyPKType[j-1]));
} //for
- pBSSList->wPKCount = (WORD)j;
+ pBSSList->wPKCount = (u16)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d\n", pBSSList->wPKCount);
}
@@ -197,7 +193,7 @@ WPA_ParseRSN(
//DBG_PRN_GRP14(("abyAuthType[%d]: %X\n", j-1, pBSSList->abyAuthType[j-1]));
}
if(j > 0)
- pBSSList->wAuthCount = (WORD)j;
+ pBSSList->wAuthCount = (u16)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d\n", pBSSList->wAuthCount);
}
@@ -209,11 +205,11 @@ WPA_ParseRSN(
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"14+4+(m+n)*4: %d\n", 14+4+(m+n)*4);
if(pRSN->len+2 >= 14+4+(m+n)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*n)+Cap(2)
- pbyCaps = (PBYTE)pIE_RSN_Auth->AuthKSList[n].abyOUI;
+ pbyCaps = (u8 *)pIE_RSN_Auth->AuthKSList[n].abyOUI;
pBSSList->byDefaultK_as_PK = (*pbyCaps) & WPA_GROUPFLAG;
pBSSList->byReplayIdx = 2 << ((*pbyCaps >> WPA_REPLAYBITSSHIFT) & WPA_REPLAYBITS);
pBSSList->sRSNCapObj.bRSNCapExist = true;
- pBSSList->sRSNCapObj.wRSNCap = *(PWORD)pbyCaps;
+ pBSSList->sRSNCapObj.wRSNCap = *(u16 *)pbyCaps;
//DBG_PRN_GRP14(("pbyCaps: %X\n", *pbyCaps));
//DBG_PRN_GRP14(("byDefaultK_as_PK: %X\n", pBSSList->byDefaultK_as_PK));
//DBG_PRN_GRP14(("byReplayIdx: %X\n", pBSSList->byReplayIdx));
@@ -241,13 +237,13 @@ WPA_ParseRSN(
-*/
bool
WPA_SearchRSN(
- BYTE byCmd,
- BYTE byEncrypt,
+ u8 byCmd,
+ u8 byEncrypt,
PKnownBSS pBSSList
)
{
int ii;
- BYTE byPKType = WPA_NONE;
+ u8 byPKType = WPA_NONE;
if (pBSSList->bWPAValid == false)
return false;
diff --git a/drivers/staging/vt6656/wpa.h b/drivers/staging/vt6656/wpa.h
index 0369cbf32c49..2a724c064e59 100644
--- a/drivers/staging/vt6656/wpa.h
+++ b/drivers/staging/vt6656/wpa.h
@@ -31,11 +31,8 @@
#ifndef __WPA_H__
#define __WPA_H__
-#include "ttype.h"
#include "80211hdr.h"
-/*--------------------- Export Definitions -------------------------*/
-
#define WPA_NONE 0
#define WPA_WEP40 1
#define WPA_TKIP 2
@@ -49,15 +46,6 @@
#define WPA_REPLAYBITSSHIFT 2
#define WPA_REPLAYBITS 0x03
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-
-/*--------------------- Export Functions --------------------------*/
-
void
WPA_ClearRSN(
PKnownBSS pBSSList
@@ -71,8 +59,8 @@ WPA_ParseRSN(
bool
WPA_SearchRSN(
- BYTE byCmd,
- BYTE byEncrypt,
+ u8 byCmd,
+ u8 byEncrypt,
PKnownBSS pBSSList
);
diff --git a/drivers/staging/vt6656/wpa2.c b/drivers/staging/vt6656/wpa2.c
index a89456a9137a..aa2216184345 100644
--- a/drivers/staging/vt6656/wpa2.c
+++ b/drivers/staging/vt6656/wpa2.c
@@ -34,28 +34,17 @@
#include "device.h"
#include "wpa2.h"
-/*--------------------- Static Definitions -------------------------*/
static int msglevel =MSG_LEVEL_INFO;
//static int msglevel =MSG_LEVEL_DEBUG;
-/*--------------------- Static Classes ----------------------------*/
-/*--------------------- Static Variables --------------------------*/
+const u8 abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 };
+const u8 abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
+const u8 abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
+const u8 abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
+const u8 abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
-const BYTE abyOUIGK[4] = { 0x00, 0x0F, 0xAC, 0x00 };
-const BYTE abyOUIWEP40[4] = { 0x00, 0x0F, 0xAC, 0x01 };
-const BYTE abyOUIWEP104[4] = { 0x00, 0x0F, 0xAC, 0x05 };
-const BYTE abyOUITKIP[4] = { 0x00, 0x0F, 0xAC, 0x02 };
-const BYTE abyOUICCMP[4] = { 0x00, 0x0F, 0xAC, 0x04 };
-
-const BYTE abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 };
-const BYTE abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
-
-
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
+const u8 abyOUI8021X[4] = { 0x00, 0x0F, 0xAC, 0x01 };
+const u8 abyOUIPSK[4] = { 0x00, 0x0F, 0xAC, 0x02 };
/*+
*
@@ -113,8 +102,8 @@ WPA2vParseRSN (
)
{
int i, j;
- WORD m = 0, n = 0;
- PBYTE pbyOUI;
+ u16 m = 0, n = 0;
+ u8 * pbyOUI;
bool bUseGK = false;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"WPA2_ParseRSN: [%d]\n", pRSN->len);
@@ -163,11 +152,11 @@ WPA2vParseRSN (
}
if (pRSN->len >= 8) { // ver(2) + GK(4) + PK count(2)
- pBSSNode->wCSSPKCount = *((PWORD) &(pRSN->abyRSN[4]));
+ pBSSNode->wCSSPKCount = *((u16 *) &(pRSN->abyRSN[4]));
j = 0;
pbyOUI = &(pRSN->abyRSN[6]);
- for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pBSSNode->wCSSPKCount) && (j < sizeof(pBSSNode->abyCSSPK)/sizeof(u8)); i++) {
if (pRSN->len >= 8+i*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*i)
if ( !memcmp(pbyOUI, abyOUIGK, 4)) {
@@ -208,17 +197,17 @@ WPA2vParseRSN (
// invalid CSS, No valid PK.
return;
}
- pBSSNode->wCSSPKCount = (WORD)j;
+ pBSSNode->wCSSPKCount = (u16)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wCSSPKCount: %d\n", pBSSNode->wCSSPKCount);
}
- m = *((PWORD) &(pRSN->abyRSN[4]));
+ m = *((u16 *) &(pRSN->abyRSN[4]));
if (pRSN->len >= 10+m*4) { // ver(2) + GK(4) + PK count(2) + PKS(4*m) + AKMSS count(2)
- pBSSNode->wAKMSSAuthCount = *((PWORD) &(pRSN->abyRSN[6+4*m]));
+ pBSSNode->wAKMSSAuthCount = *((u16 *) &(pRSN->abyRSN[6+4*m]));
j = 0;
pbyOUI = &(pRSN->abyRSN[8+4*m]);
- for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(BYTE)); i++) {
+ for (i = 0; (i < pBSSNode->wAKMSSAuthCount) && (j < sizeof(pBSSNode->abyAKMSSAuthType)/sizeof(u8)); i++) {
if (pRSN->len >= 10+(m+i)*4+4) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSS(2)+AKS(4*i)
if ( !memcmp(pbyOUI, abyOUI8021X, 4))
pBSSNode->abyAKMSSAuthType[j++] = WLAN_11i_AKMSS_802_1X;
@@ -231,134 +220,16 @@ WPA2vParseRSN (
} else
break;
}
- pBSSNode->wAKMSSAuthCount = (WORD)j;
+ pBSSNode->wAKMSSAuthCount = (u16)j;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAKMSSAuthCount: %d\n", pBSSNode->wAKMSSAuthCount);
- n = *((PWORD) &(pRSN->abyRSN[6+4*m]));
+ n = *((u16 *) &(pRSN->abyRSN[6+4*m]));
if (pRSN->len >= 12+4*m+4*n) { // ver(2)+GK(4)+PKCnt(2)+PKS(4*m)+AKMSSCnt(2)+AKMSS(4*n)+Cap(2)
pBSSNode->sRSNCapObj.bRSNCapExist = true;
- pBSSNode->sRSNCapObj.wRSNCap = *((PWORD) &(pRSN->abyRSN[8+4*m+4*n]));
+ pBSSNode->sRSNCapObj.wRSNCap = *((u16 *) &(pRSN->abyRSN[8+4*m+4*n]));
}
}
//ignore PMKID lists bcs only (Re)Assocrequest has this field
pBSSNode->bWPA2Valid = true;
}
}
-
-
-/*+
- *
- * Description:
- * Set WPA IEs
- *
- * Parameters:
- * In:
- * pMgmtHandle - Pointer to management object
- * Out:
- * pRSNIEs - Pointer to the RSN IE to set.
- *
- * Return Value: length of IEs.
- *
--*/
-unsigned int WPA2uSetIEs(void *pMgmtHandle, PWLAN_IE_RSN pRSNIEs)
-{
- struct vnt_manager *pMgmt = (struct vnt_manager *)pMgmtHandle;
- u8 *pbyBuffer = NULL;
- int ii = 0;
- u16 *pwPMKID = NULL;
-
- if (pRSNIEs == NULL)
- return 0;
-
- if (((pMgmt->eAuthenMode == WMAC_AUTH_WPA2) ||
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) &&
- (pMgmt->pCurrBSS != NULL)) {
- /* WPA2 IE */
- pbyBuffer = (PBYTE) pRSNIEs;
- pRSNIEs->byElementID = WLAN_EID_RSN;
- pRSNIEs->len = 6; //Version(2)+GK(4)
- pRSNIEs->wVersion = 1;
- //Group Key Cipher Suite
- pRSNIEs->abyRSN[0] = 0x00;
- pRSNIEs->abyRSN[1] = 0x0F;
- pRSNIEs->abyRSN[2] = 0xAC;
- if (pMgmt->byCSSGK == KEY_CTL_WEP) {
- pRSNIEs->abyRSN[3] = pMgmt->pCurrBSS->byCSSGK;
- } else if (pMgmt->byCSSGK == KEY_CTL_TKIP) {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSGK == KEY_CTL_CCMP) {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_CCMP;
- } else {
- pRSNIEs->abyRSN[3] = WLAN_11i_CSS_UNKNOWN;
- }
-
- // Pairwise Key Cipher Suite
- pRSNIEs->abyRSN[4] = 1;
- pRSNIEs->abyRSN[5] = 0;
- pRSNIEs->abyRSN[6] = 0x00;
- pRSNIEs->abyRSN[7] = 0x0F;
- pRSNIEs->abyRSN[8] = 0xAC;
- if (pMgmt->byCSSPK == KEY_CTL_TKIP) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_TKIP;
- } else if (pMgmt->byCSSPK == KEY_CTL_CCMP) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_CCMP;
- } else if (pMgmt->byCSSPK == KEY_CTL_NONE) {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_USE_GROUP;
- } else {
- pRSNIEs->abyRSN[9] = WLAN_11i_CSS_UNKNOWN;
- }
- pRSNIEs->len += 6;
-
- // Auth Key Management Suite
- pRSNIEs->abyRSN[10] = 1;
- pRSNIEs->abyRSN[11] = 0;
- pRSNIEs->abyRSN[12] = 0x00;
- pRSNIEs->abyRSN[13] = 0x0F;
- pRSNIEs->abyRSN[14] = 0xAC;
- if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK) {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_PSK;
- } else if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_802_1X;
- } else {
- pRSNIEs->abyRSN[15] = WLAN_11i_AKMSS_UNKNOWN;
- }
- pRSNIEs->len +=6;
-
- // RSN Capabilites
- if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) {
- memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2);
- } else {
- pRSNIEs->abyRSN[16] = 0;
- pRSNIEs->abyRSN[17] = 0;
- }
- pRSNIEs->len +=2;
-
- if ((pMgmt->gsPMKIDCache.BSSIDInfoCount > 0) &&
- (pMgmt->bRoaming == true) &&
- (pMgmt->eAuthenMode == WMAC_AUTH_WPA2)) {
- /* RSN PMKID, pointer to PMKID count */
- pwPMKID = (PWORD)(&pRSNIEs->abyRSN[18]);
- *pwPMKID = 0; /* Initialize PMKID count */
- pbyBuffer = &pRSNIEs->abyRSN[20]; /* Point to PMKID list */
- for (ii = 0; ii < pMgmt->gsPMKIDCache.BSSIDInfoCount; ii++) {
- if (!memcmp(&pMgmt->
- gsPMKIDCache.BSSIDInfo[ii].abyBSSID[0],
- pMgmt->abyCurrBSSID,
- ETH_ALEN)) {
- (*pwPMKID)++;
- memcpy(pbyBuffer,
- pMgmt->gsPMKIDCache.BSSIDInfo[ii].abyPMKID,
- 16);
- pbyBuffer += 16;
- }
- }
- if (*pwPMKID != 0) {
- pRSNIEs->len += (2 + (*pwPMKID)*16);
- } else {
- pbyBuffer = &pRSNIEs->abyRSN[18];
- }
- }
- return(pRSNIEs->len + WLAN_IEHDR_LEN);
- }
- return(0);
-}
diff --git a/drivers/staging/vt6656/wpa2.h b/drivers/staging/vt6656/wpa2.h
index c359252a6b0e..dc505ce7a7e4 100644
--- a/drivers/staging/vt6656/wpa2.h
+++ b/drivers/staging/vt6656/wpa2.h
@@ -31,17 +31,15 @@
#ifndef __WPA2_H__
#define __WPA2_H__
-#include "ttype.h"
#include "80211mgr.h"
#include "80211hdr.h"
#include "bssdb.h"
-/*--------------------- Export Definitions -------------------------*/
#define MAX_PMKID_CACHE 16
typedef struct tagsPMKIDInfo {
- BYTE abyBSSID[6];
- BYTE abyPMKID[16];
+ u8 abyBSSID[6];
+ u8 abyPMKID[16];
} PMKIDInfo, *PPMKIDInfo;
typedef struct tagSPMKIDCache {
@@ -49,18 +47,7 @@ typedef struct tagSPMKIDCache {
PMKIDInfo BSSIDInfo[MAX_PMKID_CACHE];
} SPMKIDCache, *PSPMKIDCache;
-
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Types ------------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
void WPA2_ClearRSN(PKnownBSS pBSSNode);
void WPA2vParseRSN(PKnownBSS pBSSNode, PWLAN_IE_RSN pRSN);
-unsigned int WPA2uSetIEs(void *pMgmtHandle, PWLAN_IE_RSN pRSNIEs);
-
#endif /* __WPA2_H__ */
diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c
index 53629b26f24d..9f1b413ce86f 100644
--- a/drivers/staging/vt6656/wpactl.c
+++ b/drivers/staging/vt6656/wpactl.c
@@ -42,18 +42,8 @@
#include "rndis.h"
#include "rf.h"
-/*--------------------- Static Definitions -------------------------*/
-
-/*--------------------- Static Classes ----------------------------*/
-
-/*--------------------- Static Variables --------------------------*/
static int msglevel = MSG_LEVEL_INFO;
-/*--------------------- Static Functions --------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-
/*
* Description:
* Set WPA algorithm & keys
@@ -71,11 +61,11 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
{
struct viawget_wpa_param *param = ctx;
struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
- DWORD dwKeyIndex = 0;
- BYTE abyKey[MAX_KEY_LEN];
- BYTE abySeq[MAX_KEY_LEN];
+ u32 dwKeyIndex = 0;
+ u8 abyKey[MAX_KEY_LEN];
+ u8 abySeq[MAX_KEY_LEN];
u64 KeyRSC;
- BYTE byKeyDecMode = KEY_CTL_WEP;
+ u8 byKeyDecMode = KEY_CTL_WEP;
int ret = 0;
int uu;
int ii;
@@ -101,14 +91,14 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
memcpy(&abyKey[0], param->u.wpa_key.key, param->u.wpa_key.key_len);
- dwKeyIndex = (DWORD)(param->u.wpa_key.key_index);
+ dwKeyIndex = (u32)(param->u.wpa_key.key_index);
if (param->u.wpa_key.alg_name == WPA_ALG_WEP) {
if (dwKeyIndex > 3) {
return -EINVAL;
} else {
if (param->u.wpa_key.set_tx) {
- pDevice->byKeyIndex = (BYTE)dwKeyIndex;
+ pDevice->byKeyIndex = (u8)dwKeyIndex;
pDevice->bTransmitKey = true;
dwKeyIndex |= (1 << 31);
}
@@ -127,7 +117,6 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
return ret;
}
-
if (param->u.wpa_key.seq && param->u.wpa_key.seq_len > sizeof(abySeq))
return -EINVAL;
@@ -159,7 +148,6 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
if (param->u.wpa_key.set_tx)
dwKeyIndex |= (1 << 31);
-
if (pDevice->eEncryptionStatus == Ndis802_11Encryption3Enabled)
byKeyDecMode = KEY_CTL_CCMP;
else if (pDevice->eEncryptionStatus == Ndis802_11Encryption2Enabled)
@@ -204,7 +192,7 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
if ((KeybSetAllGroupKey(pDevice, &(pDevice->sKey), dwKeyIndex,
param->u.wpa_key.key_len,
&KeyRSC,
- (PBYTE)abyKey,
+ (u8 *)abyKey,
byKeyDecMode
) == true) &&
(KeybSetDefaultKey(pDevice,
@@ -212,7 +200,7 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
dwKeyIndex,
param->u.wpa_key.key_len,
&KeyRSC,
- (PBYTE)abyKey,
+ (u8 *)abyKey,
byKeyDecMode
) == true) ) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "GROUP Key Assign.\n");
@@ -234,7 +222,7 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
}
if (KeybSetKey(pDevice, &(pDevice->sKey), &param->addr[0],
dwKeyIndex, param->u.wpa_key.key_len,
- &KeyRSC, (PBYTE)abyKey, byKeyDecMode
+ &KeyRSC, (u8 *)abyKey, byKeyDecMode
) == true) {
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Pairwise Key Set\n");
} else {
@@ -250,7 +238,7 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
}
} // BSSID not 0xffffffffffff
if ((ret == 0) && ((param->u.wpa_key.set_tx) != 0)) {
- pDevice->byKeyIndex = (BYTE)param->u.wpa_key.key_index;
+ pDevice->byKeyIndex = (u8)param->u.wpa_key.key_index;
pDevice->bTransmitKey = true;
}
pDevice->bEncryptionEnable = true;
@@ -258,4 +246,3 @@ int wpa_set_keys(struct vnt_private *pDevice, void *ctx)
return ret;
}
-
diff --git a/drivers/staging/vt6656/wpactl.h b/drivers/staging/vt6656/wpactl.h
index 2235ee97012e..e032a1b94ae8 100644
--- a/drivers/staging/vt6656/wpactl.h
+++ b/drivers/staging/vt6656/wpactl.h
@@ -32,9 +32,6 @@
#include "device.h"
#include "iowpa.h"
-/*--------------------- Export Definitions -------------------------*/
-
-
//WPA related
typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
@@ -43,15 +40,8 @@ typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
#define AUTH_ALG_SHARED_KEY 0x02
#define AUTH_ALG_LEAP 0x04
-
typedef unsigned long long NDIS_802_11_KEY_RSC;
-/*--------------------- Export Classes ----------------------------*/
-
-/*--------------------- Export Variables --------------------------*/
-
-/*--------------------- Export Functions --------------------------*/
-
int wpa_set_keys(struct vnt_private *, void *ctx);
#endif /* __WPACL_H__ */
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index 8d2277bb898f..428a9be25010 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -1160,30 +1160,33 @@ static void prism2sta_inf_chinforesults(wlandevice_t *wlandev,
le16_to_cpu(inf->info.chinforesult.scanchannels);
for (i = 0, n = 0; i < HFA384x_CHINFORESULT_MAX; i++) {
- if (hw->channel_info.results.scanchannels & (1 << i)) {
- int channel =
- le16_to_cpu(inf->info.chinforesult.result[n].chid) -
- 1;
- hfa384x_ChInfoResultSub_t *chinforesult =
- &hw->channel_info.results.result[channel];
- chinforesult->chid = channel;
- chinforesult->anl =
- le16_to_cpu(inf->info.chinforesult.result[n].anl);
- chinforesult->pnl =
- le16_to_cpu(inf->info.chinforesult.result[n].pnl);
- chinforesult->active =
- le16_to_cpu(inf->info.chinforesult.result[n].
- active);
- pr_debug
- ("chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n",
- channel + 1,
- chinforesult->
- active & HFA384x_CHINFORESULT_BSSACTIVE ? "signal"
- : "noise", chinforesult->anl, chinforesult->pnl,
- chinforesult->
- active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0);
- n++;
- }
+ hfa384x_ChInfoResultSub_t *result;
+ hfa384x_ChInfoResultSub_t *chinforesult;
+ int chan;
+
+ if (!(hw->channel_info.results.scanchannels & (1 << i)))
+ continue;
+
+ result = &inf->info.chinforesult.result[n];
+ chan = le16_to_cpu(result->chid) - 1;
+
+ if (chan < 0 || chan >= HFA384x_CHINFORESULT_MAX)
+ continue;
+
+ chinforesult = &hw->channel_info.results.result[chan];
+ chinforesult->chid = chan;
+ chinforesult->anl = le16_to_cpu(result->anl);
+ chinforesult->pnl = le16_to_cpu(result->pnl);
+ chinforesult->active = le16_to_cpu(result->active);
+
+ pr_debug("chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n",
+ chan + 1,
+ (chinforesult->active & HFA384x_CHINFORESULT_BSSACTIVE)
+ ? "signal" : "noise",
+ chinforesult->anl, chinforesult->pnl,
+ (chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE)
+ ? 1 : 0);
+ n++;
}
atomic_set(&hw->channel_info.done, 2);
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index b1aed1f1f749..b401974fb282 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -113,14 +113,14 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
dev = interface_to_usbdev(interface);
wlandev = create_wlan();
if (wlandev == NULL) {
- printk(KERN_ERR "%s: Memory allocation failure.\n", dev_info);
+ dev_err(&interface->dev, "Memory allocation failure.\n");
result = -EIO;
goto failed;
}
hw = wlandev->priv;
if (wlan_setup(wlandev, &(interface->dev)) != 0) {
- printk(KERN_ERR "%s: wlan_setup() failed.\n", dev_info);
+ dev_err(&interface->dev, "wlan_setup() failed.\n");
result = -EIO;
goto failed;
}
@@ -143,8 +143,7 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
unregister_wlandev(wlandev);
hfa384x_destroy(hw);
result = -EIO;
- printk(KERN_ERR
- "%s: hfa384x_corereset() failed.\n", dev_info);
+ dev_err(&interface->dev, "hfa384x_corereset() failed.\n");
goto failed;
}
}
@@ -158,7 +157,7 @@ static int prism2sta_probe_usb(struct usb_interface *interface,
prism2sta_ifstate(wlandev, P80211ENUM_ifstate_enable);
if (register_wlandev(wlandev) != 0) {
- printk(KERN_ERR "%s: register_wlandev() failed.\n", dev_info);
+ dev_err(&interface->dev, "register_wlandev() failed.\n");
result = -EIO;
goto failed;
}
@@ -329,8 +328,7 @@ static int prism2sta_resume(struct usb_interface *interface)
if (result != 0) {
unregister_wlandev(wlandev);
hfa384x_destroy(hw);
- printk(KERN_ERR
- "%s: hfa384x_corereset() failed.\n", dev_info);
+ dev_err(&interface->dev, "hfa384x_corereset() failed.\n");
kfree(wlandev);
kfree(hw);
wlandev = NULL;
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
index 148f6373c9a2..80c972305885 100644
--- a/drivers/staging/xgifb/vb_def.h
+++ b/drivers/staging/xgifb/vb_def.h
@@ -62,10 +62,6 @@
#define EnableVBCLKDRVLOW 0x4000
#define EnablePLLSPLOW 0x8000
-#define LCDBToA 0x20 /* LCD SetFlag */
-#define StLCDBToA 0x40
-#define LockLCDBToA 0x80
-#define LCDToFull 0x10
#define AVIDEOSense 0x01 /* CR32 */
#define SVIDEOSense 0x02
#define SCARTSense 0x04
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index df127e406952..19ce5a978cae 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -90,18 +90,14 @@ static void XGINew_DDR1x_MRS_340(unsigned long P3c4,
xgifb_reg_set(P3c4, 0x16, 0x80);
udelay(60);
- xgifb_reg_set(P3c4,
- 0x18,
- pVBInfo->SR15[2][pVBInfo->ram_type]); /* SR18 */
+ xgifb_reg_set(P3c4, 0x18, pVBInfo->SR18[pVBInfo->ram_type]); /* SR18 */
xgifb_reg_set(P3c4, 0x19, 0x01);
xgifb_reg_set(P3c4, 0x16, 0x03);
xgifb_reg_set(P3c4, 0x16, 0x83);
mdelay(1);
xgifb_reg_set(P3c4, 0x1B, 0x03);
udelay(500);
- xgifb_reg_set(P3c4,
- 0x18,
- pVBInfo->SR15[2][pVBInfo->ram_type]); /* SR18 */
+ xgifb_reg_set(P3c4, 0x18, pVBInfo->SR18[pVBInfo->ram_type]); /* SR18 */
xgifb_reg_set(P3c4, 0x19, 0x00);
xgifb_reg_set(P3c4, 0x16, 0x03);
xgifb_reg_set(P3c4, 0x16, 0x83);
@@ -265,18 +261,14 @@ static void XGINew_DDR1x_MRS_XG20(unsigned long P3c4,
xgifb_reg_set(P3c4, 0x16, 0x00);
xgifb_reg_set(P3c4, 0x16, 0x80);
udelay(60);
- xgifb_reg_set(P3c4,
- 0x18,
- pVBInfo->SR15[2][pVBInfo->ram_type]); /* SR18 */
+ xgifb_reg_set(P3c4, 0x18, pVBInfo->SR18[pVBInfo->ram_type]); /* SR18 */
xgifb_reg_set(P3c4, 0x19, 0x01);
xgifb_reg_set(P3c4, 0x16, 0x03);
xgifb_reg_set(P3c4, 0x16, 0x83);
mdelay(1);
xgifb_reg_set(P3c4, 0x1B, 0x03);
udelay(500);
- xgifb_reg_set(P3c4,
- 0x18,
- pVBInfo->SR15[2][pVBInfo->ram_type]); /* SR18 */
+ xgifb_reg_set(P3c4, 0x18, pVBInfo->SR18[pVBInfo->ram_type]); /* SR18 */
xgifb_reg_set(P3c4, 0x19, 0x00);
xgifb_reg_set(P3c4, 0x16, 0x03);
xgifb_reg_set(P3c4, 0x16, 0x83);
@@ -507,9 +499,7 @@ static void XGINew_SetDRAMDefaultRegister340(
xgifb_reg_set(P3d4, 0xB0, 0x80); /* DDRII Dual frequency mode */
XGINew_DDR2_DefaultRegister(HwDeviceExtension, P3d4, pVBInfo);
}
- xgifb_reg_set(P3c4,
- 0x1B,
- pVBInfo->SR15[3][pVBInfo->ram_type]); /* SR1B */
+ xgifb_reg_set(P3c4, 0x1B, 0x03); /* SR1B */
}
@@ -888,7 +878,7 @@ done:
return rom_copy;
}
-static void xgifb_read_vbios(struct pci_dev *pdev,
+static bool xgifb_read_vbios(struct pci_dev *pdev,
struct vb_device_info *pVBInfo)
{
struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
@@ -899,13 +889,10 @@ static void xgifb_read_vbios(struct pci_dev *pdev,
size_t vbios_size;
int entry;
- if (xgifb_info->chip != XG21)
- return;
- pVBInfo->IF_DEF_LVDS = 0;
vbios = xgifb_copy_rom(pdev, &vbios_size);
if (vbios == NULL) {
dev_err(&pdev->dev, "Video BIOS not available\n");
- return;
+ return false;
}
if (vbios_size <= 0x65)
goto error;
@@ -917,7 +904,7 @@ static void xgifb_read_vbios(struct pci_dev *pdev,
(!xgifb_info->display2_force ||
xgifb_info->display2 != XGIFB_DISP_LCD)) {
vfree(vbios);
- return;
+ return false;
}
if (vbios_size <= 0x317)
goto error;
@@ -956,11 +943,11 @@ static void xgifb_read_vbios(struct pci_dev *pdev,
lvds->PSC_S4 = vbios[i + 23];
lvds->PSC_S5 = vbios[i + 24];
vfree(vbios);
- pVBInfo->IF_DEF_LVDS = 1;
- return;
+ return true;
error:
dev_err(&pdev->dev, "Video BIOS corrupted\n");
vfree(vbios);
+ return false;
}
static void XGINew_ChkSenseStatus(struct xgi_hw_device_info *HwDeviceExtension,
@@ -1132,12 +1119,13 @@ static unsigned short XGINew_SenseLCD(struct xgi_hw_device_info
}
}
-static void XGINew_GetXG21Sense(struct xgi_hw_device_info *HwDeviceExtension,
+static void XGINew_GetXG21Sense(struct pci_dev *pdev,
struct vb_device_info *pVBInfo)
{
+ struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
unsigned char Temp;
- if (pVBInfo->IF_DEF_LVDS) { /* For XG21 LVDS */
+ if (xgifb_read_vbios(pdev, pVBInfo)) { /* For XG21 LVDS */
xgifb_reg_or(pVBInfo->P3d4, 0x32, LCDSense);
/* LVDS on chip */
xgifb_reg_and_or(pVBInfo->P3d4, 0x38, ~0xE0, 0xC0);
@@ -1146,7 +1134,7 @@ static void XGINew_GetXG21Sense(struct xgi_hw_device_info *HwDeviceExtension,
xgifb_reg_and_or(pVBInfo->P3d4, 0x4A, ~0x03, 0x03);
Temp = xgifb_reg_get(pVBInfo->P3d4, 0x48) & 0xC0;
if (Temp == 0xC0) { /* DVI & DVO GPIOA/B pull high */
- XGINew_SenseLCD(HwDeviceExtension, pVBInfo);
+ XGINew_SenseLCD(&xgifb_info->hw_info, pVBInfo);
xgifb_reg_or(pVBInfo->P3d4, 0x32, LCDSense);
/* Enable read GPIOF */
xgifb_reg_and_or(pVBInfo->P3d4, 0x4A, ~0x20, 0x20);
@@ -1172,7 +1160,6 @@ static void XGINew_GetXG27Sense(struct xgi_hw_device_info *HwDeviceExtension,
{
unsigned char Temp, bCR4A;
- pVBInfo->IF_DEF_LVDS = 0;
bCR4A = xgifb_reg_get(pVBInfo->P3d4, 0x4A);
/* Enable GPIOA/B/C read */
xgifb_reg_and_or(pVBInfo->P3d4, 0x4A, ~0x07, 0x07);
@@ -1254,14 +1241,12 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
InitTo330Pointer(HwDeviceExtension->jChipType, pVBInfo);
- xgifb_read_vbios(pdev, pVBInfo);
-
/* Openkey */
xgifb_reg_set(pVBInfo->P3c4, 0x05, 0x86);
/* GetXG21Sense (GPIO) */
if (HwDeviceExtension->jChipType == XG21)
- XGINew_GetXG21Sense(HwDeviceExtension, pVBInfo);
+ XGINew_GetXG21Sense(pdev, pVBInfo);
if (HwDeviceExtension->jChipType == XG27)
XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo);
@@ -1369,17 +1354,14 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
if (HwDeviceExtension->jChipType < XG20) {
if (XGI_BridgeIsOn(pVBInfo) == 1) {
- if (pVBInfo->IF_DEF_LVDS == 0) {
- xgifb_reg_set(pVBInfo->Part2Port, 0x00, 0x1C);
- xgifb_reg_set(pVBInfo->Part4Port,
- 0x0D, XGI330_CRT2Data_4_D);
- xgifb_reg_set(pVBInfo->Part4Port,
- 0x0E, XGI330_CRT2Data_4_E);
- xgifb_reg_set(pVBInfo->Part4Port,
- 0x10, XGI330_CRT2Data_4_10);
- xgifb_reg_set(pVBInfo->Part4Port, 0x0F, 0x3F);
- }
-
+ xgifb_reg_set(pVBInfo->Part2Port, 0x00, 0x1C);
+ xgifb_reg_set(pVBInfo->Part4Port,
+ 0x0D, XGI330_CRT2Data_4_D);
+ xgifb_reg_set(pVBInfo->Part4Port,
+ 0x0E, XGI330_CRT2Data_4_E);
+ xgifb_reg_set(pVBInfo->Part4Port,
+ 0x10, XGI330_CRT2Data_4_10);
+ xgifb_reg_set(pVBInfo->Part4Port, 0x0F, 0x3F);
XGI_LockCRT2(HwDeviceExtension, pVBInfo);
}
} /* != XG20 */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index dfa5303379e9..3adec3f18462 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -32,7 +32,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
pVBInfo->VBInfo = 0;
pVBInfo->TVInfo = 0;
- pVBInfo->SR15 = XGI340_SR13;
+ pVBInfo->SR18 = XGI340_SR18;
pVBInfo->CR40 = XGI340_cr41;
/* 310 customization related */
@@ -49,7 +49,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
pVBInfo->MCLKData = XGI27New_MCLKData;
pVBInfo->CR40 = XGI27_cr41;
pVBInfo->XGINew_CR97 = 0xc1;
- pVBInfo->SR15 = XG27_SR13;
+ pVBInfo->SR18 = XG27_SR18;
/*Z11m DDR*/
temp = xgifb_reg_get(pVBInfo->P3c4, 0x3B);
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index ae0c18b320a4..c08ff5b2d6ee 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -81,7 +81,6 @@ struct XGI_XG21CRT1Struct {
struct XGI330_LCDCapStruct {
unsigned char LCD_ID;
unsigned short LCD_Capability;
- unsigned char LCD_SetFlag;
unsigned char LCD_HSyncWidth;
unsigned char LCD_VSyncWidth;
unsigned char LCD_VCLK;
@@ -89,16 +88,6 @@ struct XGI330_LCDCapStruct {
unsigned char LCDA_VCLKData2;
unsigned char LCUCHAR_VCLKData1;
unsigned char LCUCHAR_VCLKData2;
- unsigned char PSC_S1;
- unsigned char PSC_S2;
- unsigned char PSC_S3;
- unsigned char PSC_S4;
- unsigned char PSC_S5;
- unsigned char PWD_2B;
- unsigned char PWD_2C;
- unsigned char PWD_2D;
- unsigned char PWD_2E;
- unsigned char PWD_2F;
unsigned char Spectrum_31;
unsigned char Spectrum_32;
unsigned char Spectrum_33;
@@ -145,7 +134,7 @@ struct vb_device_info {
unsigned short LCDHRS, LCDVRS, LCDHDES, LCDVDES;
unsigned short ModeType;
- unsigned short IF_DEF_LVDS, IF_DEF_TRUMPION, IF_DEF_DSTN;
+ unsigned short IF_DEF_LVDS;
unsigned short IF_DEF_CRT2Monitor;
unsigned short IF_DEF_YPbPr;
unsigned short IF_DEF_HiVision;
@@ -157,12 +146,11 @@ struct vb_device_info {
void __iomem *FBAddr;
- unsigned char const (*SR15)[3];
+ unsigned char const *SR18;
unsigned char const (*CR40)[3];
struct SiS_MCLKData const *MCLKData;
- unsigned char *pXGINew_DRAMTypeDefinition;
unsigned char XGINew_CR97;
struct XGI330_LCDCapStruct const *LCDCapList;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index b4c05c80b937..7168eedbd96a 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -18,18 +18,12 @@ const struct XGI_ECLKDataStruct XGI340_ECLKData[] = {
{0x7C, 0x08, 0x01, 200},
};
-static const unsigned char XG27_SR13[4][3] = {
- {0x35, 0x45, 0xb1}, /* SR13 */
- {0x41, 0x51, 0x5c}, /* SR14 */
- {0x32, 0x32, 0x42}, /* SR18 */
- {0x03, 0x03, 0x03} /* SR1B */
+static const unsigned char XG27_SR18[3] = {
+ 0x32, 0x32, 0x42 /* SR18 */
};
-static const unsigned char XGI340_SR13[4][3] = {
- {0x35, 0x45, 0xb1}, /* SR13 */
- {0x41, 0x51, 0x5c}, /* SR14 */
- {0x31, 0x42, 0x42}, /* SR18 */
- {0x03, 0x03, 0x03} /* SR1B */
+static const unsigned char XGI340_SR18[3] = {
+ 0x31, 0x42, 0x42 /* SR18 */
};
static const unsigned char XGI340_cr41[24][3] = {
@@ -1867,72 +1861,72 @@ static const struct XGI330_TVDataTablStruct XGI_TVDataTable[] = {
/* Dual link only */
static const struct XGI330_LCDCapStruct XGI_LCDDLCapList[] = {
/* LCDCap1024x768 */
- {Panel_1024x768, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
- 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+ {Panel_1024x768, DefaultLCDCap, 0x88, 0x06, VCLK65_315,
+ 0x6C, 0xC3, 0x35, 0x62,
+ 0x0A, 0xC0, 0x28, 0x10},
/* LCDCap1280x1024 */
- {Panel_1280x1024, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
+ {Panel_1280x1024, XGI_LCDDualLink+DefaultLCDCap,
0x70, 0x03, VCLK108_2_315,
- 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x70, 0x44, 0xF8, 0x2F,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1400x1050 */
- {Panel_1400x1050, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
+ {Panel_1400x1050, XGI_LCDDualLink+DefaultLCDCap,
0x70, 0x03, VCLK108_2_315,
- 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x70, 0x44, 0xF8, 0x2F,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1600x1200 */
- {Panel_1600x1200, XGI_LCDDualLink+DefaultLCDCap, LCDToFull,
+ {Panel_1600x1200, XGI_LCDDualLink+DefaultLCDCap,
0xC0, 0x03, VCLK162,
- 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x43, 0x22, 0x70, 0x24,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1024x768x75 */
- {Panel_1024x768x75, DefaultLCDCap, 0, 0x60, 0, VCLK78_75,
- 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+ {Panel_1024x768x75, DefaultLCDCap, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61,
+ 0x0A, 0xC0, 0x28, 0x10},
/* LCDCap1280x1024x75 */
- {Panel_1280x1024x75, XGI_LCDDualLink+DefaultLCDCap, StLCDBToA,
+ {Panel_1280x1024x75, XGI_LCDDualLink+DefaultLCDCap,
0x90, 0x03, VCLK135_5,
- 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x54, 0x42, 0x4A, 0x61,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCapDefault */
- {0xFF, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
- 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+ {0xFF, DefaultLCDCap, 0x88, 0x06, VCLK65_315,
+ 0x6C, 0xC3, 0x35, 0x62,
+ 0x0A, 0xC0, 0x28, 0x10}
};
static const struct XGI330_LCDCapStruct XGI_LCDCapList[] = {
/* LCDCap1024x768 */
- {Panel_1024x768, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
- 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+ {Panel_1024x768, DefaultLCDCap, 0x88, 0x06, VCLK65_315,
+ 0x6C, 0xC3, 0x35, 0x62,
+ 0x0A, 0xC0, 0x28, 0x10},
/* LCDCap1280x1024 */
- {Panel_1280x1024, DefaultLCDCap, StLCDBToA,
+ {Panel_1280x1024, DefaultLCDCap,
0x70, 0x03, VCLK108_2_315,
- 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x70, 0x44, 0xF8, 0x2F,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1400x1050 */
- {Panel_1400x1050, DefaultLCDCap, StLCDBToA,
+ {Panel_1400x1050, DefaultLCDCap,
0x70, 0x03, VCLK108_2_315,
- 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x70, 0x44, 0xF8, 0x2F,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1600x1200 */
- {Panel_1600x1200, DefaultLCDCap, LCDToFull,
+ {Panel_1600x1200, DefaultLCDCap,
0xC0, 0x03, VCLK162,
- 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x5A, 0x23, 0x5A, 0x23,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCap1024x768x75 */
- {Panel_1024x768x75, DefaultLCDCap, 0, 0x60, 0, VCLK78_75,
- 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+ {Panel_1024x768x75, DefaultLCDCap, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61,
+ 0x0A, 0xC0, 0x28, 0x10},
/* LCDCap1280x1024x75 */
- {Panel_1280x1024x75, DefaultLCDCap, StLCDBToA,
+ {Panel_1280x1024x75, DefaultLCDCap,
0x90, 0x03, VCLK135_5,
- 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+ 0x54, 0x42, 0x4A, 0x61,
+ 0x0A, 0xC0, 0x30, 0x10},
/* LCDCapDefault */
- {0xFF, DefaultLCDCap, 0, 0x88, 0x06, VCLK65_315,
- 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
- 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+ {0xFF, DefaultLCDCap, 0x88, 0x06, VCLK65_315,
+ 0x6C, 0xC3, 0x35, 0x62,
+ 0x0A, 0xC0, 0x28, 0x10}
};
const struct XGI_Ext2Struct XGI330_RefIndex[] = {
diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig
index 73582705e8c5..2d7b2da3b9e0 100644
--- a/drivers/staging/zcache/Kconfig
+++ b/drivers/staging/zcache/Kconfig
@@ -1,5 +1,5 @@
config ZCACHE
- bool "Dynamic compression of swap pages and clean pagecache pages"
+ tristate "Dynamic compression of swap pages and clean pagecache pages"
depends on CRYPTO=y && SWAP=y && CLEANCACHE && FRONTSWAP
select CRYPTO_LZO
default n
@@ -10,12 +10,20 @@ config ZCACHE
memory to store clean page cache pages and swap in RAM,
providing a noticeable reduction in disk I/O.
+config ZCACHE_DEBUG
+ bool "Enable debug statistics"
+ depends on DEBUG_FS && ZCACHE
+ default n
+ help
+ This is used to provide an debugfs directory with counters of
+ how zcache is doing. You probably want to set this to 'N'.
+
config RAMSTER
- bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
- depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE=y
+ tristate "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
+ depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE
depends on NET
# must ensure struct page is 8-byte aligned
- select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT
+ select HAVE_ALIGNED_STRUCT_PAGE if !64BIT
default n
help
RAMster allows RAM on other machines in a cluster to be utilized
@@ -25,6 +33,14 @@ config RAMSTER
zcache2, compresses swap pages into local RAM, but then remotifies
the compressed pages to another node in the RAMster cluster.
+config RAMSTER_DEBUG
+ bool "Enable ramster debug statistics"
+ depends on DEBUG_FS && RAMSTER
+ default n
+ help
+ This is used to provide an debugfs directory with counters of
+ how ramster is doing. You probably want to set this to 'N'.
+
# Depends on not-yet-upstreamed mm patches to export end_swap_bio_write and
# __add_to_swap_cache, and implement __swap_writepage (which is swap_writepage
# without the frontswap call. When these are in-tree, the dependency on
diff --git a/drivers/staging/zcache/Makefile b/drivers/staging/zcache/Makefile
index 471104957dad..845a5c2721b5 100644
--- a/drivers/staging/zcache/Makefile
+++ b/drivers/staging/zcache/Makefile
@@ -1,4 +1,6 @@
zcache-y := zcache-main.o tmem.o zbud.o
+zcache-$(CONFIG_ZCACHE_DEBUG) += debug.o
+zcache-$(CONFIG_RAMSTER_DEBUG) += ramster/debug.o
zcache-$(CONFIG_RAMSTER) += ramster/ramster.o ramster/r2net.o
zcache-$(CONFIG_RAMSTER) += ramster/nodemanager.o ramster/tcp.o
zcache-$(CONFIG_RAMSTER) += ramster/heartbeat.o ramster/masklog.o
diff --git a/drivers/staging/zcache/TODO b/drivers/staging/zcache/TODO
index c1e26d4973dc..d0c18fa95743 100644
--- a/drivers/staging/zcache/TODO
+++ b/drivers/staging/zcache/TODO
@@ -41,14 +41,10 @@ STATUS/OWNERSHIP
for 3.9, see https://lkml.org/lkml/2013/2/6/437;
7. PROTOTYPED as part of "new" zcache; in staging/zcache for 3.9;
needs more review (plan to discuss at LSF/MM 2013)
-8. IN PROGRESS; owned by Konrad Wilk; v2 recently posted
- http://lkml.org/lkml/2013/2/1/542
9. IN PROGRESS; owned by Konrad Wilk; Mel Gorman provided
great feedback in August 2012 (unfortunately of "old"
zcache)
-10. Konrad posted series of fixes (that now need rebasing)
- https://lkml.org/lkml/2013/2/1/566
-11. NOT DONE; owned by Konrad Wilk
+11. NOT DONE; owned by Konrad Wilk and Bob Liu
12. TBD (depends on quantity of feedback)
13. PROPOSED; one suggestion proposed by Dan; needs more ideas/feedback
14. TBD (depends on feedback)
@@ -65,5 +61,4 @@ ZCACHE FUTURE NEW FUNCTIONALITY
A. Support zsmalloc as an alternative high-density allocator
(See https://lkml.org/lkml/2013/1/23/511)
-B. Support zero-filled pages more efficiently
-C. Possibly support three zbuds per pageframe when space allows
+B. Possibly support three zbuds per pageframe when space allows
diff --git a/drivers/staging/zcache/debug.c b/drivers/staging/zcache/debug.c
new file mode 100644
index 000000000000..daa26919b886
--- /dev/null
+++ b/drivers/staging/zcache/debug.c
@@ -0,0 +1,107 @@
+#include <linux/atomic.h>
+#include "debug.h"
+
+#ifdef CONFIG_ZCACHE_DEBUG
+#include <linux/debugfs.h>
+
+ssize_t zcache_obj_count;
+ssize_t zcache_obj_count_max;
+ssize_t zcache_objnode_count;
+ssize_t zcache_objnode_count_max;
+u64 zcache_eph_zbytes;
+u64 zcache_eph_zbytes_max;
+u64 zcache_pers_zbytes_max;
+ssize_t zcache_eph_pageframes_max;
+ssize_t zcache_pers_pageframes_max;
+ssize_t zcache_pageframes_alloced;
+ssize_t zcache_pageframes_freed;
+ssize_t zcache_eph_zpages;
+ssize_t zcache_eph_zpages_max;
+ssize_t zcache_pers_zpages_max;
+ssize_t zcache_flush_total;
+ssize_t zcache_flush_found;
+ssize_t zcache_flobj_total;
+ssize_t zcache_flobj_found;
+ssize_t zcache_failed_eph_puts;
+ssize_t zcache_failed_pers_puts;
+ssize_t zcache_failed_getfreepages;
+ssize_t zcache_failed_alloc;
+ssize_t zcache_put_to_flush;
+ssize_t zcache_compress_poor;
+ssize_t zcache_mean_compress_poor;
+ssize_t zcache_eph_ate_tail;
+ssize_t zcache_eph_ate_tail_failed;
+ssize_t zcache_pers_ate_eph;
+ssize_t zcache_pers_ate_eph_failed;
+ssize_t zcache_evicted_eph_zpages;
+ssize_t zcache_evicted_eph_pageframes;
+ssize_t zcache_zero_filled_pages;
+ssize_t zcache_zero_filled_pages_max;
+
+#define ATTR(x) { .name = #x, .val = &zcache_##x, }
+static struct debug_entry {
+ const char *name;
+ ssize_t *val;
+} attrs[] = {
+ ATTR(obj_count), ATTR(obj_count_max),
+ ATTR(objnode_count), ATTR(objnode_count_max),
+ ATTR(flush_total), ATTR(flush_found),
+ ATTR(flobj_total), ATTR(flobj_found),
+ ATTR(failed_eph_puts), ATTR(failed_pers_puts),
+ ATTR(failed_getfreepages), ATTR(failed_alloc),
+ ATTR(put_to_flush),
+ ATTR(compress_poor), ATTR(mean_compress_poor),
+ ATTR(eph_ate_tail), ATTR(eph_ate_tail_failed),
+ ATTR(pers_ate_eph), ATTR(pers_ate_eph_failed),
+ ATTR(evicted_eph_zpages), ATTR(evicted_eph_pageframes),
+ ATTR(eph_pageframes), ATTR(eph_pageframes_max),
+ ATTR(pers_pageframes), ATTR(pers_pageframes_max),
+ ATTR(eph_zpages), ATTR(eph_zpages_max),
+ ATTR(pers_zpages), ATTR(pers_zpages_max),
+ ATTR(last_active_file_pageframes),
+ ATTR(last_inactive_file_pageframes),
+ ATTR(last_active_anon_pageframes),
+ ATTR(last_inactive_anon_pageframes),
+ ATTR(eph_nonactive_puts_ignored),
+ ATTR(pers_nonactive_puts_ignored),
+ ATTR(zero_filled_pages),
+#ifdef CONFIG_ZCACHE_WRITEBACK
+ ATTR(outstanding_writeback_pages),
+ ATTR(writtenback_pages),
+#endif
+};
+#undef ATTR
+int zcache_debugfs_init(void)
+{
+ unsigned int i;
+ struct dentry *root = debugfs_create_dir("zcache", NULL);
+ if (root == NULL)
+ return -ENXIO;
+
+ for (i = 0; i < ARRAY_SIZE(attrs); i++)
+ if (!debugfs_create_size_t(attrs[i].name, S_IRUGO, root, attrs[i].val))
+ goto out;
+
+ debugfs_create_u64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes);
+ debugfs_create_u64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max);
+ debugfs_create_u64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes);
+ debugfs_create_u64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max);
+
+ return 0;
+out:
+ return -ENODEV;
+}
+
+/* developers can call this in case of ooms, e.g. to find memory leaks */
+void zcache_dump(void)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(attrs); i++)
+ pr_debug("zcache: %s=%zu\n", attrs[i].name, *attrs[i].val);
+
+ pr_debug("zcache: eph_zbytes=%llu\n", (unsigned long long)zcache_eph_zbytes);
+ pr_debug("zcache: eph_zbytes_max=%llu\n", (unsigned long long)zcache_eph_zbytes_max);
+ pr_debug("zcache: pers_zbytes=%llu\n", (unsigned long long)zcache_pers_zbytes);
+ pr_debug("zcache: pers_zbytes_max=%llu\n", (unsigned long long)zcache_pers_zbytes_max);
+}
+#endif
diff --git a/drivers/staging/zcache/debug.h b/drivers/staging/zcache/debug.h
new file mode 100644
index 000000000000..8088d28f2dce
--- /dev/null
+++ b/drivers/staging/zcache/debug.h
@@ -0,0 +1,305 @@
+#include <linux/bug.h>
+
+#ifdef CONFIG_ZCACHE_DEBUG
+
+/* we try to keep these statistics SMP-consistent */
+extern ssize_t zcache_obj_count;
+static atomic_t zcache_obj_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_obj_count_max;
+static inline void inc_zcache_obj_count(void)
+{
+ zcache_obj_count = atomic_inc_return(&zcache_obj_atomic);
+ if (zcache_obj_count > zcache_obj_count_max)
+ zcache_obj_count_max = zcache_obj_count;
+}
+static inline void dec_zcache_obj_count(void)
+{
+ zcache_obj_count = atomic_dec_return(&zcache_obj_atomic);
+ BUG_ON(zcache_obj_count < 0);
+};
+extern ssize_t zcache_objnode_count;
+static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_objnode_count_max;
+static inline void inc_zcache_objnode_count(void)
+{
+ zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic);
+ if (zcache_objnode_count > zcache_objnode_count_max)
+ zcache_objnode_count_max = zcache_objnode_count;
+};
+static inline void dec_zcache_objnode_count(void)
+{
+ zcache_objnode_count = atomic_dec_return(&zcache_objnode_atomic);
+ BUG_ON(zcache_objnode_count < 0);
+};
+extern u64 zcache_eph_zbytes;
+static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0);
+extern u64 zcache_eph_zbytes_max;
+static inline void inc_zcache_eph_zbytes(unsigned clen)
+{
+ zcache_eph_zbytes = atomic_long_add_return(clen, &zcache_eph_zbytes_atomic);
+ if (zcache_eph_zbytes > zcache_eph_zbytes_max)
+ zcache_eph_zbytes_max = zcache_eph_zbytes;
+};
+static inline void dec_zcache_eph_zbytes(unsigned zsize)
+{
+ zcache_eph_zbytes = atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
+};
+extern u64 zcache_pers_zbytes;
+static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0);
+extern u64 zcache_pers_zbytes_max;
+static inline void inc_zcache_pers_zbytes(unsigned clen)
+{
+ zcache_pers_zbytes = atomic_long_add_return(clen, &zcache_pers_zbytes_atomic);
+ if (zcache_pers_zbytes > zcache_pers_zbytes_max)
+ zcache_pers_zbytes_max = zcache_pers_zbytes;
+}
+static inline void dec_zcache_pers_zbytes(unsigned zsize)
+{
+ zcache_pers_zbytes = atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
+}
+extern ssize_t zcache_eph_pageframes;
+static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_eph_pageframes_max;
+static inline void inc_zcache_eph_pageframes(void)
+{
+ zcache_eph_pageframes = atomic_inc_return(&zcache_eph_pageframes_atomic);
+ if (zcache_eph_pageframes > zcache_eph_pageframes_max)
+ zcache_eph_pageframes_max = zcache_eph_pageframes;
+};
+static inline void dec_zcache_eph_pageframes(void)
+{
+ zcache_eph_pageframes = atomic_dec_return(&zcache_eph_pageframes_atomic);
+};
+extern ssize_t zcache_pers_pageframes;
+static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_pers_pageframes_max;
+static inline void inc_zcache_pers_pageframes(void)
+{
+ zcache_pers_pageframes = atomic_inc_return(&zcache_pers_pageframes_atomic);
+ if (zcache_pers_pageframes > zcache_pers_pageframes_max)
+ zcache_pers_pageframes_max = zcache_pers_pageframes;
+}
+static inline void dec_zcache_pers_pageframes(void)
+{
+ zcache_pers_pageframes = atomic_dec_return(&zcache_pers_pageframes_atomic);
+}
+extern ssize_t zcache_pageframes_alloced;
+static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0);
+static inline void inc_zcache_pageframes_alloced(void)
+{
+ zcache_pageframes_alloced = atomic_inc_return(&zcache_pageframes_alloced_atomic);
+};
+extern ssize_t zcache_pageframes_freed;
+static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0);
+static inline void inc_zcache_pageframes_freed(void)
+{
+ zcache_pageframes_freed = atomic_inc_return(&zcache_pageframes_freed_atomic);
+}
+extern ssize_t zcache_eph_zpages;
+static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_eph_zpages_max;
+static inline void inc_zcache_eph_zpages(void)
+{
+ zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic);
+ if (zcache_eph_zpages > zcache_eph_zpages_max)
+ zcache_eph_zpages_max = zcache_eph_zpages;
+}
+static inline void dec_zcache_eph_zpages(unsigned zpages)
+{
+ zcache_eph_zpages = atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
+}
+extern ssize_t zcache_pers_zpages;
+static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_pers_zpages_max;
+static inline void inc_zcache_pers_zpages(void)
+{
+ zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic);
+ if (zcache_pers_zpages > zcache_pers_zpages_max)
+ zcache_pers_zpages_max = zcache_pers_zpages;
+}
+static inline void dec_zcache_pers_zpages(unsigned zpages)
+{
+ zcache_pers_zpages = atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
+}
+
+extern ssize_t zcache_zero_filled_pages;
+static atomic_t zcache_zero_filled_pages_atomic = ATOMIC_INIT(0);
+extern ssize_t zcache_zero_filled_pages_max;
+static inline void inc_zcache_zero_filled_pages(void)
+{
+ zcache_zero_filled_pages = atomic_inc_return(
+ &zcache_zero_filled_pages_atomic);
+ if (zcache_zero_filled_pages > zcache_zero_filled_pages_max)
+ zcache_zero_filled_pages_max = zcache_zero_filled_pages;
+}
+static inline void dec_zcache_zero_filled_pages(void)
+{
+ zcache_zero_filled_pages = atomic_dec_return(
+ &zcache_zero_filled_pages_atomic);
+}
+static inline unsigned long curr_pageframes_count(void)
+{
+ return zcache_pageframes_alloced -
+ atomic_read(&zcache_pageframes_freed_atomic) -
+ atomic_read(&zcache_eph_pageframes_atomic) -
+ atomic_read(&zcache_pers_pageframes_atomic);
+};
+/* but for the rest of these, counting races are ok */
+extern ssize_t zcache_flush_total;
+extern ssize_t zcache_flush_found;
+extern ssize_t zcache_flobj_total;
+extern ssize_t zcache_flobj_found;
+extern ssize_t zcache_failed_eph_puts;
+extern ssize_t zcache_failed_pers_puts;
+extern ssize_t zcache_failed_getfreepages;
+extern ssize_t zcache_failed_alloc;
+extern ssize_t zcache_put_to_flush;
+extern ssize_t zcache_compress_poor;
+extern ssize_t zcache_mean_compress_poor;
+extern ssize_t zcache_eph_ate_tail;
+extern ssize_t zcache_eph_ate_tail_failed;
+extern ssize_t zcache_pers_ate_eph;
+extern ssize_t zcache_pers_ate_eph_failed;
+extern ssize_t zcache_evicted_eph_zpages;
+extern ssize_t zcache_evicted_eph_pageframes;
+
+extern ssize_t zcache_last_active_file_pageframes;
+extern ssize_t zcache_last_inactive_file_pageframes;
+extern ssize_t zcache_last_active_anon_pageframes;
+extern ssize_t zcache_last_inactive_anon_pageframes;
+static ssize_t zcache_eph_nonactive_puts_ignored;
+static ssize_t zcache_pers_nonactive_puts_ignored;
+#ifdef CONFIG_ZCACHE_WRITEBACK
+extern ssize_t zcache_writtenback_pages;
+extern ssize_t zcache_outstanding_writeback_pages;
+#endif
+
+static inline void inc_zcache_flush_total(void)
+{
+ zcache_flush_total++;
+};
+static inline void inc_zcache_flush_found(void)
+{
+ zcache_flush_found++;
+};
+static inline void inc_zcache_flobj_total(void)
+{
+ zcache_flobj_total++;
+};
+static inline void inc_zcache_flobj_found(void)
+{
+ zcache_flobj_found++;
+};
+static inline void inc_zcache_failed_eph_puts(void)
+{
+ zcache_failed_eph_puts++;
+};
+static inline void inc_zcache_failed_pers_puts(void)
+{
+ zcache_failed_pers_puts++;
+};
+static inline void inc_zcache_failed_getfreepages(void)
+{
+ zcache_failed_getfreepages++;
+};
+static inline void inc_zcache_failed_alloc(void)
+{
+ zcache_failed_alloc++;
+};
+static inline void inc_zcache_put_to_flush(void)
+{
+ zcache_put_to_flush++;
+};
+static inline void inc_zcache_compress_poor(void)
+{
+ zcache_compress_poor++;
+};
+static inline void inc_zcache_mean_compress_poor(void)
+{
+ zcache_mean_compress_poor++;
+};
+static inline void inc_zcache_eph_ate_tail(void)
+{
+ zcache_eph_ate_tail++;
+};
+static inline void inc_zcache_eph_ate_tail_failed(void)
+{
+ zcache_eph_ate_tail_failed++;
+};
+static inline void inc_zcache_pers_ate_eph(void)
+{
+ zcache_pers_ate_eph++;
+};
+static inline void inc_zcache_pers_ate_eph_failed(void)
+{
+ zcache_pers_ate_eph_failed++;
+};
+static inline void inc_zcache_evicted_eph_zpages(unsigned zpages)
+{
+ zcache_evicted_eph_zpages += zpages;
+};
+static inline void inc_zcache_evicted_eph_pageframes(void)
+{
+ zcache_evicted_eph_pageframes++;
+};
+
+static inline void inc_zcache_eph_nonactive_puts_ignored(void)
+{
+ zcache_eph_nonactive_puts_ignored++;
+};
+static inline void inc_zcache_pers_nonactive_puts_ignored(void)
+{
+ zcache_pers_nonactive_puts_ignored++;
+};
+
+int zcache_debugfs_init(void);
+#else
+static inline void inc_zcache_obj_count(void) { };
+static inline void dec_zcache_obj_count(void) { };
+static inline void inc_zcache_objnode_count(void) { };
+static inline void dec_zcache_objnode_count(void) { };
+static inline void inc_zcache_eph_zbytes(unsigned clen) { };
+static inline void dec_zcache_eph_zbytes(unsigned zsize) { };
+static inline void inc_zcache_pers_zbytes(unsigned clen) { };
+static inline void dec_zcache_pers_zbytes(unsigned zsize) { };
+static inline void inc_zcache_eph_pageframes(void) { };
+static inline void dec_zcache_eph_pageframes(void) { };
+static inline void inc_zcache_pers_pageframes(void) { };
+static inline void dec_zcache_pers_pageframes(void) { };
+static inline void inc_zcache_pageframes_alloced(void) { };
+static inline void inc_zcache_pageframes_freed(void) { };
+static inline void inc_zcache_eph_zpages(void) { };
+static inline void dec_zcache_eph_zpages(unsigned zpages) { };
+static inline void inc_zcache_pers_zpages(void) { };
+static inline void dec_zcache_pers_zpages(unsigned zpages) { };
+static inline void inc_zcache_zero_filled_pages(void) { };
+static inline void dec_zcache_zero_filled_pages(void) { };
+static inline unsigned long curr_pageframes_count(void)
+{
+ return 0;
+};
+static inline int zcache_debugfs_init(void)
+{
+ return 0;
+};
+static inline void inc_zcache_flush_total(void) { };
+static inline void inc_zcache_flush_found(void) { };
+static inline void inc_zcache_flobj_total(void) { };
+static inline void inc_zcache_flobj_found(void) { };
+static inline void inc_zcache_failed_eph_puts(void) { };
+static inline void inc_zcache_failed_pers_puts(void) { };
+static inline void inc_zcache_failed_getfreepages(void) { };
+static inline void inc_zcache_failed_alloc(void) { };
+static inline void inc_zcache_put_to_flush(void) { };
+static inline void inc_zcache_compress_poor(void) { };
+static inline void inc_zcache_mean_compress_poor(void) { };
+static inline void inc_zcache_eph_ate_tail(void) { };
+static inline void inc_zcache_eph_ate_tail_failed(void) { };
+static inline void inc_zcache_pers_ate_eph(void) { };
+static inline void inc_zcache_pers_ate_eph_failed(void) { };
+static inline void inc_zcache_evicted_eph_zpages(unsigned zpages) { };
+static inline void inc_zcache_evicted_eph_pageframes(void) { };
+
+static inline void inc_zcache_eph_nonactive_puts_ignored(void) { };
+static inline void inc_zcache_pers_nonactive_puts_ignored(void) { };
+#endif
diff --git a/drivers/staging/zcache/ramster.h b/drivers/staging/zcache/ramster.h
index 1b71aea2ff62..e1f91d5a0f6a 100644
--- a/drivers/staging/zcache/ramster.h
+++ b/drivers/staging/zcache/ramster.h
@@ -11,10 +11,14 @@
#ifndef _ZCACHE_RAMSTER_H_
#define _ZCACHE_RAMSTER_H_
+#ifdef CONFIG_RAMSTER_MODULE
+#define CONFIG_RAMSTER
+#endif
+
#ifdef CONFIG_RAMSTER
#include "ramster/ramster.h"
#else
-static inline void ramster_init(bool x, bool y, bool z)
+static inline void ramster_init(bool x, bool y, bool z, bool w)
{
}
diff --git a/drivers/staging/zcache/ramster/debug.c b/drivers/staging/zcache/ramster/debug.c
new file mode 100644
index 000000000000..327e4f0d98e1
--- /dev/null
+++ b/drivers/staging/zcache/ramster/debug.c
@@ -0,0 +1,66 @@
+#include <linux/atomic.h>
+#include "debug.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+
+ssize_t ramster_eph_pages_remoted;
+ssize_t ramster_pers_pages_remoted;
+ssize_t ramster_eph_pages_remote_failed;
+ssize_t ramster_pers_pages_remote_failed;
+ssize_t ramster_remote_eph_pages_succ_get;
+ssize_t ramster_remote_pers_pages_succ_get;
+ssize_t ramster_remote_eph_pages_unsucc_get;
+ssize_t ramster_remote_pers_pages_unsucc_get;
+ssize_t ramster_pers_pages_remote_nomem;
+ssize_t ramster_remote_objects_flushed;
+ssize_t ramster_remote_object_flushes_failed;
+ssize_t ramster_remote_pages_flushed;
+ssize_t ramster_remote_page_flushes_failed;
+
+#define ATTR(x) { .name = #x, .val = &ramster_##x, }
+static struct debug_entry {
+ const char *name;
+ ssize_t *val;
+} attrs[] = {
+ ATTR(eph_pages_remoted),
+ ATTR(pers_pages_remoted),
+ ATTR(eph_pages_remote_failed),
+ ATTR(pers_pages_remote_failed),
+ ATTR(remote_eph_pages_succ_get),
+ ATTR(remote_pers_pages_succ_get),
+ ATTR(remote_eph_pages_unsucc_get),
+ ATTR(remote_pers_pages_unsucc_get),
+ ATTR(pers_pages_remote_nomem),
+ ATTR(remote_objects_flushed),
+ ATTR(remote_pages_flushed),
+ ATTR(remote_object_flushes_failed),
+ ATTR(remote_page_flushes_failed),
+ ATTR(foreign_eph_pages),
+ ATTR(foreign_eph_pages_max),
+ ATTR(foreign_pers_pages),
+ ATTR(foreign_pers_pages_max),
+};
+#undef ATTR
+
+int ramster_debugfs_init(void)
+{
+ int i;
+ struct dentry *root = debugfs_create_dir("ramster", NULL);
+ if (root == NULL)
+ return -ENXIO;
+
+ for (i = 0; i < ARRAY_SIZE(attrs); i++)
+ if (!debugfs_create_size_t(attrs[i].name,
+ S_IRUGO, root, attrs[i].val))
+ goto out;
+ return 0;
+out:
+ return -ENODEV;
+}
+#else
+static inline int ramster_debugfs_init(void)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/staging/zcache/ramster/debug.h b/drivers/staging/zcache/ramster/debug.h
new file mode 100644
index 000000000000..5ffab50807d8
--- /dev/null
+++ b/drivers/staging/zcache/ramster/debug.h
@@ -0,0 +1,145 @@
+#include <linux/bug.h>
+
+#ifdef CONFIG_RAMSTER_DEBUG
+
+extern long ramster_flnodes;
+static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0);
+static unsigned long ramster_flnodes_max;
+static inline void inc_ramster_flnodes(void)
+{
+ ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic);
+ if (ramster_flnodes > ramster_flnodes_max)
+ ramster_flnodes_max = ramster_flnodes;
+}
+static inline void dec_ramster_flnodes(void)
+{
+ ramster_flnodes = atomic_dec_return(&ramster_flnodes_atomic);
+}
+extern ssize_t ramster_foreign_eph_pages;
+static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0);
+static ssize_t ramster_foreign_eph_pages_max;
+static inline void inc_ramster_foreign_eph_pages(void)
+{
+ ramster_foreign_eph_pages = atomic_inc_return(
+ &ramster_foreign_eph_pages_atomic);
+ if (ramster_foreign_eph_pages > ramster_foreign_eph_pages_max)
+ ramster_foreign_eph_pages_max = ramster_foreign_eph_pages;
+}
+static inline void dec_ramster_foreign_eph_pages(void)
+{
+ ramster_foreign_eph_pages = atomic_dec_return(
+ &ramster_foreign_eph_pages_atomic);
+}
+extern ssize_t ramster_foreign_pers_pages;
+static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0);
+static ssize_t ramster_foreign_pers_pages_max;
+static inline void inc_ramster_foreign_pers_pages(void)
+{
+ ramster_foreign_pers_pages = atomic_inc_return(
+ &ramster_foreign_pers_pages_atomic);
+ if (ramster_foreign_pers_pages > ramster_foreign_pers_pages_max)
+ ramster_foreign_pers_pages_max = ramster_foreign_pers_pages;
+}
+static inline void dec_ramster_foreign_pers_pages(void)
+{
+ ramster_foreign_pers_pages = atomic_dec_return(
+ &ramster_foreign_pers_pages_atomic);
+}
+
+extern ssize_t ramster_eph_pages_remoted;
+extern ssize_t ramster_pers_pages_remoted;
+extern ssize_t ramster_eph_pages_remote_failed;
+extern ssize_t ramster_pers_pages_remote_failed;
+extern ssize_t ramster_remote_eph_pages_succ_get;
+extern ssize_t ramster_remote_pers_pages_succ_get;
+extern ssize_t ramster_remote_eph_pages_unsucc_get;
+extern ssize_t ramster_remote_pers_pages_unsucc_get;
+extern ssize_t ramster_pers_pages_remote_nomem;
+extern ssize_t ramster_remote_objects_flushed;
+extern ssize_t ramster_remote_object_flushes_failed;
+extern ssize_t ramster_remote_pages_flushed;
+extern ssize_t ramster_remote_page_flushes_failed;
+
+int ramster_debugfs_init(void);
+
+static inline void inc_ramster_eph_pages_remoted(void)
+{
+ ramster_eph_pages_remoted++;
+};
+static inline void inc_ramster_pers_pages_remoted(void)
+{
+ ramster_pers_pages_remoted++;
+};
+static inline void inc_ramster_eph_pages_remote_failed(void)
+{
+ ramster_eph_pages_remote_failed++;
+};
+static inline void inc_ramster_pers_pages_remote_failed(void)
+{
+ ramster_pers_pages_remote_failed++;
+};
+static inline void inc_ramster_remote_eph_pages_succ_get(void)
+{
+ ramster_remote_eph_pages_succ_get++;
+};
+static inline void inc_ramster_remote_pers_pages_succ_get(void)
+{
+ ramster_remote_pers_pages_succ_get++;
+};
+static inline void inc_ramster_remote_eph_pages_unsucc_get(void)
+{
+ ramster_remote_eph_pages_unsucc_get++;
+};
+static inline void inc_ramster_remote_pers_pages_unsucc_get(void)
+{
+ ramster_remote_pers_pages_unsucc_get++;
+};
+static inline void inc_ramster_pers_pages_remote_nomem(void)
+{
+ ramster_pers_pages_remote_nomem++;
+};
+static inline void inc_ramster_remote_objects_flushed(void)
+{
+ ramster_remote_objects_flushed++;
+};
+static inline void inc_ramster_remote_object_flushes_failed(void)
+{
+ ramster_remote_object_flushes_failed++;
+};
+static inline void inc_ramster_remote_pages_flushed(void)
+{
+ ramster_remote_pages_flushed++;
+};
+static inline void inc_ramster_remote_page_flushes_failed(void)
+{
+ ramster_remote_page_flushes_failed++;
+};
+
+#else
+
+static inline void inc_ramster_flnodes(void) { };
+static inline void dec_ramster_flnodes(void) { };
+static inline void inc_ramster_foreign_eph_pages(void) { };
+static inline void dec_ramster_foreign_eph_pages(void) { };
+static inline void inc_ramster_foreign_pers_pages(void) { };
+static inline void dec_ramster_foreign_pers_pages(void) { };
+
+static inline void inc_ramster_eph_pages_remoted(void) { };
+static inline void inc_ramster_pers_pages_remoted(void) { };
+static inline void inc_ramster_eph_pages_remote_failed(void) { };
+static inline void inc_ramster_pers_pages_remote_failed(void) { };
+static inline void inc_ramster_remote_eph_pages_succ_get(void) { };
+static inline void inc_ramster_remote_pers_pages_succ_get(void) { };
+static inline void inc_ramster_remote_eph_pages_unsucc_get(void) { };
+static inline void inc_ramster_remote_pers_pages_unsucc_get(void) { };
+static inline void inc_ramster_pers_pages_remote_nomem(void) { };
+static inline void inc_ramster_remote_objects_flushed(void) { };
+static inline void inc_ramster_remote_object_flushes_failed(void) { };
+static inline void inc_ramster_remote_pages_flushed(void) { };
+static inline void inc_ramster_remote_page_flushes_failed(void) { };
+
+static inline int ramster_debugfs_init(void)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/staging/zcache/ramster/nodemanager.c b/drivers/staging/zcache/ramster/nodemanager.c
index c0f48158735d..2cfe93342c0d 100644
--- a/drivers/staging/zcache/ramster/nodemanager.c
+++ b/drivers/staging/zcache/ramster/nodemanager.c
@@ -949,7 +949,7 @@ static void __exit exit_r2nm(void)
r2hb_exit();
}
-static int __init init_r2nm(void)
+int r2nm_init(void)
{
int ret = -1;
@@ -986,10 +986,11 @@ out_r2hb:
out:
return ret;
}
+EXPORT_SYMBOL_GPL(r2nm_init);
MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL");
-/* module_init(init_r2nm) */
-late_initcall(init_r2nm);
-/* module_exit(exit_r2nm) */
+#ifndef CONFIG_RAMSTER_MODULE
+late_initcall(r2nm_init);
+#endif
diff --git a/drivers/staging/zcache/ramster/ramster.c b/drivers/staging/zcache/ramster/ramster.c
index bf96a1cbf7c1..b18b887db79f 100644
--- a/drivers/staging/zcache/ramster/ramster.c
+++ b/drivers/staging/zcache/ramster/ramster.c
@@ -42,6 +42,7 @@
#include "ramster.h"
#include "ramster_nodemanager.h"
#include "tcp.h"
+#include "debug.h"
#define RAMSTER_TESTING
@@ -63,79 +64,12 @@ static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0);
static bool ramster_nodes_manual_up[MANUAL_NODES] __read_mostly;
static int ramster_remote_target_nodenum __read_mostly = -1;
-/* these counters are made available via debugfs */
-static long ramster_flnodes;
-static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0);
-static unsigned long ramster_flnodes_max;
-static ssize_t ramster_foreign_eph_pages;
-static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_eph_pages_max;
-static ssize_t ramster_foreign_pers_pages;
-static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0);
-static ssize_t ramster_foreign_pers_pages_max;
-static ssize_t ramster_eph_pages_remoted;
-static ssize_t ramster_pers_pages_remoted;
-static ssize_t ramster_eph_pages_remote_failed;
-static ssize_t ramster_pers_pages_remote_failed;
-static ssize_t ramster_remote_eph_pages_succ_get;
-static ssize_t ramster_remote_pers_pages_succ_get;
-static ssize_t ramster_remote_eph_pages_unsucc_get;
-static ssize_t ramster_remote_pers_pages_unsucc_get;
-static ssize_t ramster_pers_pages_remote_nomem;
-static ssize_t ramster_remote_objects_flushed;
-static ssize_t ramster_remote_object_flushes_failed;
-static ssize_t ramster_remote_pages_flushed;
-static ssize_t ramster_remote_page_flushes_failed;
+/* Used by this code. */
+long ramster_flnodes;
+ssize_t ramster_foreign_eph_pages;
+ssize_t ramster_foreign_pers_pages;
/* FIXME frontswap selfshrinking knobs in debugfs? */
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#define zdfs debugfs_create_size_t
-#define zdfs64 debugfs_create_u64
-static int __init ramster_debugfs_init(void)
-{
- struct dentry *root = debugfs_create_dir("ramster", NULL);
- if (root == NULL)
- return -ENXIO;
-
- zdfs("eph_pages_remoted", S_IRUGO, root, &ramster_eph_pages_remoted);
- zdfs("pers_pages_remoted", S_IRUGO, root, &ramster_pers_pages_remoted);
- zdfs("eph_pages_remote_failed", S_IRUGO, root,
- &ramster_eph_pages_remote_failed);
- zdfs("pers_pages_remote_failed", S_IRUGO, root,
- &ramster_pers_pages_remote_failed);
- zdfs("remote_eph_pages_succ_get", S_IRUGO, root,
- &ramster_remote_eph_pages_succ_get);
- zdfs("remote_pers_pages_succ_get", S_IRUGO, root,
- &ramster_remote_pers_pages_succ_get);
- zdfs("remote_eph_pages_unsucc_get", S_IRUGO, root,
- &ramster_remote_eph_pages_unsucc_get);
- zdfs("remote_pers_pages_unsucc_get", S_IRUGO, root,
- &ramster_remote_pers_pages_unsucc_get);
- zdfs("pers_pages_remote_nomem", S_IRUGO, root,
- &ramster_pers_pages_remote_nomem);
- zdfs("remote_objects_flushed", S_IRUGO, root,
- &ramster_remote_objects_flushed);
- zdfs("remote_pages_flushed", S_IRUGO, root,
- &ramster_remote_pages_flushed);
- zdfs("remote_object_flushes_failed", S_IRUGO, root,
- &ramster_remote_object_flushes_failed);
- zdfs("remote_page_flushes_failed", S_IRUGO, root,
- &ramster_remote_page_flushes_failed);
- zdfs("foreign_eph_pages", S_IRUGO, root,
- &ramster_foreign_eph_pages);
- zdfs("foreign_eph_pages_max", S_IRUGO, root,
- &ramster_foreign_eph_pages_max);
- zdfs("foreign_pers_pages", S_IRUGO, root,
- &ramster_foreign_pers_pages);
- zdfs("foreign_pers_pages_max", S_IRUGO, root,
- &ramster_foreign_pers_pages_max);
- return 0;
-}
-#undef zdebugfs
-#undef zdfs64
-#endif
-
static LIST_HEAD(ramster_rem_op_list);
static DEFINE_SPINLOCK(ramster_rem_op_list_lock);
static DEFINE_PER_CPU(struct ramster_preload, ramster_preloads);
@@ -154,9 +88,7 @@ static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
flnode = kp->flnode;
BUG_ON(flnode == NULL);
kp->flnode = NULL;
- ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic);
- if (ramster_flnodes > ramster_flnodes_max)
- ramster_flnodes_max = ramster_flnodes;
+ inc_ramster_flnodes();
return flnode;
}
@@ -165,10 +97,8 @@ static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool)
static void ramster_flnode_free(struct flushlist_node *flnode,
struct tmem_pool *pool)
{
- int flnodes;
-
- flnodes = atomic_dec_return(&ramster_flnodes_atomic);
- BUG_ON(flnodes < 0);
+ dec_ramster_flnodes();
+ BUG_ON(ramster_flnodes < 0);
kmem_cache_free(ramster_flnode_cache, flnode);
}
@@ -191,6 +121,7 @@ int ramster_do_preload_flnode(struct tmem_pool *pool)
kmem_cache_free(ramster_flnode_cache, flnode);
return ret;
}
+EXPORT_SYMBOL_GPL(ramster_do_preload_flnode);
/*
* Called by the message handler after a (still compressed) page has been
@@ -226,9 +157,9 @@ int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
pr_err("UNTESTED pampd==NULL in ramster_localify\n");
#endif
if (eph)
- ramster_remote_eph_pages_unsucc_get++;
+ inc_ramster_remote_eph_pages_unsucc_get();
else
- ramster_remote_pers_pages_unsucc_get++;
+ inc_ramster_remote_pers_pages_unsucc_get();
obj = NULL;
goto finish;
} else if (unlikely(!pampd_is_remote(pampd))) {
@@ -237,9 +168,9 @@ int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
pr_err("UNTESTED dup while waiting in ramster_localify\n");
#endif
if (eph)
- ramster_remote_eph_pages_unsucc_get++;
+ inc_ramster_remote_eph_pages_unsucc_get();
else
- ramster_remote_pers_pages_unsucc_get++;
+ inc_ramster_remote_pers_pages_unsucc_get();
obj = NULL;
pampd = NULL;
ret = -EEXIST;
@@ -248,7 +179,7 @@ int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
/* no remote data, delete the local is_remote pampd */
pampd = NULL;
if (eph)
- ramster_remote_eph_pages_unsucc_get++;
+ inc_ramster_remote_eph_pages_unsucc_get();
else
BUG();
delete = true;
@@ -279,9 +210,9 @@ int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index,
BUG_ON(extra == NULL);
zcache_decompress_to_page(data, size, (struct page *)extra);
if (eph)
- ramster_remote_eph_pages_succ_get++;
+ inc_ramster_remote_eph_pages_succ_get();
else
- ramster_remote_pers_pages_succ_get++;
+ inc_ramster_remote_pers_pages_succ_get();
ret = 0;
finish:
tmem_localify_finish(obj, index, pampd, saved_hb, delete);
@@ -366,7 +297,7 @@ void *ramster_pampd_repatriate_preload(void *pampd, struct tmem_pool *pool,
c = atomic_dec_return(&ramster_remote_pers_pages);
WARN_ON_ONCE(c < 0);
} else {
- ramster_pers_pages_remote_nomem++;
+ inc_ramster_pers_pages_remote_nomem();
}
local_irq_restore(flags);
out:
@@ -458,37 +389,28 @@ void *ramster_pampd_free(void *pampd, struct tmem_pool *pool,
}
return local_pampd;
}
+EXPORT_SYMBOL_GPL(ramster_pampd_free);
void ramster_count_foreign_pages(bool eph, int count)
{
- int c;
-
BUG_ON(count != 1 && count != -1);
if (eph) {
if (count > 0) {
- c = atomic_inc_return(
- &ramster_foreign_eph_pages_atomic);
- if (c > ramster_foreign_eph_pages_max)
- ramster_foreign_eph_pages_max = c;
+ inc_ramster_foreign_eph_pages();
} else {
- c = atomic_dec_return(&ramster_foreign_eph_pages_atomic);
- WARN_ON_ONCE(c < 0);
+ dec_ramster_foreign_eph_pages();
+ WARN_ON_ONCE(ramster_foreign_eph_pages < 0);
}
- ramster_foreign_eph_pages = c;
} else {
if (count > 0) {
- c = atomic_inc_return(
- &ramster_foreign_pers_pages_atomic);
- if (c > ramster_foreign_pers_pages_max)
- ramster_foreign_pers_pages_max = c;
+ inc_ramster_foreign_pers_pages();
} else {
- c = atomic_dec_return(
- &ramster_foreign_pers_pages_atomic);
- WARN_ON_ONCE(c < 0);
+ dec_ramster_foreign_pers_pages();
+ WARN_ON_ONCE(ramster_foreign_pers_pages < 0);
}
- ramster_foreign_pers_pages = c;
}
}
+EXPORT_SYMBOL_GPL(ramster_count_foreign_pages);
/*
* For now, just push over a few pages every few seconds to
@@ -516,9 +438,9 @@ static void ramster_remote_flush_page(struct flushlist_node *flnode)
remotenode = flnode->xh.client_id;
ret = r2net_remote_flush(xh, remotenode);
if (ret >= 0)
- ramster_remote_pages_flushed++;
+ inc_ramster_remote_pages_flushed();
else
- ramster_remote_page_flushes_failed++;
+ inc_ramster_remote_page_flushes_failed();
preempt_enable_no_resched();
ramster_flnode_free(flnode, NULL);
}
@@ -533,9 +455,9 @@ static void ramster_remote_flush_object(struct flushlist_node *flnode)
remotenode = flnode->xh.client_id;
ret = r2net_remote_flush_object(xh, remotenode);
if (ret >= 0)
- ramster_remote_objects_flushed++;
+ inc_ramster_remote_objects_flushed();
else
- ramster_remote_object_flushes_failed++;
+ inc_ramster_remote_object_flushes_failed();
preempt_enable_no_resched();
ramster_flnode_free(flnode, NULL);
}
@@ -586,18 +508,18 @@ int ramster_remotify_pageframe(bool eph)
* But count them so we know if it becomes a problem.
*/
if (eph)
- ramster_eph_pages_remote_failed++;
+ inc_ramster_eph_pages_remote_failed();
else
- ramster_pers_pages_remote_failed++;
+ inc_ramster_pers_pages_remote_failed();
break;
} else {
if (!eph)
atomic_inc(&ramster_remote_pers_pages);
}
if (eph)
- ramster_eph_pages_remoted++;
+ inc_ramster_eph_pages_remoted();
else
- ramster_pers_pages_remoted++;
+ inc_ramster_pers_pages_remoted();
/*
* data was successfully remoted so change the local version to
* point to the remote node where it landed
@@ -674,7 +596,7 @@ requeue:
ramster_remotify_queue_delayed_work(HZ);
}
-void __init ramster_remotify_init(void)
+void ramster_remotify_init(void)
{
unsigned long n = 60UL;
ramster_remotify_workqueue =
@@ -849,8 +771,10 @@ static bool frontswap_selfshrinking __read_mostly;
static void selfshrink_process(struct work_struct *work);
static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process);
+#ifndef CONFIG_RAMSTER_MODULE
/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink __initdata = true;
+static bool use_frontswap_selfshrink = true;
+#endif
/*
* The default values for the following parameters were deemed reasonable
@@ -905,6 +829,7 @@ static void frontswap_selfshrink(void)
frontswap_shrink(tgt_frontswap_pages);
}
+#ifndef CONFIG_RAMSTER_MODULE
static int __init ramster_nofrontswap_selfshrink_setup(char *s)
{
use_frontswap_selfshrink = false;
@@ -912,6 +837,7 @@ static int __init ramster_nofrontswap_selfshrink_setup(char *s)
}
__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup);
+#endif
static void selfshrink_process(struct work_struct *work)
{
@@ -930,6 +856,7 @@ void ramster_cpu_up(int cpu)
per_cpu(ramster_remoteputmem1, cpu) = p1;
per_cpu(ramster_remoteputmem2, cpu) = p2;
}
+EXPORT_SYMBOL_GPL(ramster_cpu_up);
void ramster_cpu_down(int cpu)
{
@@ -945,6 +872,7 @@ void ramster_cpu_down(int cpu)
kp->flnode = NULL;
}
}
+EXPORT_SYMBOL_GPL(ramster_cpu_down);
void ramster_register_pamops(struct tmem_pamops *pamops)
{
@@ -955,9 +883,11 @@ void ramster_register_pamops(struct tmem_pamops *pamops)
pamops->repatriate = ramster_pampd_repatriate;
pamops->repatriate_preload = ramster_pampd_repatriate_preload;
}
+EXPORT_SYMBOL_GPL(ramster_register_pamops);
-void __init ramster_init(bool cleancache, bool frontswap,
- bool frontswap_exclusive_gets)
+void ramster_init(bool cleancache, bool frontswap,
+ bool frontswap_exclusive_gets,
+ bool frontswap_selfshrink)
{
int ret = 0;
@@ -972,10 +902,17 @@ void __init ramster_init(bool cleancache, bool frontswap,
if (ret)
pr_err("ramster: can't create sysfs for ramster\n");
(void)r2net_register_handlers();
+#ifdef CONFIG_RAMSTER_MODULE
+ ret = r2nm_init();
+ if (ret)
+ pr_err("ramster: can't init r2net\n");
+ frontswap_selfshrinking = frontswap_selfshrink;
+#else
+ frontswap_selfshrinking = use_frontswap_selfshrink;
+#endif
INIT_LIST_HEAD(&ramster_rem_op_list);
ramster_flnode_cache = kmem_cache_create("ramster_flnode",
sizeof(struct flushlist_node), 0, 0, NULL);
- frontswap_selfshrinking = use_frontswap_selfshrink;
if (frontswap_selfshrinking) {
pr_info("ramster: Initializing frontswap selfshrink driver.\n");
schedule_delayed_work(&selfshrink_worker,
@@ -983,3 +920,4 @@ void __init ramster_init(bool cleancache, bool frontswap,
}
ramster_remotify_init();
}
+EXPORT_SYMBOL_GPL(ramster_init);
diff --git a/drivers/staging/zcache/ramster/ramster.h b/drivers/staging/zcache/ramster/ramster.h
index 12ae56f09ca4..6d41a7a772e3 100644
--- a/drivers/staging/zcache/ramster/ramster.h
+++ b/drivers/staging/zcache/ramster/ramster.h
@@ -147,7 +147,7 @@ extern int r2net_register_handlers(void);
extern int r2net_remote_target_node_set(int);
extern int ramster_remotify_pageframe(bool);
-extern void ramster_init(bool, bool, bool);
+extern void ramster_init(bool, bool, bool, bool);
extern void ramster_register_pamops(struct tmem_pamops *);
extern int ramster_localify(int, struct tmem_oid *oidp, uint32_t, char *,
unsigned int, void *);
diff --git a/drivers/staging/zcache/ramster/ramster_nodemanager.h b/drivers/staging/zcache/ramster/ramster_nodemanager.h
index 49f879d943ab..dbaae34ea613 100644
--- a/drivers/staging/zcache/ramster/ramster_nodemanager.h
+++ b/drivers/staging/zcache/ramster/ramster_nodemanager.h
@@ -36,4 +36,6 @@
/* host name, group name, cluster name all 64 bytes */
#define R2NM_MAX_NAME_LEN 64 /* __NEW_UTS_LEN */
+extern int r2nm_init(void);
+
#endif /* _RAMSTER_NODEMANAGER_H */
diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c
index a2b7e03b6062..d7e51e4152eb 100644
--- a/drivers/staging/zcache/tmem.c
+++ b/drivers/staging/zcache/tmem.c
@@ -35,7 +35,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/atomic.h>
-#ifdef CONFIG_RAMSTER
+#include <linux/export.h>
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
#include <linux/delay.h>
#endif
@@ -641,6 +642,7 @@ void *tmem_localify_get_pampd(struct tmem_pool *pool, struct tmem_oid *oidp,
/* note, hashbucket remains locked */
return pampd;
}
+EXPORT_SYMBOL_GPL(tmem_localify_get_pampd);
void tmem_localify_finish(struct tmem_obj *obj, uint32_t index,
void *pampd, void *saved_hb, bool delete)
@@ -658,6 +660,7 @@ void tmem_localify_finish(struct tmem_obj *obj, uint32_t index,
}
spin_unlock(&hb->lock);
}
+EXPORT_SYMBOL_GPL(tmem_localify_finish);
/*
* For ramster only. Helper function to support asynchronous tmem_get.
@@ -719,6 +722,7 @@ out:
spin_unlock(&hb->lock);
return ret;
}
+EXPORT_SYMBOL_GPL(tmem_replace);
#endif
/*
diff --git a/drivers/staging/zcache/tmem.h b/drivers/staging/zcache/tmem.h
index adbe5a8f28aa..d128ce290f1f 100644
--- a/drivers/staging/zcache/tmem.h
+++ b/drivers/staging/zcache/tmem.h
@@ -126,7 +126,7 @@ static inline unsigned tmem_oid_hash(struct tmem_oid *oidp)
TMEM_HASH_BUCKET_BITS);
}
-#ifdef CONFIG_RAMSTER
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
struct tmem_xhandle {
uint8_t client_id;
uint8_t xh_data_cksum;
@@ -171,7 +171,7 @@ struct tmem_obj {
unsigned int objnode_tree_height;
unsigned long objnode_count;
long pampd_count;
-#ifdef CONFIG_RAMSTER
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
/*
* for current design of ramster, all pages belonging to
* an object reside on the same remotenode and extra is
@@ -215,7 +215,7 @@ struct tmem_pamops {
uint32_t);
void (*free)(void *, struct tmem_pool *,
struct tmem_oid *, uint32_t, bool);
-#ifdef CONFIG_RAMSTER
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
void (*new_obj)(struct tmem_obj *);
void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool);
void *(*repatriate_preload)(void *, struct tmem_pool *,
@@ -247,7 +247,7 @@ extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *,
extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *);
extern int tmem_destroy_pool(struct tmem_pool *);
extern void tmem_new_pool(struct tmem_pool *, uint32_t);
-#ifdef CONFIG_RAMSTER
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index,
void *);
extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *,
diff --git a/drivers/staging/zcache/zbud.c b/drivers/staging/zcache/zbud.c
index fdff5c6a0239..6cda4ed9ed31 100644
--- a/drivers/staging/zcache/zbud.c
+++ b/drivers/staging/zcache/zbud.c
@@ -342,6 +342,11 @@ static int zbud_debugfs_init(void)
}
#undef zdfs
#undef zdfs64
+#else
+static inline int zbud_debugfs_init(void)
+{
+ return 0;
+}
#endif
/* protects the buddied list and all unbuddied lists */
@@ -1051,9 +1056,7 @@ void zbud_init(void)
{
int i;
-#ifdef CONFIG_DEBUG_FS
zbud_debugfs_init();
-#endif
BUG_ON((sizeof(struct tmem_handle) * 2 > CHUNK_SIZE));
BUG_ON(sizeof(struct zbudpage) > sizeof(struct page));
for (i = 0; i < NCHUNKS; i++) {
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index 328898ea76c3..522cb8e55142 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
+#include <linux/string.h>
#include <linux/atomic.h>
#include <linux/math64.h>
#include <linux/crypto.h>
@@ -33,10 +34,13 @@
#include "zcache.h"
#include "zbud.h"
#include "ramster.h"
+#include "debug.h"
#ifdef CONFIG_RAMSTER
-static int ramster_enabled;
+static bool ramster_enabled __read_mostly;
+static int disable_frontswap_selfshrink;
#else
-#define ramster_enabled 0
+#define ramster_enabled false
+#define disable_frontswap_selfshrink 0
#endif
#ifndef __PG_WAS_ACTIVE
@@ -59,24 +63,32 @@ static inline void frontswap_tmem_exclusive_gets(bool b)
}
#endif
+/*
+ * mark pampd to special value in order that later
+ * retrieve will identify zero-filled pages
+ */
+#define ZERO_FILLED 0x2
+
/* enable (or fix code) when Seth's patches are accepted upstream */
#define zcache_writeback_enabled 0
-static int zcache_enabled __read_mostly;
-static int disable_cleancache __read_mostly;
-static int disable_frontswap __read_mostly;
-static int disable_frontswap_ignore_nonactive __read_mostly;
-static int disable_cleancache_ignore_nonactive __read_mostly;
+static bool zcache_enabled __read_mostly;
+static bool disable_cleancache __read_mostly;
+static bool disable_frontswap __read_mostly;
+static bool disable_frontswap_ignore_nonactive __read_mostly;
+static bool disable_cleancache_ignore_nonactive __read_mostly;
static char *namestr __read_mostly = "zcache";
#define ZCACHE_GFP_MASK \
(__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC)
-MODULE_LICENSE("GPL");
-
/* crypto API for zcache */
+#ifdef CONFIG_ZCACHE_MODULE
+static char *zcache_comp_name = "lzo";
+#else
#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
static char zcache_comp_name[ZCACHE_COMP_NAME_SZ] __read_mostly;
+#endif
static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms __read_mostly;
enum comp_op {
@@ -134,196 +146,21 @@ static struct kmem_cache *zcache_obj_cache;
static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, };
-/* we try to keep these statistics SMP-consistent */
-static ssize_t zcache_obj_count;
-static atomic_t zcache_obj_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_obj_count_max;
-static ssize_t zcache_objnode_count;
-static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_objnode_count_max;
-static u64 zcache_eph_zbytes;
-static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0);
-static u64 zcache_eph_zbytes_max;
-static u64 zcache_pers_zbytes;
-static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0);
-static u64 zcache_pers_zbytes_max;
-static ssize_t zcache_eph_pageframes;
-static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_eph_pageframes_max;
-static ssize_t zcache_pers_pageframes;
-static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_pers_pageframes_max;
-static ssize_t zcache_pageframes_alloced;
-static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_pageframes_freed;
-static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_eph_zpages;
-static ssize_t zcache_eph_zpages;
-static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_eph_zpages_max;
-static ssize_t zcache_pers_zpages;
-static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0);
-static ssize_t zcache_pers_zpages_max;
-
-/* but for the rest of these, counting races are ok */
-static ssize_t zcache_flush_total;
-static ssize_t zcache_flush_found;
-static ssize_t zcache_flobj_total;
-static ssize_t zcache_flobj_found;
-static ssize_t zcache_failed_eph_puts;
-static ssize_t zcache_failed_pers_puts;
-static ssize_t zcache_failed_getfreepages;
-static ssize_t zcache_failed_alloc;
-static ssize_t zcache_put_to_flush;
-static ssize_t zcache_compress_poor;
-static ssize_t zcache_mean_compress_poor;
-static ssize_t zcache_eph_ate_tail;
-static ssize_t zcache_eph_ate_tail_failed;
-static ssize_t zcache_pers_ate_eph;
-static ssize_t zcache_pers_ate_eph_failed;
-static ssize_t zcache_evicted_eph_zpages;
-static ssize_t zcache_evicted_eph_pageframes;
-static ssize_t zcache_last_active_file_pageframes;
-static ssize_t zcache_last_inactive_file_pageframes;
-static ssize_t zcache_last_active_anon_pageframes;
-static ssize_t zcache_last_inactive_anon_pageframes;
-static ssize_t zcache_eph_nonactive_puts_ignored;
-static ssize_t zcache_pers_nonactive_puts_ignored;
-static ssize_t zcache_writtenback_pages;
-static ssize_t zcache_outstanding_writeback_pages;
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#define zdfs debugfs_create_size_t
-#define zdfs64 debugfs_create_u64
-static int zcache_debugfs_init(void)
-{
- struct dentry *root = debugfs_create_dir("zcache", NULL);
- if (root == NULL)
- return -ENXIO;
-
- zdfs("obj_count", S_IRUGO, root, &zcache_obj_count);
- zdfs("obj_count_max", S_IRUGO, root, &zcache_obj_count_max);
- zdfs("objnode_count", S_IRUGO, root, &zcache_objnode_count);
- zdfs("objnode_count_max", S_IRUGO, root, &zcache_objnode_count_max);
- zdfs("flush_total", S_IRUGO, root, &zcache_flush_total);
- zdfs("flush_found", S_IRUGO, root, &zcache_flush_found);
- zdfs("flobj_total", S_IRUGO, root, &zcache_flobj_total);
- zdfs("flobj_found", S_IRUGO, root, &zcache_flobj_found);
- zdfs("failed_eph_puts", S_IRUGO, root, &zcache_failed_eph_puts);
- zdfs("failed_pers_puts", S_IRUGO, root, &zcache_failed_pers_puts);
- zdfs("failed_get_free_pages", S_IRUGO, root,
- &zcache_failed_getfreepages);
- zdfs("failed_alloc", S_IRUGO, root, &zcache_failed_alloc);
- zdfs("put_to_flush", S_IRUGO, root, &zcache_put_to_flush);
- zdfs("compress_poor", S_IRUGO, root, &zcache_compress_poor);
- zdfs("mean_compress_poor", S_IRUGO, root, &zcache_mean_compress_poor);
- zdfs("eph_ate_tail", S_IRUGO, root, &zcache_eph_ate_tail);
- zdfs("eph_ate_tail_failed", S_IRUGO, root, &zcache_eph_ate_tail_failed);
- zdfs("pers_ate_eph", S_IRUGO, root, &zcache_pers_ate_eph);
- zdfs("pers_ate_eph_failed", S_IRUGO, root, &zcache_pers_ate_eph_failed);
- zdfs("evicted_eph_zpages", S_IRUGO, root, &zcache_evicted_eph_zpages);
- zdfs("evicted_eph_pageframes", S_IRUGO, root,
- &zcache_evicted_eph_pageframes);
- zdfs("eph_pageframes", S_IRUGO, root, &zcache_eph_pageframes);
- zdfs("eph_pageframes_max", S_IRUGO, root, &zcache_eph_pageframes_max);
- zdfs("pers_pageframes", S_IRUGO, root, &zcache_pers_pageframes);
- zdfs("pers_pageframes_max", S_IRUGO, root, &zcache_pers_pageframes_max);
- zdfs("eph_zpages", S_IRUGO, root, &zcache_eph_zpages);
- zdfs("eph_zpages_max", S_IRUGO, root, &zcache_eph_zpages_max);
- zdfs("pers_zpages", S_IRUGO, root, &zcache_pers_zpages);
- zdfs("pers_zpages_max", S_IRUGO, root, &zcache_pers_zpages_max);
- zdfs("last_active_file_pageframes", S_IRUGO, root,
- &zcache_last_active_file_pageframes);
- zdfs("last_inactive_file_pageframes", S_IRUGO, root,
- &zcache_last_inactive_file_pageframes);
- zdfs("last_active_anon_pageframes", S_IRUGO, root,
- &zcache_last_active_anon_pageframes);
- zdfs("last_inactive_anon_pageframes", S_IRUGO, root,
- &zcache_last_inactive_anon_pageframes);
- zdfs("eph_nonactive_puts_ignored", S_IRUGO, root,
- &zcache_eph_nonactive_puts_ignored);
- zdfs("pers_nonactive_puts_ignored", S_IRUGO, root,
- &zcache_pers_nonactive_puts_ignored);
- zdfs64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes);
- zdfs64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max);
- zdfs64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes);
- zdfs64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max);
- zdfs("outstanding_writeback_pages", S_IRUGO, root,
- &zcache_outstanding_writeback_pages);
- zdfs("writtenback_pages", S_IRUGO, root, &zcache_writtenback_pages);
- return 0;
-}
-#undef zdebugfs
-#undef zdfs64
-#endif
-
-#define ZCACHE_DEBUG
-#ifdef ZCACHE_DEBUG
-/* developers can call this in case of ooms, e.g. to find memory leaks */
-void zcache_dump(void)
-{
- pr_info("zcache: obj_count=%zd\n", zcache_obj_count);
- pr_info("zcache: obj_count_max=%zd\n", zcache_obj_count_max);
- pr_info("zcache: objnode_count=%zd\n", zcache_objnode_count);
- pr_info("zcache: objnode_count_max=%zd\n", zcache_objnode_count_max);
- pr_info("zcache: flush_total=%zd\n", zcache_flush_total);
- pr_info("zcache: flush_found=%zd\n", zcache_flush_found);
- pr_info("zcache: flobj_total=%zd\n", zcache_flobj_total);
- pr_info("zcache: flobj_found=%zd\n", zcache_flobj_found);
- pr_info("zcache: failed_eph_puts=%zd\n", zcache_failed_eph_puts);
- pr_info("zcache: failed_pers_puts=%zd\n", zcache_failed_pers_puts);
- pr_info("zcache: failed_get_free_pages=%zd\n",
- zcache_failed_getfreepages);
- pr_info("zcache: failed_alloc=%zd\n", zcache_failed_alloc);
- pr_info("zcache: put_to_flush=%zd\n", zcache_put_to_flush);
- pr_info("zcache: compress_poor=%zd\n", zcache_compress_poor);
- pr_info("zcache: mean_compress_poor=%zd\n",
- zcache_mean_compress_poor);
- pr_info("zcache: eph_ate_tail=%zd\n", zcache_eph_ate_tail);
- pr_info("zcache: eph_ate_tail_failed=%zd\n",
- zcache_eph_ate_tail_failed);
- pr_info("zcache: pers_ate_eph=%zd\n", zcache_pers_ate_eph);
- pr_info("zcache: pers_ate_eph_failed=%zd\n",
- zcache_pers_ate_eph_failed);
- pr_info("zcache: evicted_eph_zpages=%zd\n", zcache_evicted_eph_zpages);
- pr_info("zcache: evicted_eph_pageframes=%zd\n",
- zcache_evicted_eph_pageframes);
- pr_info("zcache: eph_pageframes=%zd\n", zcache_eph_pageframes);
- pr_info("zcache: eph_pageframes_max=%zd\n", zcache_eph_pageframes_max);
- pr_info("zcache: pers_pageframes=%zd\n", zcache_pers_pageframes);
- pr_info("zcache: pers_pageframes_max=%zd\n",
- zcache_pers_pageframes_max);
- pr_info("zcache: eph_zpages=%zd\n", zcache_eph_zpages);
- pr_info("zcache: eph_zpages_max=%zd\n", zcache_eph_zpages_max);
- pr_info("zcache: pers_zpages=%zd\n", zcache_pers_zpages);
- pr_info("zcache: pers_zpages_max=%zd\n", zcache_pers_zpages_max);
- pr_info("zcache: last_active_file_pageframes=%zd\n",
- zcache_last_active_file_pageframes);
- pr_info("zcache: last_inactive_file_pageframes=%zd\n",
- zcache_last_inactive_file_pageframes);
- pr_info("zcache: last_active_anon_pageframes=%zd\n",
- zcache_last_active_anon_pageframes);
- pr_info("zcache: last_inactive_anon_pageframes=%zd\n",
- zcache_last_inactive_anon_pageframes);
- pr_info("zcache: eph_nonactive_puts_ignored=%zd\n",
- zcache_eph_nonactive_puts_ignored);
- pr_info("zcache: pers_nonactive_puts_ignored=%zd\n",
- zcache_pers_nonactive_puts_ignored);
- pr_info("zcache: eph_zbytes=%llu\n",
- zcache_eph_zbytes);
- pr_info("zcache: eph_zbytes_max=%llu\n",
- zcache_eph_zbytes_max);
- pr_info("zcache: pers_zbytes=%llu\n",
- zcache_pers_zbytes);
- pr_info("zcache: pers_zbytes_max=%llu\n",
- zcache_pers_zbytes_max);
- pr_info("zcache: outstanding_writeback_pages=%zd\n",
- zcache_outstanding_writeback_pages);
- pr_info("zcache: writtenback_pages=%zd\n", zcache_writtenback_pages);
-}
+/* Used by debug.c */
+ssize_t zcache_pers_zpages;
+u64 zcache_pers_zbytes;
+ssize_t zcache_eph_pageframes;
+ssize_t zcache_pers_pageframes;
+
+/* Used by this code. */
+ssize_t zcache_last_active_file_pageframes;
+ssize_t zcache_last_inactive_file_pageframes;
+ssize_t zcache_last_active_anon_pageframes;
+ssize_t zcache_last_inactive_anon_pageframes;
+#ifdef CONFIG_ZCACHE_WRITEBACK
+ssize_t zcache_writtenback_pages;
+ssize_t zcache_outstanding_writeback_pages;
#endif
-
/*
* zcache core code starts here
*/
@@ -422,18 +259,14 @@ static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool)
}
}
BUG_ON(objnode == NULL);
- zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic);
- if (zcache_objnode_count > zcache_objnode_count_max)
- zcache_objnode_count_max = zcache_objnode_count;
+ inc_zcache_objnode_count();
return objnode;
}
static void zcache_objnode_free(struct tmem_objnode *objnode,
struct tmem_pool *pool)
{
- zcache_objnode_count =
- atomic_dec_return(&zcache_objnode_atomic);
- BUG_ON(zcache_objnode_count < 0);
+ dec_zcache_objnode_count();
kmem_cache_free(zcache_objnode_cache, objnode);
}
@@ -446,20 +279,49 @@ static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool)
obj = kp->obj;
BUG_ON(obj == NULL);
kp->obj = NULL;
- zcache_obj_count = atomic_inc_return(&zcache_obj_atomic);
- if (zcache_obj_count > zcache_obj_count_max)
- zcache_obj_count_max = zcache_obj_count;
+ inc_zcache_obj_count();
return obj;
}
static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool)
{
- zcache_obj_count =
- atomic_dec_return(&zcache_obj_atomic);
- BUG_ON(zcache_obj_count < 0);
+ dec_zcache_obj_count();
kmem_cache_free(zcache_obj_cache, obj);
}
+/*
+ * Compressing zero-filled pages will waste memory and introduce
+ * serious fragmentation, skip it to avoid overhead.
+ */
+static bool page_is_zero_filled(struct page *p)
+{
+ unsigned int pos;
+ char *page;
+
+ page = kmap_atomic(p);
+ for (pos = 0; pos < PAGE_SIZE / sizeof(*page); pos++) {
+ if (page[pos]) {
+ kunmap_atomic(page);
+ return false;
+ }
+ }
+ kunmap_atomic(page);
+
+ return true;
+}
+
+static void handle_zero_filled_page(void *p)
+{
+ void *user_mem;
+ struct page *page = (struct page *)p;
+
+ user_mem = kmap_atomic(page);
+ memset(user_mem, 0, PAGE_SIZE);
+ kunmap_atomic(user_mem);
+
+ flush_dcache_page(page);
+}
+
static struct tmem_hostops zcache_hostops = {
.obj_alloc = zcache_obj_alloc,
.obj_free = zcache_obj_free,
@@ -472,8 +334,7 @@ static struct page *zcache_alloc_page(void)
struct page *page = alloc_page(ZCACHE_GFP_MASK);
if (page != NULL)
- zcache_pageframes_alloced =
- atomic_inc_return(&zcache_pageframes_alloced_atomic);
+ inc_zcache_pageframes_alloced();
return page;
}
@@ -485,17 +346,13 @@ static void zcache_free_page(struct page *page)
if (page == NULL)
BUG();
__free_page(page);
- zcache_pageframes_freed =
- atomic_inc_return(&zcache_pageframes_freed_atomic);
- curr_pageframes = zcache_pageframes_alloced -
- atomic_read(&zcache_pageframes_freed_atomic) -
- atomic_read(&zcache_eph_pageframes_atomic) -
- atomic_read(&zcache_pers_pageframes_atomic);
+ inc_zcache_pageframes_freed();
+ curr_pageframes = curr_pageframes_count();
if (curr_pageframes > max_pageframes)
max_pageframes = curr_pageframes;
if (curr_pageframes < min_pageframes)
min_pageframes = curr_pageframes;
-#ifdef ZCACHE_DEBUG
+#ifdef CONFIG_ZCACHE_DEBUG
if (curr_pageframes > 2L || curr_pageframes < -2L) {
/* pr_info here */
}
@@ -517,12 +374,20 @@ static void *zcache_pampd_eph_create(char *data, size_t size, bool raw,
{
void *pampd = NULL, *cdata = data;
unsigned clen = size;
+ bool zero_filled = false;
struct page *page = (struct page *)(data), *newpage;
+ if (page_is_zero_filled(page)) {
+ clen = 0;
+ zero_filled = true;
+ inc_zcache_zero_filled_pages();
+ goto got_pampd;
+ }
+
if (!raw) {
zcache_compress(page, &cdata, &clen);
if (clen > zbud_max_buddy_size()) {
- zcache_compress_poor++;
+ inc_zcache_compress_poor();
goto out;
}
} else {
@@ -539,33 +404,27 @@ static void *zcache_pampd_eph_create(char *data, size_t size, bool raw,
if (newpage != NULL)
goto create_in_new_page;
- zcache_failed_getfreepages++;
+ inc_zcache_failed_getfreepages();
/* can't allocate a page, evict an ephemeral page via LRU */
newpage = zcache_evict_eph_pageframe();
if (newpage == NULL) {
- zcache_eph_ate_tail_failed++;
+ inc_zcache_eph_ate_tail_failed();
goto out;
}
- zcache_eph_ate_tail++;
+ inc_zcache_eph_ate_tail();
create_in_new_page:
pampd = (void *)zbud_create_prep(th, true, cdata, clen, newpage);
BUG_ON(pampd == NULL);
- zcache_eph_pageframes =
- atomic_inc_return(&zcache_eph_pageframes_atomic);
- if (zcache_eph_pageframes > zcache_eph_pageframes_max)
- zcache_eph_pageframes_max = zcache_eph_pageframes;
+ inc_zcache_eph_pageframes();
got_pampd:
- zcache_eph_zbytes =
- atomic_long_add_return(clen, &zcache_eph_zbytes_atomic);
- if (zcache_eph_zbytes > zcache_eph_zbytes_max)
- zcache_eph_zbytes_max = zcache_eph_zbytes;
- zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic);
- if (zcache_eph_zpages > zcache_eph_zpages_max)
- zcache_eph_zpages_max = zcache_eph_zpages;
- if (ramster_enabled && raw)
+ inc_zcache_eph_zbytes(clen);
+ inc_zcache_eph_zpages();
+ if (ramster_enabled && raw && !zero_filled)
ramster_count_foreign_pages(true, 1);
+ if (zero_filled)
+ pampd = (void *)ZERO_FILLED;
out:
return pampd;
}
@@ -575,6 +434,7 @@ static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
{
void *pampd = NULL, *cdata = data;
unsigned clen = size;
+ bool zero_filled = false;
struct page *page = (struct page *)(data), *newpage;
unsigned long zbud_mean_zsize;
unsigned long curr_pers_zpages, total_zsize;
@@ -583,13 +443,21 @@ static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
BUG_ON(!ramster_enabled);
goto create_pampd;
}
+
+ if (page_is_zero_filled(page)) {
+ clen = 0;
+ zero_filled = true;
+ inc_zcache_zero_filled_pages();
+ goto got_pampd;
+ }
+
curr_pers_zpages = zcache_pers_zpages;
/* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */
if (!raw)
zcache_compress(page, &cdata, &clen);
/* reject if compression is too poor */
if (clen > zbud_max_zsize) {
- zcache_compress_poor++;
+ inc_zcache_compress_poor();
goto out;
}
/* reject if mean compression is too poor */
@@ -600,7 +468,7 @@ static void *zcache_pampd_pers_create(char *data, size_t size, bool raw,
zbud_mean_zsize = div_u64(total_zsize,
curr_pers_zpages);
if (zbud_mean_zsize > zbud_max_mean_zsize) {
- zcache_mean_compress_poor++;
+ inc_zcache_mean_compress_poor();
goto out;
}
}
@@ -621,33 +489,27 @@ create_pampd:
* (global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE) +
* global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE)))
*/
- zcache_failed_getfreepages++;
+ inc_zcache_failed_getfreepages();
/* can't allocate a page, evict an ephemeral page via LRU */
newpage = zcache_evict_eph_pageframe();
if (newpage == NULL) {
- zcache_pers_ate_eph_failed++;
+ inc_zcache_pers_ate_eph_failed();
goto out;
}
- zcache_pers_ate_eph++;
+ inc_zcache_pers_ate_eph();
create_in_new_page:
pampd = (void *)zbud_create_prep(th, false, cdata, clen, newpage);
BUG_ON(pampd == NULL);
- zcache_pers_pageframes =
- atomic_inc_return(&zcache_pers_pageframes_atomic);
- if (zcache_pers_pageframes > zcache_pers_pageframes_max)
- zcache_pers_pageframes_max = zcache_pers_pageframes;
+ inc_zcache_pers_pageframes();
got_pampd:
- zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic);
- if (zcache_pers_zpages > zcache_pers_zpages_max)
- zcache_pers_zpages_max = zcache_pers_zpages;
- zcache_pers_zbytes =
- atomic_long_add_return(clen, &zcache_pers_zbytes_atomic);
- if (zcache_pers_zbytes > zcache_pers_zbytes_max)
- zcache_pers_zbytes_max = zcache_pers_zbytes;
- if (ramster_enabled && raw)
+ inc_zcache_pers_zpages();
+ inc_zcache_pers_zbytes(clen);
+ if (ramster_enabled && raw && !zero_filled)
ramster_count_foreign_pages(false, 1);
+ if (zero_filled)
+ pampd = (void *)ZERO_FILLED;
out:
return pampd;
}
@@ -676,7 +538,7 @@ void *zcache_pampd_create(char *data, unsigned int size, bool raw,
objnode = kmem_cache_alloc(zcache_objnode_cache,
ZCACHE_GFP_MASK);
if (unlikely(objnode == NULL)) {
- zcache_failed_alloc++;
+ inc_zcache_failed_alloc();
goto out;
}
kp->objnodes[i] = objnode;
@@ -687,7 +549,7 @@ void *zcache_pampd_create(char *data, unsigned int size, bool raw,
kp->obj = obj;
}
if (unlikely(kp->obj == NULL)) {
- zcache_failed_alloc++;
+ inc_zcache_failed_alloc();
goto out;
}
/*
@@ -709,7 +571,8 @@ out:
*/
void zcache_pampd_create_finish(void *pampd, bool eph)
{
- zbud_create_finish((struct zbudref *)pampd, eph);
+ if (pampd != (void *)ZERO_FILLED)
+ zbud_create_finish((struct zbudref *)pampd, eph);
}
/*
@@ -754,6 +617,14 @@ static int zcache_pampd_get_data(char *data, size_t *sizep, bool raw,
BUG_ON(preemptible());
BUG_ON(eph); /* fix later if shared pools get implemented */
BUG_ON(pampd_is_remote(pampd));
+
+ if (pampd == (void *)ZERO_FILLED) {
+ handle_zero_filled_page(data);
+ if (!raw)
+ *sizep = PAGE_SIZE;
+ return 0;
+ }
+
if (raw)
ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
sizep, eph);
@@ -774,13 +645,25 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw,
void *pampd, struct tmem_pool *pool,
struct tmem_oid *oid, uint32_t index)
{
- int ret;
- bool eph = !is_persistent(pool);
+ int ret = 0;
+ bool eph = !is_persistent(pool), zero_filled = false;
struct page *page = NULL;
unsigned int zsize, zpages;
BUG_ON(preemptible());
BUG_ON(pampd_is_remote(pampd));
+
+ if (pampd == (void *)ZERO_FILLED) {
+ handle_zero_filled_page(data);
+ zero_filled = true;
+ zsize = 0;
+ zpages = 1;
+ if (!raw)
+ *sizep = PAGE_SIZE;
+ dec_zcache_zero_filled_pages();
+ goto zero_fill;
+ }
+
if (raw)
ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
sizep, eph);
@@ -792,26 +675,21 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw,
}
page = zbud_free_and_delist((struct zbudref *)pampd, eph,
&zsize, &zpages);
+zero_fill:
if (eph) {
if (page)
- zcache_eph_pageframes =
- atomic_dec_return(&zcache_eph_pageframes_atomic);
- zcache_eph_zpages =
- atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
- zcache_eph_zbytes =
- atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
+ dec_zcache_eph_pageframes();
+ dec_zcache_eph_zpages(zpages);
+ dec_zcache_eph_zbytes(zsize);
} else {
if (page)
- zcache_pers_pageframes =
- atomic_dec_return(&zcache_pers_pageframes_atomic);
- zcache_pers_zpages =
- atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
- zcache_pers_zbytes =
- atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
+ dec_zcache_pers_pageframes();
+ dec_zcache_pers_zpages(zpages);
+ dec_zcache_pers_zbytes(zsize);
}
- if (!is_local_client(pool->client))
+ if (!is_local_client(pool->client) && !zero_filled)
ramster_count_foreign_pages(eph, -1);
- if (page)
+ if (page && !zero_filled)
zcache_free_page(page);
return ret;
}
@@ -825,39 +703,44 @@ static void zcache_pampd_free(void *pampd, struct tmem_pool *pool,
{
struct page *page = NULL;
unsigned int zsize, zpages;
+ bool zero_filled = false;
BUG_ON(preemptible());
- if (pampd_is_remote(pampd)) {
+
+ if (pampd == (void *)ZERO_FILLED) {
+ zero_filled = true;
+ zsize = 0;
+ zpages = 1;
+ dec_zcache_zero_filled_pages();
+ }
+
+ if (pampd_is_remote(pampd) && !zero_filled) {
BUG_ON(!ramster_enabled);
pampd = ramster_pampd_free(pampd, pool, oid, index, acct);
if (pampd == NULL)
return;
}
if (is_ephemeral(pool)) {
- page = zbud_free_and_delist((struct zbudref *)pampd,
+ if (!zero_filled)
+ page = zbud_free_and_delist((struct zbudref *)pampd,
true, &zsize, &zpages);
if (page)
- zcache_eph_pageframes =
- atomic_dec_return(&zcache_eph_pageframes_atomic);
- zcache_eph_zpages =
- atomic_sub_return(zpages, &zcache_eph_zpages_atomic);
- zcache_eph_zbytes =
- atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic);
+ dec_zcache_eph_pageframes();
+ dec_zcache_eph_zpages(zpages);
+ dec_zcache_eph_zbytes(zsize);
/* FIXME CONFIG_RAMSTER... check acct parameter? */
} else {
- page = zbud_free_and_delist((struct zbudref *)pampd,
+ if (!zero_filled)
+ page = zbud_free_and_delist((struct zbudref *)pampd,
false, &zsize, &zpages);
if (page)
- zcache_pers_pageframes =
- atomic_dec_return(&zcache_pers_pageframes_atomic);
- zcache_pers_zpages =
- atomic_sub_return(zpages, &zcache_pers_zpages_atomic);
- zcache_pers_zbytes =
- atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic);
+ dec_zcache_pers_pageframes();
+ dec_zcache_pers_zpages(zpages);
+ dec_zcache_pers_zbytes(zsize);
}
- if (!is_local_client(pool->client))
+ if (!is_local_client(pool->client) && !zero_filled)
ramster_count_foreign_pages(is_ephemeral(pool), -1);
- if (page)
+ if (page && !zero_filled)
zcache_free_page(page);
}
@@ -975,14 +858,11 @@ static struct page *zcache_evict_eph_pageframe(void)
page = zbud_evict_pageframe_lru(&zsize, &zpages);
if (page == NULL)
goto out;
- zcache_eph_zbytes = atomic_long_sub_return(zsize,
- &zcache_eph_zbytes_atomic);
- zcache_eph_zpages = atomic_sub_return(zpages,
- &zcache_eph_zpages_atomic);
- zcache_evicted_eph_zpages += zpages;
- zcache_eph_pageframes =
- atomic_dec_return(&zcache_eph_pageframes_atomic);
- zcache_evicted_eph_pageframes++;
+ dec_zcache_eph_zbytes(zsize);
+ dec_zcache_eph_zpages(zpages);
+ inc_zcache_evicted_eph_zpages(zpages);
+ dec_zcache_eph_pageframes();
+ inc_zcache_evicted_eph_pageframes();
out:
return page;
}
@@ -991,6 +871,16 @@ out:
static atomic_t zcache_outstanding_writeback_pages_atomic = ATOMIC_INIT(0);
+static inline void inc_zcache_outstanding_writeback_pages(void)
+{
+ zcache_outstanding_writeback_pages =
+ atomic_inc_return(&zcache_outstanding_writeback_pages_atomic);
+}
+static inline void dec_zcache_outstanding_writeback_pages(void)
+{
+ zcache_outstanding_writeback_pages =
+ atomic_dec_return(&zcache_outstanding_writeback_pages_atomic);
+};
static void unswiz(struct tmem_oid oid, u32 index,
unsigned *type, pgoff_t *offset);
@@ -1004,8 +894,7 @@ static void unswiz(struct tmem_oid oid, u32 index,
static void zcache_end_swap_write(struct bio *bio, int err)
{
end_swap_bio_write(bio, err);
- zcache_outstanding_writeback_pages =
- atomic_dec_return(&zcache_outstanding_writeback_pages_atomic);
+ dec_zcache_outstanding_writeback_pages();
zcache_writtenback_pages++;
}
@@ -1120,8 +1009,7 @@ static int zcache_frontswap_writeback_zpage(int type, pgoff_t offset,
*/
(void)__swap_writepage(page, &wbc, zcache_end_swap_write);
page_cache_release(page);
- zcache_outstanding_writeback_pages =
- atomic_inc_return(&zcache_outstanding_writeback_pages_atomic);
+ inc_zcache_outstanding_writeback_pages();
return 0;
}
@@ -1357,9 +1245,9 @@ int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
if (pampd == NULL) {
ret = -ENOMEM;
if (ephemeral)
- zcache_failed_eph_puts++;
+ inc_zcache_failed_eph_puts();
else
- zcache_failed_pers_puts++;
+ inc_zcache_failed_pers_puts();
} else {
if (ramster_enabled)
ramster_do_preload_flnode(pool);
@@ -1369,7 +1257,7 @@ int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp,
}
zcache_put_pool(pool);
} else {
- zcache_put_to_flush++;
+ inc_zcache_put_to_flush();
if (ramster_enabled)
ramster_do_preload_flnode(pool);
if (atomic_read(&pool->obj_count) > 0)
@@ -1419,7 +1307,7 @@ int zcache_flush_page(int cli_id, int pool_id,
unsigned long flags;
local_irq_save(flags);
- zcache_flush_total++;
+ inc_zcache_flush_total();
pool = zcache_get_pool_by_id(cli_id, pool_id);
if (ramster_enabled)
ramster_do_preload_flnode(pool);
@@ -1429,7 +1317,7 @@ int zcache_flush_page(int cli_id, int pool_id,
zcache_put_pool(pool);
}
if (ret >= 0)
- zcache_flush_found++;
+ inc_zcache_flush_found();
local_irq_restore(flags);
return ret;
}
@@ -1442,7 +1330,7 @@ int zcache_flush_object(int cli_id, int pool_id,
unsigned long flags;
local_irq_save(flags);
- zcache_flobj_total++;
+ inc_zcache_flobj_total();
pool = zcache_get_pool_by_id(cli_id, pool_id);
if (ramster_enabled)
ramster_do_preload_flnode(pool);
@@ -1452,7 +1340,7 @@ int zcache_flush_object(int cli_id, int pool_id,
zcache_put_pool(pool);
}
if (ret >= 0)
- zcache_flobj_found++;
+ inc_zcache_flobj_found();
local_irq_restore(flags);
return ret;
}
@@ -1546,7 +1434,7 @@ static int zcache_local_new_pool(uint32_t flags)
int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph)
{
struct tmem_pool *pool;
- struct zcache_client *cli;
+ struct zcache_client *cli = NULL;
uint32_t flags = eph ? 0 : TMEM_POOL_PERSIST;
int ret = -1;
@@ -1615,7 +1503,7 @@ static void zcache_cleancache_put_page(int pool_id,
struct tmem_oid oid = *(struct tmem_oid *)&key;
if (!disable_cleancache_ignore_nonactive && !PageWasActive(page)) {
- zcache_eph_nonactive_puts_ignored++;
+ inc_zcache_eph_nonactive_puts_ignored();
return;
}
if (likely(ind == index))
@@ -1694,9 +1582,9 @@ static struct cleancache_ops zcache_cleancache_ops = {
.init_fs = zcache_cleancache_init_fs
};
-struct cleancache_ops zcache_cleancache_register_ops(void)
+struct cleancache_ops *zcache_cleancache_register_ops(void)
{
- struct cleancache_ops old_ops =
+ struct cleancache_ops *old_ops =
cleancache_register_ops(&zcache_cleancache_ops);
return old_ops;
@@ -1744,7 +1632,7 @@ static int zcache_frontswap_put_page(unsigned type, pgoff_t offset,
BUG_ON(!PageLocked(page));
if (!disable_frontswap_ignore_nonactive && !PageWasActive(page)) {
- zcache_pers_nonactive_puts_ignored++;
+ inc_zcache_pers_nonactive_puts_ignored();
ret = -ERANGE;
goto out;
}
@@ -1825,9 +1713,9 @@ static struct frontswap_ops zcache_frontswap_ops = {
.init = zcache_frontswap_init
};
-struct frontswap_ops zcache_frontswap_register_ops(void)
+struct frontswap_ops *zcache_frontswap_register_ops(void)
{
- struct frontswap_ops old_ops =
+ struct frontswap_ops *old_ops =
frontswap_register_ops(&zcache_frontswap_ops);
return old_ops;
@@ -1839,18 +1727,19 @@ struct frontswap_ops zcache_frontswap_register_ops(void)
* OR NOTHING HAPPENS!
*/
+#ifndef CONFIG_ZCACHE_MODULE
static int __init enable_zcache(char *s)
{
- zcache_enabled = 1;
+ zcache_enabled = true;
return 1;
}
__setup("zcache", enable_zcache);
static int __init enable_ramster(char *s)
{
- zcache_enabled = 1;
+ zcache_enabled = true;
#ifdef CONFIG_RAMSTER
- ramster_enabled = 1;
+ ramster_enabled = true;
#endif
return 1;
}
@@ -1860,7 +1749,7 @@ __setup("ramster", enable_ramster);
static int __init no_cleancache(char *s)
{
- disable_cleancache = 1;
+ disable_cleancache = true;
return 1;
}
@@ -1868,7 +1757,7 @@ __setup("nocleancache", no_cleancache);
static int __init no_frontswap(char *s)
{
- disable_frontswap = 1;
+ disable_frontswap = true;
return 1;
}
@@ -1884,7 +1773,7 @@ __setup("nofrontswapexclusivegets", no_frontswap_exclusive_gets);
static int __init no_frontswap_ignore_nonactive(char *s)
{
- disable_frontswap_ignore_nonactive = 1;
+ disable_frontswap_ignore_nonactive = true;
return 1;
}
@@ -1892,7 +1781,7 @@ __setup("nofrontswapignorenonactive", no_frontswap_ignore_nonactive);
static int __init no_cleancache_ignore_nonactive(char *s)
{
- disable_cleancache_ignore_nonactive = 1;
+ disable_cleancache_ignore_nonactive = true;
return 1;
}
@@ -1900,23 +1789,32 @@ __setup("nocleancacheignorenonactive", no_cleancache_ignore_nonactive);
static int __init enable_zcache_compressor(char *s)
{
- strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ);
- zcache_enabled = 1;
+ strlcpy(zcache_comp_name, s, sizeof(zcache_comp_name));
+ zcache_enabled = true;
return 1;
}
__setup("zcache=", enable_zcache_compressor);
+#endif
-static int __init zcache_comp_init(void)
+static int zcache_comp_init(void)
{
int ret = 0;
/* check crypto algorithm */
+#ifdef CONFIG_ZCACHE_MODULE
+ ret = crypto_has_comp(zcache_comp_name, 0, 0);
+ if (!ret) {
+ ret = -1;
+ goto out;
+ }
+#else
if (*zcache_comp_name != '\0') {
ret = crypto_has_comp(zcache_comp_name, 0, 0);
if (!ret)
pr_info("zcache: %s not supported\n",
zcache_comp_name);
+ goto out;
}
if (!ret)
strcpy(zcache_comp_name, "lzo");
@@ -1925,6 +1823,7 @@ static int __init zcache_comp_init(void)
ret = 1;
goto out;
}
+#endif
pr_info("zcache: using %s compressor\n", zcache_comp_name);
/* alloc percpu transforms */
@@ -1936,17 +1835,18 @@ out:
return ret;
}
-static int __init zcache_init(void)
+static int zcache_init(void)
{
int ret = 0;
+#ifdef CONFIG_ZCACHE_MODULE
+ zcache_enabled = 1;
+#endif
if (ramster_enabled) {
namestr = "ramster";
ramster_register_pamops(&zcache_pamops);
}
-#ifdef CONFIG_DEBUG_FS
zcache_debugfs_init();
-#endif
if (zcache_enabled) {
unsigned int cpu;
@@ -1980,40 +1880,62 @@ static int __init zcache_init(void)
}
zbud_init();
if (zcache_enabled && !disable_cleancache) {
- struct cleancache_ops old_ops;
+ struct cleancache_ops *old_ops;
register_shrinker(&zcache_shrinker);
old_ops = zcache_cleancache_register_ops();
pr_info("%s: cleancache enabled using kernel transcendent "
"memory and compression buddies\n", namestr);
-#ifdef ZCACHE_DEBUG
+#ifdef CONFIG_ZCACHE_DEBUG
pr_info("%s: cleancache: ignorenonactive = %d\n",
namestr, !disable_cleancache_ignore_nonactive);
#endif
- if (old_ops.init_fs != NULL)
+ if (old_ops != NULL)
pr_warn("%s: cleancache_ops overridden\n", namestr);
}
if (zcache_enabled && !disable_frontswap) {
- struct frontswap_ops old_ops;
+ struct frontswap_ops *old_ops;
old_ops = zcache_frontswap_register_ops();
if (frontswap_has_exclusive_gets)
frontswap_tmem_exclusive_gets(true);
pr_info("%s: frontswap enabled using kernel transcendent "
"memory and compression buddies\n", namestr);
-#ifdef ZCACHE_DEBUG
+#ifdef CONFIG_ZCACHE_DEBUG
pr_info("%s: frontswap: excl gets = %d active only = %d\n",
namestr, frontswap_has_exclusive_gets,
!disable_frontswap_ignore_nonactive);
#endif
- if (old_ops.init != NULL)
+ if (IS_ERR(old_ops) || old_ops) {
+ if (IS_ERR(old_ops))
+ return PTR_RET(old_ops);
pr_warn("%s: frontswap_ops overridden\n", namestr);
+ }
}
if (ramster_enabled)
ramster_init(!disable_cleancache, !disable_frontswap,
- frontswap_has_exclusive_gets);
+ frontswap_has_exclusive_gets,
+ !disable_frontswap_selfshrink);
out:
return ret;
}
+#ifdef CONFIG_ZCACHE_MODULE
+#ifdef CONFIG_RAMSTER
+module_param(ramster_enabled, int, S_IRUGO);
+module_param(disable_frontswap_selfshrink, int, S_IRUGO);
+#endif
+module_param(disable_cleancache, int, S_IRUGO);
+module_param(disable_frontswap, int, S_IRUGO);
+#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
+module_param(frontswap_has_exclusive_gets, bool, S_IRUGO);
+#endif
+module_param(disable_frontswap_ignore_nonactive, int, S_IRUGO);
+module_param(zcache_comp_name, charp, S_IRUGO);
+module_init(zcache_init);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
+MODULE_DESCRIPTION("In-kernel compression of cleancache/frontswap pages");
+#else
late_initcall(zcache_init);
+#endif
diff --git a/drivers/staging/zcache/zcache.h b/drivers/staging/zcache/zcache.h
index 81722b33b087..849120095e79 100644
--- a/drivers/staging/zcache/zcache.h
+++ b/drivers/staging/zcache/zcache.h
@@ -39,7 +39,7 @@ extern int zcache_flush_page(int, int, struct tmem_oid *, uint32_t);
extern int zcache_flush_object(int, int, struct tmem_oid *);
extern void zcache_decompress_to_page(char *, unsigned int, struct page *);
-#ifdef CONFIG_RAMSTER
+#if defined(CONFIG_RAMSTER) || defined(CONFIG_RAMSTER_MODULE)
extern void *zcache_pampd_create(char *, unsigned int, bool, int,
struct tmem_handle *);
int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph);
diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c
index 5918fd7d7e36..e34e3fe0ae2e 100644
--- a/drivers/staging/zram/zram_drv.c
+++ b/drivers/staging/zram/zram_drv.c
@@ -207,11 +207,8 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
ret = zram_decompress_page(zram, uncmem, index);
/* Should NEVER happen. Return bio error if it does. */
- if (unlikely(ret != LZO_E_OK)) {
- pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
- zram_stat64_inc(zram, &zram->stats.failed_reads);
+ if (unlikely(ret != LZO_E_OK))
goto out_cleanup;
- }
if (is_partial_io(bvec))
memcpy(user_mem + bvec->bv_offset, uncmem + offset,
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
index 908456565796..7fab032298f3 100644
--- a/drivers/staging/zsmalloc/Kconfig
+++ b/drivers/staging/zsmalloc/Kconfig
@@ -1,5 +1,5 @@
config ZSMALLOC
- tristate "Memory allocator for compressed pages"
+ bool "Memory allocator for compressed pages"
default n
help
zsmalloc is a slab-based memory allocator designed to store
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index e78d262c5249..f82f7e69c8a5 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -225,7 +225,7 @@ struct zs_pool {
* so that USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use
* page table mapping rather than copying for object mapping.
*/
-#if defined(CONFIG_ARM)
+#if defined(CONFIG_ARM) && !defined(MODULE)
#define USE_PGTABLE_MAPPING
#endif
@@ -656,11 +656,8 @@ static inline void __zs_unmap_object(struct mapping_area *area,
struct page *pages[2], int off, int size)
{
unsigned long addr = (unsigned long)area->vm_addr;
- unsigned long end = addr + (PAGE_SIZE * 2);
- flush_cache_vunmap(addr, end);
- unmap_kernel_range_noflush(addr, PAGE_SIZE * 2);
- flush_tlb_kernel_range(addr, end);
+ unmap_kernel_range(addr, PAGE_SIZE * 2);
}
#else /* USE_PGTABLE_MAPPING */
diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile
index 5b9a2cf7f0a9..13a92403fe3e 100644
--- a/drivers/target/iscsi/Makefile
+++ b/drivers/target/iscsi/Makefile
@@ -15,6 +15,7 @@ iscsi_target_mod-y += iscsi_target_parameters.o \
iscsi_target_util.o \
iscsi_target.o \
iscsi_target_configfs.o \
- iscsi_target_stat.o
+ iscsi_target_stat.o \
+ iscsi_target_transport.o
obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 7ea246a07731..ffbc6a94be52 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -49,6 +49,8 @@
#include "iscsi_target_device.h"
#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_transport.h>
+
static LIST_HEAD(g_tiqn_list);
static LIST_HEAD(g_np_list);
static DEFINE_SPINLOCK(tiqn_lock);
@@ -68,8 +70,7 @@ struct kmem_cache *lio_ooo_cache;
struct kmem_cache *lio_r2t_cache;
static int iscsit_handle_immediate_data(struct iscsi_cmd *,
- unsigned char *buf, u32);
-static int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+ struct iscsi_scsi_req *, u32);
struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf)
{
@@ -401,8 +402,7 @@ struct iscsi_np *iscsit_add_np(
spin_unlock_bh(&np_lock);
pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
- np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
- "TCP" : "SCTP");
+ np->np_ip, np->np_port, np->np_transport->name);
return np;
}
@@ -441,11 +441,10 @@ int iscsit_reset_np_thread(
return 0;
}
-static int iscsit_del_np_comm(struct iscsi_np *np)
+static void iscsit_free_np(struct iscsi_np *np)
{
if (np->np_socket)
sock_release(np->np_socket);
- return 0;
}
int iscsit_del_np(struct iscsi_np *np)
@@ -467,20 +466,47 @@ int iscsit_del_np(struct iscsi_np *np)
send_sig(SIGINT, np->np_thread, 1);
kthread_stop(np->np_thread);
}
- iscsit_del_np_comm(np);
+
+ np->np_transport->iscsit_free_np(np);
spin_lock_bh(&np_lock);
list_del(&np->np_list);
spin_unlock_bh(&np_lock);
pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
- np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
- "TCP" : "SCTP");
+ np->np_ip, np->np_port, np->np_transport->name);
+ iscsit_put_transport(np->np_transport);
kfree(np);
return 0;
}
+static int iscsit_immediate_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
+static int iscsit_response_queue(struct iscsi_conn *, struct iscsi_cmd *, int);
+
+static int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+{
+ iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+ return 0;
+}
+
+static struct iscsit_transport iscsi_target_transport = {
+ .name = "iSCSI/TCP",
+ .transport_type = ISCSI_TCP,
+ .owner = NULL,
+ .iscsit_setup_np = iscsit_setup_np,
+ .iscsit_accept_np = iscsit_accept_np,
+ .iscsit_free_np = iscsit_free_np,
+ .iscsit_alloc_cmd = iscsit_alloc_cmd,
+ .iscsit_get_login_rx = iscsit_get_login_rx,
+ .iscsit_put_login_tx = iscsit_put_login_tx,
+ .iscsit_get_dataout = iscsit_build_r2ts_for_cmd,
+ .iscsit_immediate_queue = iscsit_immediate_queue,
+ .iscsit_response_queue = iscsit_response_queue,
+ .iscsit_queue_data_in = iscsit_queue_rsp,
+ .iscsit_queue_status = iscsit_queue_rsp,
+};
+
static int __init iscsi_target_init_module(void)
{
int ret = 0;
@@ -557,6 +583,8 @@ static int __init iscsi_target_init_module(void)
goto ooo_out;
}
+ iscsit_register_transport(&iscsi_target_transport);
+
if (iscsit_load_discovery_tpg() < 0)
goto r2t_out;
@@ -587,6 +615,7 @@ static void __exit iscsi_target_cleanup_module(void)
iscsi_deallocate_thread_sets();
iscsi_thread_set_free();
iscsit_release_discovery_tpg();
+ iscsit_unregister_transport(&iscsi_target_transport);
kmem_cache_destroy(lio_cmd_cache);
kmem_cache_destroy(lio_qr_cache);
kmem_cache_destroy(lio_dr_cache);
@@ -682,11 +711,20 @@ int iscsit_add_reject_from_cmd(
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
ret = wait_for_completion_interruptible(&cmd->reject_comp);
+ /*
+ * Perform the kref_put now if se_cmd has already been setup by
+ * scsit_setup_scsi_cmd()
+ */
+ if (cmd->se_cmd.se_tfo != NULL) {
+ pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n");
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ }
if (ret != 0)
return -1;
return (!fail_conn) ? 0 : -1;
}
+EXPORT_SYMBOL(iscsit_add_reject_from_cmd);
/*
* Map some portion of the allocated scatterlist to an iovec, suitable for
@@ -745,6 +783,9 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
conn->exp_statsn = exp_statsn;
+ if (conn->sess->sess_ops->RDMAExtensions)
+ return;
+
spin_lock_bh(&conn->cmd_lock);
list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) {
spin_lock(&cmd->istate_lock);
@@ -777,12 +818,10 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd)
return 0;
}
-static int iscsit_handle_scsi_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
- int data_direction, payload_length, cmdsn_ret = 0, immed_ret;
- struct iscsi_cmd *cmd = NULL;
+ int data_direction, payload_length;
struct iscsi_scsi_req *hdr;
int iscsi_task_attr;
int sam_task_attr;
@@ -805,8 +844,8 @@ static int iscsit_handle_scsi_cmd(
!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) {
pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL"
" not set. Bad iSCSI Initiator.\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (((hdr->flags & ISCSI_FLAG_CMD_READ) ||
@@ -826,8 +865,8 @@ static int iscsit_handle_scsi_cmd(
pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE"
" set when Expected Data Transfer Length is 0 for"
" CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]);
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
done:
@@ -836,29 +875,29 @@ done:
pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE"
" MUST be set if Expected Data Transfer Length is not 0."
" Bad iSCSI Initiator\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if ((hdr->flags & ISCSI_FLAG_CMD_READ) &&
(hdr->flags & ISCSI_FLAG_CMD_WRITE)) {
pr_err("Bidirectional operations not supported!\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (hdr->opcode & ISCSI_OP_IMMEDIATE) {
pr_err("Illegally set Immediate Bit in iSCSI Initiator"
" Scsi Command PDU.\n");
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
if (payload_length && !conn->sess->sess_ops->ImmediateData) {
pr_err("ImmediateData=No but DataSegmentLength=%u,"
" protocol error.\n", payload_length);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if ((be32_to_cpu(hdr->data_length )== payload_length) &&
@@ -866,43 +905,38 @@ done:
pr_err("Expected Data Transfer Length and Length of"
" Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL"
" bit is not set protocol error\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > be32_to_cpu(hdr->data_length)) {
pr_err("DataSegmentLength: %u is greater than"
" EDTL: %u, protocol error.\n", payload_length,
hdr->data_length);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) {
pr_err("DataSegmentLength: %u is greater than"
" MaxXmitDataSegmentLength: %u, protocol error.\n",
payload_length, conn->conn_ops->MaxXmitDataSegmentLength);
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if (payload_length > conn->sess->sess_ops->FirstBurstLength) {
pr_err("DataSegmentLength: %u is greater than"
" FirstBurstLength: %u, protocol error.\n",
payload_length, conn->sess->sess_ops->FirstBurstLength);
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID,
+ 1, 1, buf, cmd);
}
data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE :
(hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE :
DMA_NONE;
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
- buf, conn);
-
cmd->data_direction = data_direction;
iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK;
/*
@@ -945,7 +979,8 @@ done:
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->first_burst_len = payload_length;
- if (cmd->data_direction == DMA_FROM_DEVICE) {
+ if (!conn->sess->sess_ops->RDMAExtensions &&
+ cmd->data_direction == DMA_FROM_DEVICE) {
struct iscsi_datain_req *dr;
dr = iscsit_allocate_datain_req();
@@ -967,7 +1002,10 @@ done:
pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x,"
" ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt,
- hdr->cmdsn, hdr->data_length, payload_length, conn->cid);
+ hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length,
+ conn->cid);
+
+ target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true);
cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd,
scsilun_to_int(&hdr->lun));
@@ -1001,12 +1039,24 @@ attach_cmd:
*/
core_alua_check_nonop_delay(&cmd->se_cmd);
- if (iscsit_allocate_iovecs(cmd) < 0) {
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, 0, buf, cmd);
- }
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_setup_scsi_cmd);
+
+void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *cmd)
+{
+ iscsit_set_dataout_sequence_values(cmd);
+
+ spin_lock_bh(&cmd->dataout_timeout_lock);
+ iscsit_start_dataout_timer(cmd, cmd->conn);
+ spin_unlock_bh(&cmd->dataout_timeout_lock);
+}
+EXPORT_SYMBOL(iscsit_set_unsoliticed_dataout);
+int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_scsi_req *hdr)
+{
+ int cmdsn_ret = 0;
/*
* Check the CmdSN against ExpCmdSN/MaxCmdSN here if
* the Immediate Bit is not set, and no Immediate
@@ -1019,12 +1069,17 @@ attach_cmd:
*/
if (!cmd->immediate_data) {
cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- if (cmdsn_ret == CMDSN_LOWER_THAN_EXP)
+ if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) {
+ if (!cmd->sense_reason)
+ return 0;
+
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 0;
- else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
+ } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) {
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
+ }
}
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
@@ -1033,25 +1088,23 @@ attach_cmd:
* If no Immediate Data is attached, it's OK to return now.
*/
if (!cmd->immediate_data) {
- if (!cmd->sense_reason && cmd->unsolicited_data) {
- iscsit_set_dataout_sequence_values(cmd);
-
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
- }
+ if (!cmd->sense_reason && cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
+ if (!cmd->sense_reason)
+ return 0;
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
return 0;
}
/*
- * Early CHECK_CONDITIONs never make it to the transport processing
- * thread. They are processed in CmdSN order by
- * iscsit_check_received_cmdsn() below.
+ * Early CHECK_CONDITIONs with ImmediateData never make it to command
+ * execution. These exceptions are processed in CmdSN order using
+ * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below.
*/
if (cmd->sense_reason) {
- immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
- goto after_immediate_data;
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 1;
}
/*
* Call directly into transport_generic_new_cmd() to perform
@@ -1059,11 +1112,27 @@ attach_cmd:
*/
cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd);
if (cmd->sense_reason) {
- immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
- goto after_immediate_data;
+ target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd);
+ return 1;
}
- immed_ret = iscsit_handle_immediate_data(cmd, buf, payload_length);
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_process_scsi_cmd);
+
+static int
+iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr,
+ bool dump_payload)
+{
+ int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION;
+ /*
+ * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes.
+ */
+ if (dump_payload == true)
+ goto after_immediate_data;
+
+ immed_ret = iscsit_handle_immediate_data(cmd, hdr,
+ cmd->first_burst_len);
after_immediate_data:
if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) {
/*
@@ -1071,26 +1140,19 @@ after_immediate_data:
* DataCRC, check against ExpCmdSN/MaxCmdSN if
* Immediate Bit is not set.
*/
- cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
- /*
- * Special case for Unsupported SAM WRITE Opcodes
- * and ImmediateData=Yes.
- */
+ cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn);
+
if (cmd->sense_reason) {
- if (iscsit_dump_data_payload(conn, payload_length, 1) < 0)
+ if (iscsit_dump_data_payload(cmd->conn,
+ cmd->first_burst_len, 1) < 0)
return -1;
- } else if (cmd->unsolicited_data) {
- iscsit_set_dataout_sequence_values(cmd);
-
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
- }
+ } else if (cmd->unsolicited_data)
+ iscsit_set_unsoliticed_dataout(cmd);
if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER)
return iscsit_add_reject_from_cmd(
ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
} else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) {
/*
@@ -1105,13 +1167,47 @@ after_immediate_data:
* CmdSN and issue a retry to plug the sequence.
*/
cmd->i_state = ISTATE_REMOVE;
- iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+ iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, cmd->i_state);
} else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */
return -1;
return 0;
}
+static int
+iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
+{
+ struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
+ int rc, immed_data;
+ bool dump_payload = false;
+
+ rc = iscsit_setup_scsi_cmd(conn, cmd, buf);
+ if (rc < 0)
+ return rc;
+ /*
+ * Allocation iovecs needed for struct socket operations for
+ * traditional iSCSI block I/O.
+ */
+ if (iscsit_allocate_iovecs(cmd) < 0) {
+ return iscsit_add_reject_from_cmd(
+ ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, 0, buf, cmd);
+ }
+ immed_data = cmd->immediate_data;
+
+ rc = iscsit_process_scsi_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0)
+ dump_payload = true;
+
+ if (!immed_data)
+ return 0;
+
+ return iscsit_get_immediate_data(cmd, hdr, dump_payload);
+}
+
static u32 iscsit_do_crypto_hash_sg(
struct hash_desc *hash,
struct iscsi_cmd *cmd,
@@ -1174,20 +1270,16 @@ static void iscsit_do_crypto_hash_buf(
crypto_hash_final(hash, data_crc);
}
-static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
+int
+iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf,
+ struct iscsi_cmd **out_cmd)
{
- int iov_ret, ooo_cmdsn = 0, ret;
- u8 data_crc_failed = 0;
- u32 checksum, iov_count = 0, padding = 0, rx_got = 0;
- u32 rx_size = 0, payload_length;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
struct iscsi_cmd *cmd = NULL;
struct se_cmd *se_cmd;
- struct iscsi_data *hdr;
- struct kvec *iov;
unsigned long flags;
-
- hdr = (struct iscsi_data *) buf;
- payload_length = ntoh24(hdr->dlength);
+ u32 payload_length = ntoh24(hdr->dlength);
+ int rc;
if (!payload_length) {
pr_err("DataOUT payload is ZERO, protocol error.\n");
@@ -1220,7 +1312,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x,"
" DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
- hdr->itt, hdr->ttt, hdr->datasn, hdr->offset,
+ hdr->itt, hdr->ttt, hdr->datasn, ntohl(hdr->offset),
payload_length, conn->cid);
if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) {
@@ -1312,12 +1404,26 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
* Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and
* within-command recovery checks before receiving the payload.
*/
- ret = iscsit_check_pre_dataout(cmd, buf);
- if (ret == DATAOUT_WITHIN_COMMAND_RECOVERY)
+ rc = iscsit_check_pre_dataout(cmd, buf);
+ if (rc == DATAOUT_WITHIN_COMMAND_RECOVERY)
return 0;
- else if (ret == DATAOUT_CANNOT_RECOVER)
+ else if (rc == DATAOUT_CANNOT_RECOVER)
return -1;
+ *out_cmd = cmd;
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_check_dataout_hdr);
+
+static int
+iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ struct iscsi_data *hdr)
+{
+ struct kvec *iov;
+ u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int iov_ret, data_crc_failed = 0;
+
rx_size += payload_length;
iov = &cmd->iov_data[0];
@@ -1370,17 +1476,27 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
payload_length);
}
}
+
+ return data_crc_failed;
+}
+
+int
+iscsit_check_dataout_payload(struct iscsi_cmd *cmd, struct iscsi_data *hdr,
+ bool data_crc_failed)
+{
+ struct iscsi_conn *conn = cmd->conn;
+ int rc, ooo_cmdsn;
/*
* Increment post receive data and CRC values or perform
* within-command recovery.
*/
- ret = iscsit_check_post_dataout(cmd, buf, data_crc_failed);
- if ((ret == DATAOUT_NORMAL) || (ret == DATAOUT_WITHIN_COMMAND_RECOVERY))
+ rc = iscsit_check_post_dataout(cmd, (unsigned char *)hdr, data_crc_failed);
+ if ((rc == DATAOUT_NORMAL) || (rc == DATAOUT_WITHIN_COMMAND_RECOVERY))
return 0;
- else if (ret == DATAOUT_SEND_R2T) {
+ else if (rc == DATAOUT_SEND_R2T) {
iscsit_set_dataout_sequence_values(cmd);
- iscsit_build_r2ts_for_cmd(cmd, conn, false);
- } else if (ret == DATAOUT_SEND_TO_TRANSPORT) {
+ conn->conn_transport->iscsit_get_dataout(conn, cmd, false);
+ } else if (rc == DATAOUT_SEND_TO_TRANSPORT) {
/*
* Handle extra special case for out of order
* Unsolicited Data Out.
@@ -1401,15 +1517,37 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
return 0;
}
+EXPORT_SYMBOL(iscsit_check_dataout_payload);
-static int iscsit_handle_nop_out(
- struct iscsi_conn *conn,
- unsigned char *buf)
+static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf)
+{
+ struct iscsi_cmd *cmd;
+ struct iscsi_data *hdr = (struct iscsi_data *)buf;
+ int rc;
+ bool data_crc_failed = false;
+
+ rc = iscsit_check_dataout_hdr(conn, buf, &cmd);
+ if (rc < 0)
+ return rc;
+ else if (!cmd)
+ return 0;
+
+ rc = iscsit_get_dataout(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ else if (rc > 0)
+ data_crc_failed = true;
+
+ return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed);
+}
+
+int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
unsigned char *ping_data = NULL;
int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size;
u32 checksum, data_crc, padding = 0, payload_length;
- struct iscsi_cmd *cmd = NULL;
+ struct iscsi_cmd *cmd_p = NULL;
struct kvec *iov = NULL;
struct iscsi_nopout *hdr;
@@ -1432,7 +1570,7 @@ static int iscsit_handle_nop_out(
buf, conn);
}
- pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x,"
+ pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x,"
" CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
hdr->itt == RESERVED_ITT ? "Response" : "Request",
hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn,
@@ -1445,7 +1583,6 @@ static int iscsit_handle_nop_out(
* can contain ping data.
*/
if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
if (!cmd)
return iscsit_add_reject(
ISCSI_REASON_BOOKMARK_NO_RESOURCES,
@@ -1580,14 +1717,14 @@ static int iscsit_handle_nop_out(
/*
* This was a response to a unsolicited NOPIN ping.
*/
- cmd = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
- if (!cmd)
+ cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt));
+ if (!cmd_p)
return -1;
iscsit_stop_nopin_response_timer(conn);
- cmd->i_state = ISTATE_REMOVE;
- iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state);
+ cmd_p->i_state = ISTATE_REMOVE;
+ iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state);
iscsit_start_nopin_timer(conn);
} else {
/*
@@ -1611,12 +1748,12 @@ ping_out:
kfree(ping_data);
return ret;
}
+EXPORT_SYMBOL(iscsit_handle_nop_out);
-static int iscsit_handle_task_mgt_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int
+iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
- struct iscsi_cmd *cmd;
struct se_tmr_req *se_tmr;
struct iscsi_tmr_req *tmr_req;
struct iscsi_tm *hdr;
@@ -1645,18 +1782,13 @@ static int iscsit_handle_task_mgt_cmd(
pr_err("Task Management Request TASK_REASSIGN not"
" issued as immediate command, bad iSCSI Initiator"
"implementation\n");
- return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1,
- buf, conn);
+ return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR,
+ 1, 1, buf, cmd);
}
if ((function != ISCSI_TM_FUNC_ABORT_TASK) &&
be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG)
hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG);
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
- 1, buf, conn);
-
cmd->data_direction = DMA_NONE;
cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL);
@@ -1827,6 +1959,7 @@ attach:
iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state);
return 0;
}
+EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd);
/* #warning FIXME: Support Text Command parameters besides SendTargets */
static int iscsit_handle_text_cmd(
@@ -2089,13 +2222,12 @@ int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn
return 0;
}
-static int iscsit_handle_logout_cmd(
- struct iscsi_conn *conn,
- unsigned char *buf)
+int
+iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+ unsigned char *buf)
{
int cmdsn_ret, logout_remove = 0;
u8 reason_code = 0;
- struct iscsi_cmd *cmd;
struct iscsi_logout *hdr;
struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn);
@@ -2119,14 +2251,10 @@ static int iscsit_handle_logout_cmd(
if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
pr_err("Received logout request on connection that"
" is not in logged in state, ignoring request.\n");
+ iscsit_release_cmd(cmd);
return 0;
}
- cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
- if (!cmd)
- return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1,
- buf, conn);
-
cmd->iscsi_opcode = ISCSI_OP_LOGOUT;
cmd->i_state = ISTATE_SEND_LOGOUTRSP;
cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0);
@@ -2176,6 +2304,7 @@ static int iscsit_handle_logout_cmd(
return logout_remove;
}
+EXPORT_SYMBOL(iscsit_handle_logout_cmd);
static int iscsit_handle_snack(
struct iscsi_conn *conn,
@@ -2243,7 +2372,7 @@ static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn)
static int iscsit_handle_immediate_data(
struct iscsi_cmd *cmd,
- unsigned char *buf,
+ struct iscsi_scsi_req *hdr,
u32 length)
{
int iov_ret, rx_got = 0, rx_size = 0;
@@ -2299,12 +2428,12 @@ static int iscsit_handle_immediate_data(
" in ERL=0.\n");
iscsit_add_reject_from_cmd(
ISCSI_REASON_DATA_DIGEST_ERROR,
- 1, 0, buf, cmd);
+ 1, 0, (unsigned char *)hdr, cmd);
return IMMEDIATE_DATA_CANNOT_RECOVER;
} else {
iscsit_add_reject_from_cmd(
ISCSI_REASON_DATA_DIGEST_ERROR,
- 0, 0, buf, cmd);
+ 0, 0, (unsigned char *)hdr, cmd);
return IMMEDIATE_DATA_ERL1_CRC_FAILURE;
}
} else {
@@ -2424,18 +2553,60 @@ static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn)
}
}
-static int iscsit_send_data_in(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+static void
+iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_datain *datain, struct iscsi_data_rsp *hdr,
+ bool set_statsn)
{
- int iov_ret = 0, set_statsn = 0;
- u32 iov_count = 0, tx_size = 0;
+ hdr->opcode = ISCSI_OP_SCSI_DATA_IN;
+ hdr->flags = datain->flags;
+ if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+ if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
+ hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
+ hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
+ } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
+ hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
+ hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
+ }
+ }
+ hton24(hdr->dlength, datain->length);
+ if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+ int_to_scsilun(cmd->se_cmd.orig_fe_lun,
+ (struct scsi_lun *)&hdr->lun);
+ else
+ put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+
+ hdr->itt = cmd->init_task_tag;
+
+ if (hdr->flags & ISCSI_FLAG_DATA_ACK)
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ else
+ hdr->ttt = cpu_to_be32(0xFFFFFFFF);
+ if (set_statsn)
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ else
+ hdr->statsn = cpu_to_be32(0xFFFFFFFF);
+
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ hdr->datasn = cpu_to_be32(datain->data_sn);
+ hdr->offset = cpu_to_be32(datain->offset);
+
+ pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
+ " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
+ cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
+ ntohl(hdr->offset), datain->length, conn->cid);
+}
+
+static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_data_rsp *hdr = (struct iscsi_data_rsp *)&cmd->pdu[0];
struct iscsi_datain datain;
struct iscsi_datain_req *dr;
- struct iscsi_data_rsp *hdr;
struct kvec *iov;
- int eodr = 0;
- int ret;
+ u32 iov_count = 0, tx_size = 0;
+ int eodr = 0, ret, iov_ret;
+ bool set_statsn = false;
memset(&datain, 0, sizeof(struct iscsi_datain));
dr = iscsit_get_datain_values(cmd, &datain);
@@ -2444,7 +2615,6 @@ static int iscsit_send_data_in(
cmd->init_task_tag);
return -1;
}
-
/*
* Be paranoid and double check the logic for now.
*/
@@ -2452,7 +2622,7 @@ static int iscsit_send_data_in(
pr_err("Command ITT: 0x%08x, datain.offset: %u and"
" datain.length: %u exceeds cmd->data_length: %u\n",
cmd->init_task_tag, datain.offset, datain.length,
- cmd->se_cmd.data_length);
+ cmd->se_cmd.data_length);
return -1;
}
@@ -2476,47 +2646,13 @@ static int iscsit_send_data_in(
(dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) {
iscsit_increment_maxcmdsn(cmd, conn->sess);
cmd->stat_sn = conn->stat_sn++;
- set_statsn = 1;
+ set_statsn = true;
} else if (dr->dr_complete ==
- DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
- set_statsn = 1;
+ DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY)
+ set_statsn = true;
}
- hdr = (struct iscsi_data_rsp *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_SCSI_DATA_IN;
- hdr->flags = datain.flags;
- if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
- if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) {
- hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW;
- hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
- } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) {
- hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW;
- hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count);
- }
- }
- hton24(hdr->dlength, datain.length);
- if (hdr->flags & ISCSI_FLAG_DATA_ACK)
- int_to_scsilun(cmd->se_cmd.orig_fe_lun,
- (struct scsi_lun *)&hdr->lun);
- else
- put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
-
- hdr->itt = cmd->init_task_tag;
-
- if (hdr->flags & ISCSI_FLAG_DATA_ACK)
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- else
- hdr->ttt = cpu_to_be32(0xFFFFFFFF);
- if (set_statsn)
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
- else
- hdr->statsn = cpu_to_be32(0xFFFFFFFF);
-
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
- hdr->datasn = cpu_to_be32(datain.data_sn);
- hdr->offset = cpu_to_be32(datain.offset);
+ iscsit_build_datain_pdu(cmd, conn, &datain, hdr, set_statsn);
iov = &cmd->iov_data[0];
iov[iov_count].iov_base = cmd->pdu;
@@ -2527,7 +2663,7 @@ static int iscsit_send_data_in(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2537,7 +2673,8 @@ static int iscsit_send_data_in(
" for DataIN PDU 0x%08x\n", *header_digest);
}
- iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], datain.offset, datain.length);
+ iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1],
+ datain.offset, datain.length);
if (iov_ret < 0)
return -1;
@@ -2568,11 +2705,6 @@ static int iscsit_send_data_in(
cmd->iov_data_count = iov_count;
cmd->tx_size = tx_size;
- pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x,"
- " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n",
- cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn),
- ntohl(hdr->offset), datain.length, conn->cid);
-
/* sendpage is preferred but can't insert markers */
if (!conn->conn_ops->IFMarker)
ret = iscsit_fe_sendpage_sg(cmd, conn);
@@ -2595,16 +2727,13 @@ static int iscsit_send_data_in(
return eodr;
}
-static int iscsit_send_logout_response(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+int
+iscsit_build_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_logout_rsp *hdr)
{
- int niov = 0, tx_size;
struct iscsi_conn *logout_conn = NULL;
struct iscsi_conn_recovery *cr = NULL;
struct iscsi_session *sess = conn->sess;
- struct kvec *iov;
- struct iscsi_logout_rsp *hdr;
/*
* The actual shutting down of Sessions and/or Connections
* for CLOSESESSION and CLOSECONNECTION Logout Requests
@@ -2673,9 +2802,6 @@ static int iscsit_send_logout_response(
return -1;
}
- tx_size = ISCSI_HDR_LEN;
- hdr = (struct iscsi_logout_rsp *)cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_LOGOUT_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
hdr->response = cmd->logout_response;
@@ -2687,6 +2813,27 @@ static int iscsit_send_logout_response(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built Logout Response ITT: 0x%08x StatSN:"
+ " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, hdr->response,
+ cmd->logout_cid, conn->cid);
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_build_logout_rsp);
+
+static int
+iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct kvec *iov;
+ int niov = 0, tx_size, rc;
+
+ rc = iscsit_build_logout_rsp(cmd, conn,
+ (struct iscsi_logout_rsp *)&cmd->pdu[0]);
+ if (rc < 0)
+ return rc;
+
+ tx_size = ISCSI_HDR_LEN;
iov = &cmd->iov_misc[0];
iov[niov].iov_base = cmd->pdu;
iov[niov++].iov_len = ISCSI_HDR_LEN;
@@ -2695,7 +2842,7 @@ static int iscsit_send_logout_response(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)&cmd->pdu[0], ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -2706,14 +2853,37 @@ static int iscsit_send_logout_response(
cmd->iov_misc_count = niov;
cmd->tx_size = tx_size;
- pr_debug("Sending Logout Response ITT: 0x%08x StatSN:"
- " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n",
- cmd->init_task_tag, cmd->stat_sn, hdr->response,
- cmd->logout_cid, conn->cid);
-
return 0;
}
+void
+iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_nopin *hdr, bool nopout_response)
+{
+ hdr->opcode = ISCSI_OP_NOOP_IN;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ hton24(hdr->dlength, cmd->buf_ptr_size);
+ if (nopout_response)
+ put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
+ hdr->itt = cmd->init_task_tag;
+ hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
+ cmd->stat_sn = (nopout_response) ? conn->stat_sn++ :
+ conn->stat_sn;
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+
+ if (nopout_response)
+ iscsit_increment_maxcmdsn(cmd, conn->sess);
+
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+
+ pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x,"
+ " StatSN: 0x%08x, Length %u\n", (nopout_response) ?
+ "Solicitied" : "Unsolicitied", cmd->init_task_tag,
+ cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
+}
+EXPORT_SYMBOL(iscsit_build_nopin_rsp);
+
/*
* Unsolicited NOPIN, either requesting a response or not.
*/
@@ -2722,20 +2892,10 @@ static int iscsit_send_unsolicited_nopin(
struct iscsi_conn *conn,
int want_response)
{
- int tx_size = ISCSI_HDR_LEN;
- struct iscsi_nopin *hdr;
- int ret;
+ struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
+ int tx_size = ISCSI_HDR_LEN, ret;
- hdr = (struct iscsi_nopin *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_NOOP_IN;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hdr->itt = cmd->init_task_tag;
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- cmd->stat_sn = conn->stat_sn;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ iscsit_build_nopin_rsp(cmd, conn, hdr, false);
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
@@ -2771,31 +2931,17 @@ static int iscsit_send_unsolicited_nopin(
return 0;
}
-static int iscsit_send_nopin_response(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+static int
+iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
{
- int niov = 0, tx_size;
- u32 padding = 0;
+ struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0];
struct kvec *iov;
- struct iscsi_nopin *hdr;
-
- tx_size = ISCSI_HDR_LEN;
- hdr = (struct iscsi_nopin *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
- hdr->opcode = ISCSI_OP_NOOP_IN;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hton24(hdr->dlength, cmd->buf_ptr_size);
- put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun);
- hdr->itt = cmd->init_task_tag;
- hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag);
- cmd->stat_sn = conn->stat_sn++;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ u32 padding = 0;
+ int niov = 0, tx_size;
- iscsit_increment_maxcmdsn(cmd, conn->sess);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ iscsit_build_nopin_rsp(cmd, conn, hdr, true);
+ tx_size = ISCSI_HDR_LEN;
iov = &cmd->iov_misc[0];
iov[niov].iov_base = cmd->pdu;
iov[niov++].iov_len = ISCSI_HDR_LEN;
@@ -2851,10 +2997,6 @@ static int iscsit_send_nopin_response(
cmd->iov_misc_count = niov;
cmd->tx_size = tx_size;
- pr_debug("Sending NOPIN Response ITT: 0x%08x, TTT:"
- " 0x%08x, StatSN: 0x%08x, Length %u\n", cmd->init_task_tag,
- cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size);
-
return 0;
}
@@ -2939,8 +3081,8 @@ static int iscsit_send_r2t(
* connection recovery.
*/
int iscsit_build_r2ts_for_cmd(
- struct iscsi_cmd *cmd,
struct iscsi_conn *conn,
+ struct iscsi_cmd *cmd,
bool recovery)
{
int first_r2t = 1;
@@ -3015,24 +3157,16 @@ int iscsit_build_r2ts_for_cmd(
return 0;
}
-static int iscsit_send_status(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ bool inc_stat_sn, struct iscsi_scsi_rsp *hdr)
{
- u8 iov_count = 0, recovery;
- u32 padding = 0, tx_size = 0;
- struct iscsi_scsi_rsp *hdr;
- struct kvec *iov;
-
- recovery = (cmd->i_state != ISTATE_SEND_STATUS);
- if (!recovery)
+ if (inc_stat_sn)
cmd->stat_sn = conn->stat_sn++;
spin_lock_bh(&conn->sess->session_stats_lock);
conn->sess->rsp_pdus++;
spin_unlock_bh(&conn->sess->session_stats_lock);
- hdr = (struct iscsi_scsi_rsp *) cmd->pdu;
memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_SCSI_CMD_RSP;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
@@ -3052,6 +3186,23 @@ static int iscsit_send_status(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
+ " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, cmd->se_cmd.scsi_status,
+ cmd->se_cmd.scsi_status, conn->cid);
+}
+EXPORT_SYMBOL(iscsit_build_rsp_pdu);
+
+static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)&cmd->pdu[0];
+ struct kvec *iov;
+ u32 padding = 0, tx_size = 0;
+ int iov_count = 0;
+ bool inc_stat_sn = (cmd->i_state == ISTATE_SEND_STATUS);
+
+ iscsit_build_rsp_pdu(cmd, conn, inc_stat_sn, hdr);
+
iov = &cmd->iov_misc[0];
iov[iov_count].iov_base = cmd->pdu;
iov[iov_count++].iov_len = ISCSI_HDR_LEN;
@@ -3106,7 +3257,7 @@ static int iscsit_send_status(
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
+ (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
@@ -3118,11 +3269,6 @@ static int iscsit_send_status(
cmd->iov_misc_count = iov_count;
cmd->tx_size = tx_size;
- pr_debug("Built %sSCSI Response, ITT: 0x%08x, StatSN: 0x%08x,"
- " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n",
- (!recovery) ? "" : "Recovery ", cmd->init_task_tag,
- cmd->stat_sn, 0x00, cmd->se_cmd.scsi_status, conn->cid);
-
return 0;
}
@@ -3145,16 +3291,12 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr)
}
}
-static int iscsit_send_task_mgt_rsp(
- struct iscsi_cmd *cmd,
- struct iscsi_conn *conn)
+void
+iscsit_build_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_tm_rsp *hdr)
{
struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req;
- struct iscsi_tm_rsp *hdr;
- u32 tx_size = 0;
- hdr = (struct iscsi_tm_rsp *) cmd->pdu;
- memset(hdr, 0, ISCSI_HDR_LEN);
hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP;
hdr->flags = ISCSI_FLAG_CMD_FINAL;
hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr);
@@ -3166,6 +3308,20 @@ static int iscsit_send_task_mgt_rsp(
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ pr_debug("Built Task Management Response ITT: 0x%08x,"
+ " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
+ cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
+}
+EXPORT_SYMBOL(iscsit_build_task_mgt_rsp);
+
+static int
+iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct iscsi_tm_rsp *hdr = (struct iscsi_tm_rsp *)&cmd->pdu[0];
+ u32 tx_size = 0;
+
+ iscsit_build_task_mgt_rsp(cmd, conn, hdr);
+
cmd->iov_misc[0].iov_base = cmd->pdu;
cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN;
tx_size += ISCSI_HDR_LEN;
@@ -3186,10 +3342,6 @@ static int iscsit_send_task_mgt_rsp(
cmd->iov_misc_count = 1;
cmd->tx_size = tx_size;
- pr_debug("Built Task Management Response ITT: 0x%08x,"
- " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n",
- cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid);
-
return 0;
}
@@ -3385,6 +3537,22 @@ static int iscsit_send_text_rsp(
return 0;
}
+void
+iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
+ struct iscsi_reject *hdr)
+{
+ hdr->opcode = ISCSI_OP_REJECT;
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ hton24(hdr->dlength, ISCSI_HDR_LEN);
+ hdr->ffffffff = cpu_to_be32(0xffffffff);
+ cmd->stat_sn = conn->stat_sn++;
+ hdr->statsn = cpu_to_be32(cmd->stat_sn);
+ hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
+ hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+
+}
+EXPORT_SYMBOL(iscsit_build_reject);
+
static int iscsit_send_reject(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
@@ -3393,18 +3561,9 @@ static int iscsit_send_reject(
struct iscsi_reject *hdr;
struct kvec *iov;
- hdr = (struct iscsi_reject *) cmd->pdu;
- hdr->opcode = ISCSI_OP_REJECT;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
- hton24(hdr->dlength, ISCSI_HDR_LEN);
- hdr->ffffffff = cpu_to_be32(0xffffffff);
- cmd->stat_sn = conn->stat_sn++;
- hdr->statsn = cpu_to_be32(cmd->stat_sn);
- hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
- hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
+ iscsit_build_reject(cmd, conn, (struct iscsi_reject *)&cmd->pdu[0]);
iov = &cmd->iov_misc[0];
-
iov[iov_count].iov_base = cmd->pdu;
iov[iov_count++].iov_len = ISCSI_HDR_LEN;
iov[iov_count].iov_base = cmd->buf_ptr;
@@ -3501,55 +3660,41 @@ static inline void iscsit_thread_check_cpumask(
set_cpus_allowed_ptr(p, conn->conn_cpumask);
}
-static int handle_immediate_queue(struct iscsi_conn *conn)
+static int
+iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
{
- struct iscsi_queue_req *qr;
- struct iscsi_cmd *cmd;
- u8 state;
int ret;
- while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
- atomic_set(&conn->check_immediate_queue, 0);
- cmd = qr->cmd;
- state = qr->state;
- kmem_cache_free(lio_qr_cache, qr);
-
- switch (state) {
- case ISTATE_SEND_R2T:
- ret = iscsit_send_r2t(cmd, conn);
- if (ret < 0)
- goto err;
- break;
- case ISTATE_REMOVE:
- if (cmd->data_direction == DMA_TO_DEVICE)
- iscsit_stop_dataout_timer(cmd);
-
- spin_lock_bh(&conn->cmd_lock);
- list_del(&cmd->i_conn_node);
- spin_unlock_bh(&conn->cmd_lock);
+ switch (state) {
+ case ISTATE_SEND_R2T:
+ ret = iscsit_send_r2t(cmd, conn);
+ if (ret < 0)
+ goto err;
+ break;
+ case ISTATE_REMOVE:
+ spin_lock_bh(&conn->cmd_lock);
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
- continue;
- case ISTATE_SEND_NOPIN_WANT_RESPONSE:
- iscsit_mod_nopin_response_timer(conn);
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 1);
- if (ret < 0)
- goto err;
- break;
- case ISTATE_SEND_NOPIN_NO_RESPONSE:
- ret = iscsit_send_unsolicited_nopin(cmd,
- conn, 0);
- if (ret < 0)
- goto err;
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag, state,
- conn->cid);
+ iscsit_free_cmd(cmd);
+ break;
+ case ISTATE_SEND_NOPIN_WANT_RESPONSE:
+ iscsit_mod_nopin_response_timer(conn);
+ ret = iscsit_send_unsolicited_nopin(cmd, conn, 1);
+ if (ret < 0)
goto err;
- }
+ break;
+ case ISTATE_SEND_NOPIN_NO_RESPONSE:
+ ret = iscsit_send_unsolicited_nopin(cmd, conn, 0);
+ if (ret < 0)
+ goto err;
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag, state,
+ conn->cid);
+ goto err;
}
return 0;
@@ -3558,128 +3703,143 @@ err:
return -1;
}
-static int handle_response_queue(struct iscsi_conn *conn)
+static int
+iscsit_handle_immediate_queue(struct iscsi_conn *conn)
{
+ struct iscsit_transport *t = conn->conn_transport;
struct iscsi_queue_req *qr;
struct iscsi_cmd *cmd;
u8 state;
int ret;
- while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
+ while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) {
+ atomic_set(&conn->check_immediate_queue, 0);
cmd = qr->cmd;
state = qr->state;
kmem_cache_free(lio_qr_cache, qr);
-check_rsp_state:
- switch (state) {
- case ISTATE_SEND_DATAIN:
- ret = iscsit_send_data_in(cmd, conn);
- if (ret < 0)
- goto err;
- else if (!ret)
- /* more drs */
- goto check_rsp_state;
- else if (ret == 1) {
- /* all done */
- spin_lock_bh(&cmd->istate_lock);
- cmd->i_state = ISTATE_SENT_STATUS;
- spin_unlock_bh(&cmd->istate_lock);
-
- if (atomic_read(&conn->check_immediate_queue))
- return 1;
+ ret = t->iscsit_immediate_queue(conn, cmd, state);
+ if (ret < 0)
+ return ret;
+ }
- continue;
- } else if (ret == 2) {
- /* Still must send status,
- SCF_TRANSPORT_TASK_SENSE was set */
- spin_lock_bh(&cmd->istate_lock);
- cmd->i_state = ISTATE_SEND_STATUS;
- spin_unlock_bh(&cmd->istate_lock);
- state = ISTATE_SEND_STATUS;
- goto check_rsp_state;
- }
+ return 0;
+}
- break;
- case ISTATE_SEND_STATUS:
- case ISTATE_SEND_STATUS_RECOVERY:
- ret = iscsit_send_status(cmd, conn);
- break;
- case ISTATE_SEND_LOGOUTRSP:
- ret = iscsit_send_logout_response(cmd, conn);
- break;
- case ISTATE_SEND_ASYNCMSG:
- ret = iscsit_send_conn_drop_async_message(
- cmd, conn);
- break;
- case ISTATE_SEND_NOPIN:
- ret = iscsit_send_nopin_response(cmd, conn);
- break;
- case ISTATE_SEND_REJECT:
- ret = iscsit_send_reject(cmd, conn);
- break;
- case ISTATE_SEND_TASKMGTRSP:
- ret = iscsit_send_task_mgt_rsp(cmd, conn);
- if (ret != 0)
- break;
- ret = iscsit_tmr_post_handler(cmd, conn);
- if (ret != 0)
- iscsit_fall_back_to_erl0(conn->sess);
- break;
- case ISTATE_SEND_TEXTRSP:
- ret = iscsit_send_text_rsp(cmd, conn);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- state, conn->cid);
- goto err;
- }
+static int
+iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
+{
+ int ret;
+
+check_rsp_state:
+ switch (state) {
+ case ISTATE_SEND_DATAIN:
+ ret = iscsit_send_datain(cmd, conn);
if (ret < 0)
goto err;
+ else if (!ret)
+ /* more drs */
+ goto check_rsp_state;
+ else if (ret == 1) {
+ /* all done */
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
- if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
- iscsit_tx_thread_wait_for_tcp(conn);
- iscsit_unmap_iovec(cmd);
- goto err;
- }
- iscsit_unmap_iovec(cmd);
+ if (atomic_read(&conn->check_immediate_queue))
+ return 1;
- switch (state) {
- case ISTATE_SEND_LOGOUTRSP:
- if (!iscsit_logout_post_handler(cmd, conn))
- goto restart;
- /* fall through */
- case ISTATE_SEND_STATUS:
- case ISTATE_SEND_ASYNCMSG:
- case ISTATE_SEND_NOPIN:
- case ISTATE_SEND_STATUS_RECOVERY:
- case ISTATE_SEND_TEXTRSP:
- case ISTATE_SEND_TASKMGTRSP:
+ return 0;
+ } else if (ret == 2) {
+ /* Still must send status,
+ SCF_TRANSPORT_TASK_SENSE was set */
spin_lock_bh(&cmd->istate_lock);
- cmd->i_state = ISTATE_SENT_STATUS;
+ cmd->i_state = ISTATE_SEND_STATUS;
spin_unlock_bh(&cmd->istate_lock);
+ state = ISTATE_SEND_STATUS;
+ goto check_rsp_state;
+ }
+
+ break;
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ ret = iscsit_send_response(cmd, conn);
+ break;
+ case ISTATE_SEND_LOGOUTRSP:
+ ret = iscsit_send_logout(cmd, conn);
+ break;
+ case ISTATE_SEND_ASYNCMSG:
+ ret = iscsit_send_conn_drop_async_message(
+ cmd, conn);
+ break;
+ case ISTATE_SEND_NOPIN:
+ ret = iscsit_send_nopin(cmd, conn);
+ break;
+ case ISTATE_SEND_REJECT:
+ ret = iscsit_send_reject(cmd, conn);
+ break;
+ case ISTATE_SEND_TASKMGTRSP:
+ ret = iscsit_send_task_mgt_rsp(cmd, conn);
+ if (ret != 0)
break;
- case ISTATE_SEND_REJECT:
- if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
- cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
- complete(&cmd->reject_comp);
- goto err;
- }
+ ret = iscsit_tmr_post_handler(cmd, conn);
+ if (ret != 0)
+ iscsit_fall_back_to_erl0(conn->sess);
+ break;
+ case ISTATE_SEND_TEXTRSP:
+ ret = iscsit_send_text_rsp(cmd, conn);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ state, conn->cid);
+ goto err;
+ }
+ if (ret < 0)
+ goto err;
+
+ if (iscsit_send_tx_data(cmd, conn, 1) < 0) {
+ iscsit_tx_thread_wait_for_tcp(conn);
+ iscsit_unmap_iovec(cmd);
+ goto err;
+ }
+ iscsit_unmap_iovec(cmd);
+
+ switch (state) {
+ case ISTATE_SEND_LOGOUTRSP:
+ if (!iscsit_logout_post_handler(cmd, conn))
+ goto restart;
+ /* fall through */
+ case ISTATE_SEND_STATUS:
+ case ISTATE_SEND_ASYNCMSG:
+ case ISTATE_SEND_NOPIN:
+ case ISTATE_SEND_STATUS_RECOVERY:
+ case ISTATE_SEND_TEXTRSP:
+ case ISTATE_SEND_TASKMGTRSP:
+ spin_lock_bh(&cmd->istate_lock);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ spin_unlock_bh(&cmd->istate_lock);
+ break;
+ case ISTATE_SEND_REJECT:
+ if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) {
+ cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN;
complete(&cmd->reject_comp);
- break;
- default:
- pr_err("Unknown Opcode: 0x%02x ITT:"
- " 0x%08x, i_state: %d on CID: %hu\n",
- cmd->iscsi_opcode, cmd->init_task_tag,
- cmd->i_state, conn->cid);
goto err;
}
-
- if (atomic_read(&conn->check_immediate_queue))
- return 1;
+ complete(&cmd->reject_comp);
+ break;
+ default:
+ pr_err("Unknown Opcode: 0x%02x ITT:"
+ " 0x%08x, i_state: %d on CID: %hu\n",
+ cmd->iscsi_opcode, cmd->init_task_tag,
+ cmd->i_state, conn->cid);
+ goto err;
}
+ if (atomic_read(&conn->check_immediate_queue))
+ return 1;
+
return 0;
err:
@@ -3688,6 +3848,27 @@ restart:
return -EAGAIN;
}
+static int iscsit_handle_response_queue(struct iscsi_conn *conn)
+{
+ struct iscsit_transport *t = conn->conn_transport;
+ struct iscsi_queue_req *qr;
+ struct iscsi_cmd *cmd;
+ u8 state;
+ int ret;
+
+ while ((qr = iscsit_get_cmd_from_response_queue(conn))) {
+ cmd = qr->cmd;
+ state = qr->state;
+ kmem_cache_free(lio_qr_cache, qr);
+
+ ret = t->iscsit_response_queue(conn, cmd, state);
+ if (ret == 1 || ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
int iscsi_target_tx_thread(void *arg)
{
int ret = 0;
@@ -3722,11 +3903,11 @@ restart:
goto transport_err;
get_immediate:
- ret = handle_immediate_queue(conn);
+ ret = iscsit_handle_immediate_queue(conn);
if (ret < 0)
goto transport_err;
- ret = handle_response_queue(conn);
+ ret = iscsit_handle_response_queue(conn);
if (ret == 1)
goto get_immediate;
else if (ret == -EAGAIN)
@@ -3742,6 +3923,83 @@ out:
return 0;
}
+static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
+{
+ struct iscsi_hdr *hdr = (struct iscsi_hdr *)buf;
+ struct iscsi_cmd *cmd;
+ int ret = 0;
+
+ switch (hdr->opcode & ISCSI_OPCODE_MASK) {
+ case ISCSI_OP_SCSI_CMD:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_scsi_cmd(conn, cmd, buf);
+ break;
+ case ISCSI_OP_SCSI_DATA_OUT:
+ ret = iscsit_handle_data_out(conn, buf);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ cmd = NULL;
+ if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+ }
+ ret = iscsit_handle_nop_out(conn, cmd, buf);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
+ break;
+ case ISCSI_OP_TEXT:
+ ret = iscsit_handle_text_cmd(conn, buf);
+ break;
+ case ISCSI_OP_LOGOUT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES,
+ 1, buf, conn);
+
+ ret = iscsit_handle_logout_cmd(conn, cmd, buf);
+ if (ret > 0)
+ wait_for_completion_timeout(&conn->conn_logout_comp,
+ SECONDS_FOR_LOGOUT_COMP * HZ);
+ break;
+ case ISCSI_OP_SNACK:
+ ret = iscsit_handle_snack(conn, buf);
+ break;
+ default:
+ pr_err("Got unknown iSCSI OpCode: 0x%02x\n", hdr->opcode);
+ if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
+ pr_err("Cannot recover from unknown"
+ " opcode while ERL=0, closing iSCSI connection.\n");
+ return -1;
+ }
+ if (!conn->conn_ops->OFMarker) {
+ pr_err("Unable to recover from unknown"
+ " opcode while OFMarker=No, closing iSCSI"
+ " connection.\n");
+ return -1;
+ }
+ if (iscsit_recover_from_unknown_opcode(conn) < 0) {
+ pr_err("Unable to recover from unknown"
+ " opcode, closing iSCSI connection.\n");
+ return -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
int iscsi_target_rx_thread(void *arg)
{
int ret;
@@ -3761,6 +4019,18 @@ restart:
if (!conn)
goto out;
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
+ struct completion comp;
+ int rc;
+
+ init_completion(&comp);
+ rc = wait_for_completion_interruptible(&comp);
+ if (rc < 0)
+ goto transport_err;
+
+ goto out;
+ }
+
while (!kthread_should_stop()) {
/*
* Ensure that both TX and RX per connection kthreads
@@ -3832,62 +4102,9 @@ restart:
goto transport_err;
}
- switch (opcode) {
- case ISCSI_OP_SCSI_CMD:
- if (iscsit_handle_scsi_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SCSI_DATA_OUT:
- if (iscsit_handle_data_out(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_NOOP_OUT:
- if (iscsit_handle_nop_out(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SCSI_TMFUNC:
- if (iscsit_handle_task_mgt_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_TEXT:
- if (iscsit_handle_text_cmd(conn, buffer) < 0)
- goto transport_err;
- break;
- case ISCSI_OP_LOGOUT:
- ret = iscsit_handle_logout_cmd(conn, buffer);
- if (ret > 0) {
- wait_for_completion_timeout(&conn->conn_logout_comp,
- SECONDS_FOR_LOGOUT_COMP * HZ);
- goto transport_err;
- } else if (ret < 0)
- goto transport_err;
- break;
- case ISCSI_OP_SNACK:
- if (iscsit_handle_snack(conn, buffer) < 0)
- goto transport_err;
- break;
- default:
- pr_err("Got unknown iSCSI OpCode: 0x%02x\n",
- opcode);
- if (!conn->sess->sess_ops->ErrorRecoveryLevel) {
- pr_err("Cannot recover from unknown"
- " opcode while ERL=0, closing iSCSI connection"
- ".\n");
- goto transport_err;
- }
- if (!conn->conn_ops->OFMarker) {
- pr_err("Unable to recover from unknown"
- " opcode while OFMarker=No, closing iSCSI"
- " connection.\n");
- goto transport_err;
- }
- if (iscsit_recover_from_unknown_opcode(conn) < 0) {
- pr_err("Unable to recover from unknown"
- " opcode, closing iSCSI connection.\n");
- goto transport_err;
- }
- break;
- }
+ ret = iscsi_target_rx_opcode(conn, buffer);
+ if (ret < 0)
+ goto transport_err;
}
transport_err:
@@ -4053,6 +4270,12 @@ int iscsit_close_connection(
if (conn->sock)
sock_release(conn->sock);
+
+ if (conn->conn_transport->iscsit_free_conn)
+ conn->conn_transport->iscsit_free_conn(conn);
+
+ iscsit_put_transport(conn->conn_transport);
+
conn->thread_set = NULL;
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
@@ -4284,7 +4507,7 @@ static void iscsit_logout_post_handler_diffcid(
/*
* Return of 0 causes the TX thread to restart.
*/
-static int iscsit_logout_post_handler(
+int iscsit_logout_post_handler(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
{
@@ -4342,6 +4565,7 @@ static int iscsit_logout_post_handler(
}
return ret;
}
+EXPORT_SYMBOL(iscsit_logout_post_handler);
void iscsit_fail_session(struct iscsi_session *sess)
{
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h
index b1a1e6350707..a0050b2f294e 100644
--- a/drivers/target/iscsi/iscsi_target.h
+++ b/drivers/target/iscsi/iscsi_target.h
@@ -16,11 +16,12 @@ extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
struct iscsi_portal_group *);
extern int iscsit_del_np(struct iscsi_np *);
extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *);
+extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *);
extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8);
-extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, bool recovery);
+extern int iscsit_build_r2ts_for_cmd(struct iscsi_conn *, struct iscsi_cmd *, bool recovery);
extern void iscsit_thread_get_cpumask(struct iscsi_conn *);
extern int iscsi_target_tx_thread(void *);
extern int iscsi_target_rx_thread(void *);
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index a0fc7b9eea65..cee17543278c 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -49,32 +49,6 @@ static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len)
}
}
-static void chap_set_random(char *data, int length)
-{
- long r;
- unsigned n;
-
- while (length > 0) {
- get_random_bytes(&r, sizeof(long));
- r = r ^ (r >> 8);
- r = r ^ (r >> 4);
- n = r & 0x7;
-
- get_random_bytes(&r, sizeof(long));
- r = r ^ (r >> 8);
- r = r ^ (r >> 5);
- n = (n << 3) | (r & 0x7);
-
- get_random_bytes(&r, sizeof(long));
- r = r ^ (r >> 8);
- r = r ^ (r >> 5);
- n = (n << 2) | (r & 0x3);
-
- *data++ = n;
- length--;
- }
-}
-
static void chap_gen_challenge(
struct iscsi_conn *conn,
int caller,
@@ -86,7 +60,7 @@ static void chap_gen_challenge(
memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1);
- chap_set_random(chap->challenge, CHAP_CHALLENGE_LENGTH);
+ get_random_bytes(chap->challenge, CHAP_CHALLENGE_LENGTH);
chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge,
CHAP_CHALLENGE_LENGTH);
/*
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 78d75c8567d0..13e9e715ad2e 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -27,6 +27,7 @@
#include <target/target_core_fabric_configfs.h>
#include <target/target_core_configfs.h>
#include <target/configfs_macros.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -124,8 +125,87 @@ out:
TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR);
+static ssize_t lio_target_np_show_iser(
+ struct se_tpg_np *se_tpg_np,
+ char *page)
+{
+ struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+ struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np_iser;
+ ssize_t rb;
+
+ tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND);
+ if (tpg_np_iser)
+ rb = sprintf(page, "1\n");
+ else
+ rb = sprintf(page, "0\n");
+
+ return rb;
+}
+
+static ssize_t lio_target_np_store_iser(
+ struct se_tpg_np *se_tpg_np,
+ const char *page,
+ size_t count)
+{
+ struct iscsi_np *np;
+ struct iscsi_portal_group *tpg;
+ struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
+ struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np_iser = NULL;
+ char *endptr;
+ u32 op;
+ int rc;
+
+ op = simple_strtoul(page, &endptr, 0);
+ if ((op != 1) && (op != 0)) {
+ pr_err("Illegal value for tpg_enable: %u\n", op);
+ return -EINVAL;
+ }
+ np = tpg_np->tpg_np;
+ if (!np) {
+ pr_err("Unable to locate struct iscsi_np from"
+ " struct iscsi_tpg_np\n");
+ return -EINVAL;
+ }
+
+ tpg = tpg_np->tpg;
+ if (iscsit_get_tpg(tpg) < 0)
+ return -EINVAL;
+
+ if (op) {
+ int rc = request_module("ib_isert");
+ if (rc != 0)
+ pr_warn("Unable to request_module for ib_isert\n");
+
+ tpg_np_iser = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr,
+ np->np_ip, tpg_np, ISCSI_INFINIBAND);
+ if (!tpg_np_iser || IS_ERR(tpg_np_iser))
+ goto out;
+ } else {
+ tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND);
+ if (!tpg_np_iser)
+ goto out;
+
+ rc = iscsit_tpg_del_network_portal(tpg, tpg_np_iser);
+ if (rc < 0)
+ goto out;
+ }
+
+ printk("lio_target_np_store_iser() done, op: %d\n", op);
+
+ iscsit_put_tpg(tpg);
+ return count;
+out:
+ iscsit_put_tpg(tpg);
+ return -EINVAL;
+}
+
+TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR);
+
static struct configfs_attribute *lio_target_portal_attrs[] = {
&lio_target_np_sctp.attr,
+ &lio_target_np_iser.attr,
NULL,
};
@@ -1536,16 +1616,18 @@ static int lio_queue_data_in(struct se_cmd *se_cmd)
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
cmd->i_state = ISTATE_SEND_DATAIN;
- iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+ cmd->conn->conn_transport->iscsit_queue_data_in(cmd->conn, cmd);
+
return 0;
}
static int lio_write_pending(struct se_cmd *se_cmd)
{
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
+ struct iscsi_conn *conn = cmd->conn;
if (!cmd->immediate_data && !cmd->unsolicited_data)
- return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false);
+ return conn->conn_transport->iscsit_get_dataout(conn, cmd, false);
return 0;
}
@@ -1567,7 +1649,8 @@ static int lio_queue_status(struct se_cmd *se_cmd)
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
cmd->i_state = ISTATE_SEND_STATUS;
- iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state);
+ cmd->conn->conn_transport->iscsit_queue_status(cmd->conn, cmd);
+
return 0;
}
@@ -1696,11 +1779,17 @@ static void lio_set_default_node_attributes(struct se_node_acl *se_acl)
iscsit_set_default_node_attribues(acl);
}
+static int lio_check_stop_free(struct se_cmd *se_cmd)
+{
+ return target_put_sess_cmd(se_cmd->se_sess, se_cmd);
+}
+
static void lio_release_cmd(struct se_cmd *se_cmd)
{
struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
- iscsit_release_cmd(cmd);
+ pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd);
+ cmd->release_cmd(cmd);
}
/* End functions for target_core_fabric_ops */
@@ -1740,6 +1829,7 @@ int iscsi_target_register_configfs(void)
fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl;
fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl;
fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index;
+ fabric->tf_ops.check_stop_free = &lio_check_stop_free,
fabric->tf_ops.release_cmd = &lio_release_cmd;
fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session;
fabric->tf_ops.close_session = &lio_tpg_close_session;
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
index 7a333d28d9a2..60ec4b92be03 100644
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ b/drivers/target/iscsi/iscsi_target_core.h
@@ -60,7 +60,7 @@
#define ISCSI_IOV_DATA_BUFFER 5
-enum tpg_np_network_transport_table {
+enum iscsit_transport_type {
ISCSI_TCP = 0,
ISCSI_SCTP_TCP = 1,
ISCSI_SCTP_UDP = 2,
@@ -244,6 +244,11 @@ struct iscsi_conn_ops {
u8 IFMarker; /* [0,1] == [No,Yes] */
u32 OFMarkInt; /* [1..65535] */
u32 IFMarkInt; /* [1..65535] */
+ /*
+ * iSER specific connection parameters
+ */
+ u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */
+ u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */
};
struct iscsi_sess_ops {
@@ -265,6 +270,10 @@ struct iscsi_sess_ops {
u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */
u8 ErrorRecoveryLevel; /* [0..2] */
u8 SessionType; /* [0,1] == [Normal,Discovery]*/
+ /*
+ * iSER specific session parameters
+ */
+ u8 RDMAExtensions; /* [0,1] == [No,Yes] */
};
struct iscsi_queue_req {
@@ -284,6 +293,7 @@ struct iscsi_data_count {
};
struct iscsi_param_list {
+ bool iser;
struct list_head param_list;
struct list_head extra_response_list;
};
@@ -475,6 +485,7 @@ struct iscsi_cmd {
u32 first_data_sg_off;
u32 kmapped_nents;
sense_reason_t sense_reason;
+ void (*release_cmd)(struct iscsi_cmd *);
} ____cacheline_aligned;
struct iscsi_tmr_req {
@@ -503,6 +514,7 @@ struct iscsi_conn {
u16 login_port;
u16 local_port;
int net_size;
+ int login_family;
u32 auth_id;
u32 conn_flags;
/* Used for iscsi_tx_login_rsp() */
@@ -562,9 +574,12 @@ struct iscsi_conn {
struct list_head immed_queue_list;
struct list_head response_queue_list;
struct iscsi_conn_ops *conn_ops;
+ struct iscsi_login *conn_login;
+ struct iscsit_transport *conn_transport;
struct iscsi_param_list *param_list;
/* Used for per connection auth state machine */
void *auth_protocol;
+ void *context;
struct iscsi_login_thread_s *login_thread;
struct iscsi_portal_group *tpg;
/* Pointer to parent session */
@@ -663,6 +678,8 @@ struct iscsi_login {
u8 first_request;
u8 version_min;
u8 version_max;
+ u8 login_complete;
+ u8 login_failed;
char isid[6];
u32 cmd_sn;
itt_t init_task_tag;
@@ -670,10 +687,11 @@ struct iscsi_login {
u32 rsp_length;
u16 cid;
u16 tsih;
- char *req;
- char *rsp;
+ char req[ISCSI_HDR_LEN];
+ char rsp[ISCSI_HDR_LEN];
char *req_buf;
char *rsp_buf;
+ struct iscsi_conn *conn;
} ____cacheline_aligned;
struct iscsi_node_attrib {
@@ -754,6 +772,8 @@ struct iscsi_np {
struct task_struct *np_thread;
struct timer_list np_login_timer;
struct iscsi_portal_group *np_login_tpg;
+ void *np_context;
+ struct iscsit_transport *np_transport;
struct list_head np_list;
} ____cacheline_aligned;
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
index bcc409853a67..1b74033510a0 100644
--- a/drivers/target/iscsi/iscsi_target_device.c
+++ b/drivers/target/iscsi/iscsi_target_device.c
@@ -60,8 +60,13 @@ void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess
cmd->maxcmdsn_inc = 1;
- mutex_lock(&sess->cmdsn_mutex);
+ if (!mutex_trylock(&sess->cmdsn_mutex)) {
+ sess->max_cmd_sn += 1;
+ pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn);
+ return;
+ }
sess->max_cmd_sn += 1;
pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn);
mutex_unlock(&sess->cmdsn_mutex);
}
+EXPORT_SYMBOL(iscsit_increment_maxcmdsn);
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 0b52a2371305..7816af6cdd12 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -22,6 +22,7 @@
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_seq_pdu_list.h"
@@ -53,6 +54,9 @@ int iscsit_dump_data_payload(
u32 length, padding, offset = 0, size;
struct kvec iov;
+ if (conn->sess->sess_ops->RDMAExtensions)
+ return 0;
+
length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len;
buf = kzalloc(length, GFP_ATOMIC);
@@ -919,6 +923,7 @@ int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess)
int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
{
struct se_cmd *se_cmd = &cmd->se_cmd;
+ struct iscsi_conn *conn = cmd->conn;
int lr = 0;
spin_lock_bh(&cmd->istate_lock);
@@ -981,7 +986,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
return 0;
iscsit_set_dataout_sequence_values(cmd);
- iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false);
+ conn->conn_transport->iscsit_get_dataout(conn, cmd, false);
}
return 0;
}
@@ -999,10 +1004,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo)
if (transport_check_aborted_status(se_cmd, 1) != 0)
return 0;
- iscsit_set_dataout_sequence_values(cmd);
- spin_lock_bh(&cmd->dataout_timeout_lock);
- iscsit_start_dataout_timer(cmd, cmd->conn);
- spin_unlock_bh(&cmd->dataout_timeout_lock);
+ iscsit_set_unsoliticed_dataout(cmd);
}
return transport_handle_cdb_direct(&cmd->se_cmd);
@@ -1290,3 +1292,4 @@ void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd)
cmd->init_task_tag);
spin_unlock_bh(&cmd->dataout_timeout_lock);
}
+EXPORT_SYMBOL(iscsit_stop_dataout_timer);
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 2535d4d46c0e..bb5d5c5bce65 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -39,8 +39,39 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"
-static int iscsi_login_init_conn(struct iscsi_conn *conn)
+#include <target/iscsi/iscsi_transport.h>
+
+static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
{
+ struct iscsi_login *login;
+
+ login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
+ if (!login) {
+ pr_err("Unable to allocate memory for struct iscsi_login.\n");
+ return NULL;
+ }
+ login->conn = conn;
+ login->first_request = 1;
+
+ login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ if (!login->req_buf) {
+ pr_err("Unable to allocate memory for response buffer.\n");
+ goto out_login;
+ }
+
+ login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+ if (!login->rsp_buf) {
+ pr_err("Unable to allocate memory for request buffer.\n");
+ goto out_req_buf;
+ }
+
+ conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
+ if (!conn->conn_ops) {
+ pr_err("Unable to allocate memory for"
+ " struct iscsi_conn_ops.\n");
+ goto out_rsp_buf;
+ }
+
init_waitqueue_head(&conn->queues_wq);
INIT_LIST_HEAD(&conn->conn_list);
INIT_LIST_HEAD(&conn->conn_cmd_list);
@@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn)
if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
pr_err("Unable to allocate conn->conn_cpumask\n");
- return -ENOMEM;
+ goto out_conn_ops;
}
+ conn->conn_login = login;
- return 0;
+ return login;
+
+out_conn_ops:
+ kfree(conn->conn_ops);
+out_rsp_buf:
+ kfree(login->rsp_buf);
+out_req_buf:
+ kfree(login->req_buf);
+out_login:
+ kfree(login);
+ return NULL;
}
/*
@@ -298,6 +340,7 @@ static int iscsi_login_zero_tsih_s2(
struct iscsi_node_attrib *na;
struct iscsi_session *sess = conn->sess;
unsigned char buf[32];
+ bool iser = false;
sess->tpg = conn->tpg;
@@ -319,7 +362,10 @@ static int iscsi_login_zero_tsih_s2(
return -1;
}
- iscsi_set_keys_to_negotiate(0, conn->param_list);
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
+ iser = true;
+
+ iscsi_set_keys_to_negotiate(conn->param_list, iser);
if (sess->sess_ops->SessionType)
return iscsi_set_keys_irrelevant_for_discovery(
@@ -357,6 +403,56 @@ static int iscsi_login_zero_tsih_s2(
if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
return -1;
+ /*
+ * Set RDMAExtensions=Yes by default for iSER enabled network portals
+ */
+ if (iser) {
+ struct iscsi_param *param;
+ unsigned long mrdsl, off;
+ int rc;
+
+ sprintf(buf, "RDMAExtensions=Yes");
+ if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ /*
+ * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
+ * Immediate Data + Unsolicitied Data-OUT if necessary..
+ */
+ param = iscsi_find_param_from_key("MaxRecvDataSegmentLength",
+ conn->param_list);
+ if (!param) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ rc = strict_strtoul(param->value, 0, &mrdsl);
+ if (rc < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ off = mrdsl % PAGE_SIZE;
+ if (!off)
+ return 0;
+
+ if (mrdsl < PAGE_SIZE)
+ mrdsl = PAGE_SIZE;
+ else
+ mrdsl -= off;
+
+ pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
+ " to PAGE_SIZE\n", mrdsl);
+
+ sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl);
+ if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_NO_RESOURCES);
+ return -1;
+ }
+ }
return 0;
}
@@ -436,6 +532,7 @@ static int iscsi_login_non_zero_tsih_s2(
struct se_portal_group *se_tpg = &tpg->tpg_se_tpg;
struct se_session *se_sess, *se_sess_tmp;
struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf;
+ bool iser = false;
spin_lock_bh(&se_tpg->session_lock);
list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list,
@@ -485,7 +582,10 @@ static int iscsi_login_non_zero_tsih_s2(
return -1;
}
- iscsi_set_keys_to_negotiate(0, conn->param_list);
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
+ iser = true;
+
+ iscsi_set_keys_to_negotiate(conn->param_list, iser);
/*
* Need to send TargetPortalGroupTag back in first login response
* on any iSCSI connection where the Initiator provides TargetName.
@@ -574,6 +674,11 @@ int iscsi_login_post_auth_non_zero_tsih(
static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
{
struct iscsi_session *sess = conn->sess;
+ /*
+ * FIXME: Unsolicitied NopIN support for ISER
+ */
+ if (conn->conn_transport->transport_type == ISCSI_INFINIBAND)
+ return;
if (!sess->sess_ops->SessionType)
iscsit_start_nopin_timer(conn);
@@ -632,6 +737,7 @@ static int iscsi_post_login_handler(
spin_unlock_bh(&sess->conn_lock);
iscsi_post_login_start_timers(conn);
+
iscsi_activate_thread_set(conn, ts);
/*
* Determine CPU mask to ensure connection's RX and TX kthreads
@@ -761,11 +867,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
spin_unlock_bh(&np->np_thread_lock);
}
-int iscsi_target_setup_login_socket(
+int iscsit_setup_np(
struct iscsi_np *np,
struct __kernel_sockaddr_storage *sockaddr)
{
- struct socket *sock;
+ struct socket *sock = NULL;
int backlog = 5, ret, opt = 0, len;
switch (np->np_network_transport) {
@@ -781,15 +887,15 @@ int iscsi_target_setup_login_socket(
np->np_ip_proto = IPPROTO_SCTP;
np->np_sock_type = SOCK_SEQPACKET;
break;
- case ISCSI_IWARP_TCP:
- case ISCSI_IWARP_SCTP:
- case ISCSI_INFINIBAND:
default:
pr_err("Unsupported network_transport: %d\n",
np->np_network_transport);
return -EINVAL;
}
+ np->np_ip_proto = IPPROTO_TCP;
+ np->np_sock_type = SOCK_STREAM;
+
ret = sock_create(sockaddr->ss_family, np->np_sock_type,
np->np_ip_proto, &sock);
if (ret < 0) {
@@ -853,7 +959,6 @@ int iscsi_target_setup_login_socket(
}
return 0;
-
fail:
np->np_socket = NULL;
if (sock)
@@ -861,21 +966,169 @@ fail:
return ret;
}
+int iscsi_target_setup_login_socket(
+ struct iscsi_np *np,
+ struct __kernel_sockaddr_storage *sockaddr)
+{
+ struct iscsit_transport *t;
+ int rc;
+
+ t = iscsit_get_transport(np->np_network_transport);
+ if (!t)
+ return -EINVAL;
+
+ rc = t->iscsit_setup_np(np, sockaddr);
+ if (rc < 0) {
+ iscsit_put_transport(t);
+ return rc;
+ }
+
+ np->np_transport = t;
+ printk("Set np->np_transport to %p -> %s\n", np->np_transport,
+ np->np_transport->name);
+ return 0;
+}
+
+int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
+{
+ struct socket *new_sock, *sock = np->np_socket;
+ struct sockaddr_in sock_in;
+ struct sockaddr_in6 sock_in6;
+ int rc, err;
+
+ rc = kernel_accept(sock, &new_sock, 0);
+ if (rc < 0)
+ return rc;
+
+ conn->sock = new_sock;
+ conn->login_family = np->np_sockaddr.ss_family;
+ printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock);
+
+ if (np->np_sockaddr.ss_family == AF_INET6) {
+ memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in6, &err, 1);
+ if (!rc) {
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6.sin6_port);
+ }
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in6, &err, 0);
+ if (!rc) {
+ snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->local_port = ntohs(sock_in6.sin6_port);
+ }
+ } else {
+ memset(&sock_in, 0, sizeof(struct sockaddr_in));
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in, &err, 1);
+ if (!rc) {
+ sprintf(conn->login_ip, "%pI4",
+ &sock_in.sin_addr.s_addr);
+ conn->login_port = ntohs(sock_in.sin_port);
+ }
+
+ rc = conn->sock->ops->getname(conn->sock,
+ (struct sockaddr *)&sock_in, &err, 0);
+ if (!rc) {
+ sprintf(conn->local_ip, "%pI4",
+ &sock_in.sin_addr.s_addr);
+ conn->local_port = ntohs(sock_in.sin_port);
+ }
+ }
+
+ return 0;
+}
+
+int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+ struct iscsi_login_req *login_req;
+ u32 padding = 0, payload_length;
+
+ if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
+ return -1;
+
+ login_req = (struct iscsi_login_req *)login->req;
+ payload_length = ntoh24(login_req->dlength);
+ padding = ((-payload_length) & 3);
+
+ pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
+ " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
+ login_req->flags, login_req->itt, login_req->cmdsn,
+ login_req->exp_statsn, login_req->cid, payload_length);
+ /*
+ * Setup the initial iscsi_login values from the leading
+ * login request PDU.
+ */
+ if (login->first_request) {
+ login_req = (struct iscsi_login_req *)login->req;
+ login->leading_connection = (!login_req->tsih) ? 1 : 0;
+ login->current_stage = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags);
+ login->version_min = login_req->min_version;
+ login->version_max = login_req->max_version;
+ memcpy(login->isid, login_req->isid, 6);
+ login->cmd_sn = be32_to_cpu(login_req->cmdsn);
+ login->init_task_tag = login_req->itt;
+ login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+ login->cid = be16_to_cpu(login_req->cid);
+ login->tsih = be16_to_cpu(login_req->tsih);
+ }
+
+ if (iscsi_target_check_login_request(conn, login) < 0)
+ return -1;
+
+ memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
+ if (iscsi_login_rx_data(conn, login->req_buf,
+ payload_length + padding) < 0)
+ return -1;
+
+ return 0;
+}
+
+int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
+ u32 length)
+{
+ if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
+{
+ int rc;
+
+ if (!t->owner) {
+ conn->conn_transport = t;
+ return 0;
+ }
+
+ rc = try_module_get(t->owner);
+ if (!rc) {
+ pr_err("try_module_get() failed for %s\n", t->name);
+ return -EINVAL;
+ }
+
+ conn->conn_transport = t;
+ return 0;
+}
+
static int __iscsi_target_login_thread(struct iscsi_np *np)
{
- u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
- int err, ret = 0, stop;
+ u8 *buffer, zero_tsih = 0;
+ int ret = 0, rc, stop;
struct iscsi_conn *conn = NULL;
struct iscsi_login *login;
struct iscsi_portal_group *tpg = NULL;
- struct socket *new_sock, *sock;
- struct kvec iov;
struct iscsi_login_req *pdu;
- struct sockaddr_in sock_in;
- struct sockaddr_in6 sock_in6;
flush_signals(current);
- sock = np->np_socket;
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
@@ -886,75 +1139,76 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
spin_unlock_bh(&np->np_thread_lock);
- if (kernel_accept(sock, &new_sock, 0) < 0) {
- spin_lock_bh(&np->np_thread_lock);
- if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
- spin_unlock_bh(&np->np_thread_lock);
- complete(&np->np_restart_comp);
- /* Get another socket */
- return 1;
- }
- spin_unlock_bh(&np->np_thread_lock);
- goto out;
- }
- iscsi_start_login_thread_timer(np);
-
conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
if (!conn) {
pr_err("Could not allocate memory for"
" new connection\n");
- sock_release(new_sock);
/* Get another socket */
return 1;
}
-
pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
conn->conn_state = TARG_CONN_STATE_FREE;
- conn->sock = new_sock;
- pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
- conn->conn_state = TARG_CONN_STATE_XPT_UP;
+ if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
+ kfree(conn);
+ return 1;
+ }
- /*
- * Allocate conn->conn_ops early as a failure calling
- * iscsit_tx_login_rsp() below will call tx_data().
- */
- conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
- if (!conn->conn_ops) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_conn_ops.\n");
- goto new_sess_out;
+ rc = np->np_transport->iscsit_accept_np(np, conn);
+ if (rc == -ENOSYS) {
+ complete(&np->np_restart_comp);
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto exit;
+ } else if (rc < 0) {
+ spin_lock_bh(&np->np_thread_lock);
+ if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+ spin_unlock_bh(&np->np_thread_lock);
+ complete(&np->np_restart_comp);
+ if (ret == -ENODEV) {
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto out;
+ }
+ /* Get another socket */
+ return 1;
+ }
+ spin_unlock_bh(&np->np_thread_lock);
+ iscsit_put_transport(conn->conn_transport);
+ kfree(conn);
+ conn = NULL;
+ goto out;
}
/*
* Perform the remaining iSCSI connection initialization items..
*/
- if (iscsi_login_init_conn(conn) < 0)
- goto new_sess_out;
-
- memset(buffer, 0, ISCSI_HDR_LEN);
- memset(&iov, 0, sizeof(struct kvec));
- iov.iov_base = buffer;
- iov.iov_len = ISCSI_HDR_LEN;
-
- if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
- pr_err("rx_data() returned an error.\n");
+ login = iscsi_login_init_conn(conn);
+ if (!login) {
goto new_sess_out;
}
- iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
- if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
- pr_err("First opcode is not login request,"
- " failing login request.\n");
- goto new_sess_out;
- }
+ iscsi_start_login_thread_timer(np);
- pdu = (struct iscsi_login_req *) buffer;
+ pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
+ conn->conn_state = TARG_CONN_STATE_XPT_UP;
+ /*
+ * This will process the first login request + payload..
+ */
+ rc = np->np_transport->iscsit_get_login_rx(conn, login);
+ if (rc == 1)
+ return 1;
+ else if (rc < 0)
+ goto new_sess_out;
+ buffer = &login->req[0];
+ pdu = (struct iscsi_login_req *)buffer;
/*
* Used by iscsit_tx_login_rsp() for Login Resonses PDUs
* when Status-Class != 0.
*/
- conn->login_itt = pdu->itt;
+ conn->login_itt = pdu->itt;
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
@@ -967,61 +1221,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
spin_unlock_bh(&np->np_thread_lock);
- if (np->np_sockaddr.ss_family == AF_INET6) {
- memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in6, &err, 1) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
- &sock_in6.sin6_addr.in6_u);
- conn->login_port = ntohs(sock_in6.sin6_port);
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in6, &err, 0) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
- &sock_in6.sin6_addr.in6_u);
- conn->local_port = ntohs(sock_in6.sin6_port);
-
- } else {
- memset(&sock_in, 0, sizeof(struct sockaddr_in));
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in, &err, 1) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
- conn->login_port = ntohs(sock_in.sin_port);
-
- if (conn->sock->ops->getname(conn->sock,
- (struct sockaddr *)&sock_in, &err, 0) < 0) {
- pr_err("sock_ops->getname() failed.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
- sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
- conn->local_port = ntohs(sock_in.sin_port);
- }
-
conn->network_transport = np->np_network_transport;
pr_debug("Received iSCSI login request from %s on %s Network"
- " Portal %s:%hu\n", conn->login_ip,
- (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
- conn->local_ip, conn->local_port);
+ " Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
+ conn->local_ip, conn->local_port);
pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
conn->conn_state = TARG_CONN_STATE_IN_LOGIN;
@@ -1050,13 +1254,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
goto new_sess_out;
}
-
/*
- * This will process the first login request, and call
- * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
+ * SessionType: Discovery
+ *
+ * Locates Default Portal
+ *
+ * SessionType: Normal
+ *
+ * Locates Target Portal from NP -> Target IQN
*/
- login = iscsi_target_init_negotiation(np, conn, buffer);
- if (!login) {
+ rc = iscsi_target_locate_portal(np, conn, login);
+ if (rc < 0) {
tpg = conn->tpg;
goto new_sess_out;
}
@@ -1068,15 +1276,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
}
if (zero_tsih) {
- if (iscsi_login_zero_tsih_s2(conn) < 0) {
- iscsi_target_nego_release(login, conn);
+ if (iscsi_login_zero_tsih_s2(conn) < 0)
goto new_sess_out;
- }
} else {
- if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
- iscsi_target_nego_release(login, conn);
+ if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
goto old_sess_out;
- }
}
if (iscsi_target_start_negotiation(login, conn) < 0)
@@ -1153,8 +1357,18 @@ old_sess_out:
iscsi_release_param_list(conn->param_list);
conn->param_list = NULL;
}
- if (conn->sock)
+ iscsi_target_nego_release(conn);
+
+ if (conn->sock) {
sock_release(conn->sock);
+ conn->sock = NULL;
+ }
+
+ if (conn->conn_transport->iscsit_free_conn)
+ conn->conn_transport->iscsit_free_conn(conn);
+
+ iscsit_put_transport(conn->conn_transport);
+
kfree(conn);
if (tpg) {
@@ -1172,11 +1386,13 @@ out:
/* Wait for another socket.. */
if (!stop)
return 1;
-
+exit:
iscsi_stop_login_thread_timer(np);
spin_lock_bh(&np->np_thread_lock);
np->np_thread_state = ISCSI_NP_THREAD_EXIT;
+ np->np_thread = NULL;
spin_unlock_bh(&np->np_thread_lock);
+
return 0;
}
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h
index 091dcae2532b..63efd2878451 100644
--- a/drivers/target/iscsi/iscsi_target_login.h
+++ b/drivers/target/iscsi/iscsi_target_login.h
@@ -4,8 +4,14 @@
extern int iscsi_login_setup_crypto(struct iscsi_conn *);
extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
+extern int iscsit_setup_np(struct iscsi_np *,
+ struct __kernel_sockaddr_storage *);
extern int iscsi_target_setup_login_socket(struct iscsi_np *,
struct __kernel_sockaddr_storage *);
+extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
+extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
+extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
+extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
extern int iscsi_target_login_thread(void *);
extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 9d902aefe01a..7ad912060e21 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -22,6 +22,7 @@
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
kfree(conn->auth_protocol);
}
-static int iscsi_target_check_login_request(
+int iscsi_target_check_login_request(
struct iscsi_conn *conn,
struct iscsi_login *login)
{
@@ -200,8 +201,8 @@ static int iscsi_target_check_login_request(
return -1;
}
- req_csg = (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
- req_nsg = (login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK);
+ req_csg = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags);
+ req_nsg = ISCSI_LOGIN_NEXT_STAGE(login_req->flags);
if (req_csg != login->current_stage) {
pr_err("Initiator unexpectedly changed login stage"
@@ -352,11 +353,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
padding = ((-login->rsp_length) & 3);
- if (iscsi_login_tx_data(
- conn,
- login->rsp,
- login->rsp_buf,
- login->rsp_length + padding) < 0)
+ if (conn->conn_transport->iscsit_put_login_tx(conn, login,
+ login->rsp_length + padding) < 0)
return -1;
login->rsp_length = 0;
@@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
return 0;
}
-static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
-{
- u32 padding = 0, payload_length;
- struct iscsi_login_req *login_req;
-
- if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
- return -1;
-
- login_req = (struct iscsi_login_req *) login->req;
- payload_length = ntoh24(login_req->dlength);
-
- pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
- " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
- login_req->flags, login_req->itt, login_req->cmdsn,
- login_req->exp_statsn, login_req->cid, payload_length);
-
- if (iscsi_target_check_login_request(conn, login) < 0)
- return -1;
-
- padding = ((-payload_length) & 3);
- memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
-
- if (iscsi_login_rx_data(
- conn,
- login->req_buf,
- payload_length + padding) < 0)
- return -1;
-
- return 0;
-}
-
static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
{
if (iscsi_target_do_tx_login_io(conn, login) < 0)
return -1;
- if (iscsi_target_do_rx_login_io(conn, login) < 0)
- return -1;
-
- return 0;
-}
-
-static int iscsi_target_get_initial_payload(
- struct iscsi_conn *conn,
- struct iscsi_login *login)
-{
- u32 padding = 0, payload_length;
- struct iscsi_login_req *login_req;
-
- login_req = (struct iscsi_login_req *) login->req;
- payload_length = ntoh24(login_req->dlength);
-
- pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
- " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
- login_req->flags, login_req->itt, login_req->cmdsn,
- login_req->exp_statsn, payload_length);
-
- if (iscsi_target_check_login_request(conn, login) < 0)
- return -1;
-
- padding = ((-payload_length) & 3);
-
- if (iscsi_login_rx_data(
- conn,
- login->req_buf,
- payload_length + padding) < 0)
+ if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
return -1;
return 0;
@@ -681,9 +619,9 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
return -1;
}
- switch ((login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2) {
+ switch (ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)) {
case 0:
- login_rsp->flags |= (0 & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK);
+ login_rsp->flags &= ~ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK;
if (iscsi_target_handle_csg_zero(conn, login) < 0)
return -1;
break;
@@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
return -1;
if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
login->tsih = conn->sess->tsih;
+ login->login_complete = 1;
if (iscsi_target_do_tx_login_io(conn,
login) < 0)
return -1;
@@ -702,8 +641,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
default:
pr_err("Illegal CSG: %d received from"
" Initiator, protocol error.\n",
- (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK)
- >> 2);
+ ISCSI_LOGIN_CURRENT_STAGE(login_req->flags));
break;
}
@@ -737,7 +675,7 @@ static void iscsi_initiatorname_tolower(
/*
* Processes the first Login Request..
*/
-static int iscsi_target_locate_portal(
+int iscsi_target_locate_portal(
struct iscsi_np *np,
struct iscsi_conn *conn,
struct iscsi_login *login)
@@ -753,22 +691,6 @@ static int iscsi_target_locate_portal(
login_req = (struct iscsi_login_req *) login->req;
payload_length = ntoh24(login_req->dlength);
- login->first_request = 1;
- login->leading_connection = (!login_req->tsih) ? 1 : 0;
- login->current_stage =
- (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
- login->version_min = login_req->min_version;
- login->version_max = login_req->max_version;
- memcpy(login->isid, login_req->isid, 6);
- login->cmd_sn = be32_to_cpu(login_req->cmdsn);
- login->init_task_tag = login_req->itt;
- login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
- login->cid = be16_to_cpu(login_req->cid);
- login->tsih = be16_to_cpu(login_req->tsih);
-
- if (iscsi_target_get_initial_payload(conn, login) < 0)
- return -1;
-
tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate memory for tmpbuf.\n");
@@ -800,6 +722,8 @@ static int iscsi_target_locate_portal(
start += strlen(key) + strlen(value) + 2;
}
+ printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf);
+
/*
* See 5.3. Login Phase.
*/
@@ -958,100 +882,30 @@ out:
return ret;
}
-struct iscsi_login *iscsi_target_init_negotiation(
- struct iscsi_np *np,
- struct iscsi_conn *conn,
- char *login_pdu)
-{
- struct iscsi_login *login;
-
- login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
- if (!login) {
- pr_err("Unable to allocate memory for struct iscsi_login.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- return NULL;
- }
-
- login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL);
- if (!login->req) {
- pr_err("Unable to allocate memory for Login Request.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- goto out;
- }
-
- login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
- if (!login->req_buf) {
- pr_err("Unable to allocate memory for response buffer.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- goto out;
- }
- /*
- * SessionType: Discovery
- *
- * Locates Default Portal
- *
- * SessionType: Normal
- *
- * Locates Target Portal from NP -> Target IQN
- */
- if (iscsi_target_locate_portal(np, conn, login) < 0) {
- goto out;
- }
-
- return login;
-out:
- kfree(login->req);
- kfree(login->req_buf);
- kfree(login);
-
- return NULL;
-}
-
int iscsi_target_start_negotiation(
struct iscsi_login *login,
struct iscsi_conn *conn)
{
- int ret = -1;
-
- login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
- if (!login->rsp) {
- pr_err("Unable to allocate memory for"
- " Login Response.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- ret = -1;
- goto out;
- }
-
- login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
- if (!login->rsp_buf) {
- pr_err("Unable to allocate memory for"
- " request buffer.\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_NO_RESOURCES);
- ret = -1;
- goto out;
- }
+ int ret;
ret = iscsi_target_do_login(conn, login);
-out:
if (ret != 0)
iscsi_remove_failed_auth_entry(conn);
- iscsi_target_nego_release(login, conn);
+ iscsi_target_nego_release(conn);
return ret;
}
-void iscsi_target_nego_release(
- struct iscsi_login *login,
- struct iscsi_conn *conn)
+void iscsi_target_nego_release(struct iscsi_conn *conn)
{
- kfree(login->req);
- kfree(login->rsp);
+ struct iscsi_login *login = conn->conn_login;
+
+ if (!login)
+ return;
+
kfree(login->req_buf);
kfree(login->rsp_buf);
kfree(login);
+
+ conn->conn_login = NULL;
}
diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h
index 92e133a5158f..f021cbd330e5 100644
--- a/drivers/target/iscsi/iscsi_target_nego.h
+++ b/drivers/target/iscsi/iscsi_target_nego.h
@@ -7,11 +7,14 @@
extern void convert_null_to_semi(char *, int);
extern int extract_param(const char *, const char *, unsigned int, char *,
unsigned char *);
-extern struct iscsi_login *iscsi_target_init_negotiation(
- struct iscsi_np *, struct iscsi_conn *, char *);
+extern int iscsi_target_check_login_request(struct iscsi_conn *,
+ struct iscsi_login *);
+extern int iscsi_target_get_initial_payload(struct iscsi_conn *,
+ struct iscsi_login *);
+extern int iscsi_target_locate_portal(struct iscsi_np *, struct iscsi_conn *,
+ struct iscsi_login *);
extern int iscsi_target_start_negotiation(
struct iscsi_login *, struct iscsi_conn *);
-extern void iscsi_target_nego_release(
- struct iscsi_login *, struct iscsi_conn *);
+extern void iscsi_target_nego_release(struct iscsi_conn *);
#endif /* ISCSI_TARGET_NEGO_H */
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index ca2be406f141..f690be9e5293 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -59,7 +59,7 @@ int iscsi_login_tx_data(
char *text_buf,
int text_length)
{
- int length, tx_sent;
+ int length, tx_sent, iov_cnt = 1;
struct kvec iov[2];
length = (ISCSI_HDR_LEN + text_length);
@@ -67,8 +67,12 @@ int iscsi_login_tx_data(
memset(&iov[0], 0, 2 * sizeof(struct kvec));
iov[0].iov_len = ISCSI_HDR_LEN;
iov[0].iov_base = pdu_buf;
- iov[1].iov_len = text_length;
- iov[1].iov_base = text_buf;
+
+ if (text_buf && text_length) {
+ iov[1].iov_len = text_length;
+ iov[1].iov_base = text_buf;
+ iov_cnt++;
+ }
/*
* Initial Marker-less Interval.
@@ -77,7 +81,7 @@ int iscsi_login_tx_data(
*/
conn->if_marker += length;
- tx_sent = tx_data(conn, &iov[0], 2, length);
+ tx_sent = tx_data(conn, &iov[0], iov_cnt, length);
if (tx_sent != length) {
pr_err("tx_data returned %d, expecting %d.\n",
tx_sent, length);
@@ -429,6 +433,28 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
TYPERANGE_MARKINT, USE_INITIAL_ONLY);
if (!param)
goto out;
+ /*
+ * Extra parameters for ISER from RFC-5046
+ */
+ param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS,
+ PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
+ TYPERANGE_BOOL_AND, USE_LEADING_ONLY);
+ if (!param)
+ goto out;
+
+ param = iscsi_set_default_param(pl, INITIATORRECVDATASEGMENTLENGTH,
+ INITIAL_INITIATORRECVDATASEGMENTLENGTH,
+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+ TYPERANGE_512_TO_16777215, USE_ALL);
+ if (!param)
+ goto out;
+
+ param = iscsi_set_default_param(pl, TARGETRECVDATASEGMENTLENGTH,
+ INITIAL_TARGETRECVDATASEGMENTLENGTH,
+ PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH,
+ TYPERANGE_512_TO_16777215, USE_ALL);
+ if (!param)
+ goto out;
*param_list_ptr = pl;
return 0;
@@ -438,19 +464,23 @@ out:
}
int iscsi_set_keys_to_negotiate(
- int sessiontype,
- struct iscsi_param_list *param_list)
+ struct iscsi_param_list *param_list,
+ bool iser)
{
struct iscsi_param *param;
+ param_list->iser = iser;
+
list_for_each_entry(param, &param_list->param_list, p_list) {
param->state = 0;
if (!strcmp(param->name, AUTHMETHOD)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, HEADERDIGEST)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, DATADIGEST)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXCONNECTIONS)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, TARGETNAME)) {
@@ -469,7 +499,8 @@ int iscsi_set_keys_to_negotiate(
} else if (!strcmp(param->name, IMMEDIATEDATA)) {
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) {
- SET_PSTATE_NEGOTIATE(param);
+ if (iser == false)
+ SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
continue;
} else if (!strcmp(param->name, MAXBURSTLENGTH)) {
@@ -498,6 +529,15 @@ int iscsi_set_keys_to_negotiate(
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, OFMARKINT)) {
SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
+ if (iser == true)
+ SET_PSTATE_NEGOTIATE(param);
}
}
@@ -540,6 +580,12 @@ int iscsi_set_keys_irrelevant_for_discovery(
param->state &= ~PSTATE_NEGOTIATE;
else if (!strcmp(param->name, OFMARKINT))
param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, RDMAEXTENTIONS))
+ param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH))
+ param->state &= ~PSTATE_NEGOTIATE;
+ else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH))
+ param->state &= ~PSTATE_NEGOTIATE;
}
return 0;
@@ -1755,6 +1801,9 @@ void iscsi_set_connection_parameters(
* this key is not sent over the wire.
*/
if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) {
+ if (param_list->iser == true)
+ continue;
+
ops->MaxXmitDataSegmentLength =
simple_strtoul(param->value, &tmpptr, 0);
pr_debug("MaxXmitDataSegmentLength: %s\n",
@@ -1800,6 +1849,22 @@ void iscsi_set_connection_parameters(
simple_strtoul(param->value, &tmpptr, 0);
pr_debug("IFMarkInt: %s\n",
param->value);
+ } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
+ ops->InitiatorRecvDataSegmentLength =
+ simple_strtoul(param->value, &tmpptr, 0);
+ pr_debug("InitiatorRecvDataSegmentLength: %s\n",
+ param->value);
+ ops->MaxRecvDataSegmentLength =
+ ops->InitiatorRecvDataSegmentLength;
+ pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n");
+ } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) {
+ ops->TargetRecvDataSegmentLength =
+ simple_strtoul(param->value, &tmpptr, 0);
+ pr_debug("TargetRecvDataSegmentLength: %s\n",
+ param->value);
+ ops->MaxXmitDataSegmentLength =
+ ops->TargetRecvDataSegmentLength;
+ pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n");
}
}
pr_debug("----------------------------------------------------"
@@ -1912,6 +1977,10 @@ void iscsi_set_session_parameters(
ops->SessionType = !strcmp(param->value, DISCOVERY);
pr_debug("SessionType: %s\n",
param->value);
+ } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ ops->RDMAExtensions = !strcmp(param->value, YES);
+ pr_debug("RDMAExtensions: %s\n",
+ param->value);
}
}
pr_debug("----------------------------------------------------"
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index 1e1b7504a76b..f31b9c4b83f2 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -27,7 +27,7 @@ extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *);
extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *);
extern void iscsi_print_params(struct iscsi_param_list *);
extern int iscsi_create_default_params(struct iscsi_param_list **);
-extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *);
+extern int iscsi_set_keys_to_negotiate(struct iscsi_param_list *, bool);
extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *);
extern int iscsi_copy_param_list(struct iscsi_param_list **,
struct iscsi_param_list *, int);
@@ -89,6 +89,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft"
/*
+ * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046
+ */
+#define RDMAEXTENTIONS "RDMAExtensions"
+#define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength"
+#define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength"
+
+/*
* For AuthMethod.
*/
#define KRB5 "KRB5"
@@ -133,6 +140,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
#define INITIAL_OFMARKINT "2048~65535"
/*
+ * Initial values for iSER parameters following RFC-5046 Section 6
+ */
+#define INITIAL_RDMAEXTENTIONS NO
+#define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144"
+#define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192"
+
+/*
* For [Header,Data]Digests.
*/
#define CRC32C "CRC32C"
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 9d4417aae921..b997e5da47d3 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -23,6 +23,7 @@
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_seq_pdu_list.h"
@@ -301,7 +302,7 @@ static int iscsit_task_reassign_complete_write(
/*
* iscsit_build_r2ts_for_cmd() can handle the rest from here.
*/
- return iscsit_build_r2ts_for_cmd(cmd, conn, true);
+ return conn->conn_transport->iscsit_get_dataout(conn, cmd, true);
}
static int iscsit_task_reassign_complete_read(
@@ -471,6 +472,7 @@ int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
return 0;
}
+EXPORT_SYMBOL(iscsit_tmr_post_handler);
/*
* Nothing to do here, but leave it for good measure. :-)
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index ee8f8c66248d..439260b7d87f 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -31,6 +31,8 @@
#include "iscsi_target.h"
#include "iscsi_target_parameters.h"
+#include <target/iscsi/iscsi_transport.h>
+
struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt)
{
struct iscsi_portal_group *tpg;
@@ -508,7 +510,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n",
tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
- (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+ np->np_transport->name);
return tpg_np;
}
@@ -522,7 +524,7 @@ static int iscsit_tpg_release_np(
pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
- (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+ np->np_transport->name);
tpg_np->tpg_np = NULL;
tpg_np->tpg = NULL;
diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c
new file mode 100644
index 000000000000..882728fac30c
--- /dev/null
+++ b/drivers/target/iscsi/iscsi_target_transport.c
@@ -0,0 +1,55 @@
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <target/iscsi/iscsi_transport.h>
+
+static LIST_HEAD(g_transport_list);
+static DEFINE_MUTEX(transport_mutex);
+
+struct iscsit_transport *iscsit_get_transport(int type)
+{
+ struct iscsit_transport *t;
+
+ mutex_lock(&transport_mutex);
+ list_for_each_entry(t, &g_transport_list, t_node) {
+ if (t->transport_type == type) {
+ if (t->owner && !try_module_get(t->owner)) {
+ t = NULL;
+ }
+ mutex_unlock(&transport_mutex);
+ return t;
+ }
+ }
+ mutex_unlock(&transport_mutex);
+
+ return NULL;
+}
+
+void iscsit_put_transport(struct iscsit_transport *t)
+{
+ if (t->owner)
+ module_put(t->owner);
+}
+
+int iscsit_register_transport(struct iscsit_transport *t)
+{
+ INIT_LIST_HEAD(&t->t_node);
+
+ mutex_lock(&transport_mutex);
+ list_add_tail(&t->t_node, &g_transport_list);
+ mutex_unlock(&transport_mutex);
+
+ pr_debug("Registered iSCSI transport: %s\n", t->name);
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsit_register_transport);
+
+void iscsit_unregister_transport(struct iscsit_transport *t)
+{
+ mutex_lock(&transport_mutex);
+ list_del(&t->t_node);
+ mutex_unlock(&transport_mutex);
+
+ pr_debug("Unregistered iSCSI transport: %s\n", t->name);
+}
+EXPORT_SYMBOL(iscsit_unregister_transport);
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 7ce350578c82..2cc6c9a3ffb8 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -24,6 +24,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_core.h"
#include "iscsi_target_parameters.h"
@@ -148,6 +149,18 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
spin_unlock_bh(&cmd->r2t_lock);
}
+struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
+{
+ struct iscsi_cmd *cmd;
+
+ cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
+ if (!cmd)
+ return NULL;
+
+ cmd->release_cmd = &iscsit_release_cmd;
+ return cmd;
+}
+
/*
* May be called from software interrupt (timer) context for allocating
* iSCSI NopINs.
@@ -156,13 +169,12 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
{
struct iscsi_cmd *cmd;
- cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
+ cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask);
if (!cmd) {
pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
return NULL;
}
-
- cmd->conn = conn;
+ cmd->conn = conn;
INIT_LIST_HEAD(&cmd->i_conn_node);
INIT_LIST_HEAD(&cmd->datain_list);
INIT_LIST_HEAD(&cmd->cmd_r2t_list);
@@ -175,6 +187,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
return cmd;
}
+EXPORT_SYMBOL(iscsit_allocate_cmd);
struct iscsi_seq *iscsit_get_seq_holder_for_datain(
struct iscsi_cmd *cmd,
@@ -304,6 +317,7 @@ int iscsit_sequence_cmd(
return ret;
}
+EXPORT_SYMBOL(iscsit_sequence_cmd);
int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf)
{
@@ -689,6 +703,11 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
*/
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
+ if (cmd->data_direction == DMA_TO_DEVICE)
+ iscsit_stop_dataout_timer(cmd);
+ /*
+ * Fallthrough
+ */
case ISCSI_OP_SCSI_TMFUNC:
transport_generic_free_cmd(&cmd->se_cmd, 1);
break;
@@ -704,7 +723,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
}
/* Fall-through */
default:
- iscsit_release_cmd(cmd);
+ cmd->release_cmd(cmd);
break;
}
}
@@ -1226,34 +1245,19 @@ send_datacrc:
*/
int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
{
- u8 iscsi_hdr[ISCSI_HDR_LEN];
- int err;
- struct kvec iov;
struct iscsi_login_rsp *hdr;
+ struct iscsi_login *login = conn->conn_login;
+ login->login_failed = 1;
iscsit_collect_login_stats(conn, status_class, status_detail);
- memset(&iov, 0, sizeof(struct kvec));
- memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN);
-
- hdr = (struct iscsi_login_rsp *)&iscsi_hdr;
+ hdr = (struct iscsi_login_rsp *)&login->rsp[0];
hdr->opcode = ISCSI_OP_LOGIN_RSP;
hdr->status_class = status_class;
hdr->status_detail = status_detail;
hdr->itt = conn->login_itt;
- iov.iov_base = &iscsi_hdr;
- iov.iov_len = ISCSI_HDR_LEN;
-
- PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN);
-
- err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN);
- if (err != ISCSI_HDR_LEN) {
- pr_err("tx_data returned less than expected\n");
- return -1;
- }
-
- return 0;
+ return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
}
void iscsit_print_session_params(struct iscsi_session *sess)
@@ -1432,7 +1436,8 @@ void iscsit_collect_login_stats(
strcpy(ls->last_intr_fail_name,
(intrname ? intrname->value : "Unknown"));
- ls->last_intr_fail_ip_family = conn->sock->sk->sk_family;
+ ls->last_intr_fail_ip_family = conn->login_family;
+
snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE,
"%s", conn->login_ip);
ls->last_fail_time = get_jiffies_64();
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 894d0f837924..4f8e01a47081 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -8,6 +8,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32);
extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
+extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index ff1c5ee352cb..cbe48ab41745 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -409,6 +409,7 @@ static inline int core_alua_state_standby(
case REPORT_LUNS:
case RECEIVE_DIAGNOSTIC:
case SEND_DIAGNOSTIC:
+ return 0;
case MAINTENANCE_IN:
switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
@@ -451,6 +452,7 @@ static inline int core_alua_state_unavailable(
switch (cdb[0]) {
case INQUIRY:
case REPORT_LUNS:
+ return 0;
case MAINTENANCE_IN:
switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
@@ -491,6 +493,7 @@ static inline int core_alua_state_transition(
switch (cdb[0]) {
case INQUIRY:
case REPORT_LUNS:
+ return 0;
case MAINTENANCE_IN:
switch (cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 17a6acbc3ab0..58ed683e04ae 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -30,8 +30,10 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
+#include <linux/falloc.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
+#include <asm/unaligned.h>
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
@@ -166,6 +168,33 @@ static int fd_configure_device(struct se_device *dev)
" block_device blocks: %llu logical_block_size: %d\n",
dev_size, div_u64(dev_size, fd_dev->fd_block_size),
fd_dev->fd_block_size);
+ /*
+ * Check if the underlying struct block_device request_queue supports
+ * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM
+ * in ATA and we need to set TPE=1
+ */
+ if (blk_queue_discard(q)) {
+ dev->dev_attrib.max_unmap_lba_count =
+ q->limits.max_discard_sectors;
+ /*
+ * Currently hardcoded to 1 in Linux/SCSI code..
+ */
+ dev->dev_attrib.max_unmap_block_desc_count = 1;
+ dev->dev_attrib.unmap_granularity =
+ q->limits.discard_granularity >> 9;
+ dev->dev_attrib.unmap_granularity_alignment =
+ q->limits.discard_alignment;
+ pr_debug("IFILE: BLOCK Discard support available,"
+ " disabled by default\n");
+ }
+ /*
+ * Enable write same emulation for IBLOCK and use 0xFFFF as
+ * the smaller WRITE_SAME(10) only has a two-byte block count.
+ */
+ dev->dev_attrib.max_write_same_len = 0xFFFF;
+
+ if (blk_queue_nonrot(q))
+ dev->dev_attrib.is_nonrot = 1;
} else {
if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) {
pr_err("FILEIO: Missing fd_dev_size="
@@ -176,6 +205,23 @@ static int fd_configure_device(struct se_device *dev)
dev->dev_attrib.hw_block_size = FD_BLOCKSIZE;
dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS;
+
+ /*
+ * Limit UNMAP emulation to 8k Number of LBAs (NoLB)
+ */
+ dev->dev_attrib.max_unmap_lba_count = 0x2000;
+ /*
+ * Currently hardcoded to 1 in Linux/SCSI code..
+ */
+ dev->dev_attrib.max_unmap_block_desc_count = 1;
+ dev->dev_attrib.unmap_granularity = 1;
+ dev->dev_attrib.unmap_granularity_alignment = 0;
+
+ /*
+ * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
+ * based upon struct iovec limit for vfs_writev()
+ */
+ dev->dev_attrib.max_write_same_len = 0x1000;
}
fd_dev->fd_block_size = dev->dev_attrib.hw_block_size;
@@ -190,11 +236,6 @@ static int fd_configure_device(struct se_device *dev)
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
fd_dev->fd_queue_depth = dev->queue_depth;
- /*
- * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
- * based upon struct iovec limit for vfs_writev()
- */
- dev->dev_attrib.max_write_same_len = 0x1000;
pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
" %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
@@ -442,6 +483,75 @@ fd_execute_write_same(struct se_cmd *cmd)
}
static sense_reason_t
+fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb)
+{
+ struct file *file = priv;
+ struct inode *inode = file->f_mapping->host;
+ int ret;
+
+ if (S_ISBLK(inode->i_mode)) {
+ /* The backend is block device, use discard */
+ struct block_device *bdev = inode->i_bdev;
+
+ ret = blkdev_issue_discard(bdev, lba,
+ nolb, GFP_KERNEL, 0);
+ if (ret < 0) {
+ pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n",
+ ret);
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
+ } else {
+ /* The backend is normal file, use fallocate */
+ struct se_device *se_dev = cmd->se_dev;
+ loff_t pos = lba * se_dev->dev_attrib.block_size;
+ unsigned int len = nolb * se_dev->dev_attrib.block_size;
+ int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
+
+ if (!file->f_op->fallocate)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ ret = file->f_op->fallocate(file, mode, pos, len);
+ if (ret < 0) {
+ pr_warn("FILEIO: fallocate() failed: %d\n", ret);
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
+ }
+
+ return 0;
+}
+
+static sense_reason_t
+fd_execute_write_same_unmap(struct se_cmd *cmd)
+{
+ struct se_device *se_dev = cmd->se_dev;
+ struct fd_dev *fd_dev = FD_DEV(se_dev);
+ struct file *file = fd_dev->fd_file;
+ sector_t lba = cmd->t_task_lba;
+ sector_t nolb = sbc_get_write_same_sectors(cmd);
+ int ret;
+
+ if (!nolb) {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ return 0;
+ }
+
+ ret = fd_do_unmap(cmd, file, lba, nolb);
+ if (ret)
+ return ret;
+
+ target_complete_cmd(cmd, GOOD);
+ return 0;
+}
+
+static sense_reason_t
+fd_execute_unmap(struct se_cmd *cmd)
+{
+ struct file *file = FD_DEV(cmd->se_dev)->fd_file;
+
+ return sbc_execute_unmap(cmd, fd_do_unmap, file);
+}
+
+static sense_reason_t
fd_execute_rw(struct se_cmd *cmd)
{
struct scatterlist *sgl = cmd->t_data_sg;
@@ -600,6 +710,8 @@ static struct sbc_ops fd_sbc_ops = {
.execute_rw = fd_execute_rw,
.execute_sync_cache = fd_execute_sync_cache,
.execute_write_same = fd_execute_write_same,
+ .execute_write_same_unmap = fd_execute_write_same_unmap,
+ .execute_unmap = fd_execute_unmap,
};
static sense_reason_t
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 8bcc514ec8b6..07f5f94634bb 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -380,104 +380,40 @@ iblock_execute_sync_cache(struct se_cmd *cmd)
}
static sense_reason_t
-iblock_execute_unmap(struct se_cmd *cmd)
+iblock_do_unmap(struct se_cmd *cmd, void *priv,
+ sector_t lba, sector_t nolb)
{
- struct se_device *dev = cmd->se_dev;
- struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
- unsigned char *buf, *ptr = NULL;
- sector_t lba;
- int size;
- u32 range;
- sense_reason_t ret = 0;
- int dl, bd_dl, err;
-
- /* We never set ANC_SUP */
- if (cmd->t_task_cdb[1])
- return TCM_INVALID_CDB_FIELD;
-
- if (cmd->data_length == 0) {
- target_complete_cmd(cmd, SAM_STAT_GOOD);
- return 0;
- }
+ struct block_device *bdev = priv;
+ int ret;
- if (cmd->data_length < 8) {
- pr_warn("UNMAP parameter list length %u too small\n",
- cmd->data_length);
- return TCM_PARAMETER_LIST_LENGTH_ERROR;
- }
-
- buf = transport_kmap_data_sg(cmd);
- if (!buf)
+ ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0);
+ if (ret < 0) {
+ pr_err("blkdev_issue_discard() failed: %d\n", ret);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
-
- dl = get_unaligned_be16(&buf[0]);
- bd_dl = get_unaligned_be16(&buf[2]);
-
- size = cmd->data_length - 8;
- if (bd_dl > size)
- pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
- cmd->data_length, bd_dl);
- else
- size = bd_dl;
-
- if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
- ret = TCM_INVALID_PARAMETER_LIST;
- goto err;
}
- /* First UNMAP block descriptor starts at 8 byte offset */
- ptr = &buf[8];
- pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
- " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
-
- while (size >= 16) {
- lba = get_unaligned_be64(&ptr[0]);
- range = get_unaligned_be32(&ptr[8]);
- pr_debug("UNMAP: Using lba: %llu and range: %u\n",
- (unsigned long long)lba, range);
-
- if (range > dev->dev_attrib.max_unmap_lba_count) {
- ret = TCM_INVALID_PARAMETER_LIST;
- goto err;
- }
-
- if (lba + range > dev->transport->get_blocks(dev) + 1) {
- ret = TCM_ADDRESS_OUT_OF_RANGE;
- goto err;
- }
-
- err = blkdev_issue_discard(ib_dev->ibd_bd, lba, range,
- GFP_KERNEL, 0);
- if (err < 0) {
- pr_err("blkdev_issue_discard() failed: %d\n",
- err);
- ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- goto err;
- }
+ return 0;
+}
- ptr += 16;
- size -= 16;
- }
+static sense_reason_t
+iblock_execute_unmap(struct se_cmd *cmd)
+{
+ struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
-err:
- transport_kunmap_data_sg(cmd);
- if (!ret)
- target_complete_cmd(cmd, GOOD);
- return ret;
+ return sbc_execute_unmap(cmd, iblock_do_unmap, bdev);
}
static sense_reason_t
iblock_execute_write_same_unmap(struct se_cmd *cmd)
{
- struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev);
- int rc;
-
- rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba,
- sbc_get_write_same_sectors(cmd), GFP_KERNEL, 0);
- if (rc < 0) {
- pr_warn("blkdev_issue_discard() failed: %d\n", rc);
- return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- }
+ struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd;
+ sector_t lba = cmd->t_task_lba;
+ sector_t nolb = sbc_get_write_same_sectors(cmd);
+ int ret;
+
+ ret = iblock_do_unmap(cmd, bdev, lba, nolb);
+ if (ret)
+ return ret;
target_complete_cmd(cmd, GOOD);
return 0;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 60d4b5185f32..bbc5b0ee2bdc 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -596,3 +596,88 @@ u32 sbc_get_device_type(struct se_device *dev)
return TYPE_DISK;
}
EXPORT_SYMBOL(sbc_get_device_type);
+
+sense_reason_t
+sbc_execute_unmap(struct se_cmd *cmd,
+ sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *,
+ sector_t, sector_t),
+ void *priv)
+{
+ struct se_device *dev = cmd->se_dev;
+ unsigned char *buf, *ptr = NULL;
+ sector_t lba;
+ int size;
+ u32 range;
+ sense_reason_t ret = 0;
+ int dl, bd_dl;
+
+ /* We never set ANC_SUP */
+ if (cmd->t_task_cdb[1])
+ return TCM_INVALID_CDB_FIELD;
+
+ if (cmd->data_length == 0) {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ return 0;
+ }
+
+ if (cmd->data_length < 8) {
+ pr_warn("UNMAP parameter list length %u too small\n",
+ cmd->data_length);
+ return TCM_PARAMETER_LIST_LENGTH_ERROR;
+ }
+
+ buf = transport_kmap_data_sg(cmd);
+ if (!buf)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ dl = get_unaligned_be16(&buf[0]);
+ bd_dl = get_unaligned_be16(&buf[2]);
+
+ size = cmd->data_length - 8;
+ if (bd_dl > size)
+ pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
+ cmd->data_length, bd_dl);
+ else
+ size = bd_dl;
+
+ if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
+ ret = TCM_INVALID_PARAMETER_LIST;
+ goto err;
+ }
+
+ /* First UNMAP block descriptor starts at 8 byte offset */
+ ptr = &buf[8];
+ pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
+ " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
+
+ while (size >= 16) {
+ lba = get_unaligned_be64(&ptr[0]);
+ range = get_unaligned_be32(&ptr[8]);
+ pr_debug("UNMAP: Using lba: %llu and range: %u\n",
+ (unsigned long long)lba, range);
+
+ if (range > dev->dev_attrib.max_unmap_lba_count) {
+ ret = TCM_INVALID_PARAMETER_LIST;
+ goto err;
+ }
+
+ if (lba + range > dev->transport->get_blocks(dev) + 1) {
+ ret = TCM_ADDRESS_OUT_OF_RANGE;
+ goto err;
+ }
+
+ ret = do_unmap_fn(cmd, priv, lba, range);
+ if (ret)
+ goto err;
+
+ ptr += 16;
+ size -= 16;
+ }
+
+err:
+ transport_kunmap_data_sg(cmd);
+ if (!ret)
+ target_complete_cmd(cmd, GOOD);
+ return ret;
+}
+EXPORT_SYMBOL(sbc_execute_unmap);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 2030b608136d..f8388b4024aa 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -65,7 +65,6 @@ static void transport_complete_task_attr(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
struct se_device *dev);
static int transport_generic_get_mem(struct se_cmd *cmd);
-static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
static void transport_put_cmd(struct se_cmd *cmd);
static void target_complete_ok_work(struct work_struct *work);
@@ -1139,8 +1138,10 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
return ret;
ret = target_check_reservation(cmd);
- if (ret)
+ if (ret) {
+ cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
return ret;
+ }
ret = dev->transport->parse_cdb(cmd);
if (ret)
@@ -2177,7 +2178,7 @@ EXPORT_SYMBOL(transport_generic_free_cmd);
* @se_cmd: command descriptor to add
* @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd()
*/
-static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
+int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd,
bool ack_kref)
{
unsigned long flags;
@@ -2206,6 +2207,7 @@ out:
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
return ret;
}
+EXPORT_SYMBOL(target_get_sess_cmd);
static void target_release_cmd_kref(struct kref *kref)
{
@@ -2763,8 +2765,13 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
/* CURRENT ERROR */
buffer[0] = 0x70;
buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
- /* ILLEGAL REQUEST */
- buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /*
+ * Returning ILLEGAL REQUEST would cause immediate IO errors on
+ * Solaris initiators. Returning NOT READY instead means the
+ * operations will be retried a finite number of times and we
+ * can survive intermittent errors.
+ */
+ buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY;
/* LOGICAL UNIT COMMUNICATION FAILURE */
buffer[SPC_ASC_KEY_OFFSET] = 0x08;
break;
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index b6fd4cf42840..e415af32115a 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -103,6 +103,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
use_sg = !(remaining % 4);
while (remaining) {
+ struct fc_seq *seq = cmd->seq;
+
+ if (!seq) {
+ pr_debug("%s: Command aborted, xid 0x%x\n",
+ __func__, ep->xid);
+ break;
+ }
if (!mem_len) {
sg = sg_next(sg);
mem_len = min((size_t)sg->length, remaining);
@@ -169,7 +176,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd)
f_ctl |= FC_FC_END_SEQ;
fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid,
FC_TYPE_FCP, f_ctl, fh_off);
- error = lport->tt.seq_send(lport, cmd->seq, fp);
+ error = lport->tt.seq_send(lport, seq, fp);
if (error) {
/* XXX For now, initiator will retry */
pr_err_ratelimited("%s: Failed to send frame %p, "
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 113f33598b9f..4859505ae2ed 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -428,19 +428,12 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len,
return ret;
}
-static void ft_sess_rcu_free(struct rcu_head *rcu)
-{
- struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu);
-
- kfree(sess);
-}
-
static void ft_sess_free(struct kref *kref)
{
struct ft_sess *sess = container_of(kref, struct ft_sess, kref);
transport_deregister_session(sess->se_sess);
- call_rcu(&sess->rcu, ft_sess_rcu_free);
+ kfree_rcu(sess, rcu);
}
void ft_sess_put(struct ft_sess *sess)
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index fc700342d43f..083710e02367 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1798,19 +1798,7 @@ static struct platform_driver amiga_serial_driver = {
},
};
-static int __init amiga_serial_init(void)
-{
- return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe);
-}
-
-module_init(amiga_serial_init);
-
-static void __exit amiga_serial_exit(void)
-{
- platform_driver_unregister(&amiga_serial_driver);
-}
-
-module_exit(amiga_serial_exit);
+module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);
#if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index 345bd0e0884e..33f83fee9fae 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1124,14 +1124,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
readl(&info->u.cyz.ch_ctrl->rs_status);
if (dcd & C_RS_DCD)
wake_up_interruptible(&info->port.open_wait);
- else {
- struct tty_struct *tty;
- tty = tty_port_tty_get(&info->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- }
+ else
+ tty_port_tty_hangup(&info->port, false);
}
break;
case C_CM_MCTS:
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index ed92622b8949..6d0c27cd03da 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -472,13 +472,9 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
{
struct ehv_bc_data *bc = data;
- struct tty_struct *ttys = tty_port_tty_get(&bc->port);
ehv_bc_tx_dequeue(bc);
- if (ttys) {
- tty_wakeup(ttys);
- tty_kref_put(ttys);
- }
+ tty_port_tty_wakeup(&bc->port);
return IRQ_HANDLED;
}
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index ef95a154854a..41901997c0d6 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -861,7 +861,6 @@ static void hvsi_write_worker(struct work_struct *work)
{
struct hvsi_struct *hp =
container_of(work, struct hvsi_struct, writer.work);
- struct tty_struct *tty;
unsigned long flags;
#ifdef DEBUG
static long start_j = 0;
@@ -895,11 +894,7 @@ static void hvsi_write_worker(struct work_struct *work)
start_j = 0;
#endif /* DEBUG */
wake_up_all(&hp->emptyq);
- tty = tty_port_tty_get(&hp->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&hp->port);
}
out:
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c
index 97a511f4185d..2c14842541dd 100644
--- a/drivers/tty/ipwireless/hardware.c
+++ b/drivers/tty/ipwireless/hardware.c
@@ -1732,8 +1732,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
flush_work(&hw->work_rx);
for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
- if (hw->packet_assembler[i] != NULL)
- kfree(hw->packet_assembler[i]);
+ kfree(hw->packet_assembler[i]);
for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index adeac255e526..1deaca4674e4 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -913,16 +913,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
/* pci hot-un-plug support */
for (a = 0; a < brd->numPorts; a++)
- if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
- struct tty_struct *tty = tty_port_tty_get(
- &brd->ports[a].port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- }
+ if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
+ tty_port_tty_hangup(&brd->ports[a].port, false);
+
for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
tty_port_destroy(&brd->ports[a].port);
+
while (1) {
opened = 0;
for (a = 0; a < brd->numPorts; a++)
@@ -1365,7 +1361,6 @@ static void moxa_hangup(struct tty_struct *tty)
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
{
- struct tty_struct *tty;
unsigned long flags;
dcd = !!dcd;
@@ -1373,10 +1368,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
if (dcd != p->DCDState) {
p->DCDState = dcd;
spin_unlock_irqrestore(&p->port.lock, flags);
- tty = tty_port_tty_get(&p->port);
- if (tty && !C_CLOCAL(tty) && !dcd)
- tty_hangup(tty);
- tty_kref_put(tty);
+ if (!dcd)
+ tty_port_tty_hangup(&p->port, true);
}
else
spin_unlock_irqrestore(&p->port.lock, flags);
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 484b6a3c9b03..71d6eb2c93b1 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1084,6 +1084,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
mutex_lock(&port->mutex);
mxser_close_port(port);
mxser_flush_buffer(tty);
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ if (C_HUPCL(tty))
+ tty_port_lower_dtr_rts(port);
+ }
mxser_shutdown_port(port);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
mutex_unlock(&port->mutex);
@@ -2643,9 +2647,9 @@ static int mxser_probe(struct pci_dev *pdev,
mxvar_sdriver, brd->idx + i, &pdev->dev);
if (IS_ERR(tty_dev)) {
retval = PTR_ERR(tty_dev);
- for (i--; i >= 0; i--)
+ for (; i > 0; i--)
tty_unregister_device(mxvar_sdriver,
- brd->idx + i);
+ brd->idx + i - 1);
goto err_relbrd;
}
}
@@ -2751,9 +2755,9 @@ static int __init mxser_module_init(void)
tty_dev = tty_port_register_device(&brd->ports[i].port,
mxvar_sdriver, brd->idx + i, NULL);
if (IS_ERR(tty_dev)) {
- for (i--; i >= 0; i--)
+ for (; i > 0; i--)
tty_unregister_device(mxvar_sdriver,
- brd->idx + i);
+ brd->idx + i - 1);
for (i = 0; i < brd->info->nports; i++)
tty_port_destroy(&brd->ports[i].port);
free_irq(brd->irq, brd);
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 4a43ef5d7962..642239015b46 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1418,11 +1418,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) {
- struct tty_struct *tty = tty_port_tty_get(&dlci->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&dlci->port, false);
kfifo_reset(dlci->fifo);
} else
dlci->gsm->dead = 1;
@@ -2968,6 +2964,10 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
if (tty_port_close_start(&dlci->port, tty, filp) == 0)
goto out;
gsm_dlci_begin_close(dlci);
+ if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
+ if (C_HUPCL(tty))
+ tty_port_lower_dtr_rts(&dlci->port);
+ }
tty_port_close_end(&dlci->port, tty);
tty_port_tty_set(&dlci->port, NULL);
out:
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 05e72bea9b07..d655416087b7 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)
if (left && !old_left) {
WARN_RATELIMIT(tty->port->itty == NULL,
"scheduling with invalid itty\n");
+ /* see if ldisc has been killed - if so, this means that
+ * even though the ldisc has been halted and ->buf.work
+ * cancelled, ->buf.work is about to be rescheduled
+ */
+ WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
+ "scheduling buffer work for halted ldisc\n");
schedule_work(&tty->port->buf.work);
}
}
@@ -189,34 +195,17 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
}
/**
- * check_unthrottle - allow new receive data
- * @tty; tty device
- *
- * Check whether to call the driver unthrottle functions
- *
- * Can sleep, may be called under the atomic_read_lock mutex but
- * this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
- if (tty->count)
- tty_unthrottle(tty);
-}
-
-/**
* reset_buffer_flags - reset buffer state
* @tty: terminal to reset
*
- * Reset the read buffer counters, clear the flags,
- * and make sure the driver is unthrottled. Called
- * from n_tty_open() and n_tty_flush_buffer().
+ * Reset the read buffer counters and clear the flags.
+ * Called from n_tty_open() and n_tty_flush_buffer().
*
* Locking: tty_read_lock for read fields.
*/
-static void reset_buffer_flags(struct tty_struct *tty)
+static void reset_buffer_flags(struct n_tty_data *ldata)
{
- struct n_tty_data *ldata = tty->disc_data;
unsigned long flags;
raw_spin_lock_irqsave(&ldata->read_lock, flags);
@@ -229,36 +218,38 @@ static void reset_buffer_flags(struct tty_struct *tty)
ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
- n_tty_set_room(tty);
+}
+
+static void n_tty_packet_mode_flush(struct tty_struct *tty)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->link->packet) {
+ tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+ wake_up_interruptible(&tty->link->read_wait);
+ }
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
/**
* n_tty_flush_buffer - clean input queue
* @tty: terminal device
*
- * Flush the input buffer. Called when the line discipline is
- * being closed, when the tty layer wants the buffer flushed (eg
- * at hangup) or when the N_TTY line discipline internally has to
- * clean the pending queue (for example some signals).
+ * Flush the input buffer. Called when the tty layer wants the
+ * buffer flushed (eg at hangup) or when the N_TTY line discipline
+ * internally has to clean the pending queue (for example some signals).
*
* Locking: ctrl_lock, read_lock.
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
- unsigned long flags;
- /* clear everything and unthrottle the driver */
- reset_buffer_flags(tty);
-
- if (!tty->link)
- return;
+ reset_buffer_flags(tty->disc_data);
+ n_tty_set_room(tty);
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->link->packet) {
- tty->ctrl_status |= TIOCPKT_FLUSHREAD;
- wake_up_interruptible(&tty->link->read_wait);
- }
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link)
+ n_tty_packet_mode_flush(tty);
}
/**
@@ -1032,23 +1023,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* isig - handle the ISIG optio
* @sig: signal
* @tty: terminal
- * @flush: force flush
*
- * Called when a signal is being sent due to terminal input. This
- * may caus terminal flushing to take place according to the termios
- * settings and character used. Called from the driver receive_buf
- * path so serialized.
+ * Called when a signal is being sent due to terminal input.
+ * Called from the driver receive_buf path so serialized.
*
- * Locking: ctrl_lock, read_lock (both via flush buffer)
+ * Locking: ctrl_lock
*/
-static inline void isig(int sig, struct tty_struct *tty, int flush)
+static inline void isig(int sig, struct tty_struct *tty)
{
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, sig, 1);
- if (flush || !L_NOFLSH(tty)) {
- n_tty_flush_buffer(tty);
- tty_driver_flush_buffer(tty);
+ struct pid *tty_pgrp = tty_get_pgrp(tty);
+ if (tty_pgrp) {
+ kill_pgrp(tty_pgrp, sig, 1);
+ put_pid(tty_pgrp);
}
}
@@ -1069,7 +1056,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
if (I_IGNBRK(tty))
return;
if (I_BRKINT(tty)) {
- isig(SIGINT, tty, 1);
+ isig(SIGINT, tty);
+ if (!L_NOFLSH(tty)) {
+ n_tty_flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
+ }
return;
}
if (I_PARMRK(tty)) {
@@ -1236,11 +1227,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
signal = SIGTSTP;
if (c == SUSP_CHAR(tty)) {
send_signal:
- /*
- * Note that we do not use isig() here because we want
- * the order to be:
- * 1) flush, 2) echo, 3) signal
- */
if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty);
@@ -1251,8 +1237,7 @@ send_signal:
echo_char(c, tty);
process_echoes(tty);
}
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, signal, 1);
+ isig(signal, tty);
return;
}
}
@@ -1483,14 +1468,14 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
- tty_throttle(tty);
-
- /* FIXME: there is a tiny race here if the receive room check runs
- before the other work executes and empties the buffer (upping
- the receiving room and unthrottling. We then throttle and get
- stuck. This has been observed and traced down by Vincent Pillet/
- We need to address this when we sort out out the rx path locking */
+ while (1) {
+ tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
+ if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
+ break;
+ if (!tty_throttle_safe(tty))
+ break;
+ }
+ __tty_set_flow_change(tty, 0);
}
int is_ignored(int sig)
@@ -1607,7 +1592,9 @@ static void n_tty_close(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- n_tty_flush_buffer(tty);
+ if (tty->link)
+ n_tty_packet_mode_flush(tty);
+
kfree(ldata->read_buf);
kfree(ldata->echo_buf);
kfree(ldata);
@@ -1645,12 +1632,14 @@ static int n_tty_open(struct tty_struct *tty)
goto err_free_bufs;
tty->disc_data = ldata;
- reset_buffer_flags(tty);
- tty_unthrottle(tty);
+ reset_buffer_flags(tty->disc_data);
ldata->column = 0;
- n_tty_set_termios(tty, NULL);
tty->minimum_to_wake = 1;
tty->closing = 0;
+ /* indicate buffer work may resume */
+ clear_bit(TTY_LDISC_HALTED, &tty->flags);
+ n_tty_set_termios(tty, NULL);
+ tty_unthrottle(tty);
return 0;
err_free_bufs:
@@ -1740,10 +1729,9 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
*
- * FIXME:
- * Locking: None - redirected write test is safe, testing
- * current->signal should possibly lock current->sighand
- * pgrp locking ?
+ * Locking: redirected write test is safe
+ * current->signal->tty check is safe
+ * ctrl_lock to safely reference tty->pgrp
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -1753,19 +1741,22 @@ static int job_control(struct tty_struct *tty, struct file *file)
/* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */
/* don't stop on /dev/console */
- if (file->f_op->write != redirected_tty_write &&
- current->signal->tty == tty) {
- if (!tty->pgrp)
- printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
- else if (task_pgrp(current) != tty->pgrp) {
- if (is_ignored(SIGTTIN) ||
- is_current_pgrp_orphaned())
- return -EIO;
- kill_pgrp(task_pgrp(current), SIGTTIN, 1);
- set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
- }
+ if (file->f_op->write == redirected_tty_write ||
+ current->signal->tty != tty)
+ return 0;
+
+ spin_lock_irq(&tty->ctrl_lock);
+ if (!tty->pgrp)
+ printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+ else if (task_pgrp(current) != tty->pgrp) {
+ spin_unlock_irq(&tty->ctrl_lock);
+ if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
+ return -EIO;
+ kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+ set_thread_flag(TIF_SIGPENDING);
+ return -ERESTARTSYS;
}
+ spin_unlock_irq(&tty->ctrl_lock);
return 0;
}
@@ -1959,10 +1950,17 @@ do_it_again:
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters.
*/
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+ while (1) {
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+ break;
+ if (!tty->count)
+ break;
n_tty_set_room(tty);
- check_unthrottle(tty);
+ if (!tty_unthrottle_safe(tty))
+ break;
}
+ __tty_set_flow_change(tty, 0);
if (b - buf >= minimum)
break;
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 2dff19796157..d6080c3831ef 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -791,7 +791,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
const u8 toggle = port->toggle_ul;
void __iomem *addr = port->ul_addr[toggle];
const u32 ul_size = port->ul_size[toggle];
- struct tty_struct *tty = tty_port_tty_get(&port->port);
/* Get data from tty and place in buf for now */
size = kfifo_out(&port->fifo_ul, dc->send_buf,
@@ -799,7 +798,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
if (size == 0) {
DBG4("No more data to send, disable link:");
- tty_kref_put(tty);
return 0;
}
@@ -809,10 +807,8 @@ static int send_data(enum port_type index, struct nozomi *dc)
write_mem32(addr, (u32 *) &size, 4);
write_mem32(addr + 4, (u32 *) dc->send_buf, size);
- if (tty)
- tty_wakeup(tty);
+ tty_port_tty_wakeup(&port->port);
- tty_kref_put(tty);
return 1;
}
@@ -1505,12 +1501,9 @@ static void tty_exit(struct nozomi *dc)
DBG1(" ");
- for (i = 0; i < MAX_PORT; ++i) {
- struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port);
- if (tty && list_empty(&tty->hangup_work.entry))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ for (i = 0; i < MAX_PORT; ++i)
+ tty_port_tty_hangup(&dc->port[i].port, false);
+
/* Racy below - surely should wait for scheduled work to be done or
complete off a hangup method ? */
while (dc->open_ttys)
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index c24b4db243b9..59bfaecc4e14 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -405,15 +405,8 @@ err:
return retval;
}
-/* this is called once with whichever end is closed last */
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
- devpts_kill_index(tty->driver_data, tty->index);
-}
-
static void pty_cleanup(struct tty_struct *tty)
{
- tty->port->itty = NULL;
tty_port_put(tty->port);
}
@@ -627,6 +620,12 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
}
+/* this is called once with whichever end is closed last */
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+ devpts_kill_index(tty->driver_data, tty->index);
+}
+
static const struct tty_operations ptm_unix98_ops = {
.lookup = ptm_unix98_lookup,
.install = pty_unix98_install,
@@ -682,6 +681,9 @@ static int ptmx_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
+ /* We refuse fsnotify events on ptmx, since it's a shared resource */
+ filp->f_mode |= FMODE_NONOTIFY;
+
retval = tty_alloc_file(filp);
if (retval)
return retval;
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 1d270034bfc3..82d35c5a58fd 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -449,7 +449,7 @@ static void rp_do_transmit(struct r_port *info)
/* Loop sending data to FIFO until done or FIFO full */
while (1) {
- if (tty->stopped || tty->hw_stopped)
+ if (tty->stopped)
break;
c = min(info->xmit_fifo_room, info->xmit_cnt);
c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
@@ -521,15 +521,10 @@ static void rp_handle_port(struct r_port *info)
(ChanStatus & CD_ACT) ? "on" : "off");
#endif
if (!(ChanStatus & CD_ACT) && info->cd_status) {
- struct tty_struct *tty;
#ifdef ROCKET_DEBUG_HANGUP
printk(KERN_INFO "CD drop, calling hangup.\n");
#endif
- tty = tty_port_tty_get(&info->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&info->port, false);
}
info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
wake_up_interruptible(&info->port.open_wait);
@@ -1111,15 +1106,12 @@ static void rp_set_termios(struct tty_struct *tty,
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
- if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
- sSetRTS(cp);
+ sSetRTS(cp);
sSetDTR(cp);
}
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
+ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
rp_start(tty);
- }
}
static int rp_break(struct tty_struct *tty, int break_state)
@@ -1575,10 +1567,10 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)
spin_lock_irqsave(&info->slock, flags);
cp = &info->channel;
- if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
+ if (!tty->stopped && info->xmit_fifo_room == 0)
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
- if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
+ if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= XMIT_BUF_SIZE - 1;
info->xmit_cnt++;
@@ -1619,14 +1611,14 @@ static int rp_write(struct tty_struct *tty,
#endif
cp = &info->channel;
- if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
+ if (!tty->stopped && info->xmit_fifo_room < count)
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
/*
* If the write queue for the port is empty, and there is FIFO space, stuff bytes
* into FIFO. Use the write queue for temp storage.
*/
- if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
+ if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
c = min(count, info->xmit_fifo_room);
b = buf;
@@ -1674,7 +1666,7 @@ static int rp_write(struct tty_struct *tty,
retval += c;
}
- if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
+ if ((retval > 0) && !tty->stopped)
set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
end:
@@ -2527,6 +2519,7 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
return (CtlP->NumAiop);
}
+#ifdef CONFIG_PCI
/***************************************************************************
Function: sPCIInitController
Purpose: Initialization of controller global registers and controller
@@ -2647,6 +2640,26 @@ static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
return (CtlP->NumAiop);
}
+/* Resets the speaker controller on RocketModem II and III devices */
+static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
+{
+ ByteIO_t addr;
+
+ /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
+ if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
+ addr = CtlP->AiopIO[0] + 0x4F;
+ sOutB(addr, 0);
+ }
+
+ /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
+ if ((model == MODEL_UPCI_RM3_8PORT)
+ || (model == MODEL_UPCI_RM3_4PORT)) {
+ addr = CtlP->AiopIO[0] + 0x88;
+ sOutB(addr, 0);
+ }
+}
+#endif
+
/***************************************************************************
Function: sReadAiopID
Purpose: Read the AIOP idenfication number directly from an AIOP.
@@ -3136,25 +3149,6 @@ static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
sOutB(addr + chan, 0); /* apply or remove reset */
}
-/* Resets the speaker controller on RocketModem II and III devices */
-static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
-{
- ByteIO_t addr;
-
- /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
- if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
- addr = CtlP->AiopIO[0] + 0x4F;
- sOutB(addr, 0);
- }
-
- /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
- if ((model == MODEL_UPCI_RM3_8PORT)
- || (model == MODEL_UPCI_RM3_4PORT)) {
- addr = CtlP->AiopIO[0] + 0x88;
- sOutB(addr, 0);
- }
-}
-
/* Returns the line number given the controller (board), aiop and channel number */
static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
{
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 49399470794d..ef2e08e9b590 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -630,8 +630,7 @@ static void rs_flush_chars(struct tty_struct *tty)
/* Enable transmitter */
local_irq_save(flags);
- if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
- !info->xmit_buf) {
+ if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
local_irq_restore(flags);
return;
}
@@ -697,7 +696,7 @@ static int rs_write(struct tty_struct * tty,
total += c;
}
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ if (info->xmit_cnt && !tty->stopped) {
/* Enable transmitter */
local_irq_disable();
#ifndef USE_INTS
@@ -978,10 +977,8 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
+ !(tty->termios.c_cflag & CRTSCTS))
rs_start(tty);
- }
}
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 34eb676916fe..1ebf8538b4fa 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -117,13 +117,6 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
* is cleared, the machine locks up with endless interrupts.
*/
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
-#elif defined(CONFIG_SBC8560)
-/*
- * WindRiver did something similarly broken on their SBC8560 board. The
- * UART tristates its IRQ output while OUT2 is clear, but they pulled
- * the interrupt line _up_ instead of down, so if we register the IRQ
- * while the UART is in that state, we die in an IRQ storm. */
-#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
#else
#define ALPHA_KLUDGE_MCR 0
#endif
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250_core.c
index cf6a5383748a..46528d57be72 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void)
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
- for (i = 0; i < nr_uarts; i++) {
+ for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
struct uart_port *port = &up->port;
@@ -2916,7 +2916,7 @@ static int __init serial8250_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index >= nr_uarts)
+ if (co->index >= UART_NR)
co->index = 0;
port = &serial8250_ports[co->index].port;
if (!port->iobase && !port->membase)
@@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p)
int line;
struct uart_port *port;
- for (line = 0; line < nr_uarts; line++) {
+ for (line = 0; line < UART_NR; line++) {
port = &serial8250_ports[line].port;
if (uart_match_port(p, port))
return line;
@@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev)
{
int i;
- for (i = 0; i < nr_uarts; i++) {
+ for (i = 0; i < UART_NR; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &dev->dev)
@@ -3178,7 +3178,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
/*
* First, find a port entry which matches.
*/
- for (i = 0; i < nr_uarts; i++)
+ for (i = 0; i < UART_NR; i++)
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
@@ -3187,7 +3187,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* free entry. We look for one which hasn't been previously
* used (indicated by zero iobase).
*/
- for (i = 0; i < nr_uarts; i++)
+ for (i = 0; i < UART_NR; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
serial8250_ports[i].port.iobase == 0)
return &serial8250_ports[i];
@@ -3196,7 +3196,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it.
*/
- for (i = 0; i < nr_uarts; i++)
+ for (i = 0; i < UART_NR; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
return &serial8250_ports[i];
@@ -3247,6 +3247,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
uart->tx_loadsz = up->tx_loadsz;
uart->capabilities = up->capabilities;
+ /* Take tx_loadsz from fifosize if it wasn't set separately */
+ if (uart->port.fifosize && !uart->tx_loadsz)
+ uart->tx_loadsz = uart->port.fifosize;
+
if (up->port.dev)
uart->port.dev = up->port.dev;
@@ -3418,6 +3422,7 @@ MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
#endif
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
+#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
#ifndef MODULE
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
* working as well for the module options so we don't break people. We
@@ -3432,7 +3437,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
static void __used s8250_options(void)
{
#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250."
+#define MODULE_PARAM_PREFIX "8250_core."
module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
@@ -3444,5 +3449,6 @@ static void __used s8250_options(void)
#endif
}
#else
-MODULE_ALIAS("8250");
+MODULE_ALIAS("8250_core");
+#endif
#endif
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index b9f7fd28112e..7046769608d4 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -33,10 +33,8 @@ static void __dma_tx_complete(void *param)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port))
serial8250_tx_dma(p);
- uart_write_wakeup(&p->port);
- }
}
static void __dma_rx_complete(void *param)
@@ -67,12 +65,11 @@ int serial8250_tx_dma(struct uart_8250_port *p)
struct circ_buf *xmit = &p->port.state->xmit;
struct dma_async_tx_descriptor *desc;
- if (dma->tx_running)
- return -EBUSY;
+ if (uart_tx_stopped(&p->port) || dma->tx_running ||
+ uart_circ_empty(xmit))
+ return 0;
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- if (!dma->tx_size)
- return -EINVAL;
desc = dmaengine_prep_slave_single(dma->txchan,
dma->tx_addr + xmit->tail,
@@ -104,20 +101,29 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
struct dma_tx_state state;
int dma_status;
- /*
- * If RCVR FIFO trigger level was not reached, complete the transfer and
- * let 8250.c copy the remaining data.
- */
- if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
- dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie,
- &state);
+ dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
+
+ switch (iir & 0x3f) {
+ case UART_IIR_RLSI:
+ /* 8250_core handles errors and break interrupts */
+ return -EIO;
+ case UART_IIR_RX_TIMEOUT:
+ /*
+ * If RCVR FIFO trigger level was not reached, complete the
+ * transfer and let 8250_core copy the remaining data.
+ */
if (dma_status == DMA_IN_PROGRESS) {
dmaengine_pause(dma->rxchan);
__dma_rx_complete(p);
}
return -ETIMEDOUT;
+ default:
+ break;
}
+ if (dma_status)
+ return 0;
+
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
dma->rx_size, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -143,21 +149,31 @@ int serial8250_request_dma(struct uart_8250_port *p)
struct uart_8250_dma *dma = p->dma;
dma_cap_mask_t mask;
- dma->rxconf.src_addr = p->port.mapbase + UART_RX;
- dma->txconf.dst_addr = p->port.mapbase + UART_TX;
+ /* Default slave configuration parameters */
+ dma->rxconf.direction = DMA_DEV_TO_MEM;
+ dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma->rxconf.src_addr = p->port.mapbase + UART_RX;
+
+ dma->txconf.direction = DMA_MEM_TO_DEV;
+ dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma->txconf.dst_addr = p->port.mapbase + UART_TX;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
/* Get a channel for RX */
- dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param);
+ dma->rxchan = dma_request_slave_channel_compat(mask,
+ dma->fn, dma->rx_param,
+ p->port.dev, "rx");
if (!dma->rxchan)
return -ENODEV;
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
/* Get a channel for TX */
- dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param);
+ dma->txchan = dma_request_slave_channel_compat(mask,
+ dma->fn, dma->tx_param,
+ p->port.dev, "tx");
if (!dma->txchan) {
dma_release_channel(dma->rxchan);
return -ENODEV;
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index db0e66f6dd0e..beaa283f5cc6 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -26,6 +26,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include "8250.h"
@@ -34,9 +36,6 @@
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
#define DW_UART_UCV 0xf8 /* UART Component Version */
-/* Intel Low Power Subsystem specific */
-#define LPSS_PRV_CLOCK_PARAMS 0x800
-
/* Component Parameter Register bits */
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
#define DW_UART_CPR_AFCE_MODE (1 << 4)
@@ -55,8 +54,9 @@
struct dw8250_data {
- int last_lcr;
- int line;
+ int last_lcr;
+ int line;
+ struct clk *clk;
};
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
@@ -113,6 +113,18 @@ static int dw8250_handle_irq(struct uart_port *p)
return 0;
}
+static void
+dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
+{
+ if (!state)
+ pm_runtime_get_sync(port->dev);
+
+ serial8250_do_pm(port, state, old);
+
+ if (state)
+ pm_runtime_put_sync_suspend(port->dev);
+}
+
static int dw8250_probe_of(struct uart_port *p)
{
struct device_node *np = p->dev->of_node;
@@ -136,8 +148,13 @@ static int dw8250_probe_of(struct uart_port *p)
if (!of_property_read_u32(np, "reg-shift", &val))
p->regshift = val;
+ /* clock got configured through clk api, all done */
+ if (p->uartclk)
+ return 0;
+
+ /* try to find out clock frequency from DT as fallback */
if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(p->dev, "no clock-frequency property set\n");
+ dev_err(p->dev, "clk or clock-frequency not defined\n");
return -EINVAL;
}
p->uartclk = val;
@@ -146,67 +163,10 @@ static int dw8250_probe_of(struct uart_port *p)
}
#ifdef CONFIG_ACPI
-static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm)
-{
- return chan->chan_id == *(int *)parm;
-}
-
-static acpi_status
-dw8250_acpi_walk_resource(struct acpi_resource *res, void *data)
-{
- struct uart_port *p = data;
- struct uart_8250_port *port;
- struct uart_8250_dma *dma;
- struct acpi_resource_fixed_dma *fixed_dma;
- struct dma_slave_config *slave;
-
- port = container_of(p, struct uart_8250_port, port);
-
- switch (res->type) {
- case ACPI_RESOURCE_TYPE_FIXED_DMA:
- fixed_dma = &res->data.fixed_dma;
-
- /* TX comes first */
- if (!port->dma) {
- dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL);
- if (!dma)
- return AE_NO_MEMORY;
-
- port->dma = dma;
- slave = &dma->txconf;
-
- slave->direction = DMA_MEM_TO_DEV;
- slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave->slave_id = fixed_dma->request_lines;
- slave->dst_maxburst = port->tx_loadsz / 4;
-
- dma->tx_chan_id = fixed_dma->channels;
- dma->tx_param = &dma->tx_chan_id;
- dma->fn = dw8250_acpi_dma_filter;
- } else {
- dma = port->dma;
- slave = &dma->rxconf;
-
- slave->direction = DMA_DEV_TO_MEM;
- slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
- slave->slave_id = fixed_dma->request_lines;
- slave->src_maxburst = p->fifosize / 4;
-
- dma->rx_chan_id = fixed_dma->channels;
- dma->rx_param = &dma->rx_chan_id;
- }
-
- break;
- }
-
- return AE_OK;
-}
-
-static int dw8250_probe_acpi(struct uart_port *p)
+static int dw8250_probe_acpi(struct uart_8250_port *up)
{
const struct acpi_device_id *id;
- acpi_status status;
- u32 reg;
+ struct uart_port *p = &up->port;
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
if (!id)
@@ -216,26 +176,21 @@ static int dw8250_probe_acpi(struct uart_port *p)
p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32;
p->regshift = 2;
- p->uartclk = (unsigned int)id->driver_data;
- status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS,
- dw8250_acpi_walk_resource, p);
- if (ACPI_FAILURE(status)) {
- dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
- acpi_format_exception(status));
- return -ENODEV;
- }
+ if (!p->uartclk)
+ p->uartclk = (unsigned int)id->driver_data;
- /* Fix Haswell issue where the clocks do not get enabled */
- if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) {
- reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS);
- writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS);
- }
+ up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL);
+ if (!up->dma)
+ return -ENOMEM;
+
+ up->dma->rxconf.src_maxburst = p->fifosize / 4;
+ up->dma->txconf.dst_maxburst = p->fifosize / 4;
return 0;
}
#else
-static inline int dw8250_probe_acpi(struct uart_port *p)
+static inline int dw8250_probe_acpi(struct uart_8250_port *up)
{
return -ENODEV;
}
@@ -266,7 +221,11 @@ static void dw8250_setup_port(struct uart_8250_port *up)
p->flags |= UPF_FIXED_TYPE;
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
up->tx_loadsz = p->fifosize;
+ up->capabilities = UART_CAP_FIFO;
}
+
+ if (reg & DW_UART_CPR_AFCE_MODE)
+ up->capabilities |= UART_CAP_AFE;
}
static int dw8250_probe(struct platform_device *pdev)
@@ -286,17 +245,30 @@ static int dw8250_probe(struct platform_device *pdev)
uart.port.mapbase = regs->start;
uart.port.irq = irq->start;
uart.port.handle_irq = dw8250_handle_irq;
+ uart.port.pm = dw8250_do_pm;
uart.port.type = PORT_8250;
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
uart.port.dev = &pdev->dev;
- uart.port.membase = ioremap(regs->start, resource_size(regs));
+ uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
if (!uart.port.membase)
return -ENOMEM;
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(data->clk)) {
+ clk_prepare_enable(data->clk);
+ uart.port.uartclk = clk_get_rate(data->clk);
+ }
+
uart.port.iotype = UPIO_MEM;
uart.port.serial_in = dw8250_serial_in;
uart.port.serial_out = dw8250_serial_out;
+ uart.port.private_data = data;
dw8250_setup_port(&uart);
@@ -305,25 +277,22 @@ static int dw8250_probe(struct platform_device *pdev)
if (err)
return err;
} else if (ACPI_HANDLE(&pdev->dev)) {
- err = dw8250_probe_acpi(&uart.port);
+ err = dw8250_probe_acpi(&uart);
if (err)
return err;
} else {
return -ENODEV;
}
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- uart.port.private_data = data;
-
data->line = serial8250_register_8250_port(&uart);
if (data->line < 0)
return data->line;
platform_set_drvdata(pdev, data);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;
}
@@ -331,34 +300,64 @@ static int dw8250_remove(struct platform_device *pdev)
{
struct dw8250_data *data = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+
serial8250_unregister_port(data->line);
+ if (!IS_ERR(data->clk))
+ clk_disable_unprepare(data->clk);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
return 0;
}
#ifdef CONFIG_PM
-static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
+static int dw8250_suspend(struct device *dev)
{
- struct dw8250_data *data = platform_get_drvdata(pdev);
+ struct dw8250_data *data = dev_get_drvdata(dev);
serial8250_suspend_port(data->line);
return 0;
}
-static int dw8250_resume(struct platform_device *pdev)
+static int dw8250_resume(struct device *dev)
{
- struct dw8250_data *data = platform_get_drvdata(pdev);
+ struct dw8250_data *data = dev_get_drvdata(dev);
serial8250_resume_port(data->line);
return 0;
}
-#else
-#define dw8250_suspend NULL
-#define dw8250_resume NULL
#endif /* CONFIG_PM */
+#ifdef CONFIG_PM_RUNTIME
+static int dw8250_runtime_suspend(struct device *dev)
+{
+ struct dw8250_data *data = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int dw8250_runtime_resume(struct device *dev)
+{
+ struct dw8250_data *data = dev_get_drvdata(dev);
+
+ clk_prepare_enable(data->clk);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops dw8250_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
+ SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
+};
+
static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ }
@@ -366,8 +365,8 @@ static const struct of_device_id dw8250_of_match[] = {
MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = {
- { "INT33C4", 100000000 },
- { "INT33C5", 100000000 },
+ { "INT33C4", 0 },
+ { "INT33C5", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
@@ -376,13 +375,12 @@ static struct platform_driver dw8250_platform_driver = {
.driver = {
.name = "dw-apb-uart",
.owner = THIS_MODULE,
+ .pm = &dw8250_pm_ops,
.of_match_table = dw8250_of_match,
.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
},
.probe = dw8250_probe,
.remove = dw8250_remove,
- .suspend = dw8250_suspend,
- .resume = dw8250_resume,
};
module_platform_driver(dw8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index aa76825229dc..26e3a97ab157 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1554,6 +1554,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
#define PCI_VENDOR_ID_WCH 0x4348
+#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
@@ -2172,6 +2173,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
+ /* WCH CH352 2S card (16550 clone) */
+ {
+ .vendor = PCI_VENDOR_ID_WCH,
+ .device = PCI_DEVICE_ID_WCH_CH352_2S,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .setup = pci_wch_ch353_setup,
+ },
/*
* ASIX devices with FIFO bug
*/
@@ -4870,6 +4879,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, pbn_b0_bt_2_115200 },
+
/*
* Commtech, Inc. Fastcom adapters
*/
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index b3455a970a1d..35d9ab95c5cb 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -429,7 +429,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart;
int ret, line, flags = dev_id->driver_data;
- struct resource *res = NULL;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev);
@@ -440,12 +439,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
memset(&uart, 0, sizeof(uart));
if (pnp_irq_valid(dev, 0))
uart.port.irq = pnp_irq(dev, 0);
- if ((flags & CIR_PORT) && pnp_port_valid(dev, 2))
- res = pnp_get_resource(dev, IORESOURCE_IO, 2);
- else if (pnp_port_valid(dev, 0))
- res = pnp_get_resource(dev, IORESOURCE_IO, 0);
- if (pnp_resource_enabled(res)) {
- uart.port.iobase = res->start;
+ if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
+ uart.port.iobase = pnp_port_start(dev, 2);
+ uart.port.iotype = UPIO_PORT;
+ } else if (pnp_port_valid(dev, 0)) {
+ uart.port.iobase = pnp_port_start(dev, 0);
uart.port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
uart.port.mapbase = pnp_mem_start(dev, 0);
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 2ef9537bcb2c..80fe91e64a52 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -33,6 +33,23 @@ config SERIAL_8250
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
+config SERIAL_8250_DEPRECATED_OPTIONS
+ bool "Support 8250_core.* kernel options (DEPRECATED)"
+ depends on SERIAL_8250
+ default y
+ ---help---
+ In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to
+ accept kernel parameters in both forms like 8250_core.nr_uarts=4 and
+ 8250.nr_uarts=4. We now renamed the module back to 8250, but if
+ anybody noticed in 3.7 and changed their userspace we still have to
+ keep the 8350_core.* options around until they revert the changes
+ they already did.
+
+ If 8250 is built as a module, this adds 8250_core alias instead.
+
+ If you did not notice yet and/or you have userspace from pre-3.7, it
+ is safe (and recommended) to say N here.
+
config SERIAL_8250_PNP
bool "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index a23838a4d535..36d68d054307 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -2,10 +2,10 @@
# Makefile for the 8250 serial device drivers.
#
-obj-$(CONFIG_SERIAL_8250) += 8250_core.o
-8250_core-y := 8250.o
-8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
-8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
+obj-$(CONFIG_SERIAL_8250) += 8250.o
+8250-y := 8250_core.o
+8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index b7d48b346393..1b74b88e1e1e 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -852,18 +852,6 @@ static struct pcmcia_driver serial_cs_driver = {
.suspend = serial_suspend,
.resume = serial_resume,
};
-
-static int __init init_serial_cs(void)
-{
- return pcmcia_register_driver(&serial_cs_driver);
-}
-
-static void __exit exit_serial_cs(void)
-{
- pcmcia_unregister_driver(&serial_cs_driver);
-}
-
-module_init(init_serial_cs);
-module_exit(exit_serial_cs);
+module_pcmcia_driver(serial_cs_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3ea5408fcbeb..b2e9e177a354 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -29,6 +29,7 @@
* and hooked into this driver.
*/
+
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
@@ -72,32 +73,44 @@
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
- unsigned int fifosize;
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
bool dma_threshold;
bool cts_event_workaround;
+
+ unsigned int (*get_fifosize)(unsigned int periphid);
};
+static unsigned int get_fifosize_arm(unsigned int periphid)
+{
+ unsigned int rev = (periphid >> 20) & 0xf;
+ return rev < 3 ? 16 : 32;
+}
+
static struct vendor_data vendor_arm = {
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
- .fifosize = 16,
.lcrh_tx = UART011_LCRH,
.lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
+ .get_fifosize = get_fifosize_arm,
};
+static unsigned int get_fifosize_st(unsigned int periphid)
+{
+ return 64;
+}
+
static struct vendor_data vendor_st = {
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
- .fifosize = 64,
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
.dma_threshold = true,
.cts_event_workaround = true,
+ .get_fifosize = get_fifosize_st,
};
static struct uart_amba_port *amba_ports[UART_NR];
@@ -117,6 +130,12 @@ struct pl011_dmarx_data {
struct pl011_sgbuf sgbuf_b;
dma_cookie_t cookie;
bool running;
+ struct timer_list timer;
+ unsigned int last_residue;
+ unsigned long last_jiffies;
+ bool auto_poll_rate;
+ unsigned int poll_rate;
+ unsigned int poll_timeout;
};
struct pl011_dmatx_data {
@@ -223,16 +242,18 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
enum dma_data_direction dir)
{
- sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
+ dma_addr_t dma_addr;
+
+ sg->buf = dma_alloc_coherent(chan->device->dev,
+ PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);
if (!sg->buf)
return -ENOMEM;
- sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
+ sg_init_table(&sg->sg, 1);
+ sg_set_page(&sg->sg, phys_to_page(dma_addr),
+ PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
+ sg_dma_address(&sg->sg) = dma_addr;
- if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
- kfree(sg->buf);
- return -EINVAL;
- }
return 0;
}
@@ -240,8 +261,9 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
enum dma_data_direction dir)
{
if (sg->buf) {
- dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
- kfree(sg->buf);
+ dma_free_coherent(chan->device->dev,
+ PL011_DMA_BUFFER_SIZE, sg->buf,
+ sg_dma_address(&sg->sg));
}
}
@@ -300,6 +322,29 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
dmaengine_slave_config(chan, &rx_conf);
uap->dmarx.chan = chan;
+ if (plat->dma_rx_poll_enable) {
+ /* Set poll rate if specified. */
+ if (plat->dma_rx_poll_rate) {
+ uap->dmarx.auto_poll_rate = false;
+ uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
+ } else {
+ /*
+ * 100 ms defaults to poll rate if not
+ * specified. This will be adjusted with
+ * the baud rate at set_termios.
+ */
+ uap->dmarx.auto_poll_rate = true;
+ uap->dmarx.poll_rate = 100;
+ }
+ /* 3 secs defaults poll_timeout if not specified. */
+ if (plat->dma_rx_poll_timeout)
+ uap->dmarx.poll_timeout =
+ plat->dma_rx_poll_timeout;
+ else
+ uap->dmarx.poll_timeout = 3000;
+ } else
+ uap->dmarx.auto_poll_rate = false;
+
dev_info(uap->port.dev, "DMA channel RX %s\n",
dma_chan_name(uap->dmarx.chan));
}
@@ -701,24 +746,30 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
struct tty_port *port = &uap->port.state->port;
struct pl011_sgbuf *sgbuf = use_buf_b ?
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
- struct device *dev = uap->dmarx.chan->device->dev;
int dma_count = 0;
u32 fifotaken = 0; /* only used for vdbg() */
- /* Pick everything from the DMA first */
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ int dmataken = 0;
+
+ if (uap->dmarx.poll_rate) {
+ /* The data can be taken by polling */
+ dmataken = sgbuf->sg.length - dmarx->last_residue;
+ /* Recalculate the pending size */
+ if (pending >= dmataken)
+ pending -= dmataken;
+ }
+
+ /* Pick the remain data from the DMA */
if (pending) {
- /* Sync in buffer */
- dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
/*
* First take all chars in the DMA pipe, then look in the FIFO.
* Note that tty_insert_flip_buf() tries to take as many chars
* as it can.
*/
- dma_count = tty_insert_flip_string(port, sgbuf->buf, pending);
-
- /* Return buffer to device */
- dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
+ dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
+ pending);
uap->port.icount.rx += dma_count;
if (dma_count < pending)
@@ -726,6 +777,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
"couldn't insert all characters (TTY is full?)\n");
}
+ /* Reset the last_residue for Rx DMA poll */
+ if (uap->dmarx.poll_rate)
+ dmarx->last_residue = sgbuf->sg.length;
+
/*
* Only continue with trying to read the FIFO if all DMA chars have
* been taken first.
@@ -865,6 +920,57 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
}
+/*
+ * Timer handler for Rx DMA polling.
+ * Every polling, It checks the residue in the dma buffer and transfer
+ * data to the tty. Also, last_residue is updated for the next polling.
+ */
+static void pl011_dma_rx_poll(unsigned long args)
+{
+ struct uart_amba_port *uap = (struct uart_amba_port *)args;
+ struct tty_port *port = &uap->port.state->port;
+ struct pl011_dmarx_data *dmarx = &uap->dmarx;
+ struct dma_chan *rxchan = uap->dmarx.chan;
+ unsigned long flags = 0;
+ unsigned int dmataken = 0;
+ unsigned int size = 0;
+ struct pl011_sgbuf *sgbuf;
+ int dma_count;
+ struct dma_tx_state state;
+
+ sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
+ rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
+ if (likely(state.residue < dmarx->last_residue)) {
+ dmataken = sgbuf->sg.length - dmarx->last_residue;
+ size = dmarx->last_residue - state.residue;
+ dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
+ size);
+ if (dma_count == size)
+ dmarx->last_residue = state.residue;
+ dmarx->last_jiffies = jiffies;
+ }
+ tty_flip_buffer_push(port);
+
+ /*
+ * If no data is received in poll_timeout, the driver will fall back
+ * to interrupt mode. We will retrigger DMA at the first interrupt.
+ */
+ if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
+ > uap->dmarx.poll_timeout) {
+
+ spin_lock_irqsave(&uap->port.lock, flags);
+ pl011_dma_rx_stop(uap);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+
+ uap->dmarx.running = false;
+ dmaengine_terminate_all(rxchan);
+ del_timer(&uap->dmarx.timer);
+ } else {
+ mod_timer(&uap->dmarx.timer,
+ jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
+ }
+}
+
static void pl011_dma_startup(struct uart_amba_port *uap)
{
int ret;
@@ -927,6 +1033,16 @@ skip_rx:
if (pl011_dma_rx_trigger_dma(uap))
dev_dbg(uap->port.dev, "could not trigger initial "
"RX DMA job, fall back to interrupt mode\n");
+ if (uap->dmarx.poll_rate) {
+ init_timer(&(uap->dmarx.timer));
+ uap->dmarx.timer.function = pl011_dma_rx_poll;
+ uap->dmarx.timer.data = (unsigned long)uap;
+ mod_timer(&uap->dmarx.timer,
+ jiffies +
+ msecs_to_jiffies(uap->dmarx.poll_rate));
+ uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
+ uap->dmarx.last_jiffies = jiffies;
+ }
}
}
@@ -962,6 +1078,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
/* Clean up the RX DMA */
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
+ if (uap->dmarx.poll_rate)
+ del_timer_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
@@ -976,7 +1094,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
return uap->using_rx_dma && uap->dmarx.running;
}
-
#else
/* Blank functions if the DMA engine is not available */
static inline void pl011_dma_probe(struct uart_amba_port *uap)
@@ -1088,8 +1205,20 @@ static void pl011_rx_chars(struct uart_amba_port *uap)
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
"fall back to interrupt mode again\n");
uap->im |= UART011_RXIM;
- } else
+ } else {
uap->im &= ~UART011_RXIM;
+#ifdef CONFIG_DMA_ENGINE
+ /* Start Rx DMA poll */
+ if (uap->dmarx.poll_rate) {
+ uap->dmarx.last_jiffies = jiffies;
+ uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
+ mod_timer(&uap->dmarx.timer,
+ jiffies +
+ msecs_to_jiffies(uap->dmarx.poll_rate));
+ }
+#endif
+ }
+
writew(uap->im, uap->port.membase + UART011_IMSC);
}
spin_lock(&uap->port.lock);
@@ -1164,7 +1293,6 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
-
status = readw(uap->port.membase + UART011_MIS);
if (status) {
do {
@@ -1551,6 +1679,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
*/
baud = uart_get_baud_rate(port, termios, old, 0,
port->uartclk / clkdiv);
+#ifdef CONFIG_DMA_ENGINE
+ /*
+ * Adjust RX DMA polling rate with baud rate if not specified.
+ */
+ if (uap->dmarx.auto_poll_rate)
+ uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
+#endif
if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
@@ -2010,7 +2145,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->old_cr = 0;
- uap->fifosize = vendor->fifosize;
+ uap->fifosize = vendor->get_fifosize(dev->periphid);
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index d97e194b6bc5..cbf1d155b7b2 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -162,7 +162,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
/*
* Driver internal routine, used by both tty(serial core) as well as tx-isr
* -Called under spinlock in either cases
- * -also tty->stopped / tty->hw_stopped has already been checked
+ * -also tty->stopped has already been checked
* = by uart_start( ) before calling us
* = tx_ist checks that too before calling
*/
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index d4a7c241b751..3467462869ce 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -158,7 +158,7 @@ struct atmel_uart_port {
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
-static unsigned long atmel_ports_in_use;
+static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART);
#ifdef SUPPORT_SYSRQ
static struct console atmel_console;
@@ -1769,15 +1769,14 @@ static int atmel_serial_probe(struct platform_device *pdev)
if (ret < 0)
/* port id not found in platform data nor device-tree aliases:
* auto-enumerate it */
- ret = find_first_zero_bit(&atmel_ports_in_use,
- sizeof(atmel_ports_in_use));
+ ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART);
- if (ret > ATMEL_MAX_UART) {
+ if (ret >= ATMEL_MAX_UART) {
ret = -ENODEV;
goto err;
}
- if (test_and_set_bit(ret, &atmel_ports_in_use)) {
+ if (test_and_set_bit(ret, atmel_ports_in_use)) {
/* port already in use */
ret = -EBUSY;
goto err;
@@ -1857,7 +1856,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
/* "port" is allocated statically, so we shouldn't free it */
- clear_bit(port->line, &atmel_ports_in_use);
+ clear_bit(port->line, atmel_ports_in_use);
clk_put(atmel_port->clk);
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 12dceda9db33..26a3be7ced7d 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -1011,24 +1011,6 @@ static int bfin_serial_poll_get_char(struct uart_port *port)
}
#endif
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
- defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
-static void bfin_kgdboc_port_shutdown(struct uart_port *port)
-{
- if (kgdboc_break_enabled) {
- kgdboc_break_enabled = 0;
- bfin_serial_shutdown(port);
- }
-}
-
-static int bfin_kgdboc_port_startup(struct uart_port *port)
-{
- kgdboc_port_line = port->line;
- kgdboc_break_enabled = !bfin_serial_startup(port);
- return 0;
-}
-#endif
-
static struct uart_ops bfin_serial_pops = {
.tx_empty = bfin_serial_tx_empty,
.set_mctrl = bfin_serial_set_mctrl,
@@ -1047,11 +1029,6 @@ static struct uart_ops bfin_serial_pops = {
.request_port = bfin_serial_request_port,
.config_port = bfin_serial_config_port,
.verify_port = bfin_serial_verify_port,
-#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
- defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
- .kgdboc_port_startup = bfin_kgdboc_port_startup,
- .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown,
-#endif
#ifdef CONFIG_CONSOLE_POLL
.poll_put_char = bfin_serial_poll_put_char,
.poll_get_char = bfin_serial_poll_get_char,
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 5f37c31e32bc..477f22f773fc 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -169,7 +169,6 @@ static int get_lsr_info(struct e100_serial *info, unsigned int *value);
#define DEF_BAUD 115200 /* 115.2 kbit/s */
-#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
#define DEF_TX 0x80 /* or SERIAL_CTRL_B */
@@ -246,7 +245,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH7_FIRST,
.icmdadr = R_DMA_CH7_CMD,
.idescradr = R_DMA_CH7_DESCR,
- .flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 2,
@@ -300,7 +298,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH9_FIRST,
.icmdadr = R_DMA_CH9_CMD,
.idescradr = R_DMA_CH9_DESCR,
- .flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 3,
@@ -356,7 +353,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH3_FIRST,
.icmdadr = R_DMA_CH3_CMD,
.idescradr = R_DMA_CH3_DESCR,
- .flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 0,
@@ -410,7 +406,6 @@ static struct e100_serial rs_table[] = {
.ifirstadr = R_DMA_CH5_FIRST,
.icmdadr = R_DMA_CH5_CMD,
.idescradr = R_DMA_CH5_DESCR,
- .flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 1,
@@ -2263,8 +2258,7 @@ TODO: The break will be delayed until an F or V character is received.
*/
-static
-struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
+static void handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
{
unsigned long data_read;
@@ -2370,10 +2364,9 @@ more_data:
}
tty_flip_buffer_push(&info->port);
- return info;
}
-static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
+static void handle_ser_rx_interrupt(struct e100_serial *info)
{
unsigned char rstat;
@@ -2382,7 +2375,8 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
#endif
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
if (!info->uses_dma_in) {
- return handle_ser_rx_interrupt_no_dma(info);
+ handle_ser_rx_interrupt_no_dma(info);
+ return;
}
/* DMA is used */
rstat = info->ioport[REG_STATUS];
@@ -2489,7 +2483,6 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
/* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
START_FLUSH_FAST_TIMER(info, "ser_int");
- return info;
} /* handle_ser_rx_interrupt */
static void handle_ser_tx_interrupt(struct e100_serial *info)
@@ -2534,8 +2527,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
}
/* Normal char-by-char interrupt */
if (info->xmit.head == info->xmit.tail
- || info->port.tty->stopped
- || info->port.tty->hw_stopped) {
+ || info->port.tty->stopped) {
DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
info->port.tty->stopped));
e100_disable_serial_tx_ready_irq(info);
@@ -2722,7 +2714,7 @@ startup(struct e100_serial * info)
/* if it was already initialized, skip this */
- if (info->flags & ASYNC_INITIALIZED) {
+ if (info->port.flags & ASYNC_INITIALIZED) {
local_irq_restore(flags);
free_page(xmit_page);
return 0;
@@ -2847,7 +2839,7 @@ startup(struct e100_serial * info)
#endif /* CONFIG_SVINTO_SIM */
- info->flags |= ASYNC_INITIALIZED;
+ info->port.flags |= ASYNC_INITIALIZED;
local_irq_restore(flags);
return 0;
@@ -2892,7 +2884,7 @@ shutdown(struct e100_serial * info)
#endif /* CONFIG_SVINTO_SIM */
- if (!(info->flags & ASYNC_INITIALIZED))
+ if (!(info->port.flags & ASYNC_INITIALIZED))
return;
#ifdef SERIAL_DEBUG_OPEN
@@ -2923,7 +2915,7 @@ shutdown(struct e100_serial * info)
if (info->port.tty)
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->flags &= ~ASYNC_INITIALIZED;
+ info->port.flags &= ~ASYNC_INITIALIZED;
local_irq_restore(flags);
}
@@ -2948,7 +2940,7 @@ change_speed(struct e100_serial *info)
/* possibly, the tx/rx should be disabled first to do this safely */
/* change baud-rate and write it to the hardware */
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
+ if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
/* Special baudrate */
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
unsigned long alt_source =
@@ -3098,7 +3090,6 @@ rs_flush_chars(struct tty_struct *tty)
if (info->tr_running ||
info->xmit.head == info->xmit.tail ||
tty->stopped ||
- tty->hw_stopped ||
!info->xmit.buf)
return;
@@ -3176,7 +3167,6 @@ static int rs_raw_write(struct tty_struct *tty,
if (info->xmit.head != info->xmit.tail &&
!tty->stopped &&
- !tty->hw_stopped &&
!info->tr_running) {
start_transmit(info);
}
@@ -3400,10 +3390,10 @@ get_serial_info(struct e100_serial * info,
tmp.line = info->line;
tmp.port = (int)info->ioport;
tmp.irq = info->irq;
- tmp.flags = info->flags;
+ tmp.flags = info->port.flags;
tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
+ tmp.close_delay = info->port.close_delay;
+ tmp.closing_wait = info->port.closing_wait;
tmp.custom_divisor = info->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -3425,16 +3415,16 @@ set_serial_info(struct e100_serial *info,
if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
+ (new_serial.close_delay != info->port.close_delay) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
- (info->flags & ~ASYNC_USR_MASK)))
+ (info->port.flags & ~ASYNC_USR_MASK)))
return -EPERM;
- info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
goto check_and_exit;
}
- if (info->count > 1)
+ if (info->port.count > 1)
return -EBUSY;
/*
@@ -3443,16 +3433,16 @@ set_serial_info(struct e100_serial *info,
*/
info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
- info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->port.close_delay = new_serial.close_delay;
+ info->port.closing_wait = new_serial.closing_wait;
+ info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit:
- if (info->flags & ASYNC_INITIALIZED) {
+ if (info->port.flags & ASYNC_INITIALIZED) {
change_speed(info);
} else
retval = startup(info);
@@ -3733,10 +3723,8 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios.c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
+ !(tty->termios.c_cflag & CRTSCTS))
rs_start(tty);
- }
}
@@ -3772,7 +3760,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
+ if ((tty->count == 1) && (info->port.count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -3782,32 +3770,32 @@ rs_close(struct tty_struct *tty, struct file * filp)
*/
printk(KERN_ERR
"rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
+ "info->count is %d\n", info->port.count);
+ info->port.count = 1;
}
- if (--info->count < 0) {
+ if (--info->port.count < 0) {
printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, info->count);
- info->count = 0;
+ info->line, info->port.count);
+ info->port.count = 0;
}
- if (info->count) {
+ if (info->port.count) {
local_irq_restore(flags);
return;
}
- info->flags |= ASYNC_CLOSING;
+ info->port.flags |= ASYNC_CLOSING;
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
*/
- if (info->flags & ASYNC_NORMAL_ACTIVE)
+ if (info->port.flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = tty->termios;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
+ if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->port.closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the serial receiver and the DMA receive interrupt.
@@ -3820,7 +3808,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
e100_disable_rx(info);
e100_disable_rx_irq(info);
- if (info->flags & ASYNC_INITIALIZED) {
+ if (info->port.flags & ASYNC_INITIALIZED) {
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
@@ -3836,13 +3824,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
tty->closing = 0;
info->event = 0;
info->port.tty = NULL;
- if (info->blocked_open) {
- if (info->close_delay)
- schedule_timeout_interruptible(info->close_delay);
- wake_up_interruptible(&info->open_wait);
+ if (info->port.blocked_open) {
+ if (info->port.close_delay)
+ schedule_timeout_interruptible(info->port.close_delay);
+ wake_up_interruptible(&info->port.open_wait);
}
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+ info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&info->port.close_wait);
local_irq_restore(flags);
/* port closed */
@@ -3935,10 +3923,10 @@ rs_hangup(struct tty_struct *tty)
rs_flush_buffer(tty);
shutdown(info);
info->event = 0;
- info->count = 0;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ info->port.count = 0;
+ info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
info->port.tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ wake_up_interruptible(&info->port.open_wait);
}
/*
@@ -3960,11 +3948,11 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
* until it's done, and then try again.
*/
if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(tty, info->close_wait,
- !(info->flags & ASYNC_CLOSING));
+ (info->port.flags & ASYNC_CLOSING)) {
+ wait_event_interruptible_tty(tty, info->port.close_wait,
+ !(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
+ if (info->port.flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
return -ERESTARTSYS;
@@ -3979,7 +3967,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
+ info->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -3990,23 +3978,23 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
+ * this loop, info->port.count is dropped by one, so that
* rs_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
- add_wait_queue(&info->open_wait, &wait);
+ add_wait_queue(&info->port.open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
+ info->line, info->port.count);
#endif
local_irq_save(flags);
if (!tty_hung_up_p(filp)) {
extra_count++;
- info->count--;
+ info->port.count--;
}
local_irq_restore(flags);
- info->blocked_open++;
+ info->port.blocked_open++;
while (1) {
local_irq_save(flags);
/* assert RTS and DTR */
@@ -4015,9 +4003,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
local_irq_restore(flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
+ !(info->port.flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
+ if (info->port.flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
@@ -4026,7 +4014,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
break;
}
- if (!(info->flags & ASYNC_CLOSING) && do_clocal)
+ if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
/* && (do_clocal || DCD_IS_ASSERTED) */
break;
if (signal_pending(current)) {
@@ -4035,24 +4023,24 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
}
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
+ info->line, info->port.count);
#endif
tty_unlock(tty);
schedule();
tty_lock(tty);
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&info->open_wait, &wait);
+ remove_wait_queue(&info->port.open_wait, &wait);
if (extra_count)
- info->count++;
- info->blocked_open--;
+ info->port.count++;
+ info->port.blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
+ info->line, info->port.count);
#endif
if (retval)
return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
+ info->port.flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -4086,24 +4074,24 @@ rs_open(struct tty_struct *tty, struct file * filp)
#ifdef SERIAL_DEBUG_OPEN
printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
- info->count);
+ info->port.count);
#endif
- info->count++;
+ info->port.count++;
tty->driver_data = info;
info->port.tty = tty;
- info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
+ info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);
/*
* If the port is in the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(tty, info->close_wait,
- !(info->flags & ASYNC_CLOSING));
+ (info->port.flags & ASYNC_CLOSING)) {
+ wait_event_interruptible_tty(tty, info->port.close_wait,
+ !(info->port.flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
- return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
#else
return -EAGAIN;
@@ -4113,7 +4101,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
/*
* If DMA is enabled try to allocate the irq's.
*/
- if (info->count == 1) {
+ if (info->port.count == 1) {
allocated_resources = 1;
if (info->dma_in_enabled) {
if (request_irq(info->dma_in_irq_nbr,
@@ -4186,7 +4174,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
if (allocated_resources)
deinit_port(info);
- /* FIXME Decrease count info->count here too? */
+ /* FIXME Decrease count info->port.count here too? */
return retval;
}
@@ -4203,7 +4191,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
return retval;
}
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) {
tty->termios = info->normal_termios;
change_speed(info);
}
@@ -4256,9 +4244,6 @@ static void seq_line_info(struct seq_file *m, struct e100_serial *info)
if (info->port.tty->stopped)
seq_printf(m, " stopped:%i",
(int)info->port.tty->stopped);
- if (info->port.tty->hw_stopped)
- seq_printf(m, " hw_stopped:%i",
- (int)info->port.tty->hw_stopped);
}
{
@@ -4455,16 +4440,9 @@ static int __init rs_init(void)
info->forced_eop = 0;
info->baud_base = DEF_BAUD_BASE;
info->custom_divisor = 0;
- info->flags = 0;
- info->close_delay = 5*HZ/10;
- info->closing_wait = 30*HZ;
info->x_char = 0;
info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
info->normal_termios = driver->init_termios;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
info->xmit.buf = NULL;
info->xmit.tail = info->xmit.head = 0;
info->first_recv_buffer = info->last_recv_buffer = NULL;
diff --git a/drivers/tty/serial/crisv10.h b/drivers/tty/serial/crisv10.h
index ea0beb46a10d..7599014ae03f 100644
--- a/drivers/tty/serial/crisv10.h
+++ b/drivers/tty/serial/crisv10.h
@@ -53,8 +53,6 @@ struct e100_serial {
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
- int flags; /* defined in tty.h */
-
u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
u8 iseteop; /* bit number for R_SET_EOP for the input dma */
@@ -88,19 +86,10 @@ struct e100_serial {
volatile int tr_running; /* 1 if output is running */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
unsigned long event;
- unsigned long last_active;
int line;
int type; /* PORT_ETRAX */
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
struct circ_buf xmit;
struct etrax_recv_buffer *first_recv_buffer;
struct etrax_recv_buffer *last_recv_buffer;
@@ -110,9 +99,6 @@ struct e100_serial {
struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/
struct ktermios normal_termios;
- struct ktermios callout_termios;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
unsigned long char_time_usec; /* The time for 1 char, in usecs */
unsigned long flush_time_usec; /* How often we should flush */
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index bc9e6b017b05..18ed5aebb166 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1415,8 +1415,7 @@ static int icom_alloc_adapter(struct icom_adapter
struct icom_adapter *cur_adapter_entry;
struct list_head *tmp;
- icom_adapter = (struct icom_adapter *)
- kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
+ icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
if (!icom_adapter) {
return -ENOMEM;
diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c
index 68d7ce997ede..8b1534c424af 100644
--- a/drivers/tty/serial/ifx6x60.c
+++ b/drivers/tty/serial/ifx6x60.c
@@ -270,23 +270,6 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
}
/**
- * ifx_spi_hangup - hang up an IFX device
- * @ifx_dev: our SPI device
- *
- * Hang up the tty attached to the IFX device if one is currently
- * open. If not take no action
- */
-static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
-{
- struct tty_port *pport = &ifx_dev->tty_port;
- struct tty_struct *tty = tty_port_tty_get(pport);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
-}
-
-/**
* ifx_spi_timeout - SPI timeout
* @arg: our SPI device
*
@@ -298,7 +281,7 @@ static void ifx_spi_timeout(unsigned long arg)
struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
- ifx_spi_ttyhangup(ifx_dev);
+ tty_port_tty_hangup(&ifx_dev->tty_port, false);
mrdy_set_low(ifx_dev);
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
}
@@ -443,25 +426,6 @@ static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
}
/**
- * ifx_spi_wakeup_serial - SPI space made
- * @port_data: our SPI device
- *
- * We have emptied the FIFO enough that we want to get more data
- * queued into it. Poke the line discipline via tty_wakeup so that
- * it will feed us more bits
- */
-static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
-{
- struct tty_struct *tty;
-
- tty = tty_port_tty_get(&ifx_dev->tty_port);
- if (!tty)
- return;
- tty_wakeup(tty);
- tty_kref_put(tty);
-}
-
-/**
* ifx_spi_prepare_tx_buffer - prepare transmit frame
* @ifx_dev: our SPI device
*
@@ -506,7 +470,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
tx_count += temp_count;
if (temp_count == queue_length)
/* poke port to get more data */
- ifx_spi_wakeup_serial(ifx_dev);
+ tty_port_tty_wakeup(&ifx_dev->tty_port);
else /* more data in port, use next SPI message */
ifx_dev->spi_more = 1;
}
@@ -683,8 +647,6 @@ static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
static void ifx_spi_complete(void *ctx)
{
struct ifx_spi_device *ifx_dev = ctx;
- struct tty_struct *tty;
- struct tty_ldisc *ldisc = NULL;
int length;
int actual_length;
unsigned char more;
@@ -762,15 +724,7 @@ complete_exit:
*/
ifx_spi_power_state_clear(ifx_dev,
IFX_SPI_POWER_DATA_PENDING);
- tty = tty_port_tty_get(&ifx_dev->tty_port);
- if (tty) {
- ldisc = tty_ldisc_ref(tty);
- if (ldisc) {
- ldisc->ops->write_wakeup(tty);
- tty_ldisc_deref(ldisc);
- }
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&ifx_dev->tty_port);
}
}
}
@@ -962,7 +916,7 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
if (!solreset) {
/* unsolicited reset */
- ifx_spi_ttyhangup(ifx_dev);
+ tty_port_tty_hangup(&ifx_dev->tty_port, false);
}
} else {
/* exited reset */
@@ -1325,30 +1279,6 @@ static void ifx_spi_spi_shutdown(struct spi_device *spi)
*/
/**
- * ifx_spi_spi_suspend - suspend SPI on system suspend
- * @dev: device being suspended
- *
- * Suspend the SPI side. No action needed on Intel MID platforms, may
- * need extending for other systems.
- */
-static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
-{
- return 0;
-}
-
-/**
- * ifx_spi_spi_resume - resume SPI side on system resume
- * @dev: device being suspended
- *
- * Suspend the SPI side. No action needed on Intel MID platforms, may
- * need extending for other systems.
- */
-static int ifx_spi_spi_resume(struct spi_device *spi)
-{
- return 0;
-}
-
-/**
* ifx_spi_pm_suspend - suspend modem on system suspend
* @dev: device being suspended
*
@@ -1437,8 +1367,6 @@ static struct spi_driver ifx_spi_driver = {
.probe = ifx_spi_spi_probe,
.shutdown = ifx_spi_spi_shutdown,
.remove = ifx_spi_spi_remove,
- .suspend = ifx_spi_spi_suspend,
- .resume = ifx_spi_spi_resume,
.id_table = ifx_id_table
};
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index 00f250ae14c5..27bb75070c96 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -596,12 +596,6 @@ void jsm_input(struct jsm_channel *ch)
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
- if (data_len <= 0) {
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n");
- return;
- }
-
len = tty_buffer_request_room(port, data_len);
n = len;
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 32517d4bceab..35866d5872ad 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -778,7 +778,7 @@ static int max3100_probe(struct spi_device *spi)
max3100s[i]->spi = spi;
max3100s[i]->irq = spi->irq;
spin_lock_init(&max3100s[i]->conf_lock);
- dev_set_drvdata(&spi->dev, max3100s[i]);
+ spi_set_drvdata(spi, max3100s[i]);
pdata = spi->dev.platform_data;
max3100s[i]->crystal = pdata->crystal;
max3100s[i]->loopback = pdata->loopback;
@@ -819,7 +819,7 @@ static int max3100_probe(struct spi_device *spi)
static int max3100_remove(struct spi_device *spi)
{
- struct max3100_port *s = dev_get_drvdata(&spi->dev);
+ struct max3100_port *s = spi_get_drvdata(spi);
int i;
mutex_lock(&max3100s_lock);
@@ -849,11 +849,11 @@ static int max3100_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
-static int max3100_suspend(struct spi_device *spi, pm_message_t state)
+static int max3100_suspend(struct device *dev)
{
- struct max3100_port *s = dev_get_drvdata(&spi->dev);
+ struct max3100_port *s = dev_get_drvdata(dev);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -874,9 +874,9 @@ static int max3100_suspend(struct spi_device *spi, pm_message_t state)
return 0;
}
-static int max3100_resume(struct spi_device *spi)
+static int max3100_resume(struct device *dev)
{
- struct max3100_port *s = dev_get_drvdata(&spi->dev);
+ struct max3100_port *s = dev_get_drvdata(dev);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -894,21 +894,21 @@ static int max3100_resume(struct spi_device *spi)
return 0;
}
+static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
+#define MAX3100_PM_OPS (&max3100_pm_ops)
+
#else
-#define max3100_suspend NULL
-#define max3100_resume NULL
+#define MAX3100_PM_OPS NULL
#endif
static struct spi_driver max3100_driver = {
.driver = {
.name = "max3100",
.owner = THIS_MODULE,
+ .pm = MAX3100_PM_OPS,
},
-
.probe = max3100_probe,
.remove = max3100_remove,
- .suspend = max3100_suspend,
- .resume = max3100_resume,
};
module_spi_driver(max3100_driver);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 0c2422cb04ea..8941e6418942 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -881,12 +881,14 @@ static struct uart_ops max310x_ops = {
.verify_port = max310x_verify_port,
};
-static int max310x_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+
+static int max310x_suspend(struct device *dev)
{
int ret;
- struct max310x_port *s = dev_get_drvdata(&spi->dev);
+ struct max310x_port *s = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "Suspend\n");
+ dev_dbg(dev, "Suspend\n");
ret = uart_suspend_port(&s->uart, &s->port);
@@ -905,11 +907,11 @@ static int max310x_suspend(struct spi_device *spi, pm_message_t state)
return ret;
}
-static int max310x_resume(struct spi_device *spi)
+static int max310x_resume(struct device *dev)
{
- struct max310x_port *s = dev_get_drvdata(&spi->dev);
+ struct max310x_port *s = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "Resume\n");
+ dev_dbg(dev, "Resume\n");
if (s->pdata->suspend)
s->pdata->suspend(0);
@@ -928,6 +930,13 @@ static int max310x_resume(struct spi_device *spi)
return uart_resume_port(&s->uart, &s->port);
}
+static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
+#define MAX310X_PM_OPS (&max310x_pm_ops)
+
+#else
+#define MAX310X_PM_OPS NULL
+#endif
+
#ifdef CONFIG_GPIOLIB
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
@@ -1242,11 +1251,10 @@ static struct spi_driver max310x_driver = {
.driver = {
.name = "max310x",
.owner = THIS_MODULE,
+ .pm = MAX310X_PM_OPS,
},
.probe = max310x_probe,
.remove = max310x_remove,
- .suspend = max310x_suspend,
- .resume = max310x_resume,
.id_table = max310x_id_table,
};
module_spi_driver(max310x_driver);
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index f641c232beca..9b6ef20420c0 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -743,9 +743,10 @@ static struct uart_driver serial_m3110_reg = {
.cons = &serial_m3110_console,
};
-#ifdef CONFIG_PM
-static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int serial_m3110_suspend(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct uart_max3110 *max = spi_get_drvdata(spi);
disable_irq(max->irq);
@@ -754,8 +755,9 @@ static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
return 0;
}
-static int serial_m3110_resume(struct spi_device *spi)
+static int serial_m3110_resume(struct device *dev)
{
+ struct spi_device *spi = to_spi_device(dev);
struct uart_max3110 *max = spi_get_drvdata(spi);
max3110_out(max, max->cur_conf);
@@ -763,9 +765,13 @@ static int serial_m3110_resume(struct spi_device *spi)
enable_irq(max->irq);
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
+ serial_m3110_resume);
+#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
+
#else
-#define serial_m3110_suspend NULL
-#define serial_m3110_resume NULL
+#define SERIAL_M3110_PM_OPS NULL
#endif
static int serial_m3110_probe(struct spi_device *spi)
@@ -872,11 +878,10 @@ static struct spi_driver uart_max3110_driver = {
.driver = {
.name = "spi_max3111",
.owner = THIS_MODULE,
+ .pm = SERIAL_M3110_PM_OPS,
},
.probe = serial_m3110_probe,
.remove = serial_m3110_remove,
- .suspend = serial_m3110_suspend,
- .resume = serial_m3110_resume,
};
static int __init serial_m3110_init(void)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 4a942c78347e..4ca2f64861e6 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -907,7 +907,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
unsigned int error_f = 0;
unsigned long flags;
unsigned int flush;
- struct tty_struct *tty;
struct tty_port *port;
struct uart_port *uport;
struct msm_hs_port *msm_uport;
@@ -919,7 +918,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
clk_enable(msm_uport->clk);
port = &uport->state->port;
- tty = port->tty;
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
diff --git a/drivers/tty/serial/msm_smd_tty.c b/drivers/tty/serial/msm_smd_tty.c
index e722ff163d91..1238ac370bff 100644
--- a/drivers/tty/serial/msm_smd_tty.c
+++ b/drivers/tty/serial/msm_smd_tty.c
@@ -90,13 +90,13 @@ static void smd_tty_notify(void *priv, unsigned event)
static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
{
+ struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
+ port);
int i, res = 0;
- int n = tty->index;
const char *name = NULL;
- struct smd_tty_info *info = smd_tty + n;
for (i = 0; i < smd_tty_channels_len; i++) {
- if (smd_tty_channels[i].id == n) {
+ if (smd_tty_channels[i].id == tty->index) {
name = smd_tty_channels[i].name;
break;
}
@@ -117,17 +117,13 @@ static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
static void smd_tty_port_shutdown(struct tty_port *tport)
{
- struct smd_tty_info *info;
- struct tty_struct *tty = tty_port_tty_get(tport);
+ struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
+ port);
- info = tty->driver_data;
if (info->ch) {
smd_close(info->ch);
info->ch = 0;
}
-
- tty->driver_data = 0;
- tty_kref_put(tty);
}
static int smd_tty_open(struct tty_struct *tty, struct file *f)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index d549fe1fa42a..62e7d3b015a1 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -883,7 +883,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
unsigned int old_ctrl0, old_ctrl2;
unsigned int to = 1000;
- if (co->index > MXS_AUART_PORTS || co->index < 0)
+ if (co->index >= MXS_AUART_PORTS || co->index < 0)
return;
s = auart_port[co->index];
@@ -1103,7 +1103,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->port.fifosize = 16;
s->port.uartclk = clk_get_rate(s->clk);
s->port.type = PORT_IMX;
- s->port.dev = s->dev = get_device(&pdev->dev);
+ s->port.dev = s->dev = &pdev->dev;
s->ctrl = 0;
@@ -1134,7 +1134,6 @@ out_free_irq:
auart_port[pdev->id] = NULL;
free_irq(s->irq, s);
out_free_clk:
- put_device(s->dev);
clk_put(s->clk);
out_free:
kfree(s);
@@ -1150,7 +1149,6 @@ static int mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
- put_device(s->dev);
clk_put(s->clk);
free_irq(s->irq, s);
kfree(s);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index b025d5438275..39c7ea4cb14f 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
-#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -22,6 +21,8 @@
#include <linux/nwpserial.h>
#include <linux/clk.h>
+#include "8250/8250.h"
+
struct of_serial_info {
struct clk *clk;
int type;
@@ -97,6 +98,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
port->regshift = prop;
+ /* Check for fifo size */
+ if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ port->fifosize = prop;
+
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
@@ -167,11 +172,17 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
{
- /* For now the of bindings don't support the extra
- 8250 specific bits */
struct uart_8250_port port8250;
memset(&port8250, 0, sizeof(port8250));
port8250.port = port;
+
+ if (port.fifosize)
+ port8250.capabilities = UART_CAP_FIFO;
+
+ if (of_property_read_bool(ofdev->dev.of_node,
+ "auto-flow-control"))
+ port8250.capabilities |= UART_CAP_AFE;
+
ret = serial8250_register_8250_port(&port8250);
break;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 4dc41408ecb7..30d4f7a783cd 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -886,6 +886,17 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
/* FIFO ENABLE, DMA MODE */
+ up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
+ /*
+ * NOTE: Setting OMAP_UART_SCR_RX_TRIG_GRANU1_MASK
+ * sets Enables the granularity of 1 for TRIGGER RX
+ * level. Along with setting RX FIFO trigger level
+ * to 1 (as noted below, 16 characters) and TLR[3:0]
+ * to zero this will result RX FIFO threshold level
+ * to 1 character, instead of 16 as noted in comment
+ * below.
+ */
+
/* Set receive FIFO threshold to 16 characters and
* transmit FIFO threshold to 16 spaces
*/
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 7a6c989924b3..21a7e179edf3 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -1493,29 +1493,6 @@ static int pch_uart_verify_port(struct uart_port *port,
return 0;
}
-static struct uart_ops pch_uart_ops = {
- .tx_empty = pch_uart_tx_empty,
- .set_mctrl = pch_uart_set_mctrl,
- .get_mctrl = pch_uart_get_mctrl,
- .stop_tx = pch_uart_stop_tx,
- .start_tx = pch_uart_start_tx,
- .stop_rx = pch_uart_stop_rx,
- .enable_ms = pch_uart_enable_ms,
- .break_ctl = pch_uart_break_ctl,
- .startup = pch_uart_startup,
- .shutdown = pch_uart_shutdown,
- .set_termios = pch_uart_set_termios,
-/* .pm = pch_uart_pm, Not supported yet */
-/* .set_wake = pch_uart_set_wake, Not supported yet */
- .type = pch_uart_type,
- .release_port = pch_uart_release_port,
- .request_port = pch_uart_request_port,
- .config_port = pch_uart_config_port,
- .verify_port = pch_uart_verify_port
-};
-
-#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
-
/*
* Wait for transmitter & holding register to empty
*/
@@ -1547,6 +1524,84 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits)
}
}
+#ifdef CONFIG_CONSOLE_POLL
+/*
+ * Console polling routines for communicate via uart while
+ * in an interrupt or debug context.
+ */
+static int pch_uart_get_poll_char(struct uart_port *port)
+{
+ struct eg20t_port *priv =
+ container_of(port, struct eg20t_port, port);
+ u8 lsr = ioread8(priv->membase + UART_LSR);
+
+ if (!(lsr & UART_LSR_DR))
+ return NO_POLL_CHAR;
+
+ return ioread8(priv->membase + PCH_UART_RBR);
+}
+
+
+static void pch_uart_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ unsigned int ier;
+ struct eg20t_port *priv =
+ container_of(port, struct eg20t_port, port);
+
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = ioread8(priv->membase + UART_IER);
+ pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
+
+ wait_for_xmitr(priv, UART_LSR_THRE);
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ iowrite8(c, priv->membase + PCH_UART_THR);
+ if (c == 10) {
+ wait_for_xmitr(priv, UART_LSR_THRE);
+ iowrite8(13, priv->membase + PCH_UART_THR);
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the IER
+ */
+ wait_for_xmitr(priv, BOTH_EMPTY);
+ iowrite8(ier, priv->membase + UART_IER);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static struct uart_ops pch_uart_ops = {
+ .tx_empty = pch_uart_tx_empty,
+ .set_mctrl = pch_uart_set_mctrl,
+ .get_mctrl = pch_uart_get_mctrl,
+ .stop_tx = pch_uart_stop_tx,
+ .start_tx = pch_uart_start_tx,
+ .stop_rx = pch_uart_stop_rx,
+ .enable_ms = pch_uart_enable_ms,
+ .break_ctl = pch_uart_break_ctl,
+ .startup = pch_uart_startup,
+ .shutdown = pch_uart_shutdown,
+ .set_termios = pch_uart_set_termios,
+/* .pm = pch_uart_pm, Not supported yet */
+/* .set_wake = pch_uart_set_wake, Not supported yet */
+ .type = pch_uart_type,
+ .release_port = pch_uart_release_port,
+ .request_port = pch_uart_request_port,
+ .config_port = pch_uart_config_port,
+ .verify_port = pch_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = pch_uart_get_poll_char,
+ .poll_put_char = pch_uart_put_poll_char,
+#endif
+};
+
+#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
+
static void pch_console_putchar(struct uart_port *port, int ch)
{
struct eg20t_port *priv =
@@ -1655,7 +1710,7 @@ static struct console pch_console = {
#define PCH_CONSOLE (&pch_console)
#else
#define PCH_CONSOLE NULL
-#endif
+#endif /* CONFIG_SERIAL_PCH_UART_CONSOLE */
static struct uart_driver pch_uart_driver = {
.owner = THIS_MODULE,
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 2769a38d15b6..074b9194144f 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -39,6 +39,7 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/serial_s3c.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
@@ -46,10 +47,9 @@
#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <plat/regs-serial.h>
+#ifdef CONFIG_SAMSUNG_CLOCK
#include <plat/clock.h>
+#endif
#include "samsung.h"
@@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
/* Clear pending interrupts and mask all interrupts */
if (s3c24xx_serial_has_interrupt_mask(port)) {
+ free_irq(port->irq, ourport);
+
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 0xf);
}
@@ -505,6 +507,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
+ wr_regl(port, S3C64XX_UINTM, 0xf);
+
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
if (ret) {
@@ -894,7 +898,7 @@ console_initcall(s3c24xx_serial_console_init);
#define S3C24XX_SERIAL_CONSOLE NULL
#endif
-#ifdef CONFIG_CONSOLE_POLL
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
static int s3c24xx_serial_get_poll_char(struct uart_port *port);
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
unsigned char c);
@@ -918,7 +922,7 @@ static struct uart_ops s3c24xx_serial_ops = {
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
-#ifdef CONFIG_CONSOLE_POLL
+#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
.poll_get_char = s3c24xx_serial_get_poll_char,
.poll_put_char = s3c24xx_serial_put_poll_char,
#endif
@@ -1179,6 +1183,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
return 0;
}
+#ifdef CONFIG_SAMSUNG_CLOCK
static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1194,7 +1199,7 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
}
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
-
+#endif
/* Device driver serial port probe */
@@ -1252,9 +1257,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(pdev, &ourport->port);
+#ifdef CONFIG_SAMSUNG_CLOCK
ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
if (ret < 0)
dev_err(&pdev->dev, "failed to add clock source attr.\n");
+#endif
ret = s3c24xx_serial_cpufreq_register(ourport);
if (ret < 0)
@@ -1272,7 +1279,9 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
if (port) {
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
+#ifdef CONFIG_SAMSUNG_CLOCK
device_remove_file(&dev->dev, &dev_attr_clock_source);
+#endif
uart_remove_one_port(&s3c24xx_uart_drv, port);
}
@@ -1307,9 +1316,29 @@ static int s3c24xx_serial_resume(struct device *dev)
return 0;
}
+static int s3c24xx_serial_resume_noirq(struct device *dev)
+{
+ struct uart_port *port = s3c24xx_dev_to_port(dev);
+
+ if (port) {
+ /* restore IRQ mask */
+ if (s3c24xx_serial_has_interrupt_mask(port)) {
+ unsigned int uintm = 0xf;
+ if (tx_enabled(port))
+ uintm &= ~S3C64XX_UINTM_TXD_MSK;
+ if (rx_enabled(port))
+ uintm &= ~S3C64XX_UINTM_RXD_MSK;
+ wr_regl(port, S3C64XX_UINTM, uintm);
+ }
+ }
+
+ return 0;
+}
+
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
.suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume,
+ .resume_noirq = s3c24xx_serial_resume_noirq,
};
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
@@ -1343,6 +1372,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
}
+static bool
+s3c24xx_port_configured(unsigned int ucon)
+{
+ /* consider the serial port configured if the tx/rx mode set */
+ return (ucon & 0xf) != 0;
+}
+
#ifdef CONFIG_CONSOLE_POLL
/*
* Console polling routines for writing and reading from the uart while
@@ -1365,6 +1401,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
unsigned char c)
{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+ unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+
+ /* not possible to xmit on unconfigured port */
+ if (!s3c24xx_port_configured(ucon))
+ return;
while (!s3c24xx_serial_console_txrdy(port, ufcon))
cpu_relax();
@@ -1377,6 +1418,12 @@ static void
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
{
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+ unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
+
+ /* not possible to xmit on unconfigured port */
+ if (!s3c24xx_port_configured(ucon))
+ return;
+
while (!s3c24xx_serial_console_txrdy(port, ufcon))
barrier();
wr_regb(cons_uart, S3C2410_UTXH, ch);
@@ -1409,9 +1456,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
port, ulcon, ucon, ubrdiv);
- if ((ucon & 0xf) != 0) {
- /* consider the serial port configured if the tx/rx mode set */
-
+ if (s3c24xx_port_configured(ucon)) {
switch (ulcon & S3C2410_LCON_CSMASK) {
case S3C2410_LCON_CS5:
*bits = 5;
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index 1a4bca3e4179..00a499ecd385 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -76,7 +76,9 @@ struct s3c24xx_uart_port {
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
-#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
+#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
+ defined(CONFIG_DEBUG_LL) && \
+ !defined(MODULE)
extern void printascii(const char *);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 08dbfb88d42c..c77304155410 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -27,6 +27,7 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/platform_data/serial-sccnxp.h>
+#include <linux/regulator/consumer.h>
#define SCCNXP_NAME "uart-sccnxp"
#define SCCNXP_MAJOR 204
@@ -131,6 +132,8 @@ struct sccnxp_port {
struct timer_list timer;
struct sccnxp_pdata pdata;
+
+ struct regulator *regulator;
};
static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
@@ -789,8 +792,6 @@ static int sccnxp_probe(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}
- dev_set_name(&pdev->dev, SCCNXP_NAME);
-
s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
if (!s) {
dev_err(&pdev->dev, "Error allocating port structure\n");
@@ -918,6 +919,16 @@ static int sccnxp_probe(struct platform_device *pdev)
goto err_out;
}
+ s->regulator = devm_regulator_get(&pdev->dev, "VCC");
+ if (!IS_ERR(s->regulator)) {
+ ret = regulator_enable(s->regulator);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to enable regulator: %i\n", ret);
+ return ret;
+ }
+ }
+
membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(membase)) {
ret = PTR_ERR(membase);
@@ -967,10 +978,6 @@ static int sccnxp_probe(struct platform_device *pdev)
s->imr = 0;
sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
- /* Board specific configure */
- if (s->pdata.init)
- s->pdata.init();
-
if (!s->poll) {
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
sccnxp_ist,
@@ -1011,8 +1018,8 @@ static int sccnxp_remove(struct platform_device *pdev)
uart_unregister_driver(&s->uart);
platform_set_drvdata(pdev, NULL);
- if (s->pdata.exit)
- s->pdata.exit();
+ if (!IS_ERR(s->regulator))
+ return regulator_disable(s->regulator);
return 0;
}
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 372de8ade76a..9799d043a9bd 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -26,6 +26,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -1301,11 +1302,9 @@ static int tegra_uart_probe(struct platform_device *pdev)
}
u->mapbase = resource->start;
- u->membase = devm_request_and_ioremap(&pdev->dev, resource);
- if (!u->membase) {
- dev_err(&pdev->dev, "memregion/iomap address req failed\n");
- return -EADDRNOTAVAIL;
- }
+ u->membase = devm_ioremap_resource(&pdev->dev, resource);
+ if (IS_ERR(u->membase))
+ return PTR_ERR(u->membase);
tup->uart_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tup->uart_clk)) {
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 19cc749f8386..f87dbfd32770 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1941,6 +1941,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
mutex_unlock(&port->mutex);
return 0;
}
+ put_device(tty_dev);
+
if (console_suspend_enabled || !uart_console(uport))
uport->suspended = 1;
@@ -2006,9 +2008,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
disable_irq_wake(uport->irq);
uport->irq_wake = 0;
}
+ put_device(tty_dev);
mutex_unlock(&port->mutex);
return 0;
}
+ put_device(tty_dev);
uport->suspended = 0;
/*
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 4c22a1529aac..5aca7364634c 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -15,8 +15,6 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH73A0) || \
- defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
defined(CONFIG_ARCH_SH7372) || \
defined(CONFIG_ARCH_R8A7740)
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index 6bbfe9934a4d..03465b673945 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -758,7 +758,7 @@ static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,marco-uart", },
{}
};
-MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
+MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
static struct platform_driver sirfsoc_uart_driver = {
.probe = sirfsoc_uart_probe,
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 8de2213664e0..a422c8b55a47 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -203,7 +203,7 @@ receive_chars(struct uart_sunsab_port *up,
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch))
+ if (uart_handle_sysrq_char(&up->port, ch) || !port)
continue;
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index 27669ff3d446..813ef8eb8eff 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -388,7 +388,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
else if (r1 & CRC_ERR)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch))
+ if (uart_handle_sysrq_char(&up->port, ch) || !port)
continue;
if (up->port.ignore_status_mask == 0xff ||
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
index 705240e6c4ec..1a8bc2275ea4 100644
--- a/drivers/tty/serial/vt8500_serial.c
+++ b/drivers/tty/serial/vt8500_serial.c
@@ -35,6 +35,7 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/err.h>
/*
* UART Register offsets
@@ -585,9 +586,9 @@ static int vt8500_serial_probe(struct platform_device *pdev)
if (!vt8500_port)
return -ENOMEM;
- vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres);
- if (!vt8500_port->uart.membase)
- return -EADDRNOTAVAIL;
+ vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres);
+ if (IS_ERR(vt8500_port->uart.membase))
+ return PTR_ERR(vt8500_port->uart.membase);
vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(vt8500_port->clk)) {
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index ba451c7209fc..4e5c77834c50 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -578,14 +578,13 @@ static int xuartps_startup(struct uart_port *port)
/* Receive Timeout register is enabled with value of 10 */
xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);
+ /* Clear out any pending interrupts before enabling them */
+ xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET);
/* Set the Interrupt Registers with desired interrupts */
xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
- xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
- XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
- XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);
return retval;
}
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 8983276aa35e..8eaf1ab8addb 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -1058,9 +1058,6 @@ static void mgsl_bh_handler(struct work_struct *work)
container_of(work, struct mgsl_struct, task);
int action;
- if (!info)
- return;
-
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name);
@@ -3311,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
port->blocked_open++;
while (1) {
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa9eece35c3b..1abf946463f6 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3308,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if ((tty->termios.c_cflag & CBAUD))
+ if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index 6d5780cf1d57..ff171384ea52 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3329,7 +3329,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
port->blocked_open++;
while (1) {
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 3687f0cad642..b51c15408ff3 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -43,6 +43,7 @@
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/moduleparam.h>
+#include <linux/jiffies.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -51,6 +52,9 @@
static int __read_mostly sysrq_enabled = SYSRQ_DEFAULT_ENABLE;
static bool __read_mostly sysrq_always_enabled;
+unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
+int sysrq_reset_downtime_ms __weak;
+
static bool sysrq_on(void)
{
return sysrq_enabled || sysrq_always_enabled;
@@ -101,7 +105,7 @@ static void sysrq_handle_SAK(int key)
}
static struct sysrq_key_op sysrq_SAK_op = {
.handler = sysrq_handle_SAK,
- .help_msg = "saK",
+ .help_msg = "sak(k)",
.action_msg = "SAK",
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
@@ -117,7 +121,7 @@ static void sysrq_handle_unraw(int key)
static struct sysrq_key_op sysrq_unraw_op = {
.handler = sysrq_handle_unraw,
- .help_msg = "unRaw",
+ .help_msg = "unraw(r)",
.action_msg = "Keyboard mode set to system default",
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
@@ -135,7 +139,7 @@ static void sysrq_handle_crash(int key)
}
static struct sysrq_key_op sysrq_crash_op = {
.handler = sysrq_handle_crash,
- .help_msg = "Crash",
+ .help_msg = "crash(c)",
.action_msg = "Trigger a crash",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -148,7 +152,7 @@ static void sysrq_handle_reboot(int key)
}
static struct sysrq_key_op sysrq_reboot_op = {
.handler = sysrq_handle_reboot,
- .help_msg = "reBoot",
+ .help_msg = "reboot(b)",
.action_msg = "Resetting",
.enable_mask = SYSRQ_ENABLE_BOOT,
};
@@ -159,7 +163,7 @@ static void sysrq_handle_sync(int key)
}
static struct sysrq_key_op sysrq_sync_op = {
.handler = sysrq_handle_sync,
- .help_msg = "Sync",
+ .help_msg = "sync(s)",
.action_msg = "Emergency Sync",
.enable_mask = SYSRQ_ENABLE_SYNC,
};
@@ -171,7 +175,7 @@ static void sysrq_handle_show_timers(int key)
static struct sysrq_key_op sysrq_show_timers_op = {
.handler = sysrq_handle_show_timers,
- .help_msg = "show-all-timers(Q)",
+ .help_msg = "show-all-timers(q)",
.action_msg = "Show clockevent devices & pending hrtimers (no others)",
};
@@ -181,7 +185,7 @@ static void sysrq_handle_mountro(int key)
}
static struct sysrq_key_op sysrq_mountro_op = {
.handler = sysrq_handle_mountro,
- .help_msg = "Unmount",
+ .help_msg = "unmount(u)",
.action_msg = "Emergency Remount R/O",
.enable_mask = SYSRQ_ENABLE_REMOUNT,
};
@@ -194,7 +198,7 @@ static void sysrq_handle_showlocks(int key)
static struct sysrq_key_op sysrq_showlocks_op = {
.handler = sysrq_handle_showlocks,
- .help_msg = "show-all-locks(D)",
+ .help_msg = "show-all-locks(d)",
.action_msg = "Show Locks Held",
};
#else
@@ -245,7 +249,7 @@ static void sysrq_handle_showallcpus(int key)
static struct sysrq_key_op sysrq_showallcpus_op = {
.handler = sysrq_handle_showallcpus,
- .help_msg = "show-backtrace-all-active-cpus(L)",
+ .help_msg = "show-backtrace-all-active-cpus(l)",
.action_msg = "Show backtrace of all active CPUs",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -260,7 +264,7 @@ static void sysrq_handle_showregs(int key)
}
static struct sysrq_key_op sysrq_showregs_op = {
.handler = sysrq_handle_showregs,
- .help_msg = "show-registers(P)",
+ .help_msg = "show-registers(p)",
.action_msg = "Show Regs",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -271,7 +275,7 @@ static void sysrq_handle_showstate(int key)
}
static struct sysrq_key_op sysrq_showstate_op = {
.handler = sysrq_handle_showstate,
- .help_msg = "show-task-states(T)",
+ .help_msg = "show-task-states(t)",
.action_msg = "Show State",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -282,7 +286,7 @@ static void sysrq_handle_showstate_blocked(int key)
}
static struct sysrq_key_op sysrq_showstate_blocked_op = {
.handler = sysrq_handle_showstate_blocked,
- .help_msg = "show-blocked-tasks(W)",
+ .help_msg = "show-blocked-tasks(w)",
.action_msg = "Show Blocked State",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -296,7 +300,7 @@ static void sysrq_ftrace_dump(int key)
}
static struct sysrq_key_op sysrq_ftrace_dump_op = {
.handler = sysrq_ftrace_dump,
- .help_msg = "dump-ftrace-buffer(Z)",
+ .help_msg = "dump-ftrace-buffer(z)",
.action_msg = "Dump ftrace buffer",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -310,7 +314,7 @@ static void sysrq_handle_showmem(int key)
}
static struct sysrq_key_op sysrq_showmem_op = {
.handler = sysrq_handle_showmem,
- .help_msg = "show-memory-usage(M)",
+ .help_msg = "show-memory-usage(m)",
.action_msg = "Show Memory",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
@@ -341,7 +345,7 @@ static void sysrq_handle_term(int key)
}
static struct sysrq_key_op sysrq_term_op = {
.handler = sysrq_handle_term,
- .help_msg = "terminate-all-tasks(E)",
+ .help_msg = "terminate-all-tasks(e)",
.action_msg = "Terminate All Tasks",
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
@@ -360,7 +364,7 @@ static void sysrq_handle_moom(int key)
}
static struct sysrq_key_op sysrq_moom_op = {
.handler = sysrq_handle_moom,
- .help_msg = "memory-full-oom-kill(F)",
+ .help_msg = "memory-full-oom-kill(f)",
.action_msg = "Manual OOM execution",
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
@@ -372,7 +376,7 @@ static void sysrq_handle_thaw(int key)
}
static struct sysrq_key_op sysrq_thaw_op = {
.handler = sysrq_handle_thaw,
- .help_msg = "thaw-filesystems(J)",
+ .help_msg = "thaw-filesystems(j)",
.action_msg = "Emergency Thaw of all frozen filesystems",
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
@@ -385,7 +389,7 @@ static void sysrq_handle_kill(int key)
}
static struct sysrq_key_op sysrq_kill_op = {
.handler = sysrq_handle_kill,
- .help_msg = "kill-all-tasks(I)",
+ .help_msg = "kill-all-tasks(i)",
.action_msg = "Kill All Tasks",
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
@@ -396,7 +400,7 @@ static void sysrq_handle_unrt(int key)
}
static struct sysrq_key_op sysrq_unrt_op = {
.handler = sysrq_handle_unrt,
- .help_msg = "nice-all-RT-tasks(N)",
+ .help_msg = "nice-all-RT-tasks(n)",
.action_msg = "Nice All RT Tasks",
.enable_mask = SYSRQ_ENABLE_RTNICE,
};
@@ -586,6 +590,7 @@ struct sysrq_state {
int reset_seq_len;
int reset_seq_cnt;
int reset_seq_version;
+ struct timer_list keyreset_timer;
};
#define SYSRQ_KEY_RESET_MAX 20 /* Should be plenty */
@@ -619,29 +624,51 @@ static void sysrq_parse_reset_sequence(struct sysrq_state *state)
state->reset_seq_version = sysrq_reset_seq_version;
}
-static bool sysrq_detect_reset_sequence(struct sysrq_state *state,
+static void sysrq_do_reset(unsigned long dummy)
+{
+ __handle_sysrq(sysrq_xlate[KEY_B], false);
+}
+
+static void sysrq_handle_reset_request(struct sysrq_state *state)
+{
+ if (sysrq_reset_downtime_ms)
+ mod_timer(&state->keyreset_timer,
+ jiffies + msecs_to_jiffies(sysrq_reset_downtime_ms));
+ else
+ sysrq_do_reset(0);
+}
+
+static void sysrq_detect_reset_sequence(struct sysrq_state *state,
unsigned int code, int value)
{
if (!test_bit(code, state->reset_keybit)) {
/*
* Pressing any key _not_ in reset sequence cancels
- * the reset sequence.
+ * the reset sequence. Also cancelling the timer in
+ * case additional keys were pressed after a reset
+ * has been requested.
*/
- if (value && state->reset_seq_cnt)
+ if (value && state->reset_seq_cnt) {
state->reset_canceled = true;
+ del_timer(&state->keyreset_timer);
+ }
} else if (value == 0) {
- /* key release */
+ /*
+ * Key release - all keys in the reset sequence need
+ * to be pressed and held for the reset timeout
+ * to hold.
+ */
+ del_timer(&state->keyreset_timer);
+
if (--state->reset_seq_cnt == 0)
state->reset_canceled = false;
} else if (value == 1) {
/* key press, not autorepeat */
if (++state->reset_seq_cnt == state->reset_seq_len &&
!state->reset_canceled) {
- return true;
+ sysrq_handle_reset_request(state);
}
}
-
- return false;
}
static void sysrq_reinject_alt_sysrq(struct work_struct *work)
@@ -748,10 +775,8 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
if (was_active)
schedule_work(&sysrq->reinject_work);
- if (sysrq_detect_reset_sequence(sysrq, code, value)) {
- /* Force emergency reboot */
- __handle_sysrq(sysrq_xlate[KEY_B], false);
- }
+ /* Check for reset sequence */
+ sysrq_detect_reset_sequence(sysrq, code, value);
} else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) {
/*
@@ -812,6 +837,7 @@ static int sysrq_connect(struct input_handler *handler,
sysrq->handle.handler = handler;
sysrq->handle.name = "sysrq";
sysrq->handle.private = sysrq;
+ setup_timer(&sysrq->keyreset_timer, sysrq_do_reset, 0);
error = input_register_handle(&sysrq->handle);
if (error) {
@@ -841,6 +867,7 @@ static void sysrq_disconnect(struct input_handle *handle)
input_close_device(handle);
cancel_work_sync(&sysrq->reinject_work);
+ del_timer_sync(&sysrq->keyreset_timer);
input_unregister_handle(handle);
kfree(sysrq);
}
@@ -870,8 +897,6 @@ static struct input_handler sysrq_handler = {
static bool sysrq_handler_registered;
-unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
-
static inline void sysrq_register_handler(void)
{
unsigned short key;
@@ -931,6 +956,8 @@ static struct kernel_param_ops param_ops_sysrq_reset_seq = {
module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
&sysrq_reset_seq_len, 0644);
+module_param_named(sysrq_downtime_ms, sysrq_reset_downtime_ms, int, 0644);
+
#else
static inline void sysrq_register_handler(void)
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 578aa7594b11..9121c1f7aeef 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -449,11 +449,6 @@ static void flush_to_ldisc(struct work_struct *work)
tty_buffer_free(port, head);
continue;
}
- /* Ldisc or user is trying to flush the buffers
- we are feeding to the ldisc, stop feeding the
- line discipline as we want to empty the queue */
- if (test_bit(TTYP_FLUSHPENDING, &port->iflags))
- break;
if (!tty->receive_room)
break;
if (count > tty->receive_room)
@@ -465,17 +460,20 @@ static void flush_to_ldisc(struct work_struct *work)
disc->ops->receive_buf(tty, char_buf,
flag_buf, count);
spin_lock_irqsave(&buf->lock, flags);
+ /* Ldisc or user is trying to flush the buffers.
+ We may have a deferred request to flush the
+ input buffer, if so pull the chain under the lock
+ and empty the queue */
+ if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
+ __tty_buffer_flush(port);
+ clear_bit(TTYP_FLUSHPENDING, &port->iflags);
+ wake_up(&tty->read_wait);
+ break;
+ }
}
clear_bit(TTYP_FLUSHING, &port->iflags);
}
- /* We may have a deferred request to flush the input buffer,
- if so pull the chain under the lock and empty the queue */
- if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
- __tty_buffer_flush(port);
- clear_bit(TTYP_FLUSHPENDING, &port->iflags);
- wake_up(&tty->read_wait);
- }
spin_unlock_irqrestore(&buf->lock, flags);
tty_ldisc_deref(disc);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 05400acbc456..6464029e4860 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -533,6 +533,60 @@ void tty_wakeup(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_wakeup);
/**
+ * tty_signal_session_leader - sends SIGHUP to session leader
+ * @tty controlling tty
+ * @exit_session if non-zero, signal all foreground group processes
+ *
+ * Send SIGHUP and SIGCONT to the session leader and its process group.
+ * Optionally, signal all processes in the foreground process group.
+ *
+ * Returns the number of processes in the session with this tty
+ * as their controlling terminal. This value is used to drop
+ * tty references for those processes.
+ */
+static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
+{
+ struct task_struct *p;
+ int refs = 0;
+ struct pid *tty_pgrp = NULL;
+
+ read_lock(&tasklist_lock);
+ if (tty->session) {
+ do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+ spin_lock_irq(&p->sighand->siglock);
+ if (p->signal->tty == tty) {
+ p->signal->tty = NULL;
+ /* We defer the dereferences outside fo
+ the tasklist lock */
+ refs++;
+ }
+ if (!p->signal->leader) {
+ spin_unlock_irq(&p->sighand->siglock);
+ continue;
+ }
+ __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+ __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+ put_pid(p->signal->tty_old_pgrp); /* A noop */
+ spin_lock(&tty->ctrl_lock);
+ tty_pgrp = get_pid(tty->pgrp);
+ if (tty->pgrp)
+ p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+ spin_unlock(&tty->ctrl_lock);
+ spin_unlock_irq(&p->sighand->siglock);
+ } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+ }
+ read_unlock(&tasklist_lock);
+
+ if (tty_pgrp) {
+ if (exit_session)
+ kill_pgrp(tty_pgrp, SIGHUP, exit_session);
+ put_pid(tty_pgrp);
+ }
+
+ return refs;
+}
+
+/**
* __tty_hangup - actual handler for hangup events
* @work: tty device
*
@@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
* tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand
*/
-static void __tty_hangup(struct tty_struct *tty)
+static void __tty_hangup(struct tty_struct *tty, int exit_session)
{
struct file *cons_filp = NULL;
struct file *filp, *f = NULL;
- struct task_struct *p;
struct tty_file_private *priv;
int closecount = 0, n;
- unsigned long flags;
- int refs = 0;
+ int refs;
if (!tty)
return;
@@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty)
}
spin_unlock(&tty_files_lock);
+ refs = tty_signal_session_leader(tty, exit_session);
+ /* Account for the p->signal references we killed */
+ while (refs--)
+ tty_kref_put(tty);
+
/*
* it drops BTM and thus races with reopen
* we protect the race by TTY_HUPPING
*/
tty_ldisc_hangup(tty);
- read_lock(&tasklist_lock);
- if (tty->session) {
- do_each_pid_task(tty->session, PIDTYPE_SID, p) {
- spin_lock_irq(&p->sighand->siglock);
- if (p->signal->tty == tty) {
- p->signal->tty = NULL;
- /* We defer the dereferences outside fo
- the tasklist lock */
- refs++;
- }
- if (!p->signal->leader) {
- spin_unlock_irq(&p->sighand->siglock);
- continue;
- }
- __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
- __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
- put_pid(p->signal->tty_old_pgrp); /* A noop */
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->pgrp)
- p->signal->tty_old_pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
- spin_unlock_irq(&p->sighand->siglock);
- } while_each_pid_task(tty->session, PIDTYPE_SID, p);
- }
- read_unlock(&tasklist_lock);
-
- spin_lock_irqsave(&tty->ctrl_lock, flags);
+ spin_lock_irq(&tty->ctrl_lock);
clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_PUSH, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -640,11 +671,7 @@ static void __tty_hangup(struct tty_struct *tty)
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
- /* Account for the p->signal references we killed */
- while (refs--)
- tty_kref_put(tty);
+ spin_unlock_irq(&tty->ctrl_lock);
/*
* If one of the devices matches a console pointer, we
@@ -666,7 +693,6 @@ static void __tty_hangup(struct tty_struct *tty)
*/
set_bit(TTY_HUPPED, &tty->flags);
clear_bit(TTY_HUPPING, &tty->flags);
- tty_ldisc_enable(tty);
tty_unlock(tty);
@@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work)
struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work);
- __tty_hangup(tty);
+ __tty_hangup(tty, 0);
}
/**
@@ -717,7 +743,7 @@ void tty_vhangup(struct tty_struct *tty)
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
#endif
- __tty_hangup(tty);
+ __tty_hangup(tty, 0);
}
EXPORT_SYMBOL(tty_vhangup);
@@ -741,6 +767,27 @@ void tty_vhangup_self(void)
}
/**
+ * tty_vhangup_session - hangup session leader exit
+ * @tty: tty to hangup
+ *
+ * The session leader is exiting and hanging up its controlling terminal.
+ * Every process in the foreground process group is signalled SIGHUP.
+ *
+ * We do this synchronously so that when the syscall returns the process
+ * is complete. That guarantee is necessary for security reasons.
+ */
+
+static void tty_vhangup_session(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+ char buf[64];
+
+ printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
+#endif
+ __tty_hangup(tty, 1);
+}
+
+/**
* tty_hung_up_p - was tty hung up
* @filp: file pointer of tty
*
@@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit)
tty = get_current_tty();
if (tty) {
- struct pid *tty_pgrp = get_pid(tty->pgrp);
- if (on_exit) {
- if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
- tty_vhangup(tty);
- }
- tty_kref_put(tty);
- if (tty_pgrp) {
- kill_pgrp(tty_pgrp, SIGHUP, on_exit);
- if (!on_exit)
+ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
+ tty_vhangup_session(tty);
+ } else {
+ struct pid *tty_pgrp = tty_get_pgrp(tty);
+ if (tty_pgrp) {
+ kill_pgrp(tty_pgrp, SIGHUP, on_exit);
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
- put_pid(tty_pgrp);
+ put_pid(tty_pgrp);
+ }
}
+ tty_kref_put(tty);
+
} else if (on_exit) {
struct pid *old_pgrp;
spin_lock_irq(&current->sighand->siglock);
@@ -941,6 +988,14 @@ void start_tty(struct tty_struct *tty)
EXPORT_SYMBOL(start_tty);
+/* We limit tty time update visibility to every 8 seconds or so. */
+static void tty_update_time(struct timespec *time)
+{
+ unsigned long sec = get_seconds() & ~7;
+ if ((long)(sec - time->tv_sec) > 0)
+ time->tv_sec = sec;
+}
+
/**
* tty_read - read method for tty device files
* @file: pointer to tty file
@@ -960,10 +1015,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
int i;
+ struct inode *inode = file_inode(file);
struct tty_struct *tty = file_tty(file);
struct tty_ldisc *ld;
- if (tty_paranoia_check(tty, file_inode(file), "tty_read"))
+ if (tty_paranoia_check(tty, inode, "tty_read"))
return -EIO;
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
@@ -977,6 +1033,9 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
i = -EIO;
tty_ldisc_deref(ld);
+ if (i > 0)
+ tty_update_time(&inode->i_atime);
+
return i;
}
@@ -1077,8 +1136,10 @@ static inline ssize_t do_tty_write(
break;
cond_resched();
}
- if (written)
+ if (written) {
+ tty_update_time(&file_inode(file)->i_mtime);
ret = written;
+ }
out:
tty_write_unlock(tty);
return ret;
@@ -1344,9 +1405,7 @@ static int tty_reopen(struct tty_struct *tty)
}
tty->count++;
- mutex_lock(&tty->ldisc_mutex);
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
- mutex_unlock(&tty->ldisc_mutex);
return 0;
}
@@ -1463,6 +1522,17 @@ void tty_free_termios(struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_free_termios);
+/**
+ * tty_flush_works - flush all works of a tty
+ * @tty: tty device to flush works for
+ *
+ * Sync flush all works belonging to @tty.
+ */
+static void tty_flush_works(struct tty_struct *tty)
+{
+ flush_work(&tty->SAK_work);
+ flush_work(&tty->hangup_work);
+}
/**
* release_one_tty - release tty structure memory
@@ -1548,6 +1618,7 @@ static void release_tty(struct tty_struct *tty, int idx)
tty_free_termios(tty);
tty_driver_remove_tty(tty->driver, tty);
tty->port->itty = NULL;
+ cancel_work_sync(&tty->port->buf.work);
if (tty->link)
tty_kref_put(tty->link);
@@ -1777,12 +1848,21 @@ int tty_release(struct inode *inode, struct file *filp)
return 0;
#ifdef TTY_DEBUG_HANGUP
- printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
+ printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
#endif
/*
* Ask the line discipline code to release its structures
*/
tty_ldisc_release(tty, o_tty);
+
+ /* Wait for pending work before tty destruction commmences */
+ tty_flush_works(tty);
+ if (o_tty)
+ tty_flush_works(o_tty);
+
+#ifdef TTY_DEBUG_HANGUP
+ printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
+#endif
/*
* The release_tty function takes care of the details of clearing
* the slots and preserving the termios structure. The tty_unlock_pair
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index d58b92cc187c..3500d4114147 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -106,6 +106,7 @@ void tty_throttle(struct tty_struct *tty)
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle)
tty->ops->throttle(tty);
+ tty->flow_change = 0;
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_throttle);
@@ -129,11 +130,74 @@ void tty_unthrottle(struct tty_struct *tty)
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle)
tty->ops->unthrottle(tty);
+ tty->flow_change = 0;
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_unthrottle);
/**
+ * tty_throttle_safe - flow control
+ * @tty: terminal
+ *
+ * Similar to tty_throttle() but will only attempt throttle
+ * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
+ * throttle due to race conditions when throttling is conditional
+ * on factors evaluated prior to throttling.
+ *
+ * Returns 0 if tty is throttled (or was already throttled)
+ */
+
+int tty_throttle_safe(struct tty_struct *tty)
+{
+ int ret = 0;
+
+ mutex_lock(&tty->termios_mutex);
+ if (!test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (tty->flow_change != TTY_THROTTLE_SAFE)
+ ret = 1;
+ else {
+ set_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->throttle)
+ tty->ops->throttle(tty);
+ }
+ }
+ mutex_unlock(&tty->termios_mutex);
+
+ return ret;
+}
+
+/**
+ * tty_unthrottle_safe - flow control
+ * @tty: terminal
+ *
+ * Similar to tty_unthrottle() but will only attempt unthrottle
+ * if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
+ * unthrottle due to race conditions when unthrottling is conditional
+ * on factors evaluated prior to unthrottling.
+ *
+ * Returns 0 if tty is unthrottled (or was already unthrottled)
+ */
+
+int tty_unthrottle_safe(struct tty_struct *tty)
+{
+ int ret = 0;
+
+ mutex_lock(&tty->termios_mutex);
+ if (test_bit(TTY_THROTTLED, &tty->flags)) {
+ if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
+ ret = 1;
+ else {
+ clear_bit(TTY_THROTTLED, &tty->flags);
+ if (tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+ }
+ }
+ mutex_unlock(&tty->termios_mutex);
+
+ return ret;
+}
+
+/**
* tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for
* @timeout: how long we will wait
@@ -415,34 +479,6 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
/**
- * tty_get_baud_rate - get tty bit rates
- * @tty: tty to query
- *
- * Returns the baud rate as an integer for this terminal. The
- * termios lock must be held by the caller and the terminal bit
- * flags may be updated.
- *
- * Locking: none
- */
-
-speed_t tty_get_baud_rate(struct tty_struct *tty)
-{
- speed_t baud = tty_termios_baud_rate(&tty->termios);
-
- if (baud == 38400 && tty->alt_speed) {
- if (!tty->warned) {
- printk(KERN_WARNING "Use of setserial/setrocket to "
- "set SPD_* flags is deprecated\n");
- tty->warned = 1;
- }
- baud = tty->alt_speed;
- }
-
- return baud;
-}
-EXPORT_SYMBOL(tty_get_baud_rate);
-
-/**
* tty_termios_copy_hw - copy hardware settings
* @new: New termios
* @old: Old termios
@@ -1086,14 +1122,12 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
}
EXPORT_SYMBOL_GPL(tty_mode_ioctl);
-int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+
+/* Caller guarantees ldisc reference is held */
+static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
{
- struct tty_ldisc *ld;
- int retval = tty_check_change(tty);
- if (retval)
- return retval;
+ struct tty_ldisc *ld = tty->ldisc;
- ld = tty_ldisc_ref_wait(tty);
switch (arg) {
case TCIFLUSH:
if (ld && ld->ops->flush_buffer) {
@@ -1111,12 +1145,24 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
tty_driver_flush_buffer(tty);
break;
default:
- tty_ldisc_deref(ld);
return -EINVAL;
}
- tty_ldisc_deref(ld);
return 0;
}
+
+int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+{
+ struct tty_ldisc *ld;
+ int retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ ld = tty_ldisc_ref_wait(tty);
+ retval = __tty_perform_flush(tty, arg);
+ if (ld)
+ tty_ldisc_deref(ld);
+ return retval;
+}
EXPORT_SYMBOL_GPL(tty_perform_flush);
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
@@ -1155,7 +1201,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
}
return 0;
case TCFLSH:
- return tty_perform_flush(tty, arg);
+ return __tty_perform_flush(tty, arg);
default:
/* Try the mode commands */
return tty_mode_ioctl(tty, file, cmd, arg);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index d794087c327e..1afe192bef6a 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -20,6 +20,17 @@
#include <linux/uaccess.h>
#include <linux/ratelimit.h>
+#undef LDISC_DEBUG_HANGUP
+
+#ifdef LDISC_DEBUG_HANGUP
+#define tty_ldisc_debug(tty, f, args...) ({ \
+ char __b[64]; \
+ printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
+})
+#else
+#define tty_ldisc_debug(tty, f, args...)
+#endif
+
/*
* This guards the refcounted line discipline lists. The lock
* must be taken with irqs off because there are hangup path
@@ -31,44 +42,6 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
-{
- if (ld)
- atomic_inc(&ld->users);
- return ld;
-}
-
-static void put_ldisc(struct tty_ldisc *ld)
-{
- unsigned long flags;
-
- if (WARN_ON_ONCE(!ld))
- return;
-
- /*
- * If this is the last user, free the ldisc, and
- * release the ldisc ops.
- *
- * We really want an "atomic_dec_and_raw_lock_irqsave()",
- * but we don't have it, so this does it by hand.
- */
- raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (atomic_dec_and_test(&ld->users)) {
- struct tty_ldisc_ops *ldo = ld->ops;
-
- ldo->refcount--;
- module_put(ldo->owner);
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- kfree(ld);
- return;
- }
- raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
- if (waitqueue_active(&ld->wq_idle))
- wake_up(&ld->wq_idle);
-}
-
/**
* tty_register_ldisc - install a line discipline
* @disc: ldisc number
@@ -206,6 +179,29 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
return ld;
}
+/**
+ * tty_ldisc_put - release the ldisc
+ *
+ * Complement of tty_ldisc_get().
+ */
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+ unsigned long flags;
+
+ if (WARN_ON_ONCE(!ld))
+ return;
+
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+
+ /* unreleased reader reference(s) will cause this WARN */
+ WARN_ON(!atomic_dec_and_test(&ld->users));
+
+ ld->ops->refcount--;
+ module_put(ld->ops->owner);
+ kfree(ld);
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
return (*pos < NR_LDISCS) ? pos : NULL;
@@ -255,24 +251,6 @@ const struct file_operations tty_ldiscs_proc_fops = {
};
/**
- * tty_ldisc_assign - set ldisc on a tty
- * @tty: tty to assign
- * @ld: line discipline
- *
- * Install an instance of a line discipline into a tty structure. The
- * ldisc must have a reference count above zero to ensure it remains.
- * The tty instance refcount starts at zero.
- *
- * Locking:
- * Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
- tty->ldisc = ld;
-}
-
-/**
* tty_ldisc_try - internal helper
* @tty: the tty
*
@@ -289,10 +267,13 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
unsigned long flags;
struct tty_ldisc *ld;
+ /* FIXME: this allows reference acquire after TTY_LDISC is cleared */
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
ld = NULL;
- if (test_bit(TTY_LDISC, &tty->flags))
- ld = get_ldisc(tty->ldisc);
+ if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
+ ld = tty->ldisc;
+ atomic_inc(&ld->users);
+ }
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return ld;
}
@@ -352,14 +333,23 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
void tty_ldisc_deref(struct tty_ldisc *ld)
{
- put_ldisc(ld);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+ unsigned long flags;
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
-{
- put_ldisc(ld);
+ if (WARN_ON_ONCE(!ld))
+ return;
+
+ raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
+ /*
+ * WARNs if one-too-many reader references were released
+ * - the last reference must be released with tty_ldisc_put
+ */
+ WARN_ON(atomic_dec_and_test(&ld->users));
+ raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ if (waitqueue_active(&ld->wq_idle))
+ wake_up(&ld->wq_idle);
}
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
/**
* tty_ldisc_enable - allow ldisc use
@@ -373,8 +363,9 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld)
* Clearing directly is allowed.
*/
-void tty_ldisc_enable(struct tty_struct *tty)
+static void tty_ldisc_enable(struct tty_struct *tty)
{
+ clear_bit(TTY_LDISC_HALTED, &tty->flags);
set_bit(TTY_LDISC, &tty->flags);
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
wake_up(&tty_ldisc_wait);
@@ -479,7 +470,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
/* There is an outstanding reference here so this is safe */
old = tty_ldisc_get(old->ops->num);
WARN_ON(IS_ERR(old));
- tty_ldisc_assign(tty, old);
+ tty->ldisc = old;
tty_set_termios_ldisc(tty, old->ops->num);
if (tty_ldisc_open(tty, old) < 0) {
tty_ldisc_put(old);
@@ -487,7 +478,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
new_ldisc = tty_ldisc_get(N_TTY);
if (IS_ERR(new_ldisc))
panic("n_tty: get");
- tty_ldisc_assign(tty, new_ldisc);
+ tty->ldisc = new_ldisc;
tty_set_termios_ldisc(tty, N_TTY);
r = tty_ldisc_open(tty, new_ldisc);
if (r < 0)
@@ -498,52 +489,98 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
}
/**
+ * tty_ldisc_wait_idle - wait for the ldisc to become idle
+ * @tty: tty to wait for
+ * @timeout: for how long to wait at most
+ *
+ * Wait for the line discipline to become idle. The discipline must
+ * have been halted for this to guarantee it remains idle.
+ */
+static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
+{
+ long ret;
+ ret = wait_event_timeout(tty->ldisc->wq_idle,
+ atomic_read(&tty->ldisc->users) == 1, timeout);
+ return ret > 0 ? 0 : -EBUSY;
+}
+
+/**
* tty_ldisc_halt - shut down the line discipline
* @tty: tty device
+ * @o_tty: paired pty device (can be NULL)
+ * @timeout: # of jiffies to wait for ldisc refs to be released
*
- * Shut down the line discipline and work queue for this tty device.
- * The TTY_LDISC flag being cleared ensures no further references can
- * be obtained while the delayed work queue halt ensures that no more
- * data is fed to the ldisc.
+ * Shut down the line discipline and work queue for this tty device and
+ * its paired pty (if exists). Clearing the TTY_LDISC flag ensures
+ * no further references can be obtained, while waiting for existing
+ * references to be released ensures no more data is fed to the ldisc.
*
* You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
* in order to make sure any currently executing ldisc work is also
* flushed.
*/
-static int tty_ldisc_halt(struct tty_struct *tty)
+static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty,
+ long timeout)
{
+ int retval;
+
clear_bit(TTY_LDISC, &tty->flags);
- return cancel_work_sync(&tty->port->buf.work);
-}
+ if (o_tty)
+ clear_bit(TTY_LDISC, &o_tty->flags);
-/**
- * tty_ldisc_flush_works - flush all works of a tty
- * @tty: tty device to flush works for
- *
- * Sync flush all works belonging to @tty.
- */
-static void tty_ldisc_flush_works(struct tty_struct *tty)
-{
- flush_work(&tty->hangup_work);
- flush_work(&tty->SAK_work);
- flush_work(&tty->port->buf.work);
+ retval = tty_ldisc_wait_idle(tty, timeout);
+ if (!retval && o_tty)
+ retval = tty_ldisc_wait_idle(o_tty, timeout);
+ if (retval)
+ return retval;
+
+ set_bit(TTY_LDISC_HALTED, &tty->flags);
+ if (o_tty)
+ set_bit(TTY_LDISC_HALTED, &o_tty->flags);
+
+ return 0;
}
/**
- * tty_ldisc_wait_idle - wait for the ldisc to become idle
- * @tty: tty to wait for
- * @timeout: for how long to wait at most
+ * tty_ldisc_hangup_halt - halt the line discipline for hangup
+ * @tty: tty being hung up
*
- * Wait for the line discipline to become idle. The discipline must
- * have been halted for this to guarantee it remains idle.
+ * Shut down the line discipline and work queue for the tty device
+ * being hungup. Clear the TTY_LDISC flag to ensure no further
+ * references can be obtained and wait for remaining references to be
+ * released to ensure no more data is fed to this ldisc.
+ * Caller must hold legacy and ->ldisc_mutex.
+ *
+ * NB: tty_set_ldisc() is prevented from changing the ldisc concurrently
+ * with this function by checking the TTY_HUPPING flag.
*/
-static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
+static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
{
- long ret;
- ret = wait_event_timeout(tty->ldisc->wq_idle,
- atomic_read(&tty->ldisc->users) == 1, timeout);
- return ret > 0 ? 0 : -EBUSY;
+ char cur_n[TASK_COMM_LEN], tty_n[64];
+ long timeout = 3 * HZ;
+
+ clear_bit(TTY_LDISC, &tty->flags);
+
+ if (tty->ldisc) { /* Not yet closed */
+ tty_unlock(tty);
+
+ while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ printk_ratelimited(KERN_WARNING
+ "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
+ __func__, get_task_comm(cur_n, current),
+ tty_name(tty, tty_n));
+ }
+
+ set_bit(TTY_LDISC_HALTED, &tty->flags);
+
+ /* must reacquire both locks and preserve lock order */
+ mutex_unlock(&tty->ldisc_mutex);
+ tty_lock(tty);
+ mutex_lock(&tty->ldisc_mutex);
+ }
+ return !!tty->ldisc;
}
/**
@@ -563,7 +600,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
int retval;
struct tty_ldisc *o_ldisc, *new_ldisc;
- int work, o_work = 0;
struct tty_struct *o_tty;
new_ldisc = tty_ldisc_get(ldisc);
@@ -589,15 +625,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
return 0;
}
- tty_unlock(tty);
- /*
- * Problem: What do we do if this blocks ?
- * We could deadlock here
- */
-
- tty_wait_until_sent(tty, 0);
-
- tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
@@ -637,20 +664,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
* parallel to the change and re-referencing the tty.
*/
- work = tty_ldisc_halt(tty);
- if (o_tty)
- o_work = tty_ldisc_halt(o_tty);
+ retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
/*
- * Wait for ->hangup_work and ->buf.work handlers to terminate.
+ * Wait for hangup to complete, if pending.
* We must drop the mutex here in case a hangup is also in process.
*/
mutex_unlock(&tty->ldisc_mutex);
- tty_ldisc_flush_works(tty);
-
- retval = tty_ldisc_wait_idle(tty, 5 * HZ);
+ flush_work(&tty->hangup_work);
tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
@@ -675,7 +698,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_ldisc_close(tty, o_ldisc);
/* Now set up the new line discipline. */
- tty_ldisc_assign(tty, new_ldisc);
+ tty->ldisc = new_ldisc;
tty_set_termios_ldisc(tty, ldisc);
retval = tty_ldisc_open(tty, new_ldisc);
@@ -705,10 +728,10 @@ enable:
/* Restart the work queue in case no characters kick it off. Safe if
already running */
- if (work)
- schedule_work(&tty->port->buf.work);
- if (o_work)
+ schedule_work(&tty->port->buf.work);
+ if (o_tty)
schedule_work(&o_tty->port->buf.work);
+
mutex_unlock(&tty->ldisc_mutex);
tty_unlock(tty);
return retval;
@@ -749,11 +772,10 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
tty_ldisc_close(tty, tty->ldisc);
tty_ldisc_put(tty->ldisc);
- tty->ldisc = NULL;
/*
* Switch the line discipline back
*/
- tty_ldisc_assign(tty, ld);
+ tty->ldisc = ld;
tty_set_termios_ldisc(tty, ldisc);
return 0;
@@ -780,6 +802,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
int err = 0;
+ tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
+
/*
* FIXME! What are the locking issues here? This may me overdoing
* things... This question is especially important now that we've
@@ -812,40 +836,12 @@ void tty_ldisc_hangup(struct tty_struct *tty)
*/
mutex_lock(&tty->ldisc_mutex);
- /*
- * this is like tty_ldisc_halt, but we need to give up
- * the BTM before calling cancel_work_sync, which may
- * need to wait for another function taking the BTM
- */
- clear_bit(TTY_LDISC, &tty->flags);
- tty_unlock(tty);
- cancel_work_sync(&tty->port->buf.work);
- mutex_unlock(&tty->ldisc_mutex);
-retry:
- tty_lock(tty);
- mutex_lock(&tty->ldisc_mutex);
-
- /* At this point we have a closed ldisc and we want to
- reopen it. We could defer this to the next open but
- it means auditing a lot of other paths so this is
- a FIXME */
- if (tty->ldisc) { /* Not yet closed */
- if (atomic_read(&tty->ldisc->users) != 1) {
- char cur_n[TASK_COMM_LEN], tty_n[64];
- long timeout = 3 * HZ;
- tty_unlock(tty);
-
- while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
- timeout = MAX_SCHEDULE_TIMEOUT;
- printk_ratelimited(KERN_WARNING
- "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
- __func__, get_task_comm(cur_n, current),
- tty_name(tty, tty_n));
- }
- mutex_unlock(&tty->ldisc_mutex);
- goto retry;
- }
+ if (tty_ldisc_hangup_halt(tty)) {
+ /* At this point we have a halted ldisc; we want to close it and
+ reopen a new ldisc. We could defer the reopen to the next
+ open but it means auditing a lot of other paths so this is
+ a FIXME */
if (reset == 0) {
if (!tty_ldisc_reinit(tty, tty->termios.c_line))
@@ -864,6 +860,8 @@ retry:
mutex_unlock(&tty->ldisc_mutex);
if (reset)
tty_reset_termios(tty);
+
+ tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);
}
/**
@@ -899,11 +897,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
static void tty_ldisc_kill(struct tty_struct *tty)
{
- /* There cannot be users from userspace now. But there still might be
- * drivers holding a reference via tty_ldisc_ref. Do not steal them the
- * ldisc until they are done. */
- tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT);
-
mutex_lock(&tty->ldisc_mutex);
/*
* Now kill off the ldisc
@@ -931,18 +924,13 @@ static void tty_ldisc_kill(struct tty_struct *tty)
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
{
/*
- * Prevent flush_to_ldisc() from rescheduling the work for later. Then
- * kill any delayed work. As this is the final close it does not
- * race with the set_ldisc code path.
+ * Shutdown this line discipline. As this is the final close,
+ * it does not race with the set_ldisc code path.
*/
- tty_ldisc_halt(tty);
- if (o_tty)
- tty_ldisc_halt(o_tty);
+ tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
- tty_ldisc_flush_works(tty);
- if (o_tty)
- tty_ldisc_flush_works(o_tty);
+ tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
tty_lock_pair(tty, o_tty);
/* This will need doing differently if we need to lock */
@@ -953,6 +941,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_unlock_pair(tty, o_tty);
/* And the memory resources remaining (buffers, termios) will be
disposed of when the kref hits zero */
+
+ tty_ldisc_debug(tty, "ldisc closed\n");
}
/**
@@ -968,7 +958,7 @@ void tty_ldisc_init(struct tty_struct *tty)
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
if (IS_ERR(ld))
panic("n_tty: init_tty");
- tty_ldisc_assign(tty, ld);
+ tty->ldisc = ld;
}
/**
@@ -980,8 +970,8 @@ void tty_ldisc_init(struct tty_struct *tty)
*/
void tty_ldisc_deinit(struct tty_struct *tty)
{
- put_ldisc(tty->ldisc);
- tty_ldisc_assign(tty, NULL);
+ tty_ldisc_put(tty->ldisc);
+ tty->ldisc = NULL;
}
void tty_ldisc_begin(void)
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index b7ff59d3db88..121aeb9393e1 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -132,6 +132,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
*/
void tty_port_destroy(struct tty_port *port)
{
+ cancel_work_sync(&port->buf.work);
tty_buffer_free_all(port);
}
EXPORT_SYMBOL(tty_port_destroy);
@@ -196,12 +197,24 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
}
EXPORT_SYMBOL(tty_port_tty_set);
-static void tty_port_shutdown(struct tty_port *port)
+static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
{
mutex_lock(&port->mutex);
- if (port->ops->shutdown && !port->console &&
- test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+ if (port->console)
+ goto out;
+
+ if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ /*
+ * Drop DTR/RTS if HUPCL is set. This causes any attached
+ * modem to hang up the line.
+ */
+ if (tty && C_HUPCL(tty))
+ tty_port_lower_dtr_rts(port);
+
+ if (port->ops->shutdown)
port->ops->shutdown(port);
+ }
+out:
mutex_unlock(&port->mutex);
}
@@ -215,24 +228,58 @@ static void tty_port_shutdown(struct tty_port *port)
void tty_port_hangup(struct tty_port *port)
{
+ struct tty_struct *tty;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
- if (port->tty) {
- set_bit(TTY_IO_ERROR, &port->tty->flags);
- tty_kref_put(port->tty);
- }
+ tty = port->tty;
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
port->tty = NULL;
spin_unlock_irqrestore(&port->lock, flags);
+ tty_port_shutdown(port, tty);
+ tty_kref_put(tty);
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&port->delta_msr_wait);
- tty_port_shutdown(port);
}
EXPORT_SYMBOL(tty_port_hangup);
/**
+ * tty_port_tty_hangup - helper to hang up a tty
+ *
+ * @port: tty port
+ * @check_clocal: hang only ttys with CLOCAL unset?
+ */
+void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
+{
+ struct tty_struct *tty = tty_port_tty_get(port);
+
+ if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+ tty_hangup(tty);
+ tty_kref_put(tty);
+ }
+}
+EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
+
+/**
+ * tty_port_tty_wakeup - helper to wake up a tty
+ *
+ * @port: tty port
+ */
+void tty_port_tty_wakeup(struct tty_port *port)
+{
+ struct tty_struct *tty = tty_port_tty_get(port);
+
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
+}
+EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
+
+/**
* tty_port_carrier_raised - carrier raised check
* @port: tty port
*
@@ -350,7 +397,7 @@ int tty_port_block_til_ready(struct tty_port *port,
while (1) {
/* Indicate we are open */
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port);
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
@@ -395,6 +442,20 @@ int tty_port_block_til_ready(struct tty_port *port,
}
EXPORT_SYMBOL(tty_port_block_til_ready);
+static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
+{
+ unsigned int bps = tty_get_baud_rate(tty);
+ long timeout;
+
+ if (bps > 1200) {
+ timeout = (HZ * 10 * port->drain_delay) / bps;
+ timeout = max_t(long, timeout, HZ / 10);
+ } else {
+ timeout = 2 * HZ;
+ }
+ schedule_timeout_interruptible(timeout);
+}
+
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
@@ -427,31 +488,19 @@ int tty_port_close_start(struct tty_port *port,
set_bit(ASYNCB_CLOSING, &port->flags);
tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
- /* Don't block on a stalled port, just pull the chain */
- if (tty->flow_stopped)
- tty_driver_flush_buffer(tty);
- if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
- port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent_from_close(tty, port->closing_wait);
- if (port->drain_delay) {
- unsigned int bps = tty_get_baud_rate(tty);
- long timeout;
-
- if (bps > 1200)
- timeout = max_t(long,
- (HZ * 10 * port->drain_delay) / bps, HZ / 10);
- else
- timeout = 2 * HZ;
- schedule_timeout_interruptible(timeout);
+
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+ /* Don't block on a stalled port, just pull the chain */
+ if (tty->flow_stopped)
+ tty_driver_flush_buffer(tty);
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent_from_close(tty, port->closing_wait);
+ if (port->drain_delay)
+ tty_port_drain_delay(port, tty);
}
/* Flush the ldisc buffering */
tty_ldisc_flush(tty);
- /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
- hang up the line */
- if (tty->termios.c_cflag & HUPCL)
- tty_port_lower_dtr_rts(port);
-
/* Don't call port->drop for the last reference. Callers will want
to drop the last active reference in ->shutdown() or the tty
shutdown path */
@@ -486,7 +535,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
{
if (tty_port_close_start(port, tty, filp) == 0)
return;
- tty_port_shutdown(port);
+ tty_port_shutdown(port, tty);
set_bit(TTY_IO_ERROR, &tty->flags);
tty_port_close_end(port, tty);
tty_port_tty_set(port, NULL);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 248381b30722..2978ca596a7f 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -194,8 +194,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
q = p->inverse_translations[i];
if (!q) {
- q = p->inverse_translations[i] = (unsigned char *)
- kmalloc(MAX_GLYPH, GFP_KERNEL);
+ q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
if (!q) return;
}
memset(q, 0, MAX_GLYPH);
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index c8b926291e28..b645c47501b4 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -374,6 +374,7 @@ static int uio_get_minor(struct uio_device *idev)
retval = idr_alloc(&uio_idr, idev, 0, UIO_MAX_DEVICES, GFP_KERNEL);
if (retval >= 0) {
idev->minor = retval;
+ retval = 0;
} else if (retval == -ENOSPC) {
dev_err(idev->dev, "too many uio devices\n");
retval = -EINVAL;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 640ae6c6d2d2..92e1dc94ecc8 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -122,9 +122,9 @@ config USB
To compile this driver as a module, choose M here: the
module will be called usbcore.
-source "drivers/usb/core/Kconfig"
+if USB
-source "drivers/usb/dwc3/Kconfig"
+source "drivers/usb/core/Kconfig"
source "drivers/usb/mon/Kconfig"
@@ -134,8 +134,6 @@ source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
-source "drivers/usb/chipidea/Kconfig"
-
source "drivers/usb/renesas_usbhs/Kconfig"
source "drivers/usb/class/Kconfig"
@@ -144,12 +142,19 @@ source "drivers/usb/storage/Kconfig"
source "drivers/usb/image/Kconfig"
+endif
+
+source "drivers/usb/dwc3/Kconfig"
+
+source "drivers/usb/chipidea/Kconfig"
+
comment "USB port drivers"
- depends on USB
+
+if USB
config USB_USS720
tristate "USS720 parport driver"
- depends on USB && PARPORT
+ depends on PARPORT
select PARPORT_NOT_PC
---help---
This driver is for USB parallel port adapters that use the Lucent
@@ -180,12 +185,12 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
-source "drivers/usb/phy/Kconfig"
-
source "drivers/usb/atm/Kconfig"
-source "drivers/usb/gadget/Kconfig"
+endif # USB
+
+source "drivers/usb/phy/Kconfig"
-source "drivers/usb/otg/Kconfig"
+source "drivers/usb/gadget/Kconfig"
endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 8f5ebced5df0..c41feba8d5c0 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,8 +6,6 @@
obj-$(CONFIG_USB) += core/
-obj-$(CONFIG_USB_OTG_UTILS) += otg/
-
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/
@@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
-obj-$(CONFIG_USB_OTG_UTILS) += phy/
+obj-$(CONFIG_USB_PHY) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index be0b8daac9c7..0f922942a07a 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -4,7 +4,7 @@
menuconfig USB_ATM
tristate "USB DSL modem support"
- depends on USB && ATM
+ depends on ATM
select CRC32
default n
help
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 35f10bfe15db..d3527dd8b90c 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -672,9 +672,6 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
struct usbatm_control *ctrl = UDSL_SKB(skb);
int err;
- vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
- skb, skb->len);
-
/* racy disconnection check - fine */
if (!instance || instance->disconnected) {
#ifdef DEBUG
@@ -684,6 +681,9 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
goto fail;
}
+ vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__,
+ skb, skb->len);
+
if (vcc->qos.aal != ATM_AAL5) {
atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
err = -EINVAL;
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index d92ca325b104..4ab83e98219b 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)
endif
ifneq ($(CONFIG_OF_DEVICE),)
- obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o
endif
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index e25d1263da13..b0a6bce064ca 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -21,6 +21,7 @@
/******************************************************************************
* DEFINE
*****************************************************************************/
+#define TD_PAGE_COUNT 5
#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
#define ENDPT_MAX 32
@@ -129,6 +130,7 @@ struct hw_bank {
* @vbus_active: is VBUS active
* @transceiver: pointer to USB PHY, if any
* @hcd: pointer to usb_hcd for ehci host driver
+ * @debugfs: root dentry for this controller in debugfs
*/
struct ci13xxx {
struct device *dev;
@@ -139,7 +141,6 @@ struct ci13xxx {
enum ci_role role;
bool is_otg;
struct work_struct work;
- struct work_struct vbus_work;
struct workqueue_struct *wq;
struct dma_pool *qh_pool;
@@ -165,6 +166,7 @@ struct ci13xxx {
bool global_phy;
struct usb_phy *transceiver;
struct usb_hcd *hcd;
+ struct dentry *debugfs;
};
static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -234,19 +236,6 @@ enum ci13xxx_regs {
};
/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static inline int ffs_nr(u32 x)
-{
- int n = ffs(x);
-
- return n ? n-1 : 32;
-}
-
-/**
* hw_read: reads from a hw register
* @reg: register index
* @mask: bitfield mask
@@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,
u32 val = hw_read(ci, reg, ~0);
hw_write(ci, reg, mask, data);
- return (val & mask) >> ffs_nr(mask);
+ return (val & mask) >> __ffs(mask);
}
int hw_device_reset(struct ci13xxx *ci, u32 mode);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 8c291220be7f..8faec9dbbb84 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)
if (of_find_property(np, "disable-over-current", NULL))
usbdev->disable_oc = 1;
+ if (of_find_property(np, "external-vbus-divider", NULL))
+ usbdev->evdo = 1;
+
return 0;
}
EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
@@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
goto err;
}
+ if (usbmisc_ops && usbmisc_ops->post) {
+ ret = usbmisc_ops->post(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "usbmisc post failed, ret=%d\n", ret);
+ goto put_np;
+ }
+ }
+
data->ci_pdev = plat_ci;
platform_set_drvdata(pdev, data);
diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h
index 9cd2e910b1ca..550bfa457620 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.h
+++ b/drivers/usb/chipidea/ci13xxx_imx.h
@@ -13,6 +13,8 @@
struct usbmisc_ops {
/* It's called once when probe a usb device */
int (*init)(struct device *dev);
+ /* It's called once after adding a usb device */
+ int (*post)(struct device *dev);
};
struct usbmisc_usb_device {
@@ -20,6 +22,7 @@ struct usbmisc_usb_device {
int index;
unsigned int disable_oc:1; /* over current detect disabled */
+ unsigned int evdo:1; /* set external vbus divider option */
};
int usbmisc_set_ops(const struct usbmisc_ops *ops);
diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c
index 9b227e39299a..4e1fc61b9d95 100644
--- a/drivers/usb/chipidea/ci13xxx_pci.c
+++ b/drivers/usb/chipidea/ci13xxx_pci.c
@@ -23,17 +23,17 @@
/******************************************************************************
* PCI block
*****************************************************************************/
-struct ci13xxx_platform_data pci_platdata = {
+static struct ci13xxx_platform_data pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = DEF_CAPOFFSET,
};
-struct ci13xxx_platform_data langwell_pci_platdata = {
+static struct ci13xxx_platform_data langwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
};
-struct ci13xxx_platform_data penwell_pci_platdata = {
+static struct ci13xxx_platform_data penwell_pci_platdata = {
.name = UDC_DRIVER_NAME,
.capoffset = 0,
.power_budget = 200,
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 57cae1f897b2..450107e5f657 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -51,15 +51,12 @@
*/
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/dmapool.h>
#include <linux/dma-mapping.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
if (mode > TEST_MODE_MAX)
return -EINVAL;
- hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+ hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));
return 0;
}
@@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)
*/
u8 hw_port_test_get(struct ci13xxx *ci)
{
- return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+ return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
@@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.cap = ci->hw_bank.abs;
ci->hw_bank.cap += ci->platdata->capoffset;
- ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+ ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);
hw_alloc_regmap(ci, false);
reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
- ffs_nr(HCCPARAMS_LEN);
+ __ffs(HCCPARAMS_LEN);
ci->hw_bank.lpm = reg;
hw_alloc_regmap(ci, !!reg);
ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
@@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
ci->hw_bank.size /= sizeof(u32);
reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
- ffs_nr(DCCPARAMS_DEN);
+ __ffs(DCCPARAMS_DEN);
ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
if (ci->hw_ep_max > ENDPT_MAX)
@@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)
}
}
-static ssize_t show_role(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", ci_role(ci)->name);
-}
-
-static ssize_t store_role(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *ci = dev_get_drvdata(dev);
- enum ci_role role;
- int ret;
-
- for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
- if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
- break;
-
- if (role == CI_ROLE_END || role == ci->role)
- return -EINVAL;
-
- ci_role_stop(ci);
- ret = ci_role_start(ci, role);
- if (ret)
- return ret;
-
- return count;
-}
-
-static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
-
static irqreturn_t ci_irq(int irq, void *data)
{
struct ci13xxx *ci = data;
@@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
- base = devm_request_and_ioremap(dev, res);
- if (!base) {
- dev_err(dev, "can't request and ioremap resource\n");
- return -ENOMEM;
- }
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
if (!ci) {
@@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (ret)
goto stop;
- ret = device_create_file(dev, &dev_attr_role);
- if (ret)
- goto rm_attr;
-
if (ci->is_otg)
hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
- return ret;
+ ret = dbg_create_files(ci);
+ if (!ret)
+ return 0;
-rm_attr:
- device_remove_file(dev, &dev_attr_role);
+ free_irq(ci->irq, ci);
stop:
ci_role_stop(ci);
rm_wq:
@@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
{
struct ci13xxx *ci = platform_get_drvdata(pdev);
+ dbg_remove_files(ci);
flush_workqueue(ci->wq);
destroy_workqueue(ci->wq);
- device_remove_file(ci->dev, &dev_attr_role);
free_irq(ci->irq, ci);
ci_role_stop(ci);
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index a62c4a47d52c..36a7063a6cba 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -1,590 +1,126 @@
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/chipidea.h>
#include "ci.h"
#include "udc.h"
#include "bits.h"
#include "debug.h"
-/* Interrupt statistics */
-#define ISR_MASK 0x1F
-static struct isr_statistics {
- u32 test;
- u32 ui;
- u32 uei;
- u32 pci;
- u32 uri;
- u32 sli;
- u32 none;
- struct {
- u32 cnt;
- u32 buf[ISR_MASK+1];
- u32 idx;
- } hndl;
-} isr_statistics;
-
-void dbg_interrupt(u32 intmask)
-{
- if (!intmask) {
- isr_statistics.none++;
- return;
- }
-
- isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
- isr_statistics.hndl.idx &= ISR_MASK;
- isr_statistics.hndl.cnt++;
-
- if (USBi_URI & intmask)
- isr_statistics.uri++;
- if (USBi_PCI & intmask)
- isr_statistics.pci++;
- if (USBi_UEI & intmask)
- isr_statistics.uei++;
- if (USBi_UI & intmask)
- isr_statistics.ui++;
- if (USBi_SLI & intmask)
- isr_statistics.sli++;
-}
-
/**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf: destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
+ * ci_device_show: prints information about device capabilities and status
*/
-static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size)
+static int ci_device_show(struct seq_file *s, void *data)
{
- unsigned i;
-
- if (size > ci->hw_bank.size)
- size = ci->hw_bank.size;
-
- for (i = 0; i < size; i++)
- buf[i] = hw_read(ci, i * sizeof(u32), ~0);
-
- return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data)
-{
- /* align */
- addr /= sizeof(u32);
-
- if (addr >= ci->hw_bank.size)
- return -EINVAL;
-
- /* align */
- addr *= sizeof(u32);
-
- hw_write(ci, addr, ~0, data);
- return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(struct ci13xxx *ci, int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_write(ci, OP_USBINTR, BIT(n), 0);
- hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
- return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(struct ci13xxx *ci, int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
- hw_write(ci, OP_USBINTR, BIT(n), BIT(n));
- hw_write(ci, OP_USBSTS, BIT(n), BIT(n));
- hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0);
- return 0;
-}
-
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
struct usb_gadget *gadget = &ci->gadget;
- int n = 0;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+ seq_printf(s, "speed = %d\n", gadget->speed);
+ seq_printf(s, "max_speed = %d\n", gadget->max_speed);
+ seq_printf(s, "is_otg = %d\n", gadget->is_otg);
+ seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral);
+ seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable);
+ seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support);
+ seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support);
+ seq_printf(s, "name = %s\n",
+ (gadget->name ? gadget->name : ""));
+
+ if (!ci->driver)
return 0;
- }
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
- gadget->speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
- gadget->max_speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
- gadget->is_otg);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
- gadget->is_a_peripheral);
- n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
- gadget->b_hnp_enable);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
- gadget->a_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
- gadget->a_alt_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
- (gadget->name ? gadget->name : ""));
-
- return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget_driver *driver = ci->driver;
- int n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- if (driver == NULL)
- return scnprintf(buf, PAGE_SIZE,
- "There is no gadget attached!\n");
- n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
- (driver->function ? driver->function : ""));
- n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
- driver->max_speed);
+ seq_printf(s, "gadget function = %s\n",
+ (ci->driver->function ? ci->driver->function : ""));
+ seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed);
- return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG 64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX 128UL
-
-/* Event buffer descriptor */
-static struct {
- char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
- unsigned idx; /* index */
- unsigned tty; /* print to console? */
- rwlock_t lck; /* lock */
-} dbg_data = {
- .idx = 0,
- .tty = 0,
- .lck = __RW_LOCK_UNLOCKED(dbg_data.lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
- *idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
- *idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print: prints the common part of the event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- * @extra: extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
- struct timeval tval;
- unsigned int stamp;
- unsigned long flags;
-
- write_lock_irqsave(&dbg_data.lck, flags);
-
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
- stamp = stamp * 1000000 + tval.tv_usec;
-
- scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-
- dbg_inc(&dbg_data.idx);
-
- write_unlock_irqrestore(&dbg_data.lck, flags);
-
- if (dbg_data.tty != 0)
- pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr: endpoint address
- * @td: transfer descriptor
- * @status: status
- */
-void dbg_done(u8 addr, const u32 token, int status)
-{
- char msg[DBG_DATA_MSG];
-
- scnprintf(msg, sizeof(msg), "%d %02X",
- (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
- (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
- dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- */
-void dbg_event(u8 addr, const char *name, int status)
-{
- if (name != NULL)
- dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr: endpoint address
- * @req: USB request
- * @status: status
- */
-void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%d %d", !req->no_interrupt, req->length);
- dbg_print(addr, "QUEUE", status, msg);
- }
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req: setup request
- */
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%02X %02X %04X %04X %d", req->bRequestType,
- req->bRequest, le16_to_cpu(req->wValue),
- le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
- dbg_print(addr, "SETUP", 0, msg);
- }
+ return 0;
}
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_device_open(struct inode *inode, struct file *file)
{
- unsigned long flags;
- unsigned i, j, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev->parent, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- read_lock_irqsave(&dbg_data.lck, flags);
-
- i = dbg_data.idx;
- for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
- n += strlen(dbg_data.buf[i]);
- if (n >= PAGE_SIZE) {
- n -= strlen(dbg_data.buf[i]);
- break;
- }
- }
- for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
- j += scnprintf(buf + j, PAGE_SIZE - j,
- "%s", dbg_data.buf[i]);
-
- read_unlock_irqrestore(&dbg_data.lck, flags);
-
- return n;
+ return single_open(file, ci_device_show, inode->i_private);
}
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned tty;
-
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
- dev_err(dev, "<1|0>: enable|disable console log\n");
- goto done;
- }
-
- dbg_data.tty = tty;
- dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
- return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+static const struct file_operations ci_device_fops = {
+ .open = ci_device_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
+ * ci_port_test_show: reads port test mode
*/
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_port_test_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- u32 intr;
- unsigned i, j, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ unsigned mode;
spin_lock_irqsave(&ci->lock, flags);
-
- /*n += scnprintf(buf + n, PAGE_SIZE - n,
- "status = %08x\n", hw_read_intr_status(ci));
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "enable = %08x\n", hw_read_intr_enable(ci));*/
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
- isr_statistics.test);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
- isr_statistics.ui);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
- isr_statistics.uei);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
- isr_statistics.pci);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
- isr_statistics.uri);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
- isr_statistics.sli);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
- isr_statistics.none);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
- isr_statistics.hndl.cnt);
-
- for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
- i &= ISR_MASK;
- intr = isr_statistics.hndl.buf[i];
-
- if (USBi_UI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
- intr &= ~USBi_UI;
- if (USBi_UEI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
- intr &= ~USBi_UEI;
- if (USBi_PCI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
- intr &= ~USBi_PCI;
- if (USBi_URI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
- intr &= ~USBi_URI;
- if (USBi_SLI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
- intr &= ~USBi_SLI;
- if (intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
- if (isr_statistics.hndl.buf[i])
- n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
- }
-
+ mode = hw_port_test_get(ci);
spin_unlock_irqrestore(&ci->lock, flags);
- return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- * (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned en, bit;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "EINVAL\n");
- goto done;
- }
+ seq_printf(s, "mode = %u\n", mode);
- if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
- dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n");
- goto done;
- }
-
- spin_lock_irqsave(&ci->lock, flags);
- if (en) {
- if (hw_intr_force(ci, bit))
- dev_err(dev, "invalid bit number\n");
- else
- isr_statistics.test++;
- } else {
- if (hw_intr_clear(ci, bit))
- dev_err(dev, "invalid bit number\n");
- }
- spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
- return count;
+ return 0;
}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
/**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
+ * ci_port_test_write: writes port test mode
*/
-static ssize_t show_port_test(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct seq_file *s = file->private_data;
+ struct ci13xxx *ci = s->private;
unsigned long flags;
unsigned mode;
+ char buf[32];
+ int ret;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "EINVAL\n");
- return 0;
- }
+ if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (sscanf(buf, "%u", &mode) != 1)
+ return -EINVAL;
spin_lock_irqsave(&ci->lock, flags);
- mode = hw_port_test_get(ci);
+ ret = hw_port_test_set(ci, mode);
spin_unlock_irqrestore(&ci->lock, flags);
- return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+ return ret ? ret : count;
}
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ci_port_test_open(struct inode *inode, struct file *file)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &mode) != 1) {
- dev_err(ci->dev, "<mode>: set port test mode");
- goto done;
- }
-
- spin_lock_irqsave(&ci->lock, flags);
- if (hw_port_test_set(ci, mode))
- dev_err(ci->dev, "invalid mode\n");
- spin_unlock_irqrestore(&ci->lock, flags);
-
- done:
- return count;
+ return single_open(file, ci_port_test_show, inode->i_private);
}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
- show_port_test, store_port_test);
+
+static const struct file_operations ci_port_test_fops = {
+ .open = ci_port_test_open,
+ .write = ci_port_test_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
+ * ci_qheads_show: DMA contents of all queue heads
*/
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
- char *buf)
+static int ci_qheads_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- unsigned i, j, n = 0;
+ unsigned i, j;
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
+ if (ci->role != CI_ROLE_GADGET) {
+ seq_printf(s, "not in gadget mode\n");
return 0;
}
@@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i];
struct ci13xxx_ep *mEpTx =
&ci->ci13xxx_ep[i + ci->hw_ep_max/2];
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: RX=%08X TX=%08X\n",
- i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
- for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X %08X\n", j,
- *((u32 *)mEpRx->qh.ptr + j),
- *((u32 *)mEpTx->qh.ptr + j));
- }
+ seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n",
+ i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+ for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++)
+ seq_printf(s, " %04X: %08X %08X\n", j,
+ *((u32 *)mEpRx->qh.ptr + j),
+ *((u32 *)mEpTx->qh.ptr + j));
}
spin_unlock_irqrestore(&ci->lock, flags);
- return n;
+ return 0;
+}
+
+static int ci_qheads_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ci_qheads_show, inode->i_private);
}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+static const struct file_operations ci_qheads_fops = {
+ .open = ci_qheads_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
+ * ci_requests_show: DMA contents of all requests currently queued (all endpts)
*/
-#define DUMP_ENTRIES 512
-static ssize_t show_registers(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int ci_requests_show(struct seq_file *s, void *data)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
+ struct ci13xxx *ci = s->private;
unsigned long flags;
- u32 *dump;
- unsigned i, k, n = 0;
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ struct list_head *ptr = NULL;
+ struct ci13xxx_req *req = NULL;
+ unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32);
- dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
- if (!dump) {
- dev_err(ci->dev, "%s: out of memory\n", __func__);
+ if (ci->role != CI_ROLE_GADGET) {
+ seq_printf(s, "not in gadget mode\n");
return 0;
}
spin_lock_irqsave(&ci->lock, flags);
- k = hw_register_read(ci, dump, DUMP_ENTRIES);
- spin_unlock_irqrestore(&ci->lock, flags);
+ for (i = 0; i < ci->hw_ep_max; i++)
+ list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
- for (i = 0; i < k; i++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "reg[0x%04X] = 0x%08X\n",
- i * (unsigned)sizeof(u32), dump[i]);
- }
- kfree(dump);
+ seq_printf(s, "EP=%02i: TD=%08X %s\n",
+ i % (ci->hw_ep_max / 2), (u32)req->dma,
+ ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+
+ for (j = 0; j < qsize; j++)
+ seq_printf(s, " %04X: %08X\n", j,
+ *((u32 *)req->ptr + j));
+ }
+ spin_unlock_irqrestore(&ci->lock, flags);
- return n;
+ return 0;
}
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ci_requests_open(struct inode *inode, struct file *file)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long addr, data, flags;
+ return single_open(file, ci_requests_show, inode->i_private);
+}
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
+static const struct file_operations ci_requests_fops = {
+ .open = ci_requests_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
- if (sscanf(buf, "%li %li", &addr, &data) != 2) {
- dev_err(ci->dev,
- "<addr> <data>: write data to register address\n");
- goto done;
- }
+static int ci_role_show(struct seq_file *s, void *data)
+{
+ struct ci13xxx *ci = s->private;
- spin_lock_irqsave(&ci->lock, flags);
- if (hw_register_write(ci, addr, data))
- dev_err(ci->dev, "invalid address range\n");
- spin_unlock_irqrestore(&ci->lock, flags);
+ seq_printf(s, "%s\n", ci_role(ci)->name);
- done:
- return count;
+ return 0;
}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
- show_registers, store_registers);
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
{
- struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
- if (attr == NULL || buf == NULL) {
- dev_err(ci->dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
+ struct seq_file *s = file->private_data;
+ struct ci13xxx *ci = s->private;
+ enum ci_role role;
+ char buf[8];
+ int ret;
+
+ if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+ if (ci->roles[role] &&
+ !strncmp(buf, ci->roles[role]->name,
+ strlen(ci->roles[role]->name)))
+ break;
- spin_lock_irqsave(&ci->lock, flags);
- for (i = 0; i < ci->hw_ep_max; i++)
- list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue)
- {
- req = list_entry(ptr, struct ci13xxx_req, queue);
+ if (role == CI_ROLE_END || role == ci->role)
+ return -EINVAL;
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: TD=%08X %s\n",
- i % ci->hw_ep_max/2, (u32)req->dma,
- ((i < ci->hw_ep_max/2) ? "RX" : "TX"));
+ ci_role_stop(ci);
+ ret = ci_role_start(ci, role);
- for (j = 0; j < qSize; j++)
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
- }
- spin_unlock_irqrestore(&ci->lock, flags);
+ return ret ? ret : count;
+}
- return n;
+static int ci_role_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ci_role_show, inode->i_private);
}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+static const struct file_operations ci_role_fops = {
+ .open = ci_role_open,
+ .write = ci_role_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
/**
* dbg_create_files: initializes the attribute interface
- * @dev: device
+ * @ci: device
*
* This function returns an error code
*/
-int dbg_create_files(struct device *dev)
+int dbg_create_files(struct ci13xxx *ci)
{
- int retval = 0;
-
- if (dev == NULL)
- return -EINVAL;
- retval = device_create_file(dev, &dev_attr_device);
- if (retval)
- goto done;
- retval = device_create_file(dev, &dev_attr_driver);
- if (retval)
- goto rm_device;
- retval = device_create_file(dev, &dev_attr_events);
- if (retval)
- goto rm_driver;
- retval = device_create_file(dev, &dev_attr_inters);
- if (retval)
- goto rm_events;
- retval = device_create_file(dev, &dev_attr_port_test);
- if (retval)
- goto rm_inters;
- retval = device_create_file(dev, &dev_attr_qheads);
- if (retval)
- goto rm_port_test;
- retval = device_create_file(dev, &dev_attr_registers);
- if (retval)
- goto rm_qheads;
- retval = device_create_file(dev, &dev_attr_requests);
- if (retval)
- goto rm_registers;
- return 0;
-
- rm_registers:
- device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
- device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
- device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
- device_remove_file(dev, &dev_attr_inters);
- rm_events:
- device_remove_file(dev, &dev_attr_events);
- rm_driver:
- device_remove_file(dev, &dev_attr_driver);
- rm_device:
- device_remove_file(dev, &dev_attr_device);
- done:
- return retval;
+ struct dentry *dent;
+
+ ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL);
+ if (!ci->debugfs)
+ return -ENOMEM;
+
+ dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci,
+ &ci_device_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs,
+ ci, &ci_port_test_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci,
+ &ci_qheads_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci,
+ &ci_requests_fops);
+ if (!dent)
+ goto err;
+
+ dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,
+ &ci_role_fops);
+ if (dent)
+ return 0;
+err:
+ debugfs_remove_recursive(ci->debugfs);
+ return -ENOMEM;
}
/**
* dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
+ * @ci: device
*/
-int dbg_remove_files(struct device *dev)
+void dbg_remove_files(struct ci13xxx *ci)
{
- if (dev == NULL)
- return -EINVAL;
- device_remove_file(dev, &dev_attr_requests);
- device_remove_file(dev, &dev_attr_registers);
- device_remove_file(dev, &dev_attr_qheads);
- device_remove_file(dev, &dev_attr_port_test);
- device_remove_file(dev, &dev_attr_inters);
- device_remove_file(dev, &dev_attr_events);
- device_remove_file(dev, &dev_attr_driver);
- device_remove_file(dev, &dev_attr_device);
- return 0;
+ debugfs_remove_recursive(ci->debugfs);
}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
index 80d96865775c..7ca6ca0a24a5 100644
--- a/drivers/usb/chipidea/debug.h
+++ b/drivers/usb/chipidea/debug.h
@@ -14,42 +14,16 @@
#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
#ifdef CONFIG_USB_CHIPIDEA_DEBUG
-void dbg_interrupt(u32 intmask);
-void dbg_done(u8 addr, const u32 token, int status);
-void dbg_event(u8 addr, const char *name, int status);
-void dbg_queue(u8 addr, const struct usb_request *req, int status);
-void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
-int dbg_create_files(struct device *dev);
-int dbg_remove_files(struct device *dev);
+int dbg_create_files(struct ci13xxx *ci);
+void dbg_remove_files(struct ci13xxx *ci);
#else
-static inline void dbg_interrupt(u32 intmask)
-{
-}
-
-static inline void dbg_done(u8 addr, const u32 token, int status)
-{
-}
-
-static inline void dbg_event(u8 addr, const char *name, int status)
-{
-}
-
-static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
-}
-
-static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
-}
-
-static inline int dbg_create_files(struct device *dev)
+static inline int dbg_create_files(struct ci13xxx *ci)
{
return 0;
}
-static inline int dbg_remove_files(struct device *dev)
+static inline void dbg_remove_files(struct ci13xxx *ci)
{
- return 0;
}
#endif
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index f64fbea1cf20..519ead2443c5 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -13,14 +13,8 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
+#include <linux/irqreturn.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
if (dir) {
mask = ENDPTCTRL_TXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_TXS; /* unstall */
mask |= ENDPTCTRL_TXR; /* reset data toggle */
@@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)
data |= ENDPTCTRL_TXE;
} else {
mask = ENDPTCTRL_RXT; /* type */
- data = type << ffs_nr(mask);
+ data = type << __ffs(mask);
mask |= ENDPTCTRL_RXS; /* unstall */
mask |= ENDPTCTRL_RXR; /* reset data toggle */
@@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
return reg;
}
-static void hw_enable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
- queue_work(ci->wq, &ci->vbus_work);
-}
-
-static void hw_disable_vbus_intr(struct ci13xxx *ci)
-{
- hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
-}
-
/**
* hw_test_and_clear_setup_guard: test & clear setup guard (execute without
* interruption)
@@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)
static void hw_usb_set_address(struct ci13xxx *ci, u8 value)
{
hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR,
- value << ffs_nr(DEVICEADDR_USBADR));
+ value << __ffs(DEVICEADDR_USBADR));
}
/**
@@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
return 0;
}
-static void vbus_work(struct work_struct *work)
-{
- struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
-
- if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
- usb_gadget_vbus_connect(&ci->gadget);
- else
- usb_gadget_vbus_disconnect(&ci->gadget);
-}
-
/******************************************************************************
* UTIL block
*****************************************************************************/
@@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
return -ENOMEM;
memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
+ mReq->zptr->next = cpu_to_le32(TD_TERMINATE);
+ mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE);
if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
+ mReq->zptr->token |= cpu_to_le32(TD_IOC);
}
ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);
if (ret)
@@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
* TODO - handle requests which spawns into several TDs
*/
memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
+ mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));
+ mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);
+ mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE);
if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
+ mReq->ptr->next = cpu_to_le32(mReq->zdma);
} else {
- mReq->ptr->next = TD_TERMINATE;
+ mReq->ptr->next = cpu_to_le32(TD_TERMINATE);
if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
+ mReq->ptr->token |= cpu_to_le32(TD_IOC);
+ }
+ mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma);
+ for (i = 1; i < TD_PAGE_COUNT; i++) {
+ u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE;
+ page &= ~TD_RESERVED_MASK;
+ mReq->ptr->page[i] = cpu_to_le32(page);
}
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ wmb();
if (!list_empty(&mEp->qh.queue)) {
struct ci13xxx_req *mReqPrev;
int n = hw_ep_bit(mEp->num, mEp->dir);
int tmp_stat;
+ u32 next = mReq->dma & TD_ADDR_MASK;
mReqPrev = list_entry(mEp->qh.queue.prev,
struct ci13xxx_req, queue);
if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->zptr->next = cpu_to_le32(next);
else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ mReqPrev->ptr->next = cpu_to_le32(next);
wmb();
if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
goto done;
@@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
}
/* QH configuration */
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
- mEp->qh.ptr->cap |= QH_ZLT;
+ mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */
+ mEp->qh.ptr->td.token &=
+ cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));
wmb(); /* synchronize before ep prime */
@@ -506,14 +483,16 @@ done:
*/
static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
{
+ u32 tmptoken = le32_to_cpu(mReq->ptr->token);
+
if (mReq->req.status != -EALREADY)
return -EINVAL;
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ if ((TD_STATUS_ACTIVE & tmptoken) != 0)
return -EBUSY;
if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+ if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)
return -EBUSY;
dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
mReq->zptr = NULL;
@@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir);
- mReq->req.status = mReq->ptr->token & TD_STATUS;
+ mReq->req.status = tmptoken & TD_STATUS;
if ((TD_STATUS_HALTED & mReq->req.status) != 0)
mReq->req.status = -1;
else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
@@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
mReq->req.status = -1;
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = tmptoken & TD_TOTAL_BYTES;
+ mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);
mReq->req.actual = mReq->req.length - mReq->req.actual;
mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
@@ -561,6 +540,12 @@ __acquires(mEp->lock)
struct ci13xxx_req *mReq = \
list_entry(mEp->qh.queue.next,
struct ci13xxx_req, queue);
+
+ if (mReq->zptr) {
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ }
+
list_del_init(&mReq->queue);
mReq->req.status = -ESHUTDOWN;
@@ -629,8 +614,6 @@ __acquires(ci->lock)
{
int retval;
- dbg_event(0xFF, "BUS RST", 0);
-
spin_unlock(&ci->lock);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
@@ -668,6 +651,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
}
/**
+ * _ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Caller must hold lock
+ */
+static int _ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *ci = mEp->ci;
+ int retval = 0;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (ci->ep0_dir == RX) ?
+ ci->ep0out : ci->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ dev_err(mEp->ci->dev, "request already in queue\n");
+ return -EBUSY;
+ }
+
+ if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) {
+ dev_err(mEp->ci->dev, "request bigger than one td\n");
+ return -EMSGSIZE;
+ }
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY)
+ retval = 0;
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ return retval;
+}
+
+/**
* isr_get_status_response: get_status request response
* @ci: ci struct
* @setup: setup request packet
@@ -714,9 +750,7 @@ __acquires(mEp->lock)
}
/* else do nothing; reserved for future use */
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, req, gfp_flags);
if (retval)
goto err_free_buf;
@@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
* This function returns an error code
*/
static int isr_setup_status_phase(struct ci13xxx *ci)
-__releases(mEp->lock)
-__acquires(mEp->lock)
{
int retval;
struct ci13xxx_ep *mEp;
@@ -773,9 +805,7 @@ __acquires(mEp->lock)
ci->status->context = ci;
ci->status->complete = isr_setup_status_complete;
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
+ retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);
return retval;
}
@@ -801,7 +831,6 @@ __acquires(mEp->lock)
if (retval < 0)
break;
list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
if (mReq->req.complete != NULL) {
spin_unlock(mEp->lock);
if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
@@ -814,8 +843,6 @@ __acquires(mEp->lock)
if (retval == -EBUSY)
retval = 0;
- if (retval < 0)
- dbg_event(_usb_addr(mEp), "DONE", retval);
return retval;
}
@@ -847,8 +874,6 @@ __acquires(ci->lock)
if (err > 0) /* needs status phase */
err = isr_setup_status_phase(ci);
if (err < 0) {
- dbg_event(_usb_addr(mEp),
- "ERROR", err);
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev,
@@ -884,8 +909,6 @@ __acquires(ci->lock)
ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
- dbg_setup(_usb_addr(mEp), &req);
-
switch (req.bRequest) {
case USB_REQ_CLEAR_FEATURE:
if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
@@ -997,8 +1020,6 @@ delegate:
}
if (err < 0) {
- dbg_event(_usb_addr(mEp), "ERROR", err);
-
spin_unlock(&ci->lock);
if (usb_ep_set_halt(&mEp->ep))
dev_err(ci->dev, "error: ep_set_halt\n");
@@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep,
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
int retval = 0;
unsigned long flags;
+ u32 cap = 0;
if (ep == NULL || desc == NULL)
return -EINVAL;
@@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep,
mEp->ep.maxpacket = usb_endpoint_maxp(desc);
- dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
- mEp->qh.ptr->cap = 0;
-
if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
- else
- mEp->qh.ptr->cap &= ~QH_ZLT;
+ cap |= QH_IOS;
+ if (mEp->num)
+ cap |= QH_ZLT;
+ cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT;
+
+ mEp->qh.ptr->cap = cpu_to_le32(cap);
- mEp->qh.ptr->cap |=
- (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
+ mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */
/*
* Enable endpoints in the HW other than ep0 as ep0
@@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep)
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
retval |= _ep_nuke(mEp);
retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir);
@@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
}
}
- dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
return (mReq == NULL) ? NULL : &mReq->req;
}
@@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
kfree(mReq);
- dbg_event(_usb_addr(mEp), "FREE", 0);
-
spin_unlock_irqrestore(mEp->lock, flags);
}
@@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t __maybe_unused gfp_flags)
{
struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- struct ci13xxx *ci = mEp->ci;
int retval = 0;
unsigned long flags;
@@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (ci->ep0_dir == RX) ?
- ci->ep0out : ci->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n",
- _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- dev_err(mEp->ci->dev, "request already in queue\n");
- goto done;
- }
-
- if (req->length > 4 * CI13XXX_PAGE_SIZE) {
- req->length = 4 * CI13XXX_PAGE_SIZE;
- retval = -EMSGSIZE;
- dev_warn(mEp->ci->dev, "request length truncated\n");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
-
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
+ retval = _ep_queue(ep, req, gfp_flags);
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
}
@@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
/* pop request */
@@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)
direction = mEp->dir;
do {
- dbg_event(_usb_addr(mEp), "HALT", value);
retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);
if (!value)
@@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep)
return -EINVAL;
spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "WEDGE", 0);
mEp->wedge = 1;
-
spin_unlock_irqrestore(mEp->lock, flags);
return usb_ep_set_halt(ep);
@@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep)
spin_lock_irqsave(mEp->lock, flags);
- dbg_event(_usb_addr(mEp), "FFLUSH", 0);
hw_ep_flush(mEp->ci, mEp->num, mEp->dir);
spin_unlock_irqrestore(mEp->lock, flags);
@@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
} else {
hw_device_state(ci, 0);
@@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
if (ci->vbus_active) {
- if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+ if (ci->platdata->flags & CI13XXX_REGS_SHARED)
hw_device_reset(ci, USBMODE_CM_DC);
- hw_enable_vbus_intr(ci);
- }
} else {
pm_runtime_put_sync(&ci->gadget.dev);
goto done;
@@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
}
}
intr = hw_test_and_clear_intr_active(ci);
- dbg_interrupt(intr);
if (intr) {
/* order defines priority - do NOT change it */
@@ -1676,29 +1633,12 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
} else {
retval = IRQ_NONE;
}
-
- intr = hw_read(ci, OP_OTGSC, ~0);
- hw_write(ci, OP_OTGSC, ~0, intr);
-
- if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
- queue_work(ci->wq, &ci->vbus_work);
-
spin_unlock(&ci->lock);
return retval;
}
/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
-}
-
-/**
* udc_start: initialize gadget role
* @ci: chipidea controller
*/
@@ -1717,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci)
INIT_LIST_HEAD(&ci->gadget.ep_list);
- dev_set_name(&ci->gadget.dev, "gadget");
- ci->gadget.dev.dma_mask = dev->dma_mask;
- ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- ci->gadget.dev.parent = dev;
- ci->gadget.dev.release = udc_release;
-
/* alloc resources */
ci->qh_pool = dma_pool_create("ci13xxx_qh", dev,
sizeof(struct ci13xxx_qh),
@@ -1758,24 +1692,13 @@ static int udc_start(struct ci13xxx *ci)
retval = hw_device_reset(ci, USBMODE_CM_DC);
if (retval)
goto put_transceiver;
- hw_enable_vbus_intr(ci);
- }
-
- retval = device_register(&ci->gadget.dev);
- if (retval) {
- put_device(&ci->gadget.dev);
- goto put_transceiver;
}
- retval = dbg_create_files(ci->dev);
- if (retval)
- goto unreg_device;
-
if (!IS_ERR_OR_NULL(ci->transceiver)) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
- goto remove_dbg;
+ goto put_transceiver;
}
retval = usb_add_gadget_udc(dev, &ci->gadget);
@@ -1795,10 +1718,6 @@ remove_trans:
}
dev_err(dev, "error = %i\n", retval);
-remove_dbg:
- dbg_remove_files(ci->dev);
-unreg_device:
- device_unregister(&ci->gadget.dev);
put_transceiver:
if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
usb_put_phy(ci->transceiver);
@@ -1821,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci == NULL)
return;
- hw_disable_vbus_intr(ci);
- cancel_work_sync(&ci->vbus_work);
-
usb_del_gadget_udc(&ci->gadget);
destroy_eps(ci);
@@ -1836,8 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)
if (ci->global_phy)
usb_put_phy(ci->transceiver);
}
- dbg_remove_files(ci->dev);
- device_unregister(&ci->gadget.dev);
/* my kobject is dynamic, I swear! */
memset(&ci->gadget, 0, sizeof(ci->gadget));
}
@@ -1864,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
rdrv->irq = udc_irq;
rdrv->name = "gadget";
ci->roles[CI_ROLE_GADGET] = rdrv;
- INIT_WORK(&ci->vbus_work, vbus_work);
return 0;
}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 4ff2384d7ca8..d12e8b59b110 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -40,7 +40,7 @@ struct ci13xxx_td {
#define TD_CURR_OFFSET (0x0FFFUL << 0)
#define TD_FRAME_NUM (0x07FFUL << 0)
#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/* DMA layout of queue heads */
struct ci13xxx_qh {
@@ -57,7 +57,7 @@ struct ci13xxx_qh {
/* 9 */
u32 RESERVED;
struct usb_ctrlrequest setup;
-} __attribute__ ((packed));
+} __attribute__ ((packed, aligned(4)));
/**
* struct ci13xxx_req - usb request representation
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
new file mode 100644
index 000000000000..714a6bd810ed
--- /dev/null
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "ci13xxx_imx.h"
+
+#define USB_DEV_MAX 4
+
+#define MX25_USB_PHY_CTRL_OFFSET 0x08
+#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
+
+#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
+#define MX53_USB_UH2_CTRL_OFFSET 0x14
+#define MX53_USB_UH3_CTRL_OFFSET 0x18
+#define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
+#define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
+#define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
+
+#define MX6_BM_OVER_CUR_DIS BIT(7)
+
+struct imx_usbmisc {
+ void __iomem *base;
+ spinlock_t lock;
+ struct clk *clk;
+ struct usbmisc_usb_device usbdev[USB_DEV_MAX];
+ const struct usbmisc_ops *ops;
+};
+
+static struct imx_usbmisc *usbmisc;
+
+static struct usbmisc_usb_device *get_usbdev(struct device *dev)
+{
+ int i, ret;
+
+ for (i = 0; i < USB_DEV_MAX; i++) {
+ if (usbmisc->usbdev[i].dev == dev)
+ return &usbmisc->usbdev[i];
+ else if (!usbmisc->usbdev[i].dev)
+ break;
+ }
+
+ if (i >= USB_DEV_MAX)
+ return ERR_PTR(-EBUSY);
+
+ ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return &usbmisc->usbdev[i];
+}
+
+static int usbmisc_imx25_post(struct device *dev)
+{
+ struct usbmisc_usb_device *usbdev;
+ void __iomem *reg;
+ unsigned long flags;
+ u32 val;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
+
+ if (usbdev->evdo) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ val = readl(reg);
+ writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ usleep_range(5000, 10000); /* needed to stabilize voltage */
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx53_init(struct device *dev)
+{
+ struct usbmisc_usb_device *usbdev;
+ void __iomem *reg = NULL;
+ unsigned long flags;
+ u32 val = 0;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ if (usbdev->disable_oc) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ switch (usbdev->index) {
+ case 0:
+ reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
+ break;
+ case 1:
+ reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
+ break;
+ case 2:
+ reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+ break;
+ case 3:
+ reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
+ val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
+ break;
+ }
+ if (reg && val)
+ writel(val, reg);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx6q_init(struct device *dev)
+{
+
+ struct usbmisc_usb_device *usbdev;
+ unsigned long flags;
+ u32 reg;
+
+ usbdev = get_usbdev(dev);
+ if (IS_ERR(usbdev))
+ return PTR_ERR(usbdev);
+
+ if (usbdev->disable_oc) {
+ spin_lock_irqsave(&usbmisc->lock, flags);
+ reg = readl(usbmisc->base + usbdev->index * 4);
+ writel(reg | MX6_BM_OVER_CUR_DIS,
+ usbmisc->base + usbdev->index * 4);
+ spin_unlock_irqrestore(&usbmisc->lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct usbmisc_ops imx25_usbmisc_ops = {
+ .post = usbmisc_imx25_post,
+};
+
+static const struct usbmisc_ops imx53_usbmisc_ops = {
+ .init = usbmisc_imx53_init,
+};
+
+static const struct usbmisc_ops imx6q_usbmisc_ops = {
+ .init = usbmisc_imx6q_init,
+};
+
+static const struct of_device_id usbmisc_imx_dt_ids[] = {
+ {
+ .compatible = "fsl,imx25-usbmisc",
+ .data = &imx25_usbmisc_ops,
+ },
+ {
+ .compatible = "fsl,imx53-usbmisc",
+ .data = &imx53_usbmisc_ops,
+ },
+ {
+ .compatible = "fsl,imx6q-usbmisc",
+ .data = &imx6q_usbmisc_ops,
+ },
+ { /* sentinel */ }
+};
+
+static int usbmisc_imx_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct imx_usbmisc *data;
+ int ret;
+ struct of_device_id *tmp_dev;
+
+ if (usbmisc)
+ return -EBUSY;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ dev_err(&pdev->dev,
+ "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
+ return PTR_ERR(data->clk);
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "clk_prepare_enable failed, err=%d\n", ret);
+ return ret;
+ }
+
+ tmp_dev = (struct of_device_id *)
+ of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
+ data->ops = (const struct usbmisc_ops *)tmp_dev->data;
+ usbmisc = data;
+ ret = usbmisc_set_ops(data->ops);
+ if (ret) {
+ usbmisc = NULL;
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int usbmisc_imx_remove(struct platform_device *pdev)
+{
+ usbmisc_unset_ops(usbmisc->ops);
+ clk_disable_unprepare(usbmisc->clk);
+ usbmisc = NULL;
+ return 0;
+}
+
+static struct platform_driver usbmisc_imx_driver = {
+ .probe = usbmisc_imx_probe,
+ .remove = usbmisc_imx_remove,
+ .driver = {
+ .name = "usbmisc_imx",
+ .owner = THIS_MODULE,
+ .of_match_table = usbmisc_imx_dt_ids,
+ },
+};
+
+int usbmisc_imx_drv_init(void)
+{
+ return platform_driver_register(&usbmisc_imx_driver);
+}
+subsys_initcall(usbmisc_imx_drv_init);
+
+void usbmisc_imx_drv_exit(void)
+{
+ platform_driver_unregister(&usbmisc_imx_driver);
+}
+module_exit(usbmisc_imx_drv_exit);
+
+MODULE_ALIAS("platform:usbmisc-imx");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("driver for imx usb non-core registers");
+MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c
deleted file mode 100644
index a1bce391e825..000000000000
--- a/drivers/usb/chipidea/usbmisc_imx6q.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/module.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include "ci13xxx_imx.h"
-
-#define USB_DEV_MAX 4
-
-#define BM_OVER_CUR_DIS BIT(7)
-
-struct imx6q_usbmisc {
- void __iomem *base;
- spinlock_t lock;
- struct clk *clk;
- struct usbmisc_usb_device usbdev[USB_DEV_MAX];
-};
-
-static struct imx6q_usbmisc *usbmisc;
-
-static struct usbmisc_usb_device *get_usbdev(struct device *dev)
-{
- int i, ret;
-
- for (i = 0; i < USB_DEV_MAX; i++) {
- if (usbmisc->usbdev[i].dev == dev)
- return &usbmisc->usbdev[i];
- else if (!usbmisc->usbdev[i].dev)
- break;
- }
-
- if (i >= USB_DEV_MAX)
- return ERR_PTR(-EBUSY);
-
- ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]);
- if (ret)
- return ERR_PTR(ret);
-
- return &usbmisc->usbdev[i];
-}
-
-static int usbmisc_imx6q_init(struct device *dev)
-{
-
- struct usbmisc_usb_device *usbdev;
- unsigned long flags;
- u32 reg;
-
- usbdev = get_usbdev(dev);
- if (IS_ERR(usbdev))
- return PTR_ERR(usbdev);
-
- if (usbdev->disable_oc) {
- spin_lock_irqsave(&usbmisc->lock, flags);
- reg = readl(usbmisc->base + usbdev->index * 4);
- writel(reg | BM_OVER_CUR_DIS,
- usbmisc->base + usbdev->index * 4);
- spin_unlock_irqrestore(&usbmisc->lock, flags);
- }
-
- return 0;
-}
-
-static const struct usbmisc_ops imx6q_usbmisc_ops = {
- .init = usbmisc_imx6q_init,
-};
-
-static const struct of_device_id usbmisc_imx6q_dt_ids[] = {
- { .compatible = "fsl,imx6q-usbmisc"},
- { /* sentinel */ }
-};
-
-static int usbmisc_imx6q_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct imx6q_usbmisc *data;
- int ret;
-
- if (usbmisc)
- return -EBUSY;
-
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- spin_lock_init(&data->lock);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- data->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(data->base))
- return PTR_ERR(data->base);
-
- data->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(data->clk)) {
- dev_err(&pdev->dev,
- "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
- return PTR_ERR(data->clk);
- }
-
- ret = clk_prepare_enable(data->clk);
- if (ret) {
- dev_err(&pdev->dev,
- "clk_prepare_enable failed, err=%d\n", ret);
- return ret;
- }
-
- ret = usbmisc_set_ops(&imx6q_usbmisc_ops);
- if (ret) {
- clk_disable_unprepare(data->clk);
- return ret;
- }
-
- usbmisc = data;
-
- return 0;
-}
-
-static int usbmisc_imx6q_remove(struct platform_device *pdev)
-{
- usbmisc_unset_ops(&imx6q_usbmisc_ops);
- clk_disable_unprepare(usbmisc->clk);
- return 0;
-}
-
-static struct platform_driver usbmisc_imx6q_driver = {
- .probe = usbmisc_imx6q_probe,
- .remove = usbmisc_imx6q_remove,
- .driver = {
- .name = "usbmisc_imx6q",
- .owner = THIS_MODULE,
- .of_match_table = usbmisc_imx6q_dt_ids,
- },
-};
-
-int __init usbmisc_imx6q_drv_init(void)
-{
- return platform_driver_register(&usbmisc_imx6q_driver);
-}
-subsys_initcall(usbmisc_imx6q_drv_init);
-
-void __exit usbmisc_imx6q_drv_exit(void)
-{
- platform_driver_unregister(&usbmisc_imx6q_driver);
-}
-module_exit(usbmisc_imx6q_drv_exit);
-
-MODULE_ALIAS("platform:usbmisc-imx6q");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("driver for imx6q usb non-core registers");
-MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 316aac8e4ca1..bb8b73682a70 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -2,11 +2,10 @@
# USB Class driver configuration
#
comment "USB Device Class drivers"
- depends on USB
config USB_ACM
tristate "USB Modem (CDC ACM) support"
- depends on USB && TTY
+ depends on TTY
---help---
This driver supports USB modems and ISDN adapters which support the
Communication Device Class Abstract Control Model interface.
@@ -21,7 +20,6 @@ config USB_ACM
config USB_PRINTER
tristate "USB Printer support"
- depends on USB
help
Say Y here if you want to connect a USB printer to your computer's
USB port.
@@ -31,7 +29,6 @@ config USB_PRINTER
config USB_WDM
tristate "USB Wireless Device Management support"
- depends on USB
---help---
This driver supports the WMC Device Management functionality
of cell phones compliant to the CDC WMC specification. You can use
@@ -42,7 +39,6 @@ config USB_WDM
config USB_TMC
tristate "USB Test and Measurement Class support"
- depends on USB
help
Say Y here if you want to connect a USB device that follows
the USB.org specification for USB Test and Measurement devices
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 387dc6c8ad25..9b1cbcf8fb7f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -292,7 +292,6 @@ static void acm_ctrl_irq(struct urb *urb)
{
struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer;
- struct tty_struct *tty;
unsigned char *data;
int newctrl;
int retval;
@@ -327,17 +326,12 @@ static void acm_ctrl_irq(struct urb *urb)
break;
case USB_CDC_NOTIFY_SERIAL_STATE:
- tty = tty_port_tty_get(&acm->port);
newctrl = get_unaligned_le16(data);
- if (tty) {
- if (!acm->clocal &&
- (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
- dev_dbg(&acm->control->dev,
- "%s - calling hangup\n", __func__);
- tty_hangup(tty);
- }
- tty_kref_put(tty);
+ if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+ dev_dbg(&acm->control->dev, "%s - calling hangup\n",
+ __func__);
+ tty_port_tty_hangup(&acm->port, false);
}
acm->ctrlin = newctrl;
@@ -475,15 +469,10 @@ static void acm_write_bulk(struct urb *urb)
static void acm_softint(struct work_struct *work)
{
struct acm *acm = container_of(work, struct acm, work);
- struct tty_struct *tty;
dev_vdbg(&acm->data->dev, "%s\n", __func__);
- tty = tty_port_tty_get(&acm->port);
- if (!tty)
- return;
- tty_wakeup(tty);
- tty_kref_put(tty);
+ tty_port_tty_wakeup(&acm->port);
}
/*
@@ -839,14 +828,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,
return rv;
}
-static const __u32 acm_tty_speed[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600,
- 1200, 1800, 2400, 4800, 9600, 19200, 38400,
- 57600, 115200, 230400, 460800, 500000, 576000,
- 921600, 1000000, 1152000, 1500000, 2000000,
- 2500000, 3000000, 3500000, 4000000
-};
-
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
@@ -981,6 +962,10 @@ static int acm_probe(struct usb_interface *intf,
/* normal quirks */
quirks = (unsigned long)id->driver_info;
+
+ if (quirks == IGNORE_DEVICE)
+ return -ENODEV;
+
num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;
/* handle quirks deadly to normal probing*/
@@ -1519,15 +1504,9 @@ err_out:
static int acm_reset_resume(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
- struct tty_struct *tty;
- if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
- tty = tty_port_tty_get(&acm->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- }
+ if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
+ tty_port_tty_hangup(&acm->port, false);
return acm_resume(intf);
}
@@ -1700,6 +1679,15 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = NO_DATA_INTERFACE,
},
+#if IS_ENABLED(CONFIG_INPUT_IMS_PCU)
+ { USB_DEVICE(0x04d8, 0x0082), /* Application mode */
+ .driver_info = IGNORE_DEVICE,
+ },
+ { USB_DEVICE(0x04d8, 0x0083), /* Bootloader mode */
+ .driver_info = IGNORE_DEVICE,
+ },
+#endif
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 35ef887b7417..0f76e4af600e 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -128,3 +128,4 @@ struct acm {
#define NO_CAP_LINE 4
#define NOT_A_MODEM 8
#define NO_DATA_INTERFACE 16
+#define IGNORE_DEVICE 32
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 122d056d96d5..8a230f0ef77c 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -13,6 +13,7 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)
return 0;
}
+static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct wdm_device *desc = file->private_data;
+ int rv = 0;
+
+ switch (cmd) {
+ case IOCTL_WDM_MAX_COMMAND:
+ if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand)))
+ rv = -EFAULT;
+ break;
+ default:
+ rv = -ENOTTY;
+ }
+ return rv;
+}
+
static const struct file_operations wdm_fops = {
.owner = THIS_MODULE,
.read = wdm_read,
@@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = {
.flush = wdm_flush,
.release = wdm_release,
.poll = wdm_poll,
+ .unlocked_ioctl = wdm_ioctl,
+ .compat_ioctl = wdm_ioctl,
.llseek = noop_llseek,
};
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 70d69d06054f..4c5506ae5e45 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -718,50 +718,32 @@ exit:
static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int get_capabilities(struct usbtmc_device_data *data)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index f70c1a1694ad..8772b3659296 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -3,7 +3,6 @@
#
config USB_DEBUG
bool "USB verbose debug messages"
- depends on USB
help
Say Y here if you want the USB core & hub drivers to produce a bunch
of debug messages to the system log. Select this if you are having a
@@ -11,7 +10,6 @@ config USB_DEBUG
config USB_ANNOUNCE_NEW_DEVICES
bool "USB announce new devices"
- depends on USB
default N
help
Say Y here if you want the USB core to always announce the
@@ -25,11 +23,24 @@ config USB_ANNOUNCE_NEW_DEVICES
log, or have any doubts about this, say N here.
comment "Miscellaneous USB options"
- depends on USB
+
+config USB_DEFAULT_PERSIST
+ bool "Enable USB persist by default"
+ default y
+ help
+ Say N here if you don't want USB power session persistance
+ enabled by default. If you say N it will make suspended USB
+ devices that lose power get reenumerated as if they had been
+ unplugged, causing any mounted filesystems to be lost. The
+ persist feature can still be enabled for individual devices
+ through the power/persist sysfs node. See
+ Documentation/usb/persist.txt for more info.
+
+ If you have any questions about this, say Y here, only say N
+ if you know exactly what you are doing.
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation"
- depends on USB
help
If you say Y here, the USB subsystem will use dynamic minor
allocation for any device that uses the USB major number.
@@ -38,25 +49,8 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here.
-config USB_SUSPEND
- bool "USB runtime power management (autosuspend) and wakeup"
- depends on USB && PM_RUNTIME
- help
- If you say Y here, you can use driver calls or the sysfs
- "power/control" file to enable or disable autosuspend for
- individual USB peripherals (see
- Documentation/usb/power-management.txt for more details).
-
- Also, USB "remote wakeup" signaling is supported, whereby some
- USB devices (like keyboards and network adapters) can wake up
- their parent hub. That wakeup cascades up the USB tree, and
- could wake the system from states like suspend-to-RAM.
-
- If you are unsure about this, say N here.
-
config USB_OTG
bool "OTG support"
- depends on USB
depends on USB_SUSPEND
default n
help
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8823e98989fe..caefc800f298 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -739,6 +739,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
index &= 0xff;
switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT:
+ if ((index & ~USB_DIR_IN) == 0)
+ return 0;
ret = findintfep(ps->dev, index);
if (ret >= 0)
ret = checkintf(ps, ret);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d938b2b99e31..6eab440e1542 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1196,9 +1196,14 @@ done:
*
* This is the central routine for suspending USB devices. It calls the
* suspend methods for all the interface drivers in @udev and then calls
- * the suspend method for @udev itself. If an error occurs at any stage,
- * all the interfaces which were suspended are resumed so that they remain
- * in the same state as the device.
+ * the suspend method for @udev itself. When the routine is called in
+ * autosuspend, if an error occurs at any stage, all the interfaces
+ * which were suspended are resumed so that they remain in the same
+ * state as the device, but when called from system sleep, all error
+ * from suspend methods of interfaces and the non-root-hub device itself
+ * are simply ignored, so all suspended interfaces are only resumed
+ * to the device's state when @udev is root-hub and its suspend method
+ * returns failure.
*
* Autosuspend requests originating from a child device or an interface
* driver may be made without the protection of @udev's device lock, but
@@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
- msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
- while (++i < n) {
- intf = udev->actconfig->interface[i];
- usb_resume_interface(udev, intf, msg, 0);
+ if (udev->actconfig) {
+ msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
+ while (++i < n) {
+ intf = udev->actconfig->interface[i];
+ usb_resume_interface(udev, intf, msg, 0);
+ }
}
/* If the suspend succeeded then prevent any more URB submissions
@@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
#endif /* CONFIG_PM */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
/**
* usb_enable_autosuspend - allow a USB device to be autosuspended
@@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
return ret;
}
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
struct bus_type usb_bus_type = {
.name = "usb",
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 271e761f563e..acbfeb0a0119 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)
c = usb_choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
- if (err) {
+ if (err && err != -ENODEV) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 2b487d4797bd..caeb8d6d39fb 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -37,119 +37,123 @@
/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */
-#ifdef CONFIG_PM_SLEEP
-
-/* Coordinate handoffs between EHCI and companion controllers
- * during system resume
+/*
+ * Coordinate handoffs between EHCI and companion controllers
+ * during EHCI probing and system resume.
*/
-static DEFINE_MUTEX(companions_mutex);
+static DECLARE_RWSEM(companions_rwsem);
#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
-enum companion_action {
- SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
-};
+static inline int is_ohci_or_uhci(struct pci_dev *pdev)
+{
+ return pdev->class == CL_OHCI || pdev->class == CL_UHCI;
+}
+
+typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd);
-static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
- enum companion_action action)
+/* Iterate over PCI devices in the same slot as pdev and call fn for each */
+static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,
+ companion_fn fn)
{
struct pci_dev *companion;
struct usb_hcd *companion_hcd;
unsigned int slot = PCI_SLOT(pdev->devfn);
- /* Iterate through other PCI functions in the same slot.
- * If pdev is OHCI or UHCI then we are looking for EHCI, and
- * vice versa.
+ /*
+ * Iterate through other PCI functions in the same slot.
+ * If the function's drvdata isn't set then it isn't bound to
+ * a USB host controller driver, so skip it.
*/
companion = NULL;
for_each_pci_dev(companion) {
if (companion->bus != pdev->bus ||
PCI_SLOT(companion->devfn) != slot)
continue;
-
companion_hcd = pci_get_drvdata(companion);
if (!companion_hcd)
continue;
-
- /* For SET_HS_COMPANION, store a pointer to the EHCI bus in
- * the OHCI/UHCI companion bus structure.
- * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus
- * in the OHCI/UHCI companion bus structure.
- * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI
- * companion controllers have fully resumed.
- */
-
- if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) &&
- companion->class == CL_EHCI) {
- /* action must be SET_HS_COMPANION */
- dev_dbg(&companion->dev, "HS companion for %s\n",
- dev_name(&pdev->dev));
- hcd->self.hs_companion = &companion_hcd->self;
-
- } else if (pdev->class == CL_EHCI &&
- (companion->class == CL_OHCI ||
- companion->class == CL_UHCI)) {
- switch (action) {
- case SET_HS_COMPANION:
- dev_dbg(&pdev->dev, "HS companion for %s\n",
- dev_name(&companion->dev));
- companion_hcd->self.hs_companion = &hcd->self;
- break;
- case CLEAR_HS_COMPANION:
- companion_hcd->self.hs_companion = NULL;
- break;
- case WAIT_FOR_COMPANIONS:
- device_pm_wait_for_dev(&pdev->dev,
- &companion->dev);
- break;
- }
- }
+ fn(pdev, hcd, companion, companion_hcd);
}
}
-static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+/*
+ * We're about to add an EHCI controller, which will unceremoniously grab
+ * all the port connections away from its companions. To prevent annoying
+ * error messages, lock the companion's root hub and gracefully unconfigure
+ * it beforehand. Leave it locked until the EHCI controller is all set.
+ */
+static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
- mutex_lock(&companions_mutex);
- dev_set_drvdata(&pdev->dev, hcd);
- companion_common(pdev, hcd, SET_HS_COMPANION);
- mutex_unlock(&companions_mutex);
+ struct usb_device *udev;
+
+ if (is_ohci_or_uhci(companion)) {
+ udev = companion_hcd->self.root_hub;
+ usb_lock_device(udev);
+ usb_set_configuration(udev, 0);
+ }
}
-static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd)
+/*
+ * Adding the EHCI controller has either succeeded or failed. Set the
+ * companion pointer accordingly, and in either case, reconfigure and
+ * unlock the root hub.
+ */
+static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
- mutex_lock(&companions_mutex);
- dev_set_drvdata(&pdev->dev, NULL);
+ struct usb_device *udev;
- /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */
- if (pdev->class == CL_OHCI || pdev->class == CL_UHCI)
- hcd->self.hs_companion = NULL;
+ if (is_ohci_or_uhci(companion)) {
+ if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */
+ dev_dbg(&pdev->dev, "HS companion for %s\n",
+ dev_name(&companion->dev));
+ companion_hcd->self.hs_companion = &hcd->self;
+ }
+ udev = companion_hcd->self.root_hub;
+ usb_set_configuration(udev, 1);
+ usb_unlock_device(udev);
+ }
+}
- /* Otherwise search for companion buses and clear their pointers */
- else
- companion_common(pdev, hcd, CLEAR_HS_COMPANION);
- mutex_unlock(&companions_mutex);
+/*
+ * We just added a non-EHCI controller. Find the EHCI controller to
+ * which it is a companion, and store a pointer to the bus structure.
+ */
+static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) {
+ dev_dbg(&pdev->dev, "FS/LS companion for %s\n",
+ dev_name(&companion->dev));
+ hcd->self.hs_companion = &companion_hcd->self;
+ }
}
-static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd)
+/* We are removing an EHCI controller. Clear the companions' pointers. */
+static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
{
- /* Only EHCI controllers need to wait.
- * No locking is needed because a controller cannot be resumed
- * while one of its companions is getting unbound.
- */
- if (pdev->class == CL_EHCI)
- companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
+ if (is_ohci_or_uhci(companion))
+ companion_hcd->self.hs_companion = NULL;
}
-#else /* !CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM
-static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
-static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {}
-static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {}
+/* An EHCI controller must wait for its companions before resuming. */
+static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd,
+ struct pci_dev *companion, struct usb_hcd *companion_hcd)
+{
+ if (is_ohci_or_uhci(companion))
+ device_pm_wait_for_dev(&pdev->dev, &companion->dev);
+}
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
driver->description)) {
dev_dbg(&dev->dev, "controller already in use\n");
retval = -EBUSY;
- goto clear_companion;
+ goto put_hcd;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
@@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (region == PCI_ROM_RESOURCE) {
dev_dbg(&dev->dev, "no i/o regions available\n");
retval = -EBUSY;
- goto clear_companion;
+ goto put_hcd;
}
}
pci_set_master(dev);
- retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+ /* Note: dev_set_drvdata must be called while holding the rwsem */
+ if (dev->class == CL_EHCI) {
+ down_write(&companions_rwsem);
+ dev_set_drvdata(&dev->dev, hcd);
+ for_each_companion(dev, hcd, ehci_pre_add);
+ retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+ if (retval != 0)
+ dev_set_drvdata(&dev->dev, NULL);
+ for_each_companion(dev, hcd, ehci_post_add);
+ up_write(&companions_rwsem);
+ } else {
+ down_read(&companions_rwsem);
+ dev_set_drvdata(&dev->dev, hcd);
+ retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
+ if (retval != 0)
+ dev_set_drvdata(&dev->dev, NULL);
+ else
+ for_each_companion(dev, hcd, non_ehci_add);
+ up_read(&companions_rwsem);
+ }
+
if (retval != 0)
goto unmap_registers;
- set_hs_companion(dev, hcd);
if (pci_dev_run_wake(dev))
pm_runtime_put_noidle(&dev->dev);
@@ -266,8 +289,7 @@ release_mem_region:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else
release_region(hcd->rsrc_start, hcd->rsrc_len);
-clear_companion:
- clear_hs_companion(dev, hcd);
+put_hcd:
usb_put_hcd(hcd);
disable_pci:
pci_disable_device(dev);
@@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
usb_hcd_irq(0, hcd);
local_irq_enable();
- usb_remove_hcd(hcd);
+ /* Note: dev_set_drvdata must be called while holding the rwsem */
+ if (dev->class == CL_EHCI) {
+ down_write(&companions_rwsem);
+ for_each_companion(dev, hcd, ehci_remove);
+ usb_remove_hcd(hcd);
+ dev_set_drvdata(&dev->dev, NULL);
+ up_write(&companions_rwsem);
+ } else {
+ /* Not EHCI; just clear the companion pointer */
+ down_read(&companions_rwsem);
+ hcd->self.hs_companion = NULL;
+ usb_remove_hcd(hcd);
+ dev_set_drvdata(&dev->dev, NULL);
+ up_read(&companions_rwsem);
+ }
+
if (hcd->driver->flags & HCD_MEMORY) {
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
} else {
release_region(hcd->rsrc_start, hcd->rsrc_len);
}
- clear_hs_companion(dev, hcd);
+
usb_put_hcd(hcd);
pci_disable_device(dev);
}
@@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event)
pci_set_master(pci_dev);
if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
- if (event != PM_EVENT_AUTO_RESUME)
- wait_for_companions(pci_dev, hcd);
+
+ /*
+ * Only EHCI controllers have to wait for their companions.
+ * No locking is needed because PCI controller drivers do not
+ * get unbound during system resume.
+ */
+ if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME)
+ for_each_companion(pci_dev, hcd,
+ ehci_wait_for_companions);
retval = hcd->driver->pci_resume(hcd,
event == PM_EVENT_RESTORE);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 99b34a30354f..d53547d2e4c7 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
#endif /* CONFIG_PM */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
@@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
/*-------------------------------------------------------------------------*/
@@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
@@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
+int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+ if (!hcd->driver->find_raw_port_number)
+ return port1;
+
+ return hcd->driver->find_raw_port_number(hcd, port1);
+}
+
static int usb_hcd_request_irqs(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
@@ -2582,7 +2590,7 @@ error_create_attr_group:
hcd->rh_registered = 0;
spin_unlock_irq(&hcd_root_hub_lock);
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
@@ -2637,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
cancel_work_sync(&hcd->wakeup_work);
#endif
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5480352f984d..feef9351463d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,
mutex_lock(&hub->status_mutex);
ret = get_port_status(hub->hdev, port1, &hub->status->port);
if (ret < 4) {
- dev_err(hub->intfdev,
- "%s failed (err = %d)\n", __func__, ret);
+ if (ret != -ENODEV)
+ dev_err(hub->intfdev,
+ "%s failed (err = %d)\n", __func__, ret);
if (ret >= 0)
ret = -EIO;
} else {
@@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)
/* drop lock so HCD can concurrently report other TT errors */
spin_unlock_irqrestore (&hub->tt.lock, flags);
status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
- if (status)
+ if (status && status != -ENODEV)
dev_err (&hdev->dev,
"clear tt %d (%04x) error %d\n",
clear->tt, clear->devinfo, status);
@@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,
mutex_lock(&hub->status_mutex);
ret = get_hub_status(hub->hdev, &hub->status->hub);
- if (ret < 0)
- dev_err (hub->intfdev,
- "%s failed (err = %d)\n", __func__, ret);
- else {
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ dev_err(hub->intfdev,
+ "%s failed (err = %d)\n", __func__, ret);
+ } else {
*status = le16_to_cpu(hub->status->hub.wHubStatus);
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
@@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)
return -EINVAL;
ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);
- if (ret) {
- dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
- port1, ret);
+ if (ret)
return ret;
- }
/* Wait for the link to enter the disabled state. */
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
@@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
ret = usb_clear_port_feature(hdev, port1,
USB_PORT_FEAT_ENABLE);
}
- if (ret)
+ if (ret && ret != -ENODEV)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
return ret;
@@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,
message = "hub has too many ports!";
ret = -ENODEV;
goto fail;
+ } else if (hub->descriptor->bNbrPorts == 0) {
+ message = "hub doesn't have any ports!";
+ ret = -ENODEV;
+ goto fail;
}
hdev->maxchild = hub->descriptor->bNbrPorts;
@@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)
if (udev->config == NULL) {
err = usb_get_configuration(udev);
if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
+ if (err != -ENODEV)
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
return err;
}
}
@@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
status = set_port_feature(hub->hdev, port1, (warm ?
USB_PORT_FEAT_BH_PORT_RESET :
USB_PORT_FEAT_RESET));
- if (status) {
+ if (status == -ENODEV) {
+ ; /* The hub is gone */
+ } else if (status) {
dev_err(hub->intfdev,
"cannot %sreset port %d (err = %d)\n",
warm ? "warm " : "", port1, status);
} else {
status = hub_port_wait_reset(hub, port1, udev, delay,
warm);
- if (status && status != -ENOTCONN)
+ if (status && status != -ENOTCONN && status != -ENODEV)
dev_dbg(hub->intfdev,
"port_wait_reset: err = %d\n",
status);
@@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)
}
EXPORT_SYMBOL_GPL(usb_enable_ltm);
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM
/*
* usb_disable_function_remotewakeup - disable usb3.0
* device's function remote wakeup
@@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*
- * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
- * the root hub for their bus goes into global suspend ... so we don't
- * (falsely) update the device power state to say it suspended.
+ * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get
+ * suspended only when their bus goes into global suspend (i.e., the root
+ * hub is suspended). Nevertheless, we change @udev->state to
+ * USB_STATE_SUSPENDED as this is the device's "logical" state. The actual
+ * upstream port setting is stored in @udev->port_is_suspended.
*
* Returns 0 on success, else negative errno.
*/
@@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
enum pm_qos_flags_status pm_qos_stat;
int port1 = udev->portnum;
int status;
+ bool really_suspend = true;
/* enable remote wakeup when appropriate; this lets the device
* wake up the upstream hub (including maybe the root hub).
@@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3);
- else
+ else if (PMSG_IS_AUTO(msg))
status = set_port_feature(hub->hdev, port1,
USB_PORT_FEAT_SUSPEND);
+ /*
+ * For system suspend, we do not need to enable the suspend feature
+ * on individual USB-2 ports. The devices will automatically go
+ * into suspend a few ms after the root hub stops sending packets.
+ * The USB 2.0 spec calls this "global suspend".
+ */
+ else {
+ really_suspend = false;
+ status = 0;
+ }
if (status) {
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
port1, status);
@@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
(PMSG_IS_AUTO(msg) ? "auto-" : ""),
udev->do_remote_wakeup);
usb_set_device_state(udev, USB_STATE_SUSPENDED);
- udev->port_is_suspended = 1;
- msleep(10);
+ if (really_suspend) {
+ udev->port_is_suspended = 1;
+ msleep(10);
+ }
}
/*
@@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_RUNTIME
+
/* caller has locked udev */
int usb_remote_wakeup(struct usb_device *udev)
{
@@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)
return status;
}
-#else /* CONFIG_USB_SUSPEND */
-
-/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
-
-int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
-{
- return 0;
-}
-
-/* However we may need to do a reset-resume */
-
-int usb_port_resume(struct usb_device *udev, pm_message_t msg)
-{
- struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
- int port1 = udev->portnum;
- int status;
- u16 portchange, portstatus;
-
- status = hub_port_status(hub, port1, &portstatus, &portchange);
- status = check_port_resume_type(udev,
- hub, port1, status, portchange, portstatus);
-
- if (status) {
- dev_dbg(&udev->dev, "can't resume, status %d\n", status);
- hub_port_logical_disconnect(hub, port1);
- } else if (udev->reset_resume) {
- dev_dbg(&udev->dev, "reset-resume\n");
- status = usb_reset_and_verify_device(udev);
- }
- return status;
-}
-
#endif
static int check_ports_changed(struct usb_hub *hub)
@@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
if (r) {
- dev_err(&udev->dev,
- "device descriptor read/64, error %d\n",
- r);
+ if (r != -ENODEV)
+ dev_err(&udev->dev, "device descriptor read/64, error %d\n",
+ r);
retval = -EMSGSIZE;
continue;
}
@@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
msleep(200);
}
if (retval < 0) {
- dev_err(&udev->dev,
- "device not accepting address %d, error %d\n",
- devnum, retval);
+ if (retval != -ENODEV)
+ dev_err(&udev->dev, "device not accepting address %d, error %d\n",
+ devnum, retval);
goto fail;
}
if (udev->speed == USB_SPEED_SUPER) {
@@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, 8);
if (retval < 8) {
- dev_err(&udev->dev,
+ if (retval != -ENODEV)
+ dev_err(&udev->dev,
"device descriptor read/8, error %d\n",
retval);
if (retval >= 0)
@@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(udev->descriptor)) {
- dev_err(&udev->dev, "device descriptor read/all, error %d\n",
- retval);
+ if (retval != -ENODEV)
+ dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+ retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
@@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
@@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce_be_stable(hub, port1);
if (status < 0) {
- if (printk_ratelimit())
+ if (status != -ENODEV && printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
@@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
else
unit_load = 100;
+ status = 0;
for (i = 0; i < SET_CONFIG_TRIES; i++) {
/* reallocate for each attempt, since references
@@ -4526,9 +4522,11 @@ loop:
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||
- !(hcd->driver->port_handed_over)(hcd, port1))
- dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
- port1);
+ !(hcd->driver->port_handed_over)(hcd, port1)) {
+ if (status != -ENOTCONN && status != -ENODEV)
+ dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
+ port1);
+ }
done:
hub_port_disable(hub, port1, 1);
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 797f9d514732..b8bad294eeb8 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -67,11 +67,10 @@ static void usb_port_device_release(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
- dev_pm_qos_hide_flags(dev);
kfree(port_dev);
}
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
static int usb_port_runtime_resume(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
@@ -139,7 +138,7 @@ static int usb_port_runtime_suspend(struct device *dev)
#endif
static const struct dev_pm_ops usb_port_pm_ops = {
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_port_runtime_suspend,
.runtime_resume = usb_port_runtime_resume,
.runtime_idle = pm_generic_runtime_idle,
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 3113c1d71442..ab5638d9c707 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
- /* For the present, all devices default to USB-PERSIST enabled */
-#if 0 /* was: #ifdef CONFIG_PM */
- /* Hubs are automatically enabled for USB-PERSIST */
- if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+#ifdef CONFIG_USB_DEFAULT_PERSIST
+ if (!(udev->quirks & USB_QUIRK_RESET))
udev->persist_enabled = 1;
-
#else
- /* In the absence of PM, we can safely enable USB-PERSIST
- * for all devices. It will affect things like hub resets
- * and EMF-related port disables.
- */
- if (!(udev->quirks & USB_QUIRK_RESET))
+ /* Hubs are automatically enabled for USB-PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
udev->persist_enabled = 1;
-#endif /* CONFIG_PM */
+#endif /* CONFIG_USB_DEFAULT_PERSIST */
}
void usb_detect_interface_quirks(struct usb_device *udev)
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 3f81a3dc6867..aa38db44818a 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)
#endif /* CONFIG_PM */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
static ssize_t
show_connected_duration(struct device *dev, struct device_attribute *attr,
@@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)
#define add_power_attributes(dev) 0
#define remove_power_attributes(dev) do {} while (0)
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
/* Descriptor fields */
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index e0d9d948218c..16927fa88fbd 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
void usb_poison_urb(struct urb *urb)
{
might_sleep();
- if (!(urb && urb->dev && urb->ep))
+ if (!urb)
return;
atomic_inc(&urb->reject);
+ if (!urb->dev || !urb->ep)
+ return;
+
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
}
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
index b6f4bad3f756..255c14464bf2 100644
--- a/drivers/usb/core/usb-acpi.c
+++ b/drivers/usb/core/usb-acpi.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
+#include <linux/usb/hcd.h>
#include <acpi/acpi_bus.h>
#include "usb.h"
@@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
* connected to.
*/
if (!udev->parent) {
- *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int raw_port_num;
+
+ raw_port_num = usb_hcd_find_raw_port_number(hcd,
port_num);
+ *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+ raw_port_num);
if (!*handle)
return -ENODEV;
} else {
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f81b92572735..b10da720f2b4 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";
static bool nousb; /* Disable USB when built into kernel image */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
@@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
.thaw = usb_dev_thaw,
.poweroff = usb_dev_poweroff,
.restore = usb_dev_restore,
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle,
@@ -317,7 +317,8 @@ static const struct dev_pm_ops usb_device_pm_ops = {
#endif /* CONFIG_PM */
-static char *usb_devnode(struct device *dev, umode_t *mode)
+static char *usb_devnode(struct device *dev,
+ umode_t *mode, kuid_t *uid, kgid_t *gid)
{
struct usb_device *usb_dev;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index a7f20bde0e5e..823857767a16 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
#endif
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
extern void usb_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 68e9a2c5a01a..ea5ee9c21c35 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,7 +1,6 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET) && GENERIC_HARDIRQS
- select USB_OTG_UTILS
select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index ffa6b004a84b..c35d49d39b76 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
* Returns a pointer to the allocated event buffer structure on success
* otherwise ERR_PTR(errno).
*/
-static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc,
+ unsigned length)
{
struct dwc3_event_buffer *evt;
@@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
}
}
+static void dwc3_core_num_eps(struct dwc3 *dwc)
+{
+ struct dwc3_hwparams *parms = &dwc->hwparams;
+
+ dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
+ dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
+
+ dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
+ dwc->num_in_eps, dwc->num_out_eps);
+}
+
static void dwc3_cache_hwparams(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
@@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
- dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ dwc3_core_num_eps(dwc);
- ret = dwc3_event_buffers_setup(dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to setup event buffers\n");
- goto err0;
- }
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
return 0;
@@ -351,8 +359,6 @@ err0:
static void dwc3_core_exit(struct dwc3 *dwc)
{
- dwc3_event_buffers_cleanup(dwc);
-
usb_phy_shutdown(dwc->usb2_phy);
usb_phy_shutdown(dwc->usb3_phy);
}
@@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);
}
- if (IS_ERR_OR_NULL(dwc->usb2_phy)) {
+ if (IS_ERR(dwc->usb2_phy)) {
+ ret = PTR_ERR(dwc->usb2_phy);
+
+ /*
+ * if -ENXIO is returned, it means PHY layer wasn't
+ * enabled, so it makes no sense to return -EPROBE_DEFER
+ * in that case, since no PHY driver will ever probe.
+ */
+ if (ret == -ENXIO)
+ return ret;
+
dev_err(dev, "no usb2 phy configured\n");
return -EPROBE_DEFER;
}
- if (IS_ERR_OR_NULL(dwc->usb3_phy)) {
+ if (IS_ERR(dwc->usb3_phy)) {
+ ret = PTR_ERR(dwc->usb2_phy);
+
+ /*
+ * if -ENXIO is returned, it means PHY layer wasn't
+ * enabled, so it makes no sense to return -EPROBE_DEFER
+ * in that case, since no PHY driver will ever probe.
+ */
+ if (ret == -ENXIO)
+ return ret;
+
dev_err(dev, "no usb3 phy configured\n");
return -EPROBE_DEFER;
}
@@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev)
dwc->regs_size = resource_size(res);
dwc->dev = dev;
+ dev->dma_mask = dev->parent->dma_mask;
+ dev->dma_parms = dev->parent->dma_parms;
+ dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
else if (!strncmp("high", maximum_speed, 4))
@@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev)
goto err0;
}
- mode = DWC3_MODE(dwc->hwparams.hwparams0);
+ ret = dwc3_event_buffers_setup(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to setup event buffers\n");
+ goto err1;
+ }
+
+ if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
+ mode = DWC3_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
+ mode = DWC3_MODE_DEVICE;
+ else
+ mode = DWC3_MODE_DRD;
switch (mode) {
case DWC3_MODE_DEVICE:
@@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
- goto err1;
+ goto err2;
}
break;
case DWC3_MODE_HOST:
@@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
- goto err1;
+ goto err2;
}
break;
case DWC3_MODE_DRD:
@@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
- goto err1;
+ goto err2;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
- goto err1;
+ goto err2;
}
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", mode);
- goto err1;
+ goto err2;
}
dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize debugfs\n");
- goto err2;
+ goto err3;
}
pm_runtime_allow(dev);
return 0;
-err2:
+err3:
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
@@ -546,6 +587,9 @@ err2:
break;
}
+err2:
+ dwc3_event_buffers_cleanup(dwc);
+
err1:
dwc3_core_exit(dwc);
@@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev)
break;
}
+ dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc);
dwc3_core_exit(dwc);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_prepare(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ switch (dwc->mode) {
+ case DWC3_MODE_DEVICE:
+ case DWC3_MODE_DRD:
+ dwc3_gadget_prepare(dwc);
+ /* FALLTHROUGH */
+ case DWC3_MODE_HOST:
+ default:
+ dwc3_event_buffers_cleanup(dwc);
+ break;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static void dwc3_complete(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ switch (dwc->mode) {
+ case DWC3_MODE_DEVICE:
+ case DWC3_MODE_DRD:
+ dwc3_gadget_complete(dwc);
+ /* FALLTHROUGH */
+ case DWC3_MODE_HOST:
+ default:
+ dwc3_event_buffers_setup(dwc);
+ break;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+}
+
+static int dwc3_suspend(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ switch (dwc->mode) {
+ case DWC3_MODE_DEVICE:
+ case DWC3_MODE_DRD:
+ dwc3_gadget_suspend(dwc);
+ /* FALLTHROUGH */
+ case DWC3_MODE_HOST:
+ default:
+ /* do nothing */
+ break;
+ }
+
+ dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ usb_phy_shutdown(dwc->usb3_phy);
+ usb_phy_shutdown(dwc->usb2_phy);
+
+ return 0;
+}
+
+static int dwc3_resume(struct device *dev)
+{
+ struct dwc3 *dwc = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ usb_phy_init(dwc->usb3_phy);
+ usb_phy_init(dwc->usb2_phy);
+ msleep(100);
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl);
+
+ switch (dwc->mode) {
+ case DWC3_MODE_DEVICE:
+ case DWC3_MODE_DRD:
+ dwc3_gadget_resume(dwc);
+ /* FALLTHROUGH */
+ case DWC3_MODE_HOST:
+ default:
+ /* do nothing */
+ break;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_dev_pm_ops = {
+ .prepare = dwc3_prepare,
+ .complete = dwc3_complete,
+
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
+};
+
+#define DWC3_PM_OPS &(dwc3_dev_pm_ops)
+#else
+#define DWC3_PM_OPS NULL
+#endif
+
#ifdef CONFIG_OF
static const struct of_device_id of_dwc3_match[] = {
{
@@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = {
.driver = {
.name = "dwc3",
.of_match_table = of_match_ptr(of_dwc3_match),
+ .pm = DWC3_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index b41750660235..b69d322e3cab 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -154,8 +154,9 @@
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
-#define DWC3_OEVTEN 0xcc08
-#define DWC3_OSTS 0xcc0C
+#define DWC3_OEVT 0xcc08
+#define DWC3_OEVTEN 0xcc0C
+#define DWC3_OSTS 0xcc10
/* Bit fields */
@@ -369,6 +370,9 @@ struct dwc3_trb;
* @list: a list of event buffers
* @buf: _THE_ buffer
* @length: size of this buffer
+ * @lpos: event offset
+ * @count: cache of last read event count register
+ * @flags: flags related to this event buffer
* @dma: dma_addr_t
* @dwc: pointer to DWC controller
*/
@@ -376,6 +380,10 @@ struct dwc3_event_buffer {
void *buf;
unsigned length;
unsigned int lpos;
+ unsigned int count;
+ unsigned int flags;
+
+#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma;
@@ -487,12 +495,6 @@ enum dwc3_link_state {
DWC3_LINK_STATE_MASK = 0x0f,
};
-enum dwc3_device_state {
- DWC3_DEFAULT_STATE,
- DWC3_ADDRESS_STATE,
- DWC3_CONFIGURED_STATE,
-};
-
/* TRB Length, PCM and Status */
#define DWC3_TRB_SIZE_MASK (0x00ffffff)
#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
@@ -574,6 +576,14 @@ struct dwc3_hwparams {
/* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
+/* HWPARAMS3 */
+#define DWC3_NUM_IN_EPS_MASK (0x1f << 18)
+#define DWC3_NUM_EPS_MASK (0x3f << 12)
+#define DWC3_NUM_EPS(p) (((p)->hwparams3 & \
+ (DWC3_NUM_EPS_MASK)) >> 12)
+#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \
+ (DWC3_NUM_IN_EPS_MASK)) >> 18)
+
/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
@@ -618,7 +628,6 @@ struct dwc3_scratchpad_array {
* @gadget_driver: pointer to the gadget driver
* @regs: base address for our registers
* @regs_size: address space size
- * @irq: IRQ number
* @num_event_buffers: calculated number of event buffers
* @u1u2: only used on revisions <1.83a for workaround
* @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -626,6 +635,8 @@ struct dwc3_scratchpad_array {
* @mode: mode of operation
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
+ * @dcfg: saved contents of DCFG register
+ * @gctl: saved contents of GCTL register
* @is_selfpowered: true when we are selfpowered
* @three_stage_setup: set if we perform a three phase setup
* @ep0_bounced: true when we used bounce buffer
@@ -639,6 +650,8 @@ struct dwc3_scratchpad_array {
* @u2pel: parameter from Set SEL request.
* @u1sel: parameter from Set SEL request.
* @u1pel: parameter from Set SEL request.
+ * @num_out_eps: number of out endpoints
+ * @num_in_eps: number of in endpoints
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@@ -656,8 +669,10 @@ struct dwc3 {
dma_addr_t ep0_trb_addr;
dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req;
+
/* device lock */
spinlock_t lock;
+
struct device *dev;
struct platform_device *xhci;
@@ -675,6 +690,10 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
+ /* used for suspend/resume */
+ u32 dcfg;
+ u32 gctl;
+
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -694,6 +713,9 @@ struct dwc3 {
#define DWC3_REVISION_202A 0x5533202a
#define DWC3_REVISION_210A 0x5533210a
#define DWC3_REVISION_220A 0x5533220a
+#define DWC3_REVISION_230A 0x5533230a
+#define DWC3_REVISION_240A 0x5533240a
+#define DWC3_REVISION_250A 0x5533250a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -704,11 +726,11 @@ struct dwc3 {
unsigned delayed_status:1;
unsigned needs_fifo_resize:1;
unsigned resize_fifos:1;
+ unsigned pullups_connected:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
enum dwc3_link_state link_state;
- enum dwc3_device_state dev_state;
u16 isoch_delay;
u16 u2sel;
@@ -718,6 +740,9 @@ struct dwc3 {
u8 speed;
+ u8 num_out_eps;
+ u8 num_in_eps;
+
void *mem;
struct dwc3_hwparams hwparams;
@@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ }
#endif
+/* power management interface */
+#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
+int dwc3_gadget_prepare(struct dwc3 *dwc);
+void dwc3_gadget_complete(struct dwc3 *dwc);
+int dwc3_gadget_suspend(struct dwc3 *dwc);
+int dwc3_gadget_resume(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+}
+
+static inline int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+ return 0;
+}
+
+static inline int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ return 0;
+}
+#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */
+
#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 4a752e730c5f..9e9f122162f2 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -59,7 +59,7 @@
.offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \
}
-static struct debugfs_reg32 dwc3_regs[] = {
+static const struct debugfs_reg32 dwc3_regs[] = {
dump_register(GSBUSCFG0),
dump_register(GSBUSCFG1),
dump_register(GTXTHRCFG),
@@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = {
dump_register(OCFG),
dump_register(OCTL),
+ dump_register(OEVT),
dump_register(OEVTEN),
dump_register(OSTS),
};
@@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
case DWC3_LINK_STATE_LPBK:
seq_printf(s, "Loopback\n");
break;
+ case DWC3_LINK_STATE_RESET:
+ seq_printf(s, "Reset\n");
+ break;
+ case DWC3_LINK_STATE_RESUME:
+ seq_printf(s, "Resume\n");
+ break;
default:
- seq_printf(s, "UNKNOWN %d\n", reg);
+ seq_printf(s, "UNKNOWN %d\n", state);
}
return 0;
@@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc)
goto err1;
}
-#if IS_ENABLED(CONFIG_USB_DWC3_GADGET)
- file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_mode_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
- }
-
- file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_testmode_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
+ if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
+ file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_mode_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
}
- file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
- dwc, &dwc3_link_state_fops);
- if (!file) {
- ret = -ENOMEM;
- goto err1;
+ if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) ||
+ IS_ENABLED(CONFIG_USB_DWC3_GADGET)) {
+ file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_testmode_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_link_state_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
}
-#endif
return 0;
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index b082bec7343e..a8afe6e26621 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -22,9 +22,9 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
struct dwc3_exynos {
- struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
struct device *dev;
@@ -86,21 +86,30 @@ err1:
return ret;
}
+static int dwc3_exynos_remove_child(struct device *dev, void *unused)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
+
+ return 0;
+}
+
static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
static int dwc3_exynos_probe(struct platform_device *pdev)
{
- struct platform_device *dwc3;
struct dwc3_exynos *exynos;
struct clk *clk;
struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
int ret = -ENOMEM;
exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);
if (!exynos) {
dev_err(dev, "not enough memory\n");
- return -ENOMEM;
+ goto err1;
}
/*
@@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now.
* Once we move to full device tree support this will vanish off.
*/
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &dwc3_exynos_dma_mask;
+ if (!dev->dma_mask)
+ dev->dma_mask = &dwc3_exynos_dma_mask;
platform_set_drvdata(pdev, exynos);
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
- return ret;
- }
-
- dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
- if (!dwc3) {
- dev_err(dev, "couldn't allocate dwc3 device\n");
- return -ENOMEM;
+ goto err1;
}
clk = devm_clk_get(dev, "usbdrd30");
@@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
goto err1;
}
- dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
-
- dwc3->dev.parent = dev;
- dwc3->dev.dma_mask = dev->dma_mask;
- dwc3->dev.dma_parms = dev->dma_parms;
- exynos->dwc3 = dwc3;
exynos->dev = dev;
exynos->clk = clk;
- clk_enable(exynos->clk);
-
- ret = platform_device_add_resources(dwc3, pdev->resource,
- pdev->num_resources);
- if (ret) {
- dev_err(dev, "couldn't add resources to dwc3 device\n");
- goto err2;
- }
-
- ret = platform_device_add(dwc3);
- if (ret) {
- dev_err(dev, "failed to register dwc3 device\n");
+ clk_prepare_enable(exynos->clk);
+
+ if (node) {
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "failed to add dwc3 core\n");
+ goto err2;
+ }
+ } else {
+ dev_err(dev, "no device node, failed to add dwc3 core\n");
+ ret = -ENODEV;
goto err2;
}
return 0;
err2:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
err1:
- platform_device_put(dwc3);
-
return ret;
}
@@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
- platform_device_unregister(exynos->dwc3);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
+ device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
- clk_disable(exynos->clk);
+ clk_disable_unprepare(exynos->clk);
return 0;
}
@@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = {
MODULE_DEVICE_TABLE(of, exynos_dwc3_match);
#endif
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_exynos_suspend(struct device *dev)
+{
+ struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+ clk_disable(exynos->clk);
+
+ return 0;
+}
+
+static int dwc3_exynos_resume(struct device *dev)
+{
+ struct dwc3_exynos *exynos = dev_get_drvdata(dev);
+
+ clk_enable(exynos->clk);
+
+ /* runtime set active to reflect active state. */
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver dwc3_exynos_driver = {
.probe = dwc3_exynos_probe,
.remove = dwc3_exynos_remove,
.driver = {
.name = "exynos-dwc3",
.of_match_table = of_match_ptr(exynos_dwc3_match),
+ .pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index afa05e3c9cf4..34638b92500d 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -52,7 +52,6 @@
#include <linux/of_platform.h>
#include <linux/usb/otg.h>
-#include <linux/usb/nop-usb-xceiv.h>
/*
* All these registers belong to OMAP's Wrapper around the
@@ -117,20 +116,17 @@ struct dwc3_omap {
/* device lock */
spinlock_t lock;
- struct platform_device *usb2_phy;
- struct platform_device *usb3_phy;
struct device *dev;
int irq;
void __iomem *base;
- void *context;
- u32 resource_size;
+ u32 utmi_otg_status;
u32 dma_status:1;
};
-struct dwc3_omap *_omap;
+static struct dwc3_omap *_omap;
static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
{
@@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
writel(value, base + offset);
}
-void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{
u32 val;
struct dwc3_omap *omap = _omap;
+ if (!omap)
+ return -EPROBE_DEFER;
+
switch (status) {
case OMAP_DWC3_ID_GROUND:
dev_dbg(omap->dev, "ID GND\n");
@@ -189,63 +188,9 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
dev_dbg(omap->dev, "ID float\n");
}
- return;
-}
-EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
-
-static int dwc3_omap_register_phys(struct dwc3_omap *omap)
-{
- struct nop_usb_xceiv_platform_data pdata;
- struct platform_device *pdev;
- int ret;
-
- memset(&pdata, 0x00, sizeof(pdata));
-
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
- if (!pdev)
- return -ENOMEM;
-
- omap->usb2_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB2;
-
- ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err1;
-
- pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO);
- if (!pdev) {
- ret = -ENOMEM;
- goto err1;
- }
-
- omap->usb3_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB3;
-
- ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err2;
-
- ret = platform_device_add(omap->usb2_phy);
- if (ret)
- goto err2;
-
- ret = platform_device_add(omap->usb3_phy);
- if (ret)
- goto err3;
-
return 0;
-
-err3:
- platform_device_del(omap->usb2_phy);
-
-err2:
- platform_device_put(omap->usb3_phy);
-
-err1:
- platform_device_put(omap->usb2_phy);
-
- return ret;
}
+EXPORT_SYMBOL_GPL(dwc3_omap_mailbox);
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
@@ -307,24 +252,57 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)
return 0;
}
+static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
+{
+ u32 reg;
+
+ /* enable all IRQs */
+ reg = USBOTGSS_IRQO_COREIRQ_ST;
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+ reg = (USBOTGSS_IRQ1_OEVT |
+ USBOTGSS_IRQ1_DRVVBUS_RISE |
+ USBOTGSS_IRQ1_CHRGVBUS_RISE |
+ USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+ USBOTGSS_IRQ1_IDPULLUP_RISE |
+ USBOTGSS_IRQ1_DRVVBUS_FALL |
+ USBOTGSS_IRQ1_CHRGVBUS_FALL |
+ USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+ USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+}
+
+static void dwc3_omap_disable_irqs(struct dwc3_omap *omap)
+{
+ /* disable all IRQs */
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00);
+}
+
+static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32);
+
static int dwc3_omap_probe(struct platform_device *pdev)
{
- struct dwc3_omap_data *pdata = pdev->dev.platform_data;
struct device_node *node = pdev->dev.of_node;
struct dwc3_omap *omap;
struct resource *res;
struct device *dev = &pdev->dev;
- int size;
int ret = -ENOMEM;
int irq;
- const u32 *utmi_mode;
+ int utmi_mode = 0;
+
u32 reg;
void __iomem *base;
- void *context;
+
+ if (!node) {
+ dev_err(dev, "device node not found\n");
+ return -EINVAL;
+ }
omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
@@ -334,13 +312,13 @@ static int dwc3_omap_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, omap);
- irq = platform_get_irq(pdev, 1);
+ irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "missing IRQ resource\n");
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "missing memory base resource\n");
return -EINVAL;
@@ -352,25 +330,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
return -ENOMEM;
}
- ret = dwc3_omap_register_phys(omap);
- if (ret) {
- dev_err(dev, "couldn't register PHYs\n");
- return ret;
- }
-
- context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
- if (!context) {
- dev_err(dev, "couldn't allocate dwc3 context memory\n");
- return -ENOMEM;
- }
-
spin_lock_init(&omap->lock);
- omap->resource_size = resource_size(res);
- omap->context = context;
omap->dev = dev;
omap->irq = irq;
omap->base = base;
+ dev->dma_mask = &dwc3_omap_dma_mask;
/*
* REVISIT if we ever have two instances of the wrapper, we will be
@@ -387,25 +352,17 @@ static int dwc3_omap_probe(struct platform_device *pdev)
reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
- utmi_mode = of_get_property(node, "utmi-mode", &size);
- if (utmi_mode && size == sizeof(*utmi_mode)) {
- reg |= *utmi_mode;
- } else {
- if (!pdata) {
- dev_dbg(dev, "missing platform data\n");
- } else {
- switch (pdata->utmi_mode) {
- case DWC3_OMAP_UTMI_MODE_SW:
- reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- case DWC3_OMAP_UTMI_MODE_HW:
- reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- default:
- dev_dbg(dev, "UNKNOWN utmi mode %d\n",
- pdata->utmi_mode);
- }
- }
+ of_property_read_u32(node, "utmi-mode", &utmi_mode);
+
+ switch (utmi_mode) {
+ case DWC3_OMAP_UTMI_MODE_SW:
+ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ case DWC3_OMAP_UTMI_MODE_HW:
+ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ default:
+ dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode);
}
dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
@@ -422,29 +379,12 @@ static int dwc3_omap_probe(struct platform_device *pdev)
return ret;
}
- /* enable all IRQs */
- reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_enable_irqs(omap);
- reg = (USBOTGSS_IRQ1_OEVT |
- USBOTGSS_IRQ1_DRVVBUS_RISE |
- USBOTGSS_IRQ1_CHRGVBUS_RISE |
- USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
- USBOTGSS_IRQ1_IDPULLUP_RISE |
- USBOTGSS_IRQ1_DRVVBUS_FALL |
- USBOTGSS_IRQ1_CHRGVBUS_FALL |
- USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
- USBOTGSS_IRQ1_IDPULLUP_FALL);
-
- dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
-
- if (node) {
- ret = of_platform_populate(node, NULL, NULL, dev);
- if (ret) {
- dev_err(&pdev->dev,
- "failed to add create dwc3 core\n");
- return ret;
- }
+ ret = of_platform_populate(node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create dwc3 core\n");
+ return ret;
}
return 0;
@@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
{
struct dwc3_omap *omap = platform_get_drvdata(pdev);
- platform_device_unregister(omap->usb2_phy);
- platform_device_unregister(omap->usb3_phy);
+ dwc3_omap_disable_irqs(omap);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
@@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev)
static const struct of_device_id of_dwc3_match[] = {
{
- "ti,dwc3",
+ .compatible = "ti,dwc3"
},
{ },
};
MODULE_DEVICE_TABLE(of, of_dwc3_match);
+#ifdef CONFIG_PM_SLEEP
+static int dwc3_omap_prepare(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_disable_irqs(omap);
+
+ return 0;
+}
+
+static void dwc3_omap_complete(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_enable_irqs(omap);
+}
+
+static int dwc3_omap_suspend(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ omap->utmi_otg_status = dwc3_omap_readl(omap->base,
+ USBOTGSS_UTMI_OTG_STATUS);
+
+ return 0;
+}
+
+static int dwc3_omap_resume(struct device *dev)
+{
+ struct dwc3_omap *omap = dev_get_drvdata(dev);
+
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS,
+ omap->utmi_otg_status);
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
+ .prepare = dwc3_omap_prepare,
+ .complete = dwc3_omap_complete,
+
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_omap_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver dwc3_omap_driver = {
.probe = dwc3_omap_probe,
.remove = dwc3_omap_remove,
.driver = {
.name = "omap-dwc3",
.of_match_table = of_dwc3_match,
+ .pm = DEV_PM_OPS,
},
};
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index e8d77689a322..227d4a7acad7 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+#ifdef CONFIG_PM
+static int dwc3_pci_suspend(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+
+ pci_disable_device(pci);
+
+ return 0;
+}
+
+static int dwc3_pci_resume(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+ int ret;
+
+ ret = pci_enable_device(pci);
+ if (ret) {
+ dev_err(dev, "can't re-enable device --> %d\n", ret);
+ return ret;
+ }
+
+ pci_set_master(pci);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
+};
+
+#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
+ .driver = {
+ .pm = DEV_PM_OPS,
+ },
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1d139ca05ef1..5acbb948b704 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 wIndex;
u32 reg;
int ret;
+ enum usb_device_state state;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
recip = ctrl->bRequestType & USB_RECIP_MASK;
+ state = dwc->gadget.state;
+
switch (recip) {
case USB_RECIP_DEVICE:
@@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
* default control pipe
*/
case USB_DEVICE_U1_ENABLE:
- if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
@@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
break;
case USB_DEVICE_U2_ENABLE:
- if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ if (state != USB_STATE_CONFIGURED)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
@@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
+ enum usb_device_state state = dwc->gadget.state;
u32 addr;
u32 reg;
@@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return -EINVAL;
}
- if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
+ if (state == USB_STATE_CONFIGURED) {
dev_dbg(dwc->dev, "trying to set address when configured\n");
return -EINVAL;
}
@@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
if (addr)
- dwc->dev_state = DWC3_ADDRESS_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS);
else
- dwc->dev_state = DWC3_DEFAULT_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
return 0;
}
@@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
+ enum usb_device_state state = dwc->gadget.state;
u32 cfg;
int ret;
u32 reg;
@@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dwc->start_config_issued = false;
cfg = le16_to_cpu(ctrl->wValue);
- switch (dwc->dev_state) {
- case DWC3_DEFAULT_STATE:
+ switch (state) {
+ case USB_STATE_DEFAULT:
return -EINVAL;
break;
- case DWC3_ADDRESS_STATE:
+ case USB_STATE_ADDRESS:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
- dwc->dev_state = DWC3_CONFIGURED_STATE;
+ usb_gadget_set_state(&dwc->gadget,
+ USB_STATE_CONFIGURED);
+
/*
* Enable transition to U1/U2 state when
* nothing is pending from application.
@@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
}
break;
- case DWC3_CONFIGURED_STATE:
+ case USB_STATE_CONFIGURED:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
if (!cfg)
- dwc->dev_state = DWC3_ADDRESS_STATE;
+ usb_gadget_set_state(&dwc->gadget,
+ USB_STATE_ADDRESS);
break;
default:
ret = -EINVAL;
@@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
struct dwc3_ep *dep;
+ enum usb_device_state state = dwc->gadget.state;
u16 wLength;
u16 wValue;
- if (dwc->dev_state == DWC3_DEFAULT_STATE)
+ if (state == USB_STATE_DEFAULT)
return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 82e160e96fca..2b6e7e001207 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
if (dwc->revision >= DWC3_REVISION_194A)
reg &= ~DWC3_DCTL_KEEP_CONNECT;
reg |= DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = true;
} else {
reg &= ~DWC3_DCTL_RUN_STOP;
+ dwc->pullups_connected = false;
}
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
return ret;
}
+static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+}
+
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
+{
+ /* mask all interrupts */
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc);
+
static int dwc3_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
@@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g,
struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
+ int irq;
u32 reg;
spin_lock_irqsave(&dwc->lock, flags);
@@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g,
}
dwc->gadget_driver = driver;
- dwc->gadget.dev.driver = &driver->driver;
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g,
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err1;
+ }
+
+ dwc3_gadget_enable_irq(dwc);
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
{
struct dwc3 *dwc = gadget_to_dwc(g);
unsigned long flags;
+ int irq;
spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_disable_irq(dwc);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ free_irq(irq, dwc);
+
__dwc3_gadget_ep_disable(dwc->eps[0]);
__dwc3_gadget_ep_disable(dwc->eps[1]);
dwc->gadget_driver = NULL;
- dwc->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
/* -------------------------------------------------------------------------- */
-static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
+ u8 num, u32 direction)
{
struct dwc3_ep *dep;
- u8 epnum;
+ u8 i;
- INIT_LIST_HEAD(&dwc->gadget.ep_list);
+ for (i = 0; i < num; i++) {
+ u8 epnum = (i << 1) | (!!direction);
- for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
if (!dep) {
dev_err(dwc->dev, "can't allocate endpoint %d\n",
@@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
(epnum & 1) ? "in" : "out");
+
dep->endpoint.name = dep->name;
dep->direction = (epnum & 1);
@@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
return 0;
}
+static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+ int ret;
+
+ INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+ ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
+ if (ret < 0) {
+ dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+ return ret;
+ }
+
+ ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
+ if (ret < 0) {
+ dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
@@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
+
dwc3_free_trb_pool(dep);
if (epnum != 0 && epnum != 1)
@@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
}
}
-static void dwc3_gadget_release(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-}
-
/* -------------------------------------------------------------------------- */
+
static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
struct dwc3_request *req, struct dwc3_trb *trb,
const struct dwc3_event_depevt *event, int status)
@@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
struct dwc3_ep *dep;
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
+
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
@@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
int ret;
dep = dwc->eps[epnum];
+ if (!dep)
+ continue;
if (!(dep->flags & DWC3_EP_STALL))
continue;
@@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
}
/* after reset -> Default State */
- dwc->dev_state = DWC3_DEFAULT_STATE;
+ usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT);
/* Recent versions support automatic phy suspend and don't need this */
if (dwc->revision < DWC3_REVISION_194A) {
@@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
unsigned int evtinfo)
{
enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK;
+ unsigned int pwropt;
+
+ /*
+ * WORKAROUND: DWC3 < 2.50a have an issue when configured without
+ * Hibernation mode enabled which would show up when device detects
+ * host-initiated U3 exit.
+ *
+ * In that case, device will generate a Link State Change Interrupt
+ * from U3 to RESUME which is only necessary if Hibernation is
+ * configured in.
+ *
+ * There are no functional changes due to such spurious event and we
+ * just need to ignore it.
+ *
+ * Refers to:
+ *
+ * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation
+ * operational mode
+ */
+ pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
+ if ((dwc->revision < DWC3_REVISION_250A) &&
+ (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
+ if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
+ (next == DWC3_LINK_STATE_RESUME)) {
+ dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+ return;
+ }
+ }
/*
* WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
@@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc,
}
}
+static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ int i;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ for (i = 0; i < dwc->num_event_buffers; i++) {
+ struct dwc3_event_buffer *evt;
+ int left;
+
+ evt = dwc->ev_buffs[i];
+ left = evt->count;
+
+ if (!(evt->flags & DWC3_EVENT_PENDING))
+ continue;
+
+ while (left > 0) {
+ union dwc3_event event;
+
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
+
+ dwc3_process_event_entry(dwc, &event);
+
+ /*
+ * FIXME we wrap around correctly to the next entry as
+ * almost all entries are 4 bytes in size. There is one
+ * entry which has 12 bytes which is a regular entry
+ * followed by 8 bytes data. ATM I don't know how
+ * things are organized if we get next to the a
+ * boundary so I worry about that once we try to handle
+ * that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4);
+ }
+
+ evt->count = 0;
+ evt->flags &= ~DWC3_EVENT_PENDING;
+ ret = IRQ_HANDLED;
+ }
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
{
struct dwc3_event_buffer *evt;
- int left;
u32 count;
+ evt = dwc->ev_buffs[buf];
+
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
- evt = dwc->ev_buffs[buf];
- left = count;
-
- while (left > 0) {
- union dwc3_event event;
-
- event.raw = *(u32 *) (evt->buf + evt->lpos);
+ evt->count = count;
+ evt->flags |= DWC3_EVENT_PENDING;
- dwc3_process_event_entry(dwc, &event);
- /*
- * XXX we wrap around correctly to the next entry as almost all
- * entries are 4 bytes in size. There is one entry which has 12
- * bytes which is a regular entry followed by 8 bytes data. ATM
- * I don't know how things are organized if were get next to the
- * a boundary so I worry about that once we try to handle that.
- */
- evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
- left -= 4;
-
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
- }
-
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
@@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
irqreturn_t status;
status = dwc3_process_event_buf(dwc, i);
- if (status == IRQ_HANDLED)
+ if (status == IRQ_WAKE_THREAD)
ret = status;
}
@@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc)
{
u32 reg;
int ret;
- int irq;
dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
&dwc->ctrl_req_addr, GFP_KERNEL);
@@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc)
goto err3;
}
- dev_set_name(&dwc->gadget.dev, "gadget");
-
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
- dwc->gadget.dev.parent = dwc->dev;
dwc->gadget.sg_supported = true;
-
- dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
-
- dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
- dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
- dwc->gadget.dev.release = dwc3_gadget_release;
dwc->gadget.name = "dwc3-gadget";
/*
@@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc)
if (ret)
goto err4;
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
- ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
- "dwc3", dwc);
- if (ret) {
- dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
- irq, ret);
- goto err5;
- }
-
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
- /* Enable all but Start and End of Frame IRQs */
- reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
- DWC3_DEVTEN_EVNTOVERFLOWEN |
- DWC3_DEVTEN_CMDCMPLTEN |
- DWC3_DEVTEN_ERRTICERREN |
- DWC3_DEVTEN_WKUPEVTEN |
- DWC3_DEVTEN_ULSTCNGEN |
- DWC3_DEVTEN_CONNECTDONEEN |
- DWC3_DEVTEN_USBRSTEN |
- DWC3_DEVTEN_DISCONNEVTEN);
- dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
-
- /* automatic phy suspend only on recent versions */
+ /* Enable USB2 LPM and automatic phy suspend only on recent versions */
if (dwc->revision >= DWC3_REVISION_194A) {
dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_gadget_usb3_phy_suspend(dwc, false);
}
- ret = device_register(&dwc->gadget.dev);
- if (ret) {
- dev_err(dwc->dev, "failed to register gadget device\n");
- put_device(&dwc->gadget.dev);
- goto err6;
- }
-
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
if (ret) {
dev_err(dwc->dev, "failed to register udc\n");
- goto err7;
+ goto err5;
}
return 0;
-err7:
- device_unregister(&dwc->gadget.dev);
-
-err6:
- dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
- free_irq(irq, dwc);
-
err5:
dwc3_gadget_free_endpoints(dwc);
@@ -2588,15 +2674,11 @@ err0:
return ret;
}
+/* -------------------------------------------------------------------------- */
+
void dwc3_gadget_exit(struct dwc3 *dwc)
{
- int irq;
-
usb_del_gadget_udc(&dwc->gadget);
- irq = platform_get_irq(to_platform_device(dwc->dev), 0);
-
- dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
- free_irq(irq, dwc);
dwc3_gadget_free_endpoints(dwc);
@@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
dwc->ctrl_req, dwc->ctrl_req_addr);
+}
- device_unregister(&dwc->gadget.dev);
+int dwc3_gadget_prepare(struct dwc3 *dwc)
+{
+ if (dwc->pullups_connected)
+ dwc3_gadget_disable_irq(dwc);
+
+ return 0;
+}
+
+void dwc3_gadget_complete(struct dwc3 *dwc)
+{
+ if (dwc->pullups_connected) {
+ dwc3_gadget_enable_irq(dwc);
+ dwc3_gadget_run_stop(dwc, true);
+ }
+}
+
+int dwc3_gadget_suspend(struct dwc3 *dwc)
+{
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+ dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG);
+
+ return 0;
+}
+
+int dwc3_gadget_resume(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ int ret;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret)
+ goto err0;
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false);
+ if (ret)
+ goto err1;
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg);
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ return ret;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 5a0c541daf89..83300d94a893 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -144,7 +144,9 @@ config USB_AT91
config USB_LPC32XX
tristate "LPC32XX USB Peripheral Controller"
depends on ARCH_LPC32XX
+ depends on USB_PHY
select USB_ISP1301
+ select USB_OTG_UTILS
help
This option selects the USB device controller in the LPC32xx SoC.
@@ -194,8 +196,8 @@ config USB_FUSB300
config USB_OMAP
tristate "OMAP USB Device Controller"
depends on ARCH_OMAP1
+ depends on USB_PHY
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
- select USB_OTG_UTILS if ARCH_OMAP
help
Many Texas Instruments OMAP processors have flexible full
speed USB device controllers, with support for up to 30
@@ -210,7 +212,6 @@ config USB_OMAP
config USB_PXA25X
tristate "PXA 25x or IXP 4xx"
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
- select USB_OTG_UTILS
help
Intel's PXA 25x series XScale ARM-5TE processors include
an integrated full speed USB 1.1 device controller. The
@@ -258,8 +259,6 @@ config USB_RENESAS_USBHS_UDC
config USB_PXA27X
tristate "PXA 27x"
- depends on ARCH_PXA && (PXA27x || PXA3xx)
- select USB_OTG_UTILS
help
Intel's PXA 27x series XScale ARM v5TE processors include
an integrated full speed USB 1.1 device controller.
@@ -328,9 +327,6 @@ config USB_MV_UDC
config USB_MV_U3D
tristate "MARVELL PXA2128 USB 3.0 controller"
- depends on CPU_MMP3
- select USB_GADGET_DUALSPEED
- select USB_GADGET_SUPERSPEED
help
MARVELL PXA2128 Processor series include a super speed USB3.0 device
controller, which support super speed USB peripheral.
@@ -500,6 +496,7 @@ endmenu
# composite based drivers
config USB_LIBCOMPOSITE
tristate
+ select CONFIGFS_FS
depends on USB_GADGET
config USB_F_ACM
@@ -511,6 +508,12 @@ config USB_F_SS_LB
config USB_U_SERIAL
tristate
+config USB_F_SERIAL
+ tristate
+
+config USB_F_OBEX
+ tristate
+
choice
tristate "USB Gadget Drivers"
default USB_ETH
@@ -765,6 +768,8 @@ config USB_G_SERIAL
depends on TTY
select USB_U_SERIAL
select USB_F_ACM
+ select USB_F_SERIAL
+ select USB_F_OBEX
select USB_LIBCOMPOSITE
help
The Serial Gadget talks to the Linux-USB generic serial driver.
@@ -838,6 +843,7 @@ config USB_G_NOKIA
depends on PHONET
select USB_LIBCOMPOSITE
select USB_U_SERIAL
+ select USB_F_ACM
help
The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver.
@@ -956,6 +962,7 @@ config USB_G_WEBCAM
tristate "USB Webcam Gadget"
depends on VIDEO_DEV
select USB_LIBCOMPOSITE
+ select VIDEOBUF2_VMALLOC
help
The Webcam Gadget acts as a composite USB Audio and Video Class
device. It provides a userspace API to process UVC control requests
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 82fb22511356..6afd16659e78 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
libcomposite-y := usbstring.o config.o epautoconf.o
-libcomposite-y += composite.o functions.o
+libcomposite-y += composite.o functions.o configfs.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o
@@ -36,10 +36,15 @@ obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o
# USB Functions
-obj-$(CONFIG_USB_F_ACM) += f_acm.o
-f_ss_lb-y := f_loopback.o f_sourcesink.o
-obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o
+usb_f_acm-y := f_acm.o
+obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o
+usb_f_ss_lb-y := f_loopback.o f_sourcesink.o
+obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o
obj-$(CONFIG_USB_U_SERIAL) += u_serial.o
+usb_f_serial-y := f_serial.o
+obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o
+usb_f_obex-y := f_obex.o
+obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
index 8f2b0e391534..4b947bb50f62 100644
--- a/drivers/usb/gadget/acm_ms.c
+++ b/drivers/usb/gadget/acm_ms.c
@@ -109,7 +109,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common fsg_common;
/*-------------------------------------------------------------------------*/
-static unsigned char tty_line;
static struct usb_function *f_acm;
static struct usb_function_instance *f_acm_inst;
/*
@@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst;
*/
static int __init acm_ms_do_config(struct usb_configuration *c)
{
- struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c)
if (IS_ERR(f_acm_inst))
return PTR_ERR(f_acm_inst);
- opts = container_of(f_acm_inst, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
f_acm = usb_get_function(f_acm_inst);
if (IS_ERR(f_acm)) {
status = PTR_ERR(f_acm);
@@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
int status;
void *retp;
- /* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- return status;
-
/* set up mass storage function */
retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
if (IS_ERR(retp)) {
status = PTR_ERR(retp);
- goto fail0;
+ return PTR_ERR(retp);
}
/*
@@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev)
/* error recovery */
fail1:
fsg_common_put(&fsg_common);
-fail0:
- gserial_free_line(tty_line);
return status;
}
@@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
{
usb_put_function(f_acm);
usb_put_function_instance(f_acm_inst);
- gserial_free_line(tty_line);
return 0;
}
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 75973f33a4c8..f52dcfe8f545 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* Some gadget drivers use both ep0 directions.
* NOTE: to gadget driver, ep0 is just one endpoint...
@@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g,
shutdown(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
/* set SD */
@@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev)
if (dev->active)
pci_disable_device(pdev);
- device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL);
udc_remove(dev);
@@ -3245,8 +3242,6 @@ static int udc_pci_probe(
dev->phys_addr = resource;
dev->irq = pdev->irq;
dev->pdev = pdev;
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
/* general probing */
if (udc_probe(dev) == 0)
@@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev)
dev->gadget.ops = &udc_ops;
dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = name;
dev->gadget.max_speed = USB_SPEED_HIGH;
@@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev)
"driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev;
- retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto finished;
- retval = device_register(&dev->gadget.dev);
- if (retval) {
- usb_del_gadget_udc(&dev->gadget);
- put_device(&dev->gadget.dev);
- goto finished;
- }
-
/* timer init */
init_timer(&udc_timer);
udc_timer.function = udc_timer_function;
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index f1bf32e6b8d8..6744d3b83109 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -472,7 +472,6 @@ struct udc_request {
/* flags */
unsigned dma_going : 1,
- dma_mapping : 1,
dma_done : 1;
/* phys. address */
dma_addr_t td_phys;
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 88966e0508a5..073b938f9135 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget,
udc = container_of(gadget, struct at91_udc, gadget);
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1;
udc->selfpowered = 1;
@@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget,
at91_udp_write(udc, AT91_UDP_IDR, ~0);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
DBG("unbound from %s\n", driver->driver.name);
@@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev)
DBG("clocks missing\n");
retval = -ENODEV;
/* NOTE: we "know" here that refcounts on these are NOPs */
- goto fail0b;
- }
-
- retval = device_register(&udc->gadget.dev);
- if (retval < 0) {
- put_device(&udc->gadget.dev);
- goto fail0b;
+ goto fail1;
}
/* don't do anything until we have both gadget driver and VBUS */
@@ -1857,8 +1849,6 @@ fail3:
fail2:
free_irq(udc->udp_irq, udc);
fail1:
- device_unregister(&udc->gadget.dev);
-fail0b:
iounmap(udc->udp_baseaddr);
fail0a:
if (cpu_is_at91rm9200())
@@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev)
gpio_free(udc->board.vbus_pin);
}
free_irq(udc->udp_irq, udc);
- device_unregister(&udc->gadget.dev);
-
iounmap(udc->udp_baseaddr);
if (cpu_is_at91rm9200())
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index b66130c97269..f2a970f75bfa 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status)
if (req->req.status == -EINPROGRESS)
req->req.status = status;
- if (req->mapped) {
- dma_unmap_single(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ if (req->using_dma)
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
DBG(DBG_GADGET | DBG_REQ,
"%s: req %p complete: status %d, actual %u\n",
@@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
return NULL;
INIT_LIST_HEAD(&req->queue);
- req->req.dma = DMA_ADDR_INVALID;
return &req->req;
}
@@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
return -EINVAL;
}
- req->using_dma = 1;
-
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(
- &udc->pdev->dev, req->req.buf, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(
- &udc->pdev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in);
+ if (ret)
+ return ret;
+ req->using_dma = 1;
req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
@@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget,
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
clk_enable(udc->pclk);
@@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget,
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
clk_disable(udc->hclk);
@@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
(unsigned long)fifo->start, udc->fifo);
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
platform_set_drvdata(pdev, udc);
/* Make sure we start from a clean slate */
@@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev)
}
udc->irq = irq;
- ret = device_add(&udc->gadget.dev);
- if (ret) {
- dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
- goto err_device_add;
- }
-
if (gpio_is_valid(pdata->vbus_pin)) {
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin;
@@ -2007,9 +1980,6 @@ err_add_udc:
gpio_free(udc->vbus_pin);
}
- device_unregister(&udc->gadget.dev);
-
-err_device_add:
free_irq(irq, udc);
err_request_irq:
kfree(usba_ep);
@@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
clk_put(udc->hclk);
clk_put(udc->pclk);
- device_unregister(&udc->gadget.dev);
-
return 0;
}
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 9791259cbda7..d65a61851d3d 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -216,12 +216,6 @@
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
#define EP0_NR_BANKS 1
-/*
- * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
- * provide this information?
- */
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
#define FIFO_IOMEM_ID 0
#define CTRL_IOMEM_ID 1
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index 8cc8253f1100..6e6518264c42 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget,
udc->driver = driver;
driver->driver.bus = NULL;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&udc->lock, flags);
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
/*
* If we switch the PHY too abruptly after dropping D+, the host
@@ -2306,17 +2304,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc)
***********************************************************************/
/**
- * bcm63xx_udc_gadget_release - Called from device_release().
- * @dev: Unused.
- *
- * We get a warning if this function doesn't exist, but it's empty because
- * we don't have to free any of the memory allocated with the devm_* APIs.
- */
-static void bcm63xx_udc_gadget_release(struct device *dev)
-{
-}
-
-/**
* bcm63xx_udc_probe - Initialize a new instance of the UDC.
* @pdev: Platform device struct from the bcm63xx BSP code.
*
@@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
spin_lock_init(&udc->lock);
INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process);
- dev_set_name(&udc->gadget.dev, "gadget");
udc->gadget.ops = &bcm63xx_udc_ops;
udc->gadget.name = dev_name(dev);
- udc->gadget.dev.parent = dev;
- udc->gadget.dev.release = bcm63xx_udc_gadget_release;
- udc->gadget.dev.dma_mask = dev->dma_mask;
if (!pd->use_fullspeed && !use_fullspeed)
udc->gadget.max_speed = USB_SPEED_HIGH;
@@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
}
}
- rc = device_register(&udc->gadget.dev);
- if (rc)
- goto out_uninit;
-
bcm63xx_udc_init_debugfs(udc);
rc = usb_add_gadget_udc(dev, &udc->gadget);
if (!rc)
return 0;
bcm63xx_udc_cleanup_debugfs(udc);
- device_unregister(&udc->gadget.dev);
out_uninit:
bcm63xx_uninit_udc_hw(udc);
return rc;
@@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
bcm63xx_udc_cleanup_debugfs(udc);
usb_del_gadget_udc(&udc->gadget);
- device_unregister(&udc->gadget.dev);
BUG_ON(udc->driver);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index a7d6f7026757..2c5255182769 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = {
};
static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/
static struct usb_function *f_acm;
static struct usb_function_instance *fi_serial;
-static unsigned char tty_line;
/*
* We _always_ have both CDC ECM and CDC ACM functions.
*/
static int __init cdc_do_config(struct usb_configuration *c)
{
- struct f_serial_opts *opts;
int status;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- status = ecm_bind_config(c, hostaddr);
+ status = ecm_bind_config(c, hostaddr, the_dev);
if (status < 0)
return status;
@@ -130,12 +128,11 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (IS_ERR(fi_serial))
return PTR_ERR(fi_serial);
- opts = container_of(fi_serial, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
f_acm = usb_get_function(fi_serial);
- if (IS_ERR(f_acm))
+ if (IS_ERR(f_acm)) {
+ status = PTR_ERR(f_acm);
goto err_func_acm;
+ }
status = usb_add_function(c, f_acm);
if (status)
@@ -169,14 +166,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
}
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
-
- /* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- goto fail0;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -200,9 +192,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev)
return 0;
fail1:
- gserial_free_line(tty_line);
-fail0:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
@@ -210,8 +200,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev)
{
usb_put_function(f_acm);
usb_put_function_instance(fi_serial);
- gserial_free_line(tty_line);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index c0d62b278610..55f4df60f327 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
kfree(cdev->req->buf);
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
}
+ cdev->next_string_id = 0;
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
}
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
new file mode 100644
index 000000000000..3d5cfc9c2c78
--- /dev/null
+++ b/drivers/usb/gadget/configfs.c
@@ -0,0 +1,1003 @@
+#include <linux/configfs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget_configfs.h>
+
+int check_user_usb_string(const char *name,
+ struct usb_gadget_strings *stringtab_dev)
+{
+ unsigned primary_lang;
+ unsigned sub_lang;
+ u16 num;
+ int ret;
+
+ ret = kstrtou16(name, 0, &num);
+ if (ret)
+ return ret;
+
+ primary_lang = num & 0x3ff;
+ sub_lang = num >> 10;
+
+ /* simple sanity check for valid langid */
+ switch (primary_lang) {
+ case 0:
+ case 0x62 ... 0xfe:
+ case 0x100 ... 0x3ff:
+ return -EINVAL;
+ }
+ if (!sub_lang)
+ return -EINVAL;
+
+ stringtab_dev->language = num;
+ return 0;
+}
+
+#define MAX_NAME_LEN 40
+#define MAX_USB_STRING_LANGS 2
+
+struct gadget_info {
+ struct config_group group;
+ struct config_group functions_group;
+ struct config_group configs_group;
+ struct config_group strings_group;
+ struct config_group *default_groups[4];
+
+ struct mutex lock;
+ struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+ struct list_head string_list;
+ struct list_head available_func;
+
+ const char *udc_name;
+#ifdef CONFIG_USB_OTG
+ struct usb_otg_descriptor otg;
+#endif
+ struct usb_composite_driver composite;
+ struct usb_composite_dev cdev;
+};
+
+struct config_usb_cfg {
+ struct config_group group;
+ struct config_group strings_group;
+ struct config_group *default_groups[2];
+ struct list_head string_list;
+ struct usb_configuration c;
+ struct list_head func_list;
+ struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
+};
+
+struct gadget_strings {
+ struct usb_gadget_strings stringtab_dev;
+ struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
+ char *manufacturer;
+ char *product;
+ char *serialnumber;
+
+ struct config_group group;
+ struct list_head list;
+};
+
+struct gadget_config_name {
+ struct usb_gadget_strings stringtab_dev;
+ struct usb_string strings;
+ char *configuration;
+
+ struct config_group group;
+ struct list_head list;
+};
+
+static int usb_string_copy(const char *s, char **s_copy)
+{
+ int ret;
+ char *str;
+ char *copy = *s_copy;
+ ret = strlen(s);
+ if (ret > 126)
+ return -EOVERFLOW;
+
+ str = kstrdup(s, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+ if (str[ret - 1] == '\n')
+ str[ret - 1] = '\0';
+ kfree(copy);
+ *s_copy = str;
+ return 0;
+}
+
+CONFIGFS_ATTR_STRUCT(gadget_info);
+CONFIGFS_ATTR_STRUCT(config_usb_cfg);
+
+#define GI_DEVICE_DESC_ITEM_ATTR(name) \
+ static struct gadget_info_attribute gadget_cdev_desc_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
+ gadget_dev_desc_##name##_show, \
+ gadget_dev_desc_##name##_store)
+
+#define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \
+ static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+ char *page) \
+{ \
+ return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \
+ static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+ char *page) \
+{ \
+ return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \
+}
+
+
+#define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \
+ static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+ const char *page, size_t len) \
+{ \
+ u8 val; \
+ int ret; \
+ ret = kstrtou8(page, 0, &val); \
+ if (ret) \
+ return ret; \
+ gi->cdev.desc._name = val; \
+ return len; \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \
+ static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+ const char *page, size_t len) \
+{ \
+ u16 val; \
+ int ret; \
+ ret = kstrtou16(page, 0, &val); \
+ if (ret) \
+ return ret; \
+ gi->cdev.desc._name = cpu_to_le16p(&val); \
+ return len; \
+}
+
+#define GI_DEVICE_DESC_SIMPLE_RW(_name, _type) \
+ GI_DEVICE_DESC_SIMPLE_R_##_type(_name) \
+ GI_DEVICE_DESC_SIMPLE_W_##_type(_name)
+
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8);
+GI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8);
+GI_DEVICE_DESC_SIMPLE_RW(idVendor, u16);
+GI_DEVICE_DESC_SIMPLE_RW(idProduct, u16);
+GI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice);
+
+static ssize_t is_valid_bcd(u16 bcd_val)
+{
+ if ((bcd_val & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 4) & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 8) & 0xf) > 9)
+ return -EINVAL;
+ if (((bcd_val >> 12) & 0xf) > 9)
+ return -EINVAL;
+ return 0;
+}
+
+static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ u16 bcdDevice;
+ int ret;
+
+ ret = kstrtou16(page, 0, &bcdDevice);
+ if (ret)
+ return ret;
+ ret = is_valid_bcd(bcdDevice);
+ if (ret)
+ return ret;
+
+ gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
+ return len;
+}
+
+static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ u16 bcdUSB;
+ int ret;
+
+ ret = kstrtou16(page, 0, &bcdUSB);
+ if (ret)
+ return ret;
+ ret = is_valid_bcd(bcdUSB);
+ if (ret)
+ return ret;
+
+ gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
+ return len;
+}
+
+static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page)
+{
+ return sprintf(page, "%s\n", gi->udc_name ?: "");
+}
+
+static int unregister_gadget(struct gadget_info *gi)
+{
+ int ret;
+
+ if (!gi->udc_name)
+ return -ENODEV;
+
+ ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver);
+ if (ret)
+ return ret;
+ kfree(gi->udc_name);
+ gi->udc_name = NULL;
+ return 0;
+}
+
+static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
+ const char *page, size_t len)
+{
+ char *name;
+ int ret;
+
+ name = kstrdup(page, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ if (name[len - 1] == '\n')
+ name[len - 1] = '\0';
+
+ mutex_lock(&gi->lock);
+
+ if (!strlen(name)) {
+ ret = unregister_gadget(gi);
+ if (ret)
+ goto err;
+ } else {
+ if (gi->udc_name) {
+ ret = -EBUSY;
+ goto err;
+ }
+ ret = udc_attach_driver(name, &gi->composite.gadget_driver);
+ if (ret)
+ goto err;
+ gi->udc_name = name;
+ }
+ mutex_unlock(&gi->lock);
+ return len;
+err:
+ kfree(name);
+ mutex_unlock(&gi->lock);
+ return ret;
+}
+
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass);
+GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol);
+GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0);
+GI_DEVICE_DESC_ITEM_ATTR(idVendor);
+GI_DEVICE_DESC_ITEM_ATTR(idProduct);
+GI_DEVICE_DESC_ITEM_ATTR(bcdDevice);
+GI_DEVICE_DESC_ITEM_ATTR(bcdUSB);
+GI_DEVICE_DESC_ITEM_ATTR(UDC);
+
+static struct configfs_attribute *gadget_root_attrs[] = {
+ &gadget_cdev_desc_bDeviceClass.attr,
+ &gadget_cdev_desc_bDeviceSubClass.attr,
+ &gadget_cdev_desc_bDeviceProtocol.attr,
+ &gadget_cdev_desc_bMaxPacketSize0.attr,
+ &gadget_cdev_desc_idVendor.attr,
+ &gadget_cdev_desc_idProduct.attr,
+ &gadget_cdev_desc_bcdDevice.attr,
+ &gadget_cdev_desc_bcdUSB.attr,
+ &gadget_cdev_desc_UDC.attr,
+ NULL,
+};
+
+static inline struct gadget_info *to_gadget_info(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_info, group);
+}
+
+static inline struct gadget_strings *to_gadget_strings(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_strings,
+ group);
+}
+
+static inline struct gadget_config_name *to_gadget_config_name(
+ struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_config_name,
+ group);
+}
+
+static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct config_usb_cfg,
+ group);
+}
+
+static inline struct usb_function_instance *to_usb_function_instance(
+ struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct usb_function_instance, group);
+}
+
+static void gadget_info_attr_release(struct config_item *item)
+{
+ struct gadget_info *gi = to_gadget_info(item);
+
+ WARN_ON(!list_empty(&gi->cdev.configs));
+ WARN_ON(!list_empty(&gi->string_list));
+ WARN_ON(!list_empty(&gi->available_func));
+ kfree(gi->composite.gadget_driver.function);
+ kfree(gi);
+}
+
+CONFIGFS_ATTR_OPS(gadget_info);
+
+static struct configfs_item_operations gadget_root_item_ops = {
+ .release = gadget_info_attr_release,
+ .show_attribute = gadget_info_attr_show,
+ .store_attribute = gadget_info_attr_store,
+};
+
+static void gadget_config_attr_release(struct config_item *item)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(item);
+
+ WARN_ON(!list_empty(&cfg->c.functions));
+ list_del(&cfg->c.list);
+ kfree(cfg->c.label);
+ kfree(cfg);
+}
+
+static int config_usb_cfg_link(
+ struct config_item *usb_cfg_ci,
+ struct config_item *usb_func_ci)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+ struct usb_composite_dev *cdev = cfg->c.cdev;
+ struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+ struct config_group *group = to_config_group(usb_func_ci);
+ struct usb_function_instance *fi = container_of(group,
+ struct usb_function_instance, group);
+ struct usb_function_instance *a_fi;
+ struct usb_function *f;
+ int ret;
+
+ mutex_lock(&gi->lock);
+ /*
+ * Make sure this function is from within our _this_ gadget and not
+ * from another gadget or a random directory.
+ * Also a function instance can only be linked once.
+ */
+ list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
+ if (a_fi == fi)
+ break;
+ }
+ if (a_fi != fi) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ list_for_each_entry(f, &cfg->func_list, list) {
+ if (f->fi == fi) {
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ f = usb_get_function(fi);
+ if (IS_ERR(f)) {
+ ret = PTR_ERR(f);
+ goto out;
+ }
+
+ /* stash the function until we bind it to the gadget */
+ list_add_tail(&f->list, &cfg->func_list);
+ ret = 0;
+out:
+ mutex_unlock(&gi->lock);
+ return ret;
+}
+
+static int config_usb_cfg_unlink(
+ struct config_item *usb_cfg_ci,
+ struct config_item *usb_func_ci)
+{
+ struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
+ struct usb_composite_dev *cdev = cfg->c.cdev;
+ struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
+
+ struct config_group *group = to_config_group(usb_func_ci);
+ struct usb_function_instance *fi = container_of(group,
+ struct usb_function_instance, group);
+ struct usb_function *f;
+
+ /*
+ * ideally I would like to forbid to unlink functions while a gadget is
+ * bound to an UDC. Since this isn't possible at the moment, we simply
+ * force an unbind, the function is available here and then we can
+ * remove the function.
+ */
+ mutex_lock(&gi->lock);
+ if (gi->udc_name)
+ unregister_gadget(gi);
+ WARN_ON(gi->udc_name);
+
+ list_for_each_entry(f, &cfg->func_list, list) {
+ if (f->fi == fi) {
+ list_del(&f->list);
+ usb_put_function(f);
+ mutex_unlock(&gi->lock);
+ return 0;
+ }
+ }
+ mutex_unlock(&gi->lock);
+ WARN(1, "Unable to locate function to unbind\n");
+ return 0;
+}
+
+CONFIGFS_ATTR_OPS(config_usb_cfg);
+
+static struct configfs_item_operations gadget_config_item_ops = {
+ .release = gadget_config_attr_release,
+ .show_attribute = config_usb_cfg_attr_show,
+ .store_attribute = config_usb_cfg_attr_store,
+ .allow_link = config_usb_cfg_link,
+ .drop_link = config_usb_cfg_unlink,
+};
+
+
+static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg,
+ char *page)
+{
+ return sprintf(page, "%u\n", cfg->c.MaxPower);
+}
+
+static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg,
+ const char *page, size_t len)
+{
+ u16 val;
+ int ret;
+ ret = kstrtou16(page, 0, &val);
+ if (ret)
+ return ret;
+ if (DIV_ROUND_UP(val, 8) > 0xff)
+ return -ERANGE;
+ cfg->c.MaxPower = val;
+ return len;
+}
+
+static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg,
+ char *page)
+{
+ return sprintf(page, "0x%02x\n", cfg->c.bmAttributes);
+}
+
+static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg,
+ const char *page, size_t len)
+{
+ u8 val;
+ int ret;
+ ret = kstrtou8(page, 0, &val);
+ if (ret)
+ return ret;
+ if (!(val & USB_CONFIG_ATT_ONE))
+ return -EINVAL;
+ if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER |
+ USB_CONFIG_ATT_WAKEUP))
+ return -EINVAL;
+ cfg->c.bmAttributes = val;
+ return len;
+}
+
+#define CFG_CONFIG_DESC_ITEM_ATTR(name) \
+ static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
+ gadget_config_desc_##name##_show, \
+ gadget_config_desc_##name##_store)
+
+CFG_CONFIG_DESC_ITEM_ATTR(MaxPower);
+CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes);
+
+static struct configfs_attribute *gadget_config_attrs[] = {
+ &gadget_usb_cfg_MaxPower.attr,
+ &gadget_usb_cfg_bmAttributes.attr,
+ NULL,
+};
+
+static struct config_item_type gadget_config_type = {
+ .ct_item_ops = &gadget_config_item_ops,
+ .ct_attrs = gadget_config_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type gadget_root_type = {
+ .ct_item_ops = &gadget_root_item_ops,
+ .ct_attrs = gadget_root_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void composite_init_dev(struct usb_composite_dev *cdev)
+{
+ spin_lock_init(&cdev->lock);
+ INIT_LIST_HEAD(&cdev->configs);
+ INIT_LIST_HEAD(&cdev->gstrings);
+}
+
+static struct config_group *function_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+ struct usb_function_instance *fi;
+ char buf[MAX_NAME_LEN];
+ char *func_name;
+ char *instance_name;
+ int ret;
+
+ ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+ if (ret >= MAX_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ func_name = buf;
+ instance_name = strchr(func_name, '.');
+ if (!instance_name) {
+ pr_err("Unable to locate . in FUNC.INSTANCE\n");
+ return ERR_PTR(-EINVAL);
+ }
+ *instance_name = '\0';
+ instance_name++;
+
+ fi = usb_get_function_instance(func_name);
+ if (IS_ERR(fi))
+ return ERR_PTR(PTR_ERR(fi));
+
+ ret = config_item_set_name(&fi->group.cg_item, name);
+ if (ret) {
+ usb_put_function_instance(fi);
+ return ERR_PTR(ret);
+ }
+
+ gi = container_of(group, struct gadget_info, functions_group);
+
+ mutex_lock(&gi->lock);
+ list_add_tail(&fi->cfs_list, &gi->available_func);
+ mutex_unlock(&gi->lock);
+ return &fi->group;
+}
+
+static void function_drop(
+ struct config_group *group,
+ struct config_item *item)
+{
+ struct usb_function_instance *fi = to_usb_function_instance(item);
+ struct gadget_info *gi;
+
+ gi = container_of(group, struct gadget_info, functions_group);
+
+ mutex_lock(&gi->lock);
+ list_del(&fi->cfs_list);
+ mutex_unlock(&gi->lock);
+ config_item_put(item);
+}
+
+static struct configfs_group_operations functions_ops = {
+ .make_group = &function_make,
+ .drop_item = &function_drop,
+};
+
+static struct config_item_type functions_type = {
+ .ct_group_ops = &functions_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_config_name);
+GS_STRINGS_RW(gadget_config_name, configuration);
+
+static struct configfs_attribute *gadget_config_name_langid_attrs[] = {
+ &gadget_config_name_configuration.attr,
+ NULL,
+};
+
+static void gadget_config_name_attr_release(struct config_item *item)
+{
+ struct gadget_config_name *cn = to_gadget_config_name(item);
+
+ kfree(cn->configuration);
+
+ list_del(&cn->list);
+ kfree(cn);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_config_name);
+USB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg);
+
+static struct config_group *config_desc_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+ struct config_usb_cfg *cfg;
+ char buf[MAX_NAME_LEN];
+ char *num_str;
+ u8 num;
+ int ret;
+
+ gi = container_of(group, struct gadget_info, configs_group);
+ ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
+ if (ret >= MAX_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ num_str = strchr(buf, '.');
+ if (!num_str) {
+ pr_err("Unable to locate . in name.bConfigurationValue\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ *num_str = '\0';
+ num_str++;
+
+ if (!strlen(buf))
+ return ERR_PTR(-EINVAL);
+
+ ret = kstrtou8(num_str, 0, &num);
+ if (ret)
+ return ERR_PTR(ret);
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return ERR_PTR(-ENOMEM);
+ cfg->c.label = kstrdup(buf, GFP_KERNEL);
+ if (!cfg->c.label) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ cfg->c.bConfigurationValue = num;
+ cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW;
+ cfg->c.bmAttributes = USB_CONFIG_ATT_ONE;
+ INIT_LIST_HEAD(&cfg->string_list);
+ INIT_LIST_HEAD(&cfg->func_list);
+
+ cfg->group.default_groups = cfg->default_groups;
+ cfg->default_groups[0] = &cfg->strings_group;
+
+ config_group_init_type_name(&cfg->group, name,
+ &gadget_config_type);
+ config_group_init_type_name(&cfg->strings_group, "strings",
+ &gadget_config_name_strings_type);
+
+ ret = usb_add_config_only(&gi->cdev, &cfg->c);
+ if (ret)
+ goto err;
+
+ return &cfg->group;
+err:
+ kfree(cfg->c.label);
+ kfree(cfg);
+ return ERR_PTR(ret);
+}
+
+static void config_desc_drop(
+ struct config_group *group,
+ struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations config_desc_ops = {
+ .make_group = &config_desc_make,
+ .drop_item = &config_desc_drop,
+};
+
+static struct config_item_type config_desc_type = {
+ .ct_group_ops = &config_desc_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+CONFIGFS_ATTR_STRUCT(gadget_strings);
+GS_STRINGS_RW(gadget_strings, manufacturer);
+GS_STRINGS_RW(gadget_strings, product);
+GS_STRINGS_RW(gadget_strings, serialnumber);
+
+static struct configfs_attribute *gadget_strings_langid_attrs[] = {
+ &gadget_strings_manufacturer.attr,
+ &gadget_strings_product.attr,
+ &gadget_strings_serialnumber.attr,
+ NULL,
+};
+
+static void gadget_strings_attr_release(struct config_item *item)
+{
+ struct gadget_strings *gs = to_gadget_strings(item);
+
+ kfree(gs->manufacturer);
+ kfree(gs->product);
+ kfree(gs->serialnumber);
+
+ list_del(&gs->list);
+ kfree(gs);
+}
+
+USB_CONFIG_STRING_RW_OPS(gadget_strings);
+USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
+
+static int configfs_do_nothing(struct usb_composite_dev *cdev)
+{
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+int composite_dev_prepare(struct usb_composite_driver *composite,
+ struct usb_composite_dev *dev);
+
+static void purge_configs_funcs(struct gadget_info *gi)
+{
+ struct usb_configuration *c;
+
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct usb_function *f, *tmp;
+ struct config_usb_cfg *cfg;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+
+ list_for_each_entry_safe(f, tmp, &c->functions, list) {
+
+ list_move_tail(&f->list, &cfg->func_list);
+ if (f->unbind) {
+ dev_err(&gi->cdev.gadget->dev, "unbind function"
+ " '%s'/%p\n", f->name, f);
+ f->unbind(c, f);
+ }
+ }
+ c->next_interface_id = 0;
+ c->superspeed = 0;
+ c->highspeed = 0;
+ c->fullspeed = 0;
+ }
+}
+
+static int configfs_composite_bind(struct usb_gadget *gadget,
+ struct usb_gadget_driver *gdriver)
+{
+ struct usb_composite_driver *composite = to_cdriver(gdriver);
+ struct gadget_info *gi = container_of(composite,
+ struct gadget_info, composite);
+ struct usb_composite_dev *cdev = &gi->cdev;
+ struct usb_configuration *c;
+ struct usb_string *s;
+ unsigned i;
+ int ret;
+
+ /* the gi->lock is hold by the caller */
+ cdev->gadget = gadget;
+ set_gadget_data(gadget, cdev);
+ ret = composite_dev_prepare(composite, cdev);
+ if (ret)
+ return ret;
+ /* and now the gadget bind */
+ ret = -EINVAL;
+
+ if (list_empty(&gi->cdev.configs)) {
+ pr_err("Need atleast one configuration in %s.\n",
+ gi->composite.name);
+ goto err_comp_cleanup;
+ }
+
+
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct config_usb_cfg *cfg;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+ if (list_empty(&cfg->func_list)) {
+ pr_err("Config %s/%d of %s needs atleast one function.\n",
+ c->label, c->bConfigurationValue,
+ gi->composite.name);
+ goto err_comp_cleanup;
+ }
+ }
+
+ /* init all strings */
+ if (!list_empty(&gi->string_list)) {
+ struct gadget_strings *gs;
+
+ i = 0;
+ list_for_each_entry(gs, &gi->string_list, list) {
+
+ gi->gstrings[i] = &gs->stringtab_dev;
+ gs->stringtab_dev.strings = gs->strings;
+ gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
+ gs->manufacturer;
+ gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
+ gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
+ i++;
+ }
+ gi->gstrings[i] = NULL;
+ s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
+ USB_GADGET_FIRST_AVAIL_IDX);
+ if (IS_ERR(s))
+ goto err_comp_cleanup;
+
+ gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
+ gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
+ gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
+ }
+
+ /* Go through all configs, attach all functions */
+ list_for_each_entry(c, &gi->cdev.configs, list) {
+ struct config_usb_cfg *cfg;
+ struct usb_function *f;
+ struct usb_function *tmp;
+ struct gadget_config_name *cn;
+
+ cfg = container_of(c, struct config_usb_cfg, c);
+ if (!list_empty(&cfg->string_list)) {
+ i = 0;
+ list_for_each_entry(cn, &cfg->string_list, list) {
+ cfg->gstrings[i] = &cn->stringtab_dev;
+ cn->stringtab_dev.strings = &cn->strings;
+ cn->strings.s = cn->configuration;
+ i++;
+ }
+ cfg->gstrings[i] = NULL;
+ s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
+ if (IS_ERR(s))
+ goto err_comp_cleanup;
+ c->iConfiguration = s[0].id;
+ }
+
+ list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
+ list_del(&f->list);
+ ret = usb_add_function(c, f);
+ if (ret)
+ goto err_purge_funcs;
+ }
+ usb_ep_autoconfig_reset(cdev->gadget);
+ }
+ usb_ep_autoconfig_reset(cdev->gadget);
+ return 0;
+
+err_purge_funcs:
+ purge_configs_funcs(gi);
+err_comp_cleanup:
+ composite_dev_cleanup(cdev);
+ return ret;
+}
+
+static void configfs_composite_unbind(struct usb_gadget *gadget)
+{
+ struct usb_composite_dev *cdev;
+ struct gadget_info *gi;
+
+ /* the gi->lock is hold by the caller */
+
+ cdev = get_gadget_data(gadget);
+ gi = container_of(cdev, struct gadget_info, cdev);
+
+ purge_configs_funcs(gi);
+ composite_dev_cleanup(cdev);
+ usb_ep_autoconfig_reset(cdev->gadget);
+ cdev->gadget = NULL;
+ set_gadget_data(gadget, NULL);
+}
+
+static const struct usb_gadget_driver configfs_driver_template = {
+ .bind = configfs_composite_bind,
+ .unbind = configfs_composite_unbind,
+
+ .setup = composite_setup,
+ .disconnect = composite_disconnect,
+
+ .max_speed = USB_SPEED_SUPER,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "configfs-gadget",
+ },
+};
+
+static struct config_group *gadgets_make(
+ struct config_group *group,
+ const char *name)
+{
+ struct gadget_info *gi;
+
+ gi = kzalloc(sizeof(*gi), GFP_KERNEL);
+ if (!gi)
+ return ERR_PTR(-ENOMEM);
+
+ gi->group.default_groups = gi->default_groups;
+ gi->group.default_groups[0] = &gi->functions_group;
+ gi->group.default_groups[1] = &gi->configs_group;
+ gi->group.default_groups[2] = &gi->strings_group;
+
+ config_group_init_type_name(&gi->functions_group, "functions",
+ &functions_type);
+ config_group_init_type_name(&gi->configs_group, "configs",
+ &config_desc_type);
+ config_group_init_type_name(&gi->strings_group, "strings",
+ &gadget_strings_strings_type);
+
+ gi->composite.bind = configfs_do_nothing;
+ gi->composite.unbind = configfs_do_nothing;
+ gi->composite.suspend = NULL;
+ gi->composite.resume = NULL;
+ gi->composite.max_speed = USB_SPEED_SUPER;
+
+ mutex_init(&gi->lock);
+ INIT_LIST_HEAD(&gi->string_list);
+ INIT_LIST_HEAD(&gi->available_func);
+
+ composite_init_dev(&gi->cdev);
+ gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
+ gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
+ gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
+
+ gi->composite.gadget_driver = configfs_driver_template;
+
+ gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
+ gi->composite.name = gi->composite.gadget_driver.function;
+
+ if (!gi->composite.gadget_driver.function)
+ goto err;
+
+#ifdef CONFIG_USB_OTG
+ gi->otg.bLength = sizeof(struct usb_otg_descriptor);
+ gi->otg.bDescriptorType = USB_DT_OTG;
+ gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
+#endif
+
+ config_group_init_type_name(&gi->group, name,
+ &gadget_root_type);
+ return &gi->group;
+err:
+ kfree(gi);
+ return ERR_PTR(-ENOMEM);
+}
+
+static void gadgets_drop(struct config_group *group, struct config_item *item)
+{
+ config_item_put(item);
+}
+
+static struct configfs_group_operations gadgets_ops = {
+ .make_group = &gadgets_make,
+ .drop_item = &gadgets_drop,
+};
+
+static struct config_item_type gadgets_type = {
+ .ct_group_ops = &gadgets_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem gadget_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "usb_gadget",
+ .ci_type = &gadgets_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
+};
+
+static int __init gadget_cfs_init(void)
+{
+ int ret;
+
+ config_group_init(&gadget_subsys.su_group);
+
+ ret = configfs_register_subsystem(&gadget_subsys);
+ return ret;
+}
+module_init(gadget_cfs_init);
+
+static void __exit gadget_cfs_exit(void)
+{
+ configfs_unregister_subsystem(&gadget_subsys);
+}
+module_exit(gadget_cfs_exit);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 8cf0c0f6fa1f..a792e322f4f1 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g,
dum->devstatus = 0;
dum->driver = driver;
- dum->gadget.dev.driver = &driver->driver;
dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
return 0;
@@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
driver->driver.name);
- dum->gadget.dev.driver = NULL;
dum->driver = NULL;
return 0;
@@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g,
/* The gadget structure is stored inside the hcd structure and will be
* released along with it. */
-static void dummy_gadget_release(struct device *dev)
-{
- return;
-}
-
static void init_dummy_udc_hw(struct dummy *dum)
{
int i;
@@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev)
dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER;
- dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev;
- dum->gadget.dev.release = dummy_gadget_release;
- rc = device_register(&dum->gadget.dev);
- if (rc < 0) {
- put_device(&dum->gadget.dev);
- return rc;
- }
-
init_dummy_udc_hw(dum);
rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
@@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev)
err_dev:
usb_del_gadget_udc(&dum->gadget);
err_udc:
- device_unregister(&dum->gadget.dev);
return rc;
}
@@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&dum->gadget);
platform_set_drvdata(pdev, NULL);
device_remove_file(&dum->gadget.dev, &dev_attr_function);
- device_unregister(&dum->gadget.dev);
return 0;
}
@@ -1923,7 +1906,7 @@ done:
}
/* usb 3.0 root hub device descriptor */
-struct {
+static struct {
struct usb_bos_descriptor bos;
struct usb_ss_cap_descriptor ss_cap;
} __packed usb3_bos_desc = {
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 18c3f423706e..56c8ecae9bc3 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = {
};
static u8 hostaddr[ETH_ALEN];
-
+static struct eth_dev *the_dev;
/*-------------------------------------------------------------------------*/
/*
@@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- return rndis_bind_config(c, hostaddr);
+ return rndis_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration rndis_config_driver = {
@@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c)
}
if (use_eem)
- return eem_bind_config(c);
+ return eem_bind_config(c, the_dev);
else if (can_support_ecm(c->cdev->gadget))
- return ecm_bind_config(c, hostaddr);
+ return ecm_bind_config(c, hostaddr, the_dev);
else
- return geth_bind_config(c, hostaddr);
+ return geth_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration eth_config_driver = {
@@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
int status;
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* set up main config label and device descriptor */
if (use_eem) {
@@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
static int __exit eth_unbind(struct usb_composite_dev *cdev)
{
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 1ae180baa597..4b7e33e5d9c6 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -715,13 +715,31 @@ fail:
return status;
}
-static struct f_acm *acm_alloc_basic_func(void)
+static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_acm *acm = func_to_acm(f);
+
+ acm_string_defs[0].id = 0;
+ usb_free_all_descriptors(f);
+ if (acm->notify_req)
+ gs_free_req(acm->notify, acm->notify_req);
+}
+
+static void acm_free_func(struct usb_function *f)
+{
+ struct f_acm *acm = func_to_acm(f);
+
+ kfree(acm);
+}
+
+static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
{
- struct f_acm *acm;
+ struct f_serial_opts *opts;
+ struct f_acm *acm;
acm = kzalloc(sizeof(*acm), GFP_KERNEL);
if (!acm)
- return NULL;
+ return ERR_PTR(-ENOMEM);
spin_lock_init(&acm->lock);
@@ -730,109 +748,100 @@ static struct f_acm *acm_alloc_basic_func(void)
acm->port.send_break = acm_send_break;
acm->port.func.name = "acm";
+ acm->port.func.strings = acm_strings;
/* descriptors are per-instance copies */
acm->port.func.bind = acm_bind;
acm->port.func.set_alt = acm_set_alt;
acm->port.func.setup = acm_setup;
acm->port.func.disable = acm_disable;
- return acm;
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+ acm->port_num = opts->port_num;
+ acm->port.func.unbind = acm_unbind;
+ acm->port.func.free_func = acm_free_func;
+
+ return &acm->port.func;
}
-#ifdef USB_FACM_INCLUDED
-static void
-acm_old_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
- struct f_acm *acm = func_to_acm(f);
-
- usb_free_all_descriptors(f);
- if (acm->notify_req)
- gs_free_req(acm->notify, acm->notify_req);
- kfree(acm);
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
}
-/**
- * acm_bind_config - add a CDC ACM function to a configuration
- * @c: the configuration to support the CDC ACM instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- */
-int acm_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_acm_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
{
- struct f_acm *acm;
- int status;
-
- /* allocate and initialize one new instance */
- acm = acm_alloc_basic_func();
- if (!acm)
- return -ENOMEM;
-
- acm->port_num = port_num;
- acm->port.func.unbind = acm_old_unbind;
-
- status = usb_add_function(c, &acm->port.func);
- if (status)
- kfree(acm);
- return status;
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
+
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
+ return ret;
}
-#else
-
-static void acm_unbind(struct usb_configuration *c, struct usb_function *f)
+static void acm_attr_release(struct config_item *item)
{
- struct f_acm *acm = func_to_acm(f);
+ struct f_serial_opts *opts = to_f_serial_opts(item);
- acm_string_defs[0].id = 0;
- usb_free_all_descriptors(f);
- if (acm->notify_req)
- gs_free_req(acm->notify, acm->notify_req);
+ usb_put_function_instance(&opts->func_inst);
}
-static void acm_free_func(struct usb_function *f)
-{
- struct f_acm *acm = func_to_acm(f);
+static struct configfs_item_operations acm_item_ops = {
+ .release = acm_attr_release,
+ .show_attribute = f_acm_attr_show,
+};
- kfree(acm);
+static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
}
-static struct usb_function *acm_alloc_func(struct usb_function_instance *fi)
-{
- struct f_serial_opts *opts;
- struct f_acm *acm;
+static struct f_serial_opts_attribute f_acm_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
- acm = acm_alloc_basic_func();
- if (!acm)
- return ERR_PTR(-ENOMEM);
- opts = container_of(fi, struct f_serial_opts, func_inst);
- acm->port_num = opts->port_num;
- acm->port.func.unbind = acm_unbind;
- acm->port.func.free_func = acm_free_func;
+static struct configfs_attribute *acm_attrs[] = {
+ &f_acm_port_num.attr,
+ NULL,
+};
- return &acm->port.func;
-}
+static struct config_item_type acm_func_type = {
+ .ct_item_ops = &acm_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
static void acm_free_instance(struct usb_function_instance *fi)
{
struct f_serial_opts *opts;
opts = container_of(fi, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
kfree(opts);
}
static struct usb_function_instance *acm_alloc_instance(void)
{
struct f_serial_opts *opts;
+ int ret;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = acm_free_instance;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
+ }
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &acm_func_type);
return &opts->func_inst;
}
DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
MODULE_LICENSE("GPL");
-#endif
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 83420a310fb7..d893d6929079 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
* for calling @gether_cleanup() before module unload.
*/
int
-ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_ecm *ecm;
int status;
@@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr);
ecm_string_defs[1].s = ecm->ethaddr;
+ ecm->port.ioport = dev;
ecm->port.cdc_filter = DEFAULT_FILTER;
ecm->port.func.name = "cdc_ethernet";
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index cf0ebee85563..f4e0bbef602a 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -528,7 +528,7 @@ error:
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init eem_bind_config(struct usb_configuration *c)
+int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev)
{
struct f_eem *eem;
int status;
@@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c)
if (!eem)
return -ENOMEM;
+ eem->port.ioport = dev;
eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem";
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 5e7557e23ecc..ee19bc8d0040 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_ncm *ncm;
int status;
@@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
+ ncm->port.ioport = dev;
ncm->port.is_fixed = true;
ncm->port.func.name = "cdc_network";
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 36a004563b82..8aa2be5329bc 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = {
/*-------------------------------------------------------------------------*/
-static struct usb_interface_descriptor obex_control_intf __initdata = {
+static struct usb_interface_descriptor obex_control_intf = {
.bLength = sizeof(obex_control_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
@@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = {
.bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX,
};
-static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
+static struct usb_interface_descriptor obex_data_nop_intf = {
.bLength = sizeof(obex_data_nop_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1,
@@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA,
};
-static struct usb_interface_descriptor obex_data_intf __initdata = {
+static struct usb_interface_descriptor obex_data_intf = {
.bLength = sizeof(obex_data_intf),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 2,
@@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = {
.bInterfaceClass = USB_CLASS_CDC_DATA,
};
-static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = {
+static struct usb_cdc_header_desc obex_cdc_header_desc = {
.bLength = sizeof(obex_cdc_header_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
.bcdCDC = cpu_to_le16(0x0120),
};
-static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
+static struct usb_cdc_union_desc obex_cdc_union_desc = {
.bLength = sizeof(obex_cdc_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = {
.bSlaveInterface0 = 2,
};
-static struct usb_cdc_obex_desc obex_desc __initdata = {
+static struct usb_cdc_obex_desc obex_desc = {
.bLength = sizeof(obex_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_OBEX_TYPE,
@@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = {
/* High-Speed Support */
-static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_hs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *hs_function[] __initdata = {
+static struct usb_descriptor_header *hs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = {
/* Full-Speed Support */
-static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
+static struct usb_endpoint_descriptor obex_fs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *fs_function[] __initdata = {
+static struct usb_descriptor_header *fs_function[] = {
(struct usb_descriptor_header *) &obex_control_intf,
(struct usb_descriptor_header *) &obex_cdc_header_desc,
(struct usb_descriptor_header *) &obex_desc,
@@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g)
/*-------------------------------------------------------------------------*/
-static int __init
-obex_bind(struct usb_configuration *c, struct usb_function *f)
+/* Some controllers can't support CDC OBEX ... */
+static inline bool can_support_obex(struct usb_configuration *c)
+{
+ /* Since the first interface is a NOP, we can ignore the
+ * issue of multi-interface support on most controllers.
+ *
+ * Altsettings are mandatory, however...
+ */
+ if (!gadget_supports_altsettings(c->cdev->gadget))
+ return false;
+
+ /* everything else is *probably* fine ... */
+ return true;
+}
+
+static int obex_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_obex *obex = func_to_obex(f);
int status;
struct usb_ep *ep;
+ if (!can_support_obex(c))
+ return -EINVAL;
+
+ if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
+ status = usb_string_ids_tab(c->cdev, obex_string_defs);
+ if (status < 0)
+ return status;
+ obex_control_intf.iInterface =
+ obex_string_defs[OBEX_CTRL_IDX].id;
+
+ status = obex_string_defs[OBEX_DATA_IDX].id;
+ obex_data_nop_intf.iInterface = status;
+ obex_data_intf.iInterface = status;
+ }
+
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
@@ -319,6 +348,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
/* allocate instance-specific endpoints */
+ status = -ENODEV;
ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc);
if (!ep)
goto fail;
@@ -376,29 +406,16 @@ fail:
return status;
}
+#ifdef USBF_OBEX_INCLUDED
+
static void
-obex_unbind(struct usb_configuration *c, struct usb_function *f)
+obex_old_unbind(struct usb_configuration *c, struct usb_function *f)
{
obex_string_defs[OBEX_CTRL_IDX].id = 0;
usb_free_all_descriptors(f);
kfree(func_to_obex(f));
}
-/* Some controllers can't support CDC OBEX ... */
-static inline bool can_support_obex(struct usb_configuration *c)
-{
- /* Since the first interface is a NOP, we can ignore the
- * issue of multi-interface support on most controllers.
- *
- * Altsettings are mandatory, however...
- */
- if (!gadget_supports_altsettings(c->cdev->gadget))
- return false;
-
- /* everything else is *probably* fine ... */
- return true;
-}
-
/**
* obex_bind_config - add a CDC OBEX function to a configuration
* @c: the configuration to support the CDC OBEX instance
@@ -412,21 +429,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
struct f_obex *obex;
int status;
- if (!can_support_obex(c))
- return -EINVAL;
-
- if (obex_string_defs[OBEX_CTRL_IDX].id == 0) {
- status = usb_string_ids_tab(c->cdev, obex_string_defs);
- if (status < 0)
- return status;
- obex_control_intf.iInterface =
- obex_string_defs[OBEX_CTRL_IDX].id;
-
- status = obex_string_defs[OBEX_DATA_IDX].id;
- obex_data_nop_intf.iInterface = status;
- obex_data_intf.iInterface = status;
- }
-
/* allocate and initialize one new instance */
obex = kzalloc(sizeof *obex, GFP_KERNEL);
if (!obex)
@@ -441,7 +443,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
obex->port.func.strings = obex_strings;
/* descriptors are per-instance copies */
obex->port.func.bind = obex_bind;
- obex->port.func.unbind = obex_unbind;
+ obex->port.func.unbind = obex_old_unbind;
obex->port.func.set_alt = obex_set_alt;
obex->port.func.get_alt = obex_get_alt;
obex->port.func.disable = obex_disable;
@@ -453,5 +455,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num)
return status;
}
+#else
+
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_obex_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
+
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
+
+ return ret;
+}
+
+static void obex_attr_release(struct config_item *item)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations obex_item_ops = {
+ .release = obex_attr_release,
+ .show_attribute = f_obex_attr_show,
+};
+
+static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_obex_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+ &f_obex_port_num.attr,
+ NULL,
+};
+
+static struct config_item_type obex_func_type = {
+ .ct_item_ops = &obex_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void obex_free_inst(struct usb_function_instance *f)
+{
+ struct f_serial_opts *opts;
+
+ opts = container_of(f, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
+ kfree(opts);
+}
+
+static struct usb_function_instance *obex_alloc_inst(void)
+{
+ struct f_serial_opts *opts;
+ int ret;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.free_func_inst = obex_free_inst;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
+ }
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &obex_func_type);
+
+ return &opts->func_inst;
+}
+
+static void obex_free(struct usb_function *f)
+{
+ struct f_obex *obex;
+
+ obex = func_to_obex(f);
+ kfree(obex);
+}
+
+static void obex_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ obex_string_defs[OBEX_CTRL_IDX].id = 0;
+ usb_free_all_descriptors(f);
+}
+
+struct usb_function *obex_alloc(struct usb_function_instance *fi)
+{
+ struct f_obex *obex;
+ struct f_serial_opts *opts;
+
+ /* allocate and initialize one new instance */
+ obex = kzalloc(sizeof(*obex), GFP_KERNEL);
+ if (!obex)
+ return ERR_PTR(-ENOMEM);
+
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+
+ obex->port_num = opts->port_num;
+
+ obex->port.connect = obex_connect;
+ obex->port.disconnect = obex_disconnect;
+
+ obex->port.func.name = "obex";
+ obex->port.func.strings = obex_strings;
+ /* descriptors are per-instance copies */
+ obex->port.func.bind = obex_bind;
+ obex->port.func.unbind = obex_unbind;
+ obex->port.func.set_alt = obex_set_alt;
+ obex->port.func.get_alt = obex_get_alt;
+ obex->port.func.disable = obex_disable;
+ obex->port.func.free_func = obex_free;
+
+ return &obex->port.func;
+}
+
+DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc);
+
+#endif
+
MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index cc9c49c57c80..36e8c44d8e5e 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{
struct f_rndis *rndis;
int status;
@@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->vendorID = vendorID;
rndis->manufacturer = manufacturer;
+ rndis->port.ioport = dev;
/* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0;
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index da33cfb3031d..981113c9924d 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/device.h>
#include "u_serial.h"
@@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f)
/* interface descriptor: */
-static struct usb_interface_descriptor gser_interface_desc __initdata = {
+static struct usb_interface_descriptor gser_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
@@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = {
/* full speed support: */
-static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *gser_fs_function[] __initdata = {
+static struct usb_descriptor_header *gser_fs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_fs_in_desc,
(struct usb_descriptor_header *) &gser_fs_out_desc,
@@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = {
/* high speed support: */
-static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_hs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *gser_hs_function[] __initdata = {
+static struct usb_descriptor_header *gser_hs_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_hs_in_desc,
(struct usb_descriptor_header *) &gser_hs_out_desc,
NULL,
};
-static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
+static struct usb_endpoint_descriptor gser_ss_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
.bLength = sizeof gser_ss_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
};
-static struct usb_descriptor_header *gser_ss_function[] __initdata = {
+static struct usb_descriptor_header *gser_ss_function[] = {
(struct usb_descriptor_header *) &gser_interface_desc,
(struct usb_descriptor_header *) &gser_ss_in_desc,
(struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
@@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f)
/* serial function driver setup/binding */
-static int __init
-gser_bind(struct usb_configuration *c, struct usb_function *f)
+static int gser_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_gser *gser = func_to_gser(f);
int status;
struct usb_ep *ep;
+ /* REVISIT might want instance-specific strings to help
+ * distinguish instances ...
+ */
+
+ /* maybe allocate device-global string ID */
+ if (gser_string_defs[0].id == 0) {
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ gser_string_defs[0].id = status;
+ }
+
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
@@ -246,44 +258,115 @@ fail:
return status;
}
-static void
-gser_unbind(struct usb_configuration *c, struct usb_function *f)
+static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
{
- usb_free_all_descriptors(f);
- kfree(func_to_gser(f));
+ return container_of(to_config_group(item), struct f_serial_opts,
+ func_inst.group);
}
-/**
- * gser_bind_config - add a generic serial function to a configuration
- * @c: the configuration to support the serial instance
- * @port_num: /dev/ttyGS* port this interface will use
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- */
-int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
+CONFIGFS_ATTR_STRUCT(f_serial_opts);
+static ssize_t f_serial_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
{
- struct f_gser *gser;
- int status;
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+ struct f_serial_opts_attribute *f_serial_opts_attr =
+ container_of(attr, struct f_serial_opts_attribute, attr);
+ ssize_t ret = 0;
- /* REVISIT might want instance-specific strings to help
- * distinguish instances ...
- */
+ if (f_serial_opts_attr->show)
+ ret = f_serial_opts_attr->show(opts, page);
- /* maybe allocate device-global string ID */
- if (gser_string_defs[0].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0)
- return status;
- gser_string_defs[0].id = status;
+ return ret;
+}
+
+static void serial_attr_release(struct config_item *item)
+{
+ struct f_serial_opts *opts = to_f_serial_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations serial_item_ops = {
+ .release = serial_attr_release,
+ .show_attribute = f_serial_attr_show,
+};
+
+static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
+{
+ return sprintf(page, "%u\n", opts->port_num);
+}
+
+static struct f_serial_opts_attribute f_serial_port_num =
+ __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
+
+static struct configfs_attribute *acm_attrs[] = {
+ &f_serial_port_num.attr,
+ NULL,
+};
+
+static struct config_item_type serial_func_type = {
+ .ct_item_ops = &serial_item_ops,
+ .ct_attrs = acm_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static void gser_free_inst(struct usb_function_instance *f)
+{
+ struct f_serial_opts *opts;
+
+ opts = container_of(f, struct f_serial_opts, func_inst);
+ gserial_free_line(opts->port_num);
+ kfree(opts);
+}
+
+static struct usb_function_instance *gser_alloc_inst(void)
+{
+ struct f_serial_opts *opts;
+ int ret;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.free_func_inst = gser_free_inst;
+ ret = gserial_alloc_line(&opts->port_num);
+ if (ret) {
+ kfree(opts);
+ return ERR_PTR(ret);
}
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &serial_func_type);
+
+ return &opts->func_inst;
+}
+
+static void gser_free(struct usb_function *f)
+{
+ struct f_gser *serial;
+
+ serial = func_to_gser(f);
+ kfree(serial);
+}
+
+static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ usb_free_all_descriptors(f);
+}
+
+struct usb_function *gser_alloc(struct usb_function_instance *fi)
+{
+ struct f_gser *gser;
+ struct f_serial_opts *opts;
/* allocate and initialize one new instance */
- gser = kzalloc(sizeof *gser, GFP_KERNEL);
+ gser = kzalloc(sizeof(*gser), GFP_KERNEL);
if (!gser)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- gser->port_num = port_num;
+ opts = container_of(fi, struct f_serial_opts, func_inst);
+
+ gser->port_num = opts->port_num;
gser->port.func.name = "gser";
gser->port.func.strings = gser_strings;
@@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
gser->port.func.unbind = gser_unbind;
gser->port.func.set_alt = gser_set_alt;
gser->port.func.disable = gser_disable;
+ gser->port.func.free_func = gser_free;
- status = usb_add_function(c, &gser->port.func);
- if (status)
- kfree(gser);
- return status;
+ return &gser->port.func;
}
+
+DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Al Borchers");
+MODULE_AUTHOR("David Brownell");
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 41adf3ef96c2..a8895859a221 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -898,7 +898,7 @@ static struct usb_function *source_sink_alloc_func(
return &ss->function;
}
-static void acm_free_instance(struct usb_function_instance *fi)
+static void source_sink_free_instance(struct usb_function_instance *fi)
{
struct f_ss_opts *ss_opts;
@@ -913,7 +913,7 @@ static struct usb_function_instance *source_sink_alloc_inst(void)
ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);
if (!ss_opts)
return ERR_PTR(-ENOMEM);
- ss_opts->func_inst.free_func_inst = acm_free_instance;
+ ss_opts->func_inst.free_func_inst = source_sink_free_instance;
return &ss_opts->func_inst;
}
DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index f172bd152fbb..185d6f5e4e4d 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
struct f_gether *geth;
int status;
@@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr);
geth_string_defs[1].s = geth->ethaddr;
+ geth->port.ioport = dev;
geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset";
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index 92efd6ec48af..38dcedddc52c 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param;
/*-------------------------------------------------------------------------*/
/* module parameters specific to the Video streaming endpoint */
-static unsigned streaming_interval = 1;
+static unsigned int streaming_interval = 1;
module_param(streaming_interval, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_interval, "1 - 16");
-static unsigned streaming_maxpacket = 1024;
+static unsigned int streaming_maxpacket = 1024;
module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)");
-static unsigned streaming_mult;
-module_param(streaming_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)");
-
-static unsigned streaming_maxburst;
+static unsigned int streaming_maxburst;
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
@@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
/* string IDs are assigned dynamically */
-#define UVC_STRING_ASSOCIATION_IDX 0
-#define UVC_STRING_CONTROL_IDX 1
-#define UVC_STRING_STREAMING_IDX 2
+#define UVC_STRING_CONTROL_IDX 0
+#define UVC_STRING_STREAMING_IDX 1
static struct usb_string uvc_en_us_strings[] = {
- [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera",
- [UVC_STRING_CONTROL_IDX].s = "Video Control",
+ [UVC_STRING_CONTROL_IDX].s = "UVC Camera",
[UVC_STRING_STREAMING_IDX].s = "Video Streaming",
{ }
};
@@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = {
#define UVC_INTF_VIDEO_CONTROL 0
#define UVC_INTF_VIDEO_STREAMING 1
-#define STATUS_BYTECOUNT 16 /* 16 bytes status */
+#define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */
static struct usb_interface_assoc_descriptor uvc_iad __initdata = {
.bLength = sizeof(uvc_iad),
@@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = {
.iInterface = 0,
};
-static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = {
+static struct usb_endpoint_descriptor uvc_control_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
+ .wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
.bInterval = 8,
};
+static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
+ .bLength = sizeof(uvc_ss_control_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* The following 3 values can be tweaked if necessary. */
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
+};
+
static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = {
.bLength = UVC_DT_CONTROL_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubType = UVC_EP_INTERRUPT,
- .wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT),
+ .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE),
};
static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = {
@@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = {
.iInterface = 0,
};
-static struct usb_endpoint_descriptor uvc_fs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(512),
- .bInterval = 1,
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
-static struct usb_endpoint_descriptor uvc_hs_streaming_ep = {
+static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(1024),
- .bInterval = 1,
-};
-
-/* super speed support */
-static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT),
- .bInterval = 8,
-};
-
-static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = {
- .bLength = sizeof uvc_ss_control_comp,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 3 values can be tweaked if necessary */
- /* .bMaxBurst = 0, */
- /* .bmAttributes = 0, */
- .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT),
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_ISOC,
- .wMaxPacketSize = cpu_to_le16(1024),
- .bInterval = 4,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ /* The wMaxPacketSize and bInterval values will be initialized from
+ * module parameters.
+ */
+ .wMaxPacketSize = 0,
+ .bInterval = 0,
};
-static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
- .bLength = sizeof uvc_ss_streaming_comp,
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-
- /* the following 3 values can be tweaked if necessary */
- .bMaxBurst = 0,
- .bmAttributes = 0,
- .wBytesPerInterval = cpu_to_le16(1024),
+static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = {
+ .bLength = sizeof(uvc_ss_streaming_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ /* The following 3 values can be tweaked if necessary. */
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
};
static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
@@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
return 0;
}
+void uvc_function_setup_continue(struct uvc_device *uvc)
+{
+ struct usb_composite_dev *cdev = uvc->func.config->cdev;
+
+ usb_composite_setup_continue(cdev);
+}
+
static int
uvc_function_get_alt(struct usb_function *f, unsigned interface)
{
@@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
v4l2_event_queue(uvc->vdev, &v4l2_event);
uvc->state = UVC_STATE_CONNECTED;
- break;
+ return 0;
case 1:
if (uvc->state != UVC_STATE_CONNECTED)
@@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(uvc->vdev, &v4l2_event);
-
- uvc->state = UVC_STATE_STREAMING;
- break;
+ return USB_GADGET_DELAYED_STATUS;
default:
return -EINVAL;
}
-
- return 0;
}
static void
@@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
const struct uvc_descriptor_header * const *uvc_streaming_cls;
const struct usb_descriptor_header * const *uvc_streaming_std;
const struct usb_descriptor_header * const *src;
- static struct usb_endpoint_descriptor *uvc_control_ep;
struct usb_descriptor_header **dst;
struct usb_descriptor_header **hdr;
unsigned int control_size;
@@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.ss_control;
uvc_streaming_cls = uvc->desc.ss_streaming;
uvc_streaming_std = uvc_ss_streaming;
- uvc_control_ep = &uvc_ss_control_ep;
break;
case USB_SPEED_HIGH:
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.hs_streaming;
uvc_streaming_std = uvc_hs_streaming;
- uvc_control_ep = &uvc_fs_control_ep;
break;
case USB_SPEED_FULL:
@@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_desc = uvc->desc.fs_control;
uvc_streaming_cls = uvc->desc.fs_streaming;
uvc_streaming_std = uvc_fs_streaming;
- uvc_control_ep = &uvc_fs_control_ep;
break;
}
@@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
* Class-specific UVC control descriptors
* uvc_control_ep
* uvc_control_cs_ep
+ * uvc_ss_control_comp (for SS only)
* uvc_streaming_intf_alt0
* Class-specific UVC streaming descriptors
* uvc_{fs|hs}_streaming
@@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
control_size = 0;
streaming_size = 0;
bytes = uvc_iad.bLength + uvc_control_intf.bLength
- + uvc_control_ep->bLength + uvc_control_cs_ep.bLength
+ + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
+ uvc_streaming_intf_alt0.bLength;
if (speed == USB_SPEED_SUPER) {
@@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
}
for (src = (const struct usb_descriptor_header **)uvc_control_desc;
- *src; ++src) {
+ *src; ++src) {
control_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
}
for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
- *src; ++src) {
+ *src; ++src) {
streaming_size += (*src)->bLength;
bytes += (*src)->bLength;
n_desc++;
@@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
uvc_control_header->bInCollection = 1;
uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
- UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep);
+ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
if (speed == USB_SPEED_SUPER)
UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
@@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
UVC_COPY_DESCRIPTORS(mem, dst,
(const struct usb_descriptor_header**)uvc_streaming_cls);
uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
- uvc_streaming_header->bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
+ uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
@@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep->driver_data = NULL;
uvc->video.ep->driver_data = NULL;
- uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0;
+ uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0;
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf);
@@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f);
+ unsigned int max_packet_mult;
+ unsigned int max_packet_size;
struct usb_ep *ep;
int ret = -EINVAL;
INFO(cdev, "uvc_function_bind\n");
- /* sanity check the streaming endpoint module parameters */
- if (streaming_interval < 1)
- streaming_interval = 1;
- if (streaming_interval > 16)
- streaming_interval = 16;
- if (streaming_mult > 2)
- streaming_mult = 2;
- if (streaming_maxburst > 15)
- streaming_maxburst = 15;
-
- /*
- * fill in the FS video streaming specific descriptors from the
- * module parameters
+ /* Sanity check the streaming endpoint module parameters.
*/
- uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
- 1023 : streaming_maxpacket;
+ streaming_interval = clamp(streaming_interval, 1U, 16U);
+ streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
+ streaming_maxburst = min(streaming_maxburst, 15U);
+
+ /* Fill in the FS/HS/SS Video Streaming specific descriptors from the
+ * module parameters.
+ *
+ * NOTE: We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ if (streaming_maxpacket <= 1024) {
+ max_packet_mult = 1;
+ max_packet_size = streaming_maxpacket;
+ } else if (streaming_maxpacket <= 2048) {
+ max_packet_mult = 2;
+ max_packet_size = streaming_maxpacket / 2;
+ } else {
+ max_packet_mult = 3;
+ max_packet_size = streaming_maxpacket / 3;
+ }
+
+ uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
uvc_fs_streaming_ep.bInterval = streaming_interval;
+ uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
+ uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
+ uvc_hs_streaming_ep.bInterval = streaming_interval;
+
+ uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
+ uvc_ss_streaming_ep.bInterval = streaming_interval;
+ uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
+ uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
+ uvc_ss_streaming_comp.wBytesPerInterval =
+ max_packet_size * max_packet_mult * streaming_maxburst;
+
/* Allocate endpoints. */
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
if (!ep) {
INFO(cdev, "Unable to allocate control EP\n");
goto error;
@@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->control_ep = ep;
ep->driver_data = uvc;
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+ if (gadget_is_superspeed(c->cdev->gadget))
+ ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
+ &uvc_ss_streaming_comp);
+ else if (gadget_is_dualspeed(cdev->gadget))
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
+ else
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+
if (!ep) {
INFO(cdev, "Unable to allocate streaming EP\n");
goto error;
@@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc->video.ep = ep;
ep->driver_data = uvc;
+ uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+ uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+ uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
+
/* Allocate interface IDs. */
if ((ret = usb_interface_id(c, f)) < 0)
goto error;
@@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
uvc_streaming_intf_alt1.bInterfaceNumber = ret;
uvc->streaming_intf = ret;
- /* sanity check the streaming endpoint module parameters */
- if (streaming_maxpacket > 1024)
- streaming_maxpacket = 1024;
- /*
- * Fill in the HS descriptors from the module parameters for the Video
- * Streaming endpoint.
- * NOTE: We assume that the user knows what they are doing and won't
- * give parameters that their UDC doesn't support.
- */
- uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
- uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
- uvc_hs_streaming_ep.bInterval = streaming_interval;
- uvc_hs_streaming_ep.bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
-
- /*
- * Fill in the SS descriptors from the module parameters for the Video
- * Streaming endpoint.
- * NOTE: We assume that the user knows what they are doing and won't
- * give parameters that their UDC doesn't support.
- */
- uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
- uvc_ss_streaming_ep.bInterval = streaming_interval;
- uvc_ss_streaming_comp.bmAttributes = streaming_mult;
- uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
- uvc_ss_streaming_comp.wBytesPerInterval =
- streaming_maxpacket * (streaming_mult + 1) *
- (streaming_maxburst + 1);
- uvc_ss_streaming_ep.bEndpointAddress =
- uvc_fs_streaming_ep.bEndpointAddress;
-
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
if (gadget_is_dualspeed(cdev->gadget))
@@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c,
/* Validate the descriptors. */
if (fs_control == NULL || fs_control[0] == NULL ||
- fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+ fs_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error;
if (ss_control == NULL || ss_control[0] == NULL ||
- ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
+ ss_control[0]->bDescriptorSubType != UVC_VC_HEADER)
goto error;
if (fs_streaming == NULL || fs_streaming[0] == NULL ||
- fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
if (hs_streaming == NULL || hs_streaming[0] == NULL ||
- hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
if (ss_streaming == NULL || ss_streaming[0] == NULL ||
- ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
+ ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER)
goto error;
uvc->desc.fs_control = fs_control;
@@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c,
uvc->desc.hs_streaming = hs_streaming;
uvc->desc.ss_streaming = ss_streaming;
- /* Allocate string descriptor numbers. */
- if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) {
+ /* String descriptors are global, we only need to allocate string IDs
+ * for the first UVC function. UVC functions beyond the first (if any)
+ * will reuse the same IDs.
+ */
+ if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) {
ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings);
if (ret)
goto error;
uvc_iad.iFunction =
- uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id;
+ uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
uvc_control_intf.iInterface =
uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id;
ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id;
diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h
index c3d258d30188..ec52752f7326 100644
--- a/drivers/usb/gadget/f_uvc.h
+++ b/drivers/usb/gadget/f_uvc.h
@@ -16,12 +16,12 @@
#include <linux/usb/composite.h>
#include <linux/usb/video.h>
-extern int uvc_bind_config(struct usb_configuration *c,
- const struct uvc_descriptor_header * const *fs_control,
- const struct uvc_descriptor_header * const *hs_control,
- const struct uvc_descriptor_header * const *fs_streaming,
- const struct uvc_descriptor_header * const *hs_streaming,
- const struct uvc_descriptor_header * const *ss_streaming);
+int uvc_bind_config(struct usb_configuration *c,
+ const struct uvc_descriptor_header * const *fs_control,
+ const struct uvc_descriptor_header * const *hs_control,
+ const struct uvc_descriptor_header * const *fs_streaming,
+ const struct uvc_descriptor_header * const *hs_streaming,
+ const struct uvc_descriptor_header * const *ss_streaming);
#endif /* _F_UVC_H_ */
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 034477ce77c6..9a7ee3347e4d 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget,
driver->driver.bus = NULL;
/* hook up the driver */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.speed = driver->max_speed;
/* Enable IRQ reg and Set usbcmd reg EN bit */
@@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget,
nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
@@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev)
/* name: Identifies the controller hardware type. */
udc->gadget.name = driver_name;
-
- device_initialize(&udc->gadget.dev);
-
- dev_set_name(&udc->gadget.dev, "gadget");
-
- udc->gadget.dev.release = qe_udc_release;
udc->gadget.dev.parent = &ofdev->dev;
/* initialize qe_ep struct */
@@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev)
goto err5;
}
- ret = device_add(&udc->gadget.dev);
+ ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget,
+ qe_udc_release);
if (ret)
goto err6;
- ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
- if (ret)
- goto err7;
-
dev_set_drvdata(&ofdev->dev, udc);
dev_info(udc->dev,
"%s USB controller initialized as device\n",
(udc->soc_type == PORT_QE) ? "QE" : "CPM");
return 0;
-err7:
- device_unregister(&udc->gadget.dev);
err6:
free_irq(udc->usb_irq, udc);
err5:
@@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev)
iounmap(udc->usb_regs);
- device_unregister(&udc->gadget.dev);
/* wait for release() of gadget.dev to free udc */
wait_for_completion(&done);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index ede70ffe1ab4..2d8c1cfea699 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status)
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
}
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
if (status && (status != -ESHUTDOWN))
VDBG("complete %s req %p stat %d len %u/%u",
@@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
struct fsl_req *req = container_of(_req, struct fsl_req, req);
struct fsl_udc *udc;
unsigned long flags;
+ int ret;
/* catch various bogus parameters */
if (!_req || !req->req.complete || !req->req.buf
@@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep;
- /* map virtual address to hardware */
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf,
- req->req.length, ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_is_in(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ return ret;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
@@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
{
struct fsl_req *req = udc->status_req;
struct fsl_ep *ep;
+ int ret;
if (direction == EP_DIR_IN)
udc->ep0_dir = USB_DIR_IN;
@@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
req->req.complete = NULL;
req->dtd_count = 0;
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ return ret;
if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req);
@@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
u16 tmp = 0; /* Status, cpu endian */
struct fsl_req *req;
struct fsl_ep *ep;
+ int ret;
ep = &udc->eps[0];
@@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->req.complete = NULL;
req->dtd_count = 0;
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length,
- ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
+ if (ret)
+ goto stall;
/* prime the data phase */
if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
@@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
/* hook up the driver */
udc_controller->driver = driver;
- udc_controller->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
@@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g,
if (retval < 0) {
ERR("can't bind to transceiver\n");
driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = 0;
udc_controller->driver = 0;
return retval;
}
@@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g,
nuke(loop_ep, -ESHUTDOWN);
spin_unlock_irqrestore(&udc_controller->lock, flags);
- udc_controller->gadget.dev.driver = NULL;
udc_controller->driver = NULL;
return 0;
@@ -2483,12 +2455,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
/* Setup gadget.dev and register with kernel */
dev_set_name(&udc_controller->gadget.dev, "gadget");
- udc_controller->gadget.dev.release = fsl_udc_release;
- udc_controller->gadget.dev.parent = &pdev->dev;
udc_controller->gadget.dev.of_node = pdev->dev.of_node;
- ret = device_register(&udc_controller->gadget.dev);
- if (ret < 0)
- goto err_free_irq;
if (!IS_ERR_OR_NULL(udc_controller->transceiver))
udc_controller->gadget.is_otg = 1;
@@ -2521,10 +2488,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
DTD_ALIGNMENT, UDC_DMA_BOUNDARY);
if (udc_controller->td_pool == NULL) {
ret = -ENOMEM;
- goto err_unregister;
+ goto err_free_irq;
}
- ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+ ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget,
+ fsl_udc_release);
if (ret)
goto err_del_udc;
@@ -2533,8 +2501,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
err_del_udc:
dma_pool_destroy(udc_controller->td_pool);
-err_unregister:
- device_unregister(&udc_controller->gadget.dev);
err_free_irq:
free_irq(udc_controller->irq, udc_controller);
err_iounmap:
@@ -2584,7 +2550,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
release_mem_region(res->start, resource_size(res));
- device_unregister(&udc_controller->gadget.dev);
/* free udc --wait for the release() finished */
wait_for_completion(&done);
@@ -2709,21 +2674,7 @@ static struct platform_driver udc_driver = {
},
};
-static int __init udc_init(void)
-{
- printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION);
- return platform_driver_probe(&udc_driver, fsl_udc_probe);
-}
-
-module_init(udc_init);
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
- printk(KERN_WARNING "%s unregistered\n", driver_desc);
-}
-
-module_exit(udc_exit);
+module_platform_driver_probe(udc_driver, fsl_udc_probe);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 066cb89376de..cec8871b77f9 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep)
if (reg & FUSB300_EPSET0_STL) {
printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep);
- reg &= ~FUSB300_EPSET0_STL;
+ reg |= FUSB300_EPSET0_STL_CLR;
iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep));
}
}
@@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep)
fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0,
FUSB300_IGR0_EPn_PRD_INT(ep->epnum));
+ return;
+
IDMA_RESET:
- fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0,
- FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
+ reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0);
+ reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum);
+ iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0);
}
-static void fusb300_set_idma(struct fusb300_ep *ep,
+static void fusb300_set_idma(struct fusb300_ep *ep,
struct fusb300_request *req)
{
- dma_addr_t d;
-
- d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
+ int ret;
- if (dma_mapping_error(NULL, d)) {
- printk(KERN_DEBUG "dma_mapping_error\n");
+ ret = usb_gadget_map_request(&ep->fusb300->gadget,
+ &req->req, DMA_TO_DEVICE);
+ if (ret)
return;
- }
-
- dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
- fusb300_fill_idma_prdtbl(ep, d, req->req.length);
+ fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length);
/* check idma is done */
fusb300_wait_idma_finished(ep);
- dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
+ usb_gadget_unmap_request(&ep->fusb300->gadget,
+ &req->req, DMA_TO_DEVICE);
}
static void in_ep_fifo_handler(struct fusb300_ep *ep)
@@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
fusb300->driver = driver;
- fusb300->gadget.dev.driver = &driver->driver;
return 0;
}
@@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g,
struct fusb300 *fusb300 = to_fusb300(g);
driver->unbind(&fusb300->gadget);
- fusb300->gadget.dev.driver = NULL;
init_controller(fusb300);
fusb300->driver = NULL;
@@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->gadget.ops = &fusb300_gadget_ops;
- device_initialize(&fusb300->gadget.dev);
-
- dev_set_name(&fusb300->gadget.dev, "gadget");
-
fusb300->gadget.max_speed = USB_SPEED_HIGH;
- fusb300->gadget.dev.parent = &pdev->dev;
- fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
- fusb300->gadget.dev.release = pdev->dev.release;
fusb300->gadget.name = udc_name;
fusb300->reg = reg;
@@ -1478,19 +1469,10 @@ static int __init fusb300_probe(struct platform_device *pdev)
if (ret)
goto err_add_udc;
- ret = device_add(&fusb300->gadget.dev);
- if (ret) {
- pr_err("device_add error (%d)\n", ret);
- goto err_add_device;
- }
-
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
-err_add_device:
- usb_del_gadget_udc(&fusb300->gadget);
-
err_add_udc:
fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index 6ba444ae8dd5..ae811d8d38b4 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -111,8 +111,8 @@
/*
* * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 )
* */
+#define FUSB300_EPSET0_STL_CLR (1 << 3)
#define FUSB300_EPSET0_CLRSEQNUM (1 << 2)
-#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1)
#define FUSB300_EPSET0_STL (1 << 0)
/*
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 3b343b23e4b0..787a78e92aa2 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -13,7 +13,6 @@
#define pr_fmt(fmt) "g_ffs: " fmt
#include <linux/module.h>
-
/*
* kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
@@ -38,13 +37,16 @@
# include "u_ether.c"
static u8 gfs_hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
# ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
# endif
#else
-# define gether_cleanup() do { } while (0)
-# define gether_setup(gadget, hostaddr) ((int)0)
+# define the_dev NULL
+# define gether_cleanup(dev) do { } while (0)
# define gfs_hostaddr NULL
+struct eth_dev;
#endif
#include "f_fs.c"
@@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
struct gfs_configuration {
struct usb_configuration c;
- int (*eth)(struct usb_configuration *c, u8 *ethaddr);
+ int (*eth)(struct usb_configuration *c, u8 *ethaddr,
+ struct eth_dev *dev);
} gfs_configurations[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
{
@@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev)
if (missing_funcs)
return -ENODEV;
-
- ret = gether_setup(cdev->gadget, gfs_hostaddr);
- if (unlikely(ret < 0))
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+ the_dev = gether_setup(cdev->gadget, gfs_hostaddr);
+#endif
+ if (IS_ERR(the_dev)) {
+ ret = PTR_ERR(the_dev);
goto error_quick;
+ }
gfs_ether_setup = true;
ret = usb_string_ids_tab(cdev, gfs_strings);
@@ -386,7 +392,7 @@ error_unbind:
for (i = 0; i < func_num; i++)
functionfs_unbind(ffs_tab[i].ffs_data);
error:
- gether_cleanup();
+ gether_cleanup(the_dev);
error_quick:
gfs_ether_setup = false;
return ret;
@@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
* do...?
*/
if (gfs_ether_setup)
- gether_cleanup();
+ gether_cleanup(the_dev);
gfs_ether_setup = false;
for (i = func_num; i--; )
@@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c)
}
if (gc->eth) {
- ret = gc->eth(c, gfs_hostaddr);
+ ret = gc->eth(c, gfs_hostaddr, the_dev);
if (unlikely(ret < 0))
return ret;
}
@@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c)
#ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev)
{
return can_support_ecm(c->cdev->gadget)
- ? ecm_bind_config(c, ethaddr)
- : geth_bind_config(c, ethaddr);
+ ? ecm_bind_config(c, ethaddr, dev)
+ : geth_bind_config(c, ethaddr, dev);
}
#endif
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 57a547049df5..480eeb7cfd92 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -52,8 +52,6 @@
#define DRIVER_DESC "TC86C001 USB Device Controller"
#define DRIVER_VERSION "30-Oct 2003"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
static const char driver_name [] = "goku_udc";
static const char driver_desc [] = DRIVER_DESC;
@@ -276,7 +274,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue);
return &req->req;
}
@@ -1343,7 +1340,6 @@ static int goku_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/*
* then enable host detection and ep0; and we're ready
@@ -1383,7 +1379,6 @@ static int goku_udc_stop(struct usb_gadget *g,
dev->driver = NULL;
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
return 0;
}
@@ -1705,8 +1700,6 @@ static void goku_remove(struct pci_dev *pdev)
pci_resource_len (pdev, 0));
if (dev->enabled)
pci_disable_device(pdev);
- if (dev->registered)
- device_unregister(&dev->gadget.dev);
pci_set_drvdata(pdev, NULL);
dev->regs = NULL;
@@ -1745,10 +1738,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_FULL;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name;
/* now all the pci goodies ... */
@@ -1799,13 +1788,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
proc_create_data(proc_node_name, 0, NULL, &udc_proc_fops, dev);
#endif
- retval = device_register(&dev->gadget.dev);
- if (retval) {
- put_device(&dev->gadget.dev);
- goto err;
- }
- dev->registered = 1;
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto err;
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index b4470d2b1d86..86d2adafe149 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -250,8 +250,7 @@ struct goku_udc {
got_region:1,
req_config:1,
configured:1,
- enabled:1,
- registered:1;
+ enabled:1;
/* pci state used to access those endpoints */
struct pci_dev *pdev;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 5bd930d779b9..b5cebd6b0d7a 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget,
imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
/* first hook up the driver ... */
imx_usb->driver = driver;
- imx_usb->gadget.dev.driver = &driver->driver;
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
__func__, driver->driver.name);
@@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget,
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
- imx_usb->gadget.dev.driver = NULL;
imx_usb->driver = NULL;
D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
@@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev)
imx_usb->clk = clk;
imx_usb->dev = &pdev->dev;
- device_initialize(&imx_usb->gadget.dev);
-
- imx_usb->gadget.dev.parent = &pdev->dev;
- imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- ret = device_add(&imx_usb->gadget.dev);
- if (retval)
- goto fail4;
-
platform_set_drvdata(pdev, imx_usb);
usb_init_data(imx_usb);
@@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
if (ret)
- goto fail5;
+ goto fail4;
return 0;
-fail5:
- device_unregister(&imx_usb->gadget.dev);
fail4:
for (i = 0; i < IMX_USB_NB_EP + 1; i++)
free_irq(imx_usb->usbd_int[i], imx_usb);
@@ -1509,7 +1496,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
int i;
usb_del_gadget_udc(&imx_usb->gadget);
- device_unregister(&imx_usb->gadget.dev);
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
index 1049d3745d7a..67128be1e1b7 100644
--- a/drivers/usb/gadget/lpc32xx_udc.c
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
status = req->req.status;
if (ep->lep) {
- enum dma_data_direction direction;
-
- if (ep->is_in)
- direction = DMA_TO_DEVICE;
- else
- direction = DMA_FROM_DEVICE;
-
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- direction);
- req->req.dma = 0;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- direction);
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in);
/* Free DDs */
udc_dd_free(udc, req->dd_desc_ptr);
@@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
}
if (ep->lep) {
- enum dma_data_direction direction;
struct lpc32xx_usbd_dd_gad *dd;
- /* Map DMA pointer */
- if (ep->is_in)
- direction = DMA_TO_DEVICE;
- else
- direction = DMA_FROM_DEVICE;
-
- if (req->req.dma == 0) {
- req->req.dma = dma_map_single(
- ep->udc->gadget.dev.parent,
- req->req.buf, req->req.length, direction);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(
- ep->udc->gadget.dev.parent, req->req.dma,
- req->req.length, direction);
- req->mapped = 0;
- }
+ status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in);
+ if (status)
+ return status;
/* For the request, build a list of DDs */
dd = udc_dd_alloc(udc);
@@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget,
}
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1;
udc->selfpowered = 1;
@@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget,
}
udc->enabled = 0;
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
return 0;
@@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)
udc_disable(udc);
udc_reinit(udc);
- retval = device_register(&udc->gadget.dev);
- if (retval < 0) {
- dev_err(udc->dev, "Device registration failure\n");
- goto dev_register_fail;
- }
-
/* Request IRQs - low and high priority USB device IRQs are routed to
* the same handler, while the DMA interrupt is routed elsewhere */
retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
@@ -3320,8 +3281,6 @@ irq_dev_fail:
irq_hp_fail:
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
irq_lp_fail:
- device_unregister(&udc->gadget.dev);
-dev_register_fail:
dma_pool_destroy(udc->dd_cache);
dma_alloc_fail:
dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
@@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
free_irq(udc->udp_irq[IRQ_USB_HP], udc);
free_irq(udc->udp_irq[IRQ_USB_LP], udc);
- device_unregister(&udc->gadget.dev);
-
clk_disable(udc->usb_otg_clk);
clk_put(udc->usb_otg_clk);
clk_disable(udc->usb_slv_clk);
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index c1b8c2dd808d..866ef0999247 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
m66592->driver = driver;
- m66592->gadget.dev.driver = &driver->driver;
m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
@@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g,
m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
driver->unbind(&m66592->gadget);
- m66592->gadget.dev.driver = NULL;
init_controller(m66592);
disable_controller(m66592);
@@ -1538,7 +1536,6 @@ static int __exit m66592_remove(struct platform_device *pdev)
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
usb_del_gadget_udc(&m66592->gadget);
- device_del(&m66592->gadget.dev);
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
@@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, m66592);
m66592->gadget.ops = &m66592_gadget_ops;
- device_initialize(&m66592->gadget.dev);
- dev_set_name(&m66592->gadget.dev, "gadget");
m66592->gadget.max_speed = USB_SPEED_HIGH;
- m66592->gadget.dev.parent = &pdev->dev;
- m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
- m66592->gadget.dev.release = pdev->dev.release;
m66592->gadget.name = udc_name;
init_timer(&m66592->timer);
@@ -1674,12 +1666,6 @@ static int __init m66592_probe(struct platform_device *pdev)
init_controller(m66592);
- ret = device_add(&m66592->gadget.dev);
- if (ret) {
- pr_err("device_add error (%d)\n", ret);
- goto err_device_add;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
if (ret)
goto err_add_udc;
@@ -1688,9 +1674,6 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_del(&m66592->gadget.dev);
-
-err_device_add:
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
clean_up3:
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 20bbbf917fc2..4a45e80c6e38 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -135,8 +135,8 @@ static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
-static unsigned char tty_line;
static struct usb_function_instance *fi_acm;
+static struct eth_dev *the_dev;
/********** RNDIS **********/
@@ -152,13 +152,15 @@ static __init int rndis_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- ret = rndis_bind_config(c, hostaddr);
+ ret = rndis_bind_config(c, hostaddr, the_dev);
if (ret < 0)
return ret;
f_acm_rndis = usb_get_function(fi_acm);
- if (IS_ERR(f_acm_rndis))
+ if (IS_ERR(f_acm_rndis)) {
+ ret = PTR_ERR(f_acm_rndis);
goto err_func_acm;
+ }
ret = usb_add_function(c, f_acm_rndis);
if (ret)
@@ -214,7 +216,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- ret = ecm_bind_config(c, hostaddr);
+ ret = ecm_bind_config(c, hostaddr, the_dev);
if (ret < 0)
return ret;
@@ -269,7 +271,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
static int __ref multi_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
- struct f_serial_opts *opts;
int status;
if (!can_support_ecm(cdev->gadget)) {
@@ -279,24 +280,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
}
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* set up serial link layer */
- status = gserial_alloc_line(&tty_line);
- if (status < 0)
- goto fail0;
-
fi_acm = usb_get_function_instance("acm");
if (IS_ERR(fi_acm)) {
status = PTR_ERR(fi_acm);
- goto fail0dot5;
+ goto fail0;
}
- opts = container_of(fi_acm, struct f_serial_opts, func_inst);
- opts->port_num = tty_line;
-
/* set up mass storage function */
{
void *retp;
@@ -334,10 +328,8 @@ fail2:
fsg_common_put(&fsg_common);
fail1:
usb_put_function_instance(fi_acm);
-fail0dot5:
- gserial_free_line(tty_line);
fail0:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
@@ -350,8 +342,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev)
usb_put_function(f_acm_rndis);
#endif
usb_put_function_instance(fi_acm);
- gserial_free_line(tty_line);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c
index b5cea273c957..58288e9cf728 100644
--- a/drivers/usb/gadget/mv_u3d_core.c
+++ b/drivers/usb/gadget/mv_u3d_core.c
@@ -30,9 +30,6 @@
#include <linux/platform_device.h>
#include <linux/platform_data/mv_usb.h>
#include <linux/clk.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
#include "mv_u3d.h"
@@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
struct mv_u3d_trb *curr_trb;
dma_addr_t cur_deq_lo;
struct mv_u3d_ep_context *curr_ep_context;
- int trb_complete, actual, remaining_length;
+ int trb_complete, actual, remaining_length = 0;
int direction, ep_num;
int retval = 0;
u32 tmp, status, length;
@@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index,
*/
static
void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d;
@@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0;
}
- dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n",
- __func__, _ep->name, (u32)req);
+ dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n",
+ __func__, _ep->name, req);
/* catch various bogus parameters */
if (!req->req.complete || !req->req.buf
|| !list_empty(&req->queue)) {
dev_err(u3d->dev,
- "%s, bad params, _req: 0x%x,"
- "req->req.complete: 0x%x, req->req.buf: 0x%x,"
+ "%s, bad params, _req: 0x%p,"
+ "req->req.complete: 0x%p, req->req.buf: 0x%p,"
"list_empty: 0x%x\n",
- __func__, (u32)_req,
- (u32)req->req.complete, (u32)req->req.buf,
- (u32)list_empty(&req->queue));
+ __func__, _req,
+ req->req.complete, req->req.buf,
+ list_empty(&req->queue));
return -EINVAL;
}
if (unlikely(!ep->ep.desc)) {
@@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct mv_u3d_req, queue);
/* Point first TRB of next request to the EP context. */
- iowrite32((u32) next_req->trb_head,
+ iowrite32((unsigned long) next_req->trb_head,
&ep_context->trb_addr_lo);
} else {
struct mv_u3d_ep_context *ep_context;
@@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g,
/* hook up the driver ... */
driver->driver.bus = NULL;
u3d->driver = driver;
- u3d->gadget.dev.driver = &driver->driver;
u3d->ep0_dir = USB_DIR_OUT;
@@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g,
spin_unlock_irqrestore(&u3d->lock, flags);
- u3d->gadget.dev.driver = NULL;
u3d->driver = NULL;
return 0;
@@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup)
static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num,
struct usb_ctrlrequest *setup)
+ __releases(&u3c->lock)
+ __acquires(&u3c->lock)
{
bool delegate = false;
@@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static void mv_u3d_gadget_release(struct device *dev)
-{
- dev_dbg(dev, "%s\n", __func__);
-}
-
static int mv_u3d_remove(struct platform_device *dev)
{
struct mv_u3d *u3d = platform_get_drvdata(dev);
@@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev)
clk_put(u3d->clk);
- device_unregister(&u3d->gadget.dev);
-
platform_set_drvdata(dev, NULL);
kfree(u3d);
@@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->dev = &dev->dev;
u3d->vbus = pdata->vbus;
- u3d->clk = clk_get(&dev->dev, pdata->clkname[0]);
+ u3d->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(u3d->clk)) {
retval = PTR_ERR(u3d->clk);
goto err_get_clk;
@@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev)
retval = -EBUSY;
goto err_map_cap_regs;
} else {
- dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n",
- (unsigned int)r->start, (unsigned int)u3d->cap_regs);
+ dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n",
+ (unsigned long) r->start,
+ (unsigned long) u3d->cap_regs);
}
/* we will access controller register, so enable the u3d controller */
@@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev)
}
}
- u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs
+ u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs
+ MV_U3D_USB3_OP_REGS_OFFSET);
- u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs
+ u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs
+ ioread32(&u3d->cap_regs->vuoff));
u3d->max_eps = 16;
@@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev)
u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&u3d->gadget.dev, "gadget");
- u3d->gadget.dev.parent = &dev->dev;
- u3d->gadget.dev.dma_mask = dev->dev.dma_mask;
- u3d->gadget.dev.release = mv_u3d_gadget_release;
u3d->gadget.name = driver_name; /* gadget name */
- retval = device_register(&u3d->gadget.dev);
- if (retval)
- goto err_register_gadget_device;
-
mv_u3d_eps_init(u3d);
/* external vbus detection */
@@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev)
return 0;
err_unregister:
- device_unregister(&u3d->gadget.dev);
-err_register_gadget_device:
free_irq(u3d->irq, &dev->dev);
err_request_irq:
err_get_irq:
@@ -2021,7 +2004,7 @@ err_pdata:
return retval;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mv_u3d_suspend(struct device *dev)
{
struct mv_u3d *u3d = dev_get_drvdata(dev);
@@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev)
return 0;
}
-
-SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
#endif
+static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume);
+
static void mv_u3d_shutdown(struct platform_device *dev)
{
struct mv_u3d *u3d = dev_get_drvdata(&dev->dev);
@@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev)
static struct platform_driver mv_u3d_driver = {
.probe = mv_u3d_probe,
- .remove = __exit_p(mv_u3d_remove),
+ .remove = mv_u3d_remove,
.shutdown = mv_u3d_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "mv-u3d",
-#ifdef CONFIG_PM
.pm = &mv_u3d_pm_ops,
-#endif
},
};
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 9073436d8b24..be77f207dbaf 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -222,8 +222,7 @@ struct mv_udc {
struct mv_usb_platform_data *pdata;
/* some SOC has mutiple clock sources for USB*/
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
/* endpoint data structure */
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index c8cf959057fe..c2a57023e467 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index,
* request is still in progress.
*/
static void done(struct mv_ep *ep, struct mv_req *req, int status)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
struct mv_udc *udc = NULL;
unsigned char stopped = ep->stopped;
@@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma);
}
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
if (status && (status != -ESHUTDOWN))
dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u",
@@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->ep = ep;
/* map virtual address to hardware */
- if (req->req.dma == DMA_ADDR_INVALID) {
- req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
- req->req.buf,
- req->req.length, ep_dir(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 1;
- } else {
- dma_sync_single_for_device(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ep_dir(ep)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- req->mapped = 0;
- }
+ retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep));
+ if (retval)
+ return retval;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
@@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return 0;
err_unmap_dma:
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep));
return retval;
}
@@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = {
static void udc_clock_enable(struct mv_udc *udc)
{
- unsigned int i;
-
- for (i = 0; i < udc->clknum; i++)
- clk_prepare_enable(udc->clk[i]);
+ clk_prepare_enable(udc->clk);
}
static void udc_clock_disable(struct mv_udc *udc)
{
- unsigned int i;
-
- for (i = 0; i < udc->clknum; i++)
- clk_disable_unprepare(udc->clk[i]);
+ clk_disable_unprepare(udc->clk);
}
static void udc_stop(struct mv_udc *udc)
@@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
/* hook up the driver ... */
driver->driver.bus = NULL;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
udc->usb_state = USB_STATE_ATTACHED;
udc->ep0_state = WAIT_FOR_SETUP;
@@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n");
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
return retval;
}
}
@@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget,
spin_unlock_irqrestore(&udc->lock, flags);
/* unbind gadget driver */
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
return 0;
@@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
return 0;
out:
- if (req->mapped) {
- dma_unmap_single(ep->udc->gadget.dev.parent,
- req->req.dma, req->req.length,
- ((ep_dir(ep) == EP_DIR_IN) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE));
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep));
return retval;
}
@@ -1695,6 +1647,8 @@ out:
static void handle_setup_packet(struct mv_udc *udc, u8 ep_num,
struct usb_ctrlrequest *setup)
+ __releases(&ep->udc->lock)
+ __acquires(&ep->udc->lock)
{
bool delegate = false;
@@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc)
}
}
-void irq_process_reset(struct mv_udc *udc)
+static void irq_process_reset(struct mv_udc *udc)
{
u32 tmp;
unsigned int loops;
@@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev)
mv_udc_disable(udc);
- device_unregister(&udc->gadget.dev);
-
/* free dev, wait for the release() finished */
wait_for_completion(udc->done);
@@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev)
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
struct mv_udc *udc;
int retval = 0;
- int clk_i = 0;
struct resource *r;
size_t size;
@@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum;
- udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL);
if (udc == NULL) {
dev_err(&pdev->dev, "failed to allocate memory for udc\n");
return -ENOMEM;
@@ -2173,26 +2123,24 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->dev = pdev;
-#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG) {
udc->transceiver = devm_usb_get_phy(&pdev->dev,
USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(udc->transceiver)) {
+ if (IS_ERR(udc->transceiver)) {
+ retval = PTR_ERR(udc->transceiver);
+
+ if (retval == -ENXIO)
+ return retval;
+
udc->transceiver = NULL;
- return -ENODEV;
+ return -EPROBE_DEFER;
}
}
-#endif
- udc->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
- udc->clk[clk_i] = devm_clk_get(&pdev->dev,
- pdata->clkname[clk_i]);
- if (IS_ERR(udc->clk[clk_i])) {
- retval = PTR_ERR(udc->clk[clk_i]);
- return retval;
- }
- }
+ /* udc only have one sysclk. */
+ udc->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(udc->clk))
+ return PTR_ERR(udc->clk);
r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs");
if (r == NULL) {
@@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev)
udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
- udc->gadget.dev.release = gadget_release;
udc->gadget.name = driver_name; /* gadget name */
- retval = device_register(&udc->gadget.dev);
- if (retval)
- goto err_destroy_dma;
-
eps_init(udc);
/* VBUS detect: we can disable/enable clock on demand.*/
@@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev)
if (!udc->qwork) {
dev_err(&pdev->dev, "cannot create workqueue\n");
retval = -ENOMEM;
- goto err_unregister;
+ goto err_destroy_dma;
}
INIT_WORK(&udc->vbus_work, mv_udc_vbus_work);
@@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev)
else
udc->vbus_active = 1;
- retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+ gadget_release);
if (retval)
goto err_create_workqueue;
@@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev)
err_create_workqueue:
destroy_workqueue(udc->qwork);
-err_unregister:
- device_unregister(&udc->gadget.dev);
err_destroy_dma:
dma_pool_destroy(udc->dtd_pool);
err_free_dma:
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index a22ad9af0565..3b02fd4649ce 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = {
NULL,
};
+struct eth_dev *the_dev;
static u8 hostaddr[ETH_ALEN];
/*-------------------------------------------------------------------------*/
@@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- return ncm_bind_config(c, hostaddr);
+ return ncm_bind_config(c, hostaddr, the_dev);
}
static struct usb_configuration ncm_config_driver = {
@@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
int status;
/* set up network link layer */
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
- return status;
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev))
+ return PTR_ERR(the_dev);
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- gether_cleanup();
+ gether_cleanup(the_dev);
return status;
}
static int __exit gncm_unbind(struct usb_composite_dev *cdev)
{
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 32524b631959..f1e50a3e322d 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -58,7 +58,6 @@ static const char * const ep_name[] = {
"ep-a", "ep-b", "ep-c",
};
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#ifdef CONFIG_USB_NET2272_DMA
/*
* use_dma: the NET2272 can use an external DMA controller.
@@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&req->queue);
return &req->req;
@@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
}
}
- if (likely(req != 0))
+ if (likely(req))
list_add_tail(&req->queue, &ep->queue);
if (likely(!list_empty(&ep->queue)))
@@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget,
dev->softconnect = 1;
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget,
stop_activity(dev, driver);
spin_unlock_irqrestore(&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
@@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep)
| (ep->dev->dma_eot_polarity << EOT_POLARITY)
| (ep->dev->dma_dack_polarity << DACK_POLARITY)
| (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
- | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT));
+ | (ep->dma << DMA_ENDPOINT_SELECT));
ep->dev->dma_busy = 0;
@@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep)
ep->irqs++;
dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
- ep->ep.name, stat0, stat1, req ? &req->req : 0);
+ ep->ep.name, stat0, stat1, req ? &req->req : NULL);
net2272_ep_write(ep, EP_STAT0, stat0 &
~((1 << NAK_OUT_PACKETS)
@@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev)
free_irq(dev->irq, dev);
iounmap(dev->base_addr);
- device_unregister(&dev->gadget.dev);
device_remove_file(dev->dev, &dev_attr_registers);
dev_info(dev->dev, "unbind\n");
@@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq)
ret->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&ret->gadget.dev, "gadget");
- ret->gadget.dev.parent = dev;
- ret->gadget.dev.dma_mask = dev->dma_mask;
- ret->gadget.dev.release = net2272_gadget_release;
ret->gadget.name = driver_name;
return ret;
@@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
dma_mode_string());
dev_info(dev->dev, "version: %s\n", driver_vers);
- ret = device_register(&dev->gadget.dev);
- if (ret)
- goto err_irq;
ret = device_create_file(dev->dev, &dev_attr_registers);
if (ret)
- goto err_dev_reg;
+ goto err_irq;
- ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
+ ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget,
+ net2272_gadget_release);
if (ret)
goto err_add_udc;
@@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
err_add_udc:
device_remove_file(dev->dev, &dev_attr_registers);
- err_dev_reg:
- device_unregister(&dev->gadget.dev);
err_irq:
free_irq(dev->irq, dev);
err:
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 3bd0f992fb49..fbd006ab31d3 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -65,7 +65,6 @@
#define DRIVER_DESC "PLX NET228x USB Peripheral Controller"
#define DRIVER_VERSION "2005 Sept 27"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */
#define USE_RDK_LEDS /* GPIO pins control three LEDs */
@@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
if (!req)
return NULL;
- req->req.dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD (&req->queue);
/* this dma descriptor may be swapped with the previous dummy */
@@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
return NULL;
}
td->dmacount = 0; /* not VALID */
- td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr;
req->td = td;
}
@@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget,
dev->softconnect = 1;
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
if (retval) goto err_unbind;
@@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,
err_func:
device_remove_file (&dev->pdev->dev, &dev_attr_function);
err_unbind:
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
return retval;
}
@@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget,
stop_activity (dev, driver);
spin_unlock_irqrestore (&dev->lock, flags);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
net2280_led_active (dev, 0);
@@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep)
return;
/* manual DMA queue advance after short OUT */
- if (likely (ep->dma != 0)) {
+ if (likely (ep->dma)) {
if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
u32 count;
int stopped = ep->stopped;
@@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device and interface status */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto delegate;
- if ((e = get_ep_by_addr (dev, w_index)) == 0
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL
|| w_length > 2)
goto do_stall;
@@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, w_index)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall;
if (e->wedged) {
VDEBUG(dev, "%s wedged, halt not cleared\n",
@@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, w_index)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == NULL)
goto do_stall;
if (e->ep.name == ep0name)
goto do_stall;
@@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev)
pci_resource_len (pdev, 0));
if (dev->enabled)
pci_disable_device (pdev);
- device_unregister (&dev->gadget.dev);
device_remove_file (&pdev->dev, &dev_attr_registers);
pci_set_drvdata (pdev, NULL);
@@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
dev->gadget.max_speed = USB_SPEED_HIGH;
/* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name;
/* now all the pci goodies ... */
@@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
td->dmacount = 0; /* not VALID */
- td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
td->dmadesc = td->dmaaddr;
dev->ep [i].dummy = td;
}
@@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled");
- retval = device_register (&dev->gadget.dev);
- if (retval) goto done;
retval = device_create_file (&pdev->dev, &dev_attr_registers);
if (retval) goto done;
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto done;
return 0;
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
index def37403989a..3b344b41a167 100644
--- a/drivers/usb/gadget/nokia.c
+++ b/drivers/usb/gadget/nokia.c
@@ -37,11 +37,9 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
-#define USB_FACM_INCLUDED
-#include "f_acm.c"
+#define USBF_OBEX_INCLUDED
#include "f_ecm.c"
#include "f_obex.c"
-#include "f_serial.c"
#include "f_phonet.c"
#include "u_ether.c"
@@ -98,20 +96,40 @@ MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/
-
+static struct usb_function *f_acm_cfg1;
+static struct usb_function *f_acm_cfg2;
static u8 hostaddr[ETH_ALEN];
+static struct eth_dev *the_dev;
enum {
TTY_PORT_OBEX0,
TTY_PORT_OBEX1,
- TTY_PORT_ACM,
TTY_PORTS_MAX,
};
static unsigned char tty_lines[TTY_PORTS_MAX];
+static struct usb_configuration nokia_config_500ma_driver = {
+ .label = "Bus Powered",
+ .bConfigurationValue = 1,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .MaxPower = 500,
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+ .label = "Self Powered",
+ .bConfigurationValue = 2,
+ /* .iConfiguration = DYNAMIC */
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .MaxPower = 100,
+};
+
+static struct usb_function_instance *fi_acm;
+
static int __init nokia_bind_config(struct usb_configuration *c)
{
+ struct usb_function *f_acm;
int status = 0;
status = phonet_bind_config(c);
@@ -126,33 +144,32 @@ static int __init nokia_bind_config(struct usb_configuration *c)
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
- status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]);
- if (status)
- printk(KERN_DEBUG "could not bind acm config\n");
+ f_acm = usb_get_function(fi_acm);
+ if (IS_ERR(f_acm))
+ return PTR_ERR(f_acm);
- status = ecm_bind_config(c, hostaddr);
+ status = usb_add_function(c, f_acm);
if (status)
- printk(KERN_DEBUG "could not bind ecm config\n");
+ goto err_conf;
+
+ status = ecm_bind_config(c, hostaddr, the_dev);
+ if (status) {
+ pr_debug("could not bind ecm config %d\n", status);
+ goto err_ecm;
+ }
+ if (c == &nokia_config_500ma_driver)
+ f_acm_cfg1 = f_acm;
+ else
+ f_acm_cfg2 = f_acm;
return status;
+err_ecm:
+ usb_remove_function(c, f_acm);
+err_conf:
+ usb_put_function(f_acm);
+ return status;
}
-static struct usb_configuration nokia_config_500ma_driver = {
- .label = "Bus Powered",
- .bConfigurationValue = 1,
- /* .iConfiguration = DYNAMIC */
- .bmAttributes = USB_CONFIG_ATT_ONE,
- .MaxPower = 500,
-};
-
-static struct usb_configuration nokia_config_100ma_driver = {
- .label = "Self Powered",
- .bConfigurationValue = 2,
- /* .iConfiguration = DYNAMIC */
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .MaxPower = 100,
-};
-
static int __init nokia_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
@@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
goto err_ether;
}
- status = gether_setup(cdev->gadget, hostaddr);
- if (status < 0)
+ the_dev = gether_setup(cdev->gadget, hostaddr);
+ if (IS_ERR(the_dev)) {
+ status = PTR_ERR(the_dev);
goto err_ether;
+ }
status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0)
@@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
if (!gadget_supports_altsettings(gadget))
goto err_usb;
+ fi_acm = usb_get_function_instance("acm");
+ if (IS_ERR(fi_acm))
+ goto err_usb;
+
/* finally register the configuration */
status = usb_add_config(cdev, &nokia_config_500ma_driver,
nokia_bind_config);
if (status < 0)
- goto err_usb;
+ goto err_acm_inst;
status = usb_add_config(cdev, &nokia_config_100ma_driver,
nokia_bind_config);
if (status < 0)
- goto err_usb;
+ goto err_put_cfg1;
usb_composite_overwrite_options(cdev, &coverwrite);
dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
return 0;
+err_put_cfg1:
+ usb_put_function(f_acm_cfg1);
+err_acm_inst:
+ usb_put_function_instance(fi_acm);
err_usb:
- gether_cleanup();
+ gether_cleanup(the_dev);
err_ether:
cur_line--;
while (cur_line >= 0)
@@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{
int i;
+ usb_put_function(f_acm_cfg1);
+ usb_put_function(f_acm_cfg2);
+ usb_put_function_instance(fi_acm);
gphonet_cleanup();
for (i = 0; i < TTY_PORTS_MAX; i++)
gserial_free_line(tty_lines[i]);
- gether_cleanup();
+ gether_cleanup(the_dev);
return 0;
}
@@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void)
usb_composite_unregister(&nokia_driver);
}
module_exit(nokia_cleanup);
-
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index f8445653577f..b8ed74a823cb 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g,
/* hook up the driver */
driver->driver.bus = NULL;
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
if (udc->dc_clk != NULL)
@@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g,
ERR("can't bind to transceiver\n");
if (driver->unbind) {
driver->unbind(&udc->gadget);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
}
goto done;
@@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g,
udc_quiesce(udc);
spin_unlock_irqrestore(&udc->lock, flags);
- udc->gadget.dev.driver = NULL;
udc->driver = NULL;
if (udc->dc_clk != NULL)
@@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_FULL;
udc->gadget.name = driver_name;
-
- device_initialize(&udc->gadget.dev);
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.release = omap_udc_release;
- udc->gadget.dev.parent = &odev->dev;
- if (use_dma)
- udc->gadget.dev.dma_mask = odev->dev.dma_mask;
-
udc->transceiver = xceiv;
/* ep0 is special; put it right after the SETUP buffer */
@@ -2912,14 +2901,13 @@ bad_on_1710:
}
create_proc_file();
- status = device_add(&udc->gadget.dev);
+ status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget,
+ omap_udc_release);
if (status)
goto cleanup4;
- status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
- if (!status)
- return status;
- /* If fail, fall through */
+ return 0;
+
cleanup4:
remove_proc_file();
@@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev)
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
- device_unregister(&udc->gadget.dev);
wait_for_completion(&done);
return 0;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index a787a8ef672b..24174e1d1564 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -358,7 +358,6 @@ struct pch_udc_dev {
prot_stall:1,
irq_registered:1,
mem_region:1,
- registered:1,
suspended:1,
connected:1,
vbus_session:1,
@@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
*/
static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
int status)
+ __releases(&dev->lock)
+ __acquires(&dev->lock)
{
struct pch_udc_dev *dev;
unsigned halted = ep->halted;
@@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev)
* @dev: Reference to the device structure
*/
static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
+ __releases(&dev->lock)
+ __acquires(&dev->lock)
{
u32 stat;
int setup_supported;
@@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g,
driver->driver.bus = NULL;
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
/* get ready for ep0 traffic */
pch_udc_setup_ep0(dev);
@@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g,
pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK);
/* Assures that there are no pending requests with this driver */
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dev->connected = 0;
@@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev)
pci_resource_len(pdev, PCH_UDC_PCI_BAR));
if (dev->active)
pci_disable_device(pdev);
- if (dev->registered)
- device_unregister(&dev->gadget.dev);
kfree(dev);
pci_set_drvdata(pdev, NULL);
}
@@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev,
if (retval)
goto finished;
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
dev->gadget.name = KBUILD_MODNAME;
dev->gadget.max_speed = USB_SPEED_HIGH;
- retval = device_register(&dev->gadget.dev);
- if (retval)
- goto finished;
- dev->registered = 1;
-
/* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev);
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget,
+ gadget_release);
if (retval)
goto finished;
return 0;
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index d0f37484b6b0..ef47495dec8f 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
dev->pullup = 1;
/* ... then enable host detection and ep0; and we're ready
@@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g,
if (!IS_ERR_OR_NULL(dev->transceiver))
(void) otg_set_peripheral(dev->transceiver->otg, NULL);
- dev->gadget.dev.driver = NULL;
dev->driver = NULL;
dump_state(dev);
@@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->timer.function = udc_watchdog;
dev->timer.data = (unsigned long) dev;
- device_initialize(&dev->gadget.dev);
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- retval = device_add(&dev->gadget.dev);
- if (retval) {
- dev->driver = NULL;
- dev->gadget.dev.driver = NULL;
- goto err_device_add;
- }
-
the_controller = dev;
platform_set_drvdata(pdev, dev);
@@ -2199,8 +2186,6 @@ lubbock_fail0:
free_irq(irq, dev);
#endif
err_irq1:
- device_unregister(&dev->gadget.dev);
- err_device_add:
if (gpio_is_valid(dev->mach->gpio_pullup))
gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup:
@@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&dev->gadget);
- device_unregister(&dev->gadget.dev);
dev->pullup = 0;
pullup(dev);
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 2fc867652ef5..6b4c7d95853f 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -24,14 +24,12 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
-
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
+#include <linux/byteorder/generic.h>
+#include <linux/platform_data/pxa2xx_udc.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <mach/udc.h>
#include "pxa27x_udc.h"
@@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
*
* Find the physical pxa27x ep, and setup its UDCCR
*/
-static __init void pxa_ep_setup(struct pxa_ep *ep)
+static void pxa_ep_setup(struct pxa_ep *ep)
{
u32 new_udccr;
@@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep)
*
* Setup all pxa physical endpoints, except ep0
*/
-static __init void pxa_eps_setup(struct pxa_udc *dev)
+static void pxa_eps_setup(struct pxa_udc *dev)
{
unsigned int i;
@@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc)
* Initializes gadget endpoint list, endpoints locks. No action is taken
* on the hardware.
*/
-static __init void udc_init_data(struct pxa_udc *dev)
+static void udc_init_data(struct pxa_udc *dev)
{
int i;
struct pxa_ep *ep;
@@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) {
@@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
fail:
udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
return retval;
}
@@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g,
udc->driver = NULL;
-
if (!IS_ERR_OR_NULL(udc->transceiver))
return otg_set_peripheral(udc->transceiver->otg, NULL);
return 0;
@@ -2413,7 +2408,7 @@ static struct pxa_udc memory = {
* Perform basic init : allocates udc clock, creates sysfs files, requests
* irq.
*/
-static int __init pxa_udc_probe(struct platform_device *pdev)
+static int pxa_udc_probe(struct platform_device *pdev)
{
struct resource *regs;
struct pxa_udc *udc = &memory;
@@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_map;
}
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = NULL;
udc->vbus_sensed = 0;
the_controller = udc;
@@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
goto err_irq;
}
- retval = device_add(&udc->gadget.dev);
- if (retval) {
- dev_err(udc->dev, "device_add error %d\n", retval);
- goto err_dev_add;
- }
-
retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (retval)
goto err_add_udc;
@@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_unregister(&udc->gadget.dev);
-err_dev_add:
free_irq(udc->irq, udc);
err_irq:
iounmap(udc->regs);
@@ -2506,13 +2490,12 @@ err_clk:
* pxa_udc_remove - removes the udc device driver
* @_dev: platform device
*/
-static int __exit pxa_udc_remove(struct platform_device *_dev)
+static int pxa_udc_remove(struct platform_device *_dev)
{
struct pxa_udc *udc = platform_get_drvdata(_dev);
int gpio = udc->mach->gpio_pullup;
usb_del_gadget_udc(&udc->gadget);
- device_del(&udc->gadget.dev);
usb_gadget_unregister_driver(udc->driver);
free_irq(udc->irq, udc);
pxa_cleanup_debugfs(udc);
@@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = {
.name = "pxa27x-udc",
.owner = THIS_MODULE,
},
- .remove = __exit_p(pxa_udc_remove),
+ .probe = pxa_udc_probe,
+ .remove = pxa_udc_remove,
.shutdown = pxa_udc_shutdown,
#ifdef CONFIG_PM
.suspend = pxa_udc_suspend,
@@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = {
#endif
};
-static int __init udc_init(void)
-{
- if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
- return -ENODEV;
-
- printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
- return platform_driver_probe(&udc_driver, pxa_udc_probe);
-}
-module_init(udc_init);
-
-
-static void __exit udc_exit(void)
-{
- platform_driver_unregister(&udc_driver);
-}
-module_exit(udc_exit);
+module_platform_driver(udc_driver);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Robert Jarzmik");
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index f46a1b77ce3e..0b742d171843 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
clk_put(r8a66597->clk);
}
- device_unregister(&r8a66597->gadget.dev);
kfree(r8a66597);
return 0;
}
@@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
r8a66597->gadget.ops = &r8a66597_gadget_ops;
- dev_set_name(&r8a66597->gadget.dev, "gadget");
r8a66597->gadget.max_speed = USB_SPEED_HIGH;
- r8a66597->gadget.dev.parent = &pdev->dev;
- r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
- r8a66597->gadget.dev.release = pdev->dev.release;
r8a66597->gadget.name = udc_name;
- ret = device_register(&r8a66597->gadget.dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "device_register failed\n");
- goto clean_up;
- }
init_timer(&r8a66597->timer);
r8a66597->timer.function = r8a66597_timer;
@@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
clk_name);
ret = PTR_ERR(r8a66597->clk);
- goto clean_up_dev;
+ goto clean_up;
}
clk_enable(r8a66597->clk);
}
@@ -2007,8 +1997,6 @@ clean_up2:
clk_disable(r8a66597->clk);
clk_put(r8a66597->clk);
}
-clean_up_dev:
- device_unregister(&r8a66597->gadget.dev);
clean_up:
if (r8a66597) {
if (r8a66597->sudmac_reg)
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index c26564f29a2c..a3cdc32115d5 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -39,8 +39,6 @@
#include "s3c-hsotg.h"
-#define DMA_ADDR_INVALID (~((dma_addr_t)0))
-
static const char * const s3c_hsotg_supply_names[] = {
"vusb_d", /* digital USB supply, 1.2V */
"vusb_a", /* analog USB supply, 1.1V */
@@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
INIT_LIST_HEAD(&req->queue);
- req->req.dma = DMA_ADDR_INVALID;
return &req->req;
}
@@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_req *hs_req)
{
struct usb_request *req = &hs_req->req;
- enum dma_data_direction dir;
-
- dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
/* ignore this if we're not moving any data */
if (hs_req->req.length == 0)
return;
- if (hs_req->mapped) {
- /* we mapped this, so unmap and remove the dma */
-
- dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
-
- req->dma = DMA_ADDR_INVALID;
- hs_req->mapped = 0;
- } else {
- dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
- }
+ usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
}
/**
@@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct usb_request *req)
{
- enum dma_data_direction dir;
struct s3c_hsotg_req *hs_req = our_req(req);
-
- dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+ int ret;
/* if the length is zero, ignore the DMA data */
if (hs_req->req.length == 0)
return 0;
- if (req->dma == DMA_ADDR_INVALID) {
- dma_addr_t dma;
-
- dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
-
- if (unlikely(dma_mapping_error(hsotg->dev, dma)))
- goto dma_error;
-
- if (dma & 3) {
- dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
- __func__);
-
- dma_unmap_single(hsotg->dev, dma, req->length, dir);
- return -EINVAL;
- }
-
- hs_req->mapped = 1;
- req->dma = dma;
- } else {
- dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
- hs_req->mapped = 0;
- }
+ ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in);
+ if (ret)
+ goto dma_error;
return 0;
@@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
driver->driver.bus = NULL;
hsotg->driver = driver;
- hsotg->gadget.dev.driver = &driver->driver;
hsotg->gadget.dev.of_node = hsotg->dev->of_node;
- hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
@@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
err:
hsotg->driver = NULL;
- hsotg->gadget.dev.driver = NULL;
return ret;
}
@@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
- hsotg->gadget.dev.driver = NULL;
spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -3484,16 +3444,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
}
/**
- * s3c_hsotg_release - release callback for hsotg device
- * @dev: Device to for which release is called
- *
- * Nothing to do as the resource is allocated using devm_ API.
- */
-static void s3c_hsotg_release(struct device *dev)
-{
-}
-
-/**
* s3c_hsotg_probe - probe function for hsotg driver
* @pdev: The platform information for the driver
*/
@@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
}
phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback for pdata */
plat = pdev->dev.platform_data;
if (!plat) {
@@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
- device_initialize(&hsotg->gadget.dev);
-
- dev_set_name(&hsotg->gadget.dev, "gadget");
-
hsotg->gadget.max_speed = USB_SPEED_HIGH;
hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
hsotg->gadget.name = dev_name(dev);
- hsotg->gadget.dev.parent = dev;
- hsotg->gadget.dev.dma_mask = dev->dma_mask;
- hsotg->gadget.dev.release = s3c_hsotg_release;
-
/* reset the system */
clk_prepare_enable(hsotg->clk);
@@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
s3c_hsotg_phy_disable(hsotg);
- ret = device_add(&hsotg->gadget.dev);
- if (ret) {
- put_device(&hsotg->gadget.dev);
- goto err_ep_mem;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
goto err_ep_mem;
@@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev)
}
s3c_hsotg_phy_disable(hsotg);
-
clk_disable_unprepare(hsotg->clk);
- device_unregister(&hsotg->gadget.dev);
return 0;
}
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 458965a1b138..b1f0771fbd3d 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
/**
* s3c_hsudc_stop_activity - Stop activity on all endpoints.
* @hsudc: Device controller for which EP activity is to be stopped.
- * @driver: Reference to the gadget driver which is currently active.
*
* All the endpoints are stopped and any pending transfer requests if any on
* the endpoint are terminated.
@@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
return -EBUSY;
hsudc->driver = driver;
- hsudc->gadget.dev.driver = &driver->driver;
ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
hsudc->supplies);
@@ -1190,7 +1188,6 @@ err_otg:
regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
hsudc->driver = NULL;
- hsudc->gadget.dev.driver = NULL;
return ret;
}
@@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
spin_lock_irqsave(&hsudc->lock, flags);
hsudc->driver = NULL;
- hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
@@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
spin_lock_init(&hsudc->lock);
- dev_set_name(&hsudc->gadget.dev, "gadget");
-
hsudc->gadget.max_speed = USB_SPEED_HIGH;
hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
hsudc->gadget.name = dev_name(dev);
- hsudc->gadget.dev.parent = dev;
- hsudc->gadget.dev.dma_mask = dev->dma_mask;
hsudc->gadget.ep0 = &hsudc->ep[0].ep;
-
hsudc->gadget.is_otg = 0;
hsudc->gadget.is_a_peripheral = 0;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
@@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
disable_irq(hsudc->irq);
local_irq_enable();
- ret = device_register(&hsudc->gadget.dev);
- if (ret) {
- put_device(&hsudc->gadget.dev);
- goto err_add_device;
- }
-
ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
if (ret)
goto err_add_udc;
@@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
return 0;
err_add_udc:
- device_unregister(&hsudc->gadget.dev);
err_add_device:
clk_disable(hsudc->uclk);
err_res:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 08f89652533b..d0e75e1b3ccb 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g,
/* Hook the driver */
udc->driver = driver;
- udc->gadget.dev.driver = &driver->driver;
/* Enable udc */
s3c2410_udc_enable(udc);
@@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
goto err_mem;
}
- device_initialize(&udc->gadget.dev);
- udc->gadget.dev.parent = &pdev->dev;
- udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
-
- /* Bind the driver */
- retval = device_add(&udc->gadget.dev);
- if (retval) {
- dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval);
- goto err_device_add;
- }
-
the_controller = udc;
platform_set_drvdata(pdev, udc);
@@ -1923,8 +1911,6 @@ err_gpio_claim:
err_int:
free_irq(IRQ_USBD, udc);
err_map:
- device_unregister(&udc->gadget.dev);
-err_device_add:
iounmap(base_addr);
err_mem:
release_mem_region(rsrc_start, rsrc_len);
@@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
return -EBUSY;
usb_del_gadget_udc(&udc->gadget);
- device_unregister(&udc->gadget.dev);
debugfs_remove(udc->regs_info);
if (udc_info && !udc_info->udc_command &&
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 68d7bb06ebcb..1f5f978d35d5 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/module.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -28,18 +29,6 @@
#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR
/*-------------------------------------------------------------------------*/
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module. So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "f_obex.c"
-#include "f_serial.c"
-
-/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();
/* Thanks to NetChip Technologies for donating this product ID.
@@ -126,27 +115,6 @@ module_param(n_ports, uint, 0);
MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
/*-------------------------------------------------------------------------*/
-static unsigned char tty_lines[MAX_U_SERIAL_PORTS];
-
-static int __init serial_bind_obex_config(struct usb_configuration *c)
-{
- unsigned i;
- int status = 0;
-
- for (i = 0; i < n_ports && status == 0; i++)
- status = obex_bind_config(c, tty_lines[i]);
- return status;
-}
-
-static int __init serial_bind_gser_config(struct usb_configuration *c)
-{
- unsigned i;
- int status = 0;
-
- for (i = 0; i < n_ports && status == 0; i++)
- status = gser_bind_config(c, tty_lines[i]);
- return status;
-}
static struct usb_configuration serial_config_driver = {
/* .label = f(use_acm) */
@@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev,
goto out;
for (i = 0; i < n_ports; i++) {
- struct f_serial_opts *opts;
fi_serial[i] = usb_get_function_instance(f_name);
if (IS_ERR(fi_serial[i])) {
ret = PTR_ERR(fi_serial[i]);
goto fail;
}
- opts = container_of(fi_serial[i], struct f_serial_opts, func_inst);
- opts->port_num = tty_lines[i];
f_serial[i] = usb_get_function(fi_serial[i]);
if (IS_ERR(f_serial[i])) {
@@ -212,13 +177,6 @@ out:
static int __init gs_bind(struct usb_composite_dev *cdev)
{
int status;
- int cur_line;
-
- for (cur_line = 0; cur_line < n_ports; cur_line++) {
- status = gserial_alloc_line(&tty_lines[cur_line]);
- if (status)
- goto fail;
- }
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
@@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
"acm");
usb_ep_autoconfig_reset(cdev->gadget);
} else if (use_obex)
- status = usb_add_config(cdev, &serial_config_driver,
- serial_bind_obex_config);
- else
- status = usb_add_config(cdev, &serial_config_driver,
- serial_bind_gser_config);
+ status = serial_register_ports(cdev, &serial_config_driver,
+ "obex");
+ else {
+ status = serial_register_ports(cdev, &serial_config_driver,
+ "gser");
+ }
if (status < 0)
goto fail;
@@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
return 0;
fail:
- cur_line--;
- while (cur_line >= 0)
- gserial_free_line(tty_lines[cur_line--]);
return status;
}
@@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev)
for (i = 0; i < n_ports; i++) {
usb_put_function(f_serial[i]);
usb_put_function_instance(fi_serial[i]);
- gserial_free_line(tty_lines[i]);
}
return 0;
}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index a0aa721d8b21..4b76124ce96b 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -50,7 +50,6 @@
struct eth_dev {
/* lock is held while accessing port_usb
- * or updating its backlink port_usb->ioport
*/
spinlock_t lock;
struct gether *port_usb;
@@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
-static struct eth_dev *the_dev;
-
static const struct net_device_ops eth_netdev_ops = {
.ndo_open = eth_open,
.ndo_stop = eth_stop,
@@ -758,19 +755,16 @@ static struct device_type gadget_type = {
*
* Returns negative errno, or zero on success
*/
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
int status;
- if (the_dev)
- return -EBUSY;
-
net = alloc_etherdev(sizeof *dev);
if (!net)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev = netdev_priv(net);
spin_lock_init(&dev->lock);
@@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
if (status < 0) {
dev_dbg(&g->dev, "register_netdev failed, %d\n", status);
free_netdev(net);
+ dev = ERR_PTR(status);
} else {
INFO(dev, "MAC %pM\n", net->dev_addr);
INFO(dev, "HOST MAC %pM\n", dev->host_mac);
- the_dev = dev;
-
/* two kinds of host-initiated state changes:
* - iff DATA transfer is active, carrier is "on"
* - tx queueing enabled if open *and* carrier is "on"
@@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
netif_carrier_off(net);
}
- return status;
+ return dev;
}
/**
@@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
*
* This is called to free all resources allocated by @gether_setup().
*/
-void gether_cleanup(void)
+void gether_cleanup(struct eth_dev *dev)
{
- if (!the_dev)
+ if (!dev)
return;
- unregister_netdev(the_dev->net);
- flush_work(&the_dev->work);
- free_netdev(the_dev->net);
-
- the_dev = NULL;
+ unregister_netdev(dev->net);
+ flush_work(&dev->work);
+ free_netdev(dev->net);
}
-
/**
* gether_connect - notify network layer that USB link is active
* @link: the USB link, set up with endpoints, descriptors matching
@@ -860,7 +850,7 @@ void gether_cleanup(void)
*/
struct net_device *gether_connect(struct gether *link)
{
- struct eth_dev *dev = the_dev;
+ struct eth_dev *dev = link->ioport;
int result = 0;
if (!dev)
@@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = link;
- link->ioport = dev;
if (netif_running(dev->net)) {
if (link->open)
link->open(link);
@@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link)
spin_lock(&dev->lock);
dev->port_usb = NULL;
- link->ioport = NULL;
spin_unlock(&dev->lock);
}
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 6f4a1623d854..02522338a708 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -21,6 +21,7 @@
#include "gadget_chips.h"
+struct eth_dev;
/*
* This represents the USB side of an "ethernet" link, managed by a USB
@@ -70,7 +71,7 @@ struct gether {
|USB_CDC_PACKET_TYPE_DIRECTED)
/* variant of gether_setup that allows customizing network device name */
-int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
const char *netname);
/* netdev setup/teardown as directed by the gadget driver */
@@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
*
* Returns negative errno, or zero on success
*/
-static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+static inline struct eth_dev *gether_setup(struct usb_gadget *g,
+ u8 ethaddr[ETH_ALEN])
{
return gether_setup_name(g, ethaddr, "usb");
}
-void gether_cleanup(void);
+void gether_cleanup(struct eth_dev *dev);
/* connect/disconnect is handled by individual functions */
struct net_device *gether_connect(struct gether *);
@@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
}
/* each configuration may bind one instance of an ethernet link */
-int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
-int eem_bind_config(struct usb_configuration *c);
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ struct eth_dev *dev);
+int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev);
#ifdef USB_ETH_RNDIS
int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer);
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev);
#else
static inline int
rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
- u32 vendorID, const char *manufacturer)
+ u32 vendorID, const char *manufacturer, struct eth_dev *dev)
{
return 0;
}
@@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
* for calling @gether_cleanup() before module unload.
*/
static inline int rndis_bind_config(struct usb_configuration *c,
- u8 ethaddr[ETH_ALEN])
+ u8 ethaddr[ETH_ALEN], struct eth_dev *dev)
{
- return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev);
}
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index 66ce73a00509..c20210c0babd 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num);
void gserial_disconnect(struct gserial *);
/* functions are bound to configurations by a config or gadget driver */
-int acm_bind_config(struct usb_configuration *c, u8 port_num);
int gser_bind_config(struct usb_configuration *c, u8 port_num);
int obex_bind_config(struct usb_configuration *c, u8 port_num);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index f8f62c3ed65e..ffd8fa541101 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
/* ------------------------------------------------------------------------- */
+void usb_gadget_set_state(struct usb_gadget *gadget,
+ enum usb_device_state state)
+{
+ gadget->state = state;
+ sysfs_notify(&gadget->dev.kobj, NULL, "status");
+}
+EXPORT_SYMBOL_GPL(usb_gadget_set_state);
+
+/* ------------------------------------------------------------------------- */
+
/**
* usb_gadget_udc_start - tells usb device controller to start up
* @gadget: The gadget we want to get started
@@ -156,15 +166,23 @@ static void usb_udc_release(struct device *dev)
}
static const struct attribute_group *usb_udc_attr_groups[];
+
+static void usb_udc_nop_release(struct device *dev)
+{
+ dev_vdbg(dev, "%s\n", __func__);
+}
+
/**
- * usb_add_gadget_udc - adds a new gadget to the udc class driver list
- * @parent: the parent device to this udc. Usually the controller
- * driver's device.
- * @gadget: the gadget to be added to the list
+ * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller driver's
+ * device.
+ * @gadget: the gadget to be added to the list.
+ * @release: a gadget release function.
*
* Returns zero on success, negative errno otherwise.
*/
-int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
+ void (*release)(struct device *dev))
{
struct usb_udc *udc;
int ret = -ENOMEM;
@@ -173,6 +191,22 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
if (!udc)
goto err1;
+ dev_set_name(&gadget->dev, "gadget");
+ gadget->dev.parent = parent;
+
+ dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask);
+ gadget->dev.dma_parms = parent->dma_parms;
+ gadget->dev.dma_mask = parent->dma_mask;
+
+ if (release)
+ gadget->dev.release = release;
+ else
+ gadget->dev.release = usb_udc_nop_release;
+
+ ret = device_register(&gadget->dev);
+ if (ret)
+ goto err2;
+
device_initialize(&udc->dev);
udc->dev.release = usb_udc_release;
udc->dev.class = udc_class;
@@ -180,7 +214,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
udc->dev.parent = parent;
ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
if (ret)
- goto err2;
+ goto err3;
udc->gadget = gadget;
@@ -189,21 +223,42 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
ret = device_add(&udc->dev);
if (ret)
- goto err3;
+ goto err4;
+
+ usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
mutex_unlock(&udc_lock);
return 0;
-err3:
+
+err4:
list_del(&udc->list);
mutex_unlock(&udc_lock);
-err2:
+err3:
put_device(&udc->dev);
+err2:
+ put_device(&gadget->dev);
+ kfree(udc);
+
err1:
return ret;
}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release);
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+ return usb_add_gadget_udc_release(parent, gadget, NULL);
+}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
static void usb_gadget_remove_driver(struct usb_udc *udc)
@@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
}
/**
@@ -254,6 +310,7 @@ found:
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
device_unregister(&udc->dev);
+ device_unregister(&gadget->dev);
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
@@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
udc->driver = driver;
udc->dev.driver = &driver->driver;
+ udc->gadget->dev.driver = &driver->driver;
ret = driver->bind(udc->gadget, driver);
if (ret)
@@ -286,6 +344,7 @@ err1:
udc->driver->function, ret);
udc->driver = NULL;
udc->dev.driver = NULL;
+ udc->gadget->dev.driver = NULL;
return ret;
}
@@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
}
static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+static ssize_t usb_gadget_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ struct usb_gadget *gadget = udc->gadget;
+
+ return sprintf(buf, "%s\n", usb_state_string(gadget->state));
+}
+static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL);
+
#define USB_UDC_SPEED_ATTR(name, param) \
ssize_t usb_udc_##param##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev, \
return snprintf(buf, PAGE_SIZE, "%s\n", \
usb_speed_string(udc->gadget->param)); \
} \
-static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
+static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL)
static USB_UDC_SPEED_ATTR(current_speed, speed);
static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
@@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
&dev_attr_soft_connect.attr,
+ &dev_attr_state.attr,
&dev_attr_current_speed.attr,
&dev_attr_maximum_speed.attr,
diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h
index 93b0c1191115..817e9e19cecf 100644
--- a/drivers/usb/gadget/uvc.h
+++ b/drivers/usb/gadget/uvc.h
@@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param;
#define DRIVER_VERSION "0.1.0"
#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
#define UVC_NUM_REQUESTS 4
#define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4
@@ -190,6 +188,7 @@ struct uvc_file_handle
* Functions
*/
+extern void uvc_function_setup_continue(struct uvc_device *uvc);
extern void uvc_endpoint_stream(struct uvc_device *dev);
extern void uvc_function_connect(struct uvc_device *uvc);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index 104ae9c81251..7ce27e35550b 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -10,6 +10,7 @@
* (at your option) any later version.
*/
+#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/list.h>
@@ -18,7 +19,8 @@
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
-#include <linux/atomic.h>
+
+#include <media/videobuf2-vmalloc.h>
#include "uvc.h"
@@ -28,330 +30,175 @@
* Video queues is initialized by uvc_queue_init(). The function performs
* basic initialization of the uvc_video_queue struct and never fails.
*
- * Video buffer allocation and freeing are performed by uvc_alloc_buffers and
- * uvc_free_buffers respectively. The former acquires the video queue lock,
- * while the later must be called with the lock held (so that allocation can
- * free previously allocated buffers). Trying to free buffers that are mapped
- * to user space will return -EBUSY.
- *
- * Video buffers are managed using two queues. However, unlike most USB video
- * drivers that use an in queue and an out queue, we use a main queue to hold
- * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to
- * hold empty buffers. This design (copied from video-buf) minimizes locking
- * in interrupt, as only one queue is shared between interrupt and user
- * contexts.
- *
- * Use cases
- * ---------
- *
- * Unless stated otherwise, all operations that modify the irq buffers queue
- * are protected by the irq spinlock.
- *
- * 1. The user queues the buffers, starts streaming and dequeues a buffer.
- *
- * The buffers are added to the main and irq queues. Both operations are
- * protected by the queue lock, and the later is protected by the irq
- * spinlock as well.
- *
- * The completion handler fetches a buffer from the irq queue and fills it
- * with video data. If no buffer is available (irq queue empty), the handler
- * returns immediately.
- *
- * When the buffer is full, the completion handler removes it from the irq
- * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue.
- * At that point, any process waiting on the buffer will be woken up. If a
- * process tries to dequeue a buffer after it has been marked ready, the
- * dequeing will succeed immediately.
- *
- * 2. Buffers are queued, user is waiting on a buffer and the device gets
- * disconnected.
- *
- * When the device is disconnected, the kernel calls the completion handler
- * with an appropriate status code. The handler marks all buffers in the
- * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so
- * that any process waiting on a buffer gets woken up.
- *
- * Waking up up the first buffer on the irq list is not enough, as the
- * process waiting on the buffer might restart the dequeue operation
- * immediately.
- *
+ * Video buffers are managed by videobuf2. The driver uses a mutex to protect
+ * the videobuf2 queue operations by serializing calls to videobuf2 and a
+ * spinlock to protect the IRQ queue that holds the buffers to be processed by
+ * the driver.
*/
-static void
-uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
-{
- mutex_init(&queue->mutex);
- spin_lock_init(&queue->irqlock);
- INIT_LIST_HEAD(&queue->mainqueue);
- INIT_LIST_HEAD(&queue->irqqueue);
- queue->type = type;
-}
-
-/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
+/* -----------------------------------------------------------------------------
+ * videobuf2 queue operations
*/
-static int uvc_free_buffers(struct uvc_video_queue *queue)
+
+static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- unsigned int i;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+ struct uvc_video *video = container_of(queue, struct uvc_video, queue);
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
+ if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
+ *nbuffers = UVC_MAX_VIDEO_BUFFERS;
- if (queue->count) {
- vfree(queue->mem);
- queue->count = 0;
- }
+ *nplanes = 1;
+
+ sizes[0] = video->imagesize;
return 0;
}
-/*
- * Allocate the video buffers.
- *
- * Pages are reserved to make sure they will not be swapped, as they will be
- * filled in the URB completion handler.
- *
- * Buffers will be individually mapped, so they must all be page aligned.
- */
-static int
-uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
- unsigned int buflength)
+static int uvc_buffer_prepare(struct vb2_buffer *vb)
{
- unsigned int bufsize = PAGE_ALIGN(buflength);
- unsigned int i;
- void *mem = NULL;
- int ret;
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- if (nbuffers > UVC_MAX_VIDEO_BUFFERS)
- nbuffers = UVC_MAX_VIDEO_BUFFERS;
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
+ uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
+ return -EINVAL;
+ }
- mutex_lock(&queue->mutex);
+ if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
+ return -ENODEV;
- if ((ret = uvc_free_buffers(queue)) < 0)
- goto done;
+ buf->state = UVC_BUF_STATE_QUEUED;
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+ if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ buf->bytesused = 0;
+ else
+ buf->bytesused = vb2_get_plane_payload(vb, 0);
- /* Bail out if no buffers should be allocated. */
- if (nbuffers == 0)
- goto done;
+ return 0;
+}
- /* Decrement the number of buffers until allocation succeeds. */
- for (; nbuffers > 0; --nbuffers) {
- mem = vmalloc_32(nbuffers * bufsize);
- if (mem != NULL)
- break;
- }
+static void uvc_buffer_queue(struct vb2_buffer *vb)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
+ struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
+ unsigned long flags;
- if (mem == NULL) {
- ret = -ENOMEM;
- goto done;
- }
+ spin_lock_irqsave(&queue->irqlock, flags);
- for (i = 0; i < nbuffers; ++i) {
- memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);
- queue->buffer[i].buf.index = i;
- queue->buffer[i].buf.m.offset = i * bufsize;
- queue->buffer[i].buf.length = buflength;
- queue->buffer[i].buf.type = queue->type;
- queue->buffer[i].buf.sequence = 0;
- queue->buffer[i].buf.field = V4L2_FIELD_NONE;
- queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;
- queue->buffer[i].buf.flags = 0;
- init_waitqueue_head(&queue->buffer[i].wait);
+ if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
+ list_add_tail(&buf->queue, &queue->irqqueue);
+ } else {
+ /* If the device is disconnected return the buffer to userspace
+ * directly. The next QBUF call will fail with -ENODEV.
+ */
+ buf->state = UVC_BUF_STATE_ERROR;
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
}
- queue->mem = mem;
- queue->count = nbuffers;
- queue->buf_size = bufsize;
- ret = nbuffers;
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
-static void __uvc_query_buffer(struct uvc_buffer *buf,
- struct v4l2_buffer *v4l2_buf)
-{
- memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
-
- if (buf->vma_use_count)
- v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED;
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- case UVC_BUF_STATE_DONE:
- v4l2_buf->flags |= V4L2_BUF_FLAG_DONE;
- break;
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
- break;
- case UVC_BUF_STATE_IDLE:
- default:
- break;
- }
-}
+static struct vb2_ops uvc_queue_qops = {
+ .queue_setup = uvc_queue_setup,
+ .buf_prepare = uvc_buffer_prepare,
+ .buf_queue = uvc_buffer_queue,
+};
-static int
-uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_queue_init(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type)
{
- int ret = 0;
+ int ret;
- mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- ret = -EINVAL;
- goto done;
- }
+ queue->queue.type = type;
+ queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
+ queue->queue.drv_priv = queue;
+ queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
+ queue->queue.ops = &uvc_queue_qops;
+ queue->queue.mem_ops = &vb2_vmalloc_memops;
+ ret = vb2_queue_init(&queue->queue);
+ if (ret)
+ return ret;
+
+ mutex_init(&queue->mutex);
+ spin_lock_init(&queue->irqlock);
+ INIT_LIST_HEAD(&queue->irqqueue);
+ queue->flags = 0;
- __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf);
+ return 0;
+}
-done:
+/*
+ * Free the video buffers.
+ */
+static void uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ mutex_lock(&queue->mutex);
+ vb2_queue_release(&queue->queue);
mutex_unlock(&queue->mutex);
- return ret;
}
/*
- * Queue a video buffer. Attempting to queue a buffer that has already been
- * queued will return -EINVAL.
+ * Allocate the video buffers.
*/
-static int
-uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf)
+static int uvc_alloc_buffers(struct uvc_video_queue *queue,
+ struct v4l2_requestbuffers *rb)
{
- struct uvc_buffer *buf;
- unsigned long flags;
- int ret = 0;
+ int ret;
- uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);
+ mutex_lock(&queue->mutex);
+ ret = vb2_reqbufs(&queue->queue, rb);
+ mutex_unlock(&queue->mutex);
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ return ret ? ret : rb->count;
+}
- mutex_lock(&queue->mutex);
- if (v4l2_buf->index >= queue->count) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");
- ret = -EINVAL;
- goto done;
- }
+static int uvc_query_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf)
+{
+ int ret;
- buf = &queue->buffer[v4l2_buf->index];
- if (buf->state != UVC_BUF_STATE_IDLE) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "
- "(%u).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
+ mutex_lock(&queue->mutex);
+ ret = vb2_querybuf(&queue->queue, buf);
+ mutex_unlock(&queue->mutex);
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- v4l2_buf->bytesused > buf->buf.length) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
- ret = -EINVAL;
- goto done;
- }
+ return ret;
+}
- if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- buf->buf.bytesused = 0;
- else
- buf->buf.bytesused = v4l2_buf->bytesused;
+static int uvc_queue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf)
+{
+ unsigned long flags;
+ int ret;
+ mutex_lock(&queue->mutex);
+ ret = vb2_qbuf(&queue->queue, buf);
spin_lock_irqsave(&queue->irqlock, flags);
- if (queue->flags & UVC_QUEUE_DISCONNECTED) {
- spin_unlock_irqrestore(&queue->irqlock, flags);
- ret = -ENODEV;
- goto done;
- }
- buf->state = UVC_BUF_STATE_QUEUED;
-
ret = (queue->flags & UVC_QUEUE_PAUSED) != 0;
queue->flags &= ~UVC_QUEUE_PAUSED;
-
- list_add_tail(&buf->stream, &queue->mainqueue);
- list_add_tail(&buf->queue, &queue->irqqueue);
spin_unlock_irqrestore(&queue->irqlock, flags);
-
-done:
mutex_unlock(&queue->mutex);
- return ret;
-}
-static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking)
-{
- if (nonblocking) {
- return (buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE)
- ? 0 : -EAGAIN;
- }
-
- return wait_event_interruptible(buf->wait,
- buf->state != UVC_BUF_STATE_QUEUED &&
- buf->state != UVC_BUF_STATE_ACTIVE);
+ return ret;
}
/*
* Dequeue a video buffer. If nonblocking is false, block until a buffer is
* available.
*/
-static int
-uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf,
- int nonblocking)
+static int uvc_dequeue_buffer(struct uvc_video_queue *queue,
+ struct v4l2_buffer *buf, int nonblocking)
{
- struct uvc_buffer *buf;
- int ret = 0;
-
- if (v4l2_buf->type != queue->type ||
- v4l2_buf->memory != V4L2_MEMORY_MMAP) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "
- "and/or memory (%u).\n", v4l2_buf->type,
- v4l2_buf->memory);
- return -EINVAL;
- }
+ int ret;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue)) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n");
- ret = -EINVAL;
- goto done;
- }
-
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
- if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0)
- goto done;
-
- uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n",
- buf->buf.index, buf->state, buf->buf.bytesused);
-
- switch (buf->state) {
- case UVC_BUF_STATE_ERROR:
- uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data "
- "(transmission error).\n");
- ret = -EIO;
- case UVC_BUF_STATE_DONE:
- buf->state = UVC_BUF_STATE_IDLE;
- break;
-
- case UVC_BUF_STATE_IDLE:
- case UVC_BUF_STATE_QUEUED:
- case UVC_BUF_STATE_ACTIVE:
- default:
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u "
- "(driver bug?).\n", buf->state);
- ret = -EINVAL;
- goto done;
- }
-
- list_del(&buf->stream);
- __uvc_query_buffer(buf, v4l2_buf);
-
-done:
+ ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_unlock(&queue->mutex);
+
return ret;
}
@@ -361,105 +208,47 @@ done:
* This function implements video queue polling and is intended to be used by
* the device poll handler.
*/
-static unsigned int
-uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
- poll_table *wait)
+static unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
+ struct file *file, poll_table *wait)
{
- struct uvc_buffer *buf;
- unsigned int mask = 0;
+ unsigned int ret;
mutex_lock(&queue->mutex);
- if (list_empty(&queue->mainqueue))
- goto done;
-
- buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream);
-
- poll_wait(file, &buf->wait, wait);
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
- mask |= POLLOUT | POLLWRNORM;
-
-done:
+ ret = vb2_poll(&queue->queue, file, wait);
mutex_unlock(&queue->mutex);
- return mask;
-}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
+ return ret;
}
-static void uvc_vm_close(struct vm_area_struct *vma)
+static int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma)
{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
-}
+ int ret;
-static struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
+ mutex_lock(&queue->mutex);
+ ret = vb2_mmap(&queue->queue, vma);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+#ifndef CONFIG_MMU
/*
- * Memory-map a buffer.
+ * Get unmapped area.
*
- * This function implements video buffer memory mapping and is intended to be
- * used by the device mmap handler.
+ * NO-MMU arch need this function to make mmap() work correctly.
*/
-static int
-uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff)
{
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
-
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
+ unsigned long ret;
mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || size != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
-
-done:
+ ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
mutex_unlock(&queue->mutex);
return ret;
}
+#endif
/*
* Cancel the video buffers queue.
@@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
queue);
list_del(&buf->queue);
buf->state = UVC_BUF_STATE_ERROR;
- wake_up(&buf->wait);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
}
/* This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_queue_buffer and the disconnection event that
@@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
*/
static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
{
- unsigned int i;
+ unsigned long flags;
int ret = 0;
mutex_lock(&queue->mutex);
if (enable) {
- if (uvc_queue_streaming(queue)) {
- ret = -EBUSY;
+ ret = vb2_streamon(&queue->queue, queue->queue.type);
+ if (ret < 0)
goto done;
- }
+
queue->sequence = 0;
- queue->flags |= UVC_QUEUE_STREAMING;
queue->buf_used = 0;
} else {
- uvc_queue_cancel(queue, 0);
- INIT_LIST_HEAD(&queue->mainqueue);
+ ret = vb2_streamoff(&queue->queue, queue->queue.type);
+ if (ret < 0)
+ goto done;
- for (i = 0; i < queue->count; ++i)
- queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+ spin_lock_irqsave(&queue->irqlock, flags);
+ INIT_LIST_HEAD(&queue->irqqueue);
- queue->flags &= ~UVC_QUEUE_STREAMING;
+ /*
+ * FIXME: We need to clear the DISCONNECTED flag to ensure that
+ * applications will be able to queue buffers for the next
+ * streaming run. However, clearing it here doesn't guarantee
+ * that the device will be reconnected in the meantime.
+ */
+ queue->flags &= ~UVC_QUEUE_DISCONNECTED;
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
done:
@@ -544,15 +340,15 @@ done:
}
/* called with &queue_irqlock held.. */
-static struct uvc_buffer *
-uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
+static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
+ struct uvc_buffer *buf)
{
struct uvc_buffer *nextbuf;
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
- buf->buf.length != buf->buf.bytesused) {
+ buf->length != buf->bytesused) {
buf->state = UVC_BUF_STATE_QUEUED;
- buf->buf.bytesused = 0;
+ vb2_set_plane_payload(&buf->buf, 0, 0);
return buf;
}
@@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
else
nextbuf = NULL;
- buf->buf.sequence = queue->sequence++;
- do_gettimeofday(&buf->buf.timestamp);
+ /*
+ * FIXME: with videobuf2, the sequence number or timestamp fields
+ * are valid only for video capture devices and the UVC gadget usually
+ * is a video output device. Keeping these until the specs are clear on
+ * this aspect.
+ */
+ buf->buf.v4l2_buf.sequence = queue->sequence++;
+ do_gettimeofday(&buf->buf.v4l2_buf.timestamp);
+
+ vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
+ vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
- wake_up(&buf->wait);
return nextbuf;
}
diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h
index 1812a8ecc5d0..8e76ce982f1e 100644
--- a/drivers/usb/gadget/uvc_queue.h
+++ b/drivers/usb/gadget/uvc_queue.h
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/poll.h>
#include <linux/videodev2.h>
+#include <media/videobuf2-core.h>
/* Maximum frame size in bytes, for sanity checking. */
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
@@ -25,42 +26,35 @@ enum uvc_buffer_state {
};
struct uvc_buffer {
- unsigned long vma_use_count;
- struct list_head stream;
-
- /* Touched by interrupt handler. */
- struct v4l2_buffer buf;
+ struct vb2_buffer buf;
struct list_head queue;
- wait_queue_head_t wait;
+
enum uvc_buffer_state state;
+ void *mem;
+ unsigned int length;
+ unsigned int bytesused;
};
-#define UVC_QUEUE_STREAMING (1 << 0)
-#define UVC_QUEUE_DISCONNECTED (1 << 1)
-#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
-#define UVC_QUEUE_PAUSED (1 << 3)
+#define UVC_QUEUE_DISCONNECTED (1 << 0)
+#define UVC_QUEUE_DROP_INCOMPLETE (1 << 1)
+#define UVC_QUEUE_PAUSED (1 << 2)
struct uvc_video_queue {
- enum v4l2_buf_type type;
+ struct vb2_queue queue;
+ struct mutex mutex; /* Protects queue */
- void *mem;
unsigned int flags;
__u32 sequence;
- unsigned int count;
- unsigned int buf_size;
unsigned int buf_used;
- struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];
- struct mutex mutex; /* protects buffers and mainqueue */
- spinlock_t irqlock; /* protects irqqueue */
- struct list_head mainqueue;
+ spinlock_t irqlock; /* Protects flags and irqqueue */
struct list_head irqqueue;
};
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
- return queue->flags & UVC_QUEUE_STREAMING;
+ return vb2_is_streaming(&queue->queue);
}
#endif /* __KERNEL__ */
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index 2ca9386d655b..ad48e81155e2 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -41,9 +41,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
req->length = min_t(unsigned int, uvc->event_length, data->length);
req->zero = data->length < uvc->event_length;
- req->dma = DMA_ADDR_INVALID;
- memcpy(req->buf, data->data, data->length);
+ memcpy(req->buf, data->data, req->length);
return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
}
@@ -148,16 +147,13 @@ uvc_v4l2_release(struct file *file)
uvc_function_disconnect(uvc);
uvc_video_enable(video, 0);
- mutex_lock(&video->queue.mutex);
- if (uvc_free_buffers(&video->queue) < 0)
- printk(KERN_ERR "uvc_v4l2_release: Unable to free "
- "buffers.\n");
- mutex_unlock(&video->queue.mutex);
+ uvc_free_buffers(&video->queue);
file->private_data = NULL;
v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh);
kfree(handle);
+
return 0;
}
@@ -178,9 +174,9 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_capability *cap = arg;
memset(cap, 0, sizeof *cap);
- strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
- strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
- strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
+ strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
+ strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
sizeof cap->bus_info);
cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -192,7 +188,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_format *fmt = arg;
- if (fmt->type != video->queue.type)
+ if (fmt->type != video->queue.queue.type)
return -EINVAL;
return uvc_v4l2_get_format(video, fmt);
@@ -202,7 +198,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_format *fmt = arg;
- if (fmt->type != video->queue.type)
+ if (fmt->type != video->queue.queue.type)
return -EINVAL;
return uvc_v4l2_set_format(video, fmt);
@@ -213,16 +209,13 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_requestbuffers *rb = arg;
- if (rb->type != video->queue.type ||
- rb->memory != V4L2_MEMORY_MMAP)
+ if (rb->type != video->queue.queue.type)
return -EINVAL;
- ret = uvc_alloc_buffers(&video->queue, rb->count,
- video->imagesize);
+ ret = uvc_alloc_buffers(&video->queue, rb);
if (ret < 0)
return ret;
- rb->count = ret;
ret = 0;
break;
}
@@ -231,9 +224,6 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct v4l2_buffer *buf = arg;
- if (buf->type != video->queue.type)
- return -EINVAL;
-
return uvc_query_buffer(&video->queue, buf);
}
@@ -251,24 +241,36 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
int *type = arg;
- if (*type != video->queue.type)
+ if (*type != video->queue.queue.type)
return -EINVAL;
- return uvc_video_enable(video, 1);
+ /* Enable UVC video. */
+ ret = uvc_video_enable(video, 1);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Complete the alternate setting selection setup phase now that
+ * userspace is ready to provide video frames.
+ */
+ uvc_function_setup_continue(uvc);
+ uvc->state = UVC_STATE_STREAMING;
+
+ return 0;
}
case VIDIOC_STREAMOFF:
{
int *type = arg;
- if (*type != video->queue.type)
+ if (*type != video->queue.queue.type)
return -EINVAL;
return uvc_video_enable(video, 0);
}
/* Events */
- case VIDIOC_DQEVENT:
+ case VIDIOC_DQEVENT:
{
struct v4l2_event *event = arg;
@@ -333,17 +335,21 @@ uvc_v4l2_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
- struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
- unsigned int mask = 0;
- poll_wait(file, &handle->vfh.wait, wait);
- if (v4l2_event_pending(&handle->vfh))
- mask |= POLLPRI;
+ return uvc_queue_poll(&uvc->video.queue, file, wait);
+}
- mask |= uvc_queue_poll(&uvc->video.queue, file, wait);
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct uvc_device *uvc = video_get_drvdata(vdev);
- return mask;
+ return uvc_queue_get_unmapped_area(&uvc->video.queue, pgoff);
}
+#endif
static struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE,
@@ -352,5 +358,8 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
.ioctl = uvc_v4l2_ioctl,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
};
diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
index b0e53a8ea4f7..71e896d4c5ae 100644
--- a/drivers/usb/gadget/uvc_video.c
+++ b/drivers/usb/gadget/uvc_video.c
@@ -32,7 +32,7 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf,
data[0] = 2;
data[1] = UVC_STREAM_EOH | video->fid;
- if (buf->buf.bytesused - video->queue.buf_used <= len - 2)
+ if (buf->bytesused - video->queue.buf_used <= len - 2)
data[1] |= UVC_STREAM_EOF;
return 2;
@@ -47,8 +47,8 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
void *mem;
/* Copy video data to the USB buffer. */
- mem = queue->mem + buf->buf.m.offset + queue->buf_used;
- nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ mem = buf->mem + queue->buf_used;
+ nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
memcpy(data, mem, nbytes);
queue->buf_used += nbytes;
@@ -82,7 +82,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len;
req->zero = video->payload_size == video->max_payload_size;
- if (buf->buf.bytesused == video->queue.buf_used) {
+ if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf);
@@ -92,7 +92,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
}
if (video->payload_size == video->max_payload_size ||
- buf->buf.bytesused == video->queue.buf_used)
+ buf->bytesused == video->queue.buf_used)
video->payload_size = 0;
}
@@ -115,7 +115,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
req->length = video->req_size - len;
- if (buf->buf.bytesused == video->queue.buf_used) {
+ if (buf->bytesused == video->queue.buf_used) {
video->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_DONE;
uvc_queue_next_buffer(&video->queue, buf);
@@ -161,6 +161,7 @@ static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
struct uvc_video *video = req->context;
+ struct uvc_video_queue *queue = &video->queue;
struct uvc_buffer *buf;
unsigned long flags;
int ret;
@@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
case 0:
break;
- case -ESHUTDOWN:
+ case -ESHUTDOWN: /* disconnect from host. */
printk(KERN_INFO "VS request cancelled.\n");
+ uvc_queue_cancel(queue, 1);
goto requeue;
default:
printk(KERN_INFO "VS request completed with status %d.\n",
req->status);
+ uvc_queue_cancel(queue, 0);
goto requeue;
}
@@ -229,13 +232,18 @@ uvc_video_free_requests(struct uvc_video *video)
static int
uvc_video_alloc_requests(struct uvc_video *video)
{
+ unsigned int req_size;
unsigned int i;
int ret = -ENOMEM;
BUG_ON(video->req_size);
+ req_size = video->ep->maxpacket
+ * max_t(unsigned int, video->ep->maxburst, 1)
+ * (video->ep->mult + 1);
+
for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
- video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL);
+ video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
if (video->req_buffer[i] == NULL)
goto error;
@@ -245,14 +253,14 @@ uvc_video_alloc_requests(struct uvc_video *video)
video->req[i]->buf = video->req_buffer[i];
video->req[i]->length = 0;
- video->req[i]->dma = DMA_ADDR_INVALID;
video->req[i]->complete = uvc_video_complete;
video->req[i]->context = video;
list_add_tail(&video->req[i]->list, &video->req_free);
}
- video->req_size = video->ep->maxpacket;
+ video->req_size = req_size;
+
return 0;
error:
@@ -309,7 +317,8 @@ uvc_video_pump(struct uvc_video *video)
video->encode(req, video, buf);
/* Queue the USB request */
- if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) {
+ ret = usb_ep_queue(video->ep, req, GFP_ATOMIC);
+ if (ret < 0) {
printk(KERN_INFO "Failed to queue request (%d)\n", ret);
usb_ep_set_halt(video->ep);
spin_unlock_irqrestore(&video->queue.irqlock, flags);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 685fa681cb65..2cd6262e8b71 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -368,8 +368,10 @@ static int zero_unbind(struct usb_composite_dev *cdev)
del_timer_sync(&autoresume_timer);
if (!IS_ERR_OR_NULL(func_ss))
usb_put_function(func_ss);
+ usb_put_function_instance(func_inst_ss);
if (!IS_ERR_OR_NULL(func_lb))
usb_put_function(func_lb);
+ usb_put_function_instance(func_inst_lb);
return 0;
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index c59a1126926f..de94f2699063 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -2,11 +2,9 @@
# USB Host Controller Drivers
#
comment "USB Host Controller Drivers"
- depends on USB
config USB_C67X00_HCD
tristate "Cypress C67x00 HCD support"
- depends on USB
help
The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
host/peripheral/OTG USB controllers.
@@ -19,7 +17,7 @@ config USB_C67X00_HCD
config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0) support"
- depends on USB && USB_ARCH_HAS_XHCI
+ depends on USB_ARCH_HAS_XHCI
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
@@ -27,13 +25,13 @@ config USB_XHCI_HCD
To compile this driver as a module, choose M here: the
module will be called xhci-hcd.
+if USB_XHCI_HCD
+
config USB_XHCI_PLATFORM
tristate
- depends on USB_XHCI_HCD
config USB_XHCI_HCD_DEBUGGING
bool "Debugging for the xHCI host controller"
- depends on USB_XHCI_HCD
---help---
Say 'Y' to turn on debugging for the xHCI host controller driver.
This will spew debugging output, even in interrupt context.
@@ -41,9 +39,11 @@ config USB_XHCI_HCD_DEBUGGING
If unsure, say N.
+endif # USB_XHCI_HCD
+
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
- depends on USB && USB_ARCH_HAS_EHCI
+ depends on USB_ARCH_HAS_EHCI
---help---
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
"high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware.
@@ -95,14 +95,19 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say Y.
+config USB_FSL_MPH_DR_OF
+ tristate
+
+if USB_EHCI_HCD
+
config USB_EHCI_PCI
tristate
- depends on USB_EHCI_HCD && PCI
+ depends on PCI
default y
config USB_EHCI_HCD_PMC_MSP
tristate "EHCI support for on-chip PMC MSP71xx USB controller"
- depends on USB_EHCI_HCD && MSP_HAS_USB
+ depends on MSP_HAS_USB
default n
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
@@ -112,22 +117,13 @@ config USB_EHCI_HCD_PMC_MSP
config USB_EHCI_BIG_ENDIAN_MMIO
bool
- depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
- ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
- PPC_MPC512x || CPU_CAVIUM_OCTEON || \
- PMC_MSP || SPARC_LEON || MIPS_SEAD3)
- default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
- depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
- PPC_MPC512x || PMC_MSP || SPARC_LEON || \
- MIPS_SEAD3)
- default y
config XPS_USB_HCD_XILINX
bool "Use Xilinx usb host EHCI controller core"
- depends on USB_EHCI_HCD && (PPC32 || MICROBLAZE)
+ depends on (PPC32 || MICROBLAZE)
select USB_EHCI_BIG_ENDIAN_DESC
select USB_EHCI_BIG_ENDIAN_MMIO
---help---
@@ -136,12 +132,9 @@ config XPS_USB_HCD_XILINX
support both high speed and full speed devices, or high speed
devices only.
-config USB_FSL_MPH_DR_OF
- tristate
-
config USB_EHCI_FSL
bool "Support for Freescale PPC on-chip EHCI USB controller"
- depends on USB_EHCI_HCD && FSL_SOC
+ depends on FSL_SOC
select USB_EHCI_ROOT_HUB_TT
select USB_FSL_MPH_DR_OF if OF
---help---
@@ -149,22 +142,53 @@ config USB_EHCI_FSL
config USB_EHCI_MXC
tristate "Support for Freescale i.MX on-chip EHCI USB controller"
- depends on USB_EHCI_HCD && ARCH_MXC
+ depends on ARCH_MXC
select USB_EHCI_ROOT_HUB_TT
---help---
Variation of ARC USB block used in some Freescale chips.
config USB_EHCI_HCD_OMAP
- bool "EHCI support for OMAP3 and later chips"
- depends on USB_EHCI_HCD && ARCH_OMAP
+ tristate "EHCI support for OMAP3 and later chips"
+ depends on ARCH_OMAP
default y
---help---
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
+ If your system uses a PHY on the USB port, you will need to
+ enable USB_PHY and the appropriate PHY driver as well. Most
+ boards need the NOP_USB_XCEIV PHY driver.
+
+config USB_EHCI_HCD_ORION
+ tristate "Support for Marvell EBU on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && PLAT_ORION
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on Marvell's
+ embedded ARM SoCs, including Orion, Kirkwood, Dove, Armada XP,
+ Armada 370. This is different from the EHCI implementation
+ on Marvell's mobile PXA and MMP SoC, see "EHCI support for
+ Marvell PXA/MMP USB controller" for those.
+
+config USB_EHCI_HCD_SPEAR
+ tristate "Support for ST SPEAr on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && PLAT_SPEAR
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on
+ ST SPEAr chips.
+
+config USB_EHCI_HCD_AT91
+ tristate "Support for Atmel on-chip EHCI USB controller"
+ depends on USB_EHCI_HCD && ARCH_AT91
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on
+ Atmel chips.
config USB_EHCI_MSM
- bool "Support for MSM on-chip EHCI USB controller"
- depends on USB_EHCI_HCD && ARCH_MSM
+ tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller"
+ depends on ARCH_MSM
+ depends on USB_PHY
select USB_EHCI_ROOT_HUB_TT
select USB_MSM_OTG
---help---
@@ -177,15 +201,16 @@ config USB_EHCI_MSM
config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support"
- depends on USB_EHCI_HCD && ARCH_TEGRA
+ depends on ARCH_TEGRA
select USB_EHCI_ROOT_HUB_TT
+ select USB_PHY
help
This driver enables support for the internal USB Host Controllers
found in NVIDIA Tegra SoCs. The controllers are EHCI compliant.
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
- depends on USB_EHCI_HCD && PPC_OF
+ depends on PPC_OF
default y
---help---
Enables support for the USB controller present on the PowerPC
@@ -193,35 +218,40 @@ config USB_EHCI_HCD_PPC_OF
config USB_EHCI_SH
bool "EHCI support for SuperH USB controller"
- depends on USB_EHCI_HCD && SUPERH
+ depends on SUPERH
---help---
Enables support for the on-chip EHCI controller on the SuperH.
If you use the PCI EHCI controller, this option is not necessary.
config USB_EHCI_S5P
- boolean "S5P EHCI support"
- depends on USB_EHCI_HCD && PLAT_S5P
+ tristate "EHCI support for Samsung S5P/EXYNOS SoC Series"
+ depends on PLAT_S5P
help
- Enable support for the S5P SOC's on-chip EHCI controller.
+ Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's
+ on-chip EHCI controller.
config USB_EHCI_MV
- bool "EHCI support for Marvell on-chip controller"
- depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP)
+ bool "EHCI support for Marvell PXA/MMP USB controller"
+ depends on (ARCH_PXA || ARCH_MMP)
select USB_EHCI_ROOT_HUB_TT
---help---
Enables support for Marvell (including PXA and MMP series) on-chip
USB SPH and OTG controller. SPH is a single port host, and it can
only be EHCI host. OTG is controller that can switch to host mode.
+ Note that this driver will not work on Marvell's other EHCI
+ controller used by the EBU-type SoCs including Orion, Kirkwood,
+ Dova, Armada 370 and Armada XP. See "Support for Marvell EBU
+ on-chip EHCI USB controller" for those.
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
- depends on USB_EHCI_HCD && ARCH_W90X900
+ depends on ARCH_W90X900
---help---
Enables support for the W90X900 USB controller
config USB_CNS3XXX_EHCI
bool "Cavium CNS3XXX EHCI Module (DEPRECATED)"
- depends on USB_EHCI_HCD && ARCH_CNS3XXX
+ depends on ARCH_CNS3XXX
select USB_EHCI_HCD_PLATFORM
---help---
This option is deprecated now and the driver was removed, use
@@ -233,7 +263,7 @@ config USB_CNS3XXX_EHCI
config USB_EHCI_ATH79
bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)"
- depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
+ depends on (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
select USB_EHCI_ROOT_HUB_TT
select USB_EHCI_HCD_PLATFORM
default y
@@ -244,9 +274,31 @@ config USB_EHCI_ATH79
Enables support for the built-in EHCI controller present
on the Atheros AR7XXX/AR9XXX SoCs.
+config USB_EHCI_HCD_PLATFORM
+ tristate "Generic EHCI driver for a platform device"
+ default n
+ ---help---
+ Adds an EHCI host driver for a generic platform device, which
+ provides a memory space and an irq.
+
+ If unsure, say N.
+
+config USB_OCTEON_EHCI
+ bool "Octeon on-chip EHCI support"
+ depends on CPU_CAVIUM_OCTEON
+ default n
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ help
+ Enable support for the Octeon II SOC's on-chip EHCI
+ controller. It is needed for high-speed (480Mbit/sec)
+ USB 2.0 device support. All CN6XXX based chips with USB are
+ supported.
+
+endif # USB_EHCI_HCD
+
config USB_OXU210HP_HCD
tristate "OXU210HP HCD support"
- depends on USB && GENERIC_HARDIRQS
+ depends on GENERIC_HARDIRQS
---help---
The OXU210HP is an USB host/OTG/device controller. Enable this
option if your board has this chip. If unsure, say N.
@@ -259,7 +311,6 @@ config USB_OXU210HP_HCD
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
- depends on USB
---help---
The ISP1160 and ISP1161 chips are USB host controllers. Enable this
option if your board has this chip. If unsure, say N.
@@ -271,7 +322,6 @@ config USB_ISP116X_HCD
config USB_ISP1760_HCD
tristate "ISP 1760 HCD support"
- depends on USB
---help---
The ISP1760 chip is a USB 2.0 host controller.
@@ -286,7 +336,6 @@ config USB_ISP1760_HCD
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
- depends on USB
default N
---help---
Supports the Philips ISP1362 chip as a host controller
@@ -298,9 +347,8 @@ config USB_ISP1362_HCD
config USB_OHCI_HCD
tristate "OHCI HCD support"
- depends on USB && USB_ARCH_HAS_OHCI
+ depends on USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
- select USB_OTG_UTILS if ARCH_OMAP
depends on USB_ISP1301 || !ARCH_LPC32XX
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
@@ -315,16 +363,18 @@ config USB_OHCI_HCD
To compile this driver as a module, choose M here: the
module will be called ohci-hcd.
+if USB_OHCI_HCD
+
config USB_OHCI_HCD_OMAP1
bool "OHCI support for OMAP1/2 chips"
- depends on USB_OHCI_HCD && ARCH_OMAP1
+ depends on ARCH_OMAP1
default y
---help---
Enables support for the OHCI controller on OMAP1/2 chips.
config USB_OHCI_HCD_OMAP3
bool "OHCI support for OMAP3 and later chips"
- depends on USB_OHCI_HCD && (ARCH_OMAP3 || ARCH_OMAP4)
+ depends on (ARCH_OMAP3 || ARCH_OMAP4)
default y
---help---
Enables support for the on-chip OHCI controller on
@@ -332,7 +382,7 @@ config USB_OHCI_HCD_OMAP3
config USB_OHCI_ATH79
bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)"
- depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
+ depends on (SOC_AR71XX || SOC_AR724X)
select USB_OHCI_HCD_PLATFORM
default y
help
@@ -344,7 +394,7 @@ config USB_OHCI_ATH79
config USB_OHCI_HCD_PPC_OF_BE
bool "OHCI support for OF platform bus (big endian)"
- depends on USB_OHCI_HCD && PPC_OF
+ depends on PPC_OF
select USB_OHCI_BIG_ENDIAN_DESC
select USB_OHCI_BIG_ENDIAN_MMIO
---help---
@@ -353,7 +403,7 @@ config USB_OHCI_HCD_PPC_OF_BE
config USB_OHCI_HCD_PPC_OF_LE
bool "OHCI support for OF platform bus (little endian)"
- depends on USB_OHCI_HCD && PPC_OF
+ depends on PPC_OF
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for little-endian USB controllers present on the
@@ -361,12 +411,12 @@ config USB_OHCI_HCD_PPC_OF_LE
config USB_OHCI_HCD_PPC_OF
bool
- depends on USB_OHCI_HCD && PPC_OF
+ depends on PPC_OF
default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
- depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
+ depends on PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
@@ -375,7 +425,7 @@ config USB_OHCI_HCD_PCI
config USB_OHCI_HCD_SSB
bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)"
- depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD)
+ depends on (SSB = y || SSB = USB_OHCI_HCD)
select USB_HCD_SSB
select USB_OHCI_HCD_PLATFORM
default n
@@ -393,7 +443,7 @@ config USB_OHCI_HCD_SSB
config USB_OHCI_SH
bool "OHCI support for SuperH USB controller (DEPRECATED)"
- depends on USB_OHCI_HCD && SUPERH
+ depends on SUPERH
select USB_OHCI_HCD_PLATFORM
---help---
This option is deprecated now and the driver was removed, use
@@ -404,13 +454,13 @@ config USB_OHCI_SH
config USB_OHCI_EXYNOS
boolean "OHCI support for Samsung EXYNOS SoC Series"
- depends on USB_OHCI_HCD && ARCH_EXYNOS
+ depends on ARCH_EXYNOS
help
Enable support for the Samsung Exynos SOC's on-chip OHCI controller.
config USB_CNS3XXX_OHCI
bool "Cavium CNS3XXX OHCI Module (DEPRECATED)"
- depends on USB_OHCI_HCD && ARCH_CNS3XXX
+ depends on ARCH_CNS3XXX
select USB_OHCI_HCD_PLATFORM
---help---
This option is deprecated now and the driver was removed, use
@@ -421,7 +471,6 @@ config USB_CNS3XXX_OHCI
config USB_OHCI_HCD_PLATFORM
bool "Generic OHCI driver for a platform device"
- depends on USB_OHCI_HCD
default n
---help---
Adds an OHCI host driver for a generic platform device, which
@@ -429,35 +478,36 @@ config USB_OHCI_HCD_PLATFORM
If unsure, say N.
-config USB_EHCI_HCD_PLATFORM
- tristate "Generic EHCI driver for a platform device"
- depends on USB_EHCI_HCD
- default n
- ---help---
- Adds an EHCI host driver for a generic platform device, which
- provides a memory space and an irq.
+config USB_OCTEON_OHCI
+ bool "Octeon on-chip OHCI support"
+ depends on CPU_CAVIUM_OCTEON
+ default USB_OCTEON_EHCI
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_OHCI_LITTLE_ENDIAN
+ help
+ Enable support for the Octeon II SOC's on-chip OHCI
+ controller. It is needed for low-speed USB 1.0 device
+ support. All CN6XXX based chips with USB are supported.
- If unsure, say N.
config USB_OHCI_BIG_ENDIAN_DESC
bool
- depends on USB_OHCI_HCD
default n
config USB_OHCI_BIG_ENDIAN_MMIO
bool
- depends on USB_OHCI_HCD
default n
config USB_OHCI_LITTLE_ENDIAN
bool
- depends on USB_OHCI_HCD
default n if STB03xxx || PPC_MPC52xx
default y
+endif # USB_OHCI_HCD
+
config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support"
- depends on USB && (PCI || SPARC_LEON || ARCH_VT8500)
+ depends on PCI || SPARC_LEON || ARCH_VT8500
---help---
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
@@ -497,7 +547,7 @@ config USB_UHCI_BIG_ENDIAN_DESC
config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support"
- depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE
+ depends on OF_GPIO && QE_GPIO && QUICC_ENGINE
select FSL_GTM
select QE_USB
help
@@ -514,7 +564,7 @@ config FHCI_DEBUG
config USB_U132_HCD
tristate "Elan U132 Adapter Host Controller"
- depends on USB && USB_FTDI_ELAN
+ depends on USB_FTDI_ELAN
default M
help
The U132 adapter is a USB to CardBus adapter specifically designed
@@ -542,7 +592,6 @@ config USB_U132_HCD
config USB_SL811_HCD
tristate "SL811HS HCD support"
- depends on USB
help
The SL811HS is a single-port USB controller that supports either
host side or peripheral side roles. Enable this option if your
@@ -574,7 +623,6 @@ config USB_SL811_CS
config USB_R8A66597_HCD
tristate "R8A66597 HCD support"
- depends on USB
help
The R8A66597 is a USB 2.0 host and peripheral controller.
@@ -586,7 +634,6 @@ config USB_R8A66597_HCD
config USB_RENESAS_USBHS_HCD
tristate "Renesas USBHS HCD support"
- depends on USB
depends on USB_RENESAS_USBHS
help
The Renesas USBHS is a USB 2.0 host and peripheral controller.
@@ -611,7 +658,7 @@ config USB_WHCI_HCD
config USB_HWA_HCD
tristate "Host Wire Adapter (HWA) driver"
- depends on USB && UWB
+ depends on UWB
select USB_WUSB
select UWB_HWA
help
@@ -625,7 +672,7 @@ config USB_HWA_HCD
config USB_IMX21_HCD
tristate "i.MX21 HCD support"
- depends on USB && ARM && ARCH_MXC
+ depends on ARM && ARCH_MXC
help
This driver enables support for the on-chip USB host in the
i.MX21 processor.
@@ -633,27 +680,7 @@ config USB_IMX21_HCD
To compile this driver as a module, choose M here: the
module will be called "imx21-hcd".
-config USB_OCTEON_EHCI
- bool "Octeon on-chip EHCI support"
- depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON
- default n
- select USB_EHCI_BIG_ENDIAN_MMIO
- help
- Enable support for the Octeon II SOC's on-chip EHCI
- controller. It is needed for high-speed (480Mbit/sec)
- USB 2.0 device support. All CN6XXX based chips with USB are
- supported.
-config USB_OCTEON_OHCI
- bool "Octeon on-chip OHCI support"
- depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON
- default USB_OCTEON_EHCI
- select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_OHCI_LITTLE_ENDIAN
- help
- Enable support for the Octeon II SOC's on-chip OHCI
- controller. It is needed for low-speed USB 1.0 device
- support. All CN6XXX based chips with USB are supported.
config USB_OCTEON2_COMMON
bool
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 001fbff2fdef..4fb73c156d72 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -27,6 +27,12 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
+obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
+obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
+obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
+obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o
+obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o
+obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index f3beac4d06b8..66420097c242 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -12,9 +12,22 @@
*/
#include <linux/clk.h>
-#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "ehci.h"
+
+#define DRIVER_DESC "EHCI Atmel driver"
+
+static const char hcd_name[] = "ehci-atmel";
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
/* interface and function clocks */
static struct clk *iclk, *fclk;
@@ -50,51 +63,6 @@ static void atmel_stop_ehci(struct platform_device *pdev)
/*-------------------------------------------------------------------------*/
-static int ehci_atmel_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- /* registers start at offset 0x0 */
- ehci->caps = hcd->regs;
-
- return ehci_setup(hcd);
-}
-
-static const struct hc_driver ehci_atmel_hc_driver = {
- .description = hcd_name,
- .product_desc = "Atmel EHCI UHP HS",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /* generic hardware linkage */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /* basic lifecycle operations */
- .reset = ehci_atmel_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /* managing i/o requests and associated device resources */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /* scheduling support */
- .get_frame_number = ehci_get_frame,
-
- /* root hub support */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
static int ehci_atmel_drv_probe(struct platform_device *pdev)
@@ -102,6 +70,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
struct usb_hcd *hcd;
const struct hc_driver *driver = &ehci_atmel_hc_driver;
struct resource *res;
+ struct ehci_hcd *ehci;
int irq;
int retval;
@@ -162,6 +131,10 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
goto fail_request_resource;
}
+ ehci = hcd_to_ehci(hcd);
+ /* registers start at offset 0x0 */
+ ehci->caps = hcd->regs;
+
atmel_start_ehci(pdev);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
@@ -185,7 +158,6 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- ehci_shutdown(hcd);
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
@@ -213,3 +185,25 @@ static struct platform_driver ehci_atmel_driver = {
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
};
+
+static int __init ehci_atmel_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+ ehci_init_driver(&ehci_atmel_hc_driver, NULL);
+ return platform_driver_register(&ehci_atmel_driver);
+}
+module_init(ehci_atmel_init);
+
+static void __exit ehci_atmel_cleanup(void)
+{
+ platform_driver_unregister(&ehci_atmel_driver);
+}
+module_exit(ehci_atmel_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_ALIAS("platform:atmel-ehci");
+MODULE_AUTHOR("Nicolas Ferre");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 70b496dc18a0..5429d2645bbc 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
spin_lock_irqsave (&ehci->lock, flags);
for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)
qh_lines (ehci, qh, &next, &size);
- if (ehci->async_unlink && size > 0) {
+ if (!list_empty(&ehci->async_unlink) && size > 0) {
temp = scnprintf(next, size, "\nunlink =\n");
size -= temp;
next += temp;
- for (qh = ehci->async_unlink; size > 0 && qh;
- qh = qh->unlink_next)
- qh_lines (ehci, qh, &next, &size);
+ list_for_each_entry(qh, &ehci->async_unlink, unlink_node) {
+ if (size <= 0)
+ break;
+ qh_lines(ehci, qh, &next, &size);
+ }
}
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
}
}
- if (ehci->async_unlink) {
+ if (!list_empty(&ehci->async_unlink)) {
temp = scnprintf(next, size, "async unlink qh %p\n",
- ehci->async_unlink);
+ list_first_entry(&ehci->async_unlink,
+ struct ehci_qh, unlink_node));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d81d2fcbff18..3be3df233a0e 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -370,6 +370,15 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
+#ifdef CONFIG_PPC_83xx
+ /*
+ * Deal with MPC834X that need port power to be cycled after the power
+ * fault condition is removed. Otherwise the state machine does not
+ * reflect PORTSC[CSC] correctly.
+ */
+ ehci->need_oc_pp_cycle = 1;
+#endif
+
hcd->has_tt = 1;
retval = ehci_setup(hcd);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 416a6dce5e11..312fc10da3c7 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -482,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd)
* periodic_size can shrink by USBCMD update if hcc_params allows.
*/
ehci->periodic_size = DEFAULT_I_TDPS;
+ INIT_LIST_HEAD(&ehci->async_unlink);
+ INIT_LIST_HEAD(&ehci->async_idle);
+ INIT_LIST_HEAD(&ehci->intr_unlink);
INIT_LIST_HEAD(&ehci->intr_qh_list);
INIT_LIST_HEAD(&ehci->cached_itd_list);
INIT_LIST_HEAD(&ehci->cached_sitd_list);
@@ -670,9 +673,6 @@ int ehci_setup(struct usb_hcd *hcd)
if (retval)
return retval;
- if (ehci_is_TDI(ehci))
- tdi_reset(ehci);
-
ehci_reset(ehci);
return 0;
@@ -749,7 +749,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* guard against (alleged) silicon errata */
if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
- if (ehci->async_iaa)
+ if (ehci->iaa_in_progress)
COUNT(ehci->stats.iaa);
end_unlink_async(ehci);
}
@@ -757,7 +757,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
- u32 ppcd = 0;
+ u32 ppcd = ~0;
/* kick root hub later */
pcd_status = status;
@@ -774,7 +774,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
int pstatus;
/* leverage per-port change bits feature */
- if (ehci->has_ppcd && !(ppcd & (1 << i)))
+ if (!(ppcd & (1 << i)))
continue;
pstatus = ehci_readl(ehci,
&ehci->regs->port_status[i]);
@@ -896,17 +896,24 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (rc)
goto done;
- switch (usb_pipetype (urb->pipe)) {
- // case PIPE_CONTROL:
- // case PIPE_BULK:
- default:
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ /*
+ * We don't expedite dequeue for isochronous URBs.
+ * Just wait until they complete normally or their
+ * time slot expires.
+ */
+ } else {
qh = (struct ehci_qh *) urb->hcpriv;
- if (!qh)
- break;
+ qh->exception = 1;
switch (qh->qh_state) {
case QH_STATE_LINKED:
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
+ start_unlink_intr(ehci, qh);
+ else
+ start_unlink_async(ehci, qh);
+ break;
case QH_STATE_COMPLETING:
- start_unlink_async(ehci, qh);
+ qh->dequeue_during_giveback = 1;
break;
case QH_STATE_UNLINK:
case QH_STATE_UNLINK_WAIT:
@@ -917,33 +924,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
qh_completions(ehci, qh);
break;
}
- break;
-
- case PIPE_INTERRUPT:
- qh = (struct ehci_qh *) urb->hcpriv;
- if (!qh)
- break;
- switch (qh->qh_state) {
- case QH_STATE_LINKED:
- case QH_STATE_COMPLETING:
- start_unlink_intr(ehci, qh);
- break;
- case QH_STATE_IDLE:
- qh_completions (ehci, qh);
- break;
- default:
- ehci_dbg (ehci, "bogus qh %p state %d\n",
- qh, qh->qh_state);
- goto done;
- }
- break;
-
- case PIPE_ISOCHRONOUS:
- // itd or sitd ...
-
- // wait till next completion, do it then.
- // completion irqs can wait up to 1024 msec,
- break;
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -984,6 +964,7 @@ rescan:
goto done;
}
+ qh->exception = 1;
if (ehci->rh_state < EHCI_RH_RUNNING)
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
@@ -1052,13 +1033,12 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
usb_settoggle(qh->dev, epnum, is_out, 0);
if (!list_empty(&qh->qtd_list)) {
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
- } else if (qh->qh_state == QH_STATE_LINKED ||
- qh->qh_state == QH_STATE_COMPLETING) {
-
+ } else {
/* The toggle value in the QH can't be updated
* while the QH is active. Unlink it now;
* re-linking will call qh_refresh().
*/
+ qh->exception = 1;
if (eptype == USB_ENDPOINT_XFER_BULK)
start_unlink_async(ehci, qh);
else
@@ -1251,11 +1231,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_sh_driver
#endif
-#ifdef CONFIG_USB_EHCI_HCD_OMAP
-#include "ehci-omap.c"
-#define PLATFORM_DRIVER ehci_hcd_omap_driver
-#endif
-
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
@@ -1271,41 +1246,16 @@ MODULE_LICENSE ("GPL");
#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
#endif
-#ifdef CONFIG_PLAT_ORION
-#include "ehci-orion.c"
-#define PLATFORM_DRIVER ehci_orion_driver
-#endif
-
#ifdef CONFIG_USB_W90X900_EHCI
#include "ehci-w90x900.c"
#define PLATFORM_DRIVER ehci_hcd_w90x900_driver
#endif
-#ifdef CONFIG_ARCH_AT91
-#include "ehci-atmel.c"
-#define PLATFORM_DRIVER ehci_atmel_driver
-#endif
-
#ifdef CONFIG_USB_OCTEON_EHCI
#include "ehci-octeon.c"
#define PLATFORM_DRIVER ehci_octeon_driver
#endif
-#ifdef CONFIG_ARCH_VT8500
-#include "ehci-vt8500.c"
-#define PLATFORM_DRIVER vt8500_ehci_driver
-#endif
-
-#ifdef CONFIG_PLAT_SPEAR
-#include "ehci-spear.c"
-#define PLATFORM_DRIVER spear_ehci_hcd_driver
-#endif
-
-#ifdef CONFIG_USB_EHCI_MSM
-#include "ehci-msm.c"
-#define PLATFORM_DRIVER ehci_msm_driver
-#endif
-
#ifdef CONFIG_TILE_USB
#include "ehci-tilegx.c"
#define PLATFORM_DRIVER ehci_hcd_tilegx_driver
@@ -1321,11 +1271,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER tegra_ehci_driver
#endif
-#ifdef CONFIG_USB_EHCI_S5P
-#include "ehci-s5p.c"
-#define PLATFORM_DRIVER s5p_ehci_driver
-#endif
-
#ifdef CONFIG_SPARC_LEON
#include "ehci-grlib.c"
#define PLATFORM_DRIVER ehci_grlib_driver
@@ -1345,6 +1290,12 @@ MODULE_LICENSE ("GPL");
!IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
!IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
!IS_ENABLED(CONFIG_USB_EHCI_MXC) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_S5P) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_HCD_AT91) && \
+ !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \
!defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7d06e77f6c4f..9ab4a4d9768a 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -464,7 +464,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &resume_needed)) {
- temp &= ~(PORT_RWC_BITS | PORT_RESUME);
+ temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
@@ -590,7 +590,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
u32 mask;
int ports, i, retval = 1;
unsigned long flags;
- u32 ppcd = 0;
+ u32 ppcd = ~0;
/* init status to no-changes */
buf [0] = 0;
@@ -628,9 +628,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ports; i++) {
/* leverage per-port change bits feature */
- if (ehci->has_ppcd && !(ppcd & (1 << i)))
- continue;
- temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+ if (ppcd & (1 << i))
+ temp = ehci_readl(ehci, &ehci->regs->port_status[i]);
+ else
+ temp = 0;
/*
* Return status information even for ports with OWNER set.
@@ -839,7 +840,8 @@ static int ehci_hub_control (
* power switching; they're allowed to just limit the
* current. khubd will turn the power back on.
*/
- if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) {
+ if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle))
+ && HCS_PPC(ehci->hcs_params)) {
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_POWER),
status_reg);
@@ -870,10 +872,9 @@ static int ehci_hub_control (
usb_hcd_end_port_resume(&hcd->self, wIndex);
/* stop resume signaling */
- temp = ehci_readl(ehci, status_reg);
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_RESUME),
- status_reg);
+ temp &= ~(PORT_RWC_BITS |
+ PORT_SUSPEND | PORT_RESUME);
+ ehci_writel(ehci, temp, status_reg);
clear_bit(wIndex, &ehci->resuming_ports);
retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
@@ -883,7 +884,7 @@ static int ehci_hub_control (
wIndex + 1, retval);
goto error;
}
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ temp = ehci_readl(ehci, status_reg);
}
}
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 88a49c87e748..0f717dc688b7 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -22,16 +22,26 @@
* along with this program; if not, you can find it at http://www.fsf.org
*/
-#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-
#include <linux/usb/otg.h>
#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "ehci.h"
#define MSM_USB_BASE (hcd->regs)
+#define DRIVER_DESC "Qualcomm On-Chip EHCI Host Controller"
+
+static const char hcd_name[] = "ehci-msm";
+static struct hc_driver __read_mostly msm_hc_driver;
static struct usb_phy *phy;
static int ehci_msm_reset(struct usb_hcd *hcd)
@@ -56,52 +66,6 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
return 0;
}
-static struct hc_driver msm_hc_driver = {
- .description = hcd_name,
- .product_desc = "Qualcomm On-Chip EHCI Host Controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_USB2 | HCD_MEMORY,
-
- .reset = ehci_msm_reset,
- .start = ehci_run,
-
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- /*
- * PM support
- */
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
-};
-
static int ehci_msm_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -145,7 +109,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
* management.
*/
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
goto put_hcd;
@@ -165,6 +129,8 @@ static int ehci_msm_probe(struct platform_device *pdev)
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ /* FIXME: need to call usb_add_hcd() here? */
+
return 0;
put_hcd:
@@ -183,6 +149,8 @@ static int ehci_msm_remove(struct platform_device *pdev)
otg_set_host(phy->otg, NULL);
+ /* FIXME: need to call usb_remove_hcd() here? */
+
usb_put_hcd(hcd);
return 0;
@@ -226,3 +194,28 @@ static struct platform_driver ehci_msm_driver = {
.pm = &ehci_msm_dev_pm_ops,
},
};
+
+static const struct ehci_driver_overrides msm_overrides __initdata = {
+ .reset = ehci_msm_reset,
+};
+
+static int __init ehci_msm_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+ ehci_init_driver(&msm_hc_driver, &msm_overrides);
+ return platform_driver_register(&ehci_msm_driver);
+}
+module_init(ehci_msm_init);
+
+static void __exit ehci_msm_cleanup(void)
+{
+ platform_driver_unregister(&ehci_msm_driver);
+}
+module_exit(ehci_msm_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_ALIAS("platform:msm-ehci");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 3065809546b1..402062973f03 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -33,25 +33,17 @@ struct ehci_hcd_mv {
struct mv_usb_platform_data *pdata;
- /* clock source and total clock number */
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
{
- unsigned int i;
-
- for (i = 0; i < ehci_mv->clknum; i++)
- clk_prepare_enable(ehci_mv->clk[i]);
+ clk_prepare_enable(ehci_mv->clk);
}
static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
{
- unsigned int i;
-
- for (i = 0; i < ehci_mv->clknum; i++)
- clk_disable_unprepare(ehci_mv->clk[i]);
+ clk_disable_unprepare(ehci_mv->clk);
}
static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
@@ -144,9 +136,8 @@ static int mv_ehci_probe(struct platform_device *pdev)
struct ehci_hcd *ehci;
struct ehci_hcd_mv *ehci_mv;
struct resource *r;
- int clk_i, retval = -ENODEV;
+ int retval = -ENODEV;
u32 offset;
- size_t size;
if (!pdata) {
dev_err(&pdev->dev, "missing platform_data\n");
@@ -160,8 +151,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
- size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
- ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL);
if (ehci_mv == NULL) {
dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
retval = -ENOMEM;
@@ -172,16 +162,11 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->pdata = pdata;
ehci_mv->hcd = hcd;
- ehci_mv->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
- ehci_mv->clk[clk_i] =
- devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
- if (IS_ERR(ehci_mv->clk[clk_i])) {
- dev_err(&pdev->dev, "error get clck \"%s\"\n",
- pdata->clkname[clk_i]);
- retval = PTR_ERR(ehci_mv->clk[clk_i]);
- goto err_clear_drvdata;
- }
+ ehci_mv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ehci_mv->clk)) {
+ dev_err(&pdev->dev, "error getting clock\n");
+ retval = PTR_ERR(ehci_mv->clk);
+ goto err_clear_drvdata;
}
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
@@ -225,7 +210,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
hcd->rsrc_start = r->start;
- hcd->rsrc_len = r->end - r->start + 1;
+ hcd->rsrc_len = resource_size(r);
hcd->regs = ehci_mv->op_regs;
hcd->irq = platform_get_irq(pdev, 0);
@@ -240,12 +225,16 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
-#ifdef CONFIG_USB_OTG_UTILS
ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(ehci_mv->otg)) {
- dev_err(&pdev->dev,
- "unable to find transceiver\n");
- retval = -ENODEV;
+ if (IS_ERR(ehci_mv->otg)) {
+ retval = PTR_ERR(ehci_mv->otg);
+
+ if (retval == -ENXIO)
+ dev_info(&pdev->dev, "MV_USB_MODE_OTG "
+ "must have CONFIG_USB_PHY enabled\n");
+ else
+ dev_err(&pdev->dev,
+ "unable to find transceiver\n");
goto err_disable_clk;
}
@@ -258,11 +247,6 @@ static int mv_ehci_probe(struct platform_device *pdev)
}
/* otg will enable clock before use as host */
mv_ehci_disable(ehci_mv);
-#else
- dev_info(&pdev->dev, "MV_USB_MODE_OTG "
- "must have CONFIG_USB_OTG_UTILS enabled\n");
- goto err_disable_clk;
-#endif
} else {
if (pdata->set_vbus)
pdata->set_vbus(1);
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index e9301fb97eaa..c369767b00e2 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -28,11 +28,7 @@
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
-
#include <linux/platform_data/usb-ehci-mxc.h>
-
-#include <asm/mach-types.h>
-
#include "ehci.h"
#define DRIVER_DESC "Freescale On-Chip EHCI Host driver"
@@ -47,7 +43,7 @@ struct ehci_mxc_priv {
static struct hc_driver __read_mostly ehci_mxc_hc_driver;
-static const struct ehci_driver_overrides ehci_mxc_overrides __initdata = {
+static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = {
.extra_priv_size = sizeof(struct ehci_mxc_priv),
};
@@ -61,8 +57,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ehci_hcd *ehci;
- dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
-
if (!pdata) {
dev_err(dev, "No platform data given, bailing out.\n");
return -EINVAL;
@@ -178,7 +172,7 @@ err_alloc:
return ret;
}
-static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
+static int ehci_mxc_drv_remove(struct platform_device *pdev)
{
struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 0555ee42d7cb..3d1491b5f360 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -4,10 +4,11 @@
* Bus Glue for the EHCI controllers in OMAP3/4
* Tested on several OMAP3 boards, and OMAP4 Pandaboard
*
- * Copyright (C) 2007-2011 Texas Instruments, Inc.
+ * Copyright (C) 2007-2013 Texas Instruments, Inc.
* Author: Vikram Pandita <vikram.pandita@ti.com>
* Author: Anand Gadiyar <gadiyar@ti.com>
* Author: Keshava Munegowda <keshava_mgowda@ti.com>
+ * Author: Roger Quadros <rogerq@ti.com>
*
* Copyright (C) 2009 Nokia Corporation
* Contact: Felipe Balbi <felipe.balbi@nokia.com>
@@ -28,21 +29,23 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * TODO (last updated Feb 27, 2010):
- * - add kernel-doc
- * - enable AUTOIDLE
- * - add suspend/resume
- * - add HSIC and TLL support
- * - convert to use hwmod and runtime PM
*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/ulpi.h>
-#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/clk.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+
+#include "ehci.h"
#include <linux/platform_data/usb-omap.h>
@@ -57,10 +60,16 @@
#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
-/*-------------------------------------------------------------------------*/
+#define DRIVER_DESC "OMAP-EHCI Host Controller driver"
+
+static const char hcd_name[] = "ehci-omap";
-static const struct hc_driver ehci_omap_hc_driver;
+/*-------------------------------------------------------------------------*/
+struct omap_hcd {
+ struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
+ int nports;
+};
static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
{
@@ -72,99 +81,16 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
return __raw_readl(base + reg);
}
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
-static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- unsigned reg = 0;
-
- reg = ULPI_FUNC_CTRL_RESET
- /* FUNCTION_CTRL_SET register */
- | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
- /* Write */
- | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
- /* PORTn */
- | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
- /* start ULPI access*/
- | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
-
- ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg);
-
- /* Wait for ULPI access completion */
- while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI)
- & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(hcd->self.controller,
- "phy reset operation timed out\n");
- break;
- }
- }
-}
-
-static int omap_ehci_init(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int rc;
- struct usbhs_omap_platform_data *pdata;
-
- pdata = hcd->self.controller->platform_data;
-
- /* Hold PHYs in reset while initializing EHCI controller */
- if (pdata->phy_reset) {
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0);
-
- /* Hold the PHY in RESET for enough time till DIR is high */
- udelay(10);
- }
-
- /* Soft reset the PHY using PHY reset command over ULPI */
- if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 0);
- if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY)
- omap_ehci_soft_phy_reset(hcd, 1);
-
- /* we know this is the memory we want, no need to ioremap again */
- ehci->caps = hcd->regs;
-
- rc = ehci_setup(hcd);
-
- if (pdata->phy_reset) {
- /* Hold the PHY in RESET for enough time till
- * PHY is settled and ready
- */
- udelay(10);
-
- if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
-
- if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
- }
-
- return rc;
-}
+static struct hc_driver __read_mostly ehci_omap_hc_driver;
-static void disable_put_regulator(
- struct usbhs_omap_platform_data *pdata)
-{
- int i;
-
- for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
- if (pdata->regulator[i]) {
- regulator_disable(pdata->regulator[i]);
- regulator_put(pdata->regulator[i]);
- }
- }
-}
+static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
+ .extra_priv_size = sizeof(struct omap_hcd),
+};
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
+static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32);
/**
* ehci_hcd_omap_probe - initialize TI-based HCDs
@@ -175,15 +101,15 @@ static void disable_put_regulator(
*/
static int ehci_hcd_omap_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usbhs_omap_platform_data *pdata = dev->platform_data;
- struct resource *res;
- struct usb_hcd *hcd;
- void __iomem *regs;
- int ret = -ENODEV;
- int irq;
- int i;
- char supply[7];
+ struct device *dev = &pdev->dev;
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
+ struct resource *res;
+ struct usb_hcd *hcd;
+ void __iomem *regs;
+ int ret = -ENODEV;
+ int irq;
+ int i;
+ struct omap_hcd *omap;
if (usb_disabled())
return -ENODEV;
@@ -193,52 +119,74 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq_byname(pdev, "ehci-irq");
- if (irq < 0) {
- dev_err(dev, "EHCI irq failed\n");
- return -ENODEV;
+ /* For DT boot, get platform data from parent. i.e. usbhshost */
+ if (dev->of_node) {
+ pdata = dev->parent->platform_data;
+ dev->platform_data = pdata;
}
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "ehci");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
+ if (!pdata) {
+ dev_err(dev, "Missing platform data\n");
return -ENODEV;
}
- regs = ioremap(res->start, resource_size(res));
- if (!regs) {
- dev_err(dev, "UHH EHCI ioremap failed\n");
- return -ENOMEM;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "EHCI irq failed\n");
+ return -ENODEV;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &omap_ehci_dma_mask;
+
hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
dev_name(dev));
if (!hcd) {
- dev_err(dev, "failed to create hcd with err %d\n", ret);
- ret = -ENOMEM;
- goto err_io;
+ dev_err(dev, "Failed to create HCD\n");
+ return -ENOMEM;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
-
- /* get ehci regulator and enable */
- for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
- if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) {
- pdata->regulator[i] = NULL;
- continue;
- }
- snprintf(supply, sizeof(supply), "hsusb%d", i);
- pdata->regulator[i] = regulator_get(dev, supply);
- if (IS_ERR(pdata->regulator[i])) {
- pdata->regulator[i] = NULL;
- dev_dbg(dev,
- "failed to get ehci port%d regulator\n", i);
- } else {
- regulator_enable(pdata->regulator[i]);
+ hcd_to_ehci(hcd)->caps = regs;
+
+ omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+ omap->nports = pdata->nports;
+
+ platform_set_drvdata(pdev, hcd);
+
+ /* get the PHY devices if needed */
+ for (i = 0 ; i < omap->nports ; i++) {
+ struct usb_phy *phy;
+
+ /* get the PHY device */
+ if (dev->of_node)
+ phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
+ else
+ phy = devm_usb_get_phy_dev(dev, i);
+ if (IS_ERR(phy)) {
+ /* Don't bail out if PHY is not absolutely necessary */
+ if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY)
+ continue;
+
+ ret = PTR_ERR(phy);
+ dev_err(dev, "Can't get PHY device for port %d: %d\n",
+ i, ret);
+ goto err_phy;
}
+
+ omap->phy[i] = phy;
}
pm_runtime_enable(dev);
@@ -262,16 +210,34 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
goto err_pm_runtime;
}
+ /*
+ * Bring PHYs out of reset.
+ * Even though HSIC mode is a PHY-less mode, the reset
+ * line exists between the chips and can be modelled
+ * as a PHY device for reset control.
+ */
+ for (i = 0; i < omap->nports; i++) {
+ if (!omap->phy[i])
+ continue;
+
+ usb_phy_init(omap->phy[i]);
+ /* bring PHY out of suspend */
+ usb_phy_set_suspend(omap->phy[i], 0);
+ }
return 0;
err_pm_runtime:
- disable_put_regulator(pdata);
pm_runtime_put_sync(dev);
+
+err_phy:
+ for (i = 0; i < omap->nports; i++) {
+ if (omap->phy[i])
+ usb_phy_shutdown(omap->phy[i]);
+ }
+
usb_put_hcd(hcd);
-err_io:
- iounmap(regs);
return ret;
}
@@ -286,14 +252,19 @@ err_io:
*/
static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
+ int i;
usb_remove_hcd(hcd);
- disable_put_regulator(dev->platform_data);
- iounmap(hcd->regs);
- usb_put_hcd(hcd);
+ for (i = 0; i < omap->nports; i++) {
+ if (omap->phy[i])
+ usb_phy_shutdown(omap->phy[i]);
+ }
+
+ usb_put_hcd(hcd);
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
@@ -308,6 +279,13 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id omap_ehci_dt_ids[] = {
+ { .compatible = "ti,ehci-omap" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
+
static struct platform_driver ehci_hcd_omap_driver = {
.probe = ehci_hcd_omap_probe,
.remove = ehci_hcd_omap_remove,
@@ -315,56 +293,35 @@ static struct platform_driver ehci_hcd_omap_driver = {
/*.suspend = ehci_hcd_omap_suspend, */
/*.resume = ehci_hcd_omap_resume, */
.driver = {
- .name = "ehci-omap",
+ .name = hcd_name,
+ .of_match_table = of_match_ptr(omap_ehci_dt_ids),
}
};
/*-------------------------------------------------------------------------*/
-static const struct hc_driver ehci_omap_hc_driver = {
- .description = hcd_name,
- .product_desc = "OMAP-EHCI Host Controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = omap_ehci_init,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
+static int __init ehci_omap_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
+ ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides);
+ return platform_driver_register(&ehci_hcd_omap_driver);
+}
+module_init(ehci_omap_init);
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
+static void __exit ehci_omap_cleanup(void)
+{
+ platform_driver_unregister(&ehci_hcd_omap_driver);
+}
+module_exit(ehci_omap_cleanup);
MODULE_ALIAS("platform:ehci-omap");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 914a3ecfb5d3..54c579485150 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -17,6 +17,12 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include "ehci.h"
#define rdl(off) __raw_readl(hcd->regs + (off))
#define wrl(off, val) __raw_writel((val), hcd->regs + (off))
@@ -34,6 +40,12 @@
#define USB_PHY_IVREF_CTRL 0x440
#define USB_PHY_TST_GRP_CTRL 0x450
+#define DRIVER_DESC "EHCI orion driver"
+
+static const char hcd_name[] = "ehci-orion";
+
+static struct hc_driver __read_mostly ehci_orion_hc_driver;
+
/*
* Implement Orion USB controller specification guidelines
*/
@@ -104,51 +116,6 @@ static void orion_usb_phy_v1_setup(struct usb_hcd *hcd)
wrl(USB_MODE, 0x13);
}
-static const struct hc_driver ehci_orion_hc_driver = {
- .description = hcd_name,
- .product_desc = "Marvell Orion EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
static void
ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
const struct mbus_dram_target_info *dram)
@@ -305,7 +272,7 @@ err1:
return err;
}
-static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
+static int ehci_orion_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct clk *clk;
@@ -323,8 +290,6 @@ static int __exit ehci_orion_drv_remove(struct platform_device *pdev)
return 0;
}
-MODULE_ALIAS("platform:orion-ehci");
-
static const struct of_device_id ehci_orion_dt_ids[] = {
{ .compatible = "marvell,orion-ehci", },
{},
@@ -333,7 +298,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);
static struct platform_driver ehci_orion_driver = {
.probe = ehci_orion_drv_probe,
- .remove = __exit_p(ehci_orion_drv_remove),
+ .remove = ehci_orion_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "orion-ehci",
@@ -341,3 +306,26 @@ static struct platform_driver ehci_orion_driver = {
.of_match_table = of_match_ptr(ehci_orion_dt_ids),
},
};
+
+static int __init ehci_orion_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+
+ ehci_init_driver(&ehci_orion_hc_driver, NULL);
+ return platform_driver_register(&ehci_orion_driver);
+}
+module_init(ehci_orion_init);
+
+static void __exit ehci_orion_cleanup(void)
+{
+ platform_driver_unregister(&ehci_orion_driver);
+}
+module_exit(ehci_orion_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_ALIAS("platform:orion-ehci");
+MODULE_AUTHOR("Tzachi Perelstein");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 170b9399e09f..595d210655b6 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -292,17 +292,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
}
-#ifdef CONFIG_USB_SUSPEND
- /* REVISIT: the controller works fine for wakeup iff the root hub
- * itself is "globally" suspended, but usbcore currently doesn't
- * understand such things.
- *
- * System suspend currently expects to be able to suspend the entire
- * device tree, device-at-a-time. If we failed selective suspend
- * reports, system suspend would fail; so the root hub code must claim
- * success. That's lying to usbcore, and it matters for runtime
- * PM scenarios with selective suspend and remote wakeup...
- */
+#ifdef CONFIG_PM_RUNTIME
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
#endif
@@ -385,7 +375,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
static struct hc_driver __read_mostly ehci_pci_hc_driver;
-static const struct ehci_driver_overrides pci_overrides __initdata = {
+static const struct ehci_driver_overrides pci_overrides __initconst = {
.reset = ehci_pci_setup,
};
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index ca7506390542..f47f2594c9d4 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -18,11 +18,13 @@
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
@@ -58,26 +60,36 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
static struct hc_driver __read_mostly ehci_platform_hc_driver;
-static const struct ehci_driver_overrides platform_overrides __initdata = {
+static const struct ehci_driver_overrides platform_overrides __initconst = {
.reset = ehci_platform_reset,
};
+static struct usb_ehci_pdata ehci_platform_defaults;
+
static int ehci_platform_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
- struct usb_ehci_pdata *pdata = dev->dev.platform_data;
+ struct usb_ehci_pdata *pdata;
int irq;
int err = -ENOMEM;
- if (!pdata) {
- WARN_ON(1);
- return -ENODEV;
- }
-
if (usb_disabled())
return -ENODEV;
+ /*
+ * use reasonable defaults so platforms don't have to provide these.
+ * with DT probing on ARM, none of these are set.
+ */
+ if (!dev->dev.platform_data)
+ dev->dev.platform_data = &ehci_platform_defaults;
+ if (!dev->dev.dma_mask)
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ if (!dev->dev.coherent_dma_mask)
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ pdata = dev->dev.platform_data;
+
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
@@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev)
if (pdata->power_off)
pdata->power_off(dev);
+ if (pdata == &ehci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
return 0;
}
@@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev)
#define ehci_platform_resume NULL
#endif /* CONFIG_PM */
+static const struct of_device_id vt8500_ehci_ids[] = {
+ { .compatible = "via,vt8500-ehci", },
+ { .compatible = "wm,prizm-ehci", },
+ {}
+};
+
static const struct platform_device_id ehci_platform_table[] = {
{ "ehci-platform", 0 },
{ }
@@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = {
.owner = THIS_MODULE,
.name = "ehci-platform",
.pm = &ehci_platform_pm_ops,
+ .of_match_table = of_match_ptr(vt8500_ehci_ids),
}
};
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index df5925a4f0db..fd983771b025 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -221,7 +221,6 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
tmp = hcd->irq;
- ehci_shutdown(hcd);
usb_remove_hcd(hcd);
ps3_system_bus_set_drvdata(dev, NULL);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 23d136904285..d34b399b78e2 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
struct ehci_qh_hw *hw = qh->hw;
/* writes to an active overlay are unsafe */
- BUG_ON(qh->qh_state != QH_STATE_IDLE);
+ WARN_ON(qh->qh_state != QH_STATE_IDLE);
hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
hw->hw_alt_next = EHCI_LIST_END(ehci);
@@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *qtd;
- if (list_empty (&qh->qtd_list))
- qtd = qh->dummy;
- else {
- qtd = list_entry (qh->qtd_list.next,
- struct ehci_qtd, qtd_list);
- /*
- * first qtd may already be partially processed.
- * If we come here during unlink, the QH overlay region
- * might have reference to the just unlinked qtd. The
- * qtd is updated in qh_completions(). Update the QH
- * overlay here.
- */
- if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
- qh->hw->hw_qtd_next = qtd->hw_next;
- qtd = NULL;
- }
- }
+ qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list);
- if (qtd)
- qh_update (ehci, qh, qtd);
+ /*
+ * first qtd may already be partially processed.
+ * If we come here during unlink, the QH overlay region
+ * might have reference to the just unlinked qtd. The
+ * qtd is updated in qh_completions(). Update the QH
+ * overlay here.
+ */
+ if (qh->hw->hw_token & ACTIVE_BIT(ehci))
+ qh->hw->hw_qtd_next = qtd->hw_next;
+ else
+ qh_update(ehci, qh, qtd);
}
/*-------------------------------------------------------------------------*/
@@ -299,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/*
* Process and free completed qtds for a qh, returning URBs to drivers.
- * Chases up to qh->hw_current. Returns number of completions called,
- * indicating how much "real" work we did.
+ * Chases up to qh->hw_current. Returns nonzero if the caller should
+ * unlink qh.
*/
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -309,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct list_head *entry, *tmp;
int last_status;
int stopped;
- unsigned count = 0;
u8 state;
struct ehci_qh_hw *hw = qh->hw;
- if (unlikely (list_empty (&qh->qtd_list)))
- return count;
-
/* completions (or tasks on other cpus) must never clobber HALT
* till we've gone through and cleaned everything up, even when
* they add urbs to this qh's queue or mark them for unlinking.
@@ -333,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
rescan:
last = NULL;
last_status = -EINPROGRESS;
- qh->needs_rescan = 0;
+ qh->dequeue_during_giveback = 0;
/* remove de-activated QTDs from front of queue.
* after faults (including short reads), cleanup this urb
@@ -352,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (last) {
if (likely (last->urb != urb)) {
ehci_urb_done(ehci, last->urb, last_status);
- count++;
last_status = -EINPROGRESS;
}
ehci_qtd_free (ehci, last);
@@ -526,23 +514,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
ehci_urb_done(ehci, last->urb, last_status);
- count++;
ehci_qtd_free (ehci, last);
}
/* Do we need to rescan for URBs dequeued during a giveback? */
- if (unlikely(qh->needs_rescan)) {
+ if (unlikely(qh->dequeue_during_giveback)) {
/* If the QH is already unlinked, do the rescan now. */
if (state == QH_STATE_IDLE)
goto rescan;
- /* Otherwise we have to wait until the QH is fully unlinked.
- * Our caller will start an unlink if qh->needs_rescan is
- * set. But if an unlink has already started, nothing needs
- * to be done.
- */
- if (state != QH_STATE_LINKED)
- qh->needs_rescan = 0;
+ /* Otherwise the caller must unlink the QH. */
}
/* restore original state; caller must unlink or relink */
@@ -551,33 +532,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* be sure the hardware's done with the qh before refreshing
* it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter).
+ *
+ * We won't refresh a QH that's linked (after the HC
+ * stopped the queue). That avoids a race:
+ * - HC reads first part of QH;
+ * - CPU updates that first part and the token;
+ * - HC reads rest of that QH, including token
+ * Result: HC gets an inconsistent image, and then
+ * DMAs to/from the wrong memory (corrupting it).
+ *
+ * That should be rare for interrupt transfers,
+ * except maybe high bandwidth ...
*/
- if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
- switch (state) {
- case QH_STATE_IDLE:
- qh_refresh(ehci, qh);
- break;
- case QH_STATE_LINKED:
- /* We won't refresh a QH that's linked (after the HC
- * stopped the queue). That avoids a race:
- * - HC reads first part of QH;
- * - CPU updates that first part and the token;
- * - HC reads rest of that QH, including token
- * Result: HC gets an inconsistent image, and then
- * DMAs to/from the wrong memory (corrupting it).
- *
- * That should be rare for interrupt transfers,
- * except maybe high bandwidth ...
- */
+ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci))
+ qh->exception = 1;
- /* Tell the caller to start an unlink */
- qh->needs_rescan = 1;
- break;
- /* otherwise, unlink already started */
- }
- }
-
- return count;
+ /* Let the caller know if the QH needs to be unlinked. */
+ return qh->exception;
}
/*-------------------------------------------------------------------------*/
@@ -957,14 +928,13 @@ done:
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
- /* init as live, toggle clear, advance to dummy */
+ /* init as live, toggle clear */
qh->qh_state = QH_STATE_IDLE;
hw = qh->hw;
hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2);
qh->is_out = !is_input;
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
- qh_refresh (ehci, qh);
return qh;
}
@@ -988,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci)
if (--ehci->async_count)
return;
- /* The async schedule and async_unlink list are supposed to be empty */
- WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink);
+ /* The async schedule and unlink lists are supposed to be empty */
+ WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) ||
+ !list_empty(&ehci->async_idle));
/* Don't turn off the schedule until ASS is 1 */
ehci_poll_ASS(ehci);
@@ -1020,8 +991,9 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh;
head->hw->hw_next = dma;
- qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED;
+ qh->xacterrs = 0;
+ qh->exception = 0;
/* qtd completions reported later by interrupt */
enable_async(ehci);
@@ -1179,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
/* Add to the end of the list of QHs waiting for the next IAAD */
qh->qh_state = QH_STATE_UNLINK_WAIT;
- if (ehci->async_unlink)
- ehci->async_unlink_last->unlink_next = qh;
- else
- ehci->async_unlink = qh;
- ehci->async_unlink_last = qh;
+ list_add_tail(&qh->unlink_node, &ehci->async_unlink);
/* Unlink it from the schedule */
prev = ehci->async;
@@ -1196,44 +1164,19 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->qh_scan_next = qh->qh_next.qh;
}
-static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
+static void start_iaa_cycle(struct ehci_hcd *ehci)
{
- /*
- * Do nothing if an IAA cycle is already running or
- * if one will be started shortly.
- */
- if (ehci->async_iaa || ehci->async_unlinking)
+ /* Do nothing if an IAA cycle is already running */
+ if (ehci->iaa_in_progress)
return;
+ ehci->iaa_in_progress = true;
/* If the controller isn't running, we don't have to wait for it */
if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) {
-
- /* Do all the waiting QHs */
- ehci->async_iaa = ehci->async_unlink;
- ehci->async_unlink = NULL;
-
- if (!nested) /* Avoid recursion */
- end_unlink_async(ehci);
+ end_unlink_async(ehci);
/* Otherwise start a new IAA cycle */
} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) {
- struct ehci_qh *qh;
-
- /* Do only the first waiting QH (nVidia bug?) */
- qh = ehci->async_unlink;
-
- /*
- * Intel (?) bug: The HC can write back the overlay region
- * even after the IAA interrupt occurs. In self-defense,
- * always go through two IAA cycles for each QH.
- */
- if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
- qh->qh_state = QH_STATE_UNLINK;
- } else {
- ehci->async_iaa = qh;
- ehci->async_unlink = qh->unlink_next;
- qh->unlink_next = NULL;
- }
/* Make sure the unlinks are all visible to the hardware */
wmb();
@@ -1250,36 +1193,73 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)
static void end_unlink_async(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
+ bool early_exit;
if (ehci->has_synopsys_hc_bug)
ehci_writel(ehci, (u32) ehci->async->qh_dma,
&ehci->regs->async_next);
+ /* The current IAA cycle has ended */
+ ehci->iaa_in_progress = false;
+
+ if (list_empty(&ehci->async_unlink))
+ return;
+ qh = list_first_entry(&ehci->async_unlink, struct ehci_qh,
+ unlink_node); /* QH whose IAA cycle just ended */
+
+ /*
+ * If async_unlinking is set then this routine is already running,
+ * either on the stack or on another CPU.
+ */
+ early_exit = ehci->async_unlinking;
+
+ /* If the controller isn't running, process all the waiting QHs */
+ if (ehci->rh_state < EHCI_RH_RUNNING)
+ list_splice_tail_init(&ehci->async_unlink, &ehci->async_idle);
+
+ /*
+ * Intel (?) bug: The HC can write back the overlay region even
+ * after the IAA interrupt occurs. In self-defense, always go
+ * through two IAA cycles for each QH.
+ */
+ else if (qh->qh_state == QH_STATE_UNLINK_WAIT) {
+ qh->qh_state = QH_STATE_UNLINK;
+ early_exit = true;
+ }
+
+ /* Otherwise process only the first waiting QH (NVIDIA bug?) */
+ else
+ list_move_tail(&qh->unlink_node, &ehci->async_idle);
+
+ /* Start a new IAA cycle if any QHs are waiting for it */
+ if (!list_empty(&ehci->async_unlink))
+ start_iaa_cycle(ehci);
+
+ /*
+ * Don't allow nesting or concurrent calls,
+ * or wait for the second IAA cycle for the next QH.
+ */
+ if (early_exit)
+ return;
+
/* Process the idle QHs */
- restart:
ehci->async_unlinking = true;
- while (ehci->async_iaa) {
- qh = ehci->async_iaa;
- ehci->async_iaa = qh->unlink_next;
- qh->unlink_next = NULL;
+ while (!list_empty(&ehci->async_idle)) {
+ qh = list_first_entry(&ehci->async_idle, struct ehci_qh,
+ unlink_node);
+ list_del(&qh->unlink_node);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
- qh_completions(ehci, qh);
+ if (!list_empty(&qh->qtd_list))
+ qh_completions(ehci, qh);
if (!list_empty(&qh->qtd_list) &&
ehci->rh_state == EHCI_RH_RUNNING)
qh_link_async(ehci, qh);
disable_async(ehci);
}
ehci->async_unlinking = false;
-
- /* Start a new IAA cycle if any QHs are waiting for it */
- if (ehci->async_unlink) {
- start_iaa_cycle(ehci, true);
- if (unlikely(ehci->rh_state < EHCI_RH_RUNNING))
- goto restart;
- }
}
static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
@@ -1288,7 +1268,6 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
struct ehci_qh *qh_to_unlink = NULL;
- bool check_unlinks_later = false;
int count = 0;
/* Find the last async QH which has been empty for a timer cycle */
@@ -1296,15 +1275,13 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
if (list_empty(&qh->qtd_list) &&
qh->qh_state == QH_STATE_LINKED) {
++count;
- if (qh->unlink_cycle == ehci->async_unlink_cycle)
- check_unlinks_later = true;
- else
+ if (qh->unlink_cycle != ehci->async_unlink_cycle)
qh_to_unlink = qh;
}
}
/* If nothing else is being unlinked, unlink the last empty QH */
- if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) {
+ if (list_empty(&ehci->async_unlink) && qh_to_unlink) {
start_unlink_async(ehci, qh_to_unlink);
--count;
}
@@ -1317,7 +1294,7 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
}
/* The root hub is suspended; unlink all the async QHs */
-static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
+static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
@@ -1326,7 +1303,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
WARN_ON(!list_empty(&qh->qtd_list));
single_unlink_async(ehci, qh);
}
- start_iaa_cycle(ehci, false);
+ start_iaa_cycle(ehci);
}
/* makes sure the async qh will become idle */
@@ -1334,19 +1311,12 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /*
- * If the QH isn't linked then there's nothing we can do
- * unless we were called during a giveback, in which case
- * qh_completions() has to deal with it.
- */
- if (qh->qh_state != QH_STATE_LINKED) {
- if (qh->qh_state == QH_STATE_COMPLETING)
- qh->needs_rescan = 1;
+ /* If the QH isn't linked then there's nothing we can do. */
+ if (qh->qh_state != QH_STATE_LINKED)
return;
- }
single_unlink_async(ehci, qh);
- start_iaa_cycle(ehci, false);
+ start_iaa_cycle(ehci);
}
/*-------------------------------------------------------------------------*/
@@ -1360,7 +1330,7 @@ static void scan_async (struct ehci_hcd *ehci)
while (ehci->qh_scan_next) {
qh = ehci->qh_scan_next;
ehci->qh_scan_next = qh->qh_next.qh;
- rescan:
+
/* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) {
int temp;
@@ -1373,14 +1343,13 @@ static void scan_async (struct ehci_hcd *ehci)
* in single_unlink_async().
*/
temp = qh_completions(ehci, qh);
- if (qh->needs_rescan) {
+ if (unlikely(temp)) {
start_unlink_async(ehci, qh);
} else if (list_empty(&qh->qtd_list)
&& qh->qh_state == QH_STATE_LINKED) {
qh->unlink_cycle = ehci->async_unlink_cycle;
check_unlinks_later = true;
- } else if (temp != 0)
- goto rescan;
+ }
}
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 20ebf6a8b7f4..635775278c7f 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -13,13 +13,23 @@
*/
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
-#include <linux/platform_device.h>
#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
#include <linux/platform_data/usb-ehci-s5p.h>
#include <linux/usb/phy.h>
#include <linux/usb/samsung_usb_phy.h>
-#include <plat/usb-phy.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/otg.h>
+
+#include "ehci.h"
+
+#define DRIVER_DESC "EHCI s5p driver"
#define EHCI_INSNREG00(base) (base + 0x90)
#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25)
@@ -30,82 +40,35 @@
(EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
+static const char hcd_name[] = "ehci-s5p";
+static struct hc_driver __read_mostly s5p_ehci_hc_driver;
+
struct s5p_ehci_hcd {
- struct device *dev;
- struct usb_hcd *hcd;
struct clk *clk;
struct usb_phy *phy;
struct usb_otg *otg;
struct s5p_ehci_platdata *pdata;
};
-static const struct hc_driver s5p_ehci_hc_driver = {
- .description = hcd_name,
- .product_desc = "S5P EHCI Host Controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- .get_frame_number = ehci_get_frame,
-
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
-
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci)
-{
- struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
-
- if (s5p_ehci->phy)
- usb_phy_init(s5p_ehci->phy);
- else if (s5p_ehci->pdata->phy_init)
- s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
-}
-
-static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)
-{
- struct platform_device *pdev = to_platform_device(s5p_ehci->dev);
-
- if (s5p_ehci->phy)
- usb_phy_shutdown(s5p_ehci->phy);
- else if (s5p_ehci->pdata->phy_exit)
- s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
-}
+#define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
static void s5p_setup_vbus_gpio(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
int err;
int gpio;
- if (!pdev->dev.of_node)
+ if (!dev->of_node)
return;
- gpio = of_get_named_gpio(pdev->dev.of_node,
- "samsung,vbus-gpio", 0);
+ gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);
if (!gpio_is_valid(gpio))
return;
- err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio");
+ err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH,
+ "ehci_vbus_gpio");
if (err)
- dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio);
+ dev_err(dev, "can't request ehci vbus gpio %d", gpio);
}
static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
@@ -133,13 +96,15 @@ static int s5p_ehci_probe(struct platform_device *pdev)
s5p_setup_vbus_gpio(pdev);
- s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd),
- GFP_KERNEL);
- if (!s5p_ehci)
+ hcd = usb_create_hcd(&s5p_ehci_hc_driver,
+ &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd) {
+ dev_err(&pdev->dev, "Unable to create HCD\n");
return -ENOMEM;
-
+ }
+ s5p_ehci = to_s5p_ehci(hcd);
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback to pdata */
if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
@@ -152,16 +117,6 @@ static int s5p_ehci_probe(struct platform_device *pdev)
s5p_ehci->otg = phy->otg;
}
- s5p_ehci->dev = &pdev->dev;
-
- hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
- if (!hcd) {
- dev_err(&pdev->dev, "Unable to create HCD\n");
- return -ENOMEM;
- }
-
- s5p_ehci->hcd = hcd;
s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
if (IS_ERR(s5p_ehci->clk)) {
@@ -198,9 +153,12 @@ static int s5p_ehci_probe(struct platform_device *pdev)
}
if (s5p_ehci->otg)
- s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self);
+ s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
- s5p_ehci_phy_enable(s5p_ehci);
+ if (s5p_ehci->phy)
+ usb_phy_init(s5p_ehci->phy);
+ else if (s5p_ehci->pdata->phy_init)
+ s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
@@ -214,12 +172,15 @@ static int s5p_ehci_probe(struct platform_device *pdev)
goto fail_add_hcd;
}
- platform_set_drvdata(pdev, s5p_ehci);
+ platform_set_drvdata(pdev, hcd);
return 0;
fail_add_hcd:
- s5p_ehci_phy_disable(s5p_ehci);
+ if (s5p_ehci->phy)
+ usb_phy_shutdown(s5p_ehci->phy);
+ else if (s5p_ehci->pdata->phy_exit)
+ s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
fail_io:
clk_disable_unprepare(s5p_ehci->clk);
fail_clk:
@@ -229,15 +190,18 @@ fail_clk:
static int s5p_ehci_remove(struct platform_device *pdev)
{
- struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = s5p_ehci->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
usb_remove_hcd(hcd);
if (s5p_ehci->otg)
- s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self);
+ s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
- s5p_ehci_phy_disable(s5p_ehci);
+ if (s5p_ehci->phy)
+ usb_phy_shutdown(s5p_ehci->phy);
+ else if (s5p_ehci->pdata->phy_exit)
+ s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
clk_disable_unprepare(s5p_ehci->clk);
@@ -248,8 +212,7 @@ static int s5p_ehci_remove(struct platform_device *pdev)
static void s5p_ehci_shutdown(struct platform_device *pdev)
{
- struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev);
- struct usb_hcd *hcd = s5p_ehci->hcd;
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
@@ -258,17 +221,22 @@ static void s5p_ehci_shutdown(struct platform_device *pdev)
#ifdef CONFIG_PM
static int s5p_ehci_suspend(struct device *dev)
{
- struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
- struct usb_hcd *hcd = s5p_ehci->hcd;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
+ struct platform_device *pdev = to_platform_device(dev);
+
bool do_wakeup = device_may_wakeup(dev);
int rc;
rc = ehci_suspend(hcd, do_wakeup);
if (s5p_ehci->otg)
- s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self);
+ s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
- s5p_ehci_phy_disable(s5p_ehci);
+ if (s5p_ehci->phy)
+ usb_phy_shutdown(s5p_ehci->phy);
+ else if (s5p_ehci->pdata->phy_exit)
+ s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
clk_disable_unprepare(s5p_ehci->clk);
@@ -277,15 +245,19 @@ static int s5p_ehci_suspend(struct device *dev)
static int s5p_ehci_resume(struct device *dev)
{
- struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
- struct usb_hcd *hcd = s5p_ehci->hcd;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd);
+ struct platform_device *pdev = to_platform_device(dev);
clk_prepare_enable(s5p_ehci->clk);
if (s5p_ehci->otg)
- s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self);
+ s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self);
- s5p_ehci_phy_enable(s5p_ehci);
+ if (s5p_ehci->phy)
+ usb_phy_init(s5p_ehci->phy);
+ else if (s5p_ehci->pdata->phy_init)
+ s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
/* DMA burst Enable */
writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
@@ -322,5 +294,29 @@ static struct platform_driver s5p_ehci_driver = {
.of_match_table = of_match_ptr(exynos_ehci_match),
}
};
+static const struct ehci_driver_overrides s5p_overrides __initdata = {
+ .extra_priv_size = sizeof(struct s5p_ehci_hcd),
+};
+
+static int __init ehci_s5p_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+ ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides);
+ return platform_driver_register(&s5p_ehci_driver);
+}
+module_init(ehci_s5p_init);
+
+static void __exit ehci_s5p_cleanup(void)
+{
+ platform_driver_unregister(&s5p_ehci_driver);
+}
+module_exit(ehci_s5p_cleanup);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_ALIAS("platform:s5p-ehci");
+MODULE_AUTHOR("Jingoo Han");
+MODULE_AUTHOR("Joonyoung Shim");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index b476daf49f6f..acff5b8f6e89 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
}
qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0;
+ qh->exception = 0;
/* update per-qh bandwidth for usbfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
@@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* If the QH isn't linked then there's nothing we can do
- * unless we were called during a giveback, in which case
- * qh_completions() has to deal with it.
- */
- if (qh->qh_state != QH_STATE_LINKED) {
- if (qh->qh_state == QH_STATE_COMPLETING)
- qh->needs_rescan = 1;
+ /* If the QH isn't linked then there's nothing we can do. */
+ if (qh->qh_state != QH_STATE_LINKED)
return;
- }
qh_unlink_periodic (ehci, qh);
@@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->unlink_cycle = ehci->intr_unlink_cycle;
/* New entries go at the end of the intr_unlink list */
- if (ehci->intr_unlink)
- ehci->intr_unlink_last->unlink_next = qh;
- else
- ehci->intr_unlink = qh;
- ehci->intr_unlink_last = qh;
+ list_add_tail(&qh->unlink_node, &ehci->intr_unlink);
if (ehci->intr_unlinking)
; /* Avoid recursive calls */
else if (ehci->rh_state < EHCI_RH_RUNNING)
ehci_handle_intr_unlinks(ehci);
- else if (ehci->intr_unlink == qh) {
+ else if (ehci->intr_unlink.next == &qh->unlink_node) {
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
++ehci->intr_unlink_cycle;
}
@@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_IDLE;
hw->hw_next = EHCI_LIST_END(ehci);
- qh_completions(ehci, qh);
+ if (!list_empty(&qh->qtd_list))
+ qh_completions(ehci, qh);
/* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
@@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
struct ehci_qh_hw *hw = qh->hw;
- qh_refresh(ehci, qh);
hw->hw_next = EHCI_LIST_END(ehci);
frame = qh->start;
@@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
} else
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
- /* stuff into the periodic schedule */
- qh_link_periodic(ehci, qh);
done:
return status;
}
@@ -891,6 +880,12 @@ static int intr_submit (
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
+ /* stuff into the periodic schedule */
+ if (qh->qh_state == QH_STATE_IDLE) {
+ qh_refresh(ehci, qh);
+ qh_link_periodic(ehci, qh);
+ }
+
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
@@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci)
list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
intr_node) {
- rescan:
+
/* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) {
int temp;
@@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci)
* in qh_unlink_periodic().
*/
temp = qh_completions(ehci, qh);
- if (unlikely(qh->needs_rescan ||
- (list_empty(&qh->qtd_list) &&
- qh->qh_state == QH_STATE_LINKED)))
+ if (unlikely(temp || (list_empty(&qh->qtd_list) &&
+ qh->qh_state == QH_STATE_LINKED)))
start_unlink_intr(ehci, qh);
- else if (temp != 0)
- goto rescan;
}
}
}
@@ -1214,6 +1206,7 @@ itd_urb_transaction (
memset (itd, 0, sizeof *itd);
itd->itd_dma = itd_dma;
+ itd->frame = 9999; /* an invalid value */
list_add (&itd->itd_list, &sched->td_list);
}
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1915,6 +1908,7 @@ sitd_urb_transaction (
memset (sitd, 0, sizeof *sitd);
sitd->sitd_dma = sitd_dma;
+ sitd->frame = 9999; /* an invalid value */
list_add (&sitd->sitd_list, &iso_sched->td_list);
}
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 3565a300f401..b44d716ddc82 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -77,7 +77,6 @@ static const struct hc_driver ehci_sh_hc_driver = {
static int ehci_hcd_sh_probe(struct platform_device *pdev)
{
- const struct hc_driver *driver = &ehci_sh_hc_driver;
struct resource *res;
struct ehci_sh_priv *priv;
struct ehci_sh_platdata *pdata;
@@ -170,7 +169,7 @@ fail_create_hcd:
return ret;
}
-static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
+static int ehci_hcd_sh_remove(struct platform_device *pdev)
{
struct ehci_sh_priv *priv = platform_get_drvdata(pdev);
struct usb_hcd *hcd = priv->hcd;
@@ -196,7 +195,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev)
static struct platform_driver ehci_hcd_sh_driver = {
.probe = ehci_hcd_sh_probe,
- .remove = __exit_p(ehci_hcd_sh_remove),
+ .remove = ehci_hcd_sh_remove,
.shutdown = ehci_hcd_sh_shutdown,
.driver = {
.name = "sh_ehci",
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 466c1bb5b967..61ecfb3d52f5 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -1,5 +1,5 @@
/*
-* Driver for EHCI HCD on SPEAR SOC
+* Driver for EHCI HCD on SPEAr SOC
*
* Copyright (C) 2010 ST Micro Electronics,
* Deepak Sikri <deepak.sikri@st.com>
@@ -12,73 +12,32 @@
*/
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
-struct spear_ehci {
- struct ehci_hcd ehci;
- struct clk *clk;
-};
-
-#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd)
+#include "ehci.h"
-static void spear_start_ehci(struct spear_ehci *ehci)
-{
- clk_prepare_enable(ehci->clk);
-}
+#define DRIVER_DESC "EHCI SPEAr driver"
-static void spear_stop_ehci(struct spear_ehci *ehci)
-{
- clk_disable_unprepare(ehci->clk);
-}
+static const char hcd_name[] = "SPEAr-ehci";
-static int ehci_spear_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-
- /* registers start at offset 0x0 */
- ehci->caps = hcd->regs;
+struct spear_ehci {
+ struct clk *clk;
+};
- return ehci_setup(hcd);
-}
+#define to_spear_ehci(hcd) (struct spear_ehci *)(hcd_to_ehci(hcd)->priv)
-static const struct hc_driver ehci_spear_hc_driver = {
- .description = hcd_name,
- .product_desc = "SPEAr EHCI",
- .hcd_priv_size = sizeof(struct spear_ehci),
-
- /* generic hardware linkage */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /* basic lifecycle operations */
- .reset = ehci_spear_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /* managing i/o requests and associated device resources */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /* scheduling support */
- .get_frame_number = ehci_get_frame,
-
- /* root hub support */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
+static struct hc_driver __read_mostly ehci_spear_hc_driver;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ehci_spear_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -94,7 +53,7 @@ static int ehci_spear_drv_resume(struct device *dev)
ehci_resume(hcd, false);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
ehci_spear_drv_resume);
@@ -104,7 +63,7 @@ static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
- struct spear_ehci *ehci;
+ struct spear_ehci *sehci;
struct resource *res;
struct clk *usbh_clk;
const struct hc_driver *driver = &ehci_spear_hc_driver;
@@ -161,10 +120,13 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
goto err_put_hcd;
}
- ehci = (struct spear_ehci *)hcd_to_ehci(hcd);
- ehci->clk = usbh_clk;
+ sehci = to_spear_ehci(hcd);
+ sehci->clk = usbh_clk;
+
+ /* registers start at offset 0x0 */
+ hcd_to_ehci(hcd)->caps = hcd->regs;
- spear_start_ehci(ehci);
+ clk_prepare_enable(sehci->clk);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto err_stop_ehci;
@@ -172,7 +134,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
return retval;
err_stop_ehci:
- spear_stop_ehci(ehci);
+ clk_disable_unprepare(sehci->clk);
err_put_hcd:
usb_put_hcd(hcd);
fail:
@@ -184,7 +146,7 @@ fail:
static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct spear_ehci *ehci_p = to_spear_ehci(hcd);
+ struct spear_ehci *sehci = to_spear_ehci(hcd);
if (!hcd)
return 0;
@@ -192,8 +154,8 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
BUG();
usb_remove_hcd(hcd);
- if (ehci_p->clk)
- spear_stop_ehci(ehci_p);
+ if (sehci->clk)
+ clk_disable_unprepare(sehci->clk);
usb_put_hcd(hcd);
return 0;
@@ -216,4 +178,29 @@ static struct platform_driver spear_ehci_hcd_driver = {
}
};
+static const struct ehci_driver_overrides spear_overrides __initdata = {
+ .extra_priv_size = sizeof(struct spear_ehci),
+};
+
+static int __init ehci_spear_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+
+ ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides);
+ return platform_driver_register(&spear_ehci_hcd_driver);
+}
+module_init(ehci_spear_init);
+
+static void __exit ehci_spear_cleanup(void)
+{
+ platform_driver_unregister(&spear_ehci_hcd_driver);
+}
+module_exit(ehci_spear_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_ALIAS("platform:spear-ehci");
+MODULE_AUTHOR("Deepak Sikri");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 568aecc7075b..e3eddc31ac83 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -28,6 +28,7 @@
#include <linux/pm_runtime.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/tegra_usb_phy.h>
+#include <linux/clk/tegra.h>
#define TEGRA_USB_BASE 0xC5000000
#define TEGRA_USB2_BASE 0xC5004000
@@ -610,7 +611,7 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = {
/* Bits of PORTSC1, which will get cleared by writing 1 into them */
#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
-void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
+static void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
@@ -621,9 +622,8 @@ void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val)
val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3);
writel(val, base + TEGRA_USB_PORTSC1);
}
-EXPORT_SYMBOL_GPL(tegra_ehci_set_pts);
-void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
+static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
{
unsigned long val;
struct usb_hcd *hcd = bus_to_hcd(x->otg->host);
@@ -636,7 +636,6 @@ void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
val &= ~TEGRA_USB_PORTSC1_PHCD;
writel(val, base + TEGRA_USB_PORTSC1);
}
-EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd);
static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32);
@@ -691,6 +690,10 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (err)
goto fail_clk;
+ tegra_periph_reset_assert(tegra->clk);
+ udelay(1);
+ tegra_periph_reset_deassert(tegra->clk);
+
tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,
"nvidia,needs-double-reset");
@@ -733,7 +736,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs,
pdata->phy_config,
- TEGRA_USB_PHY_MODE_HOST);
+ TEGRA_USB_PHY_MODE_HOST,
+ tegra_ehci_set_pts,
+ tegra_ehci_set_phcd);
if (IS_ERR(tegra->phy)) {
dev_err(&pdev->dev, "Failed to open USB phy\n");
err = -ENXIO;
@@ -755,7 +760,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
err = usb_phy_set_suspend(hcd->phy, 0);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
- goto fail;
+ goto fail_phy;
}
tegra->host_resumed = 1;
@@ -765,17 +770,17 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
- goto fail;
+ goto fail_phy;
}
-#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
tegra->transceiver =
devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, &hcd->self);
+ } else {
+ tegra->transceiver = ERR_PTR(-ENODEV);
}
-#endif
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
@@ -794,10 +799,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
return err;
fail:
-#ifdef CONFIG_USB_OTG_UTILS
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
-#endif
+fail_phy:
usb_phy_shutdown(hcd->phy);
fail_io:
clk_disable_unprepare(tegra->clk);
@@ -815,10 +819,8 @@ static int tegra_ehci_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-#ifdef CONFIG_USB_OTG_UTILS
- if (!IS_ERR_OR_NULL(tegra->transceiver))
+ if (!IS_ERR(tegra->transceiver))
otg_set_host(tegra->transceiver->otg, NULL);
-#endif
usb_phy_shutdown(hcd->phy);
usb_remove_hcd(hcd);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index c3fa1305f830..11e5b32f73e9 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)
if (want != actual) {
- /* Poll again later, but give up after about 20 ms */
- if (ehci->ASS_poll_count++ < 20) {
+ /* Poll again later, but give up after about 2-4 ms */
+ if (ehci->ASS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);
return;
}
@@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
if (want != actual) {
- /* Poll again later, but give up after about 20 ms */
- if (ehci->PSS_poll_count++ < 20) {
+ /* Poll again later, but give up after about 2-4 ms */
+ if (ehci->PSS_poll_count++ < 2) {
ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
return;
}
@@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
* process all the QHs on the list.
*/
ehci->intr_unlinking = true;
- while (ehci->intr_unlink) {
- struct ehci_qh *qh = ehci->intr_unlink;
+ while (!list_empty(&ehci->intr_unlink)) {
+ struct ehci_qh *qh;
+ qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh,
+ unlink_node);
if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)
break;
- ehci->intr_unlink = qh->unlink_next;
- qh->unlink_next = NULL;
+ list_del(&qh->unlink_node);
end_unlink_intr(ehci, qh);
}
/* Handle remaining entries later */
- if (ehci->intr_unlink) {
+ if (!list_empty(&ehci->intr_unlink)) {
ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
++ehci->intr_unlink_cycle;
}
@@ -295,8 +296,7 @@ static void end_free_itds(struct ehci_hcd *ehci)
/* Handle lost (or very late) IAA interrupts */
static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
{
- if (ehci->rh_state != EHCI_RH_RUNNING)
- return;
+ u32 cmd, status;
/*
* Lost IAA irqs wedge things badly; seen first with a vt8235.
@@ -304,34 +304,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)
* (a) SMP races against real IAA firing and retriggering, and
* (b) clean HC shutdown, when IAA watchdog was pending.
*/
- if (1) {
- u32 cmd, status;
-
- /* If we get here, IAA is *REALLY* late. It's barely
- * conceivable that the system is so busy that CMD_IAAD
- * is still legitimately set, so let's be sure it's
- * clear before we read STS_IAA. (The HC should clear
- * CMD_IAAD when it sets STS_IAA.)
- */
- cmd = ehci_readl(ehci, &ehci->regs->command);
-
- /*
- * If IAA is set here it either legitimately triggered
- * after the watchdog timer expired (_way_ late, so we'll
- * still count it as lost) ... or a silicon erratum:
- * - VIA seems to set IAA without triggering the IRQ;
- * - IAAD potentially cleared without setting IAA.
- */
- status = ehci_readl(ehci, &ehci->regs->status);
- if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
- COUNT(ehci->stats.lost_iaa);
- ehci_writel(ehci, STS_IAA, &ehci->regs->status);
- }
+ if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING)
+ return;
+
+ /* If we get here, IAA is *REALLY* late. It's barely
+ * conceivable that the system is so busy that CMD_IAAD
+ * is still legitimately set, so let's be sure it's
+ * clear before we read STS_IAA. (The HC should clear
+ * CMD_IAAD when it sets STS_IAA.)
+ */
+ cmd = ehci_readl(ehci, &ehci->regs->command);
- ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n",
- status, cmd);
- end_unlink_async(ehci);
+ /*
+ * If IAA is set here it either legitimately triggered
+ * after the watchdog timer expired (_way_ late, so we'll
+ * still count it as lost) ... or a silicon erratum:
+ * - VIA seems to set IAA without triggering the IRQ;
+ * - IAAD potentially cleared without setting IAA.
+ */
+ status = ehci_readl(ehci, &ehci->regs->status);
+ if ((status & STS_IAA) || !(cmd & CMD_IAAD)) {
+ COUNT(ehci->stats.lost_iaa);
+ ehci_writel(ehci, STS_IAA, &ehci->regs->status);
}
+
+ ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+ end_unlink_async(ehci);
}
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
deleted file mode 100644
index 7ecf709610ba..000000000000
--- a/drivers/usb/host/ehci-vt8500.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * drivers/usb/host/ehci-vt8500.c
- *
- * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * Based on ehci-au1xxx.c
- *
- * 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/err.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-
-static const struct hc_driver vt8500_ehci_hc_driver = {
- .description = hcd_name,
- .product_desc = "VT8500 EHCI",
- .hcd_priv_size = sizeof(struct ehci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32);
-
-static int vt8500_ehci_drv_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- struct resource *res;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- /*
- * Right now device-tree probed devices don't get dma_mask set.
- * Since shared usb code relies on it, set it here for now.
- * Once we have dma capability bindings this can go away.
- */
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &vt8500_ehci_dma_mask;
-
- if (pdev->resource[1].flags != IORESOURCE_IRQ) {
- pr_debug("resource[1] is not IORESOURCE_IRQ");
- return -ENOMEM;
- }
- hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500");
- if (!hcd)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- hcd->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hcd->regs)) {
- ret = PTR_ERR(hcd->regs);
- goto err1;
- }
-
- ehci = hcd_to_ehci(hcd);
- ehci->caps = hcd->regs;
-
- ret = usb_add_hcd(hcd, pdev->resource[1].start,
- IRQF_SHARED);
- if (ret == 0) {
- platform_set_drvdata(pdev, hcd);
- return ret;
- }
-
-err1:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int vt8500_ehci_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-static const struct of_device_id vt8500_ehci_ids[] = {
- { .compatible = "via,vt8500-ehci", },
- { .compatible = "wm,prizm-ehci", },
- {}
-};
-
-static struct platform_driver vt8500_ehci_driver = {
- .probe = vt8500_ehci_drv_probe,
- .remove = vt8500_ehci_drv_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "vt8500-ehci",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(vt8500_ehci_ids),
- }
-};
-
-MODULE_ALIAS("platform:vt8500-ehci");
-MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 36c3a8210595..7c978b23520d 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -121,6 +121,7 @@ struct ehci_hcd { /* one per controller */
bool scanning:1;
bool need_rescan:1;
bool intr_unlinking:1;
+ bool iaa_in_progress:1;
bool async_unlinking:1;
bool shutdown:1;
struct ehci_qh *qh_scan_next;
@@ -128,9 +129,8 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
- struct ehci_qh *async_unlink;
- struct ehci_qh *async_unlink_last;
- struct ehci_qh *async_iaa;
+ struct list_head async_unlink;
+ struct list_head async_idle;
unsigned async_unlink_cycle;
unsigned async_count; /* async activity count */
@@ -143,8 +143,7 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
- struct ehci_qh *intr_unlink;
- struct ehci_qh *intr_unlink_last;
+ struct list_head intr_unlink;
unsigned intr_unlink_cycle;
unsigned now_frame; /* frame from HC hardware */
unsigned last_iso_frame; /* last frame scanned for iso */
@@ -200,6 +199,7 @@ struct ehci_hcd { /* one per controller */
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
+ unsigned need_oc_pp_cycle:1; /* MPC834X port power */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
@@ -380,11 +380,10 @@ struct ehci_qh {
struct list_head qtd_list; /* sw qtd list */
struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
- struct ehci_qh *unlink_next; /* next on unlink list */
+ struct list_head unlink_node;
unsigned unlink_cycle;
- u8 needs_rescan; /* Dequeue during giveback */
u8 qh_state;
#define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */
@@ -407,6 +406,9 @@ struct ehci_qh {
struct usb_device *dev; /* access to TT */
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
+ unsigned dequeue_during_giveback:1;
+ unsigned exception:1; /* got a fault, or an unlink
+ was requested */
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index e3b7e85120e4..114583a8e92b 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -17,7 +17,6 @@
#include <linux/platform_data/usb-exynos.h>
#include <linux/usb/phy.h>
#include <linux/usb/samsung_usb_phy.h>
-#include <plat/usb-phy.h>
struct exynos_ohci_hcd {
struct device *dev;
@@ -34,7 +33,7 @@ static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci)
if (exynos_ohci->phy)
usb_phy_init(exynos_ohci->phy);
- else if (exynos_ohci->pdata->phy_init)
+ else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init)
exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST);
}
@@ -44,7 +43,7 @@ static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci)
if (exynos_ohci->phy)
usb_phy_shutdown(exynos_ohci->phy);
- else if (exynos_ohci->pdata->phy_exit)
+ else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit)
exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST);
}
@@ -127,8 +126,12 @@ static int exynos_ohci_probe(struct platform_device *pdev)
if (!exynos_ohci)
return -ENOMEM;
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "samsung,exynos5440-ohci"))
+ goto skip_phy;
+
phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR_OR_NULL(phy)) {
+ if (IS_ERR(phy)) {
/* Fallback to pdata */
if (!pdata) {
dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
@@ -141,6 +144,8 @@ static int exynos_ohci_probe(struct platform_device *pdev)
exynos_ohci->otg = phy->otg;
}
+skip_phy:
+
exynos_ohci->dev = &pdev->dev;
hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev,
@@ -311,6 +316,7 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = {
#ifdef CONFIG_OF
static const struct of_device_id exynos_ohci_match[] = {
{ .compatible = "samsung,exynos4210-ohci" },
+ { .compatible = "samsung,exynos5440-ohci" },
{},
};
MODULE_DEVICE_TABLE(of, exynos_ohci_match);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 180a2b01db56..9e6de9586ae4 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1102,12 +1102,12 @@ MODULE_LICENSE ("GPL");
#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
#include "ohci-s3c2410.c"
-#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
+#define S3C2410_PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
#ifdef CONFIG_USB_OHCI_EXYNOS
#include "ohci-exynos.c"
-#define PLATFORM_DRIVER exynos_ohci_driver
+#define EXYNOS_PLATFORM_DRIVER exynos_ohci_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_OMAP1
@@ -1127,25 +1127,24 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_ARCH_EP93XX
#include "ohci-ep93xx.c"
-#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
+#define EP93XX_PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
-#define PLATFORM_DRIVER ohci_hcd_at91_driver
+#define AT91_PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
#ifdef CONFIG_ARCH_LPC32XX
#include "ohci-nxp.c"
-#define PLATFORM_DRIVER usb_hcd_nxp_driver
+#define NXP_PLATFORM_DRIVER usb_hcd_nxp_driver
#endif
#ifdef CONFIG_ARCH_DAVINCI_DA8XX
#include "ohci-da8xx.c"
-#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
+#define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver
#endif
-
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
#include "ohci-ppc-of.c"
#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
@@ -1153,7 +1152,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PLAT_SPEAR
#include "ohci-spear.c"
-#define PLATFORM_DRIVER spear_ohci_hcd_driver
+#define SPEAR_PLATFORM_DRIVER spear_ohci_hcd_driver
#endif
#ifdef CONFIG_PPC_PS3
@@ -1199,7 +1198,14 @@ MODULE_LICENSE ("GPL");
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(SM501_OHCI_DRIVER) && \
- !defined(TMIO_OHCI_DRIVER)
+ !defined(TMIO_OHCI_DRIVER) && \
+ !defined(S3C2410_PLATFORM_DRIVER) && \
+ !defined(EXYNOS_PLATFORM_DRIVER) && \
+ !defined(EP93XX_PLATFORM_DRIVER) && \
+ !defined(AT91_PLATFORM_DRIVER) && \
+ !defined(NXP_PLATFORM_DRIVER) && \
+ !defined(DAVINCI_PLATFORM_DRIVER) && \
+ !defined(SPEAR_PLATFORM_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -1277,9 +1283,79 @@ static int __init ohci_hcd_mod_init(void)
goto error_tmio;
#endif
+#ifdef S3C2410_PLATFORM_DRIVER
+ retval = platform_driver_register(&S3C2410_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_s3c2410;
+#endif
+
+#ifdef EXYNOS_PLATFORM_DRIVER
+ retval = platform_driver_register(&EXYNOS_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_exynos;
+#endif
+
+#ifdef EP93XX_PLATFORM_DRIVER
+ retval = platform_driver_register(&EP93XX_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_ep93xx;
+#endif
+
+#ifdef AT91_PLATFORM_DRIVER
+ retval = platform_driver_register(&AT91_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_at91;
+#endif
+
+#ifdef NXP_PLATFORM_DRIVER
+ retval = platform_driver_register(&NXP_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_nxp;
+#endif
+
+#ifdef DAVINCI_PLATFORM_DRIVER
+ retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_davinci;
+#endif
+
+#ifdef SPEAR_PLATFORM_DRIVER
+ retval = platform_driver_register(&SPEAR_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto error_spear;
+#endif
+
return retval;
/* Error path */
+#ifdef SPEAR_PLATFORM_DRIVER
+ platform_driver_unregister(&SPEAR_PLATFORM_DRIVER);
+ error_spear:
+#endif
+#ifdef DAVINCI_PLATFORM_DRIVER
+ platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);
+ error_davinci:
+#endif
+#ifdef NXP_PLATFORM_DRIVER
+ platform_driver_unregister(&NXP_PLATFORM_DRIVER);
+ error_nxp:
+#endif
+#ifdef AT91_PLATFORM_DRIVER
+ platform_driver_unregister(&AT91_PLATFORM_DRIVER);
+ error_at91:
+#endif
+#ifdef EP93XX_PLATFORM_DRIVER
+ platform_driver_unregister(&EP93XX_PLATFORM_DRIVER);
+ error_ep93xx:
+#endif
+#ifdef EXYNOS_PLATFORM_DRIVER
+ platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER);
+ error_exynos:
+#endif
+#ifdef S3C2410_PLATFORM_DRIVER
+ platform_driver_unregister(&S3C2410_PLATFORM_DRIVER);
+ error_s3c2410:
+#endif
#ifdef TMIO_OHCI_DRIVER
platform_driver_unregister(&TMIO_OHCI_DRIVER);
error_tmio:
@@ -1300,17 +1376,17 @@ static int __init ohci_hcd_mod_init(void)
platform_driver_unregister(&OF_PLATFORM_DRIVER);
error_of_platform:
#endif
-#ifdef PLATFORM_DRIVER
- platform_driver_unregister(&PLATFORM_DRIVER);
- error_platform:
+#ifdef OMAP3_PLATFORM_DRIVER
+ platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
+ error_omap3_platform:
#endif
#ifdef OMAP1_PLATFORM_DRIVER
platform_driver_unregister(&OMAP1_PLATFORM_DRIVER);
error_omap1_platform:
#endif
-#ifdef OMAP3_PLATFORM_DRIVER
- platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
- error_omap3_platform:
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
@@ -1329,6 +1405,27 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef SPEAR_PLATFORM_DRIVER
+ platform_driver_unregister(&SPEAR_PLATFORM_DRIVER);
+#endif
+#ifdef DAVINCI_PLATFORM_DRIVER
+ platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);
+#endif
+#ifdef NXP_PLATFORM_DRIVER
+ platform_driver_unregister(&NXP_PLATFORM_DRIVER);
+#endif
+#ifdef AT91_PLATFORM_DRIVER
+ platform_driver_unregister(&AT91_PLATFORM_DRIVER);
+#endif
+#ifdef EP93XX_PLATFORM_DRIVER
+ platform_driver_unregister(&EP93XX_PLATFORM_DRIVER);
+#endif
+#ifdef EXYNOS_PLATFORM_DRIVER
+ platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER);
+#endif
+#ifdef S3C2410_PLATFORM_DRIVER
+ platform_driver_unregister(&S3C2410_PLATFORM_DRIVER);
+#endif
#ifdef TMIO_OHCI_DRIVER
platform_driver_unregister(&TMIO_OHCI_DRIVER);
#endif
@@ -1344,12 +1441,15 @@ static void __exit ohci_hcd_mod_exit(void)
#ifdef OF_PLATFORM_DRIVER
platform_driver_unregister(&OF_PLATFORM_DRIVER);
#endif
-#ifdef PLATFORM_DRIVER
- platform_driver_unregister(&PLATFORM_DRIVER);
-#endif
#ifdef OMAP3_PLATFORM_DRIVER
platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
#endif
+#ifdef OMAP1_PLATFORM_DRIVER
+ platform_driver_unregister(&OMAP1_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+ platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index db09dae7b557..60ff4220e8b4 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -580,14 +580,8 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)
/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling,
* not necessarily continuous ... to guard against resume signaling.
- * The short timeout is safe for non-root hubs, and is backward-compatible
- * with earlier Linux hosts.
*/
-#ifdef CONFIG_USB_SUSPEND
#define PORT_RESET_MSEC 50
-#else
-#define PORT_RESET_MSEC 10
-#endif
/* this timer value might be vendor-specific ... */
#define PORT_RESET_HW_MSEC 10
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index eb35d9630237..ddfc31427bc0 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -31,6 +31,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
/*-------------------------------------------------------------------------*/
@@ -112,6 +114,8 @@ static const struct hc_driver ohci_omap3_hc_driver = {
/*-------------------------------------------------------------------------*/
+static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32);
+
/*
* configure so an HC device and id are always provided
* always called with process context; sleeping is OK
@@ -141,14 +145,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
return -ENODEV;
}
- irq = platform_get_irq_byname(pdev, "ohci-irq");
+ irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "OHCI irq failed\n");
return -ENODEV;
}
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "ohci");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "UHH OHCI get resource failed\n");
return -ENOMEM;
@@ -160,6 +163,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &omap_ohci_dma_mask;
hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
dev_name(dev));
@@ -229,12 +239,20 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)
hcd->driver->shutdown(hcd);
}
+static const struct of_device_id omap_ohci_dt_ids[] = {
+ { .compatible = "ti,ohci-omap3" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids);
+
static struct platform_driver ohci_hcd_omap3_driver = {
.probe = ohci_hcd_omap3_probe,
.remove = ohci_hcd_omap3_remove,
.shutdown = ohci_hcd_omap3_shutdown,
.driver = {
.name = "ohci-omap3",
+ .of_match_table = of_match_ptr(omap_ohci_dt_ids),
},
};
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 313d0bbfff29..ad4483efb6d6 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1755,7 +1755,7 @@ sl811h_probe(struct platform_device *dev)
/* for this device there's no useful distinction between the controller
* and its root hub, except that the root hub only gets direct PM calls
- * when CONFIG_USB_SUSPEND is enabled.
+ * when CONFIG_PM_RUNTIME is enabled.
*/
static int
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 3b6f50eaec91..469564e57a52 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -200,17 +200,4 @@ static struct pcmcia_driver sl811_cs_driver = {
.remove = sl811_cs_detach,
.id_table = sl811_ids,
};
-
-/*====================================================================*/
-
-static int __init init_sl811_cs(void)
-{
- return pcmcia_register_driver(&sl811_cs_driver);
-}
-module_init(init_sl811_cs);
-
-static void __exit exit_sl811_cs(void)
-{
- pcmcia_unregister_driver(&sl811_cs_driver);
-}
-module_exit(exit_sl811_cs);
+module_pcmcia_driver(sl811_cs_driver);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 5efdffe32365..5c124bf5d018 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -3141,10 +3141,11 @@ static int u132_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
-/* for this device there's no useful distinction between the controller
-* and its root hub, except that the root hub only gets direct PM calls
-* when CONFIG_USB_SUSPEND is enabled.
-*/
+/*
+ * for this device there's no useful distinction between the controller
+ * and its root hub, except that the root hub only gets direct PM calls
+ * when CONFIG_PM_RUNTIME is enabled.
+ */
static int u132_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 68914429482f..187a3ec1069a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1075,7 +1075,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
set_bit(port_index, &bus_state->bus_suspended);
}
/* USB core sets remote wake mask for USB 3.0 hubs,
- * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+ * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
* is enabled, so also enable remote wake here.
*/
if (hcd->self.root_hub->do_remote_wakeup) {
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 35616ffbe3ae..965b539bc474 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -51,7 +51,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
return NULL;
}
- memset(seg->trbs, 0, SEGMENT_SIZE);
+ memset(seg->trbs, 0, TRB_SEGMENT_SIZE);
/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
if (cycle_state == 0) {
for (i = 0; i < TRBS_PER_SEGMENT; i++)
@@ -467,7 +467,7 @@ struct xhci_ring *xhci_dma_to_transfer_ring(
{
if (ep->ep_state & EP_HAS_STREAMS)
return radix_tree_lookup(&ep->stream_info->trb_address_map,
- address >> SEGMENT_SHIFT);
+ address >> TRB_SEGMENT_SHIFT);
return ep->ring;
}
@@ -478,7 +478,7 @@ static struct xhci_ring *dma_to_stream_ring(
u64 address)
{
return radix_tree_lookup(&stream_info->trb_address_map,
- address >> SEGMENT_SHIFT);
+ address >> TRB_SEGMENT_SHIFT);
}
#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */
@@ -514,7 +514,7 @@ static int xhci_test_radix_tree(struct xhci_hcd *xhci,
cur_ring = stream_info->stream_rings[cur_stream];
for (addr = cur_ring->first_seg->dma;
- addr < cur_ring->first_seg->dma + SEGMENT_SIZE;
+ addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE;
addr += trb_size) {
mapped_ring = dma_to_stream_ring(stream_info, addr);
if (cur_ring != mapped_ring) {
@@ -662,7 +662,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
cur_stream, (unsigned long long) addr);
key = (unsigned long)
- (cur_ring->first_seg->dma >> SEGMENT_SHIFT);
+ (cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT);
ret = radix_tree_insert(&stream_info->trb_address_map,
key, cur_ring);
if (ret) {
@@ -693,7 +693,7 @@ cleanup_rings:
if (cur_ring) {
addr = cur_ring->first_seg->dma;
radix_tree_delete(&stream_info->trb_address_map,
- addr >> SEGMENT_SHIFT);
+ addr >> TRB_SEGMENT_SHIFT);
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
}
@@ -764,7 +764,7 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
if (cur_ring) {
addr = cur_ring->first_seg->dma;
radix_tree_delete(&stream_info->trb_address_map,
- addr >> SEGMENT_SHIFT);
+ addr >> TRB_SEGMENT_SHIFT);
xhci_ring_free(xhci, cur_ring);
stream_info->stream_rings[cur_stream] = NULL;
}
@@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
* is attached to (or the roothub port its ancestor hub is attached to). All we
* know is the index of that port under either the USB 2.0 or the USB 3.0
* roothub, but that doesn't give us the real index into the HW port status
- * registers. Scan through the xHCI roothub port array, looking for the Nth
- * entry of the correct port speed. Return the port number of that entry.
+ * registers. Call xhci_find_raw_port_number() to get real index.
*/
static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
struct usb_device *udev)
{
struct usb_device *top_dev;
- unsigned int num_similar_speed_ports;
- unsigned int faked_port_num;
- int i;
+ struct usb_hcd *hcd;
+
+ if (udev->speed == USB_SPEED_SUPER)
+ hcd = xhci->shared_hcd;
+ else
+ hcd = xhci->main_hcd;
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
- faked_port_num = top_dev->portnum;
- for (i = 0, num_similar_speed_ports = 0;
- i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
- u8 port_speed = xhci->port_array[i];
-
- /*
- * Skip ports that don't have known speeds, or have duplicate
- * Extended Capabilities port speed entries.
- */
- if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
- continue;
- /*
- * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and
- * 1.1 ports are under the USB 2.0 hub. If the port speed
- * matches the device speed, it's a similar speed port.
- */
- if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER))
- num_similar_speed_ports++;
- if (num_similar_speed_ports == faked_port_num)
- /* Roothub ports are numbered from 1 to N */
- return i+1;
- }
- return 0;
+ return xhci_find_raw_port_number(hcd, top_dev->portnum);
}
/* Setup an xHCI virtual device for a Set Address command */
@@ -2325,7 +2305,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* so we pick the greater alignment need.
*/
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
- SEGMENT_SIZE, 64, xhci->page_size);
+ TRB_SEGMENT_SIZE, 64, xhci->page_size);
/* See Table 46 and Note on Figure 55 */
xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index af259e0ec172..1a30c380043c 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
+ .find_raw_port_number = xhci_find_raw_port_number,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 882875465301..1969c001b3f9 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci,
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
if ((port_id <= 0) || (port_id > max_ports)) {
xhci_warn(xhci, "Invalid port id %d\n", port_id);
- bogus_port_status = true;
- goto cleanup;
+ inc_deq(xhci, xhci->event_ring);
+ return;
}
/* Figure out which usb_hcd this port is attached to:
* is it a USB 3.0 port or a USB 2.0/1.1 port?
*/
major_revision = xhci->port_array[port_id - 1];
+
+ /* Find the right roothub. */
+ hcd = xhci_to_hcd(xhci);
+ if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
+ hcd = xhci->shared_hcd;
+
if (major_revision == 0) {
xhci_warn(xhci, "Event for port %u not in "
"Extended Capabilities, ignoring.\n",
@@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
* into the index into the ports on the correct split roothub, and the
* correct bus_state structure.
*/
- /* Find the right roothub. */
- hcd = xhci_to_hcd(xhci);
- if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
- hcd = xhci->shared_hcd;
bus_state = &xhci->bus_state[hcd_index(hcd)];
if (hcd->speed == HCD_USB3)
port_array = xhci->usb3_ports;
@@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
if (event_trb != ep_ring->dequeue &&
event_trb != td->last_trb)
td->urb->actual_length =
- td->urb->transfer_buffer_length
- - TRB_LEN(le32_to_cpu(event->transfer_len));
+ td->urb->transfer_buffer_length -
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
else
td->urb->actual_length = 0;
@@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* Maybe the event was for the data stage? */
td->urb->actual_length =
td->urb->transfer_buffer_length -
- TRB_LEN(le32_to_cpu(event->transfer_len));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
xhci_dbg(xhci, "Waiting for status "
"stage event\n");
return 0;
@@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* handle completion code */
switch (trb_comp_code) {
case COMP_SUCCESS:
- if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
frame->status = 0;
break;
}
@@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
}
len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
- TRB_LEN(le32_to_cpu(event->transfer_len));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
if (trb_comp_code != COMP_STOP_INVAL) {
frame->actual_length = len;
@@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
if (event_trb != td->last_trb ||
- TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
xhci_warn(xhci, "WARN Successful completion "
"on short TX\n");
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
@@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
"%d bytes untransferred\n",
td->urb->ep->desc.bEndpointAddress,
td->urb->transfer_buffer_length,
- TRB_LEN(le32_to_cpu(event->transfer_len)));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
/* Fast path - was this the last TRB in the TD for this URB? */
if (event_trb == td->last_trb) {
- if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
+ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
td->urb->actual_length =
td->urb->transfer_buffer_length -
- TRB_LEN(le32_to_cpu(event->transfer_len));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
if (td->urb->transfer_buffer_length <
td->urb->actual_length) {
xhci_warn(xhci, "HC gave bad length "
"of %d bytes left\n",
- TRB_LEN(le32_to_cpu(event->transfer_len)));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
td->urb->actual_length = 0;
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
@@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
if (trb_comp_code != COMP_STOP_INVAL)
td->urb->actual_length +=
TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
- TRB_LEN(le32_to_cpu(event->transfer_len));
+ EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
}
return finish_td(xhci, td, event_trb, event, ep, status, false);
@@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
- if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+ if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
break;
if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
trb_comp_code = COMP_SHORT_TX;
@@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* TD list.
*/
if (list_empty(&ep_ring->td_list)) {
- xhci_warn(xhci, "WARN Event TRB for slot %d ep %d "
- "with no TDs queued?\n",
- TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
- ep_index);
- xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
- (le32_to_cpu(event->flags) &
- TRB_TYPE_BITMASK)>>10);
- xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
+ /*
+ * A stopped endpoint may generate an extra completion
+ * event if the device was suspended. Don't print
+ * warnings.
+ */
+ if (!(trb_comp_code == COMP_STOP ||
+ trb_comp_code == COMP_STOP_INVAL)) {
+ xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
+ TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
+ ep_index);
+ xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
+ (le32_to_cpu(event->flags) &
+ TRB_TYPE_BITMASK)>>10);
+ xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
+ }
if (ep->skip) {
ep->skip = false;
xhci_dbg(xhci, "td_list is empty while skip "
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 849470b18831..b4aa79d154b2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -417,9 +417,9 @@ static void compliance_mode_recovery(unsigned long arg)
* Compliance Mode Detected. Letting USB Core
* handle the Warm Reset
*/
- xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n",
+ xhci_dbg(xhci, "Compliance mode detected->port %d\n",
i + 1);
- xhci_dbg(xhci, "Attempting Recovery routine!\n");
+ xhci_dbg(xhci, "Attempting compliance mode recovery\n");
hcd = xhci->shared_hcd;
if (hcd->state == HC_STATE_SUSPENDED)
@@ -457,7 +457,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
set_timer_slack(&xhci->comp_mode_recovery_timer,
msecs_to_jiffies(COMP_MODE_RCVRY_MSECS));
add_timer(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n");
+ xhci_dbg(xhci, "Compliance mode recovery timer initialized\n");
}
/*
@@ -733,8 +733,11 @@ void xhci_stop(struct usb_hcd *hcd)
/* Deleting Compliance Mode Recovery Timer */
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
- (!(xhci_all_ports_seen_u0(xhci))))
+ (!(xhci_all_ports_seen_u0(xhci)))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
+ xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+ __func__);
+ }
if (xhci->quirks & XHCI_AMD_PLL_FIX)
usb_amd_dev_put();
@@ -930,7 +933,8 @@ int xhci_suspend(struct xhci_hcd *xhci)
if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
(!(xhci_all_ports_seen_u0(xhci)))) {
del_timer_sync(&xhci->comp_mode_recovery_timer);
- xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n");
+ xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n",
+ __func__);
}
/* step 5: remove core well power */
@@ -3779,7 +3783,29 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0;
}
-#ifdef CONFIG_USB_SUSPEND
+/*
+ * Transfer the port index into real index in the HW port status
+ * registers. Caculate offset between the port's PORTSC register
+ * and port status base. Divide the number of per port register
+ * to get the real index. The raw port number bases 1.
+ */
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ __le32 __iomem *base_addr = &xhci->op_regs->port_status_base;
+ __le32 __iomem *addr;
+ int raw_port;
+
+ if (hcd->speed != HCD_USB3)
+ addr = xhci->usb2_ports[port1 - 1];
+ else
+ addr = xhci->usb3_ports[port1 - 1];
+
+ raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
+ return raw_port;
+}
+
+#ifdef CONFIG_PM_RUNTIME
/* BESL to HIRD Encoding array for USB2 LPM */
static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
@@ -4029,7 +4055,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0;
}
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
/*---------------------- USB 3.0 Link PM functions ------------------------*/
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2c510e4a7d4c..29c978e37135 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -972,6 +972,10 @@ struct xhci_transfer_event {
__le32 flags;
};
+/* Transfer event TRB length bit mask */
+/* bits 0:23 */
+#define EVENT_TRB_LEN(p) ((p) & 0xffffff)
+
/** Transfer Event bit fields **/
#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
@@ -1234,8 +1238,8 @@ union xhci_trb {
#define TRBS_PER_SEGMENT 64
/* Allow two commands + a link TRB, along with any reserved command TRBs */
#define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3)
-#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
-#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE))
+#define TRB_SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
+#define TRB_SEGMENT_SHIFT (ilog2(TRB_SEGMENT_SIZE))
/* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
@@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
#ifdef CONFIG_PM
int xhci_bus_suspend(struct usb_hcd *hcd);
diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig
index 33350f9dd34f..320d368c8dac 100644
--- a/drivers/usb/image/Kconfig
+++ b/drivers/usb/image/Kconfig
@@ -2,11 +2,9 @@
# USB Imaging devices configuration
#
comment "USB Imaging devices"
- depends on USB
config USB_MDC800
tristate "USB Mustek MDC800 Digital Camera support"
- depends on USB
---help---
Say Y here if you want to connect this type of still camera to
your computer's USB port. This driver can be used with gphoto 0.4.3
@@ -19,7 +17,7 @@ config USB_MDC800
config USB_MICROTEK
tristate "Microtek X6USB scanner support"
- depends on USB && SCSI
+ depends on SCSI
help
Say Y here if you want support for the Microtek X6USB and
possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L.
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 3b1a3f4ec5e9..a51e7d6afda9 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -2,11 +2,9 @@
# USB Miscellaneous driver configuration
#
comment "USB Miscellaneous drivers"
- depends on USB
config USB_EMI62
tristate "EMI 6|2m USB Audio interface support"
- depends on USB
---help---
This driver loads firmware to Emagic EMI 6|2m low latency USB
Audio and Midi interface.
@@ -21,7 +19,6 @@ config USB_EMI62
config USB_EMI26
tristate "EMI 2|6 USB Audio interface support"
- depends on USB
---help---
This driver loads firmware to Emagic EMI 2|6 low latency USB
Audio interface.
@@ -34,7 +31,6 @@ config USB_EMI26
config USB_ADUTUX
tristate "ADU devices from Ontrak Control Systems"
- depends on USB
help
Say Y if you want to use an ADU device from Ontrak Control
Systems.
@@ -44,7 +40,6 @@ config USB_ADUTUX
config USB_SEVSEG
tristate "USB 7-Segment LED Display"
- depends on USB
help
Say Y here if you have a USB 7-Segment Display by Delcom
@@ -53,7 +48,6 @@ config USB_SEVSEG
config USB_RIO500
tristate "USB Diamond Rio500 support"
- depends on USB
help
Say Y here if you want to connect a USB Rio500 mp3 player to your
computer's USB port. Please read <file:Documentation/usb/rio.txt>
@@ -64,7 +58,6 @@ config USB_RIO500
config USB_LEGOTOWER
tristate "USB Lego Infrared Tower support"
- depends on USB
help
Say Y here if you want to connect a USB Lego Infrared Tower to your
computer's USB port.
@@ -77,7 +70,6 @@ config USB_LEGOTOWER
config USB_LCD
tristate "USB LCD driver support"
- depends on USB
help
Say Y here if you want to connect an USBLCD to your computer's
USB port. The USBLCD is a small USB interface board for
@@ -89,7 +81,6 @@ config USB_LCD
config USB_LED
tristate "USB LED driver support"
- depends on USB
help
Say Y here if you want to connect an USBLED device to your
computer's USB port.
@@ -99,7 +90,6 @@ config USB_LED
config USB_CYPRESS_CY7C63
tristate "Cypress CY7C63xxx USB driver support"
- depends on USB
help
Say Y here if you want to connect a Cypress CY7C63xxx
micro controller to your computer's USB port. Currently this
@@ -113,7 +103,6 @@ config USB_CYPRESS_CY7C63
config USB_CYTHERM
tristate "Cypress USB thermometer driver support"
- depends on USB
help
Say Y here if you want to connect a Cypress USB thermometer
device to your computer's USB port. This device is also known
@@ -126,7 +115,6 @@ config USB_CYTHERM
config USB_IDMOUSE
tristate "Siemens ID USB Mouse Fingerprint sensor support"
- depends on USB
help
Say Y here if you want to use the fingerprint sensor on
the Siemens ID Mouse. There is also a Siemens ID Mouse
@@ -140,7 +128,6 @@ config USB_IDMOUSE
config USB_FTDI_ELAN
tristate "Elan PCMCIA CardBus Adapter USB Client"
- depends on USB
default M
help
ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
@@ -164,7 +151,6 @@ config USB_FTDI_ELAN
config USB_APPLEDISPLAY
tristate "Apple Cinema Display support"
- depends on USB
select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
help
@@ -175,7 +161,6 @@ source "drivers/usb/misc/sisusbvga/Kconfig"
config USB_LD
tristate "USB LD driver"
- depends on USB
help
This driver is for generic USB devices that use interrupt transfers,
like LD Didactic's USB devices.
@@ -185,7 +170,6 @@ config USB_LD
config USB_TRANCEVIBRATOR
tristate "PlayStation 2 Trance Vibrator driver support"
- depends on USB
help
Say Y here if you want to connect a PlayStation 2 Trance Vibrator
device to your computer's USB port.
@@ -195,7 +179,6 @@ config USB_TRANCEVIBRATOR
config USB_IOWARRIOR
tristate "IO Warrior driver support"
- depends on USB
help
Say Y here if you want to support the IO Warrior devices from Code
Mercenaries. This includes support for the following devices:
@@ -209,7 +192,6 @@ config USB_IOWARRIOR
config USB_TEST
tristate "USB testing driver"
- depends on USB
help
This driver is for testing host controller software. It is used
with specialized device firmware for regression and stress testing,
@@ -220,7 +202,6 @@ config USB_TEST
config USB_ISIGHTFW
tristate "iSight firmware loading support"
- depends on USB
select FW_LOADER
help
This driver loads firmware for USB Apple iSight cameras, allowing
@@ -233,7 +214,6 @@ config USB_ISIGHTFW
config USB_YUREX
tristate "USB YUREX driver support"
- depends on USB
help
Say Y here if you want to connect a YUREX to your computer's
USB port. The YUREX is a leg-shakes sensor. See
@@ -246,7 +226,6 @@ config USB_YUREX
config USB_EZUSB_FX2
tristate "Functions for loading firmware on EZUSB chips"
- depends on USB
help
Say Y here if you need EZUSB device support.
(Cypress FX/FX2/FX2LP microcontrollers)
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index 0fc6e5fc745f..ba6a5d6e618e 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -63,6 +63,7 @@ static const struct usb_device_id appledisplay_table[] = {
{ APPLEDISPLAY_DEVICE(0x9219) },
{ APPLEDISPLAY_DEVICE(0x921c) },
{ APPLEDISPLAY_DEVICE(0x921d) },
+ { APPLEDISPLAY_DEVICE(0x9236) },
/* Terminating entry */
{ }
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index db46143c67a6..d36f34e25bed 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -672,7 +672,7 @@ static int iowarrior_release(struct inode *inode, struct file *file)
retval = -ENODEV; /* close called more than once */
mutex_unlock(&dev->mutex);
} else {
- dev->opened = 0; /* we're closeing now */
+ dev->opened = 0; /* we're closing now */
retval = 0;
if (dev->present) {
/*
@@ -802,7 +802,7 @@ static int iowarrior_probe(struct usb_interface *interface,
/* this one will match for the IOWarrior56 only */
dev->int_out_endpoint = endpoint;
}
- /* we have to check the report_size often, so remember it in the endianess suitable for our machine */
+ /* we have to check the report_size often, so remember it in the endianness suitable for our machine */
dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56))
diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig
index 30ea7ca6846e..0d03a5200482 100644
--- a/drivers/usb/misc/sisusbvga/Kconfig
+++ b/drivers/usb/misc/sisusbvga/Kconfig
@@ -1,7 +1,7 @@
config USB_SISUSBVGA
tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
- depends on USB && (USB_MUSB_HDRC || USB_EHCI_HCD)
+ depends on (USB_MUSB_HDRC || USB_EHCI_HCD)
---help---
Say Y here if you intend to attach a USB2VGA dongle based on a
Net2280 and a SiS315 chip.
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index dd573abd2d1e..c21386ec5d35 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3084,7 +3084,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate memory for our private */
if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
- dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
+ dev_err(&dev->dev, "Failed to allocate memory for private data\n");
return -ENOMEM;
}
kref_init(&sisusb->kref);
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c
index f713f6aeb6e5..d3a1cce1bf9c 100644
--- a/drivers/usb/misc/usb3503.c
+++ b/drivers/usb/misc/usb3503.c
@@ -307,18 +307,7 @@ static struct i2c_driver usb3503_driver = {
.id_table = usb3503_id,
};
-static int __init usb3503_init(void)
-{
- return i2c_add_driver(&usb3503_driver);
-}
-
-static void __exit usb3503_exit(void)
-{
- i2c_del_driver(&usb3503_driver);
-}
-
-module_init(usb3503_init);
-module_exit(usb3503_exit);
+module_i2c_driver(usb3503_driver);
MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");
MODULE_DESCRIPTION("USB3503 USB HUB driver");
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 29cad9e0a7a9..e129cf661223 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -705,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf,
return -ENODEV;
}
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
- dev_dbg(&intf->dev, "set inteface result %d\n", i);
+ dev_dbg(&intf->dev, "set interface result %d\n", i);
interface = intf->cur_altsetting;
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
index 635745f57fbd..5c6ffa2a612e 100644
--- a/drivers/usb/mon/Kconfig
+++ b/drivers/usb/mon/Kconfig
@@ -4,7 +4,6 @@
config USB_MON
tristate "USB Monitor"
- depends on USB
help
If you select this option, a component which captures the USB traffic
between peripheral-specific drivers and HC drivers will be built.
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 05e51432dd2f..06f8d29af1ef 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -6,8 +6,7 @@
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
- depends on USB && USB_GADGET
- select USB_OTG_UTILS
+ depends on USB_GADGET
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
@@ -34,10 +33,12 @@ choice
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
+ depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
+ depends on BROKEN
config USB_MUSB_TUSB6010
tristate "TUSB6010"
@@ -53,7 +54,6 @@ config USB_MUSB_AM35X
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
- depends on SOC_TI81XX || SOC_AM33XX
config USB_MUSB_BLACKFIN
tristate "Blackfin"
@@ -61,12 +61,12 @@ config USB_MUSB_BLACKFIN
config USB_MUSB_UX500
tristate "U8500 and U5500"
- depends on (ARCH_U8500 && AB8500_USB)
endchoice
choice
prompt 'MUSB DMA mode'
+ default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM
default USB_UX500_DMA if USB_MUSB_UX500
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index 59eea219034a..2231850c0625 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -149,7 +149,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -195,7 +195,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -298,7 +298,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index dbb31b30c7fa..5e63b160db0c 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
break;
default:
dev_dbg(musb->controller, "%s state not handled\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
dev_dbg(musb->controller, "state is %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
static void bfin_musb_enable(struct musb *musb)
@@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index f522000e8f06..9db211ee15b5 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -435,7 +435,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,
}
}
-#ifdef CONFIG_USB_MUSB_DEBUG
static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
{
pr_debug("RXBD/%s %08x: "
@@ -444,21 +443,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
bd->hw_next, bd->hw_bufp, bd->hw_off_len,
bd->hw_options);
}
-#endif
static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
{
-#ifdef CONFIG_USB_MUSB_DEBUG
struct cppi_descriptor *bd;
- if (!_dbg_level(level))
- return;
cppi_dump_rx(level, rx, tag);
if (rx->last_processed)
cppi_dump_rxbd("last", rx->last_processed);
for (bd = rx->head; bd; bd = bd->next)
cppi_dump_rxbd("active", bd);
-#endif
}
@@ -784,6 +778,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
void __iomem *tibase = musb->ctrl_base;
int is_rndis = 0;
struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
+ struct cppi_descriptor *d;
if (onepacket) {
/* almost every USB driver, host or peripheral side */
@@ -897,14 +892,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
bd->hw_options |= CPPI_SOP_SET;
tail->hw_options |= CPPI_EOP_SET;
-#ifdef CONFIG_USB_MUSB_DEBUG
- if (_dbg_level(5)) {
- struct cppi_descriptor *d;
-
- for (d = rx->head; d; d = d->next)
- cppi_dump_rxbd("S", d);
- }
-#endif
+ for (d = rx->head; d; d = d->next)
+ cppi_dump_rxbd("S", d);
/* in case the preceding transfer left some state... */
tail = rx->last_processed;
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 41613a2b35e8..b903b744a224 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -198,7 +198,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -267,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -360,7 +360,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index e040d9103735..bea6cc35471c 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -349,7 +349,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
davinci_musb_source_power(musb, drvvbus, 0);
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
retval = IRQ_HANDLED;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index daec6e0f7e38..37a261a6bb6a 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -372,13 +372,13 @@ static void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
musb->ignore_disconnect = 0;
spin_unlock_irqrestore(&musb->lock, flags);
@@ -393,13 +393,14 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
- dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "HNP: stop from %s\n",
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n");
@@ -413,7 +414,7 @@ void musb_hnp_stop(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/*
@@ -451,7 +452,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
if (int_usb & MUSB_INTR_RESUME) {
handled = IRQ_HANDLED;
- dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
if (devctl & MUSB_DEVCTL_HM) {
void __iomem *mbase = musb->mregs;
@@ -493,7 +494,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"host",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else {
switch (musb->xceiv->state) {
@@ -522,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"peripheral",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
@@ -538,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical:
@@ -602,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
}
- dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
- otg_state_string(musb->xceiv->state),
+ dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
+ "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+ usb_otg_state_string(musb->xceiv->state),
devctl,
({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -628,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (int_usb & MUSB_INTR_SUSPEND) {
dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
- otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->state), devctl);
handled = IRQ_HANDLED;
switch (musb->xceiv->state) {
@@ -745,12 +747,12 @@ b_host:
usb_hcd_resume_root_hub(hcd);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
- otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->state), devctl);
}
if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
@@ -787,7 +789,7 @@ b_host:
break;
default:
WARNING("unhandled DISCONNECT transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
}
@@ -813,7 +815,7 @@ b_host:
}
} else {
dev_dbg(musb->controller, "BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
/* We need to ignore disconnect on suspend
@@ -826,7 +828,7 @@ b_host:
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */
dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
@@ -838,7 +840,7 @@ b_host:
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
@@ -850,7 +852,7 @@ b_host:
break;
default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
@@ -1632,7 +1634,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
int ret = -EINVAL;
spin_lock_irqsave(&musb->lock, flags);
- ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state));
+ ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -1951,9 +1953,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_write_ulpi_buscontrol(musb->mregs, busctl);
}
- MUSB_DEV_MODE(musb);
- musb->xceiv->otg->default_a = 0;
- musb->xceiv->state = OTG_STATE_B_IDLE;
+ if (musb->xceiv->otg->default_a) {
+ MUSB_HST_MODE(musb);
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ } else {
+ MUSB_DEV_MODE(musb);
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
status = musb_gadget_setup(musb);
@@ -2008,7 +2014,6 @@ static int musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq_byname(pdev, "mc");
- int status;
struct resource *iomem;
void __iomem *base;
@@ -2016,24 +2021,17 @@ static int musb_probe(struct platform_device *pdev)
if (!iomem || irq <= 0)
return -ENODEV;
- base = ioremap(iomem->start, resource_size(iomem));
- if (!base) {
- dev_err(dev, "ioremap failed\n");
- return -ENOMEM;
- }
+ base = devm_ioremap_resource(dev, iomem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- status = musb_init_controller(dev, irq, base);
- if (status < 0)
- iounmap(base);
-
- return status;
+ return musb_init_controller(dev, irq, base);
}
static int musb_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev);
- void __iomem *ctrl_base = musb->ctrl_base;
/* this gets called on rmmod.
* - Host mode: host may still be active
@@ -2044,7 +2042,6 @@ static int musb_remove(struct platform_device *pdev)
musb_shutdown(pdev);
musb_free(musb);
- iounmap(ctrl_base);
device_init_wakeup(dev, 0);
#ifndef CONFIG_MUSB_PIO_ONLY
dma_set_mask(dev, *dev->parent->dma_mask);
@@ -2293,8 +2290,6 @@ static int __init musb_init(void)
if (usb_disabled())
return 0;
- pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n",
- musb_driver_name);
return platform_driver_register(&musb_driver);
}
module_init(musb_init);
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 6bb89715b637..3a18e44e9391 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -38,6 +38,7 @@
#include <linux/module.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/platform_data/usb-omap.h>
+#include <linux/sizes.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -224,7 +225,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = dsps_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -273,7 +274,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || (musb->a_wait_bcon == 0 &&
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&glue->timer[pdev->id]);
glue->last_timer[pdev->id] = jiffies;
return;
@@ -288,7 +289,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
glue->last_timer[pdev->id] = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&glue->timer[pdev->id], timeout);
}
@@ -334,7 +335,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
* value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
* Also, DRVVBUS pulses for SRP (but not at 5V) ...
*/
- if (usbintr & MUSB_INTR_BABBLE)
+ if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE)
pr_info("CAUTION: musb: Babble Interrupt Occurred\n");
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@@ -377,7 +378,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -596,14 +597,13 @@ err0:
static int dsps_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue;
struct resource *iomem;
int ret, i;
- match = of_match_node(musb_dsps_of_match, np);
+ match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);
if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
ret = -EINVAL;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 83eddedcd9be..ba7092349fa9 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -46,48 +46,6 @@
#include "musb_core.h"
-/* MUSB PERIPHERAL status 3-mar-2006:
- *
- * - EP0 seems solid. It passes both USBCV and usbtest control cases.
- * Minor glitches:
- *
- * + remote wakeup to Linux hosts work, but saw USBCV failures;
- * in one test run (operator error?)
- * + endpoint halt tests -- in both usbtest and usbcv -- seem
- * to break when dma is enabled ... is something wrongly
- * clearing SENDSTALL?
- *
- * - Mass storage behaved ok when last tested. Network traffic patterns
- * (with lots of short transfers etc) need retesting; they turn up the
- * worst cases of the DMA, since short packets are typical but are not
- * required.
- *
- * - TX/IN
- * + both pio and dma behave in with network and g_zero tests
- * + no cppi throughput issues other than no-hw-queueing
- * + failed with FLAT_REG (DaVinci)
- * + seems to behave with double buffering, PIO -and- CPPI
- * + with gadgetfs + AIO, requests got lost?
- *
- * - RX/OUT
- * + both pio and dma behave in with network and g_zero tests
- * + dma is slow in typical case (short_not_ok is clear)
- * + double buffering ok with PIO
- * + double buffering *FAILS* with CPPI, wrong data bytes sometimes
- * + request lossage observed with gadgetfs
- *
- * - ISO not tested ... might work, but only weakly isochronous
- *
- * - Gadget driver disabling of softconnect during bind() is ignored; so
- * drivers can't hold off host requests until userspace is ready.
- * (Workaround: they can turn it off later.)
- *
- * - PORTABILITY (assumes PIO works):
- * + DaVinci, basically works with cppi dma
- * + OMAP 2430, ditto with mentor dma
- * + TUSB 6010, platform-specific dma in the works
- */
-
/* ----------------------------------------------------------------------- */
#define is_buffer_mapped(req) (is_dma_capable() && \
@@ -280,41 +238,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
return ep->packet_sz;
}
-
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral tx (IN) using Mentor DMA works as follows:
- Only mode 0 is used for transfers <= wPktSize,
- mode 1 is used for larger transfers,
-
- One of the following happens:
- - Host sends IN token which causes an endpoint interrupt
- -> TxAvail
- -> if DMA is currently busy, exit.
- -> if queue is non-empty, txstate().
-
- - Request is queued by the gadget driver.
- -> if queue was previously empty, txstate()
-
- txstate()
- -> start
- /\ -> setup DMA
- | (data is transferred to the FIFO, then sent out when
- | IN token(s) are recd from Host.
- | -> DMA interrupt on completion
- | calls TxAvail.
- | -> stop DMA, ~DMAENAB,
- | -> set TxPktRdy for last short pkt or zlp
- | -> Complete Request
- | -> Continue next request (call txstate)
- |___________________________________|
-
- * Non-Mentor DMA engines can of course work differently, such as by
- * upleveling from irq-per-packet to irq-per-buffer.
- */
-
-#endif
-
/*
* An endpoint is transmitting data. This can be called either from
* the IRQ routine or from ep.queue() to kickstart a request on an
@@ -621,37 +544,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
/* ------------------------------------------------------------ */
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral rx (OUT) using Mentor DMA works as follows:
- - Only mode 0 is used.
-
- - Request is queued by the gadget class driver.
- -> if queue was previously empty, rxstate()
-
- - Host sends OUT token which causes an endpoint interrupt
- /\ -> RxReady
- | -> if request queued, call rxstate
- | /\ -> setup DMA
- | | -> DMA interrupt on completion
- | | -> RxReady
- | | -> stop DMA
- | | -> ack the read
- | | -> if data recd = max expected
- | | by the request, or host
- | | sent a short packet,
- | | complete the request,
- | | and start the next one.
- | |_____________________________________|
- | else just wait for the host
- | to send the next OUT token.
- |__________________________________________________|
-
- * Non-Mentor DMA engines can of course work differently.
- */
-
-#endif
-
/*
* Context: controller locked, IRQs blocked, endpoint selected
*/
@@ -740,7 +632,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
- int transfer_size;
+ unsigned int transfer_size;
c = musb->dma_controller;
channel = musb_ep->dma;
@@ -782,10 +674,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
csr | MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR, csr);
- transfer_size = min(request->length - request->actual,
+ transfer_size = min_t(unsigned int,
+ request->length -
+ request->actual,
channel->max_len);
musb_ep->dma->desired_mode = 1;
-
} else {
if (!musb_ep->hb_mult &&
musb_ep->hw_ep->rx_double_buffered)
@@ -815,7 +708,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
- int transfer_size = 0;
+ unsigned int transfer_size = 0;
c = musb->dma_controller;
channel = musb_ep->dma;
@@ -824,11 +717,13 @@ static void rxstate(struct musb *musb, struct musb_request *req)
if (fifo_count < musb_ep->packet_sz)
transfer_size = fifo_count;
else if (request->short_not_ok)
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
channel->max_len);
else
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
(unsigned)fifo_count);
@@ -1681,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done;
default:
dev_dbg(musb->controller, "Unhandled wake: %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
goto done;
}
@@ -1801,13 +1696,6 @@ static const struct usb_gadget_ops musb_gadget_operations = {
* all peripheral ports are external...
*/
-static void musb_gadget_release(struct device *dev)
-{
- /* kref_put(WHAT) */
- dev_dbg(dev, "%s\n", __func__);
-}
-
-
static void
init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
{
@@ -1892,12 +1780,7 @@ int musb_gadget_setup(struct musb *musb)
musb->g.speed = USB_SPEED_UNKNOWN;
/* this "gadget" abstracts/virtualizes the controller */
- dev_set_name(&musb->g.dev, "gadget");
- musb->g.dev.parent = musb->controller;
- musb->g.dev.dma_mask = musb->controller->dma_mask;
- musb->g.dev.release = musb_gadget_release;
musb->g.name = musb_driver_name;
-
musb->g.is_otg = 1;
musb_g_init_endpoints(musb);
@@ -1905,11 +1788,6 @@ int musb_gadget_setup(struct musb *musb)
musb->is_active = 0;
musb_platform_try_idle(musb, 0);
- status = device_register(&musb->g.dev);
- if (status != 0) {
- put_device(&musb->g.dev);
- return status;
- }
status = usb_add_gadget_udc(musb->controller, &musb->g);
if (status)
goto err;
@@ -1924,8 +1802,6 @@ err:
void musb_gadget_cleanup(struct musb *musb)
{
usb_del_gadget_udc(&musb->g);
- if (musb->g.dev.parent)
- device_unregister(&musb->g.dev);
}
/*
@@ -1977,9 +1853,8 @@ static int musb_gadget_start(struct usb_gadget *g,
goto err;
}
- if ((musb->xceiv->last_event == USB_EVENT_ID)
- && otg->set_vbus)
- otg_set_vbus(otg, 1);
+ if (musb->xceiv->last_event == USB_EVENT_ID)
+ musb_platform_set_vbus(musb, 1);
hcd->self.uses_pio_for_control = 1;
@@ -2063,6 +1938,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
musb->is_active = 0;
+ musb->gadget_driver = NULL;
musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -2099,7 +1975,7 @@ void musb_g_resume(struct musb *musb)
break;
default:
WARNING("unhandled RESUME transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2129,7 +2005,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2163,7 +2039,7 @@ void musb_g_disconnect(struct musb *musb)
switch (musb->xceiv->state) {
default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
break;
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index c9c1ac4e075f..2af45a0c8930 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -505,8 +505,10 @@ static void ep0_rxstate(struct musb *musb)
req->status = -EOVERFLOW;
count = len;
}
- musb_read_fifo(&musb->endpoints[0], count, buf);
- req->actual += count;
+ if (count > 0) {
+ musb_read_fifo(&musb->endpoints[0], count, buf);
+ req->actual += count;
+ }
csr = MUSB_CSR0_P_SVDRXPKTRDY;
if (count < 64 || req->actual == req->length) {
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 1ce1fcf3f3e7..8914dec49f01 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2453,7 +2453,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (musb->is_active) {
WARNING("trying to suspend as %s while active\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
return -EBUSY;
} else
return 0;
@@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd)
return 0;
}
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+
+#define MUSB_USB_DMA_ALIGN 4
+
+struct musb_temp_buffer {
+ void *kmalloc_ptr;
+ void *old_xfer_buffer;
+ u8 data[0];
+};
+
+static void musb_free_temp_buffer(struct urb *urb)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ temp = container_of(urb->transfer_buffer, struct musb_temp_buffer,
+ data);
+
+ if (dir == DMA_FROM_DEVICE) {
+ memcpy(temp->old_xfer_buffer, temp->data,
+ urb->transfer_buffer_length);
+ }
+ urb->transfer_buffer = temp->old_xfer_buffer;
+ kfree(temp->kmalloc_ptr);
+
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+}
+
+static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+ void *kmalloc_ptr;
+ size_t kmalloc_size;
+
+ if (urb->num_sgs || urb->sg ||
+ urb->transfer_buffer_length == 0 ||
+ !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1)))
+ return 0;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ /* Allocate a buffer with enough padding for alignment */
+ kmalloc_size = urb->transfer_buffer_length +
+ sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1;
+
+ kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+ if (!kmalloc_ptr)
+ return -ENOMEM;
+
+ /* Position our struct temp_buffer such that data is aligned */
+ temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN);
+
+
+ temp->kmalloc_ptr = kmalloc_ptr;
+ temp->old_xfer_buffer = urb->transfer_buffer;
+ if (dir == DMA_TO_DEVICE)
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->data;
+
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+ return 0;
+}
+
+static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ int ret;
+
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * For such engine implemented (un)map_urb_for_dma hooks.
+ * Do not use these hooks for RTL<1.8
+ */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+ ret = musb_alloc_temp_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ if (ret)
+ musb_free_temp_buffer(urb);
+
+ return ret;
+}
+
+static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+
+ /* Do not use this hook for RTL<1.8 (see description above) */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return;
+
+ musb_free_temp_buffer(urb);
+}
+#endif /* !CONFIG_MUSB_PIO_ONLY */
+
const struct hc_driver musb_hc_driver = {
.description = "musb-hcd",
.product_desc = "MUSB HDRC host driver",
@@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = {
.urb_dequeue = musb_urb_dequeue,
.endpoint_disable = musb_h_disable,
+#ifndef CONFIG_MUSB_PIO_ONLY
+ .map_urb_for_dma = musb_map_urb_for_dma,
+ .unmap_urb_for_dma = musb_unmap_urb_for_dma,
+#endif
+
.hub_status_data = musb_hub_status_data,
.hub_control = musb_hub_control,
.bus_suspend = musb_bus_suspend,
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index f70579154ded..ef7d11045f56 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -95,7 +95,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
break;
default:
dev_dbg(musb->controller, "bogus rh suspend? %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else if (power & MUSB_POWER_SUSPENDM) {
power &= ~MUSB_POWER_SUSPENDM;
@@ -203,7 +203,7 @@ void musb_root_disconnect(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "host disconnect (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 1a42a458f2c4..3551f1a30c65 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -117,7 +117,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -134,7 +134,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -174,8 +174,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
}
}
- if (otg->set_vbus)
- otg_set_vbus(otg, 1);
+ otg_set_vbus(otg, 1);
} else {
musb->is_active = 1;
otg->default_a = 1;
@@ -200,7 +199,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -292,14 +291,14 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
musb->xceiv->last_event = USB_EVENT_NONE;
if (musb->gadget_driver) {
+ omap2430_musb_set_vbus(musb, 0);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
}
- if (data->interface_type == MUSB_INTERFACE_UTMI) {
- if (musb->xceiv->otg->set_vbus)
- otg_set_vbus(musb->xceiv->otg, 0);
- }
+ if (data->interface_type == MUSB_INTERFACE_UTMI)
+ otg_set_vbus(musb->xceiv->otg, 0);
+
omap_control_usb_set_mode(glue->control_otghs,
USB_MODE_DISCONNECT);
break;
@@ -355,7 +354,12 @@ static int omap2430_musb_init(struct musb *musb)
else
musb->xceiv = devm_usb_get_phy_dev(dev, 0);
- if (IS_ERR_OR_NULL(musb->xceiv)) {
+ if (IS_ERR(musb->xceiv)) {
+ status = PTR_ERR(musb->xceiv);
+
+ if (status == -ENXIO)
+ return status;
+
pr_err("HS USB OTG: no transceiver configured\n");
return -EPROBE_DEFER;
}
@@ -393,6 +397,8 @@ static int omap2430_musb_init(struct musb *musb)
if (glue->status != OMAP_MUSB_UNKNOWN)
omap_musb_set_mailbox(glue);
+ usb_phy_init(musb->xceiv);
+
pm_runtime_put_noidle(musb->controller);
return 0;
@@ -526,10 +532,10 @@ static int omap2430_probe(struct platform_device *pdev)
}
of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
- of_property_read_u32(np, "interface_type",
+ of_property_read_u32(np, "interface-type",
(u32 *)&data->interface_type);
- of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps);
- of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
+ of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+ of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
of_property_read_u32(np, "power", (u32 *)&pdata->power);
config->multipoint = of_property_read_bool(np, "multipoint");
pdata->has_mailbox = of_property_read_bool(np,
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 464bd23cccda..7369ba33c94f 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -423,7 +423,7 @@ static void musb_do_idle(unsigned long _musb)
&& (musb->idle_timeout == 0
|| time_after(jiffies, musb->idle_timeout))) {
dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/* FALLTHROUGH */
case OTG_STATE_A_IDLE:
@@ -478,7 +478,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
dev_dbg(musb->controller, "%s active, deleting timer\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -495,7 +495,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -571,7 +571,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL),
musb_readl(tbase, TUSB_DEV_OTG_STAT),
conf, prcm);
@@ -678,13 +678,13 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
musb->is_active = 0;
}
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
idle_timeout = jiffies + (1 * HZ);
schedule_work(&musb->irq_work);
} else /* A-dev state machine */ {
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
@@ -733,7 +733,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
u8 devctl;
dev_dbg(musb->controller, "%s timer, %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VRISE:
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index 13a392913769..2c80004e0a83 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -26,6 +26,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/usb/musb-ux500.h>
#include "musb_core.h"
@@ -36,6 +37,98 @@ struct ux500_glue {
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
+static void ux500_musb_set_vbus(struct musb *musb, int is_on)
+{
+ u8 devctl;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ /* start the session */
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ /*
+ * Wait for the musb to set as A device to enable the
+ * VBUS
+ */
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(musb->controller,
+ "configured as A device timeout");
+ break;
+ }
+ }
+
+ } else {
+ musb->is_active = 1;
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+ MUSB_HST_MODE(musb);
+ }
+ } else {
+ musb->is_active = 0;
+
+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
+ * right to B_IDLE...
+ */
+ musb->xceiv->otg->default_a = 0;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ MUSB_DEV_MODE(musb);
+ }
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ /*
+ * Devctl values will be updated after vbus goes below
+ * session_valid. The time taken depends on the capacitance
+ * on VBUS line. The max discharge time can be upto 1 sec
+ * as per the spec. Typically on our platform, it is 200ms
+ */
+ if (!is_on)
+ mdelay(200);
+
+ dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
+ usb_otg_state_string(musb->xceiv->state),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+
+static int musb_otg_notifications(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ struct musb *musb = container_of(nb, struct musb, nb);
+
+ dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
+ event, usb_otg_state_string(musb->xceiv->state));
+
+ switch (event) {
+ case UX500_MUSB_ID:
+ dev_dbg(musb->controller, "ID GND\n");
+ ux500_musb_set_vbus(musb, 1);
+ break;
+ case UX500_MUSB_VBUS:
+ dev_dbg(musb->controller, "VBUS Connect\n");
+ break;
+ case UX500_MUSB_NONE:
+ dev_dbg(musb->controller, "VBUS Disconnect\n");
+ if (is_host_active(musb))
+ ux500_musb_set_vbus(musb, 0);
+ else
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ break;
+ default:
+ dev_dbg(musb->controller, "ID float\n");
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
@@ -58,12 +151,21 @@ static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
static int ux500_musb_init(struct musb *musb)
{
+ int status;
+
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(musb->xceiv)) {
pr_err("HS USB OTG: no transceiver configured\n");
return -EPROBE_DEFER;
}
+ musb->nb.notifier_call = musb_otg_notifications;
+ status = usb_register_notifier(musb->xceiv, &musb->nb);
+ if (status < 0) {
+ dev_dbg(musb->controller, "notification register failed\n");
+ return status;
+ }
+
musb->isr = ux500_musb_interrupt;
return 0;
@@ -71,6 +173,8 @@ static int ux500_musb_init(struct musb *musb)
static int ux500_musb_exit(struct musb *musb)
{
+ usb_unregister_notifier(musb->xceiv, &musb->nb);
+
usb_put_phy(musb->xceiv);
return 0;
@@ -79,6 +183,8 @@ static int ux500_musb_exit(struct musb *musb)
static const struct musb_platform_ops ux500_ops = {
.init = ux500_musb_init,
.exit = ux500_musb_exit,
+
+ .set_vbus = ux500_musb_set_vbus,
};
static int ux500_probe(struct platform_device *pdev)
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 039e567dd3b6..338120641145 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -1,7 +1,7 @@
/*
* drivers/usb/musb/ux500_dma.c
*
- * U8500 and U5500 DMA support code
+ * U8500 DMA support code
*
* Copyright (C) 2009 STMicroelectronics
* Copyright (C) 2011 ST-Ericsson SA
@@ -30,6 +30,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/pfn.h>
+#include <linux/sizes.h>
#include <linux/platform_data/usb-musb-ux500.h>
#include "musb_core.h"
@@ -56,7 +57,7 @@ struct ux500_dma_controller {
};
/* Work function invoked from DMA callback to handle rx transfers. */
-void ux500_dma_callback(void *private_data)
+static void ux500_dma_callback(void *private_data)
{
struct dma_channel *channel = private_data;
struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -93,8 +94,9 @@ static bool ux500_configure_channel(struct dma_channel *channel,
struct musb *musb = ux500_channel->controller->private_data;
dev_dbg(musb->controller,
- "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
- packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+ "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n",
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, ux500_channel->is_tx);
ux500_channel->cur_len = len;
@@ -191,7 +193,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel,
u16 maxpacket, void *buf, u32 length)
{
if ((maxpacket & 0x3) ||
- ((int)buf & 0x3) ||
+ ((unsigned long int) buf & 0x3) ||
(length < 512) ||
(length & 0x3))
return false;
@@ -372,12 +374,17 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
- return NULL;
+ goto kzalloc_fail;
controller->private_data = musb;
/* Save physical address for DMA controller. */
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(musb->controller, "no memory resource defined\n");
+ goto plat_get_fail;
+ }
+
controller->phy_base = (dma_addr_t) iomem->start;
controller->controller.start = ux500_dma_controller_start;
@@ -389,4 +396,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba
controller->controller.is_compatible = ux500_dma_is_compatible;
return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ return NULL;
}
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
deleted file mode 100644
index 37962c99ff1e..000000000000
--- a/drivers/usb/otg/Kconfig
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# USB OTG infrastructure may be needed for peripheral-only, host-only,
-# or OTG-capable configurations when OTG transceivers or controllers
-# are used.
-#
-
-comment "OTG and related infrastructure"
-
-config USB_OTG_UTILS
- bool
- help
- Select this to make sure the build includes objects from
- the OTG infrastructure directory.
-
-if USB || USB_GADGET
-
-#
-# USB Transceiver Drivers
-#
-config USB_GPIO_VBUS
- tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
- depends on GENERIC_GPIO
- select USB_OTG_UTILS
- help
- Provides simple GPIO VBUS sensing for controllers with an
- internal transceiver via the usb_phy interface, and
- optionally control of a D+ pullup GPIO as well as a VBUS
- current limit regulator.
-
-config ISP1301_OMAP
- tristate "Philips ISP1301 with OMAP OTG"
- depends on I2C && ARCH_OMAP_OTG
- select USB_OTG_UTILS
- help
- If you say yes here you get support for the Philips ISP1301
- USB-On-The-Go transceiver working with the OMAP OTG controller.
- The ISP1301 is a full speed USB transceiver which is used in
- products including H2, H3, and H4 development boards for Texas
- Instruments OMAP processors.
-
- This driver can also be built as a module. If so, the module
- will be called isp1301_omap.
-
-config USB_ULPI
- bool "Generic ULPI Transceiver Driver"
- depends on ARM
- select USB_OTG_UTILS
- help
- Enable this to support ULPI connected USB OTG transceivers which
- are likely found on embedded boards.
-
-config USB_ULPI_VIEWPORT
- bool
- depends on USB_ULPI
- help
- Provides read/write operations to the ULPI phy register set for
- controllers with a viewport register (e.g. Chipidea/ARC controllers).
-
-config TWL4030_USB
- tristate "TWL4030 USB Transceiver Driver"
- depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on TWL4030
- family chips (including the TWL5030 and TPS659x0 devices).
- This transceiver supports high and full speed devices plus,
- in host mode, low speed.
-
-config TWL6030_USB
- tristate "TWL6030 USB Transceiver Driver"
- depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on TWL6030
- family chips. This TWL6030 transceiver has the VBUS and ID GND
- and OTG SRP events capabilities. For all other transceiver functionality
- UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
- are hooked to this driver through platform_data structure.
- The definition of internal PHY APIs are in the mach-omap2 layer.
-
-config NOP_USB_XCEIV
- tristate "NOP USB Transceiver Driver"
- select USB_OTG_UTILS
- help
- This driver is to be used by all the usb transceiver which are either
- built-in with usb ip or which are autonomous and doesn't require any
- phy programming such as ISP1x04 etc.
-
-config USB_MSM_OTG
- tristate "OTG support for Qualcomm on-chip USB controller"
- depends on (USB || USB_GADGET) && ARCH_MSM
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver on MSM chips. It
- handles PHY initialization, clock management, and workarounds
- required after resetting the hardware and power management.
- This driver is required even for peripheral only or host only
- mode configurations.
- This driver is not supported on boards like trout which
- has an external PHY.
-
-config AB8500_USB
- tristate "AB8500 USB Transceiver Driver"
- depends on AB8500_CORE
- select USB_OTG_UTILS
- help
- Enable this to support the USB OTG transceiver in AB8500 chip.
- This transceiver supports high and full speed devices plus,
- in host mode, low speed.
-
-config FSL_USB2_OTG
- bool "Freescale USB OTG Transceiver Driver"
- depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
- select USB_OTG
- select USB_OTG_UTILS
- help
- Enable this to support Freescale USB OTG transceiver.
-
-config USB_MXS_PHY
- tristate "Freescale MXS USB PHY support"
- depends on ARCH_MXC || ARCH_MXS
- select STMP_DEVICE
- select USB_OTG_UTILS
- help
- Enable this to support the Freescale MXS USB PHY.
-
- MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
-
-config USB_MV_OTG
- tristate "Marvell USB OTG support"
- depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
- select USB_OTG
- select USB_OTG_UTILS
- help
- Say Y here if you want to build Marvell USB OTG transciever
- driver in kernel (including PXA and MMP series). This driver
- implements role switch between EHCI host driver and gadget driver.
-
- To compile this driver as a module, choose M here.
-
-endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
deleted file mode 100644
index a844b8d35d14..000000000000
--- a/drivers/usb/otg/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-#
-# OTG infrastructure and transceiver drivers
-#
-
-ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
-
-# infrastructure
-obj-$(CONFIG_USB_OTG_UTILS) += otg.o
-
-# transceiver drivers
-obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
-obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
-obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
-obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
-obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
-obj-$(CONFIG_USB_ULPI) += ulpi.o
-obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o
-obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o
-obj-$(CONFIG_AB8500_USB) += ab8500-usb.o
-fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o
-obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o
-obj-$(CONFIG_USB_MXS_PHY) += mxs-phy.o
-obj-$(CONFIG_USB_MV_OTG) += mv_otg.o
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
deleted file mode 100644
index 2d86f26a0183..000000000000
--- a/drivers/usb/otg/ab8500-usb.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * drivers/usb/otg/ab8500_usb.c
- *
- * USB transceiver driver for AB8500 chip
- *
- * Copyright (C) 2010 ST-Ericsson AB
- * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/otg.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab8500.h>
-
-#define AB8500_MAIN_WD_CTRL_REG 0x01
-#define AB8500_USB_LINE_STAT_REG 0x80
-#define AB8500_USB_PHY_CTRL_REG 0x8A
-
-#define AB8500_BIT_OTG_STAT_ID (1 << 0)
-#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
-#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
-#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
-#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
-
-#define AB8500_V1x_LINK_STAT_WAIT (HZ/10)
-#define AB8500_WD_KICK_DELAY_US 100 /* usec */
-#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
-#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */
-
-/* Usb line status register */
-enum ab8500_usb_link_status {
- USB_LINK_NOT_CONFIGURED = 0,
- USB_LINK_STD_HOST_NC,
- USB_LINK_STD_HOST_C_NS,
- USB_LINK_STD_HOST_C_S,
- USB_LINK_HOST_CHG_NM,
- USB_LINK_HOST_CHG_HS,
- USB_LINK_HOST_CHG_HS_CHIRP,
- USB_LINK_DEDICATED_CHG,
- USB_LINK_ACA_RID_A,
- USB_LINK_ACA_RID_B,
- USB_LINK_ACA_RID_C_NM,
- USB_LINK_ACA_RID_C_HS,
- USB_LINK_ACA_RID_C_HS_CHIRP,
- USB_LINK_HM_IDGND,
- USB_LINK_RESERVED,
- USB_LINK_NOT_VALID_LINK
-};
-
-struct ab8500_usb {
- struct usb_phy phy;
- struct device *dev;
- int irq_num_id_rise;
- int irq_num_id_fall;
- int irq_num_vbus_rise;
- int irq_num_vbus_fall;
- int irq_num_link_status;
- unsigned vbus_draw;
- struct delayed_work dwork;
- struct work_struct phy_dis_work;
- unsigned long link_status_wait;
- int rev;
-};
-
-static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
-{
- return container_of(x, struct ab8500_usb, phy);
-}
-
-static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
-{
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- AB8500_BIT_WD_CTRL_ENABLE);
-
- udelay(AB8500_WD_KICK_DELAY_US);
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- (AB8500_BIT_WD_CTRL_ENABLE
- | AB8500_BIT_WD_CTRL_KICK));
-
- if (ab->rev > 0x10) /* v1.1 v2.0 */
- udelay(AB8500_WD_V11_DISABLE_DELAY_US);
- else /* v1.0 */
- msleep(AB8500_WD_V10_DISABLE_DELAY_MS);
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_SYS_CTRL2_BLOCK,
- AB8500_MAIN_WD_CTRL_REG,
- 0);
-}
-
-static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host,
- bool enable)
-{
- u8 ctrl_reg;
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_PHY_CTRL_REG,
- &ctrl_reg);
- if (sel_host) {
- if (enable)
- ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN;
- else
- ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN;
- } else {
- if (enable)
- ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN;
- else
- ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN;
- }
-
- abx500_set_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_PHY_CTRL_REG,
- ctrl_reg);
-
- /* Needed to enable the phy.*/
- if (enable)
- ab8500_usb_wd_workaround(ab);
-}
-
-#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true)
-#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false)
-#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true)
-#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false)
-
-static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
-{
- u8 reg;
- enum ab8500_usb_link_status lsts;
- void *v = NULL;
- enum usb_phy_events event;
-
- abx500_get_register_interruptible(ab->dev,
- AB8500_USB,
- AB8500_USB_LINE_STAT_REG,
- &reg);
-
- lsts = (reg >> 3) & 0x0F;
-
- switch (lsts) {
- case USB_LINK_NOT_CONFIGURED:
- case USB_LINK_RESERVED:
- case USB_LINK_NOT_VALID_LINK:
- /* TODO: Disable regulators. */
- ab8500_usb_host_phy_dis(ab);
- ab8500_usb_peri_phy_dis(ab);
- ab->phy.state = OTG_STATE_B_IDLE;
- ab->phy.otg->default_a = false;
- ab->vbus_draw = 0;
- event = USB_EVENT_NONE;
- break;
-
- case USB_LINK_STD_HOST_NC:
- case USB_LINK_STD_HOST_C_NS:
- case USB_LINK_STD_HOST_C_S:
- case USB_LINK_HOST_CHG_NM:
- case USB_LINK_HOST_CHG_HS:
- case USB_LINK_HOST_CHG_HS_CHIRP:
- if (ab->phy.otg->gadget) {
- /* TODO: Enable regulators. */
- ab8500_usb_peri_phy_en(ab);
- v = ab->phy.otg->gadget;
- }
- event = USB_EVENT_VBUS;
- break;
-
- case USB_LINK_HM_IDGND:
- if (ab->phy.otg->host) {
- /* TODO: Enable regulators. */
- ab8500_usb_host_phy_en(ab);
- v = ab->phy.otg->host;
- }
- ab->phy.state = OTG_STATE_A_IDLE;
- ab->phy.otg->default_a = true;
- event = USB_EVENT_ID;
- break;
-
- case USB_LINK_ACA_RID_A:
- case USB_LINK_ACA_RID_B:
- /* TODO */
- case USB_LINK_ACA_RID_C_NM:
- case USB_LINK_ACA_RID_C_HS:
- case USB_LINK_ACA_RID_C_HS_CHIRP:
- case USB_LINK_DEDICATED_CHG:
- /* TODO: vbus_draw */
- event = USB_EVENT_CHARGER;
- break;
- }
-
- atomic_notifier_call_chain(&ab->phy.notifier, event, v);
-
- return 0;
-}
-
-static void ab8500_usb_delayed_work(struct work_struct *work)
-{
- struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
- dwork.work);
-
- ab8500_usb_link_status_update(ab);
-}
-
-static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- /* Wait for link status to become stable. */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- /* Link status will not be updated till phy is disabled. */
- ab8500_usb_peri_phy_dis(ab);
-
- /* Wait for link status to become stable. */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ab8500_usb_v20_irq(int irq, void *data)
-{
- struct ab8500_usb *ab = (struct ab8500_usb *) data;
-
- ab8500_usb_link_status_update(ab);
-
- return IRQ_HANDLED;
-}
-
-static void ab8500_usb_phy_disable_work(struct work_struct *work)
-{
- struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
- phy_dis_work);
-
- if (!ab->phy.otg->host)
- ab8500_usb_host_phy_dis(ab);
-
- if (!ab->phy.otg->gadget)
- ab8500_usb_peri_phy_dis(ab);
-}
-
-static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
-{
- struct ab8500_usb *ab;
-
- if (!phy)
- return -ENODEV;
-
- ab = phy_to_ab(phy);
-
- ab->vbus_draw = mA;
-
- if (mA)
- atomic_notifier_call_chain(&ab->phy.notifier,
- USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
- return 0;
-}
-
-/* TODO: Implement some way for charging or other drivers to read
- * ab->vbus_draw.
- */
-
-static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
-{
- /* TODO */
- return 0;
-}
-
-static int ab8500_usb_set_peripheral(struct usb_otg *otg,
- struct usb_gadget *gadget)
-{
- struct ab8500_usb *ab;
-
- if (!otg)
- return -ENODEV;
-
- ab = phy_to_ab(otg->phy);
-
- /* Some drivers call this function in atomic context.
- * Do not update ab8500 registers directly till this
- * is fixed.
- */
-
- if (!gadget) {
- /* TODO: Disable regulators. */
- otg->gadget = NULL;
- schedule_work(&ab->phy_dis_work);
- } else {
- otg->gadget = gadget;
- otg->phy->state = OTG_STATE_B_IDLE;
-
- /* Phy will not be enabled if cable is already
- * plugged-in. Schedule to enable phy.
- * Use same delay to avoid any race condition.
- */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
- }
-
- return 0;
-}
-
-static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- struct ab8500_usb *ab;
-
- if (!otg)
- return -ENODEV;
-
- ab = phy_to_ab(otg->phy);
-
- /* Some drivers call this function in atomic context.
- * Do not update ab8500 registers directly till this
- * is fixed.
- */
-
- if (!host) {
- /* TODO: Disable regulators. */
- otg->host = NULL;
- schedule_work(&ab->phy_dis_work);
- } else {
- otg->host = host;
- /* Phy will not be enabled if cable is already
- * plugged-in. Schedule to enable phy.
- * Use same delay to avoid any race condition.
- */
- schedule_delayed_work(&ab->dwork, ab->link_status_wait);
- }
-
- return 0;
-}
-
-static void ab8500_usb_irq_free(struct ab8500_usb *ab)
-{
- if (ab->rev < 0x20) {
- free_irq(ab->irq_num_id_rise, ab);
- free_irq(ab->irq_num_id_fall, ab);
- free_irq(ab->irq_num_vbus_rise, ab);
- free_irq(ab->irq_num_vbus_fall, ab);
- } else {
- free_irq(ab->irq_num_link_status, ab);
- }
-}
-
-static int ab8500_usb_v1x_res_setup(struct platform_device *pdev,
- struct ab8500_usb *ab)
-{
- int err;
-
- ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R");
- if (ab->irq_num_id_rise < 0) {
- dev_err(&pdev->dev, "ID rise irq not found\n");
- return ab->irq_num_id_rise;
- }
- err = request_threaded_irq(ab->irq_num_id_rise, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-id-rise", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for ID rise irq\n");
- goto fail0;
- }
-
- ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
- if (ab->irq_num_id_fall < 0) {
- dev_err(&pdev->dev, "ID fall irq not found\n");
- return ab->irq_num_id_fall;
- }
- err = request_threaded_irq(ab->irq_num_id_fall, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-id-fall", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for ID fall irq\n");
- goto fail1;
- }
-
- ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R");
- if (ab->irq_num_vbus_rise < 0) {
- dev_err(&pdev->dev, "VBUS rise irq not found\n");
- return ab->irq_num_vbus_rise;
- }
- err = request_threaded_irq(ab->irq_num_vbus_rise, NULL,
- ab8500_usb_v1x_common_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-vbus-rise", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for Vbus rise irq\n");
- goto fail2;
- }
-
- ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F");
- if (ab->irq_num_vbus_fall < 0) {
- dev_err(&pdev->dev, "VBUS fall irq not found\n");
- return ab->irq_num_vbus_fall;
- }
- err = request_threaded_irq(ab->irq_num_vbus_fall, NULL,
- ab8500_usb_v1x_vbus_fall_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-vbus-fall", ab);
- if (err < 0) {
- dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
- goto fail3;
- }
-
- return 0;
-fail3:
- free_irq(ab->irq_num_vbus_rise, ab);
-fail2:
- free_irq(ab->irq_num_id_fall, ab);
-fail1:
- free_irq(ab->irq_num_id_rise, ab);
-fail0:
- return err;
-}
-
-static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
- struct ab8500_usb *ab)
-{
- int err;
-
- ab->irq_num_link_status = platform_get_irq_byname(pdev,
- "USB_LINK_STATUS");
- if (ab->irq_num_link_status < 0) {
- dev_err(&pdev->dev, "Link status irq not found\n");
- return ab->irq_num_link_status;
- }
-
- err = request_threaded_irq(ab->irq_num_link_status, NULL,
- ab8500_usb_v20_irq,
- IRQF_NO_SUSPEND | IRQF_SHARED,
- "usb-link-status", ab);
- if (err < 0) {
- dev_err(ab->dev,
- "request_irq failed for link status irq\n");
- return err;
- }
-
- return 0;
-}
-
-static int ab8500_usb_probe(struct platform_device *pdev)
-{
- struct ab8500_usb *ab;
- struct usb_otg *otg;
- int err;
- int rev;
-
- rev = abx500_get_chip_id(&pdev->dev);
- if (rev < 0) {
- dev_err(&pdev->dev, "Chip id read failed\n");
- return rev;
- } else if (rev < 0x10) {
- dev_err(&pdev->dev, "Unsupported AB8500 chip\n");
- return -ENODEV;
- }
-
- ab = kzalloc(sizeof *ab, GFP_KERNEL);
- if (!ab)
- return -ENOMEM;
-
- otg = kzalloc(sizeof *otg, GFP_KERNEL);
- if (!otg) {
- kfree(ab);
- return -ENOMEM;
- }
-
- ab->dev = &pdev->dev;
- ab->rev = rev;
- ab->phy.dev = ab->dev;
- ab->phy.otg = otg;
- ab->phy.label = "ab8500";
- ab->phy.set_suspend = ab8500_usb_set_suspend;
- ab->phy.set_power = ab8500_usb_set_power;
- ab->phy.state = OTG_STATE_UNDEFINED;
-
- otg->phy = &ab->phy;
- otg->set_host = ab8500_usb_set_host;
- otg->set_peripheral = ab8500_usb_set_peripheral;
-
- platform_set_drvdata(pdev, ab);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
-
- /* v1: Wait for link status to become stable.
- * all: Updates form set_host and set_peripheral as they are atomic.
- */
- INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work);
-
- /* all: Disable phy when called from set_host and set_peripheral */
- INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
-
- if (ab->rev < 0x20) {
- err = ab8500_usb_v1x_res_setup(pdev, ab);
- ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT;
- } else {
- err = ab8500_usb_v2_res_setup(pdev, ab);
- }
-
- if (err < 0)
- goto fail0;
-
- err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
- if (err) {
- dev_err(&pdev->dev, "Can't register transceiver\n");
- goto fail1;
- }
-
- dev_info(&pdev->dev, "AB8500 usb driver initialized\n");
-
- return 0;
-fail1:
- ab8500_usb_irq_free(ab);
-fail0:
- kfree(otg);
- kfree(ab);
- return err;
-}
-
-static int ab8500_usb_remove(struct platform_device *pdev)
-{
- struct ab8500_usb *ab = platform_get_drvdata(pdev);
-
- ab8500_usb_irq_free(ab);
-
- cancel_delayed_work_sync(&ab->dwork);
-
- cancel_work_sync(&ab->phy_dis_work);
-
- usb_remove_phy(&ab->phy);
-
- ab8500_usb_host_phy_dis(ab);
- ab8500_usb_peri_phy_dis(ab);
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(ab->phy.otg);
- kfree(ab);
-
- return 0;
-}
-
-static struct platform_driver ab8500_usb_driver = {
- .probe = ab8500_usb_probe,
- .remove = ab8500_usb_remove,
- .driver = {
- .name = "ab8500-usb",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init ab8500_usb_init(void)
-{
- return platform_driver_register(&ab8500_usb_driver);
-}
-subsys_initcall(ab8500_usb_init);
-
-static void __exit ab8500_usb_exit(void)
-{
- platform_driver_unregister(&ab8500_usb_driver);
-}
-module_exit(ab8500_usb_exit);
-
-MODULE_ALIAS("platform:ab8500_usb");
-MODULE_AUTHOR("ST-Ericsson AB");
-MODULE_DESCRIPTION("AB8500 usb transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 65217a590068..aab2ab2fbc90 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -1,13 +1,74 @@
#
# Physical Layer USB driver configuration
#
-comment "USB Physical Layer drivers"
- depends on USB || USB_GADGET
+menuconfig USB_PHY
+ bool "USB Physical Layer drivers"
+ help
+ USB controllers (those which are host, device or DRD) need a
+ device to handle the physical layer signalling, commonly called
+ a PHY.
+
+ The following drivers add support for such PHY devices.
+
+if USB_PHY
+
+#
+# USB Transceiver Drivers
+#
+config AB8500_USB
+ tristate "AB8500 USB Transceiver Driver"
+ depends on AB8500_CORE
+ help
+ Enable this to support the USB OTG transceiver in AB8500 chip.
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
+config FSL_USB2_OTG
+ bool "Freescale USB OTG Transceiver Driver"
+ depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
+ select USB_OTG
+ help
+ Enable this to support Freescale USB OTG transceiver.
+
+config ISP1301_OMAP
+ tristate "Philips ISP1301 with OMAP OTG"
+ depends on I2C && ARCH_OMAP_OTG
+ help
+ If you say yes here you get support for the Philips ISP1301
+ USB-On-The-Go transceiver working with the OMAP OTG controller.
+ The ISP1301 is a full speed USB transceiver which is used in
+ products including H2, H3, and H4 development boards for Texas
+ Instruments OMAP processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called isp1301_omap.
+
+config MV_U3D_PHY
+ bool "Marvell USB 3.0 PHY controller Driver"
+ depends on CPU_MMP3
+ help
+ Enable this to support Marvell USB 3.0 phy controller for Marvell
+ SoC.
+
+config NOP_USB_XCEIV
+ tristate "NOP USB Transceiver Driver"
+ help
+ This driver is to be used by all the usb transceiver which are either
+ built-in with usb ip or which are autonomous and doesn't require any
+ phy programming such as ISP1x04 etc.
+
+config OMAP_CONTROL_USB
+ tristate "OMAP CONTROL USB Driver"
+ help
+ Enable this to add support for the USB part present in the control
+ module. This driver has API to power on the USB2 PHY and to write to
+ the mailbox. The mailbox is present only in omap4 and the register to
+ power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+ additional register to power on USB3 PHY.
config OMAP_USB2
tristate "OMAP USB2 PHY Driver"
depends on ARCH_OMAP2PLUS
- select USB_OTG_UTILS
select OMAP_CONTROL_USB
help
Enable this to support the transceiver that is part of SOC. This
@@ -17,7 +78,6 @@ config OMAP_USB2
config OMAP_USB3
tristate "OMAP USB3 PHY Driver"
- select USB_OTG_UTILS
select OMAP_CONTROL_USB
help
Enable this to support the USB3 PHY that is part of SOC. This
@@ -25,19 +85,61 @@ config OMAP_USB3
This driver interacts with the "OMAP Control USB Driver" to power
on/off the PHY.
-config OMAP_CONTROL_USB
- tristate "OMAP CONTROL USB Driver"
+config SAMSUNG_USBPHY
+ tristate "Samsung USB PHY Driver"
help
- Enable this to add support for the USB part present in the control
- module. This driver has API to power on the USB2 PHY and to write to
- the mailbox. The mailbox is present only in omap4 and the register to
- power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
- additional register to power on USB3 PHY.
+ Enable this to support Samsung USB phy helper driver for Samsung SoCs.
+ This driver provides common interface to interact, for Samsung USB 2.0 PHY
+ driver and later for Samsung USB 3.0 PHY driver.
+
+config SAMSUNG_USB2PHY
+ tristate "Samsung USB 2.0 PHY controller Driver"
+ select SAMSUNG_USBPHY
+ help
+ Enable this to support Samsung USB 2.0 (High Speed) PHY controller
+ driver for Samsung SoCs.
+
+config SAMSUNG_USB3PHY
+ tristate "Samsung USB 3.0 PHY controller Driver"
+ select SAMSUNG_USBPHY
+ help
+ Enable this to support Samsung USB 3.0 (Super Speed) phy controller
+ for samsung SoCs.
+
+config TWL4030_USB
+ tristate "TWL4030 USB Transceiver Driver"
+ depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
+ help
+ Enable this to support the USB OTG transceiver on TWL4030
+ family chips (including the TWL5030 and TPS659x0 devices).
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
+config TWL6030_USB
+ tristate "TWL6030 USB Transceiver Driver"
+ depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
+ help
+ Enable this to support the USB OTG transceiver on TWL6030
+ family chips. This TWL6030 transceiver has the VBUS and ID GND
+ and OTG SRP events capabilities. For all other transceiver functionality
+ UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
+ are hooked to this driver through platform_data structure.
+ The definition of internal PHY APIs are in the mach-omap2 layer.
+
+config USB_GPIO_VBUS
+ tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
+ depends on GENERIC_GPIO
+ help
+ Provides simple GPIO VBUS sensing for controllers with an
+ internal transceiver via the usb_phy interface, and
+ optionally control of a D+ pullup GPIO as well as a VBUS
+ current limit regulator.
config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
depends on USB || USB_GADGET
depends on I2C
+ select USB_OTG_UTILS
help
Say Y here to add support for the NXP ISP1301 USB transceiver driver.
This chip is typically used as USB transceiver for USB host, gadget
@@ -46,18 +148,41 @@ config USB_ISP1301
To compile this driver as a module, choose M here: the
module will be called isp1301.
-config MV_U3D_PHY
- bool "Marvell USB 3.0 PHY controller Driver"
- depends on USB_MV_U3D
- select USB_OTG_UTILS
+config USB_MSM_OTG
+ tristate "OTG support for Qualcomm on-chip USB controller"
+ depends on (USB || USB_GADGET) && ARCH_MSM
help
- Enable this to support Marvell USB 3.0 phy controller for Marvell
- SoC.
+ Enable this to support the USB OTG transceiver on MSM chips. It
+ handles PHY initialization, clock management, and workarounds
+ required after resetting the hardware and power management.
+ This driver is required even for peripheral only or host only
+ mode configurations.
+ This driver is not supported on boards like trout which
+ has an external PHY.
+
+config USB_MV_OTG
+ tristate "Marvell USB OTG support"
+ depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
+ select USB_OTG
+ help
+ Say Y here if you want to build Marvell USB OTG transciever
+ driver in kernel (including PXA and MMP series). This driver
+ implements role switch between EHCI host driver and gadget driver.
+
+ To compile this driver as a module, choose M here.
+
+config USB_MXS_PHY
+ tristate "Freescale MXS USB PHY support"
+ depends on ARCH_MXC || ARCH_MXS
+ select STMP_DEVICE
+ help
+ Enable this to support the Freescale MXS USB PHY.
+
+ MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x.
config USB_RCAR_PHY
tristate "Renesas R-Car USB phy support"
depends on USB || USB_GADGET
- select USB_OTG_UTILS
help
Say Y here to add support for the Renesas R-Car USB phy driver.
This chip is typically used as USB phy for USB host, gadget.
@@ -66,10 +191,18 @@ config USB_RCAR_PHY
To compile this driver as a module, choose M here: the
module will be called rcar-phy.
-config SAMSUNG_USBPHY
- bool "Samsung USB PHY controller Driver"
- depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS
- select USB_OTG_UTILS
+config USB_ULPI
+ bool "Generic ULPI Transceiver Driver"
+ depends on ARM
+ help
+ Enable this to support ULPI connected USB OTG transceivers which
+ are likely found on embedded boards.
+
+config USB_ULPI_VIEWPORT
+ bool
+ depends on USB_ULPI
help
- Enable this to support Samsung USB phy controller for samsung
- SoCs.
+ Provides read/write operations to the ULPI phy register set for
+ controllers with a viewport register (e.g. Chipidea/ARC controllers).
+
+endif # USB_PHY
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index b13faa193e0c..a9169cb1e6fc 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -4,11 +4,30 @@
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
-obj-$(CONFIG_OMAP_USB2) += omap-usb2.o
-obj-$(CONFIG_OMAP_USB3) += omap-usb3.o
-obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o
-obj-$(CONFIG_USB_ISP1301) += isp1301.o
-obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o
-obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o
-obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o
-obj-$(CONFIG_SAMSUNG_USBPHY) += samsung-usbphy.o
+obj-$(CONFIG_USB_PHY) += phy.o
+
+# transceiver drivers, keep the list sorted
+
+obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o
+phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o
+obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o
+obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o
+obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o
+obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o
+obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o
+obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
+obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o
+obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o
+obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o
+obj-$(CONFIG_SAMSUNG_USB3PHY) += phy-samsung-usb3.o
+obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
+obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o
+obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o
+obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o
+obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o
+obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o
+obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o
+obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o
+obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o
+obj-$(CONFIG_USB_ULPI) += phy-ulpi.o
+obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
deleted file mode 100644
index 18dbf7e37607..000000000000
--- a/drivers/usb/phy/isp1301.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * NXP ISP1301 USB transceiver driver
- *
- * Copyright (C) 2012 Roland Stigge
- *
- * Author: Roland Stigge <stigge@antcom.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-
-#define DRV_NAME "isp1301"
-
-static const struct i2c_device_id isp1301_id[] = {
- { "isp1301", 0 },
- { }
-};
-
-static struct i2c_client *isp1301_i2c_client;
-
-static int isp1301_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
-{
- isp1301_i2c_client = client;
- return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
- return 0;
-}
-
-static struct i2c_driver isp1301_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .probe = isp1301_probe,
- .remove = isp1301_remove,
- .id_table = isp1301_id,
-};
-
-module_i2c_driver(isp1301_driver);
-
-static int match(struct device *dev, void *data)
-{
- struct device_node *node = (struct device_node *)data;
- return (dev->of_node == node) &&
- (dev->driver == &isp1301_driver.driver);
-}
-
-struct i2c_client *isp1301_get_client(struct device_node *node)
-{
- if (node) { /* reference of ISP1301 I2C node via DT */
- struct device *dev = bus_find_device(&i2c_bus_type, NULL,
- node, match);
- if (!dev)
- return NULL;
- return to_i2c_client(dev);
- } else { /* non-DT: only one ISP1301 chip supported */
- return isp1301_i2c_client;
- }
-}
-EXPORT_SYMBOL_GPL(isp1301_get_client);
-
-MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
-MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
new file mode 100644
index 000000000000..4acef26a2ef5
--- /dev/null
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -0,0 +1,924 @@
+/*
+ * drivers/usb/otg/ab8500_usb.c
+ *
+ * USB transceiver driver for AB8500 chip
+ *
+ * Copyright (C) 2010 ST-Ericsson AB
+ * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/usb/otg.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/usb/musb-ux500.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+
+/* Bank AB8500_SYS_CTRL2_BLOCK */
+#define AB8500_MAIN_WD_CTRL_REG 0x01
+
+/* Bank AB8500_USB */
+#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8505_USB_LINE_STAT_REG 0x94
+#define AB8500_USB_PHY_CTRL_REG 0x8A
+
+/* Bank AB8500_DEVELOPMENT */
+#define AB8500_BANK12_ACCESS 0x00
+
+/* Bank AB8500_DEBUG */
+#define AB8500_USB_PHY_TUNE1 0x05
+#define AB8500_USB_PHY_TUNE2 0x06
+#define AB8500_USB_PHY_TUNE3 0x07
+
+#define AB8500_BIT_OTG_STAT_ID (1 << 0)
+#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0)
+#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1)
+#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0)
+#define AB8500_BIT_WD_CTRL_KICK (1 << 1)
+
+#define AB8500_WD_KICK_DELAY_US 100 /* usec */
+#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */
+#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */
+
+/* Usb line status register */
+enum ab8500_usb_link_status {
+ USB_LINK_NOT_CONFIGURED_8500 = 0,
+ USB_LINK_STD_HOST_NC_8500,
+ USB_LINK_STD_HOST_C_NS_8500,
+ USB_LINK_STD_HOST_C_S_8500,
+ USB_LINK_HOST_CHG_NM_8500,
+ USB_LINK_HOST_CHG_HS_8500,
+ USB_LINK_HOST_CHG_HS_CHIRP_8500,
+ USB_LINK_DEDICATED_CHG_8500,
+ USB_LINK_ACA_RID_A_8500,
+ USB_LINK_ACA_RID_B_8500,
+ USB_LINK_ACA_RID_C_NM_8500,
+ USB_LINK_ACA_RID_C_HS_8500,
+ USB_LINK_ACA_RID_C_HS_CHIRP_8500,
+ USB_LINK_HM_IDGND_8500,
+ USB_LINK_RESERVED_8500,
+ USB_LINK_NOT_VALID_LINK_8500,
+};
+
+enum ab8505_usb_link_status {
+ USB_LINK_NOT_CONFIGURED_8505 = 0,
+ USB_LINK_STD_HOST_NC_8505,
+ USB_LINK_STD_HOST_C_NS_8505,
+ USB_LINK_STD_HOST_C_S_8505,
+ USB_LINK_CDP_8505,
+ USB_LINK_RESERVED0_8505,
+ USB_LINK_RESERVED1_8505,
+ USB_LINK_DEDICATED_CHG_8505,
+ USB_LINK_ACA_RID_A_8505,
+ USB_LINK_ACA_RID_B_8505,
+ USB_LINK_ACA_RID_C_NM_8505,
+ USB_LINK_RESERVED2_8505,
+ USB_LINK_RESERVED3_8505,
+ USB_LINK_HM_IDGND_8505,
+ USB_LINK_CHARGERPORT_NOT_OK_8505,
+ USB_LINK_CHARGER_DM_HIGH_8505,
+ USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505,
+ USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505,
+ USB_LINK_STD_UPSTREAM_8505,
+ USB_LINK_CHARGER_SE1_8505,
+ USB_LINK_CARKIT_CHGR_1_8505,
+ USB_LINK_CARKIT_CHGR_2_8505,
+ USB_LINK_ACA_DOCK_CHGR_8505,
+ USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505,
+ USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505,
+ USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505,
+ USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505,
+ USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505,
+};
+
+enum ab8500_usb_mode {
+ USB_IDLE = 0,
+ USB_PERIPHERAL,
+ USB_HOST,
+ USB_DEDICATED_CHG
+};
+
+struct ab8500_usb {
+ struct usb_phy phy;
+ struct device *dev;
+ struct ab8500 *ab8500;
+ unsigned vbus_draw;
+ struct work_struct phy_dis_work;
+ enum ab8500_usb_mode mode;
+ struct regulator *v_ape;
+ struct regulator *v_musb;
+ struct regulator *v_ulpi;
+ int saved_v_ulpi;
+ int previous_link_status_state;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_sleep;
+};
+
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
+{
+ return container_of(x, struct ab8500_usb, phy);
+}
+
+static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
+{
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ AB8500_BIT_WD_CTRL_ENABLE);
+
+ udelay(AB8500_WD_KICK_DELAY_US);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ (AB8500_BIT_WD_CTRL_ENABLE
+ | AB8500_BIT_WD_CTRL_KICK));
+
+ udelay(AB8500_WD_V11_DISABLE_DELAY_US);
+
+ abx500_set_register_interruptible(ab->dev,
+ AB8500_SYS_CTRL2_BLOCK,
+ AB8500_MAIN_WD_CTRL_REG,
+ 0);
+}
+
+static void ab8500_usb_regulator_enable(struct ab8500_usb *ab)
+{
+ int ret, volt;
+
+ ret = regulator_enable(ab->v_ape);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable v-ape\n");
+
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi);
+ if (ab->saved_v_ulpi < 0)
+ dev_err(ab->dev, "Failed to get v_ulpi voltage\n");
+
+ ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n",
+ ret);
+
+ ret = regulator_set_optimum_mode(ab->v_ulpi, 28000);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+ ret);
+ }
+
+ ret = regulator_enable(ab->v_ulpi);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable vddulpivio18\n");
+
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ volt = regulator_get_voltage(ab->v_ulpi);
+ if ((volt != 1300000) && (volt != 1350000))
+ dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n",
+ volt);
+ }
+
+ ret = regulator_enable(ab->v_musb);
+ if (ret)
+ dev_err(ab->dev, "Failed to enable musb_1v8\n");
+}
+
+static void ab8500_usb_regulator_disable(struct ab8500_usb *ab)
+{
+ int ret;
+
+ regulator_disable(ab->v_musb);
+
+ regulator_disable(ab->v_ulpi);
+
+ /* USB is not the only consumer of Vintcore, restore old settings */
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ if (ab->saved_v_ulpi > 0) {
+ ret = regulator_set_voltage(ab->v_ulpi,
+ ab->saved_v_ulpi, ab->saved_v_ulpi);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n",
+ ab->saved_v_ulpi, ret);
+ }
+
+ ret = regulator_set_optimum_mode(ab->v_ulpi, 0);
+ if (ret < 0)
+ dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
+ ret);
+ }
+
+ regulator_disable(ab->v_ape);
+}
+
+static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit)
+{
+ /* Workaround for v2.0 bug # 31952 */
+ if (is_ab8500_2p0(ab->ab8500)) {
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, bit);
+ udelay(AB8500_V20_31952_DISABLE_DELAY_US);
+ }
+}
+
+static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
+{
+ u8 bit;
+ bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+ AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+ /* mux and configure USB pins to DEFAULT state */
+ ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(ab->pinctrl))
+ dev_err(ab->dev, "could not get/set default pinstate\n");
+
+ ab8500_usb_regulator_enable(ab);
+
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, bit);
+}
+
+static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
+{
+ u8 bit;
+ bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
+ AB8500_BIT_PHY_CTRL_DEVICE_EN;
+
+ ab8500_usb_wd_linkstatus(ab, bit);
+
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ bit, 0);
+
+ /* Needed to disable the phy.*/
+ ab8500_usb_wd_workaround(ab);
+
+ ab8500_usb_regulator_disable(ab);
+
+ if (!IS_ERR(ab->pinctrl)) {
+ /* configure USB pins to SLEEP state */
+ ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl,
+ PINCTRL_STATE_SLEEP);
+
+ if (IS_ERR(ab->pins_sleep))
+ dev_dbg(ab->dev, "could not get sleep pinstate\n");
+ else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
+ dev_err(ab->dev, "could not set pins to sleep state\n");
+
+ /* as USB pins are shared with idddet, release them to allow
+ * iddet to request them
+ */
+ pinctrl_put(ab->pinctrl);
+ }
+}
+
+#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true)
+#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_disable(ab, true)
+#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false)
+#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false)
+
+static int ab8505_usb_link_status_update(struct ab8500_usb *ab,
+ enum ab8505_usb_link_status lsts)
+{
+ enum ux500_musb_vbus_id_status event = 0;
+
+ dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts);
+
+ /*
+ * Spurious link_status interrupts are seen at the time of
+ * disconnection of a device in RIDA state
+ */
+ if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
+ (lsts == USB_LINK_STD_HOST_NC_8505))
+ return 0;
+
+ ab->previous_link_status_state = lsts;
+
+ switch (lsts) {
+ case USB_LINK_ACA_RID_B_8505:
+ event = UX500_MUSB_RIDB;
+ case USB_LINK_NOT_CONFIGURED_8505:
+ case USB_LINK_RESERVED0_8505:
+ case USB_LINK_RESERVED1_8505:
+ case USB_LINK_RESERVED2_8505:
+ case USB_LINK_RESERVED3_8505:
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ if (event != UX500_MUSB_RIDB)
+ event = UX500_MUSB_NONE;
+ /*
+ * Fallback to default B_IDLE as nothing
+ * is connected
+ */
+ ab->phy.state = OTG_STATE_B_IDLE;
+ break;
+
+ case USB_LINK_ACA_RID_C_NM_8505:
+ event = UX500_MUSB_RIDC;
+ case USB_LINK_STD_HOST_NC_8505:
+ case USB_LINK_STD_HOST_C_NS_8505:
+ case USB_LINK_STD_HOST_C_S_8505:
+ case USB_LINK_CDP_8505:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_PERIPHERAL;
+ ab8500_usb_peri_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ if (event != UX500_MUSB_RIDC)
+ event = UX500_MUSB_VBUS;
+ break;
+
+ case USB_LINK_ACA_RID_A_8505:
+ case USB_LINK_ACA_DOCK_CHGR_8505:
+ event = UX500_MUSB_RIDA;
+ case USB_LINK_HM_IDGND_8505:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_HOST;
+ ab8500_usb_host_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ ab->phy.otg->default_a = true;
+ if (event != UX500_MUSB_RIDA)
+ event = UX500_MUSB_ID;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_DEDICATED_CHG_8505:
+ ab->mode = USB_DEDICATED_CHG;
+ event = UX500_MUSB_CHARGER;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_link_status_update(struct ab8500_usb *ab,
+ enum ab8500_usb_link_status lsts)
+{
+ enum ux500_musb_vbus_id_status event = 0;
+
+ dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts);
+
+ /*
+ * Spurious link_status interrupts are seen in case of a
+ * disconnection of a device in IDGND and RIDA stage
+ */
+ if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
+ (lsts == USB_LINK_STD_HOST_C_NS_8500 ||
+ lsts == USB_LINK_STD_HOST_NC_8500))
+ return 0;
+
+ if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
+ lsts == USB_LINK_STD_HOST_NC_8500)
+ return 0;
+
+ ab->previous_link_status_state = lsts;
+
+ switch (lsts) {
+ case USB_LINK_ACA_RID_B_8500:
+ event = UX500_MUSB_RIDB;
+ case USB_LINK_NOT_CONFIGURED_8500:
+ case USB_LINK_NOT_VALID_LINK_8500:
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ if (event != UX500_MUSB_RIDB)
+ event = UX500_MUSB_NONE;
+ /* Fallback to default B_IDLE as nothing is connected */
+ ab->phy.state = OTG_STATE_B_IDLE;
+ break;
+
+ case USB_LINK_ACA_RID_C_NM_8500:
+ case USB_LINK_ACA_RID_C_HS_8500:
+ case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
+ event = UX500_MUSB_RIDC;
+ case USB_LINK_STD_HOST_NC_8500:
+ case USB_LINK_STD_HOST_C_NS_8500:
+ case USB_LINK_STD_HOST_C_S_8500:
+ case USB_LINK_HOST_CHG_NM_8500:
+ case USB_LINK_HOST_CHG_HS_8500:
+ case USB_LINK_HOST_CHG_HS_CHIRP_8500:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_PERIPHERAL;
+ ab8500_usb_peri_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ if (event != UX500_MUSB_RIDC)
+ event = UX500_MUSB_VBUS;
+ break;
+
+ case USB_LINK_ACA_RID_A_8500:
+ event = UX500_MUSB_RIDA;
+ case USB_LINK_HM_IDGND_8500:
+ if (ab->mode == USB_IDLE) {
+ ab->mode = USB_HOST;
+ ab8500_usb_host_phy_en(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_PREPARE, &ab->vbus_draw);
+ }
+ ab->phy.otg->default_a = true;
+ if (event != UX500_MUSB_RIDA)
+ event = UX500_MUSB_ID;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_DEDICATED_CHG_8500:
+ ab->mode = USB_DEDICATED_CHG;
+ event = UX500_MUSB_CHARGER;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ break;
+
+ case USB_LINK_RESERVED_8500:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Connection Sequence:
+ * 1. Link Status Interrupt
+ * 2. Enable AB clock
+ * 3. Enable AB regulators
+ * 4. Enable USB phy
+ * 5. Reset the musb controller
+ * 6. Switch the ULPI GPIO pins to fucntion mode
+ * 7. Enable the musb Peripheral5 clock
+ * 8. Restore MUSB context
+ */
+static int abx500_usb_link_status_update(struct ab8500_usb *ab)
+{
+ u8 reg;
+ int ret = 0;
+
+ if (is_ab8500(ab->ab8500)) {
+ enum ab8500_usb_link_status lsts;
+
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_LINE_STAT_REG, &reg);
+ lsts = (reg >> 3) & 0x0F;
+ ret = ab8500_usb_link_status_update(ab, lsts);
+ } else if (is_ab8505(ab->ab8500)) {
+ enum ab8505_usb_link_status lsts;
+
+ abx500_get_register_interruptible(ab->dev,
+ AB8500_USB, AB8505_USB_LINE_STAT_REG, &reg);
+ lsts = (reg >> 3) & 0x1F;
+ ret = ab8505_usb_link_status_update(ab, lsts);
+ }
+
+ return ret;
+}
+
+/*
+ * Disconnection Sequence:
+ * 1. Disconect Interrupt
+ * 2. Disable regulators
+ * 3. Disable AB clock
+ * 4. Disable the Phy
+ * 5. Link Status Interrupt
+ * 6. Disable Musb Clock
+ */
+static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+ enum usb_phy_events event = UX500_MUSB_NONE;
+
+ /* Link status will not be updated till phy is disabled. */
+ if (ab->mode == USB_HOST) {
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ ab8500_usb_host_phy_dis(ab);
+ ab->mode = USB_IDLE;
+ }
+
+ if (ab->mode == USB_PERIPHERAL) {
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ event, &ab->vbus_draw);
+ ab8500_usb_peri_phy_dis(ab);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_CLEAN, &ab->vbus_draw);
+ ab->mode = USB_IDLE;
+ ab->phy.otg->default_a = false;
+ ab->vbus_draw = 0;
+ }
+
+ if (is_ab8500_2p0(ab->ab8500)) {
+ if (ab->mode == USB_DEDICATED_CHG) {
+ ab8500_usb_wd_linkstatus(ab,
+ AB8500_BIT_PHY_CTRL_DEVICE_EN);
+ abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+ AB8500_BIT_PHY_CTRL_DEVICE_EN, 0);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
+{
+ struct ab8500_usb *ab = (struct ab8500_usb *) data;
+
+ abx500_usb_link_status_update(ab);
+
+ return IRQ_HANDLED;
+}
+
+static void ab8500_usb_phy_disable_work(struct work_struct *work)
+{
+ struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
+ phy_dis_work);
+
+ if (!ab->phy.otg->host)
+ ab8500_usb_host_phy_dis(ab);
+
+ if (!ab->phy.otg->gadget)
+ ab8500_usb_peri_phy_dis(ab);
+}
+
+static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA)
+{
+ /*
+ * AB8500 V2 has eye diagram issues when drawing more than 100mA from
+ * VBUS. Set charging current to 100mA in case of standard host
+ */
+ if (is_ab8500_2p0_or_earlier(ab->ab8500))
+ if (mA > 100)
+ mA = 100;
+
+ return mA;
+}
+
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
+{
+ struct ab8500_usb *ab;
+
+ if (!phy)
+ return -ENODEV;
+
+ ab = phy_to_ab(phy);
+
+ mA = ab8500_eyediagram_workaroud(ab, mA);
+
+ ab->vbus_draw = mA;
+
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ UX500_MUSB_VBUS, &ab->vbus_draw);
+
+ return 0;
+}
+
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
+{
+ /* TODO */
+ return 0;
+}
+
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = phy_to_ab(otg->phy);
+
+ ab->phy.otg->gadget = gadget;
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if ((ab->mode != USB_IDLE) && (!gadget)) {
+ ab->mode = USB_IDLE;
+ schedule_work(&ab->phy_dis_work);
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ struct ab8500_usb *ab;
+
+ if (!otg)
+ return -ENODEV;
+
+ ab = phy_to_ab(otg->phy);
+
+ ab->phy.otg->host = host;
+
+ /* Some drivers call this function in atomic context.
+ * Do not update ab8500 registers directly till this
+ * is fixed.
+ */
+
+ if ((ab->mode != USB_IDLE) && (!host)) {
+ ab->mode = USB_IDLE;
+ schedule_work(&ab->phy_dis_work);
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_regulator_get(struct ab8500_usb *ab)
+{
+ int err;
+
+ ab->v_ape = devm_regulator_get(ab->dev, "v-ape");
+ if (IS_ERR(ab->v_ape)) {
+ dev_err(ab->dev, "Could not get v-ape supply\n");
+ err = PTR_ERR(ab->v_ape);
+ return err;
+ }
+
+ ab->v_ulpi = devm_regulator_get(ab->dev, "vddulpivio18");
+ if (IS_ERR(ab->v_ulpi)) {
+ dev_err(ab->dev, "Could not get vddulpivio18 supply\n");
+ err = PTR_ERR(ab->v_ulpi);
+ return err;
+ }
+
+ ab->v_musb = devm_regulator_get(ab->dev, "musb_1v8");
+ if (IS_ERR(ab->v_musb)) {
+ dev_err(ab->dev, "Could not get musb_1v8 supply\n");
+ err = PTR_ERR(ab->v_musb);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_irq_setup(struct platform_device *pdev,
+ struct ab8500_usb *ab)
+{
+ int err;
+ int irq;
+
+ irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Link status irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_link_status_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for link status irq\n");
+ return err;
+ }
+
+ irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "ID fall irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_disconnect_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for ID fall irq\n");
+ return err;
+ }
+
+ irq = platform_get_irq_byname(pdev, "VBUS_DET_F");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "VBUS fall irq not found\n");
+ return irq;
+ }
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ ab8500_usb_disconnect_irq,
+ IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab);
+ if (err < 0) {
+ dev_err(ab->dev, "request_irq failed for Vbus fall irq\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int ab8500_usb_probe(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab;
+ struct ab8500 *ab8500;
+ struct usb_otg *otg;
+ int err;
+ int rev;
+
+ ab8500 = dev_get_drvdata(pdev->dev.parent);
+ rev = abx500_get_chip_id(&pdev->dev);
+
+ if (is_ab8500_1p1_or_earlier(ab8500)) {
+ dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev);
+ return -ENODEV;
+ }
+
+ ab = devm_kzalloc(&pdev->dev, sizeof(*ab), GFP_KERNEL);
+ if (!ab)
+ return -ENOMEM;
+
+ otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg)
+ return -ENOMEM;
+
+ ab->dev = &pdev->dev;
+ ab->ab8500 = ab8500;
+ ab->phy.dev = ab->dev;
+ ab->phy.otg = otg;
+ ab->phy.label = "ab8500";
+ ab->phy.set_suspend = ab8500_usb_set_suspend;
+ ab->phy.set_power = ab8500_usb_set_power;
+ ab->phy.state = OTG_STATE_UNDEFINED;
+
+ otg->phy = &ab->phy;
+ otg->set_host = ab8500_usb_set_host;
+ otg->set_peripheral = ab8500_usb_set_peripheral;
+
+ platform_set_drvdata(pdev, ab);
+
+ ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
+
+ /* all: Disable phy when called from set_host and set_peripheral */
+ INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
+
+ err = ab8500_usb_regulator_get(ab);
+ if (err)
+ return err;
+
+ err = ab8500_usb_irq_setup(pdev, ab);
+ if (err < 0)
+ return err;
+
+ err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2);
+ if (err) {
+ dev_err(&pdev->dev, "Can't register transceiver\n");
+ return err;
+ }
+
+ /* Phy tuning values for AB8500 */
+ if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+ /* Enable the PBT/Bank 0x12 access */
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+ err);
+
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+ err);
+
+ /* Switch to normal mode/disable Bank 0x12 access */
+ err = abx500_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+ err);
+ }
+
+ /* Phy tuning values for AB8505 */
+ if (is_ab8505(ab->ab8500)) {
+ /* Enable the PBT/Bank 0x12 access */
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+ 0x01, 0x01);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to enable bank12 access err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE1,
+ 0xC8, 0xC8);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE2,
+ 0x60, 0x60);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n",
+ err);
+
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEBUG, AB8500_USB_PHY_TUNE3,
+ 0xFC, 0x80);
+
+ if (err < 0)
+ dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n",
+ err);
+
+ /* Switch to normal mode/disable Bank 0x12 access */
+ err = abx500_mask_and_set_register_interruptible(ab->dev,
+ AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS,
+ 0x00, 0x00);
+ if (err < 0)
+ dev_err(ab->dev, "Failed to switch bank12 access err=%d\n",
+ err);
+ }
+
+ /* Needed to enable ID detection. */
+ ab8500_usb_wd_workaround(ab);
+
+ abx500_usb_link_status_update(ab);
+
+ dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
+
+ return 0;
+}
+
+static int ab8500_usb_remove(struct platform_device *pdev)
+{
+ struct ab8500_usb *ab = platform_get_drvdata(pdev);
+
+ cancel_work_sync(&ab->phy_dis_work);
+
+ usb_remove_phy(&ab->phy);
+
+ if (ab->mode == USB_HOST)
+ ab8500_usb_host_phy_dis(ab);
+ else if (ab->mode == USB_PERIPHERAL)
+ ab8500_usb_peri_phy_dis(ab);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver ab8500_usb_driver = {
+ .probe = ab8500_usb_probe,
+ .remove = ab8500_usb_remove,
+ .driver = {
+ .name = "ab8500-usb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ab8500_usb_init(void)
+{
+ return platform_driver_register(&ab8500_usb_driver);
+}
+subsys_initcall(ab8500_usb_init);
+
+static void __exit ab8500_usb_exit(void)
+{
+ platform_driver_unregister(&ab8500_usb_driver);
+}
+module_exit(ab8500_usb_exit);
+
+MODULE_ALIAS("platform:ab8500_usb");
+MODULE_AUTHOR("ST-Ericsson AB");
+MODULE_DESCRIPTION("AB8500 usb transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/phy/phy-fsl-usb.c
index d16adb41eb21..97b9308507c3 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -43,7 +43,7 @@
#include <asm/unaligned.h>
-#include "fsl_otg.h"
+#include "phy-fsl-usb.h"
#define DRIVER_VERSION "Rev. 1.55"
#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
@@ -361,28 +361,18 @@ int fsl_otg_init_timers(struct otg_fsm *fsm)
void fsl_otg_uninit_timers(void)
{
/* FSM used timers */
- if (a_wait_vrise_tmr != NULL)
- kfree(a_wait_vrise_tmr);
- if (a_wait_bcon_tmr != NULL)
- kfree(a_wait_bcon_tmr);
- if (a_aidl_bdis_tmr != NULL)
- kfree(a_aidl_bdis_tmr);
- if (b_ase0_brst_tmr != NULL)
- kfree(b_ase0_brst_tmr);
- if (b_se0_srp_tmr != NULL)
- kfree(b_se0_srp_tmr);
- if (b_srp_fail_tmr != NULL)
- kfree(b_srp_fail_tmr);
- if (a_wait_enum_tmr != NULL)
- kfree(a_wait_enum_tmr);
+ kfree(a_wait_vrise_tmr);
+ kfree(a_wait_bcon_tmr);
+ kfree(a_aidl_bdis_tmr);
+ kfree(b_ase0_brst_tmr);
+ kfree(b_se0_srp_tmr);
+ kfree(b_srp_fail_tmr);
+ kfree(a_wait_enum_tmr);
/* device driver used timers */
- if (b_srp_wait_tmr != NULL)
- kfree(b_srp_wait_tmr);
- if (b_data_pulse_tmr != NULL)
- kfree(b_data_pulse_tmr);
- if (b_vbus_pulse_tmr != NULL)
- kfree(b_vbus_pulse_tmr);
+ kfree(b_srp_wait_tmr);
+ kfree(b_data_pulse_tmr);
+ kfree(b_vbus_pulse_tmr);
}
/* Add timer to timer list */
@@ -1002,7 +992,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
/* State */
t = scnprintf(next, size,
"OTG state: %s\n\n",
- otg_state_string(fsl_otg_dev->phy.state));
+ usb_otg_state_string(fsl_otg_dev->phy.state));
size -= t;
next += t;
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/phy/phy-fsl-usb.h
index ca266280895d..ca266280895d 100644
--- a/drivers/usb/otg/fsl_otg.h
+++ b/drivers/usb/phy/phy-fsl-usb.h
diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/phy/phy-fsm-usb.c
index ade131a8ae5e..c520b3548e7c 100644
--- a/drivers/usb/otg/otg_fsm.c
+++ b/drivers/usb/phy/phy-fsm-usb.c
@@ -29,7 +29,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
-#include "otg_fsm.h"
+#include "phy-otg-fsm.h"
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
@@ -119,7 +119,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
state_changed = 1;
if (fsm->otg->phy->state == new_state)
return 0;
- VDBG("Set state: %s\n", otg_state_string(new_state));
+ VDBG("Set state: %s\n", usb_otg_state_string(new_state));
otg_leave_state(fsm, fsm->otg->phy->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/phy/phy-fsm-usb.h
index c30a2e1d9e46..c30a2e1d9e46 100644
--- a/drivers/usb/otg/otg_fsm.h
+++ b/drivers/usb/phy/phy-fsm-usb.h
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index a7d4ac591982..4c76074e518d 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -61,6 +61,7 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
{
struct regulator *vbus_draw = gpio_vbus->vbus_draw;
int enabled;
+ int ret;
if (!vbus_draw)
return;
@@ -69,12 +70,16 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
if (mA) {
regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
if (!enabled) {
- regulator_enable(vbus_draw);
+ ret = regulator_enable(vbus_draw);
+ if (ret < 0)
+ return;
gpio_vbus->vbus_draw_enabled = 1;
}
} else {
if (enabled) {
- regulator_disable(vbus_draw);
+ ret = regulator_disable(vbus_draw);
+ if (ret < 0)
+ return;
gpio_vbus->vbus_draw_enabled = 0;
}
}
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/phy/phy-isp1301-omap.c
index af9cb11626b2..ae481afcb3ec 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/phy/phy-isp1301-omap.c
@@ -236,7 +236,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
static inline const char *state_name(struct isp1301 *isp)
{
- return otg_state_string(isp->phy.state);
+ return usb_otg_state_string(isp->phy.state);
}
/*-------------------------------------------------------------------------*/
@@ -481,7 +481,7 @@ static void check_state(struct isp1301 *isp, const char *tag)
if (isp->phy.state == state && !extra)
return;
pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
- otg_state_string(state), fsm, state_name(isp),
+ usb_otg_state_string(state), fsm, state_name(isp),
omap_readl(OTG_CTRL));
}
@@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
if (state != isp->phy.state)
pr_debug(" isp, %s -> %s\n",
- otg_state_string(state), state_name(isp));
+ usb_otg_state_string(state), state_name(isp));
#ifdef CONFIG_USB_OTG
/* update the OTG controller state to match the isp1301; may
@@ -1212,7 +1212,7 @@ static void isp1301_release(struct device *dev)
static struct isp1301 *the_transceiver;
-static int __exit isp1301_remove(struct i2c_client *i2c)
+static int isp1301_remove(struct i2c_client *i2c)
{
struct isp1301 *isp;
@@ -1634,7 +1634,7 @@ static struct i2c_driver isp1301_driver = {
.name = "isp1301_omap",
},
.probe = isp1301_probe,
- .remove = __exit_p(isp1301_remove),
+ .remove = isp1301_remove,
.id_table = isp1301_id,
};
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
new file mode 100644
index 000000000000..225ae6c97eeb
--- /dev/null
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -0,0 +1,162 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/isp1301.h>
+
+#define DRV_NAME "isp1301"
+
+struct isp1301 {
+ struct usb_phy phy;
+ struct mutex mutex;
+
+ struct i2c_client *client;
+};
+
+#define phy_to_isp(p) (container_of((p), struct isp1301, phy))
+
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301", 0 },
+ { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear)
+{
+ return i2c_smbus_write_byte_data(isp->client, reg | clear, value);
+}
+
+static int isp1301_write(struct isp1301 *isp, u8 reg, u8 value)
+{
+ return __isp1301_write(isp, reg, value, 0);
+}
+
+static int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value)
+{
+ return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR);
+}
+
+static int isp1301_phy_init(struct usb_phy *phy)
+{
+ struct isp1301 *isp = phy_to_isp(phy);
+
+ /* Disable transparent UART mode first */
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN);
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, ~MC1_SPEED_REG);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
+ isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, ~0);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_PSW_EN
+ | MC2_SPD_SUSP_CTRL));
+
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, ~0);
+ isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
+ isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLDOWN
+ | OTG1_DP_PULLDOWN));
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLUP
+ | OTG1_DP_PULLUP));
+
+ /* mask all interrupts */
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, ~0);
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, ~0);
+ isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, ~0);
+
+ return 0;
+}
+
+static int isp1301_phy_set_vbus(struct usb_phy *phy, int on)
+{
+ struct isp1301 *isp = phy_to_isp(phy);
+
+ if (on)
+ isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+ else
+ isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+
+ return 0;
+}
+
+static int isp1301_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ struct isp1301 *isp;
+ struct usb_phy *phy;
+
+ isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->client = client;
+ mutex_init(&isp->mutex);
+
+ phy = &isp->phy;
+ phy->label = DRV_NAME;
+ phy->init = isp1301_phy_init;
+ phy->set_vbus = isp1301_phy_set_vbus;
+ phy->type = USB_PHY_TYPE_USB2;
+
+ i2c_set_clientdata(client, isp);
+ usb_add_phy_dev(phy);
+
+ isp1301_i2c_client = client;
+
+ return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+ struct isp1301 *isp = i2c_get_clientdata(client);
+
+ usb_remove_phy(&isp->phy);
+ isp1301_i2c_client = NULL;
+
+ return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .probe = isp1301_probe,
+ .remove = isp1301_remove,
+ .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return (dev->of_node == node) &&
+ (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+ if (node) { /* reference of ISP1301 I2C node via DT */
+ struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+ node, match);
+ if (!dev)
+ return NULL;
+ return to_i2c_client(dev);
+ } else { /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
+ }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/phy/phy-msm-usb.c
index 749fbf41fb6f..749fbf41fb6f 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/phy/phy-msm-usb.c
diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/phy-mv-u3d-usb.c
index 9d8599122aa9..f7838a43347c 100644
--- a/drivers/usb/phy/mv_u3d_phy.c
+++ b/drivers/usb/phy/phy-mv-u3d-usb.c
@@ -15,7 +15,7 @@
#include <linux/usb/otg.h>
#include <linux/platform_data/mv_usb.h>
-#include "mv_u3d_phy.h"
+#include "phy-mv-u3d-usb.h"
/*
* struct mv_u3d_phy - transceiver driver state
@@ -313,7 +313,7 @@ err:
return ret;
}
-static int __exit mv_u3d_phy_remove(struct platform_device *pdev)
+static int mv_u3d_phy_remove(struct platform_device *pdev)
{
struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev);
diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/phy-mv-u3d-usb.h
index 2a658cb9a527..2a658cb9a527 100644
--- a/drivers/usb/phy/mv_u3d_phy.h
+++ b/drivers/usb/phy/phy-mv-u3d-usb.h
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/phy/phy-mv-usb.c
index b6a9be31133b..c987bbe27851 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -27,7 +27,7 @@
#include <linux/usb/hcd.h>
#include <linux/platform_data/mv_usb.h>
-#include "mv_otg.h"
+#include "phy-mv-usb.h"
#define DRIVER_DESC "Marvell USB OTG transceiver driver"
#define DRIVER_VERSION "Jan 20, 2010"
@@ -237,18 +237,12 @@ static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
static void otg_clock_enable(struct mv_otg *mvotg)
{
- unsigned int i;
-
- for (i = 0; i < mvotg->clknum; i++)
- clk_prepare_enable(mvotg->clk[i]);
+ clk_prepare_enable(mvotg->clk);
}
static void otg_clock_disable(struct mv_otg *mvotg)
{
- unsigned int i;
-
- for (i = 0; i < mvotg->clknum; i++)
- clk_disable_unprepare(mvotg->clk[i]);
+ clk_disable_unprepare(mvotg->clk);
}
static int mv_otg_enable_internal(struct mv_otg *mvotg)
@@ -684,16 +678,14 @@ static int mv_otg_probe(struct platform_device *pdev)
struct mv_otg *mvotg;
struct usb_otg *otg;
struct resource *r;
- int retval = 0, clk_i, i;
- size_t size;
+ int retval = 0, i;
if (pdata == NULL) {
dev_err(&pdev->dev, "failed to get platform data\n");
return -ENODEV;
}
- size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
- mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL);
if (!mvotg) {
dev_err(&pdev->dev, "failed to allocate memory!\n");
return -ENOMEM;
@@ -708,15 +700,9 @@ static int mv_otg_probe(struct platform_device *pdev)
mvotg->pdev = pdev;
mvotg->pdata = pdata;
- mvotg->clknum = pdata->clknum;
- for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
- mvotg->clk[clk_i] = devm_clk_get(&pdev->dev,
- pdata->clkname[clk_i]);
- if (IS_ERR(mvotg->clk[clk_i])) {
- retval = PTR_ERR(mvotg->clk[clk_i]);
- return retval;
- }
- }
+ mvotg->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mvotg->clk))
+ return PTR_ERR(mvotg->clk);
mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
if (!mvotg->qwork) {
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/phy/phy-mv-usb.h
index 8a9e351b36ba..551da6eb0ba8 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/phy/phy-mv-usb.h
@@ -158,8 +158,7 @@ struct mv_otg {
unsigned int active;
unsigned int clock_gating;
- unsigned int clknum;
- struct clk *clk[0];
+ struct clk *clk;
};
#endif
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/phy/phy-mxs-usb.c
index b0d9f119c749..9d4381e64d51 100644
--- a/drivers/usb/otg/mxs-phy.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -48,12 +48,12 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy)
stmp_reset_block(base + HW_USBPHY_CTRL);
/* Power up the PHY */
- writel_relaxed(0, base + HW_USBPHY_PWD);
+ writel(0, base + HW_USBPHY_PWD);
/* enable FS/LS device */
- writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 |
- BM_USBPHY_CTRL_ENUTMILEVEL3,
- base + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_ENUTMILEVEL2 |
+ BM_USBPHY_CTRL_ENUTMILEVEL3,
+ base + HW_USBPHY_CTRL_SET);
}
static int mxs_phy_init(struct usb_phy *phy)
@@ -70,8 +70,8 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- phy->io_priv + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ phy->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
}
@@ -81,15 +81,15 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
struct mxs_phy *mxs_phy = to_mxs_phy(x);
if (suspend) {
- writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- x->io_priv + HW_USBPHY_CTRL_SET);
+ writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
} else {
clk_prepare_enable(mxs_phy->clk);
- writel_relaxed(BM_USBPHY_CTRL_CLKGATE,
- x->io_priv + HW_USBPHY_CTRL_CLR);
- writel_relaxed(0, x->io_priv + HW_USBPHY_PWD);
+ writel(BM_USBPHY_CTRL_CLKGATE,
+ x->io_priv + HW_USBPHY_CTRL_CLR);
+ writel(0, x->io_priv + HW_USBPHY_PWD);
}
return 0;
@@ -102,8 +102,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy,
(speed == USB_SPEED_HIGH) ? "high" : "non-high");
if (speed == USB_SPEED_HIGH)
- writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- phy->io_priv + HW_USBPHY_CTRL_SET);
+ writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_SET);
return 0;
}
@@ -115,8 +115,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
(speed == USB_SPEED_HIGH) ? "high" : "non-high");
if (speed == USB_SPEED_HIGH)
- writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- phy->io_priv + HW_USBPHY_CTRL_CLR);
+ writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ phy->io_priv + HW_USBPHY_CTRL_CLR);
return 0;
}
@@ -127,6 +127,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
void __iomem *base;
struct clk *clk;
struct mxs_phy *mxs_phy;
+ int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -166,11 +167,19 @@ static int mxs_phy_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &mxs_phy->phy);
+ ret = usb_add_phy_dev(&mxs_phy->phy);
+ if (ret)
+ return ret;
+
return 0;
}
static int mxs_phy_remove(struct platform_device *pdev)
{
+ struct mxs_phy *mxs_phy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&mxs_phy->phy);
+
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/phy/phy-nop.c
index a3ce24b94a73..2b10cc969bbb 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/phy/phy-nop.c
@@ -32,10 +32,16 @@
#include <linux/usb/otg.h>
#include <linux/usb/nop-usb-xceiv.h>
#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
struct nop_usb_xceiv {
- struct usb_phy phy;
- struct device *dev;
+ struct usb_phy phy;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *vcc;
+ struct regulator *reset;
};
static struct platform_device *pd;
@@ -64,6 +70,46 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
return 0;
}
+static int nop_init(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_enable(nop->vcc))
+ dev_err(phy->dev, "Failed to enable power\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_enable(nop->clk);
+
+ if (!IS_ERR(nop->reset)) {
+ /* De-assert RESET */
+ if (regulator_enable(nop->reset))
+ dev_err(phy->dev, "Failed to de-assert reset\n");
+ }
+
+ return 0;
+}
+
+static void nop_shutdown(struct usb_phy *phy)
+{
+ struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev);
+
+ if (!IS_ERR(nop->reset)) {
+ /* Assert RESET */
+ if (regulator_disable(nop->reset))
+ dev_err(phy->dev, "Failed to assert reset\n");
+ }
+
+ if (!IS_ERR(nop->clk))
+ clk_disable(nop->clk);
+
+ if (!IS_ERR(nop->vcc)) {
+ if (regulator_disable(nop->vcc))
+ dev_err(phy->dev, "Failed to disable power\n");
+ }
+}
+
static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
if (!otg)
@@ -95,39 +141,96 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
static int nop_usb_xceiv_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data;
struct nop_usb_xceiv *nop;
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
+ u32 clk_rate = 0;
+ bool needs_vcc = false;
+ bool needs_reset = false;
- nop = kzalloc(sizeof *nop, GFP_KERNEL);
+ nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL);
if (!nop)
return -ENOMEM;
- nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL);
- if (!nop->phy.otg) {
- kfree(nop);
+ nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg),
+ GFP_KERNEL);
+ if (!nop->phy.otg)
return -ENOMEM;
- }
- if (pdata)
+ if (dev->of_node) {
+ struct device_node *node = dev->of_node;
+
+ if (of_property_read_u32(node, "clock-frequency", &clk_rate))
+ clk_rate = 0;
+
+ needs_vcc = of_property_read_bool(node, "vcc-supply");
+ needs_reset = of_property_read_bool(node, "reset-supply");
+
+ } else if (pdata) {
type = pdata->type;
+ clk_rate = pdata->clk_rate;
+ needs_vcc = pdata->needs_vcc;
+ needs_reset = pdata->needs_reset;
+ }
+
+ nop->clk = devm_clk_get(&pdev->dev, "main_clk");
+ if (IS_ERR(nop->clk)) {
+ dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n",
+ PTR_ERR(nop->clk));
+ }
+
+ if (!IS_ERR(nop->clk) && clk_rate) {
+ err = clk_set_rate(nop->clk, clk_rate);
+ if (err) {
+ dev_err(&pdev->dev, "Error setting clock rate\n");
+ return err;
+ }
+ }
+
+ if (!IS_ERR(nop->clk)) {
+ err = clk_prepare(nop->clk);
+ if (err) {
+ dev_err(&pdev->dev, "Error preparing clock\n");
+ return err;
+ }
+ }
+
+ nop->vcc = devm_regulator_get(&pdev->dev, "vcc");
+ if (IS_ERR(nop->vcc)) {
+ dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n",
+ PTR_ERR(nop->vcc));
+ if (needs_vcc)
+ return -EPROBE_DEFER;
+ }
+
+ nop->reset = devm_regulator_get(&pdev->dev, "reset");
+ if (IS_ERR(nop->reset)) {
+ dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n",
+ PTR_ERR(nop->reset));
+ if (needs_reset)
+ return -EPROBE_DEFER;
+ }
nop->dev = &pdev->dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
nop->phy.set_suspend = nop_set_suspend;
+ nop->phy.init = nop_init;
+ nop->phy.shutdown = nop_shutdown;
nop->phy.state = OTG_STATE_UNDEFINED;
+ nop->phy.type = type;
nop->phy.otg->phy = &nop->phy;
nop->phy.otg->set_host = nop_set_host;
nop->phy.otg->set_peripheral = nop_set_peripheral;
- err = usb_add_phy(&nop->phy, type);
+ err = usb_add_phy_dev(&nop->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
- goto exit;
+ goto err_add;
}
platform_set_drvdata(pdev, nop);
@@ -135,9 +238,10 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
return 0;
-exit:
- kfree(nop->phy.otg);
- kfree(nop);
+
+err_add:
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
return err;
}
@@ -145,21 +249,30 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev)
{
struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
+ if (!IS_ERR(nop->clk))
+ clk_unprepare(nop->clk);
+
usb_remove_phy(&nop->phy);
platform_set_drvdata(pdev, NULL);
- kfree(nop->phy.otg);
- kfree(nop);
return 0;
}
+static const struct of_device_id nop_xceiv_dt_ids[] = {
+ { .compatible = "usb-nop-xceiv" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids);
+
static struct platform_driver nop_usb_xceiv_driver = {
.probe = nop_usb_xceiv_probe,
.remove = nop_usb_xceiv_remove,
.driver = {
.name = "nop_usb_xceiv",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(nop_xceiv_dt_ids),
},
};
diff --git a/drivers/usb/phy/omap-control-usb.c b/drivers/usb/phy/phy-omap-control.c
index 1419ceda9759..1419ceda9759 100644
--- a/drivers/usb/phy/omap-control-usb.c
+++ b/drivers/usb/phy/phy-omap-control.c
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c
index 844ab68f08d0..844ab68f08d0 100644
--- a/drivers/usb/phy/omap-usb2.c
+++ b/drivers/usb/phy/phy-omap-usb2.c
diff --git a/drivers/usb/phy/omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c
index a6e60b1e102e..a6e60b1e102e 100644
--- a/drivers/usb/phy/omap-usb3.c
+++ b/drivers/usb/phy/phy-omap-usb3.c
diff --git a/drivers/usb/phy/rcar-phy.c b/drivers/usb/phy/phy-rcar-usb.c
index a35681b0c501..a35681b0c501 100644
--- a/drivers/usb/phy/rcar-phy.c
+++ b/drivers/usb/phy/phy-rcar-usb.c
diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c
new file mode 100644
index 000000000000..7b118ee5f5e4
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb.c
@@ -0,0 +1,236 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB-PHY helper driver with common function calls;
+ * interacts with Samsung USB 2.0 PHY controller driver and later
+ * with Samsung USB 3.0 PHY driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/usb/samsung_usb_phy.h>
+
+#include "phy-samsung-usb.h"
+
+int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
+{
+ struct device_node *usbphy_sys;
+
+ /* Getting node for system controller interface for usb-phy */
+ usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
+ if (!usbphy_sys) {
+ dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
+ return -ENODEV;
+ }
+
+ sphy->pmuregs = of_iomap(usbphy_sys, 0);
+
+ if (sphy->pmuregs == NULL) {
+ dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
+ goto err0;
+ }
+
+ sphy->sysreg = of_iomap(usbphy_sys, 1);
+
+ /*
+ * Not returning error code here, since this situation is not fatal.
+ * Few SoCs may not have this switch available
+ */
+ if (sphy->sysreg == NULL)
+ dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
+
+ of_node_put(usbphy_sys);
+
+ return 0;
+
+err0:
+ of_node_put(usbphy_sys);
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
+
+/*
+ * Set isolation here for phy.
+ * Here 'on = true' would mean USB PHY block is isolated, hence
+ * de-activated and vice-versa.
+ */
+void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
+{
+ void __iomem *reg = NULL;
+ u32 reg_val;
+ u32 en_mask = 0;
+
+ if (!sphy->pmuregs) {
+ dev_warn(sphy->dev, "Can't set pmu isolation\n");
+ return;
+ }
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ /*
+ * Do nothing: We will add here once S3C64xx goes for DT support
+ */
+ break;
+ case TYPE_EXYNOS4210:
+ /*
+ * Fall through since exynos4210 and exynos5250 have similar
+ * register architecture: two separate registers for host and
+ * device phy control with enable bit at position 0.
+ */
+ case TYPE_EXYNOS5250:
+ if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
+ reg = sphy->pmuregs +
+ sphy->drv_data->devphy_reg_offset;
+ en_mask = sphy->drv_data->devphy_en_mask;
+ } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+ reg = sphy->pmuregs +
+ sphy->drv_data->hostphy_reg_offset;
+ en_mask = sphy->drv_data->hostphy_en_mask;
+ }
+ break;
+ default:
+ dev_err(sphy->dev, "Invalid SoC type\n");
+ return;
+ }
+
+ reg_val = readl(reg);
+
+ if (on)
+ reg_val &= ~en_mask;
+ else
+ reg_val |= en_mask;
+
+ writel(reg_val, reg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation);
+
+/*
+ * Configure the mode of working of usb-phy here: HOST/DEVICE.
+ */
+void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
+{
+ u32 reg;
+
+ if (!sphy->sysreg) {
+ dev_warn(sphy->dev, "Can't configure specified phy mode\n");
+ return;
+ }
+
+ reg = readl(sphy->sysreg);
+
+ if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
+ reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
+ else if (sphy->phy_type == USB_PHY_TYPE_HOST)
+ reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
+
+ writel(reg, sphy->sysreg);
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
+
+/*
+ * PHYs are different for USB Device and USB Host.
+ * This make sure that correct PHY type is selected before
+ * any operation on PHY.
+ */
+int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type)
+{
+ struct samsung_usbphy *sphy = phy_to_sphy(phy);
+
+ sphy->phy_type = phy_type;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
+
+/*
+ * Returns reference clock frequency selection value
+ */
+int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
+{
+ struct clk *ref_clk;
+ int refclk_freq = 0;
+
+ /*
+ * In exynos5250 USB host and device PHY use
+ * external crystal clock XXTI
+ */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ ref_clk = devm_clk_get(sphy->dev, "ext_xtal");
+ else
+ ref_clk = devm_clk_get(sphy->dev, "xusbxti");
+ if (IS_ERR(ref_clk)) {
+ dev_err(sphy->dev, "Failed to get reference clock\n");
+ return PTR_ERR(ref_clk);
+ }
+
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
+ /* set clock frequency for PLL */
+ switch (clk_get_rate(ref_clk)) {
+ case 9600 * KHZ:
+ refclk_freq = FSEL_CLKSEL_9600K;
+ break;
+ case 10 * MHZ:
+ refclk_freq = FSEL_CLKSEL_10M;
+ break;
+ case 12 * MHZ:
+ refclk_freq = FSEL_CLKSEL_12M;
+ break;
+ case 19200 * KHZ:
+ refclk_freq = FSEL_CLKSEL_19200K;
+ break;
+ case 20 * MHZ:
+ refclk_freq = FSEL_CLKSEL_20M;
+ break;
+ case 50 * MHZ:
+ refclk_freq = FSEL_CLKSEL_50M;
+ break;
+ case 24 * MHZ:
+ default:
+ /* default reference clock */
+ refclk_freq = FSEL_CLKSEL_24M;
+ break;
+ }
+ } else {
+ switch (clk_get_rate(ref_clk)) {
+ case 12 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ case 48 * MHZ:
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ break;
+ default:
+ if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
+ refclk_freq = PHYCLK_CLKSEL_48M;
+ else
+ refclk_freq = PHYCLK_CLKSEL_24M;
+ break;
+ }
+ }
+ clk_put(ref_clk);
+
+ return refclk_freq;
+}
+EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);
diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h
new file mode 100644
index 000000000000..70a9cae5e37f
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb.h
@@ -0,0 +1,327 @@
+/* linux/drivers/usb/phy/phy-samsung-usb.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Samsung USB-PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * 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/usb/phy.h>
+
+/* Register definitions */
+
+#define SAMSUNG_PHYPWR (0x00)
+
+#define PHYPWR_NORMAL_MASK (0x19 << 0)
+#define PHYPWR_OTG_DISABLE (0x1 << 4)
+#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
+#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
+/* For Exynos4 */
+#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
+#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
+
+#define SAMSUNG_PHYCLK (0x04)
+
+#define PHYCLK_MODE_USB11 (0x1 << 6)
+#define PHYCLK_EXT_OSC (0x1 << 5)
+#define PHYCLK_COMMON_ON_N (0x1 << 4)
+#define PHYCLK_ID_PULL (0x1 << 2)
+#define PHYCLK_CLKSEL_MASK (0x3 << 0)
+#define PHYCLK_CLKSEL_48M (0x0 << 0)
+#define PHYCLK_CLKSEL_12M (0x2 << 0)
+#define PHYCLK_CLKSEL_24M (0x3 << 0)
+
+#define SAMSUNG_RSTCON (0x08)
+
+#define RSTCON_PHYLINK_SWRST (0x1 << 2)
+#define RSTCON_HLINK_SWRST (0x1 << 1)
+#define RSTCON_SWRST (0x1 << 0)
+
+/* EXYNOS5 */
+#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
+
+#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
+
+#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
+#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
+#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
+#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
+
+#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
+#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
+
+#define FSEL_CLKSEL_50M (0x7)
+#define FSEL_CLKSEL_24M (0x5)
+#define FSEL_CLKSEL_20M (0x4)
+#define FSEL_CLKSEL_19200K (0x3)
+#define FSEL_CLKSEL_12M (0x2)
+#define FSEL_CLKSEL_10M (0x1)
+#define FSEL_CLKSEL_9600K (0x0)
+
+#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
+#define HOST_CTRL0_RETENABLE (0x1 << 10)
+#define HOST_CTRL0_COMMONON_N (0x1 << 9)
+#define HOST_CTRL0_SIDDQ (0x1 << 6)
+#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
+#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
+#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
+#define HOST_CTRL0_UTMISWRST (0x1 << 2)
+#define HOST_CTRL0_LINKSWRST (0x1 << 1)
+#define HOST_CTRL0_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
+
+#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
+
+#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
+
+#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
+
+#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
+
+#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
+#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
+
+#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
+#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
+#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
+#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
+#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
+#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
+#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
+
+#define HSIC_CTRL_SIDDQ (0x1 << 6)
+#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
+#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
+#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
+#define HSIC_CTRL_UTMISWRST (0x1 << 2)
+#define HSIC_CTRL_PHYSWRST (0x1 << 0)
+
+#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
+
+#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
+#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
+#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
+#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
+
+#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
+
+#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
+#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
+#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
+#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_SYS (0x38)
+
+#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
+#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
+#define OTG_SYS_PHY0_SWRST (0x1 << 12)
+
+#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
+#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
+#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
+#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
+
+#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
+#define OTG_SYS_COMMON_ON (0x1 << 7)
+
+#define OTG_SYS_FSEL_MASK (0x7 << 4)
+#define OTG_SYS_FSEL(_x) ((_x) << 4)
+
+#define OTG_SYS_FORCESLEEP (0x1 << 3)
+#define OTG_SYS_OTGDISABLE (0x1 << 2)
+#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
+#define OTG_SYS_FORCESUSPEND (0x1 << 0)
+
+#define EXYNOS5_PHY_OTG_TUNE (0x40)
+
+/* EXYNOS5: USB 3.0 DRD */
+#define EXYNOS5_DRD_LINKSYSTEM (0x04)
+
+#define LINKSYSTEM_FLADJ_MASK (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x) ((_x) << 1)
+#define LINKSYSTEM_XHCI_VERSION_CONTROL (0x1 << 27)
+
+#define EXYNOS5_DRD_PHYUTMI (0x08)
+
+#define PHYUTMI_OTGDISABLE (0x1 << 6)
+#define PHYUTMI_FORCESUSPEND (0x1 << 1)
+#define PHYUTMI_FORCESLEEP (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYPIPE (0x0c)
+
+#define EXYNOS5_DRD_PHYCLKRST (0x10)
+
+#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23)
+
+#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21)
+
+#define PHYCLKRST_SSC_EN (0x1 << 20)
+#define PHYCLKRST_REF_SSP_EN (0x1 << 19)
+#define PHYCLKRST_REF_CLKDIV2 (0x1 << 18)
+
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x02 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
+
+#define PHYCLKRST_FSEL_MASK (0x3f << 5)
+#define PHYCLKRST_FSEL(_x) ((_x) << 5)
+#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5)
+#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5)
+#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5)
+#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5)
+
+#define PHYCLKRST_RETENABLEN (0x1 << 4)
+
+#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2)
+#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2)
+
+#define PHYCLKRST_PORTRESET (0x1 << 1)
+#define PHYCLKRST_COMMONONN (0x1 << 0)
+
+#define EXYNOS5_DRD_PHYREG0 (0x14)
+#define EXYNOS5_DRD_PHYREG1 (0x18)
+
+#define EXYNOS5_DRD_PHYPARAM0 (0x1c)
+
+#define PHYPARAM0_REF_USE_PAD (0x1 << 31)
+#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26)
+
+#define EXYNOS5_DRD_PHYPARAM1 (0x20)
+
+#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH (0x1c)
+
+#define EXYNOS5_DRD_PHYTERM (0x24)
+
+#define EXYNOS5_DRD_PHYTEST (0x28)
+
+#define PHYTEST_POWERDOWN_SSP (0x1 << 3)
+#define PHYTEST_POWERDOWN_HSP (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYADP (0x2c)
+
+#define EXYNOS5_DRD_PHYBATCHG (0x30)
+
+#define PHYBATCHG_UTMI_CLKSEL (0x1 << 2)
+
+#define EXYNOS5_DRD_PHYRESUME (0x34)
+#define EXYNOS5_DRD_LINKPORT (0x44)
+
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+
+#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
+#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
+#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
+#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
+
+enum samsung_cpu_type {
+ TYPE_S3C64XX,
+ TYPE_EXYNOS4210,
+ TYPE_EXYNOS5250,
+};
+
+/*
+ * struct samsung_usbphy_drvdata - driver data for various SoC variants
+ * @cpu_type: machine identifier
+ * @devphy_en_mask: device phy enable mask for PHY CONTROL register
+ * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
+ * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
+ * mapped address of system controller.
+ * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
+ * mapped address of system controller.
+ *
+ * Here we have a separate mask for device type phy.
+ * Having different masks for host and device type phy helps
+ * in setting independent masks in case of SoCs like S5PV210,
+ * in which PHY0 and PHY1 enable bits belong to same register
+ * placed at position 0 and 1 respectively.
+ * Although for newer SoCs like exynos these bits belong to
+ * different registers altogether placed at position 0.
+ */
+struct samsung_usbphy_drvdata {
+ int cpu_type;
+ int devphy_en_mask;
+ int hostphy_en_mask;
+ u32 devphy_reg_offset;
+ u32 hostphy_reg_offset;
+};
+
+/*
+ * struct samsung_usbphy - transceiver driver state
+ * @phy: transceiver structure
+ * @plat: platform data
+ * @dev: The parent device supplied to the probe function
+ * @clk: usb phy clock
+ * @regs: usb phy controller registers memory base
+ * @pmuregs: USB device PHY_CONTROL register memory base
+ * @sysreg: USB2.0 PHY_CFG register memory base
+ * @ref_clk_freq: reference clock frequency selection
+ * @drv_data: driver data available for different SoCs
+ * @phy_type: Samsung SoCs specific phy types: #HOST
+ * #DEVICE
+ * @phy_usage: usage count for phy
+ * @lock: lock for phy operations
+ */
+struct samsung_usbphy {
+ struct usb_phy phy;
+ struct samsung_usbphy_data *plat;
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *regs;
+ void __iomem *pmuregs;
+ void __iomem *sysreg;
+ int ref_clk_freq;
+ const struct samsung_usbphy_drvdata *drv_data;
+ enum samsung_usb_phy_type phy_type;
+ atomic_t phy_usage;
+ spinlock_t lock;
+};
+
+#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
+
+static const struct of_device_id samsung_usbphy_dt_match[];
+
+static inline const struct samsung_usbphy_drvdata
+*samsung_usbphy_get_driver_data(struct platform_device *pdev)
+{
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(samsung_usbphy_dt_match,
+ pdev->dev.of_node);
+ return match->data;
+ }
+
+ return (struct samsung_usbphy_drvdata *)
+ platform_get_device_id(pdev)->driver_data;
+}
+
+extern int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy);
+extern void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on);
+extern void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy);
+extern int samsung_usbphy_set_type(struct usb_phy *phy,
+ enum samsung_usb_phy_type phy_type);
+extern int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy);
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
new file mode 100644
index 000000000000..45ffe036dacc
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb2.c
@@ -0,0 +1,509 @@
+/* linux/drivers/usb/phy/phy-samsung-usb2.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Praveen Paneri <p.paneri@samsung.com>
+ *
+ * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
+ * OHCI-EXYNOS controllers.
+ *
+ * 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ if (!otg)
+ return -ENODEV;
+
+ if (!otg->host)
+ otg->host = host;
+
+ return 0;
+}
+
+static bool exynos5_phyhost_is_on(void __iomem *regs)
+{
+ u32 reg;
+
+ reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ return !(reg & HOST_CTRL0_SIDDQ);
+}
+
+static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyclk = sphy->ref_clk_freq;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+ u32 ehcictrl;
+ u32 ohcictrl;
+
+ /*
+ * phy_usage helps in keeping usage count for phy
+ * so that the first consumer enabling the phy is also
+ * the last consumer to disable it.
+ */
+
+ atomic_inc(&sphy->phy_usage);
+
+ if (exynos5_phyhost_is_on(regs)) {
+ dev_info(sphy->dev, "Already power on PHY\n");
+ return;
+ }
+
+ /* Host configuration */
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* phy reference clock configuration */
+ phyhost &= ~HOST_CTRL0_FSEL_MASK;
+ phyhost |= HOST_CTRL0_FSEL(phyclk);
+
+ /* host phy reset */
+ phyhost &= ~(HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL |
+ HOST_CTRL0_SIDDQ |
+ /* Enable normal mode of operation */
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP);
+
+ /* Link reset */
+ phyhost |= (HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST |
+ /* COMMON Block configuration during suspend */
+ HOST_CTRL0_COMMONON_N);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+ udelay(10);
+ phyhost &= ~(HOST_CTRL0_LINKSWRST |
+ HOST_CTRL0_UTMISWRST);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ /* OTG configuration */
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* phy reference clock configuration */
+ phyotg &= ~OTG_SYS_FSEL_MASK;
+ phyotg |= OTG_SYS_FSEL(phyclk);
+
+ /* Enable normal mode of operation */
+ phyotg &= ~(OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP |
+ OTG_SYS_REFCLKSEL_MASK |
+ /* COMMON Block configuration during suspend */
+ OTG_SYS_COMMON_ON);
+
+ /* OTG phy & link reset */
+ phyotg |= (OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET |
+ OTG_SYS_OTGDISABLE |
+ /* Set phy refclk */
+ OTG_SYS_REFCLKSEL_CLKCORE);
+
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+ udelay(10);
+ phyotg &= ~(OTG_SYS_PHY0_SWRST |
+ OTG_SYS_LINKSWRST_UOTG |
+ OTG_SYS_PHYLINK_SWRESET);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+
+ /* HSIC phy configuration */
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_PHYSWRST);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+ udelay(10);
+ phyhsic &= ~HSIC_CTRL_PHYSWRST;
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ udelay(80);
+
+ /* enable EHCI DMA burst */
+ ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
+ ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
+ HOST_EHCICTRL_ENAINCR4 |
+ HOST_EHCICTRL_ENAINCR8 |
+ HOST_EHCICTRL_ENAINCR16);
+ writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
+
+ /* set ohci_suspend_on_n */
+ ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
+ ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
+ writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
+}
+
+static void samsung_usb2phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+ u32 phyclk;
+ u32 rstcon;
+
+ /* set clock frequency for PLL */
+ phyclk = sphy->ref_clk_freq;
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+ rstcon = readl(regs + SAMSUNG_RSTCON);
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ phyclk &= ~PHYCLK_COMMON_ON_N;
+ phypwr &= ~PHYPWR_NORMAL_MASK;
+ rstcon |= RSTCON_SWRST;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
+ rstcon |= RSTCON_SWRST;
+ default:
+ break;
+ }
+
+ writel(phyclk, regs + SAMSUNG_PHYCLK);
+ /* Configure PHY0 for normal operation*/
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+ /* reset all ports of PHY and Link */
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+ udelay(10);
+ rstcon &= ~RSTCON_SWRST;
+ writel(rstcon, regs + SAMSUNG_RSTCON);
+}
+
+static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyhost;
+ u32 phyotg;
+ u32 phyhsic;
+
+ if (atomic_dec_return(&sphy->phy_usage) > 0) {
+ dev_info(sphy->dev, "still being used\n");
+ return;
+ }
+
+ phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
+ HSIC_CTRL_REFCLKSEL |
+ HSIC_CTRL_SIDDQ |
+ HSIC_CTRL_FORCESLEEP |
+ HSIC_CTRL_FORCESUSPEND);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
+ writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
+
+ phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
+ phyhost |= (HOST_CTRL0_SIDDQ |
+ HOST_CTRL0_FORCESUSPEND |
+ HOST_CTRL0_FORCESLEEP |
+ HOST_CTRL0_PHYSWRST |
+ HOST_CTRL0_PHYSWRSTALL);
+ writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
+
+ phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
+ phyotg |= (OTG_SYS_FORCESUSPEND |
+ OTG_SYS_SIDDQ_UOTG |
+ OTG_SYS_FORCESLEEP);
+ writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
+}
+
+static void samsung_usb2phy_disable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phypwr;
+
+ phypwr = readl(regs + SAMSUNG_PHYPWR);
+
+ switch (sphy->drv_data->cpu_type) {
+ case TYPE_S3C64XX:
+ phypwr |= PHYPWR_NORMAL_MASK;
+ break;
+ case TYPE_EXYNOS4210:
+ phypwr |= PHYPWR_NORMAL_MASK_PHY0;
+ default:
+ break;
+ }
+
+ /* Disable analog and otg block power */
+ writel(phypwr, regs + SAMSUNG_PHYPWR);
+}
+
+/*
+ * The function passed to the usb driver for phy initialization
+ */
+static int samsung_usb2phy_init(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_bus *host = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ sphy = phy_to_sphy(phy);
+
+ host = phy->otg->host;
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ if (host) {
+ /* setting default phy-type for USB 2.0 */
+ if (!strstr(dev_name(host->controller), "ehci") ||
+ !strstr(dev_name(host->controller), "ohci"))
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+ } else {
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+ }
+
+ /* Disable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(false);
+ else
+ samsung_usbphy_set_isolation(sphy, false);
+
+ /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
+ samsung_usbphy_cfg_sel(sphy);
+
+ /* Initialize usb phy registers */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usb2phy_enable(sphy);
+ else
+ samsung_usb2phy_enable(sphy);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+
+ return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb2phy_shutdown(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_bus *host = NULL;
+ unsigned long flags;
+
+ sphy = phy_to_sphy(phy);
+
+ host = phy->otg->host;
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ if (host) {
+ /* setting default phy-type for USB 2.0 */
+ if (!strstr(dev_name(host->controller), "ehci") ||
+ !strstr(dev_name(host->controller), "ohci"))
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
+ } else {
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+ }
+
+ /* De-initialize usb phy registers */
+ if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
+ samsung_exynos5_usb2phy_disable(sphy);
+ else
+ samsung_usb2phy_disable(sphy);
+
+ /* Enable phy isolation */
+ if (sphy->plat && sphy->plat->pmu_isolation)
+ sphy->plat->pmu_isolation(true);
+ else
+ samsung_usbphy_set_isolation(sphy, true);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static int samsung_usb2phy_probe(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy;
+ struct usb_otg *otg;
+ struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ const struct samsung_usbphy_drvdata *drv_data;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ struct clk *clk;
+ int ret;
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!phy_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
+ if (!otg)
+ return -ENOMEM;
+
+ drv_data = samsung_usbphy_get_driver_data(pdev);
+
+ if (drv_data->cpu_type == TYPE_EXYNOS5250)
+ clk = devm_clk_get(dev, "usbhost");
+ else
+ clk = devm_clk_get(dev, "otg");
+
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get otg clock\n");
+ return PTR_ERR(clk);
+ }
+
+ sphy->dev = dev;
+
+ if (dev->of_node) {
+ ret = samsung_usbphy_parse_dt(sphy);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (!pdata) {
+ dev_err(dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+ }
+
+ sphy->plat = pdata;
+ sphy->regs = phy_base;
+ sphy->clk = clk;
+ sphy->drv_data = drv_data;
+ sphy->phy.dev = sphy->dev;
+ sphy->phy.label = "samsung-usb2phy";
+ sphy->phy.init = samsung_usb2phy_init;
+ sphy->phy.shutdown = samsung_usb2phy_shutdown;
+ sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
+
+ sphy->phy.otg = otg;
+ sphy->phy.otg->phy = &sphy->phy;
+ sphy->phy.otg->set_host = samsung_usbphy_set_host;
+
+ spin_lock_init(&sphy->lock);
+
+ platform_set_drvdata(pdev, sphy);
+
+ return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
+}
+
+static int samsung_usb2phy_remove(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&sphy->phy);
+
+ if (sphy->pmuregs)
+ iounmap(sphy->pmuregs);
+ if (sphy->sysreg)
+ iounmap(sphy->sysreg);
+
+ return 0;
+}
+
+static const struct samsung_usbphy_drvdata usb2phy_s3c64xx = {
+ .cpu_type = TYPE_S3C64XX,
+ .devphy_en_mask = S3C64XX_USBPHY_ENABLE,
+};
+
+static const struct samsung_usbphy_drvdata usb2phy_exynos4 = {
+ .cpu_type = TYPE_EXYNOS4210,
+ .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
+ .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
+};
+
+static struct samsung_usbphy_drvdata usb2phy_exynos5 = {
+ .cpu_type = TYPE_EXYNOS5250,
+ .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
+ .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+ {
+ .compatible = "samsung,s3c64xx-usb2phy",
+ .data = &usb2phy_s3c64xx,
+ }, {
+ .compatible = "samsung,exynos4210-usb2phy",
+ .data = &usb2phy_exynos4,
+ }, {
+ .compatible = "samsung,exynos5250-usb2phy",
+ .data = &usb2phy_exynos5
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+ {
+ .name = "s3c64xx-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_s3c64xx,
+ }, {
+ .name = "exynos4210-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_exynos4,
+ }, {
+ .name = "exynos5250-usb2phy",
+ .driver_data = (unsigned long)&usb2phy_exynos5,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb2phy_driver = {
+ .probe = samsung_usb2phy_probe,
+ .remove = samsung_usb2phy_remove,
+ .id_table = samsung_usbphy_driver_ids,
+ .driver = {
+ .name = "samsung-usb2phy",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+ },
+};
+
+module_platform_driver(samsung_usb2phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 2.0 phy controller");
+MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb2phy");
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
new file mode 100644
index 000000000000..133f3d0c554f
--- /dev/null
+++ b/drivers/usb/phy/phy-samsung-usb3.c
@@ -0,0 +1,347 @@
+/* linux/drivers/usb/phy/phy-samsung-usb3.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Vivek Gautam <gautam.vivek@samsung.com>
+ *
+ * Samsung USB 3.0 PHY transceiver; talks to DWC3 controller.
+ *
+ * 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/usb/samsung_usb_phy.h>
+#include <linux/platform_data/samsung-usbphy.h>
+
+#include "phy-samsung-usb.h"
+
+/*
+ * Sets the phy clk as EXTREFCLK (XXTI) which is internal clock from clock core.
+ */
+static u32 samsung_usb3phy_set_refclk(struct samsung_usbphy *sphy)
+{
+ u32 reg;
+ u32 refclk;
+
+ refclk = sphy->ref_clk_freq;
+
+ reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK |
+ PHYCLKRST_FSEL(refclk);
+
+ switch (refclk) {
+ case FSEL_CLKSEL_50M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case FSEL_CLKSEL_20M:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x00));
+ break;
+ case FSEL_CLKSEL_19200K:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ case FSEL_CLKSEL_24M:
+ default:
+ reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+ PHYCLKRST_SSC_REFCLKSEL(0x88));
+ break;
+ }
+
+ return reg;
+}
+
+static int samsung_exynos5_usb3phy_enable(struct samsung_usbphy *sphy)
+{
+ void __iomem *regs = sphy->regs;
+ u32 phyparam0;
+ u32 phyparam1;
+ u32 linksystem;
+ u32 phybatchg;
+ u32 phytest;
+ u32 phyclkrst;
+
+ /* Reset USB 3.0 PHY */
+ writel(0x0, regs + EXYNOS5_DRD_PHYREG0);
+
+ phyparam0 = readl(regs + EXYNOS5_DRD_PHYPARAM0);
+ /* Select PHY CLK source */
+ phyparam0 &= ~PHYPARAM0_REF_USE_PAD;
+ /* Set Loss-of-Signal Detector sensitivity */
+ phyparam0 &= ~PHYPARAM0_REF_LOSLEVEL_MASK;
+ phyparam0 |= PHYPARAM0_REF_LOSLEVEL;
+ writel(phyparam0, regs + EXYNOS5_DRD_PHYPARAM0);
+
+ writel(0x0, regs + EXYNOS5_DRD_PHYRESUME);
+
+ /*
+ * Setting the Frame length Adj value[6:1] to default 0x20
+ * See xHCI 1.0 spec, 5.2.4
+ */
+ linksystem = LINKSYSTEM_XHCI_VERSION_CONTROL |
+ LINKSYSTEM_FLADJ(0x20);
+ writel(linksystem, regs + EXYNOS5_DRD_LINKSYSTEM);
+
+ phyparam1 = readl(regs + EXYNOS5_DRD_PHYPARAM1);
+ /* Set Tx De-Emphasis level */
+ phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_MASK;
+ phyparam1 |= PHYPARAM1_PCS_TXDEEMPH;
+ writel(phyparam1, regs + EXYNOS5_DRD_PHYPARAM1);
+
+ phybatchg = readl(regs + EXYNOS5_DRD_PHYBATCHG);
+ phybatchg |= PHYBATCHG_UTMI_CLKSEL;
+ writel(phybatchg, regs + EXYNOS5_DRD_PHYBATCHG);
+
+ /* PHYTEST POWERDOWN Control */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest &= ~(PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+
+ /* UTMI Power Control */
+ writel(PHYUTMI_OTGDISABLE, regs + EXYNOS5_DRD_PHYUTMI);
+
+ phyclkrst = samsung_usb3phy_set_refclk(sphy);
+
+ phyclkrst |= PHYCLKRST_PORTRESET |
+ /* Digital power supply in normal operating mode */
+ PHYCLKRST_RETENABLEN |
+ /* Enable ref clock for SS function */
+ PHYCLKRST_REF_SSP_EN |
+ /* Enable spread spectrum */
+ PHYCLKRST_SSC_EN |
+ /* Power down HS Bias and PLL blocks in suspend mode */
+ PHYCLKRST_COMMONONN;
+
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ udelay(10);
+
+ phyclkrst &= ~(PHYCLKRST_PORTRESET);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ return 0;
+}
+
+static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy)
+{
+ u32 phyutmi;
+ u32 phyclkrst;
+ u32 phytest;
+ void __iomem *regs = sphy->regs;
+
+ phyutmi = PHYUTMI_OTGDISABLE |
+ PHYUTMI_FORCESUSPEND |
+ PHYUTMI_FORCESLEEP;
+ writel(phyutmi, regs + EXYNOS5_DRD_PHYUTMI);
+
+ /* Resetting the PHYCLKRST enable bits to reduce leakage current */
+ phyclkrst = readl(regs + EXYNOS5_DRD_PHYCLKRST);
+ phyclkrst &= ~(PHYCLKRST_REF_SSP_EN |
+ PHYCLKRST_SSC_EN |
+ PHYCLKRST_COMMONONN);
+ writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST);
+
+ /* Control PHYTEST to remove leakage current */
+ phytest = readl(regs + EXYNOS5_DRD_PHYTEST);
+ phytest |= (PHYTEST_POWERDOWN_SSP |
+ PHYTEST_POWERDOWN_HSP);
+ writel(phytest, regs + EXYNOS5_DRD_PHYTEST);
+}
+
+static int samsung_usb3phy_init(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ unsigned long flags;
+ int ret = 0;
+
+ sphy = phy_to_sphy(phy);
+
+ /* Enable the phy clock */
+ ret = clk_prepare_enable(sphy->clk);
+ if (ret) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return ret;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+ /* Disable phy isolation */
+ samsung_usbphy_set_isolation(sphy, false);
+
+ /* Initialize usb phy registers */
+ samsung_exynos5_usb3phy_enable(sphy);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ /* Disable the phy clock */
+ clk_disable_unprepare(sphy->clk);
+
+ return ret;
+}
+
+/*
+ * The function passed to the usb driver for phy shutdown
+ */
+static void samsung_usb3phy_shutdown(struct usb_phy *phy)
+{
+ struct samsung_usbphy *sphy;
+ unsigned long flags;
+
+ sphy = phy_to_sphy(phy);
+
+ if (clk_prepare_enable(sphy->clk)) {
+ dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&sphy->lock, flags);
+
+ /* setting default phy-type for USB 3.0 */
+ samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
+
+ /* De-initialize usb phy registers */
+ samsung_exynos5_usb3phy_disable(sphy);
+
+ /* Enable phy isolation */
+ samsung_usbphy_set_isolation(sphy, true);
+
+ spin_unlock_irqrestore(&sphy->lock, flags);
+
+ clk_disable_unprepare(sphy->clk);
+}
+
+static int samsung_usb3phy_probe(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy;
+ struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct resource *phy_mem;
+ void __iomem *phy_base;
+ struct clk *clk;
+ int ret;
+
+ phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!phy_mem) {
+ dev_err(dev, "%s: missing mem resource\n", __func__);
+ return -ENODEV;
+ }
+
+ phy_base = devm_ioremap_resource(dev, phy_mem);
+ if (IS_ERR(phy_base))
+ return PTR_ERR(phy_base);
+
+ sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
+ if (!sphy)
+ return -ENOMEM;
+
+ clk = devm_clk_get(dev, "usbdrd30");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "Failed to get device clock\n");
+ return PTR_ERR(clk);
+ }
+
+ sphy->dev = dev;
+
+ if (dev->of_node) {
+ ret = samsung_usbphy_parse_dt(sphy);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (!pdata) {
+ dev_err(dev, "no platform data specified\n");
+ return -EINVAL;
+ }
+ }
+
+ sphy->plat = pdata;
+ sphy->regs = phy_base;
+ sphy->clk = clk;
+ sphy->phy.dev = sphy->dev;
+ sphy->phy.label = "samsung-usb3phy";
+ sphy->phy.init = samsung_usb3phy_init;
+ sphy->phy.shutdown = samsung_usb3phy_shutdown;
+ sphy->drv_data = samsung_usbphy_get_driver_data(pdev);
+ sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
+
+ spin_lock_init(&sphy->lock);
+
+ platform_set_drvdata(pdev, sphy);
+
+ return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3);
+}
+
+static int samsung_usb3phy_remove(struct platform_device *pdev)
+{
+ struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
+
+ usb_remove_phy(&sphy->phy);
+
+ if (sphy->pmuregs)
+ iounmap(sphy->pmuregs);
+ if (sphy->sysreg)
+ iounmap(sphy->sysreg);
+
+ return 0;
+}
+
+static struct samsung_usbphy_drvdata usb3phy_exynos5 = {
+ .cpu_type = TYPE_EXYNOS5250,
+ .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_usbphy_dt_match[] = {
+ {
+ .compatible = "samsung,exynos5250-usb3phy",
+ .data = &usb3phy_exynos5
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
+#endif
+
+static struct platform_device_id samsung_usbphy_driver_ids[] = {
+ {
+ .name = "exynos5250-usb3phy",
+ .driver_data = (unsigned long)&usb3phy_exynos5,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
+
+static struct platform_driver samsung_usb3phy_driver = {
+ .probe = samsung_usb3phy_probe,
+ .remove = samsung_usb3phy_remove,
+ .id_table = samsung_usbphy_driver_ids,
+ .driver = {
+ .name = "samsung-usb3phy",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
+ },
+};
+
+module_platform_driver(samsung_usb3phy_driver);
+
+MODULE_DESCRIPTION("Samsung USB 3.0 phy controller");
+MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-usb3phy");
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/phy-tegra-usb.c
index 5487d38481af..17d811292f3a 100644
--- a/drivers/usb/phy/tegra_usb_phy.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -299,7 +299,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
val &= ~USB_SUSP_SET;
writel(val, base + USB_SUSP_CTRL);
} else
- tegra_ehci_set_phcd(&phy->u_phy, true);
+ phy->set_phcd(&phy->u_phy, true);
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
@@ -321,7 +321,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
val &= ~USB_SUSP_CLR;
writel(val, base + USB_SUSP_CTRL);
} else
- tegra_ehci_set_phcd(&phy->u_phy, false);
+ phy->set_phcd(&phy->u_phy, false);
if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID))
@@ -444,7 +444,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
utmi_phy_clk_enable(phy);
if (!phy->is_legacy_phy)
- tegra_ehci_set_pts(&phy->u_phy, 0);
+ phy->set_pts(&phy->u_phy, 0);
return 0;
}
@@ -688,7 +688,10 @@ static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
}
struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode)
+ void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode,
+ void (*set_pts)(struct usb_phy *x, u8 pts_val),
+ void (*set_phcd)(struct usb_phy *x, bool enable))
+
{
struct tegra_usb_phy *phy;
unsigned long parent_rate;
@@ -707,6 +710,8 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
phy->dev = dev;
phy->is_legacy_phy =
of_property_read_bool(np, "nvidia,has-legacy-mode");
+ phy->set_pts = set_pts;
+ phy->set_phcd = set_phcd;
err = of_property_match_string(np, "phy_type", "ulpi");
if (err < 0)
phy->is_ulpi_phy = false;
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c
index a994715a3101..8f78d2d40722 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/phy/phy-twl4030-usb.c
@@ -163,6 +163,8 @@ struct twl4030_usb {
bool vbus_supplied;
u8 asleep;
bool irq_enabled;
+
+ struct delayed_work id_workaround_work;
};
/* internal define on top of container_of */
@@ -246,6 +248,25 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
/*-------------------------------------------------------------------------*/
+static bool twl4030_is_driving_vbus(struct twl4030_usb *twl)
+{
+ int ret;
+
+ ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS);
+ if (ret < 0 || !(ret & PHY_DPLL_CLK))
+ /*
+ * if clocks are off, registers are not updated,
+ * but we can assume we don't drive VBUS in this case
+ */
+ return false;
+
+ ret = twl4030_usb_read(twl, ULPI_OTG_CTRL);
+ if (ret < 0)
+ return false;
+
+ return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false;
+}
+
static enum omap_musb_vbus_id_status
twl4030_usb_linkstat(struct twl4030_usb *twl)
{
@@ -268,13 +289,19 @@ static enum omap_musb_vbus_id_status
if (status < 0)
dev_err(twl->dev, "USB link status err %d\n", status);
else if (status & (BIT(7) | BIT(2))) {
- if (status & (BIT(7)))
- twl->vbus_supplied = true;
+ if (status & BIT(7)) {
+ if (twl4030_is_driving_vbus(twl))
+ status &= ~BIT(7);
+ else
+ twl->vbus_supplied = true;
+ }
if (status & BIT(2))
linkstat = OMAP_MUSB_ID_GROUND;
- else
+ else if (status & BIT(7))
linkstat = OMAP_MUSB_VBUS_VALID;
+ else
+ linkstat = OMAP_MUSB_VBUS_OFF;
} else {
if (twl->linkstat != OMAP_MUSB_UNKNOWN)
linkstat = OMAP_MUSB_VBUS_OFF;
@@ -287,10 +314,6 @@ static enum omap_musb_vbus_id_status
* are registered, and that both are active...
*/
- spin_lock_irq(&twl->lock);
- twl->linkstat = linkstat;
- spin_unlock_irq(&twl->lock);
-
return linkstat;
}
@@ -361,9 +384,17 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on)
static void twl4030_phy_power(struct twl4030_usb *twl, int on)
{
+ int ret;
+
if (on) {
- regulator_enable(twl->usb3v1);
- regulator_enable(twl->usb1v8);
+ ret = regulator_enable(twl->usb3v1);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v1\n");
+
+ ret = regulator_enable(twl->usb1v8);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb1v8\n");
+
/*
* Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
* in twl4030) resets the VUSB_DEDICATED2 register. This reset
@@ -372,7 +403,11 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
* is re-activated. This ensures that VUSB3V1 is really active.
*/
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
- regulator_enable(twl->usb1v5);
+
+ ret = regulator_enable(twl->usb1v5);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb1v5\n");
+
__twl4030_phy_power(twl, 1);
twl4030_usb_write(twl, PHY_CLK_CTRL,
twl4030_usb_read(twl, PHY_CLK_CTRL) |
@@ -412,6 +447,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl)
__twl4030_phy_resume(twl);
twl->asleep = 0;
dev_dbg(twl->dev, "%s\n", __func__);
+
+ /*
+ * XXX When VBUS gets driven after musb goes to A mode,
+ * ID_PRES related interrupts no longer arrive, why?
+ * Register itself is updated fine though, so we must poll.
+ */
+ if (twl->linkstat == OMAP_MUSB_ID_GROUND) {
+ cancel_delayed_work(&twl->id_workaround_work);
+ schedule_delayed_work(&twl->id_workaround_work, HZ);
+ }
}
static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
@@ -432,7 +477,7 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
/* Initialize 3.1V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
- twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+ twl->usb3v1 = devm_regulator_get(twl->dev, "usb3v1");
if (IS_ERR(twl->usb3v1))
return -ENODEV;
@@ -441,18 +486,18 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
/* Initialize 1.5V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
- twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+ twl->usb1v5 = devm_regulator_get(twl->dev, "usb1v5");
if (IS_ERR(twl->usb1v5))
- goto fail1;
+ return -ENODEV;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
/* Initialize 1.8V regulator */
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
- twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+ twl->usb1v8 = devm_regulator_get(twl->dev, "usb1v8");
if (IS_ERR(twl->usb1v8))
- goto fail2;
+ return -ENODEV;
twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
@@ -461,14 +506,6 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
TWL4030_PM_MASTER_PROTECT_KEY);
return 0;
-
-fail2:
- regulator_put(twl->usb1v5);
- twl->usb1v5 = NULL;
-fail1:
- regulator_put(twl->usb3v1);
- twl->usb3v1 = NULL;
- return -ENODEV;
}
static ssize_t twl4030_usb_vbus_show(struct device *dev,
@@ -491,9 +528,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
{
struct twl4030_usb *twl = _twl;
enum omap_musb_vbus_id_status status;
+ bool status_changed = false;
status = twl4030_usb_linkstat(twl);
- if (status > 0) {
+
+ spin_lock_irq(&twl->lock);
+ if (status >= 0 && status != twl->linkstat) {
+ twl->linkstat = status;
+ status_changed = true;
+ }
+ spin_unlock_irq(&twl->lock);
+
+ if (status_changed) {
/* FIXME add a set_power() method so that B-devices can
* configure the charger appropriately. It's not always
* correct to consume VBUS power, and how much current to
@@ -505,37 +551,62 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
- if (status == OMAP_MUSB_VBUS_OFF ||
- status == OMAP_MUSB_ID_FLOAT)
- twl4030_phy_suspend(twl, 0);
- else
- twl4030_phy_resume(twl);
-
- omap_musb_mailbox(twl->linkstat);
+ omap_musb_mailbox(status);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
return IRQ_HANDLED;
}
-static void twl4030_usb_phy_init(struct twl4030_usb *twl)
+static void twl4030_id_workaround_work(struct work_struct *work)
{
+ struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
+ id_workaround_work.work);
enum omap_musb_vbus_id_status status;
+ bool status_changed = false;
status = twl4030_usb_linkstat(twl);
- if (status > 0) {
- if (status == OMAP_MUSB_VBUS_OFF ||
- status == OMAP_MUSB_ID_FLOAT) {
- __twl4030_phy_power(twl, 0);
- twl->asleep = 1;
- } else {
- __twl4030_phy_resume(twl);
- twl->asleep = 0;
- }
- omap_musb_mailbox(twl->linkstat);
+ spin_lock_irq(&twl->lock);
+ if (status >= 0 && status != twl->linkstat) {
+ twl->linkstat = status;
+ status_changed = true;
+ }
+ spin_unlock_irq(&twl->lock);
+
+ if (status_changed) {
+ dev_dbg(twl->dev, "handle missing status change to %d\n",
+ status);
+ omap_musb_mailbox(status);
}
+
+ /* don't schedule during sleep - irq works right then */
+ if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
+ cancel_delayed_work(&twl->id_workaround_work);
+ schedule_delayed_work(&twl->id_workaround_work, HZ);
+ }
+}
+
+static int twl4030_usb_phy_init(struct usb_phy *phy)
+{
+ struct twl4030_usb *twl = phy_to_twl(phy);
+ enum omap_musb_vbus_id_status status;
+
+ /*
+ * Start in sleep state, we'll get called through set_suspend()
+ * callback when musb is runtime resumed and it's time to start.
+ */
+ __twl4030_phy_power(twl, 0);
+ twl->asleep = 1;
+
+ status = twl4030_usb_linkstat(twl);
+ twl->linkstat = status;
+
+ if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
+ omap_musb_mailbox(twl->linkstat);
+
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+ return 0;
}
static int twl4030_set_suspend(struct usb_phy *x, int suspend)
@@ -612,6 +683,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->phy.otg = otg;
twl->phy.type = USB_PHY_TYPE_USB2;
twl->phy.set_suspend = twl4030_set_suspend;
+ twl->phy.init = twl4030_usb_phy_init;
otg->phy = &twl->phy;
otg->set_host = twl4030_set_host;
@@ -620,6 +692,8 @@ static int twl4030_usb_probe(struct platform_device *pdev)
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
+ INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work);
+
err = twl4030_usb_ldo_init(twl);
if (err) {
dev_err(&pdev->dev, "ldo init failed\n");
@@ -640,30 +714,25 @@ static int twl4030_usb_probe(struct platform_device *pdev)
* need both handles, otherwise just one suffices.
*/
twl->irq_enabled = true;
- status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
- IRQF_ONESHOT, "twl4030_usb", twl);
+ status = devm_request_threaded_irq(twl->dev, twl->irq, NULL,
+ twl4030_usb_irq, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl);
if (status < 0) {
dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq, status);
return status;
}
- /* Power down phy or make it work according to
- * current link state.
- */
- twl4030_usb_phy_init(twl);
-
dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
return 0;
}
-static int __exit twl4030_usb_remove(struct platform_device *pdev)
+static int twl4030_usb_remove(struct platform_device *pdev)
{
struct twl4030_usb *twl = platform_get_drvdata(pdev);
int val;
- free_irq(twl->irq, twl);
+ cancel_delayed_work(&twl->id_workaround_work);
device_remove_file(twl->dev, &dev_attr_vbus);
/* set transceiver mode to power on defaults */
@@ -685,9 +754,6 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
if (!twl->asleep)
twl4030_phy_power(twl, 0);
- regulator_put(twl->usb1v5);
- regulator_put(twl->usb1v8);
- regulator_put(twl->usb3v1);
return 0;
}
@@ -702,7 +768,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
static struct platform_driver twl4030_usb_driver = {
.probe = twl4030_usb_probe,
- .remove = __exit_p(twl4030_usb_remove),
+ .remove = twl4030_usb_remove,
.driver = {
.name = "twl4030_usb",
.owner = THIS_MODULE,
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 8cd6cf49bdbd..9de7ada90a8b 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -211,6 +211,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
struct twl6030_usb *twl = _twl;
enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
u8 vbus_state, hw_state;
+ int ret;
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
@@ -218,7 +219,10 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
CONTROLLER_STAT1);
if (!(hw_state & STS_USB_ID)) {
if (vbus_state & VBUS_DET) {
- regulator_enable(twl->usb3v3);
+ ret = regulator_enable(twl->usb3v3);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v3\n");
+
twl->asleep = 1;
status = OMAP_MUSB_VBUS_VALID;
twl->linkstat = status;
@@ -245,12 +249,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
struct twl6030_usb *twl = _twl;
enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN;
u8 hw_state;
+ int ret;
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
if (hw_state & STS_USB_ID) {
+ ret = regulator_enable(twl->usb3v3);
+ if (ret)
+ dev_err(twl->dev, "Failed to enable usb3v3\n");
- regulator_enable(twl->usb3v3);
twl->asleep = 1;
twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
@@ -393,7 +400,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)
return 0;
}
-static int __exit twl6030_usb_remove(struct platform_device *pdev)
+static int twl6030_usb_remove(struct platform_device *pdev)
{
struct twl6030_usb *twl = platform_get_drvdata(pdev);
@@ -420,7 +427,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
static struct platform_driver twl6030_usb_driver = {
.probe = twl6030_usb_probe,
- .remove = __exit_p(twl6030_usb_remove),
+ .remove = twl6030_usb_remove,
.driver = {
.name = "twl6030_usb",
.owner = THIS_MODULE,
diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/phy/phy-ulpi-viewport.c
index c5ba7e5423fc..c5ba7e5423fc 100644
--- a/drivers/usb/otg/ulpi_viewport.c
+++ b/drivers/usb/phy/phy-ulpi-viewport.c
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/phy/phy-ulpi.c
index 217339dd7a90..217339dd7a90 100644
--- a/drivers/usb/otg/ulpi.c
+++ b/drivers/usb/phy/phy-ulpi.c
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/phy/phy.c
index 2bd03d261a50..a9984c700d2c 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/phy/phy.c
@@ -1,14 +1,13 @@
/*
- * otg.c -- USB OTG utility code
+ * phy.c -- USB phy handling
*
- * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004-2013 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
-
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/err.h>
@@ -17,7 +16,7 @@
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
static LIST_HEAD(phy_list);
static LIST_HEAD(phy_bind_list);
@@ -110,7 +109,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy);
/**
* usb_get_phy - find the USB PHY
@@ -143,7 +142,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(usb_get_phy);
+EXPORT_SYMBOL_GPL(usb_get_phy);
/**
* devm_usb_get_phy_by_phandle - find the USB PHY by phandle
@@ -207,7 +206,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy_by_phandle);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle);
/**
* usb_get_phy_dev - find the USB PHY
@@ -240,7 +239,7 @@ err0:
return phy;
}
-EXPORT_SYMBOL(usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(usb_get_phy_dev);
/**
* devm_usb_get_phy_dev - find the USB PHY using device ptr and index
@@ -270,7 +269,7 @@ struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
return phy;
}
-EXPORT_SYMBOL(devm_usb_get_phy_dev);
+EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev);
/**
* devm_usb_put_phy - release the USB PHY
@@ -289,7 +288,7 @@ void devm_usb_put_phy(struct device *dev, struct usb_phy *phy)
r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy);
dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
}
-EXPORT_SYMBOL(devm_usb_put_phy);
+EXPORT_SYMBOL_GPL(devm_usb_put_phy);
/**
* usb_put_phy - release the USB PHY
@@ -308,7 +307,7 @@ void usb_put_phy(struct usb_phy *x)
module_put(owner);
}
}
-EXPORT_SYMBOL(usb_put_phy);
+EXPORT_SYMBOL_GPL(usb_put_phy);
/**
* usb_add_phy - declare the USB PHY
@@ -348,7 +347,7 @@ out:
spin_unlock_irqrestore(&phy_lock, flags);
return ret;
}
-EXPORT_SYMBOL(usb_add_phy);
+EXPORT_SYMBOL_GPL(usb_add_phy);
/**
* usb_add_phy_dev - declare the USB PHY
@@ -378,7 +377,7 @@ int usb_add_phy_dev(struct usb_phy *x)
spin_unlock_irqrestore(&phy_lock, flags);
return 0;
}
-EXPORT_SYMBOL(usb_add_phy_dev);
+EXPORT_SYMBOL_GPL(usb_add_phy_dev);
/**
* usb_remove_phy - remove the OTG PHY
@@ -400,7 +399,7 @@ void usb_remove_phy(struct usb_phy *x)
}
spin_unlock_irqrestore(&phy_lock, flags);
}
-EXPORT_SYMBOL(usb_remove_phy);
+EXPORT_SYMBOL_GPL(usb_remove_phy);
/**
* usb_bind_phy - bind the phy and the controller that uses the phy
@@ -414,7 +413,7 @@ EXPORT_SYMBOL(usb_remove_phy);
*
* To be used by platform specific initialization code.
*/
-int __init usb_bind_phy(const char *dev_name, u8 index,
+int usb_bind_phy(const char *dev_name, u8 index,
const char *phy_dev_name)
{
struct usb_phy_bind *phy_bind;
@@ -437,38 +436,3 @@ int __init usb_bind_phy(const char *dev_name, u8 index,
return 0;
}
EXPORT_SYMBOL_GPL(usb_bind_phy);
-
-const char *otg_state_string(enum usb_otg_state state)
-{
- switch (state) {
- case OTG_STATE_A_IDLE:
- return "a_idle";
- case OTG_STATE_A_WAIT_VRISE:
- return "a_wait_vrise";
- case OTG_STATE_A_WAIT_BCON:
- return "a_wait_bcon";
- case OTG_STATE_A_HOST:
- return "a_host";
- case OTG_STATE_A_SUSPEND:
- return "a_suspend";
- case OTG_STATE_A_PERIPHERAL:
- return "a_peripheral";
- case OTG_STATE_A_WAIT_VFALL:
- return "a_wait_vfall";
- case OTG_STATE_A_VBUS_ERR:
- return "a_vbus_err";
- case OTG_STATE_B_IDLE:
- return "b_idle";
- case OTG_STATE_B_SRP_INIT:
- return "b_srp_init";
- case OTG_STATE_B_PERIPHERAL:
- return "b_peripheral";
- case OTG_STATE_B_WAIT_ACON:
- return "b_wait_acon";
- case OTG_STATE_B_HOST:
- return "b_host";
- default:
- return "UNDEFINED";
- }
-}
-EXPORT_SYMBOL(otg_state_string);
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
deleted file mode 100644
index 967101ec15fd..000000000000
--- a/drivers/usb/phy/samsung-usbphy.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/* linux/drivers/usb/phy/samsung-usbphy.c
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * http://www.samsung.com
- *
- * Author: Praveen Paneri <p.paneri@samsung.com>
- *
- * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
- * OHCI-EXYNOS controllers.
- *
- * 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 <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/samsung_usb_phy.h>
-#include <linux/platform_data/samsung-usbphy.h>
-
-/* Register definitions */
-
-#define SAMSUNG_PHYPWR (0x00)
-
-#define PHYPWR_NORMAL_MASK (0x19 << 0)
-#define PHYPWR_OTG_DISABLE (0x1 << 4)
-#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
-#define PHYPWR_FORCE_SUSPEND (0x1 << 1)
-/* For Exynos4 */
-#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
-#define PHYPWR_SLEEP_PHY0 (0x1 << 5)
-
-#define SAMSUNG_PHYCLK (0x04)
-
-#define PHYCLK_MODE_USB11 (0x1 << 6)
-#define PHYCLK_EXT_OSC (0x1 << 5)
-#define PHYCLK_COMMON_ON_N (0x1 << 4)
-#define PHYCLK_ID_PULL (0x1 << 2)
-#define PHYCLK_CLKSEL_MASK (0x3 << 0)
-#define PHYCLK_CLKSEL_48M (0x0 << 0)
-#define PHYCLK_CLKSEL_12M (0x2 << 0)
-#define PHYCLK_CLKSEL_24M (0x3 << 0)
-
-#define SAMSUNG_RSTCON (0x08)
-
-#define RSTCON_PHYLINK_SWRST (0x1 << 2)
-#define RSTCON_HLINK_SWRST (0x1 << 1)
-#define RSTCON_SWRST (0x1 << 0)
-
-/* EXYNOS5 */
-#define EXYNOS5_PHY_HOST_CTRL0 (0x00)
-
-#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
-
-#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
-#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
-#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
-#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
-
-#define HOST_CTRL0_FSEL_MASK (0x7 << 16)
-#define HOST_CTRL0_FSEL(_x) ((_x) << 16)
-
-#define FSEL_CLKSEL_50M (0x7)
-#define FSEL_CLKSEL_24M (0x5)
-#define FSEL_CLKSEL_20M (0x4)
-#define FSEL_CLKSEL_19200K (0x3)
-#define FSEL_CLKSEL_12M (0x2)
-#define FSEL_CLKSEL_10M (0x1)
-#define FSEL_CLKSEL_9600K (0x0)
-
-#define HOST_CTRL0_TESTBURNIN (0x1 << 11)
-#define HOST_CTRL0_RETENABLE (0x1 << 10)
-#define HOST_CTRL0_COMMONON_N (0x1 << 9)
-#define HOST_CTRL0_SIDDQ (0x1 << 6)
-#define HOST_CTRL0_FORCESLEEP (0x1 << 5)
-#define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
-#define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
-#define HOST_CTRL0_UTMISWRST (0x1 << 2)
-#define HOST_CTRL0_LINKSWRST (0x1 << 1)
-#define HOST_CTRL0_PHYSWRST (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_TUNE0 (0x04)
-
-#define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
-
-#define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
-
-#define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
-
-#define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
-
-#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
-#define HSIC_CTRL_REFCLKSEL (0x2 << 23)
-
-#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
-#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
-#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
-#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
-#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
-#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
-#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
-
-#define HSIC_CTRL_SIDDQ (0x1 << 6)
-#define HSIC_CTRL_FORCESLEEP (0x1 << 5)
-#define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
-#define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
-#define HSIC_CTRL_UTMISWRST (0x1 << 2)
-#define HSIC_CTRL_PHYSWRST (0x1 << 0)
-
-#define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
-
-#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
-#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
-#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
-#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
-
-#define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
-
-#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
-#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
-#define HOST_OHCICTRL_CNTSEL (0x1 << 1)
-#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_SYS (0x38)
-
-#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
-#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
-#define OTG_SYS_PHY0_SWRST (0x1 << 12)
-
-#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
-#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
-#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
-#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
-
-#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
-#define OTG_SYS_COMMON_ON (0x1 << 7)
-
-#define OTG_SYS_FSEL_MASK (0x7 << 4)
-#define OTG_SYS_FSEL(_x) ((_x) << 4)
-
-#define OTG_SYS_FORCESLEEP (0x1 << 3)
-#define OTG_SYS_OTGDISABLE (0x1 << 2)
-#define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
-#define OTG_SYS_FORCESUSPEND (0x1 << 0)
-
-#define EXYNOS5_PHY_OTG_TUNE (0x40)
-
-#ifndef MHZ
-#define MHZ (1000*1000)
-#endif
-
-#ifndef KHZ
-#define KHZ (1000)
-#endif
-
-#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
-#define S3C64XX_USBPHY_ENABLE (0x1 << 16)
-#define EXYNOS_USBPHY_ENABLE (0x1 << 0)
-#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
-
-enum samsung_cpu_type {
- TYPE_S3C64XX,
- TYPE_EXYNOS4210,
- TYPE_EXYNOS5250,
-};
-
-/*
- * struct samsung_usbphy_drvdata - driver data for various SoC variants
- * @cpu_type: machine identifier
- * @devphy_en_mask: device phy enable mask for PHY CONTROL register
- * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
- * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
- * mapped address of system controller.
- * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
- * mapped address of system controller.
- *
- * Here we have a separate mask for device type phy.
- * Having different masks for host and device type phy helps
- * in setting independent masks in case of SoCs like S5PV210,
- * in which PHY0 and PHY1 enable bits belong to same register
- * placed at position 0 and 1 respectively.
- * Although for newer SoCs like exynos these bits belong to
- * different registers altogether placed at position 0.
- */
-struct samsung_usbphy_drvdata {
- int cpu_type;
- int devphy_en_mask;
- int hostphy_en_mask;
- u32 devphy_reg_offset;
- u32 hostphy_reg_offset;
-};
-
-/*
- * struct samsung_usbphy - transceiver driver state
- * @phy: transceiver structure
- * @plat: platform data
- * @dev: The parent device supplied to the probe function
- * @clk: usb phy clock
- * @regs: usb phy controller registers memory base
- * @pmuregs: USB device PHY_CONTROL register memory base
- * @sysreg: USB2.0 PHY_CFG register memory base
- * @ref_clk_freq: reference clock frequency selection
- * @drv_data: driver data available for different SoCs
- * @phy_type: Samsung SoCs specific phy types: #HOST
- * #DEVICE
- * @phy_usage: usage count for phy
- * @lock: lock for phy operations
- */
-struct samsung_usbphy {
- struct usb_phy phy;
- struct samsung_usbphy_data *plat;
- struct device *dev;
- struct clk *clk;
- void __iomem *regs;
- void __iomem *pmuregs;
- void __iomem *sysreg;
- int ref_clk_freq;
- const struct samsung_usbphy_drvdata *drv_data;
- enum samsung_usb_phy_type phy_type;
- atomic_t phy_usage;
- spinlock_t lock;
-};
-
-#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
-
-int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host)
-{
- if (!otg)
- return -ENODEV;
-
- if (!otg->host)
- otg->host = host;
-
- return 0;
-}
-
-static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
-{
- struct device_node *usbphy_sys;
-
- /* Getting node for system controller interface for usb-phy */
- usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
- if (!usbphy_sys) {
- dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
- return -ENODEV;
- }
-
- sphy->pmuregs = of_iomap(usbphy_sys, 0);
-
- if (sphy->pmuregs == NULL) {
- dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
- goto err0;
- }
-
- sphy->sysreg = of_iomap(usbphy_sys, 1);
-
- /*
- * Not returning error code here, since this situation is not fatal.
- * Few SoCs may not have this switch available
- */
- if (sphy->sysreg == NULL)
- dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
-
- of_node_put(usbphy_sys);
-
- return 0;
-
-err0:
- of_node_put(usbphy_sys);
- return -ENXIO;
-}
-
-/*
- * Set isolation here for phy.
- * Here 'on = true' would mean USB PHY block is isolated, hence
- * de-activated and vice-versa.
- */
-static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
-{
- void __iomem *reg = NULL;
- u32 reg_val;
- u32 en_mask = 0;
-
- if (!sphy->pmuregs) {
- dev_warn(sphy->dev, "Can't set pmu isolation\n");
- return;
- }
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- /*
- * Do nothing: We will add here once S3C64xx goes for DT support
- */
- break;
- case TYPE_EXYNOS4210:
- /*
- * Fall through since exynos4210 and exynos5250 have similar
- * register architecture: two separate registers for host and
- * device phy control with enable bit at position 0.
- */
- case TYPE_EXYNOS5250:
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
- reg = sphy->pmuregs +
- sphy->drv_data->devphy_reg_offset;
- en_mask = sphy->drv_data->devphy_en_mask;
- } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
- reg = sphy->pmuregs +
- sphy->drv_data->hostphy_reg_offset;
- en_mask = sphy->drv_data->hostphy_en_mask;
- }
- break;
- default:
- dev_err(sphy->dev, "Invalid SoC type\n");
- return;
- }
-
- reg_val = readl(reg);
-
- if (on)
- reg_val &= ~en_mask;
- else
- reg_val |= en_mask;
-
- writel(reg_val, reg);
-}
-
-/*
- * Configure the mode of working of usb-phy here: HOST/DEVICE.
- */
-static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
-{
- u32 reg;
-
- if (!sphy->sysreg) {
- dev_warn(sphy->dev, "Can't configure specified phy mode\n");
- return;
- }
-
- reg = readl(sphy->sysreg);
-
- if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
- reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
- else if (sphy->phy_type == USB_PHY_TYPE_HOST)
- reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
-
- writel(reg, sphy->sysreg);
-}
-
-/*
- * PHYs are different for USB Device and USB Host.
- * This make sure that correct PHY type is selected before
- * any operation on PHY.
- */
-static int samsung_usbphy_set_type(struct usb_phy *phy,
- enum samsung_usb_phy_type phy_type)
-{
- struct samsung_usbphy *sphy = phy_to_sphy(phy);
-
- sphy->phy_type = phy_type;
-
- return 0;
-}
-
-/*
- * Returns reference clock frequency selection value
- */
-static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
-{
- struct clk *ref_clk;
- int refclk_freq = 0;
-
- /*
- * In exynos5250 USB host and device PHY use
- * external crystal clock XXTI
- */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- ref_clk = clk_get(sphy->dev, "ext_xtal");
- else
- ref_clk = clk_get(sphy->dev, "xusbxti");
- if (IS_ERR(ref_clk)) {
- dev_err(sphy->dev, "Failed to get reference clock\n");
- return PTR_ERR(ref_clk);
- }
-
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) {
- /* set clock frequency for PLL */
- switch (clk_get_rate(ref_clk)) {
- case 9600 * KHZ:
- refclk_freq = FSEL_CLKSEL_9600K;
- break;
- case 10 * MHZ:
- refclk_freq = FSEL_CLKSEL_10M;
- break;
- case 12 * MHZ:
- refclk_freq = FSEL_CLKSEL_12M;
- break;
- case 19200 * KHZ:
- refclk_freq = FSEL_CLKSEL_19200K;
- break;
- case 20 * MHZ:
- refclk_freq = FSEL_CLKSEL_20M;
- break;
- case 50 * MHZ:
- refclk_freq = FSEL_CLKSEL_50M;
- break;
- case 24 * MHZ:
- default:
- /* default reference clock */
- refclk_freq = FSEL_CLKSEL_24M;
- break;
- }
- } else {
- switch (clk_get_rate(ref_clk)) {
- case 12 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_12M;
- break;
- case 24 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_24M;
- break;
- case 48 * MHZ:
- refclk_freq = PHYCLK_CLKSEL_48M;
- break;
- default:
- if (sphy->drv_data->cpu_type == TYPE_S3C64XX)
- refclk_freq = PHYCLK_CLKSEL_48M;
- else
- refclk_freq = PHYCLK_CLKSEL_24M;
- break;
- }
- }
- clk_put(ref_clk);
-
- return refclk_freq;
-}
-
-static bool exynos5_phyhost_is_on(void *regs)
-{
- u32 reg;
-
- reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
- return !(reg & HOST_CTRL0_SIDDQ);
-}
-
-static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phyclk = sphy->ref_clk_freq;
- u32 phyhost;
- u32 phyotg;
- u32 phyhsic;
- u32 ehcictrl;
- u32 ohcictrl;
-
- /*
- * phy_usage helps in keeping usage count for phy
- * so that the first consumer enabling the phy is also
- * the last consumer to disable it.
- */
-
- atomic_inc(&sphy->phy_usage);
-
- if (exynos5_phyhost_is_on(regs)) {
- dev_info(sphy->dev, "Already power on PHY\n");
- return;
- }
-
- /* Host configuration */
- phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
-
- /* phy reference clock configuration */
- phyhost &= ~HOST_CTRL0_FSEL_MASK;
- phyhost |= HOST_CTRL0_FSEL(phyclk);
-
- /* host phy reset */
- phyhost &= ~(HOST_CTRL0_PHYSWRST |
- HOST_CTRL0_PHYSWRSTALL |
- HOST_CTRL0_SIDDQ |
- /* Enable normal mode of operation */
- HOST_CTRL0_FORCESUSPEND |
- HOST_CTRL0_FORCESLEEP);
-
- /* Link reset */
- phyhost |= (HOST_CTRL0_LINKSWRST |
- HOST_CTRL0_UTMISWRST |
- /* COMMON Block configuration during suspend */
- HOST_CTRL0_COMMONON_N);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
- udelay(10);
- phyhost &= ~(HOST_CTRL0_LINKSWRST |
- HOST_CTRL0_UTMISWRST);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
- /* OTG configuration */
- phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
-
- /* phy reference clock configuration */
- phyotg &= ~OTG_SYS_FSEL_MASK;
- phyotg |= OTG_SYS_FSEL(phyclk);
-
- /* Enable normal mode of operation */
- phyotg &= ~(OTG_SYS_FORCESUSPEND |
- OTG_SYS_SIDDQ_UOTG |
- OTG_SYS_FORCESLEEP |
- OTG_SYS_REFCLKSEL_MASK |
- /* COMMON Block configuration during suspend */
- OTG_SYS_COMMON_ON);
-
- /* OTG phy & link reset */
- phyotg |= (OTG_SYS_PHY0_SWRST |
- OTG_SYS_LINKSWRST_UOTG |
- OTG_SYS_PHYLINK_SWRESET |
- OTG_SYS_OTGDISABLE |
- /* Set phy refclk */
- OTG_SYS_REFCLKSEL_CLKCORE);
-
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
- udelay(10);
- phyotg &= ~(OTG_SYS_PHY0_SWRST |
- OTG_SYS_LINKSWRST_UOTG |
- OTG_SYS_PHYLINK_SWRESET);
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-
- /* HSIC phy configuration */
- phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
- HSIC_CTRL_REFCLKSEL |
- HSIC_CTRL_PHYSWRST);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
- udelay(10);
- phyhsic &= ~HSIC_CTRL_PHYSWRST;
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
- udelay(80);
-
- /* enable EHCI DMA burst */
- ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL);
- ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN |
- HOST_EHCICTRL_ENAINCR4 |
- HOST_EHCICTRL_ENAINCR8 |
- HOST_EHCICTRL_ENAINCR16);
- writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL);
-
- /* set ohci_suspend_on_n */
- ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL);
- ohcictrl |= HOST_OHCICTRL_SUSPLGCY;
- writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
-}
-
-static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phypwr;
- u32 phyclk;
- u32 rstcon;
-
- /* set clock frequency for PLL */
- phyclk = sphy->ref_clk_freq;
- phypwr = readl(regs + SAMSUNG_PHYPWR);
- rstcon = readl(regs + SAMSUNG_RSTCON);
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- phyclk &= ~PHYCLK_COMMON_ON_N;
- phypwr &= ~PHYPWR_NORMAL_MASK;
- rstcon |= RSTCON_SWRST;
- break;
- case TYPE_EXYNOS4210:
- phypwr &= ~PHYPWR_NORMAL_MASK_PHY0;
- rstcon |= RSTCON_SWRST;
- default:
- break;
- }
-
- writel(phyclk, regs + SAMSUNG_PHYCLK);
- /* Configure PHY0 for normal operation*/
- writel(phypwr, regs + SAMSUNG_PHYPWR);
- /* reset all ports of PHY and Link */
- writel(rstcon, regs + SAMSUNG_RSTCON);
- udelay(10);
- rstcon &= ~RSTCON_SWRST;
- writel(rstcon, regs + SAMSUNG_RSTCON);
-}
-
-static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phyhost;
- u32 phyotg;
- u32 phyhsic;
-
- if (atomic_dec_return(&sphy->phy_usage) > 0) {
- dev_info(sphy->dev, "still being used\n");
- return;
- }
-
- phyhsic = (HSIC_CTRL_REFCLKDIV_12 |
- HSIC_CTRL_REFCLKSEL |
- HSIC_CTRL_SIDDQ |
- HSIC_CTRL_FORCESLEEP |
- HSIC_CTRL_FORCESUSPEND);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1);
- writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2);
-
- phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0);
- phyhost |= (HOST_CTRL0_SIDDQ |
- HOST_CTRL0_FORCESUSPEND |
- HOST_CTRL0_FORCESLEEP |
- HOST_CTRL0_PHYSWRST |
- HOST_CTRL0_PHYSWRSTALL);
- writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0);
-
- phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS);
- phyotg |= (OTG_SYS_FORCESUSPEND |
- OTG_SYS_SIDDQ_UOTG |
- OTG_SYS_FORCESLEEP);
- writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
-}
-
-static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
-{
- void __iomem *regs = sphy->regs;
- u32 phypwr;
-
- phypwr = readl(regs + SAMSUNG_PHYPWR);
-
- switch (sphy->drv_data->cpu_type) {
- case TYPE_S3C64XX:
- phypwr |= PHYPWR_NORMAL_MASK;
- break;
- case TYPE_EXYNOS4210:
- phypwr |= PHYPWR_NORMAL_MASK_PHY0;
- default:
- break;
- }
-
- /* Disable analog and otg block power */
- writel(phypwr, regs + SAMSUNG_PHYPWR);
-}
-
-/*
- * The function passed to the usb driver for phy initialization
- */
-static int samsung_usbphy_init(struct usb_phy *phy)
-{
- struct samsung_usbphy *sphy;
- struct usb_bus *host = NULL;
- unsigned long flags;
- int ret = 0;
-
- sphy = phy_to_sphy(phy);
-
- host = phy->otg->host;
-
- /* Enable the phy clock */
- ret = clk_prepare_enable(sphy->clk);
- if (ret) {
- dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
- return ret;
- }
-
- spin_lock_irqsave(&sphy->lock, flags);
-
- if (host) {
- /* setting default phy-type for USB 2.0 */
- if (!strstr(dev_name(host->controller), "ehci") ||
- !strstr(dev_name(host->controller), "ohci"))
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
- } else {
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
- }
-
- /* Disable phy isolation */
- if (sphy->plat && sphy->plat->pmu_isolation)
- sphy->plat->pmu_isolation(false);
- else
- samsung_usbphy_set_isolation(sphy, false);
-
- /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
- samsung_usbphy_cfg_sel(sphy);
-
- /* Initialize usb phy registers */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- samsung_exynos5_usbphy_enable(sphy);
- else
- samsung_usbphy_enable(sphy);
-
- spin_unlock_irqrestore(&sphy->lock, flags);
-
- /* Disable the phy clock */
- clk_disable_unprepare(sphy->clk);
-
- return ret;
-}
-
-/*
- * The function passed to the usb driver for phy shutdown
- */
-static void samsung_usbphy_shutdown(struct usb_phy *phy)
-{
- struct samsung_usbphy *sphy;
- struct usb_bus *host = NULL;
- unsigned long flags;
-
- sphy = phy_to_sphy(phy);
-
- host = phy->otg->host;
-
- if (clk_prepare_enable(sphy->clk)) {
- dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__);
- return;
- }
-
- spin_lock_irqsave(&sphy->lock, flags);
-
- if (host) {
- /* setting default phy-type for USB 2.0 */
- if (!strstr(dev_name(host->controller), "ehci") ||
- !strstr(dev_name(host->controller), "ohci"))
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST);
- } else {
- samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE);
- }
-
- /* De-initialize usb phy registers */
- if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
- samsung_exynos5_usbphy_disable(sphy);
- else
- samsung_usbphy_disable(sphy);
-
- /* Enable phy isolation */
- if (sphy->plat && sphy->plat->pmu_isolation)
- sphy->plat->pmu_isolation(true);
- else
- samsung_usbphy_set_isolation(sphy, true);
-
- spin_unlock_irqrestore(&sphy->lock, flags);
-
- clk_disable_unprepare(sphy->clk);
-}
-
-static const struct of_device_id samsung_usbphy_dt_match[];
-
-static inline const struct samsung_usbphy_drvdata
-*samsung_usbphy_get_driver_data(struct platform_device *pdev)
-{
- if (pdev->dev.of_node) {
- const struct of_device_id *match;
- match = of_match_node(samsung_usbphy_dt_match,
- pdev->dev.of_node);
- return match->data;
- }
-
- return (struct samsung_usbphy_drvdata *)
- platform_get_device_id(pdev)->driver_data;
-}
-
-static int samsung_usbphy_probe(struct platform_device *pdev)
-{
- struct samsung_usbphy *sphy;
- struct usb_otg *otg;
- struct samsung_usbphy_data *pdata = pdev->dev.platform_data;
- const struct samsung_usbphy_drvdata *drv_data;
- struct device *dev = &pdev->dev;
- struct resource *phy_mem;
- void __iomem *phy_base;
- struct clk *clk;
- int ret;
-
- phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!phy_mem) {
- dev_err(dev, "%s: missing mem resource\n", __func__);
- return -ENODEV;
- }
-
- phy_base = devm_ioremap_resource(dev, phy_mem);
- if (IS_ERR(phy_base))
- return PTR_ERR(phy_base);
-
- sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL);
- if (!sphy)
- return -ENOMEM;
-
- otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
- if (!otg)
- return -ENOMEM;
-
- drv_data = samsung_usbphy_get_driver_data(pdev);
-
- if (drv_data->cpu_type == TYPE_EXYNOS5250)
- clk = devm_clk_get(dev, "usbhost");
- else
- clk = devm_clk_get(dev, "otg");
-
- if (IS_ERR(clk)) {
- dev_err(dev, "Failed to get otg clock\n");
- return PTR_ERR(clk);
- }
-
- sphy->dev = dev;
-
- if (dev->of_node) {
- ret = samsung_usbphy_parse_dt(sphy);
- if (ret < 0)
- return ret;
- } else {
- if (!pdata) {
- dev_err(dev, "no platform data specified\n");
- return -EINVAL;
- }
- }
-
- sphy->plat = pdata;
- sphy->regs = phy_base;
- sphy->clk = clk;
- sphy->drv_data = drv_data;
- sphy->phy.dev = sphy->dev;
- sphy->phy.label = "samsung-usbphy";
- sphy->phy.init = samsung_usbphy_init;
- sphy->phy.shutdown = samsung_usbphy_shutdown;
- sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy);
-
- sphy->phy.otg = otg;
- sphy->phy.otg->phy = &sphy->phy;
- sphy->phy.otg->set_host = samsung_usbphy_set_host;
-
- spin_lock_init(&sphy->lock);
-
- platform_set_drvdata(pdev, sphy);
-
- return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2);
-}
-
-static int samsung_usbphy_remove(struct platform_device *pdev)
-{
- struct samsung_usbphy *sphy = platform_get_drvdata(pdev);
-
- usb_remove_phy(&sphy->phy);
-
- if (sphy->pmuregs)
- iounmap(sphy->pmuregs);
- if (sphy->sysreg)
- iounmap(sphy->sysreg);
-
- return 0;
-}
-
-static const struct samsung_usbphy_drvdata usbphy_s3c64xx = {
- .cpu_type = TYPE_S3C64XX,
- .devphy_en_mask = S3C64XX_USBPHY_ENABLE,
-};
-
-static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
- .cpu_type = TYPE_EXYNOS4210,
- .devphy_en_mask = EXYNOS_USBPHY_ENABLE,
- .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
-};
-
-static struct samsung_usbphy_drvdata usbphy_exynos5 = {
- .cpu_type = TYPE_EXYNOS5250,
- .hostphy_en_mask = EXYNOS_USBPHY_ENABLE,
- .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET,
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_usbphy_dt_match[] = {
- {
- .compatible = "samsung,s3c64xx-usbphy",
- .data = &usbphy_s3c64xx,
- }, {
- .compatible = "samsung,exynos4210-usbphy",
- .data = &usbphy_exynos4,
- }, {
- .compatible = "samsung,exynos5250-usbphy",
- .data = &usbphy_exynos5
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match);
-#endif
-
-static struct platform_device_id samsung_usbphy_driver_ids[] = {
- {
- .name = "s3c64xx-usbphy",
- .driver_data = (unsigned long)&usbphy_s3c64xx,
- }, {
- .name = "exynos4210-usbphy",
- .driver_data = (unsigned long)&usbphy_exynos4,
- }, {
- .name = "exynos5250-usbphy",
- .driver_data = (unsigned long)&usbphy_exynos5,
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids);
-
-static struct platform_driver samsung_usbphy_driver = {
- .probe = samsung_usbphy_probe,
- .remove = samsung_usbphy_remove,
- .id_table = samsung_usbphy_driver_ids,
- .driver = {
- .name = "samsung-usbphy",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(samsung_usbphy_dt_match),
- },
-};
-
-module_platform_driver(samsung_usbphy_driver);
-
-MODULE_DESCRIPTION("Samsung USB phy controller");
-MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:samsung-usbphy");
diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig
index 29feb00d7f39..019bf7e49ee6 100644
--- a/drivers/usb/renesas_usbhs/Kconfig
+++ b/drivers/usb/renesas_usbhs/Kconfig
@@ -4,7 +4,7 @@
config USB_RENESAS_USBHS
tristate 'Renesas USBHS controller'
- depends on USB && USB_GADGET && GENERIC_HARDIRQS
+ depends on USB_GADGET && GENERIC_HARDIRQS
default n
help
Renesas USBHS is a discrete USB host and peripheral controller chip
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 9538f0feafe2..45b94019aec8 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -32,7 +32,6 @@
*/
void usbhs_pkt_init(struct usbhs_pkt *pkt)
{
- pkt->dma = DMA_ADDR_INVALID;
INIT_LIST_HEAD(&pkt->node);
}
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index c31731a843d1..a168a1760fce 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -23,8 +23,6 @@
#include <asm/dma.h>
#include "pipe.h"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
struct usbhs_fifo {
char *name;
u32 port; /* xFIFO */
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 78fca978b2d0..ed4949faa70d 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -230,7 +230,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_clear_feature = {
+static struct usbhsg_recip_handle req_clear_feature = {
.name = "clear feature",
.device = usbhsg_recip_handler_std_control_done,
.interface = usbhsg_recip_handler_std_control_done,
@@ -271,7 +271,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_set_feature = {
+static struct usbhsg_recip_handle req_set_feature = {
.name = "set feature",
.device = usbhsg_recip_handler_std_set_device,
.interface = usbhsg_recip_handler_std_control_done,
@@ -372,7 +372,7 @@ static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
return 0;
}
-struct usbhsg_recip_handle req_get_status = {
+static struct usbhsg_recip_handle req_get_status = {
.name = "get status",
.device = usbhsg_recip_handler_std_get_device,
.interface = usbhsg_recip_handler_std_get_interface,
@@ -845,7 +845,6 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
/* first hook up the driver ... */
gpriv->driver = driver;
- gpriv->gadget.dev.driver = &driver->driver;
return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD);
}
@@ -861,7 +860,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget,
return -EINVAL;
usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD);
- gpriv->gadget.dev.driver = NULL;
gpriv->driver = NULL;
return 0;
@@ -925,11 +923,6 @@ static int usbhsg_stop(struct usbhs_priv *priv)
return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);
}
-static void usbhs_mod_gadget_release(struct device *pdev)
-{
- /* do nothing */
-}
-
int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
{
struct usbhsg_gpriv *gpriv;
@@ -976,15 +969,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
/*
* init gadget
*/
- dev_set_name(&gpriv->gadget.dev, "gadget");
gpriv->gadget.dev.parent = dev;
- gpriv->gadget.dev.release = usbhs_mod_gadget_release;
gpriv->gadget.name = "renesas_usbhs_udc";
gpriv->gadget.ops = &usbhsg_gadget_ops;
gpriv->gadget.max_speed = USB_SPEED_HIGH;
- ret = device_register(&gpriv->gadget.dev);
- if (ret < 0)
- goto err_add_udc;
INIT_LIST_HEAD(&gpriv->gadget.ep_list);
@@ -1014,15 +1002,13 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
ret = usb_add_gadget_udc(dev, &gpriv->gadget);
if (ret)
- goto err_register;
+ goto err_add_udc;
dev_info(dev, "gadget probed\n");
return 0;
-err_register:
- device_unregister(&gpriv->gadget.dev);
err_add_udc:
kfree(gpriv->uep);
@@ -1038,8 +1024,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
usb_del_gadget_udc(&gpriv->gadget);
- device_unregister(&gpriv->gadget.dev);
-
kfree(gpriv->uep);
kfree(gpriv);
}
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 17b7f9ae36ad..1d55762afbb1 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -4,7 +4,7 @@
menuconfig USB_SERIAL
tristate "USB Serial Converter support"
- depends on USB && TTY
+ depends on TTY
---help---
Say Y here if you have a USB device that provides normal serial
ports, or acts like a serial device, and you want to connect it to
@@ -667,6 +667,23 @@ config USB_SERIAL_ZIO
To compile this driver as a module, choose M here: the
module will be called zio.
+config USB_SERIAL_WISHBONE
+ tristate "USB-Wishbone adapter interface driver"
+ help
+ Say Y here if you want to use a USB attached Wishbone bus.
+
+ Wishbone is an open hardware SoC bus commonly used in FPGA
+ designs. Bus access can be serialized using the Etherbone
+ protocol <http://www.ohwr.org/projects/etherbone-core>.
+
+ This driver is intended to be used with devices which attach
+ their internal Wishbone bus to a USB serial interface using
+ the Etherbone protocol. A userspace library is required to
+ speak the protocol made available by this driver as ttyUSBx.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wishbone-serial.
+
config USB_SERIAL_ZTE
tristate "ZTE USB serial driver"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index eaf5ca14dfeb..cec63fa19104 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o
obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
+obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 4775f8209e55..3b16118cbf62 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -62,7 +62,6 @@ static int is_irda(struct usb_serial *serial)
}
struct ark3116_private {
- struct async_icount icount;
int irda; /* 1 for irda device */
/* protects hw register updates */
@@ -341,18 +340,15 @@ static void ark3116_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- if (serial->dev) {
- /* disable DMA */
- ark3116_write_reg(serial, UART_FCR, 0);
-
- /* deactivate interrupts */
- ark3116_write_reg(serial, UART_IER, 0);
+ /* disable DMA */
+ ark3116_write_reg(serial, UART_FCR, 0);
- usb_serial_generic_close(port);
- if (serial->num_interrupt_in)
- usb_kill_urb(port->interrupt_in_urb);
- }
+ /* deactivate interrupts */
+ ark3116_write_reg(serial, UART_IER, 0);
+ usb_serial_generic_close(port);
+ if (serial->num_interrupt_in)
+ usb_kill_urb(port->interrupt_in_urb);
}
static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -405,31 +401,10 @@ err_out:
return result;
}
-static int ark3116_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
- return 0;
-}
-
static int ark3116_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
struct serial_struct serstruct;
void __user *user_arg = (void __user *)arg;
@@ -451,33 +426,6 @@ static int ark3116_ioctl(struct tty_struct *tty,
if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
- case TIOCMIWAIT:
- for (;;) {
- struct async_icount prev = priv->icount;
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- if ((prev.rng == priv->icount.rng) &&
- (prev.dsr == priv->icount.dsr) &&
- (prev.dcd == priv->icount.dcd) &&
- (prev.cts == priv->icount.cts))
- return -EIO;
- if ((arg & TIOCM_RNG &&
- (prev.rng != priv->icount.rng)) ||
- (arg & TIOCM_DSR &&
- (prev.dsr != priv->icount.dsr)) ||
- (arg & TIOCM_CD &&
- (prev.dcd != priv->icount.dcd)) ||
- (arg & TIOCM_CTS &&
- (prev.cts != priv->icount.cts)))
- return 0;
- }
- break;
}
return -ENOIOCTLCMD;
@@ -575,14 +523,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -598,13 +546,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)
if (lsr&UART_LSR_BRK_ERROR_BITS) {
if (lsr & UART_LSR_BI)
- priv->icount.brk++;
+ port->icount.brk++;
if (lsr & UART_LSR_FE)
- priv->icount.frame++;
+ port->icount.frame++;
if (lsr & UART_LSR_PE)
- priv->icount.parity++;
+ port->icount.parity++;
if (lsr & UART_LSR_OE)
- priv->icount.overrun++;
+ port->icount.overrun++;
}
}
@@ -722,7 +670,8 @@ static struct usb_serial_driver ark3116_device = {
.ioctl = ark3116_ioctl,
.tiocmget = ark3116_tiocmget,
.tiocmset = ark3116_tiocmset,
- .get_icount = ark3116_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.open = ark3116_open,
.close = ark3116_close,
.break_ctl = ark3116_break_ctl,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 37decb13d7eb..3c4db6d196c6 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -106,14 +106,15 @@ static int usb_serial_device_remove(struct device *dev)
/* make sure suspend/resume doesn't race against port_remove */
usb_autopm_get_interface(port->serial->interface);
+ minor = port->number;
+ tty_unregister_device(usb_serial_tty_driver, minor);
+
device_remove_file(&port->dev, &dev_attr_port_number);
driver = port->serial->type;
if (driver->port_remove)
retval = driver->port_remove(port);
- minor = port->number;
- tty_unregister_device(usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->description, minor);
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 07d4650a32ab..c2a4171ab9cb 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -296,7 +296,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
- wake_up_interruptible(&port->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
@@ -489,7 +488,7 @@ static void ch341_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
exit:
@@ -500,8 +499,9 @@ exit:
__func__, status);
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 prevstatus;
@@ -515,7 +515,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (!multi_change) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -542,26 +542,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int ch341_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- return wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static int ch341_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -611,11 +591,11 @@ static struct usb_serial_driver ch341_device = {
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
- .ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,
.break_ctl = ch341_break_ctl,
.tiocmget = ch341_tiocmget,
.tiocmset = ch341_tiocmset,
+ .tiocmiwait = ch341_tiocmiwait,
.read_int_callback = ch341_read_int_callback,
.port_probe = ch341_port_probe,
.port_remove = ch341_port_remove,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 4747d1c328ff..2c659553c07c 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -462,11 +462,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
usb_serial_generic_close(port);
-
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
- mutex_unlock(&port->serial->disc_mutex);
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
}
/*
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 629bd2894506..781426230d69 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -51,7 +51,6 @@
#define CYBERJACK_PRODUCT_ID 0x0100
/* Function prototypes */
-static void cyberjack_disconnect(struct usb_serial *serial);
static int cyberjack_port_probe(struct usb_serial_port *port);
static int cyberjack_port_remove(struct usb_serial_port *port);
static int cyberjack_open(struct tty_struct *tty,
@@ -79,7 +78,6 @@ static struct usb_serial_driver cyberjack_device = {
.description = "Reiner SCT Cyberjack USB card reader",
.id_table = id_table,
.num_ports = 1,
- .disconnect = cyberjack_disconnect,
.port_probe = cyberjack_port_probe,
.port_remove = cyberjack_port_remove,
.open = cyberjack_open,
@@ -130,20 +128,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port)
{
struct cyberjack_private *priv;
+ usb_kill_urb(port->interrupt_in_urb);
+
priv = usb_get_serial_port_data(port);
kfree(priv);
return 0;
}
-static void cyberjack_disconnect(struct usb_serial *serial)
-{
- int i;
-
- for (i = 0; i < serial->num_ports; ++i)
- usb_kill_urb(serial->port[i]->interrupt_in_urb);
-}
-
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
@@ -166,11 +158,8 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port)
{
- if (port->serial->dev) {
- /* shutdown any bulk reads that might be going on */
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- }
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
}
static int cyberjack_write(struct tty_struct *tty,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index ba7352e4187e..d341555d37d8 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -129,13 +129,12 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
static int cypress_write_room(struct tty_struct *tty);
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int cypress_tiocmget(struct tty_struct *tty);
static int cypress_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg);
static int cypress_chars_in_buffer(struct tty_struct *tty);
static void cypress_throttle(struct tty_struct *tty);
static void cypress_unthrottle(struct tty_struct *tty);
@@ -158,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -184,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -210,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
- .ioctl = cypress_ioctl,
.set_termios = cypress_set_termios,
.tiocmget = cypress_tiocmget,
.tiocmset = cypress_tiocmset,
+ .tiocmiwait = cypress_tiocmiwait,
.chars_in_buffer = cypress_chars_in_buffer,
.throttle = cypress_throttle,
.unthrottle = cypress_unthrottle,
@@ -633,12 +632,6 @@ static void cypress_close(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- /* writing is potentially harmful, lock must be taken */
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
spin_lock_irqsave(&priv->lock, flags);
kfifo_reset_out(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -650,7 +643,6 @@ static void cypress_close(struct usb_serial_port *port)
if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
- mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */
@@ -855,55 +847,43 @@ static int cypress_tiocmset(struct tty_struct *tty,
}
-static int cypress_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
-
- dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd);
-
- switch (cmd) {
- /* This code comes from drivers/char/serial.c and ftdi_sio.c */
- case TIOCMIWAIT:
- for (;;) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- {
- char diff = priv->diff_status;
- if (diff == 0)
- return -EIO; /* no change => error */
-
- /* consume all events */
- priv->diff_status = 0;
-
- /* return 0 if caller wanted to know about
- these bits */
- if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
- ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
- ((arg & TIOCM_CD) && (diff & UART_CD)) ||
- ((arg & TIOCM_CTS) && (diff & UART_CTS)))
- return 0;
- /* otherwise caller can't care less about what
- * happened, and so we continue to wait for
- * more events.
- */
- }
- }
- return 0;
- default:
- break;
+ char diff;
+
+ for (;;) {
+ interruptible_sleep_on(&port->port.delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ if (port->serial->disconnected)
+ return -EIO;
+
+ diff = priv->diff_status;
+ if (diff == 0)
+ return -EIO; /* no change => error */
+
+ /* consume all events */
+ priv->diff_status = 0;
+
+ /* return 0 if caller wanted to know about
+ these bits */
+ if (((arg & TIOCM_RNG) && (diff & UART_RI)) ||
+ ((arg & TIOCM_DSR) && (diff & UART_DSR)) ||
+ ((arg & TIOCM_CD) && (diff & UART_CD)) ||
+ ((arg & TIOCM_CTS) && (diff & UART_CTS)))
+ return 0;
+ /* otherwise caller can't care less about what
+ * happened, and so we continue to wait for
+ * more events.
+ */
}
- dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd);
- return -ENOIOCTLCMD;
-} /* cypress_ioctl */
+ return 0;
+}
static void cypress_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
@@ -1189,7 +1169,7 @@ static void cypress_read_int_callback(struct urb *urb)
if (priv->current_status != priv->prev_status) {
priv->diff_status |= priv->current_status ^
priv->prev_status;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = priv->current_status;
}
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index ebe45fa0ed50..7b807d389527 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -196,7 +196,6 @@ struct digi_port {
unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
int dp_write_urb_in_use;
unsigned int dp_modem_signals;
- wait_queue_head_t dp_modem_change_wait;
int dp_transmit_idle;
wait_queue_head_t dp_transmit_idle_wait;
int dp_throttled;
@@ -210,7 +209,6 @@ struct digi_port {
/* Local Function Declarations */
-static void digi_wakeup_write(struct usb_serial_port *port);
static void digi_wakeup_write_lock(struct work_struct *work);
static int digi_write_oob_command(struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible);
@@ -374,20 +372,10 @@ static void digi_wakeup_write_lock(struct work_struct *work)
unsigned long flags;
spin_lock_irqsave(&priv->dp_port_lock, flags);
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
}
-static void digi_wakeup_write(struct usb_serial_port *port)
-{
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
-}
-
-
/*
* Digi Write OOB Command
*
@@ -1044,7 +1032,7 @@ static void digi_write_bulk_callback(struct urb *urb)
}
}
/* wake up processes sleeping on writes immediately */
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
/* also queue up a wakeup at scheduler time, in case we */
/* lost the race in write_chan(). */
schedule_work(&priv->dp_wakeup_work);
@@ -1149,53 +1137,51 @@ static void digi_close(struct usb_serial_port *port)
if (port->serial->disconnected)
goto exit;
- if (port->serial->dev) {
- /* FIXME: Transmit idle belongs in the wait_unti_sent path */
- digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
-
- /* disable input flow control */
- buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
- buf[1] = priv->dp_port_num;
- buf[2] = DIGI_DISABLE;
- buf[3] = 0;
-
- /* disable output flow control */
- buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
- buf[5] = priv->dp_port_num;
- buf[6] = DIGI_DISABLE;
- buf[7] = 0;
-
- /* disable reading modem signals automatically */
- buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
- buf[9] = priv->dp_port_num;
- buf[10] = DIGI_DISABLE;
- buf[11] = 0;
-
- /* disable receive */
- buf[12] = DIGI_CMD_RECEIVE_ENABLE;
- buf[13] = priv->dp_port_num;
- buf[14] = DIGI_DISABLE;
- buf[15] = 0;
-
- /* flush fifos */
- buf[16] = DIGI_CMD_IFLUSH_FIFO;
- buf[17] = priv->dp_port_num;
- buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
- buf[19] = 0;
-
- ret = digi_write_oob_command(port, buf, 20, 0);
- if (ret != 0)
- dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret);
-
- /* wait for final commands on oob port to complete */
- prepare_to_wait(&priv->dp_flush_wait, &wait,
- TASK_INTERRUPTIBLE);
- schedule_timeout(DIGI_CLOSE_TIMEOUT);
- finish_wait(&priv->dp_flush_wait, &wait);
-
- /* shutdown any outstanding bulk writes */
- usb_kill_urb(port->write_urb);
- }
+ /* FIXME: Transmit idle belongs in the wait_unti_sent path */
+ digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
+
+ /* disable input flow control */
+ buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+ buf[1] = priv->dp_port_num;
+ buf[2] = DIGI_DISABLE;
+ buf[3] = 0;
+
+ /* disable output flow control */
+ buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+ buf[5] = priv->dp_port_num;
+ buf[6] = DIGI_DISABLE;
+ buf[7] = 0;
+
+ /* disable reading modem signals automatically */
+ buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
+ buf[9] = priv->dp_port_num;
+ buf[10] = DIGI_DISABLE;
+ buf[11] = 0;
+
+ /* disable receive */
+ buf[12] = DIGI_CMD_RECEIVE_ENABLE;
+ buf[13] = priv->dp_port_num;
+ buf[14] = DIGI_DISABLE;
+ buf[15] = 0;
+
+ /* flush fifos */
+ buf[16] = DIGI_CMD_IFLUSH_FIFO;
+ buf[17] = priv->dp_port_num;
+ buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+ buf[19] = 0;
+
+ ret = digi_write_oob_command(port, buf, 20, 0);
+ if (ret != 0)
+ dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n",
+ ret);
+ /* wait for final commands on oob port to complete */
+ prepare_to_wait(&priv->dp_flush_wait, &wait,
+ TASK_INTERRUPTIBLE);
+ schedule_timeout(DIGI_CLOSE_TIMEOUT);
+ finish_wait(&priv->dp_flush_wait, &wait);
+
+ /* shutdown any outstanding bulk writes */
+ usb_kill_urb(port->write_urb);
exit:
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
@@ -1252,7 +1238,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)
spin_lock_init(&priv->dp_port_lock);
priv->dp_port_num = port_num;
- init_waitqueue_head(&priv->dp_modem_change_wait);
init_waitqueue_head(&priv->dp_transmit_idle_wait);
init_waitqueue_head(&priv->dp_flush_wait);
init_waitqueue_head(&priv->dp_close_wait);
@@ -1522,7 +1507,7 @@ static int digi_read_oob_callback(struct urb *urb)
/* port must be open to use tty struct */
if (rts) {
tty->hw_stopped = 0;
- digi_wakeup_write(port);
+ tty_port_tty_wakeup(&port->port);
}
} else {
priv->dp_modem_signals &= ~TIOCM_CTS;
@@ -1543,7 +1528,6 @@ static int digi_read_oob_callback(struct urb *urb)
else
priv->dp_modem_signals &= ~TIOCM_CD;
- wake_up_interruptible(&priv->dp_modem_change_wait);
spin_unlock(&priv->dp_port_lock);
} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
spin_lock(&priv->dp_port_lock);
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index a172ad5c5ce8..090b411d893f 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -110,7 +110,7 @@ static void f81232_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
if (!urb->actual_length)
return;
@@ -242,8 +242,9 @@ static int f81232_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int f81232_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct f81232_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prevstatus;
@@ -255,7 +256,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -302,11 +303,6 @@ static int f81232_ioctl(struct tty_struct *tty,
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return wait_modem_info(port, arg);
default:
dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
__func__, cmd);
@@ -358,6 +354,7 @@ static struct usb_serial_driver f81232_device = {
.set_termios = f81232_set_termios,
.tiocmget = f81232_tiocmget,
.tiocmset = f81232_tiocmset,
+ .tiocmiwait = f81232_tiocmiwait,
.process_read_urb = f81232_process_read_urb,
.read_int_callback = f81232_read_int_callback,
.port_probe = f81232_port_probe,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d4809d551473..242b5776648a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,7 +1,7 @@
/*
* USB FTDI SIO driver
*
- * Copyright (C) 2009 - 2010
+ * Copyright (C) 2009 - 2013
* Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
@@ -55,7 +55,6 @@ static __u16 vendor = FTDI_VID;
static __u16 product;
struct ftdi_private {
- struct kref kref;
enum ftdi_chip_type chip_type;
/* type of device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
@@ -68,7 +67,6 @@ struct ftdi_private {
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
- struct async_icount icount;
char prev_status; /* Used for TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
@@ -189,6 +187,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) },
{ USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -640,6 +639,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
{ USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
{ USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
+ { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
@@ -869,7 +869,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
+ { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID),
.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
{ USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
@@ -910,7 +912,6 @@ static int ftdi_sio_probe(struct usb_serial *serial,
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static void ftdi_process_read_urb(struct urb *urb);
static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
@@ -920,8 +921,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
static int ftdi_tiocmget(struct tty_struct *tty);
static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
@@ -950,7 +949,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.port_probe = ftdi_sio_port_probe,
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
- .close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
@@ -958,7 +956,8 @@ static struct usb_serial_driver ftdi_sio_device = {
.prepare_write_buffer = ftdi_prepare_write_buffer,
.tiocmget = ftdi_tiocmget,
.tiocmset = ftdi_tiocmset,
- .get_icount = ftdi_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
@@ -1687,7 +1686,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
return -ENOMEM;
}
- kref_init(&priv->kref);
mutex_init(&priv->cfg_lock);
priv->flags = ASYNC_LOW_LATENCY;
@@ -1791,20 +1789,24 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
}
/*
- * First and second port on STMCLiteadaptors is reserved for JTAG interface
- * and the forth port for pio
+ * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's
+ * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and
+ * can be accessed from userspace.
+ * The next two ports are enabled as UARTs by default, where port 2 is
+ * a conventional RS-232 UART.
*/
static int ftdi_stmclite_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- if (interface == udev->actconfig->interface[2])
- return 0;
-
- dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+ if (interface == udev->actconfig->interface[0] ||
+ interface == udev->actconfig->interface[1]) {
+ dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n");
+ return -ENODEV;
+ }
- return -ENODEV;
+ return 0;
}
/*
@@ -1825,22 +1827,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
return 0;
}
-static void ftdi_sio_priv_release(struct kref *k)
-{
- struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
-
- kfree(priv);
-}
-
static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- wake_up_interruptible(&port->delta_msr_wait);
-
remove_sysfs_attrs(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
+ kfree(priv);
return 0;
}
@@ -1850,7 +1843,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ktermios dummy;
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
- int result;
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
@@ -1869,12 +1861,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
ftdi_set_termios(tty, port, &dummy);
}
- /* Start reading from the device */
- result = usb_serial_generic_open(tty, port);
- if (!result)
- kref_get(&priv->kref);
-
- return result;
+ return usb_serial_generic_open(tty, port);
}
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
@@ -1899,19 +1886,6 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
-/*
- * usbserial:__serial_close only calls ftdi_close if the point is open
- *
- * This only gets called when it is the last close
- */
-static void ftdi_close(struct usb_serial_port *port)
-{
- struct ftdi_private *priv = usb_get_serial_port_data(port);
-
- usb_serial_generic_close(port);
- kref_put(&priv->kref, ftdi_sio_priv_release);
-}
-
/* The SIO requires the first byte to have:
* B0 1
* B1 0
@@ -1939,7 +1913,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
if (!c)
break;
- priv->icount.tx += c;
+ port->icount.tx += c;
buffer[i] = (c << 2) + 1;
count += c + 1;
}
@@ -1947,7 +1921,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
} else {
count = kfifo_out_locked(&port->write_fifo, dest, size,
&port->lock);
- priv->icount.tx += count;
+ port->icount.tx += count;
}
return count;
@@ -1976,15 +1950,15 @@ static int ftdi_process_packet(struct usb_serial_port *port,
char diff_status = status ^ priv->prev_status;
if (diff_status & FTDI_RS0_CTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (diff_status & FTDI_RS0_DSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (diff_status & FTDI_RS0_RI)
- priv->icount.rng++;
+ port->icount.rng++;
if (diff_status & FTDI_RS0_RLSD)
- priv->icount.dcd++;
+ port->icount.dcd++;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = status;
}
@@ -1994,18 +1968,18 @@ static int ftdi_process_packet(struct usb_serial_port *port,
* over framing errors */
if (packet[1] & FTDI_RS_BI) {
flag = TTY_BREAK;
- priv->icount.brk++;
+ port->icount.brk++;
usb_serial_handle_break(port);
} else if (packet[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
- priv->icount.parity++;
+ port->icount.parity++;
} else if (packet[1] & FTDI_RS_FE) {
flag = TTY_FRAME;
- priv->icount.frame++;
+ port->icount.frame++;
}
/* Overrun is special, not associated with a char */
if (packet[1] & FTDI_RS_OE) {
- priv->icount.overrun++;
+ port->icount.overrun++;
tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
}
@@ -2019,7 +1993,7 @@ static int ftdi_process_packet(struct usb_serial_port *port,
len -= 2;
if (!len)
return 0; /* status only */
- priv->icount.rx += len;
+ port->icount.rx += len;
ch = packet + 2;
if (port->port.console && port->sysrq) {
@@ -2383,34 +2357,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,
return update_mctrl(port, set, clear);
}
-static int ftdi_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount *ic = &priv->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd);
@@ -2424,35 +2374,6 @@ static int ftdi_ioctl(struct tty_struct *tty,
case TIOCSSERIAL: /* sets serial port data */
return set_serial_info(tty, port,
(struct serial_struct __user *) arg);
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was.
- *
- * This code is borrowed from linux/drivers/char/serial.c
- */
- case TIOCMIWAIT:
- cprev = priv->icount;
- for (;;) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = priv->icount;
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
break;
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 9d359e189a64..98528270c43c 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -74,6 +74,7 @@
#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
#define FTDI_OPENDCC_GBM_PID 0xBFDC
+#define FTDI_OPENDCC_GBM_BOOST_PID 0xBFDD
/* NZR SEM 16+ USB (http://www.nzr.de) */
#define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */
@@ -584,6 +585,13 @@
#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */
/*
+ * Mitsubishi Electric Corp. (http://www.meau.com)
+ * Submitted by Konstantin Holoborodko
+ */
+#define MITSUBISHI_VID 0x06D3
+#define MITSUBISHI_FXUSB_PID 0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */
+
+/*
* Definitions for B&B Electronics products.
*/
#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */
@@ -1143,7 +1151,8 @@
* STMicroelectonics
*/
#define ST_VID 0x0483
-#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */
+#define ST_STMCLT_2232_PID 0x3746
+#define ST_STMCLT_4232_PID 0x3747
/*
* Papouch products (http://www.papouch.com/)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 81caf5623ee2..b110c573ea85 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -946,16 +946,12 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
static void garmin_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",
__func__, port->number, garmin_data_p->mode,
garmin_data_p->state, garmin_data_p->flags);
- if (!serial)
- return;
-
garmin_clear(garmin_data_p);
/* shutdown our urbs */
@@ -1185,17 +1181,11 @@ static void garmin_read_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = urb->context;
- struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int retval;
- if (!serial) {
- dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__);
- return;
- }
-
if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
__func__, status);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 4c5c23f1cae5..297665fdd16d 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter Generic functions
*
- * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
@@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = {
},
.id_table = generic_device_ids,
.num_ports = 1,
- .disconnect = usb_serial_generic_disconnect,
- .release = usb_serial_generic_release,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
.resume = usb_serial_generic_resume,
@@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
}
EXPORT_SYMBOL_GPL(usb_serial_generic_open);
-static void generic_cleanup(struct usb_serial_port *port)
+void usb_serial_generic_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
unsigned long flags;
int i;
- if (serial->dev) {
- /* shutdown any bulk transfers that might be going on */
- if (port->bulk_out_size) {
- for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
+ if (port->bulk_out_size) {
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_kill_urb(port->write_urbs[i]);
- spin_lock_irqsave(&port->lock, flags);
- kfifo_reset_out(&port->write_fifo);
- spin_unlock_irqrestore(&port->lock, flags);
- }
- if (port->bulk_in_size) {
- for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
- }
+ spin_lock_irqsave(&port->lock, flags);
+ kfifo_reset_out(&port->write_fifo);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+ if (port->bulk_in_size) {
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_kill_urb(port->read_urbs[i]);
}
-}
-
-void usb_serial_generic_close(struct usb_serial_port *port)
-{
- generic_cleanup(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
if (!test_and_clear_bit(index, &port->read_urbs_free))
return 0;
- dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
- port->number, index);
+ dev_dbg(&port->dev, "%s - urb %d\n", __func__, index);
res = usb_submit_urb(port->read_urbs[index], mem_flags);
if (res) {
@@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
}
set_bit(i, &port->read_urbs_free);
- dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
- __func__, port->number, i, urb->actual_length);
+ dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
+ urb->actual_length);
if (urb->status) {
dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
@@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
+static bool usb_serial_generic_msr_changed(struct tty_struct *tty,
+ unsigned long arg, struct async_icount *cprev)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ bool ret;
+
+ /*
+ * Use tty-port initialised flag to detect all hangups including the
+ * one generated at USB-device disconnect.
+ *
+ * FIXME: Remove hupping check once tty_port_hangup calls shutdown
+ * (which clears the initialised flag) before wake up.
+ */
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ return true;
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ return true;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy*/
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts));
+
+ *cprev = cnow;
+
+ return ret;
+}
+
+int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ ret = wait_event_interruptible(port->port.delta_msr_wait,
+ usb_serial_generic_msr_changed(tty, arg, &cnow));
+ if (!ret) {
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ ret = -EIO;
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ret = -EIO;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait);
+
+int usb_serial_generic_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct async_icount cnow;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cnow = port->icount; /* atomic copy */
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ icount->cts = cnow.cts;
+ icount->dsr = cnow.dsr;
+ icount->rng = cnow.rng;
+ icount->dcd = cnow.dcd;
+ icount->tx = cnow.tx;
+ icount->rx = cnow.rx;
+ icount->frame = cnow.frame;
+ icount->parity = cnow.parity;
+ icount->overrun = cnow.overrun;
+ icount->brk = cnow.brk;
+ icount->buf_overrun = cnow.buf_overrun;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount);
+
#ifdef CONFIG_MAGIC_SYSRQ
int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
{
@@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
{
struct tty_port *port = &usb_port->port;
- dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
- usb_port->number, status);
+ dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
if (status)
wake_up_interruptible(&port->open_wait);
@@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial)
return c ? -EIO : 0;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
-
-void usb_serial_generic_disconnect(struct usb_serial *serial)
-{
- int i;
-
- /* stop reads and writes on all ports */
- for (i = 0; i < serial->num_ports; ++i)
- generic_cleanup(serial->port[i]);
-}
-EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
-
-void usb_serial_generic_release(struct usb_serial *serial)
-{
-}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index efd8b978128c..1477e8593476 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -111,7 +111,6 @@ struct edgeport_port {
wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */
wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
};
@@ -215,8 +214,6 @@ static void edge_break(struct tty_struct *tty, int break_state);
static int edge_tiocmget(struct tty_struct *tty);
static int edge_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static int edge_startup(struct usb_serial *serial);
static void edge_disconnect(struct usb_serial *serial);
static void edge_release(struct usb_serial *serial);
@@ -564,7 +561,6 @@ static void edge_interrupt_callback(struct urb *urb)
struct device *dev;
struct edgeport_port *edge_port;
struct usb_serial_port *port;
- struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int length = urb->actual_length;
int bytes_avail;
@@ -643,12 +639,7 @@ static void edge_interrupt_callback(struct urb *urb)
/* tell the tty driver that something
has changed */
- tty = tty_port_tty_get(
- &edge_port->port->port);
- if (tty) {
- tty_wakeup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_wakeup(&edge_port->port->port);
/* Since we have more credit, check
if more data can be sent */
send_more_port_data(edge_serial,
@@ -737,7 +728,6 @@ static void edge_bulk_in_callback(struct urb *urb)
static void edge_bulk_out_data_callback(struct urb *urb)
{
struct edgeport_port *edge_port = urb->context;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -746,14 +736,8 @@ static void edge_bulk_out_data_callback(struct urb *urb)
__func__, status);
}
- tty = tty_port_tty_get(&edge_port->port->port);
-
- if (tty && edge_port->open) {
- /* let the tty driver wakeup if it has a special
- write_wakeup function */
- tty_wakeup(tty);
- }
- tty_kref_put(tty);
+ if (edge_port->open)
+ tty_port_tty_wakeup(&edge_port->port->port);
/* Release the Write URB */
edge_port->write_in_progress = false;
@@ -772,7 +756,6 @@ static void edge_bulk_out_data_callback(struct urb *urb)
static void edge_bulk_out_cmd_callback(struct urb *urb)
{
struct edgeport_port *edge_port = urb->context;
- struct tty_struct *tty;
int status = urb->status;
atomic_dec(&CmdUrbs);
@@ -793,13 +776,9 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
return;
}
- /* Get pointer to tty */
- tty = tty_port_tty_get(&edge_port->port->port);
-
/* tell the tty driver that something has changed */
- if (tty && edge_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (edge_port->open)
+ tty_port_tty_wakeup(&edge_port->port->port);
/* we have completed the command */
edge_port->commandPending = false;
@@ -885,9 +864,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
init_waitqueue_head(&edge_port->wait_chase);
init_waitqueue_head(&edge_port->wait_command);
- /* initialize our icount structure */
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
/* initialize our port settings */
edge_port->txCredits = 0; /* Can't send any data yet */
/* Must always set this bit to enable ints! */
@@ -1314,7 +1290,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
/* decrement the number of credits we have by the number we just sent */
edge_port->txCredits -= count;
- edge_port->icount.tx += count;
+ edge_port->port->icount.tx += count;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
@@ -1326,7 +1302,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
/* revert the credits as something bad happened. */
edge_port->txCredits += count;
- edge_port->icount.tx -= count;
+ edge_port->port->icount.tx -= count;
}
dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n",
__func__, count, edge_port->txCredits, fifo->count);
@@ -1588,31 +1564,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- cnow = edge_port->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- port->number, icount->rx, icount->tx);
- return 0;
-}
-
static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
@@ -1649,8 +1600,6 @@ static int edge_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
DEFINE_WAIT(wait);
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
@@ -1662,37 +1611,6 @@ static int edge_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__, port->number);
return get_serial_info(edge_port, (struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number);
- cprev = edge_port->icount;
- while (1) {
- prepare_to_wait(&port->delta_msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&port->delta_msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
}
return -ENOIOCTLCMD;
}
@@ -1866,7 +1784,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,
edge_serial->rxPort);
edge_tty_recv(edge_port->port, buffer,
rxLen);
- edge_port->icount.rx += rxLen;
+ edge_port->port->icount.rx += rxLen;
}
buffer += rxLen;
}
@@ -2042,7 +1960,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
/* update input line counters */
if (newMsr & EDGEPORT_MSR_DELTA_CTS)
@@ -2053,7 +1971,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)
icount->dcd++;
if (newMsr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -2088,7 +2006,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,
edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (newLsr & LSR_BREAK)
icount->brk++;
if (newLsr & LSR_OVER_ERR)
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 1511dd0ad324..ae5fac5656c9 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -116,7 +116,8 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -147,7 +148,8 @@ static struct usb_serial_driver edgeport_4port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -178,7 +180,8 @@ static struct usb_serial_driver edgeport_8port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -209,7 +212,8 @@ static struct usb_serial_driver epic_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 7777172206de..158bf4bc29cc 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -86,7 +86,7 @@ struct edgeport_port {
int baud_rate;
int close_pending;
int lsr_event;
- struct async_icount icount;
+
struct edgeport_serial *edge_serial;
struct usb_serial_port *port;
__u8 bUartMode; /* Port type, 0: RS232, etc. */
@@ -206,7 +206,7 @@ static int restart_read(struct edgeport_port *edge_port);
static void edge_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
-static void edge_send(struct tty_struct *tty);
+static void edge_send(struct usb_serial_port *port, struct tty_struct *tty);
/* sysfs attributes */
static int edge_create_sysfs_attrs(struct usb_serial_port *port);
@@ -1445,7 +1445,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |
EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) {
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
/* update input line counters */
if (msr & EDGEPORT_MSR_DELTA_CTS)
@@ -1456,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)
icount->dcd++;
if (msr & EDGEPORT_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&edge_port->port->delta_msr_wait);
+ wake_up_interruptible(&edge_port->port->port.delta_msr_wait);
}
/* Save the new modem status */
@@ -1498,7 +1498,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,
edge_tty_recv(edge_port->port, &data, 1);
/* update input line counters */
- icount = &edge_port->icount;
+ icount = &edge_port->port->icount;
if (new_lsr & LSR_BREAK)
icount->brk++;
if (new_lsr & LSR_OVER_ERR)
@@ -1657,7 +1657,7 @@ static void edge_bulk_in_callback(struct urb *urb)
else
edge_tty_recv(edge_port->port, data,
urb->actual_length);
- edge_port->icount.rx += urb->actual_length;
+ edge_port->port->icount.rx += urb->actual_length;
}
exit:
@@ -1712,7 +1712,7 @@ static void edge_bulk_out_callback(struct urb *urb)
/* send any buffered data */
tty = tty_port_tty_get(&port->port);
- edge_send(tty);
+ edge_send(port, tty);
tty_kref_put(tty);
}
@@ -1750,8 +1750,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
dev = port->serial->dev;
- memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
/* turn off loopback */
status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);
if (status) {
@@ -1909,21 +1907,10 @@ static void edge_close(struct usb_serial_port *port)
kfifo_reset_out(&edge_port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- /* assuming we can still talk to the device,
- * send a close port command to it */
dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);
port_number = port->number - port->serial->minor;
-
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- send_cmd(serial->dev,
- UMPC_CLOSE_PORT,
- (__u8)(UMPM_UART1_PORT + port_number),
- 0,
- NULL,
- 0);
- }
- mutex_unlock(&serial->disc_mutex);
+ send_cmd(serial->dev, UMPC_CLOSE_PORT,
+ (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
@@ -1953,14 +1940,13 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
count = kfifo_in_locked(&edge_port->write_fifo, data, count,
&edge_port->ep_lock);
- edge_send(tty);
+ edge_send(port, tty);
return count;
}
-static void edge_send(struct tty_struct *tty)
+static void edge_send(struct usb_serial_port *port, struct tty_struct *tty)
{
- struct usb_serial_port *port = tty->driver_data;
int count, result;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
unsigned long flags;
@@ -1999,7 +1985,7 @@ static void edge_send(struct tty_struct *tty)
edge_port->ep_write_urb_in_use = 0;
/* TODO: reschedule edge_send */
} else
- edge_port->icount.tx += count;
+ edge_port->port->icount.tx += count;
/* wakeup any process waiting for writes to complete */
/* there is now more room in the buffer for new writes */
@@ -2360,27 +2346,6 @@ static int edge_tiocmget(struct tty_struct *tty)
return result;
}
-static int edge_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &edge_port->icount;
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->tx = ic->tx;
- icount->rx = ic->rx;
- icount->frame = ic->frame;
- icount->parity = ic->parity;
- icount->overrun = ic->overrun;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
- return 0;
-}
-
static int get_serial_info(struct edgeport_port *edge_port,
struct serial_struct __user *retinfo)
{
@@ -2392,7 +2357,7 @@ static int get_serial_info(struct edgeport_port *edge_port,
cwait = edge_port->port->port.closing_wait;
if (cwait != ASYNC_CLOSING_WAIT_NONE)
- cwait = jiffies_to_msecs(closing_wait) / 10;
+ cwait = jiffies_to_msecs(cwait) / 10;
memset(&tmp, 0, sizeof(tmp));
@@ -2416,8 +2381,6 @@ static int edge_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd);
@@ -2426,32 +2389,6 @@ static int edge_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);
return get_serial_info(edge_port,
(struct serial_struct __user *) arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = edge_port->icount;
- while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = edge_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* not reached */
- break;
}
return -ENOIOCTLCMD;
}
@@ -2463,8 +2400,6 @@ static void edge_break(struct tty_struct *tty, int break_state)
int status;
int bv = 0; /* Off */
- tty_wait_until_sent(tty, 0);
-
if (break_state == -1)
bv = 1; /* On */
status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv);
@@ -2546,7 +2481,6 @@ static int edge_port_remove(struct usb_serial_port *port)
struct edgeport_port *edge_port;
edge_port = usb_get_serial_port_data(port);
-
edge_remove_sysfs_attrs(port);
kfifo_free(&edge_port->write_fifo);
kfree(edge_port);
@@ -2618,7 +2552,8 @@ static struct usb_serial_driver edgeport_1port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
@@ -2649,7 +2584,8 @@ static struct usb_serial_driver edgeport_2port_device = {
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
.tiocmset = edge_tiocmset,
- .get_icount = edge_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index ff77027160aa..9d74c278b7b5 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -55,7 +55,6 @@ static void read_rxcmd_callback(struct urb *urb);
struct iuu_private {
spinlock_t lock; /* store irq state */
- wait_queue_head_t delta_msr_wait;
u8 line_status;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
u8 reset; /* if 1 reset is needed */
@@ -94,7 +93,6 @@ static int iuu_port_probe(struct usb_serial_port *port)
priv->vcc = vcc_default;
spin_lock_init(&priv->lock);
- init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
@@ -944,22 +942,13 @@ static void iuu_set_termios(struct tty_struct *tty,
static void iuu_close(struct usb_serial_port *port)
{
/* iuu_led (port,255,0,0,0); */
- struct usb_serial *serial;
-
- serial = port->serial;
- if (!serial)
- return;
iuu_uart_off(port);
- if (serial->dev) {
- /* free writebuf */
- /* shutdown our urbs */
- dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- iuu_led(port, 0, 0, 0xF000, 0xFF);
- }
+
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+
+ iuu_led(port, 0, 0, 0xF000, 0xFF);
}
static void iuu_init_termios(struct tty_struct *tty)
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 1fd1935c8316..eb30d7b01f36 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -378,7 +378,6 @@ static void usa26_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -421,12 +420,8 @@ static void usa26_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -510,7 +505,6 @@ static void usa28_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state;
int status = urb->status;
@@ -551,12 +545,8 @@ static void usa28_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -642,12 +632,8 @@ static void usa49_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -726,45 +712,45 @@ static void usa49wg_indat_callback(struct urb *urb)
i = 0;
len = 0;
- if (urb->actual_length) {
- while (i < urb->actual_length) {
+ while (i < urb->actual_length) {
- /* Check port number from message*/
- if (data[i] >= serial->num_ports) {
- dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
- __func__, data[i]);
- return;
- }
- port = serial->port[data[i++]];
- len = data[i++];
+ /* Check port number from message */
+ if (data[i] >= serial->num_ports) {
+ dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n",
+ __func__, data[i]);
+ return;
+ }
+ port = serial->port[data[i++]];
+ len = data[i++];
- /* 0x80 bit is error flag */
- if ((data[i] & 0x80) == 0) {
- /* no error on any byte */
- i++;
- for (x = 1; x < len ; ++x)
- tty_insert_flip_char(&port->port,
- data[i++], 0);
- } else {
- /*
- * some bytes had errors, every byte has status
- */
- for (x = 0; x + 1 < len; x += 2) {
- int stat = data[i], flag = 0;
- if (stat & RXERROR_OVERRUN)
- flag |= TTY_OVERRUN;
- if (stat & RXERROR_FRAMING)
- flag |= TTY_FRAME;
- if (stat & RXERROR_PARITY)
- flag |= TTY_PARITY;
- /* XXX should handle break (0x10) */
- tty_insert_flip_char(&port->port,
- data[i+1], flag);
- i += 2;
- }
+ /* 0x80 bit is error flag */
+ if ((data[i] & 0x80) == 0) {
+ /* no error on any byte */
+ i++;
+ for (x = 1; x < len && i < urb->actual_length; ++x)
+ tty_insert_flip_char(&port->port,
+ data[i++], 0);
+ } else {
+ /*
+ * some bytes had errors, every byte has status
+ */
+ for (x = 0; x + 1 < len &&
+ i + 1 < urb->actual_length; x += 2) {
+ int stat = data[i], flag = 0;
+
+ if (stat & RXERROR_OVERRUN)
+ flag |= TTY_OVERRUN;
+ if (stat & RXERROR_FRAMING)
+ flag |= TTY_FRAME;
+ if (stat & RXERROR_PARITY)
+ flag |= TTY_PARITY;
+ /* XXX should handle break (0x10) */
+ tty_insert_flip_char(&port->port, data[i+1],
+ flag);
+ i += 2;
}
- tty_flip_buffer_push(&port->port);
}
+ tty_flip_buffer_push(&port->port);
}
/* Resubmit urb so we continue receiving */
@@ -851,7 +837,6 @@ static void usa90_instat_callback(struct urb *urb)
struct usb_serial *serial;
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
- struct tty_struct *tty;
int old_dcd_state, err;
int status = urb->status;
@@ -880,12 +865,8 @@ static void usa90_instat_callback(struct urb *urb)
p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
p_priv->ri_state = ((msg->ri) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -953,12 +934,8 @@ static void usa67_instat_callback(struct urb *urb)
p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
- if (old_dcd_state != p_priv->dcd_state && old_dcd_state) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
+ tty_port_tty_hangup(&port->port, true);
/* Resubmit urb so we continue receiving */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1115,7 +1092,6 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
static void keyspan_close(struct usb_serial_port *port)
{
int i;
- struct usb_serial *serial = port->serial;
struct keyspan_port_private *p_priv;
p_priv = usb_get_serial_port_data(port);
@@ -1123,28 +1099,17 @@ static void keyspan_close(struct usb_serial_port *port)
p_priv->rts_state = 0;
p_priv->dtr_state = 0;
- if (serial->dev) {
- keyspan_send_setup(port, 2);
- /* pilot-xfer seems to work best with this delay */
- mdelay(100);
- /* keyspan_set_termios(port, NULL); */
- }
-
- /*while (p_priv->outcont_urb->status == -EINPROGRESS) {
- dev_dbg(&port->dev, "%s - urb in progress\n", __func__);
- }*/
+ keyspan_send_setup(port, 2);
+ /* pilot-xfer seems to work best with this delay */
+ mdelay(100);
p_priv->out_flip = 0;
p_priv->in_flip = 0;
- if (serial->dev) {
- /* Stop reading/writing urbs */
- stop_urb(p_priv->inack_urb);
- /* stop_urb(p_priv->outcont_urb); */
- for (i = 0; i < 2; i++) {
- stop_urb(p_priv->in_urbs[i]);
- stop_urb(p_priv->out_urbs[i]);
- }
+ stop_urb(p_priv->inack_urb);
+ for (i = 0; i < 2; i++) {
+ stop_urb(p_priv->in_urbs[i]);
+ stop_urb(p_priv->out_urbs[i]);
}
}
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 3b17d5d13dc8..5f1d382e55cf 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -104,10 +104,8 @@ static void keyspan_pda_wakeup_write(struct work_struct *work)
struct keyspan_pda_private *priv =
container_of(work, struct keyspan_pda_private, wakeup_work);
struct usb_serial_port *port = priv->port;
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty)
- tty_wakeup(tty);
- tty_kref_put(tty);
+
+ tty_port_tty_wakeup(&port->port);
}
static void keyspan_pda_request_unthrottle(struct work_struct *work)
@@ -595,12 +593,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
- if (serial->dev) {
- if (on)
- keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2));
- else
- keyspan_pda_set_modem_info(serial, 0);
- }
+ if (on)
+ keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2));
+ else
+ keyspan_pda_set_modem_info(serial, 0);
}
@@ -651,13 +647,8 @@ error:
}
static void keyspan_pda_close(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
-
- if (serial->dev) {
- /* shutdown our bulk reads and writes */
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->interrupt_in_urb);
- }
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 769d910ae0a5..1b4054fe52a5 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -341,28 +341,20 @@ static void klsi_105_close(struct usb_serial_port *port)
{
int rc;
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* send READ_OFF */
- rc = usb_control_msg(port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- dev_err(&port->dev,
- "Disabling read failed (error = %d)\n", rc);
- }
- mutex_unlock(&port->serial->disc_mutex);
+ /* send READ_OFF */
+ rc = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ dev_err(&port->dev, "failed to disable read: %d\n", rc);
/* shutdown our bulk reads and writes */
usb_serial_generic_close(port);
-
- /* wgg - do I need this? I think so. */
- usb_kill_urb(port->interrupt_in_urb);
}
/* We need to write a complete 64-byte data block and encode the
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 903d938e174b..78b48c31abf5 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -65,7 +65,7 @@ static int kobil_tiocmget(struct tty_struct *tty);
static int kobil_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback(struct urb *urb);
-static void kobil_write_callback(struct urb *purb);
+static void kobil_write_int_callback(struct urb *urb);
static void kobil_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void kobil_init_termios(struct tty_struct *tty);
@@ -99,6 +99,7 @@ static struct usb_serial_driver kobil_device = {
.write = kobil_write,
.write_room = kobil_write_room,
.read_int_callback = kobil_read_int_callback,
+ .write_int_callback = kobil_write_int_callback,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -106,8 +107,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
struct kobil_private {
- int write_int_endpoint_address;
- int read_int_endpoint_address;
unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */
int filled; /* index of the last char in buf */
int cur_pos; /* index of the next char to send in buf */
@@ -117,14 +116,8 @@ struct kobil_private {
static int kobil_port_probe(struct usb_serial_port *port)
{
- int i;
struct usb_serial *serial = port->serial;
struct kobil_private *priv;
- struct usb_device *pdev;
- struct usb_host_config *actconfig;
- struct usb_interface *interface;
- struct usb_host_interface *altsetting;
- struct usb_host_endpoint *endpoint;
priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL);
if (!priv)
@@ -150,30 +143,6 @@ static int kobil_port_probe(struct usb_serial_port *port)
}
usb_set_serial_port_data(port, priv);
- /* search for the necessary endpoints */
- pdev = serial->dev;
- actconfig = pdev->actconfig;
- interface = actconfig->interface[0];
- altsetting = interface->cur_altsetting;
- endpoint = altsetting->endpoint;
-
- for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
- endpoint = &altsetting->endpoint[i];
- if (usb_endpoint_is_int_out(&endpoint->desc)) {
- dev_dbg(&serial->dev->dev,
- "%s Found interrupt out endpoint. Address: %d\n",
- __func__, endpoint->desc.bEndpointAddress);
- priv->write_int_endpoint_address =
- endpoint->desc.bEndpointAddress;
- }
- if (usb_endpoint_is_int_in(&endpoint->desc)) {
- dev_dbg(&serial->dev->dev,
- "%s Found interrupt in endpoint. Address: %d\n",
- __func__, endpoint->desc.bEndpointAddress);
- priv->read_int_endpoint_address =
- endpoint->desc.bEndpointAddress;
- }
- }
return 0;
}
@@ -205,7 +174,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
- int write_urb_transfer_buffer_length = 8;
priv = usb_get_serial_port_data(port);
@@ -214,27 +182,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
if (!transfer_buffer)
return -ENOMEM;
- /* allocate write_urb */
- if (!port->write_urb) {
- dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__);
- port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urb) {
- dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__);
- kfree(transfer_buffer);
- return -ENOMEM;
- }
- }
-
- /* allocate memory for write_urb transfer buffer */
- port->write_urb->transfer_buffer =
- kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL);
- if (!port->write_urb->transfer_buffer) {
- kfree(transfer_buffer);
- usb_free_urb(port->write_urb);
- port->write_urb = NULL;
- return -ENOMEM;
- }
-
/* get hardware version */
result = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
@@ -310,12 +257,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
static void kobil_close(struct usb_serial_port *port)
{
/* FIXME: Add rts/dtr methods */
- if (port->write_urb) {
- usb_poison_urb(port->write_urb);
- kfree(port->write_urb->transfer_buffer);
- usb_free_urb(port->write_urb);
- port->write_urb = NULL;
- }
+ usb_kill_urb(port->interrupt_out_urb);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -333,24 +275,8 @@ static void kobil_read_int_callback(struct urb *urb)
}
if (urb->actual_length) {
-
- /* BEGIN DEBUG */
- /*
- char *dbg_data;
-
- dbg_data = kzalloc((3 * purb->actual_length + 10)
- * sizeof(char), GFP_KERNEL);
- if (! dbg_data) {
- return;
- }
- for (i = 0; i < purb->actual_length; i++) {
- sprintf(dbg_data +3*i, "%02X ", data[i]);
- }
- dev_dbg(&port->dev, " <-- %s\n", dbg_data);
- kfree(dbg_data);
- */
- /* END DEBUG */
-
+ usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
+ data);
tty_insert_flip_string(&port->port, data, urb->actual_length);
tty_flip_buffer_push(&port->port);
}
@@ -360,7 +286,7 @@ static void kobil_read_int_callback(struct urb *urb)
}
-static void kobil_write_callback(struct urb *purb)
+static void kobil_write_int_callback(struct urb *urb)
{
}
@@ -403,23 +329,14 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
while (todo > 0) {
/* max 8 byte in one urb (endpoint size) */
- length = (todo < 8) ? todo : 8;
+ length = min(todo, port->interrupt_out_size);
/* copy data to transfer buffer */
- memcpy(port->write_urb->transfer_buffer,
+ memcpy(port->interrupt_out_buffer,
priv->buf + priv->cur_pos, length);
- usb_fill_int_urb(port->write_urb,
- port->serial->dev,
- usb_sndintpipe(port->serial->dev,
- priv->write_int_endpoint_address),
- port->write_urb->transfer_buffer,
- length,
- kobil_write_callback,
- port,
- 8
- );
+ port->interrupt_out_urb->transfer_buffer_length = length;
priv->cur_pos = priv->cur_pos + length;
- result = usb_submit_urb(port->write_urb, GFP_NOIO);
+ result = usb_submit_urb(port->interrupt_out_urb, GFP_NOIO);
dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result);
todo = priv->filled - priv->cur_pos;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 06d5a60be2c4..6a15adf53360 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -35,7 +35,6 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <linux/ioctl.h>
#include "mct_u232.h"
#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
@@ -44,7 +43,6 @@
/*
* Function prototypes
*/
-static int mct_u232_startup(struct usb_serial *serial);
static int mct_u232_port_probe(struct usb_serial_port *port);
static int mct_u232_port_remove(struct usb_serial_port *remove);
static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
@@ -57,10 +55,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);
static int mct_u232_tiocmget(struct tty_struct *tty);
static int mct_u232_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static int mct_u232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
-static int mct_u232_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static void mct_u232_throttle(struct tty_struct *tty);
static void mct_u232_unthrottle(struct tty_struct *tty);
@@ -95,11 +89,10 @@ static struct usb_serial_driver mct_u232_device = {
.break_ctl = mct_u232_break_ctl,
.tiocmget = mct_u232_tiocmget,
.tiocmset = mct_u232_tiocmset,
- .attach = mct_u232_startup,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
.port_probe = mct_u232_port_probe,
.port_remove = mct_u232_port_remove,
- .ioctl = mct_u232_ioctl,
- .get_icount = mct_u232_get_icount,
+ .get_icount = usb_serial_generic_get_icount,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -107,13 +100,13 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
struct mct_u232_private {
+ struct urb *read_urb;
spinlock_t lock;
unsigned int control_state; /* Modem Line Setting (TIOCM) */
unsigned char last_lcr; /* Line Control Register */
unsigned char last_lsr; /* Line Status Register */
unsigned char last_msr; /* Modem Status Register */
unsigned int rx_flags; /* Throttling flags */
- struct async_icount icount;
};
#define THROTTLED 0x01
@@ -382,22 +375,6 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port,
* Driver's tty interface functions
*/
-static int mct_u232_startup(struct usb_serial *serial)
-{
- struct usb_serial_port *port, *rport;
-
- /* Puh, that's dirty */
- port = serial->port[0];
- rport = serial->port[1];
- /* No unlinking, it wasn't submitted yet. */
- usb_free_urb(port->read_urb);
- port->read_urb = rport->interrupt_in_urb;
- rport->interrupt_in_urb = NULL;
- port->read_urb->context = port;
-
- return 0;
-} /* mct_u232_startup */
-
static int mct_u232_port_probe(struct usb_serial_port *port)
{
struct mct_u232_private *priv;
@@ -406,6 +383,10 @@ static int mct_u232_port_probe(struct usb_serial_port *port)
if (!priv)
return -ENOMEM;
+ /* Use second interrupt-in endpoint for reading. */
+ priv->read_urb = port->serial->port[1]->interrupt_in_urb;
+ priv->read_urb->context = port;
+
spin_lock_init(&priv->lock);
usb_set_serial_port_data(port, priv);
@@ -469,17 +450,17 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
spin_unlock_irqrestore(&priv->lock, flags);
- retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ retval = usb_submit_urb(priv->read_urb, GFP_KERNEL);
if (retval) {
dev_err(&port->dev,
- "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n",
+ "usb_submit_urb(read) failed pipe 0x%x err %d\n",
port->read_urb->pipe, retval);
goto error;
}
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
- usb_kill_urb(port->read_urb);
+ usb_kill_urb(priv->read_urb);
dev_err(&port->dev,
"usb_submit_urb(read int) failed pipe 0x%x err %d",
port->interrupt_in_urb->pipe, retval);
@@ -509,11 +490,9 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
static void mct_u232_close(struct usb_serial_port *port)
{
- /*
- * Must kill the read urb as it is actually an interrupt urb, which
- * generic close thus fails to kill.
- */
- usb_kill_urb(port->read_urb);
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+
+ usb_kill_urb(priv->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_serial_generic_close(port);
@@ -570,7 +549,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
/* Record Control Line states */
mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr);
- mct_u232_msr_to_icount(&priv->icount, priv->last_msr);
+ mct_u232_msr_to_icount(&port->icount, priv->last_msr);
#if 0
/* Not yet handled. See belkin_sa.c for further information */
@@ -598,7 +577,7 @@ static void mct_u232_read_int_callback(struct urb *urb)
tty_kref_put(tty);
}
#endif
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
spin_unlock_irqrestore(&priv->lock, flags);
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -786,86 +765,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
}
}
-static int mct_u232_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- DEFINE_WAIT(wait);
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount cnow, cprev;
- unsigned long flags;
-
- dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd);
-
- switch (cmd) {
-
- case TIOCMIWAIT:
-
- dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__);
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cprev = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- for ( ; ; ) {
- prepare_to_wait(&port->delta_msr_wait,
- &wait, TASK_INTERRUPTIBLE);
- schedule();
- finish_wait(&port->delta_msr_wait, &wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
- cnow = mct_u232_port->icount;
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
-
- }
- return -ENOIOCTLCMD;
-}
-
-static int mct_u232_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
- struct async_icount *ic = &mct_u232_port->icount;
- unsigned long flags;
-
- spin_lock_irqsave(&mct_u232_port->lock, flags);
-
- icount->cts = ic->cts;
- icount->dsr = ic->dsr;
- icount->rng = ic->rng;
- icount->dcd = ic->dcd;
- icount->rx = ic->rx;
- icount->tx = ic->tx;
- icount->frame = ic->frame;
- icount->overrun = ic->overrun;
- icount->parity = ic->parity;
- icount->brk = ic->brk;
- icount->buf_overrun = ic->buf_overrun;
-
- spin_unlock_irqrestore(&mct_u232_port->lock, flags);
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n",
- __func__, icount->rx, icount->tx);
- return 0;
-}
-
module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index bf3c7a23553e..47e247759eb0 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -177,10 +177,7 @@ static void metrousb_cleanup(struct usb_serial_port *port)
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected)
- metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
- mutex_unlock(&port->serial->disc_mutex);
+ metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
}
static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e0ebec3b5d6a..cc0e54345df9 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -62,7 +62,6 @@ struct moschip_port {
__u8 shadowMCR; /* last MCR value received */
__u8 shadowMSR; /* last MSR value received */
char open;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner */
struct urb *write_urb_pool[NUM_URBS];
};
@@ -932,7 +931,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
static void mos7720_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7720_port;
- struct tty_struct *tty;
int status = urb->status;
if (status) {
@@ -946,11 +944,8 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
return ;
}
- tty = tty_port_tty_get(&mos7720_port->port->port);
-
- if (tty && mos7720_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (mos7720_port->open)
+ tty_port_tty_wakeup(&mos7720_port->port->port);
}
/*
@@ -1075,9 +1070,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
dev_err(&port->dev, "%s - Error %d submitting read urb\n",
__func__, response);
- /* initialize our icount structure */
- memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
-
/* initialize our port settings */
mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
@@ -1144,16 +1136,9 @@ static void mos7720_close(struct usb_serial_port *port)
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- mutex_lock(&serial->disc_mutex);
- /* these commands must not be issued if the device has
- * been disconnected */
- if (!serial->disconnected) {
- write_mos_reg(serial, port->number - port->serial->minor,
- MCR, 0x00);
- write_mos_reg(serial, port->number - port->serial->minor,
- IER, 0x00);
- }
- mutex_unlock(&serial->disc_mutex);
+ write_mos_reg(serial, port->number - port->serial->minor, MCR, 0x00);
+ write_mos_reg(serial, port->number - port->serial->minor, IER, 0x00);
+
mos7720_port->open = 0;
}
@@ -1803,33 +1788,6 @@ static int mos7720_tiocmset(struct tty_struct *tty,
return 0;
}
-static int mos7720_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7720_port;
- struct async_icount cnow;
-
- mos7720_port = usb_get_serial_port_data(port);
- cnow = mos7720_port->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- icount->rx, icount->tx);
- return 0;
-}
-
static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
unsigned int __user *value)
{
@@ -1905,8 +1863,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
struct moschip_port *mos7720_port;
- struct async_icount cnow;
- struct async_icount cprev;
mos7720_port = usb_get_serial_port_data(port);
if (mos7720_port == NULL)
@@ -1931,27 +1887,6 @@ static int mos7720_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);
return get_serial_info(mos7720_port,
(struct serial_struct __user *)arg);
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- cprev = mos7720_port->icount;
- while (1) {
- if (signal_pending(current))
- return -ERESTARTSYS;
- cnow = mos7720_port->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
}
return -ENOIOCTLCMD;
@@ -2107,7 +2042,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.ioctl = mos7720_ioctl,
.tiocmget = mos7720_tiocmget,
.tiocmset = mos7720_tiocmset,
- .get_icount = mos7720_get_icount,
.set_termios = mos7720_set_termios,
.write = mos7720_write,
.write_room = mos7720_write_room,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index b8051fa61911..a0d5ea545982 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -219,8 +219,6 @@ struct moschip_port {
char open;
char open_ports;
wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
- int delta_msr_cond;
- struct async_icount icount;
struct usb_serial_port *port; /* loop back to the owner of this object */
/* Offsets */
@@ -399,32 +397,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
struct moschip_port *mos7840_port;
struct async_icount *icount;
mos7840_port = port;
- icount = &mos7840_port->icount;
if (new_msr &
(MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
MOS_MSR_DELTA_CD)) {
- icount = &mos7840_port->icount;
+ icount = &mos7840_port->port->icount;
/* update input line counters */
- if (new_msr & MOS_MSR_DELTA_CTS) {
+ if (new_msr & MOS_MSR_DELTA_CTS)
icount->cts++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_DSR) {
+ if (new_msr & MOS_MSR_DELTA_DSR)
icount->dsr++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_CD) {
+ if (new_msr & MOS_MSR_DELTA_CD)
icount->dcd++;
- smp_wmb();
- }
- if (new_msr & MOS_MSR_DELTA_RI) {
+ if (new_msr & MOS_MSR_DELTA_RI)
icount->rng++;
- smp_wmb();
- }
- mos7840_port->delta_msr_cond = 1;
- wake_up_interruptible(&port->port->delta_msr_wait);
+ wake_up_interruptible(&port->port->port.delta_msr_wait);
}
}
@@ -442,23 +430,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
}
/* update input line counters */
- icount = &port->icount;
- if (new_lsr & SERIAL_LSR_BI) {
+ icount = &port->port->icount;
+ if (new_lsr & SERIAL_LSR_BI)
icount->brk++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_OE) {
+ if (new_lsr & SERIAL_LSR_OE)
icount->overrun++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_PE) {
+ if (new_lsr & SERIAL_LSR_PE)
icount->parity++;
- smp_wmb();
- }
- if (new_lsr & SERIAL_LSR_FE) {
+ if (new_lsr & SERIAL_LSR_FE)
icount->frame++;
- smp_wmb();
- }
}
/************************************************************************/
@@ -777,9 +757,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct tty_port *tport = &mos7840_port->port->port;
tty_insert_flip_string(tport, data, urb->actual_length);
tty_flip_buffer_push(tport);
- mos7840_port->icount.rx += urb->actual_length;
- smp_wmb();
- dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx);
+ port->icount.rx += urb->actual_length;
+ dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);
}
if (!mos7840_port->read_urb) {
@@ -816,7 +795,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7840_port;
struct usb_serial_port *port;
- struct tty_struct *tty;
int status = urb->status;
int i;
@@ -839,10 +817,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
if (mos7840_port_paranoia_check(port, __func__))
return;
- tty = tty_port_tty_get(&port->port);
- if (tty && mos7840_port->open)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (mos7840_port->open)
+ tty_port_tty_wakeup(&port->port);
}
@@ -1130,17 +1106,12 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
/* initialize our wait queues */
init_waitqueue_head(&mos7840_port->wait_chase);
- /* initialize our icount structure */
- memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
-
/* initialize our port settings */
/* Must set to enable ints! */
mos7840_port->shadowMCR = MCR_MASTER_IE;
/* send a open port command */
mos7840_port->open = 1;
/* mos7840_change_port_settings(mos7840_port,old_termios); */
- mos7840_port->icount.tx = 0;
- mos7840_port->icount.rx = 0;
return 0;
}
@@ -1223,25 +1194,10 @@ static void mos7840_close(struct usb_serial_port *port)
}
}
- /* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- if (mos7840_port->write_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk write\n");
- usb_kill_urb(mos7840_port->write_urb);
- }
- if (mos7840_port->read_urb) {
- dev_dbg(&port->dev, "%s", "Shutdown bulk read\n");
- usb_kill_urb(mos7840_port->read_urb);
- mos7840_port->read_urb_busy = false;
- }
- if ((&mos7840_port->control_urb)) {
- dev_dbg(&port->dev, "%s", "Shutdown control read\n");
- /*/ usb_kill_urb (mos7840_port->control_urb); */
- }
- }
-/* if(mos7840_port->ctrl_buf != NULL) */
-/* kfree(mos7840_port->ctrl_buf); */
+ usb_kill_urb(mos7840_port->write_urb);
+ usb_kill_urb(mos7840_port->read_urb);
+ mos7840_port->read_urb_busy = false;
+
port0->open_ports--;
dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);
if (port0->open_ports == 0) {
@@ -1253,8 +1209,7 @@ static void mos7840_close(struct usb_serial_port *port)
if (mos7840_port->write_urb) {
/* if this urb had a transfer buffer already (old tx) free it */
- if (mos7840_port->write_urb->transfer_buffer != NULL)
- kfree(mos7840_port->write_urb->transfer_buffer);
+ kfree(mos7840_port->write_urb->transfer_buffer);
usb_free_urb(mos7840_port->write_urb);
}
@@ -1331,9 +1286,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
if (mos7840_port == NULL)
return;
- if (serial->dev)
- /* flush and block until tx is empty */
- mos7840_block_until_chase_response(tty, mos7840_port);
+ /* flush and block until tx is empty */
+ mos7840_block_until_chase_response(tty, mos7840_port);
if (break_state == -1)
data = mos7840_port->shadowLCR | LCR_SET_BREAK;
@@ -1523,9 +1477,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
goto exit;
}
bytes_sent = transfer_size;
- mos7840_port->icount.tx += transfer_size;
- smp_wmb();
- dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+ port->icount.tx += transfer_size;
+ dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx);
exit:
return bytes_sent;
@@ -2144,34 +2097,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
return 0;
}
-static int mos7840_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct moschip_port *mos7840_port;
- struct async_icount cnow;
-
- mos7840_port = mos7840_get_port_private(port);
- cnow = mos7840_port->icount;
-
- smp_rmb();
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- icount->rx, icount->tx);
- return 0;
-}
-
/*****************************************************************************
* SerialIoctl
* this function handles any ioctl calls to the driver
@@ -2184,9 +2109,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
void __user *argp = (void __user *)arg;
struct moschip_port *mos7840_port;
- struct async_icount cnow;
- struct async_icount cprev;
-
if (mos7840_port_paranoia_check(port, __func__))
return -1;
@@ -2211,41 +2133,6 @@ static int mos7840_ioctl(struct tty_struct *tty,
case TIOCSSERIAL:
dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);
break;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- cprev = mos7840_port->icount;
- while (1) {
- /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */
- mos7840_port->delta_msr_cond = 0;
- wait_event_interruptible(port->delta_msr_wait,
- (port->serial->disconnected ||
- mos7840_port->
- delta_msr_cond == 1));
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = mos7840_port->icount;
- smp_rmb();
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
- break;
-
default:
break;
}
@@ -2592,7 +2479,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
.break_ctl = mos7840_break,
.tiocmget = mos7840_tiocmget,
.tiocmset = mos7840_tiocmset,
- .get_icount = mos7840_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.port_probe = mos7840_port_probe,
.port_remove = mos7840_port_remove,
.read_bulk_callback = mos7840_bulk_in_callback,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 1e1cafe287e4..5739bf6f7200 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -33,8 +33,7 @@
/* function prototypes */
static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port);
-static void omninet_close(struct usb_serial_port *port);
-static void omninet_read_bulk_callback(struct urb *urb);
+static void omninet_process_read_urb(struct urb *urb);
static void omninet_write_bulk_callback(struct urb *urb);
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -61,11 +60,10 @@ static struct usb_serial_driver zyxel_omninet_device = {
.port_probe = omninet_port_probe,
.port_remove = omninet_port_remove,
.open = omninet_open,
- .close = omninet_close,
.write = omninet_write,
.write_room = omninet_write_room,
- .read_bulk_callback = omninet_read_bulk_callback,
.write_bulk_callback = omninet_write_bulk_callback,
+ .process_read_urb = omninet_process_read_urb,
.disconnect = omninet_disconnect,
};
@@ -74,29 +72,28 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
-/* The protocol.
+/*
+ * The protocol.
*
* The omni.net always exchange 64 bytes of data with the host. The first
- * four bytes are the control header, you can see it in the above structure.
+ * four bytes are the control header.
*
* oh_seq is a sequence number. Don't know if/how it's used.
* oh_len is the length of the data bytes in the packet.
* oh_xxx Bit-mapped, related to handshaking and status info.
- * I normally set it to 0x03 in trasmitted frames.
+ * I normally set it to 0x03 in transmitted frames.
* 7: Active when the TA is in a CONNECTed state.
* 6: unknown
* 5: handshaking, unknown
* 4: handshaking, unknown
* 3: unknown, usually 0
* 2: unknown, usually 0
- * 1: handshaking, unknown, usually set to 1 in trasmitted frames
- * 0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * 1: handshaking, unknown, usually set to 1 in transmitted frames
+ * 0: handshaking, unknown, usually set to 1 in transmitted frames
* oh_pad Probably a pad byte.
*
* After the header you will find data bytes if oh_len was greater than zero.
- *
*/
-
struct omninet_header {
__u8 oh_seq;
__u8 oh_len;
@@ -112,7 +109,7 @@ static int omninet_port_probe(struct usb_serial_port *port)
{
struct omninet_data *od;
- od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL);
+ od = kzalloc(sizeof(*od), GFP_KERNEL);
if (!od)
return -ENOMEM;
@@ -135,56 +132,32 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
- int result = 0;
wport = serial->port[1];
tty_port_tty_set(&wport->port, tty);
- /* Start reading from the device */
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __func__, result);
- return result;
-}
-
-static void omninet_close(struct usb_serial_port *port)
-{
- usb_kill_urb(port->read_urb);
+ return usb_serial_generic_open(tty, port);
}
+#define OMNINET_HEADERLEN 4
+#define OMNINET_BULKOUTSIZE 64
+#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN)
-#define OMNINET_DATAOFFSET 0x04
-#define OMNINET_HEADERLEN sizeof(struct omninet_header)
-#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
-
-static void omninet_read_bulk_callback(struct urb *urb)
+static void omninet_process_read_urb(struct urb *urb)
{
- struct usb_serial_port *port = urb->context;
- unsigned char *data = urb->transfer_buffer;
- struct omninet_header *header = (struct omninet_header *) &data[0];
- int status = urb->status;
- int result;
+ struct usb_serial_port *port = urb->context;
+ const struct omninet_header *hdr = urb->transfer_buffer;
+ const unsigned char *data;
+ size_t data_len;
- if (status) {
- dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n",
- __func__, status);
+ if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len)
return;
- }
-
- if (urb->actual_length && header->oh_len) {
- tty_insert_flip_string(&port->port, data + OMNINET_DATAOFFSET,
- header->oh_len);
- tty_flip_buffer_push(&port->port);
- }
- /* Continue trying to always read */
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
+ data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN;
+ data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN,
+ hdr->oh_len);
+ tty_insert_flip_string(&port->port, data, data_len);
+ tty_flip_buffer_push(&port->port);
}
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -209,9 +182,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
return 0;
}
- count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+ count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count;
- memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET,
+ memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN,
buf, count);
usb_serial_debug_data(&port->dev, __func__, count,
@@ -223,7 +196,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
header->oh_pad = 0x00;
/* send the data out the bulk port, always 64 bytes */
- wport->write_urb->transfer_buffer_length = 64;
+ wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index e13e1a4d3e1e..5f4b0cd0f6e9 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -120,7 +120,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype,
0, 0, buffer, 1, 0);
kfree(buffer);
- return retval;
+ if (retval < 0)
+ return retval;
+
+ return 0;
}
static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -306,7 +309,6 @@ static int opticon_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct opticon_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
bool rts;
@@ -327,15 +329,11 @@ static int opticon_tiocmset(struct tty_struct *tty,
if (!changed)
return 0;
- /* Send the new RTS state to the connected device */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = send_control_msg(port, CONTROL_RTS, !rts);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = send_control_msg(port, CONTROL_RTS, !rts);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int get_serial_info(struct usb_serial_port *port,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 558adfc05007..734372846abb 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -347,6 +347,7 @@ static void option_instat_callback(struct urb *urb);
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
+#define OLIVETTI_PRODUCT_OLICARD145 0xc003
/* Celot products */
#define CELOT_VENDOR_ID 0x211f
@@ -1273,6 +1274,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
+ { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
@@ -1350,6 +1352,12 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180),
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1537,13 +1545,8 @@ static void option_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- if (old_dcd_state && !portdata->dcd_state) {
- struct tty_struct *tty =
- tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty))
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ if (old_dcd_state && !portdata->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
} else {
dev_dbg(dev, "%s: type %x req %x\n", __func__,
req_pkt->bRequestType, req_pkt->bRequest);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 87c71ccfee87..7e3e0782e51f 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void oti6858_init_termios(struct tty_struct *tty);
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg);
static void oti6858_read_int_callback(struct urb *urb);
static void oti6858_read_bulk_callback(struct urb *urb);
static void oti6858_write_bulk_callback(struct urb *urb);
@@ -136,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);
static int oti6858_tiocmget(struct tty_struct *tty);
static int oti6858_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg);
static int oti6858_port_probe(struct usb_serial_port *port);
static int oti6858_port_remove(struct usb_serial_port *port);
@@ -150,11 +149,11 @@ static struct usb_serial_driver oti6858_device = {
.open = oti6858_open,
.close = oti6858_close,
.write = oti6858_write,
- .ioctl = oti6858_ioctl,
.set_termios = oti6858_set_termios,
.init_termios = oti6858_init_termios,
.tiocmget = oti6858_tiocmget,
.tiocmset = oti6858_tiocmset,
+ .tiocmiwait = oti6858_tiocmiwait,
.read_bulk_callback = oti6858_read_bulk_callback,
.read_int_callback = oti6858_read_int_callback,
.write_bulk_callback = oti6858_write_bulk_callback,
@@ -650,8 +649,9 @@ static int oti6858_tiocmget(struct tty_struct *tty)
return result;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prev, status;
@@ -662,7 +662,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- wait_event_interruptible(port->delta_msr_wait,
+ wait_event_interruptible(port->port.delta_msr_wait,
port->serial->disconnected ||
priv->status.pin_state != prev);
if (signal_pending(current))
@@ -689,24 +689,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int oti6858_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
- default:
- dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd);
- break;
- }
- return -ENOIOCTLCMD;
-}
-
static void oti6858_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -765,7 +747,7 @@ static void oti6858_read_int_callback(struct urb *urb)
if (!priv->transient) {
if (xs->pin_state != priv->status.pin_state)
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
}
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3b10018d89a3..7151659367a0 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -149,7 +149,7 @@ static int pl2303_vendor_read(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
value, index, buf, 1, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
+ dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
res, buf[0]);
return res;
@@ -161,7 +161,7 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
- dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
+ dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
res);
return res;
@@ -248,14 +248,15 @@ static int pl2303_port_remove(struct usb_serial_port *port)
return 0;
}
-static int set_control_lines(struct usb_device *dev, u8 value)
+static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)
{
+ struct usb_device *dev = port->serial->dev;
int retval;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+ dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__,
value, retval);
return retval;
}
@@ -437,7 +438,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(serial->dev, control);
+ pl2303_set_control_lines(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -480,7 +481,7 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- set_control_lines(port->serial->dev, control);
+ pl2303_set_control_lines(port, control);
}
static void pl2303_close(struct usb_serial_port *port)
@@ -530,7 +531,6 @@ static int pl2303_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
@@ -548,14 +548,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- ret = set_control_lines(serial->dev, control);
- else
- ret = -ENODEV;
- mutex_unlock(&serial->disc_mutex);
+ ret = pl2303_set_control_lines(port, control);
+ if (ret)
+ return usb_translate_errors(ret);
- return ret;
+ return 0;
}
static int pl2303_tiocmget(struct tty_struct *tty)
@@ -592,8 +589,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+static int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)
{
+ struct usb_serial_port *port = tty->driver_data;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int prevstatus;
@@ -605,7 +603,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
+ interruptible_sleep_on(&port->port.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
@@ -651,10 +649,6 @@ static int pl2303_ioctl(struct tty_struct *tty,
return -EFAULT;
return 0;
-
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
- return wait_modem_info(port, arg);
default:
dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
break;
@@ -720,7 +714,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
spin_unlock_irqrestore(&priv->lock, flags);
if (priv->line_status & UART_BREAK_ERROR)
usb_serial_handle_break(port);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
tty = tty_port_tty_get(&port->port);
if (!tty)
@@ -784,7 +778,7 @@ static void pl2303_process_read_urb(struct urb *urb)
line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
if (!urb->actual_length)
return;
@@ -835,6 +829,7 @@ static struct usb_serial_driver pl2303_device = {
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
.tiocmset = pl2303_tiocmset,
+ .tiocmiwait = pl2303_tiocmiwait,
.process_read_urb = pl2303_process_read_urb,
.read_int_callback = pl2303_read_int_callback,
.attach = pl2303_startup,
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index 75f125ddb0c9..02b0803425c5 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -116,7 +116,6 @@ struct qt2_serial_private {
};
struct qt2_port_private {
- bool is_open;
u8 device_port;
spinlock_t urb_lock;
@@ -128,8 +127,6 @@ struct qt2_port_private {
u8 shadowLSR;
u8 shadowMSR;
- struct async_icount icount;
-
struct usb_serial_port *port;
};
@@ -397,7 +394,6 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
return status;
}
- port_priv->is_open = true;
port_priv->device_port = (u8) device_port;
if (tty)
@@ -417,19 +413,11 @@ static void qt2_close(struct usb_serial_port *port)
serial = port->serial;
port_priv = usb_get_serial_port_data(port);
- port_priv->is_open = false;
-
spin_lock_irqsave(&port_priv->urb_lock, flags);
usb_kill_urb(port_priv->write_urb);
port_priv->urb_in_use = false;
spin_unlock_irqrestore(&port_priv->urb_lock, flags);
- mutex_lock(&port->serial->disc_mutex);
- if (port->serial->disconnected) {
- mutex_unlock(&port->serial->disc_mutex);
- return;
- }
-
/* flush the port transmit buffer */
i = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
@@ -460,8 +448,6 @@ static void qt2_close(struct usb_serial_port *port)
if (i < 0)
dev_err(&port->dev, "%s - close port failed %i\n",
__func__, i);
-
- mutex_unlock(&port->serial->disc_mutex);
}
static void qt2_disconnect(struct usb_serial *serial)
@@ -494,71 +480,6 @@ static int get_serial_info(struct usb_serial_port *port,
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct qt2_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount prev, cur;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- prev = priv->icount;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- wait_event_interruptible(port->delta_msr_wait,
- (port->serial->disconnected ||
- (priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int qt2_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct qt2_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int qt2_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -568,10 +489,6 @@ static int qt2_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
return get_serial_info(port,
(struct serial_struct __user *)arg);
-
- case TIOCMIWAIT:
- return wait_modem_info(port, arg);
-
default:
break;
}
@@ -664,9 +581,7 @@ void qt2_process_read_urb(struct urb *urb)
__func__);
break;
}
-
- if (port_priv->is_open)
- tty_flip_buffer_push(&port->port);
+ tty_flip_buffer_push(&port->port);
newport = *(ch + 3);
@@ -709,8 +624,7 @@ void qt2_process_read_urb(struct urb *urb)
tty_insert_flip_string(&port->port, ch, 1);
}
- if (port_priv->is_open)
- tty_flip_buffer_push(&port->port);
+ tty_flip_buffer_push(&port->port);
}
static void qt2_write_bulk_callback(struct urb *urb)
@@ -910,12 +824,6 @@ static void qt2_break_ctl(struct tty_struct *tty, int break_state)
port_priv = usb_get_serial_port_data(port);
- if (!port_priv->is_open) {
- dev_err(&port->dev,
- "%s - port is not open\n", __func__);
- return;
- }
-
val = (break_state == -1) ? 1 : 0;
status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
@@ -961,18 +869,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
if (newMSR & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (newMSR & UART_MSR_DCTS)
- port_priv->icount.cts++;
-
+ port->icount.cts++;
if (newMSR & UART_MSR_DDSR)
- port_priv->icount.dsr++;
-
+ port->icount.dsr++;
if (newMSR & UART_MSR_DDCD)
- port_priv->icount.dcd++;
-
+ port->icount.dcd++;
if (newMSR & UART_MSR_TERI)
- port_priv->icount.rng++;
+ port->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -992,7 +897,7 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
port_priv->shadowLSR = newLSR;
spin_unlock_irqrestore(&port_priv->lock, flags);
- icount = &port_priv->icount;
+ icount = &port->icount;
if (newLSR & UART_LSR_BRK_ERROR_BITS) {
@@ -1102,7 +1007,8 @@ static struct usb_serial_driver qt2_device = {
.break_ctl = qt2_break_ctl,
.tiocmget = qt2_tiocmget,
.tiocmset = qt2_tiocmset,
- .get_icount = qt2_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = qt2_ioctl,
.set_termios = qt2_set_termios,
};
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index c13f6e747748..8894665cd610 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -628,7 +628,6 @@ static void sierra_instat_callback(struct urb *urb)
unsigned char signals = *((unsigned char *)
urb->transfer_buffer +
sizeof(struct usb_ctrlrequest));
- struct tty_struct *tty;
dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
signals);
@@ -639,11 +638,8 @@ static void sierra_instat_callback(struct urb *urb)
portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
portdata->ri_state = ((signals & 0x08) ? 1 : 0);
- tty = tty_port_tty_get(&port->port);
- if (tty && !C_CLOCAL(tty) &&
- old_dcd_state && !portdata->dcd_state)
- tty_hangup(tty);
- tty_kref_put(tty);
+ if (old_dcd_state && !portdata->dcd_state)
+ tty_port_tty_hangup(&port->port, true);
} else {
dev_dbg(&port->dev, "%s: type %x req %x\n",
__func__, req_pkt->bRequestType,
@@ -778,30 +774,25 @@ static void sierra_close(struct usb_serial_port *port)
portdata->rts_state = 0;
portdata->dtr_state = 0;
- if (serial->dev) {
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected) {
- serial->interface->needs_remote_wakeup = 0;
- /* odd error handling due to pm counters */
- if (!usb_autopm_get_interface(serial->interface))
- sierra_send_setup(port);
- else
- usb_autopm_get_interface_no_resume(serial->interface);
-
- }
- mutex_unlock(&serial->disc_mutex);
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected) {
+ serial->interface->needs_remote_wakeup = 0;
+ /* odd error handling due to pm counters */
+ if (!usb_autopm_get_interface(serial->interface))
+ sierra_send_setup(port);
+ else
+ usb_autopm_get_interface_no_resume(serial->interface);
+ }
+ mutex_unlock(&serial->disc_mutex);
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
- /* Stop reading urbs */
- sierra_stop_rx_urbs(port);
- /* .. and release them */
- for (i = 0; i < portdata->num_in_urbs; i++) {
- sierra_release_urb(portdata->in_urbs[i]);
- portdata->in_urbs[i] = NULL;
- }
+ sierra_stop_rx_urbs(port);
+ for (i = 0; i < portdata->num_in_urbs; i++) {
+ sierra_release_urb(portdata->in_urbs[i]);
+ portdata->in_urbs[i] = NULL;
}
}
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 549ef68ff5fa..cf3df793c2b7 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -1,7 +1,7 @@
/*
* spcp8x5 USB to serial adaptor driver
*
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)
* Copyright (C) 2006 S1 Corp.
*
@@ -13,8 +13,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- *
*/
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -28,7 +26,10 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
-#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
+#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver"
+
+#define SPCP825_QUIRK_NO_UART_STATUS 0x01
+#define SPCP825_QUIRK_NO_WORK_MODE 0x02
#define SPCP8x5_007_VID 0x04FC
#define SPCP8x5_007_PID 0x0201
@@ -46,13 +47,15 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
{ USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)},
- { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)},
+ { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID),
+ .driver_info = SPCP825_QUIRK_NO_UART_STATUS |
+ SPCP825_QUIRK_NO_WORK_MODE },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
struct spcp8x5_usb_ctrl_arg {
- u8 type;
+ u8 type;
u8 cmd;
u8 cmd_type;
u16 value;
@@ -138,49 +141,33 @@ struct spcp8x5_usb_ctrl_arg {
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
-enum spcp8x5_type {
- SPCP825_007_TYPE,
- SPCP825_008_TYPE,
- SPCP825_PHILIP_TYPE,
- SPCP825_INTERMATIC_TYPE,
- SPCP835_TYPE,
-};
-
struct spcp8x5_private {
- spinlock_t lock;
- enum spcp8x5_type type;
- u8 line_control;
- u8 line_status;
+ unsigned quirks;
+ spinlock_t lock;
+ u8 line_control;
};
+static int spcp8x5_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id);
+
+ return 0;
+}
+
static int spcp8x5_port_probe(struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ const struct usb_device_id *id = usb_get_serial_data(port->serial);
struct spcp8x5_private *priv;
- enum spcp8x5_type type = SPCP825_007_TYPE;
- u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-
- if (product == 0x0201)
- type = SPCP825_007_TYPE;
- else if (product == 0x0231)
- type = SPCP835_TYPE;
- else if (product == 0x0235)
- type = SPCP825_008_TYPE;
- else if (product == 0x0204)
- type = SPCP825_INTERMATIC_TYPE;
- else if (product == 0x0471 &&
- serial->dev->descriptor.idVendor == cpu_to_le16(0x081e))
- type = SPCP825_PHILIP_TYPE;
- dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
spin_lock_init(&priv->lock);
- priv->type = type;
+ priv->quirks = id->driver_info;
- usb_set_serial_port_data(port , priv);
+ usb_set_serial_port_data(port, priv);
return 0;
}
@@ -195,86 +182,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port)
return 0;
}
-/* set the modem control line of the device.
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value,
- enum spcp8x5_type type)
+static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int retval;
- u8 mcr = 0 ;
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- mcr = (unsigned short)value;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_UART_STATUS_TYPE, SET_UART_STATUS,
mcr, 0x04, NULL, 0, 100);
- if (retval != 0)
- dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval);
+ if (retval != 0) {
+ dev_err(&port->dev, "failed to set control lines: %d\n",
+ retval);
+ }
return retval;
}
-/* get the modem status register of the device
- * NOTE spcp825-007 not supported this */
-static int spcp8x5_get_msr(struct usb_device *dev, u8 *status,
- enum spcp8x5_type type)
+static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
{
- u8 *status_buffer;
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
+ u8 *buf;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)
return -EPERM;
- if (status == NULL)
- return -EINVAL;
- status_buffer = kmalloc(1, GFP_KERNEL);
- if (!status_buffer)
+ buf = kzalloc(1, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
- status_buffer[0] = status[0];
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
GET_UART_STATUS, GET_UART_STATUS_TYPE,
- 0, GET_UART_STATUS_MSR, status_buffer, 1, 100);
+ 0, GET_UART_STATUS_MSR, buf, 1, 100);
if (ret < 0)
- dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)",
- status_buffer, ret);
+ dev_err(&port->dev, "failed to get modem status: %d", ret);
- dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer);
- status[0] = status_buffer[0];
- kfree(status_buffer);
+ dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x", ret, *buf);
+ *status = *buf;
+ kfree(buf);
return ret;
}
-/* select the work mode.
- * NOTE this function not supported by spcp825-007 */
-static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
- u16 index, enum spcp8x5_type type)
+static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value,
+ u16 index)
{
+ struct spcp8x5_private *priv = usb_get_serial_port_data(port);
+ struct usb_device *dev = port->serial->dev;
int ret;
- /* I return Permited not support here but seem inval device
- * is more fix */
- if (type == SPCP825_007_TYPE)
+ if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)
return;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_WORKING_MODE_TYPE, SET_WORKING_MODE,
value, index, NULL, 0, 100);
- dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index);
+ dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);
if (ret < 0)
- dev_dbg(&dev->dev,
- "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
+ dev_err(&port->dev, "failed to set work mode: %d\n", ret);
}
static int spcp8x5_carrier_raised(struct usb_serial_port *port)
{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- if (priv->line_status & MSR_STATUS_LINE_DCD)
+ u8 msr;
+ int ret;
+
+ ret = spcp8x5_get_msr(port, &msr);
+ if (ret || msr & MSR_STATUS_LINE_DCD)
return 1;
+
return 0;
}
@@ -293,20 +273,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
| MCR_CONTROL_LINE_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
}
static void spcp8x5_init_termios(struct tty_struct *tty)
{
- /* for the 1st time call this function */
tty->termios = tty_std_termios;
tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
tty->termios.c_ispeed = 115200;
tty->termios.c_ospeed = 115200;
}
-/* set the serial param for transfer. we should check if we really need to
- * transfer. if we set flow control we should do this too. */
static void spcp8x5_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -321,7 +298,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
int i;
u8 control;
-
/* check that they really want us to change something */
if (!tty_termios_hw_change(&tty->termios, old_termios))
return;
@@ -337,7 +313,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- spcp8x5_set_ctrlLine(serial->dev, control , priv->type);
+ spcp8x5_set_ctrl_line(port, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -397,9 +373,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & PARENB) {
buf[1] |= (cflag & PARODD) ?
SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ;
- } else
+ } else {
buf[1] |= SET_UART_FORMAT_PAR_NONE;
-
+ }
uartdata = buf[0] | buf[1]<<8;
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -412,22 +388,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (cflag & CRTSCTS) {
/* enable hardware flow control */
- spcp8x5_set_workMode(serial->dev, 0x000a,
- SET_WORKING_MODE_U2C, priv->type);
+ spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);
}
}
-/* open the serial port. do some usb system call. set termios and get the line
- * status of the device. */
static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
int ret;
- unsigned long flags;
- u8 status = 0x30;
- /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -438,142 +408,16 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
if (ret)
return ret;
- spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
+ spcp8x5_set_ctrl_line(port, priv->line_control);
- /* Setup termios */
if (tty)
spcp8x5_set_termios(tty, port, &tmp_termios);
- spcp8x5_get_msr(serial->dev, &status, priv->type);
-
- /* may be we should update uart status here but now we did not do */
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_status = status & 0xf0 ;
- spin_unlock_irqrestore(&priv->lock, flags);
-
port->port.drain_delay = 256;
return usb_serial_generic_open(tty, port);
}
-static void spcp8x5_process_read_urb(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- unsigned char *data = urb->transfer_buffer;
- unsigned long flags;
- u8 status;
- char tty_flag;
-
- /* get tty_flag from status */
- tty_flag = TTY_NORMAL;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
- spin_unlock_irqrestore(&priv->lock, flags);
- /* wake up the wait for termios */
- wake_up_interruptible(&port->delta_msr_wait);
-
- if (!urb->actual_length)
- return;
-
-
- if (status & UART_STATE_TRANSIENT_MASK) {
- /* break takes precedence over parity, which takes precedence
- * over framing errors */
- if (status & UART_BREAK_ERROR)
- tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
- tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
- tty_flag = TTY_FRAME;
- dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag);
-
- /* overrun is special, not associated with a char */
- if (status & UART_OVERRUN_ERROR)
- tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
-
- if (status & UART_DCD) {
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- if (tty) {
- usb_serial_handle_dcd_change(port, tty,
- priv->line_status & MSR_STATUS_LINE_DCD);
- tty_kref_put(tty);
- }
- }
- }
-
- tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag,
- urb->actual_length);
- tty_flip_buffer_push(&port->port);
-}
-
-static int spcp8x5_wait_modem_info(struct usb_serial_port *port,
- unsigned int arg)
-{
- struct spcp8x5_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int prevstatus;
- unsigned int status;
- unsigned int changed;
-
- spin_lock_irqsave(&priv->lock, flags);
- prevstatus = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- while (1) {
- /* wake up in bulk read */
- interruptible_sleep_on(&port->delta_msr_wait);
-
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- changed = prevstatus^status;
-
- if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) ||
- ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) ||
- ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) ||
- ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS)))
- return 0;
-
- prevstatus = status;
- }
- /* NOTREACHED */
- return 0;
-}
-
-static int spcp8x5_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
-
- dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
- port->number, cmd);
-
- switch (cmd) {
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
- port->number);
- return spcp8x5_wait_modem_info(port, arg);
-
- default:
- dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
- cmd);
- break;
- }
-
- return -ENOIOCTLCMD;
-}
-
static int spcp8x5_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
@@ -594,7 +438,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
+ return spcp8x5_set_ctrl_line(port, control);
}
static int spcp8x5_tiocmget(struct tty_struct *tty)
@@ -603,12 +447,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr;
- unsigned int status;
+ u8 status;
unsigned int result;
+ result = spcp8x5_get_msr(port, &status);
+ if (result)
+ return result;
+
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
- status = priv->line_status;
spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
@@ -621,7 +468,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)
return result;
}
-/* All of the device info needed for the spcp8x5 SIO serial converter */
static struct usb_serial_driver spcp8x5_device = {
.driver = {
.owner = THIS_MODULE,
@@ -629,17 +475,16 @@ static struct usb_serial_driver spcp8x5_device = {
},
.id_table = id_table,
.num_ports = 1,
- .open = spcp8x5_open,
+ .open = spcp8x5_open,
.dtr_rts = spcp8x5_dtr_rts,
.carrier_raised = spcp8x5_carrier_raised,
- .set_termios = spcp8x5_set_termios,
+ .set_termios = spcp8x5_set_termios,
.init_termios = spcp8x5_init_termios,
- .ioctl = spcp8x5_ioctl,
- .tiocmget = spcp8x5_tiocmget,
- .tiocmset = spcp8x5_tiocmset,
+ .tiocmget = spcp8x5_tiocmget,
+ .tiocmset = spcp8x5_tiocmset,
+ .probe = spcp8x5_probe,
.port_probe = spcp8x5_port_probe,
.port_remove = spcp8x5_port_remove,
- .process_read_urb = spcp8x5_process_read_urb,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 4b2a19757b4d..5b62dbbdf996 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -61,7 +61,6 @@ struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
u8 shadowMSR;
- struct async_icount icount;
};
static inline int ssu100_control_msg(struct usb_device *dev,
@@ -315,11 +314,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
return usb_serial_generic_open(tty, port);
}
-static void ssu100_close(struct usb_serial_port *port)
-{
- usb_serial_generic_close(port);
-}
-
static int get_serial_info(struct usb_serial_port *port,
struct serial_struct __user *retinfo)
{
@@ -343,73 +337,6 @@ static int get_serial_info(struct usb_serial_port *port,
return 0;
}
-static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
-{
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount prev, cur;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- prev = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- while (1) {
- wait_event_interruptible(port->delta_msr_wait,
- (port->serial->disconnected ||
- (priv->icount.rng != prev.rng) ||
- (priv->icount.dsr != prev.dsr) ||
- (priv->icount.dcd != prev.dcd) ||
- (priv->icount.cts != prev.cts)));
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- spin_lock_irqsave(&priv->status_lock, flags);
- cur = priv->icount;
- spin_unlock_irqrestore(&priv->status_lock, flags);
-
- if ((prev.rng == cur.rng) &&
- (prev.dsr == cur.dsr) &&
- (prev.dcd == cur.dcd) &&
- (prev.cts == cur.cts))
- return -EIO;
-
- if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
- (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
- (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
- (arg & TIOCM_CTS && (prev.cts != cur.cts)))
- return 0;
- }
- return 0;
-}
-
-static int ssu100_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ssu100_port_private *priv = usb_get_serial_port_data(port);
- struct async_icount cnow = priv->icount;
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
-
-
static int ssu100_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
@@ -421,10 +348,6 @@ static int ssu100_ioctl(struct tty_struct *tty,
case TIOCGSERIAL:
return get_serial_info(port,
(struct serial_struct __user *) arg);
-
- case TIOCMIWAIT:
- return wait_modem_info(port, arg);
-
default:
break;
}
@@ -532,14 +455,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
if (msr & UART_MSR_ANY_DELTA) {
/* update input line counters */
if (msr & UART_MSR_DCTS)
- priv->icount.cts++;
+ port->icount.cts++;
if (msr & UART_MSR_DDSR)
- priv->icount.dsr++;
+ port->icount.dsr++;
if (msr & UART_MSR_DDCD)
- priv->icount.dcd++;
+ port->icount.dcd++;
if (msr & UART_MSR_TERI)
- priv->icount.rng++;
- wake_up_interruptible(&port->delta_msr_wait);
+ port->icount.rng++;
+ wake_up_interruptible(&port->port.delta_msr_wait);
}
}
@@ -558,22 +481,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
/* we always want to update icount, but we only want to
* update tty_flag for one case */
if (lsr & UART_LSR_BI) {
- priv->icount.brk++;
+ port->icount.brk++;
*tty_flag = TTY_BREAK;
usb_serial_handle_break(port);
}
if (lsr & UART_LSR_PE) {
- priv->icount.parity++;
+ port->icount.parity++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_PARITY;
}
if (lsr & UART_LSR_FE) {
- priv->icount.frame++;
+ port->icount.frame++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_FRAME;
}
if (lsr & UART_LSR_OE){
- priv->icount.overrun++;
+ port->icount.overrun++;
if (*tty_flag == TTY_NORMAL)
*tty_flag = TTY_OVERRUN;
}
@@ -630,7 +553,6 @@ static struct usb_serial_driver ssu100_device = {
.id_table = id_table,
.num_ports = 1,
.open = ssu100_open,
- .close = ssu100_close,
.attach = ssu100_attach,
.port_probe = ssu100_port_probe,
.port_remove = ssu100_port_remove,
@@ -638,10 +560,10 @@ static struct usb_serial_driver ssu100_device = {
.process_read_urb = ssu100_process_read_urb,
.tiocmget = ssu100_tiocmget,
.tiocmset = ssu100_tiocmset,
- .get_icount = ssu100_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.ioctl = ssu100_ioctl,
.set_termios = ssu100_set_termios,
- .disconnect = usb_serial_generic_disconnect,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index be05e6caf9a3..9b1648945e7a 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -1,6 +1,7 @@
/*
* Symbol USB barcode to serial driver
*
+ * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com>
* Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (C) 2009 Novell Inc.
*
@@ -26,27 +27,17 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-/* This structure holds all of the individual device information */
struct symbol_private {
- struct usb_device *udev;
- struct usb_serial *serial;
- struct usb_serial_port *port;
- unsigned char *int_buffer;
- struct urb *int_urb;
- int buffer_size;
- u8 bInterval;
- u8 int_address;
spinlock_t lock; /* protects the following flags */
bool throttled;
bool actually_throttled;
- bool rts;
};
static void symbol_int_callback(struct urb *urb)
{
- struct symbol_private *priv = urb->context;
+ struct usb_serial_port *port = urb->context;
+ struct symbol_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
- struct usb_serial_port *port = priv->port;
int status = urb->status;
int result;
int data_length;
@@ -84,7 +75,7 @@ static void symbol_int_callback(struct urb *urb)
tty_insert_flip_string(&port->port, &data[1], data_length);
tty_flip_buffer_push(&port->port);
} else {
- dev_dbg(&priv->udev->dev,
+ dev_dbg(&port->dev,
"Improper amount of data received from the device, "
"%d bytes", urb->actual_length);
}
@@ -94,12 +85,7 @@ exit:
/* Continue trying to always read if we should */
if (!priv->throttled) {
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev,
- priv->int_address),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
- result = usb_submit_urb(priv->int_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
@@ -118,15 +104,10 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
- priv->port = port;
spin_unlock_irqrestore(&priv->lock, flags);
/* Start reading from the device */
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev, priv->int_address),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
- result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
@@ -136,10 +117,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
static void symbol_close(struct usb_serial_port *port)
{
- struct symbol_private *priv = usb_get_serial_data(port->serial);
-
- /* shutdown our urbs */
- usb_kill_urb(priv->int_urb);
+ usb_kill_urb(port->interrupt_in_urb);
}
static void symbol_throttle(struct tty_struct *tty)
@@ -166,7 +144,7 @@ static void symbol_unthrottle(struct tty_struct *tty)
spin_unlock_irq(&priv->lock);
if (was_throttled) {
- result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
@@ -176,89 +154,36 @@ static void symbol_unthrottle(struct tty_struct *tty)
static int symbol_startup(struct usb_serial *serial)
{
+ if (!serial->num_interrupt_in) {
+ dev_err(&serial->dev->dev, "no interrupt-in endpoint\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int symbol_port_probe(struct usb_serial_port *port)
+{
struct symbol_private *priv;
- struct usb_host_interface *intf;
- int i;
- int retval = -ENOMEM;
- bool int_in_found = false;
- /* create our private serial structure */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ if (!priv)
return -ENOMEM;
- }
+
spin_lock_init(&priv->lock);
- priv->serial = serial;
- priv->port = serial->port[0];
- priv->udev = serial->dev;
-
- /* find our interrupt endpoint */
- intf = serial->interface->altsetting;
- for (i = 0; i < intf->desc.bNumEndpoints; ++i) {
- struct usb_endpoint_descriptor *endpoint;
-
- endpoint = &intf->endpoint[i].desc;
- if (!usb_endpoint_is_int_in(endpoint))
- continue;
-
- priv->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!priv->int_urb) {
- dev_err(&priv->udev->dev, "out of memory\n");
- goto error;
- }
-
- priv->buffer_size = usb_endpoint_maxp(endpoint) * 2;
- priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
- if (!priv->int_buffer) {
- dev_err(&priv->udev->dev, "out of memory\n");
- goto error;
- }
-
- priv->int_address = endpoint->bEndpointAddress;
- priv->bInterval = endpoint->bInterval;
-
- /* set up our int urb */
- usb_fill_int_urb(priv->int_urb, priv->udev,
- usb_rcvintpipe(priv->udev,
- endpoint->bEndpointAddress),
- priv->int_buffer, priv->buffer_size,
- symbol_int_callback, priv, priv->bInterval);
-
- int_in_found = true;
- break;
- }
- if (!int_in_found) {
- dev_err(&priv->udev->dev,
- "Error - the proper endpoints were not found!\n");
- goto error;
- }
+ usb_set_serial_port_data(port, priv);
- usb_set_serial_data(serial, priv);
return 0;
-
-error:
- usb_free_urb(priv->int_urb);
- kfree(priv->int_buffer);
- kfree(priv);
- return retval;
-}
-
-static void symbol_disconnect(struct usb_serial *serial)
-{
- struct symbol_private *priv = usb_get_serial_data(serial);
-
- usb_kill_urb(priv->int_urb);
- usb_free_urb(priv->int_urb);
}
-static void symbol_release(struct usb_serial *serial)
+static int symbol_port_remove(struct usb_serial_port *port)
{
- struct symbol_private *priv = usb_get_serial_data(serial);
+ struct symbol_private *priv = usb_get_serial_port_data(port);
- kfree(priv->int_buffer);
kfree(priv);
+
+ return 0;
}
static struct usb_serial_driver symbol_device = {
@@ -269,12 +194,13 @@ static struct usb_serial_driver symbol_device = {
.id_table = id_table,
.num_ports = 1,
.attach = symbol_startup,
+ .port_probe = symbol_port_probe,
+ .port_remove = symbol_port_remove,
.open = symbol_open,
.close = symbol_close,
- .disconnect = symbol_disconnect,
- .release = symbol_release,
.throttle = symbol_throttle,
.unthrottle = symbol_unthrottle,
+ .read_int_callback = symbol_int_callback,
};
static struct usb_serial_driver * const serial_drivers[] = {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 73deb029fc05..cac47aef2918 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -67,13 +67,10 @@
struct ti_port {
int tp_is_open;
__u8 tp_msr;
- __u8 tp_lsr;
__u8 tp_shadow_mcr;
__u8 tp_uart_mode; /* 232 or 485 modes */
unsigned int tp_uart_base_addr;
int tp_flags;
- int tp_closing_wait;/* in .01 secs */
- struct async_icount tp_icount;
wait_queue_head_t tp_write_wait;
struct ti_device *tp_tdev;
struct usb_serial_port *tp_port;
@@ -108,8 +105,6 @@ static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount);
static void ti_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios);
static int ti_tiocmget(struct tty_struct *tty);
@@ -124,15 +119,13 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data,
int length);
static void ti_send(struct ti_port *tport);
static int ti_set_mcr(struct ti_port *tport, unsigned int mcr);
-static int ti_get_lsr(struct ti_port *tport);
+static int ti_get_lsr(struct ti_port *tport, u8 *lsr);
static int ti_get_serial_info(struct ti_port *tport,
struct serial_struct __user *ret_arg);
static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg);
static void ti_handle_new_msr(struct ti_port *tport, __u8 msr);
-static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush);
-
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty);
static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty);
@@ -235,7 +228,8 @@ static struct usb_serial_driver ti_1port_device = {
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -265,7 +259,8 @@ static struct usb_serial_driver ti_2port_device = {
.set_termios = ti_set_termios,
.tiocmget = ti_tiocmget,
.tiocmset = ti_tiocmset,
- .get_icount = ti_get_icount,
+ .tiocmiwait = usb_serial_generic_tiocmiwait,
+ .get_icount = usb_serial_generic_get_icount,
.break_ctl = ti_break,
.read_int_callback = ti_interrupt_callback,
.read_bulk_callback = ti_bulk_in_callback,
@@ -430,7 +425,7 @@ static int ti_port_probe(struct usb_serial_port *port)
tport->tp_uart_base_addr = TI_UART1_BASE_ADDR;
else
tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;
- tport->tp_closing_wait = closing_wait;
+ port->port.closing_wait = msecs_to_jiffies(10 * closing_wait);
init_waitqueue_head(&tport->tp_write_wait);
if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {
kfree(tport);
@@ -480,8 +475,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
port_number = port->number - port->serial->minor;
- memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount));
-
tport->tp_msr = 0;
tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR);
@@ -585,6 +578,8 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
tport->tp_is_open = 1;
++tdev->td_open_port_count;
+ port->port.drain_delay = 3;
+
goto release_lock;
unlink_int_urb:
@@ -604,6 +599,7 @@ static void ti_close(struct usb_serial_port *port)
int port_number;
int status;
int do_unlock;
+ unsigned long flags;
tdev = usb_get_serial_data(port->serial);
tport = usb_get_serial_port_data(port);
@@ -612,11 +608,12 @@ static void ti_close(struct usb_serial_port *port)
tport->tp_is_open = 0;
- ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 1);
-
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
tport->tp_write_urb_in_use = 0;
+ spin_lock_irqsave(&tport->tp_lock, flags);
+ kfifo_reset_out(&tport->write_fifo);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
port_number = port->number - port->serial->minor;
@@ -687,6 +684,8 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
struct ti_port *tport = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
+ int ret;
+ u8 lsr;
if (tport == NULL)
return 0;
@@ -695,6 +694,12 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&tport->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
+ if (!chars) {
+ ret = ti_get_lsr(tport, &lsr);
+ if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+ chars = 1;
+ }
+
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
@@ -731,38 +736,11 @@ static void ti_unthrottle(struct tty_struct *tty)
}
}
-static int ti_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow = tport->tp_icount;
-
- dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__,
- cnow.rx, cnow.tx);
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
- icount->rx = cnow.rx;
- icount->tx = cnow.tx;
- icount->frame = cnow.frame;
- icount->overrun = cnow.overrun;
- icount->parity = cnow.parity;
- icount->brk = cnow.brk;
- icount->buf_overrun = cnow.buf_overrun;
-
- return 0;
-}
-
static int ti_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- struct async_icount cnow;
- struct async_icount cprev;
dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd);
@@ -778,29 +756,6 @@ static int ti_ioctl(struct tty_struct *tty,
dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);
return ti_set_serial_info(tty, tport,
(struct serial_struct __user *)arg);
- case TIOCMIWAIT:
- dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__);
- cprev = tport->tp_icount;
- while (1) {
- interruptible_sleep_on(&port->delta_msr_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- if (port->serial->disconnected)
- return -EIO;
-
- cnow = tport->tp_icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
- return 0;
- cprev = cnow;
- }
- break;
}
return -ENOIOCTLCMD;
}
@@ -1018,8 +973,6 @@ static void ti_break(struct tty_struct *tty, int break_state)
if (tport == NULL)
return;
- ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0);
-
status = ti_write_byte(port, tport->tp_tdev,
tport->tp_uart_base_addr + TI_UART_OFFSET_LCR,
TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0);
@@ -1156,7 +1109,7 @@ static void ti_bulk_in_callback(struct urb *urb)
else
ti_recv(port, urb->transfer_buffer, urb->actual_length);
spin_lock(&tport->tp_lock);
- tport->tp_icount.rx += urb->actual_length;
+ port->icount.rx += urb->actual_length;
spin_unlock(&tport->tp_lock);
}
@@ -1229,7 +1182,6 @@ static void ti_send(struct ti_port *tport)
{
int count, result;
struct usb_serial_port *port = tport->tp_port;
- struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags;
spin_lock_irqsave(&tport->tp_lock, flags);
@@ -1265,19 +1217,17 @@ static void ti_send(struct ti_port *tport)
/* TODO: reschedule ti_send */
} else {
spin_lock_irqsave(&tport->tp_lock, flags);
- tport->tp_icount.tx += count;
+ port->icount.tx += count;
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
/* more room in the buffer for new writes, wakeup */
- if (tty)
- tty_wakeup(tty);
- tty_kref_put(tty);
+ tty_port_tty_wakeup(&port->port);
+
wake_up_interruptible(&tport->tp_write_wait);
return;
unlock:
spin_unlock_irqrestore(&tport->tp_lock, flags);
- tty_kref_put(tty);
return;
}
@@ -1300,7 +1250,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr)
}
-static int ti_get_lsr(struct ti_port *tport)
+static int ti_get_lsr(struct ti_port *tport, u8 *lsr)
{
int size, status;
struct ti_device *tdev = tport->tp_tdev;
@@ -1326,7 +1276,7 @@ static int ti_get_lsr(struct ti_port *tport)
dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR);
- tport->tp_lsr = data->bLSR;
+ *lsr = data->bLSR;
free_data:
kfree(data);
@@ -1339,10 +1289,15 @@ static int ti_get_serial_info(struct ti_port *tport,
{
struct usb_serial_port *port = tport->tp_port;
struct serial_struct ret_serial;
+ unsigned cwait;
if (!ret_arg)
return -EFAULT;
+ cwait = port->port.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = jiffies_to_msecs(cwait) / 10;
+
memset(&ret_serial, 0, sizeof(ret_serial));
ret_serial.type = PORT_16550A;
@@ -1351,7 +1306,7 @@ static int ti_get_serial_info(struct ti_port *tport,
ret_serial.flags = tport->tp_flags;
ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE;
ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800;
- ret_serial.closing_wait = tport->tp_closing_wait;
+ ret_serial.closing_wait = cwait;
if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg)))
return -EFAULT;
@@ -1364,12 +1319,17 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport,
struct serial_struct __user *new_arg)
{
struct serial_struct new_serial;
+ unsigned cwait;
if (copy_from_user(&new_serial, new_arg, sizeof(new_serial)))
return -EFAULT;
+ cwait = new_serial.closing_wait;
+ if (cwait != ASYNC_CLOSING_WAIT_NONE)
+ cwait = msecs_to_jiffies(10 * new_serial.closing_wait);
+
tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS;
- tport->tp_closing_wait = new_serial.closing_wait;
+ tport->tp_port->port.closing_wait = cwait;
return 0;
}
@@ -1385,7 +1345,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
if (msr & TI_MSR_DELTA_MASK) {
spin_lock_irqsave(&tport->tp_lock, flags);
- icount = &tport->tp_icount;
+ icount = &tport->tp_port->icount;
if (msr & TI_MSR_DELTA_CTS)
icount->cts++;
if (msr & TI_MSR_DELTA_DSR)
@@ -1394,7 +1354,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
icount->dcd++;
if (msr & TI_MSR_DELTA_RI)
icount->rng++;
- wake_up_interruptible(&tport->tp_port->delta_msr_wait);
+ wake_up_interruptible(&tport->tp_port->port.delta_msr_wait);
spin_unlock_irqrestore(&tport->tp_lock, flags);
}
@@ -1414,56 +1374,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)
}
-static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
-{
- struct ti_device *tdev = tport->tp_tdev;
- struct usb_serial_port *port = tport->tp_port;
- wait_queue_t wait;
-
- spin_lock_irq(&tport->tp_lock);
-
- /* wait for data to drain from the buffer */
- tdev->td_urb_error = 0;
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&tport->tp_write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (kfifo_len(&tport->write_fifo) == 0
- || timeout == 0 || signal_pending(current)
- || tdev->td_urb_error
- || port->serial->disconnected) /* disconnect */
- break;
- spin_unlock_irq(&tport->tp_lock);
- timeout = schedule_timeout(timeout);
- spin_lock_irq(&tport->tp_lock);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&tport->tp_write_wait, &wait);
-
- /* flush any remaining data in the buffer */
- if (flush)
- kfifo_reset_out(&tport->write_fifo);
-
- spin_unlock_irq(&tport->tp_lock);
-
- mutex_lock(&port->serial->disc_mutex);
- /* wait for data to drain from the device */
- /* wait for empty tx register, plus 20 ms */
- timeout += jiffies;
- tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
- while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
- && !port->serial->disconnected) {
- if (ti_get_lsr(tport))
- break;
- mutex_unlock(&port->serial->disc_mutex);
- msleep_interruptible(20);
- mutex_lock(&port->serial->disc_mutex);
- }
- mutex_unlock(&port->serial->disc_mutex);
-}
-
-
static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty)
{
unsigned long flags;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 2e70efa08b77..cf75beb1251b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,6 +1,7 @@
/*
* USB Serial Converter driver
*
+ * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com)
* Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
@@ -14,7 +15,6 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this
* driver
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -49,7 +49,6 @@
drivers depend on it.
*/
-/* initially all NULL */
static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
@@ -139,7 +138,7 @@ static void destroy_serial(struct kref *kref)
if (serial->minor != SERIAL_TTY_NO_MINOR)
return_serial(serial);
- if (serial->attached)
+ if (serial->attached && serial->type->release)
serial->type->release(serial);
/* Now that nothing is using the ports, they can be freed */
@@ -225,7 +224,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
return retval;
}
-static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
+static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
@@ -249,30 +248,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return tty_port_open(&port->port, tty, filp);
}
/**
- * serial_down - shut down hardware
+ * serial_port_shutdown - shut down hardware
* @tport: tty port to shut down
*
- * Shut down a USB serial port unless it is the console. We never
- * shut down the console hardware as it will always be in use. Serialized
- * against activate by the tport mutex and kept to matching open/close pairs
+ * Shut down a USB serial port. Serialized against activate by the
+ * tport mutex and kept to matching open/close pairs
* of calls by the ASYNCB_INITIALIZED flag.
+ *
+ * Not called if tty is console.
*/
-static void serial_down(struct tty_port *tport)
+static void serial_port_shutdown(struct tty_port *tport)
{
struct usb_serial_port *port =
container_of(tport, struct usb_serial_port, port);
struct usb_serial_driver *drv = port->serial->type;
- /*
- * The console is magical. Do not hang up the console hardware
- * or there will be tears.
- */
- if (port->port.console)
- return;
+
if (drv->close)
drv->close(port);
}
@@ -281,7 +277,8 @@ static void serial_hangup(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_hangup(&port->port);
}
@@ -289,7 +286,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
+
tty_port_close(&port->port, tty, filp);
}
@@ -308,14 +306,14 @@ static void serial_cleanup(struct tty_struct *tty)
struct usb_serial *serial;
struct module *owner;
+ dev_dbg(tty->dev, "%s\n", __func__);
+
/* The console is magical. Do not hang up the console hardware
* or there will be tears.
*/
if (port->port.console)
return;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
-
tty->driver_data = NULL;
serial = port->serial;
@@ -339,10 +337,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
- dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__,
- port->number, count);
+ dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count);
- /* pass on to the driver specific version of this function */
retval = port->serial->type->write(tty, port, buf, count);
if (retval < 0)
retval = usb_translate_errors(retval);
@@ -354,8 +350,8 @@ static int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
- /* pass on to the driver specific version of this function */
+ dev_dbg(tty->dev, "%s\n", __func__);
+
return port->serial->type->write_room(tty);
}
@@ -365,7 +361,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
struct usb_serial *serial = port->serial;
int count = 0;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
mutex_lock(&serial->disc_mutex);
/* if the device was unplugged then any remaining characters
@@ -383,9 +379,8 @@ static void serial_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(tty);
}
@@ -394,9 +389,8 @@ static void serial_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(tty);
}
@@ -407,15 +401,20 @@ static int serial_ioctl(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__,
- port->number, cmd);
+ dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
+
+ switch (cmd) {
+ case TIOCMIWAIT:
+ if (port->serial->type->tiocmiwait)
+ retval = port->serial->type->tiocmiwait(tty, arg);
+ break;
+ default:
+ if (port->serial->type->ioctl)
+ retval = port->serial->type->ioctl(tty, cmd, arg);
+ else
+ retval = -ENOIOCTLCMD;
+ }
- /* pass on to the driver specific version of this function
- if it is available */
- if (port->serial->type->ioctl) {
- retval = port->serial->type->ioctl(tty, cmd, arg);
- } else
- retval = -ENOIOCTLCMD;
return retval;
}
@@ -423,10 +422,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(tty, port, old);
else
@@ -437,12 +434,11 @@ static int serial_break(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
- /* pass on to the driver specific version of this function
- if it is available */
if (port->serial->type->break_ctl)
port->serial->type->break_ctl(tty, break_state);
+
return 0;
}
@@ -496,7 +492,7 @@ static int serial_tiocmget(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(tty);
@@ -508,7 +504,7 @@ static int serial_tiocmset(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(tty, set, clear);
@@ -520,7 +516,7 @@ static int serial_get_icount(struct tty_struct *tty,
{
struct usb_serial_port *port = tty->driver_data;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ dev_dbg(tty->dev, "%s\n", __func__);
if (port->serial->type->get_icount)
return port->serial->type->get_icount(tty, icount);
@@ -542,55 +538,43 @@ static void usb_serial_port_work(struct work_struct *work)
{
struct usb_serial_port *port =
container_of(work, struct usb_serial_port, work);
- struct tty_struct *tty;
- tty = tty_port_tty_get(&port->port);
- if (!tty)
- return;
+ tty_port_tty_wakeup(&port->port);
+}
+
+static void usb_serial_port_poison_urbs(struct usb_serial_port *port)
+{
+ int i;
- dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number);
+ for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+ usb_poison_urb(port->read_urbs[i]);
+ for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
+ usb_poison_urb(port->write_urbs[i]);
- tty_wakeup(tty);
- tty_kref_put(tty);
+ usb_poison_urb(port->interrupt_in_urb);
+ usb_poison_urb(port->interrupt_out_urb);
}
-static void kill_traffic(struct usb_serial_port *port)
+static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port)
{
int i;
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
- usb_kill_urb(port->read_urbs[i]);
+ usb_unpoison_urb(port->read_urbs[i]);
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
- usb_kill_urb(port->write_urbs[i]);
- /*
- * This is tricky.
- * Some drivers submit the read_urb in the
- * handler for the write_urb or vice versa
- * this order determines the order in which
- * usb_kill_urb() must be used to reliably
- * kill the URBs. As it is unknown here,
- * both orders must be used in turn.
- * The call below is not redundant.
- */
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
- usb_kill_urb(port->interrupt_out_urb);
+ usb_unpoison_urb(port->write_urbs[i]);
+
+ usb_unpoison_urb(port->interrupt_in_urb);
+ usb_unpoison_urb(port->interrupt_out_urb);
}
-static void port_release(struct device *dev)
+static void usb_serial_port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
int i;
dev_dbg(dev, "%s\n", __func__);
- /*
- * Stop all the traffic before cancelling the work, so that
- * nobody will restart it by calling usb_serial_port_softint.
- */
- kill_traffic(port);
- cancel_work_sync(&port->work);
-
usb_free_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_out_urb);
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
@@ -615,10 +599,8 @@ static struct usb_serial *create_serial(struct usb_device *dev,
struct usb_serial *serial;
serial = kzalloc(sizeof(*serial), GFP_KERNEL);
- if (!serial) {
- dev_err(&dev->dev, "%s - out of memory\n", __func__);
+ if (!serial)
return NULL;
- }
serial->dev = usb_get_dev(dev);
serial->type = driver;
serial->interface = usb_get_intf(interface);
@@ -681,7 +663,7 @@ static struct usb_serial_driver *search_serial_device(
return NULL;
}
-static int serial_carrier_raised(struct tty_port *port)
+static int serial_port_carrier_raised(struct tty_port *port)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
@@ -692,7 +674,7 @@ static int serial_carrier_raised(struct tty_port *port)
return 1;
}
-static void serial_dtr_rts(struct tty_port *port, int on)
+static void serial_port_dtr_rts(struct tty_port *port, int on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial *serial = p->serial;
@@ -712,10 +694,10 @@ static void serial_dtr_rts(struct tty_port *port, int on)
}
static const struct tty_port_operations serial_port_ops = {
- .carrier_raised = serial_carrier_raised,
- .dtr_rts = serial_dtr_rts,
- .activate = serial_activate,
- .shutdown = serial_down,
+ .carrier_raised = serial_port_carrier_raised,
+ .dtr_rts = serial_port_dtr_rts,
+ .activate = serial_port_activate,
+ .shutdown = serial_port_shutdown,
};
static int usb_serial_probe(struct usb_interface *interface,
@@ -762,7 +744,6 @@ static int usb_serial_probe(struct usb_interface *interface,
serial = create_serial(dev, interface, type);
if (!serial) {
module_put(type->driver.owner);
- dev_err(ddev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
@@ -910,7 +891,7 @@ static int usb_serial_probe(struct usb_interface *interface,
port->dev.parent = &interface->dev;
port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type;
- port->dev.release = &port_release;
+ port->dev.release = &usb_serial_port_release;
device_initialize(&port->dev);
}
@@ -926,16 +907,12 @@ static int usb_serial_probe(struct usb_interface *interface,
for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
set_bit(j, &port->read_urbs_free);
port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->read_urbs[j]) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->read_urbs[j])
goto probe_error;
- }
port->bulk_in_buffers[j] = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->bulk_in_buffers[j]) {
- dev_err(ddev, "Couldn't allocate bulk_in_buffer\n");
+ if (!port->bulk_in_buffers[j])
goto probe_error;
- }
usb_fill_bulk_urb(port->read_urbs[j], dev,
usb_rcvbulkpipe(dev,
endpoint->bEndpointAddress),
@@ -962,16 +939,12 @@ static int usb_serial_probe(struct usb_interface *interface,
for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
set_bit(j, &port->write_urbs_free);
port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urbs[j]) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->write_urbs[j])
goto probe_error;
- }
port->bulk_out_buffers[j] = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->bulk_out_buffers[j]) {
- dev_err(ddev, "Couldn't allocate bulk_out_buffer\n");
+ if (!port->bulk_out_buffers[j])
goto probe_error;
- }
usb_fill_bulk_urb(port->write_urbs[j], dev,
usb_sndbulkpipe(dev,
endpoint->bEndpointAddress),
@@ -989,19 +962,15 @@ static int usb_serial_probe(struct usb_interface *interface,
endpoint = interrupt_in_endpoint[i];
port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->interrupt_in_urb) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->interrupt_in_urb)
goto probe_error;
- }
buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_in_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n");
+ if (!port->interrupt_in_buffer)
goto probe_error;
- }
usb_fill_int_urb(port->interrupt_in_urb, dev,
usb_rcvintpipe(dev,
endpoint->bEndpointAddress),
@@ -1018,20 +987,16 @@ static int usb_serial_probe(struct usb_interface *interface,
endpoint = interrupt_out_endpoint[i];
port = serial->port[i];
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->interrupt_out_urb) {
- dev_err(ddev, "No free urbs available\n");
+ if (!port->interrupt_out_urb)
goto probe_error;
- }
buffer_size = usb_endpoint_maxp(endpoint);
port->interrupt_out_size = buffer_size;
port->interrupt_out_endpointAddress =
endpoint->bEndpointAddress;
port->interrupt_out_buffer = kmalloc(buffer_size,
GFP_KERNEL);
- if (!port->interrupt_out_buffer) {
- dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n");
+ if (!port->interrupt_out_buffer)
goto probe_error;
- }
usb_fill_int_urb(port->interrupt_out_urb, dev,
usb_sndintpipe(dev,
endpoint->bEndpointAddress),
@@ -1120,13 +1085,15 @@ static void usb_serial_disconnect(struct usb_interface *interface)
tty_vhangup(tty);
tty_kref_put(tty);
}
- kill_traffic(port);
+ usb_serial_port_poison_urbs(port);
+ wake_up_interruptible(&port->port.delta_msr_wait);
cancel_work_sync(&port->work);
if (device_is_registered(&port->dev))
device_del(&port->dev);
}
}
- serial->type->disconnect(serial);
+ if (serial->type->disconnect)
+ serial->type->disconnect(serial);
/* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
@@ -1141,6 +1108,11 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
serial->suspending = 1;
+ /*
+ * serial->type->suspend() MUST return 0 in system sleep context,
+ * otherwise, the resume callback has to recover device from
+ * previous suspend failure.
+ */
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
if (r < 0) {
@@ -1152,7 +1124,7 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port)
- kill_traffic(port);
+ usb_serial_port_poison_urbs(port);
}
err_out:
@@ -1160,11 +1132,25 @@ err_out:
}
EXPORT_SYMBOL(usb_serial_suspend);
+static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port)
+ usb_serial_port_unpoison_urbs(port);
+ }
+}
+
int usb_serial_resume(struct usb_interface *intf)
{
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
if (serial->type->resume)
rv = serial->type->resume(serial);
@@ -1180,6 +1166,8 @@ static int usb_serial_reset_resume(struct usb_interface *intf)
struct usb_serial *serial = usb_get_intfdata(intf);
int rv;
+ usb_serial_unpoison_port_urbs(serial);
+
serial->suspending = 0;
if (serial->type->reset_resume)
rv = serial->type->reset_resume(serial);
@@ -1316,12 +1304,12 @@ module_exit(usb_serial_exit);
do { \
if (!type->function) { \
type->function = usb_serial_generic_##function; \
- pr_debug("Had to override the " #function \
- " usb serial operation with the generic one.");\
- } \
+ pr_debug("%s: using generic " #function "\n", \
+ type->driver.name); \
+ } \
} while (0)
-static void fixup_generic(struct usb_serial_driver *device)
+static void usb_serial_operations_init(struct usb_serial_driver *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
@@ -1330,8 +1318,6 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, chars_in_buffer);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
- set_to_generic_if_null(device, disconnect);
- set_to_generic_if_null(device, release);
set_to_generic_if_null(device, process_read_urb);
set_to_generic_if_null(device, prepare_write_buffer);
}
@@ -1343,8 +1329,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)
if (usb_disabled())
return -ENODEV;
- fixup_generic(driver);
-
if (!driver->description)
driver->description = driver->driver.name;
if (!driver->usb_driver) {
@@ -1353,6 +1337,8 @@ static int usb_serial_register(struct usb_serial_driver *driver)
return -EINVAL;
}
+ usb_serial_operations_init(driver);
+
/* Add this device to our list of devices */
mutex_lock(&table_lock);
list_add(&driver->driver_list, &usb_serial_driver_list);
@@ -1470,7 +1456,6 @@ void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_driver
}
EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
-/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 571965aa1cc0..ece326ef63a0 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -421,20 +421,19 @@ void usb_wwan_close(struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- if (serial->dev) {
- /* Stop reading/writing urbs */
- spin_lock_irq(&intfdata->susp_lock);
- portdata->opened = 0;
- spin_unlock_irq(&intfdata->susp_lock);
+ /* Stop reading/writing urbs */
+ spin_lock_irq(&intfdata->susp_lock);
+ portdata->opened = 0;
+ spin_unlock_irq(&intfdata->susp_lock);
- for (i = 0; i < N_IN_URB; i++)
- usb_kill_urb(portdata->in_urbs[i]);
- for (i = 0; i < N_OUT_URB; i++)
- usb_kill_urb(portdata->out_urbs[i]);
- /* balancing - important as an error cannot be handled*/
- usb_autopm_get_interface_no_resume(serial->interface);
- serial->interface->needs_remote_wakeup = 0;
- }
+ for (i = 0; i < N_IN_URB; i++)
+ usb_kill_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ usb_kill_urb(portdata->out_urbs[i]);
+
+ /* balancing - important as an error cannot be handled*/
+ usb_autopm_get_interface_no_resume(serial->interface);
+ serial->interface->needs_remote_wakeup = 0;
}
EXPORT_SYMBOL(usb_wwan_close);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 1129aa73c23e..7573ec8a084f 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -257,24 +257,18 @@ static void visor_close(struct usb_serial_port *port)
{
unsigned char *transfer_buffer;
- /* shutdown our urbs */
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
- mutex_lock(&port->serial->disc_mutex);
- if (!port->serial->disconnected) {
- /* Try to send shutdown message, unless the device is gone */
- transfer_buffer = kmalloc(0x12, GFP_KERNEL);
- if (transfer_buffer) {
- usb_control_msg(port->serial->dev,
+ transfer_buffer = kmalloc(0x12, GFP_KERNEL);
+ if (!transfer_buffer)
+ return;
+ usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
VISOR_CLOSE_NOTIFICATION, 0xc2,
0x0000, 0x0000,
transfer_buffer, 0x12, 300);
- kfree(transfer_buffer);
- }
- }
- mutex_unlock(&port->serial->disc_mutex);
+ kfree(transfer_buffer);
}
static void visor_read_int_callback(struct urb *urb)
diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c
new file mode 100644
index 000000000000..100573c6f19e
--- /dev/null
+++ b/drivers/usb/serial/wishbone-serial.c
@@ -0,0 +1,95 @@
+/*
+ * USB Wishbone-Serial adapter driver
+ *
+ * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de>
+ * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+#define GSI_VENDOR_OPENCLOSE 0xB0
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/*
+ * Etherbone must be told that a new stream has begun before data arrives.
+ * This is necessary to restart the negotiation of Wishbone bus parameters.
+ * Similarly, when the stream ends, Etherbone must be told so that the cycle
+ * line can be driven low in the case that userspace failed to do so.
+ */
+static int usb_gsi_openclose(struct usb_serial_port *port, int value)
+{
+ struct usb_device *dev = port->serial->dev;
+
+ return usb_control_msg(
+ dev,
+ usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */
+ GSI_VENDOR_OPENCLOSE,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ value, /* wValue = device is open(1) or closed(0) */
+ port->serial->interface->cur_altsetting->desc.bInterfaceNumber,
+ NULL, 0, /* There is no data stage */
+ 5000); /* Timeout till operation fails */
+}
+
+static int wishbone_serial_open(struct tty_struct *tty,
+ struct usb_serial_port *port)
+{
+ int retval;
+
+ retval = usb_gsi_openclose(port, 1);
+ if (retval) {
+ dev_err(&port->serial->dev->dev,
+ "Could not mark device as open (%d)\n",
+ retval);
+ return retval;
+ }
+
+ retval = usb_serial_generic_open(tty, port);
+ if (retval)
+ usb_gsi_openclose(port, 0);
+
+ return retval;
+}
+
+static void wishbone_serial_close(struct usb_serial_port *port)
+{
+ usb_serial_generic_close(port);
+ usb_gsi_openclose(port, 0);
+}
+
+static struct usb_serial_driver wishbone_serial_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wishbone_serial",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+ .open = &wishbone_serial_open,
+ .close = &wishbone_serial_close,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &wishbone_serial_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>");
+MODULE_DESCRIPTION("USB Wishbone-Serial adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index eab04a6b5fbc..8470e1b114f2 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -4,11 +4,10 @@
comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may"
comment "also be needed; see USB_STORAGE Help for more info"
- depends on USB
config USB_STORAGE
tristate "USB Mass Storage support"
- depends on USB && SCSI
+ depends on SCSI
---help---
Say Y here if you want to connect USB mass storage devices to your
computer's USB port. This is the driver you need for USB
@@ -188,7 +187,7 @@ config USB_STORAGE_CYPRESS_ATACB
config USB_STORAGE_ENE_UB6250
tristate "USB ENE card reader support"
- depends on USB && SCSI
+ depends on SCSI
depends on USB_STORAGE
---help---
Say Y here if you wish to control a ENE SD/MS Card reader.
@@ -203,7 +202,7 @@ config USB_STORAGE_ENE_UB6250
config USB_UAS
tristate "USB Attached SCSI"
- depends on USB && SCSI && BROKEN
+ depends on SCSI && BROKEN
help
The USB Attached SCSI protocol is supported by some USB
storage devices. It permits higher performance by supporting
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index be5564cc8e01..77a2ddfe6487 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -326,8 +326,7 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data)
rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
command, 0xc0, 0, 1, data, 2);
- US_DEBUGP("alauda_get_media_status: Media status %02X %02X\n",
- data[0], data[1]);
+ usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
return rc;
}
@@ -402,7 +401,7 @@ static int alauda_init_media(struct us_data *us)
ready = 1;
}
- US_DEBUGP("alauda_init_media: We are ready for action!\n");
+ usb_stor_dbg(us, "We are ready for action!\n");
if (alauda_ack_media(us) != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -413,15 +412,15 @@ static int alauda_init_media(struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
if (data[0] != 0x14) {
- US_DEBUGP("alauda_init_media: Media not ready after ack\n");
+ usb_stor_dbg(us, "Media not ready after ack\n");
return USB_STOR_TRANSPORT_ERROR;
}
if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("alauda_init_media: Media signature: %02X %02X %02X %02X\n",
- data[0], data[1], data[2], data[3]);
+ usb_stor_dbg(us, "Media signature: %02X %02X %02X %02X\n",
+ data[0], data[1], data[2], data[3]);
media_info = alauda_card_find_id(data[1]);
if (media_info == NULL) {
printk(KERN_WARNING
@@ -432,8 +431,8 @@ static int alauda_init_media(struct us_data *us)
}
MEDIA_INFO(us).capacity = 1 << media_info->chipshift;
- US_DEBUGP("Found media with capacity: %ldMB\n",
- MEDIA_INFO(us).capacity >> 20);
+ usb_stor_dbg(us, "Found media with capacity: %ldMB\n",
+ MEDIA_INFO(us).capacity >> 20);
MEDIA_INFO(us).pageshift = media_info->pageshift;
MEDIA_INFO(us).blockshift = media_info->blockshift;
@@ -472,7 +471,7 @@ static int alauda_check_media(struct us_data *us)
/* Check for no media or door open */
if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
|| ((status[1] & 0x01) == 0)) {
- US_DEBUGP("alauda_check_media: No media, or door open\n");
+ usb_stor_dbg(us, "No media, or door open\n");
alauda_free_maps(&MEDIA_INFO(us));
info->sense_key = 0x02;
info->sense_asc = 0x3A;
@@ -482,7 +481,7 @@ static int alauda_check_media(struct us_data *us)
/* Check for media change */
if (status[0] & 0x08) {
- US_DEBUGP("alauda_check_media: Media change detected\n");
+ usb_stor_dbg(us, "Media change detected\n");
alauda_free_maps(&MEDIA_INFO(us));
alauda_init_media(us);
@@ -518,7 +517,7 @@ static int alauda_check_status2(struct us_data *us)
if (rc != USB_STOR_XFER_GOOD)
return rc;
- US_DEBUGP("alauda_check_status2: %02X %02X %02X\n", data[0], data[1], data[2]);
+ usb_stor_dbg(us, "%02X %02X %02X\n", data[0], data[1], data[2]);
if (data[0] & ALAUDA_STATUS_ERROR)
return USB_STOR_XFER_ERROR;
@@ -584,7 +583,7 @@ static int alauda_read_map(struct us_data *us, unsigned int zone)
goto error;
}
- US_DEBUGP("alauda_read_map: Mapping blocks for zone %d\n", zone);
+ usb_stor_dbg(us, "Mapping blocks for zone %d\n", zone);
/* 1024 PBA's per zone */
for (i = 0; i < zonesize; i++)
@@ -604,7 +603,7 @@ static int alauda_read_map(struct us_data *us, unsigned int zone)
if (data[j] != 0)
goto nonz;
pba_to_lba[i] = UNUSABLE;
- US_DEBUGP("alauda_read_map: PBA %d has no logical mapping\n", blocknum);
+ usb_stor_dbg(us, "PBA %d has no logical mapping\n", blocknum);
continue;
nonz:
@@ -617,19 +616,18 @@ static int alauda_read_map(struct us_data *us, unsigned int zone)
nonff:
/* normal PBAs start with six FFs */
if (j < 6) {
- US_DEBUGP("alauda_read_map: PBA %d has no logical mapping: "
- "reserved area = %02X%02X%02X%02X "
- "data status %02X block status %02X\n",
- blocknum, data[0], data[1], data[2], data[3],
- data[4], data[5]);
+ usb_stor_dbg(us, "PBA %d has no logical mapping: reserved area = %02X%02X%02X%02X data status %02X block status %02X\n",
+ blocknum,
+ data[0], data[1], data[2], data[3],
+ data[4], data[5]);
pba_to_lba[i] = UNUSABLE;
continue;
}
if ((data[6] >> 4) != 0x01) {
- US_DEBUGP("alauda_read_map: PBA %d has invalid address "
- "field %02X%02X/%02X%02X\n",
- blocknum, data[6], data[7], data[11], data[12]);
+ usb_stor_dbg(us, "PBA %d has invalid address field %02X%02X/%02X%02X\n",
+ blocknum, data[6], data[7],
+ data[11], data[12]);
pba_to_lba[i] = UNUSABLE;
continue;
}
@@ -711,7 +709,7 @@ static int alauda_erase_block(struct us_data *us, u16 pba)
};
unsigned char buf[2];
- US_DEBUGP("alauda_erase_block: Erasing PBA %d\n", pba);
+ usb_stor_dbg(us, "Erasing PBA %d\n", pba);
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
@@ -723,8 +721,7 @@ static int alauda_erase_block(struct us_data *us, u16 pba)
if (rc != USB_STOR_XFER_GOOD)
return rc;
- US_DEBUGP("alauda_erase_block: Erase result: %02X %02X\n",
- buf[0], buf[1]);
+ usb_stor_dbg(us, "Erase result: %02X %02X\n", buf[0], buf[1]);
return rc;
}
@@ -741,8 +738,7 @@ static int alauda_read_block_raw(struct us_data *us, u16 pba,
PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)
};
- US_DEBUGP("alauda_read_block: pba %d page %d count %d\n",
- pba, page, pages);
+ usb_stor_dbg(us, "pba %d page %d count %d\n", pba, page, pages);
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
@@ -793,7 +789,7 @@ static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data)
PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)
};
- US_DEBUGP("alauda_write_block: pba %d\n", pba);
+ usb_stor_dbg(us, "pba %d\n", pba);
rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
command, 9, NULL);
@@ -866,14 +862,14 @@ static int alauda_write_lba(struct us_data *us, u16 lba,
cptr = bptr + pagesize;
nand_compute_ecc(bptr, ecc);
if (!nand_compare_ecc(cptr+13, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+13, ecc);
}
nand_compute_ecc(bptr + (pagesize / 2), ecc);
if (!nand_compare_ecc(cptr+8, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+8, ecc);
}
cptr[6] = cptr[11] = MSB_of(lbap);
@@ -900,8 +896,7 @@ static int alauda_write_lba(struct us_data *us, u16 lba,
new_pba_offset = new_pba - (zone * zonesize);
MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba;
MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba;
- US_DEBUGP("alauda_write_lba: Remapped LBA %d to PBA %d\n",
- lba, new_pba);
+ usb_stor_dbg(us, "Remapped LBA %d to PBA %d\n", lba, new_pba);
if (pba != UNDEF) {
unsigned int pba_offset = pba - (zone * zonesize);
@@ -964,8 +959,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
/* Not overflowing capacity? */
if (lba >= max_lba) {
- US_DEBUGP("Error: Requested lba %u exceeds "
- "maximum %u\n", lba, max_lba);
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, max_lba);
result = USB_STOR_TRANSPORT_ERROR;
break;
}
@@ -978,8 +973,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];
if (pba == UNDEF) { /* this lba was never written */
- US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
- pages, lba, page);
+ usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+ pages, lba, page);
/* This is not really an error. It just means
that the block has never been written.
@@ -988,9 +983,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
memset(buffer, 0, len);
} else {
- US_DEBUGP("Read %d pages, from PBA %d"
- " (LBA %d) page %d\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+ pages, pba, lba, page);
result = alauda_read_block(us, pba, page, pages, buffer);
if (result != USB_STOR_TRANSPORT_GOOD)
@@ -1066,8 +1060,8 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
/* Not overflowing capacity? */
if (lba >= max_lba) {
- US_DEBUGP("alauda_write_data: Requested lba %u exceeds "
- "maximum %u\n", lba, max_lba);
+ usb_stor_dbg(us, "Requested lba %u exceeds maximum %u\n",
+ lba, max_lba);
result = USB_STOR_TRANSPORT_ERROR;
break;
}
@@ -1122,11 +1116,9 @@ static int init_alauda(struct us_data *us)
nand_init_ecc();
us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("init_alauda: Gah! Can't allocate storage for"
- "alauda info struct!\n");
+ if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- }
+
info = (struct alauda_info *) us->extra;
us->extra_destructor = alauda_info_destructor;
@@ -1147,15 +1139,14 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
};
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("alauda_transport: INQUIRY. "
- "Returning bogus response.\n");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_response, sizeof(inquiry_response));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("alauda_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
return alauda_check_media(us);
}
@@ -1193,8 +1184,7 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("alauda_transport: READ_10: page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "READ_10: page %d pagect %d\n", page, pages);
return alauda_read_data(us, page, pages);
}
@@ -1211,14 +1201,13 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("alauda_transport: WRITE_10: page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "WRITE_10: page %d pagect %d\n", page, pages);
return alauda_write_data(us, page, pages);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("alauda_transport: REQUEST_SENSE.\n");
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
memset(ptr, 0, 18);
ptr[0] = 0xF0;
@@ -1237,8 +1226,8 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
- US_DEBUGP("alauda_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index 070b5c0ebbf9..8514a2d82b72 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -159,7 +159,7 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us)
if (srb->result == SAM_STAT_CHECK_CONDITION &&
memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB)) == 0) {
- US_DEBUGP("cypress atacb not supported ???\n");
+ usb_stor_dbg(us, "cypress atacb not supported ???\n");
goto end;
}
@@ -248,14 +248,26 @@ static int cypress_probe(struct usb_interface *intf,
{
struct us_data *us;
int result;
+ struct usb_device *device;
result = usb_stor_probe1(&us, intf, id,
(id - cypress_usb_ids) + cypress_unusual_dev_list);
if (result)
return result;
- us->protocol_name = "Transparent SCSI with Cypress ATACB";
- us->proto_handler = cypress_atacb_passthrough;
+ /* Among CY7C68300 chips, the A revision does not support Cypress ATACB
+ * Filter out this revision from EEPROM default descriptor values
+ */
+ device = interface_to_usbdev(intf);
+ if (device->descriptor.iManufacturer != 0x38 ||
+ device->descriptor.iProduct != 0x4e ||
+ device->descriptor.iSerialNumber != 0x64) {
+ us->protocol_name = "Transparent SCSI with Cypress ATACB";
+ us->proto_handler = cypress_atacb_passthrough;
+ } else {
+ us->protocol_name = "Transparent SCSI";
+ us->proto_handler = usb_stor_transparent_scsi_command;
+ }
result = usb_stor_probe2(us);
return result;
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 494fee5af41d..7b17c2169812 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -123,7 +123,7 @@ datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("datafab_bulk_read: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
data, len, NULL);
}
@@ -134,7 +134,7 @@ datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("datafab_bulk_write: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
data, len, NULL);
}
@@ -300,9 +300,8 @@ static int datafab_write_data(struct us_data *us,
goto leave;
if (reply[0] != 0x50 && reply[1] != 0) {
- US_DEBUGP("datafab_write_data: Gah! "
- "write return code: %02x %02x\n",
- reply[0], reply[1]);
+ usb_stor_dbg(us, "Gah! write return code: %02x %02x\n",
+ reply[0], reply[1]);
result = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -342,7 +341,7 @@ static int datafab_determine_lun(struct us_data *us,
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("datafab_determine_lun: locating...\n");
+ usb_stor_dbg(us, "locating...\n");
// we'll try 3 times before giving up...
//
@@ -474,16 +473,16 @@ static int datafab_handle_mode_sense(struct us_data *us,
switch (pc) {
case 0x0:
- US_DEBUGP("datafab_handle_mode_sense: Current values\n");
+ usb_stor_dbg(us, "Current values\n");
break;
case 0x1:
- US_DEBUGP("datafab_handle_mode_sense: Changeable values\n");
+ usb_stor_dbg(us, "Changeable values\n");
break;
case 0x2:
- US_DEBUGP("datafab_handle_mode_sense: Default values\n");
+ usb_stor_dbg(us, "Default values\n");
break;
case 0x3:
- US_DEBUGP("datafab_handle_mode_sense: Saves values\n");
+ usb_stor_dbg(us, "Saves values\n");
break;
}
@@ -566,11 +565,9 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
if (!us->extra) {
us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("datafab_transport: Gah! "
- "Can't allocate storage for Datafab info struct!\n");
+ if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- }
+
us->extra_destructor = datafab_info_destructor;
((struct datafab_info *)us->extra)->lun = -1;
}
@@ -578,7 +575,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
info = (struct datafab_info *) (us->extra);
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_reply, sizeof(inquiry_reply));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -590,8 +587,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
// build the reply
// we need the last sector, not the number of sectors
@@ -603,7 +600,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("datafab_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -615,7 +612,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("datafab_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_read_data(us, info, block, blocks);
}
@@ -628,7 +626,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("datafab_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_read_data(us, info, block, blocks);
}
@@ -638,7 +637,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("datafab_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_write_data(us, info, block, blocks);
}
@@ -651,17 +651,18 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return datafab_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
return datafab_id_device(us, info);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("datafab_transport: REQUEST_SENSE. Returning faked response\n");
+ usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n");
// this response is pretty bogus right now. eventually if necessary
// we can set the correct sense data. so far though it hasn't been
@@ -679,12 +680,12 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SENSE) {
- US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
return datafab_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
- US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
return datafab_handle_mode_sense(us, srb, 0);
}
@@ -698,7 +699,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == START_STOP) {
/* this is used by sd.c'check_scsidisk_media_change to detect
media change */
- US_DEBUGP("datafab_transport: START_STOP.\n");
+ usb_stor_dbg(us, "START_STOP\n");
/* the first datafab_id_device after a media change returns
an error (determined experimentally) */
rc = datafab_id_device(us, info);
@@ -712,8 +713,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us)
return rc;
}
- US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index a2b5526c9fa0..e08f64780e30 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -42,16 +42,19 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/device.h>
#include <linux/cdrom.h>
+#include <linux/export.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
+#include "usb.h"
#include "debug.h"
#include "scsi.h"
-void usb_stor_show_command(struct scsi_cmnd *srb)
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
{
char *what = NULL;
int i;
@@ -149,18 +152,18 @@ void usb_stor_show_command(struct scsi_cmnd *srb)
case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
default: what = "(unknown command)"; break;
}
- US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
- US_DEBUGP("");
+ usb_stor_dbg(us, "Command %s (%d bytes)\n", what, srb->cmd_len);
+ usb_stor_dbg(us, "bytes: ");
for (i = 0; i < srb->cmd_len && i < 16; i++)
US_DEBUGPX(" %02x", srb->cmnd[i]);
US_DEBUGPX("\n");
}
-void usb_stor_show_sense(
- unsigned char key,
- unsigned char asc,
- unsigned char ascq) {
-
+void usb_stor_show_sense(const struct us_data *us,
+ unsigned char key,
+ unsigned char asc,
+ unsigned char ascq)
+{
const char *what, *keystr;
keystr = scsi_sense_key_string(key);
@@ -171,7 +174,22 @@ void usb_stor_show_sense(
if (what == NULL)
what = "(unknown ASC/ASCQ)";
- US_DEBUGP("%s: ", keystr);
+ usb_stor_dbg(us, "%s: ", keystr);
US_DEBUGPX(what, ascq);
US_DEBUGPX("\n");
}
+
+int usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+
+ r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(usb_stor_dbg);
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index dbb985d52423..b1273f03e223 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -47,15 +47,22 @@
#define USB_STORAGE "usb-storage: "
#ifdef CONFIG_USB_STORAGE_DEBUG
-void usb_stor_show_command(struct scsi_cmnd *srb);
-void usb_stor_show_sense( unsigned char key,
- unsigned char asc, unsigned char ascq );
-#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
-#define US_DEBUGPX(x...) printk( x )
-#define US_DEBUG(x) x
+void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb);
+void usb_stor_show_sense(const struct us_data *us, unsigned char key,
+ unsigned char asc, unsigned char ascq);
+__printf(2, 3) int usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...);
+
+#define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__)
+#define US_DEBUG(x) x
#else
-#define US_DEBUGP(x...)
-#define US_DEBUGPX(x...)
+__printf(2, 3)
+static inline int _usb_stor_dbg(const struct us_data *us,
+ const char *fmt, ...) {return 1;}
+#define usb_stor_dbg(us, fmt, ...) \
+ do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0)
+#define US_DEBUGPX(fmt, ...) \
+ do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
#define US_DEBUG(x)
#endif
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 118b134a1dad..1bfc9a6cab5f 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -504,12 +504,12 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
unsigned int cswlen = 0, partial = 0;
unsigned int transfer_length = bcb->DataTransferLength;
- /* US_DEBUGP("transport --- ene_send_scsi_cmd\n"); */
+ /* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
/* send cmd to out endpoint */
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("send cmd to out endpoint fail ---\n");
+ usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -529,7 +529,7 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
transfer_length, 0, &partial);
}
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("data transfer fail ---\n");
+ usb_stor_dbg(us, "data transfer fail ---\n");
return USB_STOR_TRANSPORT_ERROR;
}
}
@@ -539,14 +539,14 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
US_BULK_CS_WRAP_LEN, &cswlen);
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
- US_DEBUGP("Received 0-length CSW; retrying...\n");
+ usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
- US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+ usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, NULL);
}
@@ -626,7 +626,7 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
struct scatterlist *sg = NULL;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
- US_DEBUGP("sd_scsi_read_capacity\n");
+ usb_stor_dbg(us, "sd_scsi_read_capacity\n");
if (info->SD_Status.HiCapacity) {
bl_len = 0x200;
if (info->SD_Status.IsMMC)
@@ -639,8 +639,8 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
}
info->bl_num = bl_num;
- US_DEBUGP("bl_len = %x\n", bl_len);
- US_DEBUGP("bl_num = %x\n", bl_num);
+ usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+ usb_stor_dbg(us, "bl_num = %x\n", bl_num);
/*srb->request_bufflen = 8; */
buf[0] = (bl_num >> 24) & 0xff;
@@ -675,7 +675,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
result = ene_load_bincode(us, SD_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Load SD RW pattern Fail !!\n");
+ usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -715,7 +715,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
result = ene_load_bincode(us, SD_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Load SD RW pattern Fail !!\n");
+ usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1493,7 +1493,7 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
struct scatterlist *sg = NULL;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
- US_DEBUGP("ms_scsi_read_capacity\n");
+ usb_stor_dbg(us, "ms_scsi_read_capacity\n");
bl_len = 0x200;
if (info->MS_Status.IsMSPro)
bl_num = info->MSP_TotalBlock - 1;
@@ -1501,8 +1501,8 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1;
info->bl_num = bl_num;
- US_DEBUGP("bl_len = %x\n", bl_len);
- US_DEBUGP("bl_num = %x\n", bl_num);
+ usb_stor_dbg(us, "bl_len = %x\n", bl_len);
+ usb_stor_dbg(us, "bl_num = %x\n", bl_num);
/*srb->request_bufflen = 8; */
buf[0] = (bl_num >> 24) & 0xff;
@@ -1654,7 +1654,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
if (info->MS_Status.IsMSPro) {
result = ene_load_bincode(us, MSP_RW_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Load MPS RW pattern Fail !!\n");
+ usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1854,7 +1854,7 @@ static int ene_get_card_status(struct us_data *us, u8 *buf)
u32 reg4b;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
- /*US_DEBUGP("transport --- ENE_ReadSDReg\n");*/
+ /*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/
reg4b = *(u32 *)&buf[0x18];
info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
@@ -1894,45 +1894,44 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
switch (flag) {
/* For SD */
case SD_INIT1_PATTERN:
- US_DEBUGP("SD_INIT1_PATTERN\n");
+ usb_stor_dbg(us, "SD_INIT1_PATTERN\n");
fw_name = SD_INIT1_FIRMWARE;
break;
case SD_INIT2_PATTERN:
- US_DEBUGP("SD_INIT2_PATTERN\n");
+ usb_stor_dbg(us, "SD_INIT2_PATTERN\n");
fw_name = SD_INIT2_FIRMWARE;
break;
case SD_RW_PATTERN:
- US_DEBUGP("SD_RW_PATTERN\n");
+ usb_stor_dbg(us, "SD_RW_PATTERN\n");
fw_name = SD_RW_FIRMWARE;
break;
/* For MS */
case MS_INIT_PATTERN:
- US_DEBUGP("MS_INIT_PATTERN\n");
+ usb_stor_dbg(us, "MS_INIT_PATTERN\n");
fw_name = MS_INIT_FIRMWARE;
break;
case MSP_RW_PATTERN:
- US_DEBUGP("MSP_RW_PATTERN\n");
+ usb_stor_dbg(us, "MSP_RW_PATTERN\n");
fw_name = MSP_RW_FIRMWARE;
break;
case MS_RW_PATTERN:
- US_DEBUGP("MS_RW_PATTERN\n");
+ usb_stor_dbg(us, "MS_RW_PATTERN\n");
fw_name = MS_RW_FIRMWARE;
break;
default:
- US_DEBUGP("----------- Unknown PATTERN ----------\n");
+ usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n");
goto nofw;
}
err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
if (err) {
- US_DEBUGP("load firmware %s failed\n", fw_name);
+ usb_stor_dbg(us, "load firmware %s failed\n", fw_name);
goto nofw;
}
buf = kmalloc(sd_fw->size, GFP_KERNEL);
- if (buf == NULL) {
- US_DEBUGP("Malloc memory for fireware failed!\n");
+ if (buf == NULL)
goto nofw;
- }
+
memcpy(buf, sd_fw->data, sd_fw->size);
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -2116,9 +2115,9 @@ static int ene_ms_init(struct us_data *us)
} else {
ms_card_init(us); /* Card is MS (to ms.c)*/
}
- US_DEBUGP("MS Init Code OK !!\n");
+ usb_stor_dbg(us, "MS Init Code OK !!\n");
} else {
- US_DEBUGP("MS Card Not Ready --- %x\n", buf[0]);
+ usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -2132,11 +2131,11 @@ static int ene_sd_init(struct us_data *us)
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
- US_DEBUGP("transport --- ENE_SDInit\n");
+ usb_stor_dbg(us, "transport --- ENE_SDInit\n");
/* SD Init Part-1 */
result = ene_load_bincode(us, SD_INIT1_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Load SD Init Code Part-1 Fail !!\n");
+ usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -2147,14 +2146,14 @@ static int ene_sd_init(struct us_data *us)
result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Execution SD Init Code Fail !!\n");
+ usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* SD Init Part-2 */
result = ene_load_bincode(us, SD_INIT2_PATTERN);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Load SD Init Code Part-2 Fail !!\n");
+ usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -2166,21 +2165,23 @@ static int ene_sd_init(struct us_data *us)
result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Execution SD Init Code Fail !!\n");
+ usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR;
}
info->SD_Status = *(struct SD_STATUS *)&buf[0];
if (info->SD_Status.Insert && info->SD_Status.Ready) {
+ struct SD_STATUS *s = &info->SD_Status;
+
ene_get_card_status(us, (unsigned char *)&buf);
- US_DEBUGP("Insert = %x\n", info->SD_Status.Insert);
- US_DEBUGP("Ready = %x\n", info->SD_Status.Ready);
- US_DEBUGP("IsMMC = %x\n", info->SD_Status.IsMMC);
- US_DEBUGP("HiCapacity = %x\n", info->SD_Status.HiCapacity);
- US_DEBUGP("HiSpeed = %x\n", info->SD_Status.HiSpeed);
- US_DEBUGP("WtP = %x\n", info->SD_Status.WtP);
+ usb_stor_dbg(us, "Insert = %x\n", s->Insert);
+ usb_stor_dbg(us, "Ready = %x\n", s->Ready);
+ usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC);
+ usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity);
+ usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed);
+ usb_stor_dbg(us, "WtP = %x\n", s->WtP);
} else {
- US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]);
+ usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
return USB_STOR_TRANSPORT_GOOD;
@@ -2293,7 +2294,7 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
int result = 0;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
- /*US_DEBUG(usb_stor_show_command(srb)); */
+ /*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
result = ene_init(us);
@@ -2362,7 +2363,6 @@ static int ene_ub6250_resume(struct usb_interface *iface)
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __func__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
@@ -2382,7 +2382,7 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface)
u8 tmp = 0;
struct us_data *us = usb_get_intfdata(iface);
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
- US_DEBUGP("%s\n", __func__);
+
/* Report the reset to the SCSI core */
usb_stor_reset_resume(iface);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index e6df087dca9d..ef16068b7087 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -40,7 +40,7 @@ MODULE_AUTHOR("David Brown <usb-storage@davidb.org>");
MODULE_LICENSE("GPL");
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void pdump (void *, int);
+static void pdump(struct us_data *us, void *ibuffer, int length);
#endif
/* Bits of HD_STATUS */
@@ -161,20 +161,20 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
fxfr->Count = cpu_to_le32 (count);
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
- US_DEBUGP("Read data Freecom! (c=%d)\n", count);
+ usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("Freecom readdata transport error\n");
+ usb_stor_dbg(us, "Freecom readdata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
- US_DEBUGP("Start of read\n");
+ usb_stor_dbg(us, "Start of read\n");
result = usb_stor_bulk_srb(us, ipipe, srb);
- US_DEBUGP("freecom_readdata done!\n");
+ usb_stor_dbg(us, "freecom_readdata done!\n");
if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
@@ -194,21 +194,21 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
fxfr->Count = cpu_to_le32 (count);
memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
- US_DEBUGP("Write data Freecom! (c=%d)\n", count);
+ usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count);
/* Issue the transfer command. */
result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
FCM_PACKET_LENGTH, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("Freecom writedata transport error\n");
+ usb_stor_dbg(us, "Freecom writedata transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
/* Now transfer all of our blocks. */
- US_DEBUGP("Start of write\n");
+ usb_stor_dbg(us, "Start of write\n");
result = usb_stor_bulk_srb(us, opipe, srb);
- US_DEBUGP("freecom_writedata done!\n");
+ usb_stor_dbg(us, "freecom_writedata done!\n");
if (result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
return USB_STOR_TRANSPORT_GOOD;
@@ -230,7 +230,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
fcb = (struct freecom_cb_wrap *) us->iobuf;
fst = (struct freecom_status *) us->iobuf;
- US_DEBUGP("Freecom TRANSPORT STARTED\n");
+ usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n");
/* Get handles for both transports. */
opipe = us->send_bulk_pipe;
@@ -242,7 +242,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
memcpy (fcb->Atapi, srb->cmnd, 12);
memset (fcb->Filler, 0, sizeof (fcb->Filler));
- US_DEBUG(pdump (srb->cmnd, 12));
+ US_DEBUG(pdump(us, srb->cmnd, 12));
/* Send it out. */
result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
@@ -252,7 +252,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* USB land. It returns the status in its own registers, which
* come back in the bulk pipe. */
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("freecom transport error\n");
+ usb_stor_dbg(us, "freecom transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -260,11 +260,11 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* doesn't hurt us to always do it now. */
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_STATUS_PACKET_LENGTH, &partial);
- US_DEBUGP("foo Status result %d %u\n", result, partial);
+ usb_stor_dbg(us, "foo Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
/* The firmware will time-out commands after 20 seconds. Some commands
* can legitimately take longer than this, so we use a different
@@ -275,8 +275,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* may not work, but that is a condition that should never happen.
*/
while (fst->Status & FCM_STATUS_BUSY) {
- US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n");
- US_DEBUGP("fst->Status is %x\n", fst->Status);
+ usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n");
+ usb_stor_dbg(us, "fst->Status is %x\n", fst->Status);
/* Get the status again */
fcb->Type = FCM_PACKET_STATUS;
@@ -293,7 +293,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
* registers, which come back in the bulk pipe.
*/
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP ("freecom transport error\n");
+ usb_stor_dbg(us, "freecom transport error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -301,26 +301,26 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_STATUS_PACKET_LENGTH, &partial);
- US_DEBUGP("bar Status result %d %u\n", result, partial);
+ usb_stor_dbg(us, "bar Status result %d %u\n", result, partial);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
}
if (partial != 4)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & 1) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
/* The device might not have as much data available as we
* requested. If you ask for more than the device has, this reads
* and such will hang. */
- US_DEBUGP("Device indicates that it has %d bytes available\n",
- le16_to_cpu (fst->Count));
- US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb));
+ usb_stor_dbg(us, "Device indicates that it has %d bytes available\n",
+ le16_to_cpu(fst->Count));
+ usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb));
/* Find the length we desire to read. */
switch (srb->cmnd[0]) {
@@ -337,7 +337,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
/* verify that this amount is legal */
if (length > scsi_bufflen(srb)) {
length = scsi_bufflen(srb);
- US_DEBUGP("Truncating request to match buffer length: %d\n", length);
+ usb_stor_dbg(us, "Truncating request to match buffer length: %d\n",
+ length);
}
/* What we do now depends on what direction the data is supposed to
@@ -351,29 +352,29 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Make sure that the status indicates that the device
* wants data as well. */
if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
- US_DEBUGP("SCSI wants data, drive doesn't have any\n");
+ usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n");
return USB_STOR_TRANSPORT_FAILED;
}
result = freecom_readdata (srb, us, ipipe, opipe, length);
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- US_DEBUGP("FCM: Waiting for status\n");
+ usb_stor_dbg(us, "Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
- US_DEBUG(pdump ((void *) fst, partial));
+ US_DEBUG(pdump(us, (void *)fst, partial));
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
- US_DEBUGP("Drive seems still hungry\n");
+ usb_stor_dbg(us, "Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
- US_DEBUGP("Transfer happy\n");
+ usb_stor_dbg(us, "Transfer happy\n");
break;
case DMA_TO_DEVICE:
@@ -387,22 +388,22 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
if (result != USB_STOR_TRANSPORT_GOOD)
return result;
- US_DEBUGP("FCM: Waiting for status\n");
+ usb_stor_dbg(us, "Waiting for status\n");
result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
FCM_PACKET_LENGTH, &partial);
if (partial != 4 || result > USB_STOR_XFER_SHORT)
return USB_STOR_TRANSPORT_ERROR;
if ((fst->Status & ERR_STAT) != 0) {
- US_DEBUGP("operation failed\n");
+ usb_stor_dbg(us, "operation failed\n");
return USB_STOR_TRANSPORT_FAILED;
}
if ((fst->Reason & 3) != 3) {
- US_DEBUGP("Drive seems still hungry\n");
+ usb_stor_dbg(us, "Drive seems still hungry\n");
return USB_STOR_TRANSPORT_FAILED;
}
- US_DEBUGP("Transfer happy\n");
+ usb_stor_dbg(us, "Transfer happy\n");
break;
@@ -412,8 +413,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
default:
/* should never hit here -- filtered in usb.c */
- US_DEBUGP ("freecom unimplemented direction: %d\n",
- us->srb->sc_data_direction);
+ usb_stor_dbg(us, "freecom unimplemented direction: %d\n",
+ us->srb->sc_data_direction);
/* Return fail, SCSI seems to handle this better. */
return USB_STOR_TRANSPORT_FAILED;
break;
@@ -434,7 +435,7 @@ static int init_freecom(struct us_data *us)
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
buffer[32] = '\0';
- US_DEBUGP("String returned from FC init is: %s\n", buffer);
+ usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer);
/* Special thanks to the people at Freecom for providing me with
* this "magic sequence", which they use in their Windows and MacOS
@@ -445,7 +446,7 @@ static int init_freecom(struct us_data *us)
/* send reset */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
- US_DEBUGP("result from activate reset is %d\n", result);
+ usb_stor_dbg(us, "result from activate reset is %d\n", result);
/* wait 250ms */
mdelay(250);
@@ -453,7 +454,7 @@ static int init_freecom(struct us_data *us)
/* clear reset */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
- US_DEBUGP("result from clear reset is %d\n", result);
+ usb_stor_dbg(us, "result from clear reset is %d\n", result);
/* wait 3 seconds */
mdelay(3 * 1000);
@@ -470,7 +471,7 @@ static int usb_stor_freecom_reset(struct us_data *us)
}
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void pdump (void *ibuffer, int length)
+static void pdump(struct us_data *us, void *ibuffer, int length)
{
static char line[80];
int offset = 0;
@@ -490,7 +491,7 @@ static void pdump (void *ibuffer, int length)
line[offset++] = '.';
}
line[offset] = 0;
- US_DEBUGP("%s\n", line);
+ usb_stor_dbg(us, "%s\n", line);
offset = 0;
}
offset += sprintf (line+offset, "%08x:", i);
@@ -517,7 +518,7 @@ static void pdump (void *ibuffer, int length)
line[offset++] = '.';
}
line[offset] = 0;
- US_DEBUGP("%s\n", line);
+ usb_stor_dbg(us, "%s\n", line);
offset = 0;
}
#endif
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 105d900150c1..5a8b5ff1e45b 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -48,12 +48,12 @@ int usb_stor_euscsi_init(struct us_data *us)
{
int result;
- US_DEBUGP("Attempting to init eUSCSI bridge...\n");
+ usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n");
us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
0x01, 0x0, us->iobuf, 0x1, 5000);
- US_DEBUGP("-- result is %d\n", result);
+ usb_stor_dbg(us, "-- result is %d\n", result);
return 0;
}
@@ -68,7 +68,7 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
unsigned int partial;
static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
- US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
+ usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n");
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->Tag = 0;
@@ -83,7 +83,7 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
if (res)
return -EIO;
- US_DEBUGP("Getting status packet...\n");
+ usb_stor_dbg(us, "Getting status packet...\n");
res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &partial);
if (res)
@@ -101,6 +101,6 @@ int usb_stor_huawei_e220_init(struct us_data *us)
USB_REQ_SET_FEATURE,
USB_TYPE_STANDARD | USB_RECIP_DEVICE,
0x01, 0x0, NULL, 0x0, 1000);
- US_DEBUGP("Huawei mode set result is %d\n", result);
+ usb_stor_dbg(us, "Huawei mode set result is %d\n", result);
return 0;
}
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index ecea47877364..599d8bff26c3 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -503,7 +503,7 @@ static int isd200_action( struct us_data *us, int action,
switch ( action ) {
case ACTION_READ_STATUS:
- US_DEBUGP(" isd200_action(READ_STATUS)\n");
+ usb_stor_dbg(us, " isd200_action(READ_STATUS)\n");
ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
ata.generic.RegisterSelect =
REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
@@ -512,7 +512,7 @@ static int isd200_action( struct us_data *us, int action,
break;
case ACTION_ENUM:
- US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value);
+ usb_stor_dbg(us, " isd200_action(ENUM,0x%02x)\n", value);
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4|
ACTION_SELECT_5;
@@ -522,7 +522,7 @@ static int isd200_action( struct us_data *us, int action,
break;
case ACTION_RESET:
- US_DEBUGP(" isd200_action(RESET)\n");
+ usb_stor_dbg(us, " isd200_action(RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4;
ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
@@ -531,7 +531,7 @@ static int isd200_action( struct us_data *us, int action,
break;
case ACTION_REENABLE:
- US_DEBUGP(" isd200_action(REENABLE)\n");
+ usb_stor_dbg(us, " isd200_action(REENABLE)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
ACTION_SELECT_3|ACTION_SELECT_4;
ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
@@ -540,7 +540,7 @@ static int isd200_action( struct us_data *us, int action,
break;
case ACTION_SOFT_RESET:
- US_DEBUGP(" isd200_action(SOFT_RESET)\n");
+ usb_stor_dbg(us, " isd200_action(SOFT_RESET)\n");
ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
ata.write.DeviceHeadByte = info->DeviceHead;
@@ -549,7 +549,7 @@ static int isd200_action( struct us_data *us, int action,
break;
case ACTION_IDENTIFY:
- US_DEBUGP(" isd200_action(IDENTIFY)\n");
+ usb_stor_dbg(us, " isd200_action(IDENTIFY)\n");
ata.generic.RegisterSelect = REG_COMMAND;
ata.write.CommandByte = ATA_CMD_ID_ATA;
isd200_set_srb(info, DMA_FROM_DEVICE, info->id,
@@ -557,7 +557,7 @@ static int isd200_action( struct us_data *us, int action,
break;
default:
- US_DEBUGP("Error: Undefined action %d\n",action);
+ usb_stor_dbg(us, "Error: Undefined action %d\n", action);
return ISD200_ERROR;
}
@@ -567,7 +567,8 @@ static int isd200_action( struct us_data *us, int action,
if (status == USB_STOR_TRANSPORT_GOOD)
status = ISD200_GOOD;
else {
- US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status);
+ usb_stor_dbg(us, " isd200_action(0x%02x) error: %d\n",
+ action, status);
status = ISD200_ERROR;
/* need to reset device here */
}
@@ -589,17 +590,17 @@ static int isd200_read_regs( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_IssueATAReadRegs\n");
+ usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n");
transferStatus = isd200_action( us, ACTION_READ_STATUS,
info->RegsBuf, sizeof(info->ATARegs) );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error reading ATA registers\n");
+ usb_stor_dbg(us, " Error reading ATA registers\n");
retStatus = ISD200_ERROR;
} else {
memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
- US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
- info->ATARegs[ATA_REG_ERROR_OFFSET]);
+ usb_stor_dbg(us, " Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n",
+ info->ATARegs[ATA_REG_ERROR_OFFSET]);
}
return retStatus;
@@ -629,7 +630,7 @@ static void isd200_invoke_transport( struct us_data *us,
* short-circuit all other processing
*/
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
- US_DEBUGP("-- command was aborted\n");
+ usb_stor_dbg(us, "-- command was aborted\n");
goto Handle_Abort;
}
@@ -641,23 +642,23 @@ static void isd200_invoke_transport( struct us_data *us,
break;
case USB_STOR_TRANSPORT_NO_SENSE:
- US_DEBUGP("-- transport indicates protocol failure\n");
+ usb_stor_dbg(us, "-- transport indicates protocol failure\n");
srb->result = SAM_STAT_CHECK_CONDITION;
return;
case USB_STOR_TRANSPORT_FAILED:
- US_DEBUGP("-- transport indicates command failure\n");
+ usb_stor_dbg(us, "-- transport indicates command failure\n");
need_auto_sense = 1;
break;
case USB_STOR_TRANSPORT_ERROR:
- US_DEBUGP("-- transport indicates transport error\n");
+ usb_stor_dbg(us, "-- transport indicates transport error\n");
srb->result = DID_ERROR << 16;
/* Need reset here */
return;
default:
- US_DEBUGP("-- transport indicates unknown error\n");
+ usb_stor_dbg(us, "-- transport indicates unknown error\n");
srb->result = DID_ERROR << 16;
/* Need reset here */
return;
@@ -669,14 +670,14 @@ static void isd200_invoke_transport( struct us_data *us,
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
- US_DEBUGP("-- unexpectedly short transfer\n");
+ usb_stor_dbg(us, "-- unexpectedly short transfer\n");
need_auto_sense = 1;
}
if (need_auto_sense) {
result = isd200_read_regs(us);
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
- US_DEBUGP("-- auto-sense aborted\n");
+ usb_stor_dbg(us, "-- auto-sense aborted\n");
goto Handle_Abort;
}
if (result == ISD200_GOOD) {
@@ -710,40 +711,40 @@ static void isd200_invoke_transport( struct us_data *us,
}
#ifdef CONFIG_USB_STORAGE_DEBUG
-static void isd200_log_config( struct isd200_info* info )
+static void isd200_log_config(struct us_data *us, struct isd200_info *info)
{
- US_DEBUGP(" Event Notification: 0x%x\n",
- info->ConfigData.EventNotification);
- US_DEBUGP(" External Clock: 0x%x\n",
- info->ConfigData.ExternalClock);
- US_DEBUGP(" ATA Init Timeout: 0x%x\n",
- info->ConfigData.ATAInitTimeout);
- US_DEBUGP(" ATAPI Command Block Size: 0x%x\n",
- (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
- US_DEBUGP(" Master/Slave Selection: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_MASTER);
- US_DEBUGP(" ATAPI Reset: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
- US_DEBUGP(" ATA Timing: 0x%x\n",
- info->ConfigData.ATAConfig & ATACFG_TIMING);
- US_DEBUGP(" ATA Major Command: 0x%x\n",
- info->ConfigData.ATAMajorCommand);
- US_DEBUGP(" ATA Minor Command: 0x%x\n",
- info->ConfigData.ATAMinorCommand);
- US_DEBUGP(" Init Status: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
- US_DEBUGP(" Config Descriptor 2: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
- US_DEBUGP(" Skip Device Boot: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
- US_DEBUGP(" ATA 3 State Supsend: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
- US_DEBUGP(" Descriptor Override: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
- US_DEBUGP(" Last LUN Identifier: 0x%x\n",
- info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
- US_DEBUGP(" SRST Enable: 0x%x\n",
- info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
+ usb_stor_dbg(us, " Event Notification: 0x%x\n",
+ info->ConfigData.EventNotification);
+ usb_stor_dbg(us, " External Clock: 0x%x\n",
+ info->ConfigData.ExternalClock);
+ usb_stor_dbg(us, " ATA Init Timeout: 0x%x\n",
+ info->ConfigData.ATAInitTimeout);
+ usb_stor_dbg(us, " ATAPI Command Block Size: 0x%x\n",
+ (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
+ usb_stor_dbg(us, " Master/Slave Selection: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_MASTER);
+ usb_stor_dbg(us, " ATAPI Reset: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
+ usb_stor_dbg(us, " ATA Timing: 0x%x\n",
+ info->ConfigData.ATAConfig & ATACFG_TIMING);
+ usb_stor_dbg(us, " ATA Major Command: 0x%x\n",
+ info->ConfigData.ATAMajorCommand);
+ usb_stor_dbg(us, " ATA Minor Command: 0x%x\n",
+ info->ConfigData.ATAMinorCommand);
+ usb_stor_dbg(us, " Init Status: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
+ usb_stor_dbg(us, " Config Descriptor 2: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
+ usb_stor_dbg(us, " Skip Device Boot: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
+ usb_stor_dbg(us, " ATA 3 State Supsend: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
+ usb_stor_dbg(us, " Descriptor Override: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
+ usb_stor_dbg(us, " Last LUN Identifier: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
+ usb_stor_dbg(us, " SRST Enable: 0x%x\n",
+ info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
}
#endif
@@ -762,9 +763,9 @@ static int isd200_write_config( struct us_data *us )
int result;
#ifdef CONFIG_USB_STORAGE_DEBUG
- US_DEBUGP("Entering isd200_write_config\n");
- US_DEBUGP(" Writing the following ISD200 Config Data:\n");
- isd200_log_config(info);
+ usb_stor_dbg(us, "Entering isd200_write_config\n");
+ usb_stor_dbg(us, " Writing the following ISD200 Config Data:\n");
+ isd200_log_config(us, info);
#endif
/* let's send the command via the control pipe */
@@ -779,13 +780,13 @@ static int isd200_write_config( struct us_data *us )
sizeof(info->ConfigData));
if (result >= 0) {
- US_DEBUGP(" ISD200 Config Data was written successfully\n");
+ usb_stor_dbg(us, " ISD200 Config Data was written successfully\n");
} else {
- US_DEBUGP(" Request to write ISD200 Config Data failed!\n");
+ usb_stor_dbg(us, " Request to write ISD200 Config Data failed!\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus);
return retStatus;
}
@@ -804,7 +805,7 @@ static int isd200_read_config( struct us_data *us )
int retStatus = ISD200_GOOD;
int result;
- US_DEBUGP("Entering isd200_read_config\n");
+ usb_stor_dbg(us, "Entering isd200_read_config\n");
/* read the configuration information from ISD200. Use this to */
/* determine what the special ATA CDB bytes are. */
@@ -821,16 +822,16 @@ static int isd200_read_config( struct us_data *us )
if (result >= 0) {
- US_DEBUGP(" Retrieved the following ISD200 Config Data:\n");
+ usb_stor_dbg(us, " Retrieved the following ISD200 Config Data:\n");
#ifdef CONFIG_USB_STORAGE_DEBUG
- isd200_log_config(info);
+ isd200_log_config(us, info);
#endif
} else {
- US_DEBUGP(" Request to get ISD200 Config Data failed!\n");
+ usb_stor_dbg(us, " Request to get ISD200 Config Data failed!\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus);
return retStatus;
}
@@ -848,15 +849,15 @@ static int isd200_atapi_soft_reset( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_atapi_soft_reset\n");
+ usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n");
transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error issuing Atapi Soft Reset\n");
+ usb_stor_dbg(us, " Error issuing Atapi Soft Reset\n");
retStatus = ISD200_ERROR;
}
- US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus);
return retStatus;
}
@@ -874,13 +875,13 @@ static int isd200_srst( struct us_data *us )
int retStatus = ISD200_GOOD;
int transferStatus;
- US_DEBUGP("Entering isd200_SRST\n");
+ usb_stor_dbg(us, "Entering isd200_SRST\n");
transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 );
/* check to see if this request failed */
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error issuing SRST\n");
+ usb_stor_dbg(us, " Error issuing SRST\n");
retStatus = ISD200_ERROR;
} else {
/* delay 10ms to give the drive a chance to see it */
@@ -888,7 +889,7 @@ static int isd200_srst( struct us_data *us )
transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 );
if (transferStatus != ISD200_TRANSPORT_GOOD) {
- US_DEBUGP(" Error taking drive out of reset\n");
+ usb_stor_dbg(us, " Error taking drive out of reset\n");
retStatus = ISD200_ERROR;
} else {
/* delay 50ms to give the drive a chance to recover after SRST */
@@ -896,7 +897,7 @@ static int isd200_srst( struct us_data *us )
}
}
- US_DEBUGP("Leaving isd200_srst %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus);
return retStatus;
}
@@ -926,10 +927,6 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
/* loop until we detect !BSY or timeout */
while(1) {
-#ifdef CONFIG_USB_STORAGE_DEBUG
- char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ?
- "Master" : "Slave";
-#endif
status = isd200_action( us, ACTION_ENUM, NULL, master_slave );
if ( status != ISD200_GOOD )
@@ -942,9 +939,13 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
if (!detect) {
if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) {
- US_DEBUGP(" %s status is still BSY, try again...\n",mstr);
+ usb_stor_dbg(us, " %s status is still BSY, try again...\n",
+ master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+ "Master" : "Slave");
} else {
- US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr);
+ usb_stor_dbg(us, " %s status !BSY, continue with next operation\n",
+ master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+ "Master" : "Slave");
break;
}
}
@@ -953,11 +954,11 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
/* ATA_ERR (workaround for Archos CD-ROM) */
else if (regs[ATA_REG_STATUS_OFFSET] &
(ATA_BUSY | ATA_DF | ATA_ERR)) {
- US_DEBUGP(" Status indicates it is not ready, try again...\n");
+ usb_stor_dbg(us, " Status indicates it is not ready, try again...\n");
}
/* check for DRDY, ATA devices set DRDY after SRST */
else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) {
- US_DEBUGP(" Identified ATA device\n");
+ usb_stor_dbg(us, " Identified ATA device\n");
info->DeviceFlags |= DF_ATA_DEVICE;
info->DeviceHead = master_slave;
break;
@@ -978,27 +979,27 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
*/
if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
!recheckAsMaster) {
- US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n");
+ usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n");
recheckAsMaster = 1;
master_slave = ATA_ADDRESS_DEVHEAD_STD;
} else {
- US_DEBUGP(" Identified ATAPI device\n");
+ usb_stor_dbg(us, " Identified ATAPI device\n");
info->DeviceHead = master_slave;
status = isd200_atapi_soft_reset(us);
break;
}
} else {
- US_DEBUGP(" Not ATA, not ATAPI. Weird.\n");
+ usb_stor_dbg(us, " Not ATA, not ATAPI - Weird\n");
break;
}
/* check for timeout on this request */
if (time_after_eq(jiffies, endTime)) {
if (!detect)
- US_DEBUGP(" BSY check timeout, just continue with next operation...\n");
+ usb_stor_dbg(us, " BSY check timeout, just continue with next operation...\n");
else
- US_DEBUGP(" Device detect timeout!\n");
+ usb_stor_dbg(us, " Device detect timeout!\n");
break;
}
}
@@ -1020,7 +1021,7 @@ static int isd200_manual_enum(struct us_data *us)
struct isd200_info *info = (struct isd200_info *)us->extra;
int retStatus = ISD200_GOOD;
- US_DEBUGP("Entering isd200_manual_enum\n");
+ usb_stor_dbg(us, "Entering isd200_manual_enum\n");
retStatus = isd200_read_config(us);
if (retStatus == ISD200_GOOD) {
@@ -1039,14 +1040,15 @@ static int isd200_manual_enum(struct us_data *us)
isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) {
- US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave);
+ usb_stor_dbg(us, " Setting Master/Slave selection to %d\n",
+ isslave);
info->ConfigData.ATAConfig &= 0x3f;
info->ConfigData.ATAConfig |= (isslave<<6);
retStatus = isd200_write_config(us);
}
}
- US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus);
return(retStatus);
}
@@ -1064,35 +1066,35 @@ static void isd200_fix_driveid(u16 *id)
#endif
}
-static void isd200_dump_driveid(u16 *id)
+static void isd200_dump_driveid(struct us_data *us, u16 *id)
{
- US_DEBUGP(" Identify Data Structure:\n");
- US_DEBUGP(" config = 0x%x\n", id[ATA_ID_CONFIG]);
- US_DEBUGP(" cyls = 0x%x\n", id[ATA_ID_CYLS]);
- US_DEBUGP(" heads = 0x%x\n", id[ATA_ID_HEADS]);
- US_DEBUGP(" track_bytes = 0x%x\n", id[4]);
- US_DEBUGP(" sector_bytes = 0x%x\n", id[5]);
- US_DEBUGP(" sectors = 0x%x\n", id[ATA_ID_SECTORS]);
- US_DEBUGP(" serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]);
- US_DEBUGP(" buf_type = 0x%x\n", id[20]);
- US_DEBUGP(" buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]);
- US_DEBUGP(" ecc_bytes = 0x%x\n", id[22]);
- US_DEBUGP(" fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]);
- US_DEBUGP(" model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]);
- US_DEBUGP(" max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff);
- US_DEBUGP(" dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]);
- US_DEBUGP(" capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8);
- US_DEBUGP(" tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8);
- US_DEBUGP(" tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8);
- US_DEBUGP(" field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]);
- US_DEBUGP(" cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]);
- US_DEBUGP(" cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]);
- US_DEBUGP(" cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]);
- US_DEBUGP(" cur_capacity = 0x%x\n", ata_id_u32(id, 57));
- US_DEBUGP(" multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff);
- US_DEBUGP(" lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY));
- US_DEBUGP(" command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]);
- US_DEBUGP(" command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]);
+ usb_stor_dbg(us, " Identify Data Structure:\n");
+ usb_stor_dbg(us, " config = 0x%x\n", id[ATA_ID_CONFIG]);
+ usb_stor_dbg(us, " cyls = 0x%x\n", id[ATA_ID_CYLS]);
+ usb_stor_dbg(us, " heads = 0x%x\n", id[ATA_ID_HEADS]);
+ usb_stor_dbg(us, " track_bytes = 0x%x\n", id[4]);
+ usb_stor_dbg(us, " sector_bytes = 0x%x\n", id[5]);
+ usb_stor_dbg(us, " sectors = 0x%x\n", id[ATA_ID_SECTORS]);
+ usb_stor_dbg(us, " serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]);
+ usb_stor_dbg(us, " buf_type = 0x%x\n", id[20]);
+ usb_stor_dbg(us, " buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]);
+ usb_stor_dbg(us, " ecc_bytes = 0x%x\n", id[22]);
+ usb_stor_dbg(us, " fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]);
+ usb_stor_dbg(us, " model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]);
+ usb_stor_dbg(us, " max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff);
+ usb_stor_dbg(us, " dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]);
+ usb_stor_dbg(us, " capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8);
+ usb_stor_dbg(us, " tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8);
+ usb_stor_dbg(us, " tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8);
+ usb_stor_dbg(us, " field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]);
+ usb_stor_dbg(us, " cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]);
+ usb_stor_dbg(us, " cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]);
+ usb_stor_dbg(us, " cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]);
+ usb_stor_dbg(us, " cur_capacity = 0x%x\n", ata_id_u32(id, 57));
+ usb_stor_dbg(us, " multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff);
+ usb_stor_dbg(us, " lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY));
+ usb_stor_dbg(us, " command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]);
+ usb_stor_dbg(us, " command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]);
}
/**************************************************************************
@@ -1109,7 +1111,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
int retStatus = ISD200_GOOD;
u16 *id = info->id;
- US_DEBUGP("Entering isd200_get_inquiry_data\n");
+ usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n");
/* set default to Master */
info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
@@ -1127,7 +1129,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
id, ATA_ID_WORDS * 2);
if (transferStatus != ISD200_TRANSPORT_GOOD) {
/* Error issuing ATA Command Identify */
- US_DEBUGP(" Error issuing ATA Command Identify\n");
+ usb_stor_dbg(us, " Error issuing ATA Command Identify\n");
retStatus = ISD200_ERROR;
} else {
/* ATA Command Identify successful */
@@ -1136,7 +1138,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
__u16 *dest;
isd200_fix_driveid(id);
- isd200_dump_driveid(id);
+ isd200_dump_driveid(us, id);
memset(&info->InquiryData, 0, sizeof(info->InquiryData));
@@ -1170,7 +1172,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
/* determine if it supports Media Status Notification */
if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) {
- US_DEBUGP(" Device supports Media Status Notification\n");
+ usb_stor_dbg(us, " Device supports Media Status Notification\n");
/* Indicate that it is enabled, even though it is not
* This allows the lock/unlock of the media to work
@@ -1190,7 +1192,8 @@ static int isd200_get_inquiry_data( struct us_data *us )
us->protocol_name = "Transparent SCSI";
us->proto_handler = usb_stor_transparent_scsi_command;
- US_DEBUGP("Protocol changed to: %s\n", us->protocol_name);
+ usb_stor_dbg(us, "Protocol changed to: %s\n",
+ us->protocol_name);
/* Free driver structure */
us->extra_destructor(info);
@@ -1200,7 +1203,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
}
}
- US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus);
+ usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus);
return(retStatus);
}
@@ -1231,7 +1234,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
/* SCSI Command */
switch (srb->cmnd[0]) {
case INQUIRY:
- US_DEBUGP(" ATA OUT - INQUIRY\n");
+ usb_stor_dbg(us, " ATA OUT - INQUIRY\n");
/* copy InquiryData */
usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData,
@@ -1241,7 +1244,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case MODE_SENSE:
- US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_MODE_SENSE\n");
/* Initialize the return buffer */
usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb);
@@ -1255,14 +1258,14 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Media Status not supported, just report okay\n");
+ usb_stor_dbg(us, " Media Status not supported, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
case TEST_UNIT_READY:
- US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_TEST_UNIT_READY\n");
if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
{
@@ -1273,7 +1276,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Media Status not supported, just report okay\n");
+ usb_stor_dbg(us, " Media Status not supported, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
@@ -1284,7 +1287,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
unsigned long capacity;
struct read_capacity_data readCapacityData;
- US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_READ_CAPACITY\n");
if (ata_id_has_lba(id))
capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1;
@@ -1303,7 +1306,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case READ_10:
- US_DEBUGP(" ATA OUT - SCSIOP_READ\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_READ\n");
lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
@@ -1335,7 +1338,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case WRITE_10:
- US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_WRITE\n");
lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
@@ -1367,10 +1370,11 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
break;
case ALLOW_MEDIUM_REMOVAL:
- US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
- US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+ usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n",
+ srb->cmnd[4]);
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
@@ -1380,25 +1384,25 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK;
isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Not removeable media, just report okay\n");
+ usb_stor_dbg(us, " Not removeable media, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
case START_STOP:
- US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n");
- US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+ usb_stor_dbg(us, " ATA OUT - SCSIOP_START_STOP_UNIT\n");
+ usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
if ((srb->cmnd[4] & 0x3) == 0x2) {
- US_DEBUGP(" Media Eject\n");
+ usb_stor_dbg(us, " Media Eject\n");
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 0;
ataCdb->generic.RegisterSelect = REG_COMMAND;
ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
} else if ((srb->cmnd[4] & 0x3) == 0x1) {
- US_DEBUGP(" Get Media Status\n");
+ usb_stor_dbg(us, " Get Media Status\n");
ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
ataCdb->generic.TransferBlockSize = 1;
@@ -1406,14 +1410,15 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
isd200_srb_set_bufflen(srb, 0);
} else {
- US_DEBUGP(" Nothing to do, just report okay\n");
+ usb_stor_dbg(us, " Nothing to do, just report okay\n");
srb->result = SAM_STAT_GOOD;
sendToTransport = 0;
}
break;
default:
- US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]);
+ usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n",
+ srb->cmnd[0]);
srb->result = DID_ERROR << 16;
sendToTransport = 0;
break;
@@ -1457,8 +1462,7 @@ static int isd200_init_info(struct us_data *us)
retStatus = ISD200_ERROR;
else {
info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
- info->RegsBuf = (unsigned char *)
- kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+ info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
info->srb.sense_buffer =
kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) {
@@ -1471,8 +1475,7 @@ static int isd200_init_info(struct us_data *us)
if (retStatus == ISD200_GOOD) {
us->extra = info;
us->extra_destructor = isd200_free_info_ptrs;
- } else
- US_DEBUGP("ERROR - kmalloc failure\n");
+ }
return retStatus;
}
@@ -1483,19 +1486,19 @@ static int isd200_init_info(struct us_data *us)
static int isd200_Initialization(struct us_data *us)
{
- US_DEBUGP("ISD200 Initialization...\n");
+ usb_stor_dbg(us, "ISD200 Initialization...\n");
/* Initialize ISD200 info struct */
if (isd200_init_info(us) == ISD200_ERROR) {
- US_DEBUGP("ERROR Initializing ISD200 Info struct\n");
+ usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n");
} else {
/* Get device specific data */
if (isd200_get_inquiry_data(us) != ISD200_GOOD)
- US_DEBUGP("ISD200 Initialization Failure\n");
+ usb_stor_dbg(us, "ISD200 Initialization Failure\n");
else
- US_DEBUGP("ISD200 Initialization complete\n");
+ usb_stor_dbg(us, "ISD200 Initialization complete\n");
}
return 0;
@@ -1520,7 +1523,7 @@ static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
/* Make sure driver was initialized */
if (us->extra == NULL)
- US_DEBUGP("ERROR Driver not initialized\n");
+ usb_stor_dbg(us, "ERROR Driver not initialized\n");
scsi_set_resid(srb, 0);
/* scsi_bufflen might change in protocol translation to ata */
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index ddc78780b1ad..563078be6547 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -118,7 +118,7 @@ static inline int jumpshot_bulk_read(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("jumpshot_bulk_read: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
data, len, NULL);
}
@@ -131,7 +131,7 @@ static inline int jumpshot_bulk_write(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("jumpshot_bulk_write: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
data, len, NULL);
}
@@ -152,8 +152,7 @@ static int jumpshot_get_status(struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
if (us->iobuf[0] != 0x50) {
- US_DEBUGP("jumpshot_get_status: 0x%2x\n",
- us->iobuf[0]);
+ usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -218,7 +217,7 @@ static int jumpshot_read_data(struct us_data *us,
if (result != USB_STOR_XFER_GOOD)
goto leave;
- US_DEBUGP("jumpshot_read_data: %d bytes\n", len);
+ usb_stor_dbg(us, "%d bytes\n", len);
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
@@ -314,7 +313,7 @@ static int jumpshot_write_data(struct us_data *us,
} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
if (result != USB_STOR_TRANSPORT_GOOD)
- US_DEBUGP("jumpshot_write_data: Gah! Waitcount = 10. Bad write!?\n");
+ usb_stor_dbg(us, "Gah! Waitcount = 10. Bad write!?\n");
sector += thistime;
totallen -= len;
@@ -349,8 +348,7 @@ static int jumpshot_id_device(struct us_data *us,
0, 0x20, 0, 6, command, 2);
if (rc != USB_STOR_XFER_GOOD) {
- US_DEBUGP("jumpshot_id_device: Gah! "
- "send_control for read_capacity failed\n");
+ usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n");
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -400,17 +398,17 @@ static int jumpshot_handle_mode_sense(struct us_data *us,
switch (pc) {
case 0x0:
- US_DEBUGP("jumpshot_handle_mode_sense: Current values\n");
- break;
+ usb_stor_dbg(us, "Current values\n");
+ break;
case 0x1:
- US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n");
- break;
+ usb_stor_dbg(us, "Changeable values\n");
+ break;
case 0x2:
- US_DEBUGP("jumpshot_handle_mode_sense: Default values\n");
- break;
+ usb_stor_dbg(us, "Default values\n");
+ break;
case 0x3:
- US_DEBUGP("jumpshot_handle_mode_sense: Saves values\n");
- break;
+ usb_stor_dbg(us, "Saves values\n");
+ break;
}
memset(ptr, 0, 8);
@@ -494,17 +492,16 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
if (!us->extra) {
us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n");
+ if (!us->extra)
return USB_STOR_TRANSPORT_ERROR;
- }
+
us->extra_destructor = jumpshot_info_destructor;
}
info = (struct jumpshot_info *) (us->extra);
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_response, sizeof(inquiry_response));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -521,8 +518,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("jumpshot_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
// build the reply
//
@@ -534,7 +531,7 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("jumpshot_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -544,7 +541,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("jumpshot_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_read_data(us, info, block, blocks);
}
@@ -557,7 +555,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("jumpshot_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_read_data(us, info, block, blocks);
}
@@ -567,7 +566,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("jumpshot_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_write_data(us, info, block, blocks);
}
@@ -580,18 +580,19 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return jumpshot_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
return jumpshot_get_status(us);
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("jumpshot_transport: REQUEST_SENSE.\n");
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
memset(ptr, 0, 18);
ptr[0] = 0xF0;
@@ -605,12 +606,12 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SENSE) {
- US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_6 detected\n");
return jumpshot_handle_mode_sense(us, srb, 1);
}
if (srb->cmnd[0] == MODE_SENSE_10) {
- US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n");
+ usb_stor_dbg(us, "MODE_SENSE_10 detected\n");
return jumpshot_handle_mode_sense(us, srb, 0);
}
@@ -624,7 +625,7 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == START_STOP) {
/* this is used by sd.c'check_scsidisk_media_change to detect
media change */
- US_DEBUGP("jumpshot_transport: START_STOP.\n");
+ usb_stor_dbg(us, "START_STOP\n");
/* the first jumpshot_id_device after a media change returns
an error (determined experimentally) */
rc = jumpshot_id_device(us, info);
@@ -638,8 +639,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us)
return rc;
}
- US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index f085ffb606c8..94d16ee5e84b 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -106,7 +106,7 @@ static int rio_karma_send_command(char cmd, struct us_data *us)
static unsigned char seq = 1;
struct karma_data *data = (struct karma_data *) us->extra;
- US_DEBUGP("karma: sending command %04x\n", cmd);
+ usb_stor_dbg(us, "sending command %04x\n", cmd);
memset(us->iobuf, 0, RIO_SEND_LEN);
memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
us->iobuf[5] = cmd;
@@ -139,10 +139,10 @@ static int rio_karma_send_command(char cmd, struct us_data *us)
if (seq == 0)
seq = 1;
- US_DEBUGP("karma: sent command %04x\n", cmd);
+ usb_stor_dbg(us, "sent command %04x\n", cmd);
return 0;
err:
- US_DEBUGP("karma: command %04x failed\n", cmd);
+ usb_stor_dbg(us, "command %04x failed\n", cmd);
return USB_STOR_TRANSPORT_FAILED;
}
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index cb79de61f4c8..26964895c88b 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -195,6 +195,7 @@ static int onetouch_connect_input(struct us_data *ss)
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ maxp = min(maxp, ONETOUCH_PKT_LEN);
onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -245,8 +246,7 @@ static int onetouch_connect_input(struct us_data *ss)
input_dev->open = usb_onetouch_open;
input_dev->close = usb_onetouch_close;
- usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data,
- (maxp > 8 ? 8 : maxp),
+ usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,
usb_onetouch_irq, onetouch, endpoint->bInterval);
onetouch->irq->transfer_dma = onetouch->data_dma;
onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
index e0f76bb05915..b2b35b1d7de8 100644
--- a/drivers/usb/storage/option_ms.c
+++ b/drivers/usb/storage/option_ms.c
@@ -50,7 +50,7 @@ static int option_rezero(struct us_data *us)
char *buffer;
int result;
- US_DEBUGP("Option MS: %s", "DEVICE MODE SWITCH\n");
+ usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH");
buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
if (buffer == NULL)
@@ -95,7 +95,7 @@ static int option_inquiry(struct us_data *us)
char *buffer;
int result;
- US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n");
+ usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name");
buffer = kzalloc(0x24, GFP_KERNEL);
if (buffer == NULL)
@@ -138,31 +138,32 @@ int option_ms_init(struct us_data *us)
{
int result;
- US_DEBUGP("Option MS: option_ms_init called\n");
+ usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called");
/* Additional test for vendor information via INQUIRY,
* because some vendor/product IDs are ambiguous
*/
result = option_inquiry(us);
if (result != 0) {
- US_DEBUGP("Option MS: vendor is not Option or not determinable,"
- " no action taken\n");
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "vendor is not Option or not determinable, no action taken");
return 0;
} else
- US_DEBUGP("Option MS: this is a genuine Option device,"
- " proceeding\n");
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "this is a genuine Option device, proceeding");
/* Force Modem mode */
if (option_zero_cd == ZCD_FORCE_MODEM) {
- US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n");
+ usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode");
result = option_rezero(us);
if (result != USB_STOR_XFER_GOOD)
- US_DEBUGP("Option MS: Failed to switch to modem mode.\n");
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "Failed to switch to modem mode");
return -EIO;
} else if (option_zero_cd == ZCD_ALLOW_MS) {
/* Allow Mass Storage mode (keep CD-Rom) */
- US_DEBUGP("Option MS: %s", "Allowing Mass Storage Mode if device"
- " requests it\n");
+ usb_stor_dbg(us, "Option MS: %s\n",
+ "Allowing Mass Storage Mode if device requests it");
}
return 0;
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 6c3586a4c956..8623577bbbe7 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -254,8 +254,8 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
/* check bulk status */
if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN)) {
- US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
- le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN);
+ usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -351,8 +351,8 @@ static int rts51x_get_max_lun(struct us_data *us)
USB_RECIP_INTERFACE,
0, us->ifnum, us->iobuf, 1, 10 * HZ);
- US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
- result, us->iobuf[0]);
+ usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+ result, us->iobuf[0]);
/* if we have a successful request, return the result */
if (result > 0)
@@ -371,7 +371,7 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
+ usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
cmnd[0] = 0xF0;
cmnd[1] = 0x0D;
@@ -402,7 +402,7 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
+ usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len);
cmnd[0] = 0xF0;
cmnd[1] = 0x0E;
@@ -431,7 +431,7 @@ static int rts51x_read_status(struct us_data *us,
if (buf == NULL)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("%s, lun = %d\n", __func__, lun);
+ usb_stor_dbg(us, "lun = %d\n", lun);
cmnd[0] = 0xF0;
cmnd[1] = 0x09;
@@ -458,7 +458,7 @@ static int rts51x_check_status(struct us_data *us, u8 lun)
if (retval != STATUS_SUCCESS)
return -EIO;
- US_DEBUGP("chip->status_len = %d\n", chip->status_len);
+ usb_stor_dbg(us, "chip->status_len = %d\n", chip->status_len);
chip->status[lun].vid = ((u16) buf[0] << 8) | buf[1];
chip->status[lun].pid = ((u16) buf[2] << 8) | buf[3];
@@ -509,7 +509,7 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
u8 cmnd[12] = {0};
u8 *buf;
- US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
+ usb_stor_dbg(us, "addr = 0xfe47, len = %d\n", len);
buf = kmemdup(data, len, GFP_NOIO);
if (!buf)
@@ -549,7 +549,7 @@ static int do_config_autodelink(struct us_data *us, int enable, int force)
value &= ~0x03;
}
- US_DEBUGP("In %s,set 0xfe47 to 0x%x\n", __func__, value);
+ usb_stor_dbg(us, "set 0xfe47 to 0x%x\n", value);
/* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */
retval = __do_config_autodelink(us, &value, 1);
@@ -565,8 +565,6 @@ static int config_autodelink_after_power_on(struct us_data *us)
int retval;
u8 value;
- US_DEBUGP("%s: <---\n", __func__);
-
if (!CHK_AUTO_DELINK(chip))
return 0;
@@ -624,8 +622,6 @@ static int config_autodelink_after_power_on(struct us_data *us)
}
}
- US_DEBUGP("%s: --->\n", __func__);
-
return 0;
}
@@ -635,8 +631,6 @@ static int config_autodelink_before_power_down(struct us_data *us)
int retval;
u8 value;
- US_DEBUGP("%s: <---\n", __func__);
-
if (!CHK_AUTO_DELINK(chip))
return 0;
@@ -698,8 +692,6 @@ static int config_autodelink_before_power_down(struct us_data *us)
}
}
- US_DEBUGP("%s: --->\n", __func__);
-
return 0;
}
@@ -709,23 +701,19 @@ static void fw5895_init(struct us_data *us)
int retval;
u8 val;
- US_DEBUGP("%s: <---\n", __func__);
-
if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
- US_DEBUGP("Not the specified device, return immediately!\n");
+ usb_stor_dbg(us, "Not the specified device, return immediately!\n");
} else {
retval = rts51x_read_mem(us, 0xFD6F, &val, 1);
if (retval == STATUS_SUCCESS && (val & 0x1F) == 0) {
val = 0x1F;
retval = rts51x_write_mem(us, 0xFD70, &val, 1);
if (retval != STATUS_SUCCESS)
- US_DEBUGP("Write memory fail\n");
+ usb_stor_dbg(us, "Write memory fail\n");
} else {
- US_DEBUGP("Read memory fail, OR (val & 0x1F) != 0\n");
+ usb_stor_dbg(us, "Read memory fail, OR (val & 0x1F) != 0\n");
}
}
-
- US_DEBUGP("%s: --->\n", __func__);
}
#ifdef CONFIG_REALTEK_AUTOPM
@@ -735,10 +723,8 @@ static void fw5895_set_mmc_wp(struct us_data *us)
int retval;
u8 buf[13];
- US_DEBUGP("%s: <---\n", __func__);
-
if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) {
- US_DEBUGP("Not the specified device, return immediately!\n");
+ usb_stor_dbg(us, "Not the specified device, return immediately!\n");
} else {
retval = rts51x_read_mem(us, 0xFD6F, buf, 1);
if (retval == STATUS_SUCCESS && (buf[0] & 0x24) == 0x24) {
@@ -748,26 +734,24 @@ static void fw5895_set_mmc_wp(struct us_data *us)
buf[0] |= 0x04;
retval = rts51x_write_mem(us, 0xFD70, buf, 1);
if (retval != STATUS_SUCCESS)
- US_DEBUGP("Write memory fail\n");
+ usb_stor_dbg(us, "Write memory fail\n");
} else {
- US_DEBUGP("Read memory fail\n");
+ usb_stor_dbg(us, "Read memory fail\n");
}
} else {
- US_DEBUGP("Read memory fail, OR (buf[0]&0x24)!=0x24\n");
+ usb_stor_dbg(us, "Read memory fail, OR (buf[0]&0x24)!=0x24\n");
}
}
-
- US_DEBUGP("%s: --->\n", __func__);
}
static void rts51x_modi_suspend_timer(struct rts51x_chip *chip)
{
- US_DEBUGP("%s: <---, state:%d\n", __func__, rts51x_get_stat(chip));
+ struct us_data *us = chip->us;
+
+ usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay);
mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires);
-
- US_DEBUGP("%s: --->\n", __func__);
}
static void rts51x_suspend_timer_fn(unsigned long data)
@@ -775,8 +759,6 @@ static void rts51x_suspend_timer_fn(unsigned long data)
struct rts51x_chip *chip = (struct rts51x_chip *)data;
struct us_data *us = chip->us;
- US_DEBUGP("%s: <---\n", __func__);
-
switch (rts51x_get_stat(chip)) {
case RTS51X_STAT_INIT:
case RTS51X_STAT_RUN:
@@ -784,32 +766,25 @@ static void rts51x_suspend_timer_fn(unsigned long data)
break;
case RTS51X_STAT_IDLE:
case RTS51X_STAT_SS:
- US_DEBUGP("%s: RTS51X_STAT_SS, intf->pm_usage_cnt:%d,"
- "power.usage:%d\n", __func__,
- atomic_read(&us->pusb_intf->pm_usage_cnt),
- atomic_read(&us->pusb_intf->dev.power.usage_count));
+ usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) {
- US_DEBUGP("%s: Ready to enter SS state.\n",
- __func__);
+ usb_stor_dbg(us, "Ready to enter SS state\n");
rts51x_set_stat(chip, RTS51X_STAT_SS);
/* ignore mass storage interface's children */
pm_suspend_ignore_children(&us->pusb_intf->dev, true);
usb_autopm_put_interface_async(us->pusb_intf);
- US_DEBUGP("%s: RTS51X_STAT_SS 01,"
- "intf->pm_usage_cnt:%d, power.usage:%d\n",
- __func__,
- atomic_read(&us->pusb_intf->pm_usage_cnt),
- atomic_read(
- &us->pusb_intf->dev.power.usage_count));
+ usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
}
break;
default:
- US_DEBUGP("%s: Unknonwn state !!!\n", __func__);
+ usb_stor_dbg(us, "Unknown state !!!\n");
break;
}
-
- US_DEBUGP("%s: --->\n", __func__);
}
static inline int working_scsi(struct scsi_cmnd *srb)
@@ -834,24 +809,21 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
};
int ret;
- US_DEBUGP("%s: <---\n", __func__);
-
if (working_scsi(srb)) {
- US_DEBUGP("%s: working scsi, intf->pm_usage_cnt:%d,"
- "power.usage:%d\n", __func__,
- atomic_read(&us->pusb_intf->pm_usage_cnt),
- atomic_read(&us->pusb_intf->dev.power.usage_count));
+ usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n",
+ atomic_read(&us->pusb_intf->pm_usage_cnt),
+ atomic_read(&us->pusb_intf->dev.power.usage_count));
if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) {
ret = usb_autopm_get_interface(us->pusb_intf);
- US_DEBUGP("%s: working scsi, ret=%d\n", __func__, ret);
+ usb_stor_dbg(us, "working scsi, ret=%d\n", ret);
}
if (rts51x_get_stat(chip) != RTS51X_STAT_RUN)
rts51x_set_stat(chip, RTS51X_STAT_RUN);
chip->proto_handler_backup(srb, us);
} else {
if (rts51x_get_stat(chip) == RTS51X_STAT_SS) {
- US_DEBUGP("%s: NOT working scsi\n", __func__);
+ usb_stor_dbg(us, "NOT working scsi\n");
if ((srb->cmnd[0] == TEST_UNIT_READY) &&
(chip->pwr_state == US_SUSPEND)) {
if (TST_LUN_READY(chip, srb->device->lun)) {
@@ -862,8 +834,7 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
media_not_present,
US_SENSE_SIZE);
}
- US_DEBUGP("%s: TEST_UNIT_READY--->\n",
- __func__);
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
goto out;
}
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
@@ -876,12 +847,11 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
} else {
srb->result = SAM_STAT_GOOD;
}
- US_DEBUGP("%s: ALLOW_MEDIUM_REMOVAL--->\n",
- __func__);
+ usb_stor_dbg(us, "ALLOW_MEDIUM_REMOVAL\n");
goto out;
}
} else {
- US_DEBUGP("%s: NOT working scsi, not SS\n", __func__);
+ usb_stor_dbg(us, "NOT working scsi, not SS\n");
chip->proto_handler_backup(srb, us);
/* Check whether card is plugged in */
if (srb->cmnd[0] == TEST_UNIT_READY) {
@@ -901,11 +871,9 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
}
}
out:
- US_DEBUGP("%s: state:%d\n", __func__, rts51x_get_stat(chip));
+ usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip));
if (rts51x_get_stat(chip) == RTS51X_STAT_RUN)
rts51x_modi_suspend_timer(chip);
-
- US_DEBUGP("%s: --->\n", __func__);
}
static int realtek_cr_autosuspend_setup(struct us_data *us)
@@ -923,7 +891,7 @@ static int realtek_cr_autosuspend_setup(struct us_data *us)
retval = rts51x_read_status(us, 0, buf, 16, &(chip->status_len));
if (retval != STATUS_SUCCESS) {
- US_DEBUGP("Read status fail\n");
+ usb_stor_dbg(us, "Read status fail\n");
return -EIO;
}
status = chip->status;
@@ -965,12 +933,11 @@ static int realtek_cr_autosuspend_setup(struct us_data *us)
static void realtek_cr_destructor(void *extra)
{
- struct rts51x_chip *chip = (struct rts51x_chip *)extra;
-
- US_DEBUGP("%s: <---\n", __func__);
+ struct rts51x_chip *chip = extra;
if (!chip)
return;
+
#ifdef CONFIG_REALTEK_AUTOPM
if (ss_en) {
del_timer(&chip->rts51x_suspend_timer);
@@ -985,8 +952,6 @@ static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s: <---\n", __func__);
-
/* wait until no command is running */
mutex_lock(&us->dev_mutex);
@@ -994,8 +959,6 @@ static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
mutex_unlock(&us->dev_mutex);
- US_DEBUGP("%s: --->\n", __func__);
-
return 0;
}
@@ -1003,13 +966,9 @@ static int realtek_cr_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s: <---\n", __func__);
-
fw5895_init(us);
config_autodelink_after_power_on(us);
- US_DEBUGP("%s: --->\n", __func__);
-
return 0;
}
#else
@@ -1030,7 +989,7 @@ static int init_realtek_cr(struct us_data *us)
us->extra_destructor = realtek_cr_destructor;
us->max_lun = chip->max_lun = rts51x_get_max_lun(us);
- US_DEBUGP("chip->max_lun = %d\n", chip->max_lun);
+ usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun);
size = (chip->max_lun + 1) * sizeof(struct rts51x_status);
chip->status = kzalloc(size, GFP_KERNEL);
@@ -1057,7 +1016,7 @@ static int init_realtek_cr(struct us_data *us)
}
#endif
- US_DEBUGP("chip->flag = 0x%x\n", chip->flag);
+ usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag);
(void)config_autodelink_after_power_on(us);
@@ -1079,7 +1038,7 @@ static int realtek_cr_probe(struct usb_interface *intf,
struct us_data *us;
int result;
- US_DEBUGP("Probe Realtek Card Reader!\n");
+ dev_dbg(&intf->dev, "Probe Realtek Card Reader!\n");
result = usb_stor_probe1(&us, intf, id,
(id - realtek_cr_ids) +
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 615c66eaedeb..92b05d95ec5e 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -313,8 +313,6 @@ static int queuecommand_lck(struct scsi_cmnd *srb,
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __func__);
-
/* check for state-transition errors */
if (us->srb != NULL) {
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
@@ -324,7 +322,7 @@ static int queuecommand_lck(struct scsi_cmnd *srb,
/* fail the command if we are disconnecting */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
- US_DEBUGP("Fail command during disconnect\n");
+ usb_stor_dbg(us, "Fail command during disconnect\n");
srb->result = DID_NO_CONNECT << 16;
done(srb);
return 0;
@@ -349,7 +347,7 @@ static int command_abort(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
- US_DEBUGP("%s called\n", __func__);
+ usb_stor_dbg(us, "%s called\n", __func__);
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. */
@@ -358,7 +356,7 @@ static int command_abort(struct scsi_cmnd *srb)
/* Is this command still active? */
if (us->srb != srb) {
scsi_unlock(us_to_host(us));
- US_DEBUGP ("-- nothing to abort\n");
+ usb_stor_dbg(us, "-- nothing to abort\n");
return FAILED;
}
@@ -386,7 +384,7 @@ static int device_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __func__);
+ usb_stor_dbg(us, "%s called\n", __func__);
/* lock the device pointers and do the reset */
mutex_lock(&(us->dev_mutex));
@@ -402,7 +400,8 @@ static int bus_reset(struct scsi_cmnd *srb)
struct us_data *us = host_to_us(srb->device->host);
int result;
- US_DEBUGP("%s called\n", __func__);
+ usb_stor_dbg(us, "%s called\n", __func__);
+
result = usb_stor_port_reset(us);
return result < 0 ? FAILED : SUCCESS;
}
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 7bd54e0d5120..732027f33200 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -105,8 +105,6 @@ static struct us_unusual_dev sddr09_unusual_dev_list[] = {
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
-/* #define US_DEBUGP printk */
-
/*
* First some stuff that does not belong here:
* data on SmartMedia and other cards, completely
@@ -347,7 +345,7 @@ sddr09_test_unit_ready(struct us_data *us) {
result = sddr09_send_scsi_command(us, command, 6);
- US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
+ usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result);
return result;
}
@@ -423,8 +421,8 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
result = sddr09_send_scsi_command(us, command, 12);
if (result) {
- US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
- x, result);
+ usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n",
+ x, result);
return result;
}
@@ -432,8 +430,8 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
buf, bulklen, use_sg, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
- x, result);
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n",
+ x, result);
return -EIO;
}
return 0;
@@ -494,8 +492,7 @@ sddr09_read22(struct us_data *us, unsigned long fromaddress,
int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
- US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n",
- nr_of_pages, bulklen);
+ usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen);
return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
buf, use_sg);
}
@@ -538,7 +535,7 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) {
unsigned char *command = us->iobuf;
int result;
- US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress);
+ usb_stor_dbg(us, "erase address %lu\n", Eaddress);
memset(command, 0, 12);
command[0] = 0xEA;
@@ -551,8 +548,8 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) {
result = sddr09_send_scsi_command(us, command, 12);
if (result)
- US_DEBUGP("Result for send_control in sddr09_erase %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n",
+ result);
return result;
}
@@ -609,8 +606,8 @@ sddr09_writeX(struct us_data *us,
result = sddr09_send_scsi_command(us, command, 12);
if (result) {
- US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n",
+ result);
return result;
}
@@ -618,8 +615,8 @@ sddr09_writeX(struct us_data *us,
buf, bulklen, use_sg, NULL);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
- result);
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n",
+ result);
return -EIO;
}
return 0;
@@ -687,8 +684,8 @@ sddr09_read_sg_test_only(struct us_data *us) {
result = sddr09_send_scsi_command(us, command, 4*nsg+3);
if (result) {
- US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n",
+ result);
return result;
}
@@ -700,8 +697,8 @@ sddr09_read_sg_test_only(struct us_data *us) {
buf, bulklen, NULL);
kfree(buf);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
- result);
+ usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n",
+ result);
return -EIO;
}
@@ -727,7 +724,7 @@ sddr09_read_status(struct us_data *us, unsigned char *status) {
unsigned char *data = us->iobuf;
int result;
- US_DEBUGP("Reading status...\n");
+ usb_stor_dbg(us, "Reading status...\n");
memset(command, 0, 12);
command[0] = 0xEC;
@@ -789,8 +786,8 @@ sddr09_read_data(struct us_data *us,
/* Not overflowing capacity? */
if (lba >= maxlba) {
- US_DEBUGP("Error: Requested lba %u exceeds "
- "maximum %u\n", lba, maxlba);
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, maxlba);
result = -EIO;
break;
}
@@ -800,8 +797,8 @@ sddr09_read_data(struct us_data *us,
if (pba == UNDEF) { /* this lba was never written */
- US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
- pages, lba, page);
+ usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n",
+ pages, lba, page);
/* This is not really an error. It just means
that the block has never been written.
@@ -811,9 +808,8 @@ sddr09_read_data(struct us_data *us,
memset(buffer, 0, len);
} else {
- US_DEBUGP("Read %d pages, from PBA %d"
- " (LBA %d) page %d\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n",
+ pages, pba, lba, page);
address = ((pba << info->blockshift) + page) <<
info->pageshift;
@@ -916,14 +912,14 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
cptr = bptr + info->pagesize;
nand_compute_ecc(bptr, ecc);
if (!nand_compare_ecc(cptr+13, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+13, ecc);
}
nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
if (!nand_compare_ecc(cptr+8, ecc)) {
- US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
- i, pba);
+ usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n",
+ i, pba);
nand_store_ecc(cptr+8, ecc);
}
cptr[6] = cptr[11] = MSB_of(lbap);
@@ -943,22 +939,21 @@ sddr09_write_lba(struct us_data *us, unsigned int lba,
nand_store_ecc(cptr+8, ecc);
}
- US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
+ usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba);
result = sddr09_write_inplace(us, address>>1, info->blocksize,
info->pageshift, blockbuffer, 0);
- US_DEBUGP("sddr09_write_inplace returns %d\n", result);
+ usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result);
#if 0
{
unsigned char status = 0;
int result2 = sddr09_read_status(us, &status);
if (result2)
- US_DEBUGP("sddr09_write_inplace: cannot read status\n");
+ usb_stor_dbg(us, "cannot read status\n");
else if (status != 0xc0)
- US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
- status);
+ usb_stor_dbg(us, "status after write: 0x%x\n", status);
}
#endif
@@ -1031,8 +1026,8 @@ sddr09_write_data(struct us_data *us,
/* Not overflowing capacity? */
if (lba >= maxlba) {
- US_DEBUGP("Error: Requested lba %u exceeds "
- "maximum %u\n", lba, maxlba);
+ usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n",
+ lba, maxlba);
result = -EIO;
break;
}
@@ -1064,8 +1059,8 @@ sddr09_read_control(struct us_data *us,
unsigned char *content,
int use_sg) {
- US_DEBUGP("Read control address %lu, blocks %d\n",
- address, blocks);
+ usb_stor_dbg(us, "Read control address %lu, blocks %d\n",
+ address, blocks);
return sddr09_read21(us, address, blocks,
CONTROL_SHIFT, content, use_sg);
@@ -1111,21 +1106,21 @@ sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
result = sddr09_read_status(us, &status);
if (result) {
- US_DEBUGP("sddr09_get_wp: read_status fails\n");
+ usb_stor_dbg(us, "read_status fails\n");
return result;
}
- US_DEBUGP("sddr09_get_wp: status 0x%02X", status);
+ usb_stor_dbg(us, "status 0x%02X", status);
if ((status & 0x80) == 0) {
info->flags |= SDDR09_WP; /* write protected */
- US_DEBUGP(" WP");
+ US_DEBUGPX(" WP");
}
if (status & 0x40)
- US_DEBUGP(" Ready");
+ US_DEBUGPX(" Ready");
if (status & LUNBITS)
- US_DEBUGP(" Suspended");
+ US_DEBUGPX(" Suspended");
if (status & 0x1)
- US_DEBUGP(" Error");
- US_DEBUGP("\n");
+ US_DEBUGPX(" Error");
+ US_DEBUGPX("\n");
return 0;
}
@@ -1154,12 +1149,12 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
char blurbtxt[256];
int result;
- US_DEBUGP("Reading capacity...\n");
+ usb_stor_dbg(us, "Reading capacity...\n");
result = sddr09_read_deviceID(us, deviceID);
if (result) {
- US_DEBUGP("Result of read_deviceID is %d\n", result);
+ usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
printk(KERN_WARNING "sddr09: could not read card info\n");
return NULL;
}
@@ -1392,7 +1387,7 @@ sddr09_read_map(struct us_data *us) {
lbact += ct;
}
info->lbact = lbact;
- US_DEBUGP("Found %d LBA's\n", lbact);
+ usb_stor_dbg(us, "Found %d LBA's\n", lbact);
result = 0;
done:
@@ -1423,18 +1418,18 @@ sddr09_common_init(struct us_data *us) {
/* set the configuration -- STALL is an acceptable response here */
if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
- US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
- ->actconfig->desc.bConfigurationValue);
+ usb_stor_dbg(us, "active config #%d != 1 ??\n",
+ us->pusb_dev->actconfig->desc.bConfigurationValue);
return -EINVAL;
}
result = usb_reset_configuration(us->pusb_dev);
- US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
+ usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result);
if (result == -EPIPE) {
- US_DEBUGP("-- stall on control interface\n");
+ usb_stor_dbg(us, "-- stall on control interface\n");
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
- US_DEBUGP("-- Unknown error. Rejecting device\n");
+ usb_stor_dbg(us, "-- Unknown error. Rejecting device\n");
return -EINVAL;
}
@@ -1464,20 +1459,20 @@ usb_stor_sddr09_dpcm_init(struct us_data *us) {
result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
if (result) {
- US_DEBUGP("sddr09_init: send_command fails\n");
+ usb_stor_dbg(us, "send_command fails\n");
return result;
}
- US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+ usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
// get 07 02
result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
if (result) {
- US_DEBUGP("sddr09_init: 2nd send_command fails\n");
+ usb_stor_dbg(us, "2nd send_command fails\n");
return result;
}
- US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+ usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]);
// get 07 00
result = sddr09_request_sense(us, data, 18);
@@ -1507,7 +1502,7 @@ static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
{
int ret;
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+ usb_stor_dbg(us, "LUN=%d\n", srb->device->lun);
switch (srb->device->lun) {
case 0:
@@ -1533,8 +1528,7 @@ static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
break;
default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n",
- srb->device->lun);
+ usb_stor_dbg(us, "Invalid LUN %d\n", srb->device->lun);
ret = USB_STOR_TRANSPORT_ERROR;
break;
}
@@ -1640,8 +1634,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
or for all pages. */
/* %% We should check DBD %% */
if (modepage == 0x01 || modepage == 0x3F) {
- US_DEBUGP("SDDR09: Dummy up request for "
- "mode page 0x%x\n", modepage);
+ usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n",
+ modepage);
memcpy(ptr, mode_page_01, sizeof(mode_page_01));
((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
@@ -1667,8 +1661,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("READ_10: read page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "READ_10: read page %d pagect %d\n",
+ page, pages);
result = sddr09_read_data(us, page, pages);
return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
@@ -1682,8 +1676,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
- US_DEBUGP("WRITE_10: write page %d pagect %d\n",
- page, pages);
+ usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n",
+ page, pages);
result = sddr09_write_data(us, page, pages);
return (result == 0 ? USB_STOR_TRANSPORT_GOOD :
@@ -1710,12 +1704,12 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
for (i=0; i<12; i++)
sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]);
- US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
+ usb_stor_dbg(us, "Send control for command %s\n", ptr);
result = sddr09_send_scsi_command(us, srb->cmnd, 12);
if (result) {
- US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
- "returns %d\n", result);
+ usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n",
+ result);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1727,10 +1721,10 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE)
? us->send_bulk_pipe : us->recv_bulk_pipe;
- US_DEBUGP("SDDR09: %s %d bytes\n",
- (srb->sc_data_direction == DMA_TO_DEVICE) ?
- "sending" : "receiving",
- scsi_bufflen(srb));
+ usb_stor_dbg(us, "%s %d bytes\n",
+ (srb->sc_data_direction == DMA_TO_DEVICE) ?
+ "sending" : "receiving",
+ scsi_bufflen(srb));
result = usb_stor_bulk_srb(us, pipe, srb);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index d278c5a99b7a..aacedef9667c 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -145,8 +145,7 @@ static int sddr55_status(struct us_data *us)
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result for send_command in status %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in status %d\n", result);
if (result != USB_STOR_XFER_GOOD) {
set_sense_info (4, 0, 0); /* hardware error */
@@ -236,9 +235,8 @@ static int sddr55_read_data(struct us_data *us,
info->blocksize - page);
len = pages << info->pageshift;
- US_DEBUGP("Read %02X pages, from PBA %04X"
- " (LBA %04X) page %02X\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Read %02X pages, from PBA %04X (LBA %04X) page %02X\n",
+ pages, pba, lba, page);
if (pba == NOT_ALLOCATED) {
/* no pba for this lba, fill with zeroes */
@@ -261,8 +259,8 @@ static int sddr55_read_data(struct us_data *us,
result = sddr55_bulk_transport(us,
DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result for send_command in read_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in read_data %d\n",
+ result);
if (result != USB_STOR_XFER_GOOD) {
result = USB_STOR_TRANSPORT_ERROR;
@@ -368,9 +366,8 @@ static int sddr55_write_data(struct us_data *us,
usb_stor_access_xfer_buf(buffer, len, us->srb,
&sg, &offset, FROM_XFER_BUF);
- US_DEBUGP("Write %02X pages, to PBA %04X"
- " (LBA %04X) page %02X\n",
- pages, pba, lba, page);
+ usb_stor_dbg(us, "Write %02X pages, to PBA %04X (LBA %04X) page %02X\n",
+ pages, pba, lba, page);
command[4] = 0;
@@ -384,7 +381,7 @@ static int sddr55_write_data(struct us_data *us,
/* set pba to first block in zone lba is in */
pba = (lba / 1000) * 1024;
- US_DEBUGP("No PBA for LBA %04X\n",lba);
+ usb_stor_dbg(us, "No PBA for LBA %04X\n", lba);
if (max_pba > 1024)
max_pba = 1024;
@@ -407,14 +404,15 @@ static int sddr55_write_data(struct us_data *us,
if (pba == -1) {
/* oh dear */
- US_DEBUGP("Couldn't find unallocated block\n");
+ usb_stor_dbg(us, "Couldn't find unallocated block\n");
set_sense_info (3, 0x31, 0); /* medium error */
result = USB_STOR_TRANSPORT_FAILED;
goto leave;
}
- US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba);
+ usb_stor_dbg(us, "Allocating PBA %04X for LBA %04X\n",
+ pba, lba);
/* set writing to unallocated block flag */
command[4] = 0x40;
@@ -439,8 +437,8 @@ static int sddr55_write_data(struct us_data *us,
DMA_TO_DEVICE, command, 8);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for send_command in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_command in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -453,8 +451,8 @@ static int sddr55_write_data(struct us_data *us,
DMA_TO_DEVICE, buffer, len);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for send_data in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for send_data in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -466,8 +464,8 @@ static int sddr55_write_data(struct us_data *us,
result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6);
if (result != USB_STOR_XFER_GOOD) {
- US_DEBUGP("Result for get_status in write_data %d\n",
- result);
+ usb_stor_dbg(us, "Result for get_status in write_data %d\n",
+ result);
/* set_sense_info is superfluous here? */
set_sense_info (3, 0x3, 0);/* peripheral write error */
@@ -487,8 +485,8 @@ static int sddr55_write_data(struct us_data *us,
goto leave;
}
- US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
- lba, pba, new_pba);
+ usb_stor_dbg(us, "Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
+ lba, pba, new_pba);
/* update the lba<->pba maps, note new_pba might be the same as pba */
info->lba_to_pba[lba] = new_pba;
@@ -531,8 +529,8 @@ static int sddr55_read_deviceID(struct us_data *us,
command[7] = 0x84;
result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
- US_DEBUGP("Result of send_control for device ID is %d\n",
- result);
+ usb_stor_dbg(us, "Result of send_control for device ID is %d\n",
+ result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -568,20 +566,19 @@ static unsigned long sddr55_get_capacity(struct us_data *us) {
int result;
struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
- US_DEBUGP("Reading capacity...\n");
+ usb_stor_dbg(us, "Reading capacity...\n");
result = sddr55_read_deviceID(us,
&manufacturerID,
&deviceID);
- US_DEBUGP("Result of read_deviceID is %d\n",
- result);
+ usb_stor_dbg(us, "Result of read_deviceID is %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return 0;
- US_DEBUGP("Device ID = %02X\n", deviceID);
- US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
+ usb_stor_dbg(us, "Device ID = %02X\n", deviceID);
+ usb_stor_dbg(us, "Manuf ID = %02X\n", manufacturerID);
info->pageshift = 9;
info->smallpageshift = 0;
@@ -753,7 +750,7 @@ static int sddr55_read_map(struct us_data *us) {
}
if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
- US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
+ usb_stor_dbg(us, "LBA %04X <-> PBA %04X\n", lba, i);
info->lba_to_pba[lba + zone * 1000] = i;
}
@@ -808,7 +805,10 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
info = (struct sddr55_card_info *)(us->extra);
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]);
+ usb_stor_dbg(us, "request sense %02x/%02x/%02x\n",
+ info->sense_data[2],
+ info->sense_data[12],
+ info->sense_data[13]);
memcpy (ptr, info->sense_data, sizeof info->sense_data);
ptr[0] = 0x70;
@@ -892,13 +892,11 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
- US_DEBUGP(
- "SDDR55: Dummy up request for mode page 1\n");
+ usb_stor_dbg(us, "Dummy up request for mode page 1\n");
return USB_STOR_TRANSPORT_GOOD;
} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
- US_DEBUGP(
- "SDDR55: Dummy up request for all mode pages\n");
+ usb_stor_dbg(us, "Dummy up request for all mode pages\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -908,10 +906,8 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
- US_DEBUGP(
- "SDDR55: %s medium removal. Not that I can do"
- " anything about it...\n",
- (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+ usb_stor_dbg(us, "%s medium removal. Not that I can do anything about it...\n",
+ (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
return USB_STOR_TRANSPORT_GOOD;
@@ -935,8 +931,8 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
if (lba >= info->max_log_blks) {
- US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
- "block %04X\n", lba, info->max_log_blks-1);
+ usb_stor_dbg(us, "Error: Requested LBA %04X exceeds maximum block %04X\n",
+ lba, info->max_log_blks - 1);
set_sense_info (5, 0x24, 0); /* invalid field in command */
@@ -946,15 +942,13 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
pba = info->lba_to_pba[lba];
if (srb->cmnd[0] == WRITE_10) {
- US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X"
- " pages %d\n",
- pba, lba, page, pages);
+ usb_stor_dbg(us, "WRITE_10: write block %04X (LBA %04X) page %01X pages %d\n",
+ pba, lba, page, pages);
return sddr55_write_data(us, lba, page, pages);
} else {
- US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
- " pages %d\n",
- pba, lba, page, pages);
+ usb_stor_dbg(us, "READ_10: read block %04X (LBA %04X) page %01X pages %d\n",
+ pba, lba, page, pages);
return sddr55_read_data(us, lba, page, pages);
}
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index daf2fc58ae02..4ef2a80728f7 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -271,7 +271,7 @@ static int usbat_bulk_read(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("usbat_bulk_read: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL);
}
@@ -286,7 +286,7 @@ static int usbat_bulk_write(struct us_data *us,
if (len == 0)
return USB_STOR_XFER_GOOD;
- US_DEBUGP("usbat_bulk_write: len = %d\n", len);
+ usb_stor_dbg(us, "len = %d\n", len);
return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL);
}
@@ -312,7 +312,7 @@ static int usbat_get_status(struct us_data *us, unsigned char *status)
int rc;
rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
- US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status));
+ usb_stor_dbg(us, "0x%02X\n", *status);
return rc;
}
@@ -425,7 +425,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
return USB_STOR_TRANSPORT_FAILED;
if ((*status & 0x80)==0x00) { /* not busy */
- US_DEBUGP("Waited not busy for %d steps\n", i);
+ usb_stor_dbg(us, "Waited not busy for %d steps\n", i);
return USB_STOR_TRANSPORT_GOOD;
}
@@ -439,8 +439,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes)
msleep(1000); /* X minutes */
}
- US_DEBUGP("Waited not busy for %d minutes, timing out.\n",
- minutes);
+ usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n",
+ minutes);
return USB_STOR_TRANSPORT_FAILED;
}
@@ -657,8 +657,9 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
if (*status & 0x20) /* device fault */
return USB_STOR_TRANSPORT_FAILED;
- US_DEBUGP("Redoing %s\n",
- direction==DMA_TO_DEVICE ? "write" : "read");
+ usb_stor_dbg(us, "Redoing %s\n",
+ direction == DMA_TO_DEVICE
+ ? "write" : "read");
} else if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -667,8 +668,8 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us,
}
- US_DEBUGP("Bummer! %s bulk data 20 times failed.\n",
- direction==DMA_TO_DEVICE ? "Writing" : "Reading");
+ usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n",
+ direction == DMA_TO_DEVICE ? "Writing" : "Reading");
return USB_STOR_TRANSPORT_FAILED;
}
@@ -827,7 +828,7 @@ static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
data_flags,
USBAT_UIO_READ);
- US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags));
+ usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags);
return result;
}
@@ -900,10 +901,11 @@ static int usbat_device_enable_cdt(struct us_data *us)
/*
* Determine if media is present.
*/
-static int usbat_flash_check_media_present(unsigned char *uio)
+static int usbat_flash_check_media_present(struct us_data *us,
+ unsigned char *uio)
{
if (*uio & USBAT_UIO_UI0) {
- US_DEBUGP("usbat_flash_check_media_present: no media detected\n");
+ usb_stor_dbg(us, "no media detected\n");
return USBAT_FLASH_MEDIA_NONE;
}
@@ -913,10 +915,11 @@ static int usbat_flash_check_media_present(unsigned char *uio)
/*
* Determine if media has changed since last operation
*/
-static int usbat_flash_check_media_changed(unsigned char *uio)
+static int usbat_flash_check_media_changed(struct us_data *us,
+ unsigned char *uio)
{
if (*uio & USBAT_UIO_0) {
- US_DEBUGP("usbat_flash_check_media_changed: media change detected\n");
+ usb_stor_dbg(us, "media change detected\n");
return USBAT_FLASH_MEDIA_CHANGED;
}
@@ -937,7 +940,7 @@ static int usbat_flash_check_media(struct us_data *us,
return USB_STOR_TRANSPORT_ERROR;
/* Check for media existence */
- rc = usbat_flash_check_media_present(uio);
+ rc = usbat_flash_check_media_present(us, uio);
if (rc == USBAT_FLASH_MEDIA_NONE) {
info->sense_key = 0x02;
info->sense_asc = 0x3A;
@@ -946,7 +949,7 @@ static int usbat_flash_check_media(struct us_data *us,
}
/* Check for media change */
- rc = usbat_flash_check_media_changed(uio);
+ rc = usbat_flash_check_media_changed(us, uio);
if (rc == USBAT_FLASH_MEDIA_CHANGED) {
/* Reset and re-enable card detect */
@@ -1008,11 +1011,11 @@ static int usbat_identify_device(struct us_data *us,
/* Check for error bit, or if the command 'fell through' */
if (status == 0xA1 || !(status & 0x01)) {
/* Device is HP 8200 */
- US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
+ usb_stor_dbg(us, "Detected HP8200 CDRW\n");
info->devicetype = USBAT_DEV_HP8200;
} else {
/* Device is a CompactFlash reader/writer */
- US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+ usb_stor_dbg(us, "Detected Flash reader/writer\n");
info->devicetype = USBAT_DEV_FLASH;
}
@@ -1075,7 +1078,7 @@ static int usbat_flash_get_sector_count(struct us_data *us,
/* ATA command : IDENTIFY DEVICE */
rc = usbat_multiple_write(us, registers, command, 3);
if (rc != USB_STOR_XFER_GOOD) {
- US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
+ usb_stor_dbg(us, "Gah! identify_device failed\n");
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
@@ -1178,7 +1181,7 @@ static int usbat_flash_read_data(struct us_data *us,
if (result != USB_STOR_TRANSPORT_GOOD)
goto leave;
- US_DEBUGP("usbat_flash_read_data: %d bytes\n", len);
+ usb_stor_dbg(us, "%d bytes\n", len);
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
@@ -1301,8 +1304,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
unsigned int sg_offset = 0;
struct scatterlist *sg = NULL;
- US_DEBUGP("handle_read10: transfersize %d\n",
- srb->transfersize);
+ usb_stor_dbg(us, "transfersize %d\n", srb->transfersize);
if (scsi_bufflen(srb) < 0x10000) {
@@ -1329,14 +1331,14 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
len = short_pack(data[7+9], data[7+8]);
len <<= 16;
len |= data[7+7];
- US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
+ usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len);
srb->transfersize = scsi_bufflen(srb)/len;
}
if (!srb->transfersize) {
srb->transfersize = 2048; /* A guess */
- US_DEBUGP("handle_read10: transfersize 0, forcing %d\n",
- srb->transfersize);
+ usb_stor_dbg(us, "transfersize 0, forcing %d\n",
+ srb->transfersize);
}
/*
@@ -1346,7 +1348,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
*/
len = (65535/srb->transfersize) * srb->transfersize;
- US_DEBUGP("Max read is %d bytes\n", len);
+ usb_stor_dbg(us, "Max read is %d bytes\n", len);
len = min(len, scsi_bufflen(srb));
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL) /* bloody hell! */
@@ -1460,10 +1462,9 @@ static int init_usbat(struct us_data *us, int devicetype)
unsigned char *status = us->iobuf;
us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO);
- if (!us->extra) {
- US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+ if (!us->extra)
return 1;
- }
+
info = (struct usbat_info *) (us->extra);
/* Enable peripheral control signals */
@@ -1473,7 +1474,7 @@ static int init_usbat(struct us_data *us, int devicetype)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 1\n");
+ usb_stor_dbg(us, "INIT 1\n");
msleep(2000);
@@ -1481,7 +1482,7 @@ static int init_usbat(struct us_data *us, int devicetype)
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 2\n");
+ usb_stor_dbg(us, "INIT 2\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
@@ -1491,32 +1492,32 @@ static int init_usbat(struct us_data *us, int devicetype)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 3\n");
+ usb_stor_dbg(us, "INIT 3\n");
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 4\n");
+ usb_stor_dbg(us, "INIT 4\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 5\n");
+ usb_stor_dbg(us, "INIT 5\n");
/* Enable peripheral control signals and card detect */
rc = usbat_device_enable_cdt(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 6\n");
+ usb_stor_dbg(us, "INIT 6\n");
rc = usbat_read_user_io(us, status);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 7\n");
+ usb_stor_dbg(us, "INIT 7\n");
msleep(1400);
@@ -1524,19 +1525,19 @@ static int init_usbat(struct us_data *us, int devicetype)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 8\n");
+ usb_stor_dbg(us, "INIT 8\n");
rc = usbat_select_and_test_registers(us);
if (rc != USB_STOR_TRANSPORT_GOOD)
return rc;
- US_DEBUGP("INIT 9\n");
+ usb_stor_dbg(us, "INIT 9\n");
/* At this point, we need to detect which device we are using */
if (usbat_set_transport(us, info, devicetype))
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 10\n");
+ usb_stor_dbg(us, "INIT 10\n");
if (usbat_get_device_type(us) == USBAT_DEV_FLASH) {
subcountH = 0x02;
@@ -1547,7 +1548,7 @@ static int init_usbat(struct us_data *us, int devicetype)
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 11\n");
+ usb_stor_dbg(us, "INIT 11\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -1592,7 +1593,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
}
result = usbat_get_status(us, status);
- US_DEBUGP("Status = %02X\n", *status);
+ usb_stor_dbg(us, "Status = %02X\n", *status);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (srb->cmnd[0] == TEST_UNIT_READY)
@@ -1610,7 +1611,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
if (result == USB_STOR_TRANSPORT_GOOD) {
transferred += len;
- US_DEBUGP("Wrote %08X bytes\n", transferred);
+ usb_stor_dbg(us, "Wrote %08X bytes\n", transferred);
}
return result;
@@ -1623,8 +1624,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
}
if (len > 0xFFFF) {
- US_DEBUGP("Error: len = %08X... what do I do now?\n",
- len);
+ usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n",
+ len);
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1693,7 +1694,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
};
if (srb->cmnd[0] == INQUIRY) {
- US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n");
+ usb_stor_dbg(us, "INQUIRY - Returning bogus response\n");
memcpy(ptr, inquiry_response, sizeof(inquiry_response));
fill_inquiry_response(us, ptr, 36);
return USB_STOR_TRANSPORT_GOOD;
@@ -1710,8 +1711,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
/* hard coded 512 byte sectors as per ATA spec */
info->ssize = 0x200;
- US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
- info->sectors, info->ssize);
+ usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+ info->sectors, info->ssize);
/*
* build the reply
@@ -1726,7 +1727,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == MODE_SELECT_10) {
- US_DEBUGP("usbat_flash_transport: Gah! MODE_SELECT_10.\n");
+ usb_stor_dbg(us, "Gah! MODE_SELECT_10\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1736,7 +1737,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("usbat_flash_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_read_data(us, info, block, blocks);
}
@@ -1750,7 +1752,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_read_data(us, info, block, blocks);
}
@@ -1760,7 +1763,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
- US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_write_data(us, info, block, blocks);
}
@@ -1774,13 +1778,14 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9]));
- US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks);
+ usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n",
+ block, blocks);
return usbat_flash_write_data(us, info, block, blocks);
}
if (srb->cmnd[0] == TEST_UNIT_READY) {
- US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n");
+ usb_stor_dbg(us, "TEST_UNIT_READY\n");
rc = usbat_flash_check_media(us, info);
if (rc != USB_STOR_TRANSPORT_GOOD)
@@ -1790,7 +1795,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
}
if (srb->cmnd[0] == REQUEST_SENSE) {
- US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n");
+ usb_stor_dbg(us, "REQUEST_SENSE\n");
memset(ptr, 0, 18);
ptr[0] = 0xF0;
@@ -1811,8 +1816,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
}
- US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n",
- srb->cmnd[0], srb->cmnd[0]);
+ usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n",
+ srb->cmnd[0], srb->cmnd[0]);
info->sense_key = 0x05;
info->sense_asc = 0x20;
info->sense_ascq = 0x00;
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
index 17e36952bced..2ea657be14c8 100644
--- a/drivers/usb/storage/sierra_ms.c
+++ b/drivers/usb/storage/sierra_ms.c
@@ -47,7 +47,7 @@ static bool containsFullLinuxPackage(struct swoc_info *swocInfo)
static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
{
int result;
- US_DEBUGP("SWIMS: %s", "DEVICE MODE SWITCH\n");
+ dev_dbg(&udev->dev, "SWIMS: %s", "DEVICE MODE SWITCH\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */
USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */
@@ -65,7 +65,7 @@ static int sierra_get_swoc_info(struct usb_device *udev,
{
int result;
- US_DEBUGP("SWIMS: Attempting to get TRU-Install info.\n");
+ dev_dbg(&udev->dev, "SWIMS: Attempting to get TRU-Install info\n");
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */
@@ -81,11 +81,11 @@ static int sierra_get_swoc_info(struct usb_device *udev,
return result;
}
-static void debug_swoc(struct swoc_info *swocInfo)
+static void debug_swoc(const struct device *dev, struct swoc_info *swocInfo)
{
- US_DEBUGP("SWIMS: SWoC Rev: %02d \n", swocInfo->rev);
- US_DEBUGP("SWIMS: Linux SKU: %04X \n", swocInfo->LinuxSKU);
- US_DEBUGP("SWIMS: Linux Version: %04X \n", swocInfo->LinuxVer);
+ dev_dbg(dev, "SWIMS: SWoC Rev: %02d\n", swocInfo->rev);
+ dev_dbg(dev, "SWIMS: Linux SKU: %04X\n", swocInfo->LinuxSKU);
+ dev_dbg(dev, "SWIMS: Linux Version: %04X\n", swocInfo->LinuxVer);
}
@@ -101,18 +101,17 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr,
} else {
swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
if (!swocInfo) {
- US_DEBUGP("SWIMS: Allocation failure\n");
snprintf(buf, PAGE_SIZE, "Error\n");
return -ENOMEM;
}
result = sierra_get_swoc_info(udev, swocInfo);
if (result < 0) {
- US_DEBUGP("SWIMS: failed SWoC query\n");
+ dev_dbg(dev, "SWIMS: failed SWoC query\n");
kfree(swocInfo);
snprintf(buf, PAGE_SIZE, "Error\n");
return -EIO;
}
- debug_swoc(swocInfo);
+ debug_swoc(dev, swocInfo);
result = snprintf(buf, PAGE_SIZE,
"REV=%02d SKU=%04X VER=%04X\n",
swocInfo->rev,
@@ -138,61 +137,55 @@ int sierra_ms_init(struct us_data *us)
sh = us_to_host(us);
scsi_get_host_dev(sh);
- US_DEBUGP("SWIMS: sierra_ms_init called\n");
-
/* Force Modem mode */
if (swi_tru_install == TRU_FORCE_MODEM) {
- US_DEBUGP("SWIMS: %s", "Forcing Modem Mode\n");
+ usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n");
result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
if (result < 0)
- US_DEBUGP("SWIMS: Failed to switch to modem mode.\n");
+ usb_stor_dbg(us, "SWIMS: Failed to switch to modem mode\n");
return -EIO;
}
/* Force Mass Storage mode (keep CD-Rom) */
else if (swi_tru_install == TRU_FORCE_MS) {
- US_DEBUGP("SWIMS: %s", "Forcing Mass Storage Mode\n");
+ usb_stor_dbg(us, "SWIMS: Forcing Mass Storage Mode\n");
goto complete;
}
/* Normal TRU-Install Logic */
else {
- US_DEBUGP("SWIMS: %s", "Normal SWoC Logic\n");
+ usb_stor_dbg(us, "SWIMS: Normal SWoC Logic\n");
swocInfo = kmalloc(sizeof(struct swoc_info),
GFP_KERNEL);
- if (!swocInfo) {
- US_DEBUGP("SWIMS: %s", "Allocation failure\n");
+ if (!swocInfo)
return -ENOMEM;
- }
retries = 3;
do {
retries--;
result = sierra_get_swoc_info(udev, swocInfo);
if (result < 0) {
- US_DEBUGP("SWIMS: %s", "Failed SWoC query\n");
+ usb_stor_dbg(us, "SWIMS: Failed SWoC query\n");
schedule_timeout_uninterruptible(2*HZ);
}
} while (retries && result < 0);
if (result < 0) {
- US_DEBUGP("SWIMS: %s",
- "Completely failed SWoC query\n");
+ usb_stor_dbg(us, "SWIMS: Completely failed SWoC query\n");
kfree(swocInfo);
return -EIO;
}
- debug_swoc(swocInfo);
+ debug_swoc(&us->pusb_dev->dev, swocInfo);
/* If there is not Linux software on the TRU-Install device
* then switch to modem mode
*/
if (!containsFullLinuxPackage(swocInfo)) {
- US_DEBUGP("SWIMS: %s",
- "Switching to Modem Mode\n");
+ usb_stor_dbg(us, "SWIMS: Switching to Modem Mode\n");
result = sierra_set_ms_mode(udev,
SWIMS_SET_MODE_Modem);
if (result < 0)
- US_DEBUGP("SWIMS: Failed to switch modem\n");
+ usb_stor_dbg(us, "SWIMS: Failed to switch modem\n");
kfree(swocInfo);
return -EIO;
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c0543c83923e..22c7d4360fa2 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -166,7 +166,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
/* cancel the URB, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
- US_DEBUGP("-- cancelling URB\n");
+ usb_stor_dbg(us, "-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
}
@@ -178,8 +178,8 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
if (timeleft <= 0) {
- US_DEBUGP("%s -- cancelling URB\n",
- timeleft == 0 ? "Timeout" : "Signal");
+ usb_stor_dbg(us, "%s -- cancelling URB\n",
+ timeleft == 0 ? "Timeout" : "Signal");
usb_kill_urb(us->current_urb);
}
@@ -197,9 +197,8 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
{
int status;
- US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __func__, request, requesttype,
- value, index, size);
+ usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+ request, requesttype, value, index, size);
/* fill in the devrequest structure */
us->cr->bRequestType = requesttype;
@@ -249,7 +248,7 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
if (result >= 0)
usb_reset_endpoint(us->pusb_dev, endp);
- US_DEBUGP("%s: result = %d\n", __func__, result);
+ usb_stor_dbg(us, "result = %d\n", result);
return result;
}
EXPORT_SYMBOL_GPL(usb_stor_clear_halt);
@@ -265,18 +264,18 @@ EXPORT_SYMBOL_GPL(usb_stor_clear_halt);
static int interpret_urb_result(struct us_data *us, unsigned int pipe,
unsigned int length, int result, unsigned int partial)
{
- US_DEBUGP("Status code %d; transferred %u/%u\n",
- result, partial, length);
+ usb_stor_dbg(us, "Status code %d; transferred %u/%u\n",
+ result, partial, length);
switch (result) {
/* no error code; did we send all the data? */
case 0:
if (partial != length) {
- US_DEBUGP("-- short transfer\n");
+ usb_stor_dbg(us, "-- short transfer\n");
return USB_STOR_XFER_SHORT;
}
- US_DEBUGP("-- transfer complete\n");
+ usb_stor_dbg(us, "-- transfer complete\n");
return USB_STOR_XFER_GOOD;
/* stalled */
@@ -284,39 +283,40 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
/* for control endpoints, (used by CB[I]) a stall indicates
* a failed command */
if (usb_pipecontrol(pipe)) {
- US_DEBUGP("-- stall on control pipe\n");
+ usb_stor_dbg(us, "-- stall on control pipe\n");
return USB_STOR_XFER_STALLED;
}
/* for other sorts of endpoint, clear the stall */
- US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+ usb_stor_dbg(us, "clearing endpoint halt for pipe 0x%x\n",
+ pipe);
if (usb_stor_clear_halt(us, pipe) < 0)
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
- US_DEBUGP("-- babble\n");
+ usb_stor_dbg(us, "-- babble\n");
return USB_STOR_XFER_LONG;
/* the transfer was cancelled by abort, disconnect, or timeout */
case -ECONNRESET:
- US_DEBUGP("-- transfer cancelled\n");
+ usb_stor_dbg(us, "-- transfer cancelled\n");
return USB_STOR_XFER_ERROR;
/* short scatter-gather read transfer */
case -EREMOTEIO:
- US_DEBUGP("-- short read transfer\n");
+ usb_stor_dbg(us, "-- short read transfer\n");
return USB_STOR_XFER_SHORT;
/* abort or disconnect in progress */
case -EIO:
- US_DEBUGP("-- abort or disconnect in progress\n");
+ usb_stor_dbg(us, "-- abort or disconnect in progress\n");
return USB_STOR_XFER_ERROR;
/* the catch-all error case */
default:
- US_DEBUGP("-- unknown error\n");
+ usb_stor_dbg(us, "-- unknown error\n");
return USB_STOR_XFER_ERROR;
}
}
@@ -331,9 +331,8 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
{
int result;
- US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
- __func__, request, requesttype,
- value, index, size);
+ usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+ request, requesttype, value, index, size);
/* fill in the devrequest structure */
us->cr->bRequestType = requesttype;
@@ -367,7 +366,7 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf,
unsigned int pipe = us->recv_intr_pipe;
unsigned int maxp;
- US_DEBUGP("%s: xfer %u bytes\n", __func__, length);
+ usb_stor_dbg(us, "xfer %u bytes\n", length);
/* calculate the max packet size */
maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
@@ -394,7 +393,7 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
{
int result;
- US_DEBUGP("%s: xfer %u bytes\n", __func__, length);
+ usb_stor_dbg(us, "xfer %u bytes\n", length);
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
@@ -426,12 +425,11 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */
- US_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
- length, num_sg);
+ usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg);
result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, GFP_NOIO);
if (result) {
- US_DEBUGP("usb_sg_init returned %d\n", result);
+ usb_stor_dbg(us, "usb_sg_init returned %d\n", result);
return USB_STOR_XFER_ERROR;
}
@@ -444,7 +442,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
- US_DEBUGP("-- cancelling sg request\n");
+ usb_stor_dbg(us, "-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
}
@@ -609,14 +607,14 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* short-circuit all other processing
*/
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
- US_DEBUGP("-- command was aborted\n");
+ usb_stor_dbg(us, "-- command was aborted\n");
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
- US_DEBUGP("-- transport indicates error, resetting\n");
+ usb_stor_dbg(us, "-- transport indicates error, resetting\n");
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
@@ -645,7 +643,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
srb->sc_data_direction != DMA_FROM_DEVICE) {
- US_DEBUGP("-- CB transport device requiring auto-sense\n");
+ usb_stor_dbg(us, "-- CB transport device requiring auto-sense\n");
need_auto_sense = 1;
}
@@ -655,7 +653,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* "failure" and an "error" in the transport mechanism.
*/
if (result == USB_STOR_TRANSPORT_FAILED) {
- US_DEBUGP("-- transport indicates command failure\n");
+ usb_stor_dbg(us, "-- transport indicates command failure\n");
need_auto_sense = 1;
}
@@ -670,7 +668,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
!(us->fflags & US_FL_SANE_SENSE) &&
!(us->fflags & US_FL_BAD_SENSE) &&
!(srb->cmnd[2] & 0x20))) {
- US_DEBUGP("-- SAT supported, increasing auto-sense\n");
+ usb_stor_dbg(us, "-- SAT supported, increasing auto-sense\n");
us->fflags |= US_FL_SANE_SENSE;
}
@@ -684,7 +682,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
(srb->cmnd[0] == MODE_SENSE) ||
(srb->cmnd[0] == LOG_SENSE) ||
(srb->cmnd[0] == MODE_SENSE_10))) {
- US_DEBUGP("-- unexpectedly short transfer\n");
+ usb_stor_dbg(us, "-- unexpectedly short transfer\n");
}
/* Now, if we need to do the auto-sense, let's do it */
@@ -700,7 +698,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
if (us->fflags & US_FL_SANE_SENSE)
sense_size = ~0;
Retry_Sense:
- US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+ usb_stor_dbg(us, "Issuing auto-REQUEST_SENSE\n");
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
@@ -719,7 +717,7 @@ Retry_Sense:
scsi_eh_restore_cmnd(srb, &ses);
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
- US_DEBUGP("-- auto-sense aborted\n");
+ usb_stor_dbg(us, "-- auto-sense aborted\n");
srb->result = DID_ABORT << 16;
/* If SANE_SENSE caused this problem, disable it */
@@ -737,7 +735,7 @@ Retry_Sense:
*/
if (temp_result == USB_STOR_TRANSPORT_FAILED &&
sense_size != US_SENSE_SIZE) {
- US_DEBUGP("-- auto-sense failure, retry small sense\n");
+ usb_stor_dbg(us, "-- auto-sense failure, retry small sense\n");
sense_size = US_SENSE_SIZE;
us->fflags &= ~US_FL_SANE_SENSE;
us->fflags |= US_FL_BAD_SENSE;
@@ -746,7 +744,7 @@ Retry_Sense:
/* Other failures */
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("-- auto-sense failure\n");
+ usb_stor_dbg(us, "-- auto-sense failure\n");
/* we skip the reset if this happens to be a
* multi-target device, since failure of an
@@ -766,27 +764,28 @@ Retry_Sense:
!(us->fflags & US_FL_SANE_SENSE) &&
!(us->fflags & US_FL_BAD_SENSE) &&
(srb->sense_buffer[0] & 0x7C) == 0x70) {
- US_DEBUGP("-- SANE_SENSE support enabled\n");
+ usb_stor_dbg(us, "-- SANE_SENSE support enabled\n");
us->fflags |= US_FL_SANE_SENSE;
/* Indicate to the user that we truncated their sense
* because we didn't know it supported larger sense.
*/
- US_DEBUGP("-- Sense data truncated to %i from %i\n",
- US_SENSE_SIZE,
- srb->sense_buffer[7] + 8);
+ usb_stor_dbg(us, "-- Sense data truncated to %i from %i\n",
+ US_SENSE_SIZE,
+ srb->sense_buffer[7] + 8);
srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
}
scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
- US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
- sshdr.response_code, sshdr.sense_key,
- sshdr.asc, sshdr.ascq);
+ usb_stor_dbg(us, "-- Result from auto-sense is %d\n",
+ temp_result);
+ usb_stor_dbg(us, "-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+ sshdr.response_code, sshdr.sense_key,
+ sshdr.asc, sshdr.ascq);
#ifdef CONFIG_USB_STORAGE_DEBUG
- usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq);
+ usb_stor_show_sense(us, sshdr.sense_key, sshdr.asc, sshdr.ascq);
#endif
/* set the result so the higher layers expect this data */
@@ -892,20 +891,18 @@ Retry_Sense:
/* Stop the current URB transfer */
void usb_stor_stop_transport(struct us_data *us)
{
- US_DEBUGP("%s called\n", __func__);
-
/* If the state machine is blocked waiting for an URB,
* let's wake it up. The test_and_clear_bit() call
* guarantees that if a URB has just been submitted,
* it won't be cancelled more than once. */
if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
- US_DEBUGP("-- cancelling URB\n");
+ usb_stor_dbg(us, "-- cancelling URB\n");
usb_unlink_urb(us->current_urb);
}
/* If we are waiting for a scatter-gather operation, cancel it. */
if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
- US_DEBUGP("-- cancelling sg request\n");
+ usb_stor_dbg(us, "-- cancelling sg request\n");
usb_sg_cancel(&us->current_sg);
}
}
@@ -928,7 +925,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
us->ifnum, srb->cmnd, srb->cmd_len);
/* check the return code for the command */
- US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
+ usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n",
+ result);
/* if we stalled the command, it means command failed */
if (result == USB_STOR_XFER_STALLED) {
@@ -946,7 +944,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
pipe = srb->sc_data_direction == DMA_FROM_DEVICE ?
us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_srb(us, pipe, srb);
- US_DEBUGP("CBI data stage result is 0x%x\n", result);
+ usb_stor_dbg(us, "CBI data stage result is 0x%x\n", result);
/* if we stalled the data transfer it means command failed */
if (result == USB_STOR_XFER_STALLED)
@@ -964,8 +962,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
return USB_STOR_TRANSPORT_GOOD;
result = usb_stor_intr_transfer(us, us->iobuf, 2);
- US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
- us->iobuf[0], us->iobuf[1]);
+ usb_stor_dbg(us, "Got interrupt data (0x%x, 0x%x)\n",
+ us->iobuf[0], us->iobuf[1]);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -992,8 +990,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
* into the first byte -- so if it's non-zero, call it a failure.
*/
if (us->iobuf[0]) {
- US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n",
- us->iobuf[0]);
+ usb_stor_dbg(us, "CBI IRQ data showed reserved bType 0x%x\n",
+ us->iobuf[0]);
goto Failed;
}
@@ -1034,8 +1032,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
USB_RECIP_INTERFACE,
0, us->ifnum, us->iobuf, 1, 10*HZ);
- US_DEBUGP("GetMaxLUN command result is %d, data is %d\n",
- result, us->iobuf[0]);
+ usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n",
+ result, us->iobuf[0]);
/* if we have a successful request, return the result */
if (result > 0)
@@ -1084,14 +1082,14 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
memcpy(bcb->CDB, srb->cmnd, bcb->Length);
/* send it to out endpoint */
- US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
- le32_to_cpu(bcb->Signature), bcb->Tag,
- le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
- (bcb->Lun >> 4), (bcb->Lun & 0x0F),
- bcb->Length);
+ usb_stor_dbg(us, "Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+ le32_to_cpu(bcb->Signature), bcb->Tag,
+ le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+ (bcb->Lun >> 4), (bcb->Lun & 0x0F),
+ bcb->Length);
result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
bcb, cbwlen, NULL);
- US_DEBUGP("Bulk command transfer result=%d\n", result);
+ usb_stor_dbg(us, "Bulk command transfer result=%d\n", result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
@@ -1108,7 +1106,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ?
us->recv_bulk_pipe : us->send_bulk_pipe;
result = usb_stor_bulk_srb(us, pipe, srb);
- US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+ usb_stor_dbg(us, "Bulk data transfer result 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
@@ -1127,7 +1125,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
/* get CSW for device status */
- US_DEBUGP("Attempting to get CSW...\n");
+ usb_stor_dbg(us, "Attempting to get CSW...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
@@ -1136,7 +1134,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
* CSWs. If we encounter such a thing, try to read the CSW again.
*/
if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
- US_DEBUGP("Received 0-length CSW; retrying...\n");
+ usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, &cswlen);
}
@@ -1145,24 +1143,24 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
if (result == USB_STOR_XFER_STALLED) {
/* get the status again */
- US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+ usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
bcs, US_BULK_CS_WRAP_LEN, NULL);
}
/* if we still have a failure at this point, we're in trouble */
- US_DEBUGP("Bulk status result = %d\n", result);
+ usb_stor_dbg(us, "Bulk status result = %d\n", result);
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
/* check bulk status */
residue = le32_to_cpu(bcs->Residue);
- US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
- le32_to_cpu(bcs->Signature), bcs->Tag,
- residue, bcs->Status);
+ usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+ le32_to_cpu(bcs->Signature), bcs->Tag,
+ residue, bcs->Status);
if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) ||
bcs->Status > US_BULK_STAT_PHASE) {
- US_DEBUGP("Bulk logical error\n");
+ usb_stor_dbg(us, "Bulk logical error\n");
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1173,12 +1171,12 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
if (!us->bcs_signature) {
us->bcs_signature = bcs->Signature;
if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
- US_DEBUGP("Learnt BCS signature 0x%08X\n",
- le32_to_cpu(us->bcs_signature));
+ usb_stor_dbg(us, "Learnt BCS signature 0x%08X\n",
+ le32_to_cpu(us->bcs_signature));
} else if (bcs->Signature != us->bcs_signature) {
- US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
- le32_to_cpu(bcs->Signature),
- le32_to_cpu(us->bcs_signature));
+ usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature),
+ le32_to_cpu(us->bcs_signature));
return USB_STOR_TRANSPORT_ERROR;
}
@@ -1255,7 +1253,7 @@ static int usb_stor_reset_common(struct us_data *us,
int result2;
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
- US_DEBUGP("No reset during disconnect\n");
+ usb_stor_dbg(us, "No reset during disconnect\n");
return -EIO;
}
@@ -1263,7 +1261,7 @@ static int usb_stor_reset_common(struct us_data *us,
request, requesttype, value, index, data, size,
5*HZ);
if (result < 0) {
- US_DEBUGP("Soft reset failed: %d\n", result);
+ usb_stor_dbg(us, "Soft reset failed: %d\n", result);
return result;
}
@@ -1273,23 +1271,23 @@ static int usb_stor_reset_common(struct us_data *us,
test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
HZ*6);
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
- US_DEBUGP("Reset interrupted by disconnect\n");
+ usb_stor_dbg(us, "Reset interrupted by disconnect\n");
return -EIO;
}
- US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
+ usb_stor_dbg(us, "Soft reset: clearing bulk-in endpoint halt\n");
result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
- US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
+ usb_stor_dbg(us, "Soft reset: clearing bulk-out endpoint halt\n");
result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
/* return a result code based on the result of the clear-halts */
if (result >= 0)
result = result2;
if (result < 0)
- US_DEBUGP("Soft reset failed\n");
+ usb_stor_dbg(us, "Soft reset failed\n");
else
- US_DEBUGP("Soft reset done\n");
+ usb_stor_dbg(us, "Soft reset done\n");
return result;
}
@@ -1299,8 +1297,6 @@ static int usb_stor_reset_common(struct us_data *us,
int usb_stor_CB_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __func__);
-
memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
us->iobuf[0] = SEND_DIAGNOSTIC;
us->iobuf[1] = 4;
@@ -1315,8 +1311,6 @@ EXPORT_SYMBOL_GPL(usb_stor_CB_reset);
*/
int usb_stor_Bulk_reset(struct us_data *us)
{
- US_DEBUGP("%s called\n", __func__);
-
return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
@@ -1336,16 +1330,17 @@ int usb_stor_port_reset(struct us_data *us)
result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0)
- US_DEBUGP("unable to lock device for reset: %d\n", result);
+ usb_stor_dbg(us, "unable to lock device for reset: %d\n",
+ result);
else {
/* Were we disconnected while waiting for the lock? */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
result = -EIO;
- US_DEBUGP("No reset during disconnect\n");
+ usb_stor_dbg(us, "No reset during disconnect\n");
} else {
result = usb_reset_device(us->pusb_dev);
- US_DEBUGP("usb_reset_device returns %d\n",
- result);
+ usb_stor_dbg(us, "usb_reset_device returns %d\n",
+ result);
}
usb_unlock_device(us->pusb_dev);
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index d6bee407af02..5c4fe0749af1 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -183,7 +183,6 @@ int usb_stor_suspend(struct usb_interface *iface, pm_message_t message)
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __func__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
@@ -201,7 +200,6 @@ int usb_stor_resume(struct usb_interface *iface)
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __func__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
@@ -214,8 +212,6 @@ int usb_stor_reset_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __func__);
-
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
@@ -236,8 +232,6 @@ int usb_stor_pre_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __func__);
-
/* Make sure no command runs during the reset */
mutex_lock(&us->dev_mutex);
return 0;
@@ -248,8 +242,6 @@ int usb_stor_post_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- US_DEBUGP("%s\n", __func__);
-
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset(us);
@@ -311,11 +303,11 @@ static int usb_stor_control_thread(void * __us)
struct Scsi_Host *host = us_to_host(us);
for (;;) {
- US_DEBUGP("*** thread sleeping.\n");
+ usb_stor_dbg(us, "*** thread sleeping\n");
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
- US_DEBUGP("*** thread awakened.\n");
+ usb_stor_dbg(us, "*** thread awakened\n");
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
@@ -327,7 +319,7 @@ static int usb_stor_control_thread(void * __us)
if (us->srb == NULL) {
scsi_unlock(host);
mutex_unlock(&us->dev_mutex);
- US_DEBUGP("-- exiting\n");
+ usb_stor_dbg(us, "-- exiting\n");
break;
}
@@ -343,7 +335,7 @@ static int usb_stor_control_thread(void * __us)
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
- US_DEBUGP("UNKNOWN data direction\n");
+ usb_stor_dbg(us, "UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
}
@@ -352,14 +344,14 @@ static int usb_stor_control_thread(void * __us)
*/
else if (us->srb->device->id &&
!(us->fflags & US_FL_SCM_MULT_TARG)) {
- US_DEBUGP("Bad target number (%d:%d)\n",
- us->srb->device->id, us->srb->device->lun);
+ usb_stor_dbg(us, "Bad target number (%d:%d)\n",
+ us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
else if (us->srb->device->lun > us->max_lun) {
- US_DEBUGP("Bad LUN (%d:%d)\n",
- us->srb->device->id, us->srb->device->lun);
+ usb_stor_dbg(us, "Bad LUN (%d:%d)\n",
+ us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
@@ -371,14 +363,14 @@ static int usb_stor_control_thread(void * __us)
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
- US_DEBUGP("Faking INQUIRY command\n");
+ usb_stor_dbg(us, "Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = SAM_STAT_GOOD;
}
/* we've got a command, let's do it! */
else {
- US_DEBUG(usb_stor_show_command(us->srb));
+ US_DEBUG(usb_stor_show_command(us, us->srb));
us->proto_handler(us->srb, us);
usb_mark_last_busy(us->pusb_dev);
}
@@ -388,12 +380,12 @@ static int usb_stor_control_thread(void * __us)
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
- US_DEBUGP("scsi cmd done, result=0x%x\n",
- us->srb->result);
+ usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
+ us->srb->result);
us->srb->scsi_done(us->srb);
} else {
SkipForAbort:
- US_DEBUGP("scsi command aborted\n");
+ usb_stor_dbg(us, "scsi command aborted\n");
}
/* If an abort request was received we need to signal that
@@ -435,34 +427,30 @@ SkipForAbort:
/* Associate our private data with the USB device */
static int associate_dev(struct us_data *us, struct usb_interface *intf)
{
- US_DEBUGP("-- %s\n", __func__);
-
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
- US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
- le16_to_cpu(us->pusb_dev->descriptor.idVendor),
- le16_to_cpu(us->pusb_dev->descriptor.idProduct),
- le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
- US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
- intf->cur_altsetting->desc.bInterfaceSubClass,
- intf->cur_altsetting->desc.bInterfaceProtocol);
+ usb_stor_dbg(us, "Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
+ le16_to_cpu(us->pusb_dev->descriptor.idVendor),
+ le16_to_cpu(us->pusb_dev->descriptor.idProduct),
+ le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
+ usb_stor_dbg(us, "Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
+ intf->cur_altsetting->desc.bInterfaceSubClass,
+ intf->cur_altsetting->desc.bInterfaceProtocol);
/* Store our private data in the interface */
usb_set_intfdata(intf, us);
/* Allocate the control/setup and DMA-mapped buffers */
us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL);
- if (!us->cr) {
- US_DEBUGP("usb_ctrlrequest allocation failed\n");
+ if (!us->cr)
return -ENOMEM;
- }
us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE,
GFP_KERNEL, &us->iobuf_dma);
if (!us->iobuf) {
- US_DEBUGP("I/O buffer allocation failed\n");
+ usb_stor_dbg(us, "I/O buffer allocation failed\n");
return -ENOMEM;
}
return 0;
@@ -738,7 +726,7 @@ static int get_pipes(struct us_data *us)
}
if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) {
- US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
+ usb_stor_dbg(us, "Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
@@ -765,7 +753,7 @@ static int usb_stor_acquire_resources(struct us_data *us)
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
- US_DEBUGP("URB allocation failed\n");
+ usb_stor_dbg(us, "URB allocation failed\n");
return -ENOMEM;
}
@@ -792,20 +780,18 @@ static int usb_stor_acquire_resources(struct us_data *us)
/* Release all our dynamic resources */
static void usb_stor_release_resources(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __func__);
-
/* Tell the control thread to exit. The SCSI host must
* already have been removed and the DISCONNECTING flag set
* so that we won't accept any more commands.
*/
- US_DEBUGP("-- sending exit command to thread\n");
+ usb_stor_dbg(us, "-- sending exit command to thread\n");
complete(&us->cmnd_ready);
if (us->ctl_thread)
kthread_stop(us->ctl_thread);
/* Call the destructor routine, if it exists */
if (us->extra_destructor) {
- US_DEBUGP("-- calling extra_destructor()\n");
+ usb_stor_dbg(us, "-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
@@ -817,8 +803,6 @@ static void usb_stor_release_resources(struct us_data *us)
/* Dissociate from the USB device */
static void dissociate_dev(struct us_data *us)
{
- US_DEBUGP("-- %s\n", __func__);
-
/* Free the buffers */
kfree(us->cr);
usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma);
@@ -918,7 +902,7 @@ int usb_stor_probe1(struct us_data **pus,
struct us_data *us;
int result;
- US_DEBUGP("USB Mass Storage device detected\n");
+ dev_info(&intf->dev, "USB Mass Storage device detected\n");
/*
* Ask the SCSI layer to allocate a host structure, with extra
@@ -926,8 +910,7 @@ int usb_stor_probe1(struct us_data **pus,
*/
host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
if (!host) {
- dev_warn(&intf->dev,
- "Unable to allocate the scsi host\n");
+ dev_warn(&intf->dev, "Unable to allocate the scsi host\n");
return -ENOMEM;
}
@@ -964,7 +947,7 @@ int usb_stor_probe1(struct us_data **pus,
return 0;
BadDevice:
- US_DEBUGP("storage_probe() failed\n");
+ usb_stor_dbg(us, "storage_probe() failed\n");
release_everything(us);
return result;
}
@@ -981,8 +964,8 @@ int usb_stor_probe2(struct us_data *us)
result = -ENXIO;
goto BadDevice;
}
- US_DEBUGP("Transport: %s\n", us->transport_name);
- US_DEBUGP("Protocol: %s\n", us->protocol_name);
+ usb_stor_dbg(us, "Transport: %s\n", us->transport_name);
+ usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name);
/* fix for single-lun devices */
if (us->fflags & US_FL_SINGLE_LUN)
@@ -1028,7 +1011,7 @@ int usb_stor_probe2(struct us_data *us)
/* We come here if there are any problems */
BadDevice:
- US_DEBUGP("storage_probe() failed\n");
+ usb_stor_dbg(us, "storage_probe() failed\n");
release_everything(us);
return result;
}
@@ -1039,7 +1022,6 @@ void usb_stor_disconnect(struct usb_interface *intf)
{
struct us_data *us = usb_get_intfdata(intf);
- US_DEBUGP("storage_disconnect() called\n");
quiesce_and_remove_host(us);
release_everything(us);
}
@@ -1075,8 +1057,7 @@ static int storage_probe(struct usb_interface *intf,
} else {
unusual_dev = &for_dynamic_ids;
- US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
- "with the Transparent SCSI protocol for dynamic id:",
+ dev_dbg(&intf->dev, "Use Bulk-Only transport with the Transparent SCSI protocol for dynamic id: 0x%04x 0x%04x\n",
id->idVendor, id->idProduct);
}
@@ -1090,10 +1071,6 @@ static int storage_probe(struct usb_interface *intf,
return result;
}
-/***********************************************************************
- * Initialization and registration
- ***********************************************************************/
-
static struct usb_driver usb_storage_driver = {
.name = "usb-storage",
.probe = storage_probe,
@@ -1108,30 +1085,4 @@ static struct usb_driver usb_storage_driver = {
.soft_unbind = 1,
};
-static int __init usb_stor_init(void)
-{
- int retval;
-
- pr_info("Initializing USB Mass Storage driver...\n");
-
- /* register the driver, return usb_register return code if error */
- retval = usb_register(&usb_storage_driver);
- if (retval == 0)
- pr_info("USB Mass Storage support registered.\n");
- return retval;
-}
-
-static void __exit usb_stor_exit(void)
-{
- US_DEBUGP("usb_stor_exit() called\n");
-
- /* Deregister the driver
- * This will cause disconnect() to be called for each
- * attached unit
- */
- US_DEBUGP("-- calling usb_deregister()\n");
- usb_deregister(&usb_storage_driver) ;
-}
-
-module_init(usb_stor_init);
-module_exit(usb_stor_exit);
+module_usb_driver(usb_storage_driver);
diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c
index d29503e954ab..0db0a919d72b 100644
--- a/drivers/usb/usb-common.c
+++ b/drivers/usb/usb-common.c
@@ -14,6 +14,32 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+
+const char *usb_otg_state_string(enum usb_otg_state state)
+{
+ static const char *const names[] = {
+ [OTG_STATE_A_IDLE] = "a_idle",
+ [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise",
+ [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon",
+ [OTG_STATE_A_HOST] = "a_host",
+ [OTG_STATE_A_SUSPEND] = "a_suspend",
+ [OTG_STATE_A_PERIPHERAL] = "a_peripheral",
+ [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall",
+ [OTG_STATE_A_VBUS_ERR] = "a_vbus_err",
+ [OTG_STATE_B_IDLE] = "b_idle",
+ [OTG_STATE_B_SRP_INIT] = "b_srp_init",
+ [OTG_STATE_B_PERIPHERAL] = "b_peripheral",
+ [OTG_STATE_B_WAIT_ACON] = "b_wait_acon",
+ [OTG_STATE_B_HOST] = "b_host",
+ };
+
+ if (state < 0 || state >= ARRAY_SIZE(names))
+ return "UNDEFINED";
+
+ return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_otg_state_string);
const char *usb_speed_string(enum usb_device_speed speed)
{
@@ -32,4 +58,25 @@ const char *usb_speed_string(enum usb_device_speed speed)
}
EXPORT_SYMBOL_GPL(usb_speed_string);
+const char *usb_state_string(enum usb_device_state state)
+{
+ static const char *const names[] = {
+ [USB_STATE_NOTATTACHED] = "not attached",
+ [USB_STATE_ATTACHED] = "attached",
+ [USB_STATE_POWERED] = "powered",
+ [USB_STATE_RECONNECTING] = "reconnecting",
+ [USB_STATE_UNAUTHENTICATED] = "unauthenticated",
+ [USB_STATE_DEFAULT] = "default",
+ [USB_STATE_ADDRESS] = "addresssed",
+ [USB_STATE_CONFIGURED] = "configured",
+ [USB_STATE_SUSPENDED] = "suspended",
+ };
+
+ if (state < 0 || state >= ARRAY_SIZE(names))
+ return "UNKNOWN";
+
+ return names[state];
+}
+EXPORT_SYMBOL_GPL(usb_state_string);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index ce310170829f..7ed3b039dbe8 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -61,11 +61,10 @@ struct usb_skel {
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
int errors; /* the last request tanked */
bool ongoing_read; /* a read is going on */
- bool processed_urb; /* indicates we haven't processed the urb */
spinlock_t err_lock; /* lock for errors */
struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */
- struct completion bulk_in_completion; /* to wait for an ongoing read */
+ wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
@@ -185,7 +184,7 @@ static void skel_read_bulk_callback(struct urb *urb)
dev->ongoing_read = 0;
spin_unlock(&dev->err_lock);
- complete(&dev->bulk_in_completion);
+ wake_up_interruptible(&dev->bulk_in_wait);
}
static int skel_do_read_io(struct usb_skel *dev, size_t count)
@@ -206,13 +205,16 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)
dev->ongoing_read = 1;
spin_unlock_irq(&dev->err_lock);
+ /* submit bulk in urb, which means no data to deliver */
+ dev->bulk_in_filled = 0;
+ dev->bulk_in_copied = 0;
+
/* do it */
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
if (rv < 0) {
dev_err(&dev->interface->dev,
"%s - failed submitting read urb, error %d\n",
__func__, rv);
- dev->bulk_in_filled = 0;
rv = (rv == -ENOMEM) ? rv : -EIO;
spin_lock_irq(&dev->err_lock);
dev->ongoing_read = 0;
@@ -261,25 +263,9 @@ retry:
* IO may take forever
* hence wait in an interruptible state
*/
- rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
+ rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read));
if (rv < 0)
goto exit;
- /*
- * by waiting we also semiprocessed the urb
- * we must finish now
- */
- dev->bulk_in_copied = 0;
- dev->processed_urb = 1;
- }
-
- if (!dev->processed_urb) {
- /*
- * the URB hasn't been processed
- * do it now
- */
- wait_for_completion(&dev->bulk_in_completion);
- dev->bulk_in_copied = 0;
- dev->processed_urb = 1;
}
/* errors must be reported */
@@ -289,8 +275,6 @@ retry:
dev->errors = 0;
/* to preserve notifications about reset */
rv = (rv == -EPIPE) ? rv : -EIO;
- /* no data to deliver */
- dev->bulk_in_filled = 0;
/* report it */
goto exit;
}
@@ -526,7 +510,7 @@ static int skel_probe(struct usb_interface *interface,
mutex_init(&dev->io_mutex);
spin_lock_init(&dev->err_lock);
init_usb_anchor(&dev->submitted);
- init_completion(&dev->bulk_in_completion);
+ init_waitqueue_head(&dev->bulk_in_wait);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
index 8bf19760d447..0e17b966e1b4 100644
--- a/drivers/usb/wusbcore/Kconfig
+++ b/drivers/usb/wusbcore/Kconfig
@@ -3,7 +3,6 @@
#
config USB_WUSB
tristate "Enable Wireless USB extensions"
- depends on USB
depends on PCI
depends on UWB
select CRYPTO
@@ -19,7 +18,6 @@ config USB_WUSB
config USB_WUSB_CBAF
tristate "Support WUSB Cable Based Association (CBA)"
- depends on USB
help
Some WUSB devices support Cable Based Association. It's used to
enable the secure communication between the host and the
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
index 0b0d8bce842e..f4ae05f78c42 100644
--- a/drivers/uwb/rsv.c
+++ b/drivers/uwb/rsv.c
@@ -231,7 +231,7 @@ void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
return;
bow->window <<= 1;
- bow->n = random32() & (bow->window - 1);
+ bow->n = prandom_u32() & (bow->window - 1);
dev_dbg(dev, "new_window=%d, n=%d\n: ", bow->window, bow->n);
/* reset the timer associated variables */
@@ -557,7 +557,7 @@ int uwb_rsv_establish(struct uwb_rsv *rsv)
if (ret)
goto out;
- rsv->tiebreaker = random32() & 1;
+ rsv->tiebreaker = prandom_u32() & 1;
/* get available mas bitmap */
uwb_drp_available(rc, &available);
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 8189cb6a86af..09d2e3ffd6fc 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -70,7 +70,7 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
pci_write_config_word(pdev, PCI_COMMAND, cmd);
}
- msix_pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+ msix_pos = pdev->msix_cap;
if (msix_pos) {
u16 flags;
u32 table;
@@ -78,8 +78,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
pci_read_config_word(pdev, msix_pos + PCI_MSIX_FLAGS, &flags);
pci_read_config_dword(pdev, msix_pos + PCI_MSIX_TABLE, &table);
- vdev->msix_bar = table & PCI_MSIX_FLAGS_BIRMASK;
- vdev->msix_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
+ vdev->msix_bar = table & PCI_MSIX_TABLE_BIR;
+ vdev->msix_offset = table & PCI_MSIX_TABLE_OFFSET;
vdev->msix_size = ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) * 16;
} else
vdev->msix_bar = 0xFF;
@@ -183,7 +183,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
u8 pos;
u16 flags;
- pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSI);
+ pos = vdev->pdev->msi_cap;
if (pos) {
pci_read_config_word(vdev->pdev,
pos + PCI_MSI_FLAGS, &flags);
@@ -194,7 +194,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
u8 pos;
u16 flags;
- pos = pci_find_capability(vdev->pdev, PCI_CAP_ID_MSIX);
+ pos = vdev->pdev->msix_cap;
if (pos) {
pci_read_config_word(vdev->pdev,
pos + PCI_MSIX_FLAGS, &flags);
@@ -346,6 +346,7 @@ static long vfio_pci_ioctl(void *device_data,
if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
size_t size;
+ int max = vfio_pci_get_irq_count(vdev, hdr.index);
if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
size = sizeof(uint8_t);
@@ -355,7 +356,7 @@ static long vfio_pci_ioctl(void *device_data,
return -EINVAL;
if (hdr.argsz - minsz < hdr.count * size ||
- hdr.count > vfio_pci_get_irq_count(vdev, hdr.index))
+ hdr.start >= max || hdr.start + hdr.count > max)
return -EINVAL;
data = memdup_user((void __user *)(arg + minsz),
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index ec6fb3fa59bb..87c216c1e54e 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -64,20 +64,10 @@ enum {
VHOST_NET_VQ_MAX = 2,
};
-enum vhost_net_poll_state {
- VHOST_NET_POLL_DISABLED = 0,
- VHOST_NET_POLL_STARTED = 1,
- VHOST_NET_POLL_STOPPED = 2,
-};
-
struct vhost_net {
struct vhost_dev dev;
struct vhost_virtqueue vqs[VHOST_NET_VQ_MAX];
struct vhost_poll poll[VHOST_NET_VQ_MAX];
- /* Tells us whether we are polling a socket for TX.
- * We only do this when socket buffer fills up.
- * Protected by tx vq lock. */
- enum vhost_net_poll_state tx_poll_state;
/* Number of TX recently submitted.
* Protected by tx vq lock. */
unsigned tx_packets;
@@ -155,28 +145,6 @@ static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
}
}
-/* Caller must have TX VQ lock */
-static void tx_poll_stop(struct vhost_net *net)
-{
- if (likely(net->tx_poll_state != VHOST_NET_POLL_STARTED))
- return;
- vhost_poll_stop(net->poll + VHOST_NET_VQ_TX);
- net->tx_poll_state = VHOST_NET_POLL_STOPPED;
-}
-
-/* Caller must have TX VQ lock */
-static int tx_poll_start(struct vhost_net *net, struct socket *sock)
-{
- int ret;
-
- if (unlikely(net->tx_poll_state != VHOST_NET_POLL_STOPPED))
- return 0;
- ret = vhost_poll_start(net->poll + VHOST_NET_VQ_TX, sock->file);
- if (!ret)
- net->tx_poll_state = VHOST_NET_POLL_STARTED;
- return ret;
-}
-
/* In case of DMA done not in order in lower device driver for some reason.
* upend_idx is used to track end of used idx, done_idx is used to track head
* of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -242,7 +210,7 @@ static void handle_tx(struct vhost_net *net)
.msg_flags = MSG_DONTWAIT,
};
size_t len, total_len = 0;
- int err, wmem;
+ int err;
size_t hdr_size;
struct socket *sock;
struct vhost_ubuf_ref *uninitialized_var(ubufs);
@@ -253,19 +221,9 @@ static void handle_tx(struct vhost_net *net)
if (!sock)
return;
- wmem = atomic_read(&sock->sk->sk_wmem_alloc);
- if (wmem >= sock->sk->sk_sndbuf) {
- mutex_lock(&vq->mutex);
- tx_poll_start(net, sock);
- mutex_unlock(&vq->mutex);
- return;
- }
-
mutex_lock(&vq->mutex);
vhost_disable_notify(&net->dev, vq);
- if (wmem < sock->sk->sk_sndbuf / 2)
- tx_poll_stop(net);
hdr_size = vq->vhost_hlen;
zcopy = vq->ubufs;
@@ -285,23 +243,14 @@ static void handle_tx(struct vhost_net *net)
if (head == vq->num) {
int num_pends;
- wmem = atomic_read(&sock->sk->sk_wmem_alloc);
- if (wmem >= sock->sk->sk_sndbuf * 3 / 4) {
- tx_poll_start(net, sock);
- set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
- break;
- }
/* If more outstanding DMAs, queue the work.
* Handle upend_idx wrap around
*/
num_pends = likely(vq->upend_idx >= vq->done_idx) ?
(vq->upend_idx - vq->done_idx) :
(vq->upend_idx + UIO_MAXIOV - vq->done_idx);
- if (unlikely(num_pends > VHOST_MAX_PEND)) {
- tx_poll_start(net, sock);
- set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+ if (unlikely(num_pends > VHOST_MAX_PEND))
break;
- }
if (unlikely(vhost_enable_notify(&net->dev, vq))) {
vhost_disable_notify(&net->dev, vq);
continue;
@@ -364,8 +313,6 @@ static void handle_tx(struct vhost_net *net)
UIO_MAXIOV;
}
vhost_discard_vq_desc(vq, 1);
- if (err == -EAGAIN || err == -ENOBUFS)
- tx_poll_start(net, sock);
break;
}
if (err != len)
@@ -628,7 +575,6 @@ static int vhost_net_open(struct inode *inode, struct file *f)
vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, POLLOUT, dev);
vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, POLLIN, dev);
- n->tx_poll_state = VHOST_NET_POLL_DISABLED;
f->private_data = n;
@@ -638,32 +584,24 @@ static int vhost_net_open(struct inode *inode, struct file *f)
static void vhost_net_disable_vq(struct vhost_net *n,
struct vhost_virtqueue *vq)
{
+ struct vhost_poll *poll = n->poll + (vq - n->vqs);
if (!vq->private_data)
return;
- if (vq == n->vqs + VHOST_NET_VQ_TX) {
- tx_poll_stop(n);
- n->tx_poll_state = VHOST_NET_POLL_DISABLED;
- } else
- vhost_poll_stop(n->poll + VHOST_NET_VQ_RX);
+ vhost_poll_stop(poll);
}
static int vhost_net_enable_vq(struct vhost_net *n,
struct vhost_virtqueue *vq)
{
+ struct vhost_poll *poll = n->poll + (vq - n->vqs);
struct socket *sock;
- int ret;
sock = rcu_dereference_protected(vq->private_data,
lockdep_is_held(&vq->mutex));
if (!sock)
return 0;
- if (vq == n->vqs + VHOST_NET_VQ_TX) {
- n->tx_poll_state = VHOST_NET_POLL_STOPPED;
- ret = tx_poll_start(n, sock);
- } else
- ret = vhost_poll_start(n->poll + VHOST_NET_VQ_RX, sock->file);
- return ret;
+ return vhost_poll_start(poll, sock->file);
}
static struct socket *vhost_net_stop_vq(struct vhost_net *n,
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
index 43fb11ee2e8d..1677238d281f 100644
--- a/drivers/vhost/tcm_vhost.c
+++ b/drivers/vhost/tcm_vhost.c
@@ -60,20 +60,36 @@ enum {
VHOST_SCSI_VQ_IO = 2,
};
+/*
+ * VIRTIO_RING_F_EVENT_IDX seems broken. Not sure the bug is in
+ * kernel but disabling it helps.
+ * TODO: debug and remove the workaround.
+ */
+enum {
+ VHOST_SCSI_FEATURES = (VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)) |
+ (1ULL << VIRTIO_SCSI_F_HOTPLUG)
+};
+
#define VHOST_SCSI_MAX_TARGET 256
#define VHOST_SCSI_MAX_VQ 128
+#define VHOST_SCSI_MAX_EVENT 128
struct vhost_scsi {
/* Protected by vhost_scsi->dev.mutex */
- struct tcm_vhost_tpg *vs_tpg[VHOST_SCSI_MAX_TARGET];
+ struct tcm_vhost_tpg **vs_tpg;
char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
- bool vs_endpoint;
struct vhost_dev dev;
struct vhost_virtqueue vqs[VHOST_SCSI_MAX_VQ];
struct vhost_work vs_completion_work; /* cmd completion work item */
struct llist_head vs_completion_list; /* cmd completion queue */
+
+ struct vhost_work vs_event_work; /* evt injection work item */
+ struct llist_head vs_event_list; /* evt injection queue */
+
+ bool vs_events_missed; /* any missed events, protected by vq->mutex */
+ int vs_events_nr; /* num of pending events, protected by vq->mutex */
};
/* Local pointer to allocated TCM configfs fabric module */
@@ -341,6 +357,37 @@ static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
return 0;
}
+static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
+{
+ vs->vs_events_nr--;
+ kfree(evt);
+}
+
+static struct tcm_vhost_evt *tcm_vhost_allocate_evt(struct vhost_scsi *vs,
+ u32 event, u32 reason)
+{
+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];
+ struct tcm_vhost_evt *evt;
+
+ if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {
+ vs->vs_events_missed = true;
+ return NULL;
+ }
+
+ evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+ if (!evt) {
+ vq_err(vq, "Failed to allocate tcm_vhost_evt\n");
+ vs->vs_events_missed = true;
+ return NULL;
+ }
+
+ evt->event.event = event;
+ evt->event.reason = reason;
+ vs->vs_events_nr++;
+
+ return evt;
+}
+
static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
{
struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
@@ -359,6 +406,75 @@ static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
kfree(tv_cmd);
}
+static void tcm_vhost_do_evt_work(struct vhost_scsi *vs,
+ struct tcm_vhost_evt *evt)
+{
+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];
+ struct virtio_scsi_event *event = &evt->event;
+ struct virtio_scsi_event __user *eventp;
+ unsigned out, in;
+ int head, ret;
+
+ if (!vq->private_data) {
+ vs->vs_events_missed = true;
+ return;
+ }
+
+again:
+ vhost_disable_notify(&vs->dev, vq);
+ head = vhost_get_vq_desc(&vs->dev, vq, vq->iov,
+ ARRAY_SIZE(vq->iov), &out, &in,
+ NULL, NULL);
+ if (head < 0) {
+ vs->vs_events_missed = true;
+ return;
+ }
+ if (head == vq->num) {
+ if (vhost_enable_notify(&vs->dev, vq))
+ goto again;
+ vs->vs_events_missed = true;
+ return;
+ }
+
+ if ((vq->iov[out].iov_len != sizeof(struct virtio_scsi_event))) {
+ vq_err(vq, "Expecting virtio_scsi_event, got %zu bytes\n",
+ vq->iov[out].iov_len);
+ vs->vs_events_missed = true;
+ return;
+ }
+
+ if (vs->vs_events_missed) {
+ event->event |= VIRTIO_SCSI_T_EVENTS_MISSED;
+ vs->vs_events_missed = false;
+ }
+
+ eventp = vq->iov[out].iov_base;
+ ret = __copy_to_user(eventp, event, sizeof(*event));
+ if (!ret)
+ vhost_add_used_and_signal(&vs->dev, vq, head, 0);
+ else
+ vq_err(vq, "Faulted on tcm_vhost_send_event\n");
+}
+
+static void tcm_vhost_evt_work(struct vhost_work *work)
+{
+ struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
+ vs_event_work);
+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];
+ struct tcm_vhost_evt *evt;
+ struct llist_node *llnode;
+
+ mutex_lock(&vq->mutex);
+ llnode = llist_del_all(&vs->vs_event_list);
+ while (llnode) {
+ evt = llist_entry(llnode, struct tcm_vhost_evt, list);
+ llnode = llist_next(llnode);
+ tcm_vhost_do_evt_work(vs, evt);
+ tcm_vhost_free_evt(vs, evt);
+ }
+ mutex_unlock(&vq->mutex);
+}
+
/* Fill in status and signal that we are done processing this command
*
* This is scheduled in the vhost work queue so we are called with the owner
@@ -570,9 +686,27 @@ static void tcm_vhost_submission_work(struct work_struct *work)
}
}
+static void vhost_scsi_send_bad_target(struct vhost_scsi *vs,
+ struct vhost_virtqueue *vq, int head, unsigned out)
+{
+ struct virtio_scsi_cmd_resp __user *resp;
+ struct virtio_scsi_cmd_resp rsp;
+ int ret;
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
+ resp = vq->iov[out].iov_base;
+ ret = __copy_to_user(resp, &rsp, sizeof(rsp));
+ if (!ret)
+ vhost_add_used_and_signal(&vs->dev, vq, head, 0);
+ else
+ pr_err("Faulted on virtio_scsi_cmd_resp\n");
+}
+
static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
struct vhost_virtqueue *vq)
{
+ struct tcm_vhost_tpg **vs_tpg;
struct virtio_scsi_cmd_req v_req;
struct tcm_vhost_tpg *tv_tpg;
struct tcm_vhost_cmd *tv_cmd;
@@ -581,8 +715,16 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
int head, ret;
u8 target;
- /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */
- if (unlikely(!vs->vs_endpoint))
+ /*
+ * We can handle the vq only after the endpoint is setup by calling the
+ * VHOST_SCSI_SET_ENDPOINT ioctl.
+ *
+ * TODO: Check that we are running from vhost_worker which acts
+ * as read-side critical section for vhost kind of RCU.
+ * See the comments in struct vhost_virtqueue in drivers/vhost/vhost.h
+ */
+ vs_tpg = rcu_dereference_check(vq->private_data, 1);
+ if (!vs_tpg)
return;
mutex_lock(&vq->mutex);
@@ -652,23 +794,11 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
/* Extract the tpgt */
target = v_req.lun[1];
- tv_tpg = vs->vs_tpg[target];
+ tv_tpg = ACCESS_ONCE(vs_tpg[target]);
/* Target does not exist, fail the request */
if (unlikely(!tv_tpg)) {
- struct virtio_scsi_cmd_resp __user *resp;
- struct virtio_scsi_cmd_resp rsp;
-
- memset(&rsp, 0, sizeof(rsp));
- rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
- resp = vq->iov[out].iov_base;
- ret = __copy_to_user(resp, &rsp, sizeof(rsp));
- if (!ret)
- vhost_add_used_and_signal(&vs->dev,
- vq, head, 0);
- else
- pr_err("Faulted on virtio_scsi_cmd_resp\n");
-
+ vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
@@ -681,22 +811,13 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
if (IS_ERR(tv_cmd)) {
vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
PTR_ERR(tv_cmd));
- break;
+ goto err_cmd;
}
pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
": %d\n", tv_cmd, exp_data_len, data_direction);
tv_cmd->tvc_vhost = vs;
tv_cmd->tvc_vq = vq;
-
- if (unlikely(vq->iov[out].iov_len !=
- sizeof(struct virtio_scsi_cmd_resp))) {
- vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
- " bytes, out: %d, in: %d\n",
- vq->iov[out].iov_len, out, in);
- break;
- }
-
tv_cmd->tvc_resp = vq->iov[out].iov_base;
/*
@@ -716,7 +837,7 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
scsi_command_size(tv_cmd->tvc_cdb),
TCM_VHOST_MAX_CDB_SIZE);
- break; /* TODO */
+ goto err_free;
}
tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
@@ -729,7 +850,7 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
data_direction == DMA_TO_DEVICE);
if (unlikely(ret)) {
vq_err(vq, "Failed to map iov to sgl\n");
- break; /* TODO */
+ goto err_free;
}
}
@@ -750,6 +871,13 @@ static void vhost_scsi_handle_vq(struct vhost_scsi *vs,
}
mutex_unlock(&vq->mutex);
+ return;
+
+err_free:
+ vhost_scsi_free_cmd(tv_cmd);
+err_cmd:
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ mutex_unlock(&vq->mutex);
}
static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
@@ -757,9 +885,46 @@ static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
pr_debug("%s: The handling func for control queue.\n", __func__);
}
+static void tcm_vhost_send_evt(struct vhost_scsi *vs, struct tcm_vhost_tpg *tpg,
+ struct se_lun *lun, u32 event, u32 reason)
+{
+ struct tcm_vhost_evt *evt;
+
+ evt = tcm_vhost_allocate_evt(vs, event, reason);
+ if (!evt)
+ return;
+
+ if (tpg && lun) {
+ /* TODO: share lun setup code with virtio-scsi.ko */
+ /*
+ * Note: evt->event is zeroed when we allocate it and
+ * lun[4-7] need to be zero according to virtio-scsi spec.
+ */
+ evt->event.lun[0] = 0x01;
+ evt->event.lun[1] = tpg->tport_tpgt & 0xFF;
+ if (lun->unpacked_lun >= 256)
+ evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
+ evt->event.lun[3] = lun->unpacked_lun & 0xFF;
+ }
+
+ llist_add(&evt->list, &vs->vs_event_list);
+ vhost_work_queue(&vs->dev, &vs->vs_event_work);
+}
+
static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
{
- pr_debug("%s: The handling func for event queue.\n", __func__);
+ struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+ poll.work);
+ struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
+
+ mutex_lock(&vq->mutex);
+ if (!vq->private_data)
+ goto out;
+
+ if (vs->vs_events_missed)
+ tcm_vhost_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
+out:
+ mutex_unlock(&vq->mutex);
}
static void vhost_scsi_handle_kick(struct vhost_work *work)
@@ -771,9 +936,27 @@ static void vhost_scsi_handle_kick(struct vhost_work *work)
vhost_scsi_handle_vq(vs, vq);
}
+static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
+{
+ vhost_poll_flush(&vs->dev.vqs[index].poll);
+}
+
+static void vhost_scsi_flush(struct vhost_scsi *vs)
+{
+ int i;
+
+ for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
+ vhost_scsi_flush_vq(vs, i);
+ vhost_work_flush(&vs->dev, &vs->vs_completion_work);
+ vhost_work_flush(&vs->dev, &vs->vs_event_work);
+}
+
/*
* Called from vhost_scsi_ioctl() context to walk the list of available
* tcm_vhost_tpg with an active struct tcm_vhost_nexus
+ *
+ * The lock nesting rule is:
+ * tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
*/
static int vhost_scsi_set_endpoint(
struct vhost_scsi *vs,
@@ -781,20 +964,32 @@ static int vhost_scsi_set_endpoint(
{
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tv_tpg;
+ struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_virtqueue *vq;
+ int index, ret, i, len;
bool match = false;
- int index, ret;
+ mutex_lock(&tcm_vhost_mutex);
mutex_lock(&vs->dev.mutex);
+
/* Verify that ring has been setup correctly. */
for (index = 0; index < vs->dev.nvqs; ++index) {
/* Verify that ring has been setup correctly. */
if (!vhost_vq_access_ok(&vs->vqs[index])) {
- mutex_unlock(&vs->dev.mutex);
- return -EFAULT;
+ ret = -EFAULT;
+ goto out;
}
}
- mutex_lock(&tcm_vhost_mutex);
+ len = sizeof(vs_tpg[0]) * VHOST_SCSI_MAX_TARGET;
+ vs_tpg = kzalloc(len, GFP_KERNEL);
+ if (!vs_tpg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (vs->vs_tpg)
+ memcpy(vs_tpg, vs->vs_tpg, len);
+
list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {
mutex_lock(&tv_tpg->tv_tpg_mutex);
if (!tv_tpg->tpg_nexus) {
@@ -808,31 +1003,48 @@ static int vhost_scsi_set_endpoint(
tv_tport = tv_tpg->tport;
if (!strcmp(tv_tport->tport_name, t->vhost_wwpn)) {
- if (vs->vs_tpg[tv_tpg->tport_tpgt]) {
+ if (vs->vs_tpg && vs->vs_tpg[tv_tpg->tport_tpgt]) {
+ kfree(vs_tpg);
mutex_unlock(&tv_tpg->tv_tpg_mutex);
- mutex_unlock(&tcm_vhost_mutex);
- mutex_unlock(&vs->dev.mutex);
- return -EEXIST;
+ ret = -EEXIST;
+ goto out;
}
tv_tpg->tv_tpg_vhost_count++;
- vs->vs_tpg[tv_tpg->tport_tpgt] = tv_tpg;
+ tv_tpg->vhost_scsi = vs;
+ vs_tpg[tv_tpg->tport_tpgt] = tv_tpg;
smp_mb__after_atomic_inc();
match = true;
}
mutex_unlock(&tv_tpg->tv_tpg_mutex);
}
- mutex_unlock(&tcm_vhost_mutex);
if (match) {
memcpy(vs->vs_vhost_wwpn, t->vhost_wwpn,
sizeof(vs->vs_vhost_wwpn));
- vs->vs_endpoint = true;
+ for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+ vq = &vs->vqs[i];
+ /* Flushing the vhost_work acts as synchronize_rcu */
+ mutex_lock(&vq->mutex);
+ rcu_assign_pointer(vq->private_data, vs_tpg);
+ vhost_init_used(vq);
+ mutex_unlock(&vq->mutex);
+ }
ret = 0;
} else {
ret = -EEXIST;
}
+ /*
+ * Act as synchronize_rcu to make sure access to
+ * old vs->vs_tpg is finished.
+ */
+ vhost_scsi_flush(vs);
+ kfree(vs->vs_tpg);
+ vs->vs_tpg = vs_tpg;
+
+out:
mutex_unlock(&vs->dev.mutex);
+ mutex_unlock(&tcm_vhost_mutex);
return ret;
}
@@ -842,9 +1054,12 @@ static int vhost_scsi_clear_endpoint(
{
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tv_tpg;
+ struct vhost_virtqueue *vq;
+ bool match = false;
int index, ret, i;
u8 target;
+ mutex_lock(&tcm_vhost_mutex);
mutex_lock(&vs->dev.mutex);
/* Verify that ring has been setup correctly. */
for (index = 0; index < vs->dev.nvqs; ++index) {
@@ -853,9 +1068,14 @@ static int vhost_scsi_clear_endpoint(
goto err_dev;
}
}
+
+ if (!vs->vs_tpg) {
+ ret = 0;
+ goto err_dev;
+ }
+
for (i = 0; i < VHOST_SCSI_MAX_TARGET; i++) {
target = i;
-
tv_tpg = vs->vs_tpg[target];
if (!tv_tpg)
continue;
@@ -876,20 +1096,58 @@ static int vhost_scsi_clear_endpoint(
goto err_tpg;
}
tv_tpg->tv_tpg_vhost_count--;
+ tv_tpg->vhost_scsi = NULL;
vs->vs_tpg[target] = NULL;
- vs->vs_endpoint = false;
+ match = true;
mutex_unlock(&tv_tpg->tv_tpg_mutex);
}
+ if (match) {
+ for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
+ vq = &vs->vqs[i];
+ /* Flushing the vhost_work acts as synchronize_rcu */
+ mutex_lock(&vq->mutex);
+ rcu_assign_pointer(vq->private_data, NULL);
+ mutex_unlock(&vq->mutex);
+ }
+ }
+ /*
+ * Act as synchronize_rcu to make sure access to
+ * old vs->vs_tpg is finished.
+ */
+ vhost_scsi_flush(vs);
+ kfree(vs->vs_tpg);
+ vs->vs_tpg = NULL;
+ WARN_ON(vs->vs_events_nr);
mutex_unlock(&vs->dev.mutex);
+ mutex_unlock(&tcm_vhost_mutex);
return 0;
err_tpg:
mutex_unlock(&tv_tpg->tv_tpg_mutex);
err_dev:
mutex_unlock(&vs->dev.mutex);
+ mutex_unlock(&tcm_vhost_mutex);
return ret;
}
+static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+{
+ if (features & ~VHOST_SCSI_FEATURES)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&vs->dev.mutex);
+ if ((features & (1 << VHOST_F_LOG_ALL)) &&
+ !vhost_log_access_ok(&vs->dev)) {
+ mutex_unlock(&vs->dev.mutex);
+ return -EFAULT;
+ }
+ vs->dev.acked_features = features;
+ smp_wmb();
+ vhost_scsi_flush(vs);
+ mutex_unlock(&vs->dev.mutex);
+ return 0;
+}
+
static int vhost_scsi_open(struct inode *inode, struct file *f)
{
struct vhost_scsi *s;
@@ -900,6 +1158,10 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
return -ENOMEM;
vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);
+ vhost_work_init(&s->vs_event_work, tcm_vhost_evt_work);
+
+ s->vs_events_nr = 0;
+ s->vs_events_missed = false;
s->vqs[VHOST_SCSI_VQ_CTL].handle_kick = vhost_scsi_ctl_handle_kick;
s->vqs[VHOST_SCSI_VQ_EVT].handle_kick = vhost_scsi_evt_handle_kick;
@@ -926,42 +1188,12 @@ static int vhost_scsi_release(struct inode *inode, struct file *f)
vhost_scsi_clear_endpoint(s, &t);
vhost_dev_stop(&s->dev);
vhost_dev_cleanup(&s->dev, false);
+ /* Jobs can re-queue themselves in evt kick handler. Do extra flush. */
+ vhost_scsi_flush(s);
kfree(s);
return 0;
}
-static void vhost_scsi_flush_vq(struct vhost_scsi *vs, int index)
-{
- vhost_poll_flush(&vs->dev.vqs[index].poll);
-}
-
-static void vhost_scsi_flush(struct vhost_scsi *vs)
-{
- int i;
-
- for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
- vhost_scsi_flush_vq(vs, i);
- vhost_work_flush(&vs->dev, &vs->vs_completion_work);
-}
-
-static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
-{
- if (features & ~VHOST_FEATURES)
- return -EOPNOTSUPP;
-
- mutex_lock(&vs->dev.mutex);
- if ((features & (1 << VHOST_F_LOG_ALL)) &&
- !vhost_log_access_ok(&vs->dev)) {
- mutex_unlock(&vs->dev.mutex);
- return -EFAULT;
- }
- vs->dev.acked_features = features;
- smp_wmb();
- vhost_scsi_flush(vs);
- mutex_unlock(&vs->dev.mutex);
- return 0;
-}
-
static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
unsigned long arg)
{
@@ -969,8 +1201,11 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
struct vhost_scsi_target backend;
void __user *argp = (void __user *)arg;
u64 __user *featurep = argp;
+ u32 __user *eventsp = argp;
+ u32 events_missed;
u64 features;
int r, abi_version = VHOST_SCSI_ABI_VERSION;
+ struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT];
switch (ioctl) {
case VHOST_SCSI_SET_ENDPOINT:
@@ -991,8 +1226,22 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
if (copy_to_user(argp, &abi_version, sizeof abi_version))
return -EFAULT;
return 0;
+ case VHOST_SCSI_SET_EVENTS_MISSED:
+ if (get_user(events_missed, eventsp))
+ return -EFAULT;
+ mutex_lock(&vq->mutex);
+ vs->vs_events_missed = events_missed;
+ mutex_unlock(&vq->mutex);
+ return 0;
+ case VHOST_SCSI_GET_EVENTS_MISSED:
+ mutex_lock(&vq->mutex);
+ events_missed = vs->vs_events_missed;
+ mutex_unlock(&vq->mutex);
+ if (put_user(events_missed, eventsp))
+ return -EFAULT;
+ return 0;
case VHOST_GET_FEATURES:
- features = VHOST_FEATURES;
+ features = VHOST_SCSI_FEATURES;
if (copy_to_user(featurep, &features, sizeof features))
return -EFAULT;
return 0;
@@ -1062,28 +1311,80 @@ static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
return "Unknown";
}
+static void tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
+ struct se_lun *lun, bool plug)
+{
+
+ struct vhost_scsi *vs = tpg->vhost_scsi;
+ struct vhost_virtqueue *vq;
+ u32 reason;
+
+ if (!vs)
+ return;
+
+ mutex_lock(&vs->dev.mutex);
+ if (!vhost_has_feature(&vs->dev, VIRTIO_SCSI_F_HOTPLUG)) {
+ mutex_unlock(&vs->dev.mutex);
+ return;
+ }
+
+ if (plug)
+ reason = VIRTIO_SCSI_EVT_RESET_RESCAN;
+ else
+ reason = VIRTIO_SCSI_EVT_RESET_REMOVED;
+
+ vq = &vs->vqs[VHOST_SCSI_VQ_EVT];
+ mutex_lock(&vq->mutex);
+ tcm_vhost_send_evt(vs, tpg, lun,
+ VIRTIO_SCSI_T_TRANSPORT_RESET, reason);
+ mutex_unlock(&vq->mutex);
+ mutex_unlock(&vs->dev.mutex);
+}
+
+static void tcm_vhost_hotplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+{
+ tcm_vhost_do_plug(tpg, lun, true);
+}
+
+static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+{
+ tcm_vhost_do_plug(tpg, lun, false);
+}
+
static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
struct se_lun *lun)
{
struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
+ mutex_lock(&tcm_vhost_mutex);
+
mutex_lock(&tv_tpg->tv_tpg_mutex);
tv_tpg->tv_tpg_port_count++;
mutex_unlock(&tv_tpg->tv_tpg_mutex);
+ tcm_vhost_hotplug(tv_tpg, lun);
+
+ mutex_unlock(&tcm_vhost_mutex);
+
return 0;
}
static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
- struct se_lun *se_lun)
+ struct se_lun *lun)
{
struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
struct tcm_vhost_tpg, se_tpg);
+ mutex_lock(&tcm_vhost_mutex);
+
mutex_lock(&tv_tpg->tv_tpg_mutex);
tv_tpg->tv_tpg_port_count--;
mutex_unlock(&tv_tpg->tv_tpg_mutex);
+
+ tcm_vhost_hotunplug(tv_tpg, lun);
+
+ mutex_unlock(&tcm_vhost_mutex);
}
static struct se_node_acl *tcm_vhost_make_nodeacl(
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
index 1d2ae7a60e11..514b9fda230e 100644
--- a/drivers/vhost/tcm_vhost.h
+++ b/drivers/vhost/tcm_vhost.h
@@ -53,6 +53,7 @@ struct tcm_vhost_nacl {
struct se_node_acl se_node_acl;
};
+struct vhost_scsi;
struct tcm_vhost_tpg {
/* Vhost port target portal group tag for TCM */
u16 tport_tpgt;
@@ -70,6 +71,8 @@ struct tcm_vhost_tpg {
struct tcm_vhost_tport *tport;
/* Returned by tcm_vhost_make_tpg() */
struct se_portal_group se_tpg;
+ /* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
+ struct vhost_scsi *vhost_scsi;
};
struct tcm_vhost_tport {
@@ -83,6 +86,13 @@ struct tcm_vhost_tport {
struct se_wwn tport_wwn;
};
+struct tcm_vhost_evt {
+ /* event to be sent to guest */
+ struct virtio_scsi_event event;
+ /* event list, serviced from vhost worker thread */
+ struct llist_node list;
+};
+
/*
* As per request from MST, keep TCM_VHOST related ioctl defines out of
* linux/vhost.h (user-space) for now..
@@ -113,3 +123,6 @@ struct vhost_scsi_target {
#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target)
/* Changing this breaks userspace. */
#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, int)
+/* Set and get the events missed flag */
+#define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32)
+#define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 9759249e6d90..4eecdb867d53 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -89,6 +89,9 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file)
unsigned long mask;
int ret = 0;
+ if (poll->wqh)
+ return 0;
+
mask = file->f_op->poll(file, &poll->table);
if (mask)
vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c1546f71d56..76be61701c97 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -31,26 +31,8 @@ config VIDEO_OUTPUT_CONTROL
This framework adds support for low-level control of the video
output switch.
-config DISPLAY_TIMING
- bool
-
-config VIDEOMODE
- bool
-
-config OF_DISPLAY_TIMING
- bool "Enable device tree display timing support"
- depends on OF
- select DISPLAY_TIMING
- help
- helper to parse display timings from the devicetree
-
-config OF_VIDEOMODE
- bool "Enable device tree videomode support"
- depends on OF
- select VIDEOMODE
- select OF_DISPLAY_TIMING
- help
- helper to get videomodes from the devicetree
+config VIDEOMODE_HELPERS
+ bool
config HDMI
bool
@@ -212,14 +194,6 @@ config FB_SYS_FOPS
depends on FB
default n
-config FB_WMT_GE_ROPS
- tristate
- depends on FB
- default n
- ---help---
- Include functions for accelerated rectangle filling and area
- copying using WonderMedia Graphics Engine operations.
-
config FB_DEFERRED_IO
bool
depends on FB
@@ -1797,22 +1771,37 @@ config FB_AU1200
option au1200fb:panel=<name>.
config FB_VT8500
- bool "VT8500 LCD Driver"
+ bool "VIA VT8500 framebuffer support"
depends on (FB = y) && ARM && ARCH_VT8500
- select FB_WMT_GE_ROPS
+ select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+ select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
select FB_SYS_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
help
This is the framebuffer driver for VIA VT8500 integrated LCD
controller.
config FB_WM8505
- bool "WM8505 frame buffer support"
+ bool "Wondermedia WM8xxx-series frame buffer support"
depends on (FB = y) && ARM && ARCH_VT8500
- select FB_WMT_GE_ROPS
+ select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS)
+ select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS)
select FB_SYS_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
+ help
+ This is the framebuffer driver for WonderMedia WM8xxx-series
+ integrated LCD controller. This driver covers the WM8505, WM8650
+ and WM8850 SoCs.
+
+config FB_WMT_GE_ROPS
+ bool "VT8500/WM8xxx accelerated raster ops support"
+ depends on (FB = y) && (FB_VT8500 || FB_WM8505)
+ default n
help
- This is the framebuffer driver for WonderMedia WM8505/WM8650
- integrated LCD controller.
+ This adds support for accelerated raster operations on the
+ VIA VT8500 and Wondermedia 85xx series SoCs.
source "drivers/video/geode/Kconfig"
@@ -2277,7 +2266,7 @@ config XEN_FBDEV_FRONTEND
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
- select INPUT_XEN_KBDDEV_FRONTEND
+ select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC
select XEN_XENBUS_FRONTEND
default y
help
@@ -2451,6 +2440,15 @@ config FB_PUV3_UNIGFX
Choose this option if you want to use the Unigfx device as a
framebuffer device. Without the support of PCI & AGP.
+config FB_HYPERV
+ tristate "Microsoft Hyper-V Synthetic Video support"
+ depends on FB && HYPERV
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9df387334cb7..7234e4a959e8 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -149,6 +149,7 @@ obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o
+obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
@@ -171,7 +172,7 @@ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
#video output switch sysfs driver
obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
-obj-$(CONFIG_DISPLAY_TIMING) += display_timing.o
-obj-$(CONFIG_OF_DISPLAY_TIMING) += of_display_timing.o
-obj-$(CONFIG_VIDEOMODE) += videomode.o
-obj-$(CONFIG_OF_VIDEOMODE) += of_videomode.o
+obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o
+ifeq ($(CONFIG_OF),y)
+obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o
+endif
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 7fa1bf823729..a6780eecff0e 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1181,7 +1181,7 @@ static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par,
}
/*
- * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing
+ * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following
* checks failed and smooth scrolling is not possible
*/
@@ -3788,19 +3788,7 @@ static struct platform_driver amifb_driver = {
},
};
-static int __init amifb_init(void)
-{
- return platform_driver_probe(&amifb_driver, amifb_probe);
-}
-
-module_init(amifb_init);
-
-static void __exit amifb_exit(void)
-{
- platform_driver_unregister(&amifb_driver);
-}
-
-module_exit(amifb_exit);
+module_platform_driver_probe(amifb_driver, amifb_probe);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-video");
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 025428e04c33..98348ec0b3ce 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -1158,18 +1158,7 @@ static struct platform_driver atmel_lcdfb_driver = {
},
};
-static int __init atmel_lcdfb_init(void)
-{
- return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
-}
-
-static void __exit atmel_lcdfb_exit(void)
-{
- platform_driver_unregister(&atmel_lcdfb_driver);
-}
-
-module_init(atmel_lcdfb_init);
-module_exit(atmel_lcdfb_exit);
+module_platform_driver_probe(atmel_lcdfb_driver, atmel_lcdfb_probe);
MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
diff --git a/drivers/video/auo_k1900fb.c b/drivers/video/auo_k1900fb.c
index 1a9ac6e1f4b3..f5b668e77af3 100644
--- a/drivers/video/auo_k1900fb.c
+++ b/drivers/video/auo_k1900fb.c
@@ -60,9 +60,12 @@
static void auok1900_init(struct auok190xfb_par *par)
{
+ struct device *dev = par->info->device;
struct auok190x_board *board = par->board;
u16 init_param = 0;
+ pm_runtime_get_sync(dev);
+
init_param |= AUOK1900_INIT_TEMP_AVERAGE;
init_param |= AUOK1900_INIT_ROTATE(par->rotation);
init_param |= AUOK190X_INIT_INVERSE_WHITE;
@@ -74,6 +77,9 @@ static void auok1900_init(struct auok190xfb_par *par)
/* let the controller finish */
board->wait_for_rdy(par);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
static void auok1900_update_region(struct auok190xfb_par *par, int mode,
@@ -82,6 +88,7 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode,
struct device *dev = par->info->device;
unsigned char *buf = (unsigned char *)par->info->screen_base;
int xres = par->info->var.xres;
+ int line_length = par->info->fix.line_length;
u16 args[4];
pm_runtime_get_sync(dev);
@@ -100,9 +107,9 @@ static void auok1900_update_region(struct auok190xfb_par *par, int mode,
args[1] = y1 + 1;
args[2] = xres;
args[3] = y2 - y1;
- buf += y1 * xres;
+ buf += y1 * line_length;
auok190x_send_cmdargs_pixels(par, AUOK1900_CMD_PARTIALDISP, 4, args,
- ((y2 - y1) * xres)/2, (u16 *) buf);
+ ((y2 - y1) * line_length)/2, (u16 *) buf);
auok190x_send_command(par, AUOK190X_CMD_DATA_STOP);
par->update_cnt++;
diff --git a/drivers/video/auo_k1901fb.c b/drivers/video/auo_k1901fb.c
index d1db1653cd88..12b9adcb75c5 100644
--- a/drivers/video/auo_k1901fb.c
+++ b/drivers/video/auo_k1901fb.c
@@ -101,9 +101,12 @@
static void auok1901_init(struct auok190xfb_par *par)
{
+ struct device *dev = par->info->device;
struct auok190x_board *board = par->board;
u16 init_param = 0;
+ pm_runtime_get_sync(dev);
+
init_param |= AUOK190X_INIT_INVERSE_WHITE;
init_param |= AUOK190X_INIT_FORMAT0;
init_param |= AUOK1901_INIT_RESOLUTION(par->resolution);
@@ -113,6 +116,9 @@ static void auok1901_init(struct auok190xfb_par *par)
/* let the controller finish */
board->wait_for_rdy(par);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
static void auok1901_update_region(struct auok190xfb_par *par, int mode,
@@ -121,6 +127,7 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode,
struct device *dev = par->info->device;
unsigned char *buf = (unsigned char *)par->info->screen_base;
int xres = par->info->var.xres;
+ int line_length = par->info->fix.line_length;
u16 args[5];
pm_runtime_get_sync(dev);
@@ -139,9 +146,9 @@ static void auok1901_update_region(struct auok190xfb_par *par, int mode,
args[1] = y1 + 1;
args[2] = xres;
args[3] = y2 - y1;
- buf += y1 * xres;
+ buf += y1 * line_length;
auok190x_send_cmdargs_pixels_nowait(par, AUOK1901_CMD_DMA_START, 4,
- args, ((y2 - y1) * xres)/2,
+ args, ((y2 - y1) * line_length)/2,
(u16 *) buf);
auok190x_send_command_nowait(par, AUOK190X_CMD_DATA_STOP);
diff --git a/drivers/video/auo_k190x.c b/drivers/video/auo_k190x.c
index 53846cb534d4..8d2499d1cafb 100644
--- a/drivers/video/auo_k190x.c
+++ b/drivers/video/auo_k190x.c
@@ -40,6 +40,14 @@ static struct panel_info panel_table[] = {
.w = 1024,
.h = 768,
},
+ [AUOK190X_RESOLUTION_600_800] = {
+ .w = 600,
+ .h = 800,
+ },
+ [AUOK190X_RESOLUTION_768_1024] = {
+ .w = 768,
+ .h = 1024,
+ },
};
/*
@@ -60,8 +68,48 @@ static void auok190x_issue_cmd(struct auok190xfb_par *par, u16 data)
par->board->set_ctl(par, AUOK190X_I80_DC, 1);
}
-static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
- u16 *data)
+/**
+ * Conversion of 16bit color to 4bit grayscale
+ * does roughly (0.3 * R + 0.6 G + 0.1 B) / 2
+ */
+static inline int rgb565_to_gray4(u16 data, struct fb_var_screeninfo *var)
+{
+ return ((((data & 0xF800) >> var->red.offset) * 77 +
+ ((data & 0x07E0) >> (var->green.offset + 1)) * 151 +
+ ((data & 0x1F) >> var->blue.offset) * 28) >> 8 >> 1);
+}
+
+static int auok190x_issue_pixels_rgb565(struct auok190xfb_par *par, int size,
+ u16 *data)
+{
+ struct fb_var_screeninfo *var = &par->info->var;
+ struct device *dev = par->info->device;
+ int i;
+ u16 tmp;
+
+ if (size & 7) {
+ dev_err(dev, "issue_pixels: size %d must be a multiple of 8\n",
+ size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < (size >> 2); i++) {
+ par->board->set_ctl(par, AUOK190X_I80_WR, 0);
+
+ tmp = (rgb565_to_gray4(data[4*i], var) & 0x000F);
+ tmp |= (rgb565_to_gray4(data[4*i+1], var) << 4) & 0x00F0;
+ tmp |= (rgb565_to_gray4(data[4*i+2], var) << 8) & 0x0F00;
+ tmp |= (rgb565_to_gray4(data[4*i+3], var) << 12) & 0xF000;
+
+ par->board->set_hdb(par, tmp);
+ par->board->set_ctl(par, AUOK190X_I80_WR, 1);
+ }
+
+ return 0;
+}
+
+static int auok190x_issue_pixels_gray8(struct auok190xfb_par *par, int size,
+ u16 *data)
{
struct device *dev = par->info->device;
int i;
@@ -91,6 +139,23 @@ static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
return 0;
}
+static int auok190x_issue_pixels(struct auok190xfb_par *par, int size,
+ u16 *data)
+{
+ struct fb_info *info = par->info;
+ struct device *dev = par->info->device;
+
+ if (info->var.bits_per_pixel == 8 && info->var.grayscale)
+ auok190x_issue_pixels_gray8(par, size, data);
+ else if (info->var.bits_per_pixel == 16)
+ auok190x_issue_pixels_rgb565(par, size, data);
+ else
+ dev_err(dev, "unsupported color mode (bits: %d, gray: %d)\n",
+ info->var.bits_per_pixel, info->var.grayscale);
+
+ return 0;
+}
+
static u16 auok190x_read_data(struct auok190xfb_par *par)
{
u16 data;
@@ -224,8 +289,8 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
{
struct fb_deferred_io *fbdefio = info->fbdefio;
struct auok190xfb_par *par = info->par;
+ u16 line_length = info->fix.line_length;
u16 yres = info->var.yres;
- u16 xres = info->var.xres;
u16 y1 = 0, h = 0;
int prev_index = -1;
struct page *cur;
@@ -254,7 +319,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
}
/* height increment is fixed per page */
- h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
+ h_inc = DIV_ROUND_UP(PAGE_SIZE , line_length);
/* calculate number of pages from pixel height */
threshold = par->consecutive_threshold / h_inc;
@@ -265,7 +330,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
if (prev_index < 0) {
/* just starting so assign first page */
- y1 = (cur->index << PAGE_SHIFT) / xres;
+ y1 = (cur->index << PAGE_SHIFT) / line_length;
h = h_inc;
} else if ((cur->index - prev_index) <= threshold) {
/* page is within our threshold for single updates */
@@ -275,7 +340,7 @@ static void auok190xfb_dpy_deferred_io(struct fb_info *info,
par->update_partial(par, y1, y1 + h);
/* start over with our non consecutive page */
- y1 = (cur->index << PAGE_SHIFT) / xres;
+ y1 = (cur->index << PAGE_SHIFT) / line_length;
h = h_inc;
}
prev_index = cur->index;
@@ -376,27 +441,127 @@ static void auok190xfb_imageblit(struct fb_info *info,
static int auok190xfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- if (info->var.xres != var->xres || info->var.yres != var->yres ||
- info->var.xres_virtual != var->xres_virtual ||
- info->var.yres_virtual != var->yres_virtual) {
- pr_info("%s: Resolution not supported: X%u x Y%u\n",
- __func__, var->xres, var->yres);
+ struct device *dev = info->device;
+ struct auok190xfb_par *par = info->par;
+ struct panel_info *panel = &panel_table[par->resolution];
+ int size;
+
+ /*
+ * Color depth
+ */
+
+ if (var->bits_per_pixel == 8 && var->grayscale == 1) {
+ /*
+ * For 8-bit grayscale, R, G, and B offset are equal.
+ */
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 0;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ } else if (var->bits_per_pixel == 16) {
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ } else {
+ dev_warn(dev, "unsupported color mode (bits: %d, grayscale: %d)\n",
+ info->var.bits_per_pixel, info->var.grayscale);
return -EINVAL;
}
/*
+ * Dimensions
+ */
+
+ switch (var->rotate) {
+ case FB_ROTATE_UR:
+ case FB_ROTATE_UD:
+ var->xres = panel->w;
+ var->yres = panel->h;
+ break;
+ case FB_ROTATE_CW:
+ case FB_ROTATE_CCW:
+ var->xres = panel->h;
+ var->yres = panel->w;
+ break;
+ default:
+ dev_dbg(dev, "Invalid rotation request\n");
+ return -EINVAL;
+ }
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+
+ /*
* Memory limit
*/
- if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
- pr_info("%s: Memory Limit requested yres_virtual = %u\n",
- __func__, var->yres_virtual);
+ size = var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8;
+ if (size > info->fix.smem_len) {
+ dev_err(dev, "Memory limit exceeded, requested %dK\n",
+ size >> 10);
return -ENOMEM;
}
return 0;
}
+static int auok190xfb_set_fix(struct fb_info *info)
+{
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct fb_var_screeninfo *var = &info->var;
+
+ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->accel = FB_ACCEL_NONE;
+ fix->visual = (var->grayscale) ? FB_VISUAL_STATIC_PSEUDOCOLOR
+ : FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 0;
+ fix->ypanstep = 0;
+ fix->ywrapstep = 0;
+
+ return 0;
+}
+
+static int auok190xfb_set_par(struct fb_info *info)
+{
+ struct auok190xfb_par *par = info->par;
+
+ par->rotation = info->var.rotate;
+ auok190xfb_set_fix(info);
+
+ /* reinit the controller to honor the rotation */
+ par->init(par);
+
+ /* wait for init to complete */
+ par->board->wait_for_rdy(par);
+
+ return 0;
+}
+
static struct fb_ops auok190xfb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
@@ -405,6 +570,7 @@ static struct fb_ops auok190xfb_ops = {
.fb_copyarea = auok190xfb_copyarea,
.fb_imageblit = auok190xfb_imageblit,
.fb_check_var = auok190xfb_check_var,
+ .fb_set_par = auok190xfb_set_par,
};
/*
@@ -588,10 +754,16 @@ static int auok190x_power(struct auok190xfb_par *par, bool on)
static void auok190x_recover(struct auok190xfb_par *par)
{
+ struct device *dev = par->info->device;
+
auok190x_power(par, 0);
msleep(100);
auok190x_power(par, 1);
+ /* after powercycling the device, it's always active */
+ pm_runtime_set_active(dev);
+ par->standby = 0;
+
par->init(par);
/* wait for init to complete */
@@ -875,42 +1047,17 @@ int auok190x_common_probe(struct platform_device *pdev,
/* initialise fix, var, resolution and rotation */
strlcpy(info->fix.id, init->id, 16);
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
- info->fix.xpanstep = 0;
- info->fix.ypanstep = 0;
- info->fix.ywrapstep = 0;
- info->fix.accel = FB_ACCEL_NONE;
-
info->var.bits_per_pixel = 8;
info->var.grayscale = 1;
- info->var.red.length = 8;
- info->var.green.length = 8;
- info->var.blue.length = 8;
panel = &panel_table[board->resolution];
- /* if 90 degree rotation, switch width and height */
- if (board->rotation & 1) {
- info->var.xres = panel->h;
- info->var.yres = panel->w;
- info->var.xres_virtual = panel->h;
- info->var.yres_virtual = panel->w;
- info->fix.line_length = panel->h;
- } else {
- info->var.xres = panel->w;
- info->var.yres = panel->h;
- info->var.xres_virtual = panel->w;
- info->var.yres_virtual = panel->h;
- info->fix.line_length = panel->w;
- }
-
par->resolution = board->resolution;
- par->rotation = board->rotation;
+ par->rotation = 0;
/* videomemory handling */
- videomemorysize = roundup((panel->w * panel->h), PAGE_SIZE);
+ videomemorysize = roundup((panel->w * panel->h) * 2, PAGE_SIZE);
videomemory = vmalloc(videomemorysize);
if (!videomemory) {
ret = -ENOMEM;
@@ -924,6 +1071,12 @@ int auok190x_common_probe(struct platform_device *pdev,
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
info->fbops = &auok190xfb_ops;
+ ret = auok190xfb_check_var(&info->var, info);
+ if (ret)
+ goto err_defio;
+
+ auok190xfb_set_fix(info);
+
/* deferred io init */
info->fbdefio = devm_kzalloc(info->device,
@@ -935,7 +1088,7 @@ int auok190x_common_probe(struct platform_device *pdev,
goto err_defio;
}
- dev_dbg(info->device, "targetting %d frames per second\n", board->fps);
+ dev_dbg(info->device, "targeting %d frames per second\n", board->fps);
info->fbdefio->delay = HZ / board->fps;
info->fbdefio->first_io = auok190xfb_dpy_first_io,
info->fbdefio->deferred_io = auok190xfb_dpy_deferred_io,
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index db10d0120d2b..2e166c3fc4c3 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -59,6 +59,13 @@ config LCD_LTV350QV
The LTV350QV panel is present on all ATSTK1000 boards.
+config LCD_ILI922X
+ tristate "ILI Technology ILI9221/ILI9222 support"
+ depends on SPI
+ help
+ If you have a panel based on the ILI9221/9222 controller
+ chip then say y to include a driver for it.
+
config LCD_ILI9320
tristate "ILI Technology ILI9320 controller support"
depends on SPI
@@ -161,7 +168,7 @@ if BACKLIGHT_CLASS_DEVICE
config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control"
depends on FB_ATMEL
- default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
+ default y if MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK
help
This provides a backlight control internal to the Atmel LCDC
driver. If the LCD "contrast control" on your board is wired
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 96c4d620c5ce..92711fe60464 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o
obj-$(CONFIG_LCD_HX8357) += hx8357.o
+obj-$(CONFIG_LCD_ILI922X) += ili922x.o
obj-$(CONFIG_LCD_ILI9320) += ili9320.o
obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o
obj-$(CONFIG_LCD_LD9040) += ld9040.o
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index a1e41d4faa71..c84701b7ca6e 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -143,13 +143,16 @@ static int adp5520_bl_setup(struct backlight_device *bl)
static ssize_t adp5520_show(struct device *dev, char *buf, int reg)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
- int error;
+ int ret;
uint8_t reg_val;
mutex_lock(&data->lock);
- error = adp5520_read(data->master, reg, &reg_val);
+ ret = adp5520_read(data->master, reg, &reg_val);
mutex_unlock(&data->lock);
+ if (ret < 0)
+ return ret;
+
return sprintf(buf, "%u\n", reg_val);
}
@@ -349,35 +352,34 @@ static int adp5520_bl_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int adp5520_bl_suspend(struct platform_device *pdev,
- pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int adp5520_bl_suspend(struct device *dev)
{
- struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct backlight_device *bl = dev_get_drvdata(dev);
+
return adp5520_bl_set(bl, 0);
}
-static int adp5520_bl_resume(struct platform_device *pdev)
+static int adp5520_bl_resume(struct device *dev)
{
- struct backlight_device *bl = platform_get_drvdata(pdev);
+ struct backlight_device *bl = dev_get_drvdata(dev);
backlight_update_status(bl);
return 0;
}
-#else
-#define adp5520_bl_suspend NULL
-#define adp5520_bl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(adp5520_bl_pm_ops, adp5520_bl_suspend,
+ adp5520_bl_resume);
+
static struct platform_driver adp5520_bl_driver = {
.driver = {
.name = "adp5520-backlight",
.owner = THIS_MODULE,
+ .pm = &adp5520_bl_pm_ops,
},
.probe = adp5520_bl_probe,
.remove = adp5520_bl_remove,
- .suspend = adp5520_bl_suspend,
- .resume = adp5520_bl_resume,
};
module_platform_driver(adp5520_bl_driver);
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index a77c9cad3320..75b10f876127 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -249,12 +249,14 @@ static int adp8860_led_probe(struct i2c_client *client)
if (led_dat->id > 7 || led_dat->id < 1) {
dev_err(&client->dev, "Invalid LED ID %d\n",
led_dat->id);
+ ret = -EINVAL;
goto err;
}
if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
dev_err(&client->dev, "LED %d used by Backlight\n",
led_dat->id);
+ ret = -EBUSY;
goto err;
}
@@ -773,25 +775,29 @@ static int adp8860_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int adp8860_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
return 0;
}
-static int adp8860_i2c_resume(struct i2c_client *client)
+static int adp8860_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN);
return 0;
}
-#else
-#define adp8860_i2c_suspend NULL
-#define adp8860_i2c_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(adp8860_i2c_pm_ops, adp8860_i2c_suspend,
+ adp8860_i2c_resume);
+
static const struct i2c_device_id adp8860_id[] = {
{ "adp8860", adp8860 },
{ "adp8861", adp8861 },
@@ -802,12 +808,11 @@ MODULE_DEVICE_TABLE(i2c, adp8860_id);
static struct i2c_driver adp8860_driver = {
.driver = {
- .name = KBUILD_MODNAME,
+ .name = KBUILD_MODNAME,
+ .pm = &adp8860_i2c_pm_ops,
},
.probe = adp8860_probe,
.remove = adp8860_remove,
- .suspend = adp8860_i2c_suspend,
- .resume = adp8860_i2c_resume,
.id_table = adp8860_id,
};
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 712c25a0d8fe..90049d7b5c60 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -274,12 +274,14 @@ static int adp8870_led_probe(struct i2c_client *client)
if (led_dat->id > 7 || led_dat->id < 1) {
dev_err(&client->dev, "Invalid LED ID %d\n",
led_dat->id);
+ ret = -EINVAL;
goto err;
}
if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
dev_err(&client->dev, "LED %d used by Backlight\n",
led_dat->id);
+ ret = -EBUSY;
goto err;
}
@@ -895,13 +897,13 @@ static int adp8870_probe(struct i2c_client *client,
data->bl = bl;
- if (pdata->en_ambl_sens)
+ if (pdata->en_ambl_sens) {
ret = sysfs_create_group(&bl->dev.kobj,
&adp8870_bl_attr_group);
-
- if (ret) {
- dev_err(&client->dev, "failed to register sysfs\n");
- goto out1;
+ if (ret) {
+ dev_err(&client->dev, "failed to register sysfs\n");
+ goto out1;
+ }
}
ret = adp8870_bl_setup(bl);
@@ -947,25 +949,29 @@ static int adp8870_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message)
+#ifdef CONFIG_PM_SLEEP
+static int adp8870_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
adp8870_clr_bits(client, ADP8870_MDCR, NSTBY);
return 0;
}
-static int adp8870_i2c_resume(struct i2c_client *client)
+static int adp8870_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+
adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN);
return 0;
}
-#else
-#define adp8870_i2c_suspend NULL
-#define adp8870_i2c_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(adp8870_i2c_pm_ops, adp8870_i2c_suspend,
+ adp8870_i2c_resume);
+
static const struct i2c_device_id adp8870_id[] = {
{ "adp8870", 0 },
{ }
@@ -974,12 +980,11 @@ MODULE_DEVICE_TABLE(i2c, adp8870_id);
static struct i2c_driver adp8870_driver = {
.driver = {
- .name = KBUILD_MODNAME,
+ .name = KBUILD_MODNAME,
+ .pm = &adp8870_i2c_pm_ops,
},
.probe = adp8870_probe,
.remove = adp8870_remove,
- .suspend = adp8870_i2c_suspend,
- .resume = adp8870_i2c_resume,
.id_table = adp8870_id,
};
diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c
index c02aa2c2575a..319fef6cb422 100644
--- a/drivers/video/backlight/ams369fg06.c
+++ b/drivers/video/backlight/ams369fg06.c
@@ -533,12 +533,12 @@ static int ams369fg06_remove(struct spi_device *spi)
return 0;
}
-#if defined(CONFIG_PM)
-static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int ams369fg06_suspend(struct device *dev)
{
- struct ams369fg06 *lcd = spi_get_drvdata(spi);
+ struct ams369fg06 *lcd = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+ dev_dbg(dev, "lcd->power = %d\n", lcd->power);
/*
* when lcd panel is suspend, lcd panel becomes off
@@ -547,19 +547,19 @@ static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
return ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
}
-static int ams369fg06_resume(struct spi_device *spi)
+static int ams369fg06_resume(struct device *dev)
{
- struct ams369fg06 *lcd = spi_get_drvdata(spi);
+ struct ams369fg06 *lcd = dev_get_drvdata(dev);
lcd->power = FB_BLANK_POWERDOWN;
return ams369fg06_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define ams369fg06_suspend NULL
-#define ams369fg06_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ams369fg06_pm_ops, ams369fg06_suspend,
+ ams369fg06_resume);
+
static void ams369fg06_shutdown(struct spi_device *spi)
{
struct ams369fg06 *lcd = spi_get_drvdata(spi);
@@ -571,12 +571,11 @@ static struct spi_driver ams369fg06_driver = {
.driver = {
.name = "ams369fg06",
.owner = THIS_MODULE,
+ .pm = &ams369fg06_pm_ops,
},
.probe = ams369fg06_probe,
.remove = ams369fg06_remove,
.shutdown = ams369fg06_shutdown,
- .suspend = ams369fg06_suspend,
- .resume = ams369fg06_resume,
};
module_spi_driver(ams369fg06_driver);
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
index 41d52fe52543..123887cd76bd 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -258,6 +258,109 @@ static int as3711_bl_register(struct platform_device *pdev,
return 0;
}
+static int as3711_backlight_parse_dt(struct device *dev)
+{
+ struct as3711_bl_pdata *pdata = dev_get_platdata(dev);
+ struct device_node *bl =
+ of_find_node_by_name(dev->parent->of_node, "backlight"), *fb;
+ int ret;
+
+ if (!bl) {
+ dev_dbg(dev, "backlight node not found\n");
+ return -ENODEV;
+ }
+
+ fb = of_parse_phandle(bl, "su1-dev", 0);
+ if (fb) {
+ pdata->su1_fb = fb->full_name;
+
+ ret = of_property_read_u32(bl, "su1-max-uA", &pdata->su1_max_uA);
+ if (pdata->su1_max_uA <= 0)
+ ret = -EINVAL;
+ if (ret < 0)
+ return ret;
+ }
+
+ fb = of_parse_phandle(bl, "su2-dev", 0);
+ if (fb) {
+ int count = 0;
+
+ pdata->su2_fb = fb->full_name;
+
+ ret = of_property_read_u32(bl, "su2-max-uA", &pdata->su2_max_uA);
+ if (pdata->su2_max_uA <= 0)
+ ret = -EINVAL;
+ if (ret < 0)
+ return ret;
+
+ if (of_find_property(bl, "su2-feedback-voltage", NULL)) {
+ pdata->su2_feedback = AS3711_SU2_VOLTAGE;
+ count++;
+ }
+ if (of_find_property(bl, "su2-feedback-curr1", NULL)) {
+ pdata->su2_feedback = AS3711_SU2_CURR1;
+ count++;
+ }
+ if (of_find_property(bl, "su2-feedback-curr2", NULL)) {
+ pdata->su2_feedback = AS3711_SU2_CURR2;
+ count++;
+ }
+ if (of_find_property(bl, "su2-feedback-curr3", NULL)) {
+ pdata->su2_feedback = AS3711_SU2_CURR3;
+ count++;
+ }
+ if (of_find_property(bl, "su2-feedback-curr-auto", NULL)) {
+ pdata->su2_feedback = AS3711_SU2_CURR_AUTO;
+ count++;
+ }
+ if (count != 1)
+ return -EINVAL;
+
+ count = 0;
+ if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) {
+ pdata->su2_fbprot = AS3711_SU2_LX_SD4;
+ count++;
+ }
+ if (of_find_property(bl, "su2-fbprot-gpio2", NULL)) {
+ pdata->su2_fbprot = AS3711_SU2_GPIO2;
+ count++;
+ }
+ if (of_find_property(bl, "su2-fbprot-gpio3", NULL)) {
+ pdata->su2_fbprot = AS3711_SU2_GPIO3;
+ count++;
+ }
+ if (of_find_property(bl, "su2-fbprot-gpio4", NULL)) {
+ pdata->su2_fbprot = AS3711_SU2_GPIO4;
+ count++;
+ }
+ if (count != 1)
+ return -EINVAL;
+
+ count = 0;
+ if (of_find_property(bl, "su2-auto-curr1", NULL)) {
+ pdata->su2_auto_curr1 = true;
+ count++;
+ }
+ if (of_find_property(bl, "su2-auto-curr2", NULL)) {
+ pdata->su2_auto_curr2 = true;
+ count++;
+ }
+ if (of_find_property(bl, "su2-auto-curr3", NULL)) {
+ pdata->su2_auto_curr3 = true;
+ count++;
+ }
+
+ /*
+ * At least one su2-auto-curr* must be specified iff
+ * AS3711_SU2_CURR_AUTO is used
+ */
+ if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int as3711_backlight_probe(struct platform_device *pdev)
{
struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
@@ -267,11 +370,24 @@ static int as3711_backlight_probe(struct platform_device *pdev)
unsigned int max_brightness;
int ret;
- if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
+ if (!pdata) {
dev_err(&pdev->dev, "No platform data, exiting...\n");
return -ENODEV;
}
+ if (pdev->dev.parent->of_node) {
+ ret = as3711_backlight_parse_dt(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "DT parsing failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!pdata->su1_fb && !pdata->su2_fb) {
+ dev_err(&pdev->dev, "No framebuffer specified\n");
+ return -EINVAL;
+ }
+
/*
* Due to possible hardware damage I chose to block all modes,
* unsupported on my hardware. Anyone, wishing to use any of those modes
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index de5e5e74e2a7..a60d6afca97c 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -118,7 +118,7 @@ static const struct backlight_ops atmel_pwm_bl_ops = {
.update_status = atmel_pwm_bl_set_intensity,
};
-static int atmel_pwm_bl_probe(struct platform_device *pdev)
+static int __init atmel_pwm_bl_probe(struct platform_device *pdev)
{
struct backlight_properties props;
const struct atmel_pwm_bl_platform_data *pdata;
@@ -225,17 +225,7 @@ static struct platform_driver atmel_pwm_bl_driver = {
.remove = __exit_p(atmel_pwm_bl_remove),
};
-static int __init atmel_pwm_bl_init(void)
-{
- return platform_driver_probe(&atmel_pwm_bl_driver, atmel_pwm_bl_probe);
-}
-module_init(atmel_pwm_bl_init);
-
-static void __exit atmel_pwm_bl_exit(void)
-{
- platform_driver_unregister(&atmel_pwm_bl_driver);
-}
-module_exit(atmel_pwm_bl_exit);
+module_platform_driver_probe(atmel_pwm_bl_driver, atmel_pwm_bl_probe);
MODULE_AUTHOR("Hans-Christian egtvedt <hans-christian.egtvedt@atmel.com>");
MODULE_DESCRIPTION("Atmel PWM backlight driver");
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index aa782f302983..c97867a717a7 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -457,10 +457,10 @@ static const struct backlight_ops corgi_bl_ops = {
.update_status = corgi_bl_update_status,
};
-#ifdef CONFIG_PM
-static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int corgi_lcd_suspend(struct device *dev)
{
- struct corgi_lcd *lcd = spi_get_drvdata(spi);
+ struct corgi_lcd *lcd = dev_get_drvdata(dev);
corgibl_flags |= CORGIBL_SUSPENDED;
corgi_bl_set_intensity(lcd, 0);
@@ -468,20 +468,19 @@ static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
return 0;
}
-static int corgi_lcd_resume(struct spi_device *spi)
+static int corgi_lcd_resume(struct device *dev)
{
- struct corgi_lcd *lcd = spi_get_drvdata(spi);
+ struct corgi_lcd *lcd = dev_get_drvdata(dev);
corgibl_flags &= ~CORGIBL_SUSPENDED;
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
backlight_update_status(lcd->bl_dev);
return 0;
}
-#else
-#define corgi_lcd_suspend NULL
-#define corgi_lcd_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(corgi_lcd_pm_ops, corgi_lcd_suspend, corgi_lcd_resume);
+
static int setup_gpio_backlight(struct corgi_lcd *lcd,
struct corgi_lcd_platform_data *pdata)
{
@@ -611,11 +610,10 @@ static struct spi_driver corgi_lcd_driver = {
.driver = {
.name = "corgi-lcd",
.owner = THIS_MODULE,
+ .pm = &corgi_lcd_pm_ops,
},
.probe = corgi_lcd_probe,
.remove = corgi_lcd_remove,
- .suspend = corgi_lcd_suspend,
- .resume = corgi_lcd_resume,
};
module_spi_driver(corgi_lcd_driver);
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index 8179cef0730f..67cadd30e273 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -88,16 +88,21 @@ static int da903x_backlight_update_status(struct backlight_device *bl)
if (bl->props.fb_blank != FB_BLANK_UNBLANK)
brightness = 0;
+ if (bl->props.state & BL_CORE_SUSPENDED)
+ brightness = 0;
+
return da903x_backlight_set(bl, brightness);
}
static int da903x_backlight_get_brightness(struct backlight_device *bl)
{
struct da903x_backlight_data *data = bl_get_data(bl);
+
return data->current_brightness;
}
static const struct backlight_ops da903x_backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
.update_status = da903x_backlight_update_status,
.get_brightness = da903x_backlight_get_brightness,
};
@@ -161,35 +166,10 @@ static int da903x_backlight_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int da903x_backlight_suspend(struct device *dev)
-{
- struct backlight_device *bl = dev_get_drvdata(dev);
-
- return da903x_backlight_set(bl, 0);
-}
-
-static int da903x_backlight_resume(struct device *dev)
-{
- struct backlight_device *bl = dev_get_drvdata(dev);
-
- backlight_update_status(bl);
- return 0;
-}
-
-static const struct dev_pm_ops da903x_backlight_pm_ops = {
- .suspend = da903x_backlight_suspend,
- .resume = da903x_backlight_resume,
-};
-#endif
-
static struct platform_driver da903x_backlight_driver = {
.driver = {
.name = "da903x-backlight",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &da903x_backlight_pm_ops,
-#endif
},
.probe = da903x_backlight_probe,
.remove = da903x_backlight_remove,
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index ef3e21e8f825..33455821dd31 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -60,7 +60,7 @@ static const struct backlight_ops ep93xxbl_ops = {
.get_brightness = ep93xxbl_get_brightness,
};
-static int __init ep93xxbl_probe(struct platform_device *dev)
+static int ep93xxbl_probe(struct platform_device *dev)
{
struct ep93xxbl *ep93xxbl;
struct backlight_device *bl;
@@ -115,35 +115,33 @@ static int ep93xxbl_remove(struct platform_device *dev)
return 0;
}
-#ifdef CONFIG_PM
-static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ep93xxbl_suspend(struct device *dev)
{
- struct backlight_device *bl = platform_get_drvdata(dev);
+ struct backlight_device *bl = dev_get_drvdata(dev);
return ep93xxbl_set(bl, 0);
}
-static int ep93xxbl_resume(struct platform_device *dev)
+static int ep93xxbl_resume(struct device *dev)
{
- struct backlight_device *bl = platform_get_drvdata(dev);
+ struct backlight_device *bl = dev_get_drvdata(dev);
backlight_update_status(bl);
return 0;
}
-#else
-#define ep93xxbl_suspend NULL
-#define ep93xxbl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ep93xxbl_pm_ops, ep93xxbl_suspend, ep93xxbl_resume);
+
static struct platform_driver ep93xxbl_driver = {
.driver = {
.name = "ep93xx-bl",
.owner = THIS_MODULE,
+ .pm = &ep93xxbl_pm_ops,
},
.probe = ep93xxbl_probe,
.remove = ep93xxbl_remove,
- .suspend = ep93xxbl_suspend,
- .resume = ep93xxbl_resume,
};
module_platform_driver(ep93xxbl_driver);
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 0ae155be9c89..19e393b41438 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -9,8 +9,6 @@
*
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -108,7 +106,7 @@ static int genericbl_probe(struct platform_device *pdev)
generic_backlight_device = bd;
- pr_info("Generic Backlight Driver Initialized.\n");
+ dev_info(&pdev->dev, "Generic Backlight Driver Initialized.\n");
return 0;
}
@@ -122,7 +120,7 @@ static int genericbl_remove(struct platform_device *pdev)
backlight_device_unregister(bd);
- pr_info("Generic Backlight Driver Unloaded\n");
+ dev_info(&pdev->dev, "Generic Backlight Driver Unloaded\n");
return 0;
}
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 5cefd73526f8..00076ecfe9b8 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -64,29 +64,28 @@ static void hp680bl_send_intensity(struct backlight_device *bd)
}
-#ifdef CONFIG_PM
-static int hp680bl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int hp680bl_suspend(struct device *dev)
{
- struct backlight_device *bd = platform_get_drvdata(pdev);
+ struct backlight_device *bd = dev_get_drvdata(dev);
hp680bl_suspended = 1;
hp680bl_send_intensity(bd);
return 0;
}
-static int hp680bl_resume(struct platform_device *pdev)
+static int hp680bl_resume(struct device *dev)
{
- struct backlight_device *bd = platform_get_drvdata(pdev);
+ struct backlight_device *bd = dev_get_drvdata(dev);
hp680bl_suspended = 0;
hp680bl_send_intensity(bd);
return 0;
}
-#else
-#define hp680bl_suspend NULL
-#define hp680bl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(hp680bl_pm_ops, hp680bl_suspend, hp680bl_resume);
+
static int hp680bl_set_intensity(struct backlight_device *bd)
{
hp680bl_send_intensity(bd);
@@ -140,10 +139,9 @@ static int hp680bl_remove(struct platform_device *pdev)
static struct platform_driver hp680bl_driver = {
.probe = hp680bl_probe,
.remove = hp680bl_remove,
- .suspend = hp680bl_suspend,
- .resume = hp680bl_resume,
.driver = {
.name = "hp680-bl",
+ .pm = &hp680bl_pm_ops,
},
};
diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c
new file mode 100644
index 000000000000..d9f65c2d9b01
--- /dev/null
+++ b/drivers/video/backlight/ili922x.c
@@ -0,0 +1,555 @@
+/*
+ * (C) Copyright 2008
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This driver implements a lcd device for the ILITEK 922x display
+ * controller. The interface to the display is SPI and the display's
+ * memory is cyclically updated over the RGB interface.
+ */
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/string.h>
+
+/* Register offset, see manual section 8.2 */
+#define REG_START_OSCILLATION 0x00
+#define REG_DRIVER_CODE_READ 0x00
+#define REG_DRIVER_OUTPUT_CONTROL 0x01
+#define REG_LCD_AC_DRIVEING_CONTROL 0x02
+#define REG_ENTRY_MODE 0x03
+#define REG_COMPARE_1 0x04
+#define REG_COMPARE_2 0x05
+#define REG_DISPLAY_CONTROL_1 0x07
+#define REG_DISPLAY_CONTROL_2 0x08
+#define REG_DISPLAY_CONTROL_3 0x09
+#define REG_FRAME_CYCLE_CONTROL 0x0B
+#define REG_EXT_INTF_CONTROL 0x0C
+#define REG_POWER_CONTROL_1 0x10
+#define REG_POWER_CONTROL_2 0x11
+#define REG_POWER_CONTROL_3 0x12
+#define REG_POWER_CONTROL_4 0x13
+#define REG_RAM_ADDRESS_SET 0x21
+#define REG_WRITE_DATA_TO_GRAM 0x22
+#define REG_RAM_WRITE_MASK1 0x23
+#define REG_RAM_WRITE_MASK2 0x24
+#define REG_GAMMA_CONTROL_1 0x30
+#define REG_GAMMA_CONTROL_2 0x31
+#define REG_GAMMA_CONTROL_3 0x32
+#define REG_GAMMA_CONTROL_4 0x33
+#define REG_GAMMA_CONTROL_5 0x34
+#define REG_GAMMA_CONTROL_6 0x35
+#define REG_GAMMA_CONTROL_7 0x36
+#define REG_GAMMA_CONTROL_8 0x37
+#define REG_GAMMA_CONTROL_9 0x38
+#define REG_GAMMA_CONTROL_10 0x39
+#define REG_GATE_SCAN_CONTROL 0x40
+#define REG_VERT_SCROLL_CONTROL 0x41
+#define REG_FIRST_SCREEN_DRIVE_POS 0x42
+#define REG_SECOND_SCREEN_DRIVE_POS 0x43
+#define REG_RAM_ADDR_POS_H 0x44
+#define REG_RAM_ADDR_POS_V 0x45
+#define REG_OSCILLATOR_CONTROL 0x4F
+#define REG_GPIO 0x60
+#define REG_OTP_VCM_PROGRAMMING 0x61
+#define REG_OTP_VCM_STATUS_ENABLE 0x62
+#define REG_OTP_PROGRAMMING_ID_KEY 0x65
+
+/*
+ * maximum frequency for register access
+ * (not for the GRAM access)
+ */
+#define ILITEK_MAX_FREQ_REG 4000000
+
+/*
+ * Device ID as found in the datasheet (supports 9221 and 9222)
+ */
+#define ILITEK_DEVICE_ID 0x9220
+#define ILITEK_DEVICE_ID_MASK 0xFFF0
+
+/* Last two bits in the START BYTE */
+#define START_RS_INDEX 0
+#define START_RS_REG 1
+#define START_RW_WRITE 0
+#define START_RW_READ 1
+
+/**
+ * START_BYTE(id, rs, rw)
+ *
+ * Set the start byte according to the required operation.
+ * The start byte is defined as:
+ * ----------------------------------
+ * | 0 | 1 | 1 | 1 | 0 | ID | RS | RW |
+ * ----------------------------------
+ * @id: display's id as set by the manufacturer
+ * @rs: operation type bit, one of:
+ * - START_RS_INDEX set the index register
+ * - START_RS_REG write/read registers/GRAM
+ * @rw: read/write operation
+ * - START_RW_WRITE write
+ * - START_RW_READ read
+ */
+#define START_BYTE(id, rs, rw) \
+ (0x70 | (((id) & 0x01) << 2) | (((rs) & 0x01) << 1) | ((rw) & 0x01))
+
+/**
+ * CHECK_FREQ_REG(spi_device s, spi_transfer x) - Check the frequency
+ * for the SPI transfer. According to the datasheet, the controller
+ * accept higher frequency for the GRAM transfer, but it requires
+ * lower frequency when the registers are read/written.
+ * The macro sets the frequency in the spi_transfer structure if
+ * the frequency exceeds the maximum value.
+ */
+#define CHECK_FREQ_REG(s, x) \
+ do { \
+ if (s->max_speed_hz > ILITEK_MAX_FREQ_REG) \
+ ((struct spi_transfer *)x)->speed_hz = \
+ ILITEK_MAX_FREQ_REG; \
+ } while (0)
+
+#define CMD_BUFSIZE 16
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+#define set_tx_byte(b) (tx_invert ? ~(b) : b)
+
+/**
+ * ili922x_id - id as set by manufacturer
+ */
+static int ili922x_id = 1;
+module_param(ili922x_id, int, 0);
+
+static int tx_invert;
+module_param(tx_invert, int, 0);
+
+/**
+ * driver's private structure
+ */
+struct ili922x {
+ struct spi_device *spi;
+ struct lcd_device *ld;
+ int power;
+};
+
+/**
+ * ili922x_read_status - read status register from display
+ * @spi: spi device
+ * @rs: output value
+ */
+static int ili922x_read_status(struct spi_device *spi, u16 *rs)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ unsigned char tbuf[CMD_BUFSIZE];
+ unsigned char rbuf[CMD_BUFSIZE];
+ int ret, i;
+
+ memset(&xfer, 0, sizeof(struct spi_transfer));
+ spi_message_init(&msg);
+ xfer.tx_buf = tbuf;
+ xfer.rx_buf = rbuf;
+ xfer.cs_change = 1;
+ CHECK_FREQ_REG(spi, &xfer);
+
+ tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX,
+ START_RW_READ));
+ /*
+ * we need 4-byte xfer here due to invalid dummy byte
+ * received after start byte
+ */
+ for (i = 1; i < 4; i++)
+ tbuf[i] = set_tx_byte(0); /* dummy */
+
+ xfer.bits_per_word = 8;
+ xfer.len = 4;
+ spi_message_add_tail(&xfer, &msg);
+ ret = spi_sync(spi, &msg);
+ if (ret < 0) {
+ dev_dbg(&spi->dev, "Error sending SPI message 0x%x", ret);
+ return ret;
+ }
+
+ *rs = (rbuf[2] << 8) + rbuf[3];
+ return 0;
+}
+
+/**
+ * ili922x_read - read register from display
+ * @spi: spi device
+ * @reg: offset of the register to be read
+ * @rx: output value
+ */
+static int ili922x_read(struct spi_device *spi, u8 reg, u16 *rx)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer_regindex, xfer_regvalue;
+ unsigned char tbuf[CMD_BUFSIZE];
+ unsigned char rbuf[CMD_BUFSIZE];
+ int ret, len = 0, send_bytes;
+
+ memset(&xfer_regindex, 0, sizeof(struct spi_transfer));
+ memset(&xfer_regvalue, 0, sizeof(struct spi_transfer));
+ spi_message_init(&msg);
+ xfer_regindex.tx_buf = tbuf;
+ xfer_regindex.rx_buf = rbuf;
+ xfer_regindex.cs_change = 1;
+ CHECK_FREQ_REG(spi, &xfer_regindex);
+
+ tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX,
+ START_RW_WRITE));
+ tbuf[1] = set_tx_byte(0);
+ tbuf[2] = set_tx_byte(reg);
+ xfer_regindex.bits_per_word = 8;
+ len = xfer_regindex.len = 3;
+ spi_message_add_tail(&xfer_regindex, &msg);
+
+ send_bytes = len;
+
+ tbuf[len++] = set_tx_byte(START_BYTE(ili922x_id, START_RS_REG,
+ START_RW_READ));
+ tbuf[len++] = set_tx_byte(0);
+ tbuf[len] = set_tx_byte(0);
+
+ xfer_regvalue.cs_change = 1;
+ xfer_regvalue.len = 3;
+ xfer_regvalue.tx_buf = &tbuf[send_bytes];
+ xfer_regvalue.rx_buf = &rbuf[send_bytes];
+ CHECK_FREQ_REG(spi, &xfer_regvalue);
+
+ spi_message_add_tail(&xfer_regvalue, &msg);
+ ret = spi_sync(spi, &msg);
+ if (ret < 0) {
+ dev_dbg(&spi->dev, "Error sending SPI message 0x%x", ret);
+ return ret;
+ }
+
+ *rx = (rbuf[1 + send_bytes] << 8) + rbuf[2 + send_bytes];
+ return 0;
+}
+
+/**
+ * ili922x_write - write a controller register
+ * @spi: struct spi_device *
+ * @reg: offset of the register to be written
+ * @value: value to be written
+ */
+static int ili922x_write(struct spi_device *spi, u8 reg, u16 value)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer_regindex, xfer_regvalue;
+ unsigned char tbuf[CMD_BUFSIZE];
+ unsigned char rbuf[CMD_BUFSIZE];
+ int ret, len = 0;
+
+ memset(&xfer_regindex, 0, sizeof(struct spi_transfer));
+ memset(&xfer_regvalue, 0, sizeof(struct spi_transfer));
+
+ spi_message_init(&msg);
+ xfer_regindex.tx_buf = tbuf;
+ xfer_regindex.rx_buf = rbuf;
+ xfer_regindex.cs_change = 1;
+ CHECK_FREQ_REG(spi, &xfer_regindex);
+
+ tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_INDEX,
+ START_RW_WRITE));
+ tbuf[1] = set_tx_byte(0);
+ tbuf[2] = set_tx_byte(reg);
+ xfer_regindex.bits_per_word = 8;
+ xfer_regindex.len = 3;
+ spi_message_add_tail(&xfer_regindex, &msg);
+
+ ret = spi_sync(spi, &msg);
+
+ spi_message_init(&msg);
+ len = 0;
+ tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_REG,
+ START_RW_WRITE));
+ tbuf[1] = set_tx_byte((value & 0xFF00) >> 8);
+ tbuf[2] = set_tx_byte(value & 0x00FF);
+
+ xfer_regvalue.cs_change = 1;
+ xfer_regvalue.len = 3;
+ xfer_regvalue.tx_buf = tbuf;
+ xfer_regvalue.rx_buf = rbuf;
+ CHECK_FREQ_REG(spi, &xfer_regvalue);
+
+ spi_message_add_tail(&xfer_regvalue, &msg);
+
+ ret = spi_sync(spi, &msg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Error sending SPI message 0x%x", ret);
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef DEBUG
+/**
+ * ili922x_reg_dump - dump all registers
+ */
+static void ili922x_reg_dump(struct spi_device *spi)
+{
+ u8 reg;
+ u16 rx;
+
+ dev_dbg(&spi->dev, "ILI922x configuration registers:\n");
+ for (reg = REG_START_OSCILLATION;
+ reg <= REG_OTP_PROGRAMMING_ID_KEY; reg++) {
+ ili922x_read(spi, reg, &rx);
+ dev_dbg(&spi->dev, "reg @ 0x%02X: 0x%04X\n", reg, rx);
+ }
+}
+#else
+static inline void ili922x_reg_dump(struct spi_device *spi) {}
+#endif
+
+/**
+ * set_write_to_gram_reg - initialize the display to write the GRAM
+ * @spi: spi device
+ */
+static void set_write_to_gram_reg(struct spi_device *spi)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ unsigned char tbuf[CMD_BUFSIZE];
+
+ memset(&xfer, 0, sizeof(struct spi_transfer));
+
+ spi_message_init(&msg);
+ xfer.tx_buf = tbuf;
+ xfer.rx_buf = NULL;
+ xfer.cs_change = 1;
+
+ tbuf[0] = START_BYTE(ili922x_id, START_RS_INDEX, START_RW_WRITE);
+ tbuf[1] = 0;
+ tbuf[2] = REG_WRITE_DATA_TO_GRAM;
+
+ xfer.bits_per_word = 8;
+ xfer.len = 3;
+ spi_message_add_tail(&xfer, &msg);
+ spi_sync(spi, &msg);
+}
+
+/**
+ * ili922x_poweron - turn the display on
+ * @spi: spi device
+ *
+ * The sequence to turn on the display is taken from
+ * the datasheet and/or the example code provided by the
+ * manufacturer.
+ */
+static int ili922x_poweron(struct spi_device *spi)
+{
+ int ret;
+
+ /* Power on */
+ ret = ili922x_write(spi, REG_POWER_CONTROL_1, 0x0000);
+ usleep_range(10000, 10500);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0000);
+ msleep(40);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x0000);
+ msleep(40);
+ /* register 0x56 is not documented in the datasheet */
+ ret += ili922x_write(spi, 0x56, 0x080F);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_1, 0x4240);
+ usleep_range(10000, 10500);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0014);
+ msleep(40);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x1319);
+ msleep(40);
+
+ return ret;
+}
+
+/**
+ * ili922x_poweroff - turn the display off
+ * @spi: spi device
+ */
+static int ili922x_poweroff(struct spi_device *spi)
+{
+ int ret;
+
+ /* Power off */
+ ret = ili922x_write(spi, REG_POWER_CONTROL_1, 0x0000);
+ usleep_range(10000, 10500);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_2, 0x0000);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_3, 0x0000);
+ msleep(40);
+ ret += ili922x_write(spi, REG_POWER_CONTROL_4, 0x0000);
+ msleep(40);
+
+ return ret;
+}
+
+/**
+ * ili922x_display_init - initialize the display by setting
+ * the configuration registers
+ * @spi: spi device
+ */
+static void ili922x_display_init(struct spi_device *spi)
+{
+ ili922x_write(spi, REG_START_OSCILLATION, 1);
+ usleep_range(10000, 10500);
+ ili922x_write(spi, REG_DRIVER_OUTPUT_CONTROL, 0x691B);
+ ili922x_write(spi, REG_LCD_AC_DRIVEING_CONTROL, 0x0700);
+ ili922x_write(spi, REG_ENTRY_MODE, 0x1030);
+ ili922x_write(spi, REG_COMPARE_1, 0x0000);
+ ili922x_write(spi, REG_COMPARE_2, 0x0000);
+ ili922x_write(spi, REG_DISPLAY_CONTROL_1, 0x0037);
+ ili922x_write(spi, REG_DISPLAY_CONTROL_2, 0x0202);
+ ili922x_write(spi, REG_DISPLAY_CONTROL_3, 0x0000);
+ ili922x_write(spi, REG_FRAME_CYCLE_CONTROL, 0x0000);
+
+ /* Set RGB interface */
+ ili922x_write(spi, REG_EXT_INTF_CONTROL, 0x0110);
+
+ ili922x_poweron(spi);
+
+ ili922x_write(spi, REG_GAMMA_CONTROL_1, 0x0302);
+ ili922x_write(spi, REG_GAMMA_CONTROL_2, 0x0407);
+ ili922x_write(spi, REG_GAMMA_CONTROL_3, 0x0304);
+ ili922x_write(spi, REG_GAMMA_CONTROL_4, 0x0203);
+ ili922x_write(spi, REG_GAMMA_CONTROL_5, 0x0706);
+ ili922x_write(spi, REG_GAMMA_CONTROL_6, 0x0407);
+ ili922x_write(spi, REG_GAMMA_CONTROL_7, 0x0706);
+ ili922x_write(spi, REG_GAMMA_CONTROL_8, 0x0000);
+ ili922x_write(spi, REG_GAMMA_CONTROL_9, 0x0C06);
+ ili922x_write(spi, REG_GAMMA_CONTROL_10, 0x0F00);
+ ili922x_write(spi, REG_RAM_ADDRESS_SET, 0x0000);
+ ili922x_write(spi, REG_GATE_SCAN_CONTROL, 0x0000);
+ ili922x_write(spi, REG_VERT_SCROLL_CONTROL, 0x0000);
+ ili922x_write(spi, REG_FIRST_SCREEN_DRIVE_POS, 0xDB00);
+ ili922x_write(spi, REG_SECOND_SCREEN_DRIVE_POS, 0xDB00);
+ ili922x_write(spi, REG_RAM_ADDR_POS_H, 0xAF00);
+ ili922x_write(spi, REG_RAM_ADDR_POS_V, 0xDB00);
+ ili922x_reg_dump(spi);
+ set_write_to_gram_reg(spi);
+}
+
+static int ili922x_lcd_power(struct ili922x *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = ili922x_poweron(lcd->spi);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = ili922x_poweroff(lcd->spi);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int ili922x_set_power(struct lcd_device *ld, int power)
+{
+ struct ili922x *ili = lcd_get_data(ld);
+
+ return ili922x_lcd_power(ili, power);
+}
+
+static int ili922x_get_power(struct lcd_device *ld)
+{
+ struct ili922x *ili = lcd_get_data(ld);
+
+ return ili->power;
+}
+
+static struct lcd_ops ili922x_ops = {
+ .get_power = ili922x_get_power,
+ .set_power = ili922x_set_power,
+};
+
+static int ili922x_probe(struct spi_device *spi)
+{
+ struct ili922x *ili;
+ struct lcd_device *lcd;
+ int ret;
+ u16 reg = 0;
+
+ ili = devm_kzalloc(&spi->dev, sizeof(*ili), GFP_KERNEL);
+ if (!ili) {
+ dev_err(&spi->dev, "cannot alloc priv data\n");
+ return -ENOMEM;
+ }
+
+ ili->spi = spi;
+ spi_set_drvdata(spi, ili);
+
+ /* check if the device is connected */
+ ret = ili922x_read(spi, REG_DRIVER_CODE_READ, &reg);
+ if (ret || ((reg & ILITEK_DEVICE_ID_MASK) != ILITEK_DEVICE_ID)) {
+ dev_err(&spi->dev,
+ "no LCD found: Chip ID 0x%x, ret %d\n",
+ reg, ret);
+ return -ENODEV;
+ } else {
+ dev_info(&spi->dev, "ILI%x found, SPI freq %d, mode %d\n",
+ reg, spi->max_speed_hz, spi->mode);
+ }
+
+ ret = ili922x_read_status(spi, &reg);
+ if (ret) {
+ dev_err(&spi->dev, "reading RS failed...\n");
+ return ret;
+ } else
+ dev_dbg(&spi->dev, "status: 0x%x\n", reg);
+
+ ili922x_display_init(spi);
+
+ ili->power = FB_BLANK_POWERDOWN;
+
+ lcd = lcd_device_register("ili922xlcd", &spi->dev, ili,
+ &ili922x_ops);
+ if (IS_ERR(lcd)) {
+ dev_err(&spi->dev, "cannot register LCD\n");
+ return PTR_ERR(lcd);
+ }
+
+ ili->ld = lcd;
+ spi_set_drvdata(spi, ili);
+
+ ili922x_lcd_power(ili, FB_BLANK_UNBLANK);
+
+ return 0;
+}
+
+static int ili922x_remove(struct spi_device *spi)
+{
+ struct ili922x *ili = spi_get_drvdata(spi);
+
+ ili922x_poweroff(spi);
+ lcd_device_unregister(ili->ld);
+ return 0;
+}
+
+static struct spi_driver ili922x_driver = {
+ .driver = {
+ .name = "ili922x",
+ .owner = THIS_MODULE,
+ },
+ .probe = ili922x_probe,
+ .remove = ili922x_remove,
+};
+
+module_spi_driver(ili922x_driver);
+
+MODULE_AUTHOR("Stefano Babic <sbabic@denx.de>");
+MODULE_DESCRIPTION("ILI9221/9222 LCD driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(ili922x_id, "set controller identifier (default=1)");
+MODULE_PARM_DESC(tx_invert, "invert bytes before sending");
diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c
index 1235bf9defc4..f8be90c5dedc 100644
--- a/drivers/video/backlight/ili9320.c
+++ b/drivers/video/backlight/ili9320.c
@@ -231,7 +231,7 @@ int ili9320_probe_spi(struct spi_device *spi,
ili->power = FB_BLANK_POWERDOWN;
ili->platdata = cfg;
- dev_set_drvdata(&spi->dev, ili);
+ spi_set_drvdata(spi, ili);
ili9320_setup_spi(ili, spi);
@@ -270,27 +270,21 @@ int ili9320_remove(struct ili9320 *ili)
}
EXPORT_SYMBOL_GPL(ili9320_remove);
-#ifdef CONFIG_PM
-int ili9320_suspend(struct ili9320 *lcd, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+int ili9320_suspend(struct ili9320 *lcd)
{
int ret;
- dev_dbg(lcd->dev, "%s: event %d\n", __func__, state.event);
+ ret = ili9320_power(lcd, FB_BLANK_POWERDOWN);
- if (state.event == PM_EVENT_SUSPEND) {
- ret = ili9320_power(lcd, FB_BLANK_POWERDOWN);
-
- if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
- ili9320_write(lcd, ILI9320_POWER1, lcd->power1 |
- ILI9320_POWER1_SLP |
- ILI9320_POWER1_DSTB);
- lcd->initialised = 0;
- }
-
- return ret;
+ if (lcd->platdata->suspend == ILI9320_SUSPEND_DEEP) {
+ ili9320_write(lcd, ILI9320_POWER1, lcd->power1 |
+ ILI9320_POWER1_SLP |
+ ILI9320_POWER1_DSTB);
+ lcd->initialised = 0;
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(ili9320_suspend);
diff --git a/drivers/video/backlight/ili9320.h b/drivers/video/backlight/ili9320.h
index e0db738f7bb9..42329e7aa9a8 100644
--- a/drivers/video/backlight/ili9320.h
+++ b/drivers/video/backlight/ili9320.h
@@ -76,5 +76,5 @@ extern void ili9320_shutdown(struct ili9320 *lcd);
/* PM */
-extern int ili9320_suspend(struct ili9320 *lcd, pm_message_t state);
+extern int ili9320_suspend(struct ili9320 *lcd);
extern int ili9320_resume(struct ili9320 *lcd);
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index fef6ce4fad71..3ccb89340f22 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -9,8 +9,6 @@
*
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/backlight.h>
#include <linux/device.h>
#include <linux/fb.h>
@@ -40,11 +38,13 @@ static int jornada_bl_get_brightness(struct backlight_device *bd)
ret = jornada_ssp_byte(GETBRIGHTNESS);
if (jornada_ssp_byte(GETBRIGHTNESS) != TXDUMMY) {
- pr_err("get brightness timeout\n");
+ dev_err(&bd->dev, "get brightness timeout\n");
jornada_ssp_end();
return -ETIMEDOUT;
- } else /* exchange txdummy for value */
+ } else {
+ /* exchange txdummy for value */
ret = jornada_ssp_byte(TXDUMMY);
+ }
jornada_ssp_end();
@@ -61,7 +61,7 @@ static int jornada_bl_update_status(struct backlight_device *bd)
if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
ret = jornada_ssp_byte(BRIGHTNESSOFF);
if (ret != TXDUMMY) {
- pr_info("brightness off timeout\n");
+ dev_info(&bd->dev, "brightness off timeout\n");
/* turn off backlight */
PPSR &= ~PPC_LDD1;
PPDR |= PPC_LDD1;
@@ -72,7 +72,7 @@ static int jornada_bl_update_status(struct backlight_device *bd)
/* send command to our mcu */
if (jornada_ssp_byte(SETBRIGHTNESS) != TXDUMMY) {
- pr_info("failed to set brightness\n");
+ dev_info(&bd->dev, "failed to set brightness\n");
ret = -ETIMEDOUT;
goto out;
}
@@ -86,7 +86,7 @@ static int jornada_bl_update_status(struct backlight_device *bd)
*/
if (jornada_ssp_byte(BL_MAX_BRIGHT - bd->props.brightness)
!= TXDUMMY) {
- pr_err("set brightness failed\n");
+ dev_err(&bd->dev, "set brightness failed\n");
ret = -ETIMEDOUT;
}
@@ -120,7 +120,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
if (IS_ERR(bd)) {
ret = PTR_ERR(bd);
- pr_err("failed to register device, err=%x\n", ret);
+ dev_err(&pdev->dev, "failed to register device, err=%x\n", ret);
return ret;
}
@@ -134,7 +134,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
jornada_bl_update_status(bd);
platform_set_drvdata(pdev, bd);
- pr_info("HP Jornada 700 series backlight driver\n");
+ dev_info(&pdev->dev, "HP Jornada 700 series backlight driver\n");
return 0;
}
diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c
index 635b30523fd5..b061413f1a65 100644
--- a/drivers/video/backlight/jornada720_lcd.c
+++ b/drivers/video/backlight/jornada720_lcd.c
@@ -9,8 +9,6 @@
*
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/kernel.h>
@@ -27,7 +25,7 @@
#define LCD_MAX_CONTRAST 0xff
#define LCD_DEF_CONTRAST 0x80
-static int jornada_lcd_get_power(struct lcd_device *dev)
+static int jornada_lcd_get_power(struct lcd_device *ld)
{
/* LDD2 in PPC = LCD POWER */
if (PPSR & PPC_LDD2)
@@ -36,17 +34,17 @@ static int jornada_lcd_get_power(struct lcd_device *dev)
return FB_BLANK_POWERDOWN; /* PW OFF */
}
-static int jornada_lcd_get_contrast(struct lcd_device *dev)
+static int jornada_lcd_get_contrast(struct lcd_device *ld)
{
int ret;
- if (jornada_lcd_get_power(dev) != FB_BLANK_UNBLANK)
+ if (jornada_lcd_get_power(ld) != FB_BLANK_UNBLANK)
return 0;
jornada_ssp_start();
if (jornada_ssp_byte(GETCONTRAST) != TXDUMMY) {
- pr_err("get contrast failed\n");
+ dev_err(&ld->dev, "get contrast failed\n");
jornada_ssp_end();
return -ETIMEDOUT;
} else {
@@ -56,7 +54,7 @@ static int jornada_lcd_get_contrast(struct lcd_device *dev)
}
}
-static int jornada_lcd_set_contrast(struct lcd_device *dev, int value)
+static int jornada_lcd_set_contrast(struct lcd_device *ld, int value)
{
int ret;
@@ -67,7 +65,7 @@ static int jornada_lcd_set_contrast(struct lcd_device *dev, int value)
/* push the new value */
if (jornada_ssp_byte(value) != TXDUMMY) {
- pr_err("set contrast failed\n");
+ dev_err(&ld->dev, "set contrast failed\n");
jornada_ssp_end();
return -ETIMEDOUT;
}
@@ -78,13 +76,14 @@ static int jornada_lcd_set_contrast(struct lcd_device *dev, int value)
return 0;
}
-static int jornada_lcd_set_power(struct lcd_device *dev, int power)
+static int jornada_lcd_set_power(struct lcd_device *ld, int power)
{
if (power != FB_BLANK_UNBLANK) {
PPSR &= ~PPC_LDD2;
PPDR |= PPC_LDD2;
- } else
+ } else {
PPSR |= PPC_LDD2;
+ }
return 0;
}
@@ -105,7 +104,7 @@ static int jornada_lcd_probe(struct platform_device *pdev)
if (IS_ERR(lcd_device)) {
ret = PTR_ERR(lcd_device);
- pr_err("failed to register device\n");
+ dev_err(&pdev->dev, "failed to register device\n");
return ret;
}
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index 6c5ed6b242cc..bca6ccc74dfb 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -106,29 +106,28 @@ static int kb3886bl_send_intensity(struct backlight_device *bd)
return 0;
}
-#ifdef CONFIG_PM
-static int kb3886bl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int kb3886bl_suspend(struct device *dev)
{
- struct backlight_device *bd = platform_get_drvdata(pdev);
+ struct backlight_device *bd = dev_get_drvdata(dev);
kb3886bl_flags |= KB3886BL_SUSPENDED;
backlight_update_status(bd);
return 0;
}
-static int kb3886bl_resume(struct platform_device *pdev)
+static int kb3886bl_resume(struct device *dev)
{
- struct backlight_device *bd = platform_get_drvdata(pdev);
+ struct backlight_device *bd = dev_get_drvdata(dev);
kb3886bl_flags &= ~KB3886BL_SUSPENDED;
backlight_update_status(bd);
return 0;
}
-#else
-#define kb3886bl_suspend NULL
-#define kb3886bl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(kb3886bl_pm_ops, kb3886bl_suspend, kb3886bl_resume);
+
static int kb3886bl_get_intensity(struct backlight_device *bd)
{
return kb3886bl_intensity;
@@ -179,10 +178,9 @@ static int kb3886bl_remove(struct platform_device *pdev)
static struct platform_driver kb3886bl_driver = {
.probe = kb3886bl_probe,
.remove = kb3886bl_remove,
- .suspend = kb3886bl_suspend,
- .resume = kb3886bl_resume,
.driver = {
.name = "kb3886-bl",
+ .pm = &kb3886bl_pm_ops,
},
};
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index fb6155771326..a35a38c709cf 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -51,14 +51,33 @@ static void l4f00242t03_lcd_init(struct spi_device *spi)
struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
+ int ret;
dev_dbg(&spi->dev, "initializing LCD\n");
- regulator_set_voltage(priv->io_reg, 1800000, 1800000);
- regulator_enable(priv->io_reg);
+ ret = regulator_set_voltage(priv->io_reg, 1800000, 1800000);
+ if (ret) {
+ dev_err(&spi->dev, "failed to set the IO regulator voltage.\n");
+ return;
+ }
+ ret = regulator_enable(priv->io_reg);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable the IO regulator.\n");
+ return;
+ }
- regulator_set_voltage(priv->core_reg, 2800000, 2800000);
- regulator_enable(priv->core_reg);
+ ret = regulator_set_voltage(priv->core_reg, 2800000, 2800000);
+ if (ret) {
+ dev_err(&spi->dev, "failed to set the core regulator voltage.\n");
+ regulator_disable(priv->io_reg);
+ return;
+ }
+ ret = regulator_enable(priv->core_reg);
+ if (ret) {
+ dev_err(&spi->dev, "failed to enable the core regulator.\n");
+ regulator_disable(priv->io_reg);
+ return;
+ }
l4f00242t03_reset(pdata->reset_gpio);
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c
index 1b642f5f381a..1e0a3093ce50 100644
--- a/drivers/video/backlight/ld9040.c
+++ b/drivers/video/backlight/ld9040.c
@@ -775,12 +775,12 @@ static int ld9040_remove(struct spi_device *spi)
return 0;
}
-#if defined(CONFIG_PM)
-static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int ld9040_suspend(struct device *dev)
{
- struct ld9040 *lcd = spi_get_drvdata(spi);
+ struct ld9040 *lcd = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+ dev_dbg(dev, "lcd->power = %d\n", lcd->power);
/*
* when lcd panel is suspend, lcd panel becomes off
@@ -789,19 +789,18 @@ static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
return ld9040_power(lcd, FB_BLANK_POWERDOWN);
}
-static int ld9040_resume(struct spi_device *spi)
+static int ld9040_resume(struct device *dev)
{
- struct ld9040 *lcd = spi_get_drvdata(spi);
+ struct ld9040 *lcd = dev_get_drvdata(dev);
lcd->power = FB_BLANK_POWERDOWN;
return ld9040_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define ld9040_suspend NULL
-#define ld9040_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ld9040_pm_ops, ld9040_suspend, ld9040_resume);
+
/* Power down all displays on reboot, poweroff or halt. */
static void ld9040_shutdown(struct spi_device *spi)
{
@@ -814,12 +813,11 @@ static struct spi_driver ld9040_driver = {
.driver = {
.name = "ld9040",
.owner = THIS_MODULE,
+ .pm = &ld9040_pm_ops,
},
.probe = ld9040_probe,
.remove = ld9040_remove,
.shutdown = ld9040_shutdown,
- .suspend = ld9040_suspend,
- .resume = ld9040_resume,
};
module_spi_driver(ld9040_driver);
diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c
index 5d18d4d7f470..1d1dbfb789e3 100644
--- a/drivers/video/backlight/lm3533_bl.c
+++ b/drivers/video/backlight/lm3533_bl.c
@@ -368,29 +368,28 @@ static int lm3533_bl_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int lm3533_bl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int lm3533_bl_suspend(struct device *dev)
{
- struct lm3533_bl *bl = platform_get_drvdata(pdev);
+ struct lm3533_bl *bl = dev_get_drvdata(dev);
- dev_dbg(&pdev->dev, "%s\n", __func__);
+ dev_dbg(dev, "%s\n", __func__);
return lm3533_ctrlbank_disable(&bl->cb);
}
-static int lm3533_bl_resume(struct platform_device *pdev)
+static int lm3533_bl_resume(struct device *dev)
{
- struct lm3533_bl *bl = platform_get_drvdata(pdev);
+ struct lm3533_bl *bl = dev_get_drvdata(dev);
- dev_dbg(&pdev->dev, "%s\n", __func__);
+ dev_dbg(dev, "%s\n", __func__);
return lm3533_ctrlbank_enable(&bl->cb);
}
-#else
-#define lm3533_bl_suspend NULL
-#define lm3533_bl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(lm3533_bl_pm_ops, lm3533_bl_suspend, lm3533_bl_resume);
+
static void lm3533_bl_shutdown(struct platform_device *pdev)
{
struct lm3533_bl *bl = platform_get_drvdata(pdev);
@@ -404,12 +403,11 @@ static struct platform_driver lm3533_bl_driver = {
.driver = {
.name = "lm3533-backlight",
.owner = THIS_MODULE,
+ .pm = &lm3533_bl_pm_ops,
},
.probe = lm3533_bl_probe,
.remove = lm3533_bl_remove,
.shutdown = lm3533_bl_shutdown,
- .suspend = lm3533_bl_suspend,
- .resume = lm3533_bl_resume,
};
module_platform_driver(lm3533_bl_driver);
diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c
index b43882abefaf..cf01b9ac8131 100644
--- a/drivers/video/backlight/lms501kf03.c
+++ b/drivers/video/backlight/lms501kf03.c
@@ -387,13 +387,12 @@ static int lms501kf03_remove(struct spi_device *spi)
return 0;
}
-#if defined(CONFIG_PM)
-
-static int lms501kf03_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int lms501kf03_suspend(struct device *dev)
{
- struct lms501kf03 *lcd = spi_get_drvdata(spi);
+ struct lms501kf03 *lcd = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+ dev_dbg(dev, "lcd->power = %d\n", lcd->power);
/*
* when lcd panel is suspend, lcd panel becomes off
@@ -402,19 +401,19 @@ static int lms501kf03_suspend(struct spi_device *spi, pm_message_t mesg)
return lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
}
-static int lms501kf03_resume(struct spi_device *spi)
+static int lms501kf03_resume(struct device *dev)
{
- struct lms501kf03 *lcd = spi_get_drvdata(spi);
+ struct lms501kf03 *lcd = dev_get_drvdata(dev);
lcd->power = FB_BLANK_POWERDOWN;
return lms501kf03_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define lms501kf03_suspend NULL
-#define lms501kf03_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(lms501kf03_pm_ops, lms501kf03_suspend,
+ lms501kf03_resume);
+
static void lms501kf03_shutdown(struct spi_device *spi)
{
struct lms501kf03 *lcd = spi_get_drvdata(spi);
@@ -426,12 +425,11 @@ static struct spi_driver lms501kf03_driver = {
.driver = {
.name = "lms501kf03",
.owner = THIS_MODULE,
+ .pm = &lms501kf03_pm_ops,
},
.probe = lms501kf03_probe,
.remove = lms501kf03_remove,
.shutdown = lms501kf03_shutdown,
- .suspend = lms501kf03_suspend,
- .resume = lms501kf03_resume,
};
module_spi_driver(lms501kf03_driver);
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 146fea8aa431..6c3ec4259a60 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -157,25 +157,24 @@ static const struct backlight_ops locomobl_data = {
.update_status = locomolcd_set_intensity,
};
-#ifdef CONFIG_PM
-static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int locomolcd_suspend(struct device *dev)
{
locomolcd_flags |= LOCOMOLCD_SUSPENDED;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
}
-static int locomolcd_resume(struct locomo_dev *dev)
+static int locomolcd_resume(struct device *dev)
{
locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
locomolcd_set_intensity(locomolcd_bl_device);
return 0;
}
-#else
-#define locomolcd_suspend NULL
-#define locomolcd_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume);
+
static int locomolcd_probe(struct locomo_dev *ldev)
{
struct backlight_properties props;
@@ -230,13 +229,12 @@ static int locomolcd_remove(struct locomo_dev *dev)
static struct locomo_driver poodle_lcd_driver = {
.drv = {
- .name = "locomo-backlight",
+ .name = "locomo-backlight",
+ .pm = &locomolcd_pm_ops,
},
.devid = LOCOMO_DEVID_BACKLIGHT,
.probe = locomolcd_probe,
.remove = locomolcd_remove,
- .suspend = locomolcd_suspend,
- .resume = locomolcd_resume,
};
static int __init locomolcd_init(void)
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index 7ae9ae6f4655..a0e1e02bdc2e 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -14,6 +14,7 @@
#include <linux/i2c.h>
#include <linux/backlight.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/platform_data/lp855x.h>
#include <linux/pwm.h>
@@ -35,10 +36,14 @@
#define LP8557_EPROM_START 0x10
#define LP8557_EPROM_END 0x1E
-#define BUF_SIZE 20
#define DEFAULT_BL_NAME "lcd-backlight"
#define MAX_BRIGHTNESS 255
+enum lp855x_brightness_ctrl_mode {
+ PWM_BASED = 1,
+ REGISTER_BASED,
+};
+
struct lp855x;
/*
@@ -58,6 +63,7 @@ struct lp855x_device_config {
struct lp855x {
const char *chipname;
enum lp855x_chip_id chip_id;
+ enum lp855x_brightness_ctrl_mode mode;
struct lp855x_device_config *cfg;
struct i2c_client *client;
struct backlight_device *bl;
@@ -187,7 +193,7 @@ static int lp855x_configure(struct lp855x *lp)
if (ret)
goto err;
- if (pd->load_new_rom_data && pd->size_program) {
+ if (pd->size_program > 0) {
for (i = 0; i < pd->size_program; i++) {
addr = pd->rom_data[i].addr;
val = pd->rom_data[i].val;
@@ -239,18 +245,17 @@ static void lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
static int lp855x_bl_update_status(struct backlight_device *bl)
{
struct lp855x *lp = bl_get_data(bl);
- enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
if (bl->props.state & BL_CORE_SUSPENDED)
bl->props.brightness = 0;
- if (mode == PWM_BASED) {
+ if (lp->mode == PWM_BASED) {
int br = bl->props.brightness;
int max_br = bl->props.max_brightness;
lp855x_pwm_ctrl(lp, br, max_br);
- } else if (mode == REGISTER_BASED) {
+ } else if (lp->mode == REGISTER_BASED) {
u8 val = bl->props.brightness;
lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
}
@@ -274,7 +279,7 @@ static int lp855x_backlight_register(struct lp855x *lp)
struct backlight_device *bl;
struct backlight_properties props;
struct lp855x_platform_data *pdata = lp->pdata;
- char *name = pdata->name ? : DEFAULT_BL_NAME;
+ const char *name = pdata->name ? : DEFAULT_BL_NAME;
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = MAX_BRIGHTNESS;
@@ -304,22 +309,21 @@ static ssize_t lp855x_get_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lp855x *lp = dev_get_drvdata(dev);
- return scnprintf(buf, BUF_SIZE, "%s\n", lp->chipname);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
}
static ssize_t lp855x_get_bl_ctl_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lp855x *lp = dev_get_drvdata(dev);
- enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
char *strmode = NULL;
- if (mode == PWM_BASED)
+ if (lp->mode == PWM_BASED)
strmode = "pwm based";
- else if (mode == REGISTER_BASED)
+ else if (lp->mode == REGISTER_BASED)
strmode = "register based";
- return scnprintf(buf, BUF_SIZE, "%s\n", strmode);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
}
static DEVICE_ATTR(chip_id, S_IRUGO, lp855x_get_chip_id, NULL);
@@ -335,16 +339,71 @@ static const struct attribute_group lp855x_attr_group = {
.attrs = lp855x_attributes,
};
+#ifdef CONFIG_OF
+static int lp855x_parse_dt(struct device *dev, struct device_node *node)
+{
+ struct lp855x_platform_data *pdata;
+ int rom_length;
+
+ if (!node) {
+ dev_err(dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ of_property_read_string(node, "bl-name", &pdata->name);
+ of_property_read_u8(node, "dev-ctrl", &pdata->device_control);
+ of_property_read_u8(node, "init-brt", &pdata->initial_brightness);
+ of_property_read_u32(node, "pwm-period", &pdata->period_ns);
+
+ /* Fill ROM platform data if defined */
+ rom_length = of_get_child_count(node);
+ if (rom_length > 0) {
+ struct lp855x_rom_data *rom;
+ struct device_node *child;
+ int i = 0;
+
+ rom = devm_kzalloc(dev, sizeof(*rom) * rom_length, GFP_KERNEL);
+ if (!rom)
+ return -ENOMEM;
+
+ for_each_child_of_node(node, child) {
+ of_property_read_u8(child, "rom-addr", &rom[i].addr);
+ of_property_read_u8(child, "rom-val", &rom[i].val);
+ i++;
+ }
+
+ pdata->size_program = rom_length;
+ pdata->rom_data = &rom[0];
+ }
+
+ dev->platform_data = pdata;
+
+ return 0;
+}
+#else
+static int lp855x_parse_dt(struct device *dev, struct device_node *node)
+{
+ return -EINVAL;
+}
+#endif
+
static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct lp855x *lp;
struct lp855x_platform_data *pdata = cl->dev.platform_data;
- enum lp855x_brightness_ctrl_mode mode;
+ struct device_node *node = cl->dev.of_node;
int ret;
if (!pdata) {
- dev_err(&cl->dev, "no platform data supplied\n");
- return -EINVAL;
+ ret = lp855x_parse_dt(&cl->dev, node);
+ if (ret < 0)
+ return ret;
+
+ pdata = cl->dev.platform_data;
}
if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
@@ -354,7 +413,11 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
if (!lp)
return -ENOMEM;
- mode = pdata->mode;
+ if (pdata->period_ns > 0)
+ lp->mode = PWM_BASED;
+ else
+ lp->mode = REGISTER_BASED;
+
lp->client = cl;
lp->dev = &cl->dev;
lp->pdata = pdata;
@@ -402,6 +465,17 @@ static int lp855x_remove(struct i2c_client *cl)
return 0;
}
+static const struct of_device_id lp855x_dt_ids[] = {
+ { .compatible = "ti,lp8550", },
+ { .compatible = "ti,lp8551", },
+ { .compatible = "ti,lp8552", },
+ { .compatible = "ti,lp8553", },
+ { .compatible = "ti,lp8556", },
+ { .compatible = "ti,lp8557", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lp855x_dt_ids);
+
static const struct i2c_device_id lp855x_ids[] = {
{"lp8550", LP8550},
{"lp8551", LP8551},
@@ -416,6 +490,7 @@ MODULE_DEVICE_TABLE(i2c, lp855x_ids);
static struct i2c_driver lp855x_driver = {
.driver = {
.name = "lp855x",
+ .of_match_table = of_match_ptr(lp855x_dt_ids),
},
.probe = lp855x_probe,
.remove = lp855x_remove,
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
index c0b4b8f2de98..ed1b39268131 100644
--- a/drivers/video/backlight/ltv350qv.c
+++ b/drivers/video/backlight/ltv350qv.c
@@ -271,25 +271,24 @@ static int ltv350qv_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ltv350qv_suspend(struct device *dev)
{
- struct ltv350qv *lcd = spi_get_drvdata(spi);
+ struct ltv350qv *lcd = dev_get_drvdata(dev);
return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
}
-static int ltv350qv_resume(struct spi_device *spi)
+static int ltv350qv_resume(struct device *dev)
{
- struct ltv350qv *lcd = spi_get_drvdata(spi);
+ struct ltv350qv *lcd = dev_get_drvdata(dev);
return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define ltv350qv_suspend NULL
-#define ltv350qv_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ltv350qv_pm_ops, ltv350qv_suspend, ltv350qv_resume);
+
/* Power down all displays on reboot, poweroff or halt */
static void ltv350qv_shutdown(struct spi_device *spi)
{
@@ -302,13 +301,12 @@ static struct spi_driver ltv350qv_driver = {
.driver = {
.name = "ltv350qv",
.owner = THIS_MODULE,
+ .pm = &ltv350qv_pm_ops,
},
.probe = ltv350qv_probe,
.remove = ltv350qv_remove,
.shutdown = ltv350qv_shutdown,
- .suspend = ltv350qv_suspend,
- .resume = ltv350qv_resume,
};
module_spi_driver(ltv350qv_driver);
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index 627110163067..812e22e35cab 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -18,8 +18,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -73,27 +71,24 @@ static void omapbl_blank(struct omap_backlight *bl, int mode)
}
}
-#ifdef CONFIG_PM
-static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int omapbl_suspend(struct device *dev)
{
- struct backlight_device *dev = platform_get_drvdata(pdev);
- struct omap_backlight *bl = bl_get_data(dev);
+ struct backlight_device *bl_dev = dev_get_drvdata(dev);
+ struct omap_backlight *bl = bl_get_data(bl_dev);
omapbl_blank(bl, FB_BLANK_POWERDOWN);
return 0;
}
-static int omapbl_resume(struct platform_device *pdev)
+static int omapbl_resume(struct device *dev)
{
- struct backlight_device *dev = platform_get_drvdata(pdev);
- struct omap_backlight *bl = bl_get_data(dev);
+ struct backlight_device *bl_dev = dev_get_drvdata(dev);
+ struct omap_backlight *bl = bl_get_data(bl_dev);
omapbl_blank(bl, bl->powermode);
return 0;
}
-#else
-#define omapbl_suspend NULL
-#define omapbl_resume NULL
#endif
static int omapbl_set_power(struct backlight_device *dev, int state)
@@ -170,7 +165,7 @@ static int omapbl_probe(struct platform_device *pdev)
dev->props.brightness = pdata->default_intensity;
omapbl_update_status(dev);
- pr_info("OMAP LCD backlight initialised\n");
+ dev_info(&pdev->dev, "OMAP LCD backlight initialised\n");
return 0;
}
@@ -184,13 +179,14 @@ static int omapbl_remove(struct platform_device *pdev)
return 0;
}
+static SIMPLE_DEV_PM_OPS(omapbl_pm_ops, omapbl_suspend, omapbl_resume);
+
static struct platform_driver omapbl_driver = {
.probe = omapbl_probe,
.remove = omapbl_remove,
- .suspend = omapbl_suspend,
- .resume = omapbl_resume,
.driver = {
.name = "omap-bl",
+ .pm = &omapbl_pm_ops,
},
};
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c
index 17a6b83f97af..056836706708 100644
--- a/drivers/video/backlight/platform_lcd.c
+++ b/drivers/video/backlight/platform_lcd.c
@@ -86,6 +86,12 @@ static int platform_lcd_probe(struct platform_device *pdev)
return -EINVAL;
}
+ if (pdata->probe) {
+ err = pdata->probe(pdata);
+ if (err)
+ return err;
+ }
+
plcd = devm_kzalloc(&pdev->dev, sizeof(struct platform_lcd),
GFP_KERNEL);
if (!plcd) {
@@ -121,7 +127,7 @@ static int platform_lcd_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int platform_lcd_suspend(struct device *dev)
{
struct platform_lcd *plcd = dev_get_drvdata(dev);
@@ -141,10 +147,10 @@ static int platform_lcd_resume(struct device *dev)
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend,
platform_lcd_resume);
-#endif
#ifdef CONFIG_OF
static const struct of_device_id platform_lcd_of_match[] = {
@@ -158,9 +164,7 @@ static struct platform_driver platform_lcd_driver = {
.driver = {
.name = "platform-lcd",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &platform_lcd_pm_ops,
-#endif
.of_match_table = of_match_ptr(platform_lcd_of_match),
},
.probe = platform_lcd_probe,
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
index 9c2677f0ef7d..b37bb1854bf4 100644
--- a/drivers/video/backlight/s6e63m0.c
+++ b/drivers/video/backlight/s6e63m0.c
@@ -817,12 +817,12 @@ static int s6e63m0_remove(struct spi_device *spi)
return 0;
}
-#if defined(CONFIG_PM)
-static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
+#ifdef CONFIG_PM_SLEEP
+static int s6e63m0_suspend(struct device *dev)
{
- struct s6e63m0 *lcd = spi_get_drvdata(spi);
+ struct s6e63m0 *lcd = dev_get_drvdata(dev);
- dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+ dev_dbg(dev, "lcd->power = %d\n", lcd->power);
/*
* when lcd panel is suspend, lcd panel becomes off
@@ -831,19 +831,18 @@ static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
return s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
}
-static int s6e63m0_resume(struct spi_device *spi)
+static int s6e63m0_resume(struct device *dev)
{
- struct s6e63m0 *lcd = spi_get_drvdata(spi);
+ struct s6e63m0 *lcd = dev_get_drvdata(dev);
lcd->power = FB_BLANK_POWERDOWN;
return s6e63m0_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define s6e63m0_suspend NULL
-#define s6e63m0_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(s6e63m0_pm_ops, s6e63m0_suspend, s6e63m0_resume);
+
/* Power down all displays on reboot, poweroff or halt. */
static void s6e63m0_shutdown(struct spi_device *spi)
{
@@ -856,12 +855,11 @@ static struct spi_driver s6e63m0_driver = {
.driver = {
.name = "s6e63m0",
.owner = THIS_MODULE,
+ .pm = &s6e63m0_pm_ops,
},
.probe = s6e63m0_probe,
.remove = s6e63m0_remove,
.shutdown = s6e63m0_shutdown,
- .suspend = s6e63m0_suspend,
- .resume = s6e63m0_resume,
};
module_spi_driver(s6e63m0_driver);
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index 00162085eec0..18cdf466d50a 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -412,25 +412,24 @@ static int tdo24m_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tdo24m_suspend(struct device *dev)
{
- struct tdo24m *lcd = spi_get_drvdata(spi);
+ struct tdo24m *lcd = dev_get_drvdata(dev);
return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
}
-static int tdo24m_resume(struct spi_device *spi)
+static int tdo24m_resume(struct device *dev)
{
- struct tdo24m *lcd = spi_get_drvdata(spi);
+ struct tdo24m *lcd = dev_get_drvdata(dev);
return tdo24m_power(lcd, FB_BLANK_UNBLANK);
}
-#else
-#define tdo24m_suspend NULL
-#define tdo24m_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(tdo24m_pm_ops, tdo24m_suspend, tdo24m_resume);
+
/* Power down all displays on reboot, poweroff or halt */
static void tdo24m_shutdown(struct spi_device *spi)
{
@@ -443,12 +442,11 @@ static struct spi_driver tdo24m_driver = {
.driver = {
.name = "tdo24m",
.owner = THIS_MODULE,
+ .pm = &tdo24m_pm_ops,
},
.probe = tdo24m_probe,
.remove = tdo24m_remove,
.shutdown = tdo24m_shutdown,
- .suspend = tdo24m_suspend,
- .resume = tdo24m_resume,
};
module_spi_driver(tdo24m_driver);
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 2326fa810c59..9df66ac68b34 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -134,28 +134,27 @@ static int tosa_bl_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int tosa_bl_suspend(struct i2c_client *client, pm_message_t pm)
+#ifdef CONFIG_PM_SLEEP
+static int tosa_bl_suspend(struct device *dev)
{
- struct tosa_bl_data *data = i2c_get_clientdata(client);
+ struct tosa_bl_data *data = dev_get_drvdata(dev);
tosa_bl_set_backlight(data, 0);
return 0;
}
-static int tosa_bl_resume(struct i2c_client *client)
+static int tosa_bl_resume(struct device *dev)
{
- struct tosa_bl_data *data = i2c_get_clientdata(client);
+ struct tosa_bl_data *data = dev_get_drvdata(dev);
backlight_update_status(data->bl);
return 0;
}
-#else
-#define tosa_bl_suspend NULL
-#define tosa_bl_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(tosa_bl_pm_ops, tosa_bl_suspend, tosa_bl_resume);
+
static const struct i2c_device_id tosa_bl_id[] = {
{ "tosa-bl", 0 },
{ },
@@ -165,11 +164,10 @@ static struct i2c_driver tosa_bl_driver = {
.driver = {
.name = "tosa-bl",
.owner = THIS_MODULE,
+ .pm = &tosa_bl_pm_ops,
},
.probe = tosa_bl_probe,
.remove = tosa_bl_remove,
- .suspend = tosa_bl_suspend,
- .resume = tosa_bl_resume,
.id_table = tosa_bl_id,
};
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 666fe2593ea4..bf081573e5b5 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -240,19 +240,19 @@ static int tosa_lcd_remove(struct spi_device *spi)
return 0;
}
-#ifdef CONFIG_PM
-static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tosa_lcd_suspend(struct device *dev)
{
- struct tosa_lcd_data *data = spi_get_drvdata(spi);
+ struct tosa_lcd_data *data = dev_get_drvdata(dev);
tosa_lcd_tg_off(data);
return 0;
}
-static int tosa_lcd_resume(struct spi_device *spi)
+static int tosa_lcd_resume(struct device *dev)
{
- struct tosa_lcd_data *data = spi_get_drvdata(spi);
+ struct tosa_lcd_data *data = dev_get_drvdata(dev);
tosa_lcd_tg_init(data);
if (POWER_IS_ON(data->lcd_power))
@@ -262,20 +262,18 @@ static int tosa_lcd_resume(struct spi_device *spi)
return 0;
}
-#else
-#define tosa_lcd_suspend NULL
-#define tosa_lcd_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(tosa_lcd_pm_ops, tosa_lcd_suspend, tosa_lcd_resume);
+
static struct spi_driver tosa_lcd_driver = {
.driver = {
.name = "tosa-lcd",
.owner = THIS_MODULE,
+ .pm = &tosa_lcd_pm_ops,
},
.probe = tosa_lcd_probe,
.remove = tosa_lcd_remove,
- .suspend = tosa_lcd_suspend,
- .resume = tosa_lcd_resume,
};
module_spi_driver(tosa_lcd_driver);
diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c
index 70881633b45a..05782312aeb3 100644
--- a/drivers/video/backlight/tps65217_bl.c
+++ b/drivers/video/backlight/tps65217_bl.c
@@ -245,6 +245,18 @@ tps65217_bl_parse_dt(struct platform_device *pdev)
}
}
+ if (!of_property_read_u32(node, "default-brightness", &val)) {
+ if (val < 0 ||
+ val > 100) {
+ dev_err(&pdev->dev,
+ "invalid 'default-brightness' value in the device tree\n");
+ err = ERR_PTR(-EINVAL);
+ goto err;
+ }
+
+ pdata->dft_brightness = val;
+ }
+
of_node_put(node);
return pdata;
@@ -311,7 +323,8 @@ static int tps65217_bl_probe(struct platform_device *pdev)
return PTR_ERR(tps65217_bl->bl);
}
- tps65217_bl->bl->props.brightness = 0;
+ tps65217_bl->bl->props.brightness = pdata->dft_brightness;
+ backlight_update_status(tps65217_bl->bl);
platform_set_drvdata(pdev, tps65217_bl);
return 0;
diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c
index 84d582f591dc..d538947a67d3 100644
--- a/drivers/video/backlight/vgg2432a4.c
+++ b/drivers/video/backlight/vgg2432a4.c
@@ -205,18 +205,15 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd,
return ret;
}
-#ifdef CONFIG_PM
-static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int vgg2432a4_suspend(struct device *dev)
{
- return ili9320_suspend(spi_get_drvdata(spi), state);
+ return ili9320_suspend(dev_get_drvdata(dev));
}
-static int vgg2432a4_resume(struct spi_device *spi)
+static int vgg2432a4_resume(struct device *dev)
{
- return ili9320_resume(spi_get_drvdata(spi));
+ return ili9320_resume(dev_get_drvdata(dev));
}
-#else
-#define vgg2432a4_suspend NULL
-#define vgg2432a4_resume NULL
#endif
static struct ili9320_client vgg2432a4_client = {
@@ -249,16 +246,17 @@ static void vgg2432a4_shutdown(struct spi_device *spi)
ili9320_shutdown(spi_get_drvdata(spi));
}
+static SIMPLE_DEV_PM_OPS(vgg2432a4_pm_ops, vgg2432a4_suspend, vgg2432a4_resume);
+
static struct spi_driver vgg2432a4_driver = {
.driver = {
.name = "VGG2432A4",
.owner = THIS_MODULE,
+ .pm = &vgg2432a4_pm_ops,
},
.probe = vgg2432a4_probe,
.remove = vgg2432a4_remove,
.shutdown = vgg2432a4_shutdown,
- .suspend = vgg2432a4_suspend,
- .resume = vgg2432a4_resume,
};
module_spi_driver(vgg2432a4_driver);
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index 6a737827beb1..a93670ef7f89 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -27,7 +27,7 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
int width = (vc->vc_font.height + 7) >> 3;
- u8 c, t = 0, msk = ~(0xff >> offset);
+ u8 c, msk = ~(0xff >> offset);
for (i = 0; i < vc->vc_font.width; i++) {
for (j = 0; j < width; j++) {
@@ -40,7 +40,6 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
c = ~c;
src++;
*dst++ = c;
- t = c;
}
}
}
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 0c189b32a4c5..67b77b40aa7f 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -285,36 +285,26 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var,
static int controlfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
- unsigned long off, start;
- u32 len;
-
- off = vma->vm_pgoff << PAGE_SHIFT;
-
- /* frame buffer memory */
- start = info->fix.smem_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.smem_len);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags)
- return -EINVAL;
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK)+info->fix.mmio_len);
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- } else {
- /* framebuffer */
- vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
- }
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
-
- return 0;
+ unsigned long mmio_pgoff;
+ unsigned long start;
+ u32 len;
+
+ start = info->fix.smem_start;
+ len = info->fix.smem_len;
+ mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
+ if (vma->vm_pgoff >= mmio_pgoff) {
+ if (info->var.accel_flags)
+ return -EINVAL;
+ vma->vm_pgoff -= mmio_pgoff;
+ start = info->fix.mmio_start;
+ len = info->fix.mmio_len;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ } else {
+ /* framebuffer */
+ vma->vm_page_prot = pgprot_cached_wthru(vma->vm_page_prot);
+ }
+
+ return vm_iomap_memory(vma, start, len);
}
static int controlfb_blank(int blank_mode, struct fb_info *info)
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index e06cd5d90c97..ee1ee5401544 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -419,7 +419,7 @@ static struct fb_ops ep93xxfb_ops = {
.fb_mmap = ep93xxfb_mmap,
};
-static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
+static int ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
{
int i, fb_size = 0;
@@ -441,7 +441,7 @@ static int __init ep93xxfb_calc_fbsize(struct ep93xxfb_mach_info *mach_info)
return fb_size;
}
-static int __init ep93xxfb_alloc_videomem(struct fb_info *info)
+static int ep93xxfb_alloc_videomem(struct fb_info *info)
{
struct ep93xx_fbi *fbi = info->par;
char __iomem *virt_addr;
@@ -627,19 +627,7 @@ static struct platform_driver ep93xxfb_driver = {
.owner = THIS_MODULE,
},
};
-
-static int ep93xxfb_init(void)
-{
- return platform_driver_register(&ep93xxfb_driver);
-}
-
-static void __exit ep93xxfb_exit(void)
-{
- platform_driver_unregister(&ep93xxfb_driver);
-}
-
-module_init(ep93xxfb_init);
-module_exit(ep93xxfb_exit);
+module_platform_driver(ep93xxfb_driver);
MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
MODULE_ALIAS("platform:ep93xx-fb");
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index de9d4da0e3da..12bbede3b091 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -976,14 +976,14 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
}
if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
- dev_err(dp->dev, "faild to get reg for dptx-phy\n");
+ dev_err(dp->dev, "failed to get reg for dptx-phy\n");
ret = -EINVAL;
goto err;
}
if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
&dp->enable_mask)) {
- dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
+ dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
ret = -EINVAL;
goto err;
}
diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c
index fac7df6d1aba..32e540600f99 100644
--- a/drivers/video/exynos/exynos_mipi_dsi.c
+++ b/drivers/video/exynos/exynos_mipi_dsi.c
@@ -32,11 +32,10 @@
#include <linux/notifier.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/err.h>
#include <video/exynos_mipi_dsim.h>
-#include <plat/fb.h>
-
#include "exynos_mipi_dsi_common.h"
#include "exynos_mipi_dsi_lowlevel.h"
@@ -384,10 +383,9 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dsim->reg_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!dsim->reg_base) {
- dev_err(&pdev->dev, "failed to remap io region\n");
- ret = -ENOMEM;
+ dsim->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dsim->reg_base)) {
+ ret = PTR_ERR(dsim->reg_base);
goto error;
}
diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c
index c70cb8926df6..520fc9bd887b 100644
--- a/drivers/video/exynos/exynos_mipi_dsi_common.c
+++ b/drivers/video/exynos/exynos_mipi_dsi_common.c
@@ -31,8 +31,6 @@
#include <video/mipi_display.h>
#include <video/exynos_mipi_dsim.h>
-#include <mach/map.h>
-
#include "exynos_mipi_dsi_regs.h"
#include "exynos_mipi_dsi_lowlevel.h"
#include "exynos_mipi_dsi_common.h"
diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
index 95cb99a1fe2d..15c5abd408dc 100644
--- a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
+++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
@@ -26,8 +26,6 @@
#include <video/exynos_mipi_dsim.h>
-#include <mach/map.h>
-
#include "exynos_mipi_dsi_regs.h"
void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c
index 7d106f1f4906..27fc956166fa 100644
--- a/drivers/video/fb-puv3.c
+++ b/drivers/video/fb-puv3.c
@@ -640,21 +640,9 @@ static int unifb_pan_display(struct fb_var_screeninfo *var,
int unifb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long pos = info->fix.smem_start + offset;
-
- if (offset + size > info->fix.smem_len)
- return -EINVAL;
-
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start, pos >> PAGE_SHIFT, size,
- vma->vm_page_prot))
- return -EAGAIN;
-
- /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
- return 0;
+ return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
}
static struct fb_ops unifb_ops = {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 7c254084b6a0..dcb669eb4532 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1373,15 +1373,12 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
{
struct fb_info *info = file_fb_info(file);
struct fb_ops *fb;
- unsigned long off;
+ unsigned long mmio_pgoff;
unsigned long start;
u32 len;
if (!info)
return -ENODEV;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
fb = info->fbops;
if (!fb)
return -ENODEV;
@@ -1393,32 +1390,29 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
return res;
}
- /* frame buffer memory */
+ /*
+ * Ugh. This can be either the frame buffer mapping, or
+ * if pgoff points past it, the mmio mapping.
+ */
start = info->fix.smem_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
+ len = info->fix.smem_len;
+ mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
+ if (vma->vm_pgoff >= mmio_pgoff) {
if (info->var.accel_flags) {
mutex_unlock(&info->mm_lock);
return -EINVAL;
}
+
+ vma->vm_pgoff -= mmio_pgoff;
start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+ len = info->fix.mmio_len;
}
mutex_unlock(&info->mm_lock);
- start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
- off += start;
- vma->vm_pgoff = off >> PAGE_SHIFT;
- /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/
+
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
- fb_pgprotect(file, vma, off);
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot))
- return -EAGAIN;
- return 0;
+ fb_pgprotect(file, vma, start);
+
+ return vm_iomap_memory(vma, start, len);
}
static int
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 94ad0f71383c..6103fa6fb54f 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -1376,7 +1376,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf
return err;
}
-#if IS_ENABLED(CONFIG_VIDEOMODE)
+#ifdef CONFIG_VIDEOMODE_HELPERS
int fb_videomode_from_videomode(const struct videomode *vm,
struct fb_videomode *fbmode)
{
@@ -1398,13 +1398,13 @@ int fb_videomode_from_videomode(const struct videomode *vm,
fbmode->sync = 0;
fbmode->vmode = 0;
- if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+ if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
- if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+ if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
- if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED)
fbmode->vmode |= FB_VMODE_INTERLACED;
- if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
+ if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
fbmode->vmode |= FB_VMODE_DOUBLE;
fbmode->flag = 0;
@@ -1424,9 +1424,8 @@ int fb_videomode_from_videomode(const struct videomode *vm,
return 0;
}
EXPORT_SYMBOL_GPL(fb_videomode_from_videomode);
-#endif
-#if IS_ENABLED(CONFIG_OF_VIDEOMODE)
+#ifdef CONFIG_OF
static inline void dump_fb_videomode(const struct fb_videomode *m)
{
pr_debug("fb_videomode = %ux%u@%uHz (%ukHz) %u %u %u %u %u %u %u %u %u\n",
@@ -1465,7 +1464,8 @@ int of_get_fb_videomode(struct device_node *np, struct fb_videomode *fb,
return 0;
}
EXPORT_SYMBOL_GPL(of_get_fb_videomode);
-#endif
+#endif /* CONFIG_OF */
+#endif /* CONFIG_VIDEOMODE_HELPERS */
#else
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 41fbd9453c5f..6c278056fc60 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -375,7 +375,10 @@ struct fsl_diu_data {
struct diu_ad dummy_ad __aligned(8);
struct diu_ad ad[NUM_AOIS] __aligned(8);
u8 gamma[256 * 3] __aligned(32);
- u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32);
+ /* It's easier to parse the cursor data as little-endian */
+ __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32);
+ /* Blank cursor data -- used to hide the cursor */
+ __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
uint8_t edid_data[EDID_LENGTH];
bool has_edid;
} __aligned(32);
@@ -824,7 +827,6 @@ static void update_lcdc(struct fb_info *info)
/* Program DIU registers */
out_be32(&hw->gamma, DMA_ADDR(data, gamma));
- out_be32(&hw->cursor, DMA_ADDR(data, cursor));
out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */
out_be32(&hw->disp_size, (var->yres << 16) | var->xres);
@@ -968,6 +970,156 @@ static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
}
/*
+ * Copies a cursor image from user space to the proper place in driver
+ * memory so that the hardware can display the cursor image.
+ *
+ * Cursor data is represented as a sequence of 'width' bits packed into bytes.
+ * That is, the first 8 bits are in the first byte, the second 8 bits in the
+ * second byte, and so on. Therefore, the each row of the cursor is (width +
+ * 7) / 8 bytes of 'data'
+ *
+ * The DIU only supports cursors up to 32x32 (MAX_CURS). We reject cursors
+ * larger than this, so we already know that 'width' <= 32. Therefore, we can
+ * simplify our code by using a 32-bit big-endian integer ("line") to read in
+ * a single line of pixels, and only look at the top 'width' bits of that
+ * integer.
+ *
+ * This could result in an unaligned 32-bit read. For example, if the cursor
+ * is 24x24, then the first three bytes of 'image' contain the pixel data for
+ * the top line of the cursor. We do a 32-bit read of 'image', but we look
+ * only at the top 24 bits. Then we increment 'image' by 3 bytes. The next
+ * read is unaligned. The only problem is that we might read past the end of
+ * 'image' by 1-3 bytes, but that should not cause any problems.
+ */
+static void fsl_diu_load_cursor_image(struct fb_info *info,
+ const void *image, uint16_t bg, uint16_t fg,
+ unsigned int width, unsigned int height)
+{
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *data = mfbi->parent;
+ __le16 *cursor = data->cursor;
+ __le16 _fg = cpu_to_le16(fg);
+ __le16 _bg = cpu_to_le16(bg);
+ unsigned int h, w;
+
+ for (h = 0; h < height; h++) {
+ uint32_t mask = 1 << 31;
+ uint32_t line = be32_to_cpup(image);
+
+ for (w = 0; w < width; w++) {
+ cursor[w] = (line & mask) ? _fg : _bg;
+ mask >>= 1;
+ }
+
+ cursor += MAX_CURS;
+ image += DIV_ROUND_UP(width, 8);
+ }
+}
+
+/*
+ * Set a hardware cursor. The image data for the cursor is passed via the
+ * fb_cursor object.
+ */
+static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct mfb_info *mfbi = info->par;
+ struct fsl_diu_data *data = mfbi->parent;
+ struct diu __iomem *hw = data->diu_reg;
+
+ if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS)
+ return -EINVAL;
+
+ /* The cursor size has changed */
+ if (cursor->set & FB_CUR_SETSIZE) {
+ /*
+ * The DIU cursor is a fixed size, so when we get this
+ * message, instead of resizing the cursor, we just clear
+ * all the image data, in expectation of new data. However,
+ * in tests this control does not appear to be normally
+ * called.
+ */
+ memset(data->cursor, 0, sizeof(data->cursor));
+ }
+
+ /* The cursor position has changed (cursor->image.dx|dy) */
+ if (cursor->set & FB_CUR_SETPOS) {
+ uint32_t xx, yy;
+
+ yy = (cursor->image.dy - info->var.yoffset) & 0x7ff;
+ xx = (cursor->image.dx - info->var.xoffset) & 0x7ff;
+
+ out_be32(&hw->curs_pos, yy << 16 | xx);
+ }
+
+ /*
+ * FB_CUR_SETIMAGE - the cursor image has changed
+ * FB_CUR_SETCMAP - the cursor colors has changed
+ * FB_CUR_SETSHAPE - the cursor bitmask has changed
+ */
+ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) {
+ unsigned int image_size =
+ DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height;
+ unsigned int image_words =
+ DIV_ROUND_UP(image_size, sizeof(uint32_t));
+ unsigned int bg_idx = cursor->image.bg_color;
+ unsigned int fg_idx = cursor->image.fg_color;
+ uint8_t buffer[image_size];
+ uint32_t *image, *source, *mask;
+ uint16_t fg, bg;
+ unsigned int i;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return 0;
+
+ /*
+ * Determine the size of the cursor image data. Normally,
+ * it's 8x16.
+ */
+ image_size = DIV_ROUND_UP(cursor->image.width, 8) *
+ cursor->image.height;
+
+ bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) |
+ ((info->cmap.green[bg_idx] & 0xf8) << 2) |
+ ((info->cmap.blue[bg_idx] & 0xf8) >> 3) |
+ 1 << 15;
+
+ fg = ((info->cmap.red[fg_idx] & 0xf8) << 7) |
+ ((info->cmap.green[fg_idx] & 0xf8) << 2) |
+ ((info->cmap.blue[fg_idx] & 0xf8) >> 3) |
+ 1 << 15;
+
+ /* Use 32-bit operations on the data to improve performance */
+ image = (uint32_t *)buffer;
+ source = (uint32_t *)cursor->image.data;
+ mask = (uint32_t *)cursor->mask;
+
+ if (cursor->rop == ROP_XOR)
+ for (i = 0; i < image_words; i++)
+ image[i] = source[i] ^ mask[i];
+ else
+ for (i = 0; i < image_words; i++)
+ image[i] = source[i] & mask[i];
+
+ fsl_diu_load_cursor_image(info, image, bg, fg,
+ cursor->image.width, cursor->image.height);
+ };
+
+ /*
+ * Show or hide the cursor. The cursor data is always stored in the
+ * 'cursor' memory block, and the actual cursor position is always in
+ * the DIU's CURS_POS register. To hide the cursor, we redirect the
+ * CURSOR register to a blank cursor. The show the cursor, we
+ * redirect the CURSOR register to the real cursor data.
+ */
+ if (cursor->enable)
+ out_be32(&hw->cursor, DMA_ADDR(data, cursor));
+ else
+ out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
+
+ return 0;
+}
+
+/*
* Using the fb_var_screeninfo in fb_info we set the resolution of this
* particular framebuffer. This function alters the fb_fix_screeninfo stored
* in fb_info. It does not alter var in fb_info since we are using that
@@ -1312,6 +1464,7 @@ static struct fb_ops fsl_diu_ops = {
.fb_ioctl = fsl_diu_ioctl,
.fb_open = fsl_diu_open,
.fb_release = fsl_diu_release,
+ .fb_cursor = fsl_diu_cursor,
};
static int install_fb(struct fb_info *info)
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index bda5e3941510..ceab37020fff 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -1016,7 +1016,9 @@ static int gbefb_mmap(struct fb_info *info,
/* check range */
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
- if (offset + size > gbe_mem_size)
+ if (size > gbe_mem_size)
+ return -EINVAL;
+ if (offset > gbe_mem_size - size)
return -EINVAL;
/* remap using the fastest write-through mode on architecture */
diff --git a/drivers/video/goldfishfb.c b/drivers/video/goldfishfb.c
index 489abb32fc04..7f6c9e6cfc6c 100644
--- a/drivers/video/goldfishfb.c
+++ b/drivers/video/goldfishfb.c
@@ -148,7 +148,7 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var,
wait_event_timeout(fb->wait,
fb->base_update_count != base_update_count, HZ / 15);
if (fb->base_update_count == base_update_count)
- pr_err("goldfish_fb_pan_display: timeout wating for base update\n");
+ pr_err("goldfish_fb_pan_display: timeout waiting for base update\n");
return 0;
}
diff --git a/drivers/video/hyperv_fb.c b/drivers/video/hyperv_fb.c
new file mode 100644
index 000000000000..d4d2c5fe2488
--- /dev/null
+++ b/drivers/video/hyperv_fb.c
@@ -0,0 +1,829 @@
+/*
+ * Copyright (c) 2012, Microsoft Corporation.
+ *
+ * Author:
+ * Haiyang Zhang <haiyangz@microsoft.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+/*
+ * Hyper-V Synthetic Video Frame Buffer Driver
+ *
+ * This is the driver for the Hyper-V Synthetic Video, which supports
+ * screen resolution up to Full HD 1920x1080 with 32 bit color on Windows
+ * Server 2012, and 1600x1200 with 16 bit color on Windows Server 2008 R2
+ * or earlier.
+ *
+ * It also solves the double mouse cursor issue of the emulated video mode.
+ *
+ * The default screen resolution is 1152x864, which may be changed by a
+ * kernel parameter:
+ * video=hyperv_fb:<width>x<height>
+ * For example: video=hyperv_fb:1280x1024
+ *
+ * Portrait orientation is also supported:
+ * For example: video=hyperv_fb:864x1152
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+#include <linux/hyperv.h>
+
+
+/* Hyper-V Synthetic Video Protocol definitions and structures */
+#define MAX_VMBUS_PKT_SIZE 0x4000
+
+#define SYNTHVID_VERSION(major, minor) ((minor) << 16 | (major))
+#define SYNTHVID_VERSION_WIN7 SYNTHVID_VERSION(3, 0)
+#define SYNTHVID_VERSION_WIN8 SYNTHVID_VERSION(3, 2)
+
+#define SYNTHVID_DEPTH_WIN7 16
+#define SYNTHVID_DEPTH_WIN8 32
+
+#define SYNTHVID_FB_SIZE_WIN7 (4 * 1024 * 1024)
+#define SYNTHVID_WIDTH_MAX_WIN7 1600
+#define SYNTHVID_HEIGHT_MAX_WIN7 1200
+
+#define SYNTHVID_FB_SIZE_WIN8 (8 * 1024 * 1024)
+
+#define PCI_VENDOR_ID_MICROSOFT 0x1414
+#define PCI_DEVICE_ID_HYPERV_VIDEO 0x5353
+
+
+enum pipe_msg_type {
+ PIPE_MSG_INVALID,
+ PIPE_MSG_DATA,
+ PIPE_MSG_MAX
+};
+
+struct pipe_msg_hdr {
+ u32 type;
+ u32 size; /* size of message after this field */
+} __packed;
+
+
+enum synthvid_msg_type {
+ SYNTHVID_ERROR = 0,
+ SYNTHVID_VERSION_REQUEST = 1,
+ SYNTHVID_VERSION_RESPONSE = 2,
+ SYNTHVID_VRAM_LOCATION = 3,
+ SYNTHVID_VRAM_LOCATION_ACK = 4,
+ SYNTHVID_SITUATION_UPDATE = 5,
+ SYNTHVID_SITUATION_UPDATE_ACK = 6,
+ SYNTHVID_POINTER_POSITION = 7,
+ SYNTHVID_POINTER_SHAPE = 8,
+ SYNTHVID_FEATURE_CHANGE = 9,
+ SYNTHVID_DIRT = 10,
+
+ SYNTHVID_MAX = 11
+};
+
+struct synthvid_msg_hdr {
+ u32 type;
+ u32 size; /* size of this header + payload after this field*/
+} __packed;
+
+
+struct synthvid_version_req {
+ u32 version;
+} __packed;
+
+struct synthvid_version_resp {
+ u32 version;
+ u8 is_accepted;
+ u8 max_video_outputs;
+} __packed;
+
+struct synthvid_vram_location {
+ u64 user_ctx;
+ u8 is_vram_gpa_specified;
+ u64 vram_gpa;
+} __packed;
+
+struct synthvid_vram_location_ack {
+ u64 user_ctx;
+} __packed;
+
+struct video_output_situation {
+ u8 active;
+ u32 vram_offset;
+ u8 depth_bits;
+ u32 width_pixels;
+ u32 height_pixels;
+ u32 pitch_bytes;
+} __packed;
+
+struct synthvid_situation_update {
+ u64 user_ctx;
+ u8 video_output_count;
+ struct video_output_situation video_output[1];
+} __packed;
+
+struct synthvid_situation_update_ack {
+ u64 user_ctx;
+} __packed;
+
+struct synthvid_pointer_position {
+ u8 is_visible;
+ u8 video_output;
+ s32 image_x;
+ s32 image_y;
+} __packed;
+
+
+#define CURSOR_MAX_X 96
+#define CURSOR_MAX_Y 96
+#define CURSOR_ARGB_PIXEL_SIZE 4
+#define CURSOR_MAX_SIZE (CURSOR_MAX_X * CURSOR_MAX_Y * CURSOR_ARGB_PIXEL_SIZE)
+#define CURSOR_COMPLETE (-1)
+
+struct synthvid_pointer_shape {
+ u8 part_idx;
+ u8 is_argb;
+ u32 width; /* CURSOR_MAX_X at most */
+ u32 height; /* CURSOR_MAX_Y at most */
+ u32 hot_x; /* hotspot relative to upper-left of pointer image */
+ u32 hot_y;
+ u8 data[4];
+} __packed;
+
+struct synthvid_feature_change {
+ u8 is_dirt_needed;
+ u8 is_ptr_pos_needed;
+ u8 is_ptr_shape_needed;
+ u8 is_situ_needed;
+} __packed;
+
+struct rect {
+ s32 x1, y1; /* top left corner */
+ s32 x2, y2; /* bottom right corner, exclusive */
+} __packed;
+
+struct synthvid_dirt {
+ u8 video_output;
+ u8 dirt_count;
+ struct rect rect[1];
+} __packed;
+
+struct synthvid_msg {
+ struct pipe_msg_hdr pipe_hdr;
+ struct synthvid_msg_hdr vid_hdr;
+ union {
+ struct synthvid_version_req ver_req;
+ struct synthvid_version_resp ver_resp;
+ struct synthvid_vram_location vram;
+ struct synthvid_vram_location_ack vram_ack;
+ struct synthvid_situation_update situ;
+ struct synthvid_situation_update_ack situ_ack;
+ struct synthvid_pointer_position ptr_pos;
+ struct synthvid_pointer_shape ptr_shape;
+ struct synthvid_feature_change feature_chg;
+ struct synthvid_dirt dirt;
+ };
+} __packed;
+
+
+
+/* FB driver definitions and structures */
+#define HVFB_WIDTH 1152 /* default screen width */
+#define HVFB_HEIGHT 864 /* default screen height */
+#define HVFB_WIDTH_MIN 640
+#define HVFB_HEIGHT_MIN 480
+
+#define RING_BUFSIZE (256 * 1024)
+#define VSP_TIMEOUT (10 * HZ)
+#define HVFB_UPDATE_DELAY (HZ / 20)
+
+struct hvfb_par {
+ struct fb_info *info;
+ bool fb_ready; /* fb device is ready */
+ struct completion wait;
+ u32 synthvid_version;
+
+ struct delayed_work dwork;
+ bool update;
+
+ u32 pseudo_palette[16];
+ u8 init_buf[MAX_VMBUS_PKT_SIZE];
+ u8 recv_buf[MAX_VMBUS_PKT_SIZE];
+};
+
+static uint screen_width = HVFB_WIDTH;
+static uint screen_height = HVFB_HEIGHT;
+static uint screen_depth;
+static uint screen_fb_size;
+
+/* Send message to Hyper-V host */
+static inline int synthvid_send(struct hv_device *hdev,
+ struct synthvid_msg *msg)
+{
+ static atomic64_t request_id = ATOMIC64_INIT(0);
+ int ret;
+
+ msg->pipe_hdr.type = PIPE_MSG_DATA;
+ msg->pipe_hdr.size = msg->vid_hdr.size;
+
+ ret = vmbus_sendpacket(hdev->channel, msg,
+ msg->vid_hdr.size + sizeof(struct pipe_msg_hdr),
+ atomic64_inc_return(&request_id),
+ VM_PKT_DATA_INBAND, 0);
+
+ if (ret)
+ pr_err("Unable to send packet via vmbus\n");
+
+ return ret;
+}
+
+
+/* Send screen resolution info to host */
+static int synthvid_send_situ(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct synthvid_msg msg;
+
+ if (!info)
+ return -ENODEV;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+
+ msg.vid_hdr.type = SYNTHVID_SITUATION_UPDATE;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_situation_update);
+ msg.situ.user_ctx = 0;
+ msg.situ.video_output_count = 1;
+ msg.situ.video_output[0].active = 1;
+ msg.situ.video_output[0].vram_offset = 0;
+ msg.situ.video_output[0].depth_bits = info->var.bits_per_pixel;
+ msg.situ.video_output[0].width_pixels = info->var.xres;
+ msg.situ.video_output[0].height_pixels = info->var.yres;
+ msg.situ.video_output[0].pitch_bytes = info->fix.line_length;
+
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+/* Send mouse pointer info to host */
+static int synthvid_send_ptr(struct hv_device *hdev)
+{
+ struct synthvid_msg msg;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+ msg.vid_hdr.type = SYNTHVID_POINTER_POSITION;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_pointer_position);
+ msg.ptr_pos.is_visible = 1;
+ msg.ptr_pos.video_output = 0;
+ msg.ptr_pos.image_x = 0;
+ msg.ptr_pos.image_y = 0;
+ synthvid_send(hdev, &msg);
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+ msg.vid_hdr.type = SYNTHVID_POINTER_SHAPE;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_pointer_shape);
+ msg.ptr_shape.part_idx = CURSOR_COMPLETE;
+ msg.ptr_shape.is_argb = 1;
+ msg.ptr_shape.width = 1;
+ msg.ptr_shape.height = 1;
+ msg.ptr_shape.hot_x = 0;
+ msg.ptr_shape.hot_y = 0;
+ msg.ptr_shape.data[0] = 0;
+ msg.ptr_shape.data[1] = 1;
+ msg.ptr_shape.data[2] = 1;
+ msg.ptr_shape.data[3] = 1;
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+/* Send updated screen area (dirty rectangle) location to host */
+static int synthvid_update(struct fb_info *info)
+{
+ struct hv_device *hdev = device_to_hv_device(info->device);
+ struct synthvid_msg msg;
+
+ memset(&msg, 0, sizeof(struct synthvid_msg));
+
+ msg.vid_hdr.type = SYNTHVID_DIRT;
+ msg.vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_dirt);
+ msg.dirt.video_output = 0;
+ msg.dirt.dirt_count = 1;
+ msg.dirt.rect[0].x1 = 0;
+ msg.dirt.rect[0].y1 = 0;
+ msg.dirt.rect[0].x2 = info->var.xres;
+ msg.dirt.rect[0].y2 = info->var.yres;
+
+ synthvid_send(hdev, &msg);
+
+ return 0;
+}
+
+
+/*
+ * Actions on received messages from host:
+ * Complete the wait event.
+ * Or, reply with screen and cursor info.
+ */
+static void synthvid_recv_sub(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par;
+ struct synthvid_msg *msg;
+
+ if (!info)
+ return;
+
+ par = info->par;
+ msg = (struct synthvid_msg *)par->recv_buf;
+
+ /* Complete the wait event */
+ if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE ||
+ msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) {
+ memcpy(par->init_buf, msg, MAX_VMBUS_PKT_SIZE);
+ complete(&par->wait);
+ return;
+ }
+
+ /* Reply with screen and cursor info */
+ if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
+ if (par->fb_ready) {
+ synthvid_send_ptr(hdev);
+ synthvid_send_situ(hdev);
+ }
+
+ par->update = msg->feature_chg.is_dirt_needed;
+ if (par->update)
+ schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+ }
+}
+
+/* Receive callback for messages from the host */
+static void synthvid_receive(void *ctx)
+{
+ struct hv_device *hdev = ctx;
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par;
+ struct synthvid_msg *recv_buf;
+ u32 bytes_recvd;
+ u64 req_id;
+ int ret;
+
+ if (!info)
+ return;
+
+ par = info->par;
+ recv_buf = (struct synthvid_msg *)par->recv_buf;
+
+ do {
+ ret = vmbus_recvpacket(hdev->channel, recv_buf,
+ MAX_VMBUS_PKT_SIZE,
+ &bytes_recvd, &req_id);
+ if (bytes_recvd > 0 &&
+ recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
+ synthvid_recv_sub(hdev);
+ } while (bytes_recvd > 0 && ret == 0);
+}
+
+/* Check synthetic video protocol version with the host */
+static int synthvid_negotiate_ver(struct hv_device *hdev, u32 ver)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+ int t, ret = 0;
+
+ memset(msg, 0, sizeof(struct synthvid_msg));
+ msg->vid_hdr.type = SYNTHVID_VERSION_REQUEST;
+ msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_version_req);
+ msg->ver_req.version = ver;
+ synthvid_send(hdev, msg);
+
+ t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+ if (!t) {
+ pr_err("Time out on waiting version response\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ if (!msg->ver_resp.is_accepted) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ par->synthvid_version = ver;
+
+out:
+ return ret;
+}
+
+/* Connect to VSP (Virtual Service Provider) on host */
+static int synthvid_connect_vsp(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ int ret;
+
+ ret = vmbus_open(hdev->channel, RING_BUFSIZE, RING_BUFSIZE,
+ NULL, 0, synthvid_receive, hdev);
+ if (ret) {
+ pr_err("Unable to open vmbus channel\n");
+ return ret;
+ }
+
+ /* Negotiate the protocol version with host */
+ if (vmbus_proto_version == VERSION_WS2008 ||
+ vmbus_proto_version == VERSION_WIN7)
+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN7);
+ else
+ ret = synthvid_negotiate_ver(hdev, SYNTHVID_VERSION_WIN8);
+
+ if (ret) {
+ pr_err("Synthetic video device version not accepted\n");
+ goto error;
+ }
+
+ if (par->synthvid_version == SYNTHVID_VERSION_WIN7) {
+ screen_depth = SYNTHVID_DEPTH_WIN7;
+ screen_fb_size = SYNTHVID_FB_SIZE_WIN7;
+ } else {
+ screen_depth = SYNTHVID_DEPTH_WIN8;
+ screen_fb_size = SYNTHVID_FB_SIZE_WIN8;
+ }
+
+ return 0;
+
+error:
+ vmbus_close(hdev->channel);
+ return ret;
+}
+
+/* Send VRAM and Situation messages to the host */
+static int synthvid_send_config(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+ struct synthvid_msg *msg = (struct synthvid_msg *)par->init_buf;
+ int t, ret = 0;
+
+ /* Send VRAM location */
+ memset(msg, 0, sizeof(struct synthvid_msg));
+ msg->vid_hdr.type = SYNTHVID_VRAM_LOCATION;
+ msg->vid_hdr.size = sizeof(struct synthvid_msg_hdr) +
+ sizeof(struct synthvid_vram_location);
+ msg->vram.user_ctx = msg->vram.vram_gpa = info->fix.smem_start;
+ msg->vram.is_vram_gpa_specified = 1;
+ synthvid_send(hdev, msg);
+
+ t = wait_for_completion_timeout(&par->wait, VSP_TIMEOUT);
+ if (!t) {
+ pr_err("Time out on waiting vram location ack\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ if (msg->vram_ack.user_ctx != info->fix.smem_start) {
+ pr_err("Unable to set VRAM location\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Send pointer and situation update */
+ synthvid_send_ptr(hdev);
+ synthvid_send_situ(hdev);
+
+out:
+ return ret;
+}
+
+
+/*
+ * Delayed work callback:
+ * It is called at HVFB_UPDATE_DELAY or longer time interval to process
+ * screen updates. It is re-scheduled if further update is necessary.
+ */
+static void hvfb_update_work(struct work_struct *w)
+{
+ struct hvfb_par *par = container_of(w, struct hvfb_par, dwork.work);
+ struct fb_info *info = par->info;
+
+ if (par->fb_ready)
+ synthvid_update(info);
+
+ if (par->update)
+ schedule_delayed_work(&par->dwork, HVFB_UPDATE_DELAY);
+}
+
+
+/* Framebuffer operation handlers */
+
+static int hvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ if (var->xres < HVFB_WIDTH_MIN || var->yres < HVFB_HEIGHT_MIN ||
+ var->xres > screen_width || var->yres > screen_height ||
+ var->bits_per_pixel != screen_depth)
+ return -EINVAL;
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+
+ return 0;
+}
+
+static int hvfb_set_par(struct fb_info *info)
+{
+ struct hv_device *hdev = device_to_hv_device(info->device);
+
+ return synthvid_send_situ(hdev);
+}
+
+
+static inline u32 chan_to_field(u32 chan, struct fb_bitfield *bf)
+{
+ return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static int hvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp, struct fb_info *info)
+{
+ u32 *pal = info->pseudo_palette;
+
+ if (regno > 15)
+ return -EINVAL;
+
+ pal[regno] = chan_to_field(red, &info->var.red)
+ | chan_to_field(green, &info->var.green)
+ | chan_to_field(blue, &info->var.blue)
+ | chan_to_field(transp, &info->var.transp);
+
+ return 0;
+}
+
+
+static struct fb_ops hvfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = hvfb_check_var,
+ .fb_set_par = hvfb_set_par,
+ .fb_setcolreg = hvfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+
+/* Get options from kernel paramenter "video=" */
+static void hvfb_get_option(struct fb_info *info)
+{
+ struct hvfb_par *par = info->par;
+ char *opt = NULL, *p;
+ uint x = 0, y = 0;
+
+ if (fb_get_options(KBUILD_MODNAME, &opt) || !opt || !*opt)
+ return;
+
+ p = strsep(&opt, "x");
+ if (!*p || kstrtouint(p, 0, &x) ||
+ !opt || !*opt || kstrtouint(opt, 0, &y)) {
+ pr_err("Screen option is invalid: skipped\n");
+ return;
+ }
+
+ if (x < HVFB_WIDTH_MIN || y < HVFB_HEIGHT_MIN ||
+ (par->synthvid_version == SYNTHVID_VERSION_WIN8 &&
+ x * y * screen_depth / 8 > SYNTHVID_FB_SIZE_WIN8) ||
+ (par->synthvid_version == SYNTHVID_VERSION_WIN7 &&
+ (x > SYNTHVID_WIDTH_MAX_WIN7 || y > SYNTHVID_HEIGHT_MAX_WIN7))) {
+ pr_err("Screen resolution option is out of range: skipped\n");
+ return;
+ }
+
+ screen_width = x;
+ screen_height = y;
+ return;
+}
+
+
+/* Get framebuffer memory from Hyper-V video pci space */
+static int hvfb_getmem(struct fb_info *info)
+{
+ struct pci_dev *pdev;
+ ulong fb_phys;
+ void __iomem *fb_virt;
+
+ pdev = pci_get_device(PCI_VENDOR_ID_MICROSOFT,
+ PCI_DEVICE_ID_HYPERV_VIDEO, NULL);
+ if (!pdev) {
+ pr_err("Unable to find PCI Hyper-V video\n");
+ return -ENODEV;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ pci_resource_len(pdev, 0) < screen_fb_size)
+ goto err1;
+
+ fb_phys = pci_resource_end(pdev, 0) - screen_fb_size + 1;
+ if (!request_mem_region(fb_phys, screen_fb_size, KBUILD_MODNAME))
+ goto err1;
+
+ fb_virt = ioremap(fb_phys, screen_fb_size);
+ if (!fb_virt)
+ goto err2;
+
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures)
+ goto err3;
+
+ info->apertures->ranges[0].base = pci_resource_start(pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(pdev, 0);
+ info->fix.smem_start = fb_phys;
+ info->fix.smem_len = screen_fb_size;
+ info->screen_base = fb_virt;
+ info->screen_size = screen_fb_size;
+
+ pci_dev_put(pdev);
+ return 0;
+
+err3:
+ iounmap(fb_virt);
+err2:
+ release_mem_region(fb_phys, screen_fb_size);
+err1:
+ pci_dev_put(pdev);
+ return -ENOMEM;
+}
+
+/* Release the framebuffer */
+static void hvfb_putmem(struct fb_info *info)
+{
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, screen_fb_size);
+}
+
+
+static int hvfb_probe(struct hv_device *hdev,
+ const struct hv_vmbus_device_id *dev_id)
+{
+ struct fb_info *info;
+ struct hvfb_par *par;
+ int ret;
+
+ info = framebuffer_alloc(sizeof(struct hvfb_par), &hdev->device);
+ if (!info) {
+ pr_err("No memory for framebuffer info\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ par->info = info;
+ par->fb_ready = false;
+ init_completion(&par->wait);
+ INIT_DELAYED_WORK(&par->dwork, hvfb_update_work);
+
+ /* Connect to VSP */
+ hv_set_drvdata(hdev, info);
+ ret = synthvid_connect_vsp(hdev);
+ if (ret) {
+ pr_err("Unable to connect to VSP\n");
+ goto error1;
+ }
+
+ ret = hvfb_getmem(info);
+ if (ret) {
+ pr_err("No memory for framebuffer\n");
+ goto error2;
+ }
+
+ hvfb_get_option(info);
+ pr_info("Screen resolution: %dx%d, Color depth: %d\n",
+ screen_width, screen_height, screen_depth);
+
+
+ /* Set up fb_info */
+ info->flags = FBINFO_DEFAULT;
+
+ info->var.xres_virtual = info->var.xres = screen_width;
+ info->var.yres_virtual = info->var.yres = screen_height;
+ info->var.bits_per_pixel = screen_depth;
+
+ if (info->var.bits_per_pixel == 16) {
+ info->var.red = (struct fb_bitfield){11, 5, 0};
+ info->var.green = (struct fb_bitfield){5, 6, 0};
+ info->var.blue = (struct fb_bitfield){0, 5, 0};
+ info->var.transp = (struct fb_bitfield){0, 0, 0};
+ } else {
+ info->var.red = (struct fb_bitfield){16, 8, 0};
+ info->var.green = (struct fb_bitfield){8, 8, 0};
+ info->var.blue = (struct fb_bitfield){0, 8, 0};
+ info->var.transp = (struct fb_bitfield){24, 8, 0};
+ }
+
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ strcpy(info->fix.id, KBUILD_MODNAME);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = screen_width * screen_depth / 8;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->fbops = &hvfb_ops;
+ info->pseudo_palette = par->pseudo_palette;
+
+ /* Send config to host */
+ ret = synthvid_send_config(hdev);
+ if (ret)
+ goto error;
+
+ ret = register_framebuffer(info);
+ if (ret) {
+ pr_err("Unable to register framebuffer\n");
+ goto error;
+ }
+
+ par->fb_ready = true;
+
+ return 0;
+
+error:
+ hvfb_putmem(info);
+error2:
+ vmbus_close(hdev->channel);
+error1:
+ cancel_delayed_work_sync(&par->dwork);
+ hv_set_drvdata(hdev, NULL);
+ framebuffer_release(info);
+ return ret;
+}
+
+
+static int hvfb_remove(struct hv_device *hdev)
+{
+ struct fb_info *info = hv_get_drvdata(hdev);
+ struct hvfb_par *par = info->par;
+
+ par->update = false;
+ par->fb_ready = false;
+
+ unregister_framebuffer(info);
+ cancel_delayed_work_sync(&par->dwork);
+
+ vmbus_close(hdev->channel);
+ hv_set_drvdata(hdev, NULL);
+
+ hvfb_putmem(info);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+
+static const struct hv_vmbus_device_id id_table[] = {
+ /* Synthetic Video Device GUID */
+ {HV_SYNTHVID_GUID},
+ {}
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static struct hv_driver hvfb_drv = {
+ .name = KBUILD_MODNAME,
+ .id_table = id_table,
+ .probe = hvfb_probe,
+ .remove = hvfb_remove,
+};
+
+
+static int __init hvfb_drv_init(void)
+{
+ return vmbus_driver_register(&hvfb_drv);
+}
+
+static void __exit hvfb_drv_exit(void)
+{
+ vmbus_driver_unregister(&hvfb_drv);
+}
+
+module_init(hvfb_drv_init);
+module_exit(hvfb_drv_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic Video Frame Buffer Driver");
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 217678e0b983..fd2897455696 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -137,8 +137,20 @@ static int* get_ctrl_ptr(struct maven_data* md, int idx) {
static int maven_get_reg(struct i2c_client* c, char reg) {
char dst;
- struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
- { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
+ struct i2c_msg msgs[] = {
+ {
+ .addr = c->addr,
+ .flags = I2C_M_REV_DIR_ADDR,
+ .len = sizeof(reg),
+ .buf = &reg
+ },
+ {
+ .addr = c->addr,
+ .flags = I2C_M_RD | I2C_M_NOSTART,
+ .len = sizeof(dst),
+ .buf = &dst
+ }
+ };
s32 err;
err = i2c_transfer(c->adapter, msgs, 2);
diff --git a/drivers/video/mmp/core.c b/drivers/video/mmp/core.c
index 9ed83419038b..84de2632857a 100644
--- a/drivers/video/mmp/core.c
+++ b/drivers/video/mmp/core.c
@@ -252,7 +252,5 @@ void mmp_unregister_path(struct mmp_path *path)
kfree(path);
mutex_unlock(&disp_lock);
-
- dev_info(path->dev, "de-register %s\n", path->name);
}
EXPORT_SYMBOL_GPL(mmp_unregister_path);
diff --git a/drivers/video/mmp/hw/mmp_ctrl.h b/drivers/video/mmp/hw/mmp_ctrl.h
index 6408d8ef3abb..edd2002b0e99 100644
--- a/drivers/video/mmp/hw/mmp_ctrl.h
+++ b/drivers/video/mmp/hw/mmp_ctrl.h
@@ -961,56 +961,7 @@ struct lcd_regs {
LCD_TVG_CUTVLN : PN2_LCD_GRA_CUTVLN) : LCD_GRA_CUTVLN)
/*
- * defined Video Memory Color format for DMA control 0 register
- * DMA0 bit[23:20]
- */
-#define VMODE_RGB565 0x0
-#define VMODE_RGB1555 0x1
-#define VMODE_RGB888PACKED 0x2
-#define VMODE_RGB888UNPACKED 0x3
-#define VMODE_RGBA888 0x4
-#define VMODE_YUV422PACKED 0x5
-#define VMODE_YUV422PLANAR 0x6
-#define VMODE_YUV420PLANAR 0x7
-#define VMODE_SMPNCMD 0x8
-#define VMODE_PALETTE4BIT 0x9
-#define VMODE_PALETTE8BIT 0xa
-#define VMODE_RESERVED 0xb
-
-/*
- * defined Graphic Memory Color format for DMA control 0 register
- * DMA0 bit[19:16]
- */
-#define GMODE_RGB565 0x0
-#define GMODE_RGB1555 0x1
-#define GMODE_RGB888PACKED 0x2
-#define GMODE_RGB888UNPACKED 0x3
-#define GMODE_RGBA888 0x4
-#define GMODE_YUV422PACKED 0x5
-#define GMODE_YUV422PLANAR 0x6
-#define GMODE_YUV420PLANAR 0x7
-#define GMODE_SMPNCMD 0x8
-#define GMODE_PALETTE4BIT 0x9
-#define GMODE_PALETTE8BIT 0xa
-#define GMODE_RESERVED 0xb
-
-/*
- * define for DMA control 1 register
- */
-#define DMA1_FRAME_TRIG 31 /* bit location */
-#define DMA1_VSYNC_MODE 28
-#define DMA1_VSYNC_INV 27
-#define DMA1_CKEY 24
-#define DMA1_CARRY 23
-#define DMA1_LNBUF_ENA 22
-#define DMA1_GATED_ENA 21
-#define DMA1_PWRDN_ENA 20
-#define DMA1_DSCALE 18
-#define DMA1_ALPHA_MODE 16
-#define DMA1_ALPHA 08
-#define DMA1_PXLCMD 00
-
-/*
+ * defined for Configure Dumb Mode
* defined for Configure Dumb Mode
* DUMB LCD Panel bit[31:28]
*/
@@ -1050,18 +1001,6 @@ struct lcd_regs {
#define CFG_CYC_BURST_LEN16 (1<<4)
#define CFG_CYC_BURST_LEN8 (0<<4)
-/*
- * defined Dumb Panel Clock Divider register
- * SCLK_Source bit[31]
- */
- /* 0: PLL clock select*/
-#define AXI_BUS_SEL 0x80000000
-#define CCD_CLK_SEL 0x40000000
-#define DCON_CLK_SEL 0x20000000
-#define ENA_CLK_INT_DIV CONFIG_FB_DOVE_CLCD_SCLK_DIV
-#define IDLE_CLK_INT_DIV 0x1 /* idle Integer Divider */
-#define DIS_CLK_INT_DIV 0x0 /* Disable Integer Divider */
-
/* SRAM ID */
#define SRAMID_GAMMA_YR 0x0
#define SRAMID_GAMMA_UG 0x1
@@ -1471,422 +1410,6 @@ struct dsi_regs {
#define LVDS_FREQ_OFFSET_MODE_CK_DIV4_OUT (0x1 << 1)
#define LVDS_FREQ_OFFSET_MODE_EN (0x1 << 0)
-/* VDMA */
-struct vdma_ch_regs {
-#define VDMA_DC_SADDR_1 0x320
-#define VDMA_DC_SADDR_2 0x3A0
-#define VDMA_DC_SZ_1 0x324
-#define VDMA_DC_SZ_2 0x3A4
-#define VDMA_CTRL_1 0x328
-#define VDMA_CTRL_2 0x3A8
-#define VDMA_SRC_SZ_1 0x32C
-#define VDMA_SRC_SZ_2 0x3AC
-#define VDMA_SA_1 0x330
-#define VDMA_SA_2 0x3B0
-#define VDMA_DA_1 0x334
-#define VDMA_DA_2 0x3B4
-#define VDMA_SZ_1 0x338
-#define VDMA_SZ_2 0x3B8
- u32 dc_saddr;
- u32 dc_size;
- u32 ctrl;
- u32 src_size;
- u32 src_addr;
- u32 dst_addr;
- u32 dst_size;
-#define VDMA_PITCH_1 0x33C
-#define VDMA_PITCH_2 0x3BC
-#define VDMA_ROT_CTRL_1 0x340
-#define VDMA_ROT_CTRL_2 0x3C0
-#define VDMA_RAM_CTRL0_1 0x344
-#define VDMA_RAM_CTRL0_2 0x3C4
-#define VDMA_RAM_CTRL1_1 0x348
-#define VDMA_RAM_CTRL1_2 0x3C8
- u32 pitch;
- u32 rot_ctrl;
- u32 ram_ctrl0;
- u32 ram_ctrl1;
-
-};
-struct vdma_regs {
-#define VDMA_ARBR_CTRL 0x300
-#define VDMA_IRQR 0x304
-#define VDMA_IRQM 0x308
-#define VDMA_IRQS 0x30C
-#define VDMA_MDMA_ARBR_CTRL 0x310
- u32 arbr_ctr;
- u32 irq_raw;
- u32 irq_mask;
- u32 irq_status;
- u32 mdma_arbr_ctrl;
- u32 reserved[3];
-
- struct vdma_ch_regs ch1;
- u32 reserved2[21];
- struct vdma_ch_regs ch2;
-};
-
-/* CMU */
-#define CMU_PIP_DE_H_CFG 0x0008
-#define CMU_PRI1_H_CFG 0x000C
-#define CMU_PRI2_H_CFG 0x0010
-#define CMU_ACE_MAIN_DE1_H_CFG 0x0014
-#define CMU_ACE_MAIN_DE2_H_CFG 0x0018
-#define CMU_ACE_PIP_DE1_H_CFG 0x001C
-#define CMU_ACE_PIP_DE2_H_CFG 0x0020
-#define CMU_PIP_DE_V_CFG 0x0024
-#define CMU_PRI_V_CFG 0x0028
-#define CMU_ACE_MAIN_DE_V_CFG 0x002C
-#define CMU_ACE_PIP_DE_V_CFG 0x0030
-#define CMU_BAR_0_CFG 0x0034
-#define CMU_BAR_1_CFG 0x0038
-#define CMU_BAR_2_CFG 0x003C
-#define CMU_BAR_3_CFG 0x0040
-#define CMU_BAR_4_CFG 0x0044
-#define CMU_BAR_5_CFG 0x0048
-#define CMU_BAR_6_CFG 0x004C
-#define CMU_BAR_7_CFG 0x0050
-#define CMU_BAR_8_CFG 0x0054
-#define CMU_BAR_9_CFG 0x0058
-#define CMU_BAR_10_CFG 0x005C
-#define CMU_BAR_11_CFG 0x0060
-#define CMU_BAR_12_CFG 0x0064
-#define CMU_BAR_13_CFG 0x0068
-#define CMU_BAR_14_CFG 0x006C
-#define CMU_BAR_15_CFG 0x0070
-#define CMU_BAR_CTRL 0x0074
-#define PATTERN_TOTAL 0x0078
-#define PATTERN_ACTIVE 0x007C
-#define PATTERN_FRONT_PORCH 0x0080
-#define PATTERN_BACK_PORCH 0x0084
-#define CMU_CLK_CTRL 0x0088
-
-#define CMU_ICSC_M_C0_L 0x0900
-#define CMU_ICSC_M_C0_H 0x0901
-#define CMU_ICSC_M_C1_L 0x0902
-#define CMU_ICSC_M_C1_H 0x0903
-#define CMU_ICSC_M_C2_L 0x0904
-#define CMU_ICSC_M_C2_H 0x0905
-#define CMU_ICSC_M_C3_L 0x0906
-#define CMU_ICSC_M_C3_H 0x0907
-#define CMU_ICSC_M_C4_L 0x0908
-#define CMU_ICSC_M_C4_H 0x0909
-#define CMU_ICSC_M_C5_L 0x090A
-#define CMU_ICSC_M_C5_H 0x090B
-#define CMU_ICSC_M_C6_L 0x090C
-#define CMU_ICSC_M_C6_H 0x090D
-#define CMU_ICSC_M_C7_L 0x090E
-#define CMU_ICSC_M_C7_H 0x090F
-#define CMU_ICSC_M_C8_L 0x0910
-#define CMU_ICSC_M_C8_H 0x0911
-#define CMU_ICSC_M_O1_0 0x0914
-#define CMU_ICSC_M_O1_1 0x0915
-#define CMU_ICSC_M_O1_2 0x0916
-#define CMU_ICSC_M_O2_0 0x0918
-#define CMU_ICSC_M_O2_1 0x0919
-#define CMU_ICSC_M_O2_2 0x091A
-#define CMU_ICSC_M_O3_0 0x091C
-#define CMU_ICSC_M_O3_1 0x091D
-#define CMU_ICSC_M_O3_2 0x091E
-#define CMU_ICSC_P_C0_L 0x0920
-#define CMU_ICSC_P_C0_H 0x0921
-#define CMU_ICSC_P_C1_L 0x0922
-#define CMU_ICSC_P_C1_H 0x0923
-#define CMU_ICSC_P_C2_L 0x0924
-#define CMU_ICSC_P_C2_H 0x0925
-#define CMU_ICSC_P_C3_L 0x0926
-#define CMU_ICSC_P_C3_H 0x0927
-#define CMU_ICSC_P_C4_L 0x0928
-#define CMU_ICSC_P_C4_H 0x0929
-#define CMU_ICSC_P_C5_L 0x092A
-#define CMU_ICSC_P_C5_H 0x092B
-#define CMU_ICSC_P_C6_L 0x092C
-#define CMU_ICSC_P_C6_H 0x092D
-#define CMU_ICSC_P_C7_L 0x092E
-#define CMU_ICSC_P_C7_H 0x092F
-#define CMU_ICSC_P_C8_L 0x0930
-#define CMU_ICSC_P_C8_H 0x0931
-#define CMU_ICSC_P_O1_0 0x0934
-#define CMU_ICSC_P_O1_1 0x0935
-#define CMU_ICSC_P_O1_2 0x0936
-#define CMU_ICSC_P_O2_0 0x0938
-#define CMU_ICSC_P_O2_1 0x0939
-#define CMU_ICSC_P_O2_2 0x093A
-#define CMU_ICSC_P_O3_0 0x093C
-#define CMU_ICSC_P_O3_1 0x093D
-#define CMU_ICSC_P_O3_2 0x093E
-#define CMU_BR_M_EN 0x0940
-#define CMU_BR_M_TH1_L 0x0942
-#define CMU_BR_M_TH1_H 0x0943
-#define CMU_BR_M_TH2_L 0x0944
-#define CMU_BR_M_TH2_H 0x0945
-#define CMU_ACE_M_EN 0x0950
-#define CMU_ACE_M_WFG1 0x0951
-#define CMU_ACE_M_WFG2 0x0952
-#define CMU_ACE_M_WFG3 0x0953
-#define CMU_ACE_M_TH0 0x0954
-#define CMU_ACE_M_TH1 0x0955
-#define CMU_ACE_M_TH2 0x0956
-#define CMU_ACE_M_TH3 0x0957
-#define CMU_ACE_M_TH4 0x0958
-#define CMU_ACE_M_TH5 0x0959
-#define CMU_ACE_M_OP0_L 0x095A
-#define CMU_ACE_M_OP0_H 0x095B
-#define CMU_ACE_M_OP5_L 0x095C
-#define CMU_ACE_M_OP5_H 0x095D
-#define CMU_ACE_M_GB2 0x095E
-#define CMU_ACE_M_GB3 0x095F
-#define CMU_ACE_M_MS1 0x0960
-#define CMU_ACE_M_MS2 0x0961
-#define CMU_ACE_M_MS3 0x0962
-#define CMU_BR_P_EN 0x0970
-#define CMU_BR_P_TH1_L 0x0972
-#define CMU_BR_P_TH1_H 0x0973
-#define CMU_BR_P_TH2_L 0x0974
-#define CMU_BR_P_TH2_H 0x0975
-#define CMU_ACE_P_EN 0x0980
-#define CMU_ACE_P_WFG1 0x0981
-#define CMU_ACE_P_WFG2 0x0982
-#define CMU_ACE_P_WFG3 0x0983
-#define CMU_ACE_P_TH0 0x0984
-#define CMU_ACE_P_TH1 0x0985
-#define CMU_ACE_P_TH2 0x0986
-#define CMU_ACE_P_TH3 0x0987
-#define CMU_ACE_P_TH4 0x0988
-#define CMU_ACE_P_TH5 0x0989
-#define CMU_ACE_P_OP0_L 0x098A
-#define CMU_ACE_P_OP0_H 0x098B
-#define CMU_ACE_P_OP5_L 0x098C
-#define CMU_ACE_P_OP5_H 0x098D
-#define CMU_ACE_P_GB2 0x098E
-#define CMU_ACE_P_GB3 0x098F
-#define CMU_ACE_P_MS1 0x0990
-#define CMU_ACE_P_MS2 0x0991
-#define CMU_ACE_P_MS3 0x0992
-#define CMU_FTDC_M_EN 0x09A0
-#define CMU_FTDC_P_EN 0x09A1
-#define CMU_FTDC_INLOW_L 0x09A2
-#define CMU_FTDC_INLOW_H 0x09A3
-#define CMU_FTDC_INHIGH_L 0x09A4
-#define CMU_FTDC_INHIGH_H 0x09A5
-#define CMU_FTDC_OUTLOW_L 0x09A6
-#define CMU_FTDC_OUTLOW_H 0x09A7
-#define CMU_FTDC_OUTHIGH_L 0x09A8
-#define CMU_FTDC_OUTHIGH_H 0x09A9
-#define CMU_FTDC_YLOW 0x09AA
-#define CMU_FTDC_YHIGH 0x09AB
-#define CMU_FTDC_CH1 0x09AC
-#define CMU_FTDC_CH2_L 0x09AE
-#define CMU_FTDC_CH2_H 0x09AF
-#define CMU_FTDC_CH3_L 0x09B0
-#define CMU_FTDC_CH3_H 0x09B1
-#define CMU_FTDC_1_C00_6 0x09B2
-#define CMU_FTDC_1_C01_6 0x09B8
-#define CMU_FTDC_1_C11_6 0x09BE
-#define CMU_FTDC_1_C10_6 0x09C4
-#define CMU_FTDC_1_OFF00_6 0x09CA
-#define CMU_FTDC_1_OFF10_6 0x09D0
-#define CMU_HS_M_EN 0x0A00
-#define CMU_HS_M_AX1_L 0x0A02
-#define CMU_HS_M_AX1_H 0x0A03
-#define CMU_HS_M_AX2_L 0x0A04
-#define CMU_HS_M_AX2_H 0x0A05
-#define CMU_HS_M_AX3_L 0x0A06
-#define CMU_HS_M_AX3_H 0x0A07
-#define CMU_HS_M_AX4_L 0x0A08
-#define CMU_HS_M_AX4_H 0x0A09
-#define CMU_HS_M_AX5_L 0x0A0A
-#define CMU_HS_M_AX5_H 0x0A0B
-#define CMU_HS_M_AX6_L 0x0A0C
-#define CMU_HS_M_AX6_H 0x0A0D
-#define CMU_HS_M_AX7_L 0x0A0E
-#define CMU_HS_M_AX7_H 0x0A0F
-#define CMU_HS_M_AX8_L 0x0A10
-#define CMU_HS_M_AX8_H 0x0A11
-#define CMU_HS_M_AX9_L 0x0A12
-#define CMU_HS_M_AX9_H 0x0A13
-#define CMU_HS_M_AX10_L 0x0A14
-#define CMU_HS_M_AX10_H 0x0A15
-#define CMU_HS_M_AX11_L 0x0A16
-#define CMU_HS_M_AX11_H 0x0A17
-#define CMU_HS_M_AX12_L 0x0A18
-#define CMU_HS_M_AX12_H 0x0A19
-#define CMU_HS_M_AX13_L 0x0A1A
-#define CMU_HS_M_AX13_H 0x0A1B
-#define CMU_HS_M_AX14_L 0x0A1C
-#define CMU_HS_M_AX14_H 0x0A1D
-#define CMU_HS_M_H1_H14 0x0A1E
-#define CMU_HS_M_S1_S14 0x0A2C
-#define CMU_HS_M_GL 0x0A3A
-#define CMU_HS_M_MAXSAT_RGB_Y_L 0x0A3C
-#define CMU_HS_M_MAXSAT_RGB_Y_H 0x0A3D
-#define CMU_HS_M_MAXSAT_RCR_L 0x0A3E
-#define CMU_HS_M_MAXSAT_RCR_H 0x0A3F
-#define CMU_HS_M_MAXSAT_RCB_L 0x0A40
-#define CMU_HS_M_MAXSAT_RCB_H 0x0A41
-#define CMU_HS_M_MAXSAT_GCR_L 0x0A42
-#define CMU_HS_M_MAXSAT_GCR_H 0x0A43
-#define CMU_HS_M_MAXSAT_GCB_L 0x0A44
-#define CMU_HS_M_MAXSAT_GCB_H 0x0A45
-#define CMU_HS_M_MAXSAT_BCR_L 0x0A46
-#define CMU_HS_M_MAXSAT_BCR_H 0x0A47
-#define CMU_HS_M_MAXSAT_BCB_L 0x0A48
-#define CMU_HS_M_MAXSAT_BCB_H 0x0A49
-#define CMU_HS_M_ROFF_L 0x0A4A
-#define CMU_HS_M_ROFF_H 0x0A4B
-#define CMU_HS_M_GOFF_L 0x0A4C
-#define CMU_HS_M_GOFF_H 0x0A4D
-#define CMU_HS_M_BOFF_L 0x0A4E
-#define CMU_HS_M_BOFF_H 0x0A4F
-#define CMU_HS_P_EN 0x0A50
-#define CMU_HS_P_AX1_L 0x0A52
-#define CMU_HS_P_AX1_H 0x0A53
-#define CMU_HS_P_AX2_L 0x0A54
-#define CMU_HS_P_AX2_H 0x0A55
-#define CMU_HS_P_AX3_L 0x0A56
-#define CMU_HS_P_AX3_H 0x0A57
-#define CMU_HS_P_AX4_L 0x0A58
-#define CMU_HS_P_AX4_H 0x0A59
-#define CMU_HS_P_AX5_L 0x0A5A
-#define CMU_HS_P_AX5_H 0x0A5B
-#define CMU_HS_P_AX6_L 0x0A5C
-#define CMU_HS_P_AX6_H 0x0A5D
-#define CMU_HS_P_AX7_L 0x0A5E
-#define CMU_HS_P_AX7_H 0x0A5F
-#define CMU_HS_P_AX8_L 0x0A60
-#define CMU_HS_P_AX8_H 0x0A61
-#define CMU_HS_P_AX9_L 0x0A62
-#define CMU_HS_P_AX9_H 0x0A63
-#define CMU_HS_P_AX10_L 0x0A64
-#define CMU_HS_P_AX10_H 0x0A65
-#define CMU_HS_P_AX11_L 0x0A66
-#define CMU_HS_P_AX11_H 0x0A67
-#define CMU_HS_P_AX12_L 0x0A68
-#define CMU_HS_P_AX12_H 0x0A69
-#define CMU_HS_P_AX13_L 0x0A6A
-#define CMU_HS_P_AX13_H 0x0A6B
-#define CMU_HS_P_AX14_L 0x0A6C
-#define CMU_HS_P_AX14_H 0x0A6D
-#define CMU_HS_P_H1_H14 0x0A6E
-#define CMU_HS_P_S1_S14 0x0A7C
-#define CMU_HS_P_GL 0x0A8A
-#define CMU_HS_P_MAXSAT_RGB_Y_L 0x0A8C
-#define CMU_HS_P_MAXSAT_RGB_Y_H 0x0A8D
-#define CMU_HS_P_MAXSAT_RCR_L 0x0A8E
-#define CMU_HS_P_MAXSAT_RCR_H 0x0A8F
-#define CMU_HS_P_MAXSAT_RCB_L 0x0A90
-#define CMU_HS_P_MAXSAT_RCB_H 0x0A91
-#define CMU_HS_P_MAXSAT_GCR_L 0x0A92
-#define CMU_HS_P_MAXSAT_GCR_H 0x0A93
-#define CMU_HS_P_MAXSAT_GCB_L 0x0A94
-#define CMU_HS_P_MAXSAT_GCB_H 0x0A95
-#define CMU_HS_P_MAXSAT_BCR_L 0x0A96
-#define CMU_HS_P_MAXSAT_BCR_H 0x0A97
-#define CMU_HS_P_MAXSAT_BCB_L 0x0A98
-#define CMU_HS_P_MAXSAT_BCB_H 0x0A99
-#define CMU_HS_P_ROFF_L 0x0A9A
-#define CMU_HS_P_ROFF_H 0x0A9B
-#define CMU_HS_P_GOFF_L 0x0A9C
-#define CMU_HS_P_GOFF_H 0x0A9D
-#define CMU_HS_P_BOFF_L 0x0A9E
-#define CMU_HS_P_BOFF_H 0x0A9F
-#define CMU_GLCSC_M_C0_L 0x0AA0
-#define CMU_GLCSC_M_C0_H 0x0AA1
-#define CMU_GLCSC_M_C1_L 0x0AA2
-#define CMU_GLCSC_M_C1_H 0x0AA3
-#define CMU_GLCSC_M_C2_L 0x0AA4
-#define CMU_GLCSC_M_C2_H 0x0AA5
-#define CMU_GLCSC_M_C3_L 0x0AA6
-#define CMU_GLCSC_M_C3_H 0x0AA7
-#define CMU_GLCSC_M_C4_L 0x0AA8
-#define CMU_GLCSC_M_C4_H 0x0AA9
-#define CMU_GLCSC_M_C5_L 0x0AAA
-#define CMU_GLCSC_M_C5_H 0x0AAB
-#define CMU_GLCSC_M_C6_L 0x0AAC
-#define CMU_GLCSC_M_C6_H 0x0AAD
-#define CMU_GLCSC_M_C7_L 0x0AAE
-#define CMU_GLCSC_M_C7_H 0x0AAF
-#define CMU_GLCSC_M_C8_L 0x0AB0
-#define CMU_GLCSC_M_C8_H 0x0AB1
-#define CMU_GLCSC_M_O1_1 0x0AB4
-#define CMU_GLCSC_M_O1_2 0x0AB5
-#define CMU_GLCSC_M_O1_3 0x0AB6
-#define CMU_GLCSC_M_O2_1 0x0AB8
-#define CMU_GLCSC_M_O2_2 0x0AB9
-#define CMU_GLCSC_M_O2_3 0x0ABA
-#define CMU_GLCSC_M_O3_1 0x0ABC
-#define CMU_GLCSC_M_O3_2 0x0ABD
-#define CMU_GLCSC_M_O3_3 0x0ABE
-#define CMU_GLCSC_P_C0_L 0x0AC0
-#define CMU_GLCSC_P_C0_H 0x0AC1
-#define CMU_GLCSC_P_C1_L 0x0AC2
-#define CMU_GLCSC_P_C1_H 0x0AC3
-#define CMU_GLCSC_P_C2_L 0x0AC4
-#define CMU_GLCSC_P_C2_H 0x0AC5
-#define CMU_GLCSC_P_C3_L 0x0AC6
-#define CMU_GLCSC_P_C3_H 0x0AC7
-#define CMU_GLCSC_P_C4_L 0x0AC8
-#define CMU_GLCSC_P_C4_H 0x0AC9
-#define CMU_GLCSC_P_C5_L 0x0ACA
-#define CMU_GLCSC_P_C5_H 0x0ACB
-#define CMU_GLCSC_P_C6_L 0x0ACC
-#define CMU_GLCSC_P_C6_H 0x0ACD
-#define CMU_GLCSC_P_C7_L 0x0ACE
-#define CMU_GLCSC_P_C7_H 0x0ACF
-#define CMU_GLCSC_P_C8_L 0x0AD0
-#define CMU_GLCSC_P_C8_H 0x0AD1
-#define CMU_GLCSC_P_O1_1 0x0AD4
-#define CMU_GLCSC_P_O1_2 0x0AD5
-#define CMU_GLCSC_P_O1_3 0x0AD6
-#define CMU_GLCSC_P_O2_1 0x0AD8
-#define CMU_GLCSC_P_O2_2 0x0AD9
-#define CMU_GLCSC_P_O2_3 0x0ADA
-#define CMU_GLCSC_P_O3_1 0x0ADC
-#define CMU_GLCSC_P_O3_2 0x0ADD
-#define CMU_GLCSC_P_O3_3 0x0ADE
-#define CMU_PIXVAL_M_EN 0x0AE0
-#define CMU_PIXVAL_P_EN 0x0AE1
-
-#define CMU_CLK_CTRL_TCLK 0x0
-#define CMU_CLK_CTRL_SCLK 0x2
-#define CMU_CLK_CTRL_MSK 0x2
-#define CMU_CLK_CTRL_ENABLE 0x1
-
-#define LCD_TOP_CTRL_TV 0x2
-#define LCD_TOP_CTRL_PN 0x0
-#define LCD_TOP_CTRL_SEL_MSK 0x2
-#define LCD_IO_CMU_IN_SEL_MSK (0x3 << 20)
-#define LCD_IO_CMU_IN_SEL_TV 0
-#define LCD_IO_CMU_IN_SEL_PN 1
-#define LCD_IO_CMU_IN_SEL_PN2 2
-#define LCD_IO_TV_OUT_SEL_MSK (0x3 << 26)
-#define LCD_IO_PN_OUT_SEL_MSK (0x3 << 24)
-#define LCD_IO_PN2_OUT_SEL_MSK (0x3 << 28)
-#define LCD_IO_TV_OUT_SEL_NON 3
-#define LCD_IO_PN_OUT_SEL_NON 3
-#define LCD_IO_PN2_OUT_SEL_NON 3
-#define LCD_TOP_CTRL_CMU_ENABLE 0x1
-#define LCD_IO_OVERL_MSK 0xC00000
-#define LCD_IO_OVERL_TV 0x0
-#define LCD_IO_OVERL_LCD1 0x400000
-#define LCD_IO_OVERL_LCD2 0xC00000
-#define HINVERT_MSK 0x4
-#define VINVERT_MSK 0x8
-#define HINVERT_LEN 0x2
-#define VINVERT_LEN 0x3
-
-#define CMU_CTRL 0x88
-#define CMU_CTRL_A0_MSK 0x6
-#define CMU_CTRL_A0_TV 0x0
-#define CMU_CTRL_A0_LCD1 0x1
-#define CMU_CTRL_A0_LCD2 0x2
-#define CMU_CTRL_A0_HDMI 0x3
-
-#define ICR_DRV_ROUTE_OFF 0x0
-#define ICR_DRV_ROUTE_TV 0x1
-#define ICR_DRV_ROUTE_LCD1 0x2
-#define ICR_DRV_ROUTE_LCD2 0x3
-
enum {
PATH_PN = 0,
PATH_TV,
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
index 13ecd9897010..56009bc02b02 100644
--- a/drivers/video/of_display_timing.c
+++ b/drivers/video/of_display_timing.c
@@ -79,25 +79,24 @@ static struct display_timing *of_get_display_timing(struct device_node *np)
ret |= parse_timing_property(np, "vsync-len", &dt->vsync_len);
ret |= parse_timing_property(np, "clock-frequency", &dt->pixelclock);
- dt->dmt_flags = 0;
- dt->data_flags = 0;
+ dt->flags = 0;
if (!of_property_read_u32(np, "vsync-active", &val))
- dt->dmt_flags |= val ? VESA_DMT_VSYNC_HIGH :
- VESA_DMT_VSYNC_LOW;
+ dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
+ DISPLAY_FLAGS_VSYNC_LOW;
if (!of_property_read_u32(np, "hsync-active", &val))
- dt->dmt_flags |= val ? VESA_DMT_HSYNC_HIGH :
- VESA_DMT_HSYNC_LOW;
+ dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
+ DISPLAY_FLAGS_HSYNC_LOW;
if (!of_property_read_u32(np, "de-active", &val))
- dt->data_flags |= val ? DISPLAY_FLAGS_DE_HIGH :
+ dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
DISPLAY_FLAGS_DE_LOW;
if (!of_property_read_u32(np, "pixelclk-active", &val))
- dt->data_flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
+ dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
DISPLAY_FLAGS_PIXDATA_NEGEDGE;
if (of_property_read_bool(np, "interlaced"))
- dt->data_flags |= DISPLAY_FLAGS_INTERLACED;
+ dt->flags |= DISPLAY_FLAGS_INTERLACED;
if (of_property_read_bool(np, "doublescan"))
- dt->data_flags |= DISPLAY_FLAGS_DOUBLESCAN;
+ dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
if (ret) {
pr_err("%s: error reading timing properties\n",
diff --git a/drivers/video/of_videomode.c b/drivers/video/of_videomode.c
index 5b8066cd397f..111c2d1911d3 100644
--- a/drivers/video/of_videomode.c
+++ b/drivers/video/of_videomode.c
@@ -43,7 +43,7 @@ int of_get_videomode(struct device_node *np, struct videomode *vm,
if (index == OF_USE_NATIVE_MODE)
index = disp->native_mode;
- ret = videomode_from_timing(disp, vm, index);
+ ret = videomode_from_timings(disp, vm, index);
if (ret)
return ret;
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index e512581300fc..0bc3a936ce2b 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -39,17 +39,6 @@ config FB_OMAP_LCD_MIPID
the Mobile Industry Processor Interface DBI-C/DCS
specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
-config FB_OMAP_CONSISTENT_DMA_SIZE
- int "Consistent DMA memory size (MB)"
- depends on FB_OMAP
- range 1 14
- default 2
- help
- Increase the DMA consistent memory size according to your video
- memory needs, for example if you want to use multiple planes.
- The size must be 2MB aligned.
- If unsure say 1.
-
config FB_OMAP_DMA_TUNE
bool "Set DMA SDRAM access priority high"
depends on FB_OMAP
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index e31f5b33b501..d40612c31a98 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -32,6 +32,8 @@
#include <linux/omap-dma.h>
+#include <mach/hardware.h>
+
#include "omapfb.h"
#include "lcdc.h"
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
index 6b6643911d29..048c98381ef6 100644
--- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
+++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c
@@ -63,6 +63,9 @@ struct tpo_td043_device {
u32 power_on_resume:1;
};
+/* used to pass spi_device from SPI to DSS portion of the driver */
+static struct tpo_td043_device *g_tpo_td043;
+
static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
{
struct spi_message m;
@@ -403,7 +406,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
static int tpo_td043_probe(struct omap_dss_device *dssdev)
{
- struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+ struct tpo_td043_device *tpo_td043 = g_tpo_td043;
int nreset_gpio = dssdev->reset_gpio;
int ret = 0;
@@ -440,6 +443,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
if (ret)
dev_warn(&dssdev->dev, "failed to create sysfs files\n");
+ dev_set_drvdata(&dssdev->dev, tpo_td043);
+
return 0;
fail_gpio_req:
@@ -505,6 +510,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
return -ENODEV;
}
+ if (g_tpo_td043 != NULL)
+ return -EBUSY;
+
spi->bits_per_word = 16;
spi->mode = SPI_MODE_0;
@@ -521,7 +529,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
tpo_td043->spi = spi;
tpo_td043->nreset_gpio = dssdev->reset_gpio;
dev_set_drvdata(&spi->dev, tpo_td043);
- dev_set_drvdata(&dssdev->dev, tpo_td043);
+ g_tpo_td043 = tpo_td043;
omap_dss_register_driver(&tpo_td043_driver);
@@ -534,6 +542,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi)
omap_dss_unregister_driver(&tpo_td043_driver);
kfree(tpo_td043);
+ g_tpo_td043 = NULL;
return 0;
}
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index d7d66ef5cb58..7f791aeda4d2 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -202,12 +202,10 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
- OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
- OMAP_DSS_OUTPUT_DSI1,
+ OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
- OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
- OMAP_DSS_OUTPUT_DPI,
+ OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index ca585ef37f25..717f13a93351 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -1101,41 +1101,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_fix_screeninfo *fix = &fbi->fix;
struct omapfb2_mem_region *rg;
- unsigned long off;
unsigned long start;
u32 len;
- int r = -EINVAL;
-
- if (vma->vm_end - vma->vm_start == 0)
- return 0;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- off = vma->vm_pgoff << PAGE_SHIFT;
+ int r;
rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len;
- if (off >= len)
- goto error;
- if ((vma->vm_end - vma->vm_start + off) > len)
- goto error;
-
- off += start;
- DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
+ DBG("user mmap region start %lx, len %d, off %lx\n", start, len,
+ vma->vm_pgoff << PAGE_SHIFT);
- vma->vm_pgoff = off >> PAGE_SHIFT;
- /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = rg;
- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot)) {
- r = -EAGAIN;
+
+ r = vm_iomap_memory(vma, start, len);
+ if (r)
goto error;
- }
/* vm_ops.open won't be called for mmap itself. */
atomic_inc(&rg->map_count);
@@ -1144,7 +1128,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
- error:
+error:
omapfb_put_mem_region(ofbi->region);
return r;
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
index 10560efeb35a..5261229c79af 100644
--- a/drivers/video/omap2/vrfb.c
+++ b/drivers/video/omap2/vrfb.c
@@ -397,18 +397,7 @@ static struct platform_driver vrfb_driver = {
.remove = __exit_p(vrfb_remove),
};
-static int __init vrfb_init(void)
-{
- return platform_driver_probe(&vrfb_driver, &vrfb_probe);
-}
-
-static void __exit vrfb_exit(void)
-{
- platform_driver_unregister(&vrfb_driver);
-}
-
-module_init(vrfb_init);
-module_exit(vrfb_exit);
+module_platform_driver_probe(vrfb_driver, vrfb_probe);
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("OMAP VRFB");
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 920c27bf3947..d9f08c653d62 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -705,21 +705,15 @@ static int ps3fb_pan_display(struct fb_var_screeninfo *var,
static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
- unsigned long size, offset;
+ int r;
- size = vma->vm_end - vma->vm_start;
- offset = vma->vm_pgoff << PAGE_SHIFT;
- if (offset + size > info->fix.smem_len)
- return -EINVAL;
-
- offset += info->fix.smem_start;
- if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
+ r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
- offset, vma->vm_start);
- return 0;
+ info->fix.smem_start + vma->vm_pgoff << PAGE_SHIFT,
+ vma->vm_start);
+
+ return r;
}
/*
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 76d9053d88c1..05c2dc3d4bc0 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -862,7 +862,7 @@ static int s1d13xxxfb_probe(struct platform_device *pdev)
printk(KERN_INFO PFX
"unknown chip production id %i, revision %i\n",
prod_id, revision);
- printk(KERN_INFO PFX "please contant maintainer\n");
+ printk(KERN_INFO PFX "please contact maintainer\n");
goto bail;
}
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index 968a62571df7..2e7991c7ca08 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -24,10 +24,9 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
+#include <linux/platform_data/video_s3c.h>
#include <video/samsung_fimd.h>
-#include <mach/map.h>
-#include <plat/fb.h>
/* This driver will export a number of framebuffer interfaces depending
* on the configuration passed in via the platform data. Each fb instance
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index cfbde5e85cbf..f34c858642e8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -556,7 +556,7 @@ static int sa1100fb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
- unsigned long start, len, off = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
vma->vm_pgoff += 1; /* skip over the palette */
@@ -564,19 +564,9 @@ static int sa1100fb_mmap(struct fb_info *info,
fbi->map_dma, fbi->map_size);
}
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
-
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
-
- off += start & PAGE_MASK;
- vma->vm_pgoff = off >> PAGE_SHIFT;
- vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- return io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
+
+ return vm_iomap_memory(vma, info->fix.mmio_start, info->fix.mmio_len);
}
static struct fb_ops sa1100fb_ops = {
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index 2331fadc272b..b2a8912f6435 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -705,23 +705,17 @@ static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
static int sgivwfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int r;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- if (offset + size > sgivwfb_mem_size)
- return -EINVAL;
- offset += sgivwfb_mem_phys;
pgprot_val(vma->vm_page_prot) =
- pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
- vma->vm_flags |= VM_IO;
- if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
+ pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
+
+ r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
+
printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
offset, vma->vm_start);
- return 0;
+
+ return r;
}
int __init sgivwfb_setup(char *options)
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
index 701b461cf8a9..6cad53075e99 100644
--- a/drivers/video/sh_mipi_dsi.c
+++ b/drivers/video/sh_mipi_dsi.c
@@ -581,17 +581,7 @@ static struct platform_driver sh_mipi_driver = {
},
};
-static int __init sh_mipi_init(void)
-{
- return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
-}
-module_init(sh_mipi_init);
-
-static void __exit sh_mipi_exit(void)
-{
- platform_driver_unregister(&sh_mipi_driver);
-}
-module_exit(sh_mipi_exit);
+module_platform_driver_probe(sh_mipi_driver, sh_mipi_probe);
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c
index 930e550e752a..bfe4728480fd 100644
--- a/drivers/video/sh_mobile_hdmi.c
+++ b/drivers/video/sh_mobile_hdmi.c
@@ -1445,17 +1445,7 @@ static struct platform_driver sh_hdmi_driver = {
},
};
-static int __init sh_hdmi_init(void)
-{
- return platform_driver_probe(&sh_hdmi_driver, sh_hdmi_probe);
-}
-module_init(sh_hdmi_init);
-
-static void __exit sh_hdmi_exit(void)
-{
- platform_driver_unregister(&sh_hdmi_driver);
-}
-module_exit(sh_hdmi_exit);
+module_platform_driver_probe(sh_hdmi_driver, sh_hdmi_probe);
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver");
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 63203acef812..0264704a52be 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -858,6 +858,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
| ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
lcdc_write_chan(ch, LDHAJR, tmp);
+ lcdc_write_chan_mirror(ch, LDHAJR, tmp);
}
static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
diff --git a/drivers/video/smscufx.c b/drivers/video/smscufx.c
index 97bd6620c364..b2b33fc1ac3f 100644
--- a/drivers/video/smscufx.c
+++ b/drivers/video/smscufx.c
@@ -782,7 +782,11 @@ static int ufx_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len)
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
pos = (unsigned long)info->fix.smem_start + offset;
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c
index 395cb6a8d8f3..9ef05d3ef68a 100644
--- a/drivers/video/ssd1307fb.c
+++ b/drivers/video/ssd1307fb.c
@@ -1,5 +1,5 @@
/*
- * Driver for the Solomon SSD1307 OLED controler
+ * Driver for the Solomon SSD1307 OLED controller
*
* Copyright 2012 Free Electrons
*
@@ -392,6 +392,6 @@ static struct i2c_driver ssd1307fb_driver = {
module_i2c_driver(ssd1307fb_driver);
-MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controler");
+MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controller");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 86d449ea3169..ec03e726c940 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -324,7 +324,11 @@ static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len)
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
pos = (unsigned long)info->fix.smem_start + offset;
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index b75db0186488..e328a61b64ba 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -166,7 +166,7 @@ static int uvesafb_exec(struct uvesafb_ktask *task)
memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id));
m->seq = seq;
m->len = len;
- m->ack = random32();
+ m->ack = prandom_u32();
/* uvesafb_task structure */
memcpy(m + 1, &task->t, sizeof(task->t));
@@ -1973,7 +1973,8 @@ static int uvesafb_init(void)
err = -ENOMEM;
if (err) {
- platform_device_put(uvesafb_device);
+ if (uvesafb_device)
+ platform_device_put(uvesafb_device);
platform_driver_unregister(&uvesafb_driver);
cn_del_callback(&uvesafb_cn_id);
return err;
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index 0aa516fc59cd..09a136633f35 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -1003,24 +1003,18 @@ static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct vml_info *vinfo = container_of(info, struct vml_info, info);
- unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
int ret;
- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
- return -EINVAL;
- if (offset + size > vinfo->vram_contig_size)
- return -EINVAL;
ret = vmlfb_vram_offset(vinfo, offset);
if (ret)
return -EINVAL;
- offset += vinfo->vram_start;
+
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
- if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
- return 0;
+
+ return vm_iomap_memory(vma, vinfo->vram_start,
+ vinfo->vram_contig_size);
}
static int vmlfb_sync(struct fb_info *info)
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 8bc1f9398945..ee5985efa15c 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -420,9 +420,12 @@ static int vfb_mmap(struct fb_info *info,
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos;
- if (offset + size > info->fix.smem_len) {
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (size > info->fix.smem_len)
+ return -EINVAL;
+ if (offset > info->fix.smem_len - size)
return -EINVAL;
- }
pos = (unsigned long)info->fix.smem_start + offset;
diff --git a/drivers/video/videomode.c b/drivers/video/videomode.c
index 21c47a202afa..df375c96c5d3 100644
--- a/drivers/video/videomode.c
+++ b/drivers/video/videomode.c
@@ -11,7 +11,25 @@
#include <video/display_timing.h>
#include <video/videomode.h>
-int videomode_from_timing(const struct display_timings *disp,
+void videomode_from_timing(const struct display_timing *dt,
+ struct videomode *vm)
+{
+ vm->pixelclock = dt->pixelclock.typ;
+ vm->hactive = dt->hactive.typ;
+ vm->hfront_porch = dt->hfront_porch.typ;
+ vm->hback_porch = dt->hback_porch.typ;
+ vm->hsync_len = dt->hsync_len.typ;
+
+ vm->vactive = dt->vactive.typ;
+ vm->vfront_porch = dt->vfront_porch.typ;
+ vm->vback_porch = dt->vback_porch.typ;
+ vm->vsync_len = dt->vsync_len.typ;
+
+ vm->flags = dt->flags;
+}
+EXPORT_SYMBOL_GPL(videomode_from_timing);
+
+int videomode_from_timings(const struct display_timings *disp,
struct videomode *vm, unsigned int index)
{
struct display_timing *dt;
@@ -20,20 +38,8 @@ int videomode_from_timing(const struct display_timings *disp,
if (!dt)
return -EINVAL;
- vm->pixelclock = display_timing_get_value(&dt->pixelclock, TE_TYP);
- vm->hactive = display_timing_get_value(&dt->hactive, TE_TYP);
- vm->hfront_porch = display_timing_get_value(&dt->hfront_porch, TE_TYP);
- vm->hback_porch = display_timing_get_value(&dt->hback_porch, TE_TYP);
- vm->hsync_len = display_timing_get_value(&dt->hsync_len, TE_TYP);
-
- vm->vactive = display_timing_get_value(&dt->vactive, TE_TYP);
- vm->vfront_porch = display_timing_get_value(&dt->vfront_porch, TE_TYP);
- vm->vback_porch = display_timing_get_value(&dt->vback_porch, TE_TYP);
- vm->vsync_len = display_timing_get_value(&dt->vsync_len, TE_TYP);
-
- vm->dmt_flags = dt->dmt_flags;
- vm->data_flags = dt->data_flags;
+ videomode_from_timing(dt, vm);
return 0;
}
-EXPORT_SYMBOL_GPL(videomode_from_timing);
+EXPORT_SYMBOL_GPL(videomode_from_timings);
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c
index aa2579c2364a..9547e1831e03 100644
--- a/drivers/video/vt8500lcdfb.c
+++ b/drivers/video/vt8500lcdfb.c
@@ -15,22 +15,21 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/wait.h>
-
-#include <linux/platform_data/video-vt8500lcdfb.h>
+#include <video/of_display_timing.h>
#include "vt8500lcdfb.h"
#include "wmt_ge_rops.h"
@@ -277,11 +276,11 @@ static int vt8500lcd_probe(struct platform_device *pdev)
{
struct vt8500lcd_info *fbi;
struct resource *res;
+ struct display_timings *disp_timing;
void *addr;
int irq, ret;
struct fb_videomode of_mode;
- struct device_node *np;
u32 bpp;
dma_addr_t fb_mem_phys;
unsigned long fb_mem_len;
@@ -346,32 +345,18 @@ static int vt8500lcd_probe(struct platform_device *pdev)
goto failed_free_res;
}
- np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0);
- if (!np) {
- pr_err("%s: No display description in Device Tree\n", __func__);
- ret = -EINVAL;
- goto failed_free_res;
- }
+ disp_timing = of_get_display_timings(pdev->dev.of_node);
+ if (!disp_timing)
+ return -EINVAL;
- /*
- * This code is copied from Sascha Hauer's of_videomode helper
- * and can be replaced with a call to the helper once mainlined
- */
- ret = 0;
- ret |= of_property_read_u32(np, "hactive", &of_mode.xres);
- ret |= of_property_read_u32(np, "vactive", &of_mode.yres);
- ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin);
- ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin);
- ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len);
- ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin);
- ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin);
- ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len);
- ret |= of_property_read_u32(np, "bpp", &bpp);
- if (ret) {
- pr_err("%s: Unable to read display properties\n", __func__);
- goto failed_free_res;
- }
- of_mode.vmode = FB_VMODE_NONINTERLACED;
+ ret = of_get_fb_videomode(pdev->dev.of_node, &of_mode,
+ OF_USE_NATIVE_MODE);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp);
+ if (ret)
+ return ret;
/* try allocating the framebuffer */
fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8);
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c
index 4dd0580f96fd..01f9ace068e2 100644
--- a/drivers/video/wm8505fb.c
+++ b/drivers/video/wm8505fb.c
@@ -14,25 +14,25 @@
* GNU General Public License for more details.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/fb.h>
+#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/wait.h>
+#include <linux/kernel.h>
+#include <linux/memblock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
-#include <linux/memblock.h>
-
-#include <linux/platform_data/video-vt8500lcdfb.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <video/of_display_timing.h>
#include "wm8505fb_regs.h"
#include "wmt_ge_rops.h"
@@ -263,26 +263,22 @@ static struct fb_ops wm8505fb_ops = {
static int wm8505fb_probe(struct platform_device *pdev)
{
struct wm8505fb_info *fbi;
- struct resource *res;
+ struct resource *res;
+ struct display_timings *disp_timing;
void *addr;
int ret;
- struct fb_videomode of_mode;
- struct device_node *np;
+ struct fb_videomode mode;
u32 bpp;
dma_addr_t fb_mem_phys;
unsigned long fb_mem_len;
void *fb_mem_virt;
- ret = -ENOMEM;
- fbi = NULL;
-
fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) +
sizeof(u32) * 16, GFP_KERNEL);
if (!fbi) {
dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
- ret = -ENOMEM;
- goto failed;
+ return -ENOMEM;
}
strcpy(fbi->fb.fix.id, DRIVER_NAME);
@@ -308,54 +304,23 @@ static int wm8505fb_probe(struct platform_device *pdev)
fbi->fb.pseudo_palette = addr;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no I/O memory resource defined\n");
- ret = -ENODEV;
- goto failed_fbi;
- }
+ fbi->regbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(fbi->regbase))
+ return PTR_ERR(fbi->regbase);
- res = request_mem_region(res->start, resource_size(res), DRIVER_NAME);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to request I/O memory\n");
- ret = -EBUSY;
- goto failed_fbi;
- }
-
- fbi->regbase = ioremap(res->start, resource_size(res));
- if (fbi->regbase == NULL) {
- dev_err(&pdev->dev, "failed to map I/O memory\n");
- ret = -EBUSY;
- goto failed_free_res;
- }
+ disp_timing = of_get_display_timings(pdev->dev.of_node);
+ if (!disp_timing)
+ return -EINVAL;
- np = of_parse_phandle(pdev->dev.of_node, "default-mode", 0);
- if (!np) {
- pr_err("%s: No display description in Device Tree\n", __func__);
- ret = -EINVAL;
- goto failed_free_res;
- }
+ ret = of_get_fb_videomode(pdev->dev.of_node, &mode, OF_USE_NATIVE_MODE);
+ if (ret)
+ return ret;
- /*
- * This code is copied from Sascha Hauer's of_videomode helper
- * and can be replaced with a call to the helper once mainlined
- */
- ret = 0;
- ret |= of_property_read_u32(np, "hactive", &of_mode.xres);
- ret |= of_property_read_u32(np, "vactive", &of_mode.yres);
- ret |= of_property_read_u32(np, "hback-porch", &of_mode.left_margin);
- ret |= of_property_read_u32(np, "hfront-porch", &of_mode.right_margin);
- ret |= of_property_read_u32(np, "hsync-len", &of_mode.hsync_len);
- ret |= of_property_read_u32(np, "vback-porch", &of_mode.upper_margin);
- ret |= of_property_read_u32(np, "vfront-porch", &of_mode.lower_margin);
- ret |= of_property_read_u32(np, "vsync-len", &of_mode.vsync_len);
- ret |= of_property_read_u32(np, "bpp", &bpp);
- if (ret) {
- pr_err("%s: Unable to read display properties\n", __func__);
- goto failed_free_res;
- }
+ ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp);
+ if (ret)
+ return ret;
- of_mode.vmode = FB_VMODE_NONINTERLACED;
- fb_videomode_to_var(&fbi->fb.var, &of_mode);
+ fb_videomode_to_var(&fbi->fb.var, &mode);
fbi->fb.var.nonstd = 0;
fbi->fb.var.activate = FB_ACTIVATE_NOW;
@@ -364,16 +329,16 @@ static int wm8505fb_probe(struct platform_device *pdev)
fbi->fb.var.width = -1;
/* try allocating the framebuffer */
- fb_mem_len = of_mode.xres * of_mode.yres * 2 * (bpp / 8);
- fb_mem_virt = dma_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
+ fb_mem_len = mode.xres * mode.yres * 2 * (bpp / 8);
+ fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
GFP_KERNEL);
if (!fb_mem_virt) {
pr_err("%s: Failed to allocate framebuffer\n", __func__);
return -ENOMEM;
- };
+ }
- fbi->fb.var.xres_virtual = of_mode.xres;
- fbi->fb.var.yres_virtual = of_mode.yres * 2;
+ fbi->fb.var.xres_virtual = mode.xres;
+ fbi->fb.var.yres_virtual = mode.yres * 2;
fbi->fb.var.bits_per_pixel = bpp;
fbi->fb.fix.smem_start = fb_mem_phys;
@@ -381,28 +346,29 @@ static int wm8505fb_probe(struct platform_device *pdev)
fbi->fb.screen_base = fb_mem_virt;
fbi->fb.screen_size = fb_mem_len;
+ fbi->contrast = 0x10;
+ ret = wm8505fb_set_par(&fbi->fb);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set parameters\n");
+ return ret;
+ }
+
if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
dev_err(&pdev->dev, "Failed to allocate color map\n");
- ret = -ENOMEM;
- goto failed_free_io;
+ return -ENOMEM;
}
wm8505fb_init_hw(&fbi->fb);
- fbi->contrast = 0x80;
- ret = wm8505fb_set_par(&fbi->fb);
- if (ret) {
- dev_err(&pdev->dev, "Failed to set parameters\n");
- goto failed_free_cmap;
- }
-
platform_set_drvdata(pdev, fbi);
ret = register_framebuffer(&fbi->fb);
if (ret < 0) {
dev_err(&pdev->dev,
"Failed to register framebuffer device: %d\n", ret);
- goto failed_free_cmap;
+ if (fbi->fb.cmap.len)
+ fb_dealloc_cmap(&fbi->fb.cmap);
+ return ret;
}
ret = device_create_file(&pdev->dev, &dev_attr_contrast);
@@ -416,25 +382,11 @@ static int wm8505fb_probe(struct platform_device *pdev)
fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);
return 0;
-
-failed_free_cmap:
- if (fbi->fb.cmap.len)
- fb_dealloc_cmap(&fbi->fb.cmap);
-failed_free_io:
- iounmap(fbi->regbase);
-failed_free_res:
- release_mem_region(res->start, resource_size(res));
-failed_fbi:
- platform_set_drvdata(pdev, NULL);
- kfree(fbi);
-failed:
- return ret;
}
static int wm8505fb_remove(struct platform_device *pdev)
{
struct wm8505fb_info *fbi = platform_get_drvdata(pdev);
- struct resource *res;
device_remove_file(&pdev->dev, &dev_attr_contrast);
@@ -445,13 +397,6 @@ static int wm8505fb_remove(struct platform_device *pdev)
if (fbi->fb.cmap.len)
fb_dealloc_cmap(&fbi->fb.cmap);
- iounmap(fbi->regbase);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(fbi);
-
return 0;
}
diff --git a/drivers/video/wmt_ge_rops.h b/drivers/video/wmt_ge_rops.h
index 87380751a443..f73ec6377a46 100644
--- a/drivers/video/wmt_ge_rops.h
+++ b/drivers/video/wmt_ge_rops.h
@@ -1,5 +1,28 @@
+#ifdef CONFIG_FB_WMT_GE_ROPS
+
extern void wmt_ge_fillrect(struct fb_info *info,
const struct fb_fillrect *rect);
extern void wmt_ge_copyarea(struct fb_info *info,
const struct fb_copyarea *area);
extern int wmt_ge_sync(struct fb_info *info);
+
+#else
+
+static inline int wmt_ge_sync(struct fb_info *p)
+{
+ return 0;
+}
+
+static inline void wmt_ge_fillrect(struct fb_info *p,
+ const struct fb_fillrect *rect)
+{
+ sys_fillrect(p, rect);
+}
+
+static inline void wmt_ge_copyarea(struct fb_info *p,
+ const struct fb_copyarea *area)
+{
+ sys_copyarea(p, area);
+}
+
+#endif
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
index 950d354d50e2..47e12cfc2a57 100644
--- a/drivers/w1/masters/mxc_w1.c
+++ b/drivers/w1/masters/mxc_w1.c
@@ -121,9 +121,9 @@ static int mxc_w1_probe(struct platform_device *pdev)
mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mdev->regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!mdev->regs)
- return -EBUSY;
+ mdev->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mdev->regs))
+ return PTR_ERR(mdev->regs);
clk_prepare_enable(mdev->clk);
__raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index 762561fbabbf..5e6a3c9e510b 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -22,6 +22,16 @@ config W1_SLAVE_DS2408
Say Y here if you want to use a 1-wire
DS2408 8-Channel Addressable Switch device support
+config W1_SLAVE_DS2408_READBACK
+ bool "Read-back values written to DS2408's output register"
+ depends on W1_SLAVE_DS2408
+ default y
+ help
+ Enabling this will cause the driver to read back the values written
+ to the chip's output register in order to detect errors.
+
+ This is slower but useful when debugging chips and/or busses.
+
config W1_SLAVE_DS2413
tristate "Dual Channel Addressable Switch 0x3a family support (DS2413)"
help
diff --git a/drivers/w1/slaves/w1_bq27000.c b/drivers/w1/slaves/w1_bq27000.c
index 773dca5beafe..afbefed5f2c9 100644
--- a/drivers/w1/slaves/w1_bq27000.c
+++ b/drivers/w1/slaves/w1_bq27000.c
@@ -57,6 +57,8 @@ static int w1_bq27000_add_slave(struct w1_slave *sl)
ret = platform_device_add_data(pdev,
&bq27000_battery_info,
sizeof(bq27000_battery_info));
+ if (ret)
+ goto pdev_add_failed;
pdev->dev.parent = &sl->dev;
ret = platform_device_add(pdev);
@@ -68,7 +70,7 @@ static int w1_bq27000_add_slave(struct w1_slave *sl)
goto success;
pdev_add_failed:
- platform_device_unregister(pdev);
+ platform_device_put(pdev);
success:
return ret;
}
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index 441ad3a3b586..e45eca1044bd 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -178,6 +178,15 @@ static ssize_t w1_f29_write_output(
w1_write_block(sl->master, w1_buf, 3);
readBack = w1_read_8(sl->master);
+
+ if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
+ if (w1_reset_resume_command(sl->master))
+ goto error;
+ /* try again, the slave is ready for a command */
+ continue;
+ }
+
+#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
/* here the master could read another byte which
would be the PIO reg (the actual pin logic state)
since in this driver we don't know which pins are
@@ -186,11 +195,6 @@ static ssize_t w1_f29_write_output(
if (w1_reset_resume_command(sl->master))
goto error;
- if (readBack != 0xAA) {
- /* try again, the slave is ready for a command */
- continue;
- }
-
/* go read back the output latches */
/* (the direct effect of the write above) */
w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
@@ -198,7 +202,9 @@ static ssize_t w1_f29_write_output(
w1_buf[2] = 0;
w1_write_block(sl->master, w1_buf, 3);
/* read the result of the READ_PIO_REGS command */
- if (w1_read_8(sl->master) == *buf) {
+ if (w1_read_8(sl->master) == *buf)
+#endif
+ {
/* success! */
mutex_unlock(&sl->master->bus_mutex);
dev_dbg(&sl->dev,
@@ -297,8 +303,7 @@ error:
-#define NB_SYSFS_BIN_FILES 6
-static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
+static struct bin_attribute w1_f29_sysfs_bin_files[] = {
{
.attr = {
.name = "state",
@@ -357,7 +362,7 @@ static int w1_f29_add_slave(struct w1_slave *sl)
int err = 0;
int i;
- for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
+ for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
err = sysfs_create_bin_file(
&sl->dev.kobj,
&(w1_f29_sysfs_bin_files[i]));
@@ -371,7 +376,7 @@ static int w1_f29_add_slave(struct w1_slave *sl)
static void w1_f29_remove_slave(struct w1_slave *sl)
{
int i;
- for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
+ for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i)
sysfs_remove_bin_file(&sl->dev.kobj,
&(w1_f29_sysfs_bin_files[i]));
}
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index aa7bd5fa2fa8..e86a69dc411e 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -148,8 +148,9 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
goto success;
bin_attr_failed:
+ platform_device_del(pdev);
pdev_add_failed:
- platform_device_unregister(pdev);
+ platform_device_put(pdev);
pdev_alloc_failed:
ida_simple_remove(&bat_ida, id);
noid:
diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c
index 7b09307de0ef..98ed9c49cf50 100644
--- a/drivers/w1/slaves/w1_ds2780.c
+++ b/drivers/w1/slaves/w1_ds2780.c
@@ -141,8 +141,9 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
return 0;
bin_attr_failed:
+ platform_device_del(pdev);
pdev_add_failed:
- platform_device_unregister(pdev);
+ platform_device_put(pdev);
pdev_alloc_failed:
ida_simple_remove(&bat_ida, id);
noid:
diff --git a/drivers/w1/slaves/w1_ds2781.c b/drivers/w1/slaves/w1_ds2781.c
index 877daf74159c..5140d7be67ab 100644
--- a/drivers/w1/slaves/w1_ds2781.c
+++ b/drivers/w1/slaves/w1_ds2781.c
@@ -139,8 +139,9 @@ static int w1_ds2781_add_slave(struct w1_slave *sl)
return 0;
bin_attr_failed:
+ platform_device_del(pdev);
pdev_add_failed:
- platform_device_unregister(pdev);
+ platform_device_put(pdev);
pdev_alloc_failed:
ida_simple_remove(&bat_ida, id);
noid:
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 9fcc70c11cea..e89fc3133972 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -117,7 +117,7 @@ config ARM_SP805_WATCHDOG
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
- depends on ARCH_AT91
+ depends on ARCH_AT91RM9200
help
Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached.
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 5a32232cf7c1..dd4d9cb86243 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -145,9 +145,9 @@ config SWIOTLB_XEN
select SWIOTLB
config XEN_TMEM
- bool
+ tristate
depends on !ARM
- default y if (CLEANCACHE || FRONTSWAP)
+ default m if (CLEANCACHE || FRONTSWAP)
help
Shim to interface in-kernel Transcendent Memory hooks
(e.g. cleancache and frontswap) to Xen tmem hypercalls.
@@ -182,7 +182,7 @@ config XEN_PRIVCMD
config XEN_STUB
bool "Xen stub drivers"
- depends on XEN && X86_64
+ depends on XEN && X86_64 && BROKEN
default n
help
Allow kernel to install stub drivers, to reserve space for Xen drivers,
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index d17aa41a9041..d8cc8127f19c 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -85,8 +85,7 @@ enum xen_irq_type {
* event channel - irq->event channel mapping
* cpu - cpu this event channel is bound to
* index - type-specific information:
- * PIRQ - vector, with MSB being "needs EIO", or physical IRQ of the HVM
- * guest, or GSI (real passthrough IRQ) of the device.
+ * PIRQ - physical IRQ, GSI, flags, and owner domain
* VIRQ - virq number
* IPI - IPI vector
* EVTCHN -
@@ -105,7 +104,6 @@ struct irq_info {
struct {
unsigned short pirq;
unsigned short gsi;
- unsigned char vector;
unsigned char flags;
uint16_t domid;
} pirq;
@@ -211,7 +209,6 @@ static void xen_irq_info_pirq_init(unsigned irq,
unsigned short evtchn,
unsigned short pirq,
unsigned short gsi,
- unsigned short vector,
uint16_t domid,
unsigned char flags)
{
@@ -221,7 +218,6 @@ static void xen_irq_info_pirq_init(unsigned irq,
info->u.pirq.pirq = pirq;
info->u.pirq.gsi = gsi;
- info->u.pirq.vector = vector;
info->u.pirq.domid = domid;
info->u.pirq.flags = flags;
}
@@ -403,11 +399,23 @@ static void unmask_evtchn(int port)
if (unlikely((cpu != cpu_from_evtchn(port))))
do_hypercall = 1;
- else
+ else {
+ /*
+ * Need to clear the mask before checking pending to
+ * avoid a race with an event becoming pending.
+ *
+ * EVTCHNOP_unmask will only trigger an upcall if the
+ * mask bit was set, so if a hypercall is needed
+ * remask the event.
+ */
+ sync_clear_bit(port, BM(&s->evtchn_mask[0]));
evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
- if (unlikely(evtchn_pending && xen_hvm_domain()))
- do_hypercall = 1;
+ if (unlikely(evtchn_pending && xen_hvm_domain())) {
+ sync_set_bit(port, BM(&s->evtchn_mask[0]));
+ do_hypercall = 1;
+ }
+ }
/* Slow path (hypercall) if this is a non-local port or if this is
* an hvm domain and an event is pending (hvm domains don't have
@@ -418,8 +426,6 @@ static void unmask_evtchn(int port)
} else {
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
- sync_clear_bit(port, BM(&s->evtchn_mask[0]));
-
/*
* The following is basically the equivalent of
* 'hw_resend_irq'. Just like a real IO-APIC we 'lose
@@ -509,6 +515,9 @@ static void xen_free_irq(unsigned irq)
{
struct irq_info *info = irq_get_handler_data(irq);
+ if (WARN_ON(!info))
+ return;
+
list_del(&info->list);
irq_set_handler_data(irq, NULL);
@@ -704,7 +713,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
goto out;
}
- xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF,
+ xen_irq_info_pirq_init(irq, 0, pirq, gsi, DOMID_SELF,
shareable ? PIRQ_SHAREABLE : 0);
pirq_query_unmask(irq);
@@ -752,8 +761,7 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
}
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
- int pirq, int vector, const char *name,
- domid_t domid)
+ int pirq, const char *name, domid_t domid)
{
int irq, ret;
@@ -766,7 +774,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq,
name);
- xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0);
+ xen_irq_info_pirq_init(irq, 0, pirq, 0, domid, 0);
ret = irq_set_msi_desc(irq, msidesc);
if (ret < 0)
goto error_irq;
@@ -998,6 +1006,9 @@ static void unbind_from_irq(unsigned int irq)
int evtchn = evtchn_from_irq(irq);
struct irq_info *info = irq_get_handler_data(irq);
+ if (WARN_ON(!info))
+ return;
+
mutex_lock(&irq_mapping_update_lock);
if (info->refcnt > 0) {
@@ -1125,6 +1136,10 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
void unbind_from_irqhandler(unsigned int irq, void *dev_id)
{
+ struct irq_info *info = irq_get_handler_data(irq);
+
+ if (WARN_ON(!info))
+ return;
free_irq(irq, dev_id);
unbind_from_irq(irq);
}
@@ -1306,7 +1321,7 @@ static void __xen_evtchn_do_upcall(void)
{
int start_word_idx, start_bit_idx;
int word_idx, bit_idx;
- int i;
+ int i, irq;
int cpu = get_cpu();
struct shared_info *s = HYPERVISOR_shared_info;
struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
@@ -1314,6 +1329,8 @@ static void __xen_evtchn_do_upcall(void)
do {
xen_ulong_t pending_words;
+ xen_ulong_t pending_bits;
+ struct irq_desc *desc;
vcpu_info->evtchn_upcall_pending = 0;
@@ -1325,6 +1342,17 @@ static void __xen_evtchn_do_upcall(void)
* selector flag. xchg_xen_ulong must contain an
* appropriate barrier.
*/
+ if ((irq = per_cpu(virq_to_irq, cpu)[VIRQ_TIMER]) != -1) {
+ int evtchn = evtchn_from_irq(irq);
+ word_idx = evtchn / BITS_PER_LONG;
+ pending_bits = evtchn % BITS_PER_LONG;
+ if (active_evtchns(cpu, s, word_idx) & (1ULL << pending_bits)) {
+ desc = irq_to_desc(irq);
+ if (desc)
+ generic_handle_irq_desc(irq, desc);
+ }
+ }
+
pending_words = xchg_xen_ulong(&vcpu_info->evtchn_pending_sel, 0);
start_word_idx = __this_cpu_read(current_word_idx);
@@ -1333,7 +1361,6 @@ static void __xen_evtchn_do_upcall(void)
word_idx = start_word_idx;
for (i = 0; pending_words != 0; i++) {
- xen_ulong_t pending_bits;
xen_ulong_t words;
words = MASK_LSBS(pending_words, word_idx);
@@ -1362,8 +1389,7 @@ static void __xen_evtchn_do_upcall(void)
do {
xen_ulong_t bits;
- int port, irq;
- struct irq_desc *desc;
+ int port;
bits = MASK_LSBS(pending_bits, bit_idx);
@@ -1436,6 +1462,9 @@ void rebind_evtchn_irq(int evtchn, int irq)
{
struct irq_info *info = info_for_irq(irq);
+ if (WARN_ON(!info))
+ return;
+
/* Make sure the irq is masked, since the new event channel
will also be masked. */
disable_irq(irq);
@@ -1709,7 +1738,12 @@ void xen_poll_irq(int irq)
int xen_test_irq_shared(int irq)
{
struct irq_info *info = info_for_irq(irq);
- struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq };
+ struct physdev_irq_status_query irq_status;
+
+ if (WARN_ON(!info))
+ return -ENOENT;
+
+ irq_status.irq = info->u.pirq.pirq;
if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
return 0;
diff --git a/drivers/xen/fallback.c b/drivers/xen/fallback.c
index 0ef7c4d40f86..b04fb64c5a91 100644
--- a/drivers/xen/fallback.c
+++ b/drivers/xen/fallback.c
@@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, void *arg)
}
EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
-int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
+int xen_physdev_op_compat(int cmd, void *arg)
{
struct physdev_op op;
int rc;
@@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
return rc;
}
+EXPORT_SYMBOL_GPL(xen_physdev_op_compat);
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
index 3ee836d42581..e3600be4e7fa 100644
--- a/drivers/xen/tmem.c
+++ b/drivers/xen/tmem.c
@@ -5,6 +5,7 @@
* Author: Dan Magenheimer
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
@@ -128,6 +129,7 @@ static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
}
+#ifndef CONFIG_XEN_TMEM_MODULE
bool __read_mostly tmem_enabled = false;
static int __init enable_tmem(char *s)
@@ -136,6 +138,7 @@ static int __init enable_tmem(char *s)
return 1;
}
__setup("tmem", enable_tmem);
+#endif
#ifdef CONFIG_CLEANCACHE
static int xen_tmem_destroy_pool(u32 pool_id)
@@ -227,16 +230,21 @@ static int tmem_cleancache_init_shared_fs(char *uuid, size_t pagesize)
return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
}
-static bool __initdata use_cleancache = true;
-
+static bool disable_cleancache __read_mostly;
+static bool disable_selfballooning __read_mostly;
+#ifdef CONFIG_XEN_TMEM_MODULE
+module_param(disable_cleancache, bool, S_IRUGO);
+module_param(disable_selfballooning, bool, S_IRUGO);
+#else
static int __init no_cleancache(char *s)
{
- use_cleancache = false;
+ disable_cleancache = true;
return 1;
}
__setup("nocleancache", no_cleancache);
+#endif
-static struct cleancache_ops __initdata tmem_cleancache_ops = {
+static struct cleancache_ops tmem_cleancache_ops = {
.put_page = tmem_cleancache_put_page,
.get_page = tmem_cleancache_get_page,
.invalidate_page = tmem_cleancache_flush_page,
@@ -353,54 +361,71 @@ static void tmem_frontswap_init(unsigned ignored)
xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
}
-static bool __initdata use_frontswap = true;
-
+static bool disable_frontswap __read_mostly;
+static bool disable_frontswap_selfshrinking __read_mostly;
+#ifdef CONFIG_XEN_TMEM_MODULE
+module_param(disable_frontswap, bool, S_IRUGO);
+module_param(disable_frontswap_selfshrinking, bool, S_IRUGO);
+#else
static int __init no_frontswap(char *s)
{
- use_frontswap = false;
+ disable_frontswap = true;
return 1;
}
__setup("nofrontswap", no_frontswap);
+#endif
-static struct frontswap_ops __initdata tmem_frontswap_ops = {
+static struct frontswap_ops tmem_frontswap_ops = {
.store = tmem_frontswap_store,
.load = tmem_frontswap_load,
.invalidate_page = tmem_frontswap_flush_page,
.invalidate_area = tmem_frontswap_flush_area,
.init = tmem_frontswap_init
};
+#else /* CONFIG_FRONTSWAP */
+#define disable_frontswap_selfshrinking 1
#endif
-static int __init xen_tmem_init(void)
+static int xen_tmem_init(void)
{
if (!xen_domain())
return 0;
#ifdef CONFIG_FRONTSWAP
- if (tmem_enabled && use_frontswap) {
+ if (tmem_enabled && !disable_frontswap) {
char *s = "";
- struct frontswap_ops old_ops =
+ struct frontswap_ops *old_ops =
frontswap_register_ops(&tmem_frontswap_ops);
tmem_frontswap_poolid = -1;
- if (old_ops.init != NULL)
+ if (IS_ERR(old_ops) || old_ops) {
+ if (IS_ERR(old_ops))
+ return PTR_ERR(old_ops);
s = " (WARNING: frontswap_ops overridden)";
+ }
printk(KERN_INFO "frontswap enabled, RAM provided by "
"Xen Transcendent Memory%s\n", s);
}
#endif
#ifdef CONFIG_CLEANCACHE
BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
- if (tmem_enabled && use_cleancache) {
+ if (tmem_enabled && !disable_cleancache) {
char *s = "";
- struct cleancache_ops old_ops =
+ struct cleancache_ops *old_ops =
cleancache_register_ops(&tmem_cleancache_ops);
- if (old_ops.init_fs != NULL)
+ if (old_ops)
s = " (WARNING: cleancache_ops overridden)";
printk(KERN_INFO "cleancache enabled, RAM provided by "
"Xen Transcendent Memory%s\n", s);
}
#endif
+#ifdef CONFIG_XEN_SELFBALLOONING
+ xen_selfballoon_init(!disable_selfballooning,
+ !disable_frontswap_selfshrinking);
+#endif
return 0;
}
module_init(xen_tmem_init)
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dan Magenheimer <dan.magenheimer@oracle.com>");
+MODULE_DESCRIPTION("Shim to Xen transcendent memory");
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index f3278a6603ca..8abd7d579037 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/syscore_ops.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
@@ -51,9 +52,9 @@ static DEFINE_MUTEX(acpi_ids_mutex);
/* Which ACPI ID we have processed from 'struct acpi_processor'. */
static unsigned long *acpi_ids_done;
/* Which ACPI ID exist in the SSDT/DSDT processor definitions. */
-static unsigned long __initdata *acpi_id_present;
+static unsigned long *acpi_id_present;
/* And if there is an _CST definition (or a PBLK) for the ACPI IDs */
-static unsigned long __initdata *acpi_id_cst_present;
+static unsigned long *acpi_id_cst_present;
static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
{
@@ -329,7 +330,7 @@ static unsigned int __init get_max_acpi_id(void)
* for_each_[present|online]_cpu macros which are banded to the virtual
* CPU amount.
*/
-static acpi_status __init
+static acpi_status
read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
{
u32 acpi_id;
@@ -384,12 +385,16 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-static int __init check_acpi_ids(struct acpi_processor *pr_backup)
+static int check_acpi_ids(struct acpi_processor *pr_backup)
{
if (!pr_backup)
return -ENODEV;
+ if (acpi_id_present && acpi_id_cst_present)
+ /* OK, done this once .. skip to uploading */
+ goto upload;
+
/* All online CPUs have been processed at this stage. Now verify
* whether in fact "online CPUs" == physical CPUs.
*/
@@ -408,6 +413,7 @@ static int __init check_acpi_ids(struct acpi_processor *pr_backup)
read_acpi_id, NULL, NULL, NULL);
acpi_get_devices("ACPI0007", read_acpi_id, NULL, NULL);
+upload:
if (!bitmap_equal(acpi_id_present, acpi_ids_done, nr_acpi_bits)) {
unsigned int i;
for_each_set_bit(i, acpi_id_present, nr_acpi_bits) {
@@ -417,10 +423,7 @@ static int __init check_acpi_ids(struct acpi_processor *pr_backup)
(void)upload_pm_data(pr_backup);
}
}
- kfree(acpi_id_present);
- acpi_id_present = NULL;
- kfree(acpi_id_cst_present);
- acpi_id_cst_present = NULL;
+
return 0;
}
static int __init check_prereq(void)
@@ -467,10 +470,47 @@ static void free_acpi_perf_data(void)
free_percpu(acpi_perf_data);
}
-static int __init xen_acpi_processor_init(void)
+static int xen_upload_processor_pm_data(void)
{
struct acpi_processor *pr_backup = NULL;
unsigned int i;
+ int rc = 0;
+
+ pr_info(DRV_NAME "Uploading Xen processor PM info\n");
+
+ for_each_possible_cpu(i) {
+ struct acpi_processor *_pr;
+ _pr = per_cpu(processors, i /* APIC ID */);
+ if (!_pr)
+ continue;
+
+ if (!pr_backup) {
+ pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ if (pr_backup)
+ memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
+ }
+ (void)upload_pm_data(_pr);
+ }
+
+ rc = check_acpi_ids(pr_backup);
+ kfree(pr_backup);
+
+ return rc;
+}
+
+static void xen_acpi_processor_resume(void)
+{
+ bitmap_zero(acpi_ids_done, nr_acpi_bits);
+ xen_upload_processor_pm_data();
+}
+
+static struct syscore_ops xap_syscore_ops = {
+ .resume = xen_acpi_processor_resume,
+};
+
+static int __init xen_acpi_processor_init(void)
+{
+ unsigned int i;
int rc = check_prereq();
if (rc)
@@ -505,33 +545,21 @@ static int __init xen_acpi_processor_init(void)
pr = per_cpu(processors, i);
perf = per_cpu_ptr(acpi_perf_data, i);
+ if (!pr)
+ continue;
+
pr->performance = perf;
rc = acpi_processor_get_performance_info(pr);
if (rc)
goto err_out;
}
- for_each_possible_cpu(i) {
- struct acpi_processor *_pr;
- _pr = per_cpu(processors, i /* APIC ID */);
- if (!_pr)
- continue;
-
- if (!pr_backup) {
- pr_backup = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
- if (pr_backup)
- memcpy(pr_backup, _pr, sizeof(struct acpi_processor));
- }
- (void)upload_pm_data(_pr);
- }
- rc = check_acpi_ids(pr_backup);
-
- kfree(pr_backup);
- pr_backup = NULL;
-
+ rc = xen_upload_processor_pm_data();
if (rc)
goto err_unregister;
+ register_syscore_ops(&xap_syscore_ops);
+
return 0;
err_unregister:
for_each_possible_cpu(i) {
@@ -549,7 +577,10 @@ static void __exit xen_acpi_processor_exit(void)
{
int i;
+ unregister_syscore_ops(&xap_syscore_ops);
kfree(acpi_ids_done);
+ kfree(acpi_id_present);
+ kfree(acpi_id_cst_present);
for_each_possible_cpu(i) {
struct acpi_processor_performance *perf;
perf = per_cpu_ptr(acpi_perf_data, i);
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index 9204126f1560..a2278ba7fb27 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -17,6 +17,7 @@
#include <xen/events.h>
#include <asm/xen/pci.h>
#include <asm/xen/hypervisor.h>
+#include <xen/interface/physdev.h>
#include "pciback.h"
#include "conf_space.h"
#include "conf_space_quirks.h"
@@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
static void pcistub_device_release(struct kref *kref)
{
struct pcistub_device *psdev;
+ struct pci_dev *dev;
struct xen_pcibk_dev_data *dev_data;
psdev = container_of(kref, struct pcistub_device, kref);
- dev_data = pci_get_drvdata(psdev->dev);
+ dev = psdev->dev;
+ dev_data = pci_get_drvdata(dev);
- dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
+ dev_dbg(&dev->dev, "pcistub_device_release\n");
- xen_unregister_device_domain_owner(psdev->dev);
+ xen_unregister_device_domain_owner(dev);
/* Call the reset function which does not take lock as this
* is called from "unbind" which takes a device_lock mutex.
*/
- __pci_reset_function_locked(psdev->dev);
- if (pci_load_and_free_saved_state(psdev->dev,
- &dev_data->pci_saved_state)) {
- dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n");
- } else
- pci_restore_state(psdev->dev);
+ __pci_reset_function_locked(dev);
+ if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
+ dev_dbg(&dev->dev, "Could not reload PCI state\n");
+ else
+ pci_restore_state(dev);
+
+ if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+ struct physdev_pci_device ppdev = {
+ .seg = pci_domain_nr(dev->bus),
+ .bus = dev->bus->number,
+ .devfn = dev->devfn
+ };
+ int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix,
+ &ppdev);
+
+ if (err)
+ dev_warn(&dev->dev, "MSI-X release failed (%d)\n",
+ err);
+ }
/* Disable the device */
- xen_pcibk_reset_device(psdev->dev);
+ xen_pcibk_reset_device(dev);
kfree(dev_data);
- pci_set_drvdata(psdev->dev, NULL);
+ pci_set_drvdata(dev, NULL);
/* Clean-up the device */
- xen_pcibk_config_free_dyn_fields(psdev->dev);
- xen_pcibk_config_free_dev(psdev->dev);
+ xen_pcibk_config_free_dyn_fields(dev);
+ xen_pcibk_config_free_dev(dev);
- psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
- pci_dev_put(psdev->dev);
+ dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
+ pci_dev_put(dev);
kfree(psdev);
}
@@ -355,6 +371,19 @@ static int pcistub_init_device(struct pci_dev *dev)
if (err)
goto config_release;
+ if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+ struct physdev_pci_device ppdev = {
+ .seg = pci_domain_nr(dev->bus),
+ .bus = dev->bus->number,
+ .devfn = dev->devfn
+ };
+
+ err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev);
+ if (err)
+ dev_err(&dev->dev, "MSI-X preparation failed (%d)\n",
+ err);
+ }
+
/* We need the device active to save the state. */
dev_dbg(&dev->dev, "save state of device\n");
pci_save_state(dev);
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index 2552d3e0a70f..f2ef569c7cc1 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -121,7 +121,7 @@ static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
static bool frontswap_selfshrinking __read_mostly;
/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink __initdata = true;
+static bool use_frontswap_selfshrink = true;
/*
* The default values for the following parameters were deemed reasonable
@@ -185,7 +185,7 @@ static int __init xen_nofrontswap_selfshrink_setup(char *s)
__setup("noselfshrink", xen_nofrontswap_selfshrink_setup);
/* Disable with kernel boot option. */
-static bool use_selfballooning __initdata = true;
+static bool use_selfballooning = true;
static int __init xen_noselfballooning_setup(char *s)
{
@@ -196,7 +196,7 @@ static int __init xen_noselfballooning_setup(char *s)
__setup("noselfballooning", xen_noselfballooning_setup);
#else /* !CONFIG_FRONTSWAP */
/* Enable with kernel boot option. */
-static bool use_selfballooning __initdata = false;
+static bool use_selfballooning;
static int __init xen_selfballooning_setup(char *s)
{
@@ -537,7 +537,7 @@ int register_xen_selfballooning(struct device *dev)
}
EXPORT_SYMBOL(register_xen_selfballooning);
-static int __init xen_selfballoon_init(void)
+int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
{
bool enable = false;
@@ -571,7 +571,4 @@ static int __init xen_selfballoon_init(void)
return 0;
}
-
-subsys_initcall(xen_selfballoon_init);
-
-MODULE_LICENSE("GPL");
+EXPORT_SYMBOL(xen_selfballoon_init);
diff --git a/firmware/Makefile b/firmware/Makefile
index 5d8ee1319b5c..cbb09ce9730a 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -82,7 +82,7 @@ fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \
qlogic/12160.bin
fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin
-fw-shipped-$(CONFIG_INFINIBAND_QIB) += intel/sd7220.fw
+fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw
fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp
fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \
ess/maestro3_assp_minisrc.fw
diff --git a/firmware/intel/sd7220.fw.ihex b/firmware/qlogic/sd7220.fw.ihex
index a33636319112..a33636319112 100644
--- a/firmware/intel/sd7220.fw.ihex
+++ b/firmware/qlogic/sd7220.fw.ihex
diff --git a/fs/Kconfig b/fs/Kconfig
index 780725a463b1..c229f828eb01 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -211,6 +211,7 @@ source "fs/sysv/Kconfig"
source "fs/ufs/Kconfig"
source "fs/exofs/Kconfig"
source "fs/f2fs/Kconfig"
+source "fs/efivarfs/Kconfig"
endif # MISC_FILESYSTEMS
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 0efd1524b977..370b24cee4d8 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -65,6 +65,20 @@ config CORE_DUMP_DEFAULT_ELF_HEADERS
This config option changes the default setting of coredump_filter
seen at boot time. If unsure, say Y.
+config BINFMT_SCRIPT
+ tristate "Kernel support for scripts starting with #!"
+ default y
+ help
+ Say Y here if you want to execute interpreted scripts starting with
+ #! followed by the path to an interpreter.
+
+ You can build this support as a module; however, until that module
+ gets loaded, you cannot run scripts. Thus, if you want to load this
+ module from an initramfs, the portion of the initramfs before loading
+ this module must consist of compiled binaries only.
+
+ Most systems will not boot if you say M or N here. If unsure, say Y.
+
config BINFMT_FLAT
bool "Kernel support for flat binaries"
depends on !MMU && (!FRV || BROKEN)
diff --git a/fs/Makefile b/fs/Makefile
index b691a965dc1a..4fe6df3ec28f 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,7 +10,7 @@ obj-y := open.o read_write.o file_table.o super.o \
ioctl.o readdir.o select.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
- pnode.o drop_caches.o splice.o sync.o utimes.o \
+ pnode.o splice.o sync.o utimes.o \
stack.o fs_struct.o statfs.o
ifeq ($(CONFIG_BLOCK),y)
@@ -34,10 +34,7 @@ obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o
obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o
obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o
-
-# binfmt_script is always there
-obj-y += binfmt_script.o
-
+obj-$(CONFIG_BINFMT_SCRIPT) += binfmt_script.o
obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o
obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o
obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o
@@ -49,6 +46,7 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
obj-$(CONFIG_NFS_COMMON) += nfs_common/
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
obj-$(CONFIG_COREDUMP) += coredump.o
+obj-$(CONFIG_SYSCTL) += drop_caches.o
obj-$(CONFIG_FHANDLE) += fhandle.o
@@ -127,3 +125,4 @@ obj-$(CONFIG_F2FS_FS) += f2fs/
obj-y += exofs/ # Multiple modules
obj-$(CONFIG_CEPH_FS) += ceph/
obj-$(CONFIG_PSTORE) += pstore/
+obj-$(CONFIG_EFIVAR_FS) += efivarfs/
diff --git a/fs/aio.c b/fs/aio.c
index 4ec28f13a92e..351afe7ac78e 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1029,9 +1029,9 @@ static int aio_read_evt(struct kioctx *ioctx, struct io_event *ent)
spin_unlock(&info->ring_lock);
out:
- kunmap_atomic(ring);
dprintk("leaving aio_read_evt: %d h%lu t%lu\n", ret,
(unsigned long)ring->head, (unsigned long)ring->tail);
+ kunmap_atomic(ring);
return ret;
}
@@ -1794,7 +1794,5 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
ret = read_events(ioctx, min_nr, nr, events, timeout);
put_ioctx(ioctx);
}
-
- asmlinkage_protect(5, ret, ctx_id, min_nr, nr, events, timeout);
return ret;
}
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index a66c9b1136e0..74e397db0b8b 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -436,8 +436,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
goto error;
}
- if ((this_node = (befs_btree_node *)
- kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
+ if ((this_node = kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) {
befs_error(sb, "befs_btree_read() failed to allocate %u "
"bytes of memory", sizeof (befs_btree_node));
goto error;
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index b23253df8756..bce87694f7b0 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -62,7 +62,6 @@ static int aout_core_dump(struct coredump_params *cprm)
fs = get_fs();
set_fs(KERNEL_DS);
has_dumped = 1;
- current->flags |= PF_DUMPCORE;
strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm));
dump.u_ar0 = offsetof(struct user, regs);
dump.signal = cprm->siginfo->si_signo;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 3939829f6c5c..34a9771eaa6c 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -803,7 +803,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
* follow the loader, and is not movable. */
#ifdef CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE
/* Memory randomization might have been switched off
- * in runtime via sysctl.
+ * in runtime via sysctl or explicit setting of
+ * personality flags.
* If that is the case, retain the original non-zero
* load_bias value in order to establish proper
* non-randomized mappings.
@@ -1137,6 +1138,7 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
goto whole;
if (!(vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_PRIVATE))
goto whole;
+ return 0;
}
/* Do not dump I/O mapped devices or special mappings */
@@ -2090,8 +2092,7 @@ static int elf_core_dump(struct coredump_params *cprm)
goto cleanup;
has_dumped = 1;
- current->flags |= PF_DUMPCORE;
-
+
fs = get_fs();
set_fs(KERNEL_DS);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 2711d9901632..9dac212fc6f9 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1684,8 +1684,6 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
fill_elf_fdpic_header(elf, e_phnum);
has_dumped = 1;
- current->flags |= PF_DUMPCORE;
-
/*
* Set up the notes in similar form to SVR4 core dumps made
* with info from their /proc.
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 751df5e4f61a..1c740e152f38 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -23,6 +23,7 @@
#include <linux/binfmts.h>
#include <linux/slab.h>
#include <linux/ctype.h>
+#include <linux/string_helpers.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/namei.h>
@@ -234,24 +235,6 @@ static char *scanarg(char *s, char del)
return s;
}
-static int unquote(char *from)
-{
- char c = 0, *s = from, *p = from;
-
- while ((c = *s++) != '\0') {
- if (c == '\\' && *s == 'x') {
- s++;
- c = toupper(*s++);
- *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
- c = toupper(*s++);
- *p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
- continue;
- }
- *p++ = c;
- }
- return p - from;
-}
-
static char * check_special_flags (char * sfs, Node * e)
{
char * p = sfs;
@@ -354,8 +337,9 @@ static Node *create_entry(const char __user *buffer, size_t count)
p[-1] = '\0';
if (!e->mask[0])
e->mask = NULL;
- e->size = unquote(e->magic);
- if (e->mask && unquote(e->mask) != e->size)
+ e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX);
+ if (e->mask &&
+ string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
goto Einval;
if (e->size + e->offset > BINPRM_BUF_SIZE)
goto Einval;
diff --git a/fs/bio.c b/fs/bio.c
index bb5768f59b32..b96fc6ce4855 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1428,8 +1428,6 @@ void bio_endio(struct bio *bio, int error)
else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
error = -EIO;
- trace_block_bio_complete(bio, error);
-
if (bio->bi_end_io)
bio->bi_end_io(bio, error);
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index aea605c98ba6..ce08de7467a3 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -551,6 +551,7 @@ struct block_device *bdgrab(struct block_device *bdev)
ihold(bdev->bd_inode);
return bdev;
}
+EXPORT_SYMBOL(bdgrab);
long nr_blockdev_pages(void)
{
@@ -616,11 +617,9 @@ void bd_forget(struct inode *inode)
struct block_device *bdev = NULL;
spin_lock(&bdev_lock);
- if (inode->i_bdev) {
- if (!sb_is_blkdev_sb(inode->i_sb))
- bdev = inode->i_bdev;
- __bd_forget(inode);
- }
+ if (!sb_is_blkdev_sb(inode->i_sb))
+ bdev = inode->i_bdev;
+ __bd_forget(inode);
spin_unlock(&bdev_lock);
if (bdev)
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index ecd25a1b4e51..ca9d8f1a3bb6 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -651,6 +651,8 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
if (tree_mod_dont_log(fs_info, NULL))
return 0;
+ __tree_mod_log_free_eb(fs_info, old_root);
+
ret = tree_mod_alloc(fs_info, flags, &tm);
if (ret < 0)
goto out;
@@ -736,7 +738,7 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq)
static noinline void
tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
struct extent_buffer *src, unsigned long dst_offset,
- unsigned long src_offset, int nr_items)
+ unsigned long src_offset, int nr_items, int log_removal)
{
int ret;
int i;
@@ -750,10 +752,12 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
}
for (i = 0; i < nr_items; i++) {
- ret = tree_mod_log_insert_key_locked(fs_info, src,
- i + src_offset,
- MOD_LOG_KEY_REMOVE);
- BUG_ON(ret < 0);
+ if (log_removal) {
+ ret = tree_mod_log_insert_key_locked(fs_info, src,
+ i + src_offset,
+ MOD_LOG_KEY_REMOVE);
+ BUG_ON(ret < 0);
+ }
ret = tree_mod_log_insert_key_locked(fs_info, dst,
i + dst_offset,
MOD_LOG_KEY_ADD);
@@ -927,7 +931,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
ret = btrfs_dec_ref(trans, root, buf, 1, 1);
BUG_ON(ret); /* -ENOMEM */
}
- tree_mod_log_free_eb(root->fs_info, buf);
clean_tree_block(trans, root, buf);
*last_ref = 1;
}
@@ -1046,6 +1049,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_set_node_ptr_generation(parent, parent_slot,
trans->transid);
btrfs_mark_buffer_dirty(parent);
+ tree_mod_log_free_eb(root->fs_info, buf);
btrfs_free_tree_block(trans, root, buf, parent_start,
last_ref);
}
@@ -1750,7 +1754,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto enospc;
}
- tree_mod_log_free_eb(root->fs_info, root->node);
tree_mod_log_set_root_pointer(root, child);
rcu_assign_pointer(root->node, child);
@@ -2995,7 +2998,7 @@ static int push_node_left(struct btrfs_trans_handle *trans,
push_items = min(src_nritems - 8, push_items);
tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
- push_items);
+ push_items, 1);
copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(dst_nritems),
btrfs_node_key_ptr_offset(0),
@@ -3066,7 +3069,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
sizeof(struct btrfs_key_ptr));
tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
- src_nritems - push_items, push_items);
+ src_nritems - push_items, push_items, 1);
copy_extent_buffer(dst, src,
btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(src_nritems - push_items),
@@ -3218,12 +3221,18 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
int mid;
int ret;
u32 c_nritems;
+ int tree_mod_log_removal = 1;
c = path->nodes[level];
WARN_ON(btrfs_header_generation(c) != trans->transid);
if (c == root->node) {
/* trying to split the root, lets make a new one */
ret = insert_new_root(trans, root, path, level + 1);
+ /*
+ * removal of root nodes has been logged by
+ * tree_mod_log_set_root_pointer due to locking
+ */
+ tree_mod_log_removal = 0;
if (ret)
return ret;
} else {
@@ -3261,7 +3270,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
(unsigned long)btrfs_header_chunk_tree_uuid(split),
BTRFS_UUID_SIZE);
- tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
+ tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid,
+ tree_mod_log_removal);
copy_extent_buffer(split, c,
btrfs_node_key_ptr_offset(0),
btrfs_node_key_ptr_offset(mid),
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 7d84651e850b..6d19a0a554aa 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1291,6 +1291,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
0, objectid, NULL, 0, 0, 0);
if (IS_ERR(leaf)) {
ret = PTR_ERR(leaf);
+ leaf = NULL;
goto fail;
}
@@ -1334,11 +1335,16 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
btrfs_tree_unlock(leaf);
+ return root;
+
fail:
- if (ret)
- return ERR_PTR(ret);
+ if (leaf) {
+ btrfs_tree_unlock(leaf);
+ free_extent_buffer(leaf);
+ }
+ kfree(root);
- return root;
+ return ERR_PTR(ret);
}
static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
@@ -3253,7 +3259,7 @@ void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
if (btrfs_root_refs(&root->root_item) == 0)
synchronize_srcu(&fs_info->subvol_srcu);
- if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+ if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
btrfs_free_log(NULL, root);
btrfs_free_log_root_tree(NULL, fs_info);
}
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 9ac2eca681eb..3d551231caba 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root,
cache->bytes_super += stripe_len;
ret = add_excluded_extent(root, cache->key.objectid,
stripe_len);
- BUG_ON(ret); /* -ENOMEM */
+ if (ret)
+ return ret;
}
for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
@@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root,
ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
cache->key.objectid, bytenr,
0, &logical, &nr, &stripe_len);
- BUG_ON(ret); /* -ENOMEM */
+ if (ret)
+ return ret;
while (nr--) {
cache->bytes_super += stripe_len;
ret = add_excluded_extent(root, logical[nr],
stripe_len);
- BUG_ON(ret); /* -ENOMEM */
+ if (ret) {
+ kfree(logical);
+ return ret;
+ }
}
kfree(logical);
@@ -4438,7 +4443,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
spin_lock(&sinfo->lock);
spin_lock(&block_rsv->lock);
- block_rsv->size = num_bytes;
+ block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024);
num_bytes = sinfo->bytes_used + sinfo->bytes_pinned +
sinfo->bytes_reserved + sinfo->bytes_readonly +
@@ -4793,14 +4798,49 @@ out_fail:
* If the inodes csum_bytes is the same as the original
* csum_bytes then we know we haven't raced with any free()ers
* so we can just reduce our inodes csum bytes and carry on.
- * Otherwise we have to do the normal free thing to account for
- * the case that the free side didn't free up its reserve
- * because of this outstanding reservation.
*/
- if (BTRFS_I(inode)->csum_bytes == csum_bytes)
+ if (BTRFS_I(inode)->csum_bytes == csum_bytes) {
calc_csum_metadata_size(inode, num_bytes, 0);
- else
- to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+ } else {
+ u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes;
+ u64 bytes;
+
+ /*
+ * This is tricky, but first we need to figure out how much we
+ * free'd from any free-ers that occured during this
+ * reservation, so we reset ->csum_bytes to the csum_bytes
+ * before we dropped our lock, and then call the free for the
+ * number of bytes that were freed while we were trying our
+ * reservation.
+ */
+ bytes = csum_bytes - BTRFS_I(inode)->csum_bytes;
+ BTRFS_I(inode)->csum_bytes = csum_bytes;
+ to_free = calc_csum_metadata_size(inode, bytes, 0);
+
+
+ /*
+ * Now we need to see how much we would have freed had we not
+ * been making this reservation and our ->csum_bytes were not
+ * artificially inflated.
+ */
+ BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes;
+ bytes = csum_bytes - orig_csum_bytes;
+ bytes = calc_csum_metadata_size(inode, bytes, 0);
+
+ /*
+ * Now reset ->csum_bytes to what it should be. If bytes is
+ * more than to_free then we would have free'd more space had we
+ * not had an artificially high ->csum_bytes, so we need to free
+ * the remainder. If bytes is the same or less then we don't
+ * need to do anything, the other free-ers did the correct
+ * thing.
+ */
+ BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes;
+ if (bytes > to_free)
+ to_free = bytes - to_free;
+ else
+ to_free = 0;
+ }
spin_unlock(&BTRFS_I(inode)->lock);
if (dropped)
to_free += btrfs_calc_trans_metadata_size(root, dropped);
@@ -7947,7 +7987,17 @@ int btrfs_read_block_groups(struct btrfs_root *root)
* info has super bytes accounted for, otherwise we'll think
* we have more space than we actually do.
*/
- exclude_super_stripes(root, cache);
+ ret = exclude_super_stripes(root, cache);
+ if (ret) {
+ /*
+ * We may have excluded something, so call this just in
+ * case.
+ */
+ free_excluded_extents(root, cache);
+ kfree(cache->free_space_ctl);
+ kfree(cache);
+ goto error;
+ }
/*
* check for two cases, either we are full, and therefore
@@ -8089,7 +8139,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
cache->last_byte_to_unpin = (u64)-1;
cache->cached = BTRFS_CACHE_FINISHED;
- exclude_super_stripes(root, cache);
+ ret = exclude_super_stripes(root, cache);
+ if (ret) {
+ /*
+ * We may have excluded something, so call this just in
+ * case.
+ */
+ free_excluded_extents(root, cache);
+ kfree(cache->free_space_ctl);
+ kfree(cache);
+ return ret;
+ }
add_new_free_space(cache, root->fs_info, chunk_offset,
chunk_offset + size);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index f173c5af6461..cdee391fc7bf 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1257,6 +1257,39 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end)
GFP_NOFS);
}
+int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
+{
+ unsigned long index = start >> PAGE_CACHE_SHIFT;
+ unsigned long end_index = end >> PAGE_CACHE_SHIFT;
+ struct page *page;
+
+ while (index <= end_index) {
+ page = find_get_page(inode->i_mapping, index);
+ BUG_ON(!page); /* Pages should be in the extent_io_tree */
+ clear_page_dirty_for_io(page);
+ page_cache_release(page);
+ index++;
+ }
+ return 0;
+}
+
+int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
+{
+ unsigned long index = start >> PAGE_CACHE_SHIFT;
+ unsigned long end_index = end >> PAGE_CACHE_SHIFT;
+ struct page *page;
+
+ while (index <= end_index) {
+ page = find_get_page(inode->i_mapping, index);
+ BUG_ON(!page); /* Pages should be in the extent_io_tree */
+ account_page_redirty(page);
+ __set_page_dirty_nobuffers(page);
+ page_cache_release(page);
+ index++;
+ }
+ return 0;
+}
+
/*
* helper function to set both pages and extents in the tree writeback
*/
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 6068a1985560..258c92156857 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -325,6 +325,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
unsigned long *map_len);
int extent_range_uptodate(struct extent_io_tree *tree,
u64 start, u64 end);
+int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
+int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page,
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index ec160202be3e..c4628a201cb3 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -118,9 +118,11 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
csums_in_item /= csum_size;
- if (csum_offset >= csums_in_item) {
+ if (csum_offset == csums_in_item) {
ret = -EFBIG;
goto fail;
+ } else if (csum_offset > csums_in_item) {
+ goto fail;
}
}
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
@@ -728,7 +730,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
return -ENOMEM;
sector_sum = sums->sums;
- trans->adding_csums = 1;
again:
next_offset = (u64)-1;
found_next = 0;
@@ -899,7 +900,6 @@ next_sector:
goto again;
}
out:
- trans->adding_csums = 0;
btrfs_free_path(path);
return ret;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 254aeb72915f..bb8b7a0e28a6 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2139,6 +2139,7 @@ static long btrfs_fallocate(struct file *file, int mode,
{
struct inode *inode = file_inode(file);
struct extent_state *cached_state = NULL;
+ struct btrfs_root *root = BTRFS_I(inode)->root;
u64 cur_offset;
u64 last_byte;
u64 alloc_start;
@@ -2166,6 +2167,11 @@ static long btrfs_fallocate(struct file *file, int mode,
ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
if (ret)
return ret;
+ if (root->fs_info->quota_enabled) {
+ ret = btrfs_qgroup_reserve(root, alloc_end - alloc_start);
+ if (ret)
+ goto out_reserve_fail;
+ }
/*
* wait for ordered IO before we have any locks. We'll loop again
@@ -2269,6 +2275,9 @@ static long btrfs_fallocate(struct file *file, int mode,
&cached_state, GFP_NOFS);
out:
mutex_unlock(&inode->i_mutex);
+ if (root->fs_info->quota_enabled)
+ btrfs_qgroup_free(root, alloc_end - alloc_start);
+out_reserve_fail:
/* Let go of our reservation. */
btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
return ret;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ca1b767d51f7..09c58a35b429 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -353,6 +353,7 @@ static noinline int compress_file_range(struct inode *inode,
int i;
int will_compress;
int compress_type = root->fs_info->compress_type;
+ int redirty = 0;
/* if this is a small write inside eof, kick off a defrag */
if ((end - start + 1) < 16 * 1024 &&
@@ -415,6 +416,17 @@ again:
if (BTRFS_I(inode)->force_compress)
compress_type = BTRFS_I(inode)->force_compress;
+ /*
+ * we need to call clear_page_dirty_for_io on each
+ * page in the range. Otherwise applications with the file
+ * mmap'd can wander in and change the page contents while
+ * we are compressing them.
+ *
+ * If the compression fails for any reason, we set the pages
+ * dirty again later on.
+ */
+ extent_range_clear_dirty_for_io(inode, start, end);
+ redirty = 1;
ret = btrfs_compress_pages(compress_type,
inode->i_mapping, start,
total_compressed, pages,
@@ -554,6 +566,8 @@ cleanup_and_bail_uncompressed:
__set_page_dirty_nobuffers(locked_page);
/* unlocked later on in the async handlers */
}
+ if (redirty)
+ extent_range_redirty_for_io(inode, start, end);
add_async_extent(async_cow, start, end - start + 1,
0, NULL, 0, BTRFS_COMPRESS_NONE);
*num_added += 1;
@@ -1743,8 +1757,10 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
struct btrfs_ordered_sum *sum;
list_for_each_entry(sum, list, list) {
+ trans->adding_csums = 1;
btrfs_csum_file_blocks(trans,
BTRFS_I(inode)->root->fs_info->csum_root, sum);
+ trans->adding_csums = 0;
}
return 0;
}
@@ -3679,11 +3695,9 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
* 1 for the dir item
* 1 for the dir index
* 1 for the inode ref
- * 1 for the inode ref in the tree log
- * 2 for the dir entries in the log
* 1 for the inode
*/
- trans = btrfs_start_transaction(root, 8);
+ trans = btrfs_start_transaction(root, 5);
if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
return trans;
@@ -8127,7 +8141,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
* inodes. So 5 * 2 is 10, plus 1 for the new link, so 11 total items
* should cover the worst case number of items we'll modify.
*/
- trans = btrfs_start_transaction(root, 20);
+ trans = btrfs_start_transaction(root, 11);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out_notrans;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index dc08d77b717e..005c45db699e 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -557,6 +557,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
INIT_LIST_HEAD(&splice);
INIT_LIST_HEAD(&works);
+ mutex_lock(&root->fs_info->ordered_operations_mutex);
spin_lock(&root->fs_info->ordered_extent_lock);
list_splice_init(&root->fs_info->ordered_extents, &splice);
while (!list_empty(&splice)) {
@@ -600,6 +601,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
cond_resched();
}
+ mutex_unlock(&root->fs_info->ordered_operations_mutex);
}
/*
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 5471e47d6559..b44124dd2370 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1153,7 +1153,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
ret = btrfs_find_all_roots(trans, fs_info, node->bytenr,
sgn > 0 ? node->seq - 1 : node->seq, &roots);
if (ret < 0)
- goto out;
+ return ret;
spin_lock(&fs_info->qgroup_lock);
quota_root = fs_info->quota_root;
@@ -1275,7 +1275,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
ret = 0;
unlock:
spin_unlock(&fs_info->qgroup_lock);
-out:
ulist_free(roots);
ulist_free(tmp);
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 53c3501fa4ca..85e072b956d5 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -542,7 +542,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
eb = path->nodes[0];
ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
item_size = btrfs_item_size_nr(eb, path->slots[0]);
- btrfs_release_path(path);
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
do {
@@ -558,7 +557,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
ret < 0 ? -1 : ref_level,
ret < 0 ? -1 : ref_root);
} while (ret != 1);
+ btrfs_release_path(path);
} else {
+ btrfs_release_path(path);
swarn.path = path;
swarn.dev = dev;
iterate_extent_inodes(fs_info, found_key.objectid,
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index f7a8b861058b..c85e7c6b4598 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -3945,12 +3945,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
found_key.type != key.type) {
key.offset += right_len;
break;
- } else {
- if (found_key.offset != key.offset + right_len) {
- /* Should really not happen */
- ret = -EIO;
- goto out;
- }
+ }
+ if (found_key.offset != key.offset + right_len) {
+ ret = 0;
+ goto out;
}
key = found_key;
}
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 451fad96ecd1..ef96381569a4 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -317,6 +317,7 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
unsigned long src_ptr;
unsigned long dst_ptr;
int overwrite_root = 0;
+ bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
overwrite_root = 1;
@@ -326,6 +327,9 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
/* look for the key in the destination tree */
ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+ if (ret < 0)
+ return ret;
+
if (ret == 0) {
char *src_copy;
char *dst_copy;
@@ -367,6 +371,30 @@ static noinline int overwrite_item(struct btrfs_trans_handle *trans,
return 0;
}
+ /*
+ * We need to load the old nbytes into the inode so when we
+ * replay the extents we've logged we get the right nbytes.
+ */
+ if (inode_item) {
+ struct btrfs_inode_item *item;
+ u64 nbytes;
+
+ item = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_inode_item);
+ nbytes = btrfs_inode_nbytes(path->nodes[0], item);
+ item = btrfs_item_ptr(eb, slot,
+ struct btrfs_inode_item);
+ btrfs_set_inode_nbytes(eb, item, nbytes);
+ }
+ } else if (inode_item) {
+ struct btrfs_inode_item *item;
+
+ /*
+ * New inode, set nbytes to 0 so that the nbytes comes out
+ * properly when we replay the extents.
+ */
+ item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item);
+ btrfs_set_inode_nbytes(eb, item, 0);
}
insert:
btrfs_release_path(path);
@@ -486,7 +514,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
int found_type;
u64 extent_end;
u64 start = key->offset;
- u64 saved_nbytes;
+ u64 nbytes = 0;
struct btrfs_file_extent_item *item;
struct inode *inode = NULL;
unsigned long size;
@@ -496,10 +524,19 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
found_type = btrfs_file_extent_type(eb, item);
if (found_type == BTRFS_FILE_EXTENT_REG ||
- found_type == BTRFS_FILE_EXTENT_PREALLOC)
- extent_end = start + btrfs_file_extent_num_bytes(eb, item);
- else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
+ found_type == BTRFS_FILE_EXTENT_PREALLOC) {
+ nbytes = btrfs_file_extent_num_bytes(eb, item);
+ extent_end = start + nbytes;
+
+ /*
+ * We don't add to the inodes nbytes if we are prealloc or a
+ * hole.
+ */
+ if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
+ nbytes = 0;
+ } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
size = btrfs_file_extent_inline_len(eb, item);
+ nbytes = btrfs_file_extent_ram_bytes(eb, item);
extent_end = ALIGN(start + size, root->sectorsize);
} else {
ret = 0;
@@ -548,7 +585,6 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
}
btrfs_release_path(path);
- saved_nbytes = inode_get_bytes(inode);
/* drop any overlapping extents */
ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1);
BUG_ON(ret);
@@ -635,7 +671,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
BUG_ON(ret);
}
- inode_set_bytes(inode, saved_nbytes);
+ inode_add_bytes(inode, nbytes);
ret = btrfs_update_inode(trans, root, inode);
out:
if (inode)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 5989a92236f7..2854c824ab64 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
em = lookup_extent_mapping(em_tree, chunk_start, 1);
read_unlock(&em_tree->lock);
- BUG_ON(!em || em->start != chunk_start);
+ if (!em) {
+ printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n",
+ chunk_start);
+ return -EIO;
+ }
+
+ if (em->start != chunk_start) {
+ printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n",
+ em->start, chunk_start);
+ free_extent_map(em);
+ return -EIO;
+ }
map = (struct map_lookup *)em->bdev;
length = em->len;
diff --git a/fs/buffer.c b/fs/buffer.c
index b4dcb34c9635..bc1fe14aaa3e 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -865,8 +865,6 @@ try_again:
/* Link the buffer to its page */
set_bh_page(bh, page, offset);
-
- init_buffer(bh, NULL, NULL);
}
return head;
/*
@@ -2949,7 +2947,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
}
}
-int submit_bh(int rw, struct buffer_head * bh)
+int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags)
{
struct bio *bio;
int ret = 0;
@@ -2984,10 +2982,16 @@ int submit_bh(int rw, struct buffer_head * bh)
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
+ bio->bi_flags |= bio_flags;
/* Take care of bh's that straddle the end of the device */
guard_bh_eod(rw, bio, bh);
+ if (buffer_meta(bh))
+ rw |= REQ_META;
+ if (buffer_prio(bh))
+ rw |= REQ_PRIO;
+
bio_get(bio);
submit_bio(rw, bio);
@@ -2997,6 +3001,12 @@ int submit_bh(int rw, struct buffer_head * bh)
bio_put(bio);
return ret;
}
+EXPORT_SYMBOL_GPL(_submit_bh);
+
+int submit_bh(int rw, struct buffer_head *bh)
+{
+ return _submit_bh(rw, bh, 0);
+}
EXPORT_SYMBOL(submit_bh);
/**
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 991c63c6bdd0..21b3a291c327 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1575,14 +1575,24 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
}
break;
case Opt_blank_pass:
- vol->password = NULL;
- break;
- case Opt_pass:
/* passwords have to be handled differently
* to allow the character used for deliminator
* to be passed within them
*/
+ /*
+ * Check if this is a case where the password
+ * starts with a delimiter
+ */
+ tmp_end = strchr(data, '=');
+ tmp_end++;
+ if (!(tmp_end < end && tmp_end[1] == delim)) {
+ /* No it is not. Set the password to NULL */
+ vol->password = NULL;
+ break;
+ }
+ /* Yes it is. Drop down to Opt_pass below.*/
+ case Opt_pass:
/* Obtain the value string */
value = strchr(data, '=');
value++;
diff --git a/fs/compat.c b/fs/compat.c
index 5058345dc279..d0560c93973d 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -44,7 +44,6 @@
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/mm.h>
-#include <linux/eventpoll.h>
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
@@ -1069,26 +1068,6 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
}
#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
-asmlinkage long
-compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
- unsigned int nr_segs, unsigned int flags)
-{
- unsigned i;
- struct iovec __user *iov;
- if (nr_segs > UIO_MAXIOV)
- return -EINVAL;
- iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
- for (i = 0; i < nr_segs; i++) {
- struct compat_iovec v;
- if (get_user(v.iov_base, &iov32[i].iov_base) ||
- get_user(v.iov_len, &iov32[i].iov_len) ||
- put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
- put_user(v.iov_len, &iov[i].iov_len))
- return -EFAULT;
- }
- return sys_vmsplice(fd, iov, nr_segs, flags);
-}
-
/*
* Exactly like fs/open.c:sys_open(), except that it doesn't set the
* O_LARGEFILE flag.
@@ -1474,84 +1453,6 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
return ret;
}
-#ifdef CONFIG_EPOLL
-
-asmlinkage long compat_sys_epoll_pwait(int epfd,
- struct compat_epoll_event __user *events,
- int maxevents, int timeout,
- const compat_sigset_t __user *sigmask,
- compat_size_t sigsetsize)
-{
- long err;
- compat_sigset_t csigmask;
- sigset_t ksigmask, sigsaved;
-
- /*
- * If the caller wants a certain signal mask to be set during the wait,
- * we apply it here.
- */
- if (sigmask) {
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
- if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
- return -EFAULT;
- sigset_from_compat(&ksigmask, &csigmask);
- sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
- sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
- }
-
- err = sys_epoll_wait(epfd, events, maxevents, timeout);
-
- /*
- * If we changed the signal mask, we need to restore the original one.
- * In case we've got a signal while waiting, we do not restore the
- * signal mask yet, and we allow do_signal() to deliver the signal on
- * the way back to userspace, before the signal mask is restored.
- */
- if (sigmask) {
- if (err == -EINTR) {
- memcpy(&current->saved_sigmask, &sigsaved,
- sizeof(sigsaved));
- set_restore_sigmask();
- } else
- sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- }
-
- return err;
-}
-
-#endif /* CONFIG_EPOLL */
-
-#ifdef CONFIG_SIGNALFD
-
-asmlinkage long compat_sys_signalfd4(int ufd,
- const compat_sigset_t __user *sigmask,
- compat_size_t sigsetsize, int flags)
-{
- compat_sigset_t ss32;
- sigset_t tmp;
- sigset_t __user *ksigmask;
-
- if (sigsetsize != sizeof(compat_sigset_t))
- return -EINVAL;
- if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
- return -EFAULT;
- sigset_from_compat(&tmp, &ss32);
- ksigmask = compat_alloc_user_space(sizeof(sigset_t));
- if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
- return -EFAULT;
-
- return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
-}
-
-asmlinkage long compat_sys_signalfd(int ufd,
- const compat_sigset_t __user *sigmask,
- compat_size_t sigsetsize)
-{
- return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0);
-}
-#endif /* CONFIG_SIGNALFD */
-
#ifdef CONFIG_FHANDLE
/*
* Exactly like fs/open.c:sys_open_by_handle_at(), except that it
@@ -1563,25 +1464,3 @@ COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
return do_handle_open(mountdirfd, handle, flags);
}
#endif
-
-#ifdef __ARCH_WANT_COMPAT_SYS_SENDFILE
-asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
- compat_off_t __user *offset, compat_size_t count)
-{
- loff_t pos;
- off_t off;
- ssize_t ret;
-
- if (offset) {
- if (unlikely(get_user(off, offset)))
- return -EFAULT;
- pos = off;
- ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
- if (unlikely(put_user(pos, offset)))
- return -EFAULT;
- return ret;
- }
-
- return do_sendfile(out_fd, in_fd, NULL, count, 0);
-}
-#endif /* __ARCH_WANT_COMPAT_SYS_SENDFILE */
diff --git a/fs/coredump.c b/fs/coredump.c
index a987f3d39d93..a9abe313e8d5 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -263,7 +263,6 @@ static int zap_process(struct task_struct *start, int exit_code)
struct task_struct *t;
int nr = 0;
- start->signal->flags = SIGNAL_GROUP_EXIT;
start->signal->group_exit_code = exit_code;
start->signal->group_stop_count = 0;
@@ -280,8 +279,8 @@ static int zap_process(struct task_struct *start, int exit_code)
return nr;
}
-static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
- struct core_state *core_state, int exit_code)
+static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
+ struct core_state *core_state, int exit_code)
{
struct task_struct *g, *p;
unsigned long flags;
@@ -291,11 +290,16 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
if (!signal_group_exit(tsk->signal)) {
mm->core_state = core_state;
nr = zap_process(tsk, exit_code);
+ tsk->signal->group_exit_task = tsk;
+ /* ignore all signals except SIGKILL, see prepare_signal() */
+ tsk->signal->flags = SIGNAL_GROUP_COREDUMP;
+ clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
}
spin_unlock_irq(&tsk->sighand->siglock);
if (unlikely(nr < 0))
return nr;
+ tsk->flags = PF_DUMPCORE;
if (atomic_read(&mm->mm_users) == nr + 1)
goto done;
/*
@@ -340,6 +344,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
if (unlikely(p->mm == mm)) {
lock_task_sighand(p, &flags);
nr += zap_process(p, exit_code);
+ p->signal->flags = SIGNAL_GROUP_EXIT;
unlock_task_sighand(p, &flags);
}
break;
@@ -386,11 +391,18 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
return core_waiters;
}
-static void coredump_finish(struct mm_struct *mm)
+static void coredump_finish(struct mm_struct *mm, bool core_dumped)
{
struct core_thread *curr, *next;
struct task_struct *task;
+ spin_lock_irq(&current->sighand->siglock);
+ if (core_dumped && !__fatal_signal_pending(current))
+ current->signal->group_exit_code |= 0x80;
+ current->signal->group_exit_task = NULL;
+ current->signal->flags = SIGNAL_GROUP_EXIT;
+ spin_unlock_irq(&current->sighand->siglock);
+
next = mm->core_state->dumper.next;
while ((curr = next) != NULL) {
next = curr->next;
@@ -407,6 +419,17 @@ static void coredump_finish(struct mm_struct *mm)
mm->core_state = NULL;
}
+static bool dump_interrupted(void)
+{
+ /*
+ * SIGKILL or freezing() interrupt the coredumping. Perhaps we
+ * can do try_to_freeze() and check __fatal_signal_pending(),
+ * but then we need to teach dump_write() to restart and clear
+ * TIF_SIGPENDING.
+ */
+ return signal_pending(current);
+}
+
static void wait_for_dump_helpers(struct file *file)
{
struct pipe_inode_info *pipe = file->private_data;
@@ -414,17 +437,20 @@ static void wait_for_dump_helpers(struct file *file)
pipe_lock(pipe);
pipe->readers++;
pipe->writers--;
+ wake_up_interruptible_sync(&pipe->wait);
+ kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+ pipe_unlock(pipe);
- while ((pipe->readers > 1) && (!signal_pending(current))) {
- wake_up_interruptible_sync(&pipe->wait);
- kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
- pipe_wait(pipe);
- }
+ /*
+ * We actually want wait_event_freezable() but then we need
+ * to clear TIF_SIGPENDING and improve dump_interrupted().
+ */
+ wait_event_interruptible(pipe->wait, pipe->readers == 1);
+ pipe_lock(pipe);
pipe->readers--;
pipe->writers++;
pipe_unlock(pipe);
-
}
/*
@@ -469,6 +495,7 @@ void do_coredump(siginfo_t *siginfo)
int ispipe;
struct files_struct *displaced;
bool need_nonrelative = false;
+ bool core_dumped = false;
static atomic_t core_dump_count = ATOMIC_INIT(0);
struct coredump_params cprm = {
.siginfo = siginfo,
@@ -512,17 +539,12 @@ void do_coredump(siginfo_t *siginfo)
old_cred = override_creds(cred);
- /*
- * Clear any false indication of pending signals that might
- * be seen by the filesystem code called to write the core file.
- */
- clear_thread_flag(TIF_SIGPENDING);
-
ispipe = format_corename(&cn, &cprm);
- if (ispipe) {
+ if (ispipe) {
int dump_count;
char **helper_argv;
+ struct subprocess_info *sub_info;
if (ispipe < 0) {
printk(KERN_WARNING "format_corename failed\n");
@@ -569,15 +591,20 @@ void do_coredump(siginfo_t *siginfo)
goto fail_dropcount;
}
- retval = call_usermodehelper_fns(helper_argv[0], helper_argv,
- NULL, UMH_WAIT_EXEC, umh_pipe_setup,
- NULL, &cprm);
+ retval = -ENOMEM;
+ sub_info = call_usermodehelper_setup(helper_argv[0],
+ helper_argv, NULL, GFP_KERNEL,
+ umh_pipe_setup, NULL, &cprm);
+ if (sub_info)
+ retval = call_usermodehelper_exec(sub_info,
+ UMH_WAIT_EXEC);
+
argv_free(helper_argv);
if (retval) {
- printk(KERN_INFO "Core dump to %s pipe failed\n",
+ printk(KERN_INFO "Core dump to %s pipe failed\n",
cn.corename);
goto close_fail;
- }
+ }
} else {
struct inode *inode;
@@ -628,9 +655,7 @@ void do_coredump(siginfo_t *siginfo)
if (displaced)
put_files_struct(displaced);
file_start_write(cprm.file);
- retval = binfmt->core_dump(&cprm);
- if (retval)
- current->signal->group_exit_code |= 0x80;
+ core_dumped = !dump_interrupted() && binfmt->core_dump(&cprm);
file_end_write(cprm.file);
if (ispipe && core_pipe_limit)
@@ -644,7 +669,7 @@ fail_dropcount:
fail_unlock:
kfree(cn.corename);
fail_corename:
- coredump_finish(mm);
+ coredump_finish(mm, core_dumped);
revert_creds(old_cred);
fail_creds:
put_cred(cred);
@@ -659,7 +684,9 @@ fail:
*/
int dump_write(struct file *file, const void *addr, int nr)
{
- return access_ok(VERIFY_READ, addr, nr) && file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+ return !dump_interrupted() &&
+ access_ok(VERIFY_READ, addr, nr) &&
+ file->f_op->write(file, addr, nr, &file->f_pos) == nr;
}
EXPORT_SYMBOL(dump_write);
@@ -668,7 +695,8 @@ int dump_seek(struct file *file, loff_t off)
int ret = 1;
if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
- if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
+ if (dump_interrupted() ||
+ file->f_op->llseek(file, off, SEEK_CUR) < 0)
return 0;
} else {
char *buf = (char *)get_zeroed_page(GFP_KERNEL);
diff --git a/fs/dcache.c b/fs/dcache.c
index e8bc3420d63e..e689268046c3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1230,8 +1230,10 @@ void shrink_dcache_parent(struct dentry * parent)
LIST_HEAD(dispose);
int found;
- while ((found = select_parent(parent, &dispose)) != 0)
+ while ((found = select_parent(parent, &dispose)) != 0) {
shrink_dentry_list(&dispose);
+ cond_resched();
+ }
}
EXPORT_SYMBOL(shrink_dcache_parent);
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 17c779967828..ab5954b50267 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -25,6 +25,7 @@
#include <linux/dcookies.h>
#include <linux/mutex.h>
#include <linux/path.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
/* The dcookies are allocated from a kmem_cache and
@@ -145,7 +146,7 @@ out:
/* And here is where the userspace process can look up the cookie value
* to retrieve the path.
*/
-SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len)
+SYSCALL_DEFINE3(lookup_dcookie, u64, cookie64, char __user *, buf, size_t, len)
{
unsigned long cookie = (unsigned long)cookie64;
int err = -EINVAL;
@@ -201,12 +202,16 @@ out:
mutex_unlock(&dcookie_mutex);
return err;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_lookup_dcookie(u64 cookie64, long buf, long len)
+
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, size_t, len)
{
- return SYSC_lookup_dcookie(cookie64, (char __user *) buf, (size_t) len);
+#ifdef __BIG_ENDIAN
+ return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len);
+#else
+ return sys_lookup_dcookie(((u64)w1 << 32) | w0, buf, len);
+#endif
}
-SYSCALL_ALIAS(sys_lookup_dcookie, SyS_lookup_dcookie);
#endif
static int dcookie_init(void)
diff --git a/fs/direct-io.c b/fs/direct-io.c
index f853263cf74f..cfb816dc6d9f 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -672,12 +672,6 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio,
if (sdio->final_block_in_bio != sdio->cur_page_block ||
cur_offset != bio_next_offset)
dio_bio_submit(dio, sdio);
- /*
- * Submit now if the underlying fs is about to perform a
- * metadata read
- */
- else if (sdio->boundary)
- dio_bio_submit(dio, sdio);
}
if (sdio->bio == NULL) {
@@ -737,16 +731,6 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
sdio->cur_page_block +
(sdio->cur_page_len >> sdio->blkbits) == blocknr) {
sdio->cur_page_len += len;
-
- /*
- * If sdio->boundary then we want to schedule the IO now to
- * avoid metadata seeks.
- */
- if (sdio->boundary) {
- ret = dio_send_cur_page(dio, sdio, map_bh);
- page_cache_release(sdio->cur_page);
- sdio->cur_page = NULL;
- }
goto out;
}
@@ -758,7 +742,7 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
page_cache_release(sdio->cur_page);
sdio->cur_page = NULL;
if (ret)
- goto out;
+ return ret;
}
page_cache_get(page); /* It is in dio */
@@ -768,6 +752,16 @@ submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page,
sdio->cur_page_block = blocknr;
sdio->cur_page_fs_offset = sdio->block_in_file << sdio->blkbits;
out:
+ /*
+ * If sdio->boundary then we want to schedule the IO now to
+ * avoid metadata seeks.
+ */
+ if (sdio->boundary) {
+ ret = dio_send_cur_page(dio, sdio, map_bh);
+ dio_bio_submit(dio, sdio);
+ page_cache_release(sdio->cur_page);
+ sdio->cur_page = NULL;
+ }
return ret;
}
@@ -969,7 +963,8 @@ do_holes:
this_chunk_bytes = this_chunk_blocks << blkbits;
BUG_ON(this_chunk_bytes == 0);
- sdio->boundary = buffer_boundary(map_bh);
+ if (this_chunk_blocks == sdio->blocks_available)
+ sdio->boundary = buffer_boundary(map_bh);
ret = submit_page_section(dio, sdio, page,
offset_in_page,
this_chunk_bytes,
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 4f5ad246582f..d0ccd2fd79eb 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -52,8 +52,8 @@
#include <linux/mutex.h>
#include <linux/sctp.h>
#include <linux/slab.h>
+#include <linux/sctp.h>
#include <net/sctp/sctp.h>
-#include <net/sctp/user.h>
#include <net/ipv6.h>
#include "dlm_internal.h"
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
index 01fd5c11a7fb..f704458ea5f5 100644
--- a/fs/dlm/plock.c
+++ b/fs/dlm/plock.c
@@ -247,6 +247,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
struct dlm_ls *ls;
struct plock_op *op;
int rv;
+ unsigned char fl_flags = fl->fl_flags;
ls = dlm_find_lockspace_local(lockspace);
if (!ls)
@@ -258,9 +259,18 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
goto out;
}
- if (posix_lock_file_wait(file, fl) < 0)
- log_error(ls, "dlm_posix_unlock: vfs unlock error %llx",
- (unsigned long long)number);
+ /* cause the vfs unlock to return ENOENT if lock is not found */
+ fl->fl_flags |= FL_EXISTS;
+
+ rv = posix_lock_file_wait(file, fl);
+ if (rv == -ENOENT) {
+ rv = 0;
+ goto out_free;
+ }
+ if (rv < 0) {
+ log_error(ls, "dlm_posix_unlock: vfs unlock error %d %llx",
+ rv, (unsigned long long)number);
+ }
op->info.optype = DLM_PLOCK_OP_UNLOCK;
op->info.pid = fl->fl_pid;
@@ -296,9 +306,11 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
if (rv == -ENOENT)
rv = 0;
+out_free:
kfree(op);
out:
dlm_put_lockspace(ls);
+ fl->fl_flags = fl_flags;
return rv;
}
EXPORT_SYMBOL_GPL(dlm_posix_unlock);
diff --git a/fs/efivarfs/Kconfig b/fs/efivarfs/Kconfig
new file mode 100644
index 000000000000..367bbb10c543
--- /dev/null
+++ b/fs/efivarfs/Kconfig
@@ -0,0 +1,12 @@
+config EFIVAR_FS
+ tristate "EFI Variable filesystem"
+ depends on EFI
+ help
+ efivarfs is a replacement filesystem for the old EFI
+ variable support via sysfs, as it doesn't suffer from the
+ same 1024-byte variable size limit.
+
+ To compile this file system support as a module, choose M
+ here. The module will be called efivarfs.
+
+ If unsure, say N.
diff --git a/fs/efivarfs/Makefile b/fs/efivarfs/Makefile
new file mode 100644
index 000000000000..955d478177d5
--- /dev/null
+++ b/fs/efivarfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the efivarfs filesystem
+#
+
+obj-$(CONFIG_EFIVAR_FS) += efivarfs.o
+
+efivarfs-objs := inode.o file.o super.o
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
new file mode 100644
index 000000000000..bfb531564319
--- /dev/null
+++ b/fs/efivarfs/file.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static ssize_t efivarfs_file_write(struct file *file,
+ const char __user *userbuf, size_t count, loff_t *ppos)
+{
+ struct efivar_entry *var = file->private_data;
+ void *data;
+ u32 attributes;
+ struct inode *inode = file->f_mapping->host;
+ unsigned long datasize = count - sizeof(attributes);
+ ssize_t bytes = 0;
+ bool set = false;
+
+ if (count < sizeof(attributes))
+ return -EINVAL;
+
+ if (copy_from_user(&attributes, userbuf, sizeof(attributes)))
+ return -EFAULT;
+
+ if (attributes & ~(EFI_VARIABLE_MASK))
+ return -EINVAL;
+
+ data = kmalloc(datasize, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (copy_from_user(data, userbuf + sizeof(attributes), datasize)) {
+ bytes = -EFAULT;
+ goto out;
+ }
+
+ bytes = efivar_entry_set_get_size(var, attributes, &datasize,
+ data, &set);
+ if (!set && bytes)
+ goto out;
+
+ if (bytes == -ENOENT) {
+ drop_nlink(inode);
+ d_delete(file->f_dentry);
+ dput(file->f_dentry);
+ } else {
+ mutex_lock(&inode->i_mutex);
+ i_size_write(inode, datasize + sizeof(attributes));
+ mutex_unlock(&inode->i_mutex);
+ }
+
+ bytes = count;
+
+out:
+ kfree(data);
+
+ return bytes;
+}
+
+static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct efivar_entry *var = file->private_data;
+ unsigned long datasize = 0;
+ u32 attributes;
+ void *data;
+ ssize_t size = 0;
+ int err;
+
+ err = efivar_entry_size(var, &datasize);
+ if (err)
+ return err;
+
+ data = kmalloc(datasize + sizeof(attributes), GFP_KERNEL);
+
+ if (!data)
+ return -ENOMEM;
+
+ size = efivar_entry_get(var, &attributes, &datasize,
+ data + sizeof(attributes));
+ if (size)
+ goto out_free;
+
+ memcpy(data, &attributes, sizeof(attributes));
+ size = simple_read_from_buffer(userbuf, count, ppos,
+ data, datasize + sizeof(attributes));
+out_free:
+ kfree(data);
+
+ return size;
+}
+
+const struct file_operations efivarfs_file_operations = {
+ .open = simple_open,
+ .read = efivarfs_file_read,
+ .write = efivarfs_file_write,
+ .llseek = no_llseek,
+};
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
new file mode 100644
index 000000000000..7e787fb90293
--- /dev/null
+++ b/fs/efivarfs/inode.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <linux/fs.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+struct inode *efivarfs_get_inode(struct super_block *sb,
+ const struct inode *dir, int mode, dev_t dev)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode) {
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ inode->i_fop = &efivarfs_file_operations;
+ break;
+ case S_IFDIR:
+ inode->i_op = &efivarfs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inc_nlink(inode);
+ break;
+ }
+ }
+ return inode;
+}
+
+/*
+ * Return true if 'str' is a valid efivarfs filename of the form,
+ *
+ * VariableName-12345678-1234-1234-1234-1234567891bc
+ */
+bool efivarfs_valid_name(const char *str, int len)
+{
+ static const char dashes[EFI_VARIABLE_GUID_LEN] = {
+ [8] = 1, [13] = 1, [18] = 1, [23] = 1
+ };
+ const char *s = str + len - EFI_VARIABLE_GUID_LEN;
+ int i;
+
+ /*
+ * We need a GUID, plus at least one letter for the variable name,
+ * plus the '-' separator
+ */
+ if (len < EFI_VARIABLE_GUID_LEN + 2)
+ return false;
+
+ /* GUID must be preceded by a '-' */
+ if (*(s - 1) != '-')
+ return false;
+
+ /*
+ * Validate that 's' is of the correct format, e.g.
+ *
+ * 12345678-1234-1234-1234-123456789abc
+ */
+ for (i = 0; i < EFI_VARIABLE_GUID_LEN; i++) {
+ if (dashes[i]) {
+ if (*s++ != '-')
+ return false;
+ } else {
+ if (!isxdigit(*s++))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
+{
+ guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
+ guid->b[1] = hex_to_bin(str[4]) << 4 | hex_to_bin(str[5]);
+ guid->b[2] = hex_to_bin(str[2]) << 4 | hex_to_bin(str[3]);
+ guid->b[3] = hex_to_bin(str[0]) << 4 | hex_to_bin(str[1]);
+ guid->b[4] = hex_to_bin(str[11]) << 4 | hex_to_bin(str[12]);
+ guid->b[5] = hex_to_bin(str[9]) << 4 | hex_to_bin(str[10]);
+ guid->b[6] = hex_to_bin(str[16]) << 4 | hex_to_bin(str[17]);
+ guid->b[7] = hex_to_bin(str[14]) << 4 | hex_to_bin(str[15]);
+ guid->b[8] = hex_to_bin(str[19]) << 4 | hex_to_bin(str[20]);
+ guid->b[9] = hex_to_bin(str[21]) << 4 | hex_to_bin(str[22]);
+ guid->b[10] = hex_to_bin(str[24]) << 4 | hex_to_bin(str[25]);
+ guid->b[11] = hex_to_bin(str[26]) << 4 | hex_to_bin(str[27]);
+ guid->b[12] = hex_to_bin(str[28]) << 4 | hex_to_bin(str[29]);
+ guid->b[13] = hex_to_bin(str[30]) << 4 | hex_to_bin(str[31]);
+ guid->b[14] = hex_to_bin(str[32]) << 4 | hex_to_bin(str[33]);
+ guid->b[15] = hex_to_bin(str[34]) << 4 | hex_to_bin(str[35]);
+}
+
+static int efivarfs_create(struct inode *dir, struct dentry *dentry,
+ umode_t mode, bool excl)
+{
+ struct inode *inode;
+ struct efivar_entry *var;
+ int namelen, i = 0, err = 0;
+
+ if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
+ return -EINVAL;
+
+ inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
+ if (!inode)
+ return -ENOMEM;
+
+ var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL);
+ if (!var) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* length of the variable name itself: remove GUID and separator */
+ namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1;
+
+ efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1,
+ &var->var.VendorGuid);
+
+ for (i = 0; i < namelen; i++)
+ var->var.VariableName[i] = dentry->d_name.name[i];
+
+ var->var.VariableName[i] = '\0';
+
+ inode->i_private = var;
+
+ efivar_entry_add(var, &efivarfs_list);
+ d_instantiate(dentry, inode);
+ dget(dentry);
+out:
+ if (err) {
+ kfree(var);
+ iput(inode);
+ }
+ return err;
+}
+
+static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct efivar_entry *var = dentry->d_inode->i_private;
+
+ if (efivar_entry_delete(var))
+ return -EINVAL;
+
+ drop_nlink(dentry->d_inode);
+ dput(dentry);
+ return 0;
+};
+
+/*
+ * Handle negative dentry.
+ */
+static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ if (dentry->d_name.len > NAME_MAX)
+ return ERR_PTR(-ENAMETOOLONG);
+ d_add(dentry, NULL);
+ return NULL;
+}
+
+const struct inode_operations efivarfs_dir_inode_operations = {
+ .lookup = efivarfs_lookup,
+ .unlink = efivarfs_unlink,
+ .create = efivarfs_create,
+};
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
new file mode 100644
index 000000000000..b5ff16addb7c
--- /dev/null
+++ b/fs/efivarfs/internal.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef EFIVAR_FS_INTERNAL_H
+#define EFIVAR_FS_INTERNAL_H
+
+#include <linux/list.h>
+
+extern const struct file_operations efivarfs_file_operations;
+extern const struct inode_operations efivarfs_dir_inode_operations;
+extern bool efivarfs_valid_name(const char *str, int len);
+extern struct inode *efivarfs_get_inode(struct super_block *sb,
+ const struct inode *dir, int mode, dev_t dev);
+
+extern struct list_head efivarfs_list;
+
+#endif /* EFIVAR_FS_INTERNAL_H */
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
new file mode 100644
index 000000000000..141aee31884f
--- /dev/null
+++ b/fs/efivarfs/super.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2012 Jeremy Kerr <jeremy.kerr@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ctype.h>
+#include <linux/efi.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/ucs2_string.h>
+#include <linux/slab.h>
+#include <linux/magic.h>
+
+#include "internal.h"
+
+LIST_HEAD(efivarfs_list);
+
+static void efivarfs_evict_inode(struct inode *inode)
+{
+ clear_inode(inode);
+}
+
+static const struct super_operations efivarfs_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+ .evict_inode = efivarfs_evict_inode,
+ .show_options = generic_show_options,
+};
+
+static struct super_block *efivarfs_sb;
+
+/*
+ * Compare two efivarfs file names.
+ *
+ * An efivarfs filename is composed of two parts,
+ *
+ * 1. A case-sensitive variable name
+ * 2. A case-insensitive GUID
+ *
+ * So we need to perform a case-sensitive match on part 1 and a
+ * case-insensitive match on part 2.
+ */
+static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
+ const struct dentry *dentry, const struct inode *inode,
+ unsigned int len, const char *str,
+ const struct qstr *name)
+{
+ int guid = len - EFI_VARIABLE_GUID_LEN;
+
+ if (name->len != len)
+ return 1;
+
+ /* Case-sensitive compare for the variable name */
+ if (memcmp(str, name->name, guid))
+ return 1;
+
+ /* Case-insensitive compare for the GUID */
+ return strncasecmp(name->name + guid, str + guid, EFI_VARIABLE_GUID_LEN);
+}
+
+static int efivarfs_d_hash(const struct dentry *dentry,
+ const struct inode *inode, struct qstr *qstr)
+{
+ unsigned long hash = init_name_hash();
+ const unsigned char *s = qstr->name;
+ unsigned int len = qstr->len;
+
+ if (!efivarfs_valid_name(s, len))
+ return -EINVAL;
+
+ while (len-- > EFI_VARIABLE_GUID_LEN)
+ hash = partial_name_hash(*s++, hash);
+
+ /* GUID is case-insensitive. */
+ while (len--)
+ hash = partial_name_hash(tolower(*s++), hash);
+
+ qstr->hash = end_name_hash(hash);
+ return 0;
+}
+
+/*
+ * Retaining negative dentries for an in-memory filesystem just wastes
+ * memory and lookup time: arrange for them to be deleted immediately.
+ */
+static int efivarfs_delete_dentry(const struct dentry *dentry)
+{
+ return 1;
+}
+
+static struct dentry_operations efivarfs_d_ops = {
+ .d_compare = efivarfs_d_compare,
+ .d_hash = efivarfs_d_hash,
+ .d_delete = efivarfs_delete_dentry,
+};
+
+static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
+{
+ struct dentry *d;
+ struct qstr q;
+ int err;
+
+ q.name = name;
+ q.len = strlen(name);
+
+ err = efivarfs_d_hash(NULL, NULL, &q);
+ if (err)
+ return ERR_PTR(err);
+
+ d = d_alloc(parent, &q);
+ if (d)
+ return d;
+
+ return ERR_PTR(-ENOMEM);
+}
+
+static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
+ unsigned long name_size, void *data)
+{
+ struct super_block *sb = (struct super_block *)data;
+ struct efivar_entry *entry;
+ struct inode *inode = NULL;
+ struct dentry *dentry, *root = sb->s_root;
+ unsigned long size = 0;
+ char *name;
+ int len, i;
+ int err = -ENOMEM;
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return err;
+
+ memcpy(entry->var.VariableName, name16, name_size);
+ memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
+
+ len = ucs2_strlen(entry->var.VariableName);
+
+ /* name, plus '-', plus GUID, plus NUL*/
+ name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL);
+ if (!name)
+ goto fail;
+
+ for (i = 0; i < len; i++)
+ name[i] = entry->var.VariableName[i] & 0xFF;
+
+ name[len] = '-';
+
+ efi_guid_unparse(&entry->var.VendorGuid, name + len + 1);
+
+ name[len + EFI_VARIABLE_GUID_LEN+1] = '\0';
+
+ inode = efivarfs_get_inode(sb, root->d_inode, S_IFREG | 0644, 0);
+ if (!inode)
+ goto fail_name;
+
+ dentry = efivarfs_alloc_dentry(root, name);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ goto fail_inode;
+ }
+
+ /* copied by the above to local storage in the dentry. */
+ kfree(name);
+
+ efivar_entry_size(entry, &size);
+ efivar_entry_add(entry, &efivarfs_list);
+
+ mutex_lock(&inode->i_mutex);
+ inode->i_private = entry;
+ i_size_write(inode, size + sizeof(entry->var.Attributes));
+ mutex_unlock(&inode->i_mutex);
+ d_add(dentry, inode);
+
+ return 0;
+
+fail_inode:
+ iput(inode);
+fail_name:
+ kfree(name);
+fail:
+ kfree(entry);
+ return err;
+}
+
+static int efivarfs_destroy(struct efivar_entry *entry, void *data)
+{
+ efivar_entry_remove(entry);
+ kfree(entry);
+ return 0;
+}
+
+static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *inode = NULL;
+ struct dentry *root;
+ int err;
+
+ efivarfs_sb = sb;
+
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = EFIVARFS_MAGIC;
+ sb->s_op = &efivarfs_ops;
+ sb->s_d_op = &efivarfs_d_ops;
+ sb->s_time_gran = 1;
+
+ inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
+ if (!inode)
+ return -ENOMEM;
+ inode->i_op = &efivarfs_dir_inode_operations;
+
+ root = d_make_root(inode);
+ sb->s_root = root;
+ if (!root)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&efivarfs_list);
+
+ err = efivar_init(efivarfs_callback, (void *)sb, false,
+ true, &efivarfs_list);
+ if (err)
+ __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
+
+ return err;
+}
+
+static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
+{
+ return mount_single(fs_type, flags, data, efivarfs_fill_super);
+}
+
+static void efivarfs_kill_sb(struct super_block *sb)
+{
+ kill_litter_super(sb);
+ efivarfs_sb = NULL;
+
+ /* Remove all entries and destroy */
+ __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
+}
+
+static struct file_system_type efivarfs_type = {
+ .name = "efivarfs",
+ .mount = efivarfs_mount,
+ .kill_sb = efivarfs_kill_sb,
+};
+
+static __init int efivarfs_init(void)
+{
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ return 0;
+
+ if (!efivars_kobject())
+ return 0;
+
+ return register_filesystem(&efivarfs_type);
+}
+
+MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr");
+MODULE_DESCRIPTION("EFI Variable Filesystem");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_FS("efivarfs");
+
+module_init(efivarfs_init);
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 9fec1836057a..deecc7294a67 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -40,6 +40,7 @@
#include <linux/atomic.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/compat.h>
/*
* LOCKING:
@@ -104,7 +105,7 @@
struct epoll_filefd {
struct file *file;
int fd;
-};
+} __packed;
/*
* Structure used to track possible nested calls, for too deep recursions
@@ -128,6 +129,8 @@ struct nested_calls {
/*
* Each file descriptor added to the eventpoll interface will
* have an entry of this type linked to the "rbr" RB tree.
+ * Avoid increasing the size of this struct, there can be many thousands
+ * of these on a server and we do not want this to take another cache line.
*/
struct epitem {
/* RB tree node used to link this structure to the eventpoll RB tree */
@@ -158,7 +161,7 @@ struct epitem {
struct list_head fllink;
/* wakeup_source used when EPOLLWAKEUP is set */
- struct wakeup_source *ws;
+ struct wakeup_source __rcu *ws;
/* The structure that describe the interested events and the source fd */
struct epoll_event event;
@@ -536,6 +539,38 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
}
}
+/* call only when ep->mtx is held */
+static inline struct wakeup_source *ep_wakeup_source(struct epitem *epi)
+{
+ return rcu_dereference_check(epi->ws, lockdep_is_held(&epi->ep->mtx));
+}
+
+/* call only when ep->mtx is held */
+static inline void ep_pm_stay_awake(struct epitem *epi)
+{
+ struct wakeup_source *ws = ep_wakeup_source(epi);
+
+ if (ws)
+ __pm_stay_awake(ws);
+}
+
+static inline bool ep_has_wakeup_source(struct epitem *epi)
+{
+ return rcu_access_pointer(epi->ws) ? true : false;
+}
+
+/* call when ep->mtx cannot be held (ep_poll_callback) */
+static inline void ep_pm_stay_awake_rcu(struct epitem *epi)
+{
+ struct wakeup_source *ws;
+
+ rcu_read_lock();
+ ws = rcu_dereference(epi->ws);
+ if (ws)
+ __pm_stay_awake(ws);
+ rcu_read_unlock();
+}
+
/**
* ep_scan_ready_list - Scans the ready list in a way that makes possible for
* the scan code, to call f_op->poll(). Also allows for
@@ -599,7 +634,7 @@ static int ep_scan_ready_list(struct eventpoll *ep,
*/
if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake(epi);
}
}
/*
@@ -668,7 +703,7 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
list_del_init(&epi->rdllink);
spin_unlock_irqrestore(&ep->lock, flags);
- wakeup_source_unregister(epi->ws);
+ wakeup_source_unregister(ep_wakeup_source(epi));
/* At this point it is safe to free the eventpoll item */
kmem_cache_free(epi_cache, epi);
@@ -711,11 +746,15 @@ static void ep_free(struct eventpoll *ep)
* point we are sure no poll callbacks will be lingering around, and also by
* holding "epmutex" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
+ * We do not need to lock ep->mtx, either, we only do it to prevent
+ * a lockdep warning.
*/
+ mutex_lock(&ep->mtx);
while ((rbp = rb_first(&ep->rbr)) != NULL) {
epi = rb_entry(rbp, struct epitem, rbn);
ep_remove(ep, epi);
}
+ mutex_unlock(&ep->mtx);
mutex_unlock(&epmutex);
mutex_destroy(&ep->mtx);
@@ -734,6 +773,13 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file)
return 0;
}
+static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt)
+{
+ pt->_key = epi->event.events;
+
+ return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events;
+}
+
static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
void *priv)
{
@@ -741,10 +787,9 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
poll_table pt;
init_poll_funcptr(&pt, NULL);
+
list_for_each_entry_safe(epi, tmp, head, rdllink) {
- pt._key = epi->event.events;
- if (epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
- epi->event.events)
+ if (ep_item_poll(epi, &pt))
return POLLIN | POLLRDNORM;
else {
/*
@@ -752,7 +797,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
* callback, but it's not actually ready, as far as
* caller requested events goes. We can remove it here.
*/
- __pm_relax(epi->ws);
+ __pm_relax(ep_wakeup_source(epi));
list_del_init(&epi->rdllink);
}
}
@@ -984,7 +1029,7 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
/* If this file is already in the ready list we exit soon */
if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake_rcu(epi);
}
/*
@@ -1146,6 +1191,7 @@ static int reverse_path_check(void)
static int ep_create_wakeup_source(struct epitem *epi)
{
const char *name;
+ struct wakeup_source *ws;
if (!epi->ep->ws) {
epi->ep->ws = wakeup_source_register("eventpoll");
@@ -1154,17 +1200,29 @@ static int ep_create_wakeup_source(struct epitem *epi)
}
name = epi->ffd.file->f_path.dentry->d_name.name;
- epi->ws = wakeup_source_register(name);
- if (!epi->ws)
+ ws = wakeup_source_register(name);
+
+ if (!ws)
return -ENOMEM;
+ rcu_assign_pointer(epi->ws, ws);
return 0;
}
-static void ep_destroy_wakeup_source(struct epitem *epi)
+/* rare code path, only used when EPOLL_CTL_MOD removes a wakeup source */
+static noinline void ep_destroy_wakeup_source(struct epitem *epi)
{
- wakeup_source_unregister(epi->ws);
- epi->ws = NULL;
+ struct wakeup_source *ws = ep_wakeup_source(epi);
+
+ RCU_INIT_POINTER(epi->ws, NULL);
+
+ /*
+ * wait for ep_pm_stay_awake_rcu to finish, synchronize_rcu is
+ * used internally by wakeup_source_remove, too (called by
+ * wakeup_source_unregister), so we cannot use call_rcu
+ */
+ synchronize_rcu();
+ wakeup_source_unregister(ws);
}
/*
@@ -1199,13 +1257,12 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
if (error)
goto error_create_wakeup_source;
} else {
- epi->ws = NULL;
+ RCU_INIT_POINTER(epi->ws, NULL);
}
/* Initialize the poll table using the queue callback */
epq.epi = epi;
init_poll_funcptr(&epq.pt, ep_ptable_queue_proc);
- epq.pt._key = event->events;
/*
* Attach the item to the poll hooks and get current event bits.
@@ -1214,7 +1271,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
* this operation completes, the poll callback can start hitting
* the new item.
*/
- revents = tfile->f_op->poll(tfile, &epq.pt);
+ revents = ep_item_poll(epi, &epq.pt);
/*
* We have to check if something went wrong during the poll wait queue
@@ -1247,7 +1304,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
/* If the file is already "ready" we drop it inside the ready list */
if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake(epi);
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
@@ -1288,7 +1345,7 @@ error_unregister:
list_del_init(&epi->rdllink);
spin_unlock_irqrestore(&ep->lock, flags);
- wakeup_source_unregister(epi->ws);
+ wakeup_source_unregister(ep_wakeup_source(epi));
error_create_wakeup_source:
kmem_cache_free(epi_cache, epi);
@@ -1314,12 +1371,11 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
* f_op->poll() call and the new event set registering.
*/
epi->event.events = event->events; /* need barrier below */
- pt._key = event->events;
epi->event.data = event->data; /* protected by mtx */
if (epi->event.events & EPOLLWAKEUP) {
- if (!epi->ws)
+ if (!ep_has_wakeup_source(epi))
ep_create_wakeup_source(epi);
- } else if (epi->ws) {
+ } else if (ep_has_wakeup_source(epi)) {
ep_destroy_wakeup_source(epi);
}
@@ -1347,7 +1403,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
* Get current event bits. We can safely use the file* here because
* its usage count has been increased by the caller of this function.
*/
- revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt);
+ revents = ep_item_poll(epi, &pt);
/*
* If the item is "hot" and it is not registered inside the ready
@@ -1357,7 +1413,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
spin_lock_irq(&ep->lock);
if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake(epi);
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
@@ -1383,6 +1439,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
unsigned int revents;
struct epitem *epi;
struct epoll_event __user *uevent;
+ struct wakeup_source *ws;
poll_table pt;
init_poll_funcptr(&pt, NULL);
@@ -1405,14 +1462,16 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
* instead, but then epi->ws would temporarily be out of sync
* with ep_is_linked().
*/
- if (epi->ws && epi->ws->active)
- __pm_stay_awake(ep->ws);
- __pm_relax(epi->ws);
+ ws = ep_wakeup_source(epi);
+ if (ws) {
+ if (ws->active)
+ __pm_stay_awake(ep->ws);
+ __pm_relax(ws);
+ }
+
list_del_init(&epi->rdllink);
- pt._key = epi->event.events;
- revents = epi->ffd.file->f_op->poll(epi->ffd.file, &pt) &
- epi->event.events;
+ revents = ep_item_poll(epi, &pt);
/*
* If the event mask intersect the caller-requested one,
@@ -1424,7 +1483,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
if (__put_user(revents, &uevent->events) ||
__put_user(epi->event.data, &uevent->data)) {
list_add(&epi->rdllink, head);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake(epi);
return eventcnt ? eventcnt : -EFAULT;
}
eventcnt++;
@@ -1444,7 +1503,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
* poll callback will queue them in ep->ovflist.
*/
list_add_tail(&epi->rdllink, &ep->rdllist);
- __pm_stay_awake(epi->ws);
+ ep_pm_stay_awake(epi);
}
}
}
@@ -1940,6 +1999,52 @@ SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events,
return error;
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd,
+ struct epoll_event __user *, events,
+ int, maxevents, int, timeout,
+ const compat_sigset_t __user *, sigmask,
+ compat_size_t, sigsetsize)
+{
+ long err;
+ compat_sigset_t csigmask;
+ sigset_t ksigmask, sigsaved;
+
+ /*
+ * If the caller wants a certain signal mask to be set during the wait,
+ * we apply it here.
+ */
+ if (sigmask) {
+ if (sigsetsize != sizeof(compat_sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&csigmask, sigmask, sizeof(csigmask)))
+ return -EFAULT;
+ sigset_from_compat(&ksigmask, &csigmask);
+ sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+ sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+ }
+
+ err = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+ /*
+ * If we changed the signal mask, we need to restore the original one.
+ * In case we've got a signal while waiting, we do not restore the
+ * signal mask yet, and we allow do_signal() to deliver the signal on
+ * the way back to userspace, before the signal mask is restored.
+ */
+ if (sigmask) {
+ if (err == -EINTR) {
+ memcpy(&current->saved_sigmask, &sigsaved,
+ sizeof(sigsaved));
+ set_restore_sigmask();
+ } else
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+ }
+
+ return err;
+}
+#endif
+
static int __init eventpoll_init(void)
{
struct sysinfo si;
@@ -1964,6 +2069,12 @@ static int __init eventpoll_init(void)
/* Initialize the structure used to perform file's f_op->poll() calls */
ep_nested_calls_init(&poll_readywalk_ncalls);
+ /*
+ * We can have many thousands of epitems, so prevent this from
+ * using an extra cache line on 64-bit (and smaller) CPUs
+ */
+ BUILD_BUG_ON(sizeof(void *) <= 8 && sizeof(struct epitem) > 128);
+
/* Allocates slab cache used to allocate "struct epitem" items */
epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
diff --git a/fs/exec.c b/fs/exec.c
index 77dc9096440f..643019585574 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -613,7 +613,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
* when the old and new regions overlap clear from new_end.
*/
free_pgd_range(&tlb, new_end, old_end, new_end,
- vma->vm_next ? vma->vm_next->vm_start : 0);
+ vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING);
} else {
/*
* otherwise, clean from old_start; this is done to not touch
@@ -622,7 +622,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
* for the others its just a little faster.
*/
free_pgd_range(&tlb, old_start, old_end, new_end,
- vma->vm_next ? vma->vm_next->vm_start : 0);
+ vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING);
}
tlb_finish_mmu(&tlb, new_end, old_end);
@@ -907,11 +907,13 @@ static int de_thread(struct task_struct *tsk)
sig->notify_count = -1; /* for exit_notify() */
for (;;) {
+ threadgroup_change_begin(tsk);
write_lock_irq(&tasklist_lock);
if (likely(leader->exit_state))
break;
__set_current_state(TASK_KILLABLE);
write_unlock_irq(&tasklist_lock);
+ threadgroup_change_end(tsk);
schedule();
if (unlikely(__fatal_signal_pending(tsk)))
goto killed;
@@ -969,6 +971,7 @@ static int de_thread(struct task_struct *tsk)
if (unlikely(leader->ptrace))
__wake_up_parent(leader, leader->parent);
write_unlock_irq(&tasklist_lock);
+ threadgroup_change_end(tsk);
release_task(leader);
}
@@ -1036,17 +1039,7 @@ EXPORT_SYMBOL_GPL(get_task_comm);
void set_task_comm(struct task_struct *tsk, char *buf)
{
task_lock(tsk);
-
trace_task_rename(tsk, buf);
-
- /*
- * Threads may access current->comm without holding
- * the task lock, so write the string carefully.
- * Readers without a lock may see incomplete new
- * names but are safe from non-terminating string reads.
- */
- memset(tsk->comm, 0, TASK_COMM_LEN);
- wmb();
strlcpy(tsk->comm, buf, sizeof(tsk->comm));
task_unlock(tsk);
perf_event_comm(tsk);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index fb5120a5505c..3dc48cc8b6eb 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2067,7 +2067,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal":
test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
"writeback");
- sb->s_flags |= MS_SNAP_STABLE;
return 0;
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index 987358740cb9..efea5d5c44ce 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -71,4 +71,5 @@ config EXT4_DEBUG
Enables run-time debugging support for the ext4 filesystem.
If you select Y here, then you will be able to turn on debugging
- with a command such as "echo 1 > /sys/kernel/debug/ext4/mballoc-debug"
+ with a command such as:
+ echo 1 > /sys/module/ext4/parameters/mballoc_debug
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 92e68b33fffd..d0f13eada0ed 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -30,6 +30,23 @@ static unsigned ext4_num_base_meta_clusters(struct super_block *sb,
*/
/*
+ * Calculate block group number for a given block number
+ */
+ext4_group_t ext4_get_group_number(struct super_block *sb,
+ ext4_fsblk_t block)
+{
+ ext4_group_t group;
+
+ if (test_opt2(sb, STD_GROUP_SIZE))
+ group = (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) +
+ block) >>
+ (EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3);
+ else
+ ext4_get_group_no_and_offset(sb, block, &group, NULL);
+ return group;
+}
+
+/*
* Calculate the block group number and offset into the block/cluster
* allocation bitmap, given a block number
*/
@@ -49,14 +66,18 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
}
-static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
- ext4_group_t block_group)
+/*
+ * Check whether the 'block' lives within the 'block_group'. Returns 1 if so
+ * and 0 otherwise.
+ */
+static inline int ext4_block_in_group(struct super_block *sb,
+ ext4_fsblk_t block,
+ ext4_group_t block_group)
{
ext4_group_t actual_group;
- ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
- if (actual_group == block_group)
- return 1;
- return 0;
+
+ actual_group = ext4_get_group_number(sb, block);
+ return (actual_group == block_group) ? 1 : 0;
}
/* Return the number of clusters used for file system metadata; this
@@ -420,7 +441,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group)
trace_ext4_read_block_bitmap_load(sb, block_group);
bh->b_end_io = ext4_end_bitmap_read;
get_bh(bh);
- submit_bh(READ, bh);
+ submit_bh(READ | REQ_META | REQ_PRIO, bh);
return bh;
verify:
ext4_validate_block_bitmap(sb, desc, block_group, bh);
@@ -478,20 +499,22 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group)
static int ext4_has_free_clusters(struct ext4_sb_info *sbi,
s64 nclusters, unsigned int flags)
{
- s64 free_clusters, dirty_clusters, root_clusters;
+ s64 free_clusters, dirty_clusters, rsv, resv_clusters;
struct percpu_counter *fcc = &sbi->s_freeclusters_counter;
struct percpu_counter *dcc = &sbi->s_dirtyclusters_counter;
free_clusters = percpu_counter_read_positive(fcc);
dirty_clusters = percpu_counter_read_positive(dcc);
+ resv_clusters = atomic64_read(&sbi->s_resv_clusters);
/*
* r_blocks_count should always be multiple of the cluster ratio so
* we are safe to do a plane bit shift only.
*/
- root_clusters = ext4_r_blocks_count(sbi->s_es) >> sbi->s_cluster_bits;
+ rsv = (ext4_r_blocks_count(sbi->s_es) >> sbi->s_cluster_bits) +
+ resv_clusters;
- if (free_clusters - (nclusters + root_clusters + dirty_clusters) <
+ if (free_clusters - (nclusters + rsv + dirty_clusters) <
EXT4_FREECLUSTERS_WATERMARK) {
free_clusters = percpu_counter_sum_positive(fcc);
dirty_clusters = percpu_counter_sum_positive(dcc);
@@ -499,15 +522,21 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi,
/* Check whether we have space after accounting for current
* dirty clusters & root reserved clusters.
*/
- if (free_clusters >= ((root_clusters + nclusters) + dirty_clusters))
+ if (free_clusters >= (rsv + nclusters + dirty_clusters))
return 1;
/* Hm, nope. Are (enough) root reserved clusters available? */
if (uid_eq(sbi->s_resuid, current_fsuid()) ||
(!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||
capable(CAP_SYS_RESOURCE) ||
- (flags & EXT4_MB_USE_ROOT_BLOCKS)) {
+ (flags & EXT4_MB_USE_ROOT_BLOCKS)) {
+ if (free_clusters >= (nclusters + dirty_clusters +
+ resv_clusters))
+ return 1;
+ }
+ /* No free blocks. Let's see if we can dip into reserved pool */
+ if (flags & EXT4_MB_USE_RESERVED) {
if (free_clusters >= (nclusters + dirty_clusters))
return 1;
}
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index d8cd1f0f4661..f8d56e4254e0 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -46,7 +46,8 @@ static int is_dx_dir(struct inode *inode)
if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_COMPAT_DIR_INDEX) &&
((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) ||
- ((inode->i_size >> sb->s_blocksize_bits) == 1)))
+ ((inode->i_size >> sb->s_blocksize_bits) == 1) ||
+ ext4_has_inline_data(inode)))
return 1;
return 0;
@@ -115,14 +116,6 @@ static int ext4_readdir(struct file *filp,
int ret = 0;
int dir_has_error = 0;
- if (ext4_has_inline_data(inode)) {
- int has_inline_data = 1;
- ret = ext4_read_inline_dir(filp, dirent, filldir,
- &has_inline_data);
- if (has_inline_data)
- return ret;
- }
-
if (is_dx_dir(inode)) {
err = ext4_dx_readdir(filp, dirent, filldir);
if (err != ERR_BAD_DX_DIR) {
@@ -136,6 +129,15 @@ static int ext4_readdir(struct file *filp,
ext4_clear_inode_flag(file_inode(filp),
EXT4_INODE_INDEX);
}
+
+ if (ext4_has_inline_data(inode)) {
+ int has_inline_data = 1;
+ ret = ext4_read_inline_dir(filp, dirent, filldir,
+ &has_inline_data);
+ if (has_inline_data)
+ return ret;
+ }
+
stored = 0;
offset = filp->f_pos & (sb->s_blocksize - 1);
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 3b83cd604796..0aabb344b02e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -121,6 +121,8 @@ typedef unsigned int ext4_group_t;
#define EXT4_MB_STREAM_ALLOC 0x0800
/* Use reserved root blocks if needed */
#define EXT4_MB_USE_ROOT_BLOCKS 0x1000
+/* Use blocks from reserved pool */
+#define EXT4_MB_USE_RESERVED 0x2000
struct ext4_allocation_request {
/* target inode for block we're allocating */
@@ -196,19 +198,8 @@ struct mpage_da_data {
#define EXT4_IO_END_ERROR 0x0002
#define EXT4_IO_END_DIRECT 0x0004
-struct ext4_io_page {
- struct page *p_page;
- atomic_t p_count;
-};
-
-#define MAX_IO_PAGES 128
-
/*
* For converting uninitialized extents on a work queue.
- *
- * 'page' is only used from the writepage() path; 'pages' is only used for
- * buffered writes; they are used to keep page references until conversion
- * takes place. For AIO/DIO, neither field is filled in.
*/
typedef struct ext4_io_end {
struct list_head list; /* per-file finished IO list */
@@ -218,15 +209,13 @@ typedef struct ext4_io_end {
ssize_t size; /* size of the extent */
struct kiocb *iocb; /* iocb struct for AIO */
int result; /* error value for AIO */
- int num_io_pages; /* for writepages() */
- struct ext4_io_page *pages[MAX_IO_PAGES]; /* for writepages() */
+ atomic_t count; /* reference counter */
} ext4_io_end_t;
struct ext4_io_submit {
int io_op;
struct bio *io_bio;
ext4_io_end_t *io_end;
- struct ext4_io_page *io_page;
sector_t io_next_block;
};
@@ -403,7 +392,7 @@ struct flex_groups {
#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */
-#define EXT4_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */
+#define EXT4_FL_USER_MODIFIABLE 0x004380FF /* User modifiable flags */
/* Flags that should be inherited by new inodes from their parent. */
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
@@ -557,9 +546,8 @@ enum {
#define EXT4_GET_BLOCKS_UNINIT_EXT 0x0002
#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT (EXT4_GET_BLOCKS_UNINIT_EXT|\
EXT4_GET_BLOCKS_CREATE)
- /* Caller is from the delayed allocation writeout path,
- so set the magic i_delalloc_reserve_flag after taking the
- inode allocation semaphore for */
+ /* Caller is from the delayed allocation writeout path
+ * finally doing the actual allocation of delayed blocks */
#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004
/* caller is from the direct IO path, request to creation of an
unitialized extents if not allocated, split the uninitialized
@@ -571,8 +559,9 @@ enum {
/* Convert extent to initialized after IO complete */
#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
- /* Punch out blocks of an extent */
-#define EXT4_GET_BLOCKS_PUNCH_OUT_EXT 0x0020
+ /* Eventual metadata allocation (due to growing extent tree)
+ * should not fail, so try to use reserved blocks for that.*/
+#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020
/* Don't normalize allocation size (used for fallocate) */
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
/* Request will not result in inode size update (user for fallocate) */
@@ -616,6 +605,7 @@ enum {
#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12)
#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
/*
@@ -949,7 +939,7 @@ struct ext4_inode_info {
#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
/*
- * Mount flags
+ * Mount flags set via mount options or defaults
*/
#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
@@ -981,8 +971,16 @@ struct ext4_inode_info {
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
+/*
+ * Mount flags set either automatically (could not be set by mount option)
+ * based on per file system feature or property or in special cases such as
+ * distinguishing between explicit mount option definition and default.
+ */
#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly
specified delalloc */
+#define EXT4_MOUNT2_STD_GROUP_SIZE 0x00000002 /* We have standard group
+ size of blocksize * 8
+ blocks */
#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \
~EXT4_MOUNT_##opt
@@ -1179,6 +1177,7 @@ struct ext4_sb_info {
unsigned int s_mount_flags;
unsigned int s_def_mount_opt;
ext4_fsblk_t s_sb_block;
+ atomic64_t s_resv_clusters;
kuid_t s_resuid;
kgid_t s_resgid;
unsigned short s_mount_state;
@@ -1333,6 +1332,7 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
return ino == EXT4_ROOT_INO ||
ino == EXT4_USR_QUOTA_INO ||
ino == EXT4_GRP_QUOTA_INO ||
+ ino == EXT4_BOOT_LOADER_INO ||
ino == EXT4_JOURNAL_INO ||
ino == EXT4_RESIZE_INO ||
(ino >= EXT4_FIRST_INO(sb) &&
@@ -1374,6 +1374,7 @@ enum {
EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
nolocking */
EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
+ EXT4_STATE_ORDERED_MODE, /* data=ordered mode */
};
#define EXT4_INODE_BIT_FNS(name, field, offset) \
@@ -1784,9 +1785,6 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
*/
#define ERR_BAD_DX_DIR -75000
-void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
- ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp);
-
/*
* Timeout and state flag for lazy initialization inode thread.
*/
@@ -1908,6 +1906,13 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
struct buffer_head *bh);
/* balloc.c */
+extern void ext4_get_group_no_and_offset(struct super_block *sb,
+ ext4_fsblk_t blocknr,
+ ext4_group_t *blockgrpp,
+ ext4_grpblk_t *offsetp);
+extern ext4_group_t ext4_get_group_number(struct super_block *sb,
+ ext4_fsblk_t block);
+
extern void ext4_validate_block_bitmap(struct super_block *sb,
struct ext4_group_desc *desc,
unsigned int block_group,
@@ -2108,8 +2113,9 @@ extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
unsigned long nr_segs);
extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk);
-extern void ext4_ind_truncate(struct inode *inode);
-extern int ext4_ind_punch_hole(struct file *file, loff_t offset, loff_t length);
+extern void ext4_ind_truncate(handle_t *, struct inode *inode);
+extern int ext4_free_hole_blocks(handle_t *handle, struct inode *inode,
+ ext4_lblk_t first, ext4_lblk_t stop);
/* ioctl.c */
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
@@ -2117,6 +2123,7 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
/* migrate.c */
extern int ext4_ext_migrate(struct inode *);
+extern int ext4_ind_migrate(struct inode *inode);
/* namei.c */
extern int ext4_dirent_csum_verify(struct inode *inode,
@@ -2511,6 +2518,11 @@ extern int ext4_try_create_inline_dir(handle_t *handle,
extern int ext4_read_inline_dir(struct file *filp,
void *dirent, filldir_t filldir,
int *has_inline_data);
+extern int htree_inlinedir_to_tree(struct file *dir_file,
+ struct inode *dir, ext4_lblk_t block,
+ struct dx_hash_info *hinfo,
+ __u32 start_hash, __u32 start_minor_hash,
+ int *has_inline_data);
extern struct buffer_head *ext4_find_inline_entry(struct inode *dir,
const struct qstr *d_name,
struct ext4_dir_entry_2 **res_dir,
@@ -2547,6 +2559,24 @@ extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
extern int ext4_handle_dirty_dirent_node(handle_t *handle,
struct inode *inode,
struct buffer_head *bh);
+#define S_SHIFT 12
+static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
+ [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
+ [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
+ [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
+ [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
+ [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
+ [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
+ [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
+};
+
+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))
+ de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+}
+
/* symlink.c */
extern const struct inode_operations ext4_symlink_inode_operations;
@@ -2573,9 +2603,9 @@ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
int chunk);
extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map, int flags);
-extern void ext4_ext_truncate(struct inode *);
-extern int ext4_ext_punch_hole(struct file *file, loff_t offset,
- loff_t length);
+extern void ext4_ext_truncate(handle_t *, struct inode *);
+extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+ ext4_lblk_t end);
extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *);
extern long ext4_fallocate(struct file *file, int mode, loff_t offset,
@@ -2609,17 +2639,26 @@ extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
/* move_extent.c */
+extern void ext4_double_down_write_data_sem(struct inode *first,
+ struct inode *second);
+extern void ext4_double_up_write_data_sem(struct inode *orig_inode,
+ struct inode *donor_inode);
+void ext4_inode_double_lock(struct inode *inode1, struct inode *inode2);
+void ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2);
extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
__u64 start_orig, __u64 start_donor,
__u64 len, __u64 *moved_len);
/* page-io.c */
extern int __init ext4_init_pageio(void);
-extern void ext4_add_complete_io(ext4_io_end_t *io_end);
extern void ext4_exit_pageio(void);
extern void ext4_ioend_shutdown(struct inode *);
-extern void ext4_free_io_end(ext4_io_end_t *io);
extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
+extern ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end);
+extern int ext4_put_io_end(ext4_io_end_t *io_end);
+extern void ext4_put_io_end_defer(ext4_io_end_t *io_end);
+extern void ext4_io_submit_init(struct ext4_io_submit *io,
+ struct writeback_control *wbc);
extern void ext4_end_io_work(struct work_struct *work);
extern void ext4_io_submit(struct ext4_io_submit *io);
extern int ext4_bio_write_page(struct ext4_io_submit *io,
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index 8643ff5bbeb7..51bc821ade90 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -270,5 +270,10 @@ static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
0xffff);
}
+#define ext4_ext_dirty(handle, inode, path) \
+ __ext4_ext_dirty(__func__, __LINE__, (handle), (inode), (path))
+int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle,
+ struct inode *inode, struct ext4_ext_path *path);
+
#endif /* _EXT4_EXTENTS */
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index 7058975e3a55..451eb4045330 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -43,6 +43,8 @@ handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line,
{
journal_t *journal;
+ might_sleep();
+
trace_ext4_journal_start(sb, nblocks, _RET_IP_);
if (sb->s_flags & MS_RDONLY)
return ERR_PTR(-EROFS);
@@ -113,6 +115,8 @@ int __ext4_journal_get_write_access(const char *where, unsigned int line,
{
int err = 0;
+ might_sleep();
+
if (ext4_handle_valid(handle)) {
err = jbd2_journal_get_write_access(handle, bh);
if (err)
@@ -209,6 +213,10 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
{
int err = 0;
+ might_sleep();
+
+ set_buffer_meta(bh);
+ set_buffer_prio(bh);
if (ext4_handle_valid(handle)) {
err = jbd2_journal_dirty_metadata(handle, bh);
if (err) {
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 4c216b1bf20c..c8c6885406db 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -29,11 +29,13 @@
* block to complete the transaction.
*
* For extents-enabled fs we may have to allocate and modify up to
- * 5 levels of tree + root which are stored in the inode. */
+ * 5 levels of tree, data block (for each of these we need bitmap + group
+ * summaries), root which is stored in the inode, sb
+ */
#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \
(EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \
- ? 27U : 8U)
+ ? 20U : 8U)
/* Extended attribute operations touch at most two data buffers,
* two bitmap buffers, and two group summaries, in addition to the inode
@@ -194,16 +196,20 @@ static inline void ext4_journal_callback_add(handle_t *handle,
* ext4_journal_callback_del: delete a registered callback
* @handle: active journal transaction handle on which callback was registered
* @jce: registered journal callback entry to unregister
+ * Return true if object was sucessfully removed
*/
-static inline void ext4_journal_callback_del(handle_t *handle,
+static inline bool ext4_journal_callback_try_del(handle_t *handle,
struct ext4_journal_cb_entry *jce)
{
+ bool deleted;
struct ext4_sb_info *sbi =
EXT4_SB(handle->h_transaction->t_journal->j_private);
spin_lock(&sbi->s_md_lock);
+ deleted = !list_empty(&jce->jce_list);
list_del_init(&jce->jce_list);
spin_unlock(&sbi->s_md_lock);
+ return deleted;
}
int
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 56efcaadf848..107936db244e 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -157,11 +157,8 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
* - ENOMEM
* - EIO
*/
-#define ext4_ext_dirty(handle, inode, path) \
- __ext4_ext_dirty(__func__, __LINE__, (handle), (inode), (path))
-static int __ext4_ext_dirty(const char *where, unsigned int line,
- handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path)
+int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle,
+ struct inode *inode, struct ext4_ext_path *path)
{
int err;
if (path->p_bh) {
@@ -1813,39 +1810,101 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
}
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;
}
/* try to insert block into found extent and return */
- if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)
- && ext4_can_extents_be_merged(inode, ex, newext)) {
- ext_debug("append [%d]%d block to %u:[%d]%d (from %llu)\n",
- ext4_ext_is_uninitialized(newext),
- ext4_ext_get_actual_len(newext),
- le32_to_cpu(ex->ee_block),
- ext4_ext_is_uninitialized(ex),
- ext4_ext_get_actual_len(ex),
- ext4_ext_pblock(ex));
- err = ext4_ext_get_access(handle, inode, path + depth);
- if (err)
- return err;
+ if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)) {
/*
- * ext4_can_extents_be_merged should have checked that either
- * both extents are uninitialized, or both aren't. Thus we
- * need to check only one of them here.
+ * Try to see whether we should rather test the extent on
+ * right from ex, or from the left of ex. This is because
+ * ext4_ext_find_extent() can return either extent on the
+ * left, or on the right from the searched position. This
+ * will make merging more effective.
*/
- if (ext4_ext_is_uninitialized(ex))
- uninitialized = 1;
- ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ if (ex < EXT_LAST_EXTENT(eh) &&
+ (le32_to_cpu(ex->ee_block) +
+ ext4_ext_get_actual_len(ex) <
+ le32_to_cpu(newext->ee_block))) {
+ ex += 1;
+ goto prepend;
+ } else if ((ex > EXT_FIRST_EXTENT(eh)) &&
+ (le32_to_cpu(newext->ee_block) +
+ ext4_ext_get_actual_len(newext) <
+ le32_to_cpu(ex->ee_block)))
+ ex -= 1;
+
+ /* Try to append newex to the ex */
+ if (ext4_can_extents_be_merged(inode, ex, newext)) {
+ ext_debug("append [%d]%d block to %u:[%d]%d"
+ "(from %llu)\n",
+ ext4_ext_is_uninitialized(newext),
+ ext4_ext_get_actual_len(newext),
+ le32_to_cpu(ex->ee_block),
+ ext4_ext_is_uninitialized(ex),
+ ext4_ext_get_actual_len(ex),
+ ext4_ext_pblock(ex));
+ err = ext4_ext_get_access(handle, inode,
+ path + depth);
+ if (err)
+ return err;
+
+ /*
+ * ext4_can_extents_be_merged should have checked
+ * that either both extents are uninitialized, or
+ * both aren't. Thus we need to check only one of
+ * them here.
+ */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ ext4_ext_get_actual_len(newext));
- if (uninitialized)
- ext4_ext_mark_uninitialized(ex);
- eh = path[depth].p_hdr;
- nearex = ex;
- goto merge;
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
+ eh = path[depth].p_hdr;
+ nearex = ex;
+ goto merge;
+ }
+
+prepend:
+ /* Try to prepend newex to the ex */
+ if (ext4_can_extents_be_merged(inode, newext, ex)) {
+ ext_debug("prepend %u[%d]%d block to %u:[%d]%d"
+ "(from %llu)\n",
+ le32_to_cpu(newext->ee_block),
+ ext4_ext_is_uninitialized(newext),
+ ext4_ext_get_actual_len(newext),
+ le32_to_cpu(ex->ee_block),
+ ext4_ext_is_uninitialized(ex),
+ ext4_ext_get_actual_len(ex),
+ ext4_ext_pblock(ex));
+ err = ext4_ext_get_access(handle, inode,
+ path + depth);
+ if (err)
+ return err;
+
+ /*
+ * ext4_can_extents_be_merged should have checked
+ * that either both extents are uninitialized, or
+ * both aren't. Thus we need to check only one of
+ * them here.
+ */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_block = newext->ee_block;
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ + ext4_ext_get_actual_len(newext));
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
+ eh = path[depth].p_hdr;
+ nearex = ex;
+ goto merge;
+ }
}
depth = ext_depth(inode);
@@ -1880,8 +1939,8 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
* There is no free space in the found leaf.
* We're gonna add a new leaf in the tree.
*/
- if (flag & EXT4_GET_BLOCKS_PUNCH_OUT_EXT)
- flags = EXT4_MB_USE_ROOT_BLOCKS;
+ if (flag & EXT4_GET_BLOCKS_METADATA_NOFAIL)
+ flags = EXT4_MB_USE_RESERVED;
err = ext4_ext_create_new_leaf(handle, inode, flags, path, newext);
if (err)
goto cleanup;
@@ -2599,8 +2658,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
return 1;
}
-static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
- ext4_lblk_t end)
+int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+ ext4_lblk_t end)
{
struct super_block *sb = inode->i_sb;
int depth = ext_depth(inode);
@@ -2667,12 +2726,14 @@ again:
/*
* Split the extent in two so that 'end' is the last
- * block in the first new extent
+ * block in the first new extent. Also we should not
+ * fail removing space due to ENOSPC so try to use
+ * reserved block if that happens.
*/
err = ext4_split_extent_at(handle, inode, path,
- end + 1, split_flag,
- EXT4_GET_BLOCKS_PRE_IO |
- EXT4_GET_BLOCKS_PUNCH_OUT_EXT);
+ end + 1, split_flag,
+ EXT4_GET_BLOCKS_PRE_IO |
+ EXT4_GET_BLOCKS_METADATA_NOFAIL);
if (err < 0)
goto out;
@@ -2999,20 +3060,23 @@ static int ext4_split_extent_at(handle_t *handle,
if (split_flag & EXT4_EXT_DATA_VALID1) {
err = ext4_ext_zeroout(inode, ex2);
zero_ex.ee_block = ex2->ee_block;
- zero_ex.ee_len = ext4_ext_get_actual_len(ex2);
+ zero_ex.ee_len = cpu_to_le16(
+ ext4_ext_get_actual_len(ex2));
ext4_ext_store_pblock(&zero_ex,
ext4_ext_pblock(ex2));
} else {
err = ext4_ext_zeroout(inode, ex);
zero_ex.ee_block = ex->ee_block;
- zero_ex.ee_len = ext4_ext_get_actual_len(ex);
+ zero_ex.ee_len = cpu_to_le16(
+ ext4_ext_get_actual_len(ex));
ext4_ext_store_pblock(&zero_ex,
ext4_ext_pblock(ex));
}
} else {
err = ext4_ext_zeroout(inode, &orig_ex);
zero_ex.ee_block = orig_ex.ee_block;
- zero_ex.ee_len = ext4_ext_get_actual_len(&orig_ex);
+ zero_ex.ee_len = cpu_to_le16(
+ ext4_ext_get_actual_len(&orig_ex));
ext4_ext_store_pblock(&zero_ex,
ext4_ext_pblock(&orig_ex));
}
@@ -3144,35 +3208,35 @@ out:
static int ext4_ext_convert_to_initialized(handle_t *handle,
struct inode *inode,
struct ext4_map_blocks *map,
- struct ext4_ext_path *path)
+ struct ext4_ext_path *path,
+ int flags)
{
struct ext4_sb_info *sbi;
struct ext4_extent_header *eh;
struct ext4_map_blocks split_map;
struct ext4_extent zero_ex;
- struct ext4_extent *ex;
+ struct ext4_extent *ex, *abut_ex;
ext4_lblk_t ee_block, eof_block;
- unsigned int ee_len, depth;
- int allocated, max_zeroout = 0;
+ unsigned int ee_len, depth, map_len = map->m_len;
+ int allocated = 0, max_zeroout = 0;
int err = 0;
int split_flag = 0;
ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
"block %llu, max_blocks %u\n", inode->i_ino,
- (unsigned long long)map->m_lblk, map->m_len);
+ (unsigned long long)map->m_lblk, map_len);
sbi = EXT4_SB(inode->i_sb);
eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
inode->i_sb->s_blocksize_bits;
- if (eof_block < map->m_lblk + map->m_len)
- eof_block = map->m_lblk + map->m_len;
+ if (eof_block < map->m_lblk + map_len)
+ eof_block = map->m_lblk + map_len;
depth = ext_depth(inode);
eh = path[depth].p_hdr;
ex = path[depth].p_ext;
ee_block = le32_to_cpu(ex->ee_block);
ee_len = ext4_ext_get_actual_len(ex);
- allocated = ee_len - (map->m_lblk - ee_block);
zero_ex.ee_len = 0;
trace_ext4_ext_convert_to_initialized_enter(inode, map, ex);
@@ -3183,77 +3247,121 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
/*
* Attempt to transfer newly initialized blocks from the currently
- * uninitialized extent to its left neighbor. This is much cheaper
+ * uninitialized extent to its neighbor. This is much cheaper
* than an insertion followed by a merge as those involve costly
- * memmove() calls. This is the common case in steady state for
- * workloads doing fallocate(FALLOC_FL_KEEP_SIZE) followed by append
- * writes.
+ * memmove() calls. Transferring to the left is the common case in
+ * steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE)
+ * followed by append writes.
*
* Limitations of the current logic:
- * - L1: we only deal with writes at the start of the extent.
- * The approach could be extended to writes at the end
- * of the extent but this scenario was deemed less common.
- * - L2: we do not deal with writes covering the whole extent.
+ * - L1: we do not deal with writes covering the whole extent.
* This would require removing the extent if the transfer
* is possible.
- * - L3: we only attempt to merge with an extent stored in the
+ * - L2: we only attempt to merge with an extent stored in the
* same extent tree node.
*/
- if ((map->m_lblk == ee_block) && /*L1*/
- (map->m_len < ee_len) && /*L2*/
- (ex > EXT_FIRST_EXTENT(eh))) { /*L3*/
- struct ext4_extent *prev_ex;
+ if ((map->m_lblk == ee_block) &&
+ /* See if we can merge left */
+ (map_len < ee_len) && /*L1*/
+ (ex > EXT_FIRST_EXTENT(eh))) { /*L2*/
ext4_lblk_t prev_lblk;
ext4_fsblk_t prev_pblk, ee_pblk;
- unsigned int prev_len, write_len;
+ unsigned int prev_len;
- prev_ex = ex - 1;
- prev_lblk = le32_to_cpu(prev_ex->ee_block);
- prev_len = ext4_ext_get_actual_len(prev_ex);
- prev_pblk = ext4_ext_pblock(prev_ex);
+ abut_ex = ex - 1;
+ prev_lblk = le32_to_cpu(abut_ex->ee_block);
+ prev_len = ext4_ext_get_actual_len(abut_ex);
+ prev_pblk = ext4_ext_pblock(abut_ex);
ee_pblk = ext4_ext_pblock(ex);
- write_len = map->m_len;
/*
- * A transfer of blocks from 'ex' to 'prev_ex' is allowed
+ * A transfer of blocks from 'ex' to 'abut_ex' is allowed
* upon those conditions:
- * - C1: prev_ex is initialized,
- * - C2: prev_ex is logically abutting ex,
- * - C3: prev_ex is physically abutting ex,
- * - C4: prev_ex can receive the additional blocks without
+ * - C1: abut_ex is initialized,
+ * - C2: abut_ex is logically abutting ex,
+ * - C3: abut_ex is physically abutting ex,
+ * - C4: abut_ex can receive the additional blocks without
* overflowing the (initialized) length limit.
*/
- if ((!ext4_ext_is_uninitialized(prev_ex)) && /*C1*/
+ if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/
((prev_lblk + prev_len) == ee_block) && /*C2*/
((prev_pblk + prev_len) == ee_pblk) && /*C3*/
- (prev_len < (EXT_INIT_MAX_LEN - write_len))) { /*C4*/
+ (prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;
trace_ext4_ext_convert_to_initialized_fastpath(inode,
- map, ex, prev_ex);
+ map, ex, abut_ex);
- /* Shift the start of ex by 'write_len' blocks */
- ex->ee_block = cpu_to_le32(ee_block + write_len);
- ext4_ext_store_pblock(ex, ee_pblk + write_len);
- ex->ee_len = cpu_to_le16(ee_len - write_len);
+ /* Shift the start of ex by 'map_len' blocks */
+ ex->ee_block = cpu_to_le32(ee_block + map_len);
+ ext4_ext_store_pblock(ex, ee_pblk + map_len);
+ ex->ee_len = cpu_to_le16(ee_len - map_len);
ext4_ext_mark_uninitialized(ex); /* Restore the flag */
- /* Extend prev_ex by 'write_len' blocks */
- prev_ex->ee_len = cpu_to_le16(prev_len + write_len);
+ /* Extend abut_ex by 'map_len' blocks */
+ abut_ex->ee_len = cpu_to_le16(prev_len + map_len);
- /* Mark the block containing both extents as dirty */
- ext4_ext_dirty(handle, inode, path + depth);
+ /* Result: number of initialized blocks past m_lblk */
+ allocated = map_len;
+ }
+ } else if (((map->m_lblk + map_len) == (ee_block + ee_len)) &&
+ (map_len < ee_len) && /*L1*/
+ ex < EXT_LAST_EXTENT(eh)) { /*L2*/
+ /* See if we can merge right */
+ ext4_lblk_t next_lblk;
+ ext4_fsblk_t next_pblk, ee_pblk;
+ unsigned int next_len;
+
+ abut_ex = ex + 1;
+ next_lblk = le32_to_cpu(abut_ex->ee_block);
+ next_len = ext4_ext_get_actual_len(abut_ex);
+ next_pblk = ext4_ext_pblock(abut_ex);
+ ee_pblk = ext4_ext_pblock(ex);
- /* Update path to point to the right extent */
- path[depth].p_ext = prev_ex;
+ /*
+ * A transfer of blocks from 'ex' to 'abut_ex' is allowed
+ * upon those conditions:
+ * - C1: abut_ex is initialized,
+ * - C2: abut_ex is logically abutting ex,
+ * - C3: abut_ex is physically abutting ex,
+ * - C4: abut_ex can receive the additional blocks without
+ * overflowing the (initialized) length limit.
+ */
+ if ((!ext4_ext_is_uninitialized(abut_ex)) && /*C1*/
+ ((map->m_lblk + map_len) == next_lblk) && /*C2*/
+ ((ee_pblk + ee_len) == next_pblk) && /*C3*/
+ (next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+
+ trace_ext4_ext_convert_to_initialized_fastpath(inode,
+ map, ex, abut_ex);
+
+ /* Shift the start of abut_ex by 'map_len' blocks */
+ abut_ex->ee_block = cpu_to_le32(next_lblk - map_len);
+ ext4_ext_store_pblock(abut_ex, next_pblk - map_len);
+ ex->ee_len = cpu_to_le16(ee_len - map_len);
+ ext4_ext_mark_uninitialized(ex); /* Restore the flag */
+
+ /* Extend abut_ex by 'map_len' blocks */
+ abut_ex->ee_len = cpu_to_le16(next_len + map_len);
/* Result: number of initialized blocks past m_lblk */
- allocated = write_len;
- goto out;
+ allocated = map_len;
}
}
+ if (allocated) {
+ /* Mark the block containing both extents as dirty */
+ ext4_ext_dirty(handle, inode, path + depth);
+
+ /* Update path to point to the right extent */
+ path[depth].p_ext = abut_ex;
+ goto out;
+ } else
+ allocated = ee_len - (map->m_lblk - ee_block);
WARN_ON(map->m_lblk < ee_block);
/*
@@ -3272,7 +3380,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
if (err)
goto out;
zero_ex.ee_block = ex->ee_block;
- zero_ex.ee_len = ext4_ext_get_actual_len(ex);
+ zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex));
ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, path + depth);
@@ -3327,7 +3435,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
}
allocated = ext4_split_extent(handle, inode, path,
- &split_map, split_flag, 0);
+ &split_map, split_flag, flags);
if (allocated < 0)
err = allocated;
@@ -3647,6 +3755,12 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
flags, allocated);
ext4_ext_show_leaf(inode, path);
+ /*
+ * When writing into uninitialized space, we should not fail to
+ * allocate metadata blocks for the new extent block if needed.
+ */
+ flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL;
+
trace_ext4_ext_handle_uninitialized_extents(inode, map, flags,
allocated, newblock);
@@ -3710,7 +3824,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
}
/* buffered write, writepage time, convert*/
- ret = ext4_ext_convert_to_initialized(handle, inode, map, path);
+ ret = ext4_ext_convert_to_initialized(handle, inode, map, path, flags);
if (ret >= 0)
ext4_update_inode_fsync_trans(handle, inode, 1);
out:
@@ -4254,48 +4368,13 @@ out3:
return err ? err : allocated;
}
-void ext4_ext_truncate(struct inode *inode)
+void ext4_ext_truncate(handle_t *handle, struct inode *inode)
{
- struct address_space *mapping = inode->i_mapping;
struct super_block *sb = inode->i_sb;
ext4_lblk_t last_block;
- handle_t *handle;
- loff_t page_len;
int err = 0;
/*
- * finish any pending end_io work so we won't run the risk of
- * converting any truncated blocks to initialized later
- */
- ext4_flush_unwritten_io(inode);
-
- /*
- * probably first extent we're gonna free will be last in block
- */
- err = ext4_writepage_trans_blocks(inode);
- handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, err);
- if (IS_ERR(handle))
- return;
-
- if (inode->i_size % PAGE_CACHE_SIZE != 0) {
- page_len = PAGE_CACHE_SIZE -
- (inode->i_size & (PAGE_CACHE_SIZE - 1));
-
- err = ext4_discard_partial_page_buffers(handle,
- mapping, inode->i_size, page_len, 0);
-
- if (err)
- goto out_stop;
- }
-
- if (ext4_orphan_add(handle, inode))
- goto out_stop;
-
- down_write(&EXT4_I(inode)->i_data_sem);
-
- ext4_discard_preallocations(inode);
-
- /*
* TODO: optimization is possible here.
* Probably we need not scan at all,
* because page truncation is enough.
@@ -4310,29 +4389,6 @@ void ext4_ext_truncate(struct inode *inode)
err = ext4_es_remove_extent(inode, last_block,
EXT_MAX_BLOCKS - last_block);
err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1);
-
- /* In a multi-transaction truncate, we only make the final
- * transaction synchronous.
- */
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
-
- up_write(&EXT4_I(inode)->i_data_sem);
-
-out_stop:
- /*
- * If this was a simple ftruncate() and the file will remain alive,
- * then we need to clear up the orphan record which we created above.
- * However, if this was a real unlink then we were called by
- * ext4_delete_inode(), and we allow that function to clean up the
- * orphan info for us.
- */
- if (inode->i_nlink)
- ext4_orphan_del(handle, inode);
-
- inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- ext4_journal_stop(handle);
}
static void ext4_falloc_update_inode(struct inode *inode,
@@ -4620,187 +4676,6 @@ static int ext4_xattr_fiemap(struct inode *inode,
return (error < 0 ? error : 0);
}
-/*
- * ext4_ext_punch_hole
- *
- * Punches a hole of "length" bytes in a file starting
- * at byte "offset"
- *
- * @inode: The inode of the file to punch a hole in
- * @offset: The starting byte offset of the hole
- * @length: The length of the hole
- *
- * Returns the number of blocks removed or negative on err
- */
-int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length)
-{
- struct inode *inode = file_inode(file);
- struct super_block *sb = inode->i_sb;
- ext4_lblk_t first_block, stop_block;
- struct address_space *mapping = inode->i_mapping;
- handle_t *handle;
- loff_t first_page, last_page, page_len;
- loff_t first_page_offset, last_page_offset;
- int credits, err = 0;
-
- /*
- * Write out all dirty pages to avoid race conditions
- * Then release them.
- */
- if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
- err = filemap_write_and_wait_range(mapping,
- offset, offset + length - 1);
-
- if (err)
- return err;
- }
-
- mutex_lock(&inode->i_mutex);
- /* It's not possible punch hole on append only file */
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) {
- err = -EPERM;
- goto out_mutex;
- }
- if (IS_SWAPFILE(inode)) {
- err = -ETXTBSY;
- goto out_mutex;
- }
-
- /* No need to punch hole beyond i_size */
- if (offset >= inode->i_size)
- goto out_mutex;
-
- /*
- * If the hole extends beyond i_size, set the hole
- * to end after the page that contains i_size
- */
- if (offset + length > inode->i_size) {
- length = inode->i_size +
- PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) -
- offset;
- }
-
- first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- last_page = (offset + length) >> PAGE_CACHE_SHIFT;
-
- first_page_offset = first_page << PAGE_CACHE_SHIFT;
- last_page_offset = last_page << PAGE_CACHE_SHIFT;
-
- /* Now release the pages */
- if (last_page_offset > first_page_offset) {
- truncate_pagecache_range(inode, first_page_offset,
- last_page_offset - 1);
- }
-
- /* Wait all existing dio workers, newcomers will block on i_mutex */
- ext4_inode_block_unlocked_dio(inode);
- err = ext4_flush_unwritten_io(inode);
- if (err)
- goto out_dio;
- inode_dio_wait(inode);
-
- credits = ext4_writepage_trans_blocks(inode);
- handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
- if (IS_ERR(handle)) {
- err = PTR_ERR(handle);
- goto out_dio;
- }
-
-
- /*
- * Now we need to zero out the non-page-aligned data in the
- * pages at the start and tail of the hole, and unmap the buffer
- * heads for the block aligned regions of the page that were
- * completely zeroed.
- */
- if (first_page > last_page) {
- /*
- * If the file space being truncated is contained within a page
- * just zero out and unmap the middle of that page
- */
- err = ext4_discard_partial_page_buffers(handle,
- mapping, offset, length, 0);
-
- if (err)
- goto out;
- } else {
- /*
- * zero out and unmap the partial page that contains
- * the start of the hole
- */
- page_len = first_page_offset - offset;
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle, mapping,
- offset, page_len, 0);
- if (err)
- goto out;
- }
-
- /*
- * zero out and unmap the partial page that contains
- * the end of the hole
- */
- page_len = offset + length - last_page_offset;
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle, mapping,
- last_page_offset, page_len, 0);
- if (err)
- goto out;
- }
- }
-
- /*
- * If i_size is contained in the last page, we need to
- * unmap and zero the partial page after i_size
- */
- if (inode->i_size >> PAGE_CACHE_SHIFT == last_page &&
- inode->i_size % PAGE_CACHE_SIZE != 0) {
-
- page_len = PAGE_CACHE_SIZE -
- (inode->i_size & (PAGE_CACHE_SIZE - 1));
-
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle,
- mapping, inode->i_size, page_len, 0);
-
- if (err)
- goto out;
- }
- }
-
- first_block = (offset + sb->s_blocksize - 1) >>
- EXT4_BLOCK_SIZE_BITS(sb);
- stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
-
- /* If there are no blocks to remove, return now */
- if (first_block >= stop_block)
- goto out;
-
- down_write(&EXT4_I(inode)->i_data_sem);
- ext4_discard_preallocations(inode);
-
- err = ext4_es_remove_extent(inode, first_block,
- stop_block - first_block);
- err = ext4_ext_remove_space(inode, first_block, stop_block - 1);
-
- ext4_discard_preallocations(inode);
-
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
-
- up_write(&EXT4_I(inode)->i_data_sem);
-
-out:
- inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- ext4_journal_stop(handle);
-out_dio:
- ext4_inode_resume_unlocked_dio(inode);
-out_mutex:
- mutex_unlock(&inode->i_mutex);
- return err;
-}
-
int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
__u64 start, __u64 len)
{
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 3278e64e57b6..e0ba8a408def 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -166,8 +166,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (journal->j_flags & JBD2_BARRIER &&
!jbd2_trans_will_send_data_barrier(journal, commit_tid))
needs_barrier = true;
- jbd2_log_start_commit(journal, commit_tid);
- ret = jbd2_log_wait_commit(journal, commit_tid);
+ ret = jbd2_complete_transaction(journal, commit_tid);
if (needs_barrier) {
err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
if (!ret)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 6c5bb8d993fe..00a818d67b54 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -166,7 +166,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
trace_ext4_load_inode_bitmap(sb, block_group);
bh->b_end_io = ext4_end_bitmap_read;
get_bh(bh);
- submit_bh(READ, bh);
+ submit_bh(READ | REQ_META | REQ_PRIO, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
put_bh(bh);
@@ -666,6 +666,23 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
ei = EXT4_I(inode);
sbi = EXT4_SB(sb);
+ /*
+ * Initalize owners and quota early so that we don't have to account
+ * for quota initialization worst case in standard inode creating
+ * transaction
+ */
+ if (owner) {
+ inode->i_mode = mode;
+ i_uid_write(inode, owner[0]);
+ i_gid_write(inode, owner[1]);
+ } else if (test_opt(sb, GRPID)) {
+ inode->i_mode = mode;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = dir->i_gid;
+ } else
+ inode_init_owner(inode, dir, mode);
+ dquot_initialize(inode);
+
if (!goal)
goal = sbi->s_inode_goal;
@@ -697,7 +714,7 @@ got_group:
gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
if (!gdp)
- goto fail;
+ goto out;
/*
* Check free inodes count before loading bitmap.
@@ -711,7 +728,7 @@ got_group:
brelse(inode_bitmap_bh);
inode_bitmap_bh = ext4_read_inode_bitmap(sb, group);
if (!inode_bitmap_bh)
- goto fail;
+ goto out;
repeat_in_this_group:
ino = ext4_find_next_zero_bit((unsigned long *)
@@ -733,13 +750,16 @@ repeat_in_this_group:
handle_type, nblocks);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
- goto fail;
+ ext4_std_error(sb, err);
+ goto out;
}
}
BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
- if (err)
- goto fail;
+ if (err) {
+ ext4_std_error(sb, err);
+ goto out;
+ }
ext4_lock_group(sb, group);
ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data);
ext4_unlock_group(sb, group);
@@ -755,8 +775,10 @@ repeat_in_this_group:
got:
BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
- if (err)
- goto fail;
+ if (err) {
+ ext4_std_error(sb, err);
+ goto out;
+ }
/* We may have to initialize the block bitmap if it isn't already */
if (ext4_has_group_desc_csum(sb) &&
@@ -768,7 +790,8 @@ got:
err = ext4_journal_get_write_access(handle, block_bitmap_bh);
if (err) {
brelse(block_bitmap_bh);
- goto fail;
+ ext4_std_error(sb, err);
+ goto out;
}
BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap");
@@ -787,14 +810,18 @@ got:
ext4_unlock_group(sb, group);
brelse(block_bitmap_bh);
- if (err)
- goto fail;
+ if (err) {
+ ext4_std_error(sb, err);
+ goto out;
+ }
}
BUFFER_TRACE(group_desc_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, group_desc_bh);
- if (err)
- goto fail;
+ if (err) {
+ ext4_std_error(sb, err);
+ goto out;
+ }
/* Update the relevant bg descriptor fields */
if (ext4_has_group_desc_csum(sb)) {
@@ -840,8 +867,10 @@ got:
BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh);
- if (err)
- goto fail;
+ if (err) {
+ ext4_std_error(sb, err);
+ goto out;
+ }
percpu_counter_dec(&sbi->s_freeinodes_counter);
if (S_ISDIR(mode))
@@ -851,16 +880,6 @@ got:
flex_group = ext4_flex_group(sbi, group);
atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes);
}
- if (owner) {
- inode->i_mode = mode;
- i_uid_write(inode, owner[0]);
- i_gid_write(inode, owner[1]);
- } else if (test_opt(sb, GRPID)) {
- inode->i_mode = mode;
- inode->i_uid = current_fsuid();
- inode->i_gid = dir->i_gid;
- } else
- inode_init_owner(inode, dir, mode);
inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
/* This is the optimal IO size (for stat), not the fs block size */
@@ -889,7 +908,9 @@ got:
* twice.
*/
err = -EIO;
- goto fail;
+ ext4_error(sb, "failed to insert inode %lu: doubly allocated?",
+ inode->i_ino);
+ goto out;
}
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
@@ -899,7 +920,6 @@ got:
if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
__u32 csum;
- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
__le32 inum = cpu_to_le32(inode->i_ino);
__le32 gen = cpu_to_le32(inode->i_generation);
csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum,
@@ -918,7 +938,6 @@ got:
ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
ret = inode;
- dquot_initialize(inode);
err = dquot_alloc_inode(inode);
if (err)
goto fail_drop;
@@ -952,24 +971,17 @@ got:
ext4_debug("allocating inode %lu\n", inode->i_ino);
trace_ext4_allocate_inode(inode, dir, mode);
- goto really_out;
-fail:
- ext4_std_error(sb, err);
-out:
- iput(inode);
- ret = ERR_PTR(err);
-really_out:
brelse(inode_bitmap_bh);
return ret;
fail_free_drop:
dquot_free_inode(inode);
-
fail_drop:
- dquot_drop(inode);
- inode->i_flags |= S_NOQUOTA;
clear_nlink(inode);
unlock_new_inode(inode);
+out:
+ dquot_drop(inode);
+ inode->i_flags |= S_NOQUOTA;
iput(inode);
brelse(inode_bitmap_bh);
return ERR_PTR(err);
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index b505a145a593..98be6f697463 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -292,131 +292,6 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks,
}
/**
- * ext4_alloc_blocks: multiple allocate blocks needed for a branch
- * @handle: handle for this transaction
- * @inode: inode which needs allocated blocks
- * @iblock: the logical block to start allocated at
- * @goal: preferred physical block of allocation
- * @indirect_blks: the number of blocks need to allocate for indirect
- * blocks
- * @blks: number of desired blocks
- * @new_blocks: on return it will store the new block numbers for
- * the indirect blocks(if needed) and the first direct block,
- * @err: on return it will store the error code
- *
- * This function will return the number of blocks allocated as
- * requested by the passed-in parameters.
- */
-static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
- ext4_lblk_t iblock, ext4_fsblk_t goal,
- int indirect_blks, int blks,
- ext4_fsblk_t new_blocks[4], int *err)
-{
- struct ext4_allocation_request ar;
- int target, i;
- unsigned long count = 0, blk_allocated = 0;
- int index = 0;
- ext4_fsblk_t current_block = 0;
- int ret = 0;
-
- /*
- * Here we try to allocate the requested multiple blocks at once,
- * on a best-effort basis.
- * To build a branch, we should allocate blocks for
- * the indirect blocks(if not allocated yet), and at least
- * the first direct block of this branch. That's the
- * minimum number of blocks need to allocate(required)
- */
- /* first we try to allocate the indirect blocks */
- target = indirect_blks;
- while (target > 0) {
- count = target;
- /* allocating blocks for indirect blocks and direct blocks */
- current_block = ext4_new_meta_blocks(handle, inode, goal,
- 0, &count, err);
- if (*err)
- goto failed_out;
-
- if (unlikely(current_block + count > EXT4_MAX_BLOCK_FILE_PHYS)) {
- EXT4_ERROR_INODE(inode,
- "current_block %llu + count %lu > %d!",
- current_block, count,
- EXT4_MAX_BLOCK_FILE_PHYS);
- *err = -EIO;
- goto failed_out;
- }
-
- target -= count;
- /* allocate blocks for indirect blocks */
- while (index < indirect_blks && count) {
- new_blocks[index++] = current_block++;
- count--;
- }
- if (count > 0) {
- /*
- * save the new block number
- * for the first direct block
- */
- new_blocks[index] = current_block;
- WARN(1, KERN_INFO "%s returned more blocks than "
- "requested\n", __func__);
- break;
- }
- }
-
- target = blks - count ;
- blk_allocated = count;
- if (!target)
- goto allocated;
- /* Now allocate data blocks */
- memset(&ar, 0, sizeof(ar));
- ar.inode = inode;
- ar.goal = goal;
- ar.len = target;
- ar.logical = iblock;
- if (S_ISREG(inode->i_mode))
- /* enable in-core preallocation only for regular files */
- ar.flags = EXT4_MB_HINT_DATA;
-
- current_block = ext4_mb_new_blocks(handle, &ar, err);
- if (unlikely(current_block + ar.len > EXT4_MAX_BLOCK_FILE_PHYS)) {
- EXT4_ERROR_INODE(inode,
- "current_block %llu + ar.len %d > %d!",
- current_block, ar.len,
- EXT4_MAX_BLOCK_FILE_PHYS);
- *err = -EIO;
- goto failed_out;
- }
-
- if (*err && (target == blks)) {
- /*
- * if the allocation failed and we didn't allocate
- * any blocks before
- */
- goto failed_out;
- }
- if (!*err) {
- if (target == blks) {
- /*
- * save the new block number
- * for the first direct block
- */
- new_blocks[index] = current_block;
- }
- blk_allocated += ar.len;
- }
-allocated:
- /* total number of blocks allocated for direct blocks */
- ret = blk_allocated;
- *err = 0;
- return ret;
-failed_out:
- for (i = 0; i < index; i++)
- ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
- return ret;
-}
-
-/**
* ext4_alloc_branch - allocate and set up a chain of blocks.
* @handle: handle for this transaction
* @inode: owner
@@ -448,60 +323,59 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
int *blks, ext4_fsblk_t goal,
ext4_lblk_t *offsets, Indirect *branch)
{
- int blocksize = inode->i_sb->s_blocksize;
- int i, n = 0;
- int err = 0;
- struct buffer_head *bh;
- int num;
- ext4_fsblk_t new_blocks[4];
- ext4_fsblk_t current_block;
-
- num = ext4_alloc_blocks(handle, inode, iblock, goal, indirect_blks,
- *blks, new_blocks, &err);
- if (err)
- return err;
+ struct ext4_allocation_request ar;
+ struct buffer_head * bh;
+ ext4_fsblk_t b, new_blocks[4];
+ __le32 *p;
+ int i, j, err, len = 1;
- branch[0].key = cpu_to_le32(new_blocks[0]);
/*
- * metadata blocks and data blocks are allocated.
+ * Set up for the direct block allocation
*/
- for (n = 1; n <= indirect_blks; n++) {
- /*
- * Get buffer_head for parent block, zero it out
- * and set the pointer to new one, then send
- * parent to disk.
- */
- bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
+ memset(&ar, 0, sizeof(ar));
+ ar.inode = inode;
+ ar.len = *blks;
+ ar.logical = iblock;
+ if (S_ISREG(inode->i_mode))
+ ar.flags = EXT4_MB_HINT_DATA;
+
+ for (i = 0; i <= indirect_blks; i++) {
+ if (i == indirect_blks) {
+ ar.goal = goal;
+ new_blocks[i] = ext4_mb_new_blocks(handle, &ar, &err);
+ } else
+ goal = new_blocks[i] = ext4_new_meta_blocks(handle, inode,
+ goal, 0, NULL, &err);
+ if (err) {
+ i--;
+ goto failed;
+ }
+ branch[i].key = cpu_to_le32(new_blocks[i]);
+ if (i == 0)
+ continue;
+
+ bh = branch[i].bh = sb_getblk(inode->i_sb, new_blocks[i-1]);
if (unlikely(!bh)) {
err = -ENOMEM;
goto failed;
}
-
- branch[n].bh = bh;
lock_buffer(bh);
BUFFER_TRACE(bh, "call get_create_access");
err = ext4_journal_get_create_access(handle, bh);
if (err) {
- /* Don't brelse(bh) here; it's done in
- * ext4_journal_forget() below */
unlock_buffer(bh);
goto failed;
}
- memset(bh->b_data, 0, blocksize);
- branch[n].p = (__le32 *) bh->b_data + offsets[n];
- branch[n].key = cpu_to_le32(new_blocks[n]);
- *branch[n].p = branch[n].key;
- if (n == indirect_blks) {
- current_block = new_blocks[n];
- /*
- * End of chain, update the last new metablock of
- * the chain to point to the new allocated
- * data blocks numbers
- */
- for (i = 1; i < num; i++)
- *(branch[n].p + i) = cpu_to_le32(++current_block);
- }
+ memset(bh->b_data, 0, bh->b_size);
+ p = branch[i].p = (__le32 *) bh->b_data + offsets[i];
+ b = new_blocks[i];
+
+ if (i == indirect_blks)
+ len = ar.len;
+ for (j = 0; j < len; j++)
+ *p++ = cpu_to_le32(b++);
+
BUFFER_TRACE(bh, "marking uptodate");
set_buffer_uptodate(bh);
unlock_buffer(bh);
@@ -511,25 +385,16 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
if (err)
goto failed;
}
- *blks = num;
- return err;
+ *blks = ar.len;
+ return 0;
failed:
- /* Allocation failed, free what we already allocated */
- ext4_free_blocks(handle, inode, NULL, new_blocks[0], 1, 0);
- for (i = 1; i <= n ; i++) {
- /*
- * branch[i].bh is newly allocated, so there is no
- * need to revoke the block, which is why we don't
- * need to set EXT4_FREE_BLOCKS_METADATA.
- */
- ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1,
- EXT4_FREE_BLOCKS_FORGET);
+ for (; i >= 0; i--) {
+ if (i != indirect_blks && branch[i].bh)
+ ext4_forget(handle, 1, inode, branch[i].bh,
+ branch[i].bh->b_blocknr);
+ ext4_free_blocks(handle, inode, NULL, new_blocks[i],
+ (i == indirect_blks) ? ar.len : 1, 0);
}
- for (i = n+1; i < indirect_blks; i++)
- ext4_free_blocks(handle, inode, NULL, new_blocks[i], 1, 0);
-
- ext4_free_blocks(handle, inode, NULL, new_blocks[i], num, 0);
-
return err;
}
@@ -941,26 +806,9 @@ int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk)
* be able to restart the transaction at a conventient checkpoint to make
* sure we don't overflow the journal.
*
- * start_transaction gets us a new handle for a truncate transaction,
- * and extend_transaction tries to extend the existing one a bit. If
+ * Try to extend this transaction for the purposes of truncation. If
* extend fails, we need to propagate the failure up and restart the
* transaction in the top-level truncate loop. --sct
- */
-static handle_t *start_transaction(struct inode *inode)
-{
- handle_t *result;
-
- result = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
- ext4_blocks_for_truncate(inode));
- if (!IS_ERR(result))
- return result;
-
- ext4_std_error(inode->i_sb, PTR_ERR(result));
- return result;
-}
-
-/*
- * Try to extend this transaction for the purposes of truncation.
*
* Returns 0 if we managed to create more room. If we can't create more
* room, and the transaction must be restarted we return 1.
@@ -1353,68 +1201,30 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
}
}
-void ext4_ind_truncate(struct inode *inode)
+void ext4_ind_truncate(handle_t *handle, struct inode *inode)
{
- handle_t *handle;
struct ext4_inode_info *ei = EXT4_I(inode);
__le32 *i_data = ei->i_data;
int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
- struct address_space *mapping = inode->i_mapping;
ext4_lblk_t offsets[4];
Indirect chain[4];
Indirect *partial;
__le32 nr = 0;
int n = 0;
ext4_lblk_t last_block, max_block;
- loff_t page_len;
unsigned blocksize = inode->i_sb->s_blocksize;
- int err;
-
- handle = start_transaction(inode);
- if (IS_ERR(handle))
- return; /* AKPM: return what? */
last_block = (inode->i_size + blocksize-1)
>> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1)
>> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
- if (inode->i_size % PAGE_CACHE_SIZE != 0) {
- page_len = PAGE_CACHE_SIZE -
- (inode->i_size & (PAGE_CACHE_SIZE - 1));
-
- err = ext4_discard_partial_page_buffers(handle,
- mapping, inode->i_size, page_len, 0);
-
- if (err)
- goto out_stop;
- }
-
if (last_block != max_block) {
n = ext4_block_to_path(inode, last_block, offsets, NULL);
if (n == 0)
- goto out_stop; /* error */
+ return;
}
- /*
- * OK. This truncate is going to happen. We add the inode to the
- * orphan list, so that if this truncate spans multiple transactions,
- * and we crash, we will resume the truncate when the filesystem
- * recovers. It also marks the inode dirty, to catch the new size.
- *
- * Implication: the file must always be in a sane, consistent
- * truncatable state while each transaction commits.
- */
- if (ext4_orphan_add(handle, inode))
- goto out_stop;
-
- /*
- * From here we block out all ext4_get_block() callers who want to
- * modify the block allocation tree.
- */
- down_write(&ei->i_data_sem);
-
- ext4_discard_preallocations(inode);
ext4_es_remove_extent(inode, last_block, EXT_MAX_BLOCKS - last_block);
/*
@@ -1431,7 +1241,7 @@ void ext4_ind_truncate(struct inode *inode)
* It is unnecessary to free any data blocks if last_block is
* equal to the indirect block limit.
*/
- goto out_unlock;
+ return;
} else if (n == 1) { /* direct blocks */
ext4_free_data(handle, inode, NULL, i_data+offsets[0],
i_data + EXT4_NDIR_BLOCKS);
@@ -1491,31 +1301,6 @@ do_indirects:
case EXT4_TIND_BLOCK:
;
}
-
-out_unlock:
- up_write(&ei->i_data_sem);
- inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
-
- /*
- * In a multi-transaction truncate, we only make the final transaction
- * synchronous
- */
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
-out_stop:
- /*
- * If this was a simple ftruncate(), and the file will remain alive
- * then we need to clear up the orphan record which we created above.
- * However, if this was a real unlink then we were called by
- * ext4_delete_inode(), and we allow that function to clean up the
- * orphan info for us.
- */
- if (inode->i_nlink)
- ext4_orphan_del(handle, inode);
-
- ext4_journal_stop(handle);
- trace_ext4_truncate_exit(inode);
}
static int free_hole_blocks(handle_t *handle, struct inode *inode,
@@ -1539,9 +1324,9 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
blk = *i_data;
if (level > 0) {
ext4_lblk_t first2;
- bh = sb_bread(inode->i_sb, blk);
+ bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
if (!bh) {
- EXT4_ERROR_INODE_BLOCK(inode, blk,
+ EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
"Read failure");
return -EIO;
}
@@ -1569,8 +1354,8 @@ err:
return ret;
}
-static int ext4_free_hole_blocks(handle_t *handle, struct inode *inode,
- ext4_lblk_t first, ext4_lblk_t stop)
+int ext4_free_hole_blocks(handle_t *handle, struct inode *inode,
+ ext4_lblk_t first, ext4_lblk_t stop)
{
int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
int level, ret = 0;
@@ -1604,157 +1389,3 @@ err:
return ret;
}
-int ext4_ind_punch_hole(struct file *file, loff_t offset, loff_t length)
-{
- struct inode *inode = file_inode(file);
- struct super_block *sb = inode->i_sb;
- ext4_lblk_t first_block, stop_block;
- struct address_space *mapping = inode->i_mapping;
- handle_t *handle = NULL;
- loff_t first_page, last_page, page_len;
- loff_t first_page_offset, last_page_offset;
- int err = 0;
-
- /*
- * Write out all dirty pages to avoid race conditions
- * Then release them.
- */
- if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
- err = filemap_write_and_wait_range(mapping,
- offset, offset + length - 1);
- if (err)
- return err;
- }
-
- mutex_lock(&inode->i_mutex);
- /* It's not possible punch hole on append only file */
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) {
- err = -EPERM;
- goto out_mutex;
- }
- if (IS_SWAPFILE(inode)) {
- err = -ETXTBSY;
- goto out_mutex;
- }
-
- /* No need to punch hole beyond i_size */
- if (offset >= inode->i_size)
- goto out_mutex;
-
- /*
- * If the hole extents beyond i_size, set the hole
- * to end after the page that contains i_size
- */
- if (offset + length > inode->i_size) {
- length = inode->i_size +
- PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) -
- offset;
- }
-
- first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- last_page = (offset + length) >> PAGE_CACHE_SHIFT;
-
- first_page_offset = first_page << PAGE_CACHE_SHIFT;
- last_page_offset = last_page << PAGE_CACHE_SHIFT;
-
- /* Now release the pages */
- if (last_page_offset > first_page_offset) {
- truncate_pagecache_range(inode, first_page_offset,
- last_page_offset - 1);
- }
-
- /* Wait all existing dio works, newcomers will block on i_mutex */
- inode_dio_wait(inode);
-
- handle = start_transaction(inode);
- if (IS_ERR(handle))
- goto out_mutex;
-
- /*
- * Now we need to zero out the non-page-aligned data in the
- * pages at the start and tail of the hole, and unmap the buffer
- * heads for the block aligned regions of the page that were
- * completely zerod.
- */
- if (first_page > last_page) {
- /*
- * If the file space being truncated is contained within a page
- * just zero out and unmap the middle of that page
- */
- err = ext4_discard_partial_page_buffers(handle,
- mapping, offset, length, 0);
- if (err)
- goto out;
- } else {
- /*
- * Zero out and unmap the paritial page that contains
- * the start of the hole
- */
- page_len = first_page_offset - offset;
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle, mapping,
- offset, page_len, 0);
- if (err)
- goto out;
- }
-
- /*
- * Zero out and unmap the partial page that contains
- * the end of the hole
- */
- page_len = offset + length - last_page_offset;
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle, mapping,
- last_page_offset, page_len, 0);
- if (err)
- goto out;
- }
- }
-
- /*
- * If i_size contained in the last page, we need to
- * unmap and zero the paritial page after i_size
- */
- if (inode->i_size >> PAGE_CACHE_SHIFT == last_page &&
- inode->i_size % PAGE_CACHE_SIZE != 0) {
- page_len = PAGE_CACHE_SIZE -
- (inode->i_size & (PAGE_CACHE_SIZE - 1));
- if (page_len > 0) {
- err = ext4_discard_partial_page_buffers(handle,
- mapping, inode->i_size, page_len, 0);
- if (err)
- goto out;
- }
- }
-
- first_block = (offset + sb->s_blocksize - 1) >>
- EXT4_BLOCK_SIZE_BITS(sb);
- stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
-
- if (first_block >= stop_block)
- goto out;
-
- down_write(&EXT4_I(inode)->i_data_sem);
- ext4_discard_preallocations(inode);
-
- err = ext4_es_remove_extent(inode, first_block,
- stop_block - first_block);
- err = ext4_free_hole_blocks(handle, inode, first_block, stop_block);
-
- ext4_discard_preallocations(inode);
-
- if (IS_SYNC(inode))
- ext4_handle_sync(handle);
-
- up_write(&EXT4_I(inode)->i_data_sem);
-
-out:
- inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
- ext4_mark_inode_dirty(handle, inode);
- ext4_journal_stop(handle);
-
-out_mutex:
- mutex_unlock(&inode->i_mutex);
-
- return err;
-}
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index c0fd1a123f7d..3e2bf873e8a8 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -19,7 +19,8 @@
#define EXT4_XATTR_SYSTEM_DATA "data"
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
-#define EXT4_INLINE_DOTDOT_SIZE 4
+#define EXT4_INLINE_DOTDOT_OFFSET 2
+#define EXT4_INLINE_DOTDOT_SIZE 4
int ext4_get_inline_size(struct inode *inode)
{
@@ -1289,6 +1290,120 @@ out:
return ret;
}
+/*
+ * This function fills a red-black tree with information from an
+ * inlined dir. It returns the number directory entries loaded
+ * into the tree. If there is an error it is returned in err.
+ */
+int htree_inlinedir_to_tree(struct file *dir_file,
+ struct inode *dir, ext4_lblk_t block,
+ struct dx_hash_info *hinfo,
+ __u32 start_hash, __u32 start_minor_hash,
+ int *has_inline_data)
+{
+ int err = 0, count = 0;
+ unsigned int parent_ino;
+ int pos;
+ struct ext4_dir_entry_2 *de;
+ struct inode *inode = file_inode(dir_file);
+ int ret, inline_size = 0;
+ struct ext4_iloc iloc;
+ void *dir_buf = NULL;
+ struct ext4_dir_entry_2 fake;
+
+ ret = ext4_get_inode_loc(inode, &iloc);
+ if (ret)
+ return ret;
+
+ down_read(&EXT4_I(inode)->xattr_sem);
+ if (!ext4_has_inline_data(inode)) {
+ up_read(&EXT4_I(inode)->xattr_sem);
+ *has_inline_data = 0;
+ goto out;
+ }
+
+ inline_size = ext4_get_inline_size(inode);
+ dir_buf = kmalloc(inline_size, GFP_NOFS);
+ if (!dir_buf) {
+ ret = -ENOMEM;
+ up_read(&EXT4_I(inode)->xattr_sem);
+ goto out;
+ }
+
+ ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc);
+ up_read(&EXT4_I(inode)->xattr_sem);
+ if (ret < 0)
+ goto out;
+
+ pos = 0;
+ parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
+ while (pos < inline_size) {
+ /*
+ * As inlined dir doesn't store any information about '.' and
+ * only the inode number of '..' is stored, we have to handle
+ * them differently.
+ */
+ if (pos == 0) {
+ fake.inode = cpu_to_le32(inode->i_ino);
+ fake.name_len = 1;
+ strcpy(fake.name, ".");
+ fake.rec_len = ext4_rec_len_to_disk(
+ EXT4_DIR_REC_LEN(fake.name_len),
+ inline_size);
+ ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
+ de = &fake;
+ pos = EXT4_INLINE_DOTDOT_OFFSET;
+ } else if (pos == EXT4_INLINE_DOTDOT_OFFSET) {
+ fake.inode = cpu_to_le32(parent_ino);
+ fake.name_len = 2;
+ strcpy(fake.name, "..");
+ fake.rec_len = ext4_rec_len_to_disk(
+ EXT4_DIR_REC_LEN(fake.name_len),
+ inline_size);
+ ext4_set_de_type(inode->i_sb, &fake, S_IFDIR);
+ de = &fake;
+ pos = EXT4_INLINE_DOTDOT_SIZE;
+ } else {
+ de = (struct ext4_dir_entry_2 *)(dir_buf + pos);
+ pos += ext4_rec_len_from_disk(de->rec_len, inline_size);
+ if (ext4_check_dir_entry(inode, dir_file, de,
+ iloc.bh, dir_buf,
+ inline_size, pos)) {
+ ret = count;
+ goto out;
+ }
+ }
+
+ ext4fs_dirhash(de->name, de->name_len, hinfo);
+ if ((hinfo->hash < start_hash) ||
+ ((hinfo->hash == start_hash) &&
+ (hinfo->minor_hash < start_minor_hash)))
+ continue;
+ if (de->inode == 0)
+ continue;
+ err = ext4_htree_store_dirent(dir_file,
+ hinfo->hash, hinfo->minor_hash, de);
+ if (err) {
+ count = err;
+ goto out;
+ }
+ count++;
+ }
+ ret = count;
+out:
+ kfree(dir_buf);
+ brelse(iloc.bh);
+ return ret;
+}
+
+/*
+ * So this function is called when the volume is mkfsed with
+ * dir_index disabled. In order to keep f_pos persistent
+ * after we convert from an inlined dir to a blocked based,
+ * we just pretend that we are a normal dir and return the
+ * offset as if '.' and '..' really take place.
+ *
+ */
int ext4_read_inline_dir(struct file *filp,
void *dirent, filldir_t filldir,
int *has_inline_data)
@@ -1302,6 +1417,7 @@ int ext4_read_inline_dir(struct file *filp,
int ret, inline_size = 0;
struct ext4_iloc iloc;
void *dir_buf = NULL;
+ int dotdot_offset, dotdot_size, extra_offset, extra_size;
ret = ext4_get_inode_loc(inode, &iloc);
if (ret)
@@ -1330,8 +1446,21 @@ int ext4_read_inline_dir(struct file *filp,
sb = inode->i_sb;
stored = 0;
parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
+ offset = filp->f_pos;
- while (!error && !stored && filp->f_pos < inode->i_size) {
+ /*
+ * dotdot_offset and dotdot_size is the real offset and
+ * size for ".." and "." if the dir is block based while
+ * the real size for them are only EXT4_INLINE_DOTDOT_SIZE.
+ * So we will use extra_offset and extra_size to indicate them
+ * during the inline dir iteration.
+ */
+ dotdot_offset = EXT4_DIR_REC_LEN(1);
+ dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2);
+ extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
+ extra_size = extra_offset + inline_size;
+
+ while (!error && !stored && filp->f_pos < extra_size) {
revalidate:
/*
* If the version has changed since the last call to
@@ -1340,15 +1469,23 @@ revalidate:
* dir to make sure.
*/
if (filp->f_version != inode->i_version) {
- for (i = 0;
- i < inode->i_size && i < offset;) {
+ for (i = 0; i < extra_size && i < offset;) {
+ /*
+ * "." is with offset 0 and
+ * ".." is dotdot_offset.
+ */
if (!i) {
- /* skip "." and ".." if needed. */
- i += EXT4_INLINE_DOTDOT_SIZE;
+ i = dotdot_offset;
+ continue;
+ } else if (i == dotdot_offset) {
+ i = dotdot_size;
continue;
}
+ /* for other entry, the real offset in
+ * the buf has to be tuned accordingly.
+ */
de = (struct ext4_dir_entry_2 *)
- (dir_buf + i);
+ (dir_buf + i - extra_offset);
/* It's too expensive to do a full
* dirent test each time round this
* loop, but we do have to test at
@@ -1356,43 +1493,47 @@ revalidate:
* failure will be detected in the
* dirent test below. */
if (ext4_rec_len_from_disk(de->rec_len,
- inline_size) < EXT4_DIR_REC_LEN(1))
+ extra_size) < EXT4_DIR_REC_LEN(1))
break;
i += ext4_rec_len_from_disk(de->rec_len,
- inline_size);
+ extra_size);
}
offset = i;
filp->f_pos = offset;
filp->f_version = inode->i_version;
}
- while (!error && filp->f_pos < inode->i_size) {
+ while (!error && filp->f_pos < extra_size) {
if (filp->f_pos == 0) {
error = filldir(dirent, ".", 1, 0, inode->i_ino,
DT_DIR);
if (error)
break;
stored++;
+ filp->f_pos = dotdot_offset;
+ continue;
+ }
- error = filldir(dirent, "..", 2, 0, parent_ino,
- DT_DIR);
+ if (filp->f_pos == dotdot_offset) {
+ error = filldir(dirent, "..", 2,
+ dotdot_offset,
+ parent_ino, DT_DIR);
if (error)
break;
stored++;
- filp->f_pos = offset = EXT4_INLINE_DOTDOT_SIZE;
+ filp->f_pos = dotdot_size;
continue;
}
- de = (struct ext4_dir_entry_2 *)(dir_buf + offset);
+ de = (struct ext4_dir_entry_2 *)
+ (dir_buf + filp->f_pos - extra_offset);
if (ext4_check_dir_entry(inode, filp, de,
iloc.bh, dir_buf,
- inline_size, offset)) {
+ extra_size, filp->f_pos)) {
ret = stored;
goto out;
}
- offset += ext4_rec_len_from_disk(de->rec_len,
- inline_size);
if (le32_to_cpu(de->inode)) {
/* We might block in the next section
* if the data destination is
@@ -1415,9 +1556,8 @@ revalidate:
stored++;
}
filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
- inline_size);
+ extra_size);
}
- offset = 0;
}
out:
kfree(dir_buf);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b3a5213bc73e..793d44b84d7f 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -55,21 +55,21 @@ static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
__u16 csum_hi = 0;
__u32 csum;
- csum_lo = raw->i_checksum_lo;
+ csum_lo = le16_to_cpu(raw->i_checksum_lo);
raw->i_checksum_lo = 0;
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
- csum_hi = raw->i_checksum_hi;
+ csum_hi = le16_to_cpu(raw->i_checksum_hi);
raw->i_checksum_hi = 0;
}
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
EXT4_INODE_SIZE(inode->i_sb));
- raw->i_checksum_lo = csum_lo;
+ raw->i_checksum_lo = cpu_to_le16(csum_lo);
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
- raw->i_checksum_hi = csum_hi;
+ raw->i_checksum_hi = cpu_to_le16(csum_hi);
return csum;
}
@@ -210,8 +210,7 @@ void ext4_evict_inode(struct inode *inode)
journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
tid_t commit_tid = EXT4_I(inode)->i_datasync_tid;
- jbd2_log_start_commit(journal, commit_tid);
- jbd2_log_wait_commit(journal, commit_tid);
+ jbd2_complete_transaction(journal, commit_tid);
filemap_write_and_wait(&inode->i_data);
}
truncate_inode_pages(&inode->i_data, 0);
@@ -1081,20 +1080,42 @@ retry_journal:
/* For write_end() in data=journal mode */
static int write_end_fn(handle_t *handle, struct buffer_head *bh)
{
+ int ret;
if (!buffer_mapped(bh) || buffer_freed(bh))
return 0;
set_buffer_uptodate(bh);
- return ext4_handle_dirty_metadata(handle, NULL, bh);
+ ret = ext4_handle_dirty_metadata(handle, NULL, bh);
+ clear_buffer_meta(bh);
+ clear_buffer_prio(bh);
+ return ret;
}
-static int ext4_generic_write_end(struct file *file,
- struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
+/*
+ * We need to pick up the new inode size which generic_commit_write gave us
+ * `file' can be NULL - eg, when called from page_symlink().
+ *
+ * ext4 never places buffers on inode->i_mapping->private_list. metadata
+ * buffers are managed internally.
+ */
+static int ext4_write_end(struct file *file,
+ struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
- int i_size_changed = 0;
- struct inode *inode = mapping->host;
handle_t *handle = ext4_journal_current_handle();
+ struct inode *inode = mapping->host;
+ int ret = 0, ret2;
+ int i_size_changed = 0;
+
+ trace_ext4_write_end(inode, pos, len, copied);
+ if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
+ ret = ext4_jbd2_file_inode(handle, inode);
+ if (ret) {
+ unlock_page(page);
+ page_cache_release(page);
+ goto errout;
+ }
+ }
if (ext4_has_inline_data(inode))
copied = ext4_write_inline_data_end(inode, pos, len,
@@ -1105,7 +1126,7 @@ static int ext4_generic_write_end(struct file *file,
/*
* No need to use i_size_read() here, the i_size
- * cannot change under us because we hold i_mutex.
+ * cannot change under us because we hole i_mutex.
*
* But it's important to update i_size while still holding page lock:
* page writeout could otherwise come in and zero beyond i_size.
@@ -1115,10 +1136,10 @@ static int ext4_generic_write_end(struct file *file,
i_size_changed = 1;
}
- if (pos + copied > EXT4_I(inode)->i_disksize) {
+ if (pos + copied > EXT4_I(inode)->i_disksize) {
/* We need to mark inode dirty even if
* new_i_size is less that inode->i_size
- * bu greater than i_disksize.(hint delalloc)
+ * but greater than i_disksize. (hint delalloc)
*/
ext4_update_i_disksize(inode, (pos + copied));
i_size_changed = 1;
@@ -1135,87 +1156,15 @@ static int ext4_generic_write_end(struct file *file,
if (i_size_changed)
ext4_mark_inode_dirty(handle, inode);
- return copied;
-}
-
-/*
- * We need to pick up the new inode size which generic_commit_write gave us
- * `file' can be NULL - eg, when called from page_symlink().
- *
- * ext4 never places buffers on inode->i_mapping->private_list. metadata
- * buffers are managed internally.
- */
-static int ext4_ordered_write_end(struct file *file,
- struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
-{
- handle_t *handle = ext4_journal_current_handle();
- struct inode *inode = mapping->host;
- int ret = 0, ret2;
-
- trace_ext4_ordered_write_end(inode, pos, len, copied);
- ret = ext4_jbd2_file_inode(handle, inode);
-
- if (ret == 0) {
- ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
- page, fsdata);
- copied = ret2;
- if (pos + len > inode->i_size && ext4_can_truncate(inode))
- /* if we have allocated more blocks and copied
- * less. We will have blocks allocated outside
- * inode->i_size. So truncate them
- */
- ext4_orphan_add(handle, inode);
- if (ret2 < 0)
- ret = ret2;
- } else {
- unlock_page(page);
- page_cache_release(page);
- }
-
- ret2 = ext4_journal_stop(handle);
- if (!ret)
- ret = ret2;
-
- if (pos + len > inode->i_size) {
- ext4_truncate_failed_write(inode);
- /*
- * If truncate failed early the inode might still be
- * on the orphan list; we need to make sure the inode
- * is removed from the orphan list in that case.
- */
- if (inode->i_nlink)
- ext4_orphan_del(NULL, inode);
- }
-
-
- return ret ? ret : copied;
-}
-
-static int ext4_writeback_write_end(struct file *file,
- struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
-{
- handle_t *handle = ext4_journal_current_handle();
- struct inode *inode = mapping->host;
- int ret = 0, ret2;
-
- trace_ext4_writeback_write_end(inode, pos, len, copied);
- ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
- page, fsdata);
- copied = ret2;
+ if (copied < 0)
+ ret = copied;
if (pos + len > inode->i_size && ext4_can_truncate(inode))
/* if we have allocated more blocks and copied
* less. We will have blocks allocated outside
* inode->i_size. So truncate them
*/
ext4_orphan_add(handle, inode);
-
- if (ret2 < 0)
- ret = ret2;
-
+errout:
ret2 = ext4_journal_stop(handle);
if (!ret)
ret = ret2;
@@ -1538,7 +1487,10 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
struct ext4_io_submit io_submit;
BUG_ON(mpd->next_page <= mpd->first_page);
- memset(&io_submit, 0, sizeof(io_submit));
+ ext4_io_submit_init(&io_submit, mpd->wbc);
+ io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS);
+ if (!io_submit.io_end)
+ return -ENOMEM;
/*
* We need to start from the first_page to the next_page - 1
* to make sure we also write the mapped dirty buffer_heads.
@@ -1626,6 +1578,8 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd,
pagevec_release(&pvec);
}
ext4_io_submit(&io_submit);
+ /* Drop io_end reference we got from init */
+ ext4_put_io_end_defer(io_submit.io_end);
return ret;
}
@@ -1670,22 +1624,25 @@ static void ext4_print_free_blocks(struct inode *inode)
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct super_block *sb = inode->i_sb;
+ struct ext4_inode_info *ei = EXT4_I(inode);
ext4_msg(sb, KERN_CRIT, "Total free blocks count %lld",
EXT4_C2B(EXT4_SB(inode->i_sb),
- ext4_count_free_clusters(inode->i_sb)));
+ ext4_count_free_clusters(sb)));
ext4_msg(sb, KERN_CRIT, "Free/Dirty block details");
ext4_msg(sb, KERN_CRIT, "free_blocks=%lld",
- (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
+ (long long) EXT4_C2B(EXT4_SB(sb),
percpu_counter_sum(&sbi->s_freeclusters_counter)));
ext4_msg(sb, KERN_CRIT, "dirty_blocks=%lld",
- (long long) EXT4_C2B(EXT4_SB(inode->i_sb),
+ (long long) EXT4_C2B(EXT4_SB(sb),
percpu_counter_sum(&sbi->s_dirtyclusters_counter)));
ext4_msg(sb, KERN_CRIT, "Block reservation details");
ext4_msg(sb, KERN_CRIT, "i_reserved_data_blocks=%u",
- EXT4_I(inode)->i_reserved_data_blocks);
+ ei->i_reserved_data_blocks);
ext4_msg(sb, KERN_CRIT, "i_reserved_meta_blocks=%u",
- EXT4_I(inode)->i_reserved_meta_blocks);
+ ei->i_reserved_meta_blocks);
+ ext4_msg(sb, KERN_CRIT, "i_allocated_meta_blocks=%u",
+ ei->i_allocated_meta_blocks);
return;
}
@@ -1740,12 +1697,21 @@ static void mpage_da_map_and_submit(struct mpage_da_data *mpd)
*/
map.m_lblk = next;
map.m_len = max_blocks;
- get_blocks_flags = EXT4_GET_BLOCKS_CREATE;
+ /*
+ * We're in delalloc path and it is possible that we're going to
+ * need more metadata blocks than previously reserved. However
+ * we must not fail because we're in writeback and there is
+ * nothing we can do about it so it might result in data loss.
+ * So use reserved blocks to allocate metadata if possible.
+ */
+ get_blocks_flags = EXT4_GET_BLOCKS_CREATE |
+ EXT4_GET_BLOCKS_METADATA_NOFAIL;
if (ext4_should_dioread_nolock(mpd->inode))
get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
if (mpd->b_state & (1 << BH_Delay))
get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE;
+
blks = ext4_map_blocks(handle, mpd->inode, &map, get_blocks_flags);
if (blks < 0) {
struct super_block *sb = mpd->inode->i_sb;
@@ -2272,9 +2238,16 @@ static int ext4_writepage(struct page *page,
*/
return __ext4_journalled_writepage(page, len);
- memset(&io_submit, 0, sizeof(io_submit));
+ ext4_io_submit_init(&io_submit, wbc);
+ io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS);
+ if (!io_submit.io_end) {
+ redirty_page_for_writepage(wbc, page);
+ return -ENOMEM;
+ }
ret = ext4_bio_write_page(&io_submit, page, len, wbc);
ext4_io_submit(&io_submit);
+ /* Drop io_end reference we got from init */
+ ext4_put_io_end_defer(io_submit.io_end);
return ret;
}
@@ -2661,7 +2634,7 @@ out_writepages:
static int ext4_nonda_switch(struct super_block *sb)
{
- s64 free_blocks, dirty_blocks;
+ s64 free_clusters, dirty_clusters;
struct ext4_sb_info *sbi = EXT4_SB(sb);
/*
@@ -2672,17 +2645,18 @@ static int ext4_nonda_switch(struct super_block *sb)
* Delalloc need an accurate free block accounting. So switch
* to non delalloc when we are near to error range.
*/
- free_blocks = EXT4_C2B(sbi,
- percpu_counter_read_positive(&sbi->s_freeclusters_counter));
- dirty_blocks = percpu_counter_read_positive(&sbi->s_dirtyclusters_counter);
+ free_clusters =
+ percpu_counter_read_positive(&sbi->s_freeclusters_counter);
+ dirty_clusters =
+ percpu_counter_read_positive(&sbi->s_dirtyclusters_counter);
/*
* Start pushing delalloc when 1/2 of free blocks are dirty.
*/
- if (dirty_blocks && (free_blocks < 2 * dirty_blocks))
+ if (dirty_clusters && (free_clusters < 2 * dirty_clusters))
try_to_writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE);
- if (2 * free_blocks < 3 * dirty_blocks ||
- free_blocks < (dirty_blocks + EXT4_FREECLUSTERS_WATERMARK)) {
+ if (2 * free_clusters < 3 * dirty_clusters ||
+ free_clusters < (dirty_clusters + EXT4_FREECLUSTERS_WATERMARK)) {
/*
* free block count is less than 150% of dirty blocks
* or free blocks is less than watermark
@@ -2818,18 +2792,9 @@ static int ext4_da_write_end(struct file *file,
unsigned long start, end;
int write_mode = (int)(unsigned long)fsdata;
- if (write_mode == FALL_BACK_TO_NONDELALLOC) {
- switch (ext4_inode_journal_mode(inode)) {
- case EXT4_INODE_ORDERED_DATA_MODE:
- return ext4_ordered_write_end(file, mapping, pos,
- len, copied, page, fsdata);
- case EXT4_INODE_WRITEBACK_DATA_MODE:
- return ext4_writeback_write_end(file, mapping, pos,
- len, copied, page, fsdata);
- default:
- BUG();
- }
- }
+ if (write_mode == FALL_BACK_TO_NONDELALLOC)
+ return ext4_write_end(file, mapping, pos,
+ len, copied, page, fsdata);
trace_ext4_da_write_end(inode, pos, len, copied);
start = pos & (PAGE_CACHE_SIZE - 1);
@@ -3113,9 +3078,13 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
struct inode *inode = file_inode(iocb->ki_filp);
ext4_io_end_t *io_end = iocb->private;
- /* if not async direct IO or dio with 0 bytes write, just return */
- if (!io_end || !size)
- goto out;
+ /* if not async direct IO just return */
+ if (!io_end) {
+ inode_dio_done(inode);
+ if (is_async)
+ aio_complete(iocb, ret, 0);
+ return;
+ }
ext_debug("ext4_end_io_dio(): io_end 0x%p "
"for inode %lu, iocb 0x%p, offset %llu, size %zd\n",
@@ -3123,25 +3092,13 @@ static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
size);
iocb->private = NULL;
-
- /* if not aio dio with unwritten extents, just free io and return */
- if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
- ext4_free_io_end(io_end);
-out:
- inode_dio_done(inode);
- if (is_async)
- aio_complete(iocb, ret, 0);
- return;
- }
-
io_end->offset = offset;
io_end->size = size;
if (is_async) {
io_end->iocb = iocb;
io_end->result = ret;
}
-
- ext4_add_complete_io(io_end);
+ ext4_put_io_end_defer(io_end);
}
/*
@@ -3175,6 +3132,7 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
get_block_t *get_block_func = NULL;
int dio_flags = 0;
loff_t final_size = offset + count;
+ ext4_io_end_t *io_end = NULL;
/* Use the old path for reads and writes beyond i_size. */
if (rw != WRITE || final_size > inode->i_size)
@@ -3213,13 +3171,16 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
iocb->private = NULL;
ext4_inode_aio_set(inode, NULL);
if (!is_sync_kiocb(iocb)) {
- ext4_io_end_t *io_end = ext4_init_io_end(inode, GFP_NOFS);
+ io_end = ext4_init_io_end(inode, GFP_NOFS);
if (!io_end) {
ret = -ENOMEM;
goto retake_lock;
}
io_end->flag |= EXT4_IO_END_DIRECT;
- iocb->private = io_end;
+ /*
+ * Grab reference for DIO. Will be dropped in ext4_end_io_dio()
+ */
+ iocb->private = ext4_get_io_end(io_end);
/*
* we save the io structure for current async direct
* IO, so that later ext4_map_blocks() could flag the
@@ -3243,26 +3204,27 @@ static ssize_t ext4_ext_direct_IO(int rw, struct kiocb *iocb,
NULL,
dio_flags);
- if (iocb->private)
- ext4_inode_aio_set(inode, NULL);
/*
- * The io_end structure takes a reference to the inode, that
- * structure needs to be destroyed and the reference to the
- * inode need to be dropped, when IO is complete, even with 0
- * byte write, or failed.
- *
- * In the successful AIO DIO case, the io_end structure will
- * be destroyed and the reference to the inode will be dropped
- * after the end_io call back function is called.
- *
- * In the case there is 0 byte write, or error case, since VFS
- * direct IO won't invoke the end_io call back function, we
- * need to free the end_io structure here.
+ * Put our reference to io_end. This can free the io_end structure e.g.
+ * in sync IO case or in case of error. It can even perform extent
+ * conversion if all bios we submitted finished before we got here.
+ * Note that in that case iocb->private can be already set to NULL
+ * here.
*/
- if (ret != -EIOCBQUEUED && ret <= 0 && iocb->private) {
- ext4_free_io_end(iocb->private);
- iocb->private = NULL;
- } else if (ret > 0 && !overwrite && ext4_test_inode_state(inode,
+ if (io_end) {
+ ext4_inode_aio_set(inode, NULL);
+ ext4_put_io_end(io_end);
+ /*
+ * In case of error or no write ext4_end_io_dio() was not
+ * called so we have to put iocb's reference.
+ */
+ if (ret <= 0 && ret != -EIOCBQUEUED) {
+ WARN_ON(iocb->private != io_end);
+ ext4_put_io_end(io_end);
+ iocb->private = NULL;
+ }
+ }
+ if (ret > 0 && !overwrite && ext4_test_inode_state(inode,
EXT4_STATE_DIO_UNWRITTEN)) {
int err;
/*
@@ -3334,27 +3296,12 @@ static int ext4_journalled_set_page_dirty(struct page *page)
return __set_page_dirty_nobuffers(page);
}
-static const struct address_space_operations ext4_ordered_aops = {
+static const struct address_space_operations ext4_aops = {
.readpage = ext4_readpage,
.readpages = ext4_readpages,
.writepage = ext4_writepage,
.write_begin = ext4_write_begin,
- .write_end = ext4_ordered_write_end,
- .bmap = ext4_bmap,
- .invalidatepage = ext4_invalidatepage,
- .releasepage = ext4_releasepage,
- .direct_IO = ext4_direct_IO,
- .migratepage = buffer_migrate_page,
- .is_partially_uptodate = block_is_partially_uptodate,
- .error_remove_page = generic_error_remove_page,
-};
-
-static const struct address_space_operations ext4_writeback_aops = {
- .readpage = ext4_readpage,
- .readpages = ext4_readpages,
- .writepage = ext4_writepage,
- .write_begin = ext4_write_begin,
- .write_end = ext4_writeback_write_end,
+ .write_end = ext4_write_end,
.bmap = ext4_bmap,
.invalidatepage = ext4_invalidatepage,
.releasepage = ext4_releasepage,
@@ -3399,23 +3346,21 @@ void ext4_set_aops(struct inode *inode)
{
switch (ext4_inode_journal_mode(inode)) {
case EXT4_INODE_ORDERED_DATA_MODE:
- if (test_opt(inode->i_sb, DELALLOC))
- inode->i_mapping->a_ops = &ext4_da_aops;
- else
- inode->i_mapping->a_ops = &ext4_ordered_aops;
+ ext4_set_inode_state(inode, EXT4_STATE_ORDERED_MODE);
break;
case EXT4_INODE_WRITEBACK_DATA_MODE:
- if (test_opt(inode->i_sb, DELALLOC))
- inode->i_mapping->a_ops = &ext4_da_aops;
- else
- inode->i_mapping->a_ops = &ext4_writeback_aops;
+ ext4_clear_inode_state(inode, EXT4_STATE_ORDERED_MODE);
break;
case EXT4_INODE_JOURNAL_DATA_MODE:
inode->i_mapping->a_ops = &ext4_journalled_aops;
- break;
+ return;
default:
BUG();
}
+ if (test_opt(inode->i_sb, DELALLOC))
+ inode->i_mapping->a_ops = &ext4_da_aops;
+ else
+ inode->i_mapping->a_ops = &ext4_aops;
}
@@ -3646,20 +3591,190 @@ int ext4_can_truncate(struct inode *inode)
int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
{
struct inode *inode = file_inode(file);
+ struct super_block *sb = inode->i_sb;
+ ext4_lblk_t first_block, stop_block;
+ struct address_space *mapping = inode->i_mapping;
+ loff_t first_page, last_page, page_len;
+ loff_t first_page_offset, last_page_offset;
+ handle_t *handle;
+ unsigned int credits;
+ int ret = 0;
+
if (!S_ISREG(inode->i_mode))
return -EOPNOTSUPP;
- if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
- return ext4_ind_punch_hole(file, offset, length);
-
- if (EXT4_SB(inode->i_sb)->s_cluster_ratio > 1) {
+ if (EXT4_SB(sb)->s_cluster_ratio > 1) {
/* TODO: Add support for bigalloc file systems */
return -EOPNOTSUPP;
}
trace_ext4_punch_hole(inode, offset, length);
- return ext4_ext_punch_hole(file, offset, length);
+ /*
+ * Write out all dirty pages to avoid race conditions
+ * Then release them.
+ */
+ if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
+ ret = filemap_write_and_wait_range(mapping, offset,
+ offset + length - 1);
+ if (ret)
+ return ret;
+ }
+
+ mutex_lock(&inode->i_mutex);
+ /* It's not possible punch hole on append only file */
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) {
+ ret = -EPERM;
+ goto out_mutex;
+ }
+ if (IS_SWAPFILE(inode)) {
+ ret = -ETXTBSY;
+ goto out_mutex;
+ }
+
+ /* No need to punch hole beyond i_size */
+ if (offset >= inode->i_size)
+ goto out_mutex;
+
+ /*
+ * If the hole extends beyond i_size, set the hole
+ * to end after the page that contains i_size
+ */
+ if (offset + length > inode->i_size) {
+ length = inode->i_size +
+ PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) -
+ offset;
+ }
+
+ first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ last_page = (offset + length) >> PAGE_CACHE_SHIFT;
+
+ first_page_offset = first_page << PAGE_CACHE_SHIFT;
+ last_page_offset = last_page << PAGE_CACHE_SHIFT;
+
+ /* Now release the pages */
+ if (last_page_offset > first_page_offset) {
+ truncate_pagecache_range(inode, first_page_offset,
+ last_page_offset - 1);
+ }
+
+ /* Wait all existing dio workers, newcomers will block on i_mutex */
+ ext4_inode_block_unlocked_dio(inode);
+ ret = ext4_flush_unwritten_io(inode);
+ if (ret)
+ goto out_dio;
+ inode_dio_wait(inode);
+
+ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+ credits = ext4_writepage_trans_blocks(inode);
+ else
+ credits = ext4_blocks_for_truncate(inode);
+ handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ ext4_std_error(sb, ret);
+ goto out_dio;
+ }
+
+ /*
+ * Now we need to zero out the non-page-aligned data in the
+ * pages at the start and tail of the hole, and unmap the
+ * buffer heads for the block aligned regions of the page that
+ * were completely zeroed.
+ */
+ if (first_page > last_page) {
+ /*
+ * If the file space being truncated is contained
+ * within a page just zero out and unmap the middle of
+ * that page
+ */
+ ret = ext4_discard_partial_page_buffers(handle,
+ mapping, offset, length, 0);
+
+ if (ret)
+ goto out_stop;
+ } else {
+ /*
+ * zero out and unmap the partial page that contains
+ * the start of the hole
+ */
+ page_len = first_page_offset - offset;
+ if (page_len > 0) {
+ ret = ext4_discard_partial_page_buffers(handle, mapping,
+ offset, page_len, 0);
+ if (ret)
+ goto out_stop;
+ }
+
+ /*
+ * zero out and unmap the partial page that contains
+ * the end of the hole
+ */
+ page_len = offset + length - last_page_offset;
+ if (page_len > 0) {
+ ret = ext4_discard_partial_page_buffers(handle, mapping,
+ last_page_offset, page_len, 0);
+ if (ret)
+ goto out_stop;
+ }
+ }
+
+ /*
+ * If i_size is contained in the last page, we need to
+ * unmap and zero the partial page after i_size
+ */
+ if (inode->i_size >> PAGE_CACHE_SHIFT == last_page &&
+ inode->i_size % PAGE_CACHE_SIZE != 0) {
+ page_len = PAGE_CACHE_SIZE -
+ (inode->i_size & (PAGE_CACHE_SIZE - 1));
+
+ if (page_len > 0) {
+ ret = ext4_discard_partial_page_buffers(handle,
+ mapping, inode->i_size, page_len, 0);
+
+ if (ret)
+ goto out_stop;
+ }
+ }
+
+ first_block = (offset + sb->s_blocksize - 1) >>
+ EXT4_BLOCK_SIZE_BITS(sb);
+ stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb);
+
+ /* If there are no blocks to remove, return now */
+ if (first_block >= stop_block)
+ goto out_stop;
+
+ down_write(&EXT4_I(inode)->i_data_sem);
+ ext4_discard_preallocations(inode);
+
+ ret = ext4_es_remove_extent(inode, first_block,
+ stop_block - first_block);
+ if (ret) {
+ up_write(&EXT4_I(inode)->i_data_sem);
+ goto out_stop;
+ }
+
+ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+ ret = ext4_ext_remove_space(inode, first_block,
+ stop_block - 1);
+ else
+ ret = ext4_free_hole_blocks(handle, inode, first_block,
+ stop_block);
+
+ ext4_discard_preallocations(inode);
+ up_write(&EXT4_I(inode)->i_data_sem);
+ if (IS_SYNC(inode))
+ ext4_handle_sync(handle);
+ inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
+out_stop:
+ ext4_journal_stop(handle);
+out_dio:
+ ext4_inode_resume_unlocked_dio(inode);
+out_mutex:
+ mutex_unlock(&inode->i_mutex);
+ return ret;
}
/*
@@ -3692,6 +3807,19 @@ int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
*/
void ext4_truncate(struct inode *inode)
{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned int credits;
+ handle_t *handle;
+ struct address_space *mapping = inode->i_mapping;
+ loff_t page_len;
+
+ /*
+ * There is a possibility that we're either freeing the inode
+ * or it completely new indode. In those cases we might not
+ * have i_mutex locked because it's not necessary.
+ */
+ if (!(inode->i_state & (I_NEW|I_FREEING)))
+ WARN_ON(!mutex_is_locked(&inode->i_mutex));
trace_ext4_truncate_enter(inode);
if (!ext4_can_truncate(inode))
@@ -3710,10 +3838,72 @@ void ext4_truncate(struct inode *inode)
return;
}
+ /*
+ * finish any pending end_io work so we won't run the risk of
+ * converting any truncated blocks to initialized later
+ */
+ ext4_flush_unwritten_io(inode);
+
+ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+ credits = ext4_writepage_trans_blocks(inode);
+ else
+ credits = ext4_blocks_for_truncate(inode);
+
+ handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
+ if (IS_ERR(handle)) {
+ ext4_std_error(inode->i_sb, PTR_ERR(handle));
+ return;
+ }
+
+ if (inode->i_size % PAGE_CACHE_SIZE != 0) {
+ page_len = PAGE_CACHE_SIZE -
+ (inode->i_size & (PAGE_CACHE_SIZE - 1));
+
+ if (ext4_discard_partial_page_buffers(handle,
+ mapping, inode->i_size, page_len, 0))
+ goto out_stop;
+ }
+
+ /*
+ * We add the inode to the orphan list, so that if this
+ * truncate spans multiple transactions, and we crash, we will
+ * resume the truncate when the filesystem recovers. It also
+ * marks the inode dirty, to catch the new size.
+ *
+ * Implication: the file must always be in a sane, consistent
+ * truncatable state while each transaction commits.
+ */
+ if (ext4_orphan_add(handle, inode))
+ goto out_stop;
+
+ down_write(&EXT4_I(inode)->i_data_sem);
+
+ ext4_discard_preallocations(inode);
+
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
- ext4_ext_truncate(inode);
+ ext4_ext_truncate(handle, inode);
else
- ext4_ind_truncate(inode);
+ ext4_ind_truncate(handle, inode);
+
+ up_write(&ei->i_data_sem);
+
+ if (IS_SYNC(inode))
+ ext4_handle_sync(handle);
+
+out_stop:
+ /*
+ * If this was a simple ftruncate() and the file will remain alive,
+ * then we need to clear up the orphan record which we created above.
+ * However, if this was a real unlink then we were called by
+ * ext4_delete_inode(), and we allow that function to clean up the
+ * orphan info for us.
+ */
+ if (inode->i_nlink)
+ ext4_orphan_del(handle, inode);
+
+ inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
+ ext4_journal_stop(handle);
trace_ext4_truncate_exit(inode);
}
@@ -3821,13 +4011,14 @@ make_io:
if (EXT4_SB(sb)->s_inode_readahead_blks) {
ext4_fsblk_t b, end, table;
unsigned num;
+ __u32 ra_blks = EXT4_SB(sb)->s_inode_readahead_blks;
table = ext4_inode_table(sb, gdp);
/* s_inode_readahead_blks is always a power of 2 */
- b = block & ~(EXT4_SB(sb)->s_inode_readahead_blks-1);
+ b = block & ~((ext4_fsblk_t) ra_blks - 1);
if (table > b)
b = table;
- end = b + EXT4_SB(sb)->s_inode_readahead_blks;
+ end = b + ra_blks;
num = EXT4_INODES_PER_GROUP(sb);
if (ext4_has_group_desc_csum(sb))
num -= ext4_itable_unused_count(sb, gdp);
@@ -4024,8 +4215,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
* NeilBrown 1999oct15
*/
if (inode->i_nlink == 0) {
- if (inode->i_mode == 0 ||
- !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
+ if ((inode->i_mode == 0 ||
+ !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) &&
+ ino != EXT4_BOOT_LOADER_INO) {
/* this inode is deleted */
ret = -ESTALE;
goto bad_inode;
@@ -4033,7 +4225,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
/* The only unlinked inodes we let through here have
* valid i_mode and are being read by the orphan
* recovery code: that's fine, we're about to complete
- * the process of deleting those. */
+ * the process of deleting those.
+ * OR it is the EXT4_BOOT_LOADER_INO which is
+ * not initialized on a new filesystem. */
}
ei->i_flags = le32_to_cpu(raw_inode->i_flags);
inode->i_blocks = ext4_inode_blocks(raw_inode, ei);
@@ -4153,6 +4347,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
else
init_special_inode(inode, inode->i_mode,
new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
+ } else if (ino == EXT4_BOOT_LOADER_INO) {
+ make_bad_inode(inode);
} else {
ret = -EIO;
EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 721f4d33e148..9491ac0590f7 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -17,9 +17,201 @@
#include <asm/uaccess.h>
#include "ext4_jbd2.h"
#include "ext4.h"
+#include "ext4_extents.h"
#define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1)
+/**
+ * Swap memory between @a and @b for @len bytes.
+ *
+ * @a: pointer to first memory area
+ * @b: pointer to second memory area
+ * @len: number of bytes to swap
+ *
+ */
+static void memswap(void *a, void *b, size_t len)
+{
+ unsigned char *ap, *bp;
+ unsigned char tmp;
+
+ ap = (unsigned char *)a;
+ bp = (unsigned char *)b;
+ while (len-- > 0) {
+ tmp = *ap;
+ *ap = *bp;
+ *bp = tmp;
+ ap++;
+ bp++;
+ }
+}
+
+/**
+ * Swap i_data and associated attributes between @inode1 and @inode2.
+ * This function is used for the primary swap between inode1 and inode2
+ * and also to revert this primary swap in case of errors.
+ *
+ * Therefore you have to make sure, that calling this method twice
+ * will revert all changes.
+ *
+ * @inode1: pointer to first inode
+ * @inode2: pointer to second inode
+ */
+static void swap_inode_data(struct inode *inode1, struct inode *inode2)
+{
+ loff_t isize;
+ struct ext4_inode_info *ei1;
+ struct ext4_inode_info *ei2;
+
+ ei1 = EXT4_I(inode1);
+ ei2 = EXT4_I(inode2);
+
+ memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags));
+ memswap(&inode1->i_version, &inode2->i_version,
+ sizeof(inode1->i_version));
+ memswap(&inode1->i_blocks, &inode2->i_blocks,
+ sizeof(inode1->i_blocks));
+ memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes));
+ memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime));
+ memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime));
+
+ memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
+ memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
+ memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
+ memswap(&ei1->i_es_tree, &ei2->i_es_tree, sizeof(ei1->i_es_tree));
+ memswap(&ei1->i_es_lru_nr, &ei2->i_es_lru_nr, sizeof(ei1->i_es_lru_nr));
+
+ isize = i_size_read(inode1);
+ i_size_write(inode1, i_size_read(inode2));
+ i_size_write(inode2, isize);
+}
+
+/**
+ * Swap the information from the given @inode and the inode
+ * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other
+ * important fields of the inodes.
+ *
+ * @sb: the super block of the filesystem
+ * @inode: the inode to swap with EXT4_BOOT_LOADER_INO
+ *
+ */
+static long swap_inode_boot_loader(struct super_block *sb,
+ struct inode *inode)
+{
+ handle_t *handle;
+ int err;
+ struct inode *inode_bl;
+ struct ext4_inode_info *ei;
+ struct ext4_inode_info *ei_bl;
+ struct ext4_sb_info *sbi;
+
+ if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) {
+ err = -EINVAL;
+ goto swap_boot_out;
+ }
+
+ if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto swap_boot_out;
+ }
+
+ sbi = EXT4_SB(sb);
+ ei = EXT4_I(inode);
+
+ inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
+ if (IS_ERR(inode_bl)) {
+ err = PTR_ERR(inode_bl);
+ goto swap_boot_out;
+ }
+ ei_bl = EXT4_I(inode_bl);
+
+ filemap_flush(inode->i_mapping);
+ filemap_flush(inode_bl->i_mapping);
+
+ /* Protect orig inodes against a truncate and make sure,
+ * that only 1 swap_inode_boot_loader is running. */
+ ext4_inode_double_lock(inode, inode_bl);
+
+ truncate_inode_pages(&inode->i_data, 0);
+ truncate_inode_pages(&inode_bl->i_data, 0);
+
+ /* Wait for all existing dio workers */
+ ext4_inode_block_unlocked_dio(inode);
+ ext4_inode_block_unlocked_dio(inode_bl);
+ inode_dio_wait(inode);
+ inode_dio_wait(inode_bl);
+
+ handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
+ if (IS_ERR(handle)) {
+ err = -EINVAL;
+ goto swap_boot_out;
+ }
+
+ /* Protect extent tree against block allocations via delalloc */
+ ext4_double_down_write_data_sem(inode, inode_bl);
+
+ if (inode_bl->i_nlink == 0) {
+ /* this inode has never been used as a BOOT_LOADER */
+ set_nlink(inode_bl, 1);
+ i_uid_write(inode_bl, 0);
+ i_gid_write(inode_bl, 0);
+ inode_bl->i_flags = 0;
+ ei_bl->i_flags = 0;
+ 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)) {
+ ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS);
+ ext4_ext_tree_init(handle, inode_bl);
+ } else
+ memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
+ }
+
+ swap_inode_data(inode, inode_bl);
+
+ inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode);
+
+ spin_lock(&sbi->s_next_gen_lock);
+ inode->i_generation = sbi->s_next_generation++;
+ inode_bl->i_generation = sbi->s_next_generation++;
+ spin_unlock(&sbi->s_next_gen_lock);
+
+ ext4_discard_preallocations(inode);
+
+ err = ext4_mark_inode_dirty(handle, inode);
+ if (err < 0) {
+ ext4_warning(inode->i_sb,
+ "couldn't mark inode #%lu dirty (err %d)",
+ inode->i_ino, err);
+ /* Revert all changes: */
+ swap_inode_data(inode, inode_bl);
+ } else {
+ err = ext4_mark_inode_dirty(handle, inode_bl);
+ if (err < 0) {
+ ext4_warning(inode_bl->i_sb,
+ "couldn't mark inode #%lu dirty (err %d)",
+ inode_bl->i_ino, err);
+ /* Revert all changes: */
+ swap_inode_data(inode, inode_bl);
+ ext4_mark_inode_dirty(handle, inode);
+ }
+ }
+
+ ext4_journal_stop(handle);
+
+ ext4_double_up_write_data_sem(inode, inode_bl);
+
+ ext4_inode_resume_unlocked_dio(inode);
+ ext4_inode_resume_unlocked_dio(inode_bl);
+
+ ext4_inode_double_unlock(inode, inode_bl);
+
+ iput(inode_bl);
+
+swap_boot_out:
+ return err;
+}
+
long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file_inode(filp);
@@ -83,17 +275,8 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!capable(CAP_SYS_RESOURCE))
goto flags_out;
}
- if (oldflags & EXT4_EXTENTS_FL) {
- /* We don't support clearning extent flags */
- if (!(flags & EXT4_EXTENTS_FL)) {
- err = -EOPNOTSUPP;
- goto flags_out;
- }
- } else if (flags & EXT4_EXTENTS_FL) {
- /* migrate the file */
+ if ((flags ^ oldflags) & EXT4_EXTENTS_FL)
migrate = 1;
- flags &= ~EXT4_EXTENTS_FL;
- }
if (flags & EXT4_EOFBLOCKS_FL) {
/* we don't support adding EOFBLOCKS flag */
@@ -137,8 +320,13 @@ flags_err:
err = ext4_change_inode_journal_flag(inode, jflag);
if (err)
goto flags_out;
- if (migrate)
- err = ext4_ext_migrate(inode);
+ if (migrate) {
+ if (flags & EXT4_EXTENTS_FL)
+ err = ext4_ext_migrate(inode);
+ else
+ err = ext4_ind_migrate(inode);
+ }
+
flags_out:
mutex_unlock(&inode->i_mutex);
mnt_drop_write_file(filp);
@@ -357,9 +545,13 @@ group_add_out:
return err;
}
+ case EXT4_IOC_SWAP_BOOT:
+ if (!(filp->f_mode & FMODE_WRITE))
+ return -EBADF;
+ return swap_inode_boot_loader(sb, inode);
+
case EXT4_IOC_RESIZE_FS: {
ext4_fsblk_t n_blocks_count;
- struct super_block *sb = inode->i_sb;
int err = 0, err2 = 0;
ext4_group_t o_group = EXT4_SB(sb)->s_groups_count;
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 28e421c208a5..b1ed9e07434b 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -405,6 +405,12 @@ static inline void mb_clear_bit(int bit, void *addr)
ext4_clear_bit(bit, addr);
}
+static inline int mb_test_and_clear_bit(int bit, void *addr)
+{
+ addr = mb_correct_addr_and_bit(&bit, addr);
+ return ext4_test_and_clear_bit(bit, addr);
+}
+
static inline int mb_find_next_zero_bit(void *addr, int max, int start)
{
int fix = 0, ret, tmpmax;
@@ -764,6 +770,24 @@ void ext4_mb_generate_buddy(struct super_block *sb,
spin_unlock(&EXT4_SB(sb)->s_bal_lock);
}
+static void mb_regenerate_buddy(struct ext4_buddy *e4b)
+{
+ int count;
+ int order = 1;
+ void *buddy;
+
+ while ((buddy = mb_find_buddy(e4b, order++, &count))) {
+ ext4_set_bits(buddy, 0, count);
+ }
+ e4b->bd_info->bb_fragments = 0;
+ memset(e4b->bd_info->bb_counters, 0,
+ sizeof(*e4b->bd_info->bb_counters) *
+ (e4b->bd_sb->s_blocksize_bits + 2));
+
+ ext4_mb_generate_buddy(e4b->bd_sb, e4b->bd_buddy,
+ e4b->bd_bitmap, e4b->bd_group);
+}
+
/* The buddy information is attached the buddy cache inode
* for convenience. The information regarding each group
* is loaded via ext4_mb_load_buddy. The information involve
@@ -860,8 +884,6 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
first_block = page->index * blocks_per_page;
for (i = 0; i < blocks_per_page; i++) {
- int group;
-
group = (first_block + i) >> 1;
if (group >= ngroups)
break;
@@ -1011,6 +1033,7 @@ int ext4_mb_init_group(struct super_block *sb, ext4_group_t group)
struct page *page;
int ret = 0;
+ might_sleep();
mb_debug(1, "init group %u\n", group);
this_grp = ext4_get_group_info(sb, group);
/*
@@ -1082,6 +1105,7 @@ ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct inode *inode = sbi->s_buddy_cache;
+ might_sleep();
mb_debug(1, "load group %u\n", group);
blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
@@ -1244,6 +1268,33 @@ static void mb_clear_bits(void *bm, int cur, int len)
}
}
+/* clear bits in given range
+ * will return first found zero bit if any, -1 otherwise
+ */
+static int mb_test_and_clear_bits(void *bm, int cur, int len)
+{
+ __u32 *addr;
+ int zero_bit = -1;
+
+ len = cur + len;
+ while (cur < len) {
+ if ((cur & 31) == 0 && (len - cur) >= 32) {
+ /* fast path: clear whole word at once */
+ addr = bm + (cur >> 3);
+ if (*addr != (__u32)(-1) && zero_bit == -1)
+ zero_bit = cur + mb_find_next_zero_bit(addr, 32, 0);
+ *addr = 0;
+ cur += 32;
+ continue;
+ }
+ if (!mb_test_and_clear_bit(cur, bm) && zero_bit == -1)
+ zero_bit = cur;
+ cur++;
+ }
+
+ return zero_bit;
+}
+
void ext4_set_bits(void *bm, int cur, int len)
{
__u32 *addr;
@@ -1262,17 +1313,90 @@ void ext4_set_bits(void *bm, int cur, int len)
}
}
+/*
+ * _________________________________________________________________ */
+
+static inline int mb_buddy_adjust_border(int* bit, void* bitmap, int side)
+{
+ if (mb_test_bit(*bit + side, bitmap)) {
+ mb_clear_bit(*bit, bitmap);
+ (*bit) -= side;
+ return 1;
+ }
+ else {
+ (*bit) += side;
+ mb_set_bit(*bit, bitmap);
+ return -1;
+ }
+}
+
+static void mb_buddy_mark_free(struct ext4_buddy *e4b, int first, int last)
+{
+ int max;
+ int order = 1;
+ void *buddy = mb_find_buddy(e4b, order, &max);
+
+ while (buddy) {
+ void *buddy2;
+
+ /* Bits in range [first; last] are known to be set since
+ * corresponding blocks were allocated. Bits in range
+ * (first; last) will stay set because they form buddies on
+ * upper layer. We just deal with borders if they don't
+ * align with upper layer and then go up.
+ * Releasing entire group is all about clearing
+ * single bit of highest order buddy.
+ */
+
+ /* Example:
+ * ---------------------------------
+ * | 1 | 1 | 1 | 1 |
+ * ---------------------------------
+ * | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+ * ---------------------------------
+ * 0 1 2 3 4 5 6 7
+ * \_____________________/
+ *
+ * Neither [1] nor [6] is aligned to above layer.
+ * Left neighbour [0] is free, so mark it busy,
+ * decrease bb_counters and extend range to
+ * [0; 6]
+ * Right neighbour [7] is busy. It can't be coaleasced with [6], so
+ * mark [6] free, increase bb_counters and shrink range to
+ * [0; 5].
+ * Then shift range to [0; 2], go up and do the same.
+ */
+
+
+ if (first & 1)
+ e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&first, buddy, -1);
+ if (!(last & 1))
+ e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&last, buddy, 1);
+ if (first > last)
+ break;
+ order++;
+
+ if (first == last || !(buddy2 = mb_find_buddy(e4b, order, &max))) {
+ mb_clear_bits(buddy, first, last - first + 1);
+ e4b->bd_info->bb_counters[order - 1] += last - first + 1;
+ break;
+ }
+ first >>= 1;
+ last >>= 1;
+ buddy = buddy2;
+ }
+}
+
static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
- int first, int count)
+ int first, int count)
{
- int block = 0;
- int max = 0;
- int order;
- void *buddy;
- void *buddy2;
+ int left_is_free = 0;
+ int right_is_free = 0;
+ int block;
+ int last = first + count - 1;
struct super_block *sb = e4b->bd_sb;
- BUG_ON(first + count > (sb->s_blocksize << 3));
+ BUG_ON(last >= (sb->s_blocksize << 3));
assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
mb_check_buddy(e4b);
mb_free_blocks_double(inode, e4b, first, count);
@@ -1281,67 +1405,54 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
if (first < e4b->bd_info->bb_first_free)
e4b->bd_info->bb_first_free = first;
- /* let's maintain fragments counter */
+ /* access memory sequentially: check left neighbour,
+ * clear range and then check right neighbour
+ */
if (first != 0)
- block = !mb_test_bit(first - 1, e4b->bd_bitmap);
- if (first + count < EXT4_SB(sb)->s_mb_maxs[0])
- max = !mb_test_bit(first + count, e4b->bd_bitmap);
- if (block && max)
- e4b->bd_info->bb_fragments--;
- else if (!block && !max)
- e4b->bd_info->bb_fragments++;
+ left_is_free = !mb_test_bit(first - 1, e4b->bd_bitmap);
+ block = mb_test_and_clear_bits(e4b->bd_bitmap, first, count);
+ if (last + 1 < EXT4_SB(sb)->s_mb_maxs[0])
+ right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap);
- /* let's maintain buddy itself */
- while (count-- > 0) {
- block = first++;
- order = 0;
+ if (unlikely(block != -1)) {
+ ext4_fsblk_t blocknr;
- if (!mb_test_bit(block, e4b->bd_bitmap)) {
- ext4_fsblk_t blocknr;
-
- blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
- blocknr += EXT4_C2B(EXT4_SB(sb), block);
- ext4_grp_locked_error(sb, e4b->bd_group,
- inode ? inode->i_ino : 0,
- blocknr,
- "freeing already freed block "
- "(bit %u)", block);
- }
- mb_clear_bit(block, e4b->bd_bitmap);
- e4b->bd_info->bb_counters[order]++;
-
- /* start of the buddy */
- buddy = mb_find_buddy(e4b, order, &max);
-
- do {
- block &= ~1UL;
- if (mb_test_bit(block, buddy) ||
- mb_test_bit(block + 1, buddy))
- break;
-
- /* both the buddies are free, try to coalesce them */
- buddy2 = mb_find_buddy(e4b, order + 1, &max);
+ blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
+ blocknr += EXT4_C2B(EXT4_SB(sb), block);
+ ext4_grp_locked_error(sb, e4b->bd_group,
+ inode ? inode->i_ino : 0,
+ blocknr,
+ "freeing already freed block "
+ "(bit %u)", block);
+ mb_regenerate_buddy(e4b);
+ goto done;
+ }
- if (!buddy2)
- break;
+ /* let's maintain fragments counter */
+ if (left_is_free && right_is_free)
+ e4b->bd_info->bb_fragments--;
+ else if (!left_is_free && !right_is_free)
+ e4b->bd_info->bb_fragments++;
- if (order > 0) {
- /* for special purposes, we don't set
- * free bits in bitmap */
- mb_set_bit(block, buddy);
- mb_set_bit(block + 1, buddy);
- }
- e4b->bd_info->bb_counters[order]--;
- e4b->bd_info->bb_counters[order]--;
+ /* buddy[0] == bd_bitmap is a special case, so handle
+ * it right away and let mb_buddy_mark_free stay free of
+ * zero order checks.
+ * Check if neighbours are to be coaleasced,
+ * adjust bitmap bb_counters and borders appropriately.
+ */
+ if (first & 1) {
+ first += !left_is_free;
+ e4b->bd_info->bb_counters[0] += left_is_free ? -1 : 1;
+ }
+ if (!(last & 1)) {
+ last -= !right_is_free;
+ e4b->bd_info->bb_counters[0] += right_is_free ? -1 : 1;
+ }
- block = block >> 1;
- order++;
- e4b->bd_info->bb_counters[order]++;
+ if (first <= last)
+ mb_buddy_mark_free(e4b, first >> 1, last >> 1);
- mb_clear_bit(block, buddy2);
- buddy = buddy2;
- } while (1);
- }
+done:
mb_set_largest_free_order(sb, e4b->bd_info);
mb_check_buddy(e4b);
}
@@ -3342,7 +3453,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
if (pa->pa_type == MB_GROUP_PA)
grp_blk--;
- ext4_get_group_no_and_offset(sb, grp_blk, &grp, NULL);
+ grp = ext4_get_group_number(sb, grp_blk);
/*
* possible race:
@@ -3807,7 +3918,7 @@ repeat:
list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
BUG_ON(pa->pa_type != MB_INODE_PA);
- ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+ group = ext4_get_group_number(sb, pa->pa_pstart);
err = ext4_mb_load_buddy(sb, group, &e4b);
if (err) {
@@ -4069,7 +4180,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
- ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
+ group = ext4_get_group_number(sb, pa->pa_pstart);
if (ext4_mb_load_buddy(sb, group, &e4b)) {
ext4_error(sb, "Error loading buddy information for %u",
group);
@@ -4217,6 +4328,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
unsigned int inquota = 0;
unsigned int reserv_clstrs = 0;
+ might_sleep();
sb = ar->inode->i_sb;
sbi = EXT4_SB(sb);
@@ -4420,11 +4532,11 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
node = rb_prev(new_node);
if (node) {
entry = rb_entry(node, struct ext4_free_data, efd_node);
- if (can_merge(entry, new_entry)) {
+ if (can_merge(entry, new_entry) &&
+ ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
new_entry->efd_start_cluster = entry->efd_start_cluster;
new_entry->efd_count += entry->efd_count;
rb_erase(node, &(db->bb_free_root));
- ext4_journal_callback_del(handle, &entry->efd_jce);
kmem_cache_free(ext4_free_data_cachep, entry);
}
}
@@ -4432,10 +4544,10 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
node = rb_next(new_node);
if (node) {
entry = rb_entry(node, struct ext4_free_data, efd_node);
- if (can_merge(new_entry, entry)) {
+ if (can_merge(new_entry, entry) &&
+ ext4_journal_callback_try_del(handle, &entry->efd_jce)) {
new_entry->efd_count += entry->efd_count;
rb_erase(node, &(db->bb_free_root));
- ext4_journal_callback_del(handle, &entry->efd_jce);
kmem_cache_free(ext4_free_data_cachep, entry);
}
}
@@ -4470,6 +4582,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
int err = 0;
int ret;
+ might_sleep();
if (bh) {
if (block)
BUG_ON(block != bh->b_blocknr);
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 480acf4a085f..49e8bdff9163 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -426,7 +426,6 @@ static int free_ext_block(handle_t *handle, struct inode *inode)
return retval;
}
return retval;
-
}
int ext4_ext_migrate(struct inode *inode)
@@ -606,3 +605,64 @@ out:
return retval;
}
+
+/*
+ * Migrate a simple extent-based inode to use the i_blocks[] array
+ */
+int ext4_ind_migrate(struct inode *inode)
+{
+ struct ext4_extent_header *eh;
+ struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_extent *ex;
+ unsigned int i, len;
+ ext4_fsblk_t blk;
+ handle_t *handle;
+ int ret;
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_INCOMPAT_EXTENTS) ||
+ (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
+ return -EINVAL;
+
+ if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+ return -EOPNOTSUPP;
+
+ handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ down_write(&EXT4_I(inode)->i_data_sem);
+ ret = ext4_ext_check_inode(inode);
+ if (ret)
+ goto errout;
+
+ eh = ext_inode_hdr(inode);
+ ex = EXT_FIRST_EXTENT(eh);
+ if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS ||
+ eh->eh_depth != 0 || le16_to_cpu(eh->eh_entries) > 1) {
+ ret = -EOPNOTSUPP;
+ goto errout;
+ }
+ if (eh->eh_entries == 0)
+ blk = len = 0;
+ else {
+ len = le16_to_cpu(ex->ee_len);
+ blk = ext4_ext_pblock(ex);
+ if (len > EXT4_NDIR_BLOCKS) {
+ ret = -EOPNOTSUPP;
+ goto errout;
+ }
+ }
+
+ ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
+ memset(ei->i_data, 0, sizeof(ei->i_data));
+ for (i=0; i < len; i++)
+ ei->i_data[i] = cpu_to_le32(blk++);
+ ext4_mark_inode_dirty(handle, inode);
+errout:
+ ext4_journal_stop(handle);
+ up_write(&EXT4_I(inode)->i_data_sem);
+ return ret;
+}
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c
index f9b551561d2c..214461e42a05 100644
--- a/fs/ext4/mmp.c
+++ b/fs/ext4/mmp.c
@@ -7,7 +7,7 @@
#include "ext4.h"
/* Checksumming functions */
-static __u32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
+static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
int offset = offsetof(struct mmp_struct, mmp_checksum);
@@ -54,7 +54,7 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh)
lock_buffer(bh);
bh->b_end_io = end_buffer_write_sync;
get_bh(bh);
- submit_bh(WRITE_SYNC, bh);
+ submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
wait_on_buffer(bh);
sb_end_write(sb);
if (unlikely(!buffer_uptodate(bh)))
@@ -86,7 +86,7 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh,
get_bh(*bh);
lock_buffer(*bh);
(*bh)->b_end_io = end_buffer_read_sync;
- submit_bh(READ_SYNC, *bh);
+ submit_bh(READ_SYNC | REQ_META | REQ_PRIO, *bh);
wait_on_buffer(*bh);
if (!buffer_uptodate(*bh)) {
brelse(*bh);
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 33e1c086858b..3dcbf364022f 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -144,12 +144,13 @@ mext_next_extent(struct inode *inode, struct ext4_ext_path *path,
}
/**
- * double_down_write_data_sem - Acquire two inodes' write lock of i_data_sem
+ * ext4_double_down_write_data_sem - Acquire two inodes' write lock
+ * of i_data_sem
*
* Acquire write lock of i_data_sem of the two inodes
*/
-static void
-double_down_write_data_sem(struct inode *first, struct inode *second)
+void
+ext4_double_down_write_data_sem(struct inode *first, struct inode *second)
{
if (first < second) {
down_write(&EXT4_I(first)->i_data_sem);
@@ -162,14 +163,15 @@ double_down_write_data_sem(struct inode *first, struct inode *second)
}
/**
- * double_up_write_data_sem - Release two inodes' write lock of i_data_sem
+ * ext4_double_up_write_data_sem - Release two inodes' write lock of i_data_sem
*
* @orig_inode: original inode structure to be released its lock first
* @donor_inode: donor inode structure to be released its lock second
* Release write lock of i_data_sem of two inodes (orig and donor).
*/
-static void
-double_up_write_data_sem(struct inode *orig_inode, struct inode *donor_inode)
+void
+ext4_double_up_write_data_sem(struct inode *orig_inode,
+ struct inode *donor_inode)
{
up_write(&EXT4_I(orig_inode)->i_data_sem);
up_write(&EXT4_I(donor_inode)->i_data_sem);
@@ -407,18 +409,7 @@ mext_insert_extents(handle_t *handle, struct inode *orig_inode,
mext_insert_inside_block(o_start, o_end, start_ext, new_ext,
end_ext, eh, range_to_move);
- if (depth) {
- ret = ext4_handle_dirty_metadata(handle, orig_inode,
- orig_path->p_bh);
- if (ret)
- return ret;
- } else {
- ret = ext4_mark_inode_dirty(handle, orig_inode);
- if (ret < 0)
- return ret;
- }
-
- return 0;
+ return ext4_ext_dirty(handle, orig_inode, orig_path);
}
/**
@@ -737,6 +728,7 @@ mext_replace_branches(handle_t *handle, struct inode *orig_inode,
donor_off += dext_alen;
orig_off += dext_alen;
+ BUG_ON(replaced_count > count);
/* Already moved the expected blocks */
if (replaced_count >= count)
break;
@@ -814,7 +806,13 @@ mext_page_double_lock(struct inode *inode1, struct inode *inode2,
page_cache_release(page[0]);
return -ENOMEM;
}
-
+ /*
+ * grab_cache_page_write_begin() may not wait on page's writeback if
+ * BDI not demand that. But it is reasonable to be very conservative
+ * here and explicitly wait on page's writeback
+ */
+ wait_on_page_writeback(page[0]);
+ wait_on_page_writeback(page[1]);
if (inode1 > inode2) {
struct page *tmp;
tmp = page[0];
@@ -856,7 +854,6 @@ mext_page_mkuptodate(struct page *page, unsigned from, unsigned to)
if (buffer_uptodate(bh))
continue;
if (!buffer_mapped(bh)) {
- int err = 0;
err = ext4_get_block(inode, block, bh, 0);
if (err) {
SetPageError(page);
@@ -976,7 +973,7 @@ again:
* necessary, just swap data blocks between orig and donor.
*/
if (uninit) {
- double_down_write_data_sem(orig_inode, donor_inode);
+ ext4_double_down_write_data_sem(orig_inode, donor_inode);
/* If any of extents in range became initialized we have to
* fallback to data copying */
uninit = mext_check_coverage(orig_inode, orig_blk_offset,
@@ -990,7 +987,7 @@ again:
goto drop_data_sem;
if (!uninit) {
- double_up_write_data_sem(orig_inode, donor_inode);
+ ext4_double_up_write_data_sem(orig_inode, donor_inode);
goto data_copy;
}
if ((page_has_private(pagep[0]) &&
@@ -1004,7 +1001,7 @@ again:
donor_inode, orig_blk_offset,
block_len_in_page, err);
drop_data_sem:
- double_up_write_data_sem(orig_inode, donor_inode);
+ ext4_double_up_write_data_sem(orig_inode, donor_inode);
goto unlock_pages;
}
data_copy:
@@ -1033,7 +1030,7 @@ data_copy:
}
/* Perform all necessary steps similar write_begin()/write_end()
* but keeping in mind that i_size will not change */
- *err = __block_write_begin(pagep[0], from, from + replaced_size,
+ *err = __block_write_begin(pagep[0], from, replaced_size,
ext4_get_block);
if (!*err)
*err = block_commit_write(pagep[0], from, from + replaced_size);
@@ -1065,11 +1062,11 @@ repair_branches:
* Extents are swapped already, but we are not able to copy data.
* Try to swap extents to it's original places
*/
- double_down_write_data_sem(orig_inode, donor_inode);
+ ext4_double_down_write_data_sem(orig_inode, donor_inode);
replaced_count = mext_replace_branches(handle, donor_inode, orig_inode,
orig_blk_offset,
block_len_in_page, &err2);
- double_up_write_data_sem(orig_inode, donor_inode);
+ ext4_double_up_write_data_sem(orig_inode, donor_inode);
if (replaced_count != block_len_in_page) {
EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset),
"Unable to copy data block,"
@@ -1209,15 +1206,15 @@ mext_check_arguments(struct inode *orig_inode,
}
/**
- * mext_inode_double_lock - Lock i_mutex on both @inode1 and @inode2
+ * ext4_inode_double_lock - Lock i_mutex on both @inode1 and @inode2
*
* @inode1: the inode structure
* @inode2: the inode structure
*
* Lock two inodes' i_mutex
*/
-static void
-mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
+void
+ext4_inode_double_lock(struct inode *inode1, struct inode *inode2)
{
BUG_ON(inode1 == inode2);
if (inode1 < inode2) {
@@ -1230,15 +1227,15 @@ mext_inode_double_lock(struct inode *inode1, struct inode *inode2)
}
/**
- * mext_inode_double_unlock - Release i_mutex on both @inode1 and @inode2
+ * ext4_inode_double_unlock - Release i_mutex on both @inode1 and @inode2
*
* @inode1: the inode that is released first
* @inode2: the inode that is released second
*
*/
-static void
-mext_inode_double_unlock(struct inode *inode1, struct inode *inode2)
+void
+ext4_inode_double_unlock(struct inode *inode1, struct inode *inode2)
{
mutex_unlock(&inode1->i_mutex);
mutex_unlock(&inode2->i_mutex);
@@ -1333,7 +1330,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
return -EINVAL;
}
/* Protect orig and donor inodes against a truncate */
- mext_inode_double_lock(orig_inode, donor_inode);
+ ext4_inode_double_lock(orig_inode, donor_inode);
/* Wait for all existing dio workers */
ext4_inode_block_unlocked_dio(orig_inode);
@@ -1342,7 +1339,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
inode_dio_wait(donor_inode);
/* Protect extent tree against block allocations via delalloc */
- double_down_write_data_sem(orig_inode, donor_inode);
+ ext4_double_down_write_data_sem(orig_inode, donor_inode);
/* Check the filesystem environment whether move_extent can be done */
ret = mext_check_arguments(orig_inode, donor_inode, orig_start,
donor_start, &len);
@@ -1466,7 +1463,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
* b. racing with ->readpage, ->write_begin, and ext4_get_block
* in move_extent_per_page
*/
- double_up_write_data_sem(orig_inode, donor_inode);
+ ext4_double_up_write_data_sem(orig_inode, donor_inode);
while (orig_page_offset <= seq_end_page) {
@@ -1500,7 +1497,7 @@ ext4_move_extents(struct file *o_filp, struct file *d_filp,
block_len_in_page = rest_blocks;
}
- double_down_write_data_sem(orig_inode, donor_inode);
+ ext4_double_down_write_data_sem(orig_inode, donor_inode);
if (ret < 0)
break;
@@ -1538,10 +1535,10 @@ out:
ext4_ext_drop_refs(holecheck_path);
kfree(holecheck_path);
}
- double_up_write_data_sem(orig_inode, donor_inode);
+ ext4_double_up_write_data_sem(orig_inode, donor_inode);
ext4_inode_resume_unlocked_dio(orig_inode);
ext4_inode_resume_unlocked_dio(donor_inode);
- mext_inode_double_unlock(orig_inode, donor_inode);
+ ext4_inode_double_unlock(orig_inode, donor_inode);
return ret;
}
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 3825d6aa8336..6653fc35ecb7 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -416,15 +416,16 @@ static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent,
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct ext4_inode_info *ei = EXT4_I(inode);
- __u32 csum, old_csum;
+ __u32 csum;
+ __le32 save_csum;
int size;
size = count_offset + (count * sizeof(struct dx_entry));
- old_csum = t->dt_checksum;
+ save_csum = t->dt_checksum;
t->dt_checksum = 0;
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail));
- t->dt_checksum = old_csum;
+ t->dt_checksum = save_csum;
return cpu_to_le32(csum);
}
@@ -971,6 +972,17 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
hinfo.hash_version +=
EXT4_SB(dir->i_sb)->s_hash_unsigned;
hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+ if (ext4_has_inline_data(dir)) {
+ int has_inline_data = 1;
+ count = htree_inlinedir_to_tree(dir_file, dir, 0,
+ &hinfo, start_hash,
+ start_minor_hash,
+ &has_inline_data);
+ if (has_inline_data) {
+ *next_hash = ~0;
+ return count;
+ }
+ }
count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
start_hash, start_minor_hash);
*next_hash = ~0;
@@ -1455,24 +1467,6 @@ struct dentry *ext4_get_parent(struct dentry *child)
return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino));
}
-#define S_SHIFT 12
-static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
- [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
- [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
- [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
- [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
- [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
- [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
- [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
-};
-
-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))
- de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
-}
-
/*
* Move count entries from end of map between two memory locations.
* Returns pointer to last entry moved.
@@ -2251,8 +2245,7 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
dquot_initialize(dir);
credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,
NULL, EXT4_HT_DIR, credits);
@@ -2286,8 +2279,7 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry,
dquot_initialize(dir);
credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,
NULL, EXT4_HT_DIR, credits);
@@ -2396,8 +2388,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
dquot_initialize(dir);
credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);
retry:
inode = ext4_new_inode_start_handle(dir, S_IFDIR | mode,
&dentry->d_name,
@@ -2826,8 +2817,7 @@ static int ext4_symlink(struct inode *dir,
* quota blocks, sb is already counted in previous macros).
*/
credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3;
}
retry:
inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO,
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 047a6de04a0a..5929cd0baa20 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -29,25 +29,19 @@
#include "xattr.h"
#include "acl.h"
-static struct kmem_cache *io_page_cachep, *io_end_cachep;
+static struct kmem_cache *io_end_cachep;
int __init ext4_init_pageio(void)
{
- io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
- if (io_page_cachep == NULL)
- return -ENOMEM;
io_end_cachep = KMEM_CACHE(ext4_io_end, SLAB_RECLAIM_ACCOUNT);
- if (io_end_cachep == NULL) {
- kmem_cache_destroy(io_page_cachep);
+ if (io_end_cachep == NULL)
return -ENOMEM;
- }
return 0;
}
void ext4_exit_pageio(void)
{
kmem_cache_destroy(io_end_cachep);
- kmem_cache_destroy(io_page_cachep);
}
/*
@@ -67,29 +61,28 @@ void ext4_ioend_shutdown(struct inode *inode)
cancel_work_sync(&EXT4_I(inode)->i_unwritten_work);
}
-static void put_io_page(struct ext4_io_page *io_page)
+static void ext4_release_io_end(ext4_io_end_t *io_end)
{
- if (atomic_dec_and_test(&io_page->p_count)) {
- end_page_writeback(io_page->p_page);
- put_page(io_page->p_page);
- kmem_cache_free(io_page_cachep, io_page);
- }
+ BUG_ON(!list_empty(&io_end->list));
+ BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN);
+
+ if (atomic_dec_and_test(&EXT4_I(io_end->inode)->i_ioend_count))
+ wake_up_all(ext4_ioend_wq(io_end->inode));
+ if (io_end->flag & EXT4_IO_END_DIRECT)
+ inode_dio_done(io_end->inode);
+ if (io_end->iocb)
+ aio_complete(io_end->iocb, io_end->result, 0);
+ kmem_cache_free(io_end_cachep, io_end);
}
-void ext4_free_io_end(ext4_io_end_t *io)
+static void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
{
- int i;
-
- BUG_ON(!io);
- BUG_ON(!list_empty(&io->list));
- BUG_ON(io->flag & EXT4_IO_END_UNWRITTEN);
+ struct inode *inode = io_end->inode;
- for (i = 0; i < io->num_io_pages; i++)
- put_io_page(io->pages[i]);
- io->num_io_pages = 0;
- if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count))
- wake_up_all(ext4_ioend_wq(io->inode));
- kmem_cache_free(io_end_cachep, io);
+ io_end->flag &= ~EXT4_IO_END_UNWRITTEN;
+ /* Wake up anyone waiting on unwritten extent conversion */
+ if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
+ wake_up_all(ext4_ioend_wq(inode));
}
/* check a range of space and convert unwritten extents to written. */
@@ -112,13 +105,8 @@ static int ext4_end_io(ext4_io_end_t *io)
"(inode %lu, offset %llu, size %zd, error %d)",
inode->i_ino, offset, size, ret);
}
- /* Wake up anyone waiting on unwritten extent conversion */
- if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
- wake_up_all(ext4_ioend_wq(inode));
- if (io->flag & EXT4_IO_END_DIRECT)
- inode_dio_done(inode);
- if (io->iocb)
- aio_complete(io->iocb, io->result, 0);
+ ext4_clear_io_unwritten_flag(io);
+ ext4_release_io_end(io);
return ret;
}
@@ -149,7 +137,7 @@ static void dump_completed_IO(struct inode *inode)
}
/* Add the io_end to per-inode completed end_io list. */
-void ext4_add_complete_io(ext4_io_end_t *io_end)
+static void ext4_add_complete_io(ext4_io_end_t *io_end)
{
struct ext4_inode_info *ei = EXT4_I(io_end->inode);
struct workqueue_struct *wq;
@@ -186,8 +174,6 @@ static int ext4_do_flush_completed_IO(struct inode *inode)
err = ext4_end_io(io);
if (unlikely(!ret && err))
ret = err;
- io->flag &= ~EXT4_IO_END_UNWRITTEN;
- ext4_free_io_end(io);
}
return ret;
}
@@ -219,10 +205,43 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
atomic_inc(&EXT4_I(inode)->i_ioend_count);
io->inode = inode;
INIT_LIST_HEAD(&io->list);
+ atomic_set(&io->count, 1);
}
return io;
}
+void ext4_put_io_end_defer(ext4_io_end_t *io_end)
+{
+ if (atomic_dec_and_test(&io_end->count)) {
+ if (!(io_end->flag & EXT4_IO_END_UNWRITTEN) || !io_end->size) {
+ ext4_release_io_end(io_end);
+ return;
+ }
+ ext4_add_complete_io(io_end);
+ }
+}
+
+int ext4_put_io_end(ext4_io_end_t *io_end)
+{
+ int err = 0;
+
+ if (atomic_dec_and_test(&io_end->count)) {
+ if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
+ err = ext4_convert_unwritten_extents(io_end->inode,
+ io_end->offset, io_end->size);
+ ext4_clear_io_unwritten_flag(io_end);
+ }
+ ext4_release_io_end(io_end);
+ }
+ return err;
+}
+
+ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
+{
+ atomic_inc(&io_end->count);
+ return io_end;
+}
+
/*
* Print an buffer I/O error compatible with the fs/buffer.c. This
* provides compatibility with dmesg scrapers that look for a specific
@@ -243,45 +262,56 @@ static void ext4_end_bio(struct bio *bio, int error)
ext4_io_end_t *io_end = bio->bi_private;
struct inode *inode;
int i;
+ int blocksize;
sector_t bi_sector = bio->bi_sector;
BUG_ON(!io_end);
+ inode = io_end->inode;
+ blocksize = 1 << inode->i_blkbits;
bio->bi_private = NULL;
bio->bi_end_io = NULL;
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
error = 0;
- bio_put(bio);
-
- for (i = 0; i < io_end->num_io_pages; i++) {
- struct page *page = io_end->pages[i]->p_page;
+ for (i = 0; i < bio->bi_vcnt; i++) {
+ struct bio_vec *bvec = &bio->bi_io_vec[i];
+ struct page *page = bvec->bv_page;
struct buffer_head *bh, *head;
- loff_t offset;
- loff_t io_end_offset;
+ unsigned bio_start = bvec->bv_offset;
+ unsigned bio_end = bio_start + bvec->bv_len;
+ unsigned under_io = 0;
+ unsigned long flags;
+
+ if (!page)
+ continue;
if (error) {
SetPageError(page);
set_bit(AS_EIO, &page->mapping->flags);
- head = page_buffers(page);
- BUG_ON(!head);
-
- io_end_offset = io_end->offset + io_end->size;
-
- offset = (sector_t) page->index << PAGE_CACHE_SHIFT;
- bh = head;
- do {
- if ((offset >= io_end->offset) &&
- (offset+bh->b_size <= io_end_offset))
- buffer_io_error(bh);
-
- offset += bh->b_size;
- bh = bh->b_this_page;
- } while (bh != head);
}
-
- put_io_page(io_end->pages[i]);
+ bh = head = page_buffers(page);
+ /*
+ * We check all buffers in the page under BH_Uptodate_Lock
+ * to avoid races with other end io clearing async_write flags
+ */
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &head->b_state);
+ do {
+ if (bh_offset(bh) < bio_start ||
+ bh_offset(bh) + blocksize > bio_end) {
+ if (buffer_async_write(bh))
+ under_io++;
+ continue;
+ }
+ clear_buffer_async_write(bh);
+ if (error)
+ buffer_io_error(bh);
+ } while ((bh = bh->b_this_page) != head);
+ bit_spin_unlock(BH_Uptodate_Lock, &head->b_state);
+ local_irq_restore(flags);
+ if (!under_io)
+ end_page_writeback(page);
}
- io_end->num_io_pages = 0;
- inode = io_end->inode;
+ bio_put(bio);
if (error) {
io_end->flag |= EXT4_IO_END_ERROR;
@@ -294,12 +324,7 @@ static void ext4_end_bio(struct bio *bio, int error)
bi_sector >> (inode->i_blkbits - 9));
}
- if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
- ext4_free_io_end(io_end);
- return;
- }
-
- ext4_add_complete_io(io_end);
+ ext4_put_io_end_defer(io_end);
}
void ext4_io_submit(struct ext4_io_submit *io)
@@ -313,76 +338,59 @@ void ext4_io_submit(struct ext4_io_submit *io)
bio_put(io->io_bio);
}
io->io_bio = NULL;
- io->io_op = 0;
+}
+
+void ext4_io_submit_init(struct ext4_io_submit *io,
+ struct writeback_control *wbc)
+{
+ io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
+ io->io_bio = NULL;
io->io_end = NULL;
}
-static int io_submit_init(struct ext4_io_submit *io,
- struct inode *inode,
- struct writeback_control *wbc,
- struct buffer_head *bh)
+static int io_submit_init_bio(struct ext4_io_submit *io,
+ struct buffer_head *bh)
{
- ext4_io_end_t *io_end;
- struct page *page = bh->b_page;
int nvecs = bio_get_nr_vecs(bh->b_bdev);
struct bio *bio;
- io_end = ext4_init_io_end(inode, GFP_NOFS);
- if (!io_end)
- return -ENOMEM;
bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
bio->bi_bdev = bh->b_bdev;
- bio->bi_private = io->io_end = io_end;
bio->bi_end_io = ext4_end_bio;
-
- io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
-
+ bio->bi_private = ext4_get_io_end(io->io_end);
+ if (!io->io_end->size)
+ io->io_end->offset = (bh->b_page->index << PAGE_CACHE_SHIFT)
+ + bh_offset(bh);
io->io_bio = bio;
- io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE);
io->io_next_block = bh->b_blocknr;
return 0;
}
static int io_submit_add_bh(struct ext4_io_submit *io,
- struct ext4_io_page *io_page,
struct inode *inode,
- struct writeback_control *wbc,
struct buffer_head *bh)
{
ext4_io_end_t *io_end;
int ret;
- if (buffer_new(bh)) {
- clear_buffer_new(bh);
- unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
- }
-
if (io->io_bio && bh->b_blocknr != io->io_next_block) {
submit_and_retry:
ext4_io_submit(io);
}
if (io->io_bio == NULL) {
- ret = io_submit_init(io, inode, wbc, bh);
+ ret = io_submit_init_bio(io, bh);
if (ret)
return ret;
}
- io_end = io->io_end;
- if ((io_end->num_io_pages >= MAX_IO_PAGES) &&
- (io_end->pages[io_end->num_io_pages-1] != io_page))
- goto submit_and_retry;
- if (buffer_uninit(bh))
- ext4_set_io_unwritten_flag(inode, io_end);
- io->io_end->size += bh->b_size;
- io->io_next_block++;
ret = bio_add_page(io->io_bio, bh->b_page, bh->b_size, bh_offset(bh));
if (ret != bh->b_size)
goto submit_and_retry;
- if ((io_end->num_io_pages == 0) ||
- (io_end->pages[io_end->num_io_pages-1] != io_page)) {
- io_end->pages[io_end->num_io_pages++] = io_page;
- atomic_inc(&io_page->p_count);
- }
+ io_end = io->io_end;
+ if (test_clear_buffer_uninit(bh))
+ ext4_set_io_unwritten_flag(inode, io_end);
+ io_end->size += bh->b_size;
+ io->io_next_block++;
return 0;
}
@@ -392,33 +400,29 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
- unsigned block_start, block_end, blocksize;
- struct ext4_io_page *io_page;
+ unsigned block_start, blocksize;
struct buffer_head *bh, *head;
int ret = 0;
+ int nr_submitted = 0;
blocksize = 1 << inode->i_blkbits;
BUG_ON(!PageLocked(page));
BUG_ON(PageWriteback(page));
- io_page = kmem_cache_alloc(io_page_cachep, GFP_NOFS);
- if (!io_page) {
- redirty_page_for_writepage(wbc, page);
- unlock_page(page);
- return -ENOMEM;
- }
- io_page->p_page = page;
- atomic_set(&io_page->p_count, 1);
- get_page(page);
set_page_writeback(page);
ClearPageError(page);
- for (bh = head = page_buffers(page), block_start = 0;
- bh != head || !block_start;
- block_start = block_end, bh = bh->b_this_page) {
-
- block_end = block_start + blocksize;
+ /*
+ * In the first loop we prepare and mark buffers to submit. We have to
+ * mark all buffers in the page before submitting so that
+ * end_page_writeback() cannot be called from ext4_bio_end_io() when IO
+ * on the first buffer finishes and we are still working on submitting
+ * the second buffer.
+ */
+ bh = head = page_buffers(page);
+ do {
+ block_start = bh_offset(bh);
if (block_start >= len) {
/*
* Comments copied from block_write_full_page_endio:
@@ -431,7 +435,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
* mapped, and writes to that region are not written
* out to the file."
*/
- zero_user_segment(page, block_start, block_end);
+ zero_user_segment(page, block_start,
+ block_start + blocksize);
clear_buffer_dirty(bh);
set_buffer_uptodate(bh);
continue;
@@ -445,7 +450,19 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
ext4_io_submit(io);
continue;
}
- ret = io_submit_add_bh(io, io_page, inode, wbc, bh);
+ if (buffer_new(bh)) {
+ clear_buffer_new(bh);
+ unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr);
+ }
+ set_buffer_async_write(bh);
+ } while ((bh = bh->b_this_page) != head);
+
+ /* Now submit buffers to write */
+ bh = head = page_buffers(page);
+ do {
+ if (!buffer_async_write(bh))
+ continue;
+ ret = io_submit_add_bh(io, inode, bh);
if (ret) {
/*
* We only get here on ENOMEM. Not much else
@@ -455,17 +472,20 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
redirty_page_for_writepage(wbc, page);
break;
}
+ nr_submitted++;
clear_buffer_dirty(bh);
+ } while ((bh = bh->b_this_page) != head);
+
+ /* Error stopped previous loop? Clean up buffers... */
+ if (ret) {
+ do {
+ clear_buffer_async_write(bh);
+ bh = bh->b_this_page;
+ } while (bh != head);
}
unlock_page(page);
- /*
- * If the page was truncated before we could do the writeback,
- * or we had a memory allocation error while trying to write
- * the first buffer head, we won't have submitted any pages for
- * I/O. In that case we need to make sure we've cleared the
- * PageWriteback bit from the page to prevent the system from
- * wedging later on.
- */
- put_io_page(io_page);
+ /* Nothing submitted - we have to end page writeback */
+ if (!nr_submitted)
+ end_page_writeback(page);
return ret;
}
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index c169477a62c9..b27c96d01965 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -272,7 +272,7 @@ next_group:
if (start_blk >= last_blk)
goto next_group;
group_data[bb_index].block_bitmap = start_blk++;
- ext4_get_group_no_and_offset(sb, start_blk - 1, &group, NULL);
+ group = ext4_get_group_number(sb, start_blk - 1);
group -= group_data[0].group;
group_data[group].free_blocks_count--;
if (flexbg_size > 1)
@@ -284,7 +284,7 @@ next_group:
if (start_blk >= last_blk)
goto next_group;
group_data[ib_index].inode_bitmap = start_blk++;
- ext4_get_group_no_and_offset(sb, start_blk - 1, &group, NULL);
+ group = ext4_get_group_number(sb, start_blk - 1);
group -= group_data[0].group;
group_data[group].free_blocks_count--;
if (flexbg_size > 1)
@@ -296,7 +296,7 @@ next_group:
if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk)
goto next_group;
group_data[it_index].inode_table = start_blk;
- ext4_get_group_no_and_offset(sb, start_blk, &group, NULL);
+ group = ext4_get_group_number(sb, start_blk - 1);
group -= group_data[0].group;
group_data[group].free_blocks_count -=
EXT4_SB(sb)->s_itb_per_group;
@@ -392,7 +392,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
ext4_group_t group;
int err;
- ext4_get_group_no_and_offset(sb, block, &group, NULL);
+ group = ext4_get_group_number(sb, block);
start = ext4_group_first_block_no(sb, group);
group -= flex_gd->groups[0].group;
@@ -1341,6 +1341,8 @@ static void ext4_update_super(struct super_block *sb,
/* Update the global fs size fields */
sbi->s_groups_count += flex_gd->count;
+ sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count,
+ (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb)));
/* Update the reserved block counts only once the new group is
* active. */
@@ -1879,7 +1881,11 @@ retry:
/* Nothing need to do */
return 0;
- ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &offset);
+ n_group = ext4_get_group_number(sb, n_blocks_count - 1);
+ if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) {
+ ext4_warning(sb, "resize would cause inodes_count overflow");
+ return -EINVAL;
+ }
ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset);
n_desc_blocks = num_desc_blocks(sb, n_group + 1);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c65510548355..24a146bde742 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -81,6 +81,7 @@ 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_EXT23)
static struct file_system_type ext2_fs_type = {
@@ -353,10 +354,13 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
struct super_block *sb = journal->j_private;
struct ext4_sb_info *sbi = EXT4_SB(sb);
int error = is_journal_aborted(journal);
- struct ext4_journal_cb_entry *jce, *tmp;
+ struct ext4_journal_cb_entry *jce;
+ BUG_ON(txn->t_state == T_FINISHED);
spin_lock(&sbi->s_md_lock);
- list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) {
+ while (!list_empty(&txn->t_private_list)) {
+ jce = list_entry(txn->t_private_list.next,
+ struct ext4_journal_cb_entry, jce_list);
list_del_init(&jce->jce_list);
spin_unlock(&sbi->s_md_lock);
jce->jce_func(sb, jce, error);
@@ -1948,16 +1952,16 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
if ((sbi->s_es->s_feature_ro_compat &
cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))) {
/* Use new metadata_csum algorithm */
- __u16 old_csum;
+ __le16 save_csum;
__u32 csum32;
- old_csum = gdp->bg_checksum;
+ save_csum = gdp->bg_checksum;
gdp->bg_checksum = 0;
csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
sizeof(le_group));
csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp,
sbi->s_desc_size);
- gdp->bg_checksum = old_csum;
+ gdp->bg_checksum = save_csum;
crc = csum32 & 0xFFFF;
goto out;
@@ -2379,17 +2383,15 @@ struct ext4_attr {
int offset;
};
-static int parse_strtoul(const char *buf,
- unsigned long max, unsigned long *value)
+static int parse_strtoull(const char *buf,
+ unsigned long long max, unsigned long long *value)
{
- char *endp;
-
- *value = simple_strtoul(skip_spaces(buf), &endp, 0);
- endp = skip_spaces(endp);
- if (*endp || *value > max)
- return -EINVAL;
+ int ret;
- return 0;
+ 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,
@@ -2431,11 +2433,13 @@ static ssize_t inode_readahead_blks_store(struct ext4_attr *a,
const char *buf, size_t count)
{
unsigned long t;
+ int ret;
- if (parse_strtoul(buf, 0x40000000, &t))
- return -EINVAL;
+ ret = kstrtoul(skip_spaces(buf), 0, &t);
+ if (ret)
+ return ret;
- if (t && !is_power_of_2(t))
+ if (t && (!is_power_of_2(t) || t > 0x40000000))
return -EINVAL;
sbi->s_inode_readahead_blks = t;
@@ -2456,13 +2460,36 @@ static ssize_t sbi_ui_store(struct ext4_attr *a,
{
unsigned int *ui = (unsigned int *) (((char *) sbi) + a->offset);
unsigned long t;
+ int ret;
- if (parse_strtoul(buf, 0xffffffff, &t))
- return -EINVAL;
+ ret = kstrtoul(skip_spaces(buf), 0, &t);
+ if (ret)
+ return ret;
*ui = t;
return count;
}
+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)
@@ -2500,6 +2527,7 @@ static struct ext4_attr ext4_attr_##name = __ATTR(name, mode, show, store)
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);
@@ -2517,6 +2545,7 @@ 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),
@@ -3192,6 +3221,40 @@ int ext4_calculate_overhead(struct super_block *sb)
return 0;
}
+
+static ext4_fsblk_t ext4_calculate_resv_clusters(struct ext4_sb_info *sbi)
+{
+ ext4_fsblk_t resv_clusters;
+
+ /*
+ * By default we reserve 2% or 4096 clusters, whichever is smaller.
+ * This should cover the situations where we can not afford to run
+ * out of space like for example punch hole, or converting
+ * uninitialized extents in delalloc path. In most cases such
+ * allocation would require 1, or 2 blocks, higher numbers are
+ * very rare.
+ */
+ 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;
+}
+
static int ext4_fill_super(struct super_block *sb, void *data, int silent)
{
char *orig_data = kstrdup(data, GFP_KERNEL);
@@ -3526,6 +3589,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
+ /* Do we have standard group size of blocksize * 8 blocks ? */
+ if (sbi->s_blocks_per_group == blocksize << 3)
+ set_opt2(sb, STD_GROUP_SIZE);
+
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;
@@ -3698,6 +3765,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_err_report.function = print_daily_error_info;
sbi->s_err_report.data = (unsigned long) sb;
+ /* Register extent status tree shrinker */
+ ext4_es_register_shrinker(sb);
+
err = percpu_counter_init(&sbi->s_freeclusters_counter,
ext4_count_free_clusters(sb));
if (!err) {
@@ -3723,9 +3793,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sbi->s_max_writeback_mb_bump = 128;
sbi->s_extent_max_zeroout_kb = 32;
- /* Register extent status tree shrinker */
- ext4_es_register_shrinker(sb);
-
/*
* set up enough so that it can read an inode
*/
@@ -3911,6 +3978,13 @@ no_journal:
"available");
}
+ err = ext4_reserve_clusters(sbi, ext4_calculate_resv_clusters(sbi));
+ if (err) {
+ ext4_msg(sb, KERN_ERR, "failed to reserve %llu clusters for "
+ "reserved pool", ext4_calculate_resv_clusters(sbi));
+ goto failed_mount4a;
+ }
+
err = ext4_setup_system_zone(sb);
if (err) {
ext4_msg(sb, KERN_ERR, "failed to initialize system "
@@ -4010,6 +4084,7 @@ failed_mount_wq:
sbi->s_journal = NULL;
}
failed_mount3:
+ ext4_es_unregister_shrinker(sb);
del_timer(&sbi->s_err_report);
if (sbi->s_flex_groups)
ext4_kvfree(sbi->s_flex_groups);
@@ -4177,7 +4252,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
goto out_bdev;
}
journal->j_private = sb;
- ll_rw_block(READ, 1, &journal->j_sb_buffer);
+ ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &journal->j_sb_buffer);
wait_on_buffer(journal->j_sb_buffer);
if (!buffer_uptodate(journal->j_sb_buffer)) {
ext4_msg(sb, KERN_ERR, "I/O error on journal device");
@@ -4742,9 +4817,10 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
struct super_block *sb = dentry->d_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
- ext4_fsblk_t overhead = 0;
+ ext4_fsblk_t overhead = 0, resv_blocks;
u64 fsid;
s64 bfree;
+ resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters));
if (!test_opt(sb, MINIX_DF))
overhead = sbi->s_overhead;
@@ -4756,8 +4832,9 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter);
/* prevent underflow in case that few free space is available */
buf->f_bfree = EXT4_C2B(sbi, max_t(s64, bfree, 0));
- buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
- if (buf->f_bfree < ext4_r_blocks_count(es))
+ buf->f_bavail = buf->f_bfree -
+ (ext4_r_blocks_count(es) + resv_blocks);
+ if (buf->f_bfree < (ext4_r_blocks_count(es) + resv_blocks))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter);
@@ -4945,6 +5022,8 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
return PTR_ERR(qf_inode);
}
+ /* Don't account quota for quota files to avoid recursion */
+ qf_inode->i_flags |= S_NOQUOTA;
err = dquot_enable(qf_inode, type, format_id, flags);
iput(qf_inode);
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 3a120b277240..c081e34f717f 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -122,17 +122,18 @@ static __le32 ext4_xattr_block_csum(struct inode *inode,
struct ext4_xattr_header *hdr)
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- __u32 csum, old;
+ __u32 csum;
+ __le32 save_csum;
+ __le64 dsk_block_nr = cpu_to_le64(block_nr);
- old = hdr->h_checksum;
+ save_csum = hdr->h_checksum;
hdr->h_checksum = 0;
- block_nr = cpu_to_le64(block_nr);
- csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&block_nr,
- sizeof(block_nr));
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
+ sizeof(dsk_block_nr));
csum = ext4_chksum(sbi, csum, (__u8 *)hdr,
EXT4_BLOCK_SIZE(inode->i_sb));
- hdr->h_checksum = old;
+ hdr->h_checksum = save_csum;
return cpu_to_le32(csum);
}
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index aa25deb5c6cd..c767dbdd7fc4 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -22,6 +22,7 @@
#define EXT4_XATTR_INDEX_LUSTRE 5
#define EXT4_XATTR_INDEX_SECURITY 6
#define EXT4_XATTR_INDEX_SYSTEM 7
+#define EXT4_XATTR_INDEX_RICHACL 8
struct ext4_xattr_header {
__le32 h_magic; /* magic number for identification */
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index cc2213afdcc7..201c8d3b0f86 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -137,7 +137,7 @@ struct extent_info {
rwlock_t ext_lock; /* rwlock for consistency */
unsigned int fofs; /* start offset in a file */
u32 blk_addr; /* start block address of the extent */
- unsigned int len; /* lenth of the extent */
+ unsigned int len; /* length of the extent */
};
/*
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 94b8a0c48453..2e3eb2d4fc30 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -222,7 +222,7 @@ static unsigned int get_gc_cost(struct f2fs_sb_info *sbi, unsigned int segno,
}
/*
- * This function is called from two pathes.
+ * This function is called from two paths.
* One is garbage collection and the other is SSR segment selection.
* When it is called during GC, it just gets a victim segment
* and it does not remove it from dirty seglist.
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index fea6e582a2ed..62e017743af6 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -82,7 +82,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
init_once((void *) fi);
- /* Initilize f2fs-specific inode info */
+ /* Initialize f2fs-specific inode info */
fi->vfs_inode.i_version = 1;
atomic_set(&fi->dirty_dents, 0);
fi->i_current_depth = 1;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 165012ef363a..7a6f02caf286 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -964,6 +964,29 @@ int fat_scan(struct inode *dir, const unsigned char *name,
}
EXPORT_SYMBOL_GPL(fat_scan);
+/*
+ * Scans a directory for a given logstart.
+ * Returns an error code or zero.
+ */
+int fat_scan_logstart(struct inode *dir, int i_logstart,
+ struct fat_slot_info *sinfo)
+{
+ struct super_block *sb = dir->i_sb;
+
+ sinfo->slot_off = 0;
+ sinfo->bh = NULL;
+ while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh,
+ &sinfo->de) >= 0) {
+ if (fat_get_start(MSDOS_SB(sb), sinfo->de) == i_logstart) {
+ sinfo->slot_off -= sizeof(*sinfo->de);
+ sinfo->nr_slots = 1;
+ sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots)
{
struct super_block *sb = dir->i_sb;
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index e9cc3f0d58e2..21664fcf3616 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -23,6 +23,9 @@
#define FAT_ERRORS_PANIC 2 /* panic on error */
#define FAT_ERRORS_RO 3 /* remount r/o on error */
+#define FAT_NFS_STALE_RW 1 /* NFS RW support, can cause ESTALE */
+#define FAT_NFS_NOSTALE_RO 2 /* NFS RO support, no ESTALE issue */
+
struct fat_mount_options {
kuid_t fs_uid;
kgid_t fs_gid;
@@ -34,6 +37,7 @@ struct fat_mount_options {
unsigned short shortname; /* flags for shortname display/create rule */
unsigned char name_check; /* r = relaxed, n = normal, s = strict */
unsigned char errors; /* On error: continue, panic, remount-ro */
+ unsigned char nfs; /* NFS support: nostale_ro, stale_rw */
unsigned short allow_utime;/* permission for setting the [am]time */
unsigned quiet:1, /* set = fake successful chmods and chowns */
showexec:1, /* set = only set x bit for com/exe/bat */
@@ -48,8 +52,7 @@ struct fat_mount_options {
usefree:1, /* Use free_clusters for FAT32 */
tz_set:1, /* Filesystem timestamps' offset set */
rodir:1, /* allow ATTR_RO for directory */
- discard:1, /* Issue discard requests on deletions */
- nfs:1; /* Do extra work needed for NFS export */
+ discard:1; /* Issue discard requests on deletions */
};
#define FAT_HASH_BITS 8
@@ -72,6 +75,7 @@ struct msdos_sb_info {
unsigned long root_cluster; /* first cluster of the root directory */
unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */
struct mutex fat_lock;
+ struct mutex nfs_build_inode_lock;
struct mutex s_lock;
unsigned int prev_free; /* previously allocated cluster number */
unsigned int free_clusters; /* -1 if undefined */
@@ -215,6 +219,27 @@ static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus)
+ sbi->data_start;
}
+static inline void fat_get_blknr_offset(struct msdos_sb_info *sbi,
+ loff_t i_pos, sector_t *blknr, int *offset)
+{
+ *blknr = i_pos >> sbi->dir_per_block_bits;
+ *offset = i_pos & (sbi->dir_per_block - 1);
+}
+
+static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
+ struct inode *inode)
+{
+ loff_t i_pos;
+#if BITS_PER_LONG == 32
+ spin_lock(&sbi->inode_hash_lock);
+#endif
+ i_pos = MSDOS_I(inode)->i_pos;
+#if BITS_PER_LONG == 32
+ spin_unlock(&sbi->inode_hash_lock);
+#endif
+ return i_pos;
+}
+
static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
{
#ifdef __BIG_ENDIAN
@@ -271,6 +296,8 @@ extern int fat_dir_empty(struct inode *dir);
extern int fat_subdirs(struct inode *dir);
extern int fat_scan(struct inode *dir, const unsigned char *name,
struct fat_slot_info *sinfo);
+extern int fat_scan_logstart(struct inode *dir, int i_logstart,
+ struct fat_slot_info *sinfo);
extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh,
struct msdos_dir_entry **de);
extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts);
@@ -348,6 +375,7 @@ extern struct inode *fat_build_inode(struct super_block *sb,
extern int fat_sync_inode(struct inode *inode);
extern int fat_fill_super(struct super_block *sb, void *data, int silent,
int isvfat, void (*setup)(struct super_block *));
+extern int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
struct inode *i2);
@@ -382,12 +410,8 @@ int fat_cache_init(void);
void fat_cache_destroy(void);
/* fat/nfs.c */
-struct fid;
-extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid,
- int fh_len, int fh_type);
-extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid,
- int fh_len, int fh_type);
-extern struct dentry *fat_get_parent(struct dentry *child_dir);
+extern const struct export_operations fat_export_ops;
+extern const struct export_operations fat_export_ops_nostale;
/* helper for printk */
typedef unsigned long long llu;
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 3978f8ca1823..b0b632e50ddb 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -306,6 +306,11 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
struct inode *inode = dentry->d_inode;
generic_fillattr(inode, stat);
stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size;
+
+ if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) {
+ /* Use i_pos for ino. This is used as fileid of nfs. */
+ stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode);
+ }
return 0;
}
EXPORT_SYMBOL_GPL(fat_getattr);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index acf6e479b443..4ff901632b26 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -18,7 +18,6 @@
#include <linux/pagemap.h>
#include <linux/mpage.h>
#include <linux/buffer_head.h>
-#include <linux/exportfs.h>
#include <linux/mount.h>
#include <linux/vfs.h>
#include <linux/parser.h>
@@ -385,7 +384,7 @@ static int fat_calc_dir_size(struct inode *inode)
}
/* doesn't deal with root inode */
-static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
+int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
int error;
@@ -444,12 +443,25 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
return 0;
}
+static inline void fat_lock_build_inode(struct msdos_sb_info *sbi)
+{
+ if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+ mutex_lock(&sbi->nfs_build_inode_lock);
+}
+
+static inline void fat_unlock_build_inode(struct msdos_sb_info *sbi)
+{
+ if (sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+ mutex_unlock(&sbi->nfs_build_inode_lock);
+}
+
struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos)
{
struct inode *inode;
int err;
+ fat_lock_build_inode(MSDOS_SB(sb));
inode = fat_iget(sb, i_pos);
if (inode)
goto out;
@@ -469,6 +481,7 @@ struct inode *fat_build_inode(struct super_block *sb,
fat_attach(inode, i_pos);
insert_inode_hash(inode);
out:
+ fat_unlock_build_inode(MSDOS_SB(sb));
return inode;
}
@@ -655,20 +668,6 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
-static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi,
- struct inode *inode)
-{
- loff_t i_pos;
-#if BITS_PER_LONG == 32
- spin_lock(&sbi->inode_hash_lock);
-#endif
- i_pos = MSDOS_I(inode)->i_pos;
-#if BITS_PER_LONG == 32
- spin_unlock(&sbi->inode_hash_lock);
-#endif
- return i_pos;
-}
-
static int __fat_write_inode(struct inode *inode, int wait)
{
struct super_block *sb = inode->i_sb;
@@ -676,7 +675,8 @@ static int __fat_write_inode(struct inode *inode, int wait)
struct buffer_head *bh;
struct msdos_dir_entry *raw_entry;
loff_t i_pos;
- int err;
+ sector_t blocknr;
+ int err, offset;
if (inode->i_ino == MSDOS_ROOT_INO)
return 0;
@@ -686,7 +686,8 @@ retry:
if (!i_pos)
return 0;
- bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits);
+ fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
+ bh = sb_bread(sb, blocknr);
if (!bh) {
fat_msg(sb, KERN_ERR, "unable to read inode block "
"for updating (i_pos %lld)", i_pos);
@@ -699,8 +700,7 @@ retry:
goto retry;
}
- raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
- [i_pos & (sbi->dir_per_block - 1)];
+ raw_entry = &((struct msdos_dir_entry *) (bh->b_data))[offset];
if (S_ISDIR(inode->i_mode))
raw_entry->size = 0;
else
@@ -761,12 +761,6 @@ static const struct super_operations fat_sops = {
.show_options = fat_show_options,
};
-static const struct export_operations fat_export_ops = {
- .fh_to_dentry = fat_fh_to_dentry,
- .fh_to_parent = fat_fh_to_parent,
- .get_parent = fat_get_parent,
-};
-
static int fat_show_options(struct seq_file *m, struct dentry *root)
{
struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb);
@@ -814,8 +808,6 @@ static int fat_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",usefree");
if (opts->quiet)
seq_puts(m, ",quiet");
- if (opts->nfs)
- seq_puts(m, ",nfs");
if (opts->showexec)
seq_puts(m, ",showexec");
if (opts->sys_immutable)
@@ -849,6 +841,10 @@ static int fat_show_options(struct seq_file *m, struct dentry *root)
seq_puts(m, ",errors=panic");
else
seq_puts(m, ",errors=remount-ro");
+ if (opts->nfs == FAT_NFS_NOSTALE_RO)
+ seq_puts(m, ",nfs=nostale_ro");
+ else if (opts->nfs)
+ seq_puts(m, ",nfs=stale_rw");
if (opts->discard)
seq_puts(m, ",discard");
@@ -865,7 +861,7 @@ enum {
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
- Opt_err,
+ Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err,
};
static const match_table_t fat_tokens = {
@@ -895,7 +891,9 @@ static const match_table_t fat_tokens = {
{Opt_err_panic, "errors=panic"},
{Opt_err_ro, "errors=remount-ro"},
{Opt_discard, "discard"},
- {Opt_nfs, "nfs"},
+ {Opt_nfs_stale_rw, "nfs"},
+ {Opt_nfs_stale_rw, "nfs=stale_rw"},
+ {Opt_nfs_nostale_ro, "nfs=nostale_ro"},
{Opt_obsolete, "conv=binary"},
{Opt_obsolete, "conv=text"},
{Opt_obsolete, "conv=auto"},
@@ -1092,6 +1090,12 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
case Opt_err_ro:
opts->errors = FAT_ERRORS_RO;
break;
+ case Opt_nfs_stale_rw:
+ opts->nfs = FAT_NFS_STALE_RW;
+ break;
+ case Opt_nfs_nostale_ro:
+ opts->nfs = FAT_NFS_NOSTALE_RO;
+ break;
/* msdos specific */
case Opt_dots:
@@ -1150,9 +1154,6 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
case Opt_discard:
opts->discard = 1;
break;
- case Opt_nfs:
- opts->nfs = 1;
- break;
/* obsolete mount options */
case Opt_obsolete:
@@ -1183,6 +1184,10 @@ out:
opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
if (opts->unicode_xlate)
opts->utf8 = 0;
+ if (opts->nfs == FAT_NFS_NOSTALE_RO) {
+ sb->s_flags |= MS_RDONLY;
+ sb->s_export_op = &fat_export_ops_nostale;
+ }
return 0;
}
@@ -1193,7 +1198,7 @@ static int fat_read_root(struct inode *inode)
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error;
- MSDOS_I(inode)->i_pos = 0;
+ MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
inode->i_version++;
@@ -1256,6 +1261,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
sb->s_magic = MSDOS_SUPER_MAGIC;
sb->s_op = &fat_sops;
sb->s_export_op = &fat_export_ops;
+ mutex_init(&sbi->nfs_build_inode_lock);
ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c
index 499c10438ca2..93e14933dcb6 100644
--- a/fs/fat/nfs.c
+++ b/fs/fat/nfs.c
@@ -14,6 +14,18 @@
#include <linux/exportfs.h>
#include "fat.h"
+struct fat_fid {
+ u32 i_gen;
+ u32 i_pos_low;
+ u16 i_pos_hi;
+ u16 parent_i_pos_hi;
+ u32 parent_i_pos_low;
+ u32 parent_i_gen;
+};
+
+#define FAT_FID_SIZE_WITHOUT_PARENT 3
+#define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32))
+
/**
* Look up a directory inode given its starting cluster.
*/
@@ -38,63 +50,252 @@ static struct inode *fat_dget(struct super_block *sb, int i_logstart)
return inode;
}
-static struct inode *fat_nfs_get_inode(struct super_block *sb,
- u64 ino, u32 generation)
+static struct inode *fat_ilookup(struct super_block *sb, u64 ino, loff_t i_pos)
{
- struct inode *inode;
+ if (MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO)
+ return fat_iget(sb, i_pos);
- if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO))
- return NULL;
+ else {
+ if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO))
+ return NULL;
+ return ilookup(sb, ino);
+ }
+}
+
+static struct inode *__fat_nfs_get_inode(struct super_block *sb,
+ u64 ino, u32 generation, loff_t i_pos)
+{
+ struct inode *inode = fat_ilookup(sb, ino, i_pos);
- inode = ilookup(sb, ino);
if (inode && generation && (inode->i_generation != generation)) {
iput(inode);
inode = NULL;
}
+ if (inode == NULL && MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO) {
+ struct buffer_head *bh = NULL;
+ struct msdos_dir_entry *de ;
+ sector_t blocknr;
+ int offset;
+ fat_get_blknr_offset(MSDOS_SB(sb), i_pos, &blocknr, &offset);
+ bh = sb_bread(sb, blocknr);
+ if (!bh) {
+ fat_msg(sb, KERN_ERR,
+ "unable to read block(%llu) for building NFS inode",
+ (llu)blocknr);
+ return inode;
+ }
+ de = (struct msdos_dir_entry *)bh->b_data;
+ /* If a file is deleted on server and client is not updated
+ * yet, we must not build the inode upon a lookup call.
+ */
+ if (IS_FREE(de[offset].name))
+ inode = NULL;
+ else
+ inode = fat_build_inode(sb, &de[offset], i_pos);
+ brelse(bh);
+ }
return inode;
}
+static struct inode *fat_nfs_get_inode(struct super_block *sb,
+ u64 ino, u32 generation)
+{
+
+ return __fat_nfs_get_inode(sb, ino, generation, 0);
+}
+
+static int
+fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp,
+ struct inode *parent)
+{
+ int len = *lenp;
+ struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+ struct fat_fid *fid = (struct fat_fid *) fh;
+ loff_t i_pos;
+ int type = FILEID_FAT_WITHOUT_PARENT;
+
+ if (parent) {
+ if (len < FAT_FID_SIZE_WITH_PARENT) {
+ *lenp = FAT_FID_SIZE_WITH_PARENT;
+ return FILEID_INVALID;
+ }
+ } else {
+ if (len < FAT_FID_SIZE_WITHOUT_PARENT) {
+ *lenp = FAT_FID_SIZE_WITHOUT_PARENT;
+ return FILEID_INVALID;
+ }
+ }
+
+ i_pos = fat_i_pos_read(sbi, inode);
+ *lenp = FAT_FID_SIZE_WITHOUT_PARENT;
+ fid->i_gen = inode->i_generation;
+ fid->i_pos_low = i_pos & 0xFFFFFFFF;
+ fid->i_pos_hi = (i_pos >> 32) & 0xFFFF;
+ if (parent) {
+ i_pos = fat_i_pos_read(sbi, parent);
+ fid->parent_i_pos_hi = (i_pos >> 32) & 0xFFFF;
+ fid->parent_i_pos_low = i_pos & 0xFFFFFFFF;
+ fid->parent_i_gen = parent->i_generation;
+ type = FILEID_FAT_WITH_PARENT;
+ *lenp = FAT_FID_SIZE_WITH_PARENT;
+ }
+
+ return type;
+}
+
/**
* Map a NFS file handle to a corresponding dentry.
* The dentry may or may not be connected to the filesystem root.
*/
-struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid,
+static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
fat_nfs_get_inode);
}
+static struct dentry *fat_fh_to_dentry_nostale(struct super_block *sb,
+ struct fid *fh, int fh_len,
+ int fh_type)
+{
+ struct inode *inode = NULL;
+ struct fat_fid *fid = (struct fat_fid *)fh;
+ loff_t i_pos;
+
+ switch (fh_type) {
+ case FILEID_FAT_WITHOUT_PARENT:
+ if (fh_len < FAT_FID_SIZE_WITHOUT_PARENT)
+ return NULL;
+ break;
+ case FILEID_FAT_WITH_PARENT:
+ if (fh_len < FAT_FID_SIZE_WITH_PARENT)
+ return NULL;
+ break;
+ default:
+ return NULL;
+ }
+ i_pos = fid->i_pos_hi;
+ i_pos = (i_pos << 32) | (fid->i_pos_low);
+ inode = __fat_nfs_get_inode(sb, 0, fid->i_gen, i_pos);
+
+ return d_obtain_alias(inode);
+}
+
/*
* Find the parent for a file specified by NFS handle.
* This requires that the handle contain the i_ino of the parent.
*/
-struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid,
+static struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid,
int fh_len, int fh_type)
{
return generic_fh_to_parent(sb, fid, fh_len, fh_type,
fat_nfs_get_inode);
}
+static struct dentry *fat_fh_to_parent_nostale(struct super_block *sb,
+ struct fid *fh, int fh_len,
+ int fh_type)
+{
+ struct inode *inode = NULL;
+ struct fat_fid *fid = (struct fat_fid *)fh;
+ loff_t i_pos;
+
+ if (fh_len < FAT_FID_SIZE_WITH_PARENT)
+ return NULL;
+
+ switch (fh_type) {
+ case FILEID_FAT_WITH_PARENT:
+ i_pos = fid->parent_i_pos_hi;
+ i_pos = (i_pos << 32) | (fid->parent_i_pos_low);
+ inode = __fat_nfs_get_inode(sb, 0, fid->parent_i_gen, i_pos);
+ break;
+ }
+
+ return d_obtain_alias(inode);
+}
+
+/*
+ * Rebuild the parent for a directory that is not connected
+ * to the filesystem root
+ */
+static
+struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart)
+{
+ int search_clus, clus_to_match;
+ struct msdos_dir_entry *de;
+ struct inode *parent = NULL;
+ struct inode *dummy_grand_parent = NULL;
+ struct fat_slot_info sinfo;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
+ sector_t blknr = fat_clus_to_blknr(sbi, parent_logstart);
+ struct buffer_head *parent_bh = sb_bread(sb, blknr);
+ if (!parent_bh) {
+ fat_msg(sb, KERN_ERR,
+ "unable to read cluster of parent directory");
+ return NULL;
+ }
+
+ de = (struct msdos_dir_entry *) parent_bh->b_data;
+ clus_to_match = fat_get_start(sbi, &de[0]);
+ search_clus = fat_get_start(sbi, &de[1]);
+
+ dummy_grand_parent = fat_dget(sb, search_clus);
+ if (!dummy_grand_parent) {
+ dummy_grand_parent = new_inode(sb);
+ if (!dummy_grand_parent) {
+ brelse(parent_bh);
+ return parent;
+ }
+
+ dummy_grand_parent->i_ino = iunique(sb, MSDOS_ROOT_INO);
+ fat_fill_inode(dummy_grand_parent, &de[1]);
+ MSDOS_I(dummy_grand_parent)->i_pos = -1;
+ }
+
+ if (!fat_scan_logstart(dummy_grand_parent, clus_to_match, &sinfo))
+ parent = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
+
+ brelse(parent_bh);
+ iput(dummy_grand_parent);
+
+ return parent;
+}
+
/*
* Find the parent for a directory that is not currently connected to
* the filesystem root.
*
* On entry, the caller holds child_dir->d_inode->i_mutex.
*/
-struct dentry *fat_get_parent(struct dentry *child_dir)
+static struct dentry *fat_get_parent(struct dentry *child_dir)
{
struct super_block *sb = child_dir->d_sb;
struct buffer_head *bh = NULL;
struct msdos_dir_entry *de;
struct inode *parent_inode = NULL;
+ struct msdos_sb_info *sbi = MSDOS_SB(sb);
if (!fat_get_dotdot_entry(child_dir->d_inode, &bh, &de)) {
- int parent_logstart = fat_get_start(MSDOS_SB(sb), de);
+ int parent_logstart = fat_get_start(sbi, de);
parent_inode = fat_dget(sb, parent_logstart);
+ if (!parent_inode && sbi->options.nfs == FAT_NFS_NOSTALE_RO)
+ parent_inode = fat_rebuild_parent(sb, parent_logstart);
}
brelse(bh);
return d_obtain_alias(parent_inode);
}
+
+const struct export_operations fat_export_ops = {
+ .fh_to_dentry = fat_fh_to_dentry,
+ .fh_to_parent = fat_fh_to_parent,
+ .get_parent = fat_get_parent,
+};
+
+const struct export_operations fat_export_ops_nostale = {
+ .encode_fh = fat_encode_fh_nostale,
+ .fh_to_dentry = fat_fh_to_dentry_nostale,
+ .fh_to_parent = fat_fh_to_parent_nostale,
+ .get_parent = fat_get_parent,
+};
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 21f46fb3a101..798d4458a4d3 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1028,6 +1028,7 @@ int bdi_writeback_thread(void *data)
struct backing_dev_info *bdi = wb->bdi;
long pages_written;
+ set_worker_desc("flush-%s", dev_name(bdi->dev));
current->flags |= PF_SWAPWRITE;
set_freezable();
wb->last_active = jiffies;
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c
index 8179e8bc4a3d..40d13c70ef51 100644
--- a/fs/fscache/stats.c
+++ b/fs/fscache/stats.c
@@ -287,5 +287,5 @@ const struct file_operations fscache_stats_fops = {
.open = fscache_stats_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = single_release,
};
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 24f414f0ce61..9883694f1e7c 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -1055,7 +1055,7 @@ int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
if (atomic_read(&bh->b_count))
goto cannot_release;
bd = bh->b_private;
- if (bd && bd->bd_ail)
+ if (bd && bd->bd_tr)
goto cannot_release;
if (buffer_pinned(bh) || buffer_dirty(bh))
goto not_possible;
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 5e83657f046e..1dc9a13ce6bb 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -787,7 +787,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
goto out_rlist;
if (gfs2_rs_active(ip->i_res)) /* needs to be done with the rgrp glock held */
- gfs2_rs_deltree(ip, ip->i_res);
+ gfs2_rs_deltree(ip->i_res);
error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
RES_INDIRECT + RES_STATFS + RES_QUOTA,
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 019f45e45097..d79c2dadc536 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -923,8 +923,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
cmd = F_SETLK;
fl->fl_type = F_UNLCK;
}
- if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+ if (fl->fl_type == F_UNLCK)
+ posix_lock_file_wait(file, fl);
return -EIO;
+ }
if (IS_GETLK(cmd))
return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
else if (fl->fl_type == F_UNLCK)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index cf3515546739..9435384562a2 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -912,7 +912,7 @@ int gfs2_glock_wait(struct gfs2_holder *gh)
*/
static void handle_callback(struct gfs2_glock *gl, unsigned int state,
- unsigned long delay)
+ unsigned long delay, bool remote)
{
int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
@@ -925,8 +925,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
gl->gl_demote_state = LM_ST_UNLOCKED;
}
if (gl->gl_ops->go_callback)
- gl->gl_ops->go_callback(gl);
- trace_gfs2_demote_rq(gl);
+ gl->gl_ops->go_callback(gl, remote);
+ trace_gfs2_demote_rq(gl, remote);
}
void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
@@ -1017,11 +1017,11 @@ do_cancel:
return;
trap_recursive:
- print_symbol(KERN_ERR "original: %s\n", gh2->gh_ip);
+ printk(KERN_ERR "original: %pSR\n", (void *)gh2->gh_ip);
printk(KERN_ERR "pid: %d\n", pid_nr(gh2->gh_owner_pid));
printk(KERN_ERR "lock type: %d req lock state : %d\n",
gh2->gh_gl->gl_name.ln_type, gh2->gh_state);
- print_symbol(KERN_ERR "new: %s\n", gh->gh_ip);
+ printk(KERN_ERR "new: %pSR\n", (void *)gh->gh_ip);
printk(KERN_ERR "pid: %d\n", pid_nr(gh->gh_owner_pid));
printk(KERN_ERR "lock type: %d req lock state : %d\n",
gh->gh_gl->gl_name.ln_type, gh->gh_state);
@@ -1091,7 +1091,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
spin_lock(&gl->gl_spin);
if (gh->gh_flags & GL_NOCACHE)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, false);
list_del_init(&gh->gh_list);
if (find_first_holder(gl) == NULL) {
@@ -1279,19 +1279,6 @@ void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs)
gfs2_glock_dq(&ghs[num_gh]);
}
-/**
- * gfs2_glock_dq_uninit_m - release multiple glocks
- * @num_gh: the number of structures
- * @ghs: an array of struct gfs2_holder structures
- *
- */
-
-void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
-{
- while (num_gh--)
- gfs2_glock_dq_uninit(&ghs[num_gh]);
-}
-
void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
{
unsigned long delay = 0;
@@ -1309,7 +1296,7 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
}
spin_lock(&gl->gl_spin);
- handle_callback(gl, state, delay);
+ handle_callback(gl, state, delay, true);
spin_unlock(&gl->gl_spin);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
gfs2_glock_put(gl);
@@ -1422,7 +1409,7 @@ __acquires(&lru_lock)
spin_unlock(&lru_lock);
spin_lock(&gl->gl_spin);
if (demote_ok(gl))
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, false);
WARN_ON(!test_and_clear_bit(GLF_LOCK, &gl->gl_flags));
smp_mb__after_clear_bit();
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
@@ -1547,7 +1534,7 @@ static void clear_glock(struct gfs2_glock *gl)
spin_lock(&gl->gl_spin);
if (gl->gl_state != LM_ST_UNLOCKED)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, false);
spin_unlock(&gl->gl_spin);
gfs2_glock_hold(gl);
if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
@@ -1590,6 +1577,7 @@ static void dump_glock_func(struct gfs2_glock *gl)
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp)
{
set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags);
+ flush_workqueue(glock_workqueue);
glock_hash_walk(clear_glock, sdp);
flush_workqueue(glock_workqueue);
wait_event(sdp->sd_glock_wait, atomic_read(&sdp->sd_glock_disposal) == 0);
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index fd580b7861d5..69f66e3d22bf 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -201,7 +201,6 @@ extern int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
struct gfs2_holder *gh);
extern int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
extern void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
-extern void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
extern int gfs2_dump_glock(struct seq_file *seq, const struct gfs2_glock *gl);
#define GLOCK_BUG_ON(gl,x) do { if (unlikely(x)) { gfs2_dump_glock(NULL, gl); BUG(); } } while(0)
extern __printf(2, 3)
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 444b6503ebc4..c66e99c97571 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -515,12 +515,12 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl)
*
* gl_spin lock is held while calling this
*/
-static void iopen_go_callback(struct gfs2_glock *gl)
+static void iopen_go_callback(struct gfs2_glock *gl, bool remote)
{
struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object;
struct gfs2_sbd *sdp = gl->gl_sbd;
- if (sdp->sd_vfs->s_flags & MS_RDONLY)
+ if (!remote || (sdp->sd_vfs->s_flags & MS_RDONLY))
return;
if (gl->gl_demote_state == LM_ST_UNLOCKED &&
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 156e42ec84ea..26aabd7caba7 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -31,7 +31,6 @@ struct gfs2_holder;
struct gfs2_glock;
struct gfs2_quota_data;
struct gfs2_trans;
-struct gfs2_ail;
struct gfs2_jdesc;
struct gfs2_sbd;
struct lm_lockops;
@@ -53,7 +52,7 @@ struct gfs2_log_header_host {
struct gfs2_log_operations {
void (*lo_before_commit) (struct gfs2_sbd *sdp);
- void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai);
+ void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr);
void (*lo_before_scan) (struct gfs2_jdesc *jd,
struct gfs2_log_header_host *head, int pass);
int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start,
@@ -139,7 +138,7 @@ struct gfs2_bufdata {
struct list_head bd_list;
const struct gfs2_log_operations *bd_ops;
- struct gfs2_ail *bd_ail;
+ struct gfs2_trans *bd_tr;
struct list_head bd_ail_st_list;
struct list_head bd_ail_gl_list;
};
@@ -211,7 +210,7 @@ struct gfs2_glock_operations {
int (*go_lock) (struct gfs2_holder *gh);
void (*go_unlock) (struct gfs2_holder *gh);
int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl);
- void (*go_callback) (struct gfs2_glock *gl);
+ void (*go_callback)(struct gfs2_glock *gl, bool remote);
const int go_type;
const unsigned long go_flags;
#define GLOF_ASPACE 1
@@ -433,6 +432,7 @@ struct gfs2_trans {
struct gfs2_holder tr_t_gh;
int tr_touched;
+ int tr_attached;
unsigned int tr_num_buf_new;
unsigned int tr_num_databuf_new;
@@ -440,14 +440,12 @@ struct gfs2_trans {
unsigned int tr_num_databuf_rm;
unsigned int tr_num_revoke;
unsigned int tr_num_revoke_rm;
-};
-struct gfs2_ail {
- struct list_head ai_list;
+ struct list_head tr_list;
- unsigned int ai_first;
- struct list_head ai_ail1_list;
- struct list_head ai_ail2_list;
+ unsigned int tr_first;
+ struct list_head tr_ail1_list;
+ struct list_head tr_ail2_list;
};
struct gfs2_journal_extent {
@@ -588,6 +586,7 @@ struct lm_lockstruct {
struct dlm_lksb ls_control_lksb; /* control_lock */
char ls_control_lvb[GDLM_LVB_SIZE]; /* control_lock lvb */
struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */
+ char *ls_lvb_bits;
spinlock_t ls_recover_spin; /* protects following fields */
unsigned long ls_recover_flags; /* DFL_ */
@@ -709,6 +708,7 @@ struct gfs2_sbd {
spinlock_t sd_log_lock;
+ struct gfs2_trans *sd_log_tr;
unsigned int sd_log_blks_reserved;
unsigned int sd_log_commited_buf;
unsigned int sd_log_commited_databuf;
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index cc00bd1d1f87..8833a4f264e3 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -392,11 +392,15 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags)
int error;
int dblocks = 1;
- error = gfs2_inplace_reserve(ip, RES_DINODE, flags);
+ error = gfs2_quota_lock_check(ip);
if (error)
goto out;
- error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0);
+ error = gfs2_inplace_reserve(ip, RES_DINODE, flags);
+ if (error)
+ goto out_quota;
+
+ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 0);
if (error)
goto out_ipreserv;
@@ -409,6 +413,8 @@ static int alloc_dinode(struct gfs2_inode *ip, u32 flags)
out_ipreserv:
gfs2_inplace_release(ip);
+out_quota:
+ gfs2_quota_unlock(ip);
out:
return error;
}
@@ -440,59 +446,27 @@ static void gfs2_init_dir(struct buffer_head *dibh,
*/
static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
- const char *symname, struct buffer_head **bhp)
+ const char *symname)
{
- struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_dinode *di;
struct buffer_head *dibh;
- struct timespec tv = CURRENT_TIME;
dibh = gfs2_meta_new(ip->i_gl, ip->i_no_addr);
gfs2_trans_add_meta(ip->i_gl, dibh);
- gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI);
- gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
di = (struct gfs2_dinode *)dibh->b_data;
+ gfs2_dinode_out(ip, di);
- di->di_num.no_formal_ino = cpu_to_be64(ip->i_no_formal_ino);
- di->di_num.no_addr = cpu_to_be64(ip->i_no_addr);
- di->di_mode = cpu_to_be32(ip->i_inode.i_mode);
- di->di_uid = cpu_to_be32(i_uid_read(&ip->i_inode));
- di->di_gid = cpu_to_be32(i_gid_read(&ip->i_inode));
- di->di_nlink = 0;
- di->di_size = cpu_to_be64(ip->i_inode.i_size);
- di->di_blocks = cpu_to_be64(1);
- di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(tv.tv_sec);
di->di_major = cpu_to_be32(MAJOR(ip->i_inode.i_rdev));
di->di_minor = cpu_to_be32(MINOR(ip->i_inode.i_rdev));
- di->di_goal_meta = di->di_goal_data = cpu_to_be64(ip->i_no_addr);
- di->di_generation = cpu_to_be64(ip->i_generation);
- di->di_flags = 0;
di->__pad1 = 0;
- di->di_payload_format = cpu_to_be32(S_ISDIR(ip->i_inode.i_mode) ? GFS2_FORMAT_DE : 0);
- di->di_height = 0;
di->__pad2 = 0;
di->__pad3 = 0;
- di->di_depth = 0;
- di->di_entries = 0;
memset(&di->__pad4, 0, sizeof(di->__pad4));
- di->di_eattr = 0;
- di->di_atime_nsec = cpu_to_be32(tv.tv_nsec);
- di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec);
- di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec);
memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
switch(ip->i_inode.i_mode & S_IFMT) {
- case S_IFREG:
- if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) ||
- gfs2_tune_get(sdp, gt_new_files_jdata))
- di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA);
- break;
case S_IFDIR:
- di->di_flags |= cpu_to_be32(dip->i_diskflags &
- GFS2_DIF_INHERIT_JDATA);
- di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA);
- di->di_size = cpu_to_be64(sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode));
- di->di_entries = cpu_to_be32(2);
gfs2_init_dir(dibh, dip);
break;
case S_IFLNK:
@@ -501,63 +475,17 @@ static void init_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
}
set_buffer_uptodate(dibh);
-
- *bhp = dibh;
-}
-
-static int make_dinode(struct gfs2_inode *dip, struct gfs2_inode *ip,
- const char *symname, struct buffer_head **bhp)
-{
- struct inode *inode = &ip->i_inode;
- struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- int error;
-
- error = gfs2_rindex_update(sdp);
- if (error)
- return error;
-
- error = gfs2_quota_lock(dip, inode->i_uid, inode->i_gid);
- if (error)
- return error;
-
- error = gfs2_quota_check(dip, inode->i_uid, inode->i_gid);
- if (error)
- goto out_quota;
-
- error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0);
- if (error)
- goto out_quota;
-
- init_dinode(dip, ip, symname, bhp);
- gfs2_quota_change(dip, +1, inode->i_uid, inode->i_gid);
- gfs2_trans_end(sdp);
-
-out_quota:
- gfs2_quota_unlock(dip);
- return error;
+ brelse(dibh);
}
static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
- struct gfs2_inode *ip)
+ struct gfs2_inode *ip, int arq)
{
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
- int alloc_required;
- struct buffer_head *dibh;
int error;
- error = gfs2_rindex_update(sdp);
- if (error)
- return error;
-
- error = gfs2_quota_lock(dip, NO_UID_QUOTA_CHANGE, NO_GID_QUOTA_CHANGE);
- if (error)
- goto fail;
-
- error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
- if (alloc_required < 0)
- goto fail_quota_locks;
- if (alloc_required) {
- error = gfs2_quota_check(dip, dip->i_inode.i_uid, dip->i_inode.i_gid);
+ if (arq) {
+ error = gfs2_quota_lock_check(dip);
if (error)
goto fail_quota_locks;
@@ -581,26 +509,12 @@ static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
if (error)
goto fail_end_trans;
- error = gfs2_meta_inode_buffer(ip, &dibh);
- if (error)
- goto fail_end_trans;
- set_nlink(&ip->i_inode, S_ISDIR(ip->i_inode.i_mode) ? 2 : 1);
- gfs2_trans_add_meta(ip->i_gl, dibh);
- gfs2_dinode_out(ip, dibh->b_data);
- brelse(dibh);
- return 0;
-
fail_end_trans:
gfs2_trans_end(sdp);
-
fail_ipreserv:
- if (alloc_required)
- gfs2_inplace_release(dip);
-
+ gfs2_inplace_release(dip);
fail_quota_locks:
gfs2_quota_unlock(dip);
-
-fail:
return error;
}
@@ -650,8 +564,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_glock *io_gl;
int error;
- struct buffer_head *bh = NULL;
u32 aflags = 0;
+ int arq;
if (!name->len || name->len > GFS2_FNAMESIZE)
return -ENAMETOOLONG;
@@ -660,6 +574,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
return error;
+ error = gfs2_rindex_update(sdp);
+ if (error)
+ return error;
+
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
if (error)
goto fail;
@@ -674,22 +592,48 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_gunlock;
+ arq = error = gfs2_diradd_alloc_required(dir, name);
+ if (error < 0)
+ goto fail_gunlock;
+
inode = new_inode(sdp->sd_vfs);
- if (!inode) {
- gfs2_glock_dq_uninit(ghs);
- return -ENOMEM;
- }
+ error = -ENOMEM;
+ if (!inode)
+ goto fail_gunlock;
+
ip = GFS2_I(inode);
error = gfs2_rs_alloc(ip);
if (error)
goto fail_free_inode;
- set_bit(GIF_INVALID, &ip->i_flags);
inode->i_mode = mode;
+ set_nlink(inode, S_ISDIR(mode) ? 2 : 1);
inode->i_rdev = dev;
inode->i_size = size;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ gfs2_set_inode_blocks(inode, 1);
munge_mode_uid_gid(dip, inode);
ip->i_goal = dip->i_goal;
+ ip->i_diskflags = 0;
+ ip->i_eattr = 0;
+ ip->i_height = 0;
+ ip->i_depth = 0;
+ ip->i_entries = 0;
+
+ switch(mode & S_IFMT) {
+ case S_IFREG:
+ if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) ||
+ gfs2_tune_get(sdp, gt_new_files_jdata))
+ ip->i_diskflags |= GFS2_DIF_JDATA;
+ gfs2_set_aops(inode);
+ break;
+ case S_IFDIR:
+ ip->i_diskflags |= (dip->i_diskflags & GFS2_DIF_INHERIT_JDATA);
+ ip->i_diskflags |= GFS2_DIF_JDATA;
+ ip->i_entries = 2;
+ break;
+ }
+ gfs2_set_inode_flags(inode);
if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) ||
(dip->i_diskflags & GFS2_DIF_TOPDIR))
@@ -708,10 +652,13 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_free_inode;
- error = make_dinode(dip, ip, symname, &bh);
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
if (error)
goto fail_gunlock2;
+ init_dinode(dip, ip, symname);
+ gfs2_trans_end(sdp);
+
error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
if (error)
goto fail_gunlock2;
@@ -725,10 +672,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
gfs2_set_iop(inode);
insert_inode_hash(inode);
- error = gfs2_inode_refresh(ip);
- if (error)
- goto fail_gunlock3;
-
error = gfs2_acl_create(dip, inode);
if (error)
goto fail_gunlock3;
@@ -737,18 +680,13 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_gunlock3;
- error = link_dinode(dip, name, ip);
+ error = link_dinode(dip, name, ip, arq);
if (error)
goto fail_gunlock3;
- if (bh)
- brelse(bh);
-
- gfs2_trans_end(sdp);
- gfs2_inplace_release(dip);
- gfs2_quota_unlock(dip);
mark_inode_dirty(inode);
- gfs2_glock_dq_uninit_m(2, ghs);
+ gfs2_glock_dq_uninit(ghs);
+ gfs2_glock_dq_uninit(ghs + 1);
d_instantiate(dentry, inode);
return 0;
@@ -769,12 +707,12 @@ fail_free_inode:
fail_gunlock:
gfs2_glock_dq_uninit(ghs);
if (inode && !IS_ERR(inode)) {
+ clear_nlink(inode);
+ mark_inode_dirty(inode);
set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
iput(inode);
}
fail:
- if (bh)
- brelse(bh);
return error;
}
@@ -1151,7 +1089,9 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, 0, 0);
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ unsigned dsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
+ return gfs2_create_inode(dir, dentry, S_IFDIR | mode, 0, NULL, dsize, 0);
}
/**
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 9802de0f85e6..c8423d6de6c3 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -483,12 +483,8 @@ static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen,
static int all_jid_bits_clear(char *lvb)
{
- int i;
- for (i = JID_BITMAP_OFFSET; i < GDLM_LVB_SIZE; i++) {
- if (lvb[i])
- return 0;
- }
- return 1;
+ return !memchr_inv(lvb + JID_BITMAP_OFFSET, 0,
+ GDLM_LVB_SIZE - JID_BITMAP_OFFSET);
}
static void sync_wait_cb(void *arg)
@@ -580,7 +576,6 @@ static void gfs2_control_func(struct work_struct *work)
{
struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
- char lvb_bits[GDLM_LVB_SIZE];
uint32_t block_gen, start_gen, lvb_gen, flags;
int recover_set = 0;
int write_lvb = 0;
@@ -634,7 +629,7 @@ static void gfs2_control_func(struct work_struct *work)
return;
}
- control_lvb_read(ls, &lvb_gen, lvb_bits);
+ control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);
spin_lock(&ls->ls_recover_spin);
if (block_gen != ls->ls_recover_block ||
@@ -664,10 +659,10 @@ static void gfs2_control_func(struct work_struct *work)
ls->ls_recover_result[i] = 0;
- if (!test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET))
+ if (!test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET))
continue;
- __clear_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+ __clear_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
write_lvb = 1;
}
}
@@ -691,7 +686,7 @@ static void gfs2_control_func(struct work_struct *work)
continue;
if (ls->ls_recover_submit[i] < start_gen) {
ls->ls_recover_submit[i] = 0;
- __set_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+ __set_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
}
}
/* even if there are no bits to set, we need to write the
@@ -705,7 +700,7 @@ static void gfs2_control_func(struct work_struct *work)
spin_unlock(&ls->ls_recover_spin);
if (write_lvb) {
- control_lvb_write(ls, start_gen, lvb_bits);
+ control_lvb_write(ls, start_gen, ls->ls_lvb_bits);
flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK;
} else {
flags = DLM_LKF_CONVERT;
@@ -725,7 +720,7 @@ static void gfs2_control_func(struct work_struct *work)
*/
for (i = 0; i < recover_size; i++) {
- if (test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) {
+ if (test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET)) {
fs_info(sdp, "recover generation %u jid %d\n",
start_gen, i);
gfs2_recover_set(sdp, i);
@@ -758,7 +753,6 @@ static void gfs2_control_func(struct work_struct *work)
static int control_mount(struct gfs2_sbd *sdp)
{
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
- char lvb_bits[GDLM_LVB_SIZE];
uint32_t start_gen, block_gen, mount_gen, lvb_gen;
int mounted_mode;
int retries = 0;
@@ -857,7 +851,7 @@ locks_done:
* lvb_gen will be non-zero.
*/
- control_lvb_read(ls, &lvb_gen, lvb_bits);
+ control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);
if (lvb_gen == 0xFFFFFFFF) {
/* special value to force mount attempts to fail */
@@ -887,7 +881,7 @@ locks_done:
* and all lvb bits to be clear (no pending journal recoveries.)
*/
- if (!all_jid_bits_clear(lvb_bits)) {
+ if (!all_jid_bits_clear(ls->ls_lvb_bits)) {
/* journals need recovery, wait until all are clear */
fs_info(sdp, "control_mount wait for journal recovery\n");
goto restart;
@@ -949,7 +943,6 @@ static int dlm_recovery_wait(void *word)
static int control_first_done(struct gfs2_sbd *sdp)
{
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
- char lvb_bits[GDLM_LVB_SIZE];
uint32_t start_gen, block_gen;
int error;
@@ -991,8 +984,8 @@ restart:
memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
spin_unlock(&ls->ls_recover_spin);
- memset(lvb_bits, 0, sizeof(lvb_bits));
- control_lvb_write(ls, start_gen, lvb_bits);
+ memset(ls->ls_lvb_bits, 0, GDLM_LVB_SIZE);
+ control_lvb_write(ls, start_gen, ls->ls_lvb_bits);
error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
if (error)
@@ -1022,6 +1015,12 @@ static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
uint32_t old_size, new_size;
int i, max_jid;
+ if (!ls->ls_lvb_bits) {
+ ls->ls_lvb_bits = kzalloc(GDLM_LVB_SIZE, GFP_NOFS);
+ if (!ls->ls_lvb_bits)
+ return -ENOMEM;
+ }
+
max_jid = 0;
for (i = 0; i < num_slots; i++) {
if (max_jid < slots[i].slot - 1)
@@ -1057,6 +1056,7 @@ static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
static void free_recover_size(struct lm_lockstruct *ls)
{
+ kfree(ls->ls_lvb_bits);
kfree(ls->ls_recover_submit);
kfree(ls->ls_recover_result);
ls->ls_recover_submit = NULL;
@@ -1205,6 +1205,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
ls->ls_recover_size = 0;
ls->ls_recover_submit = NULL;
ls->ls_recover_result = NULL;
+ ls->ls_lvb_bits = NULL;
error = set_recover_size(sdp, NULL, 0);
if (error)
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 9a2ca8be7647..b404f4853034 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -73,7 +73,7 @@ unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
{
- bd->bd_ail = NULL;
+ bd->bd_tr = NULL;
list_del_init(&bd->bd_ail_st_list);
list_del_init(&bd->bd_ail_gl_list);
atomic_dec(&bd->bd_gl->gl_ail_count);
@@ -90,7 +90,7 @@ void gfs2_remove_from_ail(struct gfs2_bufdata *bd)
static int gfs2_ail1_start_one(struct gfs2_sbd *sdp,
struct writeback_control *wbc,
- struct gfs2_ail *ai)
+ struct gfs2_trans *tr)
__releases(&sdp->sd_ail_lock)
__acquires(&sdp->sd_ail_lock)
{
@@ -99,15 +99,15 @@ __acquires(&sdp->sd_ail_lock)
struct gfs2_bufdata *bd, *s;
struct buffer_head *bh;
- list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list, bd_ail_st_list) {
+ list_for_each_entry_safe_reverse(bd, s, &tr->tr_ail1_list, bd_ail_st_list) {
bh = bd->bd_bh;
- gfs2_assert(sdp, bd->bd_ail == ai);
+ gfs2_assert(sdp, bd->bd_tr == tr);
if (!buffer_busy(bh)) {
if (!buffer_uptodate(bh))
gfs2_io_error_bh(sdp, bh);
- list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+ list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
continue;
}
@@ -116,7 +116,7 @@ __acquires(&sdp->sd_ail_lock)
if (gl == bd->bd_gl)
continue;
gl = bd->bd_gl;
- list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+ list_move(&bd->bd_ail_st_list, &tr->tr_ail1_list);
mapping = bh->b_page->mapping;
if (!mapping)
continue;
@@ -144,15 +144,15 @@ __acquires(&sdp->sd_ail_lock)
void gfs2_ail1_flush(struct gfs2_sbd *sdp, struct writeback_control *wbc)
{
struct list_head *head = &sdp->sd_ail1_list;
- struct gfs2_ail *ai;
+ struct gfs2_trans *tr;
trace_gfs2_ail_flush(sdp, wbc, 1);
spin_lock(&sdp->sd_ail_lock);
restart:
- list_for_each_entry_reverse(ai, head, ai_list) {
+ list_for_each_entry_reverse(tr, head, tr_list) {
if (wbc->nr_to_write <= 0)
break;
- if (gfs2_ail1_start_one(sdp, wbc, ai))
+ if (gfs2_ail1_start_one(sdp, wbc, tr))
goto restart;
}
spin_unlock(&sdp->sd_ail_lock);
@@ -183,20 +183,20 @@ static void gfs2_ail1_start(struct gfs2_sbd *sdp)
*
*/
-static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct gfs2_bufdata *bd, *s;
struct buffer_head *bh;
- list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
+ list_for_each_entry_safe_reverse(bd, s, &tr->tr_ail1_list,
bd_ail_st_list) {
bh = bd->bd_bh;
- gfs2_assert(sdp, bd->bd_ail == ai);
+ gfs2_assert(sdp, bd->bd_tr == tr);
if (buffer_busy(bh))
continue;
if (!buffer_uptodate(bh))
gfs2_io_error_bh(sdp, bh);
- list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+ list_move(&bd->bd_ail_st_list, &tr->tr_ail2_list);
}
}
@@ -210,14 +210,14 @@ static void gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
static int gfs2_ail1_empty(struct gfs2_sbd *sdp)
{
- struct gfs2_ail *ai, *s;
+ struct gfs2_trans *tr, *s;
int ret;
spin_lock(&sdp->sd_ail_lock);
- list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {
- gfs2_ail1_empty_one(sdp, ai);
- if (list_empty(&ai->ai_ail1_list))
- list_move(&ai->ai_list, &sdp->sd_ail2_list);
+ list_for_each_entry_safe_reverse(tr, s, &sdp->sd_ail1_list, tr_list) {
+ gfs2_ail1_empty_one(sdp, tr);
+ if (list_empty(&tr->tr_ail1_list))
+ list_move(&tr->tr_list, &sdp->sd_ail2_list);
else
break;
}
@@ -229,13 +229,13 @@ static int gfs2_ail1_empty(struct gfs2_sbd *sdp)
static void gfs2_ail1_wait(struct gfs2_sbd *sdp)
{
- struct gfs2_ail *ai;
+ struct gfs2_trans *tr;
struct gfs2_bufdata *bd;
struct buffer_head *bh;
spin_lock(&sdp->sd_ail_lock);
- list_for_each_entry_reverse(ai, &sdp->sd_ail1_list, ai_list) {
- list_for_each_entry(bd, &ai->ai_ail1_list, bd_ail_st_list) {
+ list_for_each_entry_reverse(tr, &sdp->sd_ail1_list, tr_list) {
+ list_for_each_entry(bd, &tr->tr_ail1_list, bd_ail_st_list) {
bh = bd->bd_bh;
if (!buffer_locked(bh))
continue;
@@ -256,40 +256,40 @@ static void gfs2_ail1_wait(struct gfs2_sbd *sdp)
*
*/
-static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
- struct list_head *head = &ai->ai_ail2_list;
+ struct list_head *head = &tr->tr_ail2_list;
struct gfs2_bufdata *bd;
while (!list_empty(head)) {
bd = list_entry(head->prev, struct gfs2_bufdata,
bd_ail_st_list);
- gfs2_assert(sdp, bd->bd_ail == ai);
+ gfs2_assert(sdp, bd->bd_tr == tr);
gfs2_remove_from_ail(bd);
}
}
static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
{
- struct gfs2_ail *ai, *safe;
+ struct gfs2_trans *tr, *safe;
unsigned int old_tail = sdp->sd_log_tail;
int wrap = (new_tail < old_tail);
int a, b, rm;
spin_lock(&sdp->sd_ail_lock);
- list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {
- a = (old_tail <= ai->ai_first);
- b = (ai->ai_first < new_tail);
+ list_for_each_entry_safe(tr, safe, &sdp->sd_ail2_list, tr_list) {
+ a = (old_tail <= tr->tr_first);
+ b = (tr->tr_first < new_tail);
rm = (wrap) ? (a || b) : (a && b);
if (!rm)
continue;
- gfs2_ail2_empty_one(sdp, ai);
- list_del(&ai->ai_list);
- gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list));
- gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list));
- kfree(ai);
+ gfs2_ail2_empty_one(sdp, tr);
+ list_del(&tr->tr_list);
+ gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
+ gfs2_assert_warn(sdp, list_empty(&tr->tr_ail2_list));
+ kfree(tr);
}
spin_unlock(&sdp->sd_ail_lock);
@@ -435,7 +435,7 @@ static unsigned int calc_reserved(struct gfs2_sbd *sdp)
static unsigned int current_tail(struct gfs2_sbd *sdp)
{
- struct gfs2_ail *ai;
+ struct gfs2_trans *tr;
unsigned int tail;
spin_lock(&sdp->sd_ail_lock);
@@ -443,8 +443,9 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
if (list_empty(&sdp->sd_ail1_list)) {
tail = sdp->sd_log_head;
} else {
- ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list);
- tail = ai->ai_first;
+ tr = list_entry(sdp->sd_ail1_list.prev, struct gfs2_trans,
+ tr_list);
+ tail = tr->tr_first;
}
spin_unlock(&sdp->sd_ail_lock);
@@ -600,7 +601,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
{
- struct gfs2_ail *ai;
+ struct gfs2_trans *tr;
down_write(&sdp->sd_log_flush_lock);
@@ -611,9 +612,12 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
}
trace_gfs2_log_flush(sdp, 1);
- ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
- INIT_LIST_HEAD(&ai->ai_ail1_list);
- INIT_LIST_HEAD(&ai->ai_ail2_list);
+ tr = sdp->sd_log_tr;
+ if (tr) {
+ sdp->sd_log_tr = NULL;
+ INIT_LIST_HEAD(&tr->tr_ail1_list);
+ INIT_LIST_HEAD(&tr->tr_ail2_list);
+ }
if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) {
printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf,
@@ -630,7 +634,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
sdp->sd_log_flush_head = sdp->sd_log_head;
sdp->sd_log_flush_wrapped = 0;
- ai->ai_first = sdp->sd_log_flush_head;
+ if (tr)
+ tr->tr_first = sdp->sd_log_flush_head;
gfs2_ordered_write(sdp);
lops_before_commit(sdp);
@@ -643,7 +648,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
trace_gfs2_log_blocks(sdp, -1);
log_write_header(sdp, 0);
}
- lops_after_commit(sdp, ai);
+ lops_after_commit(sdp, tr);
gfs2_log_lock(sdp);
sdp->sd_log_head = sdp->sd_log_flush_head;
@@ -653,16 +658,16 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
sdp->sd_log_commited_revoke = 0;
spin_lock(&sdp->sd_ail_lock);
- if (!list_empty(&ai->ai_ail1_list)) {
- list_add(&ai->ai_list, &sdp->sd_ail1_list);
- ai = NULL;
+ if (tr && !list_empty(&tr->tr_ail1_list)) {
+ list_add(&tr->tr_list, &sdp->sd_ail1_list);
+ tr = NULL;
}
spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp);
trace_gfs2_log_flush(sdp, 0);
up_write(&sdp->sd_log_flush_lock);
- kfree(ai);
+ kfree(tr);
}
static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
@@ -687,6 +692,12 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
sdp->sd_jdesc->jd_blocks);
sdp->sd_log_blks_reserved = reserved;
+ if (sdp->sd_log_tr == NULL &&
+ (tr->tr_num_buf_new || tr->tr_num_databuf_new)) {
+ gfs2_assert_withdraw(sdp, tr->tr_t_gh.gh_gl);
+ sdp->sd_log_tr = tr;
+ tr->tr_attached = 1;
+ }
gfs2_log_unlock(sdp);
}
@@ -708,7 +719,6 @@ static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
log_refund(sdp, tr);
- up_read(&sdp->sd_log_flush_lock);
if (atomic_read(&sdp->sd_log_pinned) > atomic_read(&sdp->sd_log_thresh1) ||
((sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free)) >
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index a5055977a214..7318abf9d0fb 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -53,8 +53,8 @@ void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
* to in-place disk block, remove it from the AIL.
*/
spin_lock(&sdp->sd_ail_lock);
- if (bd->bd_ail)
- list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+ if (bd->bd_tr)
+ list_move(&bd->bd_ail_st_list, &bd->bd_tr->tr_ail2_list);
spin_unlock(&sdp->sd_ail_lock);
get_bh(bh);
atomic_inc(&sdp->sd_log_pinned);
@@ -94,7 +94,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
*/
static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
- struct gfs2_ail *ai)
+ struct gfs2_trans *tr)
{
struct gfs2_bufdata *bd = bh->b_private;
@@ -109,7 +109,7 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
maybe_release_space(bd);
spin_lock(&sdp->sd_ail_lock);
- if (bd->bd_ail) {
+ if (bd->bd_tr) {
list_del(&bd->bd_ail_st_list);
brelse(bh);
} else {
@@ -117,8 +117,8 @@ static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
atomic_inc(&gl->gl_ail_count);
}
- bd->bd_ail = ai;
- list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+ bd->bd_tr = tr;
+ list_add(&bd->bd_ail_st_list, &tr->tr_ail1_list);
spin_unlock(&sdp->sd_ail_lock);
clear_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags);
@@ -480,17 +480,22 @@ static void buf_lo_before_commit(struct gfs2_sbd *sdp)
&sdp->sd_log_le_buf, 0);
}
-static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct list_head *head = &sdp->sd_log_le_buf;
struct gfs2_bufdata *bd;
+ if (tr == NULL) {
+ gfs2_assert(sdp, list_empty(head));
+ return;
+ }
+
while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata, bd_list);
list_del_init(&bd->bd_list);
sdp->sd_log_num_buf--;
- gfs2_unpin(sdp, bd->bd_bh, ai);
+ gfs2_unpin(sdp, bd->bd_bh, tr);
}
gfs2_assert_warn(sdp, !sdp->sd_log_num_buf);
}
@@ -613,7 +618,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
gfs2_log_write_page(sdp, page);
}
-static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct list_head *head = &sdp->sd_log_le_revoke;
struct gfs2_bufdata *bd;
@@ -791,16 +796,21 @@ static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
}
-static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
{
struct list_head *head = &sdp->sd_log_le_databuf;
struct gfs2_bufdata *bd;
+ if (tr == NULL) {
+ gfs2_assert(sdp, list_empty(head));
+ return;
+ }
+
while (!list_empty(head)) {
bd = list_entry(head->next, struct gfs2_bufdata, bd_list);
list_del_init(&bd->bd_list);
sdp->sd_log_num_databuf--;
- gfs2_unpin(sdp, bd->bd_bh, ai);
+ gfs2_unpin(sdp, bd->bd_bh, tr);
}
gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
}
diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
index ba77b7da8325..87e062e05c92 100644
--- a/fs/gfs2/lops.h
+++ b/fs/gfs2/lops.h
@@ -55,12 +55,13 @@ static inline void lops_before_commit(struct gfs2_sbd *sdp)
gfs2_log_ops[x]->lo_before_commit(sdp);
}
-static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+static inline void lops_after_commit(struct gfs2_sbd *sdp,
+ struct gfs2_trans *tr)
{
int x;
for (x = 0; gfs2_log_ops[x]; x++)
if (gfs2_log_ops[x]->lo_after_commit)
- gfs2_log_ops[x]->lo_after_commit(sdp, ai);
+ gfs2_log_ops[x]->lo_after_commit(sdp, tr);
}
static inline void lops_before_scan(struct gfs2_jdesc *jd,
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index b059bbb5059e..1a89afb68472 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -295,7 +295,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
}
if (bd) {
spin_lock(&sdp->sd_ail_lock);
- if (bd->bd_ail) {
+ if (bd->bd_tr) {
gfs2_remove_from_ail(bd);
bh->b_private = NULL;
bd->bd_bh = NULL;
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index d1f51fd73f86..0c5a575b513e 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -576,7 +576,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
RB_CLEAR_NODE(&ip->i_res->rs_node);
out:
up_write(&ip->i_rw_mutex);
- return 0;
+ return error;
}
static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
@@ -592,7 +592,7 @@ static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
* @rs: The reservation to remove
*
*/
-static void __rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
+static void __rs_deltree(struct gfs2_blkreserv *rs)
{
struct gfs2_rgrpd *rgd;
@@ -605,7 +605,7 @@ static void __rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
RB_CLEAR_NODE(&rs->rs_node);
if (rs->rs_free) {
- /* return reserved blocks to the rgrp and the ip */
+ /* return reserved blocks to the rgrp */
BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free);
rs->rs_rbm.rgd->rd_reserved -= rs->rs_free;
rs->rs_free = 0;
@@ -619,14 +619,14 @@ static void __rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
* @rs: The reservation to remove
*
*/
-void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
+void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
{
struct gfs2_rgrpd *rgd;
rgd = rs->rs_rbm.rgd;
if (rgd) {
spin_lock(&rgd->rd_rsspin);
- __rs_deltree(ip, rs);
+ __rs_deltree(rs);
spin_unlock(&rgd->rd_rsspin);
}
}
@@ -640,7 +640,7 @@ void gfs2_rs_delete(struct gfs2_inode *ip)
{
down_write(&ip->i_rw_mutex);
if (ip->i_res) {
- gfs2_rs_deltree(ip, ip->i_res);
+ gfs2_rs_deltree(ip->i_res);
BUG_ON(ip->i_res->rs_free);
kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
ip->i_res = NULL;
@@ -664,7 +664,7 @@ static void return_all_reservations(struct gfs2_rgrpd *rgd)
spin_lock(&rgd->rd_rsspin);
while ((n = rb_first(&rgd->rd_rstree))) {
rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
- __rs_deltree(NULL, rs);
+ __rs_deltree(rs);
}
spin_unlock(&rgd->rd_rsspin);
}
@@ -1181,12 +1181,9 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
{
struct super_block *sb = sdp->sd_vfs;
- struct block_device *bdev = sb->s_bdev;
- const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize /
- bdev_logical_block_size(sb->s_bdev);
u64 blk;
sector_t start = 0;
- sector_t nr_sects = 0;
+ sector_t nr_blks = 0;
int rv;
unsigned int x;
u32 trimmed = 0;
@@ -1206,35 +1203,34 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
if (diff == 0)
continue;
blk = offset + ((bi->bi_start + x) * GFS2_NBBY);
- blk *= sects_per_blk; /* convert to sectors */
while(diff) {
if (diff & 1) {
- if (nr_sects == 0)
+ if (nr_blks == 0)
goto start_new_extent;
- if ((start + nr_sects) != blk) {
- if (nr_sects >= minlen) {
- rv = blkdev_issue_discard(bdev,
- start, nr_sects,
+ if ((start + nr_blks) != blk) {
+ if (nr_blks >= minlen) {
+ rv = sb_issue_discard(sb,
+ start, nr_blks,
GFP_NOFS, 0);
if (rv)
goto fail;
- trimmed += nr_sects;
+ trimmed += nr_blks;
}
- nr_sects = 0;
+ nr_blks = 0;
start_new_extent:
start = blk;
}
- nr_sects += sects_per_blk;
+ nr_blks++;
}
diff >>= 2;
- blk += sects_per_blk;
+ blk++;
}
}
- if (nr_sects >= minlen) {
- rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
+ if (nr_blks >= minlen) {
+ rv = sb_issue_discard(sb, start, nr_blks, GFP_NOFS, 0);
if (rv)
goto fail;
- trimmed += nr_sects;
+ trimmed += nr_blks;
}
if (ptrimmed)
*ptrimmed = trimmed;
@@ -1878,7 +1874,7 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested, u32 aflags)
/* Drop reservation, if we couldn't use reserved rgrp */
if (gfs2_rs_active(rs))
- gfs2_rs_deltree(ip, rs);
+ gfs2_rs_deltree(rs);
check_rgrp:
/* Check for unlinked inodes which can be reclaimed */
if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK)
@@ -2091,7 +2087,7 @@ static void gfs2_adjust_reservation(struct gfs2_inode *ip,
if (rs->rs_free && !ret)
goto out;
}
- __rs_deltree(ip, rs);
+ __rs_deltree(rs);
}
out:
spin_unlock(&rgd->rd_rsspin);
@@ -2184,13 +2180,7 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
if (dinode)
gfs2_trans_add_unrevoke(sdp, block, 1);
- /*
- * This needs reviewing to see why we cannot do the quota change
- * at this point in the dinode case.
- */
- if (ndata)
- gfs2_quota_change(ip, ndata, ip->i_inode.i_uid,
- ip->i_inode.i_gid);
+ gfs2_quota_change(ip, *nblocks, ip->i_inode.i_uid, ip->i_inode.i_gid);
rbm.rgd->rd_free_clone -= *nblocks;
trace_gfs2_block_alloc(ip, rbm.rgd, block, *nblocks,
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index 842185853f6b..5b3f4a896e6c 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -47,7 +47,7 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
bool dinode, u64 *generation);
extern int gfs2_rs_alloc(struct gfs2_inode *ip);
-extern void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs);
+extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
extern void gfs2_rs_delete(struct gfs2_inode *ip);
extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index cab77b8ba84f..917c8e1eb4ae 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -1512,7 +1512,7 @@ out_truncate:
out_unlock:
/* Error path for case 1 */
if (gfs2_rs_active(ip->i_res))
- gfs2_rs_deltree(ip, ip->i_res);
+ gfs2_rs_deltree(ip->i_res);
if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
gfs2_glock_dq(&ip->i_iopen_gh);
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h
index 2ee13e841e9f..20c007d747ab 100644
--- a/fs/gfs2/trace_gfs2.h
+++ b/fs/gfs2/trace_gfs2.h
@@ -159,9 +159,9 @@ TRACE_EVENT(gfs2_glock_put,
/* Callback (local or remote) requesting lock demotion */
TRACE_EVENT(gfs2_demote_rq,
- TP_PROTO(const struct gfs2_glock *gl),
+ TP_PROTO(const struct gfs2_glock *gl, bool remote),
- TP_ARGS(gl),
+ TP_ARGS(gl, remote),
TP_STRUCT__entry(
__field( dev_t, dev )
@@ -170,6 +170,7 @@ TRACE_EVENT(gfs2_demote_rq,
__field( u8, cur_state )
__field( u8, dmt_state )
__field( unsigned long, flags )
+ __field( bool, remote )
),
TP_fast_assign(
@@ -179,14 +180,16 @@ TRACE_EVENT(gfs2_demote_rq,
__entry->cur_state = glock_trace_state(gl->gl_state);
__entry->dmt_state = glock_trace_state(gl->gl_demote_state);
__entry->flags = gl->gl_flags | (gl->gl_object ? (1UL<<GLF_OBJECT) : 0);
+ __entry->remote = remote;
),
- TP_printk("%u,%u glock %d:%lld demote %s to %s flags:%s",
+ TP_printk("%u,%u glock %d:%lld demote %s to %s flags:%s %s",
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
(unsigned long long)__entry->glnum,
glock_trace_name(__entry->cur_state),
glock_trace_name(__entry->dmt_state),
- show_glock_flags(__entry->flags))
+ show_glock_flags(__entry->flags),
+ __entry->remote ? "remote" : "local")
);
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index 88162fae27a5..7374907742a8 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -96,7 +96,8 @@ static void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
static void gfs2_print_trans(const struct gfs2_trans *tr)
{
- print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
+ printk(KERN_WARNING "GFS2: Transaction created at: %pSR\n",
+ (void *)tr->tr_ip);
printk(KERN_WARNING "GFS2: blocks=%u revokes=%u reserved=%u touched=%d\n",
tr->tr_blocks, tr->tr_revokes, tr->tr_reserved, tr->tr_touched);
printk(KERN_WARNING "GFS2: Buf %u/%u Databuf %u/%u Revoke %u/%u\n",
@@ -135,8 +136,10 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
if (tr->tr_t_gh.gh_gl) {
gfs2_glock_dq(&tr->tr_t_gh);
gfs2_holder_uninit(&tr->tr_t_gh);
- kfree(tr);
+ if (!tr->tr_attached)
+ kfree(tr);
}
+ up_read(&sdp->sd_log_flush_lock);
if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
gfs2_log_flush(sdp, NULL);
diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c
index 571abe97b42a..de69d8a24f6d 100644
--- a/fs/hfs/bfind.c
+++ b/fs/hfs/bfind.c
@@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
return -ENOMEM;
fd->search_key = ptr;
fd->key = ptr + tree->max_key_len + 2;
- dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
+ hfs_dbg(BNODE_REFS, "find_init: %d (%p)\n",
+ tree->cnid, __builtin_return_address(0));
mutex_lock(&tree->tree_lock);
return 0;
}
@@ -31,7 +32,8 @@ void hfs_find_exit(struct hfs_find_data *fd)
{
hfs_bnode_put(fd->bnode);
kfree(fd->search_key);
- dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
+ hfs_dbg(BNODE_REFS, "find_exit: %d (%p)\n",
+ fd->tree->cnid, __builtin_return_address(0));
mutex_unlock(&fd->tree->tree_lock);
fd->tree = NULL;
}
@@ -135,8 +137,8 @@ int hfs_brec_find(struct hfs_find_data *fd)
return res;
invalid:
- printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
- height, bnode->height, bnode->type, nidx, parent);
+ pr_err("inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
+ height, bnode->height, bnode->type, nidx, parent);
res = -EIO;
release:
hfs_bnode_put(bnode);
diff --git a/fs/hfs/bitmap.c b/fs/hfs/bitmap.c
index c6e97366e8ac..28307bc9ec1e 100644
--- a/fs/hfs/bitmap.c
+++ b/fs/hfs/bitmap.c
@@ -158,7 +158,7 @@ u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits)
}
}
- dprint(DBG_BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
+ hfs_dbg(BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
HFS_SB(sb)->free_ablocks -= *num_bits;
hfs_bitmap_dirty(sb);
out:
@@ -200,7 +200,7 @@ int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count)
if (!count)
return 0;
- dprint(DBG_BITMAP, "clear_bits: %u,%u\n", start, count);
+ hfs_dbg(BITMAP, "clear_bits: %u,%u\n", start, count);
/* are all of the bits in range? */
if ((start + count) > HFS_SB(sb)->fs_ablocks)
return -2;
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index cdb41a1f6a64..f3b1a15ccd59 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -100,7 +100,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
struct hfs_btree *tree;
struct page *src_page, *dst_page;
- dprint(DBG_BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
+ hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
if (!len)
return;
tree = src_node->tree;
@@ -120,7 +120,7 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
struct page *page;
void *ptr;
- dprint(DBG_BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
+ hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
if (!len)
return;
src += node->page_offset;
@@ -138,16 +138,16 @@ void hfs_bnode_dump(struct hfs_bnode *node)
__be32 cnid;
int i, off, key_off;
- dprint(DBG_BNODE_MOD, "bnode: %d\n", node->this);
+ hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
hfs_bnode_read(node, &desc, 0, sizeof(desc));
- dprint(DBG_BNODE_MOD, "%d, %d, %d, %d, %d\n",
+ hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
desc.type, desc.height, be16_to_cpu(desc.num_recs));
off = node->tree->node_size - 2;
for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
key_off = hfs_bnode_read_u16(node, off);
- dprint(DBG_BNODE_MOD, " %d", key_off);
+ hfs_dbg_cont(BNODE_MOD, " %d", key_off);
if (i && node->type == HFS_NODE_INDEX) {
int tmp;
@@ -155,17 +155,18 @@ void hfs_bnode_dump(struct hfs_bnode *node)
tmp = (hfs_bnode_read_u8(node, key_off) | 1) + 1;
else
tmp = node->tree->max_key_len + 1;
- dprint(DBG_BNODE_MOD, " (%d,%d", tmp, hfs_bnode_read_u8(node, key_off));
+ hfs_dbg_cont(BNODE_MOD, " (%d,%d",
+ tmp, hfs_bnode_read_u8(node, key_off));
hfs_bnode_read(node, &cnid, key_off + tmp, 4);
- dprint(DBG_BNODE_MOD, ",%d)", be32_to_cpu(cnid));
+ hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
} else if (i && node->type == HFS_NODE_LEAF) {
int tmp;
tmp = hfs_bnode_read_u8(node, key_off);
- dprint(DBG_BNODE_MOD, " (%d)", tmp);
+ hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
}
}
- dprint(DBG_BNODE_MOD, "\n");
+ hfs_dbg_cont(BNODE_MOD, "\n");
}
void hfs_bnode_unlink(struct hfs_bnode *node)
@@ -220,7 +221,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
struct hfs_bnode *node;
if (cnid >= tree->node_count) {
- printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+ pr_err("request for non-existent node %d in B*Tree\n", cnid);
return NULL;
}
@@ -243,7 +244,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
loff_t off;
if (cnid >= tree->node_count) {
- printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid);
+ pr_err("request for non-existent node %d in B*Tree\n", cnid);
return NULL;
}
@@ -257,8 +258,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
node->this = cnid;
set_bit(HFS_BNODE_NEW, &node->flags);
atomic_set(&node->refcnt, 1);
- dprint(DBG_BNODE_REFS, "new_node(%d:%d): 1\n",
- node->tree->cnid, node->this);
+ hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
+ node->tree->cnid, node->this);
init_waitqueue_head(&node->lock_wq);
spin_lock(&tree->hash_lock);
node2 = hfs_bnode_findhash(tree, cnid);
@@ -301,7 +302,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
{
struct hfs_bnode **p;
- dprint(DBG_BNODE_REFS, "remove_node(%d:%d): %d\n",
+ hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
node->tree->cnid, node->this, atomic_read(&node->refcnt));
for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
*p && *p != node; p = &(*p)->next_hash)
@@ -443,8 +444,9 @@ void hfs_bnode_get(struct hfs_bnode *node)
{
if (node) {
atomic_inc(&node->refcnt);
- dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
- node->tree->cnid, node->this, atomic_read(&node->refcnt));
+ hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
+ node->tree->cnid, node->this,
+ atomic_read(&node->refcnt));
}
}
@@ -455,8 +457,9 @@ void hfs_bnode_put(struct hfs_bnode *node)
struct hfs_btree *tree = node->tree;
int i;
- dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
- node->tree->cnid, node->this, atomic_read(&node->refcnt));
+ hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
+ node->tree->cnid, node->this,
+ atomic_read(&node->refcnt));
BUG_ON(!atomic_read(&node->refcnt));
if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
return;
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c
index 92fb358ce824..9f4ee7f52026 100644
--- a/fs/hfs/brec.c
+++ b/fs/hfs/brec.c
@@ -47,15 +47,13 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
if (node->tree->attributes & HFS_TREE_BIGKEYS) {
retval = hfs_bnode_read_u16(node, recoff) + 2;
if (retval > node->tree->max_key_len + 2) {
- printk(KERN_ERR "hfs: keylen %d too large\n",
- retval);
+ pr_err("keylen %d too large\n", retval);
retval = 0;
}
} else {
retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
if (retval > node->tree->max_key_len + 1) {
- printk(KERN_ERR "hfs: keylen %d too large\n",
- retval);
+ pr_err("keylen %d too large\n", retval);
retval = 0;
}
}
@@ -94,7 +92,8 @@ again:
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
end_off = hfs_bnode_read_u16(node, end_rec_off);
end_rec_off -= 2;
- dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off);
+ hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
+ rec, size, end_off, end_rec_off);
if (size > end_rec_off - end_off) {
if (new_node)
panic("not enough room!\n");
@@ -190,7 +189,8 @@ again:
mark_inode_dirty(tree->inode);
}
hfs_bnode_dump(node);
- dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength);
+ hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
+ fd->record, fd->keylength + fd->entrylength);
if (!--node->num_recs) {
hfs_bnode_unlink(node);
if (!node->parent)
@@ -240,7 +240,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
if (IS_ERR(new_node))
return new_node;
hfs_bnode_get(node);
- dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
+ hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
node->this, new_node->this, node->next);
new_node->next = node->next;
new_node->prev = node->this;
@@ -374,7 +374,8 @@ again:
newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
else
fd->keylength = newkeylen = tree->max_key_len + 1;
- dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen);
+ hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
+ rec, fd->keylength, newkeylen);
rec_off = tree->node_size - (rec + 2) * 2;
end_rec_off = tree->node_size - (parent->num_recs + 1) * 2;
@@ -385,7 +386,7 @@ again:
end_off = hfs_bnode_read_u16(parent, end_rec_off);
if (end_rec_off - end_off < diff) {
- printk(KERN_DEBUG "hfs: splitting index node...\n");
+ printk(KERN_DEBUG "splitting index node...\n");
fd->bnode = parent;
new_node = hfs_bnode_split(fd);
if (IS_ERR(new_node))
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 1cbdeea1db44..1ab19e660e69 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -48,7 +48,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
if (HFS_I(tree->inode)->alloc_blocks >
HFS_I(tree->inode)->first_blocks) {
- printk(KERN_ERR "hfs: invalid btree extent records\n");
+ pr_err("invalid btree extent records\n");
unlock_new_inode(tree->inode);
goto free_inode;
}
@@ -60,8 +60,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
if (!HFS_I(tree->inode)->first_blocks) {
- printk(KERN_ERR "hfs: invalid btree extent records "
- "(0 size).\n");
+ pr_err("invalid btree extent records (0 size)\n");
unlock_new_inode(tree->inode);
goto free_inode;
}
@@ -100,15 +99,15 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
switch (id) {
case HFS_EXT_CNID:
if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) {
- printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
- tree->max_key_len);
+ pr_err("invalid extent max_key_len %d\n",
+ tree->max_key_len);
goto fail_page;
}
break;
case HFS_CAT_CNID:
if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) {
- printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
- tree->max_key_len);
+ pr_err("invalid catalog max_key_len %d\n",
+ tree->max_key_len);
goto fail_page;
}
break;
@@ -146,8 +145,9 @@ void hfs_btree_close(struct hfs_btree *tree)
while ((node = tree->node_hash[i])) {
tree->node_hash[i] = node->next_hash;
if (atomic_read(&node->refcnt))
- printk(KERN_ERR "hfs: node %d:%d still has %d user(s)!\n",
- node->tree->cnid, node->this, atomic_read(&node->refcnt));
+ pr_err("node %d:%d still has %d user(s)!\n",
+ node->tree->cnid, node->this,
+ atomic_read(&node->refcnt));
hfs_bnode_free(node);
tree->node_hash_cnt--;
}
@@ -290,7 +290,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
kunmap(*pagep);
nidx = node->next;
if (!nidx) {
- printk(KERN_DEBUG "hfs: create new bmap node...\n");
+ printk(KERN_DEBUG "create new bmap node...\n");
next_node = hfs_bmap_new_bmap(node, idx);
} else
next_node = hfs_bnode_find(tree, nidx);
@@ -316,7 +316,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
u32 nidx;
u8 *data, byte, m;
- dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
+ hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
tree = node->tree;
nidx = node->this;
node = hfs_bnode_find(tree, 0);
@@ -331,7 +331,8 @@ void hfs_bmap_free(struct hfs_bnode *node)
hfs_bnode_put(node);
if (!i) {
/* panic */;
- printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this);
+ pr_crit("unable to free bnode %u. bmap not found!\n",
+ node->this);
return;
}
node = hfs_bnode_find(tree, i);
@@ -339,7 +340,8 @@ void hfs_bmap_free(struct hfs_bnode *node)
return;
if (node->type != HFS_NODE_MAP) {
/* panic */;
- printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type);
+ pr_crit("invalid bmap found! (%u,%d)\n",
+ node->this, node->type);
hfs_bnode_put(node);
return;
}
@@ -352,7 +354,8 @@ void hfs_bmap_free(struct hfs_bnode *node)
m = 1 << (~nidx & 7);
byte = data[off];
if (!(byte & m)) {
- printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type);
+ pr_crit("trying to free free bnode %u(%d)\n",
+ node->this, node->type);
kunmap(page);
hfs_bnode_put(node);
return;
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index 424b0337f524..ff0316b925a5 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -87,12 +87,15 @@ int hfs_cat_create(u32 cnid, struct inode *dir, struct qstr *str, struct inode *
int entry_size;
int err;
- dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
+ hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
+ str->name, cnid, inode->i_nlink);
if (dir->i_size >= HFS_MAX_VALENCE)
return -ENOSPC;
sb = dir->i_sb;
- hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ if (err)
+ return err;
hfs_cat_build_key(sb, fd.search_key, cnid, NULL);
entry_size = hfs_cat_build_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
@@ -184,14 +187,14 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
type = rec.type;
if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
- printk(KERN_ERR "hfs: found bad thread record in catalog\n");
+ pr_err("found bad thread record in catalog\n");
return -EIO;
}
fd->search_key->cat.ParID = rec.thread.ParID;
len = fd->search_key->cat.CName.len = rec.thread.CName.len;
if (len > HFS_NAMELEN) {
- printk(KERN_ERR "hfs: bad catalog namelength\n");
+ pr_err("bad catalog namelength\n");
return -EIO;
}
memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
@@ -212,9 +215,11 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, struct qstr *str)
struct list_head *pos;
int res, type;
- dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
+ hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
sb = dir->i_sb;
- hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ if (res)
+ return res;
hfs_cat_build_key(sb, fd.search_key, dir->i_ino, str);
res = hfs_brec_find(&fd);
@@ -278,10 +283,13 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, struct qstr *src_name,
int entry_size, type;
int err;
- dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
+ hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
+ cnid, src_dir->i_ino, src_name->name,
dst_dir->i_ino, dst_name->name);
sb = src_dir->i_sb;
- hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
+ err = hfs_find_init(HFS_SB(sb)->cat_tree, &src_fd);
+ if (err)
+ return err;
dst_fd = src_fd;
/* find the old dir entry and read the data */
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 5f7f1abd5f6d..17c22a8fd40a 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -25,7 +25,9 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
struct inode *inode = NULL;
int res;
- hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+ res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+ if (res)
+ return ERR_PTR(res);
hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name);
res = hfs_brec_read(&fd, &rec, sizeof(rec));
if (res) {
@@ -63,7 +65,9 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (filp->f_pos >= inode->i_size)
return 0;
- hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ err = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ if (err)
+ return err;
hfs_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
err = hfs_brec_find(&fd);
if (err)
@@ -84,12 +88,12 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength);
if (entry.type != HFS_CDR_THD) {
- printk(KERN_ERR "hfs: bad catalog folder thread\n");
+ pr_err("bad catalog folder thread\n");
err = -EIO;
goto out;
}
//if (fd.entrylength < HFS_MIN_THREAD_SZ) {
- // printk(KERN_ERR "hfs: truncated catalog thread\n");
+ // pr_err("truncated catalog thread\n");
// err = -EIO;
// goto out;
//}
@@ -108,7 +112,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
for (;;) {
if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) {
- printk(KERN_ERR "hfs: walked past end of dir\n");
+ pr_err("walked past end of dir\n");
err = -EIO;
goto out;
}
@@ -123,7 +127,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName);
if (type == HFS_CDR_DIR) {
if (fd.entrylength < sizeof(struct hfs_cat_dir)) {
- printk(KERN_ERR "hfs: small dir entry\n");
+ pr_err("small dir entry\n");
err = -EIO;
goto out;
}
@@ -132,7 +136,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
} else if (type == HFS_CDR_FIL) {
if (fd.entrylength < sizeof(struct hfs_cat_file)) {
- printk(KERN_ERR "hfs: small file entry\n");
+ pr_err("small file entry\n");
err = -EIO;
goto out;
}
@@ -140,7 +144,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
be32_to_cpu(entry.file.FlNum), DT_REG))
break;
} else {
- printk(KERN_ERR "hfs: bad catalog entry type %d\n", type);
+ pr_err("bad catalog entry type %d\n", type);
err = -EIO;
goto out;
}
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c
index a67955a0c36f..e33a0d36a93e 100644
--- a/fs/hfs/extent.c
+++ b/fs/hfs/extent.c
@@ -107,7 +107,7 @@ static u16 hfs_ext_lastblock(struct hfs_extent *ext)
return be16_to_cpu(ext->block) + be16_to_cpu(ext->count);
}
-static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
+static int __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
{
int res;
@@ -116,26 +116,31 @@ static void __hfs_ext_write_extent(struct inode *inode, struct hfs_find_data *fd
res = hfs_brec_find(fd);
if (HFS_I(inode)->flags & HFS_FLG_EXT_NEW) {
if (res != -ENOENT)
- return;
+ return res;
hfs_brec_insert(fd, HFS_I(inode)->cached_extents, sizeof(hfs_extent_rec));
HFS_I(inode)->flags &= ~(HFS_FLG_EXT_DIRTY|HFS_FLG_EXT_NEW);
} else {
if (res)
- return;
+ return res;
hfs_bnode_write(fd->bnode, HFS_I(inode)->cached_extents, fd->entryoffset, fd->entrylength);
HFS_I(inode)->flags &= ~HFS_FLG_EXT_DIRTY;
}
+ return 0;
}
-void hfs_ext_write_extent(struct inode *inode)
+int hfs_ext_write_extent(struct inode *inode)
{
struct hfs_find_data fd;
+ int res = 0;
if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) {
- hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
- __hfs_ext_write_extent(inode, &fd);
+ res = hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
+ if (res)
+ return res;
+ res = __hfs_ext_write_extent(inode, &fd);
hfs_find_exit(&fd);
}
+ return res;
}
static inline int __hfs_ext_read_extent(struct hfs_find_data *fd, struct hfs_extent *extent,
@@ -161,8 +166,11 @@ static inline int __hfs_ext_cache_extent(struct hfs_find_data *fd, struct inode
{
int res;
- if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY)
- __hfs_ext_write_extent(inode, fd);
+ if (HFS_I(inode)->flags & HFS_FLG_EXT_DIRTY) {
+ res = __hfs_ext_write_extent(inode, fd);
+ if (res)
+ return res;
+ }
res = __hfs_ext_read_extent(fd, HFS_I(inode)->cached_extents, inode->i_ino,
block, HFS_IS_RSRC(inode) ? HFS_FK_RSRC : HFS_FK_DATA);
@@ -185,9 +193,11 @@ static int hfs_ext_read_extent(struct inode *inode, u16 block)
block < HFS_I(inode)->cached_start + HFS_I(inode)->cached_blocks)
return 0;
- hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
- res = __hfs_ext_cache_extent(&fd, inode, block);
- hfs_find_exit(&fd);
+ res = hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd);
+ if (!res) {
+ res = __hfs_ext_cache_extent(&fd, inode, block);
+ hfs_find_exit(&fd);
+ }
return res;
}
@@ -195,11 +205,12 @@ static void hfs_dump_extent(struct hfs_extent *extent)
{
int i;
- dprint(DBG_EXTENT, " ");
+ hfs_dbg(EXTENT, " ");
for (i = 0; i < 3; i++)
- dprint(DBG_EXTENT, " %u:%u", be16_to_cpu(extent[i].block),
- be16_to_cpu(extent[i].count));
- dprint(DBG_EXTENT, "\n");
+ hfs_dbg_cont(EXTENT, " %u:%u",
+ be16_to_cpu(extent[i].block),
+ be16_to_cpu(extent[i].count));
+ hfs_dbg_cont(EXTENT, "\n");
}
static int hfs_add_extent(struct hfs_extent *extent, u16 offset,
@@ -298,7 +309,9 @@ int hfs_free_fork(struct super_block *sb, struct hfs_cat_file *file, int type)
if (total_blocks == blocks)
return 0;
- hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+ res = hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+ if (res)
+ return res;
do {
res = __hfs_ext_read_extent(&fd, extent, cnid, total_blocks, type);
if (res)
@@ -392,10 +405,10 @@ int hfs_extend_file(struct inode *inode)
goto out;
}
- dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
+ hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) {
if (!HFS_I(inode)->first_blocks) {
- dprint(DBG_EXTENT, "first extents\n");
+ hfs_dbg(EXTENT, "first extents\n");
/* no extents yet */
HFS_I(inode)->first_extents[0].block = cpu_to_be16(start);
HFS_I(inode)->first_extents[0].count = cpu_to_be16(len);
@@ -437,8 +450,10 @@ out:
return res;
insert_extent:
- dprint(DBG_EXTENT, "insert new extent\n");
- hfs_ext_write_extent(inode);
+ hfs_dbg(EXTENT, "insert new extent\n");
+ res = hfs_ext_write_extent(inode);
+ if (res)
+ goto out;
memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec));
HFS_I(inode)->cached_extents[0].block = cpu_to_be16(start);
@@ -460,13 +475,13 @@ void hfs_file_truncate(struct inode *inode)
u32 size;
int res;
- dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino,
- (long long)HFS_I(inode)->phys_size, inode->i_size);
+ hfs_dbg(INODE, "truncate: %lu, %Lu -> %Lu\n",
+ inode->i_ino, (long long)HFS_I(inode)->phys_size,
+ inode->i_size);
if (inode->i_size > HFS_I(inode)->phys_size) {
struct address_space *mapping = inode->i_mapping;
void *fsdata;
struct page *page;
- int res;
/* XXX: Can use generic_cont_expand? */
size = inode->i_size - 1;
@@ -488,7 +503,12 @@ void hfs_file_truncate(struct inode *inode)
goto out;
mutex_lock(&HFS_I(inode)->extents_lock);
- hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+ res = hfs_find_init(HFS_SB(sb)->ext_tree, &fd);
+ if (res) {
+ mutex_unlock(&HFS_I(inode)->extents_lock);
+ /* XXX: We lack error handling of hfs_file_truncate() */
+ return;
+ }
while (1) {
if (alloc_cnt == HFS_I(inode)->first_blocks) {
hfs_free_extents(sb, HFS_I(inode)->first_extents,
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 693df9fe52b2..a73b11839a41 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -9,6 +9,12 @@
#ifndef _LINUX_HFS_FS_H
#define _LINUX_HFS_FS_H
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mutex.h>
@@ -34,8 +40,18 @@
//#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
#define DBG_MASK (0)
-#define dprint(flg, fmt, args...) \
- if (flg & DBG_MASK) printk(fmt , ## args)
+#define hfs_dbg(flg, fmt, ...) \
+do { \
+ if (DBG_##flg & DBG_MASK) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
+} while (0)
+
+#define hfs_dbg_cont(flg, fmt, ...) \
+do { \
+ if (DBG_##flg & DBG_MASK) \
+ pr_cont(fmt, ##__VA_ARGS__); \
+} while (0)
+
/*
* struct hfs_inode_info
@@ -174,7 +190,7 @@ extern const struct inode_operations hfs_dir_inode_operations;
/* extent.c */
extern int hfs_ext_keycmp(const btree_key *, const btree_key *);
extern int hfs_free_fork(struct super_block *, struct hfs_cat_file *, int);
-extern void hfs_ext_write_extent(struct inode *);
+extern int hfs_ext_write_extent(struct inode *);
extern int hfs_extend_file(struct inode *);
extern void hfs_file_truncate(struct inode *);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 3031dfdd2358..716e1aafb2e2 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -237,7 +237,7 @@ void hfs_delete_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
- dprint(DBG_INODE, "delete_inode: %lu\n", inode->i_ino);
+ hfs_dbg(INODE, "delete_inode: %lu\n", inode->i_ino);
if (S_ISDIR(inode->i_mode)) {
HFS_SB(sb)->folder_count--;
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
@@ -416,9 +416,12 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
struct inode *main_inode = inode;
struct hfs_find_data fd;
hfs_cat_rec rec;
+ int res;
- dprint(DBG_INODE, "hfs_write_inode: %lu\n", inode->i_ino);
- hfs_ext_write_extent(inode);
+ hfs_dbg(INODE, "hfs_write_inode: %lu\n", inode->i_ino);
+ res = hfs_ext_write_extent(inode);
+ if (res)
+ return res;
if (inode->i_ino < HFS_FIRSTUSER_CNID) {
switch (inode->i_ino) {
@@ -515,7 +518,11 @@ static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
if (!inode)
return ERR_PTR(-ENOMEM);
- hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+ res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd);
+ if (res) {
+ iput(inode);
+ return ERR_PTR(res);
+ }
fd.search_key->cat = HFS_I(dir)->cat_key;
res = hfs_brec_read(&fd, &rec, sizeof(rec));
if (!res) {
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index b7ec224910c5..aa3f0d6d043c 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -48,7 +48,7 @@ static int hfs_get_last_session(struct super_block *sb,
*start = (sector_t)te.cdte_addr.lba << 2;
return 0;
}
- printk(KERN_ERR "hfs: invalid session number or type of track\n");
+ pr_err("invalid session number or type of track\n");
return -EINVAL;
}
ms_info.addr_format = CDROM_LBA;
@@ -101,7 +101,7 @@ int hfs_mdb_get(struct super_block *sb)
HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz);
if (!size || (size & (HFS_SECTOR_SIZE - 1))) {
- printk(KERN_ERR "hfs: bad allocation block size %d\n", size);
+ pr_err("bad allocation block size %d\n", size);
goto out_bh;
}
@@ -118,7 +118,7 @@ int hfs_mdb_get(struct super_block *sb)
size >>= 1;
brelse(bh);
if (!sb_set_blocksize(sb, size)) {
- printk(KERN_ERR "hfs: unable to set blocksize to %u\n", size);
+ pr_err("unable to set blocksize to %u\n", size);
goto out;
}
@@ -162,8 +162,8 @@ int hfs_mdb_get(struct super_block *sb)
}
if (!HFS_SB(sb)->alt_mdb) {
- printk(KERN_WARNING "hfs: unable to locate alternate MDB\n");
- printk(KERN_WARNING "hfs: continuing without an alternate MDB\n");
+ pr_warn("unable to locate alternate MDB\n");
+ pr_warn("continuing without an alternate MDB\n");
}
HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0);
@@ -178,7 +178,7 @@ int hfs_mdb_get(struct super_block *sb)
while (size) {
bh = sb_bread(sb, off >> sb->s_blocksize_bits);
if (!bh) {
- printk(KERN_ERR "hfs: unable to read volume bitmap\n");
+ pr_err("unable to read volume bitmap\n");
goto out;
}
off2 = off & (sb->s_blocksize - 1);
@@ -192,23 +192,22 @@ int hfs_mdb_get(struct super_block *sb)
HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp);
if (!HFS_SB(sb)->ext_tree) {
- printk(KERN_ERR "hfs: unable to open extent tree\n");
+ pr_err("unable to open extent tree\n");
goto out;
}
HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp);
if (!HFS_SB(sb)->cat_tree) {
- printk(KERN_ERR "hfs: unable to open catalog tree\n");
+ pr_err("unable to open catalog tree\n");
goto out;
}
attrib = mdb->drAtrb;
if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
- printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
- "running fsck.hfs is recommended. mounting read-only.\n");
+ pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
}
if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
- printk(KERN_WARNING "hfs: filesystem is marked locked, mounting read-only.\n");
+ pr_warn("filesystem is marked locked, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
}
if (!(sb->s_flags & MS_RDONLY)) {
@@ -312,7 +311,7 @@ void hfs_mdb_commit(struct super_block *sb)
while (size) {
bh = sb_bread(sb, block);
if (!bh) {
- printk(KERN_ERR "hfs: unable to read volume bitmap\n");
+ pr_err("unable to read volume bitmap\n");
break;
}
len = min((int)sb->s_blocksize - off, size);
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index bbaaa8a4ee64..2d2039e754cd 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -117,12 +117,11 @@ static int hfs_remount(struct super_block *sb, int *flags, char *data)
return 0;
if (!(*flags & MS_RDONLY)) {
if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
- printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, "
- "running fsck.hfs is recommended. leaving read-only.\n");
+ pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. leaving read-only.\n");
sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY;
} else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) {
- printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
+ pr_warn("filesystem is marked locked, leaving read-only.\n");
sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY;
}
@@ -253,29 +252,29 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
switch (token) {
case opt_uid:
if (match_int(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: uid requires an argument\n");
+ pr_err("uid requires an argument\n");
return 0;
}
hsb->s_uid = make_kuid(current_user_ns(), (uid_t)tmp);
if (!uid_valid(hsb->s_uid)) {
- printk(KERN_ERR "hfs: invalid uid %d\n", tmp);
+ pr_err("invalid uid %d\n", tmp);
return 0;
}
break;
case opt_gid:
if (match_int(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: gid requires an argument\n");
+ pr_err("gid requires an argument\n");
return 0;
}
hsb->s_gid = make_kgid(current_user_ns(), (gid_t)tmp);
if (!gid_valid(hsb->s_gid)) {
- printk(KERN_ERR "hfs: invalid gid %d\n", tmp);
+ pr_err("invalid gid %d\n", tmp);
return 0;
}
break;
case opt_umask:
if (match_octal(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: umask requires a value\n");
+ pr_err("umask requires a value\n");
return 0;
}
hsb->s_file_umask = (umode_t)tmp;
@@ -283,39 +282,39 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
break;
case opt_file_umask:
if (match_octal(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: file_umask requires a value\n");
+ pr_err("file_umask requires a value\n");
return 0;
}
hsb->s_file_umask = (umode_t)tmp;
break;
case opt_dir_umask:
if (match_octal(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: dir_umask requires a value\n");
+ pr_err("dir_umask requires a value\n");
return 0;
}
hsb->s_dir_umask = (umode_t)tmp;
break;
case opt_part:
if (match_int(&args[0], &hsb->part)) {
- printk(KERN_ERR "hfs: part requires an argument\n");
+ pr_err("part requires an argument\n");
return 0;
}
break;
case opt_session:
if (match_int(&args[0], &hsb->session)) {
- printk(KERN_ERR "hfs: session requires an argument\n");
+ pr_err("session requires an argument\n");
return 0;
}
break;
case opt_type:
if (match_fourchar(&args[0], &hsb->s_type)) {
- printk(KERN_ERR "hfs: type requires a 4 character value\n");
+ pr_err("type requires a 4 character value\n");
return 0;
}
break;
case opt_creator:
if (match_fourchar(&args[0], &hsb->s_creator)) {
- printk(KERN_ERR "hfs: creator requires a 4 character value\n");
+ pr_err("creator requires a 4 character value\n");
return 0;
}
break;
@@ -324,14 +323,14 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
break;
case opt_codepage:
if (hsb->nls_disk) {
- printk(KERN_ERR "hfs: unable to change codepage\n");
+ pr_err("unable to change codepage\n");
return 0;
}
p = match_strdup(&args[0]);
if (p)
hsb->nls_disk = load_nls(p);
if (!hsb->nls_disk) {
- printk(KERN_ERR "hfs: unable to load codepage \"%s\"\n", p);
+ pr_err("unable to load codepage \"%s\"\n", p);
kfree(p);
return 0;
}
@@ -339,14 +338,14 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
break;
case opt_iocharset:
if (hsb->nls_io) {
- printk(KERN_ERR "hfs: unable to change iocharset\n");
+ pr_err("unable to change iocharset\n");
return 0;
}
p = match_strdup(&args[0]);
if (p)
hsb->nls_io = load_nls(p);
if (!hsb->nls_io) {
- printk(KERN_ERR "hfs: unable to load iocharset \"%s\"\n", p);
+ pr_err("unable to load iocharset \"%s\"\n", p);
kfree(p);
return 0;
}
@@ -360,7 +359,7 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
if (hsb->nls_disk && !hsb->nls_io) {
hsb->nls_io = load_nls_default();
if (!hsb->nls_io) {
- printk(KERN_ERR "hfs: unable to load default iocharset\n");
+ pr_err("unable to load default iocharset\n");
return 0;
}
}
@@ -400,7 +399,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
res = -EINVAL;
if (!parse_options((char *)data, sbi)) {
- printk(KERN_ERR "hfs: unable to parse mount options.\n");
+ pr_err("unable to parse mount options\n");
goto bail;
}
@@ -411,14 +410,16 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
res = hfs_mdb_get(sb);
if (res) {
if (!silent)
- printk(KERN_WARNING "hfs: can't find a HFS filesystem on dev %s.\n",
+ pr_warn("can't find a HFS filesystem on dev %s\n",
hfs_mdb_name(sb));
res = -EINVAL;
goto bail;
}
/* try to get the root inode */
- hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
+ if (res)
+ goto bail_no_root;
res = hfs_cat_find_brec(sb, HFS_ROOT_CNID, &fd);
if (!res) {
if (fd.entrylength > sizeof(rec) || fd.entrylength < 0) {
@@ -447,7 +448,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
bail_no_root:
- printk(KERN_ERR "hfs: get root inode failed.\n");
+ pr_err("get root inode failed\n");
bail:
hfs_mdb_put(sb);
return res;
diff --git a/fs/hfsplus/attributes.c b/fs/hfsplus/attributes.c
index 8d691f124714..0f47890299c4 100644
--- a/fs/hfsplus/attributes.c
+++ b/fs/hfsplus/attributes.c
@@ -56,7 +56,7 @@ int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key,
if (name) {
len = strlen(name);
if (len > HFSPLUS_ATTR_MAX_STRLEN) {
- printk(KERN_ERR "hfs: invalid xattr name's length\n");
+ pr_err("invalid xattr name's length\n");
return -EINVAL;
}
hfsplus_asc2uni(sb,
@@ -166,10 +166,10 @@ int hfsplus_find_attr(struct super_block *sb, u32 cnid,
{
int err = 0;
- dprint(DBG_ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
+ hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
if (!HFSPLUS_SB(sb)->attr_tree) {
- printk(KERN_ERR "hfs: attributes file doesn't exist\n");
+ pr_err("attributes file doesn't exist\n");
return -EINVAL;
}
@@ -228,11 +228,11 @@ int hfsplus_create_attr(struct inode *inode,
int entry_size;
int err;
- dprint(DBG_ATTR_MOD, "create_attr: %s,%ld\n",
+ hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n",
name ? name : NULL, inode->i_ino);
if (!HFSPLUS_SB(sb)->attr_tree) {
- printk(KERN_ERR "hfs: attributes file doesn't exist\n");
+ pr_err("attributes file doesn't exist\n");
return -EINVAL;
}
@@ -307,10 +307,10 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
break;
case HFSPLUS_ATTR_FORK_DATA:
case HFSPLUS_ATTR_EXTENTS:
- printk(KERN_ERR "hfs: only inline data xattr are supported\n");
+ pr_err("only inline data xattr are supported\n");
return -EOPNOTSUPP;
default:
- printk(KERN_ERR "hfs: invalid extended attribute record\n");
+ pr_err("invalid extended attribute record\n");
return -ENOENT;
}
@@ -328,11 +328,11 @@ int hfsplus_delete_attr(struct inode *inode, const char *name)
struct super_block *sb = inode->i_sb;
struct hfs_find_data fd;
- dprint(DBG_ATTR_MOD, "delete_attr: %s,%ld\n",
+ hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n",
name ? name : NULL, inode->i_ino);
if (!HFSPLUS_SB(sb)->attr_tree) {
- printk(KERN_ERR "hfs: attributes file doesn't exist\n");
+ pr_err("attributes file doesn't exist\n");
return -EINVAL;
}
@@ -346,7 +346,7 @@ int hfsplus_delete_attr(struct inode *inode, const char *name)
if (err)
goto out;
} else {
- printk(KERN_ERR "hfs: invalid extended attribute name\n");
+ pr_err("invalid extended attribute name\n");
err = -EINVAL;
goto out;
}
@@ -369,10 +369,10 @@ int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
int err = 0;
struct hfs_find_data fd;
- dprint(DBG_ATTR_MOD, "delete_all_attrs: %d\n", cnid);
+ hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid);
if (!HFSPLUS_SB(dir->i_sb)->attr_tree) {
- printk(KERN_ERR "hfs: attributes file doesn't exist\n");
+ pr_err("attributes file doesn't exist\n");
return -EINVAL;
}
@@ -384,7 +384,7 @@ int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
if (err) {
if (err != -ENOENT)
- printk(KERN_ERR "hfs: xattr search failed.\n");
+ pr_err("xattr search failed\n");
goto end_delete_all;
}
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
index d73c98d1ee99..c1422d91cd36 100644
--- a/fs/hfsplus/bfind.c
+++ b/fs/hfsplus/bfind.c
@@ -22,7 +22,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
return -ENOMEM;
fd->search_key = ptr;
fd->key = ptr + tree->max_key_len + 2;
- dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n",
+ hfs_dbg(BNODE_REFS, "find_init: %d (%p)\n",
tree->cnid, __builtin_return_address(0));
switch (tree->cnid) {
case HFSPLUS_CAT_CNID:
@@ -44,7 +44,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
{
hfs_bnode_put(fd->bnode);
kfree(fd->search_key);
- dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n",
+ hfs_dbg(BNODE_REFS, "find_exit: %d (%p)\n",
fd->tree->cnid, __builtin_return_address(0));
mutex_unlock(&fd->tree->tree_lock);
fd->tree = NULL;
@@ -56,7 +56,8 @@ int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode,
int *end,
int *cur_rec)
{
- __be32 cur_cnid, search_cnid;
+ __be32 cur_cnid;
+ __be32 search_cnid;
if (bnode->tree->cnid == HFSPLUS_EXT_CNID) {
cur_cnid = fd->key->ext.cnid;
@@ -67,8 +68,11 @@ int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode,
} else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) {
cur_cnid = fd->key->attr.cnid;
search_cnid = fd->search_key->attr.cnid;
- } else
+ } else {
+ cur_cnid = 0; /* used-uninitialized warning */
+ search_cnid = 0;
BUG();
+ }
if (cur_cnid == search_cnid) {
(*end) = (*cur_rec);
@@ -204,7 +208,7 @@ int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare)
return res;
invalid:
- printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
+ pr_err("inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
height, bnode->height, bnode->type, nidx, parent);
res = -EIO;
release:
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index 6feefc0cb48a..d2954451519e 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -30,7 +30,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size,
if (!len)
return size;
- dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
+ hfs_dbg(BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
mutex_lock(&sbi->alloc_mutex);
mapping = sbi->alloc_file->i_mapping;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
@@ -89,14 +89,14 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size,
else
end = pptr + ((size + 31) & (PAGE_CACHE_BITS - 1)) / 32;
}
- dprint(DBG_BITMAP, "bitmap full\n");
+ hfs_dbg(BITMAP, "bitmap full\n");
start = size;
goto out;
found:
start = offset + (curr - pptr) * 32 + i;
if (start >= size) {
- dprint(DBG_BITMAP, "bitmap full\n");
+ hfs_dbg(BITMAP, "bitmap full\n");
goto out;
}
/* do any partial u32 at the start */
@@ -154,7 +154,7 @@ done:
*max = offset + (curr - pptr) * 32 + i - start;
sbi->free_blocks -= *max;
hfsplus_mark_mdb_dirty(sb);
- dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
+ hfs_dbg(BITMAP, "-> %u,%u\n", start, *max);
out:
mutex_unlock(&sbi->alloc_mutex);
return start;
@@ -173,7 +173,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
if (!count)
return 0;
- dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
+ hfs_dbg(BITMAP, "block_free: %u,%u\n", offset, count);
/* are all of the bits in range? */
if ((offset + count) > sbi->total_blocks)
return -ENOENT;
@@ -238,8 +238,7 @@ out:
return 0;
kaboom:
- printk(KERN_CRIT "hfsplus: unable to mark blocks free: error %ld\n",
- PTR_ERR(page));
+ pr_crit("unable to mark blocks free: error %ld\n", PTR_ERR(page));
mutex_unlock(&sbi->alloc_mutex);
return -EIO;
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index f31ac6f404f1..11c860204520 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -130,7 +130,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
struct page **src_page, **dst_page;
int l;
- dprint(DBG_BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
+ hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
if (!len)
return;
tree = src_node->tree;
@@ -188,7 +188,7 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
struct page **src_page, **dst_page;
int l;
- dprint(DBG_BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
+ hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
if (!len)
return;
src += node->page_offset;
@@ -302,16 +302,16 @@ void hfs_bnode_dump(struct hfs_bnode *node)
__be32 cnid;
int i, off, key_off;
- dprint(DBG_BNODE_MOD, "bnode: %d\n", node->this);
+ hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
hfs_bnode_read(node, &desc, 0, sizeof(desc));
- dprint(DBG_BNODE_MOD, "%d, %d, %d, %d, %d\n",
+ hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
desc.type, desc.height, be16_to_cpu(desc.num_recs));
off = node->tree->node_size - 2;
for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
key_off = hfs_bnode_read_u16(node, off);
- dprint(DBG_BNODE_MOD, " %d", key_off);
+ hfs_dbg(BNODE_MOD, " %d", key_off);
if (i && node->type == HFS_NODE_INDEX) {
int tmp;
@@ -320,17 +320,17 @@ void hfs_bnode_dump(struct hfs_bnode *node)
tmp = hfs_bnode_read_u16(node, key_off) + 2;
else
tmp = node->tree->max_key_len + 2;
- dprint(DBG_BNODE_MOD, " (%d", tmp);
+ hfs_dbg_cont(BNODE_MOD, " (%d", tmp);
hfs_bnode_read(node, &cnid, key_off + tmp, 4);
- dprint(DBG_BNODE_MOD, ",%d)", be32_to_cpu(cnid));
+ hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
} else if (i && node->type == HFS_NODE_LEAF) {
int tmp;
tmp = hfs_bnode_read_u16(node, key_off);
- dprint(DBG_BNODE_MOD, " (%d)", tmp);
+ hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
}
}
- dprint(DBG_BNODE_MOD, "\n");
+ hfs_dbg_cont(BNODE_MOD, "\n");
}
void hfs_bnode_unlink(struct hfs_bnode *node)
@@ -366,7 +366,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
/* move down? */
if (!node->prev && !node->next)
- dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n");
+ hfs_dbg(BNODE_MOD, "hfs_btree_del_level\n");
if (!node->parent) {
tree->root = 0;
tree->depth = 0;
@@ -386,7 +386,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
struct hfs_bnode *node;
if (cnid >= tree->node_count) {
- printk(KERN_ERR "hfs: request for non-existent node "
+ pr_err("request for non-existent node "
"%d in B*Tree\n",
cnid);
return NULL;
@@ -409,7 +409,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
loff_t off;
if (cnid >= tree->node_count) {
- printk(KERN_ERR "hfs: request for non-existent node "
+ pr_err("request for non-existent node "
"%d in B*Tree\n",
cnid);
return NULL;
@@ -425,8 +425,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
node->this = cnid;
set_bit(HFS_BNODE_NEW, &node->flags);
atomic_set(&node->refcnt, 1);
- dprint(DBG_BNODE_REFS, "new_node(%d:%d): 1\n",
- node->tree->cnid, node->this);
+ hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
+ node->tree->cnid, node->this);
init_waitqueue_head(&node->lock_wq);
spin_lock(&tree->hash_lock);
node2 = hfs_bnode_findhash(tree, cnid);
@@ -470,7 +470,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
{
struct hfs_bnode **p;
- dprint(DBG_BNODE_REFS, "remove_node(%d:%d): %d\n",
+ hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
node->tree->cnid, node->this, atomic_read(&node->refcnt));
for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
*p && *p != node; p = &(*p)->next_hash)
@@ -588,7 +588,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
node = hfs_bnode_findhash(tree, num);
spin_unlock(&tree->hash_lock);
if (node) {
- printk(KERN_CRIT "new node %u already hashed?\n", num);
+ pr_crit("new node %u already hashed?\n", num);
WARN_ON(1);
return node;
}
@@ -620,7 +620,7 @@ void hfs_bnode_get(struct hfs_bnode *node)
{
if (node) {
atomic_inc(&node->refcnt);
- dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n",
+ hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
node->tree->cnid, node->this,
atomic_read(&node->refcnt));
}
@@ -633,7 +633,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
struct hfs_btree *tree = node->tree;
int i;
- dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n",
+ hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
node->tree->cnid, node->this,
atomic_read(&node->refcnt));
BUG_ON(!atomic_read(&node->refcnt));
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c
index 298d4e45604b..6e560d56094b 100644
--- a/fs/hfsplus/brec.c
+++ b/fs/hfsplus/brec.c
@@ -45,13 +45,13 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
if (!recoff)
return 0;
if (recoff > node->tree->node_size - 2) {
- printk(KERN_ERR "hfs: recoff %d too large\n", recoff);
+ pr_err("recoff %d too large\n", recoff);
return 0;
}
retval = hfs_bnode_read_u16(node, recoff) + 2;
if (retval > node->tree->max_key_len + 2) {
- printk(KERN_ERR "hfs: keylen %d too large\n",
+ pr_err("keylen %d too large\n",
retval);
retval = 0;
}
@@ -90,7 +90,7 @@ again:
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
end_off = hfs_bnode_read_u16(node, end_rec_off);
end_rec_off -= 2;
- dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
+ hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
rec, size, end_off, end_rec_off);
if (size > end_rec_off - end_off) {
if (new_node)
@@ -191,7 +191,7 @@ again:
mark_inode_dirty(tree->inode);
}
hfs_bnode_dump(node);
- dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n",
+ hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
fd->record, fd->keylength + fd->entrylength);
if (!--node->num_recs) {
hfs_bnode_unlink(node);
@@ -244,7 +244,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
if (IS_ERR(new_node))
return new_node;
hfs_bnode_get(node);
- dprint(DBG_BNODE_MOD, "split_nodes: %d - %d - %d\n",
+ hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
node->this, new_node->this, node->next);
new_node->next = node->next;
new_node->prev = node->this;
@@ -379,7 +379,7 @@ again:
newkeylen = hfs_bnode_read_u16(node, 14) + 2;
else
fd->keylength = newkeylen = tree->max_key_len + 2;
- dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n",
+ hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
rec, fd->keylength, newkeylen);
rec_off = tree->node_size - (rec + 2) * 2;
@@ -391,7 +391,7 @@ again:
end_off = hfs_bnode_read_u16(parent, end_rec_off);
if (end_rec_off - end_off < diff) {
- dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n");
+ hfs_dbg(BNODE_MOD, "splitting index node\n");
fd->bnode = parent;
new_node = hfs_bnode_split(fd);
if (IS_ERR(new_node))
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index efb689c21a95..0c6540c91167 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -40,8 +40,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
tree->inode = inode;
if (!HFSPLUS_I(tree->inode)->first_blocks) {
- printk(KERN_ERR
- "hfs: invalid btree extent records (0 size).\n");
+ pr_err("invalid btree extent records (0 size)\n");
goto free_inode;
}
@@ -68,12 +67,12 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
switch (id) {
case HFSPLUS_EXT_CNID:
if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
- printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+ pr_err("invalid extent max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (tree->attributes & HFS_TREE_VARIDXKEYS) {
- printk(KERN_ERR "hfs: invalid extent btree flag\n");
+ pr_err("invalid extent btree flag\n");
goto fail_page;
}
@@ -81,12 +80,12 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
break;
case HFSPLUS_CAT_CNID:
if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
- printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+ pr_err("invalid catalog max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
- printk(KERN_ERR "hfs: invalid catalog btree flag\n");
+ pr_err("invalid catalog btree flag\n");
goto fail_page;
}
@@ -100,19 +99,19 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
break;
case HFSPLUS_ATTR_CNID:
if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) {
- printk(KERN_ERR "hfs: invalid attributes max_key_len %d\n",
+ pr_err("invalid attributes max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
tree->keycmp = hfsplus_attr_bin_cmp_key;
break;
default:
- printk(KERN_ERR "hfs: unknown B*Tree requested\n");
+ pr_err("unknown B*Tree requested\n");
goto fail_page;
}
if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
- printk(KERN_ERR "hfs: invalid btree flag\n");
+ pr_err("invalid btree flag\n");
goto fail_page;
}
@@ -155,7 +154,7 @@ void hfs_btree_close(struct hfs_btree *tree)
while ((node = tree->node_hash[i])) {
tree->node_hash[i] = node->next_hash;
if (atomic_read(&node->refcnt))
- printk(KERN_CRIT "hfs: node %d:%d "
+ pr_crit("node %d:%d "
"still has %d user(s)!\n",
node->tree->cnid, node->this,
atomic_read(&node->refcnt));
@@ -303,7 +302,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
kunmap(*pagep);
nidx = node->next;
if (!nidx) {
- dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n");
+ hfs_dbg(BNODE_MOD, "create new bmap node\n");
next_node = hfs_bmap_new_bmap(node, idx);
} else
next_node = hfs_bnode_find(tree, nidx);
@@ -329,7 +328,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
u32 nidx;
u8 *data, byte, m;
- dprint(DBG_BNODE_MOD, "btree_free_node: %u\n", node->this);
+ hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
BUG_ON(!node->this);
tree = node->tree;
nidx = node->this;
@@ -345,7 +344,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
hfs_bnode_put(node);
if (!i) {
/* panic */;
- printk(KERN_CRIT "hfs: unable to free bnode %u. "
+ pr_crit("unable to free bnode %u. "
"bmap not found!\n",
node->this);
return;
@@ -355,7 +354,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
return;
if (node->type != HFS_NODE_MAP) {
/* panic */;
- printk(KERN_CRIT "hfs: invalid bmap found! "
+ pr_crit("invalid bmap found! "
"(%u,%d)\n",
node->this, node->type);
hfs_bnode_put(node);
@@ -370,7 +369,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
m = 1 << (~nidx & 7);
byte = data[off];
if (!(byte & m)) {
- printk(KERN_CRIT "hfs: trying to free free bnode "
+ pr_crit("trying to free free bnode "
"%u(%d)\n",
node->this, node->type);
kunmap(page);
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index 840d71edd193..968ce411db53 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -188,12 +188,12 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
type = be16_to_cpu(tmp.type);
if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) {
- printk(KERN_ERR "hfs: found bad thread record in catalog\n");
+ pr_err("found bad thread record in catalog\n");
return -EIO;
}
if (be16_to_cpu(tmp.thread.nodeName.length) > 255) {
- printk(KERN_ERR "hfs: catalog name length corrupted\n");
+ pr_err("catalog name length corrupted\n");
return -EIO;
}
@@ -212,7 +212,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
int entry_size;
int err;
- dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
+ hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
str->name, cnid, inode->i_nlink);
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
if (err)
@@ -271,8 +271,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
int err, off;
u16 type;
- dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
- str ? str->name : NULL, cnid);
+ hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
if (err)
return err;
@@ -361,7 +360,7 @@ int hfsplus_rename_cat(u32 cnid,
int entry_size, type;
int err;
- dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
+ hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
cnid, src_dir->i_ino, src_name->name,
dst_dir->i_ino, dst_name->name);
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 031c24e50521..a37ac934732f 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -103,7 +103,7 @@ again:
} else if (!dentry->d_fsdata)
dentry->d_fsdata = (void *)(unsigned long)cnid;
} else {
- printk(KERN_ERR "hfs: invalid catalog entry type in lookup\n");
+ pr_err("invalid catalog entry type in lookup\n");
err = -EIO;
goto fail;
}
@@ -159,12 +159,12 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
fd.entrylength);
if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) {
- printk(KERN_ERR "hfs: bad catalog folder thread\n");
+ pr_err("bad catalog folder thread\n");
err = -EIO;
goto out;
}
if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) {
- printk(KERN_ERR "hfs: truncated catalog thread\n");
+ pr_err("truncated catalog thread\n");
err = -EIO;
goto out;
}
@@ -183,7 +183,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
for (;;) {
if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) {
- printk(KERN_ERR "hfs: walked past end of dir\n");
+ pr_err("walked past end of dir\n");
err = -EIO;
goto out;
}
@@ -203,7 +203,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
if (type == HFSPLUS_FOLDER) {
if (fd.entrylength <
sizeof(struct hfsplus_cat_folder)) {
- printk(KERN_ERR "hfs: small dir entry\n");
+ pr_err("small dir entry\n");
err = -EIO;
goto out;
}
@@ -216,7 +216,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
break;
} else if (type == HFSPLUS_FILE) {
if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
- printk(KERN_ERR "hfs: small file entry\n");
+ pr_err("small file entry\n");
err = -EIO;
goto out;
}
@@ -224,7 +224,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
be32_to_cpu(entry.file.id), DT_REG))
break;
} else {
- printk(KERN_ERR "hfs: bad catalog entry type\n");
+ pr_err("bad catalog entry type\n");
err = -EIO;
goto out;
}
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
index a94f0f779d5e..fbb212fbb1ef 100644
--- a/fs/hfsplus/extents.c
+++ b/fs/hfsplus/extents.c
@@ -83,7 +83,7 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count);
}
-static void __hfsplus_ext_write_extent(struct inode *inode,
+static int __hfsplus_ext_write_extent(struct inode *inode,
struct hfs_find_data *fd)
{
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
@@ -98,13 +98,13 @@ static void __hfsplus_ext_write_extent(struct inode *inode,
res = hfs_brec_find(fd, hfs_find_rec_by_key);
if (hip->extent_state & HFSPLUS_EXT_NEW) {
if (res != -ENOENT)
- return;
+ return res;
hfs_brec_insert(fd, hip->cached_extents,
sizeof(hfsplus_extent_rec));
hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW);
} else {
if (res)
- return;
+ return res;
hfs_bnode_write(fd->bnode, hip->cached_extents,
fd->entryoffset, fd->entrylength);
hip->extent_state &= ~HFSPLUS_EXT_DIRTY;
@@ -117,11 +117,13 @@ static void __hfsplus_ext_write_extent(struct inode *inode,
* to explicily mark the inode dirty, too.
*/
set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
+
+ return 0;
}
static int hfsplus_ext_write_extent_locked(struct inode *inode)
{
- int res;
+ int res = 0;
if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
struct hfs_find_data fd;
@@ -129,10 +131,10 @@ static int hfsplus_ext_write_extent_locked(struct inode *inode)
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
if (res)
return res;
- __hfsplus_ext_write_extent(inode, &fd);
+ res = __hfsplus_ext_write_extent(inode, &fd);
hfs_find_exit(&fd);
}
- return 0;
+ return res;
}
int hfsplus_ext_write_extent(struct inode *inode)
@@ -175,8 +177,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd,
WARN_ON(!mutex_is_locked(&hip->extents_lock));
- if (hip->extent_state & HFSPLUS_EXT_DIRTY)
- __hfsplus_ext_write_extent(inode, fd);
+ if (hip->extent_state & HFSPLUS_EXT_DIRTY) {
+ res = __hfsplus_ext_write_extent(inode, fd);
+ if (res)
+ return res;
+ }
res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
block, HFSPLUS_IS_RSRC(inode) ?
@@ -265,7 +270,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
mutex_unlock(&hip->extents_lock);
done:
- dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n",
+ hfs_dbg(EXTENT, "get_block(%lu): %llu - %u\n",
inode->i_ino, (long long)iblock, dblock);
mask = (1 << sbi->fs_shift) - 1;
@@ -288,11 +293,12 @@ static void hfsplus_dump_extent(struct hfsplus_extent *extent)
{
int i;
- dprint(DBG_EXTENT, " ");
+ hfs_dbg(EXTENT, " ");
for (i = 0; i < 8; i++)
- dprint(DBG_EXTENT, " %u:%u", be32_to_cpu(extent[i].start_block),
- be32_to_cpu(extent[i].block_count));
- dprint(DBG_EXTENT, "\n");
+ hfs_dbg_cont(EXTENT, " %u:%u",
+ be32_to_cpu(extent[i].start_block),
+ be32_to_cpu(extent[i].block_count));
+ hfs_dbg_cont(EXTENT, "\n");
}
static int hfsplus_add_extent(struct hfsplus_extent *extent, u32 offset,
@@ -348,8 +354,8 @@ found:
if (count <= block_nr) {
err = hfsplus_block_free(sb, start, count);
if (err) {
- printk(KERN_ERR "hfs: can't free extent\n");
- dprint(DBG_EXTENT, " start: %u count: %u\n",
+ pr_err("can't free extent\n");
+ hfs_dbg(EXTENT, " start: %u count: %u\n",
start, count);
}
extent->block_count = 0;
@@ -359,8 +365,8 @@ found:
count -= block_nr;
err = hfsplus_block_free(sb, start + count, block_nr);
if (err) {
- printk(KERN_ERR "hfs: can't free extent\n");
- dprint(DBG_EXTENT, " start: %u count: %u\n",
+ pr_err("can't free extent\n");
+ hfs_dbg(EXTENT, " start: %u count: %u\n",
start, count);
}
extent->block_count = cpu_to_be32(count);
@@ -432,7 +438,7 @@ int hfsplus_file_extend(struct inode *inode)
if (sbi->alloc_file->i_size * 8 <
sbi->total_blocks - sbi->free_blocks + 8) {
/* extend alloc file */
- printk(KERN_ERR "hfs: extend alloc file! "
+ pr_err("extend alloc file! "
"(%llu,%u,%u)\n",
sbi->alloc_file->i_size * 8,
sbi->total_blocks, sbi->free_blocks);
@@ -459,11 +465,11 @@ int hfsplus_file_extend(struct inode *inode)
}
}
- dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
+ hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
if (hip->alloc_blocks <= hip->first_blocks) {
if (!hip->first_blocks) {
- dprint(DBG_EXTENT, "first extents\n");
+ hfs_dbg(EXTENT, "first extents\n");
/* no extents yet */
hip->first_extents[0].start_block = cpu_to_be32(start);
hip->first_extents[0].block_count = cpu_to_be32(len);
@@ -500,7 +506,7 @@ out:
return res;
insert_extent:
- dprint(DBG_EXTENT, "insert new extent\n");
+ hfs_dbg(EXTENT, "insert new extent\n");
res = hfsplus_ext_write_extent_locked(inode);
if (res)
goto out;
@@ -525,15 +531,14 @@ void hfsplus_file_truncate(struct inode *inode)
u32 alloc_cnt, blk_cnt, start;
int res;
- dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n",
- inode->i_ino, (long long)hip->phys_size,
- inode->i_size);
+ hfs_dbg(INODE, "truncate: %lu, %llu -> %llu\n",
+ inode->i_ino, (long long)hip->phys_size, inode->i_size);
if (inode->i_size > hip->phys_size) {
struct address_space *mapping = inode->i_mapping;
struct page *page;
void *fsdata;
- u32 size = inode->i_size;
+ loff_t size = inode->i_size;
res = pagecache_write_begin(NULL, mapping, size, 0,
AOP_FLAG_UNINTERRUPTIBLE,
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 05b11f36024c..60b0a3388b26 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -10,6 +10,12 @@
#ifndef _LINUX_HFSPLUS_FS_H
#define _LINUX_HFSPLUS_FS_H
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/buffer_head.h>
@@ -32,9 +38,17 @@
#endif
#define DBG_MASK (0)
-#define dprint(flg, fmt, args...) \
- if (flg & DBG_MASK) \
- printk(fmt , ## args)
+#define hfs_dbg(flg, fmt, ...) \
+do { \
+ if (DBG_##flg & DBG_MASK) \
+ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
+} while (0)
+
+#define hfs_dbg_cont(flg, fmt, ...) \
+do { \
+ if (DBG_##flg & DBG_MASK) \
+ pr_cont(fmt, ##__VA_ARGS__); \
+} while (0)
/* Runtime config options */
#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 160ccc9cdb4b..7faaa964968e 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -357,7 +357,7 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
if (!error)
error = error2;
} else {
- printk(KERN_ERR "hfs: sync non-existent attributes tree\n");
+ pr_err("sync non-existent attributes tree\n");
}
}
@@ -573,7 +573,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
HFSPLUS_I(inode)->create_date = file->create_date;
} else {
- printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
+ pr_err("bad catalog entry used to create inode\n");
res = -EIO;
}
return res;
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index ed257c671615..968eab5bc1f5 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -113,67 +113,67 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
switch (token) {
case opt_creator:
if (match_fourchar(&args[0], &sbi->creator)) {
- printk(KERN_ERR "hfs: creator requires a 4 character value\n");
+ pr_err("creator requires a 4 character value\n");
return 0;
}
break;
case opt_type:
if (match_fourchar(&args[0], &sbi->type)) {
- printk(KERN_ERR "hfs: type requires a 4 character value\n");
+ pr_err("type requires a 4 character value\n");
return 0;
}
break;
case opt_umask:
if (match_octal(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: umask requires a value\n");
+ pr_err("umask requires a value\n");
return 0;
}
sbi->umask = (umode_t)tmp;
break;
case opt_uid:
if (match_int(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: uid requires an argument\n");
+ pr_err("uid requires an argument\n");
return 0;
}
sbi->uid = make_kuid(current_user_ns(), (uid_t)tmp);
if (!uid_valid(sbi->uid)) {
- printk(KERN_ERR "hfs: invalid uid specified\n");
+ pr_err("invalid uid specified\n");
return 0;
}
break;
case opt_gid:
if (match_int(&args[0], &tmp)) {
- printk(KERN_ERR "hfs: gid requires an argument\n");
+ pr_err("gid requires an argument\n");
return 0;
}
sbi->gid = make_kgid(current_user_ns(), (gid_t)tmp);
if (!gid_valid(sbi->gid)) {
- printk(KERN_ERR "hfs: invalid gid specified\n");
+ pr_err("invalid gid specified\n");
return 0;
}
break;
case opt_part:
if (match_int(&args[0], &sbi->part)) {
- printk(KERN_ERR "hfs: part requires an argument\n");
+ pr_err("part requires an argument\n");
return 0;
}
break;
case opt_session:
if (match_int(&args[0], &sbi->session)) {
- printk(KERN_ERR "hfs: session requires an argument\n");
+ pr_err("session requires an argument\n");
return 0;
}
break;
case opt_nls:
if (sbi->nls) {
- printk(KERN_ERR "hfs: unable to change nls mapping\n");
+ pr_err("unable to change nls mapping\n");
return 0;
}
p = match_strdup(&args[0]);
if (p)
sbi->nls = load_nls(p);
if (!sbi->nls) {
- printk(KERN_ERR "hfs: unable to load "
+ pr_err("unable to load "
"nls mapping \"%s\"\n",
p);
kfree(p);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 7b87284e46dc..4c4d142cf890 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -132,7 +132,7 @@ static int hfsplus_system_write_inode(struct inode *inode)
if (tree) {
int err = hfs_btree_write(tree);
if (err) {
- printk(KERN_ERR "hfs: b-tree write err: %d, ino %lu\n",
+ pr_err("b-tree write err: %d, ino %lu\n",
err, inode->i_ino);
return err;
}
@@ -145,7 +145,7 @@ static int hfsplus_write_inode(struct inode *inode,
{
int err;
- dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
+ hfs_dbg(INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
err = hfsplus_ext_write_extent(inode);
if (err)
@@ -160,7 +160,7 @@ static int hfsplus_write_inode(struct inode *inode,
static void hfsplus_evict_inode(struct inode *inode)
{
- dprint(DBG_INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
+ hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
if (HFSPLUS_IS_RSRC(inode)) {
@@ -179,7 +179,7 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
if (!wait)
return 0;
- dprint(DBG_SUPER, "hfsplus_sync_fs\n");
+ hfs_dbg(SUPER, "hfsplus_sync_fs\n");
/*
* Explicitly write out the special metadata inodes.
@@ -251,7 +251,7 @@ static void delayed_sync_fs(struct work_struct *work)
err = hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
if (err)
- printk(KERN_ERR "hfs: delayed sync fs err %d\n", err);
+ pr_err("delayed sync fs err %d\n", err);
}
void hfsplus_mark_mdb_dirty(struct super_block *sb)
@@ -275,7 +275,7 @@ static void hfsplus_put_super(struct super_block *sb)
{
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
- dprint(DBG_SUPER, "hfsplus_put_super\n");
+ hfs_dbg(SUPER, "hfsplus_put_super\n");
cancel_delayed_work_sync(&sbi->sync_work);
@@ -333,25 +333,19 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
return -EINVAL;
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
- printk(KERN_WARNING "hfs: filesystem was "
- "not cleanly unmounted, "
- "running fsck.hfsplus is recommended. "
- "leaving read-only.\n");
+ pr_warn("filesystem was not cleanly unmounted, running fsck.hfsplus is recommended. leaving read-only.\n");
sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY;
} else if (force) {
/* nothing */
} else if (vhdr->attributes &
cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
- printk(KERN_WARNING "hfs: filesystem is marked locked, "
- "leaving read-only.\n");
+ pr_warn("filesystem is marked locked, leaving read-only.\n");
sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY;
} else if (vhdr->attributes &
cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
- printk(KERN_WARNING "hfs: filesystem is "
- "marked journaled, "
- "leaving read-only.\n");
+ pr_warn("filesystem is marked journaled, leaving read-only.\n");
sb->s_flags |= MS_RDONLY;
*flags |= MS_RDONLY;
}
@@ -397,7 +391,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
err = -EINVAL;
if (!hfsplus_parse_options(data, sbi)) {
- printk(KERN_ERR "hfs: unable to parse mount options\n");
+ pr_err("unable to parse mount options\n");
goto out_unload_nls;
}
@@ -405,14 +399,14 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
nls = sbi->nls;
sbi->nls = load_nls("utf8");
if (!sbi->nls) {
- printk(KERN_ERR "hfs: unable to load nls for utf8\n");
+ pr_err("unable to load nls for utf8\n");
goto out_unload_nls;
}
/* Grab the volume header */
if (hfsplus_read_wrapper(sb)) {
if (!silent)
- printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n");
+ pr_warn("unable to find HFS+ superblock\n");
goto out_unload_nls;
}
vhdr = sbi->s_vhdr;
@@ -421,7 +415,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = HFSPLUS_VOLHEAD_SIG;
if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION ||
be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) {
- printk(KERN_ERR "hfs: wrong filesystem version\n");
+ pr_err("wrong filesystem version\n");
goto out_free_vhdr;
}
sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
@@ -445,7 +439,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if ((last_fs_block > (sector_t)(~0ULL) >> (sbi->alloc_blksz_shift - 9)) ||
(last_fs_page > (pgoff_t)(~0ULL))) {
- printk(KERN_ERR "hfs: filesystem size too large.\n");
+ pr_err("filesystem size too large\n");
goto out_free_vhdr;
}
@@ -454,22 +448,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
sb->s_maxbytes = MAX_LFS_FILESIZE;
if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
- printk(KERN_WARNING "hfs: Filesystem was "
- "not cleanly unmounted, "
- "running fsck.hfsplus is recommended. "
- "mounting read-only.\n");
+ pr_warn("Filesystem was not cleanly unmounted, running fsck.hfsplus is recommended. mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
} else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
/* nothing */
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
- printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
+ pr_warn("Filesystem is marked locked, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
} else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) &&
!(sb->s_flags & MS_RDONLY)) {
- printk(KERN_WARNING "hfs: write access to "
- "a journaled filesystem is not supported, "
- "use the force option at your own risk, "
- "mounting read-only.\n");
+ pr_warn("write access to a journaled filesystem is not supported, use the force option at your own risk, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
}
@@ -478,18 +466,18 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
/* Load metadata objects (B*Trees) */
sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
if (!sbi->ext_tree) {
- printk(KERN_ERR "hfs: failed to load extents file\n");
+ pr_err("failed to load extents file\n");
goto out_free_vhdr;
}
sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
if (!sbi->cat_tree) {
- printk(KERN_ERR "hfs: failed to load catalog file\n");
+ pr_err("failed to load catalog file\n");
goto out_close_ext_tree;
}
if (vhdr->attr_file.total_blocks != 0) {
sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
if (!sbi->attr_tree) {
- printk(KERN_ERR "hfs: failed to load attributes file\n");
+ pr_err("failed to load attributes file\n");
goto out_close_cat_tree;
}
}
@@ -497,7 +485,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
if (IS_ERR(inode)) {
- printk(KERN_ERR "hfs: failed to load allocation file\n");
+ pr_err("failed to load allocation file\n");
err = PTR_ERR(inode);
goto out_close_attr_tree;
}
@@ -506,7 +494,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
/* Load the root directory */
root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
if (IS_ERR(root)) {
- printk(KERN_ERR "hfs: failed to load root directory\n");
+ pr_err("failed to load root directory\n");
err = PTR_ERR(root);
goto out_put_alloc_file;
}
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 90effcccca9a..b51a6079108d 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -156,7 +156,7 @@ static int hfsplus_get_last_session(struct super_block *sb,
*start = (sector_t)te.cdte_addr.lba << 2;
return 0;
}
- printk(KERN_ERR "hfs: invalid session number or type of track\n");
+ pr_err("invalid session number or type of track\n");
return -EINVAL;
}
ms_info.addr_format = CDROM_LBA;
@@ -234,8 +234,7 @@ reread:
error = -EINVAL;
if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) {
- printk(KERN_WARNING
- "hfs: invalid secondary volume header\n");
+ pr_warn("invalid secondary volume header\n");
goto out_free_backup_vhdr;
}
@@ -259,8 +258,7 @@ reread:
blocksize >>= 1;
if (sb_set_blocksize(sb, blocksize) != blocksize) {
- printk(KERN_ERR "hfs: unable to set blocksize to %u!\n",
- blocksize);
+ pr_err("unable to set blocksize to %u!\n", blocksize);
goto out_free_backup_vhdr;
}
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index e8a4b0815c61..f66346155df5 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -107,19 +107,19 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
if (err) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
return err;
}
err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
if (err) {
- printk(KERN_ERR "hfs: catalog searching failed\n");
+ pr_err("catalog searching failed\n");
goto end_setxattr;
}
if (!strcmp_xattr_finder_info(name)) {
if (flags & XATTR_CREATE) {
- printk(KERN_ERR "hfs: xattr exists yet\n");
+ pr_err("xattr exists yet\n");
err = -EOPNOTSUPP;
goto end_setxattr;
}
@@ -165,7 +165,7 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
if (hfsplus_attr_exists(inode, name)) {
if (flags & XATTR_CREATE) {
- printk(KERN_ERR "hfs: xattr exists yet\n");
+ pr_err("xattr exists yet\n");
err = -EOPNOTSUPP;
goto end_setxattr;
}
@@ -177,7 +177,7 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
goto end_setxattr;
} else {
if (flags & XATTR_REPLACE) {
- printk(KERN_ERR "hfs: cannot replace xattr\n");
+ pr_err("cannot replace xattr\n");
err = -EOPNOTSUPP;
goto end_setxattr;
}
@@ -210,7 +210,7 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
cat_entry_flags);
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
} else {
- printk(KERN_ERR "hfs: invalid catalog entry type\n");
+ pr_err("invalid catalog entry type\n");
err = -EIO;
goto end_setxattr;
}
@@ -269,7 +269,7 @@ static ssize_t hfsplus_getxattr_finder_info(struct dentry *dentry,
if (size >= record_len) {
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
if (res) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
return res;
}
res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@@ -340,13 +340,13 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
entry = hfsplus_alloc_attr_entry();
if (!entry) {
- printk(KERN_ERR "hfs: can't allocate xattr entry\n");
+ pr_err("can't allocate xattr entry\n");
return -ENOMEM;
}
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
if (res) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
goto failed_getxattr_init;
}
@@ -355,7 +355,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
if (res == -ENOENT)
res = -ENODATA;
else
- printk(KERN_ERR "hfs: xattr searching failed\n");
+ pr_err("xattr searching failed\n");
goto out;
}
@@ -368,17 +368,17 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
offsetof(struct hfsplus_attr_inline_data,
length));
if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) {
- printk(KERN_ERR "hfs: invalid xattr record size\n");
+ pr_err("invalid xattr record size\n");
res = -EIO;
goto out;
}
} else if (record_type == HFSPLUS_ATTR_FORK_DATA ||
record_type == HFSPLUS_ATTR_EXTENTS) {
- printk(KERN_ERR "hfs: only inline data xattr are supported\n");
+ pr_err("only inline data xattr are supported\n");
res = -EOPNOTSUPP;
goto out;
} else {
- printk(KERN_ERR "hfs: invalid xattr record\n");
+ pr_err("invalid xattr record\n");
res = -EIO;
goto out;
}
@@ -427,7 +427,7 @@ static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry,
res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
if (res) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
return res;
}
@@ -506,7 +506,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd);
if (err) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
return err;
}
@@ -525,8 +525,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
for (;;) {
key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset);
if (key_len == 0 || key_len > fd.tree->max_key_len) {
- printk(KERN_ERR "hfs: invalid xattr key length: %d\n",
- key_len);
+ pr_err("invalid xattr key length: %d\n", key_len);
res = -EIO;
goto end_listxattr;
}
@@ -541,7 +540,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
if (hfsplus_uni2asc(inode->i_sb,
(const struct hfsplus_unistr *)&fd.key->attr.key_name,
strbuf, &xattr_name_len)) {
- printk(KERN_ERR "hfs: unicode conversion failed\n");
+ pr_err("unicode conversion failed\n");
res = -EIO;
goto end_listxattr;
}
@@ -598,13 +597,13 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd);
if (err) {
- printk(KERN_ERR "hfs: can't init xattr find struct\n");
+ pr_err("can't init xattr find struct\n");
return err;
}
err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd);
if (err) {
- printk(KERN_ERR "hfs: catalog searching failed\n");
+ pr_err("catalog searching failed\n");
goto end_removexattr;
}
@@ -643,7 +642,7 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
flags);
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY);
} else {
- printk(KERN_ERR "hfs: invalid catalog entry type\n");
+ pr_err("invalid catalog entry type\n");
err = -EIO;
goto end_removexattr;
}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 84e3d856e91d..523464e62849 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -110,7 +110,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
* way when do_mmap_pgoff unwinds (may be important on powerpc
* and ia64).
*/
- vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
vma->vm_ops = &hugetlb_vm_ops;
if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
diff --git a/fs/inode.c b/fs/inode.c
index 5b76d9b1a884..00d5fc3b86e1 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -725,7 +725,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan)
* inode to the back of the list so we don't spin on it.
*/
if (!spin_trylock(&inode->i_lock)) {
- list_move_tail(&inode->i_lru, &sb->s_inode_lru);
+ list_move(&inode->i_lru, &sb->s_inode_lru);
continue;
}
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 86b39b167c23..11bb11f48b3a 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -162,8 +162,17 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs,
for (i = 0; i < bufs; i++) {
wbuf[i]->b_end_io = end_buffer_write_sync;
- /* We use-up our safety reference in submit_bh() */
- submit_bh(write_op, wbuf[i]);
+ /*
+ * Here we write back pagecache data that may be mmaped. Since
+ * we cannot afford to clean the page and set PageWriteback
+ * here due to lock ordering (page lock ranks above transaction
+ * start), the data can change while IO is in flight. Tell the
+ * block layer it should bounce the bio pages if stable data
+ * during write is required.
+ *
+ * We use up our safety reference in submit_bh().
+ */
+ _submit_bh(write_op, wbuf[i], 1 << BIO_SNAP_STABLE);
}
}
@@ -667,7 +676,17 @@ start_journal_io:
clear_buffer_dirty(bh);
set_buffer_uptodate(bh);
bh->b_end_io = journal_end_buffer_io_sync;
- submit_bh(write_op, bh);
+ /*
+ * In data=journal mode, here we can end up
+ * writing pagecache data that might be
+ * mmapped. Since we can't afford to clean the
+ * page and set PageWriteback (see the comment
+ * near the other use of _submit_bh()), the
+ * data can change while the write is in
+ * flight. Tell the block layer to bounce the
+ * bio pages if stable pages are required.
+ */
+ _submit_bh(write_op, bh, 1 << BIO_SNAP_STABLE);
}
cond_resched();
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 81cc7eaff863..865c4308acb6 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -310,8 +310,6 @@ int journal_write_metadata_buffer(transaction_t *transaction,
new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
/* keep subsequent assertions sane */
- new_bh->b_state = 0;
- init_buffer(new_bh, NULL, NULL);
atomic_set(&new_bh->b_count, 1);
new_jh = journal_add_journal_head(new_bh); /* This sleeps */
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 750c70148eff..0f53946f13c1 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -382,7 +382,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
int space_left = 0;
int first_tag = 0;
int tag_flag;
- int i, to_free = 0;
+ int i;
int tag_bytes = journal_tag_bytes(journal);
struct buffer_head *cbh = NULL; /* For transactional checksums */
__u32 crc32_sum = ~0;
@@ -1134,7 +1134,7 @@ restart_loop:
journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged;
spin_unlock(&journal->j_history_lock);
- commit_transaction->t_state = T_FINISHED;
+ commit_transaction->t_state = T_COMMIT_CALLBACK;
J_ASSERT(commit_transaction == journal->j_committing_transaction);
journal->j_commit_sequence = commit_transaction->t_tid;
journal->j_committing_transaction = NULL;
@@ -1149,38 +1149,44 @@ restart_loop:
journal->j_average_commit_time*3) / 4;
else
journal->j_average_commit_time = commit_time;
+
write_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL &&
- commit_transaction->t_checkpoint_io_list == NULL) {
- __jbd2_journal_drop_transaction(journal, commit_transaction);
- to_free = 1;
+ if (journal->j_checkpoint_transactions == NULL) {
+ journal->j_checkpoint_transactions = commit_transaction;
+ commit_transaction->t_cpnext = commit_transaction;
+ commit_transaction->t_cpprev = commit_transaction;
} else {
- if (journal->j_checkpoint_transactions == NULL) {
- journal->j_checkpoint_transactions = commit_transaction;
- commit_transaction->t_cpnext = commit_transaction;
- commit_transaction->t_cpprev = commit_transaction;
- } else {
- commit_transaction->t_cpnext =
- journal->j_checkpoint_transactions;
- commit_transaction->t_cpprev =
- commit_transaction->t_cpnext->t_cpprev;
- commit_transaction->t_cpnext->t_cpprev =
- commit_transaction;
- commit_transaction->t_cpprev->t_cpnext =
+ commit_transaction->t_cpnext =
+ journal->j_checkpoint_transactions;
+ commit_transaction->t_cpprev =
+ commit_transaction->t_cpnext->t_cpprev;
+ commit_transaction->t_cpnext->t_cpprev =
+ commit_transaction;
+ commit_transaction->t_cpprev->t_cpnext =
commit_transaction;
- }
}
spin_unlock(&journal->j_list_lock);
-
+ /* Drop all spin_locks because commit_callback may be block.
+ * __journal_remove_checkpoint() can not destroy transaction
+ * under us because it is not marked as T_FINISHED yet */
if (journal->j_commit_callback)
journal->j_commit_callback(journal, commit_transaction);
trace_jbd2_end_commit(journal, commit_transaction);
jbd_debug(1, "JBD2: commit %d complete, head %d\n",
journal->j_commit_sequence, journal->j_tail_sequence);
- if (to_free)
- jbd2_journal_free_transaction(commit_transaction);
+ write_lock(&journal->j_state_lock);
+ spin_lock(&journal->j_list_lock);
+ commit_transaction->t_state = T_FINISHED;
+ /* Recheck checkpoint lists after j_list_lock was dropped */
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
+ __jbd2_journal_drop_transaction(journal, commit_transaction);
+ jbd2_journal_free_transaction(commit_transaction);
+ }
+ spin_unlock(&journal->j_list_lock);
+ write_unlock(&journal->j_state_lock);
wake_up(&journal->j_wait_done_commit);
}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 154592ea5632..95457576e434 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -367,8 +367,6 @@ retry_alloc:
}
/* keep subsequent assertions sane */
- new_bh->b_state = 0;
- init_buffer(new_bh, NULL, NULL);
atomic_set(&new_bh->b_count, 1);
new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
@@ -710,6 +708,37 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
}
/*
+ * When this function returns the transaction corresponding to tid
+ * will be completed. If the transaction has currently running, start
+ * committing that transaction before waiting for it to complete. If
+ * the transaction id is stale, it is by definition already completed,
+ * so just return SUCCESS.
+ */
+int jbd2_complete_transaction(journal_t *journal, tid_t tid)
+{
+ int need_to_wait = 1;
+
+ read_lock(&journal->j_state_lock);
+ if (journal->j_running_transaction &&
+ journal->j_running_transaction->t_tid == tid) {
+ if (journal->j_commit_request != tid) {
+ /* transaction not yet started, so request it */
+ read_unlock(&journal->j_state_lock);
+ jbd2_log_start_commit(journal, tid);
+ goto wait_commit;
+ }
+ } else if (!(journal->j_committing_transaction &&
+ journal->j_committing_transaction->t_tid == tid))
+ need_to_wait = 0;
+ read_unlock(&journal->j_state_lock);
+ if (!need_to_wait)
+ return 0;
+wait_commit:
+ return jbd2_log_wait_commit(journal, tid);
+}
+EXPORT_SYMBOL(jbd2_complete_transaction);
+
+/*
* Log buffer allocation routines:
*/
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 325bc019ed88..10f524c59ea8 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -332,7 +332,6 @@ static handle_t *new_handle(int nblocks)
handle_t *handle = jbd2_alloc_handle(GFP_NOFS);
if (!handle)
return NULL;
- memset(handle, 0, sizeof(*handle));
handle->h_buffer_credits = nblocks;
handle->h_ref = 1;
@@ -640,6 +639,7 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
int error;
char *frozen_buffer = NULL;
int need_copy = 0;
+ unsigned long start_lock, time_lock;
if (is_handle_aborted(handle))
return -EROFS;
@@ -655,9 +655,16 @@ repeat:
/* @@@ Need to check for errors here at some point. */
+ start_lock = jiffies;
lock_buffer(bh);
jbd_lock_bh_state(bh);
+ /* If it takes too long to lock the buffer, trace it */
+ time_lock = jbd2_time_diff(start_lock, jiffies);
+ if (time_lock > HZ/10)
+ trace_jbd2_lock_buffer_stall(bh->b_bdev->bd_dev,
+ jiffies_to_msecs(time_lock));
+
/* We now hold the buffer lock so it is safe to query the buffer
* state. Is the buffer dirty?
*
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 0796c45d0d4d..01bfe7662751 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -144,6 +144,9 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
timeout);
if (ret < 0)
return -ERESTARTSYS;
+ /* Reset the lock status after a server reboot so we resend */
+ if (block->b_status == nlm_lck_denied_grace_period)
+ block->b_status = nlm_lck_blocked;
req->a_res.status = block->b_status;
return 0;
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 7e529c3c45c0..9760ecb9b60f 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -550,9 +550,6 @@ again:
status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
if (status < 0)
break;
- /* Resend the blocking lock request after a server reboot */
- if (resp->status == nlm_lck_denied_grace_period)
- continue;
if (resp->status != nlm_lck_blocked)
break;
}
diff --git a/fs/namespace.c b/fs/namespace.c
index 0f0cf9379c9e..b4f96a5230a3 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -22,6 +22,7 @@
#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */
#include <linux/uaccess.h>
#include <linux/proc_ns.h>
+#include <linux/magic.h>
#include "pnode.h"
#include "internal.h"
@@ -826,6 +827,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
}
mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD;
+ /* Don't allow unprivileged users to change mount flags */
+ if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
+ mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
+
atomic_inc(&sb->s_active);
mnt->mnt.mnt_sb = sb;
mnt->mnt.mnt_root = dget(root);
@@ -1759,6 +1764,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
if (readonly_request == __mnt_is_readonly(mnt))
return 0;
+ if (mnt->mnt_flags & MNT_LOCK_READONLY)
+ return -EPERM;
+
if (readonly_request)
error = mnt_make_readonly(real_mount(mnt));
else
@@ -2384,7 +2392,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
/* First pass: copy the tree topology */
copy_flags = CL_COPY_ALL | CL_EXPIRE;
if (user_ns != mnt_ns->user_ns)
- copy_flags |= CL_SHARED_TO_SLAVE;
+ copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
new = copy_tree(old, old->mnt.mnt_root, copy_flags);
if (IS_ERR(new)) {
namespace_unlock();
@@ -2780,6 +2788,51 @@ bool our_mnt(struct vfsmount *mnt)
return check_mnt(real_mount(mnt));
}
+bool current_chrooted(void)
+{
+ /* Does the current process have a non-standard root */
+ struct path ns_root;
+ struct path fs_root;
+ bool chrooted;
+
+ /* Find the namespace root */
+ ns_root.mnt = &current->nsproxy->mnt_ns->root->mnt;
+ ns_root.dentry = ns_root.mnt->mnt_root;
+ path_get(&ns_root);
+ while (d_mountpoint(ns_root.dentry) && follow_down_one(&ns_root))
+ ;
+
+ get_fs_root(current->fs, &fs_root);
+
+ chrooted = !path_equal(&fs_root, &ns_root);
+
+ path_put(&fs_root);
+ path_put(&ns_root);
+
+ return chrooted;
+}
+
+void update_mnt_policy(struct user_namespace *userns)
+{
+ struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+ struct mount *mnt;
+
+ down_read(&namespace_sem);
+ list_for_each_entry(mnt, &ns->list, mnt_list) {
+ switch (mnt->mnt.mnt_sb->s_magic) {
+ case SYSFS_MAGIC:
+ userns->may_mount_sysfs = true;
+ break;
+ case PROC_SUPER_MAGIC:
+ userns->may_mount_proc = true;
+ break;
+ }
+ if (userns->may_mount_sysfs && userns->may_mount_proc)
+ break;
+ }
+ up_read(&namespace_sem);
+}
+
static void *mntns_get(struct task_struct *task)
{
struct mnt_namespace *ns = NULL;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 5088b57b078a..cff089a412c7 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -125,6 +125,9 @@ nfs41_callback_svc(void *vrqstp)
set_freezable();
while (!kthread_should_stop()) {
+ if (try_to_freeze())
+ continue;
+
prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
spin_lock_bh(&serv->sv_cb_lock);
if (!list_empty(&serv->sv_cb_list)) {
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 2960512792c2..a13d26ede254 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -500,7 +500,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
&args->craa_type_mask))
pnfs_recall_all_layouts(cps->clp);
if (flags)
- nfs_expire_all_delegation_types(cps->clp, flags);
+ nfs_expire_unused_delegation_types(cps->clp, flags);
out:
dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
return status;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 84d8eae203a7..c513b0cc835f 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -593,6 +593,8 @@ int nfs_create_rpc_client(struct nfs_client *clp,
args.flags |= RPC_CLNT_CREATE_DISCRTRY;
if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+ if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
+ args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
if (!IS_ERR(clp->cl_rpcclient))
return 0;
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 6390a4b5fee7..57db3244f4d9 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -64,17 +64,15 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags)
return ret;
}
-static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
+static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
struct inode *inode = state->inode;
struct file_lock *fl;
int status = 0;
if (inode->i_flock == NULL)
- return 0;
-
- if (inode->i_flock == NULL)
goto out;
+
/* Protect inode->i_flock using the file locks lock */
lock_flocks();
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -83,7 +81,7 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
if (nfs_file_open_context(fl->fl_file) != ctx)
continue;
unlock_flocks();
- status = nfs4_lock_delegation_recall(state, fl);
+ status = nfs4_lock_delegation_recall(fl, state, stateid);
if (status < 0)
goto out;
lock_flocks();
@@ -120,7 +118,7 @@ again:
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
err = nfs4_open_delegation_recall(ctx, state, stateid);
if (!err)
- err = nfs_delegation_claim_locks(ctx, state);
+ err = nfs_delegation_claim_locks(ctx, state, stateid);
if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
err = -EAGAIN;
mutex_unlock(&sp->so_delegreturn_mutex);
@@ -389,6 +387,24 @@ out:
return err;
}
+static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
+{
+ bool ret = false;
+
+ if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
+ ret = true;
+ if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
+ struct inode *inode;
+
+ spin_lock(&delegation->lock);
+ inode = delegation->inode;
+ if (inode && list_empty(&NFS_I(inode)->open_files))
+ ret = true;
+ spin_unlock(&delegation->lock);
+ }
+ return ret;
+}
+
/**
* nfs_client_return_marked_delegations - return previously marked delegations
* @clp: nfs_client to process
@@ -411,8 +427,7 @@ restart:
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
list_for_each_entry_rcu(delegation, &server->delegations,
super_list) {
- if (!test_and_clear_bit(NFS_DELEGATION_RETURN,
- &delegation->flags))
+ if (!nfs_delegation_need_return(delegation))
continue;
inode = nfs_delegation_grab_inode(delegation);
if (inode == NULL)
@@ -471,6 +486,13 @@ int nfs4_inode_return_delegation(struct inode *inode)
return err;
}
+static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
+ struct nfs_delegation *delegation)
+{
+ set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
+ set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
+}
+
static void nfs_mark_return_delegation(struct nfs_server *server,
struct nfs_delegation *delegation)
{
@@ -478,6 +500,45 @@ static void nfs_mark_return_delegation(struct nfs_server *server,
set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
}
+static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
+{
+ struct nfs_delegation *delegation;
+ bool ret = false;
+
+ list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
+ nfs_mark_return_delegation(server, delegation);
+ ret = true;
+ }
+ return ret;
+}
+
+static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
+{
+ struct nfs_server *server;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
+ nfs_server_mark_return_all_delegations(server);
+ rcu_read_unlock();
+}
+
+static void nfs_delegation_run_state_manager(struct nfs_client *clp)
+{
+ if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
+ nfs4_schedule_state_manager(clp);
+}
+
+/**
+ * nfs_expire_all_delegations
+ * @clp: client to process
+ *
+ */
+void nfs_expire_all_delegations(struct nfs_client *clp)
+{
+ nfs_client_mark_return_all_delegations(clp);
+ nfs_delegation_run_state_manager(clp);
+}
+
/**
* nfs_super_return_all_delegations - return delegations for one superblock
* @sb: sb to process
@@ -486,24 +547,22 @@ static void nfs_mark_return_delegation(struct nfs_server *server,
void nfs_server_return_all_delegations(struct nfs_server *server)
{
struct nfs_client *clp = server->nfs_client;
- struct nfs_delegation *delegation;
+ bool need_wait;
if (clp == NULL)
return;
rcu_read_lock();
- list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
- spin_lock(&delegation->lock);
- set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
- spin_unlock(&delegation->lock);
- }
+ need_wait = nfs_server_mark_return_all_delegations(server);
rcu_read_unlock();
- if (nfs_client_return_marked_delegations(clp) != 0)
+ if (need_wait) {
nfs4_schedule_state_manager(clp);
+ nfs4_wait_clnt_recover(clp);
+ }
}
-static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
+static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
fmode_t flags)
{
struct nfs_delegation *delegation;
@@ -512,27 +571,21 @@ static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
continue;
if (delegation->type & flags)
- nfs_mark_return_delegation(server, delegation);
+ nfs_mark_return_if_closed_delegation(server, delegation);
}
}
-static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp,
+static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
fmode_t flags)
{
struct nfs_server *server;
rcu_read_lock();
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
- nfs_mark_return_all_delegation_types(server, flags);
+ nfs_mark_return_unused_delegation_types(server, flags);
rcu_read_unlock();
}
-static void nfs_delegation_run_state_manager(struct nfs_client *clp)
-{
- if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
- nfs4_schedule_state_manager(clp);
-}
-
void nfs_remove_bad_delegation(struct inode *inode)
{
struct nfs_delegation *delegation;
@@ -546,27 +599,17 @@ void nfs_remove_bad_delegation(struct inode *inode)
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
/**
- * nfs_expire_all_delegation_types
+ * nfs_expire_unused_delegation_types
* @clp: client to process
* @flags: delegation types to expire
*
*/
-void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
+void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags)
{
- nfs_client_mark_return_all_delegation_types(clp, flags);
+ nfs_client_mark_return_unused_delegation_types(clp, flags);
nfs_delegation_run_state_manager(clp);
}
-/**
- * nfs_expire_all_delegations
- * @clp: client to process
- *
- */
-void nfs_expire_all_delegations(struct nfs_client *clp)
-{
- nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
-}
-
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
{
struct nfs_delegation *delegation;
@@ -574,7 +617,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
continue;
- nfs_mark_return_delegation(server, delegation);
+ nfs_mark_return_if_closed_delegation(server, delegation);
}
}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index d54d4fca6793..9a79c7a99d6d 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -28,6 +28,7 @@ struct nfs_delegation {
enum {
NFS_DELEGATION_NEED_RECLAIM = 0,
NFS_DELEGATION_RETURN,
+ NFS_DELEGATION_RETURN_IF_CLOSED,
NFS_DELEGATION_REFERENCED,
NFS_DELEGATION_RETURNING,
};
@@ -41,7 +42,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
void nfs_server_return_all_delegations(struct nfs_server *);
void nfs_expire_all_delegations(struct nfs_client *clp);
-void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags);
+void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags);
void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
int nfs_client_return_marked_delegations(struct nfs_client *clp);
int nfs_delegations_present(struct nfs_client *clp);
@@ -53,7 +54,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
/* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync);
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
-int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
+int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_t flags);
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f23f455be42b..e093e73178b7 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1486,6 +1486,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
goto no_open;
if (d_mountpoint(dentry))
goto no_open;
+ if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1)
+ goto no_open;
inode = dentry->d_inode;
parent = dget_parent(dentry);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 29f4a48a0ee6..a87a44f84113 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -744,6 +744,7 @@ static int
do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{
struct inode *inode = filp->f_mapping->host;
+ struct nfs_lock_context *l_ctx;
int status;
/*
@@ -752,6 +753,14 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
*/
nfs_sync_mapping(filp->f_mapping);
+ l_ctx = nfs_get_lock_context(nfs_file_open_context(filp));
+ if (!IS_ERR(l_ctx)) {
+ status = nfs_iocounter_wait(&l_ctx->io_count);
+ nfs_put_lock_context(l_ctx);
+ if (status < 0)
+ return status;
+ }
+
/* NOTE: special case
* If we're signalled while cleaning up locks on process exit, we
* still need to complete the unlock.
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1f941674b089..c1c7a9d78722 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -561,20 +561,22 @@ static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
l_ctx->lockowner.l_owner = current->files;
l_ctx->lockowner.l_pid = current->tgid;
INIT_LIST_HEAD(&l_ctx->list);
+ nfs_iocounter_init(&l_ctx->io_count);
}
static struct nfs_lock_context *__nfs_find_lock_context(struct nfs_open_context *ctx)
{
- struct nfs_lock_context *pos;
+ struct nfs_lock_context *head = &ctx->lock_context;
+ struct nfs_lock_context *pos = head;
- list_for_each_entry(pos, &ctx->lock_context.list, list) {
+ do {
if (pos->lockowner.l_owner != current->files)
continue;
if (pos->lockowner.l_pid != current->tgid)
continue;
atomic_inc(&pos->count);
return pos;
- }
+ } while ((pos = list_entry(pos->list.next, typeof(*pos), list)) != head);
return NULL;
}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 541c9ebdbc5a..91e59a39fc08 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -229,6 +229,13 @@ extern void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
struct nfs_pgio_header *hdr,
void (*release)(struct nfs_pgio_header *hdr));
void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos);
+int nfs_iocounter_wait(struct nfs_io_counter *c);
+
+static inline void nfs_iocounter_init(struct nfs_io_counter *c)
+{
+ c->flags = 0;
+ atomic_set(&c->io_count, 0);
+}
/* nfs2xdr.c */
extern struct rpc_procinfo nfs_procedures[];
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 944c9a5c1039..553a83cc4106 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -36,6 +36,7 @@ enum nfs4_client_state {
struct nfs4_minor_version_ops {
u32 minor_version;
+ unsigned init_caps;
int (*call_sync)(struct rpc_clnt *clnt,
struct nfs_server *server,
@@ -143,12 +144,14 @@ struct nfs4_lock_state {
enum {
LK_STATE_IN_USE,
NFS_DELEGATED_STATE, /* Current stateid is delegation */
+ NFS_OPEN_STATE, /* OPEN stateid is set */
NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */
NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */
NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */
+ NFS_STATE_RECOVERY_FAILED, /* OPEN stateid state recovery failed */
};
struct nfs4_state {
@@ -233,6 +236,10 @@ extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr
extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *);
extern int nfs4_release_lockowner(struct nfs4_lock_state *);
extern const struct xattr_handler *nfs4_xattr_handlers[];
+extern int nfs4_set_rw_stateid(nfs4_stateid *stateid,
+ const struct nfs_open_context *ctx,
+ const struct nfs_lock_context *l_ctx,
+ fmode_t fmode);
#if defined(CONFIG_NFS_V4_1)
static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
@@ -347,13 +354,13 @@ extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
extern void nfs4_schedule_state_manager(struct nfs_client *);
extern void nfs4_schedule_path_down_recovery(struct nfs_client *clp);
-extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
+extern int nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *);
extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags);
extern void nfs41_handle_server_scope(struct nfs_client *,
struct nfs41_server_scope **);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
-extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
+extern int nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
fmode_t, const struct nfs_lockowner *);
extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
@@ -412,6 +419,11 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei
return memcmp(dst, src, sizeof(*dst)) == 0;
}
+static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
+{
+ return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
+}
+
#else
#define nfs4_close_state(a, b) do { } while (0)
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index ac4fc9a8fdbc..947b0c908aa9 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -198,8 +198,12 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
/* Check NFS protocol revision and initialize RPC op vector */
clp->rpc_ops = &nfs_v4_clientops;
+ if (clp->cl_minorversion != 0)
+ __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
__set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
- error = nfs_create_rpc_client(clp, timeparms, authflavour);
+ error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
+ if (error == -EINVAL)
+ error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_NULL);
if (error < 0)
goto error;
@@ -300,7 +304,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
struct rpc_cred *cred)
{
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
- struct nfs_client *pos, *n, *prev = NULL;
+ struct nfs_client *pos, *prev = NULL;
struct nfs4_setclientid_res clid = {
.clientid = new->cl_clientid,
.confirm = new->cl_confirm,
@@ -308,10 +312,23 @@ int nfs40_walk_client_list(struct nfs_client *new,
int status = -NFS4ERR_STALE_CLIENTID;
spin_lock(&nn->nfs_client_lock);
- list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+ list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
/* If "pos" isn't marked ready, we can't trust the
* remaining fields in "pos" */
- if (pos->cl_cons_state < NFS_CS_READY)
+ if (pos->cl_cons_state > NFS_CS_READY) {
+ atomic_inc(&pos->cl_count);
+ spin_unlock(&nn->nfs_client_lock);
+
+ if (prev)
+ nfs_put_client(prev);
+ prev = pos;
+
+ status = nfs_wait_client_init_complete(pos);
+ spin_lock(&nn->nfs_client_lock);
+ if (status < 0)
+ continue;
+ }
+ if (pos->cl_cons_state != NFS_CS_READY)
continue;
if (pos->rpc_ops != new->rpc_ops)
@@ -423,16 +440,16 @@ int nfs41_walk_client_list(struct nfs_client *new,
struct rpc_cred *cred)
{
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
- struct nfs_client *pos, *n, *prev = NULL;
+ struct nfs_client *pos, *prev = NULL;
int status = -NFS4ERR_STALE_CLIENTID;
spin_lock(&nn->nfs_client_lock);
- list_for_each_entry_safe(pos, n, &nn->nfs_client_list, cl_share_link) {
+ list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
/* If "pos" isn't marked ready, we can't trust the
* remaining fields in "pos", especially the client
* ID and serverowner fields. Wait for CREATE_SESSION
* to finish. */
- if (pos->cl_cons_state < NFS_CS_READY) {
+ if (pos->cl_cons_state > NFS_CS_READY) {
atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);
@@ -440,18 +457,17 @@ int nfs41_walk_client_list(struct nfs_client *new,
nfs_put_client(prev);
prev = pos;
- nfs4_schedule_lease_recovery(pos);
status = nfs_wait_client_init_complete(pos);
- if (status < 0) {
- nfs_put_client(pos);
- spin_lock(&nn->nfs_client_lock);
- continue;
+ if (status == 0) {
+ nfs4_schedule_lease_recovery(pos);
+ status = nfs4_wait_clnt_recover(pos);
}
- status = pos->cl_cons_state;
spin_lock(&nn->nfs_client_lock);
if (status < 0)
continue;
}
+ if (pos->cl_cons_state != NFS_CS_READY)
+ continue;
if (pos->rpc_ops != new->rpc_ops)
continue;
@@ -469,17 +485,18 @@ int nfs41_walk_client_list(struct nfs_client *new,
continue;
atomic_inc(&pos->cl_count);
- spin_unlock(&nn->nfs_client_lock);
+ *result = pos;
+ status = 0;
dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
__func__, pos, atomic_read(&pos->cl_count));
-
- *result = pos;
- return 0;
+ break;
}
/* No matching nfs_client found. */
spin_unlock(&nn->nfs_client_lock);
dprintk("NFS: <-- %s status = %d\n", __func__, status);
+ if (prev)
+ nfs_put_client(prev);
return status;
}
#endif /* CONFIG_NFS_V4_1 */
@@ -717,6 +734,19 @@ static int nfs4_server_common_setup(struct nfs_server *server,
if (error < 0)
goto out;
+ /* Set the basic capabilities */
+ server->caps |= server->nfs_client->cl_mvops->init_caps;
+ if (server->flags & NFS_MOUNT_NORDIRPLUS)
+ server->caps &= ~NFS_CAP_READDIRPLUS;
+ /*
+ * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
+ * authentication.
+ */
+ if (nfs4_disable_idmapping &&
+ server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
+ server->caps |= NFS_CAP_UIDGID_NOMAP;
+
+
/* Probe the root fh to retrieve its FSID and filehandle */
error = nfs4_get_rootfh(server, mntfh);
if (error < 0)
@@ -760,9 +790,6 @@ static int nfs4_init_server(struct nfs_server *server,
/* Initialise the client representation from the mount data */
server->flags = data->flags;
- server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|NFS_CAP_POSIX_LOCK;
- if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
- server->caps |= NFS_CAP_READDIRPLUS;
server->options = data->options;
/* Get a client record */
@@ -779,13 +806,6 @@ static int nfs4_init_server(struct nfs_server *server,
if (error < 0)
goto error;
- /*
- * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
- * authentication.
- */
- if (nfs4_disable_idmapping && data->auth_flavors[0] == RPC_AUTH_UNIX)
- server->caps |= NFS_CAP_UIDGID_NOMAP;
-
if (data->rsize)
server->rsize = nfs_block_size(data->rsize, NULL);
if (data->wsize)
@@ -863,7 +883,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
/* Initialise the client representation from the parent server */
nfs_server_copy_userdata(server, parent_server);
- server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
/* Get a client representation.
* Note: NFSv4 always uses TCP, */
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 4fb234d3aefb..22d10623f5ee 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -158,11 +158,14 @@ static int filelayout_async_handle_error(struct rpc_task *task,
case -NFS4ERR_OPENMODE:
if (state == NULL)
break;
- nfs4_schedule_stateid_recovery(mds_server, state);
+ if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
+ goto out_bad_stateid;
goto wait_on_recovery;
case -NFS4ERR_EXPIRED:
- if (state != NULL)
- nfs4_schedule_stateid_recovery(mds_server, state);
+ if (state != NULL) {
+ if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
+ goto out_bad_stateid;
+ }
nfs4_schedule_lease_recovery(mds_client);
goto wait_on_recovery;
/* DS session errors */
@@ -226,6 +229,9 @@ reset:
out:
task->tk_status = 0;
return -EAGAIN;
+out_bad_stateid:
+ task->tk_status = -EIO;
+ return 0;
wait_on_recovery:
rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
@@ -299,6 +305,10 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
{
struct nfs_read_data *rdata = data;
+ if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) {
+ rpc_exit(task, -EIO);
+ return;
+ }
if (filelayout_reset_to_mds(rdata->header->lseg)) {
dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
filelayout_reset_read(rdata);
@@ -307,10 +317,13 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
}
rdata->read_done_cb = filelayout_read_done_cb;
- nfs41_setup_sequence(rdata->ds_clp->cl_session,
+ if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
&rdata->args.seq_args,
&rdata->res.seq_res,
- task);
+ task))
+ return;
+ nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
+ rdata->args.lock_context, FMODE_READ);
}
static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -401,16 +414,23 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
{
struct nfs_write_data *wdata = data;
+ if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) {
+ rpc_exit(task, -EIO);
+ return;
+ }
if (filelayout_reset_to_mds(wdata->header->lseg)) {
dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
filelayout_reset_write(wdata);
rpc_exit(task, 0);
return;
}
- nfs41_setup_sequence(wdata->ds_clp->cl_session,
+ if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
&wdata->args.seq_args,
&wdata->res.seq_res,
- task);
+ task))
+ return;
+ nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
+ wdata->args.lock_context, FMODE_WRITE);
}
static void filelayout_write_call_done(struct rpc_task *task, void *data)
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 0dd766079e1c..cdb0b41a4810 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
return ret;
}
+/**
+ * nfs_find_best_sec - Find a security mechanism supported locally
+ * @flavors: List of security tuples returned by SECINFO procedure
+ *
+ * Return the pseudoflavor of the first security mechanism in
+ * "flavors" that is locally supported. Return RPC_AUTH_UNIX if
+ * no matching flavor is found in the array. The "flavors" array
+ * is searched in the order returned from the server, per RFC 3530
+ * recommendation.
+ */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
- struct gss_api_mech *mech;
- struct xdr_netobj oid;
- int i;
- rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
+ rpc_authflavor_t pseudoflavor;
+ struct nfs4_secinfo4 *secinfo;
+ unsigned int i;
for (i = 0; i < flavors->num_flavors; i++) {
- struct nfs4_secinfo_flavor *flavor;
- flavor = &flavors->flavors[i];
-
- if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
- pseudoflavor = flavor->flavor;
- break;
- } else if (flavor->flavor == RPC_AUTH_GSS) {
- oid.len = flavor->gss.sec_oid4.len;
- oid.data = flavor->gss.sec_oid4.data;
- mech = gss_mech_get_by_OID(&oid);
- if (!mech)
- continue;
- pseudoflavor = gss_svc_to_pseudoflavor(mech, flavor->gss.service);
- gss_mech_put(mech);
+ secinfo = &flavors->flavors[i];
+
+ switch (secinfo->flavor) {
+ case RPC_AUTH_NULL:
+ case RPC_AUTH_UNIX:
+ case RPC_AUTH_GSS:
+ pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
+ &secinfo->flavor_info);
+ if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
+ return pseudoflavor;
break;
}
}
- return pseudoflavor;
+ return RPC_AUTH_UNIX;
}
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 26431cf62ddb..9da4bd55eb30 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -107,6 +107,8 @@ static int nfs4_map_errors(int err)
return -EPROTONOSUPPORT;
case -NFS4ERR_ACCESS:
return -EACCES;
+ case -NFS4ERR_FILE_OPEN:
+ return -EBUSY;
default:
dprintk("%s could not handle NFSv4 error %d\n",
__func__, -err);
@@ -295,19 +297,30 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
}
if (state == NULL)
break;
- nfs4_schedule_stateid_recovery(server, state);
+ ret = nfs4_schedule_stateid_recovery(server, state);
+ if (ret < 0)
+ break;
goto wait_on_recovery;
case -NFS4ERR_DELEG_REVOKED:
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_BAD_STATEID:
+ if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) {
+ nfs_remove_bad_delegation(inode);
+ exception->retry = 1;
+ break;
+ }
if (state == NULL)
break;
- nfs_remove_bad_delegation(state->inode);
- nfs4_schedule_stateid_recovery(server, state);
+ ret = nfs4_schedule_stateid_recovery(server, state);
+ if (ret < 0)
+ break;
goto wait_on_recovery;
case -NFS4ERR_EXPIRED:
- if (state != NULL)
- nfs4_schedule_stateid_recovery(server, state);
+ if (state != NULL) {
+ ret = nfs4_schedule_stateid_recovery(server, state);
+ if (ret < 0)
+ break;
+ }
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_STALE_CLIENTID:
nfs4_schedule_lease_recovery(clp);
@@ -756,10 +769,40 @@ struct nfs4_opendata {
struct iattr attrs;
unsigned long timestamp;
unsigned int rpc_done : 1;
+ unsigned int is_recover : 1;
int rpc_status;
int cancelled;
};
+static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
+ int err, struct nfs4_exception *exception)
+{
+ if (err != -EINVAL)
+ return false;
+ if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
+ return false;
+ server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1;
+ exception->retry = 1;
+ return true;
+}
+
+static enum open_claim_type4
+nfs4_map_atomic_open_claim(struct nfs_server *server,
+ enum open_claim_type4 claim)
+{
+ if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
+ return claim;
+ switch (claim) {
+ default:
+ return claim;
+ case NFS4_OPEN_CLAIM_FH:
+ return NFS4_OPEN_CLAIM_NULL;
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+ return NFS4_OPEN_CLAIM_DELEGATE_CUR;
+ case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
+ return NFS4_OPEN_CLAIM_DELEGATE_PREV;
+ }
+}
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
{
@@ -775,6 +818,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
struct nfs4_state_owner *sp, fmode_t fmode, int flags,
const struct iattr *attrs,
+ enum open_claim_type4 claim,
gfp_t gfp_mask)
{
struct dentry *parent = dget_parent(dentry);
@@ -793,7 +837,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->dir = parent;
p->owner = sp;
atomic_inc(&sp->so_count);
- p->o_arg.fh = NFS_FH(dir);
p->o_arg.open_flags = flags;
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
/* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
@@ -811,7 +854,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
- p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+ p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
+ switch (p->o_arg.claim) {
+ case NFS4_OPEN_CLAIM_NULL:
+ case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+ case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+ p->o_arg.fh = NFS_FH(dir);
+ break;
+ case NFS4_OPEN_CLAIM_PREVIOUS:
+ case NFS4_OPEN_CLAIM_FH:
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+ case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
+ p->o_arg.fh = NFS_FH(dentry->d_inode);
+ }
if (attrs != NULL && attrs->ia_valid != 0) {
__be32 verf[2];
@@ -924,6 +979,7 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
nfs4_stateid_copy(&state->stateid, stateid);
nfs4_stateid_copy(&state->open_stateid, stateid);
+ set_bit(NFS_OPEN_STATE, &state->flags);
switch (fmode) {
case FMODE_READ:
set_bit(NFS_O_RDONLY_STATE, &state->flags);
@@ -1046,9 +1102,12 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
/* Save the delegation */
nfs4_stateid_copy(&stateid, &delegation->stateid);
rcu_read_unlock();
- ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
- if (ret != 0)
- goto out;
+ nfs_release_seqid(opendata->o_arg.seqid);
+ if (!opendata->is_recover) {
+ ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
+ if (ret != 0)
+ goto out;
+ }
ret = -EAGAIN;
/* Try to update the stateid using the delegation */
@@ -1193,11 +1252,13 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
return ERR_PTR(-ENOENT);
}
-static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state)
+static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx,
+ struct nfs4_state *state, enum open_claim_type4 claim)
{
struct nfs4_opendata *opendata;
- opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS);
+ opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
+ NULL, claim, GFP_NOFS);
if (opendata == NULL)
return ERR_PTR(-ENOMEM);
opendata->state = state;
@@ -1233,6 +1294,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
/* memory barrier prior to reading state->n_* */
clear_bit(NFS_DELEGATED_STATE, &state->flags);
+ clear_bit(NFS_OPEN_STATE, &state->flags);
smp_rmb();
if (state->n_rdwr != 0) {
clear_bit(NFS_O_RDWR_STATE, &state->flags);
@@ -1283,11 +1345,10 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
fmode_t delegation_type = 0;
int status;
- opendata = nfs4_open_recoverdata_alloc(ctx, state);
+ opendata = nfs4_open_recoverdata_alloc(ctx, state,
+ NFS4_OPEN_CLAIM_PREVIOUS);
if (IS_ERR(opendata))
return PTR_ERR(opendata);
- opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
- opendata->o_arg.fh = NFS_FH(state->inode);
rcu_read_lock();
delegation = rcu_dereference(NFS_I(state->inode)->delegation);
if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
@@ -1306,6 +1367,8 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
int err;
do {
err = _nfs4_do_open_reclaim(ctx, state);
+ if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
+ continue;
if (err != -NFS4ERR_DELAY)
break;
nfs4_handle_exception(server, err, &exception);
@@ -1320,71 +1383,72 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
ctx = nfs4_state_find_open_context(state);
if (IS_ERR(ctx))
- return PTR_ERR(ctx);
+ return -EAGAIN;
ret = nfs4_do_open_reclaim(ctx, state);
put_nfs_open_context(ctx);
return ret;
}
-static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
+static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err)
{
- struct nfs4_opendata *opendata;
- int ret;
-
- opendata = nfs4_open_recoverdata_alloc(ctx, state);
- if (IS_ERR(opendata))
- return PTR_ERR(opendata);
- opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
- nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
- ret = nfs4_open_recover(opendata, state);
- nfs4_opendata_put(opendata);
- return ret;
+ switch (err) {
+ default:
+ printk(KERN_ERR "NFS: %s: unhandled error "
+ "%d.\n", __func__, err);
+ case 0:
+ case -ENOENT:
+ case -ESTALE:
+ break;
+ case -NFS4ERR_BADSESSION:
+ case -NFS4ERR_BADSLOT:
+ case -NFS4ERR_BAD_HIGH_SLOT:
+ case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+ case -NFS4ERR_DEADSESSION:
+ set_bit(NFS_DELEGATED_STATE, &state->flags);
+ nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
+ return -EAGAIN;
+ case -NFS4ERR_STALE_CLIENTID:
+ case -NFS4ERR_STALE_STATEID:
+ set_bit(NFS_DELEGATED_STATE, &state->flags);
+ case -NFS4ERR_EXPIRED:
+ /* Don't recall a delegation if it was lost */
+ nfs4_schedule_lease_recovery(server->nfs_client);
+ return -EAGAIN;
+ case -NFS4ERR_DELEG_REVOKED:
+ case -NFS4ERR_ADMIN_REVOKED:
+ case -NFS4ERR_BAD_STATEID:
+ case -NFS4ERR_OPENMODE:
+ nfs_inode_find_state_and_recover(state->inode,
+ stateid);
+ nfs4_schedule_stateid_recovery(server, state);
+ return 0;
+ case -NFS4ERR_DELAY:
+ case -NFS4ERR_GRACE:
+ set_bit(NFS_DELEGATED_STATE, &state->flags);
+ ssleep(1);
+ return -EAGAIN;
+ case -ENOMEM:
+ case -NFS4ERR_DENIED:
+ /* kill_proc(fl->fl_pid, SIGLOST, 1); */
+ return 0;
+ }
+ return err;
}
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
- struct nfs4_exception exception = { };
struct nfs_server *server = NFS_SERVER(state->inode);
+ struct nfs4_opendata *opendata;
int err;
- do {
- err = _nfs4_open_delegation_recall(ctx, state, stateid);
- switch (err) {
- case 0:
- case -ENOENT:
- case -ESTALE:
- goto out;
- case -NFS4ERR_BADSESSION:
- case -NFS4ERR_BADSLOT:
- case -NFS4ERR_BAD_HIGH_SLOT:
- case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
- case -NFS4ERR_DEADSESSION:
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
- err = -EAGAIN;
- goto out;
- case -NFS4ERR_STALE_CLIENTID:
- case -NFS4ERR_STALE_STATEID:
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- case -NFS4ERR_EXPIRED:
- /* Don't recall a delegation if it was lost */
- nfs4_schedule_lease_recovery(server->nfs_client);
- err = -EAGAIN;
- goto out;
- case -NFS4ERR_DELEG_REVOKED:
- case -NFS4ERR_ADMIN_REVOKED:
- case -NFS4ERR_BAD_STATEID:
- nfs_inode_find_state_and_recover(state->inode,
- stateid);
- nfs4_schedule_stateid_recovery(server, state);
- case -ENOMEM:
- err = 0;
- goto out;
- }
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- err = nfs4_handle_exception(server, err, &exception);
- } while (exception.retry);
-out:
- return err;
+
+ opendata = nfs4_open_recoverdata_alloc(ctx, state,
+ NFS4_OPEN_CLAIM_DELEG_CUR_FH);
+ if (IS_ERR(opendata))
+ return PTR_ERR(opendata);
+ nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
+ err = nfs4_open_recover(opendata, state);
+ nfs4_opendata_put(opendata);
+ return nfs4_handle_delegation_recall_error(server, state, stateid, err);
}
static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
@@ -1467,6 +1531,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
{
struct nfs4_opendata *data = calldata;
struct nfs4_state_owner *sp = data->owner;
+ struct nfs_client *clp = sp->so_server->nfs_client;
if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
goto out_wait;
@@ -1482,15 +1547,20 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
rcu_read_lock();
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
+ data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH &&
can_open_delegated(delegation, data->o_arg.fmode))
goto unlock_no_action;
rcu_read_unlock();
}
/* Update client id. */
- data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
- if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
- task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+ data->o_arg.clientid = clp->cl_clientid;
+ switch (data->o_arg.claim) {
+ case NFS4_OPEN_CLAIM_PREVIOUS:
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+ case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
+ case NFS4_OPEN_CLAIM_FH:
+ task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
}
data->timestamp = jiffies;
@@ -1499,6 +1569,16 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
&data->o_res.seq_res,
task) != 0)
nfs_release_seqid(data->o_arg.seqid);
+
+ /* Set the create mode (note dependency on the session type) */
+ data->o_arg.createmode = NFS4_CREATE_UNCHECKED;
+ if (data->o_arg.open_flags & O_EXCL) {
+ data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE;
+ if (nfs4_has_persistent_session(clp))
+ data->o_arg.createmode = NFS4_CREATE_GUARDED;
+ else if (clp->cl_mvops->minor_version > 0)
+ data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1;
+ }
return;
unlock_no_action:
rcu_read_unlock();
@@ -1594,8 +1674,11 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
data->rpc_done = 0;
data->rpc_status = 0;
data->cancelled = 0;
- if (isrecover)
+ data->is_recover = 0;
+ if (isrecover) {
nfs4_set_sequence_privileged(&o_arg->seq_args);
+ data->is_recover = 1;
+ }
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -1720,7 +1803,8 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
struct nfs4_opendata *opendata;
int ret;
- opendata = nfs4_open_recoverdata_alloc(ctx, state);
+ opendata = nfs4_open_recoverdata_alloc(ctx, state,
+ NFS4_OPEN_CLAIM_FH);
if (IS_ERR(opendata))
return PTR_ERR(opendata);
ret = nfs4_open_recover(opendata, state);
@@ -1738,6 +1822,8 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
do {
err = _nfs4_open_expired(ctx, state);
+ if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
+ continue;
switch (err) {
default:
goto out;
@@ -1758,7 +1844,7 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
ctx = nfs4_state_find_open_context(state);
if (IS_ERR(ctx))
- return PTR_ERR(ctx);
+ return -EAGAIN;
ret = nfs4_do_open_expired(ctx, state);
put_nfs_open_context(ctx);
return ret;
@@ -1820,6 +1906,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ clear_bit(NFS_OPEN_STATE, &state->flags);
}
return status;
}
@@ -1880,10 +1967,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
if (ret != 0)
goto out;
- if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
+ if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
nfs4_schedule_stateid_recovery(server, state);
- nfs4_wait_clnt_recover(server->nfs_client);
- }
*res = state;
out:
return ret;
@@ -1905,6 +1990,7 @@ static int _nfs4_do_open(struct inode *dir,
struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_opendata *opendata;
+ enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
int status;
/* Protect against reboot recovery conflicts */
@@ -1920,7 +2006,10 @@ static int _nfs4_do_open(struct inode *dir,
if (dentry->d_inode != NULL)
nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
status = -ENOMEM;
- opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL);
+ if (dentry->d_inode)
+ claim = NFS4_OPEN_CLAIM_FH;
+ opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
+ claim, GFP_KERNEL);
if (opendata == NULL)
goto err_put_state_owner;
@@ -1937,7 +2026,8 @@ static int _nfs4_do_open(struct inode *dir,
if (status != 0)
goto err_opendata_put;
- if (opendata->o_arg.open_flags & O_EXCL) {
+ if ((opendata->o_arg.open_flags & O_EXCL) &&
+ (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
nfs4_exclusive_attrset(opendata, sattr);
nfs_fattr_init(opendata->o_res.f_attr);
@@ -1978,6 +2068,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
struct rpc_cred *cred,
struct nfs4_threshold **ctx_th)
{
+ struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { };
struct nfs4_state *res;
int status;
@@ -2021,7 +2112,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
exception.retry = 1;
continue;
}
- res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
+ if (nfs4_clear_cap_atomic_open_v1(server, status, &exception))
+ continue;
+ res = ERR_PTR(nfs4_handle_exception(server,
status, &exception));
} while (exception.retry);
return res;
@@ -2049,20 +2142,25 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
.rpc_cred = cred,
};
unsigned long timestamp = jiffies;
+ fmode_t fmode;
+ bool truncate;
int status;
nfs_fattr_init(fattr);
- if (state != NULL) {
+ /* Servers should only apply open mode checks for file size changes */
+ truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
+ fmode = truncate ? FMODE_WRITE : FMODE_READ;
+
+ if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
+ /* Use that stateid */
+ } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
struct nfs_lockowner lockowner = {
.l_owner = current->files,
.l_pid = current->tgid,
};
nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
&lockowner);
- } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
- FMODE_WRITE)) {
- /* Use that stateid */
} else
nfs4_stateid_copy(&arg.stateid, &zero_stateid);
@@ -2086,6 +2184,13 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
err = _nfs4_do_setattr(inode, cred, fattr, sattr, state);
switch (err) {
case -NFS4ERR_OPENMODE:
+ if (!(sattr->ia_valid & ATTR_SIZE)) {
+ pr_warn_once("NFSv4: server %s is incorrectly "
+ "applying open mode checks to "
+ "a SETATTR that is not "
+ "changing file size.\n",
+ server->nfs_client->cl_hostname);
+ }
if (state && !(state->state & FMODE_WRITE)) {
err = -EBADF;
if (sattr->ia_valid & ATTR_OPEN)
@@ -2129,11 +2234,19 @@ static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
fmode_t fmode)
{
spin_lock(&state->owner->so_lock);
- if (!(fmode & FMODE_READ))
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ switch (fmode & (FMODE_READ|FMODE_WRITE)) {
+ case FMODE_WRITE:
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
- if (!(fmode & FMODE_WRITE))
+ break;
+ case FMODE_READ:
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
- clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ break;
+ case 0:
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+ clear_bit(NFS_OPEN_STATE, &state->flags);
+ }
spin_unlock(&state->owner->so_lock);
}
@@ -2201,6 +2314,8 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
calldata->arg.fmode &= ~FMODE_WRITE;
}
}
+ if (!nfs4_valid_open_stateid(state))
+ call_close = 0;
spin_unlock(&state->owner->so_lock);
if (!call_close) {
@@ -2211,8 +2326,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
if (calldata->arg.fmode == 0) {
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
if (calldata->roc &&
- pnfs_roc_drain(inode, &calldata->roc_barrier, task))
+ pnfs_roc_drain(inode, &calldata->roc_barrier, task)) {
+ nfs_release_seqid(calldata->arg.seqid);
goto out_wait;
+ }
}
nfs_fattr_init(calldata->res.fattr);
@@ -2443,7 +2560,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
auth = rpcauth_create(flavor, server->client);
if (IS_ERR(auth)) {
- ret = -EIO;
+ ret = -EACCES;
goto out;
}
ret = nfs4_lookup_root(server, fhandle, info);
@@ -2451,27 +2568,36 @@ out:
return ret;
}
+/*
+ * Retry pseudoroot lookup with various security flavors. We do this when:
+ *
+ * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
+ * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
+ *
+ * Returns zero on success, or a negative NFS4ERR value, or a
+ * negative errno value.
+ */
static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
- int i, len, status = 0;
- rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
-
- len = rpcauth_list_flavors(flav_array, ARRAY_SIZE(flav_array));
- if (len < 0)
- return len;
-
- for (i = 0; i < len; i++) {
- /* AUTH_UNIX is the default flavor if none was specified,
- * thus has already been tried. */
- if (flav_array[i] == RPC_AUTH_UNIX)
- continue;
+ /* Per 3530bis 15.33.5 */
+ static const rpc_authflavor_t flav_array[] = {
+ RPC_AUTH_GSS_KRB5P,
+ RPC_AUTH_GSS_KRB5I,
+ RPC_AUTH_GSS_KRB5,
+ RPC_AUTH_UNIX, /* courtesy */
+ RPC_AUTH_NULL,
+ };
+ int status = -EPERM;
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
continue;
break;
}
+
/*
* -EACCESS could mean that the user doesn't have correct permissions
* to access the mount. It could also mean that we tried to mount
@@ -2484,24 +2610,36 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
return status;
}
-/*
- * get the file handle for the "/" directory on the server
+static int nfs4_do_find_root_sec(struct nfs_server *server,
+ struct nfs_fh *fhandle, struct nfs_fsinfo *info)
+{
+ int mv = server->nfs_client->cl_minorversion;
+ return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
+}
+
+/**
+ * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
+ * @server: initialized nfs_server handle
+ * @fhandle: we fill in the pseudo-fs root file handle
+ * @info: we fill in an FSINFO struct
+ *
+ * Returns zero on success, or a negative errno.
*/
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info)
{
- int minor_version = server->nfs_client->cl_minorversion;
- int status = nfs4_lookup_root(server, fhandle, info);
- if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
- /*
- * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
- * by nfs4_map_errors() as this function exits.
- */
- status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
+ int status;
+
+ status = nfs4_lookup_root(server, fhandle, info);
+ if ((status == -NFS4ERR_WRONGSEC) &&
+ !(server->flags & NFS_MOUNT_SECFLAVOUR))
+ status = nfs4_do_find_root_sec(server, fhandle, info);
+
if (status == 0)
status = nfs4_server_capabilities(server, fhandle);
if (status == 0)
status = nfs4_do_fsinfo(server, fhandle, info);
+
return nfs4_map_errors(status);
}
@@ -3380,12 +3518,21 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
struct nfs4_exception exception = { };
+ unsigned long now = jiffies;
int err;
do {
- err = nfs4_handle_exception(server,
- _nfs4_do_fsinfo(server, fhandle, fsinfo),
- &exception);
+ err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
+ if (err == 0) {
+ struct nfs_client *clp = server->nfs_client;
+
+ spin_lock(&clp->cl_lock);
+ clp->cl_lease_time = fsinfo->lease_time * HZ;
+ clp->cl_last_renewal = now;
+ spin_unlock(&clp->cl_lock);
+ break;
+ }
+ err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
@@ -3445,6 +3592,46 @@ static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
return err;
}
+int nfs4_set_rw_stateid(nfs4_stateid *stateid,
+ const struct nfs_open_context *ctx,
+ const struct nfs_lock_context *l_ctx,
+ fmode_t fmode)
+{
+ const struct nfs_lockowner *lockowner = NULL;
+
+ if (l_ctx != NULL)
+ lockowner = &l_ctx->lockowner;
+ return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner);
+}
+EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
+
+static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
+ const struct nfs_open_context *ctx,
+ const struct nfs_lock_context *l_ctx,
+ fmode_t fmode)
+{
+ nfs4_stateid current_stateid;
+
+ if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
+ return false;
+ return nfs4_stateid_match(stateid, &current_stateid);
+}
+
+static bool nfs4_error_stateid_expired(int err)
+{
+ switch (err) {
+ case -NFS4ERR_DELEG_REVOKED:
+ case -NFS4ERR_ADMIN_REVOKED:
+ case -NFS4ERR_BAD_STATEID:
+ case -NFS4ERR_STALE_STATEID:
+ case -NFS4ERR_OLD_STATEID:
+ case -NFS4ERR_OPENMODE:
+ case -NFS4ERR_EXPIRED:
+ return true;
+ }
+ return false;
+}
+
void __nfs4_read_done_cb(struct nfs_read_data *data)
{
nfs_invalidate_atime(data->header->inode);
@@ -3465,6 +3652,20 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
return 0;
}
+static bool nfs4_read_stateid_changed(struct rpc_task *task,
+ struct nfs_readargs *args)
+{
+
+ if (!nfs4_error_stateid_expired(task->tk_status) ||
+ nfs4_stateid_is_current(&args->stateid,
+ args->context,
+ args->lock_context,
+ FMODE_READ))
+ return false;
+ rpc_restart_call_prepare(task);
+ return true;
+}
+
static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
{
@@ -3472,7 +3673,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
if (!nfs4_sequence_done(task, &data->res.seq_res))
return -EAGAIN;
-
+ if (nfs4_read_stateid_changed(task, &data->args))
+ return -EAGAIN;
return data->read_done_cb ? data->read_done_cb(task, data) :
nfs4_read_done_cb(task, data);
}
@@ -3487,10 +3689,13 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
{
- nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+ if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args,
&data->res.seq_res,
- task);
+ task))
+ return;
+ nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+ data->args.lock_context, FMODE_READ);
}
static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
@@ -3508,10 +3713,26 @@ static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data
return 0;
}
+static bool nfs4_write_stateid_changed(struct rpc_task *task,
+ struct nfs_writeargs *args)
+{
+
+ if (!nfs4_error_stateid_expired(task->tk_status) ||
+ nfs4_stateid_is_current(&args->stateid,
+ args->context,
+ args->lock_context,
+ FMODE_WRITE))
+ return false;
+ rpc_restart_call_prepare(task);
+ return true;
+}
+
static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
{
if (!nfs4_sequence_done(task, &data->res.seq_res))
return -EAGAIN;
+ if (nfs4_write_stateid_changed(task, &data->args))
+ return -EAGAIN;
return data->write_done_cb ? data->write_done_cb(task, data) :
nfs4_write_done_cb(task, data);
}
@@ -3551,10 +3772,13 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
{
- nfs4_setup_sequence(NFS_SERVER(data->header->inode),
+ if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
&data->args.seq_args,
&data->res.seq_res,
- task);
+ task))
+ return;
+ nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+ data->args.lock_context, FMODE_WRITE);
}
static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
@@ -3656,7 +3880,7 @@ static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred,
return -ENOMEM;
data->client = clp;
data->timestamp = jiffies;
- return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
+ return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT,
&nfs4_renew_ops, data);
}
@@ -3670,7 +3894,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
unsigned long now = jiffies;
int status;
- status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+ status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (status < 0)
return status;
do_renew_lease(clp, now);
@@ -3980,11 +4204,14 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
case -NFS4ERR_OPENMODE:
if (state == NULL)
break;
- nfs4_schedule_stateid_recovery(server, state);
+ if (nfs4_schedule_stateid_recovery(server, state) < 0)
+ goto stateid_invalid;
goto wait_on_recovery;
case -NFS4ERR_EXPIRED:
- if (state != NULL)
- nfs4_schedule_stateid_recovery(server, state);
+ if (state != NULL) {
+ if (nfs4_schedule_stateid_recovery(server, state) < 0)
+ goto stateid_invalid;
+ }
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_STALE_CLIENTID:
nfs4_schedule_lease_recovery(clp);
@@ -4016,6 +4243,9 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
}
task->tk_status = nfs4_map_errors(task->tk_status);
return 0;
+stateid_invalid:
+ task->tk_status = -EIO;
+ return 0;
wait_on_recovery:
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
@@ -4143,27 +4373,17 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
struct nfs4_setclientid_res *arg,
struct rpc_cred *cred)
{
- struct nfs_fsinfo fsinfo;
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
.rpc_argp = arg,
- .rpc_resp = &fsinfo,
.rpc_cred = cred,
};
- unsigned long now;
int status;
dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
clp->cl_rpcclient->cl_auth->au_ops->au_name,
clp->cl_clientid);
- now = jiffies;
status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
- if (status == 0) {
- spin_lock(&clp->cl_lock);
- clp->cl_lease_time = fsinfo.lease_time * HZ;
- clp->cl_last_renewal = now;
- spin_unlock(&clp->cl_lock);
- }
dprintk("NFS reply setclientid_confirm: %d\n", status);
return status;
}
@@ -4627,17 +4847,23 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
goto out_release_lock_seqid;
}
- data->arg.open_stateid = &state->stateid;
+ data->arg.open_stateid = &state->open_stateid;
data->arg.new_lock_owner = 1;
data->res.open_seqid = data->arg.open_seqid;
} else
data->arg.new_lock_owner = 0;
+ if (!nfs4_valid_open_stateid(state)) {
+ data->rpc_status = -EBADF;
+ task->tk_action = NULL;
+ goto out_release_open_seqid;
+ }
data->timestamp = jiffies;
if (nfs4_setup_sequence(data->server,
&data->arg.seq_args,
&data->res.seq_res,
task) == 0)
return;
+out_release_open_seqid:
nfs_release_seqid(data->arg.open_seqid);
out_release_lock_seqid:
nfs_release_seqid(data->arg.lock_seqid);
@@ -4983,58 +5209,16 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
return status;
}
-int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
+int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
{
struct nfs_server *server = NFS_SERVER(state->inode);
- struct nfs4_exception exception = { };
int err;
err = nfs4_set_lock_state(state, fl);
if (err != 0)
- goto out;
- do {
- err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
- switch (err) {
- default:
- printk(KERN_ERR "NFS: %s: unhandled error "
- "%d.\n", __func__, err);
- case 0:
- case -ESTALE:
- goto out;
- case -NFS4ERR_STALE_CLIENTID:
- case -NFS4ERR_STALE_STATEID:
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- case -NFS4ERR_EXPIRED:
- nfs4_schedule_lease_recovery(server->nfs_client);
- err = -EAGAIN;
- goto out;
- case -NFS4ERR_BADSESSION:
- case -NFS4ERR_BADSLOT:
- case -NFS4ERR_BAD_HIGH_SLOT:
- case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
- case -NFS4ERR_DEADSESSION:
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
- err = -EAGAIN;
- goto out;
- case -NFS4ERR_DELEG_REVOKED:
- case -NFS4ERR_ADMIN_REVOKED:
- case -NFS4ERR_BAD_STATEID:
- case -NFS4ERR_OPENMODE:
- nfs4_schedule_stateid_recovery(server, state);
- err = 0;
- goto out;
- case -ENOMEM:
- case -NFS4ERR_DENIED:
- /* kill_proc(fl->fl_pid, SIGLOST, 1); */
- err = 0;
- goto out;
- }
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- err = nfs4_handle_exception(server, err, &exception);
- } while (exception.retry);
-out:
- return err;
+ return err;
+ err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
+ return nfs4_handle_delegation_recall_error(server, state, stateid, err);
}
struct nfs_release_lockowner_data {
@@ -5848,7 +6032,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
.rpc_client = clp->cl_rpcclient,
.rpc_message = &msg,
.callback_ops = &nfs41_sequence_ops,
- .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
+ .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
};
if (!atomic_inc_not_zero(&clp->cl_count))
@@ -6725,6 +6909,10 @@ static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
.minor_version = 0,
+ .init_caps = NFS_CAP_READDIRPLUS
+ | NFS_CAP_ATOMIC_OPEN
+ | NFS_CAP_CHANGE_ATTR
+ | NFS_CAP_POSIX_LOCK,
.call_sync = _nfs4_call_sync,
.match_stateid = nfs4_match_stateid,
.find_root_sec = nfs4_find_root_sec,
@@ -6736,6 +6924,12 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
#if defined(CONFIG_NFS_V4_1)
static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
.minor_version = 1,
+ .init_caps = NFS_CAP_READDIRPLUS
+ | NFS_CAP_ATOMIC_OPEN
+ | NFS_CAP_CHANGE_ATTR
+ | NFS_CAP_POSIX_LOCK
+ | NFS_CAP_STATEID_NFSV41
+ | NFS_CAP_ATOMIC_OPEN_V1,
.call_sync = nfs4_call_sync_sequence,
.match_stateid = nfs41_match_stateid,
.find_root_sec = nfs41_find_root_sec,
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 6ace365c6334..0b32f9483b7a 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -154,18 +154,6 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
return cred;
}
-static void nfs4_clear_machine_cred(struct nfs_client *clp)
-{
- struct rpc_cred *cred;
-
- spin_lock(&clp->cl_lock);
- cred = clp->cl_machine_cred;
- clp->cl_machine_cred = NULL;
- spin_unlock(&clp->cl_lock);
- if (cred != NULL)
- put_rpccred(cred);
-}
-
static struct rpc_cred *
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
{
@@ -699,6 +687,8 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
list_for_each_entry(state, &nfsi->open_states, inode_states) {
if (state->owner != owner)
continue;
+ if (!nfs4_valid_open_stateid(state))
+ continue;
if (atomic_inc_not_zero(&state->count))
return state;
}
@@ -987,13 +977,14 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
return 0;
}
-static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
+ struct nfs4_state *state,
const struct nfs_lockowner *lockowner)
{
struct nfs4_lock_state *lsp;
fl_owner_t fl_owner;
pid_t fl_pid;
- bool ret = false;
+ int ret = -ENOENT;
if (lockowner == NULL)
@@ -1008,7 +999,10 @@ static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
nfs4_stateid_copy(dst, &lsp->ls_stateid);
- ret = true;
+ ret = 0;
+ smp_rmb();
+ if (!list_empty(&lsp->ls_seqid.list))
+ ret = -EWOULDBLOCK;
}
spin_unlock(&state->state_lock);
nfs4_put_lock_state(lsp);
@@ -1016,28 +1010,44 @@ out:
return ret;
}
-static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
+ const nfs4_stateid *src;
+ int ret;
int seq;
do {
+ src = &zero_stateid;
seq = read_seqbegin(&state->seqlock);
- nfs4_stateid_copy(dst, &state->stateid);
+ if (test_bit(NFS_OPEN_STATE, &state->flags))
+ src = &state->open_stateid;
+ nfs4_stateid_copy(dst, src);
+ ret = 0;
+ smp_rmb();
+ if (!list_empty(&state->owner->so_seqid.list))
+ ret = -EWOULDBLOCK;
} while (read_seqretry(&state->seqlock, seq));
+ return ret;
}
/*
* Byte-range lock aware utility to initialize the stateid of read/write
* requests.
*/
-void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
fmode_t fmode, const struct nfs_lockowner *lockowner)
{
+ int ret = 0;
if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
- return;
- if (nfs4_copy_lock_stateid(dst, state, lockowner))
- return;
- nfs4_copy_open_stateid(dst, state);
+ goto out;
+ ret = nfs4_copy_lock_stateid(dst, state, lockowner);
+ if (ret != -ENOENT)
+ goto out;
+ ret = nfs4_copy_open_stateid(dst, state);
+out:
+ if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
+ dst->seqid = 0;
+ return ret;
}
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
@@ -1286,14 +1296,17 @@ static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_s
return 1;
}
-void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
+int nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
{
struct nfs_client *clp = server->nfs_client;
+ if (!nfs4_valid_open_stateid(state))
+ return -EBADF;
nfs4_state_mark_reclaim_nograce(clp, state);
dprintk("%s: scheduling stateid recovery for server %s\n", __func__,
clp->cl_hostname);
nfs4_schedule_state_manager(clp);
+ return 0;
}
EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
@@ -1323,6 +1336,27 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
nfs4_schedule_state_manager(clp);
}
+static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
+{
+ struct inode *inode = state->inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_open_context *ctx;
+
+ spin_lock(&inode->i_lock);
+ list_for_each_entry(ctx, &nfsi->open_files, list) {
+ if (ctx->state != state)
+ continue;
+ set_bit(NFS_CONTEXT_BAD, &ctx->flags);
+ }
+ spin_unlock(&inode->i_lock);
+}
+
+static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
+{
+ set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
+ nfs4_state_mark_open_context_bad(state);
+}
+
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
{
@@ -1398,6 +1432,8 @@ restart:
list_for_each_entry(state, &sp->so_states, open_states) {
if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
continue;
+ if (!nfs4_valid_open_stateid(state))
+ continue;
if (state->state == 0)
continue;
atomic_inc(&state->count);
@@ -1430,11 +1466,10 @@ restart:
* Open state on this file cannot be recovered
* All we can do is revert to using the zero stateid.
*/
- memset(&state->stateid, 0,
- sizeof(state->stateid));
- /* Mark the file as being 'closed' */
- state->state = 0;
+ nfs4_state_mark_recovery_failed(state, status);
break;
+ case -EAGAIN:
+ ssleep(1);
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
@@ -1696,6 +1731,10 @@ static int nfs4_check_lease(struct nfs_client *clp)
}
status = ops->renew_lease(clp, cred);
put_rpccred(cred);
+ if (status == -ETIMEDOUT) {
+ set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
+ return 0;
+ }
out:
return nfs4_recovery_handle_error(clp, status);
}
@@ -1725,10 +1764,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
return -EPERM;
case -EACCES:
- if (clp->cl_machine_cred == NULL)
- return -EACCES;
- /* Handle case where the user hasn't set up machine creds */
- nfs4_clear_machine_cred(clp);
case -NFS4ERR_DELAY:
case -ETIMEDOUT:
case -EAGAIN:
@@ -1823,31 +1858,18 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
{
const struct nfs4_state_recovery_ops *ops =
clp->cl_mvops->reboot_recovery_ops;
- rpc_authflavor_t *flavors, flav, save;
struct rpc_clnt *clnt;
struct rpc_cred *cred;
- int i, len, status;
+ int i, status;
dprintk("NFS: %s: testing '%s'\n", __func__, clp->cl_hostname);
- len = NFS_MAX_SECFLAVORS;
- flavors = kcalloc(len, sizeof(*flavors), GFP_KERNEL);
- if (flavors == NULL) {
- status = -ENOMEM;
- goto out;
- }
- len = rpcauth_list_flavors(flavors, len);
- if (len < 0) {
- status = len;
- goto out_free;
- }
clnt = clp->cl_rpcclient;
- save = clnt->cl_auth->au_flavor;
i = 0;
mutex_lock(&nfs_clid_init_mutex);
- status = -ENOENT;
again:
+ status = -ENOENT;
cred = ops->get_clid_cred(clp);
if (cred == NULL)
goto out_unlock;
@@ -1857,12 +1879,6 @@ again:
switch (status) {
case 0:
break;
-
- case -EACCES:
- if (clp->cl_machine_cred == NULL)
- break;
- /* Handle case where the user hasn't set up machine creds */
- nfs4_clear_machine_cred(clp);
case -NFS4ERR_DELAY:
case -ETIMEDOUT:
case -EAGAIN:
@@ -1871,22 +1887,23 @@ again:
dprintk("NFS: %s after status %d, retrying\n",
__func__, status);
goto again;
-
+ case -EACCES:
+ if (i++)
+ break;
case -NFS4ERR_CLID_INUSE:
case -NFS4ERR_WRONGSEC:
- status = -EPERM;
- if (i >= len)
- break;
-
- flav = flavors[i++];
- if (flav == save)
- flav = flavors[i++];
- clnt = rpc_clone_client_set_auth(clnt, flav);
+ clnt = rpc_clone_client_set_auth(clnt, RPC_AUTH_UNIX);
if (IS_ERR(clnt)) {
status = PTR_ERR(clnt);
break;
}
- clp->cl_rpcclient = clnt;
+ /* Note: this is safe because we haven't yet marked the
+ * client as ready, so we are the only user of
+ * clp->cl_rpcclient
+ */
+ clnt = xchg(&clp->cl_rpcclient, clnt);
+ rpc_shutdown_client(clnt);
+ clnt = clp->cl_rpcclient;
goto again;
case -NFS4ERR_MINOR_VERS_MISMATCH:
@@ -1897,13 +1914,15 @@ again:
case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
* in nfs4_exchange_id */
status = -EKEYEXPIRED;
+ break;
+ default:
+ pr_warn("NFS: %s unhandled error %d. Exiting with error EIO\n",
+ __func__, status);
+ status = -EIO;
}
out_unlock:
mutex_unlock(&nfs_clid_init_mutex);
-out_free:
- kfree(flavors);
-out:
dprintk("NFS: %s: status = %d\n", __func__, status);
return status;
}
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 569b166cc050..a5e1a3026d48 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -252,6 +252,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+ if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
+ data->auth_flavors[0] = RPC_AUTH_UNIX;
export_path = data->nfs_server.export_path;
data->nfs_server.export_path = "/";
root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index e3edda554ac7..3c79c5878c6d 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -530,14 +530,10 @@ static int nfs4_stat_to_errno(int);
decode_setclientid_maxsz)
#define NFS4_enc_setclientid_confirm_sz \
(compound_encode_hdr_maxsz + \
- encode_setclientid_confirm_maxsz + \
- encode_putrootfh_maxsz + \
- encode_fsinfo_maxsz)
+ encode_setclientid_confirm_maxsz)
#define NFS4_dec_setclientid_confirm_sz \
(compound_decode_hdr_maxsz + \
- decode_setclientid_confirm_maxsz + \
- decode_putrootfh_maxsz + \
- decode_fsinfo_maxsz)
+ decode_setclientid_confirm_maxsz)
#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
encode_sequence_maxsz + \
encode_putfh_maxsz + \
@@ -1058,8 +1054,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
if (iap->ia_valid & ATTR_ATIME_SET) {
bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
- *p++ = cpu_to_be32(0);
- *p++ = cpu_to_be32(iap->ia_atime.tv_sec);
+ p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
}
else if (iap->ia_valid & ATTR_ATIME) {
@@ -1069,8 +1064,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
if (iap->ia_valid & ATTR_MTIME_SET) {
bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
- *p++ = cpu_to_be32(0);
- *p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
+ p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
}
else if (iap->ia_valid & ATTR_MTIME) {
@@ -1366,33 +1360,28 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
+ struct iattr dummy;
__be32 *p;
- struct nfs_client *clp;
p = reserve_space(xdr, 4);
- switch(arg->open_flags & O_EXCL) {
- case 0:
+ switch(arg->createmode) {
+ case NFS4_CREATE_UNCHECKED:
*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
encode_attrs(xdr, arg->u.attrs, arg->server);
break;
- default:
- clp = arg->server->nfs_client;
- if (clp->cl_mvops->minor_version > 0) {
- if (nfs4_has_persistent_session(clp)) {
- *p = cpu_to_be32(NFS4_CREATE_GUARDED);
- encode_attrs(xdr, arg->u.attrs, arg->server);
- } else {
- struct iattr dummy;
-
- *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
- encode_nfs4_verifier(xdr, &arg->u.verifier);
- dummy.ia_valid = 0;
- encode_attrs(xdr, &dummy, arg->server);
- }
- } else {
- *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
- encode_nfs4_verifier(xdr, &arg->u.verifier);
- }
+ case NFS4_CREATE_GUARDED:
+ *p = cpu_to_be32(NFS4_CREATE_GUARDED);
+ encode_attrs(xdr, arg->u.attrs, arg->server);
+ break;
+ case NFS4_CREATE_EXCLUSIVE:
+ *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
+ encode_nfs4_verifier(xdr, &arg->u.verifier);
+ break;
+ case NFS4_CREATE_EXCLUSIVE4_1:
+ *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
+ encode_nfs4_verifier(xdr, &arg->u.verifier);
+ dummy.ia_valid = 0;
+ encode_attrs(xdr, &dummy, arg->server);
}
}
@@ -1459,6 +1448,23 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc
encode_string(xdr, name->len, name->name);
}
+static inline void encode_claim_fh(struct xdr_stream *xdr)
+{
+ __be32 *p;
+
+ p = reserve_space(xdr, 4);
+ *p = cpu_to_be32(NFS4_OPEN_CLAIM_FH);
+}
+
+static inline void encode_claim_delegate_cur_fh(struct xdr_stream *xdr, const nfs4_stateid *stateid)
+{
+ __be32 *p;
+
+ p = reserve_space(xdr, 4);
+ *p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEG_CUR_FH);
+ encode_nfs4_stateid(xdr, stateid);
+}
+
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
{
encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);
@@ -1474,6 +1480,12 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg,
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
break;
+ case NFS4_OPEN_CLAIM_FH:
+ encode_claim_fh(xdr);
+ break;
+ case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
+ encode_claim_delegate_cur_fh(xdr, &arg->u.delegation);
+ break;
default:
BUG();
}
@@ -1506,35 +1518,12 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
}
-static void encode_open_stateid(struct xdr_stream *xdr,
- const struct nfs_open_context *ctx,
- const struct nfs_lock_context *l_ctx,
- fmode_t fmode,
- int zero_seqid)
-{
- nfs4_stateid stateid;
-
- if (ctx->state != NULL) {
- const struct nfs_lockowner *lockowner = NULL;
-
- if (l_ctx != NULL)
- lockowner = &l_ctx->lockowner;
- nfs4_select_rw_stateid(&stateid, ctx->state,
- fmode, lockowner);
- if (zero_seqid)
- stateid.seqid = 0;
- encode_nfs4_stateid(xdr, &stateid);
- } else
- encode_nfs4_stateid(xdr, &zero_stateid);
-}
-
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
{
__be32 *p;
encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
- encode_open_stateid(xdr, args->context, args->lock_context,
- FMODE_READ, hdr->minorversion);
+ encode_nfs4_stateid(xdr, &args->stateid);
p = reserve_space(xdr, 12);
p = xdr_encode_hyper(p, args->offset);
@@ -1670,8 +1659,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
__be32 *p;
encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
- encode_open_stateid(xdr, args->context, args->lock_context,
- FMODE_WRITE, hdr->minorversion);
+ encode_nfs4_stateid(xdr, &args->stateid);
p = reserve_space(xdr, 16);
p = xdr_encode_hyper(p, args->offset);
@@ -2609,12 +2597,9 @@ static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
struct compound_hdr hdr = {
.nops = 0,
};
- const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
encode_compound_hdr(xdr, req, &hdr);
encode_setclientid_confirm(xdr, arg, &hdr);
- encode_putrootfh(xdr, &hdr);
- encode_fsinfo(xdr, lease_bitmap, &hdr);
encode_nops(&hdr);
}
@@ -3497,8 +3482,11 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
if (n == 0)
goto root_path;
dprintk("pathname4: ");
- path->ncomponents = 0;
- while (path->ncomponents < n) {
+ if (n > NFS4_PATHNAME_MAXCOMPONENTS) {
+ dprintk("cannot parse %d components in path\n", n);
+ goto out_eio;
+ }
+ for (path->ncomponents = 0; path->ncomponents < n; path->ncomponents++) {
struct nfs4_string *component = &path->components[path->ncomponents];
status = decode_opaque_inline(xdr, &component->len, &component->data);
if (unlikely(status != 0))
@@ -3507,12 +3495,6 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
pr_cont("%s%.*s ",
(path->ncomponents != n ? "/ " : ""),
component->len, component->data);
- if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
- path->ncomponents++;
- else {
- dprintk("cannot parse %d components in path\n", n);
- goto out_eio;
- }
}
out:
return status;
@@ -3557,27 +3539,23 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
n = be32_to_cpup(p);
if (n <= 0)
goto out_eio;
- res->nlocations = 0;
- while (res->nlocations < n) {
+ for (res->nlocations = 0; res->nlocations < n; res->nlocations++) {
u32 m;
- struct nfs4_fs_location *loc = &res->locations[res->nlocations];
+ struct nfs4_fs_location *loc;
+ if (res->nlocations == NFS4_FS_LOCATIONS_MAXENTRIES)
+ break;
+ loc = &res->locations[res->nlocations];
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
m = be32_to_cpup(p);
- loc->nservers = 0;
dprintk("%s: servers:\n", __func__);
- while (loc->nservers < m) {
- struct nfs4_string *server = &loc->servers[loc->nservers];
- status = decode_opaque_inline(xdr, &server->len, &server->data);
- if (unlikely(status != 0))
- goto out_eio;
- dprintk("%s ", server->data);
- if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
- loc->nservers++;
- else {
+ for (loc->nservers = 0; loc->nservers < m; loc->nservers++) {
+ struct nfs4_string *server;
+
+ if (loc->nservers == NFS4_FS_LOCATION_MAXSERVERS) {
unsigned int i;
dprintk("%s: using first %u of %u servers "
"returned for location %u\n",
@@ -3591,13 +3569,17 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
if (unlikely(status != 0))
goto out_eio;
}
+ break;
}
+ server = &loc->servers[loc->nservers];
+ status = decode_opaque_inline(xdr, &server->len, &server->data);
+ if (unlikely(status != 0))
+ goto out_eio;
+ dprintk("%s ", server->data);
}
status = decode_pathname(xdr, &loc->rootpath);
if (unlikely(status != 0))
goto out_eio;
- if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
- res->nlocations++;
}
if (res->nlocations != 0)
status = NFS_ATTR_FATTR_V4_LOCATIONS;
@@ -5209,27 +5191,30 @@ static int decode_delegreturn(struct xdr_stream *xdr)
return decode_op_hdr(xdr, OP_DELEGRETURN);
}
-static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
+static int decode_secinfo_gss(struct xdr_stream *xdr,
+ struct nfs4_secinfo4 *flavor)
{
+ u32 oid_len;
__be32 *p;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
- flavor->gss.sec_oid4.len = be32_to_cpup(p);
- if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
+ oid_len = be32_to_cpup(p);
+ if (oid_len > GSS_OID_MAX_LEN)
goto out_err;
- p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
+ p = xdr_inline_decode(xdr, oid_len);
if (unlikely(!p))
goto out_overflow;
- memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);
+ memcpy(flavor->flavor_info.oid.data, p, oid_len);
+ flavor->flavor_info.oid.len = oid_len;
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
- flavor->gss.qop4 = be32_to_cpup(p++);
- flavor->gss.service = be32_to_cpup(p);
+ flavor->flavor_info.qop = be32_to_cpup(p++);
+ flavor->flavor_info.service = be32_to_cpup(p);
return 0;
@@ -5242,10 +5227,10 @@ out_err:
static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
- struct nfs4_secinfo_flavor *sec_flavor;
+ struct nfs4_secinfo4 *sec_flavor;
+ unsigned int i, num_flavors;
int status;
__be32 *p;
- int i, num_flavors;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
@@ -6648,8 +6633,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
* Decode SETCLIENTID_CONFIRM response
*/
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
- struct xdr_stream *xdr,
- struct nfs_fsinfo *fsinfo)
+ struct xdr_stream *xdr)
{
struct compound_hdr hdr;
int status;
@@ -6657,10 +6641,6 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
status = decode_compound_hdr(xdr, &hdr);
if (!status)
status = decode_setclientid_confirm(xdr);
- if (!status)
- status = decode_putrootfh(xdr);
- if (!status)
- status = decode_fsinfo(xdr, fsinfo);
return status;
}
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index 88f9611a945c..5457745dd4f1 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -234,7 +234,7 @@ static int __alloc_objio_seg(unsigned numdevs, gfp_t gfp_flags,
lseg = kzalloc(lseg_size, gfp_flags);
if (unlikely(!lseg)) {
- dprintk("%s: Faild allocation numdevs=%d size=%zd\n", __func__,
+ dprintk("%s: Failed allocation numdevs=%d size=%zd\n", __func__,
numdevs, lseg_size);
return -ENOMEM;
}
diff --git a/fs/nfs/objlayout/objlayout.h b/fs/nfs/objlayout/objlayout.h
index 880ba086be94..87aa1dec6120 100644
--- a/fs/nfs/objlayout/objlayout.h
+++ b/fs/nfs/objlayout/objlayout.h
@@ -114,7 +114,7 @@ extern int objio_alloc_lseg(struct pnfs_layout_segment **outp,
gfp_t gfp_flags);
extern void objio_free_lseg(struct pnfs_layout_segment *lseg);
-/* objio_free_result will free these @oir structs recieved from
+/* objio_free_result will free these @oir structs received from
* objlayout_{read,write}_done
*/
extern void objio_free_result(struct objlayout_io_res *oir);
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index e56e846e9d2d..29cfb7ade121 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -84,6 +84,55 @@ nfs_page_free(struct nfs_page *p)
kmem_cache_free(nfs_page_cachep, p);
}
+static void
+nfs_iocounter_inc(struct nfs_io_counter *c)
+{
+ atomic_inc(&c->io_count);
+}
+
+static void
+nfs_iocounter_dec(struct nfs_io_counter *c)
+{
+ if (atomic_dec_and_test(&c->io_count)) {
+ clear_bit(NFS_IO_INPROGRESS, &c->flags);
+ smp_mb__after_clear_bit();
+ wake_up_bit(&c->flags, NFS_IO_INPROGRESS);
+ }
+}
+
+static int
+__nfs_iocounter_wait(struct nfs_io_counter *c)
+{
+ wait_queue_head_t *wq = bit_waitqueue(&c->flags, NFS_IO_INPROGRESS);
+ DEFINE_WAIT_BIT(q, &c->flags, NFS_IO_INPROGRESS);
+ int ret = 0;
+
+ do {
+ prepare_to_wait(wq, &q.wait, TASK_KILLABLE);
+ set_bit(NFS_IO_INPROGRESS, &c->flags);
+ if (atomic_read(&c->io_count) == 0)
+ break;
+ ret = nfs_wait_bit_killable(&c->flags);
+ } while (atomic_read(&c->io_count) != 0);
+ finish_wait(wq, &q.wait);
+ return ret;
+}
+
+/**
+ * nfs_iocounter_wait - wait for i/o to complete
+ * @c: nfs_io_counter to use
+ *
+ * returns -ERESTARTSYS if interrupted by a fatal signal.
+ * Otherwise returns 0 once the io_count hits 0.
+ */
+int
+nfs_iocounter_wait(struct nfs_io_counter *c)
+{
+ if (atomic_read(&c->io_count) == 0)
+ return 0;
+ return __nfs_iocounter_wait(c);
+}
+
/**
* nfs_create_request - Create an NFS read/write request.
* @ctx: open context to use
@@ -104,6 +153,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
struct nfs_page *req;
struct nfs_lock_context *l_ctx;
+ if (test_bit(NFS_CONTEXT_BAD, &ctx->flags))
+ return ERR_PTR(-EBADF);
/* try to allocate the request struct */
req = nfs_page_alloc();
if (req == NULL)
@@ -116,6 +167,7 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
return ERR_CAST(l_ctx);
}
req->wb_lock_context = l_ctx;
+ nfs_iocounter_inc(&l_ctx->io_count);
/* Initialize the request struct. Initially, we assume a
* long write-back delay. This will be adjusted in
@@ -175,6 +227,7 @@ static void nfs_clear_request(struct nfs_page *req)
req->wb_page = NULL;
}
if (l_ctx != NULL) {
+ nfs_iocounter_dec(&l_ctx->io_count);
nfs_put_lock_context(l_ctx);
req->wb_lock_context = NULL;
}
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0ba025..c5bd758e5637 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -718,6 +718,8 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo,
spin_lock(&lo->plh_inode->i_lock);
if (pnfs_layoutgets_blocked(lo, 1)) {
status = -EAGAIN;
+ } else if (!nfs4_valid_open_stateid(open_state)) {
+ status = -EBADF;
} else if (list_empty(&lo->plh_segs)) {
int seq;
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index a5e5d9899d56..70a26c651f09 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -514,6 +514,8 @@ void nfs_read_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_read_data *data = calldata;
NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
+ if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+ rpc_exit(task, -EIO);
}
static const struct rpc_call_ops nfs_read_common_ops = {
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2f8a29db0f1b..1bb071dca9ab 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -920,7 +920,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
data->mount_server.port = NFS_UNSPEC_PORT;
data->nfs_server.port = NFS_UNSPEC_PORT;
data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- data->auth_flavors[0] = RPC_AUTH_UNIX;
+ data->auth_flavors[0] = RPC_AUTH_MAXFLAVOR;
data->auth_flavor_len = 1;
data->minorversion = 0;
data->need_mount = true;
@@ -1608,49 +1608,57 @@ out_security_failure:
}
/*
- * Match the requested auth flavors with the list returned by
- * the server. Returns zero and sets the mount's authentication
- * flavor on success; returns -EACCES if server does not support
- * the requested flavor.
+ * Select a security flavor for this mount. The selected flavor
+ * is planted in args->auth_flavors[0].
*/
-static int nfs_walk_authlist(struct nfs_parsed_mount_data *args,
- struct nfs_mount_request *request)
+static void nfs_select_flavor(struct nfs_parsed_mount_data *args,
+ struct nfs_mount_request *request)
{
- unsigned int i, j, server_authlist_len = *(request->auth_flav_len);
+ unsigned int i, count = *(request->auth_flav_len);
+ rpc_authflavor_t flavor;
+
+ if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR)
+ goto out;
+
+ /*
+ * The NFSv2 MNT operation does not return a flavor list.
+ */
+ if (args->mount_server.version != NFS_MNT3_VERSION)
+ goto out_default;
/*
* Certain releases of Linux's mountd return an empty
- * flavor list. To prevent behavioral regression with
- * these servers (ie. rejecting mounts that used to
- * succeed), revert to pre-2.6.32 behavior (no checking)
- * if the returned flavor list is empty.
+ * flavor list in some cases.
*/
- if (server_authlist_len == 0)
- return 0;
+ if (count == 0)
+ goto out_default;
/*
- * We avoid sophisticated negotiating here, as there are
- * plenty of cases where we can get it wrong, providing
- * either too little or too much security.
- *
* RFC 2623, section 2.7 suggests we SHOULD prefer the
* flavor listed first. However, some servers list
- * AUTH_NULL first. Our caller plants AUTH_SYS, the
- * preferred default, in args->auth_flavors[0] if user
- * didn't specify sec= mount option.
+ * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
*/
- for (i = 0; i < args->auth_flavor_len; i++)
- for (j = 0; j < server_authlist_len; j++)
- if (args->auth_flavors[i] == request->auth_flavs[j]) {
- dfprintk(MOUNT, "NFS: using auth flavor %d\n",
- request->auth_flavs[j]);
- args->auth_flavors[0] = request->auth_flavs[j];
- return 0;
- }
+ for (i = 0; i < count; i++) {
+ struct rpcsec_gss_info info;
+
+ flavor = request->auth_flavs[i];
+ switch (flavor) {
+ case RPC_AUTH_UNIX:
+ goto out_set;
+ case RPC_AUTH_NULL:
+ continue;
+ default:
+ if (rpcauth_get_gssinfo(flavor, &info) == 0)
+ goto out_set;
+ }
+ }
- dfprintk(MOUNT, "NFS: server does not support requested auth flavor\n");
- nfs_umount(request);
- return -EACCES;
+out_default:
+ flavor = RPC_AUTH_UNIX;
+out_set:
+ args->auth_flavors[0] = flavor;
+out:
+ dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]);
}
/*
@@ -1713,12 +1721,8 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
return status;
}
- /*
- * MNTv1 (NFSv2) does not support auth flavor negotiation.
- */
- if (args->mount_server.version != NFS_MNT3_VERSION)
- return 0;
- return nfs_walk_authlist(args, &request);
+ nfs_select_flavor(args, &request);
+ return 0;
}
struct dentry *nfs_try_mount(int flags, const char *dev_name,
@@ -2381,10 +2385,9 @@ int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot,
struct nfs_mount_info *mount_info)
{
/* clone any lsm security options from the parent to the new sb */
- security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
if (mntroot->d_inode->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops)
return -ESTALE;
- return 0;
+ return security_sb_clone_mnt_opts(mount_info->cloned->sb, s);
}
EXPORT_SYMBOL_GPL(nfs_clone_sb_security);
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index c483cc50b82e..a2c7c28049d5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1251,6 +1251,8 @@ void nfs_write_prepare(struct rpc_task *task, void *calldata)
{
struct nfs_write_data *data = calldata;
NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);
+ if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+ rpc_exit(task, -EIO);
}
void nfs_commit_prepare(struct rpc_task *task, void *calldata)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2e27430b9070..417c84877742 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -234,7 +234,6 @@ static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct
kmem_cache *slab)
{
struct idr *stateids = &cl->cl_stateids;
- static int min_stateid = 0;
struct nfs4_stid *stid;
int new_id;
@@ -242,7 +241,7 @@ kmem_cache *slab)
if (!stid)
return NULL;
- new_id = idr_alloc(stateids, stid, min_stateid, 0, GFP_KERNEL);
+ new_id = idr_alloc_cyclic(stateids, stid, 0, 0, GFP_KERNEL);
if (new_id < 0)
goto out_free;
stid->sc_client = cl;
@@ -261,10 +260,6 @@ kmem_cache *slab)
* amount of time until an id is reused, by ensuring they always
* "increase" (mod INT_MAX):
*/
-
- min_stateid = new_id+1;
- if (min_stateid == INT_MAX)
- min_stateid = 0;
return stid;
out_free:
kfree(stid);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 01168865dd37..2502951714b1 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -264,7 +264,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
iattr->ia_valid |= ATTR_SIZE;
}
if (bmval[0] & FATTR4_WORD0_ACL) {
- int nace;
+ u32 nace;
struct nfs4_ace *ace;
READ_BUF(4); len += 4;
@@ -3138,10 +3138,9 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
static __be32
nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
- __be32 nfserr,struct svc_export *exp)
+ __be32 nfserr, struct svc_export *exp)
{
- int i = 0;
- u32 nflavs;
+ u32 i, nflavs;
struct exp_flavor_info *flavs;
struct exp_flavor_info def_flavs[2];
__be32 *p;
@@ -3172,30 +3171,29 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
WRITE32(nflavs);
ADJUST_ARGS();
for (i = 0; i < nflavs; i++) {
- u32 flav = flavs[i].pseudoflavor;
- struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
+ struct rpcsec_gss_info info;
- if (gm) {
+ if (rpcauth_get_gssinfo(flavs[i].pseudoflavor, &info) == 0) {
RESERVE_SPACE(4);
WRITE32(RPC_AUTH_GSS);
ADJUST_ARGS();
- RESERVE_SPACE(4 + gm->gm_oid.len);
- WRITE32(gm->gm_oid.len);
- WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
+ RESERVE_SPACE(4 + info.oid.len);
+ WRITE32(info.oid.len);
+ WRITEMEM(info.oid.data, info.oid.len);
ADJUST_ARGS();
RESERVE_SPACE(4);
- WRITE32(0); /* qop */
+ WRITE32(info.qop);
ADJUST_ARGS();
RESERVE_SPACE(4);
- WRITE32(gss_pseudoflavor_to_service(gm, flav));
+ WRITE32(info.service);
ADJUST_ARGS();
- gss_mech_put(gm);
} else {
RESERVE_SPACE(4);
- WRITE32(flav);
+ WRITE32(flavs[i].pseudoflavor);
ADJUST_ARGS();
}
}
+
out:
if (exp)
exp_put(exp);
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 6b49f14eac8c..cf02f5530713 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -175,6 +175,11 @@ static int nilfs_writepages(struct address_space *mapping,
struct inode *inode = mapping->host;
int err = 0;
+ if (inode->i_sb->s_flags & MS_RDONLY) {
+ nilfs_clear_dirty_pages(mapping, false);
+ return -EROFS;
+ }
+
if (wbc->sync_mode == WB_SYNC_ALL)
err = nilfs_construct_dsync_segment(inode->i_sb, inode,
wbc->range_start,
@@ -187,6 +192,18 @@ static int nilfs_writepage(struct page *page, struct writeback_control *wbc)
struct inode *inode = page->mapping->host;
int err;
+ if (inode->i_sb->s_flags & MS_RDONLY) {
+ /*
+ * It means that filesystem was remounted in read-only
+ * mode because of error or metadata corruption. But we
+ * have dirty pages that try to be flushed in background.
+ * So, here we simply discard this dirty page.
+ */
+ nilfs_clear_dirty_page(page, false);
+ unlock_page(page);
+ return -EROFS;
+ }
+
redirty_page_for_writepage(wbc, page);
unlock_page(page);
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c
index f9897d09c693..c4dcd1db57ee 100644
--- a/fs/nilfs2/mdt.c
+++ b/fs/nilfs2/mdt.c
@@ -375,14 +375,25 @@ int nilfs_mdt_fetch_dirty(struct inode *inode)
static int
nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc)
{
- struct inode *inode;
+ struct inode *inode = page->mapping->host;
struct super_block *sb;
int err = 0;
+ if (inode && (inode->i_sb->s_flags & MS_RDONLY)) {
+ /*
+ * It means that filesystem was remounted in read-only
+ * mode because of error or metadata corruption. But we
+ * have dirty pages that try to be flushed in background.
+ * So, here we simply discard this dirty page.
+ */
+ nilfs_clear_dirty_page(page, false);
+ unlock_page(page);
+ return -EROFS;
+ }
+
redirty_page_for_writepage(wbc, page);
unlock_page(page);
- inode = page->mapping->host;
if (!inode)
return 0;
@@ -561,10 +572,10 @@ void nilfs_mdt_restore_from_shadow_map(struct inode *inode)
if (mi->mi_palloc_cache)
nilfs_palloc_clear_cache(inode);
- nilfs_clear_dirty_pages(inode->i_mapping);
+ nilfs_clear_dirty_pages(inode->i_mapping, true);
nilfs_copy_back_pages(inode->i_mapping, &shadow->frozen_data);
- nilfs_clear_dirty_pages(&ii->i_btnode_cache);
+ nilfs_clear_dirty_pages(&ii->i_btnode_cache, true);
nilfs_copy_back_pages(&ii->i_btnode_cache, &shadow->frozen_btnodes);
nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store);
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
index 07f76db04ec7..0ba679866e50 100644
--- a/fs/nilfs2/page.c
+++ b/fs/nilfs2/page.c
@@ -370,7 +370,12 @@ repeat:
goto repeat;
}
-void nilfs_clear_dirty_pages(struct address_space *mapping)
+/**
+ * nilfs_clear_dirty_pages - discard dirty pages in address space
+ * @mapping: address space with dirty pages for discarding
+ * @silent: suppress [true] or print [false] warning messages
+ */
+void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent)
{
struct pagevec pvec;
unsigned int i;
@@ -382,25 +387,9 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
PAGEVEC_SIZE)) {
for (i = 0; i < pagevec_count(&pvec); i++) {
struct page *page = pvec.pages[i];
- struct buffer_head *bh, *head;
lock_page(page);
- ClearPageUptodate(page);
- ClearPageMappedToDisk(page);
- bh = head = page_buffers(page);
- do {
- lock_buffer(bh);
- clear_buffer_dirty(bh);
- clear_buffer_nilfs_volatile(bh);
- clear_buffer_nilfs_checked(bh);
- clear_buffer_nilfs_redirected(bh);
- clear_buffer_uptodate(bh);
- clear_buffer_mapped(bh);
- unlock_buffer(bh);
- bh = bh->b_this_page;
- } while (bh != head);
-
- __nilfs_clear_page_dirty(page);
+ nilfs_clear_dirty_page(page, silent);
unlock_page(page);
}
pagevec_release(&pvec);
@@ -408,6 +397,51 @@ void nilfs_clear_dirty_pages(struct address_space *mapping)
}
}
+/**
+ * nilfs_clear_dirty_page - discard dirty page
+ * @page: dirty page that will be discarded
+ * @silent: suppress [true] or print [false] warning messages
+ */
+void nilfs_clear_dirty_page(struct page *page, bool silent)
+{
+ struct inode *inode = page->mapping->host;
+ struct super_block *sb = inode->i_sb;
+
+ BUG_ON(!PageLocked(page));
+
+ if (!silent) {
+ nilfs_warning(sb, __func__,
+ "discard page: offset %lld, ino %lu",
+ page_offset(page), inode->i_ino);
+ }
+
+ ClearPageUptodate(page);
+ ClearPageMappedToDisk(page);
+
+ if (page_has_buffers(page)) {
+ struct buffer_head *bh, *head;
+
+ bh = head = page_buffers(page);
+ do {
+ lock_buffer(bh);
+ if (!silent) {
+ nilfs_warning(sb, __func__,
+ "discard block %llu, size %zu",
+ (u64)bh->b_blocknr, bh->b_size);
+ }
+ clear_buffer_dirty(bh);
+ clear_buffer_nilfs_volatile(bh);
+ clear_buffer_nilfs_checked(bh);
+ clear_buffer_nilfs_redirected(bh);
+ clear_buffer_uptodate(bh);
+ clear_buffer_mapped(bh);
+ unlock_buffer(bh);
+ } while (bh = bh->b_this_page, bh != head);
+ }
+
+ __nilfs_clear_page_dirty(page);
+}
+
unsigned nilfs_page_count_clean_buffers(struct page *page,
unsigned from, unsigned to)
{
diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h
index fb7de71605a0..ef30c5c2426f 100644
--- a/fs/nilfs2/page.h
+++ b/fs/nilfs2/page.h
@@ -55,7 +55,8 @@ void nilfs_page_bug(struct page *);
int nilfs_copy_dirty_pages(struct address_space *, struct address_space *);
void nilfs_copy_back_pages(struct address_space *, struct address_space *);
-void nilfs_clear_dirty_pages(struct address_space *);
+void nilfs_clear_dirty_page(struct page *, bool);
+void nilfs_clear_dirty_pages(struct address_space *, bool);
void nilfs_mapping_init(struct address_space *mapping, struct inode *inode,
struct backing_dev_info *bdi);
unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned);
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 5d8444268a16..d0be29fa94cf 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -755,9 +755,9 @@ out_destroy_group:
return fd;
}
-SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
- __u64 mask, int dfd,
- const char __user * pathname)
+SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
+ __u64, mask, int, dfd,
+ const char __user *, pathname)
{
struct inode *inode = NULL;
struct vfsmount *mnt = NULL;
@@ -857,17 +857,6 @@ fput_and_out:
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_fanotify_mark(long fanotify_fd, long flags, __u64 mask,
- long dfd, long pathname)
-{
- return SYSC_fanotify_mark((int) fanotify_fd, (unsigned int) flags,
- mask, (int) dfd,
- (const char __user *) pathname);
-}
-SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark);
-#endif
-
/*
* fanotify_user_setup - Our initialization function. Note that we cannot return
* error because we have compiled-in VFS hooks. So an (unlikely) failure here
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 1db6d886cbf2..959815c1e017 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -356,7 +356,6 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
}
static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
- int *last_wd,
struct inotify_inode_mark *i_mark)
{
int ret;
@@ -364,11 +363,10 @@ static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
idr_preload(GFP_KERNEL);
spin_lock(idr_lock);
- ret = idr_alloc(idr, i_mark, *last_wd + 1, 0, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(idr, i_mark, 1, 0, GFP_NOWAIT);
if (ret >= 0) {
/* we added the mark to the idr, take a reference */
i_mark->wd = ret;
- *last_wd = i_mark->wd;
fsnotify_get_mark(&i_mark->fsn_mark);
}
@@ -569,7 +567,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
int add = (arg & IN_MASK_ADD);
int ret;
- /* don't allow invalid bits: we don't want flags set */
mask = inotify_arg_to_mask(arg);
fsn_mark = fsnotify_find_inode_mark(group, inode);
@@ -620,7 +617,6 @@ static int inotify_new_watch(struct fsnotify_group *group,
struct idr *idr = &group->inotify_data.idr;
spinlock_t *idr_lock = &group->inotify_data.idr_lock;
- /* don't allow invalid bits: we don't want flags set */
mask = inotify_arg_to_mask(arg);
tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
@@ -635,8 +631,7 @@ static int inotify_new_watch(struct fsnotify_group *group,
if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
goto out_err;
- ret = inotify_add_to_idr(idr, idr_lock, &group->inotify_data.last_wd,
- tmp_i_mark);
+ ret = inotify_add_to_idr(idr, idr_lock, tmp_i_mark);
if (ret)
goto out_err;
@@ -694,7 +689,6 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
spin_lock_init(&group->inotify_data.idr_lock);
idr_init(&group->inotify_data.idr);
- group->inotify_data.last_wd = 0;
group->inotify_data.user = get_current_user();
if (atomic_inc_return(&group->inotify_data.user->inotify_devs) >
@@ -748,6 +742,10 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
int ret;
unsigned flags = 0;
+ /* don't allow invalid bits: we don't want flags set */
+ if (unlikely(!(mask & ALL_INOTIFY_BITS)))
+ return -EINVAL;
+
f = fdget(fd);
if (unlikely(!f.file))
return -EBADF;
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index eeac97bb3bfa..b3fdd1a323d6 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1498,10 +1498,8 @@ leave:
dlm_put(dlm);
if (ret < 0) {
- if (buf)
- kfree(buf);
- if (item)
- kfree(item);
+ kfree(buf);
+ kfree(item);
mlog_errno(ret);
}
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 752f0b26221d..0c60ef2d8056 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -101,13 +101,6 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
if (!S_ISDIR(inode->i_mode))
flags &= ~OCFS2_DIRSYNC_FL;
- handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
- if (IS_ERR(handle)) {
- status = PTR_ERR(handle);
- mlog_errno(status);
- goto bail_unlock;
- }
-
oldflags = ocfs2_inode->ip_attr;
flags = flags & mask;
flags |= oldflags & ~mask;
@@ -120,7 +113,14 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
if ((oldflags & OCFS2_IMMUTABLE_FL) || ((flags ^ oldflags) &
(OCFS2_APPEND_FL | OCFS2_IMMUTABLE_FL))) {
if (!capable(CAP_LINUX_IMMUTABLE))
- goto bail_commit;
+ goto bail_unlock;
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ mlog_errno(status);
+ goto bail_unlock;
}
ocfs2_inode->ip_attr = flags;
@@ -130,8 +130,8 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
if (status < 0)
mlog_errno(status);
-bail_commit:
ocfs2_commit_trans(osb, handle);
+
bail_unlock:
ocfs2_inode_unlock(inode, 1);
bail:
@@ -706,8 +706,10 @@ int ocfs2_info_handle_freefrag(struct inode *inode,
o2info_set_request_filled(&oiff->iff_req);
- if (o2info_to_user(*oiff, req))
+ if (o2info_to_user(*oiff, req)) {
+ status = -EFAULT;
goto bail;
+ }
status = 0;
bail:
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 9f8dcadd9a50..f1fc172175b6 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -471,7 +471,7 @@ static int ocfs2_validate_and_adjust_move_goal(struct inode *inode,
int ret, goal_bit = 0;
struct buffer_head *gd_bh = NULL;
- struct ocfs2_group_desc *bg = NULL;
+ struct ocfs2_group_desc *bg;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
int c_to_b = 1 << (osb->s_clustersize_bits -
inode->i_sb->s_blocksize_bits);
@@ -482,13 +482,6 @@ static int ocfs2_validate_and_adjust_move_goal(struct inode *inode,
range->me_goal = ocfs2_block_to_cluster_start(inode->i_sb,
range->me_goal);
/*
- * moving goal is not allowd to start with a group desc blok(#0 blk)
- * let's compromise to the latter cluster.
- */
- if (range->me_goal == le64_to_cpu(bg->bg_blkno))
- range->me_goal += c_to_b;
-
- /*
* validate goal sits within global_bitmap, and return the victim
* group desc
*/
@@ -502,6 +495,13 @@ static int ocfs2_validate_and_adjust_move_goal(struct inode *inode,
bg = (struct ocfs2_group_desc *)gd_bh->b_data;
/*
+ * moving goal is not allowd to start with a group desc blok(#0 blk)
+ * let's compromise to the latter cluster.
+ */
+ if (range->me_goal == le64_to_cpu(bg->bg_blkno))
+ range->me_goal += c_to_b;
+
+ /*
* movement is not gonna cross two groups.
*/
if ((le16_to_cpu(bg->bg_bits) - goal_bit) * osb->s_clustersize <
@@ -1057,42 +1057,40 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp)
struct inode *inode = file_inode(filp);
struct ocfs2_move_extents range;
- struct ocfs2_move_extents_context *context = NULL;
+ struct ocfs2_move_extents_context *context;
+
+ if (!argp)
+ return -EINVAL;
status = mnt_want_write_file(filp);
if (status)
return status;
if ((!S_ISREG(inode->i_mode)) || !(filp->f_mode & FMODE_WRITE))
- goto out;
+ goto out_drop;
if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
status = -EPERM;
- goto out;
+ goto out_drop;
}
context = kzalloc(sizeof(struct ocfs2_move_extents_context), GFP_NOFS);
if (!context) {
status = -ENOMEM;
mlog_errno(status);
- goto out;
+ goto out_drop;
}
context->inode = inode;
context->file = filp;
- if (argp) {
- if (copy_from_user(&range, argp, sizeof(range))) {
- status = -EFAULT;
- goto out;
- }
- } else {
- status = -EINVAL;
- goto out;
+ if (copy_from_user(&range, argp, sizeof(range))) {
+ status = -EFAULT;
+ goto out_free;
}
if (range.me_start > i_size_read(inode))
- goto out;
+ goto out_free;
if (range.me_start + range.me_len > i_size_read(inode))
range.me_len = i_size_read(inode) - range.me_start;
@@ -1124,25 +1122,24 @@ int ocfs2_ioctl_move_extents(struct file *filp, void __user *argp)
status = ocfs2_validate_and_adjust_move_goal(inode, &range);
if (status)
- goto out;
+ goto out_copy;
}
status = ocfs2_move_extents(context);
if (status)
mlog_errno(status);
-out:
+out_copy:
/*
* movement/defragmentation may end up being partially completed,
* that's the reason why we need to return userspace the finished
* length and new_offset even if failure happens somewhere.
*/
- if (argp) {
- if (copy_to_user(argp, &range, sizeof(range)))
- status = -EFAULT;
- }
+ if (copy_to_user(argp, &range, sizeof(range)))
+ status = -EFAULT;
+out_free:
kfree(context);
-
+out_drop:
mnt_drop_write_file(filp);
return status;
diff --git a/fs/open.c b/fs/open.c
index 68354466879f..8c741002f947 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -197,10 +197,7 @@ out:
SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length)
{
- long ret = do_sys_ftruncate(fd, length, 1);
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(2, ret, fd, length);
- return ret;
+ return do_sys_ftruncate(fd, length, 1);
}
#ifdef CONFIG_COMPAT
@@ -212,32 +209,15 @@ COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_ulong_t, length)
/* LFS versions of truncate are only needed on 32 bit machines */
#if BITS_PER_LONG == 32
-SYSCALL_DEFINE(truncate64)(const char __user * path, loff_t length)
+SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length)
{
return do_sys_truncate(path, length);
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_truncate64(long path, loff_t length)
-{
- return SYSC_truncate64((const char __user *) path, length);
-}
-SYSCALL_ALIAS(sys_truncate64, SyS_truncate64);
-#endif
-SYSCALL_DEFINE(ftruncate64)(unsigned int fd, loff_t length)
+SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length)
{
- long ret = do_sys_ftruncate(fd, length, 0);
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(2, ret, fd, length);
- return ret;
-}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_ftruncate64(long fd, loff_t length)
-{
- return SYSC_ftruncate64((unsigned int) fd, length);
+ return do_sys_ftruncate(fd, length, 0);
}
-SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64);
-#endif
#endif /* BITS_PER_LONG == 32 */
@@ -299,7 +279,7 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
return ret;
}
-SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
+SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len)
{
struct fd f = fdget(fd);
int error = -EBADF;
@@ -311,14 +291,6 @@ SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len)
return error;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len)
-{
- return SYSC_fallocate((int)fd, (int)mode, offset, len);
-}
-SYSCALL_ALIAS(sys_fallocate, SyS_fallocate);
-#endif
-
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
@@ -983,29 +955,19 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
- long ret;
-
if (force_o_largefile())
flags |= O_LARGEFILE;
- ret = do_sys_open(AT_FDCWD, filename, flags, mode);
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, filename, flags, mode);
- return ret;
+ return do_sys_open(AT_FDCWD, filename, flags, mode);
}
SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
umode_t, mode)
{
- long ret;
-
if (force_o_largefile())
flags |= O_LARGEFILE;
- ret = do_sys_open(dfd, filename, flags, mode);
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(4, ret, dfd, filename, flags, mode);
- return ret;
+ return do_sys_open(dfd, filename, flags, mode);
}
#ifndef __alpha__
diff --git a/fs/pnode.c b/fs/pnode.c
index 43617258fa6a..3d2a7141b87a 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -9,6 +9,7 @@
#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/fs.h>
+#include <linux/nsproxy.h>
#include "internal.h"
#include "pnode.h"
@@ -220,6 +221,7 @@ static struct mount *get_source(struct mount *dest,
int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
struct mount *source_mnt, struct list_head *tree_list)
{
+ struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
struct mount *m, *child;
int ret = 0;
struct mount *prev_dest_mnt = dest_mnt;
@@ -236,6 +238,10 @@ int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
source = get_source(m, prev_dest_mnt, prev_src_mnt, &type);
+ /* Notice when we are propagating across user namespaces */
+ if (m->mnt_ns->user_ns != user_ns)
+ type |= CL_UNPRIVILEGED;
+
child = copy_tree(source, source->mnt.mnt_root, type);
if (IS_ERR(child)) {
ret = PTR_ERR(child);
diff --git a/fs/pnode.h b/fs/pnode.h
index 9eb00ee65bbe..b091445c1c4a 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -23,6 +23,7 @@
#define CL_MAKE_SHARED 0x08
#define CL_PRIVATE 0x10
#define CL_SHARED_TO_SLAVE 0x20
+#define CL_UNPRIVILEGED 0x40
static inline void set_mnt_shared(struct mount *mnt)
{
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 712f24db9600..ab30716584f5 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -5,7 +5,7 @@
obj-y += proc.o
proc-y := nommu.o task_nommu.o
-proc-$(CONFIG_MMU) := mmu.o task_mmu.o
+proc-$(CONFIG_MMU) := task_mmu.o
proc-y += inode.o root.o base.o generic.o array.o \
fd.o
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f7ed9ee46eb9..cbd0f1b324b9 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -143,6 +143,7 @@ static const char * const task_state_array[] = {
"x (dead)", /* 64 */
"K (wakekill)", /* 128 */
"W (waking)", /* 256 */
+ "P (parked)", /* 512 */
};
static inline const char *get_task_state(struct task_struct *tsk)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 8281986693be..dd51e50001fe 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -86,6 +86,7 @@
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/flex_array.h>
+#include <linux/posix-timers.h>
#ifdef CONFIG_HARDWALL
#include <asm/hardwall.h>
#endif
@@ -1378,11 +1379,10 @@ static ssize_t comm_write(struct file *file, const char __user *buf,
struct inode *inode = file_inode(file);
struct task_struct *p;
char buffer[TASK_COMM_LEN];
+ const size_t maxlen = sizeof(buffer) - 1;
memset(buffer, 0, sizeof(buffer));
- if (count > sizeof(buffer) - 1)
- count = sizeof(buffer) - 1;
- if (copy_from_user(buffer, buf, count))
+ if (copy_from_user(buffer, buf, count > maxlen ? maxlen : count))
return -EFAULT;
p = get_proc_task(inode);
@@ -2053,6 +2053,102 @@ static const struct file_operations proc_map_files_operations = {
.llseek = default_llseek,
};
+struct timers_private {
+ struct pid *pid;
+ struct task_struct *task;
+ struct sighand_struct *sighand;
+ struct pid_namespace *ns;
+ unsigned long flags;
+};
+
+static void *timers_start(struct seq_file *m, loff_t *pos)
+{
+ struct timers_private *tp = m->private;
+
+ tp->task = get_pid_task(tp->pid, PIDTYPE_PID);
+ if (!tp->task)
+ return ERR_PTR(-ESRCH);
+
+ tp->sighand = lock_task_sighand(tp->task, &tp->flags);
+ if (!tp->sighand)
+ return ERR_PTR(-ESRCH);
+
+ return seq_list_start(&tp->task->signal->posix_timers, *pos);
+}
+
+static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct timers_private *tp = m->private;
+ return seq_list_next(v, &tp->task->signal->posix_timers, pos);
+}
+
+static void timers_stop(struct seq_file *m, void *v)
+{
+ struct timers_private *tp = m->private;
+
+ if (tp->sighand) {
+ unlock_task_sighand(tp->task, &tp->flags);
+ tp->sighand = NULL;
+ }
+
+ if (tp->task) {
+ put_task_struct(tp->task);
+ tp->task = NULL;
+ }
+}
+
+static int show_timer(struct seq_file *m, void *v)
+{
+ struct k_itimer *timer;
+ struct timers_private *tp = m->private;
+ int notify;
+ static char *nstr[] = {
+ [SIGEV_SIGNAL] = "signal",
+ [SIGEV_NONE] = "none",
+ [SIGEV_THREAD] = "thread",
+ };
+
+ timer = list_entry((struct list_head *)v, struct k_itimer, list);
+ notify = timer->it_sigev_notify;
+
+ seq_printf(m, "ID: %d\n", timer->it_id);
+ seq_printf(m, "signal: %d/%p\n", timer->sigq->info.si_signo,
+ timer->sigq->info.si_value.sival_ptr);
+ seq_printf(m, "notify: %s/%s.%d\n",
+ nstr[notify & ~SIGEV_THREAD_ID],
+ (notify & SIGEV_THREAD_ID) ? "tid" : "pid",
+ pid_nr_ns(timer->it_pid, tp->ns));
+
+ return 0;
+}
+
+static const struct seq_operations proc_timers_seq_ops = {
+ .start = timers_start,
+ .next = timers_next,
+ .stop = timers_stop,
+ .show = show_timer,
+};
+
+static int proc_timers_open(struct inode *inode, struct file *file)
+{
+ struct timers_private *tp;
+
+ tp = __seq_open_private(file, &proc_timers_seq_ops,
+ sizeof(struct timers_private));
+ if (!tp)
+ return -ENOMEM;
+
+ tp->pid = proc_pid(inode);
+ tp->ns = inode->i_sb->s_fs_info;
+ return 0;
+}
+
+static const struct file_operations proc_timers_operations = {
+ .open = proc_timers_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
#endif /* CONFIG_CHECKPOINT_RESTORE */
static struct dentry *proc_pident_instantiate(struct inode *dir,
@@ -2623,6 +2719,9 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
#endif
+#ifdef CONFIG_CHECKPOINT_RESTORE
+ REG("timers", S_IRUGO, proc_timers_operations),
+#endif
};
static int proc_tgid_base_readdir(struct file * filp,
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 04255b6e96b7..d600fb098b6a 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -211,27 +211,6 @@ extern int proc_fill_super(struct super_block *);
extern void proc_entry_rundown(struct proc_dir_entry *);
/*
- * mmu.c
- */
-struct vmalloc_info {
- unsigned long used;
- unsigned long largest_chunk;
-};
-
-#ifdef CONFIG_MMU
-#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
-extern void get_vmalloc_info(struct vmalloc_info *);
-
-#else
-#define VMALLOC_TOTAL 0UL
-static inline void get_vmalloc_info(struct vmalloc_info *vmi)
-{
- vmi->used = 0;
- vmi->largest_chunk = 0;
-}
-#endif
-
-/*
* proc_devtree.c
*/
#ifdef CONFIG_PROC_DEVICETREE
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 13cf87c4686f..0a22194e5d58 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -16,6 +16,7 @@
#include <linux/capability.h>
#include <linux/elf.h>
#include <linux/elfcore.h>
+#include <linux/notifier.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/printk.h>
@@ -566,7 +567,6 @@ static const struct file_operations proc_kcore_operations = {
.llseek = default_llseek,
};
-#ifdef CONFIG_MEMORY_HOTPLUG
/* just remember that we have to update kcore */
static int __meminit kcore_callback(struct notifier_block *self,
unsigned long action, void *arg)
@@ -580,8 +580,11 @@ static int __meminit kcore_callback(struct notifier_block *self,
}
return NOTIFY_OK;
}
-#endif
+static struct notifier_block kcore_callback_nb __meminitdata = {
+ .notifier_call = kcore_callback,
+ .priority = 0,
+};
static struct kcore_list kcore_vmalloc;
@@ -633,7 +636,7 @@ static int __init proc_kcore_init(void)
add_modules_range();
/* Store direct-map area from physical memory map */
kcore_update_ram();
- hotplug_memory_notifier(kcore_callback, 0);
+ register_hotmemory_notifier(&kcore_callback_nb);
return 0;
}
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 1efaaa19c4f3..5aa847a603c0 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -11,6 +11,7 @@
#include <linux/swap.h>
#include <linux/vmstat.h>
#include <linux/atomic.h>
+#include <linux/vmalloc.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include "internal.h"
diff --git a/fs/proc/mmu.c b/fs/proc/mmu.c
deleted file mode 100644
index 8ae221dfd010..000000000000
--- a/fs/proc/mmu.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* mmu.c: mmu memory info files
- *
- * Copyright (C) 2004 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 License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/spinlock.h>
-#include <linux/vmalloc.h>
-#include <linux/highmem.h>
-#include <asm/pgtable.h>
-#include "internal.h"
-
-void get_vmalloc_info(struct vmalloc_info *vmi)
-{
- struct vm_struct *vma;
- unsigned long free_area_size;
- unsigned long prev_end;
-
- vmi->used = 0;
-
- if (!vmlist) {
- vmi->largest_chunk = VMALLOC_TOTAL;
- }
- else {
- vmi->largest_chunk = 0;
-
- prev_end = VMALLOC_START;
-
- read_lock(&vmlist_lock);
-
- for (vma = vmlist; vma; vma = vma->next) {
- unsigned long addr = (unsigned long) vma->addr;
-
- /*
- * Some archs keep another range for modules in vmlist
- */
- if (addr < VMALLOC_START)
- continue;
- if (addr >= VMALLOC_END)
- break;
-
- vmi->used += vma->size;
-
- free_area_size = addr - prev_end;
- if (vmi->largest_chunk < free_area_size)
- vmi->largest_chunk = free_area_size;
-
- prev_end = vma->size + addr;
- }
-
- if (VMALLOC_END - prev_end > vmi->largest_chunk)
- vmi->largest_chunk = VMALLOC_END - prev_end;
-
- read_unlock(&vmlist_lock);
- }
-}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 20834b3c8ea3..41a6ea93f486 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/user_namespace.h>
#include <linux/mount.h>
#include <linux/pid_namespace.h>
#include <linux/parser.h>
@@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
} else {
ns = task_active_pid_ns(current);
options = data;
+
+ if (!current_user_ns()->may_mount_proc)
+ return ERR_PTR(-EPERM);
}
sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
diff --git a/fs/read_write.c b/fs/read_write.c
index a1f4d44cbc03..605dbbcb1973 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -128,7 +128,7 @@ EXPORT_SYMBOL(generic_file_llseek_size);
*
* This is a generic implemenation of ->llseek useable for all normal local
* filesystems. It just updates the file offset to the value specified by
- * @offset and @whence under i_mutex.
+ * @offset and @whence.
*/
loff_t generic_file_llseek(struct file *file, loff_t offset, int whence)
{
@@ -424,6 +424,9 @@ ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t
const char __user *p;
ssize_t ret;
+ if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
+ return -EINVAL;
+
old_fs = get_fs();
set_fs(get_ds());
p = (__force const char __user *)buf;
@@ -514,8 +517,8 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
return ret;
}
-SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf,
- size_t count, loff_t pos)
+SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf,
+ size_t, count, loff_t, pos)
{
struct fd f;
ssize_t ret = -EBADF;
@@ -533,17 +536,9 @@ SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf,
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_pread64(long fd, long buf, long count, loff_t pos)
-{
- return SYSC_pread64((unsigned int) fd, (char __user *) buf,
- (size_t) count, pos);
-}
-SYSCALL_ALIAS(sys_pread64, SyS_pread64);
-#endif
-SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf,
- size_t count, loff_t pos)
+SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf,
+ size_t, count, loff_t, pos)
{
struct fd f;
ssize_t ret = -EBADF;
@@ -561,14 +556,6 @@ SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf,
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_pwrite64(long fd, long buf, long count, loff_t pos)
-{
- return SYSC_pwrite64((unsigned int) fd, (const char __user *) buf,
- (size_t) count, pos);
-}
-SYSCALL_ALIAS(sys_pwrite64, SyS_pwrite64);
-#endif
/*
* Reduce an iovec's length in-place. Return the resulting number of segments
@@ -1095,8 +1082,8 @@ COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd,
}
#endif
-ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
- loff_t max)
+static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
+ size_t count, loff_t max)
{
struct fd in, out;
struct inode *in_inode, *out_inode;
@@ -1220,3 +1207,43 @@ SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, si
return do_sendfile(out_fd, in_fd, NULL, count, 0);
}
+
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd,
+ compat_off_t __user *, offset, compat_size_t, count)
+{
+ loff_t pos;
+ off_t off;
+ ssize_t ret;
+
+ if (offset) {
+ if (unlikely(get_user(off, offset)))
+ return -EFAULT;
+ pos = off;
+ ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS);
+ if (unlikely(put_user(pos, offset)))
+ return -EFAULT;
+ return ret;
+ }
+
+ return do_sendfile(out_fd, in_fd, NULL, count, 0);
+}
+
+COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
+ compat_loff_t __user *, offset, compat_size_t, count)
+{
+ loff_t pos;
+ ssize_t ret;
+
+ if (offset) {
+ if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
+ return -EFAULT;
+ ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
+ if (unlikely(put_user(pos, offset)))
+ return -EFAULT;
+ return ret;
+ }
+
+ return do_sendfile(out_fd, in_fd, NULL, count, 0);
+}
+#endif
diff --git a/fs/read_write.h b/fs/read_write.h
index b98780664ffa..0ec530d9305b 100644
--- a/fs/read_write.h
+++ b/fs/read_write.h
@@ -7,6 +7,3 @@
typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
unsigned long, loff_t);
-
-ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count,
- loff_t max);
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index c196369fe408..4cce1d9552fb 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -187,8 +187,8 @@ fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
return -ENOSPC;
- if (name[0] == '.' && (name[1] == '\0' ||
- (name[1] == '.' && name[2] == '\0')))
+ if (name[0] == '.' && (namelen < 2 ||
+ (namelen == 2 && name[1] == '.')))
return 0;
dentry = lookup_one_len(name, dbuf->xadir, namelen);
diff --git a/fs/signalfd.c b/fs/signalfd.c
index b53486961735..424b7b65321f 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -30,6 +30,7 @@
#include <linux/signalfd.h>
#include <linux/syscalls.h>
#include <linux/proc_fs.h>
+#include <linux/compat.h>
void signalfd_cleanup(struct sighand_struct *sighand)
{
@@ -311,3 +312,33 @@ SYSCALL_DEFINE3(signalfd, int, ufd, sigset_t __user *, user_mask,
{
return sys_signalfd4(ufd, user_mask, sizemask, 0);
}
+
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(signalfd4, int, ufd,
+ const compat_sigset_t __user *,sigmask,
+ compat_size_t, sigsetsize,
+ int, flags)
+{
+ compat_sigset_t ss32;
+ sigset_t tmp;
+ sigset_t __user *ksigmask;
+
+ if (sigsetsize != sizeof(compat_sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
+ return -EFAULT;
+ sigset_from_compat(&tmp, &ss32);
+ ksigmask = compat_alloc_user_space(sizeof(sigset_t));
+ if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+ return -EFAULT;
+
+ return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
+}
+
+COMPAT_SYSCALL_DEFINE3(signalfd, int, ufd,
+ const compat_sigset_t __user *,sigmask,
+ compat_size_t, sigsetsize)
+{
+ return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0);
+}
+#endif
diff --git a/fs/splice.c b/fs/splice.c
index 45e645b15d92..e6b25598c8c4 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -31,6 +31,7 @@
#include <linux/security.h>
#include <linux/gfp.h>
#include <linux/socket.h>
+#include <linux/compat.h>
#include "internal.h"
/*
@@ -1690,6 +1691,27 @@ SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov,
return error;
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32,
+ unsigned int, nr_segs, unsigned int, flags)
+{
+ unsigned i;
+ struct iovec __user *iov;
+ if (nr_segs > UIO_MAXIOV)
+ return -EINVAL;
+ iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
+ for (i = 0; i < nr_segs; i++) {
+ struct compat_iovec v;
+ if (get_user(v.iov_base, &iov32[i].iov_base) ||
+ get_user(v.iov_len, &iov32[i].iov_len) ||
+ put_user(compat_ptr(v.iov_base), &iov[i].iov_base) ||
+ put_user(v.iov_len, &iov[i].iov_len))
+ return -EFAULT;
+ }
+ return sys_vmsplice(fd, iov, nr_segs, flags);
+}
+#endif
+
SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
int, fd_out, loff_t __user *, off_out,
size_t, len, unsigned int, flags)
diff --git a/fs/sync.c b/fs/sync.c
index 2c5d6639a66a..905f3f6b3d85 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -283,8 +283,8 @@ EXPORT_SYMBOL(generic_write_sync);
* already-instantiated disk blocks, there are no guarantees here that the data
* will be available after a crash.
*/
-SYSCALL_DEFINE(sync_file_range)(int fd, loff_t offset, loff_t nbytes,
- unsigned int flags)
+SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes,
+ unsigned int, flags)
{
int ret;
struct fd f;
@@ -365,29 +365,11 @@ out_put:
out:
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_sync_file_range(long fd, loff_t offset, loff_t nbytes,
- long flags)
-{
- return SYSC_sync_file_range((int) fd, offset, nbytes,
- (unsigned int) flags);
-}
-SYSCALL_ALIAS(sys_sync_file_range, SyS_sync_file_range);
-#endif
/* It would be nice if people remember that not all the world's an i386
when they introduce new system calls */
-SYSCALL_DEFINE(sync_file_range2)(int fd, unsigned int flags,
- loff_t offset, loff_t nbytes)
+SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags,
+ loff_t, offset, loff_t, nbytes)
{
return sys_sync_file_range(fd, offset, nbytes, flags);
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_sync_file_range2(long fd, long flags,
- loff_t offset, loff_t nbytes)
-{
- return SYSC_sync_file_range2((int) fd, (unsigned int) flags,
- offset, nbytes);
-}
-SYSCALL_ALIAS(sys_sync_file_range2, SyS_sync_file_range2);
-#endif
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 2fbdff6be25c..e8e0e71b29d5 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -165,21 +165,8 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
if (unlikely(!sd))
return NULL;
- while (1) {
- int v, t;
-
- v = atomic_read(&sd->s_active);
- if (unlikely(v < 0))
- return NULL;
-
- t = atomic_cmpxchg(&sd->s_active, v, v + 1);
- if (likely(t == v))
- break;
- if (t < 0)
- return NULL;
-
- cpu_relax();
- }
+ if (!atomic_inc_unless_negative(&sd->s_active))
+ return NULL;
if (likely(!ignore_lockdep(sd)))
rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
@@ -281,6 +268,10 @@ void release_sysfs_dirent(struct sysfs_dirent * sd)
*/
parent_sd = sd->s_parent;
+ WARN(!(sd->s_flags & SYSFS_FLAG_REMOVED),
+ "sysfs: free using entry: %s/%s\n",
+ parent_sd ? parent_sd->s_name : "", sd->s_name);
+
if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
sysfs_put(sd->s_symlink.target_sd);
if (sysfs_type(sd) & SYSFS_COPY_NAME)
@@ -399,7 +390,7 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
sd->s_name = name;
sd->s_mode = mode;
- sd->s_flags = type;
+ sd->s_flags = type | SYSFS_FLAG_REMOVED;
return sd;
@@ -479,6 +470,9 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
}
+ /* Mark the entry added into directory tree */
+ sd->s_flags &= ~SYSFS_FLAG_REMOVED;
+
return 0;
}
@@ -1012,6 +1006,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
enum kobj_ns_type type;
const void *ns;
ino_t ino;
+ loff_t off;
type = sysfs_ns_type(parent_sd);
ns = sysfs_info(dentry->d_sb)->ns[type];
@@ -1020,6 +1015,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
ino = parent_sd->s_ino;
if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
filp->f_pos++;
+ else
+ return 0;
}
if (filp->f_pos == 1) {
if (parent_sd->s_parent)
@@ -1028,8 +1025,11 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
ino = parent_sd->s_ino;
if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
filp->f_pos++;
+ else
+ return 0;
}
mutex_lock(&sysfs_mutex);
+ off = filp->f_pos;
for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
pos;
pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) {
@@ -1041,27 +1041,43 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
len = strlen(name);
ino = pos->s_ino;
type = dt_type(pos);
- filp->f_pos = pos->s_hash;
+ off = filp->f_pos = pos->s_hash;
filp->private_data = sysfs_get(pos);
mutex_unlock(&sysfs_mutex);
- ret = filldir(dirent, name, len, filp->f_pos, ino, type);
+ ret = filldir(dirent, name, len, off, ino, type);
mutex_lock(&sysfs_mutex);
if (ret < 0)
break;
}
mutex_unlock(&sysfs_mutex);
- if ((filp->f_pos > 1) && !pos) { /* EOF */
- filp->f_pos = INT_MAX;
+
+ /* don't reference last entry if its refcount is dropped */
+ if (!pos) {
filp->private_data = NULL;
+
+ /* EOF and not changed as 0 or 1 in read/write path */
+ if (off == filp->f_pos && off > 1)
+ filp->f_pos = INT_MAX;
}
return 0;
}
+static loff_t sysfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+ struct inode *inode = file_inode(file);
+ loff_t ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = generic_file_llseek(file, offset, whence);
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
const struct file_operations sysfs_dir_operations = {
.read = generic_read_dir,
.readdir = sysfs_readdir,
.release = sysfs_dir_release,
- .llseek = generic_file_llseek,
+ .llseek = sysfs_dir_llseek,
};
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 8d924b5ec733..afd83273e6ce 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/magic.h>
#include <linux/slab.h>
+#include <linux/user_namespace.h>
#include "sysfs.h"
@@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
struct super_block *sb;
int error;
+ if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
+ return ERR_PTR(-EPERM);
+
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return ERR_PTR(-ENOMEM);
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index ac838b844936..f21acf0ef01f 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1568,6 +1568,12 @@ static int ubifs_remount_rw(struct ubifs_info *c)
c->remounting_rw = 1;
c->ro_mount = 0;
+ if (c->space_fixup) {
+ err = ubifs_fixup_free_space(c);
+ if (err)
+ return err;
+ }
+
err = check_free_space(c);
if (err)
goto out;
@@ -1684,12 +1690,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
err = dbg_check_space_info(c);
}
- if (c->space_fixup) {
- err = ubifs_fixup_free_space(c);
- if (err)
- goto out;
- }
-
mutex_unlock(&c->umount_mutex);
return err;
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 95425b59ce0a..b6c2f94e041e 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -26,8 +26,7 @@ struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
count = size >> uspi->s_fshift;
if (count > UFS_MAXFRAG)
return NULL;
- ubh = (struct ufs_buffer_head *)
- kmalloc (sizeof (struct ufs_buffer_head), GFP_NOFS);
+ ubh = kmalloc (sizeof (struct ufs_buffer_head), GFP_NOFS);
if (!ubh)
return NULL;
ubh->fragment = fragment;
diff --git a/include/Kbuild b/include/Kbuild
index 1dfd33e8d43b..bab1145bc7a7 100644
--- a/include/Kbuild
+++ b/include/Kbuild
@@ -1,5 +1,2 @@
# Top-level Makefile calls into asm-$(ARCH)
# List only non-arch directories below
-
-header-y += video/
-header-y += scsi/
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 9bf59d0e8aaa..cf051e05a8fe 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -44,17 +44,50 @@
#ifndef __ACEXCEP_H__
#define __ACEXCEP_H__
+/* This module contains all possible exception codes for acpi_status */
+
/*
- * Exceptions returned by external ACPI interfaces
+ * Exception code classes
*/
-#define AE_CODE_ENVIRONMENTAL 0x0000
-#define AE_CODE_PROGRAMMER 0x1000
-#define AE_CODE_ACPI_TABLES 0x2000
-#define AE_CODE_AML 0x3000
-#define AE_CODE_CONTROL 0x4000
+#define AE_CODE_ENVIRONMENTAL 0x0000 /* General ACPICA environment */
+#define AE_CODE_PROGRAMMER 0x1000 /* External ACPICA interface caller */
+#define AE_CODE_ACPI_TABLES 0x2000 /* ACPI tables */
+#define AE_CODE_AML 0x3000 /* From executing AML code */
+#define AE_CODE_CONTROL 0x4000 /* Internal control codes */
+
#define AE_CODE_MAX 0x4000
#define AE_CODE_MASK 0xF000
+/*
+ * Macros to insert the exception code classes
+ */
+#define EXCEP_ENV(code) ((acpi_status) (code | AE_CODE_ENVIRONMENTAL))
+#define EXCEP_PGM(code) ((acpi_status) (code | AE_CODE_PROGRAMMER))
+#define EXCEP_TBL(code) ((acpi_status) (code | AE_CODE_ACPI_TABLES))
+#define EXCEP_AML(code) ((acpi_status) (code | AE_CODE_AML))
+#define EXCEP_CTL(code) ((acpi_status) (code | AE_CODE_CONTROL))
+
+/*
+ * Exception info table. The "Description" field is used only by the
+ * ACPICA help application (acpihelp).
+ */
+struct acpi_exception_info {
+ char *name;
+
+#ifdef ACPI_HELP_APP
+ char *description;
+#endif
+};
+
+#ifdef ACPI_HELP_APP
+#define EXCEP_TXT(name,description) {name, description}
+#else
+#define EXCEP_TXT(name,description) {name}
+#endif
+
+/*
+ * Success is always zero, failure is non-zero
+ */
#define ACPI_SUCCESS(a) (!(a))
#define ACPI_FAILURE(a) (a)
@@ -64,60 +97,60 @@
/*
* Environmental exceptions
*/
-#define AE_ERROR (acpi_status) (0x0001 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_ACPI_TABLES (acpi_status) (0x0002 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_NAMESPACE (acpi_status) (0x0003 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_MEMORY (acpi_status) (0x0004 | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_FOUND (acpi_status) (0x0005 | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_EXIST (acpi_status) (0x0006 | AE_CODE_ENVIRONMENTAL)
-#define AE_ALREADY_EXISTS (acpi_status) (0x0007 | AE_CODE_ENVIRONMENTAL)
-#define AE_TYPE (acpi_status) (0x0008 | AE_CODE_ENVIRONMENTAL)
-#define AE_NULL_OBJECT (acpi_status) (0x0009 | AE_CODE_ENVIRONMENTAL)
-#define AE_NULL_ENTRY (acpi_status) (0x000A | AE_CODE_ENVIRONMENTAL)
-#define AE_BUFFER_OVERFLOW (acpi_status) (0x000B | AE_CODE_ENVIRONMENTAL)
-#define AE_STACK_OVERFLOW (acpi_status) (0x000C | AE_CODE_ENVIRONMENTAL)
-#define AE_STACK_UNDERFLOW (acpi_status) (0x000D | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_IMPLEMENTED (acpi_status) (0x000E | AE_CODE_ENVIRONMENTAL)
-#define AE_SUPPORT (acpi_status) (0x000F | AE_CODE_ENVIRONMENTAL)
-#define AE_LIMIT (acpi_status) (0x0010 | AE_CODE_ENVIRONMENTAL)
-#define AE_TIME (acpi_status) (0x0011 | AE_CODE_ENVIRONMENTAL)
-#define AE_ACQUIRE_DEADLOCK (acpi_status) (0x0012 | AE_CODE_ENVIRONMENTAL)
-#define AE_RELEASE_DEADLOCK (acpi_status) (0x0013 | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_ACQUIRED (acpi_status) (0x0014 | AE_CODE_ENVIRONMENTAL)
-#define AE_ALREADY_ACQUIRED (acpi_status) (0x0015 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_HARDWARE_RESPONSE (acpi_status) (0x0016 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_GLOBAL_LOCK (acpi_status) (0x0017 | AE_CODE_ENVIRONMENTAL)
-#define AE_ABORT_METHOD (acpi_status) (0x0018 | AE_CODE_ENVIRONMENTAL)
-#define AE_SAME_HANDLER (acpi_status) (0x0019 | AE_CODE_ENVIRONMENTAL)
-#define AE_NO_HANDLER (acpi_status) (0x001A | AE_CODE_ENVIRONMENTAL)
-#define AE_OWNER_ID_LIMIT (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL)
-#define AE_NOT_CONFIGURED (acpi_status) (0x001C | AE_CODE_ENVIRONMENTAL)
+#define AE_ERROR EXCEP_ENV (0x0001)
+#define AE_NO_ACPI_TABLES EXCEP_ENV (0x0002)
+#define AE_NO_NAMESPACE EXCEP_ENV (0x0003)
+#define AE_NO_MEMORY EXCEP_ENV (0x0004)
+#define AE_NOT_FOUND EXCEP_ENV (0x0005)
+#define AE_NOT_EXIST EXCEP_ENV (0x0006)
+#define AE_ALREADY_EXISTS EXCEP_ENV (0x0007)
+#define AE_TYPE EXCEP_ENV (0x0008)
+#define AE_NULL_OBJECT EXCEP_ENV (0x0009)
+#define AE_NULL_ENTRY EXCEP_ENV (0x000A)
+#define AE_BUFFER_OVERFLOW EXCEP_ENV (0x000B)
+#define AE_STACK_OVERFLOW EXCEP_ENV (0x000C)
+#define AE_STACK_UNDERFLOW EXCEP_ENV (0x000D)
+#define AE_NOT_IMPLEMENTED EXCEP_ENV (0x000E)
+#define AE_SUPPORT EXCEP_ENV (0x000F)
+#define AE_LIMIT EXCEP_ENV (0x0010)
+#define AE_TIME EXCEP_ENV (0x0011)
+#define AE_ACQUIRE_DEADLOCK EXCEP_ENV (0x0012)
+#define AE_RELEASE_DEADLOCK EXCEP_ENV (0x0013)
+#define AE_NOT_ACQUIRED EXCEP_ENV (0x0014)
+#define AE_ALREADY_ACQUIRED EXCEP_ENV (0x0015)
+#define AE_NO_HARDWARE_RESPONSE EXCEP_ENV (0x0016)
+#define AE_NO_GLOBAL_LOCK EXCEP_ENV (0x0017)
+#define AE_ABORT_METHOD EXCEP_ENV (0x0018)
+#define AE_SAME_HANDLER EXCEP_ENV (0x0019)
+#define AE_NO_HANDLER EXCEP_ENV (0x001A)
+#define AE_OWNER_ID_LIMIT EXCEP_ENV (0x001B)
+#define AE_NOT_CONFIGURED EXCEP_ENV (0x001C)
#define AE_CODE_ENV_MAX 0x001C
/*
* Programmer exceptions
*/
-#define AE_BAD_PARAMETER (acpi_status) (0x0001 | AE_CODE_PROGRAMMER)
-#define AE_BAD_CHARACTER (acpi_status) (0x0002 | AE_CODE_PROGRAMMER)
-#define AE_BAD_PATHNAME (acpi_status) (0x0003 | AE_CODE_PROGRAMMER)
-#define AE_BAD_DATA (acpi_status) (0x0004 | AE_CODE_PROGRAMMER)
-#define AE_BAD_HEX_CONSTANT (acpi_status) (0x0005 | AE_CODE_PROGRAMMER)
-#define AE_BAD_OCTAL_CONSTANT (acpi_status) (0x0006 | AE_CODE_PROGRAMMER)
-#define AE_BAD_DECIMAL_CONSTANT (acpi_status) (0x0007 | AE_CODE_PROGRAMMER)
-#define AE_MISSING_ARGUMENTS (acpi_status) (0x0008 | AE_CODE_PROGRAMMER)
-#define AE_BAD_ADDRESS (acpi_status) (0x0009 | AE_CODE_PROGRAMMER)
+#define AE_BAD_PARAMETER EXCEP_PGM (0x0001)
+#define AE_BAD_CHARACTER EXCEP_PGM (0x0002)
+#define AE_BAD_PATHNAME EXCEP_PGM (0x0003)
+#define AE_BAD_DATA EXCEP_PGM (0x0004)
+#define AE_BAD_HEX_CONSTANT EXCEP_PGM (0x0005)
+#define AE_BAD_OCTAL_CONSTANT EXCEP_PGM (0x0006)
+#define AE_BAD_DECIMAL_CONSTANT EXCEP_PGM (0x0007)
+#define AE_MISSING_ARGUMENTS EXCEP_PGM (0x0008)
+#define AE_BAD_ADDRESS EXCEP_PGM (0x0009)
#define AE_CODE_PGM_MAX 0x0009
/*
* Acpi table exceptions
*/
-#define AE_BAD_SIGNATURE (acpi_status) (0x0001 | AE_CODE_ACPI_TABLES)
-#define AE_BAD_HEADER (acpi_status) (0x0002 | AE_CODE_ACPI_TABLES)
-#define AE_BAD_CHECKSUM (acpi_status) (0x0003 | AE_CODE_ACPI_TABLES)
-#define AE_BAD_VALUE (acpi_status) (0x0004 | AE_CODE_ACPI_TABLES)
-#define AE_INVALID_TABLE_LENGTH (acpi_status) (0x0005 | AE_CODE_ACPI_TABLES)
+#define AE_BAD_SIGNATURE EXCEP_TBL (0x0001)
+#define AE_BAD_HEADER EXCEP_TBL (0x0002)
+#define AE_BAD_CHECKSUM EXCEP_TBL (0x0003)
+#define AE_BAD_VALUE EXCEP_TBL (0x0004)
+#define AE_INVALID_TABLE_LENGTH EXCEP_TBL (0x0005)
#define AE_CODE_TBL_MAX 0x0005
@@ -125,58 +158,58 @@
* AML exceptions. These are caused by problems with
* the actual AML byte stream
*/
-#define AE_AML_BAD_OPCODE (acpi_status) (0x0001 | AE_CODE_AML)
-#define AE_AML_NO_OPERAND (acpi_status) (0x0002 | AE_CODE_AML)
-#define AE_AML_OPERAND_TYPE (acpi_status) (0x0003 | AE_CODE_AML)
-#define AE_AML_OPERAND_VALUE (acpi_status) (0x0004 | AE_CODE_AML)
-#define AE_AML_UNINITIALIZED_LOCAL (acpi_status) (0x0005 | AE_CODE_AML)
-#define AE_AML_UNINITIALIZED_ARG (acpi_status) (0x0006 | AE_CODE_AML)
-#define AE_AML_UNINITIALIZED_ELEMENT (acpi_status) (0x0007 | AE_CODE_AML)
-#define AE_AML_NUMERIC_OVERFLOW (acpi_status) (0x0008 | AE_CODE_AML)
-#define AE_AML_REGION_LIMIT (acpi_status) (0x0009 | AE_CODE_AML)
-#define AE_AML_BUFFER_LIMIT (acpi_status) (0x000A | AE_CODE_AML)
-#define AE_AML_PACKAGE_LIMIT (acpi_status) (0x000B | AE_CODE_AML)
-#define AE_AML_DIVIDE_BY_ZERO (acpi_status) (0x000C | AE_CODE_AML)
-#define AE_AML_BAD_NAME (acpi_status) (0x000D | AE_CODE_AML)
-#define AE_AML_NAME_NOT_FOUND (acpi_status) (0x000E | AE_CODE_AML)
-#define AE_AML_INTERNAL (acpi_status) (0x000F | AE_CODE_AML)
-#define AE_AML_INVALID_SPACE_ID (acpi_status) (0x0010 | AE_CODE_AML)
-#define AE_AML_STRING_LIMIT (acpi_status) (0x0011 | AE_CODE_AML)
-#define AE_AML_NO_RETURN_VALUE (acpi_status) (0x0012 | AE_CODE_AML)
-#define AE_AML_METHOD_LIMIT (acpi_status) (0x0013 | AE_CODE_AML)
-#define AE_AML_NOT_OWNER (acpi_status) (0x0014 | AE_CODE_AML)
-#define AE_AML_MUTEX_ORDER (acpi_status) (0x0015 | AE_CODE_AML)
-#define AE_AML_MUTEX_NOT_ACQUIRED (acpi_status) (0x0016 | AE_CODE_AML)
-#define AE_AML_INVALID_RESOURCE_TYPE (acpi_status) (0x0017 | AE_CODE_AML)
-#define AE_AML_INVALID_INDEX (acpi_status) (0x0018 | AE_CODE_AML)
-#define AE_AML_REGISTER_LIMIT (acpi_status) (0x0019 | AE_CODE_AML)
-#define AE_AML_NO_WHILE (acpi_status) (0x001A | AE_CODE_AML)
-#define AE_AML_ALIGNMENT (acpi_status) (0x001B | AE_CODE_AML)
-#define AE_AML_NO_RESOURCE_END_TAG (acpi_status) (0x001C | AE_CODE_AML)
-#define AE_AML_BAD_RESOURCE_VALUE (acpi_status) (0x001D | AE_CODE_AML)
-#define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x001E | AE_CODE_AML)
-#define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x001F | AE_CODE_AML)
-#define AE_AML_ILLEGAL_ADDRESS (acpi_status) (0x0020 | AE_CODE_AML)
-#define AE_AML_INFINITE_LOOP (acpi_status) (0x0021 | AE_CODE_AML)
+#define AE_AML_BAD_OPCODE EXCEP_AML (0x0001)
+#define AE_AML_NO_OPERAND EXCEP_AML (0x0002)
+#define AE_AML_OPERAND_TYPE EXCEP_AML (0x0003)
+#define AE_AML_OPERAND_VALUE EXCEP_AML (0x0004)
+#define AE_AML_UNINITIALIZED_LOCAL EXCEP_AML (0x0005)
+#define AE_AML_UNINITIALIZED_ARG EXCEP_AML (0x0006)
+#define AE_AML_UNINITIALIZED_ELEMENT EXCEP_AML (0x0007)
+#define AE_AML_NUMERIC_OVERFLOW EXCEP_AML (0x0008)
+#define AE_AML_REGION_LIMIT EXCEP_AML (0x0009)
+#define AE_AML_BUFFER_LIMIT EXCEP_AML (0x000A)
+#define AE_AML_PACKAGE_LIMIT EXCEP_AML (0x000B)
+#define AE_AML_DIVIDE_BY_ZERO EXCEP_AML (0x000C)
+#define AE_AML_BAD_NAME EXCEP_AML (0x000D)
+#define AE_AML_NAME_NOT_FOUND EXCEP_AML (0x000E)
+#define AE_AML_INTERNAL EXCEP_AML (0x000F)
+#define AE_AML_INVALID_SPACE_ID EXCEP_AML (0x0010)
+#define AE_AML_STRING_LIMIT EXCEP_AML (0x0011)
+#define AE_AML_NO_RETURN_VALUE EXCEP_AML (0x0012)
+#define AE_AML_METHOD_LIMIT EXCEP_AML (0x0013)
+#define AE_AML_NOT_OWNER EXCEP_AML (0x0014)
+#define AE_AML_MUTEX_ORDER EXCEP_AML (0x0015)
+#define AE_AML_MUTEX_NOT_ACQUIRED EXCEP_AML (0x0016)
+#define AE_AML_INVALID_RESOURCE_TYPE EXCEP_AML (0x0017)
+#define AE_AML_INVALID_INDEX EXCEP_AML (0x0018)
+#define AE_AML_REGISTER_LIMIT EXCEP_AML (0x0019)
+#define AE_AML_NO_WHILE EXCEP_AML (0x001A)
+#define AE_AML_ALIGNMENT EXCEP_AML (0x001B)
+#define AE_AML_NO_RESOURCE_END_TAG EXCEP_AML (0x001C)
+#define AE_AML_BAD_RESOURCE_VALUE EXCEP_AML (0x001D)
+#define AE_AML_CIRCULAR_REFERENCE EXCEP_AML (0x001E)
+#define AE_AML_BAD_RESOURCE_LENGTH EXCEP_AML (0x001F)
+#define AE_AML_ILLEGAL_ADDRESS EXCEP_AML (0x0020)
+#define AE_AML_INFINITE_LOOP EXCEP_AML (0x0021)
#define AE_CODE_AML_MAX 0x0021
/*
* Internal exceptions used for control
*/
-#define AE_CTRL_RETURN_VALUE (acpi_status) (0x0001 | AE_CODE_CONTROL)
-#define AE_CTRL_PENDING (acpi_status) (0x0002 | AE_CODE_CONTROL)
-#define AE_CTRL_TERMINATE (acpi_status) (0x0003 | AE_CODE_CONTROL)
-#define AE_CTRL_TRUE (acpi_status) (0x0004 | AE_CODE_CONTROL)
-#define AE_CTRL_FALSE (acpi_status) (0x0005 | AE_CODE_CONTROL)
-#define AE_CTRL_DEPTH (acpi_status) (0x0006 | AE_CODE_CONTROL)
-#define AE_CTRL_END (acpi_status) (0x0007 | AE_CODE_CONTROL)
-#define AE_CTRL_TRANSFER (acpi_status) (0x0008 | AE_CODE_CONTROL)
-#define AE_CTRL_BREAK (acpi_status) (0x0009 | AE_CODE_CONTROL)
-#define AE_CTRL_CONTINUE (acpi_status) (0x000A | AE_CODE_CONTROL)
-#define AE_CTRL_SKIP (acpi_status) (0x000B | AE_CODE_CONTROL)
-#define AE_CTRL_PARSE_CONTINUE (acpi_status) (0x000C | AE_CODE_CONTROL)
-#define AE_CTRL_PARSE_PENDING (acpi_status) (0x000D | AE_CODE_CONTROL)
+#define AE_CTRL_RETURN_VALUE EXCEP_CTL (0x0001)
+#define AE_CTRL_PENDING EXCEP_CTL (0x0002)
+#define AE_CTRL_TERMINATE EXCEP_CTL (0x0003)
+#define AE_CTRL_TRUE EXCEP_CTL (0x0004)
+#define AE_CTRL_FALSE EXCEP_CTL (0x0005)
+#define AE_CTRL_DEPTH EXCEP_CTL (0x0006)
+#define AE_CTRL_END EXCEP_CTL (0x0007)
+#define AE_CTRL_TRANSFER EXCEP_CTL (0x0008)
+#define AE_CTRL_BREAK EXCEP_CTL (0x0009)
+#define AE_CTRL_CONTINUE EXCEP_CTL (0x000A)
+#define AE_CTRL_SKIP EXCEP_CTL (0x000B)
+#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000C)
+#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000D)
#define AE_CODE_CTRL_MAX 0x000D
@@ -188,112 +221,156 @@
* String versions of the exception codes above
* These strings must match the corresponding defines exactly
*/
-char const *acpi_gbl_exception_names_env[] = {
- "AE_OK",
- "AE_ERROR",
- "AE_NO_ACPI_TABLES",
- "AE_NO_NAMESPACE",
- "AE_NO_MEMORY",
- "AE_NOT_FOUND",
- "AE_NOT_EXIST",
- "AE_ALREADY_EXISTS",
- "AE_TYPE",
- "AE_NULL_OBJECT",
- "AE_NULL_ENTRY",
- "AE_BUFFER_OVERFLOW",
- "AE_STACK_OVERFLOW",
- "AE_STACK_UNDERFLOW",
- "AE_NOT_IMPLEMENTED",
- "AE_SUPPORT",
- "AE_LIMIT",
- "AE_TIME",
- "AE_ACQUIRE_DEADLOCK",
- "AE_RELEASE_DEADLOCK",
- "AE_NOT_ACQUIRED",
- "AE_ALREADY_ACQUIRED",
- "AE_NO_HARDWARE_RESPONSE",
- "AE_NO_GLOBAL_LOCK",
- "AE_ABORT_METHOD",
- "AE_SAME_HANDLER",
- "AE_NO_HANDLER",
- "AE_OWNER_ID_LIMIT",
- "AE_NOT_CONFIGURED"
+static const struct acpi_exception_info acpi_gbl_exception_names_env[] = {
+ EXCEP_TXT("AE_OK", "No error"),
+ EXCEP_TXT("AE_ERROR", "Unspecified error"),
+ EXCEP_TXT("AE_NO_ACPI_TABLES", "ACPI tables could not be found"),
+ EXCEP_TXT("AE_NO_NAMESPACE", "A namespace has not been loaded"),
+ EXCEP_TXT("AE_NO_MEMORY", "Insufficient dynamic memory"),
+ EXCEP_TXT("AE_NOT_FOUND", "The name was not found in the namespace"),
+ EXCEP_TXT("AE_NOT_EXIST", "A required entity does not exist"),
+ EXCEP_TXT("AE_ALREADY_EXISTS", "An entity already exists"),
+ EXCEP_TXT("AE_TYPE", "The object type is incorrect"),
+ EXCEP_TXT("AE_NULL_OBJECT", "A required object was missing"),
+ EXCEP_TXT("AE_NULL_ENTRY", "The requested object does not exist"),
+ EXCEP_TXT("AE_BUFFER_OVERFLOW", "The buffer provided is too small"),
+ EXCEP_TXT("AE_STACK_OVERFLOW", "An internal stack overflowed"),
+ EXCEP_TXT("AE_STACK_UNDERFLOW", "An internal stack underflowed"),
+ EXCEP_TXT("AE_NOT_IMPLEMENTED", "The feature is not implemented"),
+ EXCEP_TXT("AE_SUPPORT", "The feature is not supported"),
+ EXCEP_TXT("AE_LIMIT", "A predefined limit was exceeded"),
+ EXCEP_TXT("AE_TIME", "A time limit or timeout expired"),
+ EXCEP_TXT("AE_ACQUIRE_DEADLOCK",
+ "Internal error, attempt was made to acquire a mutex in improper order"),
+ EXCEP_TXT("AE_RELEASE_DEADLOCK",
+ "Internal error, attempt was made to release a mutex in improper order"),
+ EXCEP_TXT("AE_NOT_ACQUIRED",
+ "An attempt to release a mutex or Global Lock without a previous acquire"),
+ EXCEP_TXT("AE_ALREADY_ACQUIRED",
+ "Internal error, attempt was made to acquire a mutex twice"),
+ EXCEP_TXT("AE_NO_HARDWARE_RESPONSE",
+ "Hardware did not respond after an I/O operation"),
+ EXCEP_TXT("AE_NO_GLOBAL_LOCK", "There is no FACS Global Lock"),
+ EXCEP_TXT("AE_ABORT_METHOD", "A control method was aborted"),
+ EXCEP_TXT("AE_SAME_HANDLER",
+ "Attempt was made to install the same handler that is already installed"),
+ EXCEP_TXT("AE_NO_HANDLER",
+ "A handler for the operation is not installed"),
+ EXCEP_TXT("AE_OWNER_ID_LIMIT",
+ "There are no more Owner IDs available for ACPI tables or control methods"),
+ EXCEP_TXT("AE_NOT_CONFIGURED",
+ "The interface is not part of the current subsystem configuration")
};
-char const *acpi_gbl_exception_names_pgm[] = {
- NULL,
- "AE_BAD_PARAMETER",
- "AE_BAD_CHARACTER",
- "AE_BAD_PATHNAME",
- "AE_BAD_DATA",
- "AE_BAD_HEX_CONSTANT",
- "AE_BAD_OCTAL_CONSTANT",
- "AE_BAD_DECIMAL_CONSTANT",
- "AE_MISSING_ARGUMENTS",
- "AE_BAD_ADDRESS"
+static const struct acpi_exception_info acpi_gbl_exception_names_pgm[] = {
+ EXCEP_TXT(NULL, NULL),
+ EXCEP_TXT("AE_BAD_PARAMETER", "A parameter is out of range or invalid"),
+ EXCEP_TXT("AE_BAD_CHARACTER",
+ "An invalid character was found in a name"),
+ EXCEP_TXT("AE_BAD_PATHNAME",
+ "An invalid character was found in a pathname"),
+ EXCEP_TXT("AE_BAD_DATA",
+ "A package or buffer contained incorrect data"),
+ EXCEP_TXT("AE_BAD_HEX_CONSTANT", "Invalid character in a Hex constant"),
+ EXCEP_TXT("AE_BAD_OCTAL_CONSTANT",
+ "Invalid character in an Octal constant"),
+ EXCEP_TXT("AE_BAD_DECIMAL_CONSTANT",
+ "Invalid character in a Decimal constant"),
+ EXCEP_TXT("AE_MISSING_ARGUMENTS",
+ "Too few arguments were passed to a control method"),
+ EXCEP_TXT("AE_BAD_ADDRESS", "An illegal null I/O address")
};
-char const *acpi_gbl_exception_names_tbl[] = {
- NULL,
- "AE_BAD_SIGNATURE",
- "AE_BAD_HEADER",
- "AE_BAD_CHECKSUM",
- "AE_BAD_VALUE",
- "AE_INVALID_TABLE_LENGTH"
+static const struct acpi_exception_info acpi_gbl_exception_names_tbl[] = {
+ EXCEP_TXT(NULL, NULL),
+ EXCEP_TXT("AE_BAD_SIGNATURE", "An ACPI table has an invalid signature"),
+ EXCEP_TXT("AE_BAD_HEADER", "Invalid field in an ACPI table header"),
+ EXCEP_TXT("AE_BAD_CHECKSUM", "An ACPI table checksum is not correct"),
+ EXCEP_TXT("AE_BAD_VALUE", "An invalid value was found in a table"),
+ EXCEP_TXT("AE_INVALID_TABLE_LENGTH",
+ "The FADT or FACS has improper length")
};
-char const *acpi_gbl_exception_names_aml[] = {
- NULL,
- "AE_AML_BAD_OPCODE",
- "AE_AML_NO_OPERAND",
- "AE_AML_OPERAND_TYPE",
- "AE_AML_OPERAND_VALUE",
- "AE_AML_UNINITIALIZED_LOCAL",
- "AE_AML_UNINITIALIZED_ARG",
- "AE_AML_UNINITIALIZED_ELEMENT",
- "AE_AML_NUMERIC_OVERFLOW",
- "AE_AML_REGION_LIMIT",
- "AE_AML_BUFFER_LIMIT",
- "AE_AML_PACKAGE_LIMIT",
- "AE_AML_DIVIDE_BY_ZERO",
- "AE_AML_BAD_NAME",
- "AE_AML_NAME_NOT_FOUND",
- "AE_AML_INTERNAL",
- "AE_AML_INVALID_SPACE_ID",
- "AE_AML_STRING_LIMIT",
- "AE_AML_NO_RETURN_VALUE",
- "AE_AML_METHOD_LIMIT",
- "AE_AML_NOT_OWNER",
- "AE_AML_MUTEX_ORDER",
- "AE_AML_MUTEX_NOT_ACQUIRED",
- "AE_AML_INVALID_RESOURCE_TYPE",
- "AE_AML_INVALID_INDEX",
- "AE_AML_REGISTER_LIMIT",
- "AE_AML_NO_WHILE",
- "AE_AML_ALIGNMENT",
- "AE_AML_NO_RESOURCE_END_TAG",
- "AE_AML_BAD_RESOURCE_VALUE",
- "AE_AML_CIRCULAR_REFERENCE",
- "AE_AML_BAD_RESOURCE_LENGTH",
- "AE_AML_ILLEGAL_ADDRESS",
- "AE_AML_INFINITE_LOOP"
+static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = {
+ EXCEP_TXT(NULL, NULL),
+ EXCEP_TXT("AE_AML_BAD_OPCODE", "Invalid AML opcode encountered"),
+ EXCEP_TXT("AE_AML_NO_OPERAND", "A required operand is missing"),
+ EXCEP_TXT("AE_AML_OPERAND_TYPE",
+ "An operand of an incorrect type was encountered"),
+ EXCEP_TXT("AE_AML_OPERAND_VALUE",
+ "The operand had an inappropriate or invalid value"),
+ EXCEP_TXT("AE_AML_UNINITIALIZED_LOCAL",
+ "Method tried to use an uninitialized local variable"),
+ EXCEP_TXT("AE_AML_UNINITIALIZED_ARG",
+ "Method tried to use an uninitialized argument"),
+ EXCEP_TXT("AE_AML_UNINITIALIZED_ELEMENT",
+ "Method tried to use an empty package element"),
+ EXCEP_TXT("AE_AML_NUMERIC_OVERFLOW",
+ "Overflow during BCD conversion or other"),
+ EXCEP_TXT("AE_AML_REGION_LIMIT",
+ "Tried to access beyond the end of an Operation Region"),
+ EXCEP_TXT("AE_AML_BUFFER_LIMIT",
+ "Tried to access beyond the end of a buffer"),
+ EXCEP_TXT("AE_AML_PACKAGE_LIMIT",
+ "Tried to access beyond the end of a package"),
+ EXCEP_TXT("AE_AML_DIVIDE_BY_ZERO",
+ "During execution of AML Divide operator"),
+ EXCEP_TXT("AE_AML_BAD_NAME",
+ "An ACPI name contains invalid character(s)"),
+ EXCEP_TXT("AE_AML_NAME_NOT_FOUND",
+ "Could not resolve a named reference"),
+ EXCEP_TXT("AE_AML_INTERNAL", "An internal error within the interprete"),
+ EXCEP_TXT("AE_AML_INVALID_SPACE_ID",
+ "An Operation Region SpaceID is invalid"),
+ EXCEP_TXT("AE_AML_STRING_LIMIT",
+ "String is longer than 200 characters"),
+ EXCEP_TXT("AE_AML_NO_RETURN_VALUE",
+ "A method did not return a required value"),
+ EXCEP_TXT("AE_AML_METHOD_LIMIT",
+ "A control method reached the maximum reentrancy limit of 255"),
+ EXCEP_TXT("AE_AML_NOT_OWNER",
+ "A thread tried to release a mutex that it does not own"),
+ EXCEP_TXT("AE_AML_MUTEX_ORDER", "Mutex SyncLevel release mismatch"),
+ EXCEP_TXT("AE_AML_MUTEX_NOT_ACQUIRED",
+ "Attempt to release a mutex that was not previously acquired"),
+ EXCEP_TXT("AE_AML_INVALID_RESOURCE_TYPE",
+ "Invalid resource type in resource list"),
+ EXCEP_TXT("AE_AML_INVALID_INDEX",
+ "Invalid Argx or Localx (x too large)"),
+ EXCEP_TXT("AE_AML_REGISTER_LIMIT",
+ "Bank value or Index value beyond range of register"),
+ EXCEP_TXT("AE_AML_NO_WHILE", "Break or Continue without a While"),
+ EXCEP_TXT("AE_AML_ALIGNMENT",
+ "Non-aligned memory transfer on platform that does not support this"),
+ EXCEP_TXT("AE_AML_NO_RESOURCE_END_TAG",
+ "No End Tag in a resource list"),
+ EXCEP_TXT("AE_AML_BAD_RESOURCE_VALUE",
+ "Invalid value of a resource element"),
+ EXCEP_TXT("AE_AML_CIRCULAR_REFERENCE",
+ "Two references refer to each other"),
+ EXCEP_TXT("AE_AML_BAD_RESOURCE_LENGTH",
+ "The length of a Resource Descriptor in the AML is incorrect"),
+ EXCEP_TXT("AE_AML_ILLEGAL_ADDRESS",
+ "A memory, I/O, or PCI configuration address is invalid"),
+ EXCEP_TXT("AE_AML_INFINITE_LOOP",
+ "An apparent infinite AML While loop, method was aborted")
};
-char const *acpi_gbl_exception_names_ctrl[] = {
- NULL,
- "AE_CTRL_RETURN_VALUE",
- "AE_CTRL_PENDING",
- "AE_CTRL_TERMINATE",
- "AE_CTRL_TRUE",
- "AE_CTRL_FALSE",
- "AE_CTRL_DEPTH",
- "AE_CTRL_END",
- "AE_CTRL_TRANSFER",
- "AE_CTRL_BREAK",
- "AE_CTRL_CONTINUE",
- "AE_CTRL_SKIP",
- "AE_CTRL_PARSE_CONTINUE",
- "AE_CTRL_PARSE_PENDING"
+static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = {
+ EXCEP_TXT(NULL, NULL),
+ EXCEP_TXT("AE_CTRL_RETURN_VALUE", "A Method returned a value"),
+ EXCEP_TXT("AE_CTRL_PENDING", "Method is calling another method"),
+ EXCEP_TXT("AE_CTRL_TERMINATE", "Terminate the executing method"),
+ EXCEP_TXT("AE_CTRL_TRUE", "An If or While predicate result"),
+ EXCEP_TXT("AE_CTRL_FALSE", "An If or While predicate result"),
+ EXCEP_TXT("AE_CTRL_DEPTH", "Maximum search depth has been reached"),
+ EXCEP_TXT("AE_CTRL_END", "An If or While predicate is false"),
+ EXCEP_TXT("AE_CTRL_TRANSFER", "Transfer control to called method"),
+ EXCEP_TXT("AE_CTRL_BREAK", "A Break has been executed"),
+ EXCEP_TXT("AE_CTRL_CONTINUE", "A Continue has been executed"),
+ EXCEP_TXT("AE_CTRL_SKIP", "Not currently used"),
+ EXCEP_TXT("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"),
+ EXCEP_TXT("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops")
};
#endif /* EXCEPTION_TABLE */
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 9885276178e0..4f52ea795c7a 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -324,9 +324,9 @@
/* Helper macro */
-#define ACPI_TRACE_ENTRY(name, function, cast, param) \
+#define ACPI_TRACE_ENTRY(name, function, type, param) \
ACPI_FUNCTION_NAME (name) \
- function (ACPI_DEBUG_PARAMETERS, cast (param))
+ function (ACPI_DEBUG_PARAMETERS, (type) (param))
/* The actual entry trace macros */
@@ -335,13 +335,13 @@
acpi_ut_trace (ACPI_DEBUG_PARAMETERS)
#define ACPI_FUNCTION_TRACE_PTR(name, pointer) \
- ACPI_TRACE_ENTRY (name, acpi_ut_trace_ptr, (void *), pointer)
+ ACPI_TRACE_ENTRY (name, acpi_ut_trace_ptr, void *, pointer)
#define ACPI_FUNCTION_TRACE_U32(name, value) \
- ACPI_TRACE_ENTRY (name, acpi_ut_trace_u32, (u32), value)
+ ACPI_TRACE_ENTRY (name, acpi_ut_trace_u32, u32, value)
#define ACPI_FUNCTION_TRACE_STR(name, string) \
- ACPI_TRACE_ENTRY (name, acpi_ut_trace_str, (char *), string)
+ ACPI_TRACE_ENTRY (name, acpi_ut_trace_str, char *, string)
#define ACPI_FUNCTION_ENTRY() \
acpi_ut_track_stack_ptr()
@@ -355,16 +355,37 @@
*
* One of the FUNCTION_TRACE macros above must be used in conjunction
* with these macros so that "_AcpiFunctionName" is defined.
+ *
+ * There are two versions of most of the return macros. The default version is
+ * safer, since it avoids side-effects by guaranteeing that the argument will
+ * not be evaluated twice.
+ *
+ * A less-safe version of the macros is provided for optional use if the
+ * compiler uses excessive CPU stack (for example, this may happen in the
+ * debug case if code optimzation is disabled.)
*/
/* Exit trace helper macro */
-#define ACPI_TRACE_EXIT(function, cast, param) \
+#ifndef ACPI_SIMPLE_RETURN_MACROS
+
+#define ACPI_TRACE_EXIT(function, type, param) \
+ ACPI_DO_WHILE0 ({ \
+ register type _param = (type) (param); \
+ function (ACPI_DEBUG_PARAMETERS, _param); \
+ return (_param); \
+ })
+
+#else /* Use original less-safe macros */
+
+#define ACPI_TRACE_EXIT(function, type, param) \
ACPI_DO_WHILE0 ({ \
- function (ACPI_DEBUG_PARAMETERS, cast (param)); \
- return ((param)); \
+ function (ACPI_DEBUG_PARAMETERS, (type) (param)); \
+ return (param); \
})
+#endif /* ACPI_SIMPLE_RETURN_MACROS */
+
/* The actual exit macros */
#define return_VOID \
@@ -374,13 +395,19 @@
})
#define return_ACPI_STATUS(status) \
- ACPI_TRACE_EXIT (acpi_ut_status_exit, (acpi_status), status)
+ ACPI_TRACE_EXIT (acpi_ut_status_exit, acpi_status, status)
#define return_PTR(pointer) \
- ACPI_TRACE_EXIT (acpi_ut_ptr_exit, (u8 *), pointer)
+ ACPI_TRACE_EXIT (acpi_ut_ptr_exit, void *, pointer)
#define return_VALUE(value) \
- ACPI_TRACE_EXIT (acpi_ut_value_exit, (u64), value)
+ ACPI_TRACE_EXIT (acpi_ut_value_exit, u64, value)
+
+#define return_UINT32(value) \
+ ACPI_TRACE_EXIT (acpi_ut_value_exit, u32, value)
+
+#define return_UINT8(value) \
+ ACPI_TRACE_EXIT (acpi_ut_value_exit, u8, value)
/* Conditional execution */
@@ -428,8 +455,10 @@
#define return_VOID return
#define return_ACPI_STATUS(s) return(s)
-#define return_VALUE(s) return(s)
#define return_PTR(s) return(s)
+#define return_VALUE(s) return(s)
+#define return_UINT8(s) return(s)
+#define return_UINT32(s) return(s)
#endif /* ACPI_DEBUG_OUTPUT */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 22ba56e834e2..98db31d9f9b4 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -88,11 +88,30 @@ struct acpi_device;
* -----------------
*/
+enum acpi_hotplug_mode {
+ AHM_GENERIC = 0,
+ AHM_CONTAINER,
+ AHM_COUNT
+};
+
+struct acpi_hotplug_profile {
+ struct kobject kobj;
+ bool enabled:1;
+ enum acpi_hotplug_mode mode;
+};
+
+static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile(
+ struct kobject *kobj)
+{
+ return container_of(kobj, struct acpi_hotplug_profile, kobj);
+}
+
struct acpi_scan_handler {
const struct acpi_device_id *ids;
struct list_head list_node;
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
void (*detach)(struct acpi_device *dev);
+ struct acpi_hotplug_profile hotplug;
};
/*
@@ -142,7 +161,6 @@ struct acpi_device_status {
struct acpi_device_flags {
u32 dynamic_status:1;
- u32 bus_address:1;
u32 removable:1;
u32 ejectable:1;
u32 suprise_removal_ok:1;
@@ -150,7 +168,7 @@ struct acpi_device_flags {
u32 performance_manageable:1;
u32 eject_pending:1;
u32 match_driver:1;
- u32 reserved:23;
+ u32 reserved:24;
};
/* File System */
@@ -173,10 +191,17 @@ struct acpi_hardware_id {
char *id;
};
+struct acpi_pnp_type {
+ u32 hardware_id:1;
+ u32 bus_address:1;
+ u32 reserved:30;
+};
+
struct acpi_device_pnp {
- acpi_bus_id bus_id; /* Object name */
+ acpi_bus_id bus_id; /* Object name */
+ struct acpi_pnp_type type; /* ID type */
acpi_bus_address bus_address; /* _ADR */
- char *unique_id; /* _UID */
+ char *unique_id; /* _UID */
struct list_head ids; /* _HID and _CIDs */
acpi_device_name device_name; /* Driver-determined */
acpi_device_class device_class; /* " */
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index 627749af0ba7..e6168a24b9f0 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -95,7 +95,6 @@ int acpi_pci_link_free_irq(acpi_handle handle);
struct pci_bus;
struct pci_dev *acpi_get_pci_dev(acpi_handle);
-int acpi_pci_bind_root(struct acpi_device *device);
/* Arch-defined function to add a bus to the system */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 03322dddd88e..454881e6450a 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20130117
+#define ACPI_CA_VERSION 0x20130328
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 77dc7a4099a3..ffaac0e7e0c6 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -72,11 +72,13 @@
#define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */
#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */
+#define ACPI_SIG_MTMR "MTMR" /* MID Timer table */
#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */
#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */
#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */
#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */
#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */
+#define ACPI_SIG_VRTC "VRTC" /* Virtual Real Time Clock Table */
#define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */
#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */
#define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */
@@ -852,6 +854,29 @@ struct acpi_table_mchi {
/*******************************************************************************
*
+ * MTMR - MID Timer Table
+ * Version 1
+ *
+ * Conforms to "Simple Firmware Interface Specification",
+ * Draft 0.8.2, Oct 19, 2010
+ * NOTE: The ACPI MTMR is equivalent to the SFI MTMR table.
+ *
+ ******************************************************************************/
+
+struct acpi_table_mtmr {
+ struct acpi_table_header header; /* Common ACPI table header */
+};
+
+/* MTMR entry */
+
+struct acpi_mtmr_entry {
+ struct acpi_generic_address physical_address;
+ u32 frequency;
+ u32 irq;
+};
+
+/*******************************************************************************
+ *
* SLIC - Software Licensing Description Table
* Version 1
*
@@ -1025,6 +1050,28 @@ struct acpi_table_uefi {
/*******************************************************************************
*
+ * VRTC - Virtual Real Time Clock Table
+ * Version 1
+ *
+ * Conforms to "Simple Firmware Interface Specification",
+ * Draft 0.8.2, Oct 19, 2010
+ * NOTE: The ACPI VRTC is equivalent to The SFI MRTC table.
+ *
+ ******************************************************************************/
+
+struct acpi_table_vrtc {
+ struct acpi_table_header header; /* Common ACPI table header */
+};
+
+/* VRTC entry */
+
+struct acpi_vrtc_entry {
+ struct acpi_generic_address physical_address;
+ u32 irq;
+};
+
+/*******************************************************************************
+ *
* WAET - Windows ACPI Emulated devices Table
* Version 1
*
diff --git a/include/acpi/actbl3.h b/include/acpi/actbl3.h
index 332b17e3bec8..e2c0931a3d67 100644
--- a/include/acpi/actbl3.h
+++ b/include/acpi/actbl3.h
@@ -174,7 +174,7 @@ struct acpi_fpdt_header {
enum acpi_fpdt_type {
ACPI_FPDT_TYPE_BOOT = 0,
- ACPI_FPDT_TYPE_S3PERF = 1,
+ ACPI_FPDT_TYPE_S3PERF = 1
};
/*
@@ -223,7 +223,7 @@ struct acpi_s3pt_header {
enum acpi_s3pt_type {
ACPI_S3PT_TYPE_RESUME = 0,
- ACPI_S3PT_TYPE_SUSPEND = 1,
+ ACPI_S3PT_TYPE_SUSPEND = 1
};
struct acpi_s3pt_resume {
@@ -505,26 +505,59 @@ struct acpi_rasf_shared_memory {
u32 signature;
u16 command;
u16 status;
- u64 requested_address;
- u64 requested_length;
- u64 actual_address;
- u64 actual_length;
+ u16 version;
+ u8 capabilities[16];
+ u8 set_capabilities[16];
+ u16 num_parameter_blocks;
+ u32 set_capabilities_status;
+};
+
+/* RASF Parameter Block Structure Header */
+
+struct acpi_rasf_parameter_block {
+ u16 type;
+ u16 version;
+ u16 length;
+};
+
+/* RASF Parameter Block Structure for PATROL_SCRUB */
+
+struct acpi_rasf_patrol_scrub_parameter {
+ struct acpi_rasf_parameter_block header;
+ u16 patrol_scrub_command;
+ u64 requested_address_range[2];
+ u64 actual_address_range[2];
u16 flags;
- u8 speed;
+ u8 requested_speed;
};
/* Masks for Flags and Speed fields above */
#define ACPI_RASF_SCRUBBER_RUNNING 1
#define ACPI_RASF_SPEED (7<<1)
+#define ACPI_RASF_SPEED_SLOW (0<<1)
+#define ACPI_RASF_SPEED_MEDIUM (4<<1)
+#define ACPI_RASF_SPEED_FAST (7<<1)
/* Channel Commands */
enum acpi_rasf_commands {
- ACPI_RASF_GET_RAS_CAPABILITIES = 1,
- ACPI_RASF_GET_PATROL_PARAMETERS = 2,
- ACPI_RASF_START_PATROL_SCRUBBER = 3,
- ACPI_RASF_STOP_PATROL_SCRUBBER = 4
+ ACPI_RASF_EXECUTE_RASF_COMMAND = 1
+};
+
+/* Platform RAS Capabilities */
+
+enum acpi_rasf_capabiliities {
+ ACPI_HW_PATROL_SCRUB_SUPPORTED = 0,
+ ACPI_SW_PATROL_SCRUB_EXPOSED = 1
+};
+
+/* Patrol Scrub Commands */
+
+enum acpi_rasf_patrol_scrub_commands {
+ ACPI_RASF_GET_PATROL_PARAMETERS = 1,
+ ACPI_RASF_START_PATROL_SCRUBBER = 2,
+ ACPI_RASF_STOP_PATROL_SCRUBBER = 3
};
/* Channel Command flags */
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 845e75f1ffd8..a64adcc29ae5 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -650,13 +650,14 @@ typedef u32 acpi_event_type;
* The encoding of acpi_event_status is illustrated below.
* Note that a set bit (1) indicates the property is TRUE
* (e.g. if bit 0 is set then the event is enabled).
- * +-------------+-+-+-+
- * | Bits 31:3 |2|1|0|
- * +-------------+-+-+-+
- * | | | |
- * | | | +- Enabled?
- * | | +--- Enabled for wake?
- * | +----- Set?
+ * +-------------+-+-+-+-+
+ * | Bits 31:4 |3|2|1|0|
+ * +-------------+-+-+-+-+
+ * | | | | |
+ * | | | | +- Enabled?
+ * | | | +--- Enabled for wake?
+ * | | +----- Set?
+ * | +------- Has a handler?
* +----------- <Reserved>
*/
typedef u32 acpi_event_status;
@@ -1128,7 +1129,6 @@ struct acpi_memory_list {
u16 object_size;
u16 max_depth;
u16 current_depth;
- u16 link_offset;
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
diff --git a/include/asm-generic/hugetlb.h b/include/asm-generic/hugetlb.h
new file mode 100644
index 000000000000..d06079c774a0
--- /dev/null
+++ b/include/asm-generic/hugetlb.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_GENERIC_HUGETLB_H
+#define _ASM_GENERIC_HUGETLB_H
+
+static inline pte_t mk_huge_pte(struct page *page, pgprot_t pgprot)
+{
+ return mk_pte(page, pgprot);
+}
+
+static inline int huge_pte_write(pte_t pte)
+{
+ return pte_write(pte);
+}
+
+static inline int huge_pte_dirty(pte_t pte)
+{
+ return pte_dirty(pte);
+}
+
+static inline pte_t huge_pte_mkwrite(pte_t pte)
+{
+ return pte_mkwrite(pte);
+}
+
+static inline pte_t huge_pte_mkdirty(pte_t pte)
+{
+ return pte_mkdirty(pte);
+}
+
+static inline pte_t huge_pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return pte_modify(pte, newprot);
+}
+
+static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_clear(mm, addr, ptep);
+}
+
+#endif /* _ASM_GENERIC_HUGETLB_H */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index bfd87685fc1f..a59ff51b0166 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -7,6 +7,16 @@
#include <linux/mm_types.h>
#include <linux/bug.h>
+/*
+ * On almost all architectures and configurations, 0 can be used as the
+ * upper ceiling to free_pgtables(): on many architectures it has the same
+ * effect as using TASK_SIZE. However, there is one configuration which
+ * must impose a more careful limit, to avoid freeing kernel pgtables.
+ */
+#ifndef USER_PGTABLES_CEILING
+#define USER_PGTABLES_CEILING 0UL
+#endif
+
#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
extern int ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep,
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 25f01d0bc149..b1b1fa6ffffe 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -99,7 +99,12 @@ struct mmu_gather {
unsigned int need_flush : 1, /* Did free PTEs */
fast_mode : 1; /* No batching */
- unsigned int fullmm;
+ /* we are in the middle of an operation to clear
+ * a full mm and can make some optimizations */
+ unsigned int fullmm : 1,
+ /* we have performed an operation which
+ * requires a complete flush of the tlb */
+ need_flush_all : 1;
struct mmu_gather_batch *active;
struct mmu_gather_batch local;
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 4077b5d9ff81..0501fa3f783d 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -9,20 +9,3 @@
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_LLSEEK
#endif
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#ifndef cond_syscall
-#ifdef CONFIG_SYMBOL_PREFIX
-#define __SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
-#else
-#define __SYMBOL_PREFIX
-#endif
-#define cond_syscall(x) asm(".weak\t" __SYMBOL_PREFIX #x "\n\t" \
- ".set\t" __SYMBOL_PREFIX #x "," \
- __SYMBOL_PREFIX "sys_ni_syscall")
-#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index bcbdd7484e58..17b5b5967641 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -152,15 +152,6 @@ void acpi_penalize_isa_irq(int irq, int active);
void acpi_pci_irq_disable (struct pci_dev *dev);
-struct acpi_pci_driver {
- struct list_head node;
- int (*add)(struct acpi_pci_root *root);
- void (*remove)(struct acpi_pci_root *root);
-};
-
-int acpi_pci_register_driver(struct acpi_pci_driver *driver);
-void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
-
extern int ec_read(u8 addr, u8 *val);
extern int ec_write(u8 addr, u8 val);
extern int ec_transaction(u8 command,
@@ -204,7 +195,7 @@ extern bool wmi_has_guid(const char *guid);
#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
-extern long acpi_is_video_device(struct acpi_device *device);
+extern long acpi_is_video_device(acpi_handle handle);
extern void acpi_video_dmi_promote_vendor(void);
extern void acpi_video_dmi_demote_vendor(void);
extern int acpi_video_backlight_support(void);
@@ -217,7 +208,7 @@ static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
return 0;
}
-static inline long acpi_is_video_device(struct acpi_device *device)
+static inline long acpi_is_video_device(acpi_handle handle)
{
return 0;
}
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index f612c783170f..62d9303c2837 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -203,6 +203,9 @@ struct amba_pl011_data {
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
void *dma_rx_param;
void *dma_tx_param;
+ bool dma_rx_poll_enable;
+ unsigned int dma_rx_poll_rate;
+ unsigned int dma_rx_poll_timeout;
void (*init) (void);
void (*exit) (void);
};
diff --git a/include/linux/async.h b/include/linux/async.h
index a2e3f18b2ad6..6b0226bdaadc 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -16,9 +16,8 @@
#include <linux/list.h>
typedef u64 async_cookie_t;
-typedef void (async_func_ptr) (void *data, async_cookie_t cookie);
+typedef void (*async_func_t) (void *data, async_cookie_t cookie);
struct async_domain {
- struct list_head node;
struct list_head pending;
unsigned registered:1;
};
@@ -27,8 +26,7 @@ struct async_domain {
* domain participates in global async_synchronize_full
*/
#define ASYNC_DOMAIN(_name) \
- struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
- .pending = LIST_HEAD_INIT(_name.pending), \
+ struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \
.registered = 1 }
/*
@@ -36,12 +34,11 @@ struct async_domain {
* complete, this domain does not participate in async_synchronize_full
*/
#define ASYNC_DOMAIN_EXCLUSIVE(_name) \
- struct async_domain _name = { .node = LIST_HEAD_INIT(_name.node), \
- .pending = LIST_HEAD_INIT(_name.pending), \
+ struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \
.registered = 0 }
-extern async_cookie_t async_schedule(async_func_ptr *ptr, void *data);
-extern async_cookie_t async_schedule_domain(async_func_ptr *ptr, void *data,
+extern async_cookie_t async_schedule(async_func_t func, void *data);
+extern async_cookie_t async_schedule_domain(async_func_t func, void *data,
struct async_domain *domain);
void async_unregister_domain(struct async_domain *domain);
extern void async_synchronize_full(void);
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 8f7a3d68371a..ee0bd9524055 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -954,7 +954,7 @@ static inline int atapi_cdb_len(const u16 *dev_id)
}
}
-static inline bool atapi_command_packet_set(const u16 *dev_id)
+static inline int atapi_command_packet_set(const u16 *dev_id)
{
return (dev_id[ATA_ID_CONFIG] >> 8) & 0x1f;
}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index e0ce311011c0..f14a98a79c9d 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -134,6 +134,7 @@ struct bcma_host_ops {
#define BCMA_CORE_I2S 0x834
#define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */
#define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */
+#define BCMA_CORE_ARM_CR4 0x83e
#define BCMA_CORE_DEFAULT 0xFFF
#define BCMA_MAX_NR_CORES 16
@@ -173,6 +174,60 @@ struct bcma_host_ops {
#define BCMA_CHIP_ID_BCM53572 53572
#define BCMA_PKG_ID_BCM47188 9
+/* Board types (on PCI usually equals to the subsystem dev id) */
+/* BCM4313 */
+#define BCMA_BOARD_TYPE_BCM94313BU 0X050F
+#define BCMA_BOARD_TYPE_BCM94313HM 0X0510
+#define BCMA_BOARD_TYPE_BCM94313EPA 0X0511
+#define BCMA_BOARD_TYPE_BCM94313HMG 0X051C
+/* BCM4716 */
+#define BCMA_BOARD_TYPE_BCM94716NR2 0X04CD
+/* BCM43224 */
+#define BCMA_BOARD_TYPE_BCM943224X21 0X056E
+#define BCMA_BOARD_TYPE_BCM943224X21_FCC 0X00D1
+#define BCMA_BOARD_TYPE_BCM943224X21B 0X00E9
+#define BCMA_BOARD_TYPE_BCM943224M93 0X008B
+#define BCMA_BOARD_TYPE_BCM943224M93A 0X0090
+#define BCMA_BOARD_TYPE_BCM943224X16 0X0093
+#define BCMA_BOARD_TYPE_BCM94322X9 0X008D
+#define BCMA_BOARD_TYPE_BCM94322M35E 0X008E
+/* BCM43228 */
+#define BCMA_BOARD_TYPE_BCM943228BU8 0X0540
+#define BCMA_BOARD_TYPE_BCM943228BU9 0X0541
+#define BCMA_BOARD_TYPE_BCM943228BU 0X0542
+#define BCMA_BOARD_TYPE_BCM943227HM4L 0X0543
+#define BCMA_BOARD_TYPE_BCM943227HMB 0X0544
+#define BCMA_BOARD_TYPE_BCM943228HM4L 0X0545
+#define BCMA_BOARD_TYPE_BCM943228SD 0X0573
+/* BCM4331 */
+#define BCMA_BOARD_TYPE_BCM94331X19 0X00D6
+#define BCMA_BOARD_TYPE_BCM94331X28 0X00E4
+#define BCMA_BOARD_TYPE_BCM94331X28B 0X010E
+#define BCMA_BOARD_TYPE_BCM94331PCIEBT3AX 0X00E4
+#define BCMA_BOARD_TYPE_BCM94331X12_2G 0X00EC
+#define BCMA_BOARD_TYPE_BCM94331X12_5G 0X00ED
+#define BCMA_BOARD_TYPE_BCM94331X29B 0X00EF
+#define BCMA_BOARD_TYPE_BCM94331CSAX 0X00EF
+#define BCMA_BOARD_TYPE_BCM94331X19C 0X00F5
+#define BCMA_BOARD_TYPE_BCM94331X33 0X00F4
+#define BCMA_BOARD_TYPE_BCM94331BU 0X0523
+#define BCMA_BOARD_TYPE_BCM94331S9BU 0X0524
+#define BCMA_BOARD_TYPE_BCM94331MC 0X0525
+#define BCMA_BOARD_TYPE_BCM94331MCI 0X0526
+#define BCMA_BOARD_TYPE_BCM94331PCIEBT4 0X0527
+#define BCMA_BOARD_TYPE_BCM94331HM 0X0574
+#define BCMA_BOARD_TYPE_BCM94331PCIEDUAL 0X059B
+#define BCMA_BOARD_TYPE_BCM94331MCH5 0X05A9
+#define BCMA_BOARD_TYPE_BCM94331CS 0X05C6
+#define BCMA_BOARD_TYPE_BCM94331CD 0X05DA
+/* BCM53572 */
+#define BCMA_BOARD_TYPE_BCM953572BU 0X058D
+#define BCMA_BOARD_TYPE_BCM953572NR2 0X058E
+#define BCMA_BOARD_TYPE_BCM947188NR2 0X058F
+#define BCMA_BOARD_TYPE_BCM953572SDRNR2 0X0590
+/* BCM43142 */
+#define BCMA_BOARD_TYPE_BCM943142HM 0X05E0
+
struct bcma_device {
struct bcma_bus *bus;
struct bcma_device_id id;
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
index 8390c474f69a..b8b09eac60a4 100644
--- a/include/linux/bcma/bcma_driver_chipcommon.h
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -104,6 +104,7 @@
#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
+#define BCMA_CC_CHIPST_4360_XTAL_40MZ 0x00000001
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
#define BCMA_CC_JCMD_START 0x80000000
#define BCMA_CC_JCMD_BUSY 0x80000000
@@ -315,6 +316,9 @@
#define BCMA_CC_PMU_CTL 0x0600 /* PMU control */
#define BCMA_CC_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */
#define BCMA_CC_PMU_CTL_ILP_DIV_SHIFT 16
+#define BCMA_CC_PMU_CTL_RES 0x00006000 /* reset control mask */
+#define BCMA_CC_PMU_CTL_RES_SHIFT 13
+#define BCMA_CC_PMU_CTL_RES_RELOAD 0x2 /* reload POR values */
#define BCMA_CC_PMU_CTL_PLL_UPD 0x00000400
#define BCMA_CC_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */
#define BCMA_CC_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */
@@ -607,6 +611,8 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
+extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
+
void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h
index 7e8104bb7a7e..917dcd7965e7 100644
--- a/include/linux/bcma/bcma_regs.h
+++ b/include/linux/bcma/bcma_regs.h
@@ -37,6 +37,7 @@
#define BCMA_IOST_BIST_DONE 0x8000
#define BCMA_RESET_CTL 0x0800
#define BCMA_RESET_CTL_RESET 0x0001
+#define BCMA_RESET_ST 0x0804
/* BCMA PCI config space registers. */
#define BCMA_PCI_PMCSR 0x44
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index cdf11191e645..22990cf4439d 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -111,12 +111,13 @@ struct bio {
#define BIO_FS_INTEGRITY 9 /* fs owns integrity data, not block layer */
#define BIO_QUIET 10 /* Make BIO Quiet */
#define BIO_MAPPED_INTEGRITY 11/* integrity metadata has been remapped */
+#define BIO_SNAP_STABLE 12 /* bio data must be snapshotted during write */
/*
* Flags starting here get preserved by bio_reset() - this includes
* BIO_POOL_IDX()
*/
-#define BIO_RESET_BITS 12
+#define BIO_RESET_BITS 13
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 0ea61e07a91c..7c2e030e72f1 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -12,7 +12,6 @@
struct blk_trace {
int trace_state;
- bool rq_based;
struct rchan *rchan;
unsigned long __percpu *sequence;
unsigned char __percpu *msg_data;
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index cdc3bab01832..5f0b0e1f7c08 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -44,7 +44,6 @@ extern unsigned long init_bootmem_node(pg_data_t *pgdat,
unsigned long endpfn);
extern unsigned long init_bootmem(unsigned long addr, unsigned long memend);
-extern unsigned long free_low_memory_core_early(int nodeid);
extern unsigned long free_all_bootmem_node(pg_data_t *pgdat);
extern unsigned long free_all_bootmem(void);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 5afc4f94d110..9e52b0626b39 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -34,6 +34,8 @@ enum bh_state_bits {
BH_Write_EIO, /* I/O error on write */
BH_Unwritten, /* Buffer is allocated on disk but not written */
BH_Quiet, /* Buffer Error Prinks to be quiet */
+ BH_Meta, /* Buffer contains metadata */
+ BH_Prio, /* Buffer should be submitted with REQ_PRIO */
BH_PrivateStart,/* not a state bit, but the first bit available
* for private allocation by other entities
@@ -124,6 +126,8 @@ BUFFER_FNS(Delay, delay)
BUFFER_FNS(Boundary, boundary)
BUFFER_FNS(Write_EIO, write_io_error)
BUFFER_FNS(Unwritten, unwritten)
+BUFFER_FNS(Meta, meta)
+BUFFER_FNS(Prio, prio)
#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)
@@ -181,6 +185,7 @@ void ll_rw_block(int, int, struct buffer_head * bh[]);
int sync_dirty_buffer(struct buffer_head *bh);
int __sync_dirty_buffer(struct buffer_head *bh, int rw);
void write_dirty_buffer(struct buffer_head *bh, int rw);
+int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags);
int submit_bh(int, struct buffer_head *);
void write_boundary_block(struct block_device *bdev,
sector_t bblock, unsigned blocksize);
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 98503b792369..d9a4f7f40f32 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -35,6 +35,7 @@ struct cpu_vfs_cap_data {
#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t))
+struct file;
struct inode;
struct dentry;
struct user_namespace;
@@ -211,6 +212,7 @@ extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool nsown_capable(int cap);
extern bool inode_capable(const struct inode *inode, int cap);
+extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
/* audit system wants to get cap info from files as well */
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 68f2157b71d4..3bff9ce09cf7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -19,6 +19,7 @@
#include <linux/idr.h>
#include <linux/workqueue.h>
#include <linux/xattr.h>
+#include <linux/fs.h>
#ifdef CONFIG_CGROUPS
@@ -30,10 +31,6 @@ struct css_id;
extern int cgroup_init_early(void);
extern int cgroup_init(void);
-extern void cgroup_lock(void);
-extern int cgroup_lock_is_held(void);
-extern bool cgroup_lock_live_group(struct cgroup *cgrp);
-extern void cgroup_unlock(void);
extern void cgroup_fork(struct task_struct *p);
extern void cgroup_post_fork(struct task_struct *p);
extern void cgroup_exit(struct task_struct *p, int run_callbacks);
@@ -44,14 +41,25 @@ extern void cgroup_unload_subsys(struct cgroup_subsys *ss);
extern int proc_cgroup_show(struct seq_file *, void *);
-/* Define the enumeration of all builtin cgroup subsystems */
+/*
+ * Define the enumeration of all cgroup subsystems.
+ *
+ * We define ids for builtin subsystems and then modular ones.
+ */
#define SUBSYS(_x) _x ## _subsys_id,
-#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
enum cgroup_subsys_id {
+#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
#include <linux/cgroup_subsys.h>
+#undef IS_SUBSYS_ENABLED
+ CGROUP_BUILTIN_SUBSYS_COUNT,
+
+ __CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1,
+
+#define IS_SUBSYS_ENABLED(option) IS_MODULE(option)
+#include <linux/cgroup_subsys.h>
+#undef IS_SUBSYS_ENABLED
CGROUP_SUBSYS_COUNT,
};
-#undef IS_SUBSYS_ENABLED
#undef SUBSYS
/* Per-subsystem/per-cgroup state maintained by the system. */
@@ -148,6 +156,13 @@ enum {
* specified at mount time and thus is implemented here.
*/
CGRP_CPUSET_CLONE_CHILDREN,
+ /* see the comment above CGRP_ROOT_SANE_BEHAVIOR for details */
+ CGRP_SANE_BEHAVIOR,
+};
+
+struct cgroup_name {
+ struct rcu_head rcu_head;
+ char name[];
};
struct cgroup {
@@ -172,11 +187,23 @@ struct cgroup {
struct cgroup *parent; /* my parent */
struct dentry *dentry; /* cgroup fs entry, RCU protected */
+ /*
+ * This is a copy of dentry->d_name, and it's needed because
+ * we can't use dentry->d_name in cgroup_path().
+ *
+ * You must acquire rcu_read_lock() to access cgrp->name, and
+ * the only place that can change it is rename(), which is
+ * protected by parent dir's i_mutex.
+ *
+ * Normally you should use cgroup_name() wrapper rather than
+ * access it directly.
+ */
+ struct cgroup_name __rcu *name;
+
/* Private pointers for each registered subsystem */
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
struct cgroupfs_root *root;
- struct cgroup *top_cgroup;
/*
* List of cg_cgroup_links pointing at css_sets with
@@ -213,6 +240,96 @@ struct cgroup {
struct simple_xattrs xattrs;
};
+#define MAX_CGROUP_ROOT_NAMELEN 64
+
+/* cgroupfs_root->flags */
+enum {
+ /*
+ * Unfortunately, cgroup core and various controllers are riddled
+ * with idiosyncrasies and pointless options. The following flag,
+ * when set, will force sane behavior - some options are forced on,
+ * others are disallowed, and some controllers will change their
+ * hierarchical or other behaviors.
+ *
+ * The set of behaviors affected by this flag are still being
+ * determined and developed and the mount option for this flag is
+ * prefixed with __DEVEL__. The prefix will be dropped once we
+ * reach the point where all behaviors are compatible with the
+ * planned unified hierarchy, which will automatically turn on this
+ * flag.
+ *
+ * The followings are the behaviors currently affected this flag.
+ *
+ * - Mount options "noprefix" and "clone_children" are disallowed.
+ * Also, cgroupfs file cgroup.clone_children is not created.
+ *
+ * - When mounting an existing superblock, mount options should
+ * match.
+ *
+ * - Remount is disallowed.
+ *
+ * - memcg: use_hierarchy is on by default and the cgroup file for
+ * the flag is not created.
+ *
+ * The followings are planned changes.
+ *
+ * - release_agent will be disallowed once replacement notification
+ * mechanism is implemented.
+ */
+ CGRP_ROOT_SANE_BEHAVIOR = (1 << 0),
+
+ CGRP_ROOT_NOPREFIX = (1 << 1), /* mounted subsystems have no named prefix */
+ CGRP_ROOT_XATTR = (1 << 2), /* supports extended attributes */
+};
+
+/*
+ * A cgroupfs_root represents the root of a cgroup hierarchy, and may be
+ * associated with a superblock to form an active hierarchy. This is
+ * internal to cgroup core. Don't access directly from controllers.
+ */
+struct cgroupfs_root {
+ struct super_block *sb;
+
+ /*
+ * The bitmask of subsystems intended to be attached to this
+ * hierarchy
+ */
+ unsigned long subsys_mask;
+
+ /* Unique id for this hierarchy. */
+ int hierarchy_id;
+
+ /* The bitmask of subsystems currently attached to this hierarchy */
+ unsigned long actual_subsys_mask;
+
+ /* A list running through the attached subsystems */
+ struct list_head subsys_list;
+
+ /* The root cgroup for this hierarchy */
+ struct cgroup top_cgroup;
+
+ /* Tracks how many cgroups are currently defined in hierarchy.*/
+ int number_of_cgroups;
+
+ /* A list running through the active hierarchies */
+ struct list_head root_list;
+
+ /* All cgroups on this root, cgroup_mutex protected */
+ struct list_head allcg_list;
+
+ /* Hierarchy-specific flags */
+ unsigned long flags;
+
+ /* IDs for cgroups in this hierarchy */
+ struct ida cgroup_ida;
+
+ /* The path to use for release notifications. */
+ char release_agent_path[PATH_MAX];
+
+ /* The name for this hierarchy - may be empty */
+ char name[MAX_CGROUP_ROOT_NAMELEN];
+};
+
/*
* A css_set is a structure holding pointers to a set of
* cgroup_subsys_state objects. This saves space in the task struct
@@ -278,6 +395,7 @@ struct cgroup_map_cb {
/* cftype->flags */
#define CFTYPE_ONLY_ON_ROOT (1U << 0) /* only create on root cg */
#define CFTYPE_NOT_ON_ROOT (1U << 1) /* don't create on root cg */
+#define CFTYPE_INSANE (1U << 2) /* don't create if sane_behavior */
#define MAX_CFTYPE_NAME 64
@@ -304,9 +422,6 @@ struct cftype {
/* CFTYPE_* flags */
unsigned int flags;
- /* file xattrs */
- struct simple_xattrs xattrs;
-
int (*open)(struct inode *inode, struct file *file);
ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
struct file *file,
@@ -404,18 +519,31 @@ struct cgroup_scanner {
void *data;
};
+/*
+ * See the comment above CGRP_ROOT_SANE_BEHAVIOR for details. This
+ * function can be called as long as @cgrp is accessible.
+ */
+static inline bool cgroup_sane_behavior(const struct cgroup *cgrp)
+{
+ return cgrp->root->flags & CGRP_ROOT_SANE_BEHAVIOR;
+}
+
+/* Caller should hold rcu_read_lock() */
+static inline const char *cgroup_name(const struct cgroup *cgrp)
+{
+ return rcu_dereference(cgrp->name)->name;
+}
+
int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_is_removed(const struct cgroup *cgrp);
+bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor);
int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen);
int cgroup_task_count(const struct cgroup *cgrp);
-/* Return true if cgrp is a descendant of the task's cgroup */
-int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task);
-
/*
* Control Group taskset, used to pass around set of tasks to cgroup_subsys
* methods.
@@ -458,7 +586,6 @@ struct cgroup_subsys {
void (*bind)(struct cgroup *root);
int subsys_id;
- int active;
int disabled;
int early_init;
/*
@@ -523,10 +650,16 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(
* rcu_dereference_check() conditions, such as locks used during the
* cgroup_subsys::attach() methods.
*/
+#ifdef CONFIG_PROVE_RCU
+extern struct mutex cgroup_mutex;
#define task_subsys_state_check(task, subsys_id, __c) \
- rcu_dereference_check(task->cgroups->subsys[subsys_id], \
- lockdep_is_held(&task->alloc_lock) || \
- cgroup_lock_is_held() || (__c))
+ rcu_dereference_check((task)->cgroups->subsys[(subsys_id)], \
+ lockdep_is_held(&(task)->alloc_lock) || \
+ lockdep_is_held(&cgroup_mutex) || (__c))
+#else
+#define task_subsys_state_check(task, subsys_id, __c) \
+ rcu_dereference((task)->cgroups->subsys[(subsys_id)])
+#endif
static inline struct cgroup_subsys_state *
task_subsys_state(struct task_struct *task, int subsys_id)
@@ -661,8 +794,8 @@ struct task_struct *cgroup_iter_next(struct cgroup *cgrp,
struct cgroup_iter *it);
void cgroup_iter_end(struct cgroup *cgrp, struct cgroup_iter *it);
int cgroup_scan_tasks(struct cgroup_scanner *scan);
-int cgroup_attach_task(struct cgroup *, struct task_struct *);
int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
+int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
/*
* CSS ID is ID for cgroup_subsys_state structs under subsys. This only works
@@ -687,13 +820,6 @@ void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css);
struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id);
-/*
- * Get a cgroup whose id is greater than or equal to id under tree of root.
- * Returning a cgroup_subsys_state or NULL.
- */
-struct cgroup_subsys_state *css_get_next(struct cgroup_subsys *ss, int id,
- struct cgroup_subsys_state *root, int *foundid);
-
/* Returns true if root is ancestor of cg */
bool css_is_ancestor(struct cgroup_subsys_state *cg,
const struct cgroup_subsys_state *root);
diff --git a/include/linux/cleancache.h b/include/linux/cleancache.h
index 42e55deee757..4ce9056b31a8 100644
--- a/include/linux/cleancache.h
+++ b/include/linux/cleancache.h
@@ -33,7 +33,7 @@ struct cleancache_ops {
void (*invalidate_fs)(int);
};
-extern struct cleancache_ops
+extern struct cleancache_ops *
cleancache_register_ops(struct cleancache_ops *ops);
extern void __cleancache_init_fs(struct super_block *);
extern void __cleancache_init_shared_fs(char *, struct super_block *);
@@ -42,9 +42,9 @@ extern void __cleancache_put_page(struct page *);
extern void __cleancache_invalidate_page(struct address_space *, struct page *);
extern void __cleancache_invalidate_inode(struct address_space *);
extern void __cleancache_invalidate_fs(struct super_block *);
-extern int cleancache_enabled;
#ifdef CONFIG_CLEANCACHE
+#define cleancache_enabled (1)
static inline bool cleancache_fs_enabled(struct page *page)
{
return page->mapping->host->i_sb->cleancache_poolid >= 0;
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index 9c7f5807824b..dd7adff76e81 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -152,7 +152,7 @@ struct clk {
}, \
.reg = _reg, \
.shift = _shift, \
- .width = _width, \
+ .mask = BIT(_width) - 1, \
.flags = _mux_flags, \
.lock = _lock, \
}; \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7f197d7addb0..11860985fecb 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -45,6 +45,14 @@ struct clk_hw;
* undo any work done in the @prepare callback. Called with
* prepare_lock held.
*
+ * @is_prepared: Queries the hardware to determine if the clock is prepared.
+ * This function is allowed to sleep. Optional, if this op is not
+ * set then the prepare count will be used.
+ *
+ * @unprepare_unused: Unprepare the clock atomically. Only called from
+ * clk_disable_unused for prepare clocks with special needs.
+ * Called with prepare mutex held. This function may sleep.
+ *
* @enable: Enable the clock atomically. This must not return until the
* clock is generating a valid clock signal, usable by consumer
* devices. Called with enable_lock held. This function must not
@@ -108,6 +116,8 @@ struct clk_hw;
struct clk_ops {
int (*prepare)(struct clk_hw *hw);
void (*unprepare)(struct clk_hw *hw);
+ int (*is_prepared)(struct clk_hw *hw);
+ void (*unprepare_unused)(struct clk_hw *hw);
int (*enable)(struct clk_hw *hw);
void (*disable)(struct clk_hw *hw);
int (*is_enabled)(struct clk_hw *hw);
@@ -239,9 +249,14 @@ struct clk_div_table {
* CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the
* register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is
* the raw value read from the register, with the value of zero considered
- * invalid
+ * invalid, unless CLK_DIVIDER_ALLOW_ZERO is set.
* CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from
* the hardware register
+ * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have
+ * CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor.
+ * Some hardware implementations gracefully handle this case and allow a
+ * zero divisor by not modifying their input clock
+ * (divide by one / bypass).
*/
struct clk_divider {
struct clk_hw hw;
@@ -255,6 +270,7 @@ struct clk_divider {
#define CLK_DIVIDER_ONE_BASED BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
extern const struct clk_ops clk_divider_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,
@@ -274,7 +290,7 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
* @reg: register controlling multiplexer
* @shift: shift to multiplexer bit field
* @width: width of mutliplexer bit field
- * @num_clks: number of parent clocks
+ * @flags: hardware-specific flags
* @lock: register lock
*
* Clock with multiple selectable parents. Implements .get_parent, .set_parent
@@ -287,8 +303,9 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
struct clk_mux {
struct clk_hw hw;
void __iomem *reg;
+ u32 *table;
+ u32 mask;
u8 shift;
- u8 width;
u8 flags;
spinlock_t *lock;
};
@@ -297,11 +314,19 @@ struct clk_mux {
#define CLK_MUX_INDEX_BIT BIT(1)
extern const struct clk_ops clk_mux_ops;
+
struct clk *clk_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock);
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
+ const char **parent_names, u8 num_parents, unsigned long flags,
+ void __iomem *reg, u8 shift, u32 mask,
+ u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+
+void of_fixed_factor_clk_setup(struct device_node *node);
+
/**
* struct clk_fixed_factor - fixed multiplier and divider clock
*
@@ -325,6 +350,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
+/***
+ * struct clk_composite - aggregate clock of mux, divider and gate clocks
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @mux_hw: handle between composite and hardware-specific mux clock
+ * @rate_hw: handle between composite and hardware-specific rate clock
+ * @gate_hw: handle between composite and hardware-specific gate clock
+ * @mux_ops: clock ops for mux
+ * @rate_ops: clock ops for rate
+ * @gate_ops: clock ops for gate
+ */
+struct clk_composite {
+ struct clk_hw hw;
+ struct clk_ops ops;
+
+ struct clk_hw *mux_hw;
+ struct clk_hw *rate_hw;
+ struct clk_hw *gate_hw;
+
+ const struct clk_ops *mux_ops;
+ const struct clk_ops *rate_ops;
+ const struct clk_ops *gate_ops;
+};
+
+struct clk *clk_register_composite(struct device *dev, const char *name,
+ const char **parent_names, int num_parents,
+ struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
+ struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
+ struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
+ unsigned long flags);
+
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
@@ -351,6 +407,7 @@ unsigned int __clk_get_enable_count(struct clk *clk);
unsigned int __clk_get_prepare_count(struct clk *clk);
unsigned long __clk_get_rate(struct clk *clk);
unsigned long __clk_get_flags(struct clk *clk);
+bool __clk_is_prepared(struct clk *clk);
bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index b3ac22d0fc1f..9a6d04524b1a 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -28,16 +28,16 @@ struct clk;
* PRE_RATE_CHANGE - called immediately before the clk rate is changed,
* to indicate that the rate change will proceed. Drivers must
* immediately terminate any operations that will be affected by the
- * rate change. Callbacks may either return NOTIFY_DONE or
- * NOTIFY_STOP.
+ * rate change. Callbacks may either return NOTIFY_DONE, NOTIFY_OK,
+ * NOTIFY_STOP or NOTIFY_BAD.
*
* ABORT_RATE_CHANGE: called if the rate change failed for some reason
* after PRE_RATE_CHANGE. In this case, all registered notifiers on
* the clk will be called with ABORT_RATE_CHANGE. Callbacks must
- * always return NOTIFY_DONE.
+ * always return NOTIFY_DONE or NOTIFY_OK.
*
* POST_RATE_CHANGE - called after the clk rate change has successfully
- * completed. Callbacks must always return NOTIFY_DONE.
+ * completed. Callbacks must always return NOTIFY_DONE or NOTIFY_OK.
*
*/
#define PRE_RATE_CHANGE BIT(0)
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
new file mode 100644
index 000000000000..e074fdd5a236
--- /dev/null
+++ b/include/linux/clk/sunxi.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_CLK_SUNXI_H_
+#define __LINUX_CLK_SUNXI_H_
+
+void __init sunxi_init_clocks(void);
+
+#endif
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 66346521cb65..963d71431388 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -8,6 +8,20 @@
#ifndef _LINUX_CLOCKCHIPS_H
#define _LINUX_CLOCKCHIPS_H
+/* Clock event notification values */
+enum clock_event_nofitiers {
+ CLOCK_EVT_NOTIFY_ADD,
+ CLOCK_EVT_NOTIFY_BROADCAST_ON,
+ CLOCK_EVT_NOTIFY_BROADCAST_OFF,
+ CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
+ CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
+ CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
+ CLOCK_EVT_NOTIFY_SUSPEND,
+ CLOCK_EVT_NOTIFY_RESUME,
+ CLOCK_EVT_NOTIFY_CPU_DYING,
+ CLOCK_EVT_NOTIFY_CPU_DEAD,
+};
+
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
#include <linux/clocksource.h>
@@ -26,20 +40,6 @@ enum clock_event_mode {
CLOCK_EVT_MODE_RESUME,
};
-/* Clock event notification values */
-enum clock_event_nofitiers {
- CLOCK_EVT_NOTIFY_ADD,
- CLOCK_EVT_NOTIFY_BROADCAST_ON,
- CLOCK_EVT_NOTIFY_BROADCAST_OFF,
- CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
- CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
- CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
- CLOCK_EVT_NOTIFY_SUSPEND,
- CLOCK_EVT_NOTIFY_RESUME,
- CLOCK_EVT_NOTIFY_CPU_DYING,
- CLOCK_EVT_NOTIFY_CPU_DEAD,
-};
-
/*
* Clock event features
*/
@@ -55,6 +55,11 @@ enum clock_event_nofitiers {
#define CLOCK_EVT_FEAT_C3STOP 0x000008
#define CLOCK_EVT_FEAT_DUMMY 0x000010
+/*
+ * Core shall set the interrupt affinity dynamically in broadcast mode
+ */
+#define CLOCK_EVT_FEAT_DYNIRQ 0x000020
+
/**
* struct clock_event_device - clock event device descriptor
* @event_handler: Assigned by the framework to be called by the low
@@ -170,10 +175,16 @@ extern void tick_broadcast(const struct cpumask *mask);
extern int tick_receive_broadcast(void);
#endif
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
+extern int tick_check_broadcast_expired(void);
+#else
+static inline int tick_check_broadcast_expired(void) { return 0; }
+#endif
+
#ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void clockevents_notify(unsigned long reason, void *arg);
#else
-# define clockevents_notify(reason, arg) do { } while (0)
+static inline void clockevents_notify(unsigned long reason, void *arg) {}
#endif
#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
@@ -181,7 +192,8 @@ extern void clockevents_notify(unsigned long reason, void *arg);
static inline void clockevents_suspend(void) {}
static inline void clockevents_resume(void) {}
-#define clockevents_notify(reason, arg) do { } while (0)
+static inline void clockevents_notify(unsigned long reason, void *arg) {}
+static inline int tick_check_broadcast_expired(void) { return 0; }
#endif
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 27cfda427dd9..aa7032c7238f 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -206,6 +206,7 @@ struct clocksource {
#define CLOCK_SOURCE_WATCHDOG 0x10
#define CLOCK_SOURCE_VALID_FOR_HRES 0x20
#define CLOCK_SOURCE_UNSTABLE 0x40
+#define CLOCK_SOURCE_SUSPEND_NONSTOP 0x80
/* simplify initialization of mask field */
#define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1)
diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
index 2c1bc1ea04ee..1d5b02a96c46 100644
--- a/include/linux/cn_proc.h
+++ b/include/linux/cn_proc.h
@@ -26,6 +26,7 @@ void proc_id_connector(struct task_struct *task, int which_id);
void proc_sid_connector(struct task_struct *task);
void proc_ptrace_connector(struct task_struct *task, int which_id);
void proc_comm_connector(struct task_struct *task);
+void proc_coredump_connector(struct task_struct *task);
void proc_exit_connector(struct task_struct *task);
#else
static inline void proc_fork_connector(struct task_struct *task)
@@ -48,6 +49,9 @@ static inline void proc_ptrace_connector(struct task_struct *task,
int ptrace_id)
{}
+static inline void proc_coredump_connector(struct task_struct *task)
+{}
+
static inline void proc_exit_connector(struct task_struct *task)
{}
#endif /* CONFIG_PROC_EVENTS */
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 76a87fb57ac2..d53c35352ea9 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -27,12 +27,6 @@
#define __SC_DELOUSE(t,v) ((t)(unsigned long)(v))
#endif
-#define __SC_CCAST1(t1, a1) __SC_DELOUSE(t1,a1)
-#define __SC_CCAST2(t2, a2, ...) __SC_DELOUSE(t2,a2), __SC_CCAST1(__VA_ARGS__)
-#define __SC_CCAST3(t3, a3, ...) __SC_DELOUSE(t3,a3), __SC_CCAST2(__VA_ARGS__)
-#define __SC_CCAST4(t4, a4, ...) __SC_DELOUSE(t4,a4), __SC_CCAST3(__VA_ARGS__)
-#define __SC_CCAST5(t5, a5, ...) __SC_DELOUSE(t5,a5), __SC_CCAST4(__VA_ARGS__)
-#define __SC_CCAST6(t6, a6, ...) __SC_DELOUSE(t6,a6), __SC_CCAST5(__VA_ARGS__)
#define COMPAT_SYSCALL_DEFINE1(name, ...) \
COMPAT_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define COMPAT_SYSCALL_DEFINE2(name, ...) \
@@ -46,24 +40,15 @@
#define COMPAT_SYSCALL_DEFINE6(name, ...) \
COMPAT_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-
#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \
- asmlinkage long compat_sys##name(__SC_DECL##x(__VA_ARGS__)); \
- static inline long C_SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
- asmlinkage long compat_SyS##name(__SC_LONG##x(__VA_ARGS__)) \
+ asmlinkage long compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
+ static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
+ asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))\
{ \
- return (long) C_SYSC##name(__SC_CCAST##x(__VA_ARGS__)); \
+ return C_SYSC##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__)); \
} \
SYSCALL_ALIAS(compat_sys##name, compat_SyS##name); \
- static inline long C_SYSC##name(__SC_DECL##x(__VA_ARGS__))
-
-#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
-
-#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \
- asmlinkage long compat_sys##name(__SC_DECL##x(__VA_ARGS__))
-
-#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
+ static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#ifndef compat_user_stack_pointer
#define compat_user_stack_pointer() current_user_stack_pointer()
@@ -141,11 +126,11 @@ typedef struct {
} compat_sigset_t;
struct compat_sigaction {
-#ifndef __ARCH_HAS_ODD_SIGACTION
+#ifndef __ARCH_HAS_IRIX_SIGACTION
compat_uptr_t sa_handler;
compat_ulong_t sa_flags;
#else
- compat_ulong_t sa_flags;
+ compat_uint_t sa_flags;
compat_uptr_t sa_handler;
#endif
#ifdef __ARCH_HAS_SA_RESTORER
@@ -326,21 +311,13 @@ asmlinkage long
compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
compat_size_t __user *len_ptr);
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
-long compat_sys_semctl(int first, int second, int third, void __user *uptr);
-long compat_sys_msgsnd(int first, int second, int third, void __user *uptr);
-long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
- int version, void __user *uptr);
-long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
- void __user *uptr);
-#else
-long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
-long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
+asmlinkage long compat_sys_ipc(u32, int, int, u32, compat_uptr_t, u32);
+asmlinkage long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg);
+asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg);
+asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp,
compat_ssize_t msgsz, int msgflg);
-long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
+asmlinkage long compat_sys_msgrcv(int msqid, compat_uptr_t msgp,
compat_ssize_t msgsz, long msgtyp, int msgflg);
-long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg);
-#endif
long compat_sys_msgctl(int first, int second, void __user *uptr);
long compat_sys_shmctl(int first, int second, void __user *uptr);
long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
@@ -444,13 +421,13 @@ extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
compat_long_t addr, compat_long_t data);
+asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, size_t);
/*
* epoll (fs/eventpoll.c) compat bits follow ...
*/
-struct epoll_event;
-#define compat_epoll_event epoll_event
+struct epoll_event; /* fortunately, this one is fixed-layout */
asmlinkage long compat_sys_epoll_pwait(int epfd,
- struct compat_epoll_event __user *events,
+ struct epoll_event __user *events,
int maxevents, int timeout,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
@@ -685,6 +662,8 @@ asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid,
asmlinkage long compat_sys_sendfile(int out_fd, int in_fd,
compat_off_t __user *offset, compat_size_t count);
+asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd,
+ compat_loff_t __user *offset, compat_size_t count);
asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr,
compat_stack_t __user *uoss_ptr);
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 68b162d92254..842de225055f 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -13,7 +13,7 @@
#define __must_check __attribute__((warn_unused_result))
#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
-#if GCC_VERSION >= 40100
+#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 10b8f23fab0f..92669cd182a6 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -351,4 +351,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
*/
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+/* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */
+#ifdef CONFIG_KPROBES
+# define __kprobes __attribute__((__section__(".kprobes.text")))
+#else
+# define __kprobes
+#endif
#endif /* __LINUX_COMPILER_H */
diff --git a/include/linux/console.h b/include/linux/console.h
index 29680a8cda99..73bab0f58af5 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -141,6 +141,7 @@ struct console {
for (con = console_drivers; con != NULL; con = con->next)
extern int console_set_on_cmdline;
+extern struct console *early_console;
extern int add_preferred_console(char *name, int idx, char *options);
extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options);
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h
index b28d161c1091..365f4a61bf04 100644
--- a/include/linux/context_tracking.h
+++ b/include/linux/context_tracking.h
@@ -1,9 +1,9 @@
#ifndef _LINUX_CONTEXT_TRACKING_H
#define _LINUX_CONTEXT_TRACKING_H
-#ifdef CONFIG_CONTEXT_TRACKING
#include <linux/sched.h>
#include <linux/percpu.h>
+#include <asm/ptrace.h>
struct context_tracking {
/*
@@ -13,12 +13,13 @@ struct context_tracking {
* may be further optimized using static keys.
*/
bool active;
- enum {
+ enum ctx_state {
IN_KERNEL = 0,
IN_USER,
} state;
};
+#ifdef CONFIG_CONTEXT_TRACKING
DECLARE_PER_CPU(struct context_tracking, context_tracking);
static inline bool context_tracking_in_user(void)
@@ -33,12 +34,31 @@ static inline bool context_tracking_active(void)
extern void user_enter(void);
extern void user_exit(void);
+
+static inline enum ctx_state exception_enter(void)
+{
+ enum ctx_state prev_ctx;
+
+ prev_ctx = this_cpu_read(context_tracking.state);
+ user_exit();
+
+ return prev_ctx;
+}
+
+static inline void exception_exit(enum ctx_state prev_ctx)
+{
+ if (prev_ctx == IN_USER)
+ user_enter();
+}
+
extern void context_tracking_task_switch(struct task_struct *prev,
struct task_struct *next);
#else
static inline bool context_tracking_in_user(void) { return false; }
static inline void user_enter(void) { }
static inline void user_exit(void) { }
+static inline enum ctx_state exception_enter(void) { return 0; }
+static inline void exception_exit(enum ctx_state prev_ctx) { }
static inline void context_tracking_task_switch(struct task_struct *prev,
struct task_struct *next) { }
#endif /* !CONFIG_CONTEXT_TRACKING */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ce7a074f2519..c6f6e0839b61 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -212,4 +212,20 @@ static inline int disable_nonboot_cpus(void) { return 0; }
static inline void enable_nonboot_cpus(void) {}
#endif /* !CONFIG_PM_SLEEP_SMP */
+enum cpuhp_state {
+ CPUHP_OFFLINE,
+ CPUHP_ONLINE,
+};
+
+void cpu_startup_entry(enum cpuhp_state state);
+void cpu_idle(void);
+
+void cpu_idle_poll_ctrl(bool enable);
+
+void arch_cpu_idle(void);
+void arch_cpu_idle_prepare(void);
+void arch_cpu_idle_enter(void);
+void arch_cpu_idle_exit(void);
+void arch_cpu_idle_dead(void);
+
#endif /* _LINUX_CPU_H_ */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index a22944ca0526..037d36ae63e5 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -106,6 +106,7 @@ struct cpufreq_policy {
* governors are used */
unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
+ void *governor_data;
struct work_struct update; /* if update_policy() needs to be
* called, but you're in IRQ context */
@@ -178,9 +179,11 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mu
* CPUFREQ GOVERNORS *
*********************************************************************/
-#define CPUFREQ_GOV_START 1
-#define CPUFREQ_GOV_STOP 2
-#define CPUFREQ_GOV_LIMITS 3
+#define CPUFREQ_GOV_START 1
+#define CPUFREQ_GOV_STOP 2
+#define CPUFREQ_GOV_LIMITS 3
+#define CPUFREQ_GOV_POLICY_INIT 4
+#define CPUFREQ_GOV_POLICY_EXIT 5
struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN];
@@ -229,6 +232,13 @@ struct cpufreq_driver {
struct module *owner;
char name[CPUFREQ_NAME_LEN];
u8 flags;
+ /*
+ * This should be set by platforms having multiple clock-domains, i.e.
+ * supporting multiple policies. With this sysfs directories of governor
+ * would be created in cpu/cpu<num>/cpufreq/ directory and so they can
+ * use the same governor with different tunables for different clusters.
+ */
+ bool have_governor_per_policy;
/* needed by all drivers */
int (*init) (struct cpufreq_policy *policy);
@@ -268,8 +278,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
-void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
-
+void cpufreq_notify_transition(struct cpufreq_policy *policy,
+ struct cpufreq_freqs *freqs, unsigned int state);
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max)
{
@@ -329,6 +339,7 @@ const char *cpufreq_get_current_driver(void);
*********************************************************************/
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
+bool have_governor_per_policy(void);
#ifdef CONFIG_CPU_FREQ
/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 480c14dc1ddd..3c86faa59798 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -57,6 +57,7 @@ struct cpuidle_state {
/* Idle State Flags */
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
#define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */
+#define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
@@ -104,8 +105,8 @@ struct cpuidle_driver {
struct module *owner;
int refcnt;
- /* set to 1 to use the core cpuidle time keeping (for all states). */
- unsigned int en_core_tk_irqen:1;
+ /* used by the cpuidle framework to setup the broadcast timer */
+ unsigned int bctimer:1;
/* states array must be ordered in decreasing power consumption */
struct cpuidle_state states[CPUIDLE_STATE_MAX];
int state_count;
@@ -122,17 +123,15 @@ extern void cpuidle_driver_unref(void);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
-
+extern int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus);
+extern void cpuidle_unregister(struct cpuidle_driver *drv);
extern void cpuidle_pause_and_lock(void);
extern void cpuidle_resume_and_unlock(void);
extern void cpuidle_pause(void);
extern void cpuidle_resume(void);
extern int cpuidle_enable_device(struct cpuidle_device *dev);
extern void cpuidle_disable_device(struct cpuidle_device *dev);
-extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index,
- int (*enter)(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index));
extern int cpuidle_play_dead(void);
extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev);
@@ -151,7 +150,10 @@ static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
static inline int cpuidle_register_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
-
+static inline int cpuidle_register(struct cpuidle_driver *drv,
+ const struct cpumask *const coupled_cpus)
+{return -ENODEV; }
+static inline void cpuidle_unregister(struct cpuidle_driver *drv) { }
static inline void cpuidle_pause_and_lock(void) { }
static inline void cpuidle_resume_and_unlock(void) { }
static inline void cpuidle_pause(void) { }
@@ -159,11 +161,6 @@ static inline void cpuidle_resume(void) { }
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
-static inline int cpuidle_wrap_enter(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index,
- int (*enter)(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index))
-{ return -ENODEV; }
static inline int cpuidle_play_dead(void) {return -ENODEV; }
#endif
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 032560295fcb..d08e4d2a9b92 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -591,6 +591,21 @@ static inline int cpulist_scnprintf(char *buf, int len,
}
/**
+ * cpumask_parse - extract a cpumask from from a string
+ * @buf: the buffer to extract from
+ * @dstp: the cpumask to set.
+ *
+ * Returns -errno, or 0 for success.
+ */
+static inline int cpumask_parse(const char *buf, struct cpumask *dstp)
+{
+ char *nl = strchr(buf, '\n');
+ int len = nl ? nl - buf : strlen(buf);
+
+ return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
+}
+
+/**
* cpulist_parse - extract a cpumask from a user string of ranges
* @buf: the buffer to extract from
* @dstp: the cpumask to set.
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 22b637c5ecae..cc1b01cf2035 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/cpumask.h>
#include <linux/nodemask.h>
-#include <linux/cgroup.h>
#include <linux/mm.h>
#ifdef CONFIG_CPUSETS
diff --git a/include/linux/ctype.h b/include/linux/ctype.h
index 8acfe312f947..653589e3e30e 100644
--- a/include/linux/ctype.h
+++ b/include/linux/ctype.h
@@ -61,4 +61,10 @@ static inline char _tolower(const char c)
return c | 0x20;
}
+/* Fast check for octal digit */
+static inline int isodigit(const char c)
+{
+ return c >= '0' && c <= '7';
+}
+
#endif
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index a975de1ff59f..21ca773f77bf 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -27,7 +27,7 @@ extern int debug_locks_off(void);
\
if (!oops_in_progress && unlikely(c)) { \
if (debug_locks_off() && !debug_locks_silent) \
- WARN_ON(1); \
+ WARN(1, "DEBUG_LOCKS_WARN_ON(%s)", #c); \
__ret = 1; \
} \
__ret; \
@@ -51,7 +51,7 @@ struct task_struct;
extern void debug_show_all_locks(void);
extern void debug_show_held_locks(struct task_struct *task);
extern void debug_check_no_locks_freed(const void *from, unsigned long len);
-extern void debug_check_no_locks_held(void);
+extern void debug_check_no_locks_held(struct task_struct *task);
#else
static inline void debug_show_all_locks(void)
{
@@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len)
}
static inline void
-debug_check_no_locks_held(void)
+debug_check_no_locks_held(struct task_struct *task)
{
}
#endif
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index e83ef39b3bea..fe8c4476f7e4 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -213,7 +213,7 @@ struct devfreq_simple_ondemand_data {
#endif
#else /* !CONFIG_PM_DEVFREQ */
-static struct devfreq *devfreq_add_device(struct device *dev,
+static inline struct devfreq *devfreq_add_device(struct device *dev,
struct devfreq_dev_profile *profile,
const char *governor_name,
void *data)
@@ -221,34 +221,34 @@ static struct devfreq *devfreq_add_device(struct device *dev,
return NULL;
}
-static int devfreq_remove_device(struct devfreq *devfreq)
+static inline int devfreq_remove_device(struct devfreq *devfreq)
{
return 0;
}
-static int devfreq_suspend_device(struct devfreq *devfreq)
+static inline int devfreq_suspend_device(struct devfreq *devfreq)
{
return 0;
}
-static int devfreq_resume_device(struct devfreq *devfreq)
+static inline int devfreq_resume_device(struct devfreq *devfreq)
{
return 0;
}
-static struct opp *devfreq_recommended_opp(struct device *dev,
+static inline struct opp *devfreq_recommended_opp(struct device *dev,
unsigned long *freq, u32 flags)
{
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
-static int devfreq_register_opp_notifier(struct device *dev,
+static inline int devfreq_register_opp_notifier(struct device *dev,
struct devfreq *devfreq)
{
return -EINVAL;
}
-static int devfreq_unregister_opp_notifier(struct device *dev,
+static inline int devfreq_unregister_opp_notifier(struct device *dev,
struct devfreq *devfreq)
{
return -EINVAL;
diff --git a/include/linux/device.h b/include/linux/device.h
index 9d6464ea99c6..c0a126125325 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -25,6 +25,7 @@
#include <linux/pm.h>
#include <linux/atomic.h>
#include <linux/ratelimit.h>
+#include <linux/uidgid.h>
#include <asm/device.h>
struct device;
@@ -111,17 +112,11 @@ struct bus_type {
struct iommu_ops *iommu_ops;
struct subsys_private *p;
+ struct lock_class_key lock_key;
};
-/* This is a #define to keep the compiler from merging different
- * instances of the __key variable */
-#define bus_register(subsys) \
-({ \
- static struct lock_class_key __key; \
- __bus_register(subsys, &__key); \
-})
-extern int __must_check __bus_register(struct bus_type *bus,
- struct lock_class_key *key);
+extern int __must_check bus_register(struct bus_type *bus);
+
extern void bus_unregister(struct bus_type *bus);
extern int __must_check bus_rescan_devices(struct bus_type *bus);
@@ -302,6 +297,8 @@ void subsys_interface_unregister(struct subsys_interface *sif);
int subsys_system_register(struct bus_type *subsys,
const struct attribute_group **groups);
+int subsys_virtual_register(struct bus_type *subsys,
+ const struct attribute_group **groups);
/**
* struct class - device classes
@@ -471,7 +468,8 @@ struct device_type {
const char *name;
const struct attribute_group **groups;
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
- char *(*devnode)(struct device *dev, umode_t *mode);
+ char *(*devnode)(struct device *dev, umode_t *mode,
+ kuid_t *uid, kgid_t *gid);
void (*release)(struct device *dev);
const struct dev_pm_ops *pm;
@@ -578,6 +576,10 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res);
void __iomem *devm_request_and_ioremap(struct device *dev,
struct resource *res);
+/* allows to add/remove a custom action to devres stack */
+int devm_add_action(struct device *dev, void (*action)(void *), void *data);
+void devm_remove_action(struct device *dev, void (*action)(void *), void *data);
+
struct device_dma_parameters {
/*
* a low level driver may set these to teach IOMMU code about
@@ -849,7 +851,8 @@ extern int device_rename(struct device *dev, const char *new_name);
extern int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
extern const char *device_get_devnode(struct device *dev,
- umode_t *mode, const char **tmp);
+ umode_t *mode, kuid_t *uid, kgid_t *gid,
+ const char **tmp);
extern void *dev_get_drvdata(const struct device *dev);
extern int dev_set_drvdata(struct device *dev, void *data);
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index 9978b614a1aa..dfac5ed31120 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -112,6 +112,8 @@ struct dma_buf_ops {
* @file: file pointer used for sharing buffers across, and for refcounting.
* @attachments: list of dma_buf_attachment that denotes all devices attached.
* @ops: dma_buf_ops associated with this buffer object.
+ * @exp_name: name of the exporter; useful for debugging.
+ * @list_node: node for dma_buf accounting and debugging.
* @priv: exporter specific private data for this buffer object.
*/
struct dma_buf {
@@ -123,6 +125,8 @@ struct dma_buf {
struct mutex lock;
unsigned vmapping_counter;
void *vmap_ptr;
+ const char *exp_name;
+ struct list_head list_node;
void *priv;
};
@@ -162,8 +166,13 @@ struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf,
struct device *dev);
void dma_buf_detach(struct dma_buf *dmabuf,
struct dma_buf_attachment *dmabuf_attach);
-struct dma_buf *dma_buf_export(void *priv, const struct dma_buf_ops *ops,
- size_t size, int flags);
+
+struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
+ size_t size, int flags, const char *);
+
+#define dma_buf_export(priv, ops, size, flags) \
+ dma_buf_export_named(priv, ops, size, flags, __FILE__)
+
int dma_buf_fd(struct dma_buf *dmabuf, int flags);
struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dmabuf);
@@ -185,5 +194,6 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *,
unsigned long);
void *dma_buf_vmap(struct dma_buf *);
void dma_buf_vunmap(struct dma_buf *, void *vaddr);
-
+int dma_buf_debugfs_create_file(const char *name,
+ int (*write)(struct seq_file *));
#endif /* __DMA_BUF_H__ */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index f156cca25ad0..b6eb7a05d58e 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -99,6 +99,7 @@ extern const char * dmi_get_system_info(int field);
extern const struct dmi_device * dmi_find_device(int type, const char *name,
const struct dmi_device *from);
extern void dmi_scan_machine(void);
+extern void dmi_set_dump_stack_arch_desc(void);
extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
extern int dmi_name_in_vendors(const char *str);
extern int dmi_name_in_serial(const char *str);
@@ -114,6 +115,7 @@ static inline const char * dmi_get_system_info(int field) { return NULL; }
static inline const struct dmi_device * dmi_find_device(int type, const char *name,
const struct dmi_device *from) { return NULL; }
static inline void dmi_scan_machine(void) { return; }
+static inline void dmi_set_dump_stack_arch_desc(void) { }
static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp)
{
if (yearp)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 9bf2f1fcae27..2bc0ad78d058 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -333,6 +333,7 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
unsigned long count,
u64 *max_size,
int *reset_type);
+typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
/*
* EFI Configuration Table and GUID definitions
@@ -575,9 +576,15 @@ extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if pos
#ifdef CONFIG_X86
extern void efi_late_init(void);
extern void efi_free_boot_services(void);
+extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
#else
static inline void efi_late_init(void) {}
static inline void efi_free_boot_services(void) {}
+
+static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+{
+ return EFI_SUCCESS;
+}
#endif
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
extern u64 efi_get_iobase (void);
@@ -663,6 +670,12 @@ static inline int efi_enabled(int facility)
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
EFI_VARIABLE_APPEND_WRITE)
/*
+ * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"))
+ * not including trailing NUL
+ */
+#define EFI_VARIABLE_GUID_LEN 36
+
+/*
* The type of search to perform when calling boottime->locate_handle
*/
#define EFI_LOCATE_ALL_HANDLES 0
@@ -719,7 +732,6 @@ static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
*addr &= PAGE_MASK;
}
-#if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE)
/*
* EFI Variable support.
*
@@ -731,7 +743,7 @@ struct efivar_operations {
efi_get_variable_t *get_variable;
efi_get_next_variable_t *get_next_variable;
efi_set_variable_t *set_variable;
- efi_query_variable_info_t *query_variable_info;
+ efi_query_variable_store_t *query_variable_store;
};
struct efivars {
@@ -745,19 +757,88 @@ struct efivars {
* which is protected by the BKL, so that path is safe.
*/
spinlock_t lock;
- struct list_head list;
struct kset *kset;
struct kobject *kobject;
- struct bin_attribute *new_var, *del_var;
const struct efivar_operations *ops;
- struct efivar_entry *walk_entry;
- struct pstore_info efi_pstore_info;
};
-int register_efivars(struct efivars *efivars,
+/*
+ * The maximum size of VariableName + Data = 1024
+ * Therefore, it's reasonable to save that much
+ * space in each part of the structure,
+ * and we use a page for reading/writing.
+ */
+
+struct efi_variable {
+ efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
+ efi_guid_t VendorGuid;
+ unsigned long DataSize;
+ __u8 Data[1024];
+ efi_status_t Status;
+ __u32 Attributes;
+} __attribute__((packed));
+
+struct efivar_entry {
+ struct efi_variable var;
+ struct list_head list;
+ struct kobject kobj;
+};
+
+extern struct list_head efivar_sysfs_list;
+
+static inline void
+efivar_unregister(struct efivar_entry *var)
+{
+ kobject_put(&var->kobj);
+}
+
+int efivars_register(struct efivars *efivars,
const struct efivar_operations *ops,
- struct kobject *parent_kobj);
-void unregister_efivars(struct efivars *efivars);
+ struct kobject *kobject);
+int efivars_unregister(struct efivars *efivars);
+struct kobject *efivars_kobject(void);
+
+int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
+ void *data, bool atomic, bool duplicates,
+ struct list_head *head);
+
+void efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
+void efivar_entry_remove(struct efivar_entry *entry);
+
+int __efivar_entry_delete(struct efivar_entry *entry);
+int efivar_entry_delete(struct efivar_entry *entry);
+
+int efivar_entry_size(struct efivar_entry *entry, unsigned long *size);
+int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
+ unsigned long *size, void *data);
+int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
+ unsigned long *size, void *data);
+int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
+ unsigned long size, void *data, struct list_head *head);
+int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
+ unsigned long *size, void *data, bool *set);
+int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
+ bool block, unsigned long size, void *data);
+
+void efivar_entry_iter_begin(void);
+void efivar_entry_iter_end(void);
+
+int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
+ struct list_head *head, void *data,
+ struct efivar_entry **prev);
+int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
+ struct list_head *head, void *data);
+
+struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
+ struct list_head *head, bool remove);
+
+bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len);
+
+extern struct work_struct efivar_work;
+void efivar_run_worker(void);
+
+#if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE)
+int efivars_sysfs_init(void);
#endif /* CONFIG_EFI_VARS */
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 9fc13a760928..1fcb88ca88de 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -96,5 +96,5 @@ static inline int evm_inode_init_security(struct inode *inode,
return 0;
}
-#endif /* CONFIG_EVM_H */
+#endif /* CONFIG_EVM */
#endif /* LINUX_EVM_H */
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index 5b9b5b317180..41b223a59a63 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -85,6 +85,17 @@ enum fid_type {
FILEID_NILFS_WITH_PARENT = 0x62,
/*
+ * 32 bit generation number, 40 bit i_pos.
+ */
+ FILEID_FAT_WITHOUT_PARENT = 0x71,
+
+ /*
+ * 32 bit generation number, 40 bit i_pos,
+ * 32 bit parent generation number, 40 bit parent i_pos
+ */
+ FILEID_FAT_WITH_PARENT = 0x72,
+
+ /*
* Filesystems must not use 0xff file ID.
*/
FILEID_INVALID = 0xff,
diff --git a/include/linux/filter.h b/include/linux/filter.h
index c45eabc135e1..c050dcc322a4 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -48,8 +48,22 @@ extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
extern int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned len);
#ifdef CONFIG_BPF_JIT
+#include <stdarg.h>
+#include <linux/linkage.h>
+#include <linux/printk.h>
+
extern void bpf_jit_compile(struct sk_filter *fp);
extern void bpf_jit_free(struct sk_filter *fp);
+
+static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
+ u32 pass, void *image)
+{
+ pr_err("flen=%u proglen=%u pass=%u image=%p\n",
+ flen, proglen, pass, image);
+ if (image)
+ print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
+ 16, 1, image, proglen, false);
+}
#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
#else
static inline void bpf_jit_compile(struct sk_filter *fp)
@@ -126,6 +140,7 @@ enum {
BPF_S_ANC_SECCOMP_LD_W,
BPF_S_ANC_VLAN_TAG,
BPF_S_ANC_VLAN_TAG_PRESENT,
+ BPF_S_ANC_PAY_OFFSET,
};
#endif /* __LINUX_FILTER_H__ */
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 043a5cf8b5ba..e70df40d84f6 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -3,7 +3,6 @@
#ifndef FREEZER_H_INCLUDED
#define FREEZER_H_INCLUDED
-#include <linux/debug_locks.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/atomic.h>
@@ -49,8 +48,6 @@ extern void thaw_kernel_threads(void);
static inline bool try_to_freeze(void)
{
- if (!(current->flags & PF_NOFREEZE))
- debug_check_no_locks_held();
might_sleep();
if (likely(!freezing(current)))
return false;
diff --git a/include/linux/frontswap.h b/include/linux/frontswap.h
index 30442547b9e6..8293262401de 100644
--- a/include/linux/frontswap.h
+++ b/include/linux/frontswap.h
@@ -14,7 +14,7 @@ struct frontswap_ops {
};
extern bool frontswap_enabled;
-extern struct frontswap_ops
+extern struct frontswap_ops *
frontswap_register_ops(struct frontswap_ops *ops);
extern void frontswap_shrink(unsigned long);
extern unsigned long frontswap_curr_pages(void);
@@ -22,33 +22,19 @@ extern void frontswap_writethrough(bool);
#define FRONTSWAP_HAS_EXCLUSIVE_GETS
extern void frontswap_tmem_exclusive_gets(bool);
-extern void __frontswap_init(unsigned type);
+extern bool __frontswap_test(struct swap_info_struct *, pgoff_t);
+extern void __frontswap_init(unsigned type, unsigned long *map);
extern int __frontswap_store(struct page *page);
extern int __frontswap_load(struct page *page);
extern void __frontswap_invalidate_page(unsigned, pgoff_t);
extern void __frontswap_invalidate_area(unsigned);
#ifdef CONFIG_FRONTSWAP
+#define frontswap_enabled (1)
static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset)
{
- bool ret = false;
-
- if (frontswap_enabled && sis->frontswap_map)
- ret = test_bit(offset, sis->frontswap_map);
- return ret;
-}
-
-static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset)
-{
- if (frontswap_enabled && sis->frontswap_map)
- set_bit(offset, sis->frontswap_map);
-}
-
-static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
-{
- if (frontswap_enabled && sis->frontswap_map)
- clear_bit(offset, sis->frontswap_map);
+ return __frontswap_test(sis, offset);
}
static inline void frontswap_map_set(struct swap_info_struct *p,
@@ -71,14 +57,6 @@ static inline bool frontswap_test(struct swap_info_struct *sis, pgoff_t offset)
return false;
}
-static inline void frontswap_set(struct swap_info_struct *sis, pgoff_t offset)
-{
-}
-
-static inline void frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
-{
-}
-
static inline void frontswap_map_set(struct swap_info_struct *p,
unsigned long *map)
{
@@ -120,10 +98,10 @@ static inline void frontswap_invalidate_area(unsigned type)
__frontswap_invalidate_area(type);
}
-static inline void frontswap_init(unsigned type)
+static inline void frontswap_init(unsigned type, unsigned long *map)
{
if (frontswap_enabled)
- __frontswap_init(type);
+ __frontswap_init(type, map);
}
#endif /* _LINUX_FRONTSWAP_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b1f28b02ede6..e8cd6b839675 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -675,9 +675,11 @@ static inline loff_t i_size_read(const struct inode *inode)
static inline void i_size_write(struct inode *inode, loff_t i_size)
{
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+ preempt_disable();
write_seqcount_begin(&inode->i_size_seqcount);
inode->i_size = i_size;
write_seqcount_end(&inode->i_size_seqcount);
+ preempt_enable();
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
preempt_disable();
inode->i_size = i_size;
diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h
index 729eded4b24f..2b93a9a5a1e6 100644
--- a/include/linux/fs_struct.h
+++ b/include/linux/fs_struct.h
@@ -50,4 +50,6 @@ static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root,
spin_unlock(&fs->lock);
}
+extern bool current_chrooted(void);
+
#endif /* _LINUX_FS_STRUCT_H */
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index d5b0910d4961..4b2ee8d12f5e 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -157,7 +157,6 @@ struct fsnotify_group {
struct inotify_group_private_data {
spinlock_t idr_lock;
struct idr idr;
- u32 last_wd;
struct user_struct *user;
} inotify_data;
#endif
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index e5ca8ef50e9b..f83e17a40e8b 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -89,6 +89,7 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
* that the call back has its own recursion protection. If it does
* not set this, then the ftrace infrastructure will add recursion
* protection for the caller.
+ * STUB - The ftrace_ops is just a place holder.
*/
enum {
FTRACE_OPS_FL_ENABLED = 1 << 0,
@@ -98,6 +99,7 @@ enum {
FTRACE_OPS_FL_SAVE_REGS = 1 << 4,
FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 5,
FTRACE_OPS_FL_RECURSION_SAFE = 1 << 6,
+ FTRACE_OPS_FL_STUB = 1 << 7,
};
struct ftrace_ops {
@@ -259,8 +261,10 @@ struct ftrace_probe_ops {
void (*func)(unsigned long ip,
unsigned long parent_ip,
void **data);
- int (*callback)(unsigned long ip, void **data);
- void (*free)(void **data);
+ int (*init)(struct ftrace_probe_ops *ops,
+ unsigned long ip, void **data);
+ void (*free)(struct ftrace_probe_ops *ops,
+ unsigned long ip, void **data);
int (*print)(struct seq_file *m,
unsigned long ip,
struct ftrace_probe_ops *ops,
@@ -394,7 +398,6 @@ ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos);
ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos);
-loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int whence);
int ftrace_regex_release(struct inode *inode, struct file *file);
void __init
@@ -567,6 +570,8 @@ static inline int
ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; }
#endif /* CONFIG_DYNAMIC_FTRACE */
+loff_t ftrace_filter_lseek(struct file *file, loff_t offset, int whence);
+
/* totally disable ftrace - can not re-enable after this */
void ftrace_kill(void);
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 13a54d0bdfa8..34e00fb49bec 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -8,6 +8,7 @@
#include <linux/perf_event.h>
struct trace_array;
+struct trace_buffer;
struct tracer;
struct dentry;
@@ -38,6 +39,12 @@ const char *ftrace_print_symbols_seq_u64(struct trace_seq *p,
const char *ftrace_print_hex_seq(struct trace_seq *p,
const unsigned char *buf, int len);
+struct trace_iterator;
+struct trace_event;
+
+int ftrace_raw_output_prep(struct trace_iterator *iter,
+ struct trace_event *event);
+
/*
* The trace entry - the most basic unit of tracing. This is what
* is printed in the end as a single line in the trace output, such as:
@@ -61,6 +68,7 @@ struct trace_entry {
struct trace_iterator {
struct trace_array *tr;
struct tracer *trace;
+ struct trace_buffer *trace_buffer;
void *private;
int cpu_file;
struct mutex mutex;
@@ -95,8 +103,6 @@ enum trace_iter_flags {
};
-struct trace_event;
-
typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter,
int flags, struct trace_event *event);
@@ -128,6 +134,13 @@ enum print_line_t {
void tracing_generic_entry_update(struct trace_entry *entry,
unsigned long flags,
int pc);
+struct ftrace_event_file;
+
+struct ring_buffer_event *
+trace_event_buffer_lock_reserve(struct ring_buffer **current_buffer,
+ struct ftrace_event_file *ftrace_file,
+ int type, unsigned long len,
+ unsigned long flags, int pc);
struct ring_buffer_event *
trace_current_buffer_lock_reserve(struct ring_buffer **current_buffer,
int type, unsigned long len,
@@ -182,53 +195,49 @@ extern int ftrace_event_reg(struct ftrace_event_call *event,
enum trace_reg type, void *data);
enum {
- TRACE_EVENT_FL_ENABLED_BIT,
TRACE_EVENT_FL_FILTERED_BIT,
- TRACE_EVENT_FL_RECORDED_CMD_BIT,
TRACE_EVENT_FL_CAP_ANY_BIT,
TRACE_EVENT_FL_NO_SET_FILTER_BIT,
TRACE_EVENT_FL_IGNORE_ENABLE_BIT,
+ TRACE_EVENT_FL_WAS_ENABLED_BIT,
};
+/*
+ * Event flags:
+ * FILTERED - The event has a filter attached
+ * CAP_ANY - Any user can enable for perf
+ * NO_SET_FILTER - Set when filter has error and is to be ignored
+ * IGNORE_ENABLE - For ftrace internal events, do not enable with debugfs file
+ * WAS_ENABLED - Set and stays set when an event was ever enabled
+ * (used for module unloading, if a module event is enabled,
+ * it is best to clear the buffers that used it).
+ */
enum {
- TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT),
TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT),
- TRACE_EVENT_FL_RECORDED_CMD = (1 << TRACE_EVENT_FL_RECORDED_CMD_BIT),
TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT),
TRACE_EVENT_FL_NO_SET_FILTER = (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT),
TRACE_EVENT_FL_IGNORE_ENABLE = (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT),
+ TRACE_EVENT_FL_WAS_ENABLED = (1 << TRACE_EVENT_FL_WAS_ENABLED_BIT),
};
struct ftrace_event_call {
struct list_head list;
struct ftrace_event_class *class;
char *name;
- struct dentry *dir;
struct trace_event event;
const char *print_fmt;
struct event_filter *filter;
+ struct list_head *files;
void *mod;
void *data;
-
/*
- * 32 bit flags:
- * bit 1: enabled
- * bit 2: filter_active
- * bit 3: enabled cmd record
- * bit 4: allow trace by non root (cap any)
- * bit 5: failed to apply filter
- * bit 6: ftrace internal event (do not enable)
- *
- * Changes to flags must hold the event_mutex.
- *
- * Note: Reads of flags do not hold the event_mutex since
- * they occur in critical sections. But the way flags
- * is currently used, these changes do no affect the code
- * except that when a change is made, it may have a slight
- * delay in propagating the changes to other CPUs due to
- * caching and such.
+ * bit 0: filter_active
+ * bit 1: allow trace by non root (cap any)
+ * bit 2: failed to apply filter
+ * bit 3: ftrace internal event (do not enable)
+ * bit 4: Event was enabled by module
*/
- unsigned int flags;
+ int flags; /* static flags of different events */
#ifdef CONFIG_PERF_EVENTS
int perf_refcount;
@@ -236,6 +245,56 @@ struct ftrace_event_call {
#endif
};
+struct trace_array;
+struct ftrace_subsystem_dir;
+
+enum {
+ FTRACE_EVENT_FL_ENABLED_BIT,
+ FTRACE_EVENT_FL_RECORDED_CMD_BIT,
+ FTRACE_EVENT_FL_SOFT_MODE_BIT,
+ FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
+};
+
+/*
+ * Ftrace event file flags:
+ * ENABLED - The event is enabled
+ * RECORDED_CMD - The comms should be recorded at sched_switch
+ * SOFT_MODE - The event is enabled/disabled by SOFT_DISABLED
+ * SOFT_DISABLED - When set, do not trace the event (even though its
+ * tracepoint may be enabled)
+ */
+enum {
+ FTRACE_EVENT_FL_ENABLED = (1 << FTRACE_EVENT_FL_ENABLED_BIT),
+ FTRACE_EVENT_FL_RECORDED_CMD = (1 << FTRACE_EVENT_FL_RECORDED_CMD_BIT),
+ FTRACE_EVENT_FL_SOFT_MODE = (1 << FTRACE_EVENT_FL_SOFT_MODE_BIT),
+ FTRACE_EVENT_FL_SOFT_DISABLED = (1 << FTRACE_EVENT_FL_SOFT_DISABLED_BIT),
+};
+
+struct ftrace_event_file {
+ struct list_head list;
+ struct ftrace_event_call *event_call;
+ struct dentry *dir;
+ struct trace_array *tr;
+ struct ftrace_subsystem_dir *system;
+
+ /*
+ * 32 bit flags:
+ * bit 0: enabled
+ * bit 1: enabled cmd record
+ * bit 2: enable/disable with the soft disable bit
+ * bit 3: soft disabled
+ *
+ * Note: The bits must be set atomically to prevent races
+ * from other writers. Reads of flags do not need to be in
+ * sync as they occur in critical sections. But the way flags
+ * is currently used, these changes do not affect the code
+ * except that when a change is made, it may have a slight
+ * delay in propagating the changes to other CPUs due to
+ * caching and such. Which is mostly OK ;-)
+ */
+ unsigned long flags;
+};
+
#define __TRACE_EVENT_FLAGS(name, value) \
static int __init trace_init_flags_##name(void) \
{ \
@@ -274,7 +333,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type,
extern int trace_add_event_call(struct ftrace_event_call *call);
extern void trace_remove_event_call(struct ftrace_event_call *call);
-#define is_signed_type(type) (((type)(-1)) < (type)0)
+#define is_signed_type(type) (((type)(-1)) < (type)1)
int trace_set_clr_event(const char *system, const char *event, int set);
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index dd7c569aacad..661d374aeb2d 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -29,6 +29,10 @@
#ifndef __GENALLOC_H__
#define __GENALLOC_H__
+
+struct device;
+struct device_node;
+
/**
* Allocation callback function type definition
* @map: Pointer to bitmap
@@ -105,4 +109,18 @@ extern unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,
extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
unsigned long start, unsigned int nr, void *data);
+extern struct gen_pool *devm_gen_pool_create(struct device *dev,
+ int min_alloc_order, int nid);
+extern struct gen_pool *dev_get_gen_pool(struct device *dev);
+
+#ifdef CONFIG_OF
+extern struct gen_pool *of_get_named_gen_pool(struct device_node *np,
+ const char *propname, int index);
+#else
+static inline struct gen_pool *of_get_named_gen_pool(struct device_node *np,
+ const char *propname, int index)
+{
+ return NULL;
+}
+#endif
#endif /* __GENALLOC_H__ */
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h
index 53744fa1c8b7..8663f216c563 100644
--- a/include/linux/hid-debug.h
+++ b/include/linux/hid-debug.h
@@ -22,11 +22,12 @@
*
*/
-#define HID_DEBUG_BUFSIZE 512
-
#ifdef CONFIG_DEBUG_FS
+#define HID_DEBUG_BUFSIZE 512
+
void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
+void hid_dump_report(struct hid_device *, int , u8 *, int);
void hid_dump_device(struct hid_device *, struct seq_file *);
void hid_dump_field(struct hid_field *, int, struct seq_file *);
char *hid_resolv_usage(unsigned, struct seq_file *);
@@ -50,6 +51,7 @@ struct hid_debug_list {
#else
#define hid_dump_input(a,b,c) do { } while (0)
+#define hid_dump_report(a,b,c,d) do { } while (0)
#define hid_dump_device(a,b) do { } while (0)
#define hid_dump_field(a,b,c) do { } while (0)
#define hid_resolv_usage(a,b) do { } while (0)
diff --git a/include/linux/hid.h b/include/linux/hid.h
index e14b465b1146..af1b86d46f6e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -282,6 +282,7 @@ struct hid_item {
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
+#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
@@ -456,7 +457,8 @@ struct hid_device { /* device report descriptor */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
- struct semaphore driver_lock; /* protects the current driver */
+ struct semaphore driver_lock; /* protects the current driver, except during input */
+ struct semaphore driver_input_lock; /* protects the current driver */
struct device dev; /* device */
struct hid_driver *driver;
struct hid_ll_driver *ll_driver;
@@ -477,6 +479,7 @@ struct hid_device { /* device report descriptor */
unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
+ bool io_started; /* Protected by driver_lock. If IO has started */
struct list_head inputs; /* The list of inputs */
void *hiddev; /* The hiddev structure */
@@ -512,6 +515,7 @@ struct hid_device { /* device report descriptor */
struct dentry *debug_rdesc;
struct dentry *debug_events;
struct list_head debug_list;
+ struct mutex debug_list_lock;
wait_queue_head_t debug_wait;
};
@@ -599,6 +603,10 @@ struct hid_usage_id {
* @resume: invoked on resume if device was not reset (NULL means nop)
* @reset_resume: invoked on resume if device was reset (NULL means nop)
*
+ * probe should return -errno on error, or 0 on success. During probe,
+ * input will not be passed to raw_event unless hid_device_io_start is
+ * called.
+ *
* raw_event and event should return 0 on no action performed, 1 when no
* further processing should be done and negative on error
*
@@ -662,6 +670,9 @@ struct hid_driver {
* @hidinput_input_event: event input event (e.g. ff or leds)
* @parse: this method is called only once to parse the device data,
* shouldn't allocate anything to not leak memory
+ * @request: send report request to device (e.g. feature report)
+ * @wait: wait for buffered io to complete (send/recv reports)
+ * @idle: send idle request to device
*/
struct hid_ll_driver {
int (*start)(struct hid_device *hdev);
@@ -676,6 +687,13 @@ struct hid_ll_driver {
unsigned int code, int value);
int (*parse)(struct hid_device *hdev);
+
+ void (*request)(struct hid_device *hdev,
+ struct hid_report *report, int reqtype);
+
+ int (*wait)(struct hid_device *hdev);
+ int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
+
};
#define PM_HINT_FULLON 1<<5
@@ -738,6 +756,44 @@ const struct hid_device_id *hid_match_id(struct hid_device *hdev,
s32 hid_snto32(__u32 value, unsigned n);
/**
+ * hid_device_io_start - enable HID input during probe, remove
+ *
+ * @hid - the device
+ *
+ * This should only be called during probe or remove and only be
+ * called by the thread calling probe or remove. It will allow
+ * incoming packets to be delivered to the driver.
+ */
+static inline void hid_device_io_start(struct hid_device *hid) {
+ if (hid->io_started) {
+ dev_warn(&hid->dev, "io already started");
+ return;
+ }
+ hid->io_started = true;
+ up(&hid->driver_input_lock);
+}
+
+/**
+ * hid_device_io_stop - disable HID input during probe, remove
+ *
+ * @hid - the device
+ *
+ * Should only be called after hid_device_io_start. It will prevent
+ * incoming packets from going to the driver for the duration of
+ * probe, remove. If called during probe, packets will still go to the
+ * driver after probe is complete. This function should only be called
+ * by the thread calling probe or remove.
+ */
+static inline void hid_device_io_stop(struct hid_device *hid) {
+ if (!hid->io_started) {
+ dev_warn(&hid->dev, "io already stopped");
+ return;
+ }
+ hid->io_started = false;
+ down(&hid->driver_input_lock);
+}
+
+/**
* hid_map_usage - map usage input bits
*
* @hidinput: hidinput which we are interested in
@@ -883,6 +939,49 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
}
+
+/**
+ * hid_hw_request - send report request to device
+ *
+ * @hdev: hid device
+ * @report: report to send
+ * @reqtype: hid request type
+ */
+static inline void hid_hw_request(struct hid_device *hdev,
+ struct hid_report *report, int reqtype)
+{
+ if (hdev->ll_driver->request)
+ hdev->ll_driver->request(hdev, report, reqtype);
+}
+
+/**
+ * hid_hw_idle - send idle request to device
+ *
+ * @hdev: hid device
+ * @report: report to control
+ * @idle: idle state
+ * @reqtype: hid request type
+ */
+static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle,
+ int reqtype)
+{
+ if (hdev->ll_driver->idle)
+ return hdev->ll_driver->idle(hdev, report, idle, reqtype);
+
+ return 0;
+}
+
+/**
+ * hid_hw_wait - wait for buffered io to complete
+ *
+ * @hdev: hid device
+ */
+static inline void hid_hw_wait(struct hid_device *hdev)
+{
+ if (hdev->ll_driver->wait)
+ hdev->ll_driver->wait(hdev);
+}
+
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt);
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index cc07d2777bbe..d19a5c2d2270 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -157,6 +157,7 @@ enum hrtimer_base_type {
HRTIMER_BASE_MONOTONIC,
HRTIMER_BASE_REALTIME,
HRTIMER_BASE_BOOTTIME,
+ HRTIMER_BASE_TAI,
HRTIMER_MAX_CLOCK_BASES,
};
@@ -327,7 +328,9 @@ extern ktime_t ktime_get(void);
extern ktime_t ktime_get_real(void);
extern ktime_t ktime_get_boottime(void);
extern ktime_t ktime_get_monotonic_offset(void);
-extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot);
+extern ktime_t ktime_get_clocktai(void);
+extern ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
+ ktime_t *offs_tai);
DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index ee1c244a62a1..528454c2caa9 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -99,7 +99,11 @@ extern int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
extern int handle_pte_fault(struct mm_struct *mm,
struct vm_area_struct *vma, unsigned long address,
pte_t *pte, pmd_t *pmd, unsigned int flags);
-extern int split_huge_page(struct page *page);
+extern int split_huge_page_to_list(struct page *page, struct list_head *list);
+static inline int split_huge_page(struct page *page)
+{
+ return split_huge_page_to_list(page, NULL);
+}
extern void __split_huge_page_pmd(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd);
#define split_huge_page_pmd(__vma, __address, __pmd) \
@@ -186,6 +190,11 @@ extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vm
#define transparent_hugepage_enabled(__vma) 0
#define transparent_hugepage_flags 0UL
+static inline int
+split_huge_page_to_list(struct page *page, struct list_head *list)
+{
+ return 0;
+}
static inline int split_huge_page(struct page *page)
{
return 0;
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 16e4e9a643fb..3a62df310f2e 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -58,6 +58,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
void hugetlb_report_meminfo(struct seq_file *);
int hugetlb_report_node_meminfo(int, char *);
+void hugetlb_show_meminfo(void);
unsigned long hugetlb_total_pages(void);
int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, unsigned int flags);
@@ -114,6 +115,9 @@ static inline void hugetlb_report_meminfo(struct seq_file *m)
{
}
#define hugetlb_report_node_meminfo(n, buf) 0
+static inline void hugetlb_show_meminfo(void)
+{
+}
#define follow_huge_pmd(mm, addr, pmd, write) NULL
#define follow_huge_pud(mm, addr, pud, write) NULL
#define prepare_hugepage_range(file, addr, len) (-EINVAL)
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index df77ba9a8166..c2559847d7ee 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -27,6 +27,63 @@
#include <linux/types.h>
+
+/*
+ * Implementation of host controlled snapshot of the guest.
+ */
+
+#define VSS_OP_REGISTER 128
+
+enum hv_vss_op {
+ VSS_OP_CREATE = 0,
+ VSS_OP_DELETE,
+ VSS_OP_HOT_BACKUP,
+ VSS_OP_GET_DM_INFO,
+ VSS_OP_BU_COMPLETE,
+ /*
+ * Following operations are only supported with IC version >= 5.0
+ */
+ VSS_OP_FREEZE, /* Freeze the file systems in the VM */
+ VSS_OP_THAW, /* Unfreeze the file systems */
+ VSS_OP_AUTO_RECOVER,
+ VSS_OP_COUNT /* Number of operations, must be last */
+};
+
+
+/*
+ * Header for all VSS messages.
+ */
+struct hv_vss_hdr {
+ __u8 operation;
+ __u8 reserved[7];
+} __attribute__((packed));
+
+
+/*
+ * Flag values for the hv_vss_check_feature. Linux supports only
+ * one value.
+ */
+#define VSS_HBU_NO_AUTO_RECOVERY 0x00000005
+
+struct hv_vss_check_feature {
+ __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_check_dm_info {
+ __u32 flags;
+} __attribute__((packed));
+
+struct hv_vss_msg {
+ union {
+ struct hv_vss_hdr vss_hdr;
+ int error;
+ };
+ union {
+ struct hv_vss_check_feature vss_cf;
+ struct hv_vss_check_dm_info dm_info;
+ };
+} __attribute__((packed));
+
/*
* An implementation of HyperV key value pair (KVP) functionality for Linux.
*
@@ -1253,6 +1310,25 @@ void vmbus_driver_unregister(struct hv_driver *hv_driver);
}
/*
+ * VSS (Backup/Restore) GUID
+ */
+#define HV_VSS_GUID \
+ .guid = { \
+ 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \
+ 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40 \
+ }
+/*
+ * Synthetic Video GUID
+ * {DA0A7802-E377-4aac-8E77-0558EB1073F8}
+ */
+#define HV_SYNTHVID_GUID \
+ .guid = { \
+ 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \
+ 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \
+ }
+
+
+/*
* Common header for Hyper-V ICs
*/
@@ -1356,6 +1432,10 @@ int hv_kvp_init(struct hv_util_service *);
void hv_kvp_deinit(void);
void hv_kvp_onchannelcallback(void *);
+int hv_vss_init(struct hv_util_service *);
+void hv_vss_deinit(void);
+void hv_vss_onchannelcallback(void *);
+
/*
* Negotiated version with the Host.
*/
diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h
index b4f6c29caced..630f45335c73 100644
--- a/include/linux/icmpv6.h
+++ b/include/linux/icmpv6.h
@@ -11,9 +11,21 @@ static inline struct icmp6hdr *icmp6_hdr(const struct sk_buff *skb)
#include <linux/netdevice.h>
-extern void icmpv6_send(struct sk_buff *skb,
- u8 type, u8 code,
- __u32 info);
+#if IS_ENABLED(CONFIG_IPV6)
+extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info);
+
+typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info);
+extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn);
+extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn);
+
+#else
+
+static inline void icmpv6_send(struct sk_buff *skb,
+ u8 type, u8 code, __u32 info)
+{
+
+}
+#endif
extern int icmpv6_init(void);
extern int icmpv6_err_convert(u8 type, u8 code,
diff --git a/include/linux/idr.h b/include/linux/idr.h
index 2640c7e99e51..a470ac3ef49d 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -42,6 +42,7 @@ struct idr {
struct idr_layer *id_free;
int layers; /* only valid w/o concurrent changes */
int id_free_cnt;
+ int cur; /* current pos for cyclic allocation */
spinlock_t lock;
};
@@ -75,6 +76,7 @@ struct idr {
void *idr_find_slowpath(struct idr *idp, int id);
void idr_preload(gfp_t gfp_mask);
int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask);
+int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask);
int idr_for_each(struct idr *idp,
int (*fn)(int id, void *p, void *data), void *data);
void *idr_get_next(struct idr *idp, int *nextid);
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 7e24fe0cfbcd..06b0ed0154a4 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -113,6 +113,34 @@
#define IEEE80211_CTL_EXT_SSW_FBACK 0x9000
#define IEEE80211_CTL_EXT_SSW_ACK 0xa000
+
+#define IEEE80211_SN_MASK ((IEEE80211_SCTL_SEQ) >> 4)
+#define IEEE80211_MAX_SN IEEE80211_SN_MASK
+#define IEEE80211_SN_MODULO (IEEE80211_MAX_SN + 1)
+
+static inline int ieee80211_sn_less(u16 sn1, u16 sn2)
+{
+ return ((sn1 - sn2) & IEEE80211_SN_MASK) > (IEEE80211_SN_MODULO >> 1);
+}
+
+static inline u16 ieee80211_sn_add(u16 sn1, u16 sn2)
+{
+ return (sn1 + sn2) & IEEE80211_SN_MASK;
+}
+
+static inline u16 ieee80211_sn_inc(u16 sn)
+{
+ return ieee80211_sn_add(sn, 1);
+}
+
+static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
+{
+ return (sn1 - sn2) & IEEE80211_SN_MASK;
+}
+
+#define IEEE80211_SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define IEEE80211_SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+
/* miscellaneous IEEE 802.11 constants */
#define IEEE80211_MAX_FRAG_THRESHOLD 2352
#define IEEE80211_MAX_RTS_THRESHOLD 2353
@@ -185,7 +213,7 @@ struct ieee80211_hdr {
u8 addr3[6];
__le16 seq_ctrl;
u8 addr4[6];
-} __packed;
+} __packed __aligned(2);
struct ieee80211_hdr_3addr {
__le16 frame_control;
@@ -194,7 +222,7 @@ struct ieee80211_hdr_3addr {
u8 addr2[6];
u8 addr3[6];
__le16 seq_ctrl;
-} __packed;
+} __packed __aligned(2);
struct ieee80211_qos_hdr {
__le16 frame_control;
@@ -204,7 +232,7 @@ struct ieee80211_qos_hdr {
u8 addr3[6];
__le16 seq_ctrl;
__le16 qos_ctrl;
-} __packed;
+} __packed __aligned(2);
/**
* ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
@@ -581,7 +609,7 @@ struct ieee80211s_hdr {
__le32 seqnum;
u8 eaddr1[6];
u8 eaddr2[6];
-} __packed;
+} __packed __aligned(2);
/* Mesh flags */
#define MESH_FLAGS_AE_A4 0x1
@@ -645,6 +673,36 @@ struct ieee80211_channel_sw_ie {
} __packed;
/**
+ * struct ieee80211_ext_chansw_ie
+ *
+ * This structure represents the "Extended Channel Switch Announcement element"
+ */
+struct ieee80211_ext_chansw_ie {
+ u8 mode;
+ u8 new_operating_class;
+ u8 new_ch_num;
+ u8 count;
+} __packed;
+
+/**
+ * struct ieee80211_sec_chan_offs_ie - secondary channel offset IE
+ * @sec_chan_offs: secondary channel offset, uses IEEE80211_HT_PARAM_CHA_SEC_*
+ * values here
+ * This structure represents the "Secondary Channel Offset element"
+ */
+struct ieee80211_sec_chan_offs_ie {
+ u8 sec_chan_offs;
+} __packed;
+
+/**
+ * struct ieee80211_wide_bw_chansw_ie - wide bandwidth channel switch IE
+ */
+struct ieee80211_wide_bw_chansw_ie {
+ u8 new_channel_width;
+ u8 new_center_freq_seg0, new_center_freq_seg1;
+} __packed;
+
+/**
* struct ieee80211_tim
*
* This structure refers to "Traffic Indication Map information element"
@@ -812,12 +870,15 @@ struct ieee80211_mgmt {
} __packed wme_action;
struct{
u8 action_code;
- u8 element_id;
- u8 length;
- struct ieee80211_channel_sw_ie sw_elem;
+ u8 variable[0];
} __packed chan_switch;
struct{
u8 action_code;
+ struct ieee80211_ext_chansw_ie data;
+ u8 variable[0];
+ } __packed ext_chan_switch;
+ struct{
+ u8 action_code;
u8 dialog_token;
u8 element_id;
u8 length;
@@ -875,7 +936,7 @@ struct ieee80211_mgmt {
} u;
} __packed action;
} u;
-} __packed;
+} __packed __aligned(2);
/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
@@ -906,20 +967,20 @@ struct ieee80211_rts {
__le16 duration;
u8 ra[6];
u8 ta[6];
-} __packed;
+} __packed __aligned(2);
struct ieee80211_cts {
__le16 frame_control;
__le16 duration;
u8 ra[6];
-} __packed;
+} __packed __aligned(2);
struct ieee80211_pspoll {
__le16 frame_control;
__le16 aid;
u8 bssid[6];
u8 ta[6];
-} __packed;
+} __packed __aligned(2);
/* TDLS */
@@ -999,6 +1060,26 @@ enum ieee80211_p2p_attr_id {
IEEE80211_P2P_ATTR_MAX
};
+/* Notice of Absence attribute - described in P2P spec 4.1.14 */
+/* Typical max value used here */
+#define IEEE80211_P2P_NOA_DESC_MAX 4
+
+struct ieee80211_p2p_noa_desc {
+ u8 count;
+ __le32 duration;
+ __le32 interval;
+ __le32 start_time;
+} __packed;
+
+struct ieee80211_p2p_noa_attr {
+ u8 index;
+ u8 oppps_ctwindow;
+ struct ieee80211_p2p_noa_desc desc[IEEE80211_P2P_NOA_DESC_MAX];
+} __packed;
+
+#define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7)
+#define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7F
+
/**
* struct ieee80211_bar - HT Block Ack Request
*
@@ -1290,11 +1371,6 @@ struct ieee80211_vht_operation {
} __packed;
-#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0
-#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1
-#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2
-#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3
-
/* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
@@ -1310,10 +1386,11 @@ struct ieee80211_vht_operation {
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
+#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
-#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00030000
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
@@ -1594,6 +1671,7 @@ enum ieee80211_eid {
WLAN_EID_HT_CAPABILITY = 45,
WLAN_EID_HT_OPERATION = 61,
+ WLAN_EID_SECONDARY_CHANNEL_OFFSET = 62,
WLAN_EID_RSN = 48,
WLAN_EID_MMIE = 76,
@@ -1628,6 +1706,8 @@ enum ieee80211_eid {
WLAN_EID_VHT_CAPABILITY = 191,
WLAN_EID_VHT_OPERATION = 192,
WLAN_EID_OPMODE_NOTIF = 199,
+ WLAN_EID_WIDE_BW_CHANNEL_SWITCH = 194,
+ WLAN_EID_CHANNEL_SWITCH_WRAPPER = 196,
/* 802.11ad */
WLAN_EID_NON_TX_BSSID_CAP = 83,
@@ -1751,6 +1831,7 @@ enum ieee80211_key_len {
/* Public action codes */
enum ieee80211_pub_actioncode {
+ WLAN_PUB_ACTION_EXT_CHANSW_ANN = 4,
WLAN_PUB_ACTION_TDLS_DISCOVER_RES = 14,
};
@@ -1911,6 +1992,16 @@ enum ieee80211_timeout_interval_type {
WLAN_TIMEOUT_ASSOC_COMEBACK = 3 /* 802.11w */,
};
+/**
+ * struct ieee80211_timeout_interval_ie - Timeout Interval element
+ * @type: type, see &enum ieee80211_timeout_interval_type
+ * @value: timeout interval value
+ */
+struct ieee80211_timeout_interval_ie {
+ u8 type;
+ __le32 value;
+} __packed;
+
/* BACK action code */
enum ieee80211_back_actioncode {
WLAN_ACTION_ADDBA_REQ = 0,
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 89b4614a4722..f563907ed776 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -33,7 +33,15 @@ static inline struct arphdr *arp_hdr(const struct sk_buff *skb)
static inline int arp_hdr_len(struct net_device *dev)
{
- /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
- return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2;
+ switch (dev->type) {
+#if IS_ENABLED(CONFIG_FIREWIRE_NET)
+ case ARPHRD_IEEE1394:
+ /* ARP header, device address and 2 IP addresses */
+ return sizeof(struct arphdr) + dev->addr_len + sizeof(u32) * 2;
+#endif
+ default:
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2;
+ }
}
#endif /* _LINUX_IF_ARP_H */
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index cfd21e3d5506..4474557904f6 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -112,6 +112,10 @@ struct team_mode_ops {
void (*port_disabled)(struct team *team, struct team_port *port);
};
+extern int team_modeop_port_enter(struct team *team, struct team_port *port);
+extern void team_modeop_port_change_dev_addr(struct team *team,
+ struct team_port *port);
+
enum team_option_type {
TEAM_OPTION_TYPE_U32,
TEAM_OPTION_TYPE_STRING,
@@ -236,7 +240,26 @@ static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
return NULL;
}
-extern int team_port_set_team_dev_addr(struct team_port *port);
+static inline struct team_port *
+team_get_first_port_txable_rcu(struct team *team, struct team_port *port)
+{
+ struct team_port *cur;
+
+ if (likely(team_port_txable(port)))
+ return port;
+ cur = port;
+ list_for_each_entry_continue_rcu(cur, &team->port_list, list)
+ if (team_port_txable(port))
+ return cur;
+ list_for_each_entry_rcu(cur, &team->port_list, list) {
+ if (cur == port)
+ break;
+ if (team_port_txable(port))
+ return cur;
+ }
+ return NULL;
+}
+
extern int team_options_register(struct team *team,
const struct team_option *option,
size_t option_count);
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 218a3b686d90..52bd03b38962 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -86,15 +86,15 @@ static inline int is_vlan_dev(struct net_device *dev)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
- u16 vlan_id);
+ __be16 vlan_proto, u16 vlan_id);
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
extern bool vlan_do_receive(struct sk_buff **skb);
extern struct sk_buff *vlan_untag(struct sk_buff *skb);
-extern int vlan_vid_add(struct net_device *dev, unsigned short vid);
-extern void vlan_vid_del(struct net_device *dev, unsigned short vid);
+extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid);
+extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid);
extern int vlan_vids_add_by_dev(struct net_device *dev,
const struct net_device *by_dev);
@@ -104,7 +104,8 @@ extern void vlan_vids_del_by_dev(struct net_device *dev,
extern bool vlan_uses_dev(const struct net_device *dev);
#else
static inline struct net_device *
-__vlan_find_dev_deep(struct net_device *real_dev, u16 vlan_id)
+__vlan_find_dev_deep(struct net_device *real_dev,
+ __be16 vlan_proto, u16 vlan_id)
{
return NULL;
}
@@ -131,12 +132,12 @@ static inline struct sk_buff *vlan_untag(struct sk_buff *skb)
return skb;
}
-static inline int vlan_vid_add(struct net_device *dev, unsigned short vid)
+static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)
{
return 0;
}
-static inline void vlan_vid_del(struct net_device *dev, unsigned short vid)
+static inline void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid)
{
}
@@ -157,9 +158,20 @@ static inline bool vlan_uses_dev(const struct net_device *dev)
}
#endif
+static inline bool vlan_hw_offload_capable(netdev_features_t features,
+ __be16 proto)
+{
+ if (proto == htons(ETH_P_8021Q) && features & NETIF_F_HW_VLAN_CTAG_TX)
+ return true;
+ if (proto == htons(ETH_P_8021AD) && features & NETIF_F_HW_VLAN_STAG_TX)
+ return true;
+ return false;
+}
+
/**
* vlan_insert_tag - regular VLAN tag inserting
* @skb: skbuff to tag
+ * @vlan_proto: VLAN encapsulation protocol
* @vlan_tci: VLAN TCI to insert
*
* Inserts the VLAN tag into @skb as part of the payload
@@ -170,7 +182,8 @@ static inline bool vlan_uses_dev(const struct net_device *dev)
*
* Does not change skb->protocol so this function can be used during receive.
*/
-static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
+static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
+ __be16 vlan_proto, u16 vlan_tci)
{
struct vlan_ethhdr *veth;
@@ -185,7 +198,7 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
skb->mac_header -= VLAN_HLEN;
/* first, the ethernet type */
- veth->h_vlan_proto = htons(ETH_P_8021Q);
+ veth->h_vlan_proto = vlan_proto;
/* now, the TCI */
veth->h_vlan_TCI = htons(vlan_tci);
@@ -204,24 +217,28 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, u16 vlan_tci)
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
*/
-static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
+static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb,
+ __be16 vlan_proto, u16 vlan_tci)
{
- skb = vlan_insert_tag(skb, vlan_tci);
+ skb = vlan_insert_tag(skb, vlan_proto, vlan_tci);
if (skb)
- skb->protocol = htons(ETH_P_8021Q);
+ skb->protocol = vlan_proto;
return skb;
}
/**
* __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting
* @skb: skbuff to tag
+ * @vlan_proto: VLAN encapsulation protocol
* @vlan_tci: VLAN TCI to insert
*
* Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest
*/
static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
+ __be16 vlan_proto,
u16 vlan_tci)
{
+ skb->vlan_proto = vlan_proto;
skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci;
return skb;
}
@@ -236,12 +253,13 @@ static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb,
* Assumes skb->dev is the target that will xmit this frame.
* Returns a VLAN tagged skb.
*/
-static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
+static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb,
+ __be16 vlan_proto, u16 vlan_tci)
{
- if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
- return __vlan_hwaccel_put_tag(skb, vlan_tci);
+ if (vlan_hw_offload_capable(skb->dev->features, vlan_proto)) {
+ return __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
} else {
- return __vlan_put_tag(skb, vlan_tci);
+ return __vlan_put_tag(skb, vlan_proto, vlan_tci);
}
}
@@ -256,9 +274,9 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
{
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
- if (veth->h_vlan_proto != htons(ETH_P_8021Q)) {
+ if (veth->h_vlan_proto != htons(ETH_P_8021Q) &&
+ veth->h_vlan_proto != htons(ETH_P_8021AD))
return -EINVAL;
- }
*vlan_tci = ntohs(veth->h_vlan_TCI);
return 0;
@@ -294,7 +312,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
*/
static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
{
- if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
+ if (skb->dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
return __vlan_hwaccel_get_tag(skb, vlan_tci);
} else {
return __vlan_get_tag(skb, vlan_tci);
@@ -339,7 +357,7 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
*/
proto = vhdr->h_vlan_encapsulated_proto;
- if (ntohs(proto) >= 1536) {
+ if (ntohs(proto) >= ETH_P_802_3_MIN) {
skb->protocol = proto;
return;
}
diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h
index 2e4eab9868a3..e7fdec4db9da 100644
--- a/include/linux/iio/adc/ad_sigma_delta.h
+++ b/include/linux/iio/adc/ad_sigma_delta.h
@@ -133,9 +133,9 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig);
.channel2 = (_channel2), \
.address = (_address), \
.extend_name = (_extend_name), \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = (_si), \
.scan_type = { \
.sign = 'u', \
diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
index 8bd12be0b02f..172c5b23cb84 100644
--- a/include/linux/iio/common/st_sensors.h
+++ b/include/linux/iio/common/st_sensors.h
@@ -15,6 +15,7 @@
#include <linux/spi/spi.h>
#include <linux/irqreturn.h>
#include <linux/iio/trigger.h>
+#include <linux/bitops.h>
#define ST_SENSORS_TX_MAX_LENGTH 2
#define ST_SENSORS_RX_MAX_LENGTH 6
@@ -45,8 +46,8 @@
{ \
.type = device_type, \
.modified = 1, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = index, \
.channel2 = mod, \
.address = addr, \
diff --git a/include/linux/iio/gyro/itg3200.h b/include/linux/iio/gyro/itg3200.h
index c53f16914b77..2a820850f284 100644
--- a/include/linux/iio/gyro/itg3200.h
+++ b/include/linux/iio/gyro/itg3200.h
@@ -149,6 +149,6 @@ static inline void itg3200_buffer_unconfigure(struct iio_dev *indio_dev)
{
}
-#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* CONFIG_IIO_BUFFER */
#endif /* ITG3200_H_ */
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index da8c776ba0bd..8d171f427632 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -38,76 +38,6 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_HYSTERESIS,
};
-#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
-#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
-#define IIO_CHAN_INFO_BITS(type) (IIO_CHAN_INFO_SHARED_BIT(type) | \
- IIO_CHAN_INFO_SEPARATE_BIT(type))
-
-#define IIO_CHAN_INFO_RAW_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
-#define IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PROCESSED)
-#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_SCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
-#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_OFFSET_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
-#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
-#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
-#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAK_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
-#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT( \
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT( \
- IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT( \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT( \
- IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
-#define IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SAMP_FREQ)
-#define IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SAMP_FREQ)
-#define IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_FREQUENCY)
-#define IIO_CHAN_INFO_FREQUENCY_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_FREQUENCY)
-#define IIO_CHAN_INFO_PHASE_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PHASE)
-#define IIO_CHAN_INFO_PHASE_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PHASE)
-#define IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
-#define IIO_CHAN_INFO_HARDWAREGAIN_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
-#define IIO_CHAN_INFO_HYSTERESIS_SEPARATE_BIT \
- IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HYSTERESIS)
-#define IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT \
- IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HYSTERESIS)
-
enum iio_endian {
IIO_CPU,
IIO_BE,
@@ -218,6 +148,10 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
* endianness: little or big endian
* @info_mask: What information is to be exported about this channel.
* This includes calibbias, scale etc.
+ * @info_mask_separate: What information is to be exported that is specific to
+ * this channel.
+ * @info_mask_shared_by_type: What information is to be exported that is shared
+* by all channels of the same type.
* @event_mask: What events can this channel produce.
* @ext_info: Array of extended info attributes for this channel.
* The array is NULL terminated, the last element should
@@ -253,6 +187,8 @@ struct iio_chan_spec {
enum iio_endian endianness;
} scan_type;
long info_mask;
+ long info_mask_separate;
+ long info_mask_shared_by_type;
long event_mask;
const struct iio_chan_spec_ext_info *ext_info;
const char *extend_name;
@@ -275,7 +211,8 @@ struct iio_chan_spec {
static inline bool iio_channel_has_info(const struct iio_chan_spec *chan,
enum iio_chan_info_enum type)
{
- return chan->info_mask & IIO_CHAN_INFO_BITS(type);
+ return (chan->info_mask_separate & type) |
+ (chan->info_mask_shared_by_type & type);
}
#define IIO_ST(si, rb, sb, sh) \
diff --git a/include/linux/iio/imu/adis.h b/include/linux/iio/imu/adis.h
index ff781dca2e9a..b665dc7f017b 100644
--- a/include/linux/iio/imu/adis.h
+++ b/include/linux/iio/imu/adis.h
@@ -162,8 +162,8 @@ int adis_single_conversion(struct iio_dev *indio_dev,
.indexed = 1, \
.channel = (chan), \
.extend_name = name, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
@@ -184,9 +184,9 @@ int adis_single_conversion(struct iio_dev *indio_dev,
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
@@ -197,13 +197,13 @@ int adis_single_conversion(struct iio_dev *indio_dev,
}, \
}
-#define ADIS_MOD_CHAN(_type, mod, addr, si, info, bits) { \
+#define ADIS_MOD_CHAN(_type, mod, addr, si, info_sep, bits) { \
.type = (_type), \
.modified = 1, \
.channel2 = IIO_MOD_ ## mod, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SHARED_BIT | \
- info, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ info_sep, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (addr), \
.scan_index = (si), \
.scan_type = { \
@@ -214,17 +214,17 @@ int adis_single_conversion(struct iio_dev *indio_dev,
}, \
}
-#define ADIS_ACCEL_CHAN(mod, addr, si, info, bits) \
- ADIS_MOD_CHAN(IIO_ACCEL, mod, addr, si, info, bits)
+#define ADIS_ACCEL_CHAN(mod, addr, si, info_sep, bits) \
+ ADIS_MOD_CHAN(IIO_ACCEL, mod, addr, si, info_sep, bits)
-#define ADIS_GYRO_CHAN(mod, addr, si, info, bits) \
- ADIS_MOD_CHAN(IIO_ANGL_VEL, mod, addr, si, info, bits)
+#define ADIS_GYRO_CHAN(mod, addr, si, info_sep, bits) \
+ ADIS_MOD_CHAN(IIO_ANGL_VEL, mod, addr, si, info_sep, bits)
-#define ADIS_INCLI_CHAN(mod, addr, si, info, bits) \
- ADIS_MOD_CHAN(IIO_INCLI, mod, addr, si, info, bits)
+#define ADIS_INCLI_CHAN(mod, addr, si, info_sep, bits) \
+ ADIS_MOD_CHAN(IIO_INCLI, mod, addr, si, info_sep, bits)
-#define ADIS_ROT_CHAN(mod, addr, si, info, bits) \
- ADIS_MOD_CHAN(IIO_ROT, mod, addr, si, info, bits)
+#define ADIS_ROT_CHAN(mod, addr, si, info_sep, bits) \
+ ADIS_MOD_CHAN(IIO_ROT, mod, addr, si, info_sep, bits)
#ifdef CONFIG_IIO_ADIS_LIB_BUFFER
diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h
index c66e0a96f6e8..3869c525b052 100644
--- a/include/linux/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -44,7 +44,6 @@ struct iio_trigger_ops {
* @id: [INTERN] unique id number
* @name: [DRIVER] unique name
* @dev: [DRIVER] associated device (if relevant)
- * @private_data: [DRIVER] device specific data
* @list: [INTERN] used in maintenance of global trigger list
* @alloc_list: [DRIVER] used for driver specific trigger list
* @use_count: use count for the trigger
@@ -60,7 +59,6 @@ struct iio_trigger {
const char *name;
struct device dev;
- void *private_data;
struct list_head list;
struct list_head alloc_list;
int use_count;
@@ -92,6 +90,30 @@ static inline void iio_trigger_get(struct iio_trigger *trig)
}
/**
+ * iio_device_set_drvdata() - Set trigger driver data
+ * @trig: IIO trigger structure
+ * @data: Driver specific data
+ *
+ * Allows to attach an arbitrary pointer to an IIO trigger, which can later be
+ * retrieved by iio_trigger_get_drvdata().
+ */
+static inline void iio_trigger_set_drvdata(struct iio_trigger *trig, void *data)
+{
+ dev_set_drvdata(&trig->dev, data);
+}
+
+/**
+ * iio_trigger_get_drvdata() - Get trigger driver data
+ * @trig: IIO trigger structure
+ *
+ * Returns the data previously set with iio_trigger_set_drvdata()
+ */
+static inline void *iio_trigger_get_drvdata(struct iio_trigger *trig)
+{
+ return dev_get_drvdata(&trig->dev);
+}
+
+/**
* iio_trigger_register() - register a trigger with the IIO core
* @trig_info: trigger to be registered
**/
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 86c361e947b9..1b7f268cddce 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -46,7 +46,7 @@ static inline int ima_module_check(struct file *file)
return 0;
}
-#endif /* CONFIG_IMA_H */
+#endif /* CONFIG_IMA */
#ifdef CONFIG_IMA_APPRAISE
extern void ima_inode_post_setattr(struct dentry *dentry);
@@ -72,5 +72,5 @@ static inline int ima_inode_removexattr(struct dentry *dentry,
{
return 0;
}
-#endif /* CONFIG_IMA_APPRAISE_H */
+#endif /* CONFIG_IMA_APPRAISE */
#endif /* _LINUX_IMA_H */
diff --git a/include/linux/input/auo-pixcir-ts.h b/include/linux/input/auo-pixcir-ts.h
index 75d4be717714..5049f21928e4 100644
--- a/include/linux/input/auo-pixcir-ts.h
+++ b/include/linux/input/auo-pixcir-ts.h
@@ -43,12 +43,10 @@
*/
struct auo_pixcir_ts_platdata {
int gpio_int;
+ int gpio_rst;
int int_setting;
- void (*init_hw)(struct i2c_client *);
- void (*exit_hw)(struct i2c_client *);
-
unsigned int x_max;
unsigned int y_max;
};
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h
index 2e86bd0bfba1..1b1dfa80d9ff 100644
--- a/include/linux/input/mt.h
+++ b/include/linux/input/mt.h
@@ -19,6 +19,7 @@
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
+#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */
/**
* struct input_mt_slot - represents the state of an input MT slot
diff --git a/include/linux/integrity.h b/include/linux/integrity.h
index 66c5fe9550a5..83222cebd47b 100644
--- a/include/linux/integrity.h
+++ b/include/linux/integrity.h
@@ -36,5 +36,5 @@ static inline void integrity_inode_free(struct inode *inode)
{
return;
}
-#endif /* CONFIG_INTEGRITY_H */
+#endif /* CONFIG_INTEGRITY */
#endif /* _LINUX_INTEGRITY_H */
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 85ac9b9b72a2..89b7c24a36e9 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -192,6 +192,10 @@ extern struct resource * __request_region(struct resource *,
extern int __check_region(struct resource *, resource_size_t, resource_size_t);
extern void __release_region(struct resource *, resource_size_t,
resource_size_t);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+extern int release_mem_region_adjustable(struct resource *, resource_size_t,
+ resource_size_t);
+#endif
static inline int __deprecated check_region(resource_size_t s,
resource_size_t n)
diff --git a/include/linux/ipack.h b/include/linux/ipack.h
index fea12cbb2aeb..1888e06ddf64 100644
--- a/include/linux/ipack.h
+++ b/include/linux/ipack.h
@@ -207,19 +207,41 @@ int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
void ipack_driver_unregister(struct ipack_driver *edrv);
/**
- * ipack_device_register -- register an IPack device with the kernel
- * @dev: the new device to register.
+ * ipack_device_init -- initialize an IPack device
+ * @dev: the new device to initialize.
*
- * Register a new IPack device ("module" in IndustryPack jargon). The call
- * is done by the carrier driver. The carrier should populate the fields
- * bus and slot as well as the region array of @dev prior to calling this
- * function. The rest of the fields will be allocated and populated
- * during registration.
+ * Initialize a new IPack device ("module" in IndustryPack jargon). The call
+ * is done by the carrier driver. The carrier should populate the fields
+ * bus and slot as well as the region array of @dev prior to calling this
+ * function. The rest of the fields will be allocated and populated
+ * during initalization.
*
- * Return zero on success or error code on failure.
+ * Return zero on success or error code on failure.
+ *
+ * NOTE: _Never_ directly free @dev after calling this function, even
+ * if it returned an error! Always use ipack_put_device() to give up the
+ * reference initialized in this function instead.
+ */
+int ipack_device_init(struct ipack_device *dev);
+
+/**
+ * ipack_device_add -- Add an IPack device
+ * @dev: the new device to add.
+ *
+ * Add a new IPack device. The call is done by the carrier driver
+ * after calling ipack_device_init().
+ *
+ * Return zero on success or error code on failure.
+ *
+ * NOTE: _Never_ directly free @dev after calling this function, even
+ * if it returned an error! Always use ipack_put_device() to give up the
+ * reference initialized in this function instead.
*/
-int ipack_device_register(struct ipack_device *dev);
-void ipack_device_unregister(struct ipack_device *dev);
+int ipack_device_add(struct ipack_device *dev);
+void ipack_device_del(struct ipack_device *dev);
+
+void ipack_get_device(struct ipack_device *dev);
+void ipack_put_device(struct ipack_device *dev);
/**
* DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index ae221a7b5092..c4d870b0d5e6 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -43,8 +43,8 @@ struct ipc_namespace {
size_t shm_ctlmax;
size_t shm_ctlall;
+ unsigned long shm_tot;
int shm_ctlmni;
- int shm_tot;
/*
* Defines whether IPC_RMID is forced for _all_ shm segments regardless
* of shmctl()
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 50e5a5e6a712..6e051f472edb 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -480,6 +480,7 @@ struct transaction_s
T_COMMIT,
T_COMMIT_DFLUSH,
T_COMMIT_JFLUSH,
+ T_COMMIT_CALLBACK,
T_FINISHED
} t_state;
@@ -1144,7 +1145,7 @@ extern struct kmem_cache *jbd2_handle_cache;
static inline handle_t *jbd2_alloc_handle(gfp_t gfp_flags)
{
- return kmem_cache_alloc(jbd2_handle_cache, gfp_flags);
+ return kmem_cache_zalloc(jbd2_handle_cache, gfp_flags);
}
static inline void jbd2_free_handle(handle_t *handle)
@@ -1200,6 +1201,7 @@ int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
int jbd2_journal_force_commit_nested(journal_t *journal);
int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
+int jbd2_complete_transaction(journal_t *journal, tid_t tid);
int jbd2_log_do_checkpoint(journal_t *journal);
int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid);
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 82ed068b1ebe..8fb8edf12417 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -75,7 +75,6 @@ extern int register_refined_jiffies(long clock_tick_rate);
*/
extern u64 __jiffy_data jiffies_64;
extern unsigned long volatile __jiffy_data jiffies;
-extern seqlock_t jiffies_lock;
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h
index c18b46f8aeeb..13a3da25ff07 100644
--- a/include/linux/journal-head.h
+++ b/include/linux/journal-head.h
@@ -31,21 +31,14 @@ struct journal_head {
/*
* Journalling list for this buffer [jbd_lock_bh_state()]
*/
- unsigned b_jlist;
+ unsigned b_jlist:4;
/*
* This flag signals the buffer has been modified by
* the currently running transaction
* [jbd_lock_bh_state()]
*/
- unsigned b_modified;
-
- /*
- * This feild tracks the last transaction id in which this buffer
- * has been cowed
- * [jbd_lock_bh_state()]
- */
- tid_t b_cow_tid;
+ unsigned b_modified:1;
/*
* Copy of the buffer data frozen for writing to the log.
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 79fdd80a42d4..6d1844f393c0 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -486,6 +486,8 @@ enum ftrace_dump_mode {
void tracing_on(void);
void tracing_off(void);
int tracing_is_on(void);
+void tracing_snapshot(void);
+void tracing_snapshot_alloc(void);
extern void tracing_start(void);
extern void tracing_stop(void);
@@ -515,10 +517,32 @@ do { \
*
* This is intended as a debugging tool for the developer only.
* Please refrain from leaving trace_printks scattered around in
- * your code.
+ * your code. (Extra memory is used for special buffers that are
+ * allocated when trace_printk() is used)
+ *
+ * A little optization trick is done here. If there's only one
+ * argument, there's no need to scan the string for printf formats.
+ * The trace_puts() will suffice. But how can we take advantage of
+ * using trace_puts() when trace_printk() has only one argument?
+ * By stringifying the args and checking the size we can tell
+ * whether or not there are args. __stringify((__VA_ARGS__)) will
+ * turn into "()\0" with a size of 3 when there are no args, anything
+ * else will be bigger. All we need to do is define a string to this,
+ * and then take its size and compare to 3. If it's bigger, use
+ * do_trace_printk() otherwise, optimize it to trace_puts(). Then just
+ * let gcc optimize the rest.
*/
-#define trace_printk(fmt, args...) \
+#define trace_printk(fmt, ...) \
+do { \
+ char _______STR[] = __stringify((__VA_ARGS__)); \
+ if (sizeof(_______STR) > 3) \
+ do_trace_printk(fmt, ##__VA_ARGS__); \
+ else \
+ trace_puts(fmt); \
+} while (0)
+
+#define do_trace_printk(fmt, args...) \
do { \
static const char *trace_printk_fmt \
__attribute__((section("__trace_printk_fmt"))) = \
@@ -538,7 +562,45 @@ int __trace_bprintk(unsigned long ip, const char *fmt, ...);
extern __printf(2, 3)
int __trace_printk(unsigned long ip, const char *fmt, ...);
-extern void trace_dump_stack(void);
+/**
+ * trace_puts - write a string into the ftrace buffer
+ * @str: the string to record
+ *
+ * Note: __trace_bputs is an internal function for trace_puts and
+ * the @ip is passed in via the trace_puts macro.
+ *
+ * This is similar to trace_printk() but is made for those really fast
+ * paths that a developer wants the least amount of "Heisenbug" affects,
+ * where the processing of the print format is still too much.
+ *
+ * This function allows a kernel developer to debug fast path sections
+ * that printk is not appropriate for. By scattering in various
+ * printk like tracing in the code, a developer can quickly see
+ * where problems are occurring.
+ *
+ * This is intended as a debugging tool for the developer only.
+ * Please refrain from leaving trace_puts scattered around in
+ * your code. (Extra memory is used for special buffers that are
+ * allocated when trace_puts() is used)
+ *
+ * Returns: 0 if nothing was written, positive # if string was.
+ * (1 when __trace_bputs is used, strlen(str) when __trace_puts is used)
+ */
+
+extern int __trace_bputs(unsigned long ip, const char *str);
+extern int __trace_puts(unsigned long ip, const char *str, int size);
+#define trace_puts(str) ({ \
+ static const char *trace_printk_fmt \
+ __attribute__((section("__trace_printk_fmt"))) = \
+ __builtin_constant_p(str) ? str : NULL; \
+ \
+ if (__builtin_constant_p(str)) \
+ __trace_bputs(_THIS_IP_, trace_printk_fmt); \
+ else \
+ __trace_puts(_THIS_IP_, str, strlen(str)); \
+})
+
+extern void trace_dump_stack(int skip);
/*
* The double __builtin_constant_p is because gcc will give us an error
@@ -573,6 +635,8 @@ static inline void trace_dump_stack(void) { }
static inline void tracing_on(void) { }
static inline void tracing_off(void) { }
static inline int tracing_is_on(void) { return 0; }
+static inline void tracing_snapshot(void) { }
+static inline void tracing_snapshot_alloc(void) { }
static inline __printf(1, 2)
int trace_printk(const char *fmt, ...)
@@ -734,6 +798,4 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
# define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD
#endif
-extern int do_sysinfo(struct sysinfo *info);
-
#endif
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index d2e6927bbaae..d78d28a733b1 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -200,6 +200,8 @@ extern size_t vmcoreinfo_max_size;
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base);
+int parse_crashkernel_high(char *cmdline, unsigned long long system_ram,
+ unsigned long long *crash_size, unsigned long long *crash_base);
int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base);
int crash_shrink_memory(unsigned long new_size);
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 5398d5807075..0555cc66a15b 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -67,16 +67,15 @@ struct subprocess_info {
};
extern int
-call_usermodehelper_fns(char *path, char **argv, char **envp, int wait,
- int (*init)(struct subprocess_info *info, struct cred *new),
- void (*cleanup)(struct subprocess_info *), void *data);
+call_usermodehelper(char *path, char **argv, char **envp, int wait);
-static inline int
-call_usermodehelper(char *path, char **argv, char **envp, int wait)
-{
- return call_usermodehelper_fns(path, argv, envp, wait,
- NULL, NULL, NULL);
-}
+extern struct subprocess_info *
+call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask,
+ int (*init)(struct subprocess_info *info, struct cred *new),
+ void (*cleanup)(struct subprocess_info *), void *data);
+
+extern int
+call_usermodehelper_exec(struct subprocess_info *info, int wait);
extern struct ctl_table usermodehelper_table[];
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 4b6ef4d33cc2..ca1d27a0d6a6 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -29,6 +29,7 @@
* <jkenisto@us.ibm.com> and Prasanna S Panchamukhi
* <prasanna@in.ibm.com> added function-return probes.
*/
+#include <linux/compiler.h> /* for __kprobes */
#include <linux/linkage.h>
#include <linux/list.h>
#include <linux/notifier.h>
@@ -49,16 +50,11 @@
#define KPROBE_REENTER 0x00000004
#define KPROBE_HIT_SSDONE 0x00000008
-/* Attach to insert probes on any functions which should be ignored*/
-#define __kprobes __attribute__((__section__(".kprobes.text")))
-
#else /* CONFIG_KPROBES */
typedef int kprobe_opcode_t;
struct arch_specific_insn {
int dummy;
};
-#define __kprobes
-
#endif /* CONFIG_KPROBES */
struct kprobe;
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 8d816646f766..7dcef3317689 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -43,6 +43,7 @@ bool kthread_should_stop(void);
bool kthread_should_park(void);
bool kthread_freezable_should_stop(bool *was_frozen);
void *kthread_data(struct task_struct *k);
+void *probe_kthread_data(struct task_struct *k);
int kthread_park(struct task_struct *k);
void kthread_unpark(struct task_struct *k);
void kthread_parkme(void);
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index e83512f63df5..bbca12804d12 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -330,6 +330,24 @@ static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec)
extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs);
+/**
+ * ktime_to_timespec_cond - convert a ktime_t variable to timespec
+ * format only if the variable contains data
+ * @kt: the ktime_t variable to convert
+ * @ts: the timespec variable to store the result in
+ *
+ * Returns true if there was a successful conversion, false if kt was 0.
+ */
+static inline bool ktime_to_timespec_cond(const ktime_t kt, struct timespec *ts)
+{
+ if (kt.tv64) {
+ *ts = ktime_to_timespec(kt);
+ return true;
+ } else {
+ return false;
+ }
+}
+
/*
* The resolution of the clocks. The resolution value is returned in
* the clock_getres() system call to give application programmers an
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index cad77fe09d77..c13958251927 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -518,7 +518,7 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
void *data, unsigned long len);
int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
- gpa_t gpa);
+ gpa_t gpa, unsigned long len);
int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);
struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index fa7cc7244cbd..b0bcce0ddc95 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -71,6 +71,7 @@ struct gfn_to_hva_cache {
u64 generation;
gpa_t gpa;
unsigned long hva;
+ unsigned long len;
struct kvm_memory_slot *memslot;
};
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 91c9d109e5f1..eae7a053dc51 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -398,6 +398,7 @@ enum {
ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */
ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */
ATA_HORKAGE_DUMP_ID = (1 << 16), /* dump IDENTIFY data */
+ ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17), /* Set max sects to 65535 */
/* DMA mask for user DMA control: User visible values; DO NOT
renumber */
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 807f1e533226..de09dec25ec3 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -2,6 +2,7 @@
#define _LINUX_LINKAGE_H
#include <linux/compiler.h>
+#include <linux/stringify.h>
#include <asm/linkage.h>
#ifdef __cplusplus
@@ -14,6 +15,23 @@
#define asmlinkage CPP_ASMLINKAGE
#endif
+#ifdef CONFIG_SYMBOL_PREFIX
+#define __SYMBOL_NAME(x) CONFIG_SYMBOL_PREFIX __stringify(x)
+#else
+#define __SYMBOL_NAME(x) __stringify(x)
+#endif
+
+#ifndef cond_syscall
+#define cond_syscall(x) asm(".weak\t" __SYMBOL_NAME(x) \
+ "\n\t.set\t" __SYMBOL_NAME(x) "," __SYMBOL_NAME(sys_ni_syscall));
+#endif
+
+#ifndef SYSCALL_ALIAS
+#define SYSCALL_ALIAS(alias, name) \
+ asm ("\t.globl " __SYMBOL_NAME(alias) \
+ "\n\t.set\t" __SYMBOL_NAME(alias) "," __SYMBOL_NAME(name))
+#endif
+
#define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE)
#define __page_aligned_bss __section(.bss..page_aligned) __aligned(PAGE_SIZE)
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index 31f9d75adc5b..2eb88556c5c5 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -125,6 +125,11 @@ static inline void hlist_bl_unlock(struct hlist_bl_head *b)
__bit_spin_unlock(0, (unsigned long *)b);
}
+static inline bool hlist_bl_is_locked(struct hlist_bl_head *b)
+{
+ return bit_spin_is_locked(0, (unsigned long *)b);
+}
+
/**
* hlist_bl_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
diff --git a/include/linux/math64.h b/include/linux/math64.h
index b8ba85544721..931a619407bf 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -30,6 +30,15 @@ static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
}
/**
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
* div64_u64 - unsigned 64bit divide with 64bit divisor
*/
static inline u64 div64_u64(u64 dividend, u64 divisor)
@@ -61,8 +70,16 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
#endif
+#ifndef div64_u64_rem
+extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder);
+#endif
+
#ifndef div64_u64
-extern u64 div64_u64(u64 dividend, u64 divisor);
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+ u64 remainder;
+ return div64_u64_rem(dividend, divisor, &remainder);
+}
#endif
#ifndef div64_s64
diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
new file mode 100644
index 000000000000..d14af7b722ef
--- /dev/null
+++ b/include/linux/mei_cl_bus.h
@@ -0,0 +1,44 @@
+#ifndef _LINUX_MEI_CL_BUS_H
+#define _LINUX_MEI_CL_BUS_H
+
+#include <linux/device.h>
+#include <linux/uuid.h>
+
+struct mei_cl_device;
+
+struct mei_cl_driver {
+ struct device_driver driver;
+ const char *name;
+
+ const struct mei_cl_device_id *id_table;
+
+ int (*probe)(struct mei_cl_device *dev,
+ const struct mei_cl_device_id *id);
+ int (*remove)(struct mei_cl_device *dev);
+};
+
+int __mei_cl_driver_register(struct mei_cl_driver *driver,
+ struct module *owner);
+#define mei_cl_driver_register(driver) \
+ __mei_cl_driver_register(driver, THIS_MODULE)
+
+void mei_cl_driver_unregister(struct mei_cl_driver *driver);
+
+int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length);
+int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length);
+
+typedef void (*mei_cl_event_cb_t)(struct mei_cl_device *device,
+ u32 events, void *context);
+int mei_cl_register_event_cb(struct mei_cl_device *device,
+ mei_cl_event_cb_t read_cb, void *context);
+
+#define MEI_CL_EVENT_RX 0
+#define MEI_CL_EVENT_TX 1
+
+void *mei_cl_get_drvdata(const struct mei_cl_device *device);
+void mei_cl_set_drvdata(struct mei_cl_device *device, void *data);
+
+int mei_cl_enable_device(struct mei_cl_device *device);
+int mei_cl_disable_device(struct mei_cl_device *device);
+
+#endif /* _LINUX_MEI_CL_BUS_H */
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 45e93b468878..85c31a8e2904 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -18,6 +18,7 @@
#include <linux/node.h>
#include <linux/compiler.h>
#include <linux/mutex.h>
+#include <linux/notifier.h>
#define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS)
@@ -114,9 +115,10 @@ extern void unregister_memory_notifier(struct notifier_block *nb);
extern int register_memory_isolate_notifier(struct notifier_block *nb);
extern void unregister_memory_isolate_notifier(struct notifier_block *nb);
extern int register_new_memory(int, struct mem_section *);
+#ifdef CONFIG_MEMORY_HOTREMOVE
extern int unregister_memory_section(struct mem_section *);
+#endif
extern int memory_dev_init(void);
-extern int remove_memory_block(unsigned long, struct mem_section *, int);
extern int memory_notify(unsigned long val, void *v);
extern int memory_isolate_notify(unsigned long val, void *v);
extern struct memory_block *find_memory_block_hinted(struct mem_section *,
@@ -127,13 +129,18 @@ enum mem_add_context { BOOT, HOTPLUG };
#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
#ifdef CONFIG_MEMORY_HOTPLUG
-#define hotplug_memory_notifier(fn, pri) { \
+#define hotplug_memory_notifier(fn, pri) ({ \
static __meminitdata struct notifier_block fn##_mem_nb =\
- { .notifier_call = fn, .priority = pri }; \
+ { .notifier_call = fn, .priority = pri };\
register_memory_notifier(&fn##_mem_nb); \
-}
+})
+#define register_hotmemory_notifier(nb) register_memory_notifier(nb)
+#define unregister_hotmemory_notifier(nb) unregister_memory_notifier(nb)
#else
-#define hotplug_memory_notifier(fn, pri) do { } while (0)
+#define hotplug_memory_notifier(fn, pri) ({ 0; })
+/* These aren't inline functions due to a GCC bug. */
+#define register_hotmemory_notifier(nb) ({ (void)(nb); 0; })
+#define unregister_hotmemory_notifier(nb) ({ (void)(nb); })
#endif
/*
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index b6a3be7d47bf..3e622c610925 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -97,13 +97,13 @@ extern void __online_page_free(struct page *page);
#ifdef CONFIG_MEMORY_HOTREMOVE
extern bool is_pageblock_removable_nolock(struct page *page);
extern int arch_remove_memory(u64 start, u64 size);
+extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
+ unsigned long nr_pages);
#endif /* CONFIG_MEMORY_HOTREMOVE */
/* reasonably generic interface to expand the physical pages in a zone */
extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn,
unsigned long nr_pages);
-extern int __remove_pages(struct zone *zone, unsigned long start_pfn,
- unsigned long nr_pages);
#ifdef CONFIG_NUMA
extern int memory_add_physaddr_to_nid(u64 start);
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index 9ead60bc66b7..3301b2031c8d 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -89,6 +89,11 @@ struct abx500_fg;
* points.
* @maint_thres This is the threshold where we stop reporting
* battery full while in maintenance, in per cent
+ * @pcut_enable: Enable power cut feature in ab8505
+ * @pcut_max_time: Max time threshold
+ * @pcut_flag_time: Flagtime threshold
+ * @pcut_max_restart: Max number of restarts
+ * @pcut_debounce_time: Sets battery debounce time
*/
struct abx500_fg_parameters {
int recovery_sleep_timer;
@@ -106,6 +111,11 @@ struct abx500_fg_parameters {
int battok_raising_th_sel1;
int user_cap_limit;
int maint_thres;
+ bool pcut_enable;
+ u8 pcut_max_time;
+ u8 pcut_flag_time;
+ u8 pcut_max_restart;
+ u8 pcut_debounce_time;
};
/**
@@ -173,11 +183,11 @@ struct abx500_battery_type {
int low_high_vol_lvl;
int battery_resistance;
int n_temp_tbl_elements;
- struct abx500_res_to_temp *r_to_t_tbl;
+ const struct abx500_res_to_temp *r_to_t_tbl;
int n_v_cap_tbl_elements;
- struct abx500_v_to_cap *v_to_cap_tbl;
+ const struct abx500_v_to_cap *v_to_cap_tbl;
int n_batres_tbl_elements;
- struct batres_vs_temp *batres_tbl;
+ const struct batres_vs_temp *batres_tbl;
};
/**
@@ -236,7 +246,11 @@ struct abx500_bm_charger_parameters {
* @interval_not_charging charge alg cycle period time when not charging (sec)
* @temp_hysteresis temperature hysteresis
* @gnd_lift_resistance Battery ground to phone ground resistance (mOhm)
- * @maxi: maximization parameters
+ * @n_chg_out_curr number of elements in array chg_output_curr
+ * @n_chg_in_curr number of elements in array chg_input_curr
+ * @chg_output_curr charger output current level map
+ * @chg_input_curr charger input current level map
+ * @maxi maximization parameters
* @cap_levels capacity in percent for the different capacity levels
* @bat_type table of supported battery types
* @chg_params charger parameters
@@ -257,6 +271,7 @@ struct abx500_bm_data {
bool autopower_cfg;
bool ac_enabled;
bool usb_enabled;
+ bool usb_power_path;
bool no_maintenance;
bool capacity_scaling;
bool chg_unknown_bat;
@@ -270,6 +285,10 @@ struct abx500_bm_data {
int interval_not_charging;
int temp_hysteresis;
int gnd_lift_resistance;
+ int n_chg_out_curr;
+ int n_chg_in_curr;
+ int *chg_output_curr;
+ int *chg_input_curr;
const struct abx500_maxim_parameters *maxi;
const struct abx500_bm_capacity_levels *cap_levels;
struct abx500_battery_type *bat_type;
diff --git a/include/linux/mfd/abx500/ab8500-bm.h b/include/linux/mfd/abx500/ab8500-bm.h
index 8d35bfe164c8..cc892a8d8d6e 100644
--- a/include/linux/mfd/abx500/ab8500-bm.h
+++ b/include/linux/mfd/abx500/ab8500-bm.h
@@ -23,6 +23,7 @@
* Bank : 0x5
*/
#define AB8500_USB_LINE_STAT_REG 0x80
+#define AB8500_USB_LINE_CTRL2_REG 0x82
#define AB8500_USB_LINK1_STAT_REG 0x94
/*
@@ -33,7 +34,7 @@
#define AB8500_CH_STATUS2_REG 0x01
#define AB8500_CH_USBCH_STAT1_REG 0x02
#define AB8500_CH_USBCH_STAT2_REG 0x03
-#define AB8500_CH_FSM_STAT_REG 0x04
+#define AB8540_CH_USBCH_STAT3_REG 0x04
#define AB8500_CH_STAT_REG 0x05
/*
@@ -69,6 +70,8 @@
#define AB8500_USBCH_CTRL1_REG 0xC0
#define AB8500_USBCH_CTRL2_REG 0xC1
#define AB8500_USBCH_IPT_CRNTLVL_REG 0xC2
+#define AB8540_USB_PP_MODE_REG 0xC5
+#define AB8540_USB_PP_CHR_REG 0xC6
/*
* Gas Gauge register offsets
@@ -105,6 +108,7 @@
#define AB8500_RTC_BACKUP_CHG_REG 0x0C
#define AB8500_RTC_CC_CONF_REG 0x01
#define AB8500_RTC_CTRL_REG 0x0B
+#define AB8500_RTC_CTRL1_REG 0x11
/*
* OTP register offsets
@@ -154,6 +158,7 @@
#define CH_OP_CUR_LVL_1P4 0x0D
#define CH_OP_CUR_LVL_1P5 0x0E
#define CH_OP_CUR_LVL_1P6 0x0F
+#define CH_OP_CUR_LVL_2P 0x3F
/* BTEMP High thermal limits */
#define BTEMP_HIGH_TH_57_0 0x00
@@ -179,10 +184,25 @@
#define BUP_ICH_SEL_300UA 0x08
#define BUP_ICH_SEL_700UA 0x0C
-#define BUP_VCH_SEL_2P5V 0x00
-#define BUP_VCH_SEL_2P6V 0x01
-#define BUP_VCH_SEL_2P8V 0x02
-#define BUP_VCH_SEL_3P1V 0x03
+enum bup_vch_sel {
+ BUP_VCH_SEL_2P5V,
+ BUP_VCH_SEL_2P6V,
+ BUP_VCH_SEL_2P8V,
+ BUP_VCH_SEL_3P1V,
+ /*
+ * Note that the following 5 values 2.7v, 2.9v, 3.0v, 3.2v, 3.3v
+ * are only available on ab8540. You can't choose these 5
+ * voltage on ab8500/ab8505/ab9540.
+ */
+ BUP_VCH_SEL_2P7V,
+ BUP_VCH_SEL_2P9V,
+ BUP_VCH_SEL_3P0V,
+ BUP_VCH_SEL_3P2V,
+ BUP_VCH_SEL_3P3V,
+};
+
+#define BUP_VCH_RANGE 0x02
+#define VBUP33_VRTCN 0x01
/* Battery OVV constants */
#define BATT_OVV_ENA 0x02
@@ -228,6 +248,8 @@
#define BAT_CTRL_20U_ENA 0x02
#define BAT_CTRL_18U_ENA 0x01
#define BAT_CTRL_16U_ENA 0x02
+#define BAT_CTRL_60U_ENA 0x01
+#define BAT_CTRL_120U_ENA 0x02
#define BAT_CTRL_CMP_ENA 0x04
#define FORCE_BAT_CTRL_CMP_HIGH 0x08
#define BAT_CTRL_PULL_UP_ENA 0x10
@@ -235,6 +257,24 @@
/* Battery type */
#define BATTERY_UNKNOWN 00
+/* Registers for pcut feature in ab8505 and ab9540 */
+#define AB8505_RTC_PCUT_CTL_STATUS_REG 0x12
+#define AB8505_RTC_PCUT_TIME_REG 0x13
+#define AB8505_RTC_PCUT_MAX_TIME_REG 0x14
+#define AB8505_RTC_PCUT_FLAG_TIME_REG 0x15
+#define AB8505_RTC_PCUT_RESTART_REG 0x16
+#define AB8505_RTC_PCUT_DEBOUNCE_REG 0x17
+
+/* USB Power Path constants for ab8540 */
+#define BUS_VSYS_VOL_SELECT_MASK 0x06
+#define BUS_VSYS_VOL_SELECT_3P6V 0x00
+#define BUS_VSYS_VOL_SELECT_3P325V 0x02
+#define BUS_VSYS_VOL_SELECT_3P9V 0x04
+#define BUS_VSYS_VOL_SELECT_4P3V 0x06
+#define BUS_POWER_PATH_MODE_ENA 0x01
+#define BUS_PP_PRECHG_CURRENT_MASK 0x0E
+#define BUS_POWER_PATH_PRECHG_ENA 0x01
+
/**
* struct res_to_temp - defines one point in a temp to res curve. To
* be used in battery packs that combines the identification resistor with a
@@ -283,6 +323,11 @@ struct ab8500_fg;
* points.
* @maint_thres This is the threshold where we stop reporting
* battery full while in maintenance, in per cent
+ * @pcut_enable: Enable power cut feature in ab8505
+ * @pcut_max_time: Max time threshold
+ * @pcut_flag_time: Flagtime threshold
+ * @pcut_max_restart: Max number of restarts
+ * @pcut_debunce_time: Sets battery debounce time
*/
struct ab8500_fg_parameters {
int recovery_sleep_timer;
@@ -299,6 +344,11 @@ struct ab8500_fg_parameters {
int battok_raising_th_sel1;
int user_cap_limit;
int maint_thres;
+ bool pcut_enable;
+ u8 pcut_max_time;
+ u8 pcut_flag_time;
+ u8 pcut_max_restart;
+ u8 pcut_debunce_time;
};
/**
@@ -415,6 +465,7 @@ void ab8500_fg_reinit(void);
void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA);
struct ab8500_btemp *ab8500_btemp_get(void);
int ab8500_btemp_get_batctrl_temp(struct ab8500_btemp *btemp);
+int ab8500_btemp_get_temp(struct ab8500_btemp *btemp);
struct ab8500_fg *ab8500_fg_get(void);
int ab8500_fg_inst_curr_blocking(struct ab8500_fg *dev);
int ab8500_fg_inst_curr_start(struct ab8500_fg *di);
diff --git a/include/linux/mfd/abx500/ab8500-gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h
index 252966769d93..49ded001049b 100644
--- a/include/linux/mfd/abx500/ab8500-gpadc.h
+++ b/include/linux/mfd/abx500/ab8500-gpadc.h
@@ -4,32 +4,72 @@
*
* Author: Arun R Murthy <arun.murthy@stericsson.com>
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ * Author: M'boumba Cedric Madianga <cedric.madianga@stericsson.com>
*/
#ifndef _AB8500_GPADC_H
#define _AB8500_GPADC_H
-/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
-#define BAT_CTRL 0x01
-#define BTEMP_BALL 0x02
-#define MAIN_CHARGER_V 0x03
-#define ACC_DETECT1 0x04
-#define ACC_DETECT2 0x05
-#define ADC_AUX1 0x06
-#define ADC_AUX2 0x07
-#define MAIN_BAT_V 0x08
-#define VBUS_V 0x09
-#define MAIN_CHARGER_C 0x0A
-#define USB_CHARGER_C 0x0B
-#define BK_BAT_V 0x0C
-#define DIE_TEMP 0x0D
+/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2
+ * and ADCHwSel[4:0] in GPADCCtrl3 ) */
+#define BAT_CTRL 0x01
+#define BTEMP_BALL 0x02
+#define MAIN_CHARGER_V 0x03
+#define ACC_DETECT1 0x04
+#define ACC_DETECT2 0x05
+#define ADC_AUX1 0x06
+#define ADC_AUX2 0x07
+#define MAIN_BAT_V 0x08
+#define VBUS_V 0x09
+#define MAIN_CHARGER_C 0x0A
+#define USB_CHARGER_C 0x0B
+#define BK_BAT_V 0x0C
+#define DIE_TEMP 0x0D
+#define USB_ID 0x0E
+#define XTAL_TEMP 0x12
+#define VBAT_TRUE_MEAS 0x13
+#define BAT_CTRL_AND_IBAT 0x1C
+#define VBAT_MEAS_AND_IBAT 0x1D
+#define VBAT_TRUE_MEAS_AND_IBAT 0x1E
+#define BAT_TEMP_AND_IBAT 0x1F
+
+/* Virtual channel used only for ibat convertion to ampere
+ * Battery current conversion (ibat) cannot be requested as a single conversion
+ * but it is always in combination with other input requests
+ */
+#define IBAT_VIRTUAL_CHANNEL 0xFF
+
+#define SAMPLE_1 1
+#define SAMPLE_4 4
+#define SAMPLE_8 8
+#define SAMPLE_16 16
+#define RISING_EDGE 0
+#define FALLING_EDGE 1
+
+/* Arbitrary ADC conversion type constants */
+#define ADC_SW 0
+#define ADC_HW 1
struct ab8500_gpadc;
struct ab8500_gpadc *ab8500_gpadc_get(char *name);
-int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel);
-int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel);
+int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
+static inline int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
+{
+ return ab8500_gpadc_sw_hw_convert(gpadc, channel,
+ SAMPLE_16, 0, 0, ADC_SW);
+}
+
+int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
+int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+ u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
+ int *ibat);
int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
- u8 channel, int ad_value);
+ u8 channel, int ad_value);
+void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
+ u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
+ u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h);
#endif /* _AB8500_GPADC_H */
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
index ebf12e793db9..990bc93f46e1 100644
--- a/include/linux/mfd/abx500/ab8500-sysctrl.h
+++ b/include/linux/mfd/abx500/ab8500-sysctrl.h
@@ -12,6 +12,7 @@
int ab8500_sysctrl_read(u16 reg, u8 *value);
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
+void ab8500_restart(char mode, const char *cmd);
#else
@@ -40,6 +41,7 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
/* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
struct ab8500_sysctrl_platform_data {
u8 initial_req_buf_config[8];
+ u16 (*reboot_reason_code)(const char *cmd);
};
/* Registers */
@@ -299,4 +301,8 @@ struct ab8500_sysctrl_platform_data {
#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
#define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
+#define AB8500_ENABLE_WD 0x1
+#define AB8500_KICK_WD 0x2
+#define AB8500_WD_RESTART_ON_EXPIRE 0x10
+
#endif /* __AB8500_SYSCTRL_H */
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 9db0bda446a0..fb1bf7d6a410 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -362,10 +362,10 @@ struct ab8500 {
u8 *oldmask;
int mask_size;
const int *irq_reg_offset;
+ int it_latchhier_num;
};
-struct regulator_reg_init;
-struct regulator_init_data;
+struct ab8500_regulator_platform_data;
struct ab8500_gpio_platform_data;
struct ab8500_codec_platform_data;
struct ab8500_sysctrl_platform_data;
@@ -375,19 +375,13 @@ struct ab8500_sysctrl_platform_data;
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
* @pm_power_off: Should machine pm power off hook be registered or not
* @init: board-specific initialization after detection of ab8500
- * @num_regulator_reg_init: number of regulator init registers
- * @regulator_reg_init: regulator init registers
- * @num_regulator: number of regulators
* @regulator: machine-specific constraints for regulators
*/
struct ab8500_platform_data {
int irq_base;
bool pm_power_off;
void (*init) (struct ab8500 *);
- int num_regulator_reg_init;
- struct ab8500_regulator_reg_init *regulator_reg_init;
- int num_regulator;
- struct regulator_init_data *regulator;
+ struct ab8500_regulator_platform_data *regulator;
struct abx500_gpio_platform_data *gpio;
struct ab8500_codec_platform_data *codec;
struct ab8500_sysctrl_platform_data *sysctrl;
@@ -512,6 +506,8 @@ static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
}
+void ab8500_override_turn_on_stat(u8 mask, u8 set);
+
#ifdef CONFIG_AB8500_DEBUG
void ab8500_dump_all_banks(struct device *dev);
void ab8500_debug_register_interrupt(int line);
diff --git a/include/linux/mfd/abx500/ux500_chargalg.h b/include/linux/mfd/abx500/ux500_chargalg.h
index d43ac0f35526..234c99143bf7 100644
--- a/include/linux/mfd/abx500/ux500_chargalg.h
+++ b/include/linux/mfd/abx500/ux500_chargalg.h
@@ -17,8 +17,11 @@ struct ux500_charger;
struct ux500_charger_ops {
int (*enable) (struct ux500_charger *, int, int, int);
+ int (*check_enable) (struct ux500_charger *, int, int);
int (*kick_wd) (struct ux500_charger *);
int (*update_curr) (struct ux500_charger *, int);
+ int (*pp_enable) (struct ux500_charger *, bool);
+ int (*pre_chg_enable) (struct ux500_charger *, bool);
};
/**
@@ -29,6 +32,7 @@ struct ux500_charger_ops {
* @max_out_curr maximum output charger current in mA
* @enabled indicates if this charger is used or not
* @external external charger unit (pm2xxx)
+ * @power_path USB power path support
*/
struct ux500_charger {
struct power_supply psy;
@@ -38,6 +42,9 @@ struct ux500_charger {
int wdt_refresh;
bool enabled;
bool external;
+ bool power_path;
};
+extern struct blocking_notifier_head charger_notifier_list;
+
#endif
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index a710255528d7..cc281368dc55 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -100,6 +100,9 @@ struct arizona {
struct regmap_irq_chip_data *aod_irq_chip;
struct regmap_irq_chip_data *irq_chip;
+ bool hpdet_magic;
+ unsigned int hp_ena;
+
struct mutex clk_lock;
int clk32k_ref;
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 455c51d22d6b..a0f940987a3e 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -86,6 +86,11 @@ struct arizona_micd_config {
bool gpio;
};
+struct arizona_micd_range {
+ int max; /** Ohms */
+ int key; /** Key to report to input layer */
+};
+
struct arizona_pdata {
int reset; /** GPIO controlling /RESET, if any */
int ldoena; /** GPIO controlling LODENA, if any */
@@ -117,12 +122,21 @@ struct arizona_pdata {
/** GPIO5 is used for jack detection */
bool jd_gpio5;
+ /** Internal pull on GPIO5 is disabled when used for jack detection */
+ bool jd_gpio5_nopull;
+
/** Use the headphone detect circuit to identify the accessory */
bool hpdet_acc_id;
+ /** Check for line output with HPDET method */
+ bool hpdet_acc_id_line;
+
/** GPIO used for mic isolation with HPDET */
int hpdet_id_gpio;
+ /** Extra debounce timeout used during initial mic detection (ms) */
+ int micd_detect_debounce;
+
/** GPIO for mic detection polarity */
int micd_pol_gpio;
@@ -135,9 +149,16 @@ struct arizona_pdata {
/** Mic detect debounce level */
int micd_dbtime;
+ /** Mic detect timeout (ms) */
+ int micd_timeout;
+
/** Force MICBIAS on for mic detect */
bool micd_force_micbias;
+ /** Mic detect level parameters */
+ const struct arizona_micd_range *micd_ranges;
+ int num_micd_ranges;
+
/** Headset polarity configurations */
struct arizona_micd_config *micd_configs;
int num_micd_configs;
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index 340355136069..f43aa7c8d040 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -124,6 +124,10 @@
#define ARIZONA_MIC_DETECT_1 0x2A3
#define ARIZONA_MIC_DETECT_2 0x2A4
#define ARIZONA_MIC_DETECT_3 0x2A5
+#define ARIZONA_MIC_DETECT_LEVEL_1 0x2A6
+#define ARIZONA_MIC_DETECT_LEVEL_2 0x2A7
+#define ARIZONA_MIC_DETECT_LEVEL_3 0x2A8
+#define ARIZONA_MIC_DETECT_LEVEL_4 0x2A9
#define ARIZONA_MIC_NOISE_MIX_CONTROL_1 0x2C3
#define ARIZONA_ISOLATION_CONTROL 0x2CB
#define ARIZONA_JACK_DETECT_ANALOGUE 0x2D3
diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index 5b18ecde69b5..1aa4f13cdfa6 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -106,6 +106,29 @@ enum max77693_muic_reg {
MAX77693_MUIC_REG_END,
};
+/* MAX77693 INTMASK1~2 Register */
+#define INTMASK1_ADC1K_SHIFT 3
+#define INTMASK1_ADCERR_SHIFT 2
+#define INTMASK1_ADCLOW_SHIFT 1
+#define INTMASK1_ADC_SHIFT 0
+#define INTMASK1_ADC1K_MASK (1 << INTMASK1_ADC1K_SHIFT)
+#define INTMASK1_ADCERR_MASK (1 << INTMASK1_ADCERR_SHIFT)
+#define INTMASK1_ADCLOW_MASK (1 << INTMASK1_ADCLOW_SHIFT)
+#define INTMASK1_ADC_MASK (1 << INTMASK1_ADC_SHIFT)
+
+#define INTMASK2_VIDRM_SHIFT 5
+#define INTMASK2_VBVOLT_SHIFT 4
+#define INTMASK2_DXOVP_SHIFT 3
+#define INTMASK2_DCDTMR_SHIFT 2
+#define INTMASK2_CHGDETRUN_SHIFT 1
+#define INTMASK2_CHGTYP_SHIFT 0
+#define INTMASK2_VIDRM_MASK (1 << INTMASK2_VIDRM_SHIFT)
+#define INTMASK2_VBVOLT_MASK (1 << INTMASK2_VBVOLT_SHIFT)
+#define INTMASK2_DXOVP_MASK (1 << INTMASK2_DXOVP_SHIFT)
+#define INTMASK2_DCDTMR_MASK (1 << INTMASK2_DCDTMR_SHIFT)
+#define INTMASK2_CHGDETRUN_MASK (1 << INTMASK2_CHGDETRUN_SHIFT)
+#define INTMASK2_CHGTYP_MASK (1 << INTMASK2_CHGTYP_SHIFT)
+
/* MAX77693 MUIC - STATUS1~3 Register */
#define STATUS1_ADC_SHIFT (0)
#define STATUS1_ADCLOW_SHIFT (5)
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index 3bbda22721ea..ecddc5173c7c 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -109,19 +109,6 @@ struct palmas_reg_init {
*/
int mode_sleep;
- /* tstep is the timestep loaded to the TSTEP register
- *
- * For SMPS
- *
- * 0: Jump (no slope control)
- * 1: 10mV/us
- * 2: 5mV/us
- * 3: 2.5mV/us
- *
- * For LDO unused
- */
- int tstep;
-
/* voltage_sel is the bitfield loaded onto the SMPSX_VOLTAGE
* register. Set this is the default voltage set in OTP needs
* to be overridden.
@@ -154,6 +141,12 @@ enum palmas_regulators {
PALMAS_REG_LDO9,
PALMAS_REG_LDOLN,
PALMAS_REG_LDOUSB,
+ /* External regulators */
+ PALMAS_REG_REGEN1,
+ PALMAS_REG_REGEN2,
+ PALMAS_REG_REGEN3,
+ PALMAS_REG_SYSEN1,
+ PALMAS_REG_SYSEN2,
/* Total number of regulators */
PALMAS_NUM_REGS,
};
@@ -171,6 +164,9 @@ struct palmas_pmic_platform_data {
/* use LDO6 for vibrator control */
int ldo6_vibrator;
+
+ /* Enable tracking mode of LDO8 */
+ bool enable_ldo8_tracking;
};
struct palmas_usb_platform_data {
@@ -331,6 +327,8 @@ struct palmas_pmic {
int smps457;
int range[PALMAS_REG_SMPS10];
+ unsigned int ramp_delay[PALMAS_REG_SMPS10];
+ unsigned int current_reg_mode[PALMAS_REG_SMPS10];
};
struct palmas_resource {
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h
index 6694cf43e8b8..998628a2b08b 100644
--- a/include/linux/mfd/tps65090.h
+++ b/include/linux/mfd/tps65090.h
@@ -86,6 +86,11 @@ struct tps65090_regulator_plat_data {
struct tps65090_platform_data {
int irq_base;
+
+ char **supplied_to;
+ size_t num_supplicants;
+ int enable_low_current_chrg;
+
struct tps65090_regulator_plat_data *reg_pdata[TPS65090_REGULATOR_MAX];
};
diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h
index 290762f93930..29eab2bd3dfa 100644
--- a/include/linux/mfd/tps65217.h
+++ b/include/linux/mfd/tps65217.h
@@ -228,6 +228,7 @@ enum tps65217_bl_fdim {
struct tps65217_bl_pdata {
enum tps65217_bl_isel isel;
enum tps65217_bl_fdim fdim;
+ int dft_brightness;
};
/**
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index 9dbb41a4e250..8752dbbc6135 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -19,6 +19,7 @@
#define PHY_ID_KSZ9021 0x00221610
#define PHY_ID_KS8737 0x00221720
#define PHY_ID_KSZ8021 0x00221555
+#define PHY_ID_KSZ8031 0x00221556
#define PHY_ID_KSZ8041 0x00221510
#define PHY_ID_KSZ8051 0x00221550
/* same id: ks8001 Rev. A/B, and ks8721 Rev 3. */
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index 260695186256..adf6e0648f20 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -34,6 +34,7 @@
#define MLX4_CMD_H
#include <linux/dma-mapping.h>
+#include <linux/if_link.h>
enum {
/* initialization and general commands */
@@ -232,6 +233,11 @@ struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev);
void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox);
u32 mlx4_comm_get_version(void);
+int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac);
+int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos);
+int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting);
+int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf);
+
#define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8)
diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h
index 6f65b2c8bb89..98fa492cf406 100644
--- a/include/linux/mlx4/cq.h
+++ b/include/linux/mlx4/cq.h
@@ -64,6 +64,22 @@ struct mlx4_err_cqe {
u8 owner_sr_opcode;
};
+struct mlx4_ts_cqe {
+ __be32 vlan_my_qpn;
+ __be32 immed_rss_invalid;
+ __be32 g_mlpath_rqpn;
+ __be32 timestamp_hi;
+ __be16 status;
+ u8 ipv6_ext_mask;
+ u8 badfcs_enc;
+ __be32 byte_cnt;
+ __be16 wqe_index;
+ __be16 checksum;
+ u8 reserved;
+ __be16 timestamp_lo;
+ u8 owner_sr_opcode;
+} __packed;
+
enum {
MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29,
MLX4_CQE_QPN_MASK = 0xffffff,
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 811f91cf5e8c..53acaf64189f 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -40,6 +40,8 @@
#include <linux/atomic.h>
+#include <linux/clocksource.h>
+
#define MAX_MSIX_P_PORT 17
#define MAX_MSIX 64
#define MSIX_LEGACY_SZ 4
@@ -140,6 +142,7 @@ enum {
MLX4_DEV_CAP_FLAG_VEP_UC_STEER = 1LL << 41,
MLX4_DEV_CAP_FLAG_VEP_MC_STEER = 1LL << 42,
MLX4_DEV_CAP_FLAG_COUNTERS = 1LL << 48,
+ MLX4_DEV_CAP_FLAG_SET_ETH_SCHED = 1LL << 53,
MLX4_DEV_CAP_FLAG_SENSE_SUPPORT = 1LL << 55,
MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV = 1LL << 59,
MLX4_DEV_CAP_FLAG_64B_EQE = 1LL << 61,
@@ -151,7 +154,10 @@ enum {
MLX4_DEV_CAP_FLAG2_RSS_TOP = 1LL << 1,
MLX4_DEV_CAP_FLAG2_RSS_XOR = 1LL << 2,
MLX4_DEV_CAP_FLAG2_FS_EN = 1LL << 3,
- MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN = 1LL << 4
+ MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN = 1LL << 4,
+ MLX4_DEV_CAP_FLAG2_TS = 1LL << 5,
+ MLX4_DEV_CAP_FLAG2_VLAN_CONTROL = 1LL << 6,
+ MLX4_DEV_CAP_FLAG2_FSM = 1LL << 7
};
enum {
@@ -443,6 +449,7 @@ struct mlx4_caps {
u8 eqe_factor;
u32 userspace_caps; /* userspace must be aware of these */
u32 function_caps; /* VFs must be aware of these */
+ u16 hca_core_clock;
};
struct mlx4_buf_list {
@@ -837,7 +844,7 @@ void mlx4_free_hwq_res(struct mlx4_dev *mdev, struct mlx4_hwq_resources *wqres,
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
- unsigned vector, int collapsed);
+ unsigned vector, int collapsed, int timestamp_en);
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
int mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base);
@@ -1028,4 +1035,6 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int
void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid);
__be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave);
+cycle_t mlx4_read_clock(struct mlx4_dev *dev);
+
#endif /* MLX4_DEVICE_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7acc9dc73c9f..1a7f19e7f1a0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -44,6 +44,9 @@ extern int sysctl_legacy_va_layout;
#include <asm/pgtable.h>
#include <asm/processor.h>
+extern unsigned long sysctl_user_reserve_kbytes;
+extern unsigned long sysctl_admin_reserve_kbytes;
+
#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n))
/* to align the pointer to the (next) page boundary */
@@ -87,7 +90,6 @@ extern unsigned int kobjsize(const void *objp);
#define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */
#define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */
-#define VM_POPULATE 0x00001000
#define VM_LOCKED 0x00002000
#define VM_IO 0x00004000 /* Memory mapped I/O or similar */
@@ -900,7 +902,8 @@ extern void pagefault_out_of_memory(void);
* Flags passed to show_mem() and show_free_areas() to suppress output in
* various contexts.
*/
-#define SHOW_MEM_FILTER_NODES (0x0001u) /* filter disallowed nodes */
+#define SHOW_MEM_FILTER_NODES (0x0001u) /* disallowed nodes */
+#define SHOW_MEM_FILTER_PAGE_COUNT (0x0002u) /* page type count */
extern void show_free_areas(unsigned int flags);
extern bool skip_free_areas_node(unsigned int flags, int nid);
@@ -1079,9 +1082,6 @@ extern unsigned long move_page_tables(struct vm_area_struct *vma,
unsigned long old_addr, struct vm_area_struct *new_vma,
unsigned long new_addr, unsigned long len,
bool need_rmap_locks);
-extern unsigned long do_mremap(unsigned long addr,
- unsigned long old_len, unsigned long new_len,
- unsigned long flags, unsigned long new_addr);
extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
unsigned long end, pgprot_t newprot,
int dirty_accountable, int prot_numa);
@@ -1295,6 +1295,61 @@ extern void free_area_init_node(int nid, unsigned long * zones_size,
unsigned long zone_start_pfn, unsigned long *zholes_size);
extern void free_initmem(void);
+/*
+ * Free reserved pages within range [PAGE_ALIGN(start), end & PAGE_MASK)
+ * into the buddy system. The freed pages will be poisoned with pattern
+ * "poison" if it's non-zero.
+ * Return pages freed into the buddy system.
+ */
+extern unsigned long free_reserved_area(unsigned long start, unsigned long end,
+ int poison, char *s);
+#ifdef CONFIG_HIGHMEM
+/*
+ * Free a highmem page into the buddy system, adjusting totalhigh_pages
+ * and totalram_pages.
+ */
+extern void free_highmem_page(struct page *page);
+#endif
+
+static inline void adjust_managed_page_count(struct page *page, long count)
+{
+ totalram_pages += count;
+}
+
+/* Free the reserved page into the buddy system, so it gets managed. */
+static inline void __free_reserved_page(struct page *page)
+{
+ ClearPageReserved(page);
+ init_page_count(page);
+ __free_page(page);
+}
+
+static inline void free_reserved_page(struct page *page)
+{
+ __free_reserved_page(page);
+ adjust_managed_page_count(page, 1);
+}
+
+static inline void mark_page_reserved(struct page *page)
+{
+ SetPageReserved(page);
+ adjust_managed_page_count(page, -1);
+}
+
+/*
+ * Default method to free all the __init memory into the buddy system.
+ * The freed pages will be poisoned with pattern "poison" if it is
+ * non-zero. Return pages freed into the buddy system.
+ */
+static inline unsigned long free_initmem_default(int poison)
+{
+ extern char __init_begin[], __init_end[];
+
+ return free_reserved_area(PAGE_ALIGN((unsigned long)&__init_begin) ,
+ ((unsigned long)&__init_end) & PAGE_MASK,
+ poison, "unused kernel");
+}
+
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
/*
* With CONFIG_HAVE_MEMBLOCK_NODE_MAP set, an architecture may initialise its
@@ -1612,6 +1667,8 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn);
int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn);
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
+
struct page *follow_page_mask(struct vm_area_struct *vma,
unsigned long address, unsigned int foll_flags,
@@ -1674,8 +1731,12 @@ int in_gate_area_no_mm(unsigned long addr);
#define in_gate_area(mm, addr) ({(void)mm; in_gate_area_no_mm(addr);})
#endif /* __HAVE_ARCH_GATE_AREA */
+#ifdef CONFIG_SYSCTL
+extern int sysctl_drop_caches;
int drop_caches_sysctl_handler(struct ctl_table *, int,
void __user *, size_t *, loff_t *);
+#endif
+
unsigned long shrink_slab(struct shrink_control *shrink,
unsigned long nr_pages_scanned,
unsigned long lru_pages);
@@ -1703,12 +1764,12 @@ pte_t *vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node);
void *vmemmap_alloc_block(unsigned long size, int node);
void *vmemmap_alloc_block_buf(unsigned long size, int node);
void vmemmap_verify(pte_t *, int, unsigned long, unsigned long);
-int vmemmap_populate_basepages(struct page *start_page,
- unsigned long pages, int node);
-int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
+int vmemmap_populate_basepages(unsigned long start, unsigned long end,
+ int node);
+int vmemmap_populate(unsigned long start, unsigned long end, int node);
void vmemmap_populate_print_last(void);
#ifdef CONFIG_MEMORY_HOTPLUG
-void vmemmap_free(struct page *memmap, unsigned long nr_pages);
+void vmemmap_free(unsigned long start, unsigned long end);
#endif
void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
unsigned long size);
@@ -1755,5 +1816,11 @@ static inline unsigned int debug_guardpage_minorder(void) { return 0; }
static inline bool page_is_guard(struct page *page) { return false; }
#endif /* CONFIG_DEBUG_PAGEALLOC */
+#if MAX_NUMNODES > 1
+void __init setup_nr_node_ids(void);
+#else
+static inline void setup_nr_node_ids(void) {}
+#endif
+
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mman.h b/include/linux/mman.h
index 61c7a87e5d2b..9aa863da287f 100644
--- a/include/linux/mman.h
+++ b/include/linux/mman.h
@@ -79,8 +79,6 @@ calc_vm_flag_bits(unsigned long flags)
{
return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) |
_calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) |
- ((flags & MAP_LOCKED) ? (VM_LOCKED | VM_POPULATE) : 0) |
- (((flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE) ?
- VM_POPULATE : 0);
+ _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED );
}
#endif /* _LINUX_MMAN_H */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index c74092eebf5c..5c76737d836b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -450,7 +450,7 @@ struct zone {
*
* present_pages is physical pages existing within the zone, which
* is calculated as:
- * present_pages = spanned_pages - absent_pages(pags in holes);
+ * present_pages = spanned_pages - absent_pages(pages in holes);
*
* managed_pages is present pages managed by the buddy system, which
* is calculated as (reserved_pages includes pages allocated by the
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 779cf7c4a3d1..b508016fb76d 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -9,6 +9,7 @@
#ifdef __KERNEL__
#include <linux/types.h>
+#include <linux/uuid.h>
typedef unsigned long kernel_ulong_t;
#endif
@@ -568,4 +569,12 @@ struct ipack_device_id {
__u32 device; /* Device ID or IPACK_ANY_ID */
};
+#define MEI_CL_MODULE_PREFIX "mei:"
+#define MEI_CL_NAME_SIZE 32
+
+struct mei_cl_device_id {
+ char name[MEI_CL_NAME_SIZE];
+ kernel_ulong_t driver_info;
+};
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index d7029f4a191a..73005f9957ea 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -47,6 +47,8 @@ struct mnt_namespace;
#define MNT_INTERNAL 0x4000
+#define MNT_LOCK_READONLY 0x400000
+
struct vfsmount {
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
diff --git a/include/linux/msi.h b/include/linux/msi.h
index ce93a341337d..20c2d6dd5d25 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -13,14 +13,14 @@ struct msi_msg {
/* Helper functions */
struct irq_data;
struct msi_desc;
-extern void mask_msi_irq(struct irq_data *data);
-extern void unmask_msi_irq(struct irq_data *data);
-extern void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
-extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
-extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+void mask_msi_irq(struct irq_data *data);
+void unmask_msi_irq(struct irq_data *data);
+void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
+void write_msi_msg(unsigned int irq, struct msi_msg *msg);
struct msi_desc {
struct {
@@ -54,9 +54,8 @@ struct msi_desc {
*/
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
void arch_teardown_msi_irq(unsigned int irq);
-extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
-extern void arch_teardown_msi_irqs(struct pci_dev *dev);
-extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
-
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+void arch_teardown_msi_irqs(struct pci_dev *dev);
+int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
#endif /* LINUX_MSI_H */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 9121595a8ebf..433da8a1a426 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -53,6 +53,9 @@ struct mutex {
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
struct task_struct *owner;
#endif
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+ void *spin_mlock; /* Spinner MCS lock */
+#endif
#ifdef CONFIG_DEBUG_MUTEXES
const char *name;
void *magic;
diff --git a/include/linux/mv643xx_eth.h b/include/linux/mv643xx_eth.h
index 49258e0ed1c6..141d395bbb5f 100644
--- a/include/linux/mv643xx_eth.h
+++ b/include/linux/mv643xx_eth.h
@@ -19,7 +19,6 @@
struct mv643xx_eth_shared_platform_data {
struct mbus_dram_target_info *dram;
- struct platform_device *shared_smi;
/*
* Max packet size for Tx IP/Layer 4 checksum, when set to 0, default
* limit of 9KiB will be used.
diff --git a/include/linux/net.h b/include/linux/net.h
index aa1673160a45..99c9f0c103c2 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -240,8 +240,8 @@ do { \
#define net_dbg_ratelimited(fmt, ...) \
net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
-#define net_random() random32()
-#define net_srandom(seed) srandom32((__force u32)seed)
+#define net_random() prandom_u32()
+#define net_srandom(seed) prandom_seed((__force u32)(seed))
extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t len);
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 3dd39340430e..cbaa027ef5a7 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -22,9 +22,12 @@ enum {
NETIF_F_IPV6_CSUM_BIT, /* Can checksum TCP/UDP over IPV6 */
NETIF_F_HIGHDMA_BIT, /* Can DMA to high memory. */
NETIF_F_FRAGLIST_BIT, /* Scatter/gather IO. */
- NETIF_F_HW_VLAN_TX_BIT, /* Transmit VLAN hw acceleration */
- NETIF_F_HW_VLAN_RX_BIT, /* Receive VLAN hw acceleration */
- NETIF_F_HW_VLAN_FILTER_BIT, /* Receive filtering on VLAN */
+ NETIF_F_HW_VLAN_CTAG_TX_BIT, /* Transmit VLAN CTAG HW acceleration */
+ NETIF_F_HW_VLAN_CTAG_RX_BIT, /* Receive VLAN CTAG HW acceleration */
+ NETIF_F_HW_VLAN_CTAG_FILTER_BIT,/* Receive filtering on VLAN CTAGs */
+ NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */
+ NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */
+ NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */
NETIF_F_VLAN_CHALLENGED_BIT, /* Device cannot handle VLAN packets */
NETIF_F_GSO_BIT, /* Enable software GSO. */
NETIF_F_LLTX_BIT, /* LockLess TX - deprecated. Please */
@@ -42,9 +45,9 @@ enum {
NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */
NETIF_F_FSO_BIT, /* ... FCoE segmentation */
NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */
- /**/NETIF_F_GSO_LAST, /* [can't be last bit, see GSO_MASK] */
- NETIF_F_GSO_RESERVED2 /* ... free (fill GSO_MASK to 8 bits) */
- = NETIF_F_GSO_LAST,
+ NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */
+ /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */
+ NETIF_F_GSO_UDP_TUNNEL_BIT,
NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */
NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */
@@ -80,9 +83,12 @@ enum {
#define NETIF_F_GSO_ROBUST __NETIF_F(GSO_ROBUST)
#define NETIF_F_HIGHDMA __NETIF_F(HIGHDMA)
#define NETIF_F_HW_CSUM __NETIF_F(HW_CSUM)
-#define NETIF_F_HW_VLAN_FILTER __NETIF_F(HW_VLAN_FILTER)
-#define NETIF_F_HW_VLAN_RX __NETIF_F(HW_VLAN_RX)
-#define NETIF_F_HW_VLAN_TX __NETIF_F(HW_VLAN_TX)
+#define NETIF_F_HW_VLAN_CTAG_FILTER __NETIF_F(HW_VLAN_CTAG_FILTER)
+#define NETIF_F_HW_VLAN_CTAG_RX __NETIF_F(HW_VLAN_CTAG_RX)
+#define NETIF_F_HW_VLAN_CTAG_TX __NETIF_F(HW_VLAN_CTAG_TX)
+#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
+#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
+#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
#define NETIF_F_IP_CSUM __NETIF_F(IP_CSUM)
#define NETIF_F_IPV6_CSUM __NETIF_F(IPV6_CSUM)
#define NETIF_F_LLTX __NETIF_F(LLTX)
@@ -102,7 +108,8 @@ enum {
#define NETIF_F_VLAN_CHALLENGED __NETIF_F(VLAN_CHALLENGED)
#define NETIF_F_RXFCS __NETIF_F(RXFCS)
#define NETIF_F_RXALL __NETIF_F(RXALL)
-#define NETIF_F_GRE_GSO __NETIF_F(GSO_GRE)
+#define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE)
+#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
/* Features valid for ethtool to change */
/* = all defined minus driver/device-class-related */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b3d00fa4b314..f8898a435dc5 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -144,8 +144,6 @@ static inline bool dev_xmit_complete(int rc)
# else
# define LL_MAX_HEADER 96
# endif
-#elif IS_ENABLED(CONFIG_TR)
-# define LL_MAX_HEADER 48
#else
# define LL_MAX_HEADER 32
#endif
@@ -210,9 +208,10 @@ struct netdev_hw_addr {
#define NETDEV_HW_ADDR_T_SLAVE 3
#define NETDEV_HW_ADDR_T_UNICAST 4
#define NETDEV_HW_ADDR_T_MULTICAST 5
- bool synced;
bool global_use;
+ int sync_cnt;
int refcount;
+ int synced;
struct rcu_head rcu_head;
};
@@ -785,13 +784,13 @@ struct netdev_fcoe_hbainfo {
* 3. Update dev->stats asynchronously and atomically, and define
* neither operation.
*
- * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid);
- * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER)
- * this function is called when a VLAN id is registered.
+ * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, __be16 proto, u16t vid);
+ * If device support VLAN filtering this function is called when a
+ * VLAN id is registered.
*
* int (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid);
- * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER)
- * this function is called when a VLAN id is unregistered.
+ * If device support VLAN filtering this function is called when a
+ * VLAN id is unregistered.
*
* void (*ndo_poll_controller)(struct net_device *dev);
*
@@ -895,7 +894,7 @@ struct netdev_fcoe_hbainfo {
*
* int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
* int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
- * struct net_device *dev)
+ * struct net_device *dev, u32 filter_mask)
*
* int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
* Called to change device carrier. Soft-devices (like dummy, team, etc)
@@ -935,9 +934,9 @@ struct net_device_ops {
struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
int (*ndo_vlan_rx_add_vid)(struct net_device *dev,
- unsigned short vid);
+ __be16 proto, u16 vid);
int (*ndo_vlan_rx_kill_vid)(struct net_device *dev,
- unsigned short vid);
+ __be16 proto, u16 vid);
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
int (*ndo_netpoll_setup)(struct net_device *dev,
@@ -1073,6 +1072,8 @@ struct net_device {
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
+ struct list_head upper_dev_list; /* List of upper devices */
+
/* currently active device features */
netdev_features_t features;
@@ -1145,6 +1146,13 @@ struct net_device {
spinlock_t addr_list_lock;
struct netdev_hw_addr_list uc; /* Unicast mac addresses */
struct netdev_hw_addr_list mc; /* Multicast mac addresses */
+ struct netdev_hw_addr_list dev_addrs; /* list of device
+ * hw addresses
+ */
+#ifdef CONFIG_SYSFS
+ struct kset *queues_kset;
+#endif
+
bool uc_promisc;
unsigned int promiscuity;
unsigned int allmulti;
@@ -1177,21 +1185,11 @@ struct net_device {
* avoid dirtying this cache line.
*/
- struct list_head upper_dev_list; /* List of upper devices */
-
/* Interface address info used in eth_type_trans() */
unsigned char *dev_addr; /* hw address, (before bcast
because most packets are
unicast) */
- struct netdev_hw_addr_list dev_addrs; /* list of device
- hw addresses */
-
- unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
-
-#ifdef CONFIG_SYSFS
- struct kset *queues_kset;
-#endif
#ifdef CONFIG_RPS
struct netdev_rx_queue *_rx;
@@ -1202,18 +1200,14 @@ struct net_device {
/* Number of RX queues currently active in device */
unsigned int real_num_rx_queues;
-#ifdef CONFIG_RFS_ACCEL
- /* CPU reverse-mapping for RX completion interrupts, indexed
- * by RX queue number. Assigned by driver. This must only be
- * set if the ndo_rx_flow_steer operation is defined. */
- struct cpu_rmap *rx_cpu_rmap;
-#endif
#endif
rx_handler_func_t __rcu *rx_handler;
void __rcu *rx_handler_data;
struct netdev_queue __rcu *ingress_queue;
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+
/*
* Cache lines mostly used on transmit path
@@ -1235,6 +1229,12 @@ struct net_device {
#ifdef CONFIG_XPS
struct xps_dev_maps __rcu *xps_maps;
#endif
+#ifdef CONFIG_RFS_ACCEL
+ /* CPU reverse-mapping for RX completion interrupts, indexed
+ * by RX queue number. Assigned by driver. This must only be
+ * set if the ndo_rx_flow_steer operation is defined. */
+ struct cpu_rmap *rx_cpu_rmap;
+#endif
/* These may be needed for future network-power-down code. */
@@ -1475,6 +1475,11 @@ static inline void *netdev_priv(const struct net_device *dev)
*/
#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype))
+/* Default NAPI poll() weight
+ * Device drivers are strongly advised to not use bigger value
+ */
+#define NAPI_POLL_WEIGHT 64
+
/**
* netif_napi_add - initialize a napi context
* @dev: network device
@@ -1612,6 +1617,9 @@ extern seqcount_t devnet_rename_seq; /* Device rename seq */
list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list)
#define for_each_netdev_continue_rcu(net, d) \
list_for_each_entry_continue_rcu(d, &(net)->dev_base_head, dev_list)
+#define for_each_netdev_in_bond_rcu(bond, slave) \
+ for_each_netdev_rcu(&init_net, slave) \
+ if (netdev_master_upper_dev_get_rcu(slave) == bond)
#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list)
static inline struct net_device *next_net_device(struct net_device *dev)
@@ -1684,7 +1692,6 @@ extern int netdev_refcnt_read(const struct net_device *dev);
extern void free_netdev(struct net_device *dev);
extern void synchronize_net(void);
extern int init_dummy_netdev(struct net_device *dev);
-extern void netdev_resync_ops(struct net_device *dev);
extern struct net_device *dev_get_by_index(struct net *net, int ifindex);
extern struct net_device *__dev_get_by_index(struct net *net, int ifindex);
@@ -2621,6 +2628,7 @@ extern int dev_uc_add(struct net_device *dev, const unsigned char *addr);
extern int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr);
extern int dev_uc_del(struct net_device *dev, const unsigned char *addr);
extern int dev_uc_sync(struct net_device *to, struct net_device *from);
+extern int dev_uc_sync_multiple(struct net_device *to, struct net_device *from);
extern void dev_uc_unsync(struct net_device *to, struct net_device *from);
extern void dev_uc_flush(struct net_device *dev);
extern void dev_uc_init(struct net_device *dev);
@@ -2632,6 +2640,7 @@ extern int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr);
extern int dev_mc_del(struct net_device *dev, const unsigned char *addr);
extern int dev_mc_del_global(struct net_device *dev, const unsigned char *addr);
extern int dev_mc_sync(struct net_device *to, struct net_device *from);
+extern int dev_mc_sync_multiple(struct net_device *to, struct net_device *from);
extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
extern void dev_mc_flush(struct net_device *dev);
extern void dev_mc_init(struct net_device *dev);
@@ -2678,6 +2687,19 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
{
return __skb_gso_segment(skb, features, true);
}
+__be16 skb_network_protocol(struct sk_buff *skb);
+
+static inline bool can_checksum_protocol(netdev_features_t features,
+ __be16 protocol)
+{
+ return ((features & NETIF_F_GEN_CSUM) ||
+ ((features & NETIF_F_V4_CSUM) &&
+ protocol == htons(ETH_P_IP)) ||
+ ((features & NETIF_F_V6_CSUM) &&
+ protocol == htons(ETH_P_IPV6)) ||
+ ((features & NETIF_F_FCOE_CRC) &&
+ protocol == htons(ETH_P_FCOE)));
+}
#ifdef CONFIG_BUG
extern void netdev_rx_csum_fault(struct net_device *dev);
@@ -2756,6 +2778,11 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
dev->gso_max_size = size;
}
+static inline bool netif_is_bond_master(struct net_device *dev)
+{
+ return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING;
+}
+
static inline bool netif_is_bond_slave(struct net_device *dev)
{
return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING;
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index ee142846f56a..0060fde3160e 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -289,11 +289,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#endif
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_net_netfilter;
-#endif
-
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index 7958e84a65af..d80e2753847c 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -1,7 +1,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -47,10 +47,36 @@ enum ip_set_feature {
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
};
+/* Set extensions */
+enum ip_set_extension {
+ IPSET_EXT_NONE = 0,
+ IPSET_EXT_BIT_TIMEOUT = 1,
+ IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
+ IPSET_EXT_BIT_COUNTER = 2,
+ IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER),
+};
+
+/* Extension offsets */
+enum ip_set_offset {
+ IPSET_OFFSET_TIMEOUT = 0,
+ IPSET_OFFSET_COUNTER,
+ IPSET_OFFSET_MAX,
+};
+
+#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
+#define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER)
+
+struct ip_set_ext {
+ unsigned long timeout;
+ u64 packets;
+ u64 bytes;
+};
+
struct ip_set;
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
- u32 timeout, u32 flags);
+ const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 cmdflags);
/* Kernel API function options */
struct ip_set_adt_opt {
@@ -58,7 +84,7 @@ struct ip_set_adt_opt {
u8 dim; /* Dimension of match/target */
u8 flags; /* Direction and negation flags */
u32 cmdflags; /* Command-like flags */
- u32 timeout; /* Timeout value */
+ struct ip_set_ext ext; /* Extensions */
};
/* Set type, variant-specific part */
@@ -69,7 +95,7 @@ struct ip_set_type_variant {
* positive for matching element */
int (*kadt)(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt);
+ enum ipset_adt adt, struct ip_set_adt_opt *opt);
/* Userspace: test/add/del entries
* returns negative error code,
@@ -151,10 +177,76 @@ struct ip_set {
u8 family;
/* The type revision */
u8 revision;
+ /* Extensions */
+ u8 extensions;
/* The type specific data */
void *data;
};
+struct ip_set_counter {
+ atomic64_t bytes;
+ atomic64_t packets;
+};
+
+static inline void
+ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter)
+{
+ atomic64_add((long long)bytes, &(counter)->bytes);
+}
+
+static inline void
+ip_set_add_packets(u64 packets, struct ip_set_counter *counter)
+{
+ atomic64_add((long long)packets, &(counter)->packets);
+}
+
+static inline u64
+ip_set_get_bytes(const struct ip_set_counter *counter)
+{
+ return (u64)atomic64_read(&(counter)->bytes);
+}
+
+static inline u64
+ip_set_get_packets(const struct ip_set_counter *counter)
+{
+ return (u64)atomic64_read(&(counter)->packets);
+}
+
+static inline void
+ip_set_update_counter(struct ip_set_counter *counter,
+ const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ if (ext->packets != ULLONG_MAX &&
+ !(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) {
+ ip_set_add_bytes(ext->bytes, counter);
+ ip_set_add_packets(ext->packets, counter);
+ }
+ if (flags & IPSET_FLAG_MATCH_COUNTERS) {
+ mext->packets = ip_set_get_packets(counter);
+ mext->bytes = ip_set_get_bytes(counter);
+ }
+}
+
+static inline bool
+ip_set_put_counter(struct sk_buff *skb, struct ip_set_counter *counter)
+{
+ return nla_put_net64(skb, IPSET_ATTR_BYTES,
+ cpu_to_be64(ip_set_get_bytes(counter))) ||
+ nla_put_net64(skb, IPSET_ATTR_PACKETS,
+ cpu_to_be64(ip_set_get_packets(counter)));
+}
+
+static inline void
+ip_set_init_counter(struct ip_set_counter *counter,
+ const struct ip_set_ext *ext)
+{
+ if (ext->bytes != ULLONG_MAX)
+ atomic64_set(&(counter)->bytes, (long long)(ext->bytes));
+ if (ext->packets != ULLONG_MAX)
+ atomic64_set(&(counter)->packets, (long long)(ext->packets));
+}
+
/* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
extern void ip_set_put_byindex(ip_set_id_t index);
@@ -167,19 +259,21 @@ extern void ip_set_nfnl_put(ip_set_id_t index);
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt);
+ struct ip_set_adt_opt *opt);
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt);
+ struct ip_set_adt_opt *opt);
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt);
+ struct ip_set_adt_opt *opt);
/* Utility functions */
extern void *ip_set_alloc(size_t size);
extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
+extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
+ struct ip_set_ext *ext);
static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
@@ -200,6 +294,14 @@ ip_set_eexist(int ret, u32 flags)
return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
}
+/* Match elements marked with nomatch */
+static inline bool
+ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt)
+{
+ return adt == IPSET_TEST &&
+ ret == -ENOTEMPTY && ((flags >> 16) & IPSET_FLAG_NOMATCH);
+}
+
/* Check the NLA_F_NET_BYTEORDER flag */
static inline bool
ip_set_attr_netorder(struct nlattr *tb[], int type)
@@ -284,4 +386,14 @@ bitmap_bytes(u32 a, u32 b)
return 4 * ((((b - a + 8) / 8) + 3) / 4);
}
+#include <linux/netfilter/ipset/ip_set_timeout.h>
+
+#define IP_SET_INIT_KEXT(skb, opt, map) \
+ { .bytes = (skb)->len, .packets = 1, \
+ .timeout = ip_set_adt_opt_timeout(opt, map) }
+
+#define IP_SET_INIT_UEXT(map) \
+ { .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \
+ .timeout = (map)->timeout }
+
#endif /*_IP_SET_H */
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h
deleted file mode 100644
index 01d25e6fc792..000000000000
--- a/include/linux/netfilter/ipset/ip_set_ahash.h
+++ /dev/null
@@ -1,1225 +0,0 @@
-#ifndef _IP_SET_AHASH_H
-#define _IP_SET_AHASH_H
-
-#include <linux/rcupdate.h>
-#include <linux/jhash.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
-
-#define CONCAT(a, b, c) a##b##c
-#define TOKEN(a, b, c) CONCAT(a, b, c)
-
-#define type_pf_next TOKEN(TYPE, PF, _elem)
-
-/* Hashing which uses arrays to resolve clashing. The hash table is resized
- * (doubled) when searching becomes too long.
- * Internally jhash is used with the assumption that the size of the
- * stored data is a multiple of sizeof(u32). If storage supports timeout,
- * the timeout field must be the last one in the data structure - that field
- * is ignored when computing the hash key.
- *
- * Readers and resizing
- *
- * Resizing can be triggered by userspace command only, and those
- * are serialized by the nfnl mutex. During resizing the set is
- * read-locked, so the only possible concurrent operations are
- * the kernel side readers. Those must be protected by proper RCU locking.
- */
-
-/* Number of elements to store in an initial array block */
-#define AHASH_INIT_SIZE 4
-/* Max number of elements to store in an array block */
-#define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE)
-
-/* Max number of elements can be tuned */
-#ifdef IP_SET_HASH_WITH_MULTI
-#define AHASH_MAX(h) ((h)->ahash_max)
-
-static inline u8
-tune_ahash_max(u8 curr, u32 multi)
-{
- u32 n;
-
- if (multi < curr)
- return curr;
-
- n = curr + AHASH_INIT_SIZE;
- /* Currently, at listing one hash bucket must fit into a message.
- * Therefore we have a hard limit here.
- */
- return n > curr && n <= 64 ? n : curr;
-}
-#define TUNE_AHASH_MAX(h, multi) \
- ((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
-#else
-#define AHASH_MAX(h) AHASH_MAX_SIZE
-#define TUNE_AHASH_MAX(h, multi)
-#endif
-
-/* A hash bucket */
-struct hbucket {
- void *value; /* the array of the values */
- u8 size; /* size of the array */
- u8 pos; /* position of the first free entry */
-};
-
-/* The hash table: the table size stored here in order to make resizing easy */
-struct htable {
- u8 htable_bits; /* size of hash table == 2^htable_bits */
- struct hbucket bucket[0]; /* hashtable buckets */
-};
-
-#define hbucket(h, i) (&((h)->bucket[i]))
-
-/* Book-keeping of the prefixes added to the set */
-struct ip_set_hash_nets {
- u8 cidr; /* the different cidr values in the set */
- u32 nets; /* number of elements per cidr */
-};
-
-/* The generic ip_set hash structure */
-struct ip_set_hash {
- struct htable *table; /* the hash table */
- u32 maxelem; /* max elements in the hash */
- u32 elements; /* current element (vs timeout) */
- u32 initval; /* random jhash init value */
- u32 timeout; /* timeout value, if enabled */
- struct timer_list gc; /* garbage collection when timeout enabled */
- struct type_pf_next next; /* temporary storage for uadd */
-#ifdef IP_SET_HASH_WITH_MULTI
- u8 ahash_max; /* max elements in an array block */
-#endif
-#ifdef IP_SET_HASH_WITH_NETMASK
- u8 netmask; /* netmask value for subnets to store */
-#endif
-#ifdef IP_SET_HASH_WITH_RBTREE
- struct rb_root rbtree;
-#endif
-#ifdef IP_SET_HASH_WITH_NETS
- struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */
-#endif
-};
-
-static size_t
-htable_size(u8 hbits)
-{
- size_t hsize;
-
- /* We must fit both into u32 in jhash and size_t */
- if (hbits > 31)
- return 0;
- hsize = jhash_size(hbits);
- if ((((size_t)-1) - sizeof(struct htable))/sizeof(struct hbucket)
- < hsize)
- return 0;
-
- return hsize * sizeof(struct hbucket) + sizeof(struct htable);
-}
-
-/* Compute htable_bits from the user input parameter hashsize */
-static u8
-htable_bits(u32 hashsize)
-{
- /* Assume that hashsize == 2^htable_bits */
- u8 bits = fls(hashsize - 1);
- if (jhash_size(bits) != hashsize)
- /* Round up to the first 2^n value */
- bits = fls(hashsize);
-
- return bits;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-#ifdef IP_SET_HASH_WITH_NETS_PACKED
-/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
-#define CIDR(cidr) (cidr + 1)
-#else
-#define CIDR(cidr) (cidr)
-#endif
-
-#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
-#ifdef IP_SET_HASH_WITH_MULTI
-#define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1)
-#else
-#define NETS_LENGTH(family) SET_HOST_MASK(family)
-#endif
-
-/* Network cidr size book keeping when the hash stores different
- * sized networks */
-static void
-add_cidr(struct ip_set_hash *h, u8 cidr, u8 nets_length)
-{
- int i, j;
-
- /* Add in increasing prefix order, so larger cidr first */
- for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
- if (j != -1)
- continue;
- else if (h->nets[i].cidr < cidr)
- j = i;
- else if (h->nets[i].cidr == cidr) {
- h->nets[i].nets++;
- return;
- }
- }
- if (j != -1) {
- for (; i > j; i--) {
- h->nets[i].cidr = h->nets[i - 1].cidr;
- h->nets[i].nets = h->nets[i - 1].nets;
- }
- }
- h->nets[i].cidr = cidr;
- h->nets[i].nets = 1;
-}
-
-static void
-del_cidr(struct ip_set_hash *h, u8 cidr, u8 nets_length)
-{
- u8 i, j;
-
- for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
- ;
- h->nets[i].nets--;
-
- if (h->nets[i].nets != 0)
- return;
-
- for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
- h->nets[j].cidr = h->nets[j + 1].cidr;
- h->nets[j].nets = h->nets[j + 1].nets;
- }
-}
-#else
-#define NETS_LENGTH(family) 0
-#endif
-
-/* Destroy the hashtable part of the set */
-static void
-ahash_destroy(struct htable *t)
-{
- struct hbucket *n;
- u32 i;
-
- for (i = 0; i < jhash_size(t->htable_bits); i++) {
- n = hbucket(t, i);
- if (n->size)
- /* FIXME: use slab cache */
- kfree(n->value);
- }
-
- ip_set_free(t);
-}
-
-/* Calculate the actual memory size of the set data */
-static size_t
-ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 nets_length)
-{
- u32 i;
- struct htable *t = h->table;
- size_t memsize = sizeof(*h)
- + sizeof(*t)
-#ifdef IP_SET_HASH_WITH_NETS
- + sizeof(struct ip_set_hash_nets) * nets_length
-#endif
- + jhash_size(t->htable_bits) * sizeof(struct hbucket);
-
- for (i = 0; i < jhash_size(t->htable_bits); i++)
- memsize += t->bucket[i].size * dsize;
-
- return memsize;
-}
-
-/* Flush a hash type of set: destroy all elements */
-static void
-ip_set_hash_flush(struct ip_set *set)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- struct hbucket *n;
- u32 i;
-
- for (i = 0; i < jhash_size(t->htable_bits); i++) {
- n = hbucket(t, i);
- if (n->size) {
- n->size = n->pos = 0;
- /* FIXME: use slab cache */
- kfree(n->value);
- }
- }
-#ifdef IP_SET_HASH_WITH_NETS
- memset(h->nets, 0, sizeof(struct ip_set_hash_nets)
- * NETS_LENGTH(set->family));
-#endif
- h->elements = 0;
-}
-
-/* Destroy a hash type of set */
-static void
-ip_set_hash_destroy(struct ip_set *set)
-{
- struct ip_set_hash *h = set->data;
-
- if (with_timeout(h->timeout))
- del_timer_sync(&h->gc);
-
- ahash_destroy(h->table);
-#ifdef IP_SET_HASH_WITH_RBTREE
- rbtree_destroy(&h->rbtree);
-#endif
- kfree(h);
-
- set->data = NULL;
-}
-
-#endif /* _IP_SET_AHASH_H */
-
-#ifndef HKEY_DATALEN
-#define HKEY_DATALEN sizeof(struct type_pf_elem)
-#endif
-
-#define HKEY(data, initval, htable_bits) \
-(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval) \
- & jhash_mask(htable_bits))
-
-/* Type/family dependent function prototypes */
-
-#define type_pf_data_equal TOKEN(TYPE, PF, _data_equal)
-#define type_pf_data_isnull TOKEN(TYPE, PF, _data_isnull)
-#define type_pf_data_copy TOKEN(TYPE, PF, _data_copy)
-#define type_pf_data_zero_out TOKEN(TYPE, PF, _data_zero_out)
-#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask)
-#define type_pf_data_list TOKEN(TYPE, PF, _data_list)
-#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist)
-#define type_pf_data_next TOKEN(TYPE, PF, _data_next)
-#define type_pf_data_flags TOKEN(TYPE, PF, _data_flags)
-#ifdef IP_SET_HASH_WITH_NETS
-#define type_pf_data_match TOKEN(TYPE, PF, _data_match)
-#else
-#define type_pf_data_match(d) 1
-#endif
-
-#define type_pf_elem TOKEN(TYPE, PF, _elem)
-#define type_pf_telem TOKEN(TYPE, PF, _telem)
-#define type_pf_data_timeout TOKEN(TYPE, PF, _data_timeout)
-#define type_pf_data_expired TOKEN(TYPE, PF, _data_expired)
-#define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set)
-
-#define type_pf_elem_add TOKEN(TYPE, PF, _elem_add)
-#define type_pf_add TOKEN(TYPE, PF, _add)
-#define type_pf_del TOKEN(TYPE, PF, _del)
-#define type_pf_test_cidrs TOKEN(TYPE, PF, _test_cidrs)
-#define type_pf_test TOKEN(TYPE, PF, _test)
-
-#define type_pf_elem_tadd TOKEN(TYPE, PF, _elem_tadd)
-#define type_pf_del_telem TOKEN(TYPE, PF, _ahash_del_telem)
-#define type_pf_expire TOKEN(TYPE, PF, _expire)
-#define type_pf_tadd TOKEN(TYPE, PF, _tadd)
-#define type_pf_tdel TOKEN(TYPE, PF, _tdel)
-#define type_pf_ttest_cidrs TOKEN(TYPE, PF, _ahash_ttest_cidrs)
-#define type_pf_ttest TOKEN(TYPE, PF, _ahash_ttest)
-
-#define type_pf_resize TOKEN(TYPE, PF, _resize)
-#define type_pf_tresize TOKEN(TYPE, PF, _tresize)
-#define type_pf_flush ip_set_hash_flush
-#define type_pf_destroy ip_set_hash_destroy
-#define type_pf_head TOKEN(TYPE, PF, _head)
-#define type_pf_list TOKEN(TYPE, PF, _list)
-#define type_pf_tlist TOKEN(TYPE, PF, _tlist)
-#define type_pf_same_set TOKEN(TYPE, PF, _same_set)
-#define type_pf_kadt TOKEN(TYPE, PF, _kadt)
-#define type_pf_uadt TOKEN(TYPE, PF, _uadt)
-#define type_pf_gc TOKEN(TYPE, PF, _gc)
-#define type_pf_gc_init TOKEN(TYPE, PF, _gc_init)
-#define type_pf_variant TOKEN(TYPE, PF, _variant)
-#define type_pf_tvariant TOKEN(TYPE, PF, _tvariant)
-
-/* Flavour without timeout */
-
-/* Get the ith element from the array block n */
-#define ahash_data(n, i) \
- ((struct type_pf_elem *)((n)->value) + (i))
-
-/* Add an element to the hash table when resizing the set:
- * we spare the maintenance of the internal counters. */
-static int
-type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value,
- u8 ahash_max, u32 cadt_flags)
-{
- struct type_pf_elem *data;
-
- if (n->pos >= n->size) {
- void *tmp;
-
- if (n->size >= ahash_max)
- /* Trigger rehashing */
- return -EAGAIN;
-
- tmp = kzalloc((n->size + AHASH_INIT_SIZE)
- * sizeof(struct type_pf_elem),
- GFP_ATOMIC);
- if (!tmp)
- return -ENOMEM;
- if (n->size) {
- memcpy(tmp, n->value,
- sizeof(struct type_pf_elem) * n->size);
- kfree(n->value);
- }
- n->value = tmp;
- n->size += AHASH_INIT_SIZE;
- }
- data = ahash_data(n, n->pos++);
- type_pf_data_copy(data, value);
-#ifdef IP_SET_HASH_WITH_NETS
- /* Resizing won't overwrite stored flags */
- if (cadt_flags)
- type_pf_data_flags(data, cadt_flags);
-#endif
- return 0;
-}
-
-/* Resize a hash: create a new hash table with doubling the hashsize
- * and inserting the elements to it. Repeat until we succeed or
- * fail due to memory pressures. */
-static int
-type_pf_resize(struct ip_set *set, bool retried)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t, *orig = h->table;
- u8 htable_bits = orig->htable_bits;
- const struct type_pf_elem *data;
- struct hbucket *n, *m;
- u32 i, j;
- int ret;
-
-retry:
- ret = 0;
- htable_bits++;
- pr_debug("attempt to resize set %s from %u to %u, t %p\n",
- set->name, orig->htable_bits, htable_bits, orig);
- if (!htable_bits) {
- /* In case we have plenty of memory :-) */
- pr_warning("Cannot increase the hashsize of set %s further\n",
- set->name);
- return -IPSET_ERR_HASH_FULL;
- }
- t = ip_set_alloc(sizeof(*t)
- + jhash_size(htable_bits) * sizeof(struct hbucket));
- if (!t)
- return -ENOMEM;
- t->htable_bits = htable_bits;
-
- read_lock_bh(&set->lock);
- for (i = 0; i < jhash_size(orig->htable_bits); i++) {
- n = hbucket(orig, i);
- for (j = 0; j < n->pos; j++) {
- data = ahash_data(n, j);
- m = hbucket(t, HKEY(data, h->initval, htable_bits));
- ret = type_pf_elem_add(m, data, AHASH_MAX(h), 0);
- if (ret < 0) {
- read_unlock_bh(&set->lock);
- ahash_destroy(t);
- if (ret == -EAGAIN)
- goto retry;
- return ret;
- }
- }
- }
-
- rcu_assign_pointer(h->table, t);
- read_unlock_bh(&set->lock);
-
- /* Give time to other readers of the set */
- synchronize_rcu_bh();
-
- pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
- orig->htable_bits, orig, t->htable_bits, t);
- ahash_destroy(orig);
-
- return 0;
-}
-
-static inline void
-type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
-
-/* Add an element to a hash and update the internal counters when succeeded,
- * otherwise report the proper error code. */
-static int
-type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t;
- const struct type_pf_elem *d = value;
- struct hbucket *n;
- int i, ret = 0;
- u32 key, multi = 0;
- u32 cadt_flags = flags >> 16;
-
- if (h->elements >= h->maxelem) {
- if (net_ratelimit())
- pr_warning("Set %s is full, maxelem %u reached\n",
- set->name, h->maxelem);
- return -IPSET_ERR_HASH_FULL;
- }
-
- rcu_read_lock_bh();
- t = rcu_dereference_bh(h->table);
- key = HKEY(value, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++)
- if (type_pf_data_equal(ahash_data(n, i), d, &multi)) {
-#ifdef IP_SET_HASH_WITH_NETS
- if (flags & IPSET_FLAG_EXIST)
- /* Support overwriting just the flags */
- type_pf_data_flags(ahash_data(n, i),
- cadt_flags);
-#endif
- ret = -IPSET_ERR_EXIST;
- goto out;
- }
- TUNE_AHASH_MAX(h, multi);
- ret = type_pf_elem_add(n, value, AHASH_MAX(h), cadt_flags);
- if (ret != 0) {
- if (ret == -EAGAIN)
- type_pf_data_next(h, d);
- goto out;
- }
-
-#ifdef IP_SET_HASH_WITH_NETS
- add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
-#endif
- h->elements++;
-out:
- rcu_read_unlock_bh();
- return ret;
-}
-
-/* Delete an element from the hash: swap it with the last element
- * and free up space if possible.
- */
-static int
-type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- const struct type_pf_elem *d = value;
- struct hbucket *n;
- int i;
- struct type_pf_elem *data;
- u32 key, multi = 0;
-
- key = HKEY(value, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i);
- if (!type_pf_data_equal(data, d, &multi))
- continue;
- if (i != n->pos - 1)
- /* Not last one */
- type_pf_data_copy(data, ahash_data(n, n->pos - 1));
-
- n->pos--;
- h->elements--;
-#ifdef IP_SET_HASH_WITH_NETS
- del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
-#endif
- if (n->pos + AHASH_INIT_SIZE < n->size) {
- void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
- * sizeof(struct type_pf_elem),
- GFP_ATOMIC);
- if (!tmp)
- return 0;
- n->size -= AHASH_INIT_SIZE;
- memcpy(tmp, n->value,
- n->size * sizeof(struct type_pf_elem));
- kfree(n->value);
- n->value = tmp;
- }
- return 0;
- }
-
- return -IPSET_ERR_EXIST;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-
-/* Special test function which takes into account the different network
- * sizes added to the set */
-static int
-type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- struct hbucket *n;
- const struct type_pf_elem *data;
- int i, j = 0;
- u32 key, multi = 0;
- u8 nets_length = NETS_LENGTH(set->family);
-
- pr_debug("test by nets\n");
- for (; j < nets_length && h->nets[j].nets && !multi; j++) {
- type_pf_data_netmask(d, h->nets[j].cidr);
- key = HKEY(d, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i);
- if (type_pf_data_equal(data, d, &multi))
- return type_pf_data_match(data);
- }
- }
- return 0;
-}
-#endif
-
-/* Test whether the element is added to the set */
-static int
-type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- struct type_pf_elem *d = value;
- struct hbucket *n;
- const struct type_pf_elem *data;
- int i;
- u32 key, multi = 0;
-
-#ifdef IP_SET_HASH_WITH_NETS
- /* If we test an IP address and not a network address,
- * try all possible network sizes */
- if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
- return type_pf_test_cidrs(set, d, timeout);
-#endif
-
- key = HKEY(d, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i);
- if (type_pf_data_equal(data, d, &multi))
- return type_pf_data_match(data);
- }
- return 0;
-}
-
-/* Reply a HEADER request: fill out the header part of the set */
-static int
-type_pf_head(struct ip_set *set, struct sk_buff *skb)
-{
- const struct ip_set_hash *h = set->data;
- struct nlattr *nested;
- size_t memsize;
-
- read_lock_bh(&set->lock);
- memsize = ahash_memsize(h, with_timeout(h->timeout)
- ? sizeof(struct type_pf_telem)
- : sizeof(struct type_pf_elem),
- NETS_LENGTH(set->family));
- read_unlock_bh(&set->lock);
-
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested)
- goto nla_put_failure;
- if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
- htonl(jhash_size(h->table->htable_bits))) ||
- nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
- goto nla_put_failure;
-#ifdef IP_SET_HASH_WITH_NETMASK
- if (h->netmask != HOST_MASK &&
- nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
- goto nla_put_failure;
-#endif
- if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
- (with_timeout(h->timeout) &&
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
-
- return 0;
-nla_put_failure:
- return -EMSGSIZE;
-}
-
-/* Reply a LIST/SAVE request: dump the elements of the specified set */
-static int
-type_pf_list(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
-{
- const struct ip_set_hash *h = set->data;
- const struct htable *t = h->table;
- struct nlattr *atd, *nested;
- const struct hbucket *n;
- const struct type_pf_elem *data;
- u32 first = cb->args[2];
- /* We assume that one hash bucket fills into one page */
- void *incomplete;
- int i;
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- pr_debug("list hash set %s\n", set->name);
- for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
- incomplete = skb_tail_pointer(skb);
- n = hbucket(t, cb->args[2]);
- pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
- for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i);
- pr_debug("list hash %lu hbucket %p i %u, data %p\n",
- cb->args[2], n, i, data);
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (cb->args[2] == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (type_pf_data_list(skb, data))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
-
-nla_put_failure:
- nlmsg_trim(skb, incomplete);
- ipset_nest_end(skb, atd);
- if (unlikely(first == cb->args[2])) {
- pr_warning("Can't list set %s: one bucket does not fit into "
- "a message. Please report it!\n", set->name);
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
-}
-
-static int
-type_pf_kadt(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt);
-static int
-type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
-
-static const struct ip_set_type_variant type_pf_variant = {
- .kadt = type_pf_kadt,
- .uadt = type_pf_uadt,
- .adt = {
- [IPSET_ADD] = type_pf_add,
- [IPSET_DEL] = type_pf_del,
- [IPSET_TEST] = type_pf_test,
- },
- .destroy = type_pf_destroy,
- .flush = type_pf_flush,
- .head = type_pf_head,
- .list = type_pf_list,
- .resize = type_pf_resize,
- .same_set = type_pf_same_set,
-};
-
-/* Flavour with timeout support */
-
-#define ahash_tdata(n, i) \
- (struct type_pf_elem *)((struct type_pf_telem *)((n)->value) + (i))
-
-static inline u32
-type_pf_data_timeout(const struct type_pf_elem *data)
-{
- const struct type_pf_telem *tdata =
- (const struct type_pf_telem *) data;
-
- return tdata->timeout;
-}
-
-static inline bool
-type_pf_data_expired(const struct type_pf_elem *data)
-{
- const struct type_pf_telem *tdata =
- (const struct type_pf_telem *) data;
-
- return ip_set_timeout_expired(tdata->timeout);
-}
-
-static inline void
-type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
-{
- struct type_pf_telem *tdata = (struct type_pf_telem *) data;
-
- tdata->timeout = ip_set_timeout_set(timeout);
-}
-
-static int
-type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,
- u8 ahash_max, u32 cadt_flags, u32 timeout)
-{
- struct type_pf_elem *data;
-
- if (n->pos >= n->size) {
- void *tmp;
-
- if (n->size >= ahash_max)
- /* Trigger rehashing */
- return -EAGAIN;
-
- tmp = kzalloc((n->size + AHASH_INIT_SIZE)
- * sizeof(struct type_pf_telem),
- GFP_ATOMIC);
- if (!tmp)
- return -ENOMEM;
- if (n->size) {
- memcpy(tmp, n->value,
- sizeof(struct type_pf_telem) * n->size);
- kfree(n->value);
- }
- n->value = tmp;
- n->size += AHASH_INIT_SIZE;
- }
- data = ahash_tdata(n, n->pos++);
- type_pf_data_copy(data, value);
- type_pf_data_timeout_set(data, timeout);
-#ifdef IP_SET_HASH_WITH_NETS
- /* Resizing won't overwrite stored flags */
- if (cadt_flags)
- type_pf_data_flags(data, cadt_flags);
-#endif
- return 0;
-}
-
-/* Delete expired elements from the hashtable */
-static void
-type_pf_expire(struct ip_set_hash *h, u8 nets_length)
-{
- struct htable *t = h->table;
- struct hbucket *n;
- struct type_pf_elem *data;
- u32 i;
- int j;
-
- for (i = 0; i < jhash_size(t->htable_bits); i++) {
- n = hbucket(t, i);
- for (j = 0; j < n->pos; j++) {
- data = ahash_tdata(n, j);
- if (type_pf_data_expired(data)) {
- pr_debug("expired %u/%u\n", i, j);
-#ifdef IP_SET_HASH_WITH_NETS
- del_cidr(h, CIDR(data->cidr), nets_length);
-#endif
- if (j != n->pos - 1)
- /* Not last one */
- type_pf_data_copy(data,
- ahash_tdata(n, n->pos - 1));
- n->pos--;
- h->elements--;
- }
- }
- if (n->pos + AHASH_INIT_SIZE < n->size) {
- void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
- * sizeof(struct type_pf_telem),
- GFP_ATOMIC);
- if (!tmp)
- /* Still try to delete expired elements */
- continue;
- n->size -= AHASH_INIT_SIZE;
- memcpy(tmp, n->value,
- n->size * sizeof(struct type_pf_telem));
- kfree(n->value);
- n->value = tmp;
- }
- }
-}
-
-static int
-type_pf_tresize(struct ip_set *set, bool retried)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t, *orig = h->table;
- u8 htable_bits = orig->htable_bits;
- const struct type_pf_elem *data;
- struct hbucket *n, *m;
- u32 i, j;
- int ret;
-
- /* Try to cleanup once */
- if (!retried) {
- i = h->elements;
- write_lock_bh(&set->lock);
- type_pf_expire(set->data, NETS_LENGTH(set->family));
- write_unlock_bh(&set->lock);
- if (h->elements < i)
- return 0;
- }
-
-retry:
- ret = 0;
- htable_bits++;
- pr_debug("attempt to resize set %s from %u to %u, t %p\n",
- set->name, orig->htable_bits, htable_bits, orig);
- if (!htable_bits) {
- /* In case we have plenty of memory :-) */
- pr_warning("Cannot increase the hashsize of set %s further\n",
- set->name);
- return -IPSET_ERR_HASH_FULL;
- }
- t = ip_set_alloc(sizeof(*t)
- + jhash_size(htable_bits) * sizeof(struct hbucket));
- if (!t)
- return -ENOMEM;
- t->htable_bits = htable_bits;
-
- read_lock_bh(&set->lock);
- for (i = 0; i < jhash_size(orig->htable_bits); i++) {
- n = hbucket(orig, i);
- for (j = 0; j < n->pos; j++) {
- data = ahash_tdata(n, j);
- m = hbucket(t, HKEY(data, h->initval, htable_bits));
- ret = type_pf_elem_tadd(m, data, AHASH_MAX(h), 0,
- ip_set_timeout_get(type_pf_data_timeout(data)));
- if (ret < 0) {
- read_unlock_bh(&set->lock);
- ahash_destroy(t);
- if (ret == -EAGAIN)
- goto retry;
- return ret;
- }
- }
- }
-
- rcu_assign_pointer(h->table, t);
- read_unlock_bh(&set->lock);
-
- /* Give time to other readers of the set */
- synchronize_rcu_bh();
-
- ahash_destroy(orig);
-
- return 0;
-}
-
-static int
-type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- const struct type_pf_elem *d = value;
- struct hbucket *n;
- struct type_pf_elem *data;
- int ret = 0, i, j = AHASH_MAX(h) + 1;
- bool flag_exist = flags & IPSET_FLAG_EXIST;
- u32 key, multi = 0;
- u32 cadt_flags = flags >> 16;
-
- if (h->elements >= h->maxelem)
- /* FIXME: when set is full, we slow down here */
- type_pf_expire(h, NETS_LENGTH(set->family));
- if (h->elements >= h->maxelem) {
- if (net_ratelimit())
- pr_warning("Set %s is full, maxelem %u reached\n",
- set->name, h->maxelem);
- return -IPSET_ERR_HASH_FULL;
- }
-
- rcu_read_lock_bh();
- t = rcu_dereference_bh(h->table);
- key = HKEY(d, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_tdata(n, i);
- if (type_pf_data_equal(data, d, &multi)) {
- if (type_pf_data_expired(data) || flag_exist)
- /* Just timeout value may be updated */
- j = i;
- else {
- ret = -IPSET_ERR_EXIST;
- goto out;
- }
- } else if (j == AHASH_MAX(h) + 1 &&
- type_pf_data_expired(data))
- j = i;
- }
- if (j != AHASH_MAX(h) + 1) {
- data = ahash_tdata(n, j);
-#ifdef IP_SET_HASH_WITH_NETS
- del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
- add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
-#endif
- type_pf_data_copy(data, d);
- type_pf_data_timeout_set(data, timeout);
-#ifdef IP_SET_HASH_WITH_NETS
- type_pf_data_flags(data, cadt_flags);
-#endif
- goto out;
- }
- TUNE_AHASH_MAX(h, multi);
- ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), cadt_flags, timeout);
- if (ret != 0) {
- if (ret == -EAGAIN)
- type_pf_data_next(h, d);
- goto out;
- }
-
-#ifdef IP_SET_HASH_WITH_NETS
- add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
-#endif
- h->elements++;
-out:
- rcu_read_unlock_bh();
- return ret;
-}
-
-static int
-type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- const struct type_pf_elem *d = value;
- struct hbucket *n;
- int i;
- struct type_pf_elem *data;
- u32 key, multi = 0;
-
- key = HKEY(value, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_tdata(n, i);
- if (!type_pf_data_equal(data, d, &multi))
- continue;
- if (type_pf_data_expired(data))
- return -IPSET_ERR_EXIST;
- if (i != n->pos - 1)
- /* Not last one */
- type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));
-
- n->pos--;
- h->elements--;
-#ifdef IP_SET_HASH_WITH_NETS
- del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
-#endif
- if (n->pos + AHASH_INIT_SIZE < n->size) {
- void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
- * sizeof(struct type_pf_telem),
- GFP_ATOMIC);
- if (!tmp)
- return 0;
- n->size -= AHASH_INIT_SIZE;
- memcpy(tmp, n->value,
- n->size * sizeof(struct type_pf_telem));
- kfree(n->value);
- n->value = tmp;
- }
- return 0;
- }
-
- return -IPSET_ERR_EXIST;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-static int
-type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- struct type_pf_elem *data;
- struct hbucket *n;
- int i, j = 0;
- u32 key, multi = 0;
- u8 nets_length = NETS_LENGTH(set->family);
-
- for (; j < nets_length && h->nets[j].nets && !multi; j++) {
- type_pf_data_netmask(d, h->nets[j].cidr);
- key = HKEY(d, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_tdata(n, i);
-#ifdef IP_SET_HASH_WITH_MULTI
- if (type_pf_data_equal(data, d, &multi)) {
- if (!type_pf_data_expired(data))
- return type_pf_data_match(data);
- multi = 0;
- }
-#else
- if (type_pf_data_equal(data, d, &multi) &&
- !type_pf_data_expired(data))
- return type_pf_data_match(data);
-#endif
- }
- }
- return 0;
-}
-#endif
-
-static int
-type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct ip_set_hash *h = set->data;
- struct htable *t = h->table;
- struct type_pf_elem *data, *d = value;
- struct hbucket *n;
- int i;
- u32 key, multi = 0;
-
-#ifdef IP_SET_HASH_WITH_NETS
- if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
- return type_pf_ttest_cidrs(set, d, timeout);
-#endif
- key = HKEY(d, h->initval, t->htable_bits);
- n = hbucket(t, key);
- for (i = 0; i < n->pos; i++) {
- data = ahash_tdata(n, i);
- if (type_pf_data_equal(data, d, &multi) &&
- !type_pf_data_expired(data))
- return type_pf_data_match(data);
- }
- return 0;
-}
-
-static int
-type_pf_tlist(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
-{
- const struct ip_set_hash *h = set->data;
- const struct htable *t = h->table;
- struct nlattr *atd, *nested;
- const struct hbucket *n;
- const struct type_pf_elem *data;
- u32 first = cb->args[2];
- /* We assume that one hash bucket fills into one page */
- void *incomplete;
- int i;
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
- incomplete = skb_tail_pointer(skb);
- n = hbucket(t, cb->args[2]);
- for (i = 0; i < n->pos; i++) {
- data = ahash_tdata(n, i);
- pr_debug("list %p %u\n", n, i);
- if (type_pf_data_expired(data))
- continue;
- pr_debug("do list %p %u\n", n, i);
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (cb->args[2] == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (type_pf_data_tlist(skb, data))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
-
-nla_put_failure:
- nlmsg_trim(skb, incomplete);
- ipset_nest_end(skb, atd);
- if (unlikely(first == cb->args[2])) {
- pr_warning("Can't list set %s: one bucket does not fit into "
- "a message. Please report it!\n", set->name);
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
-}
-
-static const struct ip_set_type_variant type_pf_tvariant = {
- .kadt = type_pf_kadt,
- .uadt = type_pf_uadt,
- .adt = {
- [IPSET_ADD] = type_pf_tadd,
- [IPSET_DEL] = type_pf_tdel,
- [IPSET_TEST] = type_pf_ttest,
- },
- .destroy = type_pf_destroy,
- .flush = type_pf_flush,
- .head = type_pf_head,
- .list = type_pf_tlist,
- .resize = type_pf_tresize,
- .same_set = type_pf_same_set,
-};
-
-static void
-type_pf_gc(unsigned long ul_set)
-{
- struct ip_set *set = (struct ip_set *) ul_set;
- struct ip_set_hash *h = set->data;
-
- pr_debug("called\n");
- write_lock_bh(&set->lock);
- type_pf_expire(h, NETS_LENGTH(set->family));
- write_unlock_bh(&set->lock);
-
- h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
- add_timer(&h->gc);
-}
-
-static void
-type_pf_gc_init(struct ip_set *set)
-{
- struct ip_set_hash *h = set->data;
-
- init_timer(&h->gc);
- h->gc.data = (unsigned long) set;
- h->gc.function = type_pf_gc;
- h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
- add_timer(&h->gc);
- pr_debug("gc initialized, run in every %u\n",
- IPSET_GC_PERIOD(h->timeout));
-}
-
-#undef HKEY_DATALEN
-#undef HKEY
-#undef type_pf_data_equal
-#undef type_pf_data_isnull
-#undef type_pf_data_copy
-#undef type_pf_data_zero_out
-#undef type_pf_data_netmask
-#undef type_pf_data_list
-#undef type_pf_data_tlist
-#undef type_pf_data_next
-#undef type_pf_data_flags
-#undef type_pf_data_match
-
-#undef type_pf_elem
-#undef type_pf_telem
-#undef type_pf_data_timeout
-#undef type_pf_data_expired
-#undef type_pf_data_timeout_set
-
-#undef type_pf_elem_add
-#undef type_pf_add
-#undef type_pf_del
-#undef type_pf_test_cidrs
-#undef type_pf_test
-
-#undef type_pf_elem_tadd
-#undef type_pf_del_telem
-#undef type_pf_expire
-#undef type_pf_tadd
-#undef type_pf_tdel
-#undef type_pf_ttest_cidrs
-#undef type_pf_ttest
-
-#undef type_pf_resize
-#undef type_pf_tresize
-#undef type_pf_flush
-#undef type_pf_destroy
-#undef type_pf_head
-#undef type_pf_list
-#undef type_pf_tlist
-#undef type_pf_same_set
-#undef type_pf_kadt
-#undef type_pf_uadt
-#undef type_pf_gc
-#undef type_pf_gc_init
-#undef type_pf_variant
-#undef type_pf_tvariant
diff --git a/include/linux/netfilter/ipset/ip_set_bitmap.h b/include/linux/netfilter/ipset/ip_set_bitmap.h
index 1a30646d5be8..5e4662a71e01 100644
--- a/include/linux/netfilter/ipset/ip_set_bitmap.h
+++ b/include/linux/netfilter/ipset/ip_set_bitmap.h
@@ -5,6 +5,12 @@
#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF
+enum {
+ IPSET_ADD_FAILED = 1,
+ IPSET_ADD_STORE_PLAIN_TIMEOUT,
+ IPSET_ADD_START_STORED_TIMEOUT,
+};
+
/* Common functions */
static inline u32
diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h
index 41d9cfa08167..3aac04167ca7 100644
--- a/include/linux/netfilter/ipset/ip_set_timeout.h
+++ b/include/linux/netfilter/ipset/ip_set_timeout.h
@@ -1,7 +1,7 @@
#ifndef _IP_SET_TIMEOUT_H
#define _IP_SET_TIMEOUT_H
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -17,13 +17,14 @@
#define IPSET_GC_PERIOD(timeout) \
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
-/* Set is defined without timeout support: timeout value may be 0 */
-#define IPSET_NO_TIMEOUT UINT_MAX
+/* Entry is set with no timeout value */
+#define IPSET_ELEM_PERMANENT 0
-#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
+/* Set is defined with timeout support: timeout value may be 0 */
+#define IPSET_NO_TIMEOUT UINT_MAX
-#define opt_timeout(opt, map) \
- (with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
+#define ip_set_adt_opt_timeout(opt, map) \
+((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout)
static inline unsigned int
ip_set_timeout_uget(struct nlattr *tb)
@@ -38,61 +39,6 @@ ip_set_timeout_uget(struct nlattr *tb)
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
}
-#ifdef IP_SET_BITMAP_TIMEOUT
-
-/* Bitmap specific timeout constants and macros for the entries */
-
-/* Bitmap entry is unset */
-#define IPSET_ELEM_UNSET 0
-/* Bitmap entry is set with no timeout value */
-#define IPSET_ELEM_PERMANENT (UINT_MAX/2)
-
-static inline bool
-ip_set_timeout_test(unsigned long timeout)
-{
- return timeout != IPSET_ELEM_UNSET &&
- (timeout == IPSET_ELEM_PERMANENT ||
- time_is_after_jiffies(timeout));
-}
-
-static inline bool
-ip_set_timeout_expired(unsigned long timeout)
-{
- return timeout != IPSET_ELEM_UNSET &&
- timeout != IPSET_ELEM_PERMANENT &&
- time_is_before_jiffies(timeout);
-}
-
-static inline unsigned long
-ip_set_timeout_set(u32 timeout)
-{
- unsigned long t;
-
- if (!timeout)
- return IPSET_ELEM_PERMANENT;
-
- t = msecs_to_jiffies(timeout * 1000) + jiffies;
- if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
- /* Bingo! */
- t++;
-
- return t;
-}
-
-static inline u32
-ip_set_timeout_get(unsigned long timeout)
-{
- return timeout == IPSET_ELEM_PERMANENT ? 0 :
- jiffies_to_msecs(timeout - jiffies)/1000;
-}
-
-#else
-
-/* Hash specific timeout constants and macros for the entries */
-
-/* Hash entry is set with no timeout value */
-#define IPSET_ELEM_PERMANENT 0
-
static inline bool
ip_set_timeout_test(unsigned long timeout)
{
@@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout)
}
static inline bool
-ip_set_timeout_expired(unsigned long timeout)
+ip_set_timeout_expired(unsigned long *timeout)
{
- return timeout != IPSET_ELEM_PERMANENT &&
- time_is_before_jiffies(timeout);
+ return *timeout != IPSET_ELEM_PERMANENT &&
+ time_is_before_jiffies(*timeout);
}
-static inline unsigned long
-ip_set_timeout_set(u32 timeout)
+static inline void
+ip_set_timeout_set(unsigned long *timeout, u32 t)
{
- unsigned long t;
-
- if (!timeout)
- return IPSET_ELEM_PERMANENT;
+ if (!t) {
+ *timeout = IPSET_ELEM_PERMANENT;
+ return;
+ }
- t = msecs_to_jiffies(timeout * 1000) + jiffies;
- if (t == IPSET_ELEM_PERMANENT)
+ *timeout = msecs_to_jiffies(t * 1000) + jiffies;
+ if (*timeout == IPSET_ELEM_PERMANENT)
/* Bingo! :-) */
- t++;
-
- return t;
+ (*timeout)--;
}
static inline u32
-ip_set_timeout_get(unsigned long timeout)
+ip_set_timeout_get(unsigned long *timeout)
{
- return timeout == IPSET_ELEM_PERMANENT ? 0 :
- jiffies_to_msecs(timeout - jiffies)/1000;
+ return *timeout == IPSET_ELEM_PERMANENT ? 0 :
+ jiffies_to_msecs(*timeout - jiffies)/1000;
}
-#endif /* ! IP_SET_BITMAP_TIMEOUT */
#endif /* __KERNEL__ */
-
#endif /* _IP_SET_TIMEOUT_H */
diff --git a/include/linux/netfilter/ipset/pfxlen.h b/include/linux/netfilter/ipset/pfxlen.h
index 199fd11fedc0..1afbb94b4b65 100644
--- a/include/linux/netfilter/ipset/pfxlen.h
+++ b/include/linux/netfilter/ipset/pfxlen.h
@@ -41,4 +41,13 @@ do { \
to = from | ~ip_set_hostmask(cidr); \
} while (0)
+static inline void
+ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+{
+ ip->ip6[0] &= ip_set_netmask6(prefix)[0];
+ ip->ip6[1] &= ip_set_netmask6(prefix)[1];
+ ip->ip6[2] &= ip_set_netmask6(prefix)[2];
+ ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+}
+
#endif /*_PFXLEN_H */
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index ecbb8e495912..cadb7402d7a7 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -29,10 +29,13 @@ extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
extern int nfnetlink_has_listeners(struct net *net, unsigned int group);
-extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group,
- int echo, gfp_t flags);
-extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
-extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
+extern struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
+ u32 dst_portid, gfp_t gfp_mask);
+extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
+ unsigned int group, int echo, gfp_t flags);
+extern int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error);
+extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net,
+ u32 portid, int flags);
extern void nfnl_lock(__u8 subsys_id);
extern void nfnl_unlock(__u8 subsys_id);
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index e0f746b7b95c..6358da5eeee8 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -15,11 +15,18 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
return (struct nlmsghdr *)skb->data;
}
+enum netlink_skb_flags {
+ NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */
+ NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */
+ NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */
+};
+
struct netlink_skb_parms {
struct scm_creds creds; /* Skb credentials */
__u32 portid;
__u32 dst_group;
- struct sock *ssk;
+ __u32 flags;
+ struct sock *sk;
};
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))
@@ -57,6 +64,8 @@ extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group)
extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group);
extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
extern int netlink_has_listeners(struct sock *sk, unsigned int group);
+extern struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
+ u32 dst_portid, gfp_t gfp_mask);
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
__u32 group, gfp_t allocation);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 9d7d8c64f7c8..fa2cb76a7029 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -40,7 +40,7 @@ struct netpoll_info {
unsigned long rx_flags;
spinlock_t rx_lock;
- struct mutex dev_lock;
+ struct semaphore dev_lock;
struct list_head rx_np; /* netpolls that registered an rx_hook */
struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1cc25682b20b..fc01d5cb4cf1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -59,11 +59,18 @@ struct nfs_lockowner {
pid_t l_pid;
};
+#define NFS_IO_INPROGRESS 0
+struct nfs_io_counter {
+ unsigned long flags;
+ atomic_t io_count;
+};
+
struct nfs_lock_context {
atomic_t count;
struct list_head list;
struct nfs_open_context *open_context;
struct nfs_lockowner lockowner;
+ struct nfs_io_counter io_count;
};
struct nfs4_state;
@@ -77,6 +84,7 @@ struct nfs_open_context {
unsigned long flags;
#define NFS_CONTEXT_ERROR_WRITE (0)
#define NFS_CONTEXT_RESEND_WRITES (1)
+#define NFS_CONTEXT_BAD (2)
int error;
struct list_head list;
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 6c6ed153a9b4..3b7fa2abecca 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -40,6 +40,7 @@ struct nfs_client {
#define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */
#define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */
#define NFS_CS_MIGRATION 2 /* - transparent state migr */
+#define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */
struct sockaddr_storage cl_addr; /* server identifier */
size_t cl_addrlen;
char * cl_hostname; /* hostname of server */
@@ -197,5 +198,7 @@ struct nfs_server {
#define NFS_CAP_MTIME (1U << 13)
#define NFS_CAP_POSIX_LOCK (1U << 14)
#define NFS_CAP_UIDGID_NOMAP (1U << 15)
+#define NFS_CAP_STATEID_NFSV41 (1U << 16)
+#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17)
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4b993d358dad..766c5bc9d441 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -14,9 +14,6 @@
#define NFS_DEF_FILE_IO_SIZE (4096U)
#define NFS_MIN_FILE_IO_SIZE (1024U)
-/* Forward declaration for NFS v3 */
-struct nfs4_secinfo_flavors;
-
struct nfs4_string {
unsigned int len;
char *data;
@@ -349,6 +346,7 @@ struct nfs_openargs {
const u32 * bitmask;
const u32 * open_bitmap;
__u32 claim;
+ enum createmode4 createmode;
};
struct nfs_openres {
@@ -486,6 +484,7 @@ struct nfs_readargs {
struct nfs_fh * fh;
struct nfs_open_context *context;
struct nfs_lock_context *lock_context;
+ nfs4_stateid stateid;
__u64 offset;
__u32 count;
unsigned int pgbase;
@@ -507,6 +506,7 @@ struct nfs_writeargs {
struct nfs_fh * fh;
struct nfs_open_context *context;
struct nfs_lock_context *lock_context;
+ nfs4_stateid stateid;
__u64 offset;
__u32 count;
enum nfs3_stable_how stable;
@@ -1050,25 +1050,14 @@ struct nfs4_fs_locations_res {
struct nfs4_fs_locations *fs_locations;
};
-struct nfs4_secinfo_oid {
- unsigned int len;
- char data[GSS_OID_MAX_LEN];
-};
-
-struct nfs4_secinfo_gss {
- struct nfs4_secinfo_oid sec_oid4;
- unsigned int qop4;
- unsigned int service;
-};
-
-struct nfs4_secinfo_flavor {
- unsigned int flavor;
- struct nfs4_secinfo_gss gss;
+struct nfs4_secinfo4 {
+ u32 flavor;
+ struct rpcsec_gss_info flavor_info;
};
struct nfs4_secinfo_flavors {
- unsigned int num_flavors;
- struct nfs4_secinfo_flavor flavors[0];
+ unsigned int num_flavors;
+ struct nfs4_secinfo4 flavors[0];
};
struct nfs4_secinfo_arg {
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index d65746efc954..d14a4c362465 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -47,8 +47,11 @@
* runtime initialization.
*/
+typedef int (*notifier_fn_t)(struct notifier_block *nb,
+ unsigned long action, void *data);
+
struct notifier_block {
- int (*notifier_call)(struct notifier_block *, unsigned long, void *);
+ notifier_fn_t notifier_call;
struct notifier_block __rcu *next;
int priority;
};
diff --git a/include/linux/of_net.h b/include/linux/of_net.h
index f47464188710..61bf53b02779 100644
--- a/include/linux/of_net.h
+++ b/include/linux/of_net.h
@@ -11,6 +11,16 @@
#include <linux/of.h>
extern const int of_get_phy_mode(struct device_node *np);
extern const void *of_get_mac_address(struct device_node *np);
+#else
+static inline const int of_get_phy_mode(struct device_node *np)
+{
+ return -ENODEV;
+}
+
+static inline const void *of_get_mac_address(struct device_node *np)
+{
+ return NULL;
+}
#endif
#endif /* __LINUX_OF_NET_H */
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index d42e174bd0c8..e6b240b6196c 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -19,435 +19,6 @@
#ifndef _LINUX_OPENVSWITCH_H
#define _LINUX_OPENVSWITCH_H 1
-#include <linux/types.h>
-
-/**
- * struct ovs_header - header for OVS Generic Netlink messages.
- * @dp_ifindex: ifindex of local port for datapath (0 to make a request not
- * specific to a datapath).
- *
- * Attributes following the header are specific to a particular OVS Generic
- * Netlink family, but all of the OVS families use this header.
- */
-
-struct ovs_header {
- int dp_ifindex;
-};
-
-/* Datapaths. */
-
-#define OVS_DATAPATH_FAMILY "ovs_datapath"
-#define OVS_DATAPATH_MCGROUP "ovs_datapath"
-#define OVS_DATAPATH_VERSION 0x1
-
-enum ovs_datapath_cmd {
- OVS_DP_CMD_UNSPEC,
- OVS_DP_CMD_NEW,
- OVS_DP_CMD_DEL,
- OVS_DP_CMD_GET,
- OVS_DP_CMD_SET
-};
-
-/**
- * enum ovs_datapath_attr - attributes for %OVS_DP_* commands.
- * @OVS_DP_ATTR_NAME: Name of the network device that serves as the "local
- * port". This is the name of the network device whose dp_ifindex is given in
- * the &struct ovs_header. Always present in notifications. Required in
- * %OVS_DP_NEW requests. May be used as an alternative to specifying
- * dp_ifindex in other requests (with a dp_ifindex of 0).
- * @OVS_DP_ATTR_UPCALL_PID: The Netlink socket in userspace that is initially
- * set on the datapath port (for OVS_ACTION_ATTR_MISS). Only valid on
- * %OVS_DP_CMD_NEW requests. A value of zero indicates that upcalls should
- * not be sent.
- * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the
- * datapath. Always present in notifications.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_DP_* commands.
- */
-enum ovs_datapath_attr {
- OVS_DP_ATTR_UNSPEC,
- OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */
- OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */
- OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */
- __OVS_DP_ATTR_MAX
-};
-
-#define OVS_DP_ATTR_MAX (__OVS_DP_ATTR_MAX - 1)
-
-struct ovs_dp_stats {
- __u64 n_hit; /* Number of flow table matches. */
- __u64 n_missed; /* Number of flow table misses. */
- __u64 n_lost; /* Number of misses not sent to userspace. */
- __u64 n_flows; /* Number of flows present */
-};
-
-struct ovs_vport_stats {
- __u64 rx_packets; /* total packets received */
- __u64 tx_packets; /* total packets transmitted */
- __u64 rx_bytes; /* total bytes received */
- __u64 tx_bytes; /* total bytes transmitted */
- __u64 rx_errors; /* bad packets received */
- __u64 tx_errors; /* packet transmit problems */
- __u64 rx_dropped; /* no space in linux buffers */
- __u64 tx_dropped; /* no space available in linux */
-};
-
-/* Fixed logical ports. */
-#define OVSP_LOCAL ((__u16)0)
-
-/* Packet transfer. */
-
-#define OVS_PACKET_FAMILY "ovs_packet"
-#define OVS_PACKET_VERSION 0x1
-
-enum ovs_packet_cmd {
- OVS_PACKET_CMD_UNSPEC,
-
- /* Kernel-to-user notifications. */
- OVS_PACKET_CMD_MISS, /* Flow table miss. */
- OVS_PACKET_CMD_ACTION, /* OVS_ACTION_ATTR_USERSPACE action. */
-
- /* Userspace commands. */
- OVS_PACKET_CMD_EXECUTE /* Apply actions to a packet. */
-};
-
-/**
- * enum ovs_packet_attr - attributes for %OVS_PACKET_* commands.
- * @OVS_PACKET_ATTR_PACKET: Present for all notifications. Contains the entire
- * packet as received, from the start of the Ethernet header onward. For
- * %OVS_PACKET_CMD_ACTION, %OVS_PACKET_ATTR_PACKET reflects changes made by
- * actions preceding %OVS_ACTION_ATTR_USERSPACE, but %OVS_PACKET_ATTR_KEY is
- * the flow key extracted from the packet as originally received.
- * @OVS_PACKET_ATTR_KEY: Present for all notifications. Contains the flow key
- * extracted from the packet as nested %OVS_KEY_ATTR_* attributes. This allows
- * userspace to adapt its flow setup strategy by comparing its notion of the
- * flow key against the kernel's.
- * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet. Used
- * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
- * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
- * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
- * %OVS_USERSPACE_ATTR_USERDATA attribute.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_PACKET_* commands.
- */
-enum ovs_packet_attr {
- OVS_PACKET_ATTR_UNSPEC,
- OVS_PACKET_ATTR_PACKET, /* Packet data. */
- OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
- OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- OVS_PACKET_ATTR_USERDATA, /* u64 OVS_ACTION_ATTR_USERSPACE arg. */
- __OVS_PACKET_ATTR_MAX
-};
-
-#define OVS_PACKET_ATTR_MAX (__OVS_PACKET_ATTR_MAX - 1)
-
-/* Virtual ports. */
-
-#define OVS_VPORT_FAMILY "ovs_vport"
-#define OVS_VPORT_MCGROUP "ovs_vport"
-#define OVS_VPORT_VERSION 0x1
-
-enum ovs_vport_cmd {
- OVS_VPORT_CMD_UNSPEC,
- OVS_VPORT_CMD_NEW,
- OVS_VPORT_CMD_DEL,
- OVS_VPORT_CMD_GET,
- OVS_VPORT_CMD_SET
-};
-
-enum ovs_vport_type {
- OVS_VPORT_TYPE_UNSPEC,
- OVS_VPORT_TYPE_NETDEV, /* network device */
- OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
- __OVS_VPORT_TYPE_MAX
-};
-
-#define OVS_VPORT_TYPE_MAX (__OVS_VPORT_TYPE_MAX - 1)
-
-/**
- * enum ovs_vport_attr - attributes for %OVS_VPORT_* commands.
- * @OVS_VPORT_ATTR_PORT_NO: 32-bit port number within datapath.
- * @OVS_VPORT_ATTR_TYPE: 32-bit %OVS_VPORT_TYPE_* constant describing the type
- * of vport.
- * @OVS_VPORT_ATTR_NAME: Name of vport. For a vport based on a network device
- * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes
- * plus a null terminator.
- * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information.
- * @OVS_VPORT_ATTR_UPCALL_PID: The Netlink socket in userspace that
- * OVS_PACKET_CMD_MISS upcalls will be directed to for packets received on
- * this port. A value of zero indicates that upcalls should not be sent.
- * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for
- * packets sent or received through the vport.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_VPORT_* commands.
- *
- * For %OVS_VPORT_CMD_NEW requests, the %OVS_VPORT_ATTR_TYPE and
- * %OVS_VPORT_ATTR_NAME attributes are required. %OVS_VPORT_ATTR_PORT_NO is
- * optional; if not specified a free port number is automatically selected.
- * Whether %OVS_VPORT_ATTR_OPTIONS is required or optional depends on the type
- * of vport.
- * and other attributes are ignored.
- *
- * For other requests, if %OVS_VPORT_ATTR_NAME is specified then it is used to
- * look up the vport to operate on; otherwise dp_idx from the &struct
- * ovs_header plus %OVS_VPORT_ATTR_PORT_NO determine the vport.
- */
-enum ovs_vport_attr {
- OVS_VPORT_ATTR_UNSPEC,
- OVS_VPORT_ATTR_PORT_NO, /* u32 port number within datapath */
- OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */
- OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */
- OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */
- OVS_VPORT_ATTR_UPCALL_PID, /* u32 Netlink PID to receive upcalls */
- OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */
- __OVS_VPORT_ATTR_MAX
-};
-
-#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
-
-/* Flows. */
-
-#define OVS_FLOW_FAMILY "ovs_flow"
-#define OVS_FLOW_MCGROUP "ovs_flow"
-#define OVS_FLOW_VERSION 0x1
-
-enum ovs_flow_cmd {
- OVS_FLOW_CMD_UNSPEC,
- OVS_FLOW_CMD_NEW,
- OVS_FLOW_CMD_DEL,
- OVS_FLOW_CMD_GET,
- OVS_FLOW_CMD_SET
-};
-
-struct ovs_flow_stats {
- __u64 n_packets; /* Number of matched packets. */
- __u64 n_bytes; /* Number of matched bytes. */
-};
-
-enum ovs_key_attr {
- OVS_KEY_ATTR_UNSPEC,
- OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
- OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
- OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
- OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
- OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
- OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
- OVS_KEY_ATTR_IPV4, /* struct ovs_key_ipv4 */
- OVS_KEY_ATTR_IPV6, /* struct ovs_key_ipv6 */
- OVS_KEY_ATTR_TCP, /* struct ovs_key_tcp */
- OVS_KEY_ATTR_UDP, /* struct ovs_key_udp */
- OVS_KEY_ATTR_ICMP, /* struct ovs_key_icmp */
- OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */
- OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */
- OVS_KEY_ATTR_ND, /* struct ovs_key_nd */
- OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */
- __OVS_KEY_ATTR_MAX
-};
-
-#define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1)
-
-/**
- * enum ovs_frag_type - IPv4 and IPv6 fragment type
- * @OVS_FRAG_TYPE_NONE: Packet is not a fragment.
- * @OVS_FRAG_TYPE_FIRST: Packet is a fragment with offset 0.
- * @OVS_FRAG_TYPE_LATER: Packet is a fragment with nonzero offset.
- *
- * Used as the @ipv4_frag in &struct ovs_key_ipv4 and as @ipv6_frag &struct
- * ovs_key_ipv6.
- */
-enum ovs_frag_type {
- OVS_FRAG_TYPE_NONE,
- OVS_FRAG_TYPE_FIRST,
- OVS_FRAG_TYPE_LATER,
- __OVS_FRAG_TYPE_MAX
-};
-
-#define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
-
-struct ovs_key_ethernet {
- __u8 eth_src[6];
- __u8 eth_dst[6];
-};
-
-struct ovs_key_ipv4 {
- __be32 ipv4_src;
- __be32 ipv4_dst;
- __u8 ipv4_proto;
- __u8 ipv4_tos;
- __u8 ipv4_ttl;
- __u8 ipv4_frag; /* One of OVS_FRAG_TYPE_*. */
-};
-
-struct ovs_key_ipv6 {
- __be32 ipv6_src[4];
- __be32 ipv6_dst[4];
- __be32 ipv6_label; /* 20-bits in least-significant bits. */
- __u8 ipv6_proto;
- __u8 ipv6_tclass;
- __u8 ipv6_hlimit;
- __u8 ipv6_frag; /* One of OVS_FRAG_TYPE_*. */
-};
-
-struct ovs_key_tcp {
- __be16 tcp_src;
- __be16 tcp_dst;
-};
-
-struct ovs_key_udp {
- __be16 udp_src;
- __be16 udp_dst;
-};
-
-struct ovs_key_icmp {
- __u8 icmp_type;
- __u8 icmp_code;
-};
-
-struct ovs_key_icmpv6 {
- __u8 icmpv6_type;
- __u8 icmpv6_code;
-};
-
-struct ovs_key_arp {
- __be32 arp_sip;
- __be32 arp_tip;
- __be16 arp_op;
- __u8 arp_sha[6];
- __u8 arp_tha[6];
-};
-
-struct ovs_key_nd {
- __u32 nd_target[4];
- __u8 nd_sll[6];
- __u8 nd_tll[6];
-};
-
-/**
- * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
- * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
- * key. Always present in notifications. Required for all requests (except
- * dumps).
- * @OVS_FLOW_ATTR_ACTIONS: Nested %OVS_ACTION_ATTR_* attributes specifying
- * the actions to take for packets that match the key. Always present in
- * notifications. Required for %OVS_FLOW_CMD_NEW requests, optional for
- * %OVS_FLOW_CMD_SET requests.
- * @OVS_FLOW_ATTR_STATS: &struct ovs_flow_stats giving statistics for this
- * flow. Present in notifications if the stats would be nonzero. Ignored in
- * requests.
- * @OVS_FLOW_ATTR_TCP_FLAGS: An 8-bit value giving the OR'd value of all of the
- * TCP flags seen on packets in this flow. Only present in notifications for
- * TCP flows, and only if it would be nonzero. Ignored in requests.
- * @OVS_FLOW_ATTR_USED: A 64-bit integer giving the time, in milliseconds on
- * the system monotonic clock, at which a packet was last processed for this
- * flow. Only present in notifications if a packet has been processed for this
- * flow. Ignored in requests.
- * @OVS_FLOW_ATTR_CLEAR: If present in a %OVS_FLOW_CMD_SET request, clears the
- * last-used time, accumulated TCP flags, and statistics for this flow.
- * Otherwise ignored in requests. Never present in notifications.
- *
- * These attributes follow the &struct ovs_header within the Generic Netlink
- * payload for %OVS_FLOW_* commands.
- */
-enum ovs_flow_attr {
- OVS_FLOW_ATTR_UNSPEC,
- OVS_FLOW_ATTR_KEY, /* Sequence of OVS_KEY_ATTR_* attributes. */
- OVS_FLOW_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- OVS_FLOW_ATTR_STATS, /* struct ovs_flow_stats. */
- OVS_FLOW_ATTR_TCP_FLAGS, /* 8-bit OR'd TCP flags. */
- OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
- OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
- __OVS_FLOW_ATTR_MAX
-};
-
-#define OVS_FLOW_ATTR_MAX (__OVS_FLOW_ATTR_MAX - 1)
-
-/**
- * enum ovs_sample_attr - Attributes for %OVS_ACTION_ATTR_SAMPLE action.
- * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
- * @OVS_ACTION_ATTR_SAMPLE. A value of 0 samples no packets, a value of
- * %UINT32_MAX samples all packets and intermediate values sample intermediate
- * fractions of packets.
- * @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event.
- * Actions are passed as nested attributes.
- *
- * Executes the specified actions with the given probability on a per-packet
- * basis.
- */
-enum ovs_sample_attr {
- OVS_SAMPLE_ATTR_UNSPEC,
- OVS_SAMPLE_ATTR_PROBABILITY, /* u32 number */
- OVS_SAMPLE_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
- __OVS_SAMPLE_ATTR_MAX,
-};
-
-#define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
-
-/**
- * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
- * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
- * message should be sent. Required.
- * @OVS_USERSPACE_ATTR_USERDATA: If present, its u64 argument is copied to the
- * %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA,
- */
-enum ovs_userspace_attr {
- OVS_USERSPACE_ATTR_UNSPEC,
- OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
- OVS_USERSPACE_ATTR_USERDATA, /* u64 optional user-specified cookie. */
- __OVS_USERSPACE_ATTR_MAX
-};
-
-#define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
-
-/**
- * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
- * @vlan_tpid: Tag protocol identifier (TPID) to push.
- * @vlan_tci: Tag control identifier (TCI) to push. The CFI bit must be set
- * (but it will not be set in the 802.1Q header that is pushed).
- *
- * The @vlan_tpid value is typically %ETH_P_8021Q. The only acceptable TPID
- * values are those that the kernel module also parses as 802.1Q headers, to
- * prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by %OVS_ACTION_ATTR_POP_VLAN
- * from having surprising results.
- */
-struct ovs_action_push_vlan {
- __be16 vlan_tpid; /* 802.1Q TPID. */
- __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
-};
-
-/**
- * enum ovs_action_attr - Action types.
- *
- * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
- * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
- * %OVS_USERSPACE_ATTR_* attributes.
- * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header. The
- * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
- * value.
- * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
- * packet.
- * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
- * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
- * the nested %OVS_SAMPLE_ATTR_* attributes.
- *
- * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
- * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
- * type may not be changed.
- */
-
-enum ovs_action_attr {
- OVS_ACTION_ATTR_UNSPEC,
- OVS_ACTION_ATTR_OUTPUT, /* u32 port number. */
- OVS_ACTION_ATTR_USERSPACE, /* Nested OVS_USERSPACE_ATTR_*. */
- OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
- OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
- OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
- OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
- __OVS_ACTION_ATTR_MAX
-};
-
-#define OVS_ACTION_ATTR_MAX (__OVS_ACTION_ATTR_MAX - 1)
+#include <uapi/linux/openvswitch.h>
#endif /* _LINUX_OPENVSWITCH_H */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 0e38e13eb249..e3dea75a078b 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -149,7 +149,7 @@ static inline int page_cache_get_speculative(struct page *page)
{
VM_BUG_ON(in_interrupt());
-#if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU)
+#ifdef CONFIG_TINY_RCU
# ifdef CONFIG_PREEMPT_COUNT
VM_BUG_ON(!in_atomic());
# endif
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index 9a22b5efb384..81b31613eb25 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -41,8 +41,37 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
return DEVICE_ACPI_HANDLE(dev);
}
+
+void acpi_pci_add_bus(struct pci_bus *bus);
+void acpi_pci_remove_bus(struct pci_bus *bus);
+
+#ifdef CONFIG_ACPI_PCI_SLOT
+void acpi_pci_slot_init(void);
+void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle);
+void acpi_pci_slot_remove(struct pci_bus *bus);
+#else
+static inline void acpi_pci_slot_init(void) { }
+static inline void acpi_pci_slot_enumerate(struct pci_bus *bus,
+ acpi_handle handle) { }
+static inline void acpi_pci_slot_remove(struct pci_bus *bus) { }
#endif
+#ifdef CONFIG_HOTPLUG_PCI_ACPI
+void acpiphp_init(void);
+void acpiphp_enumerate_slots(struct pci_bus *bus, acpi_handle handle);
+void acpiphp_remove_slots(struct pci_bus *bus);
+#else
+static inline void acpiphp_init(void) { }
+static inline void acpiphp_enumerate_slots(struct pci_bus *bus,
+ acpi_handle handle) { }
+static inline void acpiphp_remove_slots(struct pci_bus *bus) { }
+#endif
+
+#else /* CONFIG_ACPI */
+static inline void acpi_pci_add_bus(struct pci_bus *bus) { }
+static inline void acpi_pci_remove_bus(struct pci_bus *bus) { }
+#endif /* CONFIG_ACPI */
+
#ifdef CONFIG_ACPI_APEI
extern bool aer_acpi_firmware_first(void);
#else
diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h
index c8320144fe79..8af4610c2e41 100644
--- a/include/linux/pci-aspm.h
+++ b/include/linux/pci-aspm.h
@@ -23,14 +23,14 @@
#define PCIE_LINK_STATE_CLKPM 4
#ifdef CONFIG_PCIEASPM
-extern void pcie_aspm_init_link_state(struct pci_dev *pdev);
-extern void pcie_aspm_exit_link_state(struct pci_dev *pdev);
-extern void pcie_aspm_pm_state_change(struct pci_dev *pdev);
-extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
-extern void pci_disable_link_state(struct pci_dev *pdev, int state);
-extern void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
-extern void pcie_clear_aspm(struct pci_bus *bus);
-extern void pcie_no_aspm(void);
+void pcie_aspm_init_link_state(struct pci_dev *pdev);
+void pcie_aspm_exit_link_state(struct pci_dev *pdev);
+void pcie_aspm_pm_state_change(struct pci_dev *pdev);
+void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pci_disable_link_state(struct pci_dev *pdev, int state);
+void pci_disable_link_state_locked(struct pci_dev *pdev, int state);
+void pcie_clear_aspm(struct pci_bus *bus);
+void pcie_no_aspm(void);
#else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev)
{
@@ -56,8 +56,8 @@ static inline void pcie_no_aspm(void)
#endif
#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */
-extern void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
-extern void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
+void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev);
+void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev);
#else
static inline void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
{
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 7ef68724f0f0..68bcefd7fca0 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -14,9 +14,9 @@ struct pci_ats {
#ifdef CONFIG_PCI_ATS
-extern int pci_enable_ats(struct pci_dev *dev, int ps);
-extern void pci_disable_ats(struct pci_dev *dev);
-extern int pci_ats_queue_depth(struct pci_dev *dev);
+int pci_enable_ats(struct pci_dev *dev, int ps);
+void pci_disable_ats(struct pci_dev *dev);
+int pci_ats_queue_depth(struct pci_dev *dev);
/**
* pci_ats_enabled - query the ATS status
@@ -54,12 +54,12 @@ static inline int pci_ats_enabled(struct pci_dev *dev)
#ifdef CONFIG_PCI_PRI
-extern int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
-extern void pci_disable_pri(struct pci_dev *pdev);
-extern bool pci_pri_enabled(struct pci_dev *pdev);
-extern int pci_reset_pri(struct pci_dev *pdev);
-extern bool pci_pri_stopped(struct pci_dev *pdev);
-extern int pci_pri_status(struct pci_dev *pdev);
+int pci_enable_pri(struct pci_dev *pdev, u32 reqs);
+void pci_disable_pri(struct pci_dev *pdev);
+bool pci_pri_enabled(struct pci_dev *pdev);
+int pci_reset_pri(struct pci_dev *pdev);
+bool pci_pri_stopped(struct pci_dev *pdev);
+int pci_pri_status(struct pci_dev *pdev);
#else /* CONFIG_PCI_PRI */
@@ -95,10 +95,10 @@ static inline int pci_pri_status(struct pci_dev *pdev)
#ifdef CONFIG_PCI_PASID
-extern int pci_enable_pasid(struct pci_dev *pdev, int features);
-extern void pci_disable_pasid(struct pci_dev *pdev);
-extern int pci_pasid_features(struct pci_dev *pdev);
-extern int pci_max_pasids(struct pci_dev *pdev);
+int pci_enable_pasid(struct pci_dev *pdev, int features);
+void pci_disable_pasid(struct pci_dev *pdev);
+int pci_pasid_features(struct pci_dev *pdev);
+int pci_max_pasids(struct pci_dev *pdev);
#else /* CONFIG_PCI_PASID */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2461033a7987..3a24e4ff3248 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -35,6 +35,21 @@
/* Include the ID list */
#include <linux/pci_ids.h>
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 7:3 = slot
+ * 2:0 = function
+ * PCI_DEVFN(), PCI_SLOT(), and PCI_FUNC() are defined uapi/linux/pci.h
+ * In the interest of not exposing interfaces to user-space unnecessarily,
+ * the following kernel only defines are being added here.
+ */
+#define PCI_DEVID(bus, devfn) ((((u16)bus) << 8) | devfn)
+/* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */
+#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff)
+
/* pci_slot represents a physical slot */
struct pci_slot {
struct pci_bus *bus; /* The bus this slot is on */
@@ -232,6 +247,8 @@ struct pci_dev {
u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 pcie_cap; /* PCI-E capability offset */
+ u8 msi_cap; /* MSI capability offset */
+ u8 msix_cap; /* MSI-X capability offset */
u8 pcie_mpss:3; /* PCI-E Max Payload Size Supported */
u8 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */
@@ -249,8 +266,7 @@ struct pci_dev {
pci_power_t current_state; /* Current operating state. In ACPI-speak,
this is D0-D3, D0 being fully functional,
and D3 being off. */
- int pm_cap; /* PM capability offset in the
- configuration space */
+ u8 pm_cap; /* PM capability offset */
unsigned int pme_support:5; /* Bitmask of states from which PME#
can be generated */
unsigned int pme_interrupt:1;
@@ -348,7 +364,7 @@ static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
return dev;
}
-extern struct pci_dev *alloc_pci_dev(void);
+struct pci_dev *alloc_pci_dev(void);
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
@@ -504,10 +520,10 @@ struct pci_ops {
* ACPI needs to be able to access PCI config space before we've done a
* PCI bus scan and created pci_bus structures.
*/
-extern int raw_pci_read(unsigned int domain, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 *val);
-extern int raw_pci_write(unsigned int domain, unsigned int bus,
- unsigned int devfn, int reg, int len, u32 val);
+int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 *val);
+int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
+ int reg, int len, u32 val);
struct pci_bus_region {
resource_size_t start;
@@ -658,7 +674,7 @@ struct pci_driver {
/* these external functions are only available when PCI support is enabled */
#ifdef CONFIG_PCI
-extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
+void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss);
enum pcie_bus_config_types {
PCIE_BUS_TUNE_OFF,
@@ -675,9 +691,11 @@ extern struct bus_type pci_bus_type;
* code, or pci core code. */
extern struct list_head pci_root_buses; /* list of all known PCI buses */
/* Some device drivers need know if pci is initiated */
-extern int no_pci_devices(void);
+int no_pci_devices(void);
void pcibios_resource_survey_bus(struct pci_bus *bus);
+void pcibios_add_bus(struct pci_bus *bus);
+void pcibios_remove_bus(struct pci_bus *bus);
void pcibios_fixup_bus(struct pci_bus *);
int __must_check pcibios_enable_device(struct pci_dev *, int mask);
/* Architecture specific versions may override this (weak) */
@@ -699,7 +717,7 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
struct pci_bus_region *region);
void pcibios_scan_specific_bus(int busn);
-extern struct pci_bus *pci_find_bus(int domain, int busnr);
+struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata);
@@ -732,14 +750,14 @@ struct resource *pci_find_parent_resource(const 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);
-extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
-extern void pci_dev_put(struct pci_dev *dev);
-extern void pci_remove_bus(struct pci_bus *b);
-extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+struct pci_dev *pci_dev_get(struct pci_dev *dev);
+void pci_dev_put(struct pci_dev *dev);
+void pci_remove_bus(struct pci_bus *b);
+void pci_stop_and_remove_bus_device(struct pci_dev *dev);
void pci_stop_root_bus(struct pci_bus *bus);
void pci_remove_root_bus(struct pci_bus *bus);
void pci_setup_cardbus(struct pci_bus *bus);
-extern void pci_sort_breadthfirst(void);
+void pci_sort_breadthfirst(void);
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
@@ -916,6 +934,7 @@ void pci_disable_rom(struct pci_dev *pdev);
void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
+void __iomem __must_check *pci_platform_rom(struct pci_dev *pdev, size_t *size);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
@@ -1141,18 +1160,17 @@ static inline int pci_msi_enabled(void)
return 0;
}
#else
-extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
-extern int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec);
-extern void pci_msi_shutdown(struct pci_dev *dev);
-extern void pci_disable_msi(struct pci_dev *dev);
-extern int pci_msix_table_size(struct pci_dev *dev);
-extern int pci_enable_msix(struct pci_dev *dev,
- struct msix_entry *entries, int nvec);
-extern void pci_msix_shutdown(struct pci_dev *dev);
-extern void pci_disable_msix(struct pci_dev *dev);
-extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
-extern void pci_restore_msi_state(struct pci_dev *dev);
-extern int pci_msi_enabled(void);
+int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
+int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec);
+void pci_msi_shutdown(struct pci_dev *dev);
+void pci_disable_msi(struct pci_dev *dev);
+int pci_msix_table_size(struct pci_dev *dev);
+int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec);
+void pci_msix_shutdown(struct pci_dev *dev);
+void pci_disable_msix(struct pci_dev *dev);
+void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+void pci_restore_msi_state(struct pci_dev *dev);
+int pci_msi_enabled(void);
#endif
#ifdef CONFIG_PCIEPORTBUS
@@ -1167,8 +1185,8 @@ extern bool pcie_ports_auto;
static inline int pcie_aspm_enabled(void) { return 0; }
static inline bool pcie_aspm_support_enabled(void) { return false; }
#else
-extern int pcie_aspm_enabled(void);
-extern bool pcie_aspm_support_enabled(void);
+int pcie_aspm_enabled(void);
+bool pcie_aspm_support_enabled(void);
#endif
#ifdef CONFIG_PCIEAER
@@ -1186,8 +1204,8 @@ static inline void pcie_set_ecrc_checking(struct pci_dev *dev)
}
static inline void pcie_ecrc_get_policy(char *str) {};
#else
-extern void pcie_set_ecrc_checking(struct pci_dev *dev);
-extern void pcie_ecrc_get_policy(char *str);
+void pcie_set_ecrc_checking(struct pci_dev *dev);
+void pcie_ecrc_get_policy(char *str);
#endif
#define pci_enable_msi(pdev) pci_enable_msi_block(pdev, 1)
@@ -1198,9 +1216,9 @@ int ht_create_irq(struct pci_dev *dev, int idx);
void ht_destroy_irq(unsigned int irq);
#endif /* CONFIG_HT_IRQ */
-extern void pci_cfg_access_lock(struct pci_dev *dev);
-extern bool pci_cfg_access_trylock(struct pci_dev *dev);
-extern void pci_cfg_access_unlock(struct pci_dev *dev);
+void pci_cfg_access_lock(struct pci_dev *dev);
+bool pci_cfg_access_trylock(struct pci_dev *dev);
+void pci_cfg_access_unlock(struct pci_dev *dev);
/*
* PCI domain support. Sometimes called PCI segment (eg by ACPI),
@@ -1225,7 +1243,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
/* some architectures require additional setup to direct VGA traffic */
typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
unsigned int command_bits, u32 flags);
-extern void pci_register_set_vga_state(arch_set_vga_state_t func);
+void pci_register_set_vga_state(arch_set_vga_state_t func);
#else /* CONFIG_PCI is not enabled */
@@ -1627,8 +1645,8 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev,
int pcibios_add_device(struct pci_dev *dev);
#ifdef CONFIG_PCI_MMCONFIG
-extern void __init pci_mmcfg_early_init(void);
-extern void __init pci_mmcfg_late_init(void);
+void __init pci_mmcfg_early_init(void);
+void __init pci_mmcfg_late_init(void);
#else
static inline void pci_mmcfg_early_init(void) { }
static inline void pci_mmcfg_late_init(void) { }
@@ -1639,12 +1657,13 @@ int pci_ext_cfg_avail(void);
void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
#ifdef CONFIG_PCI_IOV
-extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
-extern void pci_disable_sriov(struct pci_dev *dev);
-extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
-extern int pci_num_vf(struct pci_dev *dev);
-extern int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
-extern int pci_sriov_get_totalvfs(struct pci_dev *dev);
+int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+void pci_disable_sriov(struct pci_dev *dev);
+irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+int pci_num_vf(struct pci_dev *dev);
+int pci_vfs_assigned(struct pci_dev *dev);
+int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
+int pci_sriov_get_totalvfs(struct pci_dev *dev);
#else
static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
{
@@ -1661,6 +1680,10 @@ static inline int pci_num_vf(struct pci_dev *dev)
{
return 0;
}
+static inline int pci_vfs_assigned(struct pci_dev *dev)
+{
+ return 0;
+}
static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
{
return 0;
@@ -1672,8 +1695,8 @@ static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
#endif
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
-extern void pci_hp_create_module_link(struct pci_slot *pci_slot);
-extern void pci_hp_remove_module_link(struct pci_slot *pci_slot);
+void pci_hp_create_module_link(struct pci_slot *pci_slot);
+void pci_hp_remove_module_link(struct pci_slot *pci_slot);
#endif
/**
@@ -1817,13 +1840,13 @@ int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off,
/* PCI <-> OF binding helpers */
#ifdef CONFIG_OF
struct device_node;
-extern void pci_set_of_node(struct pci_dev *dev);
-extern void pci_release_of_node(struct pci_dev *dev);
-extern void pci_set_bus_of_node(struct pci_bus *bus);
-extern void pci_release_bus_of_node(struct pci_bus *bus);
+void pci_set_of_node(struct pci_dev *dev);
+void pci_release_of_node(struct pci_dev *dev);
+void pci_set_bus_of_node(struct pci_bus *bus);
+void pci_release_bus_of_node(struct pci_bus *bus);
/* Arch may override this (weak) */
-extern struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus);
+struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus);
static inline struct device_node *
pci_device_to_OF_node(const struct pci_dev *pdev)
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index 45fc162cbdc0..8db71dcd6337 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -125,12 +125,12 @@ static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
return pci_slot_name(slot->pci_slot);
}
-extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus,
- int nr, const char *name,
- struct module *owner, const char *mod_name);
-extern int pci_hp_deregister(struct hotplug_slot *slot);
-extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
- struct hotplug_slot_info *info);
+int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus, int nr,
+ const char *name, struct module *owner,
+ const char *mod_name);
+int pci_hp_deregister(struct hotplug_slot *slot);
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+ struct hotplug_slot_info *info);
/* use a define to avoid include chaining to get THIS_MODULE & friends */
#define pci_hp_register(slot, pbus, devnr, name) \
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f11c1c2609d5..2b85c521f737 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -524,6 +524,8 @@
#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603
#define PCI_DEVICE_ID_AMD_15H_NB_F4 0x1604
#define PCI_DEVICE_ID_AMD_15H_NB_F5 0x1605
+#define PCI_DEVICE_ID_AMD_16H_NB_F3 0x1533
+#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
@@ -1604,6 +1606,7 @@
#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334
#define PCI_VENDOR_ID_MARVELL 0x11ab
+#define PCI_VENDOR_ID_MARVELL_EXT 0x1b4b
#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146
#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
index e6f91b1406d8..9572669eea97 100644
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -62,7 +62,7 @@ struct pcie_port_service_driver {
#define to_service_driver(d) \
container_of(d, struct pcie_port_service_driver, driver)
-extern int pcie_port_service_register(struct pcie_port_service_driver *new);
-extern void pcie_port_service_unregister(struct pcie_port_service_driver *new);
+int pcie_port_service_register(struct pcie_port_service_driver *new);
+void pcie_port_service_unregister(struct pcie_port_service_driver *new);
#endif /* _PCIEPORT_IF_H_ */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 1d795df6f4cf..e0373d26c244 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -21,7 +21,6 @@
*/
#ifdef CONFIG_PERF_EVENTS
-# include <linux/cgroup.h>
# include <asm/perf_event.h>
# include <asm/local64.h>
#endif
@@ -128,6 +127,7 @@ struct hw_perf_event {
int event_base_rdpmc;
int idx;
int last_cpu;
+ int flags;
struct hw_perf_event_extra extra_reg;
struct hw_perf_event_extra branch_reg;
@@ -299,22 +299,7 @@ struct swevent_hlist {
#define PERF_ATTACH_GROUP 0x02
#define PERF_ATTACH_TASK 0x04
-#ifdef CONFIG_CGROUP_PERF
-/*
- * perf_cgroup_info keeps track of time_enabled for a cgroup.
- * This is a per-cpu dynamically allocated data structure.
- */
-struct perf_cgroup_info {
- u64 time;
- u64 timestamp;
-};
-
-struct perf_cgroup {
- struct cgroup_subsys_state css;
- struct perf_cgroup_info *info; /* timing info, one per cpu */
-};
-#endif
-
+struct perf_cgroup;
struct ring_buffer;
/**
@@ -583,11 +568,13 @@ struct perf_sample_data {
u32 reserved;
} cpu_entry;
u64 period;
+ union perf_mem_data_src data_src;
struct perf_callchain_entry *callchain;
struct perf_raw_record *raw;
struct perf_branch_stack *br_stack;
struct perf_regs_user regs_user;
u64 stack_user_size;
+ u64 weight;
};
static inline void perf_sample_data_init(struct perf_sample_data *data,
@@ -601,6 +588,8 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE;
data->regs_user.regs = NULL;
data->stack_user_size = 0;
+ data->weight = 0;
+ data->data_src.val = 0;
}
extern void perf_output_sample(struct perf_output_handle *handle,
@@ -831,6 +820,7 @@ do { \
struct perf_pmu_events_attr {
struct device_attribute attr;
u64 id;
+ const char *event_str;
};
#define PMU_EVENT_ATTR(_name, _var, _id, _show) \
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 33999adbf8c8..9e11039dd7a3 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -455,6 +455,14 @@ struct phy_driver {
*/
void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
+ /* Some devices (e.g. qnap TS-119P II) require PHY register changes to
+ * enable Wake on LAN, so set_wol is provided to be called in the
+ * ethernet driver's set_wol function. */
+ int (*set_wol)(struct phy_device *dev, struct ethtool_wolinfo *wol);
+
+ /* See set_wol, but for checking whether Wake on LAN is enabled. */
+ void (*get_wol)(struct phy_device *dev, struct ethtool_wolinfo *wol);
+
struct device_driver driver;
};
#define to_phy_driver(d) container_of(d, struct phy_driver, driver)
@@ -560,6 +568,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable);
int phy_get_eee_err(struct phy_device *phydev);
int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data);
int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data);
+int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
+void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol);
int __init mdio_bus_init(void);
void mdio_bus_exit(void);
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 5524f8cfa950..731e4ecee3bd 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -13,7 +13,9 @@ struct pidmap {
void *page;
};
-#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
+#define BITS_PER_PAGE (PAGE_SIZE * 8)
+#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
+#define PIDMAP_ENTRIES ((PID_MAX_LIMIT+BITS_PER_PAGE-1)/BITS_PER_PAGE)
struct bsd_acct_struct;
diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h
index e7a720104a47..1ad4f31ef6b8 100644
--- a/include/linux/pinctrl/pinconf.h
+++ b/include/linux/pinctrl/pinconf.h
@@ -14,6 +14,8 @@
#ifdef CONFIG_PINCONF
+#include <linux/pinctrl/machine.h>
+
struct pinctrl_dev;
struct seq_file;
@@ -28,6 +30,7 @@ struct seq_file;
* @pin_config_set: configure an individual pin
* @pin_config_group_get: get configurations for an entire pin group
* @pin_config_group_set: configure all pins in a group
+ * @pin_config_group_dbg_set: optional debugfs to modify a pin configuration
* @pin_config_dbg_show: optional debugfs display hook that will provide
* per-device info for a certain pin in debugfs
* @pin_config_group_dbg_show: optional debugfs display hook that will provide
@@ -51,6 +54,9 @@ struct pinconf_ops {
int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
unsigned selector,
unsigned long config);
+ int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
+ const char *arg,
+ unsigned long *config);
void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned offset);
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 778804df293f..2c2a9e8d8578 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -118,9 +118,9 @@ struct pinctrl_desc {
const char *name;
struct pinctrl_pin_desc const *pins;
unsigned int npins;
- struct pinctrl_ops *pctlops;
- struct pinmux_ops *pmxops;
- struct pinconf_ops *confops;
+ const struct pinctrl_ops *pctlops;
+ const struct pinmux_ops *pmxops;
+ const struct pinconf_ops *confops;
struct module *owner;
};
diff --git a/include/linux/platform_data/brcmfmac-sdio.h b/include/linux/platform_data/brcmfmac-sdio.h
new file mode 100644
index 000000000000..1ade657d5fc1
--- /dev/null
+++ b/include/linux/platform_data/brcmfmac-sdio.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_BRCMFMAC_PLATFORM_H
+#define _LINUX_BRCMFMAC_PLATFORM_H
+
+/*
+ * Platform specific driver functions and data. Through the platform specific
+ * device data functions can be provided to help the brcmfmac driver to
+ * operate with the device in combination with the used platform.
+ *
+ * Use the platform data in the following (similar) way:
+ *
+ *
+#include <brcmfmac_platform.h>
+
+
+static void brcmfmac_power_on(void)
+{
+}
+
+static void brcmfmac_power_off(void)
+{
+}
+
+static void brcmfmac_reset(void)
+{
+}
+
+static struct brcmfmac_sdio_platform_data brcmfmac_sdio_pdata = {
+ .power_on = brcmfmac_power_on,
+ .power_off = brcmfmac_power_off,
+ .reset = brcmfmac_reset
+};
+
+static struct platform_device brcmfmac_device = {
+ .name = BRCMFMAC_SDIO_PDATA_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .dev.platform_data = &brcmfmac_sdio_pdata
+};
+
+void __init brcmfmac_init_pdata(void)
+{
+ brcmfmac_sdio_pdata.oob_irq_supported = true;
+ brcmfmac_sdio_pdata.oob_irq_nr = gpio_to_irq(GPIO_BRCMF_SDIO_OOB);
+ brcmfmac_sdio_pdata.oob_irq_flags = IORESOURCE_IRQ |
+ IORESOURCE_IRQ_HIGHLEVEL;
+ platform_device_register(&brcmfmac_device);
+}
+ *
+ *
+ * Note: the brcmfmac can be loaded as module or be statically built-in into
+ * the kernel. If built-in then do note that it uses module_init (and
+ * module_exit) routines which equal device_initcall. So if you intend to
+ * create a module with the platform specific data for the brcmfmac and have
+ * it built-in to the kernel then use a higher initcall then device_initcall
+ * (see init.h). If this is not done then brcmfmac will load without problems
+ * but will not pickup the platform data.
+ *
+ * When the driver does not "detect" platform driver data then it will continue
+ * without reporting anything and just assume there is no data needed. Which is
+ * probably true for most platforms.
+ *
+ * Explanation of the platform_data fields:
+ *
+ * drive_strength: is the preferred drive_strength to be used for the SDIO
+ * pins. If 0 then a default value will be used. This is the target drive
+ * strength, the exact drive strength which will be used depends on the
+ * capabilities of the device.
+ *
+ * oob_irq_supported: does the board have support for OOB interrupts. SDIO
+ * in-band interrupts are relatively slow and for having less overhead on
+ * interrupt processing an out of band interrupt can be used. If the HW
+ * supports this then enable this by setting this field to true and configure
+ * the oob related fields.
+ *
+ * oob_irq_nr, oob_irq_flags: the OOB interrupt information. The values are
+ * used for registering the irq using request_irq function.
+ *
+ * power_on: This function is called by the brcmfmac when the module gets
+ * loaded. This can be particularly useful for low power devices. The platform
+ * spcific routine may for example decide to power up the complete device.
+ * If there is no use-case for this function then provide NULL.
+ *
+ * power_off: This function is called by the brcmfmac when the module gets
+ * unloaded. At this point the device can be powered down or otherwise be reset.
+ * So if an actual power_off is not supported but reset is then reset the device
+ * when this function gets called. This can be particularly useful for low power
+ * devices. If there is no use-case for this function (either power-down or
+ * reset) then provide NULL.
+ *
+ * reset: This function can get called if the device communication broke down.
+ * This functionality is particularly useful in case of SDIO type devices. It is
+ * possible to reset a dongle via sdio data interface, but it requires that
+ * this is fully functional. This function is chip/module specific and this
+ * function should return only after the complete reset has completed.
+ */
+
+#define BRCMFMAC_SDIO_PDATA_NAME "brcmfmac_sdio"
+
+struct brcmfmac_sdio_platform_data {
+ unsigned int drive_strength;
+ bool oob_irq_supported;
+ unsigned int oob_irq_nr;
+ unsigned long oob_irq_flags;
+ void (*power_on)(void);
+ void (*power_off)(void);
+ void (*reset)(void);
+};
+
+#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
diff --git a/include/linux/platform_data/clk-lpss.h b/include/linux/platform_data/clk-lpss.h
new file mode 100644
index 000000000000..528e73ce46d2
--- /dev/null
+++ b/include/linux/platform_data/clk-lpss.h
@@ -0,0 +1,18 @@
+/*
+ * Intel Low Power Subsystem clocks.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.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 __CLK_LPSS_H
+#define __CLK_LPSS_H
+
+extern int lpt_clk_init(void);
+
+#endif /* __CLK_LPSS_H */
diff --git a/include/linux/platform_data/coda.h b/include/linux/platform_data/coda.h
new file mode 100644
index 000000000000..6ad4410d9e20
--- /dev/null
+++ b/include/linux/platform_data/coda.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ *
+ * 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 PLATFORM_CODA_H
+#define PLATFORM_CODA_H
+
+struct device;
+
+struct coda_platform_data {
+ struct device *iram_dev;
+};
+
+#endif
diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h
index 798fb80b024b..bb3cd58d71e3 100644
--- a/include/linux/platform_data/cpsw.h
+++ b/include/linux/platform_data/cpsw.h
@@ -30,7 +30,7 @@ struct cpsw_platform_data {
u32 channels; /* number of cpdma channels (symmetric) */
u32 slaves; /* number of slave cpgmac ports */
struct cpsw_slave_data *slave_data;
- u32 cpts_active_slave; /* time stamping slave */
+ u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */
u32 cpts_clock_mult; /* convert input clock ticks to nanoseconds */
u32 cpts_clock_shift; /* convert input clock ticks to nanoseconds */
u32 ale_entries; /* ale table size */
diff --git a/include/linux/platform_data/dwc3-omap.h b/include/linux/platform_data/dwc3-omap.h
index ada401244e0b..1d36ca874cc8 100644
--- a/include/linux/platform_data/dwc3-omap.h
+++ b/include/linux/platform_data/dwc3-omap.h
@@ -41,7 +41,3 @@ enum dwc3_omap_utmi_mode {
DWC3_OMAP_UTMI_MODE_HW,
DWC3_OMAP_UTMI_MODE_SW,
};
-
-struct dwc3_omap_data {
- enum dwc3_omap_utmi_mode utmi_mode;
-};
diff --git a/include/linux/platform_data/emif_plat.h b/include/linux/platform_data/emif_plat.h
index 03378ca84061..5c19a2a647c4 100644
--- a/include/linux/platform_data/emif_plat.h
+++ b/include/linux/platform_data/emif_plat.h
@@ -40,6 +40,7 @@
/* Custom config requests */
#define EMIF_CUSTOM_CONFIG_LPMODE 0x00000001
#define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL 0x00000002
+#define EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART 0x00000004
#ifndef __ASSEMBLY__
/**
diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h
index 20ee8b221dbd..ea3200527dd3 100644
--- a/include/linux/platform_data/lp855x.h
+++ b/include/linux/platform_data/lp855x.h
@@ -69,11 +69,6 @@ enum lp855x_chip_id {
LP8557,
};
-enum lp855x_brightness_ctrl_mode {
- PWM_BASED = 1,
- REGISTER_BASED,
-};
-
enum lp8550_brighntess_source {
LP8550_PWM_ONLY,
LP8550_I2C_ONLY = 2,
@@ -116,24 +111,18 @@ struct lp855x_rom_data {
/**
* struct lp855x_platform_data
* @name : Backlight driver name. If it is not defined, default name is set.
- * @mode : brightness control by pwm or lp855x register
* @device_control : value of DEVICE CONTROL register
* @initial_brightness : initial value of backlight brightness
* @period_ns : platform specific pwm period value. unit is nano.
Only valid when mode is PWM_BASED.
- * @load_new_rom_data :
- 0 : use default configuration data
- 1 : update values of eeprom or eprom registers on loading driver
* @size_program : total size of lp855x_rom_data
* @rom_data : list of new eeprom/eprom registers
*/
struct lp855x_platform_data {
- char *name;
- enum lp855x_brightness_ctrl_mode mode;
+ const char *name;
u8 device_control;
- int initial_brightness;
+ u8 initial_brightness;
unsigned int period_ns;
- u8 load_new_rom_data;
int size_program;
struct lp855x_rom_data *rom_data;
};
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
index 944b01dd103e..98b7925f1a2d 100644
--- a/include/linux/platform_data/mv_usb.h
+++ b/include/linux/platform_data/mv_usb.h
@@ -34,8 +34,6 @@ struct mv_usb_addon_irq {
};
struct mv_usb_platform_data {
- unsigned int clknum;
- char **clkname;
struct mv_usb_addon_irq *id; /* Only valid for OTG. ID pin change*/
struct mv_usb_addon_irq *vbus; /* valid for OTG/UDC. VBUS change*/
diff --git a/include/linux/platform_data/ntc_thermistor.h b/include/linux/platform_data/ntc_thermistor.h
index 88734e871e3a..c7285b575462 100644
--- a/include/linux/platform_data/ntc_thermistor.h
+++ b/include/linux/platform_data/ntc_thermistor.h
@@ -21,6 +21,8 @@
#ifndef _LINUX_NTC_H
#define _LINUX_NTC_H
+struct iio_channel;
+
enum ntc_thermistor_type {
TYPE_NCPXXWB473,
TYPE_NCPXXWL333,
@@ -39,13 +41,17 @@ struct ntc_thermistor_platform_data {
* described at Documentation/hwmon/ntc_thermistor
*
* pullup/down_ohm: 0 for infinite / not-connected
+ *
+ * chan: iio_channel pointer to communicate with the ADC which the
+ * thermistor is using for conversion of the analog values.
*/
- int (*read_uV)(void);
- unsigned int pullup_uV;
+ int (*read_uv)(struct ntc_thermistor_platform_data *);
+ unsigned int pullup_uv;
unsigned int pullup_ohm;
unsigned int pulldown_ohm;
enum { NTC_CONNECTED_POSITIVE, NTC_CONNECTED_GROUND } connect;
+ struct iio_channel *chan;
int (*read_ohm)(void);
};
diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h
index 215574d1e81d..bdc510d03245 100644
--- a/include/linux/platform_data/serial-sccnxp.h
+++ b/include/linux/platform_data/serial-sccnxp.h
@@ -86,10 +86,6 @@ struct sccnxp_pdata {
const u32 mctrl_cfg[SCCNXP_MAX_UARTS];
/* Timer value for polling mode (usecs) */
const unsigned int poll_time_us;
- /* Called during startup */
- void (*init)(void);
- /* Called before finish */
- void (*exit)(void);
};
#endif
diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h
new file mode 100644
index 000000000000..92dabcaf6499
--- /dev/null
+++ b/include/linux/platform_data/si5351.h
@@ -0,0 +1,114 @@
+/*
+ * Si5351A/B/C programmable clock generator platform_data.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_SI5351_H__
+#define __LINUX_PLATFORM_DATA_SI5351_H__
+
+struct clk;
+
+/**
+ * enum si5351_variant - SiLabs Si5351 chip variant
+ * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input)
+ * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input)
+ * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input)
+ * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input)
+ */
+enum si5351_variant {
+ SI5351_VARIANT_A = 1,
+ SI5351_VARIANT_A3 = 2,
+ SI5351_VARIANT_B = 3,
+ SI5351_VARIANT_C = 4,
+};
+
+/**
+ * enum si5351_pll_src - Si5351 pll clock source
+ * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config
+ * @SI5351_PLL_SRC_XTAL: pll source clock is XTAL input
+ * @SI5351_PLL_SRC_CLKIN: pll source clock is CLKIN input (Si5351C only)
+ */
+enum si5351_pll_src {
+ SI5351_PLL_SRC_DEFAULT = 0,
+ SI5351_PLL_SRC_XTAL = 1,
+ SI5351_PLL_SRC_CLKIN = 2,
+};
+
+/**
+ * enum si5351_multisynth_src - Si5351 multisynth clock source
+ * @SI5351_MULTISYNTH_SRC_DEFAULT: default, do not change eeprom config
+ * @SI5351_MULTISYNTH_SRC_VCO0: multisynth source clock is VCO0
+ * @SI5351_MULTISYNTH_SRC_VCO1: multisynth source clock is VCO1/VXCO
+ */
+enum si5351_multisynth_src {
+ SI5351_MULTISYNTH_SRC_DEFAULT = 0,
+ SI5351_MULTISYNTH_SRC_VCO0 = 1,
+ SI5351_MULTISYNTH_SRC_VCO1 = 2,
+};
+
+/**
+ * enum si5351_clkout_src - Si5351 clock output clock source
+ * @SI5351_CLKOUT_SRC_DEFAULT: default, do not change eeprom config
+ * @SI5351_CLKOUT_SRC_MSYNTH_N: clkout N source clock is multisynth N
+ * @SI5351_CLKOUT_SRC_MSYNTH_0_4: clkout N source clock is multisynth 0 (N<4)
+ * or 4 (N>=4)
+ * @SI5351_CLKOUT_SRC_XTAL: clkout N source clock is XTAL
+ * @SI5351_CLKOUT_SRC_CLKIN: clkout N source clock is CLKIN (Si5351C only)
+ */
+enum si5351_clkout_src {
+ SI5351_CLKOUT_SRC_DEFAULT = 0,
+ SI5351_CLKOUT_SRC_MSYNTH_N = 1,
+ SI5351_CLKOUT_SRC_MSYNTH_0_4 = 2,
+ SI5351_CLKOUT_SRC_XTAL = 3,
+ SI5351_CLKOUT_SRC_CLKIN = 4,
+};
+
+/**
+ * enum si5351_drive_strength - Si5351 clock output drive strength
+ * @SI5351_DRIVE_DEFAULT: default, do not change eeprom config
+ * @SI5351_DRIVE_2MA: 2mA clock output drive strength
+ * @SI5351_DRIVE_4MA: 4mA clock output drive strength
+ * @SI5351_DRIVE_6MA: 6mA clock output drive strength
+ * @SI5351_DRIVE_8MA: 8mA clock output drive strength
+ */
+enum si5351_drive_strength {
+ SI5351_DRIVE_DEFAULT = 0,
+ SI5351_DRIVE_2MA = 2,
+ SI5351_DRIVE_4MA = 4,
+ SI5351_DRIVE_6MA = 6,
+ SI5351_DRIVE_8MA = 8,
+};
+
+/**
+ * struct si5351_clkout_config - Si5351 clock output configuration
+ * @clkout: clkout number
+ * @multisynth_src: multisynth source clock
+ * @clkout_src: clkout source clock
+ * @pll_master: if true, clkout can also change pll rate
+ * @drive: output drive strength
+ * @rate: initial clkout rate, or default if 0
+ */
+struct si5351_clkout_config {
+ enum si5351_multisynth_src multisynth_src;
+ enum si5351_clkout_src clkout_src;
+ enum si5351_drive_strength drive;
+ bool pll_master;
+ unsigned long rate;
+};
+
+/**
+ * struct si5351_platform_data - Platform data for the Si5351 clock driver
+ * @variant: Si5351 chip variant
+ * @clk_xtal: xtal input clock
+ * @clk_clkin: clkin input clock
+ * @pll_src: array of pll source clock setting
+ * @clkout: array of clkout configuration
+ */
+struct si5351_platform_data {
+ enum si5351_variant variant;
+ struct clk *clk_xtal;
+ struct clk *clk_clkin;
+ enum si5351_pll_src pll_src[2];
+ struct si5351_clkout_config clkout[8];
+};
+
+#endif
diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h
index ceba18d23a5a..8447f634c7f5 100644
--- a/include/linux/platform_data/spi-s3c64xx.h
+++ b/include/linux/platform_data/spi-s3c64xx.h
@@ -11,6 +11,8 @@
#ifndef __S3C64XX_PLAT_SPI_H
#define __S3C64XX_PLAT_SPI_H
+#include <linux/dmaengine.h>
+
struct platform_device;
/**
@@ -38,6 +40,7 @@ struct s3c64xx_spi_info {
int src_clk_nr;
int num_cs;
int (*cfg_gpio)(void);
+ dma_filter_fn filter;
};
/**
diff --git a/include/linux/platform_data/st1232_pdata.h b/include/linux/platform_data/st1232_pdata.h
new file mode 100644
index 000000000000..cac3e7b4c454
--- /dev/null
+++ b/include/linux/platform_data/st1232_pdata.h
@@ -0,0 +1,13 @@
+#ifndef _LINUX_ST1232_PDATA_H
+#define _LINUX_ST1232_PDATA_H
+
+/*
+ * Optional platform data
+ *
+ * Use this if you want the driver to drive the reset pin.
+ */
+struct st1232_pdata {
+ int reset_gpio;
+};
+
+#endif
diff --git a/include/linux/platform_data/video-vt8500lcdfb.h b/include/linux/platform_data/video-vt8500lcdfb.h
deleted file mode 100644
index 7f399c370fe0..000000000000
--- a/include/linux/platform_data/video-vt8500lcdfb.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * VT8500/WM8505 Frame Buffer platform data definitions
- *
- * Copyright (C) 2010 Ed Spiridonov <edo.rus@gmail.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#ifndef _VT8500FB_H
-#define _VT8500FB_H
-
-#include <linux/fb.h>
-
-struct vt8500fb_platform_data {
- struct fb_videomode mode;
- u32 xres_virtual;
- u32 yres_virtual;
- u32 bpp;
- unsigned long video_mem_phys;
- void *video_mem_virt;
- unsigned long video_mem_len;
-};
-
-#endif /* _VT8500FB_H */
diff --git a/include/linux/platform_data/video_s3c.h b/include/linux/platform_data/video_s3c.h
new file mode 100644
index 000000000000..48883995f47f
--- /dev/null
+++ b/include/linux/platform_data/video_s3c.h
@@ -0,0 +1,54 @@
+#ifndef __PLATFORM_DATA_VIDEO_S3C
+#define __PLATFORM_DATA_VIDEO_S3C
+
+/* S3C_FB_MAX_WIN
+ * Set to the maximum number of windows that any of the supported hardware
+ * can use. Since the platform data uses this for an array size, having it
+ * set to the maximum of any version of the hardware can do is safe.
+ */
+#define S3C_FB_MAX_WIN (5)
+
+/**
+ * struct s3c_fb_pd_win - per window setup data
+ * @xres : The window X size.
+ * @yres : The window Y size.
+ * @virtual_x: The virtual X size.
+ * @virtual_y: The virtual Y size.
+ */
+struct s3c_fb_pd_win {
+ unsigned short default_bpp;
+ unsigned short max_bpp;
+ unsigned short xres;
+ unsigned short yres;
+ unsigned short virtual_x;
+ unsigned short virtual_y;
+};
+
+/**
+ * struct s3c_fb_platdata - S3C driver platform specific information
+ * @setup_gpio: Setup the external GPIO pins to the right state to transfer
+ * the data from the display system to the connected display
+ * device.
+ * @vidcon0: The base vidcon0 values to control the panel data format.
+ * @vidcon1: The base vidcon1 values to control the panel data output.
+ * @vtiming: Video timing when connected to a RGB type panel.
+ * @win: The setup data for each hardware window, or NULL for unused.
+ * @display_mode: The LCD output display mode.
+ *
+ * The platform data supplies the video driver with all the information
+ * it requires to work with the display(s) attached to the machine. It
+ * controls the initial mode, the number of display windows (0 is always
+ * the base framebuffer) that are initialised etc.
+ *
+ */
+struct s3c_fb_platdata {
+ void (*setup_gpio)(void);
+
+ struct s3c_fb_pd_win *win[S3C_FB_MAX_WIN];
+ struct fb_videomode *vtiming;
+
+ u32 vidcon0;
+ u32 vidcon1;
+};
+
+#endif
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index c082c71f7225..9abf1db6aea6 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -20,12 +20,12 @@
struct mfd_cell;
struct platform_device {
- const char * name;
+ const char *name;
int id;
bool id_auto;
struct device dev;
u32 num_resources;
- struct resource * resource;
+ struct resource *resource;
const struct platform_device_id *id_entry;
@@ -47,9 +47,12 @@ extern struct bus_type platform_bus_type;
extern struct device platform_bus;
extern void arch_setup_pdev_archdata(struct platform_device *);
-extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
+extern struct resource *platform_get_resource(struct platform_device *,
+ unsigned int, unsigned int);
extern int platform_get_irq(struct platform_device *, unsigned int);
-extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
+extern struct resource *platform_get_resource_byname(struct platform_device *,
+ unsigned int,
+ const char *);
extern int platform_get_irq_byname(struct platform_device *, const char *);
extern int platform_add_devices(struct platform_device **, int);
@@ -161,7 +164,8 @@ extern struct platform_device *platform_device_alloc(const char *name, int id);
extern int platform_device_add_resources(struct platform_device *pdev,
const struct resource *res,
unsigned int num);
-extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
+extern int platform_device_add_data(struct platform_device *pdev,
+ const void *data, size_t size);
extern int platform_device_add(struct platform_device *pdev);
extern void platform_device_del(struct platform_device *pdev);
extern void platform_device_put(struct platform_device *pdev);
@@ -190,7 +194,8 @@ static inline void *platform_get_drvdata(const struct platform_device *pdev)
return dev_get_drvdata(&pdev->dev);
}
-static inline void platform_set_drvdata(struct platform_device *pdev, void *data)
+static inline void platform_set_drvdata(struct platform_device *pdev,
+ void *data)
{
dev_set_drvdata(&pdev->dev, data);
}
@@ -222,10 +227,10 @@ static void __exit __platform_driver##_exit(void) \
} \
module_exit(__platform_driver##_exit);
-extern struct platform_device *platform_create_bundle(struct platform_driver *driver,
- int (*probe)(struct platform_device *),
- struct resource *res, unsigned int n_res,
- const void *data, size_t size);
+extern struct platform_device *platform_create_bundle(
+ struct platform_driver *driver, int (*probe)(struct platform_device *),
+ struct resource *res, unsigned int n_res,
+ const void *data, size_t size);
/* early platform driver interface */
struct early_platform_driver {
diff --git a/include/linux/pm2301_charger.h b/include/linux/pm2301_charger.h
index fc3f026922ae..85c16defe11a 100644
--- a/include/linux/pm2301_charger.h
+++ b/include/linux/pm2301_charger.h
@@ -48,7 +48,7 @@ struct pm2xxx_charger_platform_data {
size_t num_supplicants;
int i2c_bus;
const char *label;
- int irq_number;
+ int gpio_irq_number;
unsigned int lpn_gpio;
int irq_type;
};
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 042058fdb0af..60bac697a91b 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -55,6 +55,7 @@ struct cpu_timer_list {
/* POSIX.1b interval timer structure. */
struct k_itimer {
struct list_head list; /* free/ allocate list */
+ struct hlist_node t_hash;
spinlock_t it_lock;
clockid_t it_clock; /* which timer type */
timer_t it_id; /* timer id */
diff --git a/include/linux/power/ab8500.h b/include/linux/power/ab8500.h
new file mode 100644
index 000000000000..cdbb6c2a8c51
--- /dev/null
+++ b/include/linux/power/ab8500.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) ST-Ericsson 2013
+ * Author: Hongbo Zhang <hongbo.zhang@linaro.com>
+ * License terms: GNU General Public License v2
+ */
+
+#ifndef PWR_AB8500_H
+#define PWR_AB8500_H
+
+extern const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[];
+extern const int ab8500_temp_tbl_a_size;
+
+extern const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[];
+extern const int ab8500_temp_tbl_b_size;
+
+#endif /* PWR_AB8500_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 002a99f96331..3828cefb4f65 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -171,6 +171,12 @@ struct power_supply {
char **supplied_to;
size_t num_supplicants;
+ char **supplied_from;
+ size_t num_supplies;
+#ifdef CONFIG_OF
+ struct device_node *of_node;
+#endif
+
int (*get_property)(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val);
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 5a710b9c578e..87a03c746f17 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -93,14 +93,20 @@ do { \
#else /* !CONFIG_PREEMPT_COUNT */
-#define preempt_disable() do { } while (0)
-#define sched_preempt_enable_no_resched() do { } while (0)
-#define preempt_enable_no_resched() do { } while (0)
-#define preempt_enable() do { } while (0)
-
-#define preempt_disable_notrace() do { } while (0)
-#define preempt_enable_no_resched_notrace() do { } while (0)
-#define preempt_enable_notrace() do { } while (0)
+/*
+ * Even if we don't have any preemption, we need preempt disable/enable
+ * to be barriers, so that we don't have things like get_user/put_user
+ * that can cause faults and scheduling migrate into our preempt-protected
+ * region.
+ */
+#define preempt_disable() barrier()
+#define sched_preempt_enable_no_resched() barrier()
+#define preempt_enable_no_resched() barrier()
+#define preempt_enable() barrier()
+
+#define preempt_disable_notrace() barrier()
+#define preempt_enable_no_resched_notrace() barrier()
+#define preempt_enable_notrace() barrier()
#endif /* CONFIG_PREEMPT_COUNT */
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 822171fcb1c8..6af944ab38f0 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -1,6 +1,7 @@
#ifndef __KERNEL_PRINTK__
#define __KERNEL_PRINTK__
+#include <stdarg.h>
#include <linux/init.h>
#include <linux/kern_levels.h>
@@ -95,8 +96,14 @@ int no_printk(const char *fmt, ...)
return 0;
}
+#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
+void early_vprintk(const char *fmt, va_list ap);
+#else
+static inline __printf(1, 2) __cold
+void early_printk(const char *s, ...) { }
+#endif
#ifdef CONFIG_PRINTK
asmlinkage __printf(5, 0)
@@ -138,6 +145,9 @@ extern void wake_up_klogd(void);
void log_buf_kexec_setup(void);
void __init setup_log_buf(int early);
+void dump_stack_set_arch_desc(const char *fmt, ...);
+void dump_stack_print_info(const char *log_lvl);
+void show_regs_print_info(const char *log_lvl);
#else
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
@@ -175,6 +185,18 @@ static inline void log_buf_kexec_setup(void)
static inline void setup_log_buf(int early)
{
}
+
+static inline void dump_stack_set_arch_desc(const char *fmt, ...)
+{
+}
+
+static inline void dump_stack_print_info(const char *log_lvl)
+{
+}
+
+static inline void show_regs_print_info(const char *log_lvl)
+{
+}
#endif
extern void dump_stack(void) __cold;
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index 5bf5500db83d..69e37c2d1ea5 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -6,7 +6,13 @@ struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir,
extern struct dentry *ramfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data);
-#ifndef CONFIG_MMU
+#ifdef CONFIG_MMU
+static inline int
+ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
+{
+ return 0;
+}
+#else
extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize);
extern unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
unsigned long addr,
diff --git a/include/linux/rculist_bl.h b/include/linux/rculist_bl.h
index cf1244fbf3b6..4f216c59e7db 100644
--- a/include/linux/rculist_bl.h
+++ b/include/linux/rculist_bl.h
@@ -20,7 +20,7 @@ static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h,
static inline struct hlist_bl_node *hlist_bl_first_rcu(struct hlist_bl_head *h)
{
return (struct hlist_bl_node *)
- ((unsigned long)rcu_dereference(h->first) & ~LIST_BL_LOCKMASK);
+ ((unsigned long)rcu_dereference_check(h->first, hlist_bl_is_locked(h)) & ~LIST_BL_LOCKMASK);
}
/**
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b758ce17b309..9ed2c9a4de45 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -80,6 +80,7 @@ extern void do_trace_rcu_torture_read(char *rcutorturename,
#define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b))
#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b))
#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b))
+#define ulong2long(a) (*(long *)(&(a)))
/* Exported common interfaces */
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index bf77dfdabef9..02d84e24b7c2 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -389,6 +389,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
bool *change);
int regmap_get_val_bytes(struct regmap *map);
int regmap_async_complete(struct regmap *map);
+bool regmap_can_raw_write(struct regmap *map);
int regcache_sync(struct regmap *map);
int regcache_sync_region(struct regmap *map, unsigned int min,
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
index 7bd73bbdfd1b..7c5ff0c55773 100644
--- a/include/linux/regulator/ab8500.h
+++ b/include/linux/regulator/ab8500.h
@@ -5,11 +5,14 @@
*
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ * Daniel Willerud <daniel.willerud@stericsson.com> for ST-Ericsson
*/
#ifndef __LINUX_MFD_AB8500_REGULATOR_H
#define __LINUX_MFD_AB8500_REGULATOR_H
+#include <linux/platform_device.h>
+
/* AB8500 regulators */
enum ab8500_regulator_id {
AB8500_LDO_AUX1,
@@ -17,7 +20,6 @@ enum ab8500_regulator_id {
AB8500_LDO_AUX3,
AB8500_LDO_INTCORE,
AB8500_LDO_TVOUT,
- AB8500_LDO_USB,
AB8500_LDO_AUDIO,
AB8500_LDO_ANAMIC1,
AB8500_LDO_ANAMIC2,
@@ -26,7 +28,28 @@ enum ab8500_regulator_id {
AB8500_NUM_REGULATORS,
};
-/* AB9450 regulators */
+/* AB8505 regulators */
+enum ab8505_regulator_id {
+ AB8505_LDO_AUX1,
+ AB8505_LDO_AUX2,
+ AB8505_LDO_AUX3,
+ AB8505_LDO_AUX4,
+ AB8505_LDO_AUX5,
+ AB8505_LDO_AUX6,
+ AB8505_LDO_INTCORE,
+ AB8505_LDO_ADC,
+ AB8505_LDO_USB,
+ AB8505_LDO_AUDIO,
+ AB8505_LDO_ANAMIC1,
+ AB8505_LDO_ANAMIC2,
+ AB8505_LDO_AUX8,
+ AB8505_LDO_ANA,
+ AB8505_SYSCLKREQ_2,
+ AB8505_SYSCLKREQ_4,
+ AB8505_NUM_REGULATORS,
+};
+
+/* AB9540 regulators */
enum ab9540_regulator_id {
AB9540_LDO_AUX1,
AB9540_LDO_AUX2,
@@ -45,16 +68,39 @@ enum ab9540_regulator_id {
AB9540_NUM_REGULATORS,
};
-/* AB8500 and AB9540 register initialization */
+/* AB8540 regulators */
+enum ab8540_regulator_id {
+ AB8540_LDO_AUX1,
+ AB8540_LDO_AUX2,
+ AB8540_LDO_AUX3,
+ AB8540_LDO_AUX4,
+ AB8540_LDO_AUX5,
+ AB8540_LDO_AUX6,
+ AB8540_LDO_INTCORE,
+ AB8540_LDO_TVOUT,
+ AB8540_LDO_AUDIO,
+ AB8540_LDO_ANAMIC1,
+ AB8540_LDO_ANAMIC2,
+ AB8540_LDO_DMIC,
+ AB8540_LDO_ANA,
+ AB8540_LDO_SDIO,
+ AB8540_SYSCLKREQ_2,
+ AB8540_SYSCLKREQ_4,
+ AB8540_NUM_REGULATORS,
+};
+
+/* AB8500, AB8505, and AB9540 register initialization */
struct ab8500_regulator_reg_init {
int id;
+ u8 mask;
u8 value;
};
-#define INIT_REGULATOR_REGISTER(_id, _value) \
- { \
- .id = _id, \
- .value = _value, \
+#define INIT_REGULATOR_REGISTER(_id, _mask, _value) \
+ { \
+ .id = _id, \
+ .mask = _mask, \
+ .value = _value, \
}
/* AB8500 registers */
@@ -86,10 +132,58 @@ enum ab8500_regulator_reg {
AB8500_REGUCTRL2SPARE,
AB8500_REGUCTRLDISCH,
AB8500_REGUCTRLDISCH2,
- AB8500_VSMPS1SEL1,
AB8500_NUM_REGULATOR_REGISTERS,
};
+/* AB8505 registers */
+enum ab8505_regulator_reg {
+ AB8505_REGUREQUESTCTRL1,
+ AB8505_REGUREQUESTCTRL2,
+ AB8505_REGUREQUESTCTRL3,
+ AB8505_REGUREQUESTCTRL4,
+ AB8505_REGUSYSCLKREQ1HPVALID1,
+ AB8505_REGUSYSCLKREQ1HPVALID2,
+ AB8505_REGUHWHPREQ1VALID1,
+ AB8505_REGUHWHPREQ1VALID2,
+ AB8505_REGUHWHPREQ2VALID1,
+ AB8505_REGUHWHPREQ2VALID2,
+ AB8505_REGUSWHPREQVALID1,
+ AB8505_REGUSWHPREQVALID2,
+ AB8505_REGUSYSCLKREQVALID1,
+ AB8505_REGUSYSCLKREQVALID2,
+ AB8505_REGUVAUX4REQVALID,
+ AB8505_REGUMISC1,
+ AB8505_VAUDIOSUPPLY,
+ AB8505_REGUCTRL1VAMIC,
+ AB8505_VSMPSAREGU,
+ AB8505_VSMPSBREGU,
+ AB8505_VSAFEREGU, /* NOTE! PRCMU register */
+ AB8505_VPLLVANAREGU,
+ AB8505_EXTSUPPLYREGU,
+ AB8505_VAUX12REGU,
+ AB8505_VRF1VAUX3REGU,
+ AB8505_VSMPSASEL1,
+ AB8505_VSMPSASEL2,
+ AB8505_VSMPSASEL3,
+ AB8505_VSMPSBSEL1,
+ AB8505_VSMPSBSEL2,
+ AB8505_VSMPSBSEL3,
+ AB8505_VSAFESEL1, /* NOTE! PRCMU register */
+ AB8505_VSAFESEL2, /* NOTE! PRCMU register */
+ AB8505_VSAFESEL3, /* NOTE! PRCMU register */
+ AB8505_VAUX1SEL,
+ AB8505_VAUX2SEL,
+ AB8505_VRF1VAUX3SEL,
+ AB8505_VAUX4REQCTRL,
+ AB8505_VAUX4REGU,
+ AB8505_VAUX4SEL,
+ AB8505_REGUCTRLDISCH,
+ AB8505_REGUCTRLDISCH2,
+ AB8505_REGUCTRLDISCH3,
+ AB8505_CTRLVAUX5,
+ AB8505_CTRLVAUX6,
+ AB8505_NUM_REGULATOR_REGISTERS,
+};
/* AB9540 registers */
enum ab9540_regulator_reg {
@@ -139,4 +233,111 @@ enum ab9540_regulator_reg {
AB9540_NUM_REGULATOR_REGISTERS,
};
+/* AB8540 registers */
+enum ab8540_regulator_reg {
+ AB8540_REGUREQUESTCTRL1,
+ AB8540_REGUREQUESTCTRL2,
+ AB8540_REGUREQUESTCTRL3,
+ AB8540_REGUREQUESTCTRL4,
+ AB8540_REGUSYSCLKREQ1HPVALID1,
+ AB8540_REGUSYSCLKREQ1HPVALID2,
+ AB8540_REGUHWHPREQ1VALID1,
+ AB8540_REGUHWHPREQ1VALID2,
+ AB8540_REGUHWHPREQ2VALID1,
+ AB8540_REGUHWHPREQ2VALID2,
+ AB8540_REGUSWHPREQVALID1,
+ AB8540_REGUSWHPREQVALID2,
+ AB8540_REGUSYSCLKREQVALID1,
+ AB8540_REGUSYSCLKREQVALID2,
+ AB8540_REGUVAUX4REQVALID,
+ AB8540_REGUVAUX5REQVALID,
+ AB8540_REGUVAUX6REQVALID,
+ AB8540_REGUVCLKBREQVALID,
+ AB8540_REGUVRF1REQVALID,
+ AB8540_REGUMISC1,
+ AB8540_VAUDIOSUPPLY,
+ AB8540_REGUCTRL1VAMIC,
+ AB8540_VHSIC,
+ AB8540_VSDIO,
+ AB8540_VSMPS1REGU,
+ AB8540_VSMPS2REGU,
+ AB8540_VSMPS3REGU,
+ AB8540_VPLLVANAREGU,
+ AB8540_EXTSUPPLYREGU,
+ AB8540_VAUX12REGU,
+ AB8540_VRF1VAUX3REGU,
+ AB8540_VSMPS1SEL1,
+ AB8540_VSMPS1SEL2,
+ AB8540_VSMPS1SEL3,
+ AB8540_VSMPS2SEL1,
+ AB8540_VSMPS2SEL2,
+ AB8540_VSMPS2SEL3,
+ AB8540_VSMPS3SEL1,
+ AB8540_VSMPS3SEL2,
+ AB8540_VAUX1SEL,
+ AB8540_VAUX2SEL,
+ AB8540_VRF1VAUX3SEL,
+ AB8540_REGUCTRL2SPARE,
+ AB8540_VAUX4REQCTRL,
+ AB8540_VAUX4REGU,
+ AB8540_VAUX4SEL,
+ AB8540_VAUX5REQCTRL,
+ AB8540_VAUX5REGU,
+ AB8540_VAUX5SEL,
+ AB8540_VAUX6REQCTRL,
+ AB8540_VAUX6REGU,
+ AB8540_VAUX6SEL,
+ AB8540_VCLKBREQCTRL,
+ AB8540_VCLKBREGU,
+ AB8540_VCLKBSEL,
+ AB8540_VRF1REQCTRL,
+ AB8540_REGUCTRLDISCH,
+ AB8540_REGUCTRLDISCH2,
+ AB8540_REGUCTRLDISCH3,
+ AB8540_REGUCTRLDISCH4,
+ AB8540_VSIMSYSCLKCTRL,
+ AB8540_VANAVPLLSEL,
+ AB8540_NUM_REGULATOR_REGISTERS,
+};
+
+/* AB8500 external regulators */
+struct ab8500_ext_regulator_cfg {
+ bool hwreq; /* requires hw mode or high power mode */
+};
+
+enum ab8500_ext_regulator_id {
+ AB8500_EXT_SUPPLY1,
+ AB8500_EXT_SUPPLY2,
+ AB8500_EXT_SUPPLY3,
+ AB8500_NUM_EXT_REGULATORS,
+};
+
+/* AB8500 regulator platform data */
+struct ab8500_regulator_platform_data {
+ int num_reg_init;
+ struct ab8500_regulator_reg_init *reg_init;
+ int num_regulator;
+ struct regulator_init_data *regulator;
+ int num_ext_regulator;
+ struct regulator_init_data *ext_regulator;
+};
+
+#ifdef CONFIG_REGULATOR_AB8500_DEBUG
+int ab8500_regulator_debug_init(struct platform_device *pdev);
+int ab8500_regulator_debug_exit(struct platform_device *pdev);
+#else
+static inline int ab8500_regulator_debug_init(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline int ab8500_regulator_debug_exit(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+/* AB8500 external regulator functions. */
+int ab8500_ext_regulator_init(struct platform_device *pdev);
+void ab8500_ext_regulator_exit(struct platform_device *pdev);
+
#endif
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 7bc732ce6e50..145022a83085 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -141,18 +141,18 @@ void regulator_put(struct regulator *regulator);
void devm_regulator_put(struct regulator *regulator);
/* regulator output control and status */
-int regulator_enable(struct regulator *regulator);
+int __must_check regulator_enable(struct regulator *regulator);
int regulator_disable(struct regulator *regulator);
int regulator_force_disable(struct regulator *regulator);
int regulator_is_enabled(struct regulator *regulator);
int regulator_disable_deferred(struct regulator *regulator, int ms);
-int regulator_bulk_get(struct device *dev, int num_consumers,
- struct regulator_bulk_data *consumers);
-int devm_regulator_bulk_get(struct device *dev, int num_consumers,
- struct regulator_bulk_data *consumers);
-int regulator_bulk_enable(int num_consumers,
- struct regulator_bulk_data *consumers);
+int __must_check regulator_bulk_get(struct device *dev, int num_consumers,
+ struct regulator_bulk_data *consumers);
+int __must_check devm_regulator_bulk_get(struct device *dev, int num_consumers,
+ struct regulator_bulk_data *consumers);
+int __must_check regulator_bulk_enable(int num_consumers,
+ struct regulator_bulk_data *consumers);
int regulator_bulk_disable(int num_consumers,
struct regulator_bulk_data *consumers);
int regulator_bulk_force_disable(int num_consumers,
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 7df93f52db08..6700cc94bdd1 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -22,6 +22,7 @@
struct regmap;
struct regulator_dev;
struct regulator_init_data;
+struct regulator_enable_gpio;
enum regulator_status {
REGULATOR_STATUS_OFF,
@@ -199,6 +200,8 @@ enum regulator_type {
* output when using regulator_set_voltage_sel_regmap
* @enable_reg: Register for control when using regmap enable/disable ops
* @enable_mask: Mask for control when using regmap enable/disable ops
+ * @enable_is_inverted: A flag to indicate set enable_mask bits to disable
+ * when using regulator_enable_regmap and friends APIs.
* @bypass_reg: Register for control when using regmap set_bypass
* @bypass_mask: Mask for control when using regmap set_bypass
*
@@ -228,6 +231,7 @@ struct regulator_desc {
unsigned int apply_bit;
unsigned int enable_reg;
unsigned int enable_mask;
+ bool enable_is_inverted;
unsigned int bypass_reg;
unsigned int bypass_mask;
@@ -302,8 +306,7 @@ struct regulator_dev {
struct dentry *debugfs;
- int ena_gpio;
- unsigned int ena_gpio_invert:1;
+ struct regulator_enable_gpio *ena_pin;
unsigned int ena_gpio_state:1;
};
@@ -329,6 +332,8 @@ int regulator_map_voltage_linear(struct regulator_dev *rdev,
int min_uV, int max_uV);
int regulator_map_voltage_iterate(struct regulator_dev *rdev,
int min_uV, int max_uV);
+int regulator_map_voltage_ascend(struct regulator_dev *rdev,
+ int min_uV, int max_uV);
int regulator_get_voltage_sel_regmap(struct regulator_dev *rdev);
int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel);
int regulator_is_enabled_regmap(struct regulator_dev *rdev);
diff --git a/include/linux/regulator/max8952.h b/include/linux/regulator/max8952.h
index 45e42855ad05..4dbb63a1d4ab 100644
--- a/include/linux/regulator/max8952.h
+++ b/include/linux/regulator/max8952.h
@@ -122,13 +122,13 @@ struct max8952_platform_data {
int gpio_vid1;
int gpio_en;
- u8 default_mode;
- u8 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */
+ u32 default_mode;
+ u32 dvs_mode[MAX8952_NUM_DVS_MODE]; /* MAX8952_DVS_MODEx_XXXXmV */
- u8 sync_freq;
- u8 ramp_speed;
+ u32 sync_freq;
+ u32 ramp_speed;
- struct regulator_init_data reg_data;
+ struct regulator_init_data *reg_data;
};
diff --git a/include/linux/relay.h b/include/linux/relay.h
index 91cacc34c159..d7c8359693c6 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -20,9 +20,6 @@
#include <linux/poll.h>
#include <linux/kref.h>
-/* Needs a _much_ better name... */
-#define FIX_SIZE(x) ((((x) - 1) & PAGE_MASK) + PAGE_SIZE)
-
/*
* Tracks changes to rchan/rchan_buf structs
*/
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index c23099413ad6..96a509b6be04 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -13,7 +13,7 @@
* info about what this counter is.
*/
-#include <linux/cgroup.h>
+#include <linux/spinlock.h>
#include <linux/errno.h>
/*
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 1342e69542f3..d69cf637a15a 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -4,6 +4,7 @@
#include <linux/kmemcheck.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
+#include <linux/poll.h>
struct ring_buffer;
struct ring_buffer_iter;
@@ -96,6 +97,11 @@ __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *k
__ring_buffer_alloc((size), (flags), &__key); \
})
+void ring_buffer_wait(struct ring_buffer *buffer, int cpu);
+int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu,
+ struct file *filp, poll_table *poll_table);
+
+
#define RING_BUFFER_ALL_CPUS -1
void ring_buffer_free(struct ring_buffer *buffer);
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 580b24c8b8ca..c2c28975293c 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -133,7 +133,13 @@ extern struct rtc_device *rtc_device_register(const char *name,
struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner);
+extern struct rtc_device *devm_rtc_device_register(struct device *dev,
+ const char *name,
+ const struct rtc_class_ops *ops,
+ struct module *owner);
extern void rtc_device_unregister(struct rtc_device *rtc);
+extern void devm_rtc_device_unregister(struct device *dev,
+ struct rtc_device *rtc);
extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 489dd7bb28ec..f28544b2f9af 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -69,6 +69,15 @@ extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
int idx);
+extern int ndo_dflt_fdb_add(struct ndmsg *ndm,
+ struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr,
+ u16 flags);
+extern int ndo_dflt_fdb_del(struct ndmsg *ndm,
+ struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr);
extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
struct net_device *dev, u16 mode);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index d35d2b6ddbfb..6f950048b6e9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -127,18 +127,6 @@ extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
extern void proc_sched_set_task(struct task_struct *p);
extern void
print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
-#else
-static inline void
-proc_sched_show_task(struct task_struct *p, struct seq_file *m)
-{
-}
-static inline void proc_sched_set_task(struct task_struct *p)
-{
-}
-static inline void
-print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
-{
-}
#endif
/*
@@ -163,9 +151,10 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
#define TASK_DEAD 64
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
-#define TASK_STATE_MAX 512
+#define TASK_PARKED 512
+#define TASK_STATE_MAX 1024
-#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKW"
+#define TASK_STATE_TO_CHAR_STR "RSDTtZXxKWP"
extern char ___assert_task_state[1 - 2*!!(
sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];
@@ -320,7 +309,6 @@ extern signed long schedule_timeout_killable(signed long timeout);
extern signed long schedule_timeout_uninterruptible(signed long timeout);
asmlinkage void schedule(void);
extern void schedule_preempt_disabled(void);
-extern int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner);
struct nsproxy;
struct user_namespace;
@@ -526,7 +514,8 @@ struct signal_struct {
unsigned int has_child_subreaper:1;
/* POSIX.1b Interval Timers */
- struct list_head posix_timers;
+ int posix_timer_id;
+ struct list_head posix_timers;
/* ITIMER_REAL timer for the process */
struct hrtimer real_timer;
@@ -570,7 +559,7 @@ struct signal_struct {
cputime_t utime, stime, cutime, cstime;
cputime_t gtime;
cputime_t cgtime;
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
struct cputime prev_cputime;
#endif
unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
@@ -637,6 +626,7 @@ struct signal_struct {
#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */
#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */
#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */
+#define SIGNAL_GROUP_COREDUMP 0x00000008 /* coredump in progress */
/*
* Pending notifications to parent.
*/
@@ -768,31 +758,6 @@ enum cpu_idle_type {
};
/*
- * Increase resolution of nice-level calculations for 64-bit architectures.
- * The extra resolution improves shares distribution and load balancing of
- * low-weight task groups (eg. nice +19 on an autogroup), deeper taskgroup
- * hierarchies, especially on larger systems. This is not a user-visible change
- * and does not change the user-interface for setting shares/weights.
- *
- * We increase resolution only if we have enough bits to allow this increased
- * resolution (i.e. BITS_PER_LONG > 32). The costs for increasing resolution
- * when BITS_PER_LONG <= 32 are pretty high and the returns do not justify the
- * increased costs.
- */
-#if 0 /* BITS_PER_LONG > 32 -- currently broken: it increases power usage under light load */
-# define SCHED_LOAD_RESOLUTION 10
-# define scale_load(w) ((w) << SCHED_LOAD_RESOLUTION)
-# define scale_load_down(w) ((w) >> SCHED_LOAD_RESOLUTION)
-#else
-# define SCHED_LOAD_RESOLUTION 0
-# define scale_load(w) (w)
-# define scale_load_down(w) (w)
-#endif
-
-#define SCHED_LOAD_SHIFT (10 + SCHED_LOAD_RESOLUTION)
-#define SCHED_LOAD_SCALE (1L << SCHED_LOAD_SHIFT)
-
-/*
* Increase resolution of cpu_power calculations
*/
#define SCHED_POWER_SHIFT 10
@@ -817,62 +782,6 @@ enum cpu_idle_type {
extern int __weak arch_sd_sibiling_asym_packing(void);
-struct sched_group_power {
- atomic_t ref;
- /*
- * CPU power of this group, SCHED_LOAD_SCALE being max power for a
- * single CPU.
- */
- unsigned int power, power_orig;
- unsigned long next_update;
- /*
- * Number of busy cpus in this group.
- */
- atomic_t nr_busy_cpus;
-
- unsigned long cpumask[0]; /* iteration mask */
-};
-
-struct sched_group {
- struct sched_group *next; /* Must be a circular list */
- atomic_t ref;
-
- unsigned int group_weight;
- struct sched_group_power *sgp;
-
- /*
- * The CPUs this group covers.
- *
- * NOTE: this field is variable length. (Allocated dynamically
- * by attaching extra space to the end of the structure,
- * depending on how many CPUs the kernel has booted up with)
- */
- unsigned long cpumask[0];
-};
-
-static inline struct cpumask *sched_group_cpus(struct sched_group *sg)
-{
- return to_cpumask(sg->cpumask);
-}
-
-/*
- * cpumask masking which cpus in the group are allowed to iterate up the domain
- * tree.
- */
-static inline struct cpumask *sched_group_mask(struct sched_group *sg)
-{
- return to_cpumask(sg->sgp->cpumask);
-}
-
-/**
- * group_first_cpu - Returns the first cpu in the cpumask of a sched_group.
- * @group: The group whose first cpu is to be returned.
- */
-static inline unsigned int group_first_cpu(struct sched_group *group)
-{
- return cpumask_first(sched_group_cpus(group));
-}
-
struct sched_domain_attr {
int relax_domain_level;
};
@@ -883,6 +792,8 @@ struct sched_domain_attr {
extern int sched_domain_level_max;
+struct sched_group;
+
struct sched_domain {
/* These fields must be setup */
struct sched_domain *parent; /* top domain must be null terminated */
@@ -899,6 +810,8 @@ struct sched_domain {
unsigned int wake_idx;
unsigned int forkexec_idx;
unsigned int smt_gain;
+
+ int nohz_idle; /* NOHZ IDLE status */
int flags; /* See SD_* */
int level;
@@ -971,18 +884,6 @@ extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[],
cpumask_var_t *alloc_sched_domains(unsigned int ndoms);
void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);
-/* Test a flag in parent sched domain */
-static inline int test_sd_parent(struct sched_domain *sd, int flag)
-{
- if (sd->parent && (sd->parent->flags & flag))
- return 1;
-
- return 0;
-}
-
-unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu);
-unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu);
-
bool cpus_share_cache(int this_cpu, int that_cpu);
#else /* CONFIG_SMP */
@@ -1017,72 +918,6 @@ struct mempolicy;
struct pipe_inode_info;
struct uts_namespace;
-struct rq;
-struct sched_domain;
-
-/*
- * wake flags
- */
-#define WF_SYNC 0x01 /* waker goes to sleep after wakup */
-#define WF_FORK 0x02 /* child wakeup after fork */
-#define WF_MIGRATED 0x04 /* internal use, task got migrated */
-
-#define ENQUEUE_WAKEUP 1
-#define ENQUEUE_HEAD 2
-#ifdef CONFIG_SMP
-#define ENQUEUE_WAKING 4 /* sched_class::task_waking was called */
-#else
-#define ENQUEUE_WAKING 0
-#endif
-
-#define DEQUEUE_SLEEP 1
-
-struct sched_class {
- const struct sched_class *next;
-
- void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
- void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
- void (*yield_task) (struct rq *rq);
- bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);
-
- void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
-
- struct task_struct * (*pick_next_task) (struct rq *rq);
- void (*put_prev_task) (struct rq *rq, struct task_struct *p);
-
-#ifdef CONFIG_SMP
- int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags);
- void (*migrate_task_rq)(struct task_struct *p, int next_cpu);
-
- void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
- void (*post_schedule) (struct rq *this_rq);
- void (*task_waking) (struct task_struct *task);
- void (*task_woken) (struct rq *this_rq, struct task_struct *task);
-
- void (*set_cpus_allowed)(struct task_struct *p,
- const struct cpumask *newmask);
-
- void (*rq_online)(struct rq *rq);
- void (*rq_offline)(struct rq *rq);
-#endif
-
- void (*set_curr_task) (struct rq *rq);
- void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
- void (*task_fork) (struct task_struct *p);
-
- void (*switched_from) (struct rq *this_rq, struct task_struct *task);
- void (*switched_to) (struct rq *this_rq, struct task_struct *task);
- void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
- int oldprio);
-
- unsigned int (*get_rr_interval) (struct rq *rq,
- struct task_struct *task);
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
- void (*task_move_group) (struct task_struct *p, int on_rq);
-#endif
-};
-
struct load_weight {
unsigned long weight, inv_weight;
};
@@ -1274,8 +1109,10 @@ struct task_struct {
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
unsigned int jobctl; /* JOBCTL_*, siglock protected */
- /* ??? */
+
+ /* Used for emulating ABI behavior of previous Linux versions */
unsigned int personality;
+
unsigned did_exec:1;
unsigned in_execve:1; /* Tell the LSMs that the process is doing an
* execve */
@@ -1327,7 +1164,7 @@ struct task_struct {
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime;
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
struct cputime prev_cputime;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
@@ -1793,7 +1630,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
#define PF_SPREAD_PAGE 0x01000000 /* Spread page cache over cpuset */
#define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */
-#define PF_THREAD_BOUND 0x04000000 /* Thread bound to specific cpu */
+#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
#define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */
#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
@@ -2412,27 +2249,18 @@ static inline void threadgroup_change_end(struct task_struct *tsk)
*
* Lock the threadgroup @tsk belongs to. No new task is allowed to enter
* and member tasks aren't allowed to exit (as indicated by PF_EXITING) or
- * perform exec. This is useful for cases where the threadgroup needs to
- * stay stable across blockable operations.
+ * change ->group_leader/pid. This is useful for cases where the threadgroup
+ * needs to stay stable across blockable operations.
*
* fork and exit paths explicitly call threadgroup_change_{begin|end}() for
* synchronization. While held, no new task will be added to threadgroup
* and no existing live task will have its PF_EXITING set.
*
- * During exec, a task goes and puts its thread group through unusual
- * changes. After de-threading, exclusive access is assumed to resources
- * which are usually shared by tasks in the same group - e.g. sighand may
- * be replaced with a new one. Also, the exec'ing task takes over group
- * leader role including its pid. Exclude these changes while locked by
- * grabbing cred_guard_mutex which is used to synchronize exec path.
+ * de_thread() does threadgroup_change_{begin|end}() when a non-leader
+ * sub-thread becomes a new leader.
*/
static inline void threadgroup_lock(struct task_struct *tsk)
{
- /*
- * exec uses exit for de-threading nesting group_rwsem inside
- * cred_guard_mutex. Grab cred_guard_mutex first.
- */
- mutex_lock(&tsk->signal->cred_guard_mutex);
down_write(&tsk->signal->group_rwsem);
}
@@ -2445,7 +2273,6 @@ static inline void threadgroup_lock(struct task_struct *tsk)
static inline void threadgroup_unlock(struct task_struct *tsk)
{
up_write(&tsk->signal->group_rwsem);
- mutex_unlock(&tsk->signal->cred_guard_mutex);
}
#else
static inline void threadgroup_change_begin(struct task_struct *tsk) {}
@@ -2622,6 +2449,47 @@ static inline int spin_needbreak(spinlock_t *lock)
}
/*
+ * Idle thread specific functions to determine the need_resched
+ * polling state. We have two versions, one based on TS_POLLING in
+ * thread_info.status and one based on TIF_POLLING_NRFLAG in
+ * thread_info.flags
+ */
+#ifdef TS_POLLING
+static inline int tsk_is_polling(struct task_struct *p)
+{
+ return task_thread_info(p)->status & TS_POLLING;
+}
+static inline void current_set_polling(void)
+{
+ current_thread_info()->status |= TS_POLLING;
+}
+
+static inline void current_clr_polling(void)
+{
+ current_thread_info()->status &= ~TS_POLLING;
+ smp_mb__after_clear_bit();
+}
+#elif defined(TIF_POLLING_NRFLAG)
+static inline int tsk_is_polling(struct task_struct *p)
+{
+ return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG);
+}
+static inline void current_set_polling(void)
+{
+ set_thread_flag(TIF_POLLING_NRFLAG);
+}
+
+static inline void current_clr_polling(void)
+{
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+}
+#else
+static inline int tsk_is_polling(struct task_struct *p) { return 0; }
+static inline void current_set_polling(void) { }
+static inline void current_clr_polling(void) { }
+#endif
+
+/*
* Thread group CPU time accounting.
*/
void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times);
@@ -2681,28 +2549,7 @@ extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask);
extern long sched_getaffinity(pid_t pid, struct cpumask *mask);
#ifdef CONFIG_CGROUP_SCHED
-
extern struct task_group root_task_group;
-
-extern struct task_group *sched_create_group(struct task_group *parent);
-extern void sched_online_group(struct task_group *tg,
- struct task_group *parent);
-extern void sched_destroy_group(struct task_group *tg);
-extern void sched_offline_group(struct task_group *tg);
-extern void sched_move_task(struct task_struct *tsk);
-#ifdef CONFIG_FAIR_GROUP_SCHED
-extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
-extern unsigned long sched_group_shares(struct task_group *tg);
-#endif
-#ifdef CONFIG_RT_GROUP_SCHED
-extern int sched_group_set_rt_runtime(struct task_group *tg,
- long rt_runtime_us);
-extern long sched_group_rt_runtime(struct task_group *tg);
-extern int sched_group_set_rt_period(struct task_group *tg,
- long rt_period_us);
-extern long sched_group_rt_period(struct task_group *tg);
-extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk);
-#endif
#endif /* CONFIG_CGROUP_SCHED */
extern int task_can_switch_user(struct user_struct *up,
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index c11a28706fa4..3bfe8d6ee248 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -53,7 +53,9 @@
#include <linux/in.h> /* We need in_addr. */
#include <linux/in6.h> /* We need in6_addr. */
+#include <linux/skbuff.h>
+#include <uapi/linux/sctp.h>
/* Section 3.1. SCTP Common Header Format */
typedef struct sctphdr {
@@ -63,14 +65,10 @@ typedef struct sctphdr {
__le32 checksum;
} __packed sctp_sctphdr_t;
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
static inline struct sctphdr *sctp_hdr(const struct sk_buff *skb)
{
return (struct sctphdr *)skb_transport_header(skb);
}
-#endif
/* Section 3.2. Chunk Field Descriptions. */
typedef struct sctp_chunkhdr {
diff --git a/include/linux/security.h b/include/linux/security.h
index eee7478cda70..4686491852a7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1012,6 +1012,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* This hook can be used by the module to update any security state
* associated with the TUN device's security structure.
* @security pointer to the TUN devices's security structure.
+ * @skb_owned_by:
+ * This hook sets the packet's owning sock.
+ * @skb is the packet.
+ * @sk the sock which owns the packet.
*
* Security hooks for XFRM operations.
*
@@ -1436,7 +1440,7 @@ struct security_operations {
struct path *new_path);
int (*sb_set_mnt_opts) (struct super_block *sb,
struct security_mnt_opts *opts);
- void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
+ int (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
@@ -1638,6 +1642,7 @@ struct security_operations {
int (*tun_dev_attach_queue) (void *security);
int (*tun_dev_attach) (struct sock *sk, void *security);
int (*tun_dev_open) (void *security);
+ void (*skb_owned_by) (struct sk_buff *skb, struct sock *sk);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1721,7 +1726,7 @@ int security_sb_mount(const char *dev_name, struct path *path,
int security_sb_umount(struct vfsmount *mnt, int flags);
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
-void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
@@ -2011,9 +2016,11 @@ static inline int security_sb_set_mnt_opts(struct super_block *sb,
return 0;
}
-static inline void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
-{ }
+{
+ return 0;
+}
static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
@@ -2588,6 +2595,8 @@ int security_tun_dev_attach_queue(void *security);
int security_tun_dev_attach(struct sock *sk, void *security);
int security_tun_dev_open(void *security);
+void security_skb_owned_by(struct sk_buff *skb, struct sock *sk);
+
#else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct sock *sock,
struct sock *other,
@@ -2779,6 +2788,11 @@ static inline int security_tun_dev_open(void *security)
{
return 0;
}
+
+static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
+{
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h
new file mode 100644
index 000000000000..907d9d1d56cf
--- /dev/null
+++ b/include/linux/serial_s3c.h
@@ -0,0 +1,260 @@
+/*
+ * Internal header file for Samsung S3C2410 serial ports (UART0-2)
+ *
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * Additional defines, Copyright 2003 Simtec Electronics (linux@simtec.co.uk)
+ *
+ * Adapted from:
+ *
+ * Internal header file for MX1ADS serial ports (UART1 & 2)
+ *
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __ASM_ARM_REGS_SERIAL_H
+#define __ASM_ARM_REGS_SERIAL_H
+
+#define S3C2410_URXH (0x24)
+#define S3C2410_UTXH (0x20)
+#define S3C2410_ULCON (0x00)
+#define S3C2410_UCON (0x04)
+#define S3C2410_UFCON (0x08)
+#define S3C2410_UMCON (0x0C)
+#define S3C2410_UBRDIV (0x28)
+#define S3C2410_UTRSTAT (0x10)
+#define S3C2410_UERSTAT (0x14)
+#define S3C2410_UFSTAT (0x18)
+#define S3C2410_UMSTAT (0x1C)
+
+#define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3))
+
+#define S3C2410_LCON_CS5 (0x0)
+#define S3C2410_LCON_CS6 (0x1)
+#define S3C2410_LCON_CS7 (0x2)
+#define S3C2410_LCON_CS8 (0x3)
+#define S3C2410_LCON_CSMASK (0x3)
+
+#define S3C2410_LCON_PNONE (0x0)
+#define S3C2410_LCON_PEVEN (0x5 << 3)
+#define S3C2410_LCON_PODD (0x4 << 3)
+#define S3C2410_LCON_PMASK (0x7 << 3)
+
+#define S3C2410_LCON_STOPB (1<<2)
+#define S3C2410_LCON_IRM (1<<6)
+
+#define S3C2440_UCON_CLKMASK (3<<10)
+#define S3C2440_UCON_CLKSHIFT (10)
+#define S3C2440_UCON_PCLK (0<<10)
+#define S3C2440_UCON_UCLK (1<<10)
+#define S3C2440_UCON_PCLK2 (2<<10)
+#define S3C2440_UCON_FCLK (3<<10)
+#define S3C2443_UCON_EPLL (3<<10)
+
+#define S3C6400_UCON_CLKMASK (3<<10)
+#define S3C6400_UCON_CLKSHIFT (10)
+#define S3C6400_UCON_PCLK (0<<10)
+#define S3C6400_UCON_PCLK2 (2<<10)
+#define S3C6400_UCON_UCLK0 (1<<10)
+#define S3C6400_UCON_UCLK1 (3<<10)
+
+#define S3C2440_UCON2_FCLK_EN (1<<15)
+#define S3C2440_UCON0_DIVMASK (15 << 12)
+#define S3C2440_UCON1_DIVMASK (15 << 12)
+#define S3C2440_UCON2_DIVMASK (7 << 12)
+#define S3C2440_UCON_DIVSHIFT (12)
+
+#define S3C2412_UCON_CLKMASK (3<<10)
+#define S3C2412_UCON_CLKSHIFT (10)
+#define S3C2412_UCON_UCLK (1<<10)
+#define S3C2412_UCON_USYSCLK (3<<10)
+#define S3C2412_UCON_PCLK (0<<10)
+#define S3C2412_UCON_PCLK2 (2<<10)
+
+#define S3C2410_UCON_CLKMASK (1 << 10)
+#define S3C2410_UCON_CLKSHIFT (10)
+#define S3C2410_UCON_UCLK (1<<10)
+#define S3C2410_UCON_SBREAK (1<<4)
+
+#define S3C2410_UCON_TXILEVEL (1<<9)
+#define S3C2410_UCON_RXILEVEL (1<<8)
+#define S3C2410_UCON_TXIRQMODE (1<<2)
+#define S3C2410_UCON_RXIRQMODE (1<<0)
+#define S3C2410_UCON_RXFIFO_TOI (1<<7)
+#define S3C2443_UCON_RXERR_IRQEN (1<<6)
+#define S3C2443_UCON_LOOPBACK (1<<5)
+
+#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI)
+
+#define S3C2410_UFCON_FIFOMODE (1<<0)
+#define S3C2410_UFCON_TXTRIG0 (0<<6)
+#define S3C2410_UFCON_RXTRIG8 (1<<4)
+#define S3C2410_UFCON_RXTRIG12 (2<<4)
+
+/* S3C2440 FIFO trigger levels */
+#define S3C2440_UFCON_RXTRIG1 (0<<4)
+#define S3C2440_UFCON_RXTRIG8 (1<<4)
+#define S3C2440_UFCON_RXTRIG16 (2<<4)
+#define S3C2440_UFCON_RXTRIG32 (3<<4)
+
+#define S3C2440_UFCON_TXTRIG0 (0<<6)
+#define S3C2440_UFCON_TXTRIG16 (1<<6)
+#define S3C2440_UFCON_TXTRIG32 (2<<6)
+#define S3C2440_UFCON_TXTRIG48 (3<<6)
+
+#define S3C2410_UFCON_RESETBOTH (3<<1)
+#define S3C2410_UFCON_RESETTX (1<<2)
+#define S3C2410_UFCON_RESETRX (1<<1)
+
+#define S3C2410_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S3C2410_UFCON_TXTRIG0 | \
+ S3C2410_UFCON_RXTRIG8 )
+
+#define S3C2410_UMCOM_AFC (1<<4)
+#define S3C2410_UMCOM_RTS_LOW (1<<0)
+
+#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */
+#define S3C2412_UMCON_AFC_56 (1<<5)
+#define S3C2412_UMCON_AFC_48 (2<<5)
+#define S3C2412_UMCON_AFC_40 (3<<5)
+#define S3C2412_UMCON_AFC_32 (4<<5)
+#define S3C2412_UMCON_AFC_24 (5<<5)
+#define S3C2412_UMCON_AFC_16 (6<<5)
+#define S3C2412_UMCON_AFC_8 (7<<5)
+
+#define S3C2410_UFSTAT_TXFULL (1<<9)
+#define S3C2410_UFSTAT_RXFULL (1<<8)
+#define S3C2410_UFSTAT_TXMASK (15<<4)
+#define S3C2410_UFSTAT_TXSHIFT (4)
+#define S3C2410_UFSTAT_RXMASK (15<<0)
+#define S3C2410_UFSTAT_RXSHIFT (0)
+
+/* UFSTAT S3C2443 same as S3C2440 */
+#define S3C2440_UFSTAT_TXFULL (1<<14)
+#define S3C2440_UFSTAT_RXFULL (1<<6)
+#define S3C2440_UFSTAT_TXSHIFT (8)
+#define S3C2440_UFSTAT_RXSHIFT (0)
+#define S3C2440_UFSTAT_TXMASK (63<<8)
+#define S3C2440_UFSTAT_RXMASK (63)
+
+#define S3C2410_UTRSTAT_TXE (1<<2)
+#define S3C2410_UTRSTAT_TXFE (1<<1)
+#define S3C2410_UTRSTAT_RXDR (1<<0)
+
+#define S3C2410_UERSTAT_OVERRUN (1<<0)
+#define S3C2410_UERSTAT_FRAME (1<<2)
+#define S3C2410_UERSTAT_BREAK (1<<3)
+#define S3C2443_UERSTAT_PARITY (1<<1)
+
+#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
+ S3C2410_UERSTAT_FRAME | \
+ S3C2410_UERSTAT_BREAK)
+
+#define S3C2410_UMSTAT_CTS (1<<0)
+#define S3C2410_UMSTAT_DeltaCTS (1<<2)
+
+#define S3C2443_DIVSLOT (0x2C)
+
+/* S3C64XX interrupt registers. */
+#define S3C64XX_UINTP 0x30
+#define S3C64XX_UINTSP 0x34
+#define S3C64XX_UINTM 0x38
+
+#define S3C64XX_UINTM_RXD (0)
+#define S3C64XX_UINTM_TXD (2)
+#define S3C64XX_UINTM_RXD_MSK (1 << S3C64XX_UINTM_RXD)
+#define S3C64XX_UINTM_TXD_MSK (1 << S3C64XX_UINTM_TXD)
+
+/* Following are specific to S5PV210 */
+#define S5PV210_UCON_CLKMASK (1<<10)
+#define S5PV210_UCON_CLKSHIFT (10)
+#define S5PV210_UCON_PCLK (0<<10)
+#define S5PV210_UCON_UCLK (1<<10)
+
+#define S5PV210_UFCON_TXTRIG0 (0<<8)
+#define S5PV210_UFCON_TXTRIG4 (1<<8)
+#define S5PV210_UFCON_TXTRIG8 (2<<8)
+#define S5PV210_UFCON_TXTRIG16 (3<<8)
+#define S5PV210_UFCON_TXTRIG32 (4<<8)
+#define S5PV210_UFCON_TXTRIG64 (5<<8)
+#define S5PV210_UFCON_TXTRIG128 (6<<8)
+#define S5PV210_UFCON_TXTRIG256 (7<<8)
+
+#define S5PV210_UFCON_RXTRIG1 (0<<4)
+#define S5PV210_UFCON_RXTRIG4 (1<<4)
+#define S5PV210_UFCON_RXTRIG8 (2<<4)
+#define S5PV210_UFCON_RXTRIG16 (3<<4)
+#define S5PV210_UFCON_RXTRIG32 (4<<4)
+#define S5PV210_UFCON_RXTRIG64 (5<<4)
+#define S5PV210_UFCON_RXTRIG128 (6<<4)
+#define S5PV210_UFCON_RXTRIG256 (7<<4)
+
+#define S5PV210_UFSTAT_TXFULL (1<<24)
+#define S5PV210_UFSTAT_RXFULL (1<<8)
+#define S5PV210_UFSTAT_TXMASK (255<<16)
+#define S5PV210_UFSTAT_TXSHIFT (16)
+#define S5PV210_UFSTAT_RXMASK (255<<0)
+#define S5PV210_UFSTAT_RXSHIFT (0)
+
+#define S3C2410_UCON_CLKSEL0 (1 << 0)
+#define S3C2410_UCON_CLKSEL1 (1 << 1)
+#define S3C2410_UCON_CLKSEL2 (1 << 2)
+#define S3C2410_UCON_CLKSEL3 (1 << 3)
+
+/* Default values for s5pv210 UCON and UFCON uart registers */
+#define S5PV210_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
+ S3C2410_UCON_RXILEVEL | \
+ S3C2410_UCON_TXIRQMODE | \
+ S3C2410_UCON_RXIRQMODE | \
+ S3C2410_UCON_RXFIFO_TOI | \
+ S3C2443_UCON_RXERR_IRQEN)
+
+#define S5PV210_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \
+ S5PV210_UFCON_TXTRIG4 | \
+ S5PV210_UFCON_RXTRIG4)
+
+#ifndef __ASSEMBLY__
+
+/* configuration structure for per-machine configurations for the
+ * serial port
+ *
+ * the pointer is setup by the machine specific initialisation from the
+ * arch/arm/mach-s3c2410/ directory.
+*/
+
+struct s3c2410_uartcfg {
+ unsigned char hwport; /* hardware port number */
+ unsigned char unused;
+ unsigned short flags;
+ upf_t uart_flags; /* default uart flags */
+ unsigned int clk_sel;
+
+ unsigned int has_fracval;
+
+ unsigned long ucon; /* value of ucon for port */
+ unsigned long ulcon; /* value of ulcon for port */
+ unsigned long ufcon; /* value of ufcon for port */
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ARM_REGS_SERIAL_H */
+
diff --git a/include/linux/sh_eth.h b/include/linux/sh_eth.h
index b17d765ded84..fc305713fc6d 100644
--- a/include/linux/sh_eth.h
+++ b/include/linux/sh_eth.h
@@ -6,6 +6,7 @@
enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN};
enum {
SH_ETH_REG_GIGABIT,
+ SH_ETH_REG_FAST_RCAR,
SH_ETH_REG_FAST_SH4,
SH_ETH_REG_FAST_SH3_SH2
};
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 1135e3696e81..d897484730c0 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -250,11 +250,11 @@ extern int show_unhandled_signals;
extern int sigsuspend(sigset_t *);
struct sigaction {
-#ifndef __ARCH_HAS_ODD_SIGACTION
+#ifndef __ARCH_HAS_IRIX_SIGACTION
__sighandler_t sa_handler;
unsigned long sa_flags;
#else
- unsigned long sa_flags;
+ unsigned int sa_flags;
__sighandler_t sa_handler;
#endif
#ifdef __ARCH_HAS_SA_RESTORER
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 441f5bfdab8e..2e0ced1af3b1 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -32,6 +32,7 @@
#include <linux/hrtimer.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
+#include <net/flow_keys.h>
/* Don't change this without changing skb_csum_unnecessary! */
#define CHECKSUM_NONE 0
@@ -316,6 +317,8 @@ enum {
SKB_GSO_FCOE = 1 << 5,
SKB_GSO_GRE = 1 << 6,
+
+ SKB_GSO_UDP_TUNNEL = 1 << 7,
};
#if BITS_PER_LONG > 32
@@ -384,9 +387,11 @@ typedef unsigned char *sk_buff_data_t;
* @secmark: security marking
* @mark: Generic packet mark
* @dropcount: total number of sk_receive_queue overflows
+ * @vlan_proto: vlan encapsulation protocol
* @vlan_tci: vlan tag control information
* @inner_transport_header: Inner transport layer header (encapsulation)
* @inner_network_header: Network layer header (encapsulation)
+ * @inner_mac_header: Link layer header (encapsulation)
* @transport_header: Transport layer header
* @network_header: Network layer header
* @mac_header: Link layer header
@@ -461,6 +466,7 @@ struct sk_buff {
__u32 rxhash;
+ __be16 vlan_proto;
__u16 vlan_tci;
#ifdef CONFIG_NET_SCHED
@@ -505,6 +511,7 @@ struct sk_buff {
sk_buff_data_t inner_transport_header;
sk_buff_data_t inner_network_header;
+ sk_buff_data_t inner_mac_header;
sk_buff_data_t transport_header;
sk_buff_data_t network_header;
sk_buff_data_t mac_header;
@@ -570,7 +577,40 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
skb->_skb_refdst = (unsigned long)dst;
}
-extern void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst);
+extern void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst,
+ bool force);
+
+/**
+ * skb_dst_set_noref - sets skb dst, hopefully, without taking reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst.
+ * If dst entry is cached, we do not take reference and dst_release
+ * will be avoided by refdst_drop. If dst entry is not cached, we take
+ * reference, so that last dst_release can destroy the dst immediately.
+ */
+static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+{
+ __skb_dst_set_noref(skb, dst, false);
+}
+
+/**
+ * skb_dst_set_noref_force - sets skb dst, without taking reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst.
+ * No reference is taken and no dst_release will be called. While for
+ * cached dsts deferred reclaim is a basic feature, for entries that are
+ * not cached it is caller's job to guarantee that last dst_release for
+ * provided dst happens when nobody uses it, eg. after a RCU grace period.
+ */
+static inline void skb_dst_set_noref_force(struct sk_buff *skb,
+ struct dst_entry *dst)
+{
+ __skb_dst_set_noref(skb, dst, true);
+}
/**
* skb_dst_is_noref - Test if skb dst isn't refcounted
@@ -611,6 +651,12 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
return __alloc_skb(size, priority, SKB_ALLOC_FCLONE, NUMA_NO_NODE);
}
+extern struct sk_buff *__alloc_skb_head(gfp_t priority, int node);
+static inline struct sk_buff *alloc_skb_head(gfp_t priority)
+{
+ return __alloc_skb_head(priority, -1);
+}
+
extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
extern int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask);
extern struct sk_buff *skb_clone(struct sk_buff *skb,
@@ -1471,6 +1517,7 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
static inline void skb_reset_inner_headers(struct sk_buff *skb)
{
+ skb->inner_mac_header = skb->mac_header;
skb->inner_network_header = skb->network_header;
skb->inner_transport_header = skb->transport_header;
}
@@ -1516,6 +1563,22 @@ static inline void skb_set_inner_network_header(struct sk_buff *skb,
skb->inner_network_header += offset;
}
+static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb)
+{
+ return skb->head + skb->inner_mac_header;
+}
+
+static inline void skb_reset_inner_mac_header(struct sk_buff *skb)
+{
+ skb->inner_mac_header = skb->data - skb->head;
+}
+
+static inline void skb_set_inner_mac_header(struct sk_buff *skb,
+ const int offset)
+{
+ skb_reset_inner_mac_header(skb);
+ skb->inner_mac_header += offset;
+}
static inline bool skb_transport_header_was_set(const struct sk_buff *skb)
{
return skb->transport_header != ~0U;
@@ -1609,6 +1672,21 @@ static inline void skb_set_inner_network_header(struct sk_buff *skb,
skb->inner_network_header = skb->data + offset;
}
+static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb)
+{
+ return skb->inner_mac_header;
+}
+
+static inline void skb_reset_inner_mac_header(struct sk_buff *skb)
+{
+ skb->inner_mac_header = skb->data;
+}
+
+static inline void skb_set_inner_mac_header(struct sk_buff *skb,
+ const int offset)
+{
+ skb->inner_mac_header = skb->data + offset;
+}
static inline bool skb_transport_header_was_set(const struct sk_buff *skb)
{
return skb->transport_header != NULL;
@@ -1666,6 +1744,19 @@ static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
}
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+static inline void skb_probe_transport_header(struct sk_buff *skb,
+ const int offset_hint)
+{
+ struct flow_keys keys;
+
+ if (skb_transport_header_was_set(skb))
+ return;
+ else if (skb_flow_dissect(skb, &keys))
+ skb_set_transport_header(skb, keys.thoff);
+ else
+ skb_set_transport_header(skb, offset_hint);
+}
+
static inline void skb_mac_header_rebuild(struct sk_buff *skb)
{
if (skb_mac_header_was_set(skb)) {
@@ -2643,6 +2734,13 @@ static inline void nf_reset(struct sk_buff *skb)
#endif
}
+static inline void nf_reset_trace(struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+ skb->nf_trace = 0;
+#endif
+}
+
/* Note: This doesn't put any conntrack and bridge info in dst. */
static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
{
@@ -2804,6 +2902,8 @@ static inline void skb_checksum_none_assert(const struct sk_buff *skb)
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
+u32 __skb_get_poff(const struct sk_buff *skb);
+
/**
* skb_head_is_locked - Determine if the skb->head is locked down
* @skb: skb to check
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 3e07a7df6478..e6564c1dc552 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -20,7 +20,6 @@ struct call_single_data {
smp_call_func_t func;
void *info;
u16 flags;
- u16 priv;
};
/* total number of cpus in this system (may exceed NR_CPUS) */
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index e8d702e0fd89..54f91d35e5fd 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -1,6 +1,7 @@
#ifndef __SOCK_DIAG_H__
#define __SOCK_DIAG_H__
+#include <linux/user_namespace.h>
#include <uapi/linux/sock_diag.h>
struct sk_buff;
@@ -22,5 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie);
void sock_diag_save_cookie(void *sk, __u32 *cookie);
int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
+int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+ struct sk_buff *skb, int attrtype);
#endif
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 2b9f74b0ffea..428c37a1f95c 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -298,6 +298,7 @@ struct ucred {
#define SOL_IUCV 277
#define SOL_CAIF 278
#define SOL_ALG 279
+#define SOL_NFC 280
/* IPX options */
#define IPX_TYPE 1
diff --git a/include/linux/spi/at86rf230.h b/include/linux/spi/at86rf230.h
index b2b1afbb3202..aa327a8105ad 100644
--- a/include/linux/spi/at86rf230.h
+++ b/include/linux/spi/at86rf230.h
@@ -26,6 +26,20 @@ struct at86rf230_platform_data {
int rstn;
int slp_tr;
int dig2;
+
+ /* Setting the irq_type will configure the driver to request
+ * the platform irq trigger type according to the given value
+ * and configure the interrupt polarity of the device to the
+ * corresponding polarity.
+ *
+ * Allowed values are: IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING,
+ * IRQF_TRIGGER_HIGH and IRQF_TRIGGER_LOW
+ *
+ * Setting it to 0, the driver does not touch the trigger type
+ * configuration of the interrupt and sets the interrupt polarity
+ * of the device to high active (the default value).
+ */
+ int irq_type;
};
#endif
diff --git a/include/linux/spi/spi-tegra.h b/include/linux/spi/spi-tegra.h
deleted file mode 100644
index 786932c62edb..000000000000
--- a/include/linux/spi/spi-tegra.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * spi-tegra.h: SPI interface for Nvidia Tegra20 SLINK controller.
- *
- * Copyright (C) 2011 NVIDIA Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _LINUX_SPI_TEGRA_H
-#define _LINUX_SPI_TEGRA_H
-
-struct tegra_spi_platform_data {
- int dma_req_sel;
- unsigned int spi_max_frequency;
-};
-
-/*
- * Controller data from device to pass some info like
- * hw based chip select can be used or not and if yes
- * then CS hold and setup time.
- */
-struct tegra_spi_device_controller_data {
- bool is_hw_based_cs;
- int cs_setup_clk_count;
- int cs_hold_clk_count;
-};
-
-#endif /* _LINUX_SPI_TEGRA_H */
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 38c2b925923d..733eb5ee31c5 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -228,6 +228,11 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* every chipselect is connected to a slave.
* @dma_alignment: SPI controller constraint on DMA buffers alignment.
* @mode_bits: flags understood by this controller driver
+ * @bits_per_word_mask: A mask indicating which values of bits_per_word are
+ * supported by the driver. Bit n indicates that a bits_per_word n+1 is
+ * suported. If set, the SPI core will reject any transfer with an
+ * unsupported bits_per_word. If not set, this value is simply ignored,
+ * and it's up to the individual driver to perform any validation.
* @flags: other constraints relevant to this driver
* @bus_lock_spinlock: spinlock for SPI bus locking
* @bus_lock_mutex: mutex for SPI bus locking
@@ -301,6 +306,9 @@ struct spi_master {
/* spi_device.mode flags understood by this controller driver */
u16 mode_bits;
+ /* bitmask of supported bits_per_word for transfers */
+ u32 bits_per_word_mask;
+
/* other constraints relevant to this driver */
u16 flags;
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index a26e2fb604e6..e2369c167dbd 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -16,7 +16,10 @@
* In the debug case, 1 means unlocked, 0 means locked. (the values
* are inverted, to catch initialization bugs)
*
- * No atomicity anywhere, we are on UP.
+ * No atomicity anywhere, we are on UP. However, we still need
+ * the compiler barriers, because we do not want the compiler to
+ * move potentially faulting instructions (notably user accesses)
+ * into the locked sequence, resulting in non-atomic execution.
*/
#ifdef CONFIG_DEBUG_SPINLOCK
@@ -25,6 +28,7 @@
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
lock->slock = 0;
+ barrier();
}
static inline void
@@ -32,6 +36,7 @@ arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags)
{
local_irq_save(flags);
lock->slock = 0;
+ barrier();
}
static inline int arch_spin_trylock(arch_spinlock_t *lock)
@@ -39,32 +44,34 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
char oldval = lock->slock;
lock->slock = 0;
+ barrier();
return oldval > 0;
}
static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
+ barrier();
lock->slock = 1;
}
/*
* Read-write spinlocks. No debug version.
*/
-#define arch_read_lock(lock) do { (void)(lock); } while (0)
-#define arch_write_lock(lock) do { (void)(lock); } while (0)
-#define arch_read_trylock(lock) ({ (void)(lock); 1; })
-#define arch_write_trylock(lock) ({ (void)(lock); 1; })
-#define arch_read_unlock(lock) do { (void)(lock); } while (0)
-#define arch_write_unlock(lock) do { (void)(lock); } while (0)
+#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; })
+#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; })
+#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0)
+#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0)
#else /* DEBUG_SPINLOCK */
#define arch_spin_is_locked(lock) ((void)(lock), 0)
/* for sched.c and kernel_lock.c: */
-# define arch_spin_lock(lock) do { (void)(lock); } while (0)
-# define arch_spin_lock_flags(lock, flags) do { (void)(lock); } while (0)
-# define arch_spin_unlock(lock) do { (void)(lock); } while (0)
-# define arch_spin_trylock(lock) ({ (void)(lock); 1; })
+# define arch_spin_lock(lock) do { barrier(); (void)(lock); } while (0)
+# define arch_spin_lock_flags(lock, flags) do { barrier(); (void)(lock); } while (0)
+# define arch_spin_unlock(lock) do { barrier(); (void)(lock); } while (0)
+# define arch_spin_trylock(lock) ({ barrier(); (void)(lock); 1; })
#endif /* DEBUG_SPINLOCK */
#define arch_spin_is_contended(lock) (((void)(lock), 0))
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 22958d68ecfe..c64999fd1660 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -26,9 +26,9 @@ struct ssb_sprom_core_pwr_info {
struct ssb_sprom {
u8 revision;
- u8 il0mac[6]; /* MAC address for 802.11b/g */
- u8 et0mac[6]; /* MAC address for Ethernet */
- u8 et1mac[6]; /* MAC address for 802.11a */
+ u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */
+ u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */
+ u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */
u8 et0phyaddr; /* MII address for enet0 */
u8 et1phyaddr; /* MII address for enet1 */
u8 et0mdcport; /* MDIO for enet0 */
@@ -340,13 +340,61 @@ enum ssb_bustype {
#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */
#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */
/* board_type */
+#define SSB_BOARD_BCM94301CB 0x0406
+#define SSB_BOARD_BCM94301MP 0x0407
+#define SSB_BOARD_BU4309 0x040A
+#define SSB_BOARD_BCM94309CB 0x040B
+#define SSB_BOARD_BCM4309MP 0x040C
+#define SSB_BOARD_BU4306 0x0416
#define SSB_BOARD_BCM94306MP 0x0418
#define SSB_BOARD_BCM4309G 0x0421
#define SSB_BOARD_BCM4306CB 0x0417
-#define SSB_BOARD_BCM4309MP 0x040C
+#define SSB_BOARD_BCM94306PC 0x0425 /* pcmcia 3.3v 4306 card */
+#define SSB_BOARD_BCM94306CBSG 0x042B /* with SiGe PA */
+#define SSB_BOARD_PCSG94306 0x042D /* with SiGe PA */
+#define SSB_BOARD_BU4704SD 0x042E /* with sdram */
+#define SSB_BOARD_BCM94704AGR 0x042F /* dual 11a/11g Router */
+#define SSB_BOARD_BCM94308MP 0x0430 /* 11a-only minipci */
+#define SSB_BOARD_BU4318 0x0447
+#define SSB_BOARD_CB4318 0x0448
+#define SSB_BOARD_MPG4318 0x0449
#define SSB_BOARD_MP4318 0x044A
-#define SSB_BOARD_BU4306 0x0416
-#define SSB_BOARD_BU4309 0x040A
+#define SSB_BOARD_SD4318 0x044B
+#define SSB_BOARD_BCM94306P 0x044C /* with SiGe */
+#define SSB_BOARD_BCM94303MP 0x044E
+#define SSB_BOARD_BCM94306MPM 0x0450
+#define SSB_BOARD_BCM94306MPL 0x0453
+#define SSB_BOARD_PC4303 0x0454 /* pcmcia */
+#define SSB_BOARD_BCM94306MPLNA 0x0457
+#define SSB_BOARD_BCM94306MPH 0x045B
+#define SSB_BOARD_BCM94306PCIV 0x045C
+#define SSB_BOARD_BCM94318MPGH 0x0463
+#define SSB_BOARD_BU4311 0x0464
+#define SSB_BOARD_BCM94311MC 0x0465
+#define SSB_BOARD_BCM94311MCAG 0x0466
+/* 4321 boards */
+#define SSB_BOARD_BU4321 0x046B
+#define SSB_BOARD_BU4321E 0x047C
+#define SSB_BOARD_MP4321 0x046C
+#define SSB_BOARD_CB2_4321 0x046D
+#define SSB_BOARD_CB2_4321_AG 0x0066
+#define SSB_BOARD_MC4321 0x046E
+/* 4325 boards */
+#define SSB_BOARD_BCM94325DEVBU 0x0490
+#define SSB_BOARD_BCM94325BGABU 0x0491
+#define SSB_BOARD_BCM94325SDGWB 0x0492
+#define SSB_BOARD_BCM94325SDGMDL 0x04AA
+#define SSB_BOARD_BCM94325SDGMDL2 0x04C6
+#define SSB_BOARD_BCM94325SDGMDL3 0x04C9
+#define SSB_BOARD_BCM94325SDABGWBA 0x04E1
+/* 4322 boards */
+#define SSB_BOARD_BCM94322MC 0x04A4
+#define SSB_BOARD_BCM94322USB 0x04A8 /* dualband */
+#define SSB_BOARD_BCM94322HM 0x04B0
+#define SSB_BOARD_BCM94322USB2D 0x04Bf /* single band discrete front end */
+/* 4312 boards */
+#define SSB_BOARD_BU4312 0x048A
+#define SSB_BOARD_BCM4312MCGSG 0x04B5
/* chip_package */
#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */
#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h
index 9e492be5244b..6fcfe99bd999 100644
--- a/include/linux/ssb/ssb_driver_chipcommon.h
+++ b/include/linux/ssb/ssb_driver_chipcommon.h
@@ -219,6 +219,7 @@
#define SSB_CHIPCO_PMU_CTL 0x0600 /* PMU control */
#define SSB_CHIPCO_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */
#define SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT 16
+#define SSB_CHIPCO_PMU_CTL_PLL_UPD 0x00000400
#define SSB_CHIPCO_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */
#define SSB_CHIPCO_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */
#define SSB_CHIPCO_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */
@@ -667,5 +668,6 @@ enum ssb_pmu_ldo_volt_id {
void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
enum ssb_pmu_ldo_volt_id id, u32 voltage);
void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on);
+void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid);
#endif /* LINUX_SSB_CHIPCO_H_ */
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index 6ecfa02ddbac..3a7256955b10 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -289,11 +289,11 @@
#define SSB_SPROM4_ETHPHY_ET1A_SHIFT 5
#define SSB_SPROM4_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */
#define SSB_SPROM4_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM4_ANTAVAIL 0x005D /* Antenna available bitfields */
-#define SSB_SPROM4_ANTAVAIL_A 0x00FF /* A-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_A_SHIFT 0
-#define SSB_SPROM4_ANTAVAIL_BG 0xFF00 /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 8
+#define SSB_SPROM4_ANTAVAIL 0x005C /* Antenna available bitfields */
+#define SSB_SPROM4_ANTAVAIL_BG 0x00FF /* B-PHY and G-PHY bitfield */
+#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 0
+#define SSB_SPROM4_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */
+#define SSB_SPROM4_ANTAVAIL_A_SHIFT 8
#define SSB_SPROM4_AGAIN01 0x005E /* Antenna Gain (in dBm Q5.2) */
#define SSB_SPROM4_AGAIN0 0x00FF /* Antenna 0 */
#define SSB_SPROM4_AGAIN0_SHIFT 0
diff --git a/include/linux/ssbi.h b/include/linux/ssbi.h
new file mode 100644
index 000000000000..44ef5da21470
--- /dev/null
+++ b/include/linux/ssbi.h
@@ -0,0 +1,38 @@
+/* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Author: Dima Zavin <dima@android.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 and
+ * only 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.
+ */
+
+#ifndef _LINUX_SSBI_H
+#define _LINUX_SSBI_H
+
+#include <linux/types.h>
+
+struct ssbi_slave_info {
+ const char *name;
+ void *platform_data;
+};
+
+enum ssbi_controller_type {
+ MSM_SBI_CTRL_SSBI = 0,
+ MSM_SBI_CTRL_SSBI2,
+ MSM_SBI_CTRL_PMIC_ARBITER,
+};
+
+struct ssbi_platform_data {
+ struct ssbi_slave_info slave;
+ enum ssbi_controller_type controller_type;
+};
+
+int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len);
+int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len);
+#endif
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
index a3eb2f65b656..3eeee9672a4a 100644
--- a/include/linux/string_helpers.h
+++ b/include/linux/string_helpers.h
@@ -13,4 +13,62 @@ enum string_size_units {
int string_get_size(u64 size, enum string_size_units units,
char *buf, int len);
+#define UNESCAPE_SPACE 0x01
+#define UNESCAPE_OCTAL 0x02
+#define UNESCAPE_HEX 0x04
+#define UNESCAPE_SPECIAL 0x08
+#define UNESCAPE_ANY \
+ (UNESCAPE_SPACE | UNESCAPE_OCTAL | UNESCAPE_HEX | UNESCAPE_SPECIAL)
+
+/**
+ * string_unescape - unquote characters in the given string
+ * @src: source buffer (escaped)
+ * @dst: destination buffer (unescaped)
+ * @size: size of the destination buffer (0 to unlimit)
+ * @flags: combination of the flags (bitwise OR):
+ * %UNESCAPE_SPACE:
+ * '\f' - form feed
+ * '\n' - new line
+ * '\r' - carriage return
+ * '\t' - horizontal tab
+ * '\v' - vertical tab
+ * %UNESCAPE_OCTAL:
+ * '\NNN' - byte with octal value NNN (1 to 3 digits)
+ * %UNESCAPE_HEX:
+ * '\xHH' - byte with hexadecimal value HH (1 to 2 digits)
+ * %UNESCAPE_SPECIAL:
+ * '\"' - double quote
+ * '\\' - backslash
+ * '\a' - alert (BEL)
+ * '\e' - escape
+ * %UNESCAPE_ANY:
+ * all previous together
+ *
+ * Returns amount of characters processed to the destination buffer excluding
+ * trailing '\0'.
+ *
+ * Because the size of the output will be the same as or less than the size of
+ * the input, the transformation may be performed in place.
+ *
+ * Caller must provide valid source and destination pointers. Be aware that
+ * destination buffer will always be NULL-terminated. Source string must be
+ * NULL-terminated as well.
+ */
+int string_unescape(char *src, char *dst, size_t size, unsigned int flags);
+
+static inline int string_unescape_inplace(char *buf, unsigned int flags)
+{
+ return string_unescape(buf, buf, 0, flags);
+}
+
+static inline int string_unescape_any(char *src, char *dst, size_t size)
+{
+ return string_unescape(src, dst, size, UNESCAPE_ANY);
+}
+
+static inline int string_unescape_any_inplace(char *buf)
+{
+ return string_unescape_any(buf, buf, 0);
+}
+
#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 58fda1c3c783..0dd00f4f6810 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -22,6 +22,8 @@
/* size of the nodename buffer */
#define UNX_MAXNODENAME 32
+struct rpcsec_gss_info;
+
/* Work around the lack of a VFS credential */
struct auth_cred {
kuid_t uid;
@@ -103,6 +105,9 @@ struct rpc_authops {
int (*pipes_create)(struct rpc_auth *);
void (*pipes_destroy)(struct rpc_auth *);
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
+ rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
+ int (*flavor2info)(rpc_authflavor_t,
+ struct rpcsec_gss_info *);
};
struct rpc_credops {
@@ -137,6 +142,10 @@ int rpcauth_register(const struct rpc_authops *);
int rpcauth_unregister(const struct rpc_authops *);
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
void rpcauth_release(struct rpc_auth *);
+rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
+ struct rpcsec_gss_info *);
+int rpcauth_get_gssinfo(rpc_authflavor_t,
+ struct rpcsec_gss_info *);
int rpcauth_list_flavors(rpc_authflavor_t *, int);
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 2cf4ffaa3cd4..e7d492ce7c18 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -124,6 +124,7 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_NOPING (1UL << 4)
#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5)
#define RPC_CLNT_CREATE_QUIET (1UL << 6)
+#define RPC_CLNT_CREATE_INFINITE_SLOTS (1UL << 7)
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index a19e2547ae6a..f32b7a47e13f 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -25,10 +25,21 @@ struct gss_ctx {
#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0)
#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0)
-#define GSS_C_NULL_OID ((struct xdr_netobj) 0)
+#define GSS_C_QOP_DEFAULT (0)
/*XXX arbitrary length - is this set somewhere? */
#define GSS_OID_MAX_LEN 32
+struct rpcsec_gss_oid {
+ unsigned int len;
+ u8 data[GSS_OID_MAX_LEN];
+};
+
+/* From RFC 3530 */
+struct rpcsec_gss_info {
+ struct rpcsec_gss_oid oid;
+ u32 qop;
+ u32 service;
+};
/* gss-api prototypes; note that these are somewhat simplified versions of
* the prototypes specified in RFC 2744. */
@@ -58,12 +69,14 @@ u32 gss_unwrap(
u32 gss_delete_sec_context(
struct gss_ctx **ctx_id);
-u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service);
+rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop,
+ u32 service);
u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
struct pf_desc {
u32 pseudoflavor;
+ u32 qop;
u32 service;
char *name;
char *auth_domain_name;
@@ -76,7 +89,7 @@ struct pf_desc {
struct gss_api_mech {
struct list_head gm_list;
struct module *gm_owner;
- struct xdr_netobj gm_oid;
+ struct rpcsec_gss_oid gm_oid;
char *gm_name;
const struct gss_api_ops *gm_ops;
/* pseudoflavors supported by this mechanism: */
@@ -117,9 +130,11 @@ struct gss_api_ops {
int gss_mech_register(struct gss_api_mech *);
void gss_mech_unregister(struct gss_api_mech *);
-/* returns a mechanism descriptor given an OID, and increments the mechanism's
- * reference count. */
-struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
+/* Given a GSS security tuple, look up a pseudoflavor */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
+
+/* Given a pseudoflavor, look up a GSS security tuple */
+int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
/* Returns a reference to a mechanism, given a name like "krb5" etc. */
struct gss_api_mech *gss_mech_get_by_name(const char *);
@@ -130,9 +145,6 @@ struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32);
/* Fill in an array with a list of supported pseudoflavors */
int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int);
-/* Just increments the mechanism's reference count and returns its input: */
-struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
-
/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a
* corresponding call to gss_mech_put. */
void gss_mech_put(struct gss_api_mech *);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 30834be03011..ff5392421cb2 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -255,6 +255,8 @@ static inline int bc_prealloc(struct rpc_rqst *req)
}
#endif /* CONFIG_SUNRPC_BACKCHANNEL */
+#define XPRT_CREATE_INFINITE_SLOTS (1U)
+
struct xprt_create {
int ident; /* XPRT_TRANSPORT identifier */
struct net * net;
@@ -263,6 +265,7 @@ struct xprt_create {
size_t addrlen;
const char *servername;
struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */
+ unsigned int flags;
};
struct xprt_class {
@@ -279,6 +282,7 @@ struct xprt_class {
struct rpc_xprt *xprt_create_transport(struct xprt_create *args);
void xprt_connect(struct rpc_task *task);
void xprt_reserve(struct rpc_task *task);
+void xprt_retry_reserve(struct rpc_task *task);
int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task);
@@ -334,6 +338,7 @@ int xs_swapper(struct rpc_xprt *xprt, int enable);
#define XPRT_CLOSING (6)
#define XPRT_CONNECTION_ABORT (7)
#define XPRT_CONNECTION_CLOSE (8)
+#define XPRT_CONGESTED (9)
static inline void xprt_set_connected(struct rpc_xprt *xprt)
{
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 2818a123f3ea..1701ce4be746 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -236,7 +236,7 @@ extern unsigned long nr_free_pagecache_pages(void);
extern void __lru_cache_add(struct page *, enum lru_list lru);
extern void lru_cache_add_lru(struct page *, enum lru_list lru);
extern void lru_add_page_tail(struct page *page, struct page *page_tail,
- struct lruvec *lruvec);
+ struct lruvec *lruvec, struct list_head *head);
extern void activate_page(struct page *);
extern void mark_page_accessed(struct page *);
extern void lru_add_drain(void);
@@ -330,6 +330,9 @@ static inline void mem_cgroup_uncharge_swap(swp_entry_t ent)
/* linux/mm/page_io.c */
extern int swap_readpage(struct page *);
extern int swap_writepage(struct page *page, struct writeback_control *wbc);
+extern void end_swap_bio_write(struct bio *bio, int err);
+extern int __swap_writepage(struct page *page, struct writeback_control *wbc,
+ void (*end_write_func)(struct bio *, int));
extern int swap_set_page_dirty(struct page *page);
extern void end_swap_bio_read(struct bio *bio, int err);
@@ -343,8 +346,9 @@ extern struct address_space swapper_spaces[];
#define swap_address_space(entry) (&swapper_spaces[swp_type(entry)])
extern unsigned long total_swapcache_pages(void);
extern void show_swap_cache_info(void);
-extern int add_to_swap(struct page *);
+extern int add_to_swap(struct page *, struct list_head *list);
extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t);
+extern int __add_to_swap_cache(struct page *page, swp_entry_t entry);
extern void __delete_from_swap_cache(struct page *);
extern void delete_from_swap_cache(struct page *);
extern void free_page_and_swap_cache(struct page *);
@@ -461,7 +465,7 @@ static inline struct page *lookup_swap_cache(swp_entry_t swp)
return NULL;
}
-static inline int add_to_swap(struct page *page)
+static inline int add_to_swap(struct page *page, struct list_head *list)
{
return 0;
}
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 2de42f9401d2..a5ffd32642fd 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -25,6 +25,7 @@ extern int swiotlb_force;
extern void swiotlb_init(int verbose);
int swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
extern unsigned long swiotlb_nr_tbl(void);
+unsigned long swiotlb_size_or_default(void);
extern int swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs);
/*
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 313a8e0a6553..4147d700a293 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -78,49 +78,34 @@ struct sigaltstack;
#include <linux/key.h>
#include <trace/syscall.h>
-#define __SC_DECL1(t1, a1) t1 a1
-#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
-#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
-#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)
-#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)
-#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__)
-
-#define __SC_LONG1(t1, a1) long a1
-#define __SC_LONG2(t2, a2, ...) long a2, __SC_LONG1(__VA_ARGS__)
-#define __SC_LONG3(t3, a3, ...) long a3, __SC_LONG2(__VA_ARGS__)
-#define __SC_LONG4(t4, a4, ...) long a4, __SC_LONG3(__VA_ARGS__)
-#define __SC_LONG5(t5, a5, ...) long a5, __SC_LONG4(__VA_ARGS__)
-#define __SC_LONG6(t6, a6, ...) long a6, __SC_LONG5(__VA_ARGS__)
-
-#define __SC_CAST1(t1, a1) (t1) a1
-#define __SC_CAST2(t2, a2, ...) (t2) a2, __SC_CAST1(__VA_ARGS__)
-#define __SC_CAST3(t3, a3, ...) (t3) a3, __SC_CAST2(__VA_ARGS__)
-#define __SC_CAST4(t4, a4, ...) (t4) a4, __SC_CAST3(__VA_ARGS__)
-#define __SC_CAST5(t5, a5, ...) (t5) a5, __SC_CAST4(__VA_ARGS__)
-#define __SC_CAST6(t6, a6, ...) (t6) a6, __SC_CAST5(__VA_ARGS__)
-
-#define __SC_TEST(type) BUILD_BUG_ON(sizeof(type) > sizeof(long))
-#define __SC_TEST1(t1, a1) __SC_TEST(t1)
-#define __SC_TEST2(t2, a2, ...) __SC_TEST(t2); __SC_TEST1(__VA_ARGS__)
-#define __SC_TEST3(t3, a3, ...) __SC_TEST(t3); __SC_TEST2(__VA_ARGS__)
-#define __SC_TEST4(t4, a4, ...) __SC_TEST(t4); __SC_TEST3(__VA_ARGS__)
-#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__)
-#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
+/*
+ * __MAP - apply a macro to syscall arguments
+ * __MAP(n, m, t1, a1, t2, a2, ..., tn, an) will expand to
+ * m(t1, a1), m(t2, a2), ..., m(tn, an)
+ * The first argument must be equal to the amount of type/name
+ * pairs given. Note that this list of pairs (i.e. the arguments
+ * of __MAP starting at the third one) is in the same format as
+ * for SYSCALL_DEFINE<n>/COMPAT_SYSCALL_DEFINE<n>
+ */
+#define __MAP0(m,...)
+#define __MAP1(m,t,a) m(t,a)
+#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
+#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
+#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
+#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
+#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
+#define __MAP(n,...) __MAP##n(__VA_ARGS__)
+
+#define __SC_DECL(t, a) t a
+#define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))
+#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
+#define __SC_CAST(t, a) (t) a
+#define __SC_ARGS(t, a) a
+#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
#ifdef CONFIG_FTRACE_SYSCALLS
-#define __SC_STR_ADECL1(t, a) #a
-#define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__)
-#define __SC_STR_ADECL3(t, a, ...) #a, __SC_STR_ADECL2(__VA_ARGS__)
-#define __SC_STR_ADECL4(t, a, ...) #a, __SC_STR_ADECL3(__VA_ARGS__)
-#define __SC_STR_ADECL5(t, a, ...) #a, __SC_STR_ADECL4(__VA_ARGS__)
-#define __SC_STR_ADECL6(t, a, ...) #a, __SC_STR_ADECL5(__VA_ARGS__)
-
-#define __SC_STR_TDECL1(t, a) #t
-#define __SC_STR_TDECL2(t, a, ...) #t, __SC_STR_TDECL1(__VA_ARGS__)
-#define __SC_STR_TDECL3(t, a, ...) #t, __SC_STR_TDECL2(__VA_ARGS__)
-#define __SC_STR_TDECL4(t, a, ...) #t, __SC_STR_TDECL3(__VA_ARGS__)
-#define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__)
-#define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__)
+#define __SC_STR_ADECL(t, a) #a
+#define __SC_STR_TDECL(t, a) #t
extern struct ftrace_event_class event_class_syscall_enter;
extern struct ftrace_event_class event_class_syscall_exit;
@@ -155,7 +140,13 @@ extern struct trace_event_functions exit_syscall_print_funcs;
__attribute__((section("_ftrace_events"))) \
*__event_exit_##sname = &event_exit_##sname;
-#define SYSCALL_METADATA(sname, nb) \
+#define SYSCALL_METADATA(sname, nb, ...) \
+ static const char *types_##sname[] = { \
+ __MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \
+ }; \
+ static const char *args_##sname[] = { \
+ __MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \
+ }; \
SYSCALL_TRACE_ENTER_EVENT(sname); \
SYSCALL_TRACE_EXIT_EVENT(sname); \
static struct syscall_metadata __used \
@@ -163,8 +154,8 @@ extern struct trace_event_functions exit_syscall_print_funcs;
.name = "sys"#sname, \
.syscall_nr = -1, /* Filled in at boot */ \
.nb_args = nb, \
- .types = types_##sname, \
- .args = args_##sname, \
+ .types = nb ? types_##sname : NULL, \
+ .args = nb ? args_##sname : NULL, \
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
@@ -172,26 +163,13 @@ extern struct trace_event_functions exit_syscall_print_funcs;
static struct syscall_metadata __used \
__attribute__((section("__syscalls_metadata"))) \
*__p_syscall_meta_##sname = &__syscall_meta_##sname;
+#else
+#define SYSCALL_METADATA(sname, nb, ...)
+#endif
#define SYSCALL_DEFINE0(sname) \
- SYSCALL_TRACE_ENTER_EVENT(_##sname); \
- SYSCALL_TRACE_EXIT_EVENT(_##sname); \
- static struct syscall_metadata __used \
- __syscall_meta__##sname = { \
- .name = "sys_"#sname, \
- .syscall_nr = -1, /* Filled in at boot */ \
- .nb_args = 0, \
- .enter_event = &event_enter__##sname, \
- .exit_event = &event_exit__##sname, \
- .enter_fields = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \
- }; \
- static struct syscall_metadata __used \
- __attribute__((section("__syscalls_metadata"))) \
- *__p_syscall_meta_##sname = &__syscall_meta__##sname; \
+ SYSCALL_METADATA(_##sname, 0); \
asmlinkage long sys_##sname(void)
-#else
-#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(void)
-#endif
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
@@ -200,57 +178,23 @@ extern struct trace_event_functions exit_syscall_print_funcs;
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
-#ifdef CONFIG_PPC64
-#define SYSCALL_ALIAS(alias, name) \
- asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \
- "\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
-#else
-#if defined(CONFIG_ALPHA) || defined(CONFIG_MIPS)
-#define SYSCALL_ALIAS(alias, name) \
- asm ( #alias " = " #name "\n\t.globl " #alias)
-#else
-#define SYSCALL_ALIAS(alias, name) \
- asm ("\t.globl " #alias "\n\t.set " #alias ", " #name)
-#endif
-#endif
-
-#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...) \
- static const char *types_##sname[] = { \
- __SC_STR_TDECL##x(__VA_ARGS__) \
- }; \
- static const char *args_##sname[] = { \
- __SC_STR_ADECL##x(__VA_ARGS__) \
- }; \
- SYSCALL_METADATA(sname, x); \
+ SYSCALL_METADATA(sname, x, __VA_ARGS__) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
-#else
-#define SYSCALL_DEFINEx(x, sname, ...) \
- __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
-#endif
-
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-
-#define SYSCALL_DEFINE(name) static inline long SYSC_##name
+#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...) \
- asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
- static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
- asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
+ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
+ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
+ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
- __SC_TEST##x(__VA_ARGS__); \
- return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \
+ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
+ __MAP(x,__SC_TEST,__VA_ARGS__); \
+ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
+ return ret; \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
- static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))
-
-#else /* CONFIG_HAVE_SYSCALL_WRAPPERS */
-
-#define SYSCALL_DEFINE(name) asmlinkage long sys_##name
-#define __SYSCALL_DEFINEx(x, name, ...) \
- asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
-
-#endif /* CONFIG_HAVE_SYSCALL_WRAPPERS */
+ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
asmlinkage long sys_time(time_t __user *tloc);
asmlinkage long sys_stime(time_t __user *tptr);
@@ -694,7 +638,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf);
asmlinkage long sys_semget(key_t key, int nsems, int semflg);
asmlinkage long sys_semop(int semid, struct sembuf __user *sops,
unsigned nsops);
-asmlinkage long sys_semctl(int semid, int semnum, int cmd, union semun arg);
+asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg);
asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
unsigned nsops,
const struct timespec __user *timeout);
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index f28408c07dc2..5adbc33d1ab3 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -90,9 +90,6 @@ struct tcp_options_received {
sack_ok : 4, /* SACK seen on SYN packet */
snd_wscale : 4, /* Window scaling received from sender */
rcv_wscale : 4; /* Window scaling to send to receiver */
- u8 cookie_plus:6, /* bytes in authenticator/cookie option */
- cookie_out_never:1,
- cookie_in_always:1;
u8 num_sacks; /* Number of SACK blocks */
u16 user_mss; /* mss requested by user in ioctl */
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
@@ -102,7 +99,6 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
{
rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
- rx_opt->cookie_plus = 0;
}
/* This is the max number of SACKS that we'll generate and process. It's safe
@@ -191,20 +187,19 @@ struct tcp_sock {
u32 window_clamp; /* Maximal window to advertise */
u32 rcv_ssthresh; /* Current window clamp */
- u32 frto_highmark; /* snd_nxt when RTO occurred */
u16 advmss; /* Advertised MSS */
- u8 frto_counter; /* Number of new acks after RTO */
+ u8 unused;
u8 nonagle : 4,/* Disable Nagle algorithm? */
thin_lto : 1,/* Use linear timeouts for thin streams */
thin_dupack : 1,/* Fast retransmit on first dupack */
repair : 1,
- unused : 1;
+ frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */
u8 repair_queue;
u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */
- early_retrans_delayed:1, /* Delayed ER timer installed */
syn_data:1, /* SYN includes data */
syn_fastopen:1, /* SYN includes Fast Open option */
syn_data_acked:1;/* data in SYN is acked by SYN-ACK */
+ u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
@@ -320,12 +315,6 @@ struct tcp_sock {
struct tcp_md5sig_info __rcu *md5sig_info;
#endif
- /* When the cookie options are generated and exchanged, then this
- * object holds a reference to them (cookie_values->kref). Also
- * contains related tcp_cookie_transactions fields.
- */
- struct tcp_cookie_values *cookie_values;
-
/* TCP fastopen related information */
struct tcp_fastopen_request *fastopen_req;
/* fastopen_rsk points to request_sock that resulted in this big
@@ -361,10 +350,6 @@ struct tcp_timewait_sock {
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *tw_md5_key;
#endif
- /* Few sockets in timewait have cookies; in that case, then this
- * object holds a reference to them (tw_cookie_values->kref).
- */
- struct tcp_cookie_values *tw_cookie_values;
};
static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk)
diff --git a/include/linux/time.h b/include/linux/time.h
index d4835dfdf25e..22d81b3c955b 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -181,6 +181,9 @@ extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
extern u64 timekeeping_max_deferment(void);
extern int timekeeping_inject_offset(struct timespec *ts);
+extern s32 timekeeping_get_tai_offset(void);
+extern void timekeeping_set_tai_offset(s32 tai_offset);
+extern void timekeeping_clocktai(struct timespec *ts);
struct tms;
extern void do_sys_times(struct tms *);
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index e1d558e237ec..c1825eb436ed 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -20,6 +20,8 @@ struct timekeeper {
u32 shift;
/* Number of clock cycles in one NTP interval. */
cycle_t cycle_interval;
+ /* Last cycle value (also stored in clock->cycle_last) */
+ cycle_t cycle_last;
/* Number of clock shifted nano seconds in one NTP interval. */
u64 xtime_interval;
/* shifted nano seconds left over when rounding cycle_interval */
@@ -62,8 +64,11 @@ struct timekeeper {
ktime_t offs_boot;
/* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
struct timespec raw_time;
- /* Seqlock for all timekeeper values */
- seqlock_t lock;
+ /* The current UTC to TAI offset in seconds */
+ s32 tai_offset;
+ /* Offset clock monotonic -> clock tai */
+ ktime_t offs_tai;
+
};
static inline struct timespec tk_xtime(struct timekeeper *tk)
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 5ec87c60b97c..b3726e61368e 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -125,9 +125,6 @@
extern unsigned long tick_usec; /* USER_HZ period (usec) */
extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */
-extern void ntp_init(void);
-extern void ntp_clear(void);
-
/* Required to safely shift negative values */
#define shift_right(x, s) ({ \
__typeof__(x) __x = (x); \
@@ -140,10 +137,6 @@ extern void ntp_clear(void);
#define NTP_INTERVAL_FREQ (HZ)
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
-/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
-extern u64 ntp_tick_length(void);
-
-extern int second_overflow(unsigned long secs);
extern int do_adjtimex(struct timex *);
extern void hardpps(const struct timespec *, const struct timespec *);
diff --git a/include/linux/trace_clock.h b/include/linux/trace_clock.h
index d563f37e1a1d..1d7ca2739272 100644
--- a/include/linux/trace_clock.h
+++ b/include/linux/trace_clock.h
@@ -16,6 +16,7 @@
extern u64 notrace trace_clock_local(void);
extern u64 notrace trace_clock(void);
+extern u64 notrace trace_clock_jiffies(void);
extern u64 notrace trace_clock_global(void);
extern u64 notrace trace_clock_counter(void);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index e014fb1a84bd..7e92bd86a808 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -255,9 +255,9 @@ struct tty_struct {
int count;
struct winsize winsize; /* termios mutex */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
- unsigned char warned:1;
unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */
+ int flow_change;
struct tty_struct *link;
struct fasync_struct *fasync;
@@ -315,9 +315,25 @@ struct tty_file_private {
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */
#define TTY_HUPPING 21 /* ->hangup() in progress */
+#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty))
+/* Values for tty->flow_change */
+#define TTY_THROTTLE_SAFE 1
+#define TTY_UNTHROTTLE_SAFE 2
+
+static inline void __tty_set_flow_change(struct tty_struct *tty, int val)
+{
+ tty->flow_change = val;
+}
+
+static inline void tty_set_flow_change(struct tty_struct *tty, int val)
+{
+ tty->flow_change = val;
+ smp_mb();
+}
+
#ifdef CONFIG_TTY
extern void console_init(void);
extern void tty_kref_put(struct tty_struct *tty);
@@ -400,6 +416,8 @@ extern int tty_write_room(struct tty_struct *tty);
extern void tty_driver_flush_buffer(struct tty_struct *tty);
extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
+extern int tty_throttle_safe(struct tty_struct *tty);
+extern int tty_unthrottle_safe(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
extern void tty_driver_remove_tty(struct tty_driver *driver,
struct tty_struct *tty);
@@ -419,13 +437,28 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);
extern void tty_buffer_free_all(struct tty_port *port);
extern void tty_buffer_flush(struct tty_struct *tty);
extern void tty_buffer_init(struct tty_port *port);
-extern speed_t tty_get_baud_rate(struct tty_struct *tty);
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
extern void tty_termios_encode_baud_rate(struct ktermios *termios,
speed_t ibaud, speed_t obaud);
extern void tty_encode_baud_rate(struct tty_struct *tty,
speed_t ibaud, speed_t obaud);
+
+/**
+ * tty_get_baud_rate - get tty bit rates
+ * @tty: tty to query
+ *
+ * Returns the baud rate as an integer for this terminal. The
+ * termios lock must be held by the caller and the terminal bit
+ * flags may be updated.
+ *
+ * Locking: none
+ */
+static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+ return tty_termios_baud_rate(&tty->termios);
+}
+
extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old);
extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt);
@@ -502,6 +535,8 @@ extern int tty_port_carrier_raised(struct tty_port *port);
extern void tty_port_raise_dtr_rts(struct tty_port *port);
extern void tty_port_lower_dtr_rts(struct tty_port *port);
extern void tty_port_hangup(struct tty_port *port);
+extern void tty_port_tty_hangup(struct tty_port *port, bool check_clocal);
+extern void tty_port_tty_wakeup(struct tty_port *port);
extern int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp);
extern int tty_port_close_start(struct tty_port *port,
@@ -526,8 +561,6 @@ extern void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty);
extern void tty_ldisc_init(struct tty_struct *tty);
extern void tty_ldisc_deinit(struct tty_struct *tty);
extern void tty_ldisc_begin(void);
-/* This last one is just for the tty layer internals and shouldn't be used elsewhere */
-extern void tty_ldisc_enable(struct tty_struct *tty);
/* n_tty.c */
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 455a0d7bf220..58390c73df8b 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -9,89 +9,89 @@
*
* int (*open)(struct tty_struct *);
*
- * This function is called when the line discipline is associated
- * with the tty. The line discipline can use this as an
- * opportunity to initialize any state needed by the ldisc routines.
- *
+ * This function is called when the line discipline is associated
+ * with the tty. The line discipline can use this as an
+ * opportunity to initialize any state needed by the ldisc routines.
+ *
* void (*close)(struct tty_struct *);
*
* This function is called when the line discipline is being
- * shutdown, either because the tty is being closed or because
- * the tty is being changed to use a new line discipline
- *
+ * shutdown, either because the tty is being closed or because
+ * the tty is being changed to use a new line discipline
+ *
* void (*flush_buffer)(struct tty_struct *tty);
*
- * This function instructs the line discipline to clear its
- * buffers of any input characters it may have queued to be
- * delivered to the user mode process.
- *
+ * This function instructs the line discipline to clear its
+ * buffers of any input characters it may have queued to be
+ * delivered to the user mode process.
+ *
* ssize_t (*chars_in_buffer)(struct tty_struct *tty);
*
- * This function returns the number of input characters the line
+ * This function returns the number of input characters the line
* discipline may have queued up to be delivered to the user mode
* process.
- *
+ *
* ssize_t (*read)(struct tty_struct * tty, struct file * file,
* unsigned char * buf, size_t nr);
*
- * This function is called when the user requests to read from
- * the tty. The line discipline will return whatever characters
- * it has buffered up for the user. If this function is not
- * defined, the user will receive an EIO error.
- *
+ * This function is called when the user requests to read from
+ * the tty. The line discipline will return whatever characters
+ * it has buffered up for the user. If this function is not
+ * defined, the user will receive an EIO error.
+ *
* ssize_t (*write)(struct tty_struct * tty, struct file * file,
- * const unsigned char * buf, size_t nr);
- *
- * This function is called when the user requests to write to the
- * tty. The line discipline will deliver the characters to the
- * low-level tty device for transmission, optionally performing
- * some processing on the characters first. If this function is
- * not defined, the user will receive an EIO error.
- *
+ * const unsigned char * buf, size_t nr);
+ *
+ * This function is called when the user requests to write to the
+ * tty. The line discipline will deliver the characters to the
+ * low-level tty device for transmission, optionally performing
+ * some processing on the characters first. If this function is
+ * not defined, the user will receive an EIO error.
+ *
* int (*ioctl)(struct tty_struct * tty, struct file * file,
- * unsigned int cmd, unsigned long arg);
+ * unsigned int cmd, unsigned long arg);
*
* This function is called when the user requests an ioctl which
- * is not handled by the tty layer or the low-level tty driver.
- * It is intended for ioctls which affect line discpline
- * operation. Note that the search order for ioctls is (1) tty
- * layer, (2) tty low-level driver, (3) line discpline. So a
- * low-level driver can "grab" an ioctl request before the line
- * discpline has a chance to see it.
- *
+ * is not handled by the tty layer or the low-level tty driver.
+ * It is intended for ioctls which affect line discpline
+ * operation. Note that the search order for ioctls is (1) tty
+ * layer, (2) tty low-level driver, (3) line discpline. So a
+ * low-level driver can "grab" an ioctl request before the line
+ * discpline has a chance to see it.
+ *
* long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
- * unsigned int cmd, unsigned long arg);
+ * unsigned int cmd, unsigned long arg);
*
- * Process ioctl calls from 32-bit process on 64-bit system
+ * Process ioctl calls from 32-bit process on 64-bit system
*
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
- * This function notifies the line discpline that a change has
- * been made to the termios structure.
- *
+ * This function notifies the line discpline that a change has
+ * been made to the termios structure.
+ *
* int (*poll)(struct tty_struct * tty, struct file * file,
- * poll_table *wait);
+ * poll_table *wait);
*
- * This function is called when a user attempts to select/poll on a
- * tty device. It is solely the responsibility of the line
- * discipline to handle poll requests.
+ * This function is called when a user attempts to select/poll on a
+ * tty device. It is solely the responsibility of the line
+ * discipline to handle poll requests.
*
* void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
- * char *fp, int count);
- *
- * This function is called by the low-level tty driver to send
- * characters received by the hardware to the line discpline for
- * processing. <cp> is a pointer to the buffer of input
- * character received by the device. <fp> is a pointer to a
- * pointer of flag bytes which indicate whether a character was
- * received with a parity error, etc.
- *
+ * char *fp, int count);
+ *
+ * This function is called by the low-level tty driver to send
+ * characters received by the hardware to the line discpline for
+ * processing. <cp> is a pointer to the buffer of input
+ * character received by the device. <fp> is a pointer to a
+ * pointer of flag bytes which indicate whether a character was
+ * received with a parity error, etc.
+ *
* void (*write_wakeup)(struct tty_struct *);
*
- * This function is called by the low-level tty driver to signal
- * that line discpline should try to send more characters to the
- * low-level driver for transmission. If the line discpline does
- * not have any more data to send, it can just return.
+ * This function is called by the low-level tty driver to signal
+ * that line discpline should try to send more characters to the
+ * low-level driver for transmission. If the line discpline does
+ * not have any more data to send, it can just return.
*
* int (*hangup)(struct tty_struct *)
*
@@ -115,7 +115,7 @@ struct tty_ldisc_ops {
char *name;
int num;
int flags;
-
+
/*
* The following routines are called from above.
*/
@@ -123,19 +123,19 @@ struct tty_ldisc_ops {
void (*close)(struct tty_struct *);
void (*flush_buffer)(struct tty_struct *tty);
ssize_t (*chars_in_buffer)(struct tty_struct *tty);
- ssize_t (*read)(struct tty_struct * tty, struct file * file,
- unsigned char __user * buf, size_t nr);
- ssize_t (*write)(struct tty_struct * tty, struct file * file,
- const unsigned char * buf, size_t nr);
- int (*ioctl)(struct tty_struct * tty, struct file * file,
+ ssize_t (*read)(struct tty_struct *tty, struct file *file,
+ unsigned char __user *buf, size_t nr);
+ ssize_t (*write)(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr);
+ int (*ioctl)(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
- long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
+ long (*compat_ioctl)(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
+ void (*set_termios)(struct tty_struct *tty, struct ktermios *old);
unsigned int (*poll)(struct tty_struct *, struct file *,
struct poll_table_struct *);
int (*hangup)(struct tty_struct *tty);
-
+
/*
* The following routines are called from below.
*/
@@ -145,7 +145,7 @@ struct tty_ldisc_ops {
void (*dcd_change)(struct tty_struct *, unsigned int);
struct module *owner;
-
+
int refcount;
};
diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h
new file mode 100644
index 000000000000..cbb20afdbc01
--- /dev/null
+++ b/include/linux/ucs2_string.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_UCS2_STRING_H_
+#define _LINUX_UCS2_STRING_H_
+
+#include <linux/types.h> /* for size_t */
+#include <linux/stddef.h> /* for NULL */
+
+typedef u16 ucs2_char_t;
+
+unsigned long ucs2_strnlen(const ucs2_char_t *s, size_t maxlength);
+unsigned long ucs2_strlen(const ucs2_char_t *s);
+unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
+int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
+
+#endif /* _LINUX_UCS2_STRING_H_ */
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 02b83db8e2c5..06f28beed7c2 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -38,6 +38,8 @@ struct inode;
#define UPROBE_HANDLER_REMOVE 1
#define UPROBE_HANDLER_MASK 1
+#define MAX_URETPROBE_DEPTH 64
+
enum uprobe_filter_ctx {
UPROBE_FILTER_REGISTER,
UPROBE_FILTER_UNREGISTER,
@@ -46,6 +48,9 @@ enum uprobe_filter_ctx {
struct uprobe_consumer {
int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
+ int (*ret_handler)(struct uprobe_consumer *self,
+ unsigned long func,
+ struct pt_regs *regs);
bool (*filter)(struct uprobe_consumer *self,
enum uprobe_filter_ctx ctx,
struct mm_struct *mm);
@@ -68,6 +73,8 @@ struct uprobe_task {
enum uprobe_task_state state;
struct arch_uprobe_task autask;
+ struct return_instance *return_instances;
+ unsigned int depth;
struct uprobe *active_uprobe;
unsigned long xol_vaddr;
@@ -100,6 +107,7 @@ struct uprobes_state {
extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
+extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 4d22d0f6167a..a0bee5a28d1a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -469,14 +469,12 @@ struct usb3_lpm_parameters {
* @lpm_capable: device supports LPM
* @usb2_hw_lpm_capable: device can perform USB2 hardware LPM
* @usb2_hw_lpm_enabled: USB2 hardware LPM enabled
+ * @usb3_lpm_enabled: USB3 hardware LPM enabled
* @string_langid: language ID for strings
* @product: iProduct string, if present (static)
* @manufacturer: iManufacturer string, if present (static)
* @serial: iSerialNumber string, if present (static)
* @filelist: usbfs files that are open to this device
- * @usb_classdev: USB class device that was created for usbfs device
- * access from userspace
- * @usbfs_dentry: usbfs dentry entry for the device
* @maxchild: number of ports if hub
* @quirks: quirks of the whole device
* @urbnum: number of URBs submitted for the whole device
@@ -619,7 +617,7 @@ static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
#endif
/* USB autosuspend and autoresume */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
extern void usb_enable_autosuspend(struct usb_device *udev);
extern void usb_disable_autosuspend(struct usb_device *udev);
@@ -978,7 +976,12 @@ struct usbdrv_wrap {
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
* do (or don't) show up otherwise in the filesystem.
- * @suspend: Called when the device is going to be suspended by the system.
+ * @suspend: Called when the device is going to be suspended by the
+ * system either from system sleep or runtime suspend context. The
+ * return value will be ignored in system sleep context, so do NOT
+ * try to continue using the device if suspend fails in this case.
+ * Instead, let the resume or reset-resume routine recover from
+ * the failure.
* @resume: Called when the device is being resumed by the system.
* @reset_resume: Called when the suspended device has been reset instead
* of being resumed.
diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h
index 719c332620fa..0b3f4295c025 100644
--- a/include/linux/usb/cdc-wdm.h
+++ b/include/linux/usb/cdc-wdm.h
@@ -11,6 +11,8 @@
#ifndef __LINUX_USB_CDC_WDM_H
#define __LINUX_USB_CDC_WDM_H
+#include <uapi/linux/usb/cdc-wdm.h>
+
extern struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep,
int bufsize,
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 9c210f2283df..27603bcbb9b9 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -43,4 +43,13 @@
*/
extern const char *usb_speed_string(enum usb_device_speed speed);
+
+/**
+ * usb_state_string - Returns human readable name for the state.
+ * @state: The state to return a human-readable name for. If it's not
+ * any of the states devices in usb_device_state_string enum,
+ * the string UNKNOWN will be returned.
+ */
+extern const char *usb_state_string(enum usb_device_state state);
+
#endif /* __LINUX_USB_CH9_H */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 8860594d6364..5e61589fc166 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -39,6 +39,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/log2.h>
+#include <linux/configfs.h>
/*
* USB function drivers should return USB_GADGET_DELAYED_STATUS if they
@@ -464,6 +465,8 @@ struct usb_function_driver {
};
struct usb_function_instance {
+ struct config_group group;
+ struct list_head cfs_list;
struct usb_function_driver *fd;
void (*free_func_inst)(struct usb_function_instance *inst);
};
diff --git a/include/linux/usb/dwc3-omap.h b/include/linux/usb/dwc3-omap.h
index 51eae14477f7..5615f4d82724 100644
--- a/include/linux/usb/dwc3-omap.h
+++ b/include/linux/usb/dwc3-omap.h
@@ -19,11 +19,11 @@ enum omap_dwc3_vbus_id_status {
};
#if (defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_DWC3_MODULE))
-extern void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
+extern int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status);
#else
-static inline void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
+static inline int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status)
{
- return;
+ return -ENODEV;
}
#endif
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 2e297e80d59a..c454a88abf2e 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -482,6 +482,7 @@ struct usb_gadget_ops {
* @speed: Speed of current connection to USB host.
* @max_speed: Maximal speed the UDC can handle. UDC must support this
* and all slower speeds.
+ * @state: the state we are now (attached, suspended, configured, etc)
* @sg_supported: true if we can handle scatter-gather
* @is_otg: True if the USB device port uses a Mini-AB jack, so that the
* gadget driver must provide a USB OTG descriptor.
@@ -525,6 +526,7 @@ struct usb_gadget {
struct list_head ep_list; /* of usb_ep */
enum usb_device_speed speed;
enum usb_device_speed max_speed;
+ enum usb_device_state state;
unsigned sg_supported:1;
unsigned is_otg:1;
unsigned is_a_peripheral:1;
@@ -872,6 +874,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver);
*/
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
+extern int usb_add_gadget_udc_release(struct device *parent,
+ struct usb_gadget *gadget, void (*release)(struct device *dev));
extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
extern void usb_del_gadget_udc(struct usb_gadget *gadget);
extern int udc_attach_driver(const char *name,
@@ -959,6 +963,13 @@ extern void usb_gadget_unmap_request(struct usb_gadget *gadget,
/*-------------------------------------------------------------------------*/
+/* utility to set gadget state properly */
+
+extern void usb_gadget_set_state(struct usb_gadget *gadget,
+ enum usb_device_state state);
+
+/*-------------------------------------------------------------------------*/
+
/* utility wrapping a simple endpoint selection policy */
extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
diff --git a/include/linux/usb/gadget_configfs.h b/include/linux/usb/gadget_configfs.h
new file mode 100644
index 000000000000..d74c0ae989d5
--- /dev/null
+++ b/include/linux/usb/gadget_configfs.h
@@ -0,0 +1,110 @@
+#ifndef __GADGET_CONFIGFS__
+#define __GADGET_CONFIGFS__
+
+#include <linux/configfs.h>
+
+int check_user_usb_string(const char *name,
+ struct usb_gadget_strings *stringtab_dev);
+
+#define GS_STRINGS_W(__struct, __name) \
+ static ssize_t __struct##_##__name##_store(struct __struct *gs, \
+ const char *page, size_t len) \
+{ \
+ int ret; \
+ \
+ ret = usb_string_copy(page, &gs->__name); \
+ if (ret) \
+ return ret; \
+ return len; \
+}
+
+#define GS_STRINGS_R(__struct, __name) \
+ static ssize_t __struct##_##__name##_show(struct __struct *gs, \
+ char *page) \
+{ \
+ return sprintf(page, "%s\n", gs->__name ?: ""); \
+}
+
+#define GS_STRING_ITEM_ATTR(struct_name, name) \
+ static struct struct_name##_attribute struct_name##_##name = \
+ __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
+ struct_name##_##name##_show, \
+ struct_name##_##name##_store)
+
+#define GS_STRINGS_RW(struct_name, _name) \
+ GS_STRINGS_R(struct_name, _name) \
+ GS_STRINGS_W(struct_name, _name) \
+ GS_STRING_ITEM_ATTR(struct_name, _name)
+
+#define USB_CONFIG_STRING_RW_OPS(struct_in) \
+ CONFIGFS_ATTR_OPS(struct_in); \
+ \
+static struct configfs_item_operations struct_in##_langid_item_ops = { \
+ .release = struct_in##_attr_release, \
+ .show_attribute = struct_in##_attr_show, \
+ .store_attribute = struct_in##_attr_store, \
+}; \
+ \
+static struct config_item_type struct_in##_langid_type = { \
+ .ct_item_ops = &struct_in##_langid_item_ops, \
+ .ct_attrs = struct_in##_langid_attrs, \
+ .ct_owner = THIS_MODULE, \
+}
+
+#define USB_CONFIG_STRINGS_LANG(struct_in, struct_member) \
+ static struct config_group *struct_in##_strings_make( \
+ struct config_group *group, \
+ const char *name) \
+ { \
+ struct struct_member *gi; \
+ struct struct_in *gs; \
+ struct struct_in *new; \
+ int langs = 0; \
+ int ret; \
+ \
+ new = kzalloc(sizeof(*new), GFP_KERNEL); \
+ if (!new) \
+ return ERR_PTR(-ENOMEM); \
+ \
+ ret = check_user_usb_string(name, &new->stringtab_dev); \
+ if (ret) \
+ goto err; \
+ config_group_init_type_name(&new->group, name, \
+ &struct_in##_langid_type); \
+ \
+ gi = container_of(group, struct struct_member, strings_group); \
+ ret = -EEXIST; \
+ list_for_each_entry(gs, &gi->string_list, list) { \
+ if (gs->stringtab_dev.language == new->stringtab_dev.language) \
+ goto err; \
+ langs++; \
+ } \
+ ret = -EOVERFLOW; \
+ if (langs >= MAX_USB_STRING_LANGS) \
+ goto err; \
+ \
+ list_add_tail(&new->list, &gi->string_list); \
+ return &new->group; \
+err: \
+ kfree(new); \
+ return ERR_PTR(ret); \
+} \
+ \
+static void struct_in##_strings_drop( \
+ struct config_group *group, \
+ struct config_item *item) \
+{ \
+ config_item_put(item); \
+} \
+ \
+static struct configfs_group_operations struct_in##_strings_ops = { \
+ .make_group = &struct_in##_strings_make, \
+ .drop_item = &struct_in##_strings_drop, \
+}; \
+ \
+static struct config_item_type struct_in##_strings_type = { \
+ .ct_group_ops = &struct_in##_strings_ops, \
+ .ct_owner = THIS_MODULE, \
+}
+
+#endif
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 0a78df5f6cfd..f5f5c7dfda90 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -84,7 +84,7 @@ struct usb_hcd {
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
struct work_struct wakeup_work; /* for remote wakeup */
#endif
@@ -357,6 +357,7 @@ struct hc_driver {
*/
int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
struct usb_device *, enum usb3_link_state state);
+ int (*find_raw_port_number)(struct usb_hcd *, int);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
+extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
struct platform_device;
extern void usb_hcd_platform_shutdown(struct platform_device *dev);
@@ -591,14 +593,14 @@ extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
#endif /* CONFIG_PM */
-#ifdef CONFIG_USB_SUSPEND
+#ifdef CONFIG_PM_RUNTIME
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
-#endif /* CONFIG_USB_SUSPEND */
+#endif /* CONFIG_PM_RUNTIME */
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/usb/musb-ux500.h b/include/linux/usb/musb-ux500.h
new file mode 100644
index 000000000000..1e2c7130f6e1
--- /dev/null
+++ b/include/linux/usb/musb-ux500.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 ST-Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MUSB_UX500_H__
+#define __MUSB_UX500_H__
+
+enum ux500_musb_vbus_id_status {
+ UX500_MUSB_NONE = 0,
+ UX500_MUSB_VBUS,
+ UX500_MUSB_ID,
+ UX500_MUSB_CHARGER,
+ UX500_MUSB_ENUMERATED,
+ UX500_MUSB_RIDA,
+ UX500_MUSB_RIDB,
+ UX500_MUSB_RIDC,
+ UX500_MUSB_PREPARE,
+ UX500_MUSB_CLEAN,
+};
+
+#endif /* __MUSB_UX500_H__ */
diff --git a/include/linux/usb/nop-usb-xceiv.h b/include/linux/usb/nop-usb-xceiv.h
index 28884c717411..148d35171aac 100644
--- a/include/linux/usb/nop-usb-xceiv.h
+++ b/include/linux/usb/nop-usb-xceiv.h
@@ -5,6 +5,11 @@
struct nop_usb_xceiv_platform_data {
enum usb_phy_type type;
+ unsigned long clk_rate;
+
+ /* if set fails with -EPROBE_DEFER if can't get regulator */
+ unsigned int needs_vcc:1;
+ unsigned int needs_reset:1;
};
#if defined(CONFIG_NOP_USB_XCEIV) || (defined(CONFIG_NOP_USB_XCEIV_MODULE) && defined(MODULE))
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index e8a5fe87c6bd..291e01ba32e5 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -36,14 +36,7 @@ struct usb_otg {
};
-#ifdef CONFIG_USB_OTG_UTILS
-extern const char *otg_state_string(enum usb_otg_state state);
-#else
-static inline const char *otg_state_string(enum usb_otg_state state)
-{
- return NULL;
-}
-#endif
+extern const char *usb_otg_state_string(enum usb_otg_state state);
/* Context: can sleep */
static inline int
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 15847cbdb512..6b5978f57633 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -91,6 +91,9 @@ struct usb_phy {
int (*init)(struct usb_phy *x);
void (*shutdown)(struct usb_phy *x);
+ /* enable/disable VBUS */
+ int (*set_vbus)(struct usb_phy *x, int on);
+
/* effective for B devices, ignored for A-peripheral */
int (*set_power)(struct usb_phy *x,
unsigned mA);
@@ -160,8 +163,26 @@ usb_phy_shutdown(struct usb_phy *x)
x->shutdown(x);
}
+static inline int
+usb_phy_vbus_on(struct usb_phy *x)
+{
+ if (!x->set_vbus)
+ return 0;
+
+ return x->set_vbus(x, true);
+}
+
+static inline int
+usb_phy_vbus_off(struct usb_phy *x)
+{
+ if (!x->set_vbus)
+ return 0;
+
+ return x->set_vbus(x, false);
+}
+
/* for usb host and peripheral controller drivers */
-#ifdef CONFIG_USB_OTG_UTILS
+#if IS_ENABLED(CONFIG_USB_PHY)
extern struct usb_phy *usb_get_phy(enum usb_phy_type type);
extern struct usb_phy *devm_usb_get_phy(struct device *dev,
enum usb_phy_type type);
@@ -176,29 +197,29 @@ extern int usb_bind_phy(const char *dev_name, u8 index,
#else
static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)
{
- return NULL;
+ return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *devm_usb_get_phy(struct device *dev,
enum usb_phy_type type)
{
- return NULL;
+ return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
{
- return NULL;
+ return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index)
{
- return NULL;
+ return ERR_PTR(-ENXIO);
}
static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
const char *phandle, u8 index)
{
- return NULL;
+ return ERR_PTR(-ENXIO);
}
static inline void usb_put_phy(struct usb_phy *x)
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index c5d36c65c33b..e452ba6ec6bd 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -62,14 +62,14 @@ struct renesas_usbhs_platform_callback {
* Hardware exit function for platform.
* it is called when driver was removed
*/
- void (*hardware_exit)(struct platform_device *pdev);
+ int (*hardware_exit)(struct platform_device *pdev);
/*
* option:
*
* for board specific clock control
*/
- void (*power_ctrl)(struct platform_device *pdev,
+ int (*power_ctrl)(struct platform_device *pdev,
void __iomem *base, int enable);
/*
@@ -77,7 +77,7 @@ struct renesas_usbhs_platform_callback {
*
* Phy reset for platform
*/
- void (*phy_reset)(struct platform_device *pdev);
+ int (*phy_reset)(struct platform_device *pdev);
/*
* get USB ID function
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 1819b59aab2a..b9b0f7b4e43b 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -15,6 +15,7 @@
#include <linux/kref.h>
#include <linux/mutex.h>
+#include <linux/serial.h>
#include <linux/sysrq.h>
#include <linux/kfifo.h>
@@ -61,12 +62,12 @@
* @bulk_out_buffers: pointers to the bulk out buffers for this port
* @write_urbs: pointers to the bulk out urbs for this port
* @write_urbs_free: status bitmap the for bulk out urbs
+ * @icount: interrupt counters
* @tx_bytes: number of bytes currently in host stack queues
* @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
* port.
* @flags: usb serial port flags
* @write_wait: a wait_queue_head_t used by the port.
- * @delta_msr_wait: modem-status-change wait queue
* @work: work queue entry for the line discipline waking up.
* @throttled: nonzero if the read urb is inactive to throttle the device
* @throttle_req: nonzero if the tty wants to throttle us
@@ -109,11 +110,11 @@ struct usb_serial_port {
unsigned long write_urbs_free;
__u8 bulk_out_endpointAddress;
+ struct async_icount icount;
int tx_bytes;
unsigned long flags;
wait_queue_head_t write_wait;
- wait_queue_head_t delta_msr_wait;
struct work_struct work;
char throttled;
char throttle_req;
@@ -272,6 +273,7 @@ struct usb_serial_driver {
int (*tiocmget)(struct tty_struct *tty);
int (*tiocmset)(struct tty_struct *tty,
unsigned int set, unsigned int clear);
+ int (*tiocmiwait)(struct tty_struct *tty, unsigned long arg);
int (*get_icount)(struct tty_struct *tty,
struct serial_icounter_struct *icount);
/* Called by the tty layer for port level work. There may or may not
@@ -329,8 +331,10 @@ extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
extern void usb_serial_generic_throttle(struct tty_struct *tty);
extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
-extern void usb_serial_generic_disconnect(struct usb_serial *serial);
-extern void usb_serial_generic_release(struct usb_serial *serial);
+extern int usb_serial_generic_tiocmiwait(struct tty_struct *tty,
+ unsigned long arg);
+extern int usb_serial_generic_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount);
extern int usb_serial_generic_register(void);
extern void usb_serial_generic_deregister(void);
extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h
index 9ebebe906925..1b7519a8c0bf 100644
--- a/include/linux/usb/tegra_usb_phy.h
+++ b/include/linux/usb/tegra_usb_phy.h
@@ -61,10 +61,14 @@ struct tegra_usb_phy {
struct device *dev;
bool is_legacy_phy;
bool is_ulpi_phy;
+ void (*set_pts)(struct usb_phy *x, u8 pts_val);
+ void (*set_phcd)(struct usb_phy *x, bool enable);
};
struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
- void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode);
+ void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode,
+ void (*set_pts)(struct usb_phy *x, u8 pts_val),
+ void (*set_phcd)(struct usb_phy *x, bool enable));
void tegra_usb_phy_preresume(struct usb_phy *phy);
@@ -75,8 +79,4 @@ void tegra_ehci_phy_restore_start(struct usb_phy *phy,
void tegra_ehci_phy_restore_end(struct usb_phy *phy);
-void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val);
-
-void tegra_ehci_set_phcd(struct usb_phy *x, bool enable);
-
#endif /* __TEGRA_USB_PHY_H */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 0e5ac93bab10..da46327fca17 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -72,6 +72,7 @@ struct usbnet {
# define EVENT_DEVICE_REPORT_IDLE 8
# define EVENT_NO_RUNTIME_PM 9
# define EVENT_RX_KILL 10
+# define EVENT_LINK_CHANGE 11
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -245,5 +246,6 @@ extern void usbnet_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
extern int usbnet_nway_reset(struct net_device *net);
extern int usbnet_manage_power(struct usbnet *, int);
+extern void usbnet_link_change(struct usbnet *, bool, bool);
#endif /* __LINUX_USB_USBNET_H */
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index 4ce009324933..b6b215f13b45 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -26,6 +26,8 @@ struct user_namespace {
kuid_t owner;
kgid_t group;
unsigned int proc_inum;
+ bool may_mount_sysfs;
+ bool may_mount_proc;
};
extern struct user_namespace init_user_ns;
@@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns)
#endif
+void update_mnt_policy(struct user_namespace *userns);
+
#endif /* _LINUX_USER_H */
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index 75818744ab59..ea7168a68081 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -115,9 +115,6 @@ unsigned __vexpress_get_site(struct device *dev, struct device_node *node);
void vexpress_sysreg_early_init(void __iomem *base);
void vexpress_sysreg_of_early_init(void);
-void vexpress_power_off(void);
-void vexpress_restart(char str, const char *cmd);
-
/* Clocks */
struct clk *vexpress_osc_setup(struct device *dev);
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index ff6714e6d0f5..2d7a5e045908 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -58,12 +58,6 @@ void *virtqueue_detach_unused_buf(struct virtqueue *vq);
unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
-/* FIXME: Obsolete accessor, but required for virtio_net merge. */
-static inline unsigned int virtqueue_get_queue_index(struct virtqueue *vq)
-{
- return vq->index;
-}
-
/**
* virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
diff --git a/include/linux/vm_sockets.h b/include/linux/vm_sockets.h
new file mode 100644
index 000000000000..0805eecba8f7
--- /dev/null
+++ b/include/linux/vm_sockets.h
@@ -0,0 +1,23 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2013 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VM_SOCKETS_H
+#define _VM_SOCKETS_H
+
+#include <uapi/linux/vm_sockets.h>
+
+int vm_sockets_get_local_cid(void);
+
+#endif /* _VM_SOCKETS_H */
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 6071e911c7f4..7d5773a99f20 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -3,7 +3,9 @@
#include <linux/spinlock.h>
#include <linux/init.h>
+#include <linux/list.h>
#include <asm/page.h> /* pgprot_t */
+#include <linux/rbtree.h>
struct vm_area_struct; /* vma defining user mapping in mm_types.h */
@@ -35,6 +37,17 @@ struct vm_struct {
const void *caller;
};
+struct vmap_area {
+ unsigned long va_start;
+ unsigned long va_end;
+ unsigned long flags;
+ struct rb_node rb_node; /* address sorted rbtree */
+ struct list_head list; /* address sorted list */
+ struct list_head purge_list; /* "lazy purge" list */
+ struct vm_struct *vm;
+ struct rcu_head rcu_head;
+};
+
/*
* Highlevel APIs for driver use
*/
@@ -130,8 +143,7 @@ extern long vwrite(char *buf, char *addr, unsigned long count);
/*
* Internals. Dont't use..
*/
-extern rwlock_t vmlist_lock;
-extern struct vm_struct *vmlist;
+extern struct list_head vmap_area_list;
extern __init void vm_area_add_early(struct vm_struct *vm);
extern __init void vm_area_register_early(struct vm_struct *vm, size_t align);
@@ -158,4 +170,22 @@ pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
# endif
#endif
+struct vmalloc_info {
+ unsigned long used;
+ unsigned long largest_chunk;
+};
+
+#ifdef CONFIG_MMU
+#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)
+extern void get_vmalloc_info(struct vmalloc_info *vmi);
+#else
+
+#define VMALLOC_TOTAL 0UL
+#define get_vmalloc_info(vmi) \
+do { \
+ (vmi)->used = 0; \
+ (vmi)->largest_chunk = 0; \
+} while (0)
+#endif
+
#endif /* _LINUX_VMALLOC_H */
diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h
new file mode 100644
index 000000000000..76be077340ea
--- /dev/null
+++ b/include/linux/vmpressure.h
@@ -0,0 +1,47 @@
+#ifndef __LINUX_VMPRESSURE_H
+#define __LINUX_VMPRESSURE_H
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/gfp.h>
+#include <linux/types.h>
+#include <linux/cgroup.h>
+
+struct vmpressure {
+ unsigned long scanned;
+ unsigned long reclaimed;
+ /* The lock is used to keep the scanned/reclaimed above in sync. */
+ struct mutex sr_lock;
+
+ /* The list of vmpressure_event structs. */
+ struct list_head events;
+ /* Have to grab the lock on events traversal or modifications. */
+ struct mutex events_lock;
+
+ struct work_struct work;
+};
+
+struct mem_cgroup;
+
+#ifdef CONFIG_MEMCG
+extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+ unsigned long scanned, unsigned long reclaimed);
+extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
+
+extern void vmpressure_init(struct vmpressure *vmpr);
+extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
+extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
+extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
+extern int vmpressure_register_event(struct cgroup *cg, struct cftype *cft,
+ struct eventfd_ctx *eventfd,
+ const char *args);
+extern void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
+ struct eventfd_ctx *eventfd);
+#else
+static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+ unsigned long scanned, unsigned long reclaimed) {}
+static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg,
+ int prio) {}
+#endif /* CONFIG_MEMCG */
+#endif /* __LINUX_VMPRESSURE_H */
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 5fd71a7d0dfd..c586679b6fef 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -48,13 +48,8 @@ static inline void count_vm_events(enum vm_event_item item, long delta)
}
extern void all_vm_events(unsigned long *);
-#ifdef CONFIG_HOTPLUG
+
extern void vm_events_fold_cpu(int cpu);
-#else
-static inline void vm_events_fold_cpu(int cpu)
-{
-}
-#endif
#else
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 8afab27cdbc2..623488fdc1f5 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -11,6 +11,7 @@
#include <linux/lockdep.h>
#include <linux/threads.h>
#include <linux/atomic.h>
+#include <linux/cpumask.h>
struct workqueue_struct;
@@ -68,7 +69,7 @@ enum {
WORK_STRUCT_COLOR_BITS,
/* data contains off-queue information when !WORK_STRUCT_PWQ */
- WORK_OFFQ_FLAG_BASE = WORK_STRUCT_FLAG_BITS,
+ WORK_OFFQ_FLAG_BASE = WORK_STRUCT_COLOR_SHIFT,
WORK_OFFQ_CANCELING = (1 << WORK_OFFQ_FLAG_BASE),
@@ -91,6 +92,9 @@ enum {
/* bit mask for work_busy() return values */
WORK_BUSY_PENDING = 1 << 0,
WORK_BUSY_RUNNING = 1 << 1,
+
+ /* maximum string length for set_worker_desc() */
+ WORKER_DESC_LEN = 24,
};
struct work_struct {
@@ -115,6 +119,20 @@ struct delayed_work {
int cpu;
};
+/*
+ * A struct for workqueue attributes. This can be used to change
+ * attributes of an unbound workqueue.
+ *
+ * Unlike other fields, ->no_numa isn't a property of a worker_pool. It
+ * only modifies how apply_workqueue_attrs() select pools and thus doesn't
+ * participate in pool hash calculations or equality comparisons.
+ */
+struct workqueue_attrs {
+ int nice; /* nice level */
+ cpumask_var_t cpumask; /* allowed CPUs */
+ bool no_numa; /* disable NUMA affinity */
+};
+
static inline struct delayed_work *to_delayed_work(struct work_struct *work)
{
return container_of(work, struct delayed_work, work);
@@ -283,9 +301,10 @@ enum {
WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */
WQ_HIGHPRI = 1 << 4, /* high priority */
WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */
+ WQ_SYSFS = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */
- WQ_DRAINING = 1 << 6, /* internal: workqueue is draining */
- WQ_RESCUER = 1 << 7, /* internal: workqueue has rescuer */
+ __WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
+ __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
@@ -388,7 +407,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
* Pointer to the allocated workqueue on success, %NULL on failure.
*/
#define alloc_ordered_workqueue(fmt, flags, args...) \
- alloc_workqueue(fmt, WQ_UNBOUND | (flags), 1, ##args)
+ alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
#define create_workqueue(name) \
alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
@@ -399,30 +418,23 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
extern void destroy_workqueue(struct workqueue_struct *wq);
+struct workqueue_attrs *alloc_workqueue_attrs(gfp_t gfp_mask);
+void free_workqueue_attrs(struct workqueue_attrs *attrs);
+int apply_workqueue_attrs(struct workqueue_struct *wq,
+ const struct workqueue_attrs *attrs);
+
extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
struct work_struct *work);
-extern bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *work, unsigned long delay);
-extern bool queue_delayed_work(struct workqueue_struct *wq,
- struct delayed_work *work, unsigned long delay);
extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay);
-extern bool mod_delayed_work(struct workqueue_struct *wq,
- struct delayed_work *dwork, unsigned long delay);
extern void flush_workqueue(struct workqueue_struct *wq);
extern void drain_workqueue(struct workqueue_struct *wq);
extern void flush_scheduled_work(void);
-extern bool schedule_work_on(int cpu, struct work_struct *work);
-extern bool schedule_work(struct work_struct *work);
-extern bool schedule_delayed_work_on(int cpu, struct delayed_work *work,
- unsigned long delay);
-extern bool schedule_delayed_work(struct delayed_work *work,
- unsigned long delay);
extern int schedule_on_each_cpu(work_func_t func);
-extern int keventd_up(void);
int execute_in_process_context(work_func_t fn, struct execute_work *);
@@ -435,8 +447,122 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
extern void workqueue_set_max_active(struct workqueue_struct *wq,
int max_active);
-extern bool workqueue_congested(unsigned int cpu, struct workqueue_struct *wq);
+extern bool current_is_workqueue_rescuer(void);
+extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
extern unsigned int work_busy(struct work_struct *work);
+extern __printf(1, 2) void set_worker_desc(const char *fmt, ...);
+extern void print_worker_info(const char *log_lvl, struct task_struct *task);
+
+/**
+ * queue_work - queue work on a workqueue
+ * @wq: workqueue to use
+ * @work: work to queue
+ *
+ * Returns %false if @work was already on a queue, %true otherwise.
+ *
+ * We queue the work to the CPU on which it was submitted, but if the CPU dies
+ * it can be processed by another CPU.
+ */
+static inline bool queue_work(struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ return queue_work_on(WORK_CPU_UNBOUND, wq, work);
+}
+
+/**
+ * queue_delayed_work - queue work on a workqueue after delay
+ * @wq: workqueue to use
+ * @dwork: delayable work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * Equivalent to queue_delayed_work_on() but tries to use the local CPU.
+ */
+static inline bool queue_delayed_work(struct workqueue_struct *wq,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
+}
+
+/**
+ * mod_delayed_work - modify delay of or queue a delayed work
+ * @wq: workqueue to use
+ * @dwork: work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * mod_delayed_work_on() on local CPU.
+ */
+static inline bool mod_delayed_work(struct workqueue_struct *wq,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return mod_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
+}
+
+/**
+ * schedule_work_on - put work task on a specific cpu
+ * @cpu: cpu to put the work task on
+ * @work: job to be done
+ *
+ * This puts a job on a specific cpu
+ */
+static inline bool schedule_work_on(int cpu, struct work_struct *work)
+{
+ return queue_work_on(cpu, system_wq, work);
+}
+
+/**
+ * schedule_work - put work task in global workqueue
+ * @work: job to be done
+ *
+ * Returns %false if @work was already on the kernel-global workqueue and
+ * %true otherwise.
+ *
+ * This puts a job in the kernel-global workqueue if it was not already
+ * queued and leaves it in the same position on the kernel-global
+ * workqueue otherwise.
+ */
+static inline bool schedule_work(struct work_struct *work)
+{
+ return queue_work(system_wq, work);
+}
+
+/**
+ * schedule_delayed_work_on - queue work in global workqueue on CPU after delay
+ * @cpu: cpu to use
+ * @dwork: job to be done
+ * @delay: number of jiffies to wait
+ *
+ * After waiting for a given time this puts a job in the kernel-global
+ * workqueue on the specified CPU.
+ */
+static inline bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_delayed_work_on(cpu, system_wq, dwork, delay);
+}
+
+/**
+ * schedule_delayed_work - put work task in global workqueue after delay
+ * @dwork: job to be done
+ * @delay: number of jiffies to wait or 0 for immediate execution
+ *
+ * After waiting for a given time this puts a job in the kernel-global
+ * workqueue.
+ */
+static inline bool schedule_delayed_work(struct delayed_work *dwork,
+ unsigned long delay)
+{
+ return queue_delayed_work(system_wq, dwork, delay);
+}
+
+/**
+ * keventd_up - is workqueue initialized yet?
+ */
+static inline bool keventd_up(void)
+{
+ return system_wq != NULL;
+}
/*
* Like above, but uses del_timer() instead of del_timer_sync(). This means,
@@ -466,12 +592,12 @@ static inline bool __deprecated flush_delayed_work_sync(struct delayed_work *dwo
}
#ifndef CONFIG_SMP
-static inline long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
+static inline long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
{
return fn(arg);
}
#else
-long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg);
+long work_on_cpu(int cpu, long (*fn)(void *), void *arg);
#endif /* CONFIG_SMP */
#ifdef CONFIG_FREEZER
@@ -480,4 +606,11 @@ extern bool freeze_workqueues_busy(void);
extern void thaw_workqueues(void);
#endif /* CONFIG_FREEZER */
+#ifdef CONFIG_SYSFS
+int workqueue_sysfs_register(struct workqueue_struct *wq);
+#else /* CONFIG_SYSFS */
+static inline int workqueue_sysfs_register(struct workqueue_struct *wq)
+{ return 0; }
+#endif /* CONFIG_SYSFS */
+
#endif
diff --git a/include/media/davinci/dm355_ccdc.h b/include/media/davinci/dm355_ccdc.h
index adf2fe4bf0bb..c669a9fb75e5 100644
--- a/include/media/davinci/dm355_ccdc.h
+++ b/include/media/davinci/dm355_ccdc.h
@@ -38,7 +38,7 @@ enum ccdc_sample_line {
CCDC_SAMPLE_16LINES
};
-/* enum for Alaw gama width */
+/* enum for Alaw gamma width */
enum ccdc_gamma_width {
CCDC_GAMMA_BITS_13_4,
CCDC_GAMMA_BITS_12_3,
@@ -97,8 +97,8 @@ enum ccdc_mfilt2 {
struct ccdc_a_law {
/* Enable/disable A-Law */
unsigned char enable;
- /* Gama Width Input */
- enum ccdc_gamma_width gama_wd;
+ /* Gamma Width Input */
+ enum ccdc_gamma_width gamma_wd;
};
/* structure for Black Clamping */
diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h
index 3e178eb52fb3..852e96c4bb46 100644
--- a/include/media/davinci/dm644x_ccdc.h
+++ b/include/media/davinci/dm644x_ccdc.h
@@ -38,17 +38,23 @@ enum ccdc_sample_line {
CCDC_SAMPLE_16LINES
};
-/* enum for Alaw gama width */
-enum ccdc_gama_width {
- CCDC_GAMMA_BITS_15_6,
+/* enum for Alaw gamma width */
+enum ccdc_gamma_width {
+ CCDC_GAMMA_BITS_15_6, /* use bits 15-6 for gamma */
CCDC_GAMMA_BITS_14_5,
CCDC_GAMMA_BITS_13_4,
CCDC_GAMMA_BITS_12_3,
CCDC_GAMMA_BITS_11_2,
CCDC_GAMMA_BITS_10_1,
- CCDC_GAMMA_BITS_09_0
+ CCDC_GAMMA_BITS_09_0 /* use bits 9-0 for gamma */
};
+/* returns the highest bit used for the gamma */
+static inline u8 ccdc_gamma_width_max_bit(enum ccdc_gamma_width width)
+{
+ return 15 - width;
+}
+
enum ccdc_data_size {
CCDC_DATA_16BITS,
CCDC_DATA_15BITS,
@@ -60,12 +66,18 @@ enum ccdc_data_size {
CCDC_DATA_8BITS
};
+/* returns the highest bit used for this data size */
+static inline u8 ccdc_data_size_max_bit(enum ccdc_data_size sz)
+{
+ return sz == CCDC_DATA_8BITS ? 7 : 15 - sz;
+}
+
/* structure for ALaw */
struct ccdc_a_law {
/* Enable/disable A-Law */
unsigned char enable;
- /* Gama Width Input */
- enum ccdc_gama_width gama_wd;
+ /* Gamma Width Input */
+ enum ccdc_gamma_width gamma_wd;
};
/* structure for Black Clamping */
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
index a7ca4884c46c..57585c7004a4 100644
--- a/include/media/davinci/vpbe.h
+++ b/include/media/davinci/vpbe.h
@@ -132,7 +132,7 @@ struct vpbe_device_ops {
struct v4l2_enum_dv_timings *timings_info);
/* Set std at the output */
- int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
+ int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id std_id);
/* Get the current std at the output */
int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id);
diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h
index 9b85396514be..05dbe0ba514c 100644
--- a/include/media/davinci/vpbe_types.h
+++ b/include/media/davinci/vpbe_types.h
@@ -26,8 +26,7 @@ enum vpbe_version {
/* vpbe_timing_type - Timing types used in vpbe device */
enum vpbe_enc_timings_type {
VPBE_ENC_STD = 0x1,
- VPBE_ENC_DV_PRESET = 0x2,
- VPBE_ENC_CUSTOM_TIMINGS = 0x4,
+ VPBE_ENC_DV_TIMINGS = 0x4,
/* Used when set timings through FB device interface */
VPBE_ENC_TIMINGS_INVALID = 0x8,
};
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index f6caafc874cb..3446af279fca 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -46,6 +46,7 @@ struct media_file_operations {
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*ioctl) (struct file *, unsigned int, unsigned long);
+ long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*open) (struct file *);
int (*release) (struct file *);
};
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
index 0c97b19af293..b1e63f2b72bd 100644
--- a/include/media/mt9p031.h
+++ b/include/media/mt9p031.h
@@ -5,13 +5,11 @@ struct v4l2_subdev;
/*
* struct mt9p031_platform_data - MT9P031 platform data
- * @set_xclk: Clock frequency set callback
* @reset: Chip reset GPIO (set to -1 if not used)
* @ext_freq: Input clock frequency
* @target_freq: Pixel clock frequency
*/
struct mt9p031_platform_data {
- int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
int reset;
int ext_freq;
int target_freq;
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index 95842696857f..c9d06d9f7e6e 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -29,10 +29,6 @@
struct i2c_board_info;
struct isp_device;
-#define ISP_XCLK_NONE 0
-#define ISP_XCLK_A 1
-#define ISP_XCLK_B 2
-
enum isp_interface_type {
ISP_INTERFACE_PARALLEL,
ISP_INTERFACE_CSI2A_PHY2,
@@ -153,7 +149,13 @@ struct isp_v4l2_subdevs_group {
} bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
};
+struct isp_platform_xclk {
+ const char *dev_id;
+ const char *con_id;
+};
+
struct isp_platform_data {
+ struct isp_platform_xclk xclks[2];
struct isp_v4l2_subdevs_group *subdevs;
void (*set_constraints)(struct isp_device *isp, bool enable);
};
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index f03445f3c767..06a75deff553 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -51,6 +51,7 @@ enum rc_driver_type {
* @driver_type: specifies if protocol decoding is done in hardware or software
* @idle: used to keep track of RX state
* @allowed_protos: bitmask with the supported RC_BIT_* protocols
+ * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols
* @scanmask: some hardware decoders are not capable of providing the full
* scancode to the application. As this is a hardware limit, we can't do
* anything with it. Yet, as the same keycode table can be used with other
@@ -99,6 +100,7 @@ struct rc_dev {
enum rc_driver_type driver_type;
bool idle;
u64 allowed_protos;
+ u64 enabled_protocols;
u32 scanmask;
void *priv;
spinlock_t keylock;
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index f74ee6f89711..5d5d3a30f04a 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -172,6 +172,7 @@ void rc_map_init(void);
#define RC_MAP_RC5_TV "rc-rc5-tv"
#define RC_MAP_RC6_MCE "rc-rc6-mce"
#define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys"
+#define RC_MAP_REDDO "rc-reddo"
#define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly"
#define RC_MAP_STREAMZAP "rc-streamzap"
#define RC_MAP_TBS_NEC "rc-tbs-nec"
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
index 28f3590aa031..f50969025ef3 100644
--- a/include/media/s5p_fimc.h
+++ b/include/media/s5p_fimc.h
@@ -13,6 +13,20 @@
#define S5P_FIMC_H_
#include <media/media-entity.h>
+#include <media/v4l2-mediabus.h>
+
+/*
+ * Enumeration of data inputs to the camera subsystem.
+ */
+enum fimc_input {
+ FIMC_INPUT_PARALLEL_0 = 1,
+ FIMC_INPUT_PARALLEL_1,
+ FIMC_INPUT_MIPI_CSI2_0 = 3,
+ FIMC_INPUT_MIPI_CSI2_1,
+ FIMC_INPUT_WRITEBACK_A = 5,
+ FIMC_INPUT_WRITEBACK_B,
+ FIMC_INPUT_WRITEBACK_ISP = 5,
+};
/*
* Enumeration of the FIMC data bus types.
@@ -32,6 +46,20 @@ enum fimc_bus_type {
FIMC_BUS_TYPE_ISP_WRITEBACK = FIMC_BUS_TYPE_LCD_WRITEBACK_B,
};
+#define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2)
+#define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4)
+
+/*
+ * The subdevices' group IDs.
+ */
+#define GRP_ID_SENSOR (1 << 8)
+#define GRP_ID_FIMC_IS_SENSOR (1 << 9)
+#define GRP_ID_WRITEBACK (1 << 10)
+#define GRP_ID_CSIS (1 << 11)
+#define GRP_ID_FIMC (1 << 12)
+#define GRP_ID_FLITE (1 << 13)
+#define GRP_ID_FIMC_IS (1 << 14)
+
struct i2c_board_info;
/**
@@ -77,10 +105,46 @@ struct s5p_platform_fimc {
*/
#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
+#define FIMC_MAX_PLANES 3
+
+/**
+ * struct fimc_fmt - color format data structure
+ * @mbus_code: media bus pixel code, -1 if not applicable
+ * @name: format description
+ * @fourcc: fourcc code for this format, 0 if not applicable
+ * @color: the driver's private color format id
+ * @memplanes: number of physically non-contiguous data planes
+ * @colplanes: number of physically contiguous data planes
+ * @depth: per plane driver's private 'number of bits per pixel'
+ * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no)
+ * @flags: flags indicating which operation mode format applies to
+ */
+struct fimc_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
+ char *name;
+ u32 fourcc;
+ u32 color;
+ u16 memplanes;
+ u16 colplanes;
+ u8 depth[FIMC_MAX_PLANES];
+ u16 mdataplanes;
+ u16 flags;
+#define FMT_FLAGS_CAM (1 << 0)
+#define FMT_FLAGS_M2M_IN (1 << 1)
+#define FMT_FLAGS_M2M_OUT (1 << 2)
+#define FMT_FLAGS_M2M (1 << 1 | 1 << 2)
+#define FMT_HAS_ALPHA (1 << 3)
+#define FMT_FLAGS_COMPRESSED (1 << 4)
+#define FMT_FLAGS_WRITEBACK (1 << 5)
+#define FMT_FLAGS_RAW_BAYER (1 << 6)
+#define FMT_FLAGS_YUV (1 << 7)
+};
+
enum fimc_subdev_index {
IDX_SENSOR,
IDX_CSIS,
IDX_FLITE,
+ IDX_IS_ISP,
IDX_FIMC,
IDX_MAX,
};
diff --git a/include/media/saa7115.h b/include/media/saa7115.h
index bab212719591..407918625c80 100644
--- a/include/media/saa7115.h
+++ b/include/media/saa7115.h
@@ -21,6 +21,8 @@
#ifndef _SAA7115_H_
#define _SAA7115_H_
+/* s_routing inputs, outputs, and config */
+
/* SAA7111/3/4/5 HW inputs */
#define SAA7115_COMPOSITE0 0
#define SAA7115_COMPOSITE1 1
@@ -33,24 +35,34 @@
#define SAA7115_SVIDEO2 8
#define SAA7115_SVIDEO3 9
-/* SAA7115 v4l2_crystal_freq frequency values */
-#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */
-#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */
-
-/* SAA7115 v4l2_crystal_freq audio clock control flags */
-#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
-#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
-#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
-
+/* outputs */
#define SAA7115_IPORT_ON 1
#define SAA7115_IPORT_OFF 0
-/* SAA7111 specific output flags */
+/* SAA7111 specific outputs. */
#define SAA7111_VBI_BYPASS 2
#define SAA7111_FMT_YUV422 0x00
#define SAA7111_FMT_RGB 0x40
#define SAA7111_FMT_CCIR 0x80
#define SAA7111_FMT_YUV411 0xc0
+/* config flags */
+/* Register 0x85 should set bit 0 to 0 (it's 1 by default). This bit
+ * controls the IDQ signal polarity which is set to 'inverted' if the bit
+ * it 1 and to 'default' if it is 0. */
+#define SAA7115_IDQ_IS_DEFAULT (1 << 0)
+
+/* s_crystal_freq values and flags */
+
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
+#define SAA7115_FREQ_FL_DOUBLE_ASCLK (1 << 3) /* SA 39, LRDIV, SAA7114/5 only */
+
#endif
diff --git a/include/media/si476x.h b/include/media/si476x.h
new file mode 100644
index 000000000000..e02e241e2d22
--- /dev/null
+++ b/include/media/si476x.h
@@ -0,0 +1,37 @@
+/*
+ * include/media/si476x.h -- Common definitions for si476x driver
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#ifndef SI476X_H
+#define SI476X_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <linux/mfd/si476x-reports.h>
+
+enum si476x_ctrl_id {
+ V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1),
+ V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2),
+ V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3),
+ V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4),
+ V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5),
+ V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6),
+};
+
+#endif /* SI476X_H*/
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 2cc70cf318bf..ff77d08c30fd 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -292,12 +292,17 @@ struct soc_camera_sense {
#define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8)
#define SOCAM_DATAWIDTH_9 SOCAM_DATAWIDTH(9)
#define SOCAM_DATAWIDTH_10 SOCAM_DATAWIDTH(10)
+#define SOCAM_DATAWIDTH_12 SOCAM_DATAWIDTH(12)
#define SOCAM_DATAWIDTH_15 SOCAM_DATAWIDTH(15)
#define SOCAM_DATAWIDTH_16 SOCAM_DATAWIDTH(16)
+#define SOCAM_DATAWIDTH_18 SOCAM_DATAWIDTH(18)
+#define SOCAM_DATAWIDTH_24 SOCAM_DATAWIDTH(24)
#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \
SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \
- SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16)
+ SOCAM_DATAWIDTH_12 | SOCAM_DATAWIDTH_15 | \
+ SOCAM_DATAWIDTH_16 | SOCAM_DATAWIDTH_18 | \
+ SOCAM_DATAWIDTH_24)
static inline void soc_camera_limit_side(int *start, int *length,
unsigned int start_min,
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
index 0dc6f4625b92..d33f6d059692 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/soc_mediabus.h
@@ -26,6 +26,8 @@
* @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing
* @SOC_MBUS_PACKING_1_5X8: used for packed YUV 4:2:0 formats, where 4
* pixels occupy 6 bytes in RAM
+ * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 24 bits) has to be extended
+ * to 32 bits
*/
enum soc_mbus_packing {
SOC_MBUS_PACKING_NONE,
@@ -34,6 +36,7 @@ enum soc_mbus_packing {
SOC_MBUS_PACKING_EXTEND16,
SOC_MBUS_PACKING_VARIABLE,
SOC_MBUS_PACKING_1_5X8,
+ SOC_MBUS_PACKING_EXTEND32,
};
/**
diff --git a/include/media/ths7303.h b/include/media/ths7303.h
new file mode 100644
index 000000000000..980ec51d574d
--- /dev/null
+++ b/include/media/ths7303.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 Texas Instruments Inc
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates.
+ *
+ * Contributors:
+ * Hans Verkuil <hans.verkuil@cisco.com>
+ * Lad, Prabhakar <prabhakar.lad@ti.com>
+ * Martin Bugge <marbugge@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef THS7353_H
+#define THS7353_H
+
+/**
+ * struct ths7303_platform_data - Platform dependent data
+ * @ch_1: Bias value for channel one.
+ * @ch_2: Bias value for channel two.
+ * @ch_3: Bias value for channel three.
+ * @init_enable: initalize on init.
+ */
+struct ths7303_platform_data {
+ u8 ch_1;
+ u8 ch_2;
+ u8 ch_3;
+ u8 init_enable;
+};
+
+#endif
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 926aff9bdf65..b46ebb48fe74 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -138,6 +138,10 @@
#define TUNER_XC4000 87 /* Xceive Silicon Tuner */
#define TUNER_XC5000C 88 /* Xceive Silicon Tuner */
+#define TUNER_SONY_BTF_PG472Z 89 /* PAL+SECAM */
+#define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */
+#define TUNER_SONY_BTF_PB463Z 91 /* NTSC */
+
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
#define TDA9887_PORT1_INACTIVE (1<<1)
@@ -188,7 +192,7 @@ struct tuner_setup {
unsigned short addr; /* I2C address */
unsigned int type; /* Tuner type */
unsigned int mode_mask; /* Allowed tuner modes */
- unsigned int config; /* configuraion for more complex tuners */
+ void *config; /* configuraion for more complex tuners */
int (*tuner_callback) (void *dev, int component, int cmd, int arg);
};
diff --git a/include/media/uda1342.h b/include/media/uda1342.h
new file mode 100644
index 000000000000..cd156403a368
--- /dev/null
+++ b/include/media/uda1342.h
@@ -0,0 +1,29 @@
+/*
+ * uda1342.h - definition for uda1342 inputs
+ *
+ * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 _UDA1342_H_
+#define _UDA1342_H_
+
+/* The UDA1342 has 2 inputs */
+
+#define UDA1342_IN1 1
+#define UDA1342_IN2 2
+
+#endif
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 4ee125bae719..c259b36bf1e9 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -96,12 +96,20 @@ enum {
/* module au0828 */
V4L2_IDENT_AU0828 = 828,
+ /* module bttv: ident 848 + 849 */
+ V4L2_IDENT_BT848 = 848,
+ V4L2_IDENT_BT849 = 849,
+
/* module bt856: just ident 856 */
V4L2_IDENT_BT856 = 856,
/* module bt866: just ident 866 */
V4L2_IDENT_BT866 = 866,
+ /* module bttv: ident 878 + 879 */
+ V4L2_IDENT_BT878 = 878,
+ V4L2_IDENT_BT879 = 879,
+
/* module ks0127: reserved range 1120-1129 */
V4L2_IDENT_KS0122S = 1122,
V4L2_IDENT_KS0127 = 1127,
@@ -180,6 +188,9 @@ enum {
/* module adv7343: just ident 7343 */
V4L2_IDENT_ADV7343 = 7343,
+ /* module ths7353: just ident 7353 */
+ V4L2_IDENT_THS7353 = 7353,
+
/* module adv7393: just ident 7393 */
V4L2_IDENT_ADV7393 = 7393,
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index ec7c9c00b256..1d93c48cb371 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -201,7 +201,6 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin,
unsigned int *h, unsigned int hmin,
unsigned int hmax, unsigned int halign,
unsigned int salign);
-int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info);
struct v4l2_discrete_probe {
const struct v4l2_frmsize_discrete *sizes;
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index f00d42bc01a6..7343a27fe819 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -259,7 +259,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags);
-/** v4l2_ctrl_handler_init() - Initialize the control handler.
+/** v4l2_ctrl_handler_init_class() - Initialize the control handler.
* @hdl: The control handler.
* @nr_of_controls_hint: A hint of how many controls this handler is
* expected to refer to. This is the total number, so including
@@ -268,12 +268,35 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
* are allocated) or the control lookup becomes slower (not enough
* buckets are allocated, so there are more slow list lookups).
* It will always work, though.
+ * @key: Used by the lock validator if CONFIG_LOCKDEP is set.
+ * @name: Used by the lock validator if CONFIG_LOCKDEP is set.
*
* Returns an error if the buckets could not be allocated. This error will
* also be stored in @hdl->error.
+ *
+ * Never use this call directly, always use the v4l2_ctrl_handler_init
+ * macro that hides the @key and @name arguments.
*/
-int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
- unsigned nr_of_controls_hint);
+int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint,
+ struct lock_class_key *key, const char *name);
+
+#ifdef CONFIG_LOCKDEP
+#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \
+( \
+ ({ \
+ static struct lock_class_key _key; \
+ v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, \
+ &_key, \
+ KBUILD_BASENAME ":" \
+ __stringify(__LINE__) ":" \
+ "(" #hdl ")->_lock"); \
+ }) \
+)
+#else
+#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \
+ v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, NULL, NULL)
+#endif
/** v4l2_ctrl_handler_free() - Free all controls owned by the handler and free
* the control list.
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
index d61febfb1668..c9b1593923f6 100644
--- a/include/media/v4l2-device.h
+++ b/include/media/v4l2-device.h
@@ -190,4 +190,17 @@ v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev);
##args); \
})
+#define v4l2_device_has_op(v4l2_dev, o, f) \
+({ \
+ struct v4l2_subdev *__sd; \
+ bool __result = false; \
+ list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \
+ if (v4l2_subdev_has_op(__sd, o, f)) { \
+ __result = true; \
+ break; \
+ } \
+ } \
+ __result; \
+})
+
#endif
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 4118ad1324c9..931652f0e2af 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -132,7 +132,7 @@ struct v4l2_ioctl_ops {
ENUMSTD is handled by videodev.c
*/
int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm);
- int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm);
+ int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id norm);
int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
/* Input handling */
@@ -219,11 +219,11 @@ struct v4l2_ioctl_ops {
int (*vidioc_g_tuner) (struct file *file, void *fh,
struct v4l2_tuner *a);
int (*vidioc_s_tuner) (struct file *file, void *fh,
- struct v4l2_tuner *a);
+ const struct v4l2_tuner *a);
int (*vidioc_g_frequency) (struct file *file, void *fh,
struct v4l2_frequency *a);
int (*vidioc_s_frequency) (struct file *file, void *fh,
- struct v4l2_frequency *a);
+ const struct v4l2_frequency *a);
int (*vidioc_enum_freq_bands) (struct file *file, void *fh,
struct v4l2_frequency_band *band);
@@ -242,7 +242,10 @@ struct v4l2_ioctl_ops {
int (*vidioc_g_register) (struct file *file, void *fh,
struct v4l2_dbg_register *reg);
int (*vidioc_s_register) (struct file *file, void *fh,
- struct v4l2_dbg_register *reg);
+ const struct v4l2_dbg_register *reg);
+
+ int (*vidioc_g_chip_info) (struct file *file, void *fh,
+ struct v4l2_dbg_chip_info *chip);
#endif
int (*vidioc_g_chip_ident) (struct file *file, void *fh,
struct v4l2_dbg_chip_ident *chip);
@@ -254,15 +257,6 @@ struct v4l2_ioctl_ops {
struct v4l2_frmivalenum *fival);
/* DV Timings IOCTLs */
- int (*vidioc_enum_dv_presets) (struct file *file, void *fh,
- struct v4l2_dv_enum_preset *preset);
-
- int (*vidioc_s_dv_preset) (struct file *file, void *fh,
- struct v4l2_dv_preset *preset);
- int (*vidioc_g_dv_preset) (struct file *file, void *fh,
- struct v4l2_dv_preset *preset);
- int (*vidioc_query_dv_preset) (struct file *file, void *fh,
- struct v4l2_dv_preset *qpreset);
int (*vidioc_s_dv_timings) (struct file *file, void *fh,
struct v4l2_dv_timings *timings);
int (*vidioc_g_dv_timings) (struct file *file, void *fh,
@@ -281,7 +275,7 @@ struct v4l2_ioctl_ops {
/* For other private ioctls */
long (*vidioc_default) (struct file *file, void *fh,
- bool valid_prio, int cmd, void *arg);
+ bool valid_prio, unsigned int cmd, void *arg);
};
diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h
new file mode 100644
index 000000000000..3a8a84124b44
--- /dev/null
+++ b/include/media/v4l2-of.h
@@ -0,0 +1,111 @@
+/*
+ * V4L2 OF binding parsing library
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * Copyright (C) 2012 Renesas Electronics Corp.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+#ifndef _V4L2_OF_H
+#define _V4L2_OF_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <media/v4l2-mediabus.h>
+
+struct device_node;
+
+/**
+ * struct v4l2_of_bus_mipi_csi2 - MIPI CSI-2 bus data structure
+ * @flags: media bus (V4L2_MBUS_*) flags
+ * @data_lanes: an array of physical data lane indexes
+ * @clock_lane: physical lane index of the clock lane
+ * @num_data_lanes: number of data lanes
+ */
+struct v4l2_of_bus_mipi_csi2 {
+ unsigned int flags;
+ unsigned char data_lanes[4];
+ unsigned char clock_lane;
+ unsigned short num_data_lanes;
+};
+
+/**
+ * struct v4l2_of_bus_parallel - parallel data bus data structure
+ * @flags: media bus (V4L2_MBUS_*) flags
+ * @bus_width: bus width in bits
+ * @data_shift: data shift in bits
+ */
+struct v4l2_of_bus_parallel {
+ unsigned int flags;
+ unsigned char bus_width;
+ unsigned char data_shift;
+};
+
+/**
+ * struct v4l2_of_endpoint - the endpoint data structure
+ * @port: identifier (value of reg property) of a port this endpoint belongs to
+ * @id: identifier (value of reg property) of this endpoint
+ * @local_node: pointer to device_node of this endpoint
+ * @remote: phandle to remote endpoint node
+ * @bus_type: bus type
+ * @bus: bus configuration data structure
+ * @head: list head for this structure
+ */
+struct v4l2_of_endpoint {
+ unsigned int port;
+ unsigned int id;
+ const struct device_node *local_node;
+ const __be32 *remote;
+ enum v4l2_mbus_type bus_type;
+ union {
+ struct v4l2_of_bus_parallel parallel;
+ struct v4l2_of_bus_mipi_csi2 mipi_csi2;
+ } bus;
+ struct list_head head;
+};
+
+#ifdef CONFIG_OF
+void v4l2_of_parse_endpoint(const struct device_node *node,
+ struct v4l2_of_endpoint *link);
+struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
+ struct device_node *previous);
+struct device_node *v4l2_of_get_remote_port_parent(
+ const struct device_node *node);
+struct device_node *v4l2_of_get_remote_port(const struct device_node *node);
+#else /* CONFIG_OF */
+
+static inline int v4l2_of_parse_endpoint(const struct device_node *node,
+ struct v4l2_of_endpoint *link)
+{
+ return -ENOSYS;
+}
+
+static inline struct device_node *v4l2_of_get_next_endpoint(
+ const struct device_node *parent,
+ struct device_node *previous)
+{
+ return NULL;
+}
+
+static inline struct device_node *v4l2_of_get_remote_port_parent(
+ const struct device_node *node)
+{
+ return NULL;
+}
+
+static inline struct device_node *v4l2_of_get_remote_port(
+ const struct device_node *node)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_OF */
+
+#endif /* _V4L2_OF_H */
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index b137a5e1151a..5298d678d0f3 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -165,7 +165,7 @@ struct v4l2_subdev_core_ops {
long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
#ifdef CONFIG_VIDEO_ADV_DEBUG
int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
- int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg);
+ int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg);
#endif
int (*s_power)(struct v4l2_subdev *sd, int on);
int (*interrupt_service_routine)(struct v4l2_subdev *sd,
@@ -191,10 +191,10 @@ struct v4l2_subdev_core_ops {
*/
struct v4l2_subdev_tuner_ops {
int (*s_radio)(struct v4l2_subdev *sd);
- int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
+ int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq);
int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq);
int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
- int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt);
+ int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt);
int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm);
int (*s_modulator)(struct v4l2_subdev *sd, const struct v4l2_modulator *vm);
int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type);
@@ -279,14 +279,6 @@ struct v4l2_mbus_frame_desc {
s_routing: see s_routing in audio_ops, except this version is for video
devices.
- s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to
- s_std()
-
- g_dv_preset: get current dv (Digital Video) preset in the sub device.
-
- query_dv_preset: query dv preset in the sub device. This is similar to
- querystd()
-
s_dv_timings(): Set custom dv timings in the sub device. This is used
when sub device is capable of setting detailed timing information
in the hardware to generate/detect the video signal.
@@ -331,14 +323,6 @@ struct v4l2_subdev_video_ops {
struct v4l2_subdev_frame_interval *interval);
int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize);
int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival);
- int (*enum_dv_presets) (struct v4l2_subdev *sd,
- struct v4l2_dv_enum_preset *preset);
- int (*s_dv_preset)(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset);
- int (*g_dv_preset)(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset);
- int (*query_dv_preset)(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *preset);
int (*s_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
int (*g_dv_timings)(struct v4l2_subdev *sd,
@@ -687,4 +671,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd,
((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \
(sd)->v4l2_dev->notify((sd), (notification), (arg)))
+#define v4l2_subdev_has_op(sd, o, f) \
+ ((sd)->ops->o && (sd)->ops->o->f)
+
#endif
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
index f473aeb86d3f..f0ed82543d9f 100644
--- a/include/media/videobuf-dma-contig.h
+++ b/include/media/videobuf-dma-contig.h
@@ -26,16 +26,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
void *priv,
struct mutex *ext_lock);
-void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
- const struct videobuf_queue_ops *ops,
- struct device *dev,
- spinlock_t *irqlock,
- enum v4l2_buf_type type,
- enum v4l2_field field,
- unsigned int msize,
- void *priv,
- struct mutex *ext_lock);
-
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
void videobuf_dma_contig_free(struct videobuf_queue *q,
struct videobuf_buffer *buf);
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 9cfd4ee9e56f..d88a098d1aff 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -27,7 +27,9 @@ struct vb2_fileio_data;
* return NULL on failure or a pointer to allocator private,
* per-buffer data on success; the returned private structure
* will then be passed as buf_priv argument to other ops in this
- * structure
+ * structure. Additional gfp_flags to use when allocating the
+ * are also passed to this operation. These flags are from the
+ * gfp_flags field of vb2_queue.
* @put: inform the allocator that the buffer will no longer be used;
* usually will result in the allocator freeing the buffer (if
* no other users of this buffer are present); the buf_priv
@@ -79,7 +81,7 @@ struct vb2_fileio_data;
* unmap_dmabuf.
*/
struct vb2_mem_ops {
- void *(*alloc)(void *alloc_ctx, unsigned long size);
+ void *(*alloc)(void *alloc_ctx, unsigned long size, gfp_t gfp_flags);
void (*put)(void *buf_priv);
struct dma_buf *(*get_dmabuf)(void *buf_priv);
@@ -302,6 +304,9 @@ struct v4l2_fh;
* @buf_struct_size: size of the driver-specific buffer structure;
* "0" indicates the driver doesn't want to use a custom buffer
* structure type, so sizeof(struct vb2_buffer) will is used
+ * @gfp_flags: additional gfp flags used when allocating the buffers.
+ * Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32
+ * to force the buffer allocation to a specific memory zone.
*
* @memory: current memory type used
* @bufs: videobuf buffer structures
@@ -326,6 +331,8 @@ struct vb2_queue {
const struct vb2_mem_ops *mem_ops;
void *drv_priv;
unsigned int buf_struct_size;
+ u32 timestamp_type;
+ gfp_t gfp_flags;
/* private: internal use only */
enum v4l2_memory memory;
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 40be2a0d8ae1..84a6440f1f19 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -199,6 +199,7 @@ extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
/* Device notifier */
extern int register_inet6addr_notifier(struct notifier_block *nb);
extern int unregister_inet6addr_notifier(struct notifier_block *nb);
+extern int inet6addr_notifier_call_chain(unsigned long val, void *v);
extern void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex,
struct ipv6_devconf *devconf);
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 0a996a3517ed..dbdfd2b0f3b3 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -29,7 +29,8 @@ struct unix_address {
struct unix_skb_parms {
struct pid *pid; /* Skb credentials */
- const struct cred *cred;
+ kuid_t uid;
+ kgid_t gid;
struct scm_fp_list *fp; /* Passed files */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Security ID */
@@ -56,9 +57,10 @@ struct unix_sock {
struct list_head link;
atomic_long_t inflight;
spinlock_t lock;
- unsigned int gc_candidate : 1;
- unsigned int gc_maybe_cycle : 1;
unsigned char recursion_level;
+ unsigned long gc_flags;
+#define UNIX_GC_CANDIDATE 0
+#define UNIX_GC_MAYBE_CYCLE 1
struct socket_wq peer_wq;
};
#define unix_sk(__sk) ((struct unix_sock *)__sk)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index ea81f0ef6492..10eb9b389014 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -193,11 +193,11 @@ static inline bool bdaddr_type_is_le(__u8 type)
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} })
/* Copy, swap, convert BD Address */
-static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
{
return memcmp(ba1, ba2, sizeof(bdaddr_t));
}
-static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
{
memcpy(dst, src, sizeof(bdaddr_t));
}
@@ -231,7 +231,7 @@ struct bt_sock_list {
};
int bt_sock_register(int proto, const struct net_proto_family *ops);
-int bt_sock_unregister(int proto);
+void bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -259,12 +259,23 @@ struct l2cap_ctrl {
__u8 retries;
};
+struct hci_dev;
+
+typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
+
+struct hci_req_ctrl {
+ bool start;
+ u8 event;
+ hci_req_complete_t complete;
+};
+
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
__u8 force_active;
struct l2cap_ctrl control;
+ struct hci_req_ctrl req;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 7f12c25f1fca..e0512aaef4b8 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -119,10 +119,16 @@ enum {
HCI_CONNECTABLE,
HCI_DISCOVERABLE,
HCI_LINK_SECURITY,
- HCI_PENDING_CLASS,
HCI_PERIODIC_INQ,
+ HCI_FAST_CONNECTABLE,
};
+/* A mask for the flags that are supposed to remain when a reset happens
+ * or the HCI device is closed.
+ */
+#define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \
+ BIT(HCI_FAST_CONNECTABLE))
+
/* HCI ioctl defines */
#define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int)
@@ -881,12 +887,25 @@ struct hci_rp_read_data_block_size {
__le16 num_blocks;
} __packed;
+#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
+struct hci_rp_read_page_scan_activity {
+ __u8 status;
+ __le16 interval;
+ __le16 window;
+} __packed;
+
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct hci_cp_write_page_scan_activity {
__le16 interval;
__le16 window;
} __packed;
+#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
+struct hci_rp_read_page_scan_type {
+ __u8 status;
+ __u8 type;
+} __packed;
+
#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
#define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01
@@ -965,6 +984,9 @@ struct hci_cp_le_set_adv_data {
#define HCI_OP_LE_SET_ADV_ENABLE 0x200a
+#define LE_SCAN_PASSIVE 0x00
+#define LE_SCAN_ACTIVE 0x01
+
#define HCI_OP_LE_SET_SCAN_PARAM 0x200b
struct hci_cp_le_set_scan_param {
__u8 type;
@@ -974,8 +996,10 @@ struct hci_cp_le_set_scan_param {
__u8 filter_policy;
} __packed;
-#define LE_SCANNING_DISABLED 0x00
-#define LE_SCANNING_ENABLED 0x01
+#define LE_SCAN_DISABLE 0x00
+#define LE_SCAN_ENABLE 0x01
+#define LE_SCAN_FILTER_DUP_DISABLE 0x00
+#define LE_SCAN_FILTER_DUP_ENABLE 0x01
#define HCI_OP_LE_SET_SCAN_ENABLE 0x200c
struct hci_cp_le_set_scan_enable {
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 90cf75afcb02..35a57cd1704c 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -134,6 +134,8 @@ struct amp_assoc {
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
};
+#define HCI_MAX_PAGES 3
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -151,8 +153,8 @@ struct hci_dev {
__u8 dev_class[3];
__u8 major_class;
__u8 minor_class;
- __u8 features[8];
- __u8 host_features[8];
+ __u8 max_page;
+ __u8 features[HCI_MAX_PAGES][8];
__u8 le_features[8];
__u8 le_white_list_size;
__u8 le_states[8];
@@ -165,6 +167,10 @@ struct hci_dev {
__u16 voice_setting;
__u8 io_capability;
__s8 inq_tx_power;
+ __u16 page_scan_interval;
+ __u16 page_scan_window;
+ __u8 page_scan_type;
+
__u16 devid_source;
__u16 devid_vendor;
__u16 devid_product;
@@ -240,6 +246,7 @@ struct hci_dev {
struct sk_buff_head raw_q;
struct sk_buff_head cmd_q;
+ struct sk_buff *recv_evt;
struct sk_buff *sent_cmd;
struct sk_buff *reassembly[NUM_REASSEMBLY];
@@ -248,8 +255,6 @@ struct hci_dev {
__u32 req_status;
__u32 req_result;
- __u16 init_last_cmd;
-
struct list_head mgmt_pending;
struct discovery_state discovery;
@@ -266,8 +271,6 @@ struct hci_dev {
struct hci_dev_stats stat;
- struct sk_buff_head driver_init;
-
atomic_t promisc;
struct dentry *debugfs;
@@ -290,6 +293,7 @@ struct hci_dev {
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
+ int (*setup)(struct hci_dev *hdev);
int (*send)(struct sk_buff *skb);
void (*notify)(struct hci_dev *hdev, unsigned int evt);
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
@@ -311,7 +315,7 @@ struct hci_conn {
bool out;
__u8 attempt;
__u8 dev_class[3];
- __u8 features[8];
+ __u8 features[HCI_MAX_PAGES][8];
__u16 interval;
__u16 pkt_type;
__u16 link_policy;
@@ -343,7 +347,6 @@ struct hci_conn {
struct timer_list auto_accept_timer;
struct device dev;
- atomic_t devref;
struct hci_dev *hdev;
void *l2cap_data;
@@ -574,7 +577,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
+void hci_disconnect(struct hci_conn *conn, __u8 reason);
void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
@@ -582,7 +585,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
-void hci_conn_accept(struct hci_conn *conn, int mask);
struct hci_chan *hci_chan_create(struct hci_conn *conn);
void hci_chan_del(struct hci_chan *chan);
@@ -599,8 +601,36 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
-void hci_conn_hold_device(struct hci_conn *conn);
-void hci_conn_put_device(struct hci_conn *conn);
+/*
+ * hci_conn_get() and hci_conn_put() are used to control the life-time of an
+ * "hci_conn" object. They do not guarantee that the hci_conn object is running,
+ * working or anything else. They just guarantee that the object is available
+ * and can be dereferenced. So you can use its locks, local variables and any
+ * other constant data.
+ * Before accessing runtime data, you _must_ lock the object and then check that
+ * it is still running. As soon as you release the locks, the connection might
+ * get dropped, though.
+ *
+ * On the other hand, hci_conn_hold() and hci_conn_drop() are used to control
+ * how long the underlying connection is held. So every channel that runs on the
+ * hci_conn object calls this to prevent the connection from disappearing. As
+ * long as you hold a device, you must also guarantee that you have a valid
+ * reference to the device via hci_conn_get() (or the initial reference from
+ * hci_conn_add()).
+ * The hold()/drop() ref-count is known to drop below 0 sometimes, which doesn't
+ * break because nobody cares for that. But this means, we cannot use
+ * _get()/_drop() in it, but require the caller to have a valid ref (FIXME).
+ */
+
+static inline void hci_conn_get(struct hci_conn *conn)
+{
+ get_device(&conn->dev);
+}
+
+static inline void hci_conn_put(struct hci_conn *conn)
+{
+ put_device(&conn->dev);
+}
static inline void hci_conn_hold(struct hci_conn *conn)
{
@@ -610,7 +640,7 @@ static inline void hci_conn_hold(struct hci_conn *conn)
cancel_delayed_work(&conn->disc_work);
}
-static inline void hci_conn_put(struct hci_conn *conn)
+static inline void hci_conn_drop(struct hci_conn *conn)
{
BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
@@ -742,8 +772,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_update_ad(struct hci_dev *hdev);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
@@ -760,29 +788,29 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
/* ----- LMP capabilities ----- */
-#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
-#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
-#define lmp_hold_capable(dev) ((dev)->features[0] & LMP_HOLD)
-#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
-#define lmp_park_capable(dev) ((dev)->features[1] & LMP_PARK)
-#define lmp_inq_rssi_capable(dev) ((dev)->features[3] & LMP_RSSI_INQ)
-#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
-#define lmp_bredr_capable(dev) (!((dev)->features[4] & LMP_NO_BREDR))
-#define lmp_le_capable(dev) ((dev)->features[4] & LMP_LE)
-#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
-#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC)
-#define lmp_ext_inq_capable(dev) ((dev)->features[6] & LMP_EXT_INQ)
-#define lmp_le_br_capable(dev) !!((dev)->features[6] & LMP_SIMUL_LE_BR)
-#define lmp_ssp_capable(dev) ((dev)->features[6] & LMP_SIMPLE_PAIR)
-#define lmp_no_flush_capable(dev) ((dev)->features[6] & LMP_NO_FLUSH)
-#define lmp_lsto_capable(dev) ((dev)->features[7] & LMP_LSTO)
-#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR)
-#define lmp_ext_feat_capable(dev) ((dev)->features[7] & LMP_EXTFEATURES)
+#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT)
+#define lmp_rswitch_capable(dev) ((dev)->features[0][0] & LMP_RSWITCH)
+#define lmp_hold_capable(dev) ((dev)->features[0][0] & LMP_HOLD)
+#define lmp_sniff_capable(dev) ((dev)->features[0][0] & LMP_SNIFF)
+#define lmp_park_capable(dev) ((dev)->features[0][1] & LMP_PARK)
+#define lmp_inq_rssi_capable(dev) ((dev)->features[0][3] & LMP_RSSI_INQ)
+#define lmp_esco_capable(dev) ((dev)->features[0][3] & LMP_ESCO)
+#define lmp_bredr_capable(dev) (!((dev)->features[0][4] & LMP_NO_BREDR))
+#define lmp_le_capable(dev) ((dev)->features[0][4] & LMP_LE)
+#define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
+#define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
+#define lmp_ext_inq_capable(dev) ((dev)->features[0][6] & LMP_EXT_INQ)
+#define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & LMP_SIMUL_LE_BR))
+#define lmp_ssp_capable(dev) ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
+#define lmp_no_flush_capable(dev) ((dev)->features[0][6] & LMP_NO_FLUSH)
+#define lmp_lsto_capable(dev) ((dev)->features[0][7] & LMP_LSTO)
+#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[0][7] & LMP_INQ_TX_PWR)
+#define lmp_ext_feat_capable(dev) ((dev)->features[0][7] & LMP_EXTFEATURES)
/* ----- Extended LMP capabilities ----- */
-#define lmp_host_ssp_capable(dev) ((dev)->host_features[0] & LMP_HOST_SSP)
-#define lmp_host_le_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE)
-#define lmp_host_le_br_capable(dev) !!((dev)->host_features[0] & LMP_HOST_LE_BREDR)
+#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP)
+#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
+#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
/* returns true if at least one AMP active */
static inline bool hci_amp_capable(void)
@@ -1041,7 +1069,31 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb);
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
+struct hci_request {
+ struct hci_dev *hdev;
+ struct sk_buff_head cmd_q;
+
+ /* If something goes wrong when building the HCI request, the error
+ * value is stored in this field.
+ */
+ int err;
+};
+
+void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
+int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param);
+void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param, u8 event);
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
+
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u32 timeout);
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u8 event, u32 timeout);
+
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
+ const void *param);
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
@@ -1153,7 +1205,7 @@ struct hci_sec_filter {
#define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock)
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result);
+void hci_update_ad(struct hci_request *req);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index cdd33021f831..fb94cf13c777 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -583,6 +583,14 @@ struct l2cap_conn {
struct list_head chan_l;
struct mutex chan_lock;
+ struct kref ref;
+ struct list_head users;
+};
+
+struct l2cap_user {
+ struct list_head list;
+ int (*probe) (struct l2cap_conn *conn, struct l2cap_user *user);
+ void (*remove) (struct l2cap_conn *conn, struct l2cap_user *user);
};
#define L2CAP_INFO_CL_MTU_REQ_SENT 0x01
@@ -786,6 +794,7 @@ extern bool disable_ertm;
int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);
+bool l2cap_is_socket(struct socket *sock);
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan);
int __l2cap_wait_ack(struct sock *sk);
@@ -812,4 +821,10 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
u8 status);
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
+void l2cap_conn_get(struct l2cap_conn *conn);
+void l2cap_conn_put(struct l2cap_conn *conn);
+
+int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
+void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
+
#endif /* __L2CAP_H */
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index e2e3ecad1008..7afd4199d6b6 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -158,7 +158,6 @@ struct rfcomm_session {
struct timer_list timer;
unsigned long state;
unsigned long flags;
- atomic_t refcnt;
int initiator;
/* Default DLC parameters */
@@ -276,11 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
bdaddr_t *dst);
-static inline void rfcomm_session_hold(struct rfcomm_session *s)
-{
- atomic_inc(&s->refcnt);
-}
-
/* ---- RFCOMM sockets ---- */
struct sockaddr_rc {
sa_family_t rc_family;
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
index ef2dd9438bb1..028b754ae9b1 100644
--- a/include/net/caif/caif_dev.h
+++ b/include/net/caif/caif_dev.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/caif_device.h b/include/net/caif/caif_device.h
index d02f044adb8a..d6e3c4267c81 100644
--- a/include/net/caif/caif_device.h
+++ b/include/net/caif/caif_device.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
index bcb9cc3ce98b..4795e817afe5 100644
--- a/include/net/caif/caif_hsi.h
+++ b/include/net/caif/caif_hsi.h
@@ -1,6 +1,5 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
* Author: Daniel Martensson / daniel.martensson@stericsson.com
* Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com
* License terms: GNU General Public License (GPL) version 2
diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h
index 0f3a39125f90..94e5ed64dc6d 100644
--- a/include/net/caif/caif_layer.h
+++ b/include/net/caif/caif_layer.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/caif_shm.h b/include/net/caif/caif_shm.h
deleted file mode 100644
index 5bcce55438cf..000000000000
--- a/include/net/caif/caif_shm.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson AB 2010
- * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
- * Author: Amarnath Revanna / amarnath.bangalore.revanna@stericsson.com
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef CAIF_SHM_H_
-#define CAIF_SHM_H_
-
-struct shmdev_layer {
- u32 shm_base_addr;
- u32 shm_total_sz;
- u32 shm_id;
- u32 shm_loopback;
- void *hmbx;
- int (*pshmdev_mbxsend) (u32 shm_id, u32 mbx_msg);
- int (*pshmdev_mbxsetup) (void *pshmdrv_cb,
- struct shmdev_layer *pshm_dev, void *pshm_drv);
- struct net_device *pshm_netdev;
-};
-
-extern int caif_shmcore_probe(struct shmdev_layer *pshm_dev);
-extern void caif_shmcore_remove(struct net_device *pshm_netdev);
-
-#endif
diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h
index 90b4ff8bad83..70bfd017581f 100644
--- a/include/net/caif/cfcnfg.h
+++ b/include/net/caif/cfcnfg.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h
index 9e5425b4a1d7..f2ae33d23baf 100644
--- a/include/net/caif/cfctrl.h
+++ b/include/net/caif/cfctrl.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h
index afac1a48cce7..a06e33fbaa8b 100644
--- a/include/net/caif/cffrml.h
+++ b/include/net/caif/cffrml.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h
index 5847a196b8ad..752999572f21 100644
--- a/include/net/caif/cfmuxl.h
+++ b/include/net/caif/cfmuxl.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h
index 83a89ba3005b..1c1ad46250d5 100644
--- a/include/net/caif/cfpkt.h
+++ b/include/net/caif/cfpkt.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h
index f121299a3427..b5b020f3c72e 100644
--- a/include/net/caif/cfserl.h
+++ b/include/net/caif/cfserl.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h
index 0f5905241843..cd47705c2cc3 100644
--- a/include/net/caif/cfsrvl.h
+++ b/include/net/caif/cfsrvl.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d581c6de5d64..26b5b692c22b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -611,22 +611,10 @@ struct cfg80211_ap_settings {
};
/**
- * enum plink_action - actions to perform in mesh peers
- *
- * @PLINK_ACTION_INVALID: action 0 is reserved
- * @PLINK_ACTION_OPEN: start mesh peer link establishment
- * @PLINK_ACTION_BLOCK: block traffic from this mesh peer
- */
-enum plink_actions {
- PLINK_ACTION_INVALID,
- PLINK_ACTION_OPEN,
- PLINK_ACTION_BLOCK,
-};
-
-/**
* enum station_parameters_apply_mask - station parameter values to apply
* @STATION_PARAM_APPLY_UAPSD: apply new uAPSD parameters (uapsd_queues, max_sp)
* @STATION_PARAM_APPLY_CAPABILITY: apply new capability
+ * @STATION_PARAM_APPLY_PLINK_STATE: apply new plink state
*
* Not all station parameters have in-band "no change" signalling,
* for those that don't these flags will are used.
@@ -634,6 +622,7 @@ enum plink_actions {
enum station_parameters_apply_mask {
STATION_PARAM_APPLY_UAPSD = BIT(0),
STATION_PARAM_APPLY_CAPABILITY = BIT(1),
+ STATION_PARAM_APPLY_PLINK_STATE = BIT(2),
};
/**
@@ -669,7 +658,7 @@ enum station_parameters_apply_mask {
* @ext_capab_len: number of extended capabilities
*/
struct station_parameters {
- u8 *supported_rates;
+ const u8 *supported_rates;
struct net_device *vlan;
u32 sta_flags_mask, sta_flags_set;
u32 sta_modify_mask;
@@ -678,17 +667,60 @@ struct station_parameters {
u8 supported_rates_len;
u8 plink_action;
u8 plink_state;
- struct ieee80211_ht_cap *ht_capa;
- struct ieee80211_vht_cap *vht_capa;
+ const struct ieee80211_ht_cap *ht_capa;
+ const struct ieee80211_vht_cap *vht_capa;
u8 uapsd_queues;
u8 max_sp;
enum nl80211_mesh_power_mode local_pm;
u16 capability;
- u8 *ext_capab;
+ const u8 *ext_capab;
u8 ext_capab_len;
};
/**
+ * enum cfg80211_station_type - the type of station being modified
+ * @CFG80211_STA_AP_CLIENT: client of an AP interface
+ * @CFG80211_STA_AP_MLME_CLIENT: client of an AP interface that has
+ * the AP MLME in the device
+ * @CFG80211_STA_AP_STA: AP station on managed interface
+ * @CFG80211_STA_IBSS: IBSS station
+ * @CFG80211_STA_TDLS_PEER_SETUP: TDLS peer on managed interface (dummy entry
+ * while TDLS setup is in progress, it moves out of this state when
+ * being marked authorized; use this only if TDLS with external setup is
+ * supported/used)
+ * @CFG80211_STA_TDLS_PEER_ACTIVE: TDLS peer on managed interface (active
+ * entry that is operating, has been marked authorized by userspace)
+ * @CFG80211_STA_MESH_PEER_KERNEL: peer on mesh interface (kernel managed)
+ * @CFG80211_STA_MESH_PEER_USER: peer on mesh interface (user managed)
+ */
+enum cfg80211_station_type {
+ CFG80211_STA_AP_CLIENT,
+ CFG80211_STA_AP_MLME_CLIENT,
+ CFG80211_STA_AP_STA,
+ CFG80211_STA_IBSS,
+ CFG80211_STA_TDLS_PEER_SETUP,
+ CFG80211_STA_TDLS_PEER_ACTIVE,
+ CFG80211_STA_MESH_PEER_KERNEL,
+ CFG80211_STA_MESH_PEER_USER,
+};
+
+/**
+ * cfg80211_check_station_change - validate parameter changes
+ * @wiphy: the wiphy this operates on
+ * @params: the new parameters for a station
+ * @statype: the type of station being modified
+ *
+ * Utility function for the @change_station driver method. Call this function
+ * with the appropriate station type looking up the station (and checking that
+ * it exists). It will verify whether the station change is acceptable, and if
+ * not will return an error code. Note that it may modify the parameters for
+ * backward compatibility reasons, so don't use them before calling this.
+ */
+int cfg80211_check_station_change(struct wiphy *wiphy,
+ struct station_parameters *params,
+ enum cfg80211_station_type statype);
+
+/**
* enum station_info_flags - station information flags
*
* Used by the driver to indicate which info in &struct station_info
@@ -1119,6 +1151,7 @@ struct mesh_config {
* @ie_len: length of vendor information elements
* @is_authenticated: this mesh requires authentication
* @is_secure: this mesh uses security
+ * @user_mpm: userspace handles all MPM functions
* @dtim_period: DTIM period to use
* @beacon_interval: beacon interval to use
* @mcast_rate: multicat rate for Mesh Node [6Mbps is the default for 802.11a]
@@ -1136,6 +1169,7 @@ struct mesh_setup {
u8 ie_len;
bool is_authenticated;
bool is_secure;
+ bool user_mpm;
u8 dtim_period;
u16 beacon_interval;
int mcast_rate[IEEE80211_NUM_BANDS];
@@ -1398,9 +1432,11 @@ struct cfg80211_auth_request {
* enum cfg80211_assoc_req_flags - Over-ride default behaviour in association.
*
* @ASSOC_REQ_DISABLE_HT: Disable HT (802.11n)
+ * @ASSOC_REQ_DISABLE_VHT: Disable VHT
*/
enum cfg80211_assoc_req_flags {
ASSOC_REQ_DISABLE_HT = BIT(0),
+ ASSOC_REQ_DISABLE_VHT = BIT(1),
};
/**
@@ -1422,6 +1458,8 @@ enum cfg80211_assoc_req_flags {
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
* will be used in ht_capa. Un-supported values will be ignored.
* @ht_capa_mask: The bits of ht_capa which are to be used.
+ * @vht_capa: VHT capability override
+ * @vht_capa_mask: VHT capability mask indicating which fields to use
*/
struct cfg80211_assoc_request {
struct cfg80211_bss *bss;
@@ -1432,6 +1470,7 @@ struct cfg80211_assoc_request {
u32 flags;
struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask;
+ struct ieee80211_vht_cap vht_capa, vht_capa_mask;
};
/**
@@ -1542,6 +1581,8 @@ struct cfg80211_ibss_params {
* @ht_capa: HT Capabilities over-rides. Values set in ht_capa_mask
* will be used in ht_capa. Un-supported values will be ignored.
* @ht_capa_mask: The bits of ht_capa which are to be used.
+ * @vht_capa: VHT Capability overrides
+ * @vht_capa_mask: The bits of vht_capa which are to be used.
*/
struct cfg80211_connect_params {
struct ieee80211_channel *channel;
@@ -1560,6 +1601,8 @@ struct cfg80211_connect_params {
int bg_scan_period;
struct ieee80211_ht_cap ht_capa;
struct ieee80211_ht_cap ht_capa_mask;
+ struct ieee80211_vht_cap vht_capa;
+ struct ieee80211_vht_cap vht_capa_mask;
};
/**
@@ -1722,6 +1765,21 @@ struct cfg80211_gtk_rekey_data {
};
/**
+ * struct cfg80211_update_ft_ies_params - FT IE Information
+ *
+ * This structure provides information needed to update the fast transition IE
+ *
+ * @md: The Mobility Domain ID, 2 Octet value
+ * @ie: Fast Transition IEs
+ * @ie_len: Length of ft_ie in octets
+ */
+struct cfg80211_update_ft_ies_params {
+ u16 md;
+ const u8 *ie;
+ size_t ie_len;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1781,9 +1839,8 @@ struct cfg80211_gtk_rekey_data {
* @change_station: Modify a given station. Note that flags changes are not much
* validated in cfg80211, in particular the auth/assoc/authorized flags
* might come to the driver in invalid combinations -- make sure to check
- * them, also against the existing state! Also, supported_rates changes are
- * not checked in station mode -- drivers need to reject (or ignore) them
- * for anything but TDLS peers.
+ * them, also against the existing state! Drivers must call
+ * cfg80211_check_station_change() to validate the information.
* @get_station: get station information for the station identified by @mac
* @dump_station: dump station callback -- resume dump at index @idx
*
@@ -1941,6 +1998,16 @@ struct cfg80211_gtk_rekey_data {
* advertise the support for MAC based ACL have to implement this callback.
*
* @start_radar_detection: Start radar detection in the driver.
+ *
+ * @update_ft_ies: Provide updated Fast BSS Transition information to the
+ * driver. If the SME is in the driver/firmware, this information can be
+ * used in building Authentication and Reassociation Request frames.
+ *
+ * @crit_proto_start: Indicates a critical protocol needs more link reliability
+ * for a given duration (milliseconds). The protocol is provided so the
+ * driver can take the most appropriate actions.
+ * @crit_proto_stop: Indicates critical protocol no longer needs increased link
+ * reliability. This operation can not fail.
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2168,6 +2235,14 @@ struct cfg80211_ops {
int (*start_radar_detection)(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef);
+ int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_update_ft_ies_params *ftie);
+ int (*crit_proto_start)(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ enum nl80211_crit_proto_id protocol,
+ u16 duration);
+ void (*crit_proto_stop)(struct wiphy *wiphy,
+ struct wireless_dev *wdev);
};
/*
@@ -2485,6 +2560,8 @@ struct wiphy_wowlan_support {
* @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
* @ht_capa_mod_mask: Specify what ht_cap values can be over-ridden.
* If null, then none can be over-ridden.
+ * @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
+ * If null, then none can be over-ridden.
*
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL.
@@ -2593,6 +2670,7 @@ struct wiphy {
struct dentry *debugfsdir;
const struct ieee80211_ht_cap *ht_capa_mod_mask;
+ const struct ieee80211_vht_cap *vht_capa_mod_mask;
#ifdef CONFIG_NET_NS
/* the network namespace this phy lives in currently */
@@ -3958,6 +4036,17 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
void cfg80211_ch_switch_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef);
+/**
+ * ieee80211_operating_class_to_band - convert operating class to band
+ *
+ * @operating_class: the operating class to convert
+ * @band: band pointer to fill
+ *
+ * Returns %true if the conversion was successful, %false otherwise.
+ */
+bool ieee80211_operating_class_to_band(u8 operating_class,
+ enum ieee80211_band *band);
+
/*
* cfg80211_tdls_oper_request - request userspace to perform TDLS operation
* @dev: the device on which the operation is requested
@@ -4002,6 +4091,30 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
void cfg80211_unregister_wdev(struct wireless_dev *wdev);
/**
+ * struct cfg80211_ft_event - FT Information Elements
+ * @ies: FT IEs
+ * @ies_len: length of the FT IE in bytes
+ * @target_ap: target AP's MAC address
+ * @ric_ies: RIC IE
+ * @ric_ies_len: length of the RIC IE in bytes
+ */
+struct cfg80211_ft_event_params {
+ const u8 *ies;
+ size_t ies_len;
+ const u8 *target_ap;
+ const u8 *ric_ies;
+ size_t ric_ies_len;
+};
+
+/**
+ * cfg80211_ft_event - notify userspace about FT IE and RIC IE
+ * @netdev: network device
+ * @ft_event: IE information
+ */
+void cfg80211_ft_event(struct net_device *netdev,
+ struct cfg80211_ft_event_params *ft_event);
+
+/**
* cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
* @ies: the input IE buffer
* @len: the input length
@@ -4036,6 +4149,17 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
struct cfg80211_wowlan_wakeup *wakeup,
gfp_t gfp);
+/**
+ * cfg80211_crit_proto_stopped() - indicate critical protocol stopped by driver.
+ *
+ * @wdev: the wireless device for which critical protocol is stopped.
+ *
+ * This function can be called by the driver to indicate it has reverted
+ * operation back to normal. One reason could be that the duration given
+ * by .crit_proto_start() has expired.
+ */
+void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
index 2581638f4a3d..0fee0617fb7d 100644
--- a/include/net/cls_cgroup.h
+++ b/include/net/cls_cgroup.h
@@ -24,7 +24,7 @@ struct cgroup_cls_state
u32 classid;
};
-extern void sock_update_classid(struct sock *sk, struct task_struct *task);
+extern void sock_update_classid(struct sock *sk);
#if IS_BUILTIN(CONFIG_NET_CLS_CGROUP)
static inline u32 task_cls_classid(struct task_struct *p)
@@ -61,7 +61,7 @@ static inline u32 task_cls_classid(struct task_struct *p)
}
#endif
#else /* !CGROUP_NET_CLS_CGROUP */
-static inline void sock_update_classid(struct sock *sk, struct task_struct *task)
+static inline void sock_update_classid(struct sock *sk)
{
}
diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h
index 1ee9d4bda30d..74004af31c48 100644
--- a/include/net/dn_fib.h
+++ b/include/net/dn_fib.h
@@ -1,24 +1,9 @@
#ifndef _NET_DN_FIB_H
#define _NET_DN_FIB_H
-/* WARNING: The ordering of these elements must match ordering
- * of RTA_* rtnetlink attribute numbers.
- */
-struct dn_kern_rta {
- void *rta_dst;
- void *rta_src;
- int *rta_iif;
- int *rta_oif;
- void *rta_gw;
- u32 *rta_priority;
- void *rta_prefsrc;
- struct rtattr *rta_mx;
- struct rtattr *rta_mp;
- unsigned char *rta_protoinfo;
- u32 *rta_flow;
- struct rta_cacheinfo *rta_ci;
- struct rta_session *rta_sess;
-};
+#include <linux/netlink.h>
+
+extern const struct nla_policy rtm_dn_policy[];
struct dn_fib_res {
struct fib_rule *r;
@@ -93,10 +78,10 @@ struct dn_fib_table {
u32 n;
int (*insert)(struct dn_fib_table *t, struct rtmsg *r,
- struct dn_kern_rta *rta, struct nlmsghdr *n,
+ struct nlattr *attrs[], struct nlmsghdr *n,
struct netlink_skb_parms *req);
int (*delete)(struct dn_fib_table *t, struct rtmsg *r,
- struct dn_kern_rta *rta, struct nlmsghdr *n,
+ struct nlattr *attrs[], struct nlmsghdr *n,
struct netlink_skb_parms *req);
int (*lookup)(struct dn_fib_table *t, const struct flowidn *fld,
struct dn_fib_res *res);
@@ -116,13 +101,12 @@ extern void dn_fib_cleanup(void);
extern int dn_fib_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg);
extern struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r,
- struct dn_kern_rta *rta,
+ struct nlattr *attrs[],
const struct nlmsghdr *nlh, int *errp);
extern int dn_fib_semantic_match(int type, struct dn_fib_info *fi,
const struct flowidn *fld,
struct dn_fib_res *res);
extern void dn_fib_release_info(struct dn_fib_info *fi);
-extern __le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type);
extern void dn_fib_flush(void);
extern void dn_fib_select_multipath(const struct flowidn *fld,
struct dn_fib_res *res);
diff --git a/include/net/firewire.h b/include/net/firewire.h
new file mode 100644
index 000000000000..31bcbfe7a220
--- /dev/null
+++ b/include/net/firewire.h
@@ -0,0 +1,25 @@
+#ifndef _NET_FIREWIRE_H
+#define _NET_FIREWIRE_H
+
+/* Pseudo L2 address */
+#define FWNET_ALEN 16
+union fwnet_hwaddr {
+ u8 u[FWNET_ALEN];
+ /* "Hardware address" defined in RFC2734/RF3146 */
+ struct {
+ __be64 uniq_id; /* EUI-64 */
+ u8 max_rec; /* max packet size */
+ u8 sspd; /* max speed */
+ __be16 fifo_hi; /* hi 16bits of FIFO addr */
+ __be32 fifo_lo; /* lo 32bits of FIFO addr */
+ } __packed uc;
+};
+
+/* Pseudo L2 Header */
+#define FWNET_HLEN 18
+struct fwnet_header {
+ u8 h_dest[FWNET_ALEN]; /* destination address */
+ __be16 h_proto; /* packet type ID field */
+} __packed;
+
+#endif
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index bdfbe68c1c3b..93024a47e0e2 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -50,6 +50,7 @@ struct genl_family {
unsigned int version;
unsigned int maxattr;
bool netnsok;
+ bool parallel_ops;
int (*pre_doit)(struct genl_ops *ops,
struct sk_buff *skb,
struct genl_info *info);
diff --git a/include/net/gre.h b/include/net/gre.h
index 82665474bcb7..9f03a390c826 100644
--- a/include/net/gre.h
+++ b/include/net/gre.h
@@ -2,6 +2,7 @@
#define __LINUX_GRE_H
#include <linux/skbuff.h>
+#include <net/ip_tunnels.h>
#define GREPROTO_CISCO 0
#define GREPROTO_PPTP 1
@@ -12,7 +13,57 @@ struct gre_protocol {
void (*err_handler)(struct sk_buff *skb, u32 info);
};
+struct gre_base_hdr {
+ __be16 flags;
+ __be16 protocol;
+};
+#define GRE_HEADER_SECTION 4
+
int gre_add_protocol(const struct gre_protocol *proto, u8 version);
int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+static inline __be16 gre_flags_to_tnl_flags(__be16 flags)
+{
+ __be16 tflags = 0;
+
+ if (flags & GRE_CSUM)
+ tflags |= TUNNEL_CSUM;
+ if (flags & GRE_ROUTING)
+ tflags |= TUNNEL_ROUTING;
+ if (flags & GRE_KEY)
+ tflags |= TUNNEL_KEY;
+ if (flags & GRE_SEQ)
+ tflags |= TUNNEL_SEQ;
+ if (flags & GRE_STRICT)
+ tflags |= TUNNEL_STRICT;
+ if (flags & GRE_REC)
+ tflags |= TUNNEL_REC;
+ if (flags & GRE_VERSION)
+ tflags |= TUNNEL_VERSION;
+
+ return tflags;
+}
+
+static inline __be16 tnl_flags_to_gre_flags(__be16 tflags)
+{
+ __be16 flags = 0;
+
+ if (tflags & TUNNEL_CSUM)
+ flags |= GRE_CSUM;
+ if (tflags & TUNNEL_ROUTING)
+ flags |= GRE_ROUTING;
+ if (tflags & TUNNEL_KEY)
+ flags |= GRE_KEY;
+ if (tflags & TUNNEL_SEQ)
+ flags |= GRE_SEQ;
+ if (tflags & TUNNEL_STRICT)
+ flags |= GRE_STRICT;
+ if (tflags & TUNNEL_REC)
+ flags |= GRE_REC;
+ if (tflags & TUNNEL_VERSION)
+ flags |= GRE_VERSION;
+
+ return flags;
+}
+
#endif
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index d104c882fc29..8196d5d40359 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -85,6 +85,8 @@ struct wpan_phy;
* Use wpan_wpy_put to put that reference.
*/
struct ieee802154_mlme_ops {
+ /* The following fields are optional (can be NULL). */
+
int (*assoc_req)(struct net_device *dev,
struct ieee802154_addr *addr,
u8 channel, u8 page, u8 cap);
@@ -101,6 +103,8 @@ struct ieee802154_mlme_ops {
int (*scan_req)(struct net_device *dev,
u8 type, u32 channels, u8 page, u8 duration);
+ /* The fields below are required. */
+
struct wpan_phy *(*get_phy)(const struct net_device *dev);
/*
@@ -110,7 +114,6 @@ struct ieee802154_mlme_ops {
u16 (*get_pan_id)(const struct net_device *dev);
u16 (*get_short_addr)(const struct net_device *dev);
u8 (*get_dsn)(const struct net_device *dev);
- u8 (*get_bsn)(const struct net_device *dev);
};
/* The IEEE 802.15.4 standard defines 2 type of the devices:
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index 93563221d29a..100fb8cec17c 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -71,6 +71,8 @@ struct inet6_ifaddr {
struct inet6_ifaddr *ifpub;
int regen_count;
#endif
+ bool tokenized;
+
struct rcu_head rcu;
};
@@ -187,6 +189,8 @@ struct inet6_dev {
struct list_head tempaddr_list;
#endif
+ struct in6_addr token;
+
struct neigh_parms *nd_parms;
struct inet6_dev *next;
struct ipv6_devconf cnf;
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index 183292722f6e..de2c78529afa 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -133,6 +133,8 @@ struct inet_connection_sock {
#define ICSK_TIME_RETRANS 1 /* Retransmit timer */
#define ICSK_TIME_DACK 2 /* Delayed ack timer */
#define ICSK_TIME_PROBE0 3 /* Zero window probe timer */
+#define ICSK_TIME_EARLY_RETRANS 4 /* Early retransmit timer */
+#define ICSK_TIME_LOSS_PROBE 5 /* Tail loss probe timer */
static inline struct inet_connection_sock *inet_csk(const struct sock *sk)
{
@@ -222,7 +224,8 @@ static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what,
when = max_when;
}
- if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) {
+ if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0 ||
+ what == ICSK_TIME_EARLY_RETRANS || what == ICSK_TIME_LOSS_PROBE) {
icsk->icsk_pending = what;
icsk->icsk_timeout = jiffies + when;
sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 0a1dcc2fa2f5..4182c9be8bb5 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -41,7 +41,7 @@ struct inet_frag_queue {
struct netns_frags *net;
};
-#define INETFRAGS_HASHSZ 64
+#define INETFRAGS_HASHSZ 1024
/* averaged:
* max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ /
@@ -50,10 +50,16 @@ struct inet_frag_queue {
*/
#define INETFRAGS_MAXDEPTH 128
+struct inet_frag_bucket {
+ struct hlist_head chain;
+ spinlock_t chain_lock;
+};
+
struct inet_frags {
- struct hlist_head hash[INETFRAGS_HASHSZ];
+ struct inet_frag_bucket hash[INETFRAGS_HASHSZ];
/* This rwlock is a global lock (seperate per IPv4, IPv6 and
* netfilter). Important to keep this on a seperate cacheline.
+ * Its primarily a rebuild protection rwlock.
*/
rwlock_t lock ____cacheline_aligned_in_smp;
int secret_interval;
@@ -143,6 +149,7 @@ static inline void inet_frag_lru_del(struct inet_frag_queue *q)
{
spin_lock(&q->net->lru_lock);
list_del(&q->lru_list);
+ q->net->nqueues--;
spin_unlock(&q->net->lru_lock);
}
@@ -151,6 +158,19 @@ static inline void inet_frag_lru_add(struct netns_frags *nf,
{
spin_lock(&nf->lru_lock);
list_add_tail(&q->lru_list, &nf->lru_list);
+ q->net->nqueues++;
spin_unlock(&nf->lru_lock);
}
+
+/* RFC 3168 support :
+ * We want to check ECN values of all fragments, do detect invalid combinations.
+ * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value.
+ */
+#define IPFRAG_ECN_NOT_ECT 0x01 /* one frag had ECN_NOT_ECT */
+#define IPFRAG_ECN_ECT_1 0x02 /* one frag had ECN_ECT_1 */
+#define IPFRAG_ECN_ECT_0 0x04 /* one frag had ECN_ECT_0 */
+#define IPFRAG_ECN_CE 0x08 /* one frag had ECN_CE */
+
+extern const u8 ip_frag_ecn_table[16];
+
#endif
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index e03047f7090b..4da5de10d1d4 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -3,6 +3,7 @@
#include <linux/ipv6.h>
#include <linux/netdevice.h>
+#include <linux/if_tunnel.h>
#include <linux/ip6_tunnel.h>
#define IP6TUNNEL_ERR_TIMEO (30*HZ)
@@ -68,4 +69,24 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
const struct in6_addr *raddr);
+static inline void ip6tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device_stats *stats = &dev->stats;
+ int pkt_len, err;
+
+ nf_reset(skb);
+ pkt_len = skb->len;
+ err = ip6_local_out(skb);
+
+ if (net_xmit_eval(err) == 0) {
+ struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
+ u64_stats_update_begin(&tstats->syncp);
+ tstats->tx_bytes += pkt_len;
+ tstats->tx_packets++;
+ u64_stats_update_end(&tstats->syncp);
+ } else {
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+ }
+}
#endif
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
new file mode 100644
index 000000000000..4b6f0b28f41f
--- /dev/null
+++ b/include/net/ip_tunnels.h
@@ -0,0 +1,177 @@
+#ifndef __NET_IP_TUNNELS_H
+#define __NET_IP_TUNNELS_H 1
+
+#include <linux/if_tunnel.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/u64_stats_sync.h>
+#include <net/dsfield.h>
+#include <net/gro_cells.h>
+#include <net/inet_ecn.h>
+#include <net/ip.h>
+#include <net/rtnetlink.h>
+
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#endif
+
+/* Keep error state on tunnel for 30 sec */
+#define IPTUNNEL_ERR_TIMEO (30*HZ)
+
+/* 6rd prefix/relay information */
+#ifdef CONFIG_IPV6_SIT_6RD
+struct ip_tunnel_6rd_parm {
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+ u16 prefixlen;
+ u16 relay_prefixlen;
+};
+#endif
+
+struct ip_tunnel_prl_entry {
+ struct ip_tunnel_prl_entry __rcu *next;
+ __be32 addr;
+ u16 flags;
+ struct rcu_head rcu_head;
+};
+
+struct ip_tunnel {
+ struct ip_tunnel __rcu *next;
+ struct hlist_node hash_node;
+ struct net_device *dev;
+
+ int err_count; /* Number of arrived ICMP errors */
+ unsigned long err_time; /* Time when the last ICMP error
+ * arrived */
+
+ /* These four fields used only by GRE */
+ __u32 i_seqno; /* The last seen seqno */
+ __u32 o_seqno; /* The last output seqno */
+ int hlen; /* Precalculated header length */
+ int mlink;
+
+ struct ip_tunnel_parm parms;
+
+ /* for SIT */
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd_parm ip6rd;
+#endif
+ struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */
+ unsigned int prl_count; /* # of entries in PRL */
+ int ip_tnl_net_id;
+ struct gro_cells gro_cells;
+};
+
+#define TUNNEL_CSUM __cpu_to_be16(0x01)
+#define TUNNEL_ROUTING __cpu_to_be16(0x02)
+#define TUNNEL_KEY __cpu_to_be16(0x04)
+#define TUNNEL_SEQ __cpu_to_be16(0x08)
+#define TUNNEL_STRICT __cpu_to_be16(0x10)
+#define TUNNEL_REC __cpu_to_be16(0x20)
+#define TUNNEL_VERSION __cpu_to_be16(0x40)
+#define TUNNEL_NO_KEY __cpu_to_be16(0x80)
+
+struct tnl_ptk_info {
+ __be16 flags;
+ __be16 proto;
+ __be32 key;
+ __be32 seq;
+};
+
+#define PACKET_RCVD 0
+#define PACKET_REJECT 1
+
+#define IP_TNL_HASH_BITS 10
+#define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS)
+
+struct ip_tunnel_net {
+ struct hlist_head *tunnels;
+ struct net_device *fb_tunnel_dev;
+};
+
+int ip_tunnel_init(struct net_device *dev);
+void ip_tunnel_uninit(struct net_device *dev);
+void ip_tunnel_dellink(struct net_device *dev, struct list_head *head);
+int __net_init ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
+ struct rtnl_link_ops *ops, char *devname);
+
+void __net_exit ip_tunnel_delete_net(struct ip_tunnel_net *itn);
+
+void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
+ const struct iphdr *tnl_params);
+int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd);
+int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu);
+
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot);
+struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
+ int link, __be16 flags,
+ __be32 remote, __be32 local,
+ __be32 key);
+
+int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
+ const struct tnl_ptk_info *tpi, bool log_ecn_error);
+int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
+ struct ip_tunnel_parm *p);
+int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
+ struct ip_tunnel_parm *p);
+void ip_tunnel_setup(struct net_device *dev, int net_id);
+
+/* Extract dsfield from inner protocol */
+static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
+ const struct sk_buff *skb)
+{
+ if (skb->protocol == htons(ETH_P_IP))
+ return iph->tos;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ return ipv6_get_dsfield((const struct ipv6hdr *)iph);
+ else
+ return 0;
+}
+
+/* Propogate ECN bits out */
+static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
+ const struct sk_buff *skb)
+{
+ u8 inner = ip_tunnel_get_dsfield(iph, skb);
+
+ return INET_ECN_encapsulate(tos, inner);
+}
+
+static inline void tunnel_ip_select_ident(struct sk_buff *skb,
+ const struct iphdr *old_iph,
+ struct dst_entry *dst)
+{
+ struct iphdr *iph = ip_hdr(skb);
+
+ /* Use inner packet iph-id if possible. */
+ if (skb->protocol == htons(ETH_P_IP) && old_iph->id)
+ iph->id = old_iph->id;
+ else
+ __ip_select_ident(iph, dst,
+ (skb_shinfo(skb)->gso_segs ?: 1) - 1);
+}
+
+static inline void iptunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err;
+ int pkt_len = skb->len - skb_transport_offset(skb);
+ struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
+
+ nf_reset(skb);
+
+ err = ip_local_out(skb);
+ if (likely(net_xmit_eval(err) == 0)) {
+ u64_stats_update_begin(&tstats->syncp);
+ tstats->tx_bytes += pkt_len;
+ tstats->tx_packets++;
+ u64_stats_update_end(&tstats->syncp);
+ } else {
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+ }
+}
+#endif /* __NET_IP_TUNNELS_H */
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index fce8e6b66d55..4c062ccff9aa 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -233,6 +233,21 @@ static inline void ip_vs_addr_copy(int af, union nf_inet_addr *dst,
dst->ip = src->ip;
}
+static inline void ip_vs_addr_set(int af, union nf_inet_addr *dst,
+ const union nf_inet_addr *src)
+{
+#ifdef CONFIG_IP_VS_IPV6
+ if (af == AF_INET6) {
+ dst->in6 = src->in6;
+ return;
+ }
+#endif
+ dst->ip = src->ip;
+ dst->all[1] = 0;
+ dst->all[2] = 0;
+ dst->all[3] = 0;
+}
+
static inline int ip_vs_addr_equal(int af, const union nf_inet_addr *a,
const union nf_inet_addr *b)
{
@@ -344,8 +359,6 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
#define LeaveFunction(level) do {} while (0)
#endif
-#define IP_VS_WAIT_WHILE(expr) while (expr) { cpu_relax(); }
-
/*
* The port number of FTP service (in network order).
@@ -459,7 +472,7 @@ struct ip_vs_estimator {
struct ip_vs_stats {
struct ip_vs_stats_user ustats; /* statistics */
struct ip_vs_estimator est; /* estimator */
- struct ip_vs_cpu_stats *cpustats; /* per cpu counters */
+ struct ip_vs_cpu_stats __percpu *cpustats; /* per cpu counters */
spinlock_t lock; /* spin lock */
struct ip_vs_stats_user ustats0; /* reset values */
};
@@ -566,20 +579,19 @@ struct ip_vs_conn_param {
*/
struct ip_vs_conn {
struct hlist_node c_list; /* hashed list heads */
-#ifdef CONFIG_NET_NS
- struct net *net; /* Name space */
-#endif
/* Protocol, addresses and port numbers */
- u16 af; /* address family */
__be16 cport;
- __be16 vport;
__be16 dport;
- __u32 fwmark; /* Fire wall mark from skb */
+ __be16 vport;
+ u16 af; /* address family */
union nf_inet_addr caddr; /* client address */
union nf_inet_addr vaddr; /* virtual address */
union nf_inet_addr daddr; /* destination address */
volatile __u32 flags; /* status flags */
__u16 protocol; /* Which protocol (TCP/UDP) */
+#ifdef CONFIG_NET_NS
+ struct net *net; /* Name space */
+#endif
/* counter and timer */
atomic_t refcnt; /* reference count */
@@ -593,6 +605,7 @@ struct ip_vs_conn {
* state transition triggerd
* synchronization
*/
+ __u32 fwmark; /* Fire wall mark from skb */
unsigned long sync_endtime; /* jiffies + sent_retries */
/* Control members */
@@ -620,6 +633,8 @@ struct ip_vs_conn {
const struct ip_vs_pe *pe;
char *pe_data;
__u8 pe_data_len;
+
+ struct rcu_head rcu_head;
};
/*
@@ -663,7 +678,7 @@ struct ip_vs_service_user_kern {
u16 af;
u16 protocol;
union nf_inet_addr addr; /* virtual ip address */
- u16 port;
+ __be16 port;
u32 fwmark; /* firwall mark of service */
/* virtual service options */
@@ -671,14 +686,14 @@ struct ip_vs_service_user_kern {
char *pe_name;
unsigned int flags; /* virtual service flags */
unsigned int timeout; /* persistent timeout in sec */
- u32 netmask; /* persistent netmask */
+ __be32 netmask; /* persistent netmask or plen */
};
struct ip_vs_dest_user_kern {
/* destination server address */
union nf_inet_addr addr;
- u16 port;
+ __be16 port;
/* real server options */
unsigned int conn_flags; /* connection flags */
@@ -695,10 +710,9 @@ struct ip_vs_dest_user_kern {
* and the forwarding entries
*/
struct ip_vs_service {
- struct list_head s_list; /* for normal service table */
- struct list_head f_list; /* for fwmark-based service table */
+ struct hlist_node s_list; /* for normal service table */
+ struct hlist_node f_list; /* for fwmark-based service table */
atomic_t refcnt; /* reference counter */
- atomic_t usecnt; /* use counter */
u16 af; /* address family */
__u16 protocol; /* which protocol (TCP/UDP) */
@@ -707,31 +721,41 @@ struct ip_vs_service {
__u32 fwmark; /* firewall mark of the service */
unsigned int flags; /* service status flags */
unsigned int timeout; /* persistent timeout in ticks */
- __be32 netmask; /* grouping granularity */
+ __be32 netmask; /* grouping granularity, mask/plen */
struct net *net;
struct list_head destinations; /* real server d-linked list */
__u32 num_dests; /* number of servers */
struct ip_vs_stats stats; /* statistics for the service */
- struct ip_vs_app *inc; /* bind conns to this app inc */
/* for scheduling */
- struct ip_vs_scheduler *scheduler; /* bound scheduler object */
- rwlock_t sched_lock; /* lock sched_data */
+ struct ip_vs_scheduler __rcu *scheduler; /* bound scheduler object */
+ spinlock_t sched_lock; /* lock sched_data */
void *sched_data; /* scheduler application data */
/* alternate persistence engine */
- struct ip_vs_pe *pe;
+ struct ip_vs_pe __rcu *pe;
+
+ struct rcu_head rcu_head;
};
+/* Information for cached dst */
+struct ip_vs_dest_dst {
+ struct dst_entry *dst_cache; /* destination cache entry */
+ u32 dst_cookie;
+ union nf_inet_addr dst_saddr;
+ struct rcu_head rcu_head;
+};
+/* In grace period after removing */
+#define IP_VS_DEST_STATE_REMOVING 0x01
/*
* The real server destination forwarding entry
* with ip address, port number, and so on.
*/
struct ip_vs_dest {
struct list_head n_list; /* for the dests in the service */
- struct list_head d_list; /* for table with all the dests */
+ struct hlist_node d_list; /* for table with all the dests */
u16 af; /* address family */
__be16 port; /* port number of the server */
@@ -742,6 +766,7 @@ struct ip_vs_dest {
atomic_t refcnt; /* reference counter */
struct ip_vs_stats stats; /* statistics */
+ unsigned long state; /* state flags */
/* connection counters and thresholds */
atomic_t activeconns; /* active connections */
@@ -752,10 +777,7 @@ struct ip_vs_dest {
/* for destination cache */
spinlock_t dst_lock; /* lock of dst_cache */
- struct dst_entry *dst_cache; /* destination cache entry */
- u32 dst_rtos; /* RT_TOS(tos) for dst */
- u32 dst_cookie;
- union nf_inet_addr dst_saddr;
+ struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
/* for virtual service */
struct ip_vs_service *svc; /* service it belongs to */
@@ -763,6 +785,10 @@ struct ip_vs_dest {
__be16 vport; /* virtual port number */
union nf_inet_addr vaddr; /* virtual IP address */
__u32 vfwmark; /* firewall mark of service */
+
+ struct list_head t_list; /* in dest_trash */
+ struct rcu_head rcu_head;
+ unsigned int in_rs_table:1; /* we are in rs_table */
};
@@ -778,9 +804,13 @@ struct ip_vs_scheduler {
/* scheduler initializing service */
int (*init_service)(struct ip_vs_service *svc);
/* scheduling service finish */
- int (*done_service)(struct ip_vs_service *svc);
- /* scheduler updating service */
- int (*update_service)(struct ip_vs_service *svc);
+ void (*done_service)(struct ip_vs_service *svc);
+ /* dest is linked */
+ int (*add_dest)(struct ip_vs_service *svc, struct ip_vs_dest *dest);
+ /* dest is unlinked */
+ int (*del_dest)(struct ip_vs_service *svc, struct ip_vs_dest *dest);
+ /* dest is updated */
+ int (*upd_dest)(struct ip_vs_service *svc, struct ip_vs_dest *dest);
/* selecting a server from the given service */
struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,
@@ -819,6 +849,7 @@ struct ip_vs_app {
struct ip_vs_app *app; /* its real application */
__be16 port; /* port number in net order */
atomic_t usecnt; /* usage counter */
+ struct rcu_head rcu_head;
/*
* output hook: Process packet in inout direction, diff set for TCP.
@@ -881,6 +912,9 @@ struct ipvs_master_sync_state {
struct netns_ipvs *ipvs;
};
+/* How much time to keep dests in trash */
+#define IP_VS_DEST_TRASH_PERIOD (120 * HZ)
+
/* IPVS in network namespace */
struct netns_ipvs {
int gen; /* Generation */
@@ -892,7 +926,7 @@ struct netns_ipvs {
#define IP_VS_RTAB_SIZE (1 << IP_VS_RTAB_BITS)
#define IP_VS_RTAB_MASK (IP_VS_RTAB_SIZE - 1)
- struct list_head rs_table[IP_VS_RTAB_SIZE];
+ struct hlist_head rs_table[IP_VS_RTAB_SIZE];
/* ip_vs_app */
struct list_head app_list;
/* ip_vs_proto */
@@ -904,7 +938,6 @@ struct netns_ipvs {
#define TCP_APP_TAB_SIZE (1 << TCP_APP_TAB_BITS)
#define TCP_APP_TAB_MASK (TCP_APP_TAB_SIZE - 1)
struct list_head tcp_apps[TCP_APP_TAB_SIZE];
- spinlock_t tcp_app_lock;
#endif
/* ip_vs_proto_udp */
#ifdef CONFIG_IP_VS_PROTO_UDP
@@ -912,7 +945,6 @@ struct netns_ipvs {
#define UDP_APP_TAB_SIZE (1 << UDP_APP_TAB_BITS)
#define UDP_APP_TAB_MASK (UDP_APP_TAB_SIZE - 1)
struct list_head udp_apps[UDP_APP_TAB_SIZE];
- spinlock_t udp_app_lock;
#endif
/* ip_vs_proto_sctp */
#ifdef CONFIG_IP_VS_PROTO_SCTP
@@ -921,7 +953,6 @@ struct netns_ipvs {
#define SCTP_APP_TAB_MASK (SCTP_APP_TAB_SIZE - 1)
/* Hash table for SCTP application incarnations */
struct list_head sctp_apps[SCTP_APP_TAB_SIZE];
- spinlock_t sctp_app_lock;
#endif
/* ip_vs_conn */
atomic_t conn_count; /* connection counter */
@@ -931,9 +962,10 @@ struct netns_ipvs {
int num_services; /* no of virtual services */
- rwlock_t rs_lock; /* real services table */
/* Trash for destinations */
struct list_head dest_trash;
+ spinlock_t dest_trash_lock;
+ struct timer_list dest_trash_timer; /* expiration timer */
/* Service counters */
atomic_t ftpsvc_counter;
atomic_t nullsvc_counter;
@@ -1181,9 +1213,19 @@ struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
const struct ip_vs_iphdr *iph,
int inverse);
+/* Get reference to gain full access to conn.
+ * By default, RCU read-side critical sections have access only to
+ * conn fields and its PE data, see ip_vs_conn_rcu_free() for reference.
+ */
+static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp)
+{
+ return atomic_inc_not_zero(&cp->refcnt);
+}
+
/* put back the conn without restarting its timer */
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
{
+ smp_mb__before_atomic_dec();
atomic_dec(&cp->refcnt);
}
extern void ip_vs_conn_put(struct ip_vs_conn *cp);
@@ -1298,8 +1340,6 @@ extern void ip_vs_app_inc_put(struct ip_vs_app *inc);
extern int ip_vs_app_pkt_out(struct ip_vs_conn *, struct sk_buff *skb);
extern int ip_vs_app_pkt_in(struct ip_vs_conn *, struct sk_buff *skb);
-void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
-void ip_vs_unbind_pe(struct ip_vs_service *svc);
int register_ip_vs_pe(struct ip_vs_pe *pe);
int unregister_ip_vs_pe(struct ip_vs_pe *pe);
struct ip_vs_pe *ip_vs_pe_getbyname(const char *name);
@@ -1346,7 +1386,8 @@ extern int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler);
extern int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler);
extern int ip_vs_bind_scheduler(struct ip_vs_service *svc,
struct ip_vs_scheduler *scheduler);
-extern int ip_vs_unbind_scheduler(struct ip_vs_service *svc);
+extern void ip_vs_unbind_scheduler(struct ip_vs_service *svc,
+ struct ip_vs_scheduler *sched);
extern struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name);
extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
extern struct ip_vs_conn *
@@ -1366,17 +1407,12 @@ extern struct ip_vs_stats ip_vs_stats;
extern int sysctl_ip_vs_sync_ver;
extern struct ip_vs_service *
-ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol,
+ip_vs_service_find(struct net *net, int af, __u32 fwmark, __u16 protocol,
const union nf_inet_addr *vaddr, __be16 vport);
-static inline void ip_vs_service_put(struct ip_vs_service *svc)
-{
- atomic_dec(&svc->usecnt);
-}
-
-extern struct ip_vs_dest *
-ip_vs_lookup_real_service(struct net *net, int af, __u16 protocol,
- const union nf_inet_addr *daddr, __be16 dport);
+extern bool
+ip_vs_has_real_service(struct net *net, int af, __u16 protocol,
+ const union nf_inet_addr *daddr, __be16 dport);
extern int ip_vs_use_count_inc(void);
extern void ip_vs_use_count_dec(void);
@@ -1388,8 +1424,18 @@ extern struct ip_vs_dest *
ip_vs_find_dest(struct net *net, int af, const union nf_inet_addr *daddr,
__be16 dport, const union nf_inet_addr *vaddr, __be16 vport,
__u16 protocol, __u32 fwmark, __u32 flags);
-extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp);
+extern void ip_vs_try_bind_dest(struct ip_vs_conn *cp);
+static inline void ip_vs_dest_hold(struct ip_vs_dest *dest)
+{
+ atomic_inc(&dest->refcnt);
+}
+
+static inline void ip_vs_dest_put(struct ip_vs_dest *dest)
+{
+ smp_mb__before_atomic_dec();
+ atomic_dec(&dest->refcnt);
+}
/*
* IPVS sync daemon data and function prototypes
@@ -1428,7 +1474,7 @@ extern int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
extern int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, int offset,
unsigned int hooknum, struct ip_vs_iphdr *iph);
-extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
+extern void ip_vs_dest_dst_rcu_free(struct rcu_head *head);
#ifdef CONFIG_IP_VS_IPV6
extern int ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
diff --git a/include/net/ipip.h b/include/net/ipip.h
deleted file mode 100644
index 982141c15200..000000000000
--- a/include/net/ipip.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef __NET_IPIP_H
-#define __NET_IPIP_H 1
-
-#include <linux/if_tunnel.h>
-#include <net/gro_cells.h>
-#include <net/ip.h>
-
-/* Keep error state on tunnel for 30 sec */
-#define IPTUNNEL_ERR_TIMEO (30*HZ)
-
-/* 6rd prefix/relay information */
-struct ip_tunnel_6rd_parm {
- struct in6_addr prefix;
- __be32 relay_prefix;
- u16 prefixlen;
- u16 relay_prefixlen;
-};
-
-struct ip_tunnel {
- struct ip_tunnel __rcu *next;
- struct net_device *dev;
-
- int err_count; /* Number of arrived ICMP errors */
- unsigned long err_time; /* Time when the last ICMP error arrived */
-
- /* These four fields used only by GRE */
- __u32 i_seqno; /* The last seen seqno */
- __u32 o_seqno; /* The last output seqno */
- int hlen; /* Precalculated GRE header length */
- int mlink;
-
- struct ip_tunnel_parm parms;
-
- /* for SIT */
-#ifdef CONFIG_IPV6_SIT_6RD
- struct ip_tunnel_6rd_parm ip6rd;
-#endif
- struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */
- unsigned int prl_count; /* # of entries in PRL */
-
- struct gro_cells gro_cells;
-};
-
-struct ip_tunnel_prl_entry {
- struct ip_tunnel_prl_entry __rcu *next;
- __be32 addr;
- u16 flags;
- struct rcu_head rcu_head;
-};
-
-static inline void iptunnel_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- int err;
- struct iphdr *iph = ip_hdr(skb);
- int pkt_len = skb->len - skb_transport_offset(skb);
- struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
-
- nf_reset(skb);
- skb->ip_summed = CHECKSUM_NONE;
- ip_select_ident(iph, skb_dst(skb), NULL);
-
- err = ip_local_out(skb);
- if (likely(net_xmit_eval(err) == 0)) {
- u64_stats_update_begin(&tstats->syncp);
- tstats->tx_bytes += pkt_len;
- tstats->tx_packets++;
- u64_stats_update_end(&tstats->syncp);
- } else {
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
- }
-}
-
-static inline void tunnel_ip_select_ident(struct sk_buff *skb,
- const struct iphdr *old_iph,
- struct dst_entry *dst)
-{
- struct iphdr *iph = ip_hdr(skb);
-
- /* Use inner packet iph-id if possible. */
- if (skb->protocol == htons(ETH_P_IP) && old_iph->id)
- iph->id = old_iph->id;
- else
- __ip_select_ident(iph, dst,
- (skb_shinfo(skb)->gso_segs ?: 1) - 1);
-}
-#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 64d12e77719a..0810aa57c780 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -217,7 +217,7 @@ struct ipv6_txoptions {
};
struct ip6_flowlabel {
- struct ip6_flowlabel *next;
+ struct ip6_flowlabel __rcu *next;
__be32 label;
atomic_t users;
struct in6_addr dst;
@@ -238,9 +238,9 @@ struct ip6_flowlabel {
#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF)
struct ipv6_fl_socklist {
- struct ipv6_fl_socklist *next;
- struct ip6_flowlabel *fl;
- struct rcu_head rcu;
+ struct ipv6_fl_socklist __rcu *next;
+ struct ip6_flowlabel *fl;
+ struct rcu_head rcu;
};
extern struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
@@ -320,6 +320,18 @@ static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
return __ipv6_addr_src_scope(__ipv6_addr_type(addr));
}
+static inline bool __ipv6_addr_needs_scope_id(int type)
+{
+ return type & IPV6_ADDR_LINKLOCAL ||
+ (type & IPV6_ADDR_MULTICAST &&
+ (type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)));
+}
+
+static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface)
+{
+ return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0;
+}
+
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
{
return memcmp(a1, a2, sizeof(struct in6_addr));
@@ -466,6 +478,7 @@ struct ip6_create_arg {
u32 user;
const struct in6_addr *src;
const struct in6_addr *dst;
+ u8 ecn;
};
void ip6_frag_init(struct inet_frag_queue *q, void *a);
@@ -485,6 +498,7 @@ struct frag_queue {
int iif;
unsigned int csum;
__u16 nhoffset;
+ u8 ecn;
};
void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index f74109144d3f..f132924cc9da 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -256,7 +256,8 @@ static inline __u32 irlmp_get_daddr(const struct lsap_cb *self)
return (self && self->lap) ? self->lap->daddr : 0;
}
-extern const char *irlmp_reasons[];
+const char *irlmp_reason_str(LM_REASON reason);
+
extern int sysctl_discovery_timeout;
extern int sysctl_discovery_slots;
extern int sysctl_discovery;
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index cc7c19732389..714cc9a54a4c 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -130,6 +130,14 @@ struct iucv_sock {
enum iucv_tx_notify n);
};
+struct iucv_skb_cb {
+ u32 class; /* target class of message */
+ u32 tag; /* tag associated with message */
+ u32 offset; /* offset for skb receival */
+};
+
+#define IUCV_SKB_CB(__skb) ((struct iucv_skb_cb *)&((__skb)->cb[0]))
+
/* iucv socket options (SOL_IUCV) */
#define SO_IPRMDATA_MSG 0x0080 /* send/recv IPRM_DATA msgs */
#define SO_MSGLIMIT 0x1000 /* get/set IUCV MSGLIMIT */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f7eba1300d82..04c2d4670dc6 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -93,9 +93,11 @@ struct device;
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
+ * @IEEE80211_MAX_QUEUE_MAP: bitmap with maximum queues set
*/
enum ieee80211_max_queues {
IEEE80211_MAX_QUEUES = 16,
+ IEEE80211_MAX_QUEUE_MAP = BIT(IEEE80211_MAX_QUEUES) - 1,
};
#define IEEE80211_INVAL_HW_QUEUE 0xff
@@ -126,6 +128,7 @@ enum ieee80211_ac_numbers {
* 2^n-1 in the range 1..32767]
* @cw_max: maximum contention window [like @cw_min]
* @txop: maximum burst time in units of 32 usecs, 0 meaning disabled
+ * @acm: is mandatory admission control required for the access category
* @uapsd: is U-APSD mode enabled for the queue
*/
struct ieee80211_tx_queue_params {
@@ -133,6 +136,7 @@ struct ieee80211_tx_queue_params {
u16 cw_min;
u16 cw_max;
u8 aifs;
+ bool acm;
bool uapsd;
};
@@ -207,7 +211,7 @@ struct ieee80211_chanctx_conf {
* @BSS_CHANGED_QOS: QoS for this association was enabled/disabled. Note
* that it is only ever disabled for station mode.
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
- * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
+ * @BSS_CHANGED_SSID: SSID changed for this BSS (AP and IBSS mode)
* @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
* @BSS_CHANGED_PS: PS changed for this BSS (STA mode)
* @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
@@ -324,12 +328,11 @@ enum ieee80211_rssi_event {
* your driver/device needs to do.
* @ps: power-save mode (STA only). This flag is NOT affected by
* offchannel/dynamic_ps operations.
- * @ssid: The SSID of the current vif. Only valid in AP-mode.
+ * @ssid: The SSID of the current vif. Valid in AP and IBSS mode.
* @ssid_len: Length of SSID given in @ssid.
* @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
* @txpower: TX power in dBm
- * @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces
- * @p2p_oppps: P2P opportunistic PS is enabled
+ * @p2p_noa_attr: P2P NoA attribute for P2P powersave
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -363,8 +366,7 @@ struct ieee80211_bss_conf {
size_t ssid_len;
bool hidden_ssid;
int txpower;
- u8 p2p_ctwindow;
- bool p2p_oppps;
+ struct ieee80211_p2p_noa_attr p2p_noa_attr;
};
/**
@@ -561,6 +563,9 @@ enum mac80211_rate_control_flags {
/* maximum number of rate stages */
#define IEEE80211_TX_MAX_RATES 4
+/* maximum number of rate table entries */
+#define IEEE80211_TX_RATE_TABLE_SIZE 4
+
/**
* struct ieee80211_tx_rate - rate selection/status
*
@@ -601,8 +606,8 @@ static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate,
u8 mcs, u8 nss)
{
WARN_ON(mcs & ~0xF);
- WARN_ON(nss & ~0x7);
- rate->idx = (nss << 4) | mcs;
+ WARN_ON((nss - 1) & ~0x7);
+ rate->idx = ((nss - 1) << 4) | mcs;
}
static inline u8
@@ -614,7 +619,7 @@ ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate)
static inline u8
ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
{
- return rate->idx >> 4;
+ return (rate->idx >> 4) + 1;
}
/**
@@ -655,7 +660,11 @@ struct ieee80211_tx_info {
struct ieee80211_tx_rate rates[
IEEE80211_TX_MAX_RATES];
s8 rts_cts_rate_idx;
- /* 3 bytes free */
+ u8 use_rts:1;
+ u8 use_cts_prot:1;
+ u8 short_preamble:1;
+ u8 skip_table:1;
+ /* 2 bytes free */
};
/* only needed before rate control */
unsigned long jiffies;
@@ -676,6 +685,8 @@ struct ieee80211_tx_info {
struct {
struct ieee80211_tx_rate driver_rates[
IEEE80211_TX_MAX_RATES];
+ u8 pad[4];
+
void *rate_driver_data[
IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)];
};
@@ -974,8 +985,7 @@ enum ieee80211_smps_mode {
* @power_level: requested transmit power (in dBm), backward compatibility
* value only that is set to the minimum of all interfaces
*
- * @channel: the channel to tune to
- * @channel_type: the channel (HT) type
+ * @chandef: the channel definition to tune to
* @radar_enabled: whether radar detection is enabled
*
* @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame
@@ -1001,8 +1011,7 @@ struct ieee80211_conf {
u8 long_frame_max_tx_count, short_frame_max_tx_count;
- struct ieee80211_channel *channel;
- enum nl80211_channel_type channel_type;
+ struct cfg80211_chan_def chandef;
bool radar_enabled;
enum ieee80211_smps_mode smps_mode;
};
@@ -1019,13 +1028,13 @@ struct ieee80211_conf {
* the driver passed into mac80211.
* @block_tx: Indicates whether transmission must be blocked before the
* scheduled channel switch, as indicated by the AP.
- * @channel: the new channel to switch to
+ * @chandef: the new channel to switch to
* @count: the number of TBTT's until the channel switch event
*/
struct ieee80211_channel_switch {
u64 timestamp;
bool block_tx;
- struct ieee80211_channel *channel;
+ struct cfg80211_chan_def chandef;
u8 count;
};
@@ -1067,6 +1076,9 @@ enum ieee80211_vif_flags {
* path needing to access it; even though the netdev carrier will always
* be off when it is %NULL there can still be races and packets could be
* processed after it switches back to %NULL.
+ * @debugfs_dir: debugfs dentry, can be used by drivers to create own per
+ * interface debug files. Note that it will be NULL for the virtual
+ * monitor interface (if that is requested.)
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *).
*/
@@ -1083,6 +1095,10 @@ struct ieee80211_vif {
u32 driver_flags;
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *debugfs_dir;
+#endif
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
@@ -1101,8 +1117,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
* These flags are used for communication about keys between the driver
* and mac80211, with the @flags parameter of &struct ieee80211_key_conf.
*
- * @IEEE80211_KEY_FLAG_WMM_STA: Set by mac80211, this flag indicates
- * that the STA this key will be used with could be using QoS.
* @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
* driver to indicate that it requires IV generation for this
* particular key.
@@ -1127,7 +1141,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
* %IEEE80211_KEY_FLAG_SW_MGMT_TX flag to encrypt such frames in SW.
*/
enum ieee80211_key_flags {
- IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
IEEE80211_KEY_FLAG_PAIRWISE = 1<<3,
@@ -1219,6 +1232,24 @@ enum ieee80211_sta_rx_bandwidth {
};
/**
+ * struct ieee80211_sta_rates - station rate selection table
+ *
+ * @rcu_head: RCU head used for freeing the table on update
+ * @rates: transmit rates/flags to be used by default.
+ * Overriding entries per-packet is possible by using cb tx control.
+ */
+struct ieee80211_sta_rates {
+ struct rcu_head rcu_head;
+ struct {
+ s8 idx;
+ u8 count;
+ u8 count_cts;
+ u8 count_rts;
+ u16 flags;
+ } rate[IEEE80211_TX_RATE_TABLE_SIZE];
+};
+
+/**
* struct ieee80211_sta - station table entry
*
* A station table entry represents a station we are possibly
@@ -1231,9 +1262,8 @@ enum ieee80211_sta_rx_bandwidth {
* @addr: MAC address
* @aid: AID we assigned to the station if we're an AP
* @supp_rates: Bitmap of supported rates (per band)
- * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities
- * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities
- * of remote STA. Taking as is.
+ * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
+ * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
* @wme: indicates whether the STA supports WME. Only valid during AP-mode.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void *), size is determined in hw information.
@@ -1246,6 +1276,7 @@ enum ieee80211_sta_rx_bandwidth {
* notifications and capabilities. The value is only valid after
* the station moves to associated state.
* @smps_mode: current SMPS mode (off, static or dynamic)
+ * @tx_rates: rate control selection table
*/
struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -1259,6 +1290,7 @@ struct ieee80211_sta {
u8 rx_nss;
enum ieee80211_sta_rx_bandwidth bandwidth;
enum ieee80211_smps_mode smps_mode;
+ struct ieee80211_sta_rates __rcu *rates;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
@@ -1414,6 +1446,9 @@ struct ieee80211_tx_control {
* for different virtual interfaces. See the doc section on HW queue
* control for more details.
*
+ * @IEEE80211_HW_SUPPORTS_RC_TABLE: The driver supports using a rate
+ * selection table provided by the rate control algorithm.
+ *
* @IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF: Use the P2P Device address for any
* P2P Interface. This will be honoured even if more than one interface
* is supported.
@@ -1446,6 +1481,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21,
IEEE80211_HW_AP_LINK_PS = 1<<22,
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW = 1<<23,
+ IEEE80211_HW_SUPPORTS_RC_TABLE = 1<<24,
IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF = 1<<25,
IEEE80211_HW_TIMING_BEACON_ONLY = 1<<26,
};
@@ -1531,6 +1567,17 @@ enum ieee80211_hw_flags {
* @netdev_features: netdev features to be set in each netdev created
* from this HW. Note only HW checksum features are currently
* compatible with mac80211. Other feature bits will be rejected.
+ *
+ * @uapsd_queues: This bitmap is included in (re)association frame to indicate
+ * for each access category if it is uAPSD trigger-enabled and delivery-
+ * enabled. Use IEEE80211_WMM_IE_STA_QOSINFO_AC_* to set this bitmap.
+ * Each bit corresponds to different AC. Value '1' in specific bit means
+ * that corresponding AC is both trigger- and delivery-enabled. '0' means
+ * neither enabled.
+ *
+ * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may
+ * deliver to a WMM STA during any Service Period triggered by the WMM STA.
+ * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -1556,6 +1603,8 @@ struct ieee80211_hw {
u8 radiotap_mcs_details;
u16 radiotap_vht_details;
netdev_features_t netdev_features;
+ u8 uapsd_queues;
+ u8 uapsd_max_sp_len;
};
/**
@@ -1950,14 +1999,14 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
* filter those response frames except in the case of frames that
* are buffered in the driver -- those must remain buffered to avoid
* reordering. Because it is possible that no frames are released
- * in this case, the driver must call ieee80211_sta_eosp_irqsafe()
+ * in this case, the driver must call ieee80211_sta_eosp()
* to indicate to mac80211 that the service period ended anyway.
*
* Finally, if frames from multiple TIDs are released from mac80211
* but the driver might reorder them, it must clear & set the flags
* appropriately (only the last frame may have %IEEE80211_TX_STATUS_EOSP)
* and also take care of the EOSP and MORE_DATA bits in the frame.
- * The driver may also use ieee80211_sta_eosp_irqsafe() in this case.
+ * The driver may also use ieee80211_sta_eosp() in this case.
*/
/**
@@ -2135,6 +2184,24 @@ enum ieee80211_rate_control_changed {
};
/**
+ * enum ieee80211_roc_type - remain on channel type
+ *
+ * With the support for multi channel contexts and multi channel operations,
+ * remain on channel operations might be limited/deferred/aborted by other
+ * flows/operations which have higher priority (and vise versa).
+ * Specifying the ROC type can be used by devices to prioritize the ROC
+ * operations compared to other operations/flows.
+ *
+ * @IEEE80211_ROC_TYPE_NORMAL: There are no special requirements for this ROC.
+ * @IEEE80211_ROC_TYPE_MGMT_TX: The remain on channel request is required
+ * for sending managment frames offchannel.
+ */
+enum ieee80211_roc_type {
+ IEEE80211_ROC_TYPE_NORMAL = 0,
+ IEEE80211_ROC_TYPE_MGMT_TX,
+};
+
+/**
* struct ieee80211_ops - callbacks from mac80211 to the driver
*
* This structure contains various callbacks that the driver may
@@ -2212,18 +2279,6 @@ enum ieee80211_rate_control_changed {
* MAC address of the device going away.
* Hence, this callback must be implemented. It can sleep.
*
- * @add_interface_debugfs: Drivers can use this callback to add debugfs files
- * when a vif is added to mac80211. This callback and
- * @remove_interface_debugfs should be within a CONFIG_MAC80211_DEBUGFS
- * conditional. @remove_interface_debugfs must be provided for cleanup.
- * This callback can sleep.
- *
- * @remove_interface_debugfs: Remove the debugfs files which were added using
- * @add_interface_debugfs. This callback must remove all debugfs entries
- * that were added because mac80211 only removes interface debugfs when the
- * interface is destroyed, not when it is removed from the driver.
- * This callback can sleep.
- *
* @config: Handler for configuration requests. IEEE 802.11 code calls this
* function to change hardware configuration, e.g., channel.
* This function should never fail but returns a negative error code
@@ -2245,6 +2300,9 @@ enum ieee80211_rate_control_changed {
* See the section "Frame filtering" for more information.
* This callback must be implemented and can sleep.
*
+ * @set_multicast_list: Configure the device's interface specific RX multicast
+ * filter. This callback is optional. This callback must be atomic.
+ *
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
* must be set or cleared for a given STA. Must be atomic.
*
@@ -2426,8 +2484,11 @@ enum ieee80211_rate_control_changed {
* @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
*
* @flush: Flush all pending frames from the hardware queue, making sure
- * that the hardware queues are empty. If the parameter @drop is set
- * to %true, pending frames may be dropped. The callback can sleep.
+ * that the hardware queues are empty. The @queues parameter is a bitmap
+ * of queues to flush, which is useful if different virtual interfaces
+ * use different hardware queues; it may also indicate all queues.
+ * If the parameter @drop is set to %true, pending frames may be dropped.
+ * The callback can sleep.
*
* @channel_switch: Drivers that need (or want) to offload the channel
* switch operation for CSAs received from the AP may implement this
@@ -2492,7 +2553,7 @@ enum ieee80211_rate_control_changed {
* setting the EOSP flag in the QoS header of the frames. Also, when the
* service period ends, the driver must set %IEEE80211_TX_STATUS_EOSP
* on the last frame in the SP. Alternatively, it may call the function
- * ieee80211_sta_eosp_irqsafe() to inform mac80211 of the end of the SP.
+ * ieee80211_sta_eosp() to inform mac80211 of the end of the SP.
* This callback must be atomic.
* @allow_buffered_frames: Prepare device to allow the given number of frames
* to go out to the given station. The frames will be sent by mac80211
@@ -2503,7 +2564,7 @@ enum ieee80211_rate_control_changed {
* them between the TIDs, it must set the %IEEE80211_TX_STATUS_EOSP flag
* on the last frame and clear it on all others and also handle the EOSP
* bit in the QoS header correctly. Alternatively, it can also call the
- * ieee80211_sta_eosp_irqsafe() function.
+ * ieee80211_sta_eosp() function.
* The @tids parameter is a bitmap and tells the driver which TIDs the
* frames will be on; it will at most have two bits set.
* This callback must be atomic.
@@ -2591,6 +2652,10 @@ struct ieee80211_ops {
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast);
+ void (*set_multicast_list)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, bool allmulti,
+ struct netdev_hw_addr_list *mc_list);
+
int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
bool set);
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -2637,12 +2702,6 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct dentry *dir);
- void (*add_interface_debugfs)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct dentry *dir);
- void (*remove_interface_debugfs)(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct dentry *dir);
#endif
void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum sta_notify_cmd, struct ieee80211_sta *sta);
@@ -2677,7 +2736,7 @@ struct ieee80211_ops {
struct netlink_callback *cb,
void *data, int len);
#endif
- void (*flush)(struct ieee80211_hw *hw, bool drop);
+ void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch);
int (*napi_poll)(struct ieee80211_hw *hw, int budget);
@@ -2687,7 +2746,8 @@ struct ieee80211_ops {
int (*remain_on_channel)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *chan,
- int duration);
+ int duration,
+ enum ieee80211_roc_type type);
int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
void (*get_ringparam)(struct ieee80211_hw *hw,
@@ -3108,6 +3168,25 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *sta,
u8 tid, bool buffered);
/**
+ * ieee80211_get_tx_rates - get the selected transmit rates for a packet
+ *
+ * Call this function in a driver with per-packet rate selection support
+ * to combine the rate info in the packet tx info with the most recent
+ * rate selection table for the station entry.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @sta: the receiver station to which this packet is sent.
+ * @skb: the frame to be transmitted.
+ * @dest: buffer for extracted rate/retry information
+ * @max_rates: maximum number of rates to fetch
+ */
+void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct ieee80211_tx_rate *dest,
+ int max_rates);
+
+/**
* ieee80211_tx_status - transmit status callback
*
* Call this function for all transmitted frames after they have been
@@ -3842,14 +3921,17 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
* %IEEE80211_TX_STATUS_EOSP bit and call this function instead.
* This applies for PS-Poll as well as uAPSD.
*
- * Note that there is no non-_irqsafe version right now as
- * it wasn't needed, but just like _tx_status() and _rx()
- * must not be mixed in irqsafe/non-irqsafe versions, this
- * function must not be mixed with those either. Use the
- * all irqsafe, or all non-irqsafe, don't mix! If you need
- * the non-irqsafe version of this, you need to add it.
+ * Note that just like with _tx_status() and _rx() drivers must
+ * not mix calls to irqsafe/non-irqsafe versions, this function
+ * must not be mixed with those either. Use the all irqsafe, or
+ * all non-irqsafe, don't mix!
+ *
+ * NB: the _irqsafe version of this function doesn't exist, no
+ * driver needs it right now. Don't call this function if
+ * you'd need the _irqsafe version, look at the git history
+ * and restore the _irqsafe version!
*/
-void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta);
+void ieee80211_sta_eosp(struct ieee80211_sta *pubsta);
/**
* ieee80211_iter_keys - iterate keys programmed into the device
@@ -4079,7 +4161,7 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
* (deprecated; this will be removed once drivers get updated to use
* rate_idx_mask)
* @rate_idx_mask: user-requested (legacy) rate mask
- * @rate_idx_mcs_mask: user-requested MCS rate mask
+ * @rate_idx_mcs_mask: user-requested MCS rate mask (NULL if not in use)
* @bss: whether this frame is sent out in AP or IBSS mode
*/
struct ieee80211_tx_rate_control {
@@ -4091,7 +4173,7 @@ struct ieee80211_tx_rate_control {
bool rts, short_preamble;
u8 max_rate_idx;
u32 rate_idx_mask;
- u8 rate_idx_mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
+ u8 *rate_idx_mcs_mask;
bool bss;
};
@@ -4180,37 +4262,55 @@ bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
return false;
}
+/**
+ * rate_control_set_rates - pass the sta rate selection to mac80211/driver
+ *
+ * When not doing a rate control probe to test rates, rate control should pass
+ * its rate selection to mac80211. If the driver supports receiving a station
+ * rate table, it will use it to ensure that frames are always sent based on
+ * the most recent rate control module decision.
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @pubsta: &struct ieee80211_sta pointer to the target destination.
+ * @rates: new tx rate set to be used for this station.
+ */
+int rate_control_set_rates(struct ieee80211_hw *hw,
+ struct ieee80211_sta *pubsta,
+ struct ieee80211_sta_rates *rates);
+
int ieee80211_rate_control_register(struct rate_control_ops *ops);
void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
static inline bool
conf_is_ht20(struct ieee80211_conf *conf)
{
- return conf->channel_type == NL80211_CHAN_HT20;
+ return conf->chandef.width == NL80211_CHAN_WIDTH_20;
}
static inline bool
conf_is_ht40_minus(struct ieee80211_conf *conf)
{
- return conf->channel_type == NL80211_CHAN_HT40MINUS;
+ return conf->chandef.width == NL80211_CHAN_WIDTH_40 &&
+ conf->chandef.center_freq1 < conf->chandef.chan->center_freq;
}
static inline bool
conf_is_ht40_plus(struct ieee80211_conf *conf)
{
- return conf->channel_type == NL80211_CHAN_HT40PLUS;
+ return conf->chandef.width == NL80211_CHAN_WIDTH_40 &&
+ conf->chandef.center_freq1 > conf->chandef.chan->center_freq;
}
static inline bool
conf_is_ht40(struct ieee80211_conf *conf)
{
- return conf_is_ht40_minus(conf) || conf_is_ht40_plus(conf);
+ return conf->chandef.width == NL80211_CHAN_WIDTH_40;
}
static inline bool
conf_is_ht(struct ieee80211_conf *conf)
{
- return conf->channel_type != NL80211_CHAN_NO_HT;
+ return conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT;
}
static inline enum nl80211_iftype
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index de644bcd8613..b17697827482 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -17,6 +17,7 @@
#include <net/netns/ipv6.h>
#include <net/netns/sctp.h>
#include <net/netns/dccp.h>
+#include <net/netns/netfilter.h>
#include <net/netns/x_tables.h>
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
#include <net/netns/conntrack.h>
@@ -94,6 +95,7 @@ struct net {
struct netns_dccp dccp;
#endif
#ifdef CONFIG_NETFILTER
+ struct netns_nf nf;
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index caca0c4d6b4b..644d9c223d24 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -184,7 +184,7 @@ extern int nf_conntrack_hash_check_insert(struct nf_conn *ct);
extern void nf_ct_delete_from_lists(struct nf_conn *ct);
extern void nf_ct_dying_timeout(struct nf_conn *ct);
-extern void nf_conntrack_flush_report(struct net *net, u32 pid, int report);
+extern void nf_conntrack_flush_report(struct net *net, u32 portid, int report);
extern bool nf_ct_get_tuplepr(const struct sk_buff *skb,
unsigned int nhoff, u_int16_t l3num,
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 930275fa2ea6..fb2b6234e937 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -27,6 +27,7 @@ extern unsigned int nf_conntrack_in(struct net *net,
extern int nf_conntrack_init_net(struct net *net);
extern void nf_conntrack_cleanup_net(struct net *net);
+extern void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list);
extern int nf_conntrack_proto_pernet_init(struct net *net);
extern void nf_conntrack_proto_pernet_fini(struct net *net);
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index cbbae7621e22..3f3aecbc8632 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -88,7 +88,7 @@ nf_ct_find_expectation(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
- u32 pid, int report);
+ u32 portid, int report);
static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
{
nf_ct_unlink_expect_report(exp, 0, 0);
@@ -106,7 +106,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t,
u_int8_t, const __be16 *, const __be16 *);
void nf_ct_expect_put(struct nf_conntrack_expect *exp);
int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
- u32 pid, int report);
+ u32 portid, int report);
static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect)
{
return nf_ct_expect_related_report(expect, 0, 0);
diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h
index e991bd0a27af..31f1fb9eb784 100644
--- a/include/net/netfilter/nf_log.h
+++ b/include/net/netfilter/nf_log.h
@@ -49,12 +49,18 @@ struct nf_logger {
int nf_log_register(u_int8_t pf, struct nf_logger *logger);
void nf_log_unregister(struct nf_logger *logger);
-int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger);
-void nf_log_unbind_pf(u_int8_t pf);
+void nf_log_set(struct net *net, u_int8_t pf,
+ const struct nf_logger *logger);
+void nf_log_unset(struct net *net, const struct nf_logger *logger);
+
+int nf_log_bind_pf(struct net *net, u_int8_t pf,
+ const struct nf_logger *logger);
+void nf_log_unbind_pf(struct net *net, u_int8_t pf);
/* Calls the registered backend logging function */
-__printf(7, 8)
-void nf_log_packet(u_int8_t pf,
+__printf(8, 9)
+void nf_log_packet(struct net *net,
+ u_int8_t pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index fb1c0be38b6d..aaba4bbcdda0 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -9,10 +9,13 @@ struct nf_queue_entry {
struct nf_hook_ops *elem;
u_int8_t pf;
+ u16 size; /* sizeof(entry) + saved route keys */
unsigned int hook;
struct net_device *indev;
struct net_device *outdev;
int (*okfn)(struct sk_buff *);
+
+ /* extra space to store route keys */
};
#define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry))
@@ -27,4 +30,7 @@ void nf_register_queue_handler(const struct nf_queue_handler *qh);
void nf_unregister_queue_handler(void);
extern void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry);
+void nf_queue_entry_release_refs(struct nf_queue_entry *entry);
+
#endif /* _NF_QUEUE_H */
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 1242f371718b..005e2c2e39a9 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -71,6 +71,7 @@ struct netns_ipv6 {
struct fib_rules_ops *mr6_rules_ops;
#endif
#endif
+ atomic_t dev_addr_genid;
};
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h
new file mode 100644
index 000000000000..88740024ccf3
--- /dev/null
+++ b/include/net/netns/netfilter.h
@@ -0,0 +1,18 @@
+#ifndef __NETNS_NETFILTER_H
+#define __NETNS_NETFILTER_H
+
+#include <linux/proc_fs.h>
+#include <linux/netfilter.h>
+
+struct nf_logger;
+
+struct netns_nf {
+#if defined CONFIG_PROC_FS
+ struct proc_dir_entry *proc_netfilter;
+#endif
+ const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
+#ifdef CONFIG_SYSCTL
+ struct ctl_table_header *nf_log_dir_header;
+#endif
+};
+#endif
diff --git a/include/net/netprio_cgroup.h b/include/net/netprio_cgroup.h
index 1d04b6f0fbd4..50ab8c26ab59 100644
--- a/include/net/netprio_cgroup.h
+++ b/include/net/netprio_cgroup.h
@@ -29,7 +29,7 @@ struct cgroup_netprio_state {
struct cgroup_subsys_state css;
};
-extern void sock_update_netprioidx(struct sock *sk, struct task_struct *task);
+extern void sock_update_netprioidx(struct sock *sk);
#if IS_BUILTIN(CONFIG_NETPRIO_CGROUP)
@@ -68,7 +68,7 @@ static inline u32 task_netprioidx(struct task_struct *p)
return 0;
}
-#define sock_update_netprioidx(sk, task)
+#define sock_update_netprioidx(sk)
#endif /* CONFIG_NETPRIO_CGROUP */
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 87a6417fc934..5eb80bb3cbb2 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -122,6 +122,8 @@ struct nfc_dev {
bool shutting_down;
+ struct rfkill *rfkill;
+
struct nfc_ops *ops;
};
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index a51dbd17c2de..59795e42c8b6 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -27,19 +27,13 @@ struct sk_buff;
struct dst_entry;
struct proto;
-/* empty to "strongly type" an otherwise void parameter.
- */
-struct request_values {
-};
-
struct request_sock_ops {
int family;
int obj_size;
struct kmem_cache *slab;
char *slab_name;
int (*rtx_syn_ack)(struct sock *sk,
- struct request_sock *req,
- struct request_values *rvp);
+ struct request_sock *req);
void (*send_ack)(struct sock *sk, struct sk_buff *skb,
struct request_sock *req);
void (*send_reset)(struct sock *sk,
@@ -54,7 +48,7 @@ extern int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req);
/* struct request_sock - mini sock to represent a connection request
*/
struct request_sock {
- struct request_sock *dl_next; /* Must be first member! */
+ struct request_sock *dl_next;
u16 mss;
u8 num_retrans; /* number of retransmits */
u8 cookie_ts:1; /* syncookie: encode tcpopts in timestamp */
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 5a15fabd6a75..702664833a53 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -4,7 +4,7 @@
#include <linux/rtnetlink.h>
#include <net/netlink.h>
-typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
+typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *);
typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
typedef u16 (*rtnl_calcit_func)(struct sk_buff *, struct nlmsghdr *);
diff --git a/include/net/scm.h b/include/net/scm.h
index 975cca01048b..8de2d37d2077 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -26,7 +26,6 @@ struct scm_fp_list {
struct scm_cookie {
struct pid *pid; /* Skb credentials */
- const struct cred *cred;
struct scm_fp_list *fp; /* Passed files */
struct scm_creds creds; /* Skb credentials */
#ifdef CONFIG_SECURITY_NETWORK
@@ -51,23 +50,18 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co
#endif /* CONFIG_SECURITY_NETWORK */
static __inline__ void scm_set_cred(struct scm_cookie *scm,
- struct pid *pid, const struct cred *cred)
+ struct pid *pid, kuid_t uid, kgid_t gid)
{
scm->pid = get_pid(pid);
- scm->cred = cred ? get_cred(cred) : NULL;
scm->creds.pid = pid_vnr(pid);
- scm->creds.uid = cred ? cred->euid : INVALID_UID;
- scm->creds.gid = cred ? cred->egid : INVALID_GID;
+ scm->creds.uid = uid;
+ scm->creds.gid = gid;
}
static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
{
put_pid(scm->pid);
scm->pid = NULL;
-
- if (scm->cred)
- put_cred(scm->cred);
- scm->cred = NULL;
}
static __inline__ void scm_destroy(struct scm_cookie *scm)
@@ -81,8 +75,10 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm, bool forcecreds)
{
memset(scm, 0, sizeof(*scm));
+ scm->creds.uid = INVALID_UID;
+ scm->creds.gid = INVALID_GID;
if (forcecreds)
- scm_set_cred(scm, task_tgid(current), current_cred());
+ scm_set_cred(scm, task_tgid(current), current_uid(), current_gid());
unix_get_peersec_dgram(sock, scm);
if (msg->msg_controllen <= 0)
return 0;
diff --git a/include/net/sctp/checksum.h b/include/net/sctp/checksum.h
index befc8d2a1b9f..5a2110d3176d 100644
--- a/include/net/sctp/checksum.h
+++ b/include/net/sctp/checksum.h
@@ -77,7 +77,7 @@ static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32)
return sctp_crc32c(crc32, buffer, length);
}
-static inline __le32 sctp_end_cksum(__be32 crc32)
+static inline __le32 sctp_end_cksum(__u32 crc32)
{
return cpu_to_le32(~crc32);
}
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index a7dd5c50df79..ca50e0751e47 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -49,7 +49,6 @@
#include <linux/sctp.h>
#include <linux/ipv6.h> /* For ipv6hdr. */
-#include <net/sctp/user.h>
#include <net/tcp_states.h> /* For TCP states used in sctp_sock_state_t */
/* Value used for stream negotiation. */
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index df85a0c0f2d5..cd89510eab2a 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -576,7 +576,7 @@ for (pos = chunk->subh.fwdtsn_hdr->skip;\
#define WORD_ROUND(s) (((s)+3)&~3)
/* Make a new instance of type. */
-#define t_new(type, flags) (type *)kzalloc(sizeof(type), flags)
+#define t_new(type, flags) kzalloc(sizeof(type), flags)
/* Compare two timevals. */
#define tv_lt(s, t) \
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 0e0f9d2322e3..1bd4c4144fe8 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -399,7 +399,6 @@ struct sctp_stream {
struct sctp_ssnmap {
struct sctp_stream in;
struct sctp_stream out;
- int malloced;
};
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
@@ -715,8 +714,7 @@ struct sctp_packet {
has_sack:1, /* This packet contains a SACK chunk. */
has_auth:1, /* This packet contains an AUTH chunk */
has_data:1, /* This packet contains at least 1 DATA chunk */
- ipfragok:1, /* So let ip fragment this packet */
- malloced:1; /* Is it malloced? */
+ ipfragok:1; /* So let ip fragment this packet */
};
struct sctp_packet *sctp_packet_init(struct sctp_packet *,
@@ -780,10 +778,7 @@ struct sctp_transport {
hb_sent:1,
/* Is the Path MTU update pending on this tranport */
- pmtu_pending:1,
-
- /* Is this structure kfree()able? */
- malloced:1;
+ pmtu_pending:1;
/* Has this transport moved the ctsn since we last sacked */
__u32 sack_generation;
@@ -992,8 +987,6 @@ struct sctp_inq {
* messages.
*/
struct work_struct immediate;
-
- int malloced; /* Is this structure kfree()able? */
};
void sctp_inq_init(struct sctp_inq *);
@@ -1062,9 +1055,6 @@ struct sctp_outq {
/* Is this structure empty? */
char empty;
-
- /* Are we kfree()able? */
- char malloced;
};
void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
@@ -1102,8 +1092,6 @@ struct sctp_bind_addr {
* peer(s) in INIT and INIT ACK chunks.
*/
struct list_head address_list;
-
- int malloced; /* Are we kfree()able? */
};
void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
@@ -1174,11 +1162,9 @@ struct sctp_ep_common {
/* Some fields to help us manage this object.
* refcnt - Reference count access to this object.
* dead - Do not attempt to use this object.
- * malloced - Do we need to kfree this object?
*/
atomic_t refcnt;
- char dead;
- char malloced;
+ bool dead;
/* What socket does this endpoint belong to? */
struct sock *sk;
diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h
index ff1b8ba73ab1..00e50ba3f24b 100644
--- a/include/net/sctp/ulpqueue.h
+++ b/include/net/sctp/ulpqueue.h
@@ -49,7 +49,6 @@
/* A structure to carry information to the ULP (e.g. Sockets API) */
struct sctp_ulpq {
- char malloced;
char pd_mode;
struct sctp_association *asoc;
struct sk_buff_head reasm;
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
index c2e542b27a5a..6ca975bebd37 100644
--- a/include/net/secure_seq.h
+++ b/include/net/secure_seq.h
@@ -3,6 +3,7 @@
#include <linux/types.h>
+extern void net_secret_init(void);
extern __u32 secure_ip_id(__be32 daddr);
extern __u32 secure_ipv6_id(const __be32 daddr[4]);
extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
diff --git a/include/net/sock.h b/include/net/sock.h
index 14f6e9d19dc7..5c97b0fc5623 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -667,6 +667,7 @@ enum sock_flags {
* user-space instead.
*/
SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
+ SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
};
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -2158,10 +2159,9 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
* @sk: socket sending this packet
* @tx_flags: filled with instructions for time stamping
*
- * Currently only depends on SOCK_TIMESTAMPING* flags. Returns error code if
- * parameters are invalid.
+ * Currently only depends on SOCK_TIMESTAMPING* flags.
*/
-extern int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags);
+extern void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags);
/**
* sk_eat_skb - Release a skb if it is no longer needed
diff --git a/include/net/tcp.h b/include/net/tcp.h
index cf0694d4ad60..5bba80fbd1d9 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -179,7 +179,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOPT_SACK 5 /* SACK Block */
#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
-#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
#define TCPOPT_EXP 254 /* Experimental */
/* Magic number to be after the option value for sharing TCP
* experimental options. See draft-ietf-tcpm-experimental-options-00.txt
@@ -273,7 +272,6 @@ extern int sysctl_tcp_app_win;
extern int sysctl_tcp_adv_win_scale;
extern int sysctl_tcp_tw_reuse;
extern int sysctl_tcp_frto;
-extern int sysctl_tcp_frto_response;
extern int sysctl_tcp_low_latency;
extern int sysctl_tcp_dma_copybreak;
extern int sysctl_tcp_nometrics_save;
@@ -284,7 +282,6 @@ extern int sysctl_tcp_base_mss;
extern int sysctl_tcp_workaround_signed_windows;
extern int sysctl_tcp_slow_start_after_idle;
extern int sysctl_tcp_max_ssthresh;
-extern int sysctl_tcp_cookie_size;
extern int sysctl_tcp_thin_linear_timeouts;
extern int sysctl_tcp_thin_dupack;
extern int sysctl_tcp_early_retrans;
@@ -373,6 +370,7 @@ extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
extern int tcp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
extern void tcp_release_cb(struct sock *sk);
+extern void tcp_wfree(struct sk_buff *skb);
extern void tcp_write_timer_handler(struct sock *sk);
extern void tcp_delack_timer_handler(struct sock *sk);
extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg);
@@ -425,8 +423,6 @@ extern struct sock * tcp_check_req(struct sock *sk,struct sk_buff *skb,
bool fastopen);
extern int tcp_child_process(struct sock *parent, struct sock *child,
struct sk_buff *skb);
-extern bool tcp_use_frto(struct sock *sk);
-extern void tcp_enter_frto(struct sock *sk);
extern void tcp_enter_loss(struct sock *sk, int how);
extern void tcp_clear_retrans(struct tcp_sock *tp);
extern void tcp_update_metrics(struct sock *sk);
@@ -454,7 +450,7 @@ extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int nonblock, int flags, int *addr_len);
extern void tcp_parse_options(const struct sk_buff *skb,
- struct tcp_options_received *opt_rx, const u8 **hvpp,
+ struct tcp_options_received *opt_rx,
int estab, struct tcp_fastopen_cookie *foc);
extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
@@ -476,7 +472,6 @@ extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
extern int tcp_connect(struct sock *sk);
extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
- struct request_values *rvp,
struct tcp_fastopen_cookie *foc);
extern int tcp_disconnect(struct sock *sk, int flags);
@@ -543,6 +538,8 @@ extern bool tcp_syn_flood_action(struct sock *sk,
extern void tcp_push_one(struct sock *, unsigned int mss_now);
extern void tcp_send_ack(struct sock *sk);
extern void tcp_send_delayed_ack(struct sock *sk);
+extern void tcp_send_loss_probe(struct sock *sk);
+extern bool tcp_schedule_loss_probe(struct sock *sk);
/* tcp_input.c */
extern void tcp_cwnd_application_limited(struct sock *sk);
@@ -756,7 +753,6 @@ enum tcp_ca_event {
CA_EVENT_TX_START, /* first transmit when no packets in flight */
CA_EVENT_CWND_RESTART, /* congestion window restart */
CA_EVENT_COMPLETE_CWR, /* end of congestion recovery */
- CA_EVENT_FRTO, /* fast recovery timeout */
CA_EVENT_LOSS, /* loss timeout */
CA_EVENT_FAST_ACK, /* in sequence ack */
CA_EVENT_SLOW_ACK, /* other ack */
@@ -873,8 +869,8 @@ static inline void tcp_enable_fack(struct tcp_sock *tp)
static inline void tcp_enable_early_retrans(struct tcp_sock *tp)
{
tp->do_early_retrans = sysctl_tcp_early_retrans &&
- !sysctl_tcp_thin_dupack && sysctl_tcp_reordering == 3;
- tp->early_retrans_delayed = 0;
+ sysctl_tcp_early_retrans < 4 && !sysctl_tcp_thin_dupack &&
+ sysctl_tcp_reordering == 3;
}
static inline void tcp_disable_early_retrans(struct tcp_sock *tp)
@@ -1030,50 +1026,7 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp)
#endif
}
-/* Packet is added to VJ-style prequeue for processing in process
- * context, if a reader task is waiting. Apparently, this exciting
- * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93)
- * failed somewhere. Latency? Burstiness? Well, at least now we will
- * see, why it failed. 8)8) --ANK
- *
- * NOTE: is this not too big to inline?
- */
-static inline bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- if (sysctl_tcp_low_latency || !tp->ucopy.task)
- return false;
-
- if (skb->len <= tcp_hdrlen(skb) &&
- skb_queue_len(&tp->ucopy.prequeue) == 0)
- return false;
-
- __skb_queue_tail(&tp->ucopy.prequeue, skb);
- tp->ucopy.memory += skb->truesize;
- if (tp->ucopy.memory > sk->sk_rcvbuf) {
- struct sk_buff *skb1;
-
- BUG_ON(sock_owned_by_user(sk));
-
- while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
- sk_backlog_rcv(sk, skb1);
- NET_INC_STATS_BH(sock_net(sk),
- LINUX_MIB_TCPPREQUEUEDROPPED);
- }
-
- tp->ucopy.memory = 0;
- } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
- wake_up_interruptible_sync_poll(sk_sleep(sk),
- POLLIN | POLLRDNORM | POLLRDBAND);
- if (!inet_csk_ack_scheduled(sk))
- inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
- (3 * tcp_rto_min(sk)) / 4,
- TCP_RTO_MAX);
- }
- return true;
-}
-
+extern bool tcp_prequeue(struct sock *sk, struct sk_buff *skb);
#undef STATE_TRACE
@@ -1630,91 +1583,6 @@ struct tcp_request_sock_ops {
#endif
};
-/* Using SHA1 for now, define some constants.
- */
-#define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS)
-#define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4)
-#define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS)
-
-extern int tcp_cookie_generator(u32 *bakery);
-
-/**
- * struct tcp_cookie_values - each socket needs extra space for the
- * cookies, together with (optional) space for any SYN data.
- *
- * A tcp_sock contains a pointer to the current value, and this is
- * cloned to the tcp_timewait_sock.
- *
- * @cookie_pair: variable data from the option exchange.
- *
- * @cookie_desired: user specified tcpct_cookie_desired. Zero
- * indicates default (sysctl_tcp_cookie_size).
- * After cookie sent, remembers size of cookie.
- * Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX.
- *
- * @s_data_desired: user specified tcpct_s_data_desired. When the
- * constant payload is specified (@s_data_constant),
- * holds its length instead.
- * Range 0 to TCP_MSS_DESIRED.
- *
- * @s_data_payload: constant data that is to be included in the
- * payload of SYN or SYNACK segments when the
- * cookie option is present.
- */
-struct tcp_cookie_values {
- struct kref kref;
- u8 cookie_pair[TCP_COOKIE_PAIR_SIZE];
- u8 cookie_pair_size;
- u8 cookie_desired;
- u16 s_data_desired:11,
- s_data_constant:1,
- s_data_in:1,
- s_data_out:1,
- s_data_unused:2;
- u8 s_data_payload[0];
-};
-
-static inline void tcp_cookie_values_release(struct kref *kref)
-{
- kfree(container_of(kref, struct tcp_cookie_values, kref));
-}
-
-/* The length of constant payload data. Note that s_data_desired is
- * overloaded, depending on s_data_constant: either the length of constant
- * data (returned here) or the limit on variable data.
- */
-static inline int tcp_s_data_size(const struct tcp_sock *tp)
-{
- return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant)
- ? tp->cookie_values->s_data_desired
- : 0;
-}
-
-/**
- * struct tcp_extend_values - tcp_ipv?.c to tcp_output.c workspace.
- *
- * As tcp_request_sock has already been extended in other places, the
- * only remaining method is to pass stack values along as function
- * parameters. These parameters are not needed after sending SYNACK.
- *
- * @cookie_bakery: cryptographic secret and message workspace.
- *
- * @cookie_plus: bytes in authenticator/cookie option, copied from
- * struct tcp_options_received (above).
- */
-struct tcp_extend_values {
- struct request_values rv;
- u32 cookie_bakery[COOKIE_WORKSPACE_WORDS];
- u8 cookie_plus:6,
- cookie_out_never:1,
- cookie_in_always:1;
-};
-
-static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp)
-{
- return (struct tcp_extend_values *)rvp;
-}
-
extern void tcp_v4_init(void);
extern void tcp_init(void);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 24c8886fd969..ae16531d0d35 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -162,6 +162,7 @@ struct xfrm_state {
xfrm_address_t saddr;
int header_len;
int trailer_len;
+ u32 extra_flags;
} props;
struct xfrm_lifetime_cfg lft;
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 3bbbd78e1439..2d56e428506c 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -65,6 +65,18 @@ struct pcmcia_driver {
int pcmcia_register_driver(struct pcmcia_driver *driver);
void pcmcia_unregister_driver(struct pcmcia_driver *driver);
+/**
+ * module_pcmcia_driver() - Helper macro for registering a pcmcia driver
+ * @__pcmcia_driver: pcmcia_driver struct
+ *
+ * Helper macro for pcmcia drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only use
+ * this macro once, and calling it replaces module_init() and module_exit().
+ */
+#define module_pcmcia_driver(__pcmcia_driver) \
+ module_driver(__pcmcia_driver, pcmcia_register_driver, \
+ pcmcia_unregister_driver)
+
/* for struct resource * array embedded in struct pcmcia_device */
enum {
PCMCIA_IOPORT_0,
diff --git a/include/scsi/Kbuild b/include/scsi/Kbuild
deleted file mode 100644
index 562ff9d591b8..000000000000
--- a/include/scsi/Kbuild
+++ /dev/null
@@ -1 +0,0 @@
-header-y += fc/
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 917741bb8e11..fe7f06c86f68 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -63,6 +63,12 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_PING = UEVENT_BASE + 22,
ISCSI_UEVENT_GET_CHAP = UEVENT_BASE + 23,
ISCSI_UEVENT_DELETE_CHAP = UEVENT_BASE + 24,
+ ISCSI_UEVENT_SET_FLASHNODE_PARAMS = UEVENT_BASE + 25,
+ ISCSI_UEVENT_NEW_FLASHNODE = UEVENT_BASE + 26,
+ ISCSI_UEVENT_DEL_FLASHNODE = UEVENT_BASE + 27,
+ ISCSI_UEVENT_LOGIN_FLASHNODE = UEVENT_BASE + 28,
+ ISCSI_UEVENT_LOGOUT_FLASHNODE = UEVENT_BASE + 29,
+ ISCSI_UEVENT_LOGOUT_FLASHNODE_SID = UEVENT_BASE + 30,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -210,6 +216,31 @@ struct iscsi_uevent {
uint32_t host_no;
uint16_t chap_tbl_idx;
} delete_chap;
+ struct msg_set_flashnode_param {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ uint32_t count;
+ } set_flashnode;
+ struct msg_new_flashnode {
+ uint32_t host_no;
+ uint32_t len;
+ } new_flashnode;
+ struct msg_del_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } del_flashnode;
+ struct msg_login_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } login_flashnode;
+ struct msg_logout_flashnode {
+ uint32_t host_no;
+ uint32_t flashnode_idx;
+ } logout_flashnode;
+ struct msg_logout_flashnode_sid {
+ uint32_t host_no;
+ uint32_t sid;
+ } logout_flashnode_sid;
} u;
union {
/* messages k -> u */
@@ -267,6 +298,9 @@ struct iscsi_uevent {
with each ping request */
uint32_t data_size;
} ping_comp;
+ struct msg_new_flashnode_ret {
+ uint32_t flashnode_idx;
+ } new_flashnode_ret;
} r;
} __attribute__ ((aligned (sizeof(uint64_t))));
@@ -274,6 +308,7 @@ enum iscsi_param_type {
ISCSI_PARAM, /* iscsi_param (session, conn, target, LU) */
ISCSI_HOST_PARAM, /* iscsi_host_param */
ISCSI_NET_PARAM, /* iscsi_net_param */
+ ISCSI_FLASHNODE_PARAM, /* iscsi_flashnode_param */
};
struct iscsi_iface_param_info {
@@ -469,6 +504,88 @@ enum iscsi_host_param {
ISCSI_HOST_PARAM_MAX,
};
+/* portal type */
+#define PORTAL_TYPE_IPV4 "ipv4"
+#define PORTAL_TYPE_IPV6 "ipv6"
+
+/* iSCSI Flash Target params */
+enum iscsi_flashnode_param {
+ ISCSI_FLASHNODE_IS_FW_ASSIGNED_IPV6,
+ ISCSI_FLASHNODE_PORTAL_TYPE,
+ ISCSI_FLASHNODE_AUTO_SND_TGT_DISABLE,
+ ISCSI_FLASHNODE_DISCOVERY_SESS,
+ ISCSI_FLASHNODE_ENTRY_EN,
+ ISCSI_FLASHNODE_HDR_DGST_EN,
+ ISCSI_FLASHNODE_DATA_DGST_EN,
+ ISCSI_FLASHNODE_IMM_DATA_EN,
+ ISCSI_FLASHNODE_INITIAL_R2T_EN,
+ ISCSI_FLASHNODE_DATASEQ_INORDER,
+ ISCSI_FLASHNODE_PDU_INORDER,
+ ISCSI_FLASHNODE_CHAP_AUTH_EN,
+ ISCSI_FLASHNODE_SNACK_REQ_EN,
+ ISCSI_FLASHNODE_DISCOVERY_LOGOUT_EN,
+ ISCSI_FLASHNODE_BIDI_CHAP_EN,
+ /* make authentication for discovery sessions optional */
+ ISCSI_FLASHNODE_DISCOVERY_AUTH_OPTIONAL,
+ ISCSI_FLASHNODE_ERL,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_STAT,
+ ISCSI_FLASHNODE_TCP_NAGLE_DISABLE,
+ ISCSI_FLASHNODE_TCP_WSF_DISABLE,
+ ISCSI_FLASHNODE_TCP_TIMER_SCALE,
+ ISCSI_FLASHNODE_TCP_TIMESTAMP_EN,
+ ISCSI_FLASHNODE_IP_FRAG_DISABLE,
+ ISCSI_FLASHNODE_MAX_RECV_DLENGTH,
+ ISCSI_FLASHNODE_MAX_XMIT_DLENGTH,
+ ISCSI_FLASHNODE_FIRST_BURST,
+ ISCSI_FLASHNODE_DEF_TIME2WAIT,
+ ISCSI_FLASHNODE_DEF_TIME2RETAIN,
+ ISCSI_FLASHNODE_MAX_R2T,
+ ISCSI_FLASHNODE_KEEPALIVE_TMO,
+ ISCSI_FLASHNODE_ISID,
+ ISCSI_FLASHNODE_TSID,
+ ISCSI_FLASHNODE_PORT,
+ ISCSI_FLASHNODE_MAX_BURST,
+ ISCSI_FLASHNODE_DEF_TASKMGMT_TMO,
+ ISCSI_FLASHNODE_IPADDR,
+ ISCSI_FLASHNODE_ALIAS,
+ ISCSI_FLASHNODE_REDIRECT_IPADDR,
+ ISCSI_FLASHNODE_MAX_SEGMENT_SIZE,
+ ISCSI_FLASHNODE_LOCAL_PORT,
+ ISCSI_FLASHNODE_IPV4_TOS,
+ ISCSI_FLASHNODE_IPV6_TC,
+ ISCSI_FLASHNODE_IPV6_FLOW_LABEL,
+ ISCSI_FLASHNODE_NAME,
+ ISCSI_FLASHNODE_TPGT,
+ ISCSI_FLASHNODE_LINK_LOCAL_IPV6,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_IDX,
+ ISCSI_FLASHNODE_DISCOVERY_PARENT_TYPE,
+ ISCSI_FLASHNODE_TCP_XMIT_WSF,
+ ISCSI_FLASHNODE_TCP_RECV_WSF,
+ ISCSI_FLASHNODE_CHAP_IN_IDX,
+ ISCSI_FLASHNODE_CHAP_OUT_IDX,
+ ISCSI_FLASHNODE_USERNAME,
+ ISCSI_FLASHNODE_USERNAME_IN,
+ ISCSI_FLASHNODE_PASSWORD,
+ ISCSI_FLASHNODE_PASSWORD_IN,
+ ISCSI_FLASHNODE_STATSN,
+ ISCSI_FLASHNODE_EXP_STATSN,
+ ISCSI_FLASHNODE_IS_BOOT_TGT,
+
+ ISCSI_FLASHNODE_MAX,
+};
+
+struct iscsi_flashnode_param_info {
+ uint32_t len; /* Actual length of the param */
+ uint16_t param; /* iscsi param value */
+ uint8_t value[0]; /* length sized value follows */
+} __packed;
+
+enum iscsi_discovery_parent_type {
+ ISCSI_DISC_PARENT_UNKNOWN = 0x1,
+ ISCSI_DISC_PARENT_SENDTGT = 0x2,
+ ISCSI_DISC_PARENT_ISNS = 0x3,
+};
+
/* iSCSI port Speed */
enum iscsi_port_speed {
ISCSI_PORT_SPEED_UNKNOWN = 0x1,
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 399162b50a8d..e1379b4e8faf 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -1074,7 +1074,8 @@ void fc_rport_terminate_io(struct fc_rport *);
/*
* DISCOVERY LAYER
*****************************/
-int fc_disc_init(struct fc_lport *);
+void fc_disc_init(struct fc_lport *);
+void fc_disc_config(struct fc_lport *, void *);
static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
{
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 6e33386a3898..09c041e6c35f 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -427,6 +427,7 @@ extern void iscsi_complete_scsi_task(struct iscsi_task *task,
*/
extern void iscsi_pool_free(struct iscsi_pool *);
extern int iscsi_pool_init(struct iscsi_pool *, int, void ***, int);
+extern int iscsi_switch_str_param(char **, char *);
/*
* inline functions to deal with padding.
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index 53f0b361d668..4a58cca2ecc1 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -39,6 +39,8 @@ struct iscsi_task;
struct sockaddr;
struct iscsi_iface;
struct bsg_job;
+struct iscsi_bus_flash_session;
+struct iscsi_bus_flash_conn;
/**
* struct iscsi_transport - iSCSI Transport template
@@ -150,6 +152,19 @@ struct iscsi_transport {
int (*get_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx,
uint32_t *num_entries, char *buf);
int (*delete_chap) (struct Scsi_Host *shost, uint16_t chap_tbl_idx);
+ int (*get_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess,
+ int param, char *buf);
+ int (*set_flashnode_param) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn,
+ void *data, int len);
+ int (*new_flashnode) (struct Scsi_Host *shost, const char *buf,
+ int len);
+ int (*del_flashnode) (struct iscsi_bus_flash_session *fnode_sess);
+ int (*login_flashnode) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+ int (*logout_flashnode) (struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_bus_flash_conn *fnode_conn);
+ int (*logout_flashnode_sid) (struct iscsi_cls_session *cls_sess);
};
/*
@@ -286,6 +301,112 @@ struct iscsi_iface {
#define iscsi_iface_to_shost(_iface) \
dev_to_shost(_iface->dev.parent)
+
+struct iscsi_bus_flash_conn {
+ struct list_head conn_list; /* item in connlist */
+ void *dd_data; /* LLD private data */
+ struct iscsi_transport *transport;
+ struct device dev; /* sysfs transport/container device */
+ /* iscsi connection parameters */
+ uint32_t exp_statsn;
+ uint32_t statsn;
+ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
+ unsigned max_xmit_dlength; /* target_max_recv_dsl */
+ unsigned max_segment_size;
+ unsigned tcp_xmit_wsf;
+ unsigned tcp_recv_wsf;
+ int hdrdgst_en;
+ int datadgst_en;
+ int port;
+ char *ipaddress;
+ char *link_local_ipv6_addr;
+ char *redirect_ipaddr;
+ uint16_t keepalive_timeout;
+ uint16_t local_port;
+ uint8_t snack_req_en;
+ /* tcp timestamp negotiation status */
+ uint8_t tcp_timestamp_stat;
+ uint8_t tcp_nagle_disable;
+ /* tcp window scale factor */
+ uint8_t tcp_wsf_disable;
+ uint8_t tcp_timer_scale;
+ uint8_t tcp_timestamp_en;
+ uint8_t ipv4_tos;
+ uint8_t ipv6_traffic_class;
+ uint8_t ipv6_flow_label;
+ uint8_t fragment_disable;
+ /* Link local IPv6 address is assigned by firmware or driver */
+ uint8_t is_fw_assigned_ipv6;
+};
+
+#define iscsi_dev_to_flash_conn(_dev) \
+ container_of(_dev, struct iscsi_bus_flash_conn, dev)
+
+#define iscsi_flash_conn_to_flash_session(_conn) \
+ iscsi_dev_to_flash_session(_conn->dev.parent)
+
+#define ISID_SIZE 6
+
+struct iscsi_bus_flash_session {
+ struct list_head sess_list; /* item in session_list */
+ struct iscsi_transport *transport;
+ unsigned int target_id;
+ int flash_state; /* persistent or non-persistent */
+ void *dd_data; /* LLD private data */
+ struct device dev; /* sysfs transport/container device */
+ /* iscsi session parameters */
+ unsigned first_burst;
+ unsigned max_burst;
+ unsigned short max_r2t;
+ int default_taskmgmt_timeout;
+ int initial_r2t_en;
+ int imm_data_en;
+ int time2wait;
+ int time2retain;
+ int pdu_inorder_en;
+ int dataseq_inorder_en;
+ int erl;
+ int tpgt;
+ char *username;
+ char *username_in;
+ char *password;
+ char *password_in;
+ char *targetname;
+ char *targetalias;
+ char *portal_type;
+ uint16_t tsid;
+ uint16_t chap_in_idx;
+ uint16_t chap_out_idx;
+ /* index of iSCSI discovery session if the entry is
+ * discovered by iSCSI discovery session
+ */
+ uint16_t discovery_parent_idx;
+ /* indicates if discovery was done through iSNS discovery service
+ * or through sendTarget */
+ uint16_t discovery_parent_type;
+ /* Firmware auto sendtarget discovery disable */
+ uint8_t auto_snd_tgt_disable;
+ uint8_t discovery_sess;
+ /* indicates if this flashnode entry is enabled or disabled */
+ uint8_t entry_state;
+ uint8_t chap_auth_en;
+ /* enables firmware to auto logout the discovery session on discovery
+ * completion
+ */
+ uint8_t discovery_logout_en;
+ uint8_t bidi_chap_en;
+ /* makes authentication for discovery session optional */
+ uint8_t discovery_auth_optional;
+ uint8_t isid[ISID_SIZE];
+ uint8_t is_boot_target;
+};
+
+#define iscsi_dev_to_flash_session(_dev) \
+ container_of(_dev, struct iscsi_bus_flash_session, dev)
+
+#define iscsi_flash_session_to_shost(_session) \
+ dev_to_shost(_session->dev.parent)
+
/*
* session and connection functions that can be used by HW iSCSI LLDs
*/
@@ -330,4 +451,34 @@ extern char *iscsi_get_port_speed_name(struct Scsi_Host *shost);
extern char *iscsi_get_port_state_name(struct Scsi_Host *shost);
extern int iscsi_is_session_dev(const struct device *dev);
+extern char *iscsi_get_discovery_parent_name(int parent_type);
+extern struct device *
+iscsi_find_flashnode(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data));
+
+extern struct iscsi_bus_flash_session *
+iscsi_create_flashnode_sess(struct Scsi_Host *shost, int index,
+ struct iscsi_transport *transport, int dd_size);
+
+extern struct iscsi_bus_flash_conn *
+iscsi_create_flashnode_conn(struct Scsi_Host *shost,
+ struct iscsi_bus_flash_session *fnode_sess,
+ struct iscsi_transport *transport, int dd_size);
+
+extern void
+iscsi_destroy_flashnode_sess(struct iscsi_bus_flash_session *fnode_sess);
+
+extern void iscsi_destroy_all_flashnode(struct Scsi_Host *shost);
+extern int iscsi_flashnode_bus_match(struct device *dev,
+ struct device_driver *drv);
+extern int iscsi_is_flashnode_conn_dev(struct device *dev, void *data);
+
+extern struct device *
+iscsi_find_flashnode_sess(struct Scsi_Host *shost, void *data,
+ int (*fn)(struct device *dev, void *data));
+
+extern struct device *
+iscsi_find_flashnode_conn(struct iscsi_bus_flash_session *fnode_sess,
+ void *data,
+ int (*fn)(struct device *dev, void *data));
#endif
diff --git a/include/sound/max98090.h b/include/sound/max98090.h
index 95efb13f8478..95efb13f8478 100755..100644
--- a/include/sound/max98090.h
+++ b/include/sound/max98090.h
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 45c1981c9ca2..5ec42dbd2308 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -867,7 +867,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format); /* in bits */
ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples);
const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format);
int snd_pcm_format_set_silence(snd_pcm_format_t format, void *buf, unsigned int frames);
-snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
+snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsigned, int big_endian);
void snd_pcm_set_ops(struct snd_pcm * pcm, int direction, struct snd_pcm_ops *ops);
void snd_pcm_set_sync(struct snd_pcm_substream *substream);
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index e1ef63d4a5c4..44a30b108683 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -488,6 +488,7 @@ struct snd_soc_dapm_path {
/* status */
u32 connect:1; /* source and sink widgets are connected */
u32 walked:1; /* path has been walked */
+ u32 walking:1; /* path is in the process of being walked */
u32 weak:1; /* path ignored for power management */
int (*connected)(struct snd_soc_dapm_widget *source,
diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h
new file mode 100644
index 000000000000..23a87d0cd72c
--- /dev/null
+++ b/include/target/iscsi/iscsi_transport.h
@@ -0,0 +1,83 @@
+#include <linux/module.h>
+#include <linux/list.h>
+#include "../../../drivers/target/iscsi/iscsi_target_core.h"
+
+struct iscsit_transport {
+#define ISCSIT_TRANSPORT_NAME 16
+ char name[ISCSIT_TRANSPORT_NAME];
+ int transport_type;
+ struct module *owner;
+ struct list_head t_node;
+ int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
+ int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
+ void (*iscsit_free_np)(struct iscsi_np *);
+ void (*iscsit_free_conn)(struct iscsi_conn *);
+ struct iscsi_cmd *(*iscsit_alloc_cmd)(struct iscsi_conn *, gfp_t);
+ int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
+ int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
+ int (*iscsit_immediate_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
+ int (*iscsit_response_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
+ int (*iscsit_get_dataout)(struct iscsi_conn *, struct iscsi_cmd *, bool);
+ int (*iscsit_queue_data_in)(struct iscsi_conn *, struct iscsi_cmd *);
+ int (*iscsit_queue_status)(struct iscsi_conn *, struct iscsi_cmd *);
+};
+
+/*
+ * From iscsi_target_transport.c
+ */
+
+extern int iscsit_register_transport(struct iscsit_transport *);
+extern void iscsit_unregister_transport(struct iscsit_transport *);
+extern struct iscsit_transport *iscsit_get_transport(int);
+extern void iscsit_put_transport(struct iscsit_transport *);
+
+/*
+ * From iscsi_target.c
+ */
+extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *,
+ struct iscsi_cmd *);
+extern int iscsit_setup_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
+extern int iscsit_process_scsi_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ struct iscsi_scsi_req *);
+extern int iscsit_check_dataout_hdr(struct iscsi_conn *, unsigned char *,
+ struct iscsi_cmd **);
+extern int iscsit_check_dataout_payload(struct iscsi_cmd *, struct iscsi_data *,
+ bool);
+extern int iscsit_handle_nop_out(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern int iscsit_handle_logout_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern int iscsit_handle_task_mgt_cmd(struct iscsi_conn *, struct iscsi_cmd *,
+ unsigned char *);
+extern void iscsit_build_rsp_pdu(struct iscsi_cmd *, struct iscsi_conn *,
+ bool, struct iscsi_scsi_rsp *);
+extern void iscsit_build_nopin_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_nopin *, bool);
+extern void iscsit_build_task_mgt_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_tm_rsp *);
+extern void iscsit_build_reject(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_reject *);
+extern int iscsit_build_logout_rsp(struct iscsi_cmd *, struct iscsi_conn *,
+ struct iscsi_logout_rsp *);
+extern int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+/*
+ * From iscsi_target_device.c
+ */
+extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *);
+/*
+ * From iscsi_target_erl1.c
+ */
+extern void iscsit_stop_dataout_timer(struct iscsi_cmd *);
+
+/*
+ * From iscsi_target_tmr.c
+ */
+extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
+
+/*
+ * From iscsi_target_util.c
+ */
+extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *, __be32);
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h
index b128c20770bc..ffa2696d64dc 100644
--- a/include/target/target_core_backend.h
+++ b/include/target/target_core_backend.h
@@ -60,6 +60,10 @@ sense_reason_t sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops);
u32 sbc_get_device_rev(struct se_device *dev);
u32 sbc_get_device_type(struct se_device *dev);
sector_t sbc_get_write_same_sectors(struct se_cmd *cmd);
+sense_reason_t sbc_execute_unmap(struct se_cmd *cmd,
+ sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv,
+ sector_t lba, sector_t nolb),
+ void *priv);
void transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
int transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index aaa1ee6ab391..ba3471b73c07 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -120,7 +120,7 @@ bool transport_wait_for_tasks(struct se_cmd *);
int transport_check_aborted_status(struct se_cmd *, int);
int transport_send_check_condition_and_sense(struct se_cmd *,
sense_reason_t, int);
-
+int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool);
int target_put_sess_cmd(struct se_session *, struct se_cmd *);
void target_sess_cmd_list_set_waiting(struct se_session *);
void target_wait_for_sess_cmds(struct se_session *, int);
diff --git a/include/trace/events/block.h b/include/trace/events/block.h
index 9961726523d0..9c1467357b03 100644
--- a/include/trace/events/block.h
+++ b/include/trace/events/block.h
@@ -257,6 +257,7 @@ TRACE_EVENT(block_bio_bounce,
/**
* block_bio_complete - completed all work on the block operation
+ * @q: queue holding the block operation
* @bio: block operation completed
* @error: io error value
*
@@ -265,9 +266,9 @@ TRACE_EVENT(block_bio_bounce,
*/
TRACE_EVENT(block_bio_complete,
- TP_PROTO(struct bio *bio, int error),
+ TP_PROTO(struct request_queue *q, struct bio *bio, int error),
- TP_ARGS(bio, error),
+ TP_ARGS(q, bio, error),
TP_STRUCT__entry(
__field( dev_t, dev )
@@ -278,8 +279,7 @@ TRACE_EVENT(block_bio_complete,
),
TP_fast_assign(
- __entry->dev = bio->bi_bdev ?
- bio->bi_bdev->bd_dev : 0;
+ __entry->dev = bio->bi_bdev->bd_dev;
__entry->sector = bio->bi_sector;
__entry->nr_sector = bio->bi_size >> 9;
__entry->error = error;
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 4ee471003859..d0e686402df8 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -257,15 +257,7 @@ DECLARE_EVENT_CLASS(ext4__write_end,
__entry->pos, __entry->len, __entry->copied)
);
-DEFINE_EVENT(ext4__write_end, ext4_ordered_write_end,
-
- TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
- unsigned int copied),
-
- TP_ARGS(inode, pos, len, copied)
-);
-
-DEFINE_EVENT(ext4__write_end, ext4_writeback_write_end,
+DEFINE_EVENT(ext4__write_end, ext4_write_end,
TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
unsigned int copied),
@@ -1956,7 +1948,7 @@ TRACE_EVENT(ext4_remove_blocks,
__entry->to = to;
__entry->partial = partial_cluster;
__entry->ee_pblk = ext4_ext_pblock(ex);
- __entry->ee_lblk = cpu_to_le32(ex->ee_block);
+ __entry->ee_lblk = le32_to_cpu(ex->ee_block);
__entry->ee_len = ext4_ext_get_actual_len(ex);
),
@@ -2060,7 +2052,7 @@ TRACE_EVENT(ext4_ext_remove_space,
TRACE_EVENT(ext4_ext_remove_space_done,
TP_PROTO(struct inode *inode, ext4_lblk_t start, int depth,
- ext4_lblk_t partial, unsigned short eh_entries),
+ ext4_lblk_t partial, __le16 eh_entries),
TP_ARGS(inode, start, depth, partial, eh_entries),
@@ -2079,7 +2071,7 @@ TRACE_EVENT(ext4_ext_remove_space_done,
__entry->start = start;
__entry->depth = depth;
__entry->partial = partial;
- __entry->eh_entries = eh_entries;
+ __entry->eh_entries = le16_to_cpu(eh_entries);
),
TP_printk("dev %d,%d ino %lu since %u depth %d partial %u "
diff --git a/include/trace/events/filemap.h b/include/trace/events/filemap.h
new file mode 100644
index 000000000000..0421f49a20f7
--- /dev/null
+++ b/include/trace/events/filemap.h
@@ -0,0 +1,58 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM filemap
+
+#if !defined(_TRACE_FILEMAP_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FILEMAP_H
+
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+#include <linux/mm.h>
+#include <linux/memcontrol.h>
+#include <linux/device.h>
+#include <linux/kdev_t.h>
+
+DECLARE_EVENT_CLASS(mm_filemap_op_page_cache,
+
+ TP_PROTO(struct page *page),
+
+ TP_ARGS(page),
+
+ TP_STRUCT__entry(
+ __field(struct page *, page)
+ __field(unsigned long, i_ino)
+ __field(unsigned long, index)
+ __field(dev_t, s_dev)
+ ),
+
+ TP_fast_assign(
+ __entry->page = page;
+ __entry->i_ino = page->mapping->host->i_ino;
+ __entry->index = page->index;
+ if (page->mapping->host->i_sb)
+ __entry->s_dev = page->mapping->host->i_sb->s_dev;
+ else
+ __entry->s_dev = page->mapping->host->i_rdev;
+ ),
+
+ TP_printk("dev %d:%d ino %lx page=%p pfn=%lu ofs=%lu",
+ MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
+ __entry->i_ino,
+ __entry->page,
+ page_to_pfn(__entry->page),
+ __entry->index << PAGE_SHIFT)
+);
+
+DEFINE_EVENT(mm_filemap_op_page_cache, mm_filemap_delete_from_page_cache,
+ TP_PROTO(struct page *page),
+ TP_ARGS(page)
+ );
+
+DEFINE_EVENT(mm_filemap_op_page_cache, mm_filemap_add_to_page_cache,
+ TP_PROTO(struct page *page),
+ TP_ARGS(page)
+ );
+
+#endif /* _TRACE_FILEMAP_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
index 070df49e4a1d..c1d1f3eb242d 100644
--- a/include/trace/events/jbd2.h
+++ b/include/trace/events/jbd2.h
@@ -358,6 +358,27 @@ TRACE_EVENT(jbd2_write_superblock,
MINOR(__entry->dev), __entry->write_op)
);
+TRACE_EVENT(jbd2_lock_buffer_stall,
+
+ TP_PROTO(dev_t dev, unsigned long stall_ms),
+
+ TP_ARGS(dev, stall_ms),
+
+ TP_STRUCT__entry(
+ __field( dev_t, dev )
+ __field(unsigned long, stall_ms )
+ ),
+
+ TP_fast_assign(
+ __entry->dev = dev;
+ __entry->stall_ms = stall_ms;
+ ),
+
+ TP_printk("dev %d,%d stall_ms %lu",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->stall_ms)
+);
+
#endif /* _TRACE_JBD2_H */
/* This part must be outside protection */
diff --git a/include/trace/events/printk.h b/include/trace/events/printk.h
index 94ec79cc011a..c008bc99f9fa 100644
--- a/include/trace/events/printk.h
+++ b/include/trace/events/printk.h
@@ -6,31 +6,18 @@
#include <linux/tracepoint.h>
-TRACE_EVENT_CONDITION(console,
- TP_PROTO(const char *log_buf, unsigned start, unsigned end,
- unsigned log_buf_len),
+TRACE_EVENT(console,
+ TP_PROTO(const char *text, size_t len),
- TP_ARGS(log_buf, start, end, log_buf_len),
-
- TP_CONDITION(start != end),
+ TP_ARGS(text, len),
TP_STRUCT__entry(
- __dynamic_array(char, msg, end - start + 1)
+ __dynamic_array(char, msg, len + 1)
),
TP_fast_assign(
- if ((start & (log_buf_len - 1)) > (end & (log_buf_len - 1))) {
- memcpy(__get_dynamic_array(msg),
- log_buf + (start & (log_buf_len - 1)),
- log_buf_len - (start & (log_buf_len - 1)));
- memcpy((char *)__get_dynamic_array(msg) +
- log_buf_len - (start & (log_buf_len - 1)),
- log_buf, end & (log_buf_len - 1));
- } else
- memcpy(__get_dynamic_array(msg),
- log_buf + (start & (log_buf_len - 1)),
- end - start);
- ((char *)__get_dynamic_array(msg))[end - start] = 0;
+ memcpy(__get_dynamic_array(msg), text, len);
+ ((char *)__get_dynamic_array(msg))[len] = 0;
),
TP_printk("%s", __get_str(msg))
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index 1918e832da4f..59ebcc89f148 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -72,6 +72,58 @@ TRACE_EVENT(rcu_grace_period,
);
/*
+ * Tracepoint for future grace-period events, including those for no-callbacks
+ * CPUs. The caller should pull the data from the rcu_node structure,
+ * other than rcuname, which comes from the rcu_state structure, and event,
+ * which is one of the following:
+ *
+ * "Startleaf": Request a nocb grace period based on leaf-node data.
+ * "Startedleaf": Leaf-node start proved sufficient.
+ * "Startedleafroot": Leaf-node start proved sufficient after checking root.
+ * "Startedroot": Requested a nocb grace period based on root-node data.
+ * "StartWait": Start waiting for the requested grace period.
+ * "ResumeWait": Resume waiting after signal.
+ * "EndWait": Complete wait.
+ * "Cleanup": Clean up rcu_node structure after previous GP.
+ * "CleanupMore": Clean up, and another no-CB GP is needed.
+ */
+TRACE_EVENT(rcu_future_grace_period,
+
+ TP_PROTO(char *rcuname, unsigned long gpnum, unsigned long completed,
+ unsigned long c, u8 level, int grplo, int grphi,
+ char *gpevent),
+
+ TP_ARGS(rcuname, gpnum, completed, c, level, grplo, grphi, gpevent),
+
+ TP_STRUCT__entry(
+ __field(char *, rcuname)
+ __field(unsigned long, gpnum)
+ __field(unsigned long, completed)
+ __field(unsigned long, c)
+ __field(u8, level)
+ __field(int, grplo)
+ __field(int, grphi)
+ __field(char *, gpevent)
+ ),
+
+ TP_fast_assign(
+ __entry->rcuname = rcuname;
+ __entry->gpnum = gpnum;
+ __entry->completed = completed;
+ __entry->c = c;
+ __entry->level = level;
+ __entry->grplo = grplo;
+ __entry->grphi = grphi;
+ __entry->gpevent = gpevent;
+ ),
+
+ TP_printk("%s %lu %lu %lu %u %d %d %s",
+ __entry->rcuname, __entry->gpnum, __entry->completed,
+ __entry->c, __entry->level, __entry->grplo, __entry->grphi,
+ __entry->gpevent)
+);
+
+/*
* Tracepoint for grace-period-initialization events. These are
* distinguished by the type of RCU, the new grace-period number, the
* rcu_node structure level, the starting and ending CPU covered by the
@@ -601,6 +653,9 @@ TRACE_EVENT(rcu_barrier,
#define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0)
#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \
qsmask) do { } while (0)
+#define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \
+ level, grplo, grphi, event) \
+ do { } while (0)
#define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0)
#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0)
#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \
diff --git a/include/trace/events/regmap.h b/include/trace/events/regmap.h
index 41a7dbd570e2..a43a2f67bd8e 100644
--- a/include/trace/events/regmap.h
+++ b/include/trace/events/regmap.h
@@ -175,6 +175,54 @@ DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
);
+DECLARE_EVENT_CLASS(regmap_async,
+
+ TP_PROTO(struct device *dev),
+
+ TP_ARGS(dev),
+
+ TP_STRUCT__entry(
+ __string( name, dev_name(dev) )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, dev_name(dev));
+ ),
+
+ TP_printk("%s", __get_str(name))
+);
+
+DEFINE_EVENT(regmap_block, regmap_async_write_start,
+
+ TP_PROTO(struct device *dev, unsigned int reg, int count),
+
+ TP_ARGS(dev, reg, count)
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_io_complete,
+
+ TP_PROTO(struct device *dev),
+
+ TP_ARGS(dev)
+
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_complete_start,
+
+ TP_PROTO(struct device *dev),
+
+ TP_ARGS(dev)
+
+);
+
+DEFINE_EVENT(regmap_async, regmap_async_complete_done,
+
+ TP_PROTO(struct device *dev),
+
+ TP_ARGS(dev)
+
+);
+
#endif /* _TRACE_REGMAP_H */
/* This part must be outside protection */
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 5a8671e8a67f..e5586caff67a 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -147,7 +147,7 @@ TRACE_EVENT(sched_switch,
__print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",
{ 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
{ 16, "Z" }, { 32, "X" }, { 64, "x" },
- { 128, "W" }) : "R",
+ { 128, "K" }, { 256, "W" }, { 512, "P" }) : "R",
__entry->prev_state & TASK_STATE_MAX ? "+" : "",
__entry->next_comm, __entry->next_pid, __entry->next_prio)
);
diff --git a/include/trace/events/timer.h b/include/trace/events/timer.h
index 425bcfe56c62..8d219470624f 100644
--- a/include/trace/events/timer.h
+++ b/include/trace/events/timer.h
@@ -123,7 +123,7 @@ DEFINE_EVENT(timer_class, timer_cancel,
/**
* hrtimer_init - called when the hrtimer is initialized
- * @timer: pointer to struct hrtimer
+ * @hrtimer: pointer to struct hrtimer
* @clockid: the hrtimers clock
* @mode: the hrtimers mode
*/
@@ -155,7 +155,7 @@ TRACE_EVENT(hrtimer_init,
/**
* hrtimer_start - called when the hrtimer is started
- * @timer: pointer to struct hrtimer
+ * @hrtimer: pointer to struct hrtimer
*/
TRACE_EVENT(hrtimer_start,
@@ -186,8 +186,8 @@ TRACE_EVENT(hrtimer_start,
);
/**
- * htimmer_expire_entry - called immediately before the hrtimer callback
- * @timer: pointer to struct hrtimer
+ * hrtimer_expire_entry - called immediately before the hrtimer callback
+ * @hrtimer: pointer to struct hrtimer
* @now: pointer to variable which contains current time of the
* timers base.
*
@@ -234,7 +234,7 @@ DECLARE_EVENT_CLASS(hrtimer_class,
/**
* hrtimer_expire_exit - called immediately after the hrtimer callback returns
- * @timer: pointer to struct hrtimer
+ * @hrtimer: pointer to struct hrtimer
*
* When used in combination with the hrtimer_expire_entry tracepoint we can
* determine the runtime of the callback function.
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 40dc5e8fe340..19edd7facaa1 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -227,29 +227,18 @@ static notrace enum print_line_t \
ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
struct trace_event *trace_event) \
{ \
- struct ftrace_event_call *event; \
struct trace_seq *s = &iter->seq; \
+ struct trace_seq __maybe_unused *p = &iter->tmp_seq; \
struct ftrace_raw_##call *field; \
- struct trace_entry *entry; \
- struct trace_seq *p = &iter->tmp_seq; \
int ret; \
\
- event = container_of(trace_event, struct ftrace_event_call, \
- event); \
- \
- entry = iter->ent; \
- \
- if (entry->type != event->event.type) { \
- WARN_ON_ONCE(1); \
- return TRACE_TYPE_UNHANDLED; \
- } \
- \
- field = (typeof(field))entry; \
+ field = (typeof(field))iter->ent; \
\
- trace_seq_init(p); \
- ret = trace_seq_printf(s, "%s: ", event->name); \
+ ret = ftrace_raw_output_prep(iter, trace_event); \
if (ret) \
- ret = trace_seq_printf(s, print); \
+ return ret; \
+ \
+ ret = trace_seq_printf(s, print); \
if (!ret) \
return TRACE_TYPE_PARTIAL_LINE; \
\
@@ -335,7 +324,7 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = { \
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \
-static int notrace \
+static int notrace __init \
ftrace_define_fields_##call(struct ftrace_event_call *event_call) \
{ \
struct ftrace_raw_##call field; \
@@ -414,7 +403,8 @@ static inline notrace int ftrace_get_offsets_##call( \
*
* static void ftrace_raw_event_<call>(void *__data, proto)
* {
- * struct ftrace_event_call *event_call = __data;
+ * struct ftrace_event_file *ftrace_file = __data;
+ * struct ftrace_event_call *event_call = ftrace_file->event_call;
* struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
* struct ring_buffer_event *event;
* struct ftrace_raw_<call> *entry; <-- defined in stage 1
@@ -423,12 +413,16 @@ static inline notrace int ftrace_get_offsets_##call( \
* int __data_size;
* int pc;
*
+ * if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
+ * &ftrace_file->flags))
+ * return;
+ *
* local_save_flags(irq_flags);
* pc = preempt_count();
*
* __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
*
- * event = trace_current_buffer_lock_reserve(&buffer,
+ * event = trace_event_buffer_lock_reserve(&buffer, ftrace_file,
* event_<call>->event.type,
* sizeof(*entry) + __data_size,
* irq_flags, pc);
@@ -440,7 +434,7 @@ static inline notrace int ftrace_get_offsets_##call( \
* __array macros.
*
* if (!filter_current_check_discard(buffer, event_call, entry, event))
- * trace_current_buffer_unlock_commit(buffer,
+ * trace_nowake_buffer_unlock_commit(buffer,
* event, irq_flags, pc);
* }
*
@@ -518,7 +512,8 @@ static inline notrace int ftrace_get_offsets_##call( \
static notrace void \
ftrace_raw_event_##call(void *__data, proto) \
{ \
- struct ftrace_event_call *event_call = __data; \
+ struct ftrace_event_file *ftrace_file = __data; \
+ struct ftrace_event_call *event_call = ftrace_file->event_call; \
struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
struct ring_buffer_event *event; \
struct ftrace_raw_##call *entry; \
@@ -527,12 +522,16 @@ ftrace_raw_event_##call(void *__data, proto) \
int __data_size; \
int pc; \
\
+ if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, \
+ &ftrace_file->flags)) \
+ return; \
+ \
local_save_flags(irq_flags); \
pc = preempt_count(); \
\
__data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
\
- event = trace_current_buffer_lock_reserve(&buffer, \
+ event = trace_event_buffer_lock_reserve(&buffer, ftrace_file, \
event_call->event.type, \
sizeof(*entry) + __data_size, \
irq_flags, pc); \
@@ -581,7 +580,7 @@ static inline void ftrace_test_probe_##call(void) \
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
_TRACE_PERF_PROTO(call, PARAMS(proto)); \
static const char print_fmt_##call[] = print; \
-static struct ftrace_event_class __used event_class_##call = { \
+static struct ftrace_event_class __used __refdata event_class_##call = { \
.system = __stringify(TRACE_SYSTEM), \
.define_fields = ftrace_define_fields_##call, \
.fields = LIST_HEAD_INIT(event_class_##call.fields),\
@@ -705,5 +704,3 @@ static inline void perf_test_probe_##call(void) \
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
#endif /* CONFIG_PERF_EVENTS */
-#undef _TRACE_PROFILE_INIT
-
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 4ef3acbba5da..c5d2e3a1cf68 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -74,4 +74,6 @@
#define SO_LOCK_FILTER 44
+#define SO_SELECT_ERR_QUEUE 45
+
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 5c8a1d25e21c..ab5d4992e568 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -285,6 +285,7 @@ header-y += nvram.h
header-y += omap3isp.h
header-y += omapfb.h
header-y += oom.h
+header-y += openvswitch.h
header-y += packet_diag.h
header-y += param.h
header-y += parport.h
@@ -331,6 +332,7 @@ header-y += rtnetlink.h
header-y += scc.h
header-y += sched.h
header-y += screen_info.h
+header-y += sctp.h
header-y += sdla.h
header-y += seccomp.h
header-y += securebits.h
diff --git a/include/uapi/linux/caif/caif_socket.h b/include/uapi/linux/caif/caif_socket.h
index 3f3bac6af7bc..586e9f98184f 100644
--- a/include/uapi/linux/caif/caif_socket.h
+++ b/include/uapi/linux/caif/caif_socket.h
@@ -1,7 +1,7 @@
/* linux/caif_socket.h
* CAIF Definitions for CAIF socket and network layer
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/uapi/linux/caif/if_caif.h b/include/uapi/linux/caif/if_caif.h
index 5e7eed4edf51..7618aabe8c6b 100644
--- a/include/uapi/linux/caif/if_caif.h
+++ b/include/uapi/linux/caif/if_caif.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/include/uapi/linux/cn_proc.h b/include/uapi/linux/cn_proc.h
index 0d7b49973bb3..f6c271035bbd 100644
--- a/include/uapi/linux/cn_proc.h
+++ b/include/uapi/linux/cn_proc.h
@@ -56,7 +56,9 @@ struct proc_event {
PROC_EVENT_PTRACE = 0x00000100,
PROC_EVENT_COMM = 0x00000200,
/* "next" should be 0x00000400 */
- /* "last" is the last process event: exit */
+ /* "last" is the last process event: exit,
+ * while "next to last" is coredumping event */
+ PROC_EVENT_COREDUMP = 0x40000000,
PROC_EVENT_EXIT = 0x80000000
} what;
__u32 cpu;
@@ -110,11 +112,17 @@ struct proc_event {
char comm[16];
} comm;
+ struct coredump_proc_event {
+ __kernel_pid_t process_pid;
+ __kernel_pid_t process_tgid;
+ } coredump;
+
struct exit_proc_event {
__kernel_pid_t process_pid;
__kernel_pid_t process_tgid;
__u32 exit_code, exit_signal;
} exit;
+
} event_data;
};
diff --git a/include/uapi/linux/connector.h b/include/uapi/linux/connector.h
index 8761a0349c74..4cb283505e45 100644
--- a/include/uapi/linux/connector.h
+++ b/include/uapi/linux/connector.h
@@ -44,8 +44,11 @@
#define CN_VAL_DRBD 0x1
#define CN_KVP_IDX 0x9 /* HyperV KVP */
#define CN_KVP_VAL 0x1 /* queries from the kernel */
+#define CN_VSS_IDX 0xA /* HyperV VSS */
+#define CN_VSS_VAL 0x1 /* queries from the kernel */
-#define CN_NETLINK_USERS 10 /* Highest index + 1 */
+
+#define CN_NETLINK_USERS 11 /* Highest index + 1 */
/*
* Maximum connector's message size.
diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h
index b2a9ad8cafdc..b4fb650d9d4f 100644
--- a/include/uapi/linux/dvb/dmx.h
+++ b/include/uapi/linux/dvb/dmx.h
@@ -51,7 +51,7 @@ typedef enum
} dmx_input_t;
-typedef enum
+typedef enum dmx_ts_pes
{
DMX_PES_AUDIO0,
DMX_PES_VIDEO0,
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index 8072d352b98f..ef6103bf1f9b 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -397,6 +397,7 @@ typedef struct elf64_shdr {
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
#define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */
#define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */
+#define NT_METAG_TLS 0x502 /* Metag TLS pointer */
/* Note header in a PT_NOTE section */
diff --git a/include/uapi/linux/filter.h b/include/uapi/linux/filter.h
index 9cfde6941099..8eb9ccaa5b48 100644
--- a/include/uapi/linux/filter.h
+++ b/include/uapi/linux/filter.h
@@ -129,7 +129,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define SKF_AD_ALU_XOR_X 40
#define SKF_AD_VLAN_TAG 44
#define SKF_AD_VLAN_TAG_PRESENT 48
-#define SKF_AD_MAX 52
+#define SKF_AD_PAY_OFFSET 52
+#define SKF_AD_MAX 56
#define SKF_NET_OFF (-0x100000)
#define SKF_LL_OFF (-0x200000)
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index c7fc1e6517c3..a4ed56cf0eac 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -88,7 +88,6 @@ struct inodes_stat_t {
#define MS_STRICTATIME (1<<24) /* Always perform atime updates */
/* These sb flags are internal to the kernel */
-#define MS_SNAP_STABLE (1<<27) /* Snapshot pages during writeback, if needed */
#define MS_NOSEC (1<<28)
#define MS_BORN (1<<29)
#define MS_ACTIVE (1<<30)
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index 4c43b4448792..706d035fa748 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -95,15 +95,10 @@
#ifndef _LINUX_FUSE_H
#define _LINUX_FUSE_H
-#ifdef __linux__
+#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
-#define __u64 uint64_t
-#define __s64 int64_t
-#define __u32 uint32_t
-#define __s32 int32_t
-#define __u16 uint16_t
#endif
/*
@@ -139,42 +134,42 @@
userspace works under 64bit kernels */
struct fuse_attr {
- __u64 ino;
- __u64 size;
- __u64 blocks;
- __u64 atime;
- __u64 mtime;
- __u64 ctime;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 ctimensec;
- __u32 mode;
- __u32 nlink;
- __u32 uid;
- __u32 gid;
- __u32 rdev;
- __u32 blksize;
- __u32 padding;
+ uint64_t ino;
+ uint64_t size;
+ uint64_t blocks;
+ uint64_t atime;
+ uint64_t mtime;
+ uint64_t ctime;
+ uint32_t atimensec;
+ uint32_t mtimensec;
+ uint32_t ctimensec;
+ uint32_t mode;
+ uint32_t nlink;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t rdev;
+ uint32_t blksize;
+ uint32_t padding;
};
struct fuse_kstatfs {
- __u64 blocks;
- __u64 bfree;
- __u64 bavail;
- __u64 files;
- __u64 ffree;
- __u32 bsize;
- __u32 namelen;
- __u32 frsize;
- __u32 padding;
- __u32 spare[6];
+ uint64_t blocks;
+ uint64_t bfree;
+ uint64_t bavail;
+ uint64_t files;
+ uint64_t ffree;
+ uint32_t bsize;
+ uint32_t namelen;
+ uint32_t frsize;
+ uint32_t padding;
+ uint32_t spare[6];
};
struct fuse_file_lock {
- __u64 start;
- __u64 end;
- __u32 type;
- __u32 pid; /* tgid */
+ uint64_t start;
+ uint64_t end;
+ uint32_t type;
+ uint32_t pid; /* tgid */
};
/**
@@ -364,143 +359,143 @@ enum fuse_notify_code {
#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
struct fuse_entry_out {
- __u64 nodeid; /* Inode ID */
- __u64 generation; /* Inode generation: nodeid:gen must
- be unique for the fs's lifetime */
- __u64 entry_valid; /* Cache timeout for the name */
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 entry_valid_nsec;
- __u32 attr_valid_nsec;
+ uint64_t nodeid; /* Inode ID */
+ uint64_t generation; /* Inode generation: nodeid:gen must
+ be unique for the fs's lifetime */
+ uint64_t entry_valid; /* Cache timeout for the name */
+ uint64_t attr_valid; /* Cache timeout for the attributes */
+ uint32_t entry_valid_nsec;
+ uint32_t attr_valid_nsec;
struct fuse_attr attr;
};
struct fuse_forget_in {
- __u64 nlookup;
+ uint64_t nlookup;
};
struct fuse_forget_one {
- __u64 nodeid;
- __u64 nlookup;
+ uint64_t nodeid;
+ uint64_t nlookup;
};
struct fuse_batch_forget_in {
- __u32 count;
- __u32 dummy;
+ uint32_t count;
+ uint32_t dummy;
};
struct fuse_getattr_in {
- __u32 getattr_flags;
- __u32 dummy;
- __u64 fh;
+ uint32_t getattr_flags;
+ uint32_t dummy;
+ uint64_t fh;
};
#define FUSE_COMPAT_ATTR_OUT_SIZE 96
struct fuse_attr_out {
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 attr_valid_nsec;
- __u32 dummy;
+ uint64_t attr_valid; /* Cache timeout for the attributes */
+ uint32_t attr_valid_nsec;
+ uint32_t dummy;
struct fuse_attr attr;
};
#define FUSE_COMPAT_MKNOD_IN_SIZE 8
struct fuse_mknod_in {
- __u32 mode;
- __u32 rdev;
- __u32 umask;
- __u32 padding;
+ uint32_t mode;
+ uint32_t rdev;
+ uint32_t umask;
+ uint32_t padding;
};
struct fuse_mkdir_in {
- __u32 mode;
- __u32 umask;
+ uint32_t mode;
+ uint32_t umask;
};
struct fuse_rename_in {
- __u64 newdir;
+ uint64_t newdir;
};
struct fuse_link_in {
- __u64 oldnodeid;
+ uint64_t oldnodeid;
};
struct fuse_setattr_in {
- __u32 valid;
- __u32 padding;
- __u64 fh;
- __u64 size;
- __u64 lock_owner;
- __u64 atime;
- __u64 mtime;
- __u64 unused2;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 unused3;
- __u32 mode;
- __u32 unused4;
- __u32 uid;
- __u32 gid;
- __u32 unused5;
+ uint32_t valid;
+ uint32_t padding;
+ uint64_t fh;
+ uint64_t size;
+ uint64_t lock_owner;
+ uint64_t atime;
+ uint64_t mtime;
+ uint64_t unused2;
+ uint32_t atimensec;
+ uint32_t mtimensec;
+ uint32_t unused3;
+ uint32_t mode;
+ uint32_t unused4;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t unused5;
};
struct fuse_open_in {
- __u32 flags;
- __u32 unused;
+ uint32_t flags;
+ uint32_t unused;
};
struct fuse_create_in {
- __u32 flags;
- __u32 mode;
- __u32 umask;
- __u32 padding;
+ uint32_t flags;
+ uint32_t mode;
+ uint32_t umask;
+ uint32_t padding;
};
struct fuse_open_out {
- __u64 fh;
- __u32 open_flags;
- __u32 padding;
+ uint64_t fh;
+ uint32_t open_flags;
+ uint32_t padding;
};
struct fuse_release_in {
- __u64 fh;
- __u32 flags;
- __u32 release_flags;
- __u64 lock_owner;
+ uint64_t fh;
+ uint32_t flags;
+ uint32_t release_flags;
+ uint64_t lock_owner;
};
struct fuse_flush_in {
- __u64 fh;
- __u32 unused;
- __u32 padding;
- __u64 lock_owner;
+ uint64_t fh;
+ uint32_t unused;
+ uint32_t padding;
+ uint64_t lock_owner;
};
struct fuse_read_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 read_flags;
- __u64 lock_owner;
- __u32 flags;
- __u32 padding;
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t read_flags;
+ uint64_t lock_owner;
+ uint32_t flags;
+ uint32_t padding;
};
#define FUSE_COMPAT_WRITE_IN_SIZE 24
struct fuse_write_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 write_flags;
- __u64 lock_owner;
- __u32 flags;
- __u32 padding;
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t write_flags;
+ uint64_t lock_owner;
+ uint32_t flags;
+ uint32_t padding;
};
struct fuse_write_out {
- __u32 size;
- __u32 padding;
+ uint32_t size;
+ uint32_t padding;
};
#define FUSE_COMPAT_STATFS_SIZE 48
@@ -510,32 +505,32 @@ struct fuse_statfs_out {
};
struct fuse_fsync_in {
- __u64 fh;
- __u32 fsync_flags;
- __u32 padding;
+ uint64_t fh;
+ uint32_t fsync_flags;
+ uint32_t padding;
};
struct fuse_setxattr_in {
- __u32 size;
- __u32 flags;
+ uint32_t size;
+ uint32_t flags;
};
struct fuse_getxattr_in {
- __u32 size;
- __u32 padding;
+ uint32_t size;
+ uint32_t padding;
};
struct fuse_getxattr_out {
- __u32 size;
- __u32 padding;
+ uint32_t size;
+ uint32_t padding;
};
struct fuse_lk_in {
- __u64 fh;
- __u64 owner;
+ uint64_t fh;
+ uint64_t owner;
struct fuse_file_lock lk;
- __u32 lk_flags;
- __u32 padding;
+ uint32_t lk_flags;
+ uint32_t padding;
};
struct fuse_lk_out {
@@ -543,134 +538,135 @@ struct fuse_lk_out {
};
struct fuse_access_in {
- __u32 mask;
- __u32 padding;
+ uint32_t mask;
+ uint32_t padding;
};
struct fuse_init_in {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
};
struct fuse_init_out {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
- __u16 max_background;
- __u16 congestion_threshold;
- __u32 max_write;
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
+ uint16_t max_background;
+ uint16_t congestion_threshold;
+ uint32_t max_write;
};
#define CUSE_INIT_INFO_MAX 4096
struct cuse_init_in {
- __u32 major;
- __u32 minor;
- __u32 unused;
- __u32 flags;
+ uint32_t major;
+ uint32_t minor;
+ uint32_t unused;
+ uint32_t flags;
};
struct cuse_init_out {
- __u32 major;
- __u32 minor;
- __u32 unused;
- __u32 flags;
- __u32 max_read;
- __u32 max_write;
- __u32 dev_major; /* chardev major */
- __u32 dev_minor; /* chardev minor */
- __u32 spare[10];
+ uint32_t major;
+ uint32_t minor;
+ uint32_t unused;
+ uint32_t flags;
+ uint32_t max_read;
+ uint32_t max_write;
+ uint32_t dev_major; /* chardev major */
+ uint32_t dev_minor; /* chardev minor */
+ uint32_t spare[10];
};
struct fuse_interrupt_in {
- __u64 unique;
+ uint64_t unique;
};
struct fuse_bmap_in {
- __u64 block;
- __u32 blocksize;
- __u32 padding;
+ uint64_t block;
+ uint32_t blocksize;
+ uint32_t padding;
};
struct fuse_bmap_out {
- __u64 block;
+ uint64_t block;
};
struct fuse_ioctl_in {
- __u64 fh;
- __u32 flags;
- __u32 cmd;
- __u64 arg;
- __u32 in_size;
- __u32 out_size;
+ uint64_t fh;
+ uint32_t flags;
+ uint32_t cmd;
+ uint64_t arg;
+ uint32_t in_size;
+ uint32_t out_size;
};
struct fuse_ioctl_iovec {
- __u64 base;
- __u64 len;
+ uint64_t base;
+ uint64_t len;
};
struct fuse_ioctl_out {
- __s32 result;
- __u32 flags;
- __u32 in_iovs;
- __u32 out_iovs;
+ int32_t result;
+ uint32_t flags;
+ uint32_t in_iovs;
+ uint32_t out_iovs;
};
struct fuse_poll_in {
- __u64 fh;
- __u64 kh;
- __u32 flags;
- __u32 events;
+ uint64_t fh;
+ uint64_t kh;
+ uint32_t flags;
+ uint32_t events;
};
struct fuse_poll_out {
- __u32 revents;
- __u32 padding;
+ uint32_t revents;
+ uint32_t padding;
};
struct fuse_notify_poll_wakeup_out {
- __u64 kh;
+ uint64_t kh;
};
struct fuse_fallocate_in {
- __u64 fh;
- __u64 offset;
- __u64 length;
- __u32 mode;
- __u32 padding;
+ uint64_t fh;
+ uint64_t offset;
+ uint64_t length;
+ uint32_t mode;
+ uint32_t padding;
};
struct fuse_in_header {
- __u32 len;
- __u32 opcode;
- __u64 unique;
- __u64 nodeid;
- __u32 uid;
- __u32 gid;
- __u32 pid;
- __u32 padding;
+ uint32_t len;
+ uint32_t opcode;
+ uint64_t unique;
+ uint64_t nodeid;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t pid;
+ uint32_t padding;
};
struct fuse_out_header {
- __u32 len;
- __s32 error;
- __u64 unique;
+ uint32_t len;
+ int32_t error;
+ uint64_t unique;
};
struct fuse_dirent {
- __u64 ino;
- __u64 off;
- __u32 namelen;
- __u32 type;
+ uint64_t ino;
+ uint64_t off;
+ uint32_t namelen;
+ uint32_t type;
char name[];
};
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
+#define FUSE_DIRENT_ALIGN(x) \
+ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
@@ -685,47 +681,47 @@ struct fuse_direntplus {
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
struct fuse_notify_inval_inode_out {
- __u64 ino;
- __s64 off;
- __s64 len;
+ uint64_t ino;
+ int64_t off;
+ int64_t len;
};
struct fuse_notify_inval_entry_out {
- __u64 parent;
- __u32 namelen;
- __u32 padding;
+ uint64_t parent;
+ uint32_t namelen;
+ uint32_t padding;
};
struct fuse_notify_delete_out {
- __u64 parent;
- __u64 child;
- __u32 namelen;
- __u32 padding;
+ uint64_t parent;
+ uint64_t child;
+ uint32_t namelen;
+ uint32_t padding;
};
struct fuse_notify_store_out {
- __u64 nodeid;
- __u64 offset;
- __u32 size;
- __u32 padding;
+ uint64_t nodeid;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t padding;
};
struct fuse_notify_retrieve_out {
- __u64 notify_unique;
- __u64 nodeid;
- __u64 offset;
- __u32 size;
- __u32 padding;
+ uint64_t notify_unique;
+ uint64_t nodeid;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t padding;
};
/* Matches the size of fuse_write_in */
struct fuse_notify_retrieve_in {
- __u64 dummy1;
- __u64 offset;
- __u32 size;
- __u32 dummy2;
- __u64 dummy3;
- __u64 dummy4;
+ uint64_t dummy1;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t dummy2;
+ uint64_t dummy3;
+ uint64_t dummy4;
};
#endif /* _LINUX_FUSE_H */
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 798032d01112..ade07f1c491a 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -94,6 +94,9 @@
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
+ * then the frame is Ethernet II. Else it is 802.3 */
+
/*
* Non DIX types. Won't clash for 1500 types.
*/
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index c4edfe11f1f7..b05823cae784 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -201,6 +201,7 @@ enum {
IFLA_INET6_MCAST, /* MC things. What of them? */
IFLA_INET6_CACHEINFO, /* time values and max reasm size */
IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
+ IFLA_INET6_TOKEN, /* device token */
__IFLA_INET6_MAX
};
@@ -249,6 +250,7 @@ enum {
IFLA_VLAN_FLAGS,
IFLA_VLAN_EGRESS_QOS,
IFLA_VLAN_INGRESS_QOS,
+ IFLA_VLAN_PROTOCOL,
__IFLA_VLAN_MAX,
};
@@ -295,7 +297,7 @@ enum macvlan_mode {
enum {
IFLA_VXLAN_UNSPEC,
IFLA_VXLAN_ID,
- IFLA_VXLAN_GROUP,
+ IFLA_VXLAN_GROUP, /* group or remote address */
IFLA_VXLAN_LINK,
IFLA_VXLAN_LOCAL,
IFLA_VXLAN_TTL,
@@ -303,11 +305,12 @@ enum {
IFLA_VXLAN_LEARNING,
IFLA_VXLAN_AGEING,
IFLA_VXLAN_LIMIT,
- IFLA_VXLAN_PORT_RANGE,
+ IFLA_VXLAN_PORT_RANGE, /* source port */
IFLA_VXLAN_PROXY,
IFLA_VXLAN_RSC,
IFLA_VXLAN_L2MISS,
IFLA_VXLAN_L3MISS,
+ IFLA_VXLAN_PORT, /* destination port */
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
index f9a60375f0d0..b950c02030c0 100644
--- a/include/uapi/linux/if_packet.h
+++ b/include/uapi/linux/if_packet.h
@@ -55,6 +55,8 @@ struct sockaddr_ll {
#define PACKET_FANOUT_HASH 0
#define PACKET_FANOUT_LB 1
#define PACKET_FANOUT_CPU 2
+#define PACKET_FANOUT_ROLLOVER 3
+#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000
#define PACKET_FANOUT_FLAG_DEFRAG 0x8000
struct tpacket_stats {
@@ -84,19 +86,24 @@ struct tpacket_auxdata {
};
/* Rx ring - header status */
-#define TP_STATUS_KERNEL 0x0
-#define TP_STATUS_USER 0x1
-#define TP_STATUS_COPY 0x2
-#define TP_STATUS_LOSING 0x4
-#define TP_STATUS_CSUMNOTREADY 0x8
-#define TP_STATUS_VLAN_VALID 0x10 /* auxdata has valid tp_vlan_tci */
-#define TP_STATUS_BLK_TMO 0x20
+#define TP_STATUS_KERNEL 0
+#define TP_STATUS_USER (1 << 0)
+#define TP_STATUS_COPY (1 << 1)
+#define TP_STATUS_LOSING (1 << 2)
+#define TP_STATUS_CSUMNOTREADY (1 << 3)
+#define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */
+#define TP_STATUS_BLK_TMO (1 << 5)
/* Tx ring - header status */
-#define TP_STATUS_AVAILABLE 0x0
-#define TP_STATUS_SEND_REQUEST 0x1
-#define TP_STATUS_SENDING 0x2
-#define TP_STATUS_WRONG_FORMAT 0x4
+#define TP_STATUS_AVAILABLE 0
+#define TP_STATUS_SEND_REQUEST (1 << 0)
+#define TP_STATUS_SENDING (1 << 1)
+#define TP_STATUS_WRONG_FORMAT (1 << 2)
+
+/* Rx and Tx ring - header status */
+#define TP_STATUS_TS_SOFTWARE (1 << 29)
+#define TP_STATUS_TS_SYS_HARDWARE (1 << 30)
+#define TP_STATUS_TS_RAW_HARDWARE (1 << 31)
/* Rx ring - feature request bits */
#define TP_FT_REQ_FILL_RXHASH 0x1
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 935119c698ac..4649ee35b605 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -702,6 +702,11 @@ struct input_keymap_entry {
#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_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
diff --git a/include/uapi/linux/ip_vs.h b/include/uapi/linux/ip_vs.h
index 8a2d438dc499..a24537725e80 100644
--- a/include/uapi/linux/ip_vs.h
+++ b/include/uapi/linux/ip_vs.h
@@ -280,8 +280,8 @@ struct ip_vs_daemon_user {
#define IPVS_GENL_VERSION 0x1
struct ip_vs_flags {
- __be32 flags;
- __be32 mask;
+ __u32 flags;
+ __u32 mask;
};
/* Generic Netlink command attributes */
diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h
index 873e086ce3a1..249df3720be2 100644
--- a/include/uapi/linux/magic.h
+++ b/include/uapi/linux/magic.h
@@ -11,6 +11,7 @@
#define DEBUGFS_MAGIC 0x64626720
#define SECURITYFS_MAGIC 0x73636673
#define SELINUX_MAGIC 0xf97cff8c
+#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
#define RAMFS_MAGIC 0x858458f6 /* some random number */
#define TMPFS_MAGIC 0x01021994
#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 0ef883327de2..ed49574ad757 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -56,6 +56,8 @@ struct media_device_info {
#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)
#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3)
+/* A converter of analogue video to its digital representation. */
+#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4)
#define MEDIA_ENT_FL_DEFAULT (1 << 0)
diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h
index adb068c53c4e..f175212420ab 100644
--- a/include/uapi/linux/neighbour.h
+++ b/include/uapi/linux/neighbour.h
@@ -21,6 +21,9 @@ enum {
NDA_CACHEINFO,
NDA_PROBES,
NDA_VLAN,
+ NDA_PORT,
+ NDA_VNI,
+ NDA_IFINDEX,
__NDA_MAX
};
diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h
index fbee42807a11..8024cdf13b70 100644
--- a/include/uapi/linux/netfilter/ipset/ip_set.h
+++ b/include/uapi/linux/netfilter/ipset/ip_set.h
@@ -108,6 +108,8 @@ enum {
IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO,
IPSET_ATTR_IFACE,
+ IPSET_ATTR_BYTES,
+ IPSET_ATTR_PACKETS,
__IPSET_ATTR_ADT_MAX,
};
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -137,12 +139,13 @@ enum ipset_errno {
IPSET_ERR_REFERENCED,
IPSET_ERR_IPADDR_IPV4,
IPSET_ERR_IPADDR_IPV6,
+ IPSET_ERR_COUNTER,
/* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 4352,
};
-/* Flags at command level */
+/* Flags at command level or match/target flags, lower half of cmdattrs*/
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
@@ -150,10 +153,20 @@ enum ipset_cmd_flags {
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
- IPSET_FLAG_CMD_MAX = 15, /* Lower half */
+ IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE = 3,
+ IPSET_FLAG_SKIP_COUNTER_UPDATE =
+ (1 << IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE),
+ IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE = 4,
+ IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE =
+ (1 << IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE),
+ IPSET_FLAG_BIT_MATCH_COUNTERS = 5,
+ IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS),
+ IPSET_FLAG_BIT_RETURN_NOMATCH = 7,
+ IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH),
+ IPSET_FLAG_CMD_MAX = 15,
};
-/* Flags at CADT attribute level */
+/* Flags at CADT attribute level, upper half of cmdattrs */
enum ipset_cadt_flags {
IPSET_FLAG_BIT_BEFORE = 0,
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
@@ -161,7 +174,9 @@ enum ipset_cadt_flags {
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
IPSET_FLAG_BIT_NOMATCH = 2,
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
- IPSET_FLAG_CADT_MAX = 15, /* Upper half */
+ IPSET_FLAG_BIT_WITH_COUNTERS = 3,
+ IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
+ IPSET_FLAG_CADT_MAX = 15,
};
/* Commands with settype-specific attributes */
@@ -190,6 +205,7 @@ enum ip_set_dim {
* If changed, new revision of iptables match/target is required.
*/
IPSET_DIM_MAX = 6,
+ /* Backward compatibility: set match revision 2 */
IPSET_BIT_RETURN_NOMATCH = 7,
};
@@ -202,6 +218,18 @@ enum ip_set_kopt {
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
};
+enum {
+ IPSET_COUNTER_NONE = 0,
+ IPSET_COUNTER_EQ,
+ IPSET_COUNTER_NE,
+ IPSET_COUNTER_LT,
+ IPSET_COUNTER_GT,
+};
+
+struct ip_set_counter_match {
+ __u8 op;
+ __u64 value;
+};
/* Interface to iptables/ip6tables */
diff --git a/include/uapi/linux/netfilter/nfnetlink_queue.h b/include/uapi/linux/netfilter/nfnetlink_queue.h
index 70ec8c2bc11a..a2308ae5a73d 100644
--- a/include/uapi/linux/netfilter/nfnetlink_queue.h
+++ b/include/uapi/linux/netfilter/nfnetlink_queue.h
@@ -45,6 +45,7 @@ enum nfqnl_attr_type {
NFQA_CT, /* nf_conntrack_netlink.h */
NFQA_CT_INFO, /* enum ip_conntrack_info */
NFQA_CAP_LEN, /* __u32 length of captured packet */
+ NFQA_SKB_INFO, /* __u32 skb meta information */
__NFQA_MAX
};
@@ -96,6 +97,13 @@ enum nfqnl_attr_config {
/* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1)
-#define NFQA_CFG_F_MAX (1 << 2)
+#define NFQA_CFG_F_GSO (1 << 2)
+#define NFQA_CFG_F_MAX (1 << 3)
+
+/* flags for NFQA_SKB_INFO */
+/* packet appears to have wrong checksums, but they are ok */
+#define NFQA_SKB_CSUMNOTREADY (1 << 0)
+/* packet is GSO (i.e., exceeds device mtu) */
+#define NFQA_SKB_GSO (1 << 1)
#endif /* _NFNETLINK_QUEUE_H */
diff --git a/include/uapi/linux/netfilter/xt_NFQUEUE.h b/include/uapi/linux/netfilter/xt_NFQUEUE.h
index 9eafdbbb401c..8bb5fe657d34 100644
--- a/include/uapi/linux/netfilter/xt_NFQUEUE.h
+++ b/include/uapi/linux/netfilter/xt_NFQUEUE.h
@@ -26,4 +26,13 @@ struct xt_NFQ_info_v2 {
__u16 bypass;
};
+struct xt_NFQ_info_v3 {
+ __u16 queuenum;
+ __u16 queues_total;
+ __u16 flags;
+#define NFQ_FLAG_BYPASS 0x01 /* for compatibility with v2 */
+#define NFQ_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */
+#define NFQ_FLAG_MASK 0x03
+};
+
#endif /* _XT_NFQ_TARGET_H */
diff --git a/include/uapi/linux/netfilter/xt_set.h b/include/uapi/linux/netfilter/xt_set.h
index e3a9978f259f..964d3d42f874 100644
--- a/include/uapi/linux/netfilter/xt_set.h
+++ b/include/uapi/linux/netfilter/xt_set.h
@@ -62,4 +62,13 @@ struct xt_set_info_target_v2 {
__u32 timeout;
};
+/* Revision 3 match */
+
+struct xt_set_info_match_v3 {
+ struct xt_set_info match_set;
+ struct ip_set_counter_match packets;
+ struct ip_set_counter_match bytes;
+ __u32 flags;
+};
+
#endif /*_XT_SET_H*/
diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_frag.h b/include/uapi/linux/netfilter_ipv6/ip6t_frag.h
index b47f61b9e082..dfd8bc2268cf 100644
--- a/include/uapi/linux/netfilter_ipv6/ip6t_frag.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_frag.h
@@ -4,9 +4,9 @@
#include <linux/types.h>
struct ip6t_frag {
- __u32 ids[2]; /* Security Parameter Index */
+ __u32 ids[2]; /* Identification range */
__u32 hdrlen; /* Header Length */
- __u8 flags; /* */
+ __u8 flags; /* Flags */
__u8 invflags; /* Inverse flags */
};
diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h
index 78d5b8a546d6..1a85940f8ab7 100644
--- a/include/uapi/linux/netlink.h
+++ b/include/uapi/linux/netlink.h
@@ -1,6 +1,7 @@
#ifndef _UAPI__LINUX_NETLINK_H
#define _UAPI__LINUX_NETLINK_H
+#include <linux/kernel.h>
#include <linux/socket.h> /* for __kernel_sa_family_t */
#include <linux/types.h>
@@ -78,7 +79,7 @@ struct nlmsghdr {
#define NLMSG_ALIGNTO 4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
@@ -105,11 +106,42 @@ struct nlmsgerr {
#define NETLINK_PKTINFO 3
#define NETLINK_BROADCAST_ERROR 4
#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
struct nl_pktinfo {
__u32 group;
};
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
enum {
diff --git a/include/uapi/linux/netlink_diag.h b/include/uapi/linux/netlink_diag.h
new file mode 100644
index 000000000000..4e31db4eea41
--- /dev/null
+++ b/include/uapi/linux/netlink_diag.h
@@ -0,0 +1,52 @@
+#ifndef __NETLINK_DIAG_H__
+#define __NETLINK_DIAG_H__
+
+#include <linux/types.h>
+
+struct netlink_diag_req {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+ __u16 pad;
+ __u32 ndiag_ino;
+ __u32 ndiag_show;
+ __u32 ndiag_cookie[2];
+};
+
+struct netlink_diag_msg {
+ __u8 ndiag_family;
+ __u8 ndiag_type;
+ __u8 ndiag_protocol;
+ __u8 ndiag_state;
+
+ __u32 ndiag_portid;
+ __u32 ndiag_dst_portid;
+ __u32 ndiag_dst_group;
+ __u32 ndiag_ino;
+ __u32 ndiag_cookie[2];
+};
+
+struct netlink_diag_ring {
+ __u32 ndr_block_size;
+ __u32 ndr_block_nr;
+ __u32 ndr_frame_size;
+ __u32 ndr_frame_nr;
+};
+
+enum {
+ NETLINK_DIAG_MEMINFO,
+ NETLINK_DIAG_GROUPS,
+ NETLINK_DIAG_RX_RING,
+ NETLINK_DIAG_TX_RING,
+
+ __NETLINK_DIAG_MAX,
+};
+
+#define NETLINK_DIAG_MAX (__NETLINK_DIAG_MAX - 1)
+
+#define NDIAG_PROTO_ALL ((__u8) ~0)
+
+#define NDIAG_SHOW_MEMINFO 0x00000001 /* show memory info of a socket */
+#define NDIAG_SHOW_GROUPS 0x00000002 /* show groups of a netlink socket */
+#define NDIAG_SHOW_RING_CFG 0x00000004 /* show ring configuration */
+
+#endif
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h
index 7969f46f1bb3..7c6f627a717d 100644
--- a/include/uapi/linux/nfc.h
+++ b/include/uapi/linux/nfc.h
@@ -90,6 +90,8 @@ enum nfc_commands {
NFC_CMD_LLC_SET_PARAMS,
NFC_CMD_ENABLE_SE,
NFC_CMD_DISABLE_SE,
+ NFC_CMD_LLC_SDREQ,
+ NFC_EVENT_LLC_SDRES,
/* private: internal use only */
__NFC_CMD_AFTER_LAST
};
@@ -140,11 +142,21 @@ enum nfc_attrs {
NFC_ATTR_LLC_PARAM_RW,
NFC_ATTR_LLC_PARAM_MIUX,
NFC_ATTR_SE,
+ NFC_ATTR_LLC_SDP,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};
#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
+enum nfc_sdp_attr {
+ NFC_SDP_ATTR_UNSPEC,
+ NFC_SDP_ATTR_URI,
+ NFC_SDP_ATTR_SAP,
+/* private: internal use only */
+ __NFC_SDP_ATTR_AFTER_LAST
+};
+#define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1)
+
#define NFC_DEVICE_NAME_MAXSIZE 8
#define NFC_NFCID1_MAXSIZE 10
#define NFC_SENSB_RES_MAXSIZE 12
@@ -220,4 +232,11 @@ struct sockaddr_nfc_llcp {
#define NFC_LLCP_DIRECTION_RX 0x00
#define NFC_LLCP_DIRECTION_TX 0x01
+/* socket option names */
+#define NFC_LLCP_RW 0
+#define NFC_LLCP_MIUX 1
+#define NFC_LLCP_REMOTE_MIU 2
+#define NFC_LLCP_REMOTE_LTO 3
+#define NFC_LLCP_REMOTE_RW 4
+
#endif /*__LINUX_NFC_H */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index c46bb016f4e4..d1e48b5e348f 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -36,7 +36,21 @@
* The station is still assumed to belong to the AP interface it was added
* to.
*
- * TODO: need more info?
+ * Station handling varies per interface type and depending on the driver's
+ * capabilities.
+ *
+ * For drivers supporting TDLS with external setup (WIPHY_FLAG_SUPPORTS_TDLS
+ * and WIPHY_FLAG_TDLS_EXTERNAL_SETUP), the station lifetime is as follows:
+ * - a setup station entry is added, not yet authorized, without any rate
+ * or capability information, this just exists to avoid race conditions
+ * - when the TDLS setup is done, a single NL80211_CMD_SET_STATION is valid
+ * to add rate and capability information to the station and at the same
+ * time mark it authorized.
+ * - %NL80211_TDLS_ENABLE_LINK is then used
+ * - after this, the only valid operation is to remove it by tearing down
+ * the TDLS link (%NL80211_TDLS_DISABLE_LINK)
+ *
+ * TODO: need more info for other interface types
*/
/**
@@ -499,9 +513,11 @@
* @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
* beacon or probe response from a compatible mesh peer. This is only
* sent while no station information (sta_info) exists for the new peer
- * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set. On
- * reception of this notification, userspace may decide to create a new
- * station (@NL80211_CMD_NEW_STATION). To stop this notification from
+ * candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH,
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE, or
+ * @NL80211_MESH_SETUP_USERSPACE_MPM is set. On reception of this
+ * notification, userspace may decide to create a new station
+ * (@NL80211_CMD_NEW_STATION). To stop this notification from
* reoccurring, the userspace authentication daemon may want to create the
* new station with the AUTHENTICATED flag unset and maybe change it later
* depending on the authentication result.
@@ -611,6 +627,25 @@
* %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
* event.
*
+ * @NL80211_CMD_GET_PROTOCOL_FEATURES: Get global nl80211 protocol features,
+ * i.e. features for the nl80211 protocol rather than device features.
+ * Returns the features in the %NL80211_ATTR_PROTOCOL_FEATURES bitmap.
+ *
+ * @NL80211_CMD_UPDATE_FT_IES: Pass down the most up-to-date Fast Transition
+ * Information Element to the WLAN driver
+ *
+ * @NL80211_CMD_FT_EVENT: Send a Fast transition event from the WLAN driver
+ * to the supplicant. This will carry the target AP's MAC address along
+ * with the relevant Information Elements. This event is used to report
+ * received FT IEs (MDIE, FTIE, RSN IE, TIE, RICIE).
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_START: Indicates user-space will start running
+ * a critical protocol that needs more reliability in the connection to
+ * complete.
+ *
+ * @NL80211_CMD_CRIT_PROTOCOL_STOP: Indicates the connection reliability can
+ * return back to normal.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -765,6 +800,14 @@ enum nl80211_commands {
NL80211_CMD_RADAR_DETECT,
+ NL80211_CMD_GET_PROTOCOL_FEATURES,
+
+ NL80211_CMD_UPDATE_FT_IES,
+ NL80211_CMD_FT_EVENT,
+
+ NL80211_CMD_CRIT_PROTOCOL_START,
+ NL80211_CMD_CRIT_PROTOCOL_STOP,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -884,7 +927,8 @@ enum nl80211_commands {
* consisting of a nested array.
*
* @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link
+ * (see &enum nl80211_plink_action).
* @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
* @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
* info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -1167,10 +1211,10 @@ enum nl80211_commands {
* @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
* allows auth frames in a mesh to be passed to userspace for processing via
* the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
- * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
- * defined in &enum nl80211_plink_state. Used when userspace is
- * driving the peer link management state machine.
- * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as defined in
+ * &enum nl80211_plink_state. Used when userspace is driving the peer link
+ * management state machine. @NL80211_MESH_SETUP_USERSPACE_AMPE or
+ * @NL80211_MESH_SETUP_USERSPACE_MPM must be enabled.
*
* @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
* capabilities, the supported WoWLAN triggers
@@ -1368,6 +1412,23 @@ enum nl80211_commands {
* advertised to the driver, e.g., to enable TDLS off channel operations
* and PU-APSD.
*
+ * @NL80211_ATTR_PROTOCOL_FEATURES: global nl80211 feature flags, see
+ * &enum nl80211_protocol_features, the attribute is a u32.
+ *
+ * @NL80211_ATTR_SPLIT_WIPHY_DUMP: flag attribute, userspace supports
+ * receiving the data for a single wiphy split across multiple
+ * messages, given with wiphy dump message
+ *
+ * @NL80211_ATTR_MDID: Mobility Domain Identifier
+ *
+ * @NL80211_ATTR_IE_RIC: Resource Information Container Information
+ * Element
+ *
+ * @NL80211_ATTR_CRIT_PROT_ID: critical protocol identifier requiring increased
+ * reliability, see &enum nl80211_crit_proto_id (u16).
+ * @NL80211_ATTR_MAX_CRIT_PROT_DURATION: duration in milliseconds in which
+ * the connection should have increased reliability (u16).
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1654,6 +1715,18 @@ enum nl80211_attrs {
NL80211_ATTR_STA_CAPABILITY,
NL80211_ATTR_STA_EXT_CAPABILITY,
+ NL80211_ATTR_PROTOCOL_FEATURES,
+ NL80211_ATTR_SPLIT_WIPHY_DUMP,
+
+ NL80211_ATTR_DISABLE_VHT,
+ NL80211_ATTR_VHT_CAPABILITY_MASK,
+
+ NL80211_ATTR_MDID,
+ NL80211_ATTR_IE_RIC,
+
+ NL80211_ATTR_CRIT_PROT_ID,
+ NL80211_ATTR_MAX_CRIT_PROT_DURATION,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2412,8 +2485,10 @@ enum nl80211_mesh_power_mode {
* @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
* point.
*
- * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
- * open peer links when we detect compatible mesh peers.
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically open
+ * peer links when we detect compatible mesh peers. Disabled if
+ * @NL80211_MESH_SETUP_USERSPACE_MPM or @NL80211_MESH_SETUP_USERSPACE_AMPE are
+ * set.
*
* @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
* containing a PREQ that an MP can send to a particular destination (path
@@ -2559,6 +2634,9 @@ enum nl80211_meshconf_params {
* vendor specific synchronization method or disable it to use the default
* neighbor offset synchronization
*
+ * @NL80211_MESH_SETUP_USERSPACE_MPM: Enable this option if userspace will
+ * implement an MPM which handles peer allocation and state.
+ *
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
*
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
@@ -2571,6 +2649,7 @@ enum nl80211_mesh_setup_params {
NL80211_MESH_SETUP_USERSPACE_AUTH,
NL80211_MESH_SETUP_USERSPACE_AMPE,
NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC,
+ NL80211_MESH_SETUP_USERSPACE_MPM,
/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -3307,6 +3386,23 @@ enum nl80211_plink_state {
MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
};
+/**
+ * enum nl80211_plink_action - actions to perform in mesh peers
+ *
+ * @NL80211_PLINK_ACTION_NO_ACTION: perform no action
+ * @NL80211_PLINK_ACTION_OPEN: start mesh peer link establishment
+ * @NL80211_PLINK_ACTION_BLOCK: block traffic from this mesh peer
+ * @NUM_NL80211_PLINK_ACTIONS: number of possible actions
+ */
+enum plink_actions {
+ NL80211_PLINK_ACTION_NO_ACTION,
+ NL80211_PLINK_ACTION_OPEN,
+ NL80211_PLINK_ACTION_BLOCK,
+
+ NUM_NL80211_PLINK_ACTIONS,
+};
+
+
#define NL80211_KCK_LEN 16
#define NL80211_KEK_LEN 16
#define NL80211_REPLAY_CTR_LEN 8
@@ -3456,6 +3552,10 @@ enum nl80211_ap_sme_features {
* stations the authenticated/associated bits have to be set in the mask.
* @NL80211_FEATURE_ADVERTISE_CHAN_LIMITS: cfg80211 advertises channel limits
* (HT40, VHT 80/160 MHz) if this flag is set
+ * @NL80211_FEATURE_USERSPACE_MPM: This driver supports a userspace Mesh
+ * Peering Management entity which may be implemented by registering for
+ * beacons or NL80211_CMD_NEW_PEER_CANDIDATE events. The mesh beacon is
+ * still generated by the driver.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3474,6 +3574,7 @@ enum nl80211_feature_flags {
/* bit 13 is reserved */
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
+ NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
};
/**
@@ -3587,4 +3688,37 @@ enum nl80211_dfs_state {
NL80211_DFS_AVAILABLE,
};
+/**
+ * enum enum nl80211_protocol_features - nl80211 protocol features
+ * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting
+ * wiphy dumps (if requested by the application with the attribute
+ * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the
+ * wiphy dump by %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFINDEX or
+ * %NL80211_ATTR_WDEV.
+ */
+enum nl80211_protocol_features {
+ NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP = 1 << 0,
+};
+
+/**
+ * enum nl80211_crit_proto_id - nl80211 critical protocol identifiers
+ *
+ * @NL80211_CRIT_PROTO_UNSPEC: protocol unspecified.
+ * @NL80211_CRIT_PROTO_DHCP: BOOTP or DHCPv6 protocol.
+ * @NL80211_CRIT_PROTO_EAPOL: EAPOL protocol.
+ * @NL80211_CRIT_PROTO_APIPA: APIPA protocol.
+ * @NUM_NL80211_CRIT_PROTO: must be kept last.
+ */
+enum nl80211_crit_proto_id {
+ NL80211_CRIT_PROTO_UNSPEC,
+ NL80211_CRIT_PROTO_DHCP,
+ NL80211_CRIT_PROTO_EAPOL,
+ NL80211_CRIT_PROTO_APIPA,
+ /* add other protocols before this one */
+ NUM_NL80211_CRIT_PROTO
+};
+
+/* maximum duration for critical protocol measures */
+#define NL80211_CRIT_PROTO_MAX_DURATION 5000 /* msec */
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
new file mode 100644
index 000000000000..405918dd7b3f
--- /dev/null
+++ b/include/uapi/linux/openvswitch.h
@@ -0,0 +1,456 @@
+
+/*
+ * Copyright (c) 2007-2011 Nicira Networks.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef _UAPI__LINUX_OPENVSWITCH_H
+#define _UAPI__LINUX_OPENVSWITCH_H 1
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+/**
+ * struct ovs_header - header for OVS Generic Netlink messages.
+ * @dp_ifindex: ifindex of local port for datapath (0 to make a request not
+ * specific to a datapath).
+ *
+ * Attributes following the header are specific to a particular OVS Generic
+ * Netlink family, but all of the OVS families use this header.
+ */
+
+struct ovs_header {
+ int dp_ifindex;
+};
+
+/* Datapaths. */
+
+#define OVS_DATAPATH_FAMILY "ovs_datapath"
+#define OVS_DATAPATH_MCGROUP "ovs_datapath"
+#define OVS_DATAPATH_VERSION 0x1
+
+enum ovs_datapath_cmd {
+ OVS_DP_CMD_UNSPEC,
+ OVS_DP_CMD_NEW,
+ OVS_DP_CMD_DEL,
+ OVS_DP_CMD_GET,
+ OVS_DP_CMD_SET
+};
+
+/**
+ * enum ovs_datapath_attr - attributes for %OVS_DP_* commands.
+ * @OVS_DP_ATTR_NAME: Name of the network device that serves as the "local
+ * port". This is the name of the network device whose dp_ifindex is given in
+ * the &struct ovs_header. Always present in notifications. Required in
+ * %OVS_DP_NEW requests. May be used as an alternative to specifying
+ * dp_ifindex in other requests (with a dp_ifindex of 0).
+ * @OVS_DP_ATTR_UPCALL_PID: The Netlink socket in userspace that is initially
+ * set on the datapath port (for OVS_ACTION_ATTR_MISS). Only valid on
+ * %OVS_DP_CMD_NEW requests. A value of zero indicates that upcalls should
+ * not be sent.
+ * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the
+ * datapath. Always present in notifications.
+ *
+ * These attributes follow the &struct ovs_header within the Generic Netlink
+ * payload for %OVS_DP_* commands.
+ */
+enum ovs_datapath_attr {
+ OVS_DP_ATTR_UNSPEC,
+ OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */
+ OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */
+ OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */
+ __OVS_DP_ATTR_MAX
+};
+
+#define OVS_DP_ATTR_MAX (__OVS_DP_ATTR_MAX - 1)
+
+struct ovs_dp_stats {
+ __u64 n_hit; /* Number of flow table matches. */
+ __u64 n_missed; /* Number of flow table misses. */
+ __u64 n_lost; /* Number of misses not sent to userspace. */
+ __u64 n_flows; /* Number of flows present */
+};
+
+struct ovs_vport_stats {
+ __u64 rx_packets; /* total packets received */
+ __u64 tx_packets; /* total packets transmitted */
+ __u64 rx_bytes; /* total bytes received */
+ __u64 tx_bytes; /* total bytes transmitted */
+ __u64 rx_errors; /* bad packets received */
+ __u64 tx_errors; /* packet transmit problems */
+ __u64 rx_dropped; /* no space in linux buffers */
+ __u64 tx_dropped; /* no space available in linux */
+};
+
+/* Fixed logical ports. */
+#define OVSP_LOCAL ((__u32)0)
+
+/* Packet transfer. */
+
+#define OVS_PACKET_FAMILY "ovs_packet"
+#define OVS_PACKET_VERSION 0x1
+
+enum ovs_packet_cmd {
+ OVS_PACKET_CMD_UNSPEC,
+
+ /* Kernel-to-user notifications. */
+ OVS_PACKET_CMD_MISS, /* Flow table miss. */
+ OVS_PACKET_CMD_ACTION, /* OVS_ACTION_ATTR_USERSPACE action. */
+
+ /* Userspace commands. */
+ OVS_PACKET_CMD_EXECUTE /* Apply actions to a packet. */
+};
+
+/**
+ * enum ovs_packet_attr - attributes for %OVS_PACKET_* commands.
+ * @OVS_PACKET_ATTR_PACKET: Present for all notifications. Contains the entire
+ * packet as received, from the start of the Ethernet header onward. For
+ * %OVS_PACKET_CMD_ACTION, %OVS_PACKET_ATTR_PACKET reflects changes made by
+ * actions preceding %OVS_ACTION_ATTR_USERSPACE, but %OVS_PACKET_ATTR_KEY is
+ * the flow key extracted from the packet as originally received.
+ * @OVS_PACKET_ATTR_KEY: Present for all notifications. Contains the flow key
+ * extracted from the packet as nested %OVS_KEY_ATTR_* attributes. This allows
+ * userspace to adapt its flow setup strategy by comparing its notion of the
+ * flow key against the kernel's.
+ * @OVS_PACKET_ATTR_ACTIONS: Contains actions for the packet. Used
+ * for %OVS_PACKET_CMD_EXECUTE. It has nested %OVS_ACTION_ATTR_* attributes.
+ * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
+ * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
+ * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
+ * specified there.
+ *
+ * These attributes follow the &struct ovs_header within the Generic Netlink
+ * payload for %OVS_PACKET_* commands.
+ */
+enum ovs_packet_attr {
+ OVS_PACKET_ATTR_UNSPEC,
+ OVS_PACKET_ATTR_PACKET, /* Packet data. */
+ OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */
+ OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
+ OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */
+ __OVS_PACKET_ATTR_MAX
+};
+
+#define OVS_PACKET_ATTR_MAX (__OVS_PACKET_ATTR_MAX - 1)
+
+/* Virtual ports. */
+
+#define OVS_VPORT_FAMILY "ovs_vport"
+#define OVS_VPORT_MCGROUP "ovs_vport"
+#define OVS_VPORT_VERSION 0x1
+
+enum ovs_vport_cmd {
+ OVS_VPORT_CMD_UNSPEC,
+ OVS_VPORT_CMD_NEW,
+ OVS_VPORT_CMD_DEL,
+ OVS_VPORT_CMD_GET,
+ OVS_VPORT_CMD_SET
+};
+
+enum ovs_vport_type {
+ OVS_VPORT_TYPE_UNSPEC,
+ OVS_VPORT_TYPE_NETDEV, /* network device */
+ OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
+ __OVS_VPORT_TYPE_MAX
+};
+
+#define OVS_VPORT_TYPE_MAX (__OVS_VPORT_TYPE_MAX - 1)
+
+/**
+ * enum ovs_vport_attr - attributes for %OVS_VPORT_* commands.
+ * @OVS_VPORT_ATTR_PORT_NO: 32-bit port number within datapath.
+ * @OVS_VPORT_ATTR_TYPE: 32-bit %OVS_VPORT_TYPE_* constant describing the type
+ * of vport.
+ * @OVS_VPORT_ATTR_NAME: Name of vport. For a vport based on a network device
+ * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes
+ * plus a null terminator.
+ * @OVS_VPORT_ATTR_OPTIONS: Vport-specific configuration information.
+ * @OVS_VPORT_ATTR_UPCALL_PID: The Netlink socket in userspace that
+ * OVS_PACKET_CMD_MISS upcalls will be directed to for packets received on
+ * this port. A value of zero indicates that upcalls should not be sent.
+ * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for
+ * packets sent or received through the vport.
+ *
+ * These attributes follow the &struct ovs_header within the Generic Netlink
+ * payload for %OVS_VPORT_* commands.
+ *
+ * For %OVS_VPORT_CMD_NEW requests, the %OVS_VPORT_ATTR_TYPE and
+ * %OVS_VPORT_ATTR_NAME attributes are required. %OVS_VPORT_ATTR_PORT_NO is
+ * optional; if not specified a free port number is automatically selected.
+ * Whether %OVS_VPORT_ATTR_OPTIONS is required or optional depends on the type
+ * of vport.
+ * and other attributes are ignored.
+ *
+ * For other requests, if %OVS_VPORT_ATTR_NAME is specified then it is used to
+ * look up the vport to operate on; otherwise dp_idx from the &struct
+ * ovs_header plus %OVS_VPORT_ATTR_PORT_NO determine the vport.
+ */
+enum ovs_vport_attr {
+ OVS_VPORT_ATTR_UNSPEC,
+ OVS_VPORT_ATTR_PORT_NO, /* u32 port number within datapath */
+ OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */
+ OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */
+ OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */
+ OVS_VPORT_ATTR_UPCALL_PID, /* u32 Netlink PID to receive upcalls */
+ OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */
+ __OVS_VPORT_ATTR_MAX
+};
+
+#define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
+
+/* Flows. */
+
+#define OVS_FLOW_FAMILY "ovs_flow"
+#define OVS_FLOW_MCGROUP "ovs_flow"
+#define OVS_FLOW_VERSION 0x1
+
+enum ovs_flow_cmd {
+ OVS_FLOW_CMD_UNSPEC,
+ OVS_FLOW_CMD_NEW,
+ OVS_FLOW_CMD_DEL,
+ OVS_FLOW_CMD_GET,
+ OVS_FLOW_CMD_SET
+};
+
+struct ovs_flow_stats {
+ __u64 n_packets; /* Number of matched packets. */
+ __u64 n_bytes; /* Number of matched bytes. */
+};
+
+enum ovs_key_attr {
+ OVS_KEY_ATTR_UNSPEC,
+ OVS_KEY_ATTR_ENCAP, /* Nested set of encapsulated attributes. */
+ OVS_KEY_ATTR_PRIORITY, /* u32 skb->priority */
+ OVS_KEY_ATTR_IN_PORT, /* u32 OVS dp port number */
+ OVS_KEY_ATTR_ETHERNET, /* struct ovs_key_ethernet */
+ OVS_KEY_ATTR_VLAN, /* be16 VLAN TCI */
+ OVS_KEY_ATTR_ETHERTYPE, /* be16 Ethernet type */
+ OVS_KEY_ATTR_IPV4, /* struct ovs_key_ipv4 */
+ OVS_KEY_ATTR_IPV6, /* struct ovs_key_ipv6 */
+ OVS_KEY_ATTR_TCP, /* struct ovs_key_tcp */
+ OVS_KEY_ATTR_UDP, /* struct ovs_key_udp */
+ OVS_KEY_ATTR_ICMP, /* struct ovs_key_icmp */
+ OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */
+ OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */
+ OVS_KEY_ATTR_ND, /* struct ovs_key_nd */
+ OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */
+ __OVS_KEY_ATTR_MAX
+};
+
+#define OVS_KEY_ATTR_MAX (__OVS_KEY_ATTR_MAX - 1)
+
+/**
+ * enum ovs_frag_type - IPv4 and IPv6 fragment type
+ * @OVS_FRAG_TYPE_NONE: Packet is not a fragment.
+ * @OVS_FRAG_TYPE_FIRST: Packet is a fragment with offset 0.
+ * @OVS_FRAG_TYPE_LATER: Packet is a fragment with nonzero offset.
+ *
+ * Used as the @ipv4_frag in &struct ovs_key_ipv4 and as @ipv6_frag &struct
+ * ovs_key_ipv6.
+ */
+enum ovs_frag_type {
+ OVS_FRAG_TYPE_NONE,
+ OVS_FRAG_TYPE_FIRST,
+ OVS_FRAG_TYPE_LATER,
+ __OVS_FRAG_TYPE_MAX
+};
+
+#define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
+
+struct ovs_key_ethernet {
+ __u8 eth_src[ETH_ALEN];
+ __u8 eth_dst[ETH_ALEN];
+};
+
+struct ovs_key_ipv4 {
+ __be32 ipv4_src;
+ __be32 ipv4_dst;
+ __u8 ipv4_proto;
+ __u8 ipv4_tos;
+ __u8 ipv4_ttl;
+ __u8 ipv4_frag; /* One of OVS_FRAG_TYPE_*. */
+};
+
+struct ovs_key_ipv6 {
+ __be32 ipv6_src[4];
+ __be32 ipv6_dst[4];
+ __be32 ipv6_label; /* 20-bits in least-significant bits. */
+ __u8 ipv6_proto;
+ __u8 ipv6_tclass;
+ __u8 ipv6_hlimit;
+ __u8 ipv6_frag; /* One of OVS_FRAG_TYPE_*. */
+};
+
+struct ovs_key_tcp {
+ __be16 tcp_src;
+ __be16 tcp_dst;
+};
+
+struct ovs_key_udp {
+ __be16 udp_src;
+ __be16 udp_dst;
+};
+
+struct ovs_key_icmp {
+ __u8 icmp_type;
+ __u8 icmp_code;
+};
+
+struct ovs_key_icmpv6 {
+ __u8 icmpv6_type;
+ __u8 icmpv6_code;
+};
+
+struct ovs_key_arp {
+ __be32 arp_sip;
+ __be32 arp_tip;
+ __be16 arp_op;
+ __u8 arp_sha[ETH_ALEN];
+ __u8 arp_tha[ETH_ALEN];
+};
+
+struct ovs_key_nd {
+ __u32 nd_target[4];
+ __u8 nd_sll[ETH_ALEN];
+ __u8 nd_tll[ETH_ALEN];
+};
+
+/**
+ * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
+ * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
+ * key. Always present in notifications. Required for all requests (except
+ * dumps).
+ * @OVS_FLOW_ATTR_ACTIONS: Nested %OVS_ACTION_ATTR_* attributes specifying
+ * the actions to take for packets that match the key. Always present in
+ * notifications. Required for %OVS_FLOW_CMD_NEW requests, optional for
+ * %OVS_FLOW_CMD_SET requests.
+ * @OVS_FLOW_ATTR_STATS: &struct ovs_flow_stats giving statistics for this
+ * flow. Present in notifications if the stats would be nonzero. Ignored in
+ * requests.
+ * @OVS_FLOW_ATTR_TCP_FLAGS: An 8-bit value giving the OR'd value of all of the
+ * TCP flags seen on packets in this flow. Only present in notifications for
+ * TCP flows, and only if it would be nonzero. Ignored in requests.
+ * @OVS_FLOW_ATTR_USED: A 64-bit integer giving the time, in milliseconds on
+ * the system monotonic clock, at which a packet was last processed for this
+ * flow. Only present in notifications if a packet has been processed for this
+ * flow. Ignored in requests.
+ * @OVS_FLOW_ATTR_CLEAR: If present in a %OVS_FLOW_CMD_SET request, clears the
+ * last-used time, accumulated TCP flags, and statistics for this flow.
+ * Otherwise ignored in requests. Never present in notifications.
+ *
+ * These attributes follow the &struct ovs_header within the Generic Netlink
+ * payload for %OVS_FLOW_* commands.
+ */
+enum ovs_flow_attr {
+ OVS_FLOW_ATTR_UNSPEC,
+ OVS_FLOW_ATTR_KEY, /* Sequence of OVS_KEY_ATTR_* attributes. */
+ OVS_FLOW_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
+ OVS_FLOW_ATTR_STATS, /* struct ovs_flow_stats. */
+ OVS_FLOW_ATTR_TCP_FLAGS, /* 8-bit OR'd TCP flags. */
+ OVS_FLOW_ATTR_USED, /* u64 msecs last used in monotonic time. */
+ OVS_FLOW_ATTR_CLEAR, /* Flag to clear stats, tcp_flags, used. */
+ __OVS_FLOW_ATTR_MAX
+};
+
+#define OVS_FLOW_ATTR_MAX (__OVS_FLOW_ATTR_MAX - 1)
+
+/**
+ * enum ovs_sample_attr - Attributes for %OVS_ACTION_ATTR_SAMPLE action.
+ * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
+ * @OVS_ACTION_ATTR_SAMPLE. A value of 0 samples no packets, a value of
+ * %UINT32_MAX samples all packets and intermediate values sample intermediate
+ * fractions of packets.
+ * @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event.
+ * Actions are passed as nested attributes.
+ *
+ * Executes the specified actions with the given probability on a per-packet
+ * basis.
+ */
+enum ovs_sample_attr {
+ OVS_SAMPLE_ATTR_UNSPEC,
+ OVS_SAMPLE_ATTR_PROBABILITY, /* u32 number */
+ OVS_SAMPLE_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */
+ __OVS_SAMPLE_ATTR_MAX,
+};
+
+#define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
+
+/**
+ * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
+ * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
+ * message should be sent. Required.
+ * @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
+ * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
+ */
+enum ovs_userspace_attr {
+ OVS_USERSPACE_ATTR_UNSPEC,
+ OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */
+ OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */
+ __OVS_USERSPACE_ATTR_MAX
+};
+
+#define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
+
+/**
+ * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
+ * @vlan_tpid: Tag protocol identifier (TPID) to push.
+ * @vlan_tci: Tag control identifier (TCI) to push. The CFI bit must be set
+ * (but it will not be set in the 802.1Q header that is pushed).
+ *
+ * The @vlan_tpid value is typically %ETH_P_8021Q. The only acceptable TPID
+ * values are those that the kernel module also parses as 802.1Q headers, to
+ * prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by %OVS_ACTION_ATTR_POP_VLAN
+ * from having surprising results.
+ */
+struct ovs_action_push_vlan {
+ __be16 vlan_tpid; /* 802.1Q TPID. */
+ __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
+};
+
+/**
+ * enum ovs_action_attr - Action types.
+ *
+ * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
+ * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
+ * %OVS_USERSPACE_ATTR_* attributes.
+ * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header. The
+ * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
+ * value.
+ * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
+ * packet.
+ * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
+ * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
+ * the nested %OVS_SAMPLE_ATTR_* attributes.
+ *
+ * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
+ * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
+ * type may not be changed.
+ */
+
+enum ovs_action_attr {
+ OVS_ACTION_ATTR_UNSPEC,
+ OVS_ACTION_ATTR_OUTPUT, /* u32 port number. */
+ OVS_ACTION_ATTR_USERSPACE, /* Nested OVS_USERSPACE_ATTR_*. */
+ OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */
+ OVS_ACTION_ATTR_PUSH_VLAN, /* struct ovs_action_push_vlan. */
+ OVS_ACTION_ATTR_POP_VLAN, /* No argument. */
+ OVS_ACTION_ATTR_SAMPLE, /* Nested OVS_SAMPLE_ATTR_*. */
+ __OVS_ACTION_ATTR_MAX
+};
+
+#define OVS_ACTION_ATTR_MAX (__OVS_ACTION_ATTR_MAX - 1)
+
+#endif /* _LINUX_OPENVSWITCH_H */
diff --git a/include/uapi/linux/packet_diag.h b/include/uapi/linux/packet_diag.h
index afafd703ad92..b2cc0cd9c4d9 100644
--- a/include/uapi/linux/packet_diag.h
+++ b/include/uapi/linux/packet_diag.h
@@ -16,6 +16,8 @@ struct packet_diag_req {
#define PACKET_SHOW_MCLIST 0x00000002 /* A set of packet_diag_mclist-s */
#define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */
#define PACKET_SHOW_FANOUT 0x00000008
+#define PACKET_SHOW_MEMINFO 0x00000010
+#define PACKET_SHOW_FILTER 0x00000020
struct packet_diag_msg {
__u8 pdiag_family;
@@ -32,6 +34,9 @@ enum {
PACKET_DIAG_RX_RING,
PACKET_DIAG_TX_RING,
PACKET_DIAG_FANOUT,
+ PACKET_DIAG_UID,
+ PACKET_DIAG_MEMINFO,
+ PACKET_DIAG_FILTER,
__PACKET_DIAG_MAX,
};
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index ebfadc56d1b4..864e324da80d 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -292,12 +292,12 @@
/* Message Signalled Interrupts registers */
-#define PCI_MSI_FLAGS 2 /* Various flags */
-#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */
-#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */
-#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */
-#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */
-#define PCI_MSI_FLAGS_MASKBIT 0x100 /* 64-bit mask bits allowed */
+#define PCI_MSI_FLAGS 2 /* Message Control */
+#define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */
+#define PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available */
+#define PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured */
+#define PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */
+#define PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking capable */
#define PCI_MSI_RFU 3 /* Rest of capability flags */
#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
@@ -309,13 +309,17 @@
#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */
/* MSI-X registers */
-#define PCI_MSIX_FLAGS 2
-#define PCI_MSIX_FLAGS_QSIZE 0x7FF
-#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
-#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
-#define PCI_MSIX_TABLE 4
-#define PCI_MSIX_PBA 8
-#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+#define PCI_MSIX_FLAGS 2 /* Message Control */
+#define PCI_MSIX_FLAGS_QSIZE 0x07FF /* Table size */
+#define PCI_MSIX_FLAGS_MASKALL 0x4000 /* Mask all vectors for this function */
+#define PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */
+#define PCI_MSIX_TABLE 4 /* Table offset */
+#define PCI_MSIX_TABLE_BIR 0x00000007 /* BAR index */
+#define PCI_MSIX_TABLE_OFFSET 0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */
+#define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */
+#define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */
+#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) /* deprecated */
#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */
/* MSI-X entry's format */
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 9fa9c622a7f4..fb104e51496e 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -132,8 +132,10 @@ enum perf_event_sample_format {
PERF_SAMPLE_BRANCH_STACK = 1U << 11,
PERF_SAMPLE_REGS_USER = 1U << 12,
PERF_SAMPLE_STACK_USER = 1U << 13,
+ PERF_SAMPLE_WEIGHT = 1U << 14,
+ PERF_SAMPLE_DATA_SRC = 1U << 15,
- PERF_SAMPLE_MAX = 1U << 14, /* non-ABI */
+ PERF_SAMPLE_MAX = 1U << 16, /* non-ABI */
};
/*
@@ -443,6 +445,7 @@ struct perf_event_mmap_page {
#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
+#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
/*
* Indicates that the content of PERF_SAMPLE_IP points to
* the actual instruction that triggered the event. See also
@@ -588,6 +591,9 @@ enum perf_event_type {
* { u64 size;
* char data[size];
* u64 dyn_size; } && PERF_SAMPLE_STACK_USER
+ *
+ * { u64 weight; } && PERF_SAMPLE_WEIGHT
+ * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
* };
*/
PERF_RECORD_SAMPLE = 9,
@@ -613,4 +619,67 @@ enum perf_callchain_context {
#define PERF_FLAG_FD_OUTPUT (1U << 1)
#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
+union perf_mem_data_src {
+ __u64 val;
+ struct {
+ __u64 mem_op:5, /* type of opcode */
+ mem_lvl:14, /* memory hierarchy level */
+ mem_snoop:5, /* snoop mode */
+ mem_lock:2, /* lock instr */
+ mem_dtlb:7, /* tlb access */
+ mem_rsvd:31;
+ };
+};
+
+/* type of opcode (load/store/prefetch,code) */
+#define PERF_MEM_OP_NA 0x01 /* not available */
+#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
+#define PERF_MEM_OP_STORE 0x04 /* store instruction */
+#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
+#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
+#define PERF_MEM_OP_SHIFT 0
+
+/* memory hierarchy (memory level, hit or miss) */
+#define PERF_MEM_LVL_NA 0x01 /* not available */
+#define PERF_MEM_LVL_HIT 0x02 /* hit level */
+#define PERF_MEM_LVL_MISS 0x04 /* miss level */
+#define PERF_MEM_LVL_L1 0x08 /* L1 */
+#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
+#define PERF_MEM_LVL_L2 0x20 /* L2 */
+#define PERF_MEM_LVL_L3 0x40 /* L3 */
+#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
+#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
+#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
+#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
+#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
+#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
+#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
+#define PERF_MEM_LVL_SHIFT 5
+
+/* snoop mode */
+#define PERF_MEM_SNOOP_NA 0x01 /* not available */
+#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
+#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
+#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
+#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
+#define PERF_MEM_SNOOP_SHIFT 19
+
+/* locked instruction */
+#define PERF_MEM_LOCK_NA 0x01 /* not available */
+#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
+#define PERF_MEM_LOCK_SHIFT 24
+
+/* TLB access */
+#define PERF_MEM_TLB_NA 0x01 /* not available */
+#define PERF_MEM_TLB_HIT 0x02 /* hit level */
+#define PERF_MEM_TLB_MISS 0x04 /* miss level */
+#define PERF_MEM_TLB_L1 0x08 /* L1 */
+#define PERF_MEM_TLB_L2 0x10 /* L2 */
+#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
+#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
+#define PERF_MEM_TLB_SHIFT 26
+
+#define PERF_MEM_S(a, s) \
+ (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
+
#endif /* _UAPI_LINUX_PERF_EVENT_H */
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 32aef0a439ef..dbd71b0c7d8c 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -348,6 +348,7 @@ enum {
TCA_HTB_INIT,
TCA_HTB_CTAB,
TCA_HTB_RTAB,
+ TCA_HTB_DIRECT_QLEN,
__TCA_HTB_MAX,
};
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index 022ab186a812..52ebcc89f306 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -5,6 +5,7 @@
/* has the defines to get at the registers. */
+#include <linux/types.h>
#define PTRACE_TRACEME 0
#define PTRACE_PEEKTEXT 1
@@ -52,6 +53,17 @@
#define PTRACE_INTERRUPT 0x4207
#define PTRACE_LISTEN 0x4208
+#define PTRACE_PEEKSIGINFO 0x4209
+
+struct ptrace_peeksiginfo_args {
+ __u64 off; /* from which siginfo to start */
+ __u32 flags;
+ __s32 nr; /* how may siginfos to take */
+};
+
+/* Read signals from a shared (process wide) queue */
+#define PTRACE_PEEKSIGINFO_SHARED (1 << 0)
+
/* Wait extended result codes for the above trace options. */
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
diff --git a/include/uapi/linux/rfkill.h b/include/uapi/linux/rfkill.h
index 2753c6cc9740..058757f7a733 100644
--- a/include/uapi/linux/rfkill.h
+++ b/include/uapi/linux/rfkill.h
@@ -37,6 +37,7 @@
* @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
* @RFKILL_TYPE_GPS: switch is on a GPS device.
* @RFKILL_TYPE_FM: switch is on a FM radio device.
+ * @RFKILL_TYPE_NFC: switch is on an NFC device.
* @NUM_RFKILL_TYPES: number of defined rfkill types
*/
enum rfkill_type {
@@ -48,6 +49,7 @@ enum rfkill_type {
RFKILL_TYPE_WWAN,
RFKILL_TYPE_GPS,
RFKILL_TYPE_FM,
+ RFKILL_TYPE_NFC,
NUM_RFKILL_TYPES,
};
diff --git a/include/net/sctp/user.h b/include/uapi/linux/sctp.h
index 9a0ae091366d..66b466e4ca08 100644
--- a/include/net/sctp/user.h
+++ b/include/uapi/linux/sctp.h
@@ -42,15 +42,17 @@
* Jon Grimm <jgrimm@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ryan Layer <rmlayer@us.ibm.com>
- * Ardelle Fan <ardelle.fan@intel.com>
+ * Ardelle Fan <ardelle.fan@intel.com>
* Sridhar Samudrala <sri@us.ibm.com>
+ * Inaky Perez-Gonzalez <inaky.gonzalez@intel.com>
+ * Vlad Yasevich <vladislav.yasevich@hp.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
*/
-#ifndef __net_sctp_user_h__
-#define __net_sctp_user_h__
+#ifndef _UAPI_SCTP_H
+#define _UAPI_SCTP_H
#include <linux/types.h>
#include <linux/socket.h>
@@ -165,17 +167,23 @@ enum sctp_sinfo_flags {
SCTP_ADDR_OVER = 2, /* Override the primary destination. */
SCTP_ABORT=4, /* Send an ABORT message to the peer. */
SCTP_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
};
+typedef union {
+ __u8 raw;
+ struct sctp_initmsg init;
+ struct sctp_sndrcvinfo sndrcv;
+} sctp_cmsg_data_t;
/* These are cmsg_types. */
typedef enum sctp_cmsg_type {
SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */
+#define SCTP_INIT SCTP_INIT
SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */
+#define SCTP_SNDRCV SCTP_SNDRCV
} sctp_cmsg_t;
-
/*
* 5.3.1.1 SCTP_ASSOC_CHANGE
*
@@ -345,6 +353,12 @@ struct sctp_pdapi_event {
enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
+/*
+ * 5.3.1.8. SCTP_AUTHENTICATION_EVENT
+ *
+ * When a receiver is using authentication this message will provide
+ * notifications regarding new keys being made active as well as errors.
+ */
struct sctp_authkey_event {
__u16 auth_type;
__u16 auth_flags;
@@ -421,15 +435,23 @@ union sctp_notification {
enum sctp_sn_type {
SCTP_SN_TYPE_BASE = (1<<15),
SCTP_ASSOC_CHANGE,
+#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE
SCTP_PEER_ADDR_CHANGE,
+#define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE
SCTP_SEND_FAILED,
+#define SCTP_SEND_FAILED SCTP_SEND_FAILED
SCTP_REMOTE_ERROR,
+#define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR
SCTP_SHUTDOWN_EVENT,
+#define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT
SCTP_PARTIAL_DELIVERY_EVENT,
+#define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT
SCTP_ADAPTATION_INDICATION,
+#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION
SCTP_AUTHENTICATION_EVENT,
#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT
SCTP_SENDER_DRY_EVENT,
+#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT
};
/* Notification error codes used to fill up the error fields in some
@@ -454,7 +476,7 @@ typedef enum sctp_sn_error {
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. See [SCTP] for more information on how
- * these parameters are used in RTO calculation.
+ * these parameters are used in RTO calculation.
*/
struct sctp_rtoinfo {
sctp_assoc_t srto_assoc_id;
@@ -504,6 +526,9 @@ struct sctp_prim {
struct sockaddr_storage ssp_addr;
} __attribute__((packed, aligned(4)));
+/* For backward compatibility use, define the old name too */
+#define sctp_setprim sctp_prim
+
/*
* 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER)
*
@@ -564,12 +589,27 @@ struct sctp_authchunk {
*
* This option gets or sets the list of HMAC algorithms that the local
* endpoint requires the peer to use.
-*/
+ */
+#ifndef __KERNEL__
+/* This here is only used by user space as is. It might not be a good idea
+ * to export/reveal the whole structure with reserved fields etc.
+ */
+enum {
+ SCTP_AUTH_HMAC_ID_SHA1 = 1,
+ SCTP_AUTH_HMAC_ID_SHA256 = 3,
+};
+#endif
+
struct sctp_hmacalgo {
__u32 shmac_num_idents;
__u16 shmac_idents[];
};
+/* Sadly, user and kernel space have different names for
+ * this structure member, so this is to not break anything.
+ */
+#define shmac_number_of_idents shmac_num_idents
+
/*
* 7.1.20. Set a shared key (SCTP_AUTH_KEY)
*
@@ -691,6 +731,24 @@ struct sctp_authchunks {
uint8_t gauth_chunks[];
};
+/* The broken spelling has been released already in lksctp-tools header,
+ * so don't break anyone, now that it's fixed.
+ */
+#define guth_number_of_chunks gauth_number_of_chunks
+
+/* Association states. */
+enum sctp_sstat_state {
+ SCTP_EMPTY = 0,
+ SCTP_CLOSED = 1,
+ SCTP_COOKIE_WAIT = 2,
+ SCTP_COOKIE_ECHOED = 3,
+ SCTP_ESTABLISHED = 4,
+ SCTP_SHUTDOWN_PENDING = 5,
+ SCTP_SHUTDOWN_SENT = 6,
+ SCTP_SHUTDOWN_RECEIVED = 7,
+ SCTP_SHUTDOWN_ACK_SENT = 8,
+};
+
/*
* 8.2.6. Get the Current Identifiers of Associations
* (SCTP_GET_ASSOC_ID_LIST)
@@ -705,15 +763,20 @@ struct sctp_assoc_ids {
/*
* 8.3, 8.5 get all peer/local addresses in an association.
- * This parameter struct is used by SCTP_GET_PEER_ADDRS and
+ * This parameter struct is used by SCTP_GET_PEER_ADDRS and
* SCTP_GET_LOCAL_ADDRS socket options used internally to implement
- * sctp_getpaddrs() and sctp_getladdrs() API.
+ * sctp_getpaddrs() and sctp_getladdrs() API.
*/
struct sctp_getaddrs_old {
sctp_assoc_t assoc_id;
int addr_num;
+#ifdef __KERNEL__
struct sockaddr __user *addrs;
+#else
+ struct sockaddr *addrs;
+#endif
};
+
struct sctp_getaddrs {
sctp_assoc_t assoc_id; /*input*/
__u32 addr_num; /*output*/
@@ -779,4 +842,5 @@ struct sctp_paddrthlds {
__u16 spt_pathmaxrxt;
__u16 spt_pathpfthld;
};
-#endif /* __net_sctp_user_h__ */
+
+#endif /* _UAPI_SCTP_H */
diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h
index b49eab89c9fd..df2e8b4f9c03 100644
--- a/include/uapi/linux/snmp.h
+++ b/include/uapi/linux/snmp.h
@@ -50,6 +50,7 @@ enum
IPSTATS_MIB_OUTMCASTOCTETS, /* OutMcastOctets */
IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */
IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */
+ IPSTATS_MIB_CSUMERRORS, /* InCsumErrors */
__IPSTATS_MIB_MAX
};
@@ -87,6 +88,7 @@ enum
ICMP_MIB_OUTTIMESTAMPREPS, /* OutTimestampReps */
ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */
ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */
+ ICMP_MIB_CSUMERRORS, /* InCsumErrors */
__ICMP_MIB_MAX
};
@@ -103,6 +105,7 @@ enum
ICMP6_MIB_INERRORS, /* InErrors */
ICMP6_MIB_OUTMSGS, /* OutMsgs */
ICMP6_MIB_OUTERRORS, /* OutErrors */
+ ICMP6_MIB_CSUMERRORS, /* InCsumErrors */
__ICMP6_MIB_MAX
};
@@ -130,6 +133,7 @@ enum
TCP_MIB_RETRANSSEGS, /* RetransSegs */
TCP_MIB_INERRS, /* InErrs */
TCP_MIB_OUTRSTS, /* OutRsts */
+ TCP_MIB_CSUMERRORS, /* InCsumErrors */
__TCP_MIB_MAX
};
@@ -147,6 +151,7 @@ enum
UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */
UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */
UDP_MIB_SNDBUFERRORS, /* SndbufErrors */
+ UDP_MIB_CSUMERRORS, /* InCsumErrors */
__UDP_MIB_MAX
};
@@ -202,6 +207,8 @@ enum
LINUX_MIB_TCPFORWARDRETRANS, /* TCPForwardRetrans */
LINUX_MIB_TCPSLOWSTARTRETRANS, /* TCPSlowStartRetrans */
LINUX_MIB_TCPTIMEOUTS, /* TCPTimeouts */
+ LINUX_MIB_TCPLOSSPROBES, /* TCPLossProbes */
+ LINUX_MIB_TCPLOSSPROBERECOVERY, /* TCPLossProbeRecovery */
LINUX_MIB_TCPRENORECOVERYFAIL, /* TCPRenoRecoveryFail */
LINUX_MIB_TCPSACKRECOVERYFAIL, /* TCPSackRecoveryFail */
LINUX_MIB_TCPSCHEDULERFAILED, /* TCPSchedulerFailed */
@@ -245,6 +252,7 @@ enum
LINUX_MIB_TCPFASTOPENPASSIVEFAIL, /* TCPFastOpenPassiveFail */
LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */
LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */
+ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */
__LINUX_MIB_MAX
};
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index 6b1ead0b0c9d..8d776ebc4829 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -102,7 +102,6 @@ enum {
#define TCP_QUICKACK 12 /* Block/reenable quick acks */
#define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */
-#define TCP_COOKIE_TRANSACTIONS 15 /* TCP Cookie Transactions */
#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/
#define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */
#define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */
@@ -199,29 +198,4 @@ struct tcp_md5sig {
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};
-/* for TCP_COOKIE_TRANSACTIONS (TCPCT) socket option */
-#define TCP_COOKIE_MIN 8 /* 64-bits */
-#define TCP_COOKIE_MAX 16 /* 128-bits */
-#define TCP_COOKIE_PAIR_SIZE (2*TCP_COOKIE_MAX)
-
-/* Flags for both getsockopt and setsockopt */
-#define TCP_COOKIE_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
-#define TCP_COOKIE_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
- * supercedes everything. */
-
-/* Flags for getsockopt */
-#define TCP_S_DATA_IN (1 << 2) /* Was data received? */
-#define TCP_S_DATA_OUT (1 << 3) /* Was data sent? */
-
-/* TCP_COOKIE_TRANSACTIONS data */
-struct tcp_cookie_transactions {
- __u16 tcpct_flags; /* see above */
- __u8 __tcpct_pad1; /* zero */
- __u8 tcpct_cookie_desired; /* bytes */
- __u16 tcpct_s_data_desired; /* bytes of variable data */
- __u16 tcpct_used; /* bytes in value */
- __u8 tcpct_value[TCP_MSS_DEFAULT];
-};
-
-
#endif /* _UAPI_LINUX_TCP_H */
diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h
index 0d3c0edc3eda..e75e1b6ff27f 100644
--- a/include/uapi/linux/time.h
+++ b/include/uapi/linux/time.h
@@ -54,11 +54,9 @@ struct itimerval {
#define CLOCK_BOOTTIME 7
#define CLOCK_REALTIME_ALARM 8
#define CLOCK_BOOTTIME_ALARM 9
+#define CLOCK_SGI_CYCLE 10 /* Hardware specific */
+#define CLOCK_TAI 11
-/*
- * The IDs of various hardware clocks:
- */
-#define CLOCK_SGI_CYCLE 10
#define MAX_CLOCKS 16
#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
#define CLOCKS_MONO CLOCK_MONOTONIC
diff --git a/include/uapi/linux/usb/cdc-wdm.h b/include/uapi/linux/usb/cdc-wdm.h
new file mode 100644
index 000000000000..f03134feebd6
--- /dev/null
+++ b/include/uapi/linux/usb/cdc-wdm.h
@@ -0,0 +1,21 @@
+/*
+ * USB CDC Device Management userspace API definitions
+ *
+ * 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__LINUX_USB_CDC_WDM_H
+#define _UAPI__LINUX_USB_CDC_WDM_H
+
+/*
+ * This IOCTL is used to retrieve the wMaxCommand for the device,
+ * defining the message limit for both reading and writing.
+ *
+ * For CDC WDM functions this will be the wMaxCommand field of the
+ * Device Management Functional Descriptor.
+ */
+#define IOCTL_WDM_MAX_COMMAND _IOR('H', 0xA0, __u16)
+
+#endif /* _UAPI__LINUX_USB_CDC_WDM_H */
diff --git a/include/uapi/linux/usb/ch9.h b/include/uapi/linux/usb/ch9.h
index f738e25377ff..aa33fd1b2d4f 100644
--- a/include/uapi/linux/usb/ch9.h
+++ b/include/uapi/linux/usb/ch9.h
@@ -138,7 +138,7 @@
/*
* New Feature Selectors as added by USB 3.0
- * See USB 3.0 spec Table 9-6
+ * See USB 3.0 spec Table 9-7
*/
#define USB_DEVICE_U1_ENABLE 48 /* dev may initiate U1 transition */
#define USB_DEVICE_U2_ENABLE 49 /* dev may initiate U2 transition */
@@ -147,7 +147,7 @@
#define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00
/*
- * Suspend Options, Table 9-7 USB 3.0 spec
+ * Suspend Options, Table 9-8 USB 3.0 spec
*/
#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0))
#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1))
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index dcd63745e83a..69bd5bb0d5af 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -59,6 +59,7 @@
#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */
#define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */
#define V4L2_CTRL_CLASS_DV 0x00a00000 /* Digital Video controls */
+#define V4L2_CTRL_CLASS_FM_RX 0x00a10000 /* Digital Video controls */
/* User-class control IDs */
@@ -146,6 +147,19 @@ enum v4l2_colorfx {
* of controls. We reserve 16 controls for this driver. */
#define V4L2_CID_USER_MEYE_BASE (V4L2_CID_USER_BASE + 0x1000)
+/* The base for the bttv driver controls.
+ * We reserve 32 controls for this driver. */
+#define V4L2_CID_USER_BTTV_BASE (V4L2_CID_USER_BASE + 0x1010)
+
+
+/* The base for the s2255 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1030)
+
+/* The base for the si476x driver controls. See include/media/si476x.h for the list
+ * of controls. Total of 16 controls is reserved for this driver */
+#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1040)
+
/* MPEG-class control IDs */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -351,6 +365,7 @@ enum v4l2_mpeg_video_multi_slice_mode {
#define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223)
#define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224)
#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225)
+#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (V4L2_CID_MPEG_BASE+226)
#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300)
#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301)
@@ -643,6 +658,7 @@ enum v4l2_exposure_metering {
V4L2_EXPOSURE_METERING_AVERAGE = 0,
V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1,
V4L2_EXPOSURE_METERING_SPOT = 2,
+ V4L2_EXPOSURE_METERING_MATRIX = 3,
};
#define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26)
@@ -825,4 +841,16 @@ enum v4l2_dv_rgb_range {
#define V4L2_CID_DV_RX_POWER_PRESENT (V4L2_CID_DV_CLASS_BASE + 100)
#define V4L2_CID_DV_RX_RGB_RANGE (V4L2_CID_DV_CLASS_BASE + 101)
+#define V4L2_CID_FM_RX_CLASS_BASE (V4L2_CTRL_CLASS_FM_RX | 0x900)
+#define V4L2_CID_FM_RX_CLASS (V4L2_CTRL_CLASS_FM_RX | 1)
+
+#define V4L2_CID_TUNE_DEEMPHASIS (V4L2_CID_FM_RX_CLASS_BASE + 1)
+enum v4l2_deemphasis {
+ V4L2_DEEMPHASIS_DISABLED = V4L2_PREEMPHASIS_DISABLED,
+ V4L2_DEEMPHASIS_50_uS = V4L2_PREEMPHASIS_50_uS,
+ V4L2_DEEMPHASIS_75_uS = V4L2_PREEMPHASIS_75_uS,
+};
+
+#define V4L2_CID_RDS_RECEPTION (V4L2_CID_FM_RX_CLASS_BASE + 2)
+
#endif
diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h
index 9ef8172e5ed0..4e0c58d25ff0 100644
--- a/include/uapi/linux/v4l2-dv-timings.h
+++ b/include/uapi/linux/v4l2-dv-timings.h
@@ -42,6 +42,15 @@
V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \
}
+/* Note: these are the nominal timings, for HDMI links this format is typically
+ * double-clocked to meet the minimum pixelclock requirements. */
+#define V4L2_DV_BT_CEA_720X480I59_94 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \
+ 13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
#define V4L2_DV_BT_CEA_720X480P59_94 { \
.type = V4L2_DV_BT_656_1120, \
V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \
@@ -49,6 +58,15 @@
V4L2_DV_BT_STD_CEA861, 0) \
}
+/* Note: these are the nominal timings, for HDMI links this format is typically
+ * double-clocked to meet the minimum pixelclock requirements. */
+#define V4L2_DV_BT_CEA_720X576I50 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \
+ 13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
#define V4L2_DV_BT_CEA_720X576P50 { \
.type = V4L2_DV_BT_656_1120, \
V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \
diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h
index b9b7bea04537..6ee63d09b32d 100644
--- a/include/uapi/linux/v4l2-mediabus.h
+++ b/include/uapi/linux/v4l2-mediabus.h
@@ -37,7 +37,7 @@
enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_FIXED = 0x0001,
- /* RGB - next is 0x1009 */
+ /* RGB - next is 0x100d */
V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
@@ -46,6 +46,10 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
+ V4L2_MBUS_FMT_RGB666_1X18 = 0x1009,
+ V4L2_MBUS_FMT_RGB888_1X24 = 0x100a,
+ V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b,
+ V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c,
/* YUV (including grey) - next is 0x2017 */
V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 234d1d870914..f40b41c7e108 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -72,27 +72,6 @@
#define VIDEO_MAX_FRAME 32
#define VIDEO_MAX_PLANES 8
-#ifndef __KERNEL__
-
-/* These defines are V4L1 specific and should not be used with the V4L2 API!
- They will be removed from this header in the future. */
-
-#define VID_TYPE_CAPTURE 1 /* Can capture */
-#define VID_TYPE_TUNER 2 /* Can tune */
-#define VID_TYPE_TELETEXT 4 /* Does teletext */
-#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */
-#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */
-#define VID_TYPE_CLIPPING 32 /* Can clip */
-#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */
-#define VID_TYPE_SCALES 128 /* Scalable */
-#define VID_TYPE_MONOCHROME 256 /* Monochrome only */
-#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */
-#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */
-#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */
-#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
-#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
-#endif
-
/*
* M I S C E L L A N E O U S
*/
@@ -705,6 +684,7 @@ struct v4l2_buffer {
#define V4L2_BUF_FLAG_TIMESTAMP_MASK 0xe000
#define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x0000
#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000
+#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x4000
/**
* struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor
@@ -980,52 +960,6 @@ struct v4l2_standard {
__u32 reserved[4];
};
-/* The DV Preset API is deprecated in favor of the DV Timings API.
- New drivers shouldn't use this anymore! */
-
-/*
- * V I D E O T I M I N G S D V P R E S E T
- */
-struct v4l2_dv_preset {
- __u32 preset;
- __u32 reserved[4];
-};
-
-/*
- * D V P R E S E T S E N U M E R A T I O N
- */
-struct v4l2_dv_enum_preset {
- __u32 index;
- __u32 preset;
- __u8 name[32]; /* Name of the preset timing */
- __u32 width;
- __u32 height;
- __u32 reserved[4];
-};
-
-/*
- * D V P R E S E T V A L U E S
- */
-#define V4L2_DV_INVALID 0
-#define V4L2_DV_480P59_94 1 /* BT.1362 */
-#define V4L2_DV_576P50 2 /* BT.1362 */
-#define V4L2_DV_720P24 3 /* SMPTE 296M */
-#define V4L2_DV_720P25 4 /* SMPTE 296M */
-#define V4L2_DV_720P30 5 /* SMPTE 296M */
-#define V4L2_DV_720P50 6 /* SMPTE 296M */
-#define V4L2_DV_720P59_94 7 /* SMPTE 274M */
-#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */
-#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */
-#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */
-#define V4L2_DV_1080I25 11 /* BT.1120 */
-#define V4L2_DV_1080I50 12 /* SMPTE 296M */
-#define V4L2_DV_1080I60 13 /* SMPTE 296M */
-#define V4L2_DV_1080P24 14 /* SMPTE 296M */
-#define V4L2_DV_1080P25 15 /* SMPTE 296M */
-#define V4L2_DV_1080P30 16 /* SMPTE 296M */
-#define V4L2_DV_1080P50 17 /* BT.1120 */
-#define V4L2_DV_1080P60 18 /* BT.1120 */
-
/*
* D V B T T I M I N G S
*/
@@ -1119,7 +1053,7 @@ struct v4l2_bt_timings {
longer and field 2 is really one half-line shorter, so each field has
exactly the same number of half-lines. Whether half-lines can be detected
or used depends on the hardware. */
-#define V4L2_DV_FL_HALF_LINE (1 << 0)
+#define V4L2_DV_FL_HALF_LINE (1 << 3)
/** struct v4l2_dv_timings - DV timings
@@ -1239,7 +1173,6 @@ struct v4l2_input {
#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */
/* capabilities flags */
-#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */
#define V4L2_IN_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */
#define V4L2_IN_CAP_CUSTOM_TIMINGS V4L2_IN_CAP_DV_TIMINGS /* For compatibility */
#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */
@@ -1263,7 +1196,6 @@ struct v4l2_output {
#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3
/* capabilities flags */
-#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */
#define V4L2_OUT_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */
#define V4L2_OUT_CAP_CUSTOM_TIMINGS V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */
#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */
@@ -1854,10 +1786,12 @@ struct v4l2_event_subscription {
/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
-#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */
-#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */
-#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */
-#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */
+#define V4L2_CHIP_MATCH_BRIDGE 0 /* Match against chip ID on the bridge (0 for the bridge) */
+#define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE
+#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */
+#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */
+#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */
+#define V4L2_CHIP_MATCH_SUBDEV 4 /* Match against subdev index */
struct v4l2_dbg_match {
__u32 type; /* Match type */
@@ -1881,6 +1815,17 @@ struct v4l2_dbg_chip_ident {
__u32 revision; /* chip revision, chip specific */
} __attribute__ ((packed));
+#define V4L2_CHIP_FL_READABLE (1 << 0)
+#define V4L2_CHIP_FL_WRITABLE (1 << 1)
+
+/* VIDIOC_DBG_G_CHIP_INFO */
+struct v4l2_dbg_chip_info {
+ struct v4l2_dbg_match match;
+ char name[32];
+ __u32 flags;
+ __u32 reserved[32];
+} __attribute__ ((packed));
+
/**
* struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument
* @index: on return, index of the first created buffer
@@ -1958,15 +1903,12 @@ struct v4l2_create_buffers {
#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls)
#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls)
#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls)
-#if 1
#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum)
#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx)
#define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd)
#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd)
-#endif
-#if 1
/* Experimental, meant for debugging, testing and internal use.
Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
You must be root to use these ioctls. Never use these in applications! */
@@ -1974,18 +1916,13 @@ struct v4l2_create_buffers {
#define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register)
/* Experimental, meant for debugging, testing and internal use.
- Never use this ioctl in applications! */
+ Never use this ioctl in applications!
+ Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_INFO and
+ will go away in the future. */
#define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident)
-#endif
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
-/* These four DV Preset ioctls are deprecated in favor of the DV Timings
- ioctls. */
-#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset)
-#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset)
-#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset)
-#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset)
#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings)
#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings)
#define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event)
@@ -2016,6 +1953,10 @@ struct v4l2_create_buffers {
versions. */
#define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band)
+/* Experimental, meant for debugging, testing and internal use.
+ Never use these in applications! */
+#define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info)
+
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/include/uapi/linux/vm_sockets.h b/include/uapi/linux/vm_sockets.h
index df91301847ec..b4ed5d895699 100644
--- a/include/uapi/linux/vm_sockets.h
+++ b/include/uapi/linux/vm_sockets.h
@@ -13,12 +13,10 @@
* more details.
*/
-#ifndef _VM_SOCKETS_H_
-#define _VM_SOCKETS_H_
+#ifndef _UAPI_VM_SOCKETS_H
+#define _UAPI_VM_SOCKETS_H
-#if !defined(__KERNEL__)
-#include <sys/socket.h>
-#endif
+#include <linux/socket.h>
/* Option name for STREAM socket buffer size. Use as the option name in
* setsockopt(3) or getsockopt(3) to set or get an unsigned long long that
@@ -137,14 +135,13 @@
#define VM_SOCKETS_VERSION_MINOR(_v) (((_v) & 0x0000FFFF))
/* Address structure for vSockets. The address family should be set to
- * whatever vmci_sock_get_af_value_fd() returns. The structure members should
- * all align on their natural boundaries without resorting to compiler packing
- * directives. The total size of this structure should be exactly the same as
- * that of struct sockaddr.
+ * AF_VSOCK. The structure members should all align on their natural
+ * boundaries without resorting to compiler packing directives. The total size
+ * of this structure should be exactly the same as that of struct sockaddr.
*/
struct sockaddr_vm {
- sa_family_t svm_family;
+ __kernel_sa_family_t svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
@@ -156,8 +153,4 @@ struct sockaddr_vm {
#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
-#if defined(__KERNEL__)
-int vm_sockets_get_local_cid(void);
-#endif
-
-#endif
+#endif /* _UAPI_VM_SOCKETS_H */
diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 28e493b5b94c..a8cd6a4a2970 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -297,6 +297,7 @@ enum xfrm_attr_type_t {
XFRMA_MARK, /* struct xfrm_mark */
XFRMA_TFCPAD, /* __u32 */
XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_esn */
+ XFRMA_SA_EXTRA_FLAGS, /* __u32 */
__XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -367,6 +368,8 @@ struct xfrm_usersa_info {
#define XFRM_STATE_ESN 128
};
+#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
+
struct xfrm_usersa_id {
xfrm_address_t daddr;
__be32 spi;
diff --git a/include/video/auo_k190xfb.h b/include/video/auo_k190xfb.h
index 609efe8c686e..ac329ee1d753 100644
--- a/include/video/auo_k190xfb.h
+++ b/include/video/auo_k190xfb.h
@@ -22,6 +22,8 @@
*/
#define AUOK190X_RESOLUTION_800_600 0
#define AUOK190X_RESOLUTION_1024_768 1
+#define AUOK190X_RESOLUTION_600_800 4
+#define AUOK190X_RESOLUTION_768_1024 5
/*
* struct used by auok190x. board specific stuff comes from *board
@@ -98,7 +100,6 @@ struct auok190x_board {
int gpio_nbusy;
int resolution;
- int rotation;
int quirks;
int fps;
};
diff --git a/include/video/display_timing.h b/include/video/display_timing.h
index 71e9a383a981..5d0259b08e01 100644
--- a/include/video/display_timing.h
+++ b/include/video/display_timing.h
@@ -12,19 +12,22 @@
#include <linux/bitops.h>
#include <linux/types.h>
-/* VESA display monitor timing parameters */
-#define VESA_DMT_HSYNC_LOW BIT(0)
-#define VESA_DMT_HSYNC_HIGH BIT(1)
-#define VESA_DMT_VSYNC_LOW BIT(2)
-#define VESA_DMT_VSYNC_HIGH BIT(3)
-
-/* display specific flags */
-#define DISPLAY_FLAGS_DE_LOW BIT(0) /* data enable flag */
-#define DISPLAY_FLAGS_DE_HIGH BIT(1)
-#define DISPLAY_FLAGS_PIXDATA_POSEDGE BIT(2) /* drive data on pos. edge */
-#define DISPLAY_FLAGS_PIXDATA_NEGEDGE BIT(3) /* drive data on neg. edge */
-#define DISPLAY_FLAGS_INTERLACED BIT(4)
-#define DISPLAY_FLAGS_DOUBLESCAN BIT(5)
+enum display_flags {
+ DISPLAY_FLAGS_HSYNC_LOW = BIT(0),
+ DISPLAY_FLAGS_HSYNC_HIGH = BIT(1),
+ DISPLAY_FLAGS_VSYNC_LOW = BIT(2),
+ DISPLAY_FLAGS_VSYNC_HIGH = BIT(3),
+
+ /* data enable flag */
+ DISPLAY_FLAGS_DE_LOW = BIT(4),
+ DISPLAY_FLAGS_DE_HIGH = BIT(5),
+ /* drive data on pos. edge */
+ DISPLAY_FLAGS_PIXDATA_POSEDGE = BIT(6),
+ /* drive data on neg. edge */
+ DISPLAY_FLAGS_PIXDATA_NEGEDGE = BIT(7),
+ DISPLAY_FLAGS_INTERLACED = BIT(8),
+ DISPLAY_FLAGS_DOUBLESCAN = BIT(9),
+};
/*
* A single signal can be specified via a range of minimal and maximal values
@@ -36,12 +39,6 @@ struct timing_entry {
u32 max;
};
-enum timing_entry_index {
- TE_MIN = 0,
- TE_TYP = 1,
- TE_MAX = 2,
-};
-
/*
* Single "mode" entry. This describes one set of signal timings a display can
* have in one setting. This struct can later be converted to struct videomode
@@ -72,8 +69,7 @@ struct display_timing {
struct timing_entry vback_porch; /* ver. back porch */
struct timing_entry vsync_len; /* ver. sync len */
- unsigned int dmt_flags; /* VESA DMT flags */
- unsigned int data_flags; /* video data flags */
+ enum display_flags flags; /* display flags */
};
/*
@@ -89,25 +85,6 @@ struct display_timings {
struct display_timing **timings;
};
-/* get value specified by index from struct timing_entry */
-static inline u32 display_timing_get_value(const struct timing_entry *te,
- enum timing_entry_index index)
-{
- switch (index) {
- case TE_MIN:
- return te->min;
- break;
- case TE_TYP:
- return te->typ;
- break;
- case TE_MAX:
- return te->max;
- break;
- default:
- return te->typ;
- }
-}
-
/* get one entry from struct display_timings */
static inline struct display_timing *display_timings_get(const struct
display_timings *disp,
diff --git a/include/video/platform_lcd.h b/include/video/platform_lcd.h
index ad3bdfe743b2..23864b284147 100644
--- a/include/video/platform_lcd.h
+++ b/include/video/platform_lcd.h
@@ -15,6 +15,7 @@ struct plat_lcd_data;
struct fb_info;
struct plat_lcd_data {
+ int (*probe)(struct plat_lcd_data *);
void (*set_power)(struct plat_lcd_data *, unsigned int power);
int (*match_fb)(struct plat_lcd_data *, struct fb_info *);
};
diff --git a/include/video/videomode.h b/include/video/videomode.h
index a42156234dd4..3f1049d870d5 100644
--- a/include/video/videomode.h
+++ b/include/video/videomode.h
@@ -29,20 +29,30 @@ struct videomode {
u32 vback_porch;
u32 vsync_len;
- unsigned int dmt_flags; /* VESA DMT flags */
- unsigned int data_flags; /* video data flags */
+ enum display_flags flags; /* display flags */
};
/**
* videomode_from_timing - convert display timing to videomode
+ * @dt: display_timing structure
+ * @vm: return value
+ *
+ * DESCRIPTION:
+ * This function converts a struct display_timing to a struct videomode.
+ */
+void videomode_from_timing(const struct display_timing *dt,
+ struct videomode *vm);
+
+/**
+ * videomode_from_timings - convert one display timings entry to videomode
* @disp: structure with all possible timing entries
* @vm: return value
* @index: index into the list of display timings in devicetree
*
* DESCRIPTION:
- * This function converts a struct display_timing to a struct videomode.
+ * This function converts one struct display_timing entry to a struct videomode.
*/
-int videomode_from_timing(const struct display_timings *disp,
+int videomode_from_timings(const struct display_timings *disp,
struct videomode *vm, unsigned int index);
#endif
diff --git a/include/xen/events.h b/include/xen/events.h
index c6bfe01acf6b..b2b27c6a0f7b 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -90,8 +90,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
/* Bind an PSI pirq to an irq. */
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
- int pirq, int vector, const char *name,
- domid_t domid);
+ int pirq, const char *name, domid_t domid);
#endif
/* De-allocates the above mentioned physical interrupt. */
diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
index 01c3d62436ef..ffd4652de91c 100644
--- a/include/xen/interface/io/blkif.h
+++ b/include/xen/interface/io/blkif.h
@@ -138,11 +138,21 @@ struct blkif_request_discard {
uint8_t _pad3;
} __attribute__((__packed__));
+struct blkif_request_other {
+ uint8_t _pad1;
+ blkif_vdev_t _pad2; /* only for read/write requests */
+#ifdef CONFIG_X86_64
+ uint32_t _pad3; /* offsetof(blkif_req..,u.other.id)==8*/
+#endif
+ uint64_t id; /* private guest value, echoed in resp */
+} __attribute__((__packed__));
+
struct blkif_request {
uint8_t operation; /* BLKIF_OP_??? */
union {
struct blkif_request_rw rw;
struct blkif_request_discard discard;
+ struct blkif_request_other other;
} u;
} __attribute__((__packed__));
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
index 9dfc12000980..3ef3fe05ee99 100644
--- a/include/xen/interface/io/netif.h
+++ b/include/xen/interface/io/netif.h
@@ -13,6 +13,24 @@
#include <xen/interface/grant_table.h>
/*
+ * Older implementation of Xen network frontend / backend has an
+ * implicit dependency on the MAX_SKB_FRAGS as the maximum number of
+ * ring slots a skb can use. Netfront / netback may not work as
+ * expected when frontend and backend have different MAX_SKB_FRAGS.
+ *
+ * A better approach is to add mechanism for netfront / netback to
+ * negotiate this value. However we cannot fix all possible
+ * frontends, so we need to define a value which states the minimum
+ * slots backend must support.
+ *
+ * The minimum value derives from older Linux kernel's MAX_SKB_FRAGS
+ * (18), which is proved to work with most frontends. Any new backend
+ * which doesn't negotiate with frontend should expect frontend to
+ * send a valid packet using slots up to this value.
+ */
+#define XEN_NETIF_NR_SLOTS_MIN 18
+
+/*
* Notifications after enqueuing any type of message should be conditional on
* the appropriate req_event or rsp_event field in the shared ring.
* If the client sends notification for rx requests then it should specify
@@ -47,6 +65,7 @@
#define _XEN_NETTXF_extra_info (3)
#define XEN_NETTXF_extra_info (1U<<_XEN_NETTXF_extra_info)
+#define XEN_NETIF_MAX_TX_SIZE 0xFFFF
struct xen_netif_tx_request {
grant_ref_t gref; /* Reference to buffer page */
uint16_t offset; /* Offset within buffer page */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
index 1844d31f4552..7000bb1f6e96 100644
--- a/include/xen/interface/physdev.h
+++ b/include/xen/interface/physdev.h
@@ -251,6 +251,12 @@ struct physdev_pci_device_add {
#define PHYSDEVOP_pci_device_remove 26
#define PHYSDEVOP_restore_msi_ext 27
+/*
+ * Dom0 should use these two to announce MMIO resources assigned to
+ * MSI-X capable devices won't (prepare) or may (release) change.
+ */
+#define PHYSDEVOP_prepare_msix 30
+#define PHYSDEVOP_release_msix 31
struct physdev_pci_device {
/* IN */
uint16_t seg;
diff --git a/include/xen/tmem.h b/include/xen/tmem.h
index 591550a22ac7..3930a90045ff 100644
--- a/include/xen/tmem.h
+++ b/include/xen/tmem.h
@@ -3,7 +3,15 @@
#include <linux/types.h>
+#ifdef CONFIG_XEN_TMEM_MODULE
+#define tmem_enabled true
+#else
/* defined in drivers/xen/tmem.c */
extern bool tmem_enabled;
+#endif
+
+#ifdef CONFIG_XEN_SELFBALLOONING
+extern int xen_selfballoon_init(bool, bool);
+#endif
#endif /* _XEN_TMEM_H */
diff --git a/init/Kconfig b/init/Kconfig
index 5341d7232c3a..a76d13189e47 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -505,6 +505,7 @@ config RCU_USER_QS
config CONTEXT_TRACKING_FORCE
bool "Force context tracking"
depends on CONTEXT_TRACKING
+ default CONTEXT_TRACKING
help
Probe on user/kernel boundaries by default in order to
test the features that rely on it such as userspace RCU extended
@@ -578,13 +579,16 @@ config RCU_FAST_NO_HZ
depends on NO_HZ && SMP
default n
help
- This option causes RCU to attempt to accelerate grace periods in
- order to allow CPUs to enter dynticks-idle state more quickly.
- On the other hand, this option increases the overhead of the
- dynticks-idle checking, thus degrading scheduling latency.
+ This option permits CPUs to enter dynticks-idle state even if
+ they have RCU callbacks queued, and prevents RCU from waking
+ these CPUs up more than roughly once every four jiffies (by
+ default, you can adjust this using the rcutree.rcu_idle_gp_delay
+ parameter), thus improving energy efficiency. On the other
+ hand, this option increases the duration of RCU grace periods,
+ for example, slowing down synchronize_rcu().
- Say Y if energy efficiency is critically important, and you don't
- care about real-time response.
+ Say Y if energy efficiency is critically important, and you
+ don't care about increased grace-period durations.
Say N if you are unsure.
@@ -651,7 +655,7 @@ config RCU_BOOST_DELAY
Accept the default if unsure.
config RCU_NOCB_CPU
- bool "Offload RCU callback processing from boot-selected CPUs"
+ bool "Offload RCU callback processing from boot-selected CPUs (EXPERIMENTAL"
depends on TREE_RCU || TREE_PREEMPT_RCU
default n
help
@@ -662,16 +666,56 @@ config RCU_NOCB_CPU
This option offloads callback invocation from the set of
CPUs specified at boot time by the rcu_nocbs parameter.
- For each such CPU, a kthread ("rcuoN") will be created to
- invoke callbacks, where the "N" is the CPU being offloaded.
- Nothing prevents this kthread from running on the specified
- CPUs, but (1) the kthreads may be preempted between each
- callback, and (2) affinity or cgroups can be used to force
- the kthreads to run on whatever set of CPUs is desired.
-
- Say Y here if you want reduced OS jitter on selected CPUs.
+ For each such CPU, a kthread ("rcuox/N") will be created to
+ invoke callbacks, where the "N" is the CPU being offloaded,
+ and where the "x" is "b" for RCU-bh, "p" for RCU-preempt, and
+ "s" for RCU-sched. Nothing prevents this kthread from running
+ on the specified CPUs, but (1) the kthreads may be preempted
+ between each callback, and (2) affinity or cgroups can be used
+ to force the kthreads to run on whatever set of CPUs is desired.
+
+ Say Y here if you want to help to debug reduced OS jitter.
Say N here if you are unsure.
+choice
+ prompt "Build-forced no-CBs CPUs"
+ default RCU_NOCB_CPU_NONE
+ help
+ This option allows no-CBs CPUs to be specified at build time.
+ Additional no-CBs CPUs may be specified by the rcu_nocbs=
+ boot parameter.
+
+config RCU_NOCB_CPU_NONE
+ bool "No build_forced no-CBs CPUs"
+ depends on RCU_NOCB_CPU
+ help
+ This option does not force any of the CPUs to be no-CBs CPUs.
+ Only CPUs designated by the rcu_nocbs= boot parameter will be
+ no-CBs CPUs.
+
+config RCU_NOCB_CPU_ZERO
+ bool "CPU 0 is a build_forced no-CBs CPU"
+ depends on RCU_NOCB_CPU
+ help
+ This option forces CPU 0 to be a no-CBs CPU. Additional CPUs
+ may be designated as no-CBs CPUs using the rcu_nocbs= boot
+ parameter will be no-CBs CPUs.
+
+ Select this if CPU 0 needs to be a no-CBs CPU for real-time
+ or energy-efficiency reasons.
+
+config RCU_NOCB_CPU_ALL
+ bool "All CPUs are build_forced no-CBs CPUs"
+ depends on RCU_NOCB_CPU
+ help
+ This option forces all CPUs to be no-CBs CPUs. The rcu_nocbs=
+ boot parameter will be ignored.
+
+ Select this if all CPUs need to be no-CBs CPUs for real-time
+ or energy-efficiency reasons.
+
+endchoice
+
endmenu # "RCU Subsystem"
config IKCONFIG
@@ -1177,6 +1221,35 @@ config SYSCTL
config ANON_INODES
bool
+config HAVE_UID16
+ bool
+
+config SYSCTL_EXCEPTION_TRACE
+ bool
+ help
+ Enable support for /proc/sys/debug/exception-trace.
+
+config SYSCTL_ARCH_UNALIGN_NO_WARN
+ bool
+ help
+ Enable support for /proc/sys/kernel/ignore-unaligned-usertrap
+ Allows arch to define/use @no_unaligned_warning to possibly warn
+ about unaligned access emulation going on under the hood.
+
+config SYSCTL_ARCH_UNALIGN_ALLOW
+ bool
+ help
+ Enable support for /proc/sys/kernel/unaligned-trap
+ Allows arches to define/use @unaligned_enabled to runtime toggle
+ the unaligned access emulation.
+ see arch/parisc/kernel/unaligned.c for reference
+
+config HOTPLUG
+ def_bool y
+
+config HAVE_PCSPKR_PLATFORM
+ bool
+
menuconfig EXPERT
bool "Configure standard kernel features (expert users)"
# Unhide debug options, to make the on-by-default options visible
@@ -1187,9 +1260,6 @@ menuconfig EXPERT
environments which can tolerate a "non-standard" kernel.
Only use this if you really know what you are doing.
-config HAVE_UID16
- bool
-
config UID16
bool "Enable 16-bit UID system calls" if EXPERT
depends on HAVE_UID16
@@ -1214,26 +1284,6 @@ config SYSCTL_SYSCALL
If unsure say N here.
-config SYSCTL_EXCEPTION_TRACE
- bool
- help
- Enable support for /proc/sys/debug/exception-trace.
-
-config SYSCTL_ARCH_UNALIGN_NO_WARN
- bool
- help
- Enable support for /proc/sys/kernel/ignore-unaligned-usertrap
- Allows arch to define/use @no_unaligned_warning to possibly warn
- about unaligned access emulation going on under the hood.
-
-config SYSCTL_ARCH_UNALIGN_ALLOW
- bool
- help
- Enable support for /proc/sys/kernel/unaligned-trap
- Allows arches to define/use @unaligned_enabled to runtime toggle
- the unaligned access emulation.
- see arch/parisc/kernel/unaligned.c for reference
-
config KALLSYMS
bool "Load all symbols for debugging/ksymoops" if EXPERT
default y
@@ -1259,9 +1309,6 @@ config KALLSYMS_ALL
Say N unless you really need all symbols.
-config HOTPLUG
- def_bool y
-
config PRINTK
default y
bool "Enable support for printk" if EXPERT
@@ -1300,9 +1347,6 @@ config PCSPKR_PLATFORM
This option allows to disable the internal PC-Speaker
support, saving some memory.
-config HAVE_PCSPKR_PLATFORM
- bool
-
config BASE_FULL
default y
bool "Enable full-sized data structures for core" if EXPERT
@@ -1374,8 +1418,17 @@ config AIO
default y
help
This option enables POSIX asynchronous I/O which may by used
- by some high performance threaded applications. Disabling
- this option saves about 7k.
+ by some high performance threaded applications. Disabling
+ this option saves about 7k.
+
+config PCI_QUIRKS
+ default y
+ bool "Enable PCI quirk workarounds" if EXPERT
+ depends on PCI
+ help
+ This enables workarounds for various PCI chipset
+ bugs/quirks. Disable this only if your target machine is
+ unaffected by PCI quirks.
config EMBEDDED
bool "Embedded system"
@@ -1450,15 +1503,6 @@ config VM_EVENT_COUNTERS
on EXPERT systems. /proc/vmstat will only show page counts
if VM event counters are disabled.
-config PCI_QUIRKS
- default y
- bool "Enable PCI quirk workarounds" if EXPERT
- depends on PCI
- help
- This enables workarounds for various PCI chipset
- bugs/quirks. Disable this only if your target machine is
- unaffected by PCI quirks.
-
config SLUB_DEBUG
default y
bool "Enable SLUB debugging support" if EXPERT
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index a32ec1ce882b..3e0878e8a80d 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -50,6 +50,7 @@ static int init_linuxrc(struct subprocess_info *info, struct cred *new)
static void __init handle_initrd(void)
{
+ struct subprocess_info *info;
static char *argv[] = { "linuxrc", NULL, };
extern char *envp_init[];
int error;
@@ -70,8 +71,11 @@ static void __init handle_initrd(void)
*/
current->flags |= PF_FREEZER_SKIP;
- call_usermodehelper_fns("/linuxrc", argv, envp_init, UMH_WAIT_PROC,
- init_linuxrc, NULL, NULL);
+ info = call_usermodehelper_setup("/linuxrc", argv, envp_init,
+ GFP_KERNEL, init_linuxrc, NULL, NULL);
+ if (!info)
+ return;
+ call_usermodehelper_exec(info, UMH_WAIT_PROC);
current->flags &= ~PF_FREEZER_SKIP;
diff --git a/init/main.c b/init/main.c
index 63534a141b4e..ceed17aaedfd 100644
--- a/init/main.c
+++ b/init/main.c
@@ -9,6 +9,8 @@
* Simplified starting of init: Michael A. Griffith <grif@acm.org>
*/
+#define DEBUG /* Enable initcall_debug */
+
#include <linux/types.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
@@ -174,8 +176,8 @@ static int __init obsolete_checksetup(char *line)
if (line[n] == '\0' || line[n] == '=')
had_early_param = 1;
} else if (!p->setup_func) {
- printk(KERN_WARNING "Parameter %s is obsolete,"
- " ignored\n", p->str);
+ pr_warn("Parameter %s is obsolete, ignored\n",
+ p->str);
return 1;
} else if (p->setup_func(line + n))
return 1;
@@ -384,7 +386,7 @@ static noinline void __init_refok rest_init(void)
init_idle_bootup_task(current);
schedule_preempt_disabled();
/* Call into cpu_idle with preempt disabled */
- cpu_idle();
+ cpu_startup_entry(CPUHP_ONLINE);
}
/* Check for early params. */
@@ -398,8 +400,7 @@ static int __init do_early_param(char *param, char *val, const char *unused)
strcmp(p->str, "earlycon") == 0)
) {
if (p->setup_func(val) != 0)
- printk(KERN_WARNING
- "Malformed early option '%s'\n", param);
+ pr_warn("Malformed early option '%s'\n", param);
}
}
/* We accept everything at this stage. */
@@ -494,10 +495,9 @@ asmlinkage void __init start_kernel(void)
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
- tick_init();
boot_cpu_init();
page_address_init();
- printk(KERN_NOTICE "%s", linux_banner);
+ pr_notice("%s", linux_banner);
setup_arch(&command_line);
mm_init_owner(&init_mm, &init_task);
mm_init_cpumask(&init_mm);
@@ -509,7 +509,7 @@ asmlinkage void __init start_kernel(void)
build_all_zonelists(NULL, NULL);
page_alloc_init();
- printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
+ pr_notice("Kernel command line: %s\n", boot_command_line);
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
@@ -539,11 +539,8 @@ asmlinkage void __init start_kernel(void)
* fragile until we cpu_idle() for the first time.
*/
preempt_disable();
- if (!irqs_disabled()) {
- printk(KERN_WARNING "start_kernel(): bug: interrupts were "
- "enabled *very* early, fixing it\n");
+ if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
local_irq_disable();
- }
idr_init_cache();
perf_event_init();
rcu_init();
@@ -551,6 +548,7 @@ asmlinkage void __init start_kernel(void)
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
+ tick_init();
init_timers();
hrtimers_init();
softirq_init();
@@ -558,9 +556,7 @@ asmlinkage void __init start_kernel(void)
time_init();
profile_init();
call_function_init();
- if (!irqs_disabled())
- printk(KERN_CRIT "start_kernel(): bug: interrupts were "
- "enabled early\n");
+ WARN(!irqs_disabled(), "Interrupts were enabled early\n");
early_boot_irqs_disabled = false;
local_irq_enable();
@@ -587,8 +583,7 @@ asmlinkage void __init start_kernel(void)
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
- printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
- "disabling it.\n",
+ pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = 0;
@@ -667,14 +662,14 @@ static int __init_or_module do_one_initcall_debug(initcall_t fn)
unsigned long long duration;
int ret;
- printk(KERN_DEBUG "calling %pF @ %i\n", fn, task_pid_nr(current));
+ pr_debug("calling %pF @ %i\n", fn, task_pid_nr(current));
calltime = ktime_get();
ret = fn();
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
- printk(KERN_DEBUG "initcall %pF returned %d after %lld usecs\n", fn,
- ret, duration);
+ pr_debug("initcall %pF returned %d after %lld usecs\n",
+ fn, ret, duration);
return ret;
}
@@ -691,20 +686,15 @@ int __init_or_module do_one_initcall(initcall_t fn)
msgbuf[0] = 0;
- if (ret && ret != -ENODEV && initcall_debug)
- sprintf(msgbuf, "error code %d ", ret);
-
if (preempt_count() != count) {
- strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));
+ sprintf(msgbuf, "preemption imbalance ");
preempt_count() = count;
}
if (irqs_disabled()) {
strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
local_irq_enable();
}
- if (msgbuf[0]) {
- printk("initcall %pF returned with %s\n", fn, msgbuf);
- }
+ WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf);
return ret;
}
@@ -832,8 +822,7 @@ static int __ref kernel_init(void *unused)
if (ramdisk_execute_command) {
if (!run_init_process(ramdisk_execute_command))
return 0;
- printk(KERN_WARNING "Failed to execute %s\n",
- ramdisk_execute_command);
+ pr_err("Failed to execute %s\n", ramdisk_execute_command);
}
/*
@@ -845,8 +834,8 @@ static int __ref kernel_init(void *unused)
if (execute_command) {
if (!run_init_process(execute_command))
return 0;
- printk(KERN_WARNING "Failed to execute %s. Attempting "
- "defaults...\n", execute_command);
+ pr_err("Failed to execute %s. Attempting defaults...\n",
+ execute_command);
}
if (!run_init_process("/sbin/init") ||
!run_init_process("/etc/init") ||
@@ -891,7 +880,7 @@ static noinline void __init kernel_init_freeable(void)
/* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
- printk(KERN_WARNING "Warning: unable to open an initial console.\n");
+ pr_err("Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
diff --git a/ipc/compat.c b/ipc/compat.c
index 2547f29dcd1b..892f6585dd60 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -240,7 +240,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s,
static long do_compat_semctl(int first, int second, int third, u32 pad)
{
- union semun fourth;
+ unsigned long fourth;
int err, err2;
struct semid64_ds s64;
struct semid64_ds __user *up64;
@@ -249,9 +249,13 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
memset(&s64, 0, sizeof(s64));
if ((third & (~IPC_64)) == SETVAL)
- fourth.val = (int) pad;
+#ifdef __BIG_ENDIAN
+ fourth = (unsigned long)pad << 32;
+#else
+ fourth = pad;
+#endif
else
- fourth.__pad = compat_ptr(pad);
+ fourth = (unsigned long)compat_ptr(pad);
switch (third & (~IPC_64)) {
case IPC_INFO:
case IPC_RMID:
@@ -269,7 +273,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
case IPC_STAT:
case SEM_STAT:
up64 = compat_alloc_user_space(sizeof(s64));
- fourth.__pad = up64;
+ fourth = (unsigned long)up64;
err = sys_semctl(first, second, third, fourth);
if (err < 0)
break;
@@ -295,7 +299,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
if (err)
break;
- fourth.__pad = up64;
+ fourth = (unsigned long)up64;
err = sys_semctl(first, second, third, fourth);
break;
@@ -306,7 +310,7 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
return err;
}
-long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
+static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
{
struct compat_msgbuf __user *msgp = dest;
size_t msgsz;
@@ -320,77 +324,117 @@ long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
return msgsz;
}
+#ifndef COMPAT_SHMLBA
+#define COMPAT_SHMLBA SHMLBA
+#endif
+
#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
-long compat_sys_semctl(int first, int second, int third, void __user *uptr)
+COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
+ u32, third, compat_uptr_t, ptr, u32, fifth)
{
+ int version;
u32 pad;
- if (!uptr)
- return -EINVAL;
- if (get_user(pad, (u32 __user *) uptr))
- return -EFAULT;
- return do_compat_semctl(first, second, third, pad);
-}
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ switch (call) {
+ case SEMOP:
+ /* struct sembuf is the same on 32 and 64bit :)) */
+ return sys_semtimedop(first, compat_ptr(ptr), second, NULL);
+ case SEMTIMEDOP:
+ return compat_sys_semtimedop(first, compat_ptr(ptr), second,
+ compat_ptr(fifth));
+ case SEMGET:
+ return sys_semget(first, second, third);
+ case SEMCTL:
+ if (!ptr)
+ return -EINVAL;
+ if (get_user(pad, (u32 __user *) compat_ptr(ptr)))
+ return -EFAULT;
+ return do_compat_semctl(first, second, third, pad);
-long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
-{
- struct compat_msgbuf __user *up = uptr;
- long type;
+ case MSGSND: {
+ struct compat_msgbuf __user *up = compat_ptr(ptr);
+ compat_long_t type;
- if (first < 0)
- return -EINVAL;
- if (second < 0)
- return -EINVAL;
+ if (first < 0 || second < 0)
+ return -EINVAL;
- if (get_user(type, &up->mtype))
- return -EFAULT;
+ if (get_user(type, &up->mtype))
+ return -EFAULT;
- return do_msgsnd(first, type, up->mtext, second, third);
-}
+ return do_msgsnd(first, type, up->mtext, second, third);
+ }
+ case MSGRCV: {
+ void __user *uptr = compat_ptr(ptr);
-long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
- int version, void __user *uptr)
-{
- if (first < 0)
- return -EINVAL;
- if (second < 0)
- return -EINVAL;
-
- if (!version) {
- struct compat_ipc_kludge ipck;
- if (!uptr)
+ if (first < 0 || second < 0)
return -EINVAL;
- if (copy_from_user (&ipck, uptr, sizeof(ipck)))
- return -EFAULT;
- uptr = compat_ptr(ipck.msgp);
- msgtyp = ipck.msgtyp;
+
+ if (!version) {
+ struct compat_ipc_kludge ipck;
+ if (!uptr)
+ return -EINVAL;
+ if (copy_from_user (&ipck, uptr, sizeof(ipck)))
+ return -EFAULT;
+ uptr = compat_ptr(ipck.msgp);
+ fifth = ipck.msgtyp;
+ }
+ return do_msgrcv(first, uptr, second, fifth, third,
+ compat_do_msg_fill);
}
- return do_msgrcv(first, uptr, second, msgtyp, third,
- compat_do_msg_fill);
+ case MSGGET:
+ return sys_msgget(first, second);
+ case MSGCTL:
+ return compat_sys_msgctl(first, second, compat_ptr(ptr));
+
+ case SHMAT: {
+ int err;
+ unsigned long raddr;
+
+ if (version == 1)
+ return -EINVAL;
+ err = do_shmat(first, compat_ptr(ptr), second, &raddr,
+ COMPAT_SHMLBA);
+ if (err < 0)
+ return err;
+ return put_user(raddr, (compat_ulong_t *)compat_ptr(third));
+ }
+ case SHMDT:
+ return sys_shmdt(compat_ptr(ptr));
+ case SHMGET:
+ return sys_shmget(first, (unsigned)second, third);
+ case SHMCTL:
+ return compat_sys_shmctl(first, second, compat_ptr(ptr));
+ }
+
+ return -ENOSYS;
}
-#else
-long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
+#endif
+
+COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg)
{
return do_compat_semctl(semid, semnum, cmd, arg);
}
-long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
- compat_ssize_t msgsz, int msgflg)
+COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp,
+ compat_ssize_t, msgsz, int, msgflg)
{
+ struct compat_msgbuf __user *up = compat_ptr(msgp);
compat_long_t mtype;
- if (get_user(mtype, &msgp->mtype))
+ if (get_user(mtype, &up->mtype))
return -EFAULT;
- return do_msgsnd(msqid, mtype, msgp->mtext, (ssize_t)msgsz, msgflg);
+ return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg);
}
-long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
- compat_ssize_t msgsz, long msgtyp, int msgflg)
+COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp,
+ compat_ssize_t, msgsz, long, msgtyp, int, msgflg)
{
- return do_msgrcv(msqid, msgp, (ssize_t)msgsz, msgtyp, msgflg,
- compat_do_msg_fill);
+ return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, msgtyp,
+ msgflg, compat_do_msg_fill);
}
-#endif
static inline int get_compat_msqid64(struct msqid64_ds *m64,
struct compat_msqid64_ds __user *up64)
@@ -508,28 +552,7 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
return err;
}
-#ifndef COMPAT_SHMLBA
-#define COMPAT_SHMLBA SHMLBA
-#endif
-
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
-long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
- void __user *uptr)
-{
- int err;
- unsigned long raddr;
- compat_ulong_t __user *uaddr;
-
- if (version == 1)
- return -EINVAL;
- err = do_shmat(first, uptr, second, &raddr, COMPAT_SHMLBA);
- if (err < 0)
- return err;
- uaddr = compat_ptr(third);
- return put_user(raddr, uaddr);
-}
-#else
-long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
+COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
{
unsigned long ret;
long err;
@@ -540,7 +563,6 @@ long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
force_successful_syscall_return();
return (long)ret;
}
-#endif
static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
struct compat_shmid64_ds __user *up64)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 3953fda2e8bd..e4e47f647446 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -330,8 +330,16 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
{
- if (!(flags & MS_KERNMOUNT))
- data = current->nsproxy->ipc_ns;
+ if (!(flags & MS_KERNMOUNT)) {
+ struct ipc_namespace *ns = current->nsproxy->ipc_ns;
+ /* Don't allow mounting unless the caller has CAP_SYS_ADMIN
+ * over the ipc namespace.
+ */
+ if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+ return ERR_PTR(-EPERM);
+
+ data = ns;
+ }
return mount_ns(fs_type, flags, data, mqueue_fill_super);
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 31cd1bf6af27..d0c6d967b390 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -66,6 +66,7 @@ struct msg_sender {
#define SEARCH_EQUAL 2
#define SEARCH_NOTEQUAL 3
#define SEARCH_LESSEQUAL 4
+#define SEARCH_NUMBER 5
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
@@ -237,14 +238,9 @@ static inline void ss_del(struct msg_sender *mss)
static void ss_wakeup(struct list_head *h, int kill)
{
- struct list_head *tmp;
+ struct msg_sender *mss, *t;
- tmp = h->next;
- while (tmp != h) {
- struct msg_sender *mss;
-
- mss = list_entry(tmp, struct msg_sender, list);
- tmp = tmp->next;
+ list_for_each_entry_safe(mss, t, h, list) {
if (kill)
mss->list.next = NULL;
wake_up_process(mss->tsk);
@@ -253,14 +249,9 @@ static void ss_wakeup(struct list_head *h, int kill)
static void expunge_all(struct msg_queue *msq, int res)
{
- struct list_head *tmp;
-
- tmp = msq->q_receivers.next;
- while (tmp != &msq->q_receivers) {
- struct msg_receiver *msr;
+ struct msg_receiver *msr, *t;
- msr = list_entry(tmp, struct msg_receiver, r_list);
- tmp = tmp->next;
+ list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
msr->r_msg = NULL;
wake_up_process(msr->r_tsk);
smp_mb();
@@ -278,7 +269,7 @@ static void expunge_all(struct msg_queue *msq, int res)
*/
static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
{
- struct list_head *tmp;
+ struct msg_msg *msg, *t;
struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
expunge_all(msq, -EIDRM);
@@ -286,11 +277,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
msg_rmid(ns, msq);
msg_unlock(msq);
- tmp = msq->q_messages.next;
- while (tmp != &msq->q_messages) {
- struct msg_msg *msg = list_entry(tmp, struct msg_msg, m_list);
-
- tmp = tmp->next;
+ list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
atomic_dec(&ns->msg_hdrs);
free_msg(msg);
}
@@ -583,6 +570,7 @@ static int testmsg(struct msg_msg *msg, long type, int mode)
switch(mode)
{
case SEARCH_ANY:
+ case SEARCH_NUMBER:
return 1;
case SEARCH_LESSEQUAL:
if (msg->m_type <=type)
@@ -602,14 +590,9 @@ static int testmsg(struct msg_msg *msg, long type, int mode)
static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
{
- struct list_head *tmp;
+ struct msg_receiver *msr, *t;
- tmp = msq->q_receivers.next;
- while (tmp != &msq->q_receivers) {
- struct msg_receiver *msr;
-
- msr = list_entry(tmp, struct msg_receiver, r_list);
- tmp = tmp->next;
+ list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
!security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
msr->r_msgtype, msr->r_mode)) {
@@ -685,7 +668,12 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
goto out_unlock_free;
}
ss_add(msq, &s);
- ipc_rcu_getref(msq);
+
+ if (!ipc_rcu_getref(msq)) {
+ err = -EIDRM;
+ goto out_unlock_free;
+ }
+
msg_unlock(msq);
schedule();
@@ -738,6 +726,8 @@ SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
static inline int convert_mode(long *msgtyp, int msgflg)
{
+ if (msgflg & MSG_COPY)
+ return SEARCH_NUMBER;
/*
* find message of correct type.
* msgtyp = 0 => get first.
@@ -774,14 +764,10 @@ static long do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz)
* This function creates new kernel message structure, large enough to store
* bufsz message bytes.
*/
-static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
- int msgflg, long *msgtyp,
- unsigned long *copy_number)
+static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
{
struct msg_msg *copy;
- *copy_number = *msgtyp;
- *msgtyp = 0;
/*
* Create dummy message to copy real message to.
*/
@@ -797,9 +783,7 @@ static inline void free_copy(struct msg_msg *copy)
free_msg(copy);
}
#else
-static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz,
- int msgflg, long *msgtyp,
- unsigned long *copy_number)
+static inline struct msg_msg *prepare_copy(void __user *buf, size_t bufsz)
{
return ERR_PTR(-ENOSYS);
}
@@ -809,6 +793,30 @@ static inline void free_copy(struct msg_msg *copy)
}
#endif
+static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
+{
+ struct msg_msg *msg;
+ long count = 0;
+
+ list_for_each_entry(msg, &msq->q_messages, m_list) {
+ if (testmsg(msg, *msgtyp, mode) &&
+ !security_msg_queue_msgrcv(msq, msg, current,
+ *msgtyp, mode)) {
+ if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {
+ *msgtyp = msg->m_type - 1;
+ } else if (mode == SEARCH_NUMBER) {
+ if (*msgtyp == count)
+ return msg;
+ } else
+ return msg;
+ count++;
+ }
+ }
+
+ return ERR_PTR(-EAGAIN);
+}
+
+
long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
int msgflg,
long (*msg_handler)(void __user *, struct msg_msg *, size_t))
@@ -818,15 +826,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
int mode;
struct ipc_namespace *ns;
struct msg_msg *copy = NULL;
- unsigned long copy_number = 0;
ns = current->nsproxy->ipc_ns;
if (msqid < 0 || (long) bufsz < 0)
return -EINVAL;
if (msgflg & MSG_COPY) {
- copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax),
- msgflg, &msgtyp, &copy_number);
+ copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
if (IS_ERR(copy))
return PTR_ERR(copy);
}
@@ -840,44 +846,13 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
for (;;) {
struct msg_receiver msr_d;
- struct list_head *tmp;
- long msg_counter = 0;
msg = ERR_PTR(-EACCES);
if (ipcperms(ns, &msq->q_perm, S_IRUGO))
goto out_unlock;
- msg = ERR_PTR(-EAGAIN);
- tmp = msq->q_messages.next;
- while (tmp != &msq->q_messages) {
- struct msg_msg *walk_msg;
-
- walk_msg = list_entry(tmp, struct msg_msg, m_list);
- if (testmsg(walk_msg, msgtyp, mode) &&
- !security_msg_queue_msgrcv(msq, walk_msg, current,
- msgtyp, mode)) {
-
- msg = walk_msg;
- if (mode == SEARCH_LESSEQUAL &&
- walk_msg->m_type != 1) {
- msgtyp = walk_msg->m_type - 1;
- } else if (msgflg & MSG_COPY) {
- if (copy_number == msg_counter) {
- /*
- * Found requested message.
- * Copy it.
- */
- msg = copy_msg(msg, copy);
- if (IS_ERR(msg))
- goto out_unlock;
- break;
- }
- } else
- break;
- msg_counter++;
- }
- tmp = tmp->next;
- }
+ msg = find_msg(msq, &msgtyp, mode);
+
if (!IS_ERR(msg)) {
/*
* Found a suitable message.
@@ -891,8 +866,10 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
* If we are copying, then do not unlink message and do
* not update queue parameters.
*/
- if (msgflg & MSG_COPY)
+ if (msgflg & MSG_COPY) {
+ msg = copy_msg(msg, copy);
goto out_unlock;
+ }
list_del(&msg->m_list);
msq->q_qnum--;
msq->q_rtime = get_seconds();
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 8f0201735f16..491e71f2a1b8 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -17,7 +17,7 @@
#include <linux/ipc_namespace.h>
#include <linux/utsname.h>
#include <linux/proc_ns.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "util.h"
@@ -37,59 +37,70 @@ struct ipc_namespace init_ipc_ns = {
atomic_t nr_ipc_ns = ATOMIC_INIT(1);
struct msg_msgseg {
- struct msg_msgseg* next;
+ struct msg_msgseg *next;
/* the next part of the message follows immediately */
};
-#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
-#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
+#define DATALEN_MSG (int)(PAGE_SIZE-sizeof(struct msg_msg))
+#define DATALEN_SEG (int)(PAGE_SIZE-sizeof(struct msg_msgseg))
-struct msg_msg *load_msg(const void __user *src, int len)
+
+static struct msg_msg *alloc_msg(int len)
{
struct msg_msg *msg;
struct msg_msgseg **pseg;
- int err;
int alen;
- alen = len;
- if (alen > DATALEN_MSG)
- alen = DATALEN_MSG;
-
+ alen = min(len, DATALEN_MSG);
msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
if (msg == NULL)
- return ERR_PTR(-ENOMEM);
+ return NULL;
msg->next = NULL;
msg->security = NULL;
- if (copy_from_user(msg + 1, src, alen)) {
- err = -EFAULT;
- goto out_err;
- }
-
len -= alen;
- src = ((char __user *)src) + alen;
pseg = &msg->next;
while (len > 0) {
struct msg_msgseg *seg;
- alen = len;
- if (alen > DATALEN_SEG)
- alen = DATALEN_SEG;
- seg = kmalloc(sizeof(*seg) + alen,
- GFP_KERNEL);
- if (seg == NULL) {
- err = -ENOMEM;
+ alen = min(len, DATALEN_SEG);
+ seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
+ if (seg == NULL)
goto out_err;
- }
*pseg = seg;
seg->next = NULL;
- if (copy_from_user(seg + 1, src, alen)) {
- err = -EFAULT;
- goto out_err;
- }
pseg = &seg->next;
len -= alen;
- src = ((char __user *)src) + alen;
+ }
+
+ return msg;
+
+out_err:
+ free_msg(msg);
+ return NULL;
+}
+
+struct msg_msg *load_msg(const void __user *src, int len)
+{
+ struct msg_msg *msg;
+ struct msg_msgseg *seg;
+ int err = -EFAULT;
+ int alen;
+
+ msg = alloc_msg(len);
+ if (msg == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ alen = min(len, DATALEN_MSG);
+ if (copy_from_user(msg + 1, src, alen))
+ goto out_err;
+
+ for (seg = msg->next; seg != NULL; seg = seg->next) {
+ len -= alen;
+ src = (char __user *)src + alen;
+ alen = min(len, DATALEN_SEG);
+ if (copy_from_user(seg + 1, src, alen))
+ goto out_err;
}
err = security_msg_msg_alloc(msg);
@@ -113,23 +124,16 @@ struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
if (src->m_ts > dst->m_ts)
return ERR_PTR(-EINVAL);
- alen = len;
- if (alen > DATALEN_MSG)
- alen = DATALEN_MSG;
-
+ alen = min(len, DATALEN_MSG);
memcpy(dst + 1, src + 1, alen);
- len -= alen;
- dst_pseg = dst->next;
- src_pseg = src->next;
- while (len > 0) {
- alen = len;
- if (alen > DATALEN_SEG)
- alen = DATALEN_SEG;
- memcpy(dst_pseg + 1, src_pseg + 1, alen);
- dst_pseg = dst_pseg->next;
+ for (dst_pseg = dst->next, src_pseg = src->next;
+ src_pseg != NULL;
+ dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
+
len -= alen;
- src_pseg = src_pseg->next;
+ alen = min(len, DATALEN_SEG);
+ memcpy(dst_pseg + 1, src_pseg + 1, alen);
}
dst->m_type = src->m_type;
@@ -148,24 +152,16 @@ int store_msg(void __user *dest, struct msg_msg *msg, int len)
int alen;
struct msg_msgseg *seg;
- alen = len;
- if (alen > DATALEN_MSG)
- alen = DATALEN_MSG;
+ alen = min(len, DATALEN_MSG);
if (copy_to_user(dest, msg + 1, alen))
return -1;
- len -= alen;
- dest = ((char __user *)dest) + alen;
- seg = msg->next;
- while (len > 0) {
- alen = len;
- if (alen > DATALEN_SEG)
- alen = DATALEN_SEG;
+ for (seg = msg->next; seg != NULL; seg = seg->next) {
+ len -= alen;
+ dest = (char __user *)dest + alen;
+ alen = min(len, DATALEN_SEG);
if (copy_to_user(dest, seg + 1, alen))
return -1;
- len -= alen;
- dest = ((char __user *)dest) + alen;
- seg = seg->next;
}
return 0;
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 58d31f1c1eb5..e78ee3186d1f 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -94,12 +94,12 @@
struct sem {
int semval; /* current value */
int sempid; /* pid of last operation */
+ spinlock_t lock; /* spinlock for fine-grained semtimedop */
struct list_head sem_pending; /* pending single-sop operations */
};
/* One queue for each sleeping process in the system. */
struct sem_queue {
- struct list_head simple_list; /* queue of pending operations */
struct list_head list; /* queue of pending operations */
struct task_struct *sleeper; /* this process */
struct sem_undo *undo; /* undo structure */
@@ -138,7 +138,6 @@ struct sem_undo_list {
#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])
-#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)
static int newary(struct ipc_namespace *, struct ipc_params *);
@@ -191,47 +190,164 @@ void __init sem_init (void)
}
/*
+ * If the request contains only one semaphore operation, and there are
+ * no complex transactions pending, lock only the semaphore involved.
+ * Otherwise, lock the entire semaphore array, since we either have
+ * multiple semaphores in our own semops, or we need to look at
+ * semaphores from other pending complex operations.
+ *
+ * Carefully guard against sma->complex_count changing between zero
+ * and non-zero while we are spinning for the lock. The value of
+ * sma->complex_count cannot change while we are holding the lock,
+ * so sem_unlock should be fine.
+ *
+ * The global lock path checks that all the local locks have been released,
+ * checking each local lock once. This means that the local lock paths
+ * cannot start their critical sections while the global lock is held.
+ */
+static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
+ int nsops)
+{
+ int locknum;
+ again:
+ if (nsops == 1 && !sma->complex_count) {
+ struct sem *sem = sma->sem_base + sops->sem_num;
+
+ /* Lock just the semaphore we are interested in. */
+ spin_lock(&sem->lock);
+
+ /*
+ * If sma->complex_count was set while we were spinning,
+ * we may need to look at things we did not lock here.
+ */
+ if (unlikely(sma->complex_count)) {
+ spin_unlock(&sem->lock);
+ goto lock_array;
+ }
+
+ /*
+ * Another process is holding the global lock on the
+ * sem_array; we cannot enter our critical section,
+ * but have to wait for the global lock to be released.
+ */
+ if (unlikely(spin_is_locked(&sma->sem_perm.lock))) {
+ spin_unlock(&sem->lock);
+ spin_unlock_wait(&sma->sem_perm.lock);
+ goto again;
+ }
+
+ locknum = sops->sem_num;
+ } else {
+ int i;
+ /*
+ * Lock the semaphore array, and wait for all of the
+ * individual semaphore locks to go away. The code
+ * above ensures no new single-lock holders will enter
+ * their critical section while the array lock is held.
+ */
+ lock_array:
+ spin_lock(&sma->sem_perm.lock);
+ for (i = 0; i < sma->sem_nsems; i++) {
+ struct sem *sem = sma->sem_base + i;
+ spin_unlock_wait(&sem->lock);
+ }
+ locknum = -1;
+ }
+ return locknum;
+}
+
+static inline void sem_unlock(struct sem_array *sma, int locknum)
+{
+ if (locknum == -1) {
+ spin_unlock(&sma->sem_perm.lock);
+ } else {
+ struct sem *sem = sma->sem_base + locknum;
+ spin_unlock(&sem->lock);
+ }
+ rcu_read_unlock();
+}
+
+/*
* sem_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
*/
-static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
+static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns,
+ int id, struct sembuf *sops, int nsops, int *locknum)
+{
+ struct kern_ipc_perm *ipcp;
+ struct sem_array *sma;
+
+ rcu_read_lock();
+ ipcp = ipc_obtain_object(&sem_ids(ns), id);
+ if (IS_ERR(ipcp)) {
+ sma = ERR_CAST(ipcp);
+ goto err;
+ }
+
+ sma = container_of(ipcp, struct sem_array, sem_perm);
+ *locknum = sem_lock(sma, sops, nsops);
+
+ /* ipc_rmid() may have already freed the ID while sem_lock
+ * was spinning: verify that the structure is still valid
+ */
+ if (!ipcp->deleted)
+ return container_of(ipcp, struct sem_array, sem_perm);
+
+ sem_unlock(sma, *locknum);
+ sma = ERR_PTR(-EINVAL);
+err:
+ rcu_read_unlock();
+ return sma;
+}
+
+static inline struct sem_array *sem_obtain_object(struct ipc_namespace *ns, int id)
{
- struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_obtain_object(&sem_ids(ns), id);
if (IS_ERR(ipcp))
- return (struct sem_array *)ipcp;
+ return ERR_CAST(ipcp);
return container_of(ipcp, struct sem_array, sem_perm);
}
-static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
- int id)
+static inline struct sem_array *sem_obtain_object_check(struct ipc_namespace *ns,
+ int id)
{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
+ struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&sem_ids(ns), id);
if (IS_ERR(ipcp))
- return (struct sem_array *)ipcp;
+ return ERR_CAST(ipcp);
return container_of(ipcp, struct sem_array, sem_perm);
}
static inline void sem_lock_and_putref(struct sem_array *sma)
{
- ipc_lock_by_ptr(&sma->sem_perm);
+ rcu_read_lock();
+ sem_lock(sma, NULL, -1);
ipc_rcu_putref(sma);
}
static inline void sem_getref_and_unlock(struct sem_array *sma)
{
- ipc_rcu_getref(sma);
- ipc_unlock(&(sma)->sem_perm);
+ WARN_ON_ONCE(!ipc_rcu_getref(sma));
+ sem_unlock(sma, -1);
}
static inline void sem_putref(struct sem_array *sma)
{
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- ipc_unlock(&(sma)->sem_perm);
+ sem_lock_and_putref(sma);
+ sem_unlock(sma, -1);
+}
+
+/*
+ * Call inside the rcu read section.
+ */
+static inline void sem_getref(struct sem_array *sma)
+{
+ sem_lock(sma, NULL, -1);
+ WARN_ON_ONCE(!ipc_rcu_getref(sma));
+ sem_unlock(sma, -1);
}
static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
@@ -324,15 +440,17 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
sma->sem_base = (struct sem *) &sma[1];
- for (i = 0; i < nsems; i++)
+ for (i = 0; i < nsems; i++) {
INIT_LIST_HEAD(&sma->sem_base[i].sem_pending);
+ spin_lock_init(&sma->sem_base[i].lock);
+ }
sma->complex_count = 0;
INIT_LIST_HEAD(&sma->sem_pending);
INIT_LIST_HEAD(&sma->list_id);
sma->sem_nsems = nsems;
sma->sem_ctime = get_seconds();
- sem_unlock(sma);
+ sem_unlock(sma, -1);
return sma->sem_perm.id;
}
@@ -471,7 +589,7 @@ static void wake_up_sem_queue_prepare(struct list_head *pt,
q->status = IN_WAKEUP;
q->pid = error;
- list_add_tail(&q->simple_list, pt);
+ list_add_tail(&q->list, pt);
}
/**
@@ -489,7 +607,7 @@ static void wake_up_sem_queue_do(struct list_head *pt)
int did_something;
did_something = !list_empty(pt);
- list_for_each_entry_safe(q, t, pt, simple_list) {
+ list_for_each_entry_safe(q, t, pt, list) {
wake_up_process(q->sleeper);
/* q can disappear immediately after writing q->status. */
smp_wmb();
@@ -502,9 +620,7 @@ static void wake_up_sem_queue_do(struct list_head *pt)
static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
{
list_del(&q->list);
- if (q->nsops == 1)
- list_del(&q->simple_list);
- else
+ if (q->nsops > 1)
sma->complex_count--;
}
@@ -557,9 +673,9 @@ static int check_restart(struct sem_array *sma, struct sem_queue *q)
}
/*
* semval is 0. Check if there are wait-for-zero semops.
- * They must be the first entries in the per-semaphore simple queue
+ * They must be the first entries in the per-semaphore queue
*/
- h = list_first_entry(&curr->sem_pending, struct sem_queue, simple_list);
+ h = list_first_entry(&curr->sem_pending, struct sem_queue, list);
BUG_ON(h->nsops != 1);
BUG_ON(h->sops[0].sem_num != q->sops[0].sem_num);
@@ -579,8 +695,9 @@ static int check_restart(struct sem_array *sma, struct sem_queue *q)
* @pt: list head for the tasks that must be woken up.
*
* update_queue must be called after a semaphore in a semaphore array
- * was modified. If multiple semaphore were modified, then @semnum
- * must be set to -1.
+ * was modified. If multiple semaphores were modified, update_queue must
+ * be called with semnum = -1, as well as with the number of each modified
+ * semaphore.
* The tasks that must be woken up are added to @pt. The return code
* is stored in q->pid.
* The function return 1 if at least one semop was completed successfully.
@@ -590,30 +707,19 @@ static int update_queue(struct sem_array *sma, int semnum, struct list_head *pt)
struct sem_queue *q;
struct list_head *walk;
struct list_head *pending_list;
- int offset;
int semop_completed = 0;
- /* if there are complex operations around, then knowing the semaphore
- * that was modified doesn't help us. Assume that multiple semaphores
- * were modified.
- */
- if (sma->complex_count)
- semnum = -1;
-
- if (semnum == -1) {
+ if (semnum == -1)
pending_list = &sma->sem_pending;
- offset = offsetof(struct sem_queue, list);
- } else {
+ else
pending_list = &sma->sem_base[semnum].sem_pending;
- offset = offsetof(struct sem_queue, simple_list);
- }
again:
walk = pending_list->next;
while (walk != pending_list) {
int error, restart;
- q = (struct sem_queue *)((char *)walk - offset);
+ q = container_of(walk, struct sem_queue, list);
walk = walk->next;
/* If we are scanning the single sop, per-semaphore list of
@@ -672,9 +778,18 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
if (sma->complex_count || sops == NULL) {
if (update_queue(sma, -1, pt))
otime = 1;
+ }
+
+ if (!sops) {
+ /* No semops; something special is going on. */
+ for (i = 0; i < sma->sem_nsems; i++) {
+ if (update_queue(sma, i, pt))
+ otime = 1;
+ }
goto done;
}
+ /* Check the semaphores that were modified. */
for (i = 0; i < nsops; i++) {
if (sops[i].sem_op > 0 ||
(sops[i].sem_op < 0 &&
@@ -745,6 +860,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
struct sem_queue *q, *tq;
struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
struct list_head tasks;
+ int i;
/* Free the existing undo structures for this semaphore set. */
assert_spin_locked(&sma->sem_perm.lock);
@@ -763,10 +879,17 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
unlink_queue(sma, q);
wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
}
+ for (i = 0; i < sma->sem_nsems; i++) {
+ struct sem *sem = sma->sem_base + i;
+ list_for_each_entry_safe(q, tq, &sem->sem_pending, list) {
+ unlink_queue(sma, q);
+ wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
+ }
+ }
/* Remove the semaphore set from the IDR */
sem_rmid(ns, sma);
- sem_unlock(sma);
+ sem_unlock(sma, -1);
wake_up_sem_queue_do(&tasks);
ns->used_sems -= sma->sem_nsems;
@@ -799,7 +922,7 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
}
static int semctl_nolock(struct ipc_namespace *ns, int semid,
- int cmd, int version, union semun arg)
+ int cmd, int version, void __user *p)
{
int err;
struct sem_array *sma;
@@ -834,7 +957,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
}
max_id = ipc_get_maxid(&sem_ids(ns));
up_read(&sem_ids(ns).rw_mutex);
- if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
+ if (copy_to_user(p, &seminfo, sizeof(struct seminfo)))
return -EFAULT;
return (max_id < 0) ? 0: max_id;
}
@@ -842,18 +965,25 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
case SEM_STAT:
{
struct semid64_ds tbuf;
- int id;
+ int id = 0;
+
+ memset(&tbuf, 0, sizeof(tbuf));
if (cmd == SEM_STAT) {
- sma = sem_lock(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
+ rcu_read_lock();
+ sma = sem_obtain_object(ns, semid);
+ if (IS_ERR(sma)) {
+ err = PTR_ERR(sma);
+ goto out_unlock;
+ }
id = sma->sem_perm.id;
} else {
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
- id = 0;
+ rcu_read_lock();
+ sma = sem_obtain_object_check(ns, semid);
+ if (IS_ERR(sma)) {
+ err = PTR_ERR(sma);
+ goto out_unlock;
+ }
}
err = -EACCES;
@@ -864,14 +994,12 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
if (err)
goto out_unlock;
- memset(&tbuf, 0, sizeof(tbuf));
-
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
- sem_unlock(sma);
- if (copy_semid_to_user (arg.buf, &tbuf, version))
+ rcu_read_unlock();
+ if (copy_semid_to_user(p, &tbuf, version))
return -EFAULT;
return id;
}
@@ -879,46 +1007,117 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
return -EINVAL;
}
out_unlock:
- sem_unlock(sma);
+ rcu_read_unlock();
return err;
}
-static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
- int cmd, int version, union semun arg)
+static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
+ unsigned long arg)
{
+ struct sem_undo *un;
struct sem_array *sma;
struct sem* curr;
int err;
+ struct list_head tasks;
+ int val;
+#if defined(CONFIG_64BIT) && defined(__BIG_ENDIAN)
+ /* big-endian 64bit */
+ val = arg >> 32;
+#else
+ /* 32bit or little-endian 64bit */
+ val = arg;
+#endif
+
+ if (val > SEMVMX || val < 0)
+ return -ERANGE;
+
+ INIT_LIST_HEAD(&tasks);
+
+ rcu_read_lock();
+ sma = sem_obtain_object_check(ns, semid);
+ if (IS_ERR(sma)) {
+ rcu_read_unlock();
+ return PTR_ERR(sma);
+ }
+
+ if (semnum < 0 || semnum >= sma->sem_nsems) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+
+ if (ipcperms(ns, &sma->sem_perm, S_IWUGO)) {
+ rcu_read_unlock();
+ return -EACCES;
+ }
+
+ err = security_sem_semctl(sma, SETVAL);
+ if (err) {
+ rcu_read_unlock();
+ return -EACCES;
+ }
+
+ sem_lock(sma, NULL, -1);
+
+ curr = &sma->sem_base[semnum];
+
+ assert_spin_locked(&sma->sem_perm.lock);
+ list_for_each_entry(un, &sma->list_id, list_id)
+ un->semadj[semnum] = 0;
+
+ curr->semval = val;
+ curr->sempid = task_tgid_vnr(current);
+ sma->sem_ctime = get_seconds();
+ /* maybe some queued-up processes were waiting for this */
+ do_smart_update(sma, NULL, 0, 0, &tasks);
+ sem_unlock(sma, -1);
+ wake_up_sem_queue_do(&tasks);
+ return 0;
+}
+
+static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
+ int cmd, void __user *p)
+{
+ struct sem_array *sma;
+ struct sem* curr;
+ int err, nsems;
ushort fast_sem_io[SEMMSL_FAST];
ushort* sem_io = fast_sem_io;
- int nsems;
struct list_head tasks;
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
+ INIT_LIST_HEAD(&tasks);
+
+ rcu_read_lock();
+ sma = sem_obtain_object_check(ns, semid);
+ if (IS_ERR(sma)) {
+ rcu_read_unlock();
return PTR_ERR(sma);
+ }
- INIT_LIST_HEAD(&tasks);
nsems = sma->sem_nsems;
err = -EACCES;
if (ipcperms(ns, &sma->sem_perm,
- (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
- goto out_unlock;
+ cmd == SETALL ? S_IWUGO : S_IRUGO)) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
err = security_sem_semctl(sma, cmd);
- if (err)
- goto out_unlock;
+ if (err) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
err = -EACCES;
switch (cmd) {
case GETALL:
{
- ushort __user *array = arg.array;
+ ushort __user *array = p;
int i;
if(nsems > SEMMSL_FAST) {
- sem_getref_and_unlock(sma);
+ sem_getref(sma);
sem_io = ipc_alloc(sizeof(ushort)*nsems);
if(sem_io == NULL) {
@@ -928,15 +1127,16 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, -1);
err = -EIDRM;
goto out_free;
}
- }
+ } else
+ sem_lock(sma, NULL, -1);
for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval;
- sem_unlock(sma);
+ sem_unlock(sma, -1);
err = 0;
if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
err = -EFAULT;
@@ -947,7 +1147,11 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
int i;
struct sem_undo *un;
- sem_getref_and_unlock(sma);
+ if (!ipc_rcu_getref(sma)) {
+ rcu_read_unlock();
+ return -EIDRM;
+ }
+ rcu_read_unlock();
if(nsems > SEMMSL_FAST) {
sem_io = ipc_alloc(sizeof(ushort)*nsems);
@@ -957,7 +1161,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
}
}
- if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
+ if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) {
sem_putref(sma);
err = -EFAULT;
goto out_free;
@@ -972,7 +1176,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
}
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, -1);
err = -EIDRM;
goto out_free;
}
@@ -991,12 +1195,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
err = 0;
goto out_unlock;
}
- /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */
+ /* GETVAL, GETPID, GETNCTN, GETZCNT: fall-through */
}
err = -EINVAL;
- if(semnum < 0 || semnum >= nsems)
- goto out_unlock;
+ if (semnum < 0 || semnum >= nsems) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
+ sem_lock(sma, NULL, -1);
curr = &sma->sem_base[semnum];
switch (cmd) {
@@ -1012,32 +1219,12 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
case GETZCNT:
err = count_semzcnt(sma,semnum);
goto out_unlock;
- case SETVAL:
- {
- int val = arg.val;
- struct sem_undo *un;
-
- err = -ERANGE;
- if (val > SEMVMX || val < 0)
- goto out_unlock;
-
- assert_spin_locked(&sma->sem_perm.lock);
- list_for_each_entry(un, &sma->list_id, list_id)
- un->semadj[semnum] = 0;
-
- curr->semval = val;
- curr->sempid = task_tgid_vnr(current);
- sma->sem_ctime = get_seconds();
- /* maybe some queued-up processes were waiting for this */
- do_smart_update(sma, NULL, 0, 0, &tasks);
- err = 0;
- goto out_unlock;
- }
}
+
out_unlock:
- sem_unlock(sma);
+ sem_unlock(sma, -1);
+out_wakeup:
wake_up_sem_queue_do(&tasks);
-
out_free:
if(sem_io != fast_sem_io)
ipc_free(sem_io, sizeof(ushort)*nsems);
@@ -1076,7 +1263,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
* NOTE: no locks must be held, the rw_mutex is taken inside this function.
*/
static int semctl_down(struct ipc_namespace *ns, int semid,
- int cmd, int version, union semun arg)
+ int cmd, int version, void __user *p)
{
struct sem_array *sma;
int err;
@@ -1084,47 +1271,53 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
struct kern_ipc_perm *ipcp;
if(cmd == IPC_SET) {
- if (copy_semid_from_user(&semid64, arg.buf, version))
+ if (copy_semid_from_user(&semid64, p, version))
return -EFAULT;
}
- ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
- &semid64.sem_perm, 0);
+ ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
+ &semid64.sem_perm, 0);
if (IS_ERR(ipcp))
return PTR_ERR(ipcp);
sma = container_of(ipcp, struct sem_array, sem_perm);
err = security_sem_semctl(sma, cmd);
- if (err)
+ if (err) {
+ rcu_read_unlock();
goto out_unlock;
+ }
switch(cmd){
case IPC_RMID:
+ sem_lock(sma, NULL, -1);
freeary(ns, ipcp);
goto out_up;
case IPC_SET:
+ sem_lock(sma, NULL, -1);
err = ipc_update_perm(&semid64.sem_perm, ipcp);
if (err)
goto out_unlock;
sma->sem_ctime = get_seconds();
break;
default:
+ rcu_read_unlock();
err = -EINVAL;
+ goto out_up;
}
out_unlock:
- sem_unlock(sma);
+ sem_unlock(sma, -1);
out_up:
up_write(&sem_ids(ns).rw_mutex);
return err;
}
-SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)
+SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
{
- int err = -EINVAL;
int version;
struct ipc_namespace *ns;
+ void __user *p = (void __user *)arg;
if (semid < 0)
return -EINVAL;
@@ -1137,32 +1330,23 @@ SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)
case SEM_INFO:
case IPC_STAT:
case SEM_STAT:
- err = semctl_nolock(ns, semid, cmd, version, arg);
- return err;
+ return semctl_nolock(ns, semid, cmd, version, p);
case GETALL:
case GETVAL:
case GETPID:
case GETNCNT:
case GETZCNT:
- case SETVAL:
case SETALL:
- err = semctl_main(ns,semid,semnum,cmd,version,arg);
- return err;
+ return semctl_main(ns, semid, semnum, cmd, p);
+ case SETVAL:
+ return semctl_setval(ns, semid, semnum, arg);
case IPC_RMID:
case IPC_SET:
- err = semctl_down(ns, semid, cmd, version, arg);
- return err;
+ return semctl_down(ns, semid, cmd, version, p);
default:
return -EINVAL;
}
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg)
-{
- return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg);
-}
-SYSCALL_ALIAS(sys_semctl, SyS_semctl);
-#endif
/* If the task doesn't already have a undo_list, then allocate one
* here. We guarantee there is only one thread using this undo list,
@@ -1235,8 +1419,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
struct sem_array *sma;
struct sem_undo_list *ulp;
struct sem_undo *un, *new;
- int nsems;
- int error;
+ int nsems, error;
error = get_undo_list(&ulp);
if (error)
@@ -1248,16 +1431,22 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
spin_unlock(&ulp->lock);
if (likely(un!=NULL))
goto out;
- rcu_read_unlock();
/* no undo structure around - allocate one. */
/* step 1: figure out the size of the semaphore array */
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
+ sma = sem_obtain_object_check(ns, semid);
+ if (IS_ERR(sma)) {
+ rcu_read_unlock();
return ERR_CAST(sma);
+ }
nsems = sma->sem_nsems;
- sem_getref_and_unlock(sma);
+ if (!ipc_rcu_getref(sma)) {
+ rcu_read_unlock();
+ un = ERR_PTR(-EIDRM);
+ goto out;
+ }
+ rcu_read_unlock();
/* step 2: allocate new undo structure */
new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
@@ -1269,7 +1458,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
/* step 3: Acquire the lock on semaphore array */
sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
- sem_unlock(sma);
+ sem_unlock(sma, -1);
kfree(new);
un = ERR_PTR(-EIDRM);
goto out;
@@ -1297,7 +1486,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
success:
spin_unlock(&ulp->lock);
rcu_read_lock();
- sem_unlock(sma);
+ sem_unlock(sma, -1);
out:
return un;
}
@@ -1337,7 +1526,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
struct sembuf fast_sops[SEMOPM_FAST];
struct sembuf* sops = fast_sops, *sop;
struct sem_undo *un;
- int undos = 0, alter = 0, max;
+ int undos = 0, alter = 0, max, locknum;
struct sem_queue queue;
unsigned long jiffies_left = 0;
struct ipc_namespace *ns;
@@ -1381,25 +1570,45 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
alter = 1;
}
+ INIT_LIST_HEAD(&tasks);
+
if (undos) {
+ /* On success, find_alloc_undo takes the rcu_read_lock */
un = find_alloc_undo(ns, semid);
if (IS_ERR(un)) {
error = PTR_ERR(un);
goto out_free;
}
- } else
+ } else {
un = NULL;
+ rcu_read_lock();
+ }
- INIT_LIST_HEAD(&tasks);
-
- sma = sem_lock_check(ns, semid);
+ sma = sem_obtain_object_check(ns, semid);
if (IS_ERR(sma)) {
- if (un)
- rcu_read_unlock();
+ rcu_read_unlock();
error = PTR_ERR(sma);
goto out_free;
}
+ error = -EFBIG;
+ if (max >= sma->sem_nsems) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
+
+ error = -EACCES;
+ if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
+
+ error = security_sem_semop(sma, sops, nsops, alter);
+ if (error) {
+ rcu_read_unlock();
+ goto out_wakeup;
+ }
+
/*
* semid identifiers are not unique - find_alloc_undo may have
* allocated an undo structure, it was invalidated by an RMID
@@ -1408,33 +1617,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
* "un" itself is guaranteed by rcu.
*/
error = -EIDRM;
- if (un) {
- if (un->semid == -1) {
- rcu_read_unlock();
- goto out_unlock_free;
- } else {
- /*
- * rcu lock can be released, "un" cannot disappear:
- * - sem_lock is acquired, thus IPC_RMID is
- * impossible.
- * - exit_sem is impossible, it always operates on
- * current (or a dead task).
- */
-
- rcu_read_unlock();
- }
- }
-
- error = -EFBIG;
- if (max >= sma->sem_nsems)
- goto out_unlock_free;
-
- error = -EACCES;
- if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
- goto out_unlock_free;
-
- error = security_sem_semop(sma, sops, nsops, alter);
- if (error)
+ locknum = sem_lock(sma, sops, nsops);
+ if (un && un->semid == -1)
goto out_unlock_free;
error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
@@ -1454,21 +1638,20 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
queue.undo = un;
queue.pid = task_tgid_vnr(current);
queue.alter = alter;
- if (alter)
- list_add_tail(&queue.list, &sma->sem_pending);
- else
- list_add(&queue.list, &sma->sem_pending);
if (nsops == 1) {
struct sem *curr;
curr = &sma->sem_base[sops->sem_num];
if (alter)
- list_add_tail(&queue.simple_list, &curr->sem_pending);
+ list_add_tail(&queue.list, &curr->sem_pending);
else
- list_add(&queue.simple_list, &curr->sem_pending);
+ list_add(&queue.list, &curr->sem_pending);
} else {
- INIT_LIST_HEAD(&queue.simple_list);
+ if (alter)
+ list_add_tail(&queue.list, &sma->sem_pending);
+ else
+ list_add(&queue.list, &sma->sem_pending);
sma->complex_count++;
}
@@ -1477,7 +1660,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
sleep_again:
current->state = TASK_INTERRUPTIBLE;
- sem_unlock(sma);
+ sem_unlock(sma, locknum);
if (timeout)
jiffies_left = schedule_timeout(jiffies_left);
@@ -1499,7 +1682,7 @@ sleep_again:
goto out_free;
}
- sma = sem_lock(ns, semid);
+ sma = sem_obtain_lock(ns, semid, sops, nsops, &locknum);
/*
* Wait until it's guaranteed that no wakeup_sem_queue_do() is ongoing.
@@ -1538,8 +1721,8 @@ sleep_again:
unlink_queue(sma, &queue);
out_unlock_free:
- sem_unlock(sma);
-
+ sem_unlock(sma, locknum);
+out_wakeup:
wake_up_sem_queue_do(&tasks);
out_free:
if(sops != fast_sops)
@@ -1602,8 +1785,7 @@ void exit_sem(struct task_struct *tsk)
struct sem_array *sma;
struct sem_undo *un;
struct list_head tasks;
- int semid;
- int i;
+ int semid, i;
rcu_read_lock();
un = list_entry_rcu(ulp->list_proc.next,
@@ -1612,23 +1794,26 @@ void exit_sem(struct task_struct *tsk)
semid = -1;
else
semid = un->semid;
- rcu_read_unlock();
- if (semid == -1)
+ if (semid == -1) {
+ rcu_read_unlock();
break;
+ }
- sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
-
+ sma = sem_obtain_object_check(tsk->nsproxy->ipc_ns, un->semid);
/* exit_sem raced with IPC_RMID, nothing to do */
- if (IS_ERR(sma))
+ if (IS_ERR(sma)) {
+ rcu_read_unlock();
continue;
+ }
+ sem_lock(sma, NULL, -1);
un = __lookup_undo(ulp, semid);
if (un == NULL) {
/* exit_sem raced with IPC_RMID+semget() that created
* exactly the same semid. Nothing to do.
*/
- sem_unlock(sma);
+ sem_unlock(sma, -1);
continue;
}
@@ -1668,7 +1853,7 @@ void exit_sem(struct task_struct *tsk)
/* maybe some queued-up processes were waiting for this */
INIT_LIST_HEAD(&tasks);
do_smart_update(sma, NULL, 0, 1, &tasks);
- sem_unlock(sma);
+ sem_unlock(sma, -1);
wake_up_sem_queue_do(&tasks);
kfree_rcu(un, rcu);
diff --git a/ipc/shm.c b/ipc/shm.c
index cb858df061d3..8247c49ec073 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -462,7 +462,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
size_t size = params->u.size;
int error;
struct shmid_kernel *shp;
- int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
+ size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
struct file * file;
char name[13];
int id;
diff --git a/ipc/syscall.c b/ipc/syscall.c
index 0d1e32ce048e..52429489cde0 100644
--- a/ipc/syscall.c
+++ b/ipc/syscall.c
@@ -33,12 +33,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
case SEMGET:
return sys_semget(first, second, third);
case SEMCTL: {
- union semun fourth;
+ unsigned long arg;
if (!ptr)
return -EINVAL;
- if (get_user(fourth.__pad, (void __user * __user *) ptr))
+ if (get_user(arg, (unsigned long __user *) ptr))
return -EFAULT;
- return sys_semctl(first, second, third, fourth);
+ return sys_semctl(first, second, third, arg);
}
case MSGSND:
diff --git a/ipc/util.c b/ipc/util.c
index b6db68131a0e..abfc13e8677f 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -23,6 +23,7 @@
#include <linux/msg.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/notifier.h>
#include <linux/capability.h>
#include <linux/highuid.h>
#include <linux/security.h>
@@ -47,19 +48,16 @@ struct ipc_proc_iface {
int (*show)(struct seq_file *, void *);
};
-#ifdef CONFIG_MEMORY_HOTPLUG
-
static void ipc_memory_notifier(struct work_struct *work)
{
ipcns_notify(IPCNS_MEMCHANGED);
}
-static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
-
-
static int ipc_memory_callback(struct notifier_block *self,
unsigned long action, void *arg)
{
+ static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
+
switch (action) {
case MEM_ONLINE: /* memory successfully brought online */
case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */
@@ -85,7 +83,10 @@ static int ipc_memory_callback(struct notifier_block *self,
return NOTIFY_OK;
}
-#endif /* CONFIG_MEMORY_HOTPLUG */
+static struct notifier_block ipc_memory_nb = {
+ .notifier_call = ipc_memory_callback,
+ .priority = IPC_CALLBACK_PRI,
+};
/**
* ipc_init - initialise IPC subsystem
@@ -102,7 +103,7 @@ static int __init ipc_init(void)
sem_init();
msg_init();
shm_init();
- hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
+ register_hotmemory_notifier(&ipc_memory_nb);
register_ipcns_notifier(&init_ipc_ns);
return 0;
}
@@ -438,9 +439,9 @@ void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
* NULL is returned if the allocation fails
*/
-void* ipc_alloc(int size)
+void *ipc_alloc(int size)
{
- void* out;
+ void *out;
if(size > PAGE_SIZE)
out = vmalloc(size);
else
@@ -477,7 +478,7 @@ void ipc_free(void* ptr, int size)
*/
struct ipc_rcu_hdr
{
- int refcount;
+ atomic_t refcount;
int is_vmalloc;
void *data[0];
};
@@ -515,39 +516,41 @@ static inline int rcu_use_vmalloc(int size)
* @size: size desired
*
* Allocate memory for the rcu header structure + the object.
- * Returns the pointer to the object.
- * NULL is returned if the allocation fails.
+ * Returns the pointer to the object or NULL upon failure.
*/
-
-void* ipc_rcu_alloc(int size)
+void *ipc_rcu_alloc(int size)
{
- void* out;
- /*
+ void *out;
+
+ /*
* We prepend the allocation with the rcu struct, and
- * workqueue if necessary (for vmalloc).
+ * workqueue if necessary (for vmalloc).
*/
if (rcu_use_vmalloc(size)) {
out = vmalloc(HDRLEN_VMALLOC + size);
- if (out) {
- out += HDRLEN_VMALLOC;
- container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
- container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
- }
+ if (!out)
+ goto done;
+
+ out += HDRLEN_VMALLOC;
+ container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
} else {
out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
- if (out) {
- out += HDRLEN_KMALLOC;
- container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
- container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
- }
+ if (!out)
+ goto done;
+
+ out += HDRLEN_KMALLOC;
+ container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
}
+ /* set reference counter no matter what kind of allocation was done */
+ atomic_set(&container_of(out, struct ipc_rcu_hdr, data)->refcount, 1);
+done:
return out;
}
-void ipc_rcu_getref(void *ptr)
+int ipc_rcu_getref(void *ptr)
{
- container_of(ptr, struct ipc_rcu_hdr, data)->refcount++;
+ return atomic_inc_not_zero(&container_of(ptr, struct ipc_rcu_hdr, data)->refcount);
}
static void ipc_do_vfree(struct work_struct *work)
@@ -577,7 +580,7 @@ static void ipc_schedule_free(struct rcu_head *head)
void ipc_rcu_putref(void *ptr)
{
- if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
+ if (!atomic_dec_and_test(&container_of(ptr, struct ipc_rcu_hdr, data)->refcount))
return;
if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) {
@@ -668,38 +671,81 @@ void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
}
/**
+ * ipc_obtain_object
+ * @ids: ipc identifier set
+ * @id: ipc id to look for
+ *
+ * Look for an id in the ipc ids idr and return associated ipc object.
+ *
+ * Call inside the RCU critical section.
+ * The ipc object is *not* locked on exit.
+ */
+struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id)
+{
+ struct kern_ipc_perm *out;
+ int lid = ipcid_to_idx(id);
+
+ out = idr_find(&ids->ipcs_idr, lid);
+ if (!out)
+ return ERR_PTR(-EINVAL);
+
+ return out;
+}
+
+/**
* ipc_lock - Lock an ipc structure without rw_mutex held
* @ids: IPC identifier set
* @id: ipc id to look for
*
* Look for an id in the ipc ids idr and lock the associated ipc object.
*
- * The ipc object is locked on exit.
+ * The ipc object is locked on successful exit.
*/
-
struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
struct kern_ipc_perm *out;
- int lid = ipcid_to_idx(id);
rcu_read_lock();
- out = idr_find(&ids->ipcs_idr, lid);
- if (out == NULL) {
- rcu_read_unlock();
- return ERR_PTR(-EINVAL);
- }
+ out = ipc_obtain_object(ids, id);
+ if (IS_ERR(out))
+ goto err1;
spin_lock(&out->lock);
-
+
/* ipc_rmid() may have already freed the ID while ipc_lock
* was spinning: here verify that the structure is still valid
*/
- if (out->deleted) {
- spin_unlock(&out->lock);
- rcu_read_unlock();
- return ERR_PTR(-EINVAL);
- }
+ if (!out->deleted)
+ return out;
+
+ spin_unlock(&out->lock);
+ out = ERR_PTR(-EINVAL);
+err1:
+ rcu_read_unlock();
+ return out;
+}
+
+/**
+ * ipc_obtain_object_check
+ * @ids: ipc identifier set
+ * @id: ipc id to look for
+ *
+ * Similar to ipc_obtain_object() but also checks
+ * the ipc object reference counter.
+ *
+ * Call inside the RCU critical section.
+ * The ipc object is *not* locked on exit.
+ */
+struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id)
+{
+ struct kern_ipc_perm *out = ipc_obtain_object(ids, id);
+
+ if (IS_ERR(out))
+ goto out;
+ if (ipc_checkid(out, id))
+ return ERR_PTR(-EIDRM);
+out:
return out;
}
@@ -780,11 +826,28 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc64_perm *perm, int extra_perm)
{
struct kern_ipc_perm *ipcp;
+
+ ipcp = ipcctl_pre_down_nolock(ns, ids, id, cmd, perm, extra_perm);
+ if (IS_ERR(ipcp))
+ goto out;
+
+ spin_lock(&ipcp->lock);
+out:
+ return ipcp;
+}
+
+struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+ struct ipc_ids *ids, int id, int cmd,
+ struct ipc64_perm *perm, int extra_perm)
+{
kuid_t euid;
- int err;
+ int err = -EPERM;
+ struct kern_ipc_perm *ipcp;
down_write(&ids->rw_mutex);
- ipcp = ipc_lock_check(ids, id);
+ rcu_read_lock();
+
+ ipcp = ipc_obtain_object_check(ids, id);
if (IS_ERR(ipcp)) {
err = PTR_ERR(ipcp);
goto out_up;
@@ -793,17 +856,21 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
audit_ipc_obj(ipcp);
if (cmd == IPC_SET)
audit_ipc_set_perm(extra_perm, perm->uid,
- perm->gid, perm->mode);
+ perm->gid, perm->mode);
euid = current_euid();
if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||
ns_capable(ns->user_ns, CAP_SYS_ADMIN))
return ipcp;
- err = -EPERM;
- ipc_unlock(ipcp);
out_up:
+ /*
+ * Unsuccessful lookup, unlock and return
+ * the corresponding error.
+ */
+ rcu_read_unlock();
up_write(&ids->rw_mutex);
+
return ERR_PTR(err);
}
diff --git a/ipc/util.h b/ipc/util.h
index eeb79a1fbd83..2b0bdd5d92ce 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -119,14 +119,18 @@ void ipc_free(void* ptr, int size);
* to 0 schedules the rcu destruction. Caller must guarantee locking.
*/
void* ipc_rcu_alloc(int size);
-void ipc_rcu_getref(void *ptr);
+int ipc_rcu_getref(void *ptr);
void ipc_rcu_putref(void *ptr);
struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
+struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
+struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
+ struct ipc_ids *ids, int id, int cmd,
+ struct ipc64_perm *perm, int extra_perm);
struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
struct ipc_ids *ids, int id, int cmd,
struct ipc64_perm *perm, int extra_perm);
@@ -150,14 +154,9 @@ static inline int ipc_buildid(int id, int seq)
return SEQ_MULTIPLIER * seq + id;
}
-/*
- * Must be called with ipcp locked
- */
static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid)
{
- if (uid / SEQ_MULTIPLIER != ipcp->seq)
- return 1;
- return 0;
+ return uid / SEQ_MULTIPLIER != ipcp->seq;
}
static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
@@ -172,7 +171,13 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
rcu_read_unlock();
}
+static inline void ipc_lock_object(struct kern_ipc_perm *perm)
+{
+ spin_lock(&perm->lock);
+}
+
struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
+struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
struct ipc_ops *ops, struct ipc_params *params);
void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
diff --git a/kernel/.gitignore b/kernel/.gitignore
index ab4f1090f437..b3097bde4e9c 100644
--- a/kernel/.gitignore
+++ b/kernel/.gitignore
@@ -4,3 +4,4 @@
config_data.h
config_data.gz
timeconst.h
+hz.bc
diff --git a/kernel/Makefile b/kernel/Makefile
index bbde5f1a4486..d1574d47cf27 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -24,6 +24,7 @@ endif
obj-y += sched/
obj-y += power/
+obj-y += cpu/
obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
obj-$(CONFIG_FREEZER) += freezer.o
diff --git a/kernel/async.c b/kernel/async.c
index 8ddee2c3e5b0..61f023ce0228 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -73,7 +73,7 @@ struct async_entry {
struct list_head global_list;
struct work_struct work;
async_cookie_t cookie;
- async_func_ptr *func;
+ async_func_t func;
void *data;
struct async_domain *domain;
};
@@ -84,24 +84,20 @@ static atomic_t entry_count;
static async_cookie_t lowest_in_progress(struct async_domain *domain)
{
- struct async_entry *first = NULL;
+ struct list_head *pending;
async_cookie_t ret = ASYNC_COOKIE_MAX;
unsigned long flags;
spin_lock_irqsave(&async_lock, flags);
- if (domain) {
- if (!list_empty(&domain->pending))
- first = list_first_entry(&domain->pending,
- struct async_entry, domain_list);
- } else {
- if (!list_empty(&async_global_pending))
- first = list_first_entry(&async_global_pending,
- struct async_entry, global_list);
- }
+ if (domain)
+ pending = &domain->pending;
+ else
+ pending = &async_global_pending;
- if (first)
- ret = first->cookie;
+ if (!list_empty(pending))
+ ret = list_first_entry(pending, struct async_entry,
+ domain_list)->cookie;
spin_unlock_irqrestore(&async_lock, flags);
return ret;
@@ -149,7 +145,7 @@ static void async_run_entry_fn(struct work_struct *work)
wake_up(&async_done);
}
-static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct async_domain *domain)
+static async_cookie_t __async_schedule(async_func_t func, void *data, struct async_domain *domain)
{
struct async_entry *entry;
unsigned long flags;
@@ -169,13 +165,13 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct a
spin_unlock_irqrestore(&async_lock, flags);
/* low on memory.. run synchronously */
- ptr(data, newcookie);
+ func(data, newcookie);
return newcookie;
}
INIT_LIST_HEAD(&entry->domain_list);
INIT_LIST_HEAD(&entry->global_list);
INIT_WORK(&entry->work, async_run_entry_fn);
- entry->func = ptr;
+ entry->func = func;
entry->data = data;
entry->domain = domain;
@@ -202,21 +198,21 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct a
/**
* async_schedule - schedule a function for asynchronous execution
- * @ptr: function to execute asynchronously
+ * @func: function to execute asynchronously
* @data: data pointer to pass to the function
*
* Returns an async_cookie_t that may be used for checkpointing later.
* Note: This function may be called from atomic or non-atomic contexts.
*/
-async_cookie_t async_schedule(async_func_ptr *ptr, void *data)
+async_cookie_t async_schedule(async_func_t func, void *data)
{
- return __async_schedule(ptr, data, &async_dfl_domain);
+ return __async_schedule(func, data, &async_dfl_domain);
}
EXPORT_SYMBOL_GPL(async_schedule);
/**
* async_schedule_domain - schedule a function for asynchronous execution within a certain domain
- * @ptr: function to execute asynchronously
+ * @func: function to execute asynchronously
* @data: data pointer to pass to the function
* @domain: the domain
*
@@ -226,10 +222,10 @@ EXPORT_SYMBOL_GPL(async_schedule);
* synchronization domain is specified via @domain. Note: This function
* may be called from atomic or non-atomic contexts.
*/
-async_cookie_t async_schedule_domain(async_func_ptr *ptr, void *data,
+async_cookie_t async_schedule_domain(async_func_t func, void *data,
struct async_domain *domain)
{
- return __async_schedule(ptr, data, domain);
+ return __async_schedule(func, data, domain);
}
EXPORT_SYMBOL_GPL(async_schedule_domain);
diff --git a/kernel/audit.c b/kernel/audit.c
index d596e5355f15..0b084fa44b1f 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -58,7 +58,7 @@
#ifdef CONFIG_SECURITY
#include <linux/security.h>
#endif
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/freezer.h>
#include <linux/tty.h>
#include <linux/pid_namespace.h>
@@ -660,14 +660,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
/* As soon as there's any sign of userspace auditd,
* start kauditd to talk to it */
- if (!kauditd_task)
+ if (!kauditd_task) {
kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd");
- if (IS_ERR(kauditd_task)) {
- err = PTR_ERR(kauditd_task);
- kauditd_task = NULL;
- return err;
+ if (IS_ERR(kauditd_task)) {
+ err = PTR_ERR(kauditd_task);
+ kauditd_task = NULL;
+ return err;
+ }
}
-
loginuid = audit_get_loginuid(current);
sessionid = audit_get_sessionid(current);
security_task_getsecid(current, &sid);
@@ -910,7 +910,7 @@ static void audit_receive_skb(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
/*
- * len MUST be signed for NLMSG_NEXT to be able to dec it below 0
+ * len MUST be signed for nlmsg_next to be able to dec it below 0
* if the nlmsg_len was not aligned
*/
int len;
@@ -919,13 +919,13 @@ static void audit_receive_skb(struct sk_buff *skb)
nlh = nlmsg_hdr(skb);
len = skb->len;
- while (NLMSG_OK(nlh, len)) {
+ while (nlmsg_ok(nlh, len)) {
err = audit_receive_msg(skb, nlh);
/* if err or if this message says it wants a response */
if (err || (nlh->nlmsg_flags & NLM_F_ACK))
netlink_ack(skb, nlh, err);
- nlh = NLMSG_NEXT(nlh, len);
+ nlh = nlmsg_next(nlh, &len);
}
}
@@ -1483,7 +1483,7 @@ void audit_log_end(struct audit_buffer *ab)
audit_log_lost("rate limit exceeded");
} else {
struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
- nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);
+ nlh->nlmsg_len = ab->skb->len - NLMSG_HDRLEN;
if (audit_pid) {
skb_queue_tail(&audit_skb_queue, ab->skb);
diff --git a/kernel/audit.h b/kernel/audit.h
index d51cba868e1b..11468d99dad0 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -59,10 +59,7 @@ struct audit_entry {
struct audit_krule rule;
};
-#ifdef CONFIG_AUDIT
-extern int audit_enabled;
extern int audit_ever_enabled;
-#endif
extern int audit_pid;
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 642a89c4f3d6..a291aa23fb3f 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -617,9 +617,9 @@ void audit_trim_trees(void)
}
spin_unlock(&hash_lock);
trim_marked(tree);
- put_tree(tree);
drop_collected_mounts(root_mnt);
skip_it:
+ put_tree(tree);
mutex_lock(&audit_filter_mutex);
}
list_del(&cursor);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f9fc54bbe06f..267436826c3b 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -594,6 +594,10 @@ exit_nofree:
return entry;
exit_free:
+ if (entry->rule.watch)
+ audit_put_watch(entry->rule.watch); /* matches initial get */
+ if (entry->rule.tree)
+ audit_put_tree(entry->rule.tree); /* that's the temporary one */
audit_free_rule(entry);
return ERR_PTR(err);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index a371f857a0a9..c68229411a7c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1034,21 +1034,15 @@ static inline void audit_free_aux(struct audit_context *context)
}
}
-static inline void audit_zero_context(struct audit_context *context,
- enum audit_state state)
-{
- memset(context, 0, sizeof(*context));
- context->state = state;
- context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
-}
-
static inline struct audit_context *audit_alloc_context(enum audit_state state)
{
struct audit_context *context;
- if (!(context = kmalloc(sizeof(*context), GFP_KERNEL)))
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
return NULL;
- audit_zero_context(context, state);
+ context->state = state;
+ context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
INIT_LIST_HEAD(&context->killed_trees);
INIT_LIST_HEAD(&context->names_list);
return context;
diff --git a/kernel/capability.c b/kernel/capability.c
index 493d97259484..f6c2ce5701e1 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -393,6 +393,30 @@ bool ns_capable(struct user_namespace *ns, int cap)
EXPORT_SYMBOL(ns_capable);
/**
+ * file_ns_capable - Determine if the file's opener had a capability in effect
+ * @file: The file we want to check
+ * @ns: The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if task that opened the file had a capability in effect
+ * when the file was opened.
+ *
+ * This does not set PF_SUPERPRIV because the caller may not
+ * actually be privileged.
+ */
+bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
+{
+ if (WARN_ON_ONCE(!cap_valid(cap)))
+ return false;
+
+ if (security_capable(file->f_cred, ns, cap) == 0)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL(file_ns_capable);
+
+/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for
*
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index d5cffe80b469..2a9926275f80 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -30,7 +30,6 @@
#include <linux/cred.h>
#include <linux/ctype.h>
#include <linux/errno.h>
-#include <linux/fs.h>
#include <linux/init_task.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -59,7 +58,7 @@
#include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */
#include <linux/eventfd.h>
#include <linux/poll.h>
-#include <linux/flex_array.h> /* used in cgroup_attach_proc */
+#include <linux/flex_array.h> /* used in cgroup_attach_task */
#include <linux/kthread.h>
#include <linux/atomic.h>
@@ -83,7 +82,13 @@
* B happens only through cgroup_show_options() and using cgroup_root_mutex
* breaks it.
*/
+#ifdef CONFIG_PROVE_RCU
+DEFINE_MUTEX(cgroup_mutex);
+EXPORT_SYMBOL_GPL(cgroup_mutex); /* only for task_subsys_state_check() */
+#else
static DEFINE_MUTEX(cgroup_mutex);
+#endif
+
static DEFINE_MUTEX(cgroup_root_mutex);
/*
@@ -98,56 +103,6 @@ static struct cgroup_subsys *subsys[CGROUP_SUBSYS_COUNT] = {
#include <linux/cgroup_subsys.h>
};
-#define MAX_CGROUP_ROOT_NAMELEN 64
-
-/*
- * A cgroupfs_root represents the root of a cgroup hierarchy,
- * and may be associated with a superblock to form an active
- * hierarchy
- */
-struct cgroupfs_root {
- struct super_block *sb;
-
- /*
- * The bitmask of subsystems intended to be attached to this
- * hierarchy
- */
- unsigned long subsys_mask;
-
- /* Unique id for this hierarchy. */
- int hierarchy_id;
-
- /* The bitmask of subsystems currently attached to this hierarchy */
- unsigned long actual_subsys_mask;
-
- /* A list running through the attached subsystems */
- struct list_head subsys_list;
-
- /* The root cgroup for this hierarchy */
- struct cgroup top_cgroup;
-
- /* Tracks how many cgroups are currently defined in hierarchy.*/
- int number_of_cgroups;
-
- /* A list running through the active hierarchies */
- struct list_head root_list;
-
- /* All cgroups on this root, cgroup_mutex protected */
- struct list_head allcg_list;
-
- /* Hierarchy-specific flags */
- unsigned long flags;
-
- /* IDs for cgroups in this hierarchy */
- struct ida cgroup_ida;
-
- /* The path to use for release notifications. */
- char release_agent_path[PATH_MAX];
-
- /* The name for this hierarchy - may be empty */
- char name[MAX_CGROUP_ROOT_NAMELEN];
-};
-
/*
* The "rootnode" hierarchy is the "dummy hierarchy", reserved for the
* subsystems that are otherwise unattached - it never has more than a
@@ -162,6 +117,9 @@ struct cfent {
struct list_head node;
struct dentry *dentry;
struct cftype *type;
+
+ /* file xattrs */
+ struct simple_xattrs xattrs;
};
/*
@@ -238,6 +196,8 @@ static DEFINE_SPINLOCK(hierarchy_id_lock);
/* dummytop is a shorthand for the dummy hierarchy's top cgroup */
#define dummytop (&rootnode.top_cgroup)
+static struct cgroup_name root_cgroup_name = { .name = "/" };
+
/* This flag indicates whether tasks in the fork and exit paths should
* check for fork/exit handlers to call. This avoids us having to do
* extra work in the fork/exit path if none of the subsystems need to
@@ -249,20 +209,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp);
static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
struct cftype cfts[], bool is_add);
-#ifdef CONFIG_PROVE_LOCKING
-int cgroup_lock_is_held(void)
-{
- return lockdep_is_held(&cgroup_mutex);
-}
-#else /* #ifdef CONFIG_PROVE_LOCKING */
-int cgroup_lock_is_held(void)
-{
- return mutex_is_locked(&cgroup_mutex);
-}
-#endif /* #else #ifdef CONFIG_PROVE_LOCKING */
-
-EXPORT_SYMBOL_GPL(cgroup_lock_is_held);
-
static int css_unbias_refcnt(int refcnt)
{
return refcnt >= 0 ? refcnt : refcnt - CSS_DEACT_BIAS;
@@ -282,11 +228,25 @@ inline int cgroup_is_removed(const struct cgroup *cgrp)
return test_bit(CGRP_REMOVED, &cgrp->flags);
}
-/* bits in struct cgroupfs_root flags field */
-enum {
- ROOT_NOPREFIX, /* mounted subsystems have no named prefix */
- ROOT_XATTR, /* supports extended attributes */
-};
+/**
+ * cgroup_is_descendant - test ancestry
+ * @cgrp: the cgroup to be tested
+ * @ancestor: possible ancestor of @cgrp
+ *
+ * Test whether @cgrp is a descendant of @ancestor. It also returns %true
+ * if @cgrp == @ancestor. This function is safe to call as long as @cgrp
+ * and @ancestor are accessible.
+ */
+bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor)
+{
+ while (cgrp) {
+ if (cgrp == ancestor)
+ return true;
+ cgrp = cgrp->parent;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(cgroup_is_descendant);
static int cgroup_is_releasable(const struct cgroup *cgrp)
{
@@ -327,6 +287,23 @@ static inline struct cftype *__d_cft(struct dentry *dentry)
return __d_cfe(dentry)->type;
}
+/**
+ * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive.
+ * @cgrp: the cgroup to be checked for liveness
+ *
+ * On success, returns true; the mutex should be later unlocked. On
+ * failure returns false with no lock held.
+ */
+static bool cgroup_lock_live_group(struct cgroup *cgrp)
+{
+ mutex_lock(&cgroup_mutex);
+ if (cgroup_is_removed(cgrp)) {
+ mutex_unlock(&cgroup_mutex);
+ return false;
+ }
+ return true;
+}
+
/* the list of cgroups eligible for automatic release. Protected by
* release_list_lock */
static LIST_HEAD(release_list);
@@ -800,27 +777,6 @@ static struct cgroup *task_cgroup_from_root(struct task_struct *task,
* update of a tasks cgroup pointer by cgroup_attach_task()
*/
-/**
- * cgroup_lock - lock out any changes to cgroup structures
- *
- */
-void cgroup_lock(void)
-{
- mutex_lock(&cgroup_mutex);
-}
-EXPORT_SYMBOL_GPL(cgroup_lock);
-
-/**
- * cgroup_unlock - release lock on cgroup changes
- *
- * Undo the lock taken in a previous cgroup_lock() call.
- */
-void cgroup_unlock(void)
-{
- mutex_unlock(&cgroup_mutex);
-}
-EXPORT_SYMBOL_GPL(cgroup_unlock);
-
/*
* A couple of forward declarations required, due to cyclic reference loop:
* cgroup_mkdir -> cgroup_create -> cgroup_populate_dir ->
@@ -859,6 +815,17 @@ static struct inode *cgroup_new_inode(umode_t mode, struct super_block *sb)
return inode;
}
+static struct cgroup_name *cgroup_alloc_name(struct dentry *dentry)
+{
+ struct cgroup_name *name;
+
+ name = kmalloc(sizeof(*name) + dentry->d_name.len + 1, GFP_KERNEL);
+ if (!name)
+ return NULL;
+ strcpy(name->name, dentry->d_name.name);
+ return name;
+}
+
static void cgroup_free_fn(struct work_struct *work)
{
struct cgroup *cgrp = container_of(work, struct cgroup, free_work);
@@ -875,8 +842,18 @@ static void cgroup_free_fn(struct work_struct *work)
mutex_unlock(&cgroup_mutex);
/*
+ * We get a ref to the parent's dentry, and put the ref when
+ * this cgroup is being freed, so it's guaranteed that the
+ * parent won't be destroyed before its children.
+ */
+ dput(cgrp->parent->dentry);
+
+ ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
+
+ /*
* Drop the active superblock reference that we took when we
- * created the cgroup
+ * created the cgroup. This will free cgrp->root, if we are
+ * holding the last reference to @sb.
*/
deactivate_super(cgrp->root->sb);
@@ -888,7 +865,7 @@ static void cgroup_free_fn(struct work_struct *work)
simple_xattrs_free(&cgrp->xattrs);
- ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
+ kfree(rcu_dereference_raw(cgrp->name));
kfree(cgrp);
}
@@ -910,13 +887,12 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
} else {
struct cfent *cfe = __d_cfe(dentry);
struct cgroup *cgrp = dentry->d_parent->d_fsdata;
- struct cftype *cft = cfe->type;
WARN_ONCE(!list_empty(&cfe->node) &&
cgrp != &cgrp->root->top_cgroup,
"cfe still linked for %s\n", cfe->type->name);
+ simple_xattrs_free(&cfe->xattrs);
kfree(cfe);
- simple_xattrs_free(&cft->xattrs);
}
iput(inode);
}
@@ -1108,9 +1084,11 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry)
mutex_lock(&cgroup_root_mutex);
for_each_subsys(root, ss)
seq_printf(seq, ",%s", ss->name);
- if (test_bit(ROOT_NOPREFIX, &root->flags))
+ if (root->flags & CGRP_ROOT_SANE_BEHAVIOR)
+ seq_puts(seq, ",sane_behavior");
+ if (root->flags & CGRP_ROOT_NOPREFIX)
seq_puts(seq, ",noprefix");
- if (test_bit(ROOT_XATTR, &root->flags))
+ if (root->flags & CGRP_ROOT_XATTR)
seq_puts(seq, ",xattr");
if (strlen(root->release_agent_path))
seq_printf(seq, ",release_agent=%s", root->release_agent_path);
@@ -1172,8 +1150,12 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
all_ss = true;
continue;
}
+ if (!strcmp(token, "__DEVEL__sane_behavior")) {
+ opts->flags |= CGRP_ROOT_SANE_BEHAVIOR;
+ continue;
+ }
if (!strcmp(token, "noprefix")) {
- set_bit(ROOT_NOPREFIX, &opts->flags);
+ opts->flags |= CGRP_ROOT_NOPREFIX;
continue;
}
if (!strcmp(token, "clone_children")) {
@@ -1181,7 +1163,7 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
continue;
}
if (!strcmp(token, "xattr")) {
- set_bit(ROOT_XATTR, &opts->flags);
+ opts->flags |= CGRP_ROOT_XATTR;
continue;
}
if (!strncmp(token, "release_agent=", 14)) {
@@ -1259,13 +1241,26 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
/* Consistency checks */
+ if (opts->flags & CGRP_ROOT_SANE_BEHAVIOR) {
+ pr_warning("cgroup: sane_behavior: this is still under development and its behaviors will change, proceed at your own risk\n");
+
+ if (opts->flags & CGRP_ROOT_NOPREFIX) {
+ pr_err("cgroup: sane_behavior: noprefix is not allowed\n");
+ return -EINVAL;
+ }
+
+ if (opts->cpuset_clone_children) {
+ pr_err("cgroup: sane_behavior: clone_children is not allowed\n");
+ return -EINVAL;
+ }
+ }
+
/*
* Option noprefix was introduced just for backward compatibility
* with the old cpuset, so we allow noprefix only if mounting just
* the cpuset subsystem.
*/
- if (test_bit(ROOT_NOPREFIX, &opts->flags) &&
- (opts->subsys_mask & mask))
+ if ((opts->flags & CGRP_ROOT_NOPREFIX) && (opts->subsys_mask & mask))
return -EINVAL;
@@ -1336,6 +1331,11 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
struct cgroup_sb_opts opts;
unsigned long added_mask, removed_mask;
+ if (root->flags & CGRP_ROOT_SANE_BEHAVIOR) {
+ pr_err("cgroup: sane_behavior: remount is not allowed\n");
+ return -EINVAL;
+ }
+
mutex_lock(&cgrp->dentry->d_inode->i_mutex);
mutex_lock(&cgroup_mutex);
mutex_lock(&cgroup_root_mutex);
@@ -1421,7 +1421,7 @@ static void init_cgroup_root(struct cgroupfs_root *root)
INIT_LIST_HEAD(&root->allcg_list);
root->number_of_cgroups = 1;
cgrp->root = root;
- cgrp->top_cgroup = cgrp;
+ cgrp->name = &root_cgroup_name;
init_cgroup_housekeeping(cgrp);
list_add_tail(&cgrp->allcg_node, &root->allcg_list);
}
@@ -1685,6 +1685,14 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
* any) is not needed
*/
cgroup_drop_root(opts.new_root);
+
+ if (((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) &&
+ root->flags != opts.flags) {
+ pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n");
+ ret = -EINVAL;
+ goto drop_new_super;
+ }
+
/* no subsys rebinding, so refcounts don't change */
drop_parsed_module_refcounts(opts.subsys_mask);
}
@@ -1769,49 +1777,48 @@ static struct kobject *cgroup_kobj;
* @buf: the buffer to write the path into
* @buflen: the length of the buffer
*
- * Called with cgroup_mutex held or else with an RCU-protected cgroup
- * reference. Writes path of cgroup into buf. Returns 0 on success,
- * -errno on error.
+ * Writes path of cgroup into buf. Returns 0 on success, -errno on error.
+ *
+ * We can't generate cgroup path using dentry->d_name, as accessing
+ * dentry->name must be protected by irq-unsafe dentry->d_lock or parent
+ * inode's i_mutex, while on the other hand cgroup_path() can be called
+ * with some irq-safe spinlocks held.
*/
int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
{
- struct dentry *dentry = cgrp->dentry;
+ int ret = -ENAMETOOLONG;
char *start;
- rcu_lockdep_assert(rcu_read_lock_held() || cgroup_lock_is_held(),
- "cgroup_path() called without proper locking");
-
- if (cgrp == dummytop) {
- /*
- * Inactive subsystems have no dentry for their root
- * cgroup
- */
- strcpy(buf, "/");
+ if (!cgrp->parent) {
+ if (strlcpy(buf, "/", buflen) >= buflen)
+ return -ENAMETOOLONG;
return 0;
}
start = buf + buflen - 1;
-
*start = '\0';
- for (;;) {
- int len = dentry->d_name.len;
+ rcu_read_lock();
+ do {
+ const char *name = cgroup_name(cgrp);
+ int len;
+
+ len = strlen(name);
if ((start -= len) < buf)
- return -ENAMETOOLONG;
- memcpy(start, dentry->d_name.name, len);
- cgrp = cgrp->parent;
- if (!cgrp)
- break;
+ goto out;
+ memcpy(start, name, len);
- dentry = cgrp->dentry;
- if (!cgrp->parent)
- continue;
if (--start < buf)
- return -ENAMETOOLONG;
+ goto out;
*start = '/';
- }
+
+ cgrp = cgrp->parent;
+ } while (cgrp->parent);
+ ret = 0;
memmove(buf, start, buf + buflen - start);
- return 0;
+out:
+ rcu_read_unlock();
+ return ret;
}
EXPORT_SYMBOL_GPL(cgroup_path);
@@ -1900,7 +1907,7 @@ EXPORT_SYMBOL_GPL(cgroup_taskset_size);
*
* Must be called with cgroup_mutex and threadgroup locked.
*/
-static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
+static void cgroup_task_migrate(struct cgroup *oldcgrp,
struct task_struct *tsk, struct css_set *newcg)
{
struct css_set *oldcg;
@@ -1933,121 +1940,22 @@ static void cgroup_task_migrate(struct cgroup *cgrp, struct cgroup *oldcgrp,
}
/**
- * cgroup_attach_task - attach task 'tsk' to cgroup 'cgrp'
- * @cgrp: the cgroup the task is attaching to
- * @tsk: the task to be attached
- *
- * Call with cgroup_mutex and threadgroup locked. May take task_lock of
- * @tsk during call.
- */
-int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
-{
- int retval = 0;
- struct cgroup_subsys *ss, *failed_ss = NULL;
- struct cgroup *oldcgrp;
- struct cgroupfs_root *root = cgrp->root;
- struct cgroup_taskset tset = { };
- struct css_set *newcg;
-
- /* @tsk either already exited or can't exit until the end */
- if (tsk->flags & PF_EXITING)
- return -ESRCH;
-
- /* Nothing to do if the task is already in that cgroup */
- oldcgrp = task_cgroup_from_root(tsk, root);
- if (cgrp == oldcgrp)
- return 0;
-
- tset.single.task = tsk;
- tset.single.cgrp = oldcgrp;
-
- for_each_subsys(root, ss) {
- if (ss->can_attach) {
- retval = ss->can_attach(cgrp, &tset);
- if (retval) {
- /*
- * Remember on which subsystem the can_attach()
- * failed, so that we only call cancel_attach()
- * against the subsystems whose can_attach()
- * succeeded. (See below)
- */
- failed_ss = ss;
- goto out;
- }
- }
- }
-
- newcg = find_css_set(tsk->cgroups, cgrp);
- if (!newcg) {
- retval = -ENOMEM;
- goto out;
- }
-
- cgroup_task_migrate(cgrp, oldcgrp, tsk, newcg);
-
- for_each_subsys(root, ss) {
- if (ss->attach)
- ss->attach(cgrp, &tset);
- }
-
-out:
- if (retval) {
- for_each_subsys(root, ss) {
- if (ss == failed_ss)
- /*
- * This subsystem was the one that failed the
- * can_attach() check earlier, so we don't need
- * to call cancel_attach() against it or any
- * remaining subsystems.
- */
- break;
- if (ss->cancel_attach)
- ss->cancel_attach(cgrp, &tset);
- }
- }
- return retval;
-}
-
-/**
- * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
- * @from: attach to all cgroups of a given task
- * @tsk: the task to be attached
- */
-int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
-{
- struct cgroupfs_root *root;
- int retval = 0;
-
- cgroup_lock();
- for_each_active_root(root) {
- struct cgroup *from_cg = task_cgroup_from_root(from, root);
-
- retval = cgroup_attach_task(from_cg, tsk);
- if (retval)
- break;
- }
- cgroup_unlock();
-
- return retval;
-}
-EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
-
-/**
- * cgroup_attach_proc - attach all threads in a threadgroup to a cgroup
+ * cgroup_attach_task - attach a task or a whole threadgroup to a cgroup
* @cgrp: the cgroup to attach to
- * @leader: the threadgroup leader task_struct of the group to be attached
+ * @tsk: the task or the leader of the threadgroup to be attached
+ * @threadgroup: attach the whole threadgroup?
*
* Call holding cgroup_mutex and the group_rwsem of the leader. Will take
- * task_lock of each thread in leader's threadgroup individually in turn.
+ * task_lock of @tsk or each thread in the threadgroup individually in turn.
*/
-static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
+static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
+ bool threadgroup)
{
int retval, i, group_size;
struct cgroup_subsys *ss, *failed_ss = NULL;
- /* guaranteed to be initialized later, but the compiler needs this */
struct cgroupfs_root *root = cgrp->root;
/* threadgroup list cursor and array */
- struct task_struct *tsk;
+ struct task_struct *leader = tsk;
struct task_and_cgroup *tc;
struct flex_array *group;
struct cgroup_taskset tset = { };
@@ -2059,17 +1967,19 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
* group - group_rwsem prevents new threads from appearing, and if
* threads exit, this will just be an over-estimate.
*/
- group_size = get_nr_threads(leader);
+ if (threadgroup)
+ group_size = get_nr_threads(tsk);
+ else
+ group_size = 1;
/* flex_array supports very large thread-groups better than kmalloc. */
group = flex_array_alloc(sizeof(*tc), group_size, GFP_KERNEL);
if (!group)
return -ENOMEM;
/* pre-allocate to guarantee space while iterating in rcu read-side. */
- retval = flex_array_prealloc(group, 0, group_size - 1, GFP_KERNEL);
+ retval = flex_array_prealloc(group, 0, group_size, GFP_KERNEL);
if (retval)
goto out_free_group_list;
- tsk = leader;
i = 0;
/*
* Prevent freeing of tasks while we take a snapshot. Tasks that are
@@ -2098,6 +2008,9 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
retval = flex_array_put(group, i, &ent, GFP_ATOMIC);
BUG_ON(retval != 0);
i++;
+
+ if (!threadgroup)
+ break;
} while_each_thread(leader, tsk);
rcu_read_unlock();
/* remember the number of threads in the array for later. */
@@ -2143,7 +2056,7 @@ static int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
*/
for (i = 0; i < group_size; i++) {
tc = flex_array_get(group, i);
- cgroup_task_migrate(cgrp, tc->cgrp, tc->task, tc->cg);
+ cgroup_task_migrate(tc->cgrp, tc->task, tc->cg);
}
/* nothing is sensitive to fork() after this point. */
@@ -2224,11 +2137,11 @@ retry_find_task:
tsk = tsk->group_leader;
/*
- * Workqueue threads may acquire PF_THREAD_BOUND and become
+ * Workqueue threads may acquire PF_NO_SETAFFINITY and become
* trapped in a cpuset, or RT worker may be born in a cgroup
* with no rt_runtime allocated. Just say no.
*/
- if (tsk == kthreadd_task || (tsk->flags & PF_THREAD_BOUND)) {
+ if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
ret = -EINVAL;
rcu_read_unlock();
goto out_unlock_cgroup;
@@ -2251,17 +2164,42 @@ retry_find_task:
put_task_struct(tsk);
goto retry_find_task;
}
- ret = cgroup_attach_proc(cgrp, tsk);
- } else
- ret = cgroup_attach_task(cgrp, tsk);
+ }
+
+ ret = cgroup_attach_task(cgrp, tsk, threadgroup);
+
threadgroup_unlock(tsk);
put_task_struct(tsk);
out_unlock_cgroup:
- cgroup_unlock();
+ mutex_unlock(&cgroup_mutex);
return ret;
}
+/**
+ * cgroup_attach_task_all - attach task 'tsk' to all cgroups of task 'from'
+ * @from: attach to all cgroups of a given task
+ * @tsk: the task to be attached
+ */
+int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
+{
+ struct cgroupfs_root *root;
+ int retval = 0;
+
+ mutex_lock(&cgroup_mutex);
+ for_each_active_root(root) {
+ struct cgroup *from_cg = task_cgroup_from_root(from, root);
+
+ retval = cgroup_attach_task(from_cg, tsk, false);
+ if (retval)
+ break;
+ }
+ mutex_unlock(&cgroup_mutex);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(cgroup_attach_task_all);
+
static int cgroup_tasks_write(struct cgroup *cgrp, struct cftype *cft, u64 pid)
{
return attach_task_by_pid(cgrp, pid, false);
@@ -2272,24 +2210,6 @@ static int cgroup_procs_write(struct cgroup *cgrp, struct cftype *cft, u64 tgid)
return attach_task_by_pid(cgrp, tgid, true);
}
-/**
- * cgroup_lock_live_group - take cgroup_mutex and check that cgrp is alive.
- * @cgrp: the cgroup to be checked for liveness
- *
- * On success, returns true; the lock should be later released with
- * cgroup_unlock(). On failure returns false with no lock held.
- */
-bool cgroup_lock_live_group(struct cgroup *cgrp)
-{
- mutex_lock(&cgroup_mutex);
- if (cgroup_is_removed(cgrp)) {
- mutex_unlock(&cgroup_mutex);
- return false;
- }
- return true;
-}
-EXPORT_SYMBOL_GPL(cgroup_lock_live_group);
-
static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
const char *buffer)
{
@@ -2301,7 +2221,7 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,
mutex_lock(&cgroup_root_mutex);
strcpy(cgrp->root->release_agent_path, buffer);
mutex_unlock(&cgroup_root_mutex);
- cgroup_unlock();
+ mutex_unlock(&cgroup_mutex);
return 0;
}
@@ -2312,7 +2232,14 @@ static int cgroup_release_agent_show(struct cgroup *cgrp, struct cftype *cft,
return -ENODEV;
seq_puts(seq, cgrp->root->release_agent_path);
seq_putc(seq, '\n');
- cgroup_unlock();
+ mutex_unlock(&cgroup_mutex);
+ return 0;
+}
+
+static int cgroup_sane_behavior_show(struct cgroup *cgrp, struct cftype *cft,
+ struct seq_file *seq)
+{
+ seq_printf(seq, "%d\n", cgroup_sane_behavior(cgrp));
return 0;
}
@@ -2537,13 +2464,40 @@ static int cgroup_file_release(struct inode *inode, struct file *file)
static int cgroup_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
+ int ret;
+ struct cgroup_name *name, *old_name;
+ struct cgroup *cgrp;
+
+ /*
+ * It's convinient to use parent dir's i_mutex to protected
+ * cgrp->name.
+ */
+ lockdep_assert_held(&old_dir->i_mutex);
+
if (!S_ISDIR(old_dentry->d_inode->i_mode))
return -ENOTDIR;
if (new_dentry->d_inode)
return -EEXIST;
if (old_dir != new_dir)
return -EIO;
- return simple_rename(old_dir, old_dentry, new_dir, new_dentry);
+
+ cgrp = __d_cgrp(old_dentry);
+
+ name = cgroup_alloc_name(new_dentry);
+ if (!name)
+ return -ENOMEM;
+
+ ret = simple_rename(old_dir, old_dentry, new_dir, new_dentry);
+ if (ret) {
+ kfree(name);
+ return ret;
+ }
+
+ old_name = cgrp->name;
+ rcu_assign_pointer(cgrp->name, name);
+
+ kfree_rcu(old_name, rcu_head);
+ return 0;
}
static struct simple_xattrs *__d_xattrs(struct dentry *dentry)
@@ -2551,13 +2505,13 @@ static struct simple_xattrs *__d_xattrs(struct dentry *dentry)
if (S_ISDIR(dentry->d_inode->i_mode))
return &__d_cgrp(dentry)->xattrs;
else
- return &__d_cft(dentry)->xattrs;
+ return &__d_cfe(dentry)->xattrs;
}
static inline int xattr_enabled(struct dentry *dentry)
{
struct cgroupfs_root *root = dentry->d_sb->s_fs_info;
- return test_bit(ROOT_XATTR, &root->flags);
+ return root->flags & CGRP_ROOT_XATTR;
}
static bool is_valid_xattr(const char *name)
@@ -2727,9 +2681,7 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
umode_t mode;
char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
- simple_xattrs_init(&cft->xattrs);
-
- if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
+ if (subsys && !(cgrp->root->flags & CGRP_ROOT_NOPREFIX)) {
strcpy(name, subsys->name);
strcat(name, ".");
}
@@ -2753,6 +2705,7 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
cfe->type = (void *)cft;
cfe->dentry = dentry;
dentry->d_fsdata = cfe;
+ simple_xattrs_init(&cfe->xattrs);
list_add_tail(&cfe->node, &parent->files);
cfe = NULL;
}
@@ -2770,6 +2723,8 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
for (cft = cfts; cft->name[0] != '\0'; cft++) {
/* does cft->flags tell us to skip this file on @cgrp? */
+ if ((cft->flags & CFTYPE_INSANE) && cgroup_sane_behavior(cgrp))
+ continue;
if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgrp->parent)
continue;
if ((cft->flags & CFTYPE_ONLY_ON_ROOT) && cgrp->parent)
@@ -3300,6 +3255,34 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
return 0;
}
+static void cgroup_transfer_one_task(struct task_struct *task,
+ struct cgroup_scanner *scan)
+{
+ struct cgroup *new_cgroup = scan->data;
+
+ mutex_lock(&cgroup_mutex);
+ cgroup_attach_task(new_cgroup, task, false);
+ mutex_unlock(&cgroup_mutex);
+}
+
+/**
+ * cgroup_trasnsfer_tasks - move tasks from one cgroup to another
+ * @to: cgroup to which the tasks will be moved
+ * @from: cgroup in which the tasks currently reside
+ */
+int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
+{
+ struct cgroup_scanner scan;
+
+ scan.cg = from;
+ scan.test_task = NULL; /* select all tasks in cgroup */
+ scan.process_task = cgroup_transfer_one_task;
+ scan.heap = NULL;
+ scan.data = to;
+
+ return cgroup_scan_tasks(&scan);
+}
+
/*
* Stuff for reading the 'tasks'/'procs' files.
*
@@ -3362,35 +3345,14 @@ static void pidlist_free(void *p)
else
kfree(p);
}
-static void *pidlist_resize(void *p, int newcount)
-{
- void *newlist;
- /* note: if new alloc fails, old p will still be valid either way */
- if (is_vmalloc_addr(p)) {
- newlist = vmalloc(newcount * sizeof(pid_t));
- if (!newlist)
- return NULL;
- memcpy(newlist, p, newcount * sizeof(pid_t));
- vfree(p);
- } else {
- newlist = krealloc(p, newcount * sizeof(pid_t), GFP_KERNEL);
- }
- return newlist;
-}
/*
* pidlist_uniq - given a kmalloc()ed list, strip out all duplicate entries
- * If the new stripped list is sufficiently smaller and there's enough memory
- * to allocate a new buffer, will let go of the unneeded memory. Returns the
- * number of unique elements.
+ * Returns the number of unique elements.
*/
-/* is the size difference enough that we should re-allocate the array? */
-#define PIDLIST_REALLOC_DIFFERENCE(old, new) ((old) - PAGE_SIZE >= (new))
-static int pidlist_uniq(pid_t **p, int length)
+static int pidlist_uniq(pid_t *list, int length)
{
int src, dest = 1;
- pid_t *list = *p;
- pid_t *newlist;
/*
* we presume the 0th element is unique, so i starts at 1. trivial
@@ -3411,16 +3373,6 @@ static int pidlist_uniq(pid_t **p, int length)
dest++;
}
after:
- /*
- * if the length difference is large enough, we want to allocate a
- * smaller buffer to save memory. if this fails due to out of memory,
- * we'll just stay with what we've got.
- */
- if (PIDLIST_REALLOC_DIFFERENCE(length, dest)) {
- newlist = pidlist_resize(list, dest);
- if (newlist)
- *p = newlist;
- }
return dest;
}
@@ -3516,7 +3468,7 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type,
/* now sort & (if procs) strip out duplicates */
sort(array, length, sizeof(pid_t), cmppid, NULL);
if (type == CGROUP_FILE_PROCS)
- length = pidlist_uniq(&array, length);
+ length = pidlist_uniq(array, length);
l = cgroup_pidlist_find(cgrp, type);
if (!l) {
pidlist_free(array);
@@ -3930,11 +3882,7 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
if (ret)
goto fail;
- if (efile->f_op->poll(efile, &event->pt) & POLLHUP) {
- event->cft->unregister_event(cgrp, event->cft, event->eventfd);
- ret = 0;
- goto fail;
- }
+ efile->f_op->poll(efile, &event->pt);
/*
* Events should be removed after rmdir of cgroup directory, but before
@@ -4016,10 +3964,16 @@ static struct cftype files[] = {
},
{
.name = "cgroup.clone_children",
+ .flags = CFTYPE_INSANE,
.read_u64 = cgroup_clone_children_read,
.write_u64 = cgroup_clone_children_write,
},
{
+ .name = "cgroup.sane_behavior",
+ .flags = CFTYPE_ONLY_ON_ROOT,
+ .read_seq_string = cgroup_sane_behavior_show,
+ },
+ {
.name = "release_agent",
.flags = CFTYPE_ONLY_ON_ROOT,
.read_seq_string = cgroup_release_agent_show,
@@ -4131,17 +4085,8 @@ static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
if (!(css->flags & CSS_ONLINE))
return;
- /*
- * css_offline() should be called with cgroup_mutex unlocked. See
- * 3fa59dfbc3 ("cgroup: fix potential deadlock in pre_destroy") for
- * details. This temporary unlocking should go away once
- * cgroup_mutex is unexported from controllers.
- */
- if (ss->css_offline) {
- mutex_unlock(&cgroup_mutex);
+ if (ss->css_offline)
ss->css_offline(cgrp);
- mutex_lock(&cgroup_mutex);
- }
cgrp->subsys[ss->subsys_id]->flags &= ~CSS_ONLINE;
}
@@ -4158,6 +4103,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
umode_t mode)
{
struct cgroup *cgrp;
+ struct cgroup_name *name;
struct cgroupfs_root *root = parent->root;
int err = 0;
struct cgroup_subsys *ss;
@@ -4168,9 +4114,14 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
if (!cgrp)
return -ENOMEM;
+ name = cgroup_alloc_name(dentry);
+ if (!name)
+ goto err_free_cgrp;
+ rcu_assign_pointer(cgrp->name, name);
+
cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
if (cgrp->id < 0)
- goto err_free_cgrp;
+ goto err_free_name;
/*
* Only live parents can have children. Note that the liveliness
@@ -4198,7 +4149,6 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
cgrp->parent = parent;
cgrp->root = parent->root;
- cgrp->top_cgroup = parent->top_cgroup;
if (notify_on_release(parent))
set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -4241,6 +4191,9 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
for_each_subsys(root, ss)
dget(dentry);
+ /* hold a ref to the parent's dentry */
+ dget(parent->dentry);
+
/* creation succeeded, notify subsystems */
for_each_subsys(root, ss) {
err = online_css(ss, cgrp);
@@ -4276,6 +4229,8 @@ err_free_all:
deactivate_super(sb);
err_free_id:
ida_simple_remove(&root->cgroup_ida, cgrp->id);
+err_free_name:
+ kfree(rcu_dereference_raw(cgrp->name));
err_free_cgrp:
kfree(cgrp);
return err;
@@ -4295,56 +4250,13 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
return cgroup_create(c_parent, dentry, mode | S_IFDIR);
}
-/*
- * Check the reference count on each subsystem. Since we already
- * established that there are no tasks in the cgroup, if the css refcount
- * is also 1, then there should be no outstanding references, so the
- * subsystem is safe to destroy. We scan across all subsystems rather than
- * using the per-hierarchy linked list of mounted subsystems since we can
- * be called via check_for_release() with no synchronization other than
- * RCU, and the subsystem linked list isn't RCU-safe.
- */
-static int cgroup_has_css_refs(struct cgroup *cgrp)
-{
- int i;
-
- /*
- * We won't need to lock the subsys array, because the subsystems
- * we're concerned about aren't going anywhere since our cgroup root
- * has a reference on them.
- */
- for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
- struct cgroup_subsys *ss = subsys[i];
- struct cgroup_subsys_state *css;
-
- /* Skip subsystems not present or not in this hierarchy */
- if (ss == NULL || ss->root != cgrp->root)
- continue;
-
- css = cgrp->subsys[ss->subsys_id];
- /*
- * When called from check_for_release() it's possible
- * that by this point the cgroup has been removed
- * and the css deleted. But a false-positive doesn't
- * matter, since it can only happen if the cgroup
- * has been deleted and hence no longer needs the
- * release agent to be called anyway.
- */
- if (css && css_refcnt(css) > 1)
- return 1;
- }
- return 0;
-}
-
static int cgroup_destroy_locked(struct cgroup *cgrp)
__releases(&cgroup_mutex) __acquires(&cgroup_mutex)
{
struct dentry *d = cgrp->dentry;
struct cgroup *parent = cgrp->parent;
- DEFINE_WAIT(wait);
struct cgroup_event *event, *tmp;
struct cgroup_subsys *ss;
- LIST_HEAD(tmp_list);
lockdep_assert_held(&d->d_inode->i_mutex);
lockdep_assert_held(&cgroup_mutex);
@@ -4468,7 +4380,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
* need to invoke fork callbacks here. */
BUG_ON(!list_empty(&init_task.tasks));
- ss->active = 1;
BUG_ON(online_css(ss, dummytop));
mutex_unlock(&cgroup_mutex);
@@ -4573,7 +4484,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
}
write_unlock(&css_set_lock);
- ss->active = 1;
ret = online_css(ss, dummytop);
if (ret)
goto err_unload;
@@ -4614,7 +4524,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
mutex_lock(&cgroup_mutex);
offline_css(ss, dummytop);
- ss->active = 0;
if (ss->use_id)
idr_destroy(&ss->idr);
@@ -4922,17 +4831,17 @@ void cgroup_post_fork(struct task_struct *child)
* and addition to css_set.
*/
if (need_forkexit_callback) {
- for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+ /*
+ * fork/exit callbacks are supported only for builtin
+ * subsystems, and the builtin section of the subsys
+ * array is immutable, so we don't need to lock the
+ * subsys array here. On the other hand, modular section
+ * of the array can be freed at module unload, so we
+ * can't touch that.
+ */
+ for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
struct cgroup_subsys *ss = subsys[i];
- /*
- * fork/exit callbacks are supported only for
- * builtin subsystems and we don't need further
- * synchronization as they never go away.
- */
- if (!ss || ss->module)
- continue;
-
if (ss->fork)
ss->fork(child);
}
@@ -4997,13 +4906,13 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
tsk->cgroups = &init_css_set;
if (run_callbacks && need_forkexit_callback) {
- for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+ /*
+ * fork/exit callbacks are supported only for builtin
+ * subsystems, see cgroup_post_fork() for details.
+ */
+ for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
struct cgroup_subsys *ss = subsys[i];
- /* modular subsystems can't use callbacks */
- if (!ss || ss->module)
- continue;
-
if (ss->exit) {
struct cgroup *old_cgrp =
rcu_dereference_raw(cg->subsys[i])->cgroup;
@@ -5017,44 +4926,19 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
put_css_set_taskexit(cg);
}
-/**
- * cgroup_is_descendant - see if @cgrp is a descendant of @task's cgrp
- * @cgrp: the cgroup in question
- * @task: the task in question
- *
- * See if @cgrp is a descendant of @task's cgroup in the appropriate
- * hierarchy.
- *
- * If we are sending in dummytop, then presumably we are creating
- * the top cgroup in the subsystem.
- *
- * Called only by the ns (nsproxy) cgroup.
- */
-int cgroup_is_descendant(const struct cgroup *cgrp, struct task_struct *task)
-{
- int ret;
- struct cgroup *target;
-
- if (cgrp == dummytop)
- return 1;
-
- target = task_cgroup_from_root(task, cgrp->root);
- while (cgrp != target && cgrp!= cgrp->top_cgroup)
- cgrp = cgrp->parent;
- ret = (cgrp == target);
- return ret;
-}
-
static void check_for_release(struct cgroup *cgrp)
{
/* All of these checks rely on RCU to keep the cgroup
* structure alive */
- if (cgroup_is_releasable(cgrp) && !atomic_read(&cgrp->count)
- && list_empty(&cgrp->children) && !cgroup_has_css_refs(cgrp)) {
- /* Control Group is currently removeable. If it's not
+ if (cgroup_is_releasable(cgrp) &&
+ !atomic_read(&cgrp->count) && list_empty(&cgrp->children)) {
+ /*
+ * Control Group is currently removeable. If it's not
* already queued for a userspace notification, queue
- * it now */
+ * it now
+ */
int need_schedule_work = 0;
+
raw_spin_lock(&release_list_lock);
if (!cgroup_is_removed(cgrp) &&
list_empty(&cgrp->release_list)) {
@@ -5087,24 +4971,11 @@ EXPORT_SYMBOL_GPL(__css_tryget);
/* Caller must verify that the css is not for root cgroup */
void __css_put(struct cgroup_subsys_state *css)
{
- struct cgroup *cgrp = css->cgroup;
int v;
- rcu_read_lock();
v = css_unbias_refcnt(atomic_dec_return(&css->refcnt));
-
- switch (v) {
- case 1:
- if (notify_on_release(cgrp)) {
- set_bit(CGRP_RELEASABLE, &cgrp->flags);
- check_for_release(cgrp);
- }
- break;
- case 0:
+ if (v == 0)
schedule_work(&css->dput_work);
- break;
- }
- rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(__css_put);
@@ -5403,55 +5274,6 @@ struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id)
}
EXPORT_SYMBOL_GPL(css_lookup);
-/**
- * css_get_next - lookup next cgroup under specified hierarchy.
- * @ss: pointer to subsystem
- * @id: current position of iteration.
- * @root: pointer to css. search tree under this.
- * @foundid: position of found object.
- *
- * Search next css under the specified hierarchy of rootid. Calling under
- * rcu_read_lock() is necessary. Returns NULL if it reaches the end.
- */
-struct cgroup_subsys_state *
-css_get_next(struct cgroup_subsys *ss, int id,
- struct cgroup_subsys_state *root, int *foundid)
-{
- struct cgroup_subsys_state *ret = NULL;
- struct css_id *tmp;
- int tmpid;
- int rootid = css_id(root);
- int depth = css_depth(root);
-
- if (!rootid)
- return NULL;
-
- BUG_ON(!ss->use_id);
- WARN_ON_ONCE(!rcu_read_lock_held());
-
- /* fill start point for scan */
- tmpid = id;
- while (1) {
- /*
- * scan next entry from bitmap(tree), tmpid is updated after
- * idr_get_next().
- */
- tmp = idr_get_next(&ss->idr, &tmpid);
- if (!tmp)
- break;
- if (tmp->depth >= depth && tmp->stack[depth] == rootid) {
- ret = rcu_dereference(tmp->css);
- if (ret) {
- *foundid = tmpid;
- break;
- }
- }
- /* continue to scan from next id */
- tmpid = tmpid + 1;
- }
- return ret;
-}
-
/*
* get corresponding css from file open on cgroupfs directory
*/
diff --git a/kernel/compat.c b/kernel/compat.c
index 19971d8c7299..0a09e481b70b 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -516,25 +516,6 @@ int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
return 0;
}
-asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
-{
- struct rusage r;
- int ret;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- ret = sys_getrusage(who, (struct rusage __user *) &r);
- set_fs(old_fs);
-
- if (ret)
- return ret;
-
- if (put_compat_rusage(&r, ru))
- return -EFAULT;
-
- return 0;
-}
-
COMPAT_SYSCALL_DEFINE4(wait4,
compat_pid_t, pid,
compat_uint_t __user *, stat_addr,
@@ -1138,71 +1119,6 @@ asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
}
#endif
-struct compat_sysinfo {
- s32 uptime;
- u32 loads[3];
- u32 totalram;
- u32 freeram;
- u32 sharedram;
- u32 bufferram;
- u32 totalswap;
- u32 freeswap;
- u16 procs;
- u16 pad;
- u32 totalhigh;
- u32 freehigh;
- u32 mem_unit;
- char _f[20-2*sizeof(u32)-sizeof(int)];
-};
-
-asmlinkage long
-compat_sys_sysinfo(struct compat_sysinfo __user *info)
-{
- struct sysinfo s;
-
- do_sysinfo(&s);
-
- /* Check to see if any memory value is too large for 32-bit and scale
- * down if needed
- */
- if ((s.totalram >> 32) || (s.totalswap >> 32)) {
- int bitcount = 0;
-
- while (s.mem_unit < PAGE_SIZE) {
- s.mem_unit <<= 1;
- bitcount++;
- }
-
- s.totalram >>= bitcount;
- s.freeram >>= bitcount;
- s.sharedram >>= bitcount;
- s.bufferram >>= bitcount;
- s.totalswap >>= bitcount;
- s.freeswap >>= bitcount;
- s.totalhigh >>= bitcount;
- s.freehigh >>= bitcount;
- }
-
- if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) ||
- __put_user (s.uptime, &info->uptime) ||
- __put_user (s.loads[0], &info->loads[0]) ||
- __put_user (s.loads[1], &info->loads[1]) ||
- __put_user (s.loads[2], &info->loads[2]) ||
- __put_user (s.totalram, &info->totalram) ||
- __put_user (s.freeram, &info->freeram) ||
- __put_user (s.sharedram, &info->sharedram) ||
- __put_user (s.bufferram, &info->bufferram) ||
- __put_user (s.totalswap, &info->totalswap) ||
- __put_user (s.freeswap, &info->freeswap) ||
- __put_user (s.procs, &info->procs) ||
- __put_user (s.totalhigh, &info->totalhigh) ||
- __put_user (s.freehigh, &info->freehigh) ||
- __put_user (s.mem_unit, &info->mem_unit))
- return -EFAULT;
-
- return 0;
-}
-
COMPAT_SYSCALL_DEFINE2(sched_rr_get_interval,
compat_pid_t, pid,
struct compat_timespec __user *, interval)
diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile
new file mode 100644
index 000000000000..59ab052ef7a0
--- /dev/null
+++ b/kernel/cpu/Makefile
@@ -0,0 +1 @@
+obj-y = idle.o
diff --git a/kernel/cpu/idle.c b/kernel/cpu/idle.c
new file mode 100644
index 000000000000..8b86c0c68edf
--- /dev/null
+++ b/kernel/cpu/idle.c
@@ -0,0 +1,116 @@
+/*
+ * Generic entry point for the idle threads
+ */
+#include <linux/sched.h>
+#include <linux/cpu.h>
+#include <linux/tick.h>
+#include <linux/mm.h>
+
+#include <asm/tlb.h>
+
+#include <trace/events/power.h>
+
+static int __read_mostly cpu_idle_force_poll;
+
+void cpu_idle_poll_ctrl(bool enable)
+{
+ if (enable) {
+ cpu_idle_force_poll++;
+ } else {
+ cpu_idle_force_poll--;
+ WARN_ON_ONCE(cpu_idle_force_poll < 0);
+ }
+}
+
+#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP
+static int __init cpu_idle_poll_setup(char *__unused)
+{
+ cpu_idle_force_poll = 1;
+ return 1;
+}
+__setup("nohlt", cpu_idle_poll_setup);
+
+static int __init cpu_idle_nopoll_setup(char *__unused)
+{
+ cpu_idle_force_poll = 0;
+ return 1;
+}
+__setup("hlt", cpu_idle_nopoll_setup);
+#endif
+
+static inline int cpu_idle_poll(void)
+{
+ trace_cpu_idle_rcuidle(0, smp_processor_id());
+ local_irq_enable();
+ while (!need_resched())
+ cpu_relax();
+ trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
+ return 1;
+}
+
+/* Weak implementations for optional arch specific functions */
+void __weak arch_cpu_idle_prepare(void) { }
+void __weak arch_cpu_idle_enter(void) { }
+void __weak arch_cpu_idle_exit(void) { }
+void __weak arch_cpu_idle_dead(void) { }
+void __weak arch_cpu_idle(void)
+{
+ cpu_idle_force_poll = 1;
+}
+
+/*
+ * Generic idle loop implementation
+ */
+static void cpu_idle_loop(void)
+{
+ while (1) {
+ tick_nohz_idle_enter();
+
+ while (!need_resched()) {
+ check_pgt_cache();
+ rmb();
+
+ if (cpu_is_offline(smp_processor_id()))
+ arch_cpu_idle_dead();
+
+ local_irq_disable();
+ arch_cpu_idle_enter();
+
+ /*
+ * In poll mode we reenable interrupts and spin.
+ *
+ * Also if we detected in the wakeup from idle
+ * path that the tick broadcast device expired
+ * for us, we don't want to go deep idle as we
+ * know that the IPI is going to arrive right
+ * away
+ */
+ if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
+ cpu_idle_poll();
+ } else {
+ current_clr_polling();
+ if (!need_resched()) {
+ stop_critical_timings();
+ rcu_idle_enter();
+ arch_cpu_idle();
+ WARN_ON_ONCE(irqs_disabled());
+ rcu_idle_exit();
+ start_critical_timings();
+ } else {
+ local_irq_enable();
+ }
+ current_set_polling();
+ }
+ arch_cpu_idle_exit();
+ }
+ tick_nohz_idle_exit();
+ schedule_preempt_disabled();
+ }
+}
+
+void cpu_startup_entry(enum cpuhp_state state)
+{
+ current_set_polling();
+ arch_cpu_idle_prepare();
+ cpu_idle_loop();
+}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 1b6f615be587..64b3f791bbe5 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -265,17 +265,6 @@ static DEFINE_MUTEX(cpuset_mutex);
static DEFINE_MUTEX(callback_mutex);
/*
- * cpuset_buffer_lock protects both the cpuset_name and cpuset_nodelist
- * buffers. They are statically allocated to prevent using excess stack
- * when calling cpuset_print_task_mems_allowed().
- */
-#define CPUSET_NAME_LEN (128)
-#define CPUSET_NODELIST_LEN (256)
-static char cpuset_name[CPUSET_NAME_LEN];
-static char cpuset_nodelist[CPUSET_NODELIST_LEN];
-static DEFINE_SPINLOCK(cpuset_buffer_lock);
-
-/*
* CPU / memory hotplug is handled asynchronously.
*/
static struct workqueue_struct *cpuset_propagate_hotplug_wq;
@@ -780,25 +769,26 @@ static void rebuild_sched_domains_locked(void)
lockdep_assert_held(&cpuset_mutex);
get_online_cpus();
+ /*
+ * We have raced with CPU hotplug. Don't do anything to avoid
+ * passing doms with offlined cpu to partition_sched_domains().
+ * Anyways, hotplug work item will rebuild sched domains.
+ */
+ if (!cpumask_equal(top_cpuset.cpus_allowed, cpu_active_mask))
+ goto out;
+
/* Generate domain masks and attrs */
ndoms = generate_sched_domains(&doms, &attr);
/* Have scheduler rebuild the domains */
partition_sched_domains(ndoms, doms, attr);
-
+out:
put_online_cpus();
}
#else /* !CONFIG_SMP */
static void rebuild_sched_domains_locked(void)
{
}
-
-static int generate_sched_domains(cpumask_var_t **domains,
- struct sched_domain_attr **attributes)
-{
- *domains = NULL;
- return 1;
-}
#endif /* CONFIG_SMP */
void rebuild_sched_domains(void)
@@ -1388,16 +1378,16 @@ static int cpuset_can_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
cgroup_taskset_for_each(task, cgrp, tset) {
/*
- * Kthreads bound to specific cpus cannot be moved to a new
- * cpuset; we cannot change their cpu affinity and
- * isolating such threads by their set of allowed nodes is
- * unnecessary. Thus, cpusets are not applicable for such
- * threads. This prevents checking for success of
- * set_cpus_allowed_ptr() on all attached tasks before
- * cpus_allowed may be changed.
+ * Kthreads which disallow setaffinity shouldn't be moved
+ * to a new cpuset; we don't want to change their cpu
+ * affinity and isolating such threads by their set of
+ * allowed nodes is unnecessary. Thus, cpusets are not
+ * applicable for such threads. This prevents checking for
+ * success of set_cpus_allowed_ptr() on all attached tasks
+ * before cpus_allowed may be changed.
*/
ret = -EINVAL;
- if (task->flags & PF_THREAD_BOUND)
+ if (task->flags & PF_NO_SETAFFINITY)
goto out_unlock;
ret = security_task_setscheduler(task);
if (ret)
@@ -2005,50 +1995,6 @@ int __init cpuset_init(void)
return 0;
}
-/**
- * cpuset_do_move_task - move a given task to another cpuset
- * @tsk: pointer to task_struct the task to move
- * @scan: struct cgroup_scanner contained in its struct cpuset_hotplug_scanner
- *
- * Called by cgroup_scan_tasks() for each task in a cgroup.
- * Return nonzero to stop the walk through the tasks.
- */
-static void cpuset_do_move_task(struct task_struct *tsk,
- struct cgroup_scanner *scan)
-{
- struct cgroup *new_cgroup = scan->data;
-
- cgroup_lock();
- cgroup_attach_task(new_cgroup, tsk);
- cgroup_unlock();
-}
-
-/**
- * move_member_tasks_to_cpuset - move tasks from one cpuset to another
- * @from: cpuset in which the tasks currently reside
- * @to: cpuset to which the tasks will be moved
- *
- * Called with cpuset_mutex held
- * callback_mutex must not be held, as cpuset_attach() will take it.
- *
- * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
- * calling callback functions for each.
- */
-static void move_member_tasks_to_cpuset(struct cpuset *from, struct cpuset *to)
-{
- struct cgroup_scanner scan;
-
- scan.cg = from->css.cgroup;
- scan.test_task = NULL; /* select all tasks in cgroup */
- scan.process_task = cpuset_do_move_task;
- scan.heap = NULL;
- scan.data = to->css.cgroup;
-
- if (cgroup_scan_tasks(&scan))
- printk(KERN_ERR "move_member_tasks_to_cpuset: "
- "cgroup_scan_tasks failed\n");
-}
-
/*
* If CPU and/or memory hotplug handlers, below, unplug any CPUs
* or memory nodes, we need to walk over the cpuset hierarchy,
@@ -2069,7 +2015,12 @@ static void remove_tasks_in_empty_cpuset(struct cpuset *cs)
nodes_empty(parent->mems_allowed))
parent = parent_cs(parent);
- move_member_tasks_to_cpuset(cs, parent);
+ if (cgroup_transfer_tasks(parent->css.cgroup, cs->css.cgroup)) {
+ rcu_read_lock();
+ printk(KERN_ERR "cpuset: failed to transfer tasks out of empty cpuset %s\n",
+ cgroup_name(cs->css.cgroup));
+ rcu_read_unlock();
+ }
}
/**
@@ -2222,17 +2173,8 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
flush_workqueue(cpuset_propagate_hotplug_wq);
/* rebuild sched domains if cpus_allowed has changed */
- if (cpus_updated) {
- struct sched_domain_attr *attr;
- cpumask_var_t *doms;
- int ndoms;
-
- mutex_lock(&cpuset_mutex);
- ndoms = generate_sched_domains(&doms, &attr);
- mutex_unlock(&cpuset_mutex);
-
- partition_sched_domains(ndoms, doms, attr);
- }
+ if (cpus_updated)
+ rebuild_sched_domains();
}
void cpuset_update_active_cpus(bool cpu_online)
@@ -2251,7 +2193,6 @@ void cpuset_update_active_cpus(bool cpu_online)
schedule_work(&cpuset_hotplug_work);
}
-#ifdef CONFIG_MEMORY_HOTPLUG
/*
* Keep top_cpuset.mems_allowed tracking node_states[N_MEMORY].
* Call this routine anytime after node_states[N_MEMORY] changes.
@@ -2263,20 +2204,23 @@ static int cpuset_track_online_nodes(struct notifier_block *self,
schedule_work(&cpuset_hotplug_work);
return NOTIFY_OK;
}
-#endif
+
+static struct notifier_block cpuset_track_online_nodes_nb = {
+ .notifier_call = cpuset_track_online_nodes,
+ .priority = 10, /* ??! */
+};
/**
* cpuset_init_smp - initialize cpus_allowed
*
* Description: Finish top cpuset after cpu, node maps are initialized
- **/
-
+ */
void __init cpuset_init_smp(void)
{
cpumask_copy(top_cpuset.cpus_allowed, cpu_active_mask);
top_cpuset.mems_allowed = node_states[N_MEMORY];
- hotplug_memory_notifier(cpuset_track_online_nodes, 10);
+ register_hotmemory_notifier(&cpuset_track_online_nodes_nb);
cpuset_propagate_hotplug_wq =
alloc_ordered_workqueue("cpuset_hotplug", 0);
@@ -2592,6 +2536,8 @@ int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
return nodes_intersects(tsk1->mems_allowed, tsk2->mems_allowed);
}
+#define CPUSET_NODELIST_LEN (256)
+
/**
* cpuset_print_task_mems_allowed - prints task's cpuset and mems_allowed
* @task: pointer to task_struct of some task.
@@ -2602,25 +2548,22 @@ int cpuset_mems_allowed_intersects(const struct task_struct *tsk1,
*/
void cpuset_print_task_mems_allowed(struct task_struct *tsk)
{
- struct dentry *dentry;
+ /* Statically allocated to prevent using excess stack. */
+ static char cpuset_nodelist[CPUSET_NODELIST_LEN];
+ static DEFINE_SPINLOCK(cpuset_buffer_lock);
- dentry = task_cs(tsk)->css.cgroup->dentry;
- spin_lock(&cpuset_buffer_lock);
+ struct cgroup *cgrp = task_cs(tsk)->css.cgroup;
- if (!dentry) {
- strcpy(cpuset_name, "/");
- } else {
- spin_lock(&dentry->d_lock);
- strlcpy(cpuset_name, (const char *)dentry->d_name.name,
- CPUSET_NAME_LEN);
- spin_unlock(&dentry->d_lock);
- }
+ rcu_read_lock();
+ spin_lock(&cpuset_buffer_lock);
nodelist_scnprintf(cpuset_nodelist, CPUSET_NODELIST_LEN,
tsk->mems_allowed);
printk(KERN_INFO "%s cpuset=%s mems_allowed=%s\n",
- tsk->comm, cpuset_name, cpuset_nodelist);
+ tsk->comm, cgroup_name(cgrp), cpuset_nodelist);
+
spin_unlock(&cpuset_buffer_lock);
+ rcu_read_unlock();
}
/*
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c
index c26278fd4851..0506d447aed2 100644
--- a/kernel/debug/debug_core.c
+++ b/kernel/debug/debug_core.c
@@ -775,7 +775,7 @@ static void sysrq_handle_dbg(int key)
static struct sysrq_key_op sysrq_dbg_op = {
.handler = sysrq_handle_dbg,
- .help_msg = "debug(G)",
+ .help_msg = "debug(g)",
.action_msg = "DEBUG",
};
#endif
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 59412d037eed..3820e3cefbae 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -37,6 +37,7 @@
#include <linux/ftrace_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/mm_types.h>
+#include <linux/cgroup.h>
#include "internal.h"
@@ -234,6 +235,20 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx,
#ifdef CONFIG_CGROUP_PERF
/*
+ * perf_cgroup_info keeps track of time_enabled for a cgroup.
+ * This is a per-cpu dynamically allocated data structure.
+ */
+struct perf_cgroup_info {
+ u64 time;
+ u64 timestamp;
+};
+
+struct perf_cgroup {
+ struct cgroup_subsys_state css;
+ struct perf_cgroup_info __percpu *info;
+};
+
+/*
* Must ensure cgroup is pinned (css_get) before calling
* this function. In other words, we cannot call this function
* if there is no cgroup event for the current CPU context.
@@ -251,7 +266,22 @@ perf_cgroup_match(struct perf_event *event)
struct perf_event_context *ctx = event->ctx;
struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
- return !event->cgrp || event->cgrp == cpuctx->cgrp;
+ /* @event doesn't care about cgroup */
+ if (!event->cgrp)
+ return true;
+
+ /* wants specific cgroup scope but @cpuctx isn't associated with any */
+ if (!cpuctx->cgrp)
+ return false;
+
+ /*
+ * Cgroup scoping is recursive. An event enabled for a cgroup is
+ * also enabled for all its descendant cgroups. If @cpuctx's
+ * cgroup is a descendant of @event's (the test covers identity
+ * case), it's a match.
+ */
+ return cgroup_is_descendant(cpuctx->cgrp->css.cgroup,
+ event->cgrp->css.cgroup);
}
static inline bool perf_tryget_cgroup(struct perf_event *event)
@@ -961,9 +991,15 @@ static void perf_event__header_size(struct perf_event *event)
if (sample_type & PERF_SAMPLE_PERIOD)
size += sizeof(data->period);
+ if (sample_type & PERF_SAMPLE_WEIGHT)
+ size += sizeof(data->weight);
+
if (sample_type & PERF_SAMPLE_READ)
size += event->read_size;
+ if (sample_type & PERF_SAMPLE_DATA_SRC)
+ size += sizeof(data->data_src.val);
+
event->header_size = size;
}
@@ -4178,6 +4214,12 @@ void perf_output_sample(struct perf_output_handle *handle,
perf_output_sample_ustack(handle,
data->stack_user_size,
data->regs_user.regs);
+
+ if (sample_type & PERF_SAMPLE_WEIGHT)
+ perf_output_put(handle, data->weight);
+
+ if (sample_type & PERF_SAMPLE_DATA_SRC)
+ perf_output_put(handle, data->data_src.val);
}
void perf_prepare_sample(struct perf_event_header *header,
@@ -4596,6 +4638,7 @@ void perf_event_comm(struct task_struct *task)
struct perf_event_context *ctx;
int ctxn;
+ rcu_read_lock();
for_each_task_context_nr(ctxn) {
ctx = task->perf_event_ctxp[ctxn];
if (!ctx)
@@ -4603,6 +4646,7 @@ void perf_event_comm(struct task_struct *task)
perf_event_enable_on_exec(ctx);
}
+ rcu_read_unlock();
if (!atomic_read(&nr_comm_events))
return;
@@ -4737,7 +4781,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
} else {
if (arch_vma_name(mmap_event->vma)) {
name = strncpy(tmp, arch_vma_name(mmap_event->vma),
- sizeof(tmp));
+ sizeof(tmp) - 1);
+ tmp[sizeof(tmp) - 1] = '\0';
goto got_name;
}
@@ -4764,6 +4809,9 @@ got_name:
mmap_event->file_name = name;
mmap_event->file_size = size;
+ if (!(vma->vm_flags & VM_EXEC))
+ mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
+
mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
rcu_read_lock();
@@ -5330,7 +5378,7 @@ static void sw_perf_event_destroy(struct perf_event *event)
static int perf_swevent_init(struct perf_event *event)
{
- int event_id = event->attr.config;
+ u64 event_id = event->attr.config;
if (event->attr.type != PERF_TYPE_SOFTWARE)
return -ENOENT;
@@ -5986,6 +6034,7 @@ skip_type:
if (pmu->pmu_cpu_context)
goto got_cpu_context;
+ ret = -ENOMEM;
pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
if (!pmu->pmu_cpu_context)
goto free_dev;
@@ -7513,12 +7562,5 @@ struct cgroup_subsys perf_subsys = {
.css_free = perf_cgroup_css_free,
.exit = perf_cgroup_exit,
.attach = perf_cgroup_attach,
-
- /*
- * perf_event cgroup doesn't handle nesting correctly.
- * ctx->nr_cgroups adjustments should be propagated through the
- * cgroup hierarchy. Fix it and remove the following.
- */
- .broken_hierarchy = true,
};
#endif /* CONFIG_CGROUP_PERF */
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index d56a64c99a8b..eb675c4d59df 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -16,7 +16,7 @@ struct ring_buffer {
int page_order; /* allocation order */
#endif
int nr_pages; /* nr of data pages */
- int writable; /* are we writable */
+ int overwrite; /* can overwrite itself */
atomic_t poll; /* POLL_ for wakeups */
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 23cb34ff3973..97fddb09762b 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -18,12 +18,24 @@
static bool perf_output_space(struct ring_buffer *rb, unsigned long tail,
unsigned long offset, unsigned long head)
{
- unsigned long mask;
+ unsigned long sz = perf_data_size(rb);
+ unsigned long mask = sz - 1;
- if (!rb->writable)
+ /*
+ * check if user-writable
+ * overwrite : over-write its own tail
+ * !overwrite: buffer possibly drops events.
+ */
+ if (rb->overwrite)
return true;
- mask = perf_data_size(rb) - 1;
+ /*
+ * verify that payload is not bigger than buffer
+ * otherwise masking logic may fail to detect
+ * the "not enough space" condition
+ */
+ if ((head - offset) > sz)
+ return false;
offset = (offset - tail) & mask;
head = (head - tail) & mask;
@@ -212,7 +224,9 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
rb->watermark = max_size / 2;
if (flags & RING_BUFFER_WRITABLE)
- rb->writable = 1;
+ rb->overwrite = 0;
+ else
+ rb->overwrite = 1;
atomic_set(&rb->refcount, 1);
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index a567c8c7ef31..f3569747d629 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -75,6 +75,15 @@ struct uprobe {
struct arch_uprobe arch;
};
+struct return_instance {
+ struct uprobe *uprobe;
+ unsigned long func;
+ unsigned long orig_ret_vaddr; /* original return address */
+ bool chained; /* true, if instance is nested */
+
+ struct return_instance *next; /* keep as stack */
+};
+
/*
* valid_vma: Verify if the specified vma is an executable vma
* Relax restrictions while unregistering: vm_flags might have
@@ -173,10 +182,31 @@ bool __weak is_swbp_insn(uprobe_opcode_t *insn)
return *insn == UPROBE_SWBP_INSN;
}
-static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode)
+/**
+ * is_trap_insn - check if instruction is breakpoint instruction.
+ * @insn: instruction to be checked.
+ * Default implementation of is_trap_insn
+ * Returns true if @insn is a breakpoint instruction.
+ *
+ * This function is needed for the case where an architecture has multiple
+ * trap instructions (like powerpc).
+ */
+bool __weak is_trap_insn(uprobe_opcode_t *insn)
+{
+ return is_swbp_insn(insn);
+}
+
+static void copy_from_page(struct page *page, unsigned long vaddr, void *dst, int len)
{
void *kaddr = kmap_atomic(page);
- memcpy(opcode, kaddr + (vaddr & ~PAGE_MASK), UPROBE_SWBP_INSN_SIZE);
+ memcpy(dst, kaddr + (vaddr & ~PAGE_MASK), len);
+ kunmap_atomic(kaddr);
+}
+
+static void copy_to_page(struct page *page, unsigned long vaddr, const void *src, int len)
+{
+ void *kaddr = kmap_atomic(page);
+ memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len);
kunmap_atomic(kaddr);
}
@@ -185,7 +215,16 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
uprobe_opcode_t old_opcode;
bool is_swbp;
- copy_opcode(page, vaddr, &old_opcode);
+ /*
+ * Note: We only check if the old_opcode is UPROBE_SWBP_INSN here.
+ * We do not check if it is any other 'trap variant' which could
+ * be conditional trap instruction such as the one powerpc supports.
+ *
+ * The logic is that we do not care if the underlying instruction
+ * is a trap variant; uprobes always wins over any other (gdb)
+ * breakpoint.
+ */
+ copy_from_page(page, vaddr, &old_opcode, UPROBE_SWBP_INSN_SIZE);
is_swbp = is_swbp_insn(&old_opcode);
if (is_swbp_insn(new_opcode)) {
@@ -204,7 +243,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
* Expect the breakpoint instruction to be the smallest size instruction for
* the architecture. If an arch has variable length instruction and the
* breakpoint instruction is not of the smallest length instruction
- * supported by that architecture then we need to modify is_swbp_at_addr and
+ * supported by that architecture then we need to modify is_trap_at_addr and
* write_opcode accordingly. This would never be a problem for archs that
* have fixed length instructions.
*/
@@ -225,7 +264,6 @@ static int write_opcode(struct mm_struct *mm, unsigned long vaddr,
uprobe_opcode_t opcode)
{
struct page *old_page, *new_page;
- void *vaddr_old, *vaddr_new;
struct vm_area_struct *vma;
int ret;
@@ -246,15 +284,8 @@ retry:
__SetPageUptodate(new_page);
- /* copy the page now that we've got it stable */
- vaddr_old = kmap_atomic(old_page);
- vaddr_new = kmap_atomic(new_page);
-
- memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
- memcpy(vaddr_new + (vaddr & ~PAGE_MASK), &opcode, UPROBE_SWBP_INSN_SIZE);
-
- kunmap_atomic(vaddr_new);
- kunmap_atomic(vaddr_old);
+ copy_highpage(new_page, old_page);
+ copy_to_page(new_page, vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
ret = anon_vma_prepare(vma);
if (ret)
@@ -477,30 +508,18 @@ __copy_insn(struct address_space *mapping, struct file *filp, char *insn,
unsigned long nbytes, loff_t offset)
{
struct page *page;
- void *vaddr;
- unsigned long off;
- pgoff_t idx;
-
- if (!filp)
- return -EINVAL;
if (!mapping->a_ops->readpage)
return -EIO;
-
- idx = offset >> PAGE_CACHE_SHIFT;
- off = offset & ~PAGE_MASK;
-
/*
* Ensure that the page that has the original instruction is
* populated and in page-cache.
*/
- page = read_mapping_page(mapping, idx, filp);
+ page = read_mapping_page(mapping, offset >> PAGE_CACHE_SHIFT, filp);
if (IS_ERR(page))
return PTR_ERR(page);
- vaddr = kmap_atomic(page);
- memcpy(insn, vaddr + off, nbytes);
- kunmap_atomic(vaddr);
+ copy_from_page(page, offset, insn, nbytes);
page_cache_release(page);
return 0;
@@ -550,7 +569,7 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file,
goto out;
ret = -ENOTSUPP;
- if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
+ if (is_trap_insn((uprobe_opcode_t *)uprobe->arch.insn))
goto out;
ret = arch_uprobe_analyze_insn(&uprobe->arch, mm, vaddr);
@@ -758,7 +777,7 @@ register_for_each_vma(struct uprobe *uprobe, struct uprobe_consumer *new)
down_write(&mm->mmap_sem);
vma = find_vma(mm, info->vaddr);
if (!vma || !valid_vma(vma, is_register) ||
- vma->vm_file->f_mapping->host != uprobe->inode)
+ file_inode(vma->vm_file) != uprobe->inode)
goto unlock;
if (vma->vm_start > info->vaddr ||
@@ -828,6 +847,10 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
struct uprobe *uprobe;
int ret;
+ /* Uprobe must have at least one set consumer */
+ if (!uc->handler && !uc->ret_handler)
+ return -EINVAL;
+
/* Racy, just to catch the obvious mistakes */
if (offset > i_size_read(inode))
return -EINVAL;
@@ -917,7 +940,7 @@ static int unapply_uprobe(struct uprobe *uprobe, struct mm_struct *mm)
loff_t offset;
if (!valid_vma(vma, false) ||
- vma->vm_file->f_mapping->host != uprobe->inode)
+ file_inode(vma->vm_file) != uprobe->inode)
continue;
offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
@@ -1010,7 +1033,7 @@ int uprobe_mmap(struct vm_area_struct *vma)
if (no_uprobe_events() || !valid_vma(vma, true))
return 0;
- inode = vma->vm_file->f_mapping->host;
+ inode = file_inode(vma->vm_file);
if (!inode)
return 0;
@@ -1041,7 +1064,7 @@ vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long e
struct inode *inode;
struct rb_node *n;
- inode = vma->vm_file->f_mapping->host;
+ inode = file_inode(vma->vm_file);
min = vaddr_to_offset(vma, start);
max = min + (end - start) - 1;
@@ -1114,6 +1137,7 @@ static struct xol_area *get_xol_area(void)
{
struct mm_struct *mm = current->mm;
struct xol_area *area;
+ uprobe_opcode_t insn = UPROBE_SWBP_INSN;
area = mm->uprobes_state.xol_area;
if (area)
@@ -1131,7 +1155,12 @@ static struct xol_area *get_xol_area(void)
if (!area->page)
goto free_bitmap;
+ /* allocate first slot of task's xol_area for the return probes */
+ set_bit(0, area->bitmap);
+ copy_to_page(area->page, 0, &insn, UPROBE_SWBP_INSN_SIZE);
+ atomic_set(&area->slot_count, 1);
init_waitqueue_head(&area->wq);
+
if (!xol_add_vma(area))
return area;
@@ -1216,9 +1245,7 @@ static unsigned long xol_take_insn_slot(struct xol_area *area)
static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
{
struct xol_area *area;
- unsigned long offset;
unsigned long xol_vaddr;
- void *vaddr;
area = get_xol_area();
if (!area)
@@ -1229,10 +1256,7 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
return 0;
/* Initialize the slot */
- offset = xol_vaddr & ~PAGE_MASK;
- vaddr = kmap_atomic(area->page);
- memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
- kunmap_atomic(vaddr);
+ copy_to_page(area->page, xol_vaddr, uprobe->arch.insn, MAX_UINSN_BYTES);
/*
* We probably need flush_icache_user_range() but it needs vma.
* This should work on supported architectures too.
@@ -1298,6 +1322,7 @@ unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs)
void uprobe_free_utask(struct task_struct *t)
{
struct uprobe_task *utask = t->utask;
+ struct return_instance *ri, *tmp;
if (!utask)
return;
@@ -1305,6 +1330,15 @@ void uprobe_free_utask(struct task_struct *t)
if (utask->active_uprobe)
put_uprobe(utask->active_uprobe);
+ ri = utask->return_instances;
+ while (ri) {
+ tmp = ri;
+ ri = ri->next;
+
+ put_uprobe(tmp->uprobe);
+ kfree(tmp);
+ }
+
xol_free_insn_slot(t);
kfree(utask);
t->utask = NULL;
@@ -1333,6 +1367,93 @@ static struct uprobe_task *get_utask(void)
return current->utask;
}
+/*
+ * Current area->vaddr notion assume the trampoline address is always
+ * equal area->vaddr.
+ *
+ * Returns -1 in case the xol_area is not allocated.
+ */
+static unsigned long get_trampoline_vaddr(void)
+{
+ struct xol_area *area;
+ unsigned long trampoline_vaddr = -1;
+
+ area = current->mm->uprobes_state.xol_area;
+ smp_read_barrier_depends();
+ if (area)
+ trampoline_vaddr = area->vaddr;
+
+ return trampoline_vaddr;
+}
+
+static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
+{
+ struct return_instance *ri;
+ struct uprobe_task *utask;
+ unsigned long orig_ret_vaddr, trampoline_vaddr;
+ bool chained = false;
+
+ if (!get_xol_area())
+ return;
+
+ utask = get_utask();
+ if (!utask)
+ return;
+
+ if (utask->depth >= MAX_URETPROBE_DEPTH) {
+ printk_ratelimited(KERN_INFO "uprobe: omit uretprobe due to"
+ " nestedness limit pid/tgid=%d/%d\n",
+ current->pid, current->tgid);
+ return;
+ }
+
+ ri = kzalloc(sizeof(struct return_instance), GFP_KERNEL);
+ if (!ri)
+ goto fail;
+
+ trampoline_vaddr = get_trampoline_vaddr();
+ orig_ret_vaddr = arch_uretprobe_hijack_return_addr(trampoline_vaddr, regs);
+ if (orig_ret_vaddr == -1)
+ goto fail;
+
+ /*
+ * We don't want to keep trampoline address in stack, rather keep the
+ * original return address of first caller thru all the consequent
+ * instances. This also makes breakpoint unwrapping easier.
+ */
+ if (orig_ret_vaddr == trampoline_vaddr) {
+ if (!utask->return_instances) {
+ /*
+ * This situation is not possible. Likely we have an
+ * attack from user-space.
+ */
+ pr_warn("uprobe: unable to set uretprobe pid/tgid=%d/%d\n",
+ current->pid, current->tgid);
+ goto fail;
+ }
+
+ chained = true;
+ orig_ret_vaddr = utask->return_instances->orig_ret_vaddr;
+ }
+
+ atomic_inc(&uprobe->ref);
+ ri->uprobe = uprobe;
+ ri->func = instruction_pointer(regs);
+ ri->orig_ret_vaddr = orig_ret_vaddr;
+ ri->chained = chained;
+
+ utask->depth++;
+
+ /* add instance to the stack */
+ ri->next = utask->return_instances;
+ utask->return_instances = ri;
+
+ return;
+
+ fail:
+ kfree(ri);
+}
+
/* Prepare to single-step probed instruction out of line. */
static int
pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
@@ -1431,7 +1552,7 @@ static void mmf_recalc_uprobes(struct mm_struct *mm)
clear_bit(MMF_HAS_UPROBES, &mm->flags);
}
-static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
+static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
{
struct page *page;
uprobe_opcode_t opcode;
@@ -1449,10 +1570,11 @@ static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
if (result < 0)
return result;
- copy_opcode(page, vaddr, &opcode);
+ copy_from_page(page, vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
put_page(page);
out:
- return is_swbp_insn(&opcode);
+ /* This needs to return true for any variant of the trap insn */
+ return is_trap_insn(&opcode);
}
static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
@@ -1465,14 +1587,14 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
vma = find_vma(mm, bp_vaddr);
if (vma && vma->vm_start <= bp_vaddr) {
if (valid_vma(vma, false)) {
- struct inode *inode = vma->vm_file->f_mapping->host;
+ struct inode *inode = file_inode(vma->vm_file);
loff_t offset = vaddr_to_offset(vma, bp_vaddr);
uprobe = find_uprobe(inode, offset);
}
if (!uprobe)
- *is_swbp = is_swbp_at_addr(mm, bp_vaddr);
+ *is_swbp = is_trap_at_addr(mm, bp_vaddr);
} else {
*is_swbp = -EFAULT;
}
@@ -1488,16 +1610,27 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
{
struct uprobe_consumer *uc;
int remove = UPROBE_HANDLER_REMOVE;
+ bool need_prep = false; /* prepare return uprobe, when needed */
down_read(&uprobe->register_rwsem);
for (uc = uprobe->consumers; uc; uc = uc->next) {
- int rc = uc->handler(uc, regs);
+ int rc = 0;
+
+ if (uc->handler) {
+ rc = uc->handler(uc, regs);
+ WARN(rc & ~UPROBE_HANDLER_MASK,
+ "bad rc=0x%x from %pf()\n", rc, uc->handler);
+ }
+
+ if (uc->ret_handler)
+ need_prep = true;
- WARN(rc & ~UPROBE_HANDLER_MASK,
- "bad rc=0x%x from %pf()\n", rc, uc->handler);
remove &= rc;
}
+ if (need_prep && !remove)
+ prepare_uretprobe(uprobe, regs); /* put bp at return */
+
if (remove && uprobe->consumers) {
WARN_ON(!uprobe_is_active(uprobe));
unapply_uprobe(uprobe, current->mm);
@@ -1505,6 +1638,64 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
up_read(&uprobe->register_rwsem);
}
+static void
+handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
+{
+ struct uprobe *uprobe = ri->uprobe;
+ struct uprobe_consumer *uc;
+
+ down_read(&uprobe->register_rwsem);
+ for (uc = uprobe->consumers; uc; uc = uc->next) {
+ if (uc->ret_handler)
+ uc->ret_handler(uc, ri->func, regs);
+ }
+ up_read(&uprobe->register_rwsem);
+}
+
+static bool handle_trampoline(struct pt_regs *regs)
+{
+ struct uprobe_task *utask;
+ struct return_instance *ri, *tmp;
+ bool chained;
+
+ utask = current->utask;
+ if (!utask)
+ return false;
+
+ ri = utask->return_instances;
+ if (!ri)
+ return false;
+
+ /*
+ * TODO: we should throw out return_instance's invalidated by
+ * longjmp(), currently we assume that the probed function always
+ * returns.
+ */
+ instruction_pointer_set(regs, ri->orig_ret_vaddr);
+
+ for (;;) {
+ handle_uretprobe_chain(ri, regs);
+
+ chained = ri->chained;
+ put_uprobe(ri->uprobe);
+
+ tmp = ri;
+ ri = ri->next;
+ kfree(tmp);
+
+ if (!chained)
+ break;
+
+ utask->depth--;
+
+ BUG_ON(!ri);
+ }
+
+ utask->return_instances = ri;
+
+ return true;
+}
+
/*
* Run handler and ask thread to singlestep.
* Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1516,8 +1707,15 @@ static void handle_swbp(struct pt_regs *regs)
int uninitialized_var(is_swbp);
bp_vaddr = uprobe_get_swbp_addr(regs);
- uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
+ if (bp_vaddr == get_trampoline_vaddr()) {
+ if (handle_trampoline(regs))
+ return;
+
+ pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
+ current->pid, current->tgid);
+ }
+ uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
if (!uprobe) {
if (is_swbp > 0) {
/* No matching uprobe; signal SIGTRAP. */
@@ -1616,7 +1814,11 @@ void uprobe_notify_resume(struct pt_regs *regs)
*/
int uprobe_pre_sstep_notifier(struct pt_regs *regs)
{
- if (!current->mm || !test_bit(MMF_HAS_UPROBES, &current->mm->flags))
+ if (!current->mm)
+ return 0;
+
+ if (!test_bit(MMF_HAS_UPROBES, &current->mm->flags) &&
+ (!current->utask || !current->utask->return_instances))
return 0;
set_thread_flag(TIF_UPROBE);
diff --git a/kernel/exit.c b/kernel/exit.c
index cd9e9e799bd2..af2eb3cbd499 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -835,7 +835,7 @@ void do_exit(long code)
/*
* Make sure we are holding no locks:
*/
- debug_check_no_locks_held();
+ debug_check_no_locks_held(tsk);
/*
* We can do this unlocked here. The futex code uses this flag
* just to verify whether the pi state cleanup has been done
@@ -1629,9 +1629,6 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
}
put_pid(pid);
-
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(5, ret, which, upid, infop, options, ru);
return ret;
}
@@ -1669,8 +1666,6 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr,
ret = do_wait(&wo);
put_pid(pid);
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(4, ret, upid, stat_addr, options, ru);
return ret;
}
diff --git a/kernel/extable.c b/kernel/extable.c
index fe35a634bf76..67460b93b1a1 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -41,10 +41,10 @@ u32 __initdata main_extable_sort_needed = 1;
/* Sort the kernel's built-in exception table */
void __init sort_main_extable(void)
{
- if (main_extable_sort_needed)
+ if (main_extable_sort_needed) {
+ pr_notice("Sorting __ex_table...\n");
sort_extable(__start___ex_table, __stop___ex_table);
- else
- pr_notice("__ex_table already sorted, skipping sort\n");
+ }
}
/* Given an address, look for it in the exception tables. */
diff --git a/kernel/fork.c b/kernel/fork.c
index 1766d324d5e3..7d40687b1434 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1233,7 +1233,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->utime = p->stime = p->gtime = 0;
p->utimescaled = p->stimescaled = 0;
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
p->prev_cputime.utime = p->prev_cputime.stime = 0;
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
@@ -1677,10 +1677,7 @@ SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
int, tls_val)
#endif
{
- long ret = do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
- asmlinkage_protect(5, ret, clone_flags, newsp,
- parent_tidptr, child_tidptr, tls_val);
- return ret;
+ return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
}
#endif
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index cc47812d3feb..609d8ff38b74 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -63,6 +63,7 @@
DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
{
+ .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock),
.clock_base =
{
{
@@ -83,6 +84,12 @@ DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) =
.get_time = &ktime_get_boottime,
.resolution = KTIME_LOW_RES,
},
+ {
+ .index = HRTIMER_BASE_TAI,
+ .clockid = CLOCK_TAI,
+ .get_time = &ktime_get_clocktai,
+ .resolution = KTIME_LOW_RES,
+ },
}
};
@@ -90,6 +97,7 @@ static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = {
[CLOCK_REALTIME] = HRTIMER_BASE_REALTIME,
[CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC,
[CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME,
+ [CLOCK_TAI] = HRTIMER_BASE_TAI,
};
static inline int hrtimer_clockid_to_base(clockid_t clock_id)
@@ -106,8 +114,10 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
{
ktime_t xtim, mono, boot;
struct timespec xts, tom, slp;
+ s32 tai_offset;
get_xtime_and_monotonic_and_sleep_offset(&xts, &tom, &slp);
+ tai_offset = timekeeping_get_tai_offset();
xtim = timespec_to_ktime(xts);
mono = ktime_add(xtim, timespec_to_ktime(tom));
@@ -115,6 +125,8 @@ static void hrtimer_get_softirq_time(struct hrtimer_cpu_base *base)
base->clock_base[HRTIMER_BASE_REALTIME].softirq_time = xtim;
base->clock_base[HRTIMER_BASE_MONOTONIC].softirq_time = mono;
base->clock_base[HRTIMER_BASE_BOOTTIME].softirq_time = boot;
+ base->clock_base[HRTIMER_BASE_TAI].softirq_time =
+ ktime_add(xtim, ktime_set(tai_offset, 0));
}
/*
@@ -275,6 +287,10 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec)
} else {
unsigned long rem = do_div(nsec, NSEC_PER_SEC);
+ /* Make sure nsec fits into long */
+ if (unlikely(nsec > KTIME_SEC_MAX))
+ return (ktime_t){ .tv64 = KTIME_MAX };
+
tmp = ktime_set((long)nsec, rem);
}
@@ -651,8 +667,9 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
{
ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset;
ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset;
+ ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset;
- return ktime_get_update_offsets(offs_real, offs_boot);
+ return ktime_get_update_offsets(offs_real, offs_boot, offs_tai);
}
/*
@@ -1010,7 +1027,8 @@ int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
* @timer: the timer to be added
* @tim: expiry time
* @delta_ns: "slack" range for the timer
- * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ * @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or
+ * relative (HRTIMER_MODE_REL)
*
* Returns:
* 0 on success
@@ -1027,7 +1045,8 @@ EXPORT_SYMBOL_GPL(hrtimer_start_range_ns);
* hrtimer_start - (re)start an hrtimer on the current CPU
* @timer: the timer to be added
* @tim: expiry time
- * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ * @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or
+ * relative (HRTIMER_MODE_REL)
*
* Returns:
* 0 on success
@@ -1309,6 +1328,8 @@ retry:
expires = ktime_sub(hrtimer_get_expires(timer),
base->offset);
+ if (expires.tv64 < 0)
+ expires.tv64 = KTIME_MAX;
if (expires.tv64 < expires_next.tv64)
expires_next = expires;
break;
@@ -1642,8 +1663,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu)
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
- raw_spin_lock_init(&cpu_base->lock);
-
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
cpu_base->clock_base[i].cpu_base = cpu_base;
timerqueue_init_head(&cpu_base->clock_base[i].active);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index bddd3d7a74b6..59f7b55ba745 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -55,7 +55,7 @@ struct resource crashk_res = {
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
};
struct resource crashk_low_res = {
- .name = "Crash kernel low",
+ .name = "Crash kernel",
.start = 0,
.end = 0,
.flags = IORESOURCE_BUSY | IORESOURCE_MEM
@@ -786,7 +786,7 @@ static int kimage_load_normal_segment(struct kimage *image,
struct kexec_segment *segment)
{
unsigned long maddr;
- unsigned long ubytes, mbytes;
+ size_t ubytes, mbytes;
int result;
unsigned char __user *buf;
@@ -819,13 +819,9 @@ static int kimage_load_normal_segment(struct kimage *image,
/* Start with a clear page */
clear_page(ptr);
ptr += maddr & ~PAGE_MASK;
- mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
- if (mchunk > mbytes)
- mchunk = mbytes;
-
- uchunk = mchunk;
- if (uchunk > ubytes)
- uchunk = ubytes;
+ mchunk = min_t(size_t, mbytes,
+ PAGE_SIZE - (maddr & ~PAGE_MASK));
+ uchunk = min(ubytes, mchunk);
result = copy_from_user(ptr, buf, uchunk);
kunmap(page);
@@ -850,7 +846,7 @@ static int kimage_load_crash_segment(struct kimage *image,
* We do things a page at a time for the sake of kmap.
*/
unsigned long maddr;
- unsigned long ubytes, mbytes;
+ size_t ubytes, mbytes;
int result;
unsigned char __user *buf;
@@ -871,13 +867,10 @@ static int kimage_load_crash_segment(struct kimage *image,
}
ptr = kmap(page);
ptr += maddr & ~PAGE_MASK;
- mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
- if (mchunk > mbytes)
- mchunk = mbytes;
-
- uchunk = mchunk;
- if (uchunk > ubytes) {
- uchunk = ubytes;
+ mchunk = min_t(size_t, mbytes,
+ PAGE_SIZE - (maddr & ~PAGE_MASK));
+ uchunk = min(ubytes, mchunk);
+ if (mchunk > uchunk) {
/* Zero the trailing part of the page */
memset(ptr + uchunk, 0, mchunk - uchunk);
}
@@ -1118,12 +1111,8 @@ void __weak crash_free_reserved_phys_range(unsigned long begin,
{
unsigned long addr;
- for (addr = begin; addr < end; addr += PAGE_SIZE) {
- ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
- init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
- free_page((unsigned long)__va(addr));
- totalram_pages++;
- }
+ for (addr = begin; addr < end; addr += PAGE_SIZE)
+ free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
}
int crash_shrink_memory(unsigned long new_size)
@@ -1368,35 +1357,114 @@ static int __init parse_crashkernel_simple(char *cmdline,
return 0;
}
+#define SUFFIX_HIGH 0
+#define SUFFIX_LOW 1
+#define SUFFIX_NULL 2
+static __initdata char *suffix_tbl[] = {
+ [SUFFIX_HIGH] = ",high",
+ [SUFFIX_LOW] = ",low",
+ [SUFFIX_NULL] = NULL,
+};
+
/*
- * That function is the entry point for command line parsing and should be
- * called from the arch-specific code.
+ * That function parses "suffix" crashkernel command lines like
+ *
+ * crashkernel=size,[high|low]
+ *
+ * It returns 0 on success and -EINVAL on failure.
*/
+static int __init parse_crashkernel_suffix(char *cmdline,
+ unsigned long long *crash_size,
+ unsigned long long *crash_base,
+ const char *suffix)
+{
+ char *cur = cmdline;
+
+ *crash_size = memparse(cmdline, &cur);
+ if (cmdline == cur) {
+ pr_warn("crashkernel: memory value expected\n");
+ return -EINVAL;
+ }
+
+ /* check with suffix */
+ if (strncmp(cur, suffix, strlen(suffix))) {
+ pr_warn("crashkernel: unrecognized char\n");
+ return -EINVAL;
+ }
+ cur += strlen(suffix);
+ if (*cur != ' ' && *cur != '\0') {
+ pr_warn("crashkernel: unrecognized char\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static __init char *get_last_crashkernel(char *cmdline,
+ const char *name,
+ const char *suffix)
+{
+ char *p = cmdline, *ck_cmdline = NULL;
+
+ /* find crashkernel and use the last one if there are more */
+ p = strstr(p, name);
+ while (p) {
+ char *end_p = strchr(p, ' ');
+ char *q;
+
+ if (!end_p)
+ end_p = p + strlen(p);
+
+ if (!suffix) {
+ int i;
+
+ /* skip the one with any known suffix */
+ for (i = 0; suffix_tbl[i]; i++) {
+ q = end_p - strlen(suffix_tbl[i]);
+ if (!strncmp(q, suffix_tbl[i],
+ strlen(suffix_tbl[i])))
+ goto next;
+ }
+ ck_cmdline = p;
+ } else {
+ q = end_p - strlen(suffix);
+ if (!strncmp(q, suffix, strlen(suffix)))
+ ck_cmdline = p;
+ }
+next:
+ p = strstr(p+1, name);
+ }
+
+ if (!ck_cmdline)
+ return NULL;
+
+ return ck_cmdline;
+}
+
static int __init __parse_crashkernel(char *cmdline,
unsigned long long system_ram,
unsigned long long *crash_size,
unsigned long long *crash_base,
- const char *name)
+ const char *name,
+ const char *suffix)
{
- char *p = cmdline, *ck_cmdline = NULL;
char *first_colon, *first_space;
+ char *ck_cmdline;
BUG_ON(!crash_size || !crash_base);
*crash_size = 0;
*crash_base = 0;
- /* find crashkernel and use the last one if there are more */
- p = strstr(p, name);
- while (p) {
- ck_cmdline = p;
- p = strstr(p+1, name);
- }
+ ck_cmdline = get_last_crashkernel(cmdline, name, suffix);
if (!ck_cmdline)
return -EINVAL;
ck_cmdline += strlen(name);
+ if (suffix)
+ return parse_crashkernel_suffix(ck_cmdline, crash_size,
+ crash_base, suffix);
/*
* if the commandline contains a ':', then that's the extended
* syntax -- if not, it must be the classic syntax
@@ -1413,13 +1481,26 @@ static int __init __parse_crashkernel(char *cmdline,
return 0;
}
+/*
+ * That function is the entry point for command line parsing and should be
+ * called from the arch-specific code.
+ */
int __init parse_crashkernel(char *cmdline,
unsigned long long system_ram,
unsigned long long *crash_size,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
- "crashkernel=");
+ "crashkernel=", NULL);
+}
+
+int __init parse_crashkernel_high(char *cmdline,
+ unsigned long long system_ram,
+ unsigned long long *crash_size,
+ unsigned long long *crash_base)
+{
+ return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
+ "crashkernel=", suffix_tbl[SUFFIX_HIGH]);
}
int __init parse_crashkernel_low(char *cmdline,
@@ -1428,7 +1509,7 @@ int __init parse_crashkernel_low(char *cmdline,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
- "crashkernel_low=");
+ "crashkernel=", suffix_tbl[SUFFIX_LOW]);
}
static void update_vmcoreinfo_note(void)
@@ -1452,14 +1533,13 @@ void vmcoreinfo_append_str(const char *fmt, ...)
{
va_list args;
char buf[0x50];
- int r;
+ size_t r;
va_start(args, fmt);
r = vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- if (r + vmcoreinfo_size > vmcoreinfo_max_size)
- r = vmcoreinfo_max_size - vmcoreinfo_size;
+ r = min(r, vmcoreinfo_max_size - vmcoreinfo_size);
memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
@@ -1489,7 +1569,7 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_SYMBOL(swapper_pg_dir);
#endif
VMCOREINFO_SYMBOL(_stext);
- VMCOREINFO_SYMBOL(vmlist);
+ VMCOREINFO_SYMBOL(vmap_area_list);
#ifndef CONFIG_NEED_MULTIPLE_NODES
VMCOREINFO_SYMBOL(mem_map);
@@ -1527,7 +1607,8 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_OFFSET(free_area, free_list);
VMCOREINFO_OFFSET(list_head, next);
VMCOREINFO_OFFSET(list_head, prev);
- VMCOREINFO_OFFSET(vm_struct, addr);
+ VMCOREINFO_OFFSET(vmap_area, va_start);
+ VMCOREINFO_OFFSET(vmap_area, list);
VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
log_buf_kexec_setup();
VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 56dd34976d7b..1296e72e4161 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -77,6 +77,7 @@ static void free_modprobe_argv(struct subprocess_info *info)
static int call_modprobe(char *module_name, int wait)
{
+ struct subprocess_info *info;
static char *envp[] = {
"HOME=/",
"TERM=linux",
@@ -98,8 +99,15 @@ static int call_modprobe(char *module_name, int wait)
argv[3] = module_name; /* check free_modprobe_argv() */
argv[4] = NULL;
- return call_usermodehelper_fns(modprobe_path, argv, envp,
- wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL);
+ info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,
+ NULL, free_modprobe_argv, NULL);
+ if (!info)
+ goto free_module_name;
+
+ return call_usermodehelper_exec(info, wait | UMH_KILLABLE);
+
+free_module_name:
+ kfree(module_name);
free_argv:
kfree(argv);
out:
@@ -502,14 +510,28 @@ static void helper_unlock(void)
* @argv: arg vector for process
* @envp: environment for process
* @gfp_mask: gfp mask for memory allocation
+ * @cleanup: a cleanup function
+ * @init: an init function
+ * @data: arbitrary context sensitive data
*
* Returns either %NULL on allocation failure, or a subprocess_info
* structure. This should be passed to call_usermodehelper_exec to
* exec the process and free the structure.
+ *
+ * The init function is used to customize the helper process prior to
+ * exec. A non-zero return code causes the process to error out, exit,
+ * and return the failure to the calling process
+ *
+ * The cleanup function is just before ethe subprocess_info is about to
+ * be freed. This can be used for freeing the argv and envp. The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
*/
-static
struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
- char **envp, gfp_t gfp_mask)
+ char **envp, gfp_t gfp_mask,
+ int (*init)(struct subprocess_info *info, struct cred *new),
+ void (*cleanup)(struct subprocess_info *info),
+ void *data)
{
struct subprocess_info *sub_info;
sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask);
@@ -520,50 +542,27 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
sub_info->path = path;
sub_info->argv = argv;
sub_info->envp = envp;
+
+ sub_info->cleanup = cleanup;
+ sub_info->init = init;
+ sub_info->data = data;
out:
return sub_info;
}
-
-/**
- * call_usermodehelper_setfns - set a cleanup/init function
- * @info: a subprocess_info returned by call_usermodehelper_setup
- * @cleanup: a cleanup function
- * @init: an init function
- * @data: arbitrary context sensitive data
- *
- * The init function is used to customize the helper process prior to
- * exec. A non-zero return code causes the process to error out, exit,
- * and return the failure to the calling process
- *
- * The cleanup function is just before ethe subprocess_info is about to
- * be freed. This can be used for freeing the argv and envp. The
- * Function must be runnable in either a process context or the
- * context in which call_usermodehelper_exec is called.
- */
-static
-void call_usermodehelper_setfns(struct subprocess_info *info,
- int (*init)(struct subprocess_info *info, struct cred *new),
- void (*cleanup)(struct subprocess_info *info),
- void *data)
-{
- info->cleanup = cleanup;
- info->init = init;
- info->data = data;
-}
+EXPORT_SYMBOL(call_usermodehelper_setup);
/**
* call_usermodehelper_exec - start a usermode application
* @sub_info: information about the subprocessa
* @wait: wait for the application to finish and return status.
- * when -1 don't wait at all, but you get no useful error back when
- * the program couldn't be exec'ed. This makes it safe to call
+ * when UMH_NO_WAIT don't wait at all, but you get no useful error back
+ * when the program couldn't be exec'ed. This makes it safe to call
* from interrupt context.
*
* Runs a user-space application. The application is started
* asynchronously if wait is not set, and runs as a child of keventd.
* (ie. it runs with full root capabilities).
*/
-static
int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
{
DECLARE_COMPLETION_ONSTACK(done);
@@ -615,31 +614,34 @@ unlock:
helper_unlock();
return retval;
}
+EXPORT_SYMBOL(call_usermodehelper_exec);
-/*
- * call_usermodehelper_fns() will not run the caller-provided cleanup function
- * if a memory allocation failure is experienced. So the caller might need to
- * check the call_usermodehelper_fns() return value: if it is -ENOMEM, perform
- * the necessaary cleanup within the caller.
+/**
+ * call_usermodehelper() - prepare and start a usermode application
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @wait: wait for the application to finish and return status.
+ * when UMH_NO_WAIT don't wait at all, but you get no useful error back
+ * when the program couldn't be exec'ed. This makes it safe to call
+ * from interrupt context.
+ *
+ * This function is the equivalent to use call_usermodehelper_setup() and
+ * call_usermodehelper_exec().
*/
-int call_usermodehelper_fns(
- char *path, char **argv, char **envp, int wait,
- int (*init)(struct subprocess_info *info, struct cred *new),
- void (*cleanup)(struct subprocess_info *), void *data)
+int call_usermodehelper(char *path, char **argv, char **envp, int wait)
{
struct subprocess_info *info;
gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
- info = call_usermodehelper_setup(path, argv, envp, gfp_mask);
-
+ info = call_usermodehelper_setup(path, argv, envp, gfp_mask,
+ NULL, NULL, NULL);
if (info == NULL)
return -ENOMEM;
- call_usermodehelper_setfns(info, init, cleanup, data);
-
return call_usermodehelper_exec(info, wait);
}
-EXPORT_SYMBOL(call_usermodehelper_fns);
+EXPORT_SYMBOL(call_usermodehelper);
static int proc_cap_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index e35be53f6613..3fed7f0cbcdf 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -794,16 +794,16 @@ out:
}
#ifdef CONFIG_SYSCTL
-/* This should be called with kprobe_mutex locked */
static void __kprobes optimize_all_kprobes(void)
{
struct hlist_head *head;
struct kprobe *p;
unsigned int i;
+ mutex_lock(&kprobe_mutex);
/* If optimization is already allowed, just return */
if (kprobes_allow_optimization)
- return;
+ goto out;
kprobes_allow_optimization = true;
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
@@ -813,18 +813,22 @@ static void __kprobes optimize_all_kprobes(void)
optimize_kprobe(p);
}
printk(KERN_INFO "Kprobes globally optimized\n");
+out:
+ mutex_unlock(&kprobe_mutex);
}
-/* This should be called with kprobe_mutex locked */
static void __kprobes unoptimize_all_kprobes(void)
{
struct hlist_head *head;
struct kprobe *p;
unsigned int i;
+ mutex_lock(&kprobe_mutex);
/* If optimization is already prohibited, just return */
- if (!kprobes_allow_optimization)
+ if (!kprobes_allow_optimization) {
+ mutex_unlock(&kprobe_mutex);
return;
+ }
kprobes_allow_optimization = false;
for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
@@ -834,11 +838,14 @@ static void __kprobes unoptimize_all_kprobes(void)
unoptimize_kprobe(p, false);
}
}
+ mutex_unlock(&kprobe_mutex);
+
/* Wait for unoptimizing completion */
wait_for_kprobe_optimizer();
printk(KERN_INFO "Kprobes globally unoptimized\n");
}
+static DEFINE_MUTEX(kprobe_sysctl_mutex);
int sysctl_kprobes_optimization;
int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
void __user *buffer, size_t *length,
@@ -846,7 +853,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
{
int ret;
- mutex_lock(&kprobe_mutex);
+ mutex_lock(&kprobe_sysctl_mutex);
sysctl_kprobes_optimization = kprobes_allow_optimization ? 1 : 0;
ret = proc_dointvec_minmax(table, write, buffer, length, ppos);
@@ -854,7 +861,7 @@ int proc_kprobes_optimization_handler(struct ctl_table *table, int write,
optimize_all_kprobes();
else
unoptimize_all_kprobes();
- mutex_unlock(&kprobe_mutex);
+ mutex_unlock(&kprobe_sysctl_mutex);
return ret;
}
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 691dc2ef9baf..760e86df8c20 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/freezer.h>
#include <linux/ptrace.h>
+#include <linux/uaccess.h>
#include <trace/events/sched.h>
static DEFINE_SPINLOCK(kthread_create_lock);
@@ -52,8 +53,21 @@ enum KTHREAD_BITS {
KTHREAD_IS_PARKED,
};
-#define to_kthread(tsk) \
- container_of((tsk)->vfork_done, struct kthread, exited)
+#define __to_kthread(vfork) \
+ container_of(vfork, struct kthread, exited)
+
+static inline struct kthread *to_kthread(struct task_struct *k)
+{
+ return __to_kthread(k->vfork_done);
+}
+
+static struct kthread *to_live_kthread(struct task_struct *k)
+{
+ struct completion *vfork = ACCESS_ONCE(k->vfork_done);
+ if (likely(vfork))
+ return __to_kthread(vfork);
+ return NULL;
+}
/**
* kthread_should_stop - should this kthread return now?
@@ -122,14 +136,32 @@ void *kthread_data(struct task_struct *task)
return to_kthread(task)->data;
}
+/**
+ * probe_kthread_data - speculative version of kthread_data()
+ * @task: possible kthread task in question
+ *
+ * @task could be a kthread task. Return the data value specified when it
+ * was created if accessible. If @task isn't a kthread task or its data is
+ * inaccessible for any reason, %NULL is returned. This function requires
+ * that @task itself is safe to dereference.
+ */
+void *probe_kthread_data(struct task_struct *task)
+{
+ struct kthread *kthread = to_kthread(task);
+ void *data = NULL;
+
+ probe_kernel_read(&data, &kthread->data, sizeof(data));
+ return data;
+}
+
static void __kthread_parkme(struct kthread *self)
{
- __set_current_state(TASK_INTERRUPTIBLE);
+ __set_current_state(TASK_PARKED);
while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) {
if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags))
complete(&self->parked);
schedule();
- __set_current_state(TASK_INTERRUPTIBLE);
+ __set_current_state(TASK_PARKED);
}
clear_bit(KTHREAD_IS_PARKED, &self->flags);
__set_current_state(TASK_RUNNING);
@@ -256,11 +288,16 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
}
EXPORT_SYMBOL(kthread_create_on_node);
-static void __kthread_bind(struct task_struct *p, unsigned int cpu)
+static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state)
{
+ /* Must have done schedule() in kthread() before we set_task_cpu */
+ if (!wait_task_inactive(p, state)) {
+ WARN_ON(1);
+ return;
+ }
/* It's safe because the task is inactive. */
do_set_cpus_allowed(p, cpumask_of(cpu));
- p->flags |= PF_THREAD_BOUND;
+ p->flags |= PF_NO_SETAFFINITY;
}
/**
@@ -274,12 +311,7 @@ static void __kthread_bind(struct task_struct *p, unsigned int cpu)
*/
void kthread_bind(struct task_struct *p, unsigned int cpu)
{
- /* Must have done schedule() in kthread() before we set_task_cpu */
- if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE)) {
- WARN_ON(1);
- return;
- }
- __kthread_bind(p, cpu);
+ __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(kthread_bind);
@@ -311,17 +343,20 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
return p;
}
-static struct kthread *task_get_live_kthread(struct task_struct *k)
+static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)
{
- struct kthread *kthread;
-
- get_task_struct(k);
- kthread = to_kthread(k);
- /* It might have exited */
- barrier();
- if (k->vfork_done != NULL)
- return kthread;
- return NULL;
+ clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+ /*
+ * We clear the IS_PARKED bit here as we don't wait
+ * until the task has left the park code. So if we'd
+ * park before that happens we'd see the IS_PARKED bit
+ * which might be about to be cleared.
+ */
+ if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
+ if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
+ __kthread_bind(k, kthread->cpu, TASK_PARKED);
+ wake_up_state(k, TASK_PARKED);
+ }
}
/**
@@ -334,23 +369,10 @@ static struct kthread *task_get_live_kthread(struct task_struct *k)
*/
void kthread_unpark(struct task_struct *k)
{
- struct kthread *kthread = task_get_live_kthread(k);
+ struct kthread *kthread = to_live_kthread(k);
- if (kthread) {
- clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
- /*
- * We clear the IS_PARKED bit here as we don't wait
- * until the task has left the park code. So if we'd
- * park before that happens we'd see the IS_PARKED bit
- * which might be about to be cleared.
- */
- if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) {
- if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags))
- __kthread_bind(k, kthread->cpu);
- wake_up_process(k);
- }
- }
- put_task_struct(k);
+ if (kthread)
+ __kthread_unpark(k, kthread);
}
/**
@@ -367,7 +389,7 @@ void kthread_unpark(struct task_struct *k)
*/
int kthread_park(struct task_struct *k)
{
- struct kthread *kthread = task_get_live_kthread(k);
+ struct kthread *kthread = to_live_kthread(k);
int ret = -ENOSYS;
if (kthread) {
@@ -380,7 +402,6 @@ int kthread_park(struct task_struct *k)
}
ret = 0;
}
- put_task_struct(k);
return ret;
}
@@ -401,21 +422,23 @@ int kthread_park(struct task_struct *k)
*/
int kthread_stop(struct task_struct *k)
{
- struct kthread *kthread = task_get_live_kthread(k);
+ struct kthread *kthread;
int ret;
trace_sched_kthread_stop(k);
+
+ get_task_struct(k);
+ kthread = to_live_kthread(k);
if (kthread) {
set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
- clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags);
+ __kthread_unpark(k, kthread);
wake_up_process(k);
wait_for_completion(&kthread->exited);
}
ret = k->exit_code;
-
put_task_struct(k);
- trace_sched_kthread_stop_ret(ret);
+ trace_sched_kthread_stop_ret(ret);
return ret;
}
EXPORT_SYMBOL(kthread_stop);
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 259db207b5d9..6a3bccba7e7d 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -380,6 +380,13 @@ static int verbose(struct lock_class *class)
unsigned long nr_stack_trace_entries;
static unsigned long stack_trace[MAX_STACK_TRACE_ENTRIES];
+static void print_lockdep_off(const char *bug_msg)
+{
+ printk(KERN_DEBUG "%s\n", bug_msg);
+ printk(KERN_DEBUG "turning off the locking correctness validator.\n");
+ printk(KERN_DEBUG "Please attach the output of /proc/lock_stat to the bug report\n");
+}
+
static int save_trace(struct stack_trace *trace)
{
trace->nr_entries = 0;
@@ -409,8 +416,7 @@ static int save_trace(struct stack_trace *trace)
if (!debug_locks_off_graph_unlock())
return 0;
- printk("BUG: MAX_STACK_TRACE_ENTRIES too low!\n");
- printk("turning off the locking correctness validator.\n");
+ print_lockdep_off("BUG: MAX_STACK_TRACE_ENTRIES too low!");
dump_stack();
return 0;
@@ -763,8 +769,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
}
raw_local_irq_restore(flags);
- printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
- printk("turning off the locking correctness validator.\n");
+ print_lockdep_off("BUG: MAX_LOCKDEP_KEYS too low!");
dump_stack();
return NULL;
}
@@ -834,8 +839,7 @@ static struct lock_list *alloc_list_entry(void)
if (!debug_locks_off_graph_unlock())
return NULL;
- printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
- printk("turning off the locking correctness validator.\n");
+ print_lockdep_off("BUG: MAX_LOCKDEP_ENTRIES too low!");
dump_stack();
return NULL;
}
@@ -2000,7 +2004,7 @@ static inline int lookup_chain_cache(struct task_struct *curr,
struct lock_class *class = hlock_class(hlock);
struct list_head *hash_head = chainhashentry(chain_key);
struct lock_chain *chain;
- struct held_lock *hlock_curr, *hlock_next;
+ struct held_lock *hlock_curr;
int i, j;
/*
@@ -2048,8 +2052,7 @@ cache_hit:
if (!debug_locks_off_graph_unlock())
return 0;
- printk("BUG: MAX_LOCKDEP_CHAINS too low!\n");
- printk("turning off the locking correctness validator.\n");
+ print_lockdep_off("BUG: MAX_LOCKDEP_CHAINS too low!");
dump_stack();
return 0;
}
@@ -2057,12 +2060,10 @@ cache_hit:
chain->chain_key = chain_key;
chain->irq_context = hlock->irq_context;
/* Find the first held_lock of current chain */
- hlock_next = hlock;
for (i = curr->lockdep_depth - 1; i >= 0; i--) {
hlock_curr = curr->held_locks + i;
- if (hlock_curr->irq_context != hlock_next->irq_context)
+ if (hlock_curr->irq_context != hlock->irq_context)
break;
- hlock_next = hlock;
}
i++;
chain->depth = curr->lockdep_depth + 1 - i;
@@ -3190,9 +3191,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
#endif
if (unlikely(curr->lockdep_depth >= MAX_LOCK_DEPTH)) {
debug_locks_off();
- printk("BUG: MAX_LOCK_DEPTH too low, depth: %i max: %lu!\n",
+ print_lockdep_off("BUG: MAX_LOCK_DEPTH too low!");
+ printk(KERN_DEBUG "depth: %i max: %lu!\n",
curr->lockdep_depth, MAX_LOCK_DEPTH);
- printk("turning off the locking correctness validator.\n");
lockdep_print_held_locks(current);
debug_show_all_locks();
@@ -4088,7 +4089,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len)
}
EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
-static void print_held_locks_bug(void)
+static void print_held_locks_bug(struct task_struct *curr)
{
if (!debug_locks_off())
return;
@@ -4097,21 +4098,22 @@ static void print_held_locks_bug(void)
printk("\n");
printk("=====================================\n");
- printk("[ BUG: %s/%d still has locks held! ]\n",
- current->comm, task_pid_nr(current));
+ printk("[ BUG: lock held at task exit time! ]\n");
print_kernel_ident();
printk("-------------------------------------\n");
- lockdep_print_held_locks(current);
+ printk("%s/%d is exiting with locks still held!\n",
+ curr->comm, task_pid_nr(curr));
+ lockdep_print_held_locks(curr);
+
printk("\nstack backtrace:\n");
dump_stack();
}
-void debug_check_no_locks_held(void)
+void debug_check_no_locks_held(struct task_struct *task)
{
- if (unlikely(current->lockdep_depth > 0))
- print_held_locks_bug();
+ if (unlikely(task->lockdep_depth > 0))
+ print_held_locks_bug(task);
}
-EXPORT_SYMBOL_GPL(debug_check_no_locks_held);
void debug_show_all_locks(void)
{
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 52f23011b6e0..ad53a664f113 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -37,6 +37,12 @@
# include <asm/mutex.h>
#endif
+/*
+ * A negative mutex count indicates that waiters are sleeping waiting for the
+ * mutex.
+ */
+#define MUTEX_SHOW_NO_WAITER(mutex) (atomic_read(&(mutex)->count) >= 0)
+
void
__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
@@ -44,6 +50,9 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
spin_lock_init(&lock->wait_lock);
INIT_LIST_HEAD(&lock->wait_list);
mutex_clear_owner(lock);
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+ lock->spin_mlock = NULL;
+#endif
debug_mutex_init(lock, name, key);
}
@@ -95,6 +104,124 @@ void __sched mutex_lock(struct mutex *lock)
EXPORT_SYMBOL(mutex_lock);
#endif
+#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
+/*
+ * In order to avoid a stampede of mutex spinners from acquiring the mutex
+ * more or less simultaneously, the spinners need to acquire a MCS lock
+ * first before spinning on the owner field.
+ *
+ * We don't inline mspin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+struct mspin_node {
+ struct mspin_node *next ;
+ int locked; /* 1 if lock acquired */
+};
+#define MLOCK(mutex) ((struct mspin_node **)&((mutex)->spin_mlock))
+
+static noinline
+void mspin_lock(struct mspin_node **lock, struct mspin_node *node)
+{
+ struct mspin_node *prev;
+
+ /* Init node */
+ node->locked = 0;
+ node->next = NULL;
+
+ prev = xchg(lock, node);
+ if (likely(prev == NULL)) {
+ /* Lock acquired */
+ node->locked = 1;
+ return;
+ }
+ ACCESS_ONCE(prev->next) = node;
+ smp_wmb();
+ /* Wait until the lock holder passes the lock down */
+ while (!ACCESS_ONCE(node->locked))
+ arch_mutex_cpu_relax();
+}
+
+static void mspin_unlock(struct mspin_node **lock, struct mspin_node *node)
+{
+ struct mspin_node *next = ACCESS_ONCE(node->next);
+
+ if (likely(!next)) {
+ /*
+ * Release the lock by setting it to NULL
+ */
+ if (cmpxchg(lock, node, NULL) == node)
+ return;
+ /* Wait until the next pointer is set */
+ while (!(next = ACCESS_ONCE(node->next)))
+ arch_mutex_cpu_relax();
+ }
+ ACCESS_ONCE(next->locked) = 1;
+ smp_wmb();
+}
+
+/*
+ * Mutex spinning code migrated from kernel/sched/core.c
+ */
+
+static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
+{
+ if (lock->owner != owner)
+ return false;
+
+ /*
+ * Ensure we emit the owner->on_cpu, dereference _after_ checking
+ * lock->owner still matches owner, if that fails, owner might
+ * point to free()d memory, if it still matches, the rcu_read_lock()
+ * ensures the memory stays valid.
+ */
+ barrier();
+
+ return owner->on_cpu;
+}
+
+/*
+ * Look out! "owner" is an entirely speculative pointer
+ * access and not reliable.
+ */
+static noinline
+int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
+{
+ rcu_read_lock();
+ while (owner_running(lock, owner)) {
+ if (need_resched())
+ break;
+
+ arch_mutex_cpu_relax();
+ }
+ rcu_read_unlock();
+
+ /*
+ * We break out the loop above on need_resched() and when the
+ * owner changed, which is a sign for heavy contention. Return
+ * success only when lock->owner is NULL.
+ */
+ return lock->owner == NULL;
+}
+
+/*
+ * Initial check for entering the mutex spinning loop
+ */
+static inline int mutex_can_spin_on_owner(struct mutex *lock)
+{
+ int retval = 1;
+
+ rcu_read_lock();
+ if (lock->owner)
+ retval = lock->owner->on_cpu;
+ rcu_read_unlock();
+ /*
+ * if lock->owner is not set, the mutex owner may have just acquired
+ * it and not set the owner yet or the mutex has been released.
+ */
+ return retval;
+}
+#endif
+
static __used noinline void __sched __mutex_unlock_slowpath(atomic_t *lock_count);
/**
@@ -158,25 +285,39 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
*
* We can't do this for DEBUG_MUTEXES because that relies on wait_lock
* to serialize everything.
+ *
+ * The mutex spinners are queued up using MCS lock so that only one
+ * spinner can compete for the mutex. However, if mutex spinning isn't
+ * going to happen, there is no point in going through the lock/unlock
+ * overhead.
*/
+ if (!mutex_can_spin_on_owner(lock))
+ goto slowpath;
for (;;) {
struct task_struct *owner;
+ struct mspin_node node;
/*
* If there's an owner, wait for it to either
* release the lock or go to sleep.
*/
+ mspin_lock(MLOCK(lock), &node);
owner = ACCESS_ONCE(lock->owner);
- if (owner && !mutex_spin_on_owner(lock, owner))
+ if (owner && !mutex_spin_on_owner(lock, owner)) {
+ mspin_unlock(MLOCK(lock), &node);
break;
+ }
- if (atomic_cmpxchg(&lock->count, 1, 0) == 1) {
+ if ((atomic_read(&lock->count) == 1) &&
+ (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
lock_acquired(&lock->dep_map, ip);
mutex_set_owner(lock);
+ mspin_unlock(MLOCK(lock), &node);
preempt_enable();
return 0;
}
+ mspin_unlock(MLOCK(lock), &node);
/*
* When there's no owner, we might have preempted between the
@@ -195,6 +336,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
*/
arch_mutex_cpu_relax();
}
+slowpath:
#endif
spin_lock_mutex(&lock->wait_lock, flags);
@@ -205,7 +347,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
list_add_tail(&waiter.list, &lock->wait_list);
waiter.task = task;
- if (atomic_xchg(&lock->count, -1) == 1)
+ if (MUTEX_SHOW_NO_WAITER(lock) && (atomic_xchg(&lock->count, -1) == 1))
goto done;
lock_contended(&lock->dep_map, ip);
@@ -220,7 +362,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* that when we release the lock, we properly wake up the
* other waiters:
*/
- if (atomic_xchg(&lock->count, -1) == 1)
+ if (MUTEX_SHOW_NO_WAITER(lock) &&
+ (atomic_xchg(&lock->count, -1) == 1))
break;
/*
diff --git a/kernel/panic.c b/kernel/panic.c
index 7c57cc9eee2c..167ec097ce8b 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -22,7 +22,6 @@
#include <linux/sysrq.h>
#include <linux/init.h>
#include <linux/nmi.h>
-#include <linux/dmi.h>
#define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18
@@ -400,13 +399,8 @@ struct slowpath_args {
static void warn_slowpath_common(const char *file, int line, void *caller,
unsigned taint, struct slowpath_args *args)
{
- const char *board;
-
printk(KERN_WARNING "------------[ cut here ]------------\n");
printk(KERN_WARNING "WARNING: at %s:%d %pS()\n", file, line, caller);
- board = dmi_get_system_info(DMI_PRODUCT_NAME);
- if (board)
- printk(KERN_WARNING "Hardware name: %s\n", board);
if (args)
vprintk(args->fmt, args->args);
diff --git a/kernel/pid.c b/kernel/pid.c
index 686255e2c39e..0db3e791a06d 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -52,9 +52,6 @@ int pid_max = PID_MAX_DEFAULT;
int pid_max_min = RESERVED_PIDS + 1;
int pid_max_max = PID_MAX_LIMIT;
-#define BITS_PER_PAGE (PAGE_SIZE*8)
-#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
-
static inline int mk_pid(struct pid_namespace *pid_ns,
struct pidmap *map, int off)
{
@@ -184,15 +181,19 @@ static int alloc_pidmap(struct pid_namespace *pid_ns)
break;
}
if (likely(atomic_read(&map->nr_free))) {
- do {
+ for ( ; ; ) {
if (!test_and_set_bit(offset, map->page)) {
atomic_dec(&map->nr_free);
set_last_pid(pid_ns, last, pid);
return pid;
}
offset = find_next_offset(map, offset);
+ if (offset >= BITS_PER_PAGE)
+ break;
pid = mk_pid(pid_ns, map, offset);
- } while (offset < BITS_PER_PAGE && pid < pid_max);
+ if (pid >= pid_max)
+ break;
+ }
}
if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
++map;
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 4af28a849065..6917e8edb48e 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -19,8 +19,6 @@
#include <linux/reboot.h>
#include <linux/export.h>
-#define BITS_PER_PAGE (PAGE_SIZE*8)
-
struct pid_cache {
int nr_ids;
char name[16];
@@ -181,6 +179,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
int nr;
int rc;
struct task_struct *task, *me = current;
+ int init_pids = thread_group_leader(me) ? 1 : 2;
/* Don't allow any more processes into the pid namespace */
disable_pid_allocation(pid_ns);
@@ -230,7 +229,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
*/
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (pid_ns->nr_hashed == 1)
+ if (pid_ns->nr_hashed == init_pids)
break;
schedule();
}
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 6edbb2c55c22..424c2d4265c9 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -40,38 +40,31 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/compiler.h>
-#include <linux/idr.h>
+#include <linux/hash.h>
#include <linux/posix-clock.h>
#include <linux/posix-timers.h>
#include <linux/syscalls.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/export.h>
+#include <linux/hashtable.h>
/*
- * Management arrays for POSIX timers. Timers are kept in slab memory
- * Timer ids are allocated by an external routine that keeps track of the
- * id and the timer. The external interface is:
- *
- * void *idr_find(struct idr *idp, int id); to find timer_id <id>
- * int idr_get_new(struct idr *idp, void *ptr); to get a new id and
- * related it to <ptr>
- * void idr_remove(struct idr *idp, int id); to release <id>
- * void idr_init(struct idr *idp); to initialize <idp>
- * which we supply.
- * The idr_get_new *may* call slab for more memory so it must not be
- * called under a spin lock. Likewise idr_remore may release memory
- * (but it may be ok to do this under a lock...).
- * idr_find is just a memory look up and is quite fast. A -1 return
- * indicates that the requested id does not exist.
+ * Management arrays for POSIX timers. Timers are now kept in static hash table
+ * with 512 entries.
+ * Timer ids are allocated by local routine, which selects proper hash head by
+ * key, constructed from current->signal address and per signal struct counter.
+ * This keeps timer ids unique per process, but now they can intersect between
+ * processes.
*/
/*
* Lets keep our timers in a slab cache :-)
*/
static struct kmem_cache *posix_timers_cache;
-static struct idr posix_timers_id;
-static DEFINE_SPINLOCK(idr_lock);
+
+static DEFINE_HASHTABLE(posix_timers_hashtable, 9);
+static DEFINE_SPINLOCK(hash_lock);
/*
* we assume that the new SIGEV_THREAD_ID shares no bits with the other
@@ -152,6 +145,56 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags);
__timr; \
})
+static int hash(struct signal_struct *sig, unsigned int nr)
+{
+ return hash_32(hash32_ptr(sig) ^ nr, HASH_BITS(posix_timers_hashtable));
+}
+
+static struct k_itimer *__posix_timers_find(struct hlist_head *head,
+ struct signal_struct *sig,
+ timer_t id)
+{
+ struct k_itimer *timer;
+
+ hlist_for_each_entry_rcu(timer, head, t_hash) {
+ if ((timer->it_signal == sig) && (timer->it_id == id))
+ return timer;
+ }
+ return NULL;
+}
+
+static struct k_itimer *posix_timer_by_id(timer_t id)
+{
+ struct signal_struct *sig = current->signal;
+ struct hlist_head *head = &posix_timers_hashtable[hash(sig, id)];
+
+ return __posix_timers_find(head, sig, id);
+}
+
+static int posix_timer_add(struct k_itimer *timer)
+{
+ struct signal_struct *sig = current->signal;
+ int first_free_id = sig->posix_timer_id;
+ struct hlist_head *head;
+ int ret = -ENOENT;
+
+ do {
+ spin_lock(&hash_lock);
+ head = &posix_timers_hashtable[hash(sig, sig->posix_timer_id)];
+ if (!__posix_timers_find(head, sig, sig->posix_timer_id)) {
+ hlist_add_head_rcu(&timer->t_hash, head);
+ ret = sig->posix_timer_id;
+ }
+ if (++sig->posix_timer_id < 0)
+ sig->posix_timer_id = 0;
+ if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT))
+ /* Loop over all possible ids completed */
+ ret = -EAGAIN;
+ spin_unlock(&hash_lock);
+ } while (ret == -ENOENT);
+ return ret;
+}
+
static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)
{
spin_unlock_irqrestore(&timr->it_lock, flags);
@@ -221,6 +264,11 @@ static int posix_get_boottime(const clockid_t which_clock, struct timespec *tp)
return 0;
}
+static int posix_get_tai(clockid_t which_clock, struct timespec *tp)
+{
+ timekeeping_clocktai(tp);
+ return 0;
+}
/*
* Initialize everything, well, just everything in Posix clocks/timers ;)
@@ -261,6 +309,16 @@ static __init int init_posix_timers(void)
.clock_getres = posix_get_coarse_res,
.clock_get = posix_get_monotonic_coarse,
};
+ struct k_clock clock_tai = {
+ .clock_getres = hrtimer_get_res,
+ .clock_get = posix_get_tai,
+ .nsleep = common_nsleep,
+ .nsleep_restart = hrtimer_nanosleep_restart,
+ .timer_create = common_timer_create,
+ .timer_set = common_timer_set,
+ .timer_get = common_timer_get,
+ .timer_del = common_timer_del,
+ };
struct k_clock clock_boottime = {
.clock_getres = hrtimer_get_res,
.clock_get = posix_get_boottime,
@@ -278,11 +336,11 @@ static __init int init_posix_timers(void)
posix_timers_register_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse);
posix_timers_register_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse);
posix_timers_register_clock(CLOCK_BOOTTIME, &clock_boottime);
+ posix_timers_register_clock(CLOCK_TAI, &clock_tai);
posix_timers_cache = kmem_cache_create("posix_timers_cache",
sizeof (struct k_itimer), 0, SLAB_PANIC,
NULL);
- idr_init(&posix_timers_id);
return 0;
}
@@ -504,9 +562,9 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
{
if (it_id_set) {
unsigned long flags;
- spin_lock_irqsave(&idr_lock, flags);
- idr_remove(&posix_timers_id, tmr->it_id);
- spin_unlock_irqrestore(&idr_lock, flags);
+ spin_lock_irqsave(&hash_lock, flags);
+ hlist_del_rcu(&tmr->t_hash);
+ spin_unlock_irqrestore(&hash_lock, flags);
}
put_pid(tmr->it_pid);
sigqueue_free(tmr->sigq);
@@ -552,22 +610,11 @@ SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock,
return -EAGAIN;
spin_lock_init(&new_timer->it_lock);
-
- idr_preload(GFP_KERNEL);
- spin_lock_irq(&idr_lock);
- error = idr_alloc(&posix_timers_id, new_timer, 0, 0, GFP_NOWAIT);
- spin_unlock_irq(&idr_lock);
- idr_preload_end();
- if (error < 0) {
- /*
- * Weird looking, but we return EAGAIN if the IDR is
- * full (proper POSIX return value for this)
- */
- if (error == -ENOSPC)
- error = -EAGAIN;
+ new_timer_id = posix_timer_add(new_timer);
+ if (new_timer_id < 0) {
+ error = new_timer_id;
goto out;
}
- new_timer_id = error;
it_id_set = IT_ID_SET;
new_timer->it_id = (timer_t) new_timer_id;
@@ -645,7 +692,7 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
return NULL;
rcu_read_lock();
- timr = idr_find(&posix_timers_id, (int)timer_id);
+ timr = posix_timer_by_id(timer_id);
if (timr) {
spin_lock_irqsave(&timr->it_lock, *flags);
if (timr->it_signal == current->signal) {
diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c
index 68197a4e8fc9..7ef6866b521d 100644
--- a/kernel/power/poweroff.c
+++ b/kernel/power/poweroff.c
@@ -32,7 +32,7 @@ static void handle_poweroff(int key)
static struct sysrq_key_op sysrq_poweroff_op = {
.handler = handle_poweroff,
- .help_msg = "powerOff",
+ .help_msg = "poweroff(o)",
.action_msg = "Power Off",
.enable_mask = SYSRQ_ENABLE_BOOT,
};
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index d4feda084a3a..bef86d121eb2 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -76,8 +76,20 @@ EXPORT_SYMBOL_GPL(suspend_set_ops);
bool valid_state(suspend_state_t state)
{
- if (state == PM_SUSPEND_FREEZE)
- return true;
+ if (state == PM_SUSPEND_FREEZE) {
+#ifdef CONFIG_PM_DEBUG
+ if (pm_test_level != TEST_NONE &&
+ pm_test_level != TEST_FREEZER &&
+ pm_test_level != TEST_DEVICES &&
+ pm_test_level != TEST_PLATFORM) {
+ printk(KERN_WARNING "Unsupported pm_test mode for "
+ "freeze state, please choose "
+ "none/freezer/devices/platform.\n");
+ return false;
+ }
+#endif
+ return true;
+ }
/*
* PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel
* support and need to be valid to the lowlevel
@@ -184,6 +196,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
goto Platform_wake;
}
+ if (suspend_test(TEST_PLATFORM))
+ goto Platform_wake;
+
/*
* PM_SUSPEND_FREEZE equals
* frozen processes + suspended devices + idle processors.
@@ -195,9 +210,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
goto Platform_wake;
}
- if (suspend_test(TEST_PLATFORM))
- goto Platform_wake;
-
error = disable_nonboot_cpus();
if (error || suspend_test(TEST_CPUS))
goto Enable_cpus;
diff --git a/kernel/printk.c b/kernel/printk.c
index abbdd9e2ac82..96dcfcd9a2d4 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -43,19 +43,13 @@
#include <linux/rculist.h>
#include <linux/poll.h>
#include <linux/irq_work.h>
+#include <linux/utsname.h>
#include <asm/uaccess.h>
#define CREATE_TRACE_POINTS
#include <trace/events/printk.h>
-/*
- * Architectures can override it:
- */
-void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
-{
-}
-
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
@@ -608,7 +602,8 @@ static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
/* return error when data has vanished underneath us */
if (user->seq < log_first_seq)
ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
- ret = POLLIN|POLLRDNORM;
+ else
+ ret = POLLIN|POLLRDNORM;
}
raw_spin_unlock_irq(&logbuf_lock);
@@ -1265,7 +1260,7 @@ static void call_console_drivers(int level, const char *text, size_t len)
{
struct console *con;
- trace_console(text, 0, len, len);
+ trace_console(text, len);
if (level >= console_loglevel && !ignore_loglevel)
return;
@@ -1723,6 +1718,29 @@ static size_t cont_print_text(char *text, size_t size) { return 0; }
#endif /* CONFIG_PRINTK */
+#ifdef CONFIG_EARLY_PRINTK
+struct console *early_console;
+
+void early_vprintk(const char *fmt, va_list ap)
+{
+ if (early_console) {
+ char buf[512];
+ int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+
+ early_console->write(early_console, buf, n);
+ }
+}
+
+asmlinkage void early_printk(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ early_vprintk(fmt, ap);
+ va_end(ap);
+}
+#endif
+
static int __add_preferred_console(char *name, int idx, char *options,
char *brl_options)
{
@@ -2832,4 +2850,65 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
}
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
+
+static char dump_stack_arch_desc_str[128];
+
+/**
+ * dump_stack_set_arch_desc - set arch-specific str to show with task dumps
+ * @fmt: printf-style format string
+ * @...: arguments for the format string
+ *
+ * The configured string will be printed right after utsname during task
+ * dumps. Usually used to add arch-specific system identifiers. If an
+ * arch wants to make use of such an ID string, it should initialize this
+ * as soon as possible during boot.
+ */
+void __init dump_stack_set_arch_desc(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str),
+ fmt, args);
+ va_end(args);
+}
+
+/**
+ * dump_stack_print_info - print generic debug info for dump_stack()
+ * @log_lvl: log level
+ *
+ * Arch-specific dump_stack() implementations can use this function to
+ * print out the same debug information as the generic dump_stack().
+ */
+void dump_stack_print_info(const char *log_lvl)
+{
+ printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
+ log_lvl, raw_smp_processor_id(), current->pid, current->comm,
+ print_tainted(), init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+
+ if (dump_stack_arch_desc_str[0] != '\0')
+ printk("%sHardware name: %s\n",
+ log_lvl, dump_stack_arch_desc_str);
+
+ print_worker_info(log_lvl, current);
+}
+
+/**
+ * show_regs_print_info - print generic debug info for show_regs()
+ * @log_lvl: log level
+ *
+ * show_regs() implementations can use this function to print out generic
+ * debug information.
+ */
+void show_regs_print_info(const char *log_lvl)
+{
+ dump_stack_print_info(log_lvl);
+
+ printk("%stask: %p ti: %p task.ti: %p\n",
+ log_lvl, current, current_thread_info(),
+ task_thread_info(current));
+}
+
#endif
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index acbd28424d81..17ae54da0ec2 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -24,6 +24,7 @@
#include <linux/regset.h>
#include <linux/hw_breakpoint.h>
#include <linux/cn_proc.h>
+#include <linux/compat.h>
static int ptrace_trapping_sleep_fn(void *flags)
@@ -618,6 +619,81 @@ static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
return error;
}
+static int ptrace_peek_siginfo(struct task_struct *child,
+ unsigned long addr,
+ unsigned long data)
+{
+ struct ptrace_peeksiginfo_args arg;
+ struct sigpending *pending;
+ struct sigqueue *q;
+ int ret, i;
+
+ ret = copy_from_user(&arg, (void __user *) addr,
+ sizeof(struct ptrace_peeksiginfo_args));
+ if (ret)
+ return -EFAULT;
+
+ if (arg.flags & ~PTRACE_PEEKSIGINFO_SHARED)
+ return -EINVAL; /* unknown flags */
+
+ if (arg.nr < 0)
+ return -EINVAL;
+
+ if (arg.flags & PTRACE_PEEKSIGINFO_SHARED)
+ pending = &child->signal->shared_pending;
+ else
+ pending = &child->pending;
+
+ for (i = 0; i < arg.nr; ) {
+ siginfo_t info;
+ s32 off = arg.off + i;
+
+ spin_lock_irq(&child->sighand->siglock);
+ list_for_each_entry(q, &pending->list, list) {
+ if (!off--) {
+ copy_siginfo(&info, &q->info);
+ break;
+ }
+ }
+ spin_unlock_irq(&child->sighand->siglock);
+
+ if (off >= 0) /* beyond the end of the list */
+ break;
+
+#ifdef CONFIG_COMPAT
+ if (unlikely(is_compat_task())) {
+ compat_siginfo_t __user *uinfo = compat_ptr(data);
+
+ ret = copy_siginfo_to_user32(uinfo, &info);
+ ret |= __put_user(info.si_code, &uinfo->si_code);
+ } else
+#endif
+ {
+ siginfo_t __user *uinfo = (siginfo_t __user *) data;
+
+ ret = copy_siginfo_to_user(uinfo, &info);
+ ret |= __put_user(info.si_code, &uinfo->si_code);
+ }
+
+ if (ret) {
+ ret = -EFAULT;
+ break;
+ }
+
+ data += sizeof(siginfo_t);
+ i++;
+
+ if (signal_pending(current))
+ break;
+
+ cond_resched();
+ }
+
+ if (i > 0)
+ return i;
+
+ return ret;
+}
#ifdef PTRACE_SINGLESTEP
#define is_singlestep(request) ((request) == PTRACE_SINGLESTEP)
@@ -748,6 +824,10 @@ int ptrace_request(struct task_struct *child, long request,
ret = put_user(child->ptrace_message, datalp);
break;
+ case PTRACE_PEEKSIGINFO:
+ ret = ptrace_peek_siginfo(child, addr, data);
+ break;
+
case PTRACE_GETSIGINFO:
ret = ptrace_getsiginfo(child, &siginfo);
if (!ret)
diff --git a/kernel/range.c b/kernel/range.c
index 9b8ae2d6ed68..071b0ab455cb 100644
--- a/kernel/range.c
+++ b/kernel/range.c
@@ -97,7 +97,8 @@ void subtract_range(struct range *range, int az, u64 start, u64 end)
range[i].end = range[j].end;
range[i].start = end;
} else {
- printk(KERN_ERR "run of slot in ranges\n");
+ pr_err("%s: run out of slot in ranges\n",
+ __func__);
}
range[j].end = start;
continue;
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 5b8ad827fd86..d8534308fd05 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -64,7 +64,7 @@
static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
-#define RCU_STATE_INITIALIZER(sname, cr) { \
+#define RCU_STATE_INITIALIZER(sname, sabbr, cr) { \
.level = { &sname##_state.node[0] }, \
.call = cr, \
.fqs_state = RCU_GP_IDLE, \
@@ -76,13 +76,14 @@ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
.barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
.onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \
.name = #sname, \
+ .abbr = sabbr, \
}
struct rcu_state rcu_sched_state =
- RCU_STATE_INITIALIZER(rcu_sched, call_rcu_sched);
+ RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
-struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh, call_rcu_bh);
+struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);
DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
static struct rcu_state *rcu_state;
@@ -223,6 +224,8 @@ static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS;
module_param(jiffies_till_first_fqs, ulong, 0644);
module_param(jiffies_till_next_fqs, ulong, 0644);
+static void rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
+ struct rcu_data *rdp);
static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
static void force_quiescent_state(struct rcu_state *rsp);
static int rcu_pending(int cpu);
@@ -310,6 +313,8 @@ cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
if (rcu_gp_in_progress(rsp))
return 0; /* No, a grace period is already in progress. */
+ if (rcu_nocb_needs_gp(rsp))
+ return 1; /* Yes, a no-CBs CPU needs one. */
if (!rdp->nxttail[RCU_NEXT_TAIL])
return 0; /* No, this is a no-CBs (or offline) CPU. */
if (*rdp->nxttail[RCU_NEXT_READY_TAIL])
@@ -1035,10 +1040,11 @@ static void init_callback_list(struct rcu_data *rdp)
{
int i;
+ if (init_nocb_callback_list(rdp))
+ return;
rdp->nxtlist = NULL;
for (i = 0; i < RCU_NEXT_SIZE; i++)
rdp->nxttail[i] = &rdp->nxtlist;
- init_nocb_callback_list(rdp);
}
/*
@@ -1071,6 +1077,120 @@ static unsigned long rcu_cbs_completed(struct rcu_state *rsp,
}
/*
+ * Trace-event helper function for rcu_start_future_gp() and
+ * rcu_nocb_wait_gp().
+ */
+static void trace_rcu_future_gp(struct rcu_node *rnp, struct rcu_data *rdp,
+ unsigned long c, char *s)
+{
+ trace_rcu_future_grace_period(rdp->rsp->name, rnp->gpnum,
+ rnp->completed, c, rnp->level,
+ rnp->grplo, rnp->grphi, s);
+}
+
+/*
+ * Start some future grace period, as needed to handle newly arrived
+ * callbacks. The required future grace periods are recorded in each
+ * rcu_node structure's ->need_future_gp field.
+ *
+ * The caller must hold the specified rcu_node structure's ->lock.
+ */
+static unsigned long __maybe_unused
+rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp)
+{
+ unsigned long c;
+ int i;
+ struct rcu_node *rnp_root = rcu_get_root(rdp->rsp);
+
+ /*
+ * Pick up grace-period number for new callbacks. If this
+ * grace period is already marked as needed, return to the caller.
+ */
+ c = rcu_cbs_completed(rdp->rsp, rnp);
+ trace_rcu_future_gp(rnp, rdp, c, "Startleaf");
+ if (rnp->need_future_gp[c & 0x1]) {
+ trace_rcu_future_gp(rnp, rdp, c, "Prestartleaf");
+ return c;
+ }
+
+ /*
+ * If either this rcu_node structure or the root rcu_node structure
+ * believe that a grace period is in progress, then we must wait
+ * for the one following, which is in "c". Because our request
+ * will be noticed at the end of the current grace period, we don't
+ * need to explicitly start one.
+ */
+ if (rnp->gpnum != rnp->completed ||
+ ACCESS_ONCE(rnp->gpnum) != ACCESS_ONCE(rnp->completed)) {
+ rnp->need_future_gp[c & 0x1]++;
+ trace_rcu_future_gp(rnp, rdp, c, "Startedleaf");
+ return c;
+ }
+
+ /*
+ * There might be no grace period in progress. If we don't already
+ * hold it, acquire the root rcu_node structure's lock in order to
+ * start one (if needed).
+ */
+ if (rnp != rnp_root)
+ raw_spin_lock(&rnp_root->lock);
+
+ /*
+ * Get a new grace-period number. If there really is no grace
+ * period in progress, it will be smaller than the one we obtained
+ * earlier. Adjust callbacks as needed. Note that even no-CBs
+ * CPUs have a ->nxtcompleted[] array, so no no-CBs checks needed.
+ */
+ c = rcu_cbs_completed(rdp->rsp, rnp_root);
+ for (i = RCU_DONE_TAIL; i < RCU_NEXT_TAIL; i++)
+ if (ULONG_CMP_LT(c, rdp->nxtcompleted[i]))
+ rdp->nxtcompleted[i] = c;
+
+ /*
+ * If the needed for the required grace period is already
+ * recorded, trace and leave.
+ */
+ if (rnp_root->need_future_gp[c & 0x1]) {
+ trace_rcu_future_gp(rnp, rdp, c, "Prestartedroot");
+ goto unlock_out;
+ }
+
+ /* Record the need for the future grace period. */
+ rnp_root->need_future_gp[c & 0x1]++;
+
+ /* If a grace period is not already in progress, start one. */
+ if (rnp_root->gpnum != rnp_root->completed) {
+ trace_rcu_future_gp(rnp, rdp, c, "Startedleafroot");
+ } else {
+ trace_rcu_future_gp(rnp, rdp, c, "Startedroot");
+ rcu_start_gp_advanced(rdp->rsp, rnp_root, rdp);
+ }
+unlock_out:
+ if (rnp != rnp_root)
+ raw_spin_unlock(&rnp_root->lock);
+ return c;
+}
+
+/*
+ * Clean up any old requests for the just-ended grace period. Also return
+ * whether any additional grace periods have been requested. Also invoke
+ * rcu_nocb_gp_cleanup() in order to wake up any no-callbacks kthreads
+ * waiting for this grace period to complete.
+ */
+static int rcu_future_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
+{
+ int c = rnp->completed;
+ int needmore;
+ struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+
+ rcu_nocb_gp_cleanup(rsp, rnp);
+ rnp->need_future_gp[c & 0x1] = 0;
+ needmore = rnp->need_future_gp[(c + 1) & 0x1];
+ trace_rcu_future_gp(rnp, rdp, c, needmore ? "CleanupMore" : "Cleanup");
+ return needmore;
+}
+
+/*
* If there is room, assign a ->completed number to any callbacks on
* this CPU that have not already been assigned. Also accelerate any
* callbacks that were previously assigned a ->completed number that has
@@ -1129,6 +1249,8 @@ static void rcu_accelerate_cbs(struct rcu_state *rsp, struct rcu_node *rnp,
rdp->nxttail[i] = rdp->nxttail[RCU_NEXT_TAIL];
rdp->nxtcompleted[i] = c;
}
+ /* Record any needed additional grace periods. */
+ rcu_start_future_gp(rnp, rdp);
/* Trace depending on how much we were able to accelerate. */
if (!*rdp->nxttail[RCU_WAIT_TAIL])
@@ -1308,9 +1430,9 @@ static int rcu_gp_init(struct rcu_state *rsp)
rdp = this_cpu_ptr(rsp->rda);
rcu_preempt_check_blocked_tasks(rnp);
rnp->qsmask = rnp->qsmaskinit;
- rnp->gpnum = rsp->gpnum;
+ ACCESS_ONCE(rnp->gpnum) = rsp->gpnum;
WARN_ON_ONCE(rnp->completed != rsp->completed);
- rnp->completed = rsp->completed;
+ ACCESS_ONCE(rnp->completed) = rsp->completed;
if (rnp == rdp->mynode)
rcu_start_gp_per_cpu(rsp, rnp, rdp);
rcu_preempt_boost_start_gp(rnp);
@@ -1319,7 +1441,8 @@ static int rcu_gp_init(struct rcu_state *rsp)
rnp->grphi, rnp->qsmask);
raw_spin_unlock_irq(&rnp->lock);
#ifdef CONFIG_PROVE_RCU_DELAY
- if ((random32() % (rcu_num_nodes * 8)) == 0)
+ if ((prandom_u32() % (rcu_num_nodes * 8)) == 0 &&
+ system_state == SYSTEM_RUNNING)
schedule_timeout_uninterruptible(2);
#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
cond_resched();
@@ -1361,6 +1484,7 @@ int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
static void rcu_gp_cleanup(struct rcu_state *rsp)
{
unsigned long gp_duration;
+ int nocb = 0;
struct rcu_data *rdp;
struct rcu_node *rnp = rcu_get_root(rsp);
@@ -1390,17 +1514,23 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
*/
rcu_for_each_node_breadth_first(rsp, rnp) {
raw_spin_lock_irq(&rnp->lock);
- rnp->completed = rsp->gpnum;
+ ACCESS_ONCE(rnp->completed) = rsp->gpnum;
+ rdp = this_cpu_ptr(rsp->rda);
+ if (rnp == rdp->mynode)
+ __rcu_process_gp_end(rsp, rnp, rdp);
+ nocb += rcu_future_gp_cleanup(rsp, rnp);
raw_spin_unlock_irq(&rnp->lock);
cond_resched();
}
rnp = rcu_get_root(rsp);
raw_spin_lock_irq(&rnp->lock);
+ rcu_nocb_gp_set(rnp, nocb);
rsp->completed = rsp->gpnum; /* Declare grace period done. */
trace_rcu_grace_period(rsp->name, rsp->completed, "end");
rsp->fqs_state = RCU_GP_IDLE;
rdp = this_cpu_ptr(rsp->rda);
+ rcu_advance_cbs(rsp, rnp, rdp); /* Reduce false positives below. */
if (cpu_needs_another_gp(rsp, rdp))
rsp->gp_flags = 1;
raw_spin_unlock_irq(&rnp->lock);
@@ -1476,57 +1606,62 @@ static int __noreturn rcu_gp_kthread(void *arg)
/*
* Start a new RCU grace period if warranted, re-initializing the hierarchy
* in preparation for detecting the next grace period. The caller must hold
- * the root node's ->lock, which is released before return. Hard irqs must
- * be disabled.
+ * the root node's ->lock and hard irqs must be disabled.
*
* Note that it is legal for a dying CPU (which is marked as offline) to
* invoke this function. This can happen when the dying CPU reports its
* quiescent state.
*/
static void
-rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
- __releases(rcu_get_root(rsp)->lock)
+rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
+ struct rcu_data *rdp)
{
- struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
- struct rcu_node *rnp = rcu_get_root(rsp);
-
- if (!rsp->gp_kthread ||
- !cpu_needs_another_gp(rsp, rdp)) {
+ if (!rsp->gp_kthread || !cpu_needs_another_gp(rsp, rdp)) {
/*
* Either we have not yet spawned the grace-period
* task, this CPU does not need another grace period,
* or a grace period is already in progress.
* Either way, don't start a new grace period.
*/
- raw_spin_unlock_irqrestore(&rnp->lock, flags);
return;
}
-
- /*
- * Because there is no grace period in progress right now,
- * any callbacks we have up to this point will be satisfied
- * by the next grace period. So this is a good place to
- * assign a grace period number to recently posted callbacks.
- */
- rcu_accelerate_cbs(rsp, rnp, rdp);
-
rsp->gp_flags = RCU_GP_FLAG_INIT;
- raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */
-
- /* Ensure that CPU is aware of completion of last grace period. */
- rcu_process_gp_end(rsp, rdp);
- local_irq_restore(flags);
/* Wake up rcu_gp_kthread() to start the grace period. */
wake_up(&rsp->gp_wq);
}
/*
+ * Similar to rcu_start_gp_advanced(), but also advance the calling CPU's
+ * callbacks. Note that rcu_start_gp_advanced() cannot do this because it
+ * is invoked indirectly from rcu_advance_cbs(), which would result in
+ * endless recursion -- or would do so if it wasn't for the self-deadlock
+ * that is encountered beforehand.
+ */
+static void
+rcu_start_gp(struct rcu_state *rsp)
+{
+ struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+ struct rcu_node *rnp = rcu_get_root(rsp);
+
+ /*
+ * If there is no grace period in progress right now, any
+ * callbacks we have up to this point will be satisfied by the
+ * next grace period. Also, advancing the callbacks reduces the
+ * probability of false positives from cpu_needs_another_gp()
+ * resulting in pointless grace periods. So, advance callbacks
+ * then start the grace period!
+ */
+ rcu_advance_cbs(rsp, rnp, rdp);
+ rcu_start_gp_advanced(rsp, rnp, rdp);
+}
+
+/*
* Report a full set of quiescent states to the specified rcu_state
* data structure. This involves cleaning up after the prior grace
* period and letting rcu_start_gp() start up the next grace period
- * if one is needed. Note that the caller must hold rnp->lock, as
- * required by rcu_start_gp(), which will release it.
+ * if one is needed. Note that the caller must hold rnp->lock, which
+ * is released before return.
*/
static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
__releases(rcu_get_root(rsp)->lock)
@@ -2124,7 +2259,8 @@ __rcu_process_callbacks(struct rcu_state *rsp)
local_irq_save(flags);
if (cpu_needs_another_gp(rsp, rdp)) {
raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */
- rcu_start_gp(rsp, flags); /* releases above lock */
+ rcu_start_gp(rsp);
+ raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
} else {
local_irq_restore(flags);
}
@@ -2169,7 +2305,8 @@ static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp)
static void invoke_rcu_core(void)
{
- raise_softirq(RCU_SOFTIRQ);
+ if (cpu_online(smp_processor_id()))
+ raise_softirq(RCU_SOFTIRQ);
}
/*
@@ -2204,11 +2341,11 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
/* Start a new grace period if one not already started. */
if (!rcu_gp_in_progress(rsp)) {
- unsigned long nestflag;
struct rcu_node *rnp_root = rcu_get_root(rsp);
- raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
- rcu_start_gp(rsp, nestflag); /* rlses rnp_root->lock */
+ raw_spin_lock(&rnp_root->lock);
+ rcu_start_gp(rsp);
+ raw_spin_unlock(&rnp_root->lock);
} else {
/* Give the grace period a kick. */
rdp->blimit = LONG_MAX;
@@ -2628,19 +2765,27 @@ static int rcu_pending(int cpu)
}
/*
- * Check to see if any future RCU-related work will need to be done
- * by the current CPU, even if none need be done immediately, returning
- * 1 if so.
+ * Return true if the specified CPU has any callback. If all_lazy is
+ * non-NULL, store an indication of whether all callbacks are lazy.
+ * (If there are no callbacks, all of them are deemed to be lazy.)
*/
-static int rcu_cpu_has_callbacks(int cpu)
+static int rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
{
+ bool al = true;
+ bool hc = false;
+ struct rcu_data *rdp;
struct rcu_state *rsp;
- /* RCU callbacks either ready or pending? */
- for_each_rcu_flavor(rsp)
- if (per_cpu_ptr(rsp->rda, cpu)->nxtlist)
- return 1;
- return 0;
+ for_each_rcu_flavor(rsp) {
+ rdp = per_cpu_ptr(rsp->rda, cpu);
+ if (rdp->qlen != rdp->qlen_lazy)
+ al = false;
+ if (rdp->nxtlist)
+ hc = true;
+ }
+ if (all_lazy)
+ *all_lazy = al;
+ return hc;
}
/*
@@ -2859,7 +3004,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
rdp->dynticks->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
atomic_set(&rdp->dynticks->dynticks,
(atomic_read(&rdp->dynticks->dynticks) & ~0x1) + 1);
- rcu_prepare_for_idle_init(cpu);
raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
/* Add CPU to rcu_node bitmasks. */
@@ -2909,7 +3053,6 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
struct rcu_node *rnp = rdp->mynode;
struct rcu_state *rsp;
- int ret = NOTIFY_OK;
trace_rcu_utilization("Start CPU hotplug");
switch (action) {
@@ -2923,21 +3066,12 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
rcu_boost_kthread_setaffinity(rnp, -1);
break;
case CPU_DOWN_PREPARE:
- if (nocb_cpu_expendable(cpu))
- rcu_boost_kthread_setaffinity(rnp, cpu);
- else
- ret = NOTIFY_BAD;
+ rcu_boost_kthread_setaffinity(rnp, cpu);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
- /*
- * The whole machine is "stopped" except this CPU, so we can
- * touch any data without introducing corruption. We send the
- * dying CPU's callbacks to an arbitrarily chosen online CPU.
- */
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
- rcu_cleanup_after_idle(cpu);
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
@@ -2950,7 +3084,7 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
break;
}
trace_rcu_utilization("End CPU hotplug");
- return ret;
+ return NOTIFY_OK;
}
/*
@@ -3085,6 +3219,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,
}
rnp->level = i;
INIT_LIST_HEAD(&rnp->blkd_tasks);
+ rcu_init_one_nocb(rnp);
}
}
@@ -3170,8 +3305,7 @@ void __init rcu_init(void)
rcu_init_one(&rcu_sched_state, &rcu_sched_data);
rcu_init_one(&rcu_bh_state, &rcu_bh_data);
__rcu_init_preempt();
- rcu_init_nocb();
- open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
/*
* We don't need protection against CPU-hotplug here because
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index c896b5045d9d..14ee40795d6f 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -88,18 +88,13 @@ struct rcu_dynticks {
int dynticks_nmi_nesting; /* Track NMI nesting level. */
atomic_t dynticks; /* Even value for idle, else odd. */
#ifdef CONFIG_RCU_FAST_NO_HZ
- int dyntick_drain; /* Prepare-for-idle state variable. */
- unsigned long dyntick_holdoff;
- /* No retries for the jiffy of failure. */
- struct timer_list idle_gp_timer;
- /* Wake up CPU sleeping with callbacks. */
- unsigned long idle_gp_timer_expires;
- /* When to wake up CPU (for repost). */
- bool idle_first_pass; /* First pass of attempt to go idle? */
+ bool all_lazy; /* Are all CPU's CBs lazy? */
unsigned long nonlazy_posted;
/* # times non-lazy CBs posted to CPU. */
unsigned long nonlazy_posted_snap;
/* idle-period nonlazy_posted snapshot. */
+ unsigned long last_accelerate;
+ /* Last jiffy CBs were accelerated. */
int tick_nohz_enabled_snap; /* Previously seen value from sysfs. */
#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
};
@@ -134,9 +129,6 @@ struct rcu_node {
/* elements that need to drain to allow the */
/* current expedited grace period to */
/* complete (only for TREE_PREEMPT_RCU). */
- atomic_t wakemask; /* CPUs whose kthread needs to be awakened. */
- /* Since this has meaning only for leaf */
- /* rcu_node structures, 32 bits suffices. */
unsigned long qsmaskinit;
/* Per-GP initial value for qsmask & expmask. */
unsigned long grpmask; /* Mask to apply to parent qsmask. */
@@ -196,6 +188,12 @@ struct rcu_node {
/* Refused to boost: not sure why, though. */
/* This can happen due to race conditions. */
#endif /* #ifdef CONFIG_RCU_BOOST */
+#ifdef CONFIG_RCU_NOCB_CPU
+ wait_queue_head_t nocb_gp_wq[2];
+ /* Place for rcu_nocb_kthread() to wait GP. */
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
+ int need_future_gp[2];
+ /* Counts of upcoming no-CB GP requests. */
raw_spinlock_t fqslock ____cacheline_internodealigned_in_smp;
} ____cacheline_internodealigned_in_smp;
@@ -328,6 +326,11 @@ struct rcu_data {
struct task_struct *nocb_kthread;
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
+ /* 8) RCU CPU stall data. */
+#ifdef CONFIG_RCU_CPU_STALL_INFO
+ unsigned int softirq_snap; /* Snapshot of softirq activity. */
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_INFO */
+
int cpu;
struct rcu_state *rsp;
};
@@ -375,12 +378,6 @@ struct rcu_state {
struct rcu_data __percpu *rda; /* pointer of percu rcu_data. */
void (*call)(struct rcu_head *head, /* call_rcu() flavor. */
void (*func)(struct rcu_head *head));
-#ifdef CONFIG_RCU_NOCB_CPU
- void (*call_remote)(struct rcu_head *head,
- void (*func)(struct rcu_head *head));
- /* call_rcu() flavor, but for */
- /* placing on remote CPU. */
-#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
/* The following fields are guarded by the root rcu_node's lock. */
@@ -443,6 +440,7 @@ struct rcu_state {
unsigned long gp_max; /* Maximum GP duration in */
/* jiffies. */
char *name; /* Name of structure. */
+ char abbr; /* Abbreviated name. */
struct list_head flavors; /* List of RCU flavors. */
};
@@ -520,7 +518,6 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
struct rcu_node *rnp);
#endif /* #ifdef CONFIG_RCU_BOOST */
static void __cpuinit rcu_prepare_kthreads(int cpu);
-static void rcu_prepare_for_idle_init(int cpu);
static void rcu_cleanup_after_idle(int cpu);
static void rcu_prepare_for_idle(int cpu);
static void rcu_idle_count_callbacks_posted(void);
@@ -529,16 +526,18 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
static void print_cpu_stall_info_end(void);
static void zero_cpu_stall_ticks(struct rcu_data *rdp);
static void increment_cpu_stall_ticks(void);
+static int rcu_nocb_needs_gp(struct rcu_state *rsp);
+static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq);
+static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp);
+static void rcu_init_one_nocb(struct rcu_node *rnp);
static bool is_nocb_cpu(int cpu);
static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
bool lazy);
static bool rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
struct rcu_data *rdp);
-static bool nocb_cpu_expendable(int cpu);
static void rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp);
static void rcu_spawn_nocb_kthreads(struct rcu_state *rsp);
-static void init_nocb_callback_list(struct rcu_data *rdp);
-static void __init rcu_init_nocb(void);
+static bool init_nocb_callback_list(struct rcu_data *rdp);
#endif /* #ifndef RCU_TREE_NONCORE */
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index c1cc7e17ff9d..d084ae3f281c 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -85,11 +85,21 @@ static void __init rcu_bootup_announce_oddness(void)
if (nr_cpu_ids != NR_CPUS)
printk(KERN_INFO "\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
#ifdef CONFIG_RCU_NOCB_CPU
+#ifndef CONFIG_RCU_NOCB_CPU_NONE
+ if (!have_rcu_nocb_mask) {
+ alloc_bootmem_cpumask_var(&rcu_nocb_mask);
+ have_rcu_nocb_mask = true;
+ }
+#ifdef CONFIG_RCU_NOCB_CPU_ZERO
+ pr_info("\tExperimental no-CBs CPU 0\n");
+ cpumask_set_cpu(0, rcu_nocb_mask);
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
+#ifdef CONFIG_RCU_NOCB_CPU_ALL
+ pr_info("\tExperimental no-CBs for all CPUs\n");
+ cpumask_setall(rcu_nocb_mask);
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
if (have_rcu_nocb_mask) {
- if (cpumask_test_cpu(0, rcu_nocb_mask)) {
- cpumask_clear_cpu(0, rcu_nocb_mask);
- pr_info("\tCPU 0: illegal no-CBs CPU (cleared).\n");
- }
cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
pr_info("\tExperimental no-CBs CPUs: %s.\n", nocb_buf);
if (rcu_nocb_poll)
@@ -101,7 +111,7 @@ static void __init rcu_bootup_announce_oddness(void)
#ifdef CONFIG_TREE_PREEMPT_RCU
struct rcu_state rcu_preempt_state =
- RCU_STATE_INITIALIZER(rcu_preempt, call_rcu);
+ RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu);
DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
static struct rcu_state *rcu_state = &rcu_preempt_state;
@@ -1533,14 +1543,7 @@ static void __cpuinit rcu_prepare_kthreads(int cpu)
int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
- return rcu_cpu_has_callbacks(cpu);
-}
-
-/*
- * Because we do not have RCU_FAST_NO_HZ, don't bother initializing for it.
- */
-static void rcu_prepare_for_idle_init(int cpu)
-{
+ return rcu_cpu_has_callbacks(cpu, NULL);
}
/*
@@ -1577,16 +1580,6 @@ static void rcu_idle_count_callbacks_posted(void)
*
* The following three proprocessor symbols control this state machine:
*
- * RCU_IDLE_FLUSHES gives the maximum number of times that we will attempt
- * to satisfy RCU. Beyond this point, it is better to incur a periodic
- * scheduling-clock interrupt than to loop through the state machine
- * at full power.
- * RCU_IDLE_OPT_FLUSHES gives the number of RCU_IDLE_FLUSHES that are
- * optional if RCU does not need anything immediately from this
- * CPU, even if this CPU still has RCU callbacks queued. The first
- * times through the state machine are mandatory: we need to give
- * the state machine a chance to communicate a quiescent state
- * to the RCU core.
* RCU_IDLE_GP_DELAY gives the number of jiffies that a CPU is permitted
* to sleep in dyntick-idle mode with RCU callbacks pending. This
* is sized to be roughly one RCU grace period. Those energy-efficiency
@@ -1602,186 +1595,108 @@ static void rcu_idle_count_callbacks_posted(void)
* adjustment, they can be converted into kernel config parameters, though
* making the state machine smarter might be a better option.
*/
-#define RCU_IDLE_FLUSHES 5 /* Number of dyntick-idle tries. */
-#define RCU_IDLE_OPT_FLUSHES 3 /* Optional dyntick-idle tries. */
#define RCU_IDLE_GP_DELAY 4 /* Roughly one grace period. */
#define RCU_IDLE_LAZY_GP_DELAY (6 * HZ) /* Roughly six seconds. */
-extern int tick_nohz_enabled;
-
-/*
- * Does the specified flavor of RCU have non-lazy callbacks pending on
- * the specified CPU? Both RCU flavor and CPU are specified by the
- * rcu_data structure.
- */
-static bool __rcu_cpu_has_nonlazy_callbacks(struct rcu_data *rdp)
-{
- return rdp->qlen != rdp->qlen_lazy;
-}
+static int rcu_idle_gp_delay = RCU_IDLE_GP_DELAY;
+module_param(rcu_idle_gp_delay, int, 0644);
+static int rcu_idle_lazy_gp_delay = RCU_IDLE_LAZY_GP_DELAY;
+module_param(rcu_idle_lazy_gp_delay, int, 0644);
-#ifdef CONFIG_TREE_PREEMPT_RCU
+extern int tick_nohz_enabled;
/*
- * Are there non-lazy RCU-preempt callbacks? (There cannot be if there
- * is no RCU-preempt in the kernel.)
+ * Try to advance callbacks for all flavors of RCU on the current CPU.
+ * Afterwards, if there are any callbacks ready for immediate invocation,
+ * return true.
*/
-static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
+static bool rcu_try_advance_all_cbs(void)
{
- struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
-
- return __rcu_cpu_has_nonlazy_callbacks(rdp);
-}
-
-#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+ bool cbs_ready = false;
+ struct rcu_data *rdp;
+ struct rcu_node *rnp;
+ struct rcu_state *rsp;
-static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
-{
- return 0;
-}
+ for_each_rcu_flavor(rsp) {
+ rdp = this_cpu_ptr(rsp->rda);
+ rnp = rdp->mynode;
-#endif /* else #ifdef CONFIG_TREE_PREEMPT_RCU */
+ /*
+ * Don't bother checking unless a grace period has
+ * completed since we last checked and there are
+ * callbacks not yet ready to invoke.
+ */
+ if (rdp->completed != rnp->completed &&
+ rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL])
+ rcu_process_gp_end(rsp, rdp);
-/*
- * Does any flavor of RCU have non-lazy callbacks on the specified CPU?
- */
-static bool rcu_cpu_has_nonlazy_callbacks(int cpu)
-{
- return __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_sched_data, cpu)) ||
- __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_bh_data, cpu)) ||
- rcu_preempt_cpu_has_nonlazy_callbacks(cpu);
+ if (cpu_has_callbacks_ready_to_invoke(rdp))
+ cbs_ready = true;
+ }
+ return cbs_ready;
}
/*
- * Allow the CPU to enter dyntick-idle mode if either: (1) There are no
- * callbacks on this CPU, (2) this CPU has not yet attempted to enter
- * dyntick-idle mode, or (3) this CPU is in the process of attempting to
- * enter dyntick-idle mode. Otherwise, if we have recently tried and failed
- * to enter dyntick-idle mode, we refuse to try to enter it. After all,
- * it is better to incur scheduling-clock interrupts than to spin
- * continuously for the same time duration!
+ * Allow the CPU to enter dyntick-idle mode unless it has callbacks ready
+ * to invoke. If the CPU has callbacks, try to advance them. Tell the
+ * caller to set the timeout based on whether or not there are non-lazy
+ * callbacks.
*
- * The delta_jiffies argument is used to store the time when RCU is
- * going to need the CPU again if it still has callbacks. The reason
- * for this is that rcu_prepare_for_idle() might need to post a timer,
- * but if so, it will do so after tick_nohz_stop_sched_tick() has set
- * the wakeup time for this CPU. This means that RCU's timer can be
- * delayed until the wakeup time, which defeats the purpose of posting
- * a timer.
+ * The caller must have disabled interrupts.
*/
-int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
+int rcu_needs_cpu(int cpu, unsigned long *dj)
{
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
- /* Flag a new idle sojourn to the idle-entry state machine. */
- rdtp->idle_first_pass = 1;
+ /* Snapshot to detect later posting of non-lazy callback. */
+ rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
+
/* If no callbacks, RCU doesn't need the CPU. */
- if (!rcu_cpu_has_callbacks(cpu)) {
- *delta_jiffies = ULONG_MAX;
+ if (!rcu_cpu_has_callbacks(cpu, &rdtp->all_lazy)) {
+ *dj = ULONG_MAX;
return 0;
}
- if (rdtp->dyntick_holdoff == jiffies) {
- /* RCU recently tried and failed, so don't try again. */
- *delta_jiffies = 1;
+
+ /* Attempt to advance callbacks. */
+ if (rcu_try_advance_all_cbs()) {
+ /* Some ready to invoke, so initiate later invocation. */
+ invoke_rcu_core();
return 1;
}
- /* Set up for the possibility that RCU will post a timer. */
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
- *delta_jiffies = round_up(RCU_IDLE_GP_DELAY + jiffies,
- RCU_IDLE_GP_DELAY) - jiffies;
+ rdtp->last_accelerate = jiffies;
+
+ /* Request timer delay depending on laziness, and round. */
+ if (rdtp->all_lazy) {
+ *dj = round_up(rcu_idle_gp_delay + jiffies,
+ rcu_idle_gp_delay) - jiffies;
} else {
- *delta_jiffies = jiffies + RCU_IDLE_LAZY_GP_DELAY;
- *delta_jiffies = round_jiffies(*delta_jiffies) - jiffies;
+ *dj = round_jiffies(rcu_idle_lazy_gp_delay + jiffies) - jiffies;
}
return 0;
}
/*
- * Handler for smp_call_function_single(). The only point of this
- * handler is to wake the CPU up, so the handler does only tracing.
- */
-void rcu_idle_demigrate(void *unused)
-{
- trace_rcu_prep_idle("Demigrate");
-}
-
-/*
- * Timer handler used to force CPU to start pushing its remaining RCU
- * callbacks in the case where it entered dyntick-idle mode with callbacks
- * pending. The hander doesn't really need to do anything because the
- * real work is done upon re-entry to idle, or by the next scheduling-clock
- * interrupt should idle not be re-entered.
- *
- * One special case: the timer gets migrated without awakening the CPU
- * on which the timer was scheduled on. In this case, we must wake up
- * that CPU. We do so with smp_call_function_single().
- */
-static void rcu_idle_gp_timer_func(unsigned long cpu_in)
-{
- int cpu = (int)cpu_in;
-
- trace_rcu_prep_idle("Timer");
- if (cpu != smp_processor_id())
- smp_call_function_single(cpu, rcu_idle_demigrate, NULL, 0);
- else
- WARN_ON_ONCE(1); /* Getting here can hang the system... */
-}
-
-/*
- * Initialize the timer used to pull CPUs out of dyntick-idle mode.
- */
-static void rcu_prepare_for_idle_init(int cpu)
-{
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
-
- rdtp->dyntick_holdoff = jiffies - 1;
- setup_timer(&rdtp->idle_gp_timer, rcu_idle_gp_timer_func, cpu);
- rdtp->idle_gp_timer_expires = jiffies - 1;
- rdtp->idle_first_pass = 1;
-}
-
-/*
- * Clean up for exit from idle. Because we are exiting from idle, there
- * is no longer any point to ->idle_gp_timer, so cancel it. This will
- * do nothing if this timer is not active, so just cancel it unconditionally.
- */
-static void rcu_cleanup_after_idle(int cpu)
-{
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
-
- del_timer(&rdtp->idle_gp_timer);
- trace_rcu_prep_idle("Cleanup after idle");
- rdtp->tick_nohz_enabled_snap = ACCESS_ONCE(tick_nohz_enabled);
-}
-
-/*
- * Check to see if any RCU-related work can be done by the current CPU,
- * and if so, schedule a softirq to get it done. This function is part
- * of the RCU implementation; it is -not- an exported member of the RCU API.
- *
- * The idea is for the current CPU to clear out all work required by the
- * RCU core for the current grace period, so that this CPU can be permitted
- * to enter dyntick-idle mode. In some cases, it will need to be awakened
- * at the end of the grace period by whatever CPU ends the grace period.
- * This allows CPUs to go dyntick-idle more quickly, and to reduce the
- * number of wakeups by a modest integer factor.
- *
- * Because it is not legal to invoke rcu_process_callbacks() with irqs
- * disabled, we do one pass of force_quiescent_state(), then do a
- * invoke_rcu_core() to cause rcu_process_callbacks() to be invoked
- * later. The ->dyntick_drain field controls the sequencing.
+ * Prepare a CPU for idle from an RCU perspective. The first major task
+ * is to sense whether nohz mode has been enabled or disabled via sysfs.
+ * The second major task is to check to see if a non-lazy callback has
+ * arrived at a CPU that previously had only lazy callbacks. The third
+ * major task is to accelerate (that is, assign grace-period numbers to)
+ * any recently arrived callbacks.
*
* The caller must have disabled interrupts.
*/
static void rcu_prepare_for_idle(int cpu)
{
- struct timer_list *tp;
+ struct rcu_data *rdp;
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+ struct rcu_node *rnp;
+ struct rcu_state *rsp;
int tne;
/* Handle nohz enablement switches conservatively. */
tne = ACCESS_ONCE(tick_nohz_enabled);
if (tne != rdtp->tick_nohz_enabled_snap) {
- if (rcu_cpu_has_callbacks(cpu))
+ if (rcu_cpu_has_callbacks(cpu, NULL))
invoke_rcu_core(); /* force nohz to see update. */
rdtp->tick_nohz_enabled_snap = tne;
return;
@@ -1789,125 +1704,56 @@ static void rcu_prepare_for_idle(int cpu)
if (!tne)
return;
- /* Adaptive-tick mode, where usermode execution is idle to RCU. */
- if (!is_idle_task(current)) {
- rdtp->dyntick_holdoff = jiffies - 1;
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
- trace_rcu_prep_idle("User dyntick with callbacks");
- rdtp->idle_gp_timer_expires =
- round_up(jiffies + RCU_IDLE_GP_DELAY,
- RCU_IDLE_GP_DELAY);
- } else if (rcu_cpu_has_callbacks(cpu)) {
- rdtp->idle_gp_timer_expires =
- round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
- trace_rcu_prep_idle("User dyntick with lazy callbacks");
- } else {
- return;
- }
- tp = &rdtp->idle_gp_timer;
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
+ /* If this is a no-CBs CPU, no callbacks, just return. */
+ if (is_nocb_cpu(cpu))
return;
- }
/*
- * If this is an idle re-entry, for example, due to use of
- * RCU_NONIDLE() or the new idle-loop tracing API within the idle
- * loop, then don't take any state-machine actions, unless the
- * momentary exit from idle queued additional non-lazy callbacks.
- * Instead, repost the ->idle_gp_timer if this CPU has callbacks
- * pending.
+ * If a non-lazy callback arrived at a CPU having only lazy
+ * callbacks, invoke RCU core for the side-effect of recalculating
+ * idle duration on re-entry to idle.
*/
- if (!rdtp->idle_first_pass &&
- (rdtp->nonlazy_posted == rdtp->nonlazy_posted_snap)) {
- if (rcu_cpu_has_callbacks(cpu)) {
- tp = &rdtp->idle_gp_timer;
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
- }
+ if (rdtp->all_lazy &&
+ rdtp->nonlazy_posted != rdtp->nonlazy_posted_snap) {
+ invoke_rcu_core();
return;
}
- rdtp->idle_first_pass = 0;
- rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted - 1;
/*
- * If there are no callbacks on this CPU, enter dyntick-idle mode.
- * Also reset state to avoid prejudicing later attempts.
+ * If we have not yet accelerated this jiffy, accelerate all
+ * callbacks on this CPU.
*/
- if (!rcu_cpu_has_callbacks(cpu)) {
- rdtp->dyntick_holdoff = jiffies - 1;
- rdtp->dyntick_drain = 0;
- trace_rcu_prep_idle("No callbacks");
+ if (rdtp->last_accelerate == jiffies)
return;
+ rdtp->last_accelerate = jiffies;
+ for_each_rcu_flavor(rsp) {
+ rdp = per_cpu_ptr(rsp->rda, cpu);
+ if (!*rdp->nxttail[RCU_DONE_TAIL])
+ continue;
+ rnp = rdp->mynode;
+ raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+ rcu_accelerate_cbs(rsp, rnp, rdp);
+ raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
}
+}
- /*
- * If in holdoff mode, just return. We will presumably have
- * refrained from disabling the scheduling-clock tick.
- */
- if (rdtp->dyntick_holdoff == jiffies) {
- trace_rcu_prep_idle("In holdoff");
- return;
- }
+/*
+ * Clean up for exit from idle. Attempt to advance callbacks based on
+ * any grace periods that elapsed while the CPU was idle, and if any
+ * callbacks are now ready to invoke, initiate invocation.
+ */
+static void rcu_cleanup_after_idle(int cpu)
+{
+ struct rcu_data *rdp;
+ struct rcu_state *rsp;
- /* Check and update the ->dyntick_drain sequencing. */
- if (rdtp->dyntick_drain <= 0) {
- /* First time through, initialize the counter. */
- rdtp->dyntick_drain = RCU_IDLE_FLUSHES;
- } else if (rdtp->dyntick_drain <= RCU_IDLE_OPT_FLUSHES &&
- !rcu_pending(cpu) &&
- !local_softirq_pending()) {
- /* Can we go dyntick-idle despite still having callbacks? */
- rdtp->dyntick_drain = 0;
- rdtp->dyntick_holdoff = jiffies;
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
- trace_rcu_prep_idle("Dyntick with callbacks");
- rdtp->idle_gp_timer_expires =
- round_up(jiffies + RCU_IDLE_GP_DELAY,
- RCU_IDLE_GP_DELAY);
- } else {
- rdtp->idle_gp_timer_expires =
- round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
- trace_rcu_prep_idle("Dyntick with lazy callbacks");
- }
- tp = &rdtp->idle_gp_timer;
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
- rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
- return; /* Nothing more to do immediately. */
- } else if (--(rdtp->dyntick_drain) <= 0) {
- /* We have hit the limit, so time to give up. */
- rdtp->dyntick_holdoff = jiffies;
- trace_rcu_prep_idle("Begin holdoff");
- invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */
+ if (is_nocb_cpu(cpu))
return;
- }
-
- /*
- * Do one step of pushing the remaining RCU callbacks through
- * the RCU core state machine.
- */
-#ifdef CONFIG_TREE_PREEMPT_RCU
- if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
- rcu_preempt_qs(cpu);
- force_quiescent_state(&rcu_preempt_state);
- }
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
- if (per_cpu(rcu_sched_data, cpu).nxtlist) {
- rcu_sched_qs(cpu);
- force_quiescent_state(&rcu_sched_state);
- }
- if (per_cpu(rcu_bh_data, cpu).nxtlist) {
- rcu_bh_qs(cpu);
- force_quiescent_state(&rcu_bh_state);
- }
-
- /*
- * If RCU callbacks are still pending, RCU still needs this CPU.
- * So try forcing the callbacks through the grace period.
- */
- if (rcu_cpu_has_callbacks(cpu)) {
- trace_rcu_prep_idle("More callbacks");
- invoke_rcu_core();
- } else {
- trace_rcu_prep_idle("Callbacks drained");
+ rcu_try_advance_all_cbs();
+ for_each_rcu_flavor(rsp) {
+ rdp = per_cpu_ptr(rsp->rda, cpu);
+ if (cpu_has_callbacks_ready_to_invoke(rdp))
+ invoke_rcu_core();
}
}
@@ -2015,16 +1861,13 @@ early_initcall(rcu_register_oom_notifier);
static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
{
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
- struct timer_list *tltp = &rdtp->idle_gp_timer;
- char c;
+ unsigned long nlpd = rdtp->nonlazy_posted - rdtp->nonlazy_posted_snap;
- c = rdtp->dyntick_holdoff == jiffies ? 'H' : '.';
- if (timer_pending(tltp))
- sprintf(cp, "drain=%d %c timer=%lu",
- rdtp->dyntick_drain, c, tltp->expires - jiffies);
- else
- sprintf(cp, "drain=%d %c timer not pending",
- rdtp->dyntick_drain, c);
+ sprintf(cp, "last_accelerate: %04lx/%04lx, nonlazy_posted: %ld, %c%c",
+ rdtp->last_accelerate & 0xffff, jiffies & 0xffff,
+ ulong2long(nlpd),
+ rdtp->all_lazy ? 'L' : '.',
+ rdtp->tick_nohz_enabled_snap ? '.' : 'D');
}
#else /* #ifdef CONFIG_RCU_FAST_NO_HZ */
@@ -2070,10 +1913,11 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
ticks_value = rsp->gpnum - rdp->gpnum;
}
print_cpu_stall_fast_no_hz(fast_no_hz, cpu);
- printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d %s\n",
+ printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u %s\n",
cpu, ticks_value, ticks_title,
atomic_read(&rdtp->dynticks) & 0xfff,
rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting,
+ rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),
fast_no_hz);
}
@@ -2087,6 +1931,7 @@ static void print_cpu_stall_info_end(void)
static void zero_cpu_stall_ticks(struct rcu_data *rdp)
{
rdp->ticks_this_gp = 0;
+ rdp->softirq_snap = kstat_softirqs_cpu(RCU_SOFTIRQ, smp_processor_id());
}
/* Increment ->ticks_this_gp for all flavors of RCU. */
@@ -2165,6 +2010,47 @@ static int __init parse_rcu_nocb_poll(char *arg)
}
early_param("rcu_nocb_poll", parse_rcu_nocb_poll);
+/*
+ * Do any no-CBs CPUs need another grace period?
+ *
+ * Interrupts must be disabled. If the caller does not hold the root
+ * rnp_node structure's ->lock, the results are advisory only.
+ */
+static int rcu_nocb_needs_gp(struct rcu_state *rsp)
+{
+ struct rcu_node *rnp = rcu_get_root(rsp);
+
+ return rnp->need_future_gp[(ACCESS_ONCE(rnp->completed) + 1) & 0x1];
+}
+
+/*
+ * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended
+ * grace period.
+ */
+static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
+{
+ wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]);
+}
+
+/*
+ * Set the root rcu_node structure's ->need_future_gp field
+ * based on the sum of those of all rcu_node structures. This does
+ * double-count the root rcu_node structure's requests, but this
+ * is necessary to handle the possibility of a rcu_nocb_kthread()
+ * having awakened during the time that the rcu_node structures
+ * were being updated for the end of the previous grace period.
+ */
+static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq)
+{
+ rnp->need_future_gp[(rnp->completed + 1) & 0x1] += nrq;
+}
+
+static void rcu_init_one_nocb(struct rcu_node *rnp)
+{
+ init_waitqueue_head(&rnp->nocb_gp_wq[0]);
+ init_waitqueue_head(&rnp->nocb_gp_wq[1]);
+}
+
/* Is the specified CPU a no-CPUs CPU? */
static bool is_nocb_cpu(int cpu)
{
@@ -2227,6 +2113,13 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
if (!is_nocb_cpu(rdp->cpu))
return 0;
__call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy);
+ if (__is_kfree_rcu_offset((unsigned long)rhp->func))
+ trace_rcu_kfree_callback(rdp->rsp->name, rhp,
+ (unsigned long)rhp->func,
+ rdp->qlen_lazy, rdp->qlen);
+ else
+ trace_rcu_callback(rdp->rsp->name, rhp,
+ rdp->qlen_lazy, rdp->qlen);
return 1;
}
@@ -2265,95 +2158,36 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
}
/*
- * There must be at least one non-no-CBs CPU in operation at any given
- * time, because no-CBs CPUs are not capable of initiating grace periods
- * independently. This function therefore complains if the specified
- * CPU is the last non-no-CBs CPU, allowing the CPU-hotplug system to
- * avoid offlining the last such CPU. (Recursion is a wonderful thing,
- * but you have to have a base case!)
+ * If necessary, kick off a new grace period, and either way wait
+ * for a subsequent grace period to complete.
*/
-static bool nocb_cpu_expendable(int cpu)
+static void rcu_nocb_wait_gp(struct rcu_data *rdp)
{
- cpumask_var_t non_nocb_cpus;
- int ret;
+ unsigned long c;
+ bool d;
+ unsigned long flags;
+ struct rcu_node *rnp = rdp->mynode;
+
+ raw_spin_lock_irqsave(&rnp->lock, flags);
+ c = rcu_start_future_gp(rnp, rdp);
+ raw_spin_unlock_irqrestore(&rnp->lock, flags);
/*
- * If there are no no-CB CPUs or if this CPU is not a no-CB CPU,
- * then offlining this CPU is harmless. Let it happen.
+ * Wait for the grace period. Do so interruptibly to avoid messing
+ * up the load average.
*/
- if (!have_rcu_nocb_mask || is_nocb_cpu(cpu))
- return 1;
-
- /* If no memory, play it safe and keep the CPU around. */
- if (!alloc_cpumask_var(&non_nocb_cpus, GFP_NOIO))
- return 0;
- cpumask_andnot(non_nocb_cpus, cpu_online_mask, rcu_nocb_mask);
- cpumask_clear_cpu(cpu, non_nocb_cpus);
- ret = !cpumask_empty(non_nocb_cpus);
- free_cpumask_var(non_nocb_cpus);
- return ret;
-}
-
-/*
- * Helper structure for remote registry of RCU callbacks.
- * This is needed for when a no-CBs CPU needs to start a grace period.
- * If it just invokes call_rcu(), the resulting callback will be queued,
- * which can result in deadlock.
- */
-struct rcu_head_remote {
- struct rcu_head *rhp;
- call_rcu_func_t *crf;
- void (*func)(struct rcu_head *rhp);
-};
-
-/*
- * Register a callback as specified by the rcu_head_remote struct.
- * This function is intended to be invoked via smp_call_function_single().
- */
-static void call_rcu_local(void *arg)
-{
- struct rcu_head_remote *rhrp =
- container_of(arg, struct rcu_head_remote, rhp);
-
- rhrp->crf(rhrp->rhp, rhrp->func);
-}
-
-/*
- * Set up an rcu_head_remote structure and the invoke call_rcu_local()
- * on CPU 0 (which is guaranteed to be a non-no-CBs CPU) via
- * smp_call_function_single().
- */
-static void invoke_crf_remote(struct rcu_head *rhp,
- void (*func)(struct rcu_head *rhp),
- call_rcu_func_t crf)
-{
- struct rcu_head_remote rhr;
-
- rhr.rhp = rhp;
- rhr.crf = crf;
- rhr.func = func;
- smp_call_function_single(0, call_rcu_local, &rhr, 1);
-}
-
-/*
- * Helper functions to be passed to wait_rcu_gp(), each of which
- * invokes invoke_crf_remote() to register a callback appropriately.
- */
-static void __maybe_unused
-call_rcu_preempt_remote(struct rcu_head *rhp,
- void (*func)(struct rcu_head *rhp))
-{
- invoke_crf_remote(rhp, func, call_rcu);
-}
-static void call_rcu_bh_remote(struct rcu_head *rhp,
- void (*func)(struct rcu_head *rhp))
-{
- invoke_crf_remote(rhp, func, call_rcu_bh);
-}
-static void call_rcu_sched_remote(struct rcu_head *rhp,
- void (*func)(struct rcu_head *rhp))
-{
- invoke_crf_remote(rhp, func, call_rcu_sched);
+ trace_rcu_future_gp(rnp, rdp, c, "StartWait");
+ for (;;) {
+ wait_event_interruptible(
+ rnp->nocb_gp_wq[c & 0x1],
+ (d = ULONG_CMP_GE(ACCESS_ONCE(rnp->completed), c)));
+ if (likely(d))
+ break;
+ flush_signals(current);
+ trace_rcu_future_gp(rnp, rdp, c, "ResumeWait");
+ }
+ trace_rcu_future_gp(rnp, rdp, c, "EndWait");
+ smp_mb(); /* Ensure that CB invocation happens after GP end. */
}
/*
@@ -2390,7 +2224,7 @@ static int rcu_nocb_kthread(void *arg)
cl = atomic_long_xchg(&rdp->nocb_q_count_lazy, 0);
ACCESS_ONCE(rdp->nocb_p_count) += c;
ACCESS_ONCE(rdp->nocb_p_count_lazy) += cl;
- wait_rcu_gp(rdp->rsp->call_remote);
+ rcu_nocb_wait_gp(rdp);
/* Each pass through the following loop invokes a callback. */
trace_rcu_batch_start(rdp->rsp->name, cl, c, -1);
@@ -2436,32 +2270,41 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
return;
for_each_cpu(cpu, rcu_nocb_mask) {
rdp = per_cpu_ptr(rsp->rda, cpu);
- t = kthread_run(rcu_nocb_kthread, rdp, "rcuo%d", cpu);
+ t = kthread_run(rcu_nocb_kthread, rdp,
+ "rcuo%c/%d", rsp->abbr, cpu);
BUG_ON(IS_ERR(t));
ACCESS_ONCE(rdp->nocb_kthread) = t;
}
}
/* Prevent __call_rcu() from enqueuing callbacks on no-CBs CPUs */
-static void init_nocb_callback_list(struct rcu_data *rdp)
+static bool init_nocb_callback_list(struct rcu_data *rdp)
{
if (rcu_nocb_mask == NULL ||
!cpumask_test_cpu(rdp->cpu, rcu_nocb_mask))
- return;
+ return false;
rdp->nxttail[RCU_NEXT_TAIL] = NULL;
+ return true;
+}
+
+#else /* #ifdef CONFIG_RCU_NOCB_CPU */
+
+static int rcu_nocb_needs_gp(struct rcu_state *rsp)
+{
+ return 0;
}
-/* Initialize the ->call_remote fields in the rcu_state structures. */
-static void __init rcu_init_nocb(void)
+static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
{
-#ifdef CONFIG_PREEMPT_RCU
- rcu_preempt_state.call_remote = call_rcu_preempt_remote;
-#endif /* #ifdef CONFIG_PREEMPT_RCU */
- rcu_bh_state.call_remote = call_rcu_bh_remote;
- rcu_sched_state.call_remote = call_rcu_sched_remote;
}
-#else /* #ifdef CONFIG_RCU_NOCB_CPU */
+static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq)
+{
+}
+
+static void rcu_init_one_nocb(struct rcu_node *rnp)
+{
+}
static bool is_nocb_cpu(int cpu)
{
@@ -2480,11 +2323,6 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
return 0;
}
-static bool nocb_cpu_expendable(int cpu)
-{
- return 1;
-}
-
static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
{
}
@@ -2493,12 +2331,9 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
{
}
-static void init_nocb_callback_list(struct rcu_data *rdp)
-{
-}
-
-static void __init rcu_init_nocb(void)
+static bool init_nocb_callback_list(struct rcu_data *rdp)
{
+ return false;
}
#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index 0d095dcaa670..49099e81c87b 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -46,8 +46,6 @@
#define RCU_TREE_NONCORE
#include "rcutree.h"
-#define ulong2long(a) (*(long *)(&(a)))
-
static int r_open(struct inode *inode, struct file *file,
const struct seq_operations *op)
{
diff --git a/kernel/relay.c b/kernel/relay.c
index 01ab081ac53a..eef0d113b79e 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -588,7 +588,7 @@ struct rchan *relay_open(const char *base_filename,
chan->version = RELAYFS_CHANNEL_VERSION;
chan->n_subbufs = n_subbufs;
chan->subbuf_size = subbuf_size;
- chan->alloc_size = FIX_SIZE(subbuf_size * n_subbufs);
+ chan->alloc_size = PAGE_ALIGN(subbuf_size * n_subbufs);
chan->parent = parent;
chan->private_data = private_data;
if (base_filename) {
@@ -1099,8 +1099,7 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
static int subbuf_read_actor(size_t read_start,
struct rchan_buf *buf,
size_t avail,
- read_descriptor_t *desc,
- read_actor_t actor)
+ read_descriptor_t *desc)
{
void *from;
int ret = 0;
@@ -1121,15 +1120,13 @@ static int subbuf_read_actor(size_t read_start,
typedef int (*subbuf_actor_t) (size_t read_start,
struct rchan_buf *buf,
size_t avail,
- read_descriptor_t *desc,
- read_actor_t actor);
+ read_descriptor_t *desc);
/*
* relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
*/
static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
subbuf_actor_t subbuf_actor,
- read_actor_t actor,
read_descriptor_t *desc)
{
struct rchan_buf *buf = filp->private_data;
@@ -1150,7 +1147,7 @@ static ssize_t relay_file_read_subbufs(struct file *filp, loff_t *ppos,
break;
avail = min(desc->count, avail);
- ret = subbuf_actor(read_start, buf, avail, desc, actor);
+ ret = subbuf_actor(read_start, buf, avail, desc);
if (desc->error < 0)
break;
@@ -1174,8 +1171,7 @@ static ssize_t relay_file_read(struct file *filp,
desc.count = count;
desc.arg.buf = buffer;
desc.error = 0;
- return relay_file_read_subbufs(filp, ppos, subbuf_read_actor,
- NULL, &desc);
+ return relay_file_read_subbufs(filp, ppos, subbuf_read_actor, &desc);
}
static void relay_consume_bytes(struct rchan_buf *rbuf, int bytes_consumed)
diff --git a/kernel/resource.c b/kernel/resource.c
index 73f35d4b30b9..d7386986e10e 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -21,6 +21,7 @@
#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/pfn.h>
+#include <linux/mm.h>
#include <asm/io.h>
@@ -50,6 +51,14 @@ struct resource_constraint {
static DEFINE_RWLOCK(resource_lock);
+/*
+ * For memory hotplug, there is no way to free resource entries allocated
+ * by boot mem after the system is up. So for reusing the resource entry
+ * we need to remember the resource.
+ */
+static struct resource *bootmem_resource_free;
+static DEFINE_SPINLOCK(bootmem_resource_lock);
+
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
struct resource *p = v;
@@ -151,6 +160,40 @@ __initcall(ioresources_init);
#endif /* CONFIG_PROC_FS */
+static void free_resource(struct resource *res)
+{
+ if (!res)
+ return;
+
+ if (!PageSlab(virt_to_head_page(res))) {
+ spin_lock(&bootmem_resource_lock);
+ res->sibling = bootmem_resource_free;
+ bootmem_resource_free = res;
+ spin_unlock(&bootmem_resource_lock);
+ } else {
+ kfree(res);
+ }
+}
+
+static struct resource *alloc_resource(gfp_t flags)
+{
+ struct resource *res = NULL;
+
+ spin_lock(&bootmem_resource_lock);
+ if (bootmem_resource_free) {
+ res = bootmem_resource_free;
+ bootmem_resource_free = res->sibling;
+ }
+ spin_unlock(&bootmem_resource_lock);
+
+ if (res)
+ memset(res, 0, sizeof(struct resource));
+ else
+ res = kzalloc(sizeof(struct resource), flags);
+
+ return res;
+}
+
/* Return the conflict entry if you can't request it */
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
@@ -706,24 +749,13 @@ void insert_resource_expand_to_fit(struct resource *root, struct resource *new)
write_unlock(&resource_lock);
}
-/**
- * adjust_resource - modify a resource's start and size
- * @res: resource to modify
- * @start: new start value
- * @size: new size
- *
- * Given an existing resource, change its start and size to match the
- * arguments. Returns 0 on success, -EBUSY if it can't fit.
- * Existing children of the resource are assumed to be immutable.
- */
-int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)
+static int __adjust_resource(struct resource *res, resource_size_t start,
+ resource_size_t size)
{
struct resource *tmp, *parent = res->parent;
resource_size_t end = start + size - 1;
int result = -EBUSY;
- write_lock(&resource_lock);
-
if (!parent)
goto skip;
@@ -751,6 +783,26 @@ skip:
result = 0;
out:
+ return result;
+}
+
+/**
+ * adjust_resource - modify a resource's start and size
+ * @res: resource to modify
+ * @start: new start value
+ * @size: new size
+ *
+ * Given an existing resource, change its start and size to match the
+ * arguments. Returns 0 on success, -EBUSY if it can't fit.
+ * Existing children of the resource are assumed to be immutable.
+ */
+int adjust_resource(struct resource *res, resource_size_t start,
+ resource_size_t size)
+{
+ int result;
+
+ write_lock(&resource_lock);
+ result = __adjust_resource(res, start, size);
write_unlock(&resource_lock);
return result;
}
@@ -762,7 +814,7 @@ static void __init __reserve_region_with_split(struct resource *root,
{
struct resource *parent = root;
struct resource *conflict;
- struct resource *res = kzalloc(sizeof(*res), GFP_ATOMIC);
+ struct resource *res = alloc_resource(GFP_ATOMIC);
struct resource *next_res = NULL;
if (!res)
@@ -787,7 +839,7 @@ static void __init __reserve_region_with_split(struct resource *root,
/* conflict covered whole area */
if (conflict->start <= res->start &&
conflict->end >= res->end) {
- kfree(res);
+ free_resource(res);
WARN_ON(next_res);
break;
}
@@ -797,10 +849,9 @@ static void __init __reserve_region_with_split(struct resource *root,
end = res->end;
res->end = conflict->start - 1;
if (conflict->end < end) {
- next_res = kzalloc(sizeof(*next_res),
- GFP_ATOMIC);
+ next_res = alloc_resource(GFP_ATOMIC);
if (!next_res) {
- kfree(res);
+ free_resource(res);
break;
}
next_res->name = name;
@@ -890,7 +941,7 @@ struct resource * __request_region(struct resource *parent,
const char *name, int flags)
{
DECLARE_WAITQUEUE(wait, current);
- struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
+ struct resource *res = alloc_resource(GFP_KERNEL);
if (!res)
return NULL;
@@ -924,7 +975,7 @@ struct resource * __request_region(struct resource *parent,
continue;
}
/* Uhhuh, that didn't work out.. */
- kfree(res);
+ free_resource(res);
res = NULL;
break;
}
@@ -958,7 +1009,7 @@ int __check_region(struct resource *parent, resource_size_t start,
return -EBUSY;
release_resource(res);
- kfree(res);
+ free_resource(res);
return 0;
}
EXPORT_SYMBOL(__check_region);
@@ -998,7 +1049,7 @@ void __release_region(struct resource *parent, resource_size_t start,
write_unlock(&resource_lock);
if (res->flags & IORESOURCE_MUXED)
wake_up(&muxed_resource_wait);
- kfree(res);
+ free_resource(res);
return;
}
p = &res->sibling;
@@ -1012,6 +1063,109 @@ void __release_region(struct resource *parent, resource_size_t start,
}
EXPORT_SYMBOL(__release_region);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+/**
+ * release_mem_region_adjustable - release a previously reserved memory region
+ * @parent: parent resource descriptor
+ * @start: resource start address
+ * @size: resource region size
+ *
+ * This interface is intended for memory hot-delete. The requested region
+ * is released from a currently busy memory resource. The requested region
+ * must either match exactly or fit into a single busy resource entry. In
+ * the latter case, the remaining resource is adjusted accordingly.
+ * Existing children of the busy memory resource must be immutable in the
+ * request.
+ *
+ * Note:
+ * - Additional release conditions, such as overlapping region, can be
+ * supported after they are confirmed as valid cases.
+ * - When a busy memory resource gets split into two entries, the code
+ * assumes that all children remain in the lower address entry for
+ * simplicity. Enhance this logic when necessary.
+ */
+int release_mem_region_adjustable(struct resource *parent,
+ resource_size_t start, resource_size_t size)
+{
+ struct resource **p;
+ struct resource *res;
+ struct resource *new_res;
+ resource_size_t end;
+ int ret = -EINVAL;
+
+ end = start + size - 1;
+ if ((start < parent->start) || (end > parent->end))
+ return ret;
+
+ /* The alloc_resource() result gets checked later */
+ new_res = alloc_resource(GFP_KERNEL);
+
+ p = &parent->child;
+ write_lock(&resource_lock);
+
+ while ((res = *p)) {
+ if (res->start >= end)
+ break;
+
+ /* look for the next resource if it does not fit into */
+ if (res->start > start || res->end < end) {
+ p = &res->sibling;
+ continue;
+ }
+
+ if (!(res->flags & IORESOURCE_MEM))
+ break;
+
+ if (!(res->flags & IORESOURCE_BUSY)) {
+ p = &res->child;
+ continue;
+ }
+
+ /* found the target resource; let's adjust accordingly */
+ if (res->start == start && res->end == end) {
+ /* free the whole entry */
+ *p = res->sibling;
+ free_resource(res);
+ ret = 0;
+ } else if (res->start == start && res->end != end) {
+ /* adjust the start */
+ ret = __adjust_resource(res, end + 1,
+ res->end - end);
+ } else if (res->start != start && res->end == end) {
+ /* adjust the end */
+ ret = __adjust_resource(res, res->start,
+ start - res->start);
+ } else {
+ /* split into two entries */
+ if (!new_res) {
+ ret = -ENOMEM;
+ break;
+ }
+ new_res->name = res->name;
+ new_res->start = end + 1;
+ new_res->end = res->end;
+ new_res->flags = res->flags;
+ new_res->parent = res->parent;
+ new_res->sibling = res->sibling;
+ new_res->child = NULL;
+
+ ret = __adjust_resource(res, res->start,
+ start - res->start);
+ if (ret)
+ break;
+ res->sibling = new_res;
+ new_res = NULL;
+ }
+
+ break;
+ }
+
+ write_unlock(&resource_lock);
+ free_resource(new_res);
+ return ret;
+}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+
/*
* Managed region resource
*/
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
index 7890b10084a7..1d96dd0d93c1 100644
--- a/kernel/rtmutex-tester.c
+++ b/kernel/rtmutex-tester.c
@@ -14,6 +14,7 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/freezer.h>
+#include <linux/stat.h>
#include "rtmutex.h"
@@ -366,8 +367,8 @@ static ssize_t sysfs_test_status(struct device *dev, struct device_attribute *at
return curr - buf;
}
-static DEVICE_ATTR(status, 0600, sysfs_test_status, NULL);
-static DEVICE_ATTR(command, 0600, NULL, sysfs_test_command);
+static DEVICE_ATTR(status, S_IRUSR, sysfs_test_status, NULL);
+static DEVICE_ATTR(command, S_IWUSR, NULL, sysfs_test_command);
static struct bus_type rttest_subsys = {
.name = "rttest",
diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile
index f06d249e103b..deaf90e4a1de 100644
--- a/kernel/sched/Makefile
+++ b/kernel/sched/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SMP) += cpupri.o
obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS) += stats.o
obj-$(CONFIG_SCHED_DEBUG) += debug.o
+obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c
index c685e31492df..c3ae1446461c 100644
--- a/kernel/sched/clock.c
+++ b/kernel/sched/clock.c
@@ -176,10 +176,36 @@ static u64 sched_clock_remote(struct sched_clock_data *scd)
u64 this_clock, remote_clock;
u64 *ptr, old_val, val;
+#if BITS_PER_LONG != 64
+again:
+ /*
+ * Careful here: The local and the remote clock values need to
+ * be read out atomic as we need to compare the values and
+ * then update either the local or the remote side. So the
+ * cmpxchg64 below only protects one readout.
+ *
+ * We must reread via sched_clock_local() in the retry case on
+ * 32bit as an NMI could use sched_clock_local() via the
+ * tracer and hit between the readout of
+ * the low32bit and the high 32bit portion.
+ */
+ this_clock = sched_clock_local(my_scd);
+ /*
+ * We must enforce atomic readout on 32bit, otherwise the
+ * update on the remote cpu can hit inbetween the readout of
+ * the low32bit and the high 32bit portion.
+ */
+ remote_clock = cmpxchg64(&scd->clock, 0, 0);
+#else
+ /*
+ * On 64bit the read of [my]scd->clock is atomic versus the
+ * update, so we can avoid the above 32bit dance.
+ */
sched_clock_local(my_scd);
again:
this_clock = my_scd->clock;
remote_clock = scd->clock;
+#endif
/*
* Use the opportunity that we have both locks
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7f12624a393c..5662f58f0b69 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -512,11 +512,6 @@ static inline void init_hrtick(void)
* the target CPU.
*/
#ifdef CONFIG_SMP
-
-#ifndef tsk_is_polling
-#define tsk_is_polling(t) 0
-#endif
-
void resched_task(struct task_struct *p)
{
int cpu;
@@ -1288,8 +1283,8 @@ static void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags)
static void
ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
{
- trace_sched_wakeup(p, true);
check_preempt_curr(rq, p, wake_flags);
+ trace_sched_wakeup(p, true);
p->state = TASK_RUNNING;
#ifdef CONFIG_SMP
@@ -1498,8 +1493,10 @@ static void try_to_wake_up_local(struct task_struct *p)
{
struct rq *rq = task_rq(p);
- BUG_ON(rq != this_rq());
- BUG_ON(p == current);
+ if (WARN_ON_ONCE(rq != this_rq()) ||
+ WARN_ON_ONCE(p == current))
+ return;
+
lockdep_assert_held(&rq->lock);
if (!raw_spin_trylock(&p->pi_lock)) {
@@ -2997,51 +2994,6 @@ void __sched schedule_preempt_disabled(void)
preempt_disable();
}
-#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
-
-static inline bool owner_running(struct mutex *lock, struct task_struct *owner)
-{
- if (lock->owner != owner)
- return false;
-
- /*
- * Ensure we emit the owner->on_cpu, dereference _after_ checking
- * lock->owner still matches owner, if that fails, owner might
- * point to free()d memory, if it still matches, the rcu_read_lock()
- * ensures the memory stays valid.
- */
- barrier();
-
- return owner->on_cpu;
-}
-
-/*
- * Look out! "owner" is an entirely speculative pointer
- * access and not reliable.
- */
-int mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
-{
- if (!sched_feat(OWNER_SPIN))
- return 0;
-
- rcu_read_lock();
- while (owner_running(lock, owner)) {
- if (need_resched())
- break;
-
- arch_mutex_cpu_relax();
- }
- rcu_read_unlock();
-
- /*
- * We break out the loop above on need_resched() and when the
- * owner changed, which is a sign for heavy contention. Return
- * success only when lock->owner is NULL.
- */
- return lock->owner == NULL;
-}
-#endif
-
#ifdef CONFIG_PREEMPT
/*
* this is the entry point to schedule() from in-kernel preemption
@@ -3082,11 +3034,13 @@ EXPORT_SYMBOL(preempt_schedule);
asmlinkage void __sched preempt_schedule_irq(void)
{
struct thread_info *ti = current_thread_info();
+ enum ctx_state prev_state;
/* Catch callers which need to be fixed */
BUG_ON(ti->preempt_count || !irqs_disabled());
- user_exit();
+ prev_state = exception_enter();
+
do {
add_preempt_count(PREEMPT_ACTIVE);
local_irq_enable();
@@ -3100,6 +3054,8 @@ asmlinkage void __sched preempt_schedule_irq(void)
*/
barrier();
} while (need_resched());
+
+ exception_exit(prev_state);
}
#endif /* CONFIG_PREEMPT */
@@ -4126,6 +4082,10 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
get_task_struct(p);
rcu_read_unlock();
+ if (p->flags & PF_NO_SETAFFINITY) {
+ retval = -EINVAL;
+ goto out_put_task;
+ }
if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
retval = -ENOMEM;
goto out_put_task;
@@ -4626,6 +4586,7 @@ void sched_show_task(struct task_struct *p)
task_pid_nr(p), ppid,
(unsigned long)task_thread_info(p)->flags);
+ print_worker_info(KERN_INFO, p);
show_stack(p, NULL);
}
@@ -4773,11 +4734,6 @@ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
goto out;
}
- if (unlikely((p->flags & PF_THREAD_BOUND) && p != current)) {
- ret = -EINVAL;
- goto out;
- }
-
do_set_cpus_allowed(p, new_mask);
/* Can the task run on the task's current CPU? If so, we're done */
@@ -4999,7 +4955,7 @@ static void sd_free_ctl_entry(struct ctl_table **tablep)
}
static int min_load_idx = 0;
-static int max_load_idx = CPU_LOAD_IDX_MAX;
+static int max_load_idx = CPU_LOAD_IDX_MAX-1;
static void
set_table_entry(struct ctl_table *entry,
@@ -6248,7 +6204,7 @@ static void sched_init_numa(void)
* 'level' contains the number of unique distances, excluding the
* identity distance node_distance(i,i).
*
- * The sched_domains_nume_distance[] array includes the actual distance
+ * The sched_domains_numa_distance[] array includes the actual distance
* numbers.
*/
@@ -6861,11 +6817,15 @@ int in_sched_functions(unsigned long addr)
}
#ifdef CONFIG_CGROUP_SCHED
+/*
+ * Default task group.
+ * Every task in system belongs to this group at bootup.
+ */
struct task_group root_task_group;
LIST_HEAD(task_groups);
#endif
-DECLARE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
+DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
void __init sched_init(void)
{
@@ -6902,7 +6862,7 @@ void __init sched_init(void)
#endif /* CONFIG_RT_GROUP_SCHED */
#ifdef CONFIG_CPUMASK_OFFSTACK
for_each_possible_cpu(i) {
- per_cpu(load_balance_tmpmask, i) = (void *)ptr;
+ per_cpu(load_balance_mask, i) = (void *)ptr;
ptr += cpumask_size();
}
#endif /* CONFIG_CPUMASK_OFFSTACK */
@@ -6928,12 +6888,6 @@ void __init sched_init(void)
#endif /* CONFIG_CGROUP_SCHED */
-#ifdef CONFIG_CGROUP_CPUACCT
- root_cpuacct.cpustat = &kernel_cpustat;
- root_cpuacct.cpuusage = alloc_percpu(u64);
- /* Too early, not expected to fail */
- BUG_ON(!root_cpuacct.cpuusage);
-#endif
for_each_possible_cpu(i) {
struct rq *rq;
@@ -7455,7 +7409,7 @@ unlock:
return err;
}
-int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us)
+static int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us)
{
u64 rt_runtime, rt_period;
@@ -7467,7 +7421,7 @@ int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us)
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
}
-long sched_group_rt_runtime(struct task_group *tg)
+static long sched_group_rt_runtime(struct task_group *tg)
{
u64 rt_runtime_us;
@@ -7479,7 +7433,7 @@ long sched_group_rt_runtime(struct task_group *tg)
return rt_runtime_us;
}
-int sched_group_set_rt_period(struct task_group *tg, long rt_period_us)
+static int sched_group_set_rt_period(struct task_group *tg, long rt_period_us)
{
u64 rt_runtime, rt_period;
@@ -7492,7 +7446,7 @@ int sched_group_set_rt_period(struct task_group *tg, long rt_period_us)
return tg_set_rt_bandwidth(tg, rt_period, rt_runtime);
}
-long sched_group_rt_period(struct task_group *tg)
+static long sched_group_rt_period(struct task_group *tg)
{
u64 rt_period_us;
@@ -7527,7 +7481,7 @@ static int sched_rt_global_constraints(void)
return ret;
}
-int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
+static int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
{
/* Don't accept realtime tasks when there is no way for them to run */
if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0)
@@ -8035,226 +7989,6 @@ struct cgroup_subsys cpu_cgroup_subsys = {
#endif /* CONFIG_CGROUP_SCHED */
-#ifdef CONFIG_CGROUP_CPUACCT
-
-/*
- * CPU accounting code for task groups.
- *
- * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
- * (balbir@in.ibm.com).
- */
-
-struct cpuacct root_cpuacct;
-
-/* create a new cpu accounting group */
-static struct cgroup_subsys_state *cpuacct_css_alloc(struct cgroup *cgrp)
-{
- struct cpuacct *ca;
-
- if (!cgrp->parent)
- return &root_cpuacct.css;
-
- ca = kzalloc(sizeof(*ca), GFP_KERNEL);
- if (!ca)
- goto out;
-
- ca->cpuusage = alloc_percpu(u64);
- if (!ca->cpuusage)
- goto out_free_ca;
-
- ca->cpustat = alloc_percpu(struct kernel_cpustat);
- if (!ca->cpustat)
- goto out_free_cpuusage;
-
- return &ca->css;
-
-out_free_cpuusage:
- free_percpu(ca->cpuusage);
-out_free_ca:
- kfree(ca);
-out:
- return ERR_PTR(-ENOMEM);
-}
-
-/* destroy an existing cpu accounting group */
-static void cpuacct_css_free(struct cgroup *cgrp)
-{
- struct cpuacct *ca = cgroup_ca(cgrp);
-
- free_percpu(ca->cpustat);
- free_percpu(ca->cpuusage);
- kfree(ca);
-}
-
-static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu)
-{
- u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
- u64 data;
-
-#ifndef CONFIG_64BIT
- /*
- * Take rq->lock to make 64-bit read safe on 32-bit platforms.
- */
- raw_spin_lock_irq(&cpu_rq(cpu)->lock);
- data = *cpuusage;
- raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
-#else
- data = *cpuusage;
-#endif
-
- return data;
-}
-
-static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
-{
- u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
-
-#ifndef CONFIG_64BIT
- /*
- * Take rq->lock to make 64-bit write safe on 32-bit platforms.
- */
- raw_spin_lock_irq(&cpu_rq(cpu)->lock);
- *cpuusage = val;
- raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
-#else
- *cpuusage = val;
-#endif
-}
-
-/* return total cpu usage (in nanoseconds) of a group */
-static u64 cpuusage_read(struct cgroup *cgrp, struct cftype *cft)
-{
- struct cpuacct *ca = cgroup_ca(cgrp);
- u64 totalcpuusage = 0;
- int i;
-
- for_each_present_cpu(i)
- totalcpuusage += cpuacct_cpuusage_read(ca, i);
-
- return totalcpuusage;
-}
-
-static int cpuusage_write(struct cgroup *cgrp, struct cftype *cftype,
- u64 reset)
-{
- struct cpuacct *ca = cgroup_ca(cgrp);
- int err = 0;
- int i;
-
- if (reset) {
- err = -EINVAL;
- goto out;
- }
-
- for_each_present_cpu(i)
- cpuacct_cpuusage_write(ca, i, 0);
-
-out:
- return err;
-}
-
-static int cpuacct_percpu_seq_read(struct cgroup *cgroup, struct cftype *cft,
- struct seq_file *m)
-{
- struct cpuacct *ca = cgroup_ca(cgroup);
- u64 percpu;
- int i;
-
- for_each_present_cpu(i) {
- percpu = cpuacct_cpuusage_read(ca, i);
- seq_printf(m, "%llu ", (unsigned long long) percpu);
- }
- seq_printf(m, "\n");
- return 0;
-}
-
-static const char *cpuacct_stat_desc[] = {
- [CPUACCT_STAT_USER] = "user",
- [CPUACCT_STAT_SYSTEM] = "system",
-};
-
-static int cpuacct_stats_show(struct cgroup *cgrp, struct cftype *cft,
- struct cgroup_map_cb *cb)
-{
- struct cpuacct *ca = cgroup_ca(cgrp);
- int cpu;
- s64 val = 0;
-
- for_each_online_cpu(cpu) {
- struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
- val += kcpustat->cpustat[CPUTIME_USER];
- val += kcpustat->cpustat[CPUTIME_NICE];
- }
- val = cputime64_to_clock_t(val);
- cb->fill(cb, cpuacct_stat_desc[CPUACCT_STAT_USER], val);
-
- val = 0;
- for_each_online_cpu(cpu) {
- struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
- val += kcpustat->cpustat[CPUTIME_SYSTEM];
- val += kcpustat->cpustat[CPUTIME_IRQ];
- val += kcpustat->cpustat[CPUTIME_SOFTIRQ];
- }
-
- val = cputime64_to_clock_t(val);
- cb->fill(cb, cpuacct_stat_desc[CPUACCT_STAT_SYSTEM], val);
-
- return 0;
-}
-
-static struct cftype files[] = {
- {
- .name = "usage",
- .read_u64 = cpuusage_read,
- .write_u64 = cpuusage_write,
- },
- {
- .name = "usage_percpu",
- .read_seq_string = cpuacct_percpu_seq_read,
- },
- {
- .name = "stat",
- .read_map = cpuacct_stats_show,
- },
- { } /* terminate */
-};
-
-/*
- * charge this task's execution time to its accounting group.
- *
- * called with rq->lock held.
- */
-void cpuacct_charge(struct task_struct *tsk, u64 cputime)
-{
- struct cpuacct *ca;
- int cpu;
-
- if (unlikely(!cpuacct_subsys.active))
- return;
-
- cpu = task_cpu(tsk);
-
- rcu_read_lock();
-
- ca = task_ca(tsk);
-
- for (; ca; ca = parent_ca(ca)) {
- u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
- *cpuusage += cputime;
- }
-
- rcu_read_unlock();
-}
-
-struct cgroup_subsys cpuacct_subsys = {
- .name = "cpuacct",
- .css_alloc = cpuacct_css_alloc,
- .css_free = cpuacct_css_free,
- .subsys_id = cpuacct_subsys_id,
- .base_cftypes = files,
-};
-#endif /* CONFIG_CGROUP_CPUACCT */
-
void dump_cpu_task(int cpu)
{
pr_info("Task dump for CPU %d:\n", cpu);
diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c
new file mode 100644
index 000000000000..dbb7e2cd95eb
--- /dev/null
+++ b/kernel/sched/cpuacct.c
@@ -0,0 +1,296 @@
+#include <linux/cgroup.h>
+#include <linux/slab.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
+#include <linux/cpumask.h>
+#include <linux/seq_file.h>
+#include <linux/rcupdate.h>
+#include <linux/kernel_stat.h>
+#include <linux/err.h>
+
+#include "sched.h"
+
+/*
+ * CPU accounting code for task groups.
+ *
+ * Based on the work by Paul Menage (menage@google.com) and Balbir Singh
+ * (balbir@in.ibm.com).
+ */
+
+/* Time spent by the tasks of the cpu accounting group executing in ... */
+enum cpuacct_stat_index {
+ CPUACCT_STAT_USER, /* ... user mode */
+ CPUACCT_STAT_SYSTEM, /* ... kernel mode */
+
+ CPUACCT_STAT_NSTATS,
+};
+
+/* track cpu usage of a group of tasks and its child groups */
+struct cpuacct {
+ struct cgroup_subsys_state css;
+ /* cpuusage holds pointer to a u64-type object on every cpu */
+ u64 __percpu *cpuusage;
+ struct kernel_cpustat __percpu *cpustat;
+};
+
+/* return cpu accounting group corresponding to this container */
+static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
+{
+ return container_of(cgroup_subsys_state(cgrp, cpuacct_subsys_id),
+ struct cpuacct, css);
+}
+
+/* return cpu accounting group to which this task belongs */
+static inline struct cpuacct *task_ca(struct task_struct *tsk)
+{
+ return container_of(task_subsys_state(tsk, cpuacct_subsys_id),
+ struct cpuacct, css);
+}
+
+static inline struct cpuacct *__parent_ca(struct cpuacct *ca)
+{
+ return cgroup_ca(ca->css.cgroup->parent);
+}
+
+static inline struct cpuacct *parent_ca(struct cpuacct *ca)
+{
+ if (!ca->css.cgroup->parent)
+ return NULL;
+ return cgroup_ca(ca->css.cgroup->parent);
+}
+
+static DEFINE_PER_CPU(u64, root_cpuacct_cpuusage);
+static struct cpuacct root_cpuacct = {
+ .cpustat = &kernel_cpustat,
+ .cpuusage = &root_cpuacct_cpuusage,
+};
+
+/* create a new cpu accounting group */
+static struct cgroup_subsys_state *cpuacct_css_alloc(struct cgroup *cgrp)
+{
+ struct cpuacct *ca;
+
+ if (!cgrp->parent)
+ return &root_cpuacct.css;
+
+ ca = kzalloc(sizeof(*ca), GFP_KERNEL);
+ if (!ca)
+ goto out;
+
+ ca->cpuusage = alloc_percpu(u64);
+ if (!ca->cpuusage)
+ goto out_free_ca;
+
+ ca->cpustat = alloc_percpu(struct kernel_cpustat);
+ if (!ca->cpustat)
+ goto out_free_cpuusage;
+
+ return &ca->css;
+
+out_free_cpuusage:
+ free_percpu(ca->cpuusage);
+out_free_ca:
+ kfree(ca);
+out:
+ return ERR_PTR(-ENOMEM);
+}
+
+/* destroy an existing cpu accounting group */
+static void cpuacct_css_free(struct cgroup *cgrp)
+{
+ struct cpuacct *ca = cgroup_ca(cgrp);
+
+ free_percpu(ca->cpustat);
+ free_percpu(ca->cpuusage);
+ kfree(ca);
+}
+
+static u64 cpuacct_cpuusage_read(struct cpuacct *ca, int cpu)
+{
+ u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
+ u64 data;
+
+#ifndef CONFIG_64BIT
+ /*
+ * Take rq->lock to make 64-bit read safe on 32-bit platforms.
+ */
+ raw_spin_lock_irq(&cpu_rq(cpu)->lock);
+ data = *cpuusage;
+ raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
+#else
+ data = *cpuusage;
+#endif
+
+ return data;
+}
+
+static void cpuacct_cpuusage_write(struct cpuacct *ca, int cpu, u64 val)
+{
+ u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
+
+#ifndef CONFIG_64BIT
+ /*
+ * Take rq->lock to make 64-bit write safe on 32-bit platforms.
+ */
+ raw_spin_lock_irq(&cpu_rq(cpu)->lock);
+ *cpuusage = val;
+ raw_spin_unlock_irq(&cpu_rq(cpu)->lock);
+#else
+ *cpuusage = val;
+#endif
+}
+
+/* return total cpu usage (in nanoseconds) of a group */
+static u64 cpuusage_read(struct cgroup *cgrp, struct cftype *cft)
+{
+ struct cpuacct *ca = cgroup_ca(cgrp);
+ u64 totalcpuusage = 0;
+ int i;
+
+ for_each_present_cpu(i)
+ totalcpuusage += cpuacct_cpuusage_read(ca, i);
+
+ return totalcpuusage;
+}
+
+static int cpuusage_write(struct cgroup *cgrp, struct cftype *cftype,
+ u64 reset)
+{
+ struct cpuacct *ca = cgroup_ca(cgrp);
+ int err = 0;
+ int i;
+
+ if (reset) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ for_each_present_cpu(i)
+ cpuacct_cpuusage_write(ca, i, 0);
+
+out:
+ return err;
+}
+
+static int cpuacct_percpu_seq_read(struct cgroup *cgroup, struct cftype *cft,
+ struct seq_file *m)
+{
+ struct cpuacct *ca = cgroup_ca(cgroup);
+ u64 percpu;
+ int i;
+
+ for_each_present_cpu(i) {
+ percpu = cpuacct_cpuusage_read(ca, i);
+ seq_printf(m, "%llu ", (unsigned long long) percpu);
+ }
+ seq_printf(m, "\n");
+ return 0;
+}
+
+static const char * const cpuacct_stat_desc[] = {
+ [CPUACCT_STAT_USER] = "user",
+ [CPUACCT_STAT_SYSTEM] = "system",
+};
+
+static int cpuacct_stats_show(struct cgroup *cgrp, struct cftype *cft,
+ struct cgroup_map_cb *cb)
+{
+ struct cpuacct *ca = cgroup_ca(cgrp);
+ int cpu;
+ s64 val = 0;
+
+ for_each_online_cpu(cpu) {
+ struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
+ val += kcpustat->cpustat[CPUTIME_USER];
+ val += kcpustat->cpustat[CPUTIME_NICE];
+ }
+ val = cputime64_to_clock_t(val);
+ cb->fill(cb, cpuacct_stat_desc[CPUACCT_STAT_USER], val);
+
+ val = 0;
+ for_each_online_cpu(cpu) {
+ struct kernel_cpustat *kcpustat = per_cpu_ptr(ca->cpustat, cpu);
+ val += kcpustat->cpustat[CPUTIME_SYSTEM];
+ val += kcpustat->cpustat[CPUTIME_IRQ];
+ val += kcpustat->cpustat[CPUTIME_SOFTIRQ];
+ }
+
+ val = cputime64_to_clock_t(val);
+ cb->fill(cb, cpuacct_stat_desc[CPUACCT_STAT_SYSTEM], val);
+
+ return 0;
+}
+
+static struct cftype files[] = {
+ {
+ .name = "usage",
+ .read_u64 = cpuusage_read,
+ .write_u64 = cpuusage_write,
+ },
+ {
+ .name = "usage_percpu",
+ .read_seq_string = cpuacct_percpu_seq_read,
+ },
+ {
+ .name = "stat",
+ .read_map = cpuacct_stats_show,
+ },
+ { } /* terminate */
+};
+
+/*
+ * charge this task's execution time to its accounting group.
+ *
+ * called with rq->lock held.
+ */
+void cpuacct_charge(struct task_struct *tsk, u64 cputime)
+{
+ struct cpuacct *ca;
+ int cpu;
+
+ cpu = task_cpu(tsk);
+
+ rcu_read_lock();
+
+ ca = task_ca(tsk);
+
+ while (true) {
+ u64 *cpuusage = per_cpu_ptr(ca->cpuusage, cpu);
+ *cpuusage += cputime;
+
+ ca = parent_ca(ca);
+ if (!ca)
+ break;
+ }
+
+ rcu_read_unlock();
+}
+
+/*
+ * Add user/system time to cpuacct.
+ *
+ * Note: it's the caller that updates the account of the root cgroup.
+ */
+void cpuacct_account_field(struct task_struct *p, int index, u64 val)
+{
+ struct kernel_cpustat *kcpustat;
+ struct cpuacct *ca;
+
+ rcu_read_lock();
+ ca = task_ca(p);
+ while (ca != &root_cpuacct) {
+ kcpustat = this_cpu_ptr(ca->cpustat);
+ kcpustat->cpustat[index] += val;
+ ca = __parent_ca(ca);
+ }
+ rcu_read_unlock();
+}
+
+struct cgroup_subsys cpuacct_subsys = {
+ .name = "cpuacct",
+ .css_alloc = cpuacct_css_alloc,
+ .css_free = cpuacct_css_free,
+ .subsys_id = cpuacct_subsys_id,
+ .base_cftypes = files,
+ .early_init = 1,
+};
diff --git a/kernel/sched/cpuacct.h b/kernel/sched/cpuacct.h
new file mode 100644
index 000000000000..ed605624a5e7
--- /dev/null
+++ b/kernel/sched/cpuacct.h
@@ -0,0 +1,17 @@
+#ifdef CONFIG_CGROUP_CPUACCT
+
+extern void cpuacct_charge(struct task_struct *tsk, u64 cputime);
+extern void cpuacct_account_field(struct task_struct *p, int index, u64 val);
+
+#else
+
+static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime)
+{
+}
+
+static inline void
+cpuacct_account_field(struct task_struct *p, int index, u64 val)
+{
+}
+
+#endif
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index ed12cbb135f4..ea32f02bf2c3 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -115,10 +115,6 @@ static int irqtime_account_si_update(void)
static inline void task_group_account_field(struct task_struct *p, int index,
u64 tmp)
{
-#ifdef CONFIG_CGROUP_CPUACCT
- struct kernel_cpustat *kcpustat;
- struct cpuacct *ca;
-#endif
/*
* Since all updates are sure to touch the root cgroup, we
* get ourselves ahead and touch it first. If the root cgroup
@@ -127,19 +123,7 @@ static inline void task_group_account_field(struct task_struct *p, int index,
*/
__get_cpu_var(kernel_cpustat).cpustat[index] += tmp;
-#ifdef CONFIG_CGROUP_CPUACCT
- if (unlikely(!cpuacct_subsys.active))
- return;
-
- rcu_read_lock();
- ca = task_ca(p);
- while (ca && (ca != &root_cpuacct)) {
- kcpustat = this_cpu_ptr(ca->cpustat);
- kcpustat->cpustat[index] += tmp;
- ca = parent_ca(ca);
- }
- rcu_read_unlock();
-#endif
+ cpuacct_account_field(p, index, tmp);
}
/*
@@ -310,7 +294,7 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
t = tsk;
do {
- task_cputime(tsk, &utime, &stime);
+ task_cputime(t, &utime, &stime);
times->utime += utime;
times->stime += stime;
times->sum_exec_runtime += task_sched_runtime(t);
@@ -388,82 +372,10 @@ static inline void irqtime_account_process_tick(struct task_struct *p, int user_
struct rq *rq) {}
#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-/*
- * Account a single tick of cpu time.
- * @p: the process that the cpu time gets accounted to
- * @user_tick: indicates if the tick is a user or a system tick
- */
-void account_process_tick(struct task_struct *p, int user_tick)
-{
- cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
- struct rq *rq = this_rq();
-
- if (vtime_accounting_enabled())
- return;
-
- if (sched_clock_irqtime) {
- irqtime_account_process_tick(p, user_tick, rq);
- return;
- }
-
- if (steal_account_process_tick())
- return;
-
- if (user_tick)
- account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
- else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
- account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
- one_jiffy_scaled);
- else
- account_idle_time(cputime_one_jiffy);
-}
-
-/*
- * Account multiple ticks of steal time.
- * @p: the process from which the cpu time has been stolen
- * @ticks: number of stolen ticks
- */
-void account_steal_ticks(unsigned long ticks)
-{
- account_steal_time(jiffies_to_cputime(ticks));
-}
-
-/*
- * Account multiple ticks of idle time.
- * @ticks: number of stolen ticks
- */
-void account_idle_ticks(unsigned long ticks)
-{
-
- if (sched_clock_irqtime) {
- irqtime_account_idle_ticks(ticks);
- return;
- }
-
- account_idle_time(jiffies_to_cputime(ticks));
-}
-#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
-
/*
* Use precise platform statistics if available:
*/
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
- *ut = p->utime;
- *st = p->stime;
-}
-
-void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
-{
- struct task_cputime cputime;
-
- thread_group_cputime(p, &cputime);
-
- *ut = cputime.utime;
- *st = cputime.stime;
-}
#ifndef __ARCH_HAS_VTIME_TASK_SWITCH
void vtime_task_switch(struct task_struct *prev)
@@ -518,21 +430,111 @@ void vtime_account_irq_enter(struct task_struct *tsk)
}
EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
#endif /* __ARCH_HAS_VTIME_ACCOUNT */
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+ *ut = p->utime;
+ *st = p->stime;
+}
-#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st)
+{
+ struct task_cputime cputime;
-static cputime_t scale_stime(cputime_t stime, cputime_t rtime, cputime_t total)
+ thread_group_cputime(p, &cputime);
+
+ *ut = cputime.utime;
+ *st = cputime.stime;
+}
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
+/*
+ * Account a single tick of cpu time.
+ * @p: the process that the cpu time gets accounted to
+ * @user_tick: indicates if the tick is a user or a system tick
+ */
+void account_process_tick(struct task_struct *p, int user_tick)
{
- u64 temp = (__force u64) rtime;
+ cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
+ struct rq *rq = this_rq();
- temp *= (__force u64) stime;
+ if (vtime_accounting_enabled())
+ return;
+
+ if (sched_clock_irqtime) {
+ irqtime_account_process_tick(p, user_tick, rq);
+ return;
+ }
+
+ if (steal_account_process_tick())
+ return;
- if (sizeof(cputime_t) == 4)
- temp = div_u64(temp, (__force u32) total);
+ if (user_tick)
+ account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
+ else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
+ account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
+ one_jiffy_scaled);
else
- temp = div64_u64(temp, (__force u64) total);
+ account_idle_time(cputime_one_jiffy);
+}
- return (__force cputime_t) temp;
+/*
+ * Account multiple ticks of steal time.
+ * @p: the process from which the cpu time has been stolen
+ * @ticks: number of stolen ticks
+ */
+void account_steal_ticks(unsigned long ticks)
+{
+ account_steal_time(jiffies_to_cputime(ticks));
+}
+
+/*
+ * Account multiple ticks of idle time.
+ * @ticks: number of stolen ticks
+ */
+void account_idle_ticks(unsigned long ticks)
+{
+
+ if (sched_clock_irqtime) {
+ irqtime_account_idle_ticks(ticks);
+ return;
+ }
+
+ account_idle_time(jiffies_to_cputime(ticks));
+}
+
+/*
+ * Perform (stime * rtime) / total with reduced chances
+ * of multiplication overflows by using smaller factors
+ * like quotient and remainders of divisions between
+ * rtime and total.
+ */
+static cputime_t scale_stime(u64 stime, u64 rtime, u64 total)
+{
+ u64 rem, res, scaled;
+
+ if (rtime >= total) {
+ /*
+ * Scale up to rtime / total then add
+ * the remainder scaled to stime / total.
+ */
+ res = div64_u64_rem(rtime, total, &rem);
+ scaled = stime * res;
+ scaled += div64_u64(stime * rem, total);
+ } else {
+ /*
+ * Same in reverse: scale down to total / rtime
+ * then substract that result scaled to
+ * to the remaining part.
+ */
+ res = div64_u64_rem(total, rtime, &rem);
+ scaled = div64_u64(stime, res);
+ scaled -= div64_u64(scaled * rem, total);
+ }
+
+ return (__force cputime_t) scaled;
}
/*
@@ -545,6 +547,12 @@ static void cputime_adjust(struct task_cputime *curr,
{
cputime_t rtime, stime, total;
+ if (vtime_accounting_enabled()) {
+ *ut = curr->utime;
+ *st = curr->stime;
+ return;
+ }
+
stime = curr->stime;
total = stime + curr->utime;
@@ -560,10 +568,14 @@ static void cputime_adjust(struct task_cputime *curr,
*/
rtime = nsecs_to_cputime(curr->sum_exec_runtime);
- if (total)
- stime = scale_stime(stime, rtime, total);
- else
+ if (!rtime) {
+ stime = 0;
+ } else if (!total) {
stime = rtime;
+ } else {
+ stime = scale_stime((__force u64)stime,
+ (__force u64)rtime, (__force u64)total);
+ }
/*
* If the tick based count grows faster than the scheduler one,
@@ -597,7 +609,7 @@ void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime
thread_group_cputime(p, &cputime);
cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st);
}
-#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
+#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
static unsigned long long vtime_delta(struct task_struct *tsk)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 7a33e5986fc5..8bf7081b1ec5 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -431,13 +431,13 @@ void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, unsigned long delta_exec);
* Scheduling class tree data structure manipulation methods:
*/
-static inline u64 max_vruntime(u64 min_vruntime, u64 vruntime)
+static inline u64 max_vruntime(u64 max_vruntime, u64 vruntime)
{
- s64 delta = (s64)(vruntime - min_vruntime);
+ s64 delta = (s64)(vruntime - max_vruntime);
if (delta > 0)
- min_vruntime = vruntime;
+ max_vruntime = vruntime;
- return min_vruntime;
+ return max_vruntime;
}
static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
@@ -473,6 +473,7 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq)
vruntime = min_vruntime(vruntime, se->vruntime);
}
+ /* ensure we never gain time by being placed backwards. */
cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime);
#ifndef CONFIG_64BIT
smp_wmb();
@@ -652,7 +653,7 @@ static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
/*
- * We calculate the vruntime slice of a to be inserted task
+ * We calculate the vruntime slice of a to-be-inserted task.
*
* vs = s/w
*/
@@ -1562,6 +1563,27 @@ static inline void dequeue_entity_load_avg(struct cfs_rq *cfs_rq,
se->avg.decay_count = atomic64_read(&cfs_rq->decay_counter);
} /* migrations, e.g. sleep=0 leave decay_count == 0 */
}
+
+/*
+ * Update the rq's load with the elapsed running time before entering
+ * idle. if the last scheduled task is not a CFS task, idle_enter will
+ * be the only way to update the runnable statistic.
+ */
+void idle_enter_fair(struct rq *this_rq)
+{
+ update_rq_runnable_avg(this_rq, 1);
+}
+
+/*
+ * Update the rq's load with the elapsed idle time before a task is
+ * scheduled. if the newly scheduled task is not a CFS task, idle_exit will
+ * be the only way to update the runnable statistic.
+ */
+void idle_exit_fair(struct rq *this_rq)
+{
+ update_rq_runnable_avg(this_rq, 0);
+}
+
#else
static inline void update_entity_load_avg(struct sched_entity *se,
int update_cfs_rq) {}
@@ -3874,12 +3896,16 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
int tsk_cache_hot = 0;
/*
* We do not migrate tasks that are:
- * 1) running (obviously), or
+ * 1) throttled_lb_pair, or
* 2) cannot be migrated to this CPU due to cpus_allowed, or
- * 3) are cache-hot on their current CPU.
+ * 3) running (obviously), or
+ * 4) are cache-hot on their current CPU.
*/
+ if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
+ return 0;
+
if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) {
- int new_dst_cpu;
+ int cpu;
schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
@@ -3894,12 +3920,15 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
if (!env->dst_grpmask || (env->flags & LBF_SOME_PINNED))
return 0;
- new_dst_cpu = cpumask_first_and(env->dst_grpmask,
- tsk_cpus_allowed(p));
- if (new_dst_cpu < nr_cpu_ids) {
- env->flags |= LBF_SOME_PINNED;
- env->new_dst_cpu = new_dst_cpu;
+ /* Prevent to re-select dst_cpu via env's cpus */
+ for_each_cpu_and(cpu, env->dst_grpmask, env->cpus) {
+ if (cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) {
+ env->flags |= LBF_SOME_PINNED;
+ env->new_dst_cpu = cpu;
+ break;
+ }
}
+
return 0;
}
@@ -3920,20 +3949,17 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env)
tsk_cache_hot = task_hot(p, env->src_rq->clock_task, env->sd);
if (!tsk_cache_hot ||
env->sd->nr_balance_failed > env->sd->cache_nice_tries) {
-#ifdef CONFIG_SCHEDSTATS
+
if (tsk_cache_hot) {
schedstat_inc(env->sd, lb_hot_gained[env->idle]);
schedstat_inc(p, se.statistics.nr_forced_migrations);
}
-#endif
+
return 1;
}
- if (tsk_cache_hot) {
- schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
- return 0;
- }
- return 1;
+ schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
+ return 0;
}
/*
@@ -3948,9 +3974,6 @@ static int move_one_task(struct lb_env *env)
struct task_struct *p, *n;
list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) {
- if (throttled_lb_pair(task_group(p), env->src_rq->cpu, env->dst_cpu))
- continue;
-
if (!can_migrate_task(p, env))
continue;
@@ -4002,7 +4025,7 @@ static int move_tasks(struct lb_env *env)
break;
}
- if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu))
+ if (!can_migrate_task(p, env))
goto next;
load = task_h_load(p);
@@ -4013,9 +4036,6 @@ static int move_tasks(struct lb_env *env)
if ((load / 2) > env->imbalance)
goto next;
- if (!can_migrate_task(p, env))
- goto next;
-
move_task(p, env);
pulled++;
env->imbalance -= load;
@@ -4245,7 +4265,7 @@ static inline int get_sd_load_idx(struct sched_domain *sd,
return load_idx;
}
-unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu)
+static unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu)
{
return SCHED_POWER_SCALE;
}
@@ -4255,7 +4275,7 @@ unsigned long __weak arch_scale_freq_power(struct sched_domain *sd, int cpu)
return default_scale_freq_power(sd, cpu);
}
-unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu)
+static unsigned long default_scale_smt_power(struct sched_domain *sd, int cpu)
{
unsigned long weight = sd->span_weight;
unsigned long smt_gain = sd->smt_gain;
@@ -4270,7 +4290,7 @@ unsigned long __weak arch_scale_smt_power(struct sched_domain *sd, int cpu)
return default_scale_smt_power(sd, cpu);
}
-unsigned long scale_rt_power(int cpu)
+static unsigned long scale_rt_power(int cpu)
{
struct rq *rq = cpu_rq(cpu);
u64 total, available, age_stamp, avg;
@@ -4960,7 +4980,7 @@ static struct rq *find_busiest_queue(struct lb_env *env,
#define MAX_PINNED_INTERVAL 512
/* Working cpumask for load_balance and load_balance_newidle. */
-DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
+DEFINE_PER_CPU(cpumask_var_t, load_balance_mask);
static int need_active_balance(struct lb_env *env)
{
@@ -4991,11 +5011,10 @@ static int load_balance(int this_cpu, struct rq *this_rq,
int *balance)
{
int ld_moved, cur_ld_moved, active_balance = 0;
- int lb_iterations, max_lb_iterations;
struct sched_group *group;
struct rq *busiest;
unsigned long flags;
- struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
+ struct cpumask *cpus = __get_cpu_var(load_balance_mask);
struct lb_env env = {
.sd = sd,
@@ -5007,8 +5026,14 @@ static int load_balance(int this_cpu, struct rq *this_rq,
.cpus = cpus,
};
+ /*
+ * For NEWLY_IDLE load_balancing, we don't need to consider
+ * other cpus in our group
+ */
+ if (idle == CPU_NEWLY_IDLE)
+ env.dst_grpmask = NULL;
+
cpumask_copy(cpus, cpu_active_mask);
- max_lb_iterations = cpumask_weight(env.dst_grpmask);
schedstat_inc(sd, lb_count[idle]);
@@ -5034,7 +5059,6 @@ redo:
schedstat_add(sd, lb_imbalance[idle], env.imbalance);
ld_moved = 0;
- lb_iterations = 1;
if (busiest->nr_running > 1) {
/*
* Attempt to move tasks. If find_busiest_group has found
@@ -5061,17 +5085,17 @@ more_balance:
double_rq_unlock(env.dst_rq, busiest);
local_irq_restore(flags);
- if (env.flags & LBF_NEED_BREAK) {
- env.flags &= ~LBF_NEED_BREAK;
- goto more_balance;
- }
-
/*
* some other cpu did the load balance for us.
*/
if (cur_ld_moved && env.dst_cpu != smp_processor_id())
resched_cpu(env.dst_cpu);
+ if (env.flags & LBF_NEED_BREAK) {
+ env.flags &= ~LBF_NEED_BREAK;
+ goto more_balance;
+ }
+
/*
* Revisit (affine) tasks on src_cpu that couldn't be moved to
* us and move them to an alternate dst_cpu in our sched_group
@@ -5091,14 +5115,17 @@ more_balance:
* moreover subsequent load balance cycles should correct the
* excess load moved.
*/
- if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0 &&
- lb_iterations++ < max_lb_iterations) {
+ if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0) {
env.dst_rq = cpu_rq(env.new_dst_cpu);
env.dst_cpu = env.new_dst_cpu;
env.flags &= ~LBF_SOME_PINNED;
env.loop = 0;
env.loop_break = sched_nr_migrate_break;
+
+ /* Prevent to re-select dst_cpu via env's cpus */
+ cpumask_clear_cpu(env.dst_cpu, env.cpus);
+
/*
* Go back to "more_balance" rather than "redo" since we
* need to continue with same src_cpu.
@@ -5219,8 +5246,6 @@ void idle_balance(int this_cpu, struct rq *this_rq)
if (this_rq->avg_idle < sysctl_sched_migration_cost)
return;
- update_rq_runnable_avg(this_rq, 1);
-
/*
* Drop the rq->lock, but keep IRQ/preempt disabled.
*/
@@ -5395,13 +5420,16 @@ static inline void set_cpu_sd_state_busy(void)
struct sched_domain *sd;
int cpu = smp_processor_id();
- if (!test_bit(NOHZ_IDLE, nohz_flags(cpu)))
- return;
- clear_bit(NOHZ_IDLE, nohz_flags(cpu));
-
rcu_read_lock();
- for_each_domain(cpu, sd)
+ sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd);
+
+ if (!sd || !sd->nohz_idle)
+ goto unlock;
+ sd->nohz_idle = 0;
+
+ for (; sd; sd = sd->parent)
atomic_inc(&sd->groups->sgp->nr_busy_cpus);
+unlock:
rcu_read_unlock();
}
@@ -5410,13 +5438,16 @@ void set_cpu_sd_state_idle(void)
struct sched_domain *sd;
int cpu = smp_processor_id();
- if (test_bit(NOHZ_IDLE, nohz_flags(cpu)))
- return;
- set_bit(NOHZ_IDLE, nohz_flags(cpu));
-
rcu_read_lock();
- for_each_domain(cpu, sd)
+ sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd);
+
+ if (!sd || sd->nohz_idle)
+ goto unlock;
+ sd->nohz_idle = 1;
+
+ for (; sd; sd = sd->parent)
atomic_dec(&sd->groups->sgp->nr_busy_cpus);
+unlock:
rcu_read_unlock();
}
@@ -5468,7 +5499,7 @@ void update_max_interval(void)
* It checks each scheduling domain to see if it is due to be balanced,
* and initiates a balancing operation if so.
*
- * Balancing parameters are set up in arch_init_sched_domains.
+ * Balancing parameters are set up in init_sched_domains.
*/
static void rebalance_domains(int cpu, enum cpu_idle_type idle)
{
@@ -5506,10 +5537,11 @@ static void rebalance_domains(int cpu, enum cpu_idle_type idle)
if (time_after_eq(jiffies, sd->last_balance + interval)) {
if (load_balance(cpu, rq, sd, idle, &balance)) {
/*
- * We've pulled tasks over so either we're no
- * longer idle.
+ * The LBF_SOME_PINNED logic could have changed
+ * env->dst_cpu, so we can't know our idle
+ * state even if we migrated tasks. Update it.
*/
- idle = CPU_NOT_IDLE;
+ idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE;
}
sd->last_balance = jiffies;
}
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index 1ad1d2b5395f..99399f8e4799 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -46,13 +46,6 @@ SCHED_FEAT(DOUBLE_TICK, false)
SCHED_FEAT(LB_BIAS, true)
/*
- * Spin-wait on mutex acquisition when the mutex owner is running on
- * another cpu -- assumes that when the owner is running, it will soon
- * release the lock. Decreases scheduling overhead.
- */
-SCHED_FEAT(OWNER_SPIN, true)
-
-/*
* Decrement CPU power based on time not spent running tasks
*/
SCHED_FEAT(NONTASK_POWER, true)
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index b6baf370cae9..b8ce77328341 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -13,6 +13,16 @@ select_task_rq_idle(struct task_struct *p, int sd_flag, int flags)
{
return task_cpu(p); /* IDLE tasks as never migrated */
}
+
+static void pre_schedule_idle(struct rq *rq, struct task_struct *prev)
+{
+ idle_exit_fair(rq);
+}
+
+static void post_schedule_idle(struct rq *rq)
+{
+ idle_enter_fair(rq);
+}
#endif /* CONFIG_SMP */
/*
* Idle tasks are unconditionally rescheduled:
@@ -25,6 +35,10 @@ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int fl
static struct task_struct *pick_next_task_idle(struct rq *rq)
{
schedstat_inc(rq, sched_goidle);
+#ifdef CONFIG_SMP
+ /* Trigger the post schedule to do an idle_enter for CFS */
+ rq->post_schedule = 1;
+#endif
return rq->idle;
}
@@ -86,6 +100,8 @@ const struct sched_class idle_sched_class = {
#ifdef CONFIG_SMP
.select_task_rq = select_task_rq_idle,
+ .pre_schedule = pre_schedule_idle,
+ .post_schedule = post_schedule_idle,
#endif
.set_curr_task = set_curr_task_idle,
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index cc03cfdf469f..4c225c4c7111 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -7,6 +7,7 @@
#include <linux/stop_machine.h>
#include "cpupri.h"
+#include "cpuacct.h"
extern __read_mostly int scheduler_running;
@@ -33,6 +34,31 @@ extern __read_mostly int scheduler_running;
*/
#define NS_TO_JIFFIES(TIME) ((unsigned long)(TIME) / (NSEC_PER_SEC / HZ))
+/*
+ * Increase resolution of nice-level calculations for 64-bit architectures.
+ * The extra resolution improves shares distribution and load balancing of
+ * low-weight task groups (eg. nice +19 on an autogroup), deeper taskgroup
+ * hierarchies, especially on larger systems. This is not a user-visible change
+ * and does not change the user-interface for setting shares/weights.
+ *
+ * We increase resolution only if we have enough bits to allow this increased
+ * resolution (i.e. BITS_PER_LONG > 32). The costs for increasing resolution
+ * when BITS_PER_LONG <= 32 are pretty high and the returns do not justify the
+ * increased costs.
+ */
+#if 0 /* BITS_PER_LONG > 32 -- currently broken: it increases power usage under light load */
+# define SCHED_LOAD_RESOLUTION 10
+# define scale_load(w) ((w) << SCHED_LOAD_RESOLUTION)
+# define scale_load_down(w) ((w) >> SCHED_LOAD_RESOLUTION)
+#else
+# define SCHED_LOAD_RESOLUTION 0
+# define scale_load(w) (w)
+# define scale_load_down(w) (w)
+#endif
+
+#define SCHED_LOAD_SHIFT (10 + SCHED_LOAD_RESOLUTION)
+#define SCHED_LOAD_SCALE (1L << SCHED_LOAD_SHIFT)
+
#define NICE_0_LOAD SCHED_LOAD_SCALE
#define NICE_0_SHIFT SCHED_LOAD_SHIFT
@@ -154,11 +180,6 @@ struct task_group {
#define MAX_SHARES (1UL << 18)
#endif
-/* Default task group.
- * Every task in system belong to this group at bootup.
- */
-extern struct task_group root_task_group;
-
typedef int (*tg_visitor)(struct task_group *, void *);
extern int walk_tg_tree_from(struct task_group *from,
@@ -196,6 +217,18 @@ extern void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,
struct sched_rt_entity *rt_se, int cpu,
struct sched_rt_entity *parent);
+extern struct task_group *sched_create_group(struct task_group *parent);
+extern void sched_online_group(struct task_group *tg,
+ struct task_group *parent);
+extern void sched_destroy_group(struct task_group *tg);
+extern void sched_offline_group(struct task_group *tg);
+
+extern void sched_move_task(struct task_struct *tsk);
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
+#endif
+
#else /* CONFIG_CGROUP_SCHED */
struct cfs_bandwidth { };
@@ -547,6 +580,62 @@ static inline struct sched_domain *highest_flag_domain(int cpu, int flag)
DECLARE_PER_CPU(struct sched_domain *, sd_llc);
DECLARE_PER_CPU(int, sd_llc_id);
+struct sched_group_power {
+ atomic_t ref;
+ /*
+ * CPU power of this group, SCHED_LOAD_SCALE being max power for a
+ * single CPU.
+ */
+ unsigned int power, power_orig;
+ unsigned long next_update;
+ /*
+ * Number of busy cpus in this group.
+ */
+ atomic_t nr_busy_cpus;
+
+ unsigned long cpumask[0]; /* iteration mask */
+};
+
+struct sched_group {
+ struct sched_group *next; /* Must be a circular list */
+ atomic_t ref;
+
+ unsigned int group_weight;
+ struct sched_group_power *sgp;
+
+ /*
+ * The CPUs this group covers.
+ *
+ * NOTE: this field is variable length. (Allocated dynamically
+ * by attaching extra space to the end of the structure,
+ * depending on how many CPUs the kernel has booted up with)
+ */
+ unsigned long cpumask[0];
+};
+
+static inline struct cpumask *sched_group_cpus(struct sched_group *sg)
+{
+ return to_cpumask(sg->cpumask);
+}
+
+/*
+ * cpumask masking which cpus in the group are allowed to iterate up the domain
+ * tree.
+ */
+static inline struct cpumask *sched_group_mask(struct sched_group *sg)
+{
+ return to_cpumask(sg->sgp->cpumask);
+}
+
+/**
+ * group_first_cpu - Returns the first cpu in the cpumask of a sched_group.
+ * @group: The group whose first cpu is to be returned.
+ */
+static inline unsigned int group_first_cpu(struct sched_group *group)
+{
+ return cpumask_first(sched_group_cpus(group));
+}
+
extern int group_balance_cpu(struct sched_group *sg);
#endif /* CONFIG_SMP */
@@ -784,6 +873,12 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
}
#endif /* __ARCH_WANT_UNLOCKED_CTXSW */
+/*
+ * wake flags
+ */
+#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */
+#define WF_FORK 0x02 /* child wakeup after fork */
+#define WF_MIGRATED 0x4 /* internal use, task got migrated */
static inline void update_load_add(struct load_weight *lw, unsigned long inc)
{
@@ -856,14 +951,61 @@ static const u32 prio_to_wmult[40] = {
/* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
};
-/* Time spent by the tasks of the cpu accounting group executing in ... */
-enum cpuacct_stat_index {
- CPUACCT_STAT_USER, /* ... user mode */
- CPUACCT_STAT_SYSTEM, /* ... kernel mode */
+#define ENQUEUE_WAKEUP 1
+#define ENQUEUE_HEAD 2
+#ifdef CONFIG_SMP
+#define ENQUEUE_WAKING 4 /* sched_class::task_waking was called */
+#else
+#define ENQUEUE_WAKING 0
+#endif
- CPUACCT_STAT_NSTATS,
-};
+#define DEQUEUE_SLEEP 1
+
+struct sched_class {
+ const struct sched_class *next;
+
+ void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
+ void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
+ void (*yield_task) (struct rq *rq);
+ bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);
+
+ void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);
+
+ struct task_struct * (*pick_next_task) (struct rq *rq);
+ void (*put_prev_task) (struct rq *rq, struct task_struct *p);
+
+#ifdef CONFIG_SMP
+ int (*select_task_rq)(struct task_struct *p, int sd_flag, int flags);
+ void (*migrate_task_rq)(struct task_struct *p, int next_cpu);
+
+ void (*pre_schedule) (struct rq *this_rq, struct task_struct *task);
+ void (*post_schedule) (struct rq *this_rq);
+ void (*task_waking) (struct task_struct *task);
+ void (*task_woken) (struct rq *this_rq, struct task_struct *task);
+
+ void (*set_cpus_allowed)(struct task_struct *p,
+ const struct cpumask *newmask);
+ void (*rq_online)(struct rq *rq);
+ void (*rq_offline)(struct rq *rq);
+#endif
+
+ void (*set_curr_task) (struct rq *rq);
+ void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
+ void (*task_fork) (struct task_struct *p);
+
+ void (*switched_from) (struct rq *this_rq, struct task_struct *task);
+ void (*switched_to) (struct rq *this_rq, struct task_struct *task);
+ void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
+ int oldprio);
+
+ unsigned int (*get_rr_interval) (struct rq *rq,
+ struct task_struct *task);
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+ void (*task_move_group) (struct task_struct *p, int on_rq);
+#endif
+};
#define sched_class_highest (&stop_sched_class)
#define for_each_class(class) \
@@ -877,9 +1019,23 @@ extern const struct sched_class idle_sched_class;
#ifdef CONFIG_SMP
+extern void update_group_power(struct sched_domain *sd, int cpu);
+
extern void trigger_load_balance(struct rq *rq, int cpu);
extern void idle_balance(int this_cpu, struct rq *this_rq);
+/*
+ * Only depends on SMP, FAIR_GROUP_SCHED may be removed when runnable_avg
+ * becomes useful in lb
+ */
+#if defined(CONFIG_FAIR_GROUP_SCHED)
+extern void idle_enter_fair(struct rq *this_rq);
+extern void idle_exit_fair(struct rq *this_rq);
+#else
+static inline void idle_enter_fair(struct rq *this_rq) {}
+static inline void idle_exit_fair(struct rq *this_rq) {}
+#endif
+
#else /* CONFIG_SMP */
static inline void idle_balance(int cpu, struct rq *rq)
@@ -891,7 +1047,6 @@ static inline void idle_balance(int cpu, struct rq *rq)
extern void sysrq_sched_debug_show(void);
extern void sched_init_granularity(void);
extern void update_max_interval(void);
-extern void update_group_power(struct sched_domain *sd, int cpu);
extern int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu);
extern void init_sched_rt_class(void);
extern void init_sched_fair_class(void);
@@ -904,45 +1059,6 @@ extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime
extern void update_idle_cpu_load(struct rq *this_rq);
-#ifdef CONFIG_CGROUP_CPUACCT
-#include <linux/cgroup.h>
-/* track cpu usage of a group of tasks and its child groups */
-struct cpuacct {
- struct cgroup_subsys_state css;
- /* cpuusage holds pointer to a u64-type object on every cpu */
- u64 __percpu *cpuusage;
- struct kernel_cpustat __percpu *cpustat;
-};
-
-extern struct cgroup_subsys cpuacct_subsys;
-extern struct cpuacct root_cpuacct;
-
-/* return cpu accounting group corresponding to this container */
-static inline struct cpuacct *cgroup_ca(struct cgroup *cgrp)
-{
- return container_of(cgroup_subsys_state(cgrp, cpuacct_subsys_id),
- struct cpuacct, css);
-}
-
-/* return cpu accounting group to which this task belongs */
-static inline struct cpuacct *task_ca(struct task_struct *tsk)
-{
- return container_of(task_subsys_state(tsk, cpuacct_subsys_id),
- struct cpuacct, css);
-}
-
-static inline struct cpuacct *parent_ca(struct cpuacct *ca)
-{
- if (!ca || !ca->css.cgroup->parent)
- return NULL;
- return cgroup_ca(ca->css.cgroup->parent);
-}
-
-extern void cpuacct_charge(struct task_struct *tsk, u64 cputime);
-#else
-static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {}
-#endif
-
#ifdef CONFIG_PARAVIRT
static inline u64 steal_ticks(u64 steal)
{
@@ -1187,7 +1303,6 @@ extern void account_cfs_bandwidth_used(int enabled, int was_enabled);
enum rq_nohz_flag_bits {
NOHZ_TICK_STOPPED,
NOHZ_BALANCE_KICK,
- NOHZ_IDLE,
};
#define nohz_flags(cpu) (&cpu_rq(cpu)->nohz_flags)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 5af44b593770..b7a10048a32c 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -160,6 +160,8 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
case BPF_S_ALU_AND_X:
case BPF_S_ALU_OR_K:
case BPF_S_ALU_OR_X:
+ case BPF_S_ALU_XOR_K:
+ case BPF_S_ALU_XOR_X:
case BPF_S_ALU_LSH_K:
case BPF_S_ALU_LSH_X:
case BPF_S_ALU_RSH_K:
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
index 4567fc020fe3..6815171a4fff 100644
--- a/kernel/semaphore.c
+++ b/kernel/semaphore.c
@@ -193,7 +193,7 @@ EXPORT_SYMBOL(up);
struct semaphore_waiter {
struct list_head list;
struct task_struct *task;
- int up;
+ bool up;
};
/*
@@ -209,12 +209,12 @@ static inline int __sched __down_common(struct semaphore *sem, long state,
list_add_tail(&waiter.list, &sem->wait_list);
waiter.task = task;
- waiter.up = 0;
+ waiter.up = false;
for (;;) {
if (signal_pending_state(state, task))
goto interrupted;
- if (timeout <= 0)
+ if (unlikely(timeout <= 0))
goto timed_out;
__set_task_state(task, state);
raw_spin_unlock_irq(&sem->lock);
@@ -258,6 +258,6 @@ static noinline void __sched __up(struct semaphore *sem)
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter, list);
list_del(&waiter->list);
- waiter->up = 1;
+ waiter->up = true;
wake_up_process(waiter->task);
}
diff --git a/kernel/signal.c b/kernel/signal.c
index dd72567767d9..113411bfe8b1 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -32,6 +32,7 @@
#include <linux/user_namespace.h>
#include <linux/uprobes.h>
#include <linux/compat.h>
+#include <linux/cn_proc.h>
#define CREATE_TRACE_POINTS
#include <trace/events/signal.h>
@@ -854,12 +855,14 @@ static void ptrace_trap_notify(struct task_struct *t)
* Returns true if the signal should be actually delivered, otherwise
* it should be dropped.
*/
-static int prepare_signal(int sig, struct task_struct *p, bool force)
+static bool prepare_signal(int sig, struct task_struct *p, bool force)
{
struct signal_struct *signal = p->signal;
struct task_struct *t;
- if (unlikely(signal->flags & SIGNAL_GROUP_EXIT)) {
+ if (signal->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) {
+ if (signal->flags & SIGNAL_GROUP_COREDUMP)
+ return sig == SIGKILL;
/*
* The process is in the middle of dying, nothing to do.
*/
@@ -1160,8 +1163,7 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
static void print_fatal_signal(int signr)
{
struct pt_regs *regs = signal_pt_regs();
- printk(KERN_INFO "%s/%d: potentially unexpected fatal signal %d.\n",
- current->comm, task_pid_nr(current), signr);
+ printk(KERN_INFO "potentially unexpected fatal signal %d.\n", signr);
#if defined(__i386__) && !defined(__arch_um__)
printk(KERN_INFO "code at %08lx: ", regs->ip);
@@ -2350,6 +2352,7 @@ relock:
if (sig_kernel_coredump(signr)) {
if (print_fatal_signals)
print_fatal_signal(info->si_signo);
+ proc_coredump_connector(current);
/*
* If it was able to dump core, this kills all
* other threads in the group and synchronizes with
@@ -2948,7 +2951,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
static int do_tkill(pid_t tgid, pid_t pid, int sig)
{
- struct siginfo info;
+ struct siginfo info = {};
info.si_signo = sig;
info.si_errno = 0;
diff --git a/kernel/smp.c b/kernel/smp.c
index 8e451f3ff51b..4dba0f7b72ad 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -100,16 +100,16 @@ void __init call_function_init(void)
* previous function call. For multi-cpu calls its even more interesting
* as we'll have to ensure no other cpu is observing our csd.
*/
-static void csd_lock_wait(struct call_single_data *data)
+static void csd_lock_wait(struct call_single_data *csd)
{
- while (data->flags & CSD_FLAG_LOCK)
+ while (csd->flags & CSD_FLAG_LOCK)
cpu_relax();
}
-static void csd_lock(struct call_single_data *data)
+static void csd_lock(struct call_single_data *csd)
{
- csd_lock_wait(data);
- data->flags = CSD_FLAG_LOCK;
+ csd_lock_wait(csd);
+ csd->flags |= CSD_FLAG_LOCK;
/*
* prevent CPU from reordering the above assignment
@@ -119,16 +119,16 @@ static void csd_lock(struct call_single_data *data)
smp_mb();
}
-static void csd_unlock(struct call_single_data *data)
+static void csd_unlock(struct call_single_data *csd)
{
- WARN_ON(!(data->flags & CSD_FLAG_LOCK));
+ WARN_ON(!(csd->flags & CSD_FLAG_LOCK));
/*
* ensure we're all done before releasing data:
*/
smp_mb();
- data->flags &= ~CSD_FLAG_LOCK;
+ csd->flags &= ~CSD_FLAG_LOCK;
}
/*
@@ -137,7 +137,7 @@ static void csd_unlock(struct call_single_data *data)
* ->func, ->info, and ->flags set.
*/
static
-void generic_exec_single(int cpu, struct call_single_data *data, int wait)
+void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
{
struct call_single_queue *dst = &per_cpu(call_single_queue, cpu);
unsigned long flags;
@@ -145,7 +145,7 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait)
raw_spin_lock_irqsave(&dst->lock, flags);
ipi = list_empty(&dst->list);
- list_add_tail(&data->list, &dst->list);
+ list_add_tail(&csd->list, &dst->list);
raw_spin_unlock_irqrestore(&dst->lock, flags);
/*
@@ -163,7 +163,7 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait)
arch_send_call_function_single_ipi(cpu);
if (wait)
- csd_lock_wait(data);
+ csd_lock_wait(csd);
}
/*
@@ -173,7 +173,6 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait)
void generic_smp_call_function_single_interrupt(void)
{
struct call_single_queue *q = &__get_cpu_var(call_single_queue);
- unsigned int data_flags;
LIST_HEAD(list);
/*
@@ -186,25 +185,26 @@ void generic_smp_call_function_single_interrupt(void)
raw_spin_unlock(&q->lock);
while (!list_empty(&list)) {
- struct call_single_data *data;
+ struct call_single_data *csd;
+ unsigned int csd_flags;
- data = list_entry(list.next, struct call_single_data, list);
- list_del(&data->list);
+ csd = list_entry(list.next, struct call_single_data, list);
+ list_del(&csd->list);
/*
- * 'data' can be invalid after this call if flags == 0
+ * 'csd' can be invalid after this call if flags == 0
* (when called through generic_exec_single()),
* so save them away before making the call:
*/
- data_flags = data->flags;
+ csd_flags = csd->flags;
- data->func(data->info);
+ csd->func(csd->info);
/*
* Unlocked CSDs are valid through generic_exec_single():
*/
- if (data_flags & CSD_FLAG_LOCK)
- csd_unlock(data);
+ if (csd_flags & CSD_FLAG_LOCK)
+ csd_unlock(csd);
}
}
@@ -249,16 +249,16 @@ int smp_call_function_single(int cpu, smp_call_func_t func, void *info,
local_irq_restore(flags);
} else {
if ((unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) {
- struct call_single_data *data = &d;
+ struct call_single_data *csd = &d;
if (!wait)
- data = &__get_cpu_var(csd_data);
+ csd = &__get_cpu_var(csd_data);
- csd_lock(data);
+ csd_lock(csd);
- data->func = func;
- data->info = info;
- generic_exec_single(cpu, data, wait);
+ csd->func = func;
+ csd->info = info;
+ generic_exec_single(cpu, csd, wait);
} else {
err = -ENXIO; /* CPU not online */
}
@@ -325,7 +325,7 @@ EXPORT_SYMBOL_GPL(smp_call_function_any);
* pre-allocated data structure. Useful for embedding @data inside
* other structures, for instance.
*/
-void __smp_call_function_single(int cpu, struct call_single_data *data,
+void __smp_call_function_single(int cpu, struct call_single_data *csd,
int wait)
{
unsigned int this_cpu;
@@ -343,11 +343,11 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
if (cpu == this_cpu) {
local_irq_save(flags);
- data->func(data->info);
+ csd->func(csd->info);
local_irq_restore(flags);
} else {
- csd_lock(data);
- generic_exec_single(cpu, data, wait);
+ csd_lock(csd);
+ generic_exec_single(cpu, csd, wait);
}
put_cpu();
}
@@ -369,7 +369,7 @@ void __smp_call_function_single(int cpu, struct call_single_data *data,
void smp_call_function_many(const struct cpumask *mask,
smp_call_func_t func, void *info, bool wait)
{
- struct call_function_data *data;
+ struct call_function_data *cfd;
int cpu, next_cpu, this_cpu = smp_processor_id();
/*
@@ -401,24 +401,24 @@ void smp_call_function_many(const struct cpumask *mask,
return;
}
- data = &__get_cpu_var(cfd_data);
+ cfd = &__get_cpu_var(cfd_data);
- cpumask_and(data->cpumask, mask, cpu_online_mask);
- cpumask_clear_cpu(this_cpu, data->cpumask);
+ cpumask_and(cfd->cpumask, mask, cpu_online_mask);
+ cpumask_clear_cpu(this_cpu, cfd->cpumask);
/* Some callers race with other cpus changing the passed mask */
- if (unlikely(!cpumask_weight(data->cpumask)))
+ if (unlikely(!cpumask_weight(cfd->cpumask)))
return;
/*
- * After we put an entry into the list, data->cpumask
- * may be cleared again when another CPU sends another IPI for
- * a SMP function call, so data->cpumask will be zero.
+ * After we put an entry into the list, cfd->cpumask may be cleared
+ * again when another CPU sends another IPI for a SMP function call, so
+ * cfd->cpumask will be zero.
*/
- cpumask_copy(data->cpumask_ipi, data->cpumask);
+ cpumask_copy(cfd->cpumask_ipi, cfd->cpumask);
- for_each_cpu(cpu, data->cpumask) {
- struct call_single_data *csd = per_cpu_ptr(data->csd, cpu);
+ for_each_cpu(cpu, cfd->cpumask) {
+ struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu);
struct call_single_queue *dst =
&per_cpu(call_single_queue, cpu);
unsigned long flags;
@@ -433,12 +433,13 @@ void smp_call_function_many(const struct cpumask *mask,
}
/* Send a message to all CPUs in the map */
- arch_send_call_function_ipi_mask(data->cpumask_ipi);
+ arch_send_call_function_ipi_mask(cfd->cpumask_ipi);
if (wait) {
- for_each_cpu(cpu, data->cpumask) {
- struct call_single_data *csd =
- per_cpu_ptr(data->csd, cpu);
+ for_each_cpu(cpu, cfd->cpumask) {
+ struct call_single_data *csd;
+
+ csd = per_cpu_ptr(cfd->csd, cpu);
csd_lock_wait(csd);
}
}
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 8eaed9aa9cf0..02fc5c933673 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -185,8 +185,18 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
}
get_task_struct(tsk);
*per_cpu_ptr(ht->store, cpu) = tsk;
- if (ht->create)
- ht->create(cpu);
+ if (ht->create) {
+ /*
+ * Make sure that the task has actually scheduled out
+ * into park position, before calling the create
+ * callback. At least the migration thread callback
+ * requires that the task is off the runqueue.
+ */
+ if (!wait_task_inactive(tsk, TASK_PARKED))
+ WARN_ON(1);
+ else
+ ht->create(cpu);
+ }
return 0;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 14d7758074aa..aa82723c7202 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -620,8 +620,7 @@ static void remote_softirq_receive(void *data)
unsigned long flags;
int softirq;
- softirq = cp->priv;
-
+ softirq = *(int *)cp->info;
local_irq_save(flags);
__local_trigger(cp, softirq);
local_irq_restore(flags);
@@ -631,9 +630,8 @@ static int __try_remote_softirq(struct call_single_data *cp, int cpu, int softir
{
if (cpu_online(cpu)) {
cp->func = remote_softirq_receive;
- cp->info = cp;
+ cp->info = &softirq;
cp->flags = 0;
- cp->priv = softirq;
__smp_call_function_single(cpu, cp, 0);
return 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index 39c9c4a2949f..b95d3c72ba21 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -49,6 +49,11 @@
#include <linux/user_namespace.h>
#include <linux/binfmts.h>
+#include <linux/sched.h>
+#include <linux/rcupdate.h>
+#include <linux/uidgid.h>
+#include <linux/cred.h>
+
#include <linux/kmsg_dump.h>
/* Move somewhere else to avoid recompiling? */
#include <generated/utsrelease.h>
@@ -324,7 +329,6 @@ void kernel_restart_prepare(char *cmd)
system_state = SYSTEM_RESTART;
usermodehelper_disable();
device_shutdown();
- syscore_shutdown();
}
/**
@@ -370,6 +374,7 @@ void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
disable_nonboot_cpus();
+ syscore_shutdown();
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
else
@@ -395,6 +400,7 @@ static void kernel_shutdown_prepare(enum system_states state)
void kernel_halt(void)
{
kernel_shutdown_prepare(SYSTEM_HALT);
+ disable_nonboot_cpus();
syscore_shutdown();
printk(KERN_EMERG "System halted.\n");
kmsg_dump(KMSG_DUMP_HALT);
@@ -1043,6 +1049,67 @@ change_okay:
return old_fsgid;
}
+/**
+ * sys_getpid - return the thread group id of the current process
+ *
+ * Note, despite the name, this returns the tgid not the pid. The tgid and
+ * the pid are identical unless CLONE_THREAD was specified on clone() in
+ * which case the tgid is the same in all threads of the same group.
+ *
+ * This is SMP safe as current->tgid does not change.
+ */
+SYSCALL_DEFINE0(getpid)
+{
+ return task_tgid_vnr(current);
+}
+
+/* Thread ID - the internal kernel "pid" */
+SYSCALL_DEFINE0(gettid)
+{
+ return task_pid_vnr(current);
+}
+
+/*
+ * Accessing ->real_parent is not SMP-safe, it could
+ * change from under us. However, we can use a stale
+ * value of ->real_parent under rcu_read_lock(), see
+ * release_task()->call_rcu(delayed_put_task_struct).
+ */
+SYSCALL_DEFINE0(getppid)
+{
+ int pid;
+
+ rcu_read_lock();
+ pid = task_tgid_vnr(rcu_dereference(current->real_parent));
+ rcu_read_unlock();
+
+ return pid;
+}
+
+SYSCALL_DEFINE0(getuid)
+{
+ /* Only we change this so SMP safe */
+ return from_kuid_munged(current_user_ns(), current_uid());
+}
+
+SYSCALL_DEFINE0(geteuid)
+{
+ /* Only we change this so SMP safe */
+ return from_kuid_munged(current_user_ns(), current_euid());
+}
+
+SYSCALL_DEFINE0(getgid)
+{
+ /* Only we change this so SMP safe */
+ return from_kgid_munged(current_user_ns(), current_gid());
+}
+
+SYSCALL_DEFINE0(getegid)
+{
+ /* Only we change this so SMP safe */
+ return from_kgid_munged(current_user_ns(), current_egid());
+}
+
void do_sys_times(struct tms *tms)
{
cputime_t tgutime, tgstime, cutime, cstime;
@@ -1784,13 +1851,26 @@ SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
return getrusage(current, who, ru);
}
+#ifdef CONFIG_COMPAT
+COMPAT_SYSCALL_DEFINE2(getrusage, int, who, struct compat_rusage __user *, ru)
+{
+ struct rusage r;
+
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&
+ who != RUSAGE_THREAD)
+ return -EINVAL;
+
+ k_getrusage(current, who, &r);
+ return put_compat_rusage(&r, ru);
+}
+#endif
+
SYSCALL_DEFINE1(umask, int, mask)
{
mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
return mask;
}
-#ifdef CONFIG_CHECKPOINT_RESTORE
static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd)
{
struct fd exe;
@@ -1984,17 +2064,12 @@ out:
return error;
}
+#ifdef CONFIG_CHECKPOINT_RESTORE
static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr)
{
return put_user(me->clear_child_tid, tid_addr);
}
-
-#else /* CONFIG_CHECKPOINT_RESTORE */
-static int prctl_set_mm(int opt, unsigned long addr,
- unsigned long arg4, unsigned long arg5)
-{
- return -EINVAL;
-}
+#else
static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr)
{
return -EINVAL;
@@ -2244,3 +2319,148 @@ int orderly_poweroff(bool force)
return 0;
}
EXPORT_SYMBOL_GPL(orderly_poweroff);
+
+/**
+ * do_sysinfo - fill in sysinfo struct
+ * @info: pointer to buffer to fill
+ */
+static int do_sysinfo(struct sysinfo *info)
+{
+ unsigned long mem_total, sav_total;
+ unsigned int mem_unit, bitcount;
+ struct timespec tp;
+
+ memset(info, 0, sizeof(struct sysinfo));
+
+ ktime_get_ts(&tp);
+ monotonic_to_bootbased(&tp);
+ info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
+
+ get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT);
+
+ info->procs = nr_threads;
+
+ si_meminfo(info);
+ si_swapinfo(info);
+
+ /*
+ * If the sum of all the available memory (i.e. ram + swap)
+ * is less than can be stored in a 32 bit unsigned long then
+ * we can be binary compatible with 2.2.x kernels. If not,
+ * well, in that case 2.2.x was broken anyways...
+ *
+ * -Erik Andersen <andersee@debian.org>
+ */
+
+ mem_total = info->totalram + info->totalswap;
+ if (mem_total < info->totalram || mem_total < info->totalswap)
+ goto out;
+ bitcount = 0;
+ mem_unit = info->mem_unit;
+ while (mem_unit > 1) {
+ bitcount++;
+ mem_unit >>= 1;
+ sav_total = mem_total;
+ mem_total <<= 1;
+ if (mem_total < sav_total)
+ goto out;
+ }
+
+ /*
+ * If mem_total did not overflow, multiply all memory values by
+ * info->mem_unit and set it to 1. This leaves things compatible
+ * with 2.2.x, and also retains compatibility with earlier 2.4.x
+ * kernels...
+ */
+
+ info->mem_unit = 1;
+ info->totalram <<= bitcount;
+ info->freeram <<= bitcount;
+ info->sharedram <<= bitcount;
+ info->bufferram <<= bitcount;
+ info->totalswap <<= bitcount;
+ info->freeswap <<= bitcount;
+ info->totalhigh <<= bitcount;
+ info->freehigh <<= bitcount;
+
+out:
+ return 0;
+}
+
+SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
+{
+ struct sysinfo val;
+
+ do_sysinfo(&val);
+
+ if (copy_to_user(info, &val, sizeof(struct sysinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+#ifdef CONFIG_COMPAT
+struct compat_sysinfo {
+ s32 uptime;
+ u32 loads[3];
+ u32 totalram;
+ u32 freeram;
+ u32 sharedram;
+ u32 bufferram;
+ u32 totalswap;
+ u32 freeswap;
+ u16 procs;
+ u16 pad;
+ u32 totalhigh;
+ u32 freehigh;
+ u32 mem_unit;
+ char _f[20-2*sizeof(u32)-sizeof(int)];
+};
+
+COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info)
+{
+ struct sysinfo s;
+
+ do_sysinfo(&s);
+
+ /* Check to see if any memory value is too large for 32-bit and scale
+ * down if needed
+ */
+ if ((s.totalram >> 32) || (s.totalswap >> 32)) {
+ int bitcount = 0;
+
+ while (s.mem_unit < PAGE_SIZE) {
+ s.mem_unit <<= 1;
+ bitcount++;
+ }
+
+ s.totalram >>= bitcount;
+ s.freeram >>= bitcount;
+ s.sharedram >>= bitcount;
+ s.bufferram >>= bitcount;
+ s.totalswap >>= bitcount;
+ s.freeswap >>= bitcount;
+ s.totalhigh >>= bitcount;
+ s.freehigh >>= bitcount;
+ }
+
+ if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) ||
+ __put_user(s.uptime, &info->uptime) ||
+ __put_user(s.loads[0], &info->loads[0]) ||
+ __put_user(s.loads[1], &info->loads[1]) ||
+ __put_user(s.loads[2], &info->loads[2]) ||
+ __put_user(s.totalram, &info->totalram) ||
+ __put_user(s.freeram, &info->freeram) ||
+ __put_user(s.sharedram, &info->sharedram) ||
+ __put_user(s.bufferram, &info->bufferram) ||
+ __put_user(s.totalswap, &info->totalswap) ||
+ __put_user(s.freeswap, &info->freeswap) ||
+ __put_user(s.procs, &info->procs) ||
+ __put_user(s.totalhigh, &info->totalhigh) ||
+ __put_user(s.freehigh, &info->freehigh) ||
+ __put_user(s.mem_unit, &info->mem_unit))
+ return -EFAULT;
+
+ return 0;
+}
+#endif /* CONFIG_COMPAT */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 395084d4ce16..bfd6787b355a 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -20,6 +20,7 @@ cond_syscall(sys_quotactl);
cond_syscall(sys32_quotactl);
cond_syscall(sys_acct);
cond_syscall(sys_lookup_dcookie);
+cond_syscall(compat_sys_lookup_dcookie);
cond_syscall(sys_swapon);
cond_syscall(sys_swapoff);
cond_syscall(sys_kexec_load);
@@ -155,7 +156,7 @@ cond_syscall(compat_sys_process_vm_writev);
cond_syscall(sys_pciconfig_read);
cond_syscall(sys_pciconfig_write);
cond_syscall(sys_pciconfig_iobase);
-cond_syscall(sys32_ipc);
+cond_syscall(compat_sys_s390_ipc);
cond_syscall(ppc_rtas);
cond_syscall(sys_spu_run);
cond_syscall(sys_spu_create);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index afc1dc60f3f8..9edcf456e0fc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -106,7 +106,6 @@ extern unsigned int core_pipe_limit;
#endif
extern int pid_max;
extern int pid_max_min, pid_max_max;
-extern int sysctl_drop_caches;
extern int percpu_pagelist_fraction;
extern int compat_log;
extern int latencytop_enabled;
@@ -1430,6 +1429,20 @@ static struct ctl_table vm_table[] = {
.extra2 = &one,
},
#endif
+ {
+ .procname = "user_reserve_kbytes",
+ .data = &sysctl_user_reserve_kbytes,
+ .maxlen = sizeof(sysctl_user_reserve_kbytes),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ },
+ {
+ .procname = "admin_reserve_kbytes",
+ .data = &sysctl_admin_reserve_kbytes,
+ .maxlen = sizeof(sysctl_admin_reserve_kbytes),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ },
{ }
};
diff --git a/kernel/test_kprobes.c b/kernel/test_kprobes.c
index f8b11a283171..12d6ebbfdd83 100644
--- a/kernel/test_kprobes.c
+++ b/kernel/test_kprobes.c
@@ -365,7 +365,7 @@ int init_test_probes(void)
target2 = kprobe_target2;
do {
- rand1 = random32();
+ rand1 = prandom_u32();
} while (rand1 <= div_factor);
printk(KERN_INFO "Kprobe smoke test started\n");
diff --git a/kernel/time.c b/kernel/time.c
index f8342a41efa6..d3617dbd3dca 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -138,13 +138,14 @@ int persistent_clock_is_local;
*/
static inline void warp_clock(void)
{
- struct timespec adjust;
+ if (sys_tz.tz_minuteswest != 0) {
+ struct timespec adjust;
- adjust = current_kernel_time();
- if (sys_tz.tz_minuteswest != 0)
persistent_clock_is_local = 1;
- adjust.tv_sec += sys_tz.tz_minuteswest * 60;
- do_settimeofday(&adjust);
+ adjust.tv_sec = sys_tz.tz_minuteswest * 60;
+ adjust.tv_nsec = 0;
+ timekeeping_inject_offset(&adjust);
+ }
}
/*
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 072bb066bb7d..12ff13a838c6 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -18,13 +18,14 @@
#include <linux/rtc.h>
#include "tick-internal.h"
+#include "ntp_internal.h"
/*
* NTP timekeeping variables:
+ *
+ * Note: All of the NTP state is protected by the timekeeping locks.
*/
-DEFINE_RAW_SPINLOCK(ntp_lock);
-
/* USER_HZ period (usecs): */
unsigned long tick_usec = TICK_USEC;
@@ -53,9 +54,6 @@ static int time_state = TIME_OK;
/* clock status bits: */
static int time_status = STA_UNSYNC;
-/* TAI offset (secs): */
-static long time_tai;
-
/* time adjustment (nsecs): */
static s64 time_offset;
@@ -134,8 +132,6 @@ static inline void pps_reset_freq_interval(void)
/**
* pps_clear - Clears the PPS state variables
- *
- * Must be called while holding a write on the ntp_lock
*/
static inline void pps_clear(void)
{
@@ -150,8 +146,6 @@ static inline void pps_clear(void)
/* Decrease pps_valid to indicate that another second has passed since
* the last PPS signal. When it reaches 0, indicate that PPS signal is
* missing.
- *
- * Must be called while holding a write on the ntp_lock
*/
static inline void pps_dec_valid(void)
{
@@ -346,10 +340,6 @@ static void ntp_update_offset(long offset)
*/
void ntp_clear(void)
{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ntp_lock, flags);
-
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
@@ -362,20 +352,12 @@ void ntp_clear(void)
/* Clear PPS state variables */
pps_clear();
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
-
}
u64 ntp_tick_length(void)
{
- unsigned long flags;
- s64 ret;
-
- raw_spin_lock_irqsave(&ntp_lock, flags);
- ret = tick_length;
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
- return ret;
+ return tick_length;
}
@@ -393,9 +375,6 @@ int second_overflow(unsigned long secs)
{
s64 delta;
int leap = 0;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ntp_lock, flags);
/*
* Leap second processing. If in leap-insert state at the end of the
@@ -415,7 +394,6 @@ int second_overflow(unsigned long secs)
else if (secs % 86400 == 0) {
leap = -1;
time_state = TIME_OOP;
- time_tai++;
printk(KERN_NOTICE
"Clock: inserting leap second 23:59:60 UTC\n");
}
@@ -425,7 +403,6 @@ int second_overflow(unsigned long secs)
time_state = TIME_OK;
else if ((secs + 1) % 86400 == 0) {
leap = 1;
- time_tai--;
time_state = TIME_WAIT;
printk(KERN_NOTICE
"Clock: deleting leap second 23:59:59 UTC\n");
@@ -479,8 +456,6 @@ int second_overflow(unsigned long secs)
time_adjust = 0;
out:
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
-
return leap;
}
@@ -575,11 +550,10 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
time_status |= txc->status & ~STA_RONLY;
}
-/*
- * Called with ntp_lock held, so we can access and modify
- * all the global NTP state:
- */
-static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts)
+
+static inline void process_adjtimex_modes(struct timex *txc,
+ struct timespec *ts,
+ s32 *time_tai)
{
if (txc->modes & ADJ_STATUS)
process_adj_status(txc, ts);
@@ -613,7 +587,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts
}
if (txc->modes & ADJ_TAI && txc->constant > 0)
- time_tai = txc->constant;
+ *time_tai = txc->constant;
if (txc->modes & ADJ_OFFSET)
ntp_update_offset(txc->offset);
@@ -625,16 +599,13 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts
ntp_update_frequency();
}
-/*
- * adjtimex mainly allows reading (and writing, if superuser) of
- * kernel time-keeping variables. used by xntpd.
+
+
+/**
+ * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex
*/
-int do_adjtimex(struct timex *txc)
+int ntp_validate_timex(struct timex *txc)
{
- struct timespec ts;
- int result;
-
- /* Validate the data before disabling interrupts */
if (txc->modes & ADJ_ADJTIME) {
/* singleshot must not be used with any other mode bits */
if (!(txc->modes & ADJ_OFFSET_SINGLESHOT))
@@ -646,7 +617,6 @@ int do_adjtimex(struct timex *txc)
/* In order to modify anything, you gotta be super-user! */
if (txc->modes && !capable(CAP_SYS_TIME))
return -EPERM;
-
/*
* if the quartz is off by more than 10% then
* something is VERY wrong!
@@ -657,22 +627,20 @@ int do_adjtimex(struct timex *txc)
return -EINVAL;
}
- if (txc->modes & ADJ_SETOFFSET) {
- struct timespec delta;
- delta.tv_sec = txc->time.tv_sec;
- delta.tv_nsec = txc->time.tv_usec;
- if (!capable(CAP_SYS_TIME))
- return -EPERM;
- if (!(txc->modes & ADJ_NANO))
- delta.tv_nsec *= 1000;
- result = timekeeping_inject_offset(&delta);
- if (result)
- return result;
- }
+ if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
+ return -EPERM;
- getnstimeofday(&ts);
+ return 0;
+}
- raw_spin_lock_irq(&ntp_lock);
+
+/*
+ * adjtimex mainly allows reading (and writing, if superuser) of
+ * kernel time-keeping variables. used by xntpd.
+ */
+int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
+{
+ int result;
if (txc->modes & ADJ_ADJTIME) {
long save_adjust = time_adjust;
@@ -687,7 +655,7 @@ int do_adjtimex(struct timex *txc)
/* If there are input parameters, then process them: */
if (txc->modes)
- process_adjtimex_modes(txc, &ts);
+ process_adjtimex_modes(txc, ts, time_tai);
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
NTP_SCALE_SHIFT);
@@ -709,15 +677,13 @@ int do_adjtimex(struct timex *txc)
txc->precision = 1;
txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
txc->tick = tick_usec;
- txc->tai = time_tai;
+ txc->tai = *time_tai;
/* fill PPS status fields */
pps_fill_timex(txc);
- raw_spin_unlock_irq(&ntp_lock);
-
- txc->time.tv_sec = ts.tv_sec;
- txc->time.tv_usec = ts.tv_nsec;
+ txc->time.tv_sec = ts->tv_sec;
+ txc->time.tv_usec = ts->tv_nsec;
if (!(time_status & STA_NANO))
txc->time.tv_usec /= NSEC_PER_USEC;
@@ -894,7 +860,7 @@ static void hardpps_update_phase(long error)
}
/*
- * hardpps() - discipline CPU clock oscillator to external PPS signal
+ * __hardpps() - discipline CPU clock oscillator to external PPS signal
*
* This routine is called at each PPS signal arrival in order to
* discipline the CPU clock oscillator to the PPS signal. It takes two
@@ -905,15 +871,13 @@ static void hardpps_update_phase(long error)
* This code is based on David Mills's reference nanokernel
* implementation. It was mostly rewritten but keeps the same idea.
*/
-void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
+void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
{
struct pps_normtime pts_norm, freq_norm;
unsigned long flags;
pts_norm = pps_normalize_ts(*phase_ts);
- raw_spin_lock_irqsave(&ntp_lock, flags);
-
/* clear the error bits, they will be set again if needed */
time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
@@ -925,7 +889,6 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
* just start the frequency interval */
if (unlikely(pps_fbase.tv_sec == 0)) {
pps_fbase = *raw_ts;
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
return;
}
@@ -940,7 +903,6 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
time_status |= STA_PPSJITTER;
/* restart the frequency calibration interval */
pps_fbase = *raw_ts;
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
pr_err("hardpps: PPSJITTER: bad pulse\n");
return;
}
@@ -957,10 +919,7 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
hardpps_update_phase(pts_norm.nsec);
- raw_spin_unlock_irqrestore(&ntp_lock, flags);
}
-EXPORT_SYMBOL(hardpps);
-
#endif /* CONFIG_NTP_PPS */
static int __init ntp_tick_adj_setup(char *str)
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h
new file mode 100644
index 000000000000..1950cb4ca2a4
--- /dev/null
+++ b/kernel/time/ntp_internal.h
@@ -0,0 +1,12 @@
+#ifndef _LINUX_NTP_INTERNAL_H
+#define _LINUX_NTP_INTERNAL_H
+
+extern void ntp_init(void);
+extern void ntp_clear(void);
+/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
+extern u64 ntp_tick_length(void);
+extern int second_overflow(unsigned long secs);
+extern int ntp_validate_timex(struct timex *);
+extern int __do_adjtimex(struct timex *, struct timespec *, s32 *);
+extern void __hardpps(const struct timespec *, const struct timespec *);
+#endif /* _LINUX_NTP_INTERNAL_H */
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 7f32fe0e52cd..61d00a8cdf2f 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -28,9 +28,8 @@
*/
static struct tick_device tick_broadcast_device;
-/* FIXME: Use cpumask_var_t. */
-static DECLARE_BITMAP(tick_broadcast_mask, NR_CPUS);
-static DECLARE_BITMAP(tmpmask, NR_CPUS);
+static cpumask_var_t tick_broadcast_mask;
+static cpumask_var_t tmpmask;
static DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
static int tick_broadcast_force;
@@ -50,7 +49,7 @@ struct tick_device *tick_get_broadcast_device(void)
struct cpumask *tick_get_broadcast_mask(void)
{
- return to_cpumask(tick_broadcast_mask);
+ return tick_broadcast_mask;
}
/*
@@ -67,6 +66,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
*/
int tick_check_broadcast_device(struct clock_event_device *dev)
{
+ struct clock_event_device *cur = tick_broadcast_device.evtdev;
+
if ((dev->features & CLOCK_EVT_FEAT_DUMMY) ||
(tick_broadcast_device.evtdev &&
tick_broadcast_device.evtdev->rating >= dev->rating) ||
@@ -74,9 +75,21 @@ int tick_check_broadcast_device(struct clock_event_device *dev)
return 0;
clockevents_exchange_device(tick_broadcast_device.evtdev, dev);
+ if (cur)
+ cur->event_handler = clockevents_handle_noop;
tick_broadcast_device.evtdev = dev;
- if (!cpumask_empty(tick_get_broadcast_mask()))
+ if (!cpumask_empty(tick_broadcast_mask))
tick_broadcast_start_periodic(dev);
+ /*
+ * Inform all cpus about this. We might be in a situation
+ * where we did not switch to oneshot mode because the per cpu
+ * devices are affected by CLOCK_EVT_FEAT_C3STOP and the lack
+ * of a oneshot capable broadcast device. Without that
+ * notification the systems stays stuck in periodic mode
+ * forever.
+ */
+ if (dev->features & CLOCK_EVT_FEAT_ONESHOT)
+ tick_clock_notify();
return 1;
}
@@ -124,7 +137,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
if (!tick_device_is_functional(dev)) {
dev->event_handler = tick_handle_periodic;
tick_device_setup_broadcast_func(dev);
- cpumask_set_cpu(cpu, tick_get_broadcast_mask());
+ cpumask_set_cpu(cpu, tick_broadcast_mask);
tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
ret = 1;
} else {
@@ -135,7 +148,7 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
*/
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
int cpu = smp_processor_id();
- cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
+ cpumask_clear_cpu(cpu, tick_broadcast_mask);
tick_broadcast_clear_oneshot(cpu);
} else {
tick_device_setup_broadcast_func(dev);
@@ -199,9 +212,8 @@ static void tick_do_periodic_broadcast(void)
{
raw_spin_lock(&tick_broadcast_lock);
- cpumask_and(to_cpumask(tmpmask),
- cpu_online_mask, tick_get_broadcast_mask());
- tick_do_broadcast(to_cpumask(tmpmask));
+ cpumask_and(tmpmask, cpu_online_mask, tick_broadcast_mask);
+ tick_do_broadcast(tmpmask);
raw_spin_unlock(&tick_broadcast_lock);
}
@@ -264,13 +276,12 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
if (!tick_device_is_functional(dev))
goto out;
- bc_stopped = cpumask_empty(tick_get_broadcast_mask());
+ bc_stopped = cpumask_empty(tick_broadcast_mask);
switch (*reason) {
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
- if (!cpumask_test_cpu(cpu, tick_get_broadcast_mask())) {
- cpumask_set_cpu(cpu, tick_get_broadcast_mask());
+ if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
if (tick_broadcast_device.mode ==
TICKDEV_MODE_PERIODIC)
clockevents_shutdown(dev);
@@ -280,8 +291,7 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
break;
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
if (!tick_broadcast_force &&
- cpumask_test_cpu(cpu, tick_get_broadcast_mask())) {
- cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
+ cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) {
if (tick_broadcast_device.mode ==
TICKDEV_MODE_PERIODIC)
tick_setup_periodic(dev, 0);
@@ -289,7 +299,7 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
break;
}
- if (cpumask_empty(tick_get_broadcast_mask())) {
+ if (cpumask_empty(tick_broadcast_mask)) {
if (!bc_stopped)
clockevents_shutdown(bc);
} else if (bc_stopped) {
@@ -338,10 +348,10 @@ void tick_shutdown_broadcast(unsigned int *cpup)
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
bc = tick_broadcast_device.evtdev;
- cpumask_clear_cpu(cpu, tick_get_broadcast_mask());
+ cpumask_clear_cpu(cpu, tick_broadcast_mask);
if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) {
- if (bc && cpumask_empty(tick_get_broadcast_mask()))
+ if (bc && cpumask_empty(tick_broadcast_mask))
clockevents_shutdown(bc);
}
@@ -377,13 +387,13 @@ int tick_resume_broadcast(void)
switch (tick_broadcast_device.mode) {
case TICKDEV_MODE_PERIODIC:
- if (!cpumask_empty(tick_get_broadcast_mask()))
+ if (!cpumask_empty(tick_broadcast_mask))
tick_broadcast_start_periodic(bc);
broadcast = cpumask_test_cpu(smp_processor_id(),
- tick_get_broadcast_mask());
+ tick_broadcast_mask);
break;
case TICKDEV_MODE_ONESHOT:
- if (!cpumask_empty(tick_get_broadcast_mask()))
+ if (!cpumask_empty(tick_broadcast_mask))
broadcast = tick_resume_broadcast_oneshot(bc);
break;
}
@@ -396,25 +406,58 @@ int tick_resume_broadcast(void)
#ifdef CONFIG_TICK_ONESHOT
-/* FIXME: use cpumask_var_t. */
-static DECLARE_BITMAP(tick_broadcast_oneshot_mask, NR_CPUS);
+static cpumask_var_t tick_broadcast_oneshot_mask;
+static cpumask_var_t tick_broadcast_pending_mask;
+static cpumask_var_t tick_broadcast_force_mask;
/*
* Exposed for debugging: see timer_list.c
*/
struct cpumask *tick_get_broadcast_oneshot_mask(void)
{
- return to_cpumask(tick_broadcast_oneshot_mask);
+ return tick_broadcast_oneshot_mask;
}
-static int tick_broadcast_set_event(ktime_t expires, int force)
+/*
+ * Called before going idle with interrupts disabled. Checks whether a
+ * broadcast event from the other core is about to happen. We detected
+ * that in tick_broadcast_oneshot_control(). The callsite can use this
+ * to avoid a deep idle transition as we are about to get the
+ * broadcast IPI right away.
+ */
+int tick_check_broadcast_expired(void)
{
- struct clock_event_device *bc = tick_broadcast_device.evtdev;
+ return cpumask_test_cpu(smp_processor_id(), tick_broadcast_force_mask);
+}
+
+/*
+ * Set broadcast interrupt affinity
+ */
+static void tick_broadcast_set_affinity(struct clock_event_device *bc,
+ const struct cpumask *cpumask)
+{
+ if (!(bc->features & CLOCK_EVT_FEAT_DYNIRQ))
+ return;
+
+ if (cpumask_equal(bc->cpumask, cpumask))
+ return;
+
+ bc->cpumask = cpumask;
+ irq_set_affinity(bc->irq, bc->cpumask);
+}
+
+static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
+ ktime_t expires, int force)
+{
+ int ret;
if (bc->mode != CLOCK_EVT_MODE_ONESHOT)
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
- return clockevents_program_event(bc, expires, force);
+ ret = clockevents_program_event(bc, expires, force);
+ if (!ret)
+ tick_broadcast_set_affinity(bc, cpumask_of(cpu));
+ return ret;
}
int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
@@ -429,7 +472,7 @@ int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
*/
void tick_check_oneshot_broadcast(int cpu)
{
- if (cpumask_test_cpu(cpu, to_cpumask(tick_broadcast_oneshot_mask))) {
+ if (cpumask_test_cpu(cpu, tick_broadcast_oneshot_mask)) {
struct tick_device *td = &per_cpu(tick_cpu_device, cpu);
clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_ONESHOT);
@@ -443,27 +486,39 @@ static void tick_handle_oneshot_broadcast(struct clock_event_device *dev)
{
struct tick_device *td;
ktime_t now, next_event;
- int cpu;
+ int cpu, next_cpu = 0;
raw_spin_lock(&tick_broadcast_lock);
again:
dev->next_event.tv64 = KTIME_MAX;
next_event.tv64 = KTIME_MAX;
- cpumask_clear(to_cpumask(tmpmask));
+ cpumask_clear(tmpmask);
now = ktime_get();
/* Find all expired events */
- for_each_cpu(cpu, tick_get_broadcast_oneshot_mask()) {
+ for_each_cpu(cpu, tick_broadcast_oneshot_mask) {
td = &per_cpu(tick_cpu_device, cpu);
- if (td->evtdev->next_event.tv64 <= now.tv64)
- cpumask_set_cpu(cpu, to_cpumask(tmpmask));
- else if (td->evtdev->next_event.tv64 < next_event.tv64)
+ if (td->evtdev->next_event.tv64 <= now.tv64) {
+ cpumask_set_cpu(cpu, tmpmask);
+ /*
+ * Mark the remote cpu in the pending mask, so
+ * it can avoid reprogramming the cpu local
+ * timer in tick_broadcast_oneshot_control().
+ */
+ cpumask_set_cpu(cpu, tick_broadcast_pending_mask);
+ } else if (td->evtdev->next_event.tv64 < next_event.tv64) {
next_event.tv64 = td->evtdev->next_event.tv64;
+ next_cpu = cpu;
+ }
}
+ /* Take care of enforced broadcast requests */
+ cpumask_or(tmpmask, tmpmask, tick_broadcast_force_mask);
+ cpumask_clear(tick_broadcast_force_mask);
+
/*
* Wakeup the cpus which have an expired event.
*/
- tick_do_broadcast(to_cpumask(tmpmask));
+ tick_do_broadcast(tmpmask);
/*
* Two reasons for reprogram:
@@ -480,7 +535,7 @@ again:
* Rearm the broadcast device. If event expired,
* repeat the above
*/
- if (tick_broadcast_set_event(next_event, 0))
+ if (tick_broadcast_set_event(dev, next_cpu, next_event, 0))
goto again;
}
raw_spin_unlock(&tick_broadcast_lock);
@@ -495,6 +550,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
struct clock_event_device *bc, *dev;
struct tick_device *td;
unsigned long flags;
+ ktime_t now;
int cpu;
/*
@@ -519,21 +575,84 @@ void tick_broadcast_oneshot_control(unsigned long reason)
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) {
- if (!cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
- cpumask_set_cpu(cpu, tick_get_broadcast_oneshot_mask());
+ WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
+ if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
- if (dev->next_event.tv64 < bc->next_event.tv64)
- tick_broadcast_set_event(dev->next_event, 1);
+ /*
+ * We only reprogram the broadcast timer if we
+ * did not mark ourself in the force mask and
+ * if the cpu local event is earlier than the
+ * broadcast event. If the current CPU is in
+ * the force mask, then we are going to be
+ * woken by the IPI right away.
+ */
+ if (!cpumask_test_cpu(cpu, tick_broadcast_force_mask) &&
+ dev->next_event.tv64 < bc->next_event.tv64)
+ tick_broadcast_set_event(bc, cpu, dev->next_event, 1);
}
} else {
- if (cpumask_test_cpu(cpu, tick_get_broadcast_oneshot_mask())) {
- cpumask_clear_cpu(cpu,
- tick_get_broadcast_oneshot_mask());
+ if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
- if (dev->next_event.tv64 != KTIME_MAX)
- tick_program_event(dev->next_event, 1);
+ if (dev->next_event.tv64 == KTIME_MAX)
+ goto out;
+ /*
+ * The cpu which was handling the broadcast
+ * timer marked this cpu in the broadcast
+ * pending mask and fired the broadcast
+ * IPI. So we are going to handle the expired
+ * event anyway via the broadcast IPI
+ * handler. No need to reprogram the timer
+ * with an already expired event.
+ */
+ if (cpumask_test_and_clear_cpu(cpu,
+ tick_broadcast_pending_mask))
+ goto out;
+
+ /*
+ * If the pending bit is not set, then we are
+ * either the CPU handling the broadcast
+ * interrupt or we got woken by something else.
+ *
+ * We are not longer in the broadcast mask, so
+ * if the cpu local expiry time is already
+ * reached, we would reprogram the cpu local
+ * timer with an already expired event.
+ *
+ * This can lead to a ping-pong when we return
+ * to idle and therefor rearm the broadcast
+ * timer before the cpu local timer was able
+ * to fire. This happens because the forced
+ * reprogramming makes sure that the event
+ * will happen in the future and depending on
+ * the min_delta setting this might be far
+ * enough out that the ping-pong starts.
+ *
+ * If the cpu local next_event has expired
+ * then we know that the broadcast timer
+ * next_event has expired as well and
+ * broadcast is about to be handled. So we
+ * avoid reprogramming and enforce that the
+ * broadcast handler, which did not run yet,
+ * will invoke the cpu local handler.
+ *
+ * We cannot call the handler directly from
+ * here, because we might be in a NOHZ phase
+ * and we did not go through the irq_enter()
+ * nohz fixups.
+ */
+ now = ktime_get();
+ if (dev->next_event.tv64 <= now.tv64) {
+ cpumask_set_cpu(cpu, tick_broadcast_force_mask);
+ goto out;
+ }
+ /*
+ * We got woken by something else. Reprogram
+ * the cpu local timer device.
+ */
+ tick_program_event(dev->next_event, 1);
}
}
+out:
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
@@ -544,7 +663,7 @@ void tick_broadcast_oneshot_control(unsigned long reason)
*/
static void tick_broadcast_clear_oneshot(int cpu)
{
- cpumask_clear_cpu(cpu, tick_get_broadcast_oneshot_mask());
+ cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
}
static void tick_broadcast_init_next_event(struct cpumask *mask,
@@ -582,17 +701,16 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
* oneshot_mask bits for those and program the
* broadcast device to fire.
*/
- cpumask_copy(to_cpumask(tmpmask), tick_get_broadcast_mask());
- cpumask_clear_cpu(cpu, to_cpumask(tmpmask));
- cpumask_or(tick_get_broadcast_oneshot_mask(),
- tick_get_broadcast_oneshot_mask(),
- to_cpumask(tmpmask));
+ cpumask_copy(tmpmask, tick_broadcast_mask);
+ cpumask_clear_cpu(cpu, tmpmask);
+ cpumask_or(tick_broadcast_oneshot_mask,
+ tick_broadcast_oneshot_mask, tmpmask);
- if (was_periodic && !cpumask_empty(to_cpumask(tmpmask))) {
+ if (was_periodic && !cpumask_empty(tmpmask)) {
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
- tick_broadcast_init_next_event(to_cpumask(tmpmask),
+ tick_broadcast_init_next_event(tmpmask,
tick_next_period);
- tick_broadcast_set_event(tick_next_period, 1);
+ tick_broadcast_set_event(bc, cpu, tick_next_period, 1);
} else
bc->next_event.tv64 = KTIME_MAX;
} else {
@@ -640,7 +758,7 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
* Clear the broadcast mask flag for the dead cpu, but do not
* stop the broadcast device!
*/
- cpumask_clear_cpu(cpu, tick_get_broadcast_oneshot_mask());
+ cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
@@ -664,3 +782,14 @@ bool tick_broadcast_oneshot_available(void)
}
#endif
+
+void __init tick_broadcast_init(void)
+{
+ alloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT);
+ alloc_cpumask_var(&tmpmask, GFP_NOWAIT);
+#ifdef CONFIG_TICK_ONESHOT
+ alloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT);
+ alloc_cpumask_var(&tick_broadcast_pending_mask, GFP_NOWAIT);
+ alloc_cpumask_var(&tick_broadcast_force_mask, GFP_NOWAIT);
+#endif
+}
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index b1600a6973f4..6176a3e45709 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -323,6 +323,7 @@ static void tick_shutdown(unsigned int *cpup)
*/
dev->mode = CLOCK_EVT_MODE_UNUSED;
clockevents_exchange_device(dev, NULL);
+ dev->event_handler = clockevents_handle_noop;
td->evtdev = NULL;
}
raw_spin_unlock_irqrestore(&tick_device_lock, flags);
@@ -416,4 +417,5 @@ static struct notifier_block tick_notifier = {
void __init tick_init(void)
{
clockevents_register_notifier(&tick_notifier);
+ tick_broadcast_init();
}
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index cf3e59ed6dc0..f0299eae4602 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -4,6 +4,8 @@
#include <linux/hrtimer.h>
#include <linux/tick.h>
+extern seqlock_t jiffies_lock;
+
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
#define TICK_DO_TIMER_NONE -1
@@ -94,7 +96,7 @@ extern void tick_broadcast_on_off(unsigned long reason, int *oncpu);
extern void tick_shutdown_broadcast(unsigned int *cpup);
extern void tick_suspend_broadcast(void);
extern int tick_resume_broadcast(void);
-
+extern void tick_broadcast_init(void);
extern void
tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
@@ -119,6 +121,7 @@ static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { }
static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
static inline void tick_suspend_broadcast(void) { }
static inline int tick_resume_broadcast(void) { return 0; }
+static inline void tick_broadcast_init(void) { }
/*
* Set the periodic handler in non broadcast mode
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index a19a39952c1b..225f8bf19095 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -482,8 +482,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
if (ratelimit < 10 &&
(local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
- printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n",
- (unsigned int) local_softirq_pending());
+ pr_warn("NOHZ: local_softirq_pending %02x\n",
+ (unsigned int) local_softirq_pending());
ratelimit++;
}
return false;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 9a0bc98fbe1d..98cd470bbe49 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -23,8 +23,13 @@
#include <linux/stop_machine.h>
#include <linux/pvclock_gtod.h>
+#include "tick-internal.h"
+#include "ntp_internal.h"
static struct timekeeper timekeeper;
+static DEFINE_RAW_SPINLOCK(timekeeper_lock);
+static seqcount_t timekeeper_seq;
+static struct timekeeper shadow_timekeeper;
/* flag for if timekeeping is suspended */
int __read_mostly timekeeping_suspended;
@@ -67,6 +72,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
tk->wall_to_monotonic = wtm;
set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec);
tk->offs_real = timespec_to_ktime(tmp);
+ tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0));
}
static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t)
@@ -96,7 +102,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
old_clock = tk->clock;
tk->clock = clock;
- clock->cycle_last = clock->read(clock);
+ tk->cycle_last = clock->cycle_last = clock->read(clock);
/* Do the ns -> cycle conversion first, using original mult */
tmp = NTP_INTERVAL_LENGTH;
@@ -201,8 +207,6 @@ static void update_pvclock_gtod(struct timekeeper *tk)
/**
* pvclock_gtod_register_notifier - register a pvclock timedata update listener
- *
- * Must hold write on timekeeper.lock
*/
int pvclock_gtod_register_notifier(struct notifier_block *nb)
{
@@ -210,11 +214,10 @@ int pvclock_gtod_register_notifier(struct notifier_block *nb)
unsigned long flags;
int ret;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
- /* update timekeeping data */
update_pvclock_gtod(tk);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
return ret;
}
@@ -223,25 +226,22 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier);
/**
* pvclock_gtod_unregister_notifier - unregister a pvclock
* timedata update listener
- *
- * Must hold write on timekeeper.lock
*/
int pvclock_gtod_unregister_notifier(struct notifier_block *nb)
{
- struct timekeeper *tk = &timekeeper;
unsigned long flags;
int ret;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
return ret;
}
EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
-/* must hold write on timekeeper.lock */
-static void timekeeping_update(struct timekeeper *tk, bool clearntp)
+/* must hold timekeeper_lock */
+static void timekeeping_update(struct timekeeper *tk, bool clearntp, bool mirror)
{
if (clearntp) {
tk->ntp_error = 0;
@@ -249,6 +249,9 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
}
update_vsyscall(tk);
update_pvclock_gtod(tk);
+
+ if (mirror)
+ memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));
}
/**
@@ -267,7 +270,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)
clock = tk->clock;
cycle_now = clock->read(clock);
cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
- clock->cycle_last = cycle_now;
+ tk->cycle_last = clock->cycle_last = cycle_now;
tk->xtime_nsec += cycle_delta * tk->mult;
@@ -294,12 +297,12 @@ int __getnstimeofday(struct timespec *ts)
s64 nsecs = 0;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
ts->tv_sec = tk->xtime_sec;
nsecs = timekeeping_get_ns(tk);
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
ts->tv_nsec = 0;
timespec_add_ns(ts, nsecs);
@@ -335,11 +338,11 @@ ktime_t ktime_get(void)
WARN_ON(timekeeping_suspended);
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
/*
* Use ktime_set/ktime_add_ns to create a proper ktime on
* 32-bit architectures without CONFIG_KTIME_SCALAR.
@@ -366,12 +369,12 @@ void ktime_get_ts(struct timespec *ts)
WARN_ON(timekeeping_suspended);
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
ts->tv_sec = tk->xtime_sec;
nsec = timekeeping_get_ns(tk);
tomono = tk->wall_to_monotonic;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
ts->tv_sec += tomono.tv_sec;
ts->tv_nsec = 0;
@@ -379,6 +382,50 @@ void ktime_get_ts(struct timespec *ts)
}
EXPORT_SYMBOL_GPL(ktime_get_ts);
+
+/**
+ * timekeeping_clocktai - Returns the TAI time of day in a timespec
+ * @ts: pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ */
+void timekeeping_clocktai(struct timespec *ts)
+{
+ struct timekeeper *tk = &timekeeper;
+ unsigned long seq;
+ u64 nsecs;
+
+ WARN_ON(timekeeping_suspended);
+
+ do {
+ seq = read_seqcount_begin(&timekeeper_seq);
+
+ ts->tv_sec = tk->xtime_sec + tk->tai_offset;
+ nsecs = timekeeping_get_ns(tk);
+
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
+
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, nsecs);
+
+}
+EXPORT_SYMBOL(timekeeping_clocktai);
+
+
+/**
+ * ktime_get_clocktai - Returns the TAI time of day in a ktime
+ *
+ * Returns the time of day in a ktime.
+ */
+ktime_t ktime_get_clocktai(void)
+{
+ struct timespec ts;
+
+ timekeeping_clocktai(&ts);
+ return timespec_to_ktime(ts);
+}
+EXPORT_SYMBOL(ktime_get_clocktai);
+
#ifdef CONFIG_NTP_PPS
/**
@@ -399,7 +446,7 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
WARN_ON_ONCE(timekeeping_suspended);
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
*ts_raw = tk->raw_time;
ts_real->tv_sec = tk->xtime_sec;
@@ -408,7 +455,7 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
nsecs_raw = timekeeping_get_ns_raw(tk);
nsecs_real = timekeeping_get_ns(tk);
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
timespec_add_ns(ts_raw, nsecs_raw);
timespec_add_ns(ts_real, nsecs_real);
@@ -448,7 +495,8 @@ int do_settimeofday(const struct timespec *tv)
if (!timespec_valid_strict(tv))
return -EINVAL;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
timekeeping_forward_now(tk);
@@ -460,9 +508,10 @@ int do_settimeofday(const struct timespec *tv)
tk_set_xtime(tk, tv);
- timekeeping_update(tk, true);
+ timekeeping_update(tk, true, true);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
/* signal hrtimers about time change */
clock_was_set();
@@ -487,7 +536,8 @@ int timekeeping_inject_offset(struct timespec *ts)
if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
timekeeping_forward_now(tk);
@@ -502,9 +552,10 @@ int timekeeping_inject_offset(struct timespec *ts)
tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
error: /* even if we error out, we forwarded the time, so call update */
- timekeeping_update(tk, true);
+ timekeeping_update(tk, true, true);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
/* signal hrtimers about time change */
clock_was_set();
@@ -513,6 +564,52 @@ error: /* even if we error out, we forwarded the time, so call update */
}
EXPORT_SYMBOL(timekeeping_inject_offset);
+
+/**
+ * timekeeping_get_tai_offset - Returns current TAI offset from UTC
+ *
+ */
+s32 timekeeping_get_tai_offset(void)
+{
+ struct timekeeper *tk = &timekeeper;
+ unsigned int seq;
+ s32 ret;
+
+ do {
+ seq = read_seqcount_begin(&timekeeper_seq);
+ ret = tk->tai_offset;
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
+
+ return ret;
+}
+
+/**
+ * __timekeeping_set_tai_offset - Lock free worker function
+ *
+ */
+static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset)
+{
+ tk->tai_offset = tai_offset;
+ tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0));
+}
+
+/**
+ * timekeeping_set_tai_offset - Sets the current TAI offset from UTC
+ *
+ */
+void timekeeping_set_tai_offset(s32 tai_offset)
+{
+ struct timekeeper *tk = &timekeeper;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
+ __timekeeping_set_tai_offset(tk, tai_offset);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
+ clock_was_set();
+}
+
/**
* change_clocksource - Swaps clocksources if a new one is available
*
@@ -526,7 +623,8 @@ static int change_clocksource(void *data)
new = (struct clocksource *) data;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
timekeeping_forward_now(tk);
if (!new->enable || new->enable(new) == 0) {
@@ -535,9 +633,10 @@ static int change_clocksource(void *data)
if (old->disable)
old->disable(old);
}
- timekeeping_update(tk, true);
+ timekeeping_update(tk, true, true);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
return 0;
}
@@ -587,11 +686,11 @@ void getrawmonotonic(struct timespec *ts)
s64 nsecs;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
nsecs = timekeeping_get_ns_raw(tk);
*ts = tk->raw_time;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
timespec_add_ns(ts, nsecs);
}
@@ -607,11 +706,11 @@ int timekeeping_valid_for_hres(void)
int ret;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
return ret;
}
@@ -626,11 +725,11 @@ u64 timekeeping_max_deferment(void)
u64 ret;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
ret = tk->clock->max_idle_ns;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
return ret;
}
@@ -693,11 +792,10 @@ void __init timekeeping_init(void)
boot.tv_nsec = 0;
}
- seqlock_init(&tk->lock);
-
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
ntp_init();
- write_seqlock_irqsave(&tk->lock, flags);
clock = clocksource_default_clock();
if (clock->enable)
clock->enable(clock);
@@ -716,7 +814,10 @@ void __init timekeeping_init(void)
tmp.tv_nsec = 0;
tk_set_sleep_time(tk, tmp);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));
+
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
}
/* time in seconds when suspend began */
@@ -764,15 +865,17 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
if (has_persistent_clock())
return;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
timekeeping_forward_now(tk);
__timekeeping_inject_sleeptime(tk, delta);
- timekeeping_update(tk, true);
+ timekeeping_update(tk, true, true);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
/* signal hrtimers about time change */
clock_was_set();
@@ -788,26 +891,72 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
static void timekeeping_resume(void)
{
struct timekeeper *tk = &timekeeper;
+ struct clocksource *clock = tk->clock;
unsigned long flags;
- struct timespec ts;
+ struct timespec ts_new, ts_delta;
+ cycle_t cycle_now, cycle_delta;
+ bool suspendtime_found = false;
- read_persistent_clock(&ts);
+ read_persistent_clock(&ts_new);
clockevents_resume();
clocksource_resume();
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
+
+ /*
+ * After system resumes, we need to calculate the suspended time and
+ * compensate it for the OS time. There are 3 sources that could be
+ * used: Nonstop clocksource during suspend, persistent clock and rtc
+ * device.
+ *
+ * One specific platform may have 1 or 2 or all of them, and the
+ * preference will be:
+ * suspend-nonstop clocksource -> persistent clock -> rtc
+ * The less preferred source will only be tried if there is no better
+ * usable source. The rtc part is handled separately in rtc core code.
+ */
+ cycle_now = clock->read(clock);
+ if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
+ cycle_now > clock->cycle_last) {
+ u64 num, max = ULLONG_MAX;
+ u32 mult = clock->mult;
+ u32 shift = clock->shift;
+ s64 nsec = 0;
+
+ cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
- if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
- ts = timespec_sub(ts, timekeeping_suspend_time);
- __timekeeping_inject_sleeptime(tk, &ts);
+ /*
+ * "cycle_delta * mutl" may cause 64 bits overflow, if the
+ * suspended time is too long. In that case we need do the
+ * 64 bits math carefully
+ */
+ do_div(max, mult);
+ if (cycle_delta > max) {
+ num = div64_u64(cycle_delta, max);
+ nsec = (((u64) max * mult) >> shift) * num;
+ cycle_delta -= num * max;
+ }
+ nsec += ((u64) cycle_delta * mult) >> shift;
+
+ ts_delta = ns_to_timespec(nsec);
+ suspendtime_found = true;
+ } else if (timespec_compare(&ts_new, &timekeeping_suspend_time) > 0) {
+ ts_delta = timespec_sub(ts_new, timekeeping_suspend_time);
+ suspendtime_found = true;
}
- /* re-base the last cycle value */
- tk->clock->cycle_last = tk->clock->read(tk->clock);
+
+ if (suspendtime_found)
+ __timekeeping_inject_sleeptime(tk, &ts_delta);
+
+ /* Re-base the last cycle value */
+ tk->cycle_last = clock->cycle_last = cycle_now;
tk->ntp_error = 0;
timekeeping_suspended = 0;
- timekeeping_update(tk, false);
- write_sequnlock_irqrestore(&tk->lock, flags);
+ timekeeping_update(tk, false, true);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
touch_softlockup_watchdog();
@@ -826,7 +975,8 @@ static int timekeeping_suspend(void)
read_persistent_clock(&timekeeping_suspend_time);
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
timekeeping_forward_now(tk);
timekeeping_suspended = 1;
@@ -849,7 +999,8 @@ static int timekeeping_suspend(void)
timekeeping_suspend_time =
timespec_add(timekeeping_suspend_time, delta_delta);
}
- write_sequnlock_irqrestore(&tk->lock, flags);
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
clocksource_suspend();
@@ -1099,6 +1250,8 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
tk_set_wall_to_mono(tk,
timespec_sub(tk->wall_to_monotonic, ts));
+ __timekeeping_set_tai_offset(tk, tk->tai_offset - leap);
+
clock_was_set_delayed();
}
}
@@ -1116,15 +1269,16 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
u32 shift)
{
+ cycle_t interval = tk->cycle_interval << shift;
u64 raw_nsecs;
/* If the offset is smaller then a shifted interval, do nothing */
- if (offset < tk->cycle_interval<<shift)
+ if (offset < interval)
return offset;
/* Accumulate one shifted interval */
- offset -= tk->cycle_interval << shift;
- tk->clock->cycle_last += tk->cycle_interval << shift;
+ offset -= interval;
+ tk->cycle_last += interval;
tk->xtime_nsec += tk->xtime_interval << shift;
accumulate_nsecs_to_secs(tk);
@@ -1181,27 +1335,28 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)
static void update_wall_time(void)
{
struct clocksource *clock;
- struct timekeeper *tk = &timekeeper;
+ struct timekeeper *real_tk = &timekeeper;
+ struct timekeeper *tk = &shadow_timekeeper;
cycle_t offset;
int shift = 0, maxshift;
unsigned long flags;
- write_seqlock_irqsave(&tk->lock, flags);
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
/* Make sure we're fully resumed: */
if (unlikely(timekeeping_suspended))
goto out;
- clock = tk->clock;
+ clock = real_tk->clock;
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
- offset = tk->cycle_interval;
+ offset = real_tk->cycle_interval;
#else
offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
#endif
/* Check if there's really nothing to do */
- if (offset < tk->cycle_interval)
+ if (offset < real_tk->cycle_interval)
goto out;
/*
@@ -1238,11 +1393,24 @@ static void update_wall_time(void)
*/
accumulate_nsecs_to_secs(tk);
- timekeeping_update(tk, false);
-
+ write_seqcount_begin(&timekeeper_seq);
+ /* Update clock->cycle_last with the new value */
+ clock->cycle_last = tk->cycle_last;
+ /*
+ * Update the real timekeeper.
+ *
+ * We could avoid this memcpy by switching pointers, but that
+ * requires changes to all other timekeeper usage sites as
+ * well, i.e. move the timekeeper pointer getter into the
+ * spinlocked/seqcount protected sections. And we trade this
+ * memcpy under the timekeeper_seq against one before we start
+ * updating.
+ */
+ memcpy(real_tk, tk, sizeof(*tk));
+ timekeeping_update(real_tk, false, false);
+ write_seqcount_end(&timekeeper_seq);
out:
- write_sequnlock_irqrestore(&tk->lock, flags);
-
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
}
/**
@@ -1289,13 +1457,13 @@ void get_monotonic_boottime(struct timespec *ts)
WARN_ON(timekeeping_suspended);
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
ts->tv_sec = tk->xtime_sec;
nsec = timekeeping_get_ns(tk);
tomono = tk->wall_to_monotonic;
sleep = tk->total_sleep_time;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
ts->tv_sec += tomono.tv_sec + sleep.tv_sec;
ts->tv_nsec = 0;
@@ -1354,10 +1522,10 @@ struct timespec current_kernel_time(void)
unsigned long seq;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
now = tk_xtime(tk);
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
return now;
}
@@ -1370,11 +1538,11 @@ struct timespec get_monotonic_coarse(void)
unsigned long seq;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
now = tk_xtime(tk);
mono = tk->wall_to_monotonic;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,
now.tv_nsec + mono.tv_nsec);
@@ -1405,11 +1573,11 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
unsigned long seq;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
*xtim = tk_xtime(tk);
*wtom = tk->wall_to_monotonic;
*sleep = tk->total_sleep_time;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
}
#ifdef CONFIG_HIGH_RES_TIMERS
@@ -1421,7 +1589,8 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
* Returns current monotonic time and updates the offsets
* Called from hrtimer_interupt() or retrigger_next_event()
*/
-ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
+ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
+ ktime_t *offs_tai)
{
struct timekeeper *tk = &timekeeper;
ktime_t now;
@@ -1429,14 +1598,15 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
u64 secs, nsecs;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
secs = tk->xtime_sec;
nsecs = timekeeping_get_ns(tk);
*offs_real = tk->offs_real;
*offs_boot = tk->offs_boot;
- } while (read_seqretry(&tk->lock, seq));
+ *offs_tai = tk->offs_tai;
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
now = ktime_add_ns(ktime_set(secs, 0), nsecs);
now = ktime_sub(now, *offs_real);
@@ -1454,15 +1624,79 @@ ktime_t ktime_get_monotonic_offset(void)
struct timespec wtom;
do {
- seq = read_seqbegin(&tk->lock);
+ seq = read_seqcount_begin(&timekeeper_seq);
wtom = tk->wall_to_monotonic;
- } while (read_seqretry(&tk->lock, seq));
+ } while (read_seqcount_retry(&timekeeper_seq, seq));
return timespec_to_ktime(wtom);
}
EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
/**
+ * do_adjtimex() - Accessor function to NTP __do_adjtimex function
+ */
+int do_adjtimex(struct timex *txc)
+{
+ struct timekeeper *tk = &timekeeper;
+ unsigned long flags;
+ struct timespec ts;
+ s32 orig_tai, tai;
+ int ret;
+
+ /* Validate the data before disabling interrupts */
+ ret = ntp_validate_timex(txc);
+ if (ret)
+ return ret;
+
+ if (txc->modes & ADJ_SETOFFSET) {
+ struct timespec delta;
+ delta.tv_sec = txc->time.tv_sec;
+ delta.tv_nsec = txc->time.tv_usec;
+ if (!(txc->modes & ADJ_NANO))
+ delta.tv_nsec *= 1000;
+ ret = timekeeping_inject_offset(&delta);
+ if (ret)
+ return ret;
+ }
+
+ getnstimeofday(&ts);
+
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
+
+ orig_tai = tai = tk->tai_offset;
+ ret = __do_adjtimex(txc, &ts, &tai);
+
+ if (tai != orig_tai) {
+ __timekeeping_set_tai_offset(tk, tai);
+ clock_was_set_delayed();
+ }
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
+
+ return ret;
+}
+
+#ifdef CONFIG_NTP_PPS
+/**
+ * hardpps() - Accessor function to NTP __hardpps function
+ */
+void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&timekeeper_lock, flags);
+ write_seqcount_begin(&timekeeper_seq);
+
+ __hardpps(phase_ts, raw_ts);
+
+ write_seqcount_end(&timekeeper_seq);
+ raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
+}
+EXPORT_SYMBOL(hardpps);
+#endif
+
+/**
* xtime_update() - advances the timekeeping infrastructure
* @ticks: number of ticks, that have elapsed since the last call.
*
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index af5a7e9f164b..3bdf28323012 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -20,6 +20,13 @@
#include <asm/uaccess.h>
+
+struct timer_list_iter {
+ int cpu;
+ bool second_pass;
+ u64 now;
+};
+
typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes);
DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
@@ -133,7 +140,6 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
- SEQ_printf(m, "\n");
SEQ_printf(m, "cpu: %d\n", cpu);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
SEQ_printf(m, " clock %d:\n", i);
@@ -187,6 +193,7 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
#undef P
#undef P_ns
+ SEQ_printf(m, "\n");
}
#ifdef CONFIG_GENERIC_CLOCKEVENTS
@@ -195,7 +202,6 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
{
struct clock_event_device *dev = td->evtdev;
- SEQ_printf(m, "\n");
SEQ_printf(m, "Tick Device: mode: %d\n", td->mode);
if (cpu < 0)
SEQ_printf(m, "Broadcast device\n");
@@ -230,12 +236,11 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
print_name_offset(m, dev->event_handler);
SEQ_printf(m, "\n");
SEQ_printf(m, " retries: %lu\n", dev->retries);
+ SEQ_printf(m, "\n");
}
-static void timer_list_show_tickdevices(struct seq_file *m)
+static void timer_list_show_tickdevices_header(struct seq_file *m)
{
- int cpu;
-
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
print_tickdevice(m, tick_get_broadcast_device(), -1);
SEQ_printf(m, "tick_broadcast_mask: %08lx\n",
@@ -246,47 +251,104 @@ static void timer_list_show_tickdevices(struct seq_file *m)
#endif
SEQ_printf(m, "\n");
#endif
- for_each_online_cpu(cpu)
- print_tickdevice(m, tick_get_device(cpu), cpu);
- SEQ_printf(m, "\n");
}
-#else
-static void timer_list_show_tickdevices(struct seq_file *m) { }
#endif
+static inline void timer_list_header(struct seq_file *m, u64 now)
+{
+ SEQ_printf(m, "Timer List Version: v0.7\n");
+ SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
+ SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
+ SEQ_printf(m, "\n");
+}
+
static int timer_list_show(struct seq_file *m, void *v)
{
+ struct timer_list_iter *iter = v;
+ u64 now = ktime_to_ns(ktime_get());
+
+ if (iter->cpu == -1 && !iter->second_pass)
+ timer_list_header(m, now);
+ else if (!iter->second_pass)
+ print_cpu(m, iter->cpu, iter->now);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ else if (iter->cpu == -1 && iter->second_pass)
+ timer_list_show_tickdevices_header(m);
+ else
+ print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
+#endif
+ return 0;
+}
+
+void sysrq_timer_list_show(void)
+{
u64 now = ktime_to_ns(ktime_get());
int cpu;
- SEQ_printf(m, "Timer List Version: v0.7\n");
- SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
- SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
+ timer_list_header(NULL, now);
for_each_online_cpu(cpu)
- print_cpu(m, cpu, now);
+ print_cpu(NULL, cpu, now);
- SEQ_printf(m, "\n");
- timer_list_show_tickdevices(m);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ timer_list_show_tickdevices_header(NULL);
+ for_each_online_cpu(cpu)
+ print_tickdevice(NULL, tick_get_device(cpu), cpu);
+#endif
+ return;
+}
- return 0;
+static void *timer_list_start(struct seq_file *file, loff_t *offset)
+{
+ struct timer_list_iter *iter = file->private;
+
+ if (!*offset) {
+ iter->cpu = -1;
+ iter->now = ktime_to_ns(ktime_get());
+ } else if (iter->cpu >= nr_cpu_ids) {
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ if (!iter->second_pass) {
+ iter->cpu = -1;
+ iter->second_pass = true;
+ } else
+ return NULL;
+#else
+ return NULL;
+#endif
+ }
+ return iter;
}
-void sysrq_timer_list_show(void)
+static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset)
+{
+ struct timer_list_iter *iter = file->private;
+ iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);
+ ++*offset;
+ return timer_list_start(file, offset);
+}
+
+static void timer_list_stop(struct seq_file *seq, void *v)
{
- timer_list_show(NULL, NULL);
}
+static const struct seq_operations timer_list_sops = {
+ .start = timer_list_start,
+ .next = timer_list_next,
+ .stop = timer_list_stop,
+ .show = timer_list_show,
+};
+
static int timer_list_open(struct inode *inode, struct file *filp)
{
- return single_open(filp, timer_list_show, NULL);
+ return seq_open_private(filp, &timer_list_sops,
+ sizeof(struct timer_list_iter));
}
static const struct file_operations timer_list_fops = {
.open = timer_list_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = seq_release_private,
};
static int __init init_timer_list_procfs(void)
diff --git a/kernel/timer.c b/kernel/timer.c
index dbf7a78a1ef1..09bca8ce9771 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1,7 +1,7 @@
/*
* linux/kernel/timer.c
*
- * Kernel internal timers, basic process system calls
+ * Kernel internal timers
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
@@ -41,6 +41,7 @@
#include <linux/sched.h>
#include <linux/sched/sysctl.h>
#include <linux/slab.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -1395,61 +1396,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, seconds)
#endif
-/**
- * sys_getpid - return the thread group id of the current process
- *
- * Note, despite the name, this returns the tgid not the pid. The tgid and
- * the pid are identical unless CLONE_THREAD was specified on clone() in
- * which case the tgid is the same in all threads of the same group.
- *
- * This is SMP safe as current->tgid does not change.
- */
-SYSCALL_DEFINE0(getpid)
-{
- return task_tgid_vnr(current);
-}
-
-/*
- * Accessing ->real_parent is not SMP-safe, it could
- * change from under us. However, we can use a stale
- * value of ->real_parent under rcu_read_lock(), see
- * release_task()->call_rcu(delayed_put_task_struct).
- */
-SYSCALL_DEFINE0(getppid)
-{
- int pid;
-
- rcu_read_lock();
- pid = task_tgid_vnr(rcu_dereference(current->real_parent));
- rcu_read_unlock();
-
- return pid;
-}
-
-SYSCALL_DEFINE0(getuid)
-{
- /* Only we change this so SMP safe */
- return from_kuid_munged(current_user_ns(), current_uid());
-}
-
-SYSCALL_DEFINE0(geteuid)
-{
- /* Only we change this so SMP safe */
- return from_kuid_munged(current_user_ns(), current_euid());
-}
-
-SYSCALL_DEFINE0(getgid)
-{
- /* Only we change this so SMP safe */
- return from_kgid_munged(current_user_ns(), current_gid());
-}
-
-SYSCALL_DEFINE0(getegid)
-{
- /* Only we change this so SMP safe */
- return from_kgid_munged(current_user_ns(), current_egid());
-}
-
static void process_timeout(unsigned long __data)
{
wake_up_process((struct task_struct *)__data);
@@ -1557,91 +1503,6 @@ signed long __sched schedule_timeout_uninterruptible(signed long timeout)
}
EXPORT_SYMBOL(schedule_timeout_uninterruptible);
-/* Thread ID - the internal kernel "pid" */
-SYSCALL_DEFINE0(gettid)
-{
- return task_pid_vnr(current);
-}
-
-/**
- * do_sysinfo - fill in sysinfo struct
- * @info: pointer to buffer to fill
- */
-int do_sysinfo(struct sysinfo *info)
-{
- unsigned long mem_total, sav_total;
- unsigned int mem_unit, bitcount;
- struct timespec tp;
-
- memset(info, 0, sizeof(struct sysinfo));
-
- ktime_get_ts(&tp);
- monotonic_to_bootbased(&tp);
- info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
-
- get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT);
-
- info->procs = nr_threads;
-
- si_meminfo(info);
- si_swapinfo(info);
-
- /*
- * If the sum of all the available memory (i.e. ram + swap)
- * is less than can be stored in a 32 bit unsigned long then
- * we can be binary compatible with 2.2.x kernels. If not,
- * well, in that case 2.2.x was broken anyways...
- *
- * -Erik Andersen <andersee@debian.org>
- */
-
- mem_total = info->totalram + info->totalswap;
- if (mem_total < info->totalram || mem_total < info->totalswap)
- goto out;
- bitcount = 0;
- mem_unit = info->mem_unit;
- while (mem_unit > 1) {
- bitcount++;
- mem_unit >>= 1;
- sav_total = mem_total;
- mem_total <<= 1;
- if (mem_total < sav_total)
- goto out;
- }
-
- /*
- * If mem_total did not overflow, multiply all memory values by
- * info->mem_unit and set it to 1. This leaves things compatible
- * with 2.2.x, and also retains compatibility with earlier 2.4.x
- * kernels...
- */
-
- info->mem_unit = 1;
- info->totalram <<= bitcount;
- info->freeram <<= bitcount;
- info->sharedram <<= bitcount;
- info->bufferram <<= bitcount;
- info->totalswap <<= bitcount;
- info->freeswap <<= bitcount;
- info->totalhigh <<= bitcount;
- info->freehigh <<= bitcount;
-
-out:
- return 0;
-}
-
-SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info)
-{
- struct sysinfo val;
-
- do_sysinfo(&val);
-
- if (copy_to_user(info, &val, sizeof(struct sysinfo)))
- return -EFAULT;
-
- return 0;
-}
-
static int __cpuinit init_timers_cpu(int cpu)
{
int j;
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index fc382d6e2765..5e9efd4b83a4 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -176,6 +176,8 @@ config IRQSOFF_TRACER
select GENERIC_TRACER
select TRACER_MAX_TRACE
select RING_BUFFER_ALLOW_SWAP
+ select TRACER_SNAPSHOT
+ select TRACER_SNAPSHOT_PER_CPU_SWAP
help
This option measures the time spent in irqs-off critical
sections, with microsecond accuracy.
@@ -198,6 +200,8 @@ config PREEMPT_TRACER
select GENERIC_TRACER
select TRACER_MAX_TRACE
select RING_BUFFER_ALLOW_SWAP
+ select TRACER_SNAPSHOT
+ select TRACER_SNAPSHOT_PER_CPU_SWAP
help
This option measures the time spent in preemption-off critical
sections, with microsecond accuracy.
@@ -217,6 +221,7 @@ config SCHED_TRACER
select GENERIC_TRACER
select CONTEXT_SWITCH_TRACER
select TRACER_MAX_TRACE
+ select TRACER_SNAPSHOT
help
This tracer tracks the latency of the highest priority task
to be scheduled in, starting from the point it has woken up.
@@ -248,6 +253,27 @@ config TRACER_SNAPSHOT
echo 1 > /sys/kernel/debug/tracing/snapshot
cat snapshot
+config TRACER_SNAPSHOT_PER_CPU_SWAP
+ bool "Allow snapshot to swap per CPU"
+ depends on TRACER_SNAPSHOT
+ select RING_BUFFER_ALLOW_SWAP
+ help
+ Allow doing a snapshot of a single CPU buffer instead of a
+ full swap (all buffers). If this is set, then the following is
+ allowed:
+
+ echo 1 > /sys/kernel/debug/tracing/per_cpu/cpu2/snapshot
+
+ After which, only the tracing buffer for CPU 2 was swapped with
+ the main tracing buffer, and the other CPU buffers remain the same.
+
+ When this is enabled, this adds a little more overhead to the
+ trace recording, as it needs to add some checks to synchronize
+ recording with swaps. But this does not affect the performance
+ of the overall system. This is enabled by default when the preempt
+ or irq latency tracers are enabled, as those need to swap as well
+ and already adds the overhead (plus a lot more).
+
config TRACE_BRANCH_PROFILING
bool
select GENERIC_TRACER
@@ -524,6 +550,29 @@ config RING_BUFFER_BENCHMARK
If unsure, say N.
+config RING_BUFFER_STARTUP_TEST
+ bool "Ring buffer startup self test"
+ depends on RING_BUFFER
+ help
+ Run a simple self test on the ring buffer on boot up. Late in the
+ kernel boot sequence, the test will start that kicks off
+ a thread per cpu. Each thread will write various size events
+ into the ring buffer. Another thread is created to send IPIs
+ to each of the threads, where the IPI handler will also write
+ to the ring buffer, to test/stress the nesting ability.
+ If any anomalies are discovered, a warning will be displayed
+ and all ring buffers will be disabled.
+
+ The test runs for 10 seconds. This will slow your boot time
+ by at least 10 more seconds.
+
+ At the end of the test, statics and more checks are done.
+ It will output the stats of each per cpu buffer. What
+ was written, the sizes, what was read, what was lost, and
+ other similar details.
+
+ If unsure, say N
+
endif # FTRACE
endif # TRACING_SUPPORT
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 9e5b8c272eec..ed58a3216a6d 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -72,7 +72,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action,
bool blk_tracer = blk_tracer_enabled;
if (blk_tracer) {
- buffer = blk_tr->buffer;
+ buffer = blk_tr->trace_buffer.buffer;
pc = preempt_count();
event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
sizeof(*t) + len,
@@ -218,7 +218,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
if (blk_tracer) {
tracing_record_cmdline(current);
- buffer = blk_tr->buffer;
+ buffer = blk_tr->trace_buffer.buffer;
pc = preempt_count();
event = trace_buffer_lock_reserve(buffer, TRACE_BLK,
sizeof(*t) + pdu_len,
@@ -739,12 +739,6 @@ static void blk_add_trace_rq_complete(void *ignore,
struct request_queue *q,
struct request *rq)
{
- struct blk_trace *bt = q->blk_trace;
-
- /* if control ever passes through here, it's a request based driver */
- if (unlikely(bt && !bt->rq_based))
- bt->rq_based = true;
-
blk_add_trace_rq(q, rq, BLK_TA_COMPLETE);
}
@@ -780,24 +774,10 @@ static void blk_add_trace_bio_bounce(void *ignore,
blk_add_trace_bio(q, bio, BLK_TA_BOUNCE, 0);
}
-static void blk_add_trace_bio_complete(void *ignore, struct bio *bio, int error)
+static void blk_add_trace_bio_complete(void *ignore,
+ struct request_queue *q, struct bio *bio,
+ int error)
{
- struct request_queue *q;
- struct blk_trace *bt;
-
- if (!bio->bi_bdev)
- return;
-
- q = bdev_get_queue(bio->bi_bdev);
- bt = q->blk_trace;
-
- /*
- * Request based drivers will generate both rq and bio completions.
- * Ignore bio ones.
- */
- if (likely(!bt) || bt->rq_based)
- return;
-
blk_add_trace_bio(q, bio, BLK_TA_COMPLETE, error);
}
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6893d5a2bf08..8a5c017bb50c 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -66,7 +66,7 @@
static struct ftrace_ops ftrace_list_end __read_mostly = {
.func = ftrace_stub,
- .flags = FTRACE_OPS_FL_RECURSION_SAFE,
+ .flags = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB,
};
/* ftrace_enabled is a method to turn ftrace on or off */
@@ -486,7 +486,6 @@ struct ftrace_profile_stat {
#define PROFILES_PER_PAGE \
(PROFILE_RECORDS_SIZE / sizeof(struct ftrace_profile))
-static int ftrace_profile_bits __read_mostly;
static int ftrace_profile_enabled __read_mostly;
/* ftrace_profile_lock - synchronize the enable and disable of the profiler */
@@ -494,7 +493,8 @@ static DEFINE_MUTEX(ftrace_profile_lock);
static DEFINE_PER_CPU(struct ftrace_profile_stat, ftrace_profile_stats);
-#define FTRACE_PROFILE_HASH_SIZE 1024 /* must be power of 2 */
+#define FTRACE_PROFILE_HASH_BITS 10
+#define FTRACE_PROFILE_HASH_SIZE (1 << FTRACE_PROFILE_HASH_BITS)
static void *
function_stat_next(void *v, int idx)
@@ -676,7 +676,7 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat)
pages = DIV_ROUND_UP(functions, PROFILES_PER_PAGE);
- for (i = 0; i < pages; i++) {
+ for (i = 1; i < pages; i++) {
pg->next = (void *)get_zeroed_page(GFP_KERNEL);
if (!pg->next)
goto out_free;
@@ -694,7 +694,6 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat)
free_page(tmp);
}
- free_page((unsigned long)stat->pages);
stat->pages = NULL;
stat->start = NULL;
@@ -725,13 +724,6 @@ static int ftrace_profile_init_cpu(int cpu)
if (!stat->hash)
return -ENOMEM;
- if (!ftrace_profile_bits) {
- size--;
-
- for (; size; size >>= 1)
- ftrace_profile_bits++;
- }
-
/* Preallocate the function profiling pages */
if (ftrace_profile_pages_init(stat) < 0) {
kfree(stat->hash);
@@ -764,7 +756,7 @@ ftrace_find_profiled_func(struct ftrace_profile_stat *stat, unsigned long ip)
struct hlist_head *hhd;
unsigned long key;
- key = hash_long(ip, ftrace_profile_bits);
+ key = hash_long(ip, FTRACE_PROFILE_HASH_BITS);
hhd = &stat->hash[key];
if (hlist_empty(hhd))
@@ -783,7 +775,7 @@ static void ftrace_add_profile(struct ftrace_profile_stat *stat,
{
unsigned long key;
- key = hash_long(rec->ip, ftrace_profile_bits);
+ key = hash_long(rec->ip, FTRACE_PROFILE_HASH_BITS);
hlist_add_head_rcu(&rec->node, &stat->hash[key]);
}
@@ -1053,6 +1045,19 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer)
static struct pid * const ftrace_swapper_pid = &init_struct_pid;
+loff_t
+ftrace_filter_lseek(struct file *file, loff_t offset, int whence)
+{
+ loff_t ret;
+
+ if (file->f_mode & FMODE_READ)
+ ret = seq_lseek(file, offset, whence);
+ else
+ file->f_pos = ret = 1;
+
+ return ret;
+}
+
#ifdef CONFIG_DYNAMIC_FTRACE
#ifndef CONFIG_FTRACE_MCOUNT_RECORD
@@ -1067,7 +1072,7 @@ struct ftrace_func_probe {
unsigned long flags;
unsigned long ip;
void *data;
- struct rcu_head rcu;
+ struct list_head free_list;
};
struct ftrace_func_entry {
@@ -1317,7 +1322,6 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
struct hlist_head *hhd;
struct ftrace_hash *old_hash;
struct ftrace_hash *new_hash;
- unsigned long key;
int size = src->count;
int bits = 0;
int ret;
@@ -1360,10 +1364,6 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
for (i = 0; i < size; i++) {
hhd = &src->buckets[i];
hlist_for_each_entry_safe(entry, tn, hhd, hlist) {
- if (bits > 0)
- key = hash_long(entry->ip, bits);
- else
- key = 0;
remove_hash_entry(src, entry);
__add_hash_entry(new_hash, entry);
}
@@ -2613,7 +2613,7 @@ static void ftrace_filter_reset(struct ftrace_hash *hash)
* routine, you can use ftrace_filter_write() for the write
* routine if @flag has FTRACE_ITER_FILTER set, or
* ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set.
- * ftrace_regex_lseek() should be used as the lseek routine, and
+ * ftrace_filter_lseek() should be used as the lseek routine, and
* release must call ftrace_regex_release().
*/
int
@@ -2697,19 +2697,6 @@ ftrace_notrace_open(struct inode *inode, struct file *file)
inode, file);
}
-loff_t
-ftrace_regex_lseek(struct file *file, loff_t offset, int whence)
-{
- loff_t ret;
-
- if (file->f_mode & FMODE_READ)
- ret = seq_lseek(file, offset, whence);
- else
- file->f_pos = ret = 1;
-
- return ret;
-}
-
static int ftrace_match(char *str, char *regex, int len, int type)
{
int matched = 0;
@@ -2974,28 +2961,27 @@ static void __disable_ftrace_function_probe(void)
}
-static void ftrace_free_entry_rcu(struct rcu_head *rhp)
+static void ftrace_free_entry(struct ftrace_func_probe *entry)
{
- struct ftrace_func_probe *entry =
- container_of(rhp, struct ftrace_func_probe, rcu);
-
if (entry->ops->free)
- entry->ops->free(&entry->data);
+ entry->ops->free(entry->ops, entry->ip, &entry->data);
kfree(entry);
}
-
int
register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data)
{
struct ftrace_func_probe *entry;
+ struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
+ struct ftrace_hash *hash;
struct ftrace_page *pg;
struct dyn_ftrace *rec;
int type, len, not;
unsigned long key;
int count = 0;
char *search;
+ int ret;
type = filter_parse_regex(glob, strlen(glob), &search, &not);
len = strlen(search);
@@ -3006,8 +2992,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
mutex_lock(&ftrace_lock);
- if (unlikely(ftrace_disabled))
+ hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
+ if (!hash) {
+ count = -ENOMEM;
+ goto out_unlock;
+ }
+
+ if (unlikely(ftrace_disabled)) {
+ count = -ENODEV;
goto out_unlock;
+ }
do_for_each_ftrace_rec(pg, rec) {
@@ -3031,14 +3025,21 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
* for each function we find. We call the callback
* to give the caller an opportunity to do so.
*/
- if (ops->callback) {
- if (ops->callback(rec->ip, &entry->data) < 0) {
+ if (ops->init) {
+ if (ops->init(ops, rec->ip, &entry->data) < 0) {
/* caller does not like this func */
kfree(entry);
continue;
}
}
+ ret = enter_record(hash, rec, 0);
+ if (ret < 0) {
+ kfree(entry);
+ count = ret;
+ goto out_unlock;
+ }
+
entry->ops = ops;
entry->ip = rec->ip;
@@ -3046,10 +3047,16 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
hlist_add_head_rcu(&entry->node, &ftrace_func_hash[key]);
} while_for_each_ftrace_rec();
+
+ ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+ if (ret < 0)
+ count = ret;
+
__enable_ftrace_function_probe();
out_unlock:
mutex_unlock(&ftrace_lock);
+ free_ftrace_hash(hash);
return count;
}
@@ -3063,7 +3070,12 @@ static void
__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data, int flags)
{
+ struct ftrace_func_entry *rec_entry;
struct ftrace_func_probe *entry;
+ struct ftrace_func_probe *p;
+ struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
+ struct list_head free_list;
+ struct ftrace_hash *hash;
struct hlist_node *tmp;
char str[KSYM_SYMBOL_LEN];
int type = MATCH_FULL;
@@ -3084,6 +3096,14 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
}
mutex_lock(&ftrace_lock);
+
+ hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
+ if (!hash)
+ /* Hmm, should report this somehow */
+ goto out_unlock;
+
+ INIT_LIST_HEAD(&free_list);
+
for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
struct hlist_head *hhd = &ftrace_func_hash[i];
@@ -3104,12 +3124,30 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
continue;
}
+ rec_entry = ftrace_lookup_ip(hash, entry->ip);
+ /* It is possible more than one entry had this ip */
+ if (rec_entry)
+ free_hash_entry(hash, rec_entry);
+
hlist_del_rcu(&entry->node);
- call_rcu_sched(&entry->rcu, ftrace_free_entry_rcu);
+ list_add(&entry->free_list, &free_list);
}
}
__disable_ftrace_function_probe();
+ /*
+ * Remove after the disable is called. Otherwise, if the last
+ * probe is removed, a null hash means *all enabled*.
+ */
+ ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+ synchronize_sched();
+ list_for_each_entry_safe(entry, p, &free_list, free_list) {
+ list_del(&entry->free_list);
+ ftrace_free_entry(entry);
+ }
+
+ out_unlock:
mutex_unlock(&ftrace_lock);
+ free_ftrace_hash(hash);
}
void
@@ -3441,14 +3479,14 @@ static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata;
static int __init set_ftrace_notrace(char *str)
{
- strncpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
+ strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE);
return 1;
}
__setup("ftrace_notrace=", set_ftrace_notrace);
static int __init set_ftrace_filter(char *str)
{
- strncpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
+ strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE);
return 1;
}
__setup("ftrace_filter=", set_ftrace_filter);
@@ -3571,7 +3609,7 @@ static const struct file_operations ftrace_filter_fops = {
.open = ftrace_filter_open,
.read = seq_read,
.write = ftrace_filter_write,
- .llseek = ftrace_regex_lseek,
+ .llseek = ftrace_filter_lseek,
.release = ftrace_regex_release,
};
@@ -3579,7 +3617,7 @@ static const struct file_operations ftrace_notrace_fops = {
.open = ftrace_notrace_open,
.read = seq_read,
.write = ftrace_notrace_write,
- .llseek = ftrace_regex_lseek,
+ .llseek = ftrace_filter_lseek,
.release = ftrace_regex_release,
};
@@ -3737,7 +3775,8 @@ out:
if (fail)
return -EINVAL;
- ftrace_graph_filter_enabled = 1;
+ ftrace_graph_filter_enabled = !!(*idx);
+
return 0;
}
@@ -3784,8 +3823,8 @@ static const struct file_operations ftrace_graph_fops = {
.open = ftrace_graph_open,
.read = seq_read,
.write = ftrace_graph_write,
+ .llseek = ftrace_filter_lseek,
.release = ftrace_graph_release,
- .llseek = seq_lseek,
};
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
@@ -4131,7 +4170,8 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
preempt_disable_notrace();
trace_recursion_set(TRACE_CONTROL_BIT);
do_for_each_ftrace_op(op, ftrace_control_list) {
- if (!ftrace_function_local_disabled(op) &&
+ if (!(op->flags & FTRACE_OPS_FL_STUB) &&
+ !ftrace_function_local_disabled(op) &&
ftrace_ops_test(op, ip))
op->func(ip, parent_ip, op, regs);
} while_for_each_ftrace_op(op);
@@ -4439,7 +4479,7 @@ static const struct file_operations ftrace_pid_fops = {
.open = ftrace_pid_open,
.write = ftrace_pid_write,
.read = seq_read,
- .llseek = seq_lseek,
+ .llseek = ftrace_filter_lseek,
.release = ftrace_pid_release,
};
@@ -4555,12 +4595,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
ftrace_startup_sysctl();
/* we are starting ftrace again */
- if (ftrace_ops_list != &ftrace_list_end) {
- if (ftrace_ops_list->next == &ftrace_list_end)
- ftrace_trace_function = ftrace_ops_list->func;
- else
- ftrace_trace_function = ftrace_ops_list_func;
- }
+ if (ftrace_ops_list != &ftrace_list_end)
+ update_ftrace_function();
} else {
/* stopping ftrace calls (just send to ftrace_stub) */
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 6989df2ba194..b59aea2c48c2 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -8,13 +8,16 @@
#include <linux/trace_clock.h>
#include <linux/trace_seq.h>
#include <linux/spinlock.h>
+#include <linux/irq_work.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
+#include <linux/kthread.h> /* for self test */
#include <linux/kmemcheck.h>
#include <linux/module.h>
#include <linux/percpu.h>
#include <linux/mutex.h>
+#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/hash.h>
@@ -444,6 +447,12 @@ int ring_buffer_print_page_header(struct trace_seq *s)
return ret;
}
+struct rb_irq_work {
+ struct irq_work work;
+ wait_queue_head_t waiters;
+ bool waiters_pending;
+};
+
/*
* head_page == tail_page && head == tail then buffer is empty.
*/
@@ -478,6 +487,8 @@ struct ring_buffer_per_cpu {
struct list_head new_pages; /* new pages to add */
struct work_struct update_pages_work;
struct completion update_done;
+
+ struct rb_irq_work irq_work;
};
struct ring_buffer {
@@ -497,6 +508,8 @@ struct ring_buffer {
struct notifier_block cpu_notify;
#endif
u64 (*clock)(void);
+
+ struct rb_irq_work irq_work;
};
struct ring_buffer_iter {
@@ -508,6 +521,118 @@ struct ring_buffer_iter {
u64 read_stamp;
};
+/*
+ * rb_wake_up_waiters - wake up tasks waiting for ring buffer input
+ *
+ * Schedules a delayed work to wake up any task that is blocked on the
+ * ring buffer waiters queue.
+ */
+static void rb_wake_up_waiters(struct irq_work *work)
+{
+ struct rb_irq_work *rbwork = container_of(work, struct rb_irq_work, work);
+
+ wake_up_all(&rbwork->waiters);
+}
+
+/**
+ * ring_buffer_wait - wait for input to the ring buffer
+ * @buffer: buffer to wait on
+ * @cpu: the cpu buffer to wait on
+ *
+ * If @cpu == RING_BUFFER_ALL_CPUS then the task will wake up as soon
+ * as data is added to any of the @buffer's cpu buffers. Otherwise
+ * it will wait for data to be added to a specific cpu buffer.
+ */
+void ring_buffer_wait(struct ring_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ DEFINE_WAIT(wait);
+ struct rb_irq_work *work;
+
+ /*
+ * Depending on what the caller is waiting for, either any
+ * data in any cpu buffer, or a specific buffer, put the
+ * caller on the appropriate wait queue.
+ */
+ if (cpu == RING_BUFFER_ALL_CPUS)
+ work = &buffer->irq_work;
+ else {
+ cpu_buffer = buffer->buffers[cpu];
+ work = &cpu_buffer->irq_work;
+ }
+
+
+ prepare_to_wait(&work->waiters, &wait, TASK_INTERRUPTIBLE);
+
+ /*
+ * The events can happen in critical sections where
+ * checking a work queue can cause deadlocks.
+ * After adding a task to the queue, this flag is set
+ * only to notify events to try to wake up the queue
+ * using irq_work.
+ *
+ * We don't clear it even if the buffer is no longer
+ * empty. The flag only causes the next event to run
+ * irq_work to do the work queue wake up. The worse
+ * that can happen if we race with !trace_empty() is that
+ * an event will cause an irq_work to try to wake up
+ * an empty queue.
+ *
+ * There's no reason to protect this flag either, as
+ * the work queue and irq_work logic will do the necessary
+ * synchronization for the wake ups. The only thing
+ * that is necessary is that the wake up happens after
+ * a task has been queued. It's OK for spurious wake ups.
+ */
+ work->waiters_pending = true;
+
+ if ((cpu == RING_BUFFER_ALL_CPUS && ring_buffer_empty(buffer)) ||
+ (cpu != RING_BUFFER_ALL_CPUS && ring_buffer_empty_cpu(buffer, cpu)))
+ schedule();
+
+ finish_wait(&work->waiters, &wait);
+}
+
+/**
+ * ring_buffer_poll_wait - poll on buffer input
+ * @buffer: buffer to wait on
+ * @cpu: the cpu buffer to wait on
+ * @filp: the file descriptor
+ * @poll_table: The poll descriptor
+ *
+ * If @cpu == RING_BUFFER_ALL_CPUS then the task will wake up as soon
+ * as data is added to any of the @buffer's cpu buffers. Otherwise
+ * it will wait for data to be added to a specific cpu buffer.
+ *
+ * Returns POLLIN | POLLRDNORM if data exists in the buffers,
+ * zero otherwise.
+ */
+int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu,
+ struct file *filp, poll_table *poll_table)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ struct rb_irq_work *work;
+
+ if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
+ (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
+ return POLLIN | POLLRDNORM;
+
+ if (cpu == RING_BUFFER_ALL_CPUS)
+ work = &buffer->irq_work;
+ else {
+ cpu_buffer = buffer->buffers[cpu];
+ work = &cpu_buffer->irq_work;
+ }
+
+ work->waiters_pending = true;
+ poll_wait(filp, &work->waiters, poll_table);
+
+ if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
+ (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
/* buffer may be either ring_buffer or ring_buffer_per_cpu */
#define RB_WARN_ON(b, cond) \
({ \
@@ -1063,6 +1188,8 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
cpu_buffer->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
INIT_WORK(&cpu_buffer->update_pages_work, update_pages_handler);
init_completion(&cpu_buffer->update_done);
+ init_irq_work(&cpu_buffer->irq_work.work, rb_wake_up_waiters);
+ init_waitqueue_head(&cpu_buffer->irq_work.waiters);
bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
GFP_KERNEL, cpu_to_node(cpu));
@@ -1158,6 +1285,9 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
buffer->clock = trace_clock_local;
buffer->reader_lock_key = key;
+ init_irq_work(&buffer->irq_work.work, rb_wake_up_waiters);
+ init_waitqueue_head(&buffer->irq_work.waiters);
+
/* need at least two pages */
if (nr_pages < 2)
nr_pages = 2;
@@ -1553,11 +1683,22 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
if (!cpu_buffer->nr_pages_to_update)
continue;
- if (cpu_online(cpu))
+ /* The update must run on the CPU that is being updated. */
+ preempt_disable();
+ if (cpu == smp_processor_id() || !cpu_online(cpu)) {
+ rb_update_pages(cpu_buffer);
+ cpu_buffer->nr_pages_to_update = 0;
+ } else {
+ /*
+ * Can not disable preemption for schedule_work_on()
+ * on PREEMPT_RT.
+ */
+ preempt_enable();
schedule_work_on(cpu,
&cpu_buffer->update_pages_work);
- else
- rb_update_pages(cpu_buffer);
+ preempt_disable();
+ }
+ preempt_enable();
}
/* wait for all the updates to complete */
@@ -1595,12 +1736,22 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
get_online_cpus();
- if (cpu_online(cpu_id)) {
+ preempt_disable();
+ /* The update must run on the CPU that is being updated. */
+ if (cpu_id == smp_processor_id() || !cpu_online(cpu_id))
+ rb_update_pages(cpu_buffer);
+ else {
+ /*
+ * Can not disable preemption for schedule_work_on()
+ * on PREEMPT_RT.
+ */
+ preempt_enable();
schedule_work_on(cpu_id,
&cpu_buffer->update_pages_work);
wait_for_completion(&cpu_buffer->update_done);
- } else
- rb_update_pages(cpu_buffer);
+ preempt_disable();
+ }
+ preempt_enable();
cpu_buffer->nr_pages_to_update = 0;
put_online_cpus();
@@ -2612,6 +2763,22 @@ static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer,
rb_end_commit(cpu_buffer);
}
+static __always_inline void
+rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
+{
+ if (buffer->irq_work.waiters_pending) {
+ buffer->irq_work.waiters_pending = false;
+ /* irq_work_queue() supplies it's own memory barriers */
+ irq_work_queue(&buffer->irq_work.work);
+ }
+
+ if (cpu_buffer->irq_work.waiters_pending) {
+ cpu_buffer->irq_work.waiters_pending = false;
+ /* irq_work_queue() supplies it's own memory barriers */
+ irq_work_queue(&cpu_buffer->irq_work.work);
+ }
+}
+
/**
* ring_buffer_unlock_commit - commit a reserved
* @buffer: The buffer to commit to
@@ -2631,6 +2798,8 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,
rb_commit(cpu_buffer, event);
+ rb_wakeups(buffer, cpu_buffer);
+
trace_recursive_unlock();
preempt_enable_notrace();
@@ -2803,6 +2972,8 @@ int ring_buffer_write(struct ring_buffer *buffer,
rb_commit(cpu_buffer, event);
+ rb_wakeups(buffer, cpu_buffer);
+
ret = 0;
out:
preempt_enable_notrace();
@@ -4467,3 +4638,320 @@ static int rb_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
#endif
+
+#ifdef CONFIG_RING_BUFFER_STARTUP_TEST
+/*
+ * This is a basic integrity check of the ring buffer.
+ * Late in the boot cycle this test will run when configured in.
+ * It will kick off a thread per CPU that will go into a loop
+ * writing to the per cpu ring buffer various sizes of data.
+ * Some of the data will be large items, some small.
+ *
+ * Another thread is created that goes into a spin, sending out
+ * IPIs to the other CPUs to also write into the ring buffer.
+ * this is to test the nesting ability of the buffer.
+ *
+ * Basic stats are recorded and reported. If something in the
+ * ring buffer should happen that's not expected, a big warning
+ * is displayed and all ring buffers are disabled.
+ */
+static struct task_struct *rb_threads[NR_CPUS] __initdata;
+
+struct rb_test_data {
+ struct ring_buffer *buffer;
+ unsigned long events;
+ unsigned long bytes_written;
+ unsigned long bytes_alloc;
+ unsigned long bytes_dropped;
+ unsigned long events_nested;
+ unsigned long bytes_written_nested;
+ unsigned long bytes_alloc_nested;
+ unsigned long bytes_dropped_nested;
+ int min_size_nested;
+ int max_size_nested;
+ int max_size;
+ int min_size;
+ int cpu;
+ int cnt;
+};
+
+static struct rb_test_data rb_data[NR_CPUS] __initdata;
+
+/* 1 meg per cpu */
+#define RB_TEST_BUFFER_SIZE 1048576
+
+static char rb_string[] __initdata =
+ "abcdefghijklmnopqrstuvwxyz1234567890!@#$%^&*()?+\\"
+ "?+|:';\",.<>/?abcdefghijklmnopqrstuvwxyz1234567890"
+ "!@#$%^&*()?+\\?+|:';\",.<>/?abcdefghijklmnopqrstuv";
+
+static bool rb_test_started __initdata;
+
+struct rb_item {
+ int size;
+ char str[];
+};
+
+static __init int rb_write_something(struct rb_test_data *data, bool nested)
+{
+ struct ring_buffer_event *event;
+ struct rb_item *item;
+ bool started;
+ int event_len;
+ int size;
+ int len;
+ int cnt;
+
+ /* Have nested writes different that what is written */
+ cnt = data->cnt + (nested ? 27 : 0);
+
+ /* Multiply cnt by ~e, to make some unique increment */
+ size = (data->cnt * 68 / 25) % (sizeof(rb_string) - 1);
+
+ len = size + sizeof(struct rb_item);
+
+ started = rb_test_started;
+ /* read rb_test_started before checking buffer enabled */
+ smp_rmb();
+
+ event = ring_buffer_lock_reserve(data->buffer, len);
+ if (!event) {
+ /* Ignore dropped events before test starts. */
+ if (started) {
+ if (nested)
+ data->bytes_dropped += len;
+ else
+ data->bytes_dropped_nested += len;
+ }
+ return len;
+ }
+
+ event_len = ring_buffer_event_length(event);
+
+ if (RB_WARN_ON(data->buffer, event_len < len))
+ goto out;
+
+ item = ring_buffer_event_data(event);
+ item->size = size;
+ memcpy(item->str, rb_string, size);
+
+ if (nested) {
+ data->bytes_alloc_nested += event_len;
+ data->bytes_written_nested += len;
+ data->events_nested++;
+ if (!data->min_size_nested || len < data->min_size_nested)
+ data->min_size_nested = len;
+ if (len > data->max_size_nested)
+ data->max_size_nested = len;
+ } else {
+ data->bytes_alloc += event_len;
+ data->bytes_written += len;
+ data->events++;
+ if (!data->min_size || len < data->min_size)
+ data->max_size = len;
+ if (len > data->max_size)
+ data->max_size = len;
+ }
+
+ out:
+ ring_buffer_unlock_commit(data->buffer, event);
+
+ return 0;
+}
+
+static __init int rb_test(void *arg)
+{
+ struct rb_test_data *data = arg;
+
+ while (!kthread_should_stop()) {
+ rb_write_something(data, false);
+ data->cnt++;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* Now sleep between a min of 100-300us and a max of 1ms */
+ usleep_range(((data->cnt % 3) + 1) * 100, 1000);
+ }
+
+ return 0;
+}
+
+static __init void rb_ipi(void *ignore)
+{
+ struct rb_test_data *data;
+ int cpu = smp_processor_id();
+
+ data = &rb_data[cpu];
+ rb_write_something(data, true);
+}
+
+static __init int rb_hammer_test(void *arg)
+{
+ while (!kthread_should_stop()) {
+
+ /* Send an IPI to all cpus to write data! */
+ smp_call_function(rb_ipi, NULL, 1);
+ /* No sleep, but for non preempt, let others run */
+ schedule();
+ }
+
+ return 0;
+}
+
+static __init int test_ringbuffer(void)
+{
+ struct task_struct *rb_hammer;
+ struct ring_buffer *buffer;
+ int cpu;
+ int ret = 0;
+
+ pr_info("Running ring buffer tests...\n");
+
+ buffer = ring_buffer_alloc(RB_TEST_BUFFER_SIZE, RB_FL_OVERWRITE);
+ if (WARN_ON(!buffer))
+ return 0;
+
+ /* Disable buffer so that threads can't write to it yet */
+ ring_buffer_record_off(buffer);
+
+ for_each_online_cpu(cpu) {
+ rb_data[cpu].buffer = buffer;
+ rb_data[cpu].cpu = cpu;
+ rb_data[cpu].cnt = cpu;
+ rb_threads[cpu] = kthread_create(rb_test, &rb_data[cpu],
+ "rbtester/%d", cpu);
+ if (WARN_ON(!rb_threads[cpu])) {
+ pr_cont("FAILED\n");
+ ret = -1;
+ goto out_free;
+ }
+
+ kthread_bind(rb_threads[cpu], cpu);
+ wake_up_process(rb_threads[cpu]);
+ }
+
+ /* Now create the rb hammer! */
+ rb_hammer = kthread_run(rb_hammer_test, NULL, "rbhammer");
+ if (WARN_ON(!rb_hammer)) {
+ pr_cont("FAILED\n");
+ ret = -1;
+ goto out_free;
+ }
+
+ ring_buffer_record_on(buffer);
+ /*
+ * Show buffer is enabled before setting rb_test_started.
+ * Yes there's a small race window where events could be
+ * dropped and the thread wont catch it. But when a ring
+ * buffer gets enabled, there will always be some kind of
+ * delay before other CPUs see it. Thus, we don't care about
+ * those dropped events. We care about events dropped after
+ * the threads see that the buffer is active.
+ */
+ smp_wmb();
+ rb_test_started = true;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* Just run for 10 seconds */;
+ schedule_timeout(10 * HZ);
+
+ kthread_stop(rb_hammer);
+
+ out_free:
+ for_each_online_cpu(cpu) {
+ if (!rb_threads[cpu])
+ break;
+ kthread_stop(rb_threads[cpu]);
+ }
+ if (ret) {
+ ring_buffer_free(buffer);
+ return ret;
+ }
+
+ /* Report! */
+ pr_info("finished\n");
+ for_each_online_cpu(cpu) {
+ struct ring_buffer_event *event;
+ struct rb_test_data *data = &rb_data[cpu];
+ struct rb_item *item;
+ unsigned long total_events;
+ unsigned long total_dropped;
+ unsigned long total_written;
+ unsigned long total_alloc;
+ unsigned long total_read = 0;
+ unsigned long total_size = 0;
+ unsigned long total_len = 0;
+ unsigned long total_lost = 0;
+ unsigned long lost;
+ int big_event_size;
+ int small_event_size;
+
+ ret = -1;
+
+ total_events = data->events + data->events_nested;
+ total_written = data->bytes_written + data->bytes_written_nested;
+ total_alloc = data->bytes_alloc + data->bytes_alloc_nested;
+ total_dropped = data->bytes_dropped + data->bytes_dropped_nested;
+
+ big_event_size = data->max_size + data->max_size_nested;
+ small_event_size = data->min_size + data->min_size_nested;
+
+ pr_info("CPU %d:\n", cpu);
+ pr_info(" events: %ld\n", total_events);
+ pr_info(" dropped bytes: %ld\n", total_dropped);
+ pr_info(" alloced bytes: %ld\n", total_alloc);
+ pr_info(" written bytes: %ld\n", total_written);
+ pr_info(" biggest event: %d\n", big_event_size);
+ pr_info(" smallest event: %d\n", small_event_size);
+
+ if (RB_WARN_ON(buffer, total_dropped))
+ break;
+
+ ret = 0;
+
+ while ((event = ring_buffer_consume(buffer, cpu, NULL, &lost))) {
+ total_lost += lost;
+ item = ring_buffer_event_data(event);
+ total_len += ring_buffer_event_length(event);
+ total_size += item->size + sizeof(struct rb_item);
+ if (memcmp(&item->str[0], rb_string, item->size) != 0) {
+ pr_info("FAILED!\n");
+ pr_info("buffer had: %.*s\n", item->size, item->str);
+ pr_info("expected: %.*s\n", item->size, rb_string);
+ RB_WARN_ON(buffer, 1);
+ ret = -1;
+ break;
+ }
+ total_read++;
+ }
+ if (ret)
+ break;
+
+ ret = -1;
+
+ pr_info(" read events: %ld\n", total_read);
+ pr_info(" lost events: %ld\n", total_lost);
+ pr_info(" total events: %ld\n", total_lost + total_read);
+ pr_info(" recorded len bytes: %ld\n", total_len);
+ pr_info(" recorded size bytes: %ld\n", total_size);
+ if (total_lost)
+ pr_info(" With dropped events, record len and size may not match\n"
+ " alloced and written from above\n");
+ if (!total_lost) {
+ if (RB_WARN_ON(buffer, total_len != total_alloc ||
+ total_size != total_written))
+ break;
+ }
+ if (RB_WARN_ON(buffer, total_lost + total_read != total_events))
+ break;
+
+ ret = 0;
+ }
+ if (!ret)
+ pr_info("Ring buffer PASSED!\n");
+
+ ring_buffer_free(buffer);
+ return 0;
+}
+
+late_initcall(test_ringbuffer);
+#endif /* CONFIG_RING_BUFFER_STARTUP_TEST */
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4f1dade56981..ae6fa2d1cdf7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1,7 +1,7 @@
/*
* ring buffer based function tracer
*
- * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ * Copyright (C) 2007-2012 Steven Rostedt <srostedt@redhat.com>
* Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
*
* Originally taken from the RT patch by:
@@ -19,7 +19,6 @@
#include <linux/seq_file.h>
#include <linux/notifier.h>
#include <linux/irqflags.h>
-#include <linux/irq_work.h>
#include <linux/debugfs.h>
#include <linux/pagemap.h>
#include <linux/hardirq.h>
@@ -48,7 +47,7 @@
* On boot up, the ring buffer is set to the minimum size, so that
* we do not waste memory on systems that are not using tracing.
*/
-int ring_buffer_expanded;
+bool ring_buffer_expanded;
/*
* We need to change this state when a selftest is running.
@@ -87,14 +86,6 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set)
static DEFINE_PER_CPU(bool, trace_cmdline_save);
/*
- * When a reader is waiting for data, then this variable is
- * set to true.
- */
-static bool trace_wakeup_needed;
-
-static struct irq_work trace_work_wakeup;
-
-/*
* Kill all tracing for good (never come back).
* It is initialized to 1 but will turn to zero if the initialization
* of the tracer is successful. But that is the only place that sets
@@ -130,12 +121,14 @@ static int tracing_set_tracer(const char *buf);
static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata;
static char *default_bootup_tracer;
+static bool allocate_snapshot;
+
static int __init set_cmdline_ftrace(char *str)
{
- strncpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
+ strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE);
default_bootup_tracer = bootup_tracer_buf;
/* We are using ftrace early, expand it */
- ring_buffer_expanded = 1;
+ ring_buffer_expanded = true;
return 1;
}
__setup("ftrace=", set_cmdline_ftrace);
@@ -156,13 +149,22 @@ static int __init set_ftrace_dump_on_oops(char *str)
}
__setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
+static int __init boot_alloc_snapshot(char *str)
+{
+ allocate_snapshot = true;
+ /* We also need the main ring buffer expanded */
+ ring_buffer_expanded = true;
+ return 1;
+}
+__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)
{
- strncpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
+ strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
trace_boot_options = trace_boot_options_buf;
return 0;
}
@@ -189,7 +191,7 @@ unsigned long long ns2usecs(cycle_t nsec)
*/
static struct trace_array global_trace;
-static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu);
+LIST_HEAD(ftrace_trace_arrays);
int filter_current_check_discard(struct ring_buffer *buffer,
struct ftrace_event_call *call, void *rec,
@@ -204,29 +206,15 @@ cycle_t ftrace_now(int cpu)
u64 ts;
/* Early boot up does not have a buffer yet */
- if (!global_trace.buffer)
+ if (!global_trace.trace_buffer.buffer)
return trace_clock_local();
- ts = ring_buffer_time_stamp(global_trace.buffer, cpu);
- ring_buffer_normalize_time_stamp(global_trace.buffer, cpu, &ts);
+ ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu);
+ ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts);
return ts;
}
-/*
- * The max_tr is used to snapshot the global_trace when a maximum
- * latency is reached. Some tracers will use this to store a maximum
- * trace while it continues examining live traces.
- *
- * The buffers for the max_tr are set up the same as the global_trace.
- * When a snapshot is taken, the link list of the max_tr is swapped
- * with the link list of the global_trace and the buffers are reset for
- * the global_trace so the tracing can continue.
- */
-static struct trace_array max_tr;
-
-static DEFINE_PER_CPU(struct trace_array_cpu, max_tr_data);
-
int tracing_is_enabled(void)
{
return tracing_is_on();
@@ -249,9 +237,6 @@ static unsigned long trace_buf_size = TRACE_BUF_SIZE_DEFAULT;
/* trace_types holds a link list of available tracers. */
static struct tracer *trace_types __read_mostly;
-/* current_trace points to the tracer that is currently active */
-static struct tracer *current_trace __read_mostly = &nop_trace;
-
/*
* trace_types_lock is used to protect the trace_types list.
*/
@@ -285,13 +270,13 @@ static DEFINE_PER_CPU(struct mutex, cpu_access_lock);
static inline void trace_access_lock(int cpu)
{
- if (cpu == TRACE_PIPE_ALL_CPU) {
+ if (cpu == RING_BUFFER_ALL_CPUS) {
/* gain it for accessing the whole ring buffer. */
down_write(&all_cpu_access_lock);
} else {
/* gain it for accessing a cpu ring buffer. */
- /* Firstly block other trace_access_lock(TRACE_PIPE_ALL_CPU). */
+ /* Firstly block other trace_access_lock(RING_BUFFER_ALL_CPUS). */
down_read(&all_cpu_access_lock);
/* Secondly block other access to this @cpu ring buffer. */
@@ -301,7 +286,7 @@ static inline void trace_access_lock(int cpu)
static inline void trace_access_unlock(int cpu)
{
- if (cpu == TRACE_PIPE_ALL_CPU) {
+ if (cpu == RING_BUFFER_ALL_CPUS) {
up_write(&all_cpu_access_lock);
} else {
mutex_unlock(&per_cpu(cpu_access_lock, cpu));
@@ -339,30 +324,11 @@ static inline void trace_access_lock_init(void)
#endif
-/* trace_wait is a waitqueue for tasks blocked on trace_poll */
-static DECLARE_WAIT_QUEUE_HEAD(trace_wait);
-
/* trace_flags holds trace_options default values */
unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME |
TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
- TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS;
-
-static int trace_stop_count;
-static DEFINE_RAW_SPINLOCK(tracing_start_lock);
-
-/**
- * trace_wake_up - wake up tasks waiting for trace input
- *
- * Schedules a delayed work to wake up any task that is blocked on the
- * trace_wait queue. These is used with trace_poll for tasks polling the
- * trace.
- */
-static void trace_wake_up(struct irq_work *work)
-{
- wake_up_all(&trace_wait);
-
-}
+ TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION;
/**
* tracing_on - enable tracing buffers
@@ -372,8 +338,8 @@ static void trace_wake_up(struct irq_work *work)
*/
void tracing_on(void)
{
- if (global_trace.buffer)
- ring_buffer_record_on(global_trace.buffer);
+ if (global_trace.trace_buffer.buffer)
+ ring_buffer_record_on(global_trace.trace_buffer.buffer);
/*
* This flag is only looked at when buffers haven't been
* allocated yet. We don't really care about the race
@@ -385,6 +351,196 @@ void tracing_on(void)
EXPORT_SYMBOL_GPL(tracing_on);
/**
+ * __trace_puts - write a constant string into the trace buffer.
+ * @ip: The address of the caller
+ * @str: The constant string to write
+ * @size: The size of the string.
+ */
+int __trace_puts(unsigned long ip, const char *str, int size)
+{
+ struct ring_buffer_event *event;
+ struct ring_buffer *buffer;
+ struct print_entry *entry;
+ unsigned long irq_flags;
+ int alloc;
+
+ alloc = sizeof(*entry) + size + 2; /* possible \n added */
+
+ local_save_flags(irq_flags);
+ buffer = global_trace.trace_buffer.buffer;
+ event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,
+ irq_flags, preempt_count());
+ if (!event)
+ return 0;
+
+ entry = ring_buffer_event_data(event);
+ entry->ip = ip;
+
+ memcpy(&entry->buf, str, size);
+
+ /* Add a newline if necessary */
+ if (entry->buf[size - 1] != '\n') {
+ entry->buf[size] = '\n';
+ entry->buf[size + 1] = '\0';
+ } else
+ entry->buf[size] = '\0';
+
+ __buffer_unlock_commit(buffer, event);
+
+ return size;
+}
+EXPORT_SYMBOL_GPL(__trace_puts);
+
+/**
+ * __trace_bputs - write the pointer to a constant string into trace buffer
+ * @ip: The address of the caller
+ * @str: The constant string to write to the buffer to
+ */
+int __trace_bputs(unsigned long ip, const char *str)
+{
+ struct ring_buffer_event *event;
+ struct ring_buffer *buffer;
+ struct bputs_entry *entry;
+ unsigned long irq_flags;
+ int size = sizeof(struct bputs_entry);
+
+ local_save_flags(irq_flags);
+ buffer = global_trace.trace_buffer.buffer;
+ event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
+ irq_flags, preempt_count());
+ if (!event)
+ return 0;
+
+ entry = ring_buffer_event_data(event);
+ entry->ip = ip;
+ entry->str = str;
+
+ __buffer_unlock_commit(buffer, event);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(__trace_bputs);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+/**
+ * trace_snapshot - take a snapshot of the current buffer.
+ *
+ * This causes a swap between the snapshot buffer and the current live
+ * tracing buffer. You can use this to take snapshots of the live
+ * trace when some condition is triggered, but continue to trace.
+ *
+ * Note, make sure to allocate the snapshot with either
+ * a tracing_snapshot_alloc(), or by doing it manually
+ * with: echo 1 > /sys/kernel/debug/tracing/snapshot
+ *
+ * If the snapshot buffer is not allocated, it will stop tracing.
+ * Basically making a permanent snapshot.
+ */
+void tracing_snapshot(void)
+{
+ struct trace_array *tr = &global_trace;
+ struct tracer *tracer = tr->current_trace;
+ unsigned long flags;
+
+ if (in_nmi()) {
+ internal_trace_puts("*** SNAPSHOT CALLED FROM NMI CONTEXT ***\n");
+ internal_trace_puts("*** snapshot is being ignored ***\n");
+ return;
+ }
+
+ if (!tr->allocated_snapshot) {
+ internal_trace_puts("*** SNAPSHOT NOT ALLOCATED ***\n");
+ internal_trace_puts("*** stopping trace here! ***\n");
+ tracing_off();
+ return;
+ }
+
+ /* Note, snapshot can not be used when the tracer uses it */
+ if (tracer->use_max_tr) {
+ internal_trace_puts("*** LATENCY TRACER ACTIVE ***\n");
+ internal_trace_puts("*** Can not use snapshot (sorry) ***\n");
+ return;
+ }
+
+ local_irq_save(flags);
+ update_max_tr(tr, current, smp_processor_id());
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(tracing_snapshot);
+
+static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
+ struct trace_buffer *size_buf, int cpu_id);
+static void set_buffer_entries(struct trace_buffer *buf, unsigned long val);
+
+static int alloc_snapshot(struct trace_array *tr)
+{
+ int ret;
+
+ if (!tr->allocated_snapshot) {
+
+ /* allocate spare buffer */
+ ret = resize_buffer_duplicate_size(&tr->max_buffer,
+ &tr->trace_buffer, RING_BUFFER_ALL_CPUS);
+ if (ret < 0)
+ return ret;
+
+ tr->allocated_snapshot = true;
+ }
+
+ return 0;
+}
+
+void free_snapshot(struct trace_array *tr)
+{
+ /*
+ * We don't free the ring buffer. instead, resize it because
+ * The max_tr ring buffer has some state (e.g. ring->clock) and
+ * we want preserve it.
+ */
+ ring_buffer_resize(tr->max_buffer.buffer, 1, RING_BUFFER_ALL_CPUS);
+ set_buffer_entries(&tr->max_buffer, 1);
+ tracing_reset_online_cpus(&tr->max_buffer);
+ tr->allocated_snapshot = false;
+}
+
+/**
+ * trace_snapshot_alloc - allocate and take a snapshot of the current buffer.
+ *
+ * This is similar to trace_snapshot(), but it will allocate the
+ * snapshot buffer if it isn't already allocated. Use this only
+ * where it is safe to sleep, as the allocation may sleep.
+ *
+ * This causes a swap between the snapshot buffer and the current live
+ * tracing buffer. You can use this to take snapshots of the live
+ * trace when some condition is triggered, but continue to trace.
+ */
+void tracing_snapshot_alloc(void)
+{
+ struct trace_array *tr = &global_trace;
+ int ret;
+
+ ret = alloc_snapshot(tr);
+ if (WARN_ON(ret < 0))
+ return;
+
+ tracing_snapshot();
+}
+EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
+#else
+void tracing_snapshot(void)
+{
+ WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used");
+}
+EXPORT_SYMBOL_GPL(tracing_snapshot);
+void tracing_snapshot_alloc(void)
+{
+ /* Give warning */
+ tracing_snapshot();
+}
+EXPORT_SYMBOL_GPL(tracing_snapshot_alloc);
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
+/**
* tracing_off - turn off tracing buffers
*
* This function stops the tracing buffers from recording data.
@@ -394,8 +550,8 @@ EXPORT_SYMBOL_GPL(tracing_on);
*/
void tracing_off(void)
{
- if (global_trace.buffer)
- ring_buffer_record_off(global_trace.buffer);
+ if (global_trace.trace_buffer.buffer)
+ ring_buffer_record_off(global_trace.trace_buffer.buffer);
/*
* This flag is only looked at when buffers haven't been
* allocated yet. We don't really care about the race
@@ -411,8 +567,8 @@ EXPORT_SYMBOL_GPL(tracing_off);
*/
int tracing_is_on(void)
{
- if (global_trace.buffer)
- return ring_buffer_record_is_on(global_trace.buffer);
+ if (global_trace.trace_buffer.buffer)
+ return ring_buffer_record_is_on(global_trace.trace_buffer.buffer);
return !global_trace.buffer_disabled;
}
EXPORT_SYMBOL_GPL(tracing_is_on);
@@ -479,6 +635,7 @@ static const char *trace_options[] = {
"disable_on_free",
"irq-info",
"markers",
+ "function-trace",
NULL
};
@@ -490,6 +647,8 @@ static struct {
{ trace_clock_local, "local", 1 },
{ trace_clock_global, "global", 1 },
{ trace_clock_counter, "counter", 0 },
+ { trace_clock_jiffies, "uptime", 1 },
+ { trace_clock, "perf", 1 },
ARCH_TRACE_CLOCKS
};
@@ -670,13 +829,14 @@ unsigned long __read_mostly tracing_max_latency;
static void
__update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
{
- struct trace_array_cpu *data = tr->data[cpu];
- struct trace_array_cpu *max_data;
+ struct trace_buffer *trace_buf = &tr->trace_buffer;
+ struct trace_buffer *max_buf = &tr->max_buffer;
+ struct trace_array_cpu *data = per_cpu_ptr(trace_buf->data, cpu);
+ struct trace_array_cpu *max_data = per_cpu_ptr(max_buf->data, cpu);
- max_tr.cpu = cpu;
- max_tr.time_start = data->preempt_timestamp;
+ max_buf->cpu = cpu;
+ max_buf->time_start = data->preempt_timestamp;
- max_data = max_tr.data[cpu];
max_data->saved_latency = tracing_max_latency;
max_data->critical_start = data->critical_start;
max_data->critical_end = data->critical_end;
@@ -706,22 +866,22 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
{
struct ring_buffer *buf;
- if (trace_stop_count)
+ if (tr->stop_count)
return;
WARN_ON_ONCE(!irqs_disabled());
- if (!current_trace->allocated_snapshot) {
+ if (!tr->allocated_snapshot) {
/* Only the nop tracer should hit this when disabling */
- WARN_ON_ONCE(current_trace != &nop_trace);
+ WARN_ON_ONCE(tr->current_trace != &nop_trace);
return;
}
arch_spin_lock(&ftrace_max_lock);
- buf = tr->buffer;
- tr->buffer = max_tr.buffer;
- max_tr.buffer = buf;
+ buf = tr->trace_buffer.buffer;
+ tr->trace_buffer.buffer = tr->max_buffer.buffer;
+ tr->max_buffer.buffer = buf;
__update_max_tr(tr, tsk, cpu);
arch_spin_unlock(&ftrace_max_lock);
@@ -740,16 +900,19 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
{
int ret;
- if (trace_stop_count)
+ if (tr->stop_count)
return;
WARN_ON_ONCE(!irqs_disabled());
- if (WARN_ON_ONCE(!current_trace->allocated_snapshot))
+ if (!tr->allocated_snapshot) {
+ /* Only the nop tracer should hit this when disabling */
+ WARN_ON_ONCE(tr->current_trace != &nop_trace);
return;
+ }
arch_spin_lock(&ftrace_max_lock);
- ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu);
+ ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu);
if (ret == -EBUSY) {
/*
@@ -758,7 +921,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
* the max trace buffer (no one writes directly to it)
* and flag that it failed.
*/
- trace_array_printk(&max_tr, _THIS_IP_,
+ trace_array_printk_buf(tr->max_buffer.buffer, _THIS_IP_,
"Failed to swap buffers due to commit in progress\n");
}
@@ -771,37 +934,78 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
static void default_wait_pipe(struct trace_iterator *iter)
{
- DEFINE_WAIT(wait);
+ /* Iterators are static, they should be filled or empty */
+ if (trace_buffer_iter(iter, iter->cpu_file))
+ return;
+
+ ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file);
+}
+
+#ifdef CONFIG_FTRACE_STARTUP_TEST
+static int run_tracer_selftest(struct tracer *type)
+{
+ struct trace_array *tr = &global_trace;
+ struct tracer *saved_tracer = tr->current_trace;
+ int ret;
- prepare_to_wait(&trace_wait, &wait, TASK_INTERRUPTIBLE);
+ if (!type->selftest || tracing_selftest_disabled)
+ return 0;
/*
- * The events can happen in critical sections where
- * checking a work queue can cause deadlocks.
- * After adding a task to the queue, this flag is set
- * only to notify events to try to wake up the queue
- * using irq_work.
- *
- * We don't clear it even if the buffer is no longer
- * empty. The flag only causes the next event to run
- * irq_work to do the work queue wake up. The worse
- * that can happen if we race with !trace_empty() is that
- * an event will cause an irq_work to try to wake up
- * an empty queue.
- *
- * There's no reason to protect this flag either, as
- * the work queue and irq_work logic will do the necessary
- * synchronization for the wake ups. The only thing
- * that is necessary is that the wake up happens after
- * a task has been queued. It's OK for spurious wake ups.
+ * Run a selftest on this tracer.
+ * Here we reset the trace buffer, and set the current
+ * tracer to be this tracer. The tracer can then run some
+ * internal tracing to verify that everything is in order.
+ * If we fail, we do not register this tracer.
*/
- trace_wakeup_needed = true;
+ tracing_reset_online_cpus(&tr->trace_buffer);
- if (trace_empty(iter))
- schedule();
+ tr->current_trace = type;
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (type->use_max_tr) {
+ /* If we expanded the buffers, make sure the max is expanded too */
+ if (ring_buffer_expanded)
+ ring_buffer_resize(tr->max_buffer.buffer, trace_buf_size,
+ RING_BUFFER_ALL_CPUS);
+ tr->allocated_snapshot = true;
+ }
+#endif
- finish_wait(&trace_wait, &wait);
+ /* the test is responsible for initializing and enabling */
+ pr_info("Testing tracer %s: ", type->name);
+ ret = type->selftest(type, tr);
+ /* the test is responsible for resetting too */
+ tr->current_trace = saved_tracer;
+ if (ret) {
+ printk(KERN_CONT "FAILED!\n");
+ /* Add the warning after printing 'FAILED' */
+ WARN_ON(1);
+ return -1;
+ }
+ /* Only reset on passing, to avoid touching corrupted buffers */
+ tracing_reset_online_cpus(&tr->trace_buffer);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (type->use_max_tr) {
+ tr->allocated_snapshot = false;
+
+ /* Shrink the max buffer again */
+ if (ring_buffer_expanded)
+ ring_buffer_resize(tr->max_buffer.buffer, 1,
+ RING_BUFFER_ALL_CPUS);
+ }
+#endif
+
+ printk(KERN_CONT "PASSED\n");
+ return 0;
}
+#else
+static inline int run_tracer_selftest(struct tracer *type)
+{
+ return 0;
+}
+#endif /* CONFIG_FTRACE_STARTUP_TEST */
/**
* register_tracer - register a tracer with the ftrace system.
@@ -848,57 +1052,9 @@ int register_tracer(struct tracer *type)
if (!type->wait_pipe)
type->wait_pipe = default_wait_pipe;
-
-#ifdef CONFIG_FTRACE_STARTUP_TEST
- if (type->selftest && !tracing_selftest_disabled) {
- struct tracer *saved_tracer = current_trace;
- struct trace_array *tr = &global_trace;
-
- /*
- * Run a selftest on this tracer.
- * Here we reset the trace buffer, and set the current
- * tracer to be this tracer. The tracer can then run some
- * internal tracing to verify that everything is in order.
- * If we fail, we do not register this tracer.
- */
- tracing_reset_online_cpus(tr);
-
- current_trace = type;
-
- if (type->use_max_tr) {
- /* If we expanded the buffers, make sure the max is expanded too */
- if (ring_buffer_expanded)
- ring_buffer_resize(max_tr.buffer, trace_buf_size,
- RING_BUFFER_ALL_CPUS);
- type->allocated_snapshot = true;
- }
-
- /* the test is responsible for initializing and enabling */
- pr_info("Testing tracer %s: ", type->name);
- ret = type->selftest(type, tr);
- /* the test is responsible for resetting too */
- current_trace = saved_tracer;
- if (ret) {
- printk(KERN_CONT "FAILED!\n");
- /* Add the warning after printing 'FAILED' */
- WARN_ON(1);
- goto out;
- }
- /* Only reset on passing, to avoid touching corrupted buffers */
- tracing_reset_online_cpus(tr);
-
- if (type->use_max_tr) {
- type->allocated_snapshot = false;
-
- /* Shrink the max buffer again */
- if (ring_buffer_expanded)
- ring_buffer_resize(max_tr.buffer, 1,
- RING_BUFFER_ALL_CPUS);
- }
-
- printk(KERN_CONT "PASSED\n");
- }
-#endif
+ ret = run_tracer_selftest(type);
+ if (ret < 0)
+ goto out;
type->next = trace_types;
trace_types = type;
@@ -918,7 +1074,7 @@ int register_tracer(struct tracer *type)
tracing_set_tracer(type->name);
default_bootup_tracer = NULL;
/* disable other selftests, since this will break it. */
- tracing_selftest_disabled = 1;
+ tracing_selftest_disabled = true;
#ifdef CONFIG_FTRACE_STARTUP_TEST
printk(KERN_INFO "Disabling FTRACE selftests due to running tracer '%s'\n",
type->name);
@@ -928,9 +1084,9 @@ int register_tracer(struct tracer *type)
return ret;
}
-void tracing_reset(struct trace_array *tr, int cpu)
+void tracing_reset(struct trace_buffer *buf, int cpu)
{
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = buf->buffer;
if (!buffer)
return;
@@ -944,9 +1100,9 @@ void tracing_reset(struct trace_array *tr, int cpu)
ring_buffer_record_enable(buffer);
}
-void tracing_reset_online_cpus(struct trace_array *tr)
+void tracing_reset_online_cpus(struct trace_buffer *buf)
{
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = buf->buffer;
int cpu;
if (!buffer)
@@ -957,7 +1113,7 @@ void tracing_reset_online_cpus(struct trace_array *tr)
/* Make sure all commits have finished */
synchronize_sched();
- tr->time_start = ftrace_now(tr->cpu);
+ buf->time_start = ftrace_now(buf->cpu);
for_each_online_cpu(cpu)
ring_buffer_reset_cpu(buffer, cpu);
@@ -967,12 +1123,21 @@ void tracing_reset_online_cpus(struct trace_array *tr)
void tracing_reset_current(int cpu)
{
- tracing_reset(&global_trace, cpu);
+ tracing_reset(&global_trace.trace_buffer, cpu);
}
-void tracing_reset_current_online_cpus(void)
+void tracing_reset_all_online_cpus(void)
{
- tracing_reset_online_cpus(&global_trace);
+ struct trace_array *tr;
+
+ mutex_lock(&trace_types_lock);
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ tracing_reset_online_cpus(&tr->trace_buffer);
+#ifdef CONFIG_TRACER_MAX_TRACE
+ tracing_reset_online_cpus(&tr->max_buffer);
+#endif
+ }
+ mutex_unlock(&trace_types_lock);
}
#define SAVED_CMDLINES 128
@@ -995,7 +1160,7 @@ static void trace_init_cmdlines(void)
int is_tracing_stopped(void)
{
- return trace_stop_count;
+ return global_trace.stop_count;
}
/**
@@ -1027,12 +1192,12 @@ void tracing_start(void)
if (tracing_disabled)
return;
- raw_spin_lock_irqsave(&tracing_start_lock, flags);
- if (--trace_stop_count) {
- if (trace_stop_count < 0) {
+ raw_spin_lock_irqsave(&global_trace.start_lock, flags);
+ if (--global_trace.stop_count) {
+ if (global_trace.stop_count < 0) {
/* Someone screwed up their debugging */
WARN_ON_ONCE(1);
- trace_stop_count = 0;
+ global_trace.stop_count = 0;
}
goto out;
}
@@ -1040,19 +1205,52 @@ void tracing_start(void)
/* Prevent the buffers from switching */
arch_spin_lock(&ftrace_max_lock);
- buffer = global_trace.buffer;
+ buffer = global_trace.trace_buffer.buffer;
if (buffer)
ring_buffer_record_enable(buffer);
- buffer = max_tr.buffer;
+#ifdef CONFIG_TRACER_MAX_TRACE
+ buffer = global_trace.max_buffer.buffer;
if (buffer)
ring_buffer_record_enable(buffer);
+#endif
arch_spin_unlock(&ftrace_max_lock);
ftrace_start();
out:
- raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
+ raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
+}
+
+static void tracing_start_tr(struct trace_array *tr)
+{
+ struct ring_buffer *buffer;
+ unsigned long flags;
+
+ if (tracing_disabled)
+ return;
+
+ /* If global, we need to also start the max tracer */
+ if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+ return tracing_start();
+
+ raw_spin_lock_irqsave(&tr->start_lock, flags);
+
+ if (--tr->stop_count) {
+ if (tr->stop_count < 0) {
+ /* Someone screwed up their debugging */
+ WARN_ON_ONCE(1);
+ tr->stop_count = 0;
+ }
+ goto out;
+ }
+
+ buffer = tr->trace_buffer.buffer;
+ if (buffer)
+ ring_buffer_record_enable(buffer);
+
+ out:
+ raw_spin_unlock_irqrestore(&tr->start_lock, flags);
}
/**
@@ -1067,25 +1265,48 @@ void tracing_stop(void)
unsigned long flags;
ftrace_stop();
- raw_spin_lock_irqsave(&tracing_start_lock, flags);
- if (trace_stop_count++)
+ raw_spin_lock_irqsave(&global_trace.start_lock, flags);
+ if (global_trace.stop_count++)
goto out;
/* Prevent the buffers from switching */
arch_spin_lock(&ftrace_max_lock);
- buffer = global_trace.buffer;
+ buffer = global_trace.trace_buffer.buffer;
if (buffer)
ring_buffer_record_disable(buffer);
- buffer = max_tr.buffer;
+#ifdef CONFIG_TRACER_MAX_TRACE
+ buffer = global_trace.max_buffer.buffer;
if (buffer)
ring_buffer_record_disable(buffer);
+#endif
arch_spin_unlock(&ftrace_max_lock);
out:
- raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
+ raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
+}
+
+static void tracing_stop_tr(struct trace_array *tr)
+{
+ struct ring_buffer *buffer;
+ unsigned long flags;
+
+ /* If global, we need to also stop the max tracer */
+ if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+ return tracing_stop();
+
+ raw_spin_lock_irqsave(&tr->start_lock, flags);
+ if (tr->stop_count++)
+ goto out;
+
+ buffer = tr->trace_buffer.buffer;
+ if (buffer)
+ ring_buffer_record_disable(buffer);
+
+ out:
+ raw_spin_unlock_irqrestore(&tr->start_lock, flags);
}
void trace_stop_cmdline_recording(void);
@@ -1218,11 +1439,6 @@ void
__buffer_unlock_commit(struct ring_buffer *buffer, struct ring_buffer_event *event)
{
__this_cpu_write(trace_cmdline_save, true);
- if (trace_wakeup_needed) {
- trace_wakeup_needed = false;
- /* irq_work_queue() supplies it's own memory barriers */
- irq_work_queue(&trace_work_wakeup);
- }
ring_buffer_unlock_commit(buffer, event);
}
@@ -1246,11 +1462,23 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
struct ring_buffer_event *
+trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
+ struct ftrace_event_file *ftrace_file,
+ int type, unsigned long len,
+ unsigned long flags, int pc)
+{
+ *current_rb = ftrace_file->tr->trace_buffer.buffer;
+ return trace_buffer_lock_reserve(*current_rb,
+ type, len, flags, pc);
+}
+EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
+
+struct ring_buffer_event *
trace_current_buffer_lock_reserve(struct ring_buffer **current_rb,
int type, unsigned long len,
unsigned long flags, int pc)
{
- *current_rb = global_trace.buffer;
+ *current_rb = global_trace.trace_buffer.buffer;
return trace_buffer_lock_reserve(*current_rb,
type, len, flags, pc);
}
@@ -1289,7 +1517,7 @@ trace_function(struct trace_array *tr,
int pc)
{
struct ftrace_event_call *call = &event_function;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ring_buffer_event *event;
struct ftrace_entry *entry;
@@ -1430,13 +1658,14 @@ void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
int pc)
{
- __ftrace_trace_stack(tr->buffer, flags, skip, pc, NULL);
+ __ftrace_trace_stack(tr->trace_buffer.buffer, flags, skip, pc, NULL);
}
/**
* trace_dump_stack - record a stack back trace in the trace buffer
+ * @skip: Number of functions to skip (helper handlers)
*/
-void trace_dump_stack(void)
+void trace_dump_stack(int skip)
{
unsigned long flags;
@@ -1445,8 +1674,13 @@ void trace_dump_stack(void)
local_save_flags(flags);
- /* skipping 3 traces, seems to get us at the caller of this function */
- __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count(), NULL);
+ /*
+ * Skip 3 more, seems to get us at the caller of
+ * this function.
+ */
+ skip += 3;
+ __ftrace_trace_stack(global_trace.trace_buffer.buffer,
+ flags, skip, preempt_count(), NULL);
}
static DEFINE_PER_CPU(int, user_stack_count);
@@ -1616,7 +1850,7 @@ void trace_printk_init_buffers(void)
* directly here. If the global_trace.buffer is already
* allocated here, then this was called by module code.
*/
- if (global_trace.buffer)
+ if (global_trace.trace_buffer.buffer)
tracing_start_cmdline_record();
}
@@ -1676,7 +1910,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
local_save_flags(flags);
size = sizeof(*entry) + sizeof(u32) * len;
- buffer = tr->buffer;
+ buffer = tr->trace_buffer.buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
flags, pc);
if (!event)
@@ -1699,27 +1933,12 @@ out:
}
EXPORT_SYMBOL_GPL(trace_vbprintk);
-int trace_array_printk(struct trace_array *tr,
- unsigned long ip, const char *fmt, ...)
-{
- int ret;
- va_list ap;
-
- if (!(trace_flags & TRACE_ITER_PRINTK))
- return 0;
-
- va_start(ap, fmt);
- ret = trace_array_vprintk(tr, ip, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-int trace_array_vprintk(struct trace_array *tr,
- unsigned long ip, const char *fmt, va_list args)
+static int
+__trace_array_vprintk(struct ring_buffer *buffer,
+ unsigned long ip, const char *fmt, va_list args)
{
struct ftrace_event_call *call = &event_print;
struct ring_buffer_event *event;
- struct ring_buffer *buffer;
int len = 0, size, pc;
struct print_entry *entry;
unsigned long flags;
@@ -1747,7 +1966,6 @@ int trace_array_vprintk(struct trace_array *tr,
local_save_flags(flags);
size = sizeof(*entry) + len + 1;
- buffer = tr->buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
flags, pc);
if (!event)
@@ -1768,6 +1986,42 @@ int trace_array_vprintk(struct trace_array *tr,
return len;
}
+int trace_array_vprintk(struct trace_array *tr,
+ unsigned long ip, const char *fmt, va_list args)
+{
+ return __trace_array_vprintk(tr->trace_buffer.buffer, ip, fmt, args);
+}
+
+int trace_array_printk(struct trace_array *tr,
+ unsigned long ip, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!(trace_flags & TRACE_ITER_PRINTK))
+ return 0;
+
+ va_start(ap, fmt);
+ ret = trace_array_vprintk(tr, ip, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int trace_array_printk_buf(struct ring_buffer *buffer,
+ unsigned long ip, const char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!(trace_flags & TRACE_ITER_PRINTK))
+ return 0;
+
+ va_start(ap, fmt);
+ ret = __trace_array_vprintk(buffer, ip, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
{
return trace_array_vprintk(&global_trace, ip, fmt, args);
@@ -1793,7 +2047,7 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
if (buf_iter)
event = ring_buffer_iter_peek(buf_iter, ts);
else
- event = ring_buffer_peek(iter->tr->buffer, cpu, ts,
+ event = ring_buffer_peek(iter->trace_buffer->buffer, cpu, ts,
lost_events);
if (event) {
@@ -1808,7 +2062,7 @@ static struct trace_entry *
__find_next_entry(struct trace_iterator *iter, int *ent_cpu,
unsigned long *missing_events, u64 *ent_ts)
{
- struct ring_buffer *buffer = iter->tr->buffer;
+ struct ring_buffer *buffer = iter->trace_buffer->buffer;
struct trace_entry *ent, *next = NULL;
unsigned long lost_events = 0, next_lost = 0;
int cpu_file = iter->cpu_file;
@@ -1821,7 +2075,7 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
* If we are in a per_cpu trace file, don't bother by iterating over
* all cpu and peek directly.
*/
- if (cpu_file > TRACE_PIPE_ALL_CPU) {
+ if (cpu_file > RING_BUFFER_ALL_CPUS) {
if (ring_buffer_empty_cpu(buffer, cpu_file))
return NULL;
ent = peek_next_entry(iter, cpu_file, ent_ts, missing_events);
@@ -1885,7 +2139,7 @@ void *trace_find_next_entry_inc(struct trace_iterator *iter)
static void trace_consume(struct trace_iterator *iter)
{
- ring_buffer_consume(iter->tr->buffer, iter->cpu, &iter->ts,
+ ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu, &iter->ts,
&iter->lost_events);
}
@@ -1918,13 +2172,12 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
void tracing_iter_reset(struct trace_iterator *iter, int cpu)
{
- struct trace_array *tr = iter->tr;
struct ring_buffer_event *event;
struct ring_buffer_iter *buf_iter;
unsigned long entries = 0;
u64 ts;
- tr->data[cpu]->skipped_entries = 0;
+ per_cpu_ptr(iter->trace_buffer->data, cpu)->skipped_entries = 0;
buf_iter = trace_buffer_iter(iter, cpu);
if (!buf_iter)
@@ -1938,13 +2191,13 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
* by the timestamp being before the start of the buffer.
*/
while ((event = ring_buffer_iter_peek(buf_iter, &ts))) {
- if (ts >= iter->tr->time_start)
+ if (ts >= iter->trace_buffer->time_start)
break;
entries++;
ring_buffer_read(buf_iter, NULL);
}
- tr->data[cpu]->skipped_entries = entries;
+ per_cpu_ptr(iter->trace_buffer->data, cpu)->skipped_entries = entries;
}
/*
@@ -1954,6 +2207,7 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
static void *s_start(struct seq_file *m, loff_t *pos)
{
struct trace_iterator *iter = m->private;
+ struct trace_array *tr = iter->tr;
int cpu_file = iter->cpu_file;
void *p = NULL;
loff_t l = 0;
@@ -1966,12 +2220,14 @@ static void *s_start(struct seq_file *m, loff_t *pos)
* will point to the same string as current_trace->name.
*/
mutex_lock(&trace_types_lock);
- if (unlikely(current_trace && iter->trace->name != current_trace->name))
- *iter->trace = *current_trace;
+ if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name))
+ *iter->trace = *tr->current_trace;
mutex_unlock(&trace_types_lock);
+#ifdef CONFIG_TRACER_MAX_TRACE
if (iter->snapshot && iter->trace->use_max_tr)
return ERR_PTR(-EBUSY);
+#endif
if (!iter->snapshot)
atomic_inc(&trace_record_cmdline_disabled);
@@ -1981,7 +2237,7 @@ static void *s_start(struct seq_file *m, loff_t *pos)
iter->cpu = 0;
iter->idx = -1;
- if (cpu_file == TRACE_PIPE_ALL_CPU) {
+ if (cpu_file == RING_BUFFER_ALL_CPUS) {
for_each_tracing_cpu(cpu)
tracing_iter_reset(iter, cpu);
} else
@@ -2013,17 +2269,21 @@ static void s_stop(struct seq_file *m, void *p)
{
struct trace_iterator *iter = m->private;
+#ifdef CONFIG_TRACER_MAX_TRACE
if (iter->snapshot && iter->trace->use_max_tr)
return;
+#endif
if (!iter->snapshot)
atomic_dec(&trace_record_cmdline_disabled);
+
trace_access_unlock(iter->cpu_file);
trace_event_read_unlock();
}
static void
-get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *entries)
+get_total_entries(struct trace_buffer *buf,
+ unsigned long *total, unsigned long *entries)
{
unsigned long count;
int cpu;
@@ -2032,19 +2292,19 @@ get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *e
*entries = 0;
for_each_tracing_cpu(cpu) {
- count = ring_buffer_entries_cpu(tr->buffer, cpu);
+ count = ring_buffer_entries_cpu(buf->buffer, cpu);
/*
* If this buffer has skipped entries, then we hold all
* entries for the trace and we need to ignore the
* ones before the time stamp.
*/
- if (tr->data[cpu]->skipped_entries) {
- count -= tr->data[cpu]->skipped_entries;
+ if (per_cpu_ptr(buf->data, cpu)->skipped_entries) {
+ count -= per_cpu_ptr(buf->data, cpu)->skipped_entries;
/* total is the same as the entries */
*total += count;
} else
*total += count +
- ring_buffer_overrun_cpu(tr->buffer, cpu);
+ ring_buffer_overrun_cpu(buf->buffer, cpu);
*entries += count;
}
}
@@ -2061,27 +2321,27 @@ static void print_lat_help_header(struct seq_file *m)
seq_puts(m, "# \\ / ||||| \\ | / \n");
}
-static void print_event_info(struct trace_array *tr, struct seq_file *m)
+static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
{
unsigned long total;
unsigned long entries;
- get_total_entries(tr, &total, &entries);
+ get_total_entries(buf, &total, &entries);
seq_printf(m, "# entries-in-buffer/entries-written: %lu/%lu #P:%d\n",
entries, total, num_online_cpus());
seq_puts(m, "#\n");
}
-static void print_func_help_header(struct trace_array *tr, struct seq_file *m)
+static void print_func_help_header(struct trace_buffer *buf, struct seq_file *m)
{
- print_event_info(tr, m);
+ print_event_info(buf, m);
seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n");
seq_puts(m, "# | | | | |\n");
}
-static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m)
+static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file *m)
{
- print_event_info(tr, m);
+ print_event_info(buf, m);
seq_puts(m, "# _-----=> irqs-off\n");
seq_puts(m, "# / _----=> need-resched\n");
seq_puts(m, "# | / _---=> hardirq/softirq\n");
@@ -2095,16 +2355,16 @@ void
print_trace_header(struct seq_file *m, struct trace_iterator *iter)
{
unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
- struct trace_array *tr = iter->tr;
- struct trace_array_cpu *data = tr->data[tr->cpu];
- struct tracer *type = current_trace;
+ struct trace_buffer *buf = iter->trace_buffer;
+ struct trace_array_cpu *data = per_cpu_ptr(buf->data, buf->cpu);
+ struct tracer *type = iter->trace;
unsigned long entries;
unsigned long total;
const char *name = "preemption";
name = type->name;
- get_total_entries(tr, &total, &entries);
+ get_total_entries(buf, &total, &entries);
seq_printf(m, "# %s latency trace v1.1.5 on %s\n",
name, UTS_RELEASE);
@@ -2115,7 +2375,7 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
nsecs_to_usecs(data->saved_latency),
entries,
total,
- tr->cpu,
+ buf->cpu,
#if defined(CONFIG_PREEMPT_NONE)
"server",
#elif defined(CONFIG_PREEMPT_VOLUNTARY)
@@ -2166,7 +2426,7 @@ static void test_cpu_buff_start(struct trace_iterator *iter)
if (cpumask_test_cpu(iter->cpu, iter->started))
return;
- if (iter->tr->data[iter->cpu]->skipped_entries)
+ if (per_cpu_ptr(iter->trace_buffer->data, iter->cpu)->skipped_entries)
return;
cpumask_set_cpu(iter->cpu, iter->started);
@@ -2289,14 +2549,14 @@ int trace_empty(struct trace_iterator *iter)
int cpu;
/* If we are looking at one CPU buffer, only check that one */
- if (iter->cpu_file != TRACE_PIPE_ALL_CPU) {
+ if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
cpu = iter->cpu_file;
buf_iter = trace_buffer_iter(iter, cpu);
if (buf_iter) {
if (!ring_buffer_iter_empty(buf_iter))
return 0;
} else {
- if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
+ if (!ring_buffer_empty_cpu(iter->trace_buffer->buffer, cpu))
return 0;
}
return 1;
@@ -2308,7 +2568,7 @@ int trace_empty(struct trace_iterator *iter)
if (!ring_buffer_iter_empty(buf_iter))
return 0;
} else {
- if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
+ if (!ring_buffer_empty_cpu(iter->trace_buffer->buffer, cpu))
return 0;
}
}
@@ -2332,6 +2592,11 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
return ret;
}
+ if (iter->ent->type == TRACE_BPUTS &&
+ trace_flags & TRACE_ITER_PRINTK &&
+ trace_flags & TRACE_ITER_PRINTK_MSGONLY)
+ return trace_print_bputs_msg_only(iter);
+
if (iter->ent->type == TRACE_BPRINT &&
trace_flags & TRACE_ITER_PRINTK &&
trace_flags & TRACE_ITER_PRINTK_MSGONLY)
@@ -2386,9 +2651,9 @@ void trace_default_header(struct seq_file *m)
} else {
if (!(trace_flags & TRACE_ITER_VERBOSE)) {
if (trace_flags & TRACE_ITER_IRQ_INFO)
- print_func_help_header_irq(iter->tr, m);
+ print_func_help_header_irq(iter->trace_buffer, m);
else
- print_func_help_header(iter->tr, m);
+ print_func_help_header(iter->trace_buffer, m);
}
}
}
@@ -2402,14 +2667,8 @@ static void test_ftrace_alive(struct seq_file *m)
}
#ifdef CONFIG_TRACER_MAX_TRACE
-static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
+static void show_snapshot_main_help(struct seq_file *m)
{
- if (iter->trace->allocated_snapshot)
- seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
- else
- seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
-
- seq_printf(m, "# Snapshot commands:\n");
seq_printf(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n");
seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
seq_printf(m, "# Takes a snapshot of the main buffer.\n");
@@ -2417,6 +2676,35 @@ static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
seq_printf(m, "# (Doesn't have to be '2' works with any number that\n");
seq_printf(m, "# is not a '0' or '1')\n");
}
+
+static void show_snapshot_percpu_help(struct seq_file *m)
+{
+ seq_printf(m, "# echo 0 > snapshot : Invalid for per_cpu snapshot file.\n");
+#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP
+ seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
+ seq_printf(m, "# Takes a snapshot of the main buffer for this cpu.\n");
+#else
+ seq_printf(m, "# echo 1 > snapshot : Not supported with this kernel.\n");
+ seq_printf(m, "# Must use main snapshot file to allocate.\n");
+#endif
+ seq_printf(m, "# echo 2 > snapshot : Clears this cpu's snapshot buffer (but does not allocate)\n");
+ seq_printf(m, "# (Doesn't have to be '2' works with any number that\n");
+ seq_printf(m, "# is not a '0' or '1')\n");
+}
+
+static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
+{
+ if (iter->tr->allocated_snapshot)
+ seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
+ else
+ seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
+
+ seq_printf(m, "# Snapshot commands:\n");
+ if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
+ show_snapshot_main_help(m);
+ else
+ show_snapshot_percpu_help(m);
+}
#else
/* Should never be called */
static inline void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter) { }
@@ -2476,7 +2764,8 @@ static const struct seq_operations tracer_seq_ops = {
static struct trace_iterator *
__tracing_open(struct inode *inode, struct file *file, bool snapshot)
{
- long cpu_file = (long) inode->i_private;
+ struct trace_cpu *tc = inode->i_private;
+ struct trace_array *tr = tc->tr;
struct trace_iterator *iter;
int cpu;
@@ -2501,26 +2790,31 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
if (!iter->trace)
goto fail;
- *iter->trace = *current_trace;
+ *iter->trace = *tr->current_trace;
if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
goto fail;
- if (current_trace->print_max || snapshot)
- iter->tr = &max_tr;
+ iter->tr = tr;
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ /* Currently only the top directory has a snapshot */
+ if (tr->current_trace->print_max || snapshot)
+ iter->trace_buffer = &tr->max_buffer;
else
- iter->tr = &global_trace;
+#endif
+ iter->trace_buffer = &tr->trace_buffer;
iter->snapshot = snapshot;
iter->pos = -1;
mutex_init(&iter->mutex);
- iter->cpu_file = cpu_file;
+ iter->cpu_file = tc->cpu;
/* Notify the tracer early; before we stop tracing. */
if (iter->trace && iter->trace->open)
iter->trace->open(iter);
/* Annotate start of buffers if we had overruns */
- if (ring_buffer_overruns(iter->tr->buffer))
+ if (ring_buffer_overruns(iter->trace_buffer->buffer))
iter->iter_flags |= TRACE_FILE_ANNOTATE;
/* Output in nanoseconds only if we are using a clock in nanoseconds. */
@@ -2529,12 +2823,12 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
/* stop the trace while dumping if we are not opening "snapshot" */
if (!iter->snapshot)
- tracing_stop();
+ tracing_stop_tr(tr);
- if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
+ if (iter->cpu_file == RING_BUFFER_ALL_CPUS) {
for_each_tracing_cpu(cpu) {
iter->buffer_iter[cpu] =
- ring_buffer_read_prepare(iter->tr->buffer, cpu);
+ ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
}
ring_buffer_read_prepare_sync();
for_each_tracing_cpu(cpu) {
@@ -2544,12 +2838,14 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
} else {
cpu = iter->cpu_file;
iter->buffer_iter[cpu] =
- ring_buffer_read_prepare(iter->tr->buffer, cpu);
+ ring_buffer_read_prepare(iter->trace_buffer->buffer, cpu);
ring_buffer_read_prepare_sync();
ring_buffer_read_start(iter->buffer_iter[cpu]);
tracing_iter_reset(iter, cpu);
}
+ tr->ref++;
+
mutex_unlock(&trace_types_lock);
return iter;
@@ -2576,14 +2872,20 @@ static int tracing_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
struct trace_iterator *iter;
+ struct trace_array *tr;
int cpu;
if (!(file->f_mode & FMODE_READ))
return 0;
iter = m->private;
+ tr = iter->tr;
mutex_lock(&trace_types_lock);
+
+ WARN_ON(!tr->ref);
+ tr->ref--;
+
for_each_tracing_cpu(cpu) {
if (iter->buffer_iter[cpu])
ring_buffer_read_finish(iter->buffer_iter[cpu]);
@@ -2594,7 +2896,7 @@ static int tracing_release(struct inode *inode, struct file *file)
if (!iter->snapshot)
/* reenable tracing if it was previously enabled */
- tracing_start();
+ tracing_start_tr(tr);
mutex_unlock(&trace_types_lock);
mutex_destroy(&iter->mutex);
@@ -2613,12 +2915,13 @@ static int tracing_open(struct inode *inode, struct file *file)
/* If this file was open for write, then erase contents */
if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC)) {
- long cpu = (long) inode->i_private;
+ struct trace_cpu *tc = inode->i_private;
+ struct trace_array *tr = tc->tr;
- if (cpu == TRACE_PIPE_ALL_CPU)
- tracing_reset_online_cpus(&global_trace);
+ if (tc->cpu == RING_BUFFER_ALL_CPUS)
+ tracing_reset_online_cpus(&tr->trace_buffer);
else
- tracing_reset(&global_trace, cpu);
+ tracing_reset(&tr->trace_buffer, tc->cpu);
}
if (file->f_mode & FMODE_READ) {
@@ -2765,8 +3068,9 @@ static ssize_t
tracing_cpumask_write(struct file *filp, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- int err, cpu;
+ struct trace_array *tr = filp->private_data;
cpumask_var_t tracing_cpumask_new;
+ int err, cpu;
if (!alloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL))
return -ENOMEM;
@@ -2786,13 +3090,13 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
*/
if (cpumask_test_cpu(cpu, tracing_cpumask) &&
!cpumask_test_cpu(cpu, tracing_cpumask_new)) {
- atomic_inc(&global_trace.data[cpu]->disabled);
- ring_buffer_record_disable_cpu(global_trace.buffer, cpu);
+ atomic_inc(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
+ ring_buffer_record_disable_cpu(tr->trace_buffer.buffer, cpu);
}
if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
cpumask_test_cpu(cpu, tracing_cpumask_new)) {
- atomic_dec(&global_trace.data[cpu]->disabled);
- ring_buffer_record_enable_cpu(global_trace.buffer, cpu);
+ atomic_dec(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
+ ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu);
}
}
arch_spin_unlock(&ftrace_max_lock);
@@ -2821,12 +3125,13 @@ static const struct file_operations tracing_cpumask_fops = {
static int tracing_trace_options_show(struct seq_file *m, void *v)
{
struct tracer_opt *trace_opts;
+ struct trace_array *tr = m->private;
u32 tracer_flags;
int i;
mutex_lock(&trace_types_lock);
- tracer_flags = current_trace->flags->val;
- trace_opts = current_trace->flags->opts;
+ tracer_flags = tr->current_trace->flags->val;
+ trace_opts = tr->current_trace->flags->opts;
for (i = 0; trace_options[i]; i++) {
if (trace_flags & (1 << i))
@@ -2890,15 +3195,15 @@ int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
return 0;
}
-int set_tracer_flag(unsigned int mask, int enabled)
+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)
return 0;
/* Give the tracer a chance to approve the change */
- if (current_trace->flag_changed)
- if (current_trace->flag_changed(current_trace, mask, !!enabled))
+ if (tr->current_trace->flag_changed)
+ if (tr->current_trace->flag_changed(tr->current_trace, mask, !!enabled))
return -EINVAL;
if (enabled)
@@ -2910,9 +3215,9 @@ int set_tracer_flag(unsigned int mask, int enabled)
trace_event_enable_cmd_record(enabled);
if (mask == TRACE_ITER_OVERWRITE) {
- ring_buffer_change_overwrite(global_trace.buffer, enabled);
+ ring_buffer_change_overwrite(tr->trace_buffer.buffer, enabled);
#ifdef CONFIG_TRACER_MAX_TRACE
- ring_buffer_change_overwrite(max_tr.buffer, enabled);
+ ring_buffer_change_overwrite(tr->max_buffer.buffer, enabled);
#endif
}
@@ -2922,7 +3227,7 @@ int set_tracer_flag(unsigned int mask, int enabled)
return 0;
}
-static int trace_set_options(char *option)
+static int trace_set_options(struct trace_array *tr, char *option)
{
char *cmp;
int neg = 0;
@@ -2940,14 +3245,14 @@ static int trace_set_options(char *option)
for (i = 0; trace_options[i]; i++) {
if (strcmp(cmp, trace_options[i]) == 0) {
- ret = set_tracer_flag(1 << i, !neg);
+ ret = set_tracer_flag(tr, 1 << i, !neg);
break;
}
}
/* If no option could be set, test the specific tracer options */
if (!trace_options[i])
- ret = set_tracer_option(current_trace, cmp, neg);
+ ret = set_tracer_option(tr->current_trace, cmp, neg);
mutex_unlock(&trace_types_lock);
@@ -2958,6 +3263,8 @@ static ssize_t
tracing_trace_options_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;
char buf[64];
int ret;
@@ -2969,7 +3276,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
buf[cnt] = 0;
- ret = trace_set_options(buf);
+ ret = trace_set_options(tr, buf);
if (ret < 0)
return ret;
@@ -2982,7 +3289,8 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)
{
if (tracing_disabled)
return -ENODEV;
- return single_open(file, tracing_trace_options_show, NULL);
+
+ return single_open(file, tracing_trace_options_show, inode->i_private);
}
static const struct file_operations tracing_iter_fops = {
@@ -2995,20 +3303,84 @@ static const struct file_operations tracing_iter_fops = {
static const char readme_msg[] =
"tracing mini-HOWTO:\n\n"
- "# mount -t debugfs nodev /sys/kernel/debug\n\n"
- "# cat /sys/kernel/debug/tracing/available_tracers\n"
- "wakeup wakeup_rt preemptirqsoff preemptoff irqsoff function nop\n\n"
- "# cat /sys/kernel/debug/tracing/current_tracer\n"
- "nop\n"
- "# echo wakeup > /sys/kernel/debug/tracing/current_tracer\n"
- "# cat /sys/kernel/debug/tracing/current_tracer\n"
- "wakeup\n"
- "# cat /sys/kernel/debug/tracing/trace_options\n"
- "noprint-parent nosym-offset nosym-addr noverbose\n"
- "# echo print-parent > /sys/kernel/debug/tracing/trace_options\n"
- "# echo 1 > /sys/kernel/debug/tracing/tracing_on\n"
- "# cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt\n"
- "# echo 0 > /sys/kernel/debug/tracing/tracing_on\n"
+ "# echo 0 > tracing_on : quick way to disable tracing\n"
+ "# echo 1 > tracing_on : quick way to re-enable tracing\n\n"
+ " Important files:\n"
+ " trace\t\t\t- The static contents of the buffer\n"
+ "\t\t\t To clear the buffer write into this file: echo > trace\n"
+ " trace_pipe\t\t- A consuming read to see the contents of the buffer\n"
+ " current_tracer\t- function and latency tracers\n"
+ " available_tracers\t- list of configured tracers for current_tracer\n"
+ " buffer_size_kb\t- view and modify size of per cpu buffer\n"
+ " buffer_total_size_kb - view total size of all cpu buffers\n\n"
+ " trace_clock\t\t-change the clock used to order events\n"
+ " local: Per cpu clock but may not be synced across CPUs\n"
+ " global: Synced across CPUs but slows tracing down.\n"
+ " counter: Not a clock, but just an increment\n"
+ " uptime: Jiffy counter from time of boot\n"
+ " perf: Same clock that perf events use\n"
+#ifdef CONFIG_X86_64
+ " x86-tsc: TSC cycle counter\n"
+#endif
+ "\n trace_marker\t\t- Writes into this file writes into the kernel buffer\n"
+ " tracing_cpumask\t- Limit which CPUs to trace\n"
+ " instances\t\t- Make sub-buffers with: mkdir instances/foo\n"
+ "\t\t\t Remove sub-buffer with rmdir\n"
+ " trace_options\t\t- Set format or modify how tracing happens\n"
+ "\t\t\t Disable an option by adding a suffix 'no' to the option name\n"
+#ifdef CONFIG_DYNAMIC_FTRACE
+ "\n available_filter_functions - list of functions that can be filtered on\n"
+ " set_ftrace_filter\t- echo function name in here to only trace these functions\n"
+ " accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+ " modules: Can select a group via module\n"
+ " Format: :mod:<module-name>\n"
+ " example: echo :mod:ext3 > set_ftrace_filter\n"
+ " triggers: a command to perform when function is hit\n"
+ " Format: <function>:<trigger>[:count]\n"
+ " trigger: traceon, traceoff\n"
+ " enable_event:<system>:<event>\n"
+ " disable_event:<system>:<event>\n"
+#ifdef CONFIG_STACKTRACE
+ " stacktrace\n"
+#endif
+#ifdef CONFIG_TRACER_SNAPSHOT
+ " snapshot\n"
+#endif
+ " example: echo do_fault:traceoff > set_ftrace_filter\n"
+ " echo do_trap:traceoff:3 > set_ftrace_filter\n"
+ " The first one will disable tracing every time do_fault is hit\n"
+ " The second will disable tracing at most 3 times when do_trap is hit\n"
+ " The first time do trap is hit and it disables tracing, the counter\n"
+ " will decrement to 2. If tracing is already disabled, the counter\n"
+ " will not decrement. It only decrements when the trigger did work\n"
+ " To remove trigger without count:\n"
+ " echo '!<function>:<trigger> > set_ftrace_filter\n"
+ " To remove trigger with a count:\n"
+ " echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
+ " set_ftrace_notrace\t- echo function name in here to never trace.\n"
+ " accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+ " modules: Can select a group via module command :mod:\n"
+ " Does not accept triggers\n"
+#endif /* CONFIG_DYNAMIC_FTRACE */
+#ifdef CONFIG_FUNCTION_TRACER
+ " set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n"
+#endif
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ " set_graph_function\t- Trace the nested calls of a function (function_graph)\n"
+ " max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n"
+#endif
+#ifdef CONFIG_TRACER_SNAPSHOT
+ "\n snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
+ "\t\t\t Read the contents for more information\n"
+#endif
+#ifdef CONFIG_STACKTRACE
+ " stack_trace\t\t- Shows the max stack trace when active\n"
+ " stack_max_size\t- Shows current max stack size that was traced\n"
+ "\t\t\t Write into this file to reset the max size (trigger a new trace)\n"
+#ifdef CONFIG_DYNAMIC_FTRACE
+ " stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
+#endif
+#endif /* CONFIG_STACKTRACE */
;
static ssize_t
@@ -3080,11 +3452,12 @@ static ssize_t
tracing_set_trace_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
+ struct trace_array *tr = filp->private_data;
char buf[MAX_TRACER_SIZE+2];
int r;
mutex_lock(&trace_types_lock);
- r = sprintf(buf, "%s\n", current_trace->name);
+ r = sprintf(buf, "%s\n", tr->current_trace->name);
mutex_unlock(&trace_types_lock);
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
@@ -3092,43 +3465,48 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
int tracer_init(struct tracer *t, struct trace_array *tr)
{
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
return t->init(tr);
}
-static void set_buffer_entries(struct trace_array *tr, unsigned long val)
+static void set_buffer_entries(struct trace_buffer *buf, unsigned long val)
{
int cpu;
+
for_each_tracing_cpu(cpu)
- tr->data[cpu]->entries = val;
+ per_cpu_ptr(buf->data, cpu)->entries = val;
}
+#ifdef CONFIG_TRACER_MAX_TRACE
/* resize @tr's buffer to the size of @size_tr's entries */
-static int resize_buffer_duplicate_size(struct trace_array *tr,
- struct trace_array *size_tr, int cpu_id)
+static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
+ struct trace_buffer *size_buf, int cpu_id)
{
int cpu, ret = 0;
if (cpu_id == RING_BUFFER_ALL_CPUS) {
for_each_tracing_cpu(cpu) {
- ret = ring_buffer_resize(tr->buffer,
- size_tr->data[cpu]->entries, cpu);
+ ret = ring_buffer_resize(trace_buf->buffer,
+ per_cpu_ptr(size_buf->data, cpu)->entries, cpu);
if (ret < 0)
break;
- tr->data[cpu]->entries = size_tr->data[cpu]->entries;
+ per_cpu_ptr(trace_buf->data, cpu)->entries =
+ per_cpu_ptr(size_buf->data, cpu)->entries;
}
} else {
- ret = ring_buffer_resize(tr->buffer,
- size_tr->data[cpu_id]->entries, cpu_id);
+ ret = ring_buffer_resize(trace_buf->buffer,
+ per_cpu_ptr(size_buf->data, cpu_id)->entries, cpu_id);
if (ret == 0)
- tr->data[cpu_id]->entries =
- size_tr->data[cpu_id]->entries;
+ per_cpu_ptr(trace_buf->data, cpu_id)->entries =
+ per_cpu_ptr(size_buf->data, cpu_id)->entries;
}
return ret;
}
+#endif /* CONFIG_TRACER_MAX_TRACE */
-static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
+static int __tracing_resize_ring_buffer(struct trace_array *tr,
+ unsigned long size, int cpu)
{
int ret;
@@ -3137,23 +3515,25 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
* we use the size that was given, and we can forget about
* expanding it later.
*/
- ring_buffer_expanded = 1;
+ ring_buffer_expanded = true;
/* May be called before buffers are initialized */
- if (!global_trace.buffer)
+ if (!tr->trace_buffer.buffer)
return 0;
- ret = ring_buffer_resize(global_trace.buffer, size, cpu);
+ ret = ring_buffer_resize(tr->trace_buffer.buffer, size, cpu);
if (ret < 0)
return ret;
- if (!current_trace->use_max_tr)
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL) ||
+ !tr->current_trace->use_max_tr)
goto out;
- ret = ring_buffer_resize(max_tr.buffer, size, cpu);
+ ret = ring_buffer_resize(tr->max_buffer.buffer, size, cpu);
if (ret < 0) {
- int r = resize_buffer_duplicate_size(&global_trace,
- &global_trace, cpu);
+ int r = resize_buffer_duplicate_size(&tr->trace_buffer,
+ &tr->trace_buffer, cpu);
if (r < 0) {
/*
* AARGH! We are left with different
@@ -3176,20 +3556,23 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
}
if (cpu == RING_BUFFER_ALL_CPUS)
- set_buffer_entries(&max_tr, size);
+ set_buffer_entries(&tr->max_buffer, size);
else
- max_tr.data[cpu]->entries = size;
+ per_cpu_ptr(tr->max_buffer.data, cpu)->entries = size;
out:
+#endif /* CONFIG_TRACER_MAX_TRACE */
+
if (cpu == RING_BUFFER_ALL_CPUS)
- set_buffer_entries(&global_trace, size);
+ set_buffer_entries(&tr->trace_buffer, size);
else
- global_trace.data[cpu]->entries = size;
+ per_cpu_ptr(tr->trace_buffer.data, cpu)->entries = size;
return ret;
}
-static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
+static ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
+ unsigned long size, int cpu_id)
{
int ret = size;
@@ -3203,7 +3586,7 @@ static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
}
}
- ret = __tracing_resize_ring_buffer(size, cpu_id);
+ ret = __tracing_resize_ring_buffer(tr, size, cpu_id);
if (ret < 0)
ret = -ENOMEM;
@@ -3230,7 +3613,7 @@ int tracing_update_buffers(void)
mutex_lock(&trace_types_lock);
if (!ring_buffer_expanded)
- ret = __tracing_resize_ring_buffer(trace_buf_size,
+ ret = __tracing_resize_ring_buffer(&global_trace, trace_buf_size,
RING_BUFFER_ALL_CPUS);
mutex_unlock(&trace_types_lock);
@@ -3240,7 +3623,7 @@ int tracing_update_buffers(void)
struct trace_option_dentry;
static struct trace_option_dentry *
-create_trace_option_files(struct tracer *tracer);
+create_trace_option_files(struct trace_array *tr, struct tracer *tracer);
static void
destroy_trace_option_files(struct trace_option_dentry *topts);
@@ -3250,13 +3633,15 @@ static int tracing_set_tracer(const char *buf)
static struct trace_option_dentry *topts;
struct trace_array *tr = &global_trace;
struct tracer *t;
+#ifdef CONFIG_TRACER_MAX_TRACE
bool had_max_tr;
+#endif
int ret = 0;
mutex_lock(&trace_types_lock);
if (!ring_buffer_expanded) {
- ret = __tracing_resize_ring_buffer(trace_buf_size,
+ ret = __tracing_resize_ring_buffer(tr, trace_buf_size,
RING_BUFFER_ALL_CPUS);
if (ret < 0)
goto out;
@@ -3271,18 +3656,21 @@ static int tracing_set_tracer(const char *buf)
ret = -EINVAL;
goto out;
}
- if (t == current_trace)
+ if (t == tr->current_trace)
goto out;
trace_branch_disable();
- current_trace->enabled = false;
+ tr->current_trace->enabled = false;
+
+ if (tr->current_trace->reset)
+ tr->current_trace->reset(tr);
- if (current_trace->reset)
- current_trace->reset(tr);
+ /* Current trace needs to be nop_trace before synchronize_sched */
+ tr->current_trace = &nop_trace;
- had_max_tr = current_trace->allocated_snapshot;
- current_trace = &nop_trace;
+#ifdef CONFIG_TRACER_MAX_TRACE
+ had_max_tr = tr->allocated_snapshot;
if (had_max_tr && !t->use_max_tr) {
/*
@@ -3293,27 +3681,20 @@ static int tracing_set_tracer(const char *buf)
* so a synchronized_sched() is sufficient.
*/
synchronize_sched();
- /*
- * We don't free the ring buffer. instead, resize it because
- * The max_tr ring buffer has some state (e.g. ring->clock) and
- * we want preserve it.
- */
- ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
- set_buffer_entries(&max_tr, 1);
- tracing_reset_online_cpus(&max_tr);
- current_trace->allocated_snapshot = false;
+ free_snapshot(tr);
}
+#endif
destroy_trace_option_files(topts);
- topts = create_trace_option_files(t);
+ topts = create_trace_option_files(tr, t);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
if (t->use_max_tr && !had_max_tr) {
- /* we need to make per cpu buffer sizes equivalent */
- ret = resize_buffer_duplicate_size(&max_tr, &global_trace,
- RING_BUFFER_ALL_CPUS);
+ ret = alloc_snapshot(tr);
if (ret < 0)
goto out;
- t->allocated_snapshot = true;
}
+#endif
if (t->init) {
ret = tracer_init(t, tr);
@@ -3321,8 +3702,8 @@ static int tracing_set_tracer(const char *buf)
goto out;
}
- current_trace = t;
- current_trace->enabled = true;
+ tr->current_trace = t;
+ tr->current_trace->enabled = true;
trace_branch_enable(tr);
out:
mutex_unlock(&trace_types_lock);
@@ -3396,7 +3777,8 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
static int tracing_open_pipe(struct inode *inode, struct file *filp)
{
- long cpu_file = (long) inode->i_private;
+ struct trace_cpu *tc = inode->i_private;
+ struct trace_array *tr = tc->tr;
struct trace_iterator *iter;
int ret = 0;
@@ -3421,7 +3803,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
ret = -ENOMEM;
goto fail;
}
- *iter->trace = *current_trace;
+ *iter->trace = *tr->current_trace;
if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
ret = -ENOMEM;
@@ -3438,8 +3820,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
if (trace_clocks[trace_clock_id].in_ns)
iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
- iter->cpu_file = cpu_file;
- iter->tr = &global_trace;
+ iter->cpu_file = tc->cpu;
+ iter->tr = tc->tr;
+ iter->trace_buffer = &tc->tr->trace_buffer;
mutex_init(&iter->mutex);
filp->private_data = iter;
@@ -3478,24 +3861,28 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
}
static unsigned int
-tracing_poll_pipe(struct file *filp, poll_table *poll_table)
+trace_poll(struct trace_iterator *iter, struct file *filp, poll_table *poll_table)
{
- struct trace_iterator *iter = filp->private_data;
+ /* 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 (trace_flags & TRACE_ITER_BLOCK)
/*
* Always select as readable when in blocking mode
*/
return POLLIN | POLLRDNORM;
- } else {
- if (!trace_empty(iter))
- return POLLIN | POLLRDNORM;
- poll_wait(filp, &trace_wait, poll_table);
- if (!trace_empty(iter))
- return POLLIN | POLLRDNORM;
+ else
+ return ring_buffer_poll_wait(iter->trace_buffer->buffer, iter->cpu_file,
+ filp, poll_table);
+}
- return 0;
- }
+static unsigned int
+tracing_poll_pipe(struct file *filp, poll_table *poll_table)
+{
+ struct trace_iterator *iter = filp->private_data;
+
+ return trace_poll(iter, filp, poll_table);
}
/*
@@ -3561,6 +3948,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct trace_iterator *iter = filp->private_data;
+ struct trace_array *tr = iter->tr;
ssize_t sret;
/* return any leftover data */
@@ -3572,8 +3960,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
/* copy the tracer to avoid using a global lock all around */
mutex_lock(&trace_types_lock);
- if (unlikely(iter->trace->name != current_trace->name))
- *iter->trace = *current_trace;
+ if (unlikely(iter->trace->name != tr->current_trace->name))
+ *iter->trace = *tr->current_trace;
mutex_unlock(&trace_types_lock);
/*
@@ -3729,6 +4117,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
.ops = &tracing_pipe_buf_ops,
.spd_release = tracing_spd_release_pipe,
};
+ struct trace_array *tr = iter->tr;
ssize_t ret;
size_t rem;
unsigned int i;
@@ -3738,8 +4127,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
/* copy the tracer to avoid using a global lock all around */
mutex_lock(&trace_types_lock);
- if (unlikely(iter->trace->name != current_trace->name))
- *iter->trace = *current_trace;
+ if (unlikely(iter->trace->name != tr->current_trace->name))
+ *iter->trace = *tr->current_trace;
mutex_unlock(&trace_types_lock);
mutex_lock(&iter->mutex);
@@ -3801,43 +4190,19 @@ out_err:
goto out;
}
-struct ftrace_entries_info {
- struct trace_array *tr;
- int cpu;
-};
-
-static int tracing_entries_open(struct inode *inode, struct file *filp)
-{
- struct ftrace_entries_info *info;
-
- if (tracing_disabled)
- return -ENODEV;
-
- info = kzalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info->tr = &global_trace;
- info->cpu = (unsigned long)inode->i_private;
-
- filp->private_data = info;
-
- return 0;
-}
-
static ssize_t
tracing_entries_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
- struct ftrace_entries_info *info = filp->private_data;
- struct trace_array *tr = info->tr;
+ struct trace_cpu *tc = filp->private_data;
+ struct trace_array *tr = tc->tr;
char buf[64];
int r = 0;
ssize_t ret;
mutex_lock(&trace_types_lock);
- if (info->cpu == RING_BUFFER_ALL_CPUS) {
+ if (tc->cpu == RING_BUFFER_ALL_CPUS) {
int cpu, buf_size_same;
unsigned long size;
@@ -3847,8 +4212,8 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
for_each_tracing_cpu(cpu) {
/* fill in the size from first enabled cpu */
if (size == 0)
- size = tr->data[cpu]->entries;
- if (size != tr->data[cpu]->entries) {
+ size = per_cpu_ptr(tr->trace_buffer.data, cpu)->entries;
+ if (size != per_cpu_ptr(tr->trace_buffer.data, cpu)->entries) {
buf_size_same = 0;
break;
}
@@ -3864,7 +4229,7 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
} else
r = sprintf(buf, "X\n");
} else
- r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
+ r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->trace_buffer.data, tc->cpu)->entries >> 10);
mutex_unlock(&trace_types_lock);
@@ -3876,7 +4241,7 @@ static ssize_t
tracing_entries_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
- struct ftrace_entries_info *info = filp->private_data;
+ struct trace_cpu *tc = filp->private_data;
unsigned long val;
int ret;
@@ -3891,7 +4256,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
/* value is in KB */
val <<= 10;
- ret = tracing_resize_ring_buffer(val, info->cpu);
+ ret = tracing_resize_ring_buffer(tc->tr, val, tc->cpu);
if (ret < 0)
return ret;
@@ -3900,16 +4265,6 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
return cnt;
}
-static int
-tracing_entries_release(struct inode *inode, struct file *filp)
-{
- struct ftrace_entries_info *info = filp->private_data;
-
- kfree(info);
-
- return 0;
-}
-
static ssize_t
tracing_total_entries_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -3921,7 +4276,7 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
mutex_lock(&trace_types_lock);
for_each_tracing_cpu(cpu) {
- size += tr->data[cpu]->entries >> 10;
+ size += per_cpu_ptr(tr->trace_buffer.data, cpu)->entries >> 10;
if (!ring_buffer_expanded)
expanded_size += trace_buf_size >> 10;
}
@@ -3951,11 +4306,13 @@ tracing_free_buffer_write(struct file *filp, const char __user *ubuf,
static int
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)
tracing_off();
/* resize the ring buffer to 0 */
- tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
+ tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
return 0;
}
@@ -4024,7 +4381,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
local_save_flags(irq_flags);
size = sizeof(*entry) + cnt + 2; /* possible \n added */
- buffer = global_trace.buffer;
+ buffer = global_trace.trace_buffer.buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
irq_flags, preempt_count());
if (!event) {
@@ -4066,13 +4423,14 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
static int tracing_clock_show(struct seq_file *m, void *v)
{
+ struct trace_array *tr = m->private;
int i;
for (i = 0; i < ARRAY_SIZE(trace_clocks); i++)
seq_printf(m,
"%s%s%s%s", i ? " " : "",
- i == trace_clock_id ? "[" : "", trace_clocks[i].name,
- i == trace_clock_id ? "]" : "");
+ i == tr->clock_id ? "[" : "", trace_clocks[i].name,
+ i == tr->clock_id ? "]" : "");
seq_putc(m, '\n');
return 0;
@@ -4081,6 +4439,8 @@ static int tracing_clock_show(struct seq_file *m, void *v)
static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *fpos)
{
+ struct seq_file *m = filp->private_data;
+ struct trace_array *tr = m->private;
char buf[64];
const char *clockstr;
int i;
@@ -4102,20 +4462,23 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
if (i == ARRAY_SIZE(trace_clocks))
return -EINVAL;
- trace_clock_id = i;
-
mutex_lock(&trace_types_lock);
- ring_buffer_set_clock(global_trace.buffer, trace_clocks[i].func);
- if (max_tr.buffer)
- ring_buffer_set_clock(max_tr.buffer, trace_clocks[i].func);
+ tr->clock_id = i;
+
+ ring_buffer_set_clock(tr->trace_buffer.buffer, trace_clocks[i].func);
/*
* New clock may not be consistent with the previous clock.
* Reset the buffer so that it doesn't have incomparable timestamps.
*/
- tracing_reset_online_cpus(&global_trace);
- tracing_reset_online_cpus(&max_tr);
+ tracing_reset_online_cpus(&global_trace.trace_buffer);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
+ ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
+ tracing_reset_online_cpus(&global_trace.max_buffer);
+#endif
mutex_unlock(&trace_types_lock);
@@ -4128,20 +4491,45 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
{
if (tracing_disabled)
return -ENODEV;
- return single_open(file, tracing_clock_show, NULL);
+
+ return single_open(file, tracing_clock_show, inode->i_private);
}
+struct ftrace_buffer_info {
+ struct trace_iterator iter;
+ void *spare;
+ unsigned int read;
+};
+
#ifdef CONFIG_TRACER_SNAPSHOT
static int tracing_snapshot_open(struct inode *inode, struct file *file)
{
+ struct trace_cpu *tc = inode->i_private;
struct trace_iterator *iter;
+ struct seq_file *m;
int ret = 0;
if (file->f_mode & FMODE_READ) {
iter = __tracing_open(inode, file, true);
if (IS_ERR(iter))
ret = PTR_ERR(iter);
+ } else {
+ /* Writes still need the seq_file to hold the private data */
+ m = kzalloc(sizeof(*m), GFP_KERNEL);
+ if (!m)
+ return -ENOMEM;
+ iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+ if (!iter) {
+ kfree(m);
+ return -ENOMEM;
+ }
+ iter->tr = tc->tr;
+ iter->trace_buffer = &tc->tr->max_buffer;
+ iter->cpu_file = tc->cpu;
+ m->private = iter;
+ file->private_data = m;
}
+
return ret;
}
@@ -4149,6 +4537,9 @@ static ssize_t
tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
+ struct seq_file *m = filp->private_data;
+ struct trace_iterator *iter = m->private;
+ struct trace_array *tr = iter->tr;
unsigned long val;
int ret;
@@ -4162,40 +4553,48 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
mutex_lock(&trace_types_lock);
- if (current_trace->use_max_tr) {
+ if (tr->current_trace->use_max_tr) {
ret = -EBUSY;
goto out;
}
switch (val) {
case 0:
- if (current_trace->allocated_snapshot) {
- /* free spare buffer */
- ring_buffer_resize(max_tr.buffer, 1,
- RING_BUFFER_ALL_CPUS);
- set_buffer_entries(&max_tr, 1);
- tracing_reset_online_cpus(&max_tr);
- current_trace->allocated_snapshot = false;
+ if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
+ ret = -EINVAL;
+ break;
}
+ if (tr->allocated_snapshot)
+ free_snapshot(tr);
break;
case 1:
- if (!current_trace->allocated_snapshot) {
- /* allocate spare buffer */
- ret = resize_buffer_duplicate_size(&max_tr,
- &global_trace, RING_BUFFER_ALL_CPUS);
+/* Only allow per-cpu swap if the ring buffer supports it */
+#ifndef CONFIG_RING_BUFFER_ALLOW_SWAP
+ if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
+ ret = -EINVAL;
+ break;
+ }
+#endif
+ if (!tr->allocated_snapshot) {
+ ret = alloc_snapshot(tr);
if (ret < 0)
break;
- current_trace->allocated_snapshot = true;
}
-
local_irq_disable();
/* Now, we're going to swap */
- update_max_tr(&global_trace, current, smp_processor_id());
+ if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
+ update_max_tr(tr, current, smp_processor_id());
+ else
+ update_max_tr_single(tr, current, iter->cpu_file);
local_irq_enable();
break;
default:
- if (current_trace->allocated_snapshot)
- tracing_reset_online_cpus(&max_tr);
+ if (tr->allocated_snapshot) {
+ if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
+ tracing_reset_online_cpus(&tr->max_buffer);
+ else
+ tracing_reset(&tr->max_buffer, iter->cpu_file);
+ }
break;
}
@@ -4207,6 +4606,51 @@ out:
mutex_unlock(&trace_types_lock);
return ret;
}
+
+static int tracing_snapshot_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+
+ if (file->f_mode & FMODE_READ)
+ return tracing_release(inode, file);
+
+ /* If write only, the seq_file is just a stub */
+ if (m)
+ kfree(m->private);
+ kfree(m);
+
+ return 0;
+}
+
+static int tracing_buffers_open(struct inode *inode, struct file *filp);
+static ssize_t tracing_buffers_read(struct file *filp, char __user *ubuf,
+ size_t count, loff_t *ppos);
+static int tracing_buffers_release(struct inode *inode, struct file *file);
+static ssize_t tracing_buffers_splice_read(struct file *file, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len, unsigned int flags);
+
+static int snapshot_raw_open(struct inode *inode, struct file *filp)
+{
+ struct ftrace_buffer_info *info;
+ int ret;
+
+ ret = tracing_buffers_open(inode, filp);
+ if (ret < 0)
+ return ret;
+
+ info = filp->private_data;
+
+ if (info->iter.trace->use_max_tr) {
+ tracing_buffers_release(inode, filp);
+ return -EBUSY;
+ }
+
+ info->iter.snapshot = true;
+ info->iter.trace_buffer = &info->iter.tr->max_buffer;
+
+ return ret;
+}
+
#endif /* CONFIG_TRACER_SNAPSHOT */
@@ -4234,10 +4678,9 @@ static const struct file_operations tracing_pipe_fops = {
};
static const struct file_operations tracing_entries_fops = {
- .open = tracing_entries_open,
+ .open = tracing_open_generic,
.read = tracing_entries_read,
.write = tracing_entries_write,
- .release = tracing_entries_release,
.llseek = generic_file_llseek,
};
@@ -4272,20 +4715,23 @@ static const struct file_operations snapshot_fops = {
.read = seq_read,
.write = tracing_snapshot_write,
.llseek = tracing_seek,
- .release = tracing_release,
+ .release = tracing_snapshot_release,
};
-#endif /* CONFIG_TRACER_SNAPSHOT */
-struct ftrace_buffer_info {
- struct trace_array *tr;
- void *spare;
- int cpu;
- unsigned int read;
+static const struct file_operations snapshot_raw_fops = {
+ .open = snapshot_raw_open,
+ .read = tracing_buffers_read,
+ .release = tracing_buffers_release,
+ .splice_read = tracing_buffers_splice_read,
+ .llseek = no_llseek,
};
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
static int tracing_buffers_open(struct inode *inode, struct file *filp)
{
- int cpu = (int)(long)inode->i_private;
+ struct trace_cpu *tc = inode->i_private;
+ struct trace_array *tr = tc->tr;
struct ftrace_buffer_info *info;
if (tracing_disabled)
@@ -4295,72 +4741,131 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
if (!info)
return -ENOMEM;
- info->tr = &global_trace;
- info->cpu = cpu;
- info->spare = NULL;
+ mutex_lock(&trace_types_lock);
+
+ tr->ref++;
+
+ info->iter.tr = tr;
+ info->iter.cpu_file = tc->cpu;
+ info->iter.trace = tr->current_trace;
+ info->iter.trace_buffer = &tr->trace_buffer;
+ info->spare = NULL;
/* Force reading ring buffer for first read */
- info->read = (unsigned int)-1;
+ info->read = (unsigned int)-1;
filp->private_data = info;
+ mutex_unlock(&trace_types_lock);
+
return nonseekable_open(inode, filp);
}
+static unsigned int
+tracing_buffers_poll(struct file *filp, poll_table *poll_table)
+{
+ struct ftrace_buffer_info *info = filp->private_data;
+ struct trace_iterator *iter = &info->iter;
+
+ return trace_poll(iter, filp, poll_table);
+}
+
static ssize_t
tracing_buffers_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct ftrace_buffer_info *info = filp->private_data;
+ struct trace_iterator *iter = &info->iter;
ssize_t ret;
- size_t size;
+ ssize_t size;
if (!count)
return 0;
+ mutex_lock(&trace_types_lock);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (iter->snapshot && iter->tr->current_trace->use_max_tr) {
+ size = -EBUSY;
+ goto out_unlock;
+ }
+#endif
+
if (!info->spare)
- info->spare = ring_buffer_alloc_read_page(info->tr->buffer, info->cpu);
+ info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer,
+ iter->cpu_file);
+ size = -ENOMEM;
if (!info->spare)
- return -ENOMEM;
+ goto out_unlock;
/* Do we have previous read data to read? */
if (info->read < PAGE_SIZE)
goto read;
- trace_access_lock(info->cpu);
- ret = ring_buffer_read_page(info->tr->buffer,
+ again:
+ trace_access_lock(iter->cpu_file);
+ ret = ring_buffer_read_page(iter->trace_buffer->buffer,
&info->spare,
count,
- info->cpu, 0);
- trace_access_unlock(info->cpu);
- if (ret < 0)
- return 0;
+ iter->cpu_file, 0);
+ trace_access_unlock(iter->cpu_file);
- info->read = 0;
+ if (ret < 0) {
+ if (trace_empty(iter)) {
+ if ((filp->f_flags & O_NONBLOCK)) {
+ size = -EAGAIN;
+ goto out_unlock;
+ }
+ mutex_unlock(&trace_types_lock);
+ iter->trace->wait_pipe(iter);
+ mutex_lock(&trace_types_lock);
+ if (signal_pending(current)) {
+ size = -EINTR;
+ goto out_unlock;
+ }
+ goto again;
+ }
+ size = 0;
+ goto out_unlock;
+ }
-read:
+ info->read = 0;
+ read:
size = PAGE_SIZE - info->read;
if (size > count)
size = count;
ret = copy_to_user(ubuf, info->spare + info->read, size);
- if (ret == size)
- return -EFAULT;
+ if (ret == size) {
+ size = -EFAULT;
+ goto out_unlock;
+ }
size -= ret;
*ppos += size;
info->read += size;
+ out_unlock:
+ mutex_unlock(&trace_types_lock);
+
return size;
}
static int tracing_buffers_release(struct inode *inode, struct file *file)
{
struct ftrace_buffer_info *info = file->private_data;
+ struct trace_iterator *iter = &info->iter;
+
+ mutex_lock(&trace_types_lock);
+
+ WARN_ON(!iter->tr->ref);
+ iter->tr->ref--;
if (info->spare)
- ring_buffer_free_read_page(info->tr->buffer, info->spare);
+ ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare);
kfree(info);
+ mutex_unlock(&trace_types_lock);
+
return 0;
}
@@ -4425,6 +4930,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
unsigned int flags)
{
struct ftrace_buffer_info *info = file->private_data;
+ struct trace_iterator *iter = &info->iter;
struct partial_page partial_def[PIPE_DEF_BUFFERS];
struct page *pages_def[PIPE_DEF_BUFFERS];
struct splice_pipe_desc spd = {
@@ -4437,10 +4943,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
};
struct buffer_ref *ref;
int entries, size, i;
- size_t ret;
+ ssize_t ret;
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
+ mutex_lock(&trace_types_lock);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ if (iter->snapshot && iter->tr->current_trace->use_max_tr) {
+ ret = -EBUSY;
+ goto out;
+ }
+#endif
+
+ if (splice_grow_spd(pipe, &spd)) {
+ ret = -ENOMEM;
+ goto out;
+ }
if (*ppos & (PAGE_SIZE - 1)) {
ret = -EINVAL;
@@ -4455,8 +4972,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
len &= PAGE_MASK;
}
- trace_access_lock(info->cpu);
- entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
+ again:
+ trace_access_lock(iter->cpu_file);
+ entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
for (i = 0; i < pipe->buffers && len && entries; i++, len -= PAGE_SIZE) {
struct page *page;
@@ -4467,15 +4985,15 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
break;
ref->ref = 1;
- ref->buffer = info->tr->buffer;
- ref->page = ring_buffer_alloc_read_page(ref->buffer, info->cpu);
+ ref->buffer = iter->trace_buffer->buffer;
+ ref->page = ring_buffer_alloc_read_page(ref->buffer, iter->cpu_file);
if (!ref->page) {
kfree(ref);
break;
}
r = ring_buffer_read_page(ref->buffer, &ref->page,
- len, info->cpu, 1);
+ len, iter->cpu_file, 1);
if (r < 0) {
ring_buffer_free_read_page(ref->buffer, ref->page);
kfree(ref);
@@ -4499,31 +5017,40 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
spd.nr_pages++;
*ppos += PAGE_SIZE;
- entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
+ entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
}
- trace_access_unlock(info->cpu);
+ trace_access_unlock(iter->cpu_file);
spd.nr_pages = i;
/* did we read anything? */
if (!spd.nr_pages) {
- if (flags & SPLICE_F_NONBLOCK)
+ if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK)) {
ret = -EAGAIN;
- else
- ret = 0;
- /* TODO: block */
- goto out;
+ goto out;
+ }
+ mutex_unlock(&trace_types_lock);
+ iter->trace->wait_pipe(iter);
+ mutex_lock(&trace_types_lock);
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ goto out;
+ }
+ goto again;
}
ret = splice_to_pipe(pipe, &spd);
splice_shrink_spd(&spd);
out:
+ mutex_unlock(&trace_types_lock);
+
return ret;
}
static const struct file_operations tracing_buffers_fops = {
.open = tracing_buffers_open,
.read = tracing_buffers_read,
+ .poll = tracing_buffers_poll,
.release = tracing_buffers_release,
.splice_read = tracing_buffers_splice_read,
.llseek = no_llseek,
@@ -4533,12 +5060,14 @@ static ssize_t
tracing_stats_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
- unsigned long cpu = (unsigned long)filp->private_data;
- struct trace_array *tr = &global_trace;
+ struct trace_cpu *tc = filp->private_data;
+ struct trace_array *tr = tc->tr;
+ struct trace_buffer *trace_buf = &tr->trace_buffer;
struct trace_seq *s;
unsigned long cnt;
unsigned long long t;
unsigned long usec_rem;
+ int cpu = tc->cpu;
s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
@@ -4546,41 +5075,41 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
trace_seq_init(s);
- cnt = ring_buffer_entries_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_entries_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "entries: %ld\n", cnt);
- cnt = ring_buffer_overrun_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_overrun_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "overrun: %ld\n", cnt);
- cnt = ring_buffer_commit_overrun_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_commit_overrun_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "commit overrun: %ld\n", cnt);
- cnt = ring_buffer_bytes_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_bytes_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "bytes: %ld\n", cnt);
if (trace_clocks[trace_clock_id].in_ns) {
/* local or global for trace_clock */
- t = ns2usecs(ring_buffer_oldest_event_ts(tr->buffer, cpu));
+ t = ns2usecs(ring_buffer_oldest_event_ts(trace_buf->buffer, cpu));
usec_rem = do_div(t, USEC_PER_SEC);
trace_seq_printf(s, "oldest event ts: %5llu.%06lu\n",
t, usec_rem);
- t = ns2usecs(ring_buffer_time_stamp(tr->buffer, cpu));
+ t = ns2usecs(ring_buffer_time_stamp(trace_buf->buffer, cpu));
usec_rem = do_div(t, USEC_PER_SEC);
trace_seq_printf(s, "now ts: %5llu.%06lu\n", t, usec_rem);
} else {
/* counter or tsc mode for trace_clock */
trace_seq_printf(s, "oldest event ts: %llu\n",
- ring_buffer_oldest_event_ts(tr->buffer, cpu));
+ ring_buffer_oldest_event_ts(trace_buf->buffer, cpu));
trace_seq_printf(s, "now ts: %llu\n",
- ring_buffer_time_stamp(tr->buffer, cpu));
+ ring_buffer_time_stamp(trace_buf->buffer, cpu));
}
- cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_dropped_events_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "dropped events: %ld\n", cnt);
- cnt = ring_buffer_read_events_cpu(tr->buffer, cpu);
+ cnt = ring_buffer_read_events_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "read events: %ld\n", cnt);
count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
@@ -4632,60 +5161,161 @@ static const struct file_operations tracing_dyn_info_fops = {
.read = tracing_read_dyn_info,
.llseek = generic_file_llseek,
};
-#endif
+#endif /* CONFIG_DYNAMIC_FTRACE */
-static struct dentry *d_tracer;
+#if defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE)
+static void
+ftrace_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ tracing_snapshot();
+}
-struct dentry *tracing_init_dentry(void)
+static void
+ftrace_count_snapshot(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ unsigned long *count = (long *)data;
+
+ if (!*count)
+ return;
+
+ if (*count != -1)
+ (*count)--;
+
+ tracing_snapshot();
+}
+
+static int
+ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
+ struct ftrace_probe_ops *ops, void *data)
+{
+ long count = (long)data;
+
+ seq_printf(m, "%ps:", (void *)ip);
+
+ seq_printf(m, "snapshot");
+
+ if (count == -1)
+ seq_printf(m, ":unlimited\n");
+ else
+ seq_printf(m, ":count=%ld\n", count);
+
+ return 0;
+}
+
+static struct ftrace_probe_ops snapshot_probe_ops = {
+ .func = ftrace_snapshot,
+ .print = ftrace_snapshot_print,
+};
+
+static struct ftrace_probe_ops snapshot_count_probe_ops = {
+ .func = ftrace_count_snapshot,
+ .print = ftrace_snapshot_print,
+};
+
+static int
+ftrace_trace_snapshot_callback(struct ftrace_hash *hash,
+ char *glob, char *cmd, char *param, int enable)
{
- static int once;
+ struct ftrace_probe_ops *ops;
+ void *count = (void *)-1;
+ char *number;
+ int ret;
- if (d_tracer)
- return d_tracer;
+ /* hash funcs only work with set_ftrace_filter */
+ if (!enable)
+ return -EINVAL;
+
+ ops = param ? &snapshot_count_probe_ops : &snapshot_probe_ops;
+
+ if (glob[0] == '!') {
+ unregister_ftrace_function_probe_func(glob+1, ops);
+ return 0;
+ }
+
+ if (!param)
+ goto out_reg;
+
+ number = strsep(&param, ":");
+
+ if (!strlen(number))
+ goto out_reg;
+
+ /*
+ * We use the callback data field (which is a pointer)
+ * as our counter.
+ */
+ ret = kstrtoul(number, 0, (unsigned long *)&count);
+ if (ret)
+ return ret;
+
+ out_reg:
+ ret = register_ftrace_function_probe(glob, ops, count);
+
+ if (ret >= 0)
+ alloc_snapshot(&global_trace);
+
+ return ret < 0 ? ret : 0;
+}
+
+static struct ftrace_func_command ftrace_snapshot_cmd = {
+ .name = "snapshot",
+ .func = ftrace_trace_snapshot_callback,
+};
+
+static int register_snapshot_cmd(void)
+{
+ return register_ftrace_command(&ftrace_snapshot_cmd);
+}
+#else
+static inline int register_snapshot_cmd(void) { return 0; }
+#endif /* defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE) */
+
+struct dentry *tracing_init_dentry_tr(struct trace_array *tr)
+{
+ if (tr->dir)
+ return tr->dir;
if (!debugfs_initialized())
return NULL;
- d_tracer = debugfs_create_dir("tracing", NULL);
+ if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+ tr->dir = debugfs_create_dir("tracing", NULL);
- if (!d_tracer && !once) {
- once = 1;
- pr_warning("Could not create debugfs directory 'tracing'\n");
- return NULL;
- }
+ if (!tr->dir)
+ pr_warn_once("Could not create debugfs directory 'tracing'\n");
- return d_tracer;
+ return tr->dir;
}
-static struct dentry *d_percpu;
+struct dentry *tracing_init_dentry(void)
+{
+ return tracing_init_dentry_tr(&global_trace);
+}
-static struct dentry *tracing_dentry_percpu(void)
+static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
{
- static int once;
struct dentry *d_tracer;
- if (d_percpu)
- return d_percpu;
-
- d_tracer = tracing_init_dentry();
+ if (tr->percpu_dir)
+ return tr->percpu_dir;
+ d_tracer = tracing_init_dentry_tr(tr);
if (!d_tracer)
return NULL;
- d_percpu = debugfs_create_dir("per_cpu", d_tracer);
+ tr->percpu_dir = debugfs_create_dir("per_cpu", d_tracer);
- if (!d_percpu && !once) {
- once = 1;
- pr_warning("Could not create debugfs directory 'per_cpu'\n");
- return NULL;
- }
+ WARN_ONCE(!tr->percpu_dir,
+ "Could not create debugfs directory 'per_cpu/%d'\n", cpu);
- return d_percpu;
+ return tr->percpu_dir;
}
-static void tracing_init_debugfs_percpu(long cpu)
+static void
+tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
{
- struct dentry *d_percpu = tracing_dentry_percpu();
+ struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
+ struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
struct dentry *d_cpu;
char cpu_dir[30]; /* 30 characters should be more than enough */
@@ -4701,20 +5331,28 @@ static void tracing_init_debugfs_percpu(long cpu)
/* per cpu trace_pipe */
trace_create_file("trace_pipe", 0444, d_cpu,
- (void *) cpu, &tracing_pipe_fops);
+ (void *)&data->trace_cpu, &tracing_pipe_fops);
/* per cpu trace */
trace_create_file("trace", 0644, d_cpu,
- (void *) cpu, &tracing_fops);
+ (void *)&data->trace_cpu, &tracing_fops);
trace_create_file("trace_pipe_raw", 0444, d_cpu,
- (void *) cpu, &tracing_buffers_fops);
+ (void *)&data->trace_cpu, &tracing_buffers_fops);
trace_create_file("stats", 0444, d_cpu,
- (void *) cpu, &tracing_stats_fops);
+ (void *)&data->trace_cpu, &tracing_stats_fops);
trace_create_file("buffer_size_kb", 0444, d_cpu,
- (void *) cpu, &tracing_entries_fops);
+ (void *)&data->trace_cpu, &tracing_entries_fops);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ trace_create_file("snapshot", 0644, d_cpu,
+ (void *)&data->trace_cpu, &snapshot_fops);
+
+ trace_create_file("snapshot_raw", 0444, d_cpu,
+ (void *)&data->trace_cpu, &snapshot_raw_fops);
+#endif
}
#ifdef CONFIG_FTRACE_SELFTEST
@@ -4725,6 +5363,7 @@ static void tracing_init_debugfs_percpu(long cpu)
struct trace_option_dentry {
struct tracer_opt *opt;
struct tracer_flags *flags;
+ struct trace_array *tr;
struct dentry *entry;
};
@@ -4760,7 +5399,7 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (!!(topt->flags->val & topt->opt->bit) != val) {
mutex_lock(&trace_types_lock);
- ret = __set_tracer_option(current_trace, topt->flags,
+ ret = __set_tracer_option(topt->tr->current_trace, topt->flags,
topt->opt, !val);
mutex_unlock(&trace_types_lock);
if (ret)
@@ -4799,6 +5438,7 @@ 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;
unsigned long val;
int ret;
@@ -4811,7 +5451,7 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
return -EINVAL;
mutex_lock(&trace_types_lock);
- ret = set_tracer_flag(1 << index, val);
+ ret = set_tracer_flag(tr, 1 << index, val);
mutex_unlock(&trace_types_lock);
if (ret < 0)
@@ -4845,40 +5485,41 @@ struct dentry *trace_create_file(const char *name,
}
-static struct dentry *trace_options_init_dentry(void)
+static struct dentry *trace_options_init_dentry(struct trace_array *tr)
{
struct dentry *d_tracer;
- static struct dentry *t_options;
- if (t_options)
- return t_options;
+ if (tr->options)
+ return tr->options;
- d_tracer = tracing_init_dentry();
+ d_tracer = tracing_init_dentry_tr(tr);
if (!d_tracer)
return NULL;
- t_options = debugfs_create_dir("options", d_tracer);
- if (!t_options) {
+ tr->options = debugfs_create_dir("options", d_tracer);
+ if (!tr->options) {
pr_warning("Could not create debugfs directory 'options'\n");
return NULL;
}
- return t_options;
+ return tr->options;
}
static void
-create_trace_option_file(struct trace_option_dentry *topt,
+create_trace_option_file(struct trace_array *tr,
+ struct trace_option_dentry *topt,
struct tracer_flags *flags,
struct tracer_opt *opt)
{
struct dentry *t_options;
- t_options = trace_options_init_dentry();
+ t_options = trace_options_init_dentry(tr);
if (!t_options)
return;
topt->flags = flags;
topt->opt = opt;
+ topt->tr = tr;
topt->entry = trace_create_file(opt->name, 0644, t_options, topt,
&trace_options_fops);
@@ -4886,7 +5527,7 @@ create_trace_option_file(struct trace_option_dentry *topt,
}
static struct trace_option_dentry *
-create_trace_option_files(struct tracer *tracer)
+create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
{
struct trace_option_dentry *topts;
struct tracer_flags *flags;
@@ -4911,7 +5552,7 @@ create_trace_option_files(struct tracer *tracer)
return NULL;
for (cnt = 0; opts[cnt].name; cnt++)
- create_trace_option_file(&topts[cnt], flags,
+ create_trace_option_file(tr, &topts[cnt], flags,
&opts[cnt]);
return topts;
@@ -4934,11 +5575,12 @@ destroy_trace_option_files(struct trace_option_dentry *topts)
}
static struct dentry *
-create_trace_option_core_file(const char *option, long index)
+create_trace_option_core_file(struct trace_array *tr,
+ const char *option, long index)
{
struct dentry *t_options;
- t_options = trace_options_init_dentry();
+ t_options = trace_options_init_dentry(tr);
if (!t_options)
return NULL;
@@ -4946,17 +5588,17 @@ create_trace_option_core_file(const char *option, long index)
&trace_options_core_fops);
}
-static __init void create_trace_options_dir(void)
+static __init void create_trace_options_dir(struct trace_array *tr)
{
struct dentry *t_options;
int i;
- t_options = trace_options_init_dentry();
+ t_options = trace_options_init_dentry(tr);
if (!t_options)
return;
for (i = 0; trace_options[i]; i++)
- create_trace_option_core_file(trace_options[i], i);
+ create_trace_option_core_file(tr, trace_options[i], i);
}
static ssize_t
@@ -4964,7 +5606,7 @@ rb_simple_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct trace_array *tr = filp->private_data;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
char buf[64];
int r;
@@ -4983,7 +5625,7 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct trace_array *tr = filp->private_data;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
unsigned long val;
int ret;
@@ -4995,12 +5637,12 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
mutex_lock(&trace_types_lock);
if (val) {
ring_buffer_record_on(buffer);
- if (current_trace->start)
- current_trace->start(tr);
+ if (tr->current_trace->start)
+ tr->current_trace->start(tr);
} else {
ring_buffer_record_off(buffer);
- if (current_trace->stop)
- current_trace->stop(tr);
+ if (tr->current_trace->stop)
+ tr->current_trace->stop(tr);
}
mutex_unlock(&trace_types_lock);
}
@@ -5017,23 +5659,310 @@ static const struct file_operations rb_simple_fops = {
.llseek = default_llseek,
};
+struct dentry *trace_instance_dir;
+
+static void
+init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
+
+static void init_trace_buffers(struct trace_array *tr, struct trace_buffer *buf)
+{
+ int cpu;
+
+ for_each_tracing_cpu(cpu) {
+ memset(per_cpu_ptr(buf->data, cpu), 0, sizeof(struct trace_array_cpu));
+ per_cpu_ptr(buf->data, cpu)->trace_cpu.cpu = cpu;
+ per_cpu_ptr(buf->data, cpu)->trace_cpu.tr = tr;
+ }
+}
+
+static int
+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;
+
+ buf->buffer = ring_buffer_alloc(size, rb_flags);
+ if (!buf->buffer)
+ return -ENOMEM;
+
+ buf->data = alloc_percpu(struct trace_array_cpu);
+ if (!buf->data) {
+ ring_buffer_free(buf->buffer);
+ return -ENOMEM;
+ }
+
+ init_trace_buffers(tr, buf);
+
+ /* Allocate the first page for all buffers */
+ set_buffer_entries(&tr->trace_buffer,
+ ring_buffer_size(tr->trace_buffer.buffer, 0));
+
+ return 0;
+}
+
+static int allocate_trace_buffers(struct trace_array *tr, int size)
+{
+ int ret;
+
+ ret = allocate_trace_buffer(tr, &tr->trace_buffer, size);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+ ret = allocate_trace_buffer(tr, &tr->max_buffer,
+ allocate_snapshot ? size : 1);
+ if (WARN_ON(ret)) {
+ ring_buffer_free(tr->trace_buffer.buffer);
+ free_percpu(tr->trace_buffer.data);
+ return -ENOMEM;
+ }
+ tr->allocated_snapshot = allocate_snapshot;
+
+ /*
+ * Only the top level trace array gets its snapshot allocated
+ * from the kernel command line.
+ */
+ allocate_snapshot = false;
+#endif
+ return 0;
+}
+
+static int new_instance_create(const char *name)
+{
+ struct trace_array *tr;
+ int ret;
+
+ mutex_lock(&trace_types_lock);
+
+ ret = -EEXIST;
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ if (tr->name && strcmp(tr->name, name) == 0)
+ goto out_unlock;
+ }
+
+ ret = -ENOMEM;
+ tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+ if (!tr)
+ goto out_unlock;
+
+ tr->name = kstrdup(name, GFP_KERNEL);
+ if (!tr->name)
+ goto out_free_tr;
+
+ raw_spin_lock_init(&tr->start_lock);
+
+ tr->current_trace = &nop_trace;
+
+ INIT_LIST_HEAD(&tr->systems);
+ INIT_LIST_HEAD(&tr->events);
+
+ if (allocate_trace_buffers(tr, trace_buf_size) < 0)
+ goto out_free_tr;
+
+ /* Holder for file callbacks */
+ tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
+ tr->trace_cpu.tr = tr;
+
+ tr->dir = debugfs_create_dir(name, trace_instance_dir);
+ if (!tr->dir)
+ goto out_free_tr;
+
+ ret = event_trace_add_tracer(tr->dir, tr);
+ if (ret)
+ goto out_free_tr;
+
+ init_tracer_debugfs(tr, tr->dir);
+
+ list_add(&tr->list, &ftrace_trace_arrays);
+
+ mutex_unlock(&trace_types_lock);
+
+ return 0;
+
+ out_free_tr:
+ if (tr->trace_buffer.buffer)
+ ring_buffer_free(tr->trace_buffer.buffer);
+ kfree(tr->name);
+ kfree(tr);
+
+ out_unlock:
+ mutex_unlock(&trace_types_lock);
+
+ return ret;
+
+}
+
+static int instance_delete(const char *name)
+{
+ struct trace_array *tr;
+ int found = 0;
+ int ret;
+
+ mutex_lock(&trace_types_lock);
+
+ ret = -ENODEV;
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ if (tr->name && strcmp(tr->name, name) == 0) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ goto out_unlock;
+
+ ret = -EBUSY;
+ if (tr->ref)
+ goto out_unlock;
+
+ list_del(&tr->list);
+
+ event_trace_del_tracer(tr);
+ debugfs_remove_recursive(tr->dir);
+ free_percpu(tr->trace_buffer.data);
+ ring_buffer_free(tr->trace_buffer.buffer);
+
+ kfree(tr->name);
+ kfree(tr);
+
+ ret = 0;
+
+ out_unlock:
+ mutex_unlock(&trace_types_lock);
+
+ return ret;
+}
+
+static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
+{
+ struct dentry *parent;
+ int ret;
+
+ /* Paranoid: Make sure the parent is the "instances" directory */
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ if (WARN_ON_ONCE(parent != trace_instance_dir))
+ return -ENOENT;
+
+ /*
+ * The inode mutex is locked, but debugfs_create_dir() will also
+ * take the mutex. As the instances directory can not be destroyed
+ * or changed in any other way, it is safe to unlock it, and
+ * let the dentry try. If two users try to make the same dir at
+ * the same time, then the new_instance_create() will determine the
+ * winner.
+ */
+ mutex_unlock(&inode->i_mutex);
+
+ ret = new_instance_create(dentry->d_iname);
+
+ mutex_lock(&inode->i_mutex);
+
+ return ret;
+}
+
+static int instance_rmdir(struct inode *inode, struct dentry *dentry)
+{
+ struct dentry *parent;
+ int ret;
+
+ /* Paranoid: Make sure the parent is the "instances" directory */
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ if (WARN_ON_ONCE(parent != trace_instance_dir))
+ return -ENOENT;
+
+ /* The caller did a dget() on dentry */
+ mutex_unlock(&dentry->d_inode->i_mutex);
+
+ /*
+ * The inode mutex is locked, but debugfs_create_dir() will also
+ * take the mutex. As the instances directory can not be destroyed
+ * or changed in any other way, it is safe to unlock it, and
+ * let the dentry try. If two users try to make the same dir at
+ * the same time, then the instance_delete() will determine the
+ * winner.
+ */
+ mutex_unlock(&inode->i_mutex);
+
+ ret = instance_delete(dentry->d_iname);
+
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+ mutex_lock(&dentry->d_inode->i_mutex);
+
+ return ret;
+}
+
+static const struct inode_operations instance_dir_inode_operations = {
+ .lookup = simple_lookup,
+ .mkdir = instance_mkdir,
+ .rmdir = instance_rmdir,
+};
+
+static __init void create_trace_instances(struct dentry *d_tracer)
+{
+ trace_instance_dir = debugfs_create_dir("instances", d_tracer);
+ if (WARN_ON(!trace_instance_dir))
+ return;
+
+ /* Hijack the dir inode operations, to allow mkdir */
+ trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
+}
+
+static void
+init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
+{
+ int cpu;
+
+ trace_create_file("trace_options", 0644, d_tracer,
+ tr, &tracing_iter_fops);
+
+ trace_create_file("trace", 0644, d_tracer,
+ (void *)&tr->trace_cpu, &tracing_fops);
+
+ trace_create_file("trace_pipe", 0444, d_tracer,
+ (void *)&tr->trace_cpu, &tracing_pipe_fops);
+
+ trace_create_file("buffer_size_kb", 0644, d_tracer,
+ (void *)&tr->trace_cpu, &tracing_entries_fops);
+
+ trace_create_file("buffer_total_size_kb", 0444, d_tracer,
+ tr, &tracing_total_entries_fops);
+
+ trace_create_file("free_buffer", 0644, d_tracer,
+ tr, &tracing_free_buffer_fops);
+
+ trace_create_file("trace_marker", 0220, d_tracer,
+ tr, &tracing_mark_fops);
+
+ trace_create_file("trace_clock", 0644, d_tracer, tr,
+ &trace_clock_fops);
+
+ trace_create_file("tracing_on", 0644, d_tracer,
+ tr, &rb_simple_fops);
+
+#ifdef CONFIG_TRACER_SNAPSHOT
+ trace_create_file("snapshot", 0644, d_tracer,
+ (void *)&tr->trace_cpu, &snapshot_fops);
+#endif
+
+ for_each_tracing_cpu(cpu)
+ tracing_init_debugfs_percpu(tr, cpu);
+
+}
+
static __init int tracer_init_debugfs(void)
{
struct dentry *d_tracer;
- int cpu;
trace_access_lock_init();
d_tracer = tracing_init_dentry();
+ if (!d_tracer)
+ return 0;
- trace_create_file("trace_options", 0644, d_tracer,
- NULL, &tracing_iter_fops);
+ init_tracer_debugfs(&global_trace, d_tracer);
trace_create_file("tracing_cpumask", 0644, d_tracer,
- NULL, &tracing_cpumask_fops);
-
- trace_create_file("trace", 0644, d_tracer,
- (void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
+ &global_trace, &tracing_cpumask_fops);
trace_create_file("available_tracers", 0444, d_tracer,
&global_trace, &show_traces_fops);
@@ -5052,44 +5981,17 @@ static __init int tracer_init_debugfs(void)
trace_create_file("README", 0444, d_tracer,
NULL, &tracing_readme_fops);
- trace_create_file("trace_pipe", 0444, d_tracer,
- (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
-
- trace_create_file("buffer_size_kb", 0644, d_tracer,
- (void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
-
- trace_create_file("buffer_total_size_kb", 0444, d_tracer,
- &global_trace, &tracing_total_entries_fops);
-
- trace_create_file("free_buffer", 0644, d_tracer,
- &global_trace, &tracing_free_buffer_fops);
-
- trace_create_file("trace_marker", 0220, d_tracer,
- NULL, &tracing_mark_fops);
-
trace_create_file("saved_cmdlines", 0444, d_tracer,
NULL, &tracing_saved_cmdlines_fops);
- trace_create_file("trace_clock", 0644, d_tracer, NULL,
- &trace_clock_fops);
-
- trace_create_file("tracing_on", 0644, d_tracer,
- &global_trace, &rb_simple_fops);
-
#ifdef CONFIG_DYNAMIC_FTRACE
trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
&ftrace_update_tot_cnt, &tracing_dyn_info_fops);
#endif
-#ifdef CONFIG_TRACER_SNAPSHOT
- trace_create_file("snapshot", 0644, d_tracer,
- (void *) TRACE_PIPE_ALL_CPU, &snapshot_fops);
-#endif
+ create_trace_instances(d_tracer);
- create_trace_options_dir();
-
- for_each_tracing_cpu(cpu)
- tracing_init_debugfs_percpu(cpu);
+ create_trace_options_dir(&global_trace);
return 0;
}
@@ -5145,8 +6047,8 @@ void
trace_printk_seq(struct trace_seq *s)
{
/* Probably should print a warning here. */
- if (s->len >= 1000)
- s->len = 1000;
+ if (s->len >= TRACE_MAX_PRINT)
+ s->len = TRACE_MAX_PRINT;
/* should be zero ended, but we are paranoid. */
s->buffer[s->len] = 0;
@@ -5159,46 +6061,43 @@ trace_printk_seq(struct trace_seq *s)
void trace_init_global_iter(struct trace_iterator *iter)
{
iter->tr = &global_trace;
- iter->trace = current_trace;
- iter->cpu_file = TRACE_PIPE_ALL_CPU;
+ iter->trace = iter->tr->current_trace;
+ iter->cpu_file = RING_BUFFER_ALL_CPUS;
+ iter->trace_buffer = &global_trace.trace_buffer;
}
-static void
-__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
+void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
{
- static arch_spinlock_t ftrace_dump_lock =
- (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
/* use static because iter can be a bit big for the stack */
static struct trace_iterator iter;
+ static atomic_t dump_running;
unsigned int old_userobj;
- static int dump_ran;
unsigned long flags;
int cnt = 0, cpu;
- /* only one dump */
- local_irq_save(flags);
- arch_spin_lock(&ftrace_dump_lock);
- if (dump_ran)
- goto out;
-
- dump_ran = 1;
+ /* Only allow one dump user at a time. */
+ if (atomic_inc_return(&dump_running) != 1) {
+ atomic_dec(&dump_running);
+ return;
+ }
+ /*
+ * Always turn off tracing when we dump.
+ * We don't need to show trace output of what happens
+ * between multiple crashes.
+ *
+ * If the user does a sysrq-z, then they can re-enable
+ * tracing with echo 1 > tracing_on.
+ */
tracing_off();
- /* Did function tracer already get disabled? */
- if (ftrace_is_dead()) {
- printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n");
- printk("# MAY BE MISSING FUNCTION EVENTS\n");
- }
-
- if (disable_tracing)
- ftrace_kill();
+ local_irq_save(flags);
/* Simulate the iterator */
trace_init_global_iter(&iter);
for_each_tracing_cpu(cpu) {
- atomic_inc(&iter.tr->data[cpu]->disabled);
+ atomic_inc(&per_cpu_ptr(iter.tr->trace_buffer.data, cpu)->disabled);
}
old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
@@ -5208,7 +6107,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
switch (oops_dump_mode) {
case DUMP_ALL:
- iter.cpu_file = TRACE_PIPE_ALL_CPU;
+ iter.cpu_file = RING_BUFFER_ALL_CPUS;
break;
case DUMP_ORIG:
iter.cpu_file = raw_smp_processor_id();
@@ -5217,11 +6116,17 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
goto out_enable;
default:
printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
- iter.cpu_file = TRACE_PIPE_ALL_CPU;
+ iter.cpu_file = RING_BUFFER_ALL_CPUS;
}
printk(KERN_TRACE "Dumping ftrace buffer:\n");
+ /* Did function tracer already get disabled? */
+ if (ftrace_is_dead()) {
+ printk("# WARNING: FUNCTION TRACING IS CORRUPTED\n");
+ printk("# MAY BE MISSING FUNCTION EVENTS\n");
+ }
+
/*
* We need to stop all tracing on all CPUS to read the
* the next buffer. This is a bit expensive, but is
@@ -5261,33 +6166,19 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
printk(KERN_TRACE "---------------------------------\n");
out_enable:
- /* Re-enable tracing if requested */
- if (!disable_tracing) {
- trace_flags |= old_userobj;
+ trace_flags |= old_userobj;
- for_each_tracing_cpu(cpu) {
- atomic_dec(&iter.tr->data[cpu]->disabled);
- }
- tracing_on();
+ for_each_tracing_cpu(cpu) {
+ atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
-
- out:
- arch_spin_unlock(&ftrace_dump_lock);
+ atomic_dec(&dump_running);
local_irq_restore(flags);
}
-
-/* By default: disable tracing after the dump */
-void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
-{
- __ftrace_dump(true, oops_dump_mode);
-}
EXPORT_SYMBOL_GPL(ftrace_dump);
__init static int tracer_alloc_buffers(void)
{
int ring_buf_size;
- enum ring_buffer_flags rb_flags;
- int i;
int ret = -ENOMEM;
@@ -5308,49 +6199,27 @@ __init static int tracer_alloc_buffers(void)
else
ring_buf_size = 1;
- rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
-
cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
cpumask_copy(tracing_cpumask, cpu_all_mask);
+ raw_spin_lock_init(&global_trace.start_lock);
+
/* TODO: make the number of buffers hot pluggable with CPUS */
- global_trace.buffer = ring_buffer_alloc(ring_buf_size, rb_flags);
- if (!global_trace.buffer) {
+ if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
WARN_ON(1);
goto out_free_cpumask;
}
+
if (global_trace.buffer_disabled)
tracing_off();
-
-#ifdef CONFIG_TRACER_MAX_TRACE
- max_tr.buffer = ring_buffer_alloc(1, rb_flags);
- if (!max_tr.buffer) {
- printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
- WARN_ON(1);
- ring_buffer_free(global_trace.buffer);
- goto out_free_cpumask;
- }
-#endif
-
- /* Allocate the first page for all buffers */
- for_each_tracing_cpu(i) {
- global_trace.data[i] = &per_cpu(global_trace_cpu, i);
- max_tr.data[i] = &per_cpu(max_tr_data, i);
- }
-
- set_buffer_entries(&global_trace,
- ring_buffer_size(global_trace.buffer, 0));
-#ifdef CONFIG_TRACER_MAX_TRACE
- set_buffer_entries(&max_tr, 1);
-#endif
-
trace_init_cmdlines();
- init_irq_work(&trace_work_wakeup, trace_wake_up);
register_tracer(&nop_trace);
+ global_trace.current_trace = &nop_trace;
+
/* All seems OK, enable tracing */
tracing_disabled = 0;
@@ -5359,16 +6228,32 @@ __init static int tracer_alloc_buffers(void)
register_die_notifier(&trace_die_notifier);
+ global_trace.flags = TRACE_ARRAY_FL_GLOBAL;
+
+ /* Holder for file callbacks */
+ global_trace.trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
+ global_trace.trace_cpu.tr = &global_trace;
+
+ INIT_LIST_HEAD(&global_trace.systems);
+ 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(option);
+ trace_set_options(&global_trace, option);
}
+ register_snapshot_cmd();
+
return 0;
out_free_cpumask:
+ free_percpu(global_trace.trace_buffer.data);
+#ifdef CONFIG_TRACER_MAX_TRACE
+ free_percpu(global_trace.max_buffer.data);
+#endif
free_cpumask_var(tracing_cpumask);
out_free_buffer_mask:
free_cpumask_var(tracing_buffer_mask);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2081971367ea..711ca7d3e7f1 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -13,6 +13,11 @@
#include <linux/trace_seq.h>
#include <linux/ftrace_event.h>
+#ifdef CONFIG_FTRACE_SYSCALLS
+#include <asm/unistd.h> /* For NR_SYSCALLS */
+#include <asm/syscall.h> /* some archs define it here */
+#endif
+
enum trace_type {
__TRACE_FIRST_TYPE = 0,
@@ -29,6 +34,7 @@ enum trace_type {
TRACE_GRAPH_ENT,
TRACE_USER_STACK,
TRACE_BLK,
+ TRACE_BPUTS,
__TRACE_LAST_TYPE,
};
@@ -103,11 +109,6 @@ struct kretprobe_trace_entry_head {
unsigned long ret_ip;
};
-struct uprobe_trace_entry_head {
- struct trace_entry ent;
- unsigned long ip;
-};
-
/*
* trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are:
@@ -127,12 +128,21 @@ enum trace_flag_type {
#define TRACE_BUF_SIZE 1024
+struct trace_array;
+
+struct trace_cpu {
+ struct trace_array *tr;
+ struct dentry *dir;
+ int cpu;
+};
+
/*
* The CPU trace array - it consists of thousands of trace entries
* plus some other descriptor data: (for example which task started
* the trace, etc.)
*/
struct trace_array_cpu {
+ struct trace_cpu trace_cpu;
atomic_t disabled;
void *buffer_page; /* ring buffer spare */
@@ -151,20 +161,83 @@ struct trace_array_cpu {
char comm[TASK_COMM_LEN];
};
+struct tracer;
+
+struct trace_buffer {
+ struct trace_array *tr;
+ struct ring_buffer *buffer;
+ struct trace_array_cpu __percpu *data;
+ cycle_t time_start;
+ int cpu;
+};
+
/*
* The trace array - an array of per-CPU trace arrays. This is the
* highest level data structure that individual tracers deal with.
* They have on/off state as well:
*/
struct trace_array {
- struct ring_buffer *buffer;
- int cpu;
+ struct list_head list;
+ char *name;
+ struct trace_buffer trace_buffer;
+#ifdef CONFIG_TRACER_MAX_TRACE
+ /*
+ * The max_buffer is used to snapshot the trace when a maximum
+ * latency is reached, or when the user initiates a snapshot.
+ * Some tracers will use this to store a maximum trace while
+ * it continues examining live traces.
+ *
+ * The buffers for the max_buffer are set up the same as the trace_buffer
+ * When a snapshot is taken, the buffer of the max_buffer is swapped
+ * with the buffer of the trace_buffer and the buffers are reset for
+ * the trace_buffer so the tracing can continue.
+ */
+ struct trace_buffer max_buffer;
+ bool allocated_snapshot;
+#endif
int buffer_disabled;
- cycle_t time_start;
+ struct trace_cpu trace_cpu; /* place holder */
+#ifdef CONFIG_FTRACE_SYSCALLS
+ int sys_refcount_enter;
+ int sys_refcount_exit;
+ DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
+ DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
+#endif
+ int stop_count;
+ int clock_id;
+ struct tracer *current_trace;
+ unsigned int flags;
+ raw_spinlock_t start_lock;
+ struct dentry *dir;
+ struct dentry *options;
+ struct dentry *percpu_dir;
+ struct dentry *event_dir;
+ struct list_head systems;
+ struct list_head events;
struct task_struct *waiter;
- struct trace_array_cpu *data[NR_CPUS];
+ int ref;
+};
+
+enum {
+ TRACE_ARRAY_FL_GLOBAL = (1 << 0)
};
+extern struct list_head ftrace_trace_arrays;
+
+/*
+ * The global tracer (top) should be the first trace array added,
+ * but we check the flag anyway.
+ */
+static inline struct trace_array *top_trace_array(void)
+{
+ struct trace_array *tr;
+
+ tr = list_entry(ftrace_trace_arrays.prev,
+ typeof(*tr), list);
+ WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL));
+ return tr;
+}
+
#define FTRACE_CMP_TYPE(var, type) \
__builtin_types_compatible_p(typeof(var), type *)
@@ -200,6 +273,7 @@ extern void __ftrace_bad_type(void);
IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT); \
IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \
+ IF_ASSIGN(var, ent, struct bputs_entry, TRACE_BPUTS); \
IF_ASSIGN(var, ent, struct trace_mmiotrace_rw, \
TRACE_MMIO_RW); \
IF_ASSIGN(var, ent, struct trace_mmiotrace_map, \
@@ -289,9 +363,10 @@ struct tracer {
struct tracer *next;
struct tracer_flags *flags;
bool print_max;
- bool use_max_tr;
- bool allocated_snapshot;
bool enabled;
+#ifdef CONFIG_TRACER_MAX_TRACE
+ bool use_max_tr;
+#endif
};
@@ -427,8 +502,6 @@ static __always_inline void trace_clear_recursion(int bit)
current->trace_recursion = val;
}
-#define TRACE_PIPE_ALL_CPU -1
-
static inline struct ring_buffer_iter *
trace_buffer_iter(struct trace_iterator *iter, int cpu)
{
@@ -439,10 +512,10 @@ trace_buffer_iter(struct trace_iterator *iter, int cpu)
int tracer_init(struct tracer *t, struct trace_array *tr);
int tracing_is_enabled(void);
-void tracing_reset(struct trace_array *tr, int cpu);
-void tracing_reset_online_cpus(struct trace_array *tr);
+void tracing_reset(struct trace_buffer *buf, int cpu);
+void tracing_reset_online_cpus(struct trace_buffer *buf);
void tracing_reset_current(int cpu);
-void tracing_reset_current_online_cpus(void);
+void tracing_reset_all_online_cpus(void);
int tracing_open_generic(struct inode *inode, struct file *filp);
struct dentry *trace_create_file(const char *name,
umode_t mode,
@@ -450,6 +523,7 @@ struct dentry *trace_create_file(const char *name,
void *data,
const struct file_operations *fops);
+struct dentry *tracing_init_dentry_tr(struct trace_array *tr);
struct dentry *tracing_init_dentry(void);
struct ring_buffer_event;
@@ -583,7 +657,7 @@ extern int DYN_FTRACE_TEST_NAME(void);
#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
extern int DYN_FTRACE_TEST_NAME2(void);
-extern int ring_buffer_expanded;
+extern bool ring_buffer_expanded;
extern bool tracing_selftest_disabled;
DECLARE_PER_CPU(int, ftrace_cpu_disabled);
@@ -619,6 +693,8 @@ trace_array_vprintk(struct trace_array *tr,
unsigned long ip, const char *fmt, va_list args);
int trace_array_printk(struct trace_array *tr,
unsigned long ip, const char *fmt, ...);
+int trace_array_printk_buf(struct ring_buffer *buffer,
+ unsigned long ip, const char *fmt, ...);
void trace_printk_seq(struct trace_seq *s);
enum print_line_t print_trace_line(struct trace_iterator *iter);
@@ -786,6 +862,7 @@ enum trace_iterator_flags {
TRACE_ITER_STOP_ON_FREE = 0x400000,
TRACE_ITER_IRQ_INFO = 0x800000,
TRACE_ITER_MARKERS = 0x1000000,
+ TRACE_ITER_FUNCTION = 0x2000000,
};
/*
@@ -832,8 +909,8 @@ enum {
struct ftrace_event_field {
struct list_head link;
- char *name;
- char *type;
+ const char *name;
+ const char *type;
int filter_type;
int offset;
int size;
@@ -851,12 +928,19 @@ struct event_filter {
struct event_subsystem {
struct list_head list;
const char *name;
- struct dentry *entry;
struct event_filter *filter;
- int nr_events;
int ref_count;
};
+struct ftrace_subsystem_dir {
+ struct list_head list;
+ struct event_subsystem *subsystem;
+ struct trace_array *tr;
+ struct dentry *entry;
+ int ref_count;
+ int nr_events;
+};
+
#define FILTER_PRED_INVALID ((unsigned short)-1)
#define FILTER_PRED_IS_RIGHT (1 << 15)
#define FILTER_PRED_FOLD (1 << 15)
@@ -906,22 +990,20 @@ struct filter_pred {
unsigned short right;
};
-extern struct list_head ftrace_common_fields;
-
extern enum regex_type
filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct ftrace_event_call *call,
struct trace_seq *s);
extern int apply_event_filter(struct ftrace_event_call *call,
char *filter_string);
-extern int apply_subsystem_event_filter(struct event_subsystem *system,
+extern int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,
char *filter_string);
extern void print_subsystem_event_filter(struct event_subsystem *system,
struct trace_seq *s);
extern int filter_assign_type(const char *type);
-struct list_head *
-trace_get_fields(struct ftrace_event_call *event_call);
+struct ftrace_event_field *
+trace_find_event_field(struct ftrace_event_call *call, char *name);
static inline int
filter_check_discard(struct ftrace_event_call *call, void *rec,
@@ -938,6 +1020,8 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
}
extern void trace_event_enable_cmd_record(bool enable);
+extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
+extern int event_trace_del_tracer(struct trace_array *tr);
extern struct mutex event_mutex;
extern struct list_head ftrace_events;
@@ -948,7 +1032,18 @@ extern const char *__stop___trace_bprintk_fmt[];
void trace_printk_init_buffers(void);
void trace_printk_start_comm(void);
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
-int set_tracer_flag(unsigned int mask, int enabled);
+int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
+
+/*
+ * Normal trace_printk() and friends allocates special buffers
+ * to do the manipulation, as well as saves the print formats
+ * into sections to display. But the trace infrastructure wants
+ * to use these without the added overhead at the price of being
+ * a bit slower (used mainly for warnings, where we don't care
+ * about performance). The internal_trace_puts() is for such
+ * a purpose.
+ */
+#define internal_trace_puts(str) __trace_puts(_THIS_IP_, str, strlen(str))
#undef FTRACE_ENTRY
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 95e96842ed29..d594da0dc03c 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -32,6 +32,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
{
struct ftrace_event_call *call = &event_branch;
struct trace_array *tr = branch_tracer;
+ struct trace_array_cpu *data;
struct ring_buffer_event *event;
struct trace_branch *entry;
struct ring_buffer *buffer;
@@ -51,11 +52,12 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
local_irq_save(flags);
cpu = raw_smp_processor_id();
- if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
+ if (atomic_inc_return(&data->disabled) != 1)
goto out;
pc = preempt_count();
- buffer = tr->buffer;
+ buffer = tr->trace_buffer.buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
sizeof(*entry), flags, pc);
if (!event)
@@ -80,7 +82,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
__buffer_unlock_commit(buffer, event);
out:
- atomic_dec(&tr->data[cpu]->disabled);
+ atomic_dec(&data->disabled);
local_irq_restore(flags);
}
diff --git a/kernel/trace/trace_clock.c b/kernel/trace/trace_clock.c
index aa8f5f48dae6..26dc348332b7 100644
--- a/kernel/trace/trace_clock.c
+++ b/kernel/trace/trace_clock.c
@@ -57,6 +57,16 @@ u64 notrace trace_clock(void)
return local_clock();
}
+/*
+ * trace_jiffy_clock(): Simply use jiffies as a clock counter.
+ */
+u64 notrace trace_clock_jiffies(void)
+{
+ u64 jiffy = jiffies - INITIAL_JIFFIES;
+
+ /* Return nsecs */
+ return (u64)jiffies_to_usecs(jiffy) * 1000ULL;
+}
/*
* trace_clock_global(): special globally coherent trace clock
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index 4108e1250ca2..e2d027ac66a2 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -223,8 +223,8 @@ FTRACE_ENTRY(bprint, bprint_entry,
__dynamic_array( u32, buf )
),
- F_printk("%08lx fmt:%p",
- __entry->ip, __entry->fmt),
+ F_printk("%pf: %s",
+ (void *)__entry->ip, __entry->fmt),
FILTER_OTHER
);
@@ -238,8 +238,23 @@ FTRACE_ENTRY(print, print_entry,
__dynamic_array( char, buf )
),
- F_printk("%08lx %s",
- __entry->ip, __entry->buf),
+ F_printk("%pf: %s",
+ (void *)__entry->ip, __entry->buf),
+
+ FILTER_OTHER
+);
+
+FTRACE_ENTRY(bputs, bputs_entry,
+
+ TRACE_BPUTS,
+
+ F_STRUCT(
+ __field( unsigned long, ip )
+ __field( const char *, str )
+ ),
+
+ F_printk("%pf: %s",
+ (void *)__entry->ip, __entry->str),
FILTER_OTHER
);
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 57e9b284250c..53582e982e51 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -34,9 +34,27 @@ char event_storage[EVENT_STORAGE_SIZE];
EXPORT_SYMBOL_GPL(event_storage);
LIST_HEAD(ftrace_events);
-LIST_HEAD(ftrace_common_fields);
+static LIST_HEAD(ftrace_common_fields);
-struct list_head *
+#define GFP_TRACE (GFP_KERNEL | __GFP_ZERO)
+
+static struct kmem_cache *field_cachep;
+static struct kmem_cache *file_cachep;
+
+/* Double loops, do not use break, only goto's work */
+#define do_for_each_event_file(tr, file) \
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) { \
+ list_for_each_entry(file, &tr->events, list)
+
+#define do_for_each_event_file_safe(tr, file) \
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) { \
+ struct ftrace_event_file *___n; \
+ list_for_each_entry_safe(file, ___n, &tr->events, list)
+
+#define while_for_each_event_file() \
+ }
+
+static struct list_head *
trace_get_fields(struct ftrace_event_call *event_call)
{
if (!event_call->class->get_fields)
@@ -44,23 +62,45 @@ trace_get_fields(struct ftrace_event_call *event_call)
return event_call->class->get_fields(event_call);
}
+static struct ftrace_event_field *
+__find_event_field(struct list_head *head, char *name)
+{
+ struct ftrace_event_field *field;
+
+ list_for_each_entry(field, head, link) {
+ if (!strcmp(field->name, name))
+ return field;
+ }
+
+ return NULL;
+}
+
+struct ftrace_event_field *
+trace_find_event_field(struct ftrace_event_call *call, char *name)
+{
+ struct ftrace_event_field *field;
+ struct list_head *head;
+
+ field = __find_event_field(&ftrace_common_fields, name);
+ if (field)
+ return field;
+
+ head = trace_get_fields(call);
+ return __find_event_field(head, name);
+}
+
static int __trace_define_field(struct list_head *head, const char *type,
const char *name, int offset, int size,
int is_signed, int filter_type)
{
struct ftrace_event_field *field;
- field = kzalloc(sizeof(*field), GFP_KERNEL);
+ field = kmem_cache_alloc(field_cachep, GFP_TRACE);
if (!field)
goto err;
- field->name = kstrdup(name, GFP_KERNEL);
- if (!field->name)
- goto err;
-
- field->type = kstrdup(type, GFP_KERNEL);
- if (!field->type)
- goto err;
+ field->name = name;
+ field->type = type;
if (filter_type == FILTER_OTHER)
field->filter_type = filter_assign_type(type);
@@ -76,9 +116,7 @@ static int __trace_define_field(struct list_head *head, const char *type,
return 0;
err:
- if (field)
- kfree(field->name);
- kfree(field);
+ kmem_cache_free(field_cachep, field);
return -ENOMEM;
}
@@ -120,7 +158,7 @@ static int trace_define_common_fields(void)
return ret;
}
-void trace_destroy_fields(struct ftrace_event_call *call)
+static void trace_destroy_fields(struct ftrace_event_call *call)
{
struct ftrace_event_field *field, *next;
struct list_head *head;
@@ -128,9 +166,7 @@ void trace_destroy_fields(struct ftrace_event_call *call)
head = trace_get_fields(call);
list_for_each_entry_safe(field, next, head, link) {
list_del(&field->link);
- kfree(field->type);
- kfree(field->name);
- kfree(field);
+ kmem_cache_free(field_cachep, field);
}
}
@@ -149,15 +185,17 @@ EXPORT_SYMBOL_GPL(trace_event_raw_init);
int ftrace_event_reg(struct ftrace_event_call *call,
enum trace_reg type, void *data)
{
+ struct ftrace_event_file *file = data;
+
switch (type) {
case TRACE_REG_REGISTER:
return tracepoint_probe_register(call->name,
call->class->probe,
- call);
+ file);
case TRACE_REG_UNREGISTER:
tracepoint_probe_unregister(call->name,
call->class->probe,
- call);
+ file);
return 0;
#ifdef CONFIG_PERF_EVENTS
@@ -183,54 +221,100 @@ EXPORT_SYMBOL_GPL(ftrace_event_reg);
void trace_event_enable_cmd_record(bool enable)
{
- struct ftrace_event_call *call;
+ struct ftrace_event_file *file;
+ struct trace_array *tr;
mutex_lock(&event_mutex);
- list_for_each_entry(call, &ftrace_events, list) {
- if (!(call->flags & TRACE_EVENT_FL_ENABLED))
+ do_for_each_event_file(tr, file) {
+
+ if (!(file->flags & FTRACE_EVENT_FL_ENABLED))
continue;
if (enable) {
tracing_start_cmdline_record();
- call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
+ set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
} else {
tracing_stop_cmdline_record();
- call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
+ clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
}
- }
+ } while_for_each_event_file();
mutex_unlock(&event_mutex);
}
-static int ftrace_event_enable_disable(struct ftrace_event_call *call,
- int enable)
+static int __ftrace_event_enable_disable(struct ftrace_event_file *file,
+ int enable, int soft_disable)
{
+ struct ftrace_event_call *call = file->event_call;
int ret = 0;
+ int disable;
switch (enable) {
case 0:
- if (call->flags & TRACE_EVENT_FL_ENABLED) {
- call->flags &= ~TRACE_EVENT_FL_ENABLED;
- if (call->flags & TRACE_EVENT_FL_RECORDED_CMD) {
+ /*
+ * When soft_disable is set and enable is cleared, we want
+ * to clear the SOFT_DISABLED flag but leave the event in the
+ * state that it was. That is, if the event was enabled and
+ * SOFT_DISABLED isn't set, then do nothing. But if SOFT_DISABLED
+ * is set we do not want the event to be enabled before we
+ * clear the bit.
+ *
+ * When soft_disable is not set but the SOFT_MODE flag is,
+ * we do nothing. Do not disable the tracepoint, otherwise
+ * "soft enable"s (clearing the SOFT_DISABLED bit) wont work.
+ */
+ if (soft_disable) {
+ disable = file->flags & FTRACE_EVENT_FL_SOFT_DISABLED;
+ clear_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
+ } else
+ disable = !(file->flags & FTRACE_EVENT_FL_SOFT_MODE);
+
+ if (disable && (file->flags & FTRACE_EVENT_FL_ENABLED)) {
+ clear_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
+ if (file->flags & FTRACE_EVENT_FL_RECORDED_CMD) {
tracing_stop_cmdline_record();
- call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
+ clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
}
- call->class->reg(call, TRACE_REG_UNREGISTER, NULL);
+ call->class->reg(call, TRACE_REG_UNREGISTER, file);
}
+ /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT */
+ if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
+ set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
break;
case 1:
- if (!(call->flags & TRACE_EVENT_FL_ENABLED)) {
+ /*
+ * When soft_disable is set and enable is set, we want to
+ * register the tracepoint for the event, but leave the event
+ * as is. That means, if the event was already enabled, we do
+ * nothing (but set SOFT_MODE). If the event is disabled, we
+ * set SOFT_DISABLED before enabling the event tracepoint, so
+ * it still seems to be disabled.
+ */
+ if (!soft_disable)
+ clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
+ else
+ set_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
+
+ if (!(file->flags & FTRACE_EVENT_FL_ENABLED)) {
+
+ /* Keep the event disabled, when going to SOFT_MODE. */
+ if (soft_disable)
+ set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
+
if (trace_flags & TRACE_ITER_RECORD_CMD) {
tracing_start_cmdline_record();
- call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
+ set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
}
- ret = call->class->reg(call, TRACE_REG_REGISTER, NULL);
+ ret = call->class->reg(call, TRACE_REG_REGISTER, file);
if (ret) {
tracing_stop_cmdline_record();
pr_info("event trace: Could not enable event "
"%s\n", call->name);
break;
}
- call->flags |= TRACE_EVENT_FL_ENABLED;
+ set_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
+
+ /* WAS_ENABLED gets set but never cleared. */
+ call->flags |= TRACE_EVENT_FL_WAS_ENABLED;
}
break;
}
@@ -238,13 +322,19 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
return ret;
}
-static void ftrace_clear_events(void)
+static int ftrace_event_enable_disable(struct ftrace_event_file *file,
+ int enable)
{
- struct ftrace_event_call *call;
+ return __ftrace_event_enable_disable(file, enable, 0);
+}
+
+static void ftrace_clear_events(struct trace_array *tr)
+{
+ struct ftrace_event_file *file;
mutex_lock(&event_mutex);
- list_for_each_entry(call, &ftrace_events, list) {
- ftrace_event_enable_disable(call, 0);
+ list_for_each_entry(file, &tr->events, list) {
+ ftrace_event_enable_disable(file, 0);
}
mutex_unlock(&event_mutex);
}
@@ -257,11 +347,12 @@ static void __put_system(struct event_subsystem *system)
if (--system->ref_count)
return;
+ list_del(&system->list);
+
if (filter) {
kfree(filter->filter_string);
kfree(filter);
}
- kfree(system->name);
kfree(system);
}
@@ -271,24 +362,45 @@ static void __get_system(struct event_subsystem *system)
system->ref_count++;
}
-static void put_system(struct event_subsystem *system)
+static void __get_system_dir(struct ftrace_subsystem_dir *dir)
+{
+ WARN_ON_ONCE(dir->ref_count == 0);
+ dir->ref_count++;
+ __get_system(dir->subsystem);
+}
+
+static void __put_system_dir(struct ftrace_subsystem_dir *dir)
+{
+ WARN_ON_ONCE(dir->ref_count == 0);
+ /* If the subsystem is about to be freed, the dir must be too */
+ WARN_ON_ONCE(dir->subsystem->ref_count == 1 && dir->ref_count != 1);
+
+ __put_system(dir->subsystem);
+ if (!--dir->ref_count)
+ kfree(dir);
+}
+
+static void put_system(struct ftrace_subsystem_dir *dir)
{
mutex_lock(&event_mutex);
- __put_system(system);
+ __put_system_dir(dir);
mutex_unlock(&event_mutex);
}
/*
* __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
*/
-static int __ftrace_set_clr_event(const char *match, const char *sub,
- const char *event, int set)
+static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
+ const char *sub, const char *event, int set)
{
+ struct ftrace_event_file *file;
struct ftrace_event_call *call;
int ret = -EINVAL;
mutex_lock(&event_mutex);
- list_for_each_entry(call, &ftrace_events, list) {
+ list_for_each_entry(file, &tr->events, list) {
+
+ call = file->event_call;
if (!call->name || !call->class || !call->class->reg)
continue;
@@ -307,7 +419,7 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
if (event && strcmp(event, call->name) != 0)
continue;
- ftrace_event_enable_disable(call, set);
+ ftrace_event_enable_disable(file, set);
ret = 0;
}
@@ -316,7 +428,7 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
return ret;
}
-static int ftrace_set_clr_event(char *buf, int set)
+static int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set)
{
char *event = NULL, *sub = NULL, *match;
@@ -344,7 +456,7 @@ static int ftrace_set_clr_event(char *buf, int set)
event = NULL;
}
- return __ftrace_set_clr_event(match, sub, event, set);
+ return __ftrace_set_clr_event(tr, match, sub, event, set);
}
/**
@@ -361,7 +473,9 @@ static int ftrace_set_clr_event(char *buf, int set)
*/
int trace_set_clr_event(const char *system, const char *event, int set)
{
- return __ftrace_set_clr_event(NULL, system, event, set);
+ struct trace_array *tr = top_trace_array();
+
+ return __ftrace_set_clr_event(tr, NULL, system, event, set);
}
EXPORT_SYMBOL_GPL(trace_set_clr_event);
@@ -373,6 +487,8 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct trace_parser parser;
+ struct seq_file *m = file->private_data;
+ struct trace_array *tr = m->private;
ssize_t read, ret;
if (!cnt)
@@ -395,7 +511,7 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
parser.buffer[parser.idx] = 0;
- ret = ftrace_set_clr_event(parser.buffer + !set, set);
+ ret = ftrace_set_clr_event(tr, parser.buffer + !set, set);
if (ret)
goto out_put;
}
@@ -411,17 +527,20 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
static void *
t_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct ftrace_event_call *call = v;
+ struct ftrace_event_file *file = v;
+ struct ftrace_event_call *call;
+ struct trace_array *tr = m->private;
(*pos)++;
- list_for_each_entry_continue(call, &ftrace_events, list) {
+ list_for_each_entry_continue(file, &tr->events, list) {
+ call = file->event_call;
/*
* The ftrace subsystem is for showing formats only.
* They can not be enabled or disabled via the event files.
*/
if (call->class && call->class->reg)
- return call;
+ return file;
}
return NULL;
@@ -429,30 +548,32 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
static void *t_start(struct seq_file *m, loff_t *pos)
{
- struct ftrace_event_call *call;
+ struct ftrace_event_file *file;
+ struct trace_array *tr = m->private;
loff_t l;
mutex_lock(&event_mutex);
- call = list_entry(&ftrace_events, struct ftrace_event_call, list);
+ file = list_entry(&tr->events, struct ftrace_event_file, list);
for (l = 0; l <= *pos; ) {
- call = t_next(m, call, &l);
- if (!call)
+ file = t_next(m, file, &l);
+ if (!file)
break;
}
- return call;
+ return file;
}
static void *
s_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct ftrace_event_call *call = v;
+ struct ftrace_event_file *file = v;
+ struct trace_array *tr = m->private;
(*pos)++;
- list_for_each_entry_continue(call, &ftrace_events, list) {
- if (call->flags & TRACE_EVENT_FL_ENABLED)
- return call;
+ list_for_each_entry_continue(file, &tr->events, list) {
+ if (file->flags & FTRACE_EVENT_FL_ENABLED)
+ return file;
}
return NULL;
@@ -460,23 +581,25 @@ s_next(struct seq_file *m, void *v, loff_t *pos)
static void *s_start(struct seq_file *m, loff_t *pos)
{
- struct ftrace_event_call *call;
+ struct ftrace_event_file *file;
+ struct trace_array *tr = m->private;
loff_t l;
mutex_lock(&event_mutex);
- call = list_entry(&ftrace_events, struct ftrace_event_call, list);
+ file = list_entry(&tr->events, struct ftrace_event_file, list);
for (l = 0; l <= *pos; ) {
- call = s_next(m, call, &l);
- if (!call)
+ file = s_next(m, file, &l);
+ if (!file)
break;
}
- return call;
+ return file;
}
static int t_show(struct seq_file *m, void *v)
{
- struct ftrace_event_call *call = v;
+ struct ftrace_event_file *file = v;
+ struct ftrace_event_call *call = file->event_call;
if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
seq_printf(m, "%s:", call->class->system);
@@ -494,25 +617,31 @@ static ssize_t
event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- struct ftrace_event_call *call = filp->private_data;
+ struct ftrace_event_file *file = filp->private_data;
char *buf;
- if (call->flags & TRACE_EVENT_FL_ENABLED)
- buf = "1\n";
- else
+ if (file->flags & FTRACE_EVENT_FL_ENABLED) {
+ if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)
+ buf = "0*\n";
+ else
+ buf = "1\n";
+ } else
buf = "0\n";
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf));
}
static ssize_t
event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- struct ftrace_event_call *call = filp->private_data;
+ struct ftrace_event_file *file = filp->private_data;
unsigned long val;
int ret;
+ if (!file)
+ return -EINVAL;
+
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
if (ret)
return ret;
@@ -525,7 +654,7 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
case 0:
case 1:
mutex_lock(&event_mutex);
- ret = ftrace_event_enable_disable(call, val);
+ ret = ftrace_event_enable_disable(file, val);
mutex_unlock(&event_mutex);
break;
@@ -543,14 +672,18 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
const char set_to_char[4] = { '?', '0', '1', 'X' };
- struct event_subsystem *system = filp->private_data;
+ struct ftrace_subsystem_dir *dir = filp->private_data;
+ struct event_subsystem *system = dir->subsystem;
struct ftrace_event_call *call;
+ struct ftrace_event_file *file;
+ struct trace_array *tr = dir->tr;
char buf[2];
int set = 0;
int ret;
mutex_lock(&event_mutex);
- list_for_each_entry(call, &ftrace_events, list) {
+ list_for_each_entry(file, &tr->events, list) {
+ call = file->event_call;
if (!call->name || !call->class || !call->class->reg)
continue;
@@ -562,7 +695,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
* or if all events or cleared, or if we have
* a mixture.
*/
- set |= (1 << !!(call->flags & TRACE_EVENT_FL_ENABLED));
+ set |= (1 << !!(file->flags & FTRACE_EVENT_FL_ENABLED));
/*
* If we have a mixture, no need to look further.
@@ -584,7 +717,8 @@ static ssize_t
system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- struct event_subsystem *system = filp->private_data;
+ struct ftrace_subsystem_dir *dir = filp->private_data;
+ struct event_subsystem *system = dir->subsystem;
const char *name = NULL;
unsigned long val;
ssize_t ret;
@@ -607,7 +741,7 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (system)
name = system->name;
- ret = __ftrace_set_clr_event(NULL, name, NULL, val);
+ ret = __ftrace_set_clr_event(dir->tr, NULL, name, NULL, val);
if (ret)
goto out;
@@ -845,43 +979,75 @@ static LIST_HEAD(event_subsystems);
static int subsystem_open(struct inode *inode, struct file *filp)
{
struct event_subsystem *system = NULL;
+ struct ftrace_subsystem_dir *dir = NULL; /* Initialize for gcc */
+ struct trace_array *tr;
int ret;
- if (!inode->i_private)
- goto skip_search;
-
/* Make sure the system still exists */
mutex_lock(&event_mutex);
- list_for_each_entry(system, &event_subsystems, list) {
- if (system == inode->i_private) {
- /* Don't open systems with no events */
- if (!system->nr_events) {
- system = NULL;
- break;
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ list_for_each_entry(dir, &tr->systems, list) {
+ if (dir == inode->i_private) {
+ /* Don't open systems with no events */
+ if (dir->nr_events) {
+ __get_system_dir(dir);
+ system = dir->subsystem;
+ }
+ goto exit_loop;
}
- __get_system(system);
- break;
}
}
+ exit_loop:
mutex_unlock(&event_mutex);
- if (system != inode->i_private)
+ if (!system)
return -ENODEV;
- skip_search:
+ /* Some versions of gcc think dir can be uninitialized here */
+ WARN_ON(!dir);
+
ret = tracing_open_generic(inode, filp);
- if (ret < 0 && system)
- put_system(system);
+ if (ret < 0)
+ put_system(dir);
+
+ return ret;
+}
+
+static int system_tr_open(struct inode *inode, struct file *filp)
+{
+ struct ftrace_subsystem_dir *dir;
+ struct trace_array *tr = inode->i_private;
+ int ret;
+
+ /* Make a temporary dir that has no system but points to tr */
+ dir = kzalloc(sizeof(*dir), GFP_KERNEL);
+ if (!dir)
+ return -ENOMEM;
+
+ dir->tr = tr;
+
+ ret = tracing_open_generic(inode, filp);
+ if (ret < 0)
+ kfree(dir);
+
+ filp->private_data = dir;
return ret;
}
static int subsystem_release(struct inode *inode, struct file *file)
{
- struct event_subsystem *system = inode->i_private;
+ struct ftrace_subsystem_dir *dir = file->private_data;
- if (system)
- put_system(system);
+ /*
+ * If dir->subsystem is NULL, then this is a temporary
+ * descriptor that was made for a trace_array to enable
+ * all subsystems.
+ */
+ if (dir->subsystem)
+ put_system(dir);
+ else
+ kfree(dir);
return 0;
}
@@ -890,7 +1056,8 @@ static ssize_t
subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- struct event_subsystem *system = filp->private_data;
+ struct ftrace_subsystem_dir *dir = filp->private_data;
+ struct event_subsystem *system = dir->subsystem;
struct trace_seq *s;
int r;
@@ -915,7 +1082,7 @@ static ssize_t
subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
- struct event_subsystem *system = filp->private_data;
+ struct ftrace_subsystem_dir *dir = filp->private_data;
char *buf;
int err;
@@ -932,7 +1099,7 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
}
buf[cnt] = '\0';
- err = apply_subsystem_event_filter(system, buf);
+ err = apply_subsystem_event_filter(dir, buf);
free_page((unsigned long) buf);
if (err < 0)
return err;
@@ -1041,30 +1208,35 @@ static const struct file_operations ftrace_system_enable_fops = {
.release = subsystem_release,
};
+static const struct file_operations ftrace_tr_enable_fops = {
+ .open = system_tr_open,
+ .read = system_enable_read,
+ .write = system_enable_write,
+ .llseek = default_llseek,
+ .release = subsystem_release,
+};
+
static const struct file_operations ftrace_show_header_fops = {
.open = tracing_open_generic,
.read = show_header,
.llseek = default_llseek,
};
-static struct dentry *event_trace_events_dir(void)
+static int
+ftrace_event_open(struct inode *inode, struct file *file,
+ const struct seq_operations *seq_ops)
{
- static struct dentry *d_tracer;
- static struct dentry *d_events;
-
- if (d_events)
- return d_events;
-
- d_tracer = tracing_init_dentry();
- if (!d_tracer)
- return NULL;
+ struct seq_file *m;
+ int ret;
- d_events = debugfs_create_dir("events", d_tracer);
- if (!d_events)
- pr_warning("Could not create debugfs "
- "'events' directory\n");
+ ret = seq_open(file, seq_ops);
+ if (ret < 0)
+ return ret;
+ m = file->private_data;
+ /* copy tr over to seq ops */
+ m->private = inode->i_private;
- return d_events;
+ return ret;
}
static int
@@ -1072,117 +1244,165 @@ ftrace_event_avail_open(struct inode *inode, struct file *file)
{
const struct seq_operations *seq_ops = &show_event_seq_ops;
- return seq_open(file, seq_ops);
+ return ftrace_event_open(inode, file, seq_ops);
}
static int
ftrace_event_set_open(struct inode *inode, struct file *file)
{
const struct seq_operations *seq_ops = &show_set_event_seq_ops;
+ struct trace_array *tr = inode->i_private;
if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC))
- ftrace_clear_events();
+ ftrace_clear_events(tr);
- return seq_open(file, seq_ops);
+ return ftrace_event_open(inode, file, seq_ops);
+}
+
+static struct event_subsystem *
+create_new_subsystem(const char *name)
+{
+ struct event_subsystem *system;
+
+ /* need to create new entry */
+ system = kmalloc(sizeof(*system), GFP_KERNEL);
+ if (!system)
+ return NULL;
+
+ system->ref_count = 1;
+ system->name = name;
+
+ system->filter = NULL;
+
+ system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
+ if (!system->filter)
+ goto out_free;
+
+ list_add(&system->list, &event_subsystems);
+
+ return system;
+
+ out_free:
+ kfree(system);
+ return NULL;
}
static struct dentry *
-event_subsystem_dir(const char *name, struct dentry *d_events)
+event_subsystem_dir(struct trace_array *tr, const char *name,
+ struct ftrace_event_file *file, struct dentry *parent)
{
+ struct ftrace_subsystem_dir *dir;
struct event_subsystem *system;
struct dentry *entry;
/* First see if we did not already create this dir */
- list_for_each_entry(system, &event_subsystems, list) {
+ list_for_each_entry(dir, &tr->systems, list) {
+ system = dir->subsystem;
if (strcmp(system->name, name) == 0) {
- system->nr_events++;
- return system->entry;
+ dir->nr_events++;
+ file->system = dir;
+ return dir->entry;
}
}
- /* need to create new entry */
- system = kmalloc(sizeof(*system), GFP_KERNEL);
- if (!system) {
- pr_warning("No memory to create event subsystem %s\n",
- name);
- return d_events;
+ /* Now see if the system itself exists. */
+ list_for_each_entry(system, &event_subsystems, list) {
+ if (strcmp(system->name, name) == 0)
+ break;
}
+ /* Reset system variable when not found */
+ if (&system->list == &event_subsystems)
+ system = NULL;
- system->entry = debugfs_create_dir(name, d_events);
- if (!system->entry) {
- pr_warning("Could not create event subsystem %s\n",
- name);
- kfree(system);
- return d_events;
- }
+ dir = kmalloc(sizeof(*dir), GFP_KERNEL);
+ if (!dir)
+ goto out_fail;
- system->nr_events = 1;
- system->ref_count = 1;
- system->name = kstrdup(name, GFP_KERNEL);
- if (!system->name) {
- debugfs_remove(system->entry);
- kfree(system);
- return d_events;
+ if (!system) {
+ system = create_new_subsystem(name);
+ if (!system)
+ goto out_free;
+ } else
+ __get_system(system);
+
+ dir->entry = debugfs_create_dir(name, parent);
+ if (!dir->entry) {
+ pr_warning("Failed to create system directory %s\n", name);
+ __put_system(system);
+ goto out_free;
}
- list_add(&system->list, &event_subsystems);
-
- system->filter = NULL;
-
- system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL);
- if (!system->filter) {
- pr_warning("Could not allocate filter for subsystem "
- "'%s'\n", name);
- return system->entry;
- }
+ dir->tr = tr;
+ dir->ref_count = 1;
+ dir->nr_events = 1;
+ dir->subsystem = system;
+ file->system = dir;
- entry = debugfs_create_file("filter", 0644, system->entry, system,
+ entry = debugfs_create_file("filter", 0644, dir->entry, dir,
&ftrace_subsystem_filter_fops);
if (!entry) {
kfree(system->filter);
system->filter = NULL;
- pr_warning("Could not create debugfs "
- "'%s/filter' entry\n", name);
+ pr_warning("Could not create debugfs '%s/filter' entry\n", name);
}
- trace_create_file("enable", 0644, system->entry, system,
+ trace_create_file("enable", 0644, dir->entry, dir,
&ftrace_system_enable_fops);
- return system->entry;
+ list_add(&dir->list, &tr->systems);
+
+ return dir->entry;
+
+ out_free:
+ kfree(dir);
+ out_fail:
+ /* Only print this message if failed on memory allocation */
+ if (!dir || !system)
+ pr_warning("No memory to create event subsystem %s\n",
+ name);
+ return NULL;
}
static int
-event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
+event_create_dir(struct dentry *parent,
+ struct ftrace_event_file *file,
const struct file_operations *id,
const struct file_operations *enable,
const struct file_operations *filter,
const struct file_operations *format)
{
+ struct ftrace_event_call *call = file->event_call;
+ struct trace_array *tr = file->tr;
struct list_head *head;
+ struct dentry *d_events;
int ret;
/*
* If the trace point header did not define TRACE_SYSTEM
* then the system would be called "TRACE_SYSTEM".
*/
- if (strcmp(call->class->system, TRACE_SYSTEM) != 0)
- d_events = event_subsystem_dir(call->class->system, d_events);
-
- call->dir = debugfs_create_dir(call->name, d_events);
- if (!call->dir) {
- pr_warning("Could not create debugfs "
- "'%s' directory\n", call->name);
+ if (strcmp(call->class->system, TRACE_SYSTEM) != 0) {
+ d_events = event_subsystem_dir(tr, call->class->system, file, parent);
+ if (!d_events)
+ return -ENOMEM;
+ } else
+ d_events = parent;
+
+ file->dir = debugfs_create_dir(call->name, d_events);
+ if (!file->dir) {
+ pr_warning("Could not create debugfs '%s' directory\n",
+ call->name);
return -1;
}
if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
- trace_create_file("enable", 0644, call->dir, call,
+ trace_create_file("enable", 0644, file->dir, file,
enable);
#ifdef CONFIG_PERF_EVENTS
if (call->event.type && call->class->reg)
- trace_create_file("id", 0444, call->dir, call,
+ trace_create_file("id", 0444, file->dir, call,
id);
#endif
@@ -1196,23 +1416,76 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
if (ret < 0) {
pr_warning("Could not initialize trace point"
" events/%s\n", call->name);
- return ret;
+ return -1;
}
}
- trace_create_file("filter", 0644, call->dir, call,
+ trace_create_file("filter", 0644, file->dir, call,
filter);
- trace_create_file("format", 0444, call->dir, call,
+ trace_create_file("format", 0444, file->dir, call,
format);
return 0;
}
+static void remove_subsystem(struct ftrace_subsystem_dir *dir)
+{
+ if (!dir)
+ return;
+
+ if (!--dir->nr_events) {
+ debugfs_remove_recursive(dir->entry);
+ list_del(&dir->list);
+ __put_system_dir(dir);
+ }
+}
+
+static void remove_event_from_tracers(struct ftrace_event_call *call)
+{
+ struct ftrace_event_file *file;
+ struct trace_array *tr;
+
+ do_for_each_event_file_safe(tr, file) {
+
+ if (file->event_call != call)
+ continue;
+
+ list_del(&file->list);
+ debugfs_remove_recursive(file->dir);
+ remove_subsystem(file->system);
+ kmem_cache_free(file_cachep, file);
+
+ /*
+ * The do_for_each_event_file_safe() is
+ * a double loop. After finding the call for this
+ * trace_array, we use break to jump to the next
+ * trace_array.
+ */
+ break;
+ } while_for_each_event_file();
+}
+
static void event_remove(struct ftrace_event_call *call)
{
- ftrace_event_enable_disable(call, 0);
+ struct trace_array *tr;
+ struct ftrace_event_file *file;
+
+ do_for_each_event_file(tr, file) {
+ if (file->event_call != call)
+ continue;
+ ftrace_event_enable_disable(file, 0);
+ /*
+ * The do_for_each_event_file() is
+ * a double loop. After finding the call for this
+ * trace_array, we use break to jump to the next
+ * trace_array.
+ */
+ break;
+ } while_for_each_event_file();
+
if (call->event.funcs)
__unregister_ftrace_event(&call->event);
+ remove_event_from_tracers(call);
list_del(&call->list);
}
@@ -1234,82 +1507,99 @@ static int event_init(struct ftrace_event_call *call)
}
static int
-__trace_add_event_call(struct ftrace_event_call *call, struct module *mod,
- const struct file_operations *id,
- const struct file_operations *enable,
- const struct file_operations *filter,
- const struct file_operations *format)
+__register_event(struct ftrace_event_call *call, struct module *mod)
{
- struct dentry *d_events;
int ret;
ret = event_init(call);
if (ret < 0)
return ret;
- d_events = event_trace_events_dir();
- if (!d_events)
- return -ENOENT;
-
- ret = event_create_dir(call, d_events, id, enable, filter, format);
- if (!ret)
- list_add(&call->list, &ftrace_events);
+ list_add(&call->list, &ftrace_events);
call->mod = mod;
- return ret;
+ return 0;
+}
+
+/* Add an event to a trace directory */
+static int
+__trace_add_new_event(struct ftrace_event_call *call,
+ struct trace_array *tr,
+ const struct file_operations *id,
+ const struct file_operations *enable,
+ const struct file_operations *filter,
+ const struct file_operations *format)
+{
+ struct ftrace_event_file *file;
+
+ file = kmem_cache_alloc(file_cachep, GFP_TRACE);
+ if (!file)
+ return -ENOMEM;
+
+ file->event_call = call;
+ file->tr = tr;
+ list_add(&file->list, &tr->events);
+
+ return event_create_dir(tr->event_dir, file, id, enable, filter, format);
}
+/*
+ * Just create a decriptor for early init. A descriptor is required
+ * for enabling events at boot. We want to enable events before
+ * the filesystem is initialized.
+ */
+static __init int
+__trace_early_add_new_event(struct ftrace_event_call *call,
+ struct trace_array *tr)
+{
+ struct ftrace_event_file *file;
+
+ file = kmem_cache_alloc(file_cachep, GFP_TRACE);
+ if (!file)
+ return -ENOMEM;
+
+ file->event_call = call;
+ file->tr = tr;
+ list_add(&file->list, &tr->events);
+
+ return 0;
+}
+
+struct ftrace_module_file_ops;
+static void __add_event_to_tracers(struct ftrace_event_call *call,
+ struct ftrace_module_file_ops *file_ops);
+
/* Add an additional event_call dynamically */
int trace_add_event_call(struct ftrace_event_call *call)
{
int ret;
mutex_lock(&event_mutex);
- ret = __trace_add_event_call(call, NULL, &ftrace_event_id_fops,
- &ftrace_enable_fops,
- &ftrace_event_filter_fops,
- &ftrace_event_format_fops);
- mutex_unlock(&event_mutex);
- return ret;
-}
-static void remove_subsystem_dir(const char *name)
-{
- struct event_subsystem *system;
-
- if (strcmp(name, TRACE_SYSTEM) == 0)
- return;
+ ret = __register_event(call, NULL);
+ if (ret >= 0)
+ __add_event_to_tracers(call, NULL);
- list_for_each_entry(system, &event_subsystems, list) {
- if (strcmp(system->name, name) == 0) {
- if (!--system->nr_events) {
- debugfs_remove_recursive(system->entry);
- list_del(&system->list);
- __put_system(system);
- }
- break;
- }
- }
+ mutex_unlock(&event_mutex);
+ return ret;
}
/*
- * Must be called under locking both of event_mutex and trace_event_mutex.
+ * Must be called under locking both of event_mutex and trace_event_sem.
*/
static void __trace_remove_event_call(struct ftrace_event_call *call)
{
event_remove(call);
trace_destroy_fields(call);
destroy_preds(call);
- debugfs_remove_recursive(call->dir);
- remove_subsystem_dir(call->class->system);
}
/* Remove an event_call */
void trace_remove_event_call(struct ftrace_event_call *call)
{
mutex_lock(&event_mutex);
- down_write(&trace_event_mutex);
+ down_write(&trace_event_sem);
__trace_remove_event_call(call);
- up_write(&trace_event_mutex);
+ up_write(&trace_event_sem);
mutex_unlock(&event_mutex);
}
@@ -1336,6 +1626,26 @@ struct ftrace_module_file_ops {
};
static struct ftrace_module_file_ops *
+find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
+{
+ /*
+ * As event_calls are added in groups by module,
+ * when we find one file_ops, we don't need to search for
+ * each call in that module, as the rest should be the
+ * same. Only search for a new one if the last one did
+ * not match.
+ */
+ if (file_ops && mod == file_ops->mod)
+ return file_ops;
+
+ list_for_each_entry(file_ops, &ftrace_module_file_list, list) {
+ if (file_ops->mod == mod)
+ return file_ops;
+ }
+ return NULL;
+}
+
+static struct ftrace_module_file_ops *
trace_create_file_ops(struct module *mod)
{
struct ftrace_module_file_ops *file_ops;
@@ -1386,9 +1696,8 @@ static void trace_module_add_events(struct module *mod)
return;
for_each_event(call, start, end) {
- __trace_add_event_call(*call, mod,
- &file_ops->id, &file_ops->enable,
- &file_ops->filter, &file_ops->format);
+ __register_event(*call, mod);
+ __add_event_to_tracers(*call, file_ops);
}
}
@@ -1396,12 +1705,13 @@ static void trace_module_remove_events(struct module *mod)
{
struct ftrace_module_file_ops *file_ops;
struct ftrace_event_call *call, *p;
- bool found = false;
+ bool clear_trace = false;
- down_write(&trace_event_mutex);
+ down_write(&trace_event_sem);
list_for_each_entry_safe(call, p, &ftrace_events, list) {
if (call->mod == mod) {
- found = true;
+ if (call->flags & TRACE_EVENT_FL_WAS_ENABLED)
+ clear_trace = true;
__trace_remove_event_call(call);
}
}
@@ -1415,14 +1725,18 @@ static void trace_module_remove_events(struct module *mod)
list_del(&file_ops->list);
kfree(file_ops);
}
+ up_write(&trace_event_sem);
/*
* It is safest to reset the ring buffer if the module being unloaded
- * registered any events.
+ * registered any events that were used. The only worry is if
+ * a new module gets loaded, and takes on the same id as the events
+ * of this module. When printing out the buffer, traced events left
+ * over from this module may be passed to the new module events and
+ * unexpected results may occur.
*/
- if (found)
- tracing_reset_current_online_cpus();
- up_write(&trace_event_mutex);
+ if (clear_trace)
+ tracing_reset_all_online_cpus();
}
static int trace_module_notify(struct notifier_block *self,
@@ -1443,14 +1757,433 @@ static int trace_module_notify(struct notifier_block *self,
return 0;
}
+
+static int
+__trace_add_new_mod_event(struct ftrace_event_call *call,
+ struct trace_array *tr,
+ struct ftrace_module_file_ops *file_ops)
+{
+ return __trace_add_new_event(call, tr,
+ &file_ops->id, &file_ops->enable,
+ &file_ops->filter, &file_ops->format);
+}
+
#else
-static int trace_module_notify(struct notifier_block *self,
- unsigned long val, void *data)
+static inline struct ftrace_module_file_ops *
+find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
+{
+ return NULL;
+}
+static inline int trace_module_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
return 0;
}
+static inline int
+__trace_add_new_mod_event(struct ftrace_event_call *call,
+ struct trace_array *tr,
+ struct ftrace_module_file_ops *file_ops)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_MODULES */
+/* Create a new event directory structure for a trace directory. */
+static void
+__trace_add_event_dirs(struct trace_array *tr)
+{
+ struct ftrace_module_file_ops *file_ops = NULL;
+ struct ftrace_event_call *call;
+ int ret;
+
+ list_for_each_entry(call, &ftrace_events, list) {
+ if (call->mod) {
+ /*
+ * Directories for events by modules need to
+ * keep module ref counts when opened (as we don't
+ * want the module to disappear when reading one
+ * of these files). The file_ops keep account of
+ * the module ref count.
+ */
+ file_ops = find_ftrace_file_ops(file_ops, call->mod);
+ if (!file_ops)
+ continue; /* Warn? */
+ ret = __trace_add_new_mod_event(call, tr, file_ops);
+ if (ret < 0)
+ pr_warning("Could not create directory for event %s\n",
+ call->name);
+ continue;
+ }
+ ret = __trace_add_new_event(call, tr,
+ &ftrace_event_id_fops,
+ &ftrace_enable_fops,
+ &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
+ if (ret < 0)
+ pr_warning("Could not create directory for event %s\n",
+ call->name);
+ }
+}
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+/* Avoid typos */
+#define ENABLE_EVENT_STR "enable_event"
+#define DISABLE_EVENT_STR "disable_event"
+
+struct event_probe_data {
+ struct ftrace_event_file *file;
+ unsigned long count;
+ int ref;
+ bool enable;
+};
+
+static struct ftrace_event_file *
+find_event_file(struct trace_array *tr, const char *system, const char *event)
+{
+ struct ftrace_event_file *file;
+ struct ftrace_event_call *call;
+
+ list_for_each_entry(file, &tr->events, list) {
+
+ call = file->event_call;
+
+ if (!call->name || !call->class || !call->class->reg)
+ continue;
+
+ if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
+ continue;
+
+ if (strcmp(event, call->name) == 0 &&
+ strcmp(system, call->class->system) == 0)
+ return file;
+ }
+ return NULL;
+}
+
+static void
+event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
+{
+ struct event_probe_data **pdata = (struct event_probe_data **)_data;
+ struct event_probe_data *data = *pdata;
+
+ if (!data)
+ return;
+
+ if (data->enable)
+ clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
+ else
+ set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
+}
+
+static void
+event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data)
+{
+ struct event_probe_data **pdata = (struct event_probe_data **)_data;
+ struct event_probe_data *data = *pdata;
+
+ if (!data)
+ return;
+
+ if (!data->count)
+ return;
+
+ /* Skip if the event is in a state we want to switch to */
+ if (data->enable == !(data->file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
+ return;
+
+ if (data->count != -1)
+ (data->count)--;
+
+ event_enable_probe(ip, parent_ip, _data);
+}
+
+static int
+event_enable_print(struct seq_file *m, unsigned long ip,
+ struct ftrace_probe_ops *ops, void *_data)
+{
+ struct event_probe_data *data = _data;
+
+ seq_printf(m, "%ps:", (void *)ip);
+
+ seq_printf(m, "%s:%s:%s",
+ data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
+ data->file->event_call->class->system,
+ data->file->event_call->name);
+
+ if (data->count == -1)
+ seq_printf(m, ":unlimited\n");
+ else
+ seq_printf(m, ":count=%ld\n", data->count);
+
+ return 0;
+}
+
+static int
+event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **_data)
+{
+ struct event_probe_data **pdata = (struct event_probe_data **)_data;
+ struct event_probe_data *data = *pdata;
+
+ data->ref++;
+ return 0;
+}
+
+static void
+event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
+ void **_data)
+{
+ struct event_probe_data **pdata = (struct event_probe_data **)_data;
+ struct event_probe_data *data = *pdata;
+
+ if (WARN_ON_ONCE(data->ref <= 0))
+ return;
+
+ data->ref--;
+ if (!data->ref) {
+ /* Remove the SOFT_MODE flag */
+ __ftrace_event_enable_disable(data->file, 0, 1);
+ module_put(data->file->event_call->mod);
+ kfree(data);
+ }
+ *pdata = NULL;
+}
+
+static struct ftrace_probe_ops event_enable_probe_ops = {
+ .func = event_enable_probe,
+ .print = event_enable_print,
+ .init = event_enable_init,
+ .free = event_enable_free,
+};
+
+static struct ftrace_probe_ops event_enable_count_probe_ops = {
+ .func = event_enable_count_probe,
+ .print = event_enable_print,
+ .init = event_enable_init,
+ .free = event_enable_free,
+};
+
+static struct ftrace_probe_ops event_disable_probe_ops = {
+ .func = event_enable_probe,
+ .print = event_enable_print,
+ .init = event_enable_init,
+ .free = event_enable_free,
+};
+
+static struct ftrace_probe_ops event_disable_count_probe_ops = {
+ .func = event_enable_count_probe,
+ .print = event_enable_print,
+ .init = event_enable_init,
+ .free = event_enable_free,
+};
+
+static int
+event_enable_func(struct ftrace_hash *hash,
+ char *glob, char *cmd, char *param, int enabled)
+{
+ struct trace_array *tr = top_trace_array();
+ struct ftrace_event_file *file;
+ struct ftrace_probe_ops *ops;
+ struct event_probe_data *data;
+ const char *system;
+ const char *event;
+ char *number;
+ bool enable;
+ int ret;
+
+ /* hash funcs only work with set_ftrace_filter */
+ if (!enabled)
+ return -EINVAL;
+
+ if (!param)
+ return -EINVAL;
+
+ system = strsep(&param, ":");
+ if (!param)
+ return -EINVAL;
+
+ event = strsep(&param, ":");
+
+ mutex_lock(&event_mutex);
+
+ ret = -EINVAL;
+ file = find_event_file(tr, system, event);
+ if (!file)
+ goto out;
+
+ enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
+
+ if (enable)
+ ops = param ? &event_enable_count_probe_ops : &event_enable_probe_ops;
+ else
+ ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
+
+ if (glob[0] == '!') {
+ unregister_ftrace_function_probe_func(glob+1, ops);
+ ret = 0;
+ goto out;
+ }
+
+ ret = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto out;
+
+ data->enable = enable;
+ data->count = -1;
+ data->file = file;
+
+ if (!param)
+ goto out_reg;
+
+ number = strsep(&param, ":");
+
+ ret = -EINVAL;
+ if (!strlen(number))
+ goto out_free;
+
+ /*
+ * We use the callback data field (which is a pointer)
+ * as our counter.
+ */
+ ret = kstrtoul(number, 0, &data->count);
+ if (ret)
+ goto out_free;
+
+ out_reg:
+ /* Don't let event modules unload while probe registered */
+ ret = try_module_get(file->event_call->mod);
+ if (!ret)
+ goto out_free;
+
+ ret = __ftrace_event_enable_disable(file, 1, 1);
+ if (ret < 0)
+ goto out_put;
+ ret = register_ftrace_function_probe(glob, ops, data);
+ if (!ret)
+ goto out_disable;
+ out:
+ mutex_unlock(&event_mutex);
+ return ret;
+
+ out_disable:
+ __ftrace_event_enable_disable(file, 0, 1);
+ out_put:
+ module_put(file->event_call->mod);
+ out_free:
+ kfree(data);
+ goto out;
+}
+
+static struct ftrace_func_command event_enable_cmd = {
+ .name = ENABLE_EVENT_STR,
+ .func = event_enable_func,
+};
+
+static struct ftrace_func_command event_disable_cmd = {
+ .name = DISABLE_EVENT_STR,
+ .func = event_enable_func,
+};
+
+static __init int register_event_cmds(void)
+{
+ int ret;
+
+ ret = register_ftrace_command(&event_enable_cmd);
+ if (WARN_ON(ret < 0))
+ return ret;
+ ret = register_ftrace_command(&event_disable_cmd);
+ if (WARN_ON(ret < 0))
+ unregister_ftrace_command(&event_enable_cmd);
+ return ret;
+}
+#else
+static inline int register_event_cmds(void) { return 0; }
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * The top level array has already had its ftrace_event_file
+ * descriptors created in order to allow for early events to
+ * be recorded. This function is called after the debugfs has been
+ * initialized, and we now have to create the files associated
+ * to the events.
+ */
+static __init void
+__trace_early_add_event_dirs(struct trace_array *tr)
+{
+ struct ftrace_event_file *file;
+ int ret;
+
+
+ list_for_each_entry(file, &tr->events, list) {
+ ret = event_create_dir(tr->event_dir, file,
+ &ftrace_event_id_fops,
+ &ftrace_enable_fops,
+ &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
+ if (ret < 0)
+ pr_warning("Could not create directory for event %s\n",
+ file->event_call->name);
+ }
+}
+
+/*
+ * For early boot up, the top trace array requires to have
+ * a list of events that can be enabled. This must be done before
+ * the filesystem is set up in order to allow events to be traced
+ * early.
+ */
+static __init void
+__trace_early_add_events(struct trace_array *tr)
+{
+ struct ftrace_event_call *call;
+ int ret;
+
+ list_for_each_entry(call, &ftrace_events, list) {
+ /* Early boot up should not have any modules loaded */
+ if (WARN_ON_ONCE(call->mod))
+ continue;
+
+ ret = __trace_early_add_new_event(call, tr);
+ if (ret < 0)
+ pr_warning("Could not create early event %s\n",
+ call->name);
+ }
+}
+
+/* Remove the event directory structure for a trace directory. */
+static void
+__trace_remove_event_dirs(struct trace_array *tr)
+{
+ struct ftrace_event_file *file, *next;
+
+ list_for_each_entry_safe(file, next, &tr->events, list) {
+ list_del(&file->list);
+ debugfs_remove_recursive(file->dir);
+ remove_subsystem(file->system);
+ kmem_cache_free(file_cachep, file);
+ }
+}
+
+static void
+__add_event_to_tracers(struct ftrace_event_call *call,
+ struct ftrace_module_file_ops *file_ops)
+{
+ struct trace_array *tr;
+
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ if (file_ops)
+ __trace_add_new_mod_event(call, tr, file_ops);
+ else
+ __trace_add_new_event(call, tr,
+ &ftrace_event_id_fops,
+ &ftrace_enable_fops,
+ &ftrace_event_filter_fops,
+ &ftrace_event_format_fops);
+ }
+}
+
static struct notifier_block trace_module_nb = {
.notifier_call = trace_module_notify,
.priority = 0,
@@ -1464,15 +2197,135 @@ static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
static __init int setup_trace_event(char *str)
{
strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
- ring_buffer_expanded = 1;
- tracing_selftest_disabled = 1;
+ ring_buffer_expanded = true;
+ tracing_selftest_disabled = true;
return 1;
}
__setup("trace_event=", setup_trace_event);
+/* Expects to have event_mutex held when called */
+static int
+create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
+{
+ struct dentry *d_events;
+ struct dentry *entry;
+
+ entry = debugfs_create_file("set_event", 0644, parent,
+ tr, &ftrace_set_event_fops);
+ if (!entry) {
+ pr_warning("Could not create debugfs 'set_event' entry\n");
+ return -ENOMEM;
+ }
+
+ d_events = debugfs_create_dir("events", parent);
+ if (!d_events) {
+ pr_warning("Could not create debugfs 'events' directory\n");
+ return -ENOMEM;
+ }
+
+ /* ring buffer internal formats */
+ trace_create_file("header_page", 0444, d_events,
+ ring_buffer_print_page_header,
+ &ftrace_show_header_fops);
+
+ trace_create_file("header_event", 0444, d_events,
+ ring_buffer_print_entry_header,
+ &ftrace_show_header_fops);
+
+ trace_create_file("enable", 0644, d_events,
+ tr, &ftrace_tr_enable_fops);
+
+ tr->event_dir = d_events;
+
+ return 0;
+}
+
+/**
+ * event_trace_add_tracer - add a instance of a trace_array to events
+ * @parent: The parent dentry to place the files/directories for events in
+ * @tr: The trace array associated with these events
+ *
+ * When a new instance is created, it needs to set up its events
+ * directory, as well as other files associated with events. It also
+ * creates the event hierachry in the @parent/events directory.
+ *
+ * Returns 0 on success.
+ */
+int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
+{
+ int ret;
+
+ mutex_lock(&event_mutex);
+
+ ret = create_event_toplevel_files(parent, tr);
+ if (ret)
+ goto out_unlock;
+
+ down_write(&trace_event_sem);
+ __trace_add_event_dirs(tr);
+ up_write(&trace_event_sem);
+
+ out_unlock:
+ mutex_unlock(&event_mutex);
+
+ return ret;
+}
+
+/*
+ * The top trace array already had its file descriptors created.
+ * Now the files themselves need to be created.
+ */
+static __init int
+early_event_add_tracer(struct dentry *parent, struct trace_array *tr)
+{
+ int ret;
+
+ mutex_lock(&event_mutex);
+
+ ret = create_event_toplevel_files(parent, tr);
+ if (ret)
+ goto out_unlock;
+
+ down_write(&trace_event_sem);
+ __trace_early_add_event_dirs(tr);
+ up_write(&trace_event_sem);
+
+ out_unlock:
+ mutex_unlock(&event_mutex);
+
+ return ret;
+}
+
+int event_trace_del_tracer(struct trace_array *tr)
+{
+ /* Disable any running events */
+ __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
+
+ mutex_lock(&event_mutex);
+
+ down_write(&trace_event_sem);
+ __trace_remove_event_dirs(tr);
+ debugfs_remove_recursive(tr->event_dir);
+ up_write(&trace_event_sem);
+
+ tr->event_dir = NULL;
+
+ mutex_unlock(&event_mutex);
+
+ return 0;
+}
+
+static __init int event_trace_memsetup(void)
+{
+ field_cachep = KMEM_CACHE(ftrace_event_field, SLAB_PANIC);
+ file_cachep = KMEM_CACHE(ftrace_event_file, SLAB_PANIC);
+ return 0;
+}
+
static __init int event_trace_enable(void)
{
+ struct trace_array *tr = top_trace_array();
struct ftrace_event_call **iter, *call;
char *buf = bootup_event_buf;
char *token;
@@ -1486,6 +2339,14 @@ static __init int event_trace_enable(void)
list_add(&call->list, &ftrace_events);
}
+ /*
+ * We need the top trace array to have a working set of trace
+ * points at early init, before the debug files and directories
+ * are created. Create the file entries now, and attach them
+ * to the actual file dentries later.
+ */
+ __trace_early_add_events(tr);
+
while (true) {
token = strsep(&buf, ",");
@@ -1494,73 +2355,43 @@ static __init int event_trace_enable(void)
if (!*token)
continue;
- ret = ftrace_set_clr_event(token, 1);
+ ret = ftrace_set_clr_event(tr, token, 1);
if (ret)
pr_warn("Failed to enable trace event: %s\n", token);
}
trace_printk_start_comm();
+ register_event_cmds();
+
return 0;
}
static __init int event_trace_init(void)
{
- struct ftrace_event_call *call;
+ struct trace_array *tr;
struct dentry *d_tracer;
struct dentry *entry;
- struct dentry *d_events;
int ret;
+ tr = top_trace_array();
+
d_tracer = tracing_init_dentry();
if (!d_tracer)
return 0;
entry = debugfs_create_file("available_events", 0444, d_tracer,
- NULL, &ftrace_avail_fops);
+ tr, &ftrace_avail_fops);
if (!entry)
pr_warning("Could not create debugfs "
"'available_events' entry\n");
- entry = debugfs_create_file("set_event", 0644, d_tracer,
- NULL, &ftrace_set_event_fops);
- if (!entry)
- pr_warning("Could not create debugfs "
- "'set_event' entry\n");
-
- d_events = event_trace_events_dir();
- if (!d_events)
- return 0;
-
- /* ring buffer internal formats */
- trace_create_file("header_page", 0444, d_events,
- ring_buffer_print_page_header,
- &ftrace_show_header_fops);
-
- trace_create_file("header_event", 0444, d_events,
- ring_buffer_print_entry_header,
- &ftrace_show_header_fops);
-
- trace_create_file("enable", 0644, d_events,
- NULL, &ftrace_system_enable_fops);
-
if (trace_define_common_fields())
pr_warning("tracing: Failed to allocate common fields");
- /*
- * Early initialization already enabled ftrace event.
- * Now it's only necessary to create the event directory.
- */
- list_for_each_entry(call, &ftrace_events, list) {
-
- ret = event_create_dir(call, d_events,
- &ftrace_event_id_fops,
- &ftrace_enable_fops,
- &ftrace_event_filter_fops,
- &ftrace_event_format_fops);
- if (ret < 0)
- event_remove(call);
- }
+ ret = early_event_add_tracer(d_tracer, tr);
+ if (ret)
+ return ret;
ret = register_module_notifier(&trace_module_nb);
if (ret)
@@ -1568,6 +2399,7 @@ static __init int event_trace_init(void)
return 0;
}
+early_initcall(event_trace_memsetup);
core_initcall(event_trace_enable);
fs_initcall(event_trace_init);
@@ -1627,13 +2459,20 @@ static __init void event_test_stuff(void)
*/
static __init void event_trace_self_tests(void)
{
+ struct ftrace_subsystem_dir *dir;
+ struct ftrace_event_file *file;
struct ftrace_event_call *call;
struct event_subsystem *system;
+ struct trace_array *tr;
int ret;
+ tr = top_trace_array();
+
pr_info("Running tests on trace events:\n");
- list_for_each_entry(call, &ftrace_events, list) {
+ list_for_each_entry(file, &tr->events, list) {
+
+ call = file->event_call;
/* Only test those that have a probe */
if (!call->class || !call->class->probe)
@@ -1657,15 +2496,15 @@ static __init void event_trace_self_tests(void)
* If an event is already enabled, someone is using
* it and the self test should not be on.
*/
- if (call->flags & TRACE_EVENT_FL_ENABLED) {
+ if (file->flags & FTRACE_EVENT_FL_ENABLED) {
pr_warning("Enabled event during self test!\n");
WARN_ON_ONCE(1);
continue;
}
- ftrace_event_enable_disable(call, 1);
+ ftrace_event_enable_disable(file, 1);
event_test_stuff();
- ftrace_event_enable_disable(call, 0);
+ ftrace_event_enable_disable(file, 0);
pr_cont("OK\n");
}
@@ -1674,7 +2513,9 @@ static __init void event_trace_self_tests(void)
pr_info("Running tests on trace event systems:\n");
- list_for_each_entry(system, &event_subsystems, list) {
+ list_for_each_entry(dir, &tr->systems, list) {
+
+ system = dir->subsystem;
/* the ftrace system is special, skip it */
if (strcmp(system->name, "ftrace") == 0)
@@ -1682,7 +2523,7 @@ static __init void event_trace_self_tests(void)
pr_info("Testing event system %s: ", system->name);
- ret = __ftrace_set_clr_event(NULL, system->name, NULL, 1);
+ ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 1);
if (WARN_ON_ONCE(ret)) {
pr_warning("error enabling system %s\n",
system->name);
@@ -1691,7 +2532,7 @@ static __init void event_trace_self_tests(void)
event_test_stuff();
- ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0);
+ ret = __ftrace_set_clr_event(tr, NULL, system->name, NULL, 0);
if (WARN_ON_ONCE(ret)) {
pr_warning("error disabling system %s\n",
system->name);
@@ -1706,7 +2547,7 @@ static __init void event_trace_self_tests(void)
pr_info("Running tests on all trace events:\n");
pr_info("Testing all events: ");
- ret = __ftrace_set_clr_event(NULL, NULL, NULL, 1);
+ ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 1);
if (WARN_ON_ONCE(ret)) {
pr_warning("error enabling all events\n");
return;
@@ -1715,7 +2556,7 @@ static __init void event_trace_self_tests(void)
event_test_stuff();
/* reset sysname */
- ret = __ftrace_set_clr_event(NULL, NULL, NULL, 0);
+ ret = __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
if (WARN_ON_ONCE(ret)) {
pr_warning("error disabling all events\n");
return;
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index e5b0ca8b8d4d..a6361178de5a 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -658,33 +658,6 @@ void print_subsystem_event_filter(struct event_subsystem *system,
mutex_unlock(&event_mutex);
}
-static struct ftrace_event_field *
-__find_event_field(struct list_head *head, char *name)
-{
- struct ftrace_event_field *field;
-
- list_for_each_entry(field, head, link) {
- if (!strcmp(field->name, name))
- return field;
- }
-
- return NULL;
-}
-
-static struct ftrace_event_field *
-find_event_field(struct ftrace_event_call *call, char *name)
-{
- struct ftrace_event_field *field;
- struct list_head *head;
-
- field = __find_event_field(&ftrace_common_fields, name);
- if (field)
- return field;
-
- head = trace_get_fields(call);
- return __find_event_field(head, name);
-}
-
static int __alloc_pred_stack(struct pred_stack *stack, int n_preds)
{
stack->preds = kcalloc(n_preds + 1, sizeof(*stack->preds), GFP_KERNEL);
@@ -1337,7 +1310,7 @@ static struct filter_pred *create_pred(struct filter_parse_state *ps,
return NULL;
}
- field = find_event_field(call, operand1);
+ field = trace_find_event_field(call, operand1);
if (!field) {
parse_error(ps, FILT_ERR_FIELD_NOT_FOUND, 0);
return NULL;
@@ -1907,16 +1880,17 @@ out_unlock:
return err;
}
-int apply_subsystem_event_filter(struct event_subsystem *system,
+int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,
char *filter_string)
{
+ struct event_subsystem *system = dir->subsystem;
struct event_filter *filter;
int err = 0;
mutex_lock(&event_mutex);
/* Make sure the system still has events */
- if (!system->nr_events) {
+ if (!dir->nr_events) {
err = -ENODEV;
goto out_unlock;
}
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index e039906b037d..d21a74670088 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -129,7 +129,7 @@ static void __always_unused ____ftrace_check_##name(void) \
#undef FTRACE_ENTRY
#define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \
-int \
+static int __init \
ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
{ \
struct struct_name field; \
@@ -168,7 +168,7 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
#define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\
regfn) \
\
-struct ftrace_event_class event_class_ftrace_##call = { \
+struct ftrace_event_class __refdata event_class_ftrace_##call = { \
.system = __stringify(TRACE_SYSTEM), \
.define_fields = ftrace_define_fields_##call, \
.fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 601152523326..c4d6d7191988 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -28,7 +28,7 @@ static void tracing_stop_function_trace(void);
static int function_trace_init(struct trace_array *tr)
{
func_trace = tr;
- tr->cpu = get_cpu();
+ tr->trace_buffer.cpu = get_cpu();
put_cpu();
tracing_start_cmdline_record();
@@ -44,7 +44,7 @@ static void function_trace_reset(struct trace_array *tr)
static void function_trace_start(struct trace_array *tr)
{
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
}
/* Our option */
@@ -76,7 +76,7 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
goto out;
cpu = smp_processor_id();
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
if (!atomic_read(&data->disabled)) {
local_save_flags(flags);
trace_function(tr, ip, parent_ip, flags, pc);
@@ -107,7 +107,7 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
*/
local_irq_save(flags);
cpu = raw_smp_processor_id();
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
disabled = atomic_inc_return(&data->disabled);
if (likely(disabled == 1)) {
@@ -214,66 +214,89 @@ static struct tracer function_trace __read_mostly =
};
#ifdef CONFIG_DYNAMIC_FTRACE
-static void
-ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
+static int update_count(void **data)
{
- long *count = (long *)data;
-
- if (tracing_is_on())
- return;
+ unsigned long *count = (long *)data;
if (!*count)
- return;
+ return 0;
if (*count != -1)
(*count)--;
- tracing_on();
+ return 1;
}
static void
-ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
+ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)
{
- long *count = (long *)data;
+ if (tracing_is_on())
+ return;
+
+ if (update_count(data))
+ tracing_on();
+}
+static void
+ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data)
+{
if (!tracing_is_on())
return;
- if (!*count)
+ if (update_count(data))
+ tracing_off();
+}
+
+static void
+ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ if (tracing_is_on())
return;
- if (*count != -1)
- (*count)--;
+ tracing_on();
+}
+
+static void
+ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ if (!tracing_is_on())
+ return;
tracing_off();
}
-static int
-ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
- struct ftrace_probe_ops *ops, void *data);
+/*
+ * Skip 4:
+ * ftrace_stacktrace()
+ * function_trace_probe_call()
+ * ftrace_ops_list_func()
+ * ftrace_call()
+ */
+#define STACK_SKIP 4
-static struct ftrace_probe_ops traceon_probe_ops = {
- .func = ftrace_traceon,
- .print = ftrace_trace_onoff_print,
-};
+static void
+ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ trace_dump_stack(STACK_SKIP);
+}
-static struct ftrace_probe_ops traceoff_probe_ops = {
- .func = ftrace_traceoff,
- .print = ftrace_trace_onoff_print,
-};
+static void
+ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
+{
+ if (!tracing_is_on())
+ return;
+
+ if (update_count(data))
+ trace_dump_stack(STACK_SKIP);
+}
static int
-ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
- struct ftrace_probe_ops *ops, void *data)
+ftrace_probe_print(const char *name, struct seq_file *m,
+ unsigned long ip, void *data)
{
long count = (long)data;
- seq_printf(m, "%ps:", (void *)ip);
-
- if (ops == &traceon_probe_ops)
- seq_printf(m, "traceon");
- else
- seq_printf(m, "traceoff");
+ seq_printf(m, "%ps:%s", (void *)ip, name);
if (count == -1)
seq_printf(m, ":unlimited\n");
@@ -284,26 +307,61 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,
}
static int
-ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param)
+ftrace_traceon_print(struct seq_file *m, unsigned long ip,
+ struct ftrace_probe_ops *ops, void *data)
{
- struct ftrace_probe_ops *ops;
-
- /* we register both traceon and traceoff to this callback */
- if (strcmp(cmd, "traceon") == 0)
- ops = &traceon_probe_ops;
- else
- ops = &traceoff_probe_ops;
+ return ftrace_probe_print("traceon", m, ip, data);
+}
- unregister_ftrace_function_probe_func(glob, ops);
+static int
+ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
+ struct ftrace_probe_ops *ops, void *data)
+{
+ return ftrace_probe_print("traceoff", m, ip, data);
+}
- return 0;
+static int
+ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
+ struct ftrace_probe_ops *ops, void *data)
+{
+ return ftrace_probe_print("stacktrace", m, ip, data);
}
+static struct ftrace_probe_ops traceon_count_probe_ops = {
+ .func = ftrace_traceon_count,
+ .print = ftrace_traceon_print,
+};
+
+static struct ftrace_probe_ops traceoff_count_probe_ops = {
+ .func = ftrace_traceoff_count,
+ .print = ftrace_traceoff_print,
+};
+
+static struct ftrace_probe_ops stacktrace_count_probe_ops = {
+ .func = ftrace_stacktrace_count,
+ .print = ftrace_stacktrace_print,
+};
+
+static struct ftrace_probe_ops traceon_probe_ops = {
+ .func = ftrace_traceon,
+ .print = ftrace_traceon_print,
+};
+
+static struct ftrace_probe_ops traceoff_probe_ops = {
+ .func = ftrace_traceoff,
+ .print = ftrace_traceoff_print,
+};
+
+static struct ftrace_probe_ops stacktrace_probe_ops = {
+ .func = ftrace_stacktrace,
+ .print = ftrace_stacktrace_print,
+};
+
static int
-ftrace_trace_onoff_callback(struct ftrace_hash *hash,
- char *glob, char *cmd, char *param, int enable)
+ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
+ struct ftrace_hash *hash, char *glob,
+ char *cmd, char *param, int enable)
{
- struct ftrace_probe_ops *ops;
void *count = (void *)-1;
char *number;
int ret;
@@ -312,14 +370,10 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
if (!enable)
return -EINVAL;
- if (glob[0] == '!')
- return ftrace_trace_onoff_unreg(glob+1, cmd, param);
-
- /* we register both traceon and traceoff to this callback */
- if (strcmp(cmd, "traceon") == 0)
- ops = &traceon_probe_ops;
- else
- ops = &traceoff_probe_ops;
+ if (glob[0] == '!') {
+ unregister_ftrace_function_probe_func(glob+1, ops);
+ return 0;
+ }
if (!param)
goto out_reg;
@@ -343,6 +397,34 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,
return ret < 0 ? ret : 0;
}
+static int
+ftrace_trace_onoff_callback(struct ftrace_hash *hash,
+ char *glob, char *cmd, char *param, int enable)
+{
+ struct ftrace_probe_ops *ops;
+
+ /* we register both traceon and traceoff to this callback */
+ if (strcmp(cmd, "traceon") == 0)
+ ops = param ? &traceon_count_probe_ops : &traceon_probe_ops;
+ else
+ ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops;
+
+ return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+ param, enable);
+}
+
+static int
+ftrace_stacktrace_callback(struct ftrace_hash *hash,
+ char *glob, char *cmd, char *param, int enable)
+{
+ struct ftrace_probe_ops *ops;
+
+ ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops;
+
+ return ftrace_trace_probe_callback(ops, hash, glob, cmd,
+ param, enable);
+}
+
static struct ftrace_func_command ftrace_traceon_cmd = {
.name = "traceon",
.func = ftrace_trace_onoff_callback,
@@ -353,6 +435,11 @@ static struct ftrace_func_command ftrace_traceoff_cmd = {
.func = ftrace_trace_onoff_callback,
};
+static struct ftrace_func_command ftrace_stacktrace_cmd = {
+ .name = "stacktrace",
+ .func = ftrace_stacktrace_callback,
+};
+
static int __init init_func_cmd_traceon(void)
{
int ret;
@@ -364,6 +451,12 @@ static int __init init_func_cmd_traceon(void)
ret = register_ftrace_command(&ftrace_traceon_cmd);
if (ret)
unregister_ftrace_command(&ftrace_traceoff_cmd);
+
+ ret = register_ftrace_command(&ftrace_stacktrace_cmd);
+ if (ret) {
+ unregister_ftrace_command(&ftrace_traceoff_cmd);
+ unregister_ftrace_command(&ftrace_traceon_cmd);
+ }
return ret;
}
#else
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 39ada66389cc..8388bc99f2ee 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -218,7 +218,7 @@ int __trace_graph_entry(struct trace_array *tr,
{
struct ftrace_event_call *call = &event_funcgraph_entry;
struct ring_buffer_event *event;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ftrace_graph_ent_entry *entry;
if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
@@ -265,7 +265,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
local_irq_save(flags);
cpu = raw_smp_processor_id();
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
disabled = atomic_inc_return(&data->disabled);
if (likely(disabled == 1)) {
pc = preempt_count();
@@ -323,7 +323,7 @@ void __trace_graph_return(struct trace_array *tr,
{
struct ftrace_event_call *call = &event_funcgraph_exit;
struct ring_buffer_event *event;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ftrace_graph_ret_entry *entry;
if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
@@ -350,7 +350,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
local_irq_save(flags);
cpu = raw_smp_processor_id();
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
disabled = atomic_inc_return(&data->disabled);
if (likely(disabled == 1)) {
pc = preempt_count();
@@ -560,9 +560,9 @@ get_return_for_leaf(struct trace_iterator *iter,
* We need to consume the current entry to see
* the next one.
*/
- ring_buffer_consume(iter->tr->buffer, iter->cpu,
+ ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu,
NULL, NULL);
- event = ring_buffer_peek(iter->tr->buffer, iter->cpu,
+ event = ring_buffer_peek(iter->trace_buffer->buffer, iter->cpu,
NULL, NULL);
}
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 443b25b43b4f..b19d065a28cb 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -33,6 +33,7 @@ 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);
@@ -121,7 +122,7 @@ static int func_prolog_dec(struct trace_array *tr,
if (!irqs_disabled_flags(*flags))
return 0;
- *data = tr->data[cpu];
+ *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
disabled = atomic_inc_return(&(*data)->disabled);
if (likely(disabled == 1))
@@ -175,7 +176,7 @@ static int irqsoff_set_flag(u32 old_flags, u32 bit, int set)
per_cpu(tracing_cpu, cpu) = 0;
tracing_max_latency = 0;
- tracing_reset_online_cpus(irqsoff_trace);
+ tracing_reset_online_cpus(&irqsoff_trace->trace_buffer);
return start_irqsoff_tracer(irqsoff_trace, set);
}
@@ -380,7 +381,7 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip)
if (per_cpu(tracing_cpu, cpu))
return;
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
if (unlikely(!data) || atomic_read(&data->disabled))
return;
@@ -418,7 +419,7 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip)
if (!tracer_enabled)
return;
- data = tr->data[cpu];
+ data = per_cpu_ptr(tr->trace_buffer.data, cpu);
if (unlikely(!data) ||
!data->critical_start || atomic_read(&data->disabled))
@@ -528,15 +529,60 @@ void trace_preempt_off(unsigned long a0, unsigned long a1)
}
#endif /* CONFIG_PREEMPT_TRACER */
-static int start_irqsoff_tracer(struct trace_array *tr, int graph)
+static int register_irqsoff_function(int graph, int set)
{
- int ret = 0;
+ int ret;
- if (!graph)
- ret = register_ftrace_function(&trace_ops);
- else
+ /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
+ if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
+ return 0;
+
+ if (graph)
ret = register_ftrace_graph(&irqsoff_graph_return,
&irqsoff_graph_entry);
+ else
+ ret = register_ftrace_function(&trace_ops);
+
+ if (!ret)
+ function_enabled = true;
+
+ return ret;
+}
+
+static void unregister_irqsoff_function(int graph)
+{
+ if (!function_enabled)
+ return;
+
+ if (graph)
+ unregister_ftrace_graph();
+ else
+ unregister_ftrace_function(&trace_ops);
+
+ function_enabled = false;
+}
+
+static void irqsoff_function_set(int set)
+{
+ if (set)
+ register_irqsoff_function(is_graph(), 1);
+ else
+ unregister_irqsoff_function(is_graph());
+}
+
+static int irqsoff_flag_changed(struct tracer *tracer, u32 mask, int set)
+{
+ if (mask & TRACE_ITER_FUNCTION)
+ irqsoff_function_set(set);
+
+ return trace_keep_overwrite(tracer, mask, set);
+}
+
+static int start_irqsoff_tracer(struct trace_array *tr, int graph)
+{
+ int ret;
+
+ ret = register_irqsoff_function(graph, 0);
if (!ret && tracing_is_enabled())
tracer_enabled = 1;
@@ -550,10 +596,7 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
{
tracer_enabled = 0;
- if (!graph)
- unregister_ftrace_function(&trace_ops);
- else
- unregister_ftrace_graph();
+ unregister_irqsoff_function(graph);
}
static void __irqsoff_tracer_init(struct trace_array *tr)
@@ -561,14 +604,14 @@ static void __irqsoff_tracer_init(struct trace_array *tr)
save_flags = trace_flags;
/* non overwrite screws up the latency tracers */
- set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
- set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
+ set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
+ set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
tracing_max_latency = 0;
irqsoff_trace = tr;
/* make sure that the tracer is visible */
smp_wmb();
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
if (start_irqsoff_tracer(tr, is_graph()))
printk(KERN_ERR "failed to start irqsoff tracer\n");
@@ -581,8 +624,8 @@ static void irqsoff_tracer_reset(struct trace_array *tr)
stop_irqsoff_tracer(tr, is_graph());
- set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
- set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
+ set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
+ set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
}
static void irqsoff_tracer_start(struct trace_array *tr)
@@ -615,7 +658,7 @@ static struct tracer irqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
- .flag_changed = trace_keep_overwrite,
+ .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_irqsoff,
#endif
@@ -649,7 +692,7 @@ static struct tracer preemptoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
- .flag_changed = trace_keep_overwrite,
+ .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptoff,
#endif
@@ -685,7 +728,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
.print_line = irqsoff_print_line,
.flags = &tracer_flags,
.set_flag = irqsoff_set_flag,
- .flag_changed = trace_keep_overwrite,
+ .flag_changed = irqsoff_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_preemptirqsoff,
#endif
diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c
index 3c5c5dfea0b3..bd90e1b06088 100644
--- a/kernel/trace/trace_kdb.c
+++ b/kernel/trace/trace_kdb.c
@@ -26,7 +26,7 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
trace_init_global_iter(&iter);
for_each_tracing_cpu(cpu) {
- atomic_inc(&iter.tr->data[cpu]->disabled);
+ atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
old_userobj = trace_flags;
@@ -43,17 +43,17 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
iter.iter_flags |= TRACE_FILE_LAT_FMT;
iter.pos = -1;
- if (cpu_file == TRACE_PIPE_ALL_CPU) {
+ if (cpu_file == RING_BUFFER_ALL_CPUS) {
for_each_tracing_cpu(cpu) {
iter.buffer_iter[cpu] =
- ring_buffer_read_prepare(iter.tr->buffer, cpu);
+ ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu);
ring_buffer_read_start(iter.buffer_iter[cpu]);
tracing_iter_reset(&iter, cpu);
}
} else {
iter.cpu_file = cpu_file;
iter.buffer_iter[cpu_file] =
- ring_buffer_read_prepare(iter.tr->buffer, cpu_file);
+ ring_buffer_read_prepare(iter.trace_buffer->buffer, cpu_file);
ring_buffer_read_start(iter.buffer_iter[cpu_file]);
tracing_iter_reset(&iter, cpu_file);
}
@@ -83,7 +83,7 @@ out:
trace_flags = old_userobj;
for_each_tracing_cpu(cpu) {
- atomic_dec(&iter.tr->data[cpu]->disabled);
+ atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
for_each_tracing_cpu(cpu)
@@ -115,7 +115,7 @@ static int kdb_ftdump(int argc, const char **argv)
!cpu_online(cpu_file))
return KDB_BADINT;
} else {
- cpu_file = TRACE_PIPE_ALL_CPU;
+ cpu_file = RING_BUFFER_ALL_CPUS;
}
kdb_trap_printk++;
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
index fd3c8aae55e5..a5e8f4878bfa 100644
--- a/kernel/trace/trace_mmiotrace.c
+++ b/kernel/trace/trace_mmiotrace.c
@@ -31,7 +31,7 @@ static void mmio_reset_data(struct trace_array *tr)
overrun_detected = false;
prev_overruns = 0;
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
}
static int mmio_trace_init(struct trace_array *tr)
@@ -128,7 +128,7 @@ static void mmio_close(struct trace_iterator *iter)
static unsigned long count_overruns(struct trace_iterator *iter)
{
unsigned long cnt = atomic_xchg(&dropped_count, 0);
- unsigned long over = ring_buffer_overruns(iter->tr->buffer);
+ unsigned long over = ring_buffer_overruns(iter->trace_buffer->buffer);
if (over > prev_overruns)
cnt += over - prev_overruns;
@@ -309,7 +309,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
struct mmiotrace_rw *rw)
{
struct ftrace_event_call *call = &event_mmiotrace_rw;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ring_buffer_event *event;
struct trace_mmiotrace_rw *entry;
int pc = preempt_count();
@@ -330,7 +330,7 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
void mmio_trace_rw(struct mmiotrace_rw *rw)
{
struct trace_array *tr = mmio_trace_array;
- struct trace_array_cpu *data = tr->data[smp_processor_id()];
+ struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, smp_processor_id());
__trace_mmiotrace_rw(tr, data, rw);
}
@@ -339,7 +339,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
struct mmiotrace_map *map)
{
struct ftrace_event_call *call = &event_mmiotrace_map;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ring_buffer_event *event;
struct trace_mmiotrace_map *entry;
int pc = preempt_count();
@@ -363,7 +363,7 @@ void mmio_trace_mapping(struct mmiotrace_map *map)
struct trace_array_cpu *data;
preempt_disable();
- data = tr->data[smp_processor_id()];
+ data = per_cpu_ptr(tr->trace_buffer.data, smp_processor_id());
__trace_mmiotrace_map(tr, data, map);
preempt_enable();
}
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 697e88d13907..bb922d9ee51b 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -14,7 +14,7 @@
/* must be a power of 2 */
#define EVENT_HASHSIZE 128
-DECLARE_RWSEM(trace_event_mutex);
+DECLARE_RWSEM(trace_event_sem);
static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
@@ -37,6 +37,22 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)
return ret;
}
+enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter)
+{
+ struct trace_seq *s = &iter->seq;
+ struct trace_entry *entry = iter->ent;
+ struct bputs_entry *field;
+ int ret;
+
+ trace_assign_type(field, entry);
+
+ ret = trace_seq_puts(s, field->str);
+ if (!ret)
+ return TRACE_TYPE_PARTIAL_LINE;
+
+ return TRACE_TYPE_HANDLED;
+}
+
enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
{
struct trace_seq *s = &iter->seq;
@@ -397,6 +413,32 @@ ftrace_print_hex_seq(struct trace_seq *p, const unsigned char *buf, int buf_len)
}
EXPORT_SYMBOL(ftrace_print_hex_seq);
+int ftrace_raw_output_prep(struct trace_iterator *iter,
+ struct trace_event *trace_event)
+{
+ struct ftrace_event_call *event;
+ struct trace_seq *s = &iter->seq;
+ struct trace_seq *p = &iter->tmp_seq;
+ struct trace_entry *entry;
+ int ret;
+
+ event = container_of(trace_event, struct ftrace_event_call, event);
+ entry = iter->ent;
+
+ if (entry->type != event->event.type) {
+ WARN_ON_ONCE(1);
+ return TRACE_TYPE_UNHANDLED;
+ }
+
+ trace_seq_init(p);
+ ret = trace_seq_printf(s, "%s: ", event->name);
+ if (!ret)
+ return TRACE_TYPE_PARTIAL_LINE;
+
+ return 0;
+}
+EXPORT_SYMBOL(ftrace_raw_output_prep);
+
#ifdef CONFIG_KRETPROBES
static inline const char *kretprobed(const char *name)
{
@@ -617,7 +659,7 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
{
unsigned long verbose = 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->tr->time_start;
+ unsigned long long abs_ts = iter->ts - iter->trace_buffer->time_start;
unsigned long long rel_ts = next_ts - iter->ts;
struct trace_seq *s = &iter->seq;
@@ -783,12 +825,12 @@ static int trace_search_list(struct list_head **list)
void trace_event_read_lock(void)
{
- down_read(&trace_event_mutex);
+ down_read(&trace_event_sem);
}
void trace_event_read_unlock(void)
{
- up_read(&trace_event_mutex);
+ up_read(&trace_event_sem);
}
/**
@@ -811,7 +853,7 @@ int register_ftrace_event(struct trace_event *event)
unsigned key;
int ret = 0;
- down_write(&trace_event_mutex);
+ down_write(&trace_event_sem);
if (WARN_ON(!event))
goto out;
@@ -866,14 +908,14 @@ int register_ftrace_event(struct trace_event *event)
ret = event->type;
out:
- up_write(&trace_event_mutex);
+ up_write(&trace_event_sem);
return ret;
}
EXPORT_SYMBOL_GPL(register_ftrace_event);
/*
- * Used by module code with the trace_event_mutex held for write.
+ * Used by module code with the trace_event_sem held for write.
*/
int __unregister_ftrace_event(struct trace_event *event)
{
@@ -888,9 +930,9 @@ int __unregister_ftrace_event(struct trace_event *event)
*/
int unregister_ftrace_event(struct trace_event *event)
{
- down_write(&trace_event_mutex);
+ down_write(&trace_event_sem);
__unregister_ftrace_event(event);
- up_write(&trace_event_mutex);
+ up_write(&trace_event_sem);
return 0;
}
@@ -1217,6 +1259,64 @@ static struct trace_event trace_user_stack_event = {
.funcs = &trace_user_stack_funcs,
};
+/* TRACE_BPUTS */
+static enum print_line_t
+trace_bputs_print(struct trace_iterator *iter, int flags,
+ struct trace_event *event)
+{
+ struct trace_entry *entry = iter->ent;
+ struct trace_seq *s = &iter->seq;
+ struct bputs_entry *field;
+
+ trace_assign_type(field, entry);
+
+ if (!seq_print_ip_sym(s, field->ip, flags))
+ goto partial;
+
+ if (!trace_seq_puts(s, ": "))
+ goto partial;
+
+ if (!trace_seq_puts(s, field->str))
+ goto partial;
+
+ return TRACE_TYPE_HANDLED;
+
+ partial:
+ return TRACE_TYPE_PARTIAL_LINE;
+}
+
+
+static enum print_line_t
+trace_bputs_raw(struct trace_iterator *iter, int flags,
+ struct trace_event *event)
+{
+ struct bputs_entry *field;
+ struct trace_seq *s = &iter->seq;
+
+ trace_assign_type(field, iter->ent);
+
+ if (!trace_seq_printf(s, ": %lx : ", field->ip))
+ goto partial;
+
+ if (!trace_seq_puts(s, field->str))
+ goto partial;
+
+ return TRACE_TYPE_HANDLED;
+
+ partial:
+ return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static struct trace_event_functions trace_bputs_funcs = {
+ .trace = trace_bputs_print,
+ .raw = trace_bputs_raw,
+};
+
+static struct trace_event trace_bputs_event = {
+ .type = TRACE_BPUTS,
+ .funcs = &trace_bputs_funcs,
+};
+
/* TRACE_BPRINT */
static enum print_line_t
trace_bprint_print(struct trace_iterator *iter, int flags,
@@ -1329,6 +1429,7 @@ static struct trace_event *events[] __initdata = {
&trace_wake_event,
&trace_stack_event,
&trace_user_stack_event,
+ &trace_bputs_event,
&trace_bprint_event,
&trace_print_event,
NULL
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
index c038eba0492b..127a9d8c8357 100644
--- a/kernel/trace/trace_output.h
+++ b/kernel/trace/trace_output.h
@@ -5,6 +5,8 @@
#include "trace.h"
extern enum print_line_t
+trace_print_bputs_msg_only(struct trace_iterator *iter);
+extern enum print_line_t
trace_print_bprintk_msg_only(struct trace_iterator *iter);
extern enum print_line_t
trace_print_printk_msg_only(struct trace_iterator *iter);
@@ -31,7 +33,7 @@ trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry);
/* used by module unregistering */
extern int __unregister_ftrace_event(struct trace_event *event);
-extern struct rw_semaphore trace_event_mutex;
+extern struct rw_semaphore trace_event_sem;
#define MAX_MEMHEX_BYTES 8
#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index 3374c792ccd8..4e98e3b257a3 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -28,7 +28,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
unsigned long flags, int pc)
{
struct ftrace_event_call *call = &event_context_switch;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ring_buffer_event *event;
struct ctx_switch_entry *entry;
@@ -69,7 +69,7 @@ probe_sched_switch(void *ignore, struct task_struct *prev, struct task_struct *n
pc = preempt_count();
local_irq_save(flags);
cpu = raw_smp_processor_id();
- data = ctx_trace->data[cpu];
+ data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
if (likely(!atomic_read(&data->disabled)))
tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc);
@@ -86,7 +86,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
struct ftrace_event_call *call = &event_wakeup;
struct ring_buffer_event *event;
struct ctx_switch_entry *entry;
- struct ring_buffer *buffer = tr->buffer;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
sizeof(*entry), flags, pc);
@@ -123,7 +123,7 @@ probe_sched_wakeup(void *ignore, struct task_struct *wakee, int success)
pc = preempt_count();
local_irq_save(flags);
cpu = raw_smp_processor_id();
- data = ctx_trace->data[cpu];
+ data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
if (likely(!atomic_read(&data->disabled)))
tracing_sched_wakeup_trace(ctx_trace, wakee, current,
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index fde652c9a511..fee77e15d815 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -37,6 +37,7 @@ 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
@@ -89,7 +90,7 @@ func_prolog_preempt_disable(struct trace_array *tr,
if (cpu != wakeup_current_cpu)
goto out_enable;
- *data = tr->data[cpu];
+ *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
disabled = atomic_inc_return(&(*data)->disabled);
if (unlikely(disabled != 1))
goto out;
@@ -134,15 +135,60 @@ static struct ftrace_ops trace_ops __read_mostly =
};
#endif /* CONFIG_FUNCTION_TRACER */
-static int start_func_tracer(int graph)
+static int register_wakeup_function(int graph, int set)
{
int ret;
- if (!graph)
- ret = register_ftrace_function(&trace_ops);
- else
+ /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
+ if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
+ return 0;
+
+ if (graph)
ret = register_ftrace_graph(&wakeup_graph_return,
&wakeup_graph_entry);
+ else
+ ret = register_ftrace_function(&trace_ops);
+
+ if (!ret)
+ function_enabled = true;
+
+ return ret;
+}
+
+static void unregister_wakeup_function(int graph)
+{
+ if (!function_enabled)
+ return;
+
+ if (graph)
+ unregister_ftrace_graph();
+ else
+ unregister_ftrace_function(&trace_ops);
+
+ function_enabled = false;
+}
+
+static void wakeup_function_set(int set)
+{
+ if (set)
+ register_wakeup_function(is_graph(), 1);
+ else
+ unregister_wakeup_function(is_graph());
+}
+
+static int wakeup_flag_changed(struct tracer *tracer, u32 mask, int set)
+{
+ if (mask & TRACE_ITER_FUNCTION)
+ wakeup_function_set(set);
+
+ return trace_keep_overwrite(tracer, mask, set);
+}
+
+static int start_func_tracer(int graph)
+{
+ int ret;
+
+ ret = register_wakeup_function(graph, 0);
if (!ret && tracing_is_enabled())
tracer_enabled = 1;
@@ -156,10 +202,7 @@ static void stop_func_tracer(int graph)
{
tracer_enabled = 0;
- if (!graph)
- unregister_ftrace_function(&trace_ops);
- else
- unregister_ftrace_graph();
+ unregister_wakeup_function(graph);
}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -353,7 +396,7 @@ probe_wakeup_sched_switch(void *ignore,
/* disable local data, not wakeup_cpu data */
cpu = raw_smp_processor_id();
- disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
+ disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
if (likely(disabled != 1))
goto out;
@@ -365,7 +408,7 @@ probe_wakeup_sched_switch(void *ignore,
goto out_unlock;
/* The task we are waiting for is waking up */
- data = wakeup_trace->data[wakeup_cpu];
+ data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
__trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
@@ -387,7 +430,7 @@ out_unlock:
arch_spin_unlock(&wakeup_lock);
local_irq_restore(flags);
out:
- atomic_dec(&wakeup_trace->data[cpu]->disabled);
+ atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
}
static void __wakeup_reset(struct trace_array *tr)
@@ -405,7 +448,7 @@ static void wakeup_reset(struct trace_array *tr)
{
unsigned long flags;
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
local_irq_save(flags);
arch_spin_lock(&wakeup_lock);
@@ -435,7 +478,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
return;
pc = preempt_count();
- disabled = atomic_inc_return(&wakeup_trace->data[cpu]->disabled);
+ disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
if (unlikely(disabled != 1))
goto out;
@@ -458,7 +501,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
local_save_flags(flags);
- data = wakeup_trace->data[wakeup_cpu];
+ data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
data->preempt_timestamp = ftrace_now(cpu);
tracing_sched_wakeup_trace(wakeup_trace, p, current, flags, pc);
@@ -472,7 +515,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
out_locked:
arch_spin_unlock(&wakeup_lock);
out:
- atomic_dec(&wakeup_trace->data[cpu]->disabled);
+ atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
}
static void start_wakeup_tracer(struct trace_array *tr)
@@ -543,8 +586,8 @@ static int __wakeup_tracer_init(struct trace_array *tr)
save_flags = trace_flags;
/* non overwrite screws up the latency tracers */
- set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
- set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
+ set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
+ set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
tracing_max_latency = 0;
wakeup_trace = tr;
@@ -573,8 +616,8 @@ static void wakeup_tracer_reset(struct trace_array *tr)
/* make sure we put back any tasks we are tracing */
wakeup_reset(tr);
- set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
- set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
+ set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
+ set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
}
static void wakeup_tracer_start(struct trace_array *tr)
@@ -600,7 +643,7 @@ static struct tracer wakeup_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
- .flag_changed = trace_keep_overwrite,
+ .flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
@@ -622,7 +665,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
.print_line = wakeup_print_line,
.flags = &tracer_flags,
.set_flag = wakeup_set_flag,
- .flag_changed = trace_keep_overwrite,
+ .flag_changed = wakeup_flag_changed,
#ifdef CONFIG_FTRACE_SELFTEST
.selftest = trace_selftest_startup_wakeup,
#endif
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index 51c819c12c29..55e2cf66967b 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -21,13 +21,13 @@ static inline int trace_valid_entry(struct trace_entry *entry)
return 0;
}
-static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
+static int trace_test_buffer_cpu(struct trace_buffer *buf, int cpu)
{
struct ring_buffer_event *event;
struct trace_entry *entry;
unsigned int loops = 0;
- while ((event = ring_buffer_consume(tr->buffer, cpu, NULL, NULL))) {
+ while ((event = ring_buffer_consume(buf->buffer, cpu, NULL, NULL))) {
entry = ring_buffer_event_data(event);
/*
@@ -58,7 +58,7 @@ static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
* Test the trace buffer to see if all the elements
* are still sane.
*/
-static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
+static int trace_test_buffer(struct trace_buffer *buf, unsigned long *count)
{
unsigned long flags, cnt = 0;
int cpu, ret = 0;
@@ -67,7 +67,7 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
local_irq_save(flags);
arch_spin_lock(&ftrace_max_lock);
- cnt = ring_buffer_entries(tr->buffer);
+ cnt = ring_buffer_entries(buf->buffer);
/*
* The trace_test_buffer_cpu runs a while loop to consume all data.
@@ -78,7 +78,7 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
*/
tracing_off();
for_each_possible_cpu(cpu) {
- ret = trace_test_buffer_cpu(tr, cpu);
+ ret = trace_test_buffer_cpu(buf, cpu);
if (ret)
break;
}
@@ -355,7 +355,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
msleep(100);
/* we should have nothing in the buffer */
- ret = trace_test_buffer(tr, &count);
+ ret = trace_test_buffer(&tr->trace_buffer, &count);
if (ret)
goto out;
@@ -376,7 +376,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
ftrace_enabled = 0;
/* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
+ ret = trace_test_buffer(&tr->trace_buffer, &count);
tracing_start();
/* we should only have one item */
@@ -666,7 +666,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
ftrace_enabled = 0;
/* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
+ ret = trace_test_buffer(&tr->trace_buffer, &count);
trace->reset(tr);
tracing_start();
@@ -703,8 +703,6 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
/* Maximum number of functions to trace before diagnosing a hang */
#define GRAPH_MAX_FUNC_TEST 100000000
-static void
-__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode);
static unsigned int graph_hang_thresh;
/* Wrap the real function entry probe to avoid possible hanging */
@@ -714,8 +712,11 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
ftrace_graph_stop();
printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
- if (ftrace_dump_on_oops)
- __ftrace_dump(false, DUMP_ALL);
+ if (ftrace_dump_on_oops) {
+ ftrace_dump(DUMP_ALL);
+ /* ftrace_dump() disables tracing */
+ tracing_on();
+ }
return 0;
}
@@ -737,7 +738,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
* Simulate the init() callback but we attach a watchdog callback
* to detect and recover from possible hangs
*/
- tracing_reset_online_cpus(tr);
+ tracing_reset_online_cpus(&tr->trace_buffer);
set_graph_array(tr);
ret = register_ftrace_graph(&trace_graph_return,
&trace_graph_entry_watchdog);
@@ -760,7 +761,7 @@ trace_selftest_startup_function_graph(struct tracer *trace,
tracing_stop();
/* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
+ ret = trace_test_buffer(&tr->trace_buffer, &count);
trace->reset(tr);
tracing_start();
@@ -815,9 +816,9 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr)
/* stop the tracing. */
tracing_stop();
/* check both trace buffers */
- ret = trace_test_buffer(tr, NULL);
+ ret = trace_test_buffer(&tr->trace_buffer, NULL);
if (!ret)
- ret = trace_test_buffer(&max_tr, &count);
+ ret = trace_test_buffer(&tr->max_buffer, &count);
trace->reset(tr);
tracing_start();
@@ -877,9 +878,9 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr)
/* stop the tracing. */
tracing_stop();
/* check both trace buffers */
- ret = trace_test_buffer(tr, NULL);
+ ret = trace_test_buffer(&tr->trace_buffer, NULL);
if (!ret)
- ret = trace_test_buffer(&max_tr, &count);
+ ret = trace_test_buffer(&tr->max_buffer, &count);
trace->reset(tr);
tracing_start();
@@ -943,11 +944,11 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
/* stop the tracing. */
tracing_stop();
/* check both trace buffers */
- ret = trace_test_buffer(tr, NULL);
+ ret = trace_test_buffer(&tr->trace_buffer, NULL);
if (ret)
goto out;
- ret = trace_test_buffer(&max_tr, &count);
+ ret = trace_test_buffer(&tr->max_buffer, &count);
if (ret)
goto out;
@@ -973,11 +974,11 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
/* stop the tracing. */
tracing_stop();
/* check both trace buffers */
- ret = trace_test_buffer(tr, NULL);
+ ret = trace_test_buffer(&tr->trace_buffer, NULL);
if (ret)
goto out;
- ret = trace_test_buffer(&max_tr, &count);
+ ret = trace_test_buffer(&tr->max_buffer, &count);
if (!ret && !count) {
printk(KERN_CONT ".. no entries found ..");
@@ -1084,10 +1085,10 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
/* stop the tracing. */
tracing_stop();
/* check both trace buffers */
- ret = trace_test_buffer(tr, NULL);
+ ret = trace_test_buffer(&tr->trace_buffer, NULL);
printk("ret = %d\n", ret);
if (!ret)
- ret = trace_test_buffer(&max_tr, &count);
+ ret = trace_test_buffer(&tr->max_buffer, &count);
trace->reset(tr);
@@ -1126,7 +1127,7 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
/* stop the tracing. */
tracing_stop();
/* check the trace buffer */
- ret = trace_test_buffer(tr, &count);
+ ret = trace_test_buffer(&tr->trace_buffer, &count);
trace->reset(tr);
tracing_start();
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 42ca822fc701..b20428c5efe2 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -20,13 +20,24 @@
#define STACK_TRACE_ENTRIES 500
+#ifdef CC_USING_FENTRY
+# define fentry 1
+#else
+# define fentry 0
+#endif
+
static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] =
{ [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX };
static unsigned stack_dump_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 = {
- .max_entries = STACK_TRACE_ENTRIES,
- .entries = stack_dump_trace,
+ .max_entries = STACK_TRACE_ENTRIES - 1,
+ .entries = &stack_dump_trace[1],
};
static unsigned long max_stack_size;
@@ -39,25 +50,34 @@ static DEFINE_MUTEX(stack_sysctl_mutex);
int stack_tracer_enabled;
static int last_stack_tracer_enabled;
-static inline void check_stack(void)
+static inline void
+check_stack(unsigned long ip, unsigned long *stack)
{
unsigned long this_size, flags;
unsigned long *p, *top, *start;
+ static int tracer_frame;
+ int frame_size = ACCESS_ONCE(tracer_frame);
int i;
- this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1);
+ this_size = ((unsigned long)stack) & (THREAD_SIZE-1);
this_size = THREAD_SIZE - this_size;
+ /* Remove the frame of the tracer */
+ this_size -= frame_size;
if (this_size <= max_stack_size)
return;
/* we do not handle interrupt stacks yet */
- if (!object_is_on_stack(&this_size))
+ if (!object_is_on_stack(stack))
return;
local_irq_save(flags);
arch_spin_lock(&max_stack_lock);
+ /* In case another CPU set the tracer_frame on us */
+ if (unlikely(!frame_size))
+ this_size -= tracer_frame;
+
/* a race could have already updated it */
if (this_size <= max_stack_size)
goto out;
@@ -70,10 +90,18 @@ static inline void check_stack(void)
save_stack_trace(&max_stack_trace);
/*
+ * Add the passed in ip from the function tracer.
+ * Searching for this on the stack will skip over
+ * most of the overhead from the stack tracer itself.
+ */
+ stack_dump_trace[0] = ip;
+ max_stack_trace.nr_entries++;
+
+ /*
* Now find where in the stack these are.
*/
i = 0;
- start = &this_size;
+ start = stack;
top = (unsigned long *)
(((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE);
@@ -97,6 +125,18 @@ static inline void check_stack(void)
found = 1;
/* Start the search from here */
start = p + 1;
+ /*
+ * We do not want to show the overhead
+ * of the stack tracer stack in the
+ * max stack. If we haven't figured
+ * out what that is, then figure it out
+ * now.
+ */
+ if (unlikely(!tracer_frame) && i == 1) {
+ tracer_frame = (p - stack) *
+ sizeof(unsigned long);
+ max_stack_size -= tracer_frame;
+ }
}
}
@@ -113,6 +153,7 @@ static void
stack_trace_call(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct pt_regs *pt_regs)
{
+ unsigned long stack;
int cpu;
preempt_disable_notrace();
@@ -122,7 +163,26 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip,
if (per_cpu(trace_active, cpu)++ != 0)
goto out;
- check_stack();
+ /*
+ * When fentry is used, the traced function does not get
+ * its stack frame set up, and we lose the parent.
+ * The ip is pretty useless because the function tracer
+ * was called before that function set up its stack frame.
+ * In this case, we use the parent ip.
+ *
+ * By adding the return address of either the parent ip
+ * or the current ip we can disregard most of the stack usage
+ * caused by the stack tracer itself.
+ *
+ * The function tracer always reports the address of where the
+ * mcount call was, but the stack will hold the return address.
+ */
+ if (fentry)
+ ip = parent_ip;
+ else
+ ip += MCOUNT_INSN_SIZE;
+
+ check_stack(ip, &stack);
out:
per_cpu(trace_active, cpu)--;
@@ -322,7 +382,7 @@ static const struct file_operations stack_trace_filter_fops = {
.open = stack_trace_filter_open,
.read = seq_read,
.write = ftrace_filter_write,
- .llseek = ftrace_regex_lseek,
+ .llseek = ftrace_filter_lseek,
.release = ftrace_regex_release,
};
@@ -371,6 +431,8 @@ static __init int stack_trace_init(void)
struct dentry *d_tracer;
d_tracer = tracing_init_dentry();
+ if (!d_tracer)
+ return 0;
trace_create_file("stack_max_size", 0644, d_tracer,
&max_stack_size, &stack_max_size_fops);
diff --git a/kernel/trace/trace_stat.c b/kernel/trace/trace_stat.c
index 96cffb269e73..847f88a6194b 100644
--- a/kernel/trace/trace_stat.c
+++ b/kernel/trace/trace_stat.c
@@ -307,6 +307,8 @@ static int tracing_stat_init(void)
struct dentry *d_tracing;
d_tracing = tracing_init_dentry();
+ if (!d_tracing)
+ return 0;
stat_dir = debugfs_create_dir("trace_stat", d_tracing);
if (!stat_dir)
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 7a809e321058..8f2ac73c7a5f 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -12,10 +12,6 @@
#include "trace.h"
static DEFINE_MUTEX(syscall_trace_lock);
-static int sys_refcount_enter;
-static int sys_refcount_exit;
-static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
-static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
static int syscall_enter_register(struct ftrace_event_call *event,
enum trace_reg type, void *data);
@@ -41,7 +37,7 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
/*
* Only compare after the "sys" prefix. Archs that use
* syscall wrappers may have syscalls symbols aliases prefixed
- * with "SyS" instead of "sys", leading to an unwanted
+ * with ".SyS" or ".sys" instead of "sys", leading to an unwanted
* mismatch.
*/
return !strcmp(sym + 3, name + 3);
@@ -265,7 +261,7 @@ static void free_syscall_print_fmt(struct ftrace_event_call *call)
kfree(call->print_fmt);
}
-static int syscall_enter_define_fields(struct ftrace_event_call *call)
+static int __init syscall_enter_define_fields(struct ftrace_event_call *call)
{
struct syscall_trace_enter trace;
struct syscall_metadata *meta = call->data;
@@ -288,7 +284,7 @@ static int syscall_enter_define_fields(struct ftrace_event_call *call)
return ret;
}
-static int syscall_exit_define_fields(struct ftrace_event_call *call)
+static int __init syscall_exit_define_fields(struct ftrace_event_call *call)
{
struct syscall_trace_exit trace;
int ret;
@@ -303,8 +299,9 @@ static int syscall_exit_define_fields(struct ftrace_event_call *call)
return ret;
}
-static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
+static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
{
+ struct trace_array *tr = data;
struct syscall_trace_enter *entry;
struct syscall_metadata *sys_data;
struct ring_buffer_event *event;
@@ -315,7 +312,7 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
syscall_nr = trace_get_syscall_nr(current, regs);
if (syscall_nr < 0)
return;
- if (!test_bit(syscall_nr, enabled_enter_syscalls))
+ if (!test_bit(syscall_nr, tr->enabled_enter_syscalls))
return;
sys_data = syscall_nr_to_meta(syscall_nr);
@@ -324,7 +321,8 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
- event = trace_current_buffer_lock_reserve(&buffer,
+ buffer = tr->trace_buffer.buffer;
+ event = trace_buffer_lock_reserve(buffer,
sys_data->enter_event->event.type, size, 0, 0);
if (!event)
return;
@@ -338,8 +336,9 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
trace_current_buffer_unlock_commit(buffer, event, 0, 0);
}
-static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
+static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
{
+ struct trace_array *tr = data;
struct syscall_trace_exit *entry;
struct syscall_metadata *sys_data;
struct ring_buffer_event *event;
@@ -349,14 +348,15 @@ static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
syscall_nr = trace_get_syscall_nr(current, regs);
if (syscall_nr < 0)
return;
- if (!test_bit(syscall_nr, enabled_exit_syscalls))
+ if (!test_bit(syscall_nr, tr->enabled_exit_syscalls))
return;
sys_data = syscall_nr_to_meta(syscall_nr);
if (!sys_data)
return;
- event = trace_current_buffer_lock_reserve(&buffer,
+ buffer = tr->trace_buffer.buffer;
+ event = trace_buffer_lock_reserve(buffer,
sys_data->exit_event->event.type, sizeof(*entry), 0, 0);
if (!event)
return;
@@ -370,8 +370,10 @@ static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
trace_current_buffer_unlock_commit(buffer, event, 0, 0);
}
-static int reg_event_syscall_enter(struct ftrace_event_call *call)
+static int reg_event_syscall_enter(struct ftrace_event_file *file,
+ struct ftrace_event_call *call)
{
+ struct trace_array *tr = file->tr;
int ret = 0;
int num;
@@ -379,33 +381,37 @@ static int reg_event_syscall_enter(struct ftrace_event_call *call)
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
return -ENOSYS;
mutex_lock(&syscall_trace_lock);
- if (!sys_refcount_enter)
- ret = register_trace_sys_enter(ftrace_syscall_enter, NULL);
+ if (!tr->sys_refcount_enter)
+ ret = register_trace_sys_enter(ftrace_syscall_enter, tr);
if (!ret) {
- set_bit(num, enabled_enter_syscalls);
- sys_refcount_enter++;
+ set_bit(num, tr->enabled_enter_syscalls);
+ tr->sys_refcount_enter++;
}
mutex_unlock(&syscall_trace_lock);
return ret;
}
-static void unreg_event_syscall_enter(struct ftrace_event_call *call)
+static void unreg_event_syscall_enter(struct ftrace_event_file *file,
+ struct ftrace_event_call *call)
{
+ struct trace_array *tr = file->tr;
int num;
num = ((struct syscall_metadata *)call->data)->syscall_nr;
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
return;
mutex_lock(&syscall_trace_lock);
- sys_refcount_enter--;
- clear_bit(num, enabled_enter_syscalls);
- if (!sys_refcount_enter)
- unregister_trace_sys_enter(ftrace_syscall_enter, NULL);
+ tr->sys_refcount_enter--;
+ clear_bit(num, tr->enabled_enter_syscalls);
+ if (!tr->sys_refcount_enter)
+ unregister_trace_sys_enter(ftrace_syscall_enter, tr);
mutex_unlock(&syscall_trace_lock);
}
-static int reg_event_syscall_exit(struct ftrace_event_call *call)
+static int reg_event_syscall_exit(struct ftrace_event_file *file,
+ struct ftrace_event_call *call)
{
+ struct trace_array *tr = file->tr;
int ret = 0;
int num;
@@ -413,28 +419,30 @@ static int reg_event_syscall_exit(struct ftrace_event_call *call)
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
return -ENOSYS;
mutex_lock(&syscall_trace_lock);
- if (!sys_refcount_exit)
- ret = register_trace_sys_exit(ftrace_syscall_exit, NULL);
+ if (!tr->sys_refcount_exit)
+ ret = register_trace_sys_exit(ftrace_syscall_exit, tr);
if (!ret) {
- set_bit(num, enabled_exit_syscalls);
- sys_refcount_exit++;
+ set_bit(num, tr->enabled_exit_syscalls);
+ tr->sys_refcount_exit++;
}
mutex_unlock(&syscall_trace_lock);
return ret;
}
-static void unreg_event_syscall_exit(struct ftrace_event_call *call)
+static void unreg_event_syscall_exit(struct ftrace_event_file *file,
+ struct ftrace_event_call *call)
{
+ struct trace_array *tr = file->tr;
int num;
num = ((struct syscall_metadata *)call->data)->syscall_nr;
if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
return;
mutex_lock(&syscall_trace_lock);
- sys_refcount_exit--;
- clear_bit(num, enabled_exit_syscalls);
- if (!sys_refcount_exit)
- unregister_trace_sys_exit(ftrace_syscall_exit, NULL);
+ tr->sys_refcount_exit--;
+ clear_bit(num, tr->enabled_exit_syscalls);
+ if (!tr->sys_refcount_exit)
+ unregister_trace_sys_exit(ftrace_syscall_exit, tr);
mutex_unlock(&syscall_trace_lock);
}
@@ -471,7 +479,7 @@ struct trace_event_functions exit_syscall_print_funcs = {
.trace = print_syscall_exit,
};
-struct ftrace_event_class event_class_syscall_enter = {
+struct ftrace_event_class __refdata event_class_syscall_enter = {
.system = "syscalls",
.reg = syscall_enter_register,
.define_fields = syscall_enter_define_fields,
@@ -479,7 +487,7 @@ struct ftrace_event_class event_class_syscall_enter = {
.raw_init = init_syscall_trace,
};
-struct ftrace_event_class event_class_syscall_exit = {
+struct ftrace_event_class __refdata event_class_syscall_exit = {
.system = "syscalls",
.reg = syscall_exit_register,
.define_fields = syscall_exit_define_fields,
@@ -685,11 +693,13 @@ static void perf_sysexit_disable(struct ftrace_event_call *call)
static int syscall_enter_register(struct ftrace_event_call *event,
enum trace_reg type, void *data)
{
+ struct ftrace_event_file *file = data;
+
switch (type) {
case TRACE_REG_REGISTER:
- return reg_event_syscall_enter(event);
+ return reg_event_syscall_enter(file, event);
case TRACE_REG_UNREGISTER:
- unreg_event_syscall_enter(event);
+ unreg_event_syscall_enter(file, event);
return 0;
#ifdef CONFIG_PERF_EVENTS
@@ -711,11 +721,13 @@ static int syscall_enter_register(struct ftrace_event_call *event,
static int syscall_exit_register(struct ftrace_event_call *event,
enum trace_reg type, void *data)
{
+ struct ftrace_event_file *file = data;
+
switch (type) {
case TRACE_REG_REGISTER:
- return reg_event_syscall_exit(event);
+ return reg_event_syscall_exit(file, event);
case TRACE_REG_UNREGISTER:
- unreg_event_syscall_exit(event);
+ unreg_event_syscall_exit(file, event);
return 0;
#ifdef CONFIG_PERF_EVENTS
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 8dad2a92dee9..32494fb0ee64 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -28,6 +28,18 @@
#define UPROBE_EVENT_SYSTEM "uprobes"
+struct uprobe_trace_entry_head {
+ struct trace_entry ent;
+ unsigned long vaddr[];
+};
+
+#define SIZEOF_TRACE_ENTRY(is_return) \
+ (sizeof(struct uprobe_trace_entry_head) + \
+ sizeof(unsigned long) * (is_return ? 2 : 1))
+
+#define DATAOF_TRACE_ENTRY(entry, is_return) \
+ ((void*)(entry) + SIZEOF_TRACE_ENTRY(is_return))
+
struct trace_uprobe_filter {
rwlock_t rwlock;
int nr_systemwide;
@@ -64,6 +76,8 @@ static DEFINE_MUTEX(uprobe_lock);
static LIST_HEAD(uprobe_list);
static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
+static int uretprobe_dispatcher(struct uprobe_consumer *con,
+ unsigned long func, struct pt_regs *regs);
static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter)
{
@@ -77,11 +91,16 @@ static inline bool uprobe_filter_is_empty(struct trace_uprobe_filter *filter)
return !filter->nr_systemwide && list_empty(&filter->perf_events);
}
+static inline bool is_ret_probe(struct trace_uprobe *tu)
+{
+ return tu->consumer.ret_handler != NULL;
+}
+
/*
* Allocate new trace_uprobe and initialize it (including uprobes).
*/
static struct trace_uprobe *
-alloc_trace_uprobe(const char *group, const char *event, int nargs)
+alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
{
struct trace_uprobe *tu;
@@ -106,6 +125,8 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs)
INIT_LIST_HEAD(&tu->list);
tu->consumer.handler = uprobe_dispatcher;
+ if (is_ret)
+ tu->consumer.ret_handler = uretprobe_dispatcher;
init_trace_uprobe_filter(&tu->filter);
return tu;
@@ -180,7 +201,7 @@ end:
/*
* Argument syntax:
- * - Add uprobe: p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS]
+ * - Add uprobe: p|r[:[GRP/]EVENT] PATH:SYMBOL [FETCHARGS]
*
* - Remove uprobe: -:[GRP/]EVENT
*/
@@ -192,20 +213,23 @@ static int create_trace_uprobe(int argc, char **argv)
char buf[MAX_EVENT_NAME_LEN];
struct path path;
unsigned long offset;
- bool is_delete;
+ bool is_delete, is_return;
int i, ret;
inode = NULL;
ret = 0;
is_delete = false;
+ is_return = false;
event = NULL;
group = NULL;
/* argc must be >= 1 */
if (argv[0][0] == '-')
is_delete = true;
+ else if (argv[0][0] == 'r')
+ is_return = true;
else if (argv[0][0] != 'p') {
- pr_info("Probe definition must be started with 'p' or '-'.\n");
+ pr_info("Probe definition must be started with 'p', 'r' or '-'.\n");
return -EINVAL;
}
@@ -303,7 +327,7 @@ static int create_trace_uprobe(int argc, char **argv)
kfree(tail);
}
- tu = alloc_trace_uprobe(group, event, argc);
+ tu = alloc_trace_uprobe(group, event, argc, is_return);
if (IS_ERR(tu)) {
pr_info("Failed to allocate trace_uprobe.(%d)\n", (int)PTR_ERR(tu));
ret = PTR_ERR(tu);
@@ -414,9 +438,10 @@ static void probes_seq_stop(struct seq_file *m, void *v)
static int probes_seq_show(struct seq_file *m, void *v)
{
struct trace_uprobe *tu = v;
+ char c = is_ret_probe(tu) ? 'r' : 'p';
int i;
- seq_printf(m, "p:%s/%s", tu->call.class->system, tu->call.name);
+ seq_printf(m, "%c:%s/%s", c, tu->call.class->system, tu->call.name);
seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset);
for (i = 0; i < tu->nr_args; i++)
@@ -485,65 +510,81 @@ static const struct file_operations uprobe_profile_ops = {
.release = seq_release,
};
-/* uprobe handler */
-static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
+static void uprobe_trace_print(struct trace_uprobe *tu,
+ unsigned long func, struct pt_regs *regs)
{
struct uprobe_trace_entry_head *entry;
struct ring_buffer_event *event;
struct ring_buffer *buffer;
- u8 *data;
- int size, i, pc;
- unsigned long irq_flags;
+ void *data;
+ int size, i;
struct ftrace_event_call *call = &tu->call;
- local_save_flags(irq_flags);
- pc = preempt_count();
-
- size = sizeof(*entry) + tu->size;
-
+ size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
- size, irq_flags, pc);
+ size + tu->size, 0, 0);
if (!event)
- return 0;
+ return;
entry = ring_buffer_event_data(event);
- entry->ip = instruction_pointer(task_pt_regs(current));
- data = (u8 *)&entry[1];
+ if (is_ret_probe(tu)) {
+ entry->vaddr[0] = func;
+ entry->vaddr[1] = instruction_pointer(regs);
+ data = DATAOF_TRACE_ENTRY(entry, true);
+ } else {
+ entry->vaddr[0] = instruction_pointer(regs);
+ data = DATAOF_TRACE_ENTRY(entry, false);
+ }
+
for (i = 0; i < tu->nr_args; i++)
call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
if (!filter_current_check_discard(buffer, call, entry, event))
- trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+ trace_buffer_unlock_commit(buffer, event, 0, 0);
+}
+/* uprobe handler */
+static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+ if (!is_ret_probe(tu))
+ uprobe_trace_print(tu, 0, regs);
return 0;
}
+static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
+ struct pt_regs *regs)
+{
+ uprobe_trace_print(tu, func, regs);
+}
+
/* Event entry printers */
static enum print_line_t
print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event)
{
- struct uprobe_trace_entry_head *field;
+ struct uprobe_trace_entry_head *entry;
struct trace_seq *s = &iter->seq;
struct trace_uprobe *tu;
u8 *data;
int i;
- field = (struct uprobe_trace_entry_head *)iter->ent;
+ entry = (struct uprobe_trace_entry_head *)iter->ent;
tu = container_of(event, struct trace_uprobe, call.event);
- if (!trace_seq_printf(s, "%s: (", tu->call.name))
- goto partial;
-
- if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
- goto partial;
-
- if (!trace_seq_puts(s, ")"))
- goto partial;
+ if (is_ret_probe(tu)) {
+ if (!trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)", tu->call.name,
+ entry->vaddr[1], entry->vaddr[0]))
+ goto partial;
+ data = DATAOF_TRACE_ENTRY(entry, true);
+ } else {
+ if (!trace_seq_printf(s, "%s: (0x%lx)", tu->call.name,
+ entry->vaddr[0]))
+ goto partial;
+ data = DATAOF_TRACE_ENTRY(entry, false);
+ }
- data = (u8 *)&field[1];
for (i = 0; i < tu->nr_args; i++) {
if (!tu->args[i].type->print(s, tu->args[i].name,
- data + tu->args[i].offset, field))
+ data + tu->args[i].offset, entry))
goto partial;
}
@@ -595,16 +636,23 @@ static void probe_event_disable(struct trace_uprobe *tu, int flag)
static int uprobe_event_define_fields(struct ftrace_event_call *event_call)
{
- int ret, i;
+ int ret, i, size;
struct uprobe_trace_entry_head field;
- struct trace_uprobe *tu = (struct trace_uprobe *)event_call->data;
+ struct trace_uprobe *tu = event_call->data;
- DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
+ if (is_ret_probe(tu)) {
+ DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_FUNC, 0);
+ DEFINE_FIELD(unsigned long, vaddr[1], FIELD_STRING_RETIP, 0);
+ size = SIZEOF_TRACE_ENTRY(true);
+ } else {
+ DEFINE_FIELD(unsigned long, vaddr[0], FIELD_STRING_IP, 0);
+ size = SIZEOF_TRACE_ENTRY(false);
+ }
/* Set argument names as fields */
for (i = 0; i < tu->nr_args; i++) {
ret = trace_define_field(event_call, tu->args[i].type->fmttype,
tu->args[i].name,
- sizeof(field) + tu->args[i].offset,
+ size + tu->args[i].offset,
tu->args[i].type->size,
tu->args[i].type->is_signed,
FILTER_OTHER);
@@ -622,8 +670,13 @@ static int __set_print_fmt(struct trace_uprobe *tu, char *buf, int len)
int i;
int pos = 0;
- fmt = "(%lx)";
- arg = "REC->" FIELD_STRING_IP;
+ if (is_ret_probe(tu)) {
+ fmt = "(%lx <- %lx)";
+ arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
+ } else {
+ fmt = "(%lx)";
+ arg = "REC->" FIELD_STRING_IP;
+ }
/* When len=0, we just calculate the needed length */
@@ -752,49 +805,68 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc,
return ret;
}
-/* uprobe profile handler */
-static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
+static void uprobe_perf_print(struct trace_uprobe *tu,
+ unsigned long func, struct pt_regs *regs)
{
struct ftrace_event_call *call = &tu->call;
struct uprobe_trace_entry_head *entry;
struct hlist_head *head;
- u8 *data;
- int size, __size, i;
- int rctx;
+ void *data;
+ int size, rctx, i;
- if (!uprobe_perf_filter(&tu->consumer, 0, current->mm))
- return UPROBE_HANDLER_REMOVE;
-
- __size = sizeof(*entry) + tu->size;
- size = ALIGN(__size + sizeof(u32), sizeof(u64));
- size -= sizeof(u32);
+ size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
+ size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32);
if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
- return 0;
+ return;
preempt_disable();
+ head = this_cpu_ptr(call->perf_events);
+ if (hlist_empty(head))
+ goto out;
entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
if (!entry)
goto out;
- entry->ip = instruction_pointer(task_pt_regs(current));
- data = (u8 *)&entry[1];
+ if (is_ret_probe(tu)) {
+ entry->vaddr[0] = func;
+ entry->vaddr[1] = instruction_pointer(regs);
+ data = DATAOF_TRACE_ENTRY(entry, true);
+ } else {
+ entry->vaddr[0] = instruction_pointer(regs);
+ data = DATAOF_TRACE_ENTRY(entry, false);
+ }
+
for (i = 0; i < tu->nr_args; i++)
call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
- head = this_cpu_ptr(call->perf_events);
- perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head, NULL);
-
+ perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL);
out:
preempt_enable();
+}
+
+/* uprobe profile handler */
+static int uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+ if (!uprobe_perf_filter(&tu->consumer, 0, current->mm))
+ return UPROBE_HANDLER_REMOVE;
+
+ if (!is_ret_probe(tu))
+ uprobe_perf_print(tu, 0, regs);
return 0;
}
+
+static void uretprobe_perf_func(struct trace_uprobe *tu, unsigned long func,
+ struct pt_regs *regs)
+{
+ uprobe_perf_print(tu, func, regs);
+}
#endif /* CONFIG_PERF_EVENTS */
static
int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data)
{
- struct trace_uprobe *tu = (struct trace_uprobe *)event->data;
+ struct trace_uprobe *tu = event->data;
switch (type) {
case TRACE_REG_REGISTER:
@@ -843,6 +915,23 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
return ret;
}
+static int uretprobe_dispatcher(struct uprobe_consumer *con,
+ unsigned long func, struct pt_regs *regs)
+{
+ struct trace_uprobe *tu;
+
+ tu = container_of(con, struct trace_uprobe, consumer);
+
+ if (tu->flags & TP_FLAG_TRACE)
+ uretprobe_trace_func(tu, func, regs);
+
+#ifdef CONFIG_PERF_EVENTS
+ if (tu->flags & TP_FLAG_PROFILE)
+ uretprobe_perf_func(tu, func, regs);
+#endif
+ return 0;
+}
+
static struct trace_event_functions uprobe_funcs = {
.trace = print_uprobe_event
};
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 0c05a4592047..29f26540e9c9 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -112,7 +112,8 @@ tracepoint_entry_add_probe(struct tracepoint_entry *entry,
int nr_probes = 0;
struct tracepoint_func *old, *new;
- WARN_ON(!probe);
+ if (WARN_ON(!probe))
+ return ERR_PTR(-EINVAL);
debug_print_probes(entry);
old = entry->funcs;
@@ -152,13 +153,18 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
debug_print_probes(entry);
/* (N -> M), (N > 1, M >= 0) probes */
- for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
- if (!probe ||
- (old[nr_probes].func == probe &&
- old[nr_probes].data == data))
- nr_del++;
+ if (probe) {
+ for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
+ if (old[nr_probes].func == probe &&
+ old[nr_probes].data == data)
+ nr_del++;
+ }
}
+ /*
+ * If probe is NULL, then nr_probes = nr_del = 0, and then the
+ * entire entry will be removed.
+ */
if (nr_probes - nr_del == 0) {
/* N -> 0, (N > 1) */
entry->funcs = NULL;
@@ -173,8 +179,7 @@ tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
if (new == NULL)
return ERR_PTR(-ENOMEM);
for (i = 0; old[i].func; i++)
- if (probe &&
- (old[i].func != probe || old[i].data != data))
+ if (old[i].func != probe || old[i].data != data)
new[j++] = old[i];
new[nr_probes - nr_del].func = NULL;
entry->refcount = nr_probes - nr_del;
diff --git a/kernel/uid16.c b/kernel/uid16.c
index d7948eb10225..f6c83d7ef000 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -18,67 +18,43 @@
SYSCALL_DEFINE3(chown16, const char __user *, filename, old_uid_t, user, old_gid_t, group)
{
- long ret = sys_chown(filename, low2highuid(user), low2highgid(group));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, filename, user, group);
- return ret;
+ return sys_chown(filename, low2highuid(user), low2highgid(group));
}
SYSCALL_DEFINE3(lchown16, const char __user *, filename, old_uid_t, user, old_gid_t, group)
{
- long ret = sys_lchown(filename, low2highuid(user), low2highgid(group));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, filename, user, group);
- return ret;
+ return sys_lchown(filename, low2highuid(user), low2highgid(group));
}
SYSCALL_DEFINE3(fchown16, unsigned int, fd, old_uid_t, user, old_gid_t, group)
{
- long ret = sys_fchown(fd, low2highuid(user), low2highgid(group));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, fd, user, group);
- return ret;
+ return sys_fchown(fd, low2highuid(user), low2highgid(group));
}
SYSCALL_DEFINE2(setregid16, old_gid_t, rgid, old_gid_t, egid)
{
- long ret = sys_setregid(low2highgid(rgid), low2highgid(egid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(2, ret, rgid, egid);
- return ret;
+ return sys_setregid(low2highgid(rgid), low2highgid(egid));
}
SYSCALL_DEFINE1(setgid16, old_gid_t, gid)
{
- long ret = sys_setgid(low2highgid(gid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(1, ret, gid);
- return ret;
+ return sys_setgid(low2highgid(gid));
}
SYSCALL_DEFINE2(setreuid16, old_uid_t, ruid, old_uid_t, euid)
{
- long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(2, ret, ruid, euid);
- return ret;
+ return sys_setreuid(low2highuid(ruid), low2highuid(euid));
}
SYSCALL_DEFINE1(setuid16, old_uid_t, uid)
{
- long ret = sys_setuid(low2highuid(uid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(1, ret, uid);
- return ret;
+ return sys_setuid(low2highuid(uid));
}
SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid)
{
- long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid),
+ return sys_setresuid(low2highuid(ruid), low2highuid(euid),
low2highuid(suid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, ruid, euid, suid);
- return ret;
}
SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euidp, old_uid_t __user *, suidp)
@@ -100,11 +76,8 @@ SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euid
SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid)
{
- long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid),
+ return sys_setresgid(low2highgid(rgid), low2highgid(egid),
low2highgid(sgid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(3, ret, rgid, egid, sgid);
- return ret;
}
@@ -127,18 +100,12 @@ SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgidp, old_gid_t __user *, egid
SYSCALL_DEFINE1(setfsuid16, old_uid_t, uid)
{
- long ret = sys_setfsuid(low2highuid(uid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(1, ret, uid);
- return ret;
+ return sys_setfsuid(low2highuid(uid));
}
SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid)
{
- long ret = sys_setfsgid(low2highgid(gid));
- /* avoid REGPARM breakage on x86: */
- asmlinkage_protect(1, ret, gid);
- return ret;
+ return sys_setfsgid(low2highgid(gid));
}
static int groups16_to_user(old_gid_t __user *grouplist,
diff --git a/kernel/user.c b/kernel/user.c
index 5bbb91988e69..69b4c3d48cde 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -51,6 +51,8 @@ struct user_namespace init_user_ns = {
.owner = GLOBAL_ROOT_UID,
.group = GLOBAL_ROOT_GID,
.proc_inum = PROC_USER_INIT_INO,
+ .may_mount_sysfs = true,
+ .may_mount_proc = true,
};
EXPORT_SYMBOL_GPL(init_user_ns);
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 51855f5f6311..d8c30db06c5b 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -25,7 +25,8 @@
static struct kmem_cache *user_ns_cachep __read_mostly;
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file,
+ struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map);
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
@@ -61,6 +62,15 @@ int create_user_ns(struct cred *new)
kgid_t group = new->egid;
int ret;
+ /*
+ * Verify that we can not violate the policy of which files
+ * may be accessed that is specified by the root directory,
+ * by verifing that the root directory is at the root of the
+ * mount namespace which allows all files to be accessed.
+ */
+ if (current_chrooted())
+ return -EPERM;
+
/* The creator needs a mapping in the parent user namespace
* or else we won't be able to reasonably tell userspace who
* created a user_namespace.
@@ -87,6 +97,8 @@ int create_user_ns(struct cred *new)
set_cred_user_ns(new, ns);
+ update_mnt_policy(ns);
+
return 0;
}
@@ -601,10 +613,10 @@ static ssize_t map_write(struct file *file, const char __user *buf,
if (map->nr_extents != 0)
goto out;
- /* Require the appropriate privilege CAP_SETUID or CAP_SETGID
- * over the user namespace in order to set the id mapping.
+ /*
+ * Adjusting namespace settings requires capabilities on the target.
*/
- if (cap_valid(cap_setid) && !ns_capable(ns, cap_setid))
+ if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
goto out;
/* Get a buffer */
@@ -689,7 +701,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
ret = -EPERM;
/* Validate the user is allowed to use user id's mapped to. */
- if (!new_idmap_permitted(ns, cap_setid, &new_map))
+ if (!new_idmap_permitted(file, ns, cap_setid, &new_map))
goto out;
/* Map the lower ids from the parent user namespace to the
@@ -776,7 +788,8 @@ ssize_t proc_projid_map_write(struct file *file, const char __user *buf, size_t
&ns->projid_map, &ns->parent->projid_map);
}
-static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+static bool new_idmap_permitted(const struct file *file,
+ struct user_namespace *ns, int cap_setid,
struct uid_gid_map *new_map)
{
/* Allow mapping to your own filesystem ids */
@@ -784,12 +797,12 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
u32 id = new_map->extent[0].lower_first;
if (cap_setid == CAP_SETUID) {
kuid_t uid = make_kuid(ns->parent, id);
- if (uid_eq(uid, current_fsuid()))
+ if (uid_eq(uid, file->f_cred->fsuid))
return true;
}
else if (cap_setid == CAP_SETGID) {
kgid_t gid = make_kgid(ns->parent, id);
- if (gid_eq(gid, current_fsgid()))
+ if (gid_eq(gid, file->f_cred->fsgid))
return true;
}
}
@@ -800,8 +813,10 @@ static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
/* Allow the specified ids if we have the appropriate capability
* (CAP_SETUID or CAP_SETGID) over the parent user namespace.
+ * And the opener of the id file also had the approprpiate capability.
*/
- if (ns_capable(ns->parent, cap_setid))
+ if (ns_capable(ns->parent, cap_setid) &&
+ file_ns_capable(file, ns->parent, cap_setid))
return true;
return false;
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 4a944676358e..05039e348f07 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -517,6 +517,11 @@ int proc_dowatchdog(struct ctl_table *table, int write,
return ret;
set_sample_period();
+ /*
+ * Watchdog threads shouldn't be enabled if they are
+ * disabled. The 'watchdog_disabled' variable check in
+ * watchdog_*_all_cpus() function takes care of this.
+ */
if (watchdog_enabled && watchdog_thresh)
watchdog_enable_all_cpus();
else
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index b48cd597145d..4aa9f5bc6b2d 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -41,7 +41,12 @@
#include <linux/debug_locks.h>
#include <linux/lockdep.h>
#include <linux/idr.h>
+#include <linux/jhash.h>
#include <linux/hashtable.h>
+#include <linux/rculist.h>
+#include <linux/nodemask.h>
+#include <linux/moduleparam.h>
+#include <linux/uaccess.h>
#include "workqueue_internal.h"
@@ -58,12 +63,11 @@ enum {
* %WORKER_UNBOUND set and concurrency management disabled, and may
* be executing on any CPU. The pool behaves as an unbound one.
*
- * Note that DISASSOCIATED can be flipped only while holding
- * assoc_mutex to avoid changing binding state while
+ * Note that DISASSOCIATED should be flipped only while holding
+ * manager_mutex to avoid changing binding state while
* create_worker() is in progress.
*/
POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
- POOL_MANAGING_WORKERS = 1 << 1, /* managing workers */
POOL_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
POOL_FREEZING = 1 << 3, /* freeze in progress */
@@ -74,12 +78,14 @@ enum {
WORKER_PREP = 1 << 3, /* preparing to run works */
WORKER_CPU_INTENSIVE = 1 << 6, /* cpu intensive */
WORKER_UNBOUND = 1 << 7, /* worker is unbound */
+ WORKER_REBOUND = 1 << 8, /* worker was rebound */
- WORKER_NOT_RUNNING = WORKER_PREP | WORKER_UNBOUND |
- WORKER_CPU_INTENSIVE,
+ WORKER_NOT_RUNNING = WORKER_PREP | WORKER_CPU_INTENSIVE |
+ WORKER_UNBOUND | WORKER_REBOUND,
NR_STD_WORKER_POOLS = 2, /* # standard pools per cpu */
+ UNBOUND_POOL_HASH_ORDER = 6, /* hashed by pool->attrs */
BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
MAX_IDLE_WORKERS_RATIO = 4, /* 1/4 of busy can be idle */
@@ -97,6 +103,8 @@ enum {
*/
RESCUER_NICE_LEVEL = -20,
HIGHPRI_NICE_LEVEL = -20,
+
+ WQ_NAME_LEN = 24,
};
/*
@@ -115,16 +123,26 @@ enum {
* cpu or grabbing pool->lock is enough for read access. If
* POOL_DISASSOCIATED is set, it's identical to L.
*
- * F: wq->flush_mutex protected.
+ * MG: pool->manager_mutex and pool->lock protected. Writes require both
+ * locks. Reads can happen under either lock.
+ *
+ * PL: wq_pool_mutex protected.
+ *
+ * PR: wq_pool_mutex protected for writes. Sched-RCU protected for reads.
+ *
+ * WQ: wq->mutex protected.
*
- * W: workqueue_lock protected.
+ * WR: wq->mutex protected for writes. Sched-RCU protected for reads.
+ *
+ * MD: wq_mayday_lock protected.
*/
/* struct worker is defined in workqueue_internal.h */
struct worker_pool {
spinlock_t lock; /* the pool lock */
- unsigned int cpu; /* I: the associated cpu */
+ int cpu; /* I: the associated cpu */
+ int node; /* I: the associated node ID */
int id; /* I: pool ID */
unsigned int flags; /* X: flags */
@@ -138,12 +156,18 @@ struct worker_pool {
struct timer_list idle_timer; /* L: worker idle timeout */
struct timer_list mayday_timer; /* L: SOS timer for workers */
- /* workers are chained either in busy_hash or idle_list */
+ /* a workers is either on busy_hash or idle_list, or the manager */
DECLARE_HASHTABLE(busy_hash, BUSY_WORKER_HASH_ORDER);
/* L: hash of busy workers */
- struct mutex assoc_mutex; /* protect POOL_DISASSOCIATED */
- struct ida worker_ida; /* L: for worker IDs */
+ /* see manage_workers() for details on the two manager mutexes */
+ struct mutex manager_arb; /* manager arbitration */
+ struct mutex manager_mutex; /* manager exclusion */
+ struct idr worker_idr; /* MG: worker IDs and iteration */
+
+ struct workqueue_attrs *attrs; /* I: worker attributes */
+ struct hlist_node hash_node; /* PL: unbound_pool_hash node */
+ int refcnt; /* PL: refcnt for unbound pools */
/*
* The current concurrency level. As it's likely to be accessed
@@ -151,6 +175,12 @@ struct worker_pool {
* cacheline.
*/
atomic_t nr_running ____cacheline_aligned_in_smp;
+
+ /*
+ * Destruction of pool is sched-RCU protected to allow dereferences
+ * from get_work_pool().
+ */
+ struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
/*
@@ -164,75 +194,107 @@ struct pool_workqueue {
struct workqueue_struct *wq; /* I: the owning workqueue */
int work_color; /* L: current color */
int flush_color; /* L: flushing color */
+ int refcnt; /* L: reference count */
int nr_in_flight[WORK_NR_COLORS];
/* L: nr of in_flight works */
int nr_active; /* L: nr of active works */
int max_active; /* L: max active works */
struct list_head delayed_works; /* L: delayed works */
-};
+ struct list_head pwqs_node; /* WR: node on wq->pwqs */
+ struct list_head mayday_node; /* MD: node on wq->maydays */
+
+ /*
+ * Release of unbound pwq is punted to system_wq. See put_pwq()
+ * and pwq_unbound_release_workfn() for details. pool_workqueue
+ * itself is also sched-RCU protected so that the first pwq can be
+ * determined without grabbing wq->mutex.
+ */
+ struct work_struct unbound_release_work;
+ struct rcu_head rcu;
+} __aligned(1 << WORK_STRUCT_FLAG_BITS);
/*
* Structure used to wait for workqueue flush.
*/
struct wq_flusher {
- struct list_head list; /* F: list of flushers */
- int flush_color; /* F: flush color waiting for */
+ struct list_head list; /* WQ: list of flushers */
+ int flush_color; /* WQ: flush color waiting for */
struct completion done; /* flush completion */
};
-/*
- * All cpumasks are assumed to be always set on UP and thus can't be
- * used to determine whether there's something to be done.
- */
-#ifdef CONFIG_SMP
-typedef cpumask_var_t mayday_mask_t;
-#define mayday_test_and_set_cpu(cpu, mask) \
- cpumask_test_and_set_cpu((cpu), (mask))
-#define mayday_clear_cpu(cpu, mask) cpumask_clear_cpu((cpu), (mask))
-#define for_each_mayday_cpu(cpu, mask) for_each_cpu((cpu), (mask))
-#define alloc_mayday_mask(maskp, gfp) zalloc_cpumask_var((maskp), (gfp))
-#define free_mayday_mask(mask) free_cpumask_var((mask))
-#else
-typedef unsigned long mayday_mask_t;
-#define mayday_test_and_set_cpu(cpu, mask) test_and_set_bit(0, &(mask))
-#define mayday_clear_cpu(cpu, mask) clear_bit(0, &(mask))
-#define for_each_mayday_cpu(cpu, mask) if ((cpu) = 0, (mask))
-#define alloc_mayday_mask(maskp, gfp) true
-#define free_mayday_mask(mask) do { } while (0)
-#endif
+struct wq_device;
/*
- * The externally visible workqueue abstraction is an array of
- * per-CPU workqueues:
+ * The externally visible workqueue. It relays the issued work items to
+ * the appropriate worker_pool through its pool_workqueues.
*/
struct workqueue_struct {
- unsigned int flags; /* W: WQ_* flags */
- union {
- struct pool_workqueue __percpu *pcpu;
- struct pool_workqueue *single;
- unsigned long v;
- } pool_wq; /* I: pwq's */
- struct list_head list; /* W: list of all workqueues */
-
- struct mutex flush_mutex; /* protects wq flushing */
- int work_color; /* F: current work color */
- int flush_color; /* F: current flush color */
+ struct list_head pwqs; /* WR: all pwqs of this wq */
+ struct list_head list; /* PL: list of all workqueues */
+
+ struct mutex mutex; /* protects this wq */
+ int work_color; /* WQ: current work color */
+ int flush_color; /* WQ: current flush color */
atomic_t nr_pwqs_to_flush; /* flush in progress */
- struct wq_flusher *first_flusher; /* F: first flusher */
- struct list_head flusher_queue; /* F: flush waiters */
- struct list_head flusher_overflow; /* F: flush overflow list */
+ struct wq_flusher *first_flusher; /* WQ: first flusher */
+ struct list_head flusher_queue; /* WQ: flush waiters */
+ struct list_head flusher_overflow; /* WQ: flush overflow list */
- mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct list_head maydays; /* MD: pwqs requesting rescue */
struct worker *rescuer; /* I: rescue worker */
- int nr_drainers; /* W: drain in progress */
- int saved_max_active; /* W: saved pwq max_active */
+ int nr_drainers; /* WQ: drain in progress */
+ int saved_max_active; /* WQ: saved pwq max_active */
+
+ struct workqueue_attrs *unbound_attrs; /* WQ: only for unbound wqs */
+ struct pool_workqueue *dfl_pwq; /* WQ: only for unbound wqs */
+
+#ifdef CONFIG_SYSFS
+ struct wq_device *wq_dev; /* I: for sysfs interface */
+#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
- char name[]; /* I: workqueue name */
+ char name[WQ_NAME_LEN]; /* I: workqueue name */
+
+ /* hot fields used during command issue, aligned to cacheline */
+ unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */
+ struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
+ struct pool_workqueue __rcu *numa_pwq_tbl[]; /* FR: unbound pwqs indexed by node */
};
+static struct kmem_cache *pwq_cache;
+
+static int wq_numa_tbl_len; /* highest possible NUMA node id + 1 */
+static cpumask_var_t *wq_numa_possible_cpumask;
+ /* possible CPUs of each node */
+
+static bool wq_disable_numa;
+module_param_named(disable_numa, wq_disable_numa, bool, 0444);
+
+static bool wq_numa_enabled; /* unbound NUMA affinity enabled */
+
+/* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */
+static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf;
+
+static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */
+static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */
+
+static LIST_HEAD(workqueues); /* PL: list of all workqueues */
+static bool workqueue_freezing; /* PL: have wqs started freezing? */
+
+/* the per-cpu worker pools */
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS],
+ cpu_worker_pools);
+
+static DEFINE_IDR(worker_pool_idr); /* PR: idr of all pools */
+
+/* PL: hash of all unbound pools keyed by pool->attrs */
+static DEFINE_HASHTABLE(unbound_pool_hash, UNBOUND_POOL_HASH_ORDER);
+
+/* I: attributes used when instantiating standard unbound pools on demand */
+static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS];
+
struct workqueue_struct *system_wq __read_mostly;
EXPORT_SYMBOL_GPL(system_wq);
struct workqueue_struct *system_highpri_wq __read_mostly;
@@ -244,64 +306,87 @@ EXPORT_SYMBOL_GPL(system_unbound_wq);
struct workqueue_struct *system_freezable_wq __read_mostly;
EXPORT_SYMBOL_GPL(system_freezable_wq);
+static int worker_thread(void *__worker);
+static void copy_workqueue_attrs(struct workqueue_attrs *to,
+ const struct workqueue_attrs *from);
+
#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>
-#define for_each_std_worker_pool(pool, cpu) \
- for ((pool) = &std_worker_pools(cpu)[0]; \
- (pool) < &std_worker_pools(cpu)[NR_STD_WORKER_POOLS]; (pool)++)
+#define assert_rcu_or_pool_mutex() \
+ rcu_lockdep_assert(rcu_read_lock_sched_held() || \
+ lockdep_is_held(&wq_pool_mutex), \
+ "sched RCU or wq_pool_mutex should be held")
-#define for_each_busy_worker(worker, i, pool) \
- hash_for_each(pool->busy_hash, i, worker, hentry)
+#define assert_rcu_or_wq_mutex(wq) \
+ rcu_lockdep_assert(rcu_read_lock_sched_held() || \
+ lockdep_is_held(&wq->mutex), \
+ "sched RCU or wq->mutex should be held")
-static inline int __next_wq_cpu(int cpu, const struct cpumask *mask,
- unsigned int sw)
-{
- if (cpu < nr_cpu_ids) {
- if (sw & 1) {
- cpu = cpumask_next(cpu, mask);
- if (cpu < nr_cpu_ids)
- return cpu;
- }
- if (sw & 2)
- return WORK_CPU_UNBOUND;
- }
- return WORK_CPU_END;
-}
+#ifdef CONFIG_LOCKDEP
+#define assert_manager_or_pool_lock(pool) \
+ WARN_ONCE(debug_locks && \
+ !lockdep_is_held(&(pool)->manager_mutex) && \
+ !lockdep_is_held(&(pool)->lock), \
+ "pool->manager_mutex or ->lock should be held")
+#else
+#define assert_manager_or_pool_lock(pool) do { } while (0)
+#endif
-static inline int __next_pwq_cpu(int cpu, const struct cpumask *mask,
- struct workqueue_struct *wq)
-{
- return __next_wq_cpu(cpu, mask, !(wq->flags & WQ_UNBOUND) ? 1 : 2);
-}
+#define for_each_cpu_worker_pool(pool, cpu) \
+ for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0]; \
+ (pool) < &per_cpu(cpu_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \
+ (pool)++)
-/*
- * CPU iterators
+/**
+ * for_each_pool - iterate through all worker_pools in the system
+ * @pool: iteration cursor
+ * @pi: integer used for iteration
*
- * An extra cpu number is defined using an invalid cpu number
- * (WORK_CPU_UNBOUND) to host workqueues which are not bound to any
- * specific CPU. The following iterators are similar to for_each_*_cpu()
- * iterators but also considers the unbound CPU.
+ * This must be called either with wq_pool_mutex held or sched RCU read
+ * locked. If the pool needs to be used beyond the locking in effect, the
+ * caller is responsible for guaranteeing that the pool stays online.
*
- * for_each_wq_cpu() : possible CPUs + WORK_CPU_UNBOUND
- * for_each_online_wq_cpu() : online CPUs + WORK_CPU_UNBOUND
- * for_each_pwq_cpu() : possible CPUs for bound workqueues,
- * WORK_CPU_UNBOUND for unbound workqueues
+ * The if/else clause exists only for the lockdep assertion and can be
+ * ignored.
*/
-#define for_each_wq_cpu(cpu) \
- for ((cpu) = __next_wq_cpu(-1, cpu_possible_mask, 3); \
- (cpu) < WORK_CPU_END; \
- (cpu) = __next_wq_cpu((cpu), cpu_possible_mask, 3))
+#define for_each_pool(pool, pi) \
+ idr_for_each_entry(&worker_pool_idr, pool, pi) \
+ if (({ assert_rcu_or_pool_mutex(); false; })) { } \
+ else
-#define for_each_online_wq_cpu(cpu) \
- for ((cpu) = __next_wq_cpu(-1, cpu_online_mask, 3); \
- (cpu) < WORK_CPU_END; \
- (cpu) = __next_wq_cpu((cpu), cpu_online_mask, 3))
+/**
+ * for_each_pool_worker - iterate through all workers of a worker_pool
+ * @worker: iteration cursor
+ * @wi: integer used for iteration
+ * @pool: worker_pool to iterate workers of
+ *
+ * This must be called with either @pool->manager_mutex or ->lock held.
+ *
+ * The if/else clause exists only for the lockdep assertion and can be
+ * ignored.
+ */
+#define for_each_pool_worker(worker, wi, pool) \
+ idr_for_each_entry(&(pool)->worker_idr, (worker), (wi)) \
+ if (({ assert_manager_or_pool_lock((pool)); false; })) { } \
+ else
-#define for_each_pwq_cpu(cpu, wq) \
- for ((cpu) = __next_pwq_cpu(-1, cpu_possible_mask, (wq)); \
- (cpu) < WORK_CPU_END; \
- (cpu) = __next_pwq_cpu((cpu), cpu_possible_mask, (wq)))
+/**
+ * for_each_pwq - iterate through all pool_workqueues of the specified workqueue
+ * @pwq: iteration cursor
+ * @wq: the target workqueue
+ *
+ * This must be called either with wq->mutex held or sched RCU read locked.
+ * If the pwq needs to be used beyond the locking in effect, the caller is
+ * responsible for guaranteeing that the pwq stays online.
+ *
+ * The if/else clause exists only for the lockdep assertion and can be
+ * ignored.
+ */
+#define for_each_pwq(pwq, wq) \
+ list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node) \
+ if (({ assert_rcu_or_wq_mutex(wq); false; })) { } \
+ else
#ifdef CONFIG_DEBUG_OBJECTS_WORK
@@ -419,77 +504,35 @@ static inline void debug_work_activate(struct work_struct *work) { }
static inline void debug_work_deactivate(struct work_struct *work) { }
#endif
-/* Serializes the accesses to the list of workqueues. */
-static DEFINE_SPINLOCK(workqueue_lock);
-static LIST_HEAD(workqueues);
-static bool workqueue_freezing; /* W: have wqs started freezing? */
-
-/*
- * The CPU and unbound standard worker pools. The unbound ones have
- * POOL_DISASSOCIATED set, and their workers have WORKER_UNBOUND set.
- */
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS],
- cpu_std_worker_pools);
-static struct worker_pool unbound_std_worker_pools[NR_STD_WORKER_POOLS];
-
-/* idr of all pools */
-static DEFINE_MUTEX(worker_pool_idr_mutex);
-static DEFINE_IDR(worker_pool_idr);
-
-static int worker_thread(void *__worker);
-
-static struct worker_pool *std_worker_pools(int cpu)
-{
- if (cpu != WORK_CPU_UNBOUND)
- return per_cpu(cpu_std_worker_pools, cpu);
- else
- return unbound_std_worker_pools;
-}
-
-static int std_worker_pool_pri(struct worker_pool *pool)
-{
- return pool - std_worker_pools(pool->cpu);
-}
-
/* allocate ID and assign it to @pool */
static int worker_pool_assign_id(struct worker_pool *pool)
{
int ret;
- mutex_lock(&worker_pool_idr_mutex);
+ lockdep_assert_held(&wq_pool_mutex);
+
ret = idr_alloc(&worker_pool_idr, pool, 0, 0, GFP_KERNEL);
- if (ret >= 0)
+ if (ret >= 0) {
pool->id = ret;
- mutex_unlock(&worker_pool_idr_mutex);
-
- return ret < 0 ? ret : 0;
+ return 0;
+ }
+ return ret;
}
-/*
- * Lookup worker_pool by id. The idr currently is built during boot and
- * never modified. Don't worry about locking for now.
+/**
+ * unbound_pwq_by_node - return the unbound pool_workqueue for the given node
+ * @wq: the target workqueue
+ * @node: the node ID
+ *
+ * This must be called either with pwq_lock held or sched RCU read locked.
+ * If the pwq needs to be used beyond the locking in effect, the caller is
+ * responsible for guaranteeing that the pwq stays online.
*/
-static struct worker_pool *worker_pool_by_id(int pool_id)
+static struct pool_workqueue *unbound_pwq_by_node(struct workqueue_struct *wq,
+ int node)
{
- return idr_find(&worker_pool_idr, pool_id);
-}
-
-static struct worker_pool *get_std_worker_pool(int cpu, bool highpri)
-{
- struct worker_pool *pools = std_worker_pools(cpu);
-
- return &pools[highpri];
-}
-
-static struct pool_workqueue *get_pwq(unsigned int cpu,
- struct workqueue_struct *wq)
-{
- if (!(wq->flags & WQ_UNBOUND)) {
- if (likely(cpu < nr_cpu_ids))
- return per_cpu_ptr(wq->pool_wq.pcpu, cpu);
- } else if (likely(cpu == WORK_CPU_UNBOUND))
- return wq->pool_wq.single;
- return NULL;
+ assert_rcu_or_wq_mutex(wq);
+ return rcu_dereference_raw(wq->numa_pwq_tbl[node]);
}
static unsigned int work_color_to_flags(int color)
@@ -531,7 +574,7 @@ static int work_next_color(int color)
static inline void set_work_data(struct work_struct *work, unsigned long data,
unsigned long flags)
{
- BUG_ON(!work_pending(work));
+ WARN_ON_ONCE(!work_pending(work));
atomic_long_set(&work->data, data | flags | work_static(work));
}
@@ -583,13 +626,23 @@ static struct pool_workqueue *get_work_pwq(struct work_struct *work)
* @work: the work item of interest
*
* Return the worker_pool @work was last associated with. %NULL if none.
+ *
+ * Pools are created and destroyed under wq_pool_mutex, and allows read
+ * access under sched-RCU read lock. As such, this function should be
+ * called under wq_pool_mutex or with preemption disabled.
+ *
+ * All fields of the returned pool are accessible as long as the above
+ * mentioned locking is in effect. If the returned pool needs to be used
+ * beyond the critical section, the caller is responsible for ensuring the
+ * returned pool is and stays online.
*/
static struct worker_pool *get_work_pool(struct work_struct *work)
{
unsigned long data = atomic_long_read(&work->data);
- struct worker_pool *pool;
int pool_id;
+ assert_rcu_or_pool_mutex();
+
if (data & WORK_STRUCT_PWQ)
return ((struct pool_workqueue *)
(data & WORK_STRUCT_WQ_DATA_MASK))->pool;
@@ -598,9 +651,7 @@ static struct worker_pool *get_work_pool(struct work_struct *work)
if (pool_id == WORK_OFFQ_POOL_NONE)
return NULL;
- pool = worker_pool_by_id(pool_id);
- WARN_ON_ONCE(!pool);
- return pool;
+ return idr_find(&worker_pool_idr, pool_id);
}
/**
@@ -689,7 +740,7 @@ static bool need_to_manage_workers(struct worker_pool *pool)
/* Do we have too many workers and should some go away? */
static bool too_many_workers(struct worker_pool *pool)
{
- bool managing = pool->flags & POOL_MANAGING_WORKERS;
+ bool managing = mutex_is_locked(&pool->manager_arb);
int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
int nr_busy = pool->nr_workers - nr_idle;
@@ -744,7 +795,7 @@ static void wake_up_worker(struct worker_pool *pool)
* CONTEXT:
* spin_lock_irq(rq->lock)
*/
-void wq_worker_waking_up(struct task_struct *task, unsigned int cpu)
+void wq_worker_waking_up(struct task_struct *task, int cpu)
{
struct worker *worker = kthread_data(task);
@@ -769,8 +820,7 @@ void wq_worker_waking_up(struct task_struct *task, unsigned int cpu)
* RETURNS:
* Worker task on @cpu to wake up, %NULL if none.
*/
-struct task_struct *wq_worker_sleeping(struct task_struct *task,
- unsigned int cpu)
+struct task_struct *wq_worker_sleeping(struct task_struct *task, int cpu)
{
struct worker *worker = kthread_data(task), *to_wakeup = NULL;
struct worker_pool *pool;
@@ -786,7 +836,8 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task,
pool = worker->pool;
/* this can only happen on the local cpu */
- BUG_ON(cpu != raw_smp_processor_id());
+ if (WARN_ON_ONCE(cpu != raw_smp_processor_id()))
+ return NULL;
/*
* The counterpart of the following dec_and_test, implied mb,
@@ -891,13 +942,12 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
* recycled work item as currently executing and make it wait until the
* current execution finishes, introducing an unwanted dependency.
*
- * This function checks the work item address, work function and workqueue
- * to avoid false positives. Note that this isn't complete as one may
- * construct a work function which can introduce dependency onto itself
- * through a recycled work item. Well, if somebody wants to shoot oneself
- * in the foot that badly, there's only so much we can do, and if such
- * deadlock actually occurs, it should be easy to locate the culprit work
- * function.
+ * This function checks the work item address and work function to avoid
+ * false positives. Note that this isn't complete as one may construct a
+ * work function which can introduce dependency onto itself through a
+ * recycled work item. Well, if somebody wants to shoot oneself in the
+ * foot that badly, there's only so much we can do, and if such deadlock
+ * actually occurs, it should be easy to locate the culprit work function.
*
* CONTEXT:
* spin_lock_irq(pool->lock).
@@ -961,6 +1011,64 @@ static void move_linked_works(struct work_struct *work, struct list_head *head,
*nextp = n;
}
+/**
+ * get_pwq - get an extra reference on the specified pool_workqueue
+ * @pwq: pool_workqueue to get
+ *
+ * Obtain an extra reference on @pwq. The caller should guarantee that
+ * @pwq has positive refcnt and be holding the matching pool->lock.
+ */
+static void get_pwq(struct pool_workqueue *pwq)
+{
+ lockdep_assert_held(&pwq->pool->lock);
+ WARN_ON_ONCE(pwq->refcnt <= 0);
+ pwq->refcnt++;
+}
+
+/**
+ * put_pwq - put a pool_workqueue reference
+ * @pwq: pool_workqueue to put
+ *
+ * Drop a reference of @pwq. If its refcnt reaches zero, schedule its
+ * destruction. The caller should be holding the matching pool->lock.
+ */
+static void put_pwq(struct pool_workqueue *pwq)
+{
+ lockdep_assert_held(&pwq->pool->lock);
+ if (likely(--pwq->refcnt))
+ return;
+ if (WARN_ON_ONCE(!(pwq->wq->flags & WQ_UNBOUND)))
+ return;
+ /*
+ * @pwq can't be released under pool->lock, bounce to
+ * pwq_unbound_release_workfn(). This never recurses on the same
+ * pool->lock as this path is taken only for unbound workqueues and
+ * the release work item is scheduled on a per-cpu workqueue. To
+ * avoid lockdep warning, unbound pool->locks are given lockdep
+ * subclass of 1 in get_unbound_pool().
+ */
+ schedule_work(&pwq->unbound_release_work);
+}
+
+/**
+ * put_pwq_unlocked - put_pwq() with surrounding pool lock/unlock
+ * @pwq: pool_workqueue to put (can be %NULL)
+ *
+ * put_pwq() with locking. This function also allows %NULL @pwq.
+ */
+static void put_pwq_unlocked(struct pool_workqueue *pwq)
+{
+ if (pwq) {
+ /*
+ * As both pwqs and pools are sched-RCU protected, the
+ * following lock operations are safe.
+ */
+ spin_lock_irq(&pwq->pool->lock);
+ put_pwq(pwq);
+ spin_unlock_irq(&pwq->pool->lock);
+ }
+}
+
static void pwq_activate_delayed_work(struct work_struct *work)
{
struct pool_workqueue *pwq = get_work_pwq(work);
@@ -992,9 +1100,9 @@ static void pwq_activate_first_delayed(struct pool_workqueue *pwq)
*/
static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color)
{
- /* ignore uncolored works */
+ /* uncolored work items don't participate in flushing or nr_active */
if (color == WORK_NO_COLOR)
- return;
+ goto out_put;
pwq->nr_in_flight[color]--;
@@ -1007,11 +1115,11 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color)
/* is flush in progress and are we at the flushing tip? */
if (likely(pwq->flush_color != color))
- return;
+ goto out_put;
/* are there still in-flight works? */
if (pwq->nr_in_flight[color])
- return;
+ goto out_put;
/* this pwq is done, clear flush_color */
pwq->flush_color = -1;
@@ -1022,6 +1130,8 @@ static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color)
*/
if (atomic_dec_and_test(&pwq->wq->nr_pwqs_to_flush))
complete(&pwq->wq->first_flusher->done);
+out_put:
+ put_pwq(pwq);
}
/**
@@ -1144,11 +1254,12 @@ static void insert_work(struct pool_workqueue *pwq, struct work_struct *work,
/* we own @work, set data and link */
set_work_pwq(work, pwq, extra_flags);
list_add_tail(&work->entry, head);
+ get_pwq(pwq);
/*
- * Ensure either worker_sched_deactivated() sees the above
- * list_add_tail() or we see zero nr_running to avoid workers
- * lying around lazily while there are works to be processed.
+ * Ensure either wq_worker_sleeping() sees the above
+ * list_add_tail() or we see zero nr_running to avoid workers lying
+ * around lazily while there are works to be processed.
*/
smp_mb();
@@ -1172,10 +1283,11 @@ static bool is_chained_work(struct workqueue_struct *wq)
return worker && worker->current_pwq->wq == wq;
}
-static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
+static void __queue_work(int cpu, struct workqueue_struct *wq,
struct work_struct *work)
{
struct pool_workqueue *pwq;
+ struct worker_pool *last_pool;
struct list_head *worklist;
unsigned int work_flags;
unsigned int req_cpu = cpu;
@@ -1191,48 +1303,62 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
debug_work_activate(work);
/* if dying, only works from the same workqueue are allowed */
- if (unlikely(wq->flags & WQ_DRAINING) &&
+ if (unlikely(wq->flags & __WQ_DRAINING) &&
WARN_ON_ONCE(!is_chained_work(wq)))
return;
+retry:
+ if (req_cpu == WORK_CPU_UNBOUND)
+ cpu = raw_smp_processor_id();
- /* determine the pwq to use */
- if (!(wq->flags & WQ_UNBOUND)) {
- struct worker_pool *last_pool;
-
- if (cpu == WORK_CPU_UNBOUND)
- cpu = raw_smp_processor_id();
-
- /*
- * It's multi cpu. If @work was previously on a different
- * cpu, it might still be running there, in which case the
- * work needs to be queued on that cpu to guarantee
- * non-reentrancy.
- */
- pwq = get_pwq(cpu, wq);
- last_pool = get_work_pool(work);
+ /* pwq which will be used unless @work is executing elsewhere */
+ if (!(wq->flags & WQ_UNBOUND))
+ pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
+ else
+ pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu));
- if (last_pool && last_pool != pwq->pool) {
- struct worker *worker;
+ /*
+ * If @work was previously on a different pool, it might still be
+ * running there, in which case the work needs to be queued on that
+ * pool to guarantee non-reentrancy.
+ */
+ last_pool = get_work_pool(work);
+ if (last_pool && last_pool != pwq->pool) {
+ struct worker *worker;
- spin_lock(&last_pool->lock);
+ spin_lock(&last_pool->lock);
- worker = find_worker_executing_work(last_pool, work);
+ worker = find_worker_executing_work(last_pool, work);
- if (worker && worker->current_pwq->wq == wq) {
- pwq = get_pwq(last_pool->cpu, wq);
- } else {
- /* meh... not running there, queue here */
- spin_unlock(&last_pool->lock);
- spin_lock(&pwq->pool->lock);
- }
+ if (worker && worker->current_pwq->wq == wq) {
+ pwq = worker->current_pwq;
} else {
+ /* meh... not running there, queue here */
+ spin_unlock(&last_pool->lock);
spin_lock(&pwq->pool->lock);
}
} else {
- pwq = get_pwq(WORK_CPU_UNBOUND, wq);
spin_lock(&pwq->pool->lock);
}
+ /*
+ * pwq is determined and locked. For unbound pools, we could have
+ * raced with pwq release and it could already be dead. If its
+ * refcnt is zero, repeat pwq selection. Note that pwqs never die
+ * without another pwq replacing it in the numa_pwq_tbl or while
+ * work items are executing on it, so the retrying is guaranteed to
+ * make forward-progress.
+ */
+ if (unlikely(!pwq->refcnt)) {
+ if (wq->flags & WQ_UNBOUND) {
+ spin_unlock(&pwq->pool->lock);
+ cpu_relax();
+ goto retry;
+ }
+ /* oops */
+ WARN_ONCE(true, "workqueue: per-cpu pwq for %s on cpu%d has 0 refcnt",
+ wq->name, cpu);
+ }
+
/* pwq determined, queue */
trace_workqueue_queue_work(req_cpu, pwq, work);
@@ -1287,22 +1413,6 @@ bool queue_work_on(int cpu, struct workqueue_struct *wq,
}
EXPORT_SYMBOL_GPL(queue_work_on);
-/**
- * queue_work - queue work on a workqueue
- * @wq: workqueue to use
- * @work: work to queue
- *
- * Returns %false if @work was already on a queue, %true otherwise.
- *
- * We queue the work to the CPU on which it was submitted, but if the CPU dies
- * it can be processed by another CPU.
- */
-bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
-{
- return queue_work_on(WORK_CPU_UNBOUND, wq, work);
-}
-EXPORT_SYMBOL_GPL(queue_work);
-
void delayed_work_timer_fn(unsigned long __data)
{
struct delayed_work *dwork = (struct delayed_work *)__data;
@@ -1378,21 +1488,6 @@ bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
EXPORT_SYMBOL_GPL(queue_delayed_work_on);
/**
- * queue_delayed_work - queue work on a workqueue after delay
- * @wq: workqueue to use
- * @dwork: delayable work to queue
- * @delay: number of jiffies to wait before queueing
- *
- * Equivalent to queue_delayed_work_on() but tries to use the local CPU.
- */
-bool queue_delayed_work(struct workqueue_struct *wq,
- struct delayed_work *dwork, unsigned long delay)
-{
- return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
-}
-EXPORT_SYMBOL_GPL(queue_delayed_work);
-
-/**
* mod_delayed_work_on - modify delay of or queue a delayed work on specific CPU
* @cpu: CPU number to execute work on
* @wq: workqueue to use
@@ -1431,21 +1526,6 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
EXPORT_SYMBOL_GPL(mod_delayed_work_on);
/**
- * mod_delayed_work - modify delay of or queue a delayed work
- * @wq: workqueue to use
- * @dwork: work to queue
- * @delay: number of jiffies to wait before queueing
- *
- * mod_delayed_work_on() on local CPU.
- */
-bool mod_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork,
- unsigned long delay)
-{
- return mod_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
-}
-EXPORT_SYMBOL_GPL(mod_delayed_work);
-
-/**
* worker_enter_idle - enter idle state
* @worker: worker which is entering idle state
*
@@ -1459,9 +1539,10 @@ static void worker_enter_idle(struct worker *worker)
{
struct worker_pool *pool = worker->pool;
- BUG_ON(worker->flags & WORKER_IDLE);
- BUG_ON(!list_empty(&worker->entry) &&
- (worker->hentry.next || worker->hentry.pprev));
+ if (WARN_ON_ONCE(worker->flags & WORKER_IDLE) ||
+ WARN_ON_ONCE(!list_empty(&worker->entry) &&
+ (worker->hentry.next || worker->hentry.pprev)))
+ return;
/* can't use worker_set_flags(), also called from start_worker() */
worker->flags |= WORKER_IDLE;
@@ -1498,22 +1579,25 @@ static void worker_leave_idle(struct worker *worker)
{
struct worker_pool *pool = worker->pool;
- BUG_ON(!(worker->flags & WORKER_IDLE));
+ if (WARN_ON_ONCE(!(worker->flags & WORKER_IDLE)))
+ return;
worker_clr_flags(worker, WORKER_IDLE);
pool->nr_idle--;
list_del_init(&worker->entry);
}
/**
- * worker_maybe_bind_and_lock - bind worker to its cpu if possible and lock pool
- * @worker: self
+ * worker_maybe_bind_and_lock - try to bind %current to worker_pool and lock it
+ * @pool: target worker_pool
+ *
+ * Bind %current to the cpu of @pool if it is associated and lock @pool.
*
* Works which are scheduled while the cpu is online must at least be
* scheduled to a worker which is bound to the cpu so that if they are
* flushed from cpu callbacks while cpu is going down, they are
* guaranteed to execute on the cpu.
*
- * This function is to be used by rogue workers and rescuers to bind
+ * This function is to be used by unbound workers and rescuers to bind
* themselves to the target cpu and may race with cpu going down or
* coming online. kthread_bind() can't be used because it may put the
* worker to already dead cpu and set_cpus_allowed_ptr() can't be used
@@ -1534,12 +1618,9 @@ static void worker_leave_idle(struct worker *worker)
* %true if the associated pool is online (@worker is successfully
* bound), %false if offline.
*/
-static bool worker_maybe_bind_and_lock(struct worker *worker)
+static bool worker_maybe_bind_and_lock(struct worker_pool *pool)
__acquires(&pool->lock)
{
- struct worker_pool *pool = worker->pool;
- struct task_struct *task = worker->task;
-
while (true) {
/*
* The following call may fail, succeed or succeed
@@ -1548,14 +1629,13 @@ __acquires(&pool->lock)
* against POOL_DISASSOCIATED.
*/
if (!(pool->flags & POOL_DISASSOCIATED))
- set_cpus_allowed_ptr(task, get_cpu_mask(pool->cpu));
+ set_cpus_allowed_ptr(current, pool->attrs->cpumask);
spin_lock_irq(&pool->lock);
if (pool->flags & POOL_DISASSOCIATED)
return false;
- if (task_cpu(task) == pool->cpu &&
- cpumask_equal(&current->cpus_allowed,
- get_cpu_mask(pool->cpu)))
+ if (task_cpu(current) == pool->cpu &&
+ cpumask_equal(&current->cpus_allowed, pool->attrs->cpumask))
return true;
spin_unlock_irq(&pool->lock);
@@ -1570,108 +1650,6 @@ __acquires(&pool->lock)
}
}
-/*
- * Rebind an idle @worker to its CPU. worker_thread() will test
- * list_empty(@worker->entry) before leaving idle and call this function.
- */
-static void idle_worker_rebind(struct worker *worker)
-{
- /* CPU may go down again inbetween, clear UNBOUND only on success */
- if (worker_maybe_bind_and_lock(worker))
- worker_clr_flags(worker, WORKER_UNBOUND);
-
- /* rebind complete, become available again */
- list_add(&worker->entry, &worker->pool->idle_list);
- spin_unlock_irq(&worker->pool->lock);
-}
-
-/*
- * Function for @worker->rebind.work used to rebind unbound busy workers to
- * the associated cpu which is coming back online. This is scheduled by
- * cpu up but can race with other cpu hotplug operations and may be
- * executed twice without intervening cpu down.
- */
-static void busy_worker_rebind_fn(struct work_struct *work)
-{
- struct worker *worker = container_of(work, struct worker, rebind_work);
-
- if (worker_maybe_bind_and_lock(worker))
- worker_clr_flags(worker, WORKER_UNBOUND);
-
- spin_unlock_irq(&worker->pool->lock);
-}
-
-/**
- * rebind_workers - rebind all workers of a pool to the associated CPU
- * @pool: pool of interest
- *
- * @pool->cpu is coming online. Rebind all workers to the CPU. Rebinding
- * is different for idle and busy ones.
- *
- * Idle ones will be removed from the idle_list and woken up. They will
- * add themselves back after completing rebind. This ensures that the
- * idle_list doesn't contain any unbound workers when re-bound busy workers
- * try to perform local wake-ups for concurrency management.
- *
- * Busy workers can rebind after they finish their current work items.
- * Queueing the rebind work item at the head of the scheduled list is
- * enough. Note that nr_running will be properly bumped as busy workers
- * rebind.
- *
- * On return, all non-manager workers are scheduled for rebind - see
- * manage_workers() for the manager special case. Any idle worker
- * including the manager will not appear on @idle_list until rebind is
- * complete, making local wake-ups safe.
- */
-static void rebind_workers(struct worker_pool *pool)
-{
- struct worker *worker, *n;
- int i;
-
- lockdep_assert_held(&pool->assoc_mutex);
- lockdep_assert_held(&pool->lock);
-
- /* dequeue and kick idle ones */
- list_for_each_entry_safe(worker, n, &pool->idle_list, entry) {
- /*
- * idle workers should be off @pool->idle_list until rebind
- * is complete to avoid receiving premature local wake-ups.
- */
- list_del_init(&worker->entry);
-
- /*
- * worker_thread() will see the above dequeuing and call
- * idle_worker_rebind().
- */
- wake_up_process(worker->task);
- }
-
- /* rebind busy workers */
- for_each_busy_worker(worker, i, pool) {
- struct work_struct *rebind_work = &worker->rebind_work;
- struct workqueue_struct *wq;
-
- if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
- work_data_bits(rebind_work)))
- continue;
-
- debug_work_activate(rebind_work);
-
- /*
- * wq doesn't really matter but let's keep @worker->pool
- * and @pwq->pool consistent for sanity.
- */
- if (std_worker_pool_pri(worker->pool))
- wq = system_highpri_wq;
- else
- wq = system_wq;
-
- insert_work(get_pwq(pool->cpu, wq), rebind_work,
- worker->scheduled.next,
- work_color_to_flags(WORK_NO_COLOR));
- }
-}
-
static struct worker *alloc_worker(void)
{
struct worker *worker;
@@ -1680,7 +1658,6 @@ static struct worker *alloc_worker(void)
if (worker) {
INIT_LIST_HEAD(&worker->entry);
INIT_LIST_HEAD(&worker->scheduled);
- INIT_WORK(&worker->rebind_work, busy_worker_rebind_fn);
/* on creation a worker is in !idle && prep state */
worker->flags = WORKER_PREP;
}
@@ -1703,18 +1680,25 @@ static struct worker *alloc_worker(void)
*/
static struct worker *create_worker(struct worker_pool *pool)
{
- const char *pri = std_worker_pool_pri(pool) ? "H" : "";
struct worker *worker = NULL;
int id = -1;
+ char id_buf[16];
+ lockdep_assert_held(&pool->manager_mutex);
+
+ /*
+ * ID is needed to determine kthread name. Allocate ID first
+ * without installing the pointer.
+ */
+ idr_preload(GFP_KERNEL);
spin_lock_irq(&pool->lock);
- while (ida_get_new(&pool->worker_ida, &id)) {
- spin_unlock_irq(&pool->lock);
- if (!ida_pre_get(&pool->worker_ida, GFP_KERNEL))
- goto fail;
- spin_lock_irq(&pool->lock);
- }
+
+ id = idr_alloc(&pool->worker_idr, NULL, 0, 0, GFP_NOWAIT);
+
spin_unlock_irq(&pool->lock);
+ idr_preload_end();
+ if (id < 0)
+ goto fail;
worker = alloc_worker();
if (!worker)
@@ -1723,40 +1707,46 @@ static struct worker *create_worker(struct worker_pool *pool)
worker->pool = pool;
worker->id = id;
- if (pool->cpu != WORK_CPU_UNBOUND)
- worker->task = kthread_create_on_node(worker_thread,
- worker, cpu_to_node(pool->cpu),
- "kworker/%u:%d%s", pool->cpu, id, pri);
+ if (pool->cpu >= 0)
+ snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,
+ pool->attrs->nice < 0 ? "H" : "");
else
- worker->task = kthread_create(worker_thread, worker,
- "kworker/u:%d%s", id, pri);
+ snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
+
+ worker->task = kthread_create_on_node(worker_thread, worker, pool->node,
+ "kworker/%s", id_buf);
if (IS_ERR(worker->task))
goto fail;
- if (std_worker_pool_pri(pool))
- set_user_nice(worker->task, HIGHPRI_NICE_LEVEL);
+ /*
+ * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
+ * online CPUs. It'll be re-applied when any of the CPUs come up.
+ */
+ set_user_nice(worker->task, pool->attrs->nice);
+ set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
+
+ /* prevent userland from meddling with cpumask of workqueue workers */
+ worker->task->flags |= PF_NO_SETAFFINITY;
/*
- * Determine CPU binding of the new worker depending on
- * %POOL_DISASSOCIATED. The caller is responsible for ensuring the
- * flag remains stable across this function. See the comments
- * above the flag definition for details.
- *
- * As an unbound worker may later become a regular one if CPU comes
- * online, make sure every worker has %PF_THREAD_BOUND set.
+ * The caller is responsible for ensuring %POOL_DISASSOCIATED
+ * remains stable across this function. See the comments above the
+ * flag definition for details.
*/
- if (!(pool->flags & POOL_DISASSOCIATED)) {
- kthread_bind(worker->task, pool->cpu);
- } else {
- worker->task->flags |= PF_THREAD_BOUND;
+ if (pool->flags & POOL_DISASSOCIATED)
worker->flags |= WORKER_UNBOUND;
- }
+
+ /* successful, commit the pointer to idr */
+ spin_lock_irq(&pool->lock);
+ idr_replace(&pool->worker_idr, worker, worker->id);
+ spin_unlock_irq(&pool->lock);
return worker;
+
fail:
if (id >= 0) {
spin_lock_irq(&pool->lock);
- ida_remove(&pool->worker_ida, id);
+ idr_remove(&pool->worker_idr, id);
spin_unlock_irq(&pool->lock);
}
kfree(worker);
@@ -1781,6 +1771,30 @@ static void start_worker(struct worker *worker)
}
/**
+ * create_and_start_worker - create and start a worker for a pool
+ * @pool: the target pool
+ *
+ * Grab the managership of @pool and create and start a new worker for it.
+ */
+static int create_and_start_worker(struct worker_pool *pool)
+{
+ struct worker *worker;
+
+ mutex_lock(&pool->manager_mutex);
+
+ worker = create_worker(pool);
+ if (worker) {
+ spin_lock_irq(&pool->lock);
+ start_worker(worker);
+ spin_unlock_irq(&pool->lock);
+ }
+
+ mutex_unlock(&pool->manager_mutex);
+
+ return worker ? 0 : -ENOMEM;
+}
+
+/**
* destroy_worker - destroy a workqueue worker
* @worker: worker to be destroyed
*
@@ -1792,11 +1806,14 @@ static void start_worker(struct worker *worker)
static void destroy_worker(struct worker *worker)
{
struct worker_pool *pool = worker->pool;
- int id = worker->id;
+
+ lockdep_assert_held(&pool->manager_mutex);
+ lockdep_assert_held(&pool->lock);
/* sanity check frenzy */
- BUG_ON(worker->current_work);
- BUG_ON(!list_empty(&worker->scheduled));
+ if (WARN_ON(worker->current_work) ||
+ WARN_ON(!list_empty(&worker->scheduled)))
+ return;
if (worker->flags & WORKER_STARTED)
pool->nr_workers--;
@@ -1806,13 +1823,14 @@ static void destroy_worker(struct worker *worker)
list_del_init(&worker->entry);
worker->flags |= WORKER_DIE;
+ idr_remove(&pool->worker_idr, worker->id);
+
spin_unlock_irq(&pool->lock);
kthread_stop(worker->task);
kfree(worker);
spin_lock_irq(&pool->lock);
- ida_remove(&pool->worker_ida, id);
}
static void idle_worker_timeout(unsigned long __pool)
@@ -1841,23 +1859,21 @@ static void idle_worker_timeout(unsigned long __pool)
spin_unlock_irq(&pool->lock);
}
-static bool send_mayday(struct work_struct *work)
+static void send_mayday(struct work_struct *work)
{
struct pool_workqueue *pwq = get_work_pwq(work);
struct workqueue_struct *wq = pwq->wq;
- unsigned int cpu;
- if (!(wq->flags & WQ_RESCUER))
- return false;
+ lockdep_assert_held(&wq_mayday_lock);
+
+ if (!wq->rescuer)
+ return;
/* mayday mayday mayday */
- cpu = pwq->pool->cpu;
- /* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
- if (cpu == WORK_CPU_UNBOUND)
- cpu = 0;
- if (!mayday_test_and_set_cpu(cpu, wq->mayday_mask))
+ if (list_empty(&pwq->mayday_node)) {
+ list_add_tail(&pwq->mayday_node, &wq->maydays);
wake_up_process(wq->rescuer->task);
- return true;
+ }
}
static void pool_mayday_timeout(unsigned long __pool)
@@ -1865,7 +1881,8 @@ static void pool_mayday_timeout(unsigned long __pool)
struct worker_pool *pool = (void *)__pool;
struct work_struct *work;
- spin_lock_irq(&pool->lock);
+ spin_lock_irq(&wq_mayday_lock); /* for wq->maydays */
+ spin_lock(&pool->lock);
if (need_to_create_worker(pool)) {
/*
@@ -1878,7 +1895,8 @@ static void pool_mayday_timeout(unsigned long __pool)
send_mayday(work);
}
- spin_unlock_irq(&pool->lock);
+ spin_unlock(&pool->lock);
+ spin_unlock_irq(&wq_mayday_lock);
mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL);
}
@@ -1893,8 +1911,8 @@ static void pool_mayday_timeout(unsigned long __pool)
* sent to all rescuers with works scheduled on @pool to resolve
* possible allocation deadlock.
*
- * On return, need_to_create_worker() is guaranteed to be false and
- * may_start_working() true.
+ * On return, need_to_create_worker() is guaranteed to be %false and
+ * may_start_working() %true.
*
* LOCKING:
* spin_lock_irq(pool->lock) which may be released and regrabbed
@@ -1902,7 +1920,7 @@ static void pool_mayday_timeout(unsigned long __pool)
* manager.
*
* RETURNS:
- * false if no action was taken and pool->lock stayed locked, true
+ * %false if no action was taken and pool->lock stayed locked, %true
* otherwise.
*/
static bool maybe_create_worker(struct worker_pool *pool)
@@ -1925,7 +1943,8 @@ restart:
del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&pool->lock);
start_worker(worker);
- BUG_ON(need_to_create_worker(pool));
+ if (WARN_ON_ONCE(need_to_create_worker(pool)))
+ goto restart;
return true;
}
@@ -1958,7 +1977,7 @@ restart:
* multiple times. Called only from manager.
*
* RETURNS:
- * false if no action was taken and pool->lock stayed locked, true
+ * %false if no action was taken and pool->lock stayed locked, %true
* otherwise.
*/
static bool maybe_destroy_workers(struct worker_pool *pool)
@@ -2009,42 +2028,37 @@ static bool manage_workers(struct worker *worker)
struct worker_pool *pool = worker->pool;
bool ret = false;
- if (pool->flags & POOL_MANAGING_WORKERS)
+ /*
+ * Managership is governed by two mutexes - manager_arb and
+ * manager_mutex. manager_arb handles arbitration of manager role.
+ * Anyone who successfully grabs manager_arb wins the arbitration
+ * and becomes the manager. mutex_trylock() on pool->manager_arb
+ * failure while holding pool->lock reliably indicates that someone
+ * else is managing the pool and the worker which failed trylock
+ * can proceed to executing work items. This means that anyone
+ * grabbing manager_arb is responsible for actually performing
+ * manager duties. If manager_arb is grabbed and released without
+ * actual management, the pool may stall indefinitely.
+ *
+ * manager_mutex is used for exclusion of actual management
+ * operations. The holder of manager_mutex can be sure that none
+ * of management operations, including creation and destruction of
+ * workers, won't take place until the mutex is released. Because
+ * manager_mutex doesn't interfere with manager role arbitration,
+ * it is guaranteed that the pool's management, while may be
+ * delayed, won't be disturbed by someone else grabbing
+ * manager_mutex.
+ */
+ if (!mutex_trylock(&pool->manager_arb))
return ret;
- pool->flags |= POOL_MANAGING_WORKERS;
-
/*
- * To simplify both worker management and CPU hotplug, hold off
- * management while hotplug is in progress. CPU hotplug path can't
- * grab %POOL_MANAGING_WORKERS to achieve this because that can
- * lead to idle worker depletion (all become busy thinking someone
- * else is managing) which in turn can result in deadlock under
- * extreme circumstances. Use @pool->assoc_mutex to synchronize
- * manager against CPU hotplug.
- *
- * assoc_mutex would always be free unless CPU hotplug is in
- * progress. trylock first without dropping @pool->lock.
+ * With manager arbitration won, manager_mutex would be free in
+ * most cases. trylock first without dropping @pool->lock.
*/
- if (unlikely(!mutex_trylock(&pool->assoc_mutex))) {
+ if (unlikely(!mutex_trylock(&pool->manager_mutex))) {
spin_unlock_irq(&pool->lock);
- mutex_lock(&pool->assoc_mutex);
- /*
- * CPU hotplug could have happened while we were waiting
- * for assoc_mutex. Hotplug itself can't handle us
- * because manager isn't either on idle or busy list, and
- * @pool's state and ours could have deviated.
- *
- * As hotplug is now excluded via assoc_mutex, we can
- * simply try to bind. It will succeed or fail depending
- * on @pool's current state. Try it and adjust
- * %WORKER_UNBOUND accordingly.
- */
- if (worker_maybe_bind_and_lock(worker))
- worker->flags &= ~WORKER_UNBOUND;
- else
- worker->flags |= WORKER_UNBOUND;
-
+ mutex_lock(&pool->manager_mutex);
ret = true;
}
@@ -2057,8 +2071,8 @@ static bool manage_workers(struct worker *worker)
ret |= maybe_destroy_workers(pool);
ret |= maybe_create_worker(pool);
- pool->flags &= ~POOL_MANAGING_WORKERS;
- mutex_unlock(&pool->assoc_mutex);
+ mutex_unlock(&pool->manager_mutex);
+ mutex_unlock(&pool->manager_arb);
return ret;
}
@@ -2184,6 +2198,7 @@ __acquires(&pool->lock)
worker->current_work = NULL;
worker->current_func = NULL;
worker->current_pwq = NULL;
+ worker->desc_valid = false;
pwq_dec_nr_in_flight(pwq, work_color);
}
@@ -2212,11 +2227,11 @@ static void process_scheduled_works(struct worker *worker)
* worker_thread - the worker thread function
* @__worker: self
*
- * The worker thread function. There are NR_CPU_WORKER_POOLS dynamic pools
- * of these per each cpu. These workers process all works regardless of
- * their specific target workqueue. The only exception is works which
- * belong to workqueues with a rescuer which will be explained in
- * rescuer_thread().
+ * The worker thread function. All workers belong to a worker_pool -
+ * either a per-cpu one or dynamic unbound one. These workers process all
+ * work items regardless of their specific target workqueue. The only
+ * exception is work items which belong to workqueues with a rescuer which
+ * will be explained in rescuer_thread().
*/
static int worker_thread(void *__worker)
{
@@ -2228,19 +2243,12 @@ static int worker_thread(void *__worker)
woke_up:
spin_lock_irq(&pool->lock);
- /* we are off idle list if destruction or rebind is requested */
- if (unlikely(list_empty(&worker->entry))) {
+ /* am I supposed to die? */
+ if (unlikely(worker->flags & WORKER_DIE)) {
spin_unlock_irq(&pool->lock);
-
- /* if DIE is set, destruction is requested */
- if (worker->flags & WORKER_DIE) {
- worker->task->flags &= ~PF_WQ_WORKER;
- return 0;
- }
-
- /* otherwise, rebind */
- idle_worker_rebind(worker);
- goto woke_up;
+ WARN_ON_ONCE(!list_empty(&worker->entry));
+ worker->task->flags &= ~PF_WQ_WORKER;
+ return 0;
}
worker_leave_idle(worker);
@@ -2258,14 +2266,16 @@ recheck:
* preparing to process a work or actually processing it.
* Make sure nobody diddled with it while I was sleeping.
*/
- BUG_ON(!list_empty(&worker->scheduled));
+ WARN_ON_ONCE(!list_empty(&worker->scheduled));
/*
- * When control reaches this point, we're guaranteed to have
- * at least one idle worker or that someone else has already
- * assumed the manager role.
+ * Finish PREP stage. We're guaranteed to have at least one idle
+ * worker or that someone else has already assumed the manager
+ * role. This is where @worker starts participating in concurrency
+ * management if applicable and concurrency management is restored
+ * after being rebound. See rebind_workers() for details.
*/
- worker_clr_flags(worker, WORKER_PREP);
+ worker_clr_flags(worker, WORKER_PREP | WORKER_REBOUND);
do {
struct work_struct *work =
@@ -2307,7 +2317,7 @@ sleep:
* @__rescuer: self
*
* Workqueue rescuer thread function. There's one rescuer for each
- * workqueue which has WQ_RESCUER set.
+ * workqueue which has WQ_MEM_RECLAIM set.
*
* Regular work processing on a pool may block trying to create a new
* worker which uses GFP_KERNEL allocation which has slight chance of
@@ -2326,8 +2336,6 @@ static int rescuer_thread(void *__rescuer)
struct worker *rescuer = __rescuer;
struct workqueue_struct *wq = rescuer->rescue_wq;
struct list_head *scheduled = &rescuer->scheduled;
- bool is_unbound = wq->flags & WQ_UNBOUND;
- unsigned int cpu;
set_user_nice(current, RESCUER_NICE_LEVEL);
@@ -2345,28 +2353,29 @@ repeat:
return 0;
}
- /*
- * See whether any cpu is asking for help. Unbounded
- * workqueues use cpu 0 in mayday_mask for CPU_UNBOUND.
- */
- for_each_mayday_cpu(cpu, wq->mayday_mask) {
- unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
- struct pool_workqueue *pwq = get_pwq(tcpu, wq);
+ /* see whether any pwq is asking for help */
+ spin_lock_irq(&wq_mayday_lock);
+
+ while (!list_empty(&wq->maydays)) {
+ struct pool_workqueue *pwq = list_first_entry(&wq->maydays,
+ struct pool_workqueue, mayday_node);
struct worker_pool *pool = pwq->pool;
struct work_struct *work, *n;
__set_current_state(TASK_RUNNING);
- mayday_clear_cpu(cpu, wq->mayday_mask);
+ list_del_init(&pwq->mayday_node);
+
+ spin_unlock_irq(&wq_mayday_lock);
/* migrate to the target cpu if possible */
+ worker_maybe_bind_and_lock(pool);
rescuer->pool = pool;
- worker_maybe_bind_and_lock(rescuer);
/*
* Slurp in all works issued via this workqueue and
* process'em.
*/
- BUG_ON(!list_empty(&rescuer->scheduled));
+ WARN_ON_ONCE(!list_empty(&rescuer->scheduled));
list_for_each_entry_safe(work, n, &pool->worklist, entry)
if (get_work_pwq(work) == pwq)
move_linked_works(work, scheduled, &n);
@@ -2381,9 +2390,13 @@ repeat:
if (keep_working(pool))
wake_up_worker(pool);
- spin_unlock_irq(&pool->lock);
+ rescuer->pool = NULL;
+ spin_unlock(&pool->lock);
+ spin_lock(&wq_mayday_lock);
}
+ spin_unlock_irq(&wq_mayday_lock);
+
/* rescuers should never participate in concurrency management */
WARN_ON_ONCE(!(rescuer->flags & WORKER_NOT_RUNNING));
schedule();
@@ -2487,7 +2500,7 @@ static void insert_wq_barrier(struct pool_workqueue *pwq,
* advanced to @work_color.
*
* CONTEXT:
- * mutex_lock(wq->flush_mutex).
+ * mutex_lock(wq->mutex).
*
* RETURNS:
* %true if @flush_color >= 0 and there's something to flush. %false
@@ -2497,21 +2510,20 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
int flush_color, int work_color)
{
bool wait = false;
- unsigned int cpu;
+ struct pool_workqueue *pwq;
if (flush_color >= 0) {
- BUG_ON(atomic_read(&wq->nr_pwqs_to_flush));
+ WARN_ON_ONCE(atomic_read(&wq->nr_pwqs_to_flush));
atomic_set(&wq->nr_pwqs_to_flush, 1);
}
- for_each_pwq_cpu(cpu, wq) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
+ for_each_pwq(pwq, wq) {
struct worker_pool *pool = pwq->pool;
spin_lock_irq(&pool->lock);
if (flush_color >= 0) {
- BUG_ON(pwq->flush_color != -1);
+ WARN_ON_ONCE(pwq->flush_color != -1);
if (pwq->nr_in_flight[flush_color]) {
pwq->flush_color = flush_color;
@@ -2521,7 +2533,7 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
}
if (work_color >= 0) {
- BUG_ON(work_color != work_next_color(pwq->work_color));
+ WARN_ON_ONCE(work_color != work_next_color(pwq->work_color));
pwq->work_color = work_color;
}
@@ -2538,11 +2550,8 @@ static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq,
* flush_workqueue - ensure that any scheduled work has run to completion.
* @wq: workqueue to flush
*
- * Forces execution of the workqueue and blocks until its completion.
- * This is typically used in driver shutdown handlers.
- *
- * We sleep until all works which were queued on entry have been handled,
- * but we are not livelocked by new incoming ones.
+ * This function sleeps until all work items which were queued on entry
+ * have finished execution, but it is not livelocked by new incoming ones.
*/
void flush_workqueue(struct workqueue_struct *wq)
{
@@ -2556,7 +2565,7 @@ void flush_workqueue(struct workqueue_struct *wq)
lock_map_acquire(&wq->lockdep_map);
lock_map_release(&wq->lockdep_map);
- mutex_lock(&wq->flush_mutex);
+ mutex_lock(&wq->mutex);
/*
* Start-to-wait phase
@@ -2569,13 +2578,13 @@ void flush_workqueue(struct workqueue_struct *wq)
* becomes our flush_color and work_color is advanced
* by one.
*/
- BUG_ON(!list_empty(&wq->flusher_overflow));
+ WARN_ON_ONCE(!list_empty(&wq->flusher_overflow));
this_flusher.flush_color = wq->work_color;
wq->work_color = next_color;
if (!wq->first_flusher) {
/* no flush in progress, become the first flusher */
- BUG_ON(wq->flush_color != this_flusher.flush_color);
+ WARN_ON_ONCE(wq->flush_color != this_flusher.flush_color);
wq->first_flusher = &this_flusher;
@@ -2588,7 +2597,7 @@ void flush_workqueue(struct workqueue_struct *wq)
}
} else {
/* wait in queue */
- BUG_ON(wq->flush_color == this_flusher.flush_color);
+ WARN_ON_ONCE(wq->flush_color == this_flusher.flush_color);
list_add_tail(&this_flusher.list, &wq->flusher_queue);
flush_workqueue_prep_pwqs(wq, -1, wq->work_color);
}
@@ -2601,7 +2610,7 @@ void flush_workqueue(struct workqueue_struct *wq)
list_add_tail(&this_flusher.list, &wq->flusher_overflow);
}
- mutex_unlock(&wq->flush_mutex);
+ mutex_unlock(&wq->mutex);
wait_for_completion(&this_flusher.done);
@@ -2614,7 +2623,7 @@ void flush_workqueue(struct workqueue_struct *wq)
if (wq->first_flusher != &this_flusher)
return;
- mutex_lock(&wq->flush_mutex);
+ mutex_lock(&wq->mutex);
/* we might have raced, check again with mutex held */
if (wq->first_flusher != &this_flusher)
@@ -2622,8 +2631,8 @@ void flush_workqueue(struct workqueue_struct *wq)
wq->first_flusher = NULL;
- BUG_ON(!list_empty(&this_flusher.list));
- BUG_ON(wq->flush_color != this_flusher.flush_color);
+ WARN_ON_ONCE(!list_empty(&this_flusher.list));
+ WARN_ON_ONCE(wq->flush_color != this_flusher.flush_color);
while (true) {
struct wq_flusher *next, *tmp;
@@ -2636,8 +2645,8 @@ void flush_workqueue(struct workqueue_struct *wq)
complete(&next->done);
}
- BUG_ON(!list_empty(&wq->flusher_overflow) &&
- wq->flush_color != work_next_color(wq->work_color));
+ WARN_ON_ONCE(!list_empty(&wq->flusher_overflow) &&
+ wq->flush_color != work_next_color(wq->work_color));
/* this flush_color is finished, advance by one */
wq->flush_color = work_next_color(wq->flush_color);
@@ -2661,7 +2670,7 @@ void flush_workqueue(struct workqueue_struct *wq)
}
if (list_empty(&wq->flusher_queue)) {
- BUG_ON(wq->flush_color != wq->work_color);
+ WARN_ON_ONCE(wq->flush_color != wq->work_color);
break;
}
@@ -2669,8 +2678,8 @@ void flush_workqueue(struct workqueue_struct *wq)
* Need to flush more colors. Make the next flusher
* the new first flusher and arm pwqs.
*/
- BUG_ON(wq->flush_color == wq->work_color);
- BUG_ON(wq->flush_color != next->flush_color);
+ WARN_ON_ONCE(wq->flush_color == wq->work_color);
+ WARN_ON_ONCE(wq->flush_color != next->flush_color);
list_del_init(&next->list);
wq->first_flusher = next;
@@ -2686,7 +2695,7 @@ void flush_workqueue(struct workqueue_struct *wq)
}
out_unlock:
- mutex_unlock(&wq->flush_mutex);
+ mutex_unlock(&wq->mutex);
}
EXPORT_SYMBOL_GPL(flush_workqueue);
@@ -2704,22 +2713,23 @@ EXPORT_SYMBOL_GPL(flush_workqueue);
void drain_workqueue(struct workqueue_struct *wq)
{
unsigned int flush_cnt = 0;
- unsigned int cpu;
+ struct pool_workqueue *pwq;
/*
* __queue_work() needs to test whether there are drainers, is much
* hotter than drain_workqueue() and already looks at @wq->flags.
- * Use WQ_DRAINING so that queue doesn't have to check nr_drainers.
+ * Use __WQ_DRAINING so that queue doesn't have to check nr_drainers.
*/
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq->mutex);
if (!wq->nr_drainers++)
- wq->flags |= WQ_DRAINING;
- spin_unlock(&workqueue_lock);
+ wq->flags |= __WQ_DRAINING;
+ mutex_unlock(&wq->mutex);
reflush:
flush_workqueue(wq);
- for_each_pwq_cpu(cpu, wq) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
+ mutex_lock(&wq->mutex);
+
+ for_each_pwq(pwq, wq) {
bool drained;
spin_lock_irq(&pwq->pool->lock);
@@ -2731,15 +2741,16 @@ reflush:
if (++flush_cnt == 10 ||
(flush_cnt % 100 == 0 && flush_cnt <= 1000))
- pr_warn("workqueue %s: flush on destruction isn't complete after %u tries\n",
+ pr_warn("workqueue %s: drain_workqueue() isn't complete after %u tries\n",
wq->name, flush_cnt);
+
+ mutex_unlock(&wq->mutex);
goto reflush;
}
- spin_lock(&workqueue_lock);
if (!--wq->nr_drainers)
- wq->flags &= ~WQ_DRAINING;
- spin_unlock(&workqueue_lock);
+ wq->flags &= ~__WQ_DRAINING;
+ mutex_unlock(&wq->mutex);
}
EXPORT_SYMBOL_GPL(drain_workqueue);
@@ -2750,11 +2761,15 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
struct pool_workqueue *pwq;
might_sleep();
+
+ local_irq_disable();
pool = get_work_pool(work);
- if (!pool)
+ if (!pool) {
+ local_irq_enable();
return false;
+ }
- spin_lock_irq(&pool->lock);
+ spin_lock(&pool->lock);
/* see the comment in try_to_grab_pending() with the same code */
pwq = get_work_pwq(work);
if (pwq) {
@@ -2776,7 +2791,7 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
* flusher is not running on the same workqueue by verifying write
* access.
*/
- if (pwq->wq->saved_max_active == 1 || pwq->wq->flags & WQ_RESCUER)
+ if (pwq->wq->saved_max_active == 1 || pwq->wq->rescuer)
lock_map_acquire(&pwq->wq->lockdep_map);
else
lock_map_acquire_read(&pwq->wq->lockdep_map);
@@ -2933,66 +2948,6 @@ bool cancel_delayed_work_sync(struct delayed_work *dwork)
EXPORT_SYMBOL(cancel_delayed_work_sync);
/**
- * schedule_work_on - put work task on a specific cpu
- * @cpu: cpu to put the work task on
- * @work: job to be done
- *
- * This puts a job on a specific cpu
- */
-bool schedule_work_on(int cpu, struct work_struct *work)
-{
- return queue_work_on(cpu, system_wq, work);
-}
-EXPORT_SYMBOL(schedule_work_on);
-
-/**
- * schedule_work - put work task in global workqueue
- * @work: job to be done
- *
- * Returns %false if @work was already on the kernel-global workqueue and
- * %true otherwise.
- *
- * This puts a job in the kernel-global workqueue if it was not already
- * queued and leaves it in the same position on the kernel-global
- * workqueue otherwise.
- */
-bool schedule_work(struct work_struct *work)
-{
- return queue_work(system_wq, work);
-}
-EXPORT_SYMBOL(schedule_work);
-
-/**
- * schedule_delayed_work_on - queue work in global workqueue on CPU after delay
- * @cpu: cpu to use
- * @dwork: job to be done
- * @delay: number of jiffies to wait
- *
- * After waiting for a given time this puts a job in the kernel-global
- * workqueue on the specified CPU.
- */
-bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
- unsigned long delay)
-{
- return queue_delayed_work_on(cpu, system_wq, dwork, delay);
-}
-EXPORT_SYMBOL(schedule_delayed_work_on);
-
-/**
- * schedule_delayed_work - put work task in global workqueue after delay
- * @dwork: job to be done
- * @delay: number of jiffies to wait or 0 for immediate execution
- *
- * After waiting for a given time this puts a job in the kernel-global
- * workqueue.
- */
-bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
-{
- return queue_delayed_work(system_wq, dwork, delay);
-}
-EXPORT_SYMBOL(schedule_delayed_work);
-
-/**
* schedule_on_each_cpu - execute a function synchronously on each online CPU
* @func: the function to call
*
@@ -3085,51 +3040,1025 @@ int execute_in_process_context(work_func_t fn, struct execute_work *ew)
}
EXPORT_SYMBOL_GPL(execute_in_process_context);
-int keventd_up(void)
+#ifdef CONFIG_SYSFS
+/*
+ * Workqueues with WQ_SYSFS flag set is visible to userland via
+ * /sys/bus/workqueue/devices/WQ_NAME. All visible workqueues have the
+ * following attributes.
+ *
+ * per_cpu RO bool : whether the workqueue is per-cpu or unbound
+ * max_active RW int : maximum number of in-flight work items
+ *
+ * Unbound workqueues have the following extra attributes.
+ *
+ * id RO int : the associated pool ID
+ * nice RW int : nice value of the workers
+ * cpumask RW mask : bitmask of allowed CPUs for the workers
+ */
+struct wq_device {
+ struct workqueue_struct *wq;
+ struct device dev;
+};
+
+static struct workqueue_struct *dev_to_wq(struct device *dev)
+{
+ struct wq_device *wq_dev = container_of(dev, struct wq_device, dev);
+
+ return wq_dev->wq;
+}
+
+static ssize_t wq_per_cpu_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", (bool)!(wq->flags & WQ_UNBOUND));
+}
+
+static ssize_t wq_max_active_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", wq->saved_max_active);
+}
+
+static ssize_t wq_max_active_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ int val;
+
+ if (sscanf(buf, "%d", &val) != 1 || val <= 0)
+ return -EINVAL;
+
+ workqueue_set_max_active(wq, val);
+ return count;
+}
+
+static struct device_attribute wq_sysfs_attrs[] = {
+ __ATTR(per_cpu, 0444, wq_per_cpu_show, NULL),
+ __ATTR(max_active, 0644, wq_max_active_show, wq_max_active_store),
+ __ATTR_NULL,
+};
+
+static ssize_t wq_pool_ids_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ const char *delim = "";
+ int node, written = 0;
+
+ rcu_read_lock_sched();
+ for_each_node(node) {
+ written += scnprintf(buf + written, PAGE_SIZE - written,
+ "%s%d:%d", delim, node,
+ unbound_pwq_by_node(wq, node)->pool->id);
+ delim = " ";
+ }
+ written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
+ rcu_read_unlock_sched();
+
+ return written;
+}
+
+static ssize_t wq_nice_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ int written;
+
+ mutex_lock(&wq->mutex);
+ written = scnprintf(buf, PAGE_SIZE, "%d\n", wq->unbound_attrs->nice);
+ mutex_unlock(&wq->mutex);
+
+ return written;
+}
+
+/* prepare workqueue_attrs for sysfs store operations */
+static struct workqueue_attrs *wq_sysfs_prep_attrs(struct workqueue_struct *wq)
+{
+ struct workqueue_attrs *attrs;
+
+ attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ if (!attrs)
+ return NULL;
+
+ mutex_lock(&wq->mutex);
+ copy_workqueue_attrs(attrs, wq->unbound_attrs);
+ mutex_unlock(&wq->mutex);
+ return attrs;
+}
+
+static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ struct workqueue_attrs *attrs;
+ int ret;
+
+ attrs = wq_sysfs_prep_attrs(wq);
+ if (!attrs)
+ return -ENOMEM;
+
+ if (sscanf(buf, "%d", &attrs->nice) == 1 &&
+ attrs->nice >= -20 && attrs->nice <= 19)
+ ret = apply_workqueue_attrs(wq, attrs);
+ else
+ ret = -EINVAL;
+
+ free_workqueue_attrs(attrs);
+ return ret ?: count;
+}
+
+static ssize_t wq_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ int written;
+
+ mutex_lock(&wq->mutex);
+ written = cpumask_scnprintf(buf, PAGE_SIZE, wq->unbound_attrs->cpumask);
+ mutex_unlock(&wq->mutex);
+
+ written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
+ return written;
+}
+
+static ssize_t wq_cpumask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ struct workqueue_attrs *attrs;
+ int ret;
+
+ attrs = wq_sysfs_prep_attrs(wq);
+ if (!attrs)
+ return -ENOMEM;
+
+ ret = cpumask_parse(buf, attrs->cpumask);
+ if (!ret)
+ ret = apply_workqueue_attrs(wq, attrs);
+
+ free_workqueue_attrs(attrs);
+ return ret ?: count;
+}
+
+static ssize_t wq_numa_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ int written;
+
+ mutex_lock(&wq->mutex);
+ written = scnprintf(buf, PAGE_SIZE, "%d\n",
+ !wq->unbound_attrs->no_numa);
+ mutex_unlock(&wq->mutex);
+
+ return written;
+}
+
+static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct workqueue_struct *wq = dev_to_wq(dev);
+ struct workqueue_attrs *attrs;
+ int v, ret;
+
+ attrs = wq_sysfs_prep_attrs(wq);
+ if (!attrs)
+ return -ENOMEM;
+
+ ret = -EINVAL;
+ if (sscanf(buf, "%d", &v) == 1) {
+ attrs->no_numa = !v;
+ ret = apply_workqueue_attrs(wq, attrs);
+ }
+
+ free_workqueue_attrs(attrs);
+ return ret ?: count;
+}
+
+static struct device_attribute wq_sysfs_unbound_attrs[] = {
+ __ATTR(pool_ids, 0444, wq_pool_ids_show, NULL),
+ __ATTR(nice, 0644, wq_nice_show, wq_nice_store),
+ __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store),
+ __ATTR(numa, 0644, wq_numa_show, wq_numa_store),
+ __ATTR_NULL,
+};
+
+static struct bus_type wq_subsys = {
+ .name = "workqueue",
+ .dev_attrs = wq_sysfs_attrs,
+};
+
+static int __init wq_sysfs_init(void)
+{
+ return subsys_virtual_register(&wq_subsys, NULL);
+}
+core_initcall(wq_sysfs_init);
+
+static void wq_device_release(struct device *dev)
{
- return system_wq != NULL;
+ struct wq_device *wq_dev = container_of(dev, struct wq_device, dev);
+
+ kfree(wq_dev);
}
-static int alloc_pwqs(struct workqueue_struct *wq)
+/**
+ * workqueue_sysfs_register - make a workqueue visible in sysfs
+ * @wq: the workqueue to register
+ *
+ * Expose @wq in sysfs under /sys/bus/workqueue/devices.
+ * alloc_workqueue*() automatically calls this function if WQ_SYSFS is set
+ * which is the preferred method.
+ *
+ * Workqueue user should use this function directly iff it wants to apply
+ * workqueue_attrs before making the workqueue visible in sysfs; otherwise,
+ * apply_workqueue_attrs() may race against userland updating the
+ * attributes.
+ *
+ * Returns 0 on success, -errno on failure.
+ */
+int workqueue_sysfs_register(struct workqueue_struct *wq)
{
+ struct wq_device *wq_dev;
+ int ret;
+
/*
- * pwqs are forced aligned according to WORK_STRUCT_FLAG_BITS.
- * Make sure that the alignment isn't lower than that of
- * unsigned long long.
+ * Adjusting max_active or creating new pwqs by applyting
+ * attributes breaks ordering guarantee. Disallow exposing ordered
+ * workqueues.
*/
- const size_t size = sizeof(struct pool_workqueue);
- const size_t align = max_t(size_t, 1 << WORK_STRUCT_FLAG_BITS,
- __alignof__(unsigned long long));
+ if (WARN_ON(wq->flags & __WQ_ORDERED))
+ return -EINVAL;
- if (!(wq->flags & WQ_UNBOUND))
- wq->pool_wq.pcpu = __alloc_percpu(size, align);
- else {
- void *ptr;
+ wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL);
+ if (!wq_dev)
+ return -ENOMEM;
+
+ wq_dev->wq = wq;
+ wq_dev->dev.bus = &wq_subsys;
+ wq_dev->dev.init_name = wq->name;
+ wq_dev->dev.release = wq_device_release;
+
+ /*
+ * unbound_attrs are created separately. Suppress uevent until
+ * everything is ready.
+ */
+ dev_set_uevent_suppress(&wq_dev->dev, true);
+
+ ret = device_register(&wq_dev->dev);
+ if (ret) {
+ kfree(wq_dev);
+ wq->wq_dev = NULL;
+ return ret;
+ }
+
+ if (wq->flags & WQ_UNBOUND) {
+ struct device_attribute *attr;
+
+ for (attr = wq_sysfs_unbound_attrs; attr->attr.name; attr++) {
+ ret = device_create_file(&wq_dev->dev, attr);
+ if (ret) {
+ device_unregister(&wq_dev->dev);
+ wq->wq_dev = NULL;
+ return ret;
+ }
+ }
+ }
+
+ kobject_uevent(&wq_dev->dev.kobj, KOBJ_ADD);
+ return 0;
+}
+
+/**
+ * workqueue_sysfs_unregister - undo workqueue_sysfs_register()
+ * @wq: the workqueue to unregister
+ *
+ * If @wq is registered to sysfs by workqueue_sysfs_register(), unregister.
+ */
+static void workqueue_sysfs_unregister(struct workqueue_struct *wq)
+{
+ struct wq_device *wq_dev = wq->wq_dev;
+
+ if (!wq->wq_dev)
+ return;
+
+ wq->wq_dev = NULL;
+ device_unregister(&wq_dev->dev);
+}
+#else /* CONFIG_SYSFS */
+static void workqueue_sysfs_unregister(struct workqueue_struct *wq) { }
+#endif /* CONFIG_SYSFS */
+
+/**
+ * free_workqueue_attrs - free a workqueue_attrs
+ * @attrs: workqueue_attrs to free
+ *
+ * Undo alloc_workqueue_attrs().
+ */
+void free_workqueue_attrs(struct workqueue_attrs *attrs)
+{
+ if (attrs) {
+ free_cpumask_var(attrs->cpumask);
+ kfree(attrs);
+ }
+}
+
+/**
+ * alloc_workqueue_attrs - allocate a workqueue_attrs
+ * @gfp_mask: allocation mask to use
+ *
+ * Allocate a new workqueue_attrs, initialize with default settings and
+ * return it. Returns NULL on failure.
+ */
+struct workqueue_attrs *alloc_workqueue_attrs(gfp_t gfp_mask)
+{
+ struct workqueue_attrs *attrs;
+
+ attrs = kzalloc(sizeof(*attrs), gfp_mask);
+ if (!attrs)
+ goto fail;
+ if (!alloc_cpumask_var(&attrs->cpumask, gfp_mask))
+ goto fail;
+
+ cpumask_copy(attrs->cpumask, cpu_possible_mask);
+ return attrs;
+fail:
+ free_workqueue_attrs(attrs);
+ return NULL;
+}
+
+static void copy_workqueue_attrs(struct workqueue_attrs *to,
+ const struct workqueue_attrs *from)
+{
+ to->nice = from->nice;
+ cpumask_copy(to->cpumask, from->cpumask);
+}
+
+/* hash value of the content of @attr */
+static u32 wqattrs_hash(const struct workqueue_attrs *attrs)
+{
+ u32 hash = 0;
+
+ hash = jhash_1word(attrs->nice, hash);
+ hash = jhash(cpumask_bits(attrs->cpumask),
+ BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash);
+ return hash;
+}
+
+/* content equality test */
+static bool wqattrs_equal(const struct workqueue_attrs *a,
+ const struct workqueue_attrs *b)
+{
+ if (a->nice != b->nice)
+ return false;
+ if (!cpumask_equal(a->cpumask, b->cpumask))
+ return false;
+ return true;
+}
+
+/**
+ * init_worker_pool - initialize a newly zalloc'd worker_pool
+ * @pool: worker_pool to initialize
+ *
+ * Initiailize a newly zalloc'd @pool. It also allocates @pool->attrs.
+ * Returns 0 on success, -errno on failure. Even on failure, all fields
+ * inside @pool proper are initialized and put_unbound_pool() can be called
+ * on @pool safely to release it.
+ */
+static int init_worker_pool(struct worker_pool *pool)
+{
+ spin_lock_init(&pool->lock);
+ pool->id = -1;
+ pool->cpu = -1;
+ pool->node = NUMA_NO_NODE;
+ pool->flags |= POOL_DISASSOCIATED;
+ INIT_LIST_HEAD(&pool->worklist);
+ INIT_LIST_HEAD(&pool->idle_list);
+ hash_init(pool->busy_hash);
+
+ init_timer_deferrable(&pool->idle_timer);
+ pool->idle_timer.function = idle_worker_timeout;
+ pool->idle_timer.data = (unsigned long)pool;
+
+ setup_timer(&pool->mayday_timer, pool_mayday_timeout,
+ (unsigned long)pool);
+
+ mutex_init(&pool->manager_arb);
+ mutex_init(&pool->manager_mutex);
+ idr_init(&pool->worker_idr);
+
+ INIT_HLIST_NODE(&pool->hash_node);
+ pool->refcnt = 1;
+
+ /* shouldn't fail above this point */
+ pool->attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ if (!pool->attrs)
+ return -ENOMEM;
+ return 0;
+}
+
+static void rcu_free_pool(struct rcu_head *rcu)
+{
+ struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu);
+
+ idr_destroy(&pool->worker_idr);
+ free_workqueue_attrs(pool->attrs);
+ kfree(pool);
+}
+
+/**
+ * put_unbound_pool - put a worker_pool
+ * @pool: worker_pool to put
+ *
+ * Put @pool. If its refcnt reaches zero, it gets destroyed in sched-RCU
+ * safe manner. get_unbound_pool() calls this function on its failure path
+ * and this function should be able to release pools which went through,
+ * successfully or not, init_worker_pool().
+ *
+ * Should be called with wq_pool_mutex held.
+ */
+static void put_unbound_pool(struct worker_pool *pool)
+{
+ struct worker *worker;
+
+ lockdep_assert_held(&wq_pool_mutex);
+
+ if (--pool->refcnt)
+ return;
+
+ /* sanity checks */
+ if (WARN_ON(!(pool->flags & POOL_DISASSOCIATED)) ||
+ WARN_ON(!list_empty(&pool->worklist)))
+ return;
+
+ /* release id and unhash */
+ if (pool->id >= 0)
+ idr_remove(&worker_pool_idr, pool->id);
+ hash_del(&pool->hash_node);
+
+ /*
+ * Become the manager and destroy all workers. Grabbing
+ * manager_arb prevents @pool's workers from blocking on
+ * manager_mutex.
+ */
+ mutex_lock(&pool->manager_arb);
+ mutex_lock(&pool->manager_mutex);
+ spin_lock_irq(&pool->lock);
+
+ while ((worker = first_worker(pool)))
+ destroy_worker(worker);
+ WARN_ON(pool->nr_workers || pool->nr_idle);
+
+ spin_unlock_irq(&pool->lock);
+ mutex_unlock(&pool->manager_mutex);
+ mutex_unlock(&pool->manager_arb);
+
+ /* shut down the timers */
+ del_timer_sync(&pool->idle_timer);
+ del_timer_sync(&pool->mayday_timer);
+
+ /* sched-RCU protected to allow dereferences from get_work_pool() */
+ call_rcu_sched(&pool->rcu, rcu_free_pool);
+}
+
+/**
+ * get_unbound_pool - get a worker_pool with the specified attributes
+ * @attrs: the attributes of the worker_pool to get
+ *
+ * Obtain a worker_pool which has the same attributes as @attrs, bump the
+ * reference count and return it. If there already is a matching
+ * worker_pool, it will be used; otherwise, this function attempts to
+ * create a new one. On failure, returns NULL.
+ *
+ * Should be called with wq_pool_mutex held.
+ */
+static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs)
+{
+ u32 hash = wqattrs_hash(attrs);
+ struct worker_pool *pool;
+ int node;
+
+ lockdep_assert_held(&wq_pool_mutex);
+
+ /* do we already have a matching pool? */
+ hash_for_each_possible(unbound_pool_hash, pool, hash_node, hash) {
+ if (wqattrs_equal(pool->attrs, attrs)) {
+ pool->refcnt++;
+ goto out_unlock;
+ }
+ }
+
+ /* nope, create a new one */
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool || init_worker_pool(pool) < 0)
+ goto fail;
+
+ if (workqueue_freezing)
+ pool->flags |= POOL_FREEZING;
+
+ lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */
+ copy_workqueue_attrs(pool->attrs, attrs);
+
+ /* if cpumask is contained inside a NUMA node, we belong to that node */
+ if (wq_numa_enabled) {
+ for_each_node(node) {
+ if (cpumask_subset(pool->attrs->cpumask,
+ wq_numa_possible_cpumask[node])) {
+ pool->node = node;
+ break;
+ }
+ }
+ }
+
+ if (worker_pool_assign_id(pool) < 0)
+ goto fail;
+
+ /* create and start the initial worker */
+ if (create_and_start_worker(pool) < 0)
+ goto fail;
+
+ /* install */
+ hash_add(unbound_pool_hash, &pool->hash_node, hash);
+out_unlock:
+ return pool;
+fail:
+ if (pool)
+ put_unbound_pool(pool);
+ return NULL;
+}
+
+static void rcu_free_pwq(struct rcu_head *rcu)
+{
+ kmem_cache_free(pwq_cache,
+ container_of(rcu, struct pool_workqueue, rcu));
+}
+
+/*
+ * Scheduled on system_wq by put_pwq() when an unbound pwq hits zero refcnt
+ * and needs to be destroyed.
+ */
+static void pwq_unbound_release_workfn(struct work_struct *work)
+{
+ struct pool_workqueue *pwq = container_of(work, struct pool_workqueue,
+ unbound_release_work);
+ struct workqueue_struct *wq = pwq->wq;
+ struct worker_pool *pool = pwq->pool;
+ bool is_last;
+
+ if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND)))
+ return;
+
+ /*
+ * Unlink @pwq. Synchronization against wq->mutex isn't strictly
+ * necessary on release but do it anyway. It's easier to verify
+ * and consistent with the linking path.
+ */
+ mutex_lock(&wq->mutex);
+ list_del_rcu(&pwq->pwqs_node);
+ is_last = list_empty(&wq->pwqs);
+ mutex_unlock(&wq->mutex);
+
+ mutex_lock(&wq_pool_mutex);
+ put_unbound_pool(pool);
+ mutex_unlock(&wq_pool_mutex);
+
+ call_rcu_sched(&pwq->rcu, rcu_free_pwq);
+
+ /*
+ * If we're the last pwq going away, @wq is already dead and no one
+ * is gonna access it anymore. Free it.
+ */
+ if (is_last) {
+ free_workqueue_attrs(wq->unbound_attrs);
+ kfree(wq);
+ }
+}
+
+/**
+ * pwq_adjust_max_active - update a pwq's max_active to the current setting
+ * @pwq: target pool_workqueue
+ *
+ * If @pwq isn't freezing, set @pwq->max_active to the associated
+ * workqueue's saved_max_active and activate delayed work items
+ * accordingly. If @pwq is freezing, clear @pwq->max_active to zero.
+ */
+static void pwq_adjust_max_active(struct pool_workqueue *pwq)
+{
+ struct workqueue_struct *wq = pwq->wq;
+ bool freezable = wq->flags & WQ_FREEZABLE;
+
+ /* for @wq->saved_max_active */
+ lockdep_assert_held(&wq->mutex);
+
+ /* fast exit for non-freezable wqs */
+ if (!freezable && pwq->max_active == wq->saved_max_active)
+ return;
+
+ spin_lock_irq(&pwq->pool->lock);
+
+ if (!freezable || !(pwq->pool->flags & POOL_FREEZING)) {
+ pwq->max_active = wq->saved_max_active;
+
+ while (!list_empty(&pwq->delayed_works) &&
+ pwq->nr_active < pwq->max_active)
+ pwq_activate_first_delayed(pwq);
/*
- * Allocate enough room to align pwq and put an extra
- * pointer at the end pointing back to the originally
- * allocated pointer which will be used for free.
+ * Need to kick a worker after thawed or an unbound wq's
+ * max_active is bumped. It's a slow path. Do it always.
*/
- ptr = kzalloc(size + align + sizeof(void *), GFP_KERNEL);
- if (ptr) {
- wq->pool_wq.single = PTR_ALIGN(ptr, align);
- *(void **)(wq->pool_wq.single + 1) = ptr;
+ wake_up_worker(pwq->pool);
+ } else {
+ pwq->max_active = 0;
+ }
+
+ spin_unlock_irq(&pwq->pool->lock);
+}
+
+/* initialize newly alloced @pwq which is associated with @wq and @pool */
+static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
+ struct worker_pool *pool)
+{
+ BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK);
+
+ memset(pwq, 0, sizeof(*pwq));
+
+ pwq->pool = pool;
+ pwq->wq = wq;
+ pwq->flush_color = -1;
+ pwq->refcnt = 1;
+ INIT_LIST_HEAD(&pwq->delayed_works);
+ INIT_LIST_HEAD(&pwq->pwqs_node);
+ INIT_LIST_HEAD(&pwq->mayday_node);
+ INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn);
+}
+
+/* sync @pwq with the current state of its associated wq and link it */
+static void link_pwq(struct pool_workqueue *pwq)
+{
+ struct workqueue_struct *wq = pwq->wq;
+
+ lockdep_assert_held(&wq->mutex);
+
+ /* may be called multiple times, ignore if already linked */
+ if (!list_empty(&pwq->pwqs_node))
+ return;
+
+ /*
+ * Set the matching work_color. This is synchronized with
+ * wq->mutex to avoid confusing flush_workqueue().
+ */
+ pwq->work_color = wq->work_color;
+
+ /* sync max_active to the current setting */
+ pwq_adjust_max_active(pwq);
+
+ /* link in @pwq */
+ list_add_rcu(&pwq->pwqs_node, &wq->pwqs);
+}
+
+/* obtain a pool matching @attr and create a pwq associating the pool and @wq */
+static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq,
+ const struct workqueue_attrs *attrs)
+{
+ struct worker_pool *pool;
+ struct pool_workqueue *pwq;
+
+ lockdep_assert_held(&wq_pool_mutex);
+
+ pool = get_unbound_pool(attrs);
+ if (!pool)
+ return NULL;
+
+ pwq = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL, pool->node);
+ if (!pwq) {
+ put_unbound_pool(pool);
+ return NULL;
+ }
+
+ init_pwq(pwq, wq, pool);
+ return pwq;
+}
+
+/* undo alloc_unbound_pwq(), used only in the error path */
+static void free_unbound_pwq(struct pool_workqueue *pwq)
+{
+ lockdep_assert_held(&wq_pool_mutex);
+
+ if (pwq) {
+ put_unbound_pool(pwq->pool);
+ kmem_cache_free(pwq_cache, pwq);
+ }
+}
+
+/**
+ * wq_calc_node_mask - calculate a wq_attrs' cpumask for the specified node
+ * @attrs: the wq_attrs of interest
+ * @node: the target NUMA node
+ * @cpu_going_down: if >= 0, the CPU to consider as offline
+ * @cpumask: outarg, the resulting cpumask
+ *
+ * Calculate the cpumask a workqueue with @attrs should use on @node. If
+ * @cpu_going_down is >= 0, that cpu is considered offline during
+ * calculation. The result is stored in @cpumask. This function returns
+ * %true if the resulting @cpumask is different from @attrs->cpumask,
+ * %false if equal.
+ *
+ * If NUMA affinity is not enabled, @attrs->cpumask is always used. If
+ * enabled and @node has online CPUs requested by @attrs, the returned
+ * cpumask is the intersection of the possible CPUs of @node and
+ * @attrs->cpumask.
+ *
+ * The caller is responsible for ensuring that the cpumask of @node stays
+ * stable.
+ */
+static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node,
+ int cpu_going_down, cpumask_t *cpumask)
+{
+ if (!wq_numa_enabled || attrs->no_numa)
+ goto use_dfl;
+
+ /* does @node have any online CPUs @attrs wants? */
+ cpumask_and(cpumask, cpumask_of_node(node), attrs->cpumask);
+ if (cpu_going_down >= 0)
+ cpumask_clear_cpu(cpu_going_down, cpumask);
+
+ if (cpumask_empty(cpumask))
+ goto use_dfl;
+
+ /* yeap, return possible CPUs in @node that @attrs wants */
+ cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]);
+ return !cpumask_equal(cpumask, attrs->cpumask);
+
+use_dfl:
+ cpumask_copy(cpumask, attrs->cpumask);
+ return false;
+}
+
+/* install @pwq into @wq's numa_pwq_tbl[] for @node and return the old pwq */
+static struct pool_workqueue *numa_pwq_tbl_install(struct workqueue_struct *wq,
+ int node,
+ struct pool_workqueue *pwq)
+{
+ struct pool_workqueue *old_pwq;
+
+ lockdep_assert_held(&wq->mutex);
+
+ /* link_pwq() can handle duplicate calls */
+ link_pwq(pwq);
+
+ old_pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]);
+ rcu_assign_pointer(wq->numa_pwq_tbl[node], pwq);
+ return old_pwq;
+}
+
+/**
+ * apply_workqueue_attrs - apply new workqueue_attrs to an unbound workqueue
+ * @wq: the target workqueue
+ * @attrs: the workqueue_attrs to apply, allocated with alloc_workqueue_attrs()
+ *
+ * Apply @attrs to an unbound workqueue @wq. Unless disabled, on NUMA
+ * machines, this function maps a separate pwq to each NUMA node with
+ * possibles CPUs in @attrs->cpumask so that work items are affine to the
+ * NUMA node it was issued on. Older pwqs are released as in-flight work
+ * items finish. Note that a work item which repeatedly requeues itself
+ * back-to-back will stay on its current pwq.
+ *
+ * Performs GFP_KERNEL allocations. Returns 0 on success and -errno on
+ * failure.
+ */
+int apply_workqueue_attrs(struct workqueue_struct *wq,
+ const struct workqueue_attrs *attrs)
+{
+ struct workqueue_attrs *new_attrs, *tmp_attrs;
+ struct pool_workqueue **pwq_tbl, *dfl_pwq;
+ int node, ret;
+
+ /* only unbound workqueues can change attributes */
+ if (WARN_ON(!(wq->flags & WQ_UNBOUND)))
+ return -EINVAL;
+
+ /* creating multiple pwqs breaks ordering guarantee */
+ if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs)))
+ return -EINVAL;
+
+ pwq_tbl = kzalloc(wq_numa_tbl_len * sizeof(pwq_tbl[0]), GFP_KERNEL);
+ new_attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ tmp_attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ if (!pwq_tbl || !new_attrs || !tmp_attrs)
+ goto enomem;
+
+ /* make a copy of @attrs and sanitize it */
+ copy_workqueue_attrs(new_attrs, attrs);
+ cpumask_and(new_attrs->cpumask, new_attrs->cpumask, cpu_possible_mask);
+
+ /*
+ * We may create multiple pwqs with differing cpumasks. Make a
+ * copy of @new_attrs which will be modified and used to obtain
+ * pools.
+ */
+ copy_workqueue_attrs(tmp_attrs, new_attrs);
+
+ /*
+ * CPUs should stay stable across pwq creations and installations.
+ * Pin CPUs, determine the target cpumask for each node and create
+ * pwqs accordingly.
+ */
+ get_online_cpus();
+
+ mutex_lock(&wq_pool_mutex);
+
+ /*
+ * If something goes wrong during CPU up/down, we'll fall back to
+ * the default pwq covering whole @attrs->cpumask. Always create
+ * it even if we don't use it immediately.
+ */
+ dfl_pwq = alloc_unbound_pwq(wq, new_attrs);
+ if (!dfl_pwq)
+ goto enomem_pwq;
+
+ for_each_node(node) {
+ if (wq_calc_node_cpumask(attrs, node, -1, tmp_attrs->cpumask)) {
+ pwq_tbl[node] = alloc_unbound_pwq(wq, tmp_attrs);
+ if (!pwq_tbl[node])
+ goto enomem_pwq;
+ } else {
+ dfl_pwq->refcnt++;
+ pwq_tbl[node] = dfl_pwq;
}
}
- /* just in case, make sure it's actually aligned */
- BUG_ON(!IS_ALIGNED(wq->pool_wq.v, align));
- return wq->pool_wq.v ? 0 : -ENOMEM;
+ mutex_unlock(&wq_pool_mutex);
+
+ /* all pwqs have been created successfully, let's install'em */
+ mutex_lock(&wq->mutex);
+
+ copy_workqueue_attrs(wq->unbound_attrs, new_attrs);
+
+ /* save the previous pwq and install the new one */
+ for_each_node(node)
+ pwq_tbl[node] = numa_pwq_tbl_install(wq, node, pwq_tbl[node]);
+
+ /* @dfl_pwq might not have been used, ensure it's linked */
+ link_pwq(dfl_pwq);
+ swap(wq->dfl_pwq, dfl_pwq);
+
+ mutex_unlock(&wq->mutex);
+
+ /* put the old pwqs */
+ for_each_node(node)
+ put_pwq_unlocked(pwq_tbl[node]);
+ put_pwq_unlocked(dfl_pwq);
+
+ put_online_cpus();
+ ret = 0;
+ /* fall through */
+out_free:
+ free_workqueue_attrs(tmp_attrs);
+ free_workqueue_attrs(new_attrs);
+ kfree(pwq_tbl);
+ return ret;
+
+enomem_pwq:
+ free_unbound_pwq(dfl_pwq);
+ for_each_node(node)
+ if (pwq_tbl && pwq_tbl[node] != dfl_pwq)
+ free_unbound_pwq(pwq_tbl[node]);
+ mutex_unlock(&wq_pool_mutex);
+ put_online_cpus();
+enomem:
+ ret = -ENOMEM;
+ goto out_free;
}
-static void free_pwqs(struct workqueue_struct *wq)
+/**
+ * wq_update_unbound_numa - update NUMA affinity of a wq for CPU hot[un]plug
+ * @wq: the target workqueue
+ * @cpu: the CPU coming up or going down
+ * @online: whether @cpu is coming up or going down
+ *
+ * This function is to be called from %CPU_DOWN_PREPARE, %CPU_ONLINE and
+ * %CPU_DOWN_FAILED. @cpu is being hot[un]plugged, update NUMA affinity of
+ * @wq accordingly.
+ *
+ * If NUMA affinity can't be adjusted due to memory allocation failure, it
+ * falls back to @wq->dfl_pwq which may not be optimal but is always
+ * correct.
+ *
+ * Note that when the last allowed CPU of a NUMA node goes offline for a
+ * workqueue with a cpumask spanning multiple nodes, the workers which were
+ * already executing the work items for the workqueue will lose their CPU
+ * affinity and may execute on any CPU. This is similar to how per-cpu
+ * workqueues behave on CPU_DOWN. If a workqueue user wants strict
+ * affinity, it's the user's responsibility to flush the work item from
+ * CPU_DOWN_PREPARE.
+ */
+static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu,
+ bool online)
{
- if (!(wq->flags & WQ_UNBOUND))
- free_percpu(wq->pool_wq.pcpu);
- else if (wq->pool_wq.single) {
- /* the pointer to free is stored right after the pwq */
- kfree(*(void **)(wq->pool_wq.single + 1));
+ int node = cpu_to_node(cpu);
+ int cpu_off = online ? -1 : cpu;
+ struct pool_workqueue *old_pwq = NULL, *pwq;
+ struct workqueue_attrs *target_attrs;
+ cpumask_t *cpumask;
+
+ lockdep_assert_held(&wq_pool_mutex);
+
+ if (!wq_numa_enabled || !(wq->flags & WQ_UNBOUND))
+ return;
+
+ /*
+ * We don't wanna alloc/free wq_attrs for each wq for each CPU.
+ * Let's use a preallocated one. The following buf is protected by
+ * CPU hotplug exclusion.
+ */
+ target_attrs = wq_update_unbound_numa_attrs_buf;
+ cpumask = target_attrs->cpumask;
+
+ mutex_lock(&wq->mutex);
+ if (wq->unbound_attrs->no_numa)
+ goto out_unlock;
+
+ copy_workqueue_attrs(target_attrs, wq->unbound_attrs);
+ pwq = unbound_pwq_by_node(wq, node);
+
+ /*
+ * Let's determine what needs to be done. If the target cpumask is
+ * different from wq's, we need to compare it to @pwq's and create
+ * a new one if they don't match. If the target cpumask equals
+ * wq's, the default pwq should be used. If @pwq is already the
+ * default one, nothing to do; otherwise, install the default one.
+ */
+ if (wq_calc_node_cpumask(wq->unbound_attrs, node, cpu_off, cpumask)) {
+ if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask))
+ goto out_unlock;
+ } else {
+ if (pwq == wq->dfl_pwq)
+ goto out_unlock;
+ else
+ goto use_dfl_pwq;
+ }
+
+ mutex_unlock(&wq->mutex);
+
+ /* create a new pwq */
+ pwq = alloc_unbound_pwq(wq, target_attrs);
+ if (!pwq) {
+ pr_warning("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n",
+ wq->name);
+ goto out_unlock;
+ }
+
+ /*
+ * Install the new pwq. As this function is called only from CPU
+ * hotplug callbacks and applying a new attrs is wrapped with
+ * get/put_online_cpus(), @wq->unbound_attrs couldn't have changed
+ * inbetween.
+ */
+ mutex_lock(&wq->mutex);
+ old_pwq = numa_pwq_tbl_install(wq, node, pwq);
+ goto out_unlock;
+
+use_dfl_pwq:
+ spin_lock_irq(&wq->dfl_pwq->pool->lock);
+ get_pwq(wq->dfl_pwq);
+ spin_unlock_irq(&wq->dfl_pwq->pool->lock);
+ old_pwq = numa_pwq_tbl_install(wq, node, wq->dfl_pwq);
+out_unlock:
+ mutex_unlock(&wq->mutex);
+ put_pwq_unlocked(old_pwq);
+}
+
+static int alloc_and_link_pwqs(struct workqueue_struct *wq)
+{
+ bool highpri = wq->flags & WQ_HIGHPRI;
+ int cpu;
+
+ if (!(wq->flags & WQ_UNBOUND)) {
+ wq->cpu_pwqs = alloc_percpu(struct pool_workqueue);
+ if (!wq->cpu_pwqs)
+ return -ENOMEM;
+
+ for_each_possible_cpu(cpu) {
+ struct pool_workqueue *pwq =
+ per_cpu_ptr(wq->cpu_pwqs, cpu);
+ struct worker_pool *cpu_pools =
+ per_cpu(cpu_worker_pools, cpu);
+
+ init_pwq(pwq, wq, &cpu_pools[highpri]);
+
+ mutex_lock(&wq->mutex);
+ link_pwq(pwq);
+ mutex_unlock(&wq->mutex);
+ }
+ return 0;
+ } else {
+ return apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]);
}
}
@@ -3151,30 +4080,28 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
struct lock_class_key *key,
const char *lock_name, ...)
{
- va_list args, args1;
+ size_t tbl_size = 0;
+ va_list args;
struct workqueue_struct *wq;
- unsigned int cpu;
- size_t namelen;
+ struct pool_workqueue *pwq;
- /* determine namelen, allocate wq and format name */
- va_start(args, lock_name);
- va_copy(args1, args);
- namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+ /* allocate wq and format name */
+ if (flags & WQ_UNBOUND)
+ tbl_size = wq_numa_tbl_len * sizeof(wq->numa_pwq_tbl[0]);
- wq = kzalloc(sizeof(*wq) + namelen, GFP_KERNEL);
+ wq = kzalloc(sizeof(*wq) + tbl_size, GFP_KERNEL);
if (!wq)
- goto err;
+ return NULL;
- vsnprintf(wq->name, namelen, fmt, args1);
- va_end(args);
- va_end(args1);
+ if (flags & WQ_UNBOUND) {
+ wq->unbound_attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ if (!wq->unbound_attrs)
+ goto err_free_wq;
+ }
- /*
- * Workqueues which may be used during memory reclaim should
- * have a rescuer to guarantee forward progress.
- */
- if (flags & WQ_MEM_RECLAIM)
- flags |= WQ_RESCUER;
+ va_start(args, lock_name);
+ vsnprintf(wq->name, sizeof(wq->name), fmt, args);
+ va_end(args);
max_active = max_active ?: WQ_DFL_ACTIVE;
max_active = wq_clamp_max_active(max_active, flags, wq->name);
@@ -3182,71 +4109,70 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
/* init wq */
wq->flags = flags;
wq->saved_max_active = max_active;
- mutex_init(&wq->flush_mutex);
+ mutex_init(&wq->mutex);
atomic_set(&wq->nr_pwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->pwqs);
INIT_LIST_HEAD(&wq->flusher_queue);
INIT_LIST_HEAD(&wq->flusher_overflow);
+ INIT_LIST_HEAD(&wq->maydays);
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
INIT_LIST_HEAD(&wq->list);
- if (alloc_pwqs(wq) < 0)
- goto err;
-
- for_each_pwq_cpu(cpu, wq) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
+ if (alloc_and_link_pwqs(wq) < 0)
+ goto err_free_wq;
- BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK);
- pwq->pool = get_std_worker_pool(cpu, flags & WQ_HIGHPRI);
- pwq->wq = wq;
- pwq->flush_color = -1;
- pwq->max_active = max_active;
- INIT_LIST_HEAD(&pwq->delayed_works);
- }
-
- if (flags & WQ_RESCUER) {
+ /*
+ * Workqueues which may be used during memory reclaim should
+ * have a rescuer to guarantee forward progress.
+ */
+ if (flags & WQ_MEM_RECLAIM) {
struct worker *rescuer;
- if (!alloc_mayday_mask(&wq->mayday_mask, GFP_KERNEL))
- goto err;
-
- wq->rescuer = rescuer = alloc_worker();
+ rescuer = alloc_worker();
if (!rescuer)
- goto err;
+ goto err_destroy;
rescuer->rescue_wq = wq;
rescuer->task = kthread_create(rescuer_thread, rescuer, "%s",
wq->name);
- if (IS_ERR(rescuer->task))
- goto err;
+ if (IS_ERR(rescuer->task)) {
+ kfree(rescuer);
+ goto err_destroy;
+ }
- rescuer->task->flags |= PF_THREAD_BOUND;
+ wq->rescuer = rescuer;
+ rescuer->task->flags |= PF_NO_SETAFFINITY;
wake_up_process(rescuer->task);
}
+ if ((wq->flags & WQ_SYSFS) && workqueue_sysfs_register(wq))
+ goto err_destroy;
+
/*
- * workqueue_lock protects global freeze state and workqueues
- * list. Grab it, set max_active accordingly and add the new
- * workqueue to workqueues list.
+ * wq_pool_mutex protects global freeze state and workqueues list.
+ * Grab it, adjust max_active and add the new @wq to workqueues
+ * list.
*/
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq_pool_mutex);
- if (workqueue_freezing && wq->flags & WQ_FREEZABLE)
- for_each_pwq_cpu(cpu, wq)
- get_pwq(cpu, wq)->max_active = 0;
+ mutex_lock(&wq->mutex);
+ for_each_pwq(pwq, wq)
+ pwq_adjust_max_active(pwq);
+ mutex_unlock(&wq->mutex);
list_add(&wq->list, &workqueues);
- spin_unlock(&workqueue_lock);
+ mutex_unlock(&wq_pool_mutex);
return wq;
-err:
- if (wq) {
- free_pwqs(wq);
- free_mayday_mask(wq->mayday_mask);
- kfree(wq->rescuer);
- kfree(wq);
- }
+
+err_free_wq:
+ free_workqueue_attrs(wq->unbound_attrs);
+ kfree(wq);
+ return NULL;
+err_destroy:
+ destroy_workqueue(wq);
return NULL;
}
EXPORT_SYMBOL_GPL(__alloc_workqueue_key);
@@ -3259,60 +4185,78 @@ EXPORT_SYMBOL_GPL(__alloc_workqueue_key);
*/
void destroy_workqueue(struct workqueue_struct *wq)
{
- unsigned int cpu;
+ struct pool_workqueue *pwq;
+ int node;
/* drain it before proceeding with destruction */
drain_workqueue(wq);
+ /* sanity checks */
+ mutex_lock(&wq->mutex);
+ for_each_pwq(pwq, wq) {
+ int i;
+
+ for (i = 0; i < WORK_NR_COLORS; i++) {
+ if (WARN_ON(pwq->nr_in_flight[i])) {
+ mutex_unlock(&wq->mutex);
+ return;
+ }
+ }
+
+ if (WARN_ON((pwq != wq->dfl_pwq) && (pwq->refcnt > 1)) ||
+ WARN_ON(pwq->nr_active) ||
+ WARN_ON(!list_empty(&pwq->delayed_works))) {
+ mutex_unlock(&wq->mutex);
+ return;
+ }
+ }
+ mutex_unlock(&wq->mutex);
+
/*
* wq list is used to freeze wq, remove from list after
* flushing is complete in case freeze races us.
*/
- spin_lock(&workqueue_lock);
- list_del(&wq->list);
- spin_unlock(&workqueue_lock);
-
- /* sanity check */
- for_each_pwq_cpu(cpu, wq) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
- int i;
+ mutex_lock(&wq_pool_mutex);
+ list_del_init(&wq->list);
+ mutex_unlock(&wq_pool_mutex);
- for (i = 0; i < WORK_NR_COLORS; i++)
- BUG_ON(pwq->nr_in_flight[i]);
- BUG_ON(pwq->nr_active);
- BUG_ON(!list_empty(&pwq->delayed_works));
- }
+ workqueue_sysfs_unregister(wq);
- if (wq->flags & WQ_RESCUER) {
+ if (wq->rescuer) {
kthread_stop(wq->rescuer->task);
- free_mayday_mask(wq->mayday_mask);
kfree(wq->rescuer);
+ wq->rescuer = NULL;
}
- free_pwqs(wq);
- kfree(wq);
-}
-EXPORT_SYMBOL_GPL(destroy_workqueue);
-
-/**
- * pwq_set_max_active - adjust max_active of a pwq
- * @pwq: target pool_workqueue
- * @max_active: new max_active value.
- *
- * Set @pwq->max_active to @max_active and activate delayed works if
- * increased.
- *
- * CONTEXT:
- * spin_lock_irq(pool->lock).
- */
-static void pwq_set_max_active(struct pool_workqueue *pwq, int max_active)
-{
- pwq->max_active = max_active;
+ if (!(wq->flags & WQ_UNBOUND)) {
+ /*
+ * The base ref is never dropped on per-cpu pwqs. Directly
+ * free the pwqs and wq.
+ */
+ free_percpu(wq->cpu_pwqs);
+ kfree(wq);
+ } else {
+ /*
+ * We're the sole accessor of @wq at this point. Directly
+ * access numa_pwq_tbl[] and dfl_pwq to put the base refs.
+ * @wq will be freed when the last pwq is released.
+ */
+ for_each_node(node) {
+ pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]);
+ RCU_INIT_POINTER(wq->numa_pwq_tbl[node], NULL);
+ put_pwq_unlocked(pwq);
+ }
- while (!list_empty(&pwq->delayed_works) &&
- pwq->nr_active < pwq->max_active)
- pwq_activate_first_delayed(pwq);
+ /*
+ * Put dfl_pwq. @wq may be freed any time after dfl_pwq is
+ * put. Don't access it afterwards.
+ */
+ pwq = wq->dfl_pwq;
+ wq->dfl_pwq = NULL;
+ put_pwq_unlocked(pwq);
+ }
}
+EXPORT_SYMBOL_GPL(destroy_workqueue);
/**
* workqueue_set_max_active - adjust max_active of a workqueue
@@ -3326,30 +4270,37 @@ static void pwq_set_max_active(struct pool_workqueue *pwq, int max_active)
*/
void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
{
- unsigned int cpu;
+ struct pool_workqueue *pwq;
+
+ /* disallow meddling with max_active for ordered workqueues */
+ if (WARN_ON(wq->flags & __WQ_ORDERED))
+ return;
max_active = wq_clamp_max_active(max_active, wq->flags, wq->name);
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq->mutex);
wq->saved_max_active = max_active;
- for_each_pwq_cpu(cpu, wq) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
- struct worker_pool *pool = pwq->pool;
+ for_each_pwq(pwq, wq)
+ pwq_adjust_max_active(pwq);
- spin_lock_irq(&pool->lock);
-
- if (!(wq->flags & WQ_FREEZABLE) ||
- !(pool->flags & POOL_FREEZING))
- pwq_set_max_active(pwq, max_active);
+ mutex_unlock(&wq->mutex);
+}
+EXPORT_SYMBOL_GPL(workqueue_set_max_active);
- spin_unlock_irq(&pool->lock);
- }
+/**
+ * current_is_workqueue_rescuer - is %current workqueue rescuer?
+ *
+ * Determine whether %current is a workqueue rescuer. Can be used from
+ * work functions to determine whether it's being run off the rescuer task.
+ */
+bool current_is_workqueue_rescuer(void)
+{
+ struct worker *worker = current_wq_worker();
- spin_unlock(&workqueue_lock);
+ return worker && worker->rescue_wq;
}
-EXPORT_SYMBOL_GPL(workqueue_set_max_active);
/**
* workqueue_congested - test whether a workqueue is congested
@@ -3363,11 +4314,22 @@ EXPORT_SYMBOL_GPL(workqueue_set_max_active);
* RETURNS:
* %true if congested, %false otherwise.
*/
-bool workqueue_congested(unsigned int cpu, struct workqueue_struct *wq)
+bool workqueue_congested(int cpu, struct workqueue_struct *wq)
{
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
+ struct pool_workqueue *pwq;
+ bool ret;
+
+ rcu_read_lock_sched();
- return !list_empty(&pwq->delayed_works);
+ if (!(wq->flags & WQ_UNBOUND))
+ pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
+ else
+ pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu));
+
+ ret = !list_empty(&pwq->delayed_works);
+ rcu_read_unlock_sched();
+
+ return ret;
}
EXPORT_SYMBOL_GPL(workqueue_congested);
@@ -3384,24 +4346,104 @@ EXPORT_SYMBOL_GPL(workqueue_congested);
*/
unsigned int work_busy(struct work_struct *work)
{
- struct worker_pool *pool = get_work_pool(work);
+ struct worker_pool *pool;
unsigned long flags;
unsigned int ret = 0;
if (work_pending(work))
ret |= WORK_BUSY_PENDING;
+ local_irq_save(flags);
+ pool = get_work_pool(work);
if (pool) {
- spin_lock_irqsave(&pool->lock, flags);
+ spin_lock(&pool->lock);
if (find_worker_executing_work(pool, work))
ret |= WORK_BUSY_RUNNING;
- spin_unlock_irqrestore(&pool->lock, flags);
+ spin_unlock(&pool->lock);
}
+ local_irq_restore(flags);
return ret;
}
EXPORT_SYMBOL_GPL(work_busy);
+/**
+ * set_worker_desc - set description for the current work item
+ * @fmt: printf-style format string
+ * @...: arguments for the format string
+ *
+ * This function can be called by a running work function to describe what
+ * the work item is about. If the worker task gets dumped, this
+ * information will be printed out together to help debugging. The
+ * description can be at most WORKER_DESC_LEN including the trailing '\0'.
+ */
+void set_worker_desc(const char *fmt, ...)
+{
+ struct worker *worker = current_wq_worker();
+ va_list args;
+
+ if (worker) {
+ va_start(args, fmt);
+ vsnprintf(worker->desc, sizeof(worker->desc), fmt, args);
+ va_end(args);
+ worker->desc_valid = true;
+ }
+}
+
+/**
+ * print_worker_info - print out worker information and description
+ * @log_lvl: the log level to use when printing
+ * @task: target task
+ *
+ * If @task is a worker and currently executing a work item, print out the
+ * name of the workqueue being serviced and worker description set with
+ * set_worker_desc() by the currently executing work item.
+ *
+ * This function can be safely called on any task as long as the
+ * task_struct itself is accessible. While safe, this function isn't
+ * synchronized and may print out mixups or garbages of limited length.
+ */
+void print_worker_info(const char *log_lvl, struct task_struct *task)
+{
+ work_func_t *fn = NULL;
+ char name[WQ_NAME_LEN] = { };
+ char desc[WORKER_DESC_LEN] = { };
+ struct pool_workqueue *pwq = NULL;
+ struct workqueue_struct *wq = NULL;
+ bool desc_valid = false;
+ struct worker *worker;
+
+ if (!(task->flags & PF_WQ_WORKER))
+ return;
+
+ /*
+ * This function is called without any synchronization and @task
+ * could be in any state. Be careful with dereferences.
+ */
+ worker = probe_kthread_data(task);
+
+ /*
+ * Carefully copy the associated workqueue's workfn and name. Keep
+ * the original last '\0' in case the original contains garbage.
+ */
+ probe_kernel_read(&fn, &worker->current_func, sizeof(fn));
+ probe_kernel_read(&pwq, &worker->current_pwq, sizeof(pwq));
+ probe_kernel_read(&wq, &pwq->wq, sizeof(wq));
+ probe_kernel_read(name, wq->name, sizeof(name) - 1);
+
+ /* copy worker description */
+ probe_kernel_read(&desc_valid, &worker->desc_valid, sizeof(desc_valid));
+ if (desc_valid)
+ probe_kernel_read(desc, worker->desc, sizeof(desc) - 1);
+
+ if (fn || name[0] || desc[0]) {
+ printk("%sWorkqueue: %s %pf", log_lvl, name, fn);
+ if (desc[0])
+ pr_cont(" (%s)", desc);
+ pr_cont("\n");
+ }
+}
+
/*
* CPU hotplug.
*
@@ -3422,31 +4464,28 @@ static void wq_unbind_fn(struct work_struct *work)
int cpu = smp_processor_id();
struct worker_pool *pool;
struct worker *worker;
- int i;
+ int wi;
- for_each_std_worker_pool(pool, cpu) {
- BUG_ON(cpu != smp_processor_id());
+ for_each_cpu_worker_pool(pool, cpu) {
+ WARN_ON_ONCE(cpu != smp_processor_id());
- mutex_lock(&pool->assoc_mutex);
+ mutex_lock(&pool->manager_mutex);
spin_lock_irq(&pool->lock);
/*
- * We've claimed all manager positions. Make all workers
+ * We've blocked all manager operations. Make all workers
* unbound and set DISASSOCIATED. Before this, all workers
* except for the ones which are still executing works from
* before the last CPU down must be on the cpu. After
* this, they may become diasporas.
*/
- list_for_each_entry(worker, &pool->idle_list, entry)
- worker->flags |= WORKER_UNBOUND;
-
- for_each_busy_worker(worker, i, pool)
+ for_each_pool_worker(worker, wi, pool)
worker->flags |= WORKER_UNBOUND;
pool->flags |= POOL_DISASSOCIATED;
spin_unlock_irq(&pool->lock);
- mutex_unlock(&pool->assoc_mutex);
+ mutex_unlock(&pool->manager_mutex);
/*
* Call schedule() so that we cross rq->lock and thus can
@@ -3477,6 +4516,103 @@ static void wq_unbind_fn(struct work_struct *work)
}
}
+/**
+ * rebind_workers - rebind all workers of a pool to the associated CPU
+ * @pool: pool of interest
+ *
+ * @pool->cpu is coming online. Rebind all workers to the CPU.
+ */
+static void rebind_workers(struct worker_pool *pool)
+{
+ struct worker *worker;
+ int wi;
+
+ lockdep_assert_held(&pool->manager_mutex);
+
+ /*
+ * Restore CPU affinity of all workers. As all idle workers should
+ * be on the run-queue of the associated CPU before any local
+ * wake-ups for concurrency management happen, restore CPU affinty
+ * of all workers first and then clear UNBOUND. As we're called
+ * from CPU_ONLINE, the following shouldn't fail.
+ */
+ for_each_pool_worker(worker, wi, pool)
+ WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task,
+ pool->attrs->cpumask) < 0);
+
+ spin_lock_irq(&pool->lock);
+
+ for_each_pool_worker(worker, wi, pool) {
+ unsigned int worker_flags = worker->flags;
+
+ /*
+ * A bound idle worker should actually be on the runqueue
+ * of the associated CPU for local wake-ups targeting it to
+ * work. Kick all idle workers so that they migrate to the
+ * associated CPU. Doing this in the same loop as
+ * replacing UNBOUND with REBOUND is safe as no worker will
+ * be bound before @pool->lock is released.
+ */
+ if (worker_flags & WORKER_IDLE)
+ wake_up_process(worker->task);
+
+ /*
+ * We want to clear UNBOUND but can't directly call
+ * worker_clr_flags() or adjust nr_running. Atomically
+ * replace UNBOUND with another NOT_RUNNING flag REBOUND.
+ * @worker will clear REBOUND using worker_clr_flags() when
+ * it initiates the next execution cycle thus restoring
+ * concurrency management. Note that when or whether
+ * @worker clears REBOUND doesn't affect correctness.
+ *
+ * ACCESS_ONCE() is necessary because @worker->flags may be
+ * tested without holding any lock in
+ * wq_worker_waking_up(). Without it, NOT_RUNNING test may
+ * fail incorrectly leading to premature concurrency
+ * management operations.
+ */
+ WARN_ON_ONCE(!(worker_flags & WORKER_UNBOUND));
+ worker_flags |= WORKER_REBOUND;
+ worker_flags &= ~WORKER_UNBOUND;
+ ACCESS_ONCE(worker->flags) = worker_flags;
+ }
+
+ spin_unlock_irq(&pool->lock);
+}
+
+/**
+ * restore_unbound_workers_cpumask - restore cpumask of unbound workers
+ * @pool: unbound pool of interest
+ * @cpu: the CPU which is coming up
+ *
+ * An unbound pool may end up with a cpumask which doesn't have any online
+ * CPUs. When a worker of such pool get scheduled, the scheduler resets
+ * its cpus_allowed. If @cpu is in @pool's cpumask which didn't have any
+ * online CPU before, cpus_allowed of all its workers should be restored.
+ */
+static void restore_unbound_workers_cpumask(struct worker_pool *pool, int cpu)
+{
+ static cpumask_t cpumask;
+ struct worker *worker;
+ int wi;
+
+ lockdep_assert_held(&pool->manager_mutex);
+
+ /* is @cpu allowed for @pool? */
+ if (!cpumask_test_cpu(cpu, pool->attrs->cpumask))
+ return;
+
+ /* is @cpu the only online CPU? */
+ cpumask_and(&cpumask, pool->attrs->cpumask, cpu_online_mask);
+ if (cpumask_weight(&cpumask) != 1)
+ return;
+
+ /* as we're called from CPU_ONLINE, the following shouldn't fail */
+ for_each_pool_worker(worker, wi, pool)
+ WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task,
+ pool->attrs->cpumask) < 0);
+}
+
/*
* Workqueues should be brought up before normal priority CPU notifiers.
* This will be registered high priority CPU notifier.
@@ -3485,39 +4621,46 @@ static int __cpuinit workqueue_cpu_up_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
- unsigned int cpu = (unsigned long)hcpu;
+ int cpu = (unsigned long)hcpu;
struct worker_pool *pool;
+ struct workqueue_struct *wq;
+ int pi;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- for_each_std_worker_pool(pool, cpu) {
- struct worker *worker;
-
+ for_each_cpu_worker_pool(pool, cpu) {
if (pool->nr_workers)
continue;
-
- worker = create_worker(pool);
- if (!worker)
+ if (create_and_start_worker(pool) < 0)
return NOTIFY_BAD;
-
- spin_lock_irq(&pool->lock);
- start_worker(worker);
- spin_unlock_irq(&pool->lock);
}
break;
case CPU_DOWN_FAILED:
case CPU_ONLINE:
- for_each_std_worker_pool(pool, cpu) {
- mutex_lock(&pool->assoc_mutex);
- spin_lock_irq(&pool->lock);
+ mutex_lock(&wq_pool_mutex);
- pool->flags &= ~POOL_DISASSOCIATED;
- rebind_workers(pool);
+ for_each_pool(pool, pi) {
+ mutex_lock(&pool->manager_mutex);
+
+ if (pool->cpu == cpu) {
+ spin_lock_irq(&pool->lock);
+ pool->flags &= ~POOL_DISASSOCIATED;
+ spin_unlock_irq(&pool->lock);
- spin_unlock_irq(&pool->lock);
- mutex_unlock(&pool->assoc_mutex);
+ rebind_workers(pool);
+ } else if (pool->cpu < 0) {
+ restore_unbound_workers_cpumask(pool, cpu);
+ }
+
+ mutex_unlock(&pool->manager_mutex);
}
+
+ /* update NUMA affinity of unbound workqueues */
+ list_for_each_entry(wq, &workqueues, list)
+ wq_update_unbound_numa(wq, cpu, true);
+
+ mutex_unlock(&wq_pool_mutex);
break;
}
return NOTIFY_OK;
@@ -3531,14 +4674,23 @@ static int __cpuinit workqueue_cpu_down_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
- unsigned int cpu = (unsigned long)hcpu;
+ int cpu = (unsigned long)hcpu;
struct work_struct unbind_work;
+ struct workqueue_struct *wq;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
- /* unbinding should happen on the local CPU */
+ /* unbinding per-cpu workers should happen on the local CPU */
INIT_WORK_ONSTACK(&unbind_work, wq_unbind_fn);
queue_work_on(cpu, system_highpri_wq, &unbind_work);
+
+ /* update NUMA affinity of unbound workqueues */
+ mutex_lock(&wq_pool_mutex);
+ list_for_each_entry(wq, &workqueues, list)
+ wq_update_unbound_numa(wq, cpu, false);
+ mutex_unlock(&wq_pool_mutex);
+
+ /* wait for per-cpu unbinding to finish */
flush_work(&unbind_work);
break;
}
@@ -3571,7 +4723,7 @@ static void work_for_cpu_fn(struct work_struct *work)
* It is up to the caller to ensure that the cpu doesn't go offline.
* The caller must not hold any locks which would prevent @fn from completing.
*/
-long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
+long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
{
struct work_for_cpu wfc = { .fn = fn, .arg = arg };
@@ -3589,44 +4741,40 @@ EXPORT_SYMBOL_GPL(work_on_cpu);
* freeze_workqueues_begin - begin freezing workqueues
*
* Start freezing workqueues. After this function returns, all freezable
- * workqueues will queue new works to their frozen_works list instead of
+ * workqueues will queue new works to their delayed_works list instead of
* pool->worklist.
*
* CONTEXT:
- * Grabs and releases workqueue_lock and pool->lock's.
+ * Grabs and releases wq_pool_mutex, wq->mutex and pool->lock's.
*/
void freeze_workqueues_begin(void)
{
- unsigned int cpu;
+ struct worker_pool *pool;
+ struct workqueue_struct *wq;
+ struct pool_workqueue *pwq;
+ int pi;
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq_pool_mutex);
- BUG_ON(workqueue_freezing);
+ WARN_ON_ONCE(workqueue_freezing);
workqueue_freezing = true;
- for_each_wq_cpu(cpu) {
- struct worker_pool *pool;
- struct workqueue_struct *wq;
-
- for_each_std_worker_pool(pool, cpu) {
- spin_lock_irq(&pool->lock);
-
- WARN_ON_ONCE(pool->flags & POOL_FREEZING);
- pool->flags |= POOL_FREEZING;
-
- list_for_each_entry(wq, &workqueues, list) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
-
- if (pwq && pwq->pool == pool &&
- (wq->flags & WQ_FREEZABLE))
- pwq->max_active = 0;
- }
+ /* set FREEZING */
+ for_each_pool(pool, pi) {
+ spin_lock_irq(&pool->lock);
+ WARN_ON_ONCE(pool->flags & POOL_FREEZING);
+ pool->flags |= POOL_FREEZING;
+ spin_unlock_irq(&pool->lock);
+ }
- spin_unlock_irq(&pool->lock);
- }
+ list_for_each_entry(wq, &workqueues, list) {
+ mutex_lock(&wq->mutex);
+ for_each_pwq(pwq, wq)
+ pwq_adjust_max_active(pwq);
+ mutex_unlock(&wq->mutex);
}
- spin_unlock(&workqueue_lock);
+ mutex_unlock(&wq_pool_mutex);
}
/**
@@ -3636,7 +4784,7 @@ void freeze_workqueues_begin(void)
* between freeze_workqueues_begin() and thaw_workqueues().
*
* CONTEXT:
- * Grabs and releases workqueue_lock.
+ * Grabs and releases wq_pool_mutex.
*
* RETURNS:
* %true if some freezable workqueues are still busy. %false if freezing
@@ -3644,34 +4792,34 @@ void freeze_workqueues_begin(void)
*/
bool freeze_workqueues_busy(void)
{
- unsigned int cpu;
bool busy = false;
+ struct workqueue_struct *wq;
+ struct pool_workqueue *pwq;
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq_pool_mutex);
- BUG_ON(!workqueue_freezing);
+ WARN_ON_ONCE(!workqueue_freezing);
- for_each_wq_cpu(cpu) {
- struct workqueue_struct *wq;
+ list_for_each_entry(wq, &workqueues, list) {
+ if (!(wq->flags & WQ_FREEZABLE))
+ continue;
/*
* nr_active is monotonically decreasing. It's safe
* to peek without lock.
*/
- list_for_each_entry(wq, &workqueues, list) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
-
- if (!pwq || !(wq->flags & WQ_FREEZABLE))
- continue;
-
- BUG_ON(pwq->nr_active < 0);
+ rcu_read_lock_sched();
+ for_each_pwq(pwq, wq) {
+ WARN_ON_ONCE(pwq->nr_active < 0);
if (pwq->nr_active) {
busy = true;
+ rcu_read_unlock_sched();
goto out_unlock;
}
}
+ rcu_read_unlock_sched();
}
out_unlock:
- spin_unlock(&workqueue_lock);
+ mutex_unlock(&wq_pool_mutex);
return busy;
}
@@ -3682,104 +4830,141 @@ out_unlock:
* frozen works are transferred to their respective pool worklists.
*
* CONTEXT:
- * Grabs and releases workqueue_lock and pool->lock's.
+ * Grabs and releases wq_pool_mutex, wq->mutex and pool->lock's.
*/
void thaw_workqueues(void)
{
- unsigned int cpu;
+ struct workqueue_struct *wq;
+ struct pool_workqueue *pwq;
+ struct worker_pool *pool;
+ int pi;
- spin_lock(&workqueue_lock);
+ mutex_lock(&wq_pool_mutex);
if (!workqueue_freezing)
goto out_unlock;
- for_each_wq_cpu(cpu) {
- struct worker_pool *pool;
- struct workqueue_struct *wq;
+ /* clear FREEZING */
+ for_each_pool(pool, pi) {
+ spin_lock_irq(&pool->lock);
+ WARN_ON_ONCE(!(pool->flags & POOL_FREEZING));
+ pool->flags &= ~POOL_FREEZING;
+ spin_unlock_irq(&pool->lock);
+ }
- for_each_std_worker_pool(pool, cpu) {
- spin_lock_irq(&pool->lock);
+ /* restore max_active and repopulate worklist */
+ list_for_each_entry(wq, &workqueues, list) {
+ mutex_lock(&wq->mutex);
+ for_each_pwq(pwq, wq)
+ pwq_adjust_max_active(pwq);
+ mutex_unlock(&wq->mutex);
+ }
- WARN_ON_ONCE(!(pool->flags & POOL_FREEZING));
- pool->flags &= ~POOL_FREEZING;
+ workqueue_freezing = false;
+out_unlock:
+ mutex_unlock(&wq_pool_mutex);
+}
+#endif /* CONFIG_FREEZER */
- list_for_each_entry(wq, &workqueues, list) {
- struct pool_workqueue *pwq = get_pwq(cpu, wq);
+static void __init wq_numa_init(void)
+{
+ cpumask_var_t *tbl;
+ int node, cpu;
- if (!pwq || pwq->pool != pool ||
- !(wq->flags & WQ_FREEZABLE))
- continue;
+ /* determine NUMA pwq table len - highest node id + 1 */
+ for_each_node(node)
+ wq_numa_tbl_len = max(wq_numa_tbl_len, node + 1);
- /* restore max_active and repopulate worklist */
- pwq_set_max_active(pwq, wq->saved_max_active);
- }
+ if (num_possible_nodes() <= 1)
+ return;
- wake_up_worker(pool);
+ if (wq_disable_numa) {
+ pr_info("workqueue: NUMA affinity support disabled\n");
+ return;
+ }
+
+ wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs(GFP_KERNEL);
+ BUG_ON(!wq_update_unbound_numa_attrs_buf);
- spin_unlock_irq(&pool->lock);
+ /*
+ * We want masks of possible CPUs of each node which isn't readily
+ * available. Build one from cpu_to_node() which should have been
+ * fully initialized by now.
+ */
+ tbl = kzalloc(wq_numa_tbl_len * sizeof(tbl[0]), GFP_KERNEL);
+ BUG_ON(!tbl);
+
+ for_each_node(node)
+ BUG_ON(!alloc_cpumask_var_node(&tbl[node], GFP_KERNEL, node));
+
+ for_each_possible_cpu(cpu) {
+ node = cpu_to_node(cpu);
+ if (WARN_ON(node == NUMA_NO_NODE)) {
+ pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu);
+ /* happens iff arch is bonkers, let's just proceed */
+ return;
}
+ cpumask_set_cpu(cpu, tbl[node]);
}
- workqueue_freezing = false;
-out_unlock:
- spin_unlock(&workqueue_lock);
+ wq_numa_possible_cpumask = tbl;
+ wq_numa_enabled = true;
}
-#endif /* CONFIG_FREEZER */
static int __init init_workqueues(void)
{
- unsigned int cpu;
+ int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL };
+ int i, cpu;
/* make sure we have enough bits for OFFQ pool ID */
BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT)) <
WORK_CPU_END * NR_STD_WORKER_POOLS);
+ WARN_ON(__alignof__(struct pool_workqueue) < __alignof__(long long));
+
+ pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
+
cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
hotcpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
+ wq_numa_init();
+
/* initialize CPU pools */
- for_each_wq_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
struct worker_pool *pool;
- for_each_std_worker_pool(pool, cpu) {
- spin_lock_init(&pool->lock);
+ i = 0;
+ for_each_cpu_worker_pool(pool, cpu) {
+ BUG_ON(init_worker_pool(pool));
pool->cpu = cpu;
- pool->flags |= POOL_DISASSOCIATED;
- INIT_LIST_HEAD(&pool->worklist);
- INIT_LIST_HEAD(&pool->idle_list);
- hash_init(pool->busy_hash);
-
- init_timer_deferrable(&pool->idle_timer);
- pool->idle_timer.function = idle_worker_timeout;
- pool->idle_timer.data = (unsigned long)pool;
-
- setup_timer(&pool->mayday_timer, pool_mayday_timeout,
- (unsigned long)pool);
-
- mutex_init(&pool->assoc_mutex);
- ida_init(&pool->worker_ida);
+ cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));
+ pool->attrs->nice = std_nice[i++];
+ pool->node = cpu_to_node(cpu);
/* alloc pool ID */
+ mutex_lock(&wq_pool_mutex);
BUG_ON(worker_pool_assign_id(pool));
+ mutex_unlock(&wq_pool_mutex);
}
}
/* create the initial worker */
- for_each_online_wq_cpu(cpu) {
+ for_each_online_cpu(cpu) {
struct worker_pool *pool;
- for_each_std_worker_pool(pool, cpu) {
- struct worker *worker;
+ for_each_cpu_worker_pool(pool, cpu) {
+ pool->flags &= ~POOL_DISASSOCIATED;
+ BUG_ON(create_and_start_worker(pool) < 0);
+ }
+ }
- if (cpu != WORK_CPU_UNBOUND)
- pool->flags &= ~POOL_DISASSOCIATED;
+ /* create default unbound wq attrs */
+ for (i = 0; i < NR_STD_WORKER_POOLS; i++) {
+ struct workqueue_attrs *attrs;
- worker = create_worker(pool);
- BUG_ON(!worker);
- spin_lock_irq(&pool->lock);
- start_worker(worker);
- spin_unlock_irq(&pool->lock);
- }
+ BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL)));
+ attrs->nice = std_nice[i];
+ unbound_std_wq_attrs[i] = attrs;
}
system_wq = alloc_workqueue("events", 0, 0);
diff --git a/kernel/workqueue_internal.h b/kernel/workqueue_internal.h
index 07650264ec15..ad83c96b2ece 100644
--- a/kernel/workqueue_internal.h
+++ b/kernel/workqueue_internal.h
@@ -29,16 +29,24 @@ struct worker {
struct work_struct *current_work; /* L: work being processed */
work_func_t current_func; /* L: current_work's fn */
struct pool_workqueue *current_pwq; /* L: current_work's pwq */
+ bool desc_valid; /* ->desc is valid */
struct list_head scheduled; /* L: scheduled works */
+
+ /* 64 bytes boundary on 64bit, 32 on 32bit */
+
struct task_struct *task; /* I: worker task */
struct worker_pool *pool; /* I: the associated pool */
- /* 64 bytes boundary on 64bit, 32 on 32bit */
+ /* L: for rescuers */
+
unsigned long last_active; /* L: last active timestamp */
unsigned int flags; /* X: flags */
int id; /* I: worker id */
- /* for rebinding worker to CPU */
- struct work_struct rebind_work; /* L: for busy worker */
+ /*
+ * Opaque string set with work_set_desc(). Printed out with task
+ * dump for debugging - WARN, BUG, panic or sysrq.
+ */
+ char desc[WORKER_DESC_LEN];
/* used only by rescuers to point to the target workqueue */
struct workqueue_struct *rescue_wq; /* I: the workqueue to rescue */
@@ -58,8 +66,7 @@ static inline struct worker *current_wq_worker(void)
* Scheduler hooks for concurrency managed workqueue. Only to be used from
* sched.c and workqueue.c.
*/
-void wq_worker_waking_up(struct task_struct *task, unsigned int cpu);
-struct task_struct *wq_worker_sleeping(struct task_struct *task,
- unsigned int cpu);
+void wq_worker_waking_up(struct task_struct *task, int cpu);
+struct task_struct *wq_worker_sleeping(struct task_struct *task, int cpu);
#endif /* _KERNEL_WORKQUEUE_INTERNAL_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 3958dc4389f9..fe01d418b09a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -404,4 +404,7 @@ config OID_REGISTRY
help
Enable fast lookup object identifier registry.
+config UCS2_STRING
+ tristate
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 28be08c09bab..566cf2bc08ea 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1192,7 +1192,7 @@ config MEMORY_NOTIFIER_ERROR_INJECT
bash: echo: write error: Cannot allocate memory
To compile this code as a module, choose M here: the module will
- be called pSeries-reconfig-notifier-error-inject.
+ be called memory-notifier-error-inject.
If unsure, say N.
@@ -1209,7 +1209,7 @@ config OF_RECONFIG_NOTIFIER_ERROR_INJECT
notified, write the error code to "actions/<notifier event>/error".
To compile this code as a module, choose M here: the module will
- be called memory-notifier-error-inject.
+ be called of-reconfig-notifier-error-inject.
If unsure, say N.
@@ -1292,6 +1292,24 @@ config LATENCYTOP
Enable this option if you want to use the LatencyTOP tool
to find out which userspace is blocking on what kernel operations.
+config ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ bool
+
+config DEBUG_STRICT_USER_COPY_CHECKS
+ bool "Strict user copy size checks"
+ depends on ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
+ depends on DEBUG_KERNEL && !TRACE_BRANCH_PROFILING
+ help
+ Enabling this option turns a certain set of sanity checks for user
+ copy operations into compile time failures.
+
+ The copy_from_user() etc checks are there to help test if there
+ are sufficient security checks on the length argument of
+ the copy operation, by having gcc prove that the argument is
+ within bounds.
+
+ If unsure, say N.
+
source mm/Kconfig.debug
source kernel/trace/Kconfig
@@ -1463,5 +1481,8 @@ source "lib/Kconfig.kgdb"
source "lib/Kconfig.kmemcheck"
+config TEST_STRING_HELPERS
+ tristate "Test functions located in the string_helpers module at runtime"
+
config TEST_KSTRTOX
tristate "Test kstrto*() family of functions at runtime"
diff --git a/lib/Makefile b/lib/Makefile
index d7946ff75b2e..e9c52e1b853a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -15,6 +15,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
earlycpio.o
+obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -22,8 +23,10 @@ lib-y += kobject.o klist.o
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
- string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
+ gcd.o lcm.o list_sort.o uuid.o flex_array.o \
bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o
+obj-y += string_helpers.o
+obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
obj-y += kstrtox.o
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
@@ -174,3 +177,5 @@ quiet_cmd_build_OID_registry = GEN $@
cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@
clean-files += oid_registry_data.c
+
+obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
diff --git a/lib/argv_split.c b/lib/argv_split.c
index 1e9a6cbc3689..e927ed0e18a8 100644
--- a/lib/argv_split.c
+++ b/lib/argv_split.c
@@ -8,23 +8,17 @@
#include <linux/slab.h>
#include <linux/export.h>
-static const char *skip_arg(const char *cp)
-{
- while (*cp && !isspace(*cp))
- cp++;
-
- return cp;
-}
-
static int count_argc(const char *str)
{
int count = 0;
+ bool was_space;
- while (*str) {
- str = skip_spaces(str);
- if (*str) {
+ for (was_space = true; *str; str++) {
+ if (isspace(*str)) {
+ was_space = true;
+ } else if (was_space) {
+ was_space = false;
count++;
- str = skip_arg(str);
}
}
@@ -39,10 +33,8 @@ static int count_argc(const char *str)
*/
void argv_free(char **argv)
{
- char **p;
- for (p = argv; *p; p++)
- kfree(*p);
-
+ argv--;
+ kfree(argv[0]);
kfree(argv);
}
EXPORT_SYMBOL(argv_free);
@@ -59,43 +51,44 @@ EXPORT_SYMBOL(argv_free);
* considered to be a single argument separator. The returned array
* is always NULL-terminated. Returns NULL on memory allocation
* failure.
+ *
+ * The source string at `str' may be undergoing concurrent alteration via
+ * userspace sysctl activity (at least). The argv_split() implementation
+ * attempts to handle this gracefully by taking a local copy to work on.
*/
char **argv_split(gfp_t gfp, const char *str, int *argcp)
{
- int argc = count_argc(str);
- char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
- char **argvp;
-
- if (argv == NULL)
- goto out;
-
- if (argcp)
- *argcp = argc;
-
- argvp = argv;
-
- while (*str) {
- str = skip_spaces(str);
-
- if (*str) {
- const char *p = str;
- char *t;
-
- str = skip_arg(str);
+ char *argv_str;
+ bool was_space;
+ char **argv, **argv_ret;
+ int argc;
+
+ argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp);
+ if (!argv_str)
+ return NULL;
+
+ argc = count_argc(argv_str);
+ argv = kmalloc(sizeof(*argv) * (argc + 2), gfp);
+ if (!argv) {
+ kfree(argv_str);
+ return NULL;
+ }
- t = kstrndup(p, str-p, gfp);
- if (t == NULL)
- goto fail;
- *argvp++ = t;
+ *argv = argv_str;
+ argv_ret = ++argv;
+ for (was_space = true; *argv_str; argv_str++) {
+ if (isspace(*argv_str)) {
+ was_space = true;
+ *argv_str = 0;
+ } else if (was_space) {
+ was_space = false;
+ *argv++ = argv_str;
}
}
- *argvp = NULL;
-
- out:
- return argv;
+ *argv = NULL;
- fail:
- argv_free(argv);
- return NULL;
+ if (argcp)
+ *argcp = argc;
+ return argv_ret;
}
EXPORT_SYMBOL(argv_split);
diff --git a/lib/decompress.c b/lib/decompress.c
index 31a804277282..f8fdedaf7b3d 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -38,7 +38,7 @@ struct compress_format {
decompress_fn decompressor;
};
-static const struct compress_format compressed_formats[] __initdata = {
+static const struct compress_format compressed_formats[] __initconst = {
{ {037, 0213}, "gzip", gunzip },
{ {037, 0236}, "gzip", gunzip },
{ {0x42, 0x5a}, "bzip2", bunzip2 },
diff --git a/lib/div64.c b/lib/div64.c
index a163b6caef73..3af5728d95fd 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -79,9 +79,10 @@ EXPORT_SYMBOL(div_s64_rem);
#endif
/**
- * div64_u64 - unsigned 64bit divide with 64bit divisor
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and 64bit remainder
* @dividend: 64bit dividend
* @divisor: 64bit divisor
+ * @remainder: 64bit remainder
*
* This implementation is a modified version of the algorithm proposed
* by the book 'Hacker's Delight'. The original source and full proof
@@ -89,27 +90,33 @@ EXPORT_SYMBOL(div_s64_rem);
*
* 'http://www.hackersdelight.org/HDcode/newCode/divDouble.c.txt'
*/
-#ifndef div64_u64
-u64 div64_u64(u64 dividend, u64 divisor)
+#ifndef div64_u64_rem
+u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
{
u32 high = divisor >> 32;
u64 quot;
if (high == 0) {
- quot = div_u64(dividend, divisor);
+ u32 rem32;
+ quot = div_u64_rem(dividend, divisor, &rem32);
+ *remainder = rem32;
} else {
int n = 1 + fls(high);
quot = div_u64(dividend >> n, divisor >> n);
if (quot != 0)
quot--;
- if ((dividend - quot * divisor) >= divisor)
+
+ *remainder = dividend - quot * divisor;
+ if (*remainder >= divisor) {
quot++;
+ *remainder -= divisor;
+ }
}
return quot;
}
-EXPORT_SYMBOL(div64_u64);
+EXPORT_SYMBOL(div64_u64_rem);
#endif
/**
diff --git a/lib/dump_stack.c b/lib/dump_stack.c
index 42f4f55c9458..53bad099ebd6 100644
--- a/lib/dump_stack.c
+++ b/lib/dump_stack.c
@@ -5,11 +5,16 @@
#include <linux/kernel.h>
#include <linux/export.h>
+#include <linux/sched.h>
+/**
+ * dump_stack - dump the current task information and its stack trace
+ *
+ * Architectures can override this implementation by implementing its own.
+ */
void dump_stack(void)
{
- printk(KERN_NOTICE
- "This architecture does not implement dump_stack()\n");
+ dump_stack_print_info(KERN_DEFAULT);
+ show_stack(NULL, NULL);
}
-
EXPORT_SYMBOL(dump_stack);
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 5276b99ca650..99fec3ae405a 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -24,6 +24,7 @@
#include <linux/sysctl.h>
#include <linux/ctype.h>
#include <linux/string.h>
+#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include <linux/dynamic_debug.h>
#include <linux/debugfs.h>
@@ -276,48 +277,6 @@ static inline int parse_lineno(const char *str, unsigned int *val)
return 0;
}
-/*
- * Undo octal escaping in a string, inplace. This is useful to
- * allow the user to express a query which matches a format
- * containing embedded spaces.
- */
-#define isodigit(c) ((c) >= '0' && (c) <= '7')
-static char *unescape(char *str)
-{
- char *in = str;
- char *out = str;
-
- while (*in) {
- if (*in == '\\') {
- if (in[1] == '\\') {
- *out++ = '\\';
- in += 2;
- continue;
- } else if (in[1] == 't') {
- *out++ = '\t';
- in += 2;
- continue;
- } else if (in[1] == 'n') {
- *out++ = '\n';
- in += 2;
- continue;
- } else if (isodigit(in[1]) &&
- isodigit(in[2]) &&
- isodigit(in[3])) {
- *out++ = (((in[1] - '0') << 6) |
- ((in[2] - '0') << 3) |
- (in[3] - '0'));
- in += 4;
- continue;
- }
- }
- *out++ = *in++;
- }
- *out = '\0';
-
- return str;
-}
-
static int check_set(const char **dest, char *src, char *name)
{
int rc = 0;
@@ -371,8 +330,10 @@ static int ddebug_parse_query(char *words[], int nwords,
} else if (!strcmp(words[i], "module")) {
rc = check_set(&query->module, words[i+1], "module");
} else if (!strcmp(words[i], "format")) {
- rc = check_set(&query->format, unescape(words[i+1]),
- "format");
+ string_unescape_inplace(words[i+1], UNESCAPE_SPACE |
+ UNESCAPE_OCTAL |
+ UNESCAPE_SPECIAL);
+ rc = check_set(&query->format, words[i+1], "format");
} else if (!strcmp(words[i], "line")) {
char *first = words[i+1];
char *last = strchr(first, '-');
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index f7210ad6cffd..c5c7a762b850 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -122,7 +122,7 @@ bool should_fail(struct fault_attr *attr, ssize_t size)
return false;
}
- if (attr->probability <= random32() % 100)
+ if (attr->probability <= prandom_u32() % 100)
return false;
if (!fail_stacktrace(attr))
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 54920433705a..b35cfa9bc3d4 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -34,6 +34,8 @@
#include <linux/rculist.h>
#include <linux/interrupt.h>
#include <linux/genalloc.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
{
@@ -480,3 +482,82 @@ unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size,
return start_bit;
}
EXPORT_SYMBOL(gen_pool_best_fit);
+
+static void devm_gen_pool_release(struct device *dev, void *res)
+{
+ gen_pool_destroy(*(struct gen_pool **)res);
+}
+
+/**
+ * devm_gen_pool_create - managed gen_pool_create
+ * @dev: device that provides the gen_pool
+ * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
+ * @nid: node id of the node the pool structure should be allocated on, or -1
+ *
+ * Create a new special memory pool that can be used to manage special purpose
+ * memory not managed by the regular kmalloc/kfree interface. The pool will be
+ * automatically destroyed by the device management code.
+ */
+struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order,
+ int nid)
+{
+ struct gen_pool **ptr, *pool;
+
+ ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL);
+
+ pool = gen_pool_create(min_alloc_order, nid);
+ if (pool) {
+ *ptr = pool;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return pool;
+}
+
+/**
+ * dev_get_gen_pool - Obtain the gen_pool (if any) for a device
+ * @dev: device to retrieve the gen_pool from
+ * @name: Optional name for the gen_pool, usually NULL
+ *
+ * Returns the gen_pool for the device if one is present, or NULL.
+ */
+struct gen_pool *dev_get_gen_pool(struct device *dev)
+{
+ struct gen_pool **p = devres_find(dev, devm_gen_pool_release, NULL,
+ NULL);
+
+ if (!p)
+ return NULL;
+ return *p;
+}
+EXPORT_SYMBOL_GPL(dev_get_gen_pool);
+
+#ifdef CONFIG_OF
+/**
+ * of_get_named_gen_pool - find a pool by phandle property
+ * @np: device node
+ * @propname: property name containing phandle(s)
+ * @index: index into the phandle array
+ *
+ * Returns the pool that contains the chunk starting at the physical
+ * address of the device tree node pointed at by the phandle property,
+ * or NULL if not found.
+ */
+struct gen_pool *of_get_named_gen_pool(struct device_node *np,
+ const char *propname, int index)
+{
+ struct platform_device *pdev;
+ struct device_node *np_pool;
+
+ np_pool = of_parse_phandle(np, propname, index);
+ if (!np_pool)
+ return NULL;
+ pdev = of_find_device_by_node(np_pool);
+ if (!pdev)
+ return NULL;
+ return dev_get_gen_pool(&pdev->dev);
+}
+EXPORT_SYMBOL_GPL(of_get_named_gen_pool);
+#endif /* CONFIG_OF */
diff --git a/lib/idr.c b/lib/idr.c
index 322e2816f2fb..cca4b9302a71 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -495,6 +495,33 @@ int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask)
}
EXPORT_SYMBOL_GPL(idr_alloc);
+/**
+ * idr_alloc_cyclic - allocate new idr entry in a cyclical fashion
+ * @idr: the (initialized) idr
+ * @ptr: pointer to be associated with the new id
+ * @start: the minimum id (inclusive)
+ * @end: the maximum id (exclusive, <= 0 for max)
+ * @gfp_mask: memory allocation flags
+ *
+ * Essentially the same as idr_alloc, but prefers to allocate progressively
+ * higher ids if it can. If the "cur" counter wraps, then it will start again
+ * at the "start" end of the range and allocate one that has already been used.
+ */
+int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end,
+ gfp_t gfp_mask)
+{
+ int id;
+
+ id = idr_alloc(idr, ptr, max(start, idr->cur), end, gfp_mask);
+ if (id == -ENOSPC)
+ id = idr_alloc(idr, ptr, start, end, gfp_mask);
+
+ if (likely(id >= 0))
+ idr->cur = id + 1;
+ return id;
+}
+EXPORT_SYMBOL(idr_alloc_cyclic);
+
static void idr_remove_warning(int id)
{
printk(KERN_WARNING
diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
index fc2eeb7cb2ea..1ef4cc344977 100644
--- a/lib/int_sqrt.c
+++ b/lib/int_sqrt.c
@@ -1,3 +1,9 @@
+/*
+ * Copyright (C) 2013 Davidlohr Bueso <davidlohr.bueso@hp.com>
+ *
+ * Based on the shift-and-subtract algorithm for computing integer
+ * square root from Guy L. Steele.
+ */
#include <linux/kernel.h>
#include <linux/export.h>
@@ -10,23 +16,23 @@
*/
unsigned long int_sqrt(unsigned long x)
{
- unsigned long op, res, one;
+ unsigned long b, m, y = 0;
- op = x;
- res = 0;
+ if (x <= 1)
+ return x;
- one = 1UL << (BITS_PER_LONG - 2);
- while (one > op)
- one >>= 2;
+ m = 1UL << (BITS_PER_LONG - 2);
+ while (m != 0) {
+ b = y + m;
+ y >>= 1;
- while (one != 0) {
- if (op >= res + one) {
- op = op - (res + one);
- res = res + 2 * one;
+ if (x >= b) {
+ x -= b;
+ y += m;
}
- res /= 2;
- one /= 4;
+ m >>= 2;
}
- return res;
+
+ return y;
}
EXPORT_SYMBOL(int_sqrt);
diff --git a/lib/kobject.c b/lib/kobject.c
index e07ee1fcd6f1..a65486613d79 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -529,6 +529,13 @@ struct kobject *kobject_get(struct kobject *kobj)
return kobj;
}
+static struct kobject *kobject_get_unless_zero(struct kobject *kobj)
+{
+ if (!kref_get_unless_zero(&kobj->kref))
+ kobj = NULL;
+ return kobj;
+}
+
/*
* kobject_cleanup - free kobject resources.
* @kobj: object to cleanup
@@ -751,7 +758,7 @@ struct kobject *kset_find_obj(struct kset *kset, const char *name)
list_for_each_entry(k, &kset->list, entry) {
if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
- ret = kobject_get(k);
+ ret = kobject_get_unless_zero(k);
break;
}
}
diff --git a/lib/list_sort.c b/lib/list_sort.c
index d7325c6b103f..1183fa70a44d 100644
--- a/lib/list_sort.c
+++ b/lib/list_sort.c
@@ -229,7 +229,7 @@ static int __init list_sort_test(void)
goto exit;
}
/* force some equivalencies */
- el->value = random32() % (TEST_LIST_LEN/3);
+ el->value = prandom_u32() % (TEST_LIST_LEN / 3);
el->serial = i;
el->poison1 = TEST_POISON1;
el->poison2 = TEST_POISON2;
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
index af38aedbd874..122f02f9941b 100644
--- a/lib/rbtree_test.c
+++ b/lib/rbtree_test.c
@@ -117,8 +117,7 @@ static int black_path_count(struct rb_node *rb)
static void check(int nr_nodes)
{
struct rb_node *rb;
- int count = 0;
- int blacks = 0;
+ int count = 0, blacks = 0;
u32 prev_key = 0;
for (rb = rb_first(&root); rb; rb = rb_next(rb)) {
@@ -134,7 +133,9 @@ static void check(int nr_nodes)
prev_key = node->key;
count++;
}
+
WARN_ON_ONCE(count != nr_nodes);
+ WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root))) - 1);
}
static void check_augmented(int nr_nodes)
@@ -148,7 +149,7 @@ static void check_augmented(int nr_nodes)
}
}
-static int rbtree_test_init(void)
+static int __init rbtree_test_init(void)
{
int i, j;
cycles_t time1, time2, time;
@@ -221,7 +222,7 @@ static int rbtree_test_init(void)
return -EAGAIN; /* Fail will directly unload the module */
}
-static void rbtree_test_exit(void)
+static void __exit rbtree_test_exit(void)
{
printk(KERN_ALERT "test exit\n");
}
diff --git a/lib/show_mem.c b/lib/show_mem.c
index 4407f8c9b1f7..b7c72311ad0c 100644
--- a/lib/show_mem.c
+++ b/lib/show_mem.c
@@ -18,6 +18,9 @@ void show_mem(unsigned int filter)
printk("Mem-Info:\n");
show_free_areas(filter);
+ if (filter & SHOW_MEM_FILTER_PAGE_COUNT)
+ return;
+
for_each_online_pgdat(pgdat) {
unsigned long i, flags;
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 1cffc223bff5..ed5c1454dd62 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -2,10 +2,12 @@
* Helpers for formatting and printing strings
*
* Copyright 31 August 2008 James Bottomley
+ * Copyright (C) 2013, Intel Corporation
*/
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/export.h>
+#include <linux/ctype.h>
#include <linux/string_helpers.h>
/**
@@ -66,3 +68,134 @@ int string_get_size(u64 size, const enum string_size_units units,
return 0;
}
EXPORT_SYMBOL(string_get_size);
+
+static bool unescape_space(char **src, char **dst)
+{
+ char *p = *dst, *q = *src;
+
+ switch (*q) {
+ case 'n':
+ *p = '\n';
+ break;
+ case 'r':
+ *p = '\r';
+ break;
+ case 't':
+ *p = '\t';
+ break;
+ case 'v':
+ *p = '\v';
+ break;
+ case 'f':
+ *p = '\f';
+ break;
+ default:
+ return false;
+ }
+ *dst += 1;
+ *src += 1;
+ return true;
+}
+
+static bool unescape_octal(char **src, char **dst)
+{
+ char *p = *dst, *q = *src;
+ u8 num;
+
+ if (isodigit(*q) == 0)
+ return false;
+
+ num = (*q++) & 7;
+ while (num < 32 && isodigit(*q) && (q - *src < 3)) {
+ num <<= 3;
+ num += (*q++) & 7;
+ }
+ *p = num;
+ *dst += 1;
+ *src = q;
+ return true;
+}
+
+static bool unescape_hex(char **src, char **dst)
+{
+ char *p = *dst, *q = *src;
+ int digit;
+ u8 num;
+
+ if (*q++ != 'x')
+ return false;
+
+ num = digit = hex_to_bin(*q++);
+ if (digit < 0)
+ return false;
+
+ digit = hex_to_bin(*q);
+ if (digit >= 0) {
+ q++;
+ num = (num << 4) | digit;
+ }
+ *p = num;
+ *dst += 1;
+ *src = q;
+ return true;
+}
+
+static bool unescape_special(char **src, char **dst)
+{
+ char *p = *dst, *q = *src;
+
+ switch (*q) {
+ case '\"':
+ *p = '\"';
+ break;
+ case '\\':
+ *p = '\\';
+ break;
+ case 'a':
+ *p = '\a';
+ break;
+ case 'e':
+ *p = '\e';
+ break;
+ default:
+ return false;
+ }
+ *dst += 1;
+ *src += 1;
+ return true;
+}
+
+int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
+{
+ char *out = dst;
+
+ while (*src && --size) {
+ if (src[0] == '\\' && src[1] != '\0' && size > 1) {
+ src++;
+ size--;
+
+ if (flags & UNESCAPE_SPACE &&
+ unescape_space(&src, &out))
+ continue;
+
+ if (flags & UNESCAPE_OCTAL &&
+ unescape_octal(&src, &out))
+ continue;
+
+ if (flags & UNESCAPE_HEX &&
+ unescape_hex(&src, &out))
+ continue;
+
+ if (flags & UNESCAPE_SPECIAL &&
+ unescape_special(&src, &out))
+ continue;
+
+ *out++ = '\\';
+ }
+ *out++ = *src++;
+ }
+ *out = '\0';
+
+ return out - dst;
+}
+EXPORT_SYMBOL(string_unescape);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index bfe02b8fc55b..d23762e6652c 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -105,9 +105,9 @@ setup_io_tlb_npages(char *str)
if (!strcmp(str, "force"))
swiotlb_force = 1;
- return 1;
+ return 0;
}
-__setup("swiotlb=", setup_io_tlb_npages);
+early_param("swiotlb", setup_io_tlb_npages);
/* make io_tlb_overflow tunable too? */
unsigned long swiotlb_nr_tbl(void)
@@ -115,6 +115,18 @@ unsigned long swiotlb_nr_tbl(void)
return io_tlb_nslabs;
}
EXPORT_SYMBOL_GPL(swiotlb_nr_tbl);
+
+/* default to 64MB */
+#define IO_TLB_DEFAULT_SIZE (64UL<<20)
+unsigned long swiotlb_size_or_default(void)
+{
+ unsigned long size;
+
+ size = io_tlb_nslabs << IO_TLB_SHIFT;
+
+ return size ? size : (IO_TLB_DEFAULT_SIZE);
+}
+
/* Note that this doesn't work with highmem page */
static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
volatile void *address)
@@ -188,8 +200,7 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
void __init
swiotlb_init(int verbose)
{
- /* default to 64MB */
- size_t default_size = 64UL<<20;
+ size_t default_size = IO_TLB_DEFAULT_SIZE;
unsigned char *vstart;
unsigned long bytes;
diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c
new file mode 100644
index 000000000000..6ac48de04c0e
--- /dev/null
+++ b/lib/test-string_helpers.c
@@ -0,0 +1,103 @@
+/*
+ * Test cases for lib/string_helpers.c module.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/string.h>
+#include <linux/string_helpers.h>
+
+struct test_string {
+ const char *in;
+ const char *out;
+ unsigned int flags;
+};
+
+static const struct test_string strings[] __initconst = {
+ {
+ .in = "\\f\\ \\n\\r\\t\\v",
+ .out = "\f\\ \n\r\t\v",
+ .flags = UNESCAPE_SPACE,
+ },
+ {
+ .in = "\\40\\1\\387\\0064\\05\\040\\8a\\110\\777",
+ .out = " \001\00387\0064\005 \\8aH?7",
+ .flags = UNESCAPE_OCTAL,
+ },
+ {
+ .in = "\\xv\\xa\\x2c\\xD\\x6f2",
+ .out = "\\xv\n,\ro2",
+ .flags = UNESCAPE_HEX,
+ },
+ {
+ .in = "\\h\\\\\\\"\\a\\e\\",
+ .out = "\\h\\\"\a\e\\",
+ .flags = UNESCAPE_SPECIAL,
+ },
+};
+
+static void __init test_string_unescape(unsigned int flags, bool inplace)
+{
+ char in[256];
+ char out_test[256];
+ char out_real[256];
+ int i, p = 0, q_test = 0, q_real = sizeof(out_real);
+
+ for (i = 0; i < ARRAY_SIZE(strings); i++) {
+ const char *s = strings[i].in;
+ int len = strlen(strings[i].in);
+
+ /* Copy string to in buffer */
+ memcpy(&in[p], s, len);
+ p += len;
+
+ /* Copy expected result for given flags */
+ if (flags & strings[i].flags) {
+ s = strings[i].out;
+ len = strlen(strings[i].out);
+ }
+ memcpy(&out_test[q_test], s, len);
+ q_test += len;
+ }
+ in[p++] = '\0';
+
+ /* Call string_unescape and compare result */
+ if (inplace) {
+ memcpy(out_real, in, p);
+ if (flags == UNESCAPE_ANY)
+ q_real = string_unescape_any_inplace(out_real);
+ else
+ q_real = string_unescape_inplace(out_real, flags);
+ } else if (flags == UNESCAPE_ANY) {
+ q_real = string_unescape_any(in, out_real, q_real);
+ } else {
+ q_real = string_unescape(in, out_real, q_real, flags);
+ }
+
+ if (q_real != q_test || memcmp(out_test, out_real, q_test)) {
+ pr_warn("Test failed: flags = %u\n", flags);
+ print_hex_dump(KERN_WARNING, "Input: ",
+ DUMP_PREFIX_NONE, 16, 1, in, p - 1, true);
+ print_hex_dump(KERN_WARNING, "Expected: ",
+ DUMP_PREFIX_NONE, 16, 1, out_test, q_test, true);
+ print_hex_dump(KERN_WARNING, "Got: ",
+ DUMP_PREFIX_NONE, 16, 1, out_real, q_real, true);
+ }
+}
+
+static int __init test_string_helpers_init(void)
+{
+ unsigned int i;
+
+ pr_info("Running tests...\n");
+ for (i = 0; i < UNESCAPE_ANY + 1; i++)
+ test_string_unescape(i, false);
+ test_string_unescape(get_random_int() % (UNESCAPE_ANY + 1), true);
+
+ return -EINVAL;
+}
+module_init(test_string_helpers_init);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c
new file mode 100644
index 000000000000..6f500ef2301d
--- /dev/null
+++ b/lib/ucs2_string.c
@@ -0,0 +1,51 @@
+#include <linux/ucs2_string.h>
+#include <linux/module.h>
+
+/* Return the number of unicode characters in data */
+unsigned long
+ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
+{
+ unsigned long length = 0;
+
+ while (*s++ != 0 && length < maxlength)
+ length++;
+ return length;
+}
+EXPORT_SYMBOL(ucs2_strnlen);
+
+unsigned long
+ucs2_strlen(const ucs2_char_t *s)
+{
+ return ucs2_strnlen(s, ~0UL);
+}
+EXPORT_SYMBOL(ucs2_strlen);
+
+/*
+ * Return the number of bytes is the length of this string
+ * Note: this is NOT the same as the number of unicode characters
+ */
+unsigned long
+ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
+{
+ return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
+}
+EXPORT_SYMBOL(ucs2_strsize);
+
+int
+ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
+{
+ while (1) {
+ if (len == 0)
+ return 0;
+ if (*a < *b)
+ return -1;
+ if (*a > *b)
+ return 1;
+ if (*a == 0) /* implies *b == 0 */
+ return 0;
+ a++;
+ b++;
+ len--;
+ }
+}
+EXPORT_SYMBOL(ucs2_strncmp);
diff --git a/arch/sparc/lib/usercopy.c b/lib/usercopy.c
index 5c4284ce1c03..4f5b1ddbcd25 100644
--- a/arch/sparc/lib/usercopy.c
+++ b/lib/usercopy.c
@@ -1,6 +1,6 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
+#include <linux/export.h>
#include <linux/bug.h>
+#include <linux/uaccess.h>
void copy_from_user_overflow(void)
{
diff --git a/lib/uuid.c b/lib/uuid.c
index 52a6fe6387de..398821e4dce1 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -25,13 +25,7 @@
static void __uuid_gen_common(__u8 b[16])
{
- int i;
- u32 r;
-
- for (i = 0; i < 4; i++) {
- r = random32();
- memcpy(b + i * 4, &r, 4);
- }
+ prandom_bytes(b, 16);
/* reversion 0b10 */
b[8] = (b[8] & 0x3F) | 0x80;
}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 0d62fd700f68..e149c6416384 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -534,14 +534,21 @@ char *string(char *buf, char *end, const char *s, struct printf_spec spec)
static noinline_for_stack
char *symbol_string(char *buf, char *end, void *ptr,
- struct printf_spec spec, char ext)
+ struct printf_spec spec, const char *fmt)
{
- unsigned long value = (unsigned long) ptr;
+ unsigned long value;
#ifdef CONFIG_KALLSYMS
char sym[KSYM_SYMBOL_LEN];
- if (ext == 'B')
+#endif
+
+ if (fmt[1] == 'R')
+ ptr = __builtin_extract_return_addr(ptr);
+ value = (unsigned long)ptr;
+
+#ifdef CONFIG_KALLSYMS
+ if (*fmt == 'B')
sprint_backtrace(sym, value);
- else if (ext != 'f' && ext != 's')
+ else if (*fmt != 'f' && *fmt != 's')
sprint_symbol(sym, value);
else
sprint_symbol_no_offset(sym, value);
@@ -987,6 +994,7 @@ int kptr_restrict __read_mostly;
* - 'f' For simple symbolic function names without offset
* - 'S' For symbolic direct pointers with offset
* - 's' For symbolic direct pointers without offset
+ * - '[FfSs]R' as above with __builtin_extract_return_addr() translation
* - 'B' For backtraced symbolic direct pointers with offset
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
@@ -1060,7 +1068,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'S':
case 's':
case 'B':
- return symbol_string(buf, end, ptr, spec, *fmt);
+ return symbol_string(buf, end, ptr, spec, fmt);
case 'R':
case 'r':
return resource_string(buf, end, ptr, spec, fmt);
diff --git a/mm/Kconfig b/mm/Kconfig
index 3bea74f1ccfe..e742d06285b7 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -263,8 +263,14 @@ config ZONE_DMA_FLAG
default "1"
config BOUNCE
- def_bool y
+ bool "Enable bounce buffers"
+ default y
depends on BLOCK && MMU && (ZONE_DMA || HIGHMEM)
+ help
+ Enable bounce buffers for devices that cannot access
+ the full range of memory available to the CPU. Enabled
+ by default when ZONE_DMA or HIGHMEM is selected, but you
+ may say n to override this.
# On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often
# have more than 4GB of memory, but we don't currently use the IOTLB to present
diff --git a/mm/Makefile b/mm/Makefile
index 3a4628751f89..72c5acb9345f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -50,7 +50,7 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
obj-$(CONFIG_QUICKLIST) += quicklist.o
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o
-obj-$(CONFIG_MEMCG) += memcontrol.o page_cgroup.o
+obj-$(CONFIG_MEMCG) += memcontrol.o page_cgroup.o vmpressure.o
obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o
obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
diff --git a/mm/bounce.c b/mm/bounce.c
index 5f8901768602..a5c2ec3589cb 100644
--- a/mm/bounce.c
+++ b/mm/bounce.c
@@ -181,32 +181,13 @@ static void bounce_end_io_read_isa(struct bio *bio, int err)
#ifdef CONFIG_NEED_BOUNCE_POOL
static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio)
{
- struct page *page;
- struct backing_dev_info *bdi;
- struct address_space *mapping;
- struct bio_vec *from;
- int i;
-
if (bio_data_dir(bio) != WRITE)
return 0;
if (!bdi_cap_stable_pages_required(&q->backing_dev_info))
return 0;
- /*
- * Based on the first page that has a valid mapping, decide whether or
- * not we have to employ bounce buffering to guarantee stable pages.
- */
- bio_for_each_segment(from, bio, i) {
- page = from->bv_page;
- mapping = page_mapping(page);
- if (!mapping)
- continue;
- bdi = mapping->backing_dev_info;
- return mapping->host->i_sb->s_flags & MS_SNAP_STABLE;
- }
-
- return 0;
+ return test_bit(BIO_SNAP_STABLE, &bio->bi_flags);
}
#else
static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio)
diff --git a/mm/cleancache.c b/mm/cleancache.c
index d76ba74be2d0..5875f48ce279 100644
--- a/mm/cleancache.c
+++ b/mm/cleancache.c
@@ -19,20 +19,10 @@
#include <linux/cleancache.h>
/*
- * This global enablement flag may be read thousands of times per second
- * by cleancache_get/put/invalidate even on systems where cleancache_ops
- * is not claimed (e.g. cleancache is config'ed on but remains
- * disabled), so is preferred to the slower alternative: a function
- * call that checks a non-global.
- */
-int cleancache_enabled __read_mostly;
-EXPORT_SYMBOL(cleancache_enabled);
-
-/*
* cleancache_ops is set by cleancache_ops_register to contain the pointers
* to the cleancache "backend" implementation functions.
*/
-static struct cleancache_ops cleancache_ops __read_mostly;
+static struct cleancache_ops *cleancache_ops __read_mostly;
/*
* Counters available via /sys/kernel/debug/frontswap (if debugfs is
@@ -45,15 +35,101 @@ static u64 cleancache_puts;
static u64 cleancache_invalidates;
/*
- * register operations for cleancache, returning previous thus allowing
- * detection of multiple backends and possible nesting
+ * When no backend is registered all calls to init_fs and init_shared_fs
+ * are registered and fake poolids (FAKE_FS_POOLID_OFFSET or
+ * FAKE_SHARED_FS_POOLID_OFFSET, plus offset in the respective array
+ * [shared_|]fs_poolid_map) are given to the respective super block
+ * (sb->cleancache_poolid) and no tmem_pools are created. When a backend
+ * registers with cleancache the previous calls to init_fs and init_shared_fs
+ * are executed to create tmem_pools and set the respective poolids. While no
+ * backend is registered all "puts", "gets" and "flushes" are ignored or failed.
+ */
+#define MAX_INITIALIZABLE_FS 32
+#define FAKE_FS_POOLID_OFFSET 1000
+#define FAKE_SHARED_FS_POOLID_OFFSET 2000
+
+#define FS_NO_BACKEND (-1)
+#define FS_UNKNOWN (-2)
+static int fs_poolid_map[MAX_INITIALIZABLE_FS];
+static int shared_fs_poolid_map[MAX_INITIALIZABLE_FS];
+static char *uuids[MAX_INITIALIZABLE_FS];
+/*
+ * Mutex for the [shared_|]fs_poolid_map to guard against multiple threads
+ * invoking umount (and ending in __cleancache_invalidate_fs) and also multiple
+ * threads calling mount (and ending up in __cleancache_init_[shared|]fs).
+ */
+static DEFINE_MUTEX(poolid_mutex);
+/*
+ * When set to false (default) all calls to the cleancache functions, except
+ * the __cleancache_invalidate_fs and __cleancache_init_[shared|]fs are guarded
+ * by the if (!cleancache_ops) return. This means multiple threads (from
+ * different filesystems) will be checking cleancache_ops. The usage of a
+ * bool instead of a atomic_t or a bool guarded by a spinlock is OK - we are
+ * OK if the time between the backend's have been initialized (and
+ * cleancache_ops has been set to not NULL) and when the filesystems start
+ * actually calling the backends. The inverse (when unloading) is obviously
+ * not good - but this shim does not do that (yet).
+ */
+
+/*
+ * The backends and filesystems work all asynchronously. This is b/c the
+ * backends can be built as modules.
+ * The usual sequence of events is:
+ * a) mount / -> __cleancache_init_fs is called. We set the
+ * [shared_|]fs_poolid_map and uuids for.
+ *
+ * b). user does I/Os -> we call the rest of __cleancache_* functions
+ * which return immediately as cleancache_ops is false.
+ *
+ * c). modprobe zcache -> cleancache_register_ops. We init the backend
+ * and set cleancache_ops to true, and for any fs_poolid_map
+ * (which is set by __cleancache_init_fs) we initialize the poolid.
+ *
+ * d). user does I/Os -> now that cleancache_ops is true all the
+ * __cleancache_* functions can call the backend. They all check
+ * that fs_poolid_map is valid and if so invoke the backend.
+ *
+ * e). umount / -> __cleancache_invalidate_fs, the fs_poolid_map is
+ * reset (which is the second check in the __cleancache_* ops
+ * to call the backend).
+ *
+ * The sequence of event could also be c), followed by a), and d). and e). The
+ * c) would not happen anymore. There is also the chance of c), and one thread
+ * doing a) + d), and another doing e). For that case we depend on the
+ * filesystem calling __cleancache_invalidate_fs in the proper sequence (so
+ * that it handles all I/Os before it invalidates the fs (which is last part
+ * of unmounting process).
+ *
+ * Note: The acute reader will notice that there is no "rmmod zcache" case.
+ * This is b/c the functionality for that is not yet implemented and when
+ * done, will require some extra locking not yet devised.
+ */
+
+/*
+ * Register operations for cleancache, returning previous thus allowing
+ * detection of multiple backends and possible nesting.
*/
-struct cleancache_ops cleancache_register_ops(struct cleancache_ops *ops)
+struct cleancache_ops *cleancache_register_ops(struct cleancache_ops *ops)
{
- struct cleancache_ops old = cleancache_ops;
+ struct cleancache_ops *old = cleancache_ops;
+ int i;
- cleancache_ops = *ops;
- cleancache_enabled = 1;
+ mutex_lock(&poolid_mutex);
+ for (i = 0; i < MAX_INITIALIZABLE_FS; i++) {
+ if (fs_poolid_map[i] == FS_NO_BACKEND)
+ fs_poolid_map[i] = ops->init_fs(PAGE_SIZE);
+ if (shared_fs_poolid_map[i] == FS_NO_BACKEND)
+ shared_fs_poolid_map[i] = ops->init_shared_fs
+ (uuids[i], PAGE_SIZE);
+ }
+ /*
+ * We MUST set cleancache_ops _after_ we have called the backends
+ * init_fs or init_shared_fs functions. Otherwise the compiler might
+ * re-order where cleancache_ops is set in this function.
+ */
+ barrier();
+ cleancache_ops = ops;
+ mutex_unlock(&poolid_mutex);
return old;
}
EXPORT_SYMBOL(cleancache_register_ops);
@@ -61,15 +137,42 @@ EXPORT_SYMBOL(cleancache_register_ops);
/* Called by a cleancache-enabled filesystem at time of mount */
void __cleancache_init_fs(struct super_block *sb)
{
- sb->cleancache_poolid = (*cleancache_ops.init_fs)(PAGE_SIZE);
+ int i;
+
+ mutex_lock(&poolid_mutex);
+ for (i = 0; i < MAX_INITIALIZABLE_FS; i++) {
+ if (fs_poolid_map[i] == FS_UNKNOWN) {
+ sb->cleancache_poolid = i + FAKE_FS_POOLID_OFFSET;
+ if (cleancache_ops)
+ fs_poolid_map[i] = cleancache_ops->init_fs(PAGE_SIZE);
+ else
+ fs_poolid_map[i] = FS_NO_BACKEND;
+ break;
+ }
+ }
+ mutex_unlock(&poolid_mutex);
}
EXPORT_SYMBOL(__cleancache_init_fs);
/* Called by a cleancache-enabled clustered filesystem at time of mount */
void __cleancache_init_shared_fs(char *uuid, struct super_block *sb)
{
- sb->cleancache_poolid =
- (*cleancache_ops.init_shared_fs)(uuid, PAGE_SIZE);
+ int i;
+
+ mutex_lock(&poolid_mutex);
+ for (i = 0; i < MAX_INITIALIZABLE_FS; i++) {
+ if (shared_fs_poolid_map[i] == FS_UNKNOWN) {
+ sb->cleancache_poolid = i + FAKE_SHARED_FS_POOLID_OFFSET;
+ uuids[i] = uuid;
+ if (cleancache_ops)
+ shared_fs_poolid_map[i] = cleancache_ops->init_shared_fs
+ (uuid, PAGE_SIZE);
+ else
+ shared_fs_poolid_map[i] = FS_NO_BACKEND;
+ break;
+ }
+ }
+ mutex_unlock(&poolid_mutex);
}
EXPORT_SYMBOL(__cleancache_init_shared_fs);
@@ -99,27 +202,53 @@ static int cleancache_get_key(struct inode *inode,
}
/*
+ * Returns a pool_id that is associated with a given fake poolid.
+ */
+static int get_poolid_from_fake(int fake_pool_id)
+{
+ if (fake_pool_id >= FAKE_SHARED_FS_POOLID_OFFSET)
+ return shared_fs_poolid_map[fake_pool_id -
+ FAKE_SHARED_FS_POOLID_OFFSET];
+ else if (fake_pool_id >= FAKE_FS_POOLID_OFFSET)
+ return fs_poolid_map[fake_pool_id - FAKE_FS_POOLID_OFFSET];
+ return FS_NO_BACKEND;
+}
+
+/*
* "Get" data from cleancache associated with the poolid/inode/index
* that were specified when the data was put to cleanache and, if
* successful, use it to fill the specified page with data and return 0.
* The pageframe is unchanged and returns -1 if the get fails.
* Page must be locked by caller.
+ *
+ * The function has two checks before any action is taken - whether
+ * a backend is registered and whether the sb->cleancache_poolid
+ * is correct.
*/
int __cleancache_get_page(struct page *page)
{
int ret = -1;
int pool_id;
+ int fake_pool_id;
struct cleancache_filekey key = { .u.key = { 0 } };
+ if (!cleancache_ops) {
+ cleancache_failed_gets++;
+ goto out;
+ }
+
VM_BUG_ON(!PageLocked(page));
- pool_id = page->mapping->host->i_sb->cleancache_poolid;
- if (pool_id < 0)
+ fake_pool_id = page->mapping->host->i_sb->cleancache_poolid;
+ if (fake_pool_id < 0)
goto out;
+ pool_id = get_poolid_from_fake(fake_pool_id);
if (cleancache_get_key(page->mapping->host, &key) < 0)
goto out;
- ret = (*cleancache_ops.get_page)(pool_id, key, page->index, page);
+ if (pool_id >= 0)
+ ret = cleancache_ops->get_page(pool_id,
+ key, page->index, page);
if (ret == 0)
cleancache_succ_gets++;
else
@@ -134,17 +263,32 @@ EXPORT_SYMBOL(__cleancache_get_page);
* (previously-obtained per-filesystem) poolid and the page's,
* inode and page index. Page must be locked. Note that a put_page
* always "succeeds", though a subsequent get_page may succeed or fail.
+ *
+ * The function has two checks before any action is taken - whether
+ * a backend is registered and whether the sb->cleancache_poolid
+ * is correct.
*/
void __cleancache_put_page(struct page *page)
{
int pool_id;
+ int fake_pool_id;
struct cleancache_filekey key = { .u.key = { 0 } };
+ if (!cleancache_ops) {
+ cleancache_puts++;
+ return;
+ }
+
VM_BUG_ON(!PageLocked(page));
- pool_id = page->mapping->host->i_sb->cleancache_poolid;
+ fake_pool_id = page->mapping->host->i_sb->cleancache_poolid;
+ if (fake_pool_id < 0)
+ return;
+
+ pool_id = get_poolid_from_fake(fake_pool_id);
+
if (pool_id >= 0 &&
- cleancache_get_key(page->mapping->host, &key) >= 0) {
- (*cleancache_ops.put_page)(pool_id, key, page->index, page);
+ cleancache_get_key(page->mapping->host, &key) >= 0) {
+ cleancache_ops->put_page(pool_id, key, page->index, page);
cleancache_puts++;
}
}
@@ -153,19 +297,31 @@ EXPORT_SYMBOL(__cleancache_put_page);
/*
* Invalidate any data from cleancache associated with the poolid and the
* page's inode and page index so that a subsequent "get" will fail.
+ *
+ * The function has two checks before any action is taken - whether
+ * a backend is registered and whether the sb->cleancache_poolid
+ * is correct.
*/
void __cleancache_invalidate_page(struct address_space *mapping,
struct page *page)
{
/* careful... page->mapping is NULL sometimes when this is called */
- int pool_id = mapping->host->i_sb->cleancache_poolid;
+ int pool_id;
+ int fake_pool_id = mapping->host->i_sb->cleancache_poolid;
struct cleancache_filekey key = { .u.key = { 0 } };
- if (pool_id >= 0) {
+ if (!cleancache_ops)
+ return;
+
+ if (fake_pool_id >= 0) {
+ pool_id = get_poolid_from_fake(fake_pool_id);
+ if (pool_id < 0)
+ return;
+
VM_BUG_ON(!PageLocked(page));
if (cleancache_get_key(mapping->host, &key) >= 0) {
- (*cleancache_ops.invalidate_page)(pool_id,
- key, page->index);
+ cleancache_ops->invalidate_page(pool_id,
+ key, page->index);
cleancache_invalidates++;
}
}
@@ -176,34 +332,63 @@ EXPORT_SYMBOL(__cleancache_invalidate_page);
* Invalidate all data from cleancache associated with the poolid and the
* mappings's inode so that all subsequent gets to this poolid/inode
* will fail.
+ *
+ * The function has two checks before any action is taken - whether
+ * a backend is registered and whether the sb->cleancache_poolid
+ * is correct.
*/
void __cleancache_invalidate_inode(struct address_space *mapping)
{
- int pool_id = mapping->host->i_sb->cleancache_poolid;
+ int pool_id;
+ int fake_pool_id = mapping->host->i_sb->cleancache_poolid;
struct cleancache_filekey key = { .u.key = { 0 } };
+ if (!cleancache_ops)
+ return;
+
+ if (fake_pool_id < 0)
+ return;
+
+ pool_id = get_poolid_from_fake(fake_pool_id);
+
if (pool_id >= 0 && cleancache_get_key(mapping->host, &key) >= 0)
- (*cleancache_ops.invalidate_inode)(pool_id, key);
+ cleancache_ops->invalidate_inode(pool_id, key);
}
EXPORT_SYMBOL(__cleancache_invalidate_inode);
/*
* Called by any cleancache-enabled filesystem at time of unmount;
- * note that pool_id is surrendered and may be reutrned by a subsequent
- * cleancache_init_fs or cleancache_init_shared_fs
+ * note that pool_id is surrendered and may be returned by a subsequent
+ * cleancache_init_fs or cleancache_init_shared_fs.
*/
void __cleancache_invalidate_fs(struct super_block *sb)
{
- if (sb->cleancache_poolid >= 0) {
- int old_poolid = sb->cleancache_poolid;
- sb->cleancache_poolid = -1;
- (*cleancache_ops.invalidate_fs)(old_poolid);
+ int index;
+ int fake_pool_id = sb->cleancache_poolid;
+ int old_poolid = fake_pool_id;
+
+ mutex_lock(&poolid_mutex);
+ if (fake_pool_id >= FAKE_SHARED_FS_POOLID_OFFSET) {
+ index = fake_pool_id - FAKE_SHARED_FS_POOLID_OFFSET;
+ old_poolid = shared_fs_poolid_map[index];
+ shared_fs_poolid_map[index] = FS_UNKNOWN;
+ uuids[index] = NULL;
+ } else if (fake_pool_id >= FAKE_FS_POOLID_OFFSET) {
+ index = fake_pool_id - FAKE_FS_POOLID_OFFSET;
+ old_poolid = fs_poolid_map[index];
+ fs_poolid_map[index] = FS_UNKNOWN;
}
+ sb->cleancache_poolid = -1;
+ if (cleancache_ops)
+ cleancache_ops->invalidate_fs(old_poolid);
+ mutex_unlock(&poolid_mutex);
}
EXPORT_SYMBOL(__cleancache_invalidate_fs);
static int __init init_cleancache(void)
{
+ int i;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *root = debugfs_create_dir("cleancache", NULL);
if (root == NULL)
@@ -215,6 +400,10 @@ static int __init init_cleancache(void)
debugfs_create_u64("invalidates", S_IRUGO,
root, &cleancache_invalidates);
#endif
+ for (i = 0; i < MAX_INITIALIZABLE_FS; i++) {
+ fs_poolid_map[i] = FS_UNKNOWN;
+ shared_fs_poolid_map[i] = FS_UNKNOWN;
+ }
return 0;
}
module_init(init_cleancache)
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 7e092689a12a..3bcfd81db45e 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -25,7 +25,7 @@
* POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
* deactivate the pages and clear PG_Referenced.
*/
-SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
+SYSCALL_DEFINE4(fadvise64_64, int, fd, loff_t, offset, loff_t, len, int, advice)
{
struct fd f = fdget(fd);
struct address_space *mapping;
@@ -145,26 +145,12 @@ out:
fdput(f);
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice)
-{
- return SYSC_fadvise64_64((int) fd, offset, len, (int) advice);
-}
-SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64);
-#endif
#ifdef __ARCH_WANT_SYS_FADVISE64
-SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice)
+SYSCALL_DEFINE4(fadvise64, int, fd, loff_t, offset, size_t, len, int, advice)
{
return sys_fadvise64_64(fd, offset, len, advice);
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice)
-{
- return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice);
-}
-SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64);
-#endif
#endif
diff --git a/mm/filemap.c b/mm/filemap.c
index cbde8842a374..7905fe721aa8 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -35,6 +35,9 @@
#include <linux/cleancache.h>
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/filemap.h>
+
/*
* FIXME: remove all knowledge of the buffer layer from the core VM
*/
@@ -113,6 +116,7 @@ void __delete_from_page_cache(struct page *page)
{
struct address_space *mapping = page->mapping;
+ trace_mm_filemap_delete_from_page_cache(page);
/*
* if we're uptodate, flush out into the cleancache, otherwise
* invalidate any existing cleancache entries. We can't leave
@@ -184,6 +188,17 @@ static int sleep_on_page_killable(void *word)
return fatal_signal_pending(current) ? -EINTR : 0;
}
+static int filemap_check_errors(struct address_space *mapping)
+{
+ int ret = 0;
+ /* Check for outstanding write errors */
+ if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
+ ret = -ENOSPC;
+ if (test_and_clear_bit(AS_EIO, &mapping->flags))
+ ret = -EIO;
+ return ret;
+}
+
/**
* __filemap_fdatawrite_range - start writeback on mapping dirty pages in range
* @mapping: address space structure to write
@@ -265,10 +280,10 @@ int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
pgoff_t end = end_byte >> PAGE_CACHE_SHIFT;
struct pagevec pvec;
int nr_pages;
- int ret = 0;
+ int ret2, ret = 0;
if (end_byte < start_byte)
- return 0;
+ goto out;
pagevec_init(&pvec, 0);
while ((index <= end) &&
@@ -291,12 +306,10 @@ int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
pagevec_release(&pvec);
cond_resched();
}
-
- /* Check for outstanding write errors */
- if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
- ret = -ENOSPC;
- if (test_and_clear_bit(AS_EIO, &mapping->flags))
- ret = -EIO;
+out:
+ ret2 = filemap_check_errors(mapping);
+ if (!ret)
+ ret = ret2;
return ret;
}
@@ -337,6 +350,8 @@ int filemap_write_and_wait(struct address_space *mapping)
if (!err)
err = err2;
}
+ } else {
+ err = filemap_check_errors(mapping);
}
return err;
}
@@ -368,6 +383,8 @@ int filemap_write_and_wait_range(struct address_space *mapping,
if (!err)
err = err2;
}
+ } else {
+ err = filemap_check_errors(mapping);
}
return err;
}
@@ -464,6 +481,7 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
mapping->nrpages++;
__inc_zone_page_state(page, NR_FILE_PAGES);
spin_unlock_irq(&mapping->tree_lock);
+ trace_mm_filemap_add_to_page_cache(page);
} else {
page->mapping = NULL;
/* Leave page->index set: truncation relies upon it */
diff --git a/mm/fremap.c b/mm/fremap.c
index 4723ac8d2fc2..87da3590c61e 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -204,10 +204,8 @@ get_write_lock:
unsigned long addr;
struct file *file = get_file(vma->vm_file);
- vm_flags = vma->vm_flags;
- if (!(flags & MAP_NONBLOCK))
- vm_flags |= VM_POPULATE;
- addr = mmap_region(file, start, size, vm_flags, pgoff);
+ addr = mmap_region(file, start, size,
+ vma->vm_flags, pgoff);
fput(file);
if (IS_ERR_VALUE(addr)) {
err = addr;
@@ -226,12 +224,6 @@ get_write_lock:
mutex_unlock(&mapping->i_mmap_mutex);
}
- if (!(flags & MAP_NONBLOCK) && !(vma->vm_flags & VM_POPULATE)) {
- if (!has_write_lock)
- goto get_write_lock;
- vma->vm_flags |= VM_POPULATE;
- }
-
if (vma->vm_flags & VM_LOCKED) {
/*
* drop PG_Mlocked flag for over-mapped range
diff --git a/mm/frontswap.c b/mm/frontswap.c
index 2890e67d6026..538367ef1372 100644
--- a/mm/frontswap.c
+++ b/mm/frontswap.c
@@ -24,15 +24,7 @@
* frontswap_ops is set by frontswap_register_ops to contain the pointers
* to the frontswap "backend" implementation functions.
*/
-static struct frontswap_ops frontswap_ops __read_mostly;
-
-/*
- * This global enablement flag reduces overhead on systems where frontswap_ops
- * has not been registered, so is preferred to the slower alternative: a
- * function call that checks a non-global.
- */
-bool frontswap_enabled __read_mostly;
-EXPORT_SYMBOL(frontswap_enabled);
+static struct frontswap_ops *frontswap_ops __read_mostly;
/*
* If enabled, frontswap_store will return failure even on success. As
@@ -80,16 +72,70 @@ static inline void inc_frontswap_succ_stores(void) { }
static inline void inc_frontswap_failed_stores(void) { }
static inline void inc_frontswap_invalidates(void) { }
#endif
+
+/*
+ * Due to the asynchronous nature of the backends loading potentially
+ * _after_ the swap system has been activated, we have chokepoints
+ * on all frontswap functions to not call the backend until the backend
+ * has registered.
+ *
+ * Specifically when no backend is registered (nobody called
+ * frontswap_register_ops) all calls to frontswap_init (which is done via
+ * swapon -> enable_swap_info -> frontswap_init) are registered and remembered
+ * (via the setting of need_init bitmap) but fail to create tmem_pools. When a
+ * backend registers with frontswap at some later point the previous
+ * calls to frontswap_init are executed (by iterating over the need_init
+ * bitmap) to create tmem_pools and set the respective poolids. All of that is
+ * guarded by us using atomic bit operations on the 'need_init' bitmap.
+ *
+ * This would not guards us against the user deciding to call swapoff right as
+ * we are calling the backend to initialize (so swapon is in action).
+ * Fortunatly for us, the swapon_mutex has been taked by the callee so we are
+ * OK. The other scenario where calls to frontswap_store (called via
+ * swap_writepage) is racing with frontswap_invalidate_area (called via
+ * swapoff) is again guarded by the swap subsystem.
+ *
+ * While no backend is registered all calls to frontswap_[store|load|
+ * invalidate_area|invalidate_page] are ignored or fail.
+ *
+ * The time between the backend being registered and the swap file system
+ * calling the backend (via the frontswap_* functions) is indeterminate as
+ * frontswap_ops is not atomic_t (or a value guarded by a spinlock).
+ * That is OK as we are comfortable missing some of these calls to the newly
+ * registered backend.
+ *
+ * Obviously the opposite (unloading the backend) must be done after all
+ * the frontswap_[store|load|invalidate_area|invalidate_page] start
+ * ignorning or failing the requests - at which point frontswap_ops
+ * would have to be made in some fashion atomic.
+ */
+static DECLARE_BITMAP(need_init, MAX_SWAPFILES);
+
/*
* Register operations for frontswap, returning previous thus allowing
* detection of multiple backends and possible nesting.
*/
-struct frontswap_ops frontswap_register_ops(struct frontswap_ops *ops)
+struct frontswap_ops *frontswap_register_ops(struct frontswap_ops *ops)
{
- struct frontswap_ops old = frontswap_ops;
-
- frontswap_ops = *ops;
- frontswap_enabled = true;
+ struct frontswap_ops *old = frontswap_ops;
+ int i;
+
+ for (i = 0; i < MAX_SWAPFILES; i++) {
+ if (test_and_clear_bit(i, need_init)) {
+ struct swap_info_struct *sis = swap_info[i];
+ /* __frontswap_init _should_ have set it! */
+ if (!sis->frontswap_map)
+ return ERR_PTR(-EINVAL);
+ ops->init(i);
+ }
+ }
+ /*
+ * We MUST have frontswap_ops set _after_ the frontswap_init's
+ * have been called. Otherwise __frontswap_store might fail. Hence
+ * the barrier to make sure compiler does not re-order us.
+ */
+ barrier();
+ frontswap_ops = ops;
return old;
}
EXPORT_SYMBOL(frontswap_register_ops);
@@ -115,20 +161,48 @@ EXPORT_SYMBOL(frontswap_tmem_exclusive_gets);
/*
* Called when a swap device is swapon'd.
*/
-void __frontswap_init(unsigned type)
+void __frontswap_init(unsigned type, unsigned long *map)
{
struct swap_info_struct *sis = swap_info[type];
BUG_ON(sis == NULL);
- if (sis->frontswap_map == NULL)
+
+ /*
+ * p->frontswap is a bitmap that we MUST have to figure out which page
+ * has gone in frontswap. Without it there is no point of continuing.
+ */
+ if (WARN_ON(!map))
return;
- frontswap_ops.init(type);
+ /*
+ * Irregardless of whether the frontswap backend has been loaded
+ * before this function or it will be later, we _MUST_ have the
+ * p->frontswap set to something valid to work properly.
+ */
+ frontswap_map_set(sis, map);
+ if (frontswap_ops)
+ frontswap_ops->init(type);
+ else {
+ BUG_ON(type > MAX_SWAPFILES);
+ set_bit(type, need_init);
+ }
}
EXPORT_SYMBOL(__frontswap_init);
-static inline void __frontswap_clear(struct swap_info_struct *sis, pgoff_t offset)
+bool __frontswap_test(struct swap_info_struct *sis,
+ pgoff_t offset)
+{
+ bool ret = false;
+
+ if (frontswap_ops && sis->frontswap_map)
+ ret = test_bit(offset, sis->frontswap_map);
+ return ret;
+}
+EXPORT_SYMBOL(__frontswap_test);
+
+static inline void __frontswap_clear(struct swap_info_struct *sis,
+ pgoff_t offset)
{
- frontswap_clear(sis, offset);
+ clear_bit(offset, sis->frontswap_map);
atomic_dec(&sis->frontswap_pages);
}
@@ -147,13 +221,20 @@ int __frontswap_store(struct page *page)
struct swap_info_struct *sis = swap_info[type];
pgoff_t offset = swp_offset(entry);
+ /*
+ * Return if no backend registed.
+ * Don't need to inc frontswap_failed_stores here.
+ */
+ if (!frontswap_ops)
+ return ret;
+
BUG_ON(!PageLocked(page));
BUG_ON(sis == NULL);
- if (frontswap_test(sis, offset))
+ if (__frontswap_test(sis, offset))
dup = 1;
- ret = frontswap_ops.store(type, offset, page);
+ ret = frontswap_ops->store(type, offset, page);
if (ret == 0) {
- frontswap_set(sis, offset);
+ set_bit(offset, sis->frontswap_map);
inc_frontswap_succ_stores();
if (!dup)
atomic_inc(&sis->frontswap_pages);
@@ -188,13 +269,16 @@ int __frontswap_load(struct page *page)
BUG_ON(!PageLocked(page));
BUG_ON(sis == NULL);
- if (frontswap_test(sis, offset))
- ret = frontswap_ops.load(type, offset, page);
+ /*
+ * __frontswap_test() will check whether there is backend registered
+ */
+ if (__frontswap_test(sis, offset))
+ ret = frontswap_ops->load(type, offset, page);
if (ret == 0) {
inc_frontswap_loads();
if (frontswap_tmem_exclusive_gets_enabled) {
SetPageDirty(page);
- frontswap_clear(sis, offset);
+ __frontswap_clear(sis, offset);
}
}
return ret;
@@ -210,8 +294,11 @@ void __frontswap_invalidate_page(unsigned type, pgoff_t offset)
struct swap_info_struct *sis = swap_info[type];
BUG_ON(sis == NULL);
- if (frontswap_test(sis, offset)) {
- frontswap_ops.invalidate_page(type, offset);
+ /*
+ * __frontswap_test() will check whether there is backend registered
+ */
+ if (__frontswap_test(sis, offset)) {
+ frontswap_ops->invalidate_page(type, offset);
__frontswap_clear(sis, offset);
inc_frontswap_invalidates();
}
@@ -226,12 +313,15 @@ void __frontswap_invalidate_area(unsigned type)
{
struct swap_info_struct *sis = swap_info[type];
- BUG_ON(sis == NULL);
- if (sis->frontswap_map == NULL)
- return;
- frontswap_ops.invalidate_area(type);
- atomic_set(&sis->frontswap_pages, 0);
- memset(sis->frontswap_map, 0, sis->max / sizeof(long));
+ if (frontswap_ops) {
+ BUG_ON(sis == NULL);
+ if (sis->frontswap_map == NULL)
+ return;
+ frontswap_ops->invalidate_area(type);
+ atomic_set(&sis->frontswap_pages, 0);
+ memset(sis->frontswap_map, 0, sis->max / sizeof(long));
+ }
+ clear_bit(type, need_init);
}
EXPORT_SYMBOL(__frontswap_invalidate_area);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e2f7f5aaaafb..03a89a2f464b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -163,35 +163,34 @@ static int start_khugepaged(void)
}
static atomic_t huge_zero_refcount;
-static unsigned long huge_zero_pfn __read_mostly;
+static struct page *huge_zero_page __read_mostly;
-static inline bool is_huge_zero_pfn(unsigned long pfn)
+static inline bool is_huge_zero_page(struct page *page)
{
- unsigned long zero_pfn = ACCESS_ONCE(huge_zero_pfn);
- return zero_pfn && pfn == zero_pfn;
+ return ACCESS_ONCE(huge_zero_page) == page;
}
static inline bool is_huge_zero_pmd(pmd_t pmd)
{
- return is_huge_zero_pfn(pmd_pfn(pmd));
+ return is_huge_zero_page(pmd_page(pmd));
}
-static unsigned long get_huge_zero_page(void)
+static struct page *get_huge_zero_page(void)
{
struct page *zero_page;
retry:
if (likely(atomic_inc_not_zero(&huge_zero_refcount)))
- return ACCESS_ONCE(huge_zero_pfn);
+ return ACCESS_ONCE(huge_zero_page);
zero_page = alloc_pages((GFP_TRANSHUGE | __GFP_ZERO) & ~__GFP_MOVABLE,
HPAGE_PMD_ORDER);
if (!zero_page) {
count_vm_event(THP_ZERO_PAGE_ALLOC_FAILED);
- return 0;
+ return NULL;
}
count_vm_event(THP_ZERO_PAGE_ALLOC);
preempt_disable();
- if (cmpxchg(&huge_zero_pfn, 0, page_to_pfn(zero_page))) {
+ if (cmpxchg(&huge_zero_page, NULL, zero_page)) {
preempt_enable();
__free_page(zero_page);
goto retry;
@@ -200,7 +199,7 @@ retry:
/* We take additional reference here. It will be put back by shrinker */
atomic_set(&huge_zero_refcount, 2);
preempt_enable();
- return ACCESS_ONCE(huge_zero_pfn);
+ return ACCESS_ONCE(huge_zero_page);
}
static void put_huge_zero_page(void)
@@ -220,9 +219,9 @@ static int shrink_huge_zero_page(struct shrinker *shrink,
return atomic_read(&huge_zero_refcount) == 1 ? HPAGE_PMD_NR : 0;
if (atomic_cmpxchg(&huge_zero_refcount, 1, 0) == 1) {
- unsigned long zero_pfn = xchg(&huge_zero_pfn, 0);
- BUG_ON(zero_pfn == 0);
- __free_page(__pfn_to_page(zero_pfn));
+ struct page *zero_page = xchg(&huge_zero_page, NULL);
+ BUG_ON(zero_page == NULL);
+ __free_page(zero_page);
}
return 0;
@@ -713,6 +712,11 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
return VM_FAULT_OOM;
clear_huge_page(page, haddr, HPAGE_PMD_NR);
+ /*
+ * The memory barrier inside __SetPageUptodate makes sure that
+ * clear_huge_page writes become visible before the set_pmd_at()
+ * write.
+ */
__SetPageUptodate(page);
spin_lock(&mm->page_table_lock);
@@ -724,12 +728,6 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
} else {
pmd_t entry;
entry = mk_huge_pmd(page, vma);
- /*
- * The spinlocking to take the lru_lock inside
- * page_add_new_anon_rmap() acts as a full memory
- * barrier to be sure clear_huge_page writes become
- * visible after the set_pmd_at() write.
- */
page_add_new_anon_rmap(page, vma, haddr);
set_pmd_at(mm, haddr, pmd, entry);
pgtable_trans_huge_deposit(mm, pgtable);
@@ -765,12 +763,12 @@ static inline struct page *alloc_hugepage(int defrag)
static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm,
struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd,
- unsigned long zero_pfn)
+ struct page *zero_page)
{
pmd_t entry;
if (!pmd_none(*pmd))
return false;
- entry = pfn_pmd(zero_pfn, vma->vm_page_prot);
+ entry = mk_pmd(zero_page, vma->vm_page_prot);
entry = pmd_wrprotect(entry);
entry = pmd_mkhuge(entry);
set_pmd_at(mm, haddr, pmd, entry);
@@ -795,20 +793,20 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
if (!(flags & FAULT_FLAG_WRITE) &&
transparent_hugepage_use_zero_page()) {
pgtable_t pgtable;
- unsigned long zero_pfn;
+ struct page *zero_page;
bool set;
pgtable = pte_alloc_one(mm, haddr);
if (unlikely(!pgtable))
return VM_FAULT_OOM;
- zero_pfn = get_huge_zero_page();
- if (unlikely(!zero_pfn)) {
+ zero_page = get_huge_zero_page();
+ if (unlikely(!zero_page)) {
pte_free(mm, pgtable);
count_vm_event(THP_FAULT_FALLBACK);
goto out;
}
spin_lock(&mm->page_table_lock);
set = set_huge_zero_page(pgtable, mm, vma, haddr, pmd,
- zero_pfn);
+ zero_page);
spin_unlock(&mm->page_table_lock);
if (!set) {
pte_free(mm, pgtable);
@@ -887,16 +885,16 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
* a page table.
*/
if (is_huge_zero_pmd(pmd)) {
- unsigned long zero_pfn;
+ struct page *zero_page;
bool set;
/*
* get_huge_zero_page() will never allocate a new page here,
* since we already have a zero page to copy. It just takes a
* reference.
*/
- zero_pfn = get_huge_zero_page();
+ zero_page = get_huge_zero_page();
set = set_huge_zero_page(pgtable, dst_mm, vma, addr, dst_pmd,
- zero_pfn);
+ zero_page);
BUG_ON(!set); /* unexpected !pmd_none(dst_pmd) */
ret = 0;
goto out_unlock;
@@ -1560,7 +1558,8 @@ static int __split_huge_page_splitting(struct page *page,
return ret;
}
-static void __split_huge_page_refcount(struct page *page)
+static void __split_huge_page_refcount(struct page *page,
+ struct list_head *list)
{
int i;
struct zone *zone = page_zone(page);
@@ -1646,7 +1645,7 @@ static void __split_huge_page_refcount(struct page *page)
BUG_ON(!PageDirty(page_tail));
BUG_ON(!PageSwapBacked(page_tail));
- lru_add_page_tail(page, page_tail, lruvec);
+ lru_add_page_tail(page, page_tail, lruvec, list);
}
atomic_sub(tail_count, &page->_count);
BUG_ON(atomic_read(&page->_count) <= 0);
@@ -1753,7 +1752,8 @@ static int __split_huge_page_map(struct page *page,
/* must be called with anon_vma->root->rwsem held */
static void __split_huge_page(struct page *page,
- struct anon_vma *anon_vma)
+ struct anon_vma *anon_vma,
+ struct list_head *list)
{
int mapcount, mapcount2;
pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
@@ -1784,7 +1784,7 @@ static void __split_huge_page(struct page *page,
mapcount, page_mapcount(page));
BUG_ON(mapcount != page_mapcount(page));
- __split_huge_page_refcount(page);
+ __split_huge_page_refcount(page, list);
mapcount2 = 0;
anon_vma_interval_tree_foreach(avc, &anon_vma->rb_root, pgoff, pgoff) {
@@ -1799,12 +1799,19 @@ static void __split_huge_page(struct page *page,
BUG_ON(mapcount != mapcount2);
}
-int split_huge_page(struct page *page)
+/*
+ * Split a hugepage into normal pages. This doesn't change the position of head
+ * page. If @list is null, tail pages will be added to LRU list, otherwise, to
+ * @list. Both head page and tail pages will inherit mapping, flags, and so on
+ * from the hugepage.
+ * Return 0 if the hugepage is split successfully otherwise return 1.
+ */
+int split_huge_page_to_list(struct page *page, struct list_head *list)
{
struct anon_vma *anon_vma;
int ret = 1;
- BUG_ON(is_huge_zero_pfn(page_to_pfn(page)));
+ BUG_ON(is_huge_zero_page(page));
BUG_ON(!PageAnon(page));
/*
@@ -1824,7 +1831,7 @@ int split_huge_page(struct page *page)
goto out_unlock;
BUG_ON(!PageSwapBacked(page));
- __split_huge_page(page, anon_vma);
+ __split_huge_page(page, anon_vma, list);
count_vm_event(THP_SPLIT);
BUG_ON(PageCompound(page));
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ca9a7c6d7e97..f8feeeca6686 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1761,7 +1761,7 @@ static struct hstate *kobj_to_node_hstate(struct kobject *kobj, int *nidp)
* Unregister hstate attributes from a single node device.
* No-op if no hstate attributes attached.
*/
-void hugetlb_unregister_node(struct node *node)
+static void hugetlb_unregister_node(struct node *node)
{
struct hstate *h;
struct node_hstate *nhs = &node_hstates[node->dev.id];
@@ -1805,7 +1805,7 @@ static void hugetlb_unregister_all_nodes(void)
* Register hstate attributes for a single node device.
* No-op if attributes already registered.
*/
-void hugetlb_register_node(struct node *node)
+static void hugetlb_register_node(struct node *node)
{
struct hstate *h;
struct node_hstate *nhs = &node_hstates[node->dev.id];
@@ -2121,6 +2121,21 @@ int hugetlb_report_node_meminfo(int nid, char *buf)
nid, h->surplus_huge_pages_node[nid]);
}
+void hugetlb_show_meminfo(void)
+{
+ struct hstate *h;
+ int nid;
+
+ for_each_node_state(nid, N_MEMORY)
+ for_each_hstate(h)
+ pr_info("Node %d hugepages_total=%u hugepages_free=%u hugepages_surp=%u hugepages_size=%lukB\n",
+ nid,
+ h->nr_huge_pages_node[nid],
+ h->free_huge_pages_node[nid],
+ h->surplus_huge_pages_node[nid],
+ 1UL << (huge_page_order(h) + PAGE_SHIFT - 10));
+}
+
/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
unsigned long hugetlb_total_pages(void)
{
@@ -2247,10 +2262,11 @@ static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
pte_t entry;
if (writable) {
- entry =
- pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+ entry = huge_pte_mkwrite(huge_pte_mkdirty(mk_huge_pte(page,
+ vma->vm_page_prot)));
} else {
- entry = huge_pte_wrprotect(mk_pte(page, vma->vm_page_prot));
+ entry = huge_pte_wrprotect(mk_huge_pte(page,
+ vma->vm_page_prot));
}
entry = pte_mkyoung(entry);
entry = pte_mkhuge(entry);
@@ -2264,7 +2280,7 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
{
pte_t entry;
- entry = pte_mkwrite(pte_mkdirty(huge_ptep_get(ptep)));
+ entry = huge_pte_mkwrite(huge_pte_mkdirty(huge_ptep_get(ptep)));
if (huge_ptep_set_access_flags(vma, address, ptep, entry, 1))
update_mmu_cache(vma, address, ptep);
}
@@ -2379,7 +2395,7 @@ again:
* HWPoisoned hugepage is already unmapped and dropped reference
*/
if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) {
- pte_clear(mm, address, ptep);
+ huge_pte_clear(mm, address, ptep);
continue;
}
@@ -2403,7 +2419,7 @@ again:
pte = huge_ptep_get_and_clear(mm, address, ptep);
tlb_remove_tlb_entry(tlb, ptep, address);
- if (pte_dirty(pte))
+ if (huge_pte_dirty(pte))
set_page_dirty(page);
page_remove_rmap(page);
@@ -2856,7 +2872,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
* page now as it is used to determine if a reservation has been
* consumed.
*/
- if ((flags & FAULT_FLAG_WRITE) && !pte_write(entry)) {
+ if ((flags & FAULT_FLAG_WRITE) && !huge_pte_write(entry)) {
if (vma_needs_reservation(h, vma, address) < 0) {
ret = VM_FAULT_OOM;
goto out_mutex;
@@ -2886,12 +2902,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (flags & FAULT_FLAG_WRITE) {
- if (!pte_write(entry)) {
+ if (!huge_pte_write(entry)) {
ret = hugetlb_cow(mm, vma, address, ptep, entry,
pagecache_page);
goto out_page_table_lock;
}
- entry = pte_mkdirty(entry);
+ entry = huge_pte_mkdirty(entry);
}
entry = pte_mkyoung(entry);
if (huge_ptep_set_access_flags(vma, address, ptep, entry,
@@ -2961,8 +2977,19 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
break;
}
- if (absent ||
- ((flags & FOLL_WRITE) && !pte_write(huge_ptep_get(pte)))) {
+ /*
+ * We need call hugetlb_fault for both hugepages under migration
+ * (in which case hugetlb_fault waits for the migration,) and
+ * hwpoisoned hugepages (in which case we need to prevent the
+ * caller from accessing to them.) In order to do this, we use
+ * here is_swap_pte instead of is_hugetlb_entry_migration and
+ * is_hugetlb_entry_hwpoisoned. This is because it simply covers
+ * both cases, and because we can't follow correct pages
+ * directly from any kind of swap entries.
+ */
+ if (absent || is_swap_pte(huge_ptep_get(pte)) ||
+ ((flags & FOLL_WRITE) &&
+ !huge_pte_write(huge_ptep_get(pte)))) {
int ret;
spin_unlock(&mm->page_table_lock);
@@ -3032,7 +3059,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
}
if (!huge_pte_none(huge_ptep_get(ptep))) {
pte = huge_ptep_get_and_clear(mm, address, ptep);
- pte = pte_mkhuge(pte_modify(pte, newprot));
+ pte = pte_mkhuge(huge_pte_modify(pte, newprot));
pte = arch_make_huge_pte(pte, vma, NULL, 0);
set_huge_pte_at(mm, address, ptep, pte);
pages++;
diff --git a/mm/madvise.c b/mm/madvise.c
index c58c94b56c3d..7055883e6e25 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -473,27 +473,27 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
if (!madvise_behavior_valid(behavior))
return error;
- write = madvise_need_mmap_write(behavior);
- if (write)
- down_write(&current->mm->mmap_sem);
- else
- down_read(&current->mm->mmap_sem);
-
if (start & ~PAGE_MASK)
- goto out;
+ return error;
len = (len_in + ~PAGE_MASK) & PAGE_MASK;
/* Check to see whether len was rounded up from small -ve to zero */
if (len_in && !len)
- goto out;
+ return error;
end = start + len;
if (end < start)
- goto out;
+ return error;
error = 0;
if (end == start)
- goto out;
+ return error;
+
+ write = madvise_need_mmap_write(behavior);
+ if (write)
+ down_write(&current->mm->mmap_sem);
+ else
+ down_read(&current->mm->mmap_sem);
/*
* If the interval [start,end) covers some unmapped address
@@ -509,14 +509,14 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
/* Still start < end. */
error = -ENOMEM;
if (!vma)
- goto out_plug;
+ goto out;
/* Here start < (end|vma->vm_end). */
if (start < vma->vm_start) {
unmapped_error = -ENOMEM;
start = vma->vm_start;
if (start >= end)
- goto out_plug;
+ goto out;
}
/* Here vma->vm_start <= start < (end|vma->vm_end) */
@@ -527,21 +527,20 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
error = madvise_vma(vma, &prev, start, tmp, behavior);
if (error)
- goto out_plug;
+ goto out;
start = tmp;
if (prev && start < prev->vm_end)
start = prev->vm_end;
error = unmapped_error;
if (start >= end)
- goto out_plug;
+ goto out;
if (prev)
vma = prev->vm_next;
else /* madvise_remove dropped mmap_sem */
vma = find_vma(current->mm, start);
}
-out_plug:
- blk_finish_plug(&plug);
out:
+ blk_finish_plug(&plug);
if (write)
up_write(&current->mm->mmap_sem);
else
diff --git a/mm/memblock.c b/mm/memblock.c
index b8d9147e5c08..c5fad932fa51 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -322,10 +322,11 @@ static void __init_memblock memblock_merge_regions(struct memblock_type *type)
/**
* memblock_insert_region - insert new memblock region
- * @type: memblock type to insert into
- * @idx: index for the insertion point
- * @base: base address of the new region
- * @size: size of the new region
+ * @type: memblock type to insert into
+ * @idx: index for the insertion point
+ * @base: base address of the new region
+ * @size: size of the new region
+ * @nid: node id of the new region
*
* Insert new memblock region [@base,@base+@size) into @type at @idx.
* @type must already have extra room to accomodate the new region.
@@ -771,6 +772,9 @@ static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
{
phys_addr_t found;
+ if (WARN_ON(!align))
+ align = __alignof__(long long);
+
/* align @size to avoid excessive fragmentation on reserved array */
size = round_up(size, align);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2b552224f5cf..0f1d92163f30 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -49,6 +49,7 @@
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
+#include <linux/vmpressure.h>
#include <linux/mm_inline.h>
#include <linux/page_cgroup.h>
#include <linux/cpu.h>
@@ -152,8 +153,13 @@ struct mem_cgroup_stat_cpu {
};
struct mem_cgroup_reclaim_iter {
- /* css_id of the last scanned hierarchy member */
- int position;
+ /*
+ * last scanned hierarchy member. Valid only if last_dead_count
+ * matches memcg->dead_count of the hierarchy root group.
+ */
+ struct mem_cgroup *last_visited;
+ unsigned long last_dead_count;
+
/* scan generation, increased every round-trip */
unsigned int generation;
};
@@ -256,6 +262,9 @@ struct mem_cgroup {
*/
struct res_counter res;
+ /* vmpressure notifications */
+ struct vmpressure vmpressure;
+
union {
/*
* the counter to account for mem+swap usage.
@@ -335,6 +344,7 @@ struct mem_cgroup {
struct mem_cgroup_stat_cpu nocpu_base;
spinlock_t pcp_counter_lock;
+ atomic_t dead_count;
#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET)
struct tcp_memcontrol tcp_mem;
#endif
@@ -353,6 +363,7 @@ struct mem_cgroup {
atomic_t numainfo_events;
atomic_t numainfo_updating;
#endif
+
/*
* Per cgroup active and inactive list, similar to the
* per zone LRU lists.
@@ -504,6 +515,24 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *s)
return container_of(s, struct mem_cgroup, css);
}
+/* Some nice accessors for the vmpressure. */
+struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg)
+{
+ if (!memcg)
+ memcg = root_mem_cgroup;
+ return &memcg->vmpressure;
+}
+
+struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr)
+{
+ return &container_of(vmpr, struct mem_cgroup, vmpressure)->css;
+}
+
+struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css)
+{
+ return &mem_cgroup_from_css(css)->vmpressure;
+}
+
static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
{
return (memcg == root_mem_cgroup);
@@ -1067,6 +1096,51 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
return memcg;
}
+/*
+ * Returns a next (in a pre-order walk) alive memcg (with elevated css
+ * ref. count) or NULL if the whole root's subtree has been visited.
+ *
+ * helper function to be used by mem_cgroup_iter
+ */
+static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
+ struct mem_cgroup *last_visited)
+{
+ struct cgroup *prev_cgroup, *next_cgroup;
+
+ /*
+ * Root is not visited by cgroup iterators so it needs an
+ * explicit visit.
+ */
+ if (!last_visited)
+ return root;
+
+ prev_cgroup = (last_visited == root) ? NULL
+ : last_visited->css.cgroup;
+skip_node:
+ next_cgroup = cgroup_next_descendant_pre(
+ prev_cgroup, root->css.cgroup);
+
+ /*
+ * Even if we found a group we have to make sure it is
+ * alive. css && !memcg means that the groups should be
+ * skipped and we should continue the tree walk.
+ * last_visited css is safe to use because it is
+ * protected by css_get and the tree walk is rcu safe.
+ */
+ if (next_cgroup) {
+ struct mem_cgroup *mem = mem_cgroup_from_cont(
+ next_cgroup);
+ if (css_tryget(&mem->css))
+ return mem;
+ else {
+ prev_cgroup = next_cgroup;
+ goto skip_node;
+ }
+ }
+
+ return NULL;
+}
+
/**
* mem_cgroup_iter - iterate over memory cgroup hierarchy
* @root: hierarchy root
@@ -1089,7 +1163,8 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
struct mem_cgroup_reclaim_cookie *reclaim)
{
struct mem_cgroup *memcg = NULL;
- int id = 0;
+ struct mem_cgroup *last_visited = NULL;
+ unsigned long uninitialized_var(dead_count);
if (mem_cgroup_disabled())
return NULL;
@@ -1098,20 +1173,17 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
root = root_mem_cgroup;
if (prev && !reclaim)
- id = css_id(&prev->css);
-
- if (prev && prev != root)
- css_put(&prev->css);
+ last_visited = prev;
if (!root->use_hierarchy && root != root_mem_cgroup) {
if (prev)
- return NULL;
+ goto out_css_put;
return root;
}
+ rcu_read_lock();
while (!memcg) {
struct mem_cgroup_reclaim_iter *uninitialized_var(iter);
- struct cgroup_subsys_state *css;
if (reclaim) {
int nid = zone_to_nid(reclaim->zone);
@@ -1120,31 +1192,60 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
mz = mem_cgroup_zoneinfo(root, nid, zid);
iter = &mz->reclaim_iter[reclaim->priority];
- if (prev && reclaim->generation != iter->generation)
- return NULL;
- id = iter->position;
+ last_visited = iter->last_visited;
+ if (prev && reclaim->generation != iter->generation) {
+ iter->last_visited = NULL;
+ goto out_unlock;
+ }
+
+ /*
+ * If the dead_count mismatches, a destruction
+ * has happened or is happening concurrently.
+ * If the dead_count matches, a destruction
+ * might still happen concurrently, but since
+ * we checked under RCU, that destruction
+ * won't free the object until we release the
+ * RCU reader lock. Thus, the dead_count
+ * check verifies the pointer is still valid,
+ * css_tryget() verifies the cgroup pointed to
+ * is alive.
+ */
+ dead_count = atomic_read(&root->dead_count);
+ smp_rmb();
+ last_visited = iter->last_visited;
+ if (last_visited) {
+ if ((dead_count != iter->last_dead_count) ||
+ !css_tryget(&last_visited->css)) {
+ last_visited = NULL;
+ }
+ }
}
- rcu_read_lock();
- css = css_get_next(&mem_cgroup_subsys, id + 1, &root->css, &id);
- if (css) {
- if (css == &root->css || css_tryget(css))
- memcg = mem_cgroup_from_css(css);
- } else
- id = 0;
- rcu_read_unlock();
+ memcg = __mem_cgroup_iter_next(root, last_visited);
if (reclaim) {
- iter->position = id;
- if (!css)
+ if (last_visited)
+ css_put(&last_visited->css);
+
+ iter->last_visited = memcg;
+ smp_wmb();
+ iter->last_dead_count = dead_count;
+
+ if (!memcg)
iter->generation++;
else if (!prev && memcg)
reclaim->generation = iter->generation;
}
- if (prev && !css)
- return NULL;
+ if (prev && !memcg)
+ goto out_unlock;
}
+out_unlock:
+ rcu_read_unlock();
+out_css_put:
+ if (prev && prev != root)
+ css_put(&prev->css);
+
return memcg;
}
@@ -1686,11 +1787,11 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
struct task_struct *chosen = NULL;
/*
- * If current has a pending SIGKILL, then automatically select it. The
- * goal is to allow it to allocate so that it may quickly exit and free
- * its memory.
+ * If current has a pending SIGKILL or is exiting, then automatically
+ * select it. The goal is to allow it to allocate so that it may
+ * quickly exit and free its memory.
*/
- if (fatal_signal_pending(current)) {
+ if (fatal_signal_pending(current) || current->flags & PF_EXITING) {
set_thread_flag(TIF_MEMDIE);
return;
}
@@ -3114,12 +3215,12 @@ void memcg_release_cache(struct kmem_cache *s)
root = s->memcg_params->root_cache;
root->memcg_params->memcg_caches[id] = NULL;
- mem_cgroup_put(memcg);
mutex_lock(&memcg->slab_caches_mutex);
list_del(&s->memcg_params->list);
mutex_unlock(&memcg->slab_caches_mutex);
+ mem_cgroup_put(memcg);
out:
kfree(s->memcg_params);
}
@@ -3220,52 +3321,53 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)
schedule_work(&cachep->memcg_params->destroy);
}
-static char *memcg_cache_name(struct mem_cgroup *memcg, struct kmem_cache *s)
-{
- char *name;
- struct dentry *dentry;
-
- rcu_read_lock();
- dentry = rcu_dereference(memcg->css.cgroup->dentry);
- rcu_read_unlock();
-
- BUG_ON(dentry == NULL);
-
- name = kasprintf(GFP_KERNEL, "%s(%d:%s)", s->name,
- memcg_cache_id(memcg), dentry->d_name.name);
-
- return name;
-}
+/*
+ * This lock protects updaters, not readers. We want readers to be as fast as
+ * they can, and they will either see NULL or a valid cache value. Our model
+ * allow them to see NULL, in which case the root memcg will be selected.
+ *
+ * We need this lock because multiple allocations to the same cache from a non
+ * will span more than one worker. Only one of them can create the cache.
+ */
+static DEFINE_MUTEX(memcg_cache_mutex);
+/*
+ * Called with memcg_cache_mutex held
+ */
static struct kmem_cache *kmem_cache_dup(struct mem_cgroup *memcg,
struct kmem_cache *s)
{
- char *name;
struct kmem_cache *new;
+ static char *tmp_name = NULL;
- name = memcg_cache_name(memcg, s);
- if (!name)
- return NULL;
+ lockdep_assert_held(&memcg_cache_mutex);
+
+ /*
+ * kmem_cache_create_memcg duplicates the given name and
+ * cgroup_name for this name requires RCU context.
+ * This static temporary buffer is used to prevent from
+ * pointless shortliving allocation.
+ */
+ if (!tmp_name) {
+ tmp_name = kmalloc(PATH_MAX, GFP_KERNEL);
+ if (!tmp_name)
+ return NULL;
+ }
+
+ rcu_read_lock();
+ snprintf(tmp_name, PATH_MAX, "%s(%d:%s)", s->name,
+ memcg_cache_id(memcg), cgroup_name(memcg->css.cgroup));
+ rcu_read_unlock();
- new = kmem_cache_create_memcg(memcg, name, s->object_size, s->align,
+ new = kmem_cache_create_memcg(memcg, tmp_name, s->object_size, s->align,
(s->flags & ~SLAB_PANIC), s->ctor, s);
if (new)
new->allocflags |= __GFP_KMEMCG;
- kfree(name);
return new;
}
-/*
- * This lock protects updaters, not readers. We want readers to be as fast as
- * they can, and they will either see NULL or a valid cache value. Our model
- * allow them to see NULL, in which case the root memcg will be selected.
- *
- * We need this lock because multiple allocations to the same cache from a non
- * will span more than one worker. Only one of them can create the cache.
- */
-static DEFINE_MUTEX(memcg_cache_mutex);
static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
struct kmem_cache *cachep)
{
@@ -3382,7 +3484,6 @@ static void memcg_create_cache_work_func(struct work_struct *w)
/*
* Enqueue the creation of a per-memcg kmem_cache.
- * Called with rcu_read_lock.
*/
static void __memcg_create_cache_enqueue(struct mem_cgroup *memcg,
struct kmem_cache *cachep)
@@ -3390,12 +3491,8 @@ static void __memcg_create_cache_enqueue(struct mem_cgroup *memcg,
struct create_work *cw;
cw = kmalloc(sizeof(struct create_work), GFP_NOWAIT);
- if (cw == NULL)
- return;
-
- /* The corresponding put will be done in the workqueue. */
- if (!css_tryget(&memcg->css)) {
- kfree(cw);
+ if (cw == NULL) {
+ css_put(&memcg->css);
return;
}
@@ -3451,10 +3548,9 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
rcu_read_lock();
memcg = mem_cgroup_from_task(rcu_dereference(current->mm->owner));
- rcu_read_unlock();
if (!memcg_can_account_kmem(memcg))
- return cachep;
+ goto out;
idx = memcg_cache_id(memcg);
@@ -3463,29 +3559,38 @@ struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep,
* code updating memcg_caches will issue a write barrier to match this.
*/
read_barrier_depends();
- if (unlikely(cachep->memcg_params->memcg_caches[idx] == NULL)) {
- /*
- * If we are in a safe context (can wait, and not in interrupt
- * context), we could be be predictable and return right away.
- * This would guarantee that the allocation being performed
- * already belongs in the new cache.
- *
- * However, there are some clashes that can arrive from locking.
- * For instance, because we acquire the slab_mutex while doing
- * kmem_cache_dup, this means no further allocation could happen
- * with the slab_mutex held.
- *
- * Also, because cache creation issue get_online_cpus(), this
- * creates a lock chain: memcg_slab_mutex -> cpu_hotplug_mutex,
- * that ends up reversed during cpu hotplug. (cpuset allocates
- * a bunch of GFP_KERNEL memory during cpuup). Due to all that,
- * better to defer everything.
- */
- memcg_create_cache_enqueue(memcg, cachep);
- return cachep;
+ if (likely(cachep->memcg_params->memcg_caches[idx])) {
+ cachep = cachep->memcg_params->memcg_caches[idx];
+ goto out;
}
- return cachep->memcg_params->memcg_caches[idx];
+ /* The corresponding put will be done in the workqueue. */
+ if (!css_tryget(&memcg->css))
+ goto out;
+ rcu_read_unlock();
+
+ /*
+ * If we are in a safe context (can wait, and not in interrupt
+ * context), we could be be predictable and return right away.
+ * This would guarantee that the allocation being performed
+ * already belongs in the new cache.
+ *
+ * However, there are some clashes that can arrive from locking.
+ * For instance, because we acquire the slab_mutex while doing
+ * kmem_cache_dup, this means no further allocation could happen
+ * with the slab_mutex held.
+ *
+ * Also, because cache creation issue get_online_cpus(), this
+ * creates a lock chain: memcg_slab_mutex -> cpu_hotplug_mutex,
+ * that ends up reversed during cpu hotplug. (cpuset allocates
+ * a bunch of GFP_KERNEL memory during cpuup). Due to all that,
+ * better to defer everything.
+ */
+ memcg_create_cache_enqueue(memcg, cachep);
+ return cachep;
+out:
+ rcu_read_unlock();
+ return cachep;
}
EXPORT_SYMBOL(__memcg_kmem_get_cache);
@@ -4947,9 +5052,6 @@ static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private);
- if (!do_swap_account && type == _MEMSWAP)
- return -EOPNOTSUPP;
-
switch (type) {
case _MEM:
if (name == RES_USAGE)
@@ -5084,9 +5186,6 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private);
- if (!do_swap_account && type == _MEMSWAP)
- return -EOPNOTSUPP;
-
switch (name) {
case RES_LIMIT:
if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */
@@ -5163,9 +5262,6 @@ static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
type = MEMFILE_TYPE(event);
name = MEMFILE_ATTR(event);
- if (!do_swap_account && type == _MEMSWAP)
- return -EOPNOTSUPP;
-
switch (name) {
case RES_MAX_USAGE:
if (type == _MEM)
@@ -5744,7 +5840,7 @@ static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
return ret;
return mem_cgroup_sockets_init(memcg, ss);
-};
+}
static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
{
@@ -5817,6 +5913,7 @@ static struct cftype mem_cgroup_files[] = {
},
{
.name = "use_hierarchy",
+ .flags = CFTYPE_INSANE,
.write_u64 = mem_cgroup_hierarchy_write,
.read_u64 = mem_cgroup_hierarchy_read,
},
@@ -5838,6 +5935,11 @@ static struct cftype mem_cgroup_files[] = {
.unregister_event = mem_cgroup_oom_unregister_event,
.private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL),
},
+ {
+ .name = "pressure_level",
+ .register_event = vmpressure_register_event,
+ .unregister_event = vmpressure_unregister_event,
+ },
#ifdef CONFIG_NUMA
{
.name = "numa_stat",
@@ -6119,6 +6221,7 @@ mem_cgroup_css_alloc(struct cgroup *cont)
memcg->move_charge_at_immigrate = 0;
mutex_init(&memcg->thresholds_lock);
spin_lock_init(&memcg->move_lock);
+ vmpressure_init(&memcg->vmpressure);
return &memcg->css;
@@ -6184,10 +6287,29 @@ mem_cgroup_css_online(struct cgroup *cont)
return error;
}
+/*
+ * Announce all parents that a group from their hierarchy is gone.
+ */
+static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg)
+{
+ struct mem_cgroup *parent = memcg;
+
+ while ((parent = parent_mem_cgroup(parent)))
+ atomic_inc(&parent->dead_count);
+
+ /*
+ * if the root memcg is not hierarchical we have to check it
+ * explicitely.
+ */
+ if (!root_mem_cgroup->use_hierarchy)
+ atomic_inc(&root_mem_cgroup->dead_count);
+}
+
static void mem_cgroup_css_offline(struct cgroup *cont)
{
struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+ mem_cgroup_invalidate_reclaim_iterators(memcg);
mem_cgroup_reparent_charges(memcg);
mem_cgroup_destroy_all_caches(memcg);
}
@@ -6787,6 +6909,21 @@ static void mem_cgroup_move_task(struct cgroup *cont,
}
#endif
+/*
+ * Cgroup retains root cgroups across [un]mount cycles making it necessary
+ * to verify sane_behavior flag on each mount attempt.
+ */
+static void mem_cgroup_bind(struct cgroup *root)
+{
+ /*
+ * use_hierarchy is forced with sane_behavior. cgroup core
+ * guarantees that @root doesn't have any children, so turning it
+ * on for the root memcg is enough.
+ */
+ if (cgroup_sane_behavior(root))
+ mem_cgroup_from_cont(root)->use_hierarchy = true;
+}
+
struct cgroup_subsys mem_cgroup_subsys = {
.name = "memory",
.subsys_id = mem_cgroup_subsys_id,
@@ -6797,6 +6934,7 @@ struct cgroup_subsys mem_cgroup_subsys = {
.can_attach = mem_cgroup_can_attach,
.cancel_attach = mem_cgroup_cancel_attach,
.attach = mem_cgroup_move_task,
+ .bind = mem_cgroup_bind,
.base_cftypes = mem_cgroup_files,
.early_init = 0,
.use_id = 1,
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index df0694c6adef..ceb0c7f1932f 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -785,10 +785,10 @@ static struct page_state {
{ sc|dirty, sc, "clean swapcache", me_swapcache_clean },
{ mlock|dirty, mlock|dirty, "dirty mlocked LRU", me_pagecache_dirty },
- { mlock, mlock, "clean mlocked LRU", me_pagecache_clean },
+ { mlock|dirty, mlock, "clean mlocked LRU", me_pagecache_clean },
{ unevict|dirty, unevict|dirty, "dirty unevictable LRU", me_pagecache_dirty },
- { unevict, unevict, "clean unevictable LRU", me_pagecache_clean },
+ { unevict|dirty, unevict, "clean unevictable LRU", me_pagecache_clean },
{ lru|dirty, lru|dirty, "dirty LRU", me_pagecache_dirty },
{ lru|dirty, lru, "clean LRU", me_pagecache_clean },
diff --git a/mm/memory.c b/mm/memory.c
index 494526ae024a..6dc1882fbd72 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -216,6 +216,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
tlb->mm = mm;
tlb->fullmm = fullmm;
+ tlb->need_flush_all = 0;
tlb->start = -1UL;
tlb->end = 0;
tlb->need_flush = 0;
@@ -714,11 +715,11 @@ static void print_bad_pte(struct vm_area_struct *vma, unsigned long addr,
* Choose text because data symbols depend on CONFIG_KALLSYMS_ALL=y
*/
if (vma->vm_ops)
- print_symbol(KERN_ALERT "vma->vm_ops->fault: %s\n",
- (unsigned long)vma->vm_ops->fault);
+ printk(KERN_ALERT "vma->vm_ops->fault: %pSR\n",
+ vma->vm_ops->fault);
if (vma->vm_file && vma->vm_file->f_op)
- print_symbol(KERN_ALERT "vma->vm_file->f_op->mmap: %s\n",
- (unsigned long)vma->vm_file->f_op->mmap);
+ printk(KERN_ALERT "vma->vm_file->f_op->mmap: %pSR\n",
+ vma->vm_file->f_op->mmap);
dump_stack();
add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE);
}
@@ -2392,6 +2393,53 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
}
EXPORT_SYMBOL(remap_pfn_range);
+/**
+ * vm_iomap_memory - remap memory to userspace
+ * @vma: user vma to map to
+ * @start: start of area
+ * @len: size of area
+ *
+ * This is a simplified io_remap_pfn_range() for common driver use. The
+ * driver just needs to give us the physical memory range to be mapped,
+ * we'll figure out the rest from the vma information.
+ *
+ * NOTE! Some drivers might want to tweak vma->vm_page_prot first to get
+ * whatever write-combining details or similar.
+ */
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
+{
+ unsigned long vm_len, pfn, pages;
+
+ /* Check that the physical memory area passed in looks valid */
+ if (start + len < start)
+ return -EINVAL;
+ /*
+ * You *really* shouldn't map things that aren't page-aligned,
+ * but we've historically allowed it because IO memory might
+ * just have smaller alignment.
+ */
+ len += start & ~PAGE_MASK;
+ pfn = start >> PAGE_SHIFT;
+ pages = (len + ~PAGE_MASK) >> PAGE_SHIFT;
+ if (pfn + pages < pfn)
+ return -EINVAL;
+
+ /* We start the mapping 'vm_pgoff' pages into the area */
+ if (vma->vm_pgoff > pages)
+ return -EINVAL;
+ pfn += vma->vm_pgoff;
+ pages -= vma->vm_pgoff;
+
+ /* Can we fit all of the mapping? */
+ vm_len = vma->vm_end - vma->vm_start;
+ if (vm_len >> PAGE_SHIFT > pages)
+ return -EINVAL;
+
+ /* Ok, let it rip */
+ return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_iomap_memory);
+
static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
unsigned long addr, unsigned long end,
pte_fn_t fn, void *data)
@@ -3196,6 +3244,11 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
page = alloc_zeroed_user_highpage_movable(vma, address);
if (!page)
goto oom;
+ /*
+ * The memory barrier inside __SetPageUptodate makes sure that
+ * preceeding stores to the page contents become visible before
+ * the set_pte_at() write.
+ */
__SetPageUptodate(page);
if (mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index ee3765760818..a221fac1f47d 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -436,6 +436,40 @@ static int __meminit __add_section(int nid, struct zone *zone,
return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
}
+/*
+ * Reasonably generic function for adding memory. It is
+ * expected that archs that support memory hotplug will
+ * call this function after deciding the zone to which to
+ * add the new pages.
+ */
+int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
+ unsigned long nr_pages)
+{
+ unsigned long i;
+ int err = 0;
+ int start_sec, end_sec;
+ /* during initialize mem_map, align hot-added range to section */
+ start_sec = pfn_to_section_nr(phys_start_pfn);
+ end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
+
+ for (i = start_sec; i <= end_sec; i++) {
+ err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
+
+ /*
+ * EEXIST is finally dealt with by ioresource collision
+ * check. see add_memory() => register_memory_resource()
+ * Warning will be printed if there is collision.
+ */
+ if (err && (err != -EEXIST))
+ break;
+ err = 0;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(__add_pages);
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
/* find the smallest valid pfn in the range [start_pfn, end_pfn) */
static int find_smallest_section_pfn(int nid, struct zone *zone,
unsigned long start_pfn,
@@ -658,39 +692,6 @@ static int __remove_section(struct zone *zone, struct mem_section *ms)
return 0;
}
-/*
- * Reasonably generic function for adding memory. It is
- * expected that archs that support memory hotplug will
- * call this function after deciding the zone to which to
- * add the new pages.
- */
-int __ref __add_pages(int nid, struct zone *zone, unsigned long phys_start_pfn,
- unsigned long nr_pages)
-{
- unsigned long i;
- int err = 0;
- int start_sec, end_sec;
- /* during initialize mem_map, align hot-added range to section */
- start_sec = pfn_to_section_nr(phys_start_pfn);
- end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
-
- for (i = start_sec; i <= end_sec; i++) {
- err = __add_section(nid, zone, i << PFN_SECTION_SHIFT);
-
- /*
- * EEXIST is finally dealt with by ioresource collision
- * check. see add_memory() => register_memory_resource()
- * Warning will be printed if there is collision.
- */
- if (err && (err != -EEXIST))
- break;
- err = 0;
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(__add_pages);
-
/**
* __remove_pages() - remove sections of pages from a zone
* @zone: zone from which pages need to be removed
@@ -705,8 +706,10 @@ EXPORT_SYMBOL_GPL(__add_pages);
int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
unsigned long nr_pages)
{
- unsigned long i, ret = 0;
+ unsigned long i;
int sections_to_remove;
+ resource_size_t start, size;
+ int ret = 0;
/*
* We can only remove entire sections
@@ -714,7 +717,12 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
BUG_ON(nr_pages % PAGES_PER_SECTION);
- release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE);
+ start = phys_start_pfn << PAGE_SHIFT;
+ size = nr_pages * PAGE_SIZE;
+ ret = release_mem_region_adjustable(&iomem_resource, start, size);
+ if (ret)
+ pr_warn("Unable to release resource <%016llx-%016llx> (%d)\n",
+ start, start + size - 1, ret);
sections_to_remove = nr_pages / PAGES_PER_SECTION;
for (i = 0; i < sections_to_remove; i++) {
@@ -726,6 +734,7 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn,
return ret;
}
EXPORT_SYMBOL_GPL(__remove_pages);
+#endif /* CONFIG_MEMORY_HOTREMOVE */
int set_online_page_callback(online_page_callback_t callback)
{
@@ -1613,7 +1622,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
/**
* walk_memory_range - walks through all mem sections in [start_pfn, end_pfn)
* @start_pfn: start pfn of the memory range
- * @end_pfn: end pft of the memory range
+ * @end_pfn: end pfn of the memory range
* @arg: argument passed to func
* @func: callback for each memory section walked
*
@@ -1681,11 +1690,15 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
{
int ret = !is_memblock_offlined(mem);
- if (unlikely(ret))
+ if (unlikely(ret)) {
+ phys_addr_t beginpa, endpa;
+
+ beginpa = PFN_PHYS(section_nr_to_pfn(mem->start_section_nr));
+ endpa = PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1;
pr_warn("removing memory fails, because memory "
- "[%#010llx-%#010llx] is onlined\n",
- PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)),
- PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1);
+ "[%pa-%pa] is onlined\n",
+ &beginpa, &endpa);
+ }
return ret;
}
diff --git a/mm/migrate.c b/mm/migrate.c
index 3bbaf5d230b0..27ed22579fd9 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -736,7 +736,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
if (PageWriteback(page)) {
/*
- * Only in the case of a full syncronous migration is it
+ * Only in the case of a full synchronous migration is it
* necessary to wait for PageWriteback. In the async case,
* the retry loop is too short and in the sync-light case,
* the overhead of stalling is too much
@@ -973,19 +973,23 @@ out:
}
/*
- * migrate_pages
+ * migrate_pages - migrate the pages specified in a list, to the free pages
+ * supplied as the target for the page migration
*
- * The function takes one list of pages to migrate and a function
- * that determines from the page to be migrated and the private data
- * the target of the move and allocates the page.
+ * @from: The list of pages to be migrated.
+ * @get_new_page: The function used to allocate free pages to be used
+ * as the target of the page migration.
+ * @private: Private data to be passed on to get_new_page()
+ * @mode: The migration mode that specifies the constraints for
+ * page migration, if any.
+ * @reason: The reason for page migration.
*
- * The function returns after 10 attempts or if no pages
- * are movable anymore because to has become empty
- * or no retryable pages exist anymore.
- * Caller should call putback_lru_pages to return pages to the LRU
+ * The function returns after 10 attempts or if no pages are movable any more
+ * because the list has become empty or no retryable pages exist any more.
+ * The caller should call putback_lru_pages() to return pages to the LRU
* or free list only if ret != 0.
*
- * Return: Number of pages not migrated or error code.
+ * Returns the number of pages that were not migrated, or an error code.
*/
int migrate_pages(struct list_head *from, new_page_t get_new_page,
unsigned long private, enum migrate_mode mode, int reason)
diff --git a/mm/mlock.c b/mm/mlock.c
index 1c5e33fce639..79b7cf7d1bca 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -358,7 +358,7 @@ static int do_mlock(unsigned long start, size_t len, int on)
newflags = vma->vm_flags & ~VM_LOCKED;
if (on)
- newflags |= VM_LOCKED | VM_POPULATE;
+ newflags |= VM_LOCKED;
tmp = vma->vm_end;
if (tmp > end)
@@ -418,8 +418,7 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors)
* range with the first VMA. Also, skip undesirable VMA types.
*/
nend = min(end, vma->vm_end);
- if ((vma->vm_flags & (VM_IO | VM_PFNMAP | VM_POPULATE)) !=
- VM_POPULATE)
+ if (vma->vm_flags & (VM_IO | VM_PFNMAP))
continue;
if (nstart < vma->vm_start)
nstart = vma->vm_start;
@@ -492,9 +491,9 @@ static int do_mlockall(int flags)
struct vm_area_struct * vma, * prev = NULL;
if (flags & MCL_FUTURE)
- current->mm->def_flags |= VM_LOCKED | VM_POPULATE;
+ current->mm->def_flags |= VM_LOCKED;
else
- current->mm->def_flags &= ~(VM_LOCKED | VM_POPULATE);
+ current->mm->def_flags &= ~VM_LOCKED;
if (flags == MCL_FUTURE)
goto out;
@@ -503,7 +502,7 @@ static int do_mlockall(int flags)
newflags = vma->vm_flags & ~VM_LOCKED;
if (flags & MCL_CURRENT)
- newflags |= VM_LOCKED | VM_POPULATE;
+ newflags |= VM_LOCKED;
/* Ignore errors */
mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
diff --git a/mm/mmap.c b/mm/mmap.c
index 2664a47cec93..da3e9c04bf37 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -6,6 +6,7 @@
* Address space accounting code <alan@lxorguk.ukuu.org.uk>
*/
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/backing-dev.h>
#include <linux/mm.h>
@@ -33,6 +34,8 @@
#include <linux/uprobes.h>
#include <linux/rbtree_augmented.h>
#include <linux/sched/sysctl.h>
+#include <linux/notifier.h>
+#include <linux/memory.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -84,6 +87,8 @@ EXPORT_SYMBOL(vm_get_page_prot);
int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; /* heuristic overcommit */
int sysctl_overcommit_ratio __read_mostly = 50; /* default is 50% */
int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
/*
* Make sure vm_committed_as in one cacheline and not cacheline shared with
* other variables. It can be updated by several CPUs frequently.
@@ -122,7 +127,7 @@ EXPORT_SYMBOL_GPL(vm_memory_committed);
*/
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
{
- unsigned long free, allowed;
+ unsigned long free, allowed, reserve;
vm_acct_memory(pages);
@@ -163,10 +168,10 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
free -= totalreserve_pages;
/*
- * Leave the last 3% for root
+ * Reserve some for root
*/
if (!cap_sys_admin)
- free -= free / 32;
+ free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
if (free > pages)
return 0;
@@ -177,16 +182,19 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
allowed = (totalram_pages - hugetlb_total_pages())
* sysctl_overcommit_ratio / 100;
/*
- * Leave the last 3% for root
+ * Reserve some for root
*/
if (!cap_sys_admin)
- allowed -= allowed / 32;
+ allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
allowed += total_swap_pages;
- /* Don't let a single process grow too big:
- leave 3% of the size of this process for other processes */
- if (mm)
- allowed -= mm->total_vm / 32;
+ /*
+ * Don't let a single process grow so big a user can't recover
+ */
+ if (mm) {
+ reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
+ allowed -= min(mm->total_vm / 32, reserve);
+ }
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
return 0;
@@ -543,6 +551,34 @@ static int find_vma_links(struct mm_struct *mm, unsigned long addr,
return 0;
}
+static unsigned long count_vma_pages_range(struct mm_struct *mm,
+ unsigned long addr, unsigned long end)
+{
+ unsigned long nr_pages = 0;
+ struct vm_area_struct *vma;
+
+ /* Find first overlaping mapping */
+ vma = find_vma_intersection(mm, addr, end);
+ if (!vma)
+ return 0;
+
+ nr_pages = (min(end, vma->vm_end) -
+ max(addr, vma->vm_start)) >> PAGE_SHIFT;
+
+ /* Iterate over the rest of the overlaps */
+ for (vma = vma->vm_next; vma; vma = vma->vm_next) {
+ unsigned long overlap_len;
+
+ if (vma->vm_start > end)
+ break;
+
+ overlap_len = min(end, vma->vm_end) - vma->vm_start;
+ nr_pages += overlap_len >> PAGE_SHIFT;
+ }
+
+ return nr_pages;
+}
+
void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
struct rb_node **rb_link, struct rb_node *rb_parent)
{
@@ -829,7 +865,7 @@ again: remove_next = 1 + (end > next->vm_end);
if (next->anon_vma)
anon_vma_merge(vma, next);
mm->map_count--;
- mpol_put(vma_policy(next));
+ vma_set_policy(vma, vma_policy(next));
kmem_cache_free(vm_area_cachep, next);
/*
* In mprotect's case 6 (see comments on vma_merge),
@@ -1306,7 +1342,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
}
addr = mmap_region(file, addr, len, vm_flags, pgoff);
- if (!IS_ERR_VALUE(addr) && (vm_flags & VM_POPULATE))
+ if (!IS_ERR_VALUE(addr) &&
+ ((vm_flags & VM_LOCKED) ||
+ (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
*populate = len;
return addr;
}
@@ -1433,6 +1471,23 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
unsigned long charged = 0;
struct inode *inode = file ? file_inode(file) : NULL;
+ /* Check against address space limit. */
+ if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
+ unsigned long nr_pages;
+
+ /*
+ * MAP_FIXED may remove pages of mappings that intersects with
+ * requested mapping. Account for the pages it would unmap.
+ */
+ if (!(vm_flags & MAP_FIXED))
+ return -ENOMEM;
+
+ nr_pages = count_vma_pages_range(mm, addr, addr + len);
+
+ if (!may_expand_vm(mm, (len >> PAGE_SHIFT) - nr_pages))
+ return -ENOMEM;
+ }
+
/* Clear old maps */
error = -ENOMEM;
munmap_back:
@@ -1442,10 +1497,6 @@ munmap_back:
goto munmap_back;
}
- /* Check against address space limit. */
- if (!may_expand_vm(mm, len >> PAGE_SHIFT))
- return -ENOMEM;
-
/*
* Private writable mapping: check memory availability
*/
@@ -1933,12 +1984,9 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
{
struct vm_area_struct *vma = NULL;
- if (WARN_ON_ONCE(!mm)) /* Remove this in linux-3.6 */
- return NULL;
-
/* Check the cache first. */
/* (Cache hit rate is typically around 35%.) */
- vma = mm->mmap_cache;
+ vma = ACCESS_ONCE(mm->mmap_cache);
if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
struct rb_node *rb_node;
@@ -2303,7 +2351,7 @@ static void unmap_region(struct mm_struct *mm,
update_hiwater_rss(mm);
unmap_vmas(&tlb, vma, start, end);
free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
- next ? next->vm_start : 0);
+ next ? next->vm_start : USER_PGTABLES_CEILING);
tlb_finish_mmu(&tlb, start, end);
}
@@ -2683,7 +2731,7 @@ void exit_mmap(struct mm_struct *mm)
/* Use -1 here to ensure all VMAs in the mm are unmapped */
unmap_vmas(&tlb, vma, 0, -1);
- free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
+ free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
tlb_finish_mmu(&tlb, 0, -1);
/*
@@ -3095,3 +3143,115 @@ void __init mmap_init(void)
ret = percpu_counter_init(&vm_committed_as, 0);
VM_BUG_ON(ret);
}
+
+/*
+ * Initialise sysctl_user_reserve_kbytes.
+ *
+ * This is intended to prevent a user from starting a single memory hogging
+ * process, such that they cannot recover (kill the hog) in OVERCOMMIT_NEVER
+ * mode.
+ *
+ * The default value is min(3% of free memory, 128MB)
+ * 128MB is enough to recover with sshd/login, bash, and top/kill.
+ */
+static int init_user_reserve(void)
+{
+ unsigned long free_kbytes;
+
+ free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
+
+ sysctl_user_reserve_kbytes = min(free_kbytes / 32, 1UL << 17);
+ return 0;
+}
+module_init(init_user_reserve)
+
+/*
+ * Initialise sysctl_admin_reserve_kbytes.
+ *
+ * The purpose of sysctl_admin_reserve_kbytes is to allow the sys admin
+ * to log in and kill a memory hogging process.
+ *
+ * Systems with more than 256MB will reserve 8MB, enough to recover
+ * with sshd, bash, and top in OVERCOMMIT_GUESS. Smaller systems will
+ * only reserve 3% of free pages by default.
+ */
+static int init_admin_reserve(void)
+{
+ unsigned long free_kbytes;
+
+ free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
+
+ sysctl_admin_reserve_kbytes = min(free_kbytes / 32, 1UL << 13);
+ return 0;
+}
+module_init(init_admin_reserve)
+
+/*
+ * Reinititalise user and admin reserves if memory is added or removed.
+ *
+ * The default user reserve max is 128MB, and the default max for the
+ * admin reserve is 8MB. These are usually, but not always, enough to
+ * enable recovery from a memory hogging process using login/sshd, a shell,
+ * and tools like top. It may make sense to increase or even disable the
+ * reserve depending on the existence of swap or variations in the recovery
+ * tools. So, the admin may have changed them.
+ *
+ * If memory is added and the reserves have been eliminated or increased above
+ * the default max, then we'll trust the admin.
+ *
+ * If memory is removed and there isn't enough free memory, then we
+ * need to reset the reserves.
+ *
+ * Otherwise keep the reserve set by the admin.
+ */
+static int reserve_mem_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ unsigned long tmp, free_kbytes;
+
+ switch (action) {
+ case MEM_ONLINE:
+ /* Default max is 128MB. Leave alone if modified by operator. */
+ tmp = sysctl_user_reserve_kbytes;
+ if (0 < tmp && tmp < (1UL << 17))
+ init_user_reserve();
+
+ /* Default max is 8MB. Leave alone if modified by operator. */
+ tmp = sysctl_admin_reserve_kbytes;
+ if (0 < tmp && tmp < (1UL << 13))
+ init_admin_reserve();
+
+ break;
+ case MEM_OFFLINE:
+ free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
+
+ if (sysctl_user_reserve_kbytes > free_kbytes) {
+ init_user_reserve();
+ pr_info("vm.user_reserve_kbytes reset to %lu\n",
+ sysctl_user_reserve_kbytes);
+ }
+
+ if (sysctl_admin_reserve_kbytes > free_kbytes) {
+ init_admin_reserve();
+ pr_info("vm.admin_reserve_kbytes reset to %lu\n",
+ sysctl_admin_reserve_kbytes);
+ }
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block reserve_mem_nb = {
+ .notifier_call = reserve_mem_notifier,
+};
+
+static int __meminit init_reserve_notifier(void)
+{
+ if (register_hotmemory_notifier(&reserve_mem_nb))
+ printk("Failed registering memory add/remove notifier for admin reserve");
+
+ return 0;
+}
+module_init(init_reserve_notifier)
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index 5e07d36e381e..bdd3fa2fc73b 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -45,9 +45,9 @@ static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
if (!addr)
return NULL;
+ memblock_reserve(addr, size);
ptr = phys_to_virt(addr);
memset(ptr, 0, size);
- memblock_reserve(addr, size);
/*
* The min_count is set to 0 so that bootmem allocated blocks
* are never reported as leaks.
@@ -120,7 +120,7 @@ static unsigned long __init __free_memory_core(phys_addr_t start,
return end_pfn - start_pfn;
}
-unsigned long __init free_low_memory_core_early(int nodeid)
+static unsigned long __init free_low_memory_core_early(void)
{
unsigned long count = 0;
phys_addr_t start, end, size;
@@ -170,7 +170,7 @@ unsigned long __init free_all_bootmem(void)
* because in some case like Node0 doesn't have RAM installed
* low ram will be on Node1
*/
- return free_low_memory_core_early(MAX_NUMNODES);
+ return free_low_memory_core_early();
}
/**
diff --git a/mm/nommu.c b/mm/nommu.c
index e19328087534..298884dcd6e7 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -63,6 +63,8 @@ int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */
int sysctl_overcommit_ratio = 50; /* default is 50% */
int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS;
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
int heap_stack_gap = 0;
atomic_long_t mmap_pages_allocated;
@@ -228,8 +230,7 @@ int follow_pfn(struct vm_area_struct *vma, unsigned long address,
}
EXPORT_SYMBOL(follow_pfn);
-DEFINE_RWLOCK(vmlist_lock);
-struct vm_struct *vmlist;
+LIST_HEAD(vmap_area_list);
void vfree(const void *addr)
{
@@ -821,7 +822,7 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
struct vm_area_struct *vma;
/* check the cache first */
- vma = mm->mmap_cache;
+ vma = ACCESS_ONCE(mm->mmap_cache);
if (vma && vma->vm_start <= addr && vma->vm_end > addr)
return vma;
@@ -1770,7 +1771,7 @@ unsigned long vm_brk(unsigned long addr, unsigned long len)
*
* MREMAP_FIXED is not supported under NOMMU conditions
*/
-unsigned long do_mremap(unsigned long addr,
+static unsigned long do_mremap(unsigned long addr,
unsigned long old_len, unsigned long new_len,
unsigned long flags, unsigned long new_addr)
{
@@ -1805,7 +1806,6 @@ unsigned long do_mremap(unsigned long addr,
vma->vm_end = vma->vm_start + new_len;
return vma->vm_start;
}
-EXPORT_SYMBOL(do_mremap);
SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
unsigned long, new_len, unsigned long, flags,
@@ -1838,6 +1838,16 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
}
EXPORT_SYMBOL(remap_pfn_range);
+int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
+{
+ unsigned long pfn = start >> PAGE_SHIFT;
+ unsigned long vm_len = vma->vm_end - vma->vm_start;
+
+ pfn += vma->vm_pgoff;
+ return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
+}
+EXPORT_SYMBOL(vm_iomap_memory);
+
int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
unsigned long pgoff)
{
@@ -1888,7 +1898,7 @@ EXPORT_SYMBOL(unmap_mapping_range);
*/
int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
{
- unsigned long free, allowed;
+ unsigned long free, allowed, reserve;
vm_acct_memory(pages);
@@ -1929,10 +1939,10 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
free -= totalreserve_pages;
/*
- * Leave the last 3% for root
+ * Reserve some for root
*/
if (!cap_sys_admin)
- free -= free / 32;
+ free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
if (free > pages)
return 0;
@@ -1942,16 +1952,19 @@ int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin)
allowed = totalram_pages * sysctl_overcommit_ratio / 100;
/*
- * Leave the last 3% for root
+ * Reserve some 3% for root
*/
if (!cap_sys_admin)
- allowed -= allowed / 32;
+ allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10);
allowed += total_swap_pages;
- /* Don't let a single process grow too big:
- leave 3% of the size of this process for other processes */
- if (mm)
- allowed -= mm->total_vm / 32;
+ /*
+ * Don't let a single process grow so big a user can't recover
+ */
+ if (mm) {
+ reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10);
+ allowed -= min(mm->total_vm / 32, reserve);
+ }
if (percpu_counter_read_positive(&vm_committed_as) < allowed)
return 0;
@@ -2113,3 +2126,45 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size,
up_write(&nommu_region_sem);
return 0;
}
+
+/*
+ * Initialise sysctl_user_reserve_kbytes.
+ *
+ * This is intended to prevent a user from starting a single memory hogging
+ * process, such that they cannot recover (kill the hog) in OVERCOMMIT_NEVER
+ * mode.
+ *
+ * The default value is min(3% of free memory, 128MB)
+ * 128MB is enough to recover with sshd/login, bash, and top/kill.
+ */
+static int __meminit init_user_reserve(void)
+{
+ unsigned long free_kbytes;
+
+ free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
+
+ sysctl_user_reserve_kbytes = min(free_kbytes / 32, 1UL << 17);
+ return 0;
+}
+module_init(init_user_reserve)
+
+/*
+ * Initialise sysctl_admin_reserve_kbytes.
+ *
+ * The purpose of sysctl_admin_reserve_kbytes is to allow the sys admin
+ * to log in and kill a memory hogging process.
+ *
+ * Systems with more than 256MB will reserve 8MB, enough to recover
+ * with sshd, bash, and top in OVERCOMMIT_GUESS. Smaller systems will
+ * only reserve 3% of free pages by default.
+ */
+static int __meminit init_admin_reserve(void)
+{
+ unsigned long free_kbytes;
+
+ free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
+
+ sysctl_admin_reserve_kbytes = min(free_kbytes / 32, 1UL << 13);
+ return 0;
+}
+module_init(init_admin_reserve)
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index efe68148f621..4514ad7415c3 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2311,10 +2311,6 @@ void wait_for_stable_page(struct page *page)
if (!bdi_cap_stable_pages_required(bdi))
return;
-#ifdef CONFIG_NEED_BOUNCE_POOL
- if (mapping->host->i_sb->s_flags & MS_SNAP_STABLE)
- return;
-#endif /* CONFIG_NEED_BOUNCE_POOL */
wait_on_page_writeback(page);
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 8fcced7823fa..98cbdf6e5532 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -58,6 +58,7 @@
#include <linux/prefetch.h>
#include <linux/migrate.h>
#include <linux/page-debug-flags.h>
+#include <linux/hugetlb.h>
#include <linux/sched/rt.h>
#include <asm/tlbflush.h>
@@ -1397,6 +1398,7 @@ void split_page(struct page *page, unsigned int order)
for (i = 1; i < (1 << order); i++)
set_page_refcounted(page + i);
}
+EXPORT_SYMBOL_GPL(split_page);
static int __isolate_free_page(struct page *page, unsigned int order)
{
@@ -1940,9 +1942,24 @@ zonelist_scan:
continue;
default:
/* did we reclaim enough */
- if (!zone_watermark_ok(zone, order, mark,
+ if (zone_watermark_ok(zone, order, mark,
classzone_idx, alloc_flags))
+ goto try_this_zone;
+
+ /*
+ * Failed to reclaim enough to meet watermark.
+ * Only mark the zone full if checking the min
+ * watermark or if we failed to reclaim just
+ * 1<<order pages or else the page allocator
+ * fastpath will prematurely mark zones full
+ * when the watermark is between the low and
+ * min watermarks.
+ */
+ if (((alloc_flags & ALLOC_WMARK_MASK) == ALLOC_WMARK_MIN) ||
+ ret == ZONE_RECLAIM_SOME)
goto this_zone_full;
+
+ continue;
}
}
@@ -2002,6 +2019,13 @@ void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
return;
/*
+ * Walking all memory to count page types is very expensive and should
+ * be inhibited in non-blockable contexts.
+ */
+ if (!(gfp_mask & __GFP_WAIT))
+ filter |= SHOW_MEM_FILTER_PAGE_COUNT;
+
+ /*
* This documents exceptions given to allocations in certain
* contexts that are allowed to allocate outside current's set
* of allowed nodes.
@@ -3105,6 +3129,8 @@ void show_free_areas(unsigned int filter)
printk("= %lukB\n", K(total));
}
+ hugetlb_show_meminfo();
+
printk("%ld total pagecache pages\n", global_page_state(NR_FILE_PAGES));
show_swap_cache_info();
@@ -4161,10 +4187,23 @@ int __meminit __early_pfn_to_nid(unsigned long pfn)
{
unsigned long start_pfn, end_pfn;
int i, nid;
+ /*
+ * NOTE: The following SMP-unsafe globals are only used early in boot
+ * when the kernel is running single-threaded.
+ */
+ static unsigned long __meminitdata last_start_pfn, last_end_pfn;
+ static int __meminitdata last_nid;
+
+ if (last_start_pfn <= pfn && pfn < last_end_pfn)
+ return last_nid;
for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
- if (start_pfn <= pfn && pfn < end_pfn)
+ if (start_pfn <= pfn && pfn < end_pfn) {
+ last_start_pfn = start_pfn;
+ last_end_pfn = end_pfn;
+ last_nid = nid;
return nid;
+ }
/* This is a memory hole */
return -1;
}
@@ -4710,7 +4749,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
/*
* Figure out the number of possible node ids.
*/
-static void __init setup_nr_node_ids(void)
+void __init setup_nr_node_ids(void)
{
unsigned int node;
unsigned int highest = 0;
@@ -4719,10 +4758,6 @@ static void __init setup_nr_node_ids(void)
highest = node;
nr_node_ids = highest + 1;
}
-#else
-static inline void setup_nr_node_ids(void)
-{
-}
#endif
/**
@@ -5113,6 +5148,35 @@ early_param("movablecore", cmdline_parse_movablecore);
#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
+unsigned long free_reserved_area(unsigned long start, unsigned long end,
+ int poison, char *s)
+{
+ unsigned long pages, pos;
+
+ pos = start = PAGE_ALIGN(start);
+ end &= PAGE_MASK;
+ for (pages = 0; pos < end; pos += PAGE_SIZE, pages++) {
+ if (poison)
+ memset((void *)pos, poison, PAGE_SIZE);
+ free_reserved_page(virt_to_page(pos));
+ }
+
+ if (pages && s)
+ pr_info("Freeing %s memory: %ldK (%lx - %lx)\n",
+ s, pages << (PAGE_SHIFT - 10), start, end);
+
+ return pages;
+}
+
+#ifdef CONFIG_HIGHMEM
+void free_highmem_page(struct page *page)
+{
+ __free_reserved_page(page);
+ totalram_pages++;
+ totalhigh_pages++;
+}
+#endif
+
/**
* set_dma_reserve - set the specified number of pages reserved in the first zone
* @new_dma_reserve: The number of pages to mark reserved
diff --git a/mm/page_io.c b/mm/page_io.c
index 78eee32ee486..bb5d75274686 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -42,7 +42,7 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
return bio;
}
-static void end_swap_bio_write(struct bio *bio, int err)
+void end_swap_bio_write(struct bio *bio, int err)
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct page *page = bio->bi_io_vec[0].bv_page;
@@ -185,9 +185,7 @@ bad_bmap:
*/
int swap_writepage(struct page *page, struct writeback_control *wbc)
{
- struct bio *bio;
- int ret = 0, rw = WRITE;
- struct swap_info_struct *sis = page_swap_info(page);
+ int ret = 0;
if (try_to_free_swap(page)) {
unlock_page(page);
@@ -199,6 +197,17 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
end_page_writeback(page);
goto out;
}
+ ret = __swap_writepage(page, wbc, end_swap_bio_write);
+out:
+ return ret;
+}
+
+int __swap_writepage(struct page *page, struct writeback_control *wbc,
+ void (*end_write_func)(struct bio *, int))
+{
+ struct bio *bio;
+ int ret = 0, rw = WRITE;
+ struct swap_info_struct *sis = page_swap_info(page);
if (sis->flags & SWP_FILE) {
struct kiocb kiocb;
@@ -214,6 +223,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
kiocb.ki_left = PAGE_SIZE;
kiocb.ki_nbytes = PAGE_SIZE;
+ set_page_writeback(page);
unlock_page(page);
ret = mapping->a_ops->direct_IO(KERNEL_WRITE,
&kiocb, &iov,
@@ -222,11 +232,27 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
if (ret == PAGE_SIZE) {
count_vm_event(PSWPOUT);
ret = 0;
+ } else {
+ /*
+ * In the case of swap-over-nfs, this can be a
+ * temporary failure if the system has limited
+ * memory for allocating transmit buffers.
+ * Mark the page dirty and avoid
+ * rotate_reclaimable_page but rate-limit the
+ * messages but do not flag PageError like
+ * the normal direct-to-bio case as it could
+ * be temporary.
+ */
+ set_page_dirty(page);
+ ClearPageReclaim(page);
+ pr_err_ratelimited("Write error on dio swapfile (%Lu)\n",
+ page_file_offset(page));
}
+ end_page_writeback(page);
return ret;
}
- bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
+ bio = get_swap_bio(GFP_NOIO, page, end_write_func);
if (bio == NULL) {
set_page_dirty(page);
unlock_page(page);
diff --git a/mm/readahead.c b/mm/readahead.c
index 7963f2391236..daed28dd5830 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -576,7 +576,7 @@ do_readahead(struct address_space *mapping, struct file *filp,
return 0;
}
-SYSCALL_DEFINE(readahead)(int fd, loff_t offset, size_t count)
+SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count)
{
ssize_t ret;
struct fd f;
@@ -595,10 +595,3 @@ SYSCALL_DEFINE(readahead)(int fd, loff_t offset, size_t count)
}
return ret;
}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_readahead(long fd, loff_t offset, long count)
-{
- return SYSC_readahead((int) fd, offset, (size_t) count);
-}
-SYSCALL_ALIAS(sys_readahead, SyS_readahead);
-#endif
diff --git a/mm/rmap.c b/mm/rmap.c
index 807c96bf0dc6..6280da86b5d6 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1513,6 +1513,9 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
unsigned long max_nl_size = 0;
unsigned int mapcount;
+ if (PageHuge(page))
+ pgoff = page->index << compound_order(page);
+
mutex_lock(&mapping->i_mmap_mutex);
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
unsigned long address = vma_address(page, vma);
diff --git a/mm/shmem.c b/mm/shmem.c
index 1c44af71fcf5..39b2a0b86fe8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -25,6 +25,7 @@
#include <linux/init.h>
#include <linux/vfs.h>
#include <linux/mount.h>
+#include <linux/ramfs.h>
#include <linux/pagemap.h>
#include <linux/file.h>
#include <linux/mm.h>
@@ -2830,8 +2831,6 @@ out4:
* effectively equivalent, but much lighter weight.
*/
-#include <linux/ramfs.h>
-
static struct file_system_type shmem_fs_type = {
.name = "tmpfs",
.mount = ramfs_mount,
@@ -2931,11 +2930,9 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags
d_instantiate(path.dentry, inode);
inode->i_size = size;
clear_nlink(inode); /* It is unlinked */
-#ifndef CONFIG_MMU
res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size));
if (IS_ERR(res))
goto put_dentry;
-#endif
res = alloc_file(&path, FMODE_WRITE | FMODE_READ,
&shmem_file_operations);
diff --git a/mm/slab.c b/mm/slab.c
index 856e4a192d25..96079244c860 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2040,11 +2040,9 @@ static void print_objinfo(struct kmem_cache *cachep, void *objp, int lines)
}
if (cachep->flags & SLAB_STORE_USER) {
- printk(KERN_ERR "Last user: [<%p>]",
- *dbg_userword(cachep, objp));
- print_symbol("(%s)",
- (unsigned long)*dbg_userword(cachep, objp));
- printk("\n");
+ printk(KERN_ERR "Last user: [<%p>](%pSR)\n",
+ *dbg_userword(cachep, objp),
+ *dbg_userword(cachep, objp));
}
realobj = (char *)objp + obj_offset(cachep);
size = cachep->object_size;
diff --git a/mm/slub.c b/mm/slub.c
index 4aec53705e4f..a0206df88aba 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include "slab.h"
#include <linux/proc_fs.h>
+#include <linux/notifier.h>
#include <linux/seq_file.h>
#include <linux/kmemcheck.h>
#include <linux/cpu.h>
@@ -3483,7 +3484,6 @@ int kmem_cache_shrink(struct kmem_cache *s)
}
EXPORT_SYMBOL(kmem_cache_shrink);
-#if defined(CONFIG_MEMORY_HOTPLUG)
static int slab_mem_going_offline_callback(void *arg)
{
struct kmem_cache *s;
@@ -3598,7 +3598,10 @@ static int slab_memory_callback(struct notifier_block *self,
return ret;
}
-#endif /* CONFIG_MEMORY_HOTPLUG */
+static struct notifier_block slab_memory_callback_nb = {
+ .notifier_call = slab_memory_callback,
+ .priority = SLAB_CALLBACK_PRI,
+};
/********************************************************************
* Basic setup of slabs
@@ -3651,7 +3654,7 @@ void __init kmem_cache_init(void)
create_boot_cache(kmem_cache_node, "kmem_cache_node",
sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
- hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
+ register_hotmemory_notifier(&slab_memory_callback_nb);
/* Able to allocate the per node structures */
slab_state = PARTIAL;
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 1b7e22ab9b09..27eeab3be757 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -53,10 +53,12 @@ void * __meminit vmemmap_alloc_block(unsigned long size, int node)
struct page *page;
if (node_state(node, N_HIGH_MEMORY))
- page = alloc_pages_node(node,
- GFP_KERNEL | __GFP_ZERO, get_order(size));
+ page = alloc_pages_node(
+ node, GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT,
+ get_order(size));
else
- page = alloc_pages(GFP_KERNEL | __GFP_ZERO,
+ page = alloc_pages(
+ GFP_KERNEL | __GFP_ZERO | __GFP_REPEAT,
get_order(size));
if (page)
return page_address(page);
@@ -145,11 +147,10 @@ pgd_t * __meminit vmemmap_pgd_populate(unsigned long addr, int node)
return pgd;
}
-int __meminit vmemmap_populate_basepages(struct page *start_page,
- unsigned long size, int node)
+int __meminit vmemmap_populate_basepages(unsigned long start,
+ unsigned long end, int node)
{
- unsigned long addr = (unsigned long)start_page;
- unsigned long end = (unsigned long)(start_page + size);
+ unsigned long addr = start;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
@@ -176,9 +177,15 @@ int __meminit vmemmap_populate_basepages(struct page *start_page,
struct page * __meminit sparse_mem_map_populate(unsigned long pnum, int nid)
{
- struct page *map = pfn_to_page(pnum * PAGES_PER_SECTION);
- int error = vmemmap_populate(map, PAGES_PER_SECTION, nid);
- if (error)
+ unsigned long start;
+ unsigned long end;
+ struct page *map;
+
+ map = pfn_to_page(pnum * PAGES_PER_SECTION);
+ start = (unsigned long)map;
+ end = (unsigned long)(map + PAGES_PER_SECTION);
+
+ if (vmemmap_populate(start, end, nid))
return NULL;
return map;
diff --git a/mm/sparse.c b/mm/sparse.c
index 7ca6dc847947..1c91f0d3f6ab 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -615,12 +615,20 @@ static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid,
}
static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
{
- vmemmap_free(memmap, nr_pages);
+ unsigned long start = (unsigned long)memmap;
+ unsigned long end = (unsigned long)(memmap + nr_pages);
+
+ vmemmap_free(start, end);
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
- vmemmap_free(memmap, nr_pages);
+ unsigned long start = (unsigned long)memmap;
+ unsigned long end = (unsigned long)(memmap + nr_pages);
+
+ vmemmap_free(start, end);
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
#else
static struct page *__kmalloc_section_memmap(unsigned long nr_pages)
{
@@ -658,6 +666,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
get_order(sizeof(struct page) * nr_pages));
}
+#ifdef CONFIG_MEMORY_HOTREMOVE
static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
unsigned long maps_section_nr, removing_section_nr, i;
@@ -684,40 +693,9 @@ static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
put_page_bootmem(page);
}
}
+#endif /* CONFIG_MEMORY_HOTREMOVE */
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
-static void free_section_usemap(struct page *memmap, unsigned long *usemap)
-{
- struct page *usemap_page;
- unsigned long nr_pages;
-
- if (!usemap)
- return;
-
- usemap_page = virt_to_page(usemap);
- /*
- * Check to see if allocation came from hot-plug-add
- */
- if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
- kfree(usemap);
- if (memmap)
- __kfree_section_memmap(memmap, PAGES_PER_SECTION);
- return;
- }
-
- /*
- * The usemap came from bootmem. This is packed with other usemaps
- * on the section which has pgdat at boot time. Just keep it as is now.
- */
-
- if (memmap) {
- nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
- >> PAGE_SHIFT;
-
- free_map_bootmem(memmap, nr_pages);
- }
-}
-
/*
* returns the number of sections whose mem_maps were properly
* set. If this is <=0, then that means that the passed-in
@@ -794,6 +772,39 @@ static inline void clear_hwpoisoned_pages(struct page *memmap, int nr_pages)
}
#endif
+#ifdef CONFIG_MEMORY_HOTREMOVE
+static void free_section_usemap(struct page *memmap, unsigned long *usemap)
+{
+ struct page *usemap_page;
+ unsigned long nr_pages;
+
+ if (!usemap)
+ return;
+
+ usemap_page = virt_to_page(usemap);
+ /*
+ * Check to see if allocation came from hot-plug-add
+ */
+ if (PageSlab(usemap_page) || PageCompound(usemap_page)) {
+ kfree(usemap);
+ if (memmap)
+ __kfree_section_memmap(memmap, PAGES_PER_SECTION);
+ return;
+ }
+
+ /*
+ * The usemap came from bootmem. This is packed with other usemaps
+ * on the section which has pgdat at boot time. Just keep it as is now.
+ */
+
+ if (memmap) {
+ nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
+ >> PAGE_SHIFT;
+
+ free_map_bootmem(memmap, nr_pages);
+ }
+}
+
void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
{
struct page *memmap = NULL;
@@ -813,4 +824,5 @@ void sparse_remove_one_section(struct zone *zone, struct mem_section *ms)
clear_hwpoisoned_pages(memmap, PAGES_PER_SECTION);
free_section_usemap(memmap, usemap);
}
-#endif
+#endif /* CONFIG_MEMORY_HOTREMOVE */
+#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/mm/swap.c b/mm/swap.c
index 8a529a01e8fc..acd40bfffa82 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -737,7 +737,7 @@ EXPORT_SYMBOL(__pagevec_release);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
/* used by __split_huge_page_refcount() */
void lru_add_page_tail(struct page *page, struct page *page_tail,
- struct lruvec *lruvec)
+ struct lruvec *lruvec, struct list_head *list)
{
int uninitialized_var(active);
enum lru_list lru;
@@ -749,7 +749,8 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
VM_BUG_ON(NR_CPUS != 1 &&
!spin_is_locked(&lruvec_zone(lruvec)->lru_lock));
- SetPageLRU(page_tail);
+ if (!list)
+ SetPageLRU(page_tail);
if (page_evictable(page_tail)) {
if (PageActive(page)) {
@@ -767,7 +768,11 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
if (likely(PageLRU(page)))
list_add_tail(&page_tail->lru, &page->lru);
- else {
+ else if (list) {
+ /* page reclaim is reclaiming a huge page */
+ get_page(page_tail);
+ list_add_tail(&page_tail->lru, list);
+ } else {
struct list_head *list_head;
/*
* Head page has not yet been counted, as an hpage,
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 7efcf1525921..b3d40dcf3624 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -78,7 +78,7 @@ void show_swap_cache_info(void)
* __add_to_swap_cache resembles add_to_page_cache_locked on swapper_space,
* but sets SwapCache flag and private instead of mapping and index.
*/
-static int __add_to_swap_cache(struct page *page, swp_entry_t entry)
+int __add_to_swap_cache(struct page *page, swp_entry_t entry)
{
int error;
struct address_space *address_space;
@@ -160,7 +160,7 @@ void __delete_from_swap_cache(struct page *page)
* Allocate swap space for the page and add the page to the
* swap cache. Caller needs to hold the page lock.
*/
-int add_to_swap(struct page *page)
+int add_to_swap(struct page *page, struct list_head *list)
{
swp_entry_t entry;
int err;
@@ -173,7 +173,7 @@ int add_to_swap(struct page *page)
return 0;
if (unlikely(PageTransHuge(page)))
- if (unlikely(split_huge_page(page))) {
+ if (unlikely(split_huge_page_to_list(page, list))) {
swapcache_free(entry, NULL);
return 0;
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a1f7772a01fc..6c340d908b27 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1509,8 +1509,7 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
}
static void _enable_swap_info(struct swap_info_struct *p, int prio,
- unsigned char *swap_map,
- unsigned long *frontswap_map)
+ unsigned char *swap_map)
{
int i, prev;
@@ -1519,7 +1518,6 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio,
else
p->prio = --least_priority;
p->swap_map = swap_map;
- frontswap_map_set(p, frontswap_map);
p->flags |= SWP_WRITEOK;
atomic_long_add(p->pages, &nr_swap_pages);
total_swap_pages += p->pages;
@@ -1542,10 +1540,10 @@ static void enable_swap_info(struct swap_info_struct *p, int prio,
unsigned char *swap_map,
unsigned long *frontswap_map)
{
+ frontswap_init(p->type, frontswap_map);
spin_lock(&swap_lock);
spin_lock(&p->lock);
- _enable_swap_info(p, prio, swap_map, frontswap_map);
- frontswap_init(p->type);
+ _enable_swap_info(p, prio, swap_map);
spin_unlock(&p->lock);
spin_unlock(&swap_lock);
}
@@ -1554,7 +1552,7 @@ static void reinsert_swap_info(struct swap_info_struct *p)
{
spin_lock(&swap_lock);
spin_lock(&p->lock);
- _enable_swap_info(p, p->prio, p->swap_map, frontswap_map_get(p));
+ _enable_swap_info(p, p->prio, p->swap_map);
spin_unlock(&p->lock);
spin_unlock(&swap_lock);
}
@@ -1563,6 +1561,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
{
struct swap_info_struct *p = NULL;
unsigned char *swap_map;
+ unsigned long *frontswap_map;
struct file *swap_file, *victim;
struct address_space *mapping;
struct inode *inode;
@@ -1662,12 +1661,14 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
swap_map = p->swap_map;
p->swap_map = NULL;
p->flags = 0;
- frontswap_invalidate_area(type);
+ frontswap_map = frontswap_map_get(p);
+ frontswap_map_set(p, NULL);
spin_unlock(&p->lock);
spin_unlock(&swap_lock);
+ frontswap_invalidate_area(type);
mutex_unlock(&swapon_mutex);
vfree(swap_map);
- vfree(frontswap_map_get(p));
+ vfree(frontswap_map);
/* Destroy swap account informatin */
swap_cgroup_swapoff(type);
@@ -2120,7 +2121,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
if (p->bdev) {
if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
p->flags |= SWP_SOLIDSTATE;
- p->cluster_next = 1 + (random32() % p->highest_bit);
+ p->cluster_next = 1 + (prandom_u32() % p->highest_bit);
}
if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0)
p->flags |= SWP_DISCARDABLE;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index ef9bdf742273..b12fd8612604 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -269,19 +269,9 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
#define VM_LAZY_FREEING 0x02
#define VM_VM_AREA 0x04
-struct vmap_area {
- unsigned long va_start;
- unsigned long va_end;
- unsigned long flags;
- struct rb_node rb_node; /* address sorted rbtree */
- struct list_head list; /* address sorted list */
- struct list_head purge_list; /* "lazy purge" list */
- struct vm_struct *vm;
- struct rcu_head rcu_head;
-};
-
static DEFINE_SPINLOCK(vmap_area_lock);
-static LIST_HEAD(vmap_area_list);
+/* Export for kexec only */
+LIST_HEAD(vmap_area_list);
static struct rb_root vmap_area_root = RB_ROOT;
/* The vmap cache globals are protected by vmap_area_lock */
@@ -333,7 +323,7 @@ static void __insert_vmap_area(struct vmap_area *va)
rb_link_node(&va->rb_node, parent, p);
rb_insert_color(&va->rb_node, &vmap_area_root);
- /* address-sort this list so it is usable like the vmlist */
+ /* address-sort this list */
tmp = rb_prev(&va->rb_node);
if (tmp) {
struct vmap_area *prev;
@@ -1145,6 +1135,7 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro
}
EXPORT_SYMBOL(vm_map_ram);
+static struct vm_struct *vmlist __initdata;
/**
* vm_area_add_early - add vmap area early during boot
* @vm: vm_struct to add
@@ -1307,41 +1298,35 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
}
EXPORT_SYMBOL_GPL(map_vm_area);
-/*** Old vmalloc interfaces ***/
-DEFINE_RWLOCK(vmlist_lock);
-struct vm_struct *vmlist;
-
static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
unsigned long flags, const void *caller)
{
+ spin_lock(&vmap_area_lock);
vm->flags = flags;
vm->addr = (void *)va->va_start;
vm->size = va->va_end - va->va_start;
vm->caller = caller;
va->vm = vm;
va->flags |= VM_VM_AREA;
+ spin_unlock(&vmap_area_lock);
}
-static void insert_vmalloc_vmlist(struct vm_struct *vm)
+static void clear_vm_unlist(struct vm_struct *vm)
{
- struct vm_struct *tmp, **p;
-
+ /*
+ * Before removing VM_UNLIST,
+ * we should make sure that vm has proper values.
+ * Pair with smp_rmb() in show_numa_info().
+ */
+ smp_wmb();
vm->flags &= ~VM_UNLIST;
- write_lock(&vmlist_lock);
- for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) {
- if (tmp->addr >= vm->addr)
- break;
- }
- vm->next = *p;
- *p = vm;
- write_unlock(&vmlist_lock);
}
static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
unsigned long flags, const void *caller)
{
setup_vmalloc_vm(vm, va, flags, caller);
- insert_vmalloc_vmlist(vm);
+ clear_vm_unlist(vm);
}
static struct vm_struct *__get_vm_area_node(unsigned long size,
@@ -1384,10 +1369,9 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
/*
* When this function is called from __vmalloc_node_range,
- * we do not add vm_struct to vmlist here to avoid
- * accessing uninitialized members of vm_struct such as
- * pages and nr_pages fields. They will be set later.
- * To distinguish it from others, we use a VM_UNLIST flag.
+ * we add VM_UNLIST flag to avoid accessing uninitialized
+ * members of vm_struct such as pages and nr_pages fields.
+ * They will be set later.
*/
if (flags & VM_UNLIST)
setup_vmalloc_vm(area, va, flags, caller);
@@ -1471,19 +1455,10 @@ struct vm_struct *remove_vm_area(const void *addr)
if (va && va->flags & VM_VM_AREA) {
struct vm_struct *vm = va->vm;
- if (!(vm->flags & VM_UNLIST)) {
- struct vm_struct *tmp, **p;
- /*
- * remove from list and disallow access to
- * this vm_struct before unmap. (address range
- * confliction is maintained by vmap.)
- */
- write_lock(&vmlist_lock);
- for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next)
- ;
- *p = tmp->next;
- write_unlock(&vmlist_lock);
- }
+ spin_lock(&vmap_area_lock);
+ va->vm = NULL;
+ va->flags &= ~VM_VM_AREA;
+ spin_unlock(&vmap_area_lock);
vmap_debug_free_range(va->va_start, va->va_end);
free_unmap_vmap_area(va);
@@ -1715,10 +1690,11 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align,
return NULL;
/*
- * In this function, newly allocated vm_struct is not added
- * to vmlist at __get_vm_area_node(). so, it is added here.
+ * In this function, newly allocated vm_struct has VM_UNLIST flag.
+ * It means that vm_struct is not fully initialized.
+ * Now, it is fully initialized, so remove this flag here.
*/
- insert_vmalloc_vmlist(area);
+ clear_vm_unlist(area);
/*
* A ref_count = 3 is needed because the vm_struct and vmap_area
@@ -2040,7 +2016,8 @@ static int aligned_vwrite(char *buf, char *addr, unsigned long count)
long vread(char *buf, char *addr, unsigned long count)
{
- struct vm_struct *tmp;
+ struct vmap_area *va;
+ struct vm_struct *vm;
char *vaddr, *buf_start = buf;
unsigned long buflen = count;
unsigned long n;
@@ -2049,10 +2026,17 @@ long vread(char *buf, char *addr, unsigned long count)
if ((unsigned long) addr + count < count)
count = -(unsigned long) addr;
- read_lock(&vmlist_lock);
- for (tmp = vmlist; count && tmp; tmp = tmp->next) {
- vaddr = (char *) tmp->addr;
- if (addr >= vaddr + tmp->size - PAGE_SIZE)
+ spin_lock(&vmap_area_lock);
+ list_for_each_entry(va, &vmap_area_list, list) {
+ if (!count)
+ break;
+
+ if (!(va->flags & VM_VM_AREA))
+ continue;
+
+ vm = va->vm;
+ vaddr = (char *) vm->addr;
+ if (addr >= vaddr + vm->size - PAGE_SIZE)
continue;
while (addr < vaddr) {
if (count == 0)
@@ -2062,10 +2046,10 @@ long vread(char *buf, char *addr, unsigned long count)
addr++;
count--;
}
- n = vaddr + tmp->size - PAGE_SIZE - addr;
+ n = vaddr + vm->size - PAGE_SIZE - addr;
if (n > count)
n = count;
- if (!(tmp->flags & VM_IOREMAP))
+ if (!(vm->flags & VM_IOREMAP))
aligned_vread(buf, addr, n);
else /* IOREMAP area is treated as memory hole */
memset(buf, 0, n);
@@ -2074,7 +2058,7 @@ long vread(char *buf, char *addr, unsigned long count)
count -= n;
}
finished:
- read_unlock(&vmlist_lock);
+ spin_unlock(&vmap_area_lock);
if (buf == buf_start)
return 0;
@@ -2113,7 +2097,8 @@ finished:
long vwrite(char *buf, char *addr, unsigned long count)
{
- struct vm_struct *tmp;
+ struct vmap_area *va;
+ struct vm_struct *vm;
char *vaddr;
unsigned long n, buflen;
int copied = 0;
@@ -2123,10 +2108,17 @@ long vwrite(char *buf, char *addr, unsigned long count)
count = -(unsigned long) addr;
buflen = count;
- read_lock(&vmlist_lock);
- for (tmp = vmlist; count && tmp; tmp = tmp->next) {
- vaddr = (char *) tmp->addr;
- if (addr >= vaddr + tmp->size - PAGE_SIZE)
+ spin_lock(&vmap_area_lock);
+ list_for_each_entry(va, &vmap_area_list, list) {
+ if (!count)
+ break;
+
+ if (!(va->flags & VM_VM_AREA))
+ continue;
+
+ vm = va->vm;
+ vaddr = (char *) vm->addr;
+ if (addr >= vaddr + vm->size - PAGE_SIZE)
continue;
while (addr < vaddr) {
if (count == 0)
@@ -2135,10 +2127,10 @@ long vwrite(char *buf, char *addr, unsigned long count)
addr++;
count--;
}
- n = vaddr + tmp->size - PAGE_SIZE - addr;
+ n = vaddr + vm->size - PAGE_SIZE - addr;
if (n > count)
n = count;
- if (!(tmp->flags & VM_IOREMAP)) {
+ if (!(vm->flags & VM_IOREMAP)) {
aligned_vwrite(buf, addr, n);
copied++;
}
@@ -2147,7 +2139,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
count -= n;
}
finished:
- read_unlock(&vmlist_lock);
+ spin_unlock(&vmap_area_lock);
if (!copied)
return 0;
return buflen;
@@ -2554,19 +2546,19 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms)
#ifdef CONFIG_PROC_FS
static void *s_start(struct seq_file *m, loff_t *pos)
- __acquires(&vmlist_lock)
+ __acquires(&vmap_area_lock)
{
loff_t n = *pos;
- struct vm_struct *v;
+ struct vmap_area *va;
- read_lock(&vmlist_lock);
- v = vmlist;
- while (n > 0 && v) {
+ spin_lock(&vmap_area_lock);
+ va = list_entry((&vmap_area_list)->next, typeof(*va), list);
+ while (n > 0 && &va->list != &vmap_area_list) {
n--;
- v = v->next;
+ va = list_entry(va->list.next, typeof(*va), list);
}
- if (!n)
- return v;
+ if (!n && &va->list != &vmap_area_list)
+ return va;
return NULL;
@@ -2574,16 +2566,20 @@ static void *s_start(struct seq_file *m, loff_t *pos)
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
{
- struct vm_struct *v = p;
+ struct vmap_area *va = p, *next;
++*pos;
- return v->next;
+ next = list_entry(va->list.next, typeof(*va), list);
+ if (&next->list != &vmap_area_list)
+ return next;
+
+ return NULL;
}
static void s_stop(struct seq_file *m, void *p)
- __releases(&vmlist_lock)
+ __releases(&vmap_area_lock)
{
- read_unlock(&vmlist_lock);
+ spin_unlock(&vmap_area_lock);
}
static void show_numa_info(struct seq_file *m, struct vm_struct *v)
@@ -2594,6 +2590,11 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)
if (!counters)
return;
+ /* Pair with smp_wmb() in clear_vm_unlist() */
+ smp_rmb();
+ if (v->flags & VM_UNLIST)
+ return;
+
memset(counters, 0, nr_node_ids * sizeof(unsigned int));
for (nr = 0; nr < v->nr_pages; nr++)
@@ -2607,7 +2608,20 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)
static int s_show(struct seq_file *m, void *p)
{
- struct vm_struct *v = p;
+ struct vmap_area *va = p;
+ struct vm_struct *v;
+
+ if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
+ return 0;
+
+ if (!(va->flags & VM_VM_AREA)) {
+ seq_printf(m, "0x%pK-0x%pK %7ld vm_map_ram\n",
+ (void *)va->va_start, (void *)va->va_end,
+ va->va_end - va->va_start);
+ return 0;
+ }
+
+ v = va->vm;
seq_printf(m, "0x%pK-0x%pK %7ld",
v->addr, v->addr + v->size, v->size);
@@ -2680,5 +2694,53 @@ static int __init proc_vmalloc_init(void)
return 0;
}
module_init(proc_vmalloc_init);
+
+void get_vmalloc_info(struct vmalloc_info *vmi)
+{
+ struct vmap_area *va;
+ unsigned long free_area_size;
+ unsigned long prev_end;
+
+ vmi->used = 0;
+ vmi->largest_chunk = 0;
+
+ prev_end = VMALLOC_START;
+
+ spin_lock(&vmap_area_lock);
+
+ if (list_empty(&vmap_area_list)) {
+ vmi->largest_chunk = VMALLOC_TOTAL;
+ goto out;
+ }
+
+ list_for_each_entry(va, &vmap_area_list, list) {
+ unsigned long addr = va->va_start;
+
+ /*
+ * Some archs keep another range for modules in vmalloc space
+ */
+ if (addr < VMALLOC_START)
+ continue;
+ if (addr >= VMALLOC_END)
+ break;
+
+ if (va->flags & (VM_LAZY_FREE | VM_LAZY_FREEING))
+ continue;
+
+ vmi->used += (va->va_end - va->va_start);
+
+ free_area_size = addr - prev_end;
+ if (vmi->largest_chunk < free_area_size)
+ vmi->largest_chunk = free_area_size;
+
+ prev_end = va->va_end;
+ }
+
+ if (VMALLOC_END - prev_end > vmi->largest_chunk)
+ vmi->largest_chunk = VMALLOC_END - prev_end;
+
+out:
+ spin_unlock(&vmap_area_lock);
+}
#endif
diff --git a/mm/vmpressure.c b/mm/vmpressure.c
new file mode 100644
index 000000000000..736a6011c2c8
--- /dev/null
+++ b/mm/vmpressure.c
@@ -0,0 +1,374 @@
+/*
+ * Linux VM pressure
+ *
+ * Copyright 2012 Linaro Ltd.
+ * Anton Vorontsov <anton.vorontsov@linaro.org>
+ *
+ * Based on ideas from Andrew Morton, David Rientjes, KOSAKI Motohiro,
+ * Leonid Moiseichuk, Mel Gorman, Minchan Kim and Pekka Enberg.
+ *
+ * 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/cgroup.h>
+#include <linux/fs.h>
+#include <linux/log2.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmstat.h>
+#include <linux/eventfd.h>
+#include <linux/swap.h>
+#include <linux/printk.h>
+#include <linux/vmpressure.h>
+
+/*
+ * The window size (vmpressure_win) is the number of scanned pages before
+ * we try to analyze scanned/reclaimed ratio. So the window is used as a
+ * rate-limit tunable for the "low" level notification, and also for
+ * averaging the ratio for medium/critical levels. Using small window
+ * sizes can cause lot of false positives, but too big window size will
+ * delay the notifications.
+ *
+ * As the vmscan reclaimer logic works with chunks which are multiple of
+ * SWAP_CLUSTER_MAX, it makes sense to use it for the window size as well.
+ *
+ * TODO: Make the window size depend on machine size, as we do for vmstat
+ * thresholds. Currently we set it to 512 pages (2MB for 4KB pages).
+ */
+static const unsigned long vmpressure_win = SWAP_CLUSTER_MAX * 16;
+
+/*
+ * These thresholds are used when we account memory pressure through
+ * scanned/reclaimed ratio. The current values were chosen empirically. In
+ * essence, they are percents: the higher the value, the more number
+ * unsuccessful reclaims there were.
+ */
+static const unsigned int vmpressure_level_med = 60;
+static const unsigned int vmpressure_level_critical = 95;
+
+/*
+ * When there are too little pages left to scan, vmpressure() may miss the
+ * critical pressure as number of pages will be less than "window size".
+ * However, in that case the vmscan priority will raise fast as the
+ * reclaimer will try to scan LRUs more deeply.
+ *
+ * The vmscan logic considers these special priorities:
+ *
+ * prio == DEF_PRIORITY (12): reclaimer starts with that value
+ * prio <= DEF_PRIORITY - 2 : kswapd becomes somewhat overwhelmed
+ * prio == 0 : close to OOM, kernel scans every page in an lru
+ *
+ * Any value in this range is acceptable for this tunable (i.e. from 12 to
+ * 0). Current value for the vmpressure_level_critical_prio is chosen
+ * empirically, but the number, in essence, means that we consider
+ * critical level when scanning depth is ~10% of the lru size (vmscan
+ * scans 'lru_size >> prio' pages, so it is actually 12.5%, or one
+ * eights).
+ */
+static const unsigned int vmpressure_level_critical_prio = ilog2(100 / 10);
+
+static struct vmpressure *work_to_vmpressure(struct work_struct *work)
+{
+ return container_of(work, struct vmpressure, work);
+}
+
+static struct vmpressure *cg_to_vmpressure(struct cgroup *cg)
+{
+ return css_to_vmpressure(cgroup_subsys_state(cg, mem_cgroup_subsys_id));
+}
+
+static struct vmpressure *vmpressure_parent(struct vmpressure *vmpr)
+{
+ struct cgroup *cg = vmpressure_to_css(vmpr)->cgroup;
+ struct mem_cgroup *memcg = mem_cgroup_from_cont(cg);
+
+ memcg = parent_mem_cgroup(memcg);
+ if (!memcg)
+ return NULL;
+ return memcg_to_vmpressure(memcg);
+}
+
+enum vmpressure_levels {
+ VMPRESSURE_LOW = 0,
+ VMPRESSURE_MEDIUM,
+ VMPRESSURE_CRITICAL,
+ VMPRESSURE_NUM_LEVELS,
+};
+
+static const char * const vmpressure_str_levels[] = {
+ [VMPRESSURE_LOW] = "low",
+ [VMPRESSURE_MEDIUM] = "medium",
+ [VMPRESSURE_CRITICAL] = "critical",
+};
+
+static enum vmpressure_levels vmpressure_level(unsigned long pressure)
+{
+ if (pressure >= vmpressure_level_critical)
+ return VMPRESSURE_CRITICAL;
+ else if (pressure >= vmpressure_level_med)
+ return VMPRESSURE_MEDIUM;
+ return VMPRESSURE_LOW;
+}
+
+static enum vmpressure_levels vmpressure_calc_level(unsigned long scanned,
+ unsigned long reclaimed)
+{
+ unsigned long scale = scanned + reclaimed;
+ unsigned long pressure;
+
+ /*
+ * We calculate the ratio (in percents) of how many pages were
+ * scanned vs. reclaimed in a given time frame (window). Note that
+ * time is in VM reclaimer's "ticks", i.e. number of pages
+ * scanned. This makes it possible to set desired reaction time
+ * and serves as a ratelimit.
+ */
+ pressure = scale - (reclaimed * scale / scanned);
+ pressure = pressure * 100 / scale;
+
+ pr_debug("%s: %3lu (s: %lu r: %lu)\n", __func__, pressure,
+ scanned, reclaimed);
+
+ return vmpressure_level(pressure);
+}
+
+struct vmpressure_event {
+ struct eventfd_ctx *efd;
+ enum vmpressure_levels level;
+ struct list_head node;
+};
+
+static bool vmpressure_event(struct vmpressure *vmpr,
+ unsigned long scanned, unsigned long reclaimed)
+{
+ struct vmpressure_event *ev;
+ enum vmpressure_levels level;
+ bool signalled = false;
+
+ level = vmpressure_calc_level(scanned, reclaimed);
+
+ mutex_lock(&vmpr->events_lock);
+
+ list_for_each_entry(ev, &vmpr->events, node) {
+ if (level >= ev->level) {
+ eventfd_signal(ev->efd, 1);
+ signalled = true;
+ }
+ }
+
+ mutex_unlock(&vmpr->events_lock);
+
+ return signalled;
+}
+
+static void vmpressure_work_fn(struct work_struct *work)
+{
+ struct vmpressure *vmpr = work_to_vmpressure(work);
+ unsigned long scanned;
+ unsigned long reclaimed;
+
+ /*
+ * Several contexts might be calling vmpressure(), so it is
+ * possible that the work was rescheduled again before the old
+ * work context cleared the counters. In that case we will run
+ * just after the old work returns, but then scanned might be zero
+ * here. No need for any locks here since we don't care if
+ * vmpr->reclaimed is in sync.
+ */
+ if (!vmpr->scanned)
+ return;
+
+ mutex_lock(&vmpr->sr_lock);
+ scanned = vmpr->scanned;
+ reclaimed = vmpr->reclaimed;
+ vmpr->scanned = 0;
+ vmpr->reclaimed = 0;
+ mutex_unlock(&vmpr->sr_lock);
+
+ do {
+ if (vmpressure_event(vmpr, scanned, reclaimed))
+ break;
+ /*
+ * If not handled, propagate the event upward into the
+ * hierarchy.
+ */
+ } while ((vmpr = vmpressure_parent(vmpr)));
+}
+
+/**
+ * vmpressure() - Account memory pressure through scanned/reclaimed ratio
+ * @gfp: reclaimer's gfp mask
+ * @memcg: cgroup memory controller handle
+ * @scanned: number of pages scanned
+ * @reclaimed: number of pages reclaimed
+ *
+ * This function should be called from the vmscan reclaim path to account
+ * "instantaneous" memory pressure (scanned/reclaimed ratio). The raw
+ * pressure index is then further refined and averaged over time.
+ *
+ * This function does not return any value.
+ */
+void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
+ unsigned long scanned, unsigned long reclaimed)
+{
+ struct vmpressure *vmpr = memcg_to_vmpressure(memcg);
+
+ /*
+ * Here we only want to account pressure that userland is able to
+ * help us with. For example, suppose that DMA zone is under
+ * pressure; if we notify userland about that kind of pressure,
+ * then it will be mostly a waste as it will trigger unnecessary
+ * freeing of memory by userland (since userland is more likely to
+ * have HIGHMEM/MOVABLE pages instead of the DMA fallback). That
+ * is why we include only movable, highmem and FS/IO pages.
+ * Indirect reclaim (kswapd) sets sc->gfp_mask to GFP_KERNEL, so
+ * we account it too.
+ */
+ if (!(gfp & (__GFP_HIGHMEM | __GFP_MOVABLE | __GFP_IO | __GFP_FS)))
+ return;
+
+ /*
+ * If we got here with no pages scanned, then that is an indicator
+ * that reclaimer was unable to find any shrinkable LRUs at the
+ * current scanning depth. But it does not mean that we should
+ * report the critical pressure, yet. If the scanning priority
+ * (scanning depth) goes too high (deep), we will be notified
+ * through vmpressure_prio(). But so far, keep calm.
+ */
+ if (!scanned)
+ return;
+
+ mutex_lock(&vmpr->sr_lock);
+ vmpr->scanned += scanned;
+ vmpr->reclaimed += reclaimed;
+ scanned = vmpr->scanned;
+ mutex_unlock(&vmpr->sr_lock);
+
+ if (scanned < vmpressure_win || work_pending(&vmpr->work))
+ return;
+ schedule_work(&vmpr->work);
+}
+
+/**
+ * vmpressure_prio() - Account memory pressure through reclaimer priority level
+ * @gfp: reclaimer's gfp mask
+ * @memcg: cgroup memory controller handle
+ * @prio: reclaimer's priority
+ *
+ * This function should be called from the reclaim path every time when
+ * the vmscan's reclaiming priority (scanning depth) changes.
+ *
+ * This function does not return any value.
+ */
+void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio)
+{
+ /*
+ * We only use prio for accounting critical level. For more info
+ * see comment for vmpressure_level_critical_prio variable above.
+ */
+ if (prio > vmpressure_level_critical_prio)
+ return;
+
+ /*
+ * OK, the prio is below the threshold, updating vmpressure
+ * information before shrinker dives into long shrinking of long
+ * range vmscan. Passing scanned = vmpressure_win, reclaimed = 0
+ * to the vmpressure() basically means that we signal 'critical'
+ * level.
+ */
+ vmpressure(gfp, memcg, vmpressure_win, 0);
+}
+
+/**
+ * vmpressure_register_event() - Bind vmpressure notifications to an eventfd
+ * @cg: cgroup that is interested in vmpressure notifications
+ * @cft: cgroup control files handle
+ * @eventfd: eventfd context to link notifications with
+ * @args: event arguments (used to set up a pressure level threshold)
+ *
+ * This function associates eventfd context with the vmpressure
+ * infrastructure, so that the notifications will be delivered to the
+ * @eventfd. The @args parameter is a string that denotes pressure level
+ * threshold (one of vmpressure_str_levels, i.e. "low", "medium", or
+ * "critical").
+ *
+ * This function should not be used directly, just pass it to (struct
+ * cftype).register_event, and then cgroup core will handle everything by
+ * itself.
+ */
+int vmpressure_register_event(struct cgroup *cg, struct cftype *cft,
+ struct eventfd_ctx *eventfd, const char *args)
+{
+ struct vmpressure *vmpr = cg_to_vmpressure(cg);
+ struct vmpressure_event *ev;
+ int level;
+
+ for (level = 0; level < VMPRESSURE_NUM_LEVELS; level++) {
+ if (!strcmp(vmpressure_str_levels[level], args))
+ break;
+ }
+
+ if (level >= VMPRESSURE_NUM_LEVELS)
+ return -EINVAL;
+
+ ev = kzalloc(sizeof(*ev), GFP_KERNEL);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->efd = eventfd;
+ ev->level = level;
+
+ mutex_lock(&vmpr->events_lock);
+ list_add(&ev->node, &vmpr->events);
+ mutex_unlock(&vmpr->events_lock);
+
+ return 0;
+}
+
+/**
+ * vmpressure_unregister_event() - Unbind eventfd from vmpressure
+ * @cg: cgroup handle
+ * @cft: cgroup control files handle
+ * @eventfd: eventfd context that was used to link vmpressure with the @cg
+ *
+ * This function does internal manipulations to detach the @eventfd from
+ * the vmpressure notifications, and then frees internal resources
+ * associated with the @eventfd (but the @eventfd itself is not freed).
+ *
+ * This function should not be used directly, just pass it to (struct
+ * cftype).unregister_event, and then cgroup core will handle everything
+ * by itself.
+ */
+void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
+ struct eventfd_ctx *eventfd)
+{
+ struct vmpressure *vmpr = cg_to_vmpressure(cg);
+ struct vmpressure_event *ev;
+
+ mutex_lock(&vmpr->events_lock);
+ list_for_each_entry(ev, &vmpr->events, node) {
+ if (ev->efd != eventfd)
+ continue;
+ list_del(&ev->node);
+ kfree(ev);
+ break;
+ }
+ mutex_unlock(&vmpr->events_lock);
+}
+
+/**
+ * vmpressure_init() - Initialize vmpressure control structure
+ * @vmpr: Structure to be initialized
+ *
+ * This function should be called on every allocated vmpressure structure
+ * before any usage.
+ */
+void vmpressure_init(struct vmpressure *vmpr)
+{
+ mutex_init(&vmpr->sr_lock);
+ mutex_init(&vmpr->events_lock);
+ INIT_LIST_HEAD(&vmpr->events);
+ INIT_WORK(&vmpr->work, vmpressure_work_fn);
+}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 88c5fed8b9a4..fa6a85378ee4 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -19,6 +19,7 @@
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/highmem.h>
+#include <linux/vmpressure.h>
#include <linux/vmstat.h>
#include <linux/file.h>
#include <linux/writeback.h>
@@ -780,7 +781,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
if (PageAnon(page) && !PageSwapCache(page)) {
if (!(sc->gfp_mask & __GFP_IO))
goto keep_locked;
- if (!add_to_swap(page))
+ if (!add_to_swap(page, page_list))
goto activate_locked;
may_enter_fs = 1;
}
@@ -1982,6 +1983,11 @@ static void shrink_zone(struct zone *zone, struct scan_control *sc)
}
memcg = mem_cgroup_iter(root, memcg, &reclaim);
} while (memcg);
+
+ vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
+ sc->nr_scanned - nr_scanned,
+ sc->nr_reclaimed - nr_reclaimed);
+
} while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed,
sc->nr_scanned - nr_scanned, sc));
}
@@ -2167,6 +2173,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
count_vm_event(ALLOCSTALL);
do {
+ vmpressure_prio(sc->gfp_mask, sc->target_mem_cgroup,
+ sc->priority);
sc->nr_scanned = 0;
aborted_reclaim = shrink_zones(zonelist, sc);
@@ -2619,7 +2627,6 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
bool pgdat_is_balanced = false;
int i;
int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
- unsigned long total_scanned;
struct reclaim_state *reclaim_state = current->reclaim_state;
unsigned long nr_soft_reclaimed;
unsigned long nr_soft_scanned;
@@ -2639,7 +2646,6 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
.gfp_mask = sc.gfp_mask,
};
loop_again:
- total_scanned = 0;
sc.priority = DEF_PRIORITY;
sc.nr_reclaimed = 0;
sc.may_writepage = !laptop_mode;
@@ -2730,7 +2736,6 @@ loop_again:
order, sc.gfp_mask,
&nr_soft_scanned);
sc.nr_reclaimed += nr_soft_reclaimed;
- total_scanned += nr_soft_scanned;
/*
* We put equal pressure on every zone, unless
@@ -2765,7 +2770,6 @@ loop_again:
reclaim_state->reclaimed_slab = 0;
nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
sc.nr_reclaimed += reclaim_state->reclaimed_slab;
- total_scanned += sc.nr_scanned;
if (nr_slab == 0 && !zone_reclaimable(zone))
zone->all_unreclaimable = 1;
@@ -3188,9 +3192,9 @@ int kswapd_run(int nid)
if (IS_ERR(pgdat->kswapd)) {
/* failure at boot is fatal */
BUG_ON(system_state == SYSTEM_BOOTING);
- pgdat->kswapd = NULL;
pr_err("Failed to start kswapd on node %d\n", nid);
ret = PTR_ERR(pgdat->kswapd);
+ pgdat->kswapd = NULL;
}
return ret;
}
diff --git a/mm/vmstat.c b/mm/vmstat.c
index e1d8ed172c42..f42745e65780 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -52,7 +52,6 @@ void all_vm_events(unsigned long *ret)
}
EXPORT_SYMBOL_GPL(all_vm_events);
-#ifdef CONFIG_HOTPLUG
/*
* Fold the foreign cpu events into our own.
*
@@ -69,7 +68,6 @@ void vm_events_fold_cpu(int cpu)
fold_state->event[i] = 0;
}
}
-#endif /* CONFIG_HOTPLUG */
#endif /* CONFIG_VM_EVENT_COUNTERS */
@@ -495,6 +493,10 @@ void refresh_cpu_vm_stats(int cpu)
atomic_long_add(global_diff[i], &vm_stat[i]);
}
+/*
+ * this is only called if !populated_zone(zone), which implies no other users of
+ * pset->vm_stat_diff[] exsist.
+ */
void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset)
{
int i;
diff --git a/net/802/garp.c b/net/802/garp.c
index 8456f5d98b85..5d9630a0eb93 100644
--- a/net/802/garp.c
+++ b/net/802/garp.c
@@ -609,8 +609,12 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl
/* Delete timer and generate a final TRANSMIT_PDU event to flush out
* all pending messages before the applicant is gone. */
del_timer_sync(&app->join_timer);
+
+ spin_lock_bh(&app->lock);
garp_gid_event(app, GARP_EVENT_TRANSMIT_PDU);
garp_pdu_queue(app);
+ spin_unlock_bh(&app->lock);
+
garp_queue_xmit(app);
dev_mc_del(dev, appl->proto.group_address);
diff --git a/net/802/mrp.c b/net/802/mrp.c
index a4cc3229952a..e085bcc754f6 100644
--- a/net/802/mrp.c
+++ b/net/802/mrp.c
@@ -870,8 +870,12 @@ void mrp_uninit_applicant(struct net_device *dev, struct mrp_application *appl)
* all pending messages before the applicant is gone.
*/
del_timer_sync(&app->join_timer);
+
+ spin_lock(&app->lock);
mrp_mad_event(app, MRP_EVENT_TX);
mrp_pdu_queue(app);
+ spin_unlock(&app->lock);
+
mrp_queue_xmit(app);
dev_mc_del(dev, appl->group_address);
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
index 8f7517df41a5..b85a91fa61f1 100644
--- a/net/8021q/Kconfig
+++ b/net/8021q/Kconfig
@@ -3,7 +3,7 @@
#
config VLAN_8021Q
- tristate "802.1Q VLAN Support"
+ tristate "802.1Q/802.1ad VLAN Support"
---help---
Select this and you will be able to create 802.1Q VLAN interfaces
on your ethernet interfaces. 802.1Q VLAN supports almost
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 85addcd9372b..9424f3718ea7 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -51,14 +51,18 @@ const char vlan_version[] = DRV_VERSION;
/* End of global variables definitions. */
-static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
+static int vlan_group_prealloc_vid(struct vlan_group *vg,
+ __be16 vlan_proto, u16 vlan_id)
{
struct net_device **array;
+ unsigned int pidx, vidx;
unsigned int size;
ASSERT_RTNL();
- array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
+ pidx = vlan_proto_idx(vlan_proto);
+ vidx = vlan_id / VLAN_GROUP_ARRAY_PART_LEN;
+ array = vg->vlan_devices_arrays[pidx][vidx];
if (array != NULL)
return 0;
@@ -67,7 +71,7 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, u16 vlan_id)
if (array == NULL)
return -ENOBUFS;
- vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN] = array;
+ vg->vlan_devices_arrays[pidx][vidx] = array;
return 0;
}
@@ -93,7 +97,7 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
if (vlan->flags & VLAN_FLAG_GVRP)
vlan_gvrp_request_leave(dev);
- vlan_group_set_device(grp, vlan_id, NULL);
+ vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, NULL);
/* Because unregister_netdevice_queue() makes sure at least one rcu
* grace period is respected before device freeing,
* we dont need to call synchronize_net() here.
@@ -112,13 +116,14 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
* VLAN is not 0 (leave it there for 802.1p).
*/
if (vlan_id)
- vlan_vid_del(real_dev, vlan_id);
+ vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
/* Get rid of the vlan's reference to real_dev */
dev_put(real_dev);
}
-int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
+int vlan_check_real_dev(struct net_device *real_dev,
+ __be16 protocol, u16 vlan_id)
{
const char *name = real_dev->name;
@@ -127,7 +132,7 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
return -EOPNOTSUPP;
}
- if (vlan_find_dev(real_dev, vlan_id) != NULL)
+ if (vlan_find_dev(real_dev, protocol, vlan_id) != NULL)
return -EEXIST;
return 0;
@@ -142,7 +147,7 @@ int register_vlan_dev(struct net_device *dev)
struct vlan_group *grp;
int err;
- err = vlan_vid_add(real_dev, vlan_id);
+ err = vlan_vid_add(real_dev, vlan->vlan_proto, vlan_id);
if (err)
return err;
@@ -160,7 +165,7 @@ int register_vlan_dev(struct net_device *dev)
goto out_uninit_gvrp;
}
- err = vlan_group_prealloc_vid(grp, vlan_id);
+ err = vlan_group_prealloc_vid(grp, vlan->vlan_proto, vlan_id);
if (err < 0)
goto out_uninit_mvrp;
@@ -181,7 +186,7 @@ int register_vlan_dev(struct net_device *dev)
/* So, got the sucker initialized, now lets place
* it into our local structure.
*/
- vlan_group_set_device(grp, vlan_id, dev);
+ vlan_group_set_device(grp, vlan->vlan_proto, vlan_id, dev);
grp->nr_vlan_devs++;
return 0;
@@ -195,7 +200,7 @@ out_uninit_gvrp:
if (grp->nr_vlan_devs == 0)
vlan_gvrp_uninit_applicant(real_dev);
out_vid_del:
- vlan_vid_del(real_dev, vlan_id);
+ vlan_vid_del(real_dev, vlan->vlan_proto, vlan_id);
return err;
}
@@ -213,7 +218,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
if (vlan_id >= VLAN_VID_MASK)
return -ERANGE;
- err = vlan_check_real_dev(real_dev, vlan_id);
+ err = vlan_check_real_dev(real_dev, htons(ETH_P_8021Q), vlan_id);
if (err < 0)
return err;
@@ -255,6 +260,7 @@ static int register_vlan_device(struct net_device *real_dev, u16 vlan_id)
new_dev->mtu = real_dev->mtu;
new_dev->priv_flags |= (real_dev->priv_flags & IFF_UNICAST_FLT);
+ vlan_dev_priv(new_dev)->vlan_proto = htons(ETH_P_8021Q);
vlan_dev_priv(new_dev)->vlan_id = vlan_id;
vlan_dev_priv(new_dev)->real_dev = real_dev;
vlan_dev_priv(new_dev)->dent = NULL;
@@ -301,7 +307,7 @@ static void vlan_transfer_features(struct net_device *dev,
{
vlandev->gso_max_size = dev->gso_max_size;
- if (dev->features & NETIF_F_HW_VLAN_TX)
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
vlandev->hard_header_len = dev->hard_header_len;
else
vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
@@ -341,16 +347,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
int i, flgs;
struct net_device *vlandev;
struct vlan_dev_priv *vlan;
+ bool last = false;
LIST_HEAD(list);
if (is_vlan_dev(dev))
__vlan_device_event(dev, event);
if ((event == NETDEV_UP) &&
- (dev->features & NETIF_F_HW_VLAN_FILTER)) {
+ (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
pr_info("adding VLAN 0 to HW filter on device %s\n",
dev->name);
- vlan_vid_add(dev, 0);
+ vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
}
vlan_info = rtnl_dereference(dev->vlan_info);
@@ -365,22 +372,13 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
switch (event) {
case NETDEV_CHANGE:
/* Propagate real device state to vlan devices */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev)
netif_stacked_transfer_operstate(dev, vlandev);
- }
break;
case NETDEV_CHANGEADDR:
/* Adjust unicast filters on underlying device */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (!(flgs & IFF_UP))
continue;
@@ -390,11 +388,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
break;
case NETDEV_CHANGEMTU:
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev) {
if (vlandev->mtu <= dev->mtu)
continue;
@@ -404,26 +398,16 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_FEAT_CHANGE:
/* Propagate device features to underlying device */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev)
vlan_transfer_features(dev, vlandev);
- }
-
break;
case NETDEV_DOWN:
- if (dev->features & NETIF_F_HW_VLAN_FILTER)
- vlan_vid_del(dev, 0);
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
/* Put all VLANs for this dev in the down state too. */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (!(flgs & IFF_UP))
continue;
@@ -437,11 +421,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_UP:
/* Put all VLANs for this dev in the up state too. */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev) {
flgs = vlandev->flags;
if (flgs & IFF_UP)
continue;
@@ -458,17 +438,15 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (dev->reg_state != NETREG_UNREGISTERING)
break;
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev) {
/* removal of last vid destroys vlan_info, abort
* afterwards */
if (vlan_info->nr_vids == 1)
- i = VLAN_N_VID;
+ last = true;
unregister_vlan_dev(vlandev, &list);
+ if (last)
+ break;
}
unregister_netdevice_many(&list);
break;
@@ -482,13 +460,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_NOTIFY_PEERS:
case NETDEV_BONDING_FAILOVER:
/* Propagate to vlan devices */
- for (i = 0; i < VLAN_N_VID; i++) {
- vlandev = vlan_group_get_device(grp, i);
- if (!vlandev)
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev)
call_netdevice_notifiers(event, vlandev);
- }
break;
}
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 670f1e8cfc0f..ba5983f34c42 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -49,6 +49,7 @@ struct netpoll;
* @ingress_priority_map: ingress priority mappings
* @nr_egress_mappings: number of egress priority mappings
* @egress_priority_map: hash of egress priority mappings
+ * @vlan_proto: VLAN encapsulation protocol
* @vlan_id: VLAN identifier
* @flags: device flags
* @real_dev: underlying netdevice
@@ -62,6 +63,7 @@ struct vlan_dev_priv {
unsigned int nr_egress_mappings;
struct vlan_priority_tci_mapping *egress_priority_map[16];
+ __be16 vlan_proto;
u16 vlan_id;
u16 flags;
@@ -87,10 +89,17 @@ static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev)
#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8
#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_N_VID/VLAN_GROUP_ARRAY_SPLIT_PARTS)
+enum vlan_protos {
+ VLAN_PROTO_8021Q = 0,
+ VLAN_PROTO_8021AD,
+ VLAN_PROTO_NUM,
+};
+
struct vlan_group {
unsigned int nr_vlan_devs;
struct hlist_node hlist; /* linked list */
- struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS];
+ struct net_device **vlan_devices_arrays[VLAN_PROTO_NUM]
+ [VLAN_GROUP_ARRAY_SPLIT_PARTS];
};
struct vlan_info {
@@ -103,37 +112,67 @@ struct vlan_info {
struct rcu_head rcu;
};
-static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
- u16 vlan_id)
+static inline unsigned int vlan_proto_idx(__be16 proto)
+{
+ switch (proto) {
+ case __constant_htons(ETH_P_8021Q):
+ return VLAN_PROTO_8021Q;
+ case __constant_htons(ETH_P_8021AD):
+ return VLAN_PROTO_8021AD;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+static inline struct net_device *__vlan_group_get_device(struct vlan_group *vg,
+ unsigned int pidx,
+ u16 vlan_id)
{
struct net_device **array;
- array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
+
+ array = vg->vlan_devices_arrays[pidx]
+ [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL;
}
+static inline struct net_device *vlan_group_get_device(struct vlan_group *vg,
+ __be16 vlan_proto,
+ u16 vlan_id)
+{
+ return __vlan_group_get_device(vg, vlan_proto_idx(vlan_proto), vlan_id);
+}
+
static inline void vlan_group_set_device(struct vlan_group *vg,
- u16 vlan_id,
+ __be16 vlan_proto, u16 vlan_id,
struct net_device *dev)
{
struct net_device **array;
if (!vg)
return;
- array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
+ array = vg->vlan_devices_arrays[vlan_proto_idx(vlan_proto)]
+ [vlan_id / VLAN_GROUP_ARRAY_PART_LEN];
array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
}
/* Must be invoked with rcu_read_lock or with RTNL. */
static inline struct net_device *vlan_find_dev(struct net_device *real_dev,
- u16 vlan_id)
+ __be16 vlan_proto, u16 vlan_id)
{
struct vlan_info *vlan_info = rcu_dereference_rtnl(real_dev->vlan_info);
if (vlan_info)
- return vlan_group_get_device(&vlan_info->grp, vlan_id);
+ return vlan_group_get_device(&vlan_info->grp,
+ vlan_proto, vlan_id);
return NULL;
}
+#define vlan_group_for_each_dev(grp, i, dev) \
+ for ((i) = 0; i < VLAN_PROTO_NUM * VLAN_N_VID; i++) \
+ if (((dev) = __vlan_group_get_device((grp), (i) / VLAN_N_VID, \
+ (i) % VLAN_N_VID)))
+
/* found in vlan_dev.c */
void vlan_dev_set_ingress_priority(const struct net_device *dev,
u32 skb_prio, u16 vlan_prio);
@@ -142,7 +181,8 @@ int vlan_dev_set_egress_priority(const struct net_device *dev,
int vlan_dev_change_flags(const struct net_device *dev, u32 flag, u32 mask);
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
-int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id);
+int vlan_check_real_dev(struct net_device *real_dev,
+ __be16 protocol, u16 vlan_id);
void vlan_setup(struct net_device *dev);
int register_vlan_dev(struct net_device *dev);
void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index f3b6f515eba6..8a15eaadc4bd 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -8,11 +8,12 @@
bool vlan_do_receive(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
+ __be16 vlan_proto = skb->vlan_proto;
u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
struct net_device *vlan_dev;
struct vlan_pcpu_stats *rx_stats;
- vlan_dev = vlan_find_dev(skb->dev, vlan_id);
+ vlan_dev = vlan_find_dev(skb->dev, vlan_proto, vlan_id);
if (!vlan_dev)
return false;
@@ -38,7 +39,8 @@ bool vlan_do_receive(struct sk_buff **skbp)
* original position later
*/
skb_push(skb, offset);
- skb = *skbp = vlan_insert_tag(skb, skb->vlan_tci);
+ skb = *skbp = vlan_insert_tag(skb, skb->vlan_proto,
+ skb->vlan_tci);
if (!skb)
return false;
skb_pull(skb, offset + VLAN_HLEN);
@@ -62,12 +64,13 @@ bool vlan_do_receive(struct sk_buff **skbp)
/* Must be invoked with rcu_read_lock. */
struct net_device *__vlan_find_dev_deep(struct net_device *dev,
- u16 vlan_id)
+ __be16 vlan_proto, u16 vlan_id)
{
struct vlan_info *vlan_info = rcu_dereference(dev->vlan_info);
if (vlan_info) {
- return vlan_group_get_device(&vlan_info->grp, vlan_id);
+ return vlan_group_get_device(&vlan_info->grp,
+ vlan_proto, vlan_id);
} else {
/*
* Lower devices of master uppers (bonding, team) do not have
@@ -78,7 +81,8 @@ struct net_device *__vlan_find_dev_deep(struct net_device *dev,
upper_dev = netdev_master_upper_dev_get_rcu(dev);
if (upper_dev)
- return __vlan_find_dev_deep(upper_dev, vlan_id);
+ return __vlan_find_dev_deep(upper_dev,
+ vlan_proto, vlan_id);
}
return NULL;
@@ -125,7 +129,7 @@ struct sk_buff *vlan_untag(struct sk_buff *skb)
vhdr = (struct vlan_hdr *) skb->data;
vlan_tci = ntohs(vhdr->h_vlan_TCI);
- __vlan_hwaccel_put_tag(skb, vlan_tci);
+ __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci);
skb_pull_rcsum(skb, VLAN_HLEN);
vlan_set_encap_proto(skb, vhdr);
@@ -153,10 +157,11 @@ EXPORT_SYMBOL(vlan_untag);
static void vlan_group_free(struct vlan_group *grp)
{
- int i;
+ int i, j;
- for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++)
- kfree(grp->vlan_devices_arrays[i]);
+ for (i = 0; i < VLAN_PROTO_NUM; i++)
+ for (j = 0; j < VLAN_GROUP_ARRAY_SPLIT_PARTS; j++)
+ kfree(grp->vlan_devices_arrays[i][j]);
}
static void vlan_info_free(struct vlan_info *vlan_info)
@@ -185,35 +190,49 @@ static struct vlan_info *vlan_info_alloc(struct net_device *dev)
struct vlan_vid_info {
struct list_head list;
- unsigned short vid;
+ __be16 proto;
+ u16 vid;
int refcount;
};
+static bool vlan_hw_filter_capable(const struct net_device *dev,
+ const struct vlan_vid_info *vid_info)
+{
+ if (vid_info->proto == htons(ETH_P_8021Q) &&
+ dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ return true;
+ if (vid_info->proto == htons(ETH_P_8021AD) &&
+ dev->features & NETIF_F_HW_VLAN_STAG_FILTER)
+ return true;
+ return false;
+}
+
static struct vlan_vid_info *vlan_vid_info_get(struct vlan_info *vlan_info,
- unsigned short vid)
+ __be16 proto, u16 vid)
{
struct vlan_vid_info *vid_info;
list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
- if (vid_info->vid == vid)
+ if (vid_info->proto == proto && vid_info->vid == vid)
return vid_info;
}
return NULL;
}
-static struct vlan_vid_info *vlan_vid_info_alloc(unsigned short vid)
+static struct vlan_vid_info *vlan_vid_info_alloc(__be16 proto, u16 vid)
{
struct vlan_vid_info *vid_info;
vid_info = kzalloc(sizeof(struct vlan_vid_info), GFP_KERNEL);
if (!vid_info)
return NULL;
+ vid_info->proto = proto;
vid_info->vid = vid;
return vid_info;
}
-static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,
+static int __vlan_vid_add(struct vlan_info *vlan_info, __be16 proto, u16 vid,
struct vlan_vid_info **pvid_info)
{
struct net_device *dev = vlan_info->real_dev;
@@ -221,12 +240,12 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,
struct vlan_vid_info *vid_info;
int err;
- vid_info = vlan_vid_info_alloc(vid);
+ vid_info = vlan_vid_info_alloc(proto, vid);
if (!vid_info)
return -ENOMEM;
- if (dev->features & NETIF_F_HW_VLAN_FILTER) {
- err = ops->ndo_vlan_rx_add_vid(dev, vid);
+ if (vlan_hw_filter_capable(dev, vid_info)) {
+ err = ops->ndo_vlan_rx_add_vid(dev, proto, vid);
if (err) {
kfree(vid_info);
return err;
@@ -238,7 +257,7 @@ static int __vlan_vid_add(struct vlan_info *vlan_info, unsigned short vid,
return 0;
}
-int vlan_vid_add(struct net_device *dev, unsigned short vid)
+int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)
{
struct vlan_info *vlan_info;
struct vlan_vid_info *vid_info;
@@ -254,9 +273,9 @@ int vlan_vid_add(struct net_device *dev, unsigned short vid)
return -ENOMEM;
vlan_info_created = true;
}
- vid_info = vlan_vid_info_get(vlan_info, vid);
+ vid_info = vlan_vid_info_get(vlan_info, proto, vid);
if (!vid_info) {
- err = __vlan_vid_add(vlan_info, vid, &vid_info);
+ err = __vlan_vid_add(vlan_info, proto, vid, &vid_info);
if (err)
goto out_free_vlan_info;
}
@@ -279,14 +298,15 @@ static void __vlan_vid_del(struct vlan_info *vlan_info,
{
struct net_device *dev = vlan_info->real_dev;
const struct net_device_ops *ops = dev->netdev_ops;
- unsigned short vid = vid_info->vid;
+ __be16 proto = vid_info->proto;
+ u16 vid = vid_info->vid;
int err;
- if (dev->features & NETIF_F_HW_VLAN_FILTER) {
- err = ops->ndo_vlan_rx_kill_vid(dev, vid);
+ if (vlan_hw_filter_capable(dev, vid_info)) {
+ err = ops->ndo_vlan_rx_kill_vid(dev, proto, vid);
if (err) {
- pr_warn("failed to kill vid %d for device %s\n",
- vid, dev->name);
+ pr_warn("failed to kill vid %04x/%d for device %s\n",
+ proto, vid, dev->name);
}
}
list_del(&vid_info->list);
@@ -294,7 +314,7 @@ static void __vlan_vid_del(struct vlan_info *vlan_info,
vlan_info->nr_vids--;
}
-void vlan_vid_del(struct net_device *dev, unsigned short vid)
+void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid)
{
struct vlan_info *vlan_info;
struct vlan_vid_info *vid_info;
@@ -305,7 +325,7 @@ void vlan_vid_del(struct net_device *dev, unsigned short vid)
if (!vlan_info)
return;
- vid_info = vlan_vid_info_get(vlan_info, vid);
+ vid_info = vlan_vid_info_get(vlan_info, proto, vid);
if (!vid_info)
return;
vid_info->refcount--;
@@ -333,7 +353,7 @@ int vlan_vids_add_by_dev(struct net_device *dev,
return 0;
list_for_each_entry(vid_info, &vlan_info->vid_list, list) {
- err = vlan_vid_add(dev, vid_info->vid);
+ err = vlan_vid_add(dev, vid_info->proto, vid_info->vid);
if (err)
goto unwind;
}
@@ -343,7 +363,7 @@ unwind:
list_for_each_entry_continue_reverse(vid_info,
&vlan_info->vid_list,
list) {
- vlan_vid_del(dev, vid_info->vid);
+ vlan_vid_del(dev, vid_info->proto, vid_info->vid);
}
return err;
@@ -363,7 +383,7 @@ void vlan_vids_del_by_dev(struct net_device *dev,
return;
list_for_each_entry(vid_info, &vlan_info->vid_list, list)
- vlan_vid_del(dev, vid_info->vid);
+ vlan_vid_del(dev, vid_info->proto, vid_info->vid);
}
EXPORT_SYMBOL(vlan_vids_del_by_dev);
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 19cf81bf9f69..8af508536d36 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -99,6 +99,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
const void *daddr, const void *saddr,
unsigned int len)
{
+ struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
struct vlan_hdr *vhdr;
unsigned int vhdrlen = 0;
u16 vlan_tci = 0;
@@ -120,8 +121,8 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
else
vhdr->h_vlan_encapsulated_proto = htons(len);
- skb->protocol = htons(ETH_P_8021Q);
- type = ETH_P_8021Q;
+ skb->protocol = vlan->vlan_proto;
+ type = ntohs(vlan->vlan_proto);
vhdrlen = VLAN_HLEN;
}
@@ -161,12 +162,12 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
* NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING
* OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
*/
- if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
+ if (veth->h_vlan_proto != vlan->vlan_proto ||
vlan->flags & VLAN_FLAG_REORDER_HDR) {
u16 vlan_tci;
vlan_tci = vlan->vlan_id;
vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
- skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
+ skb = __vlan_hwaccel_put_tag(skb, vlan->vlan_proto, vlan_tci);
}
skb->dev = vlan->real_dev;
@@ -583,7 +584,7 @@ static int vlan_dev_init(struct net_device *dev)
#endif
dev->needed_headroom = real_dev->needed_headroom;
- if (real_dev->features & NETIF_F_HW_VLAN_TX) {
+ if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
dev->header_ops = real_dev->header_ops;
dev->hard_header_len = real_dev->hard_header_len;
} else {
diff --git a/net/8021q/vlan_gvrp.c b/net/8021q/vlan_gvrp.c
index 6f9755352760..66a80320b032 100644
--- a/net/8021q/vlan_gvrp.c
+++ b/net/8021q/vlan_gvrp.c
@@ -32,6 +32,8 @@ int vlan_gvrp_request_join(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id);
+ if (vlan->vlan_proto != htons(ETH_P_8021Q))
+ return 0;
return garp_request_join(vlan->real_dev, &vlan_gvrp_app,
&vlan_id, sizeof(vlan_id), GVRP_ATTR_VID);
}
@@ -41,6 +43,8 @@ void vlan_gvrp_request_leave(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id);
+ if (vlan->vlan_proto != htons(ETH_P_8021Q))
+ return;
garp_request_leave(vlan->real_dev, &vlan_gvrp_app,
&vlan_id, sizeof(vlan_id), GVRP_ATTR_VID);
}
diff --git a/net/8021q/vlan_mvrp.c b/net/8021q/vlan_mvrp.c
index d9ec1d5964aa..e0fe091801b0 100644
--- a/net/8021q/vlan_mvrp.c
+++ b/net/8021q/vlan_mvrp.c
@@ -38,6 +38,8 @@ int vlan_mvrp_request_join(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id);
+ if (vlan->vlan_proto != htons(ETH_P_8021Q))
+ return 0;
return mrp_request_join(vlan->real_dev, &vlan_mrp_app,
&vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
}
@@ -47,6 +49,8 @@ void vlan_mvrp_request_leave(const struct net_device *dev)
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
__be16 vlan_id = htons(vlan->vlan_id);
+ if (vlan->vlan_proto != htons(ETH_P_8021Q))
+ return;
mrp_request_leave(vlan->real_dev, &vlan_mrp_app,
&vlan_id, sizeof(vlan_id), MVRP_ATTR_VID);
}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 1789658b7cd7..309129732285 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -23,6 +23,7 @@ static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
[IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
[IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
[IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+ [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
};
static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
@@ -53,6 +54,16 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
if (!data)
return -EINVAL;
+ if (data[IFLA_VLAN_PROTOCOL]) {
+ switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
+ case __constant_htons(ETH_P_8021Q):
+ case __constant_htons(ETH_P_8021AD):
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+ }
+
if (data[IFLA_VLAN_ID]) {
id = nla_get_u16(data[IFLA_VLAN_ID]);
if (id >= VLAN_VID_MASK)
@@ -107,6 +118,7 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
{
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
struct net_device *real_dev;
+ __be16 proto;
int err;
if (!data[IFLA_VLAN_ID])
@@ -118,11 +130,17 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
if (!real_dev)
return -ENODEV;
- vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
- vlan->real_dev = real_dev;
- vlan->flags = VLAN_FLAG_REORDER_HDR;
+ if (data[IFLA_VLAN_PROTOCOL])
+ proto = nla_get_be16(data[IFLA_VLAN_PROTOCOL]);
+ else
+ proto = htons(ETH_P_8021Q);
+
+ vlan->vlan_proto = proto;
+ vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
+ vlan->real_dev = real_dev;
+ vlan->flags = VLAN_FLAG_REORDER_HDR;
- err = vlan_check_real_dev(real_dev, vlan->vlan_id);
+ err = vlan_check_real_dev(real_dev, vlan->vlan_proto, vlan->vlan_id);
if (err < 0)
return err;
@@ -151,7 +169,8 @@ static size_t vlan_get_size(const struct net_device *dev)
{
struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
- return nla_total_size(2) + /* IFLA_VLAN_ID */
+ return nla_total_size(2) + /* IFLA_VLAN_PROTOCOL */
+ nla_total_size(2) + /* IFLA_VLAN_ID */
sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */
vlan_qos_map_size(vlan->nr_ingress_mappings) +
vlan_qos_map_size(vlan->nr_egress_mappings);
@@ -166,7 +185,8 @@ static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct nlattr *nest;
unsigned int i;
- if (nla_put_u16(skb, IFLA_VLAN_ID, vlan_dev_priv(dev)->vlan_id))
+ if (nla_put_be16(skb, IFLA_VLAN_PROTOCOL, vlan->vlan_proto) ||
+ nla_put_u16(skb, IFLA_VLAN_ID, vlan->vlan_id))
goto nla_put_failure;
if (vlan->flags) {
f.flags = vlan->flags;
diff --git a/net/Kconfig b/net/Kconfig
index 6f676ab885be..2ddc9046868e 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -217,6 +217,7 @@ source "net/dns_resolver/Kconfig"
source "net/batman-adv/Kconfig"
source "net/openvswitch/Kconfig"
source "net/vmw_vsock/Kconfig"
+source "net/netlink/Kconfig"
config RPS
boolean
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 4a141e3cf076..ef12839a7cfe 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1253,7 +1253,7 @@ static int atalk_getname(struct socket *sock, struct sockaddr *uaddr,
goto out;
*uaddr_len = sizeof(struct sockaddr_at);
- memset(&sat.sat_zero, 0, sizeof(sat.sat_zero));
+ memset(&sat, 0, sizeof(sat));
if (peer) {
err = -ENOTCONN;
diff --git a/net/atm/common.c b/net/atm/common.c
index 7b491006eaf4..737bef59ce89 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -531,6 +531,8 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
struct sk_buff *skb;
int copied, error = -EINVAL;
+ msg->msg_namelen = 0;
+
if (sock->state != SS_CONNECTED)
return -ENOTCONN;
diff --git a/net/atm/lec.h b/net/atm/lec.h
index a86aff9a3c04..4149db1b7885 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -58,7 +58,7 @@ struct lane2_ops {
* field in h_type field. Data follows immediately after header.
* 2. LLC Data frames whose total length, including LLC field and data,
* but not padding required to meet the minimum data frame length,
- * is less than 1536(0x0600) MUST be encoded by placing that length
+ * is less than ETH_P_802_3_MIN MUST be encoded by placing that length
* in the h_type field. The LLC field follows header immediately.
* 3. LLC data frames longer than this maximum MUST be encoded by placing
* the value 0 in the h_type field.
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 7b11f8bc5071..e277e38f736b 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1642,6 +1642,7 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
ax25_address src;
const unsigned char *mac = skb_mac_header(skb);
+ memset(sax, 0, sizeof(struct full_sockaddr_ax25));
ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,
&digi, NULL, NULL);
sax->sax25_family = AF_AX25;
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 8d8afb134b3a..fa780b76630e 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -36,6 +36,20 @@ config BATMAN_ADV_DAT
mesh networks. If you think that your network does not need
this option you can safely remove it and save some space.
+config BATMAN_ADV_NC
+ bool "Network Coding"
+ depends on BATMAN_ADV
+ default n
+ help
+ This option enables network coding, a mechanism that aims to
+ increase the overall network throughput by fusing multiple
+ packets in one transmission.
+ Note that interfaces controlled by batman-adv must be manually
+ configured to have promiscuous mode enabled in order to make
+ network coding work.
+ If you think that your network does not need this feature you
+ can safely disable it and save some space.
+
config BATMAN_ADV_DEBUG
bool "B.A.T.M.A.N. debugging"
depends on BATMAN_ADV
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index e45e3b4e32e3..acbac2a9c62f 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+# Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
#
# Marek Lindner, Simon Wunderlich
#
@@ -30,6 +30,7 @@ batman-adv-y += hard-interface.o
batman-adv-y += hash.o
batman-adv-y += icmp_socket.o
batman-adv-y += main.o
+batman-adv-$(CONFIG_BATMAN_ADV_NC) += network-coding.o
batman-adv-y += originator.o
batman-adv-y += ring_buffer.o
batman-adv-y += routing.o
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index a5bb0a769eb9..071f288b77a8 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -27,6 +27,7 @@
#include "hard-interface.h"
#include "send.h"
#include "bat_algo.h"
+#include "network-coding.h"
static struct batadv_neigh_node *
batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
@@ -1185,6 +1186,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
if (!orig_neigh_node)
goto out;
+ /* Update nc_nodes of the originator */
+ batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
+ batadv_ogm_packet, is_single_hop_neigh);
+
orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
/* drop packet if sender is not a direct neighbor and if we
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 6a4f728680ae..379061c72549 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -341,7 +341,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
}
if (vid != -1)
- skb = vlan_insert_tag(skb, vid);
+ skb = vlan_insert_tag(skb, htons(ETH_P_8021Q), vid);
skb_reset_mac_header(skb);
skb->protocol = eth_type_trans(skb, soft_iface);
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c
index 6ae86516db4d..f186a55b23c3 100644
--- a/net/batman-adv/debugfs.c
+++ b/net/batman-adv/debugfs.c
@@ -32,6 +32,7 @@
#include "icmp_socket.h"
#include "bridge_loop_avoidance.h"
#include "distributed-arp-table.h"
+#include "network-coding.h"
static struct dentry *batadv_debugfs;
@@ -310,6 +311,14 @@ struct batadv_debuginfo {
const struct file_operations fops;
};
+#ifdef CONFIG_BATMAN_ADV_NC
+static int batadv_nc_nodes_open(struct inode *inode, struct file *file)
+{
+ struct net_device *net_dev = (struct net_device *)inode->i_private;
+ return single_open(file, batadv_nc_nodes_seq_print_text, net_dev);
+}
+#endif
+
#define BATADV_DEBUGINFO(_name, _mode, _open) \
struct batadv_debuginfo batadv_debuginfo_##_name = { \
.attr = { .name = __stringify(_name), \
@@ -348,6 +357,9 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open);
static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
batadv_transtable_local_open);
static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
+#ifdef CONFIG_BATMAN_ADV_NC
+static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
+#endif
static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
&batadv_debuginfo_originators,
@@ -362,6 +374,9 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
#endif
&batadv_debuginfo_transtable_local,
&batadv_debuginfo_vis_data,
+#ifdef CONFIG_BATMAN_ADV_NC
+ &batadv_debuginfo_nc_nodes,
+#endif
NULL,
};
@@ -431,6 +446,9 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
}
}
+ if (batadv_nc_init_debugfs(bat_priv) < 0)
+ goto rem_attr;
+
return 0;
rem_attr:
debugfs_remove_recursive(bat_priv->debug_dir);
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index d54188a112ea..8e15d966d9b0 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -816,7 +816,6 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
bool ret = false;
struct batadv_dat_entry *dat_entry = NULL;
struct sk_buff *skb_new;
- struct batadv_hard_iface *primary_if = NULL;
if (!atomic_read(&bat_priv->distributed_arp_table))
goto out;
@@ -838,22 +837,18 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
if (dat_entry) {
- primary_if = batadv_primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
- primary_if->soft_iface, ip_dst, hw_src,
+ bat_priv->soft_iface, ip_dst, hw_src,
dat_entry->mac_addr, hw_src);
if (!skb_new)
goto out;
skb_reset_mac_header(skb_new);
skb_new->protocol = eth_type_trans(skb_new,
- primary_if->soft_iface);
+ bat_priv->soft_iface);
bat_priv->stats.rx_packets++;
bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
- primary_if->soft_iface->last_rx = jiffies;
+ bat_priv->soft_iface->last_rx = jiffies;
netif_rx(skb_new);
batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally\n");
@@ -866,8 +861,6 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
out:
if (dat_entry)
batadv_dat_entry_free_ref(dat_entry);
- if (primary_if)
- batadv_hardif_free_ref(primary_if);
return ret;
}
@@ -887,7 +880,6 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
__be32 ip_src, ip_dst;
uint8_t *hw_src;
struct sk_buff *skb_new;
- struct batadv_hard_iface *primary_if = NULL;
struct batadv_dat_entry *dat_entry = NULL;
bool ret = false;
int err;
@@ -912,12 +904,8 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!dat_entry)
goto out;
- primary_if = batadv_primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src,
- primary_if->soft_iface, ip_dst, hw_src,
+ bat_priv->soft_iface, ip_dst, hw_src,
dat_entry->mac_addr, hw_src);
if (!skb_new)
@@ -941,8 +929,6 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
out:
if (dat_entry)
batadv_dat_entry_free_ref(dat_entry);
- if (primary_if)
- batadv_hardif_free_ref(primary_if);
if (ret)
kfree_skb(skb);
return ret;
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 34f99a46ec1d..f105219f4a4b 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -500,7 +500,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
rcu_read_unlock();
if (gw_count == 0)
- seq_printf(seq, "No gateways in range ...\n");
+ seq_puts(seq, "No gateways in range ...\n");
out:
if (primary_if)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 368219e026a9..522243aff2f3 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -307,11 +307,35 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
batadv_update_min_mtu(hard_iface->soft_iface);
}
+/**
+ * batadv_master_del_slave - remove hard_iface from the current master interface
+ * @slave: the interface enslaved in another master
+ * @master: the master from which slave has to be removed
+ *
+ * Invoke ndo_del_slave on master passing slave as argument. In this way slave
+ * is free'd and master can correctly change its internal state.
+ * Return 0 on success, a negative value representing the error otherwise
+ */
+static int batadv_master_del_slave(struct batadv_hard_iface *slave,
+ struct net_device *master)
+{
+ int ret;
+
+ if (!master)
+ return 0;
+
+ ret = -EBUSY;
+ if (master->netdev_ops->ndo_del_slave)
+ ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);
+
+ return ret;
+}
+
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name)
{
struct batadv_priv *bat_priv;
- struct net_device *soft_iface;
+ struct net_device *soft_iface, *master;
__be16 ethertype = __constant_htons(ETH_P_BATMAN);
int ret;
@@ -321,11 +345,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (!atomic_inc_not_zero(&hard_iface->refcount))
goto out;
- /* hard-interface is part of a bridge */
- if (hard_iface->net_dev->priv_flags & IFF_BRIDGE_PORT)
- pr_err("You are about to enable batman-adv on '%s' which already is part of a bridge. Unless you know exactly what you are doing this is probably wrong and won't work the way you think it would.\n",
- hard_iface->net_dev->name);
-
soft_iface = dev_get_by_name(&init_net, iface_name);
if (!soft_iface) {
@@ -347,12 +366,24 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
goto err_dev;
}
+ /* check if the interface is enslaved in another virtual one and
+ * in that case unlink it first
+ */
+ master = netdev_master_upper_dev_get(hard_iface->net_dev);
+ ret = batadv_master_del_slave(hard_iface, master);
+ if (ret)
+ goto err_dev;
+
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
+ ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface);
+ if (ret)
+ goto err_dev;
+
ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
if (ret < 0)
- goto err_dev;
+ goto err_upper;
hard_iface->if_num = bat_priv->num_ifaces;
bat_priv->num_ifaces++;
@@ -362,7 +393,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
bat_priv->num_ifaces--;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
- goto err_dev;
+ goto err_upper;
}
hard_iface->batman_adv_ptype.type = ethertype;
@@ -401,14 +432,18 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
out:
return 0;
+err_upper:
+ netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface);
err_dev:
+ hard_iface->soft_iface = NULL;
dev_put(soft_iface);
err:
batadv_hardif_free_ref(hard_iface);
return ret;
}
-void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
+void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
+ enum batadv_hard_if_cleanup autodel)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct batadv_hard_iface *primary_if = NULL;
@@ -446,9 +481,10 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
dev_put(hard_iface->soft_iface);
/* nobody uses this interface anymore */
- if (!bat_priv->num_ifaces)
- batadv_softif_destroy(hard_iface->soft_iface);
+ if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO)
+ batadv_softif_destroy_sysfs(hard_iface->soft_iface);
+ netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
hard_iface->soft_iface = NULL;
batadv_hardif_free_ref(hard_iface);
@@ -533,7 +569,8 @@ static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
/* first deactivate interface */
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- batadv_hardif_disable_interface(hard_iface);
+ batadv_hardif_disable_interface(hard_iface,
+ BATADV_IF_CLEANUP_AUTO);
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
return;
@@ -563,6 +600,11 @@ static int batadv_hard_if_event(struct notifier_block *this,
struct batadv_hard_iface *primary_if = NULL;
struct batadv_priv *bat_priv;
+ if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
+ batadv_sysfs_add_meshif(net_dev);
+ return NOTIFY_DONE;
+ }
+
hard_iface = batadv_hardif_get_by_netdev(net_dev);
if (!hard_iface && event == NETDEV_REGISTER)
hard_iface = batadv_hardif_add_interface(net_dev);
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 308437d52e22..49892881a7c5 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -29,13 +29,24 @@ enum batadv_hard_if_state {
BATADV_IF_I_WANT_YOU,
};
+/**
+ * enum batadv_hard_if_cleanup - Cleanup modi for soft_iface after slave removal
+ * @BATADV_IF_CLEANUP_KEEP: Don't automatically delete soft-interface
+ * @BATADV_IF_CLEANUP_AUTO: Delete soft-interface after last slave was removed
+ */
+enum batadv_hard_if_cleanup {
+ BATADV_IF_CLEANUP_KEEP,
+ BATADV_IF_CLEANUP_AUTO,
+};
+
extern struct notifier_block batadv_hard_if_notifier;
struct batadv_hard_iface*
batadv_hardif_get_by_netdev(const struct net_device *net_dev);
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
const char *iface_name);
-void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface);
+void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
+ enum batadv_hard_if_cleanup autodel);
void batadv_hardif_remove_interfaces(void);
int batadv_hardif_min_mtu(struct net_device *soft_iface);
void batadv_update_min_mtu(struct net_device *soft_iface);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 0488d70c8c35..3e30a0f1b908 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -35,6 +35,7 @@
#include "vis.h"
#include "hash.h"
#include "bat_algo.h"
+#include "network-coding.h"
/* List manipulations on hardif_list have to be rtnl_lock()'ed,
@@ -70,6 +71,7 @@ static int __init batadv_init(void)
batadv_debugfs_init();
register_netdevice_notifier(&batadv_hard_if_notifier);
+ rtnl_link_register(&batadv_link_ops);
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION);
@@ -80,6 +82,7 @@ static int __init batadv_init(void)
static void __exit batadv_exit(void)
{
batadv_debugfs_destroy();
+ rtnl_link_unregister(&batadv_link_ops);
unregister_netdevice_notifier(&batadv_hard_if_notifier);
batadv_hardif_remove_interfaces();
@@ -135,6 +138,10 @@ int batadv_mesh_init(struct net_device *soft_iface)
if (ret < 0)
goto err;
+ ret = batadv_nc_init(bat_priv);
+ if (ret < 0)
+ goto err;
+
atomic_set(&bat_priv->gw.reselect, 0);
atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
@@ -157,6 +164,7 @@ void batadv_mesh_free(struct net_device *soft_iface)
batadv_gw_node_purge(bat_priv);
batadv_originator_free(bat_priv);
+ batadv_nc_free(bat_priv);
batadv_tt_free(bat_priv);
@@ -169,7 +177,13 @@ void batadv_mesh_free(struct net_device *soft_iface)
atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE);
}
-int batadv_is_my_mac(const uint8_t *addr)
+/**
+ * batadv_is_my_mac - check if the given mac address belongs to any of the real
+ * interfaces in the current mesh
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the address to check
+ */
+int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr)
{
const struct batadv_hard_iface *hard_iface;
@@ -178,6 +192,9 @@ int batadv_is_my_mac(const uint8_t *addr)
if (hard_iface->if_status != BATADV_IF_ACTIVE)
continue;
+ if (hard_iface->soft_iface != bat_priv->soft_iface)
+ continue;
+
if (batadv_compare_eth(hard_iface->net_dev->dev_addr, addr)) {
rcu_read_unlock();
return 1;
@@ -411,7 +428,7 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset)
{
struct batadv_algo_ops *bat_algo_ops;
- seq_printf(seq, "Available routing algorithms:\n");
+ seq_puts(seq, "Available routing algorithms:\n");
hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) {
seq_printf(seq, "%s\n", bat_algo_ops->name);
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index ced08b936a96..59a0d6af15c8 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -26,7 +26,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2013.1.0"
+#define BATADV_SOURCE_VERSION "2013.2.0"
#endif
/* B.A.T.M.A.N. parameters */
@@ -105,6 +105,8 @@
#define BATADV_RESET_PROTECTION_MS 30000
#define BATADV_EXPECTED_SEQNO_RANGE 65536
+#define BATADV_NC_NODE_TIMEOUT 10000 /* Milliseconds */
+
enum batadv_mesh_state {
BATADV_MESH_INACTIVE,
BATADV_MESH_ACTIVE,
@@ -150,6 +152,7 @@ enum batadv_uev_type {
#include <linux/percpu.h>
#include <linux/slab.h>
#include <net/sock.h> /* struct sock */
+#include <net/rtnetlink.h>
#include <linux/jiffies.h>
#include <linux/seq_file.h>
#include "types.h"
@@ -162,7 +165,7 @@ extern struct workqueue_struct *batadv_event_workqueue;
int batadv_mesh_init(struct net_device *soft_iface);
void batadv_mesh_free(struct net_device *soft_iface);
-int batadv_is_my_mac(const uint8_t *addr);
+int batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr);
struct batadv_hard_iface *
batadv_seq_print_text_primary_if_get(struct seq_file *seq);
int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
@@ -185,6 +188,7 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr);
* @BATADV_DBG_TT: translation table messages
* @BATADV_DBG_BLA: bridge loop avoidance messages
* @BATADV_DBG_DAT: ARP snooping and DAT related messages
+ * @BATADV_DBG_NC: network coding related messages
* @BATADV_DBG_ALL: the union of all the above log levels
*/
enum batadv_dbg_level {
@@ -193,7 +197,8 @@ enum batadv_dbg_level {
BATADV_DBG_TT = BIT(2),
BATADV_DBG_BLA = BIT(3),
BATADV_DBG_DAT = BIT(4),
- BATADV_DBG_ALL = 31,
+ BATADV_DBG_NC = BIT(5),
+ BATADV_DBG_ALL = 63,
};
#ifdef CONFIG_BATMAN_ADV_DEBUG
@@ -298,4 +303,10 @@ static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv,
return sum;
}
+/* Define a macro to reach the control buffer of the skb. The members of the
+ * control buffer are defined in struct batadv_skb_cb in types.h.
+ * The macro is inspired by the similar macro TCP_SKB_CB() in tcp.h.
+ */
+#define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0]))
+
#endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
new file mode 100644
index 000000000000..f7c54305a918
--- /dev/null
+++ b/net/batman-adv/network-coding.c
@@ -0,0 +1,1822 @@
+/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
+ *
+ * Martin Hundebøll, Jeppe Ledet-Pedersen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include <linux/debugfs.h>
+
+#include "main.h"
+#include "hash.h"
+#include "network-coding.h"
+#include "send.h"
+#include "originator.h"
+#include "hard-interface.h"
+#include "routing.h"
+
+static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
+static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
+
+static void batadv_nc_worker(struct work_struct *work);
+static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
+ struct batadv_hard_iface *recv_if);
+
+/**
+ * batadv_nc_start_timer - initialise the nc periodic worker
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
+{
+ queue_delayed_work(batadv_event_workqueue, &bat_priv->nc.work,
+ msecs_to_jiffies(10));
+}
+
+/**
+ * batadv_nc_init - initialise coding hash table and start house keeping
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+int batadv_nc_init(struct batadv_priv *bat_priv)
+{
+ bat_priv->nc.timestamp_fwd_flush = jiffies;
+ bat_priv->nc.timestamp_sniffed_purge = jiffies;
+
+ if (bat_priv->nc.coding_hash || bat_priv->nc.decoding_hash)
+ return 0;
+
+ bat_priv->nc.coding_hash = batadv_hash_new(128);
+ if (!bat_priv->nc.coding_hash)
+ goto err;
+
+ batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
+ &batadv_nc_coding_hash_lock_class_key);
+
+ bat_priv->nc.decoding_hash = batadv_hash_new(128);
+ if (!bat_priv->nc.decoding_hash)
+ goto err;
+
+ batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
+ &batadv_nc_decoding_hash_lock_class_key);
+
+ /* Register our packet type */
+ if (batadv_recv_handler_register(BATADV_CODED,
+ batadv_nc_recv_coded_packet) < 0)
+ goto err;
+
+ INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
+ batadv_nc_start_timer(bat_priv);
+
+ return 0;
+
+err:
+ return -ENOMEM;
+}
+
+/**
+ * batadv_nc_init_bat_priv - initialise the nc specific bat_priv variables
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
+{
+ atomic_set(&bat_priv->network_coding, 1);
+ bat_priv->nc.min_tq = 200;
+ bat_priv->nc.max_fwd_delay = 10;
+ bat_priv->nc.max_buffer_time = 200;
+}
+
+/**
+ * batadv_nc_init_orig - initialise the nc fields of an orig_node
+ * @orig_node: the orig_node which is going to be initialised
+ */
+void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
+{
+ INIT_LIST_HEAD(&orig_node->in_coding_list);
+ INIT_LIST_HEAD(&orig_node->out_coding_list);
+ spin_lock_init(&orig_node->in_coding_list_lock);
+ spin_lock_init(&orig_node->out_coding_list_lock);
+}
+
+/**
+ * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove
+ * its refcount on the orig_node
+ * @rcu: rcu pointer of the nc node
+ */
+static void batadv_nc_node_free_rcu(struct rcu_head *rcu)
+{
+ struct batadv_nc_node *nc_node;
+
+ nc_node = container_of(rcu, struct batadv_nc_node, rcu);
+ batadv_orig_node_free_ref(nc_node->orig_node);
+ kfree(nc_node);
+}
+
+/**
+ * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly
+ * frees it
+ * @nc_node: the nc node to free
+ */
+static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node)
+{
+ if (atomic_dec_and_test(&nc_node->refcount))
+ call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu);
+}
+
+/**
+ * batadv_nc_path_free_ref - decrements the nc path refcounter and possibly
+ * frees it
+ * @nc_path: the nc node to free
+ */
+static void batadv_nc_path_free_ref(struct batadv_nc_path *nc_path)
+{
+ if (atomic_dec_and_test(&nc_path->refcount))
+ kfree_rcu(nc_path, rcu);
+}
+
+/**
+ * batadv_nc_packet_free - frees nc packet
+ * @nc_packet: the nc packet to free
+ */
+static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet)
+{
+ if (nc_packet->skb)
+ kfree_skb(nc_packet->skb);
+
+ batadv_nc_path_free_ref(nc_packet->nc_path);
+ kfree(nc_packet);
+}
+
+/**
+ * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged
+ * @bat_priv: the bat priv with all the soft interface information
+ * @nc_node: the nc node to check
+ *
+ * Returns true if the entry has to be purged now, false otherwise
+ */
+static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv,
+ struct batadv_nc_node *nc_node)
+{
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+ return true;
+
+ return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT);
+}
+
+/**
+ * batadv_nc_to_purge_nc_path_coding - checks whether an nc path has timed out
+ * @bat_priv: the bat priv with all the soft interface information
+ * @nc_path: the nc path to check
+ *
+ * Returns true if the entry has to be purged now, false otherwise
+ */
+static bool batadv_nc_to_purge_nc_path_coding(struct batadv_priv *bat_priv,
+ struct batadv_nc_path *nc_path)
+{
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+ return true;
+
+ /* purge the path when no packets has been added for 10 times the
+ * max_fwd_delay time
+ */
+ return batadv_has_timed_out(nc_path->last_valid,
+ bat_priv->nc.max_fwd_delay * 10);
+}
+
+/**
+ * batadv_nc_to_purge_nc_path_decoding - checks whether an nc path has timed out
+ * @bat_priv: the bat priv with all the soft interface information
+ * @nc_path: the nc path to check
+ *
+ * Returns true if the entry has to be purged now, false otherwise
+ */
+static bool batadv_nc_to_purge_nc_path_decoding(struct batadv_priv *bat_priv,
+ struct batadv_nc_path *nc_path)
+{
+ if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
+ return true;
+
+ /* purge the path when no packets has been added for 10 times the
+ * max_buffer time
+ */
+ return batadv_has_timed_out(nc_path->last_valid,
+ bat_priv->nc.max_buffer_time*10);
+}
+
+/**
+ * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale
+ * entries
+ * @bat_priv: the bat priv with all the soft interface information
+ * @list: list of nc nodes
+ * @lock: nc node list lock
+ * @to_purge: function in charge to decide whether an entry has to be purged or
+ * not. This function takes the nc node as argument and has to return
+ * a boolean value: true if the entry has to be deleted, false
+ * otherwise
+ */
+static void
+batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
+ struct list_head *list,
+ spinlock_t *lock,
+ bool (*to_purge)(struct batadv_priv *,
+ struct batadv_nc_node *))
+{
+ struct batadv_nc_node *nc_node, *nc_node_tmp;
+
+ /* For each nc_node in list */
+ spin_lock_bh(lock);
+ list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) {
+ /* if an helper function has been passed as parameter,
+ * ask it if the entry has to be purged or not
+ */
+ if (to_purge && !to_purge(bat_priv, nc_node))
+ continue;
+
+ batadv_dbg(BATADV_DBG_NC, bat_priv,
+ "Removing nc_node %pM -> %pM\n",
+ nc_node->addr, nc_node->orig_node->orig);
+ list_del_rcu(&nc_node->list);
+ batadv_nc_node_free_ref(nc_node);
+ }
+ spin_unlock_bh(lock);
+}
+
+/**
+ * batadv_nc_purge_orig - purges all nc node data attached of the given
+ * originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig_node with the nc node entries to be purged
+ * @to_purge: function in charge to decide whether an entry has to be purged or
+ * not. This function takes the nc node as argument and has to return
+ * a boolean value: true is the entry has to be deleted, false
+ * otherwise
+ */
+void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ bool (*to_purge)(struct batadv_priv *,
+ struct batadv_nc_node *))
+{
+ /* Check ingoing nc_node's of this orig_node */
+ batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list,
+ &orig_node->in_coding_list_lock,
+ to_purge);
+
+ /* Check outgoing nc_node's of this orig_node */
+ batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list,
+ &orig_node->out_coding_list_lock,
+ to_purge);
+}
+
+/**
+ * batadv_nc_purge_orig_hash - traverse entire originator hash to check if they
+ * have timed out nc nodes
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv)
+{
+ struct batadv_hashtable *hash = bat_priv->orig_hash;
+ struct hlist_head *head;
+ struct batadv_orig_node *orig_node;
+ uint32_t i;
+
+ if (!hash)
+ return;
+
+ /* For each orig_node */
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_node, head, hash_entry)
+ batadv_nc_purge_orig(bat_priv, orig_node,
+ batadv_nc_to_purge_nc_node);
+ rcu_read_unlock();
+ }
+}
+
+/**
+ * batadv_nc_purge_paths - traverse all nc paths part of the hash and remove
+ * unused ones
+ * @bat_priv: the bat priv with all the soft interface information
+ * @hash: hash table containing the nc paths to check
+ * @to_purge: function in charge to decide whether an entry has to be purged or
+ * not. This function takes the nc node as argument and has to return
+ * a boolean value: true is the entry has to be deleted, false
+ * otherwise
+ */
+static void batadv_nc_purge_paths(struct batadv_priv *bat_priv,
+ struct batadv_hashtable *hash,
+ bool (*to_purge)(struct batadv_priv *,
+ struct batadv_nc_path *))
+{
+ struct hlist_head *head;
+ struct hlist_node *node_tmp;
+ struct batadv_nc_path *nc_path;
+ spinlock_t *lock; /* Protects lists in hash */
+ uint32_t i;
+
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+ lock = &hash->list_locks[i];
+
+ /* For each nc_path in this bin */
+ spin_lock_bh(lock);
+ hlist_for_each_entry_safe(nc_path, node_tmp, head, hash_entry) {
+ /* if an helper function has been passed as parameter,
+ * ask it if the entry has to be purged or not
+ */
+ if (to_purge && !to_purge(bat_priv, nc_path))
+ continue;
+
+ /* purging an non-empty nc_path should never happen, but
+ * is observed under high CPU load. Delay the purging
+ * until next iteration to allow the packet_list to be
+ * emptied first.
+ */
+ if (!unlikely(list_empty(&nc_path->packet_list))) {
+ net_ratelimited_function(printk,
+ KERN_WARNING
+ "Skipping free of non-empty nc_path (%pM -> %pM)!\n",
+ nc_path->prev_hop,
+ nc_path->next_hop);
+ continue;
+ }
+
+ /* nc_path is unused, so remove it */
+ batadv_dbg(BATADV_DBG_NC, bat_priv,
+ "Remove nc_path %pM -> %pM\n",
+ nc_path->prev_hop, nc_path->next_hop);
+ hlist_del_rcu(&nc_path->hash_entry);
+ batadv_nc_path_free_ref(nc_path);
+ }
+ spin_unlock_bh(lock);
+ }
+}
+
+/**
+ * batadv_nc_hash_key_gen - computes the nc_path hash key
+ * @key: buffer to hold the final hash key
+ * @src: source ethernet mac address going into the hash key
+ * @dst: destination ethernet mac address going into the hash key
+ */
+static void batadv_nc_hash_key_gen(struct batadv_nc_path *key, const char *src,
+ const char *dst)
+{
+ memcpy(key->prev_hop, src, sizeof(key->prev_hop));
+ memcpy(key->next_hop, dst, sizeof(key->next_hop));
+}
+
+/**
+ * batadv_nc_hash_choose - compute the hash value for an nc path
+ * @data: data to hash
+ * @size: size of the hash table
+ *
+ * Returns the selected index in the hash table for the given data.
+ */
+static uint32_t batadv_nc_hash_choose(const void *data, uint32_t size)
+{
+ const struct batadv_nc_path *nc_path = data;
+ uint32_t hash = 0;
+
+ hash = batadv_hash_bytes(hash, &nc_path->prev_hop,
+ sizeof(nc_path->prev_hop));
+ hash = batadv_hash_bytes(hash, &nc_path->next_hop,
+ sizeof(nc_path->next_hop));
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash % size;
+}
+
+/**
+ * batadv_nc_hash_compare - comparing function used in the network coding hash
+ * tables
+ * @node: node in the local table
+ * @data2: second object to compare the node to
+ *
+ * Returns 1 if the two entry are the same, 0 otherwise
+ */
+static int batadv_nc_hash_compare(const struct hlist_node *node,
+ const void *data2)
+{
+ const struct batadv_nc_path *nc_path1, *nc_path2;
+
+ nc_path1 = container_of(node, struct batadv_nc_path, hash_entry);
+ nc_path2 = data2;
+
+ /* Return 1 if the two keys are identical */
+ if (memcmp(nc_path1->prev_hop, nc_path2->prev_hop,
+ sizeof(nc_path1->prev_hop)) != 0)
+ return 0;
+
+ if (memcmp(nc_path1->next_hop, nc_path2->next_hop,
+ sizeof(nc_path1->next_hop)) != 0)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * batadv_nc_hash_find - search for an existing nc path and return it
+ * @hash: hash table containing the nc path
+ * @data: search key
+ *
+ * Returns the nc_path if found, NULL otherwise.
+ */
+static struct batadv_nc_path *
+batadv_nc_hash_find(struct batadv_hashtable *hash,
+ void *data)
+{
+ struct hlist_head *head;
+ struct batadv_nc_path *nc_path, *nc_path_tmp = NULL;
+ int index;
+
+ if (!hash)
+ return NULL;
+
+ index = batadv_nc_hash_choose(data, hash->size);
+ head = &hash->table[index];
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
+ if (!batadv_nc_hash_compare(&nc_path->hash_entry, data))
+ continue;
+
+ if (!atomic_inc_not_zero(&nc_path->refcount))
+ continue;
+
+ nc_path_tmp = nc_path;
+ break;
+ }
+ rcu_read_unlock();
+
+ return nc_path_tmp;
+}
+
+/**
+ * batadv_nc_send_packet - send non-coded packet and free nc_packet struct
+ * @nc_packet: the nc packet to send
+ */
+static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
+{
+ batadv_send_skb_packet(nc_packet->skb,
+ nc_packet->neigh_node->if_incoming,
+ nc_packet->nc_path->next_hop);
+ nc_packet->skb = NULL;
+ batadv_nc_packet_free(nc_packet);
+}
+
+/**
+ * batadv_nc_sniffed_purge - Checks timestamp of given sniffed nc_packet.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @nc_path: the nc path the packet belongs to
+ * @nc_packet: the nc packet to be checked
+ *
+ * Checks whether the given sniffed (overheard) nc_packet has hit its buffering
+ * timeout. If so, the packet is no longer kept and the entry deleted from the
+ * queue. Has to be called with the appropriate locks.
+ *
+ * Returns false as soon as the entry in the fifo queue has not been timed out
+ * yet and true otherwise.
+ */
+static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv,
+ struct batadv_nc_path *nc_path,
+ struct batadv_nc_packet *nc_packet)
+{
+ unsigned long timeout = bat_priv->nc.max_buffer_time;
+ bool res = false;
+
+ /* Packets are added to tail, so the remaining packets did not time
+ * out and we can stop processing the current queue
+ */
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
+ !batadv_has_timed_out(nc_packet->timestamp, timeout))
+ goto out;
+
+ /* purge nc packet */
+ list_del(&nc_packet->list);
+ batadv_nc_packet_free(nc_packet);
+
+ res = true;
+
+out:
+ return res;
+}
+
+/**
+ * batadv_nc_fwd_flush - Checks the timestamp of the given nc packet.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @nc_path: the nc path the packet belongs to
+ * @nc_packet: the nc packet to be checked
+ *
+ * Checks whether the given nc packet has hit its forward timeout. If so, the
+ * packet is no longer delayed, immediately sent and the entry deleted from the
+ * queue. Has to be called with the appropriate locks.
+ *
+ * Returns false as soon as the entry in the fifo queue has not been timed out
+ * yet and true otherwise.
+ */
+static bool batadv_nc_fwd_flush(struct batadv_priv *bat_priv,
+ struct batadv_nc_path *nc_path,
+ struct batadv_nc_packet *nc_packet)
+{
+ unsigned long timeout = bat_priv->nc.max_fwd_delay;
+
+ /* Packets are added to tail, so the remaining packets did not time
+ * out and we can stop processing the current queue
+ */
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
+ !batadv_has_timed_out(nc_packet->timestamp, timeout))
+ return false;
+
+ /* Send packet */
+ batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
+ batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
+ nc_packet->skb->len + ETH_HLEN);
+ list_del(&nc_packet->list);
+ batadv_nc_send_packet(nc_packet);
+
+ return true;
+}
+
+/**
+ * batadv_nc_process_nc_paths - traverse given nc packet pool and free timed out
+ * nc packets
+ * @bat_priv: the bat priv with all the soft interface information
+ * @hash: to be processed hash table
+ * @process_fn: Function called to process given nc packet. Should return true
+ * to encourage this function to proceed with the next packet.
+ * Otherwise the rest of the current queue is skipped.
+ */
+static void
+batadv_nc_process_nc_paths(struct batadv_priv *bat_priv,
+ struct batadv_hashtable *hash,
+ bool (*process_fn)(struct batadv_priv *,
+ struct batadv_nc_path *,
+ struct batadv_nc_packet *))
+{
+ struct hlist_head *head;
+ struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
+ struct batadv_nc_path *nc_path;
+ bool ret;
+ int i;
+
+ if (!hash)
+ return;
+
+ /* Loop hash table bins */
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ /* Loop coding paths */
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
+ /* Loop packets */
+ spin_lock_bh(&nc_path->packet_list_lock);
+ list_for_each_entry_safe(nc_packet, nc_packet_tmp,
+ &nc_path->packet_list, list) {
+ ret = process_fn(bat_priv, nc_path, nc_packet);
+ if (!ret)
+ break;
+ }
+ spin_unlock_bh(&nc_path->packet_list_lock);
+ }
+ rcu_read_unlock();
+ }
+}
+
+/**
+ * batadv_nc_worker - periodic task for house keeping related to network coding
+ * @work: kernel work struct
+ */
+static void batadv_nc_worker(struct work_struct *work)
+{
+ struct delayed_work *delayed_work;
+ struct batadv_priv_nc *priv_nc;
+ struct batadv_priv *bat_priv;
+ unsigned long timeout;
+
+ delayed_work = container_of(work, struct delayed_work, work);
+ priv_nc = container_of(delayed_work, struct batadv_priv_nc, work);
+ bat_priv = container_of(priv_nc, struct batadv_priv, nc);
+
+ batadv_nc_purge_orig_hash(bat_priv);
+ batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash,
+ batadv_nc_to_purge_nc_path_coding);
+ batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash,
+ batadv_nc_to_purge_nc_path_decoding);
+
+ timeout = bat_priv->nc.max_fwd_delay;
+
+ if (batadv_has_timed_out(bat_priv->nc.timestamp_fwd_flush, timeout)) {
+ batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.coding_hash,
+ batadv_nc_fwd_flush);
+ bat_priv->nc.timestamp_fwd_flush = jiffies;
+ }
+
+ if (batadv_has_timed_out(bat_priv->nc.timestamp_sniffed_purge,
+ bat_priv->nc.max_buffer_time)) {
+ batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.decoding_hash,
+ batadv_nc_sniffed_purge);
+ bat_priv->nc.timestamp_sniffed_purge = jiffies;
+ }
+
+ /* Schedule a new check */
+ batadv_nc_start_timer(bat_priv);
+}
+
+/**
+ * batadv_can_nc_with_orig - checks whether the given orig node is suitable for
+ * coding or not
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: neighboring orig node which may be used as nc candidate
+ * @ogm_packet: incoming ogm packet also used for the checks
+ *
+ * Returns true if:
+ * 1) The OGM must have the most recent sequence number.
+ * 2) The TTL must be decremented by one and only one.
+ * 3) The OGM must be received from the first hop from orig_node.
+ * 4) The TQ value of the OGM must be above bat_priv->nc.min_tq.
+ */
+static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_ogm_packet *ogm_packet)
+{
+ if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno))
+ return false;
+ if (orig_node->last_ttl != ogm_packet->header.ttl + 1)
+ return false;
+ if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
+ return false;
+ if (ogm_packet->tq < bat_priv->nc.min_tq)
+ return false;
+
+ return true;
+}
+
+/**
+ * batadv_nc_find_nc_node - search for an existing nc node and return it
+ * @orig_node: orig node originating the ogm packet
+ * @orig_neigh_node: neighboring orig node from which we received the ogm packet
+ * (can be equal to orig_node)
+ * @in_coding: traverse incoming or outgoing network coding list
+ *
+ * Returns the nc_node if found, NULL otherwise.
+ */
+static struct batadv_nc_node
+*batadv_nc_find_nc_node(struct batadv_orig_node *orig_node,
+ struct batadv_orig_node *orig_neigh_node,
+ bool in_coding)
+{
+ struct batadv_nc_node *nc_node, *nc_node_out = NULL;
+ struct list_head *list;
+
+ if (in_coding)
+ list = &orig_neigh_node->in_coding_list;
+ else
+ list = &orig_neigh_node->out_coding_list;
+
+ /* Traverse list of nc_nodes to orig_node */
+ rcu_read_lock();
+ list_for_each_entry_rcu(nc_node, list, list) {
+ if (!batadv_compare_eth(nc_node->addr, orig_node->orig))
+ continue;
+
+ if (!atomic_inc_not_zero(&nc_node->refcount))
+ continue;
+
+ /* Found a match */
+ nc_node_out = nc_node;
+ break;
+ }
+ rcu_read_unlock();
+
+ return nc_node_out;
+}
+
+/**
+ * batadv_nc_get_nc_node - retrieves an nc node or creates the entry if it was
+ * not found
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node originating the ogm packet
+ * @orig_neigh_node: neighboring orig node from which we received the ogm packet
+ * (can be equal to orig_node)
+ * @in_coding: traverse incoming or outgoing network coding list
+ *
+ * Returns the nc_node if found or created, NULL in case of an error.
+ */
+static struct batadv_nc_node
+*batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_orig_node *orig_neigh_node,
+ bool in_coding)
+{
+ struct batadv_nc_node *nc_node;
+ spinlock_t *lock; /* Used to lock list selected by "int in_coding" */
+ struct list_head *list;
+
+ /* Check if nc_node is already added */
+ nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding);
+
+ /* Node found */
+ if (nc_node)
+ return nc_node;
+
+ nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC);
+ if (!nc_node)
+ return NULL;
+
+ if (!atomic_inc_not_zero(&orig_neigh_node->refcount))
+ goto free;
+
+ /* Initialize nc_node */
+ INIT_LIST_HEAD(&nc_node->list);
+ memcpy(nc_node->addr, orig_node->orig, ETH_ALEN);
+ nc_node->orig_node = orig_neigh_node;
+ atomic_set(&nc_node->refcount, 2);
+
+ /* Select ingoing or outgoing coding node */
+ if (in_coding) {
+ lock = &orig_neigh_node->in_coding_list_lock;
+ list = &orig_neigh_node->in_coding_list;
+ } else {
+ lock = &orig_neigh_node->out_coding_list_lock;
+ list = &orig_neigh_node->out_coding_list;
+ }
+
+ batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n",
+ nc_node->addr, nc_node->orig_node->orig);
+
+ /* Add nc_node to orig_node */
+ spin_lock_bh(lock);
+ list_add_tail_rcu(&nc_node->list, list);
+ spin_unlock_bh(lock);
+
+ return nc_node;
+
+free:
+ kfree(nc_node);
+ return NULL;
+}
+
+/**
+ * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node structs
+ * (best called on incoming OGMs)
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node originating the ogm packet
+ * @orig_neigh_node: neighboring orig node from which we received the ogm packet
+ * (can be equal to orig_node)
+ * @ogm_packet: incoming ogm packet
+ * @is_single_hop_neigh: orig_node is a single hop neighbor
+ */
+void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_orig_node *orig_neigh_node,
+ struct batadv_ogm_packet *ogm_packet,
+ int is_single_hop_neigh)
+{
+ struct batadv_nc_node *in_nc_node = NULL, *out_nc_node = NULL;
+
+ /* Check if network coding is enabled */
+ if (!atomic_read(&bat_priv->network_coding))
+ goto out;
+
+ /* accept ogms from 'good' neighbors and single hop neighbors */
+ if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) &&
+ !is_single_hop_neigh)
+ goto out;
+
+ /* Add orig_node as in_nc_node on hop */
+ in_nc_node = batadv_nc_get_nc_node(bat_priv, orig_node,
+ orig_neigh_node, true);
+ if (!in_nc_node)
+ goto out;
+
+ in_nc_node->last_seen = jiffies;
+
+ /* Add hop as out_nc_node on orig_node */
+ out_nc_node = batadv_nc_get_nc_node(bat_priv, orig_neigh_node,
+ orig_node, false);
+ if (!out_nc_node)
+ goto out;
+
+ out_nc_node->last_seen = jiffies;
+
+out:
+ if (in_nc_node)
+ batadv_nc_node_free_ref(in_nc_node);
+ if (out_nc_node)
+ batadv_nc_node_free_ref(out_nc_node);
+}
+
+/**
+ * batadv_nc_get_path - get existing nc_path or allocate a new one
+ * @bat_priv: the bat priv with all the soft interface information
+ * @hash: hash table containing the nc path
+ * @src: ethernet source address - first half of the nc path search key
+ * @dst: ethernet destination address - second half of the nc path search key
+ *
+ * Returns pointer to nc_path if the path was found or created, returns NULL
+ * on error.
+ */
+static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,
+ struct batadv_hashtable *hash,
+ uint8_t *src,
+ uint8_t *dst)
+{
+ int hash_added;
+ struct batadv_nc_path *nc_path, nc_path_key;
+
+ batadv_nc_hash_key_gen(&nc_path_key, src, dst);
+
+ /* Search for existing nc_path */
+ nc_path = batadv_nc_hash_find(hash, (void *)&nc_path_key);
+
+ if (nc_path) {
+ /* Set timestamp to delay removal of nc_path */
+ nc_path->last_valid = jiffies;
+ return nc_path;
+ }
+
+ /* No existing nc_path was found; create a new */
+ nc_path = kzalloc(sizeof(*nc_path), GFP_ATOMIC);
+
+ if (!nc_path)
+ return NULL;
+
+ /* Initialize nc_path */
+ INIT_LIST_HEAD(&nc_path->packet_list);
+ spin_lock_init(&nc_path->packet_list_lock);
+ atomic_set(&nc_path->refcount, 2);
+ nc_path->last_valid = jiffies;
+ memcpy(nc_path->next_hop, dst, ETH_ALEN);
+ memcpy(nc_path->prev_hop, src, ETH_ALEN);
+
+ batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n",
+ nc_path->prev_hop,
+ nc_path->next_hop);
+
+ /* Add nc_path to hash table */
+ hash_added = batadv_hash_add(hash, batadv_nc_hash_compare,
+ batadv_nc_hash_choose, &nc_path_key,
+ &nc_path->hash_entry);
+
+ if (hash_added < 0) {
+ kfree(nc_path);
+ return NULL;
+ }
+
+ return nc_path;
+}
+
+/**
+ * batadv_nc_random_weight_tq - scale the receivers TQ-value to avoid unfair
+ * selection of a receiver with slightly lower TQ than the other
+ * @tq: to be weighted tq value
+ */
+static uint8_t batadv_nc_random_weight_tq(uint8_t tq)
+{
+ uint8_t rand_val, rand_tq;
+
+ get_random_bytes(&rand_val, sizeof(rand_val));
+
+ /* randomize the estimated packet loss (max TQ - estimated TQ) */
+ rand_tq = rand_val * (BATADV_TQ_MAX_VALUE - tq);
+
+ /* normalize the randomized packet loss */
+ rand_tq /= BATADV_TQ_MAX_VALUE;
+
+ /* convert to (randomized) estimated tq again */
+ return BATADV_TQ_MAX_VALUE - rand_tq;
+}
+
+/**
+ * batadv_nc_memxor - XOR destination with source
+ * @dst: byte array to XOR into
+ * @src: byte array to XOR from
+ * @len: length of destination array
+ */
+static void batadv_nc_memxor(char *dst, const char *src, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; ++i)
+ dst[i] ^= src[i];
+}
+
+/**
+ * batadv_nc_code_packets - code a received unicast_packet with an nc packet
+ * into a coded_packet and send it
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: data skb to forward
+ * @ethhdr: pointer to the ethernet header inside the skb
+ * @nc_packet: structure containing the packet to the skb can be coded with
+ * @neigh_node: next hop to forward packet to
+ *
+ * Returns true if both packets are consumed, false otherwise.
+ */
+static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+ struct ethhdr *ethhdr,
+ struct batadv_nc_packet *nc_packet,
+ struct batadv_neigh_node *neigh_node)
+{
+ uint8_t tq_weighted_neigh, tq_weighted_coding;
+ struct sk_buff *skb_dest, *skb_src;
+ struct batadv_unicast_packet *packet1;
+ struct batadv_unicast_packet *packet2;
+ struct batadv_coded_packet *coded_packet;
+ struct batadv_neigh_node *neigh_tmp, *router_neigh;
+ struct batadv_neigh_node *router_coding = NULL;
+ uint8_t *first_source, *first_dest, *second_source, *second_dest;
+ __be32 packet_id1, packet_id2;
+ size_t count;
+ bool res = false;
+ int coding_len;
+ int unicast_size = sizeof(*packet1);
+ int coded_size = sizeof(*coded_packet);
+ int header_add = coded_size - unicast_size;
+
+ router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
+ if (!router_neigh)
+ goto out;
+
+ neigh_tmp = nc_packet->neigh_node;
+ router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
+ if (!router_coding)
+ goto out;
+
+ tq_weighted_neigh = batadv_nc_random_weight_tq(router_neigh->tq_avg);
+ tq_weighted_coding = batadv_nc_random_weight_tq(router_coding->tq_avg);
+
+ /* Select one destination for the MAC-header dst-field based on
+ * weighted TQ-values.
+ */
+ if (tq_weighted_neigh >= tq_weighted_coding) {
+ /* Destination from nc_packet is selected for MAC-header */
+ first_dest = nc_packet->nc_path->next_hop;
+ first_source = nc_packet->nc_path->prev_hop;
+ second_dest = neigh_node->addr;
+ second_source = ethhdr->h_source;
+ packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
+ packet2 = (struct batadv_unicast_packet *)skb->data;
+ packet_id1 = nc_packet->packet_id;
+ packet_id2 = batadv_skb_crc32(skb,
+ skb->data + sizeof(*packet2));
+ } else {
+ /* Destination for skb is selected for MAC-header */
+ first_dest = neigh_node->addr;
+ first_source = ethhdr->h_source;
+ second_dest = nc_packet->nc_path->next_hop;
+ second_source = nc_packet->nc_path->prev_hop;
+ packet1 = (struct batadv_unicast_packet *)skb->data;
+ packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
+ packet_id1 = batadv_skb_crc32(skb,
+ skb->data + sizeof(*packet1));
+ packet_id2 = nc_packet->packet_id;
+ }
+
+ /* Instead of zero padding the smallest data buffer, we
+ * code into the largest.
+ */
+ if (skb->len <= nc_packet->skb->len) {
+ skb_dest = nc_packet->skb;
+ skb_src = skb;
+ } else {
+ skb_dest = skb;
+ skb_src = nc_packet->skb;
+ }
+
+ /* coding_len is used when decoding the packet shorter packet */
+ coding_len = skb_src->len - unicast_size;
+
+ if (skb_linearize(skb_dest) < 0 || skb_linearize(skb_src) < 0)
+ goto out;
+
+ skb_push(skb_dest, header_add);
+
+ coded_packet = (struct batadv_coded_packet *)skb_dest->data;
+ skb_reset_mac_header(skb_dest);
+
+ coded_packet->header.packet_type = BATADV_CODED;
+ coded_packet->header.version = BATADV_COMPAT_VERSION;
+ coded_packet->header.ttl = packet1->header.ttl;
+
+ /* Info about first unicast packet */
+ memcpy(coded_packet->first_source, first_source, ETH_ALEN);
+ memcpy(coded_packet->first_orig_dest, packet1->dest, ETH_ALEN);
+ coded_packet->first_crc = packet_id1;
+ coded_packet->first_ttvn = packet1->ttvn;
+
+ /* Info about second unicast packet */
+ memcpy(coded_packet->second_dest, second_dest, ETH_ALEN);
+ memcpy(coded_packet->second_source, second_source, ETH_ALEN);
+ memcpy(coded_packet->second_orig_dest, packet2->dest, ETH_ALEN);
+ coded_packet->second_crc = packet_id2;
+ coded_packet->second_ttl = packet2->header.ttl;
+ coded_packet->second_ttvn = packet2->ttvn;
+ coded_packet->coded_len = htons(coding_len);
+
+ /* This is where the magic happens: Code skb_src into skb_dest */
+ batadv_nc_memxor(skb_dest->data + coded_size,
+ skb_src->data + unicast_size, coding_len);
+
+ /* Update counters accordingly */
+ if (BATADV_SKB_CB(skb_src)->decoded &&
+ BATADV_SKB_CB(skb_dest)->decoded) {
+ /* Both packets are recoded */
+ count = skb_src->len + ETH_HLEN;
+ count += skb_dest->len + ETH_HLEN;
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE, 2);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES, count);
+ } else if (!BATADV_SKB_CB(skb_src)->decoded &&
+ !BATADV_SKB_CB(skb_dest)->decoded) {
+ /* Both packets are newly coded */
+ count = skb_src->len + ETH_HLEN;
+ count += skb_dest->len + ETH_HLEN;
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE, 2);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES, count);
+ } else if (BATADV_SKB_CB(skb_src)->decoded &&
+ !BATADV_SKB_CB(skb_dest)->decoded) {
+ /* skb_src recoded and skb_dest is newly coded */
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
+ skb_src->len + ETH_HLEN);
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
+ skb_dest->len + ETH_HLEN);
+ } else if (!BATADV_SKB_CB(skb_src)->decoded &&
+ BATADV_SKB_CB(skb_dest)->decoded) {
+ /* skb_src is newly coded and skb_dest is recoded */
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
+ skb_src->len + ETH_HLEN);
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
+ skb_dest->len + ETH_HLEN);
+ }
+
+ /* skb_src is now coded into skb_dest, so free it */
+ kfree_skb(skb_src);
+
+ /* avoid duplicate free of skb from nc_packet */
+ nc_packet->skb = NULL;
+ batadv_nc_packet_free(nc_packet);
+
+ /* Send the coded packet and return true */
+ batadv_send_skb_packet(skb_dest, neigh_node->if_incoming, first_dest);
+ res = true;
+out:
+ if (router_neigh)
+ batadv_neigh_node_free_ref(router_neigh);
+ if (router_coding)
+ batadv_neigh_node_free_ref(router_coding);
+ return res;
+}
+
+/**
+ * batadv_nc_skb_coding_possible - true if a decoded skb is available at dst.
+ * @skb: data skb to forward
+ * @dst: destination mac address of the other skb to code with
+ * @src: source mac address of skb
+ *
+ * Whenever we network code a packet we have to check whether we received it in
+ * a network coded form. If so, we may not be able to use it for coding because
+ * some neighbors may also have received (overheard) the packet in the network
+ * coded form without being able to decode it. It is hard to know which of the
+ * neighboring nodes was able to decode the packet, therefore we can only
+ * re-code the packet if the source of the previous encoded packet is involved.
+ * Since the source encoded the packet we can be certain it has all necessary
+ * decode information.
+ *
+ * Returns true if coding of a decoded packet is allowed.
+ */
+static bool batadv_nc_skb_coding_possible(struct sk_buff *skb,
+ uint8_t *dst, uint8_t *src)
+{
+ if (BATADV_SKB_CB(skb)->decoded && !batadv_compare_eth(dst, src))
+ return false;
+ else
+ return true;
+}
+
+/**
+ * batadv_nc_path_search - Find the coding path matching in_nc_node and
+ * out_nc_node to retrieve a buffered packet that can be used for coding.
+ * @bat_priv: the bat priv with all the soft interface information
+ * @in_nc_node: pointer to skb next hop's neighbor nc node
+ * @out_nc_node: pointer to skb source's neighbor nc node
+ * @skb: data skb to forward
+ * @eth_dst: next hop mac address of skb
+ *
+ * Returns true if coding of a decoded skb is allowed.
+ */
+static struct batadv_nc_packet *
+batadv_nc_path_search(struct batadv_priv *bat_priv,
+ struct batadv_nc_node *in_nc_node,
+ struct batadv_nc_node *out_nc_node,
+ struct sk_buff *skb,
+ uint8_t *eth_dst)
+{
+ struct batadv_nc_path *nc_path, nc_path_key;
+ struct batadv_nc_packet *nc_packet_out = NULL;
+ struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
+ struct batadv_hashtable *hash = bat_priv->nc.coding_hash;
+ int idx;
+
+ if (!hash)
+ return NULL;
+
+ /* Create almost path key */
+ batadv_nc_hash_key_gen(&nc_path_key, in_nc_node->addr,
+ out_nc_node->addr);
+ idx = batadv_nc_hash_choose(&nc_path_key, hash->size);
+
+ /* Check for coding opportunities in this nc_path */
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(nc_path, &hash->table[idx], hash_entry) {
+ if (!batadv_compare_eth(nc_path->prev_hop, in_nc_node->addr))
+ continue;
+
+ if (!batadv_compare_eth(nc_path->next_hop, out_nc_node->addr))
+ continue;
+
+ spin_lock_bh(&nc_path->packet_list_lock);
+ if (list_empty(&nc_path->packet_list)) {
+ spin_unlock_bh(&nc_path->packet_list_lock);
+ continue;
+ }
+
+ list_for_each_entry_safe(nc_packet, nc_packet_tmp,
+ &nc_path->packet_list, list) {
+ if (!batadv_nc_skb_coding_possible(nc_packet->skb,
+ eth_dst,
+ in_nc_node->addr))
+ continue;
+
+ /* Coding opportunity is found! */
+ list_del(&nc_packet->list);
+ nc_packet_out = nc_packet;
+ break;
+ }
+
+ spin_unlock_bh(&nc_path->packet_list_lock);
+ break;
+ }
+ rcu_read_unlock();
+
+ return nc_packet_out;
+}
+
+/**
+ * batadv_nc_skb_src_search - Loops through the list of neighoring nodes of the
+ * skb's sender (may be equal to the originator).
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: data skb to forward
+ * @eth_dst: next hop mac address of skb
+ * @eth_src: source mac address of skb
+ * @in_nc_node: pointer to skb next hop's neighbor nc node
+ *
+ * Returns an nc packet if a suitable coding packet was found, NULL otherwise.
+ */
+static struct batadv_nc_packet *
+batadv_nc_skb_src_search(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+ uint8_t *eth_dst,
+ uint8_t *eth_src,
+ struct batadv_nc_node *in_nc_node)
+{
+ struct batadv_orig_node *orig_node;
+ struct batadv_nc_node *out_nc_node;
+ struct batadv_nc_packet *nc_packet = NULL;
+
+ orig_node = batadv_orig_hash_find(bat_priv, eth_src);
+ if (!orig_node)
+ return NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(out_nc_node,
+ &orig_node->out_coding_list, list) {
+ /* Check if the skb is decoded and if recoding is possible */
+ if (!batadv_nc_skb_coding_possible(skb,
+ out_nc_node->addr, eth_src))
+ continue;
+
+ /* Search for an opportunity in this nc_path */
+ nc_packet = batadv_nc_path_search(bat_priv, in_nc_node,
+ out_nc_node, skb, eth_dst);
+ if (nc_packet)
+ break;
+ }
+ rcu_read_unlock();
+
+ batadv_orig_node_free_ref(orig_node);
+ return nc_packet;
+}
+
+/**
+ * batadv_nc_skb_store_before_coding - set the ethernet src and dst of the
+ * unicast skb before it is stored for use in later decoding
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: data skb to store
+ * @eth_dst_new: new destination mac address of skb
+ */
+static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,
+ struct sk_buff *skb,
+ uint8_t *eth_dst_new)
+{
+ struct ethhdr *ethhdr;
+
+ /* Copy skb header to change the mac header */
+ skb = pskb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ /* Set the mac header as if we actually sent the packet uncoded */
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ memcpy(ethhdr->h_source, ethhdr->h_dest, ETH_ALEN);
+ memcpy(ethhdr->h_dest, eth_dst_new, ETH_ALEN);
+
+ /* Set data pointer to MAC header to mimic packets from our tx path */
+ skb_push(skb, ETH_HLEN);
+
+ /* Add the packet to the decoding packet pool */
+ batadv_nc_skb_store_for_decoding(bat_priv, skb);
+
+ /* batadv_nc_skb_store_for_decoding() clones the skb, so we must free
+ * our ref
+ */
+ kfree_skb(skb);
+}
+
+/**
+ * batadv_nc_skb_dst_search - Loops through list of neighboring nodes to dst.
+ * @skb: data skb to forward
+ * @neigh_node: next hop to forward packet to
+ * @ethhdr: pointer to the ethernet header inside the skb
+ *
+ * Loops through list of neighboring nodes the next hop has a good connection to
+ * (receives OGMs with a sufficient quality). We need to find a neighbor of our
+ * next hop that potentially sent a packet which our next hop also received
+ * (overheard) and has stored for later decoding.
+ *
+ * Returns true if the skb was consumed (encoded packet sent) or false otherwise
+ */
+static bool batadv_nc_skb_dst_search(struct sk_buff *skb,
+ struct batadv_neigh_node *neigh_node,
+ struct ethhdr *ethhdr)
+{
+ struct net_device *netdev = neigh_node->if_incoming->soft_iface;
+ struct batadv_priv *bat_priv = netdev_priv(netdev);
+ struct batadv_orig_node *orig_node = neigh_node->orig_node;
+ struct batadv_nc_node *nc_node;
+ struct batadv_nc_packet *nc_packet = NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(nc_node, &orig_node->in_coding_list, list) {
+ /* Search for coding opportunity with this in_nc_node */
+ nc_packet = batadv_nc_skb_src_search(bat_priv, skb,
+ neigh_node->addr,
+ ethhdr->h_source, nc_node);
+
+ /* Opportunity was found, so stop searching */
+ if (nc_packet)
+ break;
+ }
+ rcu_read_unlock();
+
+ if (!nc_packet)
+ return false;
+
+ /* Save packets for later decoding */
+ batadv_nc_skb_store_before_coding(bat_priv, skb,
+ neigh_node->addr);
+ batadv_nc_skb_store_before_coding(bat_priv, nc_packet->skb,
+ nc_packet->neigh_node->addr);
+
+ /* Code and send packets */
+ if (batadv_nc_code_packets(bat_priv, skb, ethhdr, nc_packet,
+ neigh_node))
+ return true;
+
+ /* out of mem ? Coding failed - we have to free the buffered packet
+ * to avoid memleaks. The skb passed as argument will be dealt with
+ * by the calling function.
+ */
+ batadv_nc_send_packet(nc_packet);
+ return false;
+}
+
+/**
+ * batadv_nc_skb_add_to_path - buffer skb for later encoding / decoding
+ * @skb: skb to add to path
+ * @nc_path: path to add skb to
+ * @neigh_node: next hop to forward packet to
+ * @packet_id: checksum to identify packet
+ *
+ * Returns true if the packet was buffered or false in case of an error.
+ */
+static bool batadv_nc_skb_add_to_path(struct sk_buff *skb,
+ struct batadv_nc_path *nc_path,
+ struct batadv_neigh_node *neigh_node,
+ __be32 packet_id)
+{
+ struct batadv_nc_packet *nc_packet;
+
+ nc_packet = kzalloc(sizeof(*nc_packet), GFP_ATOMIC);
+ if (!nc_packet)
+ return false;
+
+ /* Initialize nc_packet */
+ nc_packet->timestamp = jiffies;
+ nc_packet->packet_id = packet_id;
+ nc_packet->skb = skb;
+ nc_packet->neigh_node = neigh_node;
+ nc_packet->nc_path = nc_path;
+
+ /* Add coding packet to list */
+ spin_lock_bh(&nc_path->packet_list_lock);
+ list_add_tail(&nc_packet->list, &nc_path->packet_list);
+ spin_unlock_bh(&nc_path->packet_list_lock);
+
+ return true;
+}
+
+/**
+ * batadv_nc_skb_forward - try to code a packet or add it to the coding packet
+ * buffer
+ * @skb: data skb to forward
+ * @neigh_node: next hop to forward packet to
+ * @ethhdr: pointer to the ethernet header inside the skb
+ *
+ * Returns true if the skb was consumed (encoded packet sent) or false otherwise
+ */
+bool batadv_nc_skb_forward(struct sk_buff *skb,
+ struct batadv_neigh_node *neigh_node,
+ struct ethhdr *ethhdr)
+{
+ const struct net_device *netdev = neigh_node->if_incoming->soft_iface;
+ struct batadv_priv *bat_priv = netdev_priv(netdev);
+ struct batadv_unicast_packet *packet;
+ struct batadv_nc_path *nc_path;
+ __be32 packet_id;
+ u8 *payload;
+
+ /* Check if network coding is enabled */
+ if (!atomic_read(&bat_priv->network_coding))
+ goto out;
+
+ /* We only handle unicast packets */
+ payload = skb_network_header(skb);
+ packet = (struct batadv_unicast_packet *)payload;
+ if (packet->header.packet_type != BATADV_UNICAST)
+ goto out;
+
+ /* Try to find a coding opportunity and send the skb if one is found */
+ if (batadv_nc_skb_dst_search(skb, neigh_node, ethhdr))
+ return true;
+
+ /* Find or create a nc_path for this src-dst pair */
+ nc_path = batadv_nc_get_path(bat_priv,
+ bat_priv->nc.coding_hash,
+ ethhdr->h_source,
+ neigh_node->addr);
+
+ if (!nc_path)
+ goto out;
+
+ /* Add skb to nc_path */
+ packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet));
+ if (!batadv_nc_skb_add_to_path(skb, nc_path, neigh_node, packet_id))
+ goto free_nc_path;
+
+ /* Packet is consumed */
+ return true;
+
+free_nc_path:
+ batadv_nc_path_free_ref(nc_path);
+out:
+ /* Packet is not consumed */
+ return false;
+}
+
+/**
+ * batadv_nc_skb_store_for_decoding - save a clone of the skb which can be used
+ * when decoding coded packets
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: data skb to store
+ */
+void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
+ struct sk_buff *skb)
+{
+ struct batadv_unicast_packet *packet;
+ struct batadv_nc_path *nc_path;
+ struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ __be32 packet_id;
+ u8 *payload;
+
+ /* Check if network coding is enabled */
+ if (!atomic_read(&bat_priv->network_coding))
+ goto out;
+
+ /* Check for supported packet type */
+ payload = skb_network_header(skb);
+ packet = (struct batadv_unicast_packet *)payload;
+ if (packet->header.packet_type != BATADV_UNICAST)
+ goto out;
+
+ /* Find existing nc_path or create a new */
+ nc_path = batadv_nc_get_path(bat_priv,
+ bat_priv->nc.decoding_hash,
+ ethhdr->h_source,
+ ethhdr->h_dest);
+
+ if (!nc_path)
+ goto out;
+
+ /* Clone skb and adjust skb->data to point at batman header */
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto free_nc_path;
+
+ if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
+ goto free_skb;
+
+ if (unlikely(!skb_pull_rcsum(skb, ETH_HLEN)))
+ goto free_skb;
+
+ /* Add skb to nc_path */
+ packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet));
+ if (!batadv_nc_skb_add_to_path(skb, nc_path, NULL, packet_id))
+ goto free_skb;
+
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_BUFFER);
+ return;
+
+free_skb:
+ kfree_skb(skb);
+free_nc_path:
+ batadv_nc_path_free_ref(nc_path);
+out:
+ return;
+}
+
+/**
+ * batadv_nc_skb_store_sniffed_unicast - check if a received unicast packet
+ * should be saved in the decoding buffer and, if so, store it there
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: unicast skb to store
+ */
+void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
+ struct sk_buff *skb)
+{
+ struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ if (batadv_is_my_mac(bat_priv, ethhdr->h_dest))
+ return;
+
+ /* Set data pointer to MAC header to mimic packets from our tx path */
+ skb_push(skb, ETH_HLEN);
+
+ batadv_nc_skb_store_for_decoding(bat_priv, skb);
+}
+
+/**
+ * batadv_nc_skb_decode_packet - decode given skb using the decode data stored
+ * in nc_packet
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: unicast skb to decode
+ * @nc_packet: decode data needed to decode the skb
+ *
+ * Returns pointer to decoded unicast packet if the packet was decoded or NULL
+ * in case of an error.
+ */
+static struct batadv_unicast_packet *
+batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
+ struct batadv_nc_packet *nc_packet)
+{
+ const int h_size = sizeof(struct batadv_unicast_packet);
+ const int h_diff = sizeof(struct batadv_coded_packet) - h_size;
+ struct batadv_unicast_packet *unicast_packet;
+ struct batadv_coded_packet coded_packet_tmp;
+ struct ethhdr *ethhdr, ethhdr_tmp;
+ uint8_t *orig_dest, ttl, ttvn;
+ unsigned int coding_len;
+
+ /* Save headers temporarily */
+ memcpy(&coded_packet_tmp, skb->data, sizeof(coded_packet_tmp));
+ memcpy(&ethhdr_tmp, skb_mac_header(skb), sizeof(ethhdr_tmp));
+
+ if (skb_cow(skb, 0) < 0)
+ return NULL;
+
+ if (unlikely(!skb_pull_rcsum(skb, h_diff)))
+ return NULL;
+
+ /* Data points to batman header, so set mac header 14 bytes before
+ * and network to data
+ */
+ skb_set_mac_header(skb, -ETH_HLEN);
+ skb_reset_network_header(skb);
+
+ /* Reconstruct original mac header */
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+ memcpy(ethhdr, &ethhdr_tmp, sizeof(*ethhdr));
+
+ /* Select the correct unicast header information based on the location
+ * of our mac address in the coded_packet header
+ */
+ if (batadv_is_my_mac(bat_priv, coded_packet_tmp.second_dest)) {
+ /* If we are the second destination the packet was overheard,
+ * so the Ethernet address must be copied to h_dest and
+ * pkt_type changed from PACKET_OTHERHOST to PACKET_HOST
+ */
+ memcpy(ethhdr->h_dest, coded_packet_tmp.second_dest, ETH_ALEN);
+ skb->pkt_type = PACKET_HOST;
+
+ orig_dest = coded_packet_tmp.second_orig_dest;
+ ttl = coded_packet_tmp.second_ttl;
+ ttvn = coded_packet_tmp.second_ttvn;
+ } else {
+ orig_dest = coded_packet_tmp.first_orig_dest;
+ ttl = coded_packet_tmp.header.ttl;
+ ttvn = coded_packet_tmp.first_ttvn;
+ }
+
+ coding_len = ntohs(coded_packet_tmp.coded_len);
+
+ if (coding_len > skb->len)
+ return NULL;
+
+ /* Here the magic is reversed:
+ * extract the missing packet from the received coded packet
+ */
+ batadv_nc_memxor(skb->data + h_size,
+ nc_packet->skb->data + h_size,
+ coding_len);
+
+ /* Resize decoded skb if decoded with larger packet */
+ if (nc_packet->skb->len > coding_len + h_size)
+ pskb_trim_rcsum(skb, coding_len + h_size);
+
+ /* Create decoded unicast packet */
+ unicast_packet = (struct batadv_unicast_packet *)skb->data;
+ unicast_packet->header.packet_type = BATADV_UNICAST;
+ unicast_packet->header.version = BATADV_COMPAT_VERSION;
+ unicast_packet->header.ttl = ttl;
+ memcpy(unicast_packet->dest, orig_dest, ETH_ALEN);
+ unicast_packet->ttvn = ttvn;
+
+ batadv_nc_packet_free(nc_packet);
+ return unicast_packet;
+}
+
+/**
+ * batadv_nc_find_decoding_packet - search through buffered decoding data to
+ * find the data needed to decode the coded packet
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: pointer to the ethernet header inside the coded packet
+ * @coded: coded packet we try to find decode data for
+ *
+ * Returns pointer to nc packet if the needed data was found or NULL otherwise.
+ */
+static struct batadv_nc_packet *
+batadv_nc_find_decoding_packet(struct batadv_priv *bat_priv,
+ struct ethhdr *ethhdr,
+ struct batadv_coded_packet *coded)
+{
+ struct batadv_hashtable *hash = bat_priv->nc.decoding_hash;
+ struct batadv_nc_packet *tmp_nc_packet, *nc_packet = NULL;
+ struct batadv_nc_path *nc_path, nc_path_key;
+ uint8_t *dest, *source;
+ __be32 packet_id;
+ int index;
+
+ if (!hash)
+ return NULL;
+
+ /* Select the correct packet id based on the location of our mac-addr */
+ dest = ethhdr->h_source;
+ if (!batadv_is_my_mac(bat_priv, coded->second_dest)) {
+ source = coded->second_source;
+ packet_id = coded->second_crc;
+ } else {
+ source = coded->first_source;
+ packet_id = coded->first_crc;
+ }
+
+ batadv_nc_hash_key_gen(&nc_path_key, source, dest);
+ index = batadv_nc_hash_choose(&nc_path_key, hash->size);
+
+ /* Search for matching coding path */
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(nc_path, &hash->table[index], hash_entry) {
+ /* Find matching nc_packet */
+ spin_lock_bh(&nc_path->packet_list_lock);
+ list_for_each_entry(tmp_nc_packet,
+ &nc_path->packet_list, list) {
+ if (packet_id == tmp_nc_packet->packet_id) {
+ list_del(&tmp_nc_packet->list);
+
+ nc_packet = tmp_nc_packet;
+ break;
+ }
+ }
+ spin_unlock_bh(&nc_path->packet_list_lock);
+
+ if (nc_packet)
+ break;
+ }
+ rcu_read_unlock();
+
+ if (!nc_packet)
+ batadv_dbg(BATADV_DBG_NC, bat_priv,
+ "No decoding packet found for %u\n", packet_id);
+
+ return nc_packet;
+}
+
+/**
+ * batadv_nc_recv_coded_packet - try to decode coded packet and enqueue the
+ * resulting unicast packet
+ * @skb: incoming coded packet
+ * @recv_if: pointer to interface this packet was received on
+ */
+static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
+ struct batadv_hard_iface *recv_if)
+{
+ struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
+ struct batadv_unicast_packet *unicast_packet;
+ struct batadv_coded_packet *coded_packet;
+ struct batadv_nc_packet *nc_packet;
+ struct ethhdr *ethhdr;
+ int hdr_size = sizeof(*coded_packet);
+
+ /* Check if network coding is enabled */
+ if (!atomic_read(&bat_priv->network_coding))
+ return NET_RX_DROP;
+
+ /* Make sure we can access (and remove) header */
+ if (unlikely(!pskb_may_pull(skb, hdr_size)))
+ return NET_RX_DROP;
+
+ coded_packet = (struct batadv_coded_packet *)skb->data;
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
+
+ /* Verify frame is destined for us */
+ if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest) &&
+ !batadv_is_my_mac(bat_priv, coded_packet->second_dest))
+ return NET_RX_DROP;
+
+ /* Update stat counter */
+ if (batadv_is_my_mac(bat_priv, coded_packet->second_dest))
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_SNIFFED);
+
+ nc_packet = batadv_nc_find_decoding_packet(bat_priv, ethhdr,
+ coded_packet);
+ if (!nc_packet) {
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
+ return NET_RX_DROP;
+ }
+
+ /* Make skb's linear, because decoding accesses the entire buffer */
+ if (skb_linearize(skb) < 0)
+ goto free_nc_packet;
+
+ if (skb_linearize(nc_packet->skb) < 0)
+ goto free_nc_packet;
+
+ /* Decode the packet */
+ unicast_packet = batadv_nc_skb_decode_packet(bat_priv, skb, nc_packet);
+ if (!unicast_packet) {
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
+ goto free_nc_packet;
+ }
+
+ /* Mark packet as decoded to do correct recoding when forwarding */
+ BATADV_SKB_CB(skb)->decoded = true;
+ batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE);
+ batadv_add_counter(bat_priv, BATADV_CNT_NC_DECODE_BYTES,
+ skb->len + ETH_HLEN);
+ return batadv_recv_unicast_packet(skb, recv_if);
+
+free_nc_packet:
+ batadv_nc_packet_free(nc_packet);
+ return NET_RX_DROP;
+}
+
+/**
+ * batadv_nc_free - clean up network coding memory
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_nc_free(struct batadv_priv *bat_priv)
+{
+ batadv_recv_handler_unregister(BATADV_CODED);
+ cancel_delayed_work_sync(&bat_priv->nc.work);
+
+ batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);
+ batadv_hash_destroy(bat_priv->nc.coding_hash);
+ batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash, NULL);
+ batadv_hash_destroy(bat_priv->nc.decoding_hash);
+}
+
+/**
+ * batadv_nc_nodes_seq_print_text - print the nc node information
+ * @seq: seq file to print on
+ * @offset: not used
+ */
+int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
+{
+ struct net_device *net_dev = (struct net_device *)seq->private;
+ struct batadv_priv *bat_priv = netdev_priv(net_dev);
+ struct batadv_hashtable *hash = bat_priv->orig_hash;
+ struct batadv_hard_iface *primary_if;
+ struct hlist_head *head;
+ struct batadv_orig_node *orig_node;
+ struct batadv_nc_node *nc_node;
+ int i;
+
+ primary_if = batadv_seq_print_text_primary_if_get(seq);
+ if (!primary_if)
+ goto out;
+
+ /* Traverse list of originators */
+ for (i = 0; i < hash->size; i++) {
+ head = &hash->table[i];
+
+ /* For each orig_node in this bin */
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
+ seq_printf(seq, "Node: %pM\n", orig_node->orig);
+
+ seq_puts(seq, " Ingoing: ");
+ /* For each in_nc_node to this orig_node */
+ list_for_each_entry_rcu(nc_node,
+ &orig_node->in_coding_list,
+ list)
+ seq_printf(seq, "%pM ",
+ nc_node->addr);
+ seq_puts(seq, "\n");
+
+ seq_puts(seq, " Outgoing: ");
+ /* For out_nc_node to this orig_node */
+ list_for_each_entry_rcu(nc_node,
+ &orig_node->out_coding_list,
+ list)
+ seq_printf(seq, "%pM ",
+ nc_node->addr);
+ seq_puts(seq, "\n\n");
+ }
+ rcu_read_unlock();
+ }
+
+out:
+ if (primary_if)
+ batadv_hardif_free_ref(primary_if);
+ return 0;
+}
+
+/**
+ * batadv_nc_init_debugfs - create nc folder and related files in debugfs
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
+{
+ struct dentry *nc_dir, *file;
+
+ nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir);
+ if (!nc_dir)
+ goto out;
+
+ file = debugfs_create_u8("min_tq", S_IRUGO | S_IWUSR, nc_dir,
+ &bat_priv->nc.min_tq);
+ if (!file)
+ goto out;
+
+ file = debugfs_create_u32("max_fwd_delay", S_IRUGO | S_IWUSR, nc_dir,
+ &bat_priv->nc.max_fwd_delay);
+ if (!file)
+ goto out;
+
+ file = debugfs_create_u32("max_buffer_time", S_IRUGO | S_IWUSR, nc_dir,
+ &bat_priv->nc.max_buffer_time);
+ if (!file)
+ goto out;
+
+ return 0;
+
+out:
+ return -ENOMEM;
+}
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h
new file mode 100644
index 000000000000..4fa6d0caddbd
--- /dev/null
+++ b/net/batman-adv/network-coding.h
@@ -0,0 +1,123 @@
+/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
+ *
+ * Martin Hundebøll, Jeppe Ledet-Pedersen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef _NET_BATMAN_ADV_NETWORK_CODING_H_
+#define _NET_BATMAN_ADV_NETWORK_CODING_H_
+
+#ifdef CONFIG_BATMAN_ADV_NC
+
+int batadv_nc_init(struct batadv_priv *bat_priv);
+void batadv_nc_free(struct batadv_priv *bat_priv);
+void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_orig_node *orig_neigh_node,
+ struct batadv_ogm_packet *ogm_packet,
+ int is_single_hop_neigh);
+void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ bool (*to_purge)(struct batadv_priv *,
+ struct batadv_nc_node *));
+void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv);
+void batadv_nc_init_orig(struct batadv_orig_node *orig_node);
+bool batadv_nc_skb_forward(struct sk_buff *skb,
+ struct batadv_neigh_node *neigh_node,
+ struct ethhdr *ethhdr);
+void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
+ struct sk_buff *skb);
+void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
+ struct sk_buff *skb);
+int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset);
+int batadv_nc_init_debugfs(struct batadv_priv *bat_priv);
+
+#else /* ifdef CONFIG_BATMAN_ADV_NC */
+
+static inline int batadv_nc_init(struct batadv_priv *bat_priv)
+{
+ return 0;
+}
+
+static inline void batadv_nc_free(struct batadv_priv *bat_priv)
+{
+ return;
+}
+
+static inline void
+batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ struct batadv_orig_node *orig_neigh_node,
+ struct batadv_ogm_packet *ogm_packet,
+ int is_single_hop_neigh)
+{
+ return;
+}
+
+static inline void
+batadv_nc_purge_orig(struct batadv_priv *bat_priv,
+ struct batadv_orig_node *orig_node,
+ bool (*to_purge)(struct batadv_priv *,
+ struct batadv_nc_node *))
+{
+ return;
+}
+
+static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
+{
+ return;
+}
+
+static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
+{
+ return;
+}
+
+static inline bool batadv_nc_skb_forward(struct sk_buff *skb,
+ struct batadv_neigh_node *neigh_node,
+ struct ethhdr *ethhdr)
+{
+ return false;
+}
+
+static inline void
+batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
+ struct sk_buff *skb)
+{
+ return;
+}
+
+static inline void
+batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
+ struct sk_buff *skb)
+{
+ return;
+}
+
+static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
+ void *offset)
+{
+ return 0;
+}
+
+static inline int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
+{
+ return 0;
+}
+
+#endif /* ifdef CONFIG_BATMAN_ADV_NC */
+
+#endif /* _NET_BATMAN_ADV_NETWORK_CODING_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 96fb80b724dc..2f3452546636 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -28,6 +28,7 @@
#include "unicast.h"
#include "soft-interface.h"
#include "bridge_loop_avoidance.h"
+#include "network-coding.h"
/* hash class keys */
static struct lock_class_key batadv_orig_hash_lock_class_key;
@@ -142,6 +143,9 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
spin_unlock_bh(&orig_node->neigh_list_lock);
+ /* Free nc_nodes */
+ batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
+
batadv_frag_list_free(&orig_node->frag_list);
batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
"originator timed out");
@@ -219,6 +223,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
spin_lock_init(&orig_node->neigh_list_lock);
spin_lock_init(&orig_node->tt_buff_lock);
+ batadv_nc_init_orig(orig_node);
+
/* extra reference for return */
atomic_set(&orig_node->refcount, 2);
@@ -459,7 +465,7 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
neigh_node_tmp->tq_avg);
}
- seq_printf(seq, "\n");
+ seq_puts(seq, "\n");
batman_count++;
next:
@@ -469,7 +475,7 @@ next:
}
if (batman_count == 0)
- seq_printf(seq, "No batman nodes in range ...\n");
+ seq_puts(seq, "No batman nodes in range ...\n");
out:
if (primary_if)
diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h
index ed0aa89bbf8b..a51ccfc39da4 100644
--- a/net/batman-adv/packet.h
+++ b/net/batman-adv/packet.h
@@ -30,6 +30,7 @@ enum batadv_packettype {
BATADV_TT_QUERY = 0x07,
BATADV_ROAM_ADV = 0x08,
BATADV_UNICAST_4ADDR = 0x09,
+ BATADV_CODED = 0x0a,
};
/**
@@ -278,4 +279,36 @@ struct batadv_tt_change {
uint8_t addr[ETH_ALEN];
} __packed;
+/**
+ * struct batadv_coded_packet - network coded packet
+ * @header: common batman packet header and ttl of first included packet
+ * @reserved: Align following fields to 2-byte boundaries
+ * @first_source: original source of first included packet
+ * @first_orig_dest: original destinal of first included packet
+ * @first_crc: checksum of first included packet
+ * @first_ttvn: tt-version number of first included packet
+ * @second_ttl: ttl of second packet
+ * @second_dest: second receiver of this coded packet
+ * @second_source: original source of second included packet
+ * @second_orig_dest: original destination of second included packet
+ * @second_crc: checksum of second included packet
+ * @second_ttvn: tt version number of second included packet
+ * @coded_len: length of network coded part of the payload
+ */
+struct batadv_coded_packet {
+ struct batadv_header header;
+ uint8_t first_ttvn;
+ /* uint8_t first_dest[ETH_ALEN]; - saved in mac header destination */
+ uint8_t first_source[ETH_ALEN];
+ uint8_t first_orig_dest[ETH_ALEN];
+ __be32 first_crc;
+ uint8_t second_ttl;
+ uint8_t second_ttvn;
+ uint8_t second_dest[ETH_ALEN];
+ uint8_t second_source[ETH_ALEN];
+ uint8_t second_orig_dest[ETH_ALEN];
+ __be32 second_crc;
+ __be16 coded_len;
+};
+
#endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 5ee21cebbbb0..b27a4d792d15 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -29,6 +29,7 @@
#include "unicast.h"
#include "bridge_loop_avoidance.h"
#include "distributed-arp-table.h"
+#include "network-coding.h"
static int batadv_route_unicast_packet(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
@@ -402,7 +403,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
goto out;
/* not for me */
- if (!batadv_is_my_mac(ethhdr->h_dest))
+ if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
goto out;
icmp_packet = (struct batadv_icmp_packet_rr *)skb->data;
@@ -416,7 +417,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
}
/* packet for me */
- if (batadv_is_my_mac(icmp_packet->dst))
+ if (batadv_is_my_mac(bat_priv, icmp_packet->dst))
return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size);
/* TTL exceeded */
@@ -548,27 +549,39 @@ batadv_find_ifalter_router(struct batadv_orig_node *primary_orig,
return router;
}
-static int batadv_check_unicast_packet(struct sk_buff *skb, int hdr_size)
+/**
+ * batadv_check_unicast_packet - Check for malformed unicast packets
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: packet to check
+ * @hdr_size: size of header to pull
+ *
+ * Check for short header and bad addresses in given packet. Returns negative
+ * value when check fails and 0 otherwise. The negative value depends on the
+ * reason: -ENODATA for bad header, -EBADR for broadcast destination or source,
+ * and -EREMOTE for non-local (other host) destination.
+ */
+static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
+ struct sk_buff *skb, int hdr_size)
{
struct ethhdr *ethhdr;
/* drop packet if it has not necessary minimum size */
if (unlikely(!pskb_may_pull(skb, hdr_size)))
- return -1;
+ return -ENODATA;
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* packet with unicast indication but broadcast recipient */
if (is_broadcast_ether_addr(ethhdr->h_dest))
- return -1;
+ return -EBADR;
/* packet with broadcast sender address */
if (is_broadcast_ether_addr(ethhdr->h_source))
- return -1;
+ return -EBADR;
/* not for me */
- if (!batadv_is_my_mac(ethhdr->h_dest))
- return -1;
+ if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
+ return -EREMOTE;
return 0;
}
@@ -582,7 +595,7 @@ int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
char tt_flag;
size_t packet_size;
- if (batadv_check_unicast_packet(skb, hdr_size) < 0)
+ if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
return NET_RX_DROP;
/* I could need to modify it */
@@ -614,7 +627,7 @@ int batadv_recv_tt_query(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
case BATADV_TT_RESPONSE:
batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_RX);
- if (batadv_is_my_mac(tt_query->dst)) {
+ if (batadv_is_my_mac(bat_priv, tt_query->dst)) {
/* packet needs to be linearized to access the TT
* changes
*/
@@ -657,14 +670,15 @@ int batadv_recv_roam_adv(struct sk_buff *skb, struct batadv_hard_iface *recv_if)
struct batadv_roam_adv_packet *roam_adv_packet;
struct batadv_orig_node *orig_node;
- if (batadv_check_unicast_packet(skb, sizeof(*roam_adv_packet)) < 0)
+ if (batadv_check_unicast_packet(bat_priv, skb,
+ sizeof(*roam_adv_packet)) < 0)
goto out;
batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_RX);
roam_adv_packet = (struct batadv_roam_adv_packet *)skb->data;
- if (!batadv_is_my_mac(roam_adv_packet->dst))
+ if (!batadv_is_my_mac(bat_priv, roam_adv_packet->dst))
return batadv_route_unicast_packet(skb, recv_if);
/* check if it is a backbone gateway. we don't accept
@@ -850,15 +864,18 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
/* decrement ttl */
unicast_packet->header.ttl--;
- /* Update stats counter */
- batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
- batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
- skb->len + ETH_HLEN);
-
- /* route it */
- if (batadv_send_skb_to_orig(skb, orig_node, recv_if))
+ /* network code packet if possible */
+ if (batadv_nc_skb_forward(skb, neigh_node, ethhdr)) {
+ ret = NET_RX_SUCCESS;
+ } else if (batadv_send_skb_to_orig(skb, orig_node, recv_if)) {
ret = NET_RX_SUCCESS;
+ /* Update stats counter */
+ batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
+ batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
+ skb->len + ETH_HLEN);
+ }
+
out:
if (neigh_node)
batadv_neigh_node_free_ref(neigh_node);
@@ -922,7 +939,7 @@ out:
}
static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
- struct sk_buff *skb) {
+ struct sk_buff *skb, int hdr_len) {
uint8_t curr_ttvn, old_ttvn;
struct batadv_orig_node *orig_node;
struct ethhdr *ethhdr;
@@ -931,7 +948,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
int is_old_ttvn;
/* check if there is enough data before accessing it */
- if (pskb_may_pull(skb, sizeof(*unicast_packet) + ETH_HLEN) < 0)
+ if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0)
return 0;
/* create a copy of the skb (in case of for re-routing) to modify it. */
@@ -939,7 +956,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
return 0;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
- ethhdr = (struct ethhdr *)(skb->data + sizeof(*unicast_packet));
+ ethhdr = (struct ethhdr *)(skb->data + hdr_len);
/* check if the destination client was served by this node and it is now
* roaming. In this case, it means that the node has got a ROAM_ADV
@@ -967,7 +984,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
* last time) the packet had an updated information or not
*/
curr_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
- if (!batadv_is_my_mac(unicast_packet->dest)) {
+ if (!batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
orig_node = batadv_orig_hash_find(bat_priv,
unicast_packet->dest);
/* if it is not possible to find the orig_node representing the
@@ -1033,7 +1050,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
struct batadv_unicast_4addr_packet *unicast_4addr_packet;
uint8_t *orig_addr;
struct batadv_orig_node *orig_node = NULL;
- int hdr_size = sizeof(*unicast_packet);
+ int check, hdr_size = sizeof(*unicast_packet);
bool is4addr;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
@@ -1044,14 +1061,22 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
if (is4addr)
hdr_size = sizeof(*unicast_4addr_packet);
- if (batadv_check_unicast_packet(skb, hdr_size) < 0)
- return NET_RX_DROP;
+ /* function returns -EREMOTE for promiscuous packets */
+ check = batadv_check_unicast_packet(bat_priv, skb, hdr_size);
- if (!batadv_check_unicast_ttvn(bat_priv, skb))
+ /* Even though the packet is not for us, we might save it to use for
+ * decoding a later received coded packet
+ */
+ if (check == -EREMOTE)
+ batadv_nc_skb_store_sniffed_unicast(bat_priv, skb);
+
+ if (check < 0)
+ return NET_RX_DROP;
+ if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size))
return NET_RX_DROP;
/* packet for me */
- if (batadv_is_my_mac(unicast_packet->dest)) {
+ if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
if (is4addr) {
batadv_dat_inc_counter(bat_priv,
unicast_4addr_packet->subtype);
@@ -1088,16 +1113,16 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
struct sk_buff *new_skb = NULL;
int ret;
- if (batadv_check_unicast_packet(skb, hdr_size) < 0)
+ if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0)
return NET_RX_DROP;
- if (!batadv_check_unicast_ttvn(bat_priv, skb))
+ if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size))
return NET_RX_DROP;
unicast_packet = (struct batadv_unicast_frag_packet *)skb->data;
/* packet for me */
- if (batadv_is_my_mac(unicast_packet->dest)) {
+ if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb);
if (ret == NET_RX_DROP)
@@ -1151,13 +1176,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
goto out;
/* ignore broadcasts sent by myself */
- if (batadv_is_my_mac(ethhdr->h_source))
+ if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
goto out;
bcast_packet = (struct batadv_bcast_packet *)skb->data;
/* ignore broadcasts originated by myself */
- if (batadv_is_my_mac(bcast_packet->orig))
+ if (batadv_is_my_mac(bat_priv, bcast_packet->orig))
goto out;
if (bcast_packet->header.ttl < 2)
@@ -1243,14 +1268,14 @@ int batadv_recv_vis_packet(struct sk_buff *skb,
ethhdr = (struct ethhdr *)skb_mac_header(skb);
/* not for me */
- if (!batadv_is_my_mac(ethhdr->h_dest))
+ if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
return NET_RX_DROP;
/* ignore own packets */
- if (batadv_is_my_mac(vis_packet->vis_orig))
+ if (batadv_is_my_mac(bat_priv, vis_packet->vis_orig))
return NET_RX_DROP;
- if (batadv_is_my_mac(vis_packet->sender_orig))
+ if (batadv_is_my_mac(bat_priv, vis_packet->sender_orig))
return NET_RX_DROP;
switch (vis_packet->vis_type) {
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index a67cffde37ae..263cfd1ccee7 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -27,6 +27,7 @@
#include "vis.h"
#include "gateway_common.h"
#include "originator.h"
+#include "network-coding.h"
#include <linux/if_ether.h>
@@ -39,6 +40,7 @@ int batadv_send_skb_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface,
const uint8_t *dst_addr)
{
+ struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct ethhdr *ethhdr;
if (hard_iface->if_status != BATADV_IF_ACTIVE)
@@ -70,6 +72,9 @@ int batadv_send_skb_packet(struct sk_buff *skb,
skb->dev = hard_iface->net_dev;
+ /* Save a clone of the skb to use when decoding coded packets */
+ batadv_nc_skb_store_for_decoding(bat_priv, skb);
+
/* dev_queue_xmit() returns a negative result on error. However on
* congestion and traffic shaping, it drops and returns NET_XMIT_DROP
* (which is > 0). This will not be treated as an error.
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 2711e870f557..6f20d339e33a 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -37,6 +37,7 @@
#include <linux/if_ether.h>
#include "unicast.h"
#include "bridge_loop_avoidance.h"
+#include "network-coding.h"
static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
@@ -401,55 +402,6 @@ static void batadv_set_lockdep_class(struct net_device *dev)
}
/**
- * batadv_softif_init - Late stage initialization of soft interface
- * @dev: registered network device to modify
- *
- * Returns error code on failures
- */
-static int batadv_softif_init(struct net_device *dev)
-{
- batadv_set_lockdep_class(dev);
-
- return 0;
-}
-
-static const struct net_device_ops batadv_netdev_ops = {
- .ndo_init = batadv_softif_init,
- .ndo_open = batadv_interface_open,
- .ndo_stop = batadv_interface_release,
- .ndo_get_stats = batadv_interface_stats,
- .ndo_set_mac_address = batadv_interface_set_mac_addr,
- .ndo_change_mtu = batadv_interface_change_mtu,
- .ndo_start_xmit = batadv_interface_tx,
- .ndo_validate_addr = eth_validate_addr
-};
-
-static void batadv_interface_setup(struct net_device *dev)
-{
- struct batadv_priv *priv = netdev_priv(dev);
-
- ether_setup(dev);
-
- dev->netdev_ops = &batadv_netdev_ops;
- dev->destructor = free_netdev;
- dev->tx_queue_len = 0;
-
- /* can't call min_mtu, because the needed variables
- * have not been initialized yet
- */
- dev->mtu = ETH_DATA_LEN;
- /* reserve more space in the skbuff for our header */
- dev->hard_header_len = BATADV_HEADER_LEN;
-
- /* generate random address */
- eth_hw_addr_random(dev);
-
- SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
-
- memset(priv, 0, sizeof(*priv));
-}
-
-/**
* batadv_softif_destroy_finish - cleans up the remains of a softif
* @work: work queue item
*
@@ -465,7 +417,6 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
cleanup_work);
soft_iface = bat_priv->soft_iface;
- batadv_debugfs_del_meshif(soft_iface);
batadv_sysfs_del_meshif(soft_iface);
rtnl_lock();
@@ -473,21 +424,22 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
rtnl_unlock();
}
-struct net_device *batadv_softif_create(const char *name)
+/**
+ * batadv_softif_init_late - late stage initialization of soft interface
+ * @dev: registered network device to modify
+ *
+ * Returns error code on failures
+ */
+static int batadv_softif_init_late(struct net_device *dev)
{
- struct net_device *soft_iface;
struct batadv_priv *bat_priv;
int ret;
size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM;
- soft_iface = alloc_netdev(sizeof(*bat_priv), name,
- batadv_interface_setup);
-
- if (!soft_iface)
- goto out;
+ batadv_set_lockdep_class(dev);
- bat_priv = netdev_priv(soft_iface);
- bat_priv->soft_iface = soft_iface;
+ bat_priv = netdev_priv(dev);
+ bat_priv->soft_iface = dev;
INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish);
/* batadv_interface_stats() needs to be available as soon as
@@ -495,14 +447,7 @@ struct net_device *batadv_softif_create(const char *name)
*/
bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t));
if (!bat_priv->bat_counters)
- goto free_soft_iface;
-
- ret = register_netdevice(soft_iface);
- if (ret < 0) {
- pr_err("Unable to register the batman interface '%s': %i\n",
- name, ret);
- goto free_bat_counters;
- }
+ return -ENOMEM;
atomic_set(&bat_priv->aggregated_ogms, 1);
atomic_set(&bat_priv->bonding, 0);
@@ -540,49 +485,196 @@ struct net_device *batadv_softif_create(const char *name)
bat_priv->primary_if = NULL;
bat_priv->num_ifaces = 0;
- ret = batadv_algo_select(bat_priv, batadv_routing_algo);
- if (ret < 0)
- goto unreg_soft_iface;
+ batadv_nc_init_bat_priv(bat_priv);
- ret = batadv_sysfs_add_meshif(soft_iface);
+ ret = batadv_algo_select(bat_priv, batadv_routing_algo);
if (ret < 0)
- goto unreg_soft_iface;
+ goto free_bat_counters;
- ret = batadv_debugfs_add_meshif(soft_iface);
+ ret = batadv_debugfs_add_meshif(dev);
if (ret < 0)
- goto unreg_sysfs;
+ goto free_bat_counters;
- ret = batadv_mesh_init(soft_iface);
+ ret = batadv_mesh_init(dev);
if (ret < 0)
goto unreg_debugfs;
- return soft_iface;
+ return 0;
unreg_debugfs:
- batadv_debugfs_del_meshif(soft_iface);
-unreg_sysfs:
- batadv_sysfs_del_meshif(soft_iface);
-unreg_soft_iface:
- free_percpu(bat_priv->bat_counters);
- unregister_netdevice(soft_iface);
- return NULL;
-
+ batadv_debugfs_del_meshif(dev);
free_bat_counters:
free_percpu(bat_priv->bat_counters);
-free_soft_iface:
- free_netdev(soft_iface);
+
+ return ret;
+}
+
+/**
+ * batadv_softif_slave_add - Add a slave interface to a batadv_soft_interface
+ * @dev: batadv_soft_interface used as master interface
+ * @slave_dev: net_device which should become the slave interface
+ *
+ * Return 0 if successful or error otherwise.
+ */
+static int batadv_softif_slave_add(struct net_device *dev,
+ struct net_device *slave_dev)
+{
+ struct batadv_hard_iface *hard_iface;
+ int ret = -EINVAL;
+
+ hard_iface = batadv_hardif_get_by_netdev(slave_dev);
+ if (!hard_iface || hard_iface->soft_iface != NULL)
+ goto out;
+
+ ret = batadv_hardif_enable_interface(hard_iface, dev->name);
+
out:
- return NULL;
+ if (hard_iface)
+ batadv_hardif_free_ref(hard_iface);
+ return ret;
}
-void batadv_softif_destroy(struct net_device *soft_iface)
+/**
+ * batadv_softif_slave_del - Delete a slave iface from a batadv_soft_interface
+ * @dev: batadv_soft_interface used as master interface
+ * @slave_dev: net_device which should be removed from the master interface
+ *
+ * Return 0 if successful or error otherwise.
+ */
+static int batadv_softif_slave_del(struct net_device *dev,
+ struct net_device *slave_dev)
+{
+ struct batadv_hard_iface *hard_iface;
+ int ret = -EINVAL;
+
+ hard_iface = batadv_hardif_get_by_netdev(slave_dev);
+
+ if (!hard_iface || hard_iface->soft_iface != dev)
+ goto out;
+
+ batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_KEEP);
+ ret = 0;
+
+out:
+ if (hard_iface)
+ batadv_hardif_free_ref(hard_iface);
+ return ret;
+}
+
+static const struct net_device_ops batadv_netdev_ops = {
+ .ndo_init = batadv_softif_init_late,
+ .ndo_open = batadv_interface_open,
+ .ndo_stop = batadv_interface_release,
+ .ndo_get_stats = batadv_interface_stats,
+ .ndo_set_mac_address = batadv_interface_set_mac_addr,
+ .ndo_change_mtu = batadv_interface_change_mtu,
+ .ndo_start_xmit = batadv_interface_tx,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_add_slave = batadv_softif_slave_add,
+ .ndo_del_slave = batadv_softif_slave_del,
+};
+
+/**
+ * batadv_softif_free - Deconstructor of batadv_soft_interface
+ * @dev: Device to cleanup and remove
+ */
+static void batadv_softif_free(struct net_device *dev)
+{
+ batadv_debugfs_del_meshif(dev);
+ batadv_mesh_free(dev);
+
+ /* some scheduled RCU callbacks need the bat_priv struct to accomplish
+ * their tasks. Wait for them all to be finished before freeing the
+ * netdev and its private data (bat_priv)
+ */
+ rcu_barrier();
+
+ free_netdev(dev);
+}
+
+/**
+ * batadv_softif_init_early - early stage initialization of soft interface
+ * @dev: registered network device to modify
+ */
+static void batadv_softif_init_early(struct net_device *dev)
+{
+ struct batadv_priv *priv = netdev_priv(dev);
+
+ ether_setup(dev);
+
+ dev->netdev_ops = &batadv_netdev_ops;
+ dev->destructor = batadv_softif_free;
+ dev->tx_queue_len = 0;
+
+ /* can't call min_mtu, because the needed variables
+ * have not been initialized yet
+ */
+ dev->mtu = ETH_DATA_LEN;
+ /* reserve more space in the skbuff for our header */
+ dev->hard_header_len = BATADV_HEADER_LEN;
+
+ /* generate random address */
+ eth_hw_addr_random(dev);
+
+ SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
+
+ memset(priv, 0, sizeof(*priv));
+}
+
+struct net_device *batadv_softif_create(const char *name)
+{
+ struct net_device *soft_iface;
+ int ret;
+
+ soft_iface = alloc_netdev(sizeof(struct batadv_priv), name,
+ batadv_softif_init_early);
+ if (!soft_iface)
+ return NULL;
+
+ soft_iface->rtnl_link_ops = &batadv_link_ops;
+
+ ret = register_netdevice(soft_iface);
+ if (ret < 0) {
+ pr_err("Unable to register the batman interface '%s': %i\n",
+ name, ret);
+ free_netdev(soft_iface);
+ return NULL;
+ }
+
+ return soft_iface;
+}
+
+/**
+ * batadv_softif_destroy_sysfs - deletion of batadv_soft_interface via sysfs
+ * @soft_iface: the to-be-removed batman-adv interface
+ */
+void batadv_softif_destroy_sysfs(struct net_device *soft_iface)
{
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
- batadv_mesh_free(soft_iface);
queue_work(batadv_event_workqueue, &bat_priv->cleanup_work);
}
+/**
+ * batadv_softif_destroy_netlink - deletion of batadv_soft_interface via netlink
+ * @soft_iface: the to-be-removed batman-adv interface
+ * @head: list pointer
+ */
+static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
+ struct list_head *head)
+{
+ struct batadv_hard_iface *hard_iface;
+
+ list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
+ if (hard_iface->soft_iface == soft_iface)
+ batadv_hardif_disable_interface(hard_iface,
+ BATADV_IF_CLEANUP_KEEP);
+ }
+
+ batadv_sysfs_del_meshif(soft_iface);
+ unregister_netdevice_queue(soft_iface, head);
+}
+
int batadv_softif_is_valid(const struct net_device *net_dev)
{
if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx)
@@ -591,6 +683,13 @@ int batadv_softif_is_valid(const struct net_device *net_dev)
return 0;
}
+struct rtnl_link_ops batadv_link_ops __read_mostly = {
+ .kind = "batadv",
+ .priv_size = sizeof(struct batadv_priv),
+ .setup = batadv_softif_init_early,
+ .dellink = batadv_softif_destroy_netlink,
+};
+
/* ethtool */
static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -662,6 +761,17 @@ static const struct {
{ "dat_put_rx" },
{ "dat_cached_reply_tx" },
#endif
+#ifdef CONFIG_BATMAN_ADV_NC
+ { "nc_code" },
+ { "nc_code_bytes" },
+ { "nc_recode" },
+ { "nc_recode_bytes" },
+ { "nc_buffer" },
+ { "nc_decode" },
+ { "nc_decode_bytes" },
+ { "nc_decode_failed" },
+ { "nc_sniffed" },
+#endif
};
static void batadv_get_strings(struct net_device *dev, uint32_t stringset,
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 43182e5e603a..2f2472c2ea0d 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -25,7 +25,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, struct batadv_hard_iface *recv_if,
int hdr_size, struct batadv_orig_node *orig_node);
struct net_device *batadv_softif_create(const char *name);
-void batadv_softif_destroy(struct net_device *soft_iface);
+void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
int batadv_softif_is_valid(const struct net_device *net_dev);
+extern struct rtnl_link_ops batadv_link_ops;
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c
index afbba319d73a..15a22efa9a67 100644
--- a/net/batman-adv/sysfs.c
+++ b/net/batman-adv/sysfs.c
@@ -442,6 +442,9 @@ static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
#ifdef CONFIG_BATMAN_ADV_DEBUG
BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
#endif
+#ifdef CONFIG_BATMAN_ADV_NC
+BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, NULL);
+#endif
static struct batadv_attribute *batadv_mesh_attrs[] = {
&batadv_attr_aggregated_ogms,
@@ -464,6 +467,9 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
#ifdef CONFIG_BATMAN_ADV_DEBUG
&batadv_attr_log_level,
#endif
+#ifdef CONFIG_BATMAN_ADV_NC
+ &batadv_attr_network_coding,
+#endif
NULL,
};
@@ -582,13 +588,15 @@ static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
}
if (status_tmp == BATADV_IF_NOT_IN_USE) {
- batadv_hardif_disable_interface(hard_iface);
+ batadv_hardif_disable_interface(hard_iface,
+ BATADV_IF_CLEANUP_AUTO);
goto unlock;
}
/* if the interface already is in use */
if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- batadv_hardif_disable_interface(hard_iface);
+ batadv_hardif_disable_interface(hard_iface,
+ BATADV_IF_CLEANUP_AUTO);
ret = batadv_hardif_enable_interface(hard_iface, buff);
@@ -688,15 +696,10 @@ int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,
enum batadv_uev_action action, const char *data)
{
int ret = -ENOMEM;
- struct batadv_hard_iface *primary_if;
struct kobject *bat_kobj;
char *uevent_env[4] = { NULL, NULL, NULL, NULL };
- primary_if = batadv_primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
- bat_kobj = &primary_if->soft_iface->dev.kobj;
+ bat_kobj = &bat_priv->soft_iface->dev.kobj;
uevent_env[0] = kmalloc(strlen(BATADV_UEV_TYPE_VAR) +
strlen(batadv_uev_type_str[type]) + 1,
@@ -732,9 +735,6 @@ out:
kfree(uevent_env[1]);
kfree(uevent_env[2]);
- if (primary_if)
- batadv_hardif_free_ref(primary_if);
-
if (ret)
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 98a66a021a60..5e89deeb9542 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -385,25 +385,19 @@ static void batadv_tt_prepare_packet_buff(struct batadv_priv *bat_priv,
int *packet_buff_len,
int min_packet_len)
{
- struct batadv_hard_iface *primary_if;
int req_len;
- primary_if = batadv_primary_if_get_selected(bat_priv);
-
req_len = min_packet_len;
req_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
/* if we have too many changes for one packet don't send any
* and wait for the tt table request which will be fragmented
*/
- if ((!primary_if) || (req_len > primary_if->soft_iface->mtu))
+ if (req_len > bat_priv->soft_iface->mtu)
req_len = min_packet_len;
batadv_tt_realloc_packet_buff(packet_buff, packet_buff_len,
min_packet_len, req_len);
-
- if (primary_if)
- batadv_hardif_free_ref(primary_if);
}
static int batadv_tt_changes_fill_buff(struct batadv_priv *bat_priv,
@@ -908,7 +902,7 @@ out_remove:
/* remove address from local hash if present */
local_flags = batadv_tt_local_remove(bat_priv, tt_addr,
"global tt received",
- !!(flags & BATADV_TT_CLIENT_ROAM));
+ flags & BATADV_TT_CLIENT_ROAM);
tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
if (!(flags & BATADV_TT_CLIENT_ROAM))
@@ -1580,7 +1574,7 @@ static int batadv_tt_global_valid(const void *entry_ptr,
static struct sk_buff *
batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
struct batadv_hashtable *hash,
- struct batadv_hard_iface *primary_if,
+ struct batadv_priv *bat_priv,
int (*valid_cb)(const void *, const void *),
void *cb_data)
{
@@ -1594,8 +1588,8 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
uint32_t i;
size_t len;
- if (tt_query_size + tt_len > primary_if->soft_iface->mtu) {
- tt_len = primary_if->soft_iface->mtu - tt_query_size;
+ if (tt_query_size + tt_len > bat_priv->soft_iface->mtu) {
+ tt_len = bat_priv->soft_iface->mtu - tt_query_size;
tt_len -= tt_len % sizeof(struct batadv_tt_change);
}
tt_tot = tt_len / sizeof(struct batadv_tt_change);
@@ -1715,7 +1709,6 @@ batadv_send_other_tt_response(struct batadv_priv *bat_priv,
{
struct batadv_orig_node *req_dst_orig_node;
struct batadv_orig_node *res_dst_orig_node = NULL;
- struct batadv_hard_iface *primary_if = NULL;
uint8_t orig_ttvn, req_ttvn, ttvn;
int ret = false;
unsigned char *tt_buff;
@@ -1740,10 +1733,6 @@ batadv_send_other_tt_response(struct batadv_priv *bat_priv,
if (!res_dst_orig_node)
goto out;
- primary_if = batadv_primary_if_get_selected(bat_priv);
- if (!primary_if)
- goto out;
-
orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
req_ttvn = tt_request->ttvn;
@@ -1791,7 +1780,7 @@ batadv_send_other_tt_response(struct batadv_priv *bat_priv,
skb = batadv_tt_response_fill_table(tt_len, ttvn,
bat_priv->tt.global_hash,
- primary_if,
+ bat_priv,
batadv_tt_global_valid,
req_dst_orig_node);
if (!skb)
@@ -1828,8 +1817,6 @@ out:
batadv_orig_node_free_ref(res_dst_orig_node);
if (req_dst_orig_node)
batadv_orig_node_free_ref(req_dst_orig_node);
- if (primary_if)
- batadv_hardif_free_ref(primary_if);
if (!ret)
kfree_skb(skb);
return ret;
@@ -1907,7 +1894,7 @@ batadv_send_my_tt_response(struct batadv_priv *bat_priv,
skb = batadv_tt_response_fill_table(tt_len, ttvn,
bat_priv->tt.local_hash,
- primary_if,
+ bat_priv,
batadv_tt_local_valid_entry,
NULL);
if (!skb)
@@ -1953,7 +1940,7 @@ out:
bool batadv_send_tt_response(struct batadv_priv *bat_priv,
struct batadv_tt_query_packet *tt_request)
{
- if (batadv_is_my_mac(tt_request->dst)) {
+ if (batadv_is_my_mac(bat_priv, tt_request->dst)) {
/* don't answer backbone gws! */
if (batadv_bla_is_backbone_gw_orig(bat_priv, tt_request->src))
return true;
@@ -2528,7 +2515,7 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
if (!tt_global_entry)
goto out;
- ret = !!(tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM);
+ ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_global_entry_free_ref(tt_global_entry);
out:
return ret;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 4cd87a0b5b80..aba8364c3689 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -128,6 +128,10 @@ struct batadv_hard_iface {
* @bond_list: list of bonding candidates
* @refcount: number of contexts the object is used
* @rcu: struct used for freeing in an RCU-safe manner
+ * @in_coding_list: list of nodes this orig can hear
+ * @out_coding_list: list of nodes that can hear this orig
+ * @in_coding_list_lock: protects in_coding_list
+ * @out_coding_list_lock: protects out_coding_list
*/
struct batadv_orig_node {
uint8_t orig[ETH_ALEN];
@@ -171,6 +175,12 @@ struct batadv_orig_node {
struct list_head bond_list;
atomic_t refcount;
struct rcu_head rcu;
+#ifdef CONFIG_BATMAN_ADV_NC
+ struct list_head in_coding_list;
+ struct list_head out_coding_list;
+ spinlock_t in_coding_list_lock; /* Protects in_coding_list */
+ spinlock_t out_coding_list_lock; /* Protects out_coding_list */
+#endif
};
/**
@@ -265,6 +275,17 @@ struct batadv_bcast_duplist_entry {
* @BATADV_CNT_DAT_PUT_RX: received dht PUT traffic packet counter
* @BATADV_CNT_DAT_CACHED_REPLY_TX: transmitted dat cache reply traffic packet
* counter
+ * @BATADV_CNT_NC_CODE: transmitted nc-combined traffic packet counter
+ * @BATADV_CNT_NC_CODE_BYTES: transmitted nc-combined traffic bytes counter
+ * @BATADV_CNT_NC_RECODE: transmitted nc-recombined traffic packet counter
+ * @BATADV_CNT_NC_RECODE_BYTES: transmitted nc-recombined traffic bytes counter
+ * @BATADV_CNT_NC_BUFFER: counter for packets buffered for later nc decoding
+ * @BATADV_CNT_NC_DECODE: received and nc-decoded traffic packet counter
+ * @BATADV_CNT_NC_DECODE_BYTES: received and nc-decoded traffic bytes counter
+ * @BATADV_CNT_NC_DECODE_FAILED: received and decode-failed traffic packet
+ * counter
+ * @BATADV_CNT_NC_SNIFFED: counter for nc-decoded packets received in promisc
+ * mode.
* @BATADV_CNT_NUM: number of traffic counters
*/
enum batadv_counters {
@@ -292,6 +313,17 @@ enum batadv_counters {
BATADV_CNT_DAT_PUT_RX,
BATADV_CNT_DAT_CACHED_REPLY_TX,
#endif
+#ifdef CONFIG_BATMAN_ADV_NC
+ BATADV_CNT_NC_CODE,
+ BATADV_CNT_NC_CODE_BYTES,
+ BATADV_CNT_NC_RECODE,
+ BATADV_CNT_NC_RECODE_BYTES,
+ BATADV_CNT_NC_BUFFER,
+ BATADV_CNT_NC_DECODE,
+ BATADV_CNT_NC_DECODE_BYTES,
+ BATADV_CNT_NC_DECODE_FAILED,
+ BATADV_CNT_NC_SNIFFED,
+#endif
BATADV_CNT_NUM,
};
@@ -428,6 +460,35 @@ struct batadv_priv_dat {
#endif
/**
+ * struct batadv_priv_nc - per mesh interface network coding private data
+ * @work: work queue callback item for cleanup
+ * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
+ * @min_tq: only consider neighbors for encoding if neigh_tq > min_tq
+ * @max_fwd_delay: maximum packet forward delay to allow coding of packets
+ * @max_buffer_time: buffer time for sniffed packets used to decoding
+ * @timestamp_fwd_flush: timestamp of last forward packet queue flush
+ * @timestamp_sniffed_purge: timestamp of last sniffed packet queue purge
+ * @coding_hash: Hash table used to buffer skbs while waiting for another
+ * incoming skb to code it with. Skbs are added to the buffer just before being
+ * forwarded in routing.c
+ * @decoding_hash: Hash table used to buffer skbs that might be needed to decode
+ * a received coded skb. The buffer is used for 1) skbs arriving on the
+ * soft-interface; 2) skbs overheard on the hard-interface; and 3) skbs
+ * forwarded by batman-adv.
+ */
+struct batadv_priv_nc {
+ struct delayed_work work;
+ struct dentry *debug_dir;
+ u8 min_tq;
+ u32 max_fwd_delay;
+ u32 max_buffer_time;
+ unsigned long timestamp_fwd_flush;
+ unsigned long timestamp_sniffed_purge;
+ struct batadv_hashtable *coding_hash;
+ struct batadv_hashtable *decoding_hash;
+};
+
+/**
* struct batadv_priv - per mesh interface data
* @mesh_state: current status of the mesh (inactive/active/deactivating)
* @soft_iface: net device which holds this struct as private data
@@ -470,6 +531,8 @@ struct batadv_priv_dat {
* @tt: translation table data
* @vis: vis data
* @dat: distributed arp table data
+ * @network_coding: bool indicating whether network coding is enabled
+ * @batadv_priv_nc: network coding data
*/
struct batadv_priv {
atomic_t mesh_state;
@@ -522,6 +585,10 @@ struct batadv_priv {
#ifdef CONFIG_BATMAN_ADV_DAT
struct batadv_priv_dat dat;
#endif
+#ifdef CONFIG_BATMAN_ADV_NC
+ atomic_t network_coding;
+ struct batadv_priv_nc nc;
+#endif /* CONFIG_BATMAN_ADV_NC */
};
/**
@@ -702,6 +769,75 @@ struct batadv_tt_roam_node {
};
/**
+ * struct batadv_nc_node - network coding node
+ * @list: next and prev pointer for the list handling
+ * @addr: the node's mac address
+ * @refcount: number of contexts the object is used by
+ * @rcu: struct used for freeing in an RCU-safe manner
+ * @orig_node: pointer to corresponding orig node struct
+ * @last_seen: timestamp of last ogm received from this node
+ */
+struct batadv_nc_node {
+ struct list_head list;
+ uint8_t addr[ETH_ALEN];
+ atomic_t refcount;
+ struct rcu_head rcu;
+ struct batadv_orig_node *orig_node;
+ unsigned long last_seen;
+};
+
+/**
+ * struct batadv_nc_path - network coding path
+ * @hash_entry: next and prev pointer for the list handling
+ * @rcu: struct used for freeing in an RCU-safe manner
+ * @refcount: number of contexts the object is used by
+ * @packet_list: list of buffered packets for this path
+ * @packet_list_lock: access lock for packet list
+ * @next_hop: next hop (destination) of path
+ * @prev_hop: previous hop (source) of path
+ * @last_valid: timestamp for last validation of path
+ */
+struct batadv_nc_path {
+ struct hlist_node hash_entry;
+ struct rcu_head rcu;
+ atomic_t refcount;
+ struct list_head packet_list;
+ spinlock_t packet_list_lock; /* Protects packet_list */
+ uint8_t next_hop[ETH_ALEN];
+ uint8_t prev_hop[ETH_ALEN];
+ unsigned long last_valid;
+};
+
+/**
+ * struct batadv_nc_packet - network coding packet used when coding and
+ * decoding packets
+ * @list: next and prev pointer for the list handling
+ * @packet_id: crc32 checksum of skb data
+ * @timestamp: field containing the info when the packet was added to path
+ * @neigh_node: pointer to original next hop neighbor of skb
+ * @skb: skb which can be encoded or used for decoding
+ * @nc_path: pointer to path this nc packet is attached to
+ */
+struct batadv_nc_packet {
+ struct list_head list;
+ __be32 packet_id;
+ unsigned long timestamp;
+ struct batadv_neigh_node *neigh_node;
+ struct sk_buff *skb;
+ struct batadv_nc_path *nc_path;
+};
+
+/**
+ * batadv_skb_cb - control buffer structure used to store private data relevant
+ * to batman-adv in the skb->cb buffer in skbs.
+ * @decoded: Marks a skb as decoded, which is checked when searching for coding
+ * opportunities in network-coding.c
+ */
+struct batadv_skb_cb {
+ bool decoded;
+};
+
+/**
* struct batadv_forw_packet - structure for bcast packets to be sent/forwarded
* @list: list node for batadv_socket_client::queue_list
* @send_time: execution time for delayed_work (packet sending)
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c
index 50e079f00be6..0bb3b5982f94 100644
--- a/net/batman-adv/unicast.c
+++ b/net/batman-adv/unicast.c
@@ -122,7 +122,7 @@ batadv_frag_search_packet(struct list_head *head,
{
struct batadv_frag_packet_list_entry *tfp;
struct batadv_unicast_frag_packet *tmp_up = NULL;
- int is_head_tmp, is_head;
+ bool is_head_tmp, is_head;
uint16_t search_seqno;
if (up->flags & BATADV_UNI_FRAG_HEAD)
@@ -130,7 +130,7 @@ batadv_frag_search_packet(struct list_head *head,
else
search_seqno = ntohs(up->seqno)-1;
- is_head = !!(up->flags & BATADV_UNI_FRAG_HEAD);
+ is_head = up->flags & BATADV_UNI_FRAG_HEAD;
list_for_each_entry(tfp, head, list) {
if (!tfp->skb)
@@ -142,7 +142,7 @@ batadv_frag_search_packet(struct list_head *head,
tmp_up = (struct batadv_unicast_frag_packet *)tfp->skb->data;
if (tfp->seqno == search_seqno) {
- is_head_tmp = !!(tmp_up->flags & BATADV_UNI_FRAG_HEAD);
+ is_head_tmp = tmp_up->flags & BATADV_UNI_FRAG_HEAD;
if (is_head_tmp != is_head)
return tfp;
else
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c
index c053244b97bd..1625e5793a89 100644
--- a/net/batman-adv/vis.c
+++ b/net/batman-adv/vis.c
@@ -149,7 +149,7 @@ static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
hlist_for_each_entry(entry, if_list, list) {
if (entry->primary)
- seq_printf(seq, "PRIMARY, ");
+ seq_puts(seq, "PRIMARY, ");
else
seq_printf(seq, "SEC %pM, ", entry->addr);
}
@@ -207,7 +207,7 @@ static void batadv_vis_data_read_entries(struct seq_file *seq,
if (batadv_compare_eth(entry->addr, packet->vis_orig))
batadv_vis_data_read_prim_sec(seq, list);
- seq_printf(seq, "\n");
+ seq_puts(seq, "\n");
}
}
@@ -477,7 +477,7 @@ void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
/* Are we the target for this VIS packet? */
if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC &&
- batadv_is_my_mac(vis_packet->target_orig))
+ batadv_is_my_mac(bat_priv, vis_packet->target_orig))
are_target = 1;
spin_lock_bh(&bat_priv->vis.hash_lock);
@@ -496,7 +496,7 @@ void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
batadv_send_list_add(bat_priv, info);
/* ... we're not the recipient (and thus need to forward). */
- } else if (!batadv_is_my_mac(packet->target_orig)) {
+ } else if (!batadv_is_my_mac(bat_priv, packet->target_orig)) {
batadv_send_list_add(bat_priv, info);
}
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index eb0f4b16ff09..17f33a62f6db 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -397,13 +397,12 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
if (ctrl) {
u8 *assoc;
- assoc = kzalloc(assoc_len, GFP_KERNEL);
+ assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) {
amp_ctrl_put(ctrl);
return -ENOMEM;
}
- memcpy(assoc, rsp->amp_assoc, assoc_len);
ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len;
@@ -472,13 +471,12 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
u8 *assoc;
- assoc = kzalloc(assoc_len, GFP_KERNEL);
+ assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) {
amp_ctrl_put(ctrl);
return -ENOMEM;
}
- memcpy(assoc, req->amp_assoc, assoc_len);
ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len;
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 438a8c56938e..9096137c889c 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -92,23 +92,14 @@ int bt_sock_register(int proto, const struct net_proto_family *ops)
}
EXPORT_SYMBOL(bt_sock_register);
-int bt_sock_unregister(int proto)
+void bt_sock_unregister(int proto)
{
- int err = 0;
-
if (proto < 0 || proto >= BT_MAX_PROTO)
- return -EINVAL;
+ return;
write_lock(&bt_proto_lock);
-
- if (!bt_proto[proto])
- err = -ENOENT;
- else
- bt_proto[proto] = NULL;
-
+ bt_proto[proto] = NULL;
write_unlock(&bt_proto_lock);
-
- return err;
}
EXPORT_SYMBOL(bt_sock_unregister);
@@ -230,6 +221,8 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (flags & (MSG_OOB))
return -EOPNOTSUPP;
+ msg->msg_namelen = 0;
+
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb) {
if (sk->sk_shutdown & RCV_SHUTDOWN)
@@ -237,8 +230,6 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- msg->msg_namelen = 0;
-
copied = skb->len;
if (len < copied) {
msg->msg_flags |= MSG_TRUNC;
@@ -422,7 +413,8 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
return bt_accept_poll(sk);
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
index e58c8b32589c..4b488ec26105 100644
--- a/net/bluetooth/bnep/netdev.c
+++ b/net/bluetooth/bnep/netdev.c
@@ -136,7 +136,7 @@ static u16 bnep_net_eth_proto(struct sk_buff *skb)
struct ethhdr *eh = (void *) skb->data;
u16 proto = ntohs(eh->h_proto);
- if (proto >= 1536)
+ if (proto >= ETH_P_802_3_MIN)
return proto;
if (get_unaligned((__be16 *) skb->data) == htons(0xFFFF))
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index d4686fb7e957..5f051290daba 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -253,8 +253,6 @@ error:
void __exit bnep_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "bnep");
- if (bt_sock_unregister(BTPROTO_BNEP) < 0)
- BT_ERR("Can't unregister BNEP socket");
-
+ bt_sock_unregister(BTPROTO_BNEP);
proto_unregister(&bnep_proto);
}
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 03f26bf85d74..d82787d417bd 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -264,8 +264,6 @@ error:
void cmtp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "cmtp");
- if (bt_sock_unregister(BTPROTO_CMTP) < 0)
- BT_ERR("Can't unregister CMTP socket");
-
+ bt_sock_unregister(BTPROTO_CMTP);
proto_unregister(&cmtp_proto);
}
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 4925a02ae7e4..6c7f36379722 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -117,7 +117,17 @@ static void hci_acl_create_connection_cancel(struct hci_conn *conn)
hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
}
-void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
+static void hci_reject_sco(struct hci_conn *conn)
+{
+ struct hci_cp_reject_sync_conn_req cp;
+
+ cp.reason = HCI_ERROR_REMOTE_USER_TERM;
+ bacpy(&cp.bdaddr, &conn->dst);
+
+ hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp);
+}
+
+void hci_disconnect(struct hci_conn *conn, __u8 reason)
{
struct hci_cp_disconnect cp;
@@ -253,7 +263,7 @@ static void hci_conn_disconnect(struct hci_conn *conn)
hci_amp_disconn(conn, reason);
break;
default:
- hci_acl_disconn(conn, reason);
+ hci_disconnect(conn, reason);
break;
}
}
@@ -276,6 +286,8 @@ static void hci_conn_timeout(struct work_struct *work)
hci_acl_create_connection_cancel(conn);
else if (conn->type == LE_LINK)
hci_le_create_connection_cancel(conn);
+ } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) {
+ hci_reject_sco(conn);
}
break;
case BT_CONFIG:
@@ -398,8 +410,6 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
- atomic_set(&conn->devref, 0);
-
hci_conn_init_sysfs(conn);
return conn;
@@ -433,7 +443,7 @@ int hci_conn_del(struct hci_conn *conn)
struct hci_conn *acl = conn->link;
if (acl) {
acl->link = NULL;
- hci_conn_put(acl);
+ hci_conn_drop(acl);
}
}
@@ -448,12 +458,11 @@ int hci_conn_del(struct hci_conn *conn)
skb_queue_purge(&conn->data_q);
- hci_conn_put_device(conn);
+ hci_conn_del_sysfs(conn);
hci_dev_put(hdev);
- if (conn->handle == 0)
- kfree(conn);
+ hci_conn_put(conn);
return 0;
}
@@ -565,7 +574,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
if (!sco) {
sco = hci_conn_add(hdev, type, dst);
if (!sco) {
- hci_conn_put(acl);
+ hci_conn_drop(acl);
return ERR_PTR(-ENOMEM);
}
}
@@ -835,19 +844,6 @@ void hci_conn_check_pending(struct hci_dev *hdev)
hci_dev_unlock(hdev);
}
-void hci_conn_hold_device(struct hci_conn *conn)
-{
- atomic_inc(&conn->devref);
-}
-EXPORT_SYMBOL(hci_conn_hold_device);
-
-void hci_conn_put_device(struct hci_conn *conn)
-{
- if (atomic_dec_and_test(&conn->devref))
- hci_conn_del_sysfs(conn);
-}
-EXPORT_SYMBOL(hci_conn_put_device);
-
int hci_get_conn_list(void __user *arg)
{
struct hci_conn *c;
@@ -980,7 +976,7 @@ void hci_chan_del(struct hci_chan *chan)
synchronize_rcu();
- hci_conn_put(conn);
+ hci_conn_drop(conn);
skb_queue_purge(&chan->data_q);
kfree(chan);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 60793e7b768b..33843c5c4939 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -57,36 +57,9 @@ static void hci_notify(struct hci_dev *hdev, int event)
/* ---- HCI requests ---- */
-void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
+static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
{
- BT_DBG("%s command 0x%4.4x result 0x%2.2x", hdev->name, cmd, result);
-
- /* If this is the init phase check if the completed command matches
- * the last init command, and if not just return.
- */
- if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
- struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
- u16 opcode = __le16_to_cpu(sent->opcode);
- struct sk_buff *skb;
-
- /* Some CSR based controllers generate a spontaneous
- * reset complete event during init and any pending
- * command will never be completed. In such a case we
- * need to resend whatever was the last sent
- * command.
- */
-
- if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET)
- return;
-
- skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
- if (skb) {
- skb_queue_head(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
-
- return;
- }
+ BT_DBG("%s result 0x%2.2x", hdev->name, result);
if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = result;
@@ -106,22 +79,158 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
}
}
+static struct sk_buff *hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
+ u8 event)
+{
+ struct hci_ev_cmd_complete *ev;
+ struct hci_event_hdr *hdr;
+ struct sk_buff *skb;
+
+ hci_dev_lock(hdev);
+
+ skb = hdev->recv_evt;
+ hdev->recv_evt = NULL;
+
+ hci_dev_unlock(hdev);
+
+ if (!skb)
+ return ERR_PTR(-ENODATA);
+
+ if (skb->len < sizeof(*hdr)) {
+ BT_ERR("Too short HCI event");
+ goto failed;
+ }
+
+ hdr = (void *) skb->data;
+ skb_pull(skb, HCI_EVENT_HDR_SIZE);
+
+ if (event) {
+ if (hdr->evt != event)
+ goto failed;
+ return skb;
+ }
+
+ if (hdr->evt != HCI_EV_CMD_COMPLETE) {
+ BT_DBG("Last event is not cmd complete (0x%2.2x)", hdr->evt);
+ goto failed;
+ }
+
+ if (skb->len < sizeof(*ev)) {
+ BT_ERR("Too short cmd_complete event");
+ goto failed;
+ }
+
+ ev = (void *) skb->data;
+ skb_pull(skb, sizeof(*ev));
+
+ if (opcode == __le16_to_cpu(ev->opcode))
+ return skb;
+
+ BT_DBG("opcode doesn't match (0x%2.2x != 0x%2.2x)", opcode,
+ __le16_to_cpu(ev->opcode));
+
+failed:
+ kfree_skb(skb);
+ return ERR_PTR(-ENODATA);
+}
+
+struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u8 event, u32 timeout)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct hci_request req;
+ int err = 0;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_req_init(&req, hdev);
+
+ hci_req_add_ev(&req, opcode, plen, param, event);
+
+ hdev->req_status = HCI_REQ_PEND;
+
+ err = hci_req_run(&req, hci_req_sync_complete);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ add_wait_queue(&hdev->req_wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ schedule_timeout(timeout);
+
+ remove_wait_queue(&hdev->req_wait_q, &wait);
+
+ if (signal_pending(current))
+ return ERR_PTR(-EINTR);
+
+ switch (hdev->req_status) {
+ case HCI_REQ_DONE:
+ err = -bt_to_errno(hdev->req_result);
+ break;
+
+ case HCI_REQ_CANCELED:
+ err = -hdev->req_result;
+ break;
+
+ default:
+ err = -ETIMEDOUT;
+ break;
+ }
+
+ hdev->req_status = hdev->req_result = 0;
+
+ BT_DBG("%s end: err %d", hdev->name, err);
+
+ if (err < 0)
+ return ERR_PTR(err);
+
+ return hci_get_cmd_complete(hdev, opcode, event);
+}
+EXPORT_SYMBOL(__hci_cmd_sync_ev);
+
+struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
+ const void *param, u32 timeout)
+{
+ return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
+}
+EXPORT_SYMBOL(__hci_cmd_sync);
+
/* Execute request and wait for completion. */
-static int __hci_request(struct hci_dev *hdev,
- void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static int __hci_req_sync(struct hci_dev *hdev,
+ void (*func)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
+ struct hci_request req;
DECLARE_WAITQUEUE(wait, current);
int err = 0;
BT_DBG("%s start", hdev->name);
+ hci_req_init(&req, hdev);
+
hdev->req_status = HCI_REQ_PEND;
+ func(&req, opt);
+
+ err = hci_req_run(&req, hci_req_sync_complete);
+ if (err < 0) {
+ hdev->req_status = 0;
+
+ /* ENODATA means the HCI request command queue is empty.
+ * This can happen when a request with conditionals doesn't
+ * trigger any commands to be sent. This is normal behavior
+ * and should not trigger an error return.
+ */
+ if (err == -ENODATA)
+ return 0;
+
+ return err;
+ }
+
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- req(hdev, opt);
schedule_timeout(timeout);
remove_wait_queue(&hdev->req_wait_q, &wait);
@@ -150,9 +259,10 @@ static int __hci_request(struct hci_dev *hdev,
return err;
}
-static int hci_request(struct hci_dev *hdev,
- void (*req)(struct hci_dev *hdev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+static int hci_req_sync(struct hci_dev *hdev,
+ void (*req)(struct hci_request *req,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
int ret;
@@ -161,75 +271,66 @@ static int hci_request(struct hci_dev *hdev,
/* Serialize all requests */
hci_req_lock(hdev);
- ret = __hci_request(hdev, req, opt, timeout);
+ ret = __hci_req_sync(hdev, req, opt, timeout);
hci_req_unlock(hdev);
return ret;
}
-static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_reset_req(struct hci_request *req, unsigned long opt)
{
- BT_DBG("%s %ld", hdev->name, opt);
+ BT_DBG("%s %ld", req->hdev->name, opt);
/* Reset device */
- set_bit(HCI_RESET, &hdev->flags);
- hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
+ set_bit(HCI_RESET, &req->hdev->flags);
+ hci_req_add(req, HCI_OP_RESET, 0, NULL);
}
-static void bredr_init(struct hci_dev *hdev)
+static void bredr_init(struct hci_request *req)
{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
+ req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
/* Read Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
/* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+
+ /* Read BD Address */
+ hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
}
-static void amp_init(struct hci_dev *hdev)
+static void amp_init(struct hci_request *req)
{
- hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
+ req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
/* Read Local Version */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read Local AMP Info */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
/* Read Data Blk size */
- hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
}
-static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_init1_req(struct hci_request *req, unsigned long opt)
{
- struct sk_buff *skb;
+ struct hci_dev *hdev = req->hdev;
BT_DBG("%s %ld", hdev->name, opt);
- /* Driver initialization */
-
- /* Special commands */
- while ((skb = skb_dequeue(&hdev->driver_init))) {
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
-
- skb_queue_tail(&hdev->cmd_q, skb);
- queue_work(hdev->workqueue, &hdev->cmd_work);
- }
- skb_queue_purge(&hdev->driver_init);
-
/* Reset */
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
- hci_reset_req(hdev, 0);
+ hci_reset_req(req, 0);
switch (hdev->dev_type) {
case HCI_BREDR:
- bredr_init(hdev);
+ bredr_init(req);
break;
case HCI_AMP:
- amp_init(hdev);
+ amp_init(req);
break;
default:
@@ -238,44 +339,347 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
}
}
-static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
+static void bredr_setup(struct hci_request *req)
+{
+ struct hci_cp_delete_stored_link_key cp;
+ __le16 param;
+ __u8 flt_type;
+
+ /* Read Buffer Size (ACL mtu, max pkt, etc.) */
+ hci_req_add(req, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+
+ /* Read Class of Device */
+ hci_req_add(req, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+ /* Read Local Name */
+ hci_req_add(req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+
+ /* Read Voice Setting */
+ hci_req_add(req, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+
+ /* Clear Event Filters */
+ flt_type = HCI_FLT_CLEAR_ALL;
+ hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+
+ /* Connection accept timeout ~20 secs */
+ param = __constant_cpu_to_le16(0x7d00);
+ hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+
+ bacpy(&cp.bdaddr, BDADDR_ANY);
+ cp.delete_all = 0x01;
+ hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+
+ /* Read page scan parameters */
+ if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) {
+ hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
+ hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
+ }
+}
+
+static void le_setup(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ /* Read LE Buffer Size */
+ hci_req_add(req, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+ /* Read LE Local Supported Features */
+ hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
+
+ /* Read LE Advertising Channel TX Power */
+ hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
+
+ /* Read LE White List Size */
+ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
+
+ /* Read LE Supported States */
+ hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
+
+ /* LE-only controllers have LE implicitly enabled */
+ if (!lmp_bredr_capable(hdev))
+ set_bit(HCI_LE_ENABLED, &hdev->dev_flags);
+}
+
+static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
+{
+ if (lmp_ext_inq_capable(hdev))
+ return 0x02;
+
+ if (lmp_inq_rssi_capable(hdev))
+ return 0x01;
+
+ if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
+ hdev->lmp_subver == 0x0757)
+ return 0x01;
+
+ if (hdev->manufacturer == 15) {
+ if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
+ return 0x01;
+ if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
+ return 0x01;
+ if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
+ return 0x01;
+ }
+
+ if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
+ hdev->lmp_subver == 0x1805)
+ return 0x01;
+
+ return 0x00;
+}
+
+static void hci_setup_inquiry_mode(struct hci_request *req)
+{
+ u8 mode;
+
+ mode = hci_get_inquiry_mode(req->hdev);
+
+ hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
+}
+
+static void hci_setup_event_mask(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ /* The second byte is 0xff instead of 0x9f (two reserved bits
+ * disabled) since a Broadcom 1.2 dongle doesn't respond to the
+ * command otherwise.
+ */
+ u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
+
+ /* CSR 1.1 dongles does not accept any bitfield so don't try to set
+ * any event mask for pre 1.2 devices.
+ */
+ if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+ return;
+
+ if (lmp_bredr_capable(hdev)) {
+ events[4] |= 0x01; /* Flow Specification Complete */
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
+ events[4] |= 0x04; /* Read Remote Extended Features Complete */
+ events[5] |= 0x08; /* Synchronous Connection Complete */
+ events[5] |= 0x10; /* Synchronous Connection Changed */
+ }
+
+ if (lmp_inq_rssi_capable(hdev))
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
+
+ if (lmp_sniffsubr_capable(hdev))
+ events[5] |= 0x20; /* Sniff Subrating */
+
+ if (lmp_pause_enc_capable(hdev))
+ events[5] |= 0x80; /* Encryption Key Refresh Complete */
+
+ if (lmp_ext_inq_capable(hdev))
+ events[5] |= 0x40; /* Extended Inquiry Result */
+
+ if (lmp_no_flush_capable(hdev))
+ events[7] |= 0x01; /* Enhanced Flush Complete */
+
+ if (lmp_lsto_capable(hdev))
+ events[6] |= 0x80; /* Link Supervision Timeout Changed */
+
+ if (lmp_ssp_capable(hdev)) {
+ events[6] |= 0x01; /* IO Capability Request */
+ events[6] |= 0x02; /* IO Capability Response */
+ events[6] |= 0x04; /* User Confirmation Request */
+ events[6] |= 0x08; /* User Passkey Request */
+ events[6] |= 0x10; /* Remote OOB Data Request */
+ events[6] |= 0x20; /* Simple Pairing Complete */
+ events[7] |= 0x04; /* User Passkey Notification */
+ events[7] |= 0x08; /* Keypress Notification */
+ events[7] |= 0x10; /* Remote Host Supported
+ * Features Notification
+ */
+ }
+
+ if (lmp_le_capable(hdev))
+ events[7] |= 0x20; /* LE Meta-Event */
+
+ hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
+
+ if (lmp_le_capable(hdev)) {
+ memset(events, 0, sizeof(events));
+ events[0] = 0x1f;
+ hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK,
+ sizeof(events), events);
+ }
+}
+
+static void hci_init2_req(struct hci_request *req, unsigned long opt)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ if (lmp_bredr_capable(hdev))
+ bredr_setup(req);
+
+ if (lmp_le_capable(hdev))
+ le_setup(req);
+
+ hci_setup_event_mask(req);
+
+ if (hdev->hci_ver > BLUETOOTH_VER_1_1)
+ hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
+
+ if (lmp_ssp_capable(hdev)) {
+ if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+ u8 mode = 0x01;
+ hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
+ sizeof(mode), &mode);
+ } else {
+ struct hci_cp_write_eir cp;
+
+ memset(hdev->eir, 0, sizeof(hdev->eir));
+ memset(&cp, 0, sizeof(cp));
+
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ }
+ }
+
+ if (lmp_inq_rssi_capable(hdev))
+ hci_setup_inquiry_mode(req);
+
+ if (lmp_inq_tx_pwr_capable(hdev))
+ hci_req_add(req, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
+
+ if (lmp_ext_feat_capable(hdev)) {
+ struct hci_cp_read_local_ext_features cp;
+
+ cp.page = 0x01;
+ hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
+ sizeof(cp), &cp);
+ }
+
+ if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
+ u8 enable = 1;
+ hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
+ &enable);
+ }
+}
+
+static void hci_setup_link_policy(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_def_link_policy cp;
+ u16 link_policy = 0;
+
+ if (lmp_rswitch_capable(hdev))
+ link_policy |= HCI_LP_RSWITCH;
+ if (lmp_hold_capable(hdev))
+ link_policy |= HCI_LP_HOLD;
+ if (lmp_sniff_capable(hdev))
+ link_policy |= HCI_LP_SNIFF;
+ if (lmp_park_capable(hdev))
+ link_policy |= HCI_LP_PARK;
+
+ cp.policy = cpu_to_le16(link_policy);
+ hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
+}
+
+static void hci_set_le_support(struct hci_request *req)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_le_host_supported cp;
+
+ /* LE-only devices do not support explicit enablement */
+ if (!lmp_bredr_capable(hdev))
+ return;
+
+ memset(&cp, 0, sizeof(cp));
+
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+ cp.le = 0x01;
+ cp.simul = lmp_le_br_capable(hdev);
+ }
+
+ if (cp.le != lmp_host_le_capable(hdev))
+ hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
+ &cp);
+}
+
+static void hci_init3_req(struct hci_request *req, unsigned long opt)
+{
+ struct hci_dev *hdev = req->hdev;
+ u8 p;
+
+ if (hdev->commands[5] & 0x10)
+ hci_setup_link_policy(req);
+
+ if (lmp_le_capable(hdev)) {
+ hci_set_le_support(req);
+ hci_update_ad(req);
+ }
+
+ /* Read features beyond page 1 if available */
+ for (p = 2; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
+ struct hci_cp_read_local_ext_features cp;
+
+ cp.page = p;
+ hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
+ sizeof(cp), &cp);
+ }
+}
+
+static int __hci_init(struct hci_dev *hdev)
+{
+ int err;
+
+ err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ /* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode
+ * BR/EDR/LE type controllers. AMP controllers only need the
+ * first stage init.
+ */
+ if (hdev->dev_type != HCI_BREDR)
+ return 0;
+
+ err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ return __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
+}
+
+static void hci_scan_req(struct hci_request *req, unsigned long opt)
{
__u8 scan = opt;
- BT_DBG("%s %x", hdev->name, scan);
+ BT_DBG("%s %x", req->hdev->name, scan);
/* Inquiry and Page scans */
- hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
-static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_auth_req(struct hci_request *req, unsigned long opt)
{
__u8 auth = opt;
- BT_DBG("%s %x", hdev->name, auth);
+ BT_DBG("%s %x", req->hdev->name, auth);
/* Authentication */
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
+ hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
}
-static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_encrypt_req(struct hci_request *req, unsigned long opt)
{
__u8 encrypt = opt;
- BT_DBG("%s %x", hdev->name, encrypt);
+ BT_DBG("%s %x", req->hdev->name, encrypt);
/* Encryption */
- hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
+ hci_req_add(req, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
}
-static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_linkpol_req(struct hci_request *req, unsigned long opt)
{
__le16 policy = cpu_to_le16(opt);
- BT_DBG("%s %x", hdev->name, policy);
+ BT_DBG("%s %x", req->hdev->name, policy);
/* Default link policy */
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
+ hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
}
/* Get HCI device by index.
@@ -512,9 +916,10 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
return copied;
}
-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+static void hci_inq_req(struct hci_request *req, unsigned long opt)
{
struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_inquiry cp;
BT_DBG("%s", hdev->name);
@@ -526,7 +931,13 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
memcpy(&cp.lap, &ir->lap, 3);
cp.length = ir->length;
cp.num_rsp = ir->num_rsp;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
+}
+
+static int wait_inquiry(void *word)
+{
+ schedule();
+ return signal_pending(current);
}
int hci_inquiry(void __user *arg)
@@ -556,9 +967,17 @@ int hci_inquiry(void __user *arg)
timeo = ir.length * msecs_to_jiffies(2000);
if (do_inquiry) {
- err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);
+ err = hci_req_sync(hdev, hci_inq_req, (unsigned long) &ir,
+ timeo);
if (err < 0)
goto done;
+
+ /* Wait until Inquiry procedure finishes (HCI_INQUIRY flag is
+ * cleared). If it is interrupted by a signal, return -EINTR.
+ */
+ if (wait_on_bit(&hdev->flags, HCI_INQUIRY, wait_inquiry,
+ TASK_INTERRUPTIBLE))
+ return -EINTR;
}
/* for unlimited number of responses we will use buffer with
@@ -654,39 +1073,29 @@ static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
return ad_len;
}
-int hci_update_ad(struct hci_dev *hdev)
+void hci_update_ad(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp;
u8 len;
- int err;
-
- hci_dev_lock(hdev);
- if (!lmp_le_capable(hdev)) {
- err = -EINVAL;
- goto unlock;
- }
+ if (!lmp_le_capable(hdev))
+ return;
memset(&cp, 0, sizeof(cp));
len = create_ad(hdev, cp.data);
if (hdev->adv_data_len == len &&
- memcmp(cp.data, hdev->adv_data, len) == 0) {
- err = 0;
- goto unlock;
- }
+ memcmp(cp.data, hdev->adv_data, len) == 0)
+ return;
memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
hdev->adv_data_len = len;
cp.length = len;
- err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
-unlock:
- hci_dev_unlock(hdev);
-
- return err;
+ hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
}
/* ---- HCI ioctl helpers ---- */
@@ -719,34 +1128,37 @@ int hci_dev_open(__u16 dev)
goto done;
}
- if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
- set_bit(HCI_RAW, &hdev->flags);
-
- /* Treat all non BR/EDR controllers as raw devices if
- enable_hs is not set */
- if (hdev->dev_type != HCI_BREDR && !enable_hs)
- set_bit(HCI_RAW, &hdev->flags);
-
if (hdev->open(hdev)) {
ret = -EIO;
goto done;
}
- if (!test_bit(HCI_RAW, &hdev->flags)) {
- atomic_set(&hdev->cmd_cnt, 1);
- set_bit(HCI_INIT, &hdev->flags);
- hdev->init_last_cmd = 0;
+ atomic_set(&hdev->cmd_cnt, 1);
+ set_bit(HCI_INIT, &hdev->flags);
- ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+ if (hdev->setup && test_bit(HCI_SETUP, &hdev->dev_flags))
+ ret = hdev->setup(hdev);
- clear_bit(HCI_INIT, &hdev->flags);
+ if (!ret) {
+ /* Treat all non BR/EDR controllers as raw devices if
+ * enable_hs is not set.
+ */
+ if (hdev->dev_type != HCI_BREDR && !enable_hs)
+ set_bit(HCI_RAW, &hdev->flags);
+
+ if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+ set_bit(HCI_RAW, &hdev->flags);
+
+ if (!test_bit(HCI_RAW, &hdev->flags))
+ ret = __hci_init(hdev);
}
+ clear_bit(HCI_INIT, &hdev->flags);
+
if (!ret) {
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
- hci_update_ad(hdev);
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
@@ -828,7 +1240,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if (!test_bit(HCI_RAW, &hdev->flags) &&
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags);
- __hci_request(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
+ __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
clear_bit(HCI_INIT, &hdev->flags);
}
@@ -847,10 +1259,17 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hdev->sent_cmd = NULL;
}
+ kfree_skb(hdev->recv_evt);
+ hdev->recv_evt = NULL;
+
/* After this point our queues are empty
* and no tasks are scheduled. */
hdev->close(hdev);
+ /* Clear flags */
+ hdev->flags = 0;
+ hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
+
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
@@ -858,9 +1277,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_unlock(hdev);
}
- /* Clear flags */
- hdev->flags = 0;
-
/* Controller radio is available but is currently powered down */
hdev->amp_status = 0;
@@ -921,7 +1337,7 @@ int hci_dev_reset(__u16 dev)
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags))
- ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+ ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
done:
hci_req_unlock(hdev);
@@ -960,8 +1376,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
switch (cmd) {
case HCISETAUTH:
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETENCRYPT:
@@ -972,24 +1388,24 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
if (!test_bit(HCI_AUTH, &hdev->flags)) {
/* Auth must be enabled first */
- err = hci_request(hdev, hci_auth_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
if (err)
break;
}
- err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_encrypt_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETSCAN:
- err = hci_request(hdev, hci_scan_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETLINKPOL:
- err = hci_request(hdev, hci_linkpol_req, dr.dev_opt,
- HCI_INIT_TIMEOUT);
+ err = hci_req_sync(hdev, hci_linkpol_req, dr.dev_opt,
+ HCI_INIT_TIMEOUT);
break;
case HCISETLINKMODE:
@@ -1566,7 +1982,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type);
}
-static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
+static void le_scan_param_req(struct hci_request *req, unsigned long opt)
{
struct le_scan_params *param = (struct le_scan_params *) opt;
struct hci_cp_le_set_scan_param cp;
@@ -1576,18 +1992,18 @@ static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
cp.interval = cpu_to_le16(param->interval);
cp.window = cpu_to_le16(param->window);
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
}
-static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
+static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
{
struct hci_cp_le_set_scan_enable cp;
memset(&cp, 0, sizeof(cp));
- cp.enable = 1;
- cp.filter_dup = 1;
+ cp.enable = LE_SCAN_ENABLE;
+ cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
- hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
@@ -1608,10 +2024,10 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
hci_req_lock(hdev);
- err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param,
- timeo);
+ err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) &param,
+ timeo);
if (!err)
- err = __hci_request(hdev, le_scan_enable_req, 0, timeo);
+ err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
hci_req_unlock(hdev);
@@ -1619,7 +2035,7 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
return err;
queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
- msecs_to_jiffies(timeout));
+ timeout);
return 0;
}
@@ -1729,7 +2145,6 @@ struct hci_dev *hci_alloc_dev(void)
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
- skb_queue_head_init(&hdev->driver_init);
skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
@@ -1748,8 +2163,6 @@ EXPORT_SYMBOL(hci_alloc_dev);
/* Free HCI device */
void hci_free_dev(struct hci_dev *hdev)
{
- skb_queue_purge(&hdev->driver_init);
-
/* will free via device release */
put_device(&hdev->dev);
}
@@ -2160,20 +2573,55 @@ static int hci_send_frame(struct sk_buff *skb)
return hdev->send(skb);
}
-/* Send HCI command */
-int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
+void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
+{
+ skb_queue_head_init(&req->cmd_q);
+ req->hdev = hdev;
+ req->err = 0;
+}
+
+int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ BT_DBG("length %u", skb_queue_len(&req->cmd_q));
+
+ /* If an error occured during request building, remove all HCI
+ * commands queued on the HCI request queue.
+ */
+ if (req->err) {
+ skb_queue_purge(&req->cmd_q);
+ return req->err;
+ }
+
+ /* Do not allow empty requests */
+ if (skb_queue_empty(&req->cmd_q))
+ return -ENODATA;
+
+ skb = skb_peek_tail(&req->cmd_q);
+ bt_cb(skb)->req.complete = complete;
+
+ spin_lock_irqsave(&hdev->cmd_q.lock, flags);
+ skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
+ spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
+
+ queue_work(hdev->workqueue, &hdev->cmd_work);
+
+ return 0;
+}
+
+static struct sk_buff *hci_prepare_cmd(struct hci_dev *hdev, u16 opcode,
+ u32 plen, const void *param)
{
int len = HCI_COMMAND_HDR_SIZE + plen;
struct hci_command_hdr *hdr;
struct sk_buff *skb;
- BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
-
skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for command", hdev->name);
- return -ENOMEM;
- }
+ if (!skb)
+ return NULL;
hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
hdr->opcode = cpu_to_le16(opcode);
@@ -2187,8 +2635,27 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
+ return skb;
+}
+
+/* Send HCI command */
+int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
+ const void *param)
+{
+ struct sk_buff *skb;
+
+ BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
+
+ skb = hci_prepare_cmd(hdev, opcode, plen, param);
+ if (!skb) {
+ BT_ERR("%s no memory for command", hdev->name);
+ return -ENOMEM;
+ }
+
+ /* Stand-alone HCI commands must be flaged as
+ * single-command requests.
+ */
+ bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
@@ -2196,6 +2663,43 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
return 0;
}
+/* Queue a command to an asynchronous HCI request */
+void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param, u8 event)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct sk_buff *skb;
+
+ BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
+
+ /* If an error occured during request building, there is no point in
+ * queueing the HCI command. We can simply return.
+ */
+ if (req->err)
+ return;
+
+ skb = hci_prepare_cmd(hdev, opcode, plen, param);
+ if (!skb) {
+ BT_ERR("%s no memory for command (opcode 0x%4.4x)",
+ hdev->name, opcode);
+ req->err = -ENOMEM;
+ return;
+ }
+
+ if (skb_queue_empty(&req->cmd_q))
+ bt_cb(skb)->req.start = true;
+
+ bt_cb(skb)->req.event = event;
+
+ skb_queue_tail(&req->cmd_q, skb);
+}
+
+void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
+ const void *param)
+{
+ hci_req_add_ev(req, opcode, plen, param, 0);
+}
+
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{
@@ -2398,7 +2902,7 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
if (c->type == type && c->sent) {
BT_ERR("%s killing stalled connection %pMR",
hdev->name, &c->dst);
- hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
+ hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM);
}
}
@@ -2860,6 +3364,97 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
kfree_skb(skb);
}
+static bool hci_req_is_complete(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+
+ skb = skb_peek(&hdev->cmd_q);
+ if (!skb)
+ return true;
+
+ return bt_cb(skb)->req.start;
+}
+
+static void hci_resend_last(struct hci_dev *hdev)
+{
+ struct hci_command_hdr *sent;
+ struct sk_buff *skb;
+ u16 opcode;
+
+ if (!hdev->sent_cmd)
+ return;
+
+ sent = (void *) hdev->sent_cmd->data;
+ opcode = __le16_to_cpu(sent->opcode);
+ if (opcode == HCI_OP_RESET)
+ return;
+
+ skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
+ if (!skb)
+ return;
+
+ skb_queue_head(&hdev->cmd_q, skb);
+ queue_work(hdev->workqueue, &hdev->cmd_work);
+}
+
+void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
+{
+ hci_req_complete_t req_complete = NULL;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
+
+ /* If the completed command doesn't match the last one that was
+ * sent we need to do special handling of it.
+ */
+ if (!hci_sent_cmd_data(hdev, opcode)) {
+ /* Some CSR based controllers generate a spontaneous
+ * reset complete event during init and any pending
+ * command will never be completed. In such a case we
+ * need to resend whatever was the last sent
+ * command.
+ */
+ if (test_bit(HCI_INIT, &hdev->flags) && opcode == HCI_OP_RESET)
+ hci_resend_last(hdev);
+
+ return;
+ }
+
+ /* If the command succeeded and there's still more commands in
+ * this request the request is not yet complete.
+ */
+ if (!status && !hci_req_is_complete(hdev))
+ return;
+
+ /* If this was the last command in a request the complete
+ * callback would be found in hdev->sent_cmd instead of the
+ * command queue (hdev->cmd_q).
+ */
+ if (hdev->sent_cmd) {
+ req_complete = bt_cb(hdev->sent_cmd)->req.complete;
+ if (req_complete)
+ goto call_complete;
+ }
+
+ /* Remove all pending commands belonging to this request */
+ spin_lock_irqsave(&hdev->cmd_q.lock, flags);
+ while ((skb = __skb_dequeue(&hdev->cmd_q))) {
+ if (bt_cb(skb)->req.start) {
+ __skb_queue_head(&hdev->cmd_q, skb);
+ break;
+ }
+
+ req_complete = bt_cb(skb)->req.complete;
+ kfree_skb(skb);
+ }
+ spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
+
+call_complete:
+ if (req_complete)
+ req_complete(hdev, status);
+}
+
static void hci_rx_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 477726a63512..b93cd2eb5d58 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -48,13 +48,13 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
}
clear_bit(HCI_INQUIRY, &hdev->flags);
+ smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
+ wake_up_bit(&hdev->flags, HCI_INQUIRY);
hci_dev_lock(hdev);
hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
-
hci_conn_check_pending(hdev);
}
@@ -183,8 +183,6 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
if (!status)
hdev->link_policy = get_unaligned_le16(sent);
-
- hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
}
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
@@ -195,11 +193,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_RESET, &hdev->flags);
- hci_req_complete(hdev, HCI_OP_RESET, status);
-
/* Reset all non-persistent flags */
- hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) |
- BIT(HCI_PERIODIC_INQ));
+ hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
hdev->discovery.state = DISCOVERY_STOPPED;
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
@@ -228,11 +223,6 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
hci_dev_unlock(hdev);
-
- if (!status && !test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -270,8 +260,6 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_auth_enable_complete(hdev, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
}
static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
@@ -293,8 +281,6 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
else
clear_bit(HCI_ENCRYPT, &hdev->flags);
}
-
- hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
}
static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
@@ -343,7 +329,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
done:
hci_dev_unlock(hdev);
- hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
}
static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
@@ -435,15 +420,6 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
}
-static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
-}
-
static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -457,9 +433,9 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
if (!status) {
if (sent->mode)
- hdev->host_features[0] |= LMP_HOST_SSP;
+ hdev->features[1][0] |= LMP_HOST_SSP;
else
- hdev->host_features[0] &= ~LMP_HOST_SSP;
+ hdev->features[1][0] &= ~LMP_HOST_SSP;
}
if (test_bit(HCI_MGMT, &hdev->dev_flags))
@@ -472,211 +448,6 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
}
}
-static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
-{
- if (lmp_ext_inq_capable(hdev))
- return 2;
-
- if (lmp_inq_rssi_capable(hdev))
- return 1;
-
- if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
- hdev->lmp_subver == 0x0757)
- return 1;
-
- if (hdev->manufacturer == 15) {
- if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
- return 1;
- if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
- return 1;
- }
-
- if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
- hdev->lmp_subver == 0x1805)
- return 1;
-
- return 0;
-}
-
-static void hci_setup_inquiry_mode(struct hci_dev *hdev)
-{
- u8 mode;
-
- mode = hci_get_inquiry_mode(hdev);
-
- hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
-}
-
-static void hci_setup_event_mask(struct hci_dev *hdev)
-{
- /* The second byte is 0xff instead of 0x9f (two reserved bits
- * disabled) since a Broadcom 1.2 dongle doesn't respond to the
- * command otherwise */
- u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
- /* CSR 1.1 dongles does not accept any bitfield so don't try to set
- * any event mask for pre 1.2 devices */
- if (hdev->hci_ver < BLUETOOTH_VER_1_2)
- return;
-
- if (lmp_bredr_capable(hdev)) {
- events[4] |= 0x01; /* Flow Specification Complete */
- events[4] |= 0x02; /* Inquiry Result with RSSI */
- events[4] |= 0x04; /* Read Remote Extended Features Complete */
- events[5] |= 0x08; /* Synchronous Connection Complete */
- events[5] |= 0x10; /* Synchronous Connection Changed */
- }
-
- if (lmp_inq_rssi_capable(hdev))
- events[4] |= 0x02; /* Inquiry Result with RSSI */
-
- if (lmp_sniffsubr_capable(hdev))
- events[5] |= 0x20; /* Sniff Subrating */
-
- if (lmp_pause_enc_capable(hdev))
- events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
- if (lmp_ext_inq_capable(hdev))
- events[5] |= 0x40; /* Extended Inquiry Result */
-
- if (lmp_no_flush_capable(hdev))
- events[7] |= 0x01; /* Enhanced Flush Complete */
-
- if (lmp_lsto_capable(hdev))
- events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
- if (lmp_ssp_capable(hdev)) {
- events[6] |= 0x01; /* IO Capability Request */
- events[6] |= 0x02; /* IO Capability Response */
- events[6] |= 0x04; /* User Confirmation Request */
- events[6] |= 0x08; /* User Passkey Request */
- events[6] |= 0x10; /* Remote OOB Data Request */
- events[6] |= 0x20; /* Simple Pairing Complete */
- events[7] |= 0x04; /* User Passkey Notification */
- events[7] |= 0x08; /* Keypress Notification */
- events[7] |= 0x10; /* Remote Host Supported
- * Features Notification */
- }
-
- if (lmp_le_capable(hdev))
- events[7] |= 0x20; /* LE Meta-Event */
-
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
-
- if (lmp_le_capable(hdev)) {
- memset(events, 0, sizeof(events));
- events[0] = 0x1f;
- hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
- sizeof(events), events);
- }
-}
-
-static void bredr_setup(struct hci_dev *hdev)
-{
- struct hci_cp_delete_stored_link_key cp;
- __le16 param;
- __u8 flt_type;
-
- /* Read Buffer Size (ACL mtu, max pkt, etc.) */
- hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read Class of Device */
- hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
- /* Read Local Name */
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
- /* Read Voice Setting */
- hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
- /* Clear Event Filters */
- flt_type = HCI_FLT_CLEAR_ALL;
- hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
- /* Connection accept timeout ~20 secs */
- param = __constant_cpu_to_le16(0x7d00);
- hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
- bacpy(&cp.bdaddr, BDADDR_ANY);
- cp.delete_all = 1;
- hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
-}
-
-static void le_setup(struct hci_dev *hdev)
-{
- /* Read LE Buffer Size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-
- /* Read LE Local Supported Features */
- hci_send_cmd(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
-
- /* Read LE Advertising Channel TX Power */
- hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
-
- /* Read LE White List Size */
- hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
-
- /* Read LE Supported States */
- hci_send_cmd(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
-}
-
-static void hci_setup(struct hci_dev *hdev)
-{
- if (hdev->dev_type != HCI_BREDR)
- return;
-
- /* Read BD Address */
- hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
- if (lmp_bredr_capable(hdev))
- bredr_setup(hdev);
-
- if (lmp_le_capable(hdev))
- le_setup(hdev);
-
- hci_setup_event_mask(hdev);
-
- if (hdev->hci_ver > BLUETOOTH_VER_1_1)
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
-
- if (lmp_ssp_capable(hdev)) {
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
- u8 mode = 0x01;
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
- sizeof(mode), &mode);
- } else {
- struct hci_cp_write_eir cp;
-
- memset(hdev->eir, 0, sizeof(hdev->eir));
- memset(&cp, 0, sizeof(cp));
-
- hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
- }
- }
-
- if (lmp_inq_rssi_capable(hdev))
- hci_setup_inquiry_mode(hdev);
-
- if (lmp_inq_tx_pwr_capable(hdev))
- hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
-
- if (lmp_ext_feat_capable(hdev)) {
- struct hci_cp_read_local_ext_features cp;
-
- cp.page = 0x01;
- hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
- &cp);
- }
-
- if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
- u8 enable = 1;
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
- &enable);
- }
-}
-
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_local_version *rp = (void *) skb->data;
@@ -684,7 +455,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- goto done;
+ return;
hdev->hci_ver = rp->hci_ver;
hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
@@ -694,30 +465,6 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name,
hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
-
- if (test_bit(HCI_INIT, &hdev->flags))
- hci_setup(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
-}
-
-static void hci_setup_link_policy(struct hci_dev *hdev)
-{
- struct hci_cp_write_def_link_policy cp;
- u16 link_policy = 0;
-
- if (lmp_rswitch_capable(hdev))
- link_policy |= HCI_LP_RSWITCH;
- if (lmp_hold_capable(hdev))
- link_policy |= HCI_LP_HOLD;
- if (lmp_sniff_capable(hdev))
- link_policy |= HCI_LP_SNIFF;
- if (lmp_park_capable(hdev))
- link_policy |= HCI_LP_PARK;
-
- cp.policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
}
static void hci_cc_read_local_commands(struct hci_dev *hdev,
@@ -727,16 +474,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- goto done;
-
- memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
-
- if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
- hci_setup_link_policy(hdev);
-
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
+ if (!rp->status)
+ memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
}
static void hci_cc_read_local_features(struct hci_dev *hdev,
@@ -754,18 +493,18 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
/* Adjust default settings according to features
* supported by device. */
- if (hdev->features[0] & LMP_3SLOT)
+ if (hdev->features[0][0] & LMP_3SLOT)
hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
- if (hdev->features[0] & LMP_5SLOT)
+ if (hdev->features[0][0] & LMP_5SLOT)
hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
- if (hdev->features[1] & LMP_HV2) {
+ if (hdev->features[0][1] & LMP_HV2) {
hdev->pkt_type |= (HCI_HV2);
hdev->esco_type |= (ESCO_HV2);
}
- if (hdev->features[1] & LMP_HV3) {
+ if (hdev->features[0][1] & LMP_HV3) {
hdev->pkt_type |= (HCI_HV3);
hdev->esco_type |= (ESCO_HV3);
}
@@ -773,42 +512,26 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
if (lmp_esco_capable(hdev))
hdev->esco_type |= (ESCO_EV3);
- if (hdev->features[4] & LMP_EV4)
+ if (hdev->features[0][4] & LMP_EV4)
hdev->esco_type |= (ESCO_EV4);
- if (hdev->features[4] & LMP_EV5)
+ if (hdev->features[0][4] & LMP_EV5)
hdev->esco_type |= (ESCO_EV5);
- if (hdev->features[5] & LMP_EDR_ESCO_2M)
+ if (hdev->features[0][5] & LMP_EDR_ESCO_2M)
hdev->esco_type |= (ESCO_2EV3);
- if (hdev->features[5] & LMP_EDR_ESCO_3M)
+ if (hdev->features[0][5] & LMP_EDR_ESCO_3M)
hdev->esco_type |= (ESCO_3EV3);
- if (hdev->features[5] & LMP_EDR_3S_ESCO)
+ if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
- hdev->features[0], hdev->features[1],
- hdev->features[2], hdev->features[3],
- hdev->features[4], hdev->features[5],
- hdev->features[6], hdev->features[7]);
-}
-
-static void hci_set_le_support(struct hci_dev *hdev)
-{
- struct hci_cp_write_le_host_supported cp;
-
- memset(&cp, 0, sizeof(cp));
-
- if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- cp.le = 1;
- cp.simul = lmp_le_br_capable(hdev);
- }
-
- if (cp.le != lmp_host_le_capable(hdev))
- hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
- &cp);
+ hdev->features[0][0], hdev->features[0][1],
+ hdev->features[0][2], hdev->features[0][3],
+ hdev->features[0][4], hdev->features[0][5],
+ hdev->features[0][6], hdev->features[0][7]);
}
static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
@@ -819,22 +542,12 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- goto done;
-
- switch (rp->page) {
- case 0:
- memcpy(hdev->features, rp->features, 8);
- break;
- case 1:
- memcpy(hdev->host_features, rp->features, 8);
- break;
- }
+ return;
- if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
- hci_set_le_support(hdev);
+ hdev->max_page = rp->max_page;
-done:
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
+ if (rp->page < HCI_MAX_PAGES)
+ memcpy(hdev->features[rp->page], rp->features, 8);
}
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
@@ -844,12 +557,8 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (rp->status)
- return;
-
- hdev->flow_ctl_mode = rp->mode;
-
- hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
+ if (!rp->status)
+ hdev->flow_ctl_mode = rp->mode;
}
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
@@ -886,8 +595,65 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
if (!rp->status)
bacpy(&hdev->bdaddr, &rp->bdaddr);
+}
+
+static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
+ if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) {
+ hdev->page_scan_interval = __le16_to_cpu(rp->interval);
+ hdev->page_scan_window = __le16_to_cpu(rp->window);
+ }
+}
+
+static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ u8 status = *((u8 *) skb->data);
+ struct hci_cp_write_page_scan_activity *sent;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (status)
+ return;
+
+ sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
+ if (!sent)
+ return;
+
+ hdev->page_scan_interval = __le16_to_cpu(sent->interval);
+ hdev->page_scan_window = __le16_to_cpu(sent->window);
+}
+
+static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (test_bit(HCI_INIT, &hdev->flags) && !rp->status)
+ hdev->page_scan_type = rp->type;
+}
+
+static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ u8 status = *((u8 *) skb->data);
+ u8 *type;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (status)
+ return;
+
+ type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
+ if (type)
+ hdev->page_scan_type = *type;
}
static void hci_cc_read_data_block_size(struct hci_dev *hdev,
@@ -908,17 +674,6 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
hdev->block_cnt, hdev->block_len);
-
- hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
-}
-
-static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
}
static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
@@ -942,8 +697,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
- hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
-
a2mp_rsp:
a2mp_send_getinfo_rsp(hdev);
}
@@ -985,35 +738,6 @@ a2mp_rsp:
a2mp_send_create_phy_link_req(hdev, rp->status);
}
-static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
-}
-
-static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
-}
-
-static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
-}
-
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -1023,17 +747,6 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
if (!rp->status)
hdev->inq_tx_power = rp->tx_power;
-
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status);
-}
-
-static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
}
static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1095,8 +808,6 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
hdev->le_cnt = hdev->le_pkts;
BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
}
static void hci_cc_le_read_local_features(struct hci_dev *hdev,
@@ -1108,8 +819,6 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
if (!rp->status)
memcpy(hdev->le_features, rp->features, 8);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, rp->status);
}
static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
@@ -1119,22 +828,8 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
- if (!rp->status) {
+ if (!rp->status)
hdev->adv_tx_power = rp->tx_power;
- if (!test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
- }
-
- hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
-}
-
-static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
-{
- __u8 status = *((__u8 *) skb->data);
-
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-
- hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
}
static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1231,12 +926,15 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
}
- hci_dev_unlock(hdev);
+ if (!test_bit(HCI_INIT, &hdev->flags)) {
+ struct hci_request req;
- if (!test_bit(HCI_INIT, &hdev->flags))
- hci_update_ad(hdev);
+ hci_req_init(&req, hdev);
+ hci_update_ad(&req);
+ hci_req_run(&req, NULL);
+ }
- hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
+ hci_dev_unlock(hdev);
}
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1245,8 +943,6 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
-
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
@@ -1268,9 +964,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
return;
switch (cp->enable) {
- case LE_SCANNING_ENABLED:
- hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
-
+ case LE_SCAN_ENABLE:
if (status) {
hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status);
@@ -1285,7 +979,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
hci_dev_unlock(hdev);
break;
- case LE_SCANNING_DISABLED:
+ case LE_SCAN_DISABLE:
if (status) {
hci_dev_lock(hdev);
mgmt_stop_discovery_failed(hdev, status);
@@ -1321,32 +1015,6 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
if (!rp->status)
hdev->le_white_list_size = rp->size;
-
- hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status);
-}
-
-static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
-}
-
-static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
-
- if (rp->status)
- return;
-
- hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
}
static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
@@ -1358,8 +1026,6 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
if (!rp->status)
memcpy(hdev->le_states, rp->le_states, 8);
-
- hci_req_complete(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, rp->status);
}
static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
@@ -1376,21 +1042,19 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
if (!status) {
if (sent->le)
- hdev->host_features[0] |= LMP_HOST_LE;
+ hdev->features[1][0] |= LMP_HOST_LE;
else
- hdev->host_features[0] &= ~LMP_HOST_LE;
+ hdev->features[1][0] &= ~LMP_HOST_LE;
if (sent->simul)
- hdev->host_features[0] |= LMP_HOST_LE_BREDR;
+ hdev->features[1][0] |= LMP_HOST_LE_BREDR;
else
- hdev->host_features[0] &= ~LMP_HOST_LE_BREDR;
+ hdev->features[1][0] &= ~LMP_HOST_LE_BREDR;
}
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_bit(HCI_INIT, &hdev->flags))
mgmt_le_enable_complete(hdev, sent->le, status);
-
- hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
}
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
@@ -1412,7 +1076,6 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status) {
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags))
@@ -1523,7 +1186,7 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status)
if (conn) {
if (conn->state == BT_CONFIG) {
hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
}
@@ -1550,7 +1213,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
if (conn) {
if (conn->state == BT_CONFIG) {
hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
}
@@ -1712,7 +1375,7 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
if (conn) {
if (conn->state == BT_CONFIG) {
hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
}
@@ -1739,7 +1402,7 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status)
if (conn) {
if (conn->state == BT_CONFIG) {
hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
}
@@ -1884,11 +1547,6 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
}
}
-static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-}
-
static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_create_phy_link *cp;
@@ -1930,11 +1588,6 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
amp_write_remote_assoc(hdev, cp->phy_handle);
}
-static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
-{
- BT_DBG("%s status 0x%2.2x", hdev->name, status);
-}
-
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1943,13 +1596,14 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
- hci_req_complete(hdev, HCI_OP_INQUIRY, status);
-
hci_conn_check_pending(hdev);
if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
return;
+ smp_mb__after_clear_bit(); /* wake_up_bit advises about this barrier */
+ wake_up_bit(&hdev->flags, HCI_INQUIRY);
+
if (!test_bit(HCI_MGMT, &hdev->dev_flags))
return;
@@ -2048,7 +1702,6 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
} else
conn->state = BT_CONNECTED;
- hci_conn_hold_device(conn);
hci_conn_add_sysfs(conn);
if (test_bit(HCI_AUTH, &hdev->flags))
@@ -2095,42 +1748,6 @@ unlock:
hci_conn_check_pending(hdev);
}
-void hci_conn_accept(struct hci_conn *conn, int mask)
-{
- struct hci_dev *hdev = conn->hdev;
-
- BT_DBG("conn %p", conn);
-
- conn->state = BT_CONFIG;
-
- if (!lmp_esco_capable(hdev)) {
- struct hci_cp_accept_conn_req cp;
-
- bacpy(&cp.bdaddr, &conn->dst);
-
- if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
- cp.role = 0x00; /* Become master */
- else
- cp.role = 0x01; /* Remain slave */
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
- } else /* lmp_esco_capable(hdev)) */ {
- struct hci_cp_accept_sync_conn_req cp;
-
- bacpy(&cp.bdaddr, &conn->dst);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
-
- cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
- cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
- cp.max_latency = __constant_cpu_to_le16(0xffff);
- cp.content_format = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
-
- hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
- sizeof(cp), &cp);
- }
-}
-
static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_request *ev = (void *) skb->data;
@@ -2202,7 +1819,6 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
} else {
conn->state = BT_CONNECT2;
hci_proto_connect_cfm(conn, 0);
- hci_conn_put(conn);
}
} else {
/* Connection rejected */
@@ -2309,14 +1925,14 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
} else {
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
} else {
hci_auth_cfm(conn, ev->status);
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) {
@@ -2399,8 +2015,8 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
- hci_conn_put(conn);
+ hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+ hci_conn_drop(conn);
goto unlock;
}
@@ -2409,7 +2025,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
} else
hci_encrypt_cfm(conn, ev->status, ev->encrypt);
}
@@ -2456,7 +2072,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
goto unlock;
if (!ev->status)
- memcpy(conn->features, ev->features, 8);
+ memcpy(conn->features[0], ev->features, 8);
if (conn->state != BT_CONFIG)
goto unlock;
@@ -2484,27 +2100,17 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
unlock:
hci_dev_unlock(hdev);
}
-static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
- struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_cmd_complete *ev = (void *) skb->data;
+ u8 status = skb->data[sizeof(*ev)];
__u16 opcode;
skb_pull(skb, sizeof(*ev));
@@ -2588,10 +2194,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_write_voice_setting(hdev, skb);
break;
- case HCI_OP_HOST_BUFFER_SIZE:
- hci_cc_host_buffer_size(hdev, skb);
- break;
-
case HCI_OP_WRITE_SSP_MODE:
hci_cc_write_ssp_mode(hdev, skb);
break;
@@ -2620,46 +2222,42 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_read_bd_addr(hdev, skb);
break;
- case HCI_OP_READ_DATA_BLOCK_SIZE:
- hci_cc_read_data_block_size(hdev, skb);
+ case HCI_OP_READ_PAGE_SCAN_ACTIVITY:
+ hci_cc_read_page_scan_activity(hdev, skb);
break;
- case HCI_OP_WRITE_CA_TIMEOUT:
- hci_cc_write_ca_timeout(hdev, skb);
+ case HCI_OP_WRITE_PAGE_SCAN_ACTIVITY:
+ hci_cc_write_page_scan_activity(hdev, skb);
break;
- case HCI_OP_READ_FLOW_CONTROL_MODE:
- hci_cc_read_flow_control_mode(hdev, skb);
+ case HCI_OP_READ_PAGE_SCAN_TYPE:
+ hci_cc_read_page_scan_type(hdev, skb);
break;
- case HCI_OP_READ_LOCAL_AMP_INFO:
- hci_cc_read_local_amp_info(hdev, skb);
+ case HCI_OP_WRITE_PAGE_SCAN_TYPE:
+ hci_cc_write_page_scan_type(hdev, skb);
break;
- case HCI_OP_READ_LOCAL_AMP_ASSOC:
- hci_cc_read_local_amp_assoc(hdev, skb);
+ case HCI_OP_READ_DATA_BLOCK_SIZE:
+ hci_cc_read_data_block_size(hdev, skb);
break;
- case HCI_OP_DELETE_STORED_LINK_KEY:
- hci_cc_delete_stored_link_key(hdev, skb);
+ case HCI_OP_READ_FLOW_CONTROL_MODE:
+ hci_cc_read_flow_control_mode(hdev, skb);
break;
- case HCI_OP_SET_EVENT_MASK:
- hci_cc_set_event_mask(hdev, skb);
+ case HCI_OP_READ_LOCAL_AMP_INFO:
+ hci_cc_read_local_amp_info(hdev, skb);
break;
- case HCI_OP_WRITE_INQUIRY_MODE:
- hci_cc_write_inquiry_mode(hdev, skb);
+ case HCI_OP_READ_LOCAL_AMP_ASSOC:
+ hci_cc_read_local_amp_assoc(hdev, skb);
break;
case HCI_OP_READ_INQ_RSP_TX_POWER:
hci_cc_read_inq_rsp_tx_power(hdev, skb);
break;
- case HCI_OP_SET_EVENT_FLT:
- hci_cc_set_event_flt(hdev, skb);
- break;
-
case HCI_OP_PIN_CODE_REPLY:
hci_cc_pin_code_reply(hdev, skb);
break;
@@ -2684,10 +2282,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_adv_tx_power(hdev, skb);
break;
- case HCI_OP_LE_SET_EVENT_MASK:
- hci_cc_le_set_event_mask(hdev, skb);
- break;
-
case HCI_OP_USER_CONFIRM_REPLY:
hci_cc_user_confirm_reply(hdev, skb);
break;
@@ -2720,14 +2314,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_white_list_size(hdev, skb);
break;
- case HCI_OP_LE_LTK_REPLY:
- hci_cc_le_ltk_reply(hdev, skb);
- break;
-
- case HCI_OP_LE_LTK_NEG_REPLY:
- hci_cc_le_ltk_neg_reply(hdev, skb);
- break;
-
case HCI_OP_LE_READ_SUPPORTED_STATES:
hci_cc_le_read_supported_states(hdev, skb);
break;
@@ -2745,9 +2331,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
break;
}
- if (ev->opcode != HCI_OP_NOP)
+ if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
+ hci_req_cmd_complete(hdev, opcode, status);
+
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -2817,10 +2405,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status);
break;
- case HCI_OP_LE_START_ENC:
- hci_cs_le_start_enc(hdev, ev->status);
- break;
-
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
break;
@@ -2829,18 +2413,18 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_accept_phylink(hdev, ev->status);
break;
- case HCI_OP_CREATE_LOGICAL_LINK:
- hci_cs_create_logical_link(hdev, ev->status);
- break;
-
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break;
}
- if (ev->opcode != HCI_OP_NOP)
+ if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer);
+ if (ev->status ||
+ (hdev->sent_cmd && !bt_cb(hdev->sent_cmd)->req.event))
+ hci_req_cmd_complete(hdev, opcode, ev->status);
+
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
@@ -3056,7 +2640,7 @@ static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (conn->state == BT_CONNECTED) {
hci_conn_hold(conn);
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags))
@@ -3159,7 +2743,7 @@ static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (ev->key_type != HCI_LK_CHANGED_COMBINATION)
conn->key_type = ev->key_type;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags))
@@ -3300,6 +2884,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
if (!conn)
goto unlock;
+ if (ev->page < HCI_MAX_PAGES)
+ memcpy(conn->features[ev->page], ev->features, 8);
+
if (!ev->status && ev->page == 0x01) {
struct inquiry_entry *ie;
@@ -3307,8 +2894,19 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
if (ie)
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
- if (ev->features[0] & LMP_HOST_SSP)
+ if (ev->features[0] & LMP_HOST_SSP) {
set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
+ } else {
+ /* It is mandatory by the Bluetooth specification that
+ * Extended Inquiry Results are only used when Secure
+ * Simple Pairing is enabled, but some devices violate
+ * this.
+ *
+ * To make these devices work, the internal SSP
+ * enabled flag needs to be cleared if the remote host
+ * features do not indicate SSP support */
+ clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
+ }
}
if (conn->state != BT_CONFIG)
@@ -3328,7 +2926,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
unlock:
@@ -3362,7 +2960,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
- hci_conn_hold_device(conn);
hci_conn_add_sysfs(conn);
break;
@@ -3391,18 +2988,6 @@ unlock:
hci_dev_unlock(hdev);
}
-static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- BT_DBG("%s", hdev->name);
-}
-
-static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
-{
- struct hci_ev_sniff_subrate *ev = (void *) skb->data;
-
- BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
-}
-
static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -3472,8 +3057,8 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
- hci_conn_put(conn);
+ hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
+ hci_conn_drop(conn);
goto unlock;
}
@@ -3482,13 +3067,13 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
conn->state = BT_CONNECTED;
hci_proto_connect_cfm(conn, ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
} else {
hci_auth_cfm(conn, ev->status);
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
}
unlock:
@@ -3749,7 +3334,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
ev->status);
- hci_conn_put(conn);
+ hci_conn_drop(conn);
unlock:
hci_dev_unlock(hdev);
@@ -3760,11 +3345,16 @@ static void hci_remote_host_features_evt(struct hci_dev *hdev,
{
struct hci_ev_remote_host_features *ev = (void *) skb->data;
struct inquiry_entry *ie;
+ struct hci_conn *conn;
BT_DBG("%s", hdev->name);
hci_dev_lock(hdev);
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+ if (conn)
+ memcpy(conn->features[1], ev->features, 8);
+
ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
if (ie)
ie->data.ssp_mode = (ev->features[0] & LMP_HOST_SSP);
@@ -3837,9 +3427,8 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
hci_conn_hold(hcon);
hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
- hci_conn_put(hcon);
+ hci_conn_drop(hcon);
- hci_conn_hold_device(hcon);
hci_conn_add_sysfs(hcon);
amp_physical_cfm(bredr_hcon, hcon);
@@ -3973,7 +3562,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
- hci_conn_hold_device(conn);
hci_conn_add_sysfs(conn);
hci_proto_connect_cfm(conn, ev->status);
@@ -4087,8 +3675,27 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
struct hci_event_hdr *hdr = (void *) skb->data;
__u8 event = hdr->evt;
+ hci_dev_lock(hdev);
+
+ /* Received events are (currently) only needed when a request is
+ * ongoing so avoid unnecessary memory allocation.
+ */
+ if (hdev->req_status == HCI_REQ_PEND) {
+ kfree_skb(hdev->recv_evt);
+ hdev->recv_evt = skb_clone(skb, GFP_KERNEL);
+ }
+
+ hci_dev_unlock(hdev);
+
skb_pull(skb, HCI_EVENT_HDR_SIZE);
+ if (hdev->sent_cmd && bt_cb(hdev->sent_cmd)->req.event == event) {
+ struct hci_command_hdr *hdr = (void *) hdev->sent_cmd->data;
+ u16 opcode = __le16_to_cpu(hdr->opcode);
+
+ hci_req_cmd_complete(hdev, opcode, 0);
+ }
+
switch (event) {
case HCI_EV_INQUIRY_COMPLETE:
hci_inquiry_complete_evt(hdev, skb);
@@ -4130,14 +3737,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_features_evt(hdev, skb);
break;
- case HCI_EV_REMOTE_VERSION:
- hci_remote_version_evt(hdev, skb);
- break;
-
- case HCI_EV_QOS_SETUP_COMPLETE:
- hci_qos_setup_complete_evt(hdev, skb);
- break;
-
case HCI_EV_CMD_COMPLETE:
hci_cmd_complete_evt(hdev, skb);
break;
@@ -4194,14 +3793,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_sync_conn_complete_evt(hdev, skb);
break;
- case HCI_EV_SYNC_CONN_CHANGED:
- hci_sync_conn_changed_evt(hdev, skb);
- break;
-
- case HCI_EV_SNIFF_SUBRATE:
- hci_sniff_subrate_evt(hdev, skb);
- break;
-
case HCI_EV_EXTENDED_INQUIRY_RESULT:
hci_extended_inquiry_result_evt(hdev, skb);
break;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 6ad23951c133..9bd7d959e384 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -854,6 +854,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work);
} else {
+ /* Stand-alone HCI commands must be flaged as
+ * single-command requests.
+ */
+ bt_cb(skb)->req.start = true;
+
skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
@@ -1121,8 +1126,6 @@ error:
void hci_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "hci");
- if (bt_sock_unregister(BTPROTO_HCI) < 0)
- BT_ERR("HCI socket unregistration failed");
-
+ bt_sock_unregister(BTPROTO_HCI);
proto_unregister(&hci_sk_proto);
}
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 23b4e242a31a..7ad6ecf36f20 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -48,10 +48,10 @@ static ssize_t show_link_features(struct device *dev,
struct hci_conn *conn = to_hci_conn(dev);
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- conn->features[0], conn->features[1],
- conn->features[2], conn->features[3],
- conn->features[4], conn->features[5],
- conn->features[6], conn->features[7]);
+ conn->features[0][0], conn->features[0][1],
+ conn->features[0][2], conn->features[0][3],
+ conn->features[0][4], conn->features[0][5],
+ conn->features[0][6], conn->features[0][7]);
}
#define LINK_ATTR(_name, _mode, _show, _store) \
@@ -146,7 +146,6 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
}
device_del(&conn->dev);
- put_device(&conn->dev);
hci_dev_put(hdev);
}
@@ -234,10 +233,10 @@ static ssize_t show_features(struct device *dev,
struct hci_dev *hdev = to_hci_dev(dev);
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- hdev->features[0], hdev->features[1],
- hdev->features[2], hdev->features[3],
- hdev->features[4], hdev->features[5],
- hdev->features[6], hdev->features[7]);
+ hdev->features[0][0], hdev->features[0][1],
+ hdev->features[0][2], hdev->features[0][3],
+ hdev->features[0][4], hdev->features[0][5],
+ hdev->features[0][6], hdev->features[0][7]);
}
static ssize_t show_manufacturer(struct device *dev,
@@ -590,10 +589,8 @@ int __init bt_sysfs_init(void)
bt_debugfs = debugfs_create_dir("bluetooth", NULL);
bt_class = class_create(THIS_MODULE, "bluetooth");
- if (IS_ERR(bt_class))
- return PTR_ERR(bt_class);
- return 0;
+ return PTR_RET(bt_class);
}
void bt_sysfs_cleanup(void)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index a7352ff3fd1e..940f5acb6694 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1,6 +1,7 @@
/*
HIDP implementation for Linux Bluetooth stack (BlueZ).
Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
+ Copyright (C) 2013 David Herrmann <dh.herrmann@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
@@ -20,6 +21,7 @@
SOFTWARE IS DISCLAIMED.
*/
+#include <linux/kref.h>
#include <linux/module.h>
#include <linux/file.h>
#include <linux/kthread.h>
@@ -59,39 +61,20 @@ static unsigned char hidp_keycode[256] = {
static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
-static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
-{
- struct hidp_session *session;
-
- BT_DBG("");
+static int hidp_session_probe(struct l2cap_conn *conn,
+ struct l2cap_user *user);
+static void hidp_session_remove(struct l2cap_conn *conn,
+ struct l2cap_user *user);
+static int hidp_session_thread(void *arg);
+static void hidp_session_terminate(struct hidp_session *s);
- list_for_each_entry(session, &hidp_session_list, list) {
- if (!bacmp(bdaddr, &session->bdaddr))
- return session;
- }
-
- return NULL;
-}
-
-static void __hidp_link_session(struct hidp_session *session)
-{
- list_add(&session->list, &hidp_session_list);
-}
-
-static void __hidp_unlink_session(struct hidp_session *session)
-{
- hci_conn_put_device(session->conn);
-
- list_del(&session->list);
-}
-
-static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
+static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
{
memset(ci, 0, sizeof(*ci));
bacpy(&ci->bdaddr, &session->bdaddr);
ci->flags = session->flags;
- ci->state = session->state;
+ ci->state = BT_CONNECTED;
ci->vendor = 0x0000;
ci->product = 0x0000;
@@ -115,58 +98,80 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin
}
}
-static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
- unsigned int type, unsigned int code, int value)
+/* assemble skb, queue message on @transmit and wake up the session thread */
+static int hidp_send_message(struct hidp_session *session, struct socket *sock,
+ struct sk_buff_head *transmit, unsigned char hdr,
+ const unsigned char *data, int size)
{
- unsigned char newleds;
struct sk_buff *skb;
+ struct sock *sk = sock->sk;
- BT_DBG("session %p type %d code %d value %d", session, type, code, value);
-
- if (type != EV_LED)
- return -1;
-
- newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
- (!!test_bit(LED_COMPOSE, dev->led) << 3) |
- (!!test_bit(LED_SCROLLL, dev->led) << 2) |
- (!!test_bit(LED_CAPSL, dev->led) << 1) |
- (!!test_bit(LED_NUML, dev->led));
-
- if (session->leds == newleds)
- return 0;
+ BT_DBG("session %p data %p size %d", session, data, size);
- session->leds = newleds;
+ if (atomic_read(&session->terminate))
+ return -EIO;
- skb = alloc_skb(3, GFP_ATOMIC);
+ skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}
- *skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
- *skb_put(skb, 1) = 0x01;
- *skb_put(skb, 1) = newleds;
-
- skb_queue_tail(&session->intr_transmit, skb);
+ *skb_put(skb, 1) = hdr;
+ if (data && size > 0)
+ memcpy(skb_put(skb, size), data, size);
- hidp_schedule(session);
+ skb_queue_tail(transmit, skb);
+ wake_up_interruptible(sk_sleep(sk));
return 0;
}
-static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int hidp_send_ctrl_message(struct hidp_session *session,
+ unsigned char hdr, const unsigned char *data,
+ int size)
{
- struct hid_device *hid = input_get_drvdata(dev);
- struct hidp_session *session = hid->driver_data;
+ return hidp_send_message(session, session->ctrl_sock,
+ &session->ctrl_transmit, hdr, data, size);
+}
- return hidp_queue_event(session, dev, type, code, value);
+static int hidp_send_intr_message(struct hidp_session *session,
+ unsigned char hdr, const unsigned char *data,
+ int size)
+{
+ return hidp_send_message(session, session->intr_sock,
+ &session->intr_transmit, hdr, data, size);
}
-static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int hidp_input_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
{
struct hidp_session *session = input_get_drvdata(dev);
+ unsigned char newleds;
+ unsigned char hdr, data[2];
+
+ BT_DBG("session %p type %d code %d value %d",
+ session, type, code, value);
+
+ if (type != EV_LED)
+ return -1;
+
+ newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
+ (!!test_bit(LED_COMPOSE, dev->led) << 3) |
+ (!!test_bit(LED_SCROLLL, dev->led) << 2) |
+ (!!test_bit(LED_CAPSL, dev->led) << 1) |
+ (!!test_bit(LED_NUML, dev->led));
- return hidp_queue_event(session, dev, type, code, value);
+ if (session->leds == newleds)
+ return 0;
+
+ session->leds = newleds;
+
+ hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
+ data[0] = 0x01;
+ data[1] = newleds;
+
+ return hidp_send_intr_message(session, hdr, data, 2);
}
static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
@@ -224,71 +229,9 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
input_sync(dev);
}
-static int __hidp_send_ctrl_message(struct hidp_session *session,
- unsigned char hdr, unsigned char *data,
- int size)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p data %p size %d", session, data, size);
-
- if (atomic_read(&session->terminate))
- return -EIO;
-
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
- }
-
- *skb_put(skb, 1) = hdr;
- if (data && size > 0)
- memcpy(skb_put(skb, size), data, size);
-
- skb_queue_tail(&session->ctrl_transmit, skb);
-
- return 0;
-}
-
-static int hidp_send_ctrl_message(struct hidp_session *session,
- unsigned char hdr, unsigned char *data, int size)
-{
- int err;
-
- err = __hidp_send_ctrl_message(session, hdr, data, size);
-
- hidp_schedule(session);
-
- return err;
-}
-
-static int hidp_queue_report(struct hidp_session *session,
- unsigned char *data, int size)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
-
- skb = alloc_skb(size + 1, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
- }
-
- *skb_put(skb, 1) = 0xa2;
- if (size > 0)
- memcpy(skb_put(skb, size), data, size);
-
- skb_queue_tail(&session->intr_transmit, skb);
-
- hidp_schedule(session);
-
- return 0;
-}
-
static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
{
- unsigned char buf[32];
+ unsigned char buf[32], hdr;
int rsize;
rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
@@ -296,8 +239,9 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
return -EIO;
hid_output_report(report, buf);
+ hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
- return hidp_queue_report(session, buf, rsize);
+ return hidp_send_intr_message(session, hdr, buf, rsize);
}
static int hidp_get_raw_report(struct hid_device *hid,
@@ -311,6 +255,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
int numbered_reports = hid->report_enum[report_type].numbered;
int ret;
+ if (atomic_read(&session->terminate))
+ return -EIO;
+
switch (report_type) {
case HID_FEATURE_REPORT:
report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
@@ -333,17 +280,19 @@ static int hidp_get_raw_report(struct hid_device *hid,
session->waiting_report_number = numbered_reports ? report_number : -1;
set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
data[0] = report_number;
- ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
+ ret = hidp_send_ctrl_message(session, report_type, data, 1);
if (ret)
goto err;
/* Wait for the return of the report. The returned report
gets put in session->report_return. */
- while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
+ while (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags) &&
+ !atomic_read(&session->terminate)) {
int res;
res = wait_event_interruptible_timeout(session->report_queue,
- !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags),
+ !test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)
+ || atomic_read(&session->terminate),
5*HZ);
if (res == 0) {
/* timeout */
@@ -386,14 +335,11 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
struct hidp_session *session = hid->driver_data;
int ret;
- switch (report_type) {
- case HID_FEATURE_REPORT:
- report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
- break;
- case HID_OUTPUT_REPORT:
- report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
- break;
- default:
+ if (report_type == HID_OUTPUT_REPORT) {
+ report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
+ return hidp_send_intr_message(session, report_type,
+ data, count);
+ } else if (report_type != HID_FEATURE_REPORT) {
return -EINVAL;
}
@@ -402,17 +348,19 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
/* Set up our wait, and send the report request to the device. */
set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
- ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
- count);
+ report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
+ ret = hidp_send_ctrl_message(session, report_type, data, count);
if (ret)
goto err;
/* Wait for the ACK from the device. */
- while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
+ while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags) &&
+ !atomic_read(&session->terminate)) {
int res;
res = wait_event_interruptible_timeout(session->report_queue,
- !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags),
+ !test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)
+ || atomic_read(&session->terminate),
10*HZ);
if (res == 0) {
/* timeout */
@@ -443,8 +391,7 @@ static void hidp_idle_timeout(unsigned long arg)
{
struct hidp_session *session = (struct hidp_session *) arg;
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
+ hidp_session_terminate(session);
}
static void hidp_set_timer(struct hidp_session *session)
@@ -487,12 +434,12 @@ static void hidp_process_handshake(struct hidp_session *session,
case HIDP_HSHK_ERR_FATAL:
/* Device requests a reboot, as this is the only way this error
* can be recovered. */
- __hidp_send_ctrl_message(session,
+ hidp_send_ctrl_message(session,
HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
break;
default:
- __hidp_send_ctrl_message(session,
+ hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
break;
}
@@ -512,8 +459,7 @@ static void hidp_process_hid_control(struct hidp_session *session,
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
- atomic_inc(&session->terminate);
- wake_up_process(current);
+ hidp_session_terminate(session);
}
}
@@ -541,7 +487,7 @@ static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
break;
default:
- __hidp_send_ctrl_message(session,
+ hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
}
@@ -588,7 +534,7 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
break;
default:
- __hidp_send_ctrl_message(session,
+ hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
break;
}
@@ -639,32 +585,24 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
-static void hidp_process_intr_transmit(struct hidp_session *session)
+/* dequeue message from @transmit and send via @sock */
+static void hidp_process_transmit(struct hidp_session *session,
+ struct sk_buff_head *transmit,
+ struct socket *sock)
{
struct sk_buff *skb;
+ int ret;
BT_DBG("session %p", session);
- while ((skb = skb_dequeue(&session->intr_transmit))) {
- if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
- skb_queue_head(&session->intr_transmit, skb);
+ while ((skb = skb_dequeue(transmit))) {
+ ret = hidp_send_frame(sock, skb->data, skb->len);
+ if (ret == -EAGAIN) {
+ skb_queue_head(transmit, skb);
break;
- }
-
- hidp_set_timer(session);
- kfree_skb(skb);
- }
-}
-
-static void hidp_process_ctrl_transmit(struct hidp_session *session)
-{
- struct sk_buff *skb;
-
- BT_DBG("session %p", session);
-
- while ((skb = skb_dequeue(&session->ctrl_transmit))) {
- if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
- skb_queue_head(&session->ctrl_transmit, skb);
+ } else if (ret < 0) {
+ hidp_session_terminate(session);
+ kfree_skb(skb);
break;
}
@@ -673,121 +611,6 @@ static void hidp_process_ctrl_transmit(struct hidp_session *session)
}
}
-static int hidp_session(void *arg)
-{
- struct hidp_session *session = arg;
- struct sock *ctrl_sk = session->ctrl_sock->sk;
- struct sock *intr_sk = session->intr_sock->sk;
- struct sk_buff *skb;
- wait_queue_t ctrl_wait, intr_wait;
-
- BT_DBG("session %p", session);
-
- __module_get(THIS_MODULE);
- set_user_nice(current, -15);
-
- init_waitqueue_entry(&ctrl_wait, current);
- init_waitqueue_entry(&intr_wait, current);
- add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
- add_wait_queue(sk_sleep(intr_sk), &intr_wait);
- session->waiting_for_startup = 0;
- wake_up_interruptible(&session->startup_queue);
- set_current_state(TASK_INTERRUPTIBLE);
- while (!atomic_read(&session->terminate)) {
- if (ctrl_sk->sk_state != BT_CONNECTED ||
- intr_sk->sk_state != BT_CONNECTED)
- break;
-
- while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- hidp_recv_intr_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- hidp_process_intr_transmit(session);
-
- while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
- skb_orphan(skb);
- if (!skb_linearize(skb))
- hidp_recv_ctrl_frame(session, skb);
- else
- kfree_skb(skb);
- }
-
- hidp_process_ctrl_transmit(session);
-
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
- remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
-
- clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
- clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
- wake_up_interruptible(&session->report_queue);
-
- down_write(&hidp_session_sem);
-
- hidp_del_timer(session);
-
- if (session->input) {
- input_unregister_device(session->input);
- session->input = NULL;
- }
-
- if (session->hid) {
- hid_destroy_device(session->hid);
- session->hid = NULL;
- }
-
- /* Wakeup user-space polling for socket errors */
- session->intr_sock->sk->sk_err = EUNATCH;
- session->ctrl_sock->sk->sk_err = EUNATCH;
-
- hidp_schedule(session);
-
- fput(session->intr_sock->file);
-
- wait_event_timeout(*(sk_sleep(ctrl_sk)),
- (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
-
- fput(session->ctrl_sock->file);
-
- __hidp_unlink_session(session);
-
- up_write(&hidp_session_sem);
-
- kfree(session->rd_data);
- kfree(session);
- module_put_and_exit(0);
- return 0;
-}
-
-static struct hci_conn *hidp_get_connection(struct hidp_session *session)
-{
- bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
- bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
- struct hci_conn *conn;
- struct hci_dev *hdev;
-
- hdev = hci_get_route(dst, src);
- if (!hdev)
- return NULL;
-
- hci_dev_lock(hdev);
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
- if (conn)
- hci_conn_hold_device(conn);
- hci_dev_unlock(hdev);
-
- hci_dev_put(hdev);
-
- return conn;
-}
-
static int hidp_setup_input(struct hidp_session *session,
struct hidp_connadd_req *req)
{
@@ -835,7 +658,7 @@ static int hidp_setup_input(struct hidp_session *session,
input->relbit[0] |= BIT_MASK(REL_WHEEL);
}
- input->dev.parent = &session->conn->dev;
+ input->dev.parent = &session->conn->hcon->dev;
input->event = hidp_input_event;
@@ -894,7 +717,6 @@ static struct hid_ll_driver hidp_hid_driver = {
.stop = hidp_stop,
.open = hidp_open,
.close = hidp_close,
- .hidinput_input_event = hidp_hidinput_event,
};
/* This function sets up the hid device. It does not add it
@@ -939,7 +761,7 @@ static int hidp_setup_hid(struct hidp_session *session,
snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
&bt_sk(session->ctrl_sock->sk)->dst);
- hid->dev.parent = &session->conn->dev;
+ hid->dev.parent = &session->conn->hcon->dev;
hid->ll_driver = &hidp_hid_driver;
hid->hid_get_raw_report = hidp_get_raw_report;
@@ -961,80 +783,217 @@ fault:
return err;
}
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
+/* initialize session devices */
+static int hidp_session_dev_init(struct hidp_session *session,
+ struct hidp_connadd_req *req)
{
- struct hidp_session *session, *s;
- int vendor, product;
- int err;
+ int ret;
- BT_DBG("");
+ if (req->rd_size > 0) {
+ ret = hidp_setup_hid(session, req);
+ if (ret && ret != -ENODEV)
+ return ret;
+ }
- if (bacmp(&bt_sk(ctrl_sock->sk)->src, &bt_sk(intr_sock->sk)->src) ||
- bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
- return -ENOTUNIQ;
+ if (!session->hid) {
+ ret = hidp_setup_input(session, req);
+ if (ret < 0)
+ return ret;
+ }
- BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
+ return 0;
+}
- down_write(&hidp_session_sem);
+/* destroy session devices */
+static void hidp_session_dev_destroy(struct hidp_session *session)
+{
+ if (session->hid)
+ put_device(&session->hid->dev);
+ else if (session->input)
+ input_put_device(session->input);
- s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
- if (s && s->state == BT_CONNECTED) {
- up_write(&hidp_session_sem);
- return -EEXIST;
- }
+ kfree(session->rd_data);
+ session->rd_data = NULL;
+}
- session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
- if (!session) {
- up_write(&hidp_session_sem);
- return -ENOMEM;
- }
+/* add HID/input devices to their underlying bus systems */
+static int hidp_session_dev_add(struct hidp_session *session)
+{
+ int ret;
- bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
+ /* Both HID and input systems drop a ref-count when unregistering the
+ * device but they don't take a ref-count when registering them. Work
+ * around this by explicitly taking a refcount during registration
+ * which is dropped automatically by unregistering the devices. */
- session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu,
- l2cap_pi(ctrl_sock->sk)->chan->imtu);
- session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu,
- l2cap_pi(intr_sock->sk)->chan->imtu);
+ if (session->hid) {
+ ret = hid_add_device(session->hid);
+ if (ret)
+ return ret;
+ get_device(&session->hid->dev);
+ } else if (session->input) {
+ ret = input_register_device(session->input);
+ if (ret)
+ return ret;
+ input_get_device(session->input);
+ }
- BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu);
+ return 0;
+}
- session->ctrl_sock = ctrl_sock;
- session->intr_sock = intr_sock;
- session->state = BT_CONNECTED;
+/* remove HID/input devices from their bus systems */
+static void hidp_session_dev_del(struct hidp_session *session)
+{
+ if (session->hid)
+ hid_destroy_device(session->hid);
+ else if (session->input)
+ input_unregister_device(session->input);
+}
- session->conn = hidp_get_connection(session);
- if (!session->conn) {
- err = -ENOTCONN;
- goto failed;
- }
+/*
+ * Create new session object
+ * Allocate session object, initialize static fields, copy input data into the
+ * object and take a reference to all sub-objects.
+ * This returns 0 on success and puts a pointer to the new session object in
+ * \out. Otherwise, an error code is returned.
+ * The new session object has an initial ref-count of 1.
+ */
+static int hidp_session_new(struct hidp_session **out, const bdaddr_t *bdaddr,
+ struct socket *ctrl_sock,
+ struct socket *intr_sock,
+ struct hidp_connadd_req *req,
+ struct l2cap_conn *conn)
+{
+ struct hidp_session *session;
+ int ret;
+ struct bt_sock *ctrl, *intr;
+
+ ctrl = bt_sk(ctrl_sock->sk);
+ intr = bt_sk(intr_sock->sk);
- setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (!session)
+ return -ENOMEM;
+ /* object and runtime management */
+ kref_init(&session->ref);
+ atomic_set(&session->state, HIDP_SESSION_IDLING);
+ init_waitqueue_head(&session->state_queue);
+ session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
+
+ /* connection management */
+ bacpy(&session->bdaddr, bdaddr);
+ session->conn = conn;
+ session->user.probe = hidp_session_probe;
+ session->user.remove = hidp_session_remove;
+ session->ctrl_sock = ctrl_sock;
+ session->intr_sock = intr_sock;
skb_queue_head_init(&session->ctrl_transmit);
skb_queue_head_init(&session->intr_transmit);
+ session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl)->chan->omtu,
+ l2cap_pi(ctrl)->chan->imtu);
+ session->intr_mtu = min_t(uint, l2cap_pi(intr)->chan->omtu,
+ l2cap_pi(intr)->chan->imtu);
+ session->idle_to = req->idle_to;
+ /* device management */
+ setup_timer(&session->timer, hidp_idle_timeout,
+ (unsigned long)session);
+
+ /* session data */
mutex_init(&session->report_mutex);
init_waitqueue_head(&session->report_queue);
- init_waitqueue_head(&session->startup_queue);
- session->waiting_for_startup = 1;
- session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
- session->idle_to = req->idle_to;
- __hidp_link_session(session);
+ ret = hidp_session_dev_init(session, req);
+ if (ret)
+ goto err_free;
- if (req->rd_size > 0) {
- err = hidp_setup_hid(session, req);
- if (err && err != -ENODEV)
- goto purge;
- }
+ l2cap_conn_get(session->conn);
+ get_file(session->intr_sock->file);
+ get_file(session->ctrl_sock->file);
+ *out = session;
+ return 0;
- if (!session->hid) {
- err = hidp_setup_input(session, req);
- if (err < 0)
- goto purge;
+err_free:
+ kfree(session);
+ return ret;
+}
+
+/* increase ref-count of the given session by one */
+static void hidp_session_get(struct hidp_session *session)
+{
+ kref_get(&session->ref);
+}
+
+/* release callback */
+static void session_free(struct kref *ref)
+{
+ struct hidp_session *session = container_of(ref, struct hidp_session,
+ ref);
+
+ hidp_session_dev_destroy(session);
+ skb_queue_purge(&session->ctrl_transmit);
+ skb_queue_purge(&session->intr_transmit);
+ fput(session->intr_sock->file);
+ fput(session->ctrl_sock->file);
+ l2cap_conn_put(session->conn);
+ kfree(session);
+}
+
+/* decrease ref-count of the given session by one */
+static void hidp_session_put(struct hidp_session *session)
+{
+ kref_put(&session->ref, session_free);
+}
+
+/*
+ * Search the list of active sessions for a session with target address
+ * \bdaddr. You must hold at least a read-lock on \hidp_session_sem. As long as
+ * you do not release this lock, the session objects cannot vanish and you can
+ * safely take a reference to the session yourself.
+ */
+static struct hidp_session *__hidp_session_find(const bdaddr_t *bdaddr)
+{
+ struct hidp_session *session;
+
+ list_for_each_entry(session, &hidp_session_list, list) {
+ if (!bacmp(bdaddr, &session->bdaddr))
+ return session;
}
- hidp_set_timer(session);
+ return NULL;
+}
+
+/*
+ * Same as __hidp_session_find() but no locks must be held. This also takes a
+ * reference of the returned session (if non-NULL) so you must drop this
+ * reference if you no longer use the object.
+ */
+static struct hidp_session *hidp_session_find(const bdaddr_t *bdaddr)
+{
+ struct hidp_session *session;
+
+ down_read(&hidp_session_sem);
+
+ session = __hidp_session_find(bdaddr);
+ if (session)
+ hidp_session_get(session);
+
+ up_read(&hidp_session_sem);
+
+ return session;
+}
+
+/*
+ * Start session synchronously
+ * This starts a session thread and waits until initialization
+ * is done or returns an error if it couldn't be started.
+ * If this returns 0 the session thread is up and running. You must call
+ * hipd_session_stop_sync() before deleting any runtime resources.
+ */
+static int hidp_session_start_sync(struct hidp_session *session)
+{
+ unsigned int vendor, product;
if (session->hid) {
vendor = session->hid->vendor;
@@ -1047,98 +1006,320 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
product = 0x0000;
}
- session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x",
- vendor, product);
- if (IS_ERR(session->task)) {
- err = PTR_ERR(session->task);
- goto unlink;
- }
+ session->task = kthread_run(hidp_session_thread, session,
+ "khidpd_%04x%04x", vendor, product);
+ if (IS_ERR(session->task))
+ return PTR_ERR(session->task);
- while (session->waiting_for_startup) {
- wait_event_interruptible(session->startup_queue,
- !session->waiting_for_startup);
- }
+ while (atomic_read(&session->state) <= HIDP_SESSION_IDLING)
+ wait_event(session->state_queue,
+ atomic_read(&session->state) > HIDP_SESSION_IDLING);
- if (session->hid)
- err = hid_add_device(session->hid);
- else
- err = input_register_device(session->input);
+ return 0;
+}
- if (err < 0) {
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- up_write(&hidp_session_sem);
- return err;
- }
+/*
+ * Terminate session thread
+ * Wake up session thread and notify it to stop. This is asynchronous and
+ * returns immediately. Call this whenever a runtime error occurs and you want
+ * the session to stop.
+ * Note: wake_up_process() performs any necessary memory-barriers for us.
+ */
+static void hidp_session_terminate(struct hidp_session *session)
+{
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
+}
- if (session->input) {
- hidp_send_ctrl_message(session,
- HIDP_TRANS_SET_PROTOCOL | HIDP_PROTO_BOOT, NULL, 0);
- session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+/*
+ * Probe HIDP session
+ * This is called from the l2cap_conn core when our l2cap_user object is bound
+ * to the hci-connection. We get the session via the \user object and can now
+ * start the session thread, register the HID/input devices and link it into
+ * the global session list.
+ * The global session-list owns its own reference to the session object so you
+ * can drop your own reference after registering the l2cap_user object.
+ */
+static int hidp_session_probe(struct l2cap_conn *conn,
+ struct l2cap_user *user)
+{
+ struct hidp_session *session = container_of(user,
+ struct hidp_session,
+ user);
+ struct hidp_session *s;
+ int ret;
- session->leds = 0xff;
- hidp_input_event(session->input, EV_LED, 0, 0);
+ down_write(&hidp_session_sem);
+
+ /* check that no other session for this device exists */
+ s = __hidp_session_find(&session->bdaddr);
+ if (s) {
+ ret = -EEXIST;
+ goto out_unlock;
}
+ ret = hidp_session_start_sync(session);
+ if (ret)
+ goto out_unlock;
+
+ ret = hidp_session_dev_add(session);
+ if (ret)
+ goto out_stop;
+
+ hidp_session_get(session);
+ list_add(&session->list, &hidp_session_list);
+ ret = 0;
+ goto out_unlock;
+
+out_stop:
+ hidp_session_terminate(session);
+out_unlock:
up_write(&hidp_session_sem);
- return 0;
+ return ret;
+}
-unlink:
+/*
+ * Remove HIDP session
+ * Called from the l2cap_conn core when either we explicitly unregistered
+ * the l2cap_user object or if the underlying connection is shut down.
+ * We signal the hidp-session thread to shut down, unregister the HID/input
+ * devices and unlink the session from the global list.
+ * This drops the reference to the session that is owned by the global
+ * session-list.
+ * Note: We _must_ not synchronosly wait for the session-thread to shut down.
+ * This is, because the session-thread might be waiting for an HCI lock that is
+ * held while we are called. Therefore, we only unregister the devices and
+ * notify the session-thread to terminate. The thread itself owns a reference
+ * to the session object so it can safely shut down.
+ */
+static void hidp_session_remove(struct l2cap_conn *conn,
+ struct l2cap_user *user)
+{
+ struct hidp_session *session = container_of(user,
+ struct hidp_session,
+ user);
+
+ down_write(&hidp_session_sem);
+
+ hidp_session_terminate(session);
+ hidp_session_dev_del(session);
+ list_del(&session->list);
+
+ up_write(&hidp_session_sem);
+
+ hidp_session_put(session);
+}
+
+/*
+ * Session Worker
+ * This performs the actual main-loop of the HIDP worker. We first check
+ * whether the underlying connection is still alive, then parse all pending
+ * messages and finally send all outstanding messages.
+ */
+static void hidp_session_run(struct hidp_session *session)
+{
+ struct sock *ctrl_sk = session->ctrl_sock->sk;
+ struct sock *intr_sk = session->intr_sock->sk;
+ struct sk_buff *skb;
+
+ for (;;) {
+ /*
+ * This thread can be woken up two ways:
+ * - You call hidp_session_terminate() which sets the
+ * session->terminate flag and wakes this thread up.
+ * - Via modifying the socket state of ctrl/intr_sock. This
+ * thread is woken up by ->sk_state_changed().
+ *
+ * Note: set_current_state() performs any necessary
+ * memory-barriers for us.
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (atomic_read(&session->terminate))
+ break;
+
+ if (ctrl_sk->sk_state != BT_CONNECTED ||
+ intr_sk->sk_state != BT_CONNECTED)
+ break;
+
+ /* parse incoming intr-skbs */
+ while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
+ skb_orphan(skb);
+ if (!skb_linearize(skb))
+ hidp_recv_intr_frame(session, skb);
+ else
+ kfree_skb(skb);
+ }
+
+ /* send pending intr-skbs */
+ hidp_process_transmit(session, &session->intr_transmit,
+ session->intr_sock);
+
+ /* parse incoming ctrl-skbs */
+ while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
+ skb_orphan(skb);
+ if (!skb_linearize(skb))
+ hidp_recv_ctrl_frame(session, skb);
+ else
+ kfree_skb(skb);
+ }
+
+ /* send pending ctrl-skbs */
+ hidp_process_transmit(session, &session->ctrl_transmit,
+ session->ctrl_sock);
+
+ schedule();
+ }
+
+ atomic_inc(&session->terminate);
+ set_current_state(TASK_RUNNING);
+}
+
+/*
+ * HIDP session thread
+ * This thread runs the I/O for a single HIDP session. Startup is synchronous
+ * which allows us to take references to ourself here instead of doing that in
+ * the caller.
+ * When we are ready to run we notify the caller and call hidp_session_run().
+ */
+static int hidp_session_thread(void *arg)
+{
+ struct hidp_session *session = arg;
+ wait_queue_t ctrl_wait, intr_wait;
+
+ BT_DBG("session %p", session);
+
+ /* initialize runtime environment */
+ hidp_session_get(session);
+ __module_get(THIS_MODULE);
+ set_user_nice(current, -15);
+ hidp_set_timer(session);
+
+ init_waitqueue_entry(&ctrl_wait, current);
+ init_waitqueue_entry(&intr_wait, current);
+ add_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait);
+ add_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
+ /* This memory barrier is paired with wq_has_sleeper(). See
+ * sock_poll_wait() for more information why this is needed. */
+ smp_mb();
+
+ /* notify synchronous startup that we're ready */
+ atomic_inc(&session->state);
+ wake_up(&session->state_queue);
+
+ /* run session */
+ hidp_session_run(session);
+
+ /* cleanup runtime environment */
+ remove_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
+ remove_wait_queue(sk_sleep(session->intr_sock->sk), &ctrl_wait);
+ wake_up_interruptible(&session->report_queue);
hidp_del_timer(session);
- if (session->input) {
- input_unregister_device(session->input);
- session->input = NULL;
+ /*
+ * If we stopped ourself due to any internal signal, we should try to
+ * unregister our own session here to avoid having it linger until the
+ * parent l2cap_conn dies or user-space cleans it up.
+ * This does not deadlock as we don't do any synchronous shutdown.
+ * Instead, this call has the same semantics as if user-space tried to
+ * delete the session.
+ */
+ l2cap_unregister_user(session->conn, &session->user);
+ hidp_session_put(session);
+
+ module_put_and_exit(0);
+ return 0;
+}
+
+static int hidp_verify_sockets(struct socket *ctrl_sock,
+ struct socket *intr_sock)
+{
+ struct bt_sock *ctrl, *intr;
+ struct hidp_session *session;
+
+ if (!l2cap_is_socket(ctrl_sock) || !l2cap_is_socket(intr_sock))
+ return -EINVAL;
+
+ ctrl = bt_sk(ctrl_sock->sk);
+ intr = bt_sk(intr_sock->sk);
+
+ if (bacmp(&ctrl->src, &intr->src) || bacmp(&ctrl->dst, &intr->dst))
+ return -ENOTUNIQ;
+ if (ctrl->sk.sk_state != BT_CONNECTED ||
+ intr->sk.sk_state != BT_CONNECTED)
+ return -EBADFD;
+
+ /* early session check, we check again during session registration */
+ session = hidp_session_find(&ctrl->dst);
+ if (session) {
+ hidp_session_put(session);
+ return -EEXIST;
}
- if (session->hid) {
- hid_destroy_device(session->hid);
- session->hid = NULL;
+ return 0;
+}
+
+int hidp_connection_add(struct hidp_connadd_req *req,
+ struct socket *ctrl_sock,
+ struct socket *intr_sock)
+{
+ struct hidp_session *session;
+ struct l2cap_conn *conn;
+ struct l2cap_chan *chan = l2cap_pi(ctrl_sock->sk)->chan;
+ int ret;
+
+ ret = hidp_verify_sockets(ctrl_sock, intr_sock);
+ if (ret)
+ return ret;
+
+ conn = NULL;
+ l2cap_chan_lock(chan);
+ if (chan->conn) {
+ l2cap_conn_get(chan->conn);
+ conn = chan->conn;
}
+ l2cap_chan_unlock(chan);
- kfree(session->rd_data);
- session->rd_data = NULL;
+ if (!conn)
+ return -EBADFD;
-purge:
- __hidp_unlink_session(session);
+ ret = hidp_session_new(&session, &bt_sk(ctrl_sock->sk)->dst, ctrl_sock,
+ intr_sock, req, conn);
+ if (ret)
+ goto out_conn;
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
+ ret = l2cap_register_user(conn, &session->user);
+ if (ret)
+ goto out_session;
-failed:
- up_write(&hidp_session_sem);
+ ret = 0;
- kfree(session);
- return err;
+out_session:
+ hidp_session_put(session);
+out_conn:
+ l2cap_conn_put(conn);
+ return ret;
}
-int hidp_del_connection(struct hidp_conndel_req *req)
+int hidp_connection_del(struct hidp_conndel_req *req)
{
struct hidp_session *session;
- int err = 0;
- BT_DBG("");
+ session = hidp_session_find(&req->bdaddr);
+ if (!session)
+ return -ENOENT;
- down_read(&hidp_session_sem);
+ if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG))
+ hidp_send_ctrl_message(session,
+ HIDP_TRANS_HID_CONTROL |
+ HIDP_CTRL_VIRTUAL_CABLE_UNPLUG,
+ NULL, 0);
+ else
+ l2cap_unregister_user(session->conn, &session->user);
- session = __hidp_get_session(&req->bdaddr);
- if (session) {
- if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) {
- hidp_send_ctrl_message(session,
- HIDP_TRANS_HID_CONTROL | HIDP_CTRL_VIRTUAL_CABLE_UNPLUG, NULL, 0);
- } else {
- /* Flush the transmit queues */
- skb_queue_purge(&session->ctrl_transmit);
- skb_queue_purge(&session->intr_transmit);
-
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
- }
- } else
- err = -ENOENT;
+ hidp_session_put(session);
- up_read(&hidp_session_sem);
- return err;
+ return 0;
}
int hidp_get_connlist(struct hidp_connlist_req *req)
@@ -1153,7 +1334,7 @@ int hidp_get_connlist(struct hidp_connlist_req *req)
list_for_each_entry(session, &hidp_session_list, list) {
struct hidp_conninfo ci;
- __hidp_copy_session(session, &ci);
+ hidp_copy_session(session, &ci);
if (copy_to_user(req->ci, &ci, sizeof(ci))) {
err = -EFAULT;
@@ -1174,18 +1355,14 @@ int hidp_get_connlist(struct hidp_connlist_req *req)
int hidp_get_conninfo(struct hidp_conninfo *ci)
{
struct hidp_session *session;
- int err = 0;
-
- down_read(&hidp_session_sem);
- session = __hidp_get_session(&ci->bdaddr);
- if (session)
- __hidp_copy_session(session, ci);
- else
- err = -ENOENT;
+ session = hidp_session_find(&ci->bdaddr);
+ if (session) {
+ hidp_copy_session(session, ci);
+ hidp_session_put(session);
+ }
- up_read(&hidp_session_sem);
- return err;
+ return session ? 0 : -ENOENT;
}
static int __init hidp_init(void)
@@ -1204,6 +1381,7 @@ module_init(hidp_init);
module_exit(hidp_exit);
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index af1bcc823f26..6162ce8606ac 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -24,7 +24,9 @@
#define __HIDP_H
#include <linux/types.h>
+#include <linux/kref.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/l2cap.h>
/* HIDP header masks */
#define HIDP_HEADER_TRANS_MASK 0xf0
@@ -119,43 +121,52 @@ struct hidp_connlist_req {
struct hidp_conninfo __user *ci;
};
-int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
-int hidp_del_connection(struct hidp_conndel_req *req);
+int hidp_connection_add(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock);
+int hidp_connection_del(struct hidp_conndel_req *req);
int hidp_get_connlist(struct hidp_connlist_req *req);
int hidp_get_conninfo(struct hidp_conninfo *ci);
+enum hidp_session_state {
+ HIDP_SESSION_IDLING,
+ HIDP_SESSION_RUNNING,
+};
+
/* HIDP session defines */
struct hidp_session {
struct list_head list;
+ struct kref ref;
- struct hci_conn *conn;
+ /* runtime management */
+ atomic_t state;
+ wait_queue_head_t state_queue;
+ atomic_t terminate;
+ struct task_struct *task;
+ unsigned long flags;
+ /* connection management */
+ bdaddr_t bdaddr;
+ struct l2cap_conn *conn;
+ struct l2cap_user user;
struct socket *ctrl_sock;
struct socket *intr_sock;
-
- bdaddr_t bdaddr;
-
- unsigned long state;
- unsigned long flags;
- unsigned long idle_to;
-
+ struct sk_buff_head ctrl_transmit;
+ struct sk_buff_head intr_transmit;
uint ctrl_mtu;
uint intr_mtu;
+ unsigned long idle_to;
- atomic_t terminate;
- struct task_struct *task;
-
- unsigned char keys[8];
- unsigned char leds;
-
+ /* device management */
struct input_dev *input;
-
struct hid_device *hid;
-
struct timer_list timer;
- struct sk_buff_head ctrl_transmit;
- struct sk_buff_head intr_transmit;
+ /* Report descriptor */
+ __u8 *rd_data;
+ uint rd_size;
+
+ /* session data */
+ unsigned char keys[8];
+ unsigned char leds;
/* Used in hidp_get_raw_report() */
int waiting_report_type; /* HIDP_DATA_RTYPE_* */
@@ -166,24 +177,8 @@ struct hidp_session {
/* Used in hidp_output_raw_report() */
int output_report_success; /* boolean */
-
- /* Report descriptor */
- __u8 *rd_data;
- uint rd_size;
-
- wait_queue_head_t startup_queue;
- int waiting_for_startup;
};
-static inline void hidp_schedule(struct hidp_session *session)
-{
- struct sock *ctrl_sk = session->ctrl_sock->sk;
- struct sock *intr_sk = session->intr_sock->sk;
-
- wake_up_interruptible(sk_sleep(ctrl_sk));
- wake_up_interruptible(sk_sleep(intr_sk));
-}
-
/* HIDP init defines */
extern int __init hidp_init_sockets(void);
extern void __exit hidp_cleanup_sockets(void);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index e7e04d4b9d99..cb3fdde1968a 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -77,21 +77,12 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return err;
}
- if (csock->sk->sk_state != BT_CONNECTED ||
- isock->sk->sk_state != BT_CONNECTED) {
- sockfd_put(csock);
- sockfd_put(isock);
- return -EBADFD;
- }
+ err = hidp_connection_add(&ca, csock, isock);
+ if (!err && copy_to_user(argp, &ca, sizeof(ca)))
+ err = -EFAULT;
- err = hidp_add_connection(&ca, csock, isock);
- if (!err) {
- if (copy_to_user(argp, &ca, sizeof(ca)))
- err = -EFAULT;
- } else {
- sockfd_put(csock);
- sockfd_put(isock);
- }
+ sockfd_put(csock);
+ sockfd_put(isock);
return err;
@@ -102,7 +93,7 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
if (copy_from_user(&cd, argp, sizeof(cd)))
return -EFAULT;
- return hidp_del_connection(&cd);
+ return hidp_connection_del(&cd);
case HIDPGETCONNLIST:
if (copy_from_user(&cl, argp, sizeof(cl)))
@@ -296,7 +287,6 @@ int __init hidp_init_sockets(void)
return 0;
error:
- BT_ERR("Can't register HIDP socket");
proto_unregister(&hidp_proto);
return err;
}
@@ -304,8 +294,6 @@ error:
void __exit hidp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "hidp");
- if (bt_sock_unregister(BTPROTO_HIDP) < 0)
- BT_ERR("Can't unregister HIDP socket");
-
+ bt_sock_unregister(BTPROTO_HIDP);
proto_unregister(&hidp_proto);
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7c7e9321f1ea..a76d1ac0321b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -571,7 +571,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
chan->conn = NULL;
if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
- hci_conn_put(conn->hcon);
+ hci_conn_drop(conn->hcon);
if (mgr && mgr->bredr_chan == chan)
mgr->bredr_chan = NULL;
@@ -1446,6 +1446,89 @@ static void l2cap_info_timeout(struct work_struct *work)
l2cap_conn_start(conn);
}
+/*
+ * l2cap_user
+ * External modules can register l2cap_user objects on l2cap_conn. The ->probe
+ * callback is called during registration. The ->remove callback is called
+ * during unregistration.
+ * An l2cap_user object can either be explicitly unregistered or when the
+ * underlying l2cap_conn object is deleted. This guarantees that l2cap->hcon,
+ * l2cap->hchan, .. are valid as long as the remove callback hasn't been called.
+ * External modules must own a reference to the l2cap_conn object if they intend
+ * to call l2cap_unregister_user(). The l2cap_conn object might get destroyed at
+ * any time if they don't.
+ */
+
+int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
+{
+ struct hci_dev *hdev = conn->hcon->hdev;
+ int ret;
+
+ /* We need to check whether l2cap_conn is registered. If it is not, we
+ * must not register the l2cap_user. l2cap_conn_del() is unregisters
+ * l2cap_conn objects, but doesn't provide its own locking. Instead, it
+ * relies on the parent hci_conn object to be locked. This itself relies
+ * on the hci_dev object to be locked. So we must lock the hci device
+ * here, too. */
+
+ hci_dev_lock(hdev);
+
+ if (user->list.next || user->list.prev) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /* conn->hchan is NULL after l2cap_conn_del() was called */
+ if (!conn->hchan) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+
+ ret = user->probe(conn, user);
+ if (ret)
+ goto out_unlock;
+
+ list_add(&user->list, &conn->users);
+ ret = 0;
+
+out_unlock:
+ hci_dev_unlock(hdev);
+ return ret;
+}
+EXPORT_SYMBOL(l2cap_register_user);
+
+void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
+{
+ struct hci_dev *hdev = conn->hcon->hdev;
+
+ hci_dev_lock(hdev);
+
+ if (!user->list.next || !user->list.prev)
+ goto out_unlock;
+
+ list_del(&user->list);
+ user->list.next = NULL;
+ user->list.prev = NULL;
+ user->remove(conn, user);
+
+out_unlock:
+ hci_dev_unlock(hdev);
+}
+EXPORT_SYMBOL(l2cap_unregister_user);
+
+static void l2cap_unregister_all_users(struct l2cap_conn *conn)
+{
+ struct l2cap_user *user;
+
+ while (!list_empty(&conn->users)) {
+ user = list_first_entry(&conn->users, struct l2cap_user, list);
+ list_del(&user->list);
+ user->list.next = NULL;
+ user->list.prev = NULL;
+ user->remove(conn, user);
+ }
+}
+
static void l2cap_conn_del(struct hci_conn *hcon, int err)
{
struct l2cap_conn *conn = hcon->l2cap_data;
@@ -1458,6 +1541,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
kfree_skb(conn->rx_skb);
+ l2cap_unregister_all_users(conn);
+
mutex_lock(&conn->chan_lock);
/* Kill channels */
@@ -1486,7 +1571,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
}
hcon->l2cap_data = NULL;
- kfree(conn);
+ conn->hchan = NULL;
+ l2cap_conn_put(conn);
}
static void security_timeout(struct work_struct *work)
@@ -1502,12 +1588,12 @@ static void security_timeout(struct work_struct *work)
}
}
-static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
+static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct hci_chan *hchan;
- if (conn || status)
+ if (conn)
return conn;
hchan = hci_chan_create(hcon);
@@ -1520,8 +1606,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
return NULL;
}
+ kref_init(&conn->ref);
hcon->l2cap_data = conn;
conn->hcon = hcon;
+ hci_conn_get(conn->hcon);
conn->hchan = hchan;
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
@@ -1547,6 +1635,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
mutex_init(&conn->chan_lock);
INIT_LIST_HEAD(&conn->chan_l);
+ INIT_LIST_HEAD(&conn->users);
if (hcon->type == LE_LINK)
INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
@@ -1558,6 +1647,26 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
return conn;
}
+static void l2cap_conn_free(struct kref *ref)
+{
+ struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
+
+ hci_conn_put(conn->hcon);
+ kfree(conn);
+}
+
+void l2cap_conn_get(struct l2cap_conn *conn)
+{
+ kref_get(&conn->ref);
+}
+EXPORT_SYMBOL(l2cap_conn_get);
+
+void l2cap_conn_put(struct l2cap_conn *conn)
+{
+ kref_put(&conn->ref, l2cap_conn_free);
+}
+EXPORT_SYMBOL(l2cap_conn_put);
+
/* ---- Socket interface ---- */
/* Find socket with psm and source / destination bdaddr.
@@ -1695,9 +1804,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
goto done;
}
- conn = l2cap_conn_add(hcon, 0);
+ conn = l2cap_conn_add(hcon);
if (!conn) {
- hci_conn_put(hcon);
+ hci_conn_drop(hcon);
err = -ENOMEM;
goto done;
}
@@ -1707,7 +1816,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
if (!list_empty(&conn->chan_l)) {
err = -EBUSY;
- hci_conn_put(hcon);
+ hci_conn_drop(hcon);
}
if (err)
@@ -6205,12 +6314,13 @@ drop:
kfree_skb(skb);
}
-static void l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
+static void l2cap_att_channel(struct l2cap_conn *conn,
struct sk_buff *skb)
{
struct l2cap_chan *chan;
- chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst);
+ chan = l2cap_global_chan_by_scid(0, L2CAP_CID_LE_DATA,
+ conn->src, conn->dst);
if (!chan)
goto drop;
@@ -6259,7 +6369,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
break;
case L2CAP_CID_LE_DATA:
- l2cap_att_channel(conn, cid, skb);
+ l2cap_att_channel(conn, skb);
break;
case L2CAP_CID_SMP:
@@ -6313,7 +6423,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
if (!status) {
- conn = l2cap_conn_add(hcon, status);
+ conn = l2cap_conn_add(hcon);
if (conn)
l2cap_conn_ready(conn);
} else {
@@ -6482,7 +6592,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
goto drop;
if (!conn)
- conn = l2cap_conn_add(hcon, 0);
+ conn = l2cap_conn_add(hcon);
if (!conn)
goto drop;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index fe15960c02c3..36fed40c162c 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -43,6 +43,12 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio);
+bool l2cap_is_socket(struct socket *sock)
+{
+ return sock && sock->ops == &l2cap_sock_ops;
+}
+EXPORT_SYMBOL(l2cap_is_socket);
+
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sock *sk = sock->sk;
@@ -1312,8 +1318,6 @@ error:
void l2cap_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "l2cap");
- if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
- BT_ERR("L2CAP socket unregistration failed");
-
+ bt_sock_unregister(BTPROTO_L2CAP);
proto_unregister(&l2cap_proto);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 39395c7144aa..35fef22703e9 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -106,11 +106,10 @@ static const u16 mgmt_events[] = {
* These LE scan and inquiry parameters were chosen according to LE General
* Discovery Procedure specification.
*/
-#define LE_SCAN_TYPE 0x01
#define LE_SCAN_WIN 0x12
#define LE_SCAN_INT 0x12
-#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
-#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
+#define LE_SCAN_TIMEOUT_LE_ONLY msecs_to_jiffies(10240)
+#define LE_SCAN_TIMEOUT_BREDR_LE msecs_to_jiffies(5120)
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
@@ -384,7 +383,8 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (lmp_bredr_capable(hdev)) {
settings |= MGMT_SETTING_CONNECTABLE;
- settings |= MGMT_SETTING_FAST_CONNECTABLE;
+ if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
+ settings |= MGMT_SETTING_FAST_CONNECTABLE;
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
@@ -409,6 +409,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_CONNECTABLE;
+ if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
+ settings |= MGMT_SETTING_FAST_CONNECTABLE;
+
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_DISCOVERABLE;
@@ -591,32 +594,33 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
}
-static int update_eir(struct hci_dev *hdev)
+static void update_eir(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp;
if (!hdev_is_powered(hdev))
- return 0;
+ return;
if (!lmp_ext_inq_capable(hdev))
- return 0;
+ return;
if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- return 0;
+ return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
+ return;
memset(&cp, 0, sizeof(cp));
create_eir(hdev, cp.data);
if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
- return 0;
+ return;
memcpy(hdev->eir, cp.data, sizeof(cp.data));
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
static u8 get_service_classes(struct hci_dev *hdev)
@@ -630,47 +634,48 @@ static u8 get_service_classes(struct hci_dev *hdev)
return val;
}
-static int update_class(struct hci_dev *hdev)
+static void update_class(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
u8 cod[3];
- int err;
BT_DBG("%s", hdev->name);
if (!hdev_is_powered(hdev))
- return 0;
+ return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
- return 0;
+ return;
cod[0] = hdev->minor_class;
cod[1] = hdev->major_class;
cod[2] = get_service_classes(hdev);
if (memcmp(cod, hdev->dev_class, 3) == 0)
- return 0;
-
- err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
- if (err == 0)
- set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
+ return;
- return err;
+ hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
}
static void service_cache_off(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
service_cache.work);
+ struct hci_request req;
if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
return;
+ hci_req_init(&req, hdev);
+
hci_dev_lock(hdev);
- update_eir(hdev);
- update_class(hdev);
+ update_eir(&req);
+ update_class(&req);
hci_dev_unlock(hdev);
+
+ hci_req_run(&req, NULL);
}
static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
@@ -994,11 +999,64 @@ failed:
return err;
}
+static void write_fast_connectable(struct hci_request *req, bool enable)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_write_page_scan_activity acp;
+ u8 type;
+
+ if (hdev->hci_ver < BLUETOOTH_VER_1_2)
+ return;
+
+ if (enable) {
+ type = PAGE_SCAN_TYPE_INTERLACED;
+
+ /* 160 msec page scan interval */
+ acp.interval = __constant_cpu_to_le16(0x0100);
+ } else {
+ type = PAGE_SCAN_TYPE_STANDARD; /* default */
+
+ /* default 1.28 sec page scan */
+ acp.interval = __constant_cpu_to_le16(0x0800);
+ }
+
+ acp.window = __constant_cpu_to_le16(0x0012);
+
+ if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
+ __cpu_to_le16(hdev->page_scan_window) != acp.window)
+ hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+ sizeof(acp), &acp);
+
+ if (hdev->page_scan_type != type)
+ hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+}
+
+static void set_connectable_complete(struct hci_dev *hdev, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_mode *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
u8 scan;
int err;
@@ -1065,7 +1123,20 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
cancel_delayed_work(&hdev->discov_off);
}
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ hci_req_init(&req, hdev);
+
+ hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+
+ /* If we're going from non-connectable to connectable or
+ * vice-versa when fast connectable is enabled ensure that fast
+ * connectable gets disabled. write_fast_connectable won't do
+ * anything if the page scan parameters are already what they
+ * should be.
+ */
+ if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
+ write_fast_connectable(&req, false);
+
+ err = hci_req_run(&req, set_connectable_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -1280,6 +1351,11 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
MGMT_STATUS_INVALID_PARAMS);
+ /* LE-only devices do not allow toggling LE on/off */
+ if (!lmp_bredr_capable(hdev))
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
+ MGMT_STATUS_REJECTED);
+
hci_dev_lock(hdev);
val = !!cp->val;
@@ -1332,6 +1408,29 @@ unlock:
return err;
}
+/* This is a helper function to test for pending mgmt commands that can
+ * cause CoD or EIR HCI commands. We can only allow one such pending
+ * mgmt command at a time since otherwise we cannot easily track what
+ * the current values are, will be, and based on that calculate if a new
+ * HCI command needs to be sent and if yes with what value.
+ */
+static bool pending_eir_or_class(struct hci_dev *hdev)
+{
+ struct pending_cmd *cmd;
+
+ list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+ switch (cmd->opcode) {
+ case MGMT_OP_ADD_UUID:
+ case MGMT_OP_REMOVE_UUID:
+ case MGMT_OP_SET_DEV_CLASS:
+ case MGMT_OP_SET_POWERED:
+ return true;
+ }
+ }
+
+ return false;
+}
+
static const u8 bluetooth_base_uuid[] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1351,10 +1450,37 @@ static u8 get_uuid_size(const u8 *uuid)
return 16;
}
+static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(mgmt_op, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
+ hdev->dev_class, 3);
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
+static void add_uuid_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
+}
+
static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{
struct mgmt_cp_add_uuid *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
struct bt_uuid *uuid;
int err;
@@ -1362,7 +1488,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+ if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
MGMT_STATUS_BUSY);
goto failed;
@@ -1380,23 +1506,28 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
list_add_tail(&uuid->list, &hdev->uuids);
- err = update_class(hdev);
- if (err < 0)
- goto failed;
+ hci_req_init(&req, hdev);
- err = update_eir(hdev);
- if (err < 0)
- goto failed;
+ update_class(&req);
+ update_eir(&req);
+
+ err = hci_req_run(&req, add_uuid_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto failed;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
hdev->dev_class, 3);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto failed;
+ }
+
+ err = 0;
failed:
hci_dev_unlock(hdev);
@@ -1417,6 +1548,13 @@ static bool enable_service_cache(struct hci_dev *hdev)
return false;
}
+static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
+}
+
static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
@@ -1424,13 +1562,14 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
struct pending_cmd *cmd;
struct bt_uuid *match, *tmp;
u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ struct hci_request req;
int err, found;
BT_DBG("request for %s", hdev->name);
hci_dev_lock(hdev);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
+ if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
MGMT_STATUS_BUSY);
goto unlock;
@@ -1466,34 +1605,47 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
}
update_class:
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
+ hci_req_init(&req, hdev);
- err = update_eir(hdev);
- if (err < 0)
- goto unlock;
+ update_class(&req);
+ update_eir(&req);
+
+ err = hci_req_run(&req, remove_uuid_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto unlock;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto unlock;
+ }
+
+ err = 0;
unlock:
hci_dev_unlock(hdev);
return err;
}
+static void set_class_complete(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("status 0x%02x", status);
+
+ mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
+}
+
static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_set_dev_class *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("request for %s", hdev->name);
@@ -1502,15 +1654,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
MGMT_STATUS_NOT_SUPPORTED);
- if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_BUSY);
+ hci_dev_lock(hdev);
- if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
- return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
- MGMT_STATUS_INVALID_PARAMS);
+ if (pending_eir_or_class(hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
- hci_dev_lock(hdev);
+ if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
+ MGMT_STATUS_INVALID_PARAMS);
+ goto unlock;
+ }
hdev->major_class = cp->major;
hdev->minor_class = cp->minor;
@@ -1521,26 +1677,34 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
+ hci_req_init(&req, hdev);
+
if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
hci_dev_unlock(hdev);
cancel_delayed_work_sync(&hdev->service_cache);
hci_dev_lock(hdev);
- update_eir(hdev);
+ update_eir(&req);
}
- err = update_class(hdev);
- if (err < 0)
- goto unlock;
+ update_class(&req);
+
+ err = hci_req_run(&req, set_class_complete);
+ if (err < 0) {
+ if (err != -ENODATA)
+ goto unlock;
- if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
hdev->dev_class, 3);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
- if (!cmd)
+ if (!cmd) {
err = -ENOMEM;
+ goto unlock;
+ }
+
+ err = 0;
unlock:
hci_dev_unlock(hdev);
@@ -1971,7 +2135,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
conn->security_cfm_cb = NULL;
conn->disconn_cfm_cb = NULL;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
mgmt_pending_remove(cmd);
}
@@ -2062,7 +2226,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
}
if (conn->connect_cfm_cb) {
- hci_conn_put(conn);
+ hci_conn_drop(conn);
err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
MGMT_STATUS_BUSY, &rp, sizeof(rp));
goto unlock;
@@ -2071,7 +2235,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
- hci_conn_put(conn);
+ hci_conn_drop(conn);
goto unlock;
}
@@ -2140,7 +2304,7 @@ unlock:
}
static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
- bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
+ struct mgmt_addr_info *addr, u16 mgmt_op,
u16 hci_op, __le32 passkey)
{
struct pending_cmd *cmd;
@@ -2150,37 +2314,41 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_POWERED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_NOT_POWERED, addr,
+ sizeof(*addr));
goto done;
}
- if (type == BDADDR_BREDR)
- conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
+ if (addr->type == BDADDR_BREDR)
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
else
- conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
if (!conn) {
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_NOT_CONNECTED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_NOT_CONNECTED, addr,
+ sizeof(*addr));
goto done;
}
- if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
+ if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
/* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err)
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_SUCCESS);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_SUCCESS, addr,
+ sizeof(*addr));
else
- err = cmd_status(sk, hdev->id, mgmt_op,
- MGMT_STATUS_FAILED);
+ err = cmd_complete(sk, hdev->id, mgmt_op,
+ MGMT_STATUS_FAILED, addr,
+ sizeof(*addr));
goto done;
}
- cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
+ cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
if (!cmd) {
err = -ENOMEM;
goto done;
@@ -2190,11 +2358,12 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
struct hci_cp_user_passkey_reply cp;
- bacpy(&cp.bdaddr, bdaddr);
+ bacpy(&cp.bdaddr, &addr->bdaddr);
cp.passkey = passkey;
err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
} else
- err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
+ err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
+ &addr->bdaddr);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -2211,7 +2380,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_PIN_CODE_NEG_REPLY,
HCI_OP_PIN_CODE_NEG_REPLY, 0);
}
@@ -2227,7 +2396,7 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
MGMT_STATUS_INVALID_PARAMS);
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_REPLY,
HCI_OP_USER_CONFIRM_REPLY, 0);
}
@@ -2239,7 +2408,7 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_NEG_REPLY,
HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
}
@@ -2251,7 +2420,7 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_REPLY,
HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
}
@@ -2263,18 +2432,47 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG("");
- return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
+ return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_NEG_REPLY,
HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
}
-static int update_name(struct hci_dev *hdev, const char *name)
+static void update_name(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_local_name cp;
- memcpy(cp.name, name, sizeof(cp.name));
+ memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
+
+ hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+}
+
+static void set_name_complete(struct hci_dev *hdev, u8 status)
+{
+ struct mgmt_cp_set_local_name *cp;
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
- return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
+ cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
+ if (!cmd)
+ goto unlock;
+
+ cp = cmd->param;
+
+ if (status)
+ cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+ mgmt_status(status));
+ else
+ cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+ cp, sizeof(*cp));
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
}
static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
@@ -2282,12 +2480,24 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
{
struct mgmt_cp_set_local_name *cp = data;
struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("");
hci_dev_lock(hdev);
+ /* If the old values are the same as the new ones just return a
+ * direct command complete event.
+ */
+ if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
+ !memcmp(hdev->short_name, cp->short_name,
+ sizeof(hdev->short_name))) {
+ err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
+ data, len);
+ goto failed;
+ }
+
memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
if (!hdev_is_powered(hdev)) {
@@ -2310,7 +2520,19 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed;
}
- err = update_name(hdev, cp->name);
+ memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
+
+ hci_req_init(&req, hdev);
+
+ if (lmp_bredr_capable(hdev)) {
+ update_name(&req);
+ update_eir(&req);
+ }
+
+ if (lmp_le_capable(hdev))
+ hci_update_ad(&req);
+
+ err = hci_req_run(&req, set_name_complete);
if (err < 0)
mgmt_pending_remove(cmd);
@@ -2485,7 +2707,7 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
- err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
+ err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
break;
@@ -2497,8 +2719,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
- err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
- LE_SCAN_TIMEOUT_BREDR_LE);
+ err = hci_le_scan(hdev, LE_SCAN_ACTIVE, LE_SCAN_INT,
+ LE_SCAN_WIN, LE_SCAN_TIMEOUT_BREDR_LE);
break;
default:
@@ -2698,6 +2920,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len)
{
struct mgmt_cp_set_device_id *cp = data;
+ struct hci_request req;
int err;
__u16 source;
@@ -2718,24 +2941,59 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
- update_eir(hdev);
+ hci_req_init(&req, hdev);
+ update_eir(&req);
+ hci_req_run(&req, NULL);
hci_dev_unlock(hdev);
return err;
}
+static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
+{
+ struct pending_cmd *cmd;
+
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
+
+ cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
+ if (!cmd)
+ goto unlock;
+
+ if (status) {
+ cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+ mgmt_status(status));
+ } else {
+ struct mgmt_mode *cp = cmd->param;
+
+ if (cp->val)
+ set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
+ else
+ clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
+
+ send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
+ new_settings(hdev, cmd->sk);
+ }
+
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+}
+
static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
struct mgmt_mode *cp = data;
- struct hci_cp_write_page_scan_activity acp;
- u8 type;
+ struct pending_cmd *cmd;
+ struct hci_request req;
int err;
BT_DBG("%s", hdev->name);
- if (!lmp_bredr_capable(hdev))
+ if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_NOT_SUPPORTED);
@@ -2753,40 +3011,39 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
- if (cp->val) {
- type = PAGE_SCAN_TYPE_INTERLACED;
+ if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
- /* 160 msec page scan interval */
- acp.interval = __constant_cpu_to_le16(0x0100);
- } else {
- type = PAGE_SCAN_TYPE_STANDARD; /* default */
+ if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
+ err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
+ hdev);
+ goto unlock;
+ }
- /* default 1.28 sec page scan */
- acp.interval = __constant_cpu_to_le16(0x0800);
+ cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
+ data, len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
}
- /* default 11.25 msec page scan window */
- acp.window = __constant_cpu_to_le16(0x0012);
+ hci_req_init(&req, hdev);
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
- &acp);
- if (err < 0) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
- MGMT_STATUS_FAILED);
- goto done;
- }
+ write_fast_connectable(&req, cp->val);
- err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+ err = hci_req_run(&req, fast_connectable_complete);
if (err < 0) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_FAILED);
- goto done;
+ mgmt_pending_remove(cmd);
}
- err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
- NULL, 0);
-done:
+unlock:
hci_dev_unlock(hdev);
+
return err;
}
@@ -3043,79 +3300,116 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_free(cmd);
}
-static int set_bredr_scan(struct hci_dev *hdev)
+static void set_bredr_scan(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
u8 scan = 0;
+ /* Ensure that fast connectable is disabled. This function will
+ * not do anything if the page scan parameters are already what
+ * they should be.
+ */
+ write_fast_connectable(req, false);
+
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
scan |= SCAN_PAGE;
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
scan |= SCAN_INQUIRY;
- if (!scan)
- return 0;
-
- return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+ if (scan)
+ hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
-int mgmt_powered(struct hci_dev *hdev, u8 powered)
+static void powered_complete(struct hci_dev *hdev, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
- int err;
- if (!test_bit(HCI_MGMT, &hdev->dev_flags))
- return 0;
+ BT_DBG("status 0x%02x", status);
+
+ hci_dev_lock(hdev);
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
- if (powered) {
- u8 link_sec;
+ new_settings(hdev, match.sk);
- if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
- !lmp_host_ssp_capable(hdev)) {
- u8 ssp = 1;
+ hci_dev_unlock(hdev);
- hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
- }
+ if (match.sk)
+ sock_put(match.sk);
+}
+
+static int powered_update_hci(struct hci_dev *hdev)
+{
+ struct hci_request req;
+ u8 link_sec;
- if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
- struct hci_cp_write_le_host_supported cp;
+ hci_req_init(&req, hdev);
- cp.le = 1;
- cp.simul = lmp_le_br_capable(hdev);
+ if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+ !lmp_host_ssp_capable(hdev)) {
+ u8 ssp = 1;
- /* Check first if we already have the right
- * host state (host features set)
- */
- if (cp.le != lmp_host_le_capable(hdev) ||
- cp.simul != lmp_host_le_br_capable(hdev))
- hci_send_cmd(hdev,
- HCI_OP_WRITE_LE_HOST_SUPPORTED,
- sizeof(cp), &cp);
- }
+ hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
+ }
- link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
- if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
- hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE,
- sizeof(link_sec), &link_sec);
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
+ lmp_bredr_capable(hdev)) {
+ struct hci_cp_write_le_host_supported cp;
- if (lmp_bredr_capable(hdev)) {
- set_bredr_scan(hdev);
- update_class(hdev);
- update_name(hdev, hdev->dev_name);
- update_eir(hdev);
- }
- } else {
- u8 status = MGMT_STATUS_NOT_POWERED;
- u8 zero_cod[] = { 0, 0, 0 };
+ cp.le = 1;
+ cp.simul = lmp_le_br_capable(hdev);
- mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+ /* Check first if we already have the right
+ * host state (host features set)
+ */
+ if (cp.le != lmp_host_le_capable(hdev) ||
+ cp.simul != lmp_host_le_br_capable(hdev))
+ hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
+ sizeof(cp), &cp);
+ }
+
+ link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
+ if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
+ hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
+ sizeof(link_sec), &link_sec);
- if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
- mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
- zero_cod, sizeof(zero_cod), NULL);
+ if (lmp_bredr_capable(hdev)) {
+ set_bredr_scan(&req);
+ update_class(&req);
+ update_name(&req);
+ update_eir(&req);
}
+ return hci_req_run(&req, powered_complete);
+}
+
+int mgmt_powered(struct hci_dev *hdev, u8 powered)
+{
+ struct cmd_lookup match = { NULL, hdev };
+ u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
+ u8 zero_cod[] = { 0, 0, 0 };
+ int err;
+
+ if (!test_bit(HCI_MGMT, &hdev->dev_flags))
+ return 0;
+
+ if (powered) {
+ if (powered_update_hci(hdev) == 0)
+ return 0;
+
+ mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
+ &match);
+ goto new_settings;
+ }
+
+ mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
+ mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
+
+ if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
+ mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
+ zero_cod, sizeof(zero_cod), NULL);
+
+new_settings:
err = new_settings(hdev, match.sk);
if (match.sk)
@@ -3152,7 +3446,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
{
- struct cmd_lookup match = { NULL, hdev };
+ struct pending_cmd *cmd;
bool changed = false;
int err = 0;
@@ -3164,14 +3458,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
changed = true;
}
- mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
- &match);
+ cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
if (changed)
- err = new_settings(hdev, match.sk);
-
- if (match.sk)
- sock_put(match.sk);
+ err = new_settings(hdev, cmd ? cmd->sk : NULL);
return err;
}
@@ -3555,23 +3845,25 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
return err;
}
-static int clear_eir(struct hci_dev *hdev)
+static void clear_eir(struct hci_request *req)
{
+ struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp;
if (!lmp_ext_inq_capable(hdev))
- return 0;
+ return;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp));
- return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
+ hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
+ struct hci_request req;
bool changed = false;
int err = 0;
@@ -3604,29 +3896,26 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
if (match.sk)
sock_put(match.sk);
+ hci_req_init(&req, hdev);
+
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
- update_eir(hdev);
+ update_eir(&req);
else
- clear_eir(hdev);
+ clear_eir(&req);
+
+ hci_req_run(&req, NULL);
return err;
}
-static void class_rsp(struct pending_cmd *cmd, void *data)
+static void sk_lookup(struct pending_cmd *cmd, void *data)
{
struct cmd_lookup *match = data;
- cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
- match->hdev->dev_class, 3);
-
- list_del(&cmd->list);
-
if (match->sk == NULL) {
match->sk = cmd->sk;
sock_hold(match->sk);
}
-
- mgmt_pending_free(cmd);
}
int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
@@ -3635,11 +3924,9 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
int err = 0;
- clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
-
- mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
- mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
+ mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
+ mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
+ mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
if (!status)
err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
@@ -3653,55 +3940,29 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
{
- struct pending_cmd *cmd;
struct mgmt_cp_set_local_name ev;
- bool changed = false;
- int err = 0;
+ struct pending_cmd *cmd;
- if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
- memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
- changed = true;
- }
+ if (status)
+ return 0;
memset(&ev, 0, sizeof(ev));
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
- if (!cmd)
- goto send_event;
-
- /* Always assume that either the short or the complete name has
- * changed if there was a pending mgmt command */
- changed = true;
+ if (!cmd) {
+ memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
- if (status) {
- err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
- mgmt_status(status));
- goto failed;
+ /* If this is a HCI command related to powering on the
+ * HCI dev don't send any mgmt signals.
+ */
+ if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
+ return 0;
}
- err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
- sizeof(ev));
- if (err < 0)
- goto failed;
-
-send_event:
- if (changed)
- err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
- sizeof(ev), cmd ? cmd->sk : NULL);
-
- /* EIR is taken care of separately when powering on the
- * adapter so only update them here if this is a name change
- * unrelated to power on.
- */
- if (!test_bit(HCI_INIT, &hdev->flags))
- update_eir(hdev);
-
-failed:
- if (cmd)
- mgmt_pending_remove(cmd);
- return err;
+ return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
+ cmd ? cmd->sk : NULL);
}
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index b23e2713fea8..ca957d34b0c8 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -69,7 +69,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
u8 sec_level,
int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
-static void rfcomm_session_del(struct rfcomm_session *s);
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
/* ---- RFCOMM frame parsing macros ---- */
#define __get_dlci(b) ((b & 0xfc) >> 2)
@@ -108,12 +108,6 @@ static void rfcomm_schedule(void)
wake_up_process(rfcomm_thread);
}
-static void rfcomm_session_put(struct rfcomm_session *s)
-{
- if (atomic_dec_and_test(&s->refcnt))
- rfcomm_session_del(s);
-}
-
/* ---- RFCOMM FCS computation ---- */
/* reversed, 8-bit, poly=0x07 */
@@ -249,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
+ mod_timer(&s->timer, jiffies + timeout);
}
static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{
BT_DBG("session %p state %ld", s, s->state);
- if (del_timer(&s->timer))
- rfcomm_session_put(s);
+ del_timer_sync(&s->timer);
}
/* ---- RFCOMM DLCs ---- */
@@ -336,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{
BT_DBG("dlc %p session %p", d, s);
- rfcomm_session_hold(s);
-
rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs);
@@ -356,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
- rfcomm_session_put(s);
}
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
@@ -493,12 +481,34 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
{
- int r;
+ int r = 0;
+ struct rfcomm_dlc *d_list;
+ struct rfcomm_session *s, *s_list;
+
+ BT_DBG("dlc %p state %ld dlci %d err %d", d, d->state, d->dlci, err);
rfcomm_lock();
- r = __rfcomm_dlc_close(d, err);
+ s = d->session;
+ if (!s)
+ goto no_session;
+
+ /* after waiting on the mutex check the session still exists
+ * then check the dlc still exists
+ */
+ list_for_each_entry(s_list, &session_list, list) {
+ if (s_list == s) {
+ list_for_each_entry(d_list, &s->dlcs, list) {
+ if (d_list == d) {
+ r = __rfcomm_dlc_close(d, err);
+ break;
+ }
+ }
+ break;
+ }
+ }
+no_session:
rfcomm_unlock();
return r;
}
@@ -609,7 +619,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return s;
}
-static void rfcomm_session_del(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s)
{
int state = s->state;
@@ -617,15 +627,14 @@ static void rfcomm_session_del(struct rfcomm_session *s)
list_del(&s->list);
- if (state == BT_CONNECTED)
- rfcomm_send_disc(s, 0);
-
rfcomm_session_clear_timer(s);
sock_release(s->sock);
kfree(s);
if (state != BT_LISTEN)
module_put(THIS_MODULE);
+
+ return NULL;
}
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
@@ -644,17 +653,16 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
return NULL;
}
-static void rfcomm_session_close(struct rfcomm_session *s, int err)
+static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
+ int err)
{
struct rfcomm_dlc *d;
struct list_head *p, *n;
- BT_DBG("session %p state %ld err %d", s, s->state, err);
-
- rfcomm_session_hold(s);
-
s->state = BT_CLOSED;
+ BT_DBG("session %p state %ld err %d", s, s->state, err);
+
/* Close all dlcs */
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -663,7 +671,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
}
rfcomm_session_clear_timer(s);
- rfcomm_session_put(s);
+ return rfcomm_session_del(s);
}
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
@@ -715,8 +723,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
if (*err == 0 || *err == -EINPROGRESS)
return s;
- rfcomm_session_del(s);
- return NULL;
+ return rfcomm_session_del(s);
failed:
sock_release(sock);
@@ -1105,7 +1112,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
}
/* ---- RFCOMM frame reception ---- */
-static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
{
BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
@@ -1114,7 +1121,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
if (!d) {
rfcomm_send_dm(s, dlci);
- return 0;
+ return s;
}
switch (d->state) {
@@ -1150,25 +1157,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ s = rfcomm_session_close(s, ECONNRESET);
break;
}
}
- return 0;
+ return s;
}
-static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
{
int err = 0;
@@ -1192,13 +1188,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
else
err = ECONNRESET;
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
- return 0;
+ return s;
}
-static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
+static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s,
+ u8 dlci)
{
int err = 0;
@@ -1227,11 +1223,9 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
else
err = ECONNRESET;
- s->state = BT_CLOSED;
- rfcomm_session_close(s, err);
+ s = rfcomm_session_close(s, err);
}
-
- return 0;
+ return s;
}
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
@@ -1652,11 +1646,18 @@ drop:
return 0;
}
-static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
+static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
+ struct sk_buff *skb)
{
struct rfcomm_hdr *hdr = (void *) skb->data;
u8 type, dlci, fcs;
+ if (!s) {
+ /* no session, so free socket data */
+ kfree_skb(skb);
+ return s;
+ }
+
dlci = __get_dlci(hdr->addr);
type = __get_type(hdr->ctrl);
@@ -1667,7 +1668,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
if (__check_fcs(skb->data, type, fcs)) {
BT_ERR("bad checksum in packet");
kfree_skb(skb);
- return -EILSEQ;
+ return s;
}
if (__test_ea(hdr->len))
@@ -1683,22 +1684,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
case RFCOMM_DISC:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_disc(s, dlci);
+ s = rfcomm_recv_disc(s, dlci);
break;
case RFCOMM_UA:
if (__test_pf(hdr->ctrl))
- rfcomm_recv_ua(s, dlci);
+ s = rfcomm_recv_ua(s, dlci);
break;
case RFCOMM_DM:
- rfcomm_recv_dm(s, dlci);
+ s = rfcomm_recv_dm(s, dlci);
break;
case RFCOMM_UIH:
- if (dlci)
- return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
-
+ if (dlci) {
+ rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
+ return s;
+ }
rfcomm_recv_mcc(s, skb);
break;
@@ -1707,7 +1709,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
break;
}
kfree_skb(skb);
- return 0;
+ return s;
}
/* ---- Connection and data processing ---- */
@@ -1844,7 +1846,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s)
}
}
-static void rfcomm_process_rx(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
{
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
@@ -1856,17 +1858,15 @@ static void rfcomm_process_rx(struct rfcomm_session *s)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
- rfcomm_recv_frame(s, skb);
+ s = rfcomm_recv_frame(s, skb);
else
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
+ if (s && (sk->sk_state == BT_CLOSED))
+ s = rfcomm_session_close(s, sk->sk_err);
- rfcomm_session_close(s, sk->sk_err);
- }
+ return s;
}
static void rfcomm_accept_connection(struct rfcomm_session *s)
@@ -1891,8 +1891,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN);
if (s) {
- rfcomm_session_hold(s);
-
/* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
@@ -1903,7 +1901,7 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
sock_release(nsock);
}
-static void rfcomm_check_connection(struct rfcomm_session *s)
+static struct rfcomm_session *rfcomm_check_connection(struct rfcomm_session *s)
{
struct sock *sk = s->sock->sk;
@@ -1921,10 +1919,10 @@ static void rfcomm_check_connection(struct rfcomm_session *s)
break;
case BT_CLOSED:
- s->state = BT_CLOSED;
- rfcomm_session_close(s, sk->sk_err);
+ s = rfcomm_session_close(s, sk->sk_err);
break;
}
+ return s;
}
static void rfcomm_process_sessions(void)
@@ -1940,7 +1938,6 @@ static void rfcomm_process_sessions(void)
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
- rfcomm_session_put(s);
continue;
}
@@ -1949,21 +1946,18 @@ static void rfcomm_process_sessions(void)
continue;
}
- rfcomm_session_hold(s);
-
switch (s->state) {
case BT_BOUND:
- rfcomm_check_connection(s);
+ s = rfcomm_check_connection(s);
break;
default:
- rfcomm_process_rx(s);
+ s = rfcomm_process_rx(s);
break;
}
- rfcomm_process_dlcs(s);
-
- rfcomm_session_put(s);
+ if (s)
+ rfcomm_process_dlcs(s);
}
rfcomm_unlock();
@@ -2010,10 +2004,11 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Add listening session */
s = rfcomm_session_add(sock, BT_LISTEN);
- if (!s)
+ if (!s) {
+ err = -ENOMEM;
goto failed;
+ }
- rfcomm_session_hold(s);
return 0;
failed:
sock_release(sock);
@@ -2071,8 +2066,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s)
return;
- rfcomm_session_hold(s);
-
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -2104,8 +2097,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
- rfcomm_session_put(s);
-
rfcomm_schedule();
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index fda3bb4019a3..30b3721dc6d7 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -608,6 +608,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
rfcomm_dlc_accept(d);
+ msg->msg_namelen = 0;
return 0;
}
@@ -1065,8 +1066,7 @@ void __exit rfcomm_cleanup_sockets(void)
debugfs_remove(rfcomm_sock_debugfs);
- if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
- BT_ERR("RFCOMM socket layer unregistration failed");
+ bt_sock_unregister(BTPROTO_RFCOMM);
proto_unregister(&rfcomm_proto);
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 7e8dbaf8bc10..e7bd4eea575c 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -83,7 +83,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
if (conn)
return conn;
- conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
+ conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
if (!conn)
return NULL;
@@ -185,7 +185,7 @@ static int sco_connect(struct sock *sk)
conn = sco_conn_add(hcon);
if (!conn) {
- hci_conn_put(hcon);
+ hci_conn_drop(hcon);
err = -ENOMEM;
goto done;
}
@@ -353,7 +353,7 @@ static void __sco_sock_close(struct sock *sk)
if (sco_pi(sk)->conn->hcon) {
sk->sk_state = BT_DISCONN;
sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
- hci_conn_put(sco_pi(sk)->conn->hcon);
+ hci_conn_drop(sco_pi(sk)->conn->hcon);
sco_pi(sk)->conn->hcon = NULL;
} else
sco_chan_del(sk, ECONNRESET);
@@ -481,8 +481,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
{
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
- int err = 0;
-
+ int err;
BT_DBG("sk %p", sk);
@@ -653,6 +652,42 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
+static void sco_conn_defer_accept(struct hci_conn *conn, int mask)
+{
+ struct hci_dev *hdev = conn->hdev;
+
+ BT_DBG("conn %p", conn);
+
+ conn->state = BT_CONFIG;
+
+ if (!lmp_esco_capable(hdev)) {
+ struct hci_cp_accept_conn_req cp;
+
+ bacpy(&cp.bdaddr, &conn->dst);
+
+ if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
+ cp.role = 0x00; /* Become master */
+ else
+ cp.role = 0x01; /* Remain slave */
+
+ hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
+ } else {
+ struct hci_cp_accept_sync_conn_req cp;
+
+ bacpy(&cp.bdaddr, &conn->dst);
+ cp.pkt_type = cpu_to_le16(conn->pkt_type);
+
+ cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
+ cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
+ cp.max_latency = __constant_cpu_to_le16(0xffff);
+ cp.content_format = cpu_to_le16(hdev->voice_setting);
+ cp.retrans_effort = 0xff;
+
+ hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
+ sizeof(cp), &cp);
+ }
+}
+
static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags)
{
@@ -663,8 +698,9 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_state == BT_CONNECT2 &&
test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
- hci_conn_accept(pi->conn->hcon, 0);
+ sco_conn_defer_accept(pi->conn->hcon, 0);
sk->sk_state = BT_CONFIG;
+ msg->msg_namelen = 0;
release_sock(sk);
return 0;
@@ -882,7 +918,7 @@ static void sco_chan_del(struct sock *sk, int err)
sco_conn_unlock(conn);
if (conn->hcon)
- hci_conn_put(conn->hcon);
+ hci_conn_drop(conn->hcon);
}
sk->sk_state = BT_CLOSED;
@@ -1112,8 +1148,7 @@ void __exit sco_exit(void)
debugfs_remove(sco_debugfs);
- if (bt_sock_unregister(BTPROTO_SCO) < 0)
- BT_ERR("SCO socket unregistration failed");
+ bt_sock_unregister(BTPROTO_SCO);
proto_unregister(&sco_proto);
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 5abefb12891d..b2296d3857a0 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -522,7 +522,7 @@ void smp_chan_destroy(struct l2cap_conn *conn)
kfree(smp);
conn->smp_chan = NULL;
conn->hcon->smp_conn = NULL;
- hci_conn_put(conn->hcon);
+ hci_conn_drop(conn->hcon);
}
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 314c73ed418f..967312803e41 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -348,10 +348,10 @@ void br_dev_setup(struct net_device *dev)
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
- NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX;
+ NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_CTAG_TX;
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_CTAG_TX;
br->dev = dev;
spin_lock_init(&br->lock);
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index bab338e6270d..ebfa4443c69b 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -161,9 +161,7 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
if (!pv)
return;
- for (vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid);
- vid < BR_VLAN_BITMAP_LEN;
- vid = find_next_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN, vid+1)) {
+ for_each_set_bit_from(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
f = __br_fdb_get(br, br->dev->dev_addr, vid);
if (f && f->is_local && !f->dst)
fdb_delete(br, f);
@@ -617,6 +615,7 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
struct net_bridge *br = source->br;
struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
struct net_bridge_fdb_entry *fdb;
+ bool modified = false;
fdb = fdb_find(head, addr, vid);
if (fdb == NULL) {
@@ -626,10 +625,16 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
fdb = fdb_create(head, source, addr, vid);
if (!fdb)
return -ENOMEM;
- fdb_notify(br, fdb, RTM_NEWNEIGH);
+
+ modified = true;
} else {
if (flags & NLM_F_EXCL)
return -EEXIST;
+
+ if (fdb->dst != source) {
+ fdb->dst = source;
+ modified = true;
+ }
}
if (fdb_to_nud(fdb) != state) {
@@ -641,7 +646,12 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
} else
fdb->is_local = fdb->is_static = 0;
- fdb->updated = fdb->used = jiffies;
+ modified = true;
+ }
+
+ fdb->used = jiffies;
+ if (modified) {
+ fdb->updated = jiffies;
fdb_notify(br, fdb, RTM_NEWNEIGH);
}
@@ -724,13 +734,10 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
* specify a VLAN. To be nice, add/update entry for every
* vlan on this port.
*/
- vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
- while (vid < BR_VLAN_BITMAP_LEN) {
+ for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
err = __br_fdb_add(ndm, p, addr, nlh_flags, vid);
if (err)
goto out;
- vid = find_next_bit(pv->vlan_bitmap,
- BR_VLAN_BITMAP_LEN, vid+1);
}
}
@@ -815,11 +822,8 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
* vlan on this port.
*/
err = -ENOENT;
- vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
- while (vid < BR_VLAN_BITMAP_LEN) {
+ for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
err &= __br_fdb_delete(p, addr, vid);
- vid = find_next_bit(pv->vlan_bitmap,
- BR_VLAN_BITMAP_LEN, vid+1);
}
}
out:
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index ef1b91431c6b..4cdba60926ff 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -67,7 +67,8 @@ void br_port_carrier_check(struct net_bridge_port *p)
struct net_device *dev = p->dev;
struct net_bridge *br = p->br;
- if (netif_running(dev) && netif_oper_up(dev))
+ if (!(p->flags & BR_ADMIN_COST) &&
+ netif_running(dev) && netif_oper_up(dev))
p->path_cost = port_cost(dev);
if (!netif_running(br->dev))
@@ -148,7 +149,6 @@ static void del_nbp(struct net_bridge_port *p)
dev->priv_flags &= ~IFF_BRIDGE_PORT;
netdev_rx_handler_unregister(dev);
- synchronize_net();
netdev_upper_dev_unlink(dev, br->dev);
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index ee79f3f20383..19942e38fd2d 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -382,7 +382,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
return ret;
}
-static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct br_mdb_entry *entry;
@@ -458,7 +458,7 @@ unlock:
return err;
}
-static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net_device *dev;
struct br_mdb_entry *entry;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 923fbeaf7afd..81f2389f78eb 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1369,7 +1369,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
return -EINVAL;
if (iph->protocol != IPPROTO_IGMP) {
- if ((iph->daddr & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP)
+ if (!ipv4_is_local_multicast(iph->daddr))
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
return 0;
}
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index fe43bc7b063f..1ed75bfd8d1d 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -535,7 +535,8 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct
if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb))
return br;
- vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK);
+ vlan = __vlan_find_dev_deep(br, skb->vlan_proto,
+ vlan_tx_tag_get(skb) & VLAN_VID_MASK);
return vlan ? vlan : br;
}
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 299fc5f40a26..8e3abf564798 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -136,10 +136,7 @@ static int br_fill_ifinfo(struct sk_buff *skb,
goto nla_put_failure;
pvid = br_get_pvid(pv);
- for (vid = find_first_bit(pv->vlan_bitmap, BR_VLAN_BITMAP_LEN);
- vid < BR_VLAN_BITMAP_LEN;
- vid = find_next_bit(pv->vlan_bitmap,
- BR_VLAN_BITMAP_LEN, vid+1)) {
+ for_each_set_bit(vid, pv->vlan_bitmap, BR_VLAN_BITMAP_LEN) {
vinfo.vid = vid;
vinfo.flags = 0;
if (vid == pvid)
@@ -355,17 +352,14 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
/* Change state and parameters on port. */
int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
{
- struct ifinfomsg *ifm;
struct nlattr *protinfo;
struct nlattr *afspec;
struct net_bridge_port *p;
struct nlattr *tb[IFLA_BRPORT_MAX + 1];
- int err;
-
- ifm = nlmsg_data(nlh);
+ int err = 0;
- protinfo = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_PROTINFO);
- afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
+ protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO);
+ afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
if (!protinfo && !afspec)
return 0;
@@ -373,7 +367,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
/* We want to accept dev as bridge itself if the AF_SPEC
* is set to see if someone is setting vlan info on the brigde
*/
- if (!p && ((dev->priv_flags & IFF_EBRIDGE) && !afspec))
+ if (!p && !afspec)
return -EINVAL;
if (p && protinfo) {
@@ -414,14 +408,11 @@ out:
/* Delete port information */
int br_dellink(struct net_device *dev, struct nlmsghdr *nlh)
{
- struct ifinfomsg *ifm;
struct nlattr *afspec;
struct net_bridge_port *p;
int err;
- ifm = nlmsg_data(nlh);
-
- afspec = nlmsg_find_attr(nlh, sizeof(*ifm), IFLA_AF_SPEC);
+ afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
if (!afspec)
return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 3cbf5beb3d4b..d2c043a857b6 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -156,6 +156,7 @@ struct net_bridge_port
#define BR_BPDU_GUARD 0x00000002
#define BR_ROOT_BLOCK 0x00000004
#define BR_MULTICAST_FAST_LEAVE 0x00000008
+#define BR_ADMIN_COST 0x00000010
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
u32 multicast_startup_queries_sent;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index b01849a74310..1c0a50f13229 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -225,7 +225,14 @@ static void br_record_config_timeout_values(struct net_bridge *br,
/* called under bridge lock */
void br_transmit_tcn(struct net_bridge *br)
{
- br_send_tcn_bpdu(br_get_port(br, br->root_port));
+ struct net_bridge_port *p;
+
+ p = br_get_port(br, br->root_port);
+ if (p)
+ br_send_tcn_bpdu(p);
+ else
+ br_notice(br, "root port %u not found for topology notice\n",
+ br->root_port);
}
/* called under bridge lock */
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 0bdb4ebd362b..d45e760141bb 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -288,6 +288,7 @@ int br_stp_set_path_cost(struct net_bridge_port *p, unsigned long path_cost)
path_cost > BR_MAX_PATH_COST)
return -ERANGE;
+ p->flags |= BR_ADMIN_COST;
p->path_cost = path_cost;
br_configuration_update(p->br);
br_port_state_selection(p->br);
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 93dde75923f0..bd58b45f5f90 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -34,6 +34,7 @@ static void __vlan_add_flags(struct net_port_vlans *v, u16 vid, u16 flags)
static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
{
+ const struct net_device_ops *ops;
struct net_bridge_port *p = NULL;
struct net_bridge *br;
struct net_device *dev;
@@ -53,15 +54,17 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
br = v->parent.br;
dev = br->dev;
}
+ ops = dev->netdev_ops;
- if (p && (dev->features & NETIF_F_HW_VLAN_FILTER)) {
+ if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) {
/* Add VLAN to the device filter if it is supported.
* Stricly speaking, this is not necessary now, since
* devices are made promiscuous by the bridge, but if
* that ever changes this code will allow tagged
* traffic to enter the bridge.
*/
- err = dev->netdev_ops->ndo_vlan_rx_add_vid(dev, vid);
+ err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q),
+ vid);
if (err)
return err;
}
@@ -82,8 +85,8 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags)
return 0;
out_filt:
- if (p && (dev->features & NETIF_F_HW_VLAN_FILTER))
- dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
+ if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
+ ops->ndo_vlan_rx_kill_vid(dev, htons(ETH_P_8021Q), vid);
return err;
}
@@ -97,9 +100,10 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
if (v->port_idx && vid) {
struct net_device *dev = v->parent.port->dev;
+ const struct net_device_ops *ops = dev->netdev_ops;
- if (dev->features & NETIF_F_HW_VLAN_FILTER)
- dev->netdev_ops->ndo_vlan_rx_kill_vid(dev, vid);
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
+ ops->ndo_vlan_rx_kill_vid(dev, htons(ETH_P_8021Q), vid);
}
clear_bit(vid, v->vlan_bitmap);
@@ -171,7 +175,7 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
* mac header.
*/
skb_push(skb, ETH_HLEN);
- skb = __vlan_put_tag(skb, skb->vlan_tci);
+ skb = __vlan_put_tag(skb, skb->vlan_proto, skb->vlan_tci);
if (!skb)
goto out;
/* put skb->data back to where it was */
@@ -213,7 +217,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
/* PVID is set on this port. Any untagged ingress
* frame is considered to belong to this vlan.
*/
- __vlan_hwaccel_put_tag(skb, pvid);
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid);
return true;
}
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index 92de5e5f9db2..9878eb8204c5 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -78,6 +78,11 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum,
const char *prefix)
{
unsigned int bitmask;
+ struct net *net = dev_net(in ? in : out);
+
+ /* FIXME: Disabled from containers until syslog ns is supported */
+ if (!net_eq(net, &init_net))
+ return;
spin_lock_bh(&ebt_log_lock);
printk(KERN_SOH "%c%s IN=%s OUT=%s MAC source = %pM MAC dest = %pM proto = 0x%04x",
@@ -176,17 +181,18 @@ ebt_log_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ebt_log_info *info = par->targinfo;
struct nf_loginfo li;
+ struct net *net = dev_net(par->in ? par->in : par->out);
li.type = NF_LOG_TYPE_LOG;
li.u.log.level = info->loglevel;
li.u.log.logflags = info->bitmask;
if (info->bitmask & EBT_LOG_NFLOG)
- nf_log_packet(NFPROTO_BRIDGE, par->hooknum, skb, par->in,
- par->out, &li, "%s", info->prefix);
+ nf_log_packet(net, NFPROTO_BRIDGE, par->hooknum, skb,
+ par->in, par->out, &li, "%s", info->prefix);
else
ebt_log_packet(NFPROTO_BRIDGE, par->hooknum, skb, par->in,
- par->out, &li, info->prefix);
+ par->out, &li, info->prefix);
return EBT_CONTINUE;
}
@@ -206,19 +212,47 @@ static struct nf_logger ebt_log_logger __read_mostly = {
.me = THIS_MODULE,
};
+static int __net_init ebt_log_net_init(struct net *net)
+{
+ nf_log_set(net, NFPROTO_BRIDGE, &ebt_log_logger);
+ return 0;
+}
+
+static void __net_exit ebt_log_net_fini(struct net *net)
+{
+ nf_log_unset(net, &ebt_log_logger);
+}
+
+static struct pernet_operations ebt_log_net_ops = {
+ .init = ebt_log_net_init,
+ .exit = ebt_log_net_fini,
+};
+
static int __init ebt_log_init(void)
{
int ret;
+ ret = register_pernet_subsys(&ebt_log_net_ops);
+ if (ret < 0)
+ goto err_pernet;
+
ret = xt_register_target(&ebt_log_tg_reg);
if (ret < 0)
- return ret;
+ goto err_target;
+
nf_log_register(NFPROTO_BRIDGE, &ebt_log_logger);
- return 0;
+
+ return ret;
+
+err_target:
+ unregister_pernet_subsys(&ebt_log_net_ops);
+err_pernet:
+ return ret;
}
static void __exit ebt_log_fini(void)
{
+ unregister_pernet_subsys(&ebt_log_net_ops);
nf_log_unregister(&ebt_log_logger);
xt_unregister_target(&ebt_log_tg_reg);
}
diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c
index 5be68bbcc341..59ac7952010d 100644
--- a/net/bridge/netfilter/ebt_nflog.c
+++ b/net/bridge/netfilter/ebt_nflog.c
@@ -24,14 +24,15 @@ ebt_nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct ebt_nflog_info *info = par->targinfo;
struct nf_loginfo li;
+ struct net *net = dev_net(par->in ? par->in : par->out);
li.type = NF_LOG_TYPE_ULOG;
li.u.ulog.copy_len = info->len;
li.u.ulog.group = info->group;
li.u.ulog.qthreshold = info->threshold;
- nf_log_packet(PF_BRIDGE, par->hooknum, skb, par->in, par->out,
- &li, "%s", info->prefix);
+ nf_log_packet(net, PF_BRIDGE, par->hooknum, skb, par->in,
+ par->out, &li, "%s", info->prefix);
return EBT_CONTINUE;
}
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 3bf43f7bb9d4..fc1905c51417 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -35,12 +35,13 @@
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/timer.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netdevice.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_ulog.h>
#include <net/netfilter/nf_log.h>
+#include <net/netns/generic.h>
#include <net/sock.h>
#include "../br_private.h"
@@ -62,13 +63,22 @@ typedef struct {
spinlock_t lock; /* the per-queue lock */
} ebt_ulog_buff_t;
-static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS];
-static struct sock *ebtulognl;
+static int ebt_ulog_net_id __read_mostly;
+struct ebt_ulog_net {
+ unsigned int nlgroup[EBT_ULOG_MAXNLGROUPS];
+ ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS];
+ struct sock *ebtulognl;
+};
+
+static struct ebt_ulog_net *ebt_ulog_pernet(struct net *net)
+{
+ return net_generic(net, ebt_ulog_net_id);
+}
/* send one ulog_buff_t to userspace */
-static void ulog_send(unsigned int nlgroup)
+static void ulog_send(struct ebt_ulog_net *ebt, unsigned int nlgroup)
{
- ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup];
+ ebt_ulog_buff_t *ub = &ebt->ulog_buffers[nlgroup];
del_timer(&ub->timer);
@@ -80,7 +90,7 @@ static void ulog_send(unsigned int nlgroup)
ub->lastnlh->nlmsg_type = NLMSG_DONE;
NETLINK_CB(ub->skb).dst_group = nlgroup + 1;
- netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC);
+ netlink_broadcast(ebt->ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC);
ub->qlen = 0;
ub->skb = NULL;
@@ -89,10 +99,15 @@ static void ulog_send(unsigned int nlgroup)
/* timer function to flush queue in flushtimeout time */
static void ulog_timer(unsigned long data)
{
- spin_lock_bh(&ulog_buffers[data].lock);
- if (ulog_buffers[data].skb)
- ulog_send(data);
- spin_unlock_bh(&ulog_buffers[data].lock);
+ struct ebt_ulog_net *ebt = container_of((void *)data,
+ struct ebt_ulog_net,
+ nlgroup[*(unsigned int *)data]);
+
+ ebt_ulog_buff_t *ub = &ebt->ulog_buffers[*(unsigned int *)data];
+ spin_lock_bh(&ub->lock);
+ if (ub->skb)
+ ulog_send(ebt, *(unsigned int *)data);
+ spin_unlock_bh(&ub->lock);
}
static struct sk_buff *ulog_alloc_skb(unsigned int size)
@@ -123,8 +138,10 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
ebt_ulog_packet_msg_t *pm;
size_t size, copy_len;
struct nlmsghdr *nlh;
+ struct net *net = dev_net(in ? in : out);
+ struct ebt_ulog_net *ebt = ebt_ulog_pernet(net);
unsigned int group = uloginfo->nlgroup;
- ebt_ulog_buff_t *ub = &ulog_buffers[group];
+ ebt_ulog_buff_t *ub = &ebt->ulog_buffers[group];
spinlock_t *lock = &ub->lock;
ktime_t kt;
@@ -134,7 +151,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
else
copy_len = uloginfo->cprange;
- size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+ size = nlmsg_total_size(sizeof(*pm) + copy_len);
if (size > nlbufsiz) {
pr_debug("Size %Zd needed, but nlbufsiz=%d\n", size, nlbufsiz);
return;
@@ -146,7 +163,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
if (!(ub->skb = ulog_alloc_skb(size)))
goto unlock;
} else if (size > skb_tailroom(ub->skb)) {
- ulog_send(group);
+ ulog_send(ebt, group);
if (!(ub->skb = ulog_alloc_skb(size)))
goto unlock;
@@ -205,7 +222,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
ub->lastnlh = nlh;
if (ub->qlen >= uloginfo->qthreshold)
- ulog_send(group);
+ ulog_send(ebt, group);
else if (!timer_pending(&ub->timer)) {
ub->timer.expires = jiffies + flushtimeout * HZ / 100;
add_timer(&ub->timer);
@@ -277,56 +294,89 @@ static struct nf_logger ebt_ulog_logger __read_mostly = {
.me = THIS_MODULE,
};
-static int __init ebt_ulog_init(void)
+static int __net_init ebt_ulog_net_init(struct net *net)
{
- int ret;
int i;
+ struct ebt_ulog_net *ebt = ebt_ulog_pernet(net);
+
struct netlink_kernel_cfg cfg = {
.groups = EBT_ULOG_MAXNLGROUPS,
};
- if (nlbufsiz >= 128*1024) {
- pr_warning("Netlink buffer has to be <= 128kB,"
- " please try a smaller nlbufsiz parameter.\n");
- return -EINVAL;
- }
-
/* initialize ulog_buffers */
for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
- setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
- spin_lock_init(&ulog_buffers[i].lock);
+ ebt->nlgroup[i] = i;
+ setup_timer(&ebt->ulog_buffers[i].timer, ulog_timer,
+ (unsigned long)&ebt->nlgroup[i]);
+ spin_lock_init(&ebt->ulog_buffers[i].lock);
}
- ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, &cfg);
- if (!ebtulognl)
- ret = -ENOMEM;
- else if ((ret = xt_register_target(&ebt_ulog_tg_reg)) != 0)
- netlink_kernel_release(ebtulognl);
+ ebt->ebtulognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg);
+ if (!ebt->ebtulognl)
+ return -ENOMEM;
- if (ret == 0)
- nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger);
-
- return ret;
+ nf_log_set(net, NFPROTO_BRIDGE, &ebt_ulog_logger);
+ return 0;
}
-static void __exit ebt_ulog_fini(void)
+static void __net_exit ebt_ulog_net_fini(struct net *net)
{
- ebt_ulog_buff_t *ub;
int i;
+ struct ebt_ulog_net *ebt = ebt_ulog_pernet(net);
- nf_log_unregister(&ebt_ulog_logger);
- xt_unregister_target(&ebt_ulog_tg_reg);
+ nf_log_unset(net, &ebt_ulog_logger);
for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
- ub = &ulog_buffers[i];
+ ebt_ulog_buff_t *ub = &ebt->ulog_buffers[i];
del_timer(&ub->timer);
- spin_lock_bh(&ub->lock);
+
if (ub->skb) {
kfree_skb(ub->skb);
ub->skb = NULL;
}
- spin_unlock_bh(&ub->lock);
}
- netlink_kernel_release(ebtulognl);
+ netlink_kernel_release(ebt->ebtulognl);
+}
+
+static struct pernet_operations ebt_ulog_net_ops = {
+ .init = ebt_ulog_net_init,
+ .exit = ebt_ulog_net_fini,
+ .id = &ebt_ulog_net_id,
+ .size = sizeof(struct ebt_ulog_net),
+};
+
+static int __init ebt_ulog_init(void)
+{
+ int ret;
+
+ if (nlbufsiz >= 128*1024) {
+ pr_warn("Netlink buffer has to be <= 128kB,"
+ "please try a smaller nlbufsiz parameter.\n");
+ return -EINVAL;
+ }
+
+ ret = register_pernet_subsys(&ebt_ulog_net_ops);
+ if (ret)
+ goto out_pernet;
+
+ ret = xt_register_target(&ebt_ulog_tg_reg);
+ if (ret)
+ goto out_target;
+
+ nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger);
+
+ return 0;
+
+out_target:
+ unregister_pernet_subsys(&ebt_ulog_net_ops);
+out_pernet:
+ return ret;
+}
+
+static void __exit ebt_ulog_fini(void)
+{
+ nf_log_unregister(&ebt_ulog_logger);
+ xt_unregister_target(&ebt_ulog_tg_reg);
+ unregister_pernet_subsys(&ebt_ulog_net_ops);
}
module_init(ebt_ulog_init);
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 40d8258bf74f..70f656ce0f4a 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -64,9 +64,7 @@ static int ebt_broute(struct sk_buff *skb)
static int __net_init broute_net_init(struct net *net)
{
net->xt.broute_table = ebt_register_table(net, &broute_table);
- if (IS_ERR(net->xt.broute_table))
- return PTR_ERR(net->xt.broute_table);
- return 0;
+ return PTR_RET(net->xt.broute_table);
}
static void __net_exit broute_net_exit(struct net *net)
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 8d493c91a562..3d110c4fc787 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -138,7 +138,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
ethproto = h->h_proto;
if (e->bitmask & EBT_802_3) {
- if (FWINV2(ntohs(ethproto) >= 1536, EBT_IPROTO))
+ if (FWINV2(ntohs(ethproto) >= ETH_P_802_3_MIN, EBT_IPROTO))
return 1;
} else if (!(e->bitmask & EBT_NOPROTO) &&
FWINV2(e->ethproto != ethproto, EBT_IPROTO))
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
index 21760f008974..1f9ece1a9c34 100644
--- a/net/caif/caif_dev.c
+++ b/net/caif/caif_dev.c
@@ -1,7 +1,7 @@
/*
* CAIF Interface registration.
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*
* Borrowed heavily from file: pn_dev.c. Thanks to Remi Denis-Courmont
@@ -301,10 +301,11 @@ static void dev_flowctrl(struct net_device *dev, int on)
}
void caif_enroll_dev(struct net_device *dev, struct caif_dev_common *caifdev,
- struct cflayer *link_support, int head_room,
- struct cflayer **layer, int (**rcv_func)(
- struct sk_buff *, struct net_device *,
- struct packet_type *, struct net_device *))
+ struct cflayer *link_support, int head_room,
+ struct cflayer **layer,
+ int (**rcv_func)(struct sk_buff *, struct net_device *,
+ struct packet_type *,
+ struct net_device *))
{
struct caif_device_entry *caifd;
enum cfcnfg_phy_preference pref;
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 095259f83902..05a41c7ec304 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -197,8 +197,8 @@ static void cfsk_put(struct cflayer *layr)
/* Packet Control Callback function called from CAIF */
static void caif_ctrl_cb(struct cflayer *layr,
- enum caif_ctrlcmd flow,
- int phyid)
+ enum caif_ctrlcmd flow,
+ int phyid)
{
struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
switch (flow) {
@@ -274,7 +274,7 @@ static void caif_check_flow_release(struct sock *sk)
* changed locking, address handling and added MSG_TRUNC.
*/
static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *m, size_t len, int flags)
+ struct msghdr *m, size_t len, int flags)
{
struct sock *sk = sock->sk;
@@ -286,6 +286,8 @@ static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
if (m->msg_flags&MSG_OOB)
goto read_error;
+ m->msg_namelen = 0;
+
skb = skb_recv_datagram(sk, flags, 0 , &ret);
if (!skb)
goto read_error;
@@ -346,8 +348,8 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
* changed locking calls, changed address handling.
*/
static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size,
- int flags)
+ struct msghdr *msg, size_t size,
+ int flags)
{
struct sock *sk = sock->sk;
int copied = 0;
@@ -462,7 +464,7 @@ out:
* CAIF flow-on and sock_writable.
*/
static long caif_wait_for_flow_on(struct caifsock *cf_sk,
- int wait_writeable, long timeo, int *err)
+ int wait_writeable, long timeo, int *err)
{
struct sock *sk = &cf_sk->sk;
DEFINE_WAIT(wait);
@@ -516,7 +518,7 @@ static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
/* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */
static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, size_t len)
+ struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
@@ -591,7 +593,7 @@ err:
* and other minor adaptations.
*/
static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
- struct msghdr *msg, size_t len)
+ struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
@@ -670,7 +672,7 @@ out_err:
}
static int setsockopt(struct socket *sock,
- int lvl, int opt, char __user *ov, unsigned int ol)
+ int lvl, int opt, char __user *ov, unsigned int ol)
{
struct sock *sk = sock->sk;
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
@@ -932,7 +934,7 @@ static int caif_release(struct socket *sock)
/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */
static unsigned int caif_poll(struct file *file,
- struct socket *sock, poll_table *wait)
+ struct socket *sock, poll_table *wait)
{
struct sock *sk = sock->sk;
unsigned int mask;
@@ -1022,7 +1024,7 @@ static void caif_sock_destructor(struct sock *sk)
}
static int caif_create(struct net *net, struct socket *sock, int protocol,
- int kern)
+ int kern)
{
struct sock *sk = NULL;
struct caifsock *cf_sk = NULL;
diff --git a/net/caif/caif_usb.c b/net/caif/caif_usb.c
index ef8ebaa993cf..942e00a425fd 100644
--- a/net/caif/caif_usb.c
+++ b/net/caif/caif_usb.c
@@ -1,7 +1,7 @@
/*
* CAIF USB handler
* Copyright (C) ST-Ericsson AB 2011
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*
*/
@@ -75,7 +75,7 @@ static int cfusbl_transmit(struct cflayer *layr, struct cfpkt *pkt)
}
static void cfusbl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
if (layr->up && layr->up->ctrlcmd)
layr->up->ctrlcmd(layr->up, ctrl, layr->id);
@@ -121,7 +121,7 @@ static struct packet_type caif_usb_type __read_mostly = {
};
static int cfusbl_device_notify(struct notifier_block *me, unsigned long what,
- void *arg)
+ void *arg)
{
struct net_device *dev = arg;
struct caif_dev_common common;
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index f1dbddb95a6c..fa39fc298708 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -61,11 +61,11 @@ struct cfcnfg {
};
static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
- enum cfctrl_srv serv, u8 phyid,
- struct cflayer *adapt_layer);
+ enum cfctrl_srv serv, u8 phyid,
+ struct cflayer *adapt_layer);
static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
- struct cflayer *adapt_layer);
+ struct cflayer *adapt_layer);
static void cfctrl_resp_func(void);
static void cfctrl_enum_resp(void);
@@ -131,7 +131,7 @@ static void cfctrl_resp_func(void)
}
static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo_rcu(struct cfcnfg *cnfg,
- u8 phyid)
+ u8 phyid)
{
struct cfcnfg_phyinfo *phy;
@@ -216,8 +216,8 @@ static const int protohead[CFCTRL_SRV_MASK] = {
static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
- struct caif_connect_request *s,
- struct cfctrl_link_param *l)
+ struct caif_connect_request *s,
+ struct cfctrl_link_param *l)
{
struct dev_info *dev_info;
enum cfcnfg_phy_preference pref;
@@ -301,8 +301,7 @@ static int caif_connect_req_to_link_param(struct cfcnfg *cnfg,
int caif_connect_client(struct net *net, struct caif_connect_request *conn_req,
struct cflayer *adap_layer, int *ifindex,
- int *proto_head,
- int *proto_tail)
+ int *proto_head, int *proto_tail)
{
struct cflayer *frml;
struct cfcnfg_phyinfo *phy;
@@ -364,7 +363,7 @@ unlock:
EXPORT_SYMBOL(caif_connect_client);
static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
- struct cflayer *adapt_layer)
+ struct cflayer *adapt_layer)
{
if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
adapt_layer->ctrlcmd(adapt_layer,
@@ -526,7 +525,7 @@ out_err:
EXPORT_SYMBOL(cfcnfg_add_phy_layer);
int cfcnfg_set_phy_state(struct cfcnfg *cnfg, struct cflayer *phy_layer,
- bool up)
+ bool up)
{
struct cfcnfg_phyinfo *phyinfo;
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
index a376ec1ac0a7..2bd4b58f4372 100644
--- a/net/caif/cfctrl.c
+++ b/net/caif/cfctrl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -20,12 +20,12 @@
#ifdef CAIF_NO_LOOP
static int handle_loop(struct cfctrl *ctrl,
- int cmd, struct cfpkt *pkt){
+ int cmd, struct cfpkt *pkt){
return -1;
}
#else
static int handle_loop(struct cfctrl *ctrl,
- int cmd, struct cfpkt *pkt);
+ int cmd, struct cfpkt *pkt);
#endif
static int cfctrl_recv(struct cflayer *layr, struct cfpkt *pkt);
static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
@@ -72,7 +72,7 @@ void cfctrl_remove(struct cflayer *layer)
}
static bool param_eq(const struct cfctrl_link_param *p1,
- const struct cfctrl_link_param *p2)
+ const struct cfctrl_link_param *p2)
{
bool eq =
p1->linktype == p2->linktype &&
@@ -197,8 +197,8 @@ void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
}
int cfctrl_linkup_request(struct cflayer *layer,
- struct cfctrl_link_param *param,
- struct cflayer *user_layer)
+ struct cfctrl_link_param *param,
+ struct cflayer *user_layer)
{
struct cfctrl *cfctrl = container_obj(layer);
u32 tmp32;
@@ -301,7 +301,7 @@ int cfctrl_linkup_request(struct cflayer *layer,
}
int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
- struct cflayer *client)
+ struct cflayer *client)
{
int ret;
struct cfpkt *pkt;
@@ -555,7 +555,7 @@ error:
}
static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
struct cfctrl *this = container_obj(layr);
switch (ctrl) {
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index 2914659eb9b2..7aae0b56829e 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index a63f4a5f5aff..3bdddb32d55a 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
index 0a7df7ef062d..8bc7caa28e64 100644
--- a/net/caif/cffrml.c
+++ b/net/caif/cffrml.c
@@ -2,7 +2,7 @@
* CAIF Framing Layer.
*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -28,7 +28,7 @@ struct cffrml {
static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt);
static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid);
+ int phyid);
static u32 cffrml_rcv_error;
static u32 cffrml_rcv_checsum_error;
@@ -167,7 +167,7 @@ static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
}
static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
if (layr->up && layr->up->ctrlcmd)
layr->up->ctrlcmd(layr->up, ctrl, layr->id);
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
index 94b08612a4d8..8c5d6386319f 100644
--- a/net/caif/cfmuxl.c
+++ b/net/caif/cfmuxl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -42,7 +42,7 @@ struct cfmuxl {
static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt);
static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid);
+ int phyid);
static struct cflayer *get_up(struct cfmuxl *muxl, u16 id);
struct cflayer *cfmuxl_create(void)
@@ -244,7 +244,7 @@ static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
}
static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
struct cfmuxl *muxl = container_obj(layr);
struct cflayer *layer;
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
index 863dedd91bb6..6493351f39c6 100644
--- a/net/caif/cfpkt_skbuff.c
+++ b/net/caif/cfpkt_skbuff.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -266,8 +266,8 @@ inline u16 cfpkt_getlen(struct cfpkt *pkt)
}
inline u16 cfpkt_iterate(struct cfpkt *pkt,
- u16 (*iter_func)(u16, void *, u16),
- u16 data)
+ u16 (*iter_func)(u16, void *, u16),
+ u16 data)
{
/*
* Don't care about the performance hit of linearizing,
@@ -307,8 +307,8 @@ int cfpkt_setlen(struct cfpkt *pkt, u16 len)
}
struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
- struct cfpkt *addpkt,
- u16 expectlen)
+ struct cfpkt *addpkt,
+ u16 expectlen)
{
struct sk_buff *dst = pkt_to_skb(dstpkt);
struct sk_buff *add = pkt_to_skb(addpkt);
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
index 2b563ad04597..61d7617d9249 100644
--- a/net/caif/cfrfml.c
+++ b/net/caif/cfrfml.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -43,7 +43,7 @@ static void cfrfml_release(struct cflayer *layer)
}
struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
- int mtu_size)
+ int mtu_size)
{
int tmp;
struct cfrfml *this = kzalloc(sizeof(struct cfrfml), GFP_ATOMIC);
@@ -69,7 +69,7 @@ struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info,
}
static struct cfpkt *rfm_append(struct cfrfml *rfml, char *seghead,
- struct cfpkt *pkt, int *err)
+ struct cfpkt *pkt, int *err)
{
struct cfpkt *tmppkt;
*err = -EPROTO;
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index 8e68b97f13ee..ce60f06d76de 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -29,7 +29,7 @@ struct cfserl {
static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt);
static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt);
static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid);
+ int phyid);
struct cflayer *cfserl_create(int instance, bool use_stx)
{
@@ -182,7 +182,7 @@ static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt)
}
static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
layr->up->ctrlcmd(layr->up, ctrl, phyid);
}
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index ba217e90765e..353f793d1b3b 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
@@ -25,7 +25,7 @@
#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
- int phyid)
+ int phyid)
{
struct cfsrvl *service = container_obj(layr);
@@ -158,10 +158,9 @@ static void cfsrvl_release(struct cflayer *layer)
}
void cfsrvl_init(struct cfsrvl *service,
- u8 channel_id,
- struct dev_info *dev_info,
- bool supports_flowctrl
- )
+ u8 channel_id,
+ struct dev_info *dev_info,
+ bool supports_flowctrl)
{
caif_assert(offsetof(struct cfsrvl, layer) == 0);
service->open = false;
@@ -207,8 +206,8 @@ void caif_free_client(struct cflayer *adap_layer)
EXPORT_SYMBOL(caif_free_client);
void caif_client_register_refcnt(struct cflayer *adapt_layer,
- void (*hold)(struct cflayer *lyr),
- void (*put)(struct cflayer *lyr))
+ void (*hold)(struct cflayer *lyr),
+ void (*put)(struct cflayer *lyr))
{
struct cfsrvl *service;
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 86d2dadb4b73..1728fa4471cf 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
index 910ab0661f66..262224581efa 100644
--- a/net/caif/cfveil.c
+++ b/net/caif/cfveil.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index a8e2a2d758a5..b3b110e8a350 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Author: Sjur Brendeland/sjur.brandeland@stericsson.com
+ * Author: Sjur Brendeland
* License terms: GNU General Public License (GPL) version 2
*/
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index e597733affb8..7344a8fa1bb0 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) ST-Ericsson AB 2010
- * Authors: Sjur Brendeland/sjur.brandeland@stericsson.com
- * Daniel Martensson / Daniel.Martensson@stericsson.com
+ * Authors: Sjur Brendeland
+ * Daniel Martensson
* License terms: GNU General Public License (GPL) version 2
*/
@@ -167,7 +167,7 @@ static void chnl_put(struct cflayer *lyr)
}
static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
- int phyid)
+ int phyid)
{
struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
pr_debug("NET flowctrl func called flow: %s\n",
@@ -443,7 +443,7 @@ nla_put_failure:
}
static void caif_netlink_parms(struct nlattr *data[],
- struct caif_connect_request *conn_req)
+ struct caif_connect_request *conn_req)
{
if (!data) {
pr_warn("no params data found\n");
@@ -488,7 +488,7 @@ static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
}
static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[])
+ struct nlattr *data[])
{
struct chnl_net *caifdev;
ASSERT_RTNL();
diff --git a/net/can/af_can.c b/net/can/af_can.c
index c48e5220bbac..c4e50852c9f4 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -525,7 +525,7 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
d = find_dev_rcv_lists(dev);
if (!d) {
- printk(KERN_ERR "BUG: receive list not found for "
+ pr_err("BUG: receive list not found for "
"dev %s, id %03X, mask %03X\n",
DNAME(dev), can_id, mask);
goto out;
@@ -546,16 +546,13 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
}
/*
- * Check for bugs in CAN protocol implementations:
- * If no matching list item was found, the list cursor variable next
- * will be NULL, while r will point to the last item of the list.
+ * Check for bugs in CAN protocol implementations using af_can.c:
+ * 'r' will be NULL if no matching list item was found for removal.
*/
if (!r) {
- printk(KERN_ERR "BUG: receive list entry not found for "
- "dev %s, id %03X, mask %03X\n",
- DNAME(dev), can_id, mask);
- r = NULL;
+ WARN(1, "BUG: receive list entry not found for dev %s, "
+ "id %03X, mask %03X\n", DNAME(dev), can_id, mask);
goto out;
}
@@ -749,8 +746,7 @@ int can_proto_register(const struct can_proto *cp)
int err = 0;
if (proto < 0 || proto >= CAN_NPROTO) {
- printk(KERN_ERR "can: protocol number %d out of range\n",
- proto);
+ pr_err("can: protocol number %d out of range\n", proto);
return -EINVAL;
}
@@ -761,8 +757,7 @@ int can_proto_register(const struct can_proto *cp)
mutex_lock(&proto_tab_lock);
if (proto_tab[proto]) {
- printk(KERN_ERR "can: protocol %d already registered\n",
- proto);
+ pr_err("can: protocol %d already registered\n", proto);
err = -EBUSY;
} else
RCU_INIT_POINTER(proto_tab[proto], cp);
@@ -816,11 +811,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
/* create new dev_rcv_lists for this device */
d = kzalloc(sizeof(*d), GFP_KERNEL);
- if (!d) {
- printk(KERN_ERR
- "can: allocation of receive list failed\n");
+ if (!d)
return NOTIFY_DONE;
- }
BUG_ON(dev->ml_priv);
dev->ml_priv = d;
@@ -838,8 +830,8 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
dev->ml_priv = NULL;
}
} else
- printk(KERN_ERR "can: notifier: receive list not "
- "found for dev %s\n", dev->name);
+ pr_err("can: notifier: receive list not found for dev "
+ "%s\n", dev->name);
spin_unlock(&can_rcvlists_lock);
@@ -927,7 +919,7 @@ static __exit void can_exit(void)
/* remove created dev_rcv_lists from still registered CAN devices */
rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) {
- if (dev->type == ARPHRD_CAN && dev->ml_priv){
+ if (dev->type == ARPHRD_CAN && dev->ml_priv) {
struct dev_rcv_lists *d = dev->ml_priv;
diff --git a/net/can/gw.c b/net/can/gw.c
index 2d117dc5ebea..3ee690e8c7d3 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -466,7 +466,7 @@ static int cgw_notifier(struct notifier_block *nb,
if (gwj->src.dev == dev || gwj->dst.dev == dev) {
hlist_del(&gwj->list);
cgw_unregister_filter(gwj);
- kfree(gwj);
+ kmem_cache_free(cgw_cache, gwj);
}
}
}
@@ -778,8 +778,7 @@ static int cgw_parse_attr(struct nlmsghdr *nlh, struct cf_mod *mod,
return 0;
}
-static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
- void *arg)
+static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct rtcanmsg *r;
struct cgw_job *gwj;
@@ -864,11 +863,11 @@ static void cgw_remove_all_jobs(void)
hlist_for_each_entry_safe(gwj, nx, &cgw_list, list) {
hlist_del(&gwj->list);
cgw_unregister_filter(gwj);
- kfree(gwj);
+ kmem_cache_free(cgw_cache, gwj);
}
}
-static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct cgw_job *gwj = NULL;
struct hlist_node *nx;
@@ -920,7 +919,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
hlist_del(&gwj->list);
cgw_unregister_filter(gwj);
- kfree(gwj);
+ kmem_cache_free(cgw_cache, gwj);
err = 0;
break;
}
diff --git a/net/can/raw.c b/net/can/raw.c
index c1764e41ddaf..1085e65f848e 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -711,9 +711,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0)
goto free_skb;
- err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
- if (err < 0)
- goto free_skb;
+
+ sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
skb->dev = dev;
skb->sk = sk;
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 368f9c3f9dc6..b71423db7785 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -78,9 +78,10 @@ static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int syn
return autoremove_wake_function(wait, mode, sync, key);
}
/*
- * Wait for a packet..
+ * Wait for the last received packet to be different from skb
*/
-static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
+static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p,
+ const struct sk_buff *skb)
{
int error;
DEFINE_WAIT_FUNC(wait, receiver_wake_function);
@@ -92,7 +93,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
if (error)
goto out_err;
- if (!skb_queue_empty(&sk->sk_receive_queue))
+ if (sk->sk_receive_queue.prev != skb)
goto out;
/* Socket shut down? */
@@ -131,9 +132,9 @@ out_noerr:
* __skb_recv_datagram - Receive a datagram skbuff
* @sk: socket
* @flags: MSG_ flags
+ * @peeked: returns non-zero if this packet has been seen before
* @off: an offset in bytes to peek skb from. Returns an offset
* within an skb where data actually starts
- * @peeked: returns non-zero if this packet has been seen before
* @err: error code returned
*
* Get a datagram skbuff, understands the peeking, nonblocking wakeups
@@ -161,7 +162,7 @@ out_noerr:
struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
int *peeked, int *off, int *err)
{
- struct sk_buff *skb;
+ struct sk_buff *skb, *last;
long timeo;
/*
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
@@ -182,13 +183,17 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
*/
unsigned long cpu_flags;
struct sk_buff_head *queue = &sk->sk_receive_queue;
+ int _off = *off;
+ last = (struct sk_buff *)queue;
spin_lock_irqsave(&queue->lock, cpu_flags);
skb_queue_walk(queue, skb) {
+ last = skb;
*peeked = skb->peeked;
if (flags & MSG_PEEK) {
- if (*off >= skb->len && skb->len) {
- *off -= skb->len;
+ if (_off >= skb->len && (skb->len || _off ||
+ skb->peeked)) {
+ _off -= skb->len;
continue;
}
skb->peeked = 1;
@@ -197,6 +202,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
__skb_unlink(skb, queue);
spin_unlock_irqrestore(&queue->lock, cpu_flags);
+ *off = _off;
return skb;
}
spin_unlock_irqrestore(&queue->lock, cpu_flags);
@@ -206,7 +212,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
if (!timeo)
goto no_packet;
- } while (!wait_for_packet(sk, err, &timeo));
+ } while (!wait_for_more_packets(sk, err, &timeo, last));
return NULL;
@@ -749,7 +755,9 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
/* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
+
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
diff --git a/net/core/dev.c b/net/core/dev.c
index b13e5c766c11..4040673f806a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -200,7 +200,7 @@ static inline void rps_unlock(struct softnet_data *sd)
}
/* Device list insertion */
-static int list_netdevice(struct net_device *dev)
+static void list_netdevice(struct net_device *dev)
{
struct net *net = dev_net(dev);
@@ -214,8 +214,6 @@ static int list_netdevice(struct net_device *dev)
write_unlock_bh(&dev_base_lock);
dev_base_seq_inc(net);
-
- return 0;
}
/* Device list removal
@@ -1624,7 +1622,6 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
}
skb_orphan(skb);
- nf_reset(skb);
if (unlikely(!is_skb_forwardable(dev, skb))) {
atomic_long_inc(&dev->rx_dropped);
@@ -1640,6 +1637,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
skb->mark = 0;
secpath_reset(skb);
nf_reset(skb);
+ nf_reset_trace(skb);
return netif_rx(skb);
}
EXPORT_SYMBOL_GPL(dev_forward_skb);
@@ -2148,6 +2146,9 @@ static void skb_warn_bad_offload(const struct sk_buff *skb)
struct net_device *dev = skb->dev;
const char *driver = "";
+ if (!net_ratelimit())
+ return;
+
if (dev && dev->dev.parent)
driver = dev_driver_string(dev->dev.parent);
@@ -2207,30 +2208,40 @@ out:
}
EXPORT_SYMBOL(skb_checksum_help);
-/**
- * skb_mac_gso_segment - mac layer segmentation handler.
- * @skb: buffer to segment
- * @features: features for the output path (see dev->features)
- */
-struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
- netdev_features_t features)
+__be16 skb_network_protocol(struct sk_buff *skb)
{
- struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
- struct packet_offload *ptype;
__be16 type = skb->protocol;
int vlan_depth = ETH_HLEN;
- while (type == htons(ETH_P_8021Q)) {
+ while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
struct vlan_hdr *vh;
if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
- return ERR_PTR(-EINVAL);
+ return 0;
vh = (struct vlan_hdr *)(skb->data + vlan_depth);
type = vh->h_vlan_encapsulated_proto;
vlan_depth += VLAN_HLEN;
}
+ return type;
+}
+
+/**
+ * skb_mac_gso_segment - mac layer segmentation handler.
+ * @skb: buffer to segment
+ * @features: features for the output path (see dev->features)
+ */
+struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+ struct packet_offload *ptype;
+ __be16 type = skb_network_protocol(skb);
+
+ if (unlikely(!type))
+ return ERR_PTR(-EINVAL);
+
__skb_pull(skb, skb->mac_len);
rcu_read_lock();
@@ -2397,24 +2408,12 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
return 0;
}
-static bool can_checksum_protocol(netdev_features_t features, __be16 protocol)
-{
- return ((features & NETIF_F_GEN_CSUM) ||
- ((features & NETIF_F_V4_CSUM) &&
- protocol == htons(ETH_P_IP)) ||
- ((features & NETIF_F_V6_CSUM) &&
- protocol == htons(ETH_P_IPV6)) ||
- ((features & NETIF_F_FCOE_CRC) &&
- protocol == htons(ETH_P_FCOE)));
-}
-
static netdev_features_t harmonize_features(struct sk_buff *skb,
__be16 protocol, netdev_features_t features)
{
if (skb->ip_summed != CHECKSUM_NONE &&
!can_checksum_protocol(features, protocol)) {
features &= ~NETIF_F_ALL_CSUM;
- features &= ~NETIF_F_SG;
} else if (illegal_highdma(skb->dev, skb)) {
features &= ~NETIF_F_SG;
}
@@ -2430,20 +2429,22 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
features &= ~NETIF_F_GSO_MASK;
- if (protocol == htons(ETH_P_8021Q)) {
+ if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
protocol = veh->h_vlan_encapsulated_proto;
} else if (!vlan_tx_tag_present(skb)) {
return harmonize_features(skb, protocol, features);
}
- features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_TX);
+ features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX);
- if (protocol != htons(ETH_P_8021Q)) {
+ if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD)) {
return harmonize_features(skb, protocol, features);
} else {
features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
- NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_TX;
+ NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_STAG_TX;
return harmonize_features(skb, protocol, features);
}
}
@@ -2484,8 +2485,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
features = netif_skb_features(skb);
if (vlan_tx_tag_present(skb) &&
- !(features & NETIF_F_HW_VLAN_TX)) {
- skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+ !vlan_hw_offload_capable(features, skb->vlan_proto)) {
+ skb = __vlan_put_tag(skb, skb->vlan_proto,
+ vlan_tx_tag_get(skb));
if (unlikely(!skb))
goto out;
@@ -2544,13 +2546,6 @@ gso:
skb->next = nskb->next;
nskb->next = NULL;
- /*
- * If device doesn't need nskb->dst, release it right now while
- * its hot in this cpu cache
- */
- if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
- skb_dst_drop(nskb);
-
if (!list_empty(&ptype_all))
dev_queue_xmit_nit(nskb, dev);
@@ -2570,8 +2565,11 @@ gso:
} while (skb->next);
out_kfree_gso_skb:
- if (likely(skb->next == NULL))
+ if (likely(skb->next == NULL)) {
skb->destructor = DEV_GSO_CB(skb)->destructor;
+ consume_skb(skb);
+ return rc;
+ }
out_kfree_skb:
kfree_skb(skb);
out:
@@ -2589,6 +2587,7 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
*/
if (shinfo->gso_size) {
unsigned int hdr_len;
+ u16 gso_segs = shinfo->gso_segs;
/* mac layer + network layer */
hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
@@ -2598,7 +2597,12 @@ static void qdisc_pkt_len_init(struct sk_buff *skb)
hdr_len += tcp_hdrlen(skb);
else
hdr_len += sizeof(struct udphdr);
- qdisc_skb_cb(skb)->pkt_len += (shinfo->gso_segs - 1) * hdr_len;
+
+ if (shinfo->gso_type & SKB_GSO_DODGY)
+ gso_segs = DIV_ROUND_UP(skb->len - hdr_len,
+ shinfo->gso_size);
+
+ qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len;
}
}
@@ -3314,6 +3318,7 @@ int netdev_rx_handler_register(struct net_device *dev,
if (dev->rx_handler)
return -EBUSY;
+ /* Note: rx_handler_data must be set before rx_handler */
rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
rcu_assign_pointer(dev->rx_handler, rx_handler);
@@ -3325,7 +3330,7 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_register);
* netdev_rx_handler_unregister - unregister receive handler
* @dev: device to unregister a handler from
*
- * Unregister a receive hander from a device.
+ * Unregister a receive handler from a device.
*
* The caller must hold the rtnl_mutex.
*/
@@ -3334,6 +3339,11 @@ void netdev_rx_handler_unregister(struct net_device *dev)
ASSERT_RTNL();
RCU_INIT_POINTER(dev->rx_handler, NULL);
+ /* a reader seeing a non NULL rx_handler in a rcu_read_lock()
+ * section has a guarantee to see a non NULL rx_handler_data
+ * as well.
+ */
+ synchronize_net();
RCU_INIT_POINTER(dev->rx_handler_data, NULL);
}
EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
@@ -3349,6 +3359,7 @@ static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
case __constant_htons(ETH_P_IP):
case __constant_htons(ETH_P_IPV6):
case __constant_htons(ETH_P_8021Q):
+ case __constant_htons(ETH_P_8021AD):
return true;
default:
return false;
@@ -3389,7 +3400,8 @@ another_round:
__this_cpu_inc(softnet_data.processed);
- if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
+ if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
+ skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
skb = vlan_untag(skb);
if (unlikely(!skb))
goto unlock;
@@ -4057,6 +4069,9 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
napi->gro_list = NULL;
napi->skb = NULL;
napi->poll = poll;
+ if (weight > NAPI_POLL_WEIGHT)
+ pr_err_once("netif_napi_add() called with weight %d on device %s\n",
+ weight, dev->name);
napi->weight = weight;
list_add(&napi->dev_list, &dev->napi_list);
napi->dev = dev;
@@ -4918,20 +4933,25 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
}
- /* Fix illegal SG+CSUM combinations. */
- if ((features & NETIF_F_SG) &&
- !(features & NETIF_F_ALL_CSUM)) {
- netdev_dbg(dev,
- "Dropping NETIF_F_SG since no checksum feature.\n");
- features &= ~NETIF_F_SG;
- }
-
/* TSO requires that SG is present as well. */
if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) {
netdev_dbg(dev, "Dropping TSO features since no SG feature.\n");
features &= ~NETIF_F_ALL_TSO;
}
+ if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) &&
+ !(features & NETIF_F_IP_CSUM)) {
+ netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n");
+ features &= ~NETIF_F_TSO;
+ features &= ~NETIF_F_TSO_ECN;
+ }
+
+ if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) &&
+ !(features & NETIF_F_IPV6_CSUM)) {
+ netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n");
+ features &= ~NETIF_F_TSO6;
+ }
+
/* TSO ECN requires that TSO is present as well. */
if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN)
features &= ~NETIF_F_TSO_ECN;
@@ -5162,7 +5182,8 @@ int register_netdevice(struct net_device *dev)
}
}
- if (((dev->hw_features | dev->features) & NETIF_F_HW_VLAN_FILTER) &&
+ if (((dev->hw_features | dev->features) &
+ NETIF_F_HW_VLAN_CTAG_FILTER) &&
(!dev->netdev_ops->ndo_vlan_rx_add_vid ||
!dev->netdev_ops->ndo_vlan_rx_kill_vid)) {
netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n");
@@ -5199,6 +5220,10 @@ int register_netdevice(struct net_device *dev)
*/
dev->vlan_features |= NETIF_F_HIGHDMA;
+ /* Make NETIF_F_SG inheritable to tunnel devices.
+ */
+ dev->hw_enc_features |= NETIF_F_SG;
+
ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
ret = notifier_to_errno(ret);
if (ret)
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index bd2eb9d3e369..c013f38482a1 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -22,7 +22,8 @@
static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
- unsigned char addr_type, bool global)
+ unsigned char addr_type, bool global,
+ bool sync)
{
struct netdev_hw_addr *ha;
int alloc_size;
@@ -37,7 +38,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
ha->type = addr_type;
ha->refcount = 1;
ha->global_use = global;
- ha->synced = false;
+ ha->synced = sync;
list_add_tail_rcu(&ha->list, &list->list);
list->count++;
@@ -46,7 +47,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
- unsigned char addr_type, bool global)
+ unsigned char addr_type, bool global, bool sync)
{
struct netdev_hw_addr *ha;
@@ -63,43 +64,62 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
else
ha->global_use = true;
}
+ if (sync) {
+ if (ha->synced)
+ return 0;
+ else
+ ha->synced = true;
+ }
ha->refcount++;
return 0;
}
}
- return __hw_addr_create_ex(list, addr, addr_len, addr_type, global);
+ return __hw_addr_create_ex(list, addr, addr_len, addr_type, global,
+ sync);
}
static int __hw_addr_add(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
unsigned char addr_type)
{
- return __hw_addr_add_ex(list, addr, addr_len, addr_type, false);
+ return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false);
+}
+
+static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
+ struct netdev_hw_addr *ha, bool global,
+ bool sync)
+{
+ if (global && !ha->global_use)
+ return -ENOENT;
+
+ if (sync && !ha->synced)
+ return -ENOENT;
+
+ if (global)
+ ha->global_use = false;
+
+ if (sync)
+ ha->synced = false;
+
+ if (--ha->refcount)
+ return 0;
+ list_del_rcu(&ha->list);
+ kfree_rcu(ha, rcu_head);
+ list->count--;
+ return 0;
}
static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
- unsigned char addr_type, bool global)
+ unsigned char addr_type, bool global, bool sync)
{
struct netdev_hw_addr *ha;
list_for_each_entry(ha, &list->list, list) {
if (!memcmp(ha->addr, addr, addr_len) &&
- (ha->type == addr_type || !addr_type)) {
- if (global) {
- if (!ha->global_use)
- break;
- else
- ha->global_use = false;
- }
- if (--ha->refcount)
- return 0;
- list_del_rcu(&ha->list);
- kfree_rcu(ha, rcu_head);
- list->count--;
- return 0;
- }
+ (ha->type == addr_type || !addr_type))
+ return __hw_addr_del_entry(list, ha, global, sync);
}
return -ENOENT;
}
@@ -108,7 +128,57 @@ static int __hw_addr_del(struct netdev_hw_addr_list *list,
const unsigned char *addr, int addr_len,
unsigned char addr_type)
{
- return __hw_addr_del_ex(list, addr, addr_len, addr_type, false);
+ return __hw_addr_del_ex(list, addr, addr_len, addr_type, false, false);
+}
+
+static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list,
+ struct netdev_hw_addr *ha,
+ int addr_len)
+{
+ int err;
+
+ err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type,
+ false, true);
+ if (err)
+ return err;
+ ha->sync_cnt++;
+ ha->refcount++;
+
+ return 0;
+}
+
+static void __hw_addr_unsync_one(struct netdev_hw_addr_list *to_list,
+ struct netdev_hw_addr_list *from_list,
+ struct netdev_hw_addr *ha,
+ int addr_len)
+{
+ int err;
+
+ err = __hw_addr_del_ex(to_list, ha->addr, addr_len, ha->type,
+ false, true);
+ if (err)
+ return;
+ ha->sync_cnt--;
+ __hw_addr_del_entry(from_list, ha, false, true);
+}
+
+static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list,
+ struct netdev_hw_addr_list *from_list,
+ int addr_len)
+{
+ int err = 0;
+ struct netdev_hw_addr *ha, *tmp;
+
+ list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
+ if (ha->sync_cnt == ha->refcount) {
+ __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
+ } else {
+ err = __hw_addr_sync_one(to_list, ha, addr_len);
+ if (err)
+ break;
+ }
+ }
+ return err;
}
int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
@@ -152,6 +222,11 @@ void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
}
EXPORT_SYMBOL(__hw_addr_del_multiple);
+/* This function only works where there is a strict 1-1 relationship
+ * between source and destionation of they synch. If you ever need to
+ * sync addresses to more then 1 destination, you need to use
+ * __hw_addr_sync_multiple().
+ */
int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
struct netdev_hw_addr_list *from_list,
int addr_len)
@@ -160,17 +235,12 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
struct netdev_hw_addr *ha, *tmp;
list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
- if (!ha->synced) {
- err = __hw_addr_add(to_list, ha->addr,
- addr_len, ha->type);
+ if (!ha->sync_cnt) {
+ err = __hw_addr_sync_one(to_list, ha, addr_len);
if (err)
break;
- ha->synced = true;
- ha->refcount++;
- } else if (ha->refcount == 1) {
- __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
- __hw_addr_del(from_list, ha->addr, addr_len, ha->type);
- }
+ } else if (ha->refcount == 1)
+ __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
}
return err;
}
@@ -183,13 +253,8 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
struct netdev_hw_addr *ha, *tmp;
list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
- if (ha->synced) {
- __hw_addr_del(to_list, ha->addr,
- addr_len, ha->type);
- ha->synced = false;
- __hw_addr_del(from_list, ha->addr,
- addr_len, ha->type);
- }
+ if (ha->sync_cnt)
+ __hw_addr_unsync_one(to_list, from_list, ha, addr_len);
}
}
EXPORT_SYMBOL(__hw_addr_unsync);
@@ -406,7 +471,7 @@ int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr)
}
}
err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len,
- NETDEV_HW_ADDR_T_UNICAST, true);
+ NETDEV_HW_ADDR_T_UNICAST, true, false);
if (!err)
__dev_set_rx_mode(dev);
out:
@@ -469,7 +534,8 @@ EXPORT_SYMBOL(dev_uc_del);
* locked by netif_addr_lock_bh.
*
* This function is intended to be called from the dev->set_rx_mode
- * function of layered software devices.
+ * function of layered software devices. This function assumes that
+ * addresses will only ever be synced to the @to devices and no other.
*/
int dev_uc_sync(struct net_device *to, struct net_device *from)
{
@@ -488,6 +554,36 @@ int dev_uc_sync(struct net_device *to, struct net_device *from)
EXPORT_SYMBOL(dev_uc_sync);
/**
+ * dev_uc_sync_multiple - Synchronize device's unicast list to another
+ * device, but allow for multiple calls to sync to multiple devices.
+ * @to: destination device
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+ * addresses that have been deleted from the source. The source device
+ * must be locked by netif_addr_lock_bh.
+ *
+ * This function is intended to be called from the dev->set_rx_mode
+ * function of layered software devices. It allows for a single source
+ * device to be synced to multiple destination devices.
+ */
+int dev_uc_sync_multiple(struct net_device *to, struct net_device *from)
+{
+ int err = 0;
+
+ if (to->addr_len != from->addr_len)
+ return -EINVAL;
+
+ netif_addr_lock_nested(to);
+ err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len);
+ if (!err)
+ __dev_set_rx_mode(to);
+ netif_addr_unlock(to);
+ return err;
+}
+EXPORT_SYMBOL(dev_uc_sync_multiple);
+
+/**
* dev_uc_unsync - Remove synchronized addresses from the destination device
* @to: destination device
* @from: source device
@@ -559,7 +655,7 @@ int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr)
}
}
err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len,
- NETDEV_HW_ADDR_T_MULTICAST, true);
+ NETDEV_HW_ADDR_T_MULTICAST, true, false);
if (!err)
__dev_set_rx_mode(dev);
out:
@@ -575,7 +671,7 @@ static int __dev_mc_add(struct net_device *dev, const unsigned char *addr,
netif_addr_lock_bh(dev);
err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
- NETDEV_HW_ADDR_T_MULTICAST, global);
+ NETDEV_HW_ADDR_T_MULTICAST, global, false);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
@@ -615,7 +711,7 @@ static int __dev_mc_del(struct net_device *dev, const unsigned char *addr,
netif_addr_lock_bh(dev);
err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len,
- NETDEV_HW_ADDR_T_MULTICAST, global);
+ NETDEV_HW_ADDR_T_MULTICAST, global, false);
if (!err)
__dev_set_rx_mode(dev);
netif_addr_unlock_bh(dev);
@@ -679,6 +775,36 @@ int dev_mc_sync(struct net_device *to, struct net_device *from)
EXPORT_SYMBOL(dev_mc_sync);
/**
+ * dev_mc_sync_multiple - Synchronize device's unicast list to another
+ * device, but allow for multiple calls to sync to multiple devices.
+ * @to: destination device
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+ * addresses that have no users left. The source device must be
+ * locked by netif_addr_lock_bh.
+ *
+ * This function is intended to be called from the ndo_set_rx_mode
+ * function of layered software devices. It allows for a single
+ * source device to be synced to multiple destination devices.
+ */
+int dev_mc_sync_multiple(struct net_device *to, struct net_device *from)
+{
+ int err = 0;
+
+ if (to->addr_len != from->addr_len)
+ return -EINVAL;
+
+ netif_addr_lock_nested(to);
+ err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
+ if (!err)
+ __dev_set_rx_mode(to);
+ netif_addr_unlock(to);
+ return err;
+}
+EXPORT_SYMBOL(dev_mc_sync_multiple);
+
+/**
* dev_mc_unsync - Remove synchronized addresses from the destination device
* @to: destination device
* @from: source device
diff --git a/net/core/dst.c b/net/core/dst.c
index 35fd12f1a69c..df9cc810ec8e 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -320,27 +320,28 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
EXPORT_SYMBOL(__dst_destroy_metrics_generic);
/**
- * skb_dst_set_noref - sets skb dst, without a reference
+ * __skb_dst_set_noref - sets skb dst, without a reference
* @skb: buffer
* @dst: dst entry
+ * @force: if force is set, use noref version even for DST_NOCACHE entries
*
* Sets skb dst, assuming a reference was not taken on dst
* skb_dst_drop() should not dst_release() this dst
*/
-void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+void __skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst, bool force)
{
WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
/* If dst not in cache, we must take a reference, because
* dst_release() will destroy dst as soon as its refcount becomes zero
*/
- if (unlikely(dst->flags & DST_NOCACHE)) {
+ if (unlikely((dst->flags & DST_NOCACHE) && !force)) {
dst_hold(dst);
skb_dst_set(skb, dst);
} else {
skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
}
}
-EXPORT_SYMBOL(skb_dst_set_noref);
+EXPORT_SYMBOL(__skb_dst_set_noref);
/* Dirty hack. We did it in 2.2 (in __dst_free),
* we have _very_ good reasons not to repeat
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 3e9b2c3e30f0..5a934ef90f8b 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -60,10 +60,13 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6",
[NETIF_F_HIGHDMA_BIT] = "highdma",
[NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist",
- [NETIF_F_HW_VLAN_TX_BIT] = "tx-vlan-hw-insert",
+ [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-ctag-hw-insert",
- [NETIF_F_HW_VLAN_RX_BIT] = "rx-vlan-hw-parse",
- [NETIF_F_HW_VLAN_FILTER_BIT] = "rx-vlan-filter",
+ [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-ctag-hw-parse",
+ [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-ctag-filter",
+ [NETIF_F_HW_VLAN_STAG_TX_BIT] = "tx-vlan-stag-hw-insert",
+ [NETIF_F_HW_VLAN_STAG_RX_BIT] = "rx-vlan-stag-hw-parse",
+ [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
[NETIF_F_VLAN_CHALLENGED_BIT] = "vlan-challenged",
[NETIF_F_GSO_BIT] = "tx-generic-segmentation",
[NETIF_F_LLTX_BIT] = "tx-lockless",
@@ -78,6 +81,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
[NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
[NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
[NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
+ [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
[NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
[NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp",
@@ -266,18 +270,19 @@ static int ethtool_set_one_feature(struct net_device *dev,
#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
-#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
- NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
+#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \
+ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \
+ NETIF_F_RXHASH)
static u32 __ethtool_get_flags(struct net_device *dev)
{
u32 flags = 0;
- if (dev->features & NETIF_F_LRO) flags |= ETH_FLAG_LRO;
- if (dev->features & NETIF_F_HW_VLAN_RX) flags |= ETH_FLAG_RXVLAN;
- if (dev->features & NETIF_F_HW_VLAN_TX) flags |= ETH_FLAG_TXVLAN;
- if (dev->features & NETIF_F_NTUPLE) flags |= ETH_FLAG_NTUPLE;
- if (dev->features & NETIF_F_RXHASH) flags |= ETH_FLAG_RXHASH;
+ if (dev->features & NETIF_F_LRO) flags |= ETH_FLAG_LRO;
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) flags |= ETH_FLAG_RXVLAN;
+ if (dev->features & NETIF_F_HW_VLAN_CTAG_TX) flags |= ETH_FLAG_TXVLAN;
+ if (dev->features & NETIF_F_NTUPLE) flags |= ETH_FLAG_NTUPLE;
+ if (dev->features & NETIF_F_RXHASH) flags |= ETH_FLAG_RXHASH;
return flags;
}
@@ -290,8 +295,8 @@ static int __ethtool_set_flags(struct net_device *dev, u32 data)
return -EINVAL;
if (data & ETH_FLAG_LRO) features |= NETIF_F_LRO;
- if (data & ETH_FLAG_RXVLAN) features |= NETIF_F_HW_VLAN_RX;
- if (data & ETH_FLAG_TXVLAN) features |= NETIF_F_HW_VLAN_TX;
+ if (data & ETH_FLAG_RXVLAN) features |= NETIF_F_HW_VLAN_CTAG_RX;
+ if (data & ETH_FLAG_TXVLAN) features |= NETIF_F_HW_VLAN_CTAG_TX;
if (data & ETH_FLAG_NTUPLE) features |= NETIF_F_NTUPLE;
if (data & ETH_FLAG_RXHASH) features |= NETIF_F_RXHASH;
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 58a4ba27dfe3..d5a9f8ead0d8 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -266,7 +266,7 @@ errout:
return err;
}
-static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh)
{
struct net *net = sock_net(skb->sk);
struct fib_rule_hdr *frh = nlmsg_data(nlh);
@@ -415,7 +415,7 @@ errout:
return err;
}
-static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
{
struct net *net = sock_net(skb->sk);
struct fib_rule_hdr *frh = nlmsg_data(nlh);
diff --git a/net/core/filter.c b/net/core/filter.c
index 2e20b55a7830..dad2a178f9f8 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -348,6 +348,9 @@ load_b:
case BPF_S_ANC_VLAN_TAG_PRESENT:
A = !!vlan_tx_tag_present(skb);
continue;
+ case BPF_S_ANC_PAY_OFFSET:
+ A = __skb_get_poff(skb);
+ continue;
case BPF_S_ANC_NLATTR: {
struct nlattr *nla;
@@ -612,6 +615,7 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
ANCILLARY(ALU_XOR_X);
ANCILLARY(VLAN_TAG);
ANCILLARY(VLAN_TAG_PRESENT);
+ ANCILLARY(PAY_OFFSET);
}
/* ancillary operation unknown or unsupported */
@@ -814,6 +818,7 @@ static void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
[BPF_S_ANC_SECCOMP_LD_W] = BPF_LD|BPF_B|BPF_ABS,
[BPF_S_ANC_VLAN_TAG] = BPF_LD|BPF_B|BPF_ABS,
[BPF_S_ANC_VLAN_TAG_PRESENT] = BPF_LD|BPF_B|BPF_ABS,
+ [BPF_S_ANC_PAY_OFFSET] = BPF_LD|BPF_B|BPF_ABS,
[BPF_S_LD_W_LEN] = BPF_LD|BPF_W|BPF_LEN,
[BPF_S_LD_W_IND] = BPF_LD|BPF_W|BPF_IND,
[BPF_S_LD_H_IND] = BPF_LD|BPF_H|BPF_IND,
diff --git a/net/core/flow.c b/net/core/flow.c
index c56ea6f7f6c7..7102f166482d 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -323,12 +323,30 @@ static void flow_cache_flush_tasklet(unsigned long data)
complete(&info->completion);
}
+/*
+ * Return whether a cpu needs flushing. Conservatively, we assume
+ * the presence of any entries means the core may require flushing,
+ * since the flow_cache_ops.check() function may assume it's running
+ * on the same core as the per-cpu cache component.
+ */
+static int flow_cache_percpu_empty(struct flow_cache *fc, int cpu)
+{
+ struct flow_cache_percpu *fcp;
+ int i;
+
+ fcp = per_cpu_ptr(fc->percpu, cpu);
+ for (i = 0; i < flow_cache_hash_size(fc); i++)
+ if (!hlist_empty(&fcp->hash_table[i]))
+ return 0;
+ return 1;
+}
+
static void flow_cache_flush_per_cpu(void *data)
{
struct flow_flush_info *info = data;
struct tasklet_struct *tasklet;
- tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet);
+ tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;
tasklet->data = (unsigned long)info;
tasklet_schedule(tasklet);
}
@@ -337,22 +355,40 @@ void flow_cache_flush(void)
{
struct flow_flush_info info;
static DEFINE_MUTEX(flow_flush_sem);
+ cpumask_var_t mask;
+ int i, self;
+
+ /* Track which cpus need flushing to avoid disturbing all cores. */
+ if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+ return;
+ cpumask_clear(mask);
/* Don't want cpus going down or up during this. */
get_online_cpus();
mutex_lock(&flow_flush_sem);
info.cache = &flow_cache_global;
- atomic_set(&info.cpuleft, num_online_cpus());
+ for_each_online_cpu(i)
+ if (!flow_cache_percpu_empty(info.cache, i))
+ cpumask_set_cpu(i, mask);
+ atomic_set(&info.cpuleft, cpumask_weight(mask));
+ if (atomic_read(&info.cpuleft) == 0)
+ goto done;
+
init_completion(&info.completion);
local_bh_disable();
- smp_call_function(flow_cache_flush_per_cpu, &info, 0);
- flow_cache_flush_tasklet((unsigned long)&info);
+ self = cpumask_test_and_clear_cpu(smp_processor_id(), mask);
+ on_each_cpu_mask(mask, flow_cache_flush_per_cpu, &info, 0);
+ if (self)
+ flow_cache_flush_tasklet((unsigned long)&info);
local_bh_enable();
wait_for_completion(&info.completion);
+
+done:
mutex_unlock(&flow_flush_sem);
put_online_cpus();
+ free_cpumask_var(mask);
}
static void flow_cache_flush_task(struct work_struct *work)
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
index e187bf06d673..00ee068efc1c 100644
--- a/net/core/flow_dissector.c
+++ b/net/core/flow_dissector.c
@@ -5,6 +5,10 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <net/ipv6.h>
+#include <linux/igmp.h>
+#include <linux/icmp.h>
+#include <linux/sctp.h>
+#include <linux/dccp.h>
#include <linux/if_tunnel.h>
#include <linux/if_pppox.h>
#include <linux/ppp_defs.h>
@@ -119,6 +123,17 @@ ipv6:
nhoff += 4;
if (hdr->flags & GRE_SEQ)
nhoff += 4;
+ if (proto == htons(ETH_P_TEB)) {
+ const struct ethhdr *eth;
+ struct ethhdr _eth;
+
+ eth = skb_header_pointer(skb, nhoff,
+ sizeof(_eth), &_eth);
+ if (!eth)
+ return false;
+ proto = eth->h_proto;
+ nhoff += sizeof(*eth);
+ }
goto again;
}
break;
@@ -217,6 +232,59 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,
}
EXPORT_SYMBOL(__skb_tx_hash);
+/* __skb_get_poff() returns the offset to the payload as far as it could
+ * be dissected. The main user is currently BPF, so that we can dynamically
+ * truncate packets without needing to push actual payload to the user
+ * space and can analyze headers only, instead.
+ */
+u32 __skb_get_poff(const struct sk_buff *skb)
+{
+ struct flow_keys keys;
+ u32 poff = 0;
+
+ if (!skb_flow_dissect(skb, &keys))
+ return 0;
+
+ poff += keys.thoff;
+ switch (keys.ip_proto) {
+ case IPPROTO_TCP: {
+ const struct tcphdr *tcph;
+ struct tcphdr _tcph;
+
+ tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
+ if (!tcph)
+ return poff;
+
+ poff += max_t(u32, sizeof(struct tcphdr), tcph->doff * 4);
+ break;
+ }
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE:
+ poff += sizeof(struct udphdr);
+ break;
+ /* For the rest, we do not really care about header
+ * extensions at this point for now.
+ */
+ case IPPROTO_ICMP:
+ poff += sizeof(struct icmphdr);
+ break;
+ case IPPROTO_ICMPV6:
+ poff += sizeof(struct icmp6hdr);
+ break;
+ case IPPROTO_IGMP:
+ poff += sizeof(struct igmphdr);
+ break;
+ case IPPROTO_DCCP:
+ poff += sizeof(struct dccp_hdr);
+ break;
+ case IPPROTO_SCTP:
+ poff += sizeof(struct sctphdr);
+ break;
+ }
+
+ return poff;
+}
+
static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
{
if (unlikely(queue_index >= dev->real_num_tx_queues)) {
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 537301a2c31f..5c56b217b999 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -39,21 +39,13 @@
#include <linux/string.h>
#include <linux/log2.h>
+#define DEBUG
#define NEIGH_DEBUG 1
-
-#define NEIGH_PRINTK(x...) printk(x)
-#define NEIGH_NOPRINTK(x...) do { ; } while(0)
-#define NEIGH_PRINTK1 NEIGH_NOPRINTK
-#define NEIGH_PRINTK2 NEIGH_NOPRINTK
-
-#if NEIGH_DEBUG >= 1
-#undef NEIGH_PRINTK1
-#define NEIGH_PRINTK1 NEIGH_PRINTK
-#endif
-#if NEIGH_DEBUG >= 2
-#undef NEIGH_PRINTK2
-#define NEIGH_PRINTK2 NEIGH_PRINTK
-#endif
+#define neigh_dbg(level, fmt, ...) \
+do { \
+ if (level <= NEIGH_DEBUG) \
+ pr_debug(fmt, ##__VA_ARGS__); \
+} while (0)
#define PNEIGH_HASHMASK 0xF
@@ -246,7 +238,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
n->nud_state = NUD_NOARP;
else
n->nud_state = NUD_NONE;
- NEIGH_PRINTK2("neigh %p is stray.\n", n);
+ neigh_dbg(2, "neigh %p is stray\n", n);
}
write_unlock(&n->lock);
neigh_cleanup_and_release(n);
@@ -542,7 +534,7 @@ struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
lockdep_is_held(&tbl->lock)));
rcu_assign_pointer(nht->hash_buckets[hash_val], n);
write_unlock_bh(&tbl->lock);
- NEIGH_PRINTK2("neigh %p is created.\n", n);
+ neigh_dbg(2, "neigh %p is created\n", n);
rc = n;
out:
return rc;
@@ -725,7 +717,7 @@ void neigh_destroy(struct neighbour *neigh)
dev_put(dev);
neigh_parms_put(neigh->parms);
- NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
+ neigh_dbg(2, "neigh %p is destroyed\n", neigh);
atomic_dec(&neigh->tbl->entries);
kfree_rcu(neigh, rcu);
@@ -739,7 +731,7 @@ EXPORT_SYMBOL(neigh_destroy);
*/
static void neigh_suspect(struct neighbour *neigh)
{
- NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
+ neigh_dbg(2, "neigh %p is suspected\n", neigh);
neigh->output = neigh->ops->output;
}
@@ -751,7 +743,7 @@ static void neigh_suspect(struct neighbour *neigh)
*/
static void neigh_connect(struct neighbour *neigh)
{
- NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
+ neigh_dbg(2, "neigh %p is connected\n", neigh);
neigh->output = neigh->ops->connected_output;
}
@@ -852,7 +844,7 @@ static void neigh_invalidate(struct neighbour *neigh)
struct sk_buff *skb;
NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
- NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
+ neigh_dbg(2, "neigh %p is failed\n", neigh);
neigh->updated = jiffies;
/* It is very thin place. report_unreachable is very complicated
@@ -904,17 +896,17 @@ static void neigh_timer_handler(unsigned long arg)
if (state & NUD_REACHABLE) {
if (time_before_eq(now,
neigh->confirmed + neigh->parms->reachable_time)) {
- NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
+ neigh_dbg(2, "neigh %p is still alive\n", neigh);
next = neigh->confirmed + neigh->parms->reachable_time;
} else if (time_before_eq(now,
neigh->used + neigh->parms->delay_probe_time)) {
- NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
+ neigh_dbg(2, "neigh %p is delayed\n", neigh);
neigh->nud_state = NUD_DELAY;
neigh->updated = jiffies;
neigh_suspect(neigh);
next = now + neigh->parms->delay_probe_time;
} else {
- NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
+ neigh_dbg(2, "neigh %p is suspected\n", neigh);
neigh->nud_state = NUD_STALE;
neigh->updated = jiffies;
neigh_suspect(neigh);
@@ -923,14 +915,14 @@ static void neigh_timer_handler(unsigned long arg)
} else if (state & NUD_DELAY) {
if (time_before_eq(now,
neigh->confirmed + neigh->parms->delay_probe_time)) {
- NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
+ neigh_dbg(2, "neigh %p is now reachable\n", neigh);
neigh->nud_state = NUD_REACHABLE;
neigh->updated = jiffies;
neigh_connect(neigh);
notify = 1;
next = neigh->confirmed + neigh->parms->reachable_time;
} else {
- NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
+ neigh_dbg(2, "neigh %p is probed\n", neigh);
neigh->nud_state = NUD_PROBE;
neigh->updated = jiffies;
atomic_set(&neigh->probes, 0);
@@ -997,7 +989,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
return 1;
}
} else if (neigh->nud_state & NUD_STALE) {
- NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
+ neigh_dbg(2, "neigh %p is delayed\n", neigh);
neigh->nud_state = NUD_DELAY;
neigh->updated = jiffies;
neigh_add_timer(neigh,
@@ -1320,8 +1312,7 @@ int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
out:
return rc;
discard:
- NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
- dst, neigh);
+ neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
@@ -1498,7 +1489,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
}
}
write_unlock_bh(&tbl->lock);
- NEIGH_PRINTK1("neigh_parms_release: not found\n");
+ neigh_dbg(1, "%s: not found\n", __func__);
}
EXPORT_SYMBOL(neigh_parms_release);
@@ -1613,7 +1604,7 @@ int neigh_table_clear(struct neigh_table *tbl)
}
EXPORT_SYMBOL(neigh_table_clear);
-static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
@@ -1677,7 +1668,7 @@ out:
return err;
}
-static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
@@ -1955,7 +1946,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
[NDTPA_LOCKTIME] = { .type = NLA_U64 },
};
-static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct neigh_table *tbl;
diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c
index 3174f1998ee6..569d355fec3e 100644
--- a/net/core/net-procfs.c
+++ b/net/core/net-procfs.c
@@ -271,7 +271,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v)
else
seq_printf(seq, "%04x", ntohs(pt->type));
- seq_printf(seq, " %-8s %pF\n",
+ seq_printf(seq, " %-8s %pf\n",
pt->dev ? pt->dev->name : "", pt->func);
}
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index fa32899006a2..a5802a8b652f 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -47,7 +47,7 @@ static struct sk_buff_head skb_pool;
static atomic_t trapped;
-static struct srcu_struct netpoll_srcu;
+DEFINE_STATIC_SRCU(netpoll_srcu);
#define USEC_PER_POLL 50
#define NETPOLL_RX_ENABLED 1
@@ -206,17 +206,17 @@ static void netpoll_poll_dev(struct net_device *dev)
* the dev_open/close paths use this to block netpoll activity
* while changing device state
*/
- if (!mutex_trylock(&ni->dev_lock))
+ if (!down_trylock(&ni->dev_lock))
return;
if (!netif_running(dev)) {
- mutex_unlock(&ni->dev_lock);
+ up(&ni->dev_lock);
return;
}
ops = dev->netdev_ops;
if (!ops->ndo_poll_controller) {
- mutex_unlock(&ni->dev_lock);
+ up(&ni->dev_lock);
return;
}
@@ -225,7 +225,7 @@ static void netpoll_poll_dev(struct net_device *dev)
poll_napi(dev);
- mutex_unlock(&ni->dev_lock);
+ up(&ni->dev_lock);
if (dev->flags & IFF_SLAVE) {
if (ni) {
@@ -255,7 +255,7 @@ int netpoll_rx_disable(struct net_device *dev)
idx = srcu_read_lock(&netpoll_srcu);
ni = srcu_dereference(dev->npinfo, &netpoll_srcu);
if (ni)
- mutex_lock(&ni->dev_lock);
+ down(&ni->dev_lock);
srcu_read_unlock(&netpoll_srcu, idx);
return 0;
}
@@ -267,7 +267,7 @@ void netpoll_rx_enable(struct net_device *dev)
rcu_read_lock();
ni = rcu_dereference(dev->npinfo);
if (ni)
- mutex_unlock(&ni->dev_lock);
+ up(&ni->dev_lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(netpoll_rx_enable);
@@ -383,8 +383,9 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
if (__netif_tx_trylock(txq)) {
if (!netif_xmit_stopped(txq)) {
if (vlan_tx_tag_present(skb) &&
- !(netif_skb_features(skb) & NETIF_F_HW_VLAN_TX)) {
- skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+ !vlan_hw_offload_capable(netif_skb_features(skb),
+ skb->vlan_proto)) {
+ skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
if (unlikely(!skb))
break;
skb->vlan_tci = 0;
@@ -1046,7 +1047,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
INIT_LIST_HEAD(&npinfo->rx_np);
spin_lock_init(&npinfo->rx_lock);
- mutex_init(&npinfo->dev_lock);
+ sema_init(&npinfo->dev_lock, 1);
skb_queue_head_init(&npinfo->neigh_tx);
skb_queue_head_init(&npinfo->txq);
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
@@ -1212,7 +1213,6 @@ EXPORT_SYMBOL(netpoll_setup);
static int __init netpoll_init(void)
{
skb_queue_head_init(&skb_pool);
- init_srcu_struct(&netpoll_srcu);
return 0;
}
core_initcall(netpoll_init);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 6c41e979dc88..11f2704c3810 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2198,7 +2198,7 @@ static inline int f_pick(struct pktgen_dev *pkt_dev)
pkt_dev->curfl = 0; /*reset */
}
} else {
- flow = random32() % pkt_dev->cflows;
+ flow = prandom_u32() % pkt_dev->cflows;
pkt_dev->curfl = flow;
if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
@@ -2246,7 +2246,7 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
__u16 t;
if (pkt_dev->flags & F_QUEUE_MAP_RND) {
- t = random32() %
+ t = prandom_u32() %
(pkt_dev->queue_map_max -
pkt_dev->queue_map_min + 1)
+ pkt_dev->queue_map_min;
@@ -2278,7 +2278,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__u32 tmp;
if (pkt_dev->flags & F_MACSRC_RND)
- mc = random32() % pkt_dev->src_mac_count;
+ mc = prandom_u32() % pkt_dev->src_mac_count;
else {
mc = pkt_dev->cur_src_mac_offset++;
if (pkt_dev->cur_src_mac_offset >=
@@ -2304,7 +2304,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__u32 tmp;
if (pkt_dev->flags & F_MACDST_RND)
- mc = random32() % pkt_dev->dst_mac_count;
+ mc = prandom_u32() % pkt_dev->dst_mac_count;
else {
mc = pkt_dev->cur_dst_mac_offset++;
@@ -2331,21 +2331,21 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
for (i = 0; i < pkt_dev->nr_labels; i++)
if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
- ((__force __be32)random32() &
+ ((__force __be32)prandom_u32() &
htonl(0x000fffff));
}
if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
- pkt_dev->vlan_id = random32() & (4096-1);
+ pkt_dev->vlan_id = prandom_u32() & (4096 - 1);
}
if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
- pkt_dev->svlan_id = random32() & (4096 - 1);
+ pkt_dev->svlan_id = prandom_u32() & (4096 - 1);
}
if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
if (pkt_dev->flags & F_UDPSRC_RND)
- pkt_dev->cur_udp_src = random32() %
+ pkt_dev->cur_udp_src = prandom_u32() %
(pkt_dev->udp_src_max - pkt_dev->udp_src_min)
+ pkt_dev->udp_src_min;
@@ -2358,7 +2358,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
if (pkt_dev->flags & F_UDPDST_RND) {
- pkt_dev->cur_udp_dst = random32() %
+ pkt_dev->cur_udp_dst = prandom_u32() %
(pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
+ pkt_dev->udp_dst_min;
} else {
@@ -2375,7 +2375,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (imn < imx) {
__u32 t;
if (pkt_dev->flags & F_IPSRC_RND)
- t = random32() % (imx - imn) + imn;
+ t = prandom_u32() % (imx - imn) + imn;
else {
t = ntohl(pkt_dev->cur_saddr);
t++;
@@ -2396,17 +2396,15 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__be32 s;
if (pkt_dev->flags & F_IPDST_RND) {
- t = random32() % (imx - imn) + imn;
- s = htonl(t);
-
- while (ipv4_is_loopback(s) ||
- ipv4_is_multicast(s) ||
- ipv4_is_lbcast(s) ||
- ipv4_is_zeronet(s) ||
- ipv4_is_local_multicast(s)) {
- t = random32() % (imx - imn) + imn;
+ do {
+ t = prandom_u32() %
+ (imx - imn) + imn;
s = htonl(t);
- }
+ } while (ipv4_is_loopback(s) ||
+ ipv4_is_multicast(s) ||
+ ipv4_is_lbcast(s) ||
+ ipv4_is_zeronet(s) ||
+ ipv4_is_local_multicast(s));
pkt_dev->cur_daddr = s;
} else {
t = ntohl(pkt_dev->cur_daddr);
@@ -2437,7 +2435,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
for (i = 0; i < 4; i++) {
pkt_dev->cur_in6_daddr.s6_addr32[i] =
- (((__force __be32)random32() |
+ (((__force __be32)prandom_u32() |
pkt_dev->min_in6_daddr.s6_addr32[i]) &
pkt_dev->max_in6_daddr.s6_addr32[i]);
}
@@ -2447,7 +2445,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
__u32 t;
if (pkt_dev->flags & F_TXSIZE_RND) {
- t = random32() %
+ t = prandom_u32() %
(pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
+ pkt_dev->min_pkt_size;
} else {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 5fb8d7e47294..a08bd2b7fe3f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -496,8 +496,10 @@ static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
}
if (ops->fill_info) {
data = nla_nest_start(skb, IFLA_INFO_DATA);
- if (data == NULL)
+ if (data == NULL) {
+ err = -EMSGSIZE;
goto err_cancel_link;
+ }
err = ops->fill_info(skb, dev);
if (err < 0)
goto err_cancel_data;
@@ -515,32 +517,6 @@ out:
return err;
}
-static const int rtm_min[RTM_NR_FAMILIES] =
-{
- [RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- [RTM_FAM(RTM_NEWADDR)] = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
- [RTM_FAM(RTM_NEWROUTE)] = NLMSG_LENGTH(sizeof(struct rtmsg)),
- [RTM_FAM(RTM_NEWRULE)] = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
- [RTM_FAM(RTM_NEWQDISC)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
- [RTM_FAM(RTM_NEWTCLASS)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
- [RTM_FAM(RTM_NEWTFILTER)] = NLMSG_LENGTH(sizeof(struct tcmsg)),
- [RTM_FAM(RTM_NEWACTION)] = NLMSG_LENGTH(sizeof(struct tcamsg)),
- [RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
- [RTM_FAM(RTM_GETANYCAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
-};
-
-static const int rta_max[RTM_NR_FAMILIES] =
-{
- [RTM_FAM(RTM_NEWLINK)] = IFLA_MAX,
- [RTM_FAM(RTM_NEWADDR)] = IFA_MAX,
- [RTM_FAM(RTM_NEWROUTE)] = RTA_MAX,
- [RTM_FAM(RTM_NEWRULE)] = FRA_MAX,
- [RTM_FAM(RTM_NEWQDISC)] = TCA_MAX,
- [RTM_FAM(RTM_NEWTCLASS)] = TCA_MAX,
- [RTM_FAM(RTM_NEWTFILTER)] = TCA_MAX,
- [RTM_FAM(RTM_NEWACTION)] = TCAA_MAX,
-};
-
int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo)
{
struct sock *rtnl = net->rtnl;
@@ -1070,7 +1046,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
cb->seq = net->dev_base_seq;
- if (nlmsg_parse(cb->nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+ if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
ifla_policy) >= 0) {
if (tb[IFLA_EXT_MASK])
@@ -1537,7 +1513,7 @@ errout:
return err;
}
-static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
@@ -1578,7 +1554,7 @@ errout:
return err;
}
-static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
const struct rtnl_link_ops *ops;
@@ -1709,7 +1685,7 @@ static int rtnl_group_changelink(struct net *net, int group,
return 0;
}
-static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
const struct rtnl_link_ops *ops;
@@ -1864,7 +1840,7 @@ out:
}
}
-static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
@@ -1920,7 +1896,7 @@ static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh)
u32 ext_filter_mask = 0;
u16 min_ifinfo_dump_size = 0;
- if (nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, IFLA_MAX,
+ if (nlmsg_parse(nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
ifla_policy) >= 0) {
if (tb[IFLA_EXT_MASK])
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
@@ -1955,8 +1931,11 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
if (rtnl_msg_handlers[idx] == NULL ||
rtnl_msg_handlers[idx][type].dumpit == NULL)
continue;
- if (idx > s_idx)
+ if (idx > s_idx) {
memset(&cb->args[0], 0, sizeof(cb->args));
+ cb->prev_seq = 0;
+ cb->seq = 0;
+ }
if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))
break;
}
@@ -2049,7 +2028,39 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
}
-static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+/**
+ * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry
+ */
+int ndo_dflt_fdb_add(struct ndmsg *ndm,
+ struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr,
+ u16 flags)
+{
+ int err = -EINVAL;
+
+ /* If aging addresses are supported device will need to
+ * implement its own handler for this.
+ */
+ if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
+ pr_info("%s: FDB only supports static addresses\n", dev->name);
+ return err;
+ }
+
+ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+ err = dev_uc_add_excl(dev, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_add_excl(dev, addr);
+
+ /* Only return duplicate errors if NLM_F_EXCL is set */
+ if (err == -EEXIST && !(flags & NLM_F_EXCL))
+ err = 0;
+
+ return err;
+}
+EXPORT_SYMBOL(ndo_dflt_fdb_add);
+
+static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
@@ -2080,7 +2091,7 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
addr = nla_data(tb[NDA_LLADDR]);
- if (!is_valid_ether_addr(addr)) {
+ if (is_zero_ether_addr(addr)) {
pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ether address\n");
return -EINVAL;
}
@@ -2101,10 +2112,13 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
/* Embedded bridge, macvlan, and any other device support */
- if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_add) {
- err = dev->netdev_ops->ndo_fdb_add(ndm, tb,
- dev, addr,
- nlh->nlmsg_flags);
+ if ((ndm->ndm_flags & NTF_SELF)) {
+ if (dev->netdev_ops->ndo_fdb_add)
+ err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr,
+ nlh->nlmsg_flags);
+ else
+ err = ndo_dflt_fdb_add(ndm, tb, dev, addr,
+ nlh->nlmsg_flags);
if (!err) {
rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH);
@@ -2115,7 +2129,36 @@ out:
return err;
}
-static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+/**
+ * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry
+ */
+int ndo_dflt_fdb_del(struct ndmsg *ndm,
+ struct nlattr *tb[],
+ struct net_device *dev,
+ const unsigned char *addr)
+{
+ int err = -EOPNOTSUPP;
+
+ /* If aging addresses are supported device will need to
+ * implement its own handler for this.
+ */
+ if (ndm->ndm_state & NUD_PERMANENT) {
+ pr_info("%s: FDB only supports static addresses\n", dev->name);
+ return -EINVAL;
+ }
+
+ if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
+ err = dev_uc_del(dev, addr);
+ else if (is_multicast_ether_addr(addr))
+ err = dev_mc_del(dev, addr);
+ else
+ err = -EINVAL;
+
+ return err;
+}
+EXPORT_SYMBOL(ndo_dflt_fdb_del);
+
+static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ndmsg *ndm;
@@ -2149,7 +2192,7 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
addr = nla_data(tb[NDA_LLADDR]);
- if (!is_valid_ether_addr(addr)) {
+ if (is_zero_ether_addr(addr)) {
pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ether address\n");
return -EINVAL;
}
@@ -2172,8 +2215,11 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
}
/* Embedded bridge, macvlan, and any other device support */
- if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) {
- err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
+ if (ndm->ndm_flags & NTF_SELF) {
+ if (dev->netdev_ops->ndo_fdb_del)
+ err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr);
+ else
+ err = ndo_dflt_fdb_del(ndm, tb, dev, addr);
if (!err) {
rtnl_fdb_notify(dev, addr, RTM_DELNEIGH);
@@ -2218,7 +2264,7 @@ skip:
* @dev: netdevice
*
* Default netdevice operation to dump the existing unicast address list.
- * Returns zero on success.
+ * Returns number of addresses from list put in skb.
*/
int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
@@ -2258,6 +2304,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (dev->netdev_ops->ndo_fdb_dump)
idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, idx);
+ else
+ idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
}
rcu_read_unlock();
@@ -2409,8 +2457,7 @@ errout:
return err;
}
-static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
- void *arg)
+static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
@@ -2480,8 +2527,7 @@ out:
return err;
}
-static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
- void *arg)
+static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifinfomsg *ifm;
@@ -2551,10 +2597,6 @@ out:
return err;
}
-/* Protected by RTNL sempahore. */
-static struct rtattr **rta_buf;
-static int rtattr_max;
-
/* Process one rtnetlink message. */
static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -2562,7 +2604,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
struct net *net = sock_net(skb->sk);
rtnl_doit_func doit;
int sz_idx, kind;
- int min_len;
int family;
int type;
int err;
@@ -2574,10 +2615,10 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
type -= RTM_BASE;
/* All the messages must have at least 1 byte length */
- if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))
+ if (nlmsg_len(nlh) < sizeof(struct rtgenmsg))
return 0;
- family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family;
+ family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
sz_idx = type>>2;
kind = type&3;
@@ -2610,32 +2651,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return err;
}
- memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
-
- min_len = rtm_min[sz_idx];
- if (nlh->nlmsg_len < min_len)
- return -EINVAL;
-
- if (nlh->nlmsg_len > min_len) {
- int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
- struct rtattr *attr = (void *)nlh + NLMSG_ALIGN(min_len);
-
- while (RTA_OK(attr, attrlen)) {
- unsigned int flavor = attr->rta_type & NLA_TYPE_MASK;
- if (flavor) {
- if (flavor > rta_max[sz_idx])
- return -EINVAL;
- rta_buf[flavor-1] = attr;
- }
- attr = RTA_NEXT(attr, attrlen);
- }
- }
-
doit = rtnl_get_doit(family, type);
if (doit == NULL)
return -EOPNOTSUPP;
- return doit(skb, nlh, (void *)&rta_buf[0]);
+ return doit(skb, nlh);
}
static void rtnetlink_rcv(struct sk_buff *skb)
@@ -2705,16 +2725,6 @@ static struct pernet_operations rtnetlink_net_ops = {
void __init rtnetlink_init(void)
{
- int i;
-
- rtattr_max = 0;
- for (i = 0; i < ARRAY_SIZE(rta_max); i++)
- if (rta_max[i] > rtattr_max)
- rtattr_max = rta_max[i];
- rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL);
- if (!rta_buf)
- panic("rtnetlink_init: cannot allocate rta_buf\n");
-
if (register_pernet_subsys(&rtnetlink_net_ops))
panic("rtnetlink_init: cannot initialize rtnetlink\n");
diff --git a/net/core/scm.c b/net/core/scm.c
index 905dcc6ad1e3..03795d0147f2 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/security.h>
+#include <linux/pid_namespace.h>
#include <linux/pid.h>
#include <linux/nsproxy.h>
#include <linux/slab.h>
@@ -52,7 +53,8 @@ static __inline__ int scm_check_creds(struct ucred *creds)
if (!uid_valid(uid) || !gid_valid(gid))
return -EINVAL;
- if ((creds->pid == task_tgid_vnr(current) || nsown_capable(CAP_SYS_ADMIN)) &&
+ if ((creds->pid == task_tgid_vnr(current) ||
+ ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) &&
((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) ||
uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) &&
((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) ||
@@ -185,22 +187,6 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
p->creds.uid = uid;
p->creds.gid = gid;
-
- if (!p->cred ||
- !uid_eq(p->cred->euid, uid) ||
- !gid_eq(p->cred->egid, gid)) {
- struct cred *cred;
- err = -ENOMEM;
- cred = prepare_creds();
- if (!cred)
- goto error;
-
- cred->uid = cred->euid = uid;
- cred->gid = cred->egid = gid;
- if (p->cred)
- put_cred(p->cred);
- p->cred = cred;
- }
break;
}
default:
@@ -304,8 +290,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
/* Bump the usage count and install the file. */
sock = sock_from_file(fp[i], &err);
if (sock) {
- sock_update_netprioidx(sock->sk, current);
- sock_update_classid(sock->sk, current);
+ sock_update_netprioidx(sock->sk);
+ sock_update_classid(sock->sk);
}
fd_install(new_fd, get_file(fp[i]));
}
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index e61a8bb7fce7..6a2f13cee86a 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -12,12 +12,10 @@
static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
-static int __init net_secret_init(void)
+void net_secret_init(void)
{
get_random_bytes(net_secret, sizeof(net_secret));
- return 0;
}
-late_initcall(net_secret_init);
#ifdef CONFIG_INET
static u32 seq_scale(u32 seq)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 33245ef54c3b..af9185d0be6a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -179,6 +179,33 @@ out:
*
*/
+struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node)
+{
+ struct sk_buff *skb;
+
+ /* Get the HEAD */
+ skb = kmem_cache_alloc_node(skbuff_head_cache,
+ gfp_mask & ~__GFP_DMA, node);
+ if (!skb)
+ goto out;
+
+ /*
+ * Only clear those fields we need to clear, not those that we will
+ * actually initialise below. Hence, don't put any more fields after
+ * the tail pointer in struct sk_buff!
+ */
+ memset(skb, 0, offsetof(struct sk_buff, tail));
+ skb->data = NULL;
+ skb->truesize = sizeof(struct sk_buff);
+ atomic_set(&skb->users, 1);
+
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+ skb->mac_header = ~0U;
+#endif
+out:
+ return skb;
+}
+
/**
* __alloc_skb - allocate a network buffer
* @size: size to allocate
@@ -584,7 +611,8 @@ static void skb_release_head_state(struct sk_buff *skb)
static void skb_release_all(struct sk_buff *skb)
{
skb_release_head_state(skb);
- skb_release_data(skb);
+ if (likely(skb->data))
+ skb_release_data(skb);
}
/**
@@ -673,6 +701,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->mac_header = old->mac_header;
new->inner_transport_header = old->inner_transport_header;
new->inner_network_header = old->inner_network_header;
+ new->inner_mac_header = old->inner_mac_header;
skb_dst_copy(new, old);
new->rxhash = old->rxhash;
new->ooo_okay = old->ooo_okay;
@@ -706,6 +735,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->tc_verd = old->tc_verd;
#endif
#endif
+ new->vlan_proto = old->vlan_proto;
new->vlan_tci = old->vlan_tci;
skb_copy_secmark(new, old);
@@ -867,6 +897,18 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
}
EXPORT_SYMBOL(skb_clone);
+static void skb_headers_offset_update(struct sk_buff *skb, int off)
+{
+ /* {transport,network,mac}_header and tail are relative to skb->head */
+ skb->transport_header += off;
+ skb->network_header += off;
+ if (skb_mac_header_was_set(skb))
+ skb->mac_header += off;
+ skb->inner_transport_header += off;
+ skb->inner_network_header += off;
+ skb->inner_mac_header += off;
+}
+
static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
{
#ifndef NET_SKBUFF_DATA_USES_OFFSET
@@ -879,13 +921,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
__copy_skb_header(new, old);
#ifndef NET_SKBUFF_DATA_USES_OFFSET
- /* {transport,network,mac}_header are relative to skb->head */
- new->transport_header += offset;
- new->network_header += offset;
- if (skb_mac_header_was_set(new))
- new->mac_header += offset;
- new->inner_transport_header += offset;
- new->inner_network_header += offset;
+ skb_headers_offset_update(new, offset);
#endif
skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
@@ -1077,14 +1113,8 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
#else
skb->end = skb->head + size;
#endif
- /* {transport,network,mac}_header and tail are relative to skb->head */
skb->tail += off;
- skb->transport_header += off;
- skb->network_header += off;
- if (skb_mac_header_was_set(skb))
- skb->mac_header += off;
- skb->inner_transport_header += off;
- skb->inner_network_header += off;
+ skb_headers_offset_update(skb, off);
/* Only adjust this if it actually is csum_start rather than csum */
if (skb->ip_summed == CHECKSUM_PARTIAL)
skb->csum_start += nhead;
@@ -1180,12 +1210,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
if (n->ip_summed == CHECKSUM_PARTIAL)
n->csum_start += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
- n->transport_header += off;
- n->network_header += off;
- if (skb_mac_header_was_set(skb))
- n->mac_header += off;
- n->inner_transport_header += off;
- n->inner_network_header += off;
+ skb_headers_offset_update(n, off);
#endif
return n;
@@ -2741,12 +2766,19 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
unsigned int tnl_hlen = skb_tnl_header_len(skb);
unsigned int headroom;
unsigned int len;
+ __be16 proto;
+ bool csum;
int sg = !!(features & NETIF_F_SG);
int nfrags = skb_shinfo(skb)->nr_frags;
int err = -ENOMEM;
int i = 0;
int pos;
+ proto = skb_network_protocol(skb);
+ if (unlikely(!proto))
+ return ERR_PTR(-EINVAL);
+
+ csum = !!can_checksum_protocol(features, proto);
__skb_push(skb, doffset);
headroom = skb_headroom(skb);
pos = skb_headlen(skb);
@@ -2884,6 +2916,12 @@ skip_fraglist:
nskb->data_len = len - hsize;
nskb->len += nskb->data_len;
nskb->truesize += nskb->data_len;
+
+ if (!csum) {
+ nskb->csum = skb_checksum(nskb, doffset,
+ nskb->len - doffset, 0);
+ nskb->ip_summed = CHECKSUM_NONE;
+ }
} while ((offset += len) < skb->len);
return segs;
@@ -3289,12 +3327,8 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
if (!sk)
return;
- skb = skb_clone(orig_skb, GFP_ATOMIC);
- if (!skb)
- return;
-
if (hwtstamps) {
- *skb_hwtstamps(skb) =
+ *skb_hwtstamps(orig_skb) =
*hwtstamps;
} else {
/*
@@ -3302,9 +3336,13 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
* so keep the shared tx_flags and only
* store software time stamp
*/
- skb->tstamp = ktime_get_real();
+ orig_skb->tstamp = ktime_get_real();
}
+ skb = skb_clone(orig_skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
@@ -3361,6 +3399,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum_start = skb_headroom(skb) + start;
skb->csum_offset = off;
+ skb_set_transport_header(skb, start);
return true;
}
EXPORT_SYMBOL_GPL(skb_partial_csum_set);
diff --git a/net/core/sock.c b/net/core/sock.c
index b261a7977746..d4f4cea726e7 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -907,6 +907,10 @@ set_rcvbuf:
sock_valbool_flag(sk, SOCK_NOFCS, valbool);
break;
+ case SO_SELECT_ERR_QUEUE:
+ sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
+ break;
+
default:
ret = -ENOPROTOOPT;
break;
@@ -1160,6 +1164,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sock_flag(sk, SOCK_FILTER_LOCKED);
break;
+ case SO_SELECT_ERR_QUEUE:
+ v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE);
+ break;
+
default:
return -ENOPROTOOPT;
}
@@ -1298,13 +1306,12 @@ static void sk_prot_free(struct proto *prot, struct sock *sk)
module_put(owner);
}
-#ifdef CONFIG_CGROUPS
#if IS_ENABLED(CONFIG_NET_CLS_CGROUP)
-void sock_update_classid(struct sock *sk, struct task_struct *task)
+void sock_update_classid(struct sock *sk)
{
u32 classid;
- classid = task_cls_classid(task);
+ classid = task_cls_classid(current);
if (classid != sk->sk_classid)
sk->sk_classid = classid;
}
@@ -1312,16 +1319,15 @@ EXPORT_SYMBOL(sock_update_classid);
#endif
#if IS_ENABLED(CONFIG_NETPRIO_CGROUP)
-void sock_update_netprioidx(struct sock *sk, struct task_struct *task)
+void sock_update_netprioidx(struct sock *sk)
{
if (in_interrupt())
return;
- sk->sk_cgrp_prioidx = task_netprioidx(task);
+ sk->sk_cgrp_prioidx = task_netprioidx(current);
}
EXPORT_SYMBOL_GPL(sock_update_netprioidx);
#endif
-#endif
/**
* sk_alloc - All socket objects are allocated here
@@ -1347,8 +1353,8 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
sock_net_set(sk, get_net(net));
atomic_set(&sk->sk_wmem_alloc, 1);
- sock_update_classid(sk, current);
- sock_update_netprioidx(sk, current);
+ sock_update_classid(sk);
+ sock_update_netprioidx(sk);
}
return sk;
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index a29e90cf36b7..d5bef0b0f639 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -49,6 +49,39 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
}
EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
+int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+ struct sk_buff *skb, int attrtype)
+{
+ struct nlattr *attr;
+ struct sk_filter *filter;
+ unsigned int len;
+ int err = 0;
+
+ if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
+ nla_reserve(skb, attrtype, 0);
+ return 0;
+ }
+
+ rcu_read_lock();
+
+ filter = rcu_dereference(sk->sk_filter);
+ len = filter ? filter->len * sizeof(struct sock_filter) : 0;
+
+ attr = nla_reserve(skb, attrtype, len);
+ if (attr == NULL) {
+ err = -EMSGSIZE;
+ goto out;
+ }
+
+ if (filter)
+ memcpy(nla_data(attr), filter->insns, len);
+
+out:
+ rcu_read_unlock();
+ return err;
+}
+EXPORT_SYMBOL(sock_diag_put_filterinfo);
+
void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
{
mutex_lock(&sock_diag_table_mutex);
diff --git a/net/core/utils.c b/net/core/utils.c
index e3487e461939..3c7f5b51b979 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
+#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/mm.h>
#include <linux/net.h>
@@ -348,9 +349,7 @@ int mac_pton(const char *s, u8 *mac)
/* Don't dirty result unless string is valid MAC. */
for (i = 0; i < ETH_ALEN; i++) {
- if (!strchr("0123456789abcdefABCDEF", s[i * 3]))
- return 0;
- if (!strchr("0123456789abcdefABCDEF", s[i * 3 + 1]))
+ if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1]))
return 0;
if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':')
return 0;
diff --git a/net/dcb/dcbevent.c b/net/dcb/dcbevent.c
index 1d9eb7c60a68..4f72fc40bf02 100644
--- a/net/dcb/dcbevent.c
+++ b/net/dcb/dcbevent.c
@@ -20,6 +20,7 @@
#include <linux/rtnetlink.h>
#include <linux/notifier.h>
#include <linux/export.h>
+#include <net/dcbevent.h>
static ATOMIC_NOTIFIER_HEAD(dcbevent_notif_chain);
diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c
index 21291f1abcd6..40d5829ed36a 100644
--- a/net/dcb/dcbnl.c
+++ b/net/dcb/dcbnl.c
@@ -1658,7 +1658,7 @@ static const struct reply_func reply_funcs[DCB_CMD_MAX+1] = {
[DCB_CMD_CEE_GET] = { RTM_GETDCB, dcbnl_cee_get },
};
-static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct net_device *netdev;
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 4f9f5eb478f1..ebc54fef85a5 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -500,8 +500,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
return &rt->dst;
}
-static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
- struct request_values *rv_unused)
+static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
{
int err = -1;
struct sk_buff *skb;
@@ -658,7 +657,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
dreq->dreq_gss = dreq->dreq_iss;
dreq->dreq_service = service;
- if (dccp_v4_send_response(sk, req, NULL))
+ if (dccp_v4_send_response(sk, req))
goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 6e05981f271e..9c61f9c02fdb 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -213,8 +213,7 @@ out:
}
-static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
- struct request_values *rv_unused)
+static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
{
struct inet6_request_sock *ireq6 = inet6_rsk(req);
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -428,7 +427,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
dreq->dreq_gss = dreq->dreq_iss;
dreq->dreq_service = service;
- if (dccp_v6_send_response(sk, req, NULL))
+ if (dccp_v6_send_response(sk, req))
goto drop_and_free;
inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index c8da116d84a4..7d9197063ebb 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -563,7 +563,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
.len = IFNAMSIZ - 1 },
};
-static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFA_MAX+1];
@@ -607,7 +607,7 @@ errout:
return err;
}
-static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFA_MAX+1];
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index e36614eccc04..57dc159245ec 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -145,22 +145,10 @@ static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi
return NULL;
}
-__le16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type)
+static int dn_fib_count_nhs(const struct nlattr *attr)
{
- while(RTA_OK(attr,attrlen)) {
- if (attr->rta_type == type)
- return *(__le16*)RTA_DATA(attr);
- attr = RTA_NEXT(attr, attrlen);
- }
-
- return 0;
-}
-
-static int dn_fib_count_nhs(struct rtattr *rta)
-{
- int nhs = 0;
- struct rtnexthop *nhp = RTA_DATA(rta);
- int nhlen = RTA_PAYLOAD(rta);
+ struct rtnexthop *nhp = nla_data(attr);
+ int nhs = 0, nhlen = nla_len(attr);
while(nhlen >= (int)sizeof(struct rtnexthop)) {
if ((nhlen -= nhp->rtnh_len) < 0)
@@ -172,10 +160,11 @@ static int dn_fib_count_nhs(struct rtattr *rta)
return nhs;
}
-static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r)
+static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
+ const struct rtmsg *r)
{
- struct rtnexthop *nhp = RTA_DATA(rta);
- int nhlen = RTA_PAYLOAD(rta);
+ struct rtnexthop *nhp = nla_data(attr);
+ int nhlen = nla_len(attr);
change_nexthops(fi) {
int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -187,7 +176,10 @@ static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, cons
nh->nh_weight = nhp->rtnh_hops + 1;
if (attrlen) {
- nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+ struct nlattr *gw_attr;
+
+ gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
+ nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
}
nhp = RTNH_NEXT(nhp);
} endfor_nexthops(fi);
@@ -268,7 +260,8 @@ out:
}
-struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp)
+struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
+ const struct nlmsghdr *nlh, int *errp)
{
int err;
struct dn_fib_info *fi = NULL;
@@ -281,11 +274,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
goto err_inval;
- if (rta->rta_mp) {
- nhs = dn_fib_count_nhs(rta->rta_mp);
- if (nhs == 0)
- goto err_inval;
- }
+ if (attrs[RTA_MULTIPATH] &&
+ (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
+ goto err_inval;
fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);
err = -ENOBUFS;
@@ -295,53 +286,65 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
fi->fib_protocol = r->rtm_protocol;
fi->fib_nhs = nhs;
fi->fib_flags = r->rtm_flags;
- if (rta->rta_priority)
- fi->fib_priority = *rta->rta_priority;
- if (rta->rta_mx) {
- int attrlen = RTA_PAYLOAD(rta->rta_mx);
- struct rtattr *attr = RTA_DATA(rta->rta_mx);
- while(RTA_OK(attr, attrlen)) {
- unsigned int flavour = attr->rta_type;
+ if (attrs[RTA_PRIORITY])
+ fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
+
+ if (attrs[RTA_METRICS]) {
+ struct nlattr *attr;
+ int rem;
- if (flavour) {
- if (flavour > RTAX_MAX)
+ nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
+ int type = nla_type(attr);
+
+ if (type) {
+ if (type > RTAX_MAX || nla_len(attr) < 4)
goto err_inval;
- fi->fib_metrics[flavour-1] = *(unsigned int *)RTA_DATA(attr);
+
+ fi->fib_metrics[type-1] = nla_get_u32(attr);
}
- attr = RTA_NEXT(attr, attrlen);
}
}
- if (rta->rta_prefsrc)
- memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);
- if (rta->rta_mp) {
- if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)
+ if (attrs[RTA_PREFSRC])
+ fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
+
+ if (attrs[RTA_MULTIPATH]) {
+ if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
goto failure;
- if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)
+
+ if (attrs[RTA_OIF] &&
+ fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
goto err_inval;
- if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))
+
+ if (attrs[RTA_GATEWAY] &&
+ fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
goto err_inval;
} else {
struct dn_fib_nh *nh = fi->fib_nh;
- if (rta->rta_oif)
- nh->nh_oif = *rta->rta_oif;
- if (rta->rta_gw)
- memcpy(&nh->nh_gw, rta->rta_gw, 2);
+
+ if (attrs[RTA_OIF])
+ nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
+
+ if (attrs[RTA_GATEWAY])
+ nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
+
nh->nh_flags = r->rtm_flags;
nh->nh_weight = 1;
}
if (r->rtm_type == RTN_NAT) {
- if (rta->rta_gw == NULL || nhs != 1 || rta->rta_oif)
+ if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
goto err_inval;
- memcpy(&fi->fib_nh->nh_gw, rta->rta_gw, 2);
+
+ fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
goto link_it;
}
if (dn_fib_props[r->rtm_type].error) {
- if (rta->rta_gw || rta->rta_oif || rta->rta_mp)
+ if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
goto err_inval;
+
goto link_it;
}
@@ -367,8 +370,8 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
}
if (fi->fib_prefsrc) {
- if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
- memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))
+ if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
+ fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
goto err_inval;
}
@@ -486,39 +489,21 @@ void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
spin_unlock_bh(&dn_fib_multipath_lock);
}
-
-static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
-{
- int i;
-
- for(i = 1; i <= RTA_MAX; i++) {
- struct rtattr *attr = rta[i-1];
- if (attr) {
- if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
- return -EINVAL;
- if (i != RTA_MULTIPATH && i != RTA_METRICS &&
- i != RTA_TABLE)
- rta[i-1] = (struct rtattr *)RTA_DATA(attr);
- }
- }
-
- return 0;
-}
-
-static inline u32 rtm_get_table(struct rtattr **rta, u8 table)
+static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
{
- if (rta[RTA_TABLE - 1])
- table = nla_get_u32((struct nlattr *) rta[RTA_TABLE - 1]);
+ if (attrs[RTA_TABLE])
+ table = nla_get_u32(attrs[RTA_TABLE]);
return table;
}
-static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct dn_fib_table *tb;
- struct rtattr **rta = arg;
- struct rtmsg *r = NLMSG_DATA(nlh);
+ struct rtmsg *r = nlmsg_data(nlh);
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -526,22 +511,24 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
if (!net_eq(net, &init_net))
return -EINVAL;
- if (dn_fib_check_attr(r, rta))
- return -EINVAL;
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
- tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
- if (tb)
- return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
+ if (!tb)
+ return -ESRCH;
- return -ESRCH;
+ return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
}
-static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct dn_fib_table *tb;
- struct rtattr **rta = arg;
- struct rtmsg *r = NLMSG_DATA(nlh);
+ struct rtmsg *r = nlmsg_data(nlh);
+ struct nlattr *attrs[RTA_MAX+1];
+ int err;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -549,14 +536,15 @@ static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
if (!net_eq(net, &init_net))
return -EINVAL;
- if (dn_fib_check_attr(r, rta))
- return -EINVAL;
+ err = nlmsg_parse(nlh, sizeof(*r), attrs, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
- tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
- if (tb)
- return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
+ tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
+ if (!tb)
+ return -ENOBUFS;
- return -ENOBUFS;
+ return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
}
static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
@@ -566,10 +554,31 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
struct nlmsghdr nlh;
struct rtmsg rtm;
} req;
- struct dn_kern_rta rta;
+ struct {
+ struct nlattr hdr;
+ __le16 dst;
+ } dst_attr = {
+ .dst = dst,
+ };
+ struct {
+ struct nlattr hdr;
+ __le16 prefsrc;
+ } prefsrc_attr = {
+ .prefsrc = ifa->ifa_local,
+ };
+ struct {
+ struct nlattr hdr;
+ u32 oif;
+ } oif_attr = {
+ .oif = ifa->ifa_dev->dev->ifindex,
+ };
+ struct nlattr *attrs[RTA_MAX+1] = {
+ [RTA_DST] = (struct nlattr *) &dst_attr,
+ [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
+ [RTA_OIF] = (struct nlattr *) &oif_attr,
+ };
memset(&req.rtm, 0, sizeof(req.rtm));
- memset(&rta, 0, sizeof(rta));
if (type == RTN_UNICAST)
tb = dn_fib_get_table(RT_MIN_TABLE, 1);
@@ -591,14 +600,10 @@ static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifad
req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
req.rtm.rtm_type = type;
- rta.rta_dst = &dst;
- rta.rta_prefsrc = &ifa->ifa_local;
- rta.rta_oif = &ifa->ifa_dev->dev->ifindex;
-
if (cmd == RTM_NEWROUTE)
- tb->insert(tb, &req.rtm, &rta, &req.nlh, NULL);
+ tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
else
- tb->delete(tb, &req.rtm, &rta, &req.nlh, NULL);
+ tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
}
static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 5ac0e153ef83..fe32388ea24f 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1613,23 +1613,41 @@ errout:
return -EMSGSIZE;
}
+const struct nla_policy rtm_dn_policy[RTA_MAX + 1] = {
+ [RTA_DST] = { .type = NLA_U16 },
+ [RTA_SRC] = { .type = NLA_U16 },
+ [RTA_IIF] = { .type = NLA_U32 },
+ [RTA_OIF] = { .type = NLA_U32 },
+ [RTA_GATEWAY] = { .type = NLA_U16 },
+ [RTA_PRIORITY] = { .type = NLA_U32 },
+ [RTA_PREFSRC] = { .type = NLA_U16 },
+ [RTA_METRICS] = { .type = NLA_NESTED },
+ [RTA_MULTIPATH] = { .type = NLA_NESTED },
+ [RTA_TABLE] = { .type = NLA_U32 },
+ [RTA_MARK] = { .type = NLA_U32 },
+};
+
/*
* This is called by both endnodes and routers now.
*/
-static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
+static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(in_skb->sk);
- struct rtattr **rta = arg;
struct rtmsg *rtm = nlmsg_data(nlh);
struct dn_route *rt = NULL;
struct dn_skb_cb *cb;
int err;
struct sk_buff *skb;
struct flowidn fld;
+ struct nlattr *tb[RTA_MAX+1];
if (!net_eq(net, &init_net))
return -EINVAL;
+ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_dn_policy);
+ if (err < 0)
+ return err;
+
memset(&fld, 0, sizeof(fld));
fld.flowidn_proto = DNPROTO_NSP;
@@ -1639,12 +1657,14 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
skb_reset_mac_header(skb);
cb = DN_SKB_CB(skb);
- if (rta[RTA_SRC-1])
- memcpy(&fld.saddr, RTA_DATA(rta[RTA_SRC-1]), 2);
- if (rta[RTA_DST-1])
- memcpy(&fld.daddr, RTA_DATA(rta[RTA_DST-1]), 2);
- if (rta[RTA_IIF-1])
- memcpy(&fld.flowidn_iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int));
+ if (tb[RTA_SRC])
+ fld.saddr = nla_get_le16(tb[RTA_SRC]);
+
+ if (tb[RTA_DST])
+ fld.daddr = nla_get_le16(tb[RTA_DST]);
+
+ if (tb[RTA_IIF])
+ fld.flowidn_iif = nla_get_u32(tb[RTA_IIF]);
if (fld.flowidn_iif) {
struct net_device *dev;
@@ -1669,10 +1689,9 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void
if (!err && -rt->dst.error)
err = rt->dst.error;
} else {
- int oif = 0;
- if (rta[RTA_OIF - 1])
- memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
- fld.flowidn_oif = oif;
+ if (tb[RTA_OIF])
+ fld.flowidn_oif = nla_get_u32(tb[RTA_OIF]);
+
err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0);
}
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 6c2445bcaba1..86e3807052e9 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -19,7 +19,6 @@
#include <linux/sockios.h>
#include <linux/init.h>
#include <linux/skbuff.h>
-#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
@@ -224,26 +223,27 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
}
-static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern_rta *rta, struct dn_fib_info *fi)
+static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct nlattr *attrs[], struct dn_fib_info *fi)
{
struct rtnexthop *nhp;
int nhlen;
- if (rta->rta_priority && *rta->rta_priority != fi->fib_priority)
+ if (attrs[RTA_PRIORITY] &&
+ nla_get_u32(attrs[RTA_PRIORITY]) != fi->fib_priority)
return 1;
- if (rta->rta_oif || rta->rta_gw) {
- if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
- (!rta->rta_gw || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 2) == 0))
+ if (attrs[RTA_OIF] || attrs[RTA_GATEWAY]) {
+ if ((!attrs[RTA_OIF] || nla_get_u32(attrs[RTA_OIF]) == fi->fib_nh->nh_oif) &&
+ (!attrs[RTA_GATEWAY] || nla_get_le16(attrs[RTA_GATEWAY]) != fi->fib_nh->nh_gw))
return 0;
return 1;
}
- if (rta->rta_mp == NULL)
+ if (!attrs[RTA_MULTIPATH])
return 0;
- nhp = RTA_DATA(rta->rta_mp);
- nhlen = RTA_PAYLOAD(rta->rta_mp);
+ nhp = nla_data(attrs[RTA_MULTIPATH]);
+ nhlen = nla_len(attrs[RTA_MULTIPATH]);
for_nexthops(fi) {
int attrlen = nhlen - sizeof(struct rtnexthop);
@@ -254,7 +254,10 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
if (nhp->rtnh_ifindex && nhp->rtnh_ifindex != nh->nh_oif)
return 1;
if (attrlen) {
- gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);
+ struct nlattr *gw_attr;
+
+ gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
+ gw = gw_attr ? nla_get_le16(gw_attr) : 0;
if (gw && gw != nh->nh_gw)
return 1;
@@ -488,7 +491,7 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (!net_eq(net, &init_net))
return 0;
- if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
+ if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
((struct rtmsg *)nlmsg_data(cb->nlh))->rtm_flags&RTM_F_CLONED)
return dn_cache_dump(skb, cb);
@@ -517,7 +520,8 @@ out:
return skb->len;
}
-static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
{
struct dn_hash *table = (struct dn_hash *)tb->data;
struct dn_fib_node *new_f, *f, **fp, **del_fp;
@@ -536,15 +540,14 @@ static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct
return -ENOBUFS;
dz_key_0(key);
- if (rta->rta_dst) {
- __le16 dst;
- memcpy(&dst, rta->rta_dst, 2);
+ if (attrs[RTA_DST]) {
+ __le16 dst = nla_get_le16(attrs[RTA_DST]);
if (dst & ~DZ_MASK(dz))
return -EINVAL;
key = dz_key(dst, dz);
}
- if ((fi = dn_fib_create_info(r, rta, n, &err)) == NULL)
+ if ((fi = dn_fib_create_info(r, attrs, n, &err)) == NULL)
return err;
if (dz->dz_nent > (dz->dz_divisor << 2) &&
@@ -654,7 +657,8 @@ out:
}
-static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
+static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct nlattr *attrs[],
+ struct nlmsghdr *n, struct netlink_skb_parms *req)
{
struct dn_hash *table = (struct dn_hash*)tb->data;
struct dn_fib_node **fp, **del_fp, *f;
@@ -671,9 +675,8 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
return -ESRCH;
dz_key_0(key);
- if (rta->rta_dst) {
- __le16 dst;
- memcpy(&dst, rta->rta_dst, 2);
+ if (attrs[RTA_DST]) {
+ __le16 dst = nla_get_le16(attrs[RTA_DST]);
if (dst & ~DZ_MASK(dz))
return -EINVAL;
key = dz_key(dst, dz);
@@ -703,7 +706,7 @@ static int dn_fib_table_delete(struct dn_fib_table *tb, struct rtmsg *r, struct
(r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
(!r->rtm_protocol ||
fi->fib_protocol == r->rtm_protocol) &&
- dn_fib_nh_match(r, n, rta, fi) == 0)
+ dn_fib_nh_match(r, n, attrs, fi) == 0)
del_fp = fp;
}
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index dfe42012a044..2a7efe388344 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -19,7 +19,7 @@
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/spinlock.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netfilter_decnet.h>
#include <net/sock.h>
@@ -39,21 +39,21 @@ static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
unsigned char *ptr;
struct nf_dn_rtmsg *rtm;
- size = NLMSG_SPACE(rt_skb->len);
- size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
- skb = alloc_skb(size, GFP_ATOMIC);
+ size = NLMSG_ALIGN(rt_skb->len) +
+ NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
+ skb = nlmsg_new(size, GFP_ATOMIC);
if (!skb) {
*errp = -ENOMEM;
return NULL;
}
old_tail = skb->tail;
- nlh = nlmsg_put(skb, 0, 0, 0, size - sizeof(*nlh), 0);
+ nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
if (!nlh) {
kfree_skb(skb);
*errp = -ENOMEM;
return NULL;
}
- rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
+ rtm = (struct nf_dn_rtmsg *)nlmsg_data(nlh);
rtm->nfdn_ifindex = rt_skb->dev->ifindex;
ptr = NFDN_RTMSG(rtm);
skb_copy_from_linear_data(rt_skb, ptr, rt_skb->len);
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 2bc62ea857c8..0eb5d5e76dfb 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -1,6 +1,7 @@
/*
* net/dsa/dsa.c - Hardware switch handling
* Copyright (c) 2008-2009 Marvell Semiconductor
+ * Copyright (c) 2013 Florian Fainelli <florian@openwrt.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
@@ -14,6 +15,9 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <net/dsa.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/of_platform.h>
#include "dsa_priv.h"
char dsa_driver_version[] = "0.1";
@@ -287,34 +291,239 @@ static struct net_device *dev_to_net_device(struct device *dev)
return NULL;
}
+#ifdef CONFIG_OF
+static int dsa_of_setup_routing_table(struct dsa_platform_data *pd,
+ struct dsa_chip_data *cd,
+ int chip_index,
+ struct device_node *link)
+{
+ int ret;
+ const __be32 *reg;
+ int link_port_addr;
+ int link_sw_addr;
+ struct device_node *parent_sw;
+ int len;
+
+ parent_sw = of_get_parent(link);
+ if (!parent_sw)
+ return -EINVAL;
+
+ reg = of_get_property(parent_sw, "reg", &len);
+ if (!reg || (len != sizeof(*reg) * 2))
+ return -EINVAL;
+
+ link_sw_addr = be32_to_cpup(reg + 1);
+
+ if (link_sw_addr >= pd->nr_chips)
+ return -EINVAL;
+
+ /* First time routing table allocation */
+ if (!cd->rtable) {
+ cd->rtable = kmalloc(pd->nr_chips * sizeof(s8), GFP_KERNEL);
+ if (!cd->rtable)
+ return -ENOMEM;
+
+ /* default to no valid uplink/downlink */
+ memset(cd->rtable, -1, pd->nr_chips * sizeof(s8));
+ }
+
+ reg = of_get_property(link, "reg", NULL);
+ if (!reg) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ link_port_addr = be32_to_cpup(reg);
+
+ cd->rtable[link_sw_addr] = link_port_addr;
+
+ return 0;
+out:
+ kfree(cd->rtable);
+ return ret;
+}
+
+static void dsa_of_free_platform_data(struct dsa_platform_data *pd)
+{
+ int i;
+ int port_index;
+
+ for (i = 0; i < pd->nr_chips; i++) {
+ port_index = 0;
+ while (port_index < DSA_MAX_PORTS) {
+ if (pd->chip[i].port_names[port_index])
+ kfree(pd->chip[i].port_names[port_index]);
+ port_index++;
+ }
+ kfree(pd->chip[i].rtable);
+ }
+ kfree(pd->chip);
+}
+
+static int dsa_of_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child, *mdio, *ethernet, *port, *link;
+ struct mii_bus *mdio_bus;
+ struct platform_device *ethernet_dev;
+ struct dsa_platform_data *pd;
+ struct dsa_chip_data *cd;
+ const char *port_name;
+ int chip_index, port_index;
+ const unsigned int *sw_addr, *port_reg;
+ int ret;
+
+ mdio = of_parse_phandle(np, "dsa,mii-bus", 0);
+ if (!mdio)
+ return -EINVAL;
+
+ mdio_bus = of_mdio_find_bus(mdio);
+ if (!mdio_bus)
+ return -EINVAL;
+
+ ethernet = of_parse_phandle(np, "dsa,ethernet", 0);
+ if (!ethernet)
+ return -EINVAL;
+
+ ethernet_dev = of_find_device_by_node(ethernet);
+ if (!ethernet_dev)
+ return -ENODEV;
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pdev->dev.platform_data = pd;
+ pd->netdev = &ethernet_dev->dev;
+ pd->nr_chips = of_get_child_count(np);
+ if (pd->nr_chips > DSA_MAX_SWITCHES)
+ pd->nr_chips = DSA_MAX_SWITCHES;
+
+ pd->chip = kzalloc(pd->nr_chips * sizeof(struct dsa_chip_data),
+ GFP_KERNEL);
+ if (!pd->chip) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ chip_index = 0;
+ for_each_available_child_of_node(np, child) {
+ cd = &pd->chip[chip_index];
+
+ cd->mii_bus = &mdio_bus->dev;
+
+ sw_addr = of_get_property(child, "reg", NULL);
+ if (!sw_addr)
+ continue;
+
+ cd->sw_addr = be32_to_cpup(sw_addr);
+ if (cd->sw_addr > PHY_MAX_ADDR)
+ continue;
+
+ for_each_available_child_of_node(child, port) {
+ port_reg = of_get_property(port, "reg", NULL);
+ if (!port_reg)
+ continue;
+
+ port_index = be32_to_cpup(port_reg);
+
+ port_name = of_get_property(port, "label", NULL);
+ if (!port_name)
+ continue;
+
+ cd->port_names[port_index] = kstrdup(port_name,
+ GFP_KERNEL);
+ if (!cd->port_names[port_index]) {
+ ret = -ENOMEM;
+ goto out_free_chip;
+ }
+
+ link = of_parse_phandle(port, "link", 0);
+
+ if (!strcmp(port_name, "dsa") && link &&
+ pd->nr_chips > 1) {
+ ret = dsa_of_setup_routing_table(pd, cd,
+ chip_index, link);
+ if (ret)
+ goto out_free_chip;
+ }
+
+ if (port_index == DSA_MAX_PORTS)
+ break;
+ }
+ }
+
+ return 0;
+
+out_free_chip:
+ dsa_of_free_platform_data(pd);
+out_free:
+ kfree(pd);
+ pdev->dev.platform_data = NULL;
+ return ret;
+}
+
+static void dsa_of_remove(struct platform_device *pdev)
+{
+ struct dsa_platform_data *pd = pdev->dev.platform_data;
+
+ if (!pdev->dev.of_node)
+ return;
+
+ dsa_of_free_platform_data(pd);
+ kfree(pd);
+}
+#else
+static inline int dsa_of_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static inline void dsa_of_remove(struct platform_device *pdev)
+{
+}
+#endif
+
static int dsa_probe(struct platform_device *pdev)
{
static int dsa_version_printed;
struct dsa_platform_data *pd = pdev->dev.platform_data;
struct net_device *dev;
struct dsa_switch_tree *dst;
- int i;
+ int i, ret;
if (!dsa_version_printed++)
printk(KERN_NOTICE "Distributed Switch Architecture "
"driver version %s\n", dsa_driver_version);
+ if (pdev->dev.of_node) {
+ ret = dsa_of_probe(pdev);
+ if (ret)
+ return ret;
+
+ pd = pdev->dev.platform_data;
+ }
+
if (pd == NULL || pd->netdev == NULL)
return -EINVAL;
dev = dev_to_net_device(pd->netdev);
- if (dev == NULL)
- return -EINVAL;
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
if (dev->dsa_ptr != NULL) {
dev_put(dev);
- return -EEXIST;
+ ret = -EEXIST;
+ goto out;
}
dst = kzalloc(sizeof(*dst), GFP_KERNEL);
if (dst == NULL) {
dev_put(dev);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
platform_set_drvdata(pdev, dst);
@@ -366,6 +575,11 @@ static int dsa_probe(struct platform_device *pdev)
}
return 0;
+
+out:
+ dsa_of_remove(pdev);
+
+ return ret;
}
static int dsa_remove(struct platform_device *pdev)
@@ -385,6 +599,8 @@ static int dsa_remove(struct platform_device *pdev)
dsa_switch_destroy(ds);
}
+ dsa_of_remove(pdev);
+
return 0;
}
@@ -392,6 +608,12 @@ static void dsa_shutdown(struct platform_device *pdev)
{
}
+static const struct of_device_id dsa_of_match_table[] = {
+ { .compatible = "marvell,dsa", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dsa_of_match_table);
+
static struct platform_driver dsa_driver = {
.probe = dsa_probe,
.remove = dsa_remove,
@@ -399,6 +621,7 @@ static struct platform_driver dsa_driver = {
.driver = {
.name = "dsa",
.owner = THIS_MODULE,
+ .of_match_table = dsa_of_match_table,
},
};
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index a36c85eab5b4..5359560926bc 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -195,7 +195,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
if (netdev_uses_trailer_tags(dev))
return htons(ETH_P_TRAILER);
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
return eth->h_proto;
/*
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 43b95ca61114..55e1fd5b3e56 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -104,6 +104,7 @@ static const u8 lowpan_llprefix[] = {0xfe, 0x80};
struct lowpan_dev_info {
struct net_device *real_dev; /* real WPAN device ptr */
struct mutex dev_list_mtx; /* mutex for list ops */
+ unsigned short fragment_tag;
};
struct lowpan_dev_record {
@@ -120,7 +121,6 @@ struct lowpan_fragment {
struct list_head list; /* fragments list */
};
-static unsigned short fragment_tag;
static LIST_HEAD(lowpan_fragments);
static DEFINE_SPINLOCK(flist_lock);
@@ -284,6 +284,9 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
/* checksum is always inline */
memcpy(*hc06_ptr, &uh->check, 2);
*hc06_ptr += 2;
+
+ /* skip the UDP header */
+ skb_pull(skb, sizeof(struct udphdr));
}
static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
@@ -309,9 +312,8 @@ static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
}
static int
-lowpan_uncompress_udp_header(struct sk_buff *skb)
+lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
{
- struct udphdr *uh = udp_hdr(skb);
u8 tmp;
if (!uh)
@@ -358,6 +360,14 @@ lowpan_uncompress_udp_header(struct sk_buff *skb)
/* copy checksum */
memcpy(&uh->check, &skb->data[0], 2);
skb_pull(skb, 2);
+
+ /*
+ * UDP lenght needs to be infered from the lower layers
+ * here, we obtain the hint from the remaining size of the
+ * frame
+ */
+ uh->len = htons(skb->len + sizeof(struct udphdr));
+ pr_debug("uncompressed UDP length: src = %d", uh->len);
} else {
pr_debug("ERROR: unsupported NH format\n");
goto err;
@@ -572,17 +582,31 @@ static int lowpan_header_create(struct sk_buff *skb,
* this isn't implemented in mainline yet, so currently we assign 0xff
*/
{
+ mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+ mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+
/* prepare wpan address data */
sa.addr_type = IEEE802154_ADDR_LONG;
- sa.pan_id = 0xff;
-
- da.addr_type = IEEE802154_ADDR_LONG;
- da.pan_id = 0xff;
+ sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
- memcpy(&(da.hwaddr), daddr, 8);
memcpy(&(sa.hwaddr), saddr, 8);
+ /* intra-PAN communications */
+ da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
- mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+ /*
+ * if the destination address is the broadcast address, use the
+ * corresponding short address
+ */
+ if (lowpan_is_addr_broadcast(daddr)) {
+ da.addr_type = IEEE802154_ADDR_SHORT;
+ da.short_addr = IEEE802154_ADDR_BROADCAST;
+ } else {
+ da.addr_type = IEEE802154_ADDR_LONG;
+ memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
+
+ /* request acknowledgment */
+ mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+ }
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
type, (void *)&da, (void *)&sa, skb->len);
@@ -650,7 +674,7 @@ static void lowpan_fragment_timer_expired(unsigned long entry_addr)
}
static struct lowpan_fragment *
-lowpan_alloc_new_frame(struct sk_buff *skb, u8 len, u16 tag)
+lowpan_alloc_new_frame(struct sk_buff *skb, u16 len, u16 tag)
{
struct lowpan_fragment *frame;
@@ -720,7 +744,7 @@ lowpan_process_data(struct sk_buff *skb)
{
struct lowpan_fragment *frame;
/* slen stores the rightmost 8 bits of the 11 bits length */
- u8 slen, offset;
+ u8 slen, offset = 0;
u16 len, tag;
bool found = false;
@@ -731,6 +755,18 @@ lowpan_process_data(struct sk_buff *skb)
/* adds the 3 MSB to the 8 LSB to retrieve the 11 bits length */
len = ((iphc0 & 7) << 8) | slen;
+ if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) {
+ pr_debug("%s received a FRAG1 packet (tag: %d, "
+ "size of the entire IP packet: %d)",
+ __func__, tag, len);
+ } else { /* FRAGN */
+ if (lowpan_fetch_skb_u8(skb, &offset))
+ goto unlock_and_drop;
+ pr_debug("%s received a FRAGN packet (tag: %d, "
+ "size of the entire IP packet: %d, "
+ "offset: %d)", __func__, tag, len, offset * 8);
+ }
+
/*
* check if frame assembling with the same tag is
* already in progress
@@ -745,17 +781,13 @@ lowpan_process_data(struct sk_buff *skb)
/* alloc new frame structure */
if (!found) {
+ pr_debug("%s first fragment received for tag %d, "
+ "begin packet reassembly", __func__, tag);
frame = lowpan_alloc_new_frame(skb, len, tag);
if (!frame)
goto unlock_and_drop;
}
- if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
- goto unlock_and_drop;
-
- if (lowpan_fetch_skb_u8(skb, &offset)) /* fetch offset */
- goto unlock_and_drop;
-
/* if payload fits buffer, copy it */
if (likely((offset * 8 + skb->len) <= frame->length))
skb_copy_to_linear_data_offset(frame->skb, offset * 8,
@@ -773,6 +805,9 @@ lowpan_process_data(struct sk_buff *skb)
list_del(&frame->list);
spin_unlock_bh(&flist_lock);
+ pr_debug("%s successfully reassembled fragment "
+ "(tag %d)", __func__, tag);
+
dev_kfree_skb(skb);
skb = frame->skb;
kfree(frame);
@@ -918,10 +953,35 @@ lowpan_process_data(struct sk_buff *skb)
}
/* UDP data uncompression */
- if (iphc0 & LOWPAN_IPHC_NH_C)
- if (lowpan_uncompress_udp_header(skb))
+ if (iphc0 & LOWPAN_IPHC_NH_C) {
+ struct udphdr uh;
+ struct sk_buff *new;
+ if (lowpan_uncompress_udp_header(skb, &uh))
goto drop;
+ /*
+ * replace the compressed UDP head by the uncompressed UDP
+ * header
+ */
+ new = skb_copy_expand(skb, sizeof(struct udphdr),
+ skb_tailroom(skb), GFP_ATOMIC);
+ kfree_skb(skb);
+
+ if (!new)
+ return -ENOMEM;
+
+ skb = new;
+
+ skb_push(skb, sizeof(struct udphdr));
+ skb_reset_transport_header(skb);
+ skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
+
+ lowpan_raw_dump_table(__func__, "raw UDP header dump",
+ (u8 *)&uh, sizeof(uh));
+
+ hdr.nexthdr = UIP_PROTO_UDP;
+ }
+
/* Not fragmented package */
hdr.payload_len = htons(skb->len);
@@ -969,13 +1029,13 @@ static int lowpan_get_mac_header_length(struct sk_buff *skb)
static int
lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
- int mlen, int plen, int offset)
+ int mlen, int plen, int offset, int type)
{
struct sk_buff *frag;
int hlen, ret;
- /* if payload length is zero, therefore it's a first fragment */
- hlen = (plen == 0 ? LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE);
+ hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
+ LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
@@ -1003,14 +1063,14 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
}
static int
-lowpan_skb_fragmentation(struct sk_buff *skb)
+lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
{
int err, header_length, payload_length, tag, offset = 0;
u8 head[5];
header_length = lowpan_get_mac_header_length(skb);
payload_length = skb->len - header_length;
- tag = fragment_tag++;
+ tag = lowpan_dev_info(dev)->fragment_tag++;
/* first fragment header */
head[0] = LOWPAN_DISPATCH_FRAG1 | ((payload_length >> 8) & 0x7);
@@ -1018,7 +1078,16 @@ lowpan_skb_fragmentation(struct sk_buff *skb)
head[2] = tag >> 8;
head[3] = tag & 0xff;
- err = lowpan_fragment_xmit(skb, head, header_length, 0, 0);
+ err = lowpan_fragment_xmit(skb, head, header_length, LOWPAN_FRAG_SIZE,
+ 0, LOWPAN_DISPATCH_FRAG1);
+
+ if (err) {
+ pr_debug("%s unable to send FRAG1 packet (tag: %d)",
+ __func__, tag);
+ goto exit;
+ }
+
+ offset = LOWPAN_FRAG_SIZE;
/* next fragment header */
head[0] &= ~LOWPAN_DISPATCH_FRAG1;
@@ -1033,10 +1102,17 @@ lowpan_skb_fragmentation(struct sk_buff *skb)
len = payload_length - offset;
err = lowpan_fragment_xmit(skb, head, header_length,
- len, offset);
+ len, offset, LOWPAN_DISPATCH_FRAGN);
+ if (err) {
+ pr_debug("%s unable to send a subsequent FRAGN packet "
+ "(tag: %d, offset: %d", __func__, tag, offset);
+ goto exit;
+ }
+
offset += len;
}
+exit:
return err;
}
@@ -1059,14 +1135,14 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
}
pr_debug("frame is too big, fragmentation is needed\n");
- err = lowpan_skb_fragmentation(skb);
+ err = lowpan_skb_fragmentation(skb, dev);
error:
dev_kfree_skb(skb);
out:
- if (err < 0)
+ if (err)
pr_debug("ERROR: xmit failed\n");
- return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
+ return (err < 0) ? NET_XMIT_DROP : err;
}
static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
@@ -1087,6 +1163,12 @@ static u16 lowpan_get_short_addr(const struct net_device *dev)
return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
}
+static u8 lowpan_get_dsn(const struct net_device *dev)
+{
+ struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+ return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev);
+}
+
static struct header_ops lowpan_header_ops = {
.create = lowpan_header_create,
};
@@ -1100,6 +1182,7 @@ static struct ieee802154_mlme_ops lowpan_mlme = {
.get_pan_id = lowpan_get_pan_id,
.get_phy = lowpan_get_phy,
.get_short_addr = lowpan_get_short_addr,
+ .get_dsn = lowpan_get_dsn,
};
static void lowpan_setup(struct net_device *dev)
@@ -1203,6 +1286,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
return -ENODEV;
lowpan_dev_info(dev)->real_dev = real_dev;
+ lowpan_dev_info(dev)->fragment_tag = 0;
mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
entry = kzalloc(sizeof(struct lowpan_dev_record), GFP_KERNEL);
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
index bba5f8336317..4b8f917658b5 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -92,9 +92,10 @@
*/
#define lowpan_is_iid_16_bit_compressable(a) \
((((a)->s6_addr16[4]) == 0) && \
- (((a)->s6_addr16[5]) == 0) && \
- (((a)->s6_addr16[6]) == 0) && \
- ((((a)->s6_addr[14]) & 0x80) == 0))
+ (((a)->s6_addr[10]) == 0) && \
+ (((a)->s6_addr[11]) == 0xff) && \
+ (((a)->s6_addr[12]) == 0xfe) && \
+ (((a)->s6_addr[13]) == 0))
/* multicast address */
#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index e0da175f8e5b..581a59504bd5 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -291,6 +291,9 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
size_t copied = 0;
int err = -EOPNOTSUPP;
struct sk_buff *skb;
+ struct sockaddr_ieee802154 *saddr;
+
+ saddr = (struct sockaddr_ieee802154 *)msg->msg_name;
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
@@ -309,6 +312,13 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
sock_recv_ts_and_drops(msg, sk, skb);
+ if (saddr) {
+ saddr->family = AF_IEEE802154;
+ saddr->addr = mac_cb(skb)->sa;
+ }
+ if (addr_len)
+ *addr_len = sizeof(*saddr);
+
if (flags & MSG_TRUNC)
copied = skb->len;
done:
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 97351e1d07a4..7e49bbcc6967 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -64,8 +64,8 @@ struct sk_buff *ieee802154_nl_create(int flags, u8 req)
int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group)
{
- /* XXX: nlh is right at the start of msg */
- void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
+ struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ void *hdr = genlmsg_data(nlmsg_data(nlh));
if (genlmsg_end(msg, hdr) < 0)
goto out;
@@ -97,8 +97,8 @@ struct sk_buff *ieee802154_nl_new_reply(struct genl_info *info,
int ieee802154_nl_reply(struct sk_buff *msg, struct genl_info *info)
{
- /* XXX: nlh is right at the start of msg */
- void *hdr = genlmsg_data(NLMSG_DATA(msg->data));
+ struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ void *hdr = genlmsg_data(nlmsg_data(nlh));
if (genlmsg_end(msg, hdr) < 0)
goto out;
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 96bb08abece2..b0bdd8c51e9c 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -315,7 +315,7 @@ static int ieee802154_associate_req(struct sk_buff *skb,
struct net_device *dev;
struct ieee802154_addr addr;
u8 page;
- int ret = -EINVAL;
+ int ret = -EOPNOTSUPP;
if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
@@ -327,6 +327,8 @@ static int ieee802154_associate_req(struct sk_buff *skb,
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
+ if (!ieee802154_mlme_ops(dev)->assoc_req)
+ goto out;
if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG;
@@ -350,6 +352,7 @@ static int ieee802154_associate_req(struct sk_buff *skb,
page,
nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
+out:
dev_put(dev);
return ret;
}
@@ -359,7 +362,7 @@ static int ieee802154_associate_resp(struct sk_buff *skb,
{
struct net_device *dev;
struct ieee802154_addr addr;
- int ret = -EINVAL;
+ int ret = -EOPNOTSUPP;
if (!info->attrs[IEEE802154_ATTR_STATUS] ||
!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
@@ -369,6 +372,8 @@ static int ieee802154_associate_resp(struct sk_buff *skb,
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
+ if (!ieee802154_mlme_ops(dev)->assoc_resp)
+ goto out;
addr.addr_type = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
@@ -380,6 +385,7 @@ static int ieee802154_associate_resp(struct sk_buff *skb,
nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
+out:
dev_put(dev);
return ret;
}
@@ -389,7 +395,7 @@ static int ieee802154_disassociate_req(struct sk_buff *skb,
{
struct net_device *dev;
struct ieee802154_addr addr;
- int ret = -EINVAL;
+ int ret = -EOPNOTSUPP;
if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
!info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
@@ -399,6 +405,8 @@ static int ieee802154_disassociate_req(struct sk_buff *skb,
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
+ if (!ieee802154_mlme_ops(dev)->disassoc_req)
+ goto out;
if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG;
@@ -415,6 +423,7 @@ static int ieee802154_disassociate_req(struct sk_buff *skb,
ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
+out:
dev_put(dev);
return ret;
}
@@ -432,7 +441,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
u8 channel, bcn_ord, sf_ord;
u8 page;
int pan_coord, blx, coord_realign;
- int ret;
+ int ret = -EOPNOTSUPP;
if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
!info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
@@ -448,6 +457,8 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
+ if (!ieee802154_mlme_ops(dev)->start_req)
+ goto out;
addr.addr_type = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16(
@@ -476,6 +487,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
bcn_ord, sf_ord, pan_coord, blx, coord_realign);
+out:
dev_put(dev);
return ret;
}
@@ -483,7 +495,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
{
struct net_device *dev;
- int ret;
+ int ret = -EOPNOTSUPP;
u8 type;
u32 channels;
u8 duration;
@@ -497,6 +509,8 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
+ if (!ieee802154_mlme_ops(dev)->scan_req)
+ goto out;
type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
@@ -511,6 +525,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
duration);
+out:
dev_put(dev);
return ret;
}
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 7944df768454..8603ca827104 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -166,6 +166,7 @@ config IP_PNP_RARP
config NET_IPIP
tristate "IP: tunneling"
select INET_TUNNEL
+ select NET_IP_TUNNEL
---help---
Tunneling means encapsulating data of one protocol type within
another protocol and sending it over a channel that understands the
@@ -186,9 +187,14 @@ config NET_IPGRE_DEMUX
This is helper module to demultiplex GRE packets on GRE version field criteria.
Required by ip_gre and pptp modules.
+config NET_IP_TUNNEL
+ tristate
+ default n
+
config NET_IPGRE
tristate "IP: GRE tunnels over IP"
depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX
+ select NET_IP_TUNNEL
help
Tunneling means encapsulating data of one protocol type within
another protocol and sending it over a channel that understands the
@@ -313,6 +319,7 @@ config SYN_COOKIES
config NET_IPVTI
tristate "Virtual (secure) IP: tunneling"
select INET_TUNNEL
+ select NET_IP_TUNNEL
depends on INET_XFRM_MODE_TUNNEL
---help---
Tunneling means encapsulating data of one protocol type within
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 15ca63ec604e..089cb9f36387 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -13,6 +13,7 @@ obj-y := route.o inetpeer.o protocol.o \
fib_frontend.o fib_semantics.o fib_trie.o \
inet_fragment.o ping.o
+obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index c929d9c1c4b6..c61b3bb87a16 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -111,10 +111,10 @@
#include <net/sock.h>
#include <net/raw.h>
#include <net/icmp.h>
-#include <net/ipip.h>
#include <net/inet_common.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
+#include <net/secure_seq.h>
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
@@ -263,8 +263,10 @@ void build_ehash_secret(void)
get_random_bytes(&rnd, sizeof(rnd));
} while (rnd == 0);
- if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0)
+ if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) {
get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret));
+ net_secret_init();
+ }
}
EXPORT_SYMBOL(build_ehash_secret);
@@ -1283,9 +1285,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
int ihl;
int id;
unsigned int offset = 0;
-
- if (!(features & NETIF_F_V4_CSUM))
- features &= ~NETIF_F_SG;
+ bool tunnel;
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 |
@@ -1293,6 +1293,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_GRE |
+ SKB_GSO_UDP_TUNNEL |
0)))
goto out;
@@ -1307,6 +1308,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, ihl)))
goto out;
+ tunnel = !!skb->encapsulation;
+
__skb_pull(skb, ihl);
skb_reset_transport_header(skb);
iph = ip_hdr(skb);
@@ -1326,7 +1329,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
skb = segs;
do {
iph = ip_hdr(skb);
- if (proto == IPPROTO_UDP) {
+ if (!tunnel && proto == IPPROTO_UDP) {
iph->id = htons(id);
iph->frag_off = htons(offset >> 3);
if (skb->next != NULL)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index fea4929f6200..247ec1951c35 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -654,11 +654,19 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
arp_ptr += dev->addr_len;
memcpy(arp_ptr, &src_ip, 4);
arp_ptr += 4;
- if (target_hw != NULL)
- memcpy(arp_ptr, target_hw, dev->addr_len);
- else
- memset(arp_ptr, 0, dev->addr_len);
- arp_ptr += dev->addr_len;
+
+ switch (dev->type) {
+#if IS_ENABLED(CONFIG_FIREWIRE_NET)
+ case ARPHRD_IEEE1394:
+ break;
+#endif
+ default:
+ if (target_hw != NULL)
+ memcpy(arp_ptr, target_hw, dev->addr_len);
+ else
+ memset(arp_ptr, 0, dev->addr_len);
+ arp_ptr += dev->addr_len;
+ }
memcpy(arp_ptr, &dest_ip, 4);
return skb;
@@ -781,7 +789,14 @@ static int arp_process(struct sk_buff *skb)
arp_ptr += dev->addr_len;
memcpy(&sip, arp_ptr, 4);
arp_ptr += 4;
- arp_ptr += dev->addr_len;
+ switch (dev_type) {
+#if IS_ENABLED(CONFIG_FIREWIRE_NET)
+ case ARPHRD_IEEE1394:
+ break;
+#endif
+ default:
+ arp_ptr += dev->addr_len;
+ }
memcpy(&tip, arp_ptr, 4);
/*
* Check for bad requests for 127.x.x.x and requests for multicast
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index f678507bc829..dfc39d4d48b7 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -536,7 +536,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
return NULL;
}
-static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFA_MAX+1];
@@ -587,13 +587,16 @@ static void check_lifetime(struct work_struct *work)
{
unsigned long now, next, next_sec, next_sched;
struct in_ifaddr *ifa;
+ struct hlist_node *n;
int i;
now = jiffies;
next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
- rcu_read_lock();
for (i = 0; i < IN4_ADDR_HSIZE; i++) {
+ bool change_needed = false;
+
+ rcu_read_lock();
hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) {
unsigned long age;
@@ -606,16 +609,7 @@ static void check_lifetime(struct work_struct *work)
if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
age >= ifa->ifa_valid_lft) {
- struct in_ifaddr **ifap ;
-
- rtnl_lock();
- for (ifap = &ifa->ifa_dev->ifa_list;
- *ifap != NULL; ifap = &ifa->ifa_next) {
- if (*ifap == ifa)
- inet_del_ifa(ifa->ifa_dev,
- ifap, 1);
- }
- rtnl_unlock();
+ change_needed = true;
} else if (ifa->ifa_preferred_lft ==
INFINITY_LIFE_TIME) {
continue;
@@ -625,10 +619,8 @@ static void check_lifetime(struct work_struct *work)
next = ifa->ifa_tstamp +
ifa->ifa_valid_lft * HZ;
- if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) {
- ifa->ifa_flags |= IFA_F_DEPRECATED;
- rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
- }
+ if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
+ change_needed = true;
} else if (time_before(ifa->ifa_tstamp +
ifa->ifa_preferred_lft * HZ,
next)) {
@@ -636,8 +628,42 @@ static void check_lifetime(struct work_struct *work)
ifa->ifa_preferred_lft * HZ;
}
}
+ rcu_read_unlock();
+ if (!change_needed)
+ continue;
+ rtnl_lock();
+ hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) {
+ unsigned long age;
+
+ if (ifa->ifa_flags & IFA_F_PERMANENT)
+ continue;
+
+ /* We try to batch several events at once. */
+ age = (now - ifa->ifa_tstamp +
+ ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+
+ if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME &&
+ age >= ifa->ifa_valid_lft) {
+ struct in_ifaddr **ifap;
+
+ for (ifap = &ifa->ifa_dev->ifa_list;
+ *ifap != NULL; ifap = &(*ifap)->ifa_next) {
+ if (*ifap == ifa) {
+ inet_del_ifa(ifa->ifa_dev,
+ ifap, 1);
+ break;
+ }
+ }
+ } else if (ifa->ifa_preferred_lft !=
+ INFINITY_LIFE_TIME &&
+ age >= ifa->ifa_preferred_lft &&
+ !(ifa->ifa_flags & IFA_F_DEPRECATED)) {
+ ifa->ifa_flags |= IFA_F_DEPRECATED;
+ rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0);
+ }
+ }
+ rtnl_unlock();
}
- rcu_read_unlock();
next_sec = round_jiffies_up(next);
next_sched = next;
@@ -775,7 +801,7 @@ static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa)
return NULL;
}
-static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct in_ifaddr *ifa;
@@ -802,8 +828,12 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
if (nlh->nlmsg_flags & NLM_F_EXCL ||
!(nlh->nlmsg_flags & NLM_F_REPLACE))
return -EEXIST;
-
- set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
+ ifa = ifa_existing;
+ set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+ cancel_delayed_work(&check_lifetime_work);
+ schedule_delayed_work(&check_lifetime_work, 0);
+ rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
+ blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
}
return 0;
}
@@ -1499,6 +1529,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
idx = 0;
head = &net->dev_index_head[h];
rcu_read_lock();
+ cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
+ net->dev_base_seq;
hlist_for_each_entry_rcu(dev, head, index_hlist) {
if (idx < s_idx)
goto cont;
@@ -1519,6 +1551,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_unlock();
goto done;
}
+ nl_dump_check_consistent(cb, nlmsg_hdr(skb));
}
cont:
idx++;
@@ -1730,8 +1763,7 @@ static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
};
static int inet_netconf_get_devconf(struct sk_buff *in_skb,
- struct nlmsghdr *nlh,
- void *arg)
+ struct nlmsghdr *nlh)
{
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[NETCONFA_MAX+1];
@@ -1791,6 +1823,77 @@ errout:
return err;
}
+static int inet_netconf_dump_devconf(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ int h, s_h;
+ int idx, s_idx;
+ struct net_device *dev;
+ struct in_device *in_dev;
+ struct hlist_head *head;
+
+ s_h = cb->args[0];
+ s_idx = idx = cb->args[1];
+
+ for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ idx = 0;
+ head = &net->dev_index_head[h];
+ rcu_read_lock();
+ cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
+ net->dev_base_seq;
+ hlist_for_each_entry_rcu(dev, head, index_hlist) {
+ if (idx < s_idx)
+ goto cont;
+ in_dev = __in_dev_get_rcu(dev);
+ if (!in_dev)
+ goto cont;
+
+ if (inet_netconf_fill_devconf(skb, dev->ifindex,
+ &in_dev->cnf,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF,
+ NLM_F_MULTI,
+ -1) <= 0) {
+ rcu_read_unlock();
+ goto done;
+ }
+ nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+cont:
+ idx++;
+ }
+ rcu_read_unlock();
+ }
+ if (h == NETDEV_HASHENTRIES) {
+ if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
+ net->ipv4.devconf_all,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF, NLM_F_MULTI,
+ -1) <= 0)
+ goto done;
+ else
+ h++;
+ }
+ if (h == NETDEV_HASHENTRIES + 1) {
+ if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
+ net->ipv4.devconf_dflt,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF, NLM_F_MULTI,
+ -1) <= 0)
+ goto done;
+ else
+ h++;
+ }
+done:
+ cb->args[0] = h;
+ cb->args[1] = idx;
+
+ return skb->len;
+}
+
#ifdef CONFIG_SYSCTL
static void devinet_copy_dflt_conf(struct net *net, int i)
@@ -2195,6 +2298,6 @@ void __init devinet_init(void)
rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL);
rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL);
rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf,
- NULL, NULL);
+ inet_netconf_dump_devconf, NULL);
}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 3b4f0cd2e63e..4cfe34d4cc96 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -139,8 +139,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
/* skb is pure payload to encrypt */
- err = -ENOMEM;
-
esp = x->data;
aead = esp->aead;
alen = crypto_aead_authsize(aead);
@@ -176,8 +174,10 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
}
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
- if (!tmp)
+ if (!tmp) {
+ err = -ENOMEM;
goto error;
+ }
seqhi = esp_tmp_seqhi(tmp);
iv = esp_tmp_iv(aead, tmp, seqhilen);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index eb4bb12b3eb4..c7629a209f9d 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -604,7 +604,7 @@ errout:
return err;
}
-static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct fib_config cfg;
@@ -626,7 +626,7 @@ errout:
return err;
}
-static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct fib_config cfg;
@@ -957,8 +957,8 @@ static void nl_fib_input(struct sk_buff *skb)
net = sock_net(skb->sk);
nlh = nlmsg_hdr(skb);
- if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
- nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn)))
+ if (skb->len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len ||
+ nlmsg_len(nlh) < sizeof(*frn))
return;
skb = skb_clone(skb, GFP_KERNEL);
@@ -966,7 +966,7 @@ static void nl_fib_input(struct sk_buff *skb)
return;
nlh = nlmsg_hdr(skb);
- frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
+ frn = (struct fib_result_nl *) nlmsg_data(nlh);
tb = fib_get_table(net, frn->tb_id_in);
nl_fib_lookup(frn, tb);
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
index 7a4c710c4cdd..d2d5a99fba09 100644
--- a/net/ipv4/gre.c
+++ b/net/ipv4/gre.c
@@ -27,11 +27,6 @@
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
static DEFINE_SPINLOCK(gre_proto_lock);
-struct gre_base_hdr {
- __be16 flags;
- __be16 protocol;
-};
-#define GRE_HEADER_SECTION 4
int gre_add_protocol(const struct gre_protocol *proto, u8 version)
{
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 3ac5dff79627..76e10b47e053 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -881,7 +881,7 @@ int icmp_rcv(struct sk_buff *skb)
case CHECKSUM_NONE:
skb->csum = 0;
if (__skb_checksum_complete(skb))
- goto error;
+ goto csum_error;
}
if (!pskb_pull(skb, sizeof(*icmph)))
@@ -929,6 +929,8 @@ int icmp_rcv(struct sk_buff *skb)
drop:
kfree_skb(skb);
return 0;
+csum_error:
+ ICMP_INC_STATS_BH(net, ICMP_MIB_CSUMERRORS);
error:
ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
goto drop;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 786d97aee751..6acb541c9091 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -559,7 +559,7 @@ static inline void syn_ack_recalc(struct request_sock *req, const int thresh,
int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req)
{
- int err = req->rsk_ops->rtx_syn_ack(parent, req, NULL);
+ int err = req->rsk_ops->rtx_syn_ack(parent, req);
if (!err)
req->num_retrans++;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 7afa2c3c788f..5f648751fce2 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -158,7 +158,9 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
#define EXPIRES_IN_MS(tmo) DIV_ROUND_UP((tmo - jiffies) * 1000, HZ)
- if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
+ if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
r->idiag_timer = 1;
r->idiag_retrans = icsk->icsk_retransmits;
r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
@@ -322,7 +324,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
}
err = sk_diag_fill(sk, rep, req,
- sk_user_ns(NETLINK_CB(in_skb).ssk),
+ sk_user_ns(NETLINK_CB(in_skb).sk),
NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, nlh);
if (err < 0) {
@@ -628,7 +630,7 @@ static int inet_csk_diag_dump(struct sock *sk,
return 0;
return inet_csk_diag_fill(sk, skb, r,
- sk_user_ns(NETLINK_CB(cb->skb).ssk),
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
}
@@ -803,7 +805,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
}
err = inet_diag_fill_req(skb, sk, req,
- sk_user_ns(NETLINK_CB(cb->skb).ssk),
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, cb->nlh);
if (err < 0) {
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index f4fd23de9b13..e97d66a1fdde 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -23,6 +23,28 @@
#include <net/sock.h>
#include <net/inet_frag.h>
+#include <net/inet_ecn.h>
+
+/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements
+ * Value : 0xff if frame should be dropped.
+ * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field
+ */
+const u8 ip_frag_ecn_table[16] = {
+ /* at least one fragment had CE, and others ECT_0 or ECT_1 */
+ [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE,
+ [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
+ [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
+
+ /* invalid combinations : drop frame */
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff,
+ [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
+};
+EXPORT_SYMBOL(ip_frag_ecn_table);
static void inet_frag_secret_rebuild(unsigned long dummy)
{
@@ -30,20 +52,27 @@ static void inet_frag_secret_rebuild(unsigned long dummy)
unsigned long now = jiffies;
int i;
+ /* Per bucket lock NOT needed here, due to write lock protection */
write_lock(&f->lock);
+
get_random_bytes(&f->rnd, sizeof(u32));
for (i = 0; i < INETFRAGS_HASHSZ; i++) {
+ struct inet_frag_bucket *hb;
struct inet_frag_queue *q;
struct hlist_node *n;
- hlist_for_each_entry_safe(q, n, &f->hash[i], list) {
+ hb = &f->hash[i];
+ hlist_for_each_entry_safe(q, n, &hb->chain, list) {
unsigned int hval = f->hashfn(q);
if (hval != i) {
+ struct inet_frag_bucket *hb_dest;
+
hlist_del(&q->list);
/* Relink to new hash chain. */
- hlist_add_head(&q->list, &f->hash[hval]);
+ hb_dest = &f->hash[hval];
+ hlist_add_head(&q->list, &hb_dest->chain);
}
}
}
@@ -56,9 +85,12 @@ void inet_frags_init(struct inet_frags *f)
{
int i;
- for (i = 0; i < INETFRAGS_HASHSZ; i++)
- INIT_HLIST_HEAD(&f->hash[i]);
+ for (i = 0; i < INETFRAGS_HASHSZ; i++) {
+ struct inet_frag_bucket *hb = &f->hash[i];
+ spin_lock_init(&hb->chain_lock);
+ INIT_HLIST_HEAD(&hb->chain);
+ }
rwlock_init(&f->lock);
f->rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
@@ -100,10 +132,18 @@ EXPORT_SYMBOL(inet_frags_exit_net);
static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
{
- write_lock(&f->lock);
+ struct inet_frag_bucket *hb;
+ unsigned int hash;
+
+ read_lock(&f->lock);
+ hash = f->hashfn(fq);
+ hb = &f->hash[hash];
+
+ spin_lock(&hb->chain_lock);
hlist_del(&fq->list);
- fq->net->nqueues--;
- write_unlock(&f->lock);
+ spin_unlock(&hb->chain_lock);
+
+ read_unlock(&f->lock);
inet_frag_lru_del(fq);
}
@@ -182,6 +222,9 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
q = list_first_entry(&nf->lru_list,
struct inet_frag_queue, lru_list);
atomic_inc(&q->refcnt);
+ /* Remove q from list to avoid several CPUs grabbing it */
+ list_del_init(&q->lru_list);
+
spin_unlock(&nf->lru_lock);
spin_lock(&q->lock);
@@ -202,27 +245,32 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
struct inet_frag_queue *qp_in, struct inet_frags *f,
void *arg)
{
+ struct inet_frag_bucket *hb;
struct inet_frag_queue *qp;
#ifdef CONFIG_SMP
#endif
unsigned int hash;
- write_lock(&f->lock);
+ read_lock(&f->lock); /* Protects against hash rebuild */
/*
* While we stayed w/o the lock other CPU could update
* the rnd seed, so we need to re-calculate the hash
* chain. Fortunatelly the qp_in can be used to get one.
*/
hash = f->hashfn(qp_in);
+ hb = &f->hash[hash];
+ spin_lock(&hb->chain_lock);
+
#ifdef CONFIG_SMP
/* With SMP race we have to recheck hash table, because
* such entry could be created on other cpu, while we
- * promoted read lock to write lock.
+ * released the hash bucket lock.
*/
- hlist_for_each_entry(qp, &f->hash[hash], list) {
+ hlist_for_each_entry(qp, &hb->chain, list) {
if (qp->net == nf && f->match(qp, arg)) {
atomic_inc(&qp->refcnt);
- write_unlock(&f->lock);
+ spin_unlock(&hb->chain_lock);
+ read_unlock(&f->lock);
qp_in->last_in |= INET_FRAG_COMPLETE;
inet_frag_put(qp_in, f);
return qp;
@@ -234,9 +282,9 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
atomic_inc(&qp->refcnt);
atomic_inc(&qp->refcnt);
- hlist_add_head(&qp->list, &f->hash[hash]);
- nf->nqueues++;
- write_unlock(&f->lock);
+ hlist_add_head(&qp->list, &hb->chain);
+ spin_unlock(&hb->chain_lock);
+ read_unlock(&f->lock);
inet_frag_lru_add(nf, qp);
return qp;
}
@@ -277,17 +325,23 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
struct inet_frags *f, void *key, unsigned int hash)
__releases(&f->lock)
{
+ struct inet_frag_bucket *hb;
struct inet_frag_queue *q;
int depth = 0;
- hlist_for_each_entry(q, &f->hash[hash], list) {
+ hb = &f->hash[hash];
+
+ spin_lock(&hb->chain_lock);
+ hlist_for_each_entry(q, &hb->chain, list) {
if (q->net == nf && f->match(q, key)) {
atomic_inc(&q->refcnt);
+ spin_unlock(&hb->chain_lock);
read_unlock(&f->lock);
return q;
}
depth++;
}
+ spin_unlock(&hb->chain_lock);
read_unlock(&f->lock);
if (depth <= INETFRAGS_MAXDEPTH)
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index cc280a3f4f96..1975f52933c5 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/if_vlan.h>
#include <linux/inet_lro.h>
+#include <net/checksum.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jan-Bernd Themann <themann@de.ibm.com>");
@@ -114,11 +115,9 @@ static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc)
*(p+2) = lro_desc->tcp_rcv_tsecr;
}
+ csum_replace2(&iph->check, iph->tot_len, htons(lro_desc->ip_tot_len));
iph->tot_len = htons(lro_desc->ip_tot_len);
- iph->check = 0;
- iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl);
-
tcph->check = 0;
tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), 0);
lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index a6445b843ef4..b66910aaef4d 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -79,40 +79,11 @@ struct ipq {
struct inet_peer *peer;
};
-/* RFC 3168 support :
- * We want to check ECN values of all fragments, do detect invalid combinations.
- * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value.
- */
-#define IPFRAG_ECN_NOT_ECT 0x01 /* one frag had ECN_NOT_ECT */
-#define IPFRAG_ECN_ECT_1 0x02 /* one frag had ECN_ECT_1 */
-#define IPFRAG_ECN_ECT_0 0x04 /* one frag had ECN_ECT_0 */
-#define IPFRAG_ECN_CE 0x08 /* one frag had ECN_CE */
-
static inline u8 ip4_frag_ecn(u8 tos)
{
return 1 << (tos & INET_ECN_MASK);
}
-/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements
- * Value : 0xff if frame should be dropped.
- * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field
- */
-static const u8 ip4_frag_ecn_table[16] = {
- /* at least one fragment had CE, and others ECT_0 or ECT_1 */
- [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE,
- [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
- [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
-
- /* invalid combinations : drop frame */
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff,
- [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
-};
-
static struct inet_frags ip4_frags;
int ip_frag_nqueues(struct net *net)
@@ -248,8 +219,7 @@ static void ip_expire(unsigned long arg)
if (!head->dev)
goto out_rcu_unlock;
- /* skb dst is stale, drop it, and perform route lookup again */
- skb_dst_drop(head);
+ /* skb has no dst, perform route lookup again */
iph = ip_hdr(head);
err = ip_route_input_noref(head, iph->daddr, iph->saddr,
iph->tos, head->dev);
@@ -523,9 +493,16 @@ found:
qp->q.max_size = skb->len + ihl;
if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
- qp->q.meat == qp->q.len)
- return ip_frag_reasm(qp, prev, dev);
+ qp->q.meat == qp->q.len) {
+ unsigned long orefdst = skb->_skb_refdst;
+
+ skb->_skb_refdst = 0UL;
+ err = ip_frag_reasm(qp, prev, dev);
+ skb->_skb_refdst = orefdst;
+ return err;
+ }
+ skb_dst_drop(skb);
inet_frag_lru_move(&qp->q);
return -EINPROGRESS;
@@ -551,7 +528,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
ipq_kill(qp);
- ecn = ip4_frag_ecn_table[qp->ecn];
+ ecn = ip_frag_ecn_table[qp->ecn];
if (unlikely(ecn == 0xff)) {
err = -EINVAL;
goto out_fail;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 91d66dbde9c0..c625e4dad4b0 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -37,7 +37,7 @@
#include <net/ip.h>
#include <net/icmp.h>
#include <net/protocol.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/arp.h>
#include <net/checksum.h>
#include <net/dsfield.h>
@@ -108,15 +108,6 @@
fatal route to network, even if it were you who configured
fatal static route: you are innocent. :-)
-
-
- 3. Really, ipv4/ipip.c, ipv4/ip_gre.c and ipv6/sit.c contain
- practically identical code. It would be good to glue them
- together, but it is not very evident, how to make them modular.
- sit is integral part of IPv6, ipip and gre are naturally modular.
- We could extract common parts (hash table, ioctl etc)
- to a separate module (ip_tunnel.c).
-
Alexey Kuznetsov.
*/
@@ -126,400 +117,137 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
static struct rtnl_link_ops ipgre_link_ops __read_mostly;
static int ipgre_tunnel_init(struct net_device *dev);
-static void ipgre_tunnel_setup(struct net_device *dev);
-static int ipgre_tunnel_bind_dev(struct net_device *dev);
-
-/* Fallback tunnel: no source, no destination, no key, no options */
-
-#define HASH_SIZE 16
static int ipgre_net_id __read_mostly;
-struct ipgre_net {
- struct ip_tunnel __rcu *tunnels[4][HASH_SIZE];
-
- struct net_device *fb_tunnel_dev;
-};
-
-/* Tunnel hash table */
-
-/*
- 4 hash tables:
-
- 3: (remote,local)
- 2: (remote,*)
- 1: (*,local)
- 0: (*,*)
+static int gre_tap_net_id __read_mostly;
- We require exact key match i.e. if a key is present in packet
- it will match only tunnel with the same key; if it is not present,
- it will match only keyless tunnel.
-
- All keysless packets, if not matched configured keyless tunnels
- will match fallback tunnel.
- */
+static __sum16 check_checksum(struct sk_buff *skb)
+{
+ __sum16 csum = 0;
-#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
+ switch (skb->ip_summed) {
+ case CHECKSUM_COMPLETE:
+ csum = csum_fold(skb->csum);
-#define tunnels_r_l tunnels[3]
-#define tunnels_r tunnels[2]
-#define tunnels_l tunnels[1]
-#define tunnels_wc tunnels[0]
+ if (!csum)
+ break;
+ /* Fall through. */
-static struct rtnl_link_stats64 *ipgre_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
+ case CHECKSUM_NONE:
+ skb->csum = 0;
+ csum = __skb_checksum_complete(skb);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ break;
}
- tot->multicast = dev->stats.multicast;
- tot->rx_crc_errors = dev->stats.rx_crc_errors;
- tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
- tot->rx_length_errors = dev->stats.rx_length_errors;
- tot->rx_frame_errors = dev->stats.rx_frame_errors;
- tot->rx_errors = dev->stats.rx_errors;
-
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
-
- return tot;
+ return csum;
}
-/* Does key in tunnel parameters match packet */
-static bool ipgre_key_match(const struct ip_tunnel_parm *p,
- __be16 flags, __be32 key)
+static int ip_gre_calc_hlen(__be16 o_flags)
{
- if (p->i_flags & GRE_KEY) {
- if (flags & GRE_KEY)
- return key == p->i_key;
- else
- return false; /* key expected, none present */
- } else
- return !(flags & GRE_KEY);
-}
+ int addend = 4;
-/* Given src, dst and key, find appropriate for input tunnel. */
+ if (o_flags&TUNNEL_CSUM)
+ addend += 4;
+ if (o_flags&TUNNEL_KEY)
+ addend += 4;
+ if (o_flags&TUNNEL_SEQ)
+ addend += 4;
+ return addend;
+}
-static struct ip_tunnel *ipgre_tunnel_lookup(struct net_device *dev,
- __be32 remote, __be32 local,
- __be16 flags, __be32 key,
- __be16 gre_proto)
+static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
+ bool *csum_err, int *hdr_len)
{
- struct net *net = dev_net(dev);
- int link = dev->ifindex;
- unsigned int h0 = HASH(remote);
- unsigned int h1 = HASH(key);
- struct ip_tunnel *t, *cand = NULL;
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
- int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
- ARPHRD_ETHER : ARPHRD_IPGRE;
- int score, cand_score = 4;
-
- for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) {
- if (local != t->parms.iph.saddr ||
- remote != t->parms.iph.daddr ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (!ipgre_key_match(&t->parms, flags, key))
- continue;
-
- if (t->dev->type != ARPHRD_IPGRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
+ unsigned int ip_hlen = ip_hdrlen(skb);
+ const struct gre_base_hdr *greh;
+ __be32 *options;
- for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) {
- if (remote != t->parms.iph.daddr ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (!ipgre_key_match(&t->parms, flags, key))
- continue;
-
- if (t->dev->type != ARPHRD_IPGRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
+ return -EINVAL;
- for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) {
- if ((local != t->parms.iph.saddr &&
- (local != t->parms.iph.daddr ||
- !ipv4_is_multicast(local))) ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (!ipgre_key_match(&t->parms, flags, key))
- continue;
-
- if (t->dev->type != ARPHRD_IPGRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
+ greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
+ if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
+ return -EINVAL;
- for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) {
- if (t->parms.i_key != key ||
- !(t->dev->flags & IFF_UP))
- continue;
-
- if (t->dev->type != ARPHRD_IPGRE &&
- t->dev->type != dev_type)
- continue;
-
- score = 0;
- if (t->parms.link != link)
- score |= 1;
- if (t->dev->type != dev_type)
- score |= 2;
- if (score == 0)
- return t;
-
- if (score < cand_score) {
- cand = t;
- cand_score = score;
- }
- }
+ tpi->flags = gre_flags_to_tnl_flags(greh->flags);
+ *hdr_len = ip_gre_calc_hlen(tpi->flags);
- if (cand != NULL)
- return cand;
+ if (!pskb_may_pull(skb, *hdr_len))
+ return -EINVAL;
- dev = ign->fb_tunnel_dev;
- if (dev->flags & IFF_UP)
- return netdev_priv(dev);
+ greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
- return NULL;
-}
+ tpi->proto = greh->protocol;
-static struct ip_tunnel __rcu **__ipgre_bucket(struct ipgre_net *ign,
- struct ip_tunnel_parm *parms)
-{
- __be32 remote = parms->iph.daddr;
- __be32 local = parms->iph.saddr;
- __be32 key = parms->i_key;
- unsigned int h = HASH(key);
- int prio = 0;
-
- if (local)
- prio |= 1;
- if (remote && !ipv4_is_multicast(remote)) {
- prio |= 2;
- h ^= HASH(remote);
+ options = (__be32 *)(greh + 1);
+ if (greh->flags & GRE_CSUM) {
+ if (check_checksum(skb)) {
+ *csum_err = true;
+ return -EINVAL;
+ }
+ options++;
}
- return &ign->tunnels[prio][h];
-}
-
-static inline struct ip_tunnel __rcu **ipgre_bucket(struct ipgre_net *ign,
- struct ip_tunnel *t)
-{
- return __ipgre_bucket(ign, &t->parms);
-}
-
-static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t)
-{
- struct ip_tunnel __rcu **tp = ipgre_bucket(ign, t);
+ if (greh->flags & GRE_KEY) {
+ tpi->key = *options;
+ options++;
+ } else
+ tpi->key = 0;
- rcu_assign_pointer(t->next, rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
-}
+ if (unlikely(greh->flags & GRE_SEQ)) {
+ tpi->seq = *options;
+ options++;
+ } else
+ tpi->seq = 0;
-static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t)
-{
- struct ip_tunnel __rcu **tp;
- struct ip_tunnel *iter;
-
- for (tp = ipgre_bucket(ign, t);
- (iter = rtnl_dereference(*tp)) != NULL;
- tp = &iter->next) {
- if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
- break;
+ /* WCCP version 1 and 2 protocol decoding.
+ * - Change protocol to IP
+ * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
+ */
+ if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
+ tpi->proto = htons(ETH_P_IP);
+ if ((*(u8 *)options & 0xF0) != 0x40) {
+ *hdr_len += 4;
+ if (!pskb_may_pull(skb, *hdr_len))
+ return -EINVAL;
}
}
-}
-
-static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
- struct ip_tunnel_parm *parms,
- int type)
-{
- __be32 remote = parms->iph.daddr;
- __be32 local = parms->iph.saddr;
- __be32 key = parms->i_key;
- int link = parms->link;
- struct ip_tunnel *t;
- struct ip_tunnel __rcu **tp;
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
-
- for (tp = __ipgre_bucket(ign, parms);
- (t = rtnl_dereference(*tp)) != NULL;
- tp = &t->next)
- if (local == t->parms.iph.saddr &&
- remote == t->parms.iph.daddr &&
- key == t->parms.i_key &&
- link == t->parms.link &&
- type == t->dev->type)
- break;
-
- return t;
-}
-
-static struct ip_tunnel *ipgre_tunnel_locate(struct net *net,
- struct ip_tunnel_parm *parms, int create)
-{
- struct ip_tunnel *t, *nt;
- struct net_device *dev;
- char name[IFNAMSIZ];
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
-
- t = ipgre_tunnel_find(net, parms, ARPHRD_IPGRE);
- if (t || !create)
- return t;
-
- if (parms->name[0])
- strlcpy(name, parms->name, IFNAMSIZ);
- else
- strcpy(name, "gre%d");
-
- dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
- if (!dev)
- return NULL;
-
- dev_net_set(dev, net);
-
- nt = netdev_priv(dev);
- nt->parms = *parms;
- dev->rtnl_link_ops = &ipgre_link_ops;
-
- dev->mtu = ipgre_tunnel_bind_dev(dev);
- if (register_netdevice(dev) < 0)
- goto failed_free;
-
- /* Can use a lockless transmit, unless we generate output sequences */
- if (!(nt->parms.o_flags & GRE_SEQ))
- dev->features |= NETIF_F_LLTX;
-
- dev_hold(dev);
- ipgre_tunnel_link(ign, nt);
- return nt;
-
-failed_free:
- free_netdev(dev);
- return NULL;
-}
-
-static void ipgre_tunnel_uninit(struct net_device *dev)
-{
- struct net *net = dev_net(dev);
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
-
- ipgre_tunnel_unlink(ign, netdev_priv(dev));
- dev_put(dev);
+ return 0;
}
-
static void ipgre_err(struct sk_buff *skb, u32 info)
{
-/* All the routers (except for Linux) return only
- 8 bytes of packet payload. It means, that precise relaying of
- ICMP in the real Internet is absolutely infeasible.
+ /* All the routers (except for Linux) return only
+ 8 bytes of packet payload. It means, that precise relaying of
+ ICMP in the real Internet is absolutely infeasible.
- Moreover, Cisco "wise men" put GRE key to the third word
- in GRE header. It makes impossible maintaining even soft state for keyed
- GRE tunnels with enabled checksum. Tell them "thank you".
-
- Well, I wonder, rfc1812 was written by Cisco employee,
- what the hell these idiots break standards established
- by themselves???
- */
+ Moreover, Cisco "wise men" put GRE key to the third word
+ in GRE header. It makes impossible maintaining even soft
+ state for keyed GRE tunnels with enabled checksum. Tell
+ them "thank you".
+ Well, I wonder, rfc1812 was written by Cisco employee,
+ what the hell these idiots break standards established
+ by themselves???
+ */
+ struct net *net = dev_net(skb->dev);
+ struct ip_tunnel_net *itn;
const struct iphdr *iph = (const struct iphdr *)skb->data;
- __be16 *p = (__be16 *)(skb->data+(iph->ihl<<2));
- int grehlen = (iph->ihl<<2) + 4;
const int type = icmp_hdr(skb)->type;
const int code = icmp_hdr(skb)->code;
struct ip_tunnel *t;
- __be16 flags;
- __be32 key = 0;
+ struct tnl_ptk_info tpi;
+ int hdr_len;
+ bool csum_err = false;
- flags = p[0];
- if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
- if (flags&(GRE_VERSION|GRE_ROUTING))
+ if (parse_gre_header(skb, &tpi, &csum_err, &hdr_len)) {
+ if (!csum_err) /* ignore csum errors. */
return;
- if (flags&GRE_KEY) {
- grehlen += 4;
- if (flags&GRE_CSUM)
- grehlen += 4;
- }
}
- /* If only 8 bytes returned, keyed message will be dropped here */
- if (skb_headlen(skb) < grehlen)
- return;
-
- if (flags & GRE_KEY)
- key = *(((__be32 *)p) + (grehlen / 4) - 1);
-
switch (type) {
default:
case ICMP_PARAMETERPROB:
@@ -548,8 +276,13 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
break;
}
- t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
- flags, key, p[1]);
+ if (tpi.proto == htons(ETH_P_TEB))
+ itn = net_generic(net, gre_tap_net_id);
+ else
+ itn = net_generic(net, ipgre_net_id);
+
+ t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi.flags,
+ iph->daddr, iph->saddr, tpi.key);
if (t == NULL)
return;
@@ -578,158 +311,33 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
t->err_time = jiffies;
}
-static inline u8
-ipgre_ecn_encapsulate(u8 tos, const struct iphdr *old_iph, struct sk_buff *skb)
-{
- u8 inner = 0;
- if (skb->protocol == htons(ETH_P_IP))
- inner = old_iph->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- inner = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
- return INET_ECN_encapsulate(tos, inner);
-}
-
static int ipgre_rcv(struct sk_buff *skb)
{
+ struct net *net = dev_net(skb->dev);
+ struct ip_tunnel_net *itn;
const struct iphdr *iph;
- u8 *h;
- __be16 flags;
- __sum16 csum = 0;
- __be32 key = 0;
- u32 seqno = 0;
struct ip_tunnel *tunnel;
- int offset = 4;
- __be16 gre_proto;
- int err;
+ struct tnl_ptk_info tpi;
+ int hdr_len;
+ bool csum_err = false;
- if (!pskb_may_pull(skb, 16))
+ if (parse_gre_header(skb, &tpi, &csum_err, &hdr_len) < 0)
goto drop;
- iph = ip_hdr(skb);
- h = skb->data;
- flags = *(__be16 *)h;
-
- if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
- /* - Version must be 0.
- - We do not support routing headers.
- */
- if (flags&(GRE_VERSION|GRE_ROUTING))
- goto drop;
-
- if (flags&GRE_CSUM) {
- switch (skb->ip_summed) {
- case CHECKSUM_COMPLETE:
- csum = csum_fold(skb->csum);
- if (!csum)
- break;
- /* fall through */
- case CHECKSUM_NONE:
- skb->csum = 0;
- csum = __skb_checksum_complete(skb);
- skb->ip_summed = CHECKSUM_COMPLETE;
- }
- offset += 4;
- }
- if (flags&GRE_KEY) {
- key = *(__be32 *)(h + offset);
- offset += 4;
- }
- if (flags&GRE_SEQ) {
- seqno = ntohl(*(__be32 *)(h + offset));
- offset += 4;
- }
- }
+ if (tpi.proto == htons(ETH_P_TEB))
+ itn = net_generic(net, gre_tap_net_id);
+ else
+ itn = net_generic(net, ipgre_net_id);
- gre_proto = *(__be16 *)(h + 2);
+ iph = ip_hdr(skb);
+ tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi.flags,
+ iph->saddr, iph->daddr, tpi.key);
- tunnel = ipgre_tunnel_lookup(skb->dev,
- iph->saddr, iph->daddr, flags, key,
- gre_proto);
if (tunnel) {
- struct pcpu_tstats *tstats;
-
- secpath_reset(skb);
-
- skb->protocol = gre_proto;
- /* WCCP version 1 and 2 protocol decoding.
- * - Change protocol to IP
- * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
- */
- if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
- skb->protocol = htons(ETH_P_IP);
- if ((*(h + offset) & 0xF0) != 0x40)
- offset += 4;
- }
-
- skb->mac_header = skb->network_header;
- __pskb_pull(skb, offset);
- skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
- skb->pkt_type = PACKET_HOST;
-#ifdef CONFIG_NET_IPGRE_BROADCAST
- if (ipv4_is_multicast(iph->daddr)) {
- /* Looped back packet, drop it! */
- if (rt_is_output_route(skb_rtable(skb)))
- goto drop;
- tunnel->dev->stats.multicast++;
- skb->pkt_type = PACKET_BROADCAST;
- }
-#endif
-
- if (((flags&GRE_CSUM) && csum) ||
- (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
- tunnel->dev->stats.rx_crc_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
- if (tunnel->parms.i_flags&GRE_SEQ) {
- if (!(flags&GRE_SEQ) ||
- (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) {
- tunnel->dev->stats.rx_fifo_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
- tunnel->i_seqno = seqno + 1;
- }
-
- /* Warning: All skb pointers will be invalidated! */
- if (tunnel->dev->type == ARPHRD_ETHER) {
- if (!pskb_may_pull(skb, ETH_HLEN)) {
- tunnel->dev->stats.rx_length_errors++;
- tunnel->dev->stats.rx_errors++;
- goto drop;
- }
-
- iph = ip_hdr(skb);
- skb->protocol = eth_type_trans(skb, tunnel->dev);
- skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
- }
-
- __skb_tunnel_rx(skb, tunnel->dev);
-
- skb_reset_network_header(skb);
- err = IP_ECN_decapsulate(iph, skb);
- if (unlikely(err)) {
- if (log_ecn_error)
- net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
- &iph->saddr, iph->tos);
- if (err > 1) {
- ++tunnel->dev->stats.rx_frame_errors;
- ++tunnel->dev->stats.rx_errors;
- goto drop;
- }
- }
-
- tstats = this_cpu_ptr(tunnel->dev->tstats);
- u64_stats_update_begin(&tstats->syncp);
- tstats->rx_packets++;
- tstats->rx_bytes += skb->len;
- u64_stats_update_end(&tstats->syncp);
-
- gro_cells_receive(&tunnel->gro_cells, skb);
+ ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error);
return 0;
}
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-
drop:
kfree_skb(skb);
return 0;
@@ -746,7 +354,7 @@ static struct sk_buff *handle_offloads(struct ip_tunnel *tunnel, struct sk_buff
skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
return skb;
} else if (skb->ip_summed == CHECKSUM_PARTIAL &&
- tunnel->parms.o_flags&GRE_CSUM) {
+ tunnel->parms.o_flags&TUNNEL_CSUM) {
err = skb_checksum_help(skb);
if (unlikely(err))
goto error;
@@ -760,494 +368,157 @@ error:
return ERR_PTR(err);
}
-static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+static struct sk_buff *gre_build_header(struct sk_buff *skb,
+ const struct tnl_ptk_info *tpi,
+ int hdr_len)
{
- struct pcpu_tstats *tstats = this_cpu_ptr(dev->tstats);
- struct ip_tunnel *tunnel = netdev_priv(dev);
- const struct iphdr *old_iph;
- const struct iphdr *tiph;
- struct flowi4 fl4;
- u8 tos;
- __be16 df;
- struct rtable *rt; /* Route to the other host */
- struct net_device *tdev; /* Device to other host */
- struct iphdr *iph; /* Our new IP header */
- unsigned int max_headroom; /* The extra header space needed */
- int gre_hlen;
- __be32 dst;
- int mtu;
- u8 ttl;
- int err;
- int pkt_len;
-
- skb = handle_offloads(tunnel, skb);
- if (IS_ERR(skb)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
+ struct gre_base_hdr *greh;
- if (!skb->encapsulation) {
- skb_reset_inner_headers(skb);
- skb->encapsulation = 1;
- }
+ skb_push(skb, hdr_len);
- old_iph = ip_hdr(skb);
+ greh = (struct gre_base_hdr *)skb->data;
+ greh->flags = tnl_flags_to_gre_flags(tpi->flags);
+ greh->protocol = tpi->proto;
- if (dev->type == ARPHRD_ETHER)
- IPCB(skb)->flags = 0;
+ if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
+ __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
- if (dev->header_ops && dev->type == ARPHRD_IPGRE) {
- gre_hlen = 0;
- tiph = (const struct iphdr *)skb->data;
- } else {
- gre_hlen = tunnel->hlen;
- tiph = &tunnel->parms.iph;
- }
-
- if ((dst = tiph->daddr) == 0) {
- /* NBMA tunnel */
-
- if (skb_dst(skb) == NULL) {
- dev->stats.tx_fifo_errors++;
- goto tx_error;
+ if (tpi->flags&TUNNEL_SEQ) {
+ *ptr = tpi->seq;
+ ptr--;
}
-
- if (skb->protocol == htons(ETH_P_IP)) {
- rt = skb_rtable(skb);
- dst = rt_nexthop(rt, old_iph->daddr);
+ if (tpi->flags&TUNNEL_KEY) {
+ *ptr = tpi->key;
+ ptr--;
}
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6)) {
- const struct in6_addr *addr6;
- struct neighbour *neigh;
- bool do_tx_error_icmp;
- int addr_type;
-
- neigh = dst_neigh_lookup(skb_dst(skb), &ipv6_hdr(skb)->daddr);
- if (neigh == NULL)
- goto tx_error;
-
- addr6 = (const struct in6_addr *)&neigh->primary_key;
- addr_type = ipv6_addr_type(addr6);
-
- if (addr_type == IPV6_ADDR_ANY) {
- addr6 = &ipv6_hdr(skb)->daddr;
- addr_type = ipv6_addr_type(addr6);
- }
-
- if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
- do_tx_error_icmp = true;
- else {
- do_tx_error_icmp = false;
- dst = addr6->s6_addr32[3];
- }
- neigh_release(neigh);
- if (do_tx_error_icmp)
- goto tx_error_icmp;
+ if (tpi->flags&TUNNEL_CSUM &&
+ !(skb_shinfo(skb)->gso_type & SKB_GSO_GRE)) {
+ *(__sum16 *)ptr = 0;
+ *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
+ skb->len, 0));
}
-#endif
- else
- goto tx_error;
}
- ttl = tiph->ttl;
- tos = tiph->tos;
- if (tos & 0x1) {
- tos &= ~0x1;
- if (skb->protocol == htons(ETH_P_IP))
- tos = old_iph->tos;
- else if (skb->protocol == htons(ETH_P_IPV6))
- tos = ipv6_get_dsfield((const struct ipv6hdr *)old_iph);
- }
+ return skb;
+}
- rt = ip_route_output_gre(dev_net(dev), &fl4, dst, tiph->saddr,
- tunnel->parms.o_key, RT_TOS(tos),
- tunnel->parms.link);
- if (IS_ERR(rt)) {
- dev->stats.tx_carrier_errors++;
- goto tx_error;
- }
- tdev = rt->dst.dev;
+static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
+ const struct iphdr *tnl_params,
+ __be16 proto)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct tnl_ptk_info tpi;
- if (tdev == dev) {
- ip_rt_put(rt);
- dev->stats.collisions++;
- goto tx_error;
+ if (likely(!skb->encapsulation)) {
+ skb_reset_inner_headers(skb);
+ skb->encapsulation = 1;
}
- df = tiph->frag_off;
- if (df)
- mtu = dst_mtu(&rt->dst) - dev->hard_header_len - tunnel->hlen;
- else
- mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
-
- if (skb_dst(skb))
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-
- if (skb->protocol == htons(ETH_P_IP)) {
- df |= (old_iph->frag_off&htons(IP_DF));
+ tpi.flags = tunnel->parms.o_flags;
+ tpi.proto = proto;
+ tpi.key = tunnel->parms.o_key;
+ if (tunnel->parms.o_flags & TUNNEL_SEQ)
+ tunnel->o_seqno++;
+ tpi.seq = htonl(tunnel->o_seqno);
- if (!skb_is_gso(skb) &&
- (old_iph->frag_off&htons(IP_DF)) &&
- mtu < ntohs(old_iph->tot_len)) {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
- ip_rt_put(rt);
- goto tx_error;
- }
+ /* Push GRE header. */
+ skb = gre_build_header(skb, &tpi, tunnel->hlen);
+ if (unlikely(!skb)) {
+ dev->stats.tx_dropped++;
+ return;
}
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6)) {
- struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
-
- if (rt6 && mtu < dst_mtu(skb_dst(skb)) && mtu >= IPV6_MIN_MTU) {
- if ((tunnel->parms.iph.daddr &&
- !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
- rt6->rt6i_dst.plen == 128) {
- rt6->rt6i_flags |= RTF_MODIFIED;
- dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
- }
- }
- if (!skb_is_gso(skb) &&
- mtu >= IPV6_MIN_MTU &&
- mtu < skb->len - tunnel->hlen + gre_hlen) {
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- ip_rt_put(rt);
- goto tx_error;
- }
- }
-#endif
+ ip_tunnel_xmit(skb, dev, tnl_params);
+}
- if (tunnel->err_count > 0) {
- if (time_before(jiffies,
- tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
- tunnel->err_count--;
+static netdev_tx_t ipgre_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ const struct iphdr *tnl_params;
- dst_link_failure(skb);
- } else
- tunnel->err_count = 0;
- }
+ skb = handle_offloads(tunnel, skb);
+ if (IS_ERR(skb))
+ goto out;
- max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + rt->dst.header_len;
-
- if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
- (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
- struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
- if (max_headroom > dev->needed_headroom)
- dev->needed_headroom = max_headroom;
- if (!new_skb) {
- ip_rt_put(rt);
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (skb->sk)
- skb_set_owner_w(new_skb, skb->sk);
- dev_kfree_skb(skb);
- skb = new_skb;
- old_iph = ip_hdr(skb);
- /* Warning : tiph value might point to freed memory */
- }
+ if (dev->header_ops) {
+ /* Need space for new headers */
+ if (skb_cow_head(skb, dev->needed_headroom -
+ (tunnel->hlen + sizeof(struct iphdr))))
+ goto free_skb;
- skb_push(skb, gre_hlen);
- skb_reset_network_header(skb);
- skb_set_transport_header(skb, sizeof(*iph));
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
- IPSKB_REROUTED);
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
- /*
- * Push down and install the IPIP header.
- */
+ tnl_params = (const struct iphdr *)skb->data;
- iph = ip_hdr(skb);
- iph->version = 4;
- iph->ihl = sizeof(struct iphdr) >> 2;
- iph->frag_off = df;
- iph->protocol = IPPROTO_GRE;
- iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb);
- iph->daddr = fl4.daddr;
- iph->saddr = fl4.saddr;
- iph->ttl = ttl;
-
- tunnel_ip_select_ident(skb, old_iph, &rt->dst);
-
- if (ttl == 0) {
- if (skb->protocol == htons(ETH_P_IP))
- iph->ttl = old_iph->ttl;
-#if IS_ENABLED(CONFIG_IPV6)
- else if (skb->protocol == htons(ETH_P_IPV6))
- iph->ttl = ((const struct ipv6hdr *)old_iph)->hop_limit;
-#endif
- else
- iph->ttl = ip4_dst_hoplimit(&rt->dst);
- }
-
- ((__be16 *)(iph + 1))[0] = tunnel->parms.o_flags;
- ((__be16 *)(iph + 1))[1] = (dev->type == ARPHRD_ETHER) ?
- htons(ETH_P_TEB) : skb->protocol;
-
- if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
- __be32 *ptr = (__be32 *)(((u8 *)iph) + tunnel->hlen - 4);
+ /* Pull skb since ip_tunnel_xmit() needs skb->data pointing
+ * to gre header.
+ */
+ skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
+ } else {
+ if (skb_cow_head(skb, dev->needed_headroom))
+ goto free_skb;
- if (tunnel->parms.o_flags&GRE_SEQ) {
- ++tunnel->o_seqno;
- *ptr = htonl(tunnel->o_seqno);
- ptr--;
- }
- if (tunnel->parms.o_flags&GRE_KEY) {
- *ptr = tunnel->parms.o_key;
- ptr--;
- }
- /* Skip GRE checksum if skb is getting offloaded. */
- if (!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE) &&
- (tunnel->parms.o_flags&GRE_CSUM)) {
- int offset = skb_transport_offset(skb);
-
- if (skb_has_shared_frag(skb)) {
- err = __skb_linearize(skb);
- if (err)
- goto tx_error;
- }
-
- *ptr = 0;
- *(__sum16 *)ptr = csum_fold(skb_checksum(skb, offset,
- skb->len - offset,
- 0));
- }
+ tnl_params = &tunnel->parms.iph;
}
- nf_reset(skb);
+ __gre_xmit(skb, dev, tnl_params, skb->protocol);
- pkt_len = skb->len - skb_transport_offset(skb);
- err = ip_local_out(skb);
- if (likely(net_xmit_eval(err) == 0)) {
- u64_stats_update_begin(&tstats->syncp);
- tstats->tx_bytes += pkt_len;
- tstats->tx_packets++;
- u64_stats_update_end(&tstats->syncp);
- } else {
- dev->stats.tx_errors++;
- dev->stats.tx_aborted_errors++;
- }
return NETDEV_TX_OK;
-#if IS_ENABLED(CONFIG_IPV6)
-tx_error_icmp:
- dst_link_failure(skb);
-#endif
-tx_error:
- dev->stats.tx_errors++;
+free_skb:
dev_kfree_skb(skb);
+out:
+ dev->stats.tx_dropped++;
return NETDEV_TX_OK;
}
-static int ipgre_tunnel_bind_dev(struct net_device *dev)
+static netdev_tx_t gre_tap_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
- struct net_device *tdev = NULL;
- struct ip_tunnel *tunnel;
- const struct iphdr *iph;
- int hlen = LL_MAX_HEADER;
- int mtu = ETH_DATA_LEN;
- int addend = sizeof(struct iphdr) + 4;
-
- tunnel = netdev_priv(dev);
- iph = &tunnel->parms.iph;
-
- /* Guess output device to choose reasonable mtu and needed_headroom */
-
- if (iph->daddr) {
- struct flowi4 fl4;
- struct rtable *rt;
-
- rt = ip_route_output_gre(dev_net(dev), &fl4,
- iph->daddr, iph->saddr,
- tunnel->parms.o_key,
- RT_TOS(iph->tos),
- tunnel->parms.link);
- if (!IS_ERR(rt)) {
- tdev = rt->dst.dev;
- ip_rt_put(rt);
- }
-
- if (dev->type != ARPHRD_ETHER)
- dev->flags |= IFF_POINTOPOINT;
- }
+ struct ip_tunnel *tunnel = netdev_priv(dev);
- if (!tdev && tunnel->parms.link)
- tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
+ skb = handle_offloads(tunnel, skb);
+ if (IS_ERR(skb))
+ goto out;
- if (tdev) {
- hlen = tdev->hard_header_len + tdev->needed_headroom;
- mtu = tdev->mtu;
- }
- dev->iflink = tunnel->parms.link;
-
- /* Precalculate GRE options length */
- if (tunnel->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
- if (tunnel->parms.o_flags&GRE_CSUM)
- addend += 4;
- if (tunnel->parms.o_flags&GRE_KEY)
- addend += 4;
- if (tunnel->parms.o_flags&GRE_SEQ)
- addend += 4;
- }
- dev->needed_headroom = addend + hlen;
- mtu -= dev->hard_header_len + addend;
+ if (skb_cow_head(skb, dev->needed_headroom))
+ goto free_skb;
- if (mtu < 68)
- mtu = 68;
+ __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_TEB));
- tunnel->hlen = addend;
- /* TCP offload with GRE SEQ is not supported. */
- if (!(tunnel->parms.o_flags & GRE_SEQ)) {
- dev->features |= NETIF_F_GSO_SOFTWARE;
- dev->hw_features |= NETIF_F_GSO_SOFTWARE;
- }
+ return NETDEV_TX_OK;
- return mtu;
+free_skb:
+ dev_kfree_skb(skb);
+out:
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
}
-static int
-ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
+static int ipgre_tunnel_ioctl(struct net_device *dev,
+ struct ifreq *ifr, int cmd)
{
int err = 0;
struct ip_tunnel_parm p;
- struct ip_tunnel *t;
- struct net *net = dev_net(dev);
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
-
- switch (cmd) {
- case SIOCGETTUNNEL:
- t = NULL;
- if (dev == ign->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
- err = -EFAULT;
- break;
- }
- t = ipgre_tunnel_locate(net, &p, 0);
- }
- if (t == NULL)
- t = netdev_priv(dev);
- memcpy(&p, &t->parms, sizeof(p));
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
- break;
-
- case SIOCADDTUNNEL:
- case SIOCCHGTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
-
- err = -EINVAL;
- if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
- p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
- ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)))
- goto done;
- if (p.iph.ttl)
- p.iph.frag_off |= htons(IP_DF);
-
- if (!(p.i_flags&GRE_KEY))
- p.i_key = 0;
- if (!(p.o_flags&GRE_KEY))
- p.o_key = 0;
-
- t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
-
- if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
- if (t != NULL) {
- if (t->dev != dev) {
- err = -EEXIST;
- break;
- }
- } else {
- unsigned int nflags = 0;
-
- t = netdev_priv(dev);
-
- if (ipv4_is_multicast(p.iph.daddr))
- nflags = IFF_BROADCAST;
- else if (p.iph.daddr)
- nflags = IFF_POINTOPOINT;
-
- if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
- err = -EINVAL;
- break;
- }
- ipgre_tunnel_unlink(ign, t);
- synchronize_net();
- t->parms.iph.saddr = p.iph.saddr;
- t->parms.iph.daddr = p.iph.daddr;
- t->parms.i_key = p.i_key;
- t->parms.o_key = p.o_key;
- memcpy(dev->dev_addr, &p.iph.saddr, 4);
- memcpy(dev->broadcast, &p.iph.daddr, 4);
- ipgre_tunnel_link(ign, t);
- netdev_state_change(dev);
- }
- }
-
- if (t) {
- err = 0;
- if (cmd == SIOCCHGTUNNEL) {
- t->parms.iph.ttl = p.iph.ttl;
- t->parms.iph.tos = p.iph.tos;
- t->parms.iph.frag_off = p.iph.frag_off;
- if (t->parms.link != p.link) {
- t->parms.link = p.link;
- dev->mtu = ipgre_tunnel_bind_dev(dev);
- netdev_state_change(dev);
- }
- }
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- err = -EFAULT;
- } else
- err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
- break;
-
- case SIOCDELTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- if (dev == ign->fb_tunnel_dev) {
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
- err = -ENOENT;
- if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
- goto done;
- err = -EPERM;
- if (t == netdev_priv(ign->fb_tunnel_dev))
- goto done;
- dev = t->dev;
- }
- unregister_netdevice(dev);
- err = 0;
- break;
- default:
- err = -EINVAL;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
+ if (p.iph.version != 4 || p.iph.protocol != IPPROTO_GRE ||
+ p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)) ||
+ ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))) {
+ return -EINVAL;
}
+ p.i_flags = gre_flags_to_tnl_flags(p.i_flags);
+ p.o_flags = gre_flags_to_tnl_flags(p.o_flags);
-done:
- return err;
-}
+ err = ip_tunnel_ioctl(dev, &p, cmd);
+ if (err)
+ return err;
-static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- if (new_mtu < 68 ||
- new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
- return -EINVAL;
- dev->mtu = new_mtu;
+ p.i_flags = tnl_flags_to_gre_flags(p.i_flags);
+ p.o_flags = tnl_flags_to_gre_flags(p.o_flags);
+
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+ return -EFAULT;
return 0;
}
@@ -1277,25 +548,23 @@ static int ipgre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
...
ftp fec0:6666:6666::193.233.7.65
...
-
*/
-
static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr, unsigned int len)
{
struct ip_tunnel *t = netdev_priv(dev);
- struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
- __be16 *p = (__be16 *)(iph+1);
+ struct iphdr *iph;
+ struct gre_base_hdr *greh;
- memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
- p[0] = t->parms.o_flags;
- p[1] = htons(type);
+ iph = (struct iphdr *)skb_push(skb, t->hlen + sizeof(*iph));
+ greh = (struct gre_base_hdr *)(iph+1);
+ greh->flags = tnl_flags_to_gre_flags(t->parms.o_flags);
+ greh->protocol = htons(type);
- /*
- * Set the source hardware address.
- */
+ memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
+ /* Set the source hardware address. */
if (saddr)
memcpy(&iph->saddr, saddr, 4);
if (daddr)
@@ -1303,7 +572,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
if (iph->daddr)
return t->hlen;
- return -t->hlen;
+ return -(t->hlen + sizeof(*iph));
}
static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
@@ -1357,31 +626,21 @@ static int ipgre_close(struct net_device *dev)
}
return 0;
}
-
#endif
static const struct net_device_ops ipgre_netdev_ops = {
.ndo_init = ipgre_tunnel_init,
- .ndo_uninit = ipgre_tunnel_uninit,
+ .ndo_uninit = ip_tunnel_uninit,
#ifdef CONFIG_NET_IPGRE_BROADCAST
.ndo_open = ipgre_open,
.ndo_stop = ipgre_close,
#endif
- .ndo_start_xmit = ipgre_tunnel_xmit,
+ .ndo_start_xmit = ipgre_xmit,
.ndo_do_ioctl = ipgre_tunnel_ioctl,
- .ndo_change_mtu = ipgre_tunnel_change_mtu,
- .ndo_get_stats64 = ipgre_get_stats64,
+ .ndo_change_mtu = ip_tunnel_change_mtu,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
-static void ipgre_dev_free(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
-
- gro_cells_destroy(&tunnel->gro_cells);
- free_percpu(dev->tstats);
- free_netdev(dev);
-}
-
#define GRE_FEATURES (NETIF_F_SG | \
NETIF_F_FRAGLIST | \
NETIF_F_HIGHDMA | \
@@ -1390,35 +649,48 @@ static void ipgre_dev_free(struct net_device *dev)
static void ipgre_tunnel_setup(struct net_device *dev)
{
dev->netdev_ops = &ipgre_netdev_ops;
- dev->destructor = ipgre_dev_free;
+ ip_tunnel_setup(dev, ipgre_net_id);
+}
- dev->type = ARPHRD_IPGRE;
- dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
+static void __gre_tunnel_init(struct net_device *dev)
+{
+ struct ip_tunnel *tunnel;
+
+ tunnel = netdev_priv(dev);
+ tunnel->hlen = ip_gre_calc_hlen(tunnel->parms.o_flags);
+ tunnel->parms.iph.protocol = IPPROTO_GRE;
+
+ dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4;
dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4;
- dev->flags = IFF_NOARP;
- dev->iflink = 0;
- dev->addr_len = 4;
- dev->features |= NETIF_F_NETNS_LOCAL;
- dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
- dev->features |= GRE_FEATURES;
+ dev->features |= NETIF_F_NETNS_LOCAL | GRE_FEATURES;
dev->hw_features |= GRE_FEATURES;
+
+ if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) {
+ /* TCP offload with GRE SEQ is not supported. */
+ dev->features |= NETIF_F_GSO_SOFTWARE;
+ dev->hw_features |= NETIF_F_GSO_SOFTWARE;
+ /* Can use a lockless transmit, unless we generate
+ * output sequences
+ */
+ dev->features |= NETIF_F_LLTX;
+ }
}
static int ipgre_tunnel_init(struct net_device *dev)
{
- struct ip_tunnel *tunnel;
- struct iphdr *iph;
- int err;
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct iphdr *iph = &tunnel->parms.iph;
- tunnel = netdev_priv(dev);
- iph = &tunnel->parms.iph;
+ __gre_tunnel_init(dev);
- tunnel->dev = dev;
- strcpy(tunnel->parms.name, dev->name);
+ memcpy(dev->dev_addr, &iph->saddr, 4);
+ memcpy(dev->broadcast, &iph->daddr, 4);
- memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
- memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
+ dev->type = ARPHRD_IPGRE;
+ dev->flags = IFF_NOARP;
+ dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+ dev->addr_len = 4;
if (iph->daddr) {
#ifdef CONFIG_NET_IPGRE_BROADCAST
@@ -1432,106 +704,30 @@ static int ipgre_tunnel_init(struct net_device *dev)
} else
dev->header_ops = &ipgre_header_ops;
- dev->tstats = alloc_percpu(struct pcpu_tstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- err = gro_cells_init(&tunnel->gro_cells, dev);
- if (err) {
- free_percpu(dev->tstats);
- return err;
- }
-
- return 0;
-}
-
-static void ipgre_fb_tunnel_init(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct iphdr *iph = &tunnel->parms.iph;
-
- tunnel->dev = dev;
- strcpy(tunnel->parms.name, dev->name);
-
- iph->version = 4;
- iph->protocol = IPPROTO_GRE;
- iph->ihl = 5;
- tunnel->hlen = sizeof(struct iphdr) + 4;
-
- dev_hold(dev);
+ return ip_tunnel_init(dev);
}
-
static const struct gre_protocol ipgre_protocol = {
.handler = ipgre_rcv,
.err_handler = ipgre_err,
};
-static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
-{
- int prio;
-
- for (prio = 0; prio < 4; prio++) {
- int h;
- for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t;
-
- t = rtnl_dereference(ign->tunnels[prio][h]);
-
- while (t != NULL) {
- unregister_netdevice_queue(t->dev, head);
- t = rtnl_dereference(t->next);
- }
- }
- }
-}
-
static int __net_init ipgre_init_net(struct net *net)
{
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
- int err;
-
- ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
- ipgre_tunnel_setup);
- if (!ign->fb_tunnel_dev) {
- err = -ENOMEM;
- goto err_alloc_dev;
- }
- dev_net_set(ign->fb_tunnel_dev, net);
-
- ipgre_fb_tunnel_init(ign->fb_tunnel_dev);
- ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops;
-
- if ((err = register_netdev(ign->fb_tunnel_dev)))
- goto err_reg_dev;
-
- rcu_assign_pointer(ign->tunnels_wc[0],
- netdev_priv(ign->fb_tunnel_dev));
- return 0;
-
-err_reg_dev:
- ipgre_dev_free(ign->fb_tunnel_dev);
-err_alloc_dev:
- return err;
+ return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL);
}
static void __net_exit ipgre_exit_net(struct net *net)
{
- struct ipgre_net *ign;
- LIST_HEAD(list);
-
- ign = net_generic(net, ipgre_net_id);
- rtnl_lock();
- ipgre_destroy_tunnels(ign, &list);
- unregister_netdevice_many(&list);
- rtnl_unlock();
+ struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id);
+ ip_tunnel_delete_net(itn);
}
static struct pernet_operations ipgre_net_ops = {
.init = ipgre_init_net,
.exit = ipgre_exit_net,
.id = &ipgre_net_id,
- .size = sizeof(struct ipgre_net),
+ .size = sizeof(struct ip_tunnel_net),
};
static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -1576,8 +772,8 @@ out:
return ipgre_tunnel_validate(tb, data);
}
-static void ipgre_netlink_parms(struct nlattr *data[],
- struct ip_tunnel_parm *parms)
+static void ipgre_netlink_parms(struct nlattr *data[], struct nlattr *tb[],
+ struct ip_tunnel_parm *parms)
{
memset(parms, 0, sizeof(*parms));
@@ -1590,10 +786,10 @@ static void ipgre_netlink_parms(struct nlattr *data[],
parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
if (data[IFLA_GRE_IFLAGS])
- parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
+ parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS]));
if (data[IFLA_GRE_OFLAGS])
- parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
+ parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS]));
if (data[IFLA_GRE_IKEY])
parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
@@ -1617,148 +813,46 @@ static void ipgre_netlink_parms(struct nlattr *data[],
parms->iph.frag_off = htons(IP_DF);
}
-static int ipgre_tap_init(struct net_device *dev)
+static int gre_tap_init(struct net_device *dev)
{
- struct ip_tunnel *tunnel;
-
- tunnel = netdev_priv(dev);
-
- tunnel->dev = dev;
- strcpy(tunnel->parms.name, dev->name);
+ __gre_tunnel_init(dev);
- ipgre_tunnel_bind_dev(dev);
-
- dev->tstats = alloc_percpu(struct pcpu_tstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- return 0;
+ return ip_tunnel_init(dev);
}
-static const struct net_device_ops ipgre_tap_netdev_ops = {
- .ndo_init = ipgre_tap_init,
- .ndo_uninit = ipgre_tunnel_uninit,
- .ndo_start_xmit = ipgre_tunnel_xmit,
+static const struct net_device_ops gre_tap_netdev_ops = {
+ .ndo_init = gre_tap_init,
+ .ndo_uninit = ip_tunnel_uninit,
+ .ndo_start_xmit = gre_tap_xmit,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
- .ndo_change_mtu = ipgre_tunnel_change_mtu,
- .ndo_get_stats64 = ipgre_get_stats64,
+ .ndo_change_mtu = ip_tunnel_change_mtu,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
static void ipgre_tap_setup(struct net_device *dev)
{
-
ether_setup(dev);
-
- dev->netdev_ops = &ipgre_tap_netdev_ops;
- dev->destructor = ipgre_dev_free;
-
- dev->iflink = 0;
- dev->features |= NETIF_F_NETNS_LOCAL;
-
- dev->features |= GRE_FEATURES;
- dev->hw_features |= GRE_FEATURES;
+ dev->netdev_ops = &gre_tap_netdev_ops;
+ ip_tunnel_setup(dev, gre_tap_net_id);
}
-static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[],
- struct nlattr *data[])
+static int ipgre_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
{
- struct ip_tunnel *nt;
- struct net *net = dev_net(dev);
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
- int mtu;
- int err;
-
- nt = netdev_priv(dev);
- ipgre_netlink_parms(data, &nt->parms);
-
- if (ipgre_tunnel_find(net, &nt->parms, dev->type))
- return -EEXIST;
-
- if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
- eth_hw_addr_random(dev);
-
- mtu = ipgre_tunnel_bind_dev(dev);
- if (!tb[IFLA_MTU])
- dev->mtu = mtu;
-
- /* Can use a lockless transmit, unless we generate output sequences */
- if (!(nt->parms.o_flags & GRE_SEQ))
- dev->features |= NETIF_F_LLTX;
-
- err = register_netdevice(dev);
- if (err)
- goto out;
-
- dev_hold(dev);
- ipgre_tunnel_link(ign, nt);
+ struct ip_tunnel_parm p;
-out:
- return err;
+ ipgre_netlink_parms(data, tb, &p);
+ return ip_tunnel_newlink(dev, tb, &p);
}
static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
- struct ip_tunnel *t, *nt;
- struct net *net = dev_net(dev);
- struct ipgre_net *ign = net_generic(net, ipgre_net_id);
struct ip_tunnel_parm p;
- int mtu;
-
- if (dev == ign->fb_tunnel_dev)
- return -EINVAL;
-
- nt = netdev_priv(dev);
- ipgre_netlink_parms(data, &p);
-
- t = ipgre_tunnel_locate(net, &p, 0);
-
- if (t) {
- if (t->dev != dev)
- return -EEXIST;
- } else {
- t = nt;
-
- if (dev->type != ARPHRD_ETHER) {
- unsigned int nflags = 0;
-
- if (ipv4_is_multicast(p.iph.daddr))
- nflags = IFF_BROADCAST;
- else if (p.iph.daddr)
- nflags = IFF_POINTOPOINT;
-
- if ((dev->flags ^ nflags) &
- (IFF_POINTOPOINT | IFF_BROADCAST))
- return -EINVAL;
- }
- ipgre_tunnel_unlink(ign, t);
- t->parms.iph.saddr = p.iph.saddr;
- t->parms.iph.daddr = p.iph.daddr;
- t->parms.i_key = p.i_key;
- if (dev->type != ARPHRD_ETHER) {
- memcpy(dev->dev_addr, &p.iph.saddr, 4);
- memcpy(dev->broadcast, &p.iph.daddr, 4);
- }
- ipgre_tunnel_link(ign, t);
- netdev_state_change(dev);
- }
-
- t->parms.o_key = p.o_key;
- t->parms.iph.ttl = p.iph.ttl;
- t->parms.iph.tos = p.iph.tos;
- t->parms.iph.frag_off = p.iph.frag_off;
-
- if (t->parms.link != p.link) {
- t->parms.link = p.link;
- mtu = ipgre_tunnel_bind_dev(dev);
- if (!tb[IFLA_MTU])
- dev->mtu = mtu;
- netdev_state_change(dev);
- }
-
- return 0;
+ ipgre_netlink_parms(data, tb, &p);
+ return ip_tunnel_changelink(dev, tb, &p);
}
static size_t ipgre_get_size(const struct net_device *dev)
@@ -1793,8 +887,8 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
struct ip_tunnel_parm *p = &t->parms;
if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
- nla_put_be16(skb, IFLA_GRE_IFLAGS, p->i_flags) ||
- nla_put_be16(skb, IFLA_GRE_OFLAGS, p->o_flags) ||
+ nla_put_be16(skb, IFLA_GRE_IFLAGS, tnl_flags_to_gre_flags(p->i_flags)) ||
+ nla_put_be16(skb, IFLA_GRE_OFLAGS, tnl_flags_to_gre_flags(p->o_flags)) ||
nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
nla_put_be32(skb, IFLA_GRE_LOCAL, p->iph.saddr) ||
@@ -1832,6 +926,7 @@ static struct rtnl_link_ops ipgre_link_ops __read_mostly = {
.validate = ipgre_tunnel_validate,
.newlink = ipgre_newlink,
.changelink = ipgre_changelink,
+ .dellink = ip_tunnel_dellink,
.get_size = ipgre_get_size,
.fill_info = ipgre_fill_info,
};
@@ -1845,13 +940,28 @@ static struct rtnl_link_ops ipgre_tap_ops __read_mostly = {
.validate = ipgre_tap_validate,
.newlink = ipgre_newlink,
.changelink = ipgre_changelink,
+ .dellink = ip_tunnel_dellink,
.get_size = ipgre_get_size,
.fill_info = ipgre_fill_info,
};
-/*
- * And now the modules code and kernel interface.
- */
+static int __net_init ipgre_tap_init_net(struct net *net)
+{
+ return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, NULL);
+}
+
+static void __net_exit ipgre_tap_exit_net(struct net *net)
+{
+ struct ip_tunnel_net *itn = net_generic(net, gre_tap_net_id);
+ ip_tunnel_delete_net(itn);
+}
+
+static struct pernet_operations ipgre_tap_net_ops = {
+ .init = ipgre_tap_init_net,
+ .exit = ipgre_tap_exit_net,
+ .id = &gre_tap_net_id,
+ .size = sizeof(struct ip_tunnel_net),
+};
static int __init ipgre_init(void)
{
@@ -1863,6 +973,10 @@ static int __init ipgre_init(void)
if (err < 0)
return err;
+ err = register_pernet_device(&ipgre_tap_net_ops);
+ if (err < 0)
+ goto pnet_tap_faied;
+
err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
if (err < 0) {
pr_info("%s: can't add protocol\n", __func__);
@@ -1877,16 +991,17 @@ static int __init ipgre_init(void)
if (err < 0)
goto tap_ops_failed;
-out:
- return err;
+ return 0;
tap_ops_failed:
rtnl_link_unregister(&ipgre_link_ops);
rtnl_link_failed:
gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
add_proto_failed:
+ unregister_pernet_device(&ipgre_tap_net_ops);
+pnet_tap_faied:
unregister_pernet_device(&ipgre_net_ops);
- goto out;
+ return err;
}
static void __exit ipgre_fini(void)
@@ -1895,6 +1010,7 @@ static void __exit ipgre_fini(void)
rtnl_link_unregister(&ipgre_link_ops);
if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
pr_info("%s: can't remove protocol\n", __func__);
+ unregister_pernet_device(&ipgre_tap_net_ops);
unregister_pernet_device(&ipgre_net_ops);
}
@@ -1904,3 +1020,4 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_RTNL_LINK("gre");
MODULE_ALIAS_RTNL_LINK("gretap");
MODULE_ALIAS_NETDEV("gre0");
+MODULE_ALIAS_NETDEV("gretap0");
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 2bdf802e28e2..3da817b89e9b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -419,7 +419,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
iph = ip_hdr(skb);
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
- goto inhdr_error;
+ goto csum_error;
len = ntohs(iph->tot_len);
if (skb->len < len) {
@@ -446,6 +446,8 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
+csum_error:
+ IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_CSUMERRORS);
inhdr_error:
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
drop:
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 5e12dca7b3dd..147abf5275aa 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -430,8 +430,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
nf_copy(to, from);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
- defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
to->nf_trace = from->nf_trace;
#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
new file mode 100644
index 000000000000..e4147ec1665a
--- /dev/null
+++ b/net/ipv4/ip_tunnel.c
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <linux/in6.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/rculist.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/protocol.h>
+#include <net/ip_tunnels.h>
+#include <net/arp.h>
+#include <net/checksum.h>
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
+#include <net/xfrm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/rtnetlink.h>
+
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#endif
+
+static unsigned int ip_tunnel_hash(struct ip_tunnel_net *itn,
+ __be32 key, __be32 remote)
+{
+ return hash_32((__force u32)key ^ (__force u32)remote,
+ IP_TNL_HASH_BITS);
+}
+
+/* Often modified stats are per cpu, other are shared (netdev->stats) */
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *tot)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+ u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+ unsigned int start;
+
+ do {
+ start = u64_stats_fetch_begin_bh(&tstats->syncp);
+ rx_packets = tstats->rx_packets;
+ tx_packets = tstats->tx_packets;
+ rx_bytes = tstats->rx_bytes;
+ tx_bytes = tstats->tx_bytes;
+ } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+ tot->rx_packets += rx_packets;
+ tot->tx_packets += tx_packets;
+ tot->rx_bytes += rx_bytes;
+ tot->tx_bytes += tx_bytes;
+ }
+
+ tot->multicast = dev->stats.multicast;
+
+ tot->rx_crc_errors = dev->stats.rx_crc_errors;
+ tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+ tot->rx_length_errors = dev->stats.rx_length_errors;
+ tot->rx_frame_errors = dev->stats.rx_frame_errors;
+ tot->rx_errors = dev->stats.rx_errors;
+
+ tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+ tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+ tot->tx_dropped = dev->stats.tx_dropped;
+ tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+ tot->tx_errors = dev->stats.tx_errors;
+
+ tot->collisions = dev->stats.collisions;
+
+ return tot;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
+
+static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
+ __be16 flags, __be32 key)
+{
+ if (p->i_flags & TUNNEL_KEY) {
+ if (flags & TUNNEL_KEY)
+ return key == p->i_key;
+ else
+ /* key expected, none present */
+ return false;
+ } else
+ return !(flags & TUNNEL_KEY);
+}
+
+/* Fallback tunnel: no source, no destination, no key, no options
+
+ Tunnel hash table:
+ We require exact key match i.e. if a key is present in packet
+ it will match only tunnel with the same key; if it is not present,
+ it will match only keyless tunnel.
+
+ All keysless packets, if not matched configured keyless tunnels
+ will match fallback tunnel.
+ Given src, dst and key, find appropriate for input tunnel.
+*/
+struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
+ int link, __be16 flags,
+ __be32 remote, __be32 local,
+ __be32 key)
+{
+ unsigned int hash;
+ struct ip_tunnel *t, *cand = NULL;
+ struct hlist_head *head;
+
+ hash = ip_tunnel_hash(itn, key, remote);
+ head = &itn->tunnels[hash];
+
+ hlist_for_each_entry_rcu(t, head, hash_node) {
+ if (local != t->parms.iph.saddr ||
+ remote != t->parms.iph.daddr ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (!ip_tunnel_key_match(&t->parms, flags, key))
+ continue;
+
+ if (t->parms.link == link)
+ return t;
+ else
+ cand = t;
+ }
+
+ hlist_for_each_entry_rcu(t, head, hash_node) {
+ if (remote != t->parms.iph.daddr ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (!ip_tunnel_key_match(&t->parms, flags, key))
+ continue;
+
+ if (t->parms.link == link)
+ return t;
+ else if (!cand)
+ cand = t;
+ }
+
+ hash = ip_tunnel_hash(itn, key, 0);
+ head = &itn->tunnels[hash];
+
+ hlist_for_each_entry_rcu(t, head, hash_node) {
+ if ((local != t->parms.iph.saddr &&
+ (local != t->parms.iph.daddr ||
+ !ipv4_is_multicast(local))) ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (!ip_tunnel_key_match(&t->parms, flags, key))
+ continue;
+
+ if (t->parms.link == link)
+ return t;
+ else if (!cand)
+ cand = t;
+ }
+
+ if (flags & TUNNEL_NO_KEY)
+ goto skip_key_lookup;
+
+ hlist_for_each_entry_rcu(t, head, hash_node) {
+ if (t->parms.i_key != key ||
+ !(t->dev->flags & IFF_UP))
+ continue;
+
+ if (t->parms.link == link)
+ return t;
+ else if (!cand)
+ cand = t;
+ }
+
+skip_key_lookup:
+ if (cand)
+ return cand;
+
+ if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP)
+ return netdev_priv(itn->fb_tunnel_dev);
+
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_lookup);
+
+static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
+ struct ip_tunnel_parm *parms)
+{
+ unsigned int h;
+ __be32 remote;
+
+ if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
+ remote = parms->iph.daddr;
+ else
+ remote = 0;
+
+ h = ip_tunnel_hash(itn, parms->i_key, remote);
+ return &itn->tunnels[h];
+}
+
+static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t)
+{
+ struct hlist_head *head = ip_bucket(itn, &t->parms);
+
+ hlist_add_head_rcu(&t->hash_node, head);
+}
+
+static void ip_tunnel_del(struct ip_tunnel *t)
+{
+ hlist_del_init_rcu(&t->hash_node);
+}
+
+static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn,
+ struct ip_tunnel_parm *parms,
+ int type)
+{
+ __be32 remote = parms->iph.daddr;
+ __be32 local = parms->iph.saddr;
+ __be32 key = parms->i_key;
+ int link = parms->link;
+ struct ip_tunnel *t = NULL;
+ struct hlist_head *head = ip_bucket(itn, parms);
+
+ hlist_for_each_entry_rcu(t, head, hash_node) {
+ if (local == t->parms.iph.saddr &&
+ remote == t->parms.iph.daddr &&
+ key == t->parms.i_key &&
+ link == t->parms.link &&
+ type == t->dev->type)
+ break;
+ }
+ return t;
+}
+
+static struct net_device *__ip_tunnel_create(struct net *net,
+ const struct rtnl_link_ops *ops,
+ struct ip_tunnel_parm *parms)
+{
+ int err;
+ struct ip_tunnel *tunnel;
+ struct net_device *dev;
+ char name[IFNAMSIZ];
+
+ if (parms->name[0])
+ strlcpy(name, parms->name, IFNAMSIZ);
+ else {
+ if (strlen(ops->kind) > (IFNAMSIZ - 3)) {
+ err = -E2BIG;
+ goto failed;
+ }
+ strlcpy(name, ops->kind, IFNAMSIZ);
+ strncat(name, "%d", 2);
+ }
+
+ ASSERT_RTNL();
+ dev = alloc_netdev(ops->priv_size, name, ops->setup);
+ if (!dev) {
+ err = -ENOMEM;
+ goto failed;
+ }
+ dev_net_set(dev, net);
+
+ dev->rtnl_link_ops = ops;
+
+ tunnel = netdev_priv(dev);
+ tunnel->parms = *parms;
+
+ err = register_netdevice(dev);
+ if (err)
+ goto failed_free;
+
+ return dev;
+
+failed_free:
+ free_netdev(dev);
+failed:
+ return ERR_PTR(err);
+}
+
+static inline struct rtable *ip_route_output_tunnel(struct net *net,
+ struct flowi4 *fl4,
+ int proto,
+ __be32 daddr, __be32 saddr,
+ __be32 key, __u8 tos, int oif)
+{
+ memset(fl4, 0, sizeof(*fl4));
+ fl4->flowi4_oif = oif;
+ fl4->daddr = daddr;
+ fl4->saddr = saddr;
+ fl4->flowi4_tos = tos;
+ fl4->flowi4_proto = proto;
+ fl4->fl4_gre_key = key;
+ return ip_route_output_key(net, fl4);
+}
+
+static int ip_tunnel_bind_dev(struct net_device *dev)
+{
+ struct net_device *tdev = NULL;
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ const struct iphdr *iph;
+ int hlen = LL_MAX_HEADER;
+ int mtu = ETH_DATA_LEN;
+ int t_hlen = tunnel->hlen + sizeof(struct iphdr);
+
+ iph = &tunnel->parms.iph;
+
+ /* Guess output device to choose reasonable mtu and needed_headroom */
+ if (iph->daddr) {
+ struct flowi4 fl4;
+ struct rtable *rt;
+
+ rt = ip_route_output_tunnel(dev_net(dev), &fl4,
+ tunnel->parms.iph.protocol,
+ iph->daddr, iph->saddr,
+ tunnel->parms.o_key,
+ RT_TOS(iph->tos),
+ tunnel->parms.link);
+ if (!IS_ERR(rt)) {
+ tdev = rt->dst.dev;
+ ip_rt_put(rt);
+ }
+ if (dev->type != ARPHRD_ETHER)
+ dev->flags |= IFF_POINTOPOINT;
+ }
+
+ if (!tdev && tunnel->parms.link)
+ tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
+
+ if (tdev) {
+ hlen = tdev->hard_header_len + tdev->needed_headroom;
+ mtu = tdev->mtu;
+ }
+ dev->iflink = tunnel->parms.link;
+
+ dev->needed_headroom = t_hlen + hlen;
+ mtu -= (dev->hard_header_len + t_hlen);
+
+ if (mtu < 68)
+ mtu = 68;
+
+ return mtu;
+}
+
+static struct ip_tunnel *ip_tunnel_create(struct net *net,
+ struct ip_tunnel_net *itn,
+ struct ip_tunnel_parm *parms)
+{
+ struct ip_tunnel *nt, *fbt;
+ struct net_device *dev;
+
+ BUG_ON(!itn->fb_tunnel_dev);
+ fbt = netdev_priv(itn->fb_tunnel_dev);
+ dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms);
+ if (IS_ERR(dev))
+ return NULL;
+
+ dev->mtu = ip_tunnel_bind_dev(dev);
+
+ nt = netdev_priv(dev);
+ ip_tunnel_add(itn, nt);
+ return nt;
+}
+
+int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
+ const struct tnl_ptk_info *tpi, bool log_ecn_error)
+{
+ struct pcpu_tstats *tstats;
+ const struct iphdr *iph = ip_hdr(skb);
+ int err;
+
+ secpath_reset(skb);
+
+ skb->protocol = tpi->proto;
+
+ skb->mac_header = skb->network_header;
+ __pskb_pull(skb, tunnel->hlen);
+ skb_postpull_rcsum(skb, skb_transport_header(skb), tunnel->hlen);
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+ if (ipv4_is_multicast(iph->daddr)) {
+ /* Looped back packet, drop it! */
+ if (rt_is_output_route(skb_rtable(skb)))
+ goto drop;
+ tunnel->dev->stats.multicast++;
+ skb->pkt_type = PACKET_BROADCAST;
+ }
+#endif
+
+ if ((!(tpi->flags&TUNNEL_CSUM) && (tunnel->parms.i_flags&TUNNEL_CSUM)) ||
+ ((tpi->flags&TUNNEL_CSUM) && !(tunnel->parms.i_flags&TUNNEL_CSUM))) {
+ tunnel->dev->stats.rx_crc_errors++;
+ tunnel->dev->stats.rx_errors++;
+ goto drop;
+ }
+
+ if (tunnel->parms.i_flags&TUNNEL_SEQ) {
+ if (!(tpi->flags&TUNNEL_SEQ) ||
+ (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) {
+ tunnel->dev->stats.rx_fifo_errors++;
+ tunnel->dev->stats.rx_errors++;
+ goto drop;
+ }
+ tunnel->i_seqno = ntohl(tpi->seq) + 1;
+ }
+
+ /* Warning: All skb pointers will be invalidated! */
+ if (tunnel->dev->type == ARPHRD_ETHER) {
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
+ tunnel->dev->stats.rx_length_errors++;
+ tunnel->dev->stats.rx_errors++;
+ goto drop;
+ }
+
+ iph = ip_hdr(skb);
+ skb->protocol = eth_type_trans(skb, tunnel->dev);
+ skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+ }
+
+ skb->pkt_type = PACKET_HOST;
+ __skb_tunnel_rx(skb, tunnel->dev);
+
+ skb_reset_network_header(skb);
+ err = IP_ECN_decapsulate(iph, skb);
+ if (unlikely(err)) {
+ if (log_ecn_error)
+ net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
+ &iph->saddr, iph->tos);
+ if (err > 1) {
+ ++tunnel->dev->stats.rx_frame_errors;
+ ++tunnel->dev->stats.rx_errors;
+ goto drop;
+ }
+ }
+
+ tstats = this_cpu_ptr(tunnel->dev->tstats);
+ u64_stats_update_begin(&tstats->syncp);
+ tstats->rx_packets++;
+ tstats->rx_bytes += skb->len;
+ u64_stats_update_end(&tstats->syncp);
+
+ gro_cells_receive(&tunnel->gro_cells, skb);
+ return 0;
+
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_rcv);
+
+void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
+ const struct iphdr *tnl_params)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ const struct iphdr *inner_iph;
+ struct iphdr *iph;
+ struct flowi4 fl4;
+ u8 tos, ttl;
+ __be16 df;
+ struct rtable *rt; /* Route to the other host */
+ struct net_device *tdev; /* Device to other host */
+ unsigned int max_headroom; /* The extra header space needed */
+ __be32 dst;
+ int mtu;
+
+ inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
+
+ dst = tnl_params->daddr;
+ if (dst == 0) {
+ /* NBMA tunnel */
+
+ if (skb_dst(skb) == NULL) {
+ dev->stats.tx_fifo_errors++;
+ goto tx_error;
+ }
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ rt = skb_rtable(skb);
+ dst = rt_nexthop(rt, inner_iph->daddr);
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (skb->protocol == htons(ETH_P_IPV6)) {
+ const struct in6_addr *addr6;
+ struct neighbour *neigh;
+ bool do_tx_error_icmp;
+ int addr_type;
+
+ neigh = dst_neigh_lookup(skb_dst(skb),
+ &ipv6_hdr(skb)->daddr);
+ if (neigh == NULL)
+ goto tx_error;
+
+ addr6 = (const struct in6_addr *)&neigh->primary_key;
+ addr_type = ipv6_addr_type(addr6);
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ addr6 = &ipv6_hdr(skb)->daddr;
+ addr_type = ipv6_addr_type(addr6);
+ }
+
+ if ((addr_type & IPV6_ADDR_COMPATv4) == 0)
+ do_tx_error_icmp = true;
+ else {
+ do_tx_error_icmp = false;
+ dst = addr6->s6_addr32[3];
+ }
+ neigh_release(neigh);
+ if (do_tx_error_icmp)
+ goto tx_error_icmp;
+ }
+#endif
+ else
+ goto tx_error;
+ }
+
+ tos = tnl_params->tos;
+ if (tos & 0x1) {
+ tos &= ~0x1;
+ if (skb->protocol == htons(ETH_P_IP))
+ tos = inner_iph->tos;
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
+ }
+
+ rt = ip_route_output_tunnel(dev_net(dev), &fl4,
+ tunnel->parms.iph.protocol,
+ dst, tnl_params->saddr,
+ tunnel->parms.o_key,
+ RT_TOS(tos),
+ tunnel->parms.link);
+ if (IS_ERR(rt)) {
+ dev->stats.tx_carrier_errors++;
+ goto tx_error;
+ }
+ tdev = rt->dst.dev;
+
+ if (tdev == dev) {
+ ip_rt_put(rt);
+ dev->stats.collisions++;
+ goto tx_error;
+ }
+
+ df = tnl_params->frag_off;
+
+ if (df)
+ mtu = dst_mtu(&rt->dst) - dev->hard_header_len
+ - sizeof(struct iphdr);
+ else
+ mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
+
+ if (skb_dst(skb))
+ skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ df |= (inner_iph->frag_off&htons(IP_DF));
+
+ if (!skb_is_gso(skb) &&
+ (inner_iph->frag_off&htons(IP_DF)) &&
+ mtu < ntohs(inner_iph->tot_len)) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ }
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (skb->protocol == htons(ETH_P_IPV6)) {
+ struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb);
+
+ if (rt6 && mtu < dst_mtu(skb_dst(skb)) &&
+ mtu >= IPV6_MIN_MTU) {
+ if ((tunnel->parms.iph.daddr &&
+ !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
+ rt6->rt6i_dst.plen == 128) {
+ rt6->rt6i_flags |= RTF_MODIFIED;
+ dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
+ }
+ }
+
+ if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU &&
+ mtu < skb->len) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ ip_rt_put(rt);
+ goto tx_error;
+ }
+ }
+#endif
+
+ if (tunnel->err_count > 0) {
+ if (time_before(jiffies,
+ tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
+ tunnel->err_count--;
+
+ dst_link_failure(skb);
+ } else
+ tunnel->err_count = 0;
+ }
+
+ ttl = tnl_params->ttl;
+ if (ttl == 0) {
+ if (skb->protocol == htons(ETH_P_IP))
+ ttl = inner_iph->ttl;
+#if IS_ENABLED(CONFIG_IPV6)
+ else if (skb->protocol == htons(ETH_P_IPV6))
+ ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit;
+#endif
+ else
+ ttl = ip4_dst_hoplimit(&rt->dst);
+ }
+
+ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr)
+ + rt->dst.header_len;
+ if (max_headroom > dev->needed_headroom) {
+ dev->needed_headroom = max_headroom;
+ if (skb_cow_head(skb, dev->needed_headroom)) {
+ dev->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ skb_dst_drop(skb);
+ skb_dst_set(skb, &rt->dst);
+ memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+
+ /* Push down and install the IP header. */
+ skb_push(skb, sizeof(struct iphdr));
+ skb_reset_network_header(skb);
+
+ iph = ip_hdr(skb);
+ inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
+
+ iph->version = 4;
+ iph->ihl = sizeof(struct iphdr) >> 2;
+ iph->frag_off = df;
+ iph->protocol = tnl_params->protocol;
+ iph->tos = ip_tunnel_ecn_encap(tos, inner_iph, skb);
+ iph->daddr = fl4.daddr;
+ iph->saddr = fl4.saddr;
+ iph->ttl = ttl;
+ tunnel_ip_select_ident(skb, inner_iph, &rt->dst);
+
+ iptunnel_xmit(skb, dev);
+ return;
+
+#if IS_ENABLED(CONFIG_IPV6)
+tx_error_icmp:
+ dst_link_failure(skb);
+#endif
+tx_error:
+ dev->stats.tx_errors++;
+ dev_kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_xmit);
+
+static void ip_tunnel_update(struct ip_tunnel_net *itn,
+ struct ip_tunnel *t,
+ struct net_device *dev,
+ struct ip_tunnel_parm *p,
+ bool set_mtu)
+{
+ ip_tunnel_del(t);
+ t->parms.iph.saddr = p->iph.saddr;
+ t->parms.iph.daddr = p->iph.daddr;
+ t->parms.i_key = p->i_key;
+ t->parms.o_key = p->o_key;
+ if (dev->type != ARPHRD_ETHER) {
+ memcpy(dev->dev_addr, &p->iph.saddr, 4);
+ memcpy(dev->broadcast, &p->iph.daddr, 4);
+ }
+ ip_tunnel_add(itn, t);
+
+ t->parms.iph.ttl = p->iph.ttl;
+ t->parms.iph.tos = p->iph.tos;
+ t->parms.iph.frag_off = p->iph.frag_off;
+
+ if (t->parms.link != p->link) {
+ int mtu;
+
+ t->parms.link = p->link;
+ mtu = ip_tunnel_bind_dev(dev);
+ if (set_mtu)
+ dev->mtu = mtu;
+ }
+ netdev_state_change(dev);
+}
+
+int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
+{
+ int err = 0;
+ struct ip_tunnel *t;
+ struct net *net = dev_net(dev);
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);
+
+ BUG_ON(!itn->fb_tunnel_dev);
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ t = NULL;
+ if (dev == itn->fb_tunnel_dev)
+ t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
+ if (t == NULL)
+ t = netdev_priv(dev);
+ memcpy(p, &t->parms, sizeof(*p));
+ break;
+
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ goto done;
+ if (p->iph.ttl)
+ p->iph.frag_off |= htons(IP_DF);
+ if (!(p->i_flags&TUNNEL_KEY))
+ p->i_key = 0;
+ if (!(p->o_flags&TUNNEL_KEY))
+ p->o_key = 0;
+
+ t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
+
+ if (!t && (cmd == SIOCADDTUNNEL))
+ t = ip_tunnel_create(net, itn, p);
+
+ if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
+ if (t != NULL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ } else {
+ unsigned int nflags = 0;
+
+ if (ipv4_is_multicast(p->iph.daddr))
+ nflags = IFF_BROADCAST;
+ else if (p->iph.daddr)
+ nflags = IFF_POINTOPOINT;
+
+ if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) {
+ err = -EINVAL;
+ break;
+ }
+
+ t = netdev_priv(dev);
+ }
+ }
+
+ if (t) {
+ err = 0;
+ ip_tunnel_update(itn, t, dev, p, true);
+ } else
+ err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+ break;
+
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ goto done;
+
+ if (dev == itn->fb_tunnel_dev) {
+ err = -ENOENT;
+ t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
+ if (t == NULL)
+ goto done;
+ err = -EPERM;
+ if (t == netdev_priv(itn->fb_tunnel_dev))
+ goto done;
+ dev = t->dev;
+ }
+ unregister_netdevice(dev);
+ err = 0;
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+done:
+ return err;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_ioctl);
+
+int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ int t_hlen = tunnel->hlen + sizeof(struct iphdr);
+
+ if (new_mtu < 68 ||
+ new_mtu > 0xFFF8 - dev->hard_header_len - t_hlen)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu);
+
+static void ip_tunnel_dev_free(struct net_device *dev)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+
+ gro_cells_destroy(&tunnel->gro_cells);
+ free_percpu(dev->tstats);
+ free_netdev(dev);
+}
+
+void ip_tunnel_dellink(struct net_device *dev, struct list_head *head)
+{
+ struct net *net = dev_net(dev);
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct ip_tunnel_net *itn;
+
+ itn = net_generic(net, tunnel->ip_tnl_net_id);
+
+ if (itn->fb_tunnel_dev != dev) {
+ ip_tunnel_del(netdev_priv(dev));
+ unregister_netdevice_queue(dev, head);
+ }
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_dellink);
+
+int __net_init ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
+ struct rtnl_link_ops *ops, char *devname)
+{
+ struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id);
+ struct ip_tunnel_parm parms;
+
+ itn->tunnels = kzalloc(IP_TNL_HASH_SIZE * sizeof(struct hlist_head), GFP_KERNEL);
+ if (!itn->tunnels)
+ return -ENOMEM;
+
+ if (!ops) {
+ itn->fb_tunnel_dev = NULL;
+ return 0;
+ }
+ memset(&parms, 0, sizeof(parms));
+ if (devname)
+ strlcpy(parms.name, devname, IFNAMSIZ);
+
+ rtnl_lock();
+ itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms);
+ rtnl_unlock();
+ if (IS_ERR(itn->fb_tunnel_dev)) {
+ kfree(itn->tunnels);
+ return PTR_ERR(itn->fb_tunnel_dev);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
+
+static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head)
+{
+ int h;
+
+ for (h = 0; h < IP_TNL_HASH_SIZE; h++) {
+ struct ip_tunnel *t;
+ struct hlist_node *n;
+ struct hlist_head *thead = &itn->tunnels[h];
+
+ hlist_for_each_entry_safe(t, n, thead, hash_node)
+ unregister_netdevice_queue(t->dev, head);
+ }
+ if (itn->fb_tunnel_dev)
+ unregister_netdevice_queue(itn->fb_tunnel_dev, head);
+}
+
+void __net_exit ip_tunnel_delete_net(struct ip_tunnel_net *itn)
+{
+ LIST_HEAD(list);
+
+ rtnl_lock();
+ ip_tunnel_destroy(itn, &list);
+ unregister_netdevice_many(&list);
+ rtnl_unlock();
+ kfree(itn->tunnels);
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_delete_net);
+
+int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
+ struct ip_tunnel_parm *p)
+{
+ struct ip_tunnel *nt;
+ struct net *net = dev_net(dev);
+ struct ip_tunnel_net *itn;
+ int mtu;
+ int err;
+
+ nt = netdev_priv(dev);
+ itn = net_generic(net, nt->ip_tnl_net_id);
+
+ if (ip_tunnel_find(itn, p, dev->type))
+ return -EEXIST;
+
+ nt->parms = *p;
+ err = register_netdevice(dev);
+ if (err)
+ goto out;
+
+ if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
+ eth_hw_addr_random(dev);
+
+ mtu = ip_tunnel_bind_dev(dev);
+ if (!tb[IFLA_MTU])
+ dev->mtu = mtu;
+
+ ip_tunnel_add(itn, nt);
+
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
+
+int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
+ struct ip_tunnel_parm *p)
+{
+ struct ip_tunnel *t, *nt;
+ struct net *net = dev_net(dev);
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id);
+
+ if (dev == itn->fb_tunnel_dev)
+ return -EINVAL;
+
+ nt = netdev_priv(dev);
+
+ t = ip_tunnel_find(itn, p, dev->type);
+
+ if (t) {
+ if (t->dev != dev)
+ return -EEXIST;
+ } else {
+ t = nt;
+
+ if (dev->type != ARPHRD_ETHER) {
+ unsigned int nflags = 0;
+
+ if (ipv4_is_multicast(p->iph.daddr))
+ nflags = IFF_BROADCAST;
+ else if (p->iph.daddr)
+ nflags = IFF_POINTOPOINT;
+
+ if ((dev->flags ^ nflags) &
+ (IFF_POINTOPOINT | IFF_BROADCAST))
+ return -EINVAL;
+ }
+ }
+
+ ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU]);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_changelink);
+
+int ip_tunnel_init(struct net_device *dev)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct iphdr *iph = &tunnel->parms.iph;
+ int err;
+
+ dev->destructor = ip_tunnel_dev_free;
+ dev->tstats = alloc_percpu(struct pcpu_tstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
+ err = gro_cells_init(&tunnel->gro_cells, dev);
+ if (err) {
+ free_percpu(dev->tstats);
+ return err;
+ }
+
+ tunnel->dev = dev;
+ strcpy(tunnel->parms.name, dev->name);
+ iph->version = 4;
+ iph->ihl = 5;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_init);
+
+void ip_tunnel_uninit(struct net_device *dev)
+{
+ struct net *net = dev_net(dev);
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ struct ip_tunnel_net *itn;
+
+ itn = net_generic(net, tunnel->ip_tnl_net_id);
+ /* fb_tunnel_dev will be unregisted in net-exit call. */
+ if (itn->fb_tunnel_dev != dev)
+ ip_tunnel_del(netdev_priv(dev));
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
+
+/* Do least required initialization, rest of init is done in tunnel_init call */
+void ip_tunnel_setup(struct net_device *dev, int net_id)
+{
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+ tunnel->ip_tnl_net_id = net_id;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_setup);
+
+MODULE_LICENSE("GPL");
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index c3a4233c0ac2..9d2bdb2c1d3f 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -38,7 +38,7 @@
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
@@ -82,44 +82,6 @@ static int vti_tunnel_bind_dev(struct net_device *dev);
} while (0)
-static struct rtnl_link_stats64 *vti_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
- tot->multicast = dev->stats.multicast;
- tot->rx_crc_errors = dev->stats.rx_crc_errors;
- tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
- tot->rx_length_errors = dev->stats.rx_length_errors;
- tot->rx_errors = dev->stats.rx_errors;
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
-
- return tot;
-}
-
static struct ip_tunnel *vti_tunnel_lookup(struct net *net,
__be32 remote, __be32 local)
{
@@ -597,7 +559,7 @@ static const struct net_device_ops vti_netdev_ops = {
.ndo_start_xmit = vti_tunnel_xmit,
.ndo_do_ioctl = vti_tunnel_ioctl,
.ndo_change_mtu = vti_tunnel_change_mtu,
- .ndo_get_stats64 = vti_get_stats64,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
static void vti_dev_free(struct net_device *dev)
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index f01d1b1aff7f..59cb8c769056 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -75,6 +75,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
t->props.mode = x->props.mode;
t->props.saddr.a4 = x->props.saddr.a4;
t->props.flags = x->props.flags;
+ t->props.extra_flags = x->props.extra_flags;
memcpy(&t->mark, &x->mark, sizeof(t->mark));
if (xfrm_init_state(t))
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index bf6c5cf31aed..efa1138fa523 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -206,7 +206,7 @@ static int __init ic_open_devs(void)
struct ic_device *d, **last;
struct net_device *dev;
unsigned short oflags;
- unsigned long start;
+ unsigned long start, next_msg;
last = &ic_first_dev;
rtnl_lock();
@@ -263,12 +263,23 @@ static int __init ic_open_devs(void)
/* wait for a carrier on at least one device */
start = jiffies;
+ next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12);
while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) {
+ int wait, elapsed;
+
for_each_netdev(&init_net, dev)
if (ic_is_init_dev(dev) && netif_carrier_ok(dev))
goto have_carrier;
msleep(1);
+
+ if time_before(jiffies, next_msg)
+ continue;
+
+ elapsed = jiffies_to_msecs(jiffies - start);
+ wait = (CONF_CARRIER_TIMEOUT - elapsed + 500)/1000;
+ pr_info("Waiting up to %d more seconds for network.\n", wait);
+ next_msg = jiffies + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12);
}
have_carrier:
rtnl_unlock();
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 8f024d41eefa..77bfcce64fe5 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -111,227 +111,21 @@
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
-#define HASH_SIZE 16
-#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
-
static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
static int ipip_net_id __read_mostly;
-struct ipip_net {
- struct ip_tunnel __rcu *tunnels_r_l[HASH_SIZE];
- struct ip_tunnel __rcu *tunnels_r[HASH_SIZE];
- struct ip_tunnel __rcu *tunnels_l[HASH_SIZE];
- struct ip_tunnel __rcu *tunnels_wc[1];
- struct ip_tunnel __rcu **tunnels[4];
-
- struct net_device *fb_tunnel_dev;
-};
static int ipip_tunnel_init(struct net_device *dev);
-static void ipip_tunnel_setup(struct net_device *dev);
-static void ipip_dev_free(struct net_device *dev);
static struct rtnl_link_ops ipip_link_ops __read_mostly;
-static struct rtnl_link_stats64 *ipip_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
- tot->collisions = dev->stats.collisions;
-
- return tot;
-}
-
-static struct ip_tunnel *ipip_tunnel_lookup(struct net *net,
- __be32 remote, __be32 local)
-{
- unsigned int h0 = HASH(remote);
- unsigned int h1 = HASH(local);
- struct ip_tunnel *t;
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- for_each_ip_tunnel_rcu(t, ipn->tunnels_r_l[h0 ^ h1])
- if (local == t->parms.iph.saddr &&
- remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
- return t;
-
- for_each_ip_tunnel_rcu(t, ipn->tunnels_r[h0])
- if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
- return t;
-
- for_each_ip_tunnel_rcu(t, ipn->tunnels_l[h1])
- if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
- return t;
-
- t = rcu_dereference(ipn->tunnels_wc[0]);
- if (t && (t->dev->flags&IFF_UP))
- return t;
- return NULL;
-}
-
-static struct ip_tunnel __rcu **__ipip_bucket(struct ipip_net *ipn,
- struct ip_tunnel_parm *parms)
-{
- __be32 remote = parms->iph.daddr;
- __be32 local = parms->iph.saddr;
- unsigned int h = 0;
- int prio = 0;
-
- if (remote) {
- prio |= 2;
- h ^= HASH(remote);
- }
- if (local) {
- prio |= 1;
- h ^= HASH(local);
- }
- return &ipn->tunnels[prio][h];
-}
-
-static inline struct ip_tunnel __rcu **ipip_bucket(struct ipip_net *ipn,
- struct ip_tunnel *t)
-{
- return __ipip_bucket(ipn, &t->parms);
-}
-
-static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t)
-{
- struct ip_tunnel __rcu **tp;
- struct ip_tunnel *iter;
-
- for (tp = ipip_bucket(ipn, t);
- (iter = rtnl_dereference(*tp)) != NULL;
- tp = &iter->next) {
- if (t == iter) {
- rcu_assign_pointer(*tp, t->next);
- break;
- }
- }
-}
-
-static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t)
-{
- struct ip_tunnel __rcu **tp = ipip_bucket(ipn, t);
-
- rcu_assign_pointer(t->next, rtnl_dereference(*tp));
- rcu_assign_pointer(*tp, t);
-}
-
-static int ipip_tunnel_create(struct net_device *dev)
-{
- struct ip_tunnel *t = netdev_priv(dev);
- struct net *net = dev_net(dev);
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
- int err;
-
- err = ipip_tunnel_init(dev);
- if (err < 0)
- goto out;
-
- err = register_netdevice(dev);
- if (err < 0)
- goto out;
-
- strcpy(t->parms.name, dev->name);
- dev->rtnl_link_ops = &ipip_link_ops;
-
- dev_hold(dev);
- ipip_tunnel_link(ipn, t);
- return 0;
-
-out:
- return err;
-}
-
-static struct ip_tunnel *ipip_tunnel_locate(struct net *net,
- struct ip_tunnel_parm *parms, int create)
-{
- __be32 remote = parms->iph.daddr;
- __be32 local = parms->iph.saddr;
- struct ip_tunnel *t, *nt;
- struct ip_tunnel __rcu **tp;
- struct net_device *dev;
- char name[IFNAMSIZ];
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- for (tp = __ipip_bucket(ipn, parms);
- (t = rtnl_dereference(*tp)) != NULL;
- tp = &t->next) {
- if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr)
- return t;
- }
- if (!create)
- return NULL;
-
- if (parms->name[0])
- strlcpy(name, parms->name, IFNAMSIZ);
- else
- strcpy(name, "tunl%d");
-
- dev = alloc_netdev(sizeof(*t), name, ipip_tunnel_setup);
- if (dev == NULL)
- return NULL;
-
- dev_net_set(dev, net);
-
- nt = netdev_priv(dev);
- nt->parms = *parms;
-
- if (ipip_tunnel_create(dev) < 0)
- goto failed_free;
-
- return nt;
-
-failed_free:
- ipip_dev_free(dev);
- return NULL;
-}
-
-/* called with RTNL */
-static void ipip_tunnel_uninit(struct net_device *dev)
-{
- struct net *net = dev_net(dev);
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- if (dev == ipn->fb_tunnel_dev)
- RCU_INIT_POINTER(ipn->tunnels_wc[0], NULL);
- else
- ipip_tunnel_unlink(ipn, netdev_priv(dev));
- dev_put(dev);
-}
-
static int ipip_err(struct sk_buff *skb, u32 info)
{
@@ -339,41 +133,17 @@ static int ipip_err(struct sk_buff *skb, u32 info)
8 bytes of packet payload. It means, that precise relaying of
ICMP in the real Internet is absolutely infeasible.
*/
+ struct net *net = dev_net(skb->dev);
+ struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
const struct iphdr *iph = (const struct iphdr *)skb->data;
- const int type = icmp_hdr(skb)->type;
- const int code = icmp_hdr(skb)->code;
struct ip_tunnel *t;
int err;
-
- switch (type) {
- default:
- case ICMP_PARAMETERPROB:
- return 0;
-
- case ICMP_DEST_UNREACH:
- switch (code) {
- case ICMP_SR_FAILED:
- case ICMP_PORT_UNREACH:
- /* Impossible event. */
- return 0;
- default:
- /* All others are translated to HOST_UNREACH.
- rfc2003 contains "deep thoughts" about NET_UNREACH,
- I believe they are just ether pollution. --ANK
- */
- break;
- }
- break;
- case ICMP_TIME_EXCEEDED:
- if (code != ICMP_EXC_TTL)
- return 0;
- break;
- case ICMP_REDIRECT:
- break;
- }
+ const int type = icmp_hdr(skb)->type;
+ const int code = icmp_hdr(skb)->code;
err = -ENOENT;
- t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr);
+ t = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+ iph->daddr, iph->saddr, 0);
if (t == NULL)
goto out;
@@ -403,53 +173,29 @@ static int ipip_err(struct sk_buff *skb, u32 info)
else
t->err_count = 1;
t->err_time = jiffies;
-out:
+out:
return err;
}
+static const struct tnl_ptk_info tpi = {
+ /* no tunnel info required for ipip. */
+ .proto = htons(ETH_P_IP),
+};
+
static int ipip_rcv(struct sk_buff *skb)
{
+ struct net *net = dev_net(skb->dev);
+ struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
struct ip_tunnel *tunnel;
const struct iphdr *iph = ip_hdr(skb);
- int err;
-
- tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr);
- if (tunnel != NULL) {
- struct pcpu_tstats *tstats;
+ tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+ iph->saddr, iph->daddr, 0);
+ if (tunnel) {
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop;
-
- secpath_reset(skb);
-
- skb->mac_header = skb->network_header;
- skb_reset_network_header(skb);
- skb->protocol = htons(ETH_P_IP);
- skb->pkt_type = PACKET_HOST;
-
- __skb_tunnel_rx(skb, tunnel->dev);
-
- err = IP_ECN_decapsulate(iph, skb);
- if (unlikely(err)) {
- if (log_ecn_error)
- net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n",
- &iph->saddr, iph->tos);
- if (err > 1) {
- ++tunnel->dev->stats.rx_frame_errors;
- ++tunnel->dev->stats.rx_errors;
- goto drop;
- }
- }
-
- tstats = this_cpu_ptr(tunnel->dev->tstats);
- u64_stats_update_begin(&tstats->syncp);
- tstats->rx_packets++;
- tstats->rx_bytes += skb->len;
- u64_stats_update_end(&tstats->syncp);
-
- netif_rx(skb);
- return 0;
+ return ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error);
}
return -1;
@@ -463,329 +209,64 @@ drop:
* This function assumes it is being called from dev_queue_xmit()
* and that skb is filled properly by that function.
*/
-
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
const struct iphdr *tiph = &tunnel->parms.iph;
- u8 tos = tunnel->parms.iph.tos;
- __be16 df = tiph->frag_off;
- struct rtable *rt; /* Route to the other host */
- struct net_device *tdev; /* Device to other host */
- const struct iphdr *old_iph;
- struct iphdr *iph; /* Our new IP header */
- unsigned int max_headroom; /* The extra header space needed */
- __be32 dst = tiph->daddr;
- struct flowi4 fl4;
- int mtu;
-
- if (skb->protocol != htons(ETH_P_IP))
- goto tx_error;
- if (skb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_help(skb))
+ if (unlikely(skb->protocol != htons(ETH_P_IP)))
goto tx_error;
- old_iph = ip_hdr(skb);
-
- if (tos & 1)
- tos = old_iph->tos;
-
- if (!dst) {
- /* NBMA tunnel */
- if ((rt = skb_rtable(skb)) == NULL) {
- dev->stats.tx_fifo_errors++;
- goto tx_error;
- }
- dst = rt_nexthop(rt, old_iph->daddr);
+ if (likely(!skb->encapsulation)) {
+ skb_reset_inner_headers(skb);
+ skb->encapsulation = 1;
}
- rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
- dst, tiph->saddr,
- 0, 0,
- IPPROTO_IPIP, RT_TOS(tos),
- tunnel->parms.link);
- if (IS_ERR(rt)) {
- dev->stats.tx_carrier_errors++;
- goto tx_error_icmp;
- }
- tdev = rt->dst.dev;
-
- if (tdev == dev) {
- ip_rt_put(rt);
- dev->stats.collisions++;
- goto tx_error;
- }
-
- df |= old_iph->frag_off & htons(IP_DF);
-
- if (df) {
- mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
-
- if (mtu < 68) {
- dev->stats.collisions++;
- ip_rt_put(rt);
- goto tx_error;
- }
-
- if (skb_dst(skb))
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-
- if ((old_iph->frag_off & htons(IP_DF)) &&
- mtu < ntohs(old_iph->tot_len)) {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
- htonl(mtu));
- ip_rt_put(rt);
- goto tx_error;
- }
- }
-
- if (tunnel->err_count > 0) {
- if (time_before(jiffies,
- tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
- tunnel->err_count--;
- dst_link_failure(skb);
- } else
- tunnel->err_count = 0;
- }
-
- /*
- * Okay, now see if we can stuff it in the buffer as-is.
- */
- max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr));
-
- if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
- (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
- struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
- if (!new_skb) {
- ip_rt_put(rt);
- dev->stats.tx_dropped++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- if (skb->sk)
- skb_set_owner_w(new_skb, skb->sk);
- dev_kfree_skb(skb);
- skb = new_skb;
- old_iph = ip_hdr(skb);
- }
-
- skb->transport_header = skb->network_header;
- skb_push(skb, sizeof(struct iphdr));
- skb_reset_network_header(skb);
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
- IPSKB_REROUTED);
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
- /*
- * Push down and install the IPIP header.
- */
-
- iph = ip_hdr(skb);
- iph->version = 4;
- iph->ihl = sizeof(struct iphdr)>>2;
- iph->frag_off = df;
- iph->protocol = IPPROTO_IPIP;
- iph->tos = INET_ECN_encapsulate(tos, old_iph->tos);
- iph->daddr = fl4.daddr;
- iph->saddr = fl4.saddr;
-
- if ((iph->ttl = tiph->ttl) == 0)
- iph->ttl = old_iph->ttl;
-
- iptunnel_xmit(skb, dev);
+ ip_tunnel_xmit(skb, dev, tiph);
return NETDEV_TX_OK;
-tx_error_icmp:
- dst_link_failure(skb);
tx_error:
dev->stats.tx_errors++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
-static void ipip_tunnel_bind_dev(struct net_device *dev)
-{
- struct net_device *tdev = NULL;
- struct ip_tunnel *tunnel;
- const struct iphdr *iph;
-
- tunnel = netdev_priv(dev);
- iph = &tunnel->parms.iph;
-
- if (iph->daddr) {
- struct rtable *rt;
- struct flowi4 fl4;
-
- rt = ip_route_output_ports(dev_net(dev), &fl4, NULL,
- iph->daddr, iph->saddr,
- 0, 0,
- IPPROTO_IPIP,
- RT_TOS(iph->tos),
- tunnel->parms.link);
- if (!IS_ERR(rt)) {
- tdev = rt->dst.dev;
- ip_rt_put(rt);
- }
- dev->flags |= IFF_POINTOPOINT;
- }
-
- if (!tdev && tunnel->parms.link)
- tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link);
-
- if (tdev) {
- dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr);
- dev->mtu = tdev->mtu - sizeof(struct iphdr);
- }
- dev->iflink = tunnel->parms.link;
-}
-
-static void ipip_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
-{
- struct net *net = dev_net(t->dev);
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- ipip_tunnel_unlink(ipn, t);
- synchronize_net();
- t->parms.iph.saddr = p->iph.saddr;
- t->parms.iph.daddr = p->iph.daddr;
- memcpy(t->dev->dev_addr, &p->iph.saddr, 4);
- memcpy(t->dev->broadcast, &p->iph.daddr, 4);
- ipip_tunnel_link(ipn, t);
- t->parms.iph.ttl = p->iph.ttl;
- t->parms.iph.tos = p->iph.tos;
- t->parms.iph.frag_off = p->iph.frag_off;
- if (t->parms.link != p->link) {
- t->parms.link = p->link;
- ipip_tunnel_bind_dev(t->dev);
- }
- netdev_state_change(t->dev);
-}
-
static int
-ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
+ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
int err = 0;
struct ip_tunnel_parm p;
- struct ip_tunnel *t;
- struct net *net = dev_net(dev);
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- switch (cmd) {
- case SIOCGETTUNNEL:
- t = NULL;
- if (dev == ipn->fb_tunnel_dev) {
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
- err = -EFAULT;
- break;
- }
- t = ipip_tunnel_locate(net, &p, 0);
- }
- if (t == NULL)
- t = netdev_priv(dev);
- memcpy(&p, &t->parms, sizeof(p));
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
- break;
-
- case SIOCADDTUNNEL:
- case SIOCCHGTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
-
- err = -EINVAL;
- if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
- p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
- goto done;
- if (p.iph.ttl)
- p.iph.frag_off |= htons(IP_DF);
-
- t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
-
- if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
- if (t != NULL) {
- if (t->dev != dev) {
- err = -EEXIST;
- break;
- }
- } else {
- if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) ||
- (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) {
- err = -EINVAL;
- break;
- }
- t = netdev_priv(dev);
- }
-
- ipip_tunnel_update(t, &p);
- }
-
- if (t) {
- err = 0;
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p)))
- err = -EFAULT;
- } else
- err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
- break;
-
- case SIOCDELTUNNEL:
- err = -EPERM;
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
- goto done;
-
- if (dev == ipn->fb_tunnel_dev) {
- err = -EFAULT;
- if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
- goto done;
- err = -ENOENT;
- if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL)
- goto done;
- err = -EPERM;
- if (t->dev == ipn->fb_tunnel_dev)
- goto done;
- dev = t->dev;
- }
- unregister_netdevice(dev);
- err = 0;
- break;
- default:
- err = -EINVAL;
- }
-
-done:
- return err;
-}
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+ return -EFAULT;
-static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu)
-{
- if (new_mtu < 68 || new_mtu > 0xFFF8 - sizeof(struct iphdr))
+ if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP ||
+ p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
+ return -EINVAL;
+ if (p.i_key || p.o_key || p.i_flags || p.o_flags)
return -EINVAL;
- dev->mtu = new_mtu;
+ if (p.iph.ttl)
+ p.iph.frag_off |= htons(IP_DF);
+
+ err = ip_tunnel_ioctl(dev, &p, cmd);
+ if (err)
+ return err;
+
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+ return -EFAULT;
+
return 0;
}
static const struct net_device_ops ipip_netdev_ops = {
- .ndo_uninit = ipip_tunnel_uninit,
+ .ndo_init = ipip_tunnel_init,
+ .ndo_uninit = ip_tunnel_uninit,
.ndo_start_xmit = ipip_tunnel_xmit,
.ndo_do_ioctl = ipip_tunnel_ioctl,
- .ndo_change_mtu = ipip_tunnel_change_mtu,
- .ndo_get_stats64 = ipip_get_stats64,
+ .ndo_change_mtu = ip_tunnel_change_mtu,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
-static void ipip_dev_free(struct net_device *dev)
-{
- free_percpu(dev->tstats);
- free_netdev(dev);
-}
-
#define IPIP_FEATURES (NETIF_F_SG | \
NETIF_F_FRAGLIST | \
NETIF_F_HIGHDMA | \
@@ -794,11 +275,8 @@ static void ipip_dev_free(struct net_device *dev)
static void ipip_tunnel_setup(struct net_device *dev)
{
dev->netdev_ops = &ipip_netdev_ops;
- dev->destructor = ipip_dev_free;
dev->type = ARPHRD_TUNNEL;
- dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr);
- dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr);
dev->flags = IFF_NOARP;
dev->iflink = 0;
dev->addr_len = 4;
@@ -808,46 +286,19 @@ static void ipip_tunnel_setup(struct net_device *dev)
dev->features |= IPIP_FEATURES;
dev->hw_features |= IPIP_FEATURES;
+ ip_tunnel_setup(dev, ipip_net_id);
}
static int ipip_tunnel_init(struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- tunnel->dev = dev;
-
memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4);
memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
- ipip_tunnel_bind_dev(dev);
-
- dev->tstats = alloc_percpu(struct pcpu_tstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- return 0;
-}
-
-static int __net_init ipip_fb_tunnel_init(struct net_device *dev)
-{
- struct ip_tunnel *tunnel = netdev_priv(dev);
- struct iphdr *iph = &tunnel->parms.iph;
- struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id);
-
- tunnel->dev = dev;
- strcpy(tunnel->parms.name, dev->name);
-
- iph->version = 4;
- iph->protocol = IPPROTO_IPIP;
- iph->ihl = 5;
-
- dev->tstats = alloc_percpu(struct pcpu_tstats);
- if (!dev->tstats)
- return -ENOMEM;
-
- dev_hold(dev);
- rcu_assign_pointer(ipn->tunnels_wc[0], tunnel);
- return 0;
+ tunnel->hlen = 0;
+ tunnel->parms.iph.protocol = IPPROTO_IPIP;
+ return ip_tunnel_init(dev);
}
static void ipip_netlink_parms(struct nlattr *data[],
@@ -887,28 +338,16 @@ static void ipip_netlink_parms(struct nlattr *data[],
static int ipip_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
- struct net *net = dev_net(dev);
- struct ip_tunnel *nt;
-
- nt = netdev_priv(dev);
- ipip_netlink_parms(data, &nt->parms);
-
- if (ipip_tunnel_locate(net, &nt->parms, 0))
- return -EEXIST;
+ struct ip_tunnel_parm p;
- return ipip_tunnel_create(dev);
+ ipip_netlink_parms(data, &p);
+ return ip_tunnel_newlink(dev, tb, &p);
}
static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
struct nlattr *data[])
{
- struct ip_tunnel *t;
struct ip_tunnel_parm p;
- struct net *net = dev_net(dev);
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
-
- if (dev == ipn->fb_tunnel_dev)
- return -EINVAL;
ipip_netlink_parms(data, &p);
@@ -916,16 +355,7 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[],
(!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr))
return -EINVAL;
- t = ipip_tunnel_locate(net, &p, 0);
-
- if (t) {
- if (t->dev != dev)
- return -EEXIST;
- } else
- t = netdev_priv(dev);
-
- ipip_tunnel_update(t, &p);
- return 0;
+ return ip_tunnel_changelink(dev, tb, &p);
}
static size_t ipip_get_size(const struct net_device *dev)
@@ -982,6 +412,7 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly = {
.setup = ipip_tunnel_setup,
.newlink = ipip_newlink,
.changelink = ipip_changelink,
+ .dellink = ip_tunnel_dellink,
.get_size = ipip_get_size,
.fill_info = ipip_fill_info,
};
@@ -992,90 +423,29 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
.priority = 1,
};
-static const char banner[] __initconst =
- KERN_INFO "IPv4 over IPv4 tunneling driver\n";
-
-static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head)
-{
- int prio;
-
- for (prio = 1; prio < 4; prio++) {
- int h;
- for (h = 0; h < HASH_SIZE; h++) {
- struct ip_tunnel *t;
-
- t = rtnl_dereference(ipn->tunnels[prio][h]);
- while (t != NULL) {
- unregister_netdevice_queue(t->dev, head);
- t = rtnl_dereference(t->next);
- }
- }
- }
-}
-
static int __net_init ipip_init_net(struct net *net)
{
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
- struct ip_tunnel *t;
- int err;
-
- ipn->tunnels[0] = ipn->tunnels_wc;
- ipn->tunnels[1] = ipn->tunnels_l;
- ipn->tunnels[2] = ipn->tunnels_r;
- ipn->tunnels[3] = ipn->tunnels_r_l;
-
- ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel),
- "tunl0",
- ipip_tunnel_setup);
- if (!ipn->fb_tunnel_dev) {
- err = -ENOMEM;
- goto err_alloc_dev;
- }
- dev_net_set(ipn->fb_tunnel_dev, net);
-
- err = ipip_fb_tunnel_init(ipn->fb_tunnel_dev);
- if (err)
- goto err_reg_dev;
-
- if ((err = register_netdev(ipn->fb_tunnel_dev)))
- goto err_reg_dev;
-
- t = netdev_priv(ipn->fb_tunnel_dev);
-
- strcpy(t->parms.name, ipn->fb_tunnel_dev->name);
- return 0;
-
-err_reg_dev:
- ipip_dev_free(ipn->fb_tunnel_dev);
-err_alloc_dev:
- /* nothing */
- return err;
+ return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
}
static void __net_exit ipip_exit_net(struct net *net)
{
- struct ipip_net *ipn = net_generic(net, ipip_net_id);
- LIST_HEAD(list);
-
- rtnl_lock();
- ipip_destroy_tunnels(ipn, &list);
- unregister_netdevice_queue(ipn->fb_tunnel_dev, &list);
- unregister_netdevice_many(&list);
- rtnl_unlock();
+ struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
+ ip_tunnel_delete_net(itn);
}
static struct pernet_operations ipip_net_ops = {
.init = ipip_init_net,
.exit = ipip_exit_net,
.id = &ipip_net_id,
- .size = sizeof(struct ipip_net),
+ .size = sizeof(struct ip_tunnel_net),
};
static int __init ipip_init(void)
{
int err;
- printk(banner);
+ pr_info("ipip: IPv4 over IPv4 tunneling driver\n");
err = register_pernet_device(&ipip_net_ops);
if (err < 0)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 5f95b3aa579e..9d9610ae7855 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -61,7 +61,7 @@
#include <linux/netfilter_ipv4.h>
#include <linux/compat.h>
#include <linux/export.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/checksum.h>
#include <net/netlink.h>
#include <net/fib_rules.h>
@@ -626,9 +626,9 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
if (ip_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
nlh->nlmsg_type = NLMSG_ERROR;
- nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- e = NLMSG_DATA(nlh);
+ e = nlmsg_data(nlh);
e->error = -ETIMEDOUT;
memset(&e->msg, 0, sizeof(e->msg));
@@ -910,14 +910,14 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
if (ip_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
- if (__ipmr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
+ if (__ipmr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
nlh->nlmsg_len = skb_tail_pointer(skb) -
(u8 *)nlh;
} else {
nlh->nlmsg_type = NLMSG_ERROR;
- nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- e = NLMSG_DATA(nlh);
+ e = nlmsg_data(nlh);
e->error = -EMSGSIZE;
memset(&e->msg, 0, sizeof(e->msg));
}
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 4c0cf63dd92e..c3e0adea9c27 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -1,4 +1,9 @@
-/* IPv4 specific functions of netfilter core */
+/*
+ * IPv4 specific functions of netfilter core
+ *
+ * Rusty Russell (C) 2000 -- This code is GPL.
+ * Patrick McHardy (C) 2006-2012
+ */
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
@@ -40,14 +45,14 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
fl4.flowi4_flags = flags;
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
- return -1;
+ return PTR_ERR(rt);
/* Drop old route. */
skb_dst_drop(skb);
skb_dst_set(skb, &rt->dst);
if (skb_dst(skb)->error)
- return -1;
+ return skb_dst(skb)->error;
#ifdef CONFIG_XFRM
if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
@@ -56,7 +61,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
skb_dst_set(skb, NULL);
dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0);
if (IS_ERR(dst))
- return -1;
+ return PTR_ERR(dst);;
skb_dst_set(skb, dst);
}
#endif
@@ -66,7 +71,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
0, GFP_ATOMIC))
- return -1;
+ return -ENOMEM;
return 0;
}
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 0d755c50994b..e7916c193932 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -71,7 +71,7 @@ config IP_NF_MATCH_ECN
config IP_NF_MATCH_RPFILTER
tristate '"rpfilter" reverse path filter match support'
- depends on NETFILTER_ADVANCED
+ depends on NETFILTER_ADVANCED && (IP_NF_MANGLE || IP_NF_RAW)
---help---
This option allows you to match packets whose replies would
go out via the interface the packet came in.
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 7dc6a9743592..85a4f21aac1a 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -6,6 +6,7 @@
* Some ARP specific bits are:
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2006-2009 Patrick McHardy <kaber@trash.net>
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 79ca5e70d497..eadab1ed6500 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -48,9 +48,7 @@ static int __net_init arptable_filter_net_init(struct net *net)
net->ipv4.arptable_filter =
arpt_register_table(net, &packet_filter, repl);
kfree(repl);
- if (IS_ERR(net->ipv4.arptable_filter))
- return PTR_ERR(net->ipv4.arptable_filter);
- return 0;
+ return PTR_RET(net->ipv4.arptable_filter);
}
static void __net_exit arptable_filter_net_exit(struct net *net)
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 3efcf87400c3..d23118d95ff9 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
* Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
+ * Copyright (C) 2006-2010 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -182,8 +183,7 @@ ipt_get_target_c(const struct ipt_entry *e)
return ipt_get_target((struct ipt_entry *)e);
}
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
- defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
static const char *const hooknames[] = {
[NF_INET_PRE_ROUTING] = "PREROUTING",
[NF_INET_LOCAL_IN] = "INPUT",
@@ -259,6 +259,7 @@ static void trace_packet(const struct sk_buff *skb,
const char *hookname, *chainname, *comment;
const struct ipt_entry *iter;
unsigned int rulenum = 0;
+ struct net *net = dev_net(in ? in : out);
table_base = private->entries[smp_processor_id()];
root = get_entry(table_base, private->hook_entry[hook]);
@@ -271,7 +272,7 @@ static void trace_packet(const struct sk_buff *skb,
&chainname, &comment, &rulenum) != 0)
break;
- nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo,
+ nf_log_packet(net, AF_INET, hook, skb, in, out, &trace_loginfo,
"TRACE: %s:%s:%s:%u ",
tablename, chainname, comment, rulenum);
}
@@ -361,8 +362,7 @@ ipt_do_table(struct sk_buff *skb,
t = ipt_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
-#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
- defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
/* The packet is traced: log it */
if (unlikely(skb->nf_trace))
trace_packet(skb, hook, in, out,
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 7d168dcbd135..f8a222cb6448 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -4,6 +4,7 @@
* (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2005-2007 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -37,7 +38,7 @@
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/timer.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netdevice.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
@@ -45,6 +46,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
#include <net/netfilter/nf_log.h>
+#include <net/netns/generic.h>
#include <net/sock.h>
#include <linux/bitops.h>
#include <asm/unaligned.h>
@@ -78,15 +80,23 @@ typedef struct {
struct timer_list timer; /* the timer function */
} ulog_buff_t;
-static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS]; /* array of buffers */
+static int ulog_net_id __read_mostly;
+struct ulog_net {
+ unsigned int nlgroup[ULOG_MAXNLGROUPS];
+ ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];
+ struct sock *nflognl;
+ spinlock_t lock;
+};
-static struct sock *nflognl; /* our socket */
-static DEFINE_SPINLOCK(ulog_lock); /* spinlock */
+static struct ulog_net *ulog_pernet(struct net *net)
+{
+ return net_generic(net, ulog_net_id);
+}
/* send one ulog_buff_t to userspace */
-static void ulog_send(unsigned int nlgroupnum)
+static void ulog_send(struct ulog_net *ulog, unsigned int nlgroupnum)
{
- ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
+ ulog_buff_t *ub = &ulog->ulog_buffers[nlgroupnum];
pr_debug("ulog_send: timer is deleting\n");
del_timer(&ub->timer);
@@ -103,7 +113,8 @@ static void ulog_send(unsigned int nlgroupnum)
NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1;
pr_debug("throwing %d packets to netlink group %u\n",
ub->qlen, nlgroupnum + 1);
- netlink_broadcast(nflognl, ub->skb, 0, nlgroupnum + 1, GFP_ATOMIC);
+ netlink_broadcast(ulog->nflognl, ub->skb, 0, nlgroupnum + 1,
+ GFP_ATOMIC);
ub->qlen = 0;
ub->skb = NULL;
@@ -114,13 +125,16 @@ static void ulog_send(unsigned int nlgroupnum)
/* timer function to flush queue in flushtimeout time */
static void ulog_timer(unsigned long data)
{
+ struct ulog_net *ulog = container_of((void *)data,
+ struct ulog_net,
+ nlgroup[*(unsigned int *)data]);
pr_debug("timer function called, calling ulog_send\n");
/* lock to protect against somebody modifying our structure
* from ipt_ulog_target at the same time */
- spin_lock_bh(&ulog_lock);
- ulog_send(data);
- spin_unlock_bh(&ulog_lock);
+ spin_lock_bh(&ulog->lock);
+ ulog_send(ulog, data);
+ spin_unlock_bh(&ulog->lock);
}
static struct sk_buff *ulog_alloc_skb(unsigned int size)
@@ -160,6 +174,8 @@ static void ipt_ulog_packet(unsigned int hooknum,
size_t size, copy_len;
struct nlmsghdr *nlh;
struct timeval tv;
+ struct net *net = dev_net(in ? in : out);
+ struct ulog_net *ulog = ulog_pernet(net);
/* ffs == find first bit set, necessary because userspace
* is already shifting groupnumber, but we need unshifted.
@@ -172,11 +188,11 @@ static void ipt_ulog_packet(unsigned int hooknum,
else
copy_len = loginfo->copy_range;
- size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+ size = nlmsg_total_size(sizeof(*pm) + copy_len);
- ub = &ulog_buffers[groupnum];
+ ub = &ulog->ulog_buffers[groupnum];
- spin_lock_bh(&ulog_lock);
+ spin_lock_bh(&ulog->lock);
if (!ub->skb) {
if (!(ub->skb = ulog_alloc_skb(size)))
@@ -186,7 +202,7 @@ static void ipt_ulog_packet(unsigned int hooknum,
/* either the queue len is too high or we don't have
* enough room in nlskb left. send it to userspace. */
- ulog_send(groupnum);
+ ulog_send(ulog, groupnum);
if (!(ub->skb = ulog_alloc_skb(size)))
goto alloc_failure;
@@ -260,16 +276,16 @@ static void ipt_ulog_packet(unsigned int hooknum,
if (ub->qlen >= loginfo->qthreshold) {
if (loginfo->qthreshold > 1)
nlh->nlmsg_type = NLMSG_DONE;
- ulog_send(groupnum);
+ ulog_send(ulog, groupnum);
}
out_unlock:
- spin_unlock_bh(&ulog_lock);
+ spin_unlock_bh(&ulog->lock);
return;
alloc_failure:
pr_debug("Error building netlink message\n");
- spin_unlock_bh(&ulog_lock);
+ spin_unlock_bh(&ulog->lock);
}
static unsigned int
@@ -376,54 +392,43 @@ static struct nf_logger ipt_ulog_logger __read_mostly = {
.me = THIS_MODULE,
};
-static int __init ulog_tg_init(void)
+static int __net_init ulog_tg_net_init(struct net *net)
{
- int ret, i;
+ int i;
+ struct ulog_net *ulog = ulog_pernet(net);
struct netlink_kernel_cfg cfg = {
.groups = ULOG_MAXNLGROUPS,
};
- pr_debug("init module\n");
-
- if (nlbufsiz > 128*1024) {
- pr_warning("Netlink buffer has to be <= 128kB\n");
- return -EINVAL;
- }
-
+ spin_lock_init(&ulog->lock);
/* initialize ulog_buffers */
for (i = 0; i < ULOG_MAXNLGROUPS; i++)
- setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
+ setup_timer(&ulog->ulog_buffers[i].timer, ulog_timer, i);
- nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, &cfg);
- if (!nflognl)
+ ulog->nflognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg);
+ if (!ulog->nflognl)
return -ENOMEM;
- ret = xt_register_target(&ulog_tg_reg);
- if (ret < 0) {
- netlink_kernel_release(nflognl);
- return ret;
- }
if (nflog)
- nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger);
+ nf_log_set(net, NFPROTO_IPV4, &ipt_ulog_logger);
return 0;
}
-static void __exit ulog_tg_exit(void)
+static void __net_exit ulog_tg_net_exit(struct net *net)
{
ulog_buff_t *ub;
int i;
-
- pr_debug("cleanup_module\n");
+ struct ulog_net *ulog = ulog_pernet(net);
if (nflog)
- nf_log_unregister(&ipt_ulog_logger);
- xt_unregister_target(&ulog_tg_reg);
- netlink_kernel_release(nflognl);
+ nf_log_unset(net, &ipt_ulog_logger);
+
+ netlink_kernel_release(ulog->nflognl);
/* remove pending timers and free allocated skb's */
for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
- ub = &ulog_buffers[i];
+ ub = &ulog->ulog_buffers[i];
pr_debug("timer is deleting\n");
del_timer(&ub->timer);
@@ -434,5 +439,50 @@ static void __exit ulog_tg_exit(void)
}
}
+static struct pernet_operations ulog_tg_net_ops = {
+ .init = ulog_tg_net_init,
+ .exit = ulog_tg_net_exit,
+ .id = &ulog_net_id,
+ .size = sizeof(struct ulog_net),
+};
+
+static int __init ulog_tg_init(void)
+{
+ int ret;
+ pr_debug("init module\n");
+
+ if (nlbufsiz > 128*1024) {
+ pr_warn("Netlink buffer has to be <= 128kB\n");
+ return -EINVAL;
+ }
+
+ ret = register_pernet_subsys(&ulog_tg_net_ops);
+ if (ret)
+ goto out_pernet;
+
+ ret = xt_register_target(&ulog_tg_reg);
+ if (ret < 0)
+ goto out_target;
+
+ if (nflog)
+ nf_log_register(NFPROTO_IPV4, &ipt_ulog_logger);
+
+ return 0;
+
+out_target:
+ unregister_pernet_subsys(&ulog_tg_net_ops);
+out_pernet:
+ return ret;
+}
+
+static void __exit ulog_tg_exit(void)
+{
+ pr_debug("cleanup_module\n");
+ if (nflog)
+ nf_log_unregister(&ipt_ulog_logger);
+ xt_unregister_target(&ulog_tg_reg);
+ unregister_pernet_subsys(&ulog_tg_net_ops);
+}
+
module_init(ulog_tg_init);
module_exit(ulog_tg_exit);
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
index c30130062cd6..c49dcd0284a0 100644
--- a/net/ipv4/netfilter/ipt_rpfilter.c
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -66,6 +66,12 @@ static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
return dev_match;
}
+static bool rpfilter_is_local(const struct sk_buff *skb)
+{
+ const struct rtable *rt = skb_rtable(skb);
+ return rt && (rt->rt_flags & RTCF_LOCAL);
+}
+
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_rpfilter_info *info;
@@ -76,7 +82,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
info = par->matchinfo;
invert = info->flags & XT_RPFILTER_INVERT;
- if (par->in->flags & IFF_LOOPBACK)
+ if (rpfilter_is_local(skb))
return true ^ invert;
iph = ip_hdr(skb);
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 85d88f206447..cba5658ec82c 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -44,6 +44,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out)
u_int8_t tos;
__be32 saddr, daddr;
u_int32_t mark;
+ int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
@@ -66,9 +67,11 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out)
if (iph->saddr != saddr ||
iph->daddr != daddr ||
skb->mark != mark ||
- iph->tos != tos)
- if (ip_route_me_harder(skb, RTN_UNSPEC))
- ret = NF_DROP;
+ iph->tos != tos) {
+ err = ip_route_me_harder(skb, RTN_UNSPEC);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
}
return ret;
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c
index eeaff7e4acb5..6383273d54e1 100644
--- a/net/ipv4/netfilter/iptable_nat.c
+++ b/net/ipv4/netfilter/iptable_nat.c
@@ -176,6 +176,7 @@ nf_nat_ipv4_out(unsigned int hooknum,
#ifdef CONFIG_XFRM
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
+ int err;
#endif
unsigned int ret;
@@ -195,9 +196,11 @@ nf_nat_ipv4_out(unsigned int hooknum,
ct->tuplehash[!dir].tuple.dst.u3.ip) ||
(ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
ct->tuplehash[dir].tuple.src.u.all !=
- ct->tuplehash[!dir].tuple.dst.u.all))
- if (nf_xfrm_me_harder(skb, AF_INET) < 0)
- ret = NF_DROP;
+ ct->tuplehash[!dir].tuple.dst.u.all)) {
+ err = nf_xfrm_me_harder(skb, AF_INET);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
}
#endif
return ret;
@@ -213,6 +216,7 @@ nf_nat_ipv4_local_fn(unsigned int hooknum,
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned int ret;
+ int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
@@ -226,16 +230,19 @@ nf_nat_ipv4_local_fn(unsigned int hooknum,
if (ct->tuplehash[dir].tuple.dst.u3.ip !=
ct->tuplehash[!dir].tuple.src.u3.ip) {
- if (ip_route_me_harder(skb, RTN_UNSPEC))
- ret = NF_DROP;
+ err = ip_route_me_harder(skb, RTN_UNSPEC);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
}
#ifdef CONFIG_XFRM
else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) &&
ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP &&
ct->tuplehash[dir].tuple.dst.u.all !=
- ct->tuplehash[!dir].tuple.src.u.all)
- if (nf_xfrm_me_harder(skb, AF_INET) < 0)
- ret = NF_DROP;
+ ct->tuplehash[!dir].tuple.src.u.all) {
+ err = nf_xfrm_me_harder(skb, AF_INET);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
#endif
}
return ret;
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 2820aa18b542..567d84168bd2 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -1,6 +1,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index f2ca12794081..4c48e434bb1f 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -2,6 +2,7 @@
*
* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2006-2010 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 5241d997ab75..a338dad41b7d 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -1,5 +1,6 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2006-2010 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -187,8 +188,8 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
if (icmph == NULL) {
if (LOG_INVALID(net, IPPROTO_ICMP))
- nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
- "nf_ct_icmp: short packet ");
+ nf_log_packet(net, PF_INET, 0, skb, NULL, NULL,
+ NULL, "nf_ct_icmp: short packet ");
return -NF_ACCEPT;
}
@@ -196,7 +197,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
nf_ip_checksum(skb, hooknum, dataoff, 0)) {
if (LOG_INVALID(net, IPPROTO_ICMP))
- nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
"nf_ct_icmp: bad HW ICMP checksum ");
return -NF_ACCEPT;
}
@@ -209,7 +210,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
*/
if (icmph->type > NR_ICMP_TYPES) {
if (LOG_INVALID(net, IPPROTO_ICMP))
- nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
"nf_ct_icmp: invalid ICMP type ");
return -NF_ACCEPT;
}
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 9c3db10b22d3..9eea059dd621 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -2,6 +2,7 @@
* H.323 extension for NAT alteration.
*
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ * Copyright (c) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* This source code is licensed under General Public License version 2.
*
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index a06d7d74817d..657d2307f031 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -13,6 +13,8 @@
*
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
+ *
* TODO: - NAT to a unique tuple, not to TCP source port
* (needs netfilter tuple reservation)
*/
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index ea44f02563b5..690d890111bb 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -21,6 +21,8 @@
*
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
+ *
*/
#include <linux/module.h>
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index bac712293fd6..5f011cc89cd9 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -38,6 +38,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: James Morris <jmorris@intercode.com.au>
+ *
+ * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 2e91006d6076..7d93d62cd5fd 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -514,9 +514,8 @@ static int ping_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
ipc.opt = NULL;
ipc.oif = sk->sk_bound_dev_if;
ipc.tx_flags = 0;
- err = sock_tx_timestamp(sk, &ipc.tx_flags);
- if (err)
- return err;
+
+ sock_tx_timestamp(sk, &ipc.tx_flags);
if (msg->msg_controllen) {
err = ip_cmsg_send(sock_net(sk), msg, &ipc);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 32030a24e776..2a5bf86d2415 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -125,6 +125,7 @@ static const struct snmp_mib snmp4_ipextstats_list[] = {
SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS),
SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
+ SNMP_MIB_ITEM("InCsumErrors", IPSTATS_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -162,6 +163,7 @@ static const struct snmp_mib snmp4_tcp_list[] = {
SNMP_MIB_ITEM("RetransSegs", TCP_MIB_RETRANSSEGS),
SNMP_MIB_ITEM("InErrs", TCP_MIB_INERRS),
SNMP_MIB_ITEM("OutRsts", TCP_MIB_OUTRSTS),
+ SNMP_MIB_ITEM("InCsumErrors", TCP_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -172,6 +174,7 @@ static const struct snmp_mib snmp4_udp_list[] = {
SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS),
SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS),
SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS),
+ SNMP_MIB_ITEM("InCsumErrors", UDP_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -224,6 +227,8 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPForwardRetrans", LINUX_MIB_TCPFORWARDRETRANS),
SNMP_MIB_ITEM("TCPSlowStartRetrans", LINUX_MIB_TCPSLOWSTARTRETRANS),
SNMP_MIB_ITEM("TCPTimeouts", LINUX_MIB_TCPTIMEOUTS),
+ SNMP_MIB_ITEM("TCPLossProbes", LINUX_MIB_TCPLOSSPROBES),
+ SNMP_MIB_ITEM("TCPLossProbeRecovery", LINUX_MIB_TCPLOSSPROBERECOVERY),
SNMP_MIB_ITEM("TCPRenoRecoveryFail", LINUX_MIB_TCPRENORECOVERYFAIL),
SNMP_MIB_ITEM("TCPSackRecoveryFail", LINUX_MIB_TCPSACKRECOVERYFAIL),
SNMP_MIB_ITEM("TCPSchedulerFailed", LINUX_MIB_TCPSCHEDULERFAILED),
@@ -267,6 +272,7 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPFastOpenPassiveFail", LINUX_MIB_TCPFASTOPENPASSIVEFAIL),
SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW),
SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD),
+ SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES),
SNMP_MIB_SENTINEL
};
@@ -319,15 +325,16 @@ static void icmp_put(struct seq_file *seq)
struct net *net = seq->private;
atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs;
- seq_puts(seq, "\nIcmp: InMsgs InErrors");
+ seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors");
for (i=0; icmpmibmap[i].name != NULL; i++)
seq_printf(seq, " In%s", icmpmibmap[i].name);
seq_printf(seq, " OutMsgs OutErrors");
for (i=0; icmpmibmap[i].name != NULL; i++)
seq_printf(seq, " Out%s", icmpmibmap[i].name);
- seq_printf(seq, "\nIcmp: %lu %lu",
+ seq_printf(seq, "\nIcmp: %lu %lu %lu",
snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INMSGS),
- snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
+ snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS),
+ snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS));
for (i=0; icmpmibmap[i].name != NULL; i++)
seq_printf(seq, " %lu",
atomic_long_read(ptr + icmpmibmap[i].index));
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 6e2851464f8f..550781a17b34 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2311,7 +2311,7 @@ nla_put_failure:
return -EMSGSIZE;
}
-static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(in_skb->sk);
struct rtmsg *rtm;
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index ef54377fb11c..b05c96e7af8b 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -267,7 +267,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt)
{
struct tcp_options_received tcp_opt;
- const u8 *hash_location;
struct inet_request_sock *ireq;
struct tcp_request_sock *treq;
struct tcp_sock *tp = tcp_sk(sk);
@@ -294,7 +293,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
+ tcp_parse_options(skb, &tcp_opt, 0, NULL);
if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
goto out;
@@ -349,8 +348,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* hasn't changed since we received the original syn, but I see
* no easy way to do this.
*/
- flowi4_init_output(&fl4, 0, sk->sk_mark, RT_CONN_FLAGS(sk),
- RT_SCOPE_UNIVERSE, IPPROTO_TCP,
+ flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark,
+ RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP,
inet_sk_flowi_flags(sk),
(opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
ireq->loc_addr, th->source, th->dest);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 960fd29d9b8e..fa2f63fc453b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -28,7 +28,7 @@
static int zero;
static int one = 1;
-static int two = 2;
+static int four = 4;
static int tcp_retr1_max = 255;
static int ip_local_port_range_min[] = { 1, 1 };
static int ip_local_port_range_max[] = { 65535, 65535 };
@@ -592,13 +592,6 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec
},
{
- .procname = "tcp_frto_response",
- .data = &sysctl_tcp_frto_response,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
.procname = "tcp_low_latency",
.data = &sysctl_tcp_low_latency,
.maxlen = sizeof(int),
@@ -733,13 +726,6 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec,
},
{
- .procname = "tcp_cookie_size",
- .data = &sysctl_tcp_cookie_size,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
.procname = "tcp_thin_linear_timeouts",
.data = &sysctl_tcp_thin_linear_timeouts,
.maxlen = sizeof(int),
@@ -760,7 +746,7 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
- .extra2 = &two,
+ .extra2 = &four,
},
{
.procname = "udp_mem",
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index e22020790709..dcb116dde216 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -409,15 +409,6 @@ void tcp_init_sock(struct sock *sk)
icsk->icsk_sync_mss = tcp_sync_mss;
- /* TCP Cookie Transactions */
- if (sysctl_tcp_cookie_size > 0) {
- /* Default, cookies without s_data_payload. */
- tp->cookie_values =
- kzalloc(sizeof(*tp->cookie_values),
- sk->sk_allocation);
- if (tp->cookie_values != NULL)
- kref_init(&tp->cookie_values->kref);
- }
/* Presumed zeroed, in order of appearance:
* cookie_in_always, cookie_out_never,
* s_data_constant, s_data_in, s_data_out
@@ -2397,92 +2388,6 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
release_sock(sk);
return err;
}
- case TCP_COOKIE_TRANSACTIONS: {
- struct tcp_cookie_transactions ctd;
- struct tcp_cookie_values *cvp = NULL;
-
- if (sizeof(ctd) > optlen)
- return -EINVAL;
- if (copy_from_user(&ctd, optval, sizeof(ctd)))
- return -EFAULT;
-
- if (ctd.tcpct_used > sizeof(ctd.tcpct_value) ||
- ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
- return -EINVAL;
-
- if (ctd.tcpct_cookie_desired == 0) {
- /* default to global value */
- } else if ((0x1 & ctd.tcpct_cookie_desired) ||
- ctd.tcpct_cookie_desired > TCP_COOKIE_MAX ||
- ctd.tcpct_cookie_desired < TCP_COOKIE_MIN) {
- return -EINVAL;
- }
-
- if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
- /* Supercedes all other values */
- lock_sock(sk);
- if (tp->cookie_values != NULL) {
- kref_put(&tp->cookie_values->kref,
- tcp_cookie_values_release);
- tp->cookie_values = NULL;
- }
- tp->rx_opt.cookie_in_always = 0; /* false */
- tp->rx_opt.cookie_out_never = 1; /* true */
- release_sock(sk);
- return err;
- }
-
- /* Allocate ancillary memory before locking.
- */
- if (ctd.tcpct_used > 0 ||
- (tp->cookie_values == NULL &&
- (sysctl_tcp_cookie_size > 0 ||
- ctd.tcpct_cookie_desired > 0 ||
- ctd.tcpct_s_data_desired > 0))) {
- cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
- GFP_KERNEL);
- if (cvp == NULL)
- return -ENOMEM;
-
- kref_init(&cvp->kref);
- }
- lock_sock(sk);
- tp->rx_opt.cookie_in_always =
- (TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
- tp->rx_opt.cookie_out_never = 0; /* false */
-
- if (tp->cookie_values != NULL) {
- if (cvp != NULL) {
- /* Changed values are recorded by a changed
- * pointer, ensuring the cookie will differ,
- * without separately hashing each value later.
- */
- kref_put(&tp->cookie_values->kref,
- tcp_cookie_values_release);
- } else {
- cvp = tp->cookie_values;
- }
- }
-
- if (cvp != NULL) {
- cvp->cookie_desired = ctd.tcpct_cookie_desired;
-
- if (ctd.tcpct_used > 0) {
- memcpy(cvp->s_data_payload, ctd.tcpct_value,
- ctd.tcpct_used);
- cvp->s_data_desired = ctd.tcpct_used;
- cvp->s_data_constant = 1; /* true */
- } else {
- /* No constant payload data. */
- cvp->s_data_desired = ctd.tcpct_s_data_desired;
- cvp->s_data_constant = 0; /* false */
- }
-
- tp->cookie_values = cvp;
- }
- release_sock(sk);
- return err;
- }
default:
/* fallthru */
break;
@@ -2902,41 +2807,6 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return -EFAULT;
return 0;
- case TCP_COOKIE_TRANSACTIONS: {
- struct tcp_cookie_transactions ctd;
- struct tcp_cookie_values *cvp = tp->cookie_values;
-
- if (get_user(len, optlen))
- return -EFAULT;
- if (len < sizeof(ctd))
- return -EINVAL;
-
- memset(&ctd, 0, sizeof(ctd));
- ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ?
- TCP_COOKIE_IN_ALWAYS : 0)
- | (tp->rx_opt.cookie_out_never ?
- TCP_COOKIE_OUT_NEVER : 0);
-
- if (cvp != NULL) {
- ctd.tcpct_flags |= (cvp->s_data_in ?
- TCP_S_DATA_IN : 0)
- | (cvp->s_data_out ?
- TCP_S_DATA_OUT : 0);
-
- ctd.tcpct_cookie_desired = cvp->cookie_desired;
- ctd.tcpct_s_data_desired = cvp->s_data_desired;
-
- memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
- cvp->cookie_pair_size);
- ctd.tcpct_used = cvp->cookie_pair_size;
- }
-
- if (put_user(sizeof(ctd), optlen))
- return -EFAULT;
- if (copy_to_user(optval, &ctd, sizeof(ctd)))
- return -EFAULT;
- return 0;
- }
case TCP_THIN_LINEAR_TIMEOUTS:
val = tp->thin_lto;
break;
@@ -3015,6 +2885,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
__be32 delta;
unsigned int oldlen;
unsigned int mss;
+ struct sk_buff *gso_skb = skb;
+ __sum16 newcheck;
if (!pskb_may_pull(skb, sizeof(*th)))
goto out;
@@ -3044,6 +2916,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
SKB_GSO_TCP_ECN |
SKB_GSO_TCPV6 |
SKB_GSO_GRE |
+ SKB_GSO_UDP_TUNNEL |
0) ||
!(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
goto out;
@@ -3064,11 +2937,13 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
th = tcp_hdr(skb);
seq = ntohl(th->seq);
+ newcheck = ~csum_fold((__force __wsum)((__force u32)th->check +
+ (__force u32)delta));
+
do {
th->fin = th->psh = 0;
+ th->check = newcheck;
- th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
- (__force u32)delta));
if (skb->ip_summed != CHECKSUM_PARTIAL)
th->check =
csum_fold(csum_partial(skb_transport_header(skb),
@@ -3082,6 +2957,17 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
th->cwr = 0;
} while (skb->next);
+ /* Following permits TCP Small Queues to work well with GSO :
+ * The callback to TCP stack will be called at the time last frag
+ * is freed at TX completion, and not right now when gso_skb
+ * is freed by GSO engine
+ */
+ if (gso_skb->destructor == tcp_wfree) {
+ swap(gso_skb->sk, skb->sk);
+ swap(gso_skb->destructor, skb->destructor);
+ swap(gso_skb->truesize, skb->truesize);
+ }
+
delta = htonl(oldlen + (skb->tail - skb->transport_header) +
skb->data_len);
th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
@@ -3408,134 +3294,6 @@ EXPORT_SYMBOL(tcp_md5_hash_key);
#endif
-/* Each Responder maintains up to two secret values concurrently for
- * efficient secret rollover. Each secret value has 4 states:
- *
- * Generating. (tcp_secret_generating != tcp_secret_primary)
- * Generates new Responder-Cookies, but not yet used for primary
- * verification. This is a short-term state, typically lasting only
- * one round trip time (RTT).
- *
- * Primary. (tcp_secret_generating == tcp_secret_primary)
- * Used both for generation and primary verification.
- *
- * Retiring. (tcp_secret_retiring != tcp_secret_secondary)
- * Used for verification, until the first failure that can be
- * verified by the newer Generating secret. At that time, this
- * cookie's state is changed to Secondary, and the Generating
- * cookie's state is changed to Primary. This is a short-term state,
- * typically lasting only one round trip time (RTT).
- *
- * Secondary. (tcp_secret_retiring == tcp_secret_secondary)
- * Used for secondary verification, after primary verification
- * failures. This state lasts no more than twice the Maximum Segment
- * Lifetime (2MSL). Then, the secret is discarded.
- */
-struct tcp_cookie_secret {
- /* The secret is divided into two parts. The digest part is the
- * equivalent of previously hashing a secret and saving the state,
- * and serves as an initialization vector (IV). The message part
- * serves as the trailing secret.
- */
- u32 secrets[COOKIE_WORKSPACE_WORDS];
- unsigned long expires;
-};
-
-#define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL)
-#define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2)
-#define TCP_SECRET_LIFE (HZ * 600)
-
-static struct tcp_cookie_secret tcp_secret_one;
-static struct tcp_cookie_secret tcp_secret_two;
-
-/* Essentially a circular list, without dynamic allocation. */
-static struct tcp_cookie_secret *tcp_secret_generating;
-static struct tcp_cookie_secret *tcp_secret_primary;
-static struct tcp_cookie_secret *tcp_secret_retiring;
-static struct tcp_cookie_secret *tcp_secret_secondary;
-
-static DEFINE_SPINLOCK(tcp_secret_locker);
-
-/* Select a pseudo-random word in the cookie workspace.
- */
-static inline u32 tcp_cookie_work(const u32 *ws, const int n)
-{
- return ws[COOKIE_DIGEST_WORDS + ((COOKIE_MESSAGE_WORDS-1) & ws[n])];
-}
-
-/* Fill bakery[COOKIE_WORKSPACE_WORDS] with generator, updating as needed.
- * Called in softirq context.
- * Returns: 0 for success.
- */
-int tcp_cookie_generator(u32 *bakery)
-{
- unsigned long jiffy = jiffies;
-
- if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
- spin_lock_bh(&tcp_secret_locker);
- if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
- /* refreshed by another */
- memcpy(bakery,
- &tcp_secret_generating->secrets[0],
- COOKIE_WORKSPACE_WORDS);
- } else {
- /* still needs refreshing */
- get_random_bytes(bakery, COOKIE_WORKSPACE_WORDS);
-
- /* The first time, paranoia assumes that the
- * randomization function isn't as strong. But,
- * this secret initialization is delayed until
- * the last possible moment (packet arrival).
- * Although that time is observable, it is
- * unpredictably variable. Mash in the most
- * volatile clock bits available, and expire the
- * secret extra quickly.
- */
- if (unlikely(tcp_secret_primary->expires ==
- tcp_secret_secondary->expires)) {
- struct timespec tv;
-
- getnstimeofday(&tv);
- bakery[COOKIE_DIGEST_WORDS+0] ^=
- (u32)tv.tv_nsec;
-
- tcp_secret_secondary->expires = jiffy
- + TCP_SECRET_1MSL
- + (0x0f & tcp_cookie_work(bakery, 0));
- } else {
- tcp_secret_secondary->expires = jiffy
- + TCP_SECRET_LIFE
- + (0xff & tcp_cookie_work(bakery, 1));
- tcp_secret_primary->expires = jiffy
- + TCP_SECRET_2MSL
- + (0x1f & tcp_cookie_work(bakery, 2));
- }
- memcpy(&tcp_secret_secondary->secrets[0],
- bakery, COOKIE_WORKSPACE_WORDS);
-
- rcu_assign_pointer(tcp_secret_generating,
- tcp_secret_secondary);
- rcu_assign_pointer(tcp_secret_retiring,
- tcp_secret_primary);
- /*
- * Neither call_rcu() nor synchronize_rcu() needed.
- * Retiring data is not freed. It is replaced after
- * further (locked) pointer updates, and a quiet time
- * (minimum 1MSL, maximum LIFE - 2MSL).
- */
- }
- spin_unlock_bh(&tcp_secret_locker);
- } else {
- rcu_read_lock_bh();
- memcpy(bakery,
- &rcu_dereference(tcp_secret_generating)->secrets[0],
- COOKIE_WORKSPACE_WORDS);
- rcu_read_unlock_bh();
- }
- return 0;
-}
-EXPORT_SYMBOL(tcp_cookie_generator);
-
void tcp_done(struct sock *sk)
{
struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
@@ -3590,7 +3348,6 @@ void __init tcp_init(void)
unsigned long limit;
int max_rshare, max_wshare, cnt;
unsigned int i;
- unsigned long jiffy = jiffies;
BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
@@ -3666,13 +3423,5 @@ void __init tcp_init(void)
tcp_register_congestion_control(&tcp_reno);
- memset(&tcp_secret_one.secrets[0], 0, sizeof(tcp_secret_one.secrets));
- memset(&tcp_secret_two.secrets[0], 0, sizeof(tcp_secret_two.secrets));
- tcp_secret_one.expires = jiffy; /* past due */
- tcp_secret_two.expires = jiffy; /* past due */
- tcp_secret_generating = &tcp_secret_one;
- tcp_secret_primary = &tcp_secret_one;
- tcp_secret_retiring = &tcp_secret_two;
- tcp_secret_secondary = &tcp_secret_two;
tcp_tasklet_init();
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3bd55bad230a..08bbe6096528 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -93,12 +93,11 @@ int sysctl_tcp_stdurg __read_mostly;
int sysctl_tcp_rfc1337 __read_mostly;
int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
int sysctl_tcp_frto __read_mostly = 2;
-int sysctl_tcp_frto_response __read_mostly;
int sysctl_tcp_thin_dupack __read_mostly;
int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
-int sysctl_tcp_early_retrans __read_mostly = 2;
+int sysctl_tcp_early_retrans __read_mostly = 3;
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
@@ -108,17 +107,16 @@ int sysctl_tcp_early_retrans __read_mostly = 2;
#define FLAG_DATA_SACKED 0x20 /* New SACK. */
#define FLAG_ECE 0x40 /* ECE in this ACK */
#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/
-#define FLAG_ONLY_ORIG_SACKED 0x200 /* SACKs only non-rexmit sent before RTO */
+#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */
#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */
#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */
-#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */
#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */
+#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */
#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE)
#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED)
-#define FLAG_ANY_PROGRESS (FLAG_FORWARD_PROGRESS|FLAG_SND_UNA_ADVANCED)
#define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH)
#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH))
@@ -1159,10 +1157,8 @@ static u8 tcp_sacktag_one(struct sock *sk,
tcp_highest_sack_seq(tp)))
state->reord = min(fack_count,
state->reord);
-
- /* SACK enhanced F-RTO (RFC4138; Appendix B) */
- if (!after(end_seq, tp->frto_highmark))
- state->flag |= FLAG_ONLY_ORIG_SACKED;
+ if (!after(end_seq, tp->high_seq))
+ state->flag |= FLAG_ORIG_SACK_ACKED;
}
if (sacked & TCPCB_LOST) {
@@ -1555,7 +1551,6 @@ static int
tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
u32 prior_snd_una)
{
- const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
const unsigned char *ptr = (skb_transport_header(ack_skb) +
TCP_SKB_CB(ack_skb)->sacked);
@@ -1728,12 +1723,6 @@ walk:
start_seq, end_seq, dup_sack);
advance_sp:
- /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct
- * due to in-order walk
- */
- if (after(end_seq, tp->frto_highmark))
- state.flag &= ~FLAG_ONLY_ORIG_SACKED;
-
i++;
}
@@ -1750,8 +1739,7 @@ advance_sp:
tcp_verify_left_out(tp);
if ((state.reord < tp->fackets_out) &&
- ((icsk->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker) &&
- (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark)))
+ ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker))
tcp_update_reordering(sk, tp->fackets_out - state.reord, 0);
out:
@@ -1825,197 +1813,6 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp)
tp->sacked_out = 0;
}
-static int tcp_is_sackfrto(const struct tcp_sock *tp)
-{
- return (sysctl_tcp_frto == 0x2) && !tcp_is_reno(tp);
-}
-
-/* F-RTO can only be used if TCP has never retransmitted anything other than
- * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here)
- */
-bool tcp_use_frto(struct sock *sk)
-{
- const struct tcp_sock *tp = tcp_sk(sk);
- const struct inet_connection_sock *icsk = inet_csk(sk);
- struct sk_buff *skb;
-
- if (!sysctl_tcp_frto)
- return false;
-
- /* MTU probe and F-RTO won't really play nicely along currently */
- if (icsk->icsk_mtup.probe_size)
- return false;
-
- if (tcp_is_sackfrto(tp))
- return true;
-
- /* Avoid expensive walking of rexmit queue if possible */
- if (tp->retrans_out > 1)
- return false;
-
- skb = tcp_write_queue_head(sk);
- if (tcp_skb_is_last(sk, skb))
- return true;
- skb = tcp_write_queue_next(sk, skb); /* Skips head */
- tcp_for_write_queue_from(skb, sk) {
- if (skb == tcp_send_head(sk))
- break;
- if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
- return false;
- /* Short-circuit when first non-SACKed skb has been checked */
- if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
- break;
- }
- return true;
-}
-
-/* RTO occurred, but do not yet enter Loss state. Instead, defer RTO
- * recovery a bit and use heuristics in tcp_process_frto() to detect if
- * the RTO was spurious. Only clear SACKED_RETRANS of the head here to
- * keep retrans_out counting accurate (with SACK F-RTO, other than head
- * may still have that bit set); TCPCB_LOST and remaining SACKED_RETRANS
- * bits are handled if the Loss state is really to be entered (in
- * tcp_enter_frto_loss).
- *
- * Do like tcp_enter_loss() would; when RTO expires the second time it
- * does:
- * "Reduce ssthresh if it has not yet been made inside this window."
- */
-void tcp_enter_frto(struct sock *sk)
-{
- const struct inet_connection_sock *icsk = inet_csk(sk);
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
-
- if ((!tp->frto_counter && icsk->icsk_ca_state <= TCP_CA_Disorder) ||
- tp->snd_una == tp->high_seq ||
- ((icsk->icsk_ca_state == TCP_CA_Loss || tp->frto_counter) &&
- !icsk->icsk_retransmits)) {
- tp->prior_ssthresh = tcp_current_ssthresh(sk);
- /* Our state is too optimistic in ssthresh() call because cwnd
- * is not reduced until tcp_enter_frto_loss() when previous F-RTO
- * recovery has not yet completed. Pattern would be this: RTO,
- * Cumulative ACK, RTO (2xRTO for the same segment does not end
- * up here twice).
- * RFC4138 should be more specific on what to do, even though
- * RTO is quite unlikely to occur after the first Cumulative ACK
- * due to back-off and complexity of triggering events ...
- */
- if (tp->frto_counter) {
- u32 stored_cwnd;
- stored_cwnd = tp->snd_cwnd;
- tp->snd_cwnd = 2;
- tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
- tp->snd_cwnd = stored_cwnd;
- } else {
- tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
- }
- /* ... in theory, cong.control module could do "any tricks" in
- * ssthresh(), which means that ca_state, lost bits and lost_out
- * counter would have to be faked before the call occurs. We
- * consider that too expensive, unlikely and hacky, so modules
- * using these in ssthresh() must deal these incompatibility
- * issues if they receives CA_EVENT_FRTO and frto_counter != 0
- */
- tcp_ca_event(sk, CA_EVENT_FRTO);
- }
-
- tp->undo_marker = tp->snd_una;
- tp->undo_retrans = 0;
-
- skb = tcp_write_queue_head(sk);
- if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
- tp->undo_marker = 0;
- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) {
- TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
- tp->retrans_out -= tcp_skb_pcount(skb);
- }
- tcp_verify_left_out(tp);
-
- /* Too bad if TCP was application limited */
- tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp) + 1);
-
- /* Earlier loss recovery underway (see RFC4138; Appendix B).
- * The last condition is necessary at least in tp->frto_counter case.
- */
- if (tcp_is_sackfrto(tp) && (tp->frto_counter ||
- ((1 << icsk->icsk_ca_state) & (TCPF_CA_Recovery|TCPF_CA_Loss))) &&
- after(tp->high_seq, tp->snd_una)) {
- tp->frto_highmark = tp->high_seq;
- } else {
- tp->frto_highmark = tp->snd_nxt;
- }
- tcp_set_ca_state(sk, TCP_CA_Disorder);
- tp->high_seq = tp->snd_nxt;
- tp->frto_counter = 1;
-}
-
-/* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
- * which indicates that we should follow the traditional RTO recovery,
- * i.e. mark everything lost and do go-back-N retransmission.
- */
-static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
-{
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
-
- tp->lost_out = 0;
- tp->retrans_out = 0;
- if (tcp_is_reno(tp))
- tcp_reset_reno_sack(tp);
-
- tcp_for_write_queue(skb, sk) {
- if (skb == tcp_send_head(sk))
- break;
-
- TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
- /*
- * Count the retransmission made on RTO correctly (only when
- * waiting for the first ACK and did not get it)...
- */
- if ((tp->frto_counter == 1) && !(flag & FLAG_DATA_ACKED)) {
- /* For some reason this R-bit might get cleared? */
- if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
- tp->retrans_out += tcp_skb_pcount(skb);
- /* ...enter this if branch just for the first segment */
- flag |= FLAG_DATA_ACKED;
- } else {
- if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
- tp->undo_marker = 0;
- TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
- }
-
- /* Marking forward transmissions that were made after RTO lost
- * can cause unnecessary retransmissions in some scenarios,
- * SACK blocks will mitigate that in some but not in all cases.
- * We used to not mark them but it was causing break-ups with
- * receivers that do only in-order receival.
- *
- * TODO: we could detect presence of such receiver and select
- * different behavior per flow.
- */
- if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) {
- TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
- tp->lost_out += tcp_skb_pcount(skb);
- tp->retransmit_high = TCP_SKB_CB(skb)->end_seq;
- }
- }
- tcp_verify_left_out(tp);
-
- tp->snd_cwnd = tcp_packets_in_flight(tp) + allowed_segments;
- tp->snd_cwnd_cnt = 0;
- tp->snd_cwnd_stamp = tcp_time_stamp;
- tp->frto_counter = 0;
-
- tp->reordering = min_t(unsigned int, tp->reordering,
- sysctl_tcp_reordering);
- tcp_set_ca_state(sk, TCP_CA_Loss);
- tp->high_seq = tp->snd_nxt;
- TCP_ECN_queue_cwr(tp);
-
- tcp_clear_all_retrans_hints(tp);
-}
-
static void tcp_clear_retrans_partial(struct tcp_sock *tp)
{
tp->retrans_out = 0;
@@ -2042,10 +1839,13 @@ void tcp_enter_loss(struct sock *sk, int how)
const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
+ bool new_recovery = false;
/* Reduce ssthresh if it has not yet been made inside this window. */
- if (icsk->icsk_ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
+ if (icsk->icsk_ca_state <= TCP_CA_Disorder ||
+ !after(tp->high_seq, tp->snd_una) ||
(icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
+ new_recovery = true;
tp->prior_ssthresh = tcp_current_ssthresh(sk);
tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
tcp_ca_event(sk, CA_EVENT_LOSS);
@@ -2087,8 +1887,14 @@ void tcp_enter_loss(struct sock *sk, int how)
tcp_set_ca_state(sk, TCP_CA_Loss);
tp->high_seq = tp->snd_nxt;
TCP_ECN_queue_cwr(tp);
- /* Abort F-RTO algorithm if one is in progress */
- tp->frto_counter = 0;
+
+ /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous
+ * loss recovery is underway except recurring timeout(s) on
+ * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing
+ */
+ tp->frto = sysctl_tcp_frto &&
+ (new_recovery || icsk->icsk_retransmits) &&
+ !inet_csk(sk)->icsk_mtup.probe_size;
}
/* If ACK arrived pointing to a remembered SACK, it means that our
@@ -2147,15 +1953,16 @@ static bool tcp_pause_early_retransmit(struct sock *sk, int flag)
* max(RTT/4, 2msec) unless ack has ECE mark, no RTT samples
* available, or RTO is scheduled to fire first.
*/
- if (sysctl_tcp_early_retrans < 2 || (flag & FLAG_ECE) || !tp->srtt)
+ if (sysctl_tcp_early_retrans < 2 || sysctl_tcp_early_retrans > 3 ||
+ (flag & FLAG_ECE) || !tp->srtt)
return false;
delay = max_t(unsigned long, (tp->srtt >> 5), msecs_to_jiffies(2));
if (!time_after(inet_csk(sk)->icsk_timeout, (jiffies + delay)))
return false;
- inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, delay, TCP_RTO_MAX);
- tp->early_retrans_delayed = 1;
+ inet_csk_reset_xmit_timer(sk, ICSK_TIME_EARLY_RETRANS, delay,
+ TCP_RTO_MAX);
return true;
}
@@ -2271,10 +2078,6 @@ static bool tcp_time_to_recover(struct sock *sk, int flag)
struct tcp_sock *tp = tcp_sk(sk);
__u32 packets_out;
- /* Do not perform any recovery during F-RTO algorithm */
- if (tp->frto_counter)
- return false;
-
/* Trick#1: The loss is proven. */
if (tp->lost_out)
return true;
@@ -2318,7 +2121,7 @@ static bool tcp_time_to_recover(struct sock *sk, int flag)
* interval if appropriate.
*/
if (tp->do_early_retrans && !tp->retrans_out && tp->sacked_out &&
- (tp->packets_out == (tp->sacked_out + 1) && tp->packets_out < 4) &&
+ (tp->packets_out >= (tp->sacked_out + 1) && tp->packets_out < 4) &&
!tcp_may_send_now(sk))
return !tcp_pause_early_retransmit(sk, flag);
@@ -2635,12 +2438,12 @@ static int tcp_try_undo_partial(struct sock *sk, int acked)
return failed;
}
-/* Undo during loss recovery after partial ACK. */
-static bool tcp_try_undo_loss(struct sock *sk)
+/* Undo during loss recovery after partial ACK or using F-RTO. */
+static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo)
{
struct tcp_sock *tp = tcp_sk(sk);
- if (tcp_may_undo(tp)) {
+ if (frto_undo || tcp_may_undo(tp)) {
struct sk_buff *skb;
tcp_for_write_queue(skb, sk) {
if (skb == tcp_send_head(sk))
@@ -2654,9 +2457,12 @@ static bool tcp_try_undo_loss(struct sock *sk)
tp->lost_out = 0;
tcp_undo_cwr(sk, true);
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSSUNDO);
+ if (frto_undo)
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPSPURIOUSRTOS);
inet_csk(sk)->icsk_retransmits = 0;
tp->undo_marker = 0;
- if (tcp_is_sack(tp))
+ if (frto_undo || tcp_is_sack(tp))
tcp_set_ca_state(sk, TCP_CA_Open);
return true;
}
@@ -2678,6 +2484,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk, const bool set_ssthresh)
struct tcp_sock *tp = tcp_sk(sk);
tp->high_seq = tp->snd_nxt;
+ tp->tlp_high_seq = 0;
tp->snd_cwnd_cnt = 0;
tp->prior_cwnd = tp->snd_cwnd;
tp->prr_delivered = 0;
@@ -2755,7 +2562,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, int newly_acked_sacked)
tcp_verify_left_out(tp);
- if (!tp->frto_counter && !tcp_any_retrans_done(sk))
+ if (!tcp_any_retrans_done(sk))
tp->retrans_stamp = 0;
if (flag & FLAG_ECE)
@@ -2872,6 +2679,58 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
tcp_set_ca_state(sk, TCP_CA_Recovery);
}
+/* Process an ACK in CA_Loss state. Move to CA_Open if lost data are
+ * recovered or spurious. Otherwise retransmits more on partial ACKs.
+ */
+static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ bool recovered = !before(tp->snd_una, tp->high_seq);
+
+ if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
+ if (flag & FLAG_ORIG_SACK_ACKED) {
+ /* Step 3.b. A timeout is spurious if not all data are
+ * lost, i.e., never-retransmitted data are (s)acked.
+ */
+ tcp_try_undo_loss(sk, true);
+ return;
+ }
+ if (after(tp->snd_nxt, tp->high_seq) &&
+ (flag & FLAG_DATA_SACKED || is_dupack)) {
+ tp->frto = 0; /* Loss was real: 2nd part of step 3.a */
+ } else if (flag & FLAG_SND_UNA_ADVANCED && !recovered) {
+ tp->high_seq = tp->snd_nxt;
+ __tcp_push_pending_frames(sk, tcp_current_mss(sk),
+ TCP_NAGLE_OFF);
+ if (after(tp->snd_nxt, tp->high_seq))
+ return; /* Step 2.b */
+ tp->frto = 0;
+ }
+ }
+
+ if (recovered) {
+ /* F-RTO RFC5682 sec 3.1 step 2.a and 1st part of step 3.a */
+ icsk->icsk_retransmits = 0;
+ tcp_try_undo_recovery(sk);
+ return;
+ }
+ if (flag & FLAG_DATA_ACKED)
+ icsk->icsk_retransmits = 0;
+ if (tcp_is_reno(tp)) {
+ /* A Reno DUPACK means new data in F-RTO step 2.b above are
+ * delivered. Lower inflight to clock out (re)tranmissions.
+ */
+ if (after(tp->snd_nxt, tp->high_seq) && is_dupack)
+ tcp_add_reno_sack(sk);
+ else if (flag & FLAG_SND_UNA_ADVANCED)
+ tcp_reset_reno_sack(tp);
+ }
+ if (tcp_try_undo_loss(sk, false))
+ return;
+ tcp_xmit_retransmit_queue(sk);
+}
+
/* Process an event, which can update packets-in-flight not trivially.
* Main goal of this function is to calculate new estimate for left_out,
* taking into account both packets sitting in receiver's buffer and
@@ -2918,12 +2777,6 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
tp->retrans_stamp = 0;
} else if (!before(tp->snd_una, tp->high_seq)) {
switch (icsk->icsk_ca_state) {
- case TCP_CA_Loss:
- icsk->icsk_retransmits = 0;
- if (tcp_try_undo_recovery(sk))
- return;
- break;
-
case TCP_CA_CWR:
/* CWR is to be held something *above* high_seq
* is ACKed for CWR bit to reach receiver. */
@@ -2954,18 +2807,10 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked;
break;
case TCP_CA_Loss:
- if (flag & FLAG_DATA_ACKED)
- icsk->icsk_retransmits = 0;
- if (tcp_is_reno(tp) && flag & FLAG_SND_UNA_ADVANCED)
- tcp_reset_reno_sack(tp);
- if (!tcp_try_undo_loss(sk)) {
- tcp_moderate_cwnd(tp);
- tcp_xmit_retransmit_queue(sk);
- return;
- }
+ tcp_process_loss(sk, flag, is_dupack);
if (icsk->icsk_ca_state != TCP_CA_Open)
return;
- /* Loss is undone; fall through to processing in Open state. */
+ /* Fall through to processing in Open state. */
default:
if (tcp_is_reno(tp)) {
if (flag & FLAG_SND_UNA_ADVANCED)
@@ -3078,6 +2923,7 @@ static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
*/
void tcp_rearm_rto(struct sock *sk)
{
+ const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
/* If the retrans timer is currently being used by Fast Open
@@ -3091,12 +2937,13 @@ void tcp_rearm_rto(struct sock *sk)
} else {
u32 rto = inet_csk(sk)->icsk_rto;
/* Offset the time elapsed after installing regular RTO */
- if (tp->early_retrans_delayed) {
+ if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
struct sk_buff *skb = tcp_write_queue_head(sk);
const u32 rto_time_stamp = TCP_SKB_CB(skb)->when + rto;
s32 delta = (s32)(rto_time_stamp - tcp_time_stamp);
/* delta may not be positive if the socket is locked
- * when the delayed ER timer fires and is rescheduled.
+ * when the retrans timer fires and is rescheduled.
*/
if (delta > 0)
rto = delta;
@@ -3104,7 +2951,6 @@ void tcp_rearm_rto(struct sock *sk)
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto,
TCP_RTO_MAX);
}
- tp->early_retrans_delayed = 0;
}
/* This function is called when the delayed ER timer fires. TCP enters
@@ -3192,8 +3038,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
flag |= FLAG_RETRANS_DATA_ACKED;
ca_seq_rtt = -1;
seq_rtt = -1;
- if ((flag & FLAG_DATA_ACKED) || (acked_pcount > 1))
- flag |= FLAG_NONHEAD_RETRANS_ACKED;
} else {
ca_seq_rtt = now - scb->when;
last_ackt = skb->tstamp;
@@ -3202,6 +3046,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
}
if (!(sacked & TCPCB_SACKED_ACKED))
reord = min(pkts_acked, reord);
+ if (!after(scb->end_seq, tp->high_seq))
+ flag |= FLAG_ORIG_SACK_ACKED;
}
if (sacked & TCPCB_SACKED_ACKED)
@@ -3402,165 +3248,74 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32
return flag;
}
-/* A very conservative spurious RTO response algorithm: reduce cwnd and
- * continue in congestion avoidance.
- */
-static void tcp_conservative_spur_to_response(struct tcp_sock *tp)
+/* RFC 5961 7 [ACK Throttling] */
+static void tcp_send_challenge_ack(struct sock *sk)
{
- tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
- tp->snd_cwnd_cnt = 0;
- TCP_ECN_queue_cwr(tp);
- tcp_moderate_cwnd(tp);
-}
+ /* unprotected vars, we dont care of overwrites */
+ static u32 challenge_timestamp;
+ static unsigned int challenge_count;
+ u32 now = jiffies / HZ;
-/* A conservative spurious RTO response algorithm: reduce cwnd using
- * PRR and continue in congestion avoidance.
- */
-static void tcp_cwr_spur_to_response(struct sock *sk)
-{
- tcp_enter_cwr(sk, 0);
+ if (now != challenge_timestamp) {
+ challenge_timestamp = now;
+ challenge_count = 0;
+ }
+ if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
+ tcp_send_ack(sk);
+ }
}
-static void tcp_undo_spur_to_response(struct sock *sk, int flag)
+static void tcp_store_ts_recent(struct tcp_sock *tp)
{
- if (flag & FLAG_ECE)
- tcp_cwr_spur_to_response(sk);
- else
- tcp_undo_cwr(sk, true);
+ tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
+ tp->rx_opt.ts_recent_stamp = get_seconds();
}
-/* F-RTO spurious RTO detection algorithm (RFC4138)
- *
- * F-RTO affects during two new ACKs following RTO (well, almost, see inline
- * comments). State (ACK number) is kept in frto_counter. When ACK advances
- * window (but not to or beyond highest sequence sent before RTO):
- * On First ACK, send two new segments out.
- * On Second ACK, RTO was likely spurious. Do spurious response (response
- * algorithm is not part of the F-RTO detection algorithm
- * given in RFC4138 but can be selected separately).
- * Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss
- * and TCP falls back to conventional RTO recovery. F-RTO allows overriding
- * of Nagle, this is done using frto_counter states 2 and 3, when a new data
- * segment of any size sent during F-RTO, state 2 is upgraded to 3.
- *
- * Rationale: if the RTO was spurious, new ACKs should arrive from the
- * original window even after we transmit two new data segments.
- *
- * SACK version:
- * on first step, wait until first cumulative ACK arrives, then move to
- * the second step. In second step, the next ACK decides.
- *
- * F-RTO is implemented (mainly) in four functions:
- * - tcp_use_frto() is used to determine if TCP is can use F-RTO
- * - tcp_enter_frto() prepares TCP state on RTO if F-RTO is used, it is
- * called when tcp_use_frto() showed green light
- * - tcp_process_frto() handles incoming ACKs during F-RTO algorithm
- * - tcp_enter_frto_loss() is called if there is not enough evidence
- * to prove that the RTO is indeed spurious. It transfers the control
- * from F-RTO to the conventional RTO recovery
- */
-static bool tcp_process_frto(struct sock *sk, int flag)
+static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
{
- struct tcp_sock *tp = tcp_sk(sk);
-
- tcp_verify_left_out(tp);
-
- /* Duplicate the behavior from Loss state (fastretrans_alert) */
- if (flag & FLAG_DATA_ACKED)
- inet_csk(sk)->icsk_retransmits = 0;
-
- if ((flag & FLAG_NONHEAD_RETRANS_ACKED) ||
- ((tp->frto_counter >= 2) && (flag & FLAG_RETRANS_DATA_ACKED)))
- tp->undo_marker = 0;
-
- if (!before(tp->snd_una, tp->frto_highmark)) {
- tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag);
- return true;
- }
-
- if (!tcp_is_sackfrto(tp)) {
- /* RFC4138 shortcoming in step 2; should also have case c):
- * ACK isn't duplicate nor advances window, e.g., opposite dir
- * data, winupdate
+ if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
+ /* PAWS bug workaround wrt. ACK frames, the PAWS discard
+ * extra check below makes sure this can only happen
+ * for pure ACK frames. -DaveM
+ *
+ * Not only, also it occurs for expired timestamps.
*/
- if (!(flag & FLAG_ANY_PROGRESS) && (flag & FLAG_NOT_DUP))
- return true;
- if (!(flag & FLAG_DATA_ACKED)) {
- tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 0 : 3),
- flag);
- return true;
- }
- } else {
- if (!(flag & FLAG_DATA_ACKED) && (tp->frto_counter == 1)) {
- if (!tcp_packets_in_flight(tp)) {
- tcp_enter_frto_loss(sk, 2, flag);
- return true;
- }
-
- /* Prevent sending of new data. */
- tp->snd_cwnd = min(tp->snd_cwnd,
- tcp_packets_in_flight(tp));
- return true;
- }
-
- if ((tp->frto_counter >= 2) &&
- (!(flag & FLAG_FORWARD_PROGRESS) ||
- ((flag & FLAG_DATA_SACKED) &&
- !(flag & FLAG_ONLY_ORIG_SACKED)))) {
- /* RFC4138 shortcoming (see comment above) */
- if (!(flag & FLAG_FORWARD_PROGRESS) &&
- (flag & FLAG_NOT_DUP))
- return true;
-
- tcp_enter_frto_loss(sk, 3, flag);
- return true;
- }
- }
-
- if (tp->frto_counter == 1) {
- /* tcp_may_send_now needs to see updated state */
- tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
- tp->frto_counter = 2;
-
- if (!tcp_may_send_now(sk))
- tcp_enter_frto_loss(sk, 2, flag);
-
- return true;
- } else {
- switch (sysctl_tcp_frto_response) {
- case 2:
- tcp_undo_spur_to_response(sk, flag);
- break;
- case 1:
- tcp_conservative_spur_to_response(tp);
- break;
- default:
- tcp_cwr_spur_to_response(sk);
- break;
- }
- tp->frto_counter = 0;
- tp->undo_marker = 0;
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSPURIOUSRTOS);
+ if (tcp_paws_check(&tp->rx_opt, 0))
+ tcp_store_ts_recent(tp);
}
- return false;
}
-/* RFC 5961 7 [ACK Throttling] */
-static void tcp_send_challenge_ack(struct sock *sk)
+/* This routine deals with acks during a TLP episode.
+ * Ref: loss detection algorithm in draft-dukkipati-tcpm-tcp-loss-probe.
+ */
+static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag)
{
- /* unprotected vars, we dont care of overwrites */
- static u32 challenge_timestamp;
- static unsigned int challenge_count;
- u32 now = jiffies / HZ;
+ struct tcp_sock *tp = tcp_sk(sk);
+ bool is_tlp_dupack = (ack == tp->tlp_high_seq) &&
+ !(flag & (FLAG_SND_UNA_ADVANCED |
+ FLAG_NOT_DUP | FLAG_DATA_SACKED));
- if (now != challenge_timestamp) {
- challenge_timestamp = now;
- challenge_count = 0;
+ /* Mark the end of TLP episode on receiving TLP dupack or when
+ * ack is after tlp_high_seq.
+ */
+ if (is_tlp_dupack) {
+ tp->tlp_high_seq = 0;
+ return;
}
- if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
- NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
- tcp_send_ack(sk);
+
+ if (after(ack, tp->tlp_high_seq)) {
+ tp->tlp_high_seq = 0;
+ /* Don't reduce cwnd if DSACK arrives for TLP retrans. */
+ if (!(flag & FLAG_DSACKING_ACK)) {
+ tcp_init_cwnd_reduction(sk, true);
+ tcp_set_ca_state(sk, TCP_CA_CWR);
+ tcp_end_cwnd_reduction(sk);
+ tcp_set_ca_state(sk, TCP_CA_Open);
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPLOSSPROBERECOVERY);
+ }
}
}
@@ -3578,7 +3333,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
int prior_packets;
int prior_sacked = tp->sacked_out;
int pkts_acked = 0;
- bool frto_cwnd = false;
/* If the ack is older than previous acks
* then we can probably ignore it.
@@ -3598,7 +3352,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
if (after(ack, tp->snd_nxt))
goto invalid_ack;
- if (tp->early_retrans_delayed)
+ if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)
tcp_rearm_rto(sk);
if (after(ack, prior_snd_una))
@@ -3607,6 +3362,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
prior_fackets = tp->fackets_out;
prior_in_flight = tcp_packets_in_flight(tp);
+ /* ts_recent update must be made after we are sure that the packet
+ * is in window.
+ */
+ if (flag & FLAG_UPDATE_TS_RECENT)
+ tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
+
if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
/* Window is constant, pure forward advance.
* No more checks are required.
@@ -3651,30 +3412,29 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
pkts_acked = prior_packets - tp->packets_out;
- if (tp->frto_counter)
- frto_cwnd = tcp_process_frto(sk, flag);
- /* Guarantee sacktag reordering detection against wrap-arounds */
- if (before(tp->frto_highmark, tp->snd_una))
- tp->frto_highmark = 0;
-
if (tcp_ack_is_dubious(sk, flag)) {
/* Advance CWND, if state allows this. */
- if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
- tcp_may_raise_cwnd(sk, flag))
+ if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(sk, flag))
tcp_cong_avoid(sk, ack, prior_in_flight);
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
is_dupack, flag);
} else {
- if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
+ if (flag & FLAG_DATA_ACKED)
tcp_cong_avoid(sk, ack, prior_in_flight);
}
+ if (tp->tlp_high_seq)
+ tcp_process_tlp_ack(sk, ack, flag);
+
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
struct dst_entry *dst = __sk_dst_get(sk);
if (dst)
dst_confirm(dst);
}
+
+ if (icsk->icsk_pending == ICSK_TIME_RETRANS)
+ tcp_schedule_loss_probe(sk);
return 1;
no_queue:
@@ -3688,6 +3448,9 @@ no_queue:
*/
if (tcp_send_head(sk))
tcp_ack_probe(sk);
+
+ if (tp->tlp_high_seq)
+ tcp_process_tlp_ack(sk, ack, flag);
return 1;
invalid_ack:
@@ -3712,8 +3475,8 @@ old_ack:
* But, this can also be called on packets in the established flow when
* the fast version below fails.
*/
-void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx,
- const u8 **hvpp, int estab,
+void tcp_parse_options(const struct sk_buff *skb,
+ struct tcp_options_received *opt_rx, int estab,
struct tcp_fastopen_cookie *foc)
{
const unsigned char *ptr;
@@ -3797,31 +3560,6 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o
*/
break;
#endif
- case TCPOPT_COOKIE:
- /* This option is variable length.
- */
- switch (opsize) {
- case TCPOLEN_COOKIE_BASE:
- /* not yet implemented */
- break;
- case TCPOLEN_COOKIE_PAIR:
- /* not yet implemented */
- break;
- case TCPOLEN_COOKIE_MIN+0:
- case TCPOLEN_COOKIE_MIN+2:
- case TCPOLEN_COOKIE_MIN+4:
- case TCPOLEN_COOKIE_MIN+6:
- case TCPOLEN_COOKIE_MAX:
- /* 16-bit multiple */
- opt_rx->cookie_plus = opsize;
- *hvpp = ptr;
- break;
- default:
- /* ignore option */
- break;
- }
- break;
-
case TCPOPT_EXP:
/* Fast Open option shares code 254 using a
* 16 bits magic number. It's valid only in
@@ -3867,8 +3605,7 @@ static bool tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr
* If it is wrong it falls back on tcp_parse_options().
*/
static bool tcp_fast_parse_options(const struct sk_buff *skb,
- const struct tcphdr *th,
- struct tcp_sock *tp, const u8 **hvpp)
+ const struct tcphdr *th, struct tcp_sock *tp)
{
/* In the spirit of fast parsing, compare doff directly to constant
* values. Because equality is used, short doff can be ignored here.
@@ -3882,7 +3619,7 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb,
return true;
}
- tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL);
+ tcp_parse_options(skb, &tp->rx_opt, 1, NULL);
if (tp->rx_opt.saw_tstamp)
tp->rx_opt.rcv_tsecr -= tp->tsoffset;
@@ -3927,27 +3664,6 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
EXPORT_SYMBOL(tcp_parse_md5sig_option);
#endif
-static inline void tcp_store_ts_recent(struct tcp_sock *tp)
-{
- tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
- tp->rx_opt.ts_recent_stamp = get_seconds();
-}
-
-static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
-{
- if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
- /* PAWS bug workaround wrt. ACK frames, the PAWS discard
- * extra check below makes sure this can only happen
- * for pure ACK frames. -DaveM
- *
- * Not only, also it occurs for expired timestamps.
- */
-
- if (tcp_paws_check(&tp->rx_opt, 0))
- tcp_store_ts_recent(tp);
- }
-}
-
/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
*
* It is not fatal. If this ACK does _not_ change critical state (seqs, window)
@@ -5263,12 +4979,10 @@ out:
static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, int syn_inerr)
{
- const u8 *hash_location;
struct tcp_sock *tp = tcp_sk(sk);
/* RFC1323: H1. Apply PAWS check first. */
- if (tcp_fast_parse_options(skb, th, tp, &hash_location) &&
- tp->rx_opt.saw_tstamp &&
+ if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
tcp_paws_discard(sk, skb)) {
if (!th->rst) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
@@ -5543,14 +5257,9 @@ slow_path:
return 0;
step5:
- if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
+ if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0)
goto discard;
- /* ts_recent update must be made after we are sure that the packet
- * is in window.
- */
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
tcp_rcv_rtt_measure_ts(sk, skb);
/* Process urgent data. */
@@ -5564,6 +5273,7 @@ step5:
return 0;
csum_error:
+ TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
discard:
@@ -5622,12 +5332,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
if (mss == tp->rx_opt.user_mss) {
struct tcp_options_received opt;
- const u8 *hash_location;
/* Get original SYNACK MSS value if user MSS sets mss_clamp */
tcp_clear_options(&opt);
opt.user_mss = opt.mss_clamp = 0;
- tcp_parse_options(synack, &opt, &hash_location, 0, NULL);
+ tcp_parse_options(synack, &opt, 0, NULL);
mss = opt.mss_clamp;
}
@@ -5658,14 +5367,12 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, unsigned int len)
{
- const u8 *hash_location;
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct tcp_cookie_values *cvp = tp->cookie_values;
struct tcp_fastopen_cookie foc = { .len = -1 };
int saved_clamp = tp->rx_opt.mss_clamp;
- tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc);
+ tcp_parse_options(skb, &tp->rx_opt, 0, &foc);
if (tp->rx_opt.saw_tstamp)
tp->rx_opt.rcv_tsecr -= tp->tsoffset;
@@ -5762,30 +5469,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
* is initialized. */
tp->copied_seq = tp->rcv_nxt;
- if (cvp != NULL &&
- cvp->cookie_pair_size > 0 &&
- tp->rx_opt.cookie_plus > 0) {
- int cookie_size = tp->rx_opt.cookie_plus
- - TCPOLEN_COOKIE_BASE;
- int cookie_pair_size = cookie_size
- + cvp->cookie_desired;
-
- /* A cookie extension option was sent and returned.
- * Note that each incoming SYNACK replaces the
- * Responder cookie. The initial exchange is most
- * fragile, as protection against spoofing relies
- * entirely upon the sequence and timestamp (above).
- * This replacement strategy allows the correct pair to
- * pass through, while any others will be filtered via
- * Responder verification later.
- */
- if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
- memcpy(&cvp->cookie_pair[cvp->cookie_desired],
- hash_location, cookie_size);
- cvp->cookie_pair_size = cookie_pair_size;
- }
- }
-
smp_mb();
tcp_finish_connect(sk, skb);
@@ -5986,7 +5669,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* step 5: check the ACK field */
if (true) {
- int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
+ int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
+ FLAG_UPDATE_TS_RECENT) > 0;
switch (sk->sk_state) {
case TCP_SYN_RECV:
@@ -6137,11 +5821,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
}
}
- /* ts_recent update must be made after we are sure that the packet
- * is in window.
- */
- tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
-
/* step 6: check the URG bit */
tcp_urg(sk, skb, th);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fc55a1c79bd9..719652305a29 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -838,7 +838,6 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
*/
static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
- struct request_values *rvp,
u16 queue_mapping,
bool nocache)
{
@@ -851,7 +850,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
return -1;
- skb = tcp_make_synack(sk, dst, req, rvp, NULL);
+ skb = tcp_make_synack(sk, dst, req, NULL);
if (skb) {
__tcp_v4_send_check(skb, ireq->loc_addr, ireq->rmt_addr);
@@ -868,10 +867,9 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
return err;
}
-static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req,
- struct request_values *rvp)
+static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req)
{
- int res = tcp_v4_send_synack(sk, NULL, req, rvp, 0, false);
+ int res = tcp_v4_send_synack(sk, NULL, req, 0, false);
if (!res)
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
@@ -1371,8 +1369,7 @@ static bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
static int tcp_v4_conn_req_fastopen(struct sock *sk,
struct sk_buff *skb,
struct sk_buff *skb_synack,
- struct request_sock *req,
- struct request_values *rvp)
+ struct request_sock *req)
{
struct tcp_sock *tp = tcp_sk(sk);
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
@@ -1467,9 +1464,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
- struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
- const u8 *hash_location;
struct request_sock *req;
struct inet_request_sock *ireq;
struct tcp_sock *tp = tcp_sk(sk);
@@ -1519,42 +1514,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
tmp_opt.user_mss = tp->rx_opt.user_mss;
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0,
- want_cookie ? NULL : &foc);
-
- if (tmp_opt.cookie_plus > 0 &&
- tmp_opt.saw_tstamp &&
- !tp->rx_opt.cookie_out_never &&
- (sysctl_tcp_cookie_size > 0 ||
- (tp->cookie_values != NULL &&
- tp->cookie_values->cookie_desired > 0))) {
- u8 *c;
- u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
- int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
-
- if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
- goto drop_and_release;
-
- /* Secret recipe starts with IP addresses */
- *mess++ ^= (__force u32)daddr;
- *mess++ ^= (__force u32)saddr;
-
- /* plus variable length Initiator Cookie */
- c = (u8 *)mess;
- while (l-- > 0)
- *c++ ^= *hash_location++;
-
- want_cookie = false; /* not our kind of cookie */
- tmp_ext.cookie_out_never = 0; /* false */
- tmp_ext.cookie_plus = tmp_opt.cookie_plus;
- } else if (!tp->rx_opt.cookie_in_always) {
- /* redundant indications, but ensure initialization. */
- tmp_ext.cookie_out_never = 1; /* true */
- tmp_ext.cookie_plus = 0;
- } else {
- goto drop_and_release;
- }
- tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
+ tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
@@ -1636,7 +1596,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* of tcp_v4_send_synack()->tcp_select_initial_window().
*/
skb_synack = tcp_make_synack(sk, dst, req,
- (struct request_values *)&tmp_ext,
fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL);
if (skb_synack) {
@@ -1660,8 +1619,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (fastopen_cookie_present(&foc) && foc.len != 0)
NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPFASTOPENPASSIVEFAIL);
- } else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req,
- (struct request_values *)&tmp_ext))
+ } else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req))
goto drop_and_free;
return 0;
@@ -1908,6 +1866,7 @@ discard:
return 0;
csum_err:
+ TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
goto discard;
}
@@ -1950,6 +1909,51 @@ void tcp_v4_early_demux(struct sk_buff *skb)
}
}
+/* Packet is added to VJ-style prequeue for processing in process
+ * context, if a reader task is waiting. Apparently, this exciting
+ * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93)
+ * failed somewhere. Latency? Burstiness? Well, at least now we will
+ * see, why it failed. 8)8) --ANK
+ *
+ */
+bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+
+ if (sysctl_tcp_low_latency || !tp->ucopy.task)
+ return false;
+
+ if (skb->len <= tcp_hdrlen(skb) &&
+ skb_queue_len(&tp->ucopy.prequeue) == 0)
+ return false;
+
+ skb_dst_force(skb);
+ __skb_queue_tail(&tp->ucopy.prequeue, skb);
+ tp->ucopy.memory += skb->truesize;
+ if (tp->ucopy.memory > sk->sk_rcvbuf) {
+ struct sk_buff *skb1;
+
+ BUG_ON(sock_owned_by_user(sk));
+
+ while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
+ sk_backlog_rcv(sk, skb1);
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPPREQUEUEDROPPED);
+ }
+
+ tp->ucopy.memory = 0;
+ } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
+ wake_up_interruptible_sync_poll(sk_sleep(sk),
+ POLLIN | POLLRDNORM | POLLRDBAND);
+ if (!inet_csk_ack_scheduled(sk))
+ inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+ (3 * tcp_rto_min(sk)) / 4,
+ TCP_RTO_MAX);
+ }
+ return true;
+}
+EXPORT_SYMBOL(tcp_prequeue);
+
/*
* From tcp_input.c
*/
@@ -1983,7 +1987,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
* provided case of th->doff==0 is eliminated.
* So, we defer the checks. */
if (!skb_csum_unnecessary(skb) && tcp_v4_checksum_init(skb))
- goto bad_packet;
+ goto csum_error;
th = tcp_hdr(skb);
iph = ip_hdr(skb);
@@ -2049,6 +2053,8 @@ no_tcp_socket:
goto discard_it;
if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
+csum_error:
+ TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);
bad_packet:
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
} else {
@@ -2070,10 +2076,13 @@ do_time_wait:
goto discard_it;
}
- if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
- TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
+ if (skb->len < (th->doff << 2)) {
inet_twsk_put(inet_twsk(sk));
- goto discard_it;
+ goto bad_packet;
+ }
+ if (tcp_checksum_complete(skb)) {
+ inet_twsk_put(inet_twsk(sk));
+ goto csum_error;
}
switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
case TCP_TW_SYN: {
@@ -2197,12 +2206,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
if (inet_csk(sk)->icsk_bind_hash)
inet_put_port(sk);
- /* TCP Cookie Transactions */
- if (tp->cookie_values != NULL) {
- kref_put(&tp->cookie_values->kref,
- tcp_cookie_values_release);
- tp->cookie_values = NULL;
- }
BUG_ON(tp->fastopen_rsk != NULL);
/* If socket is aborted during connect operation */
@@ -2659,7 +2662,9 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
__u16 srcp = ntohs(inet->inet_sport);
int rx_queue;
- if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
+ if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
timer_active = 1;
timer_expires = icsk->icsk_timeout;
} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index b6f3583ddfe8..da14436c1735 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -64,7 +64,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
{
struct cg_proto *cg_proto;
struct tcp_memcontrol *tcp;
- u64 val;
cg_proto = tcp_prot.proto_cgroup(memcg);
if (!cg_proto)
@@ -72,8 +71,6 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
tcp = tcp_from_cgproto(cg_proto);
percpu_counter_destroy(&tcp->tcp_sockets_allocated);
-
- val = res_counter_read_u64(&tcp->tcp_memory_allocated, RES_LIMIT);
}
EXPORT_SYMBOL(tcp_destroy_cgroup);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b83a49cc3816..0f0178827259 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -93,13 +93,12 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th)
{
struct tcp_options_received tmp_opt;
- const u8 *hash_location;
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
bool paws_reject = false;
tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
+ tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (tmp_opt.saw_tstamp) {
tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset;
@@ -388,32 +387,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_request_sock *treq = tcp_rsk(req);
struct inet_connection_sock *newicsk = inet_csk(newsk);
struct tcp_sock *newtp = tcp_sk(newsk);
- struct tcp_sock *oldtp = tcp_sk(sk);
- struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
-
- /* TCP Cookie Transactions require space for the cookie pair,
- * as it differs for each connection. There is no need to
- * copy any s_data_payload stored at the original socket.
- * Failure will prevent resuming the connection.
- *
- * Presumed copied, in order of appearance:
- * cookie_in_always, cookie_out_never
- */
- if (oldcvp != NULL) {
- struct tcp_cookie_values *newcvp =
- kzalloc(sizeof(*newtp->cookie_values),
- GFP_ATOMIC);
-
- if (newcvp != NULL) {
- kref_init(&newcvp->kref);
- newcvp->cookie_desired =
- oldcvp->cookie_desired;
- newtp->cookie_values = newcvp;
- } else {
- /* Not Yet Implemented */
- newtp->cookie_values = NULL;
- }
- }
/* Now setup tcp_sock */
newtp->pred_flags = 0;
@@ -422,8 +395,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->rcv_nxt = treq->rcv_isn + 1;
newtp->snd_sml = newtp->snd_una =
- newtp->snd_nxt = newtp->snd_up =
- treq->snt_isn + 1 + tcp_s_data_size(oldtp);
+ newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
tcp_prequeue_init(newtp);
INIT_LIST_HEAD(&newtp->tsq_node);
@@ -440,6 +412,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->fackets_out = 0;
newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
tcp_enable_early_retrans(newtp);
+ newtp->tlp_high_seq = 0;
/* So many TCP implementations out there (incorrectly) count the
* initial SYN frame in their delayed-ACK and congestion control
@@ -449,9 +422,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->snd_cwnd = TCP_INIT_CWND;
newtp->snd_cwnd_cnt = 0;
- newtp->frto_counter = 0;
- newtp->frto_highmark = 0;
-
if (newicsk->icsk_ca_ops != &tcp_init_congestion_ops &&
!try_module_get(newicsk->icsk_ca_ops->owner))
newicsk->icsk_ca_ops = &tcp_init_congestion_ops;
@@ -459,8 +429,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
tcp_set_ca_state(newsk, TCP_CA_Open);
tcp_init_xmit_timers(newsk);
skb_queue_head_init(&newtp->out_of_order_queue);
- newtp->write_seq = newtp->pushed_seq =
- treq->snt_isn + 1 + tcp_s_data_size(oldtp);
+ newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1;
newtp->rx_opt.saw_tstamp = 0;
@@ -537,7 +506,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
bool fastopen)
{
struct tcp_options_received tmp_opt;
- const u8 *hash_location;
struct sock *child;
const struct tcphdr *th = tcp_hdr(skb);
__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
@@ -547,7 +515,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(struct tcphdr)>>2)) {
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
+ tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent;
@@ -583,8 +551,13 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
*
* Note that even if there is new data in the SYN packet
* they will be thrown away too.
+ *
+ * Reset timer after retransmitting SYNACK, similar to
+ * the idea of fast retransmit in recovery.
*/
- inet_rtx_syn_ack(sk, req);
+ if (!inet_rtx_syn_ack(sk, req))
+ req->expires = min(TCP_TIMEOUT_INIT << req->num_timeout,
+ TCP_RTO_MAX) + jiffies;
return NULL;
}
@@ -647,7 +620,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
*/
if ((flg & TCP_FLAG_ACK) && !fastopen &&
(TCP_SKB_CB(skb)->ack_seq !=
- tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk))))
+ tcp_rsk(req)->snt_isn + 1))
return sk;
/* Also, it would be not so bad idea to check rcv_tsecr, which
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 5d0b4387cba6..536d40929ba6 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -65,28 +65,24 @@ int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS;
/* By default, RFC2861 behavior. */
int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
-int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */
-EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);
-
static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
int push_one, gfp_t gfp);
/* Account for new data that has been sent to the network. */
static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
{
+ struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
unsigned int prior_packets = tp->packets_out;
tcp_advance_send_head(sk, skb);
tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
- /* Don't override Nagle indefinitely with F-RTO */
- if (tp->frto_counter == 2)
- tp->frto_counter = 3;
-
tp->packets_out += tcp_skb_pcount(skb);
- if (!prior_packets || tp->early_retrans_delayed)
+ if (!prior_packets || icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
+ icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
tcp_rearm_rto(sk);
+ }
}
/* SND.NXT, if window was not shrunk.
@@ -384,7 +380,6 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_TS (1 << 1)
#define OPTION_MD5 (1 << 2)
#define OPTION_WSCALE (1 << 3)
-#define OPTION_COOKIE_EXTENSION (1 << 4)
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
struct tcp_out_options {
@@ -398,36 +393,6 @@ struct tcp_out_options {
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
};
-/* The sysctl int routines are generic, so check consistency here.
- */
-static u8 tcp_cookie_size_check(u8 desired)
-{
- int cookie_size;
-
- if (desired > 0)
- /* previously specified */
- return desired;
-
- cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size);
- if (cookie_size <= 0)
- /* no default specified */
- return 0;
-
- if (cookie_size <= TCP_COOKIE_MIN)
- /* value too small, specify minimum */
- return TCP_COOKIE_MIN;
-
- if (cookie_size >= TCP_COOKIE_MAX)
- /* value too large, specify maximum */
- return TCP_COOKIE_MAX;
-
- if (cookie_size & 1)
- /* 8-bit multiple, illegal, fix it */
- cookie_size++;
-
- return (u8)cookie_size;
-}
-
/* Write previously computed TCP options to the packet.
*
* Beware: Something in the Internet is very sensitive to the ordering of
@@ -446,27 +411,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
{
u16 options = opts->options; /* mungable copy */
- /* Having both authentication and cookies for security is redundant,
- * and there's certainly not enough room. Instead, the cookie-less
- * extension variant is proposed.
- *
- * Consider the pessimal case with authentication. The options
- * could look like:
- * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
- */
if (unlikely(OPTION_MD5 & options)) {
- if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
- *ptr++ = htonl((TCPOPT_COOKIE << 24) |
- (TCPOLEN_COOKIE_BASE << 16) |
- (TCPOPT_MD5SIG << 8) |
- TCPOLEN_MD5SIG);
- } else {
- *ptr++ = htonl((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_MD5SIG << 8) |
- TCPOLEN_MD5SIG);
- }
- options &= ~OPTION_COOKIE_EXTENSION;
+ *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+ (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
/* overload cookie hash location */
opts->hash_location = (__u8 *)ptr;
ptr += 4;
@@ -495,44 +442,6 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
*ptr++ = htonl(opts->tsecr);
}
- /* Specification requires after timestamp, so do it now.
- *
- * Consider the pessimal case without authentication. The options
- * could look like:
- * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
- */
- if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
- __u8 *cookie_copy = opts->hash_location;
- u8 cookie_size = opts->hash_size;
-
- /* 8-bit multiple handled in tcp_cookie_size_check() above,
- * and elsewhere.
- */
- if (0x2 & cookie_size) {
- __u8 *p = (__u8 *)ptr;
-
- /* 16-bit multiple */
- *p++ = TCPOPT_COOKIE;
- *p++ = TCPOLEN_COOKIE_BASE + cookie_size;
- *p++ = *cookie_copy++;
- *p++ = *cookie_copy++;
- ptr++;
- cookie_size -= 2;
- } else {
- /* 32-bit multiple */
- *ptr++ = htonl(((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_COOKIE << 8) |
- TCPOLEN_COOKIE_BASE) +
- cookie_size);
- }
-
- if (cookie_size > 0) {
- memcpy(ptr, cookie_copy, cookie_size);
- ptr += (cookie_size / 4);
- }
- }
-
if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
@@ -591,11 +500,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_md5sig_key **md5)
{
struct tcp_sock *tp = tcp_sk(sk);
- struct tcp_cookie_values *cvp = tp->cookie_values;
unsigned int remaining = MAX_TCP_OPTION_SPACE;
- u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ?
- tcp_cookie_size_check(cvp->cookie_desired) :
- 0;
struct tcp_fastopen_request *fastopen = tp->fastopen_req;
#ifdef CONFIG_TCP_MD5SIG
@@ -647,52 +552,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
tp->syn_fastopen = 1;
}
}
- /* Note that timestamps are required by the specification.
- *
- * Odd numbers of bytes are prohibited by the specification, ensuring
- * that the cookie is 16-bit aligned, and the resulting cookie pair is
- * 32-bit aligned.
- */
- if (*md5 == NULL &&
- (OPTION_TS & opts->options) &&
- cookie_size > 0) {
- int need = TCPOLEN_COOKIE_BASE + cookie_size;
-
- if (0x2 & need) {
- /* 32-bit multiple */
- need += 2; /* NOPs */
-
- if (need > remaining) {
- /* try shrinking cookie to fit */
- cookie_size -= 2;
- need -= 4;
- }
- }
- while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
- cookie_size -= 4;
- need -= 4;
- }
- if (TCP_COOKIE_MIN <= cookie_size) {
- opts->options |= OPTION_COOKIE_EXTENSION;
- opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
- opts->hash_size = cookie_size;
-
- /* Remember for future incarnations. */
- cvp->cookie_desired = cookie_size;
-
- if (cvp->cookie_desired != cvp->cookie_pair_size) {
- /* Currently use random bytes as a nonce,
- * assuming these are completely unpredictable
- * by hostile users of the same system.
- */
- get_random_bytes(&cvp->cookie_pair[0],
- cookie_size);
- cvp->cookie_pair_size = cookie_size;
- }
- remaining -= need;
- }
- }
return MAX_TCP_OPTION_SPACE - remaining;
}
@@ -702,14 +562,10 @@ static unsigned int tcp_synack_options(struct sock *sk,
unsigned int mss, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5,
- struct tcp_extend_values *xvp,
struct tcp_fastopen_cookie *foc)
{
struct inet_request_sock *ireq = inet_rsk(req);
unsigned int remaining = MAX_TCP_OPTION_SPACE;
- u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
- xvp->cookie_plus :
- 0;
#ifdef CONFIG_TCP_MD5SIG
*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
@@ -757,28 +613,7 @@ static unsigned int tcp_synack_options(struct sock *sk,
remaining -= need;
}
}
- /* Similar rationale to tcp_syn_options() applies here, too.
- * If the <SYN> options fit, the same options should fit now!
- */
- if (*md5 == NULL &&
- ireq->tstamp_ok &&
- cookie_plus > TCPOLEN_COOKIE_BASE) {
- int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
-
- if (0x2 & need) {
- /* 32-bit multiple */
- need += 2; /* NOPs */
- }
- if (need <= remaining) {
- opts->options |= OPTION_COOKIE_EXTENSION;
- opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE;
- remaining -= need;
- } else {
- /* There's no error return, so flag it. */
- xvp->cookie_out_never = 1; /* true */
- opts->hash_size = 0;
- }
- }
+
return MAX_TCP_OPTION_SPACE - remaining;
}
@@ -953,7 +788,7 @@ void __init tcp_tasklet_init(void)
* We cant xmit new skbs from this context, as we might already
* hold qdisc lock.
*/
-static void tcp_wfree(struct sk_buff *skb)
+void tcp_wfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct tcp_sock *tp = tcp_sk(sk);
@@ -1012,6 +847,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
__net_timestamp(skb);
if (likely(clone_it)) {
+ const struct sk_buff *fclone = skb + 1;
+
+ if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
+ fclone->fclone == SKB_FCLONE_CLONE))
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+
if (unlikely(skb_cloned(skb)))
skb = pskb_copy(skb, gfp_mask);
else
@@ -1632,11 +1474,8 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf
if (nonagle & TCP_NAGLE_PUSH)
return true;
- /* Don't use the nagle rule for urgent data (or for the final FIN).
- * Nagle can be ignored during F-RTO too (see RFC4138).
- */
- if (tcp_urg_mode(tp) || (tp->frto_counter == 2) ||
- (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))
+ /* Don't use the nagle rule for urgent data (or for the final FIN). */
+ if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))
return true;
if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
@@ -1961,6 +1800,9 @@ static int tcp_mtu_probe(struct sock *sk)
* snd_up-64k-mss .. snd_up cannot be large. However, taking into
* account rare use of URG, this is not a big flaw.
*
+ * Send at most one packet when push_one > 0. Temporarily ignore
+ * cwnd limit to force at most one packet out when push_one == 2.
+
* Returns true, if no segments are in flight and we have queued segments,
* but cannot send anything now because of SWS or another problem.
*/
@@ -1996,8 +1838,13 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
goto repair; /* Skip network transmission */
cwnd_quota = tcp_cwnd_test(tp, skb);
- if (!cwnd_quota)
- break;
+ if (!cwnd_quota) {
+ if (push_one == 2)
+ /* Force out a loss probe pkt. */
+ cwnd_quota = 1;
+ else
+ break;
+ }
if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now)))
break;
@@ -2051,10 +1898,129 @@ repair:
if (likely(sent_pkts)) {
if (tcp_in_cwnd_reduction(sk))
tp->prr_out += sent_pkts;
+
+ /* Send one loss probe per tail loss episode. */
+ if (push_one != 2)
+ tcp_schedule_loss_probe(sk);
tcp_cwnd_validate(sk);
return false;
}
- return !tp->packets_out && tcp_send_head(sk);
+ return (push_one == 2) || (!tp->packets_out && tcp_send_head(sk));
+}
+
+bool tcp_schedule_loss_probe(struct sock *sk)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ u32 timeout, tlp_time_stamp, rto_time_stamp;
+ u32 rtt = tp->srtt >> 3;
+
+ if (WARN_ON(icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS))
+ return false;
+ /* No consecutive loss probes. */
+ if (WARN_ON(icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)) {
+ tcp_rearm_rto(sk);
+ return false;
+ }
+ /* Don't do any loss probe on a Fast Open connection before 3WHS
+ * finishes.
+ */
+ if (sk->sk_state == TCP_SYN_RECV)
+ return false;
+
+ /* TLP is only scheduled when next timer event is RTO. */
+ if (icsk->icsk_pending != ICSK_TIME_RETRANS)
+ return false;
+
+ /* Schedule a loss probe in 2*RTT for SACK capable connections
+ * in Open state, that are either limited by cwnd or application.
+ */
+ if (sysctl_tcp_early_retrans < 3 || !rtt || !tp->packets_out ||
+ !tcp_is_sack(tp) || inet_csk(sk)->icsk_ca_state != TCP_CA_Open)
+ return false;
+
+ if ((tp->snd_cwnd > tcp_packets_in_flight(tp)) &&
+ tcp_send_head(sk))
+ return false;
+
+ /* Probe timeout is at least 1.5*rtt + TCP_DELACK_MAX to account
+ * for delayed ack when there's one outstanding packet.
+ */
+ timeout = rtt << 1;
+ if (tp->packets_out == 1)
+ timeout = max_t(u32, timeout,
+ (rtt + (rtt >> 1) + TCP_DELACK_MAX));
+ timeout = max_t(u32, timeout, msecs_to_jiffies(10));
+
+ /* If RTO is shorter, just schedule TLP in its place. */
+ tlp_time_stamp = tcp_time_stamp + timeout;
+ rto_time_stamp = (u32)inet_csk(sk)->icsk_timeout;
+ if ((s32)(tlp_time_stamp - rto_time_stamp) > 0) {
+ s32 delta = rto_time_stamp - tcp_time_stamp;
+ if (delta > 0)
+ timeout = delta;
+ }
+
+ inet_csk_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout,
+ TCP_RTO_MAX);
+ return true;
+}
+
+/* When probe timeout (PTO) fires, send a new segment if one exists, else
+ * retransmit the last segment.
+ */
+void tcp_send_loss_probe(struct sock *sk)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct sk_buff *skb;
+ int pcount;
+ int mss = tcp_current_mss(sk);
+ int err = -1;
+
+ if (tcp_send_head(sk) != NULL) {
+ err = tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC);
+ goto rearm_timer;
+ }
+
+ /* At most one outstanding TLP retransmission. */
+ if (tp->tlp_high_seq)
+ goto rearm_timer;
+
+ /* Retransmit last segment. */
+ skb = tcp_write_queue_tail(sk);
+ if (WARN_ON(!skb))
+ goto rearm_timer;
+
+ pcount = tcp_skb_pcount(skb);
+ if (WARN_ON(!pcount))
+ goto rearm_timer;
+
+ if ((pcount > 1) && (skb->len > (pcount - 1) * mss)) {
+ if (unlikely(tcp_fragment(sk, skb, (pcount - 1) * mss, mss)))
+ goto rearm_timer;
+ skb = tcp_write_queue_tail(sk);
+ }
+
+ if (WARN_ON(!skb || !tcp_skb_pcount(skb)))
+ goto rearm_timer;
+
+ /* Probe with zero data doesn't trigger fast recovery. */
+ if (skb->len > 0)
+ err = __tcp_retransmit_skb(sk, skb);
+
+ /* Record snd_nxt for loss detection. */
+ if (likely(!err))
+ tp->tlp_high_seq = tp->snd_nxt;
+
+rearm_timer:
+ inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+ inet_csk(sk)->icsk_rto,
+ TCP_RTO_MAX);
+
+ if (likely(!err))
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPLOSSPROBES);
+ return;
}
/* Push out any pending frames which were held back due to
@@ -2388,8 +2354,12 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
*/
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- /* make sure skb->data is aligned on arches that require it */
- if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
+ /* make sure skb->data is aligned on arches that require it
+ * and check if ack-trimming & collapsing extended the headroom
+ * beyond what csum_start can cover.
+ */
+ if (unlikely((NET_IP_ALIGN && ((unsigned long)skb->data & 3)) ||
+ skb_headroom(skb) >= 0xFFFF)) {
struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
GFP_ATOMIC);
return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
@@ -2675,32 +2645,24 @@ int tcp_send_synack(struct sock *sk)
* sk: listener socket
* dst: dst entry attached to the SYNACK
* req: request_sock pointer
- * rvp: request_values pointer
*
* Allocate one skb and build a SYNACK packet.
* @dst is consumed : Caller should not use it again.
*/
struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
- struct request_values *rvp,
struct tcp_fastopen_cookie *foc)
{
struct tcp_out_options opts;
- struct tcp_extend_values *xvp = tcp_xv(rvp);
struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_sock *tp = tcp_sk(sk);
- const struct tcp_cookie_values *cvp = tp->cookie_values;
struct tcphdr *th;
struct sk_buff *skb;
struct tcp_md5sig_key *md5;
int tcp_header_size;
int mss;
- int s_data_desired = 0;
- if (cvp != NULL && cvp->s_data_constant && cvp->s_data_desired)
- s_data_desired = cvp->s_data_desired;
- skb = alloc_skb(MAX_TCP_HEADER + 15 + s_data_desired,
- sk_gfp_atomic(sk, GFP_ATOMIC));
+ skb = alloc_skb(MAX_TCP_HEADER + 15, sk_gfp_atomic(sk, GFP_ATOMIC));
if (unlikely(!skb)) {
dst_release(dst);
return NULL;
@@ -2709,6 +2671,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
skb_reserve(skb, MAX_TCP_HEADER);
skb_dst_set(skb, dst);
+ security_skb_owned_by(skb, sk);
mss = dst_metric_advmss(dst);
if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
@@ -2742,9 +2705,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
else
#endif
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_header_size = tcp_synack_options(sk, req, mss,
- skb, &opts, &md5, xvp, foc)
- + sizeof(*th);
+ tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,
+ foc) + sizeof(*th);
skb_push(skb, tcp_header_size);
skb_reset_transport_header(skb);
@@ -2762,40 +2724,6 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
TCPHDR_SYN | TCPHDR_ACK);
- if (OPTION_COOKIE_EXTENSION & opts.options) {
- if (s_data_desired) {
- u8 *buf = skb_put(skb, s_data_desired);
-
- /* copy data directly from the listening socket. */
- memcpy(buf, cvp->s_data_payload, s_data_desired);
- TCP_SKB_CB(skb)->end_seq += s_data_desired;
- }
-
- if (opts.hash_size > 0) {
- __u32 workspace[SHA_WORKSPACE_WORDS];
- u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS];
- u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1];
-
- /* Secret recipe depends on the Timestamp, (future)
- * Sequence and Acknowledgment Numbers, Initiator
- * Cookie, and others handled by IP variant caller.
- */
- *tail-- ^= opts.tsval;
- *tail-- ^= tcp_rsk(req)->rcv_isn + 1;
- *tail-- ^= TCP_SKB_CB(skb)->seq + 1;
-
- /* recommended */
- *tail-- ^= (((__force u32)th->dest << 16) | (__force u32)th->source);
- *tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */
-
- sha_transform((__u32 *)&xvp->cookie_bakery[0],
- (char *)mess,
- &workspace[0]);
- opts.hash_location =
- (__u8 *)&xvp->cookie_bakery[0];
- }
- }
-
th->seq = htonl(TCP_SKB_CB(skb)->seq);
/* XXX data is queued and acked as is. No buffer/window check */
th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index b78aac30c498..4b85e6f636c9 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -342,10 +342,6 @@ void tcp_retransmit_timer(struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
- if (tp->early_retrans_delayed) {
- tcp_resume_early_retransmit(sk);
- return;
- }
if (tp->fastopen_rsk) {
WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
sk->sk_state != TCP_FIN_WAIT1);
@@ -360,6 +356,8 @@ void tcp_retransmit_timer(struct sock *sk)
WARN_ON(tcp_write_queue_empty(sk));
+ tp->tlp_high_seq = 0;
+
if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) &&
!((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) {
/* Receiver dastardly shrinks window. Our retransmits
@@ -418,11 +416,7 @@ void tcp_retransmit_timer(struct sock *sk)
NET_INC_STATS_BH(sock_net(sk), mib_idx);
}
- if (tcp_use_frto(sk)) {
- tcp_enter_frto(sk);
- } else {
- tcp_enter_loss(sk, 0);
- }
+ tcp_enter_loss(sk, 0);
if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk)) > 0) {
/* Retransmission failed because of local congestion,
@@ -495,13 +489,20 @@ void tcp_write_timer_handler(struct sock *sk)
}
event = icsk->icsk_pending;
- icsk->icsk_pending = 0;
switch (event) {
+ case ICSK_TIME_EARLY_RETRANS:
+ tcp_resume_early_retransmit(sk);
+ break;
+ case ICSK_TIME_LOSS_PROBE:
+ tcp_send_loss_probe(sk);
+ break;
case ICSK_TIME_RETRANS:
+ icsk->icsk_pending = 0;
tcp_retransmit_timer(sk);
break;
case ICSK_TIME_PROBE0:
+ icsk->icsk_pending = 0;
tcp_probe_timer(sk);
break;
}
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
index 1b91bf48e277..76a1e23259e1 100644
--- a/net/ipv4/tcp_westwood.c
+++ b/net/ipv4/tcp_westwood.c
@@ -236,7 +236,7 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
tp->snd_cwnd = tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
break;
- case CA_EVENT_FRTO:
+ case CA_EVENT_LOSS:
tp->snd_ssthresh = tcp_westwood_bw_rttmin(sk);
/* Update RTT_min when next ack arrives */
w->reset_rtt_min = 1;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d27264318315..6abbe6455129 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -902,9 +902,9 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
ipc.addr = inet->inet_saddr;
ipc.oif = sk->sk_bound_dev_if;
- err = sock_tx_timestamp(sk, &ipc.tx_flags);
- if (err)
- return err;
+
+ sock_tx_timestamp(sk, &ipc.tx_flags);
+
if (msg->msg_controllen) {
err = ip_cmsg_send(sock_net(sk), msg, &ipc);
if (err)
@@ -1131,6 +1131,8 @@ static unsigned int first_packet_length(struct sock *sk)
spin_lock_bh(&rcvq->lock);
while ((skb = skb_peek(rcvq)) != NULL &&
udp_lib_checksum_complete(skb)) {
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS,
+ IS_UDPLITE(sk));
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
IS_UDPLITE(sk));
atomic_inc(&sk->sk_drops);
@@ -1286,8 +1288,10 @@ out:
csum_copy_err:
slow = lock_sock_fast(sk);
- if (!skb_kill_datagram(sk, skb, flags))
+ if (!skb_kill_datagram(sk, skb, flags)) {
+ UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);
UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
+ }
unlock_sock_fast(sk, slow);
if (noblock)
@@ -1513,7 +1517,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (rcu_access_pointer(sk->sk_filter) &&
udp_lib_checksum_complete(skb))
- goto drop;
+ goto csum_error;
if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf))
@@ -1533,6 +1537,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return rc;
+csum_error:
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);
drop:
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
atomic_inc(&sk->sk_drops);
@@ -1749,6 +1755,7 @@ csum_error:
proto == IPPROTO_UDPLITE ? "Lite" : "",
&saddr, ntohs(uh->source), &daddr, ntohs(uh->dest),
ulen);
+ UDP_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE);
drop:
UDP_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
kfree_skb(skb);
@@ -2279,31 +2286,88 @@ void __init udp_init(void)
int udp4_ufo_send_check(struct sk_buff *skb)
{
- const struct iphdr *iph;
- struct udphdr *uh;
-
- if (!pskb_may_pull(skb, sizeof(*uh)))
+ if (!pskb_may_pull(skb, sizeof(struct udphdr)))
return -EINVAL;
- iph = ip_hdr(skb);
- uh = udp_hdr(skb);
+ if (likely(!skb->encapsulation)) {
+ const struct iphdr *iph;
+ struct udphdr *uh;
+
+ iph = ip_hdr(skb);
+ uh = udp_hdr(skb);
- uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
- IPPROTO_UDP, 0);
- skb->csum_start = skb_transport_header(skb) - skb->head;
- skb->csum_offset = offsetof(struct udphdr, check);
- skb->ip_summed = CHECKSUM_PARTIAL;
+ uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,
+ IPPROTO_UDP, 0);
+ skb->csum_start = skb_transport_header(skb) - skb->head;
+ skb->csum_offset = offsetof(struct udphdr, check);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ }
return 0;
}
+static struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ int mac_len = skb->mac_len;
+ int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
+ int outer_hlen;
+ netdev_features_t enc_features;
+
+ if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
+ goto out;
+
+ skb->encapsulation = 0;
+ __skb_pull(skb, tnl_hlen);
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, skb_inner_network_offset(skb));
+ skb->mac_len = skb_inner_network_offset(skb);
+
+ /* segment inner packet. */
+ enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
+ segs = skb_mac_gso_segment(skb, enc_features);
+ if (!segs || IS_ERR(segs))
+ goto out;
+
+ outer_hlen = skb_tnl_header_len(skb);
+ skb = segs;
+ do {
+ struct udphdr *uh;
+ int udp_offset = outer_hlen - tnl_hlen;
+
+ skb->mac_len = mac_len;
+
+ skb_push(skb, outer_hlen);
+ skb_reset_mac_header(skb);
+ skb_set_network_header(skb, mac_len);
+ skb_set_transport_header(skb, udp_offset);
+ uh = udp_hdr(skb);
+ uh->len = htons(skb->len - udp_offset);
+
+ /* csum segment if tunnel sets skb with csum. */
+ if (unlikely(uh->check)) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+ skb->len - udp_offset,
+ IPPROTO_UDP, 0);
+ uh->check = csum_fold(skb_checksum(skb, udp_offset,
+ skb->len - udp_offset, 0));
+ if (uh->check == 0)
+ uh->check = CSUM_MANGLED_0;
+
+ }
+ skb->ip_summed = CHECKSUM_NONE;
+ } while ((skb = skb->next));
+out:
+ return segs;
+}
+
struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
unsigned int mss;
- int offset;
- __wsum csum;
-
mss = skb_shinfo(skb)->gso_size;
if (unlikely(skb->len <= mss))
goto out;
@@ -2313,6 +2377,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
int type = skb_shinfo(skb)->gso_type;
if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
+ SKB_GSO_UDP_TUNNEL |
SKB_GSO_GRE) ||
!(type & (SKB_GSO_UDP))))
goto out;
@@ -2323,20 +2388,27 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
goto out;
}
- /* Do software UFO. Complete and fill in the UDP checksum as HW cannot
- * do checksum of UDP packets sent as multiple IP fragments.
- */
- offset = skb_checksum_start_offset(skb);
- csum = skb_checksum(skb, offset, skb->len - offset, 0);
- offset += skb->csum_offset;
- *(__sum16 *)(skb->data + offset) = csum_fold(csum);
- skb->ip_summed = CHECKSUM_NONE;
-
/* Fragment the skb. IP headers of the fragments are updated in
* inet_gso_segment()
*/
- segs = skb_segment(skb, features);
+ if (skb->encapsulation && skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL)
+ segs = skb_udp_tunnel_segment(skb, features);
+ else {
+ int offset;
+ __wsum csum;
+
+ /* Do software UFO. Complete and fill in the UDP checksum as
+ * HW cannot do checksum of UDP packets sent as multiple
+ * IP fragments.
+ */
+ offset = skb_checksum_start_offset(skb);
+ csum = skb_checksum(skb, offset, skb->len - offset, 0);
+ offset += skb->csum_offset;
+ *(__sum16 *)(skb->data + offset) = csum_fold(csum);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ segs = skb_segment(skb, features);
+ }
out:
return segs;
}
-
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 505b30ad9182..7927db0a9279 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -25,7 +25,7 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
return 0;
return inet_sk_diag_fill(sk, NULL, skb, req,
- sk_user_ns(NETLINK_CB(cb->skb).ssk),
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
}
@@ -64,14 +64,14 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
goto out;
err = -ENOMEM;
- rep = alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg) +
- sizeof(struct inet_diag_meminfo) +
- 64)), GFP_KERNEL);
+ rep = nlmsg_new(sizeof(struct inet_diag_msg) +
+ sizeof(struct inet_diag_meminfo) + 64,
+ GFP_KERNEL);
if (!rep)
goto out;
err = inet_sk_diag_fill(sk, NULL, rep, req,
- sk_user_ns(NETLINK_CB(in_skb).ssk),
+ sk_user_ns(NETLINK_CB(in_skb).sk),
NETLINK_CB(in_skb).portid,
nlh->nlmsg_seq, 0, nlh);
if (err < 0) {
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index fe5189e2e114..eb1dd4d643f2 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -103,8 +103,12 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
- /* DS disclosed */
- top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos,
+ /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
+ if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
+ top_iph->tos = 0;
+ else
+ top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
+ top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
XFRM_MODE_SKB_CB(skb)->tos);
flags = x->props.flags;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ed0b9e2e797a..11b13ea69db4 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -156,6 +156,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
config IPV6_SIT
tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)"
select INET_TUNNEL
+ select NET_IP_TUNNEL
select IPV6_NDISC_NODETYPE
default y
---help---
@@ -201,6 +202,7 @@ config IPV6_TUNNEL
config IPV6_GRE
tristate "IPv6: GRE tunnel"
select IPV6_TUNNEL
+ select NET_IP_TUNNEL
---help---
Tunneling means encapsulating data of one protocol type within
another protocol and sending it over a channel that understands the
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 309af19a0a0a..9af088d2cdaa 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
-obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o
+obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 26512250e095..d1ab6ab29a55 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -70,6 +70,7 @@
#include <net/snmp.h>
#include <net/af_ieee802154.h>
+#include <net/firewire.h>
#include <net/ipv6.h>
#include <net/protocol.h>
#include <net/ndisc.h>
@@ -168,8 +169,6 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
struct net_device *dev);
-static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
-
static struct ipv6_devconf ipv6_devconf __read_mostly = {
.forwarding = 0,
.hop_limit = IPV6_DEFAULT_HOPLIMIT,
@@ -421,6 +420,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ipv6_regen_rndid((unsigned long) ndev);
}
#endif
+ ndev->token = in6addr_any;
if (netif_running(dev) && addrconf_qdisc_ok(dev))
ndev->if_flags |= IF_READY;
@@ -544,8 +544,7 @@ static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
};
static int inet6_netconf_get_devconf(struct sk_buff *in_skb,
- struct nlmsghdr *nlh,
- void *arg)
+ struct nlmsghdr *nlh)
{
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[NETCONFA_MAX+1];
@@ -605,6 +604,77 @@ errout:
return err;
}
+static int inet6_netconf_dump_devconf(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ int h, s_h;
+ int idx, s_idx;
+ struct net_device *dev;
+ struct inet6_dev *idev;
+ struct hlist_head *head;
+
+ s_h = cb->args[0];
+ s_idx = idx = cb->args[1];
+
+ for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ idx = 0;
+ head = &net->dev_index_head[h];
+ rcu_read_lock();
+ cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^
+ net->dev_base_seq;
+ hlist_for_each_entry_rcu(dev, head, index_hlist) {
+ if (idx < s_idx)
+ goto cont;
+ idev = __in6_dev_get(dev);
+ if (!idev)
+ goto cont;
+
+ if (inet6_netconf_fill_devconf(skb, dev->ifindex,
+ &idev->cnf,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF,
+ NLM_F_MULTI,
+ -1) <= 0) {
+ rcu_read_unlock();
+ goto done;
+ }
+ nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+cont:
+ idx++;
+ }
+ rcu_read_unlock();
+ }
+ if (h == NETDEV_HASHENTRIES) {
+ if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL,
+ net->ipv6.devconf_all,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF, NLM_F_MULTI,
+ -1) <= 0)
+ goto done;
+ else
+ h++;
+ }
+ if (h == NETDEV_HASHENTRIES + 1) {
+ if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT,
+ net->ipv6.devconf_dflt,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNETCONF, NLM_F_MULTI,
+ -1) <= 0)
+ goto done;
+ else
+ h++;
+ }
+done:
+ cb->args[0] = h;
+ cb->args[1] = idx;
+
+ return skb->len;
+}
+
#ifdef CONFIG_SYSCTL
static void dev_forward_change(struct inet6_dev *idev)
{
@@ -806,6 +876,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ifa->prefix_len = pfxlen;
ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies;
+ ifa->tokenized = false;
ifa->rt = rt;
@@ -837,7 +908,7 @@ out2:
rcu_read_unlock_bh();
if (likely(err == 0))
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
+ inet6addr_notifier_call_chain(NETDEV_UP, ifa);
else {
kfree(ifa);
ifa = ERR_PTR(err);
@@ -927,7 +998,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
ipv6_ifa_notify(RTM_DELADDR, ifp);
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
+ inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);
/*
* Purge or update corresponding prefix
@@ -1668,6 +1739,20 @@ static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev)
return 0;
}
+static int addrconf_ifid_ieee1394(u8 *eui, struct net_device *dev)
+{
+ union fwnet_hwaddr *ha;
+
+ if (dev->addr_len != FWNET_ALEN)
+ return -1;
+
+ ha = (union fwnet_hwaddr *)dev->dev_addr;
+
+ memcpy(eui, &ha->uc.uniq_id, sizeof(ha->uc.uniq_id));
+ eui[0] ^= 2;
+ return 0;
+}
+
static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
{
/* XXX: inherit EUI-64 from other interface -- yoshfuji */
@@ -1732,6 +1817,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
return addrconf_ifid_gre(eui, dev);
case ARPHRD_IEEE802154:
return addrconf_ifid_eui64(eui, dev);
+ case ARPHRD_IEEE1394:
+ return addrconf_ifid_ieee1394(eui, dev);
}
return -1;
}
@@ -2046,11 +2133,19 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
struct inet6_ifaddr *ifp;
struct in6_addr addr;
int create = 0, update_lft = 0;
+ bool tokenized = false;
if (pinfo->prefix_len == 64) {
memcpy(&addr, &pinfo->prefix, 8);
- if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
- ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) {
+
+ if (!ipv6_addr_any(&in6_dev->token)) {
+ read_lock_bh(&in6_dev->lock);
+ memcpy(addr.s6_addr + 8,
+ in6_dev->token.s6_addr + 8, 8);
+ read_unlock_bh(&in6_dev->lock);
+ tokenized = true;
+ } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
+ ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) {
in6_dev_put(in6_dev);
return;
}
@@ -2091,6 +2186,7 @@ ok:
update_lft = create = 1;
ifp->cstamp = jiffies;
+ ifp->tokenized = tokenized;
addrconf_dad_start(ifp);
}
@@ -2529,6 +2625,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
static void init_loopback(struct net_device *dev)
{
struct inet6_dev *idev;
+ struct net_device *sp_dev;
+ struct inet6_ifaddr *sp_ifa;
+ struct rt6_info *sp_rt;
/* ::1 */
@@ -2540,6 +2639,30 @@ static void init_loopback(struct net_device *dev)
}
add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
+
+ /* Add routes to other interface's IPv6 addresses */
+ for_each_netdev(dev_net(dev), sp_dev) {
+ if (!strcmp(sp_dev->name, dev->name))
+ continue;
+
+ idev = __in6_dev_get(sp_dev);
+ if (!idev)
+ continue;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(sp_ifa, &idev->addr_list, if_list) {
+
+ if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))
+ continue;
+
+ sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
+
+ /* Failure cases are ignored */
+ if (!IS_ERR(sp_rt))
+ ip6_ins_rt(sp_rt);
+ }
+ read_unlock_bh(&idev->lock);
+ }
}
static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
@@ -2573,7 +2696,8 @@ static void addrconf_dev_config(struct net_device *dev)
(dev->type != ARPHRD_FDDI) &&
(dev->type != ARPHRD_ARCNET) &&
(dev->type != ARPHRD_INFINIBAND) &&
- (dev->type != ARPHRD_IEEE802154)) {
+ (dev->type != ARPHRD_IEEE802154) &&
+ (dev->type != ARPHRD_IEEE1394)) {
/* Alas, we support only Ethernet autoconfiguration. */
return;
}
@@ -2961,7 +3085,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
if (state != INET6_IFADDR_STATE_DEAD) {
__ipv6_ifa_notify(RTM_DELADDR, ifa);
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+ inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
}
in6_ifa_put(ifa);
@@ -3510,7 +3634,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
};
static int
-inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifaddrmsg *ifm;
@@ -3576,7 +3700,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
}
static int
-inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifaddrmsg *ifm;
@@ -3807,6 +3931,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
NLM_F_MULTI);
if (err <= 0)
break;
+ nl_dump_check_consistent(cb, nlmsg_hdr(skb));
}
break;
}
@@ -3864,6 +3989,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
s_ip_idx = ip_idx = cb->args[2];
rcu_read_lock();
+ cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq;
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
head = &net->dev_index_head[h];
@@ -3915,8 +4041,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
return inet6_dump_addr(skb, cb, type);
}
-static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
- void *arg)
+static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(in_skb->sk);
struct ifaddrmsg *ifm;
@@ -4049,7 +4174,8 @@ static inline size_t inet6_ifla6_size(void)
+ nla_total_size(sizeof(struct ifla_cacheinfo))
+ nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
+ nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */
- + nla_total_size(ICMP6_MIB_MAX * 8); /* IFLA_INET6_ICMP6STATS */
+ + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */
+ + nla_total_size(sizeof(struct in6_addr)); /* IFLA_INET6_TOKEN */
}
static inline size_t inet6_if_nlmsg_size(void)
@@ -4136,6 +4262,13 @@ static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev)
goto nla_put_failure;
snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla));
+ nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr));
+ if (nla == NULL)
+ goto nla_put_failure;
+ read_lock_bh(&idev->lock);
+ memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla));
+ read_unlock_bh(&idev->lock);
+
return 0;
nla_put_failure:
@@ -4163,6 +4296,80 @@ static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
return 0;
}
+static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
+{
+ struct inet6_ifaddr *ifp;
+ struct net_device *dev = idev->dev;
+ bool update_rs = false;
+
+ if (token == NULL)
+ return -EINVAL;
+ if (ipv6_addr_any(token))
+ return -EINVAL;
+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP))
+ return -EINVAL;
+ if (!ipv6_accept_ra(idev))
+ return -EINVAL;
+ if (idev->cnf.rtr_solicits <= 0)
+ return -EINVAL;
+
+ write_lock_bh(&idev->lock);
+
+ BUILD_BUG_ON(sizeof(token->s6_addr) != 16);
+ memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8);
+
+ write_unlock_bh(&idev->lock);
+
+ if (!idev->dead && (idev->if_flags & IF_READY)) {
+ struct in6_addr ll_addr;
+
+ ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |
+ IFA_F_OPTIMISTIC);
+
+ /* If we're not ready, then normal ifup will take care
+ * of this. Otherwise, we need to request our rs here.
+ */
+ ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters);
+ update_rs = true;
+ }
+
+ write_lock_bh(&idev->lock);
+
+ if (update_rs)
+ idev->if_flags |= IF_RS_SENT;
+
+ /* Well, that's kinda nasty ... */
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ spin_lock(&ifp->lock);
+ if (ifp->tokenized) {
+ ifp->valid_lft = 0;
+ ifp->prefered_lft = 0;
+ }
+ spin_unlock(&ifp->lock);
+ }
+
+ write_unlock_bh(&idev->lock);
+ return 0;
+}
+
+static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
+{
+ int err = -EINVAL;
+ struct inet6_dev *idev = __in6_dev_get(dev);
+ struct nlattr *tb[IFLA_INET6_MAX + 1];
+
+ if (!idev)
+ return -EAFNOSUPPORT;
+
+ if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0)
+ BUG();
+
+ if (tb[IFLA_INET6_TOKEN])
+ err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN]));
+
+ return err;
+}
+
static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
u32 portid, u32 seq, int event, unsigned int flags)
{
@@ -4341,6 +4548,8 @@ errout:
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
+ struct net *net = dev_net(ifp->idev->dev);
+
inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
switch (event) {
@@ -4366,6 +4575,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
dst_free(&ifp->rt->dst);
break;
}
+ atomic_inc(&net->ipv6.dev_addr_genid);
}
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
@@ -4842,26 +5052,11 @@ static struct pernet_operations addrconf_ops = {
.exit = addrconf_exit_net,
};
-/*
- * Device notifier
- */
-
-int register_inet6addr_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&inet6addr_chain, nb);
-}
-EXPORT_SYMBOL(register_inet6addr_notifier);
-
-int unregister_inet6addr_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
-}
-EXPORT_SYMBOL(unregister_inet6addr_notifier);
-
static struct rtnl_af_ops inet6_ops = {
.family = AF_INET6,
.fill_link_af = inet6_fill_link_af,
.get_link_af_size = inet6_get_link_af_size,
+ .set_link_af = inet6_set_link_af,
};
/*
@@ -4934,7 +5129,7 @@ int __init addrconf_init(void)
__rtnl_register(PF_INET6, RTM_GETANYCAST, NULL,
inet6_dump_ifacaddr, NULL);
__rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf,
- NULL, NULL);
+ inet6_netconf_dump_devconf, NULL);
ipv6_addr_label_rtnl_register();
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index d051e5f4bf34..72104562c864 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -78,3 +78,22 @@ int __ipv6_addr_type(const struct in6_addr *addr)
}
EXPORT_SYMBOL(__ipv6_addr_type);
+static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
+
+int register_inet6addr_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&inet6addr_chain, nb);
+}
+EXPORT_SYMBOL(register_inet6addr_notifier);
+
+int unregister_inet6addr_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
+}
+EXPORT_SYMBOL(unregister_inet6addr_notifier);
+
+int inet6addr_notifier_call_chain(unsigned long val, void *v)
+{
+ return atomic_notifier_call_chain(&inet6addr_chain, val, v);
+}
+EXPORT_SYMBOL(inet6addr_notifier_call_chain);
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index aad64352cb60..f083a583a05c 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -414,8 +414,7 @@ static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
[IFAL_LABEL] = { .len = sizeof(u32), },
};
-static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
- void *arg)
+static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct ifaddrlblmsg *ifal;
@@ -436,10 +435,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
if (!tb[IFAL_ADDRESS])
return -EINVAL;
-
pfx = nla_data(tb[IFAL_ADDRESS]);
- if (!pfx)
- return -EINVAL;
if (!tb[IFAL_LABEL])
return -EINVAL;
@@ -533,8 +529,7 @@ static inline int ip6addrlbl_msgsize(void)
+ nla_total_size(4); /* IFAL_LABEL */
}
-static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
- void *arg)
+static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh)
{
struct net *net = sock_net(in_skb->sk);
struct ifaddrlblmsg *ifal;
@@ -561,10 +556,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
if (!tb[IFAL_ADDRESS])
return -EINVAL;
-
addr = nla_data(tb[IFAL_ADDRESS]);
- if (!addr)
- return -EINVAL;
rcu_read_lock();
p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 6b793bfc0e10..ab5c7ad482cd 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -49,7 +49,6 @@
#include <net/udp.h>
#include <net/udplite.h>
#include <net/tcp.h>
-#include <net/ipip.h>
#include <net/protocol.h>
#include <net/inet_common.h>
#include <net/route.h>
@@ -323,7 +322,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct net_device *dev = NULL;
rcu_read_lock();
- if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) {
/* Override any existing binding, if another one
@@ -471,8 +470,8 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin6_port = inet->inet_sport;
}
- if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin->sin6_scope_id = sk->sk_bound_dev_if;
+ sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr,
+ sk->sk_bound_dev_if);
*uaddr_len = sizeof(*sin);
return 0;
}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index f5a54782a340..4b56cbbc7890 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -124,7 +124,7 @@ ipv4_connected:
goto out;
}
- if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) &&
usin->sin6_scope_id) {
if (sk->sk_bound_dev_if &&
@@ -355,18 +355,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;
sin->sin6_port = serr->port;
- sin->sin6_scope_id = 0;
if (skb->protocol == htons(ETH_P_IPV6)) {
const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset),
struct ipv6hdr, daddr);
sin->sin6_addr = ip6h->daddr;
if (np->sndflow)
sin->sin6_flowinfo = ip6_flowinfo(ip6h);
- if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin->sin6_scope_id = IP6CB(skb)->iif;
+ sin->sin6_scope_id =
+ ipv6_iface_scope_id(&sin->sin6_addr,
+ IP6CB(skb)->iif);
} else {
ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
&sin->sin6_addr);
+ sin->sin6_scope_id = 0;
}
}
@@ -376,18 +377,19 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;
- sin->sin6_scope_id = 0;
if (skb->protocol == htons(ETH_P_IPV6)) {
sin->sin6_addr = ipv6_hdr(skb)->saddr;
if (np->rxopt.all)
ip6_datagram_recv_ctl(sk, msg, skb);
- if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin->sin6_scope_id = IP6CB(skb)->iif;
+ sin->sin6_scope_id =
+ ipv6_iface_scope_id(&sin->sin6_addr,
+ IP6CB(skb)->iif);
} else {
struct inet_sock *inet = inet_sk(sk);
ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
&sin->sin6_addr);
+ sin->sin6_scope_id = 0;
if (inet->cmsg_flags)
ip_cmsg_recv(msg, skb);
}
@@ -592,7 +594,9 @@ int ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
sin6.sin6_addr = ipv6_hdr(skb)->daddr;
sin6.sin6_port = ports[1];
sin6.sin6_flowinfo = 0;
- sin6.sin6_scope_id = 0;
+ sin6.sin6_scope_id =
+ ipv6_iface_scope_id(&ipv6_hdr(skb)->daddr,
+ opt->iif);
put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index fff5bdd8b680..b4ff0a42b8c7 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -124,15 +124,6 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
}
/*
- * Slightly more convenient version of icmpv6_send.
- */
-void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
-{
- icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos);
- kfree_skb(skb);
-}
-
-/*
* Figure out, may we reply to this packet with icmp error.
*
* We do not reply, if:
@@ -332,7 +323,7 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *sk
* anycast.
*/
if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n");
+ LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: acast source\n");
dst_release(dst);
return ERR_PTR(-EINVAL);
}
@@ -381,7 +372,7 @@ relookup_failed:
/*
* Send an ICMP message in response to a packet in error
*/
-void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
+static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
{
struct net *net = dev_net(skb->dev);
struct inet6_dev *idev = NULL;
@@ -406,7 +397,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
/*
* Make sure we respect the rules
* i.e. RFC 1885 2.4(e)
- * Rule (e.1) is enforced by not using icmpv6_send
+ * Rule (e.1) is enforced by not using icmp6_send
* in any code that processes icmp errors.
*/
addr_type = ipv6_addr_type(&hdr->daddr);
@@ -434,7 +425,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
* Source addr check
*/
- if (addr_type & IPV6_ADDR_LINKLOCAL)
+ if (__ipv6_addr_needs_scope_id(addr_type))
iif = skb->dev->ifindex;
/*
@@ -444,7 +435,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
* and anycast addresses will be checked later.
*/
if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");
+ LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: addr_any/mcast source\n");
return;
}
@@ -452,7 +443,7 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
* Never answer to a ICMP packet.
*/
if (is_ineligible(skb)) {
- LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: no reply to icmp error\n");
+ LIMIT_NETDEBUG(KERN_DEBUG "icmp6_send: no reply to icmp error\n");
return;
}
@@ -529,7 +520,14 @@ out_dst_release:
out:
icmpv6_xmit_unlock(sk);
}
-EXPORT_SYMBOL(icmpv6_send);
+
+/* Slightly more convenient version of icmp6_send.
+ */
+void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
+{
+ icmp6_send(skb, ICMPV6_PARAMPROB, code, pos);
+ kfree_skb(skb);
+}
static void icmpv6_echo_reply(struct sk_buff *skb)
{
@@ -701,7 +699,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
if (__skb_checksum_complete(skb)) {
LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
saddr, daddr);
- goto discard_it;
+ goto csum_error;
}
}
@@ -787,6 +785,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
kfree_skb(skb);
return 0;
+csum_error:
+ ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS);
discard_it:
ICMP6_INC_STATS_BH(dev_net(dev), idev, ICMP6_MIB_INERRORS);
drop_no_count:
@@ -885,8 +885,14 @@ int __init icmpv6_init(void)
err = -EAGAIN;
if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
goto fail;
+
+ err = inet6_register_icmp_sender(icmp6_send);
+ if (err)
+ goto sender_reg_err;
return 0;
+sender_reg_err:
+ inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
fail:
pr_err("Failed to register ICMP6 protocol\n");
unregister_pernet_subsys(&icmpv6_sk_ops);
@@ -895,6 +901,7 @@ fail:
void icmpv6_cleanup(void)
{
+ inet6_unregister_icmp_sender(icmp6_send);
unregister_pernet_subsys(&icmpv6_sk_ops);
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
}
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 9bfab19ff3c0..e4311cbc8b4e 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -54,6 +54,10 @@ int inet6_csk_bind_conflict(const struct sock *sk,
if (ipv6_rcv_saddr_equal(sk, sk2))
break;
}
+ if (!relax && reuse && sk2->sk_reuse &&
+ sk2->sk_state != TCP_LISTEN &&
+ ipv6_rcv_saddr_equal(sk, sk2))
+ break;
}
}
@@ -169,10 +173,8 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
sin6->sin6_port = inet_sk(sk)->inet_dport;
/* We do not store received flowlabel for TCP */
sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- if (sk->sk_bound_dev_if &&
- ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin6->sin6_scope_id = sk->sk_bound_dev_if;
+ sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+ sk->sk_bound_dev_if);
}
EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index b973ed3d06cf..46e88433ec7d 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -144,7 +144,9 @@ static void ip6_fl_gc(unsigned long dummy)
spin_lock(&ip6_fl_lock);
for (i=0; i<=FL_HASH_MASK; i++) {
- struct ip6_flowlabel *fl, **flp;
+ struct ip6_flowlabel *fl;
+ struct ip6_flowlabel __rcu **flp;
+
flp = &fl_ht[i];
while ((fl = rcu_dereference_protected(*flp,
lockdep_is_held(&ip6_fl_lock))) != NULL) {
@@ -179,7 +181,9 @@ static void __net_exit ip6_fl_purge(struct net *net)
spin_lock(&ip6_fl_lock);
for (i = 0; i <= FL_HASH_MASK; i++) {
- struct ip6_flowlabel *fl, **flp;
+ struct ip6_flowlabel *fl;
+ struct ip6_flowlabel __rcu **flp;
+
flp = &fl_ht[i];
while ((fl = rcu_dereference_protected(*flp,
lockdep_is_held(&ip6_fl_lock))) != NULL) {
@@ -506,7 +510,8 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_flowlabel_req freq;
struct ipv6_fl_socklist *sfl1=NULL;
- struct ipv6_fl_socklist *sfl, **sflp;
+ struct ipv6_fl_socklist *sfl;
+ struct ipv6_fl_socklist __rcu **sflp;
struct ip6_flowlabel *fl, *fl1 = NULL;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index e4efffe2522e..d3ddd8400354 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -38,6 +38,7 @@
#include <net/sock.h>
#include <net/ip.h>
+#include <net/ip_tunnels.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/addrconf.h>
@@ -110,46 +111,6 @@ static u32 HASH_ADDR(const struct in6_addr *addr)
#define tunnels_l tunnels[1]
#define tunnels_wc tunnels[0]
-static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
- tot->multicast = dev->stats.multicast;
- tot->rx_crc_errors = dev->stats.rx_crc_errors;
- tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
- tot->rx_length_errors = dev->stats.rx_length_errors;
- tot->rx_frame_errors = dev->stats.rx_frame_errors;
- tot->rx_errors = dev->stats.rx_errors;
-
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
-
- return tot;
-}
-
/* Given src, dst and key, find appropriate for input tunnel. */
static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
@@ -667,7 +628,6 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
struct net_device_stats *stats = &tunnel->dev->stats;
int err = -1;
u8 proto;
- int pkt_len;
struct sk_buff *new_skb;
if (dev->type == ARPHRD_ETHER)
@@ -801,23 +761,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
}
}
- nf_reset(skb);
- pkt_len = skb->len;
- err = ip6_local_out(skb);
-
- if (net_xmit_eval(err) == 0) {
- struct pcpu_tstats *tstats = this_cpu_ptr(tunnel->dev->tstats);
-
- tstats->tx_bytes += pkt_len;
- tstats->tx_packets++;
- } else {
- stats->tx_errors++;
- stats->tx_aborted_errors++;
- }
-
+ ip6tunnel_xmit(skb, dev);
if (ndst)
ip6_tnl_dst_store(tunnel, ndst);
-
return 0;
tx_err_link_failure:
stats->tx_carrier_errors++;
@@ -1271,7 +1217,7 @@ static const struct net_device_ops ip6gre_netdev_ops = {
.ndo_start_xmit = ip6gre_tunnel_xmit,
.ndo_do_ioctl = ip6gre_tunnel_ioctl,
.ndo_change_mtu = ip6gre_tunnel_change_mtu,
- .ndo_get_stats64 = ip6gre_get_stats64,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
static void ip6gre_dev_free(struct net_device *dev)
@@ -1520,7 +1466,7 @@ static const struct net_device_ops ip6gre_tap_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = ip6gre_tunnel_change_mtu,
- .ndo_get_stats64 = ip6gre_get_stats64,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
static void ip6gre_tap_setup(struct net_device *dev)
diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c
new file mode 100644
index 000000000000..4578e23834f7
--- /dev/null
+++ b/net/ipv6/ip6_icmp.c
@@ -0,0 +1,47 @@
+#include <linux/export.h>
+#include <linux/icmpv6.h>
+#include <linux/mutex.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+#include <net/ipv6.h>
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+static ip6_icmp_send_t __rcu *ip6_icmp_send;
+
+int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
+{
+ return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
+ 0 : -EBUSY;
+}
+EXPORT_SYMBOL(inet6_register_icmp_sender);
+
+int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn)
+{
+ int ret;
+
+ ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ?
+ 0 : -EINVAL;
+
+ synchronize_net();
+
+ return ret;
+}
+EXPORT_SYMBOL(inet6_unregister_icmp_sender);
+
+void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
+{
+ ip6_icmp_send_t *send;
+
+ rcu_read_lock();
+ send = rcu_dereference(ip6_icmp_send);
+
+ if (!send)
+ goto out;
+ send(skb, type, code, info);
+out:
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(icmpv6_send);
+#endif
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index e33fe0ab2568..2bab2aa59745 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -118,6 +118,18 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
ipv6_addr_loopback(&hdr->daddr))
goto err;
+ /* RFC4291 Errata ID: 3480
+ * Interface-Local scope spans only a single interface on a
+ * node and is useful only for loopback transmission of
+ * multicast. Packets with interface-local scope received
+ * from another node must be discarded.
+ */
+ if (!(skb->pkt_type == PACKET_LOOPBACK ||
+ dev->flags & IFF_LOOPBACK) &&
+ ipv6_addr_is_multicast(&hdr->daddr) &&
+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1)
+ goto err;
+
/* RFC4291 2.7
* Nodes must not originate a packet to a multicast address whose scope
* field contains the reserved value 0; if such a packet is received, it
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 8234c1dcdf72..71b766ee821d 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -92,14 +92,12 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
u8 *prevhdr;
int offset = 0;
- if (!(features & NETIF_F_V6_CSUM))
- features &= ~NETIF_F_SG;
-
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_UDP |
SKB_GSO_DODGY |
SKB_GSO_TCP_ECN |
SKB_GSO_GRE |
+ SKB_GSO_UDP_TUNNEL |
SKB_GSO_TCPV6 |
0)))
goto out;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 155eccfa7760..d2eedf192330 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1224,11 +1224,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
}
/* For UDP, check if TX timestamp is enabled */
- if (sk->sk_type == SOCK_DGRAM) {
- err = sock_tx_timestamp(sk, &tx_flags);
- if (err)
- goto error;
- }
+ if (sk->sk_type == SOCK_DGRAM)
+ sock_tx_timestamp(sk, &tx_flags);
/*
* Let's try using as much space as possible.
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index fff83cbc197f..1e55866cead7 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -47,6 +47,7 @@
#include <net/icmp.h>
#include <net/ip.h>
+#include <net/ip_tunnels.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
@@ -955,7 +956,6 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
unsigned int max_headroom = sizeof(struct ipv6hdr);
u8 proto;
int err = -1;
- int pkt_len;
if (!fl6->flowi6_mark)
dst = ip6_tnl_dst_check(t);
@@ -1035,19 +1035,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
ipv6h->nexthdr = proto;
ipv6h->saddr = fl6->saddr;
ipv6h->daddr = fl6->daddr;
- nf_reset(skb);
- pkt_len = skb->len;
- err = ip6_local_out(skb);
-
- if (net_xmit_eval(err) == 0) {
- struct pcpu_tstats *tstats = this_cpu_ptr(t->dev->tstats);
-
- tstats->tx_bytes += pkt_len;
- tstats->tx_packets++;
- } else {
- stats->tx_errors++;
- stats->tx_aborted_errors++;
- }
+ ip6tunnel_xmit(skb, dev);
if (ndst)
ip6_tnl_dst_store(t, ndst);
return 0;
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 96bfb4e4b820..241fb8ad9fcf 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -842,9 +842,9 @@ static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
if (ipv6_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
nlh->nlmsg_type = NLMSG_ERROR;
- nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
+ ((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT;
rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
} else
kfree_skb(skb);
@@ -1100,13 +1100,13 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
if (ipv6_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
- if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
+ if (__ip6mr_fill_mroute(mrt, skb, c, nlmsg_data(nlh)) > 0) {
nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
} else {
nlh->nlmsg_type = NLMSG_ERROR;
- nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
+ nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
+ ((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE;
}
rtnl_unicast(skb, net, NETLINK_CB(skb).portid);
} else
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 76ef4353d518..2712ab22a174 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -610,8 +610,6 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
}
}
#endif
- if (!dev->addr_len)
- send_sllao = 0;
if (send_sllao)
optlen += ndisc_opt_addr_space(dev);
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 429089cb073d..72836f40b730 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -1,3 +1,9 @@
+/*
+ * IPv6 specific functions of netfilter core
+ *
+ * Rusty Russell (C) 2000 -- This code is GPL.
+ * Patrick McHardy (C) 2006-2012
+ */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ipv6.h>
@@ -29,7 +35,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
dst_release(dst);
- return -EINVAL;
+ return dst->error;
}
/* Drop old route. */
@@ -43,7 +49,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
skb_dst_set(skb, NULL);
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0);
if (IS_ERR(dst))
- return -1;
+ return PTR_ERR(dst);
skb_dst_set(skb, dst);
}
#endif
@@ -53,7 +59,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
0, GFP_ATOMIC))
- return -1;
+ return -ENOMEM;
return 0;
}
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index c72532a60d88..4433ab40e7de 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -105,7 +105,7 @@ config IP6_NF_MATCH_MH
config IP6_NF_MATCH_RPFILTER
tristate '"rpfilter" reverse path filter match support'
- depends on NETFILTER_ADVANCED
+ depends on NETFILTER_ADVANCED && (IP6_NF_MANGLE || IP6_NF_RAW)
---help---
This option allows you to match packets whose replies would
go out via the interface the packet came in.
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 341b54ade72c..44400c216dc6 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
* Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
+ * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -284,6 +285,7 @@ static void trace_packet(const struct sk_buff *skb,
const char *hookname, *chainname, *comment;
const struct ip6t_entry *iter;
unsigned int rulenum = 0;
+ struct net *net = dev_net(in ? in : out);
table_base = private->entries[smp_processor_id()];
root = get_entry(table_base, private->hook_entry[hook]);
@@ -296,7 +298,7 @@ static void trace_packet(const struct sk_buff *skb,
&chainname, &comment, &rulenum) != 0)
break;
- nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
+ nf_log_packet(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
"TRACE: %s:%s:%s:%u ",
tablename, chainname, comment, rulenum);
}
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
index 33608c610276..590f767db5d4 100644
--- a/net/ipv6/netfilter/ip6t_NPT.c
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -18,9 +18,8 @@
static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
{
struct ip6t_npt_tginfo *npt = par->targinfo;
- __wsum src_sum = 0, dst_sum = 0;
struct in6_addr pfx;
- unsigned int i;
+ __wsum src_sum, dst_sum;
if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
return -EINVAL;
@@ -33,12 +32,8 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6))
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) {
- src_sum = csum_add(src_sum,
- (__force __wsum)npt->src_pfx.in6.s6_addr16[i]);
- dst_sum = csum_add(dst_sum,
- (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]);
- }
+ src_sum = csum_partial(&npt->src_pfx.in6, sizeof(npt->src_pfx.in6), 0);
+ dst_sum = csum_partial(&npt->dst_pfx.in6, sizeof(npt->dst_pfx.in6), 0);
npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum));
return 0;
@@ -57,7 +52,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
if (pfx_len - i >= 32)
mask = 0;
else
- mask = htonl(~((1 << (pfx_len - i)) - 1));
+ mask = htonl((1 << (i - pfx_len + 32)) - 1);
idx = i / 32;
addr->s6_addr32[idx] &= mask;
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index ed3b427b2841..70f9abc0efe9 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -7,6 +7,8 @@
* Authors:
* Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
*
+ * Copyright (c) 2005-2007 Patrick McHardy <kaber@trash.net>
+ *
* Based on net/ipv4/netfilter/ipt_REJECT.c
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
index 5060d54199ab..e0983f3648a6 100644
--- a/net/ipv6/netfilter/ip6t_rpfilter.c
+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
@@ -71,6 +71,12 @@ static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
return ret;
}
+static bool rpfilter_is_local(const struct sk_buff *skb)
+{
+ const struct rt6_info *rt = (const void *) skb_dst(skb);
+ return rt && (rt->rt6i_flags & RTF_LOCAL);
+}
+
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_rpfilter_info *info = par->matchinfo;
@@ -78,7 +84,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
struct ipv6hdr *iph;
bool invert = info->flags & XT_RPFILTER_INVERT;
- if (par->in->flags & IFF_LOOPBACK)
+ if (rpfilter_is_local(skb))
return true ^ invert;
iph = ipv6_hdr(skb);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index 6134a1ebfb1b..e075399d8b72 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -38,7 +38,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
struct in6_addr saddr, daddr;
u_int8_t hop_limit;
u_int32_t flowlabel, mark;
-
+ int err;
#if 0
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
@@ -65,8 +65,11 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) ||
skb->mark != mark ||
ipv6_hdr(skb)->hop_limit != hop_limit ||
- flowlabel != *((u_int32_t *)ipv6_hdr(skb))))
- return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP;
+ flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) {
+ err = ip6_route_me_harder(skb);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
return ret;
}
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c
index e0e788d25b14..6383f90efda8 100644
--- a/net/ipv6/netfilter/ip6table_nat.c
+++ b/net/ipv6/netfilter/ip6table_nat.c
@@ -179,6 +179,7 @@ nf_nat_ipv6_out(unsigned int hooknum,
#ifdef CONFIG_XFRM
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
+ int err;
#endif
unsigned int ret;
@@ -197,9 +198,11 @@ nf_nat_ipv6_out(unsigned int hooknum,
&ct->tuplehash[!dir].tuple.dst.u3) ||
(ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
ct->tuplehash[dir].tuple.src.u.all !=
- ct->tuplehash[!dir].tuple.dst.u.all))
- if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
- ret = NF_DROP;
+ ct->tuplehash[!dir].tuple.dst.u.all)) {
+ err = nf_xfrm_me_harder(skb, AF_INET6);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
}
#endif
return ret;
@@ -215,6 +218,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned int ret;
+ int err;
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr))
@@ -227,16 +231,19 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
&ct->tuplehash[!dir].tuple.src.u3)) {
- if (ip6_route_me_harder(skb))
- ret = NF_DROP;
+ err = ip6_route_me_harder(skb);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
}
#ifdef CONFIG_XFRM
else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 &&
ct->tuplehash[dir].tuple.dst.u.all !=
- ct->tuplehash[!dir].tuple.src.u.all)
- if (nf_xfrm_me_harder(skb, AF_INET6))
- ret = NF_DROP;
+ ct->tuplehash[!dir].tuple.src.u.all) {
+ err = nf_xfrm_me_harder(skb, AF_INET6);
+ if (err < 0)
+ ret = NF_DROP_ERR(err);
+ }
#endif
}
return ret;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 2b6c226f5198..97bcf2bae857 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -330,12 +330,8 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
sizeof(sin6.sin6_addr));
nf_ct_put(ct);
-
- if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin6.sin6_scope_id = sk->sk_bound_dev_if;
- else
- sin6.sin6_scope_id = 0;
-
+ sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
+ sk->sk_bound_dev_if);
return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 24df3dde0076..b3807c5cb888 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -131,7 +131,8 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
type + 128);
nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple);
if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6))
- nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(nf_ct_net(ct), PF_INET6, 0, skb, NULL,
+ NULL, NULL,
"nf_ct_icmpv6: invalid new with type %d ",
type + 128);
return false;
@@ -203,7 +204,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
if (icmp6h == NULL) {
if (LOG_INVALID(net, IPPROTO_ICMPV6))
- nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL,
"nf_ct_icmpv6: short packet ");
return -NF_ACCEPT;
}
@@ -211,7 +212,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
if (LOG_INVALID(net, IPPROTO_ICMPV6))
- nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL,
"nf_ct_icmpv6: ICMPv6 checksum failed ");
return -NF_ACCEPT;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 6700069949dd..dffdc1a389c5 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -41,6 +41,7 @@
#include <net/rawv6.h>
#include <net/ndisc.h>
#include <net/addrconf.h>
+#include <net/inet_ecn.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
#include <linux/sysctl.h>
#include <linux/netfilter.h>
@@ -138,6 +139,11 @@ static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
}
#endif
+static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
+{
+ return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
+}
+
static unsigned int nf_hashfn(struct inet_frag_queue *q)
{
const struct frag_queue *nq;
@@ -166,7 +172,7 @@ static void nf_ct_frag6_expire(unsigned long data)
/* Creation primitives. */
static inline struct frag_queue *fq_find(struct net *net, __be32 id,
u32 user, struct in6_addr *src,
- struct in6_addr *dst)
+ struct in6_addr *dst, u8 ecn)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -176,6 +182,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
arg.user = user;
arg.src = src;
arg.dst = dst;
+ arg.ecn = ecn;
read_lock_bh(&nf_frags.lock);
hash = inet6_hash_frag(id, src, dst, nf_frags.rnd);
@@ -196,6 +203,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
struct sk_buff *prev, *next;
unsigned int payload_len;
int offset, end;
+ u8 ecn;
if (fq->q.last_in & INET_FRAG_COMPLETE) {
pr_debug("Already completed\n");
@@ -213,6 +221,8 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
return -1;
}
+ ecn = ip6_frag_ecn(ipv6_hdr(skb));
+
if (skb->ip_summed == CHECKSUM_COMPLETE) {
const unsigned char *nh = skb_network_header(skb);
skb->csum = csum_sub(skb->csum,
@@ -317,6 +327,7 @@ found:
}
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
+ fq->ecn |= ecn;
if (payload_len > fq->q.max_size)
fq->q.max_size = payload_len;
add_frag_mem_limit(&fq->q, skb->truesize);
@@ -352,12 +363,17 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
{
struct sk_buff *fp, *op, *head = fq->q.fragments;
int payload_len;
+ u8 ecn;
inet_frag_kill(&fq->q, &nf_frags);
WARN_ON(head == NULL);
WARN_ON(NFCT_FRAG6_CB(head)->offset != 0);
+ ecn = ip_frag_ecn_table[fq->ecn];
+ if (unlikely(ecn == 0xff))
+ goto out_fail;
+
/* Unfragmented part is taken from the first segment. */
payload_len = ((head->data - skb_network_header(head)) -
sizeof(struct ipv6hdr) + fq->q.len -
@@ -428,6 +444,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
head->dev = dev;
head->tstamp = fq->q.stamp;
ipv6_hdr(head)->payload_len = htons(payload_len);
+ ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn);
IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size;
/* Yes, and fold redundant checksum back. 8) */
@@ -572,7 +589,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
inet_frag_evictor(&net->nf_frag.frags, &nf_frags, false);
local_bh_enable();
- fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
+ fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
+ ip6_frag_ecn(hdr));
if (fq == NULL) {
pr_debug("Can't find and can't create new queue\n");
goto ret_orig;
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 537d9ee7209f..f3c1ff4357ff 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -90,6 +90,7 @@ static const struct snmp_mib snmp6_ipstats_list[] = {
SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS),
SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS),
SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS),
+ SNMP_MIB_ITEM("InCsumErrors", IPSTATS_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -99,6 +100,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS),
SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
+ SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -129,6 +131,7 @@ static const struct snmp_mib snmp6_udp6_list[] = {
SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS),
+ SNMP_MIB_ITEM("Udp6InCsumErrors", UDP_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
@@ -139,6 +142,7 @@ static const struct snmp_mib snmp6_udplite6_list[] = {
SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS),
SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS),
+ SNMP_MIB_ITEM("UdpLite6InCsumErrors", UDP_MIB_CSUMERRORS),
SNMP_MIB_SENTINEL
};
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 330b5e7b7df6..eedff8ccded5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -263,7 +263,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (addr_type != IPV6_ADDR_ANY) {
struct net_device *dev = NULL;
- if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (__ipv6_addr_needs_scope_id(addr_type)) {
if (addr_len >= sizeof(struct sockaddr_in6) &&
addr->sin6_scope_id) {
/* Override any existing binding, if another
@@ -498,9 +498,8 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
sin6->sin6_port = 0;
sin6->sin6_addr = ipv6_hdr(skb)->saddr;
sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin6->sin6_scope_id = IP6CB(skb)->iif;
+ sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
+ IP6CB(skb)->iif);
}
sock_recv_ts_and_drops(msg, sk, skb);
@@ -802,7 +801,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (addr_len >= sizeof(struct sockaddr_in6) &&
sin6->sin6_scope_id &&
- ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
fl6.flowi6_oif = sin6->sin6_scope_id;
} else {
if (sk->sk_state != TCP_ESTABLISHED)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 196ab9347ad1..790d9f4b8b0b 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -58,6 +58,7 @@
#include <net/ndisc.h>
#include <net/addrconf.h>
#include <net/inet_frag.h>
+#include <net/inet_ecn.h>
struct ip6frag_skb_cb
{
@@ -67,6 +68,10 @@ struct ip6frag_skb_cb
#define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb))
+static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
+{
+ return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK);
+}
static struct inet_frags ip6_frags;
@@ -119,6 +124,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)
fq->user = arg->user;
fq->saddr = *arg->src;
fq->daddr = *arg->dst;
+ fq->ecn = arg->ecn;
}
EXPORT_SYMBOL(ip6_frag_init);
@@ -173,7 +179,8 @@ static void ip6_frag_expire(unsigned long data)
}
static __inline__ struct frag_queue *
-fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst)
+fq_find(struct net *net, __be32 id, const struct in6_addr *src,
+ const struct in6_addr *dst, u8 ecn)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -183,6 +190,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6
arg.user = IP6_DEFRAG_LOCAL_DELIVER;
arg.src = src;
arg.dst = dst;
+ arg.ecn = ecn;
read_lock(&ip6_frags.lock);
hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd);
@@ -202,6 +210,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
struct net_device *dev;
int offset, end;
struct net *net = dev_net(skb_dst(skb)->dev);
+ u8 ecn;
if (fq->q.last_in & INET_FRAG_COMPLETE)
goto err;
@@ -219,6 +228,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
return -1;
}
+ ecn = ip6_frag_ecn(ipv6_hdr(skb));
+
if (skb->ip_summed == CHECKSUM_COMPLETE) {
const unsigned char *nh = skb_network_header(skb);
skb->csum = csum_sub(skb->csum,
@@ -319,6 +330,7 @@ found:
}
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
+ fq->ecn |= ecn;
add_frag_mem_limit(&fq->q, skb->truesize);
/* The first fragment.
@@ -330,9 +342,17 @@ found:
}
if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
- fq->q.meat == fq->q.len)
- return ip6_frag_reasm(fq, prev, dev);
+ fq->q.meat == fq->q.len) {
+ int res;
+ unsigned long orefdst = skb->_skb_refdst;
+
+ skb->_skb_refdst = 0UL;
+ res = ip6_frag_reasm(fq, prev, dev);
+ skb->_skb_refdst = orefdst;
+ return res;
+ }
+ skb_dst_drop(skb);
inet_frag_lru_move(&fq->q);
return -1;
@@ -362,9 +382,14 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
int payload_len;
unsigned int nhoff;
int sum_truesize;
+ u8 ecn;
inet_frag_kill(&fq->q, &ip6_frags);
+ ecn = ip_frag_ecn_table[fq->ecn];
+ if (unlikely(ecn == 0xff))
+ goto out_fail;
+
/* Make the one we just received the head. */
if (prev) {
head = prev->next;
@@ -463,6 +488,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
head->dev = dev;
head->tstamp = fq->q.stamp;
ipv6_hdr(head)->payload_len = htons(payload_len);
+ ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn);
IP6CB(head)->nhoff = nhoff;
/* Yes, and fold redundant checksum back. 8) */
@@ -526,7 +552,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),
IPSTATS_MIB_REASMFAILS, evicted);
- fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr);
+ fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
+ ip6_frag_ecn(hdr));
if (fq != NULL) {
int ret;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e5fe0041adfa..ad0aa6b0b86a 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2355,7 +2355,7 @@ beginning:
return last_err;
}
-static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
{
struct fib6_config cfg;
int err;
@@ -2370,7 +2370,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a
return ip6_route_del(&cfg);
}
-static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh)
{
struct fib6_config cfg;
int err;
@@ -2562,7 +2562,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
prefix, 0, NLM_F_MULTI);
}
-static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
+static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh)
{
struct net *net = sock_net(in_skb->sk);
struct nlattr *tb[RTA_MAX+1];
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 02f96dcbcf02..335363478bbf 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -49,7 +49,7 @@
#include <net/ip.h>
#include <net/udp.h>
#include <net/icmp.h>
-#include <net/ipip.h>
+#include <net/ip_tunnels.h>
#include <net/inet_ecn.h>
#include <net/xfrm.h>
#include <net/dsfield.h>
@@ -87,41 +87,6 @@ struct sit_net {
struct net_device *fb_tunnel_dev;
};
-static struct rtnl_link_stats64 *ipip6_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *tot)
-{
- int i;
-
- for_each_possible_cpu(i) {
- const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
- u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
- unsigned int start;
-
- do {
- start = u64_stats_fetch_begin_bh(&tstats->syncp);
- rx_packets = tstats->rx_packets;
- tx_packets = tstats->tx_packets;
- rx_bytes = tstats->rx_bytes;
- tx_bytes = tstats->tx_bytes;
- } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
- tot->rx_packets += rx_packets;
- tot->tx_packets += tx_packets;
- tot->rx_bytes += rx_bytes;
- tot->tx_bytes += tx_bytes;
- }
-
- tot->rx_errors = dev->stats.rx_errors;
- tot->rx_frame_errors = dev->stats.rx_frame_errors;
- tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
- tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
- tot->tx_dropped = dev->stats.tx_dropped;
- tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
- tot->tx_errors = dev->stats.tx_errors;
-
- return tot;
-}
-
/*
* Must be invoked with rcu_read_lock
*/
@@ -899,6 +864,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
if ((iph->ttl = tiph->ttl) == 0)
iph->ttl = iph6->hop_limit;
+ skb->ip_summed = CHECKSUM_NONE;
+ ip_select_ident(iph, skb_dst(skb), NULL);
iptunnel_xmit(skb, dev);
return NETDEV_TX_OK;
@@ -1200,7 +1167,7 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_start_xmit = ipip6_tunnel_xmit,
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_change_mtu = ipip6_tunnel_change_mtu,
- .ndo_get_stats64= ipip6_get_stats64,
+ .ndo_get_stats64 = ip_tunnel_get_stats64,
};
static void ipip6_dev_free(struct net_device *dev)
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 8a0848b60b35..d5dda20bd717 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -149,7 +149,6 @@ static inline int cookie_check(const struct sk_buff *skb, __u32 cookie)
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
{
struct tcp_options_received tcp_opt;
- const u8 *hash_location;
struct inet_request_sock *ireq;
struct inet6_request_sock *ireq6;
struct tcp_request_sock *treq;
@@ -177,7 +176,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
/* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt));
- tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
+ tcp_parse_options(skb, &tcp_opt, 0, NULL);
if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
goto out;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f6d629fd6aee..71167069b394 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -386,6 +386,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
if (dst)
dst->ops->redirect(dst, sk, skb);
+ goto out;
}
if (type == ICMPV6_PKT_TOOBIG) {
@@ -461,7 +462,6 @@ out:
static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
struct flowi6 *fl6,
struct request_sock *req,
- struct request_values *rvp,
u16 queue_mapping)
{
struct inet6_request_sock *treq = inet6_rsk(req);
@@ -473,7 +473,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
goto done;
- skb = tcp_make_synack(sk, dst, req, rvp, NULL);
+ skb = tcp_make_synack(sk, dst, req, NULL);
if (skb) {
__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
@@ -488,13 +488,12 @@ done:
return err;
}
-static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
- struct request_values *rvp)
+static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
{
struct flowi6 fl6;
int res;
- res = tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0);
+ res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
if (!res)
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
return res;
@@ -947,9 +946,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
*/
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{
- struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt;
- const u8 *hash_location;
struct request_sock *req;
struct inet6_request_sock *treq;
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -987,50 +984,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
tmp_opt.user_mss = tp->rx_opt.user_mss;
- tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
-
- if (tmp_opt.cookie_plus > 0 &&
- tmp_opt.saw_tstamp &&
- !tp->rx_opt.cookie_out_never &&
- (sysctl_tcp_cookie_size > 0 ||
- (tp->cookie_values != NULL &&
- tp->cookie_values->cookie_desired > 0))) {
- u8 *c;
- u32 *d;
- u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
- int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
-
- if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
- goto drop_and_free;
-
- /* Secret recipe starts with IP addresses */
- d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
- *mess++ ^= *d++;
- *mess++ ^= *d++;
- *mess++ ^= *d++;
- *mess++ ^= *d++;
- d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
- *mess++ ^= *d++;
- *mess++ ^= *d++;
- *mess++ ^= *d++;
- *mess++ ^= *d++;
-
- /* plus variable length Initiator Cookie */
- c = (u8 *)mess;
- while (l-- > 0)
- *c++ ^= *hash_location++;
-
- want_cookie = false; /* not our kind of cookie */
- tmp_ext.cookie_out_never = 0; /* false */
- tmp_ext.cookie_plus = tmp_opt.cookie_plus;
- } else if (!tp->rx_opt.cookie_in_always) {
- /* redundant indications, but ensure initialization. */
- tmp_ext.cookie_out_never = 1; /* true */
- tmp_ext.cookie_plus = 0;
- } else {
- goto drop_and_free;
- }
- tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
+ tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt);
@@ -1108,7 +1062,6 @@ have_isn:
goto drop_and_release;
if (tcp_v6_send_synack(sk, dst, &fl6, req,
- (struct request_values *)&tmp_ext,
skb_get_queue_mapping(skb)) ||
want_cookie)
goto drop_and_free;
@@ -1452,6 +1405,7 @@ discard:
kfree_skb(skb);
return 0;
csum_err:
+ TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS);
goto discard;
@@ -1513,7 +1467,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
goto discard_it;
if (!skb_csum_unnecessary(skb) && tcp_v6_checksum_init(skb))
- goto bad_packet;
+ goto csum_error;
th = tcp_hdr(skb);
hdr = ipv6_hdr(skb);
@@ -1577,6 +1531,8 @@ no_tcp_socket:
goto discard_it;
if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+csum_error:
+ TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);
bad_packet:
TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
} else {
@@ -1584,11 +1540,6 @@ bad_packet:
}
discard_it:
-
- /*
- * Discard frame
- */
-
kfree_skb(skb);
return 0;
@@ -1602,10 +1553,13 @@ do_time_wait:
goto discard_it;
}
- if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
- TCP_INC_STATS_BH(net, TCP_MIB_INERRS);
+ if (skb->len < (th->doff<<2)) {
inet_twsk_put(inet_twsk(sk));
- goto discard_it;
+ goto bad_packet;
+ }
+ if (tcp_checksum_complete(skb)) {
+ inet_twsk_put(inet_twsk(sk));
+ goto csum_error;
}
switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d8e5e852fc7a..d4defdd44937 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -450,15 +450,16 @@ try_again:
sin6->sin6_family = AF_INET6;
sin6->sin6_port = udp_hdr(skb)->source;
sin6->sin6_flowinfo = 0;
- sin6->sin6_scope_id = 0;
- if (is_udp4)
+ if (is_udp4) {
ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
&sin6->sin6_addr);
- else {
+ sin6->sin6_scope_id = 0;
+ } else {
sin6->sin6_addr = ipv6_hdr(skb)->saddr;
- if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
- sin6->sin6_scope_id = IP6CB(skb)->iif;
+ sin6->sin6_scope_id =
+ ipv6_iface_scope_id(&sin6->sin6_addr,
+ IP6CB(skb)->iif);
}
}
@@ -482,12 +483,17 @@ out:
csum_copy_err:
slow = lock_sock_fast(sk);
if (!skb_kill_datagram(sk, skb, flags)) {
- if (is_udp4)
+ if (is_udp4) {
+ UDP_INC_STATS_USER(sock_net(sk),
+ UDP_MIB_CSUMERRORS, is_udplite);
UDP_INC_STATS_USER(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
- else
+ } else {
+ UDP6_INC_STATS_USER(sock_net(sk),
+ UDP_MIB_CSUMERRORS, is_udplite);
UDP6_INC_STATS_USER(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
+ }
}
unlock_sock_fast(sk, slow);
@@ -636,7 +642,7 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (rcu_access_pointer(sk->sk_filter)) {
if (udp_lib_checksum_complete(skb))
- goto drop;
+ goto csum_error;
}
if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf))
@@ -655,6 +661,8 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
bh_unlock_sock(sk);
return rc;
+csum_error:
+ UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite);
drop:
UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
atomic_inc(&sk->sk_drops);
@@ -816,7 +824,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
}
if (udp6_csum_init(skb, uh, proto))
- goto discard;
+ goto csum_error;
/*
* Multicast receive code
@@ -849,7 +857,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
goto discard;
if (udp_lib_checksum_complete(skb))
- goto discard;
+ goto csum_error;
UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE);
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
@@ -866,7 +874,9 @@ short_packet:
skb->len,
daddr,
ntohs(uh->dest));
-
+ goto discard;
+csum_error:
+ UDP6_INC_STATS_BH(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE);
discard:
UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
kfree_skb(skb);
@@ -1118,7 +1128,7 @@ do_udp_sendmsg:
if (addr_len >= sizeof(struct sockaddr_in6) &&
sin6->sin6_scope_id &&
- ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr)))
fl6.flowi6_oif = sin6->sin6_scope_id;
} else {
if (sk->sk_state != TCP_ESTABLISHED)
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index cf05cf073c51..3bb3a891a424 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -21,6 +21,10 @@ static int udp6_ufo_send_check(struct sk_buff *skb)
const struct ipv6hdr *ipv6h;
struct udphdr *uh;
+ /* UDP Tunnel offload on ipv6 is not yet supported. */
+ if (skb->encapsulation)
+ return -EINVAL;
+
if (!pskb_may_pull(skb, sizeof(*uh)))
return -EINVAL;
@@ -56,7 +60,9 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
/* Packet is from an untrusted source, reset gso_segs. */
int type = skb_shinfo(skb)->gso_type;
- if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
+ if (unlikely(type & ~(SKB_GSO_UDP |
+ SKB_GSO_DODGY |
+ SKB_GSO_UDP_TUNNEL |
SKB_GSO_GRE) ||
!(type & (SKB_GSO_UDP))))
goto out;
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 9bf6a74a71d2..4770d515c2c8 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -49,8 +49,11 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
sizeof(top_iph->flow_lbl));
top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family);
- dsfield = XFRM_MODE_SKB_CB(skb)->tos;
- dsfield = INET_ECN_encapsulate(dsfield, dsfield);
+ if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
+ dsfield = 0;
+ else
+ dsfield = XFRM_MODE_SKB_CB(skb)->tos;
+ dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos);
if (x->props.flags & XFRM_STATE_NOECN)
dsfield &= ~INET_ECN_MASK;
ipv6_change_dsfield(top_iph, 0, dsfield);
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index d28e7f014cc6..0578d4fa00a9 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -305,8 +305,7 @@ static void irda_connect_response(struct irda_sock *self)
IRDA_DEBUG(2, "%s()\n", __func__);
- skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
- GFP_ATOMIC);
+ skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_KERNEL);
if (skb == NULL) {
IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
__func__);
@@ -1120,7 +1119,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol,
}
/* Allocate networking socket */
- sk = sk_alloc(net, PF_IRDA, GFP_ATOMIC, &irda_proto);
+ sk = sk_alloc(net, PF_IRDA, GFP_KERNEL, &irda_proto);
if (sk == NULL)
return -ENOMEM;
@@ -1386,6 +1385,8 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __func__);
+ msg->msg_namelen = 0;
+
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
if (!skb)
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index 52079f19bbbe..b797daac063c 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -117,7 +117,7 @@ struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
IRDA_ASSERT(ircomm != NULL, return NULL;);
- self = kzalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
+ self = kzalloc(sizeof(struct ircomm_cb), GFP_KERNEL);
if (self == NULL)
return NULL;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 362ba47968e4..41ac7938268b 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -328,7 +328,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
spin_unlock_irqrestore(&port->lock, flags);
while (1) {
- if (tty->termios.c_cflag & CBAUD)
+ if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index edab393e0c82..a2a508f5f268 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -997,12 +997,8 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
self->settings.dce = IRCOMM_DELTA_CD;
ircomm_tty_check_modem_status(self);
} else {
- struct tty_struct *tty = tty_port_tty_get(&self->port);
IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
+ tty_port_tty_hangup(&self->port, false);
}
break;
default:
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 29340a9a6fb9..e1b37f5a2691 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -303,7 +303,8 @@ static void iriap_disconnect_indication(void *instance, void *sap,
{
struct iriap_cb *self;
- IRDA_DEBUG(4, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
+ IRDA_DEBUG(4, "%s(), reason=%s [%d]\n", __func__,
+ irlmp_reason_str(reason), reason);
self = instance;
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 6115a44c0a24..98ad6ec4bd3c 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -58,7 +58,7 @@ int sysctl_discovery_slots = 6; /* 6 slots by default */
int sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;
char sysctl_devname[65];
-const char *irlmp_reasons[] = {
+static const char *irlmp_reasons[] = {
"ERROR, NOT USED",
"LM_USER_REQUEST",
"LM_LAP_DISCONNECT",
@@ -66,8 +66,15 @@ const char *irlmp_reasons[] = {
"LM_LAP_RESET",
"LM_INIT_DISCONNECT",
"ERROR, NOT USED",
+ "UNKNOWN",
};
+const char *irlmp_reason_str(LM_REASON reason)
+{
+ reason = min_t(size_t, reason, ARRAY_SIZE(irlmp_reasons) - 1);
+ return irlmp_reasons[reason];
+}
+
/*
* Function irlmp_init (void)
*
@@ -747,7 +754,8 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
{
struct lsap_cb *lsap;
- IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
+ IRDA_DEBUG(1, "%s(), reason=%s [%d]\n", __func__,
+ irlmp_reason_str(reason), reason);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index a7d11ffe4284..ae691651b721 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -49,12 +49,6 @@ static const u8 iprm_shutdown[8] =
#define TRGCLS_SIZE (sizeof(((struct iucv_message *)0)->class))
-/* macros to set/get socket control buffer at correct offset */
-#define CB_TAG(skb) ((skb)->cb) /* iucv message tag */
-#define CB_TAG_LEN (sizeof(((struct iucv_message *) 0)->tag))
-#define CB_TRGCLS(skb) ((skb)->cb + CB_TAG_LEN) /* iucv msg target class */
-#define CB_TRGCLS_LEN (TRGCLS_SIZE)
-
#define __iucv_sock_wait(sk, condition, timeo, ret) \
do { \
DEFINE_WAIT(__wait); \
@@ -1141,7 +1135,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
/* increment and save iucv message tag for msg_completion cbk */
txmsg.tag = iucv->send_tag++;
- memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN);
+ IUCV_SKB_CB(skb)->tag = txmsg.tag;
if (iucv->transport == AF_IUCV_TRANS_HIPER) {
atomic_inc(&iucv->msg_sent);
@@ -1224,7 +1218,7 @@ static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len)
return -ENOMEM;
/* copy target class to control buffer of new skb */
- memcpy(CB_TRGCLS(nskb), CB_TRGCLS(skb), CB_TRGCLS_LEN);
+ IUCV_SKB_CB(nskb)->class = IUCV_SKB_CB(skb)->class;
/* copy data fragment */
memcpy(nskb->data, skb->data + copied, size);
@@ -1256,7 +1250,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
/* store msg target class in the second 4 bytes of skb ctrl buffer */
/* Note: the first 4 bytes are reserved for msg tag */
- memcpy(CB_TRGCLS(skb), &msg->class, CB_TRGCLS_LEN);
+ IUCV_SKB_CB(skb)->class = msg->class;
/* check for special IPRM messages (e.g. iucv_sock_shutdown) */
if ((msg->flags & IUCV_IPRMDATA) && len > 7) {
@@ -1292,6 +1286,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
}
}
+ IUCV_SKB_CB(skb)->offset = 0;
if (sock_queue_rcv_skb(sk, skb))
skb_queue_head(&iucv_sk(sk)->backlog_skb_q, skb);
}
@@ -1327,6 +1322,9 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
unsigned int copied, rlen;
struct sk_buff *skb, *rskb, *cskb;
int err = 0;
+ u32 offset;
+
+ msg->msg_namelen = 0;
if ((sk->sk_state == IUCV_DISCONN) &&
skb_queue_empty(&iucv->backlog_skb_q) &&
@@ -1346,13 +1344,14 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- rlen = skb->len; /* real length of skb */
+ offset = IUCV_SKB_CB(skb)->offset;
+ rlen = skb->len - offset; /* real length of skb */
copied = min_t(unsigned int, rlen, len);
if (!rlen)
sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
cskb = skb;
- if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
+ if (skb_copy_datagram_iovec(cskb, offset, msg->msg_iov, copied)) {
if (!(flags & MSG_PEEK))
skb_queue_head(&sk->sk_receive_queue, skb);
return -EFAULT;
@@ -1370,7 +1369,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
* get the trgcls from the control buffer of the skb due to
* fragmentation of original iucv message. */
err = put_cmsg(msg, SOL_IUCV, SCM_IUCV_TRGCLS,
- CB_TRGCLS_LEN, CB_TRGCLS(skb));
+ sizeof(IUCV_SKB_CB(skb)->class),
+ (void *)&IUCV_SKB_CB(skb)->class);
if (err) {
if (!(flags & MSG_PEEK))
skb_queue_head(&sk->sk_receive_queue, skb);
@@ -1382,9 +1382,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
/* SOCK_STREAM: re-queue skb if it contains unreceived data */
if (sk->sk_type == SOCK_STREAM) {
- skb_pull(skb, copied);
- if (skb->len) {
- skb_queue_head(&sk->sk_receive_queue, skb);
+ if (copied < rlen) {
+ IUCV_SKB_CB(skb)->offset = offset + copied;
goto done;
}
}
@@ -1403,6 +1402,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
spin_lock_bh(&iucv->message_q.lock);
rskb = skb_dequeue(&iucv->backlog_skb_q);
while (rskb) {
+ IUCV_SKB_CB(rskb)->offset = 0;
if (sock_queue_rcv_skb(sk, rskb)) {
skb_queue_head(&iucv->backlog_skb_q,
rskb);
@@ -1461,7 +1461,8 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
return iucv_accept_poll(sk);
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
@@ -1830,7 +1831,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
spin_lock_irqsave(&list->lock, flags);
while (list_skb != (struct sk_buff *)list) {
- if (!memcmp(&msg->tag, CB_TAG(list_skb), CB_TAG_LEN)) {
+ if (msg->tag != IUCV_SKB_CB(list_skb)->tag) {
this = list_skb;
break;
}
@@ -2091,6 +2092,7 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
skb_pull(skb, sizeof(struct af_iucv_trans_hdr));
skb_reset_transport_header(skb);
skb_reset_network_header(skb);
+ IUCV_SKB_CB(skb)->offset = 0;
spin_lock(&iucv->message_q.lock);
if (skb_queue_empty(&iucv->backlog_skb_q)) {
if (sock_queue_rcv_skb(sk, skb)) {
@@ -2195,8 +2197,7 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
/* fall through and receive zero length data */
case 0:
/* plain data frame */
- memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
- CB_TRGCLS_LEN);
+ IUCV_SKB_CB(skb)->class = trans_hdr->iucv_hdr.class;
err = afiucv_hs_callback_rx(sk, skb);
break;
default:
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 8555f331ea60..5b1e5af25713 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2693,6 +2693,7 @@ static int key_notify_policy_flush(const struct km_event *c)
hdr->sadb_msg_pid = c->portid;
hdr->sadb_msg_version = PF_KEY_V2;
hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
return 0;
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 8aecf5df6656..6984c3a353cd 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1777,7 +1777,7 @@ int l2tp_session_delete(struct l2tp_session *session)
if (session->session_close != NULL)
(*session->session_close)(session);
if (session->deref)
- (*session->ref)(session);
+ (*session->deref)(session);
l2tp_session_dec_refcount(session);
return 0;
}
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index c74f5a91ff6a..b8a6039314e8 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -690,6 +690,7 @@ static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk,
lsa->l2tp_addr = ipv6_hdr(skb)->saddr;
lsa->l2tp_flowinfo = 0;
lsa->l2tp_scope_id = 0;
+ lsa->l2tp_conn_id = 0;
if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
lsa->l2tp_scope_id = IP6CB(skb)->iif;
}
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 88709882c464..48aaa89253e0 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -720,6 +720,8 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
int target; /* Read at least this many bytes */
long timeo;
+ msg->msg_namelen = 0;
+
lock_sock(sk);
copied = -ENOTCONN;
if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN))
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fb306814576a..1a89c80e6407 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -175,7 +175,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
* add it to the device after the station.
*/
if (!sta || !test_sta_flag(sta, WLAN_STA_ASSOC)) {
- ieee80211_key_free(sdata->local, key);
+ ieee80211_key_free_unused(key);
err = -ENOENT;
goto out_unlock;
}
@@ -214,8 +214,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
err = ieee80211_key_link(key, sdata, sta);
- if (err)
- ieee80211_key_free(sdata->local, key);
out_unlock:
mutex_unlock(&sdata->local->sta_mtx);
@@ -254,7 +252,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
goto out_unlock;
}
- __ieee80211_key_free(key);
+ ieee80211_key_free(key, true);
ret = 0;
out_unlock:
@@ -445,12 +443,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct timespec uptime;
+ u64 packets = 0;
+ int ac;
sinfo->generation = sdata->local->sta_generation;
sinfo->filled = STATION_INFO_INACTIVE_TIME |
- STATION_INFO_RX_BYTES |
- STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_BYTES64 |
+ STATION_INFO_TX_BYTES64 |
STATION_INFO_RX_PACKETS |
STATION_INFO_TX_PACKETS |
STATION_INFO_TX_RETRIES |
@@ -467,10 +467,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->connected_time = uptime.tv_sec - sta->last_connected;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+ sinfo->tx_bytes = 0;
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ sinfo->tx_bytes += sta->tx_bytes[ac];
+ packets += sta->tx_packets[ac];
+ }
+ sinfo->tx_packets = packets;
sinfo->rx_bytes = sta->rx_bytes;
- sinfo->tx_bytes = sta->tx_bytes;
sinfo->rx_packets = sta->rx_packets;
- sinfo->tx_packets = sta->tx_packets;
sinfo->tx_retries = sta->tx_retry_count;
sinfo->tx_failed = sta->tx_retry_failed;
sinfo->rx_dropped_misc = sta->rx_dropped;
@@ -598,8 +602,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
data[i++] += sta->rx_fragments; \
data[i++] += sta->rx_dropped; \
\
- data[i++] += sta->tx_packets; \
- data[i++] += sta->tx_bytes; \
+ data[i++] += sinfo.tx_packets; \
+ data[i++] += sinfo.tx_bytes; \
data[i++] += sta->tx_fragments; \
data[i++] += sta->tx_filtered_count; \
data[i++] += sta->tx_retry_failed; \
@@ -621,13 +625,14 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
goto do_survey;
+ sinfo.filled = 0;
+ sta_set_sinfo(sta, &sinfo);
+
i = 0;
ADD_STA_STATS(sta);
data[i++] = sta->sta_state;
- sinfo.filled = 0;
- sta_set_sinfo(sta, &sinfo);
if (sinfo.filled & STATION_INFO_TX_BITRATE)
data[i] = 100000 *
@@ -800,8 +805,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
IEEE80211_CHANCTX_EXCLUSIVE);
}
} else if (local->open_count == local->monitors) {
- local->_oper_channel = chandef->chan;
- local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
+ local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
}
@@ -960,8 +964,13 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->vif.bss_conf.hidden_ssid =
(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
- sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow;
- sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps;
+ memset(&sdata->vif.bss_conf.p2p_noa_attr, 0,
+ sizeof(sdata->vif.bss_conf.p2p_noa_attr));
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow =
+ params->p2p_ctwindow & IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
+ if (params->p2p_opp_ps)
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
+ IEEE80211_P2P_OPPPS_ENABLE_BIT;
err = ieee80211_assign_beacon(sdata, &params->beacon);
if (err < 0)
@@ -1034,12 +1043,17 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
sta_info_flush_defer(vlan);
sta_info_flush_defer(sdata);
+ synchronize_net();
rcu_barrier();
- list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+ list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
sta_info_flush_cleanup(vlan);
+ ieee80211_free_keys(vlan);
+ }
sta_info_flush_cleanup(sdata);
+ ieee80211_free_keys(sdata);
sdata->vif.bss_conf.enable_beacon = false;
+ sdata->vif.bss_conf.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
@@ -1177,6 +1191,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
mask |= BIT(NL80211_STA_FLAG_ASSOCIATED);
if (set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
set |= BIT(NL80211_STA_FLAG_ASSOCIATED);
+ } else if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+ /*
+ * TDLS -- everything follows authorized, but
+ * only becoming authorized is possible, not
+ * going back
+ */
+ if (set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
+ set |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED);
+ mask |= BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED);
+ }
}
ret = sta_apply_auth_flags(local, sta, mask, set);
@@ -1261,7 +1287,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
if (ieee80211_vif_is_mesh(&sdata->vif)) {
#ifdef CONFIG_MAC80211_MESH
u32 changed = 0;
- if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED) {
+
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) {
switch (params->plink_state) {
case NL80211_PLINK_ESTAB:
if (sta->plink_state != NL80211_PLINK_ESTAB)
@@ -1292,15 +1319,18 @@ static int sta_apply_parameters(struct ieee80211_local *local,
/* nothing */
break;
}
- } else {
- switch (params->plink_action) {
- case PLINK_ACTION_OPEN:
- changed |= mesh_plink_open(sta);
- break;
- case PLINK_ACTION_BLOCK:
- changed |= mesh_plink_block(sta);
- break;
- }
+ }
+
+ switch (params->plink_action) {
+ case NL80211_PLINK_ACTION_NO_ACTION:
+ /* nothing */
+ break;
+ case NL80211_PLINK_ACTION_OPEN:
+ changed |= mesh_plink_open(sta);
+ break;
+ case NL80211_PLINK_ACTION_BLOCK:
+ changed |= mesh_plink_block(sta);
+ break;
}
if (params->local_pm)
@@ -1346,8 +1376,10 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
* defaults -- if userspace wants something else we'll
* change it accordingly in sta_apply_parameters()
*/
- sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
- sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
+ sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
+ sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
+ }
err = sta_apply_parameters(local, sta, params);
if (err) {
@@ -1356,8 +1388,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
}
/*
- * for TDLS, rate control should be initialized only when supported
- * rates are known.
+ * for TDLS, rate control should be initialized only when
+ * rates are known and station is marked authorized
*/
if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
rate_control_rate_init(sta);
@@ -1394,50 +1426,67 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_change_station(struct wiphy *wiphy,
- struct net_device *dev,
- u8 *mac,
+ struct net_device *dev, u8 *mac,
struct station_parameters *params)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wiphy_priv(wiphy);
struct sta_info *sta;
struct ieee80211_sub_if_data *vlansdata;
+ enum cfg80211_station_type statype;
int err;
mutex_lock(&local->sta_mtx);
sta = sta_info_get_bss(sdata, mac);
if (!sta) {
- mutex_unlock(&local->sta_mtx);
- return -ENOENT;
+ err = -ENOENT;
+ goto out_err;
}
- /* in station mode, some updates are only valid with TDLS */
- if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- (params->supported_rates || params->ht_capa || params->vht_capa ||
- params->sta_modify_mask ||
- (params->sta_flags_mask & BIT(NL80211_STA_FLAG_WME))) &&
- !test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
- mutex_unlock(&local->sta_mtx);
- return -EINVAL;
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ if (sdata->u.mesh.user_mpm)
+ statype = CFG80211_STA_MESH_PEER_USER;
+ else
+ statype = CFG80211_STA_MESH_PEER_KERNEL;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ statype = CFG80211_STA_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+ statype = CFG80211_STA_AP_STA;
+ break;
+ }
+ if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ statype = CFG80211_STA_TDLS_PEER_ACTIVE;
+ else
+ statype = CFG80211_STA_TDLS_PEER_SETUP;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_AP_VLAN:
+ statype = CFG80211_STA_AP_CLIENT;
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ goto out_err;
}
+ err = cfg80211_check_station_change(wiphy, params, statype);
+ if (err)
+ goto out_err;
+
if (params->vlan && params->vlan != sta->sdata->dev) {
bool prev_4addr = false;
bool new_4addr = false;
vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
- if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
- vlansdata->vif.type != NL80211_IFTYPE_AP) {
- mutex_unlock(&local->sta_mtx);
- return -EINVAL;
- }
-
if (params->vlan->ieee80211_ptr->use_4addr) {
if (vlansdata->u.vlan.sta) {
- mutex_unlock(&local->sta_mtx);
- return -EBUSY;
+ err = -EBUSY;
+ goto out_err;
}
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
@@ -1464,12 +1513,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
}
err = sta_apply_parameters(local, sta, params);
- if (err) {
- mutex_unlock(&local->sta_mtx);
- return err;
- }
+ if (err)
+ goto out_err;
- if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+ /* When peer becomes authorized, init rate control as well */
+ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+ test_sta_flag(sta, WLAN_STA_AUTHORIZED))
rate_control_rate_init(sta);
mutex_unlock(&local->sta_mtx);
@@ -1479,7 +1528,11 @@ static int ieee80211_change_station(struct wiphy *wiphy,
ieee80211_recalc_ps(local, -1);
ieee80211_recalc_ps_vif(sdata);
}
+
return 0;
+out_err:
+ mutex_unlock(&local->sta_mtx);
+ return err;
}
#ifdef CONFIG_MAC80211_MESH
@@ -1489,7 +1542,6 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_sub_if_data *sdata;
struct mesh_path *mpath;
struct sta_info *sta;
- int err;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1500,17 +1552,12 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
return -ENOENT;
}
- err = mesh_path_add(sdata, dst);
- if (err) {
+ mpath = mesh_path_add(sdata, dst);
+ if (IS_ERR(mpath)) {
rcu_read_unlock();
- return err;
+ return PTR_ERR(mpath);
}
- mpath = mesh_path_lookup(sdata, dst);
- if (!mpath) {
- rcu_read_unlock();
- return -ENXIO;
- }
mesh_path_fix_nexthop(mpath, sta);
rcu_read_unlock();
@@ -1687,6 +1734,7 @@ static int copy_mesh_setup(struct ieee80211_if_mesh *ifmsh,
ifmsh->mesh_sp_id = setup->sync_method;
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
+ ifmsh->user_mpm = setup->user_mpm;
ifmsh->security = IEEE80211_MESH_SEC_NONE;
if (setup->is_authenticated)
ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
@@ -1730,8 +1778,11 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy,
conf->dot11MeshTTL = nconf->dot11MeshTTL;
if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
conf->element_ttl = nconf->element_ttl;
- if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
+ if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) {
+ if (ifmsh->user_mpm)
+ return -EBUSY;
conf->auto_open_plinks = nconf->auto_open_plinks;
+ }
if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask))
conf->dot11MeshNbrOffsetMaxNeighbor =
nconf->dot11MeshNbrOffsetMaxNeighbor;
@@ -1910,12 +1961,20 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
}
if (params->p2p_ctwindow >= 0) {
- sdata->vif.bss_conf.p2p_ctwindow = params->p2p_ctwindow;
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow &=
+ ~IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
+ params->p2p_ctwindow & IEEE80211_P2P_OPPPS_CTWINDOW_MASK;
changed |= BSS_CHANGED_P2P_PS;
}
- if (params->p2p_opp_ps >= 0) {
- sdata->vif.bss_conf.p2p_oppps = params->p2p_opp_ps;
+ if (params->p2p_opp_ps > 0) {
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow |=
+ IEEE80211_P2P_OPPPS_ENABLE_BIT;
+ changed |= BSS_CHANGED_P2P_PS;
+ } else if (params->p2p_opp_ps == 0) {
+ sdata->vif.bss_conf.p2p_noa_attr.oppps_ctwindow &=
+ ~IEEE80211_P2P_OPPPS_ENABLE_BIT;
changed |= BSS_CHANGED_P2P_PS;
}
@@ -2359,9 +2418,22 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
}
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ struct ieee80211_supported_band *sband = wiphy->bands[i];
+ int j;
+
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
memcpy(sdata->rc_rateidx_mcs_mask[i], mask->control[i].mcs,
sizeof(mask->control[i].mcs));
+
+ sdata->rc_has_mcs_mask[i] = false;
+ if (!sband)
+ continue;
+
+ for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++)
+ if (~sdata->rc_rateidx_mcs_mask[i][j]) {
+ sdata->rc_has_mcs_mask[i] = true;
+ break;
+ }
}
return 0;
@@ -2371,7 +2443,8 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel,
unsigned int duration, u64 *cookie,
- struct sk_buff *txskb)
+ struct sk_buff *txskb,
+ enum ieee80211_roc_type type)
{
struct ieee80211_roc_work *roc, *tmp;
bool queued = false;
@@ -2390,6 +2463,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
roc->duration = duration;
roc->req_duration = duration;
roc->frame = txskb;
+ roc->type = type;
roc->mgmt_tx_cookie = (unsigned long)txskb;
roc->sdata = sdata;
INIT_DELAYED_WORK(&roc->work, ieee80211_sw_roc_work);
@@ -2420,7 +2494,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
if (!duration)
duration = 10;
- ret = drv_remain_on_channel(local, sdata, channel, duration);
+ ret = drv_remain_on_channel(local, sdata, channel, duration, type);
if (ret) {
kfree(roc);
return ret;
@@ -2439,10 +2513,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
*
* If it hasn't started yet, just increase the duration
* and add the new one to the list of dependents.
+ * If the type of the new ROC has higher priority, modify the
+ * type of the previous one to match that of the new one.
*/
if (!tmp->started) {
list_add_tail(&roc->list, &tmp->dependents);
tmp->duration = max(tmp->duration, roc->duration);
+ tmp->type = max(tmp->type, roc->type);
queued = true;
break;
}
@@ -2454,16 +2531,18 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
/*
* In the offloaded ROC case, if it hasn't begun, add
* this new one to the dependent list to be handled
- * when the the master one begins. If it has begun,
+ * when the master one begins. If it has begun,
* check that there's still a minimum time left and
* if so, start this one, transmitting the frame, but
- * add it to the list directly after this one with a
+ * add it to the list directly after this one with
* a reduced time so we'll ask the driver to execute
* it right after finishing the previous one, in the
* hope that it'll also be executed right afterwards,
* effectively extending the old one.
* If there's no minimum time left, just add it to the
* normal list.
+ * TODO: the ROC type is ignored here, assuming that it
+ * is better to immediately use the current ROC.
*/
if (!tmp->hw_begun) {
list_add_tail(&roc->list, &tmp->dependents);
@@ -2557,7 +2636,8 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
mutex_lock(&local->mtx);
ret = ieee80211_start_roc_work(local, sdata, chan,
- duration, cookie, NULL);
+ duration, cookie, NULL,
+ IEEE80211_ROC_TYPE_NORMAL);
mutex_unlock(&local->mtx);
return ret;
@@ -2582,7 +2662,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
list_del(&dep->list);
mutex_unlock(&local->mtx);
- ieee80211_roc_notify_destroy(dep);
+ ieee80211_roc_notify_destroy(dep, true);
return 0;
}
@@ -2622,7 +2702,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
ieee80211_start_next_roc(local);
mutex_unlock(&local->mtx);
- ieee80211_roc_notify_destroy(found);
+ ieee80211_roc_notify_destroy(found, true);
} else {
/* work may be pending so use it all the time */
found->abort = true;
@@ -2632,6 +2712,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
/* work will clean up etc */
flush_delayed_work(&found->work);
+ WARN_ON(!found->to_be_freed);
+ kfree(found);
}
return 0;
@@ -2790,7 +2872,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* This will handle all kinds of coalescing and immediate TX */
ret = ieee80211_start_roc_work(local, sdata, chan,
- wait, cookie, skb);
+ wait, cookie, skb,
+ IEEE80211_ROC_TYPE_MGMT_TX);
if (ret)
kfree_skb(skb);
out_unlock:
@@ -3300,9 +3383,7 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
if (local->use_chanctx)
*chandef = local->monitor_chandef;
else
- cfg80211_chandef_create(chandef,
- local->_oper_channel,
- local->_oper_channel_type);
+ *chandef = local->_oper_chandef;
ret = 0;
}
rcu_read_unlock();
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 78c0d90dd641..03e8d2e3270e 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -22,7 +22,7 @@ static void ieee80211_change_chanctx(struct ieee80211_local *local,
drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
if (!local->use_chanctx) {
- local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
+ local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
}
}
@@ -57,12 +57,29 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
return NULL;
}
+static bool ieee80211_is_radar_required(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (sdata->radar_required) {
+ rcu_read_unlock();
+ return true;
+ }
+ }
+ rcu_read_unlock();
+
+ return false;
+}
+
static struct ieee80211_chanctx *
ieee80211_new_chanctx(struct ieee80211_local *local,
const struct cfg80211_chan_def *chandef,
enum ieee80211_chanctx_mode mode)
{
struct ieee80211_chanctx *ctx;
+ u32 changed;
int err;
lockdep_assert_held(&local->chanctx_mtx);
@@ -75,24 +92,35 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
ctx->conf.rx_chains_static = 1;
ctx->conf.rx_chains_dynamic = 1;
ctx->mode = mode;
+ ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
+ if (!local->use_chanctx)
+ local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
+
+ /* acquire mutex to prevent idle from changing */
+ mutex_lock(&local->mtx);
+ /* turn idle off *before* setting channel -- some drivers need that */
+ changed = ieee80211_idle_off(local);
+ if (changed)
+ ieee80211_hw_config(local, changed);
if (!local->use_chanctx) {
- local->_oper_channel_type =
- cfg80211_get_chandef_type(chandef);
- local->_oper_channel = chandef->chan;
+ local->_oper_chandef = *chandef;
ieee80211_hw_config(local, 0);
} else {
err = drv_add_chanctx(local, ctx);
if (err) {
kfree(ctx);
- return ERR_PTR(err);
+ ctx = ERR_PTR(err);
+
+ ieee80211_recalc_idle(local);
+ goto out;
}
}
+ /* and keep the mutex held until the new chanctx is on the list */
list_add_rcu(&ctx->list, &local->chanctx_list);
- mutex_lock(&local->mtx);
- ieee80211_recalc_idle(local);
+ out:
mutex_unlock(&local->mtx);
return ctx;
@@ -101,12 +129,24 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
static void ieee80211_free_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *ctx)
{
+ bool check_single_channel = false;
lockdep_assert_held(&local->chanctx_mtx);
WARN_ON_ONCE(ctx->refcount != 0);
if (!local->use_chanctx) {
- local->_oper_channel_type = NL80211_CHAN_NO_HT;
+ struct cfg80211_chan_def *chandef = &local->_oper_chandef;
+ chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef->center_freq1 = chandef->chan->center_freq;
+ chandef->center_freq2 = 0;
+
+ /* NOTE: Disabling radar is only valid here for
+ * single channel context. To be sure, check it ...
+ */
+ if (local->hw.conf.radar_enabled)
+ check_single_channel = true;
+ local->hw.conf.radar_enabled = false;
+
ieee80211_hw_config(local, 0);
} else {
drv_remove_chanctx(local, ctx);
@@ -115,6 +155,9 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
list_del_rcu(&ctx->list);
kfree_rcu(ctx, rcu_head);
+ /* throw a warning if this wasn't the only channel context. */
+ WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
+
mutex_lock(&local->mtx);
ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx);
@@ -226,19 +269,11 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
struct ieee80211_chanctx *chanctx)
{
- struct ieee80211_sub_if_data *sdata;
- bool radar_enabled = false;
+ bool radar_enabled;
lockdep_assert_held(&local->chanctx_mtx);
- rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
- if (sdata->radar_required) {
- radar_enabled = true;
- break;
- }
- }
- rcu_read_unlock();
+ radar_enabled = ieee80211_is_radar_required(local);
if (radar_enabled == chanctx->conf.radar_enabled)
return;
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index c3a3082b72e5..1521cabad3d6 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -295,7 +295,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
char buf[50];
struct ieee80211_key *key;
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
lockdep_assert_held(&sdata->local->key_mtx);
@@ -311,7 +311,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_unicast_key =
debugfs_create_symlink("default_unicast_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
}
if (sdata->debugfs.default_multicast_key) {
@@ -325,7 +325,7 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_multicast_key =
debugfs_create_symlink("default_multicast_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
}
}
@@ -334,7 +334,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
char buf[50];
struct ieee80211_key *key;
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
key = key_mtx_dereference(sdata->local,
@@ -343,7 +343,7 @@ void ieee80211_debugfs_key_add_mgmt_default(struct ieee80211_sub_if_data *sdata)
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_mgmt_key =
debugfs_create_symlink("default_mgmt_key",
- sdata->debugfs.dir, buf);
+ sdata->vif.debugfs_dir, buf);
} else
ieee80211_debugfs_key_remove_mgmt_default(sdata);
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 059bbb82e84f..14abcf44f974 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -124,6 +124,15 @@ static ssize_t ieee80211_if_fmt_##name( \
return scnprintf(buf, buflen, "%d\n", sdata->field / 16); \
}
+#define IEEE80211_IF_FMT_JIFFIES_TO_MS(name, field) \
+static ssize_t ieee80211_if_fmt_##name( \
+ const struct ieee80211_sub_if_data *sdata, \
+ char *buf, int buflen) \
+{ \
+ return scnprintf(buf, buflen, "%d\n", \
+ jiffies_to_msecs(sdata->field)); \
+}
+
#define __IEEE80211_IF_FILE(name, _write) \
static ssize_t ieee80211_if_read_##name(struct file *file, \
char __user *userbuf, \
@@ -197,6 +206,7 @@ IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
+IEEE80211_IF_FILE(beacon_timeout, u.mgd.beacon_timeout, JIFFIES_TO_MS);
static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
@@ -521,7 +531,7 @@ IEEE80211_IF_FILE(dot11MeshAwakeWindowDuration,
#endif
#define DEBUGFS_ADD_MODE(name, mode) \
- debugfs_create_file(#name, mode, sdata->debugfs.dir, \
+ debugfs_create_file(#name, mode, sdata->vif.debugfs_dir, \
sdata, &name##_ops);
#define DEBUGFS_ADD(name) DEBUGFS_ADD_MODE(name, 0400)
@@ -542,6 +552,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
DEBUGFS_ADD(aid);
DEBUGFS_ADD(last_beacon);
DEBUGFS_ADD(ave_beacon);
+ DEBUGFS_ADD(beacon_timeout);
DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
DEBUGFS_ADD_MODE(uapsd_queues, 0600);
@@ -577,7 +588,7 @@ static void add_mesh_files(struct ieee80211_sub_if_data *sdata)
static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
{
struct dentry *dir = debugfs_create_dir("mesh_stats",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
#define MESHSTATS_ADD(name)\
debugfs_create_file(#name, 0400, dir, sdata, &name##_ops);
@@ -594,7 +605,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
{
struct dentry *dir = debugfs_create_dir("mesh_config",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
#define MESHPARAMS_ADD(name) \
debugfs_create_file(#name, 0600, dir, sdata, &name##_ops);
@@ -631,7 +642,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
static void add_files(struct ieee80211_sub_if_data *sdata)
{
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
DEBUGFS_ADD(flags);
@@ -673,21 +684,21 @@ void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
char buf[10+IFNAMSIZ];
sprintf(buf, "netdev:%s", sdata->name);
- sdata->debugfs.dir = debugfs_create_dir(buf,
+ sdata->vif.debugfs_dir = debugfs_create_dir(buf,
sdata->local->hw.wiphy->debugfsdir);
- if (sdata->debugfs.dir)
+ if (sdata->vif.debugfs_dir)
sdata->debugfs.subdir_stations = debugfs_create_dir("stations",
- sdata->debugfs.dir);
+ sdata->vif.debugfs_dir);
add_files(sdata);
}
void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
{
- if (!sdata->debugfs.dir)
+ if (!sdata->vif.debugfs_dir)
return;
- debugfs_remove_recursive(sdata->debugfs.dir);
- sdata->debugfs.dir = NULL;
+ debugfs_remove_recursive(sdata->vif.debugfs_dir);
+ sdata->vif.debugfs_dir = NULL;
}
void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
@@ -695,7 +706,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata)
struct dentry *dir;
char buf[10 + IFNAMSIZ];
- dir = sdata->debugfs.dir;
+ dir = sdata->vif.debugfs_dir;
if (!dir)
return;
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index c7591f73dbc3..44e201d60a13 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -54,6 +54,7 @@ STA_FILE(aid, sta.aid, D);
STA_FILE(dev, sdata->name, S);
STA_FILE(last_signal, last_signal, D);
STA_FILE(last_ack_signal, last_ack_signal, D);
+STA_FILE(beacon_loss_count, beacon_loss_count, D);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
@@ -325,6 +326,36 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
}
STA_OPS(ht_capa);
+static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[128], *p = buf;
+ struct sta_info *sta = file->private_data;
+ struct ieee80211_sta_vht_cap *vhtc = &sta->sta.vht_cap;
+
+ p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
+ vhtc->vht_supported ? "" : "not ");
+ if (vhtc->vht_supported) {
+ p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap);
+
+ p += scnprintf(p, sizeof(buf)+buf-p, "RX MCS: %.4x\n",
+ le16_to_cpu(vhtc->vht_mcs.rx_mcs_map));
+ if (vhtc->vht_mcs.rx_highest)
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "MCS RX highest: %d Mbps\n",
+ le16_to_cpu(vhtc->vht_mcs.rx_highest));
+ p += scnprintf(p, sizeof(buf)+buf-p, "TX MCS: %.4x\n",
+ le16_to_cpu(vhtc->vht_mcs.tx_mcs_map));
+ if (vhtc->vht_mcs.tx_highest)
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "MCS TX highest: %d Mbps\n",
+ le16_to_cpu(vhtc->vht_mcs.tx_highest));
+ }
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(vht_capa);
+
static ssize_t sta_current_tx_rate_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -404,7 +435,9 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(agg_status);
DEBUGFS_ADD(dev);
DEBUGFS_ADD(last_signal);
+ DEBUGFS_ADD(beacon_loss_count);
DEBUGFS_ADD(ht_capa);
+ DEBUGFS_ADD(vht_capa);
DEBUGFS_ADD(last_ack_signal);
DEBUGFS_ADD(current_tx_rate);
DEBUGFS_ADD(last_rx_rate);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index ee56d0779d8b..169664c122e2 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -241,6 +241,22 @@ static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
return ret;
}
+static inline void drv_set_multicast_list(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct netdev_hw_addr_list *mc_list)
+{
+ bool allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+
+ trace_drv_set_multicast_list(local, sdata, mc_list->count);
+
+ check_sdata_in_driver(sdata);
+
+ if (local->ops->set_multicast_list)
+ local->ops->set_multicast_list(&local->hw, &sdata->vif,
+ allmulti, mc_list);
+ trace_drv_return_void(local);
+}
+
static inline void drv_configure_filter(struct ieee80211_local *local,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -531,43 +547,6 @@ static inline void drv_sta_remove_debugfs(struct ieee80211_local *local,
local->ops->sta_remove_debugfs(&local->hw, &sdata->vif,
sta, dir);
}
-
-static inline
-void drv_add_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- if (!local->ops->add_interface_debugfs)
- return;
-
- local->ops->add_interface_debugfs(&local->hw, &sdata->vif,
- sdata->debugfs.dir);
-}
-
-static inline
-void drv_remove_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata)
-{
- might_sleep();
-
- check_sdata_in_driver(sdata);
-
- if (!local->ops->remove_interface_debugfs)
- return;
-
- local->ops->remove_interface_debugfs(&local->hw, &sdata->vif,
- sdata->debugfs.dir);
-}
-#else
-static inline
-void drv_add_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata) {}
-static inline
-void drv_remove_interface_debugfs(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata) {}
#endif
static inline __must_check
@@ -741,13 +720,14 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
local->ops->rfkill_poll(&local->hw);
}
-static inline void drv_flush(struct ieee80211_local *local, bool drop)
+static inline void drv_flush(struct ieee80211_local *local,
+ u32 queues, bool drop)
{
might_sleep();
- trace_drv_flush(local, drop);
+ trace_drv_flush(local, queues, drop);
if (local->ops->flush)
- local->ops->flush(&local->hw, drop);
+ local->ops->flush(&local->hw, queues, drop);
trace_drv_return_void(local);
}
@@ -787,15 +767,16 @@ static inline int drv_get_antenna(struct ieee80211_local *local,
static inline int drv_remain_on_channel(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
- unsigned int duration)
+ unsigned int duration,
+ enum ieee80211_roc_type type)
{
int ret;
might_sleep();
- trace_drv_remain_on_channel(local, sdata, chan, duration);
+ trace_drv_remain_on_channel(local, sdata, chan, duration, type);
ret = local->ops->remain_on_channel(&local->hw, &sdata->vif,
- chan, duration);
+ chan, duration, type);
trace_drv_return_int(local, ret);
return ret;
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 0db25d4bb223..af8cee06e4f3 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -40,13 +40,6 @@ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
if (!ht_cap->ht_supported)
return;
- if (sdata->vif.type != NL80211_IFTYPE_STATION) {
- /* AP interfaces call this code when adding new stations,
- * so just silently ignore non station interfaces.
- */
- return;
- }
-
/* NOTE: If you add more over-rides here, update register_hw
* ht_capa_mod_msk logic in main.c as well.
* And, if this method can ever change ht_cap.ht_supported, fix
@@ -97,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
const struct ieee80211_ht_cap *ht_cap_ie,
struct sta_info *sta)
{
- struct ieee80211_sta_ht_cap ht_cap;
+ struct ieee80211_sta_ht_cap ht_cap, own_cap;
u8 ampdu_info, tx_mcs_set_cap;
int i, max_tx_streams;
bool changed;
@@ -111,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
ht_cap.ht_supported = true;
+ own_cap = sband->ht_cap;
+
+ /*
+ * If user has specified capability over-rides, take care
+ * of that if the station we're setting up is the AP that
+ * we advertised a restricted capability set to. Override
+ * our own capabilities and then use those below.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+ ieee80211_apply_htcap_overrides(sdata, &own_cap);
+
/*
* The bits listed in this expression should be
* the same for the peer and us, if the station
@@ -118,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
* we mask them out.
*/
ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
- (sband->ht_cap.cap |
- ~(IEEE80211_HT_CAP_LDPC_CODING |
- IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_GRN_FLD |
- IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_DSSSCCK40));
+ (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING |
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_DSSSCCK40));
/*
* The STBC bits are asymmetric -- if we don't have
* TX then mask out the peer's RX and vice versa.
*/
- if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
+ if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
- if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC))
+ if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
ampdu_info = ht_cap_ie->ampdu_params_info;
@@ -142,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
(ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
/* own MCS TX capabilities */
- tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
+ tx_mcs_set_cap = own_cap.mcs.tx_params;
/* Copy peer MCS TX capabilities, the driver might need them. */
ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
@@ -168,26 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
*/
for (i = 0; i < max_tx_streams; i++)
ht_cap.mcs.rx_mask[i] =
- sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
+ own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
i < IEEE80211_HT_MCS_MASK_LEN; i++)
ht_cap.mcs.rx_mask[i] =
- sband->ht_cap.mcs.rx_mask[i] &
+ own_cap.mcs.rx_mask[i] &
ht_cap_ie->mcs.rx_mask[i];
/* handle MCS rate 32 too */
- if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
+ if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
ht_cap.mcs.rx_mask[32/8] |= 1;
apply:
- /*
- * If user has specified capability over-rides, take care
- * of that here.
- */
- ieee80211_apply_htcap_overrides(sdata, &ht_cap);
-
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 40b71dfcc79d..170f9a7fa319 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -44,7 +44,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
int rates, i;
- struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
@@ -52,20 +51,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
u32 bss_change;
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
struct cfg80211_chan_def chandef;
+ struct beacon_data *presp;
+ int frame_len;
lockdep_assert_held(&ifibss->mtx);
/* Reset own TSF to allow time synchronization work. */
drv_reset_tsf(local, sdata);
- skb = ifibss->skb;
- RCU_INIT_POINTER(ifibss->presp, NULL);
- synchronize_rcu();
- skb->data = skb->head;
- skb->len = 0;
- skb_reset_tail_pointer(skb);
- skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
-
if (!ether_addr_equal(ifibss->bssid, bssid))
sta_info_flush(sdata);
@@ -73,10 +66,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.bss_conf.ibss_joined) {
sdata->vif.bss_conf.ibss_joined = false;
sdata->vif.bss_conf.ibss_creator = false;
+ sdata->vif.bss_conf.enable_beacon = false;
netif_carrier_off(sdata->dev);
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
+ ieee80211_bss_info_change_notify(sdata,
+ BSS_CHANGED_IBSS |
+ BSS_CHANGED_BEACON_ENABLED);
}
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&ifibss->mtx));
+ rcu_assign_pointer(ifibss->presp, NULL);
+ if (presp)
+ kfree_rcu(presp, rcu_head);
+
sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
cfg80211_chandef_create(&chandef, chan, ifibss->channel_type);
@@ -98,19 +100,24 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[chan->band];
- /* build supported rates array */
- pos = supp_rates;
- for (i = 0; i < sband->n_bitrates; i++) {
- int rate = sband->bitrates[i].bitrate;
- u8 basic = 0;
- if (basic_rates & BIT(i))
- basic = 0x80;
- *pos++ = basic | (u8) (rate / 5);
- }
-
/* Build IBSS probe response */
- mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
- memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ frame_len = sizeof(struct ieee80211_hdr_3addr) +
+ 12 /* struct ieee80211_mgmt.u.beacon */ +
+ 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
+ 2 + 8 /* max Supported Rates */ +
+ 3 /* max DS params */ +
+ 4 /* IBSS params */ +
+ 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+ 2 + sizeof(struct ieee80211_ht_cap) +
+ 2 + sizeof(struct ieee80211_ht_operation) +
+ ifibss->ie_len;
+ presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL);
+ if (!presp)
+ return;
+
+ presp->head = (void *)(presp + 1);
+
+ mgmt = (void *) presp->head;
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_PROBE_RESP);
eth_broadcast_addr(mgmt->da);
@@ -120,27 +127,30 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
mgmt->u.beacon.capab_info = cpu_to_le16(capability);
- pos = skb_put(skb, 2 + ifibss->ssid_len);
+ pos = (u8 *)mgmt + offsetof(struct ieee80211_mgmt, u.beacon.variable);
+
*pos++ = WLAN_EID_SSID;
*pos++ = ifibss->ssid_len;
memcpy(pos, ifibss->ssid, ifibss->ssid_len);
+ pos += ifibss->ssid_len;
- rates = sband->n_bitrates;
- if (rates > 8)
- rates = 8;
- pos = skb_put(skb, 2 + rates);
+ rates = min_t(int, 8, sband->n_bitrates);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
- memcpy(pos, supp_rates, rates);
+ for (i = 0; i < rates; i++) {
+ int rate = sband->bitrates[i].bitrate;
+ u8 basic = 0;
+ if (basic_rates & BIT(i))
+ basic = 0x80;
+ *pos++ = basic | (u8) (rate / 5);
+ }
if (sband->band == IEEE80211_BAND_2GHZ) {
- pos = skb_put(skb, 2 + 1);
*pos++ = WLAN_EID_DS_PARAMS;
*pos++ = 1;
*pos++ = ieee80211_frequency_to_channel(chan->center_freq);
}
- pos = skb_put(skb, 2 + 2);
*pos++ = WLAN_EID_IBSS_PARAMS;
*pos++ = 2;
/* FIX: set ATIM window based on scan results */
@@ -148,23 +158,25 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
if (sband->n_bitrates > 8) {
- rates = sband->n_bitrates - 8;
- pos = skb_put(skb, 2 + rates);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = rates;
- memcpy(pos, &supp_rates[8], rates);
+ *pos++ = sband->n_bitrates - 8;
+ for (i = 8; i < sband->n_bitrates; i++) {
+ int rate = sband->bitrates[i].bitrate;
+ u8 basic = 0;
+ if (basic_rates & BIT(i))
+ basic = 0x80;
+ *pos++ = basic | (u8) (rate / 5);
+ }
}
- if (ifibss->ie_len)
- memcpy(skb_put(skb, ifibss->ie_len),
- ifibss->ie, ifibss->ie_len);
+ if (ifibss->ie_len) {
+ memcpy(pos, ifibss->ie, ifibss->ie_len);
+ pos += ifibss->ie_len;
+ }
/* add HT capability and information IEs */
if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
sband->ht_cap.ht_supported) {
- pos = skb_put(skb, 4 +
- sizeof(struct ieee80211_ht_cap) +
- sizeof(struct ieee80211_ht_operation));
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
sband->ht_cap.cap);
/*
@@ -177,7 +189,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
if (local->hw.queues >= IEEE80211_NUM_ACS) {
- pos = skb_put(skb, 9);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 7; /* len */
*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
@@ -189,11 +200,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0; /* U-APSD no in use */
}
- rcu_assign_pointer(ifibss->presp, skb);
+ presp->head_len = pos - presp->head;
+ if (WARN_ON(presp->head_len > frame_len))
+ return;
+
+ rcu_assign_pointer(ifibss->presp, presp);
sdata->vif.bss_conf.enable_beacon = true;
sdata->vif.bss_conf.beacon_int = beacon_int;
sdata->vif.bss_conf.basic_rates = basic_rates;
+ sdata->vif.bss_conf.ssid_len = ifibss->ssid_len;
+ memcpy(sdata->vif.bss_conf.ssid, ifibss->ssid, ifibss->ssid_len);
bss_change = BSS_CHANGED_BEACON_INT;
bss_change |= ieee80211_reset_erp_info(sdata);
bss_change |= BSS_CHANGED_BSSID;
@@ -202,6 +219,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
bss_change |= BSS_CHANGED_BASIC_RATES;
bss_change |= BSS_CHANGED_HT;
bss_change |= BSS_CHANGED_IBSS;
+ bss_change |= BSS_CHANGED_SSID;
/*
* In 5 GHz/802.11a, we can always use short slot time.
@@ -227,7 +245,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan,
- mgmt, skb->len, 0, GFP_KERNEL);
+ mgmt, presp->head_len, 0, GFP_KERNEL);
cfg80211_put_bss(local->hw.wiphy, bss);
netif_carrier_on(sdata->dev);
cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
@@ -448,7 +466,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
bool rates_updated = false;
- if (elems->ds_params && elems->ds_params_len == 1)
+ if (elems->ds_params)
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
band);
else
@@ -822,8 +840,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
int tx_last_beacon, len = req->len;
struct sk_buff *skb;
- struct ieee80211_mgmt *resp;
- struct sk_buff *presp;
+ struct beacon_data *presp;
u8 *pos, *end;
lockdep_assert_held(&ifibss->mtx);
@@ -864,13 +881,15 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
}
/* Reply with ProbeResp */
- skb = skb_copy(presp, GFP_KERNEL);
+ skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
if (!skb)
return;
- resp = (struct ieee80211_mgmt *) skb->data;
- memcpy(resp->da, mgmt->sa, ETH_ALEN);
- ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da);
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, presp->head_len), presp->head, presp->head_len);
+
+ memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN);
+ ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, skb);
}
@@ -895,7 +914,7 @@ void ieee80211_rx_mgmt_probe_beacon(struct ieee80211_sub_if_data *sdata,
return;
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
- &elems);
+ false, &elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
}
@@ -985,36 +1004,9 @@ static void ieee80211_ibss_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
-
- if (local->quiescing) {
- ifibss->timer_running = true;
- return;
- }
-
- ieee80211_queue_work(&local->hw, &sdata->work);
-}
-
-#ifdef CONFIG_PM
-void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- if (del_timer_sync(&ifibss->timer))
- ifibss->timer_running = true;
-}
-
-void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-
- if (ifibss->timer_running) {
- add_timer(&ifibss->timer);
- ifibss->timer_running = false;
- }
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
-#endif
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
@@ -1047,23 +1039,8 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params)
{
- struct sk_buff *skb;
u32 changed = 0;
- skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
- sizeof(struct ieee80211_hdr_3addr) +
- 12 /* struct ieee80211_mgmt.u.beacon */ +
- 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
- 2 + 8 /* max Supported Rates */ +
- 3 /* max DS params */ +
- 4 /* IBSS params */ +
- 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
- 2 + sizeof(struct ieee80211_ht_cap) +
- 2 + sizeof(struct ieee80211_ht_operation) +
- params->ie_len);
- if (!skb)
- return -ENOMEM;
-
mutex_lock(&sdata->u.ibss.mtx);
if (params->bssid) {
@@ -1092,7 +1069,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
sdata->u.ibss.ie_len = params->ie_len;
}
- sdata->u.ibss.skb = skb;
sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
sdata->u.ibss.ibss_join_req = jiffies;
@@ -1128,13 +1104,13 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
{
- struct sk_buff *skb;
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct cfg80211_bss *cbss;
u16 capability;
int active_ibss;
struct sta_info *sta;
+ struct beacon_data *presp;
mutex_lock(&sdata->u.ibss.mtx);
@@ -1180,17 +1156,18 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
/* remove beacon */
kfree(sdata->u.ibss.ie);
- skb = rcu_dereference_protected(sdata->u.ibss.presp,
- lockdep_is_held(&sdata->u.ibss.mtx));
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&sdata->u.ibss.mtx));
RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
sdata->vif.bss_conf.ibss_joined = false;
sdata->vif.bss_conf.ibss_creator = false;
sdata->vif.bss_conf.enable_beacon = false;
+ sdata->vif.bss_conf.ssid_len = 0;
clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
BSS_CHANGED_IBSS);
synchronize_rcu();
- kfree_skb(skb);
+ kfree(presp);
skb_queue_purge(&sdata->skb_queue);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 388580a1bada..158e6eb188d3 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -156,6 +156,7 @@ struct ieee80211_tx_data {
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct ieee80211_key *key;
+ struct ieee80211_tx_rate rate;
unsigned int flags;
};
@@ -309,12 +310,14 @@ struct ieee80211_roc_work {
struct ieee80211_channel *chan;
bool started, abort, hw_begun, notified;
+ bool to_be_freed;
unsigned long hw_start_time;
u32 duration, req_duration;
struct sk_buff *frame;
u64 cookie, mgmt_tx_cookie;
+ enum ieee80211_roc_type type;
};
/* flags used in struct ieee80211_if_managed.flags */
@@ -400,7 +403,6 @@ struct ieee80211_if_managed {
u16 aid;
- unsigned long timers_running; /* used for quiesce/restart */
bool powersave; /* powersave requested for this iface */
bool broken_ap; /* AP is broken -- turn off powersave */
u8 dtim_period;
@@ -442,7 +444,7 @@ struct ieee80211_if_managed {
u8 use_4addr;
- u8 p2p_noa_index;
+ s16 p2p_noa_index;
/* Signal strength from the last Beacon frame in the current BSS. */
int last_beacon_signal;
@@ -479,6 +481,8 @@ struct ieee80211_if_managed {
struct ieee80211_ht_cap ht_capa; /* configured ht-cap over-rides */
struct ieee80211_ht_cap ht_capa_mask; /* Valid parts of ht_capa */
+ struct ieee80211_vht_cap vht_capa; /* configured VHT overrides */
+ struct ieee80211_vht_cap vht_capa_mask; /* Valid parts of vht_capa */
};
struct ieee80211_if_ibss {
@@ -490,8 +494,6 @@ struct ieee80211_if_ibss {
u32 basic_rates;
- bool timer_running;
-
bool fixed_bssid;
bool fixed_channel;
bool privacy;
@@ -508,8 +510,7 @@ struct ieee80211_if_ibss {
unsigned long ibss_join_req;
/* probe response/beacon for IBSS */
- struct sk_buff __rcu *presp;
- struct sk_buff *skb;
+ struct beacon_data __rcu *presp;
spinlock_t incomplete_lock;
struct list_head incomplete_stations;
@@ -543,8 +544,6 @@ struct ieee80211_if_mesh {
struct timer_list mesh_path_timer;
struct timer_list mesh_path_root_timer;
- unsigned long timers_running;
-
unsigned long wrkq_flags;
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
@@ -590,6 +589,7 @@ struct ieee80211_if_mesh {
IEEE80211_MESH_SEC_AUTHED = 0x1,
IEEE80211_MESH_SEC_SECURED = 0x2,
} security;
+ bool user_mpm;
/* Extensible Synchronization Framework */
const struct ieee80211_mesh_sync_ops *sync_ops;
s64 sync_offset_clockdrift_max;
@@ -682,6 +682,8 @@ struct ieee80211_sub_if_data {
/* count for keys needing tailroom space allocation */
int crypto_tx_tailroom_needed_cnt;
+ int crypto_tx_tailroom_pending_dec;
+ struct delayed_work dec_tailroom_needed_wk;
struct net_device *dev;
struct ieee80211_local *local;
@@ -739,6 +741,8 @@ struct ieee80211_sub_if_data {
/* bitmap of allowed (non-MCS) rate indexes for rate control */
u32 rc_rateidx_mask[IEEE80211_NUM_BANDS];
+
+ bool rc_has_mcs_mask[IEEE80211_NUM_BANDS];
u8 rc_rateidx_mcs_mask[IEEE80211_NUM_BANDS][IEEE80211_HT_MCS_MASK_LEN];
union {
@@ -757,7 +761,6 @@ struct ieee80211_sub_if_data {
#ifdef CONFIG_MAC80211_DEBUGFS
struct {
- struct dentry *dir;
struct dentry *subdir_stations;
struct dentry *default_unicast_key;
struct dentry *default_multicast_key;
@@ -765,10 +768,6 @@ struct ieee80211_sub_if_data {
} debugfs;
#endif
-#ifdef CONFIG_PM
- struct ieee80211_bss_conf suspend_bss_conf;
-#endif
-
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
};
@@ -803,11 +802,6 @@ enum sdata_queue_type {
enum {
IEEE80211_RX_MSG = 1,
IEEE80211_TX_STATUS_MSG = 2,
- IEEE80211_EOSP_MSG = 3,
-};
-
-struct skb_eosp_msg_data {
- u8 sta[ETH_ALEN], iface[ETH_ALEN];
};
enum queue_stop_reason {
@@ -818,6 +812,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH,
};
#ifdef CONFIG_MAC80211_LEDS
@@ -1028,10 +1023,9 @@ struct ieee80211_local {
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
struct ieee80211_sub_if_data __rcu *scan_sdata;
- struct ieee80211_channel *csa_channel;
+ struct cfg80211_chan_def csa_chandef;
/* For backward compatibility only -- do not use */
- struct ieee80211_channel *_oper_channel;
- enum nl80211_channel_type _oper_channel_type;
+ struct cfg80211_chan_def _oper_chandef;
/* Temporary remain-on-channel for off-channel operations */
struct ieee80211_channel *tmp_channel;
@@ -1136,11 +1130,6 @@ struct ieee80211_local {
struct ieee80211_sub_if_data __rcu *p2p_sdata;
- /* dummy netdev for use w/ NAPI */
- struct net_device napi_dev;
-
- struct napi_struct napi;
-
/* virtual monitor interface */
struct ieee80211_sub_if_data __rcu *monitor_sdata;
struct cfg80211_chan_def monitor_chandef;
@@ -1172,11 +1161,8 @@ struct ieee802_11_elems {
/* pointers to IEs */
const u8 *ssid;
const u8 *supp_rates;
- const u8 *fh_params;
const u8 *ds_params;
- const u8 *cf_params;
const struct ieee80211_tim_ie *tim;
- const u8 *ibss_params;
const u8 *challenge;
const u8 *rsn;
const u8 *erp_info;
@@ -1196,23 +1182,20 @@ struct ieee802_11_elems {
const u8 *perr;
const struct ieee80211_rann_ie *rann;
const struct ieee80211_channel_sw_ie *ch_switch_ie;
+ const struct ieee80211_ext_chansw_ie *ext_chansw_ie;
+ const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
const u8 *country_elem;
const u8 *pwr_constr_elem;
- const u8 *quiet_elem; /* first quite element */
- const u8 *timeout_int;
+ const struct ieee80211_timeout_interval_ie *timeout_int;
const u8 *opmode_notif;
+ const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
/* length of them, respectively */
u8 ssid_len;
u8 supp_rates_len;
- u8 fh_params_len;
- u8 ds_params_len;
- u8 cf_params_len;
u8 tim_len;
- u8 ibss_params_len;
u8 challenge_len;
u8 rsn_len;
- u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wmm_info_len;
u8 wmm_param_len;
@@ -1222,9 +1205,6 @@ struct ieee802_11_elems {
u8 prep_len;
u8 perr_len;
u8 country_elem_len;
- u8 quiet_elem_len;
- u8 num_of_quiet_elem; /* can be more the one */
- u8 timeout_int_len;
/* whether a parse error occurred while retrieving these elements */
bool parse_error;
@@ -1279,12 +1259,6 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
-void
-ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- const struct ieee80211_channel_sw_ie *sw_elem,
- struct ieee80211_bss *bss, u64 timestamp);
-void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
@@ -1302,8 +1276,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params);
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
-void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
@@ -1346,8 +1318,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local);
void ieee80211_offchannel_return(struct ieee80211_local *local);
void ieee80211_roc_setup(struct ieee80211_local *local);
void ieee80211_start_next_roc(struct ieee80211_local *local);
-void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_roc_purge(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
void ieee80211_sw_roc_work(struct work_struct *work);
void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
@@ -1361,11 +1334,14 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
enum nl80211_iftype type);
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
void ieee80211_remove_interfaces(struct ieee80211_local *local);
+u32 ieee80211_idle_off(struct ieee80211_local *local);
void ieee80211_recalc_idle(struct ieee80211_local *local);
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset);
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
+int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
+void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
@@ -1441,6 +1417,8 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta);
void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode,
enum ieee80211_band band, bool nss_only);
+void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_vht_cap *vht_cap);
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
@@ -1518,11 +1496,15 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb_tid(sdata, skb, 7);
}
-void ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems);
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
u64 filter, u32 crc);
+static inline void ieee802_11_parse_elems(u8 *start, size_t len, bool action,
+ struct ieee802_11_elems *elems)
+{
+ ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
+}
+
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
enum ieee80211_band band);
@@ -1538,8 +1520,10 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason);
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason);
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
@@ -1556,6 +1540,8 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
{
ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
}
+void ieee80211_flush_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index baaa8608e52d..60f1ce5e5e52 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1,5 +1,5 @@
/*
- * Interface handling (except master interface)
+ * Interface handling
*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
@@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
}
-static u32 ieee80211_idle_off(struct ieee80211_local *local)
+static u32 __ieee80211_idle_off(struct ieee80211_local *local)
{
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
return 0;
@@ -87,27 +87,29 @@ static u32 ieee80211_idle_off(struct ieee80211_local *local)
return IEEE80211_CONF_CHANGE_IDLE;
}
-static u32 ieee80211_idle_on(struct ieee80211_local *local)
+static u32 __ieee80211_idle_on(struct ieee80211_local *local)
{
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
return 0;
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
return IEEE80211_CONF_CHANGE_IDLE;
}
-void ieee80211_recalc_idle(struct ieee80211_local *local)
+static u32 __ieee80211_recalc_idle(struct ieee80211_local *local,
+ bool force_active)
{
bool working = false, scanning, active;
unsigned int led_trig_start = 0, led_trig_stop = 0;
struct ieee80211_roc_work *roc;
- u32 change;
lockdep_assert_held(&local->mtx);
- active = !list_empty(&local->chanctx_list) || local->monitors;
+ active = force_active ||
+ !list_empty(&local->chanctx_list) ||
+ local->monitors;
if (!local->ops->remain_on_channel) {
list_for_each_entry(roc, &local->roc_list, list) {
@@ -132,9 +134,18 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop);
if (working || scanning || active)
- change = ieee80211_idle_off(local);
- else
- change = ieee80211_idle_on(local);
+ return __ieee80211_idle_off(local);
+ return __ieee80211_idle_on(local);
+}
+
+u32 ieee80211_idle_off(struct ieee80211_local *local)
+{
+ return __ieee80211_recalc_idle(local, true);
+}
+
+void ieee80211_recalc_idle(struct ieee80211_local *local)
+{
+ u32 change = __ieee80211_recalc_idle(local, false);
if (change)
ieee80211_hw_config(local, change);
}
@@ -346,24 +357,22 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
-static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
+int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- int ret = 0;
+ int ret;
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return 0;
- mutex_lock(&local->iflist_mtx);
+ ASSERT_RTNL();
if (local->monitor_sdata)
- goto out_unlock;
+ return 0;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
- if (!sdata) {
- ret = -ENOMEM;
- goto out_unlock;
- }
+ if (!sdata)
+ return -ENOMEM;
/* set up data */
sdata->local = local;
@@ -377,13 +386,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
- goto out_unlock;
+ return ret;
}
ret = ieee80211_check_queues(sdata);
if (ret) {
kfree(sdata);
- goto out_unlock;
+ return ret;
}
ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
@@ -391,30 +400,37 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (ret) {
drv_remove_interface(local, sdata);
kfree(sdata);
- goto out_unlock;
+ return ret;
}
+ mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, sdata);
- out_unlock:
mutex_unlock(&local->iflist_mtx);
- return ret;
+
+ return 0;
}
-static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
+void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return;
+ ASSERT_RTNL();
+
mutex_lock(&local->iflist_mtx);
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
- if (!sdata)
- goto out_unlock;
+ if (!sdata) {
+ mutex_unlock(&local->iflist_mtx);
+ return;
+ }
rcu_assign_pointer(local->monitor_sdata, NULL);
+ mutex_unlock(&local->iflist_mtx);
+
synchronize_net();
ieee80211_vif_release_channel(sdata);
@@ -422,8 +438,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
drv_remove_interface(local, sdata);
kfree(sdata);
- out_unlock:
- mutex_unlock(&local->iflist_mtx);
}
/*
@@ -485,8 +499,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
res = drv_start(local);
if (res)
goto err_del_bss;
- if (local->ops->napi_poll)
- napi_enable(&local->napi);
/* we're brought up, everything changes */
hw_reconf_flags = ~0;
ieee80211_led_radio(local, true);
@@ -559,8 +571,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
goto err_del_interface;
}
- drv_add_interface_debugfs(local, sdata);
-
if (sdata->vif.type == NL80211_IFTYPE_AP) {
local->fif_pspoll++;
local->fif_probe_req++;
@@ -585,7 +595,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
case NL80211_IFTYPE_P2P_DEVICE:
break;
default:
- netif_carrier_on(dev);
+ /* not reached */
+ WARN_ON(1);
}
/*
@@ -642,8 +653,28 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
ieee80211_recalc_ps(local, -1);
- if (dev)
- netif_tx_start_all_queues(dev);
+ if (dev) {
+ unsigned long flags;
+ int n_acs = IEEE80211_NUM_ACS;
+ int ac;
+
+ if (local->hw.queues < IEEE80211_NUM_ACS)
+ n_acs = 1;
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE ||
+ (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 &&
+ skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
+ for (ac = 0; ac < n_acs; ac++) {
+ int ac_queue = sdata->vif.hw_queue[ac];
+
+ if (local->queue_stop_reasons[ac_queue] == 0 &&
+ skb_queue_empty(&local->pending[ac_queue]))
+ netif_start_subqueue(dev, ac);
+ }
+ }
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ }
return 0;
err_del_interface:
@@ -697,7 +728,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (sdata->dev)
netif_tx_stop_all_queues(sdata->dev);
- ieee80211_roc_purge(sdata);
+ ieee80211_roc_purge(local, sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
ieee80211_mgd_stop(sdata);
@@ -722,12 +753,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
- /*
- * Don't count this interface for promisc/allmulti while it
- * is down. dev_mc_unsync() will invoke set_multicast_list
- * on the master interface which will sync these down to the
- * hardware as filter flags.
- */
+ /* don't count this interface for promisc/allmulti while it is down */
if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
atomic_dec(&local->iff_allmultis);
@@ -748,8 +774,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
sdata->dev->addr_len);
spin_unlock_bh(&local->filter_lock);
netif_addr_unlock_bh(sdata->dev);
-
- ieee80211_configure_filter(local);
}
del_timer_sync(&local->dynamic_ps_timer);
@@ -760,6 +784,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
+ WARN_ON(local->suspended);
mutex_lock(&local->iflist_mtx);
ieee80211_vif_release_channel(sdata);
mutex_unlock(&local->iflist_mtx);
@@ -810,14 +835,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
if (local->monitors == 0) {
local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
- ieee80211_del_virtual_monitor(local);
}
ieee80211_adjust_monitor_flags(sdata, -1);
- ieee80211_configure_filter(local);
- mutex_lock(&local->mtx);
- ieee80211_recalc_idle(local);
- mutex_unlock(&local->mtx);
break;
case NL80211_IFTYPE_P2P_DEVICE:
/* relies on synchronize_rcu() below */
@@ -830,46 +850,28 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
*
* sta_info_flush_cleanup() requires rcu_barrier()
* first to wait for the station call_rcu() calls
- * to complete, here we need at least sychronize_rcu()
- * it to wait for the RX path in case it is using the
+ * to complete, and we also need synchronize_rcu()
+ * to wait for the RX path in case it is using the
* interface and enqueuing frames at this very time on
* another CPU.
*/
+ synchronize_rcu();
rcu_barrier();
sta_info_flush_cleanup(sdata);
- skb_queue_purge(&sdata->skb_queue);
-
/*
* Free all remaining keys, there shouldn't be any,
- * except maybe group keys in AP more or WDS?
+ * except maybe in WDS mode?
*/
ieee80211_free_keys(sdata);
- drv_remove_interface_debugfs(local, sdata);
-
- if (going_down)
- drv_remove_interface(local, sdata);
+ /* fall through */
+ case NL80211_IFTYPE_AP:
+ skb_queue_purge(&sdata->skb_queue);
}
sdata->bss = NULL;
- ieee80211_recalc_ps(local, -1);
-
- if (local->open_count == 0) {
- if (local->ops->napi_poll)
- napi_disable(&local->napi);
- ieee80211_clear_tx_pending(local);
- ieee80211_stop_device(local);
-
- /* no reconfiguring after stop! */
- hw_reconf_flags = 0;
- }
-
- /* do after stop to avoid reconfiguring when we stop anyway */
- if (hw_reconf_flags)
- ieee80211_hw_config(local, hw_reconf_flags);
-
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_walk_safe(&local->pending[i], skb, tmp) {
@@ -882,7 +884,54 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- if (local->monitors == local->open_count && local->monitors > 0)
+ if (local->open_count == 0)
+ ieee80211_clear_tx_pending(local);
+
+ /*
+ * If the interface goes down while suspended, presumably because
+ * the device was unplugged and that happens before our resume,
+ * then the driver is already unconfigured and the remainder of
+ * this function isn't needed.
+ * XXX: what about WoWLAN? If the device has software state, e.g.
+ * memory allocated, it might expect teardown commands from
+ * mac80211 here?
+ */
+ if (local->suspended) {
+ WARN_ON(local->wowlan);
+ WARN_ON(rtnl_dereference(local->monitor_sdata));
+ return;
+ }
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ if (local->monitors == 0)
+ ieee80211_del_virtual_monitor(local);
+
+ mutex_lock(&local->mtx);
+ ieee80211_recalc_idle(local);
+ mutex_unlock(&local->mtx);
+ break;
+ default:
+ if (going_down)
+ drv_remove_interface(local, sdata);
+ }
+
+ ieee80211_recalc_ps(local, -1);
+
+ if (local->open_count == 0) {
+ ieee80211_stop_device(local);
+
+ /* no reconfiguring after stop! */
+ return;
+ }
+
+ /* do after stop to avoid reconfiguring when we stop anyway */
+ ieee80211_configure_filter(local);
+ ieee80211_hw_config(local, hw_reconf_flags);
+
+ if (local->monitors == local->open_count)
ieee80211_add_virtual_monitor(local);
}
@@ -921,6 +970,17 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
+
+ /*
+ * TODO: If somebody needs this on AP interfaces,
+ * it can be enabled easily but multicast
+ * addresses from VLANs need to be synced.
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
+ drv_set_multicast_list(local, sdata, &dev->mc);
+
spin_lock_bh(&local->filter_lock);
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
spin_unlock_bh(&local->filter_lock);
@@ -1547,6 +1607,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
INIT_WORK(&sdata->cleanup_stations_wk, ieee80211_cleanup_sdata_stas_wk);
INIT_DELAYED_WORK(&sdata->dfs_cac_timer_work,
ieee80211_dfs_cac_timer_work);
+ INIT_DELAYED_WORK(&sdata->dec_tailroom_needed_wk,
+ ieee80211_delayed_tailroom_dec);
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
struct ieee80211_supported_band *sband;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index ef252eb58c36..67059b88fea5 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -248,11 +248,11 @@ void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
}
-static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- bool pairwise,
- struct ieee80211_key *old,
- struct ieee80211_key *new)
+static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ bool pairwise,
+ struct ieee80211_key *old,
+ struct ieee80211_key *new)
{
int idx;
bool defunikey, defmultikey, defmgmtkey;
@@ -397,7 +397,41 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
return key;
}
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
+static void ieee80211_key_free_common(struct ieee80211_key *key)
+{
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
+ ieee80211_aes_key_free(key->u.ccmp.tfm);
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
+ kfree(key);
+}
+
+static void __ieee80211_key_destroy(struct ieee80211_key *key,
+ bool delay_tailroom)
+{
+ if (key->local)
+ ieee80211_key_disable_hw_accel(key);
+
+ if (key->local) {
+ struct ieee80211_sub_if_data *sdata = key->sdata;
+
+ ieee80211_debugfs_key_remove(key);
+
+ if (delay_tailroom) {
+ /* see ieee80211_delayed_tailroom_dec */
+ sdata->crypto_tx_tailroom_pending_dec++;
+ schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
+ HZ/2);
+ } else {
+ sdata->crypto_tx_tailroom_needed_cnt--;
+ }
+ }
+
+ ieee80211_key_free_common(key);
+}
+
+static void ieee80211_key_destroy(struct ieee80211_key *key,
+ bool delay_tailroom)
{
if (!key)
return;
@@ -408,19 +442,13 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
*/
synchronize_net();
- if (key->local)
- ieee80211_key_disable_hw_accel(key);
-
- if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
- ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
- if (key->local) {
- ieee80211_debugfs_key_remove(key);
- key->sdata->crypto_tx_tailroom_needed_cnt--;
- }
+ __ieee80211_key_destroy(key, delay_tailroom);
+}
- kfree(key);
+void ieee80211_key_free_unused(struct ieee80211_key *key)
+{
+ WARN_ON(key->sdata || key->local);
+ ieee80211_key_free_common(key);
}
int ieee80211_key_link(struct ieee80211_key *key,
@@ -440,32 +468,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
key->sdata = sdata;
key->sta = sta;
- if (sta) {
- /*
- * some hardware cannot handle TKIP with QoS, so
- * we indicate whether QoS could be in use.
- */
- if (test_sta_flag(sta, WLAN_STA_WME))
- key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
- } else {
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- struct sta_info *ap;
-
- /*
- * We're getting a sta pointer in, so must be under
- * appropriate locking for sta_info_get().
- */
-
- /* same here, the AP could be using QoS */
- ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
- if (ap) {
- if (test_sta_flag(ap, WLAN_STA_WME))
- key->conf.flags |=
- IEEE80211_KEY_FLAG_WMM_STA;
- }
- }
- }
-
mutex_lock(&sdata->local->key_mtx);
if (sta && pairwise)
@@ -477,19 +479,22 @@ int ieee80211_key_link(struct ieee80211_key *key,
increment_tailroom_need_count(sdata);
- __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
- __ieee80211_key_destroy(old_key);
+ ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
+ ieee80211_key_destroy(old_key, true);
ieee80211_debugfs_key_add(key);
ret = ieee80211_key_enable_hw_accel(key);
+ if (ret)
+ ieee80211_key_free(key, true);
+
mutex_unlock(&sdata->local->key_mtx);
return ret;
}
-void __ieee80211_key_free(struct ieee80211_key *key)
+void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
{
if (!key)
return;
@@ -498,18 +503,10 @@ void __ieee80211_key_free(struct ieee80211_key *key)
* Replace key with nothingness if it was ever used.
*/
if (key->sdata)
- __ieee80211_key_replace(key->sdata, key->sta,
+ ieee80211_key_replace(key->sdata, key->sta,
key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
key, NULL);
- __ieee80211_key_destroy(key);
-}
-
-void ieee80211_key_free(struct ieee80211_local *local,
- struct ieee80211_key *key)
-{
- mutex_lock(&local->key_mtx);
- __ieee80211_key_free(key);
- mutex_unlock(&local->key_mtx);
+ ieee80211_key_destroy(key, delay_tailroom);
}
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
@@ -566,36 +563,109 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_iter_keys);
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_key *key;
+ struct ieee80211_key *key, *tmp;
+ LIST_HEAD(keys);
- ASSERT_RTNL();
+ cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
mutex_lock(&sdata->local->key_mtx);
- list_for_each_entry(key, &sdata->key_list, list)
- ieee80211_key_disable_hw_accel(key);
+ sdata->crypto_tx_tailroom_needed_cnt -=
+ sdata->crypto_tx_tailroom_pending_dec;
+ sdata->crypto_tx_tailroom_pending_dec = 0;
+
+ ieee80211_debugfs_key_remove_mgmt_default(sdata);
+
+ list_for_each_entry_safe(key, tmp, &sdata->key_list, list) {
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add_tail(&key->list, &keys);
+ }
+
+ ieee80211_debugfs_key_update_default(sdata);
+
+ if (!list_empty(&keys)) {
+ synchronize_net();
+ list_for_each_entry_safe(key, tmp, &keys, list)
+ __ieee80211_key_destroy(key, false);
+ }
+
+ WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
+ sdata->crypto_tx_tailroom_pending_dec);
mutex_unlock(&sdata->local->key_mtx);
}
-void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
+void ieee80211_free_sta_keys(struct ieee80211_local *local,
+ struct sta_info *sta)
{
struct ieee80211_key *key, *tmp;
+ LIST_HEAD(keys);
+ int i;
- mutex_lock(&sdata->local->key_mtx);
+ mutex_lock(&local->key_mtx);
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ key = key_mtx_dereference(local, sta->gtk[i]);
+ if (!key)
+ continue;
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add(&key->list, &keys);
+ }
- ieee80211_debugfs_key_remove_mgmt_default(sdata);
+ key = key_mtx_dereference(local, sta->ptk);
+ if (key) {
+ ieee80211_key_replace(key->sdata, key->sta,
+ key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
+ key, NULL);
+ list_add(&key->list, &keys);
+ }
- list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
- __ieee80211_key_free(key);
+ /*
+ * NB: the station code relies on this being
+ * done even if there aren't any keys
+ */
+ synchronize_net();
- ieee80211_debugfs_key_update_default(sdata);
+ list_for_each_entry_safe(key, tmp, &keys, list)
+ __ieee80211_key_destroy(key, true);
- mutex_unlock(&sdata->local->key_mtx);
+ mutex_unlock(&local->key_mtx);
}
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = container_of(wk, struct ieee80211_sub_if_data,
+ dec_tailroom_needed_wk.work);
+
+ /*
+ * The reason for the delayed tailroom needed decrementing is to
+ * make roaming faster: during roaming, all keys are first deleted
+ * and then new keys are installed. The first new key causes the
+ * crypto_tx_tailroom_needed_cnt to go from 0 to 1, which invokes
+ * the cost of synchronize_net() (which can be slow). Avoid this
+ * by deferring the crypto_tx_tailroom_needed_cnt decrementing on
+ * key removal for a while, so if we roam the value is larger than
+ * zero and no 0->1 transition happens.
+ *
+ * The cost is that if the AP switching was from an AP with keys
+ * to one without, we still allocate tailroom while it would no
+ * longer be needed. However, in the typical (fast) roaming case
+ * within an ESS this usually won't happen.
+ */
+
+ mutex_lock(&sdata->local->key_mtx);
+ sdata->crypto_tx_tailroom_needed_cnt -=
+ sdata->crypto_tx_tailroom_pending_dec;
+ sdata->crypto_tx_tailroom_pending_dec = 0;
+ mutex_unlock(&sdata->local->key_mtx);
+}
void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp)
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 382dc44ed330..e8de3e6d7804 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -129,23 +129,25 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
size_t seq_len, const u8 *seq);
/*
* Insert a key into data structures (sdata, sta if necessary)
- * to make it used, free old key.
+ * to make it used, free old key. On failure, also free the new key.
*/
-int __must_check ieee80211_key_link(struct ieee80211_key *key,
- struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta);
-void __ieee80211_key_free(struct ieee80211_key *key);
-void ieee80211_key_free(struct ieee80211_local *local,
- struct ieee80211_key *key);
+int ieee80211_key_link(struct ieee80211_key *key,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta);
+void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom);
+void ieee80211_key_free_unused(struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
bool uni, bool multi);
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx);
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_free_sta_keys(struct ieee80211_local *local,
+ struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
#define key_mtx_dereference(local, ref) \
rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
+void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
+
#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1a8591b77a13..8a7bfc47d577 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -95,43 +95,47 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_channel *chan;
+ struct cfg80211_chan_def chandef = {};
u32 changed = 0;
int power;
- enum nl80211_channel_type channel_type;
u32 offchannel_flag;
- bool scanning = false;
offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
+
if (local->scan_channel) {
- chan = local->scan_channel;
+ chandef.chan = local->scan_channel;
/* If scanning on oper channel, use whatever channel-type
* is currently in use.
*/
- if (chan == local->_oper_channel)
- channel_type = local->_oper_channel_type;
- else
- channel_type = NL80211_CHAN_NO_HT;
+ if (chandef.chan == local->_oper_chandef.chan) {
+ chandef = local->_oper_chandef;
+ } else {
+ chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef.center_freq1 = chandef.chan->center_freq;
+ }
} else if (local->tmp_channel) {
- chan = local->tmp_channel;
- channel_type = NL80211_CHAN_NO_HT;
- } else {
- chan = local->_oper_channel;
- channel_type = local->_oper_channel_type;
- }
-
- if (chan != local->_oper_channel ||
- channel_type != local->_oper_channel_type)
+ chandef.chan = local->tmp_channel;
+ chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+ chandef.center_freq1 = chandef.chan->center_freq;
+ } else
+ chandef = local->_oper_chandef;
+
+ WARN(!cfg80211_chandef_valid(&chandef),
+ "control:%d MHz width:%d center: %d/%d MHz",
+ chandef.chan->center_freq, chandef.width,
+ chandef.center_freq1, chandef.center_freq2);
+
+ if (!cfg80211_chandef_identical(&chandef, &local->_oper_chandef))
local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL;
else
local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL;
offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
- if (offchannel_flag || chan != local->hw.conf.channel ||
- channel_type != local->hw.conf.channel_type) {
- local->hw.conf.channel = chan;
- local->hw.conf.channel_type = channel_type;
+ if (offchannel_flag ||
+ !cfg80211_chandef_identical(&local->hw.conf.chandef,
+ &local->_oper_chandef)) {
+ local->hw.conf.chandef = chandef;
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
@@ -147,10 +151,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
changed |= IEEE80211_CONF_CHANGE_SMPS;
}
- scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
- test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
- test_bit(SCAN_HW_SCANNING, &local->scanning);
- power = chan->max_power;
+ power = chandef.chan->max_power;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
@@ -226,8 +227,6 @@ u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
static void ieee80211_tasklet_handler(unsigned long data)
{
struct ieee80211_local *local = (struct ieee80211_local *) data;
- struct sta_info *sta, *tmp;
- struct skb_eosp_msg_data *eosp_data;
struct sk_buff *skb;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -243,18 +242,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
skb->pkt_type = 0;
ieee80211_tx_status(&local->hw, skb);
break;
- case IEEE80211_EOSP_MSG:
- eosp_data = (void *)skb->cb;
- for_each_sta_info(local, eosp_data->sta, sta, tmp) {
- /* skip wrong virtual interface */
- if (memcmp(eosp_data->iface,
- sta->sdata->vif.addr, ETH_ALEN))
- continue;
- clear_sta_flag(sta, WLAN_STA_SP);
- break;
- }
- dev_kfree_skb(skb);
- break;
default:
WARN(1, "mac80211: Packet is of unknown type %d\n",
skb->pkt_type);
@@ -295,8 +282,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
"Hardware restart was requested\n");
/* use this reason, ieee80211_reconfig will unblock it */
- ieee80211_stop_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* Stop all Rx during the reconfig. We don't want state changes
@@ -399,30 +386,6 @@ static int ieee80211_ifa6_changed(struct notifier_block *nb,
}
#endif
-static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
-{
- struct ieee80211_local *local =
- container_of(napi, struct ieee80211_local, napi);
-
- return local->ops->napi_poll(&local->hw, budget);
-}
-
-void ieee80211_napi_schedule(struct ieee80211_hw *hw)
-{
- struct ieee80211_local *local = hw_to_local(hw);
-
- napi_schedule(&local->napi);
-}
-EXPORT_SYMBOL(ieee80211_napi_schedule);
-
-void ieee80211_napi_complete(struct ieee80211_hw *hw)
-{
- struct ieee80211_local *local = hw_to_local(hw);
-
- napi_complete(&local->napi);
-}
-EXPORT_SYMBOL(ieee80211_napi_complete);
-
/* There isn't a lot of sense in it, but you can transmit anything you like */
static const struct ieee80211_txrx_stypes
ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
@@ -501,6 +464,27 @@ static const struct ieee80211_ht_cap mac80211_ht_capa_mod_mask = {
},
};
+static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
+ .vht_cap_info =
+ cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC |
+ IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_RXSTBC_1 |
+ IEEE80211_VHT_CAP_RXSTBC_2 |
+ IEEE80211_VHT_CAP_RXSTBC_3 |
+ IEEE80211_VHT_CAP_RXSTBC_4 |
+ IEEE80211_VHT_CAP_TXSTBC |
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN |
+ IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK),
+ .supp_mcs = {
+ .rx_mcs_map = cpu_to_le16(~0),
+ .tx_mcs_map = cpu_to_le16(~0),
+ },
+};
+
static const u8 extended_capabilities[] = {
0, 0, 0, 0, 0, 0, 0,
WLAN_EXT_CAPA8_OPMODE_NOTIF,
@@ -572,7 +556,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
NL80211_FEATURE_SAE |
NL80211_FEATURE_HT_IBSS |
- NL80211_FEATURE_VIF_TXPOWER;
+ NL80211_FEATURE_VIF_TXPOWER |
+ NL80211_FEATURE_USERSPACE_MPM;
if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -607,8 +592,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI |
IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH;
+ local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
+ local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
+ wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
INIT_LIST_HEAD(&local->interfaces);
@@ -664,9 +652,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
- /* init dummy netdev for use w/ NAPI */
- init_dummy_netdev(&local->napi_dev);
-
ieee80211_led_names(local);
ieee80211_roc_setup(local);
@@ -683,6 +668,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
int channels, max_bitrates;
bool supp_ht, supp_vht;
netdev_features_t feature_whitelist;
+ struct cfg80211_chan_def dflt_chandef = {};
static const u32 cipher_suites[] = {
/* keep WEP first, it may be removed below */
WLAN_CIPHER_SUITE_WEP40,
@@ -760,15 +746,19 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sband = local->hw.wiphy->bands[band];
if (!sband)
continue;
- if (!local->use_chanctx && !local->_oper_channel) {
+
+ if (!dflt_chandef.chan) {
+ cfg80211_chandef_create(&dflt_chandef,
+ &sband->channels[0],
+ NL80211_CHAN_NO_HT);
/* init channel we're on */
- local->hw.conf.channel =
- local->_oper_channel = &sband->channels[0];
- local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
+ if (!local->use_chanctx && !local->_oper_chandef.chan) {
+ local->hw.conf.chandef = dflt_chandef;
+ local->_oper_chandef = dflt_chandef;
+ }
+ local->monitor_chandef = dflt_chandef;
}
- cfg80211_chandef_create(&local->monitor_chandef,
- &sband->channels[0],
- NL80211_CHAN_NO_HT);
+
channels += sband->n_channels;
if (max_bitrates < sband->n_bitrates)
@@ -851,22 +841,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (supp_ht)
local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
- if (supp_vht) {
+ if (supp_vht)
local->scan_ies_len +=
2 + sizeof(struct ieee80211_vht_cap);
- /*
- * (for now at least), drivers wanting to use VHT must
- * support channel contexts, as they contain all the
- * necessary VHT information and the global hw config
- * doesn't (yet)
- */
- if (WARN_ON(!local->use_chanctx)) {
- result = -EINVAL;
- goto fail_wiphy_register;
- }
- }
-
if (!local->ops->hw_scan) {
/* For hw_scan, driver needs to set these up. */
local->hw.wiphy->max_scan_ssids = 4;
@@ -1021,9 +999,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_ifa6;
#endif
- netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
- local->hw.napi_weight);
-
return 0;
#if IS_ENABLED(CONFIG_IPV6)
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29ce2aa87e7b..6952760881c8 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,10 +13,6 @@
#include "ieee80211_i.h"
#include "mesh.h"
-#define TMR_RUNNING_HK 0
-#define TMR_RUNNING_MP 1
-#define TMR_RUNNING_MPR 2
-
static int mesh_allocated;
static struct kmem_cache *rm_cache;
@@ -50,11 +46,6 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
- if (local->quiescing) {
- set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
- return;
- }
-
ieee80211_queue_work(&local->hw, &sdata->work);
}
@@ -165,7 +156,7 @@ void mesh_sta_cleanup(struct sta_info *sta)
* an update.
*/
changed = mesh_accept_plinks_update(sdata);
- if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
+ if (!sdata->u.mesh.user_mpm) {
changed |= mesh_plink_deactivate(sta);
del_timer_sync(&sta->plink_timer);
}
@@ -479,15 +470,8 @@ static void ieee80211_mesh_path_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct ieee80211_local *local = sdata->local;
-
- if (local->quiescing) {
- set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
- return;
- }
- ieee80211_queue_work(&local->hw, &sdata->work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
static void ieee80211_mesh_path_root_timer(unsigned long data)
@@ -495,16 +479,10 @@ static void ieee80211_mesh_path_root_timer(unsigned long data)
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
- struct ieee80211_local *local = sdata->local;
set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
- if (local->quiescing) {
- set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
- return;
- }
-
- ieee80211_queue_work(&local->hw, &sdata->work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -622,35 +600,6 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
round_jiffies(TU_TO_EXP_TIME(interval)));
}
-#ifdef CONFIG_PM
-void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-
- /* use atomic bitops in case all timers fire at the same time */
-
- if (del_timer_sync(&ifmsh->housekeeping_timer))
- set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
- if (del_timer_sync(&ifmsh->mesh_path_timer))
- set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
- if (del_timer_sync(&ifmsh->mesh_path_root_timer))
- set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running);
-}
-
-void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-
- if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
- add_timer(&ifmsh->housekeeping_timer);
- if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
- add_timer(&ifmsh->mesh_path_timer);
- if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running))
- add_timer(&ifmsh->mesh_path_root_timer);
- ieee80211_mesh_root_setup(ifmsh);
-}
-#endif
-
static int
ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
{
@@ -750,10 +699,8 @@ out_free:
static int
ieee80211_mesh_rebuild_beacon(struct ieee80211_if_mesh *ifmsh)
{
- struct ieee80211_sub_if_data *sdata;
struct beacon_data *old_bcn;
int ret;
- sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
mutex_lock(&ifmsh->mtx);
@@ -871,8 +818,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
local->fif_other_bss--;
atomic_dec(&local->iff_allmultis);
ieee80211_configure_filter(local);
-
- sdata->u.mesh.timers_running = 0;
}
static void
@@ -886,15 +831,14 @@ ieee80211_mesh_rx_probe_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *hdr;
struct ieee802_11_elems elems;
size_t baselen;
- u8 *pos, *end;
+ u8 *pos;
- end = ((u8 *) mgmt) + len;
pos = mgmt->u.probe_req.variable;
baselen = (u8 *) pos - (u8 *) mgmt;
if (baselen > len)
return;
- ieee802_11_parse_elems(pos, len - baselen, &elems);
+ ieee802_11_parse_elems(pos, len - baselen, false, &elems);
/* 802.11-2012 10.1.4.3.2 */
if ((!ether_addr_equal(mgmt->da, sdata->vif.addr) &&
@@ -955,7 +899,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
return;
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
- &elems);
+ false, &elems);
/* ignore non-mesh or secure / unsecure mismatch */
if ((!elems.mesh_id || !elems.mesh_config) ||
@@ -963,7 +907,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
(!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE))
return;
- if (elems.ds_params && elems.ds_params_len == 1)
+ if (elems.ds_params)
freq = ieee80211_channel_to_frequency(elems.ds_params[0], band);
else
freq = rx_status->freq;
@@ -1060,7 +1004,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
- if (ieee80211_vif_is_mesh(&sdata->vif))
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ ieee80211_sdata_running(sdata))
ieee80211_queue_work(&local->hw, &sdata->work);
rcu_read_unlock();
}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 336c88a16687..da158774eebb 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -275,7 +275,8 @@ void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len);
-int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
+struct mesh_path *
+mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst);
int mesh_path_add_gate(struct mesh_path *mpath);
int mesh_path_send_to_gates(struct mesh_path *mpath);
@@ -313,8 +314,6 @@ void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_discard_frame(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
-void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
-void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
@@ -359,22 +358,12 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
-void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
-void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
-void mesh_plink_quiesce(struct sta_info *sta);
-void mesh_plink_restart(struct sta_info *sta);
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
void ieee80211s_stop(void);
#else
static inline void
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
-static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
-{}
-static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
-{}
-static inline void mesh_plink_quiesce(struct sta_info *sta) {}
-static inline void mesh_plink_restart(struct sta_info *sta) {}
static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
{ return false; }
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index bdb8d3b14587..486819cd02cd 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -144,7 +144,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
*pos++ = WLAN_EID_PREQ;
break;
case MPATH_PREP:
- mhwmp_dbg(sdata, "sending PREP to %pM\n", target);
+ mhwmp_dbg(sdata, "sending PREP to %pM\n", orig_addr);
ie_len = 31;
pos = skb_put(skb, 2 + ie_len);
*pos++ = WLAN_EID_PREP;
@@ -445,9 +445,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
}
}
} else {
- mesh_path_add(sdata, orig_addr);
- mpath = mesh_path_lookup(sdata, orig_addr);
- if (!mpath) {
+ mpath = mesh_path_add(sdata, orig_addr);
+ if (IS_ERR(mpath)) {
rcu_read_unlock();
return 0;
}
@@ -486,9 +485,8 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
(last_hop_metric > mpath->metric)))
fresh_info = false;
} else {
- mesh_path_add(sdata, ta);
- mpath = mesh_path_lookup(sdata, ta);
- if (!mpath) {
+ mpath = mesh_path_add(sdata, ta);
+ if (IS_ERR(mpath)) {
rcu_read_unlock();
return 0;
}
@@ -661,7 +659,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
u32 target_sn, orig_sn, lifetime;
mhwmp_dbg(sdata, "received PREP from %pM\n",
- PREP_IE_ORIG_ADDR(prep_elem));
+ PREP_IE_TARGET_ADDR(prep_elem));
orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
if (ether_addr_equal(orig_addr, sdata->vif.addr))
@@ -804,9 +802,8 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
mpath = mesh_path_lookup(sdata, orig_addr);
if (!mpath) {
- mesh_path_add(sdata, orig_addr);
- mpath = mesh_path_lookup(sdata, orig_addr);
- if (!mpath) {
+ mpath = mesh_path_add(sdata, orig_addr);
+ if (IS_ERR(mpath)) {
rcu_read_unlock();
sdata->u.mesh.mshstats.dropped_frames_no_route++;
return;
@@ -883,7 +880,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
- len - baselen, &elems);
+ len - baselen, false, &elems);
if (elems.preq) {
if (elems.preq_len != 37)
@@ -1098,11 +1095,10 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
/* no nexthop found, start resolving */
mpath = mesh_path_lookup(sdata, target_addr);
if (!mpath) {
- mesh_path_add(sdata, target_addr);
- mpath = mesh_path_lookup(sdata, target_addr);
- if (!mpath) {
+ mpath = mesh_path_add(sdata, target_addr);
+ if (IS_ERR(mpath)) {
mesh_path_discard_frame(sdata, skb);
- err = -ENOSPC;
+ err = PTR_ERR(mpath);
goto endlookup;
}
}
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index dc7c8df40c2c..89aacfd2756d 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -493,7 +493,8 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata)
*
* State: the initial state of the new path is set to 0
*/
-int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
+struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
+ const u8 *dst)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
@@ -502,18 +503,33 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
struct mpath_node *node, *new_node;
struct hlist_head *bucket;
int grow = 0;
- int err = 0;
+ int err;
u32 hash_idx;
if (ether_addr_equal(dst, sdata->vif.addr))
/* never add ourselves as neighbours */
- return -ENOTSUPP;
+ return ERR_PTR(-ENOTSUPP);
if (is_multicast_ether_addr(dst))
- return -ENOTSUPP;
+ return ERR_PTR(-ENOTSUPP);
if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0)
- return -ENOSPC;
+ return ERR_PTR(-ENOSPC);
+
+ read_lock_bh(&pathtbl_resize_lock);
+ tbl = resize_dereference_mesh_paths();
+
+ hash_idx = mesh_table_hash(dst, sdata, tbl);
+ bucket = &tbl->hash_buckets[hash_idx];
+
+ spin_lock(&tbl->hashwlock[hash_idx]);
+
+ hlist_for_each_entry(node, bucket, list) {
+ mpath = node->mpath;
+ if (mpath->sdata == sdata &&
+ ether_addr_equal(dst, mpath->dst))
+ goto found;
+ }
err = -ENOMEM;
new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
@@ -524,7 +540,6 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
if (!new_node)
goto err_node_alloc;
- read_lock_bh(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
eth_broadcast_addr(new_mpath->rann_snd_addr);
new_mpath->is_root = false;
@@ -538,21 +553,6 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
spin_lock_init(&new_mpath->state_lock);
init_timer(&new_mpath->timer);
- tbl = resize_dereference_mesh_paths();
-
- hash_idx = mesh_table_hash(dst, sdata, tbl);
- bucket = &tbl->hash_buckets[hash_idx];
-
- spin_lock(&tbl->hashwlock[hash_idx]);
-
- err = -EEXIST;
- hlist_for_each_entry(node, bucket, list) {
- mpath = node->mpath;
- if (mpath->sdata == sdata &&
- ether_addr_equal(dst, mpath->dst))
- goto err_exists;
- }
-
hlist_add_head_rcu(&new_node->list, bucket);
if (atomic_inc_return(&tbl->entries) >=
tbl->mean_chain_len * (tbl->hash_mask + 1))
@@ -560,23 +560,23 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst)
mesh_paths_generation++;
- spin_unlock(&tbl->hashwlock[hash_idx]);
- read_unlock_bh(&pathtbl_resize_lock);
if (grow) {
set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
}
- return 0;
-
-err_exists:
+ mpath = new_mpath;
+found:
spin_unlock(&tbl->hashwlock[hash_idx]);
read_unlock_bh(&pathtbl_resize_lock);
- kfree(new_node);
+ return mpath;
+
err_node_alloc:
kfree(new_mpath);
err_path_alloc:
atomic_dec(&sdata->u.mesh.mpaths);
- return err;
+ spin_unlock(&tbl->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
+ return ERR_PTR(err);
}
static void mesh_table_free_rcu(struct rcu_head *rcu)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 07d396d57079..09bebed99416 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -420,7 +420,6 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
return NULL;
sta->plink_state = NL80211_PLINK_LISTEN;
- init_timer(&sta->plink_timer);
sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
@@ -437,8 +436,9 @@ mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *addr,
{
struct sta_info *sta = NULL;
- /* Userspace handles peer allocation when security is enabled */
- if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
+ /* Userspace handles station allocation */
+ if (sdata->u.mesh.user_mpm ||
+ sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
cfg80211_notify_new_peer_candidate(sdata->dev, addr,
elems->ie_start,
elems->total_len,
@@ -534,10 +534,8 @@ static void mesh_plink_timer(unsigned long data)
*/
sta = (struct sta_info *) data;
- if (sta->sdata->local->quiescing) {
- sta->plink_timer_was_running = true;
+ if (sta->sdata->local->quiescing)
return;
- }
spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) {
@@ -546,8 +544,8 @@ static void mesh_plink_timer(unsigned long data)
return;
}
mpl_dbg(sta->sdata,
- "Mesh plink timer for %pM fired on state %d\n",
- sta->sta.addr, sta->plink_state);
+ "Mesh plink timer for %pM fired on state %s\n",
+ sta->sta.addr, mplstates[sta->plink_state]);
reason = 0;
llid = sta->llid;
plid = sta->plid;
@@ -598,29 +596,6 @@ static void mesh_plink_timer(unsigned long data)
}
}
-#ifdef CONFIG_PM
-void mesh_plink_quiesce(struct sta_info *sta)
-{
- if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
- return;
-
- /* no kernel mesh sta timers have been initialized */
- if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
- return;
-
- if (del_timer_sync(&sta->plink_timer))
- sta->plink_timer_was_running = true;
-}
-
-void mesh_plink_restart(struct sta_info *sta)
-{
- if (sta->plink_timer_was_running) {
- add_timer(&sta->plink_timer);
- sta->plink_timer_was_running = false;
- }
-}
-#endif
-
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
{
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
@@ -695,6 +670,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
return;
+ if (sdata->u.mesh.user_mpm)
+ /* userspace must register for these */
+ return;
+
if (is_multicast_ether_addr(mgmt->da)) {
mpl_dbg(sdata,
"Mesh plink: ignore frame from multicast address\n");
@@ -708,7 +687,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
baseaddr += 4;
baselen += 4;
}
- ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
+ ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
if (!elems.peering) {
mpl_dbg(sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 141577412d84..29620bfc7a69 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -56,7 +56,10 @@ MODULE_PARM_DESC(max_probe_tries,
* probe on beacon miss before declaring the connection lost
* default to what we want.
*/
-#define IEEE80211_BEACON_LOSS_COUNT 7
+static int beacon_loss_count = 7;
+module_param(beacon_loss_count, int, 0644);
+MODULE_PARM_DESC(beacon_loss_count,
+ "Number of beacon intervals before we decide beacon was lost.");
/*
* Time the connection can be idle before we probe
@@ -87,9 +90,6 @@ MODULE_PARM_DESC(probe_wait_ms,
*/
#define IEEE80211_SIGNAL_AVE_MIN_COUNT 4
-#define TMR_RUNNING_TIMER 0
-#define TMR_RUNNING_CHANSW 1
-
/*
* All cfg80211 functions have to be called outside a locked
* section so that they can acquire a lock themselves... This
@@ -289,6 +289,8 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
} else {
/* 40 MHz (and 80 MHz) must be supported for VHT */
ret = IEEE80211_STA_DISABLE_VHT;
+ /* also mark 40 MHz disabled */
+ ret |= IEEE80211_STA_DISABLE_40MHZ;
goto out;
}
@@ -303,12 +305,6 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
channel->band);
vht_chandef.center_freq2 = 0;
- if (vht_oper->center_freq_seg2_idx)
- vht_chandef.center_freq2 =
- ieee80211_channel_to_frequency(
- vht_oper->center_freq_seg2_idx,
- channel->band);
-
switch (vht_oper->chan_width) {
case IEEE80211_VHT_CHANWIDTH_USE_HT:
vht_chandef.width = chandef->width;
@@ -321,6 +317,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
break;
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
+ vht_chandef.center_freq2 =
+ ieee80211_channel_to_frequency(
+ vht_oper->center_freq_seg2_idx,
+ channel->band);
break;
default:
if (verbose)
@@ -604,11 +604,11 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
u8 *pos;
u32 cap;
struct ieee80211_sta_vht_cap vht_cap;
- int i;
BUILD_BUG_ON(sizeof(vht_cap) != sizeof(sband->vht_cap));
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
+ ieee80211_apply_vhtcap_overrides(sdata, &vht_cap);
/* determine capability flags */
cap = vht_cap.cap;
@@ -631,37 +631,6 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)))
cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
- if (!(ap_vht_cap->vht_cap_info &
- cpu_to_le32(IEEE80211_VHT_CAP_TXSTBC)))
- cap &= ~(IEEE80211_VHT_CAP_RXSTBC_1 |
- IEEE80211_VHT_CAP_RXSTBC_3 |
- IEEE80211_VHT_CAP_RXSTBC_4);
-
- for (i = 0; i < 8; i++) {
- int shift = i * 2;
- u16 mask = IEEE80211_VHT_MCS_NOT_SUPPORTED << shift;
- u16 ap_mcs, our_mcs;
-
- ap_mcs = (le16_to_cpu(ap_vht_cap->supp_mcs.tx_mcs_map) &
- mask) >> shift;
- our_mcs = (le16_to_cpu(vht_cap.vht_mcs.rx_mcs_map) &
- mask) >> shift;
-
- if (our_mcs == IEEE80211_VHT_MCS_NOT_SUPPORTED)
- continue;
-
- switch (ap_mcs) {
- default:
- if (our_mcs <= ap_mcs)
- break;
- /* fall through */
- case IEEE80211_VHT_MCS_NOT_SUPPORTED:
- vht_cap.vht_mcs.rx_mcs_map &= cpu_to_le16(~mask);
- vht_cap.vht_mcs.rx_mcs_map |=
- cpu_to_le16(ap_mcs << shift);
- }
- }
-
/* reserve and fill IE */
pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2);
ieee80211_ie_build_vht_cap(pos, &vht_cap, cap);
@@ -987,6 +956,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
if (!ieee80211_sdata_running(sdata))
@@ -996,21 +966,22 @@ static void ieee80211_chswitch_work(struct work_struct *work)
if (!ifmgd->associated)
goto out;
- sdata->local->_oper_channel = sdata->local->csa_channel;
- if (!sdata->local->ops->channel_switch) {
+ local->_oper_chandef = local->csa_chandef;
+
+ if (!local->ops->channel_switch) {
/* call "hw_config" only if doing sw channel switch */
- ieee80211_hw_config(sdata->local,
- IEEE80211_CONF_CHANGE_CHANNEL);
+ ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
} else {
/* update the device channel directly */
- sdata->local->hw.conf.channel = sdata->local->_oper_channel;
+ local->hw.conf.chandef = local->_oper_chandef;
}
/* XXX: shouldn't really modify cfg80211-owned data! */
- ifmgd->associated->channel = sdata->local->_oper_channel;
+ ifmgd->associated->channel = local->_oper_chandef.chan;
/* XXX: wait for a beacon first? */
- ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ ieee80211_wake_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
out:
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
@@ -1038,66 +1009,197 @@ static void ieee80211_chswitch_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
- if (sdata->local->quiescing) {
- set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
- return;
- }
- ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work);
}
-void
+static void
ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
- const struct ieee80211_channel_sw_ie *sw_elem,
- struct ieee80211_bss *bss, u64 timestamp)
+ u64 timestamp, struct ieee802_11_elems *elems)
{
- struct cfg80211_bss *cbss =
- container_of((void *)bss, struct cfg80211_bss, priv);
- struct ieee80211_channel *new_ch;
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num,
- cbss->channel->band);
+ struct cfg80211_bss *cbss = ifmgd->associated;
+ struct ieee80211_bss *bss;
struct ieee80211_chanctx *chanctx;
+ enum ieee80211_band new_band;
+ int new_freq;
+ u8 new_chan_no;
+ u8 count;
+ u8 mode;
+ struct ieee80211_channel *new_chan;
+ struct cfg80211_chan_def new_chandef = {};
+ struct cfg80211_chan_def new_vht_chandef = {};
+ const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+ const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
+ int secondary_channel_offset = -1;
ASSERT_MGD_MTX(ifmgd);
- if (!ifmgd->associated)
+ if (!cbss)
return;
- if (sdata->local->scanning)
+ if (local->scanning)
return;
- /* Disregard subsequent beacons if we are already running a timer
- processing a CSA */
-
+ /* disregard subsequent announcements if we are already processing */
if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
return;
- new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
- if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED) {
+ sec_chan_offs = elems->sec_chan_offs;
+ wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
+
+ if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
+ IEEE80211_STA_DISABLE_40MHZ)) {
+ sec_chan_offs = NULL;
+ wide_bw_chansw_ie = NULL;
+ }
+
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
+ wide_bw_chansw_ie = NULL;
+
+ if (elems->ext_chansw_ie) {
+ if (!ieee80211_operating_class_to_band(
+ elems->ext_chansw_ie->new_operating_class,
+ &new_band)) {
+ sdata_info(sdata,
+ "cannot understand ECSA IE operating class %d, disconnecting\n",
+ elems->ext_chansw_ie->new_operating_class);
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ }
+ new_chan_no = elems->ext_chansw_ie->new_ch_num;
+ count = elems->ext_chansw_ie->count;
+ mode = elems->ext_chansw_ie->mode;
+ } else if (elems->ch_switch_ie) {
+ new_band = cbss->channel->band;
+ new_chan_no = elems->ch_switch_ie->new_ch_num;
+ count = elems->ch_switch_ie->count;
+ mode = elems->ch_switch_ie->mode;
+ } else {
+ /* nothing here we understand */
+ return;
+ }
+
+ bss = (void *)cbss->priv;
+
+ new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
+ new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+ if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
sdata_info(sdata,
"AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
ifmgd->associated->bssid, new_freq);
- ieee80211_queue_work(&sdata->local->hw,
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ return;
+ }
+
+ if (sec_chan_offs) {
+ secondary_channel_offset = sec_chan_offs->sec_chan_offs;
+ } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
+ /* if HT is enabled and the IE not present, it's still HT */
+ secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ }
+
+ switch (secondary_channel_offset) {
+ default:
+ /* secondary_channel_offset was present but is invalid */
+ case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT20);
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT40PLUS);
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_HT40MINUS);
+ break;
+ case -1:
+ cfg80211_chandef_create(&new_chandef, new_chan,
+ NL80211_CHAN_NO_HT);
+ break;
+ }
+
+ if (wide_bw_chansw_ie) {
+ new_vht_chandef.chan = new_chan;
+ new_vht_chandef.center_freq1 =
+ ieee80211_channel_to_frequency(
+ wide_bw_chansw_ie->new_center_freq_seg0,
+ new_band);
+
+ switch (wide_bw_chansw_ie->new_channel_width) {
+ default:
+ /* hmmm, ignore VHT and use HT if present */
+ case IEEE80211_VHT_CHANWIDTH_USE_HT:
+ new_vht_chandef.chan = NULL;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80MHZ:
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_160MHZ:
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
+ break;
+ case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+ /* field is otherwise reserved */
+ new_vht_chandef.center_freq2 =
+ ieee80211_channel_to_frequency(
+ wide_bw_chansw_ie->new_center_freq_seg1,
+ new_band);
+ new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
+ break;
+ }
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+ new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
+ chandef_downgrade(&new_vht_chandef);
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
+ new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
+ chandef_downgrade(&new_vht_chandef);
+ if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
+ new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
+ chandef_downgrade(&new_vht_chandef);
+ }
+
+ /* if VHT data is there validate & use it */
+ if (new_vht_chandef.chan) {
+ if (!cfg80211_chandef_compatible(&new_vht_chandef,
+ &new_chandef)) {
+ sdata_info(sdata,
+ "AP %pM CSA has inconsistent channel data, disconnecting\n",
+ ifmgd->associated->bssid);
+ ieee80211_queue_work(&local->hw,
+ &ifmgd->csa_connection_drop_work);
+ return;
+ }
+ new_chandef = new_vht_chandef;
+ }
+
+ if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
+ IEEE80211_CHAN_DISABLED)) {
+ sdata_info(sdata,
+ "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+ ifmgd->associated->bssid, new_freq,
+ new_chandef.width, new_chandef.center_freq1,
+ new_chandef.center_freq2);
+ ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
return;
}
ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
- if (sdata->local->use_chanctx) {
+ if (local->use_chanctx) {
sdata_info(sdata,
"not handling channel switch with channel contexts\n");
- ieee80211_queue_work(&sdata->local->hw,
+ ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
return;
}
- mutex_lock(&sdata->local->chanctx_mtx);
+ mutex_lock(&local->chanctx_mtx);
if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
- mutex_unlock(&sdata->local->chanctx_mtx);
+ mutex_unlock(&local->chanctx_mtx);
return;
}
chanctx = container_of(rcu_access_pointer(sdata->vif.chanctx_conf),
@@ -1105,39 +1207,39 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (chanctx->refcount > 1) {
sdata_info(sdata,
"channel switch with multiple interfaces on the same channel, disconnecting\n");
- ieee80211_queue_work(&sdata->local->hw,
+ ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
- mutex_unlock(&sdata->local->chanctx_mtx);
+ mutex_unlock(&local->chanctx_mtx);
return;
}
- mutex_unlock(&sdata->local->chanctx_mtx);
+ mutex_unlock(&local->chanctx_mtx);
- sdata->local->csa_channel = new_ch;
+ local->csa_chandef = new_chandef;
- if (sw_elem->mode)
- ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ if (mode)
+ ieee80211_stop_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
- if (sdata->local->ops->channel_switch) {
+ if (local->ops->channel_switch) {
/* use driver's channel switch callback */
struct ieee80211_channel_switch ch_switch = {
.timestamp = timestamp,
- .block_tx = sw_elem->mode,
- .channel = new_ch,
- .count = sw_elem->count,
+ .block_tx = mode,
+ .chandef = new_chandef,
+ .count = count,
};
- drv_channel_switch(sdata->local, &ch_switch);
+ drv_channel_switch(local, &ch_switch);
return;
}
/* channel switch handled in software */
- if (sw_elem->count <= 1)
- ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+ if (count <= 1)
+ ieee80211_queue_work(&local->hw, &ifmgd->chswitch_work);
else
mod_timer(&ifmgd->chswitch_timer,
- TU_TO_EXP_TIME(sw_elem->count *
- cbss->beacon_interval));
+ TU_TO_EXP_TIME(count * cbss->beacon_interval));
}
static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
@@ -1383,6 +1485,7 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
}
ieee80211_wake_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_PS);
}
@@ -1435,16 +1538,14 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
- netif_tx_stop_all_queues(sdata->dev);
-
- if (drv_tx_frames_pending(local))
+ if (drv_tx_frames_pending(local)) {
mod_timer(&local->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
- else {
+ } else {
ieee80211_send_nullfunc(local, sdata, 1);
/* Flush to get the tx status of nullfunc frame */
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
}
}
@@ -1455,9 +1556,6 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
local->hw.conf.flags |= IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
-
- if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
- netif_tx_wake_all_queues(sdata->dev);
}
void ieee80211_dynamic_ps_timer(unsigned long data)
@@ -1563,6 +1661,7 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
params.cw_min = ecw2cw(pos[1] & 0x0f);
params.txop = get_unaligned_le16(pos + 2);
+ params.acm = acm;
params.uapsd = uapsd;
mlme_dbg(sdata,
@@ -1650,7 +1749,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value);
sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
- IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
+ beacon_loss_count * bss_conf->beacon_int));
sdata->u.mgd.associated = cbss;
memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
@@ -1663,18 +1762,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();
ies = rcu_dereference(cbss->ies);
if (ies) {
- u8 noa[2];
int ret;
ret = cfg80211_get_p2p_attr(
ies->data, ies->len,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
- noa, sizeof(noa));
+ (u8 *) &bss_conf->p2p_noa_attr,
+ sizeof(bss_conf->p2p_noa_attr));
if (ret >= 2) {
- bss_conf->p2p_oppps = noa[1] & 0x80;
- bss_conf->p2p_ctwindow = noa[1] & 0x7f;
+ sdata->u.mgd.p2p_noa_index =
+ bss_conf->p2p_noa_attr.index;
bss_info_changed |= BSS_CHANGED_P2P_PS;
- sdata->u.mgd.p2p_noa_index = noa[0];
}
}
rcu_read_unlock();
@@ -1718,7 +1816,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_smps(sdata);
ieee80211_recalc_ps_vif(sdata);
- netif_tx_start_all_queues(sdata->dev);
netif_carrier_on(sdata->dev);
}
@@ -1741,22 +1838,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
ieee80211_stop_poll(sdata);
ifmgd->associated = NULL;
-
- /*
- * we need to commit the associated = NULL change because the
- * scan code uses that to determine whether this iface should
- * go to/wake up from powersave or not -- and could otherwise
- * wake the queues erroneously.
- */
- smp_mb();
-
- /*
- * Thus, we can only afterwards stop the queues -- to account
- * for the case where another CPU is finishing a scan at this
- * time -- we don't want the scan code to enable queues.
- */
-
- netif_tx_stop_all_queues(sdata->dev);
netif_carrier_off(sdata->dev);
/*
@@ -1775,7 +1856,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
if (tx)
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
/* deauthenticate/disassociate now */
if (tx || frame_buf)
@@ -1784,7 +1865,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
/* flush out frame */
if (tx)
- drv_flush(local, false);
+ ieee80211_flush_queues(local, sdata);
/* clear bssid only after building the needed mgmt frames */
memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -1799,12 +1880,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_ASSOC;
sdata->vif.bss_conf.assoc = false;
- sdata->vif.bss_conf.p2p_ctwindow = 0;
- sdata->vif.bss_conf.p2p_oppps = false;
+ ifmgd->p2p_noa_index = -1;
+ memset(&sdata->vif.bss_conf.p2p_noa_attr, 0,
+ sizeof(sdata->vif.bss_conf.p2p_noa_attr));
- /* on the next assoc, re-program HT parameters */
+ /* on the next assoc, re-program HT/VHT parameters */
memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
+ memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
+ memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -1830,8 +1914,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
del_timer_sync(&sdata->u.mgd.timer);
del_timer_sync(&sdata->u.mgd.chswitch_timer);
- sdata->u.mgd.timers_running = 0;
-
sdata->vif.bss_conf.dtim_period = 0;
ifmgd->flags = 0;
@@ -1956,7 +2038,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
run_again(ifmgd, ifmgd->probe_timeout);
if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
- drv_flush(sdata->local, false);
+ ieee80211_flush_queues(sdata->local, sdata);
}
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
@@ -1980,12 +2062,15 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
goto out;
}
- if (beacon)
+ if (beacon) {
mlme_dbg_ratelimited(sdata,
- "detected beacon loss from AP - probing\n");
+ "detected beacon loss from AP (missed %d beacons) - probing\n",
+ beacon_loss_count);
- ieee80211_cqm_rssi_notify(&sdata->vif,
- NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL);
+ ieee80211_cqm_rssi_notify(&sdata->vif,
+ NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
+ GFP_KERNEL);
+ }
/*
* The driver/our work has already reported this event or the
@@ -2079,6 +2164,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
true, frame_buf);
ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_CSA);
mutex_unlock(&ifmgd->mtx);
@@ -2130,7 +2216,6 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
trace_api_beacon_loss(sdata);
- WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
sdata->u.mgd.connection_loss = false;
ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
}
@@ -2180,7 +2265,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
u32 tx_flags = 0;
pos = mgmt->u.auth.variable;
- ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
if (!elems.challenge)
return;
auth_data->expected_transaction = 4;
@@ -2445,7 +2530,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
}
pos = mgmt->u.assoc_resp.variable;
- ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
if (!elems.supp_rates) {
sdata_info(sdata, "no SuppRates element in AssocResp\n");
@@ -2614,13 +2699,13 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
pos = mgmt->u.assoc_resp.variable;
- ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
+ ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
- elems.timeout_int && elems.timeout_int_len == 5 &&
- elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
+ elems.timeout_int &&
+ elems.timeout_int->type == WLAN_TIMEOUT_ASSOC_COMEBACK) {
u32 tu, ms;
- tu = get_unaligned_le32(elems.timeout_int + 1);
+ tu = le32_to_cpu(elems.timeout_int->value);
ms = tu * 1024 / 1000;
sdata_info(sdata,
"%pM rejected association temporarily; comeback duration %u TU (%u ms)\n",
@@ -2669,6 +2754,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *channel;
bool need_ps = false;
+ lockdep_assert_held(&sdata->u.mgd.mtx);
+
if ((sdata->u.mgd.associated &&
ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) ||
(sdata->u.mgd.assoc_data &&
@@ -2683,7 +2770,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
}
}
- if (elems->ds_params && elems->ds_params_len == 1)
+ if (elems->ds_params)
freq = ieee80211_channel_to_frequency(elems->ds_params[0],
rx_status->band);
else
@@ -2699,7 +2786,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (bss)
ieee80211_rx_bss_put(local, bss);
- if (!sdata->u.mgd.associated)
+ if (!sdata->u.mgd.associated ||
+ !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
return;
if (need_ps) {
@@ -2708,10 +2796,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
mutex_unlock(&local->iflist_mtx);
}
- if (elems->ch_switch_ie &&
- memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, ETH_ALEN) == 0)
- ieee80211_sta_process_chanswitch(sdata, elems->ch_switch_ie,
- bss, rx_status->mactime);
+ ieee80211_sta_process_chanswitch(sdata, rx_status->mactime, elems);
+
}
@@ -2736,7 +2822,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
return;
ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
- &elems);
+ false, &elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
@@ -2819,7 +2905,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
ieee802_11_parse_elems(mgmt->u.beacon.variable,
- len - baselen, &elems);
+ len - baselen, false, &elems);
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
ifmgd->assoc_data->have_beacon = true;
@@ -2929,7 +3015,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
- len - baselen, &elems,
+ len - baselen, false, &elems,
care_about_ies, ncrc);
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
@@ -2961,22 +3047,30 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
if (sdata->vif.p2p) {
- u8 noa[2];
+ struct ieee80211_p2p_noa_attr noa = {};
int ret;
ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
len - baselen,
IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
- noa, sizeof(noa));
- if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) {
- bss_conf->p2p_oppps = noa[1] & 0x80;
- bss_conf->p2p_ctwindow = noa[1] & 0x7f;
+ (u8 *) &noa, sizeof(noa));
+ if (ret >= 2) {
+ if (sdata->u.mgd.p2p_noa_index != noa.index) {
+ /* valid noa_attr and index changed */
+ sdata->u.mgd.p2p_noa_index = noa.index;
+ memcpy(&bss_conf->p2p_noa_attr, &noa, sizeof(noa));
+ changed |= BSS_CHANGED_P2P_PS;
+ /*
+ * make sure we update all information, the CRC
+ * mechanism doesn't look at P2P attributes.
+ */
+ ifmgd->beacon_crc_valid = false;
+ }
+ } else if (sdata->u.mgd.p2p_noa_index != -1) {
+ /* noa_attr not found and we had valid noa_attr before */
+ sdata->u.mgd.p2p_noa_index = -1;
+ memset(&bss_conf->p2p_noa_attr, 0, sizeof(bss_conf->p2p_noa_attr));
changed |= BSS_CHANGED_P2P_PS;
- sdata->u.mgd.p2p_noa_index = noa[0];
- /*
- * make sure we update all information, the CRC
- * mechanism doesn't look at P2P attributes.
- */
ifmgd->beacon_crc_valid = false;
}
}
@@ -3018,7 +3112,7 @@ ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
changed |= BSS_CHANGED_DTIM_PERIOD;
}
- if (elems.erp_info && elems.erp_info_len >= 1) {
+ if (elems.erp_info) {
erp_valid = true;
erp_value = elems.erp_info[0];
} else {
@@ -3068,6 +3162,8 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
enum rx_mgmt_action rma = RX_MGMT_NONE;
u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
u16 fc;
+ struct ieee802_11_elems elems;
+ int ies_len;
rx_status = (struct ieee80211_rx_status *) skb->cb;
mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -3097,14 +3193,48 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
rma = ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, &bss);
break;
case IEEE80211_STYPE_ACTION:
- switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_SPECTRUM_MGMT:
+ if (mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT) {
+ ies_len = skb->len -
+ offsetof(struct ieee80211_mgmt,
+ u.action.u.chan_switch.variable);
+
+ if (ies_len < 0)
+ break;
+
+ ieee802_11_parse_elems(
+ mgmt->u.action.u.chan_switch.variable,
+ ies_len, true, &elems);
+
+ if (elems.parse_error)
+ break;
+
ieee80211_sta_process_chanswitch(sdata,
- &mgmt->u.action.u.chan_switch.sw_elem,
- (void *)ifmgd->associated->priv,
- rx_status->mactime);
- break;
+ rx_status->mactime,
+ &elems);
+ } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
+ ies_len = skb->len -
+ offsetof(struct ieee80211_mgmt,
+ u.action.u.ext_chan_switch.variable);
+
+ if (ies_len < 0)
+ break;
+
+ ieee802_11_parse_elems(
+ mgmt->u.action.u.ext_chan_switch.variable,
+ ies_len, true, &elems);
+
+ if (elems.parse_error)
+ break;
+
+ /* for the handling code pretend this was also an IE */
+ elems.ext_chansw_ie =
+ &mgmt->u.action.u.ext_chan_switch.data;
+
+ ieee80211_sta_process_chanswitch(sdata,
+ rx_status->mactime,
+ &elems);
}
+ break;
}
mutex_unlock(&ifmgd->mtx);
@@ -3140,15 +3270,8 @@ static void ieee80211_sta_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
(struct ieee80211_sub_if_data *) data;
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_local *local = sdata->local;
- if (local->quiescing) {
- set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
- return;
- }
-
- ieee80211_queue_work(&local->hw, &sdata->work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
@@ -3500,72 +3623,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
}
}
-#ifdef CONFIG_PM
-void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
- /*
- * Stop timers before deleting work items, as timers
- * could race and re-add the work-items. They will be
- * re-established on connection.
- */
- del_timer_sync(&ifmgd->conn_mon_timer);
- del_timer_sync(&ifmgd->bcn_mon_timer);
-
- /*
- * we need to use atomic bitops for the running bits
- * only because both timers might fire at the same
- * time -- the code here is properly synchronised.
- */
-
- cancel_work_sync(&ifmgd->request_smps_work);
-
- cancel_work_sync(&ifmgd->monitor_work);
- cancel_work_sync(&ifmgd->beacon_connection_loss_work);
- cancel_work_sync(&ifmgd->csa_connection_drop_work);
- if (del_timer_sync(&ifmgd->timer))
- set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
-
- if (del_timer_sync(&ifmgd->chswitch_timer))
- set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
- cancel_work_sync(&ifmgd->chswitch_work);
-}
-
-void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata)
-{
- struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-
- mutex_lock(&ifmgd->mtx);
- if (!ifmgd->associated) {
- mutex_unlock(&ifmgd->mtx);
- return;
- }
-
- if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
- sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
- mlme_dbg(sdata, "driver requested disconnect after resume\n");
- ieee80211_sta_connection_lost(sdata,
- ifmgd->associated->bssid,
- WLAN_REASON_UNSPECIFIED,
- true);
- mutex_unlock(&ifmgd->mtx);
- return;
- }
- mutex_unlock(&ifmgd->mtx);
-
- if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
- add_timer(&ifmgd->timer);
- if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
- add_timer(&ifmgd->chswitch_timer);
- ieee80211_sta_reset_beacon_monitor(sdata);
-
- mutex_lock(&sdata->local->mtx);
- ieee80211_restart_sta_timer(sdata);
- mutex_unlock(&sdata->local->mtx);
-}
-#endif
-
/* interface setup */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
@@ -3590,8 +3647,9 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifmgd->flags = 0;
ifmgd->powersave = sdata->wdev.ps;
- ifmgd->uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
- ifmgd->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
+ ifmgd->uapsd_queues = sdata->local->hw.uapsd_queues;
+ ifmgd->uapsd_max_sp_len = sdata->local->hw.uapsd_max_sp_len;
+ ifmgd->p2p_noa_index = -1;
mutex_init(&ifmgd->mtx);
@@ -3608,8 +3666,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
/* Restart STA timers */
rcu_read_lock();
- list_for_each_entry_rcu(sdata, &local->interfaces, list)
- ieee80211_restart_sta_timer(sdata);
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (ieee80211_sdata_running(sdata))
+ ieee80211_restart_sta_timer(sdata);
+ }
rcu_read_unlock();
}
@@ -3962,8 +4022,16 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
/* prep auth_data so we don't go into idle on disassoc */
ifmgd->auth_data = auth_data;
- if (ifmgd->associated)
- ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+ if (ifmgd->associated) {
+ u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+
+ ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+ WLAN_REASON_UNSPECIFIED,
+ false, frame_buf);
+
+ __cfg80211_send_deauth(sdata->dev, frame_buf,
+ sizeof(frame_buf));
+ }
sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
@@ -4023,8 +4091,16 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
mutex_lock(&ifmgd->mtx);
- if (ifmgd->associated)
- ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
+ if (ifmgd->associated) {
+ u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+
+ ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+ WLAN_REASON_UNSPECIFIED,
+ false, frame_buf);
+
+ __cfg80211_send_deauth(sdata->dev, frame_buf,
+ sizeof(frame_buf));
+ }
if (ifmgd->auth_data && !ifmgd->auth_data->done) {
err = -EBUSY;
@@ -4071,6 +4147,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
}
+ if (req->flags & ASSOC_REQ_DISABLE_VHT)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
+
/* Also disable HT if we don't support it or the AP doesn't use WMM */
sband = local->hw.wiphy->bands[req->bss->channel->band];
if (!sband->ht_cap.ht_supported ||
@@ -4094,6 +4173,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
memcpy(&ifmgd->ht_capa_mask, &req->ht_capa_mask,
sizeof(ifmgd->ht_capa_mask));
+ memcpy(&ifmgd->vht_capa, &req->vht_capa, sizeof(ifmgd->vht_capa));
+ memcpy(&ifmgd->vht_capa_mask, &req->vht_capa_mask,
+ sizeof(ifmgd->vht_capa_mask));
+
if (req->ie && req->ie_len) {
memcpy(assoc_data->ie, req->ie, req->ie_len);
assoc_data->ie_len = req->ie_len;
@@ -4131,7 +4214,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
if (bss->wmm_used && bss->uapsd_supported &&
- (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
+ (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) &&
+ sdata->wmm_acm != 0xff) {
assoc_data->uapsd = true;
ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
} else {
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index cc79b4a2e821..acd1f71adc03 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -118,9 +118,9 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
* Stop queues and transmit all frames queued by the driver
* before sending nullfunc to enable powersave at the AP.
*/
- ieee80211_stop_queues_by_reason(&local->hw,
+ ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
@@ -181,7 +181,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
}
mutex_unlock(&local->iflist_mtx);
- ieee80211_wake_queues_by_reason(&local->hw,
+ ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
}
@@ -277,7 +277,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
duration = 10;
ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
- duration);
+ duration, roc->type);
roc->started = true;
@@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
}
}
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free)
{
struct ieee80211_roc_work *dep, *tmp;
+ if (WARN_ON(roc->to_be_freed))
+ return;
+
/* was never transmitted */
if (roc->frame) {
cfg80211_mgmt_tx_status(&roc->sdata->wdev,
@@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
GFP_KERNEL);
list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
- ieee80211_roc_notify_destroy(dep);
+ ieee80211_roc_notify_destroy(dep, true);
- kfree(roc);
+ if (free)
+ kfree(roc);
+ else
+ roc->to_be_freed = true;
}
void ieee80211_sw_roc_work(struct work_struct *work)
@@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work)
mutex_lock(&local->mtx);
+ if (roc->to_be_freed)
+ goto out_unlock;
+
if (roc->abort)
goto finish;
@@ -370,10 +379,10 @@ void ieee80211_sw_roc_work(struct work_struct *work)
finish:
list_del(&roc->list);
started = roc->started;
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, !roc->abort);
if (started) {
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->tmp_channel = NULL;
ieee80211_hw_config(local, 0);
@@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
list_del(&roc->list);
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, true);
/* if there's another roc, start it now */
ieee80211_start_next_roc(local);
@@ -436,15 +445,15 @@ void ieee80211_roc_setup(struct ieee80211_local *local)
INIT_LIST_HEAD(&local->roc_list);
}
-void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
+void ieee80211_roc_purge(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_local *local = sdata->local;
struct ieee80211_roc_work *roc, *tmp;
LIST_HEAD(tmp_list);
mutex_lock(&local->mtx);
list_for_each_entry_safe(roc, tmp, &local->roc_list, list) {
- if (roc->sdata != sdata)
+ if (sdata && roc->sdata != sdata)
continue;
if (roc->started && local->ops->remain_on_channel) {
@@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
if (local->ops->remain_on_channel) {
list_del(&roc->list);
- ieee80211_roc_notify_destroy(roc);
+ ieee80211_roc_notify_destroy(roc, true);
} else {
ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
/* work will clean up etc */
flush_delayed_work(&roc->work);
+ WARN_ON(!roc->to_be_freed);
+ kfree(roc);
}
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index d0275f34bf70..7fc5d0d8149a 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -6,32 +6,11 @@
#include "driver-ops.h"
#include "led.h"
-/* return value indicates whether the driver should be further notified */
-static void ieee80211_quiesce(struct ieee80211_sub_if_data *sdata)
-{
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_STATION:
- ieee80211_sta_quiesce(sdata);
- break;
- case NL80211_IFTYPE_ADHOC:
- ieee80211_ibss_quiesce(sdata);
- break;
- case NL80211_IFTYPE_MESH_POINT:
- ieee80211_mesh_quiesce(sdata);
- break;
- default:
- break;
- }
-
- cancel_work_sync(&sdata->work);
-}
-
int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
- struct ieee80211_chanctx *ctx;
if (!local->open_count)
goto suspend;
@@ -40,6 +19,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_dfs_cac_cancel(local);
+ ieee80211_roc_purge(local, NULL);
+
+ ieee80211_del_virtual_monitor(local);
+
if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
@@ -51,12 +34,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
}
ieee80211_stop_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
- /* flush out all packets */
+ /* flush out all packets and station cleanup call_rcu()s */
synchronize_net();
+ rcu_barrier();
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->quiescing = true;
/* make quiescing visible to timers everywhere */
@@ -89,23 +74,17 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
mutex_unlock(&local->sta_mtx);
}
ieee80211_wake_queues_by_reason(hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
return err;
} else if (err > 0) {
WARN_ON(err != 1);
- local->wowlan = false;
+ return err;
} else {
- list_for_each_entry(sdata, &local->interfaces, list)
- if (ieee80211_sdata_running(sdata))
- ieee80211_quiesce(sdata);
goto suspend;
}
}
- /* disable keys */
- list_for_each_entry(sdata, &local->interfaces, list)
- ieee80211_disable_keys(sdata);
-
/* tear down aggregation sessions and remove STAs */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
@@ -117,100 +96,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
WARN_ON(drv_sta_state(local, sta->sdata, sta,
state, state - 1));
}
-
- mesh_plink_quiesce(sta);
}
mutex_unlock(&local->sta_mtx);
/* remove all interfaces */
list_for_each_entry(sdata, &local->interfaces, list) {
- static u8 zero_addr[ETH_ALEN] = {};
- u32 changed = 0;
-
if (!ieee80211_sdata_running(sdata))
continue;
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_MONITOR:
- /* skip these */
- continue;
- case NL80211_IFTYPE_STATION:
- if (sdata->vif.bss_conf.assoc)
- changed = BSS_CHANGED_ASSOC |
- BSS_CHANGED_BSSID |
- BSS_CHANGED_IDLE;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- if (sdata->vif.bss_conf.enable_beacon)
- changed = BSS_CHANGED_BEACON_ENABLED;
- break;
- default:
- break;
- }
-
- ieee80211_quiesce(sdata);
-
- sdata->suspend_bss_conf = sdata->vif.bss_conf;
- memset(&sdata->vif.bss_conf, 0, sizeof(sdata->vif.bss_conf));
- sdata->vif.bss_conf.idle = true;
- if (sdata->suspend_bss_conf.bssid)
- sdata->vif.bss_conf.bssid = zero_addr;
-
- /* disable beaconing or remove association */
- ieee80211_bss_info_change_notify(sdata, changed);
-
- if (sdata->vif.type == NL80211_IFTYPE_AP &&
- rcu_access_pointer(sdata->u.ap.beacon))
- drv_stop_ap(local, sdata);
-
- if (local->use_chanctx) {
- struct ieee80211_chanctx_conf *conf;
-
- mutex_lock(&local->chanctx_mtx);
- conf = rcu_dereference_protected(
- sdata->vif.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
- if (conf) {
- ctx = container_of(conf,
- struct ieee80211_chanctx,
- conf);
- drv_unassign_vif_chanctx(local, sdata, ctx);
- }
-
- mutex_unlock(&local->chanctx_mtx);
- }
- drv_remove_interface(local, sdata);
- }
-
- sdata = rtnl_dereference(local->monitor_sdata);
- if (sdata) {
- if (local->use_chanctx) {
- struct ieee80211_chanctx_conf *conf;
-
- mutex_lock(&local->chanctx_mtx);
- conf = rcu_dereference_protected(
- sdata->vif.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
- if (conf) {
- ctx = container_of(conf,
- struct ieee80211_chanctx,
- conf);
- drv_unassign_vif_chanctx(local, sdata, ctx);
- }
-
- mutex_unlock(&local->chanctx_mtx);
- }
-
drv_remove_interface(local, sdata);
}
- mutex_lock(&local->chanctx_mtx);
- list_for_each_entry(ctx, &local->chanctx_list, list)
- drv_remove_chanctx(local, ctx);
- mutex_unlock(&local->chanctx_mtx);
+ /*
+ * We disconnected on all interfaces before suspend, all channel
+ * contexts should be released.
+ */
+ WARN_ON(!list_empty(&local->chanctx_list));
/* stop hardware - this must stop RX */
if (local->open_count)
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index dd88381c53b7..0d51877efdb7 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -252,6 +252,25 @@ rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
return 0;
}
+static void __rate_control_send_low(struct ieee80211_hw *hw,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta,
+ struct ieee80211_tx_info *info)
+{
+ if ((sband->band != IEEE80211_BAND_2GHZ) ||
+ !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
+ info->control.rates[0].idx = rate_lowest_index(sband, sta);
+ else
+ info->control.rates[0].idx =
+ rate_lowest_non_cck_index(sband, sta);
+
+ info->control.rates[0].count =
+ (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
+ 1 : hw->max_rate_tries;
+
+ info->control.skip_table = 1;
+}
+
bool rate_control_send_low(struct ieee80211_sta *sta,
void *priv_sta,
@@ -262,16 +281,8 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
int mcast_rate;
if (!sta || !priv_sta || rc_no_data_or_no_ack_use_min(txrc)) {
- if ((sband->band != IEEE80211_BAND_2GHZ) ||
- !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
- info->control.rates[0].idx =
- rate_lowest_index(txrc->sband, sta);
- else
- info->control.rates[0].idx =
- rate_lowest_non_cck_index(txrc->sband, sta);
- info->control.rates[0].count =
- (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : txrc->hw->max_rate_tries;
+ __rate_control_send_low(txrc->hw, sband, sta, info);
+
if (!sta && txrc->bss) {
mcast_rate = txrc->bss_conf->mcast_rate[sband->band];
if (mcast_rate > 0) {
@@ -355,7 +366,8 @@ static bool rate_idx_match_mcs_mask(struct ieee80211_tx_rate *rate,
static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
- struct ieee80211_tx_rate_control *txrc,
+ struct ieee80211_supported_band *sband,
+ enum nl80211_chan_width chan_width,
u32 mask,
u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN])
{
@@ -375,27 +387,17 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
alt_rate.count = rate->count;
if (rate_idx_match_legacy_mask(&alt_rate,
- txrc->sband->n_bitrates,
- mask)) {
+ sband->n_bitrates, mask)) {
*rate = alt_rate;
return;
}
} else {
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- __le16 fc;
-
/* handle legacy rates */
- if (rate_idx_match_legacy_mask(rate, txrc->sband->n_bitrates,
- mask))
+ if (rate_idx_match_legacy_mask(rate, sband->n_bitrates, mask))
return;
/* if HT BSS, and we handle a data frame, also try HT rates */
- if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
- return;
-
- fc = hdr->frame_control;
- if (!ieee80211_is_data(fc))
+ if (chan_width == NL80211_CHAN_WIDTH_20_NOHT)
return;
alt_rate.idx = 0;
@@ -408,7 +410,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
alt_rate.flags |= IEEE80211_TX_RC_MCS;
- if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40)
+ if (chan_width == NL80211_CHAN_WIDTH_40)
alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
@@ -426,6 +428,228 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
*/
}
+static void rate_fixup_ratelist(struct ieee80211_vif *vif,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_tx_rate *rates,
+ int max_rates)
+{
+ struct ieee80211_rate *rate;
+ bool inval = false;
+ int i;
+
+ /*
+ * Set up the RTS/CTS rate as the fastest basic rate
+ * that is not faster than the data rate unless there
+ * is no basic rate slower than the data rate, in which
+ * case we pick the slowest basic rate
+ *
+ * XXX: Should this check all retry rates?
+ */
+ if (!(rates[0].flags & IEEE80211_TX_RC_MCS)) {
+ u32 basic_rates = vif->bss_conf.basic_rates;
+ s8 baserate = basic_rates ? ffs(basic_rates - 1) : 0;
+
+ rate = &sband->bitrates[rates[0].idx];
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ /* must be a basic rate */
+ if (!(basic_rates & BIT(i)))
+ continue;
+ /* must not be faster than the data rate */
+ if (sband->bitrates[i].bitrate > rate->bitrate)
+ continue;
+ /* maximum */
+ if (sband->bitrates[baserate].bitrate <
+ sband->bitrates[i].bitrate)
+ baserate = i;
+ }
+
+ info->control.rts_cts_rate_idx = baserate;
+ }
+
+ for (i = 0; i < max_rates; i++) {
+ /*
+ * make sure there's no valid rate following
+ * an invalid one, just in case drivers don't
+ * take the API seriously to stop at -1.
+ */
+ if (inval) {
+ rates[i].idx = -1;
+ continue;
+ }
+ if (rates[i].idx < 0) {
+ inval = true;
+ continue;
+ }
+
+ /*
+ * For now assume MCS is already set up correctly, this
+ * needs to be fixed.
+ */
+ if (rates[i].flags & IEEE80211_TX_RC_MCS) {
+ WARN_ON(rates[i].idx > 76);
+
+ if (!(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) &&
+ info->control.use_cts_prot)
+ rates[i].flags |=
+ IEEE80211_TX_RC_USE_CTS_PROTECT;
+ continue;
+ }
+
+ if (rates[i].flags & IEEE80211_TX_RC_VHT_MCS) {
+ WARN_ON(ieee80211_rate_get_vht_mcs(&rates[i]) > 9);
+ continue;
+ }
+
+ /* set up RTS protection if desired */
+ if (info->control.use_rts) {
+ rates[i].flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ info->control.use_cts_prot = false;
+ }
+
+ /* RC is busted */
+ if (WARN_ON_ONCE(rates[i].idx >= sband->n_bitrates)) {
+ rates[i].idx = -1;
+ continue;
+ }
+
+ rate = &sband->bitrates[rates[i].idx];
+
+ /* set up short preamble */
+ if (info->control.short_preamble &&
+ rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+ rates[i].flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+
+ /* set up G protection */
+ if (!(rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) &&
+ info->control.use_cts_prot &&
+ rate->flags & IEEE80211_RATE_ERP_G)
+ rates[i].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
+ }
+}
+
+
+static void rate_control_fill_sta_table(struct ieee80211_sta *sta,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_tx_rate *rates,
+ int max_rates)
+{
+ struct ieee80211_sta_rates *ratetbl = NULL;
+ int i;
+
+ if (sta && !info->control.skip_table)
+ ratetbl = rcu_dereference(sta->rates);
+
+ /* Fill remaining rate slots with data from the sta rate table. */
+ max_rates = min_t(int, max_rates, IEEE80211_TX_RATE_TABLE_SIZE);
+ for (i = 0; i < max_rates; i++) {
+ if (i < ARRAY_SIZE(info->control.rates) &&
+ info->control.rates[i].idx >= 0 &&
+ info->control.rates[i].count) {
+ if (rates != info->control.rates)
+ rates[i] = info->control.rates[i];
+ } else if (ratetbl) {
+ rates[i].idx = ratetbl->rate[i].idx;
+ rates[i].flags = ratetbl->rate[i].flags;
+ if (info->control.use_rts)
+ rates[i].count = ratetbl->rate[i].count_rts;
+ else if (info->control.use_cts_prot)
+ rates[i].count = ratetbl->rate[i].count_cts;
+ else
+ rates[i].count = ratetbl->rate[i].count;
+ } else {
+ rates[i].idx = -1;
+ rates[i].count = 0;
+ }
+
+ if (rates[i].idx < 0 || !rates[i].count)
+ break;
+ }
+}
+
+static void rate_control_apply_mask(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta,
+ struct ieee80211_supported_band *sband,
+ struct ieee80211_tx_info *info,
+ struct ieee80211_tx_rate *rates,
+ int max_rates)
+{
+ enum nl80211_chan_width chan_width;
+ u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
+ bool has_mcs_mask;
+ u32 mask;
+ int i;
+
+ /*
+ * Try to enforce the rateidx mask the user wanted. skip this if the
+ * default mask (allow all rates) is used to save some processing for
+ * the common case.
+ */
+ mask = sdata->rc_rateidx_mask[info->band];
+ has_mcs_mask = sdata->rc_has_mcs_mask[info->band];
+ if (mask == (1 << sband->n_bitrates) - 1 && !has_mcs_mask)
+ return;
+
+ if (has_mcs_mask)
+ memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
+ sizeof(mcs_mask));
+ else
+ memset(mcs_mask, 0xff, sizeof(mcs_mask));
+
+ if (sta) {
+ /* Filter out rates that the STA does not support */
+ mask &= sta->supp_rates[info->band];
+ for (i = 0; i < sizeof(mcs_mask); i++)
+ mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i];
+ }
+
+ /*
+ * Make sure the rate index selected for each TX rate is
+ * included in the configured mask and change the rate indexes
+ * if needed.
+ */
+ chan_width = sdata->vif.bss_conf.chandef.width;
+ for (i = 0; i < max_rates; i++) {
+ /* Skip invalid rates */
+ if (rates[i].idx < 0)
+ break;
+
+ rate_idx_match_mask(&rates[i], sband, mask, chan_width,
+ mcs_mask);
+ }
+}
+
+void ieee80211_get_tx_rates(struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct ieee80211_tx_rate *dest,
+ int max_rates)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_supported_band *sband;
+
+ rate_control_fill_sta_table(sta, info, dest, max_rates);
+
+ if (!vif)
+ return;
+
+ sdata = vif_to_sdata(vif);
+ sband = sdata->local->hw.wiphy->bands[info->band];
+
+ if (ieee80211_is_data(hdr->frame_control))
+ rate_control_apply_mask(sdata, sta, sband, info, dest, max_rates);
+
+ if (dest[0].idx < 0)
+ __rate_control_send_low(&sdata->local->hw, sband, sta, info);
+
+ if (sta)
+ rate_fixup_ratelist(vif, sband, info, dest, max_rates);
+}
+EXPORT_SYMBOL(ieee80211_get_tx_rates);
+
void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_tx_rate_control *txrc)
@@ -435,8 +659,6 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta *ista = NULL;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
int i;
- u32 mask;
- u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN];
if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) {
ista = &sta->sta;
@@ -454,37 +676,27 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
- /*
- * Try to enforce the rateidx mask the user wanted. skip this if the
- * default mask (allow all rates) is used to save some processing for
- * the common case.
- */
- mask = sdata->rc_rateidx_mask[info->band];
- memcpy(mcs_mask, sdata->rc_rateidx_mcs_mask[info->band],
- sizeof(mcs_mask));
- if (mask != (1 << txrc->sband->n_bitrates) - 1) {
- if (sta) {
- /* Filter out rates that the STA does not support */
- mask &= sta->sta.supp_rates[info->band];
- for (i = 0; i < sizeof(mcs_mask); i++)
- mcs_mask[i] &= sta->sta.ht_cap.mcs.rx_mask[i];
- }
- /*
- * Make sure the rate index selected for each TX rate is
- * included in the configured mask and change the rate indexes
- * if needed.
- */
- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- /* Skip invalid rates */
- if (info->control.rates[i].idx < 0)
- break;
- rate_idx_match_mask(&info->control.rates[i], txrc,
- mask, mcs_mask);
- }
- }
+ if (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_RC_TABLE)
+ return;
+
+ ieee80211_get_tx_rates(&sdata->vif, ista, txrc->skb,
+ info->control.rates,
+ ARRAY_SIZE(info->control.rates));
+}
- BUG_ON(info->control.rates[0].idx < 0);
+int rate_control_set_rates(struct ieee80211_hw *hw,
+ struct ieee80211_sta *pubsta,
+ struct ieee80211_sta_rates *rates)
+{
+ struct ieee80211_sta_rates *old = rcu_dereference(pubsta->rates);
+
+ rcu_assign_pointer(pubsta->rates, rates);
+ if (old)
+ kfree_rcu(old, rcu_head);
+
+ return 0;
}
+EXPORT_SYMBOL(rate_control_set_rates);
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
const char *name)
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index eea45a2c7c35..ac7ef5414bde 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -55,7 +55,6 @@
#include "rate.h"
#include "rc80211_minstrel.h"
-#define SAMPLE_COLUMNS 10
#define SAMPLE_TBL(_mi, _idx, _col) \
_mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col]
@@ -70,16 +69,75 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix)
return i;
}
+/* find & sort topmost throughput rates */
+static inline void
+minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list)
+{
+ int j = MAX_THR_RATES;
+
+ while (j > 0 && mi->r[i].cur_tp > mi->r[tp_list[j - 1]].cur_tp)
+ j--;
+ if (j < MAX_THR_RATES - 1)
+ memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1));
+ if (j < MAX_THR_RATES)
+ tp_list[j] = i;
+}
+
+static void
+minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *ratetbl,
+ int offset, int idx)
+{
+ struct minstrel_rate *r = &mi->r[idx];
+
+ ratetbl->rate[offset].idx = r->rix;
+ ratetbl->rate[offset].count = r->adjusted_retry_count;
+ ratetbl->rate[offset].count_cts = r->retry_count_cts;
+ ratetbl->rate[offset].count_rts = r->retry_count_rtscts;
+}
+
+static void
+minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
+{
+ struct ieee80211_sta_rates *ratetbl;
+ int i = 0;
+
+ ratetbl = kzalloc(sizeof(*ratetbl), GFP_ATOMIC);
+ if (!ratetbl)
+ return;
+
+ /* Start with max_tp_rate */
+ minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[0]);
+
+ if (mp->hw->max_rates >= 3) {
+ /* At least 3 tx rates supported, use max_tp_rate2 next */
+ minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[1]);
+ }
+
+ if (mp->hw->max_rates >= 2) {
+ /* At least 2 tx rates supported, use max_prob_rate next */
+ minstrel_set_rate(mi, ratetbl, i++, mi->max_prob_rate);
+ }
+
+ /* Use lowest rate last */
+ ratetbl->rate[i].idx = mi->lowest_rix;
+ ratetbl->rate[i].count = mp->max_retry;
+ ratetbl->rate[i].count_cts = mp->max_retry;
+ ratetbl->rate[i].count_rts = mp->max_retry;
+
+ rate_control_set_rates(mp->hw, mi->sta, ratetbl);
+}
+
static void
minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
{
- u32 max_tp = 0, index_max_tp = 0, index_max_tp2 = 0;
- u32 max_prob = 0, index_max_prob = 0;
+ u8 tmp_tp_rate[MAX_THR_RATES];
+ u8 tmp_prob_rate = 0;
u32 usecs;
- u32 p;
int i;
- mi->stats_update = jiffies;
+ for (i=0; i < MAX_THR_RATES; i++)
+ tmp_tp_rate[i] = 0;
+
for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i];
@@ -87,27 +145,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
if (!usecs)
usecs = 1000000;
- /* To avoid rounding issues, probabilities scale from 0 (0%)
- * to 18000 (100%) */
- if (mr->attempts) {
- p = (mr->success * 18000) / mr->attempts;
+ if (unlikely(mr->attempts > 0)) {
+ mr->sample_skipped = 0;
+ mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
mr->succ_hist += mr->success;
mr->att_hist += mr->attempts;
- mr->cur_prob = p;
- p = ((p * (100 - mp->ewma_level)) + (mr->probability *
- mp->ewma_level)) / 100;
- mr->probability = p;
- mr->cur_tp = p * (1000000 / usecs);
- }
+ mr->probability = minstrel_ewma(mr->probability,
+ mr->cur_prob,
+ EWMA_LEVEL);
+ } else
+ mr->sample_skipped++;
mr->last_success = mr->success;
mr->last_attempts = mr->attempts;
mr->success = 0;
mr->attempts = 0;
+ /* Update throughput per rate, reset thr. below 10% success */
+ if (mr->probability < MINSTREL_FRAC(10, 100))
+ mr->cur_tp = 0;
+ else
+ mr->cur_tp = mr->probability * (1000000 / usecs);
+
/* Sample less often below the 10% chance of success.
* Sample less often above the 95% chance of success. */
- if ((mr->probability > 17100) || (mr->probability < 1800)) {
+ if (mr->probability > MINSTREL_FRAC(95, 100) ||
+ mr->probability < MINSTREL_FRAC(10, 100)) {
mr->adjusted_retry_count = mr->retry_count >> 1;
if (mr->adjusted_retry_count > 2)
mr->adjusted_retry_count = 2;
@@ -118,35 +181,32 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
}
if (!mr->adjusted_retry_count)
mr->adjusted_retry_count = 2;
- }
- for (i = 0; i < mi->n_rates; i++) {
- struct minstrel_rate *mr = &mi->r[i];
- if (max_tp < mr->cur_tp) {
- index_max_tp = i;
- max_tp = mr->cur_tp;
- }
- if (max_prob < mr->probability) {
- index_max_prob = i;
- max_prob = mr->probability;
+ minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate);
+
+ /* To determine the most robust rate (max_prob_rate) used at
+ * 3rd mmr stage we distinct between two cases:
+ * (1) if any success probabilitiy >= 95%, out of those rates
+ * choose the maximum throughput rate as max_prob_rate
+ * (2) if all success probabilities < 95%, the rate with
+ * highest success probability is choosen as max_prob_rate */
+ if (mr->probability >= MINSTREL_FRAC(95,100)) {
+ if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
+ tmp_prob_rate = i;
+ } else {
+ if (mr->probability >= mi->r[tmp_prob_rate].probability)
+ tmp_prob_rate = i;
}
}
- max_tp = 0;
- for (i = 0; i < mi->n_rates; i++) {
- struct minstrel_rate *mr = &mi->r[i];
+ /* Assign the new rate set */
+ memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
+ mi->max_prob_rate = tmp_prob_rate;
- if (i == index_max_tp)
- continue;
+ /* Reset update timer */
+ mi->stats_update = jiffies;
- if (max_tp < mr->cur_tp) {
- index_max_tp2 = i;
- max_tp = mr->cur_tp;
- }
- }
- mi->max_tp_rate = index_max_tp;
- mi->max_tp_rate2 = index_max_tp2;
- mi->max_prob_rate = index_max_prob;
+ minstrel_update_rates(mp, mi);
}
static void
@@ -195,9 +255,9 @@ minstrel_get_retry_count(struct minstrel_rate *mr,
{
unsigned int retry = mr->adjusted_retry_count;
- if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ if (info->control.use_rts)
retry = max(2U, min(mr->retry_count_rtscts, retry));
- else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+ else if (info->control.use_cts_prot)
retry = max(2U, min(mr->retry_count_cts, retry));
return retry;
}
@@ -207,10 +267,10 @@ static int
minstrel_get_next_sample(struct minstrel_sta_info *mi)
{
unsigned int sample_ndx;
- sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
- mi->sample_idx++;
- if ((int) mi->sample_idx > (mi->n_rates - 2)) {
- mi->sample_idx = 0;
+ sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column);
+ mi->sample_row++;
+ if ((int) mi->sample_row >= mi->n_rates) {
+ mi->sample_row = 0;
mi->sample_column++;
if (mi->sample_column >= SAMPLE_COLUMNS)
mi->sample_column = 0;
@@ -226,111 +286,96 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct minstrel_sta_info *mi = priv_sta;
struct minstrel_priv *mp = priv;
- struct ieee80211_tx_rate *ar = info->control.rates;
- unsigned int ndx, sample_ndx = 0;
- bool mrr;
- bool sample_slower = false;
- bool sample = false;
- int i, delta;
- int mrr_ndx[3];
- int sample_rate;
-
+ struct ieee80211_tx_rate *rate = &info->control.rates[0];
+ struct minstrel_rate *msr, *mr;
+ unsigned int ndx;
+ bool mrr_capable;
+ bool prev_sample = mi->prev_sample;
+ int delta;
+ int sampling_ratio;
+
+ /* management/no-ack frames do not use rate control */
if (rate_control_send_low(sta, priv_sta, txrc))
return;
- mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
-
- ndx = mi->max_tp_rate;
-
- if (mrr)
- sample_rate = mp->lookaround_rate_mrr;
+ /* check multi-rate-retry capabilities & adjust lookaround_rate */
+ mrr_capable = mp->has_mrr &&
+ !txrc->rts &&
+ !txrc->bss_conf->use_cts_prot;
+ if (mrr_capable)
+ sampling_ratio = mp->lookaround_rate_mrr;
else
- sample_rate = mp->lookaround_rate;
+ sampling_ratio = mp->lookaround_rate;
+ /* increase sum packet counter */
mi->packet_count++;
- delta = (mi->packet_count * sample_rate / 100) -
+
+ delta = (mi->packet_count * sampling_ratio / 100) -
(mi->sample_count + mi->sample_deferred / 2);
- /* delta > 0: sampling required */
- if ((delta > 0) && (mrr || !mi->prev_sample)) {
- struct minstrel_rate *msr;
- if (mi->packet_count >= 10000) {
- mi->sample_deferred = 0;
- mi->sample_count = 0;
- mi->packet_count = 0;
- } else if (delta > mi->n_rates * 2) {
- /* With multi-rate retry, not every planned sample
- * attempt actually gets used, due to the way the retry
- * chain is set up - [max_tp,sample,prob,lowest] for
- * sample_rate < max_tp.
- *
- * If there's too much sampling backlog and the link
- * starts getting worse, minstrel would start bursting
- * out lots of sampling frames, which would result
- * in a large throughput loss. */
- mi->sample_count += (delta - mi->n_rates * 2);
- }
+ /* delta < 0: no sampling required */
+ mi->prev_sample = false;
+ if (delta < 0 || (!mrr_capable && prev_sample))
+ return;
- sample_ndx = minstrel_get_next_sample(mi);
- msr = &mi->r[sample_ndx];
- sample = true;
- sample_slower = mrr && (msr->perfect_tx_time >
- mi->r[ndx].perfect_tx_time);
-
- if (!sample_slower) {
- if (msr->sample_limit != 0) {
- ndx = sample_ndx;
- mi->sample_count++;
- if (msr->sample_limit > 0)
- msr->sample_limit--;
- } else {
- sample = false;
- }
- } else {
- /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
- * packets that have the sampling rate deferred to the
- * second MRR stage. Increase the sample counter only
- * if the deferred sample rate was actually used.
- * Use the sample_deferred counter to make sure that
- * the sampling is not done in large bursts */
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
- mi->sample_deferred++;
- }
+ if (mi->packet_count >= 10000) {
+ mi->sample_deferred = 0;
+ mi->sample_count = 0;
+ mi->packet_count = 0;
+ } else if (delta > mi->n_rates * 2) {
+ /* With multi-rate retry, not every planned sample
+ * attempt actually gets used, due to the way the retry
+ * chain is set up - [max_tp,sample,prob,lowest] for
+ * sample_rate < max_tp.
+ *
+ * If there's too much sampling backlog and the link
+ * starts getting worse, minstrel would start bursting
+ * out lots of sampling frames, which would result
+ * in a large throughput loss. */
+ mi->sample_count += (delta - mi->n_rates * 2);
+ }
+
+ /* get next random rate sample */
+ ndx = minstrel_get_next_sample(mi);
+ msr = &mi->r[ndx];
+ mr = &mi->r[mi->max_tp_rate[0]];
+
+ /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage)
+ * rate sampling method should be used.
+ * Respect such rates that are not sampled for 20 interations.
+ */
+ if (mrr_capable &&
+ msr->perfect_tx_time > mr->perfect_tx_time &&
+ msr->sample_skipped < 20) {
+ /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
+ * packets that have the sampling rate deferred to the
+ * second MRR stage. Increase the sample counter only
+ * if the deferred sample rate was actually used.
+ * Use the sample_deferred counter to make sure that
+ * the sampling is not done in large bursts */
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ rate++;
+ mi->sample_deferred++;
+ } else {
+ if (!msr->sample_limit != 0)
+ return;
+
+ mi->sample_count++;
+ if (msr->sample_limit > 0)
+ msr->sample_limit--;
}
- mi->prev_sample = sample;
/* If we're not using MRR and the sampling rate already
* has a probability of >95%, we shouldn't be attempting
* to use it, as this only wastes precious airtime */
- if (!mrr && sample && (mi->r[ndx].probability > 17100))
- ndx = mi->max_tp_rate;
-
- ar[0].idx = mi->r[ndx].rix;
- ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
-
- if (!mrr) {
- if (!sample)
- ar[0].count = mp->max_retry;
- ar[1].idx = mi->lowest_rix;
- ar[1].count = mp->max_retry;
+ if (!mrr_capable &&
+ (mi->r[ndx].probability > MINSTREL_FRAC(95, 100)))
return;
- }
- /* MRR setup */
- if (sample) {
- if (sample_slower)
- mrr_ndx[0] = sample_ndx;
- else
- mrr_ndx[0] = mi->max_tp_rate;
- } else {
- mrr_ndx[0] = mi->max_tp_rate2;
- }
- mrr_ndx[1] = mi->max_prob_rate;
- mrr_ndx[2] = 0;
- for (i = 1; i < 4; i++) {
- ar[i].idx = mi->r[mrr_ndx[i - 1]].rix;
- ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count;
- }
+ mi->prev_sample = true;
+
+ rate->idx = mi->r[ndx].rix;
+ rate->count = minstrel_get_retry_count(&mi->r[ndx], info);
}
@@ -351,26 +396,21 @@ static void
init_sample_table(struct minstrel_sta_info *mi)
{
unsigned int i, col, new_idx;
- unsigned int n_srates = mi->n_rates - 1;
u8 rnd[8];
mi->sample_column = 0;
- mi->sample_idx = 0;
- memset(mi->sample_table, 0, SAMPLE_COLUMNS * mi->n_rates);
+ mi->sample_row = 0;
+ memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates);
for (col = 0; col < SAMPLE_COLUMNS; col++) {
- for (i = 0; i < n_srates; i++) {
+ for (i = 0; i < mi->n_rates; i++) {
get_random_bytes(rnd, sizeof(rnd));
- new_idx = (i + rnd[i & 7]) % n_srates;
+ new_idx = (i + rnd[i & 7]) % mi->n_rates;
- while (SAMPLE_TBL(mi, new_idx, col) != 0)
- new_idx = (new_idx + 1) % n_srates;
+ while (SAMPLE_TBL(mi, new_idx, col) != 0xff)
+ new_idx = (new_idx + 1) % mi->n_rates;
- /* Don't sample the slowest rate (i.e. slowest base
- * rate). We must presume that the slowest rate works
- * fine, or else other management frames will also be
- * failing and the link will break */
- SAMPLE_TBL(mi, new_idx, col) = i + 1;
+ SAMPLE_TBL(mi, new_idx, col) = i;
}
}
}
@@ -385,12 +425,16 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
unsigned int i, n = 0;
unsigned int t_slot = 9; /* FIXME: get real slot time */
+ mi->sta = sta;
mi->lowest_rix = rate_lowest_index(sband, sta);
ctl_rate = &sband->bitrates[mi->lowest_rix];
mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10,
ctl_rate->bitrate,
!!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1);
+ memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate));
+ mi->max_prob_rate = 0;
+
for (i = 0; i < sband->n_bitrates; i++) {
struct minstrel_rate *mr = &mi->r[n];
unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0;
@@ -433,6 +477,8 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
} while ((tx_time < mp->segment_size) &&
(++mr->retry_count < mp->max_retry));
mr->adjusted_retry_count = mr->retry_count;
+ if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G))
+ mr->retry_count_cts = mr->retry_count;
}
for (i = n; i < sband->n_bitrates; i++) {
@@ -444,6 +490,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
mi->stats_update = jiffies;
init_sample_table(mi);
+ minstrel_update_rates(mp, mi);
}
static void *
@@ -542,9 +589,6 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
mp->lookaround_rate = 5;
mp->lookaround_rate_mrr = 10;
- /* moving average weight for EWMA */
- mp->ewma_level = 75;
-
/* maximum time that the hw is allowed to stay in one MRR segment */
mp->segment_size = 6000;
diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h
index 5ecf757817f2..f4301f4b2e41 100644
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -9,6 +9,29 @@
#ifndef __RC_MINSTREL_H
#define __RC_MINSTREL_H
+#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */
+#define EWMA_DIV 128
+#define SAMPLE_COLUMNS 10 /* number of columns in sample table */
+
+
+/* scaled fraction values */
+#define MINSTREL_SCALE 16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+/* number of highest throughput rates to consider*/
+#define MAX_THR_RATES 4
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+ */
+static inline int
+minstrel_ewma(int old, int new, int weight)
+{
+ return (new * (EWMA_DIV - weight) + old * weight) / EWMA_DIV;
+}
+
+
struct minstrel_rate {
int bitrate;
int rix;
@@ -26,6 +49,7 @@ struct minstrel_rate {
u32 attempts;
u32 last_attempts;
u32 last_success;
+ u8 sample_skipped;
/* parts per thousand */
u32 cur_prob;
@@ -39,20 +63,21 @@ struct minstrel_rate {
};
struct minstrel_sta_info {
+ struct ieee80211_sta *sta;
+
unsigned long stats_update;
unsigned int sp_ack_dur;
unsigned int rate_avg;
unsigned int lowest_rix;
- unsigned int max_tp_rate;
- unsigned int max_tp_rate2;
- unsigned int max_prob_rate;
+ u8 max_tp_rate[MAX_THR_RATES];
+ u8 max_prob_rate;
unsigned int packet_count;
unsigned int sample_count;
int sample_deferred;
- unsigned int sample_idx;
+ unsigned int sample_row;
unsigned int sample_column;
int n_rates;
@@ -73,7 +98,6 @@ struct minstrel_priv {
unsigned int cw_min;
unsigned int cw_max;
unsigned int max_retry;
- unsigned int ewma_level;
unsigned int segment_size;
unsigned int update_interval;
unsigned int lookaround_rate;
diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c
index d5a56226e675..fd0b9ca1570e 100644
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -68,23 +68,25 @@ minstrel_stats_open(struct inode *inode, struct file *file)
file->private_data = ms;
p = ms->buf;
- p += sprintf(p, "rate throughput ewma prob this prob "
+ p += sprintf(p, "rate throughput ewma prob this prob "
"this succ/attempt success attempts\n");
for (i = 0; i < mi->n_rates; i++) {
struct minstrel_rate *mr = &mi->r[i];
- *(p++) = (i == mi->max_tp_rate) ? 'T' : ' ';
- *(p++) = (i == mi->max_tp_rate2) ? 't' : ' ';
+ *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' ';
+ *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' ';
+ *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' ';
+ *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' ';
*(p++) = (i == mi->max_prob_rate) ? 'P' : ' ';
p += sprintf(p, "%3u%s", mr->bitrate / 2,
(mr->bitrate & 1 ? ".5" : " "));
- tp = mr->cur_tp / ((18000 << 10) / 96);
- prob = mr->cur_prob / 18;
- eprob = mr->probability / 18;
+ tp = MINSTREL_TRUNC(mr->cur_tp / 10);
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
- "%3u(%3u) %8llu %8llu\n",
+ " %3u(%3u) %8llu %8llu\n",
tp / 10, tp % 10,
eprob / 10, eprob % 10,
prob / 10, prob % 10,
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index 3af141c69712..5b2d3012b983 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -17,8 +17,6 @@
#include "rc80211_minstrel_ht.h"
#define AVG_PKT_SIZE 1200
-#define SAMPLE_COLUMNS 10
-#define EWMA_LEVEL 75
/* Number of bits for an average sized packet */
#define MCS_NBITS (AVG_PKT_SIZE << 3)
@@ -26,11 +24,11 @@
/* Number of symbols for a packet with (bps) bits per symbol */
#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
-/* Transmission time for a packet containing (syms) symbols */
+/* Transmission time (nanoseconds) for a packet containing (syms) symbols */
#define MCS_SYMBOL_TIME(sgi, syms) \
(sgi ? \
- ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \
- (syms) << 2 /* syms * 4 us */ \
+ ((syms) * 18000 + 4000) / 5 : /* syms * 3.6 us */ \
+ ((syms) * 1000) << 2 /* syms * 4 us */ \
)
/* Transmit duration for the raw data part of an average sized packet */
@@ -64,9 +62,9 @@
}
#define CCK_DURATION(_bitrate, _short, _len) \
- (10 /* SIFS */ + \
+ (1000 * (10 /* SIFS */ + \
(_short ? 72 + 24 : 144 + 48 ) + \
- (8 * (_len + 4) * 10) / (_bitrate))
+ (8 * (_len + 4) * 10) / (_bitrate)))
#define CCK_ACK_DURATION(_bitrate, _short) \
(CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \
@@ -128,14 +126,8 @@ const struct mcs_group minstrel_mcs_groups[] = {
static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
-/*
- * Perform EWMA (Exponentially Weighted Moving Average) calculation
- */
-static int
-minstrel_ewma(int old, int new, int weight)
-{
- return (new * (100 - weight) + old * weight) / 100;
-}
+static void
+minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
/*
* Look up an MCS group index based on mac80211 rate information
@@ -211,20 +203,32 @@ static void
minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
{
struct minstrel_rate_stats *mr;
- unsigned int usecs = 0;
+ unsigned int nsecs = 0;
+ unsigned int tp;
+ unsigned int prob;
mr = &mi->groups[group].rates[rate];
+ prob = mr->probability;
- if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ if (prob < MINSTREL_FRAC(1, 10)) {
mr->cur_tp = 0;
return;
}
+ /*
+ * For the throughput calculation, limit the probability value to 90% to
+ * account for collision related packet error rate fluctuation
+ */
+ if (prob > MINSTREL_FRAC(9, 10))
+ prob = MINSTREL_FRAC(9, 10);
+
if (group != MINSTREL_CCK_GROUP)
- usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+ nsecs = 1000 * mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
- usecs += minstrel_mcs_groups[group].duration[rate];
- mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+ nsecs += minstrel_mcs_groups[group].duration[rate];
+ tp = 1000000 * ((mr->probability * 1000) / nsecs);
+
+ mr->cur_tp = MINSTREL_TRUNC(tp);
}
/*
@@ -243,6 +247,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
struct minstrel_rate_stats *mr;
int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
int group, i, index;
+ bool mi_rates_valid = false;
if (mi->ampdu_packets > 0) {
mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
@@ -253,11 +258,10 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
mi->sample_slow = 0;
mi->sample_count = 0;
- mi->max_tp_rate = 0;
- mi->max_tp_rate2 = 0;
- mi->max_prob_rate = 0;
for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ bool mg_rates_valid = false;
+
cur_prob = 0;
cur_prob_tp = 0;
cur_tp = 0;
@@ -267,15 +271,24 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
if (!mg->supported)
continue;
- mg->max_tp_rate = 0;
- mg->max_tp_rate2 = 0;
- mg->max_prob_rate = 0;
mi->sample_count++;
for (i = 0; i < MCS_GROUP_RATES; i++) {
if (!(mg->supported & BIT(i)))
continue;
+ /* initialize rates selections starting indexes */
+ if (!mg_rates_valid) {
+ mg->max_tp_rate = mg->max_tp_rate2 =
+ mg->max_prob_rate = i;
+ if (!mi_rates_valid) {
+ mi->max_tp_rate = mi->max_tp_rate2 =
+ mi->max_prob_rate = i;
+ mi_rates_valid = true;
+ }
+ mg_rates_valid = true;
+ }
+
mr = &mg->rates[i];
mr->retry_updated = false;
index = MCS_GROUP_RATES * group + i;
@@ -308,8 +321,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
}
}
- /* try to sample up to half of the available rates during each interval */
- mi->sample_count *= 4;
+ /* try to sample all available rates during each interval */
+ mi->sample_count *= 8;
cur_prob = 0;
cur_prob_tp = 0;
@@ -320,20 +333,13 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
if (!mg->supported)
continue;
- mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
- if (cur_prob_tp < mr->cur_tp &&
- minstrel_mcs_groups[group].streams == 1) {
- mi->max_prob_rate = mg->max_prob_rate;
- cur_prob = mr->cur_prob;
- cur_prob_tp = mr->cur_tp;
- }
-
mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
if (cur_tp < mr->cur_tp) {
mi->max_tp_rate2 = mi->max_tp_rate;
cur_tp2 = cur_tp;
mi->max_tp_rate = mg->max_tp_rate;
cur_tp = mr->cur_tp;
+ mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1;
}
mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
@@ -343,6 +349,23 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
}
}
+ if (mi->max_prob_streams < 1)
+ mi->max_prob_streams = 1;
+
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+ mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+ if (cur_prob_tp < mr->cur_tp &&
+ minstrel_mcs_groups[group].streams <= mi->max_prob_streams) {
+ mi->max_prob_rate = mg->max_prob_rate;
+ cur_prob = mr->cur_prob;
+ cur_prob_tp = mr->cur_tp;
+ }
+ }
+
+
mi->stats_update = jiffies;
}
@@ -445,7 +468,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_tx_rate *ar = info->status.rates;
struct minstrel_rate_stats *rate, *rate2;
struct minstrel_priv *mp = priv;
- bool last;
+ bool last, update = false;
int i;
if (!msp->is_ht)
@@ -467,7 +490,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
mi->sample_wait = 16 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
- mi->sample_tries = 2;
+ mi->sample_tries = 1;
mi->sample_count--;
}
@@ -494,21 +517,29 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
if (rate->attempts > 30 &&
MINSTREL_FRAC(rate->success, rate->attempts) <
- MINSTREL_FRAC(20, 100))
+ MINSTREL_FRAC(20, 100)) {
minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+ update = true;
+ }
rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
if (rate2->attempts > 30 &&
MINSTREL_FRAC(rate2->success, rate2->attempts) <
- MINSTREL_FRAC(20, 100))
+ MINSTREL_FRAC(20, 100)) {
minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+ update = true;
+ }
if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ update = true;
minstrel_ht_update_stats(mp, mi);
if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP)
minstrel_aggr_check(sta, skb);
}
+
+ if (update)
+ minstrel_ht_update_rates(mp, mi);
}
static void
@@ -536,7 +567,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
mr->retry_updated = true;
group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
- tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+ tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len / 1000;
/* Contention time for first 2 tries */
ctime = (t_slot * cw) >> 1;
@@ -572,36 +603,71 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
static void
minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
- struct ieee80211_tx_rate *rate, int index,
- bool sample, bool rtscts)
+ struct ieee80211_sta_rates *ratetbl, int offset, int index)
{
const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
struct minstrel_rate_stats *mr;
+ u8 idx;
+ u16 flags;
mr = minstrel_get_ratestats(mi, index);
if (!mr->retry_updated)
minstrel_calc_retransmit(mp, mi, index);
- if (sample)
- rate->count = 1;
- else if (mr->probability < MINSTREL_FRAC(20, 100))
- rate->count = 2;
- else if (rtscts)
- rate->count = mr->retry_count_rtscts;
- else
- rate->count = mr->retry_count;
-
- rate->flags = 0;
- if (rtscts)
- rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ if (mr->probability < MINSTREL_FRAC(20, 100) || !mr->retry_count) {
+ ratetbl->rate[offset].count = 2;
+ ratetbl->rate[offset].count_rts = 2;
+ ratetbl->rate[offset].count_cts = 2;
+ } else {
+ ratetbl->rate[offset].count = mr->retry_count;
+ ratetbl->rate[offset].count_cts = mr->retry_count;
+ ratetbl->rate[offset].count_rts = mr->retry_count_rtscts;
+ }
if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
- rate->idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
+ idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
+ flags = 0;
+ } else {
+ idx = index % MCS_GROUP_RATES +
+ (group->streams - 1) * MCS_GROUP_RATES;
+ flags = IEEE80211_TX_RC_MCS | group->flags;
+ }
+
+ if (offset > 0) {
+ ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
+ flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ }
+
+ ratetbl->rate[offset].idx = idx;
+ ratetbl->rate[offset].flags = flags;
+}
+
+static void
+minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct ieee80211_sta_rates *rates;
+ int i = 0;
+
+ rates = kzalloc(sizeof(*rates), GFP_ATOMIC);
+ if (!rates)
return;
+
+ /* Start with max_tp_rate */
+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate);
+
+ if (mp->hw->max_rates >= 3) {
+ /* At least 3 tx rates supported, use max_tp_rate2 next */
+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate2);
}
- rate->flags |= IEEE80211_TX_RC_MCS | group->flags;
- rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+ if (mp->hw->max_rates >= 2) {
+ /*
+ * At least 2 tx rates supported, use max_prob_rate next */
+ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate);
+ }
+
+ rates->rate[i].idx = -1;
+ rate_control_set_rates(mp->hw, mi->sta, rates);
}
static inline int
@@ -616,6 +682,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
{
struct minstrel_rate_stats *mr;
struct minstrel_mcs_group_data *mg;
+ unsigned int sample_dur, sample_group;
int sample_idx = 0;
if (mi->sample_wait > 0) {
@@ -626,39 +693,46 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
if (!mi->sample_tries)
return -1;
- mi->sample_tries--;
mg = &mi->groups[mi->sample_group];
sample_idx = sample_table[mg->column][mg->index];
mr = &mg->rates[sample_idx];
- sample_idx += mi->sample_group * MCS_GROUP_RATES;
+ sample_group = mi->sample_group;
+ sample_idx += sample_group * MCS_GROUP_RATES;
minstrel_next_sample_idx(mi);
/*
* Sampling might add some overhead (RTS, no aggregation)
* to the frame. Hence, don't use sampling for the currently
- * used max TP rate.
+ * used rates.
*/
- if (sample_idx == mi->max_tp_rate)
+ if (sample_idx == mi->max_tp_rate ||
+ sample_idx == mi->max_tp_rate2 ||
+ sample_idx == mi->max_prob_rate)
return -1;
+
/*
- * When not using MRR, do not sample if the probability is already
- * higher than 95% to avoid wasting airtime
+ * Do not sample if the probability is already higher than 95%
+ * to avoid wasting airtime.
*/
- if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+ if (mr->probability > MINSTREL_FRAC(95, 100))
return -1;
/*
* Make sure that lower rates get sampled only occasionally,
* if the link is working perfectly.
*/
- if (minstrel_get_duration(sample_idx) >
- minstrel_get_duration(mi->max_tp_rate)) {
+ sample_dur = minstrel_get_duration(sample_idx);
+ if (sample_dur >= minstrel_get_duration(mi->max_tp_rate2) &&
+ (mi->max_prob_streams <
+ minstrel_mcs_groups[sample_group].streams ||
+ sample_dur >= minstrel_get_duration(mi->max_prob_rate))) {
if (mr->sample_skipped < 20)
return -1;
if (mi->sample_slow++ > 2)
return -1;
}
+ mi->sample_tries--;
return sample_idx;
}
@@ -683,13 +757,13 @@ static void
minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate_control *txrc)
{
+ const struct mcs_group *sample_group;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
- struct ieee80211_tx_rate *ar = info->status.rates;
+ struct ieee80211_tx_rate *rate = &info->status.rates[0];
struct minstrel_ht_sta_priv *msp = priv_sta;
struct minstrel_ht_sta *mi = &msp->ht;
struct minstrel_priv *mp = priv;
int sample_idx;
- bool sample = false;
if (rate_control_send_low(sta, priv_sta, txrc))
return;
@@ -717,51 +791,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
}
#endif
- if (sample_idx >= 0) {
- sample = true;
- minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
- true, false);
- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
- } else {
- minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
- false, false);
- }
-
- if (mp->hw->max_rates >= 3) {
- /*
- * At least 3 tx rates supported, use
- * sample_rate -> max_tp_rate -> max_prob_rate for sampling and
- * max_tp_rate -> max_tp_rate2 -> max_prob_rate by default.
- */
- if (sample_idx >= 0)
- minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
- false, false);
- else
- minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
- false, true);
-
- minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate,
- false, !sample);
-
- ar[3].count = 0;
- ar[3].idx = -1;
- } else if (mp->hw->max_rates == 2) {
- /*
- * Only 2 tx rates supported, use
- * sample_rate -> max_prob_rate for sampling and
- * max_tp_rate -> max_prob_rate by default.
- */
- minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_prob_rate,
- false, !sample);
-
- ar[2].count = 0;
- ar[2].idx = -1;
- } else {
- /* Not using MRR, only use the first rate */
- ar[1].count = 0;
- ar[1].idx = -1;
- }
-
mi->total_packets++;
/* wraparound */
@@ -769,6 +798,16 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
mi->total_packets = 0;
mi->sample_packets = 0;
}
+
+ if (sample_idx < 0)
+ return;
+
+ sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ rate->idx = sample_idx % MCS_GROUP_RATES +
+ (sample_group->streams - 1) * MCS_GROUP_RATES;
+ rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
+ rate->count = 1;
}
static void
@@ -818,6 +857,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
msp->is_ht = true;
memset(mi, 0, sizeof(*mi));
+
+ mi->sta = sta;
mi->stats_update = jiffies;
ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1);
@@ -879,6 +920,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
if (!n_supported)
goto use_legacy;
+ /* create an initial rate table with the lowest supported rates */
+ minstrel_ht_update_stats(mp, mi);
+ minstrel_ht_update_rates(mp, mi);
+
return;
use_legacy:
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
index 302dbd52180d..d655586773ac 100644
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -16,11 +16,6 @@
#define MINSTREL_MAX_STREAMS 3
#define MINSTREL_STREAM_GROUPS 4
-/* scaled fraction values */
-#define MINSTREL_SCALE 16
-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
-#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
-
#define MCS_GROUP_RATES 8
struct mcs_group {
@@ -70,6 +65,8 @@ struct minstrel_mcs_group_data {
};
struct minstrel_ht_sta {
+ struct ieee80211_sta *sta;
+
/* ampdu length (average, per sampling interval) */
unsigned int ampdu_len;
unsigned int ampdu_packets;
@@ -85,6 +82,7 @@ struct minstrel_ht_sta {
/* best probability rate */
unsigned int max_prob_rate;
+ unsigned int max_prob_streams;
/* time of last status update */
unsigned long stats_update;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index bb73ed2d20b9..c8447af76ead 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -648,24 +648,6 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
return RX_CONTINUE;
}
-#define SEQ_MODULO 0x1000
-#define SEQ_MASK 0xfff
-
-static inline int seq_less(u16 sq1, u16 sq2)
-{
- return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1);
-}
-
-static inline u16 seq_inc(u16 sq)
-{
- return (sq + 1) & SEQ_MASK;
-}
-
-static inline u16 seq_sub(u16 sq1, u16 sq2)
-{
- return (sq1 - sq2) & SEQ_MASK;
-}
-
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
struct tid_ampdu_rx *tid_agg_rx,
int index,
@@ -687,7 +669,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
__skb_queue_tail(frames, skb);
no_frame:
- tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+ tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
}
static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata,
@@ -699,8 +681,9 @@ static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata
lockdep_assert_held(&tid_agg_rx->reorder_lock);
- while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
- index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+ while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {
+ index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+ tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
frames);
@@ -727,8 +710,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&tid_agg_rx->reorder_lock);
/* release the buffer until next missing frame */
- index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
- tid_agg_rx->buf_size;
+ index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+ tid_agg_rx->ssn) % tid_agg_rx->buf_size;
if (!tid_agg_rx->reorder_buf[index] &&
tid_agg_rx->stored_mpdu_num) {
/*
@@ -756,19 +739,22 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
* Increment the head seq# also for the skipped slots.
*/
tid_agg_rx->head_seq_num =
- (tid_agg_rx->head_seq_num + skipped) & SEQ_MASK;
+ (tid_agg_rx->head_seq_num +
+ skipped) & IEEE80211_SN_MASK;
skipped = 0;
}
} else while (tid_agg_rx->reorder_buf[index]) {
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
frames);
- index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
+ index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+ tid_agg_rx->ssn) %
tid_agg_rx->buf_size;
}
if (tid_agg_rx->stored_mpdu_num) {
- j = index = seq_sub(tid_agg_rx->head_seq_num,
- tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+ j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,
+ tid_agg_rx->ssn) %
+ tid_agg_rx->buf_size;
for (; j != (index - 1) % tid_agg_rx->buf_size;
j = (j + 1) % tid_agg_rx->buf_size) {
@@ -809,7 +795,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
head_seq_num = tid_agg_rx->head_seq_num;
/* frame with out of date sequence number */
- if (seq_less(mpdu_seq_num, head_seq_num)) {
+ if (ieee80211_sn_less(mpdu_seq_num, head_seq_num)) {
dev_kfree_skb(skb);
goto out;
}
@@ -818,8 +804,9 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
* If frame the sequence number exceeds our buffering window
* size release some previous frames to make room for this one.
*/
- if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) {
- head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size));
+ if (!ieee80211_sn_less(mpdu_seq_num, head_seq_num + buf_size)) {
+ head_seq_num = ieee80211_sn_inc(
+ ieee80211_sn_sub(mpdu_seq_num, buf_size));
/* release stored frames up to new head to stack */
ieee80211_release_reorder_frames(sdata, tid_agg_rx,
head_seq_num, frames);
@@ -827,7 +814,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
/* Now the new frame is always in the range of the reordering buffer */
- index = seq_sub(mpdu_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size;
+ index = ieee80211_sn_sub(mpdu_seq_num,
+ tid_agg_rx->ssn) % tid_agg_rx->buf_size;
/* check if we already stored this frame */
if (tid_agg_rx->reorder_buf[index]) {
@@ -843,7 +831,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
*/
if (mpdu_seq_num == tid_agg_rx->head_seq_num &&
tid_agg_rx->stored_mpdu_num == 0) {
- tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
+ tid_agg_rx->head_seq_num =
+ ieee80211_sn_inc(tid_agg_rx->head_seq_num);
ret = false;
goto out;
}
@@ -1894,8 +1883,10 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
* 'align' will only take the values 0 or 2 here
* since all frames are required to be aligned
* to 2-byte boundaries when being passed to
- * mac80211. That also explains the __skb_push()
- * below.
+ * mac80211; the code here works just as well if
+ * that isn't true, but mac80211 assumes it can
+ * access fields as 2-byte aligned (e.g. for
+ * compare_ether_addr)
*/
align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
if (align) {
@@ -2094,6 +2085,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
}
fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
+ fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
@@ -2432,6 +2424,22 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
break;
+ case WLAN_CATEGORY_PUBLIC:
+ if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+ goto invalid;
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ break;
+ if (!rx->sta)
+ break;
+ if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
+ break;
+ if (mgmt->u.action.u.ext_chan_switch.action_code !=
+ WLAN_PUB_ACTION_EXT_CHANSW_ANN)
+ break;
+ if (len < offsetof(struct ieee80211_mgmt,
+ u.action.u.ext_chan_switch.variable))
+ goto invalid;
+ goto queue;
case WLAN_CATEGORY_VHT:
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
@@ -2515,10 +2523,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
ieee80211_process_measurement_req(sdata, mgmt, len);
goto handled;
case WLAN_ACTION_SPCT_CHL_SWITCH:
- if (len < (IEEE80211_MIN_ACTION_SIZE +
- sizeof(mgmt->u.action.u.chan_switch)))
- break;
-
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
@@ -2552,7 +2556,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
case WLAN_SP_MESH_PEERING_CONFIRM:
if (!ieee80211_vif_is_mesh(&sdata->vif))
goto invalid;
- if (sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+ if (sdata->u.mesh.user_mpm)
/* userspace handles this frame */
break;
goto queue;
@@ -2675,7 +2679,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
memset(nskb->cb, 0, sizeof(nskb->cb));
- ieee80211_tx_skb(rx->sdata, nskb);
+ if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
+
+ info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
+ IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
+ IEEE80211_TX_CTL_NO_CCK_RATE;
+ if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+ info->hw_queue =
+ local->hw.offchannel_tx_hw_queue;
+ }
+
+ __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7,
+ status->band);
}
dev_kfree_skb(rx->skb);
return RX_QUEUED;
@@ -3039,7 +3055,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
!ieee80211_is_probe_resp(hdr->frame_control) &&
!ieee80211_is_beacon(hdr->frame_control))
return 0;
- if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
+ if (!ether_addr_equal(sdata->vif.addr, hdr->addr1) &&
+ !multicast)
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
break;
default:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 43a45cf00e06..99b103921a4b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -98,9 +98,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
}
/* save the ERP value so that it is available at association time */
- if (elems->erp_info && elems->erp_info_len >= 1 &&
- (!elems->parse_error ||
- !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
+ if (elems->erp_info && (!elems->parse_error ||
+ !(bss->valid_data & IEEE80211_BSS_VALID_ERP))) {
bss->erp_value = elems->erp_info[0];
bss->has_erp_value = true;
if (!elems->parse_error)
@@ -153,7 +152,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
u8 *elements;
struct ieee80211_channel *channel;
size_t baselen;
- bool beacon;
struct ieee802_11_elems elems;
if (skb->len < 24 ||
@@ -175,17 +173,15 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
elements = mgmt->u.probe_resp.variable;
baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
- beacon = false;
} else {
baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
elements = mgmt->u.beacon.variable;
- beacon = true;
}
if (baselen > skb->len)
return;
- ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
+ ieee802_11_parse_elems(elements, skb->len - baselen, false, &elems);
channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
@@ -335,7 +331,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
ieee80211_offchannel_stop_vifs(local);
/* ensure nullfunc is transmitted before leaving operating channel */
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
ieee80211_configure_filter(local);
@@ -387,7 +383,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
{
int i;
struct ieee80211_sub_if_data *sdata;
- enum ieee80211_band band = local->hw.conf.channel->band;
+ enum ieee80211_band band = local->hw.conf.chandef.chan->band;
u32 tx_flags;
tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
@@ -404,7 +400,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len,
local->scan_req->rates[band], false,
- tx_flags, local->hw.conf.channel, true);
+ tx_flags, local->hw.conf.chandef.chan, true);
/*
* After sending probe requests, wait for probe responses
@@ -470,7 +466,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
if (local->ops->hw_scan) {
__set_bit(SCAN_HW_SCANNING, &local->scanning);
} else if ((req->n_channels == 1) &&
- (req->channels[0] == local->_oper_channel)) {
+ (req->channels[0] == local->_oper_chandef.chan)) {
/*
* If we are scanning only on the operating channel
* then we do not need to stop normal activities
@@ -671,7 +667,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
ieee80211_offchannel_stop_vifs(local);
if (local->ops->flush) {
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
*next_delay = 0;
} else
*next_delay = HZ / 10;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a79ce820cb50..11216bc13b27 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -342,6 +342,11 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
+#ifdef CONFIG_MAC80211_MESH
+ if (ieee80211_vif_is_mesh(&sdata->vif) &&
+ !sdata->u.mesh.user_mpm)
+ init_timer(&sta->plink_timer);
+#endif
memcpy(sta->sta.addr, addr, ETH_ALEN);
sta->local = local;
@@ -551,6 +556,15 @@ static inline void __bss_tim_clear(u8 *tim, u16 id)
tim[id / 8] &= ~(1 << (id % 8));
}
+static inline bool __bss_tim_get(u8 *tim, u16 id)
+{
+ /*
+ * This format has been mandated by the IEEE specifications,
+ * so this line may not be changed to use the test_bit() format.
+ */
+ return tim[id / 8] & (1 << (id % 8));
+}
+
static unsigned long ieee80211_tids_for_ac(int ac)
{
/* If we ever support TIDs > 7, this obviously needs to be adjusted */
@@ -631,6 +645,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
done:
spin_lock_bh(&local->tim_lock);
+ if (indicate_tim == __bss_tim_get(ps->tim, id))
+ goto out_unlock;
+
if (indicate_tim)
__bss_tim_set(ps->tim, id);
else
@@ -642,6 +659,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
local->tim_in_locked_section = false;
}
+out_unlock:
spin_unlock_bh(&local->tim_lock);
}
@@ -765,7 +783,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
{
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- int ret, i;
+ int ret;
might_sleep();
@@ -792,12 +810,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
list_del_rcu(&sta->list);
- mutex_lock(&local->key_mtx);
- for (i = 0; i < NUM_DEFAULT_KEYS; i++)
- __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
- if (sta->ptk)
- __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
- mutex_unlock(&local->key_mtx);
+ /* this always calls synchronize_net() */
+ ieee80211_free_sta_keys(local, sta);
sta->dead = true;
@@ -1383,30 +1397,16 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_sta_block_awake);
-void ieee80211_sta_eosp_irqsafe(struct ieee80211_sta *pubsta)
+void ieee80211_sta_eosp(struct ieee80211_sta *pubsta)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_local *local = sta->local;
- struct sk_buff *skb;
- struct skb_eosp_msg_data *data;
trace_api_eosp(local, pubsta);
- skb = alloc_skb(0, GFP_ATOMIC);
- if (!skb) {
- /* too bad ... but race is better than loss */
- clear_sta_flag(sta, WLAN_STA_SP);
- return;
- }
-
- data = (void *)skb->cb;
- memcpy(data->sta, pubsta->addr, ETH_ALEN);
- memcpy(data->iface, sta->sdata->vif.addr, ETH_ALEN);
- skb->pkt_type = IEEE80211_EOSP_MSG;
- skb_queue_tail(&local->skb_queue, skb);
- tasklet_schedule(&local->tasklet);
+ clear_sta_flag(sta, WLAN_STA_SP);
}
-EXPORT_SYMBOL(ieee80211_sta_eosp_irqsafe);
+EXPORT_SYMBOL(ieee80211_sta_eosp);
void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
u8 tid, bool buffered)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 4947341a2a82..adc30045f99e 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -281,7 +281,6 @@ struct sta_ampdu_mlme {
* @plink_state: peer link state
* @plink_timeout: timeout of peer link
* @plink_timer: peer link watch timer
- * @plink_timer_was_running: used by suspend/resume to restore timers
* @t_offset: timing offset relative to this host
* @t_offset_setpoint: reference timing offset of this sta to be used when
* calculating clockdrift
@@ -334,7 +333,8 @@ struct sta_info {
unsigned long driver_buffered_tids;
/* Updated from RX path only, no locking requirements */
- unsigned long rx_packets, rx_bytes;
+ unsigned long rx_packets;
+ u64 rx_bytes;
unsigned long wep_weak_iv_count;
unsigned long last_rx;
long last_connected;
@@ -354,9 +354,9 @@ struct sta_info {
unsigned int fail_avg;
/* Updated from TX path only, no locking requirements */
- unsigned long tx_packets;
- unsigned long tx_bytes;
- unsigned long tx_fragments;
+ u32 tx_fragments;
+ u64 tx_packets[IEEE80211_NUM_ACS];
+ u64 tx_bytes[IEEE80211_NUM_ACS];
struct ieee80211_tx_rate last_tx_rate;
int last_rx_rate_idx;
u32 last_rx_rate_flag;
@@ -379,7 +379,6 @@ struct sta_info {
__le16 reason;
u8 plink_retries;
bool ignore_plink_timer;
- bool plink_timer_was_running;
enum nl80211_plink_state plink_state;
u32 plink_timeout;
struct timer_list plink_timer;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 3d7cd2a0582f..c215fafd7a2f 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -28,27 +28,27 @@
#define VIF_PR_FMT " vif:%s(%d%s)"
#define VIF_PR_ARG __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
-#define CHANDEF_ENTRY __field(u32, control_freq) \
- __field(u32, chan_width) \
- __field(u32, center_freq1) \
+#define CHANDEF_ENTRY __field(u32, control_freq) \
+ __field(u32, chan_width) \
+ __field(u32, center_freq1) \
__field(u32, center_freq2)
-#define CHANDEF_ASSIGN(c) \
- __entry->control_freq = (c)->chan->center_freq; \
- __entry->chan_width = (c)->width; \
- __entry->center_freq1 = (c)->center_freq1; \
+#define CHANDEF_ASSIGN(c) \
+ __entry->control_freq = (c)->chan ? (c)->chan->center_freq : 0; \
+ __entry->chan_width = (c)->width; \
+ __entry->center_freq1 = (c)->center_freq1; \
__entry->center_freq2 = (c)->center_freq2;
#define CHANDEF_PR_FMT " control:%d MHz width:%d center: %d/%d MHz"
-#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
+#define CHANDEF_PR_ARG __entry->control_freq, __entry->chan_width, \
__entry->center_freq1, __entry->center_freq2
-#define CHANCTX_ENTRY CHANDEF_ENTRY \
- __field(u8, rx_chains_static) \
+#define CHANCTX_ENTRY CHANDEF_ENTRY \
+ __field(u8, rx_chains_static) \
__field(u8, rx_chains_dynamic)
-#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \
- __entry->rx_chains_static = ctx->conf.rx_chains_static; \
+#define CHANCTX_ASSIGN CHANDEF_ASSIGN(&ctx->conf.def) \
+ __entry->rx_chains_static = ctx->conf.rx_chains_static; \
__entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
#define CHANCTX_PR_FMT CHANDEF_PR_FMT " chains:%d/%d"
-#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \
+#define CHANCTX_PR_ARG CHANDEF_PR_ARG, \
__entry->rx_chains_static, __entry->rx_chains_dynamic
@@ -286,8 +286,7 @@ TRACE_EVENT(drv_config,
__field(u16, listen_interval)
__field(u8, long_frame_max_tx_count)
__field(u8, short_frame_max_tx_count)
- __field(int, center_freq)
- __field(int, channel_type)
+ CHANDEF_ENTRY
__field(int, smps)
),
@@ -303,15 +302,13 @@ TRACE_EVENT(drv_config,
local->hw.conf.long_frame_max_tx_count;
__entry->short_frame_max_tx_count =
local->hw.conf.short_frame_max_tx_count;
- __entry->center_freq = local->hw.conf.channel ?
- local->hw.conf.channel->center_freq : 0;
- __entry->channel_type = local->hw.conf.channel_type;
+ CHANDEF_ASSIGN(&local->hw.conf.chandef)
__entry->smps = local->hw.conf.smps_mode;
),
TP_printk(
- LOCAL_PR_FMT " ch:%#x freq:%d",
- LOCAL_PR_ARG, __entry->changed, __entry->center_freq
+ LOCAL_PR_FMT " ch:%#x" CHANDEF_PR_FMT,
+ LOCAL_PR_ARG, __entry->changed, CHANDEF_PR_ARG
)
);
@@ -359,8 +356,7 @@ TRACE_EVENT(drv_bss_info_changed,
__dynamic_array(u8, ssid, info->ssid_len);
__field(bool, hidden_ssid);
__field(int, txpower)
- __field(u8, p2p_ctwindow)
- __field(bool, p2p_oppps)
+ __field(u8, p2p_oppps_ctwindow)
),
TP_fast_assign(
@@ -400,8 +396,7 @@ TRACE_EVENT(drv_bss_info_changed,
memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
__entry->hidden_ssid = info->hidden_ssid;
__entry->txpower = info->txpower;
- __entry->p2p_ctwindow = info->p2p_ctwindow;
- __entry->p2p_oppps = info->p2p_oppps;
+ __entry->p2p_oppps_ctwindow = info->p2p_noa_attr.oppps_ctwindow;
),
TP_printk(
@@ -431,6 +426,30 @@ TRACE_EVENT(drv_prepare_multicast,
)
);
+TRACE_EVENT(drv_set_multicast_list,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata, int mc_count),
+
+ TP_ARGS(local, sdata, mc_count),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(bool, allmulti)
+ __field(int, mc_count)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->allmulti = sdata->flags & IEEE80211_SDATA_ALLMULTI;
+ __entry->mc_count = mc_count;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " configure mc filter, count=%d, allmulti=%d",
+ LOCAL_PR_ARG, __entry->mc_count, __entry->allmulti
+ )
+);
+
TRACE_EVENT(drv_configure_filter,
TP_PROTO(struct ieee80211_local *local,
unsigned int changed_flags,
@@ -940,23 +959,26 @@ TRACE_EVENT(drv_get_survey,
);
TRACE_EVENT(drv_flush,
- TP_PROTO(struct ieee80211_local *local, bool drop),
+ TP_PROTO(struct ieee80211_local *local,
+ u32 queues, bool drop),
- TP_ARGS(local, drop),
+ TP_ARGS(local, queues, drop),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(bool, drop)
+ __field(u32, queues)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->drop = drop;
+ __entry->queues = queues;
),
TP_printk(
- LOCAL_PR_FMT " drop:%d",
- LOCAL_PR_ARG, __entry->drop
+ LOCAL_PR_FMT " queues:0x%x drop:%d",
+ LOCAL_PR_ARG, __entry->queues, __entry->drop
)
);
@@ -968,23 +990,23 @@ TRACE_EVENT(drv_channel_switch,
TP_STRUCT__entry(
LOCAL_ENTRY
+ CHANDEF_ENTRY
__field(u64, timestamp)
__field(bool, block_tx)
- __field(u16, freq)
__field(u8, count)
),
TP_fast_assign(
LOCAL_ASSIGN;
+ CHANDEF_ASSIGN(&ch_switch->chandef)
__entry->timestamp = ch_switch->timestamp;
__entry->block_tx = ch_switch->block_tx;
- __entry->freq = ch_switch->channel->center_freq;
__entry->count = ch_switch->count;
),
TP_printk(
- LOCAL_PR_FMT " new freq:%u count:%d",
- LOCAL_PR_ARG, __entry->freq, __entry->count
+ LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+ LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
)
);
@@ -1042,15 +1064,17 @@ TRACE_EVENT(drv_remain_on_channel,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
- unsigned int duration),
+ unsigned int duration,
+ enum ieee80211_roc_type type),
- TP_ARGS(local, sdata, chan, duration),
+ TP_ARGS(local, sdata, chan, duration, type),
TP_STRUCT__entry(
LOCAL_ENTRY
VIF_ENTRY
__field(int, center_freq)
__field(unsigned int, duration)
+ __field(u32, type)
),
TP_fast_assign(
@@ -1058,12 +1082,13 @@ TRACE_EVENT(drv_remain_on_channel,
VIF_ASSIGN;
__entry->center_freq = chan->center_freq;
__entry->duration = duration;
+ __entry->type = type;
),
TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms",
+ LOCAL_PR_FMT VIF_PR_FMT " freq:%dMHz duration:%dms type=%d",
LOCAL_PR_ARG, VIF_PR_ARG,
- __entry->center_freq, __entry->duration
+ __entry->center_freq, __entry->duration, __entry->type
)
);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 8914d2d2881a..9972e07a2f96 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -48,15 +48,15 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
/* assume HW handles this */
- if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+ if (tx->rate.flags & IEEE80211_TX_RC_MCS)
return 0;
/* uh huh? */
- if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
+ if (WARN_ON_ONCE(tx->rate.idx < 0))
return 0;
sband = local->hw.wiphy->bands[info->band];
- txrate = &sband->bitrates[info->control.rates[0].idx];
+ txrate = &sband->bitrates[tx->rate.idx];
erp = txrate->flags & IEEE80211_RATE_ERP_G;
@@ -233,6 +233,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
+ IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_PS);
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
ieee80211_queue_work(&local->hw,
@@ -616,11 +617,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
struct ieee80211_hdr *hdr = (void *)tx->skb->data;
struct ieee80211_supported_band *sband;
- struct ieee80211_rate *rate;
- int i;
u32 len;
- bool inval = false, rts = false, short_preamble = false;
struct ieee80211_tx_rate_control txrc;
+ struct ieee80211_sta_rates *ratetbl = NULL;
bool assoc = false;
memset(&txrc, 0, sizeof(txrc));
@@ -641,18 +640,23 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
- memcpy(txrc.rate_idx_mcs_mask,
- tx->sdata->rc_rateidx_mcs_mask[info->band],
- sizeof(txrc.rate_idx_mcs_mask));
+
+ if (tx->sdata->rc_has_mcs_mask[info->band])
+ txrc.rate_idx_mcs_mask =
+ tx->sdata->rc_rateidx_mcs_mask[info->band];
+
txrc.bss = (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
tx->sdata->vif.type == NL80211_IFTYPE_ADHOC);
/* set up RTS protection if desired */
if (len > tx->local->hw.wiphy->rts_threshold) {
- txrc.rts = rts = true;
+ txrc.rts = true;
}
+ info->control.use_rts = txrc.rts;
+ info->control.use_cts_prot = tx->sdata->vif.bss_conf.use_cts_prot;
+
/*
* Use short preamble if the BSS can handle it, but not for
* management frames unless we know the receiver can handle
@@ -662,7 +666,9 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
if (tx->sdata->vif.bss_conf.use_short_preamble &&
(ieee80211_is_data(hdr->frame_control) ||
(tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
- txrc.short_preamble = short_preamble = true;
+ txrc.short_preamble = true;
+
+ info->control.short_preamble = txrc.short_preamble;
if (tx->sta)
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
@@ -686,16 +692,38 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
*/
rate_control_get_rate(tx->sdata, tx->sta, &txrc);
- if (unlikely(info->control.rates[0].idx < 0))
- return TX_DROP;
+ if (tx->sta && !info->control.skip_table)
+ ratetbl = rcu_dereference(tx->sta->sta.rates);
+
+ if (unlikely(info->control.rates[0].idx < 0)) {
+ if (ratetbl) {
+ struct ieee80211_tx_rate rate = {
+ .idx = ratetbl->rate[0].idx,
+ .flags = ratetbl->rate[0].flags,
+ .count = ratetbl->rate[0].count
+ };
+
+ if (ratetbl->rate[0].idx < 0)
+ return TX_DROP;
+
+ tx->rate = rate;
+ } else {
+ return TX_DROP;
+ }
+ } else {
+ tx->rate = info->control.rates[0];
+ }
if (txrc.reported_rate.idx < 0) {
- txrc.reported_rate = info->control.rates[0];
+ txrc.reported_rate = tx->rate;
if (tx->sta && ieee80211_is_data(hdr->frame_control))
tx->sta->last_tx_rate = txrc.reported_rate;
} else if (tx->sta)
tx->sta->last_tx_rate = txrc.reported_rate;
+ if (ratetbl)
+ return TX_CONTINUE;
+
if (unlikely(!info->control.rates[0].count))
info->control.rates[0].count = 1;
@@ -703,91 +731,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
(info->flags & IEEE80211_TX_CTL_NO_ACK)))
info->control.rates[0].count = 1;
- if (is_multicast_ether_addr(hdr->addr1)) {
- /*
- * XXX: verify the rate is in the basic rateset
- */
- return TX_CONTINUE;
- }
-
- /*
- * set up the RTS/CTS rate as the fastest basic rate
- * that is not faster than the data rate
- *
- * XXX: Should this check all retry rates?
- */
- if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
- s8 baserate = 0;
-
- rate = &sband->bitrates[info->control.rates[0].idx];
-
- for (i = 0; i < sband->n_bitrates; i++) {
- /* must be a basic rate */
- if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i)))
- continue;
- /* must not be faster than the data rate */
- if (sband->bitrates[i].bitrate > rate->bitrate)
- continue;
- /* maximum */
- if (sband->bitrates[baserate].bitrate <
- sband->bitrates[i].bitrate)
- baserate = i;
- }
-
- info->control.rts_cts_rate_idx = baserate;
- }
-
- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
- /*
- * make sure there's no valid rate following
- * an invalid one, just in case drivers don't
- * take the API seriously to stop at -1.
- */
- if (inval) {
- info->control.rates[i].idx = -1;
- continue;
- }
- if (info->control.rates[i].idx < 0) {
- inval = true;
- continue;
- }
-
- /*
- * For now assume MCS is already set up correctly, this
- * needs to be fixed.
- */
- if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
- WARN_ON(info->control.rates[i].idx > 76);
- continue;
- }
-
- /* set up RTS protection if desired */
- if (rts)
- info->control.rates[i].flags |=
- IEEE80211_TX_RC_USE_RTS_CTS;
-
- /* RC is busted */
- if (WARN_ON_ONCE(info->control.rates[i].idx >=
- sband->n_bitrates)) {
- info->control.rates[i].idx = -1;
- continue;
- }
-
- rate = &sband->bitrates[info->control.rates[i].idx];
-
- /* set up short preamble */
- if (short_preamble &&
- rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
- info->control.rates[i].flags |=
- IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
-
- /* set up G protection */
- if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
- rate->flags & IEEE80211_RATE_ERP_G)
- info->control.rates[i].flags |=
- IEEE80211_TX_RC_USE_CTS_PROTECT;
- }
-
return TX_CONTINUE;
}
@@ -991,15 +934,18 @@ static ieee80211_tx_result debug_noinline
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb;
+ int ac = -1;
if (!tx->sta)
return TX_CONTINUE;
- tx->sta->tx_packets++;
skb_queue_walk(&tx->skbs, skb) {
+ ac = skb_get_queue_mapping(skb);
tx->sta->tx_fragments++;
- tx->sta->tx_bytes += skb->len;
+ tx->sta->tx_bytes[ac] += skb->len;
}
+ if (ac >= 0)
+ tx->sta->tx_packets[ac]++;
return TX_CONTINUE;
}
@@ -1705,7 +1651,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
if (chanctx_conf)
chan = chanctx_conf->def.chan;
else if (!local->use_chanctx)
- chan = local->_oper_channel;
+ chan = local->_oper_chandef.chan;
else
goto fail_rcu;
@@ -1839,7 +1785,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
* This is the exception! WDS style interfaces are prohibited
* when channel contexts are in used so this must be valid
*/
- band = local->hw.conf.channel->band;
+ band = local->hw.conf.chandef.chan->band;
break;
#ifdef CONFIG_MAC80211_MESH
case NL80211_IFTYPE_MESH_POINT:
@@ -2085,7 +2031,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
encaps_data = bridge_tunnel_header;
encaps_len = sizeof(bridge_tunnel_header);
skip_header_bytes -= 2;
- } else if (ethertype >= 0x600) {
+ } else if (ethertype >= ETH_P_802_3_MIN) {
encaps_data = rfc1042_header;
encaps_len = sizeof(rfc1042_header);
skip_header_bytes -= 2;
@@ -2438,14 +2384,17 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_hdr *hdr;
- struct sk_buff *presp = rcu_dereference(ifibss->presp);
+ struct beacon_data *presp = rcu_dereference(ifibss->presp);
if (!presp)
goto out;
- skb = skb_copy(presp, GFP_ATOMIC);
+ skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
if (!skb)
goto out;
+ skb_reserve(skb, local->tx_headroom);
+ memcpy(skb_put(skb, presp->head_len), presp->head,
+ presp->head_len);
hdr = (struct ieee80211_hdr *) skb->data;
hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
@@ -2495,8 +2444,6 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
txrc.max_rate_idx = -1;
else
txrc.max_rate_idx = fls(txrc.rate_idx_mask) - 1;
- memcpy(txrc.rate_idx_mcs_mask, sdata->rc_rateidx_mcs_mask[band],
- sizeof(txrc.rate_idx_mcs_mask));
txrc.bss = true;
rate_control_get_rate(sdata, NULL, &txrc);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 0f38f43ac62e..3f87fa468b1f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -453,7 +453,8 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
}
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
- enum queue_stop_reason reason)
+ unsigned long queues,
+ enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
unsigned long flags;
@@ -461,7 +462,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
+ for_each_set_bit(i, &queues, hw->queues)
__ieee80211_stop_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -469,7 +470,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
- ieee80211_stop_queues_by_reason(hw,
+ ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_stop_queues);
@@ -484,13 +485,15 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
return true;
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- ret = !!local->queue_stop_reasons[queue];
+ ret = test_bit(IEEE80211_QUEUE_STOP_REASON_DRIVER,
+ &local->queue_stop_reasons[queue]);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
return ret;
}
EXPORT_SYMBOL(ieee80211_queue_stopped);
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
+ unsigned long queues,
enum queue_stop_reason reason)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -499,7 +502,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- for (i = 0; i < hw->queues; i++)
+ for_each_set_bit(i, &queues, hw->queues)
__ieee80211_wake_queue(hw, i, reason);
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -507,10 +510,42 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
void ieee80211_wake_queues(struct ieee80211_hw *hw)
{
- ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
+ ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
EXPORT_SYMBOL(ieee80211_wake_queues);
+void ieee80211_flush_queues(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ u32 queues;
+
+ if (!local->ops->flush)
+ return;
+
+ if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
+ int ac;
+
+ queues = 0;
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+ queues |= BIT(sdata->vif.hw_queue[ac]);
+ if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
+ queues |= BIT(sdata->vif.cab_queue);
+ } else {
+ /* all queues */
+ queues = BIT(local->hw.queues) - 1;
+ }
+
+ ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH);
+
+ drv_flush(local, queues, false);
+
+ ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_FLUSH);
+}
+
void ieee80211_iterate_active_interfaces(
struct ieee80211_hw *hw, u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
@@ -626,7 +661,7 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
-u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
+u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
u64 filter, u32 crc)
{
@@ -634,6 +669,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
u8 *pos = start;
bool calc_crc = filter != 0;
DECLARE_BITMAP(seen_elems, 256);
+ const u8 *ie;
bitmap_zero(seen_elems, 256);
memset(elems, 0, sizeof(*elems));
@@ -681,6 +717,12 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
case WLAN_EID_COUNTRY:
case WLAN_EID_PWR_CONSTRAINT:
case WLAN_EID_TIMEOUT_INTERVAL:
+ case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
+ case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
+ /*
+ * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
+ * that if the content gets bigger it might be needed more than once
+ */
if (test_bit(id, seen_elems)) {
elems->parse_error = true;
left -= elen;
@@ -704,17 +746,11 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
elems->supp_rates = pos;
elems->supp_rates_len = elen;
break;
- case WLAN_EID_FH_PARAMS:
- elems->fh_params = pos;
- elems->fh_params_len = elen;
- break;
case WLAN_EID_DS_PARAMS:
- elems->ds_params = pos;
- elems->ds_params_len = elen;
- break;
- case WLAN_EID_CF_PARAMS:
- elems->cf_params = pos;
- elems->cf_params_len = elen;
+ if (elen >= 1)
+ elems->ds_params = pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_TIM:
if (elen >= sizeof(struct ieee80211_tim_ie)) {
@@ -723,10 +759,6 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
} else
elem_parse_failed = true;
break;
- case WLAN_EID_IBSS_PARAMS:
- elems->ibss_params = pos;
- elems->ibss_params_len = elen;
- break;
case WLAN_EID_CHALLENGE:
elems->challenge = pos;
elems->challenge_len = elen;
@@ -756,8 +788,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
elems->rsn_len = elen;
break;
case WLAN_EID_ERP_INFO:
- elems->erp_info = pos;
- elems->erp_info_len = elen;
+ if (elen >= 1)
+ elems->erp_info = pos;
+ else
+ elem_parse_failed = true;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
@@ -836,12 +870,47 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
}
elems->ch_switch_ie = (void *)pos;
break;
- case WLAN_EID_QUIET:
- if (!elems->quiet_elem) {
- elems->quiet_elem = pos;
- elems->quiet_elem_len = elen;
+ case WLAN_EID_EXT_CHANSWITCH_ANN:
+ if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->ext_chansw_ie = (void *)pos;
+ break;
+ case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
+ if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->sec_chan_offs = (void *)pos;
+ break;
+ case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
+ if (!action ||
+ elen != sizeof(*elems->wide_bw_chansw_ie)) {
+ elem_parse_failed = true;
+ break;
+ }
+ elems->wide_bw_chansw_ie = (void *)pos;
+ break;
+ case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
+ if (action) {
+ elem_parse_failed = true;
+ break;
+ }
+ /*
+ * This is a bit tricky, but as we only care about
+ * the wide bandwidth channel switch element, so
+ * just parse it out manually.
+ */
+ ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
+ pos, elen);
+ if (ie) {
+ if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
+ elems->wide_bw_chansw_ie =
+ (void *)(ie + 2);
+ else
+ elem_parse_failed = true;
}
- elems->num_of_quiet_elem++;
break;
case WLAN_EID_COUNTRY:
elems->country_elem = pos;
@@ -855,8 +924,10 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
elems->pwr_constr_elem = pos;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
- elems->timeout_int = pos;
- elems->timeout_int_len = elen;
+ if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
+ elems->timeout_int = (void *)pos;
+ else
+ elem_parse_failed = true;
break;
default:
break;
@@ -877,12 +948,6 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
return crc;
}
-void ieee802_11_parse_elems(u8 *start, size_t len,
- struct ieee802_11_elems *elems)
-{
- ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
-}
-
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
bool bss_notify)
{
@@ -1357,6 +1422,25 @@ void ieee80211_stop_device(struct ieee80211_local *local)
drv_stop(local);
}
+static void ieee80211_assign_chanctx(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_chanctx_conf *conf;
+ struct ieee80211_chanctx *ctx;
+
+ if (!local->use_chanctx)
+ return;
+
+ mutex_lock(&local->chanctx_mtx);
+ conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+ lockdep_is_held(&local->chanctx_mtx));
+ if (conf) {
+ ctx = container_of(conf, struct ieee80211_chanctx, conf);
+ drv_assign_vif_chanctx(local, sdata, ctx);
+ }
+ mutex_unlock(&local->chanctx_mtx);
+}
+
int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;
@@ -1421,6 +1505,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
/* add interfaces */
sdata = rtnl_dereference(local->monitor_sdata);
if (sdata) {
+ /* in HW restart it exists already */
+ WARN_ON(local->resuming);
res = drv_add_interface(local, sdata);
if (WARN_ON(res)) {
rcu_assign_pointer(local->monitor_sdata, NULL);
@@ -1445,36 +1531,14 @@ int ieee80211_reconfig(struct ieee80211_local *local)
}
list_for_each_entry(sdata, &local->interfaces, list) {
- struct ieee80211_chanctx_conf *ctx_conf;
-
if (!ieee80211_sdata_running(sdata))
continue;
-
- mutex_lock(&local->chanctx_mtx);
- ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
- if (ctx_conf) {
- ctx = container_of(ctx_conf, struct ieee80211_chanctx,
- conf);
- drv_assign_vif_chanctx(local, sdata, ctx);
- }
- mutex_unlock(&local->chanctx_mtx);
+ ieee80211_assign_chanctx(local, sdata);
}
sdata = rtnl_dereference(local->monitor_sdata);
- if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) {
- struct ieee80211_chanctx_conf *ctx_conf;
-
- mutex_lock(&local->chanctx_mtx);
- ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
- lockdep_is_held(&local->chanctx_mtx));
- if (ctx_conf) {
- ctx = container_of(ctx_conf, struct ieee80211_chanctx,
- conf);
- drv_assign_vif_chanctx(local, sdata, ctx);
- }
- mutex_unlock(&local->chanctx_mtx);
- }
+ if (sdata && ieee80211_sdata_running(sdata))
+ ieee80211_assign_chanctx(local, sdata);
/* add STAs back */
mutex_lock(&local->sta_mtx);
@@ -1534,11 +1598,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_IDLE |
BSS_CHANGED_TXPOWER;
-#ifdef CONFIG_PM
- if (local->resuming && !reconfig_due_to_wowlan)
- sdata->vif.bss_conf = sdata->suspend_bss_conf;
-#endif
-
switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION:
changed |= BSS_CHANGED_ASSOC |
@@ -1637,6 +1696,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
local->in_reconfig = false;
barrier();
+ if (local->monitors == local->open_count && local->monitors > 0)
+ ieee80211_add_virtual_monitor(local);
+
/*
* Clear the WLAN_STA_BLOCK_BA flag so new aggregation
* sessions can be established after a resume.
@@ -1659,8 +1721,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_unlock(&local->sta_mtx);
}
- ieee80211_wake_queues_by_reason(hw,
- IEEE80211_QUEUE_STOP_REASON_SUSPEND);
+ ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
+ IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* If this is for hw restart things are still running.
@@ -1678,28 +1740,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mb();
local->resuming = false;
- list_for_each_entry(sdata, &local->interfaces, list) {
- switch(sdata->vif.type) {
- case NL80211_IFTYPE_STATION:
- ieee80211_sta_restart(sdata);
- break;
- case NL80211_IFTYPE_ADHOC:
- ieee80211_ibss_restart(sdata);
- break;
- case NL80211_IFTYPE_MESH_POINT:
- ieee80211_mesh_restart(sdata);
- break;
- default:
- break;
- }
- }
-
mod_timer(&local->sta_cleanup, jiffies + 1);
-
- mutex_lock(&local->sta_mtx);
- list_for_each_entry(sta, &local->sta_list, list)
- mesh_plink_restart(sta);
- mutex_unlock(&local->sta_mtx);
#else
WARN_ON(1);
#endif
@@ -2051,7 +2092,7 @@ int ieee80211_ave_rssi(struct ieee80211_vif *vif)
/* non-managed type inferfaces */
return 0;
}
- return ifmgd->ave_beacon_signal;
+ return ifmgd->ave_beacon_signal / 16;
}
EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
@@ -2166,8 +2207,7 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work)
/* currently not handled */
WARN_ON(1);
else {
- cfg80211_chandef_create(&chandef, local->hw.conf.channel,
- local->hw.conf.channel_type);
+ chandef = local->hw.conf.chandef;
cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
}
}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index a2c2258bc84e..171344d4eb7c 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -13,6 +13,104 @@
#include "rate.h"
+static void __check_vhtcap_disable(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_vht_cap *vht_cap,
+ u32 flag)
+{
+ __le32 le_flag = cpu_to_le32(flag);
+
+ if (sdata->u.mgd.vht_capa_mask.vht_cap_info & le_flag &&
+ !(sdata->u.mgd.vht_capa.vht_cap_info & le_flag))
+ vht_cap->cap &= ~flag;
+}
+
+void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta_vht_cap *vht_cap)
+{
+ int i;
+ u16 rxmcs_mask, rxmcs_cap, rxmcs_n, txmcs_mask, txmcs_cap, txmcs_n;
+
+ if (!vht_cap->vht_supported)
+ return;
+
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return;
+
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_RXLDPC);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_SHORT_GI_80);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_SHORT_GI_160);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_TXSTBC);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN);
+ __check_vhtcap_disable(sdata, vht_cap,
+ IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
+
+ /* Allow user to decrease AMPDU length exponent */
+ if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
+ cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
+ u32 cap, n;
+
+ n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ n >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+ cap = vht_cap->cap & IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ cap >>= IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+
+ if (n < cap) {
+ vht_cap->cap &=
+ ~IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
+ vht_cap->cap |=
+ n << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
+ }
+ }
+
+ /* Allow the user to decrease MCSes */
+ rxmcs_mask =
+ le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.rx_mcs_map);
+ rxmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.rx_mcs_map);
+ rxmcs_n &= rxmcs_mask;
+ rxmcs_cap = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
+
+ txmcs_mask =
+ le16_to_cpu(sdata->u.mgd.vht_capa_mask.supp_mcs.tx_mcs_map);
+ txmcs_n = le16_to_cpu(sdata->u.mgd.vht_capa.supp_mcs.tx_mcs_map);
+ txmcs_n &= txmcs_mask;
+ txmcs_cap = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+ for (i = 0; i < 8; i++) {
+ u8 m, n, c;
+
+ m = (rxmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ n = (rxmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ c = (rxmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
+ n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
+ rxmcs_cap &= ~(3 << 2*i);
+ rxmcs_cap |= (rxmcs_n & (3 << 2*i));
+ }
+
+ m = (txmcs_mask >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ n = (txmcs_n >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ c = (txmcs_cap >> 2*i) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ if (m && ((c != IEEE80211_VHT_MCS_NOT_SUPPORTED && n < c) ||
+ n == IEEE80211_VHT_MCS_NOT_SUPPORTED)) {
+ txmcs_cap &= ~(3 << 2*i);
+ txmcs_cap |= (txmcs_n & (3 << 2*i));
+ }
+ }
+ vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_cap);
+ vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_cap);
+}
+
void
ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
@@ -20,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
+ struct ieee80211_sta_vht_cap own_cap;
+ u32 cap_info, i;
memset(vht_cap, 0, sizeof(*vht_cap));
@@ -35,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
vht_cap->vht_supported = true;
- vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
+ own_cap = sband->vht_cap;
+ /*
+ * If user has specified capability overrides, take care
+ * of that if the station we're setting up is the AP that
+ * we advertised a restricted capability set to. Override
+ * our own capabilities and then use those below.
+ */
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+ ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
+
+ /* take some capabilities as-is */
+ cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
+ vht_cap->cap = cap_info;
+ vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+ IEEE80211_VHT_CAP_RXLDPC |
+ IEEE80211_VHT_CAP_VHT_TXOP_PS |
+ IEEE80211_VHT_CAP_HTC_VHT |
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+ IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB |
+ IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB |
+ IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
+ IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
+
+ /* and some based on our own capabilities */
+ switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+ case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+ vht_cap->cap |= cap_info &
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ break;
+ case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+ vht_cap->cap |= cap_info &
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+
+ /* symmetric capabilities */
+ vht_cap->cap |= cap_info & own_cap.cap &
+ (IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_SHORT_GI_160);
+
+ /* remaining ones */
+ if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
+ vht_cap->cap |= cap_info &
+ (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
+ IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
+ }
+
+ if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
+ vht_cap->cap |= cap_info &
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+
+ if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
+ vht_cap->cap |= cap_info &
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+ if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
+ vht_cap->cap |= cap_info &
+ IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+ if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
+ vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK;
+
+ if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
+ vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC;
/* Copy peer MCS info, the driver might need them. */
memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
sizeof(struct ieee80211_vht_mcs_info));
+ /* but also restrict MCSes */
+ for (i = 0; i < 8; i++) {
+ u16 own_rx, own_tx, peer_rx, peer_tx;
+
+ own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map);
+ own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map);
+ own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
+ peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
+ peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
+
+ if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
+ if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ else if (own_rx < peer_tx)
+ peer_tx = own_rx;
+ }
+
+ if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
+ if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
+ peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
+ else if (own_tx < peer_rx)
+ peer_rx = own_tx;
+ }
+
+ vht_cap->vht_mcs.rx_mcs_map &=
+ ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
+ vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2);
+
+ vht_cap->vht_mcs.tx_mcs_map &=
+ ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
+ vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
+ }
+
+ /* finally set up the bandwidth */
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h
index a4dcaf1dd4b6..d48422e27110 100644
--- a/net/mac802154/mac802154.h
+++ b/net/mac802154/mac802154.h
@@ -88,9 +88,7 @@ struct mac802154_sub_if_data {
#define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw)
-#define MAC802154_MAX_XMIT_ATTEMPTS 3
-
-#define MAC802154_CHAN_NONE (~(u8)0) /* No channel is assigned */
+#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
@@ -114,5 +112,6 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev);
u16 mac802154_dev_get_pan_id(const struct net_device *dev);
void mac802154_dev_set_pan_id(struct net_device *dev, u16 val);
void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
+u8 mac802154_dev_get_dsn(const struct net_device *dev);
#endif /* MAC802154_H */
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
index d8d277006089..a99910d4d52f 100644
--- a/net/mac802154/mac_cmd.c
+++ b/net/mac802154/mac_cmd.c
@@ -73,4 +73,5 @@ struct ieee802154_mlme_ops mac802154_mlme_wpan = {
.start_req = mac802154_mlme_start_req,
.get_pan_id = mac802154_dev_get_pan_id,
.get_short_addr = mac802154_dev_get_short_addr,
+ .get_dsn = mac802154_dev_get_dsn,
};
diff --git a/net/mac802154/mib.c b/net/mac802154/mib.c
index f47781ab0ccc..8ded97cf1c33 100644
--- a/net/mac802154/mib.c
+++ b/net/mac802154/mib.c
@@ -159,6 +159,15 @@ void mac802154_dev_set_pan_id(struct net_device *dev, u16 val)
}
}
+u8 mac802154_dev_get_dsn(const struct net_device *dev)
+{
+ struct mac802154_sub_if_data *priv = netdev_priv(dev);
+
+ BUG_ON(dev->type != ARPHRD_IEEE802154);
+
+ return priv->dsn++;
+}
+
static void phy_chan_notify(struct work_struct *work)
{
struct phy_chan_notify_work *nw = container_of(work,
@@ -167,9 +176,15 @@ static void phy_chan_notify(struct work_struct *work)
struct mac802154_sub_if_data *priv = netdev_priv(nw->dev);
int res;
+ mutex_lock(&priv->hw->phy->pib_lock);
res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan);
if (res)
pr_debug("set_channel failed\n");
+ else {
+ priv->hw->phy->current_channel = priv->chan;
+ priv->hw->phy->current_page = priv->page;
+ }
+ mutex_unlock(&priv->hw->phy->pib_lock);
kfree(nw);
}
@@ -186,8 +201,11 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
priv->chan = chan;
spin_unlock_bh(&priv->mib_lock);
+ mutex_lock(&priv->hw->phy->pib_lock);
if (priv->hw->phy->current_channel != priv->chan ||
priv->hw->phy->current_page != priv->page) {
+ mutex_unlock(&priv->hw->phy->pib_lock);
+
work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return;
@@ -195,5 +213,6 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
INIT_WORK(&work->work, phy_chan_notify);
work->dev = dev;
queue_work(priv->hw->dev_workqueue, &work->work);
- }
+ } else
+ mutex_unlock(&priv->hw->phy->pib_lock);
}
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index 4e09d070995a..6d1647399d4f 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -25,6 +25,7 @@
#include <linux/if_arp.h>
#include <linux/crc-ccitt.h>
+#include <net/ieee802154_netdev.h>
#include <net/mac802154.h>
#include <net/wpan-phy.h>
@@ -39,12 +40,12 @@ struct xmit_work {
struct mac802154_priv *priv;
u8 chan;
u8 page;
- u8 xmit_attempts;
};
static void mac802154_xmit_worker(struct work_struct *work)
{
struct xmit_work *xw = container_of(work, struct xmit_work, work);
+ struct mac802154_sub_if_data *sdata;
int res;
mutex_lock(&xw->priv->phy->pib_lock);
@@ -57,21 +58,23 @@ static void mac802154_xmit_worker(struct work_struct *work)
pr_debug("set_channel failed\n");
goto out;
}
+
+ xw->priv->phy->current_channel = xw->chan;
+ xw->priv->phy->current_page = xw->page;
}
res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb);
+ if (res)
+ pr_debug("transmission failed\n");
out:
mutex_unlock(&xw->priv->phy->pib_lock);
- if (res) {
- if (xw->xmit_attempts++ < MAC802154_MAX_XMIT_ATTEMPTS) {
- queue_work(xw->priv->dev_workqueue, &xw->work);
- return;
- } else
- pr_debug("transmission failed for %d times",
- MAC802154_MAX_XMIT_ATTEMPTS);
- }
+ /* Restart the netif queue on each sub_if_data object. */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &xw->priv->slaves, list)
+ netif_wake_queue(sdata->dev);
+ rcu_read_unlock();
dev_kfree_skb(xw->skb);
@@ -82,6 +85,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
u8 page, u8 chan)
{
struct xmit_work *work;
+ struct mac802154_sub_if_data *sdata;
if (!(priv->phy->channels_supported[page] & (1 << chan))) {
WARN_ON(1);
@@ -109,12 +113,17 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
+ /* Stop the netif queue on each sub_if_data object. */
+ rcu_read_lock();
+ list_for_each_entry_rcu(sdata, &priv->slaves, list)
+ netif_stop_queue(sdata->dev);
+ rcu_read_unlock();
+
INIT_WORK(&work->work, mac802154_xmit_worker);
work->skb = skb;
work->priv = priv;
work->page = page;
work->chan = chan;
- work->xmit_attempts = 0;
queue_work(priv->dev_workqueue, &work->work);
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
index d20c6d3c247d..2ca2f4dceab7 100644
--- a/net/mac802154/wpan.c
+++ b/net/mac802154/wpan.c
@@ -145,6 +145,8 @@ static int mac802154_header_create(struct sk_buff *skb,
head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
fc = mac_cb_type(skb);
+ if (mac_cb_is_ackreq(skb))
+ fc |= IEEE802154_FC_ACK_REQ;
if (!saddr) {
spin_lock_bh(&priv->mib_lock);
@@ -358,7 +360,7 @@ void mac802154_wpan_setup(struct net_device *dev)
dev->header_ops = &mac802154_header_ops;
dev->needed_tailroom = 2; /* FCS */
dev->mtu = IEEE802154_MTU;
- dev->tx_queue_len = 10;
+ dev->tx_queue_len = 300;
dev->type = ARPHRD_IEEE802154;
dev->flags = IFF_NOARP | IFF_BROADCAST;
dev->watchdog_timeo = 0;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a9c488b6c50d..07c865a31a3d 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -5,6 +5,7 @@
* way.
*
* Rusty Russell (C)2000 -- This code is GPL.
+ * Patrick McHardy (c) 2006-2012
*/
#include <linux/kernel.h>
#include <linux/netfilter.h>
@@ -276,10 +277,30 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
EXPORT_SYMBOL(nf_nat_decode_session_hook);
#endif
+static int __net_init netfilter_net_init(struct net *net)
+{
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
+ net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter",
+ net->proc_net);
+ if (!net->nf.proc_netfilter) {
+ if (!net_eq(net, &init_net))
+ pr_err("cannot create netfilter proc entry");
+
+ return -ENOMEM;
+ }
#endif
+ return 0;
+}
+
+static void __net_exit netfilter_net_exit(struct net *net)
+{
+ remove_proc_entry("netfilter", net->proc_net);
+}
+
+static struct pernet_operations netfilter_net_ops = {
+ .init = netfilter_net_init,
+ .exit = netfilter_net_exit,
+};
void __init netfilter_init(void)
{
@@ -289,11 +310,8 @@ void __init netfilter_init(void)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
- if (!proc_net_netfilter)
+ if (register_pernet_subsys(&netfilter_net_ops) < 0)
panic("cannot create netfilter proc entry");
-#endif
if (netfilter_log_init() < 0)
panic("cannot initialize nf_log");
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
new file mode 100644
index 000000000000..25243379b887
--- /dev/null
+++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
@@ -0,0 +1,277 @@
+/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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 __IP_SET_BITMAP_IP_GEN_H
+#define __IP_SET_BITMAP_IP_GEN_H
+
+#define CONCAT(a, b) a##b
+#define TOKEN(a,b) CONCAT(a, b)
+
+#define mtype_do_test TOKEN(MTYPE, _do_test)
+#define mtype_gc_test TOKEN(MTYPE, _gc_test)
+#define mtype_is_filled TOKEN(MTYPE, _is_filled)
+#define mtype_do_add TOKEN(MTYPE, _do_add)
+#define mtype_do_del TOKEN(MTYPE, _do_del)
+#define mtype_do_list TOKEN(MTYPE, _do_list)
+#define mtype_do_head TOKEN(MTYPE, _do_head)
+#define mtype_adt_elem TOKEN(MTYPE, _adt_elem)
+#define mtype_add_timeout TOKEN(MTYPE, _add_timeout)
+#define mtype_gc_init TOKEN(MTYPE, _gc_init)
+#define mtype_kadt TOKEN(MTYPE, _kadt)
+#define mtype_uadt TOKEN(MTYPE, _uadt)
+#define mtype_destroy TOKEN(MTYPE, _destroy)
+#define mtype_flush TOKEN(MTYPE, _flush)
+#define mtype_head TOKEN(MTYPE, _head)
+#define mtype_same_set TOKEN(MTYPE, _same_set)
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_test TOKEN(MTYPE, _test)
+#define mtype_add TOKEN(MTYPE, _add)
+#define mtype_del TOKEN(MTYPE, _del)
+#define mtype_list TOKEN(MTYPE, _list)
+#define mtype_gc TOKEN(MTYPE, _gc)
+#define mtype MTYPE
+
+#define ext_timeout(e, m) \
+ (unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, m) \
+ (struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER])
+#define get_ext(map, id) ((map)->extensions + (map)->dsize * (id))
+
+static void
+mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
+{
+ struct mtype *map = set->data;
+
+ init_timer(&map->gc);
+ map->gc.data = (unsigned long) set;
+ map->gc.function = gc;
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
+ add_timer(&map->gc);
+}
+
+static void
+mtype_destroy(struct ip_set *set)
+{
+ struct mtype *map = set->data;
+
+ if (SET_WITH_TIMEOUT(set))
+ del_timer_sync(&map->gc);
+
+ ip_set_free(map->members);
+ if (map->dsize)
+ ip_set_free(map->extensions);
+ kfree(map);
+
+ set->data = NULL;
+}
+
+static void
+mtype_flush(struct ip_set *set)
+{
+ struct mtype *map = set->data;
+
+ memset(map->members, 0, map->memsize);
+}
+
+static int
+mtype_head(struct ip_set *set, struct sk_buff *skb)
+{
+ const struct mtype *map = set->data;
+ struct nlattr *nested;
+
+ nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+ goto nla_put_failure;
+ if (mtype_do_head(skb, map) ||
+ nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
+ htonl(sizeof(*map) +
+ map->memsize +
+ map->dsize * map->elements)) ||
+ (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
+ (SET_WITH_COUNTER(set) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))))
+ goto nla_put_failure;
+ ipset_nest_end(skb, nested);
+
+ return 0;
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+static int
+mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct mtype *map = set->data;
+ const struct mtype_adt_elem *e = value;
+ void *x = get_ext(map, e->id);
+ int ret = mtype_do_test(e, map);
+
+ if (ret <= 0)
+ return ret;
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(x, map)))
+ return 0;
+ if (SET_WITH_COUNTER(set))
+ ip_set_update_counter(ext_counter(x, map), ext, mext, flags);
+ return 1;
+}
+
+static int
+mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct mtype *map = set->data;
+ const struct mtype_adt_elem *e = value;
+ void *x = get_ext(map, e->id);
+ int ret = mtype_do_add(e, map, flags);
+
+ if (ret == IPSET_ADD_FAILED) {
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(x, map)))
+ ret = 0;
+ else if (!(flags & IPSET_FLAG_EXIST))
+ return -IPSET_ERR_EXIST;
+ }
+
+ if (SET_WITH_TIMEOUT(set))
+#ifdef IP_SET_BITMAP_STORED_TIMEOUT
+ mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret);
+#else
+ ip_set_timeout_set(ext_timeout(x, map), ext->timeout);
+#endif
+
+ if (SET_WITH_COUNTER(set))
+ ip_set_init_counter(ext_counter(x, map), ext);
+ return 0;
+}
+
+static int
+mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct mtype *map = set->data;
+ const struct mtype_adt_elem *e = value;
+ const void *x = get_ext(map, e->id);
+
+ if (mtype_do_del(e, map) ||
+ (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(x, map))))
+ return -IPSET_ERR_EXIST;
+
+ return 0;
+}
+
+static int
+mtype_list(const struct ip_set *set,
+ struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct mtype *map = set->data;
+ struct nlattr *adt, *nested;
+ void *x;
+ u32 id, first = cb->args[2];
+
+ adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
+ if (!adt)
+ return -EMSGSIZE;
+ for (; cb->args[2] < map->elements; cb->args[2]++) {
+ id = cb->args[2];
+ x = get_ext(map, id);
+ if (!test_bit(id, map->members) ||
+ (SET_WITH_TIMEOUT(set) &&
+#ifdef IP_SET_BITMAP_STORED_TIMEOUT
+ mtype_is_filled((const struct mtype_elem *) x) &&
+#endif
+ ip_set_timeout_expired(ext_timeout(x, map))))
+ continue;
+ nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested) {
+ if (id == first) {
+ nla_nest_cancel(skb, adt);
+ return -EMSGSIZE;
+ } else
+ goto nla_put_failure;
+ }
+ if (mtype_do_list(skb, map, id))
+ goto nla_put_failure;
+ if (SET_WITH_TIMEOUT(set)) {
+#ifdef IP_SET_BITMAP_STORED_TIMEOUT
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_stored(map, id,
+ ext_timeout(x, map)))))
+ goto nla_put_failure;
+#else
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(x, map)))))
+ goto nla_put_failure;
+#endif
+ }
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(x, map)))
+ goto nla_put_failure;
+ ipset_nest_end(skb, nested);
+ }
+ ipset_nest_end(skb, adt);
+
+ /* Set listing finished */
+ cb->args[2] = 0;
+
+ return 0;
+
+nla_put_failure:
+ nla_nest_cancel(skb, nested);
+ ipset_nest_end(skb, adt);
+ if (unlikely(id == first)) {
+ cb->args[2] = 0;
+ return -EMSGSIZE;
+ }
+ return 0;
+}
+
+static void
+mtype_gc(unsigned long ul_set)
+{
+ struct ip_set *set = (struct ip_set *) ul_set;
+ struct mtype *map = set->data;
+ const void *x;
+ u32 id;
+
+ /* We run parallel with other readers (test element)
+ * but adding/deleting new entries is locked out */
+ read_lock_bh(&set->lock);
+ for (id = 0; id < map->elements; id++)
+ if (mtype_gc_test(id, map)) {
+ x = get_ext(map, id);
+ if (ip_set_timeout_expired(ext_timeout(x, map)))
+ clear_bit(id, map->members);
+ }
+ read_unlock_bh(&set->lock);
+
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
+ add_timer(&map->gc);
+}
+
+static const struct ip_set_type_variant mtype = {
+ .kadt = mtype_kadt,
+ .uadt = mtype_uadt,
+ .adt = {
+ [IPSET_ADD] = mtype_add,
+ [IPSET_DEL] = mtype_del,
+ [IPSET_TEST] = mtype_test,
+ },
+ .destroy = mtype_destroy,
+ .flush = mtype_flush,
+ .head = mtype_head,
+ .list = mtype_list,
+ .same_set = mtype_same_set,
+};
+
+#endif /* __IP_SET_BITMAP_IP_GEN_H */
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index 4a92fd47bd4c..f1a8128bef01 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -1,6 +1,6 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -24,31 +24,37 @@
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h>
-#define IP_SET_BITMAP_TIMEOUT
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#define REVISION_MIN 0
-#define REVISION_MAX 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip");
+#define MTYPE bitmap_ip
+
/* Type structure */
struct bitmap_ip {
void *members; /* the set members */
+ void *extensions; /* data extensions */
u32 first_ip; /* host byte order, included in range */
u32 last_ip; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
u32 hosts; /* number of hosts in a subnet */
size_t memsize; /* members size */
+ size_t dsize; /* extensions struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
u8 netmask; /* subnet netmask */
u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
};
-/* Base variant */
+/* ADT structure for generic function args */
+struct bitmap_ip_adt_elem {
+ u16 id;
+};
static inline u32
ip_to_id(const struct bitmap_ip *m, u32 ip)
@@ -56,188 +62,67 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)
return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
}
-static int
-bitmap_ip_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- const struct bitmap_ip *map = set->data;
- u16 id = *(u16 *)value;
-
- return !!test_bit(id, map->members);
-}
+/* Common functions */
-static int
-bitmap_ip_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
{
- struct bitmap_ip *map = set->data;
- u16 id = *(u16 *)value;
-
- if (test_and_set_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- return 0;
+ return !!test_bit(e->id, map->members);
}
-static int
-bitmap_ip_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map)
{
- struct bitmap_ip *map = set->data;
- u16 id = *(u16 *)value;
-
- if (!test_and_clear_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- return 0;
-}
-
-static int
-bitmap_ip_list(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
-{
- const struct bitmap_ip *map = set->data;
- struct nlattr *atd, *nested;
- u32 id, first = cb->args[2];
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- for (; cb->args[2] < map->elements; cb->args[2]++) {
- id = cb->args[2];
- if (!test_bit(id, map->members))
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts)))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
- return 0;
-
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, atd);
- if (unlikely(id == first)) {
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
+ return !!test_bit(id, map->members);
}
-/* Timeout variant */
-
-static int
-bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map,
+ u32 flags)
{
- const struct bitmap_ip *map = set->data;
- const unsigned long *members = map->members;
- u16 id = *(u16 *)value;
-
- return ip_set_timeout_test(members[id]);
+ return !!test_and_set_bit(e->id, map->members);
}
-static int
-bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ip_do_del(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
{
- struct bitmap_ip *map = set->data;
- unsigned long *members = map->members;
- u16 id = *(u16 *)value;
-
- if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
- return -IPSET_ERR_EXIST;
-
- members[id] = ip_set_timeout_set(timeout);
-
- return 0;
+ return !test_and_clear_bit(e->id, map->members);
}
-static int
-bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id)
{
- struct bitmap_ip *map = set->data;
- unsigned long *members = map->members;
- u16 id = *(u16 *)value;
- int ret = -IPSET_ERR_EXIST;
-
- if (ip_set_timeout_test(members[id]))
- ret = 0;
-
- members[id] = IPSET_ELEM_UNSET;
- return ret;
+ return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id * map->hosts));
}
-static int
-bitmap_ip_tlist(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
+static inline int
+bitmap_ip_do_head(struct sk_buff *skb, const struct bitmap_ip *map)
{
- const struct bitmap_ip *map = set->data;
- struct nlattr *adt, *nested;
- u32 id, first = cb->args[2];
- const unsigned long *members = map->members;
-
- adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!adt)
- return -EMSGSIZE;
- for (; cb->args[2] < map->elements; cb->args[2]++) {
- id = cb->args[2];
- if (!ip_set_timeout_test(members[id]))
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, adt);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id * map->hosts)) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(members[id]))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, adt);
-
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
-
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, adt);
- if (unlikely(id == first)) {
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
+ return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)) ||
+ (map->netmask != 32 &&
+ nla_put_u8(skb, IPSET_ATTR_NETMASK, map->netmask));
}
static int
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
+ struct bitmap_ip_adt_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
u32 ip;
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
- ip = ip_to_id(map, ip);
+ e.id = ip_to_id(map, ip);
- return adtfn(set, &ip, opt_timeout(opt, map), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
@@ -246,33 +131,31 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
{
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- u32 timeout = map->timeout;
- u32 ip, ip_to, id;
+ u32 ip, ip_to;
+ struct bitmap_ip_adt_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(map->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
if (adt == IPSET_TEST) {
- id = ip_to_id(map, ip);
- return adtfn(set, &id, timeout, flags);
+ e.id = ip_to_id(map, ip);
+ return adtfn(set, &e, &ext, &ext, flags);
}
if (tb[IPSET_ATTR_IP_TO]) {
@@ -297,8 +180,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE;
for (; !before(ip_to, ip); ip += map->hosts) {
- id = ip_to_id(map, ip);
- ret = adtfn(set, &id, timeout, flags);
+ e.id = ip_to_id(map, ip);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -308,54 +191,6 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static void
-bitmap_ip_destroy(struct ip_set *set)
-{
- struct bitmap_ip *map = set->data;
-
- if (with_timeout(map->timeout))
- del_timer_sync(&map->gc);
-
- ip_set_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void
-bitmap_ip_flush(struct ip_set *set)
-{
- struct bitmap_ip *map = set->data;
-
- memset(map->members, 0, map->memsize);
-}
-
-static int
-bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
-{
- const struct bitmap_ip *map = set->data;
- struct nlattr *nested;
-
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested)
- goto nla_put_failure;
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)) ||
- (map->netmask != 32 &&
- nla_put_u8(skb, IPSET_ATTR_NETMASK, map->netmask)) ||
- nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize)) ||
- (with_timeout(map->timeout) &&
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
-
- return 0;
-nla_put_failure:
- return -EMSGSIZE;
-}
-
static bool
bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
{
@@ -365,70 +200,35 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
x->netmask == y->netmask &&
- x->timeout == y->timeout;
+ x->timeout == y->timeout &&
+ a->extensions == b->extensions;
}
-static const struct ip_set_type_variant bitmap_ip = {
- .kadt = bitmap_ip_kadt,
- .uadt = bitmap_ip_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_ip_add,
- [IPSET_DEL] = bitmap_ip_del,
- [IPSET_TEST] = bitmap_ip_test,
- },
- .destroy = bitmap_ip_destroy,
- .flush = bitmap_ip_flush,
- .head = bitmap_ip_head,
- .list = bitmap_ip_list,
- .same_set = bitmap_ip_same_set,
+/* Plain variant */
+
+struct bitmap_ip_elem {
};
-static const struct ip_set_type_variant bitmap_tip = {
- .kadt = bitmap_ip_kadt,
- .uadt = bitmap_ip_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_ip_tadd,
- [IPSET_DEL] = bitmap_ip_tdel,
- [IPSET_TEST] = bitmap_ip_ttest,
- },
- .destroy = bitmap_ip_destroy,
- .flush = bitmap_ip_flush,
- .head = bitmap_ip_head,
- .list = bitmap_ip_tlist,
- .same_set = bitmap_ip_same_set,
+/* Timeout variant */
+
+struct bitmap_ipt_elem {
+ unsigned long timeout;
};
-static void
-bitmap_ip_gc(unsigned long ul_set)
-{
- struct ip_set *set = (struct ip_set *) ul_set;
- struct bitmap_ip *map = set->data;
- unsigned long *table = map->members;
- u32 id;
-
- /* We run parallel with other readers (test element)
- * but adding/deleting new entries is locked out */
- read_lock_bh(&set->lock);
- for (id = 0; id < map->elements; id++)
- if (ip_set_timeout_expired(table[id]))
- table[id] = IPSET_ELEM_UNSET;
- read_unlock_bh(&set->lock);
-
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+/* Plain variant with counter */
-static void
-bitmap_ip_gc_init(struct ip_set *set)
-{
- struct bitmap_ip *map = set->data;
+struct bitmap_ipc_elem {
+ struct ip_set_counter counter;
+};
- init_timer(&map->gc);
- map->gc.data = (unsigned long) set;
- map->gc.function = bitmap_ip_gc;
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+/* Timeout variant with counter */
+
+struct bitmap_ipct_elem {
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
+#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip type of sets */
@@ -440,6 +240,13 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * elements);
+ if (!map->extensions) {
+ kfree(map->members);
+ return false;
+ }
+ }
map->first_ip = first_ip;
map->last_ip = last_ip;
map->elements = elements;
@@ -457,13 +264,14 @@ static int
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
struct bitmap_ip *map;
- u32 first_ip, last_ip, hosts;
+ u32 first_ip, last_ip, hosts, cadt_flags = 0;
u64 elements;
u8 netmask = 32;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
@@ -526,8 +334,45 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (!map)
return -ENOMEM;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- map->memsize = elements * sizeof(unsigned long);
+ map->memsize = bitmap_bytes(0, elements - 1);
+ set->variant = &bitmap_ip;
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipct_elem, counter);
+
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout = ip_set_timeout_uget(
+ tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+
+ bitmap_ip_gc_init(set, bitmap_ip_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_ipc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipc_elem, counter);
+
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipt_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipt_elem, timeout);
if (!init_map_ip(set, map, first_ip, last_ip,
elements, hosts, netmask)) {
@@ -536,19 +381,16 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
}
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- set->variant = &bitmap_tip;
+ set->extensions |= IPSET_EXT_TIMEOUT;
- bitmap_ip_gc_init(set);
+ bitmap_ip_gc_init(set, bitmap_ip_gc);
} else {
- map->memsize = bitmap_bytes(0, elements - 1);
-
+ map->dsize = 0;
if (!init_map_ip(set, map, first_ip, last_ip,
elements, hosts, netmask)) {
kfree(map);
return -ENOMEM;
}
-
- set->variant = &bitmap_ip;
}
return 0;
}
@@ -568,6 +410,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -575,6 +418,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 0f92dc24cb89..3b30e0bef890 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -1,7 +1,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -23,340 +23,208 @@
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h>
#define REVISION_MIN 0
-#define REVISION_MAX 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip,mac");
+#define MTYPE bitmap_ipmac
+#define IP_SET_BITMAP_STORED_TIMEOUT
+
enum {
- MAC_EMPTY, /* element is not set */
- MAC_FILLED, /* element is set with MAC */
MAC_UNSET, /* element is set, without MAC */
+ MAC_FILLED, /* element is set with MAC */
};
/* Type structure */
struct bitmap_ipmac {
void *members; /* the set members */
+ void *extensions; /* MAC + data extensions */
u32 first_ip; /* host byte order, included in range */
u32 last_ip; /* host byte order, included in range */
+ u32 elements; /* number of max elements in the set */
u32 timeout; /* timeout value */
struct timer_list gc; /* garbage collector */
+ size_t memsize; /* members size */
size_t dsize; /* size of element */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
};
/* ADT structure for generic function args */
-struct ipmac {
- u32 id; /* id in array */
- unsigned char *ether; /* ethernet address */
+struct bitmap_ipmac_adt_elem {
+ u16 id;
+ unsigned char *ether;
};
-/* Member element without and with timeout */
-
-struct ipmac_elem {
+struct bitmap_ipmac_elem {
unsigned char ether[ETH_ALEN];
- unsigned char match;
+ unsigned char filled;
} __attribute__ ((aligned));
-struct ipmac_telem {
- unsigned char ether[ETH_ALEN];
- unsigned char match;
- unsigned long timeout;
-} __attribute__ ((aligned));
-
-static inline void *
-bitmap_ipmac_elem(const struct bitmap_ipmac *map, u32 id)
+static inline u32
+ip_to_id(const struct bitmap_ipmac *m, u32 ip)
{
- return (void *)((char *)map->members + id * map->dsize);
+ return ip - m->first_ip;
}
-static inline bool
-bitmap_timeout(const struct bitmap_ipmac *map, u32 id)
+static inline struct bitmap_ipmac_elem *
+get_elem(void *extensions, u16 id, size_t dsize)
{
- const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
-
- return ip_set_timeout_test(elem->timeout);
+ return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
}
-static inline bool
-bitmap_expired(const struct bitmap_ipmac *map, u32 id)
-{
- const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
-
- return ip_set_timeout_expired(elem->timeout);
-}
+/* Common functions */
static inline int
-bitmap_ipmac_exist(const struct ipmac_telem *elem)
+bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
+ const struct bitmap_ipmac *map)
{
- return elem->match == MAC_UNSET ||
- (elem->match == MAC_FILLED &&
- !ip_set_timeout_expired(elem->timeout));
-}
+ const struct bitmap_ipmac_elem *elem;
-/* Base variant */
-
-static int
-bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- const struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
-
- switch (elem->match) {
- case MAC_UNSET:
- /* Trigger kernel to fill out the ethernet address */
- return -EAGAIN;
- case MAC_FILLED:
- return data->ether == NULL ||
- ether_addr_equal(data->ether, elem->ether);
- }
- return 0;
-}
-
-static int
-bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
-
- switch (elem->match) {
- case MAC_UNSET:
- if (!data->ether)
- /* Already added without ethernet address */
- return -IPSET_ERR_EXIST;
- /* Fill the MAC address */
- memcpy(elem->ether, data->ether, ETH_ALEN);
- elem->match = MAC_FILLED;
- break;
- case MAC_FILLED:
- return -IPSET_ERR_EXIST;
- case MAC_EMPTY:
- if (data->ether) {
- memcpy(elem->ether, data->ether, ETH_ALEN);
- elem->match = MAC_FILLED;
- } else
- elem->match = MAC_UNSET;
- }
-
- return 0;
-}
-
-static int
-bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
-
- if (elem->match == MAC_EMPTY)
- return -IPSET_ERR_EXIST;
-
- elem->match = MAC_EMPTY;
-
- return 0;
+ if (!test_bit(e->id, map->members))
+ return 0;
+ elem = get_elem(map->extensions, e->id, map->dsize);
+ if (elem->filled == MAC_FILLED)
+ return e->ether == NULL ||
+ ether_addr_equal(e->ether, elem->ether);
+ /* Trigger kernel to fill out the ethernet address */
+ return -EAGAIN;
}
-static int
-bitmap_ipmac_list(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
+static inline int
+bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map)
{
- const struct bitmap_ipmac *map = set->data;
- const struct ipmac_elem *elem;
- struct nlattr *atd, *nested;
- u32 id, first = cb->args[2];
- u32 last = map->last_ip - map->first_ip;
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- for (; cb->args[2] <= last; cb->args[2]++) {
- id = cb->args[2];
- elem = bitmap_ipmac_elem(map, id);
- if (elem->match == MAC_EMPTY)
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id)) ||
- (elem->match == MAC_FILLED &&
- nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN,
- elem->ether)))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
+ const struct bitmap_ipmac_elem *elem;
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, atd);
- if (unlikely(id == first)) {
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
+ if (!test_bit(id, map->members))
+ return 0;
+ elem = get_elem(map->extensions, id, map->dsize);
+ /* Timer not started for the incomplete elements */
+ return elem->filled == MAC_FILLED;
}
-/* Timeout variant */
-
-static int
-bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
{
- const struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
-
- switch (elem->match) {
- case MAC_UNSET:
- /* Trigger kernel to fill out the ethernet address */
- return -EAGAIN;
- case MAC_FILLED:
- return (data->ether == NULL ||
- ether_addr_equal(data->ether, elem->ether)) &&
- !bitmap_expired(map, data->id);
- }
- return 0;
+ return elem->filled == MAC_FILLED;
}
-static int
-bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ipmac_add_timeout(unsigned long *timeout,
+ const struct bitmap_ipmac_adt_elem *e,
+ const struct ip_set_ext *ext,
+ struct bitmap_ipmac *map, int mode)
{
- struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
- bool flag_exist = flags & IPSET_FLAG_EXIST;
+ u32 t = ext->timeout;
- switch (elem->match) {
- case MAC_UNSET:
- if (!(data->ether || flag_exist))
- /* Already added without ethernet address */
- return -IPSET_ERR_EXIST;
- /* Fill the MAC address and activate the timer */
- memcpy(elem->ether, data->ether, ETH_ALEN);
- elem->match = MAC_FILLED;
- if (timeout == map->timeout)
+ if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
+ if (t == map->timeout)
/* Timeout was not specified, get stored one */
- timeout = elem->timeout;
- elem->timeout = ip_set_timeout_set(timeout);
- break;
- case MAC_FILLED:
- if (!(bitmap_expired(map, data->id) || flag_exist))
- return -IPSET_ERR_EXIST;
- /* Fall through */
- case MAC_EMPTY:
- if (data->ether) {
- memcpy(elem->ether, data->ether, ETH_ALEN);
- elem->match = MAC_FILLED;
- } else
- elem->match = MAC_UNSET;
+ t = *timeout;
+ ip_set_timeout_set(timeout, t);
+ } else {
/* If MAC is unset yet, we store plain timeout value
* because the timer is not activated yet
* and we can reuse it later when MAC is filled out,
* possibly by the kernel */
- elem->timeout = data->ether ? ip_set_timeout_set(timeout)
- : timeout;
- break;
+ if (e->ether)
+ ip_set_timeout_set(timeout, t);
+ else
+ *timeout = t;
}
-
return 0;
}
-static int
-bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
+ struct bitmap_ipmac *map, u32 flags)
{
- struct bitmap_ipmac *map = set->data;
- const struct ipmac *data = value;
- struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
+ struct bitmap_ipmac_elem *elem;
+
+ elem = get_elem(map->extensions, e->id, map->dsize);
+ if (test_and_set_bit(e->id, map->members)) {
+ if (elem->filled == MAC_FILLED) {
+ if (e->ether && (flags & IPSET_FLAG_EXIST))
+ memcpy(elem->ether, e->ether, ETH_ALEN);
+ return IPSET_ADD_FAILED;
+ } else if (!e->ether)
+ /* Already added without ethernet address */
+ return IPSET_ADD_FAILED;
+ /* Fill the MAC address and trigger the timer activation */
+ memcpy(elem->ether, e->ether, ETH_ALEN);
+ elem->filled = MAC_FILLED;
+ return IPSET_ADD_START_STORED_TIMEOUT;
+ } else if (e->ether) {
+ /* We can store MAC too */
+ memcpy(elem->ether, e->ether, ETH_ALEN);
+ elem->filled = MAC_FILLED;
+ return 0;
+ } else {
+ elem->filled = MAC_UNSET;
+ /* MAC is not stored yet, don't start timer */
+ return IPSET_ADD_STORE_PLAIN_TIMEOUT;
+ }
+}
- if (elem->match == MAC_EMPTY || bitmap_expired(map, data->id))
- return -IPSET_ERR_EXIST;
+static inline int
+bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
+ struct bitmap_ipmac *map)
+{
+ return !test_and_clear_bit(e->id, map->members);
+}
- elem->match = MAC_EMPTY;
+static inline unsigned long
+ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout)
+{
+ const struct bitmap_ipmac_elem *elem =
+ get_elem(map->extensions, id, map->dsize);
- return 0;
+ return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) :
+ *timeout;
}
-static int
-bitmap_ipmac_tlist(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
+static inline int
+bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
+ u32 id)
{
- const struct bitmap_ipmac *map = set->data;
- const struct ipmac_telem *elem;
- struct nlattr *atd, *nested;
- u32 id, first = cb->args[2];
- u32 timeout, last = map->last_ip - map->first_ip;
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- for (; cb->args[2] <= last; cb->args[2]++) {
- id = cb->args[2];
- elem = bitmap_ipmac_elem(map, id);
- if (!bitmap_ipmac_exist(elem))
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP,
- htonl(map->first_ip + id)) ||
- (elem->match == MAC_FILLED &&
- nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN,
- elem->ether)))
- goto nla_put_failure;
- timeout = elem->match == MAC_UNSET ? elem->timeout
- : ip_set_timeout_get(elem->timeout);
- if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout)))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
+ const struct bitmap_ipmac_elem *elem =
+ get_elem(map->extensions, id, map->dsize);
- return 0;
+ return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
+ htonl(map->first_ip + id)) ||
+ (elem->filled == MAC_FILLED &&
+ nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether));
+}
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, atd);
- return -EMSGSIZE;
+static inline int
+bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map)
+{
+ return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
+ nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
}
static int
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct ipmac data;
+ struct bitmap_ipmac_adt_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
+ u32 ip;
/* MAC can be src only */
if (!(opt->flags & IPSET_DIM_TWO_SRC))
return 0;
- data.id = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
- if (data.id < map->first_ip || data.id > map->last_ip)
+ ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
+ if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
/* Backward compatibility: we don't check the second flag */
@@ -364,10 +232,10 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
(skb_mac_header(skb) + ETH_HLEN) > skb->data)
return -EINVAL;
- data.id -= map->first_ip;
- data.ether = eth_hdr(skb)->h_source;
+ e.id = ip_to_id(map, ip);
+ e.ether = eth_hdr(skb)->h_source;
- return adtfn(set, &data, opt_timeout(opt, map), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
@@ -376,91 +244,39 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
{
const struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct ipmac data;
- u32 timeout = map->timeout;
+ struct bitmap_ipmac_adt_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
+ u32 ip;
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &data.id);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- if (data.id < map->first_ip || data.id > map->last_ip)
+ if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
+ e.id = ip_to_id(map, ip);
if (tb[IPSET_ATTR_ETHER])
- data.ether = nla_data(tb[IPSET_ATTR_ETHER]);
+ e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
else
- data.ether = NULL;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(map->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ e.ether = NULL;
- data.id -= map->first_ip;
-
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
-static void
-bitmap_ipmac_destroy(struct ip_set *set)
-{
- struct bitmap_ipmac *map = set->data;
-
- if (with_timeout(map->timeout))
- del_timer_sync(&map->gc);
-
- ip_set_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void
-bitmap_ipmac_flush(struct ip_set *set)
-{
- struct bitmap_ipmac *map = set->data;
-
- memset(map->members, 0,
- (map->last_ip - map->first_ip + 1) * map->dsize);
-}
-
-static int
-bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
-{
- const struct bitmap_ipmac *map = set->data;
- struct nlattr *nested;
-
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested)
- goto nla_put_failure;
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)) ||
- nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) +
- ((map->last_ip - map->first_ip + 1) *
- map->dsize))) ||
- (with_timeout(map->timeout) &&
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
-
- return 0;
-nla_put_failure:
- return -EMSGSIZE;
-}
-
static bool
bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
{
@@ -469,85 +285,64 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
- x->timeout == y->timeout;
+ x->timeout == y->timeout &&
+ a->extensions == b->extensions;
}
-static const struct ip_set_type_variant bitmap_ipmac = {
- .kadt = bitmap_ipmac_kadt,
- .uadt = bitmap_ipmac_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_ipmac_add,
- [IPSET_DEL] = bitmap_ipmac_del,
- [IPSET_TEST] = bitmap_ipmac_test,
- },
- .destroy = bitmap_ipmac_destroy,
- .flush = bitmap_ipmac_flush,
- .head = bitmap_ipmac_head,
- .list = bitmap_ipmac_list,
- .same_set = bitmap_ipmac_same_set,
-};
+/* Plain variant */
-static const struct ip_set_type_variant bitmap_tipmac = {
- .kadt = bitmap_ipmac_kadt,
- .uadt = bitmap_ipmac_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_ipmac_tadd,
- [IPSET_DEL] = bitmap_ipmac_tdel,
- [IPSET_TEST] = bitmap_ipmac_ttest,
- },
- .destroy = bitmap_ipmac_destroy,
- .flush = bitmap_ipmac_flush,
- .head = bitmap_ipmac_head,
- .list = bitmap_ipmac_tlist,
- .same_set = bitmap_ipmac_same_set,
+/* Timeout variant */
+
+struct bitmap_ipmact_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
};
-static void
-bitmap_ipmac_gc(unsigned long ul_set)
-{
- struct ip_set *set = (struct ip_set *) ul_set;
- struct bitmap_ipmac *map = set->data;
- struct ipmac_telem *elem;
- u32 id, last = map->last_ip - map->first_ip;
-
- /* We run parallel with other readers (test element)
- * but adding/deleting new entries is locked out */
- read_lock_bh(&set->lock);
- for (id = 0; id <= last; id++) {
- elem = bitmap_ipmac_elem(map, id);
- if (elem->match == MAC_FILLED &&
- ip_set_timeout_expired(elem->timeout))
- elem->match = MAC_EMPTY;
- }
- read_unlock_bh(&set->lock);
+/* Plain variant with counter */
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+struct bitmap_ipmacc_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
+};
-static void
-bitmap_ipmac_gc_init(struct ip_set *set)
-{
- struct bitmap_ipmac *map = set->data;
+/* Timeout variant with counter */
- init_timer(&map->gc);
- map->gc.data = (unsigned long) set;
- map->gc.function = bitmap_ipmac_gc;
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+struct bitmap_ipmacct_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
+#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip,mac type of sets */
static bool
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
- u32 first_ip, u32 last_ip)
+ u32 first_ip, u32 last_ip, u32 elements)
{
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
if (!map->members)
return false;
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * elements);
+ if (!map->extensions) {
+ kfree(map->members);
+ return false;
+ }
+ }
map->first_ip = first_ip;
map->last_ip = last_ip;
+ map->elements = elements;
map->timeout = IPSET_NO_TIMEOUT;
set->data = map;
@@ -560,13 +355,14 @@ static int
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
u32 flags)
{
- u32 first_ip, last_ip;
+ u32 first_ip, last_ip, cadt_flags = 0;
u64 elements;
struct bitmap_ipmac *map;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
@@ -601,28 +397,59 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
if (!map)
return -ENOMEM;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- map->dsize = sizeof(struct ipmac_telem);
+ map->memsize = bitmap_bytes(0, elements - 1);
+ set->variant = &bitmap_ipmac;
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipmacct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipmacct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipmacct_elem, counter);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip,
+ elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ map->timeout = ip_set_timeout_uget(
+ tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_ipmacc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipmacc_elem, counter);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip,
+ elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipmact_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipmact_elem, timeout);
- if (!init_map_ipmac(set, map, first_ip, last_ip)) {
+ if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
kfree(map);
return -ENOMEM;
}
-
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = &bitmap_tipmac;
-
- bitmap_ipmac_gc_init(set);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
} else {
- map->dsize = sizeof(struct ipmac_elem);
+ map->dsize = sizeof(struct bitmap_ipmac_elem);
- if (!init_map_ipmac(set, map, first_ip, last_ip)) {
+ if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
kfree(map);
return -ENOMEM;
}
set->variant = &bitmap_ipmac;
-
}
return 0;
}
@@ -641,6 +468,7 @@ static struct ip_set_type bitmap_ipmac_type = {
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -648,6 +476,8 @@ static struct ip_set_type bitmap_ipmac_type = {
.len = ETH_ALEN },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index e6b2db76f4c3..8207d1fda528 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -19,205 +19,94 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
-#define IP_SET_BITMAP_TIMEOUT
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#define REVISION_MIN 0
-#define REVISION_MAX 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:port");
+#define MTYPE bitmap_port
+
/* Type structure */
struct bitmap_port {
void *members; /* the set members */
+ void *extensions; /* data extensions */
u16 first_port; /* host byte order, included in range */
u16 last_port; /* host byte order, included in range */
+ u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */
+ size_t dsize; /* extensions struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
};
-/* Base variant */
+/* ADT structure for generic function args */
+struct bitmap_port_adt_elem {
+ u16 id;
+};
-static int
-bitmap_port_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline u16
+port_to_id(const struct bitmap_port *m, u16 port)
{
- const struct bitmap_port *map = set->data;
- u16 id = *(u16 *)value;
-
- return !!test_bit(id, map->members);
+ return port - m->first_port;
}
-static int
-bitmap_port_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
-{
- struct bitmap_port *map = set->data;
- u16 id = *(u16 *)value;
-
- if (test_and_set_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- return 0;
-}
+/* Common functions */
-static int
-bitmap_port_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_port_do_test(const struct bitmap_port_adt_elem *e,
+ const struct bitmap_port *map)
{
- struct bitmap_port *map = set->data;
- u16 id = *(u16 *)value;
-
- if (!test_and_clear_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- return 0;
+ return !!test_bit(e->id, map->members);
}
-static int
-bitmap_port_list(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
+static inline int
+bitmap_port_gc_test(u16 id, const struct bitmap_port *map)
{
- const struct bitmap_port *map = set->data;
- struct nlattr *atd, *nested;
- u16 id, first = cb->args[2];
- u16 last = map->last_port - map->first_port;
-
- atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!atd)
- return -EMSGSIZE;
- for (; cb->args[2] <= last; cb->args[2]++) {
- id = cb->args[2];
- if (!test_bit(id, map->members))
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, atd);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_net16(skb, IPSET_ATTR_PORT,
- htons(map->first_port + id)))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, atd);
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
-
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, atd);
- if (unlikely(id == first)) {
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
+ return !!test_bit(id, map->members);
}
-/* Timeout variant */
-
-static int
-bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
+ struct bitmap_port *map, u32 flags)
{
- const struct bitmap_port *map = set->data;
- const unsigned long *members = map->members;
- u16 id = *(u16 *)value;
-
- return ip_set_timeout_test(members[id]);
+ return !!test_and_set_bit(e->id, map->members);
}
-static int
-bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_port_do_del(const struct bitmap_port_adt_elem *e,
+ struct bitmap_port *map)
{
- struct bitmap_port *map = set->data;
- unsigned long *members = map->members;
- u16 id = *(u16 *)value;
-
- if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
- return -IPSET_ERR_EXIST;
-
- members[id] = ip_set_timeout_set(timeout);
-
- return 0;
+ return !test_and_clear_bit(e->id, map->members);
}
-static int
-bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
+static inline int
+bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id)
{
- struct bitmap_port *map = set->data;
- unsigned long *members = map->members;
- u16 id = *(u16 *)value;
- int ret = -IPSET_ERR_EXIST;
-
- if (ip_set_timeout_test(members[id]))
- ret = 0;
-
- members[id] = IPSET_ELEM_UNSET;
- return ret;
+ return nla_put_net16(skb, IPSET_ATTR_PORT,
+ htons(map->first_port + id));
}
-static int
-bitmap_port_tlist(const struct ip_set *set,
- struct sk_buff *skb, struct netlink_callback *cb)
+static inline int
+bitmap_port_do_head(struct sk_buff *skb, const struct bitmap_port *map)
{
- const struct bitmap_port *map = set->data;
- struct nlattr *adt, *nested;
- u16 id, first = cb->args[2];
- u16 last = map->last_port - map->first_port;
- const unsigned long *members = map->members;
-
- adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
- if (!adt)
- return -EMSGSIZE;
- for (; cb->args[2] <= last; cb->args[2]++) {
- id = cb->args[2];
- if (!ip_set_timeout_test(members[id]))
- continue;
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested) {
- if (id == first) {
- nla_nest_cancel(skb, adt);
- return -EMSGSIZE;
- } else
- goto nla_put_failure;
- }
- if (nla_put_net16(skb, IPSET_ATTR_PORT,
- htons(map->first_port + id)) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(members[id]))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
- }
- ipset_nest_end(skb, adt);
-
- /* Set listing finished */
- cb->args[2] = 0;
-
- return 0;
-
-nla_put_failure:
- nla_nest_cancel(skb, nested);
- ipset_nest_end(skb, adt);
- if (unlikely(id == first)) {
- cb->args[2] = 0;
- return -EMSGSIZE;
- }
- return 0;
+ return nla_put_net16(skb, IPSET_ATTR_PORT, htons(map->first_port)) ||
+ nla_put_net16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
}
static int
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
+ struct bitmap_port_adt_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
__be16 __port;
u16 port = 0;
@@ -230,9 +119,9 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE;
- port -= map->first_port;
+ e.id = port_to_id(map, port);
- return adtfn(set, &port, opt_timeout(opt, map), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
@@ -241,14 +130,17 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
{
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- u32 timeout = map->timeout;
+ struct bitmap_port_adt_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
u32 port; /* wraparound */
- u16 id, port_to;
+ u16 port_to;
int ret = 0;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
@@ -257,16 +149,13 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(map->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
if (adt == IPSET_TEST) {
- id = port - map->first_port;
- return adtfn(set, &id, timeout, flags);
+ e.id = port_to_id(map, port);
+ return adtfn(set, &e, &ext, &ext, flags);
}
if (tb[IPSET_ATTR_PORT_TO]) {
@@ -283,8 +172,8 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE;
for (; port <= port_to; port++) {
- id = port - map->first_port;
- ret = adtfn(set, &id, timeout, flags);
+ e.id = port_to_id(map, port);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -294,52 +183,6 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static void
-bitmap_port_destroy(struct ip_set *set)
-{
- struct bitmap_port *map = set->data;
-
- if (with_timeout(map->timeout))
- del_timer_sync(&map->gc);
-
- ip_set_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void
-bitmap_port_flush(struct ip_set *set)
-{
- struct bitmap_port *map = set->data;
-
- memset(map->members, 0, map->memsize);
-}
-
-static int
-bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
-{
- const struct bitmap_port *map = set->data;
- struct nlattr *nested;
-
- nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
- if (!nested)
- goto nla_put_failure;
- if (nla_put_net16(skb, IPSET_ATTR_PORT, htons(map->first_port)) ||
- nla_put_net16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)) ||
- nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize)) ||
- (with_timeout(map->timeout) &&
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))))
- goto nla_put_failure;
- ipset_nest_end(skb, nested);
-
- return 0;
-nla_put_failure:
- return -EMSGSIZE;
-}
-
static bool
bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
{
@@ -348,71 +191,35 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_port == y->first_port &&
x->last_port == y->last_port &&
- x->timeout == y->timeout;
+ x->timeout == y->timeout &&
+ a->extensions == b->extensions;
}
-static const struct ip_set_type_variant bitmap_port = {
- .kadt = bitmap_port_kadt,
- .uadt = bitmap_port_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_port_add,
- [IPSET_DEL] = bitmap_port_del,
- [IPSET_TEST] = bitmap_port_test,
- },
- .destroy = bitmap_port_destroy,
- .flush = bitmap_port_flush,
- .head = bitmap_port_head,
- .list = bitmap_port_list,
- .same_set = bitmap_port_same_set,
+/* Plain variant */
+
+struct bitmap_port_elem {
};
-static const struct ip_set_type_variant bitmap_tport = {
- .kadt = bitmap_port_kadt,
- .uadt = bitmap_port_uadt,
- .adt = {
- [IPSET_ADD] = bitmap_port_tadd,
- [IPSET_DEL] = bitmap_port_tdel,
- [IPSET_TEST] = bitmap_port_ttest,
- },
- .destroy = bitmap_port_destroy,
- .flush = bitmap_port_flush,
- .head = bitmap_port_head,
- .list = bitmap_port_tlist,
- .same_set = bitmap_port_same_set,
+/* Timeout variant */
+
+struct bitmap_portt_elem {
+ unsigned long timeout;
};
-static void
-bitmap_port_gc(unsigned long ul_set)
-{
- struct ip_set *set = (struct ip_set *) ul_set;
- struct bitmap_port *map = set->data;
- unsigned long *table = map->members;
- u32 id; /* wraparound */
- u16 last = map->last_port - map->first_port;
-
- /* We run parallel with other readers (test element)
- * but adding/deleting new entries is locked out */
- read_lock_bh(&set->lock);
- for (id = 0; id <= last; id++)
- if (ip_set_timeout_expired(table[id]))
- table[id] = IPSET_ELEM_UNSET;
- read_unlock_bh(&set->lock);
-
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+/* Plain variant with counter */
-static void
-bitmap_port_gc_init(struct ip_set *set)
-{
- struct bitmap_port *map = set->data;
+struct bitmap_portc_elem {
+ struct ip_set_counter counter;
+};
- init_timer(&map->gc);
- map->gc.data = (unsigned long) set;
- map->gc.function = bitmap_port_gc;
- map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
- add_timer(&map->gc);
-}
+/* Timeout variant with counter */
+
+struct bitmap_portct_elem {
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
+#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip type of sets */
@@ -423,6 +230,13 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * map->elements);
+ if (!map->extensions) {
+ kfree(map->members);
+ return false;
+ }
+ }
map->first_port = first_port;
map->last_port = last_port;
map->timeout = IPSET_NO_TIMEOUT;
@@ -434,15 +248,16 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
}
static int
-bitmap_port_create(struct ip_set *set, struct nlattr *tb[],
- u32 flags)
+bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
struct bitmap_port *map;
u16 first_port, last_port;
+ u32 cadt_flags = 0;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
@@ -458,28 +273,56 @@ bitmap_port_create(struct ip_set *set, struct nlattr *tb[],
if (!map)
return -ENOMEM;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- map->memsize = (last_port - first_port + 1)
- * sizeof(unsigned long);
-
+ map->elements = last_port - first_port + 1;
+ map->memsize = map->elements * sizeof(unsigned long);
+ set->variant = &bitmap_port;
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_portct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_portct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_portct_elem, counter);
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout =
+ ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_port_gc_init(set, bitmap_port_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_portc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_portc_elem, counter);
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_portt_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_portt_elem, timeout);
if (!init_map_port(set, map, first_port, last_port)) {
kfree(map);
return -ENOMEM;
}
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- set->variant = &bitmap_tport;
-
- bitmap_port_gc_init(set);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_port_gc_init(set, bitmap_port_gc);
} else {
- map->memsize = bitmap_bytes(0, last_port - first_port);
- pr_debug("memsize: %zu\n", map->memsize);
+ map->dsize = 0;
if (!init_map_port(set, map, first_port, last_port)) {
kfree(map);
return -ENOMEM;
}
- set->variant = &bitmap_port;
}
return 0;
}
@@ -497,12 +340,15 @@ static struct ip_set_type bitmap_port_type = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 1ba9dbc0e107..f77139007983 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1,6 +1,6 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -15,7 +15,6 @@
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
-#include <linux/netlink.h>
#include <linux/rculist.h>
#include <net/netlink.h>
@@ -316,6 +315,29 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
}
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
+int
+ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
+ struct ip_set_ext *ext)
+{
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ if (!(set->extensions & IPSET_EXT_TIMEOUT))
+ return -IPSET_ERR_TIMEOUT;
+ ext->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ }
+ if (tb[IPSET_ATTR_BYTES] || tb[IPSET_ATTR_PACKETS]) {
+ if (!(set->extensions & IPSET_EXT_COUNTER))
+ return -IPSET_ERR_COUNTER;
+ if (tb[IPSET_ATTR_BYTES])
+ ext->bytes = be64_to_cpu(nla_get_be64(
+ tb[IPSET_ATTR_BYTES]));
+ if (tb[IPSET_ATTR_PACKETS])
+ ext->packets = be64_to_cpu(nla_get_be64(
+ tb[IPSET_ATTR_PACKETS]));
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ip_set_get_extensions);
+
/*
* Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace
@@ -366,8 +388,7 @@ ip_set_rcu_get(ip_set_id_t index)
int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
- const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt)
+ const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_rcu_get(index);
int ret = 0;
@@ -392,7 +413,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
ret = 1;
} else {
/* --return-nomatch: invert matched element */
- if ((opt->flags & IPSET_RETURN_NOMATCH) &&
+ if ((opt->cmdflags & IPSET_FLAG_RETURN_NOMATCH) &&
(set->type->features & IPSET_TYPE_NOMATCH) &&
(ret > 0 || ret == -ENOTEMPTY))
ret = -ret;
@@ -405,8 +426,7 @@ EXPORT_SYMBOL_GPL(ip_set_test);
int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
- const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt)
+ const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_rcu_get(index);
int ret;
@@ -428,8 +448,7 @@ EXPORT_SYMBOL_GPL(ip_set_add);
int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
- const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt)
+ const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_rcu_get(index);
int ret = 0;
@@ -1085,7 +1104,7 @@ static int
dump_init(struct netlink_callback *cb)
{
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
- int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *attr = (void *)nlh + min_len;
u32 dump_type;
@@ -1301,7 +1320,7 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
struct sk_buff *skb2;
struct nlmsgerr *errmsg;
size_t payload = sizeof(*errmsg) + nlmsg_len(nlh);
- int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *cmdattr;
u32 *errline;
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
new file mode 100644
index 000000000000..57beb1762b2d
--- /dev/null
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -0,0 +1,1100 @@
+/* Copyright (C) 2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ *
+ * 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 _IP_SET_HASH_GEN_H
+#define _IP_SET_HASH_GEN_H
+
+#include <linux/rcupdate.h>
+#include <linux/jhash.h>
+#include <linux/netfilter/ipset/ip_set_timeout.h>
+#ifndef rcu_dereference_bh
+#define rcu_dereference_bh(p) rcu_dereference(p)
+#endif
+
+#define CONCAT(a, b) a##b
+#define TOKEN(a, b) CONCAT(a, b)
+
+/* Hashing which uses arrays to resolve clashing. The hash table is resized
+ * (doubled) when searching becomes too long.
+ * Internally jhash is used with the assumption that the size of the
+ * stored data is a multiple of sizeof(u32). If storage supports timeout,
+ * the timeout field must be the last one in the data structure - that field
+ * is ignored when computing the hash key.
+ *
+ * Readers and resizing
+ *
+ * Resizing can be triggered by userspace command only, and those
+ * are serialized by the nfnl mutex. During resizing the set is
+ * read-locked, so the only possible concurrent operations are
+ * the kernel side readers. Those must be protected by proper RCU locking.
+ */
+
+/* Number of elements to store in an initial array block */
+#define AHASH_INIT_SIZE 4
+/* Max number of elements to store in an array block */
+#define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE)
+
+/* Max number of elements can be tuned */
+#ifdef IP_SET_HASH_WITH_MULTI
+#define AHASH_MAX(h) ((h)->ahash_max)
+
+static inline u8
+tune_ahash_max(u8 curr, u32 multi)
+{
+ u32 n;
+
+ if (multi < curr)
+ return curr;
+
+ n = curr + AHASH_INIT_SIZE;
+ /* Currently, at listing one hash bucket must fit into a message.
+ * Therefore we have a hard limit here.
+ */
+ return n > curr && n <= 64 ? n : curr;
+}
+#define TUNE_AHASH_MAX(h, multi) \
+ ((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
+#else
+#define AHASH_MAX(h) AHASH_MAX_SIZE
+#define TUNE_AHASH_MAX(h, multi)
+#endif
+
+/* A hash bucket */
+struct hbucket {
+ void *value; /* the array of the values */
+ u8 size; /* size of the array */
+ u8 pos; /* position of the first free entry */
+};
+
+/* The hash table: the table size stored here in order to make resizing easy */
+struct htable {
+ u8 htable_bits; /* size of hash table == 2^htable_bits */
+ struct hbucket bucket[0]; /* hashtable buckets */
+};
+
+#define hbucket(h, i) (&((h)->bucket[i]))
+
+/* Book-keeping of the prefixes added to the set */
+struct net_prefixes {
+ u8 cidr; /* the different cidr values in the set */
+ u32 nets; /* number of elements per cidr */
+};
+
+/* Compute the hash table size */
+static size_t
+htable_size(u8 hbits)
+{
+ size_t hsize;
+
+ /* We must fit both into u32 in jhash and size_t */
+ if (hbits > 31)
+ return 0;
+ hsize = jhash_size(hbits);
+ if ((((size_t)-1) - sizeof(struct htable))/sizeof(struct hbucket)
+ < hsize)
+ return 0;
+
+ return hsize * sizeof(struct hbucket) + sizeof(struct htable);
+}
+
+/* Compute htable_bits from the user input parameter hashsize */
+static u8
+htable_bits(u32 hashsize)
+{
+ /* Assume that hashsize == 2^htable_bits */
+ u8 bits = fls(hashsize - 1);
+ if (jhash_size(bits) != hashsize)
+ /* Round up to the first 2^n value */
+ bits = fls(hashsize);
+
+ return bits;
+}
+
+/* Destroy the hashtable part of the set */
+static void
+ahash_destroy(struct htable *t)
+{
+ struct hbucket *n;
+ u32 i;
+
+ for (i = 0; i < jhash_size(t->htable_bits); i++) {
+ n = hbucket(t, i);
+ if (n->size)
+ /* FIXME: use slab cache */
+ kfree(n->value);
+ }
+
+ ip_set_free(t);
+}
+
+static int
+hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
+{
+ if (n->pos >= n->size) {
+ void *tmp;
+
+ if (n->size >= ahash_max)
+ /* Trigger rehashing */
+ return -EAGAIN;
+
+ tmp = kzalloc((n->size + AHASH_INIT_SIZE) * dsize,
+ GFP_ATOMIC);
+ if (!tmp)
+ return -ENOMEM;
+ if (n->size) {
+ memcpy(tmp, n->value, n->size * dsize);
+ kfree(n->value);
+ }
+ n->value = tmp;
+ n->size += AHASH_INIT_SIZE;
+ }
+ return 0;
+}
+
+#ifdef IP_SET_HASH_WITH_NETS
+#ifdef IP_SET_HASH_WITH_NETS_PACKED
+/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
+#define CIDR(cidr) (cidr + 1)
+#else
+#define CIDR(cidr) (cidr)
+#endif
+
+#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
+
+#ifdef IP_SET_HASH_WITH_MULTI
+#define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1)
+#else
+#define NETS_LENGTH(family) SET_HOST_MASK(family)
+#endif
+
+#else
+#define NETS_LENGTH(family) 0
+#endif /* IP_SET_HASH_WITH_NETS */
+
+#define ext_timeout(e, h) \
+(unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, h) \
+(struct ip_set_counter *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_COUNTER])
+
+#endif /* _IP_SET_HASH_GEN_H */
+
+/* Family dependent templates */
+
+#undef ahash_data
+#undef mtype_data_equal
+#undef mtype_do_data_match
+#undef mtype_data_set_flags
+#undef mtype_data_reset_flags
+#undef mtype_data_netmask
+#undef mtype_data_list
+#undef mtype_data_next
+#undef mtype_elem
+
+#undef mtype_add_cidr
+#undef mtype_del_cidr
+#undef mtype_ahash_memsize
+#undef mtype_flush
+#undef mtype_destroy
+#undef mtype_gc_init
+#undef mtype_same_set
+#undef mtype_kadt
+#undef mtype_uadt
+#undef mtype
+
+#undef mtype_add
+#undef mtype_del
+#undef mtype_test_cidrs
+#undef mtype_test
+#undef mtype_expire
+#undef mtype_resize
+#undef mtype_head
+#undef mtype_list
+#undef mtype_gc
+#undef mtype_gc_init
+#undef mtype_variant
+#undef mtype_data_match
+
+#undef HKEY
+
+#define mtype_data_equal TOKEN(MTYPE, _data_equal)
+#ifdef IP_SET_HASH_WITH_NETS
+#define mtype_do_data_match TOKEN(MTYPE, _do_data_match)
+#else
+#define mtype_do_data_match(d) 1
+#endif
+#define mtype_data_set_flags TOKEN(MTYPE, _data_set_flags)
+#define mtype_data_reset_flags TOKEN(MTYPE, _data_reset_flags)
+#define mtype_data_netmask TOKEN(MTYPE, _data_netmask)
+#define mtype_data_list TOKEN(MTYPE, _data_list)
+#define mtype_data_next TOKEN(MTYPE, _data_next)
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_add_cidr TOKEN(MTYPE, _add_cidr)
+#define mtype_del_cidr TOKEN(MTYPE, _del_cidr)
+#define mtype_ahash_memsize TOKEN(MTYPE, _ahash_memsize)
+#define mtype_flush TOKEN(MTYPE, _flush)
+#define mtype_destroy TOKEN(MTYPE, _destroy)
+#define mtype_gc_init TOKEN(MTYPE, _gc_init)
+#define mtype_same_set TOKEN(MTYPE, _same_set)
+#define mtype_kadt TOKEN(MTYPE, _kadt)
+#define mtype_uadt TOKEN(MTYPE, _uadt)
+#define mtype MTYPE
+
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_add TOKEN(MTYPE, _add)
+#define mtype_del TOKEN(MTYPE, _del)
+#define mtype_test_cidrs TOKEN(MTYPE, _test_cidrs)
+#define mtype_test TOKEN(MTYPE, _test)
+#define mtype_expire TOKEN(MTYPE, _expire)
+#define mtype_resize TOKEN(MTYPE, _resize)
+#define mtype_head TOKEN(MTYPE, _head)
+#define mtype_list TOKEN(MTYPE, _list)
+#define mtype_gc TOKEN(MTYPE, _gc)
+#define mtype_variant TOKEN(MTYPE, _variant)
+#define mtype_data_match TOKEN(MTYPE, _data_match)
+
+#ifndef HKEY_DATALEN
+#define HKEY_DATALEN sizeof(struct mtype_elem)
+#endif
+
+#define HKEY(data, initval, htable_bits) \
+(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval) \
+ & jhash_mask(htable_bits))
+
+#ifndef htype
+#define htype HTYPE
+
+/* The generic hash structure */
+struct htype {
+ struct htable *table; /* the hash table */
+ u32 maxelem; /* max elements in the hash */
+ u32 elements; /* current element (vs timeout) */
+ u32 initval; /* random jhash init value */
+ u32 timeout; /* timeout value, if enabled */
+ size_t dsize; /* data struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
+ struct timer_list gc; /* garbage collection when timeout enabled */
+ struct mtype_elem next; /* temporary storage for uadd */
+#ifdef IP_SET_HASH_WITH_MULTI
+ u8 ahash_max; /* max elements in an array block */
+#endif
+#ifdef IP_SET_HASH_WITH_NETMASK
+ u8 netmask; /* netmask value for subnets to store */
+#endif
+#ifdef IP_SET_HASH_WITH_RBTREE
+ struct rb_root rbtree;
+#endif
+#ifdef IP_SET_HASH_WITH_NETS
+ struct net_prefixes nets[0]; /* book-keeping of prefixes */
+#endif
+};
+#endif
+
+#ifdef IP_SET_HASH_WITH_NETS
+/* Network cidr size book keeping when the hash stores different
+ * sized networks */
+static void
+mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
+{
+ int i, j;
+
+ /* Add in increasing prefix order, so larger cidr first */
+ for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
+ if (j != -1)
+ continue;
+ else if (h->nets[i].cidr < cidr)
+ j = i;
+ else if (h->nets[i].cidr == cidr) {
+ h->nets[i].nets++;
+ return;
+ }
+ }
+ if (j != -1) {
+ for (; i > j; i--) {
+ h->nets[i].cidr = h->nets[i - 1].cidr;
+ h->nets[i].nets = h->nets[i - 1].nets;
+ }
+ }
+ h->nets[i].cidr = cidr;
+ h->nets[i].nets = 1;
+}
+
+static void
+mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
+{
+ u8 i, j;
+
+ for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
+ ;
+ h->nets[i].nets--;
+
+ if (h->nets[i].nets != 0)
+ return;
+
+ for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
+ h->nets[j].cidr = h->nets[j + 1].cidr;
+ h->nets[j].nets = h->nets[j + 1].nets;
+ }
+}
+#endif
+
+/* Calculate the actual memory size of the set data */
+static size_t
+mtype_ahash_memsize(const struct htype *h, u8 nets_length)
+{
+ u32 i;
+ struct htable *t = h->table;
+ size_t memsize = sizeof(*h)
+ + sizeof(*t)
+#ifdef IP_SET_HASH_WITH_NETS
+ + sizeof(struct net_prefixes) * nets_length
+#endif
+ + jhash_size(t->htable_bits) * sizeof(struct hbucket);
+
+ for (i = 0; i < jhash_size(t->htable_bits); i++)
+ memsize += t->bucket[i].size * h->dsize;
+
+ return memsize;
+}
+
+/* Flush a hash type of set: destroy all elements */
+static void
+mtype_flush(struct ip_set *set)
+{
+ struct htype *h = set->data;
+ struct htable *t = h->table;
+ struct hbucket *n;
+ u32 i;
+
+ for (i = 0; i < jhash_size(t->htable_bits); i++) {
+ n = hbucket(t, i);
+ if (n->size) {
+ n->size = n->pos = 0;
+ /* FIXME: use slab cache */
+ kfree(n->value);
+ }
+ }
+#ifdef IP_SET_HASH_WITH_NETS
+ memset(h->nets, 0, sizeof(struct net_prefixes)
+ * NETS_LENGTH(set->family));
+#endif
+ h->elements = 0;
+}
+
+/* Destroy a hash type of set */
+static void
+mtype_destroy(struct ip_set *set)
+{
+ struct htype *h = set->data;
+
+ if (set->extensions & IPSET_EXT_TIMEOUT)
+ del_timer_sync(&h->gc);
+
+ ahash_destroy(h->table);
+#ifdef IP_SET_HASH_WITH_RBTREE
+ rbtree_destroy(&h->rbtree);
+#endif
+ kfree(h);
+
+ set->data = NULL;
+}
+
+static void
+mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
+{
+ struct htype *h = set->data;
+
+ init_timer(&h->gc);
+ h->gc.data = (unsigned long) set;
+ h->gc.function = gc;
+ h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
+ add_timer(&h->gc);
+ pr_debug("gc initialized, run in every %u\n",
+ IPSET_GC_PERIOD(h->timeout));
+}
+
+static bool
+mtype_same_set(const struct ip_set *a, const struct ip_set *b)
+{
+ const struct htype *x = a->data;
+ const struct htype *y = b->data;
+
+ /* Resizing changes htable_bits, so we ignore it */
+ return x->maxelem == y->maxelem &&
+ x->timeout == y->timeout &&
+#ifdef IP_SET_HASH_WITH_NETMASK
+ x->netmask == y->netmask &&
+#endif
+ a->extensions == b->extensions;
+}
+
+/* Get the ith element from the array block n */
+#define ahash_data(n, i, dsize) \
+ ((struct mtype_elem *)((n)->value + ((i) * (dsize))))
+
+/* Delete expired elements from the hashtable */
+static void
+mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
+{
+ struct htable *t = h->table;
+ struct hbucket *n;
+ struct mtype_elem *data;
+ u32 i;
+ int j;
+
+ for (i = 0; i < jhash_size(t->htable_bits); i++) {
+ n = hbucket(t, i);
+ for (j = 0; j < n->pos; j++) {
+ data = ahash_data(n, j, dsize);
+ if (ip_set_timeout_expired(ext_timeout(data, h))) {
+ pr_debug("expired %u/%u\n", i, j);
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_del_cidr(h, CIDR(data->cidr),
+ nets_length);
+#endif
+ if (j != n->pos - 1)
+ /* Not last one */
+ memcpy(data,
+ ahash_data(n, n->pos - 1, dsize),
+ dsize);
+ n->pos--;
+ h->elements--;
+ }
+ }
+ if (n->pos + AHASH_INIT_SIZE < n->size) {
+ void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
+ * dsize,
+ GFP_ATOMIC);
+ if (!tmp)
+ /* Still try to delete expired elements */
+ continue;
+ n->size -= AHASH_INIT_SIZE;
+ memcpy(tmp, n->value, n->size * dsize);
+ kfree(n->value);
+ n->value = tmp;
+ }
+ }
+}
+
+static void
+mtype_gc(unsigned long ul_set)
+{
+ struct ip_set *set = (struct ip_set *) ul_set;
+ struct htype *h = set->data;
+
+ pr_debug("called\n");
+ write_lock_bh(&set->lock);
+ mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
+ write_unlock_bh(&set->lock);
+
+ h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
+ add_timer(&h->gc);
+}
+
+/* Resize a hash: create a new hash table with doubling the hashsize
+ * and inserting the elements to it. Repeat until we succeed or
+ * fail due to memory pressures. */
+static int
+mtype_resize(struct ip_set *set, bool retried)
+{
+ struct htype *h = set->data;
+ struct htable *t, *orig = h->table;
+ u8 htable_bits = orig->htable_bits;
+#ifdef IP_SET_HASH_WITH_NETS
+ u8 flags;
+#endif
+ struct mtype_elem *data;
+ struct mtype_elem *d;
+ struct hbucket *n, *m;
+ u32 i, j;
+ int ret;
+
+ /* Try to cleanup once */
+ if (SET_WITH_TIMEOUT(set) && !retried) {
+ i = h->elements;
+ write_lock_bh(&set->lock);
+ mtype_expire(set->data, NETS_LENGTH(set->family),
+ h->dsize);
+ write_unlock_bh(&set->lock);
+ if (h->elements < i)
+ return 0;
+ }
+
+retry:
+ ret = 0;
+ htable_bits++;
+ pr_debug("attempt to resize set %s from %u to %u, t %p\n",
+ set->name, orig->htable_bits, htable_bits, orig);
+ if (!htable_bits) {
+ /* In case we have plenty of memory :-) */
+ pr_warning("Cannot increase the hashsize of set %s further\n",
+ set->name);
+ return -IPSET_ERR_HASH_FULL;
+ }
+ t = ip_set_alloc(sizeof(*t)
+ + jhash_size(htable_bits) * sizeof(struct hbucket));
+ if (!t)
+ return -ENOMEM;
+ t->htable_bits = htable_bits;
+
+ read_lock_bh(&set->lock);
+ for (i = 0; i < jhash_size(orig->htable_bits); i++) {
+ n = hbucket(orig, i);
+ for (j = 0; j < n->pos; j++) {
+ data = ahash_data(n, j, h->dsize);
+#ifdef IP_SET_HASH_WITH_NETS
+ flags = 0;
+ mtype_data_reset_flags(data, &flags);
+#endif
+ m = hbucket(t, HKEY(data, h->initval, htable_bits));
+ ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize);
+ if (ret < 0) {
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_data_reset_flags(data, &flags);
+#endif
+ read_unlock_bh(&set->lock);
+ ahash_destroy(t);
+ if (ret == -EAGAIN)
+ goto retry;
+ return ret;
+ }
+ d = ahash_data(m, m->pos++, h->dsize);
+ memcpy(d, data, h->dsize);
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_data_reset_flags(d, &flags);
+#endif
+ }
+ }
+
+ rcu_assign_pointer(h->table, t);
+ read_unlock_bh(&set->lock);
+
+ /* Give time to other readers of the set */
+ synchronize_rcu_bh();
+
+ pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
+ orig->htable_bits, orig, t->htable_bits, t);
+ ahash_destroy(orig);
+
+ return 0;
+}
+
+/* Add an element to a hash and update the internal counters when succeeded,
+ * otherwise report the proper error code. */
+static int
+mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct htype *h = set->data;
+ struct htable *t;
+ const struct mtype_elem *d = value;
+ struct mtype_elem *data;
+ struct hbucket *n;
+ int i, ret = 0;
+ int j = AHASH_MAX(h) + 1;
+ bool flag_exist = flags & IPSET_FLAG_EXIST;
+ u32 key, multi = 0;
+
+ if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
+ /* FIXME: when set is full, we slow down here */
+ mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
+
+ if (h->elements >= h->maxelem) {
+ if (net_ratelimit())
+ pr_warning("Set %s is full, maxelem %u reached\n",
+ set->name, h->maxelem);
+ return -IPSET_ERR_HASH_FULL;
+ }
+
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
+ key = HKEY(value, h->initval, t->htable_bits);
+ n = hbucket(t, key);
+ for (i = 0; i < n->pos; i++) {
+ data = ahash_data(n, i, h->dsize);
+ if (mtype_data_equal(data, d, &multi)) {
+ if (flag_exist ||
+ (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(data, h)))) {
+ /* Just the extensions could be overwritten */
+ j = i;
+ goto reuse_slot;
+ } else {
+ ret = -IPSET_ERR_EXIST;
+ goto out;
+ }
+ }
+ /* Reuse first timed out entry */
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(data, h)) &&
+ j != AHASH_MAX(h) + 1)
+ j = i;
+ }
+reuse_slot:
+ if (j != AHASH_MAX(h) + 1) {
+ /* Fill out reused slot */
+ data = ahash_data(n, j, h->dsize);
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
+ mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+#endif
+ } else {
+ /* Use/create a new slot */
+ TUNE_AHASH_MAX(h, multi);
+ ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize);
+ if (ret != 0) {
+ if (ret == -EAGAIN)
+ mtype_data_next(&h->next, d);
+ goto out;
+ }
+ data = ahash_data(n, n->pos++, h->dsize);
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+#endif
+ h->elements++;
+ }
+ memcpy(data, d, sizeof(struct mtype_elem));
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_data_set_flags(data, flags);
+#endif
+ if (SET_WITH_TIMEOUT(set))
+ ip_set_timeout_set(ext_timeout(data, h), ext->timeout);
+ if (SET_WITH_COUNTER(set))
+ ip_set_init_counter(ext_counter(data, h), ext);
+
+out:
+ rcu_read_unlock_bh();
+ return ret;
+}
+
+/* Delete an element from the hash: swap it with the last element
+ * and free up space if possible.
+ */
+static int
+mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct htype *h = set->data;
+ struct htable *t = h->table;
+ const struct mtype_elem *d = value;
+ struct mtype_elem *data;
+ struct hbucket *n;
+ int i;
+ u32 key, multi = 0;
+
+ key = HKEY(value, h->initval, t->htable_bits);
+ n = hbucket(t, key);
+ for (i = 0; i < n->pos; i++) {
+ data = ahash_data(n, i, h->dsize);
+ if (!mtype_data_equal(data, d, &multi))
+ continue;
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(data, h)))
+ return -IPSET_ERR_EXIST;
+ if (i != n->pos - 1)
+ /* Not last one */
+ memcpy(data, ahash_data(n, n->pos - 1, h->dsize),
+ h->dsize);
+
+ n->pos--;
+ h->elements--;
+#ifdef IP_SET_HASH_WITH_NETS
+ mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
+#endif
+ if (n->pos + AHASH_INIT_SIZE < n->size) {
+ void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
+ * h->dsize,
+ GFP_ATOMIC);
+ if (!tmp)
+ return 0;
+ n->size -= AHASH_INIT_SIZE;
+ memcpy(tmp, n->value, n->size * h->dsize);
+ kfree(n->value);
+ n->value = tmp;
+ }
+ return 0;
+ }
+
+ return -IPSET_ERR_EXIST;
+}
+
+static inline int
+mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, struct ip_set *set, u32 flags)
+{
+ if (SET_WITH_COUNTER(set))
+ ip_set_update_counter(ext_counter(data,
+ (struct htype *)(set->data)),
+ ext, mext, flags);
+ return mtype_do_data_match(data);
+}
+
+#ifdef IP_SET_HASH_WITH_NETS
+/* Special test function which takes into account the different network
+ * sizes added to the set */
+static int
+mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
+ const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct htype *h = set->data;
+ struct htable *t = h->table;
+ struct hbucket *n;
+ struct mtype_elem *data;
+ int i, j = 0;
+ u32 key, multi = 0;
+ u8 nets_length = NETS_LENGTH(set->family);
+
+ pr_debug("test by nets\n");
+ for (; j < nets_length && h->nets[j].nets && !multi; j++) {
+ mtype_data_netmask(d, h->nets[j].cidr);
+ key = HKEY(d, h->initval, t->htable_bits);
+ n = hbucket(t, key);
+ for (i = 0; i < n->pos; i++) {
+ data = ahash_data(n, i, h->dsize);
+ if (!mtype_data_equal(data, d, &multi))
+ continue;
+ if (SET_WITH_TIMEOUT(set)) {
+ if (!ip_set_timeout_expired(
+ ext_timeout(data, h)))
+ return mtype_data_match(data, ext,
+ mext, set,
+ flags);
+#ifdef IP_SET_HASH_WITH_MULTI
+ multi = 0;
+#endif
+ } else
+ return mtype_data_match(data, ext,
+ mext, set, flags);
+ }
+ }
+ return 0;
+}
+#endif
+
+/* Test whether the element is added to the set */
+static int
+mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
+{
+ struct htype *h = set->data;
+ struct htable *t = h->table;
+ struct mtype_elem *d = value;
+ struct hbucket *n;
+ struct mtype_elem *data;
+ int i;
+ u32 key, multi = 0;
+
+#ifdef IP_SET_HASH_WITH_NETS
+ /* If we test an IP address and not a network address,
+ * try all possible network sizes */
+ if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
+ return mtype_test_cidrs(set, d, ext, mext, flags);
+#endif
+
+ key = HKEY(d, h->initval, t->htable_bits);
+ n = hbucket(t, key);
+ for (i = 0; i < n->pos; i++) {
+ data = ahash_data(n, i, h->dsize);
+ if (mtype_data_equal(data, d, &multi) &&
+ !(SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(data, h))))
+ return mtype_data_match(data, ext, mext, set, flags);
+ }
+ return 0;
+}
+
+/* Reply a HEADER request: fill out the header part of the set */
+static int
+mtype_head(struct ip_set *set, struct sk_buff *skb)
+{
+ const struct htype *h = set->data;
+ struct nlattr *nested;
+ size_t memsize;
+
+ read_lock_bh(&set->lock);
+ memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family));
+ read_unlock_bh(&set->lock);
+
+ nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested)
+ goto nla_put_failure;
+ if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
+ htonl(jhash_size(h->table->htable_bits))) ||
+ nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
+ goto nla_put_failure;
+#ifdef IP_SET_HASH_WITH_NETMASK
+ if (h->netmask != HOST_MASK &&
+ nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
+ goto nla_put_failure;
+#endif
+ if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
+ ((set->extensions & IPSET_EXT_TIMEOUT) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))) ||
+ ((set->extensions & IPSET_EXT_COUNTER) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))))
+ goto nla_put_failure;
+ ipset_nest_end(skb, nested);
+
+ return 0;
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+/* Reply a LIST/SAVE request: dump the elements of the specified set */
+static int
+mtype_list(const struct ip_set *set,
+ struct sk_buff *skb, struct netlink_callback *cb)
+{
+ const struct htype *h = set->data;
+ const struct htable *t = h->table;
+ struct nlattr *atd, *nested;
+ const struct hbucket *n;
+ const struct mtype_elem *e;
+ u32 first = cb->args[2];
+ /* We assume that one hash bucket fills into one page */
+ void *incomplete;
+ int i;
+
+ atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
+ if (!atd)
+ return -EMSGSIZE;
+ pr_debug("list hash set %s\n", set->name);
+ for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
+ incomplete = skb_tail_pointer(skb);
+ n = hbucket(t, cb->args[2]);
+ pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
+ for (i = 0; i < n->pos; i++) {
+ e = ahash_data(n, i, h->dsize);
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, h)))
+ continue;
+ pr_debug("list hash %lu hbucket %p i %u, data %p\n",
+ cb->args[2], n, i, e);
+ nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
+ if (!nested) {
+ if (cb->args[2] == first) {
+ nla_nest_cancel(skb, atd);
+ return -EMSGSIZE;
+ } else
+ goto nla_put_failure;
+ }
+ if (mtype_data_list(skb, e))
+ goto nla_put_failure;
+ if (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(e, h)))))
+ goto nla_put_failure;
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(e, h)))
+ goto nla_put_failure;
+ ipset_nest_end(skb, nested);
+ }
+ }
+ ipset_nest_end(skb, atd);
+ /* Set listing finished */
+ cb->args[2] = 0;
+
+ return 0;
+
+nla_put_failure:
+ nlmsg_trim(skb, incomplete);
+ ipset_nest_end(skb, atd);
+ if (unlikely(first == cb->args[2])) {
+ pr_warning("Can't list set %s: one bucket does not fit into "
+ "a message. Please report it!\n", set->name);
+ cb->args[2] = 0;
+ return -EMSGSIZE;
+ }
+ return 0;
+}
+
+static int
+TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
+ const struct xt_action_param *par,
+ enum ipset_adt adt, struct ip_set_adt_opt *opt);
+
+static int
+TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
+ enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
+
+static const struct ip_set_type_variant mtype_variant = {
+ .kadt = mtype_kadt,
+ .uadt = mtype_uadt,
+ .adt = {
+ [IPSET_ADD] = mtype_add,
+ [IPSET_DEL] = mtype_del,
+ [IPSET_TEST] = mtype_test,
+ },
+ .destroy = mtype_destroy,
+ .flush = mtype_flush,
+ .head = mtype_head,
+ .list = mtype_list,
+ .resize = mtype_resize,
+ .same_set = mtype_same_set,
+};
+
+#ifdef IP_SET_EMIT_CREATE
+static int
+TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
+{
+ u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+ u32 cadt_flags = 0;
+ u8 hbits;
+#ifdef IP_SET_HASH_WITH_NETMASK
+ u8 netmask;
+#endif
+ size_t hsize;
+ struct HTYPE *h;
+
+ if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
+ return -IPSET_ERR_INVALID_FAMILY;
+#ifdef IP_SET_HASH_WITH_NETMASK
+ netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
+ pr_debug("Create set %s with family %s\n",
+ set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
+#endif
+
+ if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ return -IPSET_ERR_PROTOCOL;
+
+ if (tb[IPSET_ATTR_HASHSIZE]) {
+ hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
+ if (hashsize < IPSET_MIMINAL_HASHSIZE)
+ hashsize = IPSET_MIMINAL_HASHSIZE;
+ }
+
+ if (tb[IPSET_ATTR_MAXELEM])
+ maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
+
+#ifdef IP_SET_HASH_WITH_NETMASK
+ if (tb[IPSET_ATTR_NETMASK]) {
+ netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
+
+ if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
+ (set->family == NFPROTO_IPV6 && netmask > 128) ||
+ netmask == 0)
+ return -IPSET_ERR_INVALID_NETMASK;
+ }
+#endif
+
+ hsize = sizeof(*h);
+#ifdef IP_SET_HASH_WITH_NETS
+ hsize += sizeof(struct net_prefixes) *
+ (set->family == NFPROTO_IPV4 ? 32 : 128);
+#endif
+ h = kzalloc(hsize, GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ h->maxelem = maxelem;
+#ifdef IP_SET_HASH_WITH_NETMASK
+ h->netmask = netmask;
+#endif
+ get_random_bytes(&h->initval, sizeof(h->initval));
+ h->timeout = IPSET_NO_TIMEOUT;
+
+ hbits = htable_bits(hashsize);
+ hsize = htable_size(hbits);
+ if (hsize == 0) {
+ kfree(h);
+ return -ENOMEM;
+ }
+ h->table = ip_set_alloc(hsize);
+ if (!h->table) {
+ kfree(h);
+ return -ENOMEM;
+ }
+ h->table->htable_bits = hbits;
+
+ set->data = h;
+ if (set->family == NFPROTO_IPV4)
+ set->variant = &TOKEN(HTYPE, 4_variant);
+ else
+ set->variant = &TOKEN(HTYPE, 6_variant);
+
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ h->timeout =
+ ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 4ct_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 4ct_elem),
+ timeout);
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 4ct_elem),
+ counter);
+ TOKEN(HTYPE, 4_gc_init)(set,
+ TOKEN(HTYPE, 4_gc));
+ } else {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 6ct_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 6ct_elem),
+ timeout);
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 6ct_elem),
+ counter);
+ TOKEN(HTYPE, 6_gc_init)(set,
+ TOKEN(HTYPE, 6_gc));
+ }
+ } else {
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 4c_elem));
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 4c_elem),
+ counter);
+ } else {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 6c_elem));
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 6c_elem),
+ counter);
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 4t_elem),
+ timeout);
+ TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc));
+ } else {
+ h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 6t_elem),
+ timeout);
+ TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc));
+ }
+ } else {
+ if (set->family == NFPROTO_IPV4)
+ h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem));
+ else
+ h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem));
+ }
+
+ pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
+ set->name, jhash_size(h->table->htable_bits),
+ h->table->htable_bits, h->maxelem, set->data, h->table);
+
+ return 0;
+}
+#endif /* IP_SET_EMIT_CREATE */
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index b7d4cb475ae6..c74e6e14cd93 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -21,11 +21,10 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
-#define REVISION_MAX 0
+#define REVISION_MAX 1 /* Counters support */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -33,58 +32,47 @@ IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip");
/* Type specific function prefix */
-#define TYPE hash_ip
-
-static bool
-hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
-
-#define hash_ip4_same_set hash_ip_same_set
-#define hash_ip6_same_set hash_ip_same_set
+#define HTYPE hash_ip
+#define IP_SET_HASH_WITH_NETMASK
-/* The type variant functions: IPv4 */
+/* IPv4 variants */
-/* Member elements without timeout */
+/* Member elements */
struct hash_ip4_elem {
+ /* Zero valued IP addresses cannot be stored */
__be32 ip;
};
-/* Member elements with timeout support */
-struct hash_ip4_telem {
+struct hash_ip4t_elem {
__be32 ip;
unsigned long timeout;
};
-static inline bool
-hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
- const struct hash_ip4_elem *ip2,
- u32 *multi)
-{
- return ip1->ip == ip2->ip;
-}
+struct hash_ip4c_elem {
+ __be32 ip;
+ struct ip_set_counter counter;
+};
-static inline bool
-hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
-{
- return elem->ip == 0;
-}
+struct hash_ip4ct_elem {
+ __be32 ip;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
-static inline void
-hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
-{
- dst->ip = src->ip;
-}
+/* Common functions */
-/* Zero valued IP addresses cannot be stored */
-static inline void
-hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
+static inline bool
+hash_ip4_data_equal(const struct hash_ip4_elem *e1,
+ const struct hash_ip4_elem *e2,
+ u32 *multi)
{
- elem->ip = 0;
+ return e1->ip == e2->ip;
}
static inline bool
-hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
+hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *e)
{
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip))
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip))
goto nla_put_failure;
return 0;
@@ -92,41 +80,26 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
+static inline void
+hash_ip4_data_next(struct hash_ip4_elem *next, const struct hash_ip4_elem *e)
{
- const struct hash_ip4_telem *tdata =
- (const struct hash_ip4_telem *)data;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = e->ip;
}
-#define IP_SET_HASH_WITH_NETMASK
+#define MTYPE hash_ip4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
-{
- h->next.ip = d->ip;
-}
+#include "ip_set_hash_gen.h"
static int
hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
+ struct hash_ip4_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
__be32 ip;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
@@ -134,43 +107,42 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
if (ip == 0)
return -EINVAL;
- return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
+ e.ip = ip;
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- u32 ip, ip_to, hosts, timeout = h->timeout;
- __be32 nip;
+ struct hash_ip4_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip, ip_to, hosts;
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
ip &= ip_set_hostmask(h->netmask);
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
if (adt == IPSET_TEST) {
- nip = htonl(ip);
- if (nip == 0)
+ e.ip = htonl(ip);
+ if (e.ip == 0)
return -IPSET_ERR_HASH_ELEM;
- return adtfn(set, &nip, timeout, flags);
+ return adtfn(set, &e, &ext, &ext, flags);
}
ip_to = ip;
@@ -193,10 +165,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip += hosts) {
- nip = htonl(ip);
- if (nip == 0)
+ e.ip = htonl(ip);
+ if (e.ip == 0)
return -IPSET_ERR_HASH_ELEM;
- ret = adtfn(set, &nip, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -206,29 +178,31 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout &&
- x->netmask == y->netmask;
-}
+/* Member elements */
+struct hash_ip6_elem {
+ union nf_inet_addr ip;
+};
-/* The type variant functions: IPv6 */
+struct hash_ip6t_elem {
+ union nf_inet_addr ip;
+ unsigned long timeout;
+};
-struct hash_ip6_elem {
+struct hash_ip6c_elem {
union nf_inet_addr ip;
+ struct ip_set_counter counter;
};
-struct hash_ip6_telem {
+struct hash_ip6ct_elem {
union nf_inet_addr ip;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
const struct hash_ip6_elem *ip2,
@@ -237,37 +211,16 @@ hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6);
}
-static inline bool
-hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
-{
- return ipv6_addr_any(&elem->ip.in6);
-}
-
static inline void
-hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
+hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix)
{
- dst->ip.in6 = src->ip.in6;
-}
-
-static inline void
-hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
-{
- ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
-}
-
-static inline void
-ip6_netmask(union nf_inet_addr *ip, u8 prefix)
-{
- ip->ip6[0] &= ip_set_netmask6(prefix)[0];
- ip->ip6[1] &= ip_set_netmask6(prefix)[1];
- ip->ip6[2] &= ip_set_netmask6(prefix)[2];
- ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+ ip6_netmask(ip, prefix);
}
static bool
-hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
+hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e)
{
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6))
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6))
goto nla_put_failure;
return 0;
@@ -275,69 +228,55 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
+static inline void
+hash_ip6_data_next(struct hash_ip4_elem *next, const struct hash_ip6_elem *e)
{
- const struct hash_ip6_telem *e =
- (const struct hash_ip6_telem *)data;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#undef HKEY_DATALEN
+#define MTYPE hash_ip6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-static inline void
-hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
-{
-}
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- union nf_inet_addr ip;
+ struct hash_ip6_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
- ip6_netmask(&ip, h->netmask);
- if (ipv6_addr_any(&ip.in6))
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ hash_ip6_netmask(&e.ip, h->netmask);
+ if (ipv6_addr_any(&e.ip.in6))
return -EINVAL;
- return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
-static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
- [IPSET_ATTR_IP] = { .type = NLA_NESTED },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
-};
-
static int
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- union nf_inet_addr ip;
- u32 timeout = h->timeout;
+ struct hash_ip6_elem e = {};
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL;
@@ -345,110 +284,20 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- ip6_netmask(&ip, h->netmask);
- if (ipv6_addr_any(&ip.in6))
+ hash_ip6_netmask(&e.ip, h->netmask);
+ if (ipv6_addr_any(&e.ip.in6))
return -IPSET_ERR_HASH_ELEM;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
- ret = adtfn(set, &ip, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
-/* Create hash:ip type of sets */
-
-static int
-hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 netmask, hbits;
- size_t hsize;
- struct ip_set_hash *h;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
- netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
- pr_debug("Create set %s with family %s\n",
- set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- if (tb[IPSET_ATTR_NETMASK]) {
- netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
-
- if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
- (set->family == NFPROTO_IPV6 && netmask > 128) ||
- netmask == 0)
- return -IPSET_ERR_INVALID_NETMASK;
- }
-
- h = kzalloc(sizeof(*h), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- h->netmask = netmask;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ip4_tvariant : &hash_ip6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_ip4_gc_init(set);
- else
- hash_ip6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ip4_variant : &hash_ip6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
-}
-
static struct ip_set_type hash_ip_type __read_mostly = {
.name = "hash:ip",
.protocol = IPSET_PROTOCOL,
@@ -465,6 +314,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -472,6 +322,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index d8f77bacae86..7a2d2bd98d04 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -21,12 +21,12 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
-#define REVISION_MAX 1 /* SCTP and UDPLITE support added */
+/* 1 SCTP and UDPLITE support added */
+#define REVISION_MAX 2 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -34,33 +34,45 @@ IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port");
/* Type specific function prefix */
-#define TYPE hash_ipport
+#define HTYPE hash_ipport
-static bool
-hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
+/* IPv4 variants */
-#define hash_ipport4_same_set hash_ipport_same_set
-#define hash_ipport6_same_set hash_ipport_same_set
+/* Member elements */
+struct hash_ipport4_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+};
-/* The type variant functions: IPv4 */
+struct hash_ipport4t_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
-/* Member elements without timeout */
-struct hash_ipport4_elem {
+struct hash_ipport4c_elem {
__be32 ip;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
};
-/* Member elements with timeout support */
-struct hash_ipport4_telem {
+struct hash_ipport4ct_elem {
__be32 ip;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
const struct hash_ipport4_elem *ip2,
@@ -71,27 +83,6 @@ hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipport4_data_isnull(const struct hash_ipport4_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
- const struct hash_ipport4_elem *src)
-{
- dst->ip = src->ip;
- dst->port = src->port;
- dst->proto = src->proto;
-}
-
-static inline void
-hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_ipport4_data_list(struct sk_buff *skb,
const struct hash_ipport4_elem *data)
@@ -106,111 +97,91 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipport4_data_tlist(struct sk_buff *skb,
- const struct hash_ipport4_elem *data)
-{
- const struct hash_ipport4_telem *tdata =
- (const struct hash_ipport4_telem *)data;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
-}
-
-#define PF 4
-#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
static inline void
-hash_ipport4_data_next(struct ip_set_hash *h,
+hash_ipport4_data_next(struct hash_ipport4_elem *next,
const struct hash_ipport4_elem *d)
{
- h->next.ip = d->ip;
- h->next.port = d->port;
+ next->ip = d->ip;
+ next->port = d->port;
}
+#define MTYPE hash_ipport4
+#define PF 4
+#define HOST_MASK 32
+#define HKEY_DATALEN sizeof(struct hash_ipport4_elem)
+#include "ip_set_hash_gen.h"
+
static int
hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = { };
+ struct hash_ipport4_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
-
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport4_elem data = { };
+ struct hash_ipport4_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 ip, ip_to, p = 0, port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMP))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMP))
+ e.port = 0;
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- ip_to = ip = ntohl(data.ip);
+ ip_to = ip = ntohl(e.ip);
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -225,7 +196,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
ip_set_mask_from_to(ip, ip_to, cidr);
}
- port_to = port = ntohs(data.port);
+ port_to = port = ntohs(e.port);
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
@@ -238,9 +209,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) {
- data.ip = htonl(ip);
- data.port = htons(p);
- ret = adtfn(set, &data, timeout, flags);
+ e.ip = htonl(ip);
+ e.port = htons(p);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -251,34 +222,42 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
+struct hash_ipport6_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+};
-/* The type variant functions: IPv6 */
+struct hash_ipport6t_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
-struct hash_ipport6_elem {
+struct hash_ipport6c_elem {
union nf_inet_addr ip;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
};
-struct hash_ipport6_telem {
+struct hash_ipport6ct_elem {
union nf_inet_addr ip;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
const struct hash_ipport6_elem *ip2,
@@ -289,25 +268,6 @@ hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
- const struct hash_ipport6_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_ipport6_data_list(struct sk_buff *skb,
const struct hash_ipport6_elem *data)
@@ -322,66 +282,52 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipport6_data_tlist(struct sk_buff *skb,
- const struct hash_ipport6_elem *data)
+static inline void
+hash_ipport6_data_next(struct hash_ipport4_elem *next,
+ const struct hash_ipport6_elem *d)
{
- const struct hash_ipport6_telem *e =
- (const struct hash_ipport6_telem *)data;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->port = d->port;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#undef HKEY_DATALEN
+#define MTYPE hash_ipport6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ipport6_data_next(struct ip_set_hash *h,
- const struct hash_ipport6_elem *d)
-{
- h->next.port = d->port;
-}
+#define HKEY_DATALEN sizeof(struct hash_ipport6_elem)
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = { };
+ struct hash_ipport6_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
-
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipport6_elem data = { };
+ struct hash_ipport6_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -389,6 +335,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL;
@@ -396,39 +344,34 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMPV6))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMPV6))
+ e.port = 0;
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- port = ntohs(data.port);
+ port = ntohs(e.port);
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
swap(port, port_to);
@@ -436,8 +379,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
port = ntohs(h->next.port);
for (; port <= port_to; port++) {
- data.port = htons(port);
- ret = adtfn(set, &data, timeout, flags);
+ e.port = htons(port);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -447,78 +390,6 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* Create hash:ip type of sets */
-
-static int
-hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- struct ip_set_hash *h;
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_ipport4_gc_init(set);
- else
- hash_ipport6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipport4_variant : &hash_ipport6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
-}
-
static struct ip_set_type hash_ipport_type __read_mostly = {
.name = "hash:ip,port",
.protocol = IPSET_PROTOCOL,
@@ -535,6 +406,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -545,6 +417,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 1da1e955f38b..34e8a1acce42 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -21,12 +21,12 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
-#define REVISION_MAX 1 /* SCTP and UDPLITE support added */
+/* 1 SCTP and UDPLITE support added */
+#define REVISION_MAX 2 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -34,32 +34,44 @@ IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,ip");
/* Type specific function prefix */
-#define TYPE hash_ipportip
+#define HTYPE hash_ipportip
-static bool
-hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
+/* IPv4 variants */
-#define hash_ipportip4_same_set hash_ipportip_same_set
-#define hash_ipportip6_same_set hash_ipportip_same_set
+/* Member elements */
+struct hash_ipportip4_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+};
-/* The type variant functions: IPv4 */
+struct hash_ipportip4t_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
-/* Member elements without timeout */
-struct hash_ipportip4_elem {
+struct hash_ipportip4c_elem {
__be32 ip;
__be32 ip2;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
};
-/* Member elements with timeout support */
-struct hash_ipportip4_telem {
+struct hash_ipportip4ct_elem {
__be32 ip;
__be32 ip2;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
unsigned long timeout;
};
@@ -74,25 +86,6 @@ hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
- const struct hash_ipportip4_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_ipportip4_data_list(struct sk_buff *skb,
const struct hash_ipportip4_elem *data)
@@ -108,117 +101,96 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipportip4_data_tlist(struct sk_buff *skb,
- const struct hash_ipportip4_elem *data)
+static inline void
+hash_ipportip4_data_next(struct hash_ipportip4_elem *next,
+ const struct hash_ipportip4_elem *d)
{
- const struct hash_ipportip4_telem *tdata =
- (const struct hash_ipportip4_telem *)data;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP2, tdata->ip2) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = d->ip;
+ next->port = d->port;
}
+/* Common functions */
+#define MTYPE hash_ipportip4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ipportip4_data_next(struct ip_set_hash *h,
- const struct hash_ipportip4_elem *d)
-{
- h->next.ip = d->ip;
- h->next.port = d->port;
-}
+#include "ip_set_hash_gen.h"
static int
hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = { };
+ struct hash_ipportip4_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
- ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
-
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip4_elem data = { };
+ struct hash_ipportip4_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 ip, ip_to, p = 0, port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
+ ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &e.ip2);
if (ret)
return ret;
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMP))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMP))
+ e.port = 0;
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- ip_to = ip = ntohl(data.ip);
+ ip_to = ip = ntohl(e.ip);
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -233,7 +205,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
ip_set_mask_from_to(ip, ip_to, cidr);
}
- port_to = port = ntohs(data.port);
+ port_to = port = ntohs(e.port);
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
@@ -246,9 +218,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) {
- data.ip = htonl(ip);
- data.port = htons(p);
- ret = adtfn(set, &data, timeout, flags);
+ e.ip = htonl(ip);
+ e.port = htons(p);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -259,36 +231,46 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
+struct hash_ipportip6_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+};
-/* The type variant functions: IPv6 */
+struct hash_ipportip6t_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
-struct hash_ipportip6_elem {
+struct hash_ipportip6c_elem {
union nf_inet_addr ip;
union nf_inet_addr ip2;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
};
-struct hash_ipportip6_telem {
+struct hash_ipportip6ct_elem {
union nf_inet_addr ip;
union nf_inet_addr ip2;
__be16 port;
u8 proto;
u8 padding;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
const struct hash_ipportip6_elem *ip2,
@@ -300,25 +282,6 @@ hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
- const struct hash_ipportip6_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_ipportip6_data_list(struct sk_buff *skb,
const struct hash_ipportip6_elem *data)
@@ -334,68 +297,51 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipportip6_data_tlist(struct sk_buff *skb,
- const struct hash_ipportip6_elem *data)
+static inline void
+hash_ipportip6_data_next(struct hash_ipportip4_elem *next,
+ const struct hash_ipportip6_elem *d)
{
- const struct hash_ipportip6_telem *e =
- (const struct hash_ipportip6_telem *)data;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->port = d->port;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#define MTYPE hash_ipportip6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ipportip6_data_next(struct ip_set_hash *h,
- const struct hash_ipportip6_elem *d)
-{
- h->next.port = d->port;
-}
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = { };
+ struct hash_ipportip6_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
-
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportip6_elem data = { };
+ struct hash_ipportip6_elem e = { };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -403,6 +349,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL;
@@ -410,43 +358,38 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
if (ret)
return ret;
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMPV6))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMPV6))
+ e.port = 0;
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- port = ntohs(data.port);
+ port = ntohs(e.port);
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
swap(port, port_to);
@@ -454,8 +397,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
port = ntohs(h->next.port);
for (; port <= port_to; port++) {
- data.port = htons(port);
- ret = adtfn(set, &data, timeout, flags);
+ e.port = htons(port);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -465,78 +408,6 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* Create hash:ip type of sets */
-
-static int
-hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- struct ip_set_hash *h;
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_ipportip4_gc_init(set);
- else
- hash_ipportip6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipportip4_variant : &hash_ipportip6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
-}
-
static struct ip_set_type hash_ipportip_type __read_mostly = {
.name = "hash:ip,port,ip",
.protocol = IPSET_PROTOCOL,
@@ -552,6 +423,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -563,6 +435,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index f2627226a087..c6a525373be4 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -21,14 +21,14 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 SCTP and UDPLITE support added */
/* 2 Range as input support for IPv4 added */
-#define REVISION_MAX 3 /* nomatch flag support added */
+/* 3 nomatch flag support added */
+#define REVISION_MAX 4 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -36,23 +36,19 @@ IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,net");
/* Type specific function prefix */
-#define TYPE hash_ipportnet
-
-static bool
-hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
-
-#define hash_ipportnet4_same_set hash_ipportnet_same_set
-#define hash_ipportnet6_same_set hash_ipportnet_same_set
-
-/* The type variant functions: IPv4 */
+#define HTYPE hash_ipportnet
/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
* However this way we have to store internally cidr - 1,
* dancing back and forth.
*/
#define IP_SET_HASH_WITH_NETS_PACKED
+#define IP_SET_HASH_WITH_PROTO
+#define IP_SET_HASH_WITH_NETS
+
+/* IPv4 variants */
-/* Member elements without timeout */
+/* Member elements */
struct hash_ipportnet4_elem {
__be32 ip;
__be32 ip2;
@@ -62,8 +58,7 @@ struct hash_ipportnet4_elem {
u8 proto;
};
-/* Member elements with timeout support */
-struct hash_ipportnet4_telem {
+struct hash_ipportnet4t_elem {
__be32 ip;
__be32 ip2;
__be16 port;
@@ -73,6 +68,29 @@ struct hash_ipportnet4_telem {
unsigned long timeout;
};
+struct hash_ipportnet4c_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipportnet4ct_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
+/* Common functions */
+
static inline bool
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
const struct hash_ipportnet4_elem *ip2,
@@ -85,29 +103,22 @@ hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipportnet4_data_isnull(const struct hash_ipportnet4_elem *elem)
+static inline int
+hash_ipportnet4_do_data_match(const struct hash_ipportnet4_elem *elem)
{
- return elem->proto == 0;
+ return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
- const struct hash_ipportnet4_elem *src)
+hash_ipportnet4_data_set_flags(struct hash_ipportnet4_elem *elem, u32 flags)
{
- memcpy(dst, src, sizeof(*dst));
+ elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
}
static inline void
-hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
+hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags)
{
- dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
-}
-
-static inline int
-hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -117,12 +128,6 @@ hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
elem->cidr = cidr - 1;
}
-static inline void
-hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_ipportnet4_data_list(struct sk_buff *skb,
const struct hash_ipportnet4_elem *data)
@@ -143,81 +148,56 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipportnet4_data_tlist(struct sk_buff *skb,
- const struct hash_ipportnet4_elem *data)
+static inline void
+hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next,
+ const struct hash_ipportnet4_elem *d)
{
- const struct hash_ipportnet4_telem *tdata =
- (const struct hash_ipportnet4_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP2, tdata->ip2) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = d->ip;
+ next->port = d->port;
+ next->ip2 = d->ip2;
}
-#define IP_SET_HASH_WITH_PROTO
-#define IP_SET_HASH_WITH_NETS
-
+#define MTYPE hash_ipportnet4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ipportnet4_data_next(struct ip_set_hash *h,
- const struct hash_ipportnet4_elem *d)
-{
- h->next.ip = d->ip;
- h->next.port = d->port;
- h->next.ip2 = d->ip2;
-}
+#include "ip_set_hash_gen.h"
static int
hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet4_elem data = {
+ struct hash_ipportnet4_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK - 1;
+ e.cidr = HOST_MASK - 1;
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
- ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
- data.ip2 &= ip_set_netmask(data.cidr + 1);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
+ e.ip2 &= ip_set_netmask(e.cidr + 1);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 };
+ struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 ip, ip_to, p = 0, port, port_to;
u32 ip2_from, ip2_to, ip2_last, ip2;
- u32 timeout = h->timeout;
bool with_ports = false;
u8 cidr;
int ret;
@@ -226,13 +206,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
@@ -244,46 +227,41 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
if (!cidr || cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- data.cidr = cidr - 1;
+ e.cidr = cidr - 1;
}
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMP))
- data.port = 0;
+ if (!(with_ports || e.proto == IPPROTO_ICMP))
+ e.port = 0;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
tb[IPSET_ATTR_IP2_TO])) {
- data.ip = htonl(ip);
- data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr + 1));
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ e.ip = htonl(ip);
+ e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
ip_to = ip;
@@ -301,7 +279,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
ip_set_mask_from_to(ip, ip_to, cidr);
}
- port_to = port = ntohs(data.port);
+ port_to = port = ntohs(e.port);
if (tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
@@ -317,28 +295,27 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(ip2_from, ip2_to);
if (ip2_from + UINT_MAX == ip2_to)
return -IPSET_ERR_HASH_RANGE;
- } else {
- ip_set_mask_from_to(ip2_from, ip2_to, data.cidr + 1);
- }
+ } else
+ ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
if (retried)
ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip++) {
- data.ip = htonl(ip);
+ e.ip = htonl(ip);
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) {
- data.port = htons(p);
+ e.port = htons(p);
ip2 = retried
&& ip == ntohl(h->next.ip)
&& p == ntohs(h->next.port)
? ntohl(h->next.ip2) : ip2_from;
while (!after(ip2, ip2_to)) {
- data.ip2 = htonl(ip2);
+ e.ip2 = htonl(ip2);
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
&cidr);
- data.cidr = cidr - 1;
- ret = adtfn(set, &data, timeout, flags);
+ e.cidr = cidr - 1;
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -351,38 +328,50 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
+struct hash_ipportnet6_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+};
-/* The type variant functions: IPv6 */
+struct hash_ipportnet6t_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ unsigned long timeout;
+};
-struct hash_ipportnet6_elem {
+struct hash_ipportnet6c_elem {
union nf_inet_addr ip;
union nf_inet_addr ip2;
__be16 port;
u8 cidr:7;
u8 nomatch:1;
u8 proto;
+ struct ip_set_counter counter;
};
-struct hash_ipportnet6_telem {
+struct hash_ipportnet6ct_elem {
union nf_inet_addr ip;
union nf_inet_addr ip2;
__be16 port;
u8 cidr:7;
u8 nomatch:1;
u8 proto;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
const struct hash_ipportnet6_elem *ip2,
@@ -395,44 +384,22 @@ hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
ip1->proto == ip2->proto;
}
-static inline bool
-hash_ipportnet6_data_isnull(const struct hash_ipportnet6_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
- const struct hash_ipportnet6_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
-{
- dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
-}
-
static inline int
-hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
+hash_ipportnet6_do_data_match(const struct hash_ipportnet6_elem *elem)
{
return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
+hash_ipportnet6_data_set_flags(struct hash_ipportnet6_elem *elem, u32 flags)
{
- elem->proto = 0;
+ elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
}
static inline void
-ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags)
{
- ip->ip6[0] &= ip_set_netmask6(prefix)[0];
- ip->ip6[1] &= ip_set_netmask6(prefix)[1];
- ip->ip6[2] &= ip_set_netmask6(prefix)[2];
- ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -462,78 +429,58 @@ nla_put_failure:
return 1;
}
-static bool
-hash_ipportnet6_data_tlist(struct sk_buff *skb,
- const struct hash_ipportnet6_elem *data)
+static inline void
+hash_ipportnet6_data_next(struct hash_ipportnet4_elem *next,
+ const struct hash_ipportnet6_elem *d)
{
- const struct hash_ipportnet6_telem *e =
- (const struct hash_ipportnet6_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->port = d->port;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#define MTYPE hash_ipportnet6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_ipportnet6_data_next(struct ip_set_hash *h,
- const struct hash_ipportnet6_elem *d)
-{
- h->next.port = d->port;
-}
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet6_elem data = {
+ struct hash_ipportnet6_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK - 1;
+ e.cidr = HOST_MASK - 1;
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
- ip6_netmask(&data.ip2, data.cidr + 1);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
+ ip6_netmask(&e.ip2, e.cidr + 1);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_ipportnet6_elem data = { .cidr = HOST_MASK - 1 };
+ struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
u8 cidr;
int ret;
@@ -543,6 +490,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL;
@@ -552,11 +501,12 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
if (ret)
return ret;
@@ -564,46 +514,41 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
if (!cidr || cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- data.cidr = cidr - 1;
+ e.cidr = cidr - 1;
}
- ip6_netmask(&data.ip2, data.cidr + 1);
+ ip6_netmask(&e.ip2, e.cidr + 1);
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMPV6))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMPV6))
+ e.port = 0;
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
- port = ntohs(data.port);
+ port = ntohs(e.port);
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
swap(port, port_to);
@@ -611,8 +556,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
port = ntohs(h->next.port);
for (; port <= port_to; port++) {
- data.port = htons(port);
- ret = adtfn(set, &data, timeout, flags);
+ e.port = htons(port);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -622,81 +567,6 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* Create hash:ip type of sets */
-
-static int
-hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- struct ip_set_hash *h;
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h)
- + sizeof(struct ip_set_hash_nets)
- * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipportnet4_tvariant
- : &hash_ipportnet6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_ipportnet4_gc_init(set);
- else
- hash_ipportnet6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
-}
-
static struct ip_set_type hash_ipportnet_type __read_mostly = {
.name = "hash:ip,port,net",
.protocol = IPSET_PROTOCOL,
@@ -713,6 +583,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -727,6 +598,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 4b677cf6bf7d..da740ceb56ae 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -20,12 +20,12 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 Range as input support for IPv4 added */
-#define REVISION_MAX 2 /* nomatch flag support added */
+/* 2 nomatch flag support added */
+#define REVISION_MAX 3 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -33,33 +33,46 @@ IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net");
/* Type specific function prefix */
-#define TYPE hash_net
+#define HTYPE hash_net
+#define IP_SET_HASH_WITH_NETS
-static bool
-hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
+/* IPv4 variants */
-#define hash_net4_same_set hash_net_same_set
-#define hash_net6_same_set hash_net_same_set
+/* Member elements */
+struct hash_net4_elem {
+ __be32 ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+};
-/* The type variant functions: IPv4 */
+struct hash_net4t_elem {
+ __be32 ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ unsigned long timeout;
+};
-/* Member elements without timeout */
-struct hash_net4_elem {
+struct hash_net4c_elem {
__be32 ip;
u16 padding0;
u8 nomatch;
u8 cidr;
+ struct ip_set_counter counter;
};
-/* Member elements with timeout support */
-struct hash_net4_telem {
+struct hash_net4ct_elem {
__be32 ip;
u16 padding0;
u8 nomatch;
u8 cidr;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_net4_data_equal(const struct hash_net4_elem *ip1,
const struct hash_net4_elem *ip2,
@@ -69,31 +82,22 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1,
ip1->cidr == ip2->cidr;
}
-static inline bool
-hash_net4_data_isnull(const struct hash_net4_elem *elem)
+static inline int
+hash_net4_do_data_match(const struct hash_net4_elem *elem)
{
- return elem->cidr == 0;
+ return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_net4_data_copy(struct hash_net4_elem *dst,
- const struct hash_net4_elem *src)
+hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags)
{
- dst->ip = src->ip;
- dst->cidr = src->cidr;
- dst->nomatch = src->nomatch;
+ elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
}
static inline void
-hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
-{
- dst->nomatch = flags & IPSET_FLAG_NOMATCH;
-}
-
-static inline int
-hash_net4_data_match(const struct hash_net4_elem *elem)
+hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
{
- return elem->nomatch ? -ENOTEMPTY : 1;
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -103,13 +107,6 @@ hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
elem->cidr = cidr;
}
-/* Zero CIDR values cannot be stored */
-static inline void
-hash_net4_data_zero_out(struct hash_net4_elem *elem)
-{
- elem->cidr = 0;
-}
-
static bool
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
{
@@ -126,106 +123,84 @@ nla_put_failure:
return 1;
}
-static bool
-hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
+static inline void
+hash_net4_data_next(struct hash_net4_elem *next,
+ const struct hash_net4_elem *d)
{
- const struct hash_net4_telem *tdata =
- (const struct hash_net4_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, tdata->cidr) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = d->ip;
}
-#define IP_SET_HASH_WITH_NETS
-
+#define MTYPE hash_net4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_net4_data_next(struct ip_set_hash *h,
- const struct hash_net4_elem *d)
-{
- h->next.ip = d->ip;
-}
+#include "ip_set_hash_gen.h"
static int
hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_net4_elem data = {
+ struct hash_net4_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
- if (data.cidr == 0)
+ if (e.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK;
+ e.cidr = HOST_MASK;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
- data.ip &= ip_set_netmask(data.cidr);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ e.ip &= ip_set_netmask(e.cidr);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_net4_elem data = { .cidr = HOST_MASK };
- u32 timeout = h->timeout;
+ struct hash_net4_elem e = { .cidr = HOST_MASK };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 ip = 0, ip_to, last;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR]) {
- data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (!data.cidr || data.cidr > HOST_MASK)
+ e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ if (!e.cidr || e.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
}
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
- data.ip = htonl(ip & ip_set_hostmask(data.cidr));
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ e.ip = htonl(ip & ip_set_hostmask(e.cidr));
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
ip_to = ip;
@@ -241,9 +216,9 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) {
- data.ip = htonl(ip);
- last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
- ret = adtfn(set, &data, timeout, flags);
+ e.ip = htonl(ip);
+ last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
@@ -253,34 +228,42 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
+struct hash_net6_elem {
+ union nf_inet_addr ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+};
-/* The type variant functions: IPv6 */
+struct hash_net6t_elem {
+ union nf_inet_addr ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ unsigned long timeout;
+};
-struct hash_net6_elem {
+struct hash_net6c_elem {
union nf_inet_addr ip;
u16 padding0;
u8 nomatch;
u8 cidr;
+ struct ip_set_counter counter;
};
-struct hash_net6_telem {
+struct hash_net6ct_elem {
union nf_inet_addr ip;
u16 padding0;
u8 nomatch;
u8 cidr;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_net6_data_equal(const struct hash_net6_elem *ip1,
const struct hash_net6_elem *ip2,
@@ -290,46 +273,22 @@ hash_net6_data_equal(const struct hash_net6_elem *ip1,
ip1->cidr == ip2->cidr;
}
-static inline bool
-hash_net6_data_isnull(const struct hash_net6_elem *elem)
-{
- return elem->cidr == 0;
-}
-
-static inline void
-hash_net6_data_copy(struct hash_net6_elem *dst,
- const struct hash_net6_elem *src)
-{
- dst->ip.in6 = src->ip.in6;
- dst->cidr = src->cidr;
- dst->nomatch = src->nomatch;
-}
-
-static inline void
-hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
-{
- dst->nomatch = flags & IPSET_FLAG_NOMATCH;
-}
-
static inline int
-hash_net6_data_match(const struct hash_net6_elem *elem)
+hash_net6_do_data_match(const struct hash_net6_elem *elem)
{
return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_net6_data_zero_out(struct hash_net6_elem *elem)
+hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags)
{
- elem->cidr = 0;
+ elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
}
static inline void
-ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
{
- ip->ip6[0] &= ip_set_netmask6(prefix)[0];
- ip->ip6[1] &= ip_set_netmask6(prefix)[1];
- ip->ip6[2] &= ip_set_netmask6(prefix)[2];
- ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -355,74 +314,60 @@ nla_put_failure:
return 1;
}
-static bool
-hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
+static inline void
+hash_net6_data_next(struct hash_net4_elem *next,
+ const struct hash_net6_elem *d)
{
- const struct hash_net6_telem *e =
- (const struct hash_net6_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, e->cidr) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#define MTYPE hash_net6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_net6_data_next(struct ip_set_hash *h,
- const struct hash_net6_elem *d)
-{
-}
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_net6_elem data = {
+ struct hash_net6_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
- if (data.cidr == 0)
+ if (e.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK;
+ e.cidr = HOST_MASK;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- ip6_netmask(&data.ip, data.cidr);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ ip6_netmask(&e.ip, e.cidr);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_net6_elem data = { .cidr = HOST_MASK };
- u32 timeout = h->timeout;
+ struct hash_net6_elem e = { .cidr = HOST_MASK };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
@@ -430,107 +375,29 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR])
- data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (!data.cidr || data.cidr > HOST_MASK)
+ if (!e.cidr || e.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- ip6_netmask(&data.ip, data.cidr);
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ ip6_netmask(&e.ip, e.cidr);
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
- }
-
- ret = adtfn(set, &data, timeout, flags);
-
- return ip_set_eexist(ret, flags) ? 0 : ret;
-}
-
-/* Create hash:ip type of sets */
-
-static int
-hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- struct ip_set_hash *h;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h)
- + sizeof(struct ip_set_hash_nets)
- * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ ret = adtfn(set, &e, &ext, &ext, flags);
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_net4_tvariant : &hash_net6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_net4_gc_init(set);
- else
- hash_net6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_net4_variant : &hash_net6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
static struct ip_set_type hash_net_type __read_mostly = {
@@ -548,6 +415,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -555,6 +423,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index 6ba985f1c96f..84ae6f6ce624 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2011-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -21,12 +21,12 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 nomatch flag support added */
-#define REVISION_MAX 2 /* /0 support added */
+/* 2 /0 support added */
+#define REVISION_MAX 3 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -127,17 +127,14 @@ iface_add(struct rb_root *root, const char **iface)
}
/* Type specific function prefix */
-#define TYPE hash_netiface
-
-static bool
-hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b);
-
-#define hash_netiface4_same_set hash_netiface_same_set
-#define hash_netiface6_same_set hash_netiface_same_set
+#define HTYPE hash_netiface
+#define IP_SET_HASH_WITH_NETS
+#define IP_SET_HASH_WITH_RBTREE
+#define IP_SET_HASH_WITH_MULTI
#define STREQ(a, b) (strcmp(a, b) == 0)
-/* The type variant functions: IPv4 */
+/* IPv4 variants */
struct hash_netiface4_elem_hashed {
__be32 ip;
@@ -147,8 +144,6 @@ struct hash_netiface4_elem_hashed {
u8 elem;
};
-#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
-
/* Member elements without timeout */
struct hash_netiface4_elem {
__be32 ip;
@@ -159,17 +154,39 @@ struct hash_netiface4_elem {
const char *iface;
};
-/* Member elements with timeout support */
-struct hash_netiface4_telem {
+struct hash_netiface4t_elem {
+ __be32 ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ unsigned long timeout;
+};
+
+struct hash_netiface4c_elem {
+ __be32 ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+};
+
+struct hash_netiface4ct_elem {
__be32 ip;
u8 physdev;
u8 cidr;
u8 nomatch;
u8 elem;
const char *iface;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
const struct hash_netiface4_elem *ip2,
@@ -182,29 +199,22 @@ hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
ip1->iface == ip2->iface;
}
-static inline bool
-hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
+static inline int
+hash_netiface4_do_data_match(const struct hash_netiface4_elem *elem)
{
- return elem->elem == 0;
+ return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
- const struct hash_netiface4_elem *src)
+hash_netiface4_data_set_flags(struct hash_netiface4_elem *elem, u32 flags)
{
- memcpy(dst, src, sizeof(*dst));
+ elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
}
static inline void
-hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
-{
- dst->nomatch = flags & IPSET_FLAG_NOMATCH;
-}
-
-static inline int
-hash_netiface4_data_match(const struct hash_netiface4_elem *elem)
+hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
{
- return elem->nomatch ? -ENOTEMPTY : 1;
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -214,12 +224,6 @@ hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
elem->cidr = cidr;
}
-static inline void
-hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
-{
- elem->elem = 0;
-}
-
static bool
hash_netiface4_data_list(struct sk_buff *skb,
const struct hash_netiface4_elem *data)
@@ -240,66 +244,40 @@ nla_put_failure:
return 1;
}
-static bool
-hash_netiface4_data_tlist(struct sk_buff *skb,
- const struct hash_netiface4_elem *data)
+static inline void
+hash_netiface4_data_next(struct hash_netiface4_elem *next,
+ const struct hash_netiface4_elem *d)
{
- const struct hash_netiface4_telem *tdata =
- (const struct hash_netiface4_telem *)data;
- u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
-
- if (data->nomatch)
- flags |= IPSET_FLAG_NOMATCH;
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
- nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = d->ip;
}
-#define IP_SET_HASH_WITH_NETS
-#define IP_SET_HASH_WITH_RBTREE
-#define IP_SET_HASH_WITH_MULTI
-
+#define MTYPE hash_netiface4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_netiface4_data_next(struct ip_set_hash *h,
- const struct hash_netiface4_elem *d)
-{
- h->next.ip = d->ip;
-}
+#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
+#include "ip_set_hash_gen.h"
static int
hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- struct ip_set_hash *h = set->data;
+ struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netiface4_elem data = {
+ struct hash_netiface4_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
int ret;
- if (data.cidr == 0)
+ if (e.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK;
+ e.cidr = HOST_MASK;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
- data.ip &= ip_set_netmask(data.cidr);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ e.ip &= ip_set_netmask(e.cidr);
#define IFACE(dir) (par->dir ? par->dir->name : NULL)
#define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
@@ -311,72 +289,69 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
if (!nf_bridge)
return -EINVAL;
- data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
- data.physdev = 1;
+ e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
+ e.physdev = 1;
#else
- data.iface = NULL;
+ e.iface = NULL;
#endif
} else
- data.iface = SRCDIR ? IFACE(in) : IFACE(out);
+ e.iface = SRCDIR ? IFACE(in) : IFACE(out);
- if (!data.iface)
+ if (!e.iface)
return -EINVAL;
- ret = iface_test(&h->rbtree, &data.iface);
+ ret = iface_test(&h->rbtree, &e.iface);
if (adt == IPSET_ADD) {
if (!ret) {
- ret = iface_add(&h->rbtree, &data.iface);
+ ret = iface_add(&h->rbtree, &e.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- struct ip_set_hash *h = set->data;
+ struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netiface4_elem data = { .cidr = HOST_MASK, .elem = 1 };
+ struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 ip = 0, ip_to, last;
- u32 timeout = h->timeout;
char iface[IFNAMSIZ];
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!tb[IPSET_ATTR_IFACE] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR]) {
- data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (data.cidr > HOST_MASK)
+ e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ if (e.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
}
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
-
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
- data.iface = iface;
- ret = iface_test(&h->rbtree, &data.iface);
+ e.iface = iface;
+ ret = iface_test(&h->rbtree, &e.iface);
if (adt == IPSET_ADD) {
if (!ret) {
- ret = iface_add(&h->rbtree, &data.iface);
+ ret = iface_add(&h->rbtree, &e.iface);
if (ret)
return ret;
}
@@ -386,14 +361,15 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV)
- data.physdev = 1;
- if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
- flags |= (cadt_flags << 16);
+ e.physdev = 1;
+ if (cadt_flags & IPSET_FLAG_NOMATCH)
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
- data.ip = htonl(ip & ip_set_hostmask(data.cidr));
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ e.ip = htonl(ip & ip_set_hostmask(e.cidr));
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
if (tb[IPSET_ATTR_IP_TO]) {
@@ -404,16 +380,15 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(ip, ip_to);
if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE;
- } else {
- ip_set_mask_from_to(ip, ip_to, data.cidr);
- }
+ } else
+ ip_set_mask_from_to(ip, ip_to, e.cidr);
if (retried)
ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) {
- data.ip = htonl(ip);
- last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
- ret = adtfn(set, &data, timeout, flags);
+ e.ip = htonl(ip);
+ last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -424,18 +399,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
-
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
-
-/* The type variant functions: IPv6 */
+/* IPv6 variants */
struct hash_netiface6_elem_hashed {
union nf_inet_addr ip;
@@ -445,8 +409,6 @@ struct hash_netiface6_elem_hashed {
u8 elem;
};
-#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
-
struct hash_netiface6_elem {
union nf_inet_addr ip;
u8 physdev;
@@ -456,16 +418,39 @@ struct hash_netiface6_elem {
const char *iface;
};
-struct hash_netiface6_telem {
+struct hash_netiface6t_elem {
+ union nf_inet_addr ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ unsigned long timeout;
+};
+
+struct hash_netiface6c_elem {
+ union nf_inet_addr ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+};
+
+struct hash_netiface6ct_elem {
union nf_inet_addr ip;
u8 physdev;
u8 cidr;
u8 nomatch;
u8 elem;
const char *iface;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
const struct hash_netiface6_elem *ip2,
@@ -478,44 +463,22 @@ hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
ip1->iface == ip2->iface;
}
-static inline bool
-hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
-{
- return elem->elem == 0;
-}
-
-static inline void
-hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
- const struct hash_netiface6_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
-{
- dst->nomatch = flags & IPSET_FLAG_NOMATCH;
-}
-
static inline int
-hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
+hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
{
return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
+hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
{
- elem->elem = 0;
+ elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
}
static inline void
-ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
{
- ip->ip6[0] &= ip_set_netmask6(prefix)[0];
- ip->ip6[1] &= ip_set_netmask6(prefix)[1];
- ip->ip6[2] &= ip_set_netmask6(prefix)[2];
- ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -545,63 +508,45 @@ nla_put_failure:
return 1;
}
-static bool
-hash_netiface6_data_tlist(struct sk_buff *skb,
- const struct hash_netiface6_elem *data)
+static inline void
+hash_netiface6_data_next(struct hash_netiface4_elem *next,
+ const struct hash_netiface6_elem *d)
{
- const struct hash_netiface6_telem *e =
- (const struct hash_netiface6_telem *)data;
- u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
-
- if (data->nomatch)
- flags |= IPSET_FLAG_NOMATCH;
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
- nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#undef HKEY_DATALEN
+#define MTYPE hash_netiface6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_netiface6_data_next(struct ip_set_hash *h,
- const struct hash_netiface6_elem *d)
-{
-}
+#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- struct ip_set_hash *h = set->data;
+ struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netiface6_elem data = {
+ struct hash_netiface6_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
int ret;
- if (data.cidr == 0)
+ if (e.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK;
+ e.cidr = HOST_MASK;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- ip6_netmask(&data.ip, data.cidr);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ ip6_netmask(&e.ip, e.cidr);
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
#ifdef CONFIG_BRIDGE_NETFILTER
@@ -609,44 +554,46 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
if (!nf_bridge)
return -EINVAL;
- data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
- data.physdev = 1;
+ e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
+ e.physdev = 1;
#else
- data.iface = NULL;
+ e.iface = NULL;
#endif
} else
- data.iface = SRCDIR ? IFACE(in) : IFACE(out);
+ e.iface = SRCDIR ? IFACE(in) : IFACE(out);
- if (!data.iface)
+ if (!e.iface)
return -EINVAL;
- ret = iface_test(&h->rbtree, &data.iface);
+ ret = iface_test(&h->rbtree, &e.iface);
if (adt == IPSET_ADD) {
if (!ret) {
- ret = iface_add(&h->rbtree, &data.iface);
+ ret = iface_add(&h->rbtree, &e.iface);
if (ret)
return ret;
}
} else if (!ret)
return ret;
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- struct ip_set_hash *h = set->data;
+ struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netiface6_elem data = { .cidr = HOST_MASK, .elem = 1 };
- u32 timeout = h->timeout;
+ struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
char iface[IFNAMSIZ];
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!tb[IPSET_ATTR_IFACE] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
@@ -654,28 +601,23 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR])
- data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (data.cidr > HOST_MASK)
+ e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ if (e.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- ip6_netmask(&data.ip, data.cidr);
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ ip6_netmask(&e.ip, e.cidr);
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
- data.iface = iface;
- ret = iface_test(&h->rbtree, &data.iface);
+ e.iface = iface;
+ ret = iface_test(&h->rbtree, &e.iface);
if (adt == IPSET_ADD) {
if (!ret) {
- ret = iface_add(&h->rbtree, &data.iface);
+ ret = iface_add(&h->rbtree, &e.iface);
if (ret)
return ret;
}
@@ -685,90 +627,15 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV)
- data.physdev = 1;
- if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
- flags |= (cadt_flags << 16);
+ e.physdev = 1;
+ if (cadt_flags & IPSET_FLAG_NOMATCH)
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
- ret = adtfn(set, &data, timeout, flags);
+ ret = adtfn(set, &e, &ext, &ext, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
-}
-
-/* Create hash:ip type of sets */
-
-static int
-hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- struct ip_set_hash *h;
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h)
- + sizeof(struct ip_set_hash_nets)
- * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
- h->ahash_max = AHASH_MAX_SIZE;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
- h->rbtree = RB_ROOT;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_netiface4_gc_init(set);
- else
- hash_netiface6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_netiface4_variant : &hash_netiface6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
static struct ip_set_type hash_netiface_type __read_mostly = {
@@ -788,6 +655,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -798,6 +666,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index af20c0c5ced2..9a0869853be5 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -20,14 +20,14 @@
#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 SCTP and UDPLITE support added */
/* 2 Range as input support for IPv4 added */
-#define REVISION_MAX 3 /* nomatch flag support added */
+/* 3 nomatch flag support added */
+#define REVISION_MAX 4 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -35,15 +35,9 @@ IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net,port");
/* Type specific function prefix */
-#define TYPE hash_netport
-
-static bool
-hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
-
-#define hash_netport4_same_set hash_netport_same_set
-#define hash_netport6_same_set hash_netport_same_set
-
-/* The type variant functions: IPv4 */
+#define HTYPE hash_netport
+#define IP_SET_HASH_WITH_PROTO
+#define IP_SET_HASH_WITH_NETS
/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
* However this way we have to store internally cidr - 1,
@@ -51,7 +45,9 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
*/
#define IP_SET_HASH_WITH_NETS_PACKED
-/* Member elements without timeout */
+/* IPv4 variants */
+
+/* Member elements */
struct hash_netport4_elem {
__be32 ip;
__be16 port;
@@ -60,8 +56,7 @@ struct hash_netport4_elem {
u8 nomatch:1;
};
-/* Member elements with timeout support */
-struct hash_netport4_telem {
+struct hash_netport4t_elem {
__be32 ip;
__be16 port;
u8 proto;
@@ -70,6 +65,27 @@ struct hash_netport4_telem {
unsigned long timeout;
};
+struct hash_netport4c_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+};
+
+struct hash_netport4ct_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
+/* Common functions */
+
static inline bool
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
const struct hash_netport4_elem *ip2,
@@ -81,33 +97,22 @@ hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
ip1->cidr == ip2->cidr;
}
-static inline bool
-hash_netport4_data_isnull(const struct hash_netport4_elem *elem)
+static inline int
+hash_netport4_do_data_match(const struct hash_netport4_elem *elem)
{
- return elem->proto == 0;
+ return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_netport4_data_copy(struct hash_netport4_elem *dst,
- const struct hash_netport4_elem *src)
+hash_netport4_data_set_flags(struct hash_netport4_elem *elem, u32 flags)
{
- dst->ip = src->ip;
- dst->port = src->port;
- dst->proto = src->proto;
- dst->cidr = src->cidr;
- dst->nomatch = src->nomatch;
+ elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
}
static inline void
-hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
+hash_netport4_data_reset_flags(struct hash_netport4_elem *elem, u8 *flags)
{
- dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
-}
-
-static inline int
-hash_netport4_data_match(const struct hash_netport4_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -117,12 +122,6 @@ hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
elem->cidr = cidr - 1;
}
-static inline void
-hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
-{
- elem->proto = 0;
-}
-
static bool
hash_netport4_data_list(struct sk_buff *skb,
const struct hash_netport4_elem *data)
@@ -142,77 +141,53 @@ nla_put_failure:
return 1;
}
-static bool
-hash_netport4_data_tlist(struct sk_buff *skb,
- const struct hash_netport4_elem *data)
+static inline void
+hash_netport4_data_next(struct hash_netport4_elem *next,
+ const struct hash_netport4_elem *d)
{
- const struct hash_netport4_telem *tdata =
- (const struct hash_netport4_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(tdata->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->ip = d->ip;
+ next->port = d->port;
}
-#define IP_SET_HASH_WITH_PROTO
-#define IP_SET_HASH_WITH_NETS
-
+#define MTYPE hash_netport4
#define PF 4
#define HOST_MASK 32
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_netport4_data_next(struct ip_set_hash *h,
- const struct hash_netport4_elem *d)
-{
- h->next.ip = d->ip;
- h->next.port = d->port;
-}
+#include "ip_set_hash_gen.h"
static int
hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netport4_elem data = {
+ struct hash_netport4_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK - 1;
+ e.cidr = HOST_MASK - 1;
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
- data.ip &= ip_set_netmask(data.cidr + 1);
+ ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ e.ip &= ip_set_netmask(e.cidr + 1);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netport4_elem data = { .cidr = HOST_MASK - 1 };
+ struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to, p = 0, ip = 0, ip_to, last;
- u32 timeout = h->timeout;
bool with_ports = false;
u8 cidr;
int ret;
@@ -221,13 +196,16 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
+ ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
@@ -235,47 +213,42 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!cidr || cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- data.cidr = cidr - 1;
+ e.cidr = cidr - 1;
}
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMP))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMP))
+ e.port = 0;
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
- data.ip = htonl(ip & ip_set_hostmask(data.cidr + 1));
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
- port = port_to = ntohs(data.port);
+ port = port_to = ntohs(e.port);
if (tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port_to < port)
@@ -289,21 +262,20 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(ip, ip_to);
if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE;
- } else {
- ip_set_mask_from_to(ip, ip_to, data.cidr + 1);
- }
+ } else
+ ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
if (retried)
ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) {
- data.ip = htonl(ip);
+ e.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &cidr);
- data.cidr = cidr - 1;
+ e.cidr = cidr - 1;
p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) {
- data.port = htons(p);
- ret = adtfn(set, &data, timeout, flags);
+ e.port = htons(p);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -315,36 +287,46 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-static bool
-hash_netport_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct ip_set_hash *x = a->data;
- const struct ip_set_hash *y = b->data;
+/* IPv6 variants */
- /* Resizing changes htable_bits, so we ignore it */
- return x->maxelem == y->maxelem &&
- x->timeout == y->timeout;
-}
+struct hash_netport6_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+};
-/* The type variant functions: IPv6 */
+struct hash_netport6t_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ unsigned long timeout;
+};
-struct hash_netport6_elem {
+struct hash_netport6c_elem {
union nf_inet_addr ip;
__be16 port;
u8 proto;
u8 cidr:7;
u8 nomatch:1;
+ struct ip_set_counter counter;
};
-struct hash_netport6_telem {
+struct hash_netport6ct_elem {
union nf_inet_addr ip;
__be16 port;
u8 proto;
u8 cidr:7;
u8 nomatch:1;
+ struct ip_set_counter counter;
unsigned long timeout;
};
+/* Common functions */
+
static inline bool
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
const struct hash_netport6_elem *ip2,
@@ -356,44 +338,22 @@ hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
ip1->cidr == ip2->cidr;
}
-static inline bool
-hash_netport6_data_isnull(const struct hash_netport6_elem *elem)
-{
- return elem->proto == 0;
-}
-
-static inline void
-hash_netport6_data_copy(struct hash_netport6_elem *dst,
- const struct hash_netport6_elem *src)
-{
- memcpy(dst, src, sizeof(*dst));
-}
-
-static inline void
-hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
-{
- dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
-}
-
static inline int
-hash_netport6_data_match(const struct hash_netport6_elem *elem)
+hash_netport6_do_data_match(const struct hash_netport6_elem *elem)
{
return elem->nomatch ? -ENOTEMPTY : 1;
}
static inline void
-hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
+hash_netport6_data_set_flags(struct hash_netport6_elem *elem, u32 flags)
{
- elem->proto = 0;
+ elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
}
static inline void
-ip6_netmask(union nf_inet_addr *ip, u8 prefix)
+hash_netport6_data_reset_flags(struct hash_netport6_elem *elem, u8 *flags)
{
- ip->ip6[0] &= ip_set_netmask6(prefix)[0];
- ip->ip6[1] &= ip_set_netmask6(prefix)[1];
- ip->ip6[2] &= ip_set_netmask6(prefix)[2];
- ip->ip6[3] &= ip_set_netmask6(prefix)[3];
+ swap(*flags, elem->nomatch);
}
static inline void
@@ -422,76 +382,57 @@ nla_put_failure:
return 1;
}
-static bool
-hash_netport6_data_tlist(struct sk_buff *skb,
- const struct hash_netport6_elem *data)
+static inline void
+hash_netport6_data_next(struct hash_netport4_elem *next,
+ const struct hash_netport6_elem *d)
{
- const struct hash_netport6_telem *e =
- (const struct hash_netport6_telem *)data;
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
- htonl(ip_set_timeout_get(e->timeout))) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
+ next->port = d->port;
}
+#undef MTYPE
#undef PF
#undef HOST_MASK
+#define MTYPE hash_netport6
#define PF 6
#define HOST_MASK 128
-#include <linux/netfilter/ipset/ip_set_ahash.h>
-
-static inline void
-hash_netport6_data_next(struct ip_set_hash *h,
- const struct hash_netport6_elem *d)
-{
- h->next.port = d->port;
-}
+#define IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
static int
hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netport6_elem data = {
+ struct hash_netport6_elem e = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
};
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
- data.cidr = HOST_MASK - 1;
+ e.cidr = HOST_MASK - 1;
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &data.port, &data.proto))
+ &e.port, &e.proto))
return -EINVAL;
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
- ip6_netmask(&data.ip, data.cidr + 1);
+ ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ ip6_netmask(&e.ip, e.cidr + 1);
- return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
+ return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
static int
hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
- const struct ip_set_hash *h = set->data;
+ const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netport6_elem data = { .cidr = HOST_MASK - 1 };
+ struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
- u32 timeout = h->timeout;
bool with_ports = false;
u8 cidr;
int ret;
@@ -500,7 +441,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
@@ -508,7 +451,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+ ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
@@ -516,45 +460,40 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!cidr || cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR;
- data.cidr = cidr - 1;
+ e.cidr = cidr - 1;
}
- ip6_netmask(&data.ip, data.cidr + 1);
+ ip6_netmask(&e.ip, e.cidr + 1);
if (tb[IPSET_ATTR_PORT])
- data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
+ e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
else
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_PROTO]) {
- data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(data.proto);
+ e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
+ with_ports = ip_set_proto_with_ports(e.proto);
- if (data.proto == 0)
+ if (e.proto == 0)
return -IPSET_ERR_INVALID_PROTO;
} else
return -IPSET_ERR_MISSING_PROTO;
- if (!(with_ports || data.proto == IPPROTO_ICMPV6))
- data.port = 0;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout(h->timeout))
- return -IPSET_ERR_TIMEOUT;
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
- }
+ if (!(with_ports || e.proto == IPPROTO_ICMPV6))
+ e.port = 0;
- if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
+ if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (cadt_flags << 16);
+ flags |= (IPSET_FLAG_NOMATCH << 16);
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &data, timeout, flags);
- return ip_set_eexist(ret, flags) ? 0 : ret;
+ ret = adtfn(set, &e, &ext, &ext, flags);
+ return ip_set_enomatch(ret, flags, adt) ? 1 :
+ ip_set_eexist(ret, flags) ? 0 : ret;
}
- port = ntohs(data.port);
+ port = ntohs(e.port);
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
swap(port, port_to);
@@ -562,8 +501,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (retried)
port = ntohs(h->next.port);
for (; port <= port_to; port++) {
- data.port = htons(port);
- ret = adtfn(set, &data, timeout, flags);
+ e.port = htons(port);
+ ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
@@ -573,80 +512,6 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* Create hash:ip type of sets */
-
-static int
-hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
-{
- struct ip_set_hash *h;
- u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
- u8 hbits;
- size_t hsize;
-
- if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
- return -IPSET_ERR_INVALID_FAMILY;
-
- if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_HASHSIZE]) {
- hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
- if (hashsize < IPSET_MIMINAL_HASHSIZE)
- hashsize = IPSET_MIMINAL_HASHSIZE;
- }
-
- if (tb[IPSET_ATTR_MAXELEM])
- maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
-
- h = kzalloc(sizeof(*h)
- + sizeof(struct ip_set_hash_nets)
- * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
- if (!h)
- return -ENOMEM;
-
- h->maxelem = maxelem;
- get_random_bytes(&h->initval, sizeof(h->initval));
- h->timeout = IPSET_NO_TIMEOUT;
-
- hbits = htable_bits(hashsize);
- hsize = htable_size(hbits);
- if (hsize == 0) {
- kfree(h);
- return -ENOMEM;
- }
- h->table = ip_set_alloc(hsize);
- if (!h->table) {
- kfree(h);
- return -ENOMEM;
- }
- h->table->htable_bits = hbits;
-
- set->data = h;
-
- if (tb[IPSET_ATTR_TIMEOUT]) {
- h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
-
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_netport4_tvariant : &hash_netport6_tvariant;
-
- if (set->family == NFPROTO_IPV4)
- hash_netport4_gc_init(set);
- else
- hash_netport6_gc_init(set);
- } else {
- set->variant = set->family == NFPROTO_IPV4
- ? &hash_netport4_variant : &hash_netport6_variant;
- }
-
- pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(h->table->htable_bits),
- h->table->htable_bits, h->maxelem, set->data, h->table);
-
- return 0;
-}
-
static struct ip_set_type hash_netport_type __read_mostly = {
.name = "hash:net,port",
.protocol = IPSET_PROTOCOL,
@@ -663,6 +528,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -674,6 +540,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 8371c2bac2e4..979b8c90e422 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+/* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -13,30 +13,53 @@
#include <linux/errno.h>
#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_list.h>
#define REVISION_MIN 0
-#define REVISION_MAX 0
+#define REVISION_MAX 1 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_list:set");
-/* Member elements without and with timeout */
+/* Member elements */
struct set_elem {
ip_set_id_t id;
};
-struct set_telem {
- ip_set_id_t id;
+struct sett_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
+};
+
+struct setc_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
+};
+
+struct setct_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
unsigned long timeout;
};
+struct set_adt_elem {
+ ip_set_id_t id;
+ ip_set_id_t refid;
+ int before;
+};
+
/* Type structure */
struct list_set {
size_t dsize; /* element size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
u32 size; /* size of set list array */
u32 timeout; /* timeout value */
struct timer_list gc; /* garbage collection */
@@ -49,175 +72,311 @@ list_set_elem(const struct list_set *map, u32 id)
return (struct set_elem *)((void *)map->members + id * map->dsize);
}
-static inline struct set_telem *
-list_set_telem(const struct list_set *map, u32 id)
-{
- return (struct set_telem *)((void *)map->members + id * map->dsize);
-}
+#define ext_timeout(e, m) \
+(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, m) \
+(struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER])
-static inline bool
-list_set_timeout(const struct list_set *map, u32 id)
+static int
+list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
+ const struct xt_action_param *par,
+ struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
{
- const struct set_telem *elem = list_set_telem(map, id);
+ struct list_set *map = set->data;
+ struct set_elem *e;
+ u32 i, cmdflags = opt->cmdflags;
+ int ret;
- return ip_set_timeout_test(elem->timeout);
+ /* Don't lookup sub-counters at all */
+ opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
+ if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
+ opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
+ for (i = 0; i < map->size; i++) {
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
+ return 0;
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
+ ret = ip_set_test(e->id, skb, par, opt);
+ if (ret > 0) {
+ if (SET_WITH_COUNTER(set))
+ ip_set_update_counter(ext_counter(e, map),
+ ext, &opt->ext,
+ cmdflags);
+ return ret;
+ }
+ }
+ return 0;
}
-static inline bool
-list_set_expired(const struct list_set *map, u32 id)
+static int
+list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
+ const struct xt_action_param *par,
+ struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
{
- const struct set_telem *elem = list_set_telem(map, id);
+ struct list_set *map = set->data;
+ struct set_elem *e;
+ u32 i;
+ int ret;
- return ip_set_timeout_expired(elem->timeout);
+ for (i = 0; i < map->size; i++) {
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
+ return 0;
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
+ ret = ip_set_add(e->id, skb, par, opt);
+ if (ret == 0)
+ return ret;
+ }
+ return 0;
}
-/* Set list without and with timeout */
-
static int
-list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
+list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
- enum ipset_adt adt, const struct ip_set_adt_opt *opt)
+ struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
{
struct list_set *map = set->data;
- struct set_elem *elem;
+ struct set_elem *e;
u32 i;
int ret;
for (i = 0; i < map->size; i++) {
- elem = list_set_elem(map, i);
- if (elem->id == IPSET_INVALID_ID)
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
return 0;
- if (with_timeout(map->timeout) && list_set_expired(map, i))
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
- switch (adt) {
- case IPSET_TEST:
- ret = ip_set_test(elem->id, skb, par, opt);
- if (ret > 0)
- return ret;
- break;
- case IPSET_ADD:
- ret = ip_set_add(elem->id, skb, par, opt);
- if (ret == 0)
- return ret;
- break;
- case IPSET_DEL:
- ret = ip_set_del(elem->id, skb, par, opt);
- if (ret == 0)
- return ret;
- break;
- default:
- break;
- }
+ ret = ip_set_del(e->id, skb, par, opt);
+ if (ret == 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int
+list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
+ const struct xt_action_param *par,
+ enum ipset_adt adt, struct ip_set_adt_opt *opt)
+{
+ struct list_set *map = set->data;
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
+
+ switch (adt) {
+ case IPSET_TEST:
+ return list_set_ktest(set, skb, par, opt, &ext);
+ case IPSET_ADD:
+ return list_set_kadd(set, skb, par, opt, &ext);
+ case IPSET_DEL:
+ return list_set_kdel(set, skb, par, opt, &ext);
+ default:
+ break;
}
return -EINVAL;
}
static bool
-id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
+id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
{
- const struct set_elem *elem;
+ const struct list_set *map = set->data;
+ const struct set_elem *e;
+
+ if (i >= map->size)
+ return 0;
- if (i < map->size) {
- elem = list_set_elem(map, i);
- return elem->id == id;
+ e = list_set_elem(map, i);
+ return !!(e->id == id &&
+ !(SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map))));
+}
+
+static int
+list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
+ const struct ip_set_ext *ext)
+{
+ struct list_set *map = set->data;
+ struct set_elem *e = list_set_elem(map, i);
+
+ if (e->id != IPSET_INVALID_ID) {
+ if (i == map->size - 1)
+ /* Last element replaced: e.g. add new,before,last */
+ ip_set_put_byindex(e->id);
+ else {
+ struct set_elem *x = list_set_elem(map, map->size - 1);
+
+ /* Last element pushed off */
+ if (x->id != IPSET_INVALID_ID)
+ ip_set_put_byindex(x->id);
+ memmove(list_set_elem(map, i + 1), e,
+ map->dsize * (map->size - (i + 1)));
+ }
}
+ e->id = d->id;
+ if (SET_WITH_TIMEOUT(set))
+ ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
+ if (SET_WITH_COUNTER(set))
+ ip_set_init_counter(ext_counter(e, map), ext);
return 0;
}
-static bool
-id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
+static int
+list_set_del(struct ip_set *set, u32 i)
{
- const struct set_elem *elem;
+ struct list_set *map = set->data;
+ struct set_elem *e = list_set_elem(map, i);
- if (i < map->size) {
- elem = list_set_elem(map, i);
- return !!(elem->id == id &&
- !(with_timeout(map->timeout) &&
- list_set_expired(map, i)));
- }
+ ip_set_put_byindex(e->id);
+
+ if (i < map->size - 1)
+ memmove(e, list_set_elem(map, i + 1),
+ map->dsize * (map->size - (i + 1)));
+ /* Last element */
+ e = list_set_elem(map, map->size - 1);
+ e->id = IPSET_INVALID_ID;
return 0;
}
static void
-list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
+set_cleanup_entries(struct ip_set *set)
{
+ struct list_set *map = set->data;
struct set_elem *e;
+ u32 i;
- for (; i < map->size; i++) {
+ for (i = 0; i < map->size; i++) {
e = list_set_elem(map, i);
- swap(e->id, id);
- if (e->id == IPSET_INVALID_ID)
- break;
+ if (e->id != IPSET_INVALID_ID &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ list_set_del(set, i);
}
}
-static void
-list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
- unsigned long timeout)
+static int
+list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
{
- struct set_telem *e;
+ struct list_set *map = set->data;
+ struct set_adt_elem *d = value;
+ struct set_elem *e;
+ u32 i;
+ int ret;
- for (; i < map->size; i++) {
- e = list_set_telem(map, i);
- swap(e->id, id);
- swap(e->timeout, timeout);
+ for (i = 0; i < map->size; i++) {
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
- break;
+ return 0;
+ else if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
+ else if (e->id != d->id)
+ continue;
+
+ if (d->before == 0)
+ return 1;
+ else if (d->before > 0)
+ ret = id_eq(set, i + 1, d->refid);
+ else
+ ret = i > 0 && id_eq(set, i - 1, d->refid);
+ return ret;
}
+ return 0;
}
+
static int
-list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
- unsigned long timeout)
+list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
{
- const struct set_elem *e = list_set_elem(map, i);
-
- if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
- /* Last element replaced: e.g. add new,before,last */
- ip_set_put_byindex(e->id);
- if (with_timeout(map->timeout))
- list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
- else
- list_elem_add(map, i, id);
+ struct list_set *map = set->data;
+ struct set_adt_elem *d = value;
+ struct set_elem *e;
+ bool flag_exist = flags & IPSET_FLAG_EXIST;
+ u32 i, ret = 0;
- return 0;
-}
+ /* Check already added element */
+ for (i = 0; i < map->size; i++) {
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
+ goto insert;
+ else if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
+ else if (e->id != d->id)
+ continue;
-static int
-list_set_del(struct list_set *map, u32 i)
-{
- struct set_elem *a = list_set_elem(map, i), *b;
-
- ip_set_put_byindex(a->id);
-
- for (; i < map->size - 1; i++) {
- b = list_set_elem(map, i + 1);
- a->id = b->id;
- if (with_timeout(map->timeout))
- ((struct set_telem *)a)->timeout =
- ((struct set_telem *)b)->timeout;
- a = b;
- if (a->id == IPSET_INVALID_ID)
- break;
+ if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
+ (d->before < 0 &&
+ (i == 0 || !id_eq(set, i - 1, d->refid))))
+ /* Before/after doesn't match */
+ return -IPSET_ERR_REF_EXIST;
+ if (!flag_exist)
+ /* Can't re-add */
+ return -IPSET_ERR_EXIST;
+ /* Update extensions */
+ if (SET_WITH_TIMEOUT(set))
+ ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
+ if (SET_WITH_COUNTER(set))
+ ip_set_init_counter(ext_counter(e, map), ext);
+ /* Set is already added to the list */
+ ip_set_put_byindex(d->id);
+ return 0;
}
- /* Last element */
- a->id = IPSET_INVALID_ID;
- return 0;
+insert:
+ ret = -IPSET_ERR_LIST_FULL;
+ for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
+ ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
+ : list_set_add(set, i, d, ext);
+ else if (e->id != d->refid)
+ continue;
+ else if (d->before > 0)
+ ret = list_set_add(set, i, d, ext);
+ else if (i + 1 < map->size)
+ ret = list_set_add(set, i + 1, d, ext);
+ }
+
+ return ret;
}
-static void
-cleanup_entries(struct list_set *map)
+static int
+list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+ struct ip_set_ext *mext, u32 flags)
{
- struct set_telem *e;
+ struct list_set *map = set->data;
+ struct set_adt_elem *d = value;
+ struct set_elem *e;
u32 i;
for (i = 0; i < map->size; i++) {
- e = list_set_telem(map, i);
- if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
- list_set_del(map, i);
+ e = list_set_elem(map, i);
+ if (e->id == IPSET_INVALID_ID)
+ return d->before != 0 ? -IPSET_ERR_REF_EXIST
+ : -IPSET_ERR_EXIST;
+ else if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
+ else if (e->id != d->id)
+ continue;
+
+ if (d->before == 0)
+ return list_set_del(set, i);
+ else if (d->before > 0) {
+ if (!id_eq(set, i + 1, d->refid))
+ return -IPSET_ERR_REF_EXIST;
+ return list_set_del(set, i);
+ } else if (i == 0 || !id_eq(set, i - 1, d->refid))
+ return -IPSET_ERR_REF_EXIST;
+ else
+ return list_set_del(set, i);
}
+ return -IPSET_ERR_EXIST;
}
static int
@@ -225,26 +384,27 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
struct list_set *map = set->data;
- bool with_timeout = with_timeout(map->timeout);
- bool flag_exist = flags & IPSET_FLAG_EXIST;
- int before = 0;
- u32 timeout = map->timeout;
- ip_set_id_t id, refid = IPSET_INVALID_ID;
- const struct set_elem *elem;
+ ipset_adtfn adtfn = set->variant->adt[adt];
+ struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
struct ip_set *s;
- u32 i;
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_NAME] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
- id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
- if (id == IPSET_INVALID_ID)
+ ret = ip_set_get_extensions(set, tb, &ext);
+ if (ret)
+ return ret;
+ e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
+ if (e.id == IPSET_INVALID_ID)
return -IPSET_ERR_NAME;
/* "Loop detection" */
if (s->type->features & IPSET_TYPE_NAME) {
@@ -254,115 +414,34 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- before = f & IPSET_FLAG_BEFORE;
+ e.before = f & IPSET_FLAG_BEFORE;
}
- if (before && !tb[IPSET_ATTR_NAMEREF]) {
+ if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
ret = -IPSET_ERR_BEFORE;
goto finish;
}
if (tb[IPSET_ATTR_NAMEREF]) {
- refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
- &s);
- if (refid == IPSET_INVALID_ID) {
+ e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
+ &s);
+ if (e.refid == IPSET_INVALID_ID) {
ret = -IPSET_ERR_NAMEREF;
goto finish;
}
- if (!before)
- before = -1;
- }
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!with_timeout) {
- ret = -IPSET_ERR_TIMEOUT;
- goto finish;
- }
- timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ if (!e.before)
+ e.before = -1;
}
- if (with_timeout && adt != IPSET_TEST)
- cleanup_entries(map);
+ if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
+ set_cleanup_entries(set);
- switch (adt) {
- case IPSET_TEST:
- for (i = 0; i < map->size && !ret; i++) {
- elem = list_set_elem(map, i);
- if (elem->id == IPSET_INVALID_ID ||
- (before != 0 && i + 1 >= map->size))
- break;
- else if (with_timeout && list_set_expired(map, i))
- continue;
- else if (before > 0 && elem->id == id)
- ret = id_eq_timeout(map, i + 1, refid);
- else if (before < 0 && elem->id == refid)
- ret = id_eq_timeout(map, i + 1, id);
- else if (before == 0 && elem->id == id)
- ret = 1;
- }
- break;
- case IPSET_ADD:
- for (i = 0; i < map->size; i++) {
- elem = list_set_elem(map, i);
- if (elem->id != id)
- continue;
- if (!(with_timeout && flag_exist)) {
- ret = -IPSET_ERR_EXIST;
- goto finish;
- } else {
- struct set_telem *e = list_set_telem(map, i);
-
- if ((before > 1 &&
- !id_eq(map, i + 1, refid)) ||
- (before < 0 &&
- (i == 0 || !id_eq(map, i - 1, refid)))) {
- ret = -IPSET_ERR_EXIST;
- goto finish;
- }
- e->timeout = ip_set_timeout_set(timeout);
- ip_set_put_byindex(id);
- ret = 0;
- goto finish;
- }
- }
- ret = -IPSET_ERR_LIST_FULL;
- for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
- elem = list_set_elem(map, i);
- if (elem->id == IPSET_INVALID_ID)
- ret = before != 0 ? -IPSET_ERR_REF_EXIST
- : list_set_add(map, i, id, timeout);
- else if (elem->id != refid)
- continue;
- else if (before > 0)
- ret = list_set_add(map, i, id, timeout);
- else if (i + 1 < map->size)
- ret = list_set_add(map, i + 1, id, timeout);
- }
- break;
- case IPSET_DEL:
- ret = -IPSET_ERR_EXIST;
- for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
- elem = list_set_elem(map, i);
- if (elem->id == IPSET_INVALID_ID) {
- ret = before != 0 ? -IPSET_ERR_REF_EXIST
- : -IPSET_ERR_EXIST;
- break;
- } else if (elem->id == id &&
- (before == 0 ||
- (before > 0 && id_eq(map, i + 1, refid))))
- ret = list_set_del(map, i);
- else if (elem->id == refid &&
- before < 0 && id_eq(map, i + 1, id))
- ret = list_set_del(map, i + 1);
- }
- break;
- default:
- break;
- }
+ ret = adtfn(set, &e, &ext, &ext, flags);
finish:
- if (refid != IPSET_INVALID_ID)
- ip_set_put_byindex(refid);
+ if (e.refid != IPSET_INVALID_ID)
+ ip_set_put_byindex(e.refid);
if (adt != IPSET_ADD || ret)
- ip_set_put_byindex(id);
+ ip_set_put_byindex(e.id);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -371,14 +450,14 @@ static void
list_set_flush(struct ip_set *set)
{
struct list_set *map = set->data;
- struct set_elem *elem;
+ struct set_elem *e;
u32 i;
for (i = 0; i < map->size; i++) {
- elem = list_set_elem(map, i);
- if (elem->id != IPSET_INVALID_ID) {
- ip_set_put_byindex(elem->id);
- elem->id = IPSET_INVALID_ID;
+ e = list_set_elem(map, i);
+ if (e->id != IPSET_INVALID_ID) {
+ ip_set_put_byindex(e->id);
+ e->id = IPSET_INVALID_ID;
}
}
}
@@ -388,7 +467,7 @@ list_set_destroy(struct ip_set *set)
{
struct list_set *map = set->data;
- if (with_timeout(map->timeout))
+ if (SET_WITH_TIMEOUT(set))
del_timer_sync(&map->gc);
list_set_flush(set);
kfree(map);
@@ -406,8 +485,11 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
if (!nested)
goto nla_put_failure;
if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
- (with_timeout(map->timeout) &&
+ (SET_WITH_TIMEOUT(set) &&
nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
+ (SET_WITH_COUNTER(set) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->size * map->dsize)))
@@ -436,7 +518,8 @@ list_set_list(const struct ip_set *set,
e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
goto finish;
- if (with_timeout(map->timeout) && list_set_expired(map, i))
+ if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
@@ -449,13 +532,14 @@ list_set_list(const struct ip_set *set,
if (nla_put_string(skb, IPSET_ATTR_NAME,
ip_set_name_byindex(e->id)))
goto nla_put_failure;
- if (with_timeout(map->timeout)) {
- const struct set_telem *te =
- (const struct set_telem *) e;
- __be32 to = htonl(ip_set_timeout_get(te->timeout));
- if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, to))
- goto nla_put_failure;
- }
+ if (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(e, map)))))
+ goto nla_put_failure;
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(e, map)))
+ goto nla_put_failure;
ipset_nest_end(skb, nested);
}
finish:
@@ -481,12 +565,18 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
const struct list_set *y = b->data;
return x->size == y->size &&
- x->timeout == y->timeout;
+ x->timeout == y->timeout &&
+ a->extensions == b->extensions;
}
-static const struct ip_set_type_variant list_set = {
+static const struct ip_set_type_variant set_variant = {
.kadt = list_set_kadt,
.uadt = list_set_uadt,
+ .adt = {
+ [IPSET_ADD] = list_set_uadd,
+ [IPSET_DEL] = list_set_udel,
+ [IPSET_TEST] = list_set_utest,
+ },
.destroy = list_set_destroy,
.flush = list_set_flush,
.head = list_set_head,
@@ -501,7 +591,7 @@ list_set_gc(unsigned long ul_set)
struct list_set *map = set->data;
write_lock_bh(&set->lock);
- cleanup_entries(map);
+ set_cleanup_entries(set);
write_unlock_bh(&set->lock);
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
@@ -509,20 +599,20 @@ list_set_gc(unsigned long ul_set)
}
static void
-list_set_gc_init(struct ip_set *set)
+list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
{
struct list_set *map = set->data;
init_timer(&map->gc);
map->gc.data = (unsigned long) set;
- map->gc.function = list_set_gc;
+ map->gc.function = gc;
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
/* Create list:set type of sets */
-static bool
+static struct list_set *
init_list_set(struct ip_set *set, u32 size, size_t dsize,
unsigned long timeout)
{
@@ -532,7 +622,7 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
if (!map)
- return false;
+ return NULL;
map->size = size;
map->dsize = dsize;
@@ -544,16 +634,19 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
e->id = IPSET_INVALID_ID;
}
- return true;
+ return map;
}
static int
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
- u32 size = IP_SET_LIST_DEFAULT_SIZE;
+ struct list_set *map;
+ u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0;
+ unsigned long timeout = 0;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+ !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_SIZE])
@@ -561,18 +654,46 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (size < IP_SET_LIST_MIN_SIZE)
size = IP_SET_LIST_MIN_SIZE;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- if (!init_list_set(set, size, sizeof(struct set_telem),
- ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (tb[IPSET_ATTR_TIMEOUT])
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->variant = &set_variant;
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map = init_list_set(set, size,
+ sizeof(struct setct_elem), timeout);
+ if (!map)
+ return -ENOMEM;
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct setct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct setct_elem, counter);
+ list_set_gc_init(set, list_set_gc);
+ } else {
+ map = init_list_set(set, size,
+ sizeof(struct setc_elem), 0);
+ if (!map)
+ return -ENOMEM;
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct setc_elem, counter);
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map = init_list_set(set, size,
+ sizeof(struct sett_elem), timeout);
+ if (!map)
return -ENOMEM;
-
- list_set_gc_init(set);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct sett_elem, timeout);
+ list_set_gc_init(set, list_set_gc);
} else {
- if (!init_list_set(set, size, sizeof(struct set_elem),
- IPSET_NO_TIMEOUT))
+ map = init_list_set(set, size, sizeof(struct set_elem), 0);
+ if (!map)
return -ENOMEM;
}
- set->variant = &list_set;
return 0;
}
@@ -588,6 +709,7 @@ static struct ip_set_type list_set_type __read_mostly = {
.create_policy = {
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
+ [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
[IPSET_ATTR_NAME] = { .type = NLA_STRING,
@@ -597,6 +719,8 @@ static struct ip_set_type list_set_type __read_mostly = {
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+ [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
+ [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c
index 0b779d7df881..dfd7b65b3d2a 100644
--- a/net/netfilter/ipvs/ip_vs_app.c
+++ b/net/netfilter/ipvs/ip_vs_app.c
@@ -58,6 +58,18 @@ static inline void ip_vs_app_put(struct ip_vs_app *app)
module_put(app->module);
}
+static void ip_vs_app_inc_destroy(struct ip_vs_app *inc)
+{
+ kfree(inc->timeout_table);
+ kfree(inc);
+}
+
+static void ip_vs_app_inc_rcu_free(struct rcu_head *head)
+{
+ struct ip_vs_app *inc = container_of(head, struct ip_vs_app, rcu_head);
+
+ ip_vs_app_inc_destroy(inc);
+}
/*
* Allocate/initialize app incarnation and register it in proto apps.
@@ -106,8 +118,7 @@ ip_vs_app_inc_new(struct net *net, struct ip_vs_app *app, __u16 proto,
return 0;
out:
- kfree(inc->timeout_table);
- kfree(inc);
+ ip_vs_app_inc_destroy(inc);
return ret;
}
@@ -131,8 +142,7 @@ ip_vs_app_inc_release(struct net *net, struct ip_vs_app *inc)
list_del(&inc->a_list);
- kfree(inc->timeout_table);
- kfree(inc);
+ call_rcu(&inc->rcu_head, ip_vs_app_inc_rcu_free);
}
@@ -144,9 +154,9 @@ int ip_vs_app_inc_get(struct ip_vs_app *inc)
{
int result;
- atomic_inc(&inc->usecnt);
- if (unlikely((result = ip_vs_app_get(inc->app)) != 1))
- atomic_dec(&inc->usecnt);
+ result = ip_vs_app_get(inc->app);
+ if (result)
+ atomic_inc(&inc->usecnt);
return result;
}
@@ -156,8 +166,8 @@ int ip_vs_app_inc_get(struct ip_vs_app *inc)
*/
void ip_vs_app_inc_put(struct ip_vs_app *inc)
{
- ip_vs_app_put(inc->app);
atomic_dec(&inc->usecnt);
+ ip_vs_app_put(inc->app);
}
@@ -218,6 +228,7 @@ out_unlock:
/*
* ip_vs_app unregistration routine
* We are sure there are no app incarnations attached to services
+ * Caller should use synchronize_rcu() or rcu_barrier()
*/
void unregister_ip_vs_app(struct net *net, struct ip_vs_app *app)
{
@@ -341,14 +352,14 @@ static inline void vs_seq_update(struct ip_vs_conn *cp, struct ip_vs_seq *vseq,
unsigned int flag, __u32 seq, int diff)
{
/* spinlock is to keep updating cp->flags atomic */
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
if (!(cp->flags & flag) || after(seq, vseq->init_seq)) {
vseq->previous_delta = vseq->delta;
vseq->delta += diff;
vseq->init_seq = seq;
cp->flags |= flag;
}
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
}
static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff *skb,
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index 704e514e02ab..a083bda322b6 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -79,51 +79,21 @@ static unsigned int ip_vs_conn_rnd __read_mostly;
struct ip_vs_aligned_lock
{
- rwlock_t l;
+ spinlock_t l;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
/* lock array for conn table */
static struct ip_vs_aligned_lock
__ip_vs_conntbl_lock_array[CT_LOCKARRAY_SIZE] __cacheline_aligned;
-static inline void ct_read_lock(unsigned int key)
-{
- read_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_unlock(unsigned int key)
-{
- read_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_lock(unsigned int key)
-{
- write_lock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_write_unlock(unsigned int key)
-{
- write_unlock(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_lock_bh(unsigned int key)
-{
- read_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
-static inline void ct_read_unlock_bh(unsigned int key)
-{
- read_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
-}
-
static inline void ct_write_lock_bh(unsigned int key)
{
- write_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+ spin_lock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
static inline void ct_write_unlock_bh(unsigned int key)
{
- write_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
+ spin_unlock_bh(&__ip_vs_conntbl_lock_array[key&CT_LOCKARRAY_MASK].l);
}
@@ -197,13 +167,13 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
/* Hash by protocol, client address and port */
hash = ip_vs_conn_hashkey_conn(cp);
- ct_write_lock(hash);
+ ct_write_lock_bh(hash);
spin_lock(&cp->lock);
if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
- hlist_add_head(&cp->c_list, &ip_vs_conn_tab[hash]);
cp->flags |= IP_VS_CONN_F_HASHED;
atomic_inc(&cp->refcnt);
+ hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]);
ret = 1;
} else {
pr_err("%s(): request for already hashed, called from %pF\n",
@@ -212,7 +182,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
}
spin_unlock(&cp->lock);
- ct_write_unlock(hash);
+ ct_write_unlock_bh(hash);
return ret;
}
@@ -220,7 +190,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
/*
* UNhashes ip_vs_conn from ip_vs_conn_tab.
- * returns bool success.
+ * returns bool success. Caller should hold conn reference.
*/
static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
{
@@ -230,11 +200,11 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
/* unhash it and decrease its reference counter */
hash = ip_vs_conn_hashkey_conn(cp);
- ct_write_lock(hash);
+ ct_write_lock_bh(hash);
spin_lock(&cp->lock);
if (cp->flags & IP_VS_CONN_F_HASHED) {
- hlist_del(&cp->c_list);
+ hlist_del_rcu(&cp->c_list);
cp->flags &= ~IP_VS_CONN_F_HASHED;
atomic_dec(&cp->refcnt);
ret = 1;
@@ -242,7 +212,37 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
ret = 0;
spin_unlock(&cp->lock);
- ct_write_unlock(hash);
+ ct_write_unlock_bh(hash);
+
+ return ret;
+}
+
+/* Try to unlink ip_vs_conn from ip_vs_conn_tab.
+ * returns bool success.
+ */
+static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp)
+{
+ unsigned int hash;
+ bool ret;
+
+ hash = ip_vs_conn_hashkey_conn(cp);
+
+ ct_write_lock_bh(hash);
+ spin_lock(&cp->lock);
+
+ if (cp->flags & IP_VS_CONN_F_HASHED) {
+ ret = false;
+ /* Decrease refcnt and unlink conn only if we are last user */
+ if (atomic_cmpxchg(&cp->refcnt, 1, 0) == 1) {
+ hlist_del_rcu(&cp->c_list);
+ cp->flags &= ~IP_VS_CONN_F_HASHED;
+ ret = true;
+ }
+ } else
+ ret = atomic_read(&cp->refcnt) ? false : true;
+
+ spin_unlock(&cp->lock);
+ ct_write_unlock_bh(hash);
return ret;
}
@@ -262,24 +262,25 @@ __ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
hash = ip_vs_conn_hashkey_param(p, false);
- ct_read_lock(hash);
+ rcu_read_lock();
- hlist_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == p->af &&
- p->cport == cp->cport && p->vport == cp->vport &&
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
+ if (p->cport == cp->cport && p->vport == cp->vport &&
+ cp->af == p->af &&
ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) &&
((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
p->protocol == cp->protocol &&
ip_vs_conn_net_eq(cp, p->net)) {
+ if (!__ip_vs_conn_get(cp))
+ continue;
/* HIT */
- atomic_inc(&cp->refcnt);
- ct_read_unlock(hash);
+ rcu_read_unlock();
return cp;
}
}
- ct_read_unlock(hash);
+ rcu_read_unlock();
return NULL;
}
@@ -346,14 +347,16 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
hash = ip_vs_conn_hashkey_param(p, false);
- ct_read_lock(hash);
+ rcu_read_lock();
- hlist_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (!ip_vs_conn_net_eq(cp, p->net))
- continue;
- if (p->pe_data && p->pe->ct_match) {
- if (p->pe == cp->pe && p->pe->ct_match(p, cp))
- goto out;
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
+ if (unlikely(p->pe_data && p->pe->ct_match)) {
+ if (!ip_vs_conn_net_eq(cp, p->net))
+ continue;
+ if (p->pe == cp->pe && p->pe->ct_match(p, cp)) {
+ if (__ip_vs_conn_get(cp))
+ goto out;
+ }
continue;
}
@@ -363,17 +366,18 @@ struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
* p->vaddr is a fwmark */
ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC :
p->af, p->vaddr, &cp->vaddr) &&
- p->cport == cp->cport && p->vport == cp->vport &&
+ p->vport == cp->vport && p->cport == cp->cport &&
cp->flags & IP_VS_CONN_F_TEMPLATE &&
- p->protocol == cp->protocol)
- goto out;
+ p->protocol == cp->protocol &&
+ ip_vs_conn_net_eq(cp, p->net)) {
+ if (__ip_vs_conn_get(cp))
+ goto out;
+ }
}
cp = NULL;
out:
- if (cp)
- atomic_inc(&cp->refcnt);
- ct_read_unlock(hash);
+ rcu_read_unlock();
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
ip_vs_proto_name(p->protocol),
@@ -398,23 +402,24 @@ struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
*/
hash = ip_vs_conn_hashkey_param(p, true);
- ct_read_lock(hash);
+ rcu_read_lock();
- hlist_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == p->af &&
- p->vport == cp->cport && p->cport == cp->dport &&
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
+ if (p->vport == cp->cport && p->cport == cp->dport &&
+ cp->af == p->af &&
ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) &&
ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) &&
p->protocol == cp->protocol &&
ip_vs_conn_net_eq(cp, p->net)) {
+ if (!__ip_vs_conn_get(cp))
+ continue;
/* HIT */
- atomic_inc(&cp->refcnt);
ret = cp;
break;
}
}
- ct_read_unlock(hash);
+ rcu_read_unlock();
IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
ip_vs_proto_name(p->protocol),
@@ -457,13 +462,13 @@ void ip_vs_conn_put(struct ip_vs_conn *cp)
void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
{
if (ip_vs_conn_unhash(cp)) {
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
atomic_dec(&ip_vs_conn_no_cport_cnt);
cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
cp->cport = cport;
}
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
/* hash on new dport */
ip_vs_conn_hash(cp);
@@ -549,7 +554,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
return;
/* Increase the refcnt counter of the dest */
- atomic_inc(&dest->refcnt);
+ ip_vs_dest_hold(dest);
conn_flags = atomic_read(&dest->conn_flags);
if (cp->protocol != IPPROTO_UDP)
@@ -606,20 +611,22 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
* Check if there is a destination for the connection, if so
* bind the connection to the destination.
*/
-struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
+void ip_vs_try_bind_dest(struct ip_vs_conn *cp)
{
struct ip_vs_dest *dest;
+ rcu_read_lock();
dest = ip_vs_find_dest(ip_vs_conn_net(cp), cp->af, &cp->daddr,
cp->dport, &cp->vaddr, cp->vport,
cp->protocol, cp->fwmark, cp->flags);
if (dest) {
struct ip_vs_proto_data *pd;
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
if (cp->dest) {
- spin_unlock(&cp->lock);
- return dest;
+ spin_unlock_bh(&cp->lock);
+ rcu_read_unlock();
+ return;
}
/* Applications work depending on the forwarding method
@@ -628,7 +635,7 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
ip_vs_unbind_app(cp);
ip_vs_bind_dest(cp, dest);
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
/* Update its packet transmitter */
cp->packet_xmit = NULL;
@@ -643,7 +650,7 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp)
if (pd && atomic_read(&pd->appcnt))
ip_vs_bind_app(cp, pd->pp);
}
- return dest;
+ rcu_read_unlock();
}
@@ -695,12 +702,7 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
}
- /*
- * Simply decrease the refcnt of the dest, because the
- * dest will be either in service's destination list
- * or in the trash.
- */
- atomic_dec(&dest->refcnt);
+ ip_vs_dest_put(dest);
}
static int expire_quiescent_template(struct netns_ipvs *ipvs,
@@ -757,41 +759,36 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
* Simply decrease the refcnt of the template,
* don't restart its timer.
*/
- atomic_dec(&ct->refcnt);
+ __ip_vs_conn_put(ct);
return 0;
}
return 1;
}
+static void ip_vs_conn_rcu_free(struct rcu_head *head)
+{
+ struct ip_vs_conn *cp = container_of(head, struct ip_vs_conn,
+ rcu_head);
+
+ ip_vs_pe_put(cp->pe);
+ kfree(cp->pe_data);
+ kmem_cache_free(ip_vs_conn_cachep, cp);
+}
+
static void ip_vs_conn_expire(unsigned long data)
{
struct ip_vs_conn *cp = (struct ip_vs_conn *)data;
struct net *net = ip_vs_conn_net(cp);
struct netns_ipvs *ipvs = net_ipvs(net);
- cp->timeout = 60*HZ;
-
- /*
- * hey, I'm using it
- */
- atomic_inc(&cp->refcnt);
-
/*
* do I control anybody?
*/
if (atomic_read(&cp->n_control))
goto expire_later;
- /*
- * unhash it if it is hashed in the conn table
- */
- if (!ip_vs_conn_unhash(cp) && !(cp->flags & IP_VS_CONN_F_ONE_PACKET))
- goto expire_later;
-
- /*
- * refcnt==1 implies I'm the only one referrer
- */
- if (likely(atomic_read(&cp->refcnt) == 1)) {
+ /* Unlink conn if not referenced anymore */
+ if (likely(ip_vs_conn_unlink(cp))) {
/* delete the timer if it is activated by other users */
del_timer(&cp->timer);
@@ -810,38 +807,41 @@ static void ip_vs_conn_expire(unsigned long data)
ip_vs_conn_drop_conntrack(cp);
}
- ip_vs_pe_put(cp->pe);
- kfree(cp->pe_data);
if (unlikely(cp->app != NULL))
ip_vs_unbind_app(cp);
ip_vs_unbind_dest(cp);
if (cp->flags & IP_VS_CONN_F_NO_CPORT)
atomic_dec(&ip_vs_conn_no_cport_cnt);
+ call_rcu(&cp->rcu_head, ip_vs_conn_rcu_free);
atomic_dec(&ipvs->conn_count);
-
- kmem_cache_free(ip_vs_conn_cachep, cp);
return;
}
- /* hash it back to the table */
- ip_vs_conn_hash(cp);
-
expire_later:
- IP_VS_DBG(7, "delayed: conn->refcnt-1=%d conn->n_control=%d\n",
- atomic_read(&cp->refcnt)-1,
+ IP_VS_DBG(7, "delayed: conn->refcnt=%d conn->n_control=%d\n",
+ atomic_read(&cp->refcnt),
atomic_read(&cp->n_control));
+ atomic_inc(&cp->refcnt);
+ cp->timeout = 60*HZ;
+
if (ipvs->sync_state & IP_VS_STATE_MASTER)
ip_vs_sync_conn(net, cp, sysctl_sync_threshold(ipvs));
ip_vs_conn_put(cp);
}
-
+/* Modify timer, so that it expires as soon as possible.
+ * Can be called without reference only if under RCU lock.
+ */
void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
{
- if (del_timer(&cp->timer))
- mod_timer(&cp->timer, jiffies);
+ /* Using mod_timer_pending will ensure the timer is not
+ * modified after the final del_timer in ip_vs_conn_expire.
+ */
+ if (timer_pending(&cp->timer) &&
+ time_after(cp->timer.expires, jiffies))
+ mod_timer_pending(&cp->timer, jiffies);
}
@@ -858,7 +858,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(p->net,
p->protocol);
- cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
+ cp = kmem_cache_alloc(ip_vs_conn_cachep, GFP_ATOMIC);
if (cp == NULL) {
IP_VS_ERR_RL("%s(): no memory\n", __func__);
return NULL;
@@ -869,13 +869,13 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
ip_vs_conn_net_set(cp, p->net);
cp->af = p->af;
cp->protocol = p->protocol;
- ip_vs_addr_copy(p->af, &cp->caddr, p->caddr);
+ ip_vs_addr_set(p->af, &cp->caddr, p->caddr);
cp->cport = p->cport;
- ip_vs_addr_copy(p->af, &cp->vaddr, p->vaddr);
+ ip_vs_addr_set(p->af, &cp->vaddr, p->vaddr);
cp->vport = p->vport;
/* proto should only be IPPROTO_IP if d_addr is a fwmark */
- ip_vs_addr_copy(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
- &cp->daddr, daddr);
+ ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
+ &cp->daddr, daddr);
cp->dport = dport;
cp->flags = flags;
cp->fwmark = fwmark;
@@ -884,6 +884,10 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
cp->pe = p->pe;
cp->pe_data = p->pe_data;
cp->pe_data_len = p->pe_data_len;
+ } else {
+ cp->pe = NULL;
+ cp->pe_data = NULL;
+ cp->pe_data_len = 0;
}
spin_lock_init(&cp->lock);
@@ -894,18 +898,28 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
*/
atomic_set(&cp->refcnt, 1);
+ cp->control = NULL;
atomic_set(&cp->n_control, 0);
atomic_set(&cp->in_pkts, 0);
+ cp->packet_xmit = NULL;
+ cp->app = NULL;
+ cp->app_data = NULL;
+ /* reset struct ip_vs_seq */
+ cp->in_seq.delta = 0;
+ cp->out_seq.delta = 0;
+
atomic_inc(&ipvs->conn_count);
if (flags & IP_VS_CONN_F_NO_CPORT)
atomic_inc(&ip_vs_conn_no_cport_cnt);
/* Bind the connection with a destination server */
+ cp->dest = NULL;
ip_vs_bind_dest(cp, dest);
/* Set its state and timeout */
cp->state = 0;
+ cp->old_state = 0;
cp->timeout = 3*HZ;
cp->sync_endtime = jiffies & ~3UL;
@@ -952,24 +966,29 @@ static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
struct ip_vs_iter_state *iter = seq->private;
for (idx = 0; idx < ip_vs_conn_tab_size; idx++) {
- ct_read_lock_bh(idx);
- hlist_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
+ /* __ip_vs_conn_get() is not needed by
+ * ip_vs_conn_seq_show and ip_vs_conn_sync_seq_show
+ */
if (pos-- == 0) {
iter->l = &ip_vs_conn_tab[idx];
return cp;
}
}
- ct_read_unlock_bh(idx);
+ rcu_read_unlock();
+ rcu_read_lock();
}
return NULL;
}
static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
+ __acquires(RCU)
{
struct ip_vs_iter_state *iter = seq->private;
iter->l = NULL;
+ rcu_read_lock();
return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
}
@@ -977,6 +996,7 @@ static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct ip_vs_conn *cp = v;
struct ip_vs_iter_state *iter = seq->private;
+ struct hlist_node *e;
struct hlist_head *l = iter->l;
int idx;
@@ -985,31 +1005,27 @@ static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
return ip_vs_conn_array(seq, 0);
/* more on same hash chain? */
- if (cp->c_list.next)
- return hlist_entry(cp->c_list.next, struct ip_vs_conn, c_list);
+ e = rcu_dereference(hlist_next_rcu(&cp->c_list));
+ if (e)
+ return hlist_entry(e, struct ip_vs_conn, c_list);
idx = l - ip_vs_conn_tab;
- ct_read_unlock_bh(idx);
-
while (++idx < ip_vs_conn_tab_size) {
- ct_read_lock_bh(idx);
- hlist_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
iter->l = &ip_vs_conn_tab[idx];
return cp;
}
- ct_read_unlock_bh(idx);
+ rcu_read_unlock();
+ rcu_read_lock();
}
iter->l = NULL;
return NULL;
}
static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)
+ __releases(RCU)
{
- struct ip_vs_iter_state *iter = seq->private;
- struct hlist_head *l = iter->l;
-
- if (l)
- ct_read_unlock_bh(l - ip_vs_conn_tab);
+ rcu_read_unlock();
}
static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
@@ -1188,7 +1204,7 @@ static inline int todrop_entry(struct ip_vs_conn *cp)
void ip_vs_random_dropentry(struct net *net)
{
int idx;
- struct ip_vs_conn *cp;
+ struct ip_vs_conn *cp, *cp_c;
/*
* Randomly scan 1/32 of the whole table every second
@@ -1199,9 +1215,9 @@ void ip_vs_random_dropentry(struct net *net)
/*
* Lock is actually needed in this loop.
*/
- ct_write_lock_bh(hash);
+ rcu_read_lock();
- hlist_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
if (cp->flags & IP_VS_CONN_F_TEMPLATE)
/* connection template */
continue;
@@ -1228,12 +1244,15 @@ void ip_vs_random_dropentry(struct net *net)
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (cp->control) {
+ cp_c = cp->control;
+ /* cp->control is valid only with reference to cp */
+ if (cp_c && __ip_vs_conn_get(cp)) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(cp->control);
+ ip_vs_conn_expire_now(cp_c);
+ __ip_vs_conn_put(cp);
}
}
- ct_write_unlock_bh(hash);
+ rcu_read_unlock();
}
}
@@ -1244,7 +1263,7 @@ void ip_vs_random_dropentry(struct net *net)
static void ip_vs_conn_flush(struct net *net)
{
int idx;
- struct ip_vs_conn *cp;
+ struct ip_vs_conn *cp, *cp_c;
struct netns_ipvs *ipvs = net_ipvs(net);
flush_again:
@@ -1252,19 +1271,22 @@ flush_again:
/*
* Lock is actually needed in this loop.
*/
- ct_write_lock_bh(idx);
+ rcu_read_lock();
- hlist_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
+ hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
if (!ip_vs_conn_net_eq(cp, net))
continue;
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (cp->control) {
+ cp_c = cp->control;
+ /* cp->control is valid only with reference to cp */
+ if (cp_c && __ip_vs_conn_get(cp)) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(cp->control);
+ ip_vs_conn_expire_now(cp_c);
+ __ip_vs_conn_put(cp);
}
}
- ct_write_unlock_bh(idx);
+ rcu_read_unlock();
}
/* the counter may be not NULL, because maybe some conn entries
@@ -1331,7 +1353,7 @@ int __init ip_vs_conn_init(void)
INIT_HLIST_HEAD(&ip_vs_conn_tab[idx]);
for (idx = 0; idx < CT_LOCKARRAY_SIZE; idx++) {
- rwlock_init(&__ip_vs_conntbl_lock_array[idx].l);
+ spin_lock_init(&__ip_vs_conntbl_lock_array[idx].l);
}
/* calculate the random value for connection hash */
@@ -1342,6 +1364,8 @@ int __init ip_vs_conn_init(void)
void ip_vs_conn_cleanup(void)
{
+ /* Wait all ip_vs_conn_rcu_free() callbacks to complete */
+ rcu_barrier();
/* Release the empty cache */
kmem_cache_destroy(ip_vs_conn_cachep);
vfree(ip_vs_conn_tab);
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 61f49d241712..085b5880ab0d 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -69,10 +69,7 @@ EXPORT_SYMBOL(ip_vs_conn_put);
EXPORT_SYMBOL(ip_vs_get_debug_level);
#endif
-int ip_vs_net_id __read_mostly;
-#ifdef IP_VS_GENERIC_NETNS
-EXPORT_SYMBOL(ip_vs_net_id);
-#endif
+static int ip_vs_net_id __read_mostly;
/* netns cnt used for uniqueness */
static atomic_t ipvs_netns_cnt = ATOMIC_INIT(0);
@@ -206,7 +203,7 @@ ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
{
ip_vs_conn_fill_param(svc->net, svc->af, protocol, caddr, cport, vaddr,
vport, p);
- p->pe = svc->pe;
+ p->pe = rcu_dereference(svc->pe);
if (p->pe && p->pe->fill_param)
return p->pe->fill_param(p, skb);
@@ -238,7 +235,8 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
/* Mask saddr with the netmask to adjust template granularity */
#ifdef CONFIG_IP_VS_IPV6
if (svc->af == AF_INET6)
- ipv6_addr_prefix(&snet.in6, &iph->saddr.in6, svc->netmask);
+ ipv6_addr_prefix(&snet.in6, &iph->saddr.in6,
+ (__force __u32) svc->netmask);
else
#endif
snet.ip = iph->saddr.ip & svc->netmask;
@@ -299,12 +297,15 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
/* Check if a template already exists */
ct = ip_vs_ct_in_get(&param);
if (!ct || !ip_vs_check_template(ct)) {
+ struct ip_vs_scheduler *sched;
+
/*
* No template found or the dest of the connection
* template is not available.
* return *ignored=0 i.e. ICMP and NF_DROP
*/
- dest = svc->scheduler->schedule(svc, skb);
+ sched = rcu_dereference(svc->scheduler);
+ dest = sched->schedule(svc, skb);
if (!dest) {
IP_VS_DBG(1, "p-schedule: no dest found.\n");
kfree(param.pe_data);
@@ -394,6 +395,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
{
struct ip_vs_protocol *pp = pd->pp;
struct ip_vs_conn *cp = NULL;
+ struct ip_vs_scheduler *sched;
struct ip_vs_dest *dest;
__be16 _ports[2], *pptr;
unsigned int flags;
@@ -449,7 +451,8 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
return NULL;
}
- dest = svc->scheduler->schedule(svc, skb);
+ sched = rcu_dereference(svc->scheduler);
+ dest = sched->schedule(svc, skb);
if (dest == NULL) {
IP_VS_DBG(1, "Schedule: no dest found.\n");
return NULL;
@@ -507,7 +510,6 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
if (pptr == NULL) {
- ip_vs_service_put(svc);
return NF_DROP;
}
@@ -533,8 +535,6 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
IP_VS_CONN_F_ONE_PACKET : 0;
union nf_inet_addr daddr = { .all = { 0, 0, 0, 0 } };
- ip_vs_service_put(svc);
-
/* create a new connection entry */
IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__);
{
@@ -571,12 +571,8 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
* listed in the ipvs table), pass the packets, because it is
* not ipvs job to decide to drop the packets.
*/
- if ((svc->port == FTPPORT) && (pptr[1] != FTPPORT)) {
- ip_vs_service_put(svc);
+ if ((svc->port == FTPPORT) && (pptr[1] != FTPPORT))
return NF_ACCEPT;
- }
-
- ip_vs_service_put(svc);
/*
* Notify the client that the destination is unreachable, and
@@ -588,9 +584,9 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
#ifdef CONFIG_IP_VS_IPV6
if (svc->af == AF_INET6) {
if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
+ struct net *net_ = dev_net(skb_dst(skb)->dev);
- skb->dev = net->loopback_dev;
+ skb->dev = net_->loopback_dev;
}
icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
} else
@@ -643,8 +639,11 @@ static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
{
- int err = ip_defrag(skb, user);
+ int err;
+ local_bh_disable();
+ err = ip_defrag(skb, user);
+ local_bh_enable();
if (!err)
ip_send_check(ip_hdr(skb));
@@ -1164,9 +1163,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
sizeof(_ports), _ports, &iph);
if (pptr == NULL)
return NF_ACCEPT; /* Not for me */
- if (ip_vs_lookup_real_service(net, af, iph.protocol,
- &iph.saddr,
- pptr[0])) {
+ if (ip_vs_has_real_service(net, af, iph.protocol, &iph.saddr,
+ pptr[0])) {
/*
* Notify the real server: there is no
* existing entry if it is not RST
@@ -1181,9 +1179,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
iph.len)))) {
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- struct net *net =
- dev_net(skb_dst(skb)->dev);
-
if (!skb->dev)
skb->dev = net->loopback_dev;
icmpv6_send(skb,
@@ -1226,13 +1221,7 @@ ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- unsigned int verdict;
-
- /* Disable BH in LOCAL_OUT until all places are fixed */
- local_bh_disable();
- verdict = ip_vs_out(hooknum, skb, AF_INET);
- local_bh_enable();
- return verdict;
+ return ip_vs_out(hooknum, skb, AF_INET);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1259,13 +1248,7 @@ ip_vs_local_reply6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- unsigned int verdict;
-
- /* Disable BH in LOCAL_OUT until all places are fixed */
- local_bh_disable();
- verdict = ip_vs_out(hooknum, skb, AF_INET6);
- local_bh_enable();
- return verdict;
+ return ip_vs_out(hooknum, skb, AF_INET6);
}
#endif
@@ -1401,10 +1384,13 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
goto ignore_ipip;
/* Prefer the resulting PMTU */
if (dest) {
- spin_lock(&dest->dst_lock);
- if (dest->dst_cache)
- mtu = dst_mtu(dest->dst_cache);
- spin_unlock(&dest->dst_lock);
+ struct ip_vs_dest_dst *dest_dst;
+
+ rcu_read_lock();
+ dest_dst = rcu_dereference(dest->dest_dst);
+ if (dest_dst)
+ mtu = dst_mtu(dest_dst->dst_cache);
+ rcu_read_unlock();
}
if (mtu > 68 + sizeof(struct iphdr))
mtu -= sizeof(struct iphdr);
@@ -1720,13 +1706,7 @@ ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- unsigned int verdict;
-
- /* Disable BH in LOCAL_OUT until all places are fixed */
- local_bh_disable();
- verdict = ip_vs_in(hooknum, skb, AF_INET);
- local_bh_enable();
- return verdict;
+ return ip_vs_in(hooknum, skb, AF_INET);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1785,13 +1765,7 @@ ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- unsigned int verdict;
-
- /* Disable BH in LOCAL_OUT until all places are fixed */
- local_bh_disable();
- verdict = ip_vs_in(hooknum, skb, AF_INET6);
- local_bh_enable();
- return verdict;
+ return ip_vs_in(hooknum, skb, AF_INET6);
}
#endif
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 9e2d1cccd1eb..5b142fb16480 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -55,9 +55,6 @@
/* semaphore for IPVS sockopts. And, [gs]etsockopt may sleep. */
static DEFINE_MUTEX(__ip_vs_mutex);
-/* lock for service table */
-static DEFINE_RWLOCK(__ip_vs_svc_lock);
-
/* sysctl variables */
#ifdef CONFIG_IP_VS_DEBUG
@@ -71,7 +68,7 @@ int ip_vs_get_debug_level(void)
/* Protos */
-static void __ip_vs_del_service(struct ip_vs_service *svc);
+static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup);
#ifdef CONFIG_IP_VS_IPV6
@@ -257,9 +254,9 @@ ip_vs_use_count_dec(void)
#define IP_VS_SVC_TAB_MASK (IP_VS_SVC_TAB_SIZE - 1)
/* the service table hashed by <protocol, addr, port> */
-static struct list_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
+static struct hlist_head ip_vs_svc_table[IP_VS_SVC_TAB_SIZE];
/* the service table hashed by fwmark */
-static struct list_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
+static struct hlist_head ip_vs_svc_fwm_table[IP_VS_SVC_TAB_SIZE];
/*
@@ -271,16 +268,18 @@ ip_vs_svc_hashkey(struct net *net, int af, unsigned int proto,
{
register unsigned int porth = ntohs(port);
__be32 addr_fold = addr->ip;
+ __u32 ahash;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
addr_fold = addr->ip6[0]^addr->ip6[1]^
addr->ip6[2]^addr->ip6[3];
#endif
- addr_fold ^= ((size_t)net>>8);
+ ahash = ntohl(addr_fold);
+ ahash ^= ((size_t) net >> 8);
- return (proto^ntohl(addr_fold)^(porth>>IP_VS_SVC_TAB_BITS)^porth)
- & IP_VS_SVC_TAB_MASK;
+ return (proto ^ ahash ^ (porth >> IP_VS_SVC_TAB_BITS) ^ porth) &
+ IP_VS_SVC_TAB_MASK;
}
/*
@@ -312,13 +311,13 @@ static int ip_vs_svc_hash(struct ip_vs_service *svc)
*/
hash = ip_vs_svc_hashkey(svc->net, svc->af, svc->protocol,
&svc->addr, svc->port);
- list_add(&svc->s_list, &ip_vs_svc_table[hash]);
+ hlist_add_head_rcu(&svc->s_list, &ip_vs_svc_table[hash]);
} else {
/*
* Hash it by fwmark in svc_fwm_table
*/
hash = ip_vs_svc_fwm_hashkey(svc->net, svc->fwmark);
- list_add(&svc->f_list, &ip_vs_svc_fwm_table[hash]);
+ hlist_add_head_rcu(&svc->f_list, &ip_vs_svc_fwm_table[hash]);
}
svc->flags |= IP_VS_SVC_F_HASHED;
@@ -342,10 +341,10 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
if (svc->fwmark == 0) {
/* Remove it from the svc_table table */
- list_del(&svc->s_list);
+ hlist_del_rcu(&svc->s_list);
} else {
/* Remove it from the svc_fwm_table table */
- list_del(&svc->f_list);
+ hlist_del_rcu(&svc->f_list);
}
svc->flags &= ~IP_VS_SVC_F_HASHED;
@@ -367,7 +366,7 @@ __ip_vs_service_find(struct net *net, int af, __u16 protocol,
/* Check for "full" addressed entries */
hash = ip_vs_svc_hashkey(net, af, protocol, vaddr, vport);
- list_for_each_entry(svc, &ip_vs_svc_table[hash], s_list){
+ hlist_for_each_entry_rcu(svc, &ip_vs_svc_table[hash], s_list) {
if ((svc->af == af)
&& ip_vs_addr_equal(af, &svc->addr, vaddr)
&& (svc->port == vport)
@@ -394,7 +393,7 @@ __ip_vs_svc_fwm_find(struct net *net, int af, __u32 fwmark)
/* Check for fwmark addressed entries */
hash = ip_vs_svc_fwm_hashkey(net, fwmark);
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[hash], f_list) {
+ hlist_for_each_entry_rcu(svc, &ip_vs_svc_fwm_table[hash], f_list) {
if (svc->fwmark == fwmark && svc->af == af
&& net_eq(svc->net, net)) {
/* HIT */
@@ -405,15 +404,14 @@ __ip_vs_svc_fwm_find(struct net *net, int af, __u32 fwmark)
return NULL;
}
+/* Find service, called under RCU lock */
struct ip_vs_service *
-ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol,
- const union nf_inet_addr *vaddr, __be16 vport)
+ip_vs_service_find(struct net *net, int af, __u32 fwmark, __u16 protocol,
+ const union nf_inet_addr *vaddr, __be16 vport)
{
struct ip_vs_service *svc;
struct netns_ipvs *ipvs = net_ipvs(net);
- read_lock(&__ip_vs_svc_lock);
-
/*
* Check the table hashed by fwmark first
*/
@@ -449,10 +447,6 @@ ip_vs_service_get(struct net *net, int af, __u32 fwmark, __u16 protocol,
}
out:
- if (svc)
- atomic_inc(&svc->usecnt);
- read_unlock(&__ip_vs_svc_lock);
-
IP_VS_DBG_BUF(9, "lookup service: fwm %u %s %s:%u %s\n",
fwmark, ip_vs_proto_name(protocol),
IP_VS_DBG_ADDR(af, vaddr), ntohs(vport),
@@ -469,6 +463,13 @@ __ip_vs_bind_svc(struct ip_vs_dest *dest, struct ip_vs_service *svc)
dest->svc = svc;
}
+static void ip_vs_service_free(struct ip_vs_service *svc)
+{
+ if (svc->stats.cpustats)
+ free_percpu(svc->stats.cpustats);
+ kfree(svc);
+}
+
static void
__ip_vs_unbind_svc(struct ip_vs_dest *dest)
{
@@ -476,12 +477,11 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
dest->svc = NULL;
if (atomic_dec_and_test(&svc->refcnt)) {
- IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
+ IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
svc->fwmark,
IP_VS_DBG_ADDR(svc->af, &svc->addr),
- ntohs(svc->port), atomic_read(&svc->usecnt));
- free_percpu(svc->stats.cpustats);
- kfree(svc);
+ ntohs(svc->port));
+ ip_vs_service_free(svc);
}
}
@@ -506,17 +506,13 @@ static inline unsigned int ip_vs_rs_hashkey(int af,
& IP_VS_RTAB_MASK;
}
-/*
- * Hashes ip_vs_dest in rs_table by <proto,addr,port>.
- * should be called with locked tables.
- */
-static int ip_vs_rs_hash(struct netns_ipvs *ipvs, struct ip_vs_dest *dest)
+/* Hash ip_vs_dest in rs_table by <proto,addr,port>. */
+static void ip_vs_rs_hash(struct netns_ipvs *ipvs, struct ip_vs_dest *dest)
{
unsigned int hash;
- if (!list_empty(&dest->d_list)) {
- return 0;
- }
+ if (dest->in_rs_table)
+ return;
/*
* Hash by proto,addr,port,
@@ -524,64 +520,51 @@ static int ip_vs_rs_hash(struct netns_ipvs *ipvs, struct ip_vs_dest *dest)
*/
hash = ip_vs_rs_hashkey(dest->af, &dest->addr, dest->port);
- list_add(&dest->d_list, &ipvs->rs_table[hash]);
-
- return 1;
+ hlist_add_head_rcu(&dest->d_list, &ipvs->rs_table[hash]);
+ dest->in_rs_table = 1;
}
-/*
- * UNhashes ip_vs_dest from rs_table.
- * should be called with locked tables.
- */
-static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
+/* Unhash ip_vs_dest from rs_table. */
+static void ip_vs_rs_unhash(struct ip_vs_dest *dest)
{
/*
* Remove it from the rs_table table.
*/
- if (!list_empty(&dest->d_list)) {
- list_del_init(&dest->d_list);
+ if (dest->in_rs_table) {
+ hlist_del_rcu(&dest->d_list);
+ dest->in_rs_table = 0;
}
-
- return 1;
}
-/*
- * Lookup real service by <proto,addr,port> in the real service table.
- */
-struct ip_vs_dest *
-ip_vs_lookup_real_service(struct net *net, int af, __u16 protocol,
- const union nf_inet_addr *daddr,
- __be16 dport)
+/* Check if real service by <proto,addr,port> is present */
+bool ip_vs_has_real_service(struct net *net, int af, __u16 protocol,
+ const union nf_inet_addr *daddr, __be16 dport)
{
struct netns_ipvs *ipvs = net_ipvs(net);
unsigned int hash;
struct ip_vs_dest *dest;
- /*
- * Check for "full" addressed entries
- * Return the first found entry
- */
+ /* Check for "full" addressed entries */
hash = ip_vs_rs_hashkey(af, daddr, dport);
- read_lock(&ipvs->rs_lock);
- list_for_each_entry(dest, &ipvs->rs_table[hash], d_list) {
- if ((dest->af == af)
- && ip_vs_addr_equal(af, &dest->addr, daddr)
- && (dest->port == dport)
- && ((dest->protocol == protocol) ||
- dest->vfwmark)) {
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(dest, &ipvs->rs_table[hash], d_list) {
+ if (dest->port == dport &&
+ dest->af == af &&
+ ip_vs_addr_equal(af, &dest->addr, daddr) &&
+ (dest->protocol == protocol || dest->vfwmark)) {
/* HIT */
- read_unlock(&ipvs->rs_lock);
- return dest;
+ rcu_read_unlock();
+ return true;
}
}
- read_unlock(&ipvs->rs_lock);
+ rcu_read_unlock();
- return NULL;
+ return false;
}
-/*
- * Lookup destination by {addr,port} in the given service
+/* Lookup destination by {addr,port} in the given service
+ * Called under RCU lock.
*/
static struct ip_vs_dest *
ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
@@ -592,7 +575,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
/*
* Find the destination for the given service
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if ((dest->af == svc->af)
&& ip_vs_addr_equal(svc->af, &dest->addr, daddr)
&& (dest->port == dport)) {
@@ -606,13 +589,11 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
/*
* Find destination by {daddr,dport,vaddr,protocol}
- * Cretaed to be used in ip_vs_process_message() in
+ * Created to be used in ip_vs_process_message() in
* the backup synchronization daemon. It finds the
* destination to be bound to the received connection
* on the backup.
- *
- * ip_vs_lookup_real_service() looked promissing, but
- * seems not working as expected.
+ * Called under RCU lock, no refcnt is returned.
*/
struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af,
const union nf_inet_addr *daddr,
@@ -625,7 +606,7 @@ struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af,
struct ip_vs_service *svc;
__be16 port = dport;
- svc = ip_vs_service_get(net, af, fwmark, protocol, vaddr, vport);
+ svc = ip_vs_service_find(net, af, fwmark, protocol, vaddr, vport);
if (!svc)
return NULL;
if (fwmark && (flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ)
@@ -633,12 +614,31 @@ struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af,
dest = ip_vs_lookup_dest(svc, daddr, port);
if (!dest)
dest = ip_vs_lookup_dest(svc, daddr, port ^ dport);
- if (dest)
- atomic_inc(&dest->refcnt);
- ip_vs_service_put(svc);
return dest;
}
+void ip_vs_dest_dst_rcu_free(struct rcu_head *head)
+{
+ struct ip_vs_dest_dst *dest_dst = container_of(head,
+ struct ip_vs_dest_dst,
+ rcu_head);
+
+ dst_release(dest_dst->dst_cache);
+ kfree(dest_dst);
+}
+
+/* Release dest_dst and dst_cache for dest in user context */
+static void __ip_vs_dst_cache_reset(struct ip_vs_dest *dest)
+{
+ struct ip_vs_dest_dst *old;
+
+ old = rcu_dereference_protected(dest->dest_dst, 1);
+ if (old) {
+ RCU_INIT_POINTER(dest->dest_dst, NULL);
+ call_rcu(&old->rcu_head, ip_vs_dest_dst_rcu_free);
+ }
+}
+
/*
* Lookup dest by {svc,addr,port} in the destination trash.
* The destination trash is used to hold the destinations that are removed
@@ -653,19 +653,25 @@ static struct ip_vs_dest *
ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
__be16 dport)
{
- struct ip_vs_dest *dest, *nxt;
+ struct ip_vs_dest *dest;
struct netns_ipvs *ipvs = net_ipvs(svc->net);
/*
* Find the destination in trash
*/
- list_for_each_entry_safe(dest, nxt, &ipvs->dest_trash, n_list) {
+ spin_lock_bh(&ipvs->dest_trash_lock);
+ list_for_each_entry(dest, &ipvs->dest_trash, t_list) {
IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, "
"dest->refcnt=%d\n",
dest->vfwmark,
IP_VS_DBG_ADDR(svc->af, &dest->addr),
ntohs(dest->port),
atomic_read(&dest->refcnt));
+ /* We can not reuse dest while in grace period
+ * because conns still can use dest->svc
+ */
+ if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
+ continue;
if (dest->af == svc->af &&
ip_vs_addr_equal(svc->af, &dest->addr, daddr) &&
dest->port == dport &&
@@ -675,29 +681,27 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
(ip_vs_addr_equal(svc->af, &dest->vaddr, &svc->addr) &&
dest->vport == svc->port))) {
/* HIT */
- return dest;
- }
-
- /*
- * Try to purge the destination from trash if not referenced
- */
- if (atomic_read(&dest->refcnt) == 1) {
- IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u "
- "from trash\n",
- dest->vfwmark,
- IP_VS_DBG_ADDR(svc->af, &dest->addr),
- ntohs(dest->port));
- list_del(&dest->n_list);
- ip_vs_dst_reset(dest);
- __ip_vs_unbind_svc(dest);
- free_percpu(dest->stats.cpustats);
- kfree(dest);
+ list_del(&dest->t_list);
+ ip_vs_dest_hold(dest);
+ goto out;
}
}
- return NULL;
+ dest = NULL;
+
+out:
+ spin_unlock_bh(&ipvs->dest_trash_lock);
+
+ return dest;
}
+static void ip_vs_dest_free(struct ip_vs_dest *dest)
+{
+ __ip_vs_dst_cache_reset(dest);
+ __ip_vs_unbind_svc(dest);
+ free_percpu(dest->stats.cpustats);
+ kfree(dest);
+}
/*
* Clean up all the destinations in the trash
@@ -706,19 +710,18 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr,
* When the ip_vs_control_clearup is activated by ipvs module exit,
* the service tables must have been flushed and all the connections
* are expired, and the refcnt of each destination in the trash must
- * be 1, so we simply release them here.
+ * be 0, so we simply release them here.
*/
static void ip_vs_trash_cleanup(struct net *net)
{
struct ip_vs_dest *dest, *nxt;
struct netns_ipvs *ipvs = net_ipvs(net);
- list_for_each_entry_safe(dest, nxt, &ipvs->dest_trash, n_list) {
- list_del(&dest->n_list);
- ip_vs_dst_reset(dest);
- __ip_vs_unbind_svc(dest);
- free_percpu(dest->stats.cpustats);
- kfree(dest);
+ del_timer_sync(&ipvs->dest_trash_timer);
+ /* No need to use dest_trash_lock */
+ list_for_each_entry_safe(dest, nxt, &ipvs->dest_trash, t_list) {
+ list_del(&dest->t_list);
+ ip_vs_dest_free(dest);
}
}
@@ -768,6 +771,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
struct ip_vs_dest_user_kern *udest, int add)
{
struct netns_ipvs *ipvs = net_ipvs(svc->net);
+ struct ip_vs_scheduler *sched;
int conn_flags;
/* set the weight and the flags */
@@ -783,9 +787,7 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
* Put the real service in rs_table if not present.
* For now only for NAT!
*/
- write_lock_bh(&ipvs->rs_lock);
ip_vs_rs_hash(ipvs, dest);
- write_unlock_bh(&ipvs->rs_lock);
}
atomic_set(&dest->conn_flags, conn_flags);
@@ -809,27 +811,20 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
dest->l_threshold = udest->l_threshold;
spin_lock_bh(&dest->dst_lock);
- ip_vs_dst_reset(dest);
+ __ip_vs_dst_cache_reset(dest);
spin_unlock_bh(&dest->dst_lock);
- if (add)
- ip_vs_start_estimator(svc->net, &dest->stats);
-
- write_lock_bh(&__ip_vs_svc_lock);
-
- /* Wait until all other svc users go away */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
-
+ sched = rcu_dereference_protected(svc->scheduler, 1);
if (add) {
- list_add(&dest->n_list, &svc->destinations);
+ ip_vs_start_estimator(svc->net, &dest->stats);
+ list_add_rcu(&dest->n_list, &svc->destinations);
svc->num_dests++;
+ if (sched->add_dest)
+ sched->add_dest(svc, dest);
+ } else {
+ if (sched->upd_dest)
+ sched->upd_dest(svc, dest);
}
-
- /* call the update_service, because server weight may be changed */
- if (svc->scheduler->update_service)
- svc->scheduler->update_service(svc);
-
- write_unlock_bh(&__ip_vs_svc_lock);
}
@@ -881,7 +876,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
atomic_set(&dest->persistconns, 0);
atomic_set(&dest->refcnt, 1);
- INIT_LIST_HEAD(&dest->d_list);
+ INIT_HLIST_NODE(&dest->d_list);
spin_lock_init(&dest->dst_lock);
spin_lock_init(&dest->stats.lock);
__ip_vs_update_dest(svc, dest, udest, 1);
@@ -923,10 +918,10 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
- /*
- * Check if the dest already exists in the list
- */
+ /* We use function that requires RCU lock */
+ rcu_read_lock();
dest = ip_vs_lookup_dest(svc, &daddr, dport);
+ rcu_read_unlock();
if (dest != NULL) {
IP_VS_DBG(1, "%s(): dest already exists\n", __func__);
@@ -948,11 +943,6 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
ntohs(dest->vport));
- /*
- * Get the destination from the trash
- */
- list_del(&dest->n_list);
-
__ip_vs_update_dest(svc, dest, udest, 1);
ret = 0;
} else {
@@ -992,10 +982,10 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
ip_vs_addr_copy(svc->af, &daddr, &udest->addr);
- /*
- * Lookup the destination list
- */
+ /* We use function that requires RCU lock */
+ rcu_read_lock();
dest = ip_vs_lookup_dest(svc, &daddr, dport);
+ rcu_read_unlock();
if (dest == NULL) {
IP_VS_DBG(1, "%s(): dest doesn't exist\n", __func__);
@@ -1008,11 +998,21 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
return 0;
}
+static void ip_vs_dest_wait_readers(struct rcu_head *head)
+{
+ struct ip_vs_dest *dest = container_of(head, struct ip_vs_dest,
+ rcu_head);
+
+ /* End of grace period after unlinking */
+ clear_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
+}
+
/*
* Delete a destination (must be already unlinked from the service)
*/
-static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest)
+static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest,
+ bool cleanup)
{
struct netns_ipvs *ipvs = net_ipvs(net);
@@ -1021,38 +1021,24 @@ static void __ip_vs_del_dest(struct net *net, struct ip_vs_dest *dest)
/*
* Remove it from the d-linked list with the real services.
*/
- write_lock_bh(&ipvs->rs_lock);
ip_vs_rs_unhash(dest);
- write_unlock_bh(&ipvs->rs_lock);
- /*
- * Decrease the refcnt of the dest, and free the dest
- * if nobody refers to it (refcnt=0). Otherwise, throw
- * the destination into the trash.
- */
- if (atomic_dec_and_test(&dest->refcnt)) {
- IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u\n",
- dest->vfwmark,
- IP_VS_DBG_ADDR(dest->af, &dest->addr),
- ntohs(dest->port));
- ip_vs_dst_reset(dest);
- /* simply decrease svc->refcnt here, let the caller check
- and release the service if nobody refers to it.
- Only user context can release destination and service,
- and only one user context can update virtual service at a
- time, so the operation here is OK */
- atomic_dec(&dest->svc->refcnt);
- free_percpu(dest->stats.cpustats);
- kfree(dest);
- } else {
- IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, "
- "dest->refcnt=%d\n",
- IP_VS_DBG_ADDR(dest->af, &dest->addr),
- ntohs(dest->port),
- atomic_read(&dest->refcnt));
- list_add(&dest->n_list, &ipvs->dest_trash);
- atomic_inc(&dest->refcnt);
+ if (!cleanup) {
+ set_bit(IP_VS_DEST_STATE_REMOVING, &dest->state);
+ call_rcu(&dest->rcu_head, ip_vs_dest_wait_readers);
}
+
+ spin_lock_bh(&ipvs->dest_trash_lock);
+ IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
+ IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
+ atomic_read(&dest->refcnt));
+ if (list_empty(&ipvs->dest_trash) && !cleanup)
+ mod_timer(&ipvs->dest_trash_timer,
+ jiffies + IP_VS_DEST_TRASH_PERIOD);
+ /* dest lives in trash without reference */
+ list_add(&dest->t_list, &ipvs->dest_trash);
+ spin_unlock_bh(&ipvs->dest_trash_lock);
+ ip_vs_dest_put(dest);
}
@@ -1068,14 +1054,16 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc,
/*
* Remove it from the d-linked destination list.
*/
- list_del(&dest->n_list);
+ list_del_rcu(&dest->n_list);
svc->num_dests--;
- /*
- * Call the update_service function of its scheduler
- */
- if (svcupd && svc->scheduler->update_service)
- svc->scheduler->update_service(svc);
+ if (svcupd) {
+ struct ip_vs_scheduler *sched;
+
+ sched = rcu_dereference_protected(svc->scheduler, 1);
+ if (sched->del_dest)
+ sched->del_dest(svc, dest);
+ }
}
@@ -1090,37 +1078,56 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
EnterFunction(2);
+ /* We use function that requires RCU lock */
+ rcu_read_lock();
dest = ip_vs_lookup_dest(svc, &udest->addr, dport);
+ rcu_read_unlock();
if (dest == NULL) {
IP_VS_DBG(1, "%s(): destination not found!\n", __func__);
return -ENOENT;
}
- write_lock_bh(&__ip_vs_svc_lock);
-
- /*
- * Wait until all other svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
-
/*
* Unlink dest from the service
*/
__ip_vs_unlink_dest(svc, dest, 1);
- write_unlock_bh(&__ip_vs_svc_lock);
-
/*
* Delete the destination
*/
- __ip_vs_del_dest(svc->net, dest);
+ __ip_vs_del_dest(svc->net, dest, false);
LeaveFunction(2);
return 0;
}
+static void ip_vs_dest_trash_expire(unsigned long data)
+{
+ struct net *net = (struct net *) data;
+ struct netns_ipvs *ipvs = net_ipvs(net);
+ struct ip_vs_dest *dest, *next;
+
+ spin_lock(&ipvs->dest_trash_lock);
+ list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
+ /* Skip if dest is in grace period */
+ if (test_bit(IP_VS_DEST_STATE_REMOVING, &dest->state))
+ continue;
+ if (atomic_read(&dest->refcnt) > 0)
+ continue;
+ IP_VS_DBG_BUF(3, "Removing destination %u/%s:%u from trash\n",
+ dest->vfwmark,
+ IP_VS_DBG_ADDR(dest->svc->af, &dest->addr),
+ ntohs(dest->port));
+ list_del(&dest->t_list);
+ ip_vs_dest_free(dest);
+ }
+ if (!list_empty(&ipvs->dest_trash))
+ mod_timer(&ipvs->dest_trash_timer,
+ jiffies + IP_VS_DEST_TRASH_PERIOD);
+ spin_unlock(&ipvs->dest_trash_lock);
+}
/*
* Add a service into the service hash table
@@ -1157,9 +1164,13 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
}
#ifdef CONFIG_IP_VS_IPV6
- if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
- ret = -EINVAL;
- goto out_err;
+ if (u->af == AF_INET6) {
+ __u32 plen = (__force __u32) u->netmask;
+
+ if (plen < 1 || plen > 128) {
+ ret = -EINVAL;
+ goto out_err;
+ }
}
#endif
@@ -1176,7 +1187,6 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
}
/* I'm the first user of the service */
- atomic_set(&svc->usecnt, 0);
atomic_set(&svc->refcnt, 0);
svc->af = u->af;
@@ -1190,7 +1200,7 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
svc->net = net;
INIT_LIST_HEAD(&svc->destinations);
- rwlock_init(&svc->sched_lock);
+ spin_lock_init(&svc->sched_lock);
spin_lock_init(&svc->stats.lock);
/* Bind the scheduler */
@@ -1200,7 +1210,7 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
sched = NULL;
/* Bind the ct retriever */
- ip_vs_bind_pe(svc, pe);
+ RCU_INIT_POINTER(svc->pe, pe);
pe = NULL;
/* Update the virtual service counters */
@@ -1216,9 +1226,7 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
ipvs->num_services++;
/* Hash the service into the service table */
- write_lock_bh(&__ip_vs_svc_lock);
ip_vs_svc_hash(svc);
- write_unlock_bh(&__ip_vs_svc_lock);
*svc_p = svc;
/* Now there is a service - full throttle */
@@ -1228,15 +1236,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
out_err:
if (svc != NULL) {
- ip_vs_unbind_scheduler(svc);
- if (svc->inc) {
- local_bh_disable();
- ip_vs_app_inc_put(svc->inc);
- local_bh_enable();
- }
- if (svc->stats.cpustats)
- free_percpu(svc->stats.cpustats);
- kfree(svc);
+ ip_vs_unbind_scheduler(svc, sched);
+ ip_vs_service_free(svc);
}
ip_vs_scheduler_put(sched);
ip_vs_pe_put(pe);
@@ -1280,18 +1281,27 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
}
#ifdef CONFIG_IP_VS_IPV6
- if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
- ret = -EINVAL;
- goto out;
+ if (u->af == AF_INET6) {
+ __u32 plen = (__force __u32) u->netmask;
+
+ if (plen < 1 || plen > 128) {
+ ret = -EINVAL;
+ goto out;
+ }
}
#endif
- write_lock_bh(&__ip_vs_svc_lock);
-
- /*
- * Wait until all other svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
+ old_sched = rcu_dereference_protected(svc->scheduler, 1);
+ if (sched != old_sched) {
+ /* Bind the new scheduler */
+ ret = ip_vs_bind_scheduler(svc, sched);
+ if (ret) {
+ old_sched = sched;
+ goto out;
+ }
+ /* Unbind the old scheduler on success */
+ ip_vs_unbind_scheduler(svc, old_sched);
+ }
/*
* Set the flags and timeout value
@@ -1300,57 +1310,30 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
svc->timeout = u->timeout * HZ;
svc->netmask = u->netmask;
- old_sched = svc->scheduler;
- if (sched != old_sched) {
- /*
- * Unbind the old scheduler
- */
- if ((ret = ip_vs_unbind_scheduler(svc))) {
- old_sched = sched;
- goto out_unlock;
- }
+ old_pe = rcu_dereference_protected(svc->pe, 1);
+ if (pe != old_pe)
+ rcu_assign_pointer(svc->pe, pe);
- /*
- * Bind the new scheduler
- */
- if ((ret = ip_vs_bind_scheduler(svc, sched))) {
- /*
- * If ip_vs_bind_scheduler fails, restore the old
- * scheduler.
- * The main reason of failure is out of memory.
- *
- * The question is if the old scheduler can be
- * restored all the time. TODO: if it cannot be
- * restored some time, we must delete the service,
- * otherwise the system may crash.
- */
- ip_vs_bind_scheduler(svc, old_sched);
- old_sched = sched;
- goto out_unlock;
- }
- }
-
- old_pe = svc->pe;
- if (pe != old_pe) {
- ip_vs_unbind_pe(svc);
- ip_vs_bind_pe(svc, pe);
- }
-
-out_unlock:
- write_unlock_bh(&__ip_vs_svc_lock);
out:
ip_vs_scheduler_put(old_sched);
ip_vs_pe_put(old_pe);
return ret;
}
+static void ip_vs_service_rcu_free(struct rcu_head *head)
+{
+ struct ip_vs_service *svc;
+
+ svc = container_of(head, struct ip_vs_service, rcu_head);
+ ip_vs_service_free(svc);
+}
/*
* Delete a service from the service list
* - The service must be unlinked, unlocked and not referenced!
* - We are called under _bh lock
*/
-static void __ip_vs_del_service(struct ip_vs_service *svc)
+static void __ip_vs_del_service(struct ip_vs_service *svc, bool cleanup)
{
struct ip_vs_dest *dest, *nxt;
struct ip_vs_scheduler *old_sched;
@@ -1366,27 +1349,20 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
ip_vs_stop_estimator(svc->net, &svc->stats);
/* Unbind scheduler */
- old_sched = svc->scheduler;
- ip_vs_unbind_scheduler(svc);
+ old_sched = rcu_dereference_protected(svc->scheduler, 1);
+ ip_vs_unbind_scheduler(svc, old_sched);
ip_vs_scheduler_put(old_sched);
- /* Unbind persistence engine */
- old_pe = svc->pe;
- ip_vs_unbind_pe(svc);
+ /* Unbind persistence engine, keep svc->pe */
+ old_pe = rcu_dereference_protected(svc->pe, 1);
ip_vs_pe_put(old_pe);
- /* Unbind app inc */
- if (svc->inc) {
- ip_vs_app_inc_put(svc->inc);
- svc->inc = NULL;
- }
-
/*
* Unlink the whole destination list
*/
list_for_each_entry_safe(dest, nxt, &svc->destinations, n_list) {
__ip_vs_unlink_dest(svc, dest, 0);
- __ip_vs_del_dest(svc->net, dest);
+ __ip_vs_del_dest(svc->net, dest, cleanup);
}
/*
@@ -1400,13 +1376,12 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
/*
* Free the service if nobody refers to it
*/
- if (atomic_read(&svc->refcnt) == 0) {
- IP_VS_DBG_BUF(3, "Removing service %u/%s:%u usecnt=%d\n",
+ if (atomic_dec_and_test(&svc->refcnt)) {
+ IP_VS_DBG_BUF(3, "Removing service %u/%s:%u\n",
svc->fwmark,
IP_VS_DBG_ADDR(svc->af, &svc->addr),
- ntohs(svc->port), atomic_read(&svc->usecnt));
- free_percpu(svc->stats.cpustats);
- kfree(svc);
+ ntohs(svc->port));
+ call_rcu(&svc->rcu_head, ip_vs_service_rcu_free);
}
/* decrease the module use count */
@@ -1416,23 +1391,16 @@ static void __ip_vs_del_service(struct ip_vs_service *svc)
/*
* Unlink a service from list and try to delete it if its refcnt reached 0
*/
-static void ip_vs_unlink_service(struct ip_vs_service *svc)
+static void ip_vs_unlink_service(struct ip_vs_service *svc, bool cleanup)
{
+ /* Hold svc to avoid double release from dest_trash */
+ atomic_inc(&svc->refcnt);
/*
* Unhash it from the service table
*/
- write_lock_bh(&__ip_vs_svc_lock);
-
ip_vs_svc_unhash(svc);
- /*
- * Wait until all the svc users go away.
- */
- IP_VS_WAIT_WHILE(atomic_read(&svc->usecnt) > 0);
-
- __ip_vs_del_service(svc);
-
- write_unlock_bh(&__ip_vs_svc_lock);
+ __ip_vs_del_service(svc, cleanup);
}
/*
@@ -1442,7 +1410,7 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
{
if (svc == NULL)
return -EEXIST;
- ip_vs_unlink_service(svc);
+ ip_vs_unlink_service(svc, false);
return 0;
}
@@ -1451,19 +1419,20 @@ static int ip_vs_del_service(struct ip_vs_service *svc)
/*
* Flush all the virtual services
*/
-static int ip_vs_flush(struct net *net)
+static int ip_vs_flush(struct net *net, bool cleanup)
{
int idx;
- struct ip_vs_service *svc, *nxt;
+ struct ip_vs_service *svc;
+ struct hlist_node *n;
/*
* Flush the service table hashed by <netns,protocol,addr,port>
*/
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry_safe(svc, nxt, &ip_vs_svc_table[idx],
- s_list) {
+ hlist_for_each_entry_safe(svc, n, &ip_vs_svc_table[idx],
+ s_list) {
if (net_eq(svc->net, net))
- ip_vs_unlink_service(svc);
+ ip_vs_unlink_service(svc, cleanup);
}
}
@@ -1471,10 +1440,10 @@ static int ip_vs_flush(struct net *net)
* Flush the service table hashed by fwmark
*/
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry_safe(svc, nxt,
- &ip_vs_svc_fwm_table[idx], f_list) {
+ hlist_for_each_entry_safe(svc, n, &ip_vs_svc_fwm_table[idx],
+ f_list) {
if (net_eq(svc->net, net))
- ip_vs_unlink_service(svc);
+ ip_vs_unlink_service(svc, cleanup);
}
}
@@ -1490,32 +1459,32 @@ void ip_vs_service_net_cleanup(struct net *net)
EnterFunction(2);
/* Check for "full" addressed entries */
mutex_lock(&__ip_vs_mutex);
- ip_vs_flush(net);
+ ip_vs_flush(net, true);
mutex_unlock(&__ip_vs_mutex);
LeaveFunction(2);
}
-/*
- * Release dst hold by dst_cache
- */
+
+/* Put all references for device (dst_cache) */
static inline void
-__ip_vs_dev_reset(struct ip_vs_dest *dest, struct net_device *dev)
+ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
{
+ struct ip_vs_dest_dst *dest_dst;
+
spin_lock_bh(&dest->dst_lock);
- if (dest->dst_cache && dest->dst_cache->dev == dev) {
+ dest_dst = rcu_dereference_protected(dest->dest_dst, 1);
+ if (dest_dst && dest_dst->dst_cache->dev == dev) {
IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n",
dev->name,
IP_VS_DBG_ADDR(dest->af, &dest->addr),
ntohs(dest->port),
atomic_read(&dest->refcnt));
- ip_vs_dst_reset(dest);
+ __ip_vs_dst_cache_reset(dest);
}
spin_unlock_bh(&dest->dst_lock);
}
-/*
- * Netdev event receiver
- * Currently only NETDEV_UNREGISTER is handled, i.e. if we hold a reference to
- * a device that is "unregister" it must be released.
+/* Netdev event receiver
+ * Currently only NETDEV_DOWN is handled to release refs to cached dsts
*/
static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
void *ptr)
@@ -1527,35 +1496,37 @@ static int ip_vs_dst_event(struct notifier_block *this, unsigned long event,
struct ip_vs_dest *dest;
unsigned int idx;
- if (event != NETDEV_UNREGISTER || !ipvs)
+ if (event != NETDEV_DOWN || !ipvs)
return NOTIFY_DONE;
IP_VS_DBG(3, "%s() dev=%s\n", __func__, dev->name);
EnterFunction(2);
mutex_lock(&__ip_vs_mutex);
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
if (net_eq(svc->net, net)) {
list_for_each_entry(dest, &svc->destinations,
n_list) {
- __ip_vs_dev_reset(dest, dev);
+ ip_vs_forget_dev(dest, dev);
}
}
}
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
if (net_eq(svc->net, net)) {
list_for_each_entry(dest, &svc->destinations,
n_list) {
- __ip_vs_dev_reset(dest, dev);
+ ip_vs_forget_dev(dest, dev);
}
}
}
}
- list_for_each_entry(dest, &ipvs->dest_trash, n_list) {
- __ip_vs_dev_reset(dest, dev);
+ spin_lock_bh(&ipvs->dest_trash_lock);
+ list_for_each_entry(dest, &ipvs->dest_trash, t_list) {
+ ip_vs_forget_dev(dest, dev);
}
+ spin_unlock_bh(&ipvs->dest_trash_lock);
mutex_unlock(&__ip_vs_mutex);
LeaveFunction(2);
return NOTIFY_DONE;
@@ -1568,12 +1539,10 @@ static int ip_vs_zero_service(struct ip_vs_service *svc)
{
struct ip_vs_dest *dest;
- write_lock_bh(&__ip_vs_svc_lock);
list_for_each_entry(dest, &svc->destinations, n_list) {
ip_vs_zero_stats(&dest->stats);
}
ip_vs_zero_stats(&svc->stats);
- write_unlock_bh(&__ip_vs_svc_lock);
return 0;
}
@@ -1583,14 +1552,14 @@ static int ip_vs_zero_all(struct net *net)
struct ip_vs_service *svc;
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
if (net_eq(svc->net, net))
ip_vs_zero_service(svc);
}
}
for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
if (net_eq(svc->net, net))
ip_vs_zero_service(svc);
}
@@ -1918,7 +1887,7 @@ static struct ctl_table vs_vars[] = {
struct ip_vs_iter {
struct seq_net_private p; /* Do not move this, netns depends upon it*/
- struct list_head *table;
+ struct hlist_head *table;
int bucket;
};
@@ -1951,7 +1920,7 @@ static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
/* look in hash by protocol */
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+ hlist_for_each_entry_rcu(svc, &ip_vs_svc_table[idx], s_list) {
if (net_eq(svc->net, net) && pos-- == 0) {
iter->table = ip_vs_svc_table;
iter->bucket = idx;
@@ -1962,7 +1931,8 @@ static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
/* keep looking in fwmark */
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+ hlist_for_each_entry_rcu(svc, &ip_vs_svc_fwm_table[idx],
+ f_list) {
if (net_eq(svc->net, net) && pos-- == 0) {
iter->table = ip_vs_svc_fwm_table;
iter->bucket = idx;
@@ -1975,17 +1945,16 @@ static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
}
static void *ip_vs_info_seq_start(struct seq_file *seq, loff_t *pos)
-__acquires(__ip_vs_svc_lock)
+ __acquires(RCU)
{
-
- read_lock_bh(&__ip_vs_svc_lock);
+ rcu_read_lock();
return *pos ? ip_vs_info_array(seq, *pos - 1) : SEQ_START_TOKEN;
}
static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct list_head *e;
+ struct hlist_node *e;
struct ip_vs_iter *iter;
struct ip_vs_service *svc;
@@ -1998,13 +1967,14 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
if (iter->table == ip_vs_svc_table) {
/* next service in table hashed by protocol */
- if ((e = svc->s_list.next) != &ip_vs_svc_table[iter->bucket])
- return list_entry(e, struct ip_vs_service, s_list);
-
+ e = rcu_dereference(hlist_next_rcu(&svc->s_list));
+ if (e)
+ return hlist_entry(e, struct ip_vs_service, s_list);
while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
- list_for_each_entry(svc,&ip_vs_svc_table[iter->bucket],
- s_list) {
+ hlist_for_each_entry_rcu(svc,
+ &ip_vs_svc_table[iter->bucket],
+ s_list) {
return svc;
}
}
@@ -2015,13 +1985,15 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
/* next service in hashed by fwmark */
- if ((e = svc->f_list.next) != &ip_vs_svc_fwm_table[iter->bucket])
- return list_entry(e, struct ip_vs_service, f_list);
+ e = rcu_dereference(hlist_next_rcu(&svc->f_list));
+ if (e)
+ return hlist_entry(e, struct ip_vs_service, f_list);
scan_fwmark:
while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[iter->bucket],
- f_list)
+ hlist_for_each_entry_rcu(svc,
+ &ip_vs_svc_fwm_table[iter->bucket],
+ f_list)
return svc;
}
@@ -2029,9 +2001,9 @@ static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void ip_vs_info_seq_stop(struct seq_file *seq, void *v)
-__releases(__ip_vs_svc_lock)
+ __releases(RCU)
{
- read_unlock_bh(&__ip_vs_svc_lock);
+ rcu_read_unlock();
}
@@ -2049,6 +2021,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
const struct ip_vs_service *svc = v;
const struct ip_vs_iter *iter = seq->private;
const struct ip_vs_dest *dest;
+ struct ip_vs_scheduler *sched = rcu_dereference(svc->scheduler);
if (iter->table == ip_vs_svc_table) {
#ifdef CONFIG_IP_VS_IPV6
@@ -2057,18 +2030,18 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
ip_vs_proto_name(svc->protocol),
&svc->addr.in6,
ntohs(svc->port),
- svc->scheduler->name);
+ sched->name);
else
#endif
seq_printf(seq, "%s %08X:%04X %s %s ",
ip_vs_proto_name(svc->protocol),
ntohl(svc->addr.ip),
ntohs(svc->port),
- svc->scheduler->name,
+ sched->name,
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
} else {
seq_printf(seq, "FWM %08X %s %s",
- svc->fwmark, svc->scheduler->name,
+ svc->fwmark, sched->name,
(svc->flags & IP_VS_SVC_F_ONEPACKET)?"ops ":"");
}
@@ -2079,7 +2052,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
else
seq_putc(seq, '\n');
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
#ifdef CONFIG_IP_VS_IPV6
if (dest->af == AF_INET6)
seq_printf(seq,
@@ -2173,7 +2146,7 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
{
struct net *net = seq_file_single_net(seq);
struct ip_vs_stats *tot_stats = &net_ipvs(net)->tot_stats;
- struct ip_vs_cpu_stats *cpustats = tot_stats->cpustats;
+ struct ip_vs_cpu_stats __percpu *cpustats = tot_stats->cpustats;
struct ip_vs_stats_user rates;
int i;
@@ -2389,7 +2362,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
if (cmd == IP_VS_SO_SET_FLUSH) {
/* Flush the virtual service */
- ret = ip_vs_flush(net);
+ ret = ip_vs_flush(net, false);
goto out_unlock;
} else if (cmd == IP_VS_SO_SET_TIMEOUT) {
/* Set timeout values for (tcp tcpfin udp) */
@@ -2424,11 +2397,13 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
}
/* Lookup the exact service by <protocol, addr, port> or fwmark */
+ rcu_read_lock();
if (usvc.fwmark == 0)
svc = __ip_vs_service_find(net, usvc.af, usvc.protocol,
&usvc.addr, usvc.port);
else
svc = __ip_vs_svc_fwm_find(net, usvc.af, usvc.fwmark);
+ rcu_read_unlock();
if (cmd != IP_VS_SO_SET_ADD
&& (svc == NULL || svc->protocol != usvc.protocol)) {
@@ -2480,11 +2455,14 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
static void
ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
{
+ struct ip_vs_scheduler *sched;
+
+ sched = rcu_dereference_protected(src->scheduler, 1);
dst->protocol = src->protocol;
dst->addr = src->addr.ip;
dst->port = src->port;
dst->fwmark = src->fwmark;
- strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
+ strlcpy(dst->sched_name, sched->name, sizeof(dst->sched_name));
dst->flags = src->flags;
dst->timeout = src->timeout / HZ;
dst->netmask = src->netmask;
@@ -2503,7 +2481,7 @@ __ip_vs_get_service_entries(struct net *net,
int ret = 0;
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
/* Only expose IPv4 entries to old interface */
if (svc->af != AF_INET || !net_eq(svc->net, net))
continue;
@@ -2522,7 +2500,7 @@ __ip_vs_get_service_entries(struct net *net,
}
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
/* Only expose IPv4 entries to old interface */
if (svc->af != AF_INET || !net_eq(svc->net, net))
continue;
@@ -2551,11 +2529,13 @@ __ip_vs_get_dest_entries(struct net *net, const struct ip_vs_get_dests *get,
union nf_inet_addr addr = { .ip = get->addr };
int ret = 0;
+ rcu_read_lock();
if (get->fwmark)
svc = __ip_vs_svc_fwm_find(net, AF_INET, get->fwmark);
else
svc = __ip_vs_service_find(net, AF_INET, get->protocol, &addr,
get->port);
+ rcu_read_unlock();
if (svc) {
int count = 0;
@@ -2738,12 +2718,14 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
entry = (struct ip_vs_service_entry *)arg;
addr.ip = entry->addr;
+ rcu_read_lock();
if (entry->fwmark)
svc = __ip_vs_svc_fwm_find(net, AF_INET, entry->fwmark);
else
svc = __ip_vs_service_find(net, AF_INET,
entry->protocol, &addr,
entry->port);
+ rcu_read_unlock();
if (svc) {
ip_vs_copy_service(entry, svc);
if (copy_to_user(user, entry, sizeof(*entry)) != 0)
@@ -2900,6 +2882,8 @@ nla_put_failure:
static int ip_vs_genl_fill_service(struct sk_buff *skb,
struct ip_vs_service *svc)
{
+ struct ip_vs_scheduler *sched;
+ struct ip_vs_pe *pe;
struct nlattr *nl_service;
struct ip_vs_flags flags = { .flags = svc->flags,
.mask = ~0 };
@@ -2916,16 +2900,17 @@ static int ip_vs_genl_fill_service(struct sk_buff *skb,
} else {
if (nla_put_u16(skb, IPVS_SVC_ATTR_PROTOCOL, svc->protocol) ||
nla_put(skb, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &svc->addr) ||
- nla_put_u16(skb, IPVS_SVC_ATTR_PORT, svc->port))
+ nla_put_be16(skb, IPVS_SVC_ATTR_PORT, svc->port))
goto nla_put_failure;
}
- if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name) ||
- (svc->pe &&
- nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name)) ||
+ sched = rcu_dereference_protected(svc->scheduler, 1);
+ pe = rcu_dereference_protected(svc->pe, 1);
+ if (nla_put_string(skb, IPVS_SVC_ATTR_SCHED_NAME, sched->name) ||
+ (pe && nla_put_string(skb, IPVS_SVC_ATTR_PE_NAME, pe->name)) ||
nla_put(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags) ||
nla_put_u32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ) ||
- nla_put_u32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask))
+ nla_put_be32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask))
goto nla_put_failure;
if (ip_vs_genl_fill_stats(skb, IPVS_SVC_ATTR_STATS, &svc->stats))
goto nla_put_failure;
@@ -2971,7 +2956,7 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,
mutex_lock(&__ip_vs_mutex);
for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
- list_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_table[i], s_list) {
if (++idx <= start || !net_eq(svc->net, net))
continue;
if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
@@ -2982,7 +2967,7 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb,
}
for (i = 0; i < IP_VS_SVC_TAB_SIZE; i++) {
- list_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {
+ hlist_for_each_entry(svc, &ip_vs_svc_fwm_table[i], f_list) {
if (++idx <= start || !net_eq(svc->net, net))
continue;
if (ip_vs_genl_dump_service(skb, svc, cb) < 0) {
@@ -3038,15 +3023,17 @@ static int ip_vs_genl_parse_service(struct net *net,
} else {
usvc->protocol = nla_get_u16(nla_protocol);
nla_memcpy(&usvc->addr, nla_addr, sizeof(usvc->addr));
- usvc->port = nla_get_u16(nla_port);
+ usvc->port = nla_get_be16(nla_port);
usvc->fwmark = 0;
}
+ rcu_read_lock();
if (usvc->fwmark)
svc = __ip_vs_svc_fwm_find(net, usvc->af, usvc->fwmark);
else
svc = __ip_vs_service_find(net, usvc->af, usvc->protocol,
&usvc->addr, usvc->port);
+ rcu_read_unlock();
*ret_svc = svc;
/* If a full entry was requested, check for the additional fields */
@@ -3076,7 +3063,7 @@ static int ip_vs_genl_parse_service(struct net *net,
usvc->sched_name = nla_data(nla_sched);
usvc->pe_name = nla_pe ? nla_data(nla_pe) : NULL;
usvc->timeout = nla_get_u32(nla_timeout);
- usvc->netmask = nla_get_u32(nla_netmask);
+ usvc->netmask = nla_get_be32(nla_netmask);
}
return 0;
@@ -3102,7 +3089,7 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest)
return -EMSGSIZE;
if (nla_put(skb, IPVS_DEST_ATTR_ADDR, sizeof(dest->addr), &dest->addr) ||
- nla_put_u16(skb, IPVS_DEST_ATTR_PORT, dest->port) ||
+ nla_put_be16(skb, IPVS_DEST_ATTR_PORT, dest->port) ||
nla_put_u32(skb, IPVS_DEST_ATTR_FWD_METHOD,
(atomic_read(&dest->conn_flags) &
IP_VS_CONN_F_FWD_MASK)) ||
@@ -3211,7 +3198,7 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
memset(udest, 0, sizeof(*udest));
nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr));
- udest->port = nla_get_u16(nla_port);
+ udest->port = nla_get_be16(nla_port);
/* If a full entry was requested, check for the additional fields */
if (full_entry) {
@@ -3236,8 +3223,8 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest,
return 0;
}
-static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __be32 state,
- const char *mcast_ifn, __be32 syncid)
+static int ip_vs_genl_fill_daemon(struct sk_buff *skb, __u32 state,
+ const char *mcast_ifn, __u32 syncid)
{
struct nlattr *nl_daemon;
@@ -3258,8 +3245,8 @@ nla_put_failure:
return -EMSGSIZE;
}
-static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __be32 state,
- const char *mcast_ifn, __be32 syncid,
+static int ip_vs_genl_dump_daemon(struct sk_buff *skb, __u32 state,
+ const char *mcast_ifn, __u32 syncid,
struct netlink_callback *cb)
{
void *hdr;
@@ -3398,7 +3385,7 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&__ip_vs_mutex);
if (cmd == IPVS_CMD_FLUSH) {
- ret = ip_vs_flush(net);
+ ret = ip_vs_flush(net, false);
goto out;
} else if (cmd == IPVS_CMD_SET_CONFIG) {
ret = ip_vs_genl_set_config(net, info->attrs);
@@ -3790,13 +3777,14 @@ int __net_init ip_vs_control_net_init(struct net *net)
int idx;
struct netns_ipvs *ipvs = net_ipvs(net);
- rwlock_init(&ipvs->rs_lock);
-
/* Initialize rs_table */
for (idx = 0; idx < IP_VS_RTAB_SIZE; idx++)
- INIT_LIST_HEAD(&ipvs->rs_table[idx]);
+ INIT_HLIST_HEAD(&ipvs->rs_table[idx]);
INIT_LIST_HEAD(&ipvs->dest_trash);
+ spin_lock_init(&ipvs->dest_trash_lock);
+ setup_timer(&ipvs->dest_trash_timer, ip_vs_dest_trash_expire,
+ (unsigned long) net);
atomic_set(&ipvs->ftpsvc_counter, 0);
atomic_set(&ipvs->nullsvc_counter, 0);
@@ -3826,6 +3814,10 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
+ /* Some dest can be in grace period even before cleanup, we have to
+ * defer ip_vs_trash_cleanup until ip_vs_dest_wait_readers is called.
+ */
+ rcu_barrier();
ip_vs_trash_cleanup(net);
ip_vs_stop_estimator(net, &ipvs->tot_stats);
ip_vs_control_net_cleanup_sysctl(net);
@@ -3871,10 +3863,10 @@ int __init ip_vs_control_init(void)
EnterFunction(2);
- /* Initialize svc_table, ip_vs_svc_fwm_table, rs_table */
+ /* Initialize svc_table, ip_vs_svc_fwm_table */
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
- INIT_LIST_HEAD(&ip_vs_svc_table[idx]);
- INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]);
+ INIT_HLIST_HEAD(&ip_vs_svc_table[idx]);
+ INIT_HLIST_HEAD(&ip_vs_svc_fwm_table[idx]);
}
smp_wmb(); /* Do we really need it now ? */
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c
index 7f3b0cc00b7a..ccab120df45e 100644
--- a/net/netfilter/ipvs/ip_vs_dh.c
+++ b/net/netfilter/ipvs/ip_vs_dh.c
@@ -51,7 +51,7 @@
* IPVS DH bucket
*/
struct ip_vs_dh_bucket {
- struct ip_vs_dest *dest; /* real server (cache) */
+ struct ip_vs_dest __rcu *dest; /* real server (cache) */
};
/*
@@ -64,6 +64,10 @@ struct ip_vs_dh_bucket {
#define IP_VS_DH_TAB_SIZE (1 << IP_VS_DH_TAB_BITS)
#define IP_VS_DH_TAB_MASK (IP_VS_DH_TAB_SIZE - 1)
+struct ip_vs_dh_state {
+ struct ip_vs_dh_bucket buckets[IP_VS_DH_TAB_SIZE];
+ struct rcu_head rcu_head;
+};
/*
* Returns hash value for IPVS DH entry
@@ -85,10 +89,9 @@ static inline unsigned int ip_vs_dh_hashkey(int af, const union nf_inet_addr *ad
* Get ip_vs_dest associated with supplied parameters.
*/
static inline struct ip_vs_dest *
-ip_vs_dh_get(int af, struct ip_vs_dh_bucket *tbl,
- const union nf_inet_addr *addr)
+ip_vs_dh_get(int af, struct ip_vs_dh_state *s, const union nf_inet_addr *addr)
{
- return (tbl[ip_vs_dh_hashkey(af, addr)]).dest;
+ return rcu_dereference(s->buckets[ip_vs_dh_hashkey(af, addr)].dest);
}
@@ -96,25 +99,30 @@ ip_vs_dh_get(int af, struct ip_vs_dh_bucket *tbl,
* Assign all the hash buckets of the specified table with the service.
*/
static int
-ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
+ip_vs_dh_reassign(struct ip_vs_dh_state *s, struct ip_vs_service *svc)
{
int i;
struct ip_vs_dh_bucket *b;
struct list_head *p;
struct ip_vs_dest *dest;
+ bool empty;
- b = tbl;
+ b = &s->buckets[0];
p = &svc->destinations;
+ empty = list_empty(p);
for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
- if (list_empty(p)) {
- b->dest = NULL;
- } else {
+ dest = rcu_dereference_protected(b->dest, 1);
+ if (dest)
+ ip_vs_dest_put(dest);
+ if (empty)
+ RCU_INIT_POINTER(b->dest, NULL);
+ else {
if (p == &svc->destinations)
p = p->next;
dest = list_entry(p, struct ip_vs_dest, n_list);
- atomic_inc(&dest->refcnt);
- b->dest = dest;
+ ip_vs_dest_hold(dest);
+ RCU_INIT_POINTER(b->dest, dest);
p = p->next;
}
@@ -127,16 +135,18 @@ ip_vs_dh_assign(struct ip_vs_dh_bucket *tbl, struct ip_vs_service *svc)
/*
* Flush all the hash buckets of the specified table.
*/
-static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
+static void ip_vs_dh_flush(struct ip_vs_dh_state *s)
{
int i;
struct ip_vs_dh_bucket *b;
+ struct ip_vs_dest *dest;
- b = tbl;
+ b = &s->buckets[0];
for (i=0; i<IP_VS_DH_TAB_SIZE; i++) {
- if (b->dest) {
- atomic_dec(&b->dest->refcnt);
- b->dest = NULL;
+ dest = rcu_dereference_protected(b->dest, 1);
+ if (dest) {
+ ip_vs_dest_put(dest);
+ RCU_INIT_POINTER(b->dest, NULL);
}
b++;
}
@@ -145,51 +155,46 @@ static void ip_vs_dh_flush(struct ip_vs_dh_bucket *tbl)
static int ip_vs_dh_init_svc(struct ip_vs_service *svc)
{
- struct ip_vs_dh_bucket *tbl;
+ struct ip_vs_dh_state *s;
/* allocate the DH table for this service */
- tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE,
- GFP_KERNEL);
- if (tbl == NULL)
+ s = kzalloc(sizeof(struct ip_vs_dh_state), GFP_KERNEL);
+ if (s == NULL)
return -ENOMEM;
- svc->sched_data = tbl;
+ svc->sched_data = s;
IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for "
"current service\n",
sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
- /* assign the hash buckets with the updated service */
- ip_vs_dh_assign(tbl, svc);
+ /* assign the hash buckets with current dests */
+ ip_vs_dh_reassign(s, svc);
return 0;
}
-static int ip_vs_dh_done_svc(struct ip_vs_service *svc)
+static void ip_vs_dh_done_svc(struct ip_vs_service *svc)
{
- struct ip_vs_dh_bucket *tbl = svc->sched_data;
+ struct ip_vs_dh_state *s = svc->sched_data;
/* got to clean up hash buckets here */
- ip_vs_dh_flush(tbl);
+ ip_vs_dh_flush(s);
/* release the table itself */
- kfree(svc->sched_data);
+ kfree_rcu(s, rcu_head);
IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) released\n",
sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE);
-
- return 0;
}
-static int ip_vs_dh_update_svc(struct ip_vs_service *svc)
+static int ip_vs_dh_dest_changed(struct ip_vs_service *svc,
+ struct ip_vs_dest *dest)
{
- struct ip_vs_dh_bucket *tbl = svc->sched_data;
-
- /* got to clean up hash buckets here */
- ip_vs_dh_flush(tbl);
+ struct ip_vs_dh_state *s = svc->sched_data;
/* assign the hash buckets with the updated service */
- ip_vs_dh_assign(tbl, svc);
+ ip_vs_dh_reassign(s, svc);
return 0;
}
@@ -212,19 +217,20 @@ static struct ip_vs_dest *
ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
struct ip_vs_dest *dest;
- struct ip_vs_dh_bucket *tbl;
+ struct ip_vs_dh_state *s;
struct ip_vs_iphdr iph;
ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
- tbl = (struct ip_vs_dh_bucket *)svc->sched_data;
- dest = ip_vs_dh_get(svc->af, tbl, &iph.daddr);
+ s = (struct ip_vs_dh_state *) svc->sched_data;
+ dest = ip_vs_dh_get(svc->af, s, &iph.daddr);
if (!dest
|| !(dest->flags & IP_VS_DEST_F_AVAILABLE)
|| atomic_read(&dest->weight) <= 0
|| is_overloaded(dest)) {
+ ip_vs_scheduler_err(svc, "no destination available");
return NULL;
}
@@ -248,7 +254,8 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler =
.n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list),
.init_service = ip_vs_dh_init_svc,
.done_service = ip_vs_dh_done_svc,
- .update_service = ip_vs_dh_update_svc,
+ .add_dest = ip_vs_dh_dest_changed,
+ .del_dest = ip_vs_dh_dest_changed,
.schedule = ip_vs_dh_schedule,
};
@@ -262,6 +269,7 @@ static int __init ip_vs_dh_init(void)
static void __exit ip_vs_dh_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_dh_scheduler);
+ synchronize_rcu();
}
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c
index 0fac6017b6fb..6bee6d0c73a5 100644
--- a/net/netfilter/ipvs/ip_vs_est.c
+++ b/net/netfilter/ipvs/ip_vs_est.c
@@ -56,7 +56,7 @@
* Make a summary from each cpu
*/
static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
- struct ip_vs_cpu_stats *stats)
+ struct ip_vs_cpu_stats __percpu *stats)
{
int i;
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c
index 4f53a5f04437..77c173282f38 100644
--- a/net/netfilter/ipvs/ip_vs_ftp.c
+++ b/net/netfilter/ipvs/ip_vs_ftp.c
@@ -267,10 +267,12 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
* hopefully it will succeed on the retransmitted
* packet.
*/
+ rcu_read_lock();
ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
iph->ihl * 4,
start-data, end-start,
buf, buf_len);
+ rcu_read_unlock();
if (ret) {
ip_vs_nfct_expect_related(skb, ct, n_cp,
IPPROTO_TCP, 0, 0);
@@ -480,6 +482,7 @@ static int __init ip_vs_ftp_init(void)
int rv;
rv = register_pernet_subsys(&ip_vs_ftp_ops);
+ /* rcu_barrier() is called by netns on error */
return rv;
}
@@ -489,6 +492,7 @@ static int __init ip_vs_ftp_init(void)
static void __exit ip_vs_ftp_exit(void)
{
unregister_pernet_subsys(&ip_vs_ftp_ops);
+ /* rcu_barrier() is called by netns */
}
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index fdd89b9564ea..5ea26bd87743 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -90,11 +90,12 @@
* IP address and its destination server
*/
struct ip_vs_lblc_entry {
- struct list_head list;
+ struct hlist_node list;
int af; /* address family */
union nf_inet_addr addr; /* destination IP address */
- struct ip_vs_dest *dest; /* real server (cache) */
+ struct ip_vs_dest __rcu *dest; /* real server (cache) */
unsigned long lastuse; /* last used time */
+ struct rcu_head rcu_head;
};
@@ -102,12 +103,14 @@ struct ip_vs_lblc_entry {
* IPVS lblc hash table
*/
struct ip_vs_lblc_table {
- struct list_head bucket[IP_VS_LBLC_TAB_SIZE]; /* hash bucket */
+ struct rcu_head rcu_head;
+ struct hlist_head bucket[IP_VS_LBLC_TAB_SIZE]; /* hash bucket */
+ struct timer_list periodic_timer; /* collect stale entries */
atomic_t entries; /* number of entries */
int max_size; /* maximum size of entries */
- struct timer_list periodic_timer; /* collect stale entries */
int rover; /* rover for expire check */
int counter; /* counter for no expire */
+ bool dead;
};
@@ -129,13 +132,16 @@ static ctl_table vs_vars_table[] = {
static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
{
- list_del(&en->list);
+ struct ip_vs_dest *dest;
+
+ hlist_del_rcu(&en->list);
/*
* We don't kfree dest because it is referred either by its service
* or the trash dest list.
*/
- atomic_dec(&en->dest->refcnt);
- kfree(en);
+ dest = rcu_dereference_protected(en->dest, 1);
+ ip_vs_dest_put(dest);
+ kfree_rcu(en, rcu_head);
}
@@ -165,15 +171,12 @@ ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
{
unsigned int hash = ip_vs_lblc_hashkey(en->af, &en->addr);
- list_add(&en->list, &tbl->bucket[hash]);
+ hlist_add_head_rcu(&en->list, &tbl->bucket[hash]);
atomic_inc(&tbl->entries);
}
-/*
- * Get ip_vs_lblc_entry associated with supplied parameters. Called under read
- * lock
- */
+/* Get ip_vs_lblc_entry associated with supplied parameters. */
static inline struct ip_vs_lblc_entry *
ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
const union nf_inet_addr *addr)
@@ -181,7 +184,7 @@ ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
unsigned int hash = ip_vs_lblc_hashkey(af, addr);
struct ip_vs_lblc_entry *en;
- list_for_each_entry(en, &tbl->bucket[hash], list)
+ hlist_for_each_entry_rcu(en, &tbl->bucket[hash], list)
if (ip_vs_addr_equal(af, &en->addr, addr))
return en;
@@ -191,7 +194,7 @@ ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl,
/*
* Create or update an ip_vs_lblc_entry, which is a mapping of a destination IP
- * address to a server. Called under write lock.
+ * address to a server. Called under spin lock.
*/
static inline struct ip_vs_lblc_entry *
ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
@@ -209,14 +212,20 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
ip_vs_addr_copy(dest->af, &en->addr, daddr);
en->lastuse = jiffies;
- atomic_inc(&dest->refcnt);
- en->dest = dest;
+ ip_vs_dest_hold(dest);
+ RCU_INIT_POINTER(en->dest, dest);
ip_vs_lblc_hash(tbl, en);
- } else if (en->dest != dest) {
- atomic_dec(&en->dest->refcnt);
- atomic_inc(&dest->refcnt);
- en->dest = dest;
+ } else {
+ struct ip_vs_dest *old_dest;
+
+ old_dest = rcu_dereference_protected(en->dest, 1);
+ if (old_dest != dest) {
+ ip_vs_dest_put(old_dest);
+ ip_vs_dest_hold(dest);
+ /* No ordering constraints for refcnt */
+ RCU_INIT_POINTER(en->dest, dest);
+ }
}
return en;
@@ -226,17 +235,22 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr,
/*
* Flush all the entries of the specified table.
*/
-static void ip_vs_lblc_flush(struct ip_vs_lblc_table *tbl)
+static void ip_vs_lblc_flush(struct ip_vs_service *svc)
{
- struct ip_vs_lblc_entry *en, *nxt;
+ struct ip_vs_lblc_table *tbl = svc->sched_data;
+ struct ip_vs_lblc_entry *en;
+ struct hlist_node *next;
int i;
+ spin_lock_bh(&svc->sched_lock);
+ tbl->dead = 1;
for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
- list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
ip_vs_lblc_free(en);
atomic_dec(&tbl->entries);
}
}
+ spin_unlock_bh(&svc->sched_lock);
}
static int sysctl_lblc_expiration(struct ip_vs_service *svc)
@@ -252,15 +266,16 @@ static int sysctl_lblc_expiration(struct ip_vs_service *svc)
static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
{
struct ip_vs_lblc_table *tbl = svc->sched_data;
- struct ip_vs_lblc_entry *en, *nxt;
+ struct ip_vs_lblc_entry *en;
+ struct hlist_node *next;
unsigned long now = jiffies;
int i, j;
for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
j = (j + 1) & IP_VS_LBLC_TAB_MASK;
- write_lock(&svc->sched_lock);
- list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+ spin_lock(&svc->sched_lock);
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
if (time_before(now,
en->lastuse +
sysctl_lblc_expiration(svc)))
@@ -269,7 +284,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
ip_vs_lblc_free(en);
atomic_dec(&tbl->entries);
}
- write_unlock(&svc->sched_lock);
+ spin_unlock(&svc->sched_lock);
}
tbl->rover = j;
}
@@ -293,7 +308,8 @@ static void ip_vs_lblc_check_expire(unsigned long data)
unsigned long now = jiffies;
int goal;
int i, j;
- struct ip_vs_lblc_entry *en, *nxt;
+ struct ip_vs_lblc_entry *en;
+ struct hlist_node *next;
if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
/* do full expiration check */
@@ -314,8 +330,8 @@ static void ip_vs_lblc_check_expire(unsigned long data)
for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
j = (j + 1) & IP_VS_LBLC_TAB_MASK;
- write_lock(&svc->sched_lock);
- list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+ spin_lock(&svc->sched_lock);
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
if (time_before(now, en->lastuse + ENTRY_TIMEOUT))
continue;
@@ -323,7 +339,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
atomic_dec(&tbl->entries);
goal--;
}
- write_unlock(&svc->sched_lock);
+ spin_unlock(&svc->sched_lock);
if (goal <= 0)
break;
}
@@ -354,11 +370,12 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
* Initialize the hash buckets
*/
for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
- INIT_LIST_HEAD(&tbl->bucket[i]);
+ INIT_HLIST_HEAD(&tbl->bucket[i]);
}
tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
tbl->rover = 0;
tbl->counter = 1;
+ tbl->dead = 0;
/*
* Hook periodic timer for garbage collection
@@ -371,7 +388,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
}
-static int ip_vs_lblc_done_svc(struct ip_vs_service *svc)
+static void ip_vs_lblc_done_svc(struct ip_vs_service *svc)
{
struct ip_vs_lblc_table *tbl = svc->sched_data;
@@ -379,14 +396,12 @@ static int ip_vs_lblc_done_svc(struct ip_vs_service *svc)
del_timer_sync(&tbl->periodic_timer);
/* got to clean up table entries here */
- ip_vs_lblc_flush(tbl);
+ ip_vs_lblc_flush(svc);
/* release the table itself */
- kfree(tbl);
+ kfree_rcu(tbl, rcu_head);
IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) released\n",
sizeof(*tbl));
-
- return 0;
}
@@ -408,7 +423,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
* The server with weight=0 is quiesced and will not receive any
* new connection.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
if (atomic_read(&dest->weight) > 0) {
@@ -423,7 +438,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
* Find the destination with the least load.
*/
nextstage:
- list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+ list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -457,7 +472,7 @@ is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
struct ip_vs_dest *d;
- list_for_each_entry(d, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(d, &svc->destinations, n_list) {
if (atomic_read(&d->activeconns)*2
< atomic_read(&d->weight)) {
return 1;
@@ -484,7 +499,6 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
/* First look in our cache */
- read_lock(&svc->sched_lock);
en = ip_vs_lblc_get(svc->af, tbl, &iph.daddr);
if (en) {
/* We only hold a read lock, but this is atomic */
@@ -499,14 +513,11 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* free up entries from the trash at any time.
*/
- if (en->dest->flags & IP_VS_DEST_F_AVAILABLE)
- dest = en->dest;
+ dest = rcu_dereference(en->dest);
+ if ((dest->flags & IP_VS_DEST_F_AVAILABLE) &&
+ atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
+ goto out;
}
- read_unlock(&svc->sched_lock);
-
- /* If the destination has a weight and is not overloaded, use it */
- if (dest && atomic_read(&dest->weight) > 0 && !is_overloaded(dest, svc))
- goto out;
/* No cache entry or it is invalid, time to schedule */
dest = __ip_vs_lblc_schedule(svc);
@@ -516,9 +527,10 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
}
/* If we fail to create a cache entry, we'll just use the valid dest */
- write_lock(&svc->sched_lock);
- ip_vs_lblc_new(tbl, &iph.daddr, dest);
- write_unlock(&svc->sched_lock);
+ spin_lock_bh(&svc->sched_lock);
+ if (!tbl->dead)
+ ip_vs_lblc_new(tbl, &iph.daddr, dest);
+ spin_unlock_bh(&svc->sched_lock);
out:
IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n",
@@ -621,6 +633,7 @@ static void __exit ip_vs_lblc_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
unregister_pernet_subsys(&ip_vs_lblc_ops);
+ synchronize_rcu();
}
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index c03b6a3ade2f..50123c2ab484 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -89,40 +89,44 @@
*/
struct ip_vs_dest_set_elem {
struct list_head list; /* list link */
- struct ip_vs_dest *dest; /* destination server */
+ struct ip_vs_dest __rcu *dest; /* destination server */
+ struct rcu_head rcu_head;
};
struct ip_vs_dest_set {
atomic_t size; /* set size */
unsigned long lastmod; /* last modified time */
struct list_head list; /* destination list */
- rwlock_t lock; /* lock for this list */
};
-static struct ip_vs_dest_set_elem *
-ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
+static void ip_vs_dest_set_insert(struct ip_vs_dest_set *set,
+ struct ip_vs_dest *dest, bool check)
{
struct ip_vs_dest_set_elem *e;
- list_for_each_entry(e, &set->list, list) {
- if (e->dest == dest)
- /* already existed */
- return NULL;
+ if (check) {
+ list_for_each_entry(e, &set->list, list) {
+ struct ip_vs_dest *d;
+
+ d = rcu_dereference_protected(e->dest, 1);
+ if (d == dest)
+ /* already existed */
+ return;
+ }
}
e = kmalloc(sizeof(*e), GFP_ATOMIC);
if (e == NULL)
- return NULL;
+ return;
- atomic_inc(&dest->refcnt);
- e->dest = dest;
+ ip_vs_dest_hold(dest);
+ RCU_INIT_POINTER(e->dest, dest);
- list_add(&e->list, &set->list);
+ list_add_rcu(&e->list, &set->list);
atomic_inc(&set->size);
set->lastmod = jiffies;
- return e;
}
static void
@@ -131,13 +135,16 @@ ip_vs_dest_set_erase(struct ip_vs_dest_set *set, struct ip_vs_dest *dest)
struct ip_vs_dest_set_elem *e;
list_for_each_entry(e, &set->list, list) {
- if (e->dest == dest) {
+ struct ip_vs_dest *d;
+
+ d = rcu_dereference_protected(e->dest, 1);
+ if (d == dest) {
/* HIT */
atomic_dec(&set->size);
set->lastmod = jiffies;
- atomic_dec(&e->dest->refcnt);
- list_del(&e->list);
- kfree(e);
+ ip_vs_dest_put(dest);
+ list_del_rcu(&e->list);
+ kfree_rcu(e, rcu_head);
break;
}
}
@@ -147,17 +154,18 @@ static void ip_vs_dest_set_eraseall(struct ip_vs_dest_set *set)
{
struct ip_vs_dest_set_elem *e, *ep;
- write_lock(&set->lock);
list_for_each_entry_safe(e, ep, &set->list, list) {
+ struct ip_vs_dest *d;
+
+ d = rcu_dereference_protected(e->dest, 1);
/*
* We don't kfree dest because it is referred either
* by its service or by the trash dest list.
*/
- atomic_dec(&e->dest->refcnt);
- list_del(&e->list);
- kfree(e);
+ ip_vs_dest_put(d);
+ list_del_rcu(&e->list);
+ kfree_rcu(e, rcu_head);
}
- write_unlock(&set->lock);
}
/* get weighted least-connection node in the destination set */
@@ -171,8 +179,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
return NULL;
/* select the first destination server, whose weight > 0 */
- list_for_each_entry(e, &set->list, list) {
- least = e->dest;
+ list_for_each_entry_rcu(e, &set->list, list) {
+ least = rcu_dereference(e->dest);
if (least->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -186,8 +194,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
/* find the destination with the weighted least load */
nextstage:
- list_for_each_entry(e, &set->list, list) {
- dest = e->dest;
+ list_for_each_entry_continue_rcu(e, &set->list, list) {
+ dest = rcu_dereference(e->dest);
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -224,7 +232,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
/* select the first destination server, whose weight > 0 */
list_for_each_entry(e, &set->list, list) {
- most = e->dest;
+ most = rcu_dereference_protected(e->dest, 1);
if (atomic_read(&most->weight) > 0) {
moh = ip_vs_dest_conn_overhead(most);
goto nextstage;
@@ -234,8 +242,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
/* find the destination with the weighted most load */
nextstage:
- list_for_each_entry(e, &set->list, list) {
- dest = e->dest;
+ list_for_each_entry_continue(e, &set->list, list) {
+ dest = rcu_dereference_protected(e->dest, 1);
doh = ip_vs_dest_conn_overhead(dest);
/* moh/mw < doh/dw ==> moh*dw < doh*mw, where mw,dw>0 */
if ((moh * atomic_read(&dest->weight) <
@@ -262,11 +270,12 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
* IP address and its destination server set
*/
struct ip_vs_lblcr_entry {
- struct list_head list;
+ struct hlist_node list;
int af; /* address family */
union nf_inet_addr addr; /* destination IP address */
struct ip_vs_dest_set set; /* destination server set */
unsigned long lastuse; /* last used time */
+ struct rcu_head rcu_head;
};
@@ -274,12 +283,14 @@ struct ip_vs_lblcr_entry {
* IPVS lblcr hash table
*/
struct ip_vs_lblcr_table {
- struct list_head bucket[IP_VS_LBLCR_TAB_SIZE]; /* hash bucket */
+ struct rcu_head rcu_head;
+ struct hlist_head bucket[IP_VS_LBLCR_TAB_SIZE]; /* hash bucket */
atomic_t entries; /* number of entries */
int max_size; /* maximum size of entries */
struct timer_list periodic_timer; /* collect stale entries */
int rover; /* rover for expire check */
int counter; /* counter for no expire */
+ bool dead;
};
@@ -302,9 +313,9 @@ static ctl_table vs_vars_table[] = {
static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
{
- list_del(&en->list);
+ hlist_del_rcu(&en->list);
ip_vs_dest_set_eraseall(&en->set);
- kfree(en);
+ kfree_rcu(en, rcu_head);
}
@@ -334,15 +345,12 @@ ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
{
unsigned int hash = ip_vs_lblcr_hashkey(en->af, &en->addr);
- list_add(&en->list, &tbl->bucket[hash]);
+ hlist_add_head_rcu(&en->list, &tbl->bucket[hash]);
atomic_inc(&tbl->entries);
}
-/*
- * Get ip_vs_lblcr_entry associated with supplied parameters. Called under
- * read lock.
- */
+/* Get ip_vs_lblcr_entry associated with supplied parameters. */
static inline struct ip_vs_lblcr_entry *
ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
const union nf_inet_addr *addr)
@@ -350,7 +358,7 @@ ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
unsigned int hash = ip_vs_lblcr_hashkey(af, addr);
struct ip_vs_lblcr_entry *en;
- list_for_each_entry(en, &tbl->bucket[hash], list)
+ hlist_for_each_entry_rcu(en, &tbl->bucket[hash], list)
if (ip_vs_addr_equal(af, &en->addr, addr))
return en;
@@ -360,7 +368,7 @@ ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl,
/*
* Create or update an ip_vs_lblcr_entry, which is a mapping of a destination
- * IP address to a server. Called under write lock.
+ * IP address to a server. Called under spin lock.
*/
static inline struct ip_vs_lblcr_entry *
ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
@@ -381,14 +389,14 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
/* initialize its dest set */
atomic_set(&(en->set.size), 0);
INIT_LIST_HEAD(&en->set.list);
- rwlock_init(&en->set.lock);
+
+ ip_vs_dest_set_insert(&en->set, dest, false);
ip_vs_lblcr_hash(tbl, en);
+ return en;
}
- write_lock(&en->set.lock);
- ip_vs_dest_set_insert(&en->set, dest);
- write_unlock(&en->set.lock);
+ ip_vs_dest_set_insert(&en->set, dest, true);
return en;
}
@@ -397,17 +405,21 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr,
/*
* Flush all the entries of the specified table.
*/
-static void ip_vs_lblcr_flush(struct ip_vs_lblcr_table *tbl)
+static void ip_vs_lblcr_flush(struct ip_vs_service *svc)
{
+ struct ip_vs_lblcr_table *tbl = svc->sched_data;
int i;
- struct ip_vs_lblcr_entry *en, *nxt;
+ struct ip_vs_lblcr_entry *en;
+ struct hlist_node *next;
- /* No locking required, only called during cleanup. */
+ spin_lock_bh(&svc->sched_lock);
+ tbl->dead = 1;
for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
- list_for_each_entry_safe(en, nxt, &tbl->bucket[i], list) {
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
ip_vs_lblcr_free(en);
}
}
+ spin_unlock_bh(&svc->sched_lock);
}
static int sysctl_lblcr_expiration(struct ip_vs_service *svc)
@@ -425,13 +437,14 @@ static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
struct ip_vs_lblcr_table *tbl = svc->sched_data;
unsigned long now = jiffies;
int i, j;
- struct ip_vs_lblcr_entry *en, *nxt;
+ struct ip_vs_lblcr_entry *en;
+ struct hlist_node *next;
for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
- write_lock(&svc->sched_lock);
- list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+ spin_lock(&svc->sched_lock);
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
if (time_after(en->lastuse +
sysctl_lblcr_expiration(svc), now))
continue;
@@ -439,7 +452,7 @@ static inline void ip_vs_lblcr_full_check(struct ip_vs_service *svc)
ip_vs_lblcr_free(en);
atomic_dec(&tbl->entries);
}
- write_unlock(&svc->sched_lock);
+ spin_unlock(&svc->sched_lock);
}
tbl->rover = j;
}
@@ -463,7 +476,8 @@ static void ip_vs_lblcr_check_expire(unsigned long data)
unsigned long now = jiffies;
int goal;
int i, j;
- struct ip_vs_lblcr_entry *en, *nxt;
+ struct ip_vs_lblcr_entry *en;
+ struct hlist_node *next;
if ((tbl->counter % COUNT_FOR_FULL_EXPIRATION) == 0) {
/* do full expiration check */
@@ -484,8 +498,8 @@ static void ip_vs_lblcr_check_expire(unsigned long data)
for (i=0, j=tbl->rover; i<IP_VS_LBLCR_TAB_SIZE; i++) {
j = (j + 1) & IP_VS_LBLCR_TAB_MASK;
- write_lock(&svc->sched_lock);
- list_for_each_entry_safe(en, nxt, &tbl->bucket[j], list) {
+ spin_lock(&svc->sched_lock);
+ hlist_for_each_entry_safe(en, next, &tbl->bucket[j], list) {
if (time_before(now, en->lastuse+ENTRY_TIMEOUT))
continue;
@@ -493,7 +507,7 @@ static void ip_vs_lblcr_check_expire(unsigned long data)
atomic_dec(&tbl->entries);
goal--;
}
- write_unlock(&svc->sched_lock);
+ spin_unlock(&svc->sched_lock);
if (goal <= 0)
break;
}
@@ -523,11 +537,12 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
* Initialize the hash buckets
*/
for (i=0; i<IP_VS_LBLCR_TAB_SIZE; i++) {
- INIT_LIST_HEAD(&tbl->bucket[i]);
+ INIT_HLIST_HEAD(&tbl->bucket[i]);
}
tbl->max_size = IP_VS_LBLCR_TAB_SIZE*16;
tbl->rover = 0;
tbl->counter = 1;
+ tbl->dead = 0;
/*
* Hook periodic timer for garbage collection
@@ -540,7 +555,7 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc)
}
-static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
+static void ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
{
struct ip_vs_lblcr_table *tbl = svc->sched_data;
@@ -548,14 +563,12 @@ static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc)
del_timer_sync(&tbl->periodic_timer);
/* got to clean up table entries here */
- ip_vs_lblcr_flush(tbl);
+ ip_vs_lblcr_flush(svc);
/* release the table itself */
- kfree(tbl);
+ kfree_rcu(tbl, rcu_head);
IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) released\n",
sizeof(*tbl));
-
- return 0;
}
@@ -577,7 +590,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
* The server with weight=0 is quiesced and will not receive any
* new connection.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -593,7 +606,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
* Find the destination with the least load.
*/
nextstage:
- list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+ list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
@@ -627,7 +640,7 @@ is_overloaded(struct ip_vs_dest *dest, struct ip_vs_service *svc)
if (atomic_read(&dest->activeconns) > atomic_read(&dest->weight)) {
struct ip_vs_dest *d;
- list_for_each_entry(d, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(d, &svc->destinations, n_list) {
if (atomic_read(&d->activeconns)*2
< atomic_read(&d->weight)) {
return 1;
@@ -646,7 +659,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
struct ip_vs_lblcr_table *tbl = svc->sched_data;
struct ip_vs_iphdr iph;
- struct ip_vs_dest *dest = NULL;
+ struct ip_vs_dest *dest;
struct ip_vs_lblcr_entry *en;
ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
@@ -654,53 +667,46 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
/* First look in our cache */
- read_lock(&svc->sched_lock);
en = ip_vs_lblcr_get(svc->af, tbl, &iph.daddr);
if (en) {
- /* We only hold a read lock, but this is atomic */
en->lastuse = jiffies;
/* Get the least loaded destination */
- read_lock(&en->set.lock);
dest = ip_vs_dest_set_min(&en->set);
- read_unlock(&en->set.lock);
/* More than one destination + enough time passed by, cleanup */
if (atomic_read(&en->set.size) > 1 &&
- time_after(jiffies, en->set.lastmod +
+ time_after(jiffies, en->set.lastmod +
sysctl_lblcr_expiration(svc))) {
- struct ip_vs_dest *m;
+ spin_lock_bh(&svc->sched_lock);
+ if (atomic_read(&en->set.size) > 1) {
+ struct ip_vs_dest *m;
- write_lock(&en->set.lock);
- m = ip_vs_dest_set_max(&en->set);
- if (m)
- ip_vs_dest_set_erase(&en->set, m);
- write_unlock(&en->set.lock);
+ m = ip_vs_dest_set_max(&en->set);
+ if (m)
+ ip_vs_dest_set_erase(&en->set, m);
+ }
+ spin_unlock_bh(&svc->sched_lock);
}
/* If the destination is not overloaded, use it */
- if (dest && !is_overloaded(dest, svc)) {
- read_unlock(&svc->sched_lock);
+ if (dest && !is_overloaded(dest, svc))
goto out;
- }
/* The cache entry is invalid, time to schedule */
dest = __ip_vs_lblcr_schedule(svc);
if (!dest) {
ip_vs_scheduler_err(svc, "no destination available");
- read_unlock(&svc->sched_lock);
return NULL;
}
/* Update our cache entry */
- write_lock(&en->set.lock);
- ip_vs_dest_set_insert(&en->set, dest);
- write_unlock(&en->set.lock);
- }
- read_unlock(&svc->sched_lock);
-
- if (dest)
+ spin_lock_bh(&svc->sched_lock);
+ if (!tbl->dead)
+ ip_vs_dest_set_insert(&en->set, dest, true);
+ spin_unlock_bh(&svc->sched_lock);
goto out;
+ }
/* No cache entry, time to schedule */
dest = __ip_vs_lblcr_schedule(svc);
@@ -710,9 +716,10 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
}
/* If we fail to create a cache entry, we'll just use the valid dest */
- write_lock(&svc->sched_lock);
- ip_vs_lblcr_new(tbl, &iph.daddr, dest);
- write_unlock(&svc->sched_lock);
+ spin_lock_bh(&svc->sched_lock);
+ if (!tbl->dead)
+ ip_vs_lblcr_new(tbl, &iph.daddr, dest);
+ spin_unlock_bh(&svc->sched_lock);
out:
IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n",
@@ -814,6 +821,7 @@ static void __exit ip_vs_lblcr_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
unregister_pernet_subsys(&ip_vs_lblcr_ops);
+ synchronize_rcu();
}
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c
index f391819c0cca..5128e338a749 100644
--- a/net/netfilter/ipvs/ip_vs_lc.c
+++ b/net/netfilter/ipvs/ip_vs_lc.c
@@ -42,7 +42,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* served, but no new connection is assigned to the server.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
atomic_read(&dest->weight) == 0)
continue;
@@ -84,6 +84,7 @@ static int __init ip_vs_lc_init(void)
static void __exit ip_vs_lc_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_lc_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_lc_init);
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c
index 984d9c137d84..646cfd4baa73 100644
--- a/net/netfilter/ipvs/ip_vs_nq.c
+++ b/net/netfilter/ipvs/ip_vs_nq.c
@@ -75,7 +75,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* new connections.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
!atomic_read(&dest->weight))
@@ -133,6 +133,7 @@ static int __init ip_vs_nq_init(void)
static void __exit ip_vs_nq_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_nq_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_nq_init);
diff --git a/net/netfilter/ipvs/ip_vs_pe.c b/net/netfilter/ipvs/ip_vs_pe.c
index 5cf859ccb31b..1a82b29ce8ea 100644
--- a/net/netfilter/ipvs/ip_vs_pe.c
+++ b/net/netfilter/ipvs/ip_vs_pe.c
@@ -13,20 +13,8 @@
/* IPVS pe list */
static LIST_HEAD(ip_vs_pe);
-/* lock for service table */
-static DEFINE_SPINLOCK(ip_vs_pe_lock);
-
-/* Bind a service with a pe */
-void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe)
-{
- svc->pe = pe;
-}
-
-/* Unbind a service from its pe */
-void ip_vs_unbind_pe(struct ip_vs_service *svc)
-{
- svc->pe = NULL;
-}
+/* semaphore for IPVS PEs. */
+static DEFINE_MUTEX(ip_vs_pe_mutex);
/* Get pe in the pe list by name */
struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name)
@@ -36,9 +24,8 @@ struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name)
IP_VS_DBG(10, "%s(): pe_name \"%s\"\n", __func__,
pe_name);
- spin_lock_bh(&ip_vs_pe_lock);
-
- list_for_each_entry(pe, &ip_vs_pe, n_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(pe, &ip_vs_pe, n_list) {
/* Test and get the modules atomically */
if (pe->module &&
!try_module_get(pe->module)) {
@@ -47,14 +34,14 @@ struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name)
}
if (strcmp(pe_name, pe->name)==0) {
/* HIT */
- spin_unlock_bh(&ip_vs_pe_lock);
+ rcu_read_unlock();
return pe;
}
if (pe->module)
module_put(pe->module);
}
+ rcu_read_unlock();
- spin_unlock_bh(&ip_vs_pe_lock);
return NULL;
}
@@ -83,22 +70,13 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
/* increase the module use count */
ip_vs_use_count_inc();
- spin_lock_bh(&ip_vs_pe_lock);
-
- if (!list_empty(&pe->n_list)) {
- spin_unlock_bh(&ip_vs_pe_lock);
- ip_vs_use_count_dec();
- pr_err("%s(): [%s] pe already linked\n",
- __func__, pe->name);
- return -EINVAL;
- }
-
+ mutex_lock(&ip_vs_pe_mutex);
/* Make sure that the pe with this name doesn't exist
* in the pe list.
*/
list_for_each_entry(tmp, &ip_vs_pe, n_list) {
if (strcmp(tmp->name, pe->name) == 0) {
- spin_unlock_bh(&ip_vs_pe_lock);
+ mutex_unlock(&ip_vs_pe_mutex);
ip_vs_use_count_dec();
pr_err("%s(): [%s] pe already existed "
"in the system\n", __func__, pe->name);
@@ -106,8 +84,8 @@ int register_ip_vs_pe(struct ip_vs_pe *pe)
}
}
/* Add it into the d-linked pe list */
- list_add(&pe->n_list, &ip_vs_pe);
- spin_unlock_bh(&ip_vs_pe_lock);
+ list_add_rcu(&pe->n_list, &ip_vs_pe);
+ mutex_unlock(&ip_vs_pe_mutex);
pr_info("[%s] pe registered.\n", pe->name);
@@ -118,17 +96,10 @@ EXPORT_SYMBOL_GPL(register_ip_vs_pe);
/* Unregister a pe from the pe list */
int unregister_ip_vs_pe(struct ip_vs_pe *pe)
{
- spin_lock_bh(&ip_vs_pe_lock);
- if (list_empty(&pe->n_list)) {
- spin_unlock_bh(&ip_vs_pe_lock);
- pr_err("%s(): [%s] pe is not in the list. failed\n",
- __func__, pe->name);
- return -EINVAL;
- }
-
+ mutex_lock(&ip_vs_pe_mutex);
/* Remove it from the d-linked pe list */
- list_del(&pe->n_list);
- spin_unlock_bh(&ip_vs_pe_lock);
+ list_del_rcu(&pe->n_list);
+ mutex_unlock(&ip_vs_pe_mutex);
/* decrease the module use count */
ip_vs_use_count_dec();
diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c
index 12475ef88daf..9ef22bdce9f1 100644
--- a/net/netfilter/ipvs/ip_vs_pe_sip.c
+++ b/net/netfilter/ipvs/ip_vs_pe_sip.c
@@ -13,7 +13,8 @@ static const char *ip_vs_dbg_callid(char *buf, size_t buf_len,
const char *callid, size_t callid_len,
int *idx)
{
- size_t len = min(min(callid_len, (size_t)64), buf_len - *idx - 1);
+ size_t max_len = 64;
+ size_t len = min3(max_len, callid_len, buf_len - *idx - 1);
memcpy(buf + *idx, callid, len);
buf[*idx+len] = '\0';
*idx += len + 1;
@@ -37,14 +38,10 @@ static int get_callid(const char *dptr, unsigned int dataoff,
if (ret > 0)
break;
if (!ret)
- return 0;
+ return -EINVAL;
dataoff += *matchoff;
}
- /* Empty callid is useless */
- if (!*matchlen)
- return -EINVAL;
-
/* Too large is useless */
if (*matchlen > IP_VS_PEDATA_MAXLEN)
return -EINVAL;
@@ -172,6 +169,7 @@ static int __init ip_vs_sip_init(void)
static void __exit ip_vs_sip_cleanup(void)
{
unregister_ip_vs_pe(&ip_vs_sip_pe);
+ synchronize_rcu();
}
module_init(ip_vs_sip_init);
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index cd1d7298f7ba..86464881cd20 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -27,9 +27,10 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
if (sch == NULL)
return 0;
net = skb_net(skb);
+ rcu_read_lock();
if ((sch->type == SCTP_CID_INIT) &&
- (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
- &iph->daddr, sh->dest))) {
+ (svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
+ &iph->daddr, sh->dest))) {
int ignored;
if (ip_vs_todrop(net_ipvs(net))) {
@@ -37,7 +38,7 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* It seems that we are very loaded.
* We have to drop this packet :(
*/
- ip_vs_service_put(svc);
+ rcu_read_unlock();
*verdict = NF_DROP;
return 0;
}
@@ -49,14 +50,13 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
if (!*cpp && ignored <= 0) {
if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd, iph);
- else {
- ip_vs_service_put(svc);
+ else
*verdict = NF_DROP;
- }
+ rcu_read_unlock();
return 0;
}
- ip_vs_service_put(svc);
}
+ rcu_read_unlock();
/* NF_ACCEPT */
return 1;
}
@@ -208,7 +208,7 @@ enum ipvs_sctp_event_t {
IP_VS_SCTP_EVE_LAST
};
-static enum ipvs_sctp_event_t sctp_events[255] = {
+static enum ipvs_sctp_event_t sctp_events[256] = {
IP_VS_SCTP_EVE_DATA_CLI,
IP_VS_SCTP_EVE_INIT_CLI,
IP_VS_SCTP_EVE_INIT_ACK_CLI,
@@ -994,9 +994,9 @@ static void
sctp_state_transition(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb, struct ip_vs_proto_data *pd)
{
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
set_sctp_state(pd, cp, direction, skb);
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
}
static inline __u16 sctp_app_hashkey(__be16 port)
@@ -1016,30 +1016,25 @@ static int sctp_register_app(struct net *net, struct ip_vs_app *inc)
hash = sctp_app_hashkey(port);
- spin_lock_bh(&ipvs->sctp_app_lock);
list_for_each_entry(i, &ipvs->sctp_apps[hash], p_list) {
if (i->port == port) {
ret = -EEXIST;
goto out;
}
}
- list_add(&inc->p_list, &ipvs->sctp_apps[hash]);
+ list_add_rcu(&inc->p_list, &ipvs->sctp_apps[hash]);
atomic_inc(&pd->appcnt);
out:
- spin_unlock_bh(&ipvs->sctp_app_lock);
return ret;
}
static void sctp_unregister_app(struct net *net, struct ip_vs_app *inc)
{
- struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_SCTP);
- spin_lock_bh(&ipvs->sctp_app_lock);
atomic_dec(&pd->appcnt);
- list_del(&inc->p_list);
- spin_unlock_bh(&ipvs->sctp_app_lock);
+ list_del_rcu(&inc->p_list);
}
static int sctp_app_conn_bind(struct ip_vs_conn *cp)
@@ -1055,12 +1050,12 @@ static int sctp_app_conn_bind(struct ip_vs_conn *cp)
/* Lookup application incarnations and bind the right one */
hash = sctp_app_hashkey(cp->vport);
- spin_lock(&ipvs->sctp_app_lock);
- list_for_each_entry(inc, &ipvs->sctp_apps[hash], p_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(inc, &ipvs->sctp_apps[hash], p_list) {
if (inc->port == cp->vport) {
if (unlikely(!ip_vs_app_inc_get(inc)))
break;
- spin_unlock(&ipvs->sctp_app_lock);
+ rcu_read_unlock();
IP_VS_DBG_BUF(9, "%s: Binding conn %s:%u->"
"%s:%u to app %s on port %u\n",
@@ -1076,7 +1071,7 @@ static int sctp_app_conn_bind(struct ip_vs_conn *cp)
goto out;
}
}
- spin_unlock(&ipvs->sctp_app_lock);
+ rcu_read_unlock();
out:
return result;
}
@@ -1090,7 +1085,6 @@ static int __ip_vs_sctp_init(struct net *net, struct ip_vs_proto_data *pd)
struct netns_ipvs *ipvs = net_ipvs(net);
ip_vs_init_hash_table(ipvs->sctp_apps, SCTP_APP_TAB_SIZE);
- spin_lock_init(&ipvs->sctp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)sctp_timeouts,
sizeof(sctp_timeouts));
if (!pd->timeout_table)
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 9af653a75825..50a15944c6c1 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -47,9 +47,10 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
}
net = skb_net(skb);
/* No !th->ack check to allow scheduling on SYN+ACK for Active FTP */
+ rcu_read_lock();
if (th->syn &&
- (svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
- &iph->daddr, th->dest))) {
+ (svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
+ &iph->daddr, th->dest))) {
int ignored;
if (ip_vs_todrop(net_ipvs(net))) {
@@ -57,7 +58,7 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* It seems that we are very loaded.
* We have to drop this packet :(
*/
- ip_vs_service_put(svc);
+ rcu_read_unlock();
*verdict = NF_DROP;
return 0;
}
@@ -70,14 +71,13 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
if (!*cpp && ignored <= 0) {
if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd, iph);
- else {
- ip_vs_service_put(svc);
+ else
*verdict = NF_DROP;
- }
+ rcu_read_unlock();
return 0;
}
- ip_vs_service_put(svc);
}
+ rcu_read_unlock();
/* NF_ACCEPT */
return 1;
}
@@ -557,9 +557,9 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
if (th == NULL)
return;
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
set_tcp_state(pd, cp, direction, th);
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
}
static inline __u16 tcp_app_hashkey(__be16 port)
@@ -580,18 +580,16 @@ static int tcp_register_app(struct net *net, struct ip_vs_app *inc)
hash = tcp_app_hashkey(port);
- spin_lock_bh(&ipvs->tcp_app_lock);
list_for_each_entry(i, &ipvs->tcp_apps[hash], p_list) {
if (i->port == port) {
ret = -EEXIST;
goto out;
}
}
- list_add(&inc->p_list, &ipvs->tcp_apps[hash]);
+ list_add_rcu(&inc->p_list, &ipvs->tcp_apps[hash]);
atomic_inc(&pd->appcnt);
out:
- spin_unlock_bh(&ipvs->tcp_app_lock);
return ret;
}
@@ -599,13 +597,10 @@ static int tcp_register_app(struct net *net, struct ip_vs_app *inc)
static void
tcp_unregister_app(struct net *net, struct ip_vs_app *inc)
{
- struct netns_ipvs *ipvs = net_ipvs(net);
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
- spin_lock_bh(&ipvs->tcp_app_lock);
atomic_dec(&pd->appcnt);
- list_del(&inc->p_list);
- spin_unlock_bh(&ipvs->tcp_app_lock);
+ list_del_rcu(&inc->p_list);
}
@@ -624,12 +619,12 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
/* Lookup application incarnations and bind the right one */
hash = tcp_app_hashkey(cp->vport);
- spin_lock(&ipvs->tcp_app_lock);
- list_for_each_entry(inc, &ipvs->tcp_apps[hash], p_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(inc, &ipvs->tcp_apps[hash], p_list) {
if (inc->port == cp->vport) {
if (unlikely(!ip_vs_app_inc_get(inc)))
break;
- spin_unlock(&ipvs->tcp_app_lock);
+ rcu_read_unlock();
IP_VS_DBG_BUF(9, "%s(): Binding conn %s:%u->"
"%s:%u to app %s on port %u\n",
@@ -646,7 +641,7 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
goto out;
}
}
- spin_unlock(&ipvs->tcp_app_lock);
+ rcu_read_unlock();
out:
return result;
@@ -660,11 +655,11 @@ void ip_vs_tcp_conn_listen(struct net *net, struct ip_vs_conn *cp)
{
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
cp->state = IP_VS_TCP_S_LISTEN;
cp->timeout = (pd ? pd->timeout_table[IP_VS_TCP_S_LISTEN]
: tcp_timeouts[IP_VS_TCP_S_LISTEN]);
- spin_unlock(&cp->lock);
+ spin_unlock_bh(&cp->lock);
}
/* ---------------------------------------------
@@ -676,7 +671,6 @@ static int __ip_vs_tcp_init(struct net *net, struct ip_vs_proto_data *pd)
struct netns_ipvs *ipvs = net_ipvs(net);
ip_vs_init_hash_table(ipvs->tcp_apps, TCP_APP_TAB_SIZE);
- spin_lock_init(&ipvs->tcp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)tcp_timeouts,
sizeof(tcp_timeouts));
if (!pd->timeout_table)
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index 503a842c90d2..b62a3c0ff9bf 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -44,8 +44,9 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
return 0;
}
net = skb_net(skb);
- svc = ip_vs_service_get(net, af, skb->mark, iph->protocol,
- &iph->daddr, uh->dest);
+ rcu_read_lock();
+ svc = ip_vs_service_find(net, af, skb->mark, iph->protocol,
+ &iph->daddr, uh->dest);
if (svc) {
int ignored;
@@ -54,7 +55,7 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
* It seems that we are very loaded.
* We have to drop this packet :(
*/
- ip_vs_service_put(svc);
+ rcu_read_unlock();
*verdict = NF_DROP;
return 0;
}
@@ -67,14 +68,13 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
if (!*cpp && ignored <= 0) {
if (!ignored)
*verdict = ip_vs_leave(svc, skb, pd, iph);
- else {
- ip_vs_service_put(svc);
+ else
*verdict = NF_DROP;
- }
+ rcu_read_unlock();
return 0;
}
- ip_vs_service_put(svc);
}
+ rcu_read_unlock();
/* NF_ACCEPT */
return 1;
}
@@ -359,19 +359,16 @@ static int udp_register_app(struct net *net, struct ip_vs_app *inc)
hash = udp_app_hashkey(port);
-
- spin_lock_bh(&ipvs->udp_app_lock);
list_for_each_entry(i, &ipvs->udp_apps[hash], p_list) {
if (i->port == port) {
ret = -EEXIST;
goto out;
}
}
- list_add(&inc->p_list, &ipvs->udp_apps[hash]);
+ list_add_rcu(&inc->p_list, &ipvs->udp_apps[hash]);
atomic_inc(&pd->appcnt);
out:
- spin_unlock_bh(&ipvs->udp_app_lock);
return ret;
}
@@ -380,12 +377,9 @@ static void
udp_unregister_app(struct net *net, struct ip_vs_app *inc)
{
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(net, IPPROTO_UDP);
- struct netns_ipvs *ipvs = net_ipvs(net);
- spin_lock_bh(&ipvs->udp_app_lock);
atomic_dec(&pd->appcnt);
- list_del(&inc->p_list);
- spin_unlock_bh(&ipvs->udp_app_lock);
+ list_del_rcu(&inc->p_list);
}
@@ -403,12 +397,12 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
/* Lookup application incarnations and bind the right one */
hash = udp_app_hashkey(cp->vport);
- spin_lock(&ipvs->udp_app_lock);
- list_for_each_entry(inc, &ipvs->udp_apps[hash], p_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(inc, &ipvs->udp_apps[hash], p_list) {
if (inc->port == cp->vport) {
if (unlikely(!ip_vs_app_inc_get(inc)))
break;
- spin_unlock(&ipvs->udp_app_lock);
+ rcu_read_unlock();
IP_VS_DBG_BUF(9, "%s(): Binding conn %s:%u->"
"%s:%u to app %s on port %u\n",
@@ -425,7 +419,7 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
goto out;
}
}
- spin_unlock(&ipvs->udp_app_lock);
+ rcu_read_unlock();
out:
return result;
@@ -467,7 +461,6 @@ static int __udp_init(struct net *net, struct ip_vs_proto_data *pd)
struct netns_ipvs *ipvs = net_ipvs(net);
ip_vs_init_hash_table(ipvs->udp_apps, UDP_APP_TAB_SIZE);
- spin_lock_init(&ipvs->udp_app_lock);
pd->timeout_table = ip_vs_create_timeout_table((int *)udp_timeouts,
sizeof(udp_timeouts));
if (!pd->timeout_table)
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c
index c49b388d1085..c35986c793d9 100644
--- a/net/netfilter/ipvs/ip_vs_rr.c
+++ b/net/netfilter/ipvs/ip_vs_rr.c
@@ -35,9 +35,18 @@ static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
}
-static int ip_vs_rr_update_svc(struct ip_vs_service *svc)
+static int ip_vs_rr_del_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest)
{
- svc->sched_data = &svc->destinations;
+ struct list_head *p;
+
+ spin_lock_bh(&svc->sched_lock);
+ p = (struct list_head *) svc->sched_data;
+ /* dest is already unlinked, so p->prev is not valid but
+ * p->next is valid, use it to reach previous entry.
+ */
+ if (p == &dest->n_list)
+ svc->sched_data = p->next->prev;
+ spin_unlock_bh(&svc->sched_lock);
return 0;
}
@@ -48,36 +57,41 @@ static int ip_vs_rr_update_svc(struct ip_vs_service *svc)
static struct ip_vs_dest *
ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
- struct list_head *p, *q;
- struct ip_vs_dest *dest;
+ struct list_head *p;
+ struct ip_vs_dest *dest, *last;
+ int pass = 0;
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
- write_lock(&svc->sched_lock);
- p = (struct list_head *)svc->sched_data;
- p = p->next;
- q = p;
+ spin_lock_bh(&svc->sched_lock);
+ p = (struct list_head *) svc->sched_data;
+ last = dest = list_entry(p, struct ip_vs_dest, n_list);
+
do {
- /* skip list head */
- if (q == &svc->destinations) {
- q = q->next;
- continue;
+ list_for_each_entry_continue_rcu(dest,
+ &svc->destinations,
+ n_list) {
+ if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
+ atomic_read(&dest->weight) > 0)
+ /* HIT */
+ goto out;
+ if (dest == last)
+ goto stop;
}
-
- dest = list_entry(q, struct ip_vs_dest, n_list);
- if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
- atomic_read(&dest->weight) > 0)
- /* HIT */
- goto out;
- q = q->next;
- } while (q != p);
- write_unlock(&svc->sched_lock);
+ pass++;
+ /* Previous dest could be unlinked, do not loop forever.
+ * If we stay at head there is no need for 2nd pass.
+ */
+ } while (pass < 2 && p != &svc->destinations);
+
+stop:
+ spin_unlock_bh(&svc->sched_lock);
ip_vs_scheduler_err(svc, "no destination available");
return NULL;
out:
- svc->sched_data = q;
- write_unlock(&svc->sched_lock);
+ svc->sched_data = &dest->n_list;
+ spin_unlock_bh(&svc->sched_lock);
IP_VS_DBG_BUF(6, "RR: server %s:%u "
"activeconns %d refcnt %d weight %d\n",
IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
@@ -94,7 +108,8 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = {
.module = THIS_MODULE,
.n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
.init_service = ip_vs_rr_init_svc,
- .update_service = ip_vs_rr_update_svc,
+ .add_dest = NULL,
+ .del_dest = ip_vs_rr_del_dest,
.schedule = ip_vs_rr_schedule,
};
@@ -106,6 +121,7 @@ static int __init ip_vs_rr_init(void)
static void __exit ip_vs_rr_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_rr_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_rr_init);
diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c
index d6bf20d6cdbe..4dbcda6258bc 100644
--- a/net/netfilter/ipvs/ip_vs_sched.c
+++ b/net/netfilter/ipvs/ip_vs_sched.c
@@ -35,8 +35,8 @@ EXPORT_SYMBOL(ip_vs_scheduler_err);
*/
static LIST_HEAD(ip_vs_schedulers);
-/* lock for service table */
-static DEFINE_SPINLOCK(ip_vs_sched_lock);
+/* semaphore for schedulers */
+static DEFINE_MUTEX(ip_vs_sched_mutex);
/*
@@ -47,8 +47,6 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc,
{
int ret;
- svc->scheduler = scheduler;
-
if (scheduler->init_service) {
ret = scheduler->init_service(svc);
if (ret) {
@@ -56,7 +54,7 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc,
return ret;
}
}
-
+ rcu_assign_pointer(svc->scheduler, scheduler);
return 0;
}
@@ -64,22 +62,19 @@ int ip_vs_bind_scheduler(struct ip_vs_service *svc,
/*
* Unbind a service with its scheduler
*/
-int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
+void ip_vs_unbind_scheduler(struct ip_vs_service *svc,
+ struct ip_vs_scheduler *sched)
{
- struct ip_vs_scheduler *sched = svc->scheduler;
+ struct ip_vs_scheduler *cur_sched;
- if (!sched)
- return 0;
+ cur_sched = rcu_dereference_protected(svc->scheduler, 1);
+ /* This check proves that old 'sched' was installed */
+ if (!cur_sched)
+ return;
- if (sched->done_service) {
- if (sched->done_service(svc) != 0) {
- pr_err("%s(): done error\n", __func__);
- return -EINVAL;
- }
- }
-
- svc->scheduler = NULL;
- return 0;
+ if (sched->done_service)
+ sched->done_service(svc);
+ /* svc->scheduler can not be set to NULL */
}
@@ -92,7 +87,7 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
IP_VS_DBG(2, "%s(): sched_name \"%s\"\n", __func__, sched_name);
- spin_lock_bh(&ip_vs_sched_lock);
+ mutex_lock(&ip_vs_sched_mutex);
list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
/*
@@ -106,14 +101,14 @@ static struct ip_vs_scheduler *ip_vs_sched_getbyname(const char *sched_name)
}
if (strcmp(sched_name, sched->name)==0) {
/* HIT */
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
return sched;
}
if (sched->module)
module_put(sched->module);
}
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
return NULL;
}
@@ -153,21 +148,21 @@ void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg)
{
+ struct ip_vs_scheduler *sched;
+
+ sched = rcu_dereference(svc->scheduler);
if (svc->fwmark) {
IP_VS_ERR_RL("%s: FWM %u 0x%08X - %s\n",
- svc->scheduler->name, svc->fwmark,
- svc->fwmark, msg);
+ sched->name, svc->fwmark, svc->fwmark, msg);
#ifdef CONFIG_IP_VS_IPV6
} else if (svc->af == AF_INET6) {
IP_VS_ERR_RL("%s: %s [%pI6c]:%d - %s\n",
- svc->scheduler->name,
- ip_vs_proto_name(svc->protocol),
+ sched->name, ip_vs_proto_name(svc->protocol),
&svc->addr.in6, ntohs(svc->port), msg);
#endif
} else {
IP_VS_ERR_RL("%s: %s %pI4:%d - %s\n",
- svc->scheduler->name,
- ip_vs_proto_name(svc->protocol),
+ sched->name, ip_vs_proto_name(svc->protocol),
&svc->addr.ip, ntohs(svc->port), msg);
}
}
@@ -192,10 +187,10 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
/* increase the module use count */
ip_vs_use_count_inc();
- spin_lock_bh(&ip_vs_sched_lock);
+ mutex_lock(&ip_vs_sched_mutex);
if (!list_empty(&scheduler->n_list)) {
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
ip_vs_use_count_dec();
pr_err("%s(): [%s] scheduler already linked\n",
__func__, scheduler->name);
@@ -208,7 +203,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
*/
list_for_each_entry(sched, &ip_vs_schedulers, n_list) {
if (strcmp(scheduler->name, sched->name) == 0) {
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
ip_vs_use_count_dec();
pr_err("%s(): [%s] scheduler already existed "
"in the system\n", __func__, scheduler->name);
@@ -219,7 +214,7 @@ int register_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
* Add it into the d-linked scheduler list
*/
list_add(&scheduler->n_list, &ip_vs_schedulers);
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
pr_info("[%s] scheduler registered.\n", scheduler->name);
@@ -237,9 +232,9 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
return -EINVAL;
}
- spin_lock_bh(&ip_vs_sched_lock);
+ mutex_lock(&ip_vs_sched_mutex);
if (list_empty(&scheduler->n_list)) {
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
pr_err("%s(): [%s] scheduler is not in the list. failed\n",
__func__, scheduler->name);
return -EINVAL;
@@ -249,7 +244,7 @@ int unregister_ip_vs_scheduler(struct ip_vs_scheduler *scheduler)
* Remove it from the d-linked scheduler list
*/
list_del(&scheduler->n_list);
- spin_unlock_bh(&ip_vs_sched_lock);
+ mutex_unlock(&ip_vs_sched_mutex);
/* decrease the module use count */
ip_vs_use_count_dec();
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c
index 89ead246ed3d..f3205925359a 100644
--- a/net/netfilter/ipvs/ip_vs_sed.c
+++ b/net/netfilter/ipvs/ip_vs_sed.c
@@ -79,7 +79,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* new connections.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
atomic_read(&dest->weight) > 0) {
least = dest;
@@ -94,7 +94,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* Find the destination with the least load.
*/
nextstage:
- list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+ list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
doh = ip_vs_sed_dest_overhead(dest);
@@ -134,6 +134,7 @@ static int __init ip_vs_sed_init(void)
static void __exit ip_vs_sed_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_sed_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_sed_init);
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index e33126994628..0df269d7c99f 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -53,7 +53,7 @@
* IPVS SH bucket
*/
struct ip_vs_sh_bucket {
- struct ip_vs_dest *dest; /* real server (cache) */
+ struct ip_vs_dest __rcu *dest; /* real server (cache) */
};
/*
@@ -66,6 +66,10 @@ struct ip_vs_sh_bucket {
#define IP_VS_SH_TAB_SIZE (1 << IP_VS_SH_TAB_BITS)
#define IP_VS_SH_TAB_MASK (IP_VS_SH_TAB_SIZE - 1)
+struct ip_vs_sh_state {
+ struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE];
+ struct rcu_head rcu_head;
+};
/*
* Returns hash value for IPVS SH entry
@@ -87,10 +91,9 @@ static inline unsigned int ip_vs_sh_hashkey(int af, const union nf_inet_addr *ad
* Get ip_vs_dest associated with supplied parameters.
*/
static inline struct ip_vs_dest *
-ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl,
- const union nf_inet_addr *addr)
+ip_vs_sh_get(int af, struct ip_vs_sh_state *s, const union nf_inet_addr *addr)
{
- return (tbl[ip_vs_sh_hashkey(af, addr)]).dest;
+ return rcu_dereference(s->buckets[ip_vs_sh_hashkey(af, addr)].dest);
}
@@ -98,27 +101,32 @@ ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl,
* Assign all the hash buckets of the specified table with the service.
*/
static int
-ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc)
+ip_vs_sh_reassign(struct ip_vs_sh_state *s, struct ip_vs_service *svc)
{
int i;
struct ip_vs_sh_bucket *b;
struct list_head *p;
struct ip_vs_dest *dest;
int d_count;
+ bool empty;
- b = tbl;
+ b = &s->buckets[0];
p = &svc->destinations;
+ empty = list_empty(p);
d_count = 0;
for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
- if (list_empty(p)) {
- b->dest = NULL;
- } else {
+ dest = rcu_dereference_protected(b->dest, 1);
+ if (dest)
+ ip_vs_dest_put(dest);
+ if (empty)
+ RCU_INIT_POINTER(b->dest, NULL);
+ else {
if (p == &svc->destinations)
p = p->next;
dest = list_entry(p, struct ip_vs_dest, n_list);
- atomic_inc(&dest->refcnt);
- b->dest = dest;
+ ip_vs_dest_hold(dest);
+ RCU_INIT_POINTER(b->dest, dest);
IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n",
i, IP_VS_DBG_ADDR(svc->af, &dest->addr),
@@ -140,16 +148,18 @@ ip_vs_sh_assign(struct ip_vs_sh_bucket *tbl, struct ip_vs_service *svc)
/*
* Flush all the hash buckets of the specified table.
*/
-static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl)
+static void ip_vs_sh_flush(struct ip_vs_sh_state *s)
{
int i;
struct ip_vs_sh_bucket *b;
+ struct ip_vs_dest *dest;
- b = tbl;
+ b = &s->buckets[0];
for (i=0; i<IP_VS_SH_TAB_SIZE; i++) {
- if (b->dest) {
- atomic_dec(&b->dest->refcnt);
- b->dest = NULL;
+ dest = rcu_dereference_protected(b->dest, 1);
+ if (dest) {
+ ip_vs_dest_put(dest);
+ RCU_INIT_POINTER(b->dest, NULL);
}
b++;
}
@@ -158,51 +168,46 @@ static void ip_vs_sh_flush(struct ip_vs_sh_bucket *tbl)
static int ip_vs_sh_init_svc(struct ip_vs_service *svc)
{
- struct ip_vs_sh_bucket *tbl;
+ struct ip_vs_sh_state *s;
/* allocate the SH table for this service */
- tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE,
- GFP_KERNEL);
- if (tbl == NULL)
+ s = kzalloc(sizeof(struct ip_vs_sh_state), GFP_KERNEL);
+ if (s == NULL)
return -ENOMEM;
- svc->sched_data = tbl;
+ svc->sched_data = s;
IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for "
"current service\n",
sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
- /* assign the hash buckets with the updated service */
- ip_vs_sh_assign(tbl, svc);
+ /* assign the hash buckets with current dests */
+ ip_vs_sh_reassign(s, svc);
return 0;
}
-static int ip_vs_sh_done_svc(struct ip_vs_service *svc)
+static void ip_vs_sh_done_svc(struct ip_vs_service *svc)
{
- struct ip_vs_sh_bucket *tbl = svc->sched_data;
+ struct ip_vs_sh_state *s = svc->sched_data;
/* got to clean up hash buckets here */
- ip_vs_sh_flush(tbl);
+ ip_vs_sh_flush(s);
/* release the table itself */
- kfree(svc->sched_data);
+ kfree_rcu(s, rcu_head);
IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) released\n",
sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE);
-
- return 0;
}
-static int ip_vs_sh_update_svc(struct ip_vs_service *svc)
+static int ip_vs_sh_dest_changed(struct ip_vs_service *svc,
+ struct ip_vs_dest *dest)
{
- struct ip_vs_sh_bucket *tbl = svc->sched_data;
-
- /* got to clean up hash buckets here */
- ip_vs_sh_flush(tbl);
+ struct ip_vs_sh_state *s = svc->sched_data;
/* assign the hash buckets with the updated service */
- ip_vs_sh_assign(tbl, svc);
+ ip_vs_sh_reassign(s, svc);
return 0;
}
@@ -225,15 +230,15 @@ static struct ip_vs_dest *
ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
struct ip_vs_dest *dest;
- struct ip_vs_sh_bucket *tbl;
+ struct ip_vs_sh_state *s;
struct ip_vs_iphdr iph;
ip_vs_fill_iph_addr_only(svc->af, skb, &iph);
IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n");
- tbl = (struct ip_vs_sh_bucket *)svc->sched_data;
- dest = ip_vs_sh_get(svc->af, tbl, &iph.saddr);
+ s = (struct ip_vs_sh_state *) svc->sched_data;
+ dest = ip_vs_sh_get(svc->af, s, &iph.saddr);
if (!dest
|| !(dest->flags & IP_VS_DEST_F_AVAILABLE)
|| atomic_read(&dest->weight) <= 0
@@ -262,7 +267,9 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler =
.n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list),
.init_service = ip_vs_sh_init_svc,
.done_service = ip_vs_sh_done_svc,
- .update_service = ip_vs_sh_update_svc,
+ .add_dest = ip_vs_sh_dest_changed,
+ .del_dest = ip_vs_sh_dest_changed,
+ .upd_dest = ip_vs_sh_dest_changed,
.schedule = ip_vs_sh_schedule,
};
@@ -276,6 +283,7 @@ static int __init ip_vs_sh_init(void)
static void __exit ip_vs_sh_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_sh_scheduler);
+ synchronize_rcu();
}
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index 44fd10c539ac..f6046d9af8d3 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -246,7 +246,7 @@ struct ip_vs_sync_thread_data {
struct ip_vs_sync_mesg_v0 {
__u8 nr_conns;
__u8 syncid;
- __u16 size;
+ __be16 size;
/* ip_vs_sync_conn entries start here */
};
@@ -255,7 +255,7 @@ struct ip_vs_sync_mesg_v0 {
struct ip_vs_sync_mesg {
__u8 reserved; /* must be zero */
__u8 syncid;
- __u16 size;
+ __be16 size;
__u8 nr_conns;
__s8 version; /* SYNC_PROTO_VER */
__u16 spare;
@@ -335,7 +335,7 @@ ip_vs_sync_buff_create(struct netns_ipvs *ipvs)
sb->mesg->reserved = 0; /* old nr_conns i.e. must be zero now */
sb->mesg->version = SYNC_PROTO_VER;
sb->mesg->syncid = ipvs->master_syncid;
- sb->mesg->size = sizeof(struct ip_vs_sync_mesg);
+ sb->mesg->size = htons(sizeof(struct ip_vs_sync_mesg));
sb->mesg->nr_conns = 0;
sb->mesg->spare = 0;
sb->head = (unsigned char *)sb->mesg + sizeof(struct ip_vs_sync_mesg);
@@ -418,7 +418,7 @@ ip_vs_sync_buff_create_v0(struct netns_ipvs *ipvs)
mesg = (struct ip_vs_sync_mesg_v0 *)sb->mesg;
mesg->nr_conns = 0;
mesg->syncid = ipvs->master_syncid;
- mesg->size = sizeof(struct ip_vs_sync_mesg_v0);
+ mesg->size = htons(sizeof(struct ip_vs_sync_mesg_v0));
sb->head = (unsigned char *)mesg + sizeof(struct ip_vs_sync_mesg_v0);
sb->end = (unsigned char *)mesg + ipvs->send_mesg_maxlen;
sb->firstuse = jiffies;
@@ -531,9 +531,9 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
if (!ip_vs_sync_conn_needed(ipvs, cp, pkts))
return;
- spin_lock(&ipvs->sync_buff_lock);
+ spin_lock_bh(&ipvs->sync_buff_lock);
if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) {
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
return;
}
@@ -552,7 +552,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
if (!buff) {
buff = ip_vs_sync_buff_create_v0(ipvs);
if (!buff) {
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
pr_err("ip_vs_sync_buff_create failed.\n");
return;
}
@@ -582,7 +582,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
}
m->nr_conns++;
- m->size += len;
+ m->size = htons(ntohs(m->size) + len);
buff->head += len;
/* check if there is a space for next one */
@@ -590,7 +590,7 @@ static void ip_vs_sync_conn_v0(struct net *net, struct ip_vs_conn *cp,
sb_queue_tail(ipvs, ms);
ms->sync_buff = NULL;
}
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
/* synchronize its controller if it has */
cp = cp->control;
@@ -641,9 +641,9 @@ sloop:
pe_name_len = strnlen(cp->pe->name, IP_VS_PENAME_MAXLEN);
}
- spin_lock(&ipvs->sync_buff_lock);
+ spin_lock_bh(&ipvs->sync_buff_lock);
if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) {
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
return;
}
@@ -683,7 +683,7 @@ sloop:
if (!buff) {
buff = ip_vs_sync_buff_create(ipvs);
if (!buff) {
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
pr_err("ip_vs_sync_buff_create failed.\n");
return;
}
@@ -693,7 +693,7 @@ sloop:
p = buff->head;
buff->head += pad + len;
- m->size += pad + len;
+ m->size = htons(ntohs(m->size) + pad + len);
/* Add ev. padding from prev. sync_conn */
while (pad--)
*(p++) = 0;
@@ -750,7 +750,7 @@ sloop:
}
}
- spin_unlock(&ipvs->sync_buff_lock);
+ spin_unlock_bh(&ipvs->sync_buff_lock);
control:
/* synchronize its controller if it has */
@@ -843,7 +843,7 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
kfree(param->pe_data);
dest = cp->dest;
- spin_lock(&cp->lock);
+ spin_lock_bh(&cp->lock);
if ((cp->flags ^ flags) & IP_VS_CONN_F_INACTIVE &&
!(flags & IP_VS_CONN_F_TEMPLATE) && dest) {
if (flags & IP_VS_CONN_F_INACTIVE) {
@@ -857,24 +857,21 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
flags &= IP_VS_CONN_F_BACKUP_UPD_MASK;
flags |= cp->flags & ~IP_VS_CONN_F_BACKUP_UPD_MASK;
cp->flags = flags;
- spin_unlock(&cp->lock);
- if (!dest) {
- dest = ip_vs_try_bind_dest(cp);
- if (dest)
- atomic_dec(&dest->refcnt);
- }
+ spin_unlock_bh(&cp->lock);
+ if (!dest)
+ ip_vs_try_bind_dest(cp);
} else {
/*
* Find the appropriate destination for the connection.
* If it is not found the connection will remain unbound
* but still handled.
*/
+ rcu_read_lock();
dest = ip_vs_find_dest(net, type, daddr, dport, param->vaddr,
param->vport, protocol, fwmark, flags);
cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark);
- if (dest)
- atomic_dec(&dest->refcnt);
+ rcu_read_unlock();
if (!cp) {
if (param->pe_data)
kfree(param->pe_data);
@@ -1178,10 +1175,8 @@ static void ip_vs_process_message(struct net *net, __u8 *buffer,
IP_VS_DBG(2, "BACKUP, message header too short\n");
return;
}
- /* Convert size back to host byte order */
- m2->size = ntohs(m2->size);
- if (buflen != m2->size) {
+ if (buflen != ntohs(m2->size)) {
IP_VS_DBG(2, "BACKUP, bogus message size\n");
return;
}
@@ -1547,10 +1542,7 @@ ip_vs_send_sync_msg(struct socket *sock, struct ip_vs_sync_mesg *msg)
int msize;
int ret;
- msize = msg->size;
-
- /* Put size in network byte order */
- msg->size = htons(msg->size);
+ msize = ntohs(msg->size);
ret = ip_vs_send_async(sock, (char *)msg, msize);
if (ret >= 0 || ret == -EAGAIN)
@@ -1692,11 +1684,7 @@ static int sync_thread_backup(void *data)
break;
}
- /* disable bottom half, because it accesses the data
- shared by softirq while getting/creating conns */
- local_bh_disable();
ip_vs_process_message(tinfo->net, tinfo->buf, len);
- local_bh_enable();
}
}
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c
index bc1bfc48a17f..c60a81c4ce9a 100644
--- a/net/netfilter/ipvs/ip_vs_wlc.c
+++ b/net/netfilter/ipvs/ip_vs_wlc.c
@@ -51,7 +51,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* new connections.
*/
- list_for_each_entry(dest, &svc->destinations, n_list) {
+ list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
atomic_read(&dest->weight) > 0) {
least = dest;
@@ -66,7 +66,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* Find the destination with the least load.
*/
nextstage:
- list_for_each_entry_continue(dest, &svc->destinations, n_list) {
+ list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
continue;
doh = ip_vs_dest_conn_overhead(dest);
@@ -106,6 +106,7 @@ static int __init ip_vs_wlc_init(void)
static void __exit ip_vs_wlc_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_wlc_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_wlc_init);
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c
index 231be7dd547a..0e68555bceb9 100644
--- a/net/netfilter/ipvs/ip_vs_wrr.c
+++ b/net/netfilter/ipvs/ip_vs_wrr.c
@@ -29,14 +29,45 @@
#include <net/ip_vs.h>
+/* The WRR algorithm depends on some caclulations:
+ * - mw: maximum weight
+ * - di: weight step, greatest common divisor from all weights
+ * - cw: current required weight
+ * As result, all weights are in the [di..mw] range with a step=di.
+ *
+ * First, we start with cw = mw and select dests with weight >= cw.
+ * Then cw is reduced with di and all dests are checked again.
+ * Last pass should be with cw = di. We have mw/di passes in total:
+ *
+ * pass 1: cw = max weight
+ * pass 2: cw = max weight - di
+ * pass 3: cw = max weight - 2 * di
+ * ...
+ * last pass: cw = di
+ *
+ * Weights are supposed to be >= di but we run in parallel with
+ * weight changes, it is possible some dest weight to be reduced
+ * below di, bad if it is the only available dest.
+ *
+ * So, we modify how mw is calculated, now it is reduced with (di - 1),
+ * so that last cw is 1 to catch such dests with weight below di:
+ * pass 1: cw = max weight - (di - 1)
+ * pass 2: cw = max weight - di - (di - 1)
+ * pass 3: cw = max weight - 2 * di - (di - 1)
+ * ...
+ * last pass: cw = 1
+ *
+ */
+
/*
* current destination pointer for weighted round-robin scheduling
*/
struct ip_vs_wrr_mark {
- struct list_head *cl; /* current list head */
+ struct ip_vs_dest *cl; /* current dest or head */
int cw; /* current weight */
int mw; /* maximum weight */
int di; /* decreasing interval */
+ struct rcu_head rcu_head;
};
@@ -88,36 +119,41 @@ static int ip_vs_wrr_init_svc(struct ip_vs_service *svc)
if (mark == NULL)
return -ENOMEM;
- mark->cl = &svc->destinations;
- mark->cw = 0;
- mark->mw = ip_vs_wrr_max_weight(svc);
+ mark->cl = list_entry(&svc->destinations, struct ip_vs_dest, n_list);
mark->di = ip_vs_wrr_gcd_weight(svc);
+ mark->mw = ip_vs_wrr_max_weight(svc) - (mark->di - 1);
+ mark->cw = mark->mw;
svc->sched_data = mark;
return 0;
}
-static int ip_vs_wrr_done_svc(struct ip_vs_service *svc)
+static void ip_vs_wrr_done_svc(struct ip_vs_service *svc)
{
+ struct ip_vs_wrr_mark *mark = svc->sched_data;
+
/*
* Release the mark variable
*/
- kfree(svc->sched_data);
-
- return 0;
+ kfree_rcu(mark, rcu_head);
}
-static int ip_vs_wrr_update_svc(struct ip_vs_service *svc)
+static int ip_vs_wrr_dest_changed(struct ip_vs_service *svc,
+ struct ip_vs_dest *dest)
{
struct ip_vs_wrr_mark *mark = svc->sched_data;
- mark->cl = &svc->destinations;
- mark->mw = ip_vs_wrr_max_weight(svc);
+ spin_lock_bh(&svc->sched_lock);
+ mark->cl = list_entry(&svc->destinations, struct ip_vs_dest, n_list);
mark->di = ip_vs_wrr_gcd_weight(svc);
- if (mark->cw > mark->mw)
- mark->cw = 0;
+ mark->mw = ip_vs_wrr_max_weight(svc) - (mark->di - 1);
+ if (mark->cw > mark->mw || !mark->cw)
+ mark->cw = mark->mw;
+ else if (mark->di > 1)
+ mark->cw = (mark->cw / mark->di) * mark->di + 1;
+ spin_unlock_bh(&svc->sched_lock);
return 0;
}
@@ -128,80 +164,79 @@ static int ip_vs_wrr_update_svc(struct ip_vs_service *svc)
static struct ip_vs_dest *
ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
{
- struct ip_vs_dest *dest;
+ struct ip_vs_dest *dest, *last, *stop = NULL;
struct ip_vs_wrr_mark *mark = svc->sched_data;
- struct list_head *p;
+ bool last_pass = false, restarted = false;
IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
- /*
- * This loop will always terminate, because mark->cw in (0, max_weight]
- * and at least one server has its weight equal to max_weight.
- */
- write_lock(&svc->sched_lock);
- p = mark->cl;
+ spin_lock_bh(&svc->sched_lock);
+ dest = mark->cl;
+ /* No available dests? */
+ if (mark->mw == 0)
+ goto err_noavail;
+ last = dest;
+ /* Stop only after all dests were checked for weight >= 1 (last pass) */
while (1) {
- if (mark->cl == &svc->destinations) {
- /* it is at the head of the destination list */
-
- if (mark->cl == mark->cl->next) {
- /* no dest entry */
- ip_vs_scheduler_err(svc,
- "no destination available: "
- "no destinations present");
- dest = NULL;
- goto out;
- }
-
- mark->cl = svc->destinations.next;
- mark->cw -= mark->di;
- if (mark->cw <= 0) {
- mark->cw = mark->mw;
- /*
- * Still zero, which means no available servers.
- */
- if (mark->cw == 0) {
- mark->cl = &svc->destinations;
- ip_vs_scheduler_err(svc,
- "no destination available");
- dest = NULL;
- goto out;
- }
- }
- } else
- mark->cl = mark->cl->next;
-
- if (mark->cl != &svc->destinations) {
- /* not at the head of the list */
- dest = list_entry(mark->cl, struct ip_vs_dest, n_list);
+ list_for_each_entry_continue_rcu(dest,
+ &svc->destinations,
+ n_list) {
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
- atomic_read(&dest->weight) >= mark->cw) {
- /* got it */
- break;
- }
+ atomic_read(&dest->weight) >= mark->cw)
+ goto found;
+ if (dest == stop)
+ goto err_over;
}
-
- if (mark->cl == p && mark->cw == mark->di) {
- /* back to the start, and no dest is found.
- It is only possible when all dests are OVERLOADED */
- dest = NULL;
- ip_vs_scheduler_err(svc,
- "no destination available: "
- "all destinations are overloaded");
- goto out;
+ mark->cw -= mark->di;
+ if (mark->cw <= 0) {
+ mark->cw = mark->mw;
+ /* Stop if we tried last pass from first dest:
+ * 1. last_pass: we started checks when cw > di but
+ * then all dests were checked for w >= 1
+ * 2. last was head: the first and only traversal
+ * was for weight >= 1, for all dests.
+ */
+ if (last_pass ||
+ &last->n_list == &svc->destinations)
+ goto err_over;
+ restarted = true;
+ }
+ last_pass = mark->cw <= mark->di;
+ if (last_pass && restarted &&
+ &last->n_list != &svc->destinations) {
+ /* First traversal was for w >= 1 but only
+ * for dests after 'last', now do the same
+ * for all dests up to 'last'.
+ */
+ stop = last;
}
}
+found:
IP_VS_DBG_BUF(6, "WRR: server %s:%u "
"activeconns %d refcnt %d weight %d\n",
IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port),
atomic_read(&dest->activeconns),
atomic_read(&dest->refcnt),
atomic_read(&dest->weight));
+ mark->cl = dest;
out:
- write_unlock(&svc->sched_lock);
+ spin_unlock_bh(&svc->sched_lock);
return dest;
+
+err_noavail:
+ mark->cl = dest;
+ dest = NULL;
+ ip_vs_scheduler_err(svc, "no destination available");
+ goto out;
+
+err_over:
+ mark->cl = dest;
+ dest = NULL;
+ ip_vs_scheduler_err(svc, "no destination available: "
+ "all destinations are overloaded");
+ goto out;
}
@@ -212,7 +247,9 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
.n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list),
.init_service = ip_vs_wrr_init_svc,
.done_service = ip_vs_wrr_done_svc,
- .update_service = ip_vs_wrr_update_svc,
+ .add_dest = ip_vs_wrr_dest_changed,
+ .del_dest = ip_vs_wrr_dest_changed,
+ .upd_dest = ip_vs_wrr_dest_changed,
.schedule = ip_vs_wrr_schedule,
};
@@ -224,6 +261,7 @@ static int __init ip_vs_wrr_init(void)
static void __exit ip_vs_wrr_cleanup(void)
{
unregister_ip_vs_scheduler(&ip_vs_wrr_scheduler);
+ synchronize_rcu();
}
module_init(ip_vs_wrr_init);
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index ee6b7a9f1ec2..b75ff6429a04 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -17,6 +17,8 @@
* - not all connections have destination server, for example,
* connections in backup server when fwmark is used
* - bypass connections use daddr from packet
+ * - we can use dst without ref while sending in RCU section, we use
+ * ref when returning NF_ACCEPT for NAT-ed packet via loopback
* LOCAL_OUT rules:
* - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
* - skb->pkt_type is not set yet
@@ -51,39 +53,54 @@ enum {
*/
IP_VS_RT_MODE_CONNECT = 8, /* Always bind route to saddr */
IP_VS_RT_MODE_KNOWN_NH = 16,/* Route via remote addr */
+ IP_VS_RT_MODE_TUNNEL = 32,/* Tunnel mode */
};
+static inline struct ip_vs_dest_dst *ip_vs_dest_dst_alloc(void)
+{
+ return kmalloc(sizeof(struct ip_vs_dest_dst), GFP_ATOMIC);
+}
+
+static inline void ip_vs_dest_dst_free(struct ip_vs_dest_dst *dest_dst)
+{
+ kfree(dest_dst);
+}
+
/*
* Destination cache to speed up outgoing route lookup
*/
static inline void
-__ip_vs_dst_set(struct ip_vs_dest *dest, u32 rtos, struct dst_entry *dst,
- u32 dst_cookie)
+__ip_vs_dst_set(struct ip_vs_dest *dest, struct ip_vs_dest_dst *dest_dst,
+ struct dst_entry *dst, u32 dst_cookie)
{
- struct dst_entry *old_dst;
+ struct ip_vs_dest_dst *old;
+
+ old = rcu_dereference_protected(dest->dest_dst,
+ lockdep_is_held(&dest->dst_lock));
- old_dst = dest->dst_cache;
- dest->dst_cache = dst;
- dest->dst_rtos = rtos;
- dest->dst_cookie = dst_cookie;
- dst_release(old_dst);
+ if (dest_dst) {
+ dest_dst->dst_cache = dst;
+ dest_dst->dst_cookie = dst_cookie;
+ }
+ rcu_assign_pointer(dest->dest_dst, dest_dst);
+
+ if (old)
+ call_rcu(&old->rcu_head, ip_vs_dest_dst_rcu_free);
}
-static inline struct dst_entry *
-__ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
+static inline struct ip_vs_dest_dst *
+__ip_vs_dst_check(struct ip_vs_dest *dest)
{
- struct dst_entry *dst = dest->dst_cache;
+ struct ip_vs_dest_dst *dest_dst = rcu_dereference(dest->dest_dst);
+ struct dst_entry *dst;
- if (!dst)
+ if (!dest_dst)
return NULL;
- if ((dst->obsolete || rtos != dest->dst_rtos) &&
- dst->ops->check(dst, dest->dst_cookie) == NULL) {
- dest->dst_cache = NULL;
- dst_release(dst);
+ dst = dest_dst->dst_cache;
+ if (dst->obsolete &&
+ dst->ops->check(dst, dest_dst->dst_cookie) == NULL)
return NULL;
- }
- dst_hold(dst);
- return dst;
+ return dest_dst;
}
static inline bool
@@ -104,7 +121,7 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
/* Get route to daddr, update *saddr, optionally bind route to saddr */
static struct rtable *do_output_route4(struct net *net, __be32 daddr,
- u32 rtos, int rt_mode, __be32 *saddr)
+ int rt_mode, __be32 *saddr)
{
struct flowi4 fl4;
struct rtable *rt;
@@ -113,7 +130,6 @@ static struct rtable *do_output_route4(struct net *net, __be32 daddr,
memset(&fl4, 0, sizeof(fl4));
fl4.daddr = daddr;
fl4.saddr = (rt_mode & IP_VS_RT_MODE_CONNECT) ? *saddr : 0;
- fl4.flowi4_tos = rtos;
fl4.flowi4_flags = (rt_mode & IP_VS_RT_MODE_KNOWN_NH) ?
FLOWI_FLAG_KNOWN_NH : 0;
@@ -124,7 +140,7 @@ retry:
if (PTR_ERR(rt) == -EINVAL && *saddr &&
rt_mode & IP_VS_RT_MODE_CONNECT && !loop) {
*saddr = 0;
- flowi4_update_output(&fl4, 0, rtos, daddr, 0);
+ flowi4_update_output(&fl4, 0, 0, daddr, 0);
goto retry;
}
IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", &daddr);
@@ -132,7 +148,7 @@ retry:
} else if (!*saddr && rt_mode & IP_VS_RT_MODE_CONNECT && fl4.saddr) {
ip_rt_put(rt);
*saddr = fl4.saddr;
- flowi4_update_output(&fl4, 0, rtos, daddr, fl4.saddr);
+ flowi4_update_output(&fl4, 0, 0, daddr, fl4.saddr);
loop++;
goto retry;
}
@@ -141,113 +157,140 @@ retry:
}
/* Get route to destination or remote server */
-static struct rtable *
+static int
__ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
- __be32 daddr, u32 rtos, int rt_mode, __be32 *ret_saddr)
+ __be32 daddr, int rt_mode, __be32 *ret_saddr)
{
struct net *net = dev_net(skb_dst(skb)->dev);
+ struct netns_ipvs *ipvs = net_ipvs(net);
+ struct ip_vs_dest_dst *dest_dst;
struct rtable *rt; /* Route to the other host */
struct rtable *ort; /* Original route */
- int local;
+ struct iphdr *iph;
+ __be16 df;
+ int mtu;
+ int local, noref = 1;
if (dest) {
- spin_lock(&dest->dst_lock);
- if (!(rt = (struct rtable *)
- __ip_vs_dst_check(dest, rtos))) {
- rt = do_output_route4(net, dest->addr.ip, rtos,
- rt_mode, &dest->dst_saddr.ip);
+ dest_dst = __ip_vs_dst_check(dest);
+ if (likely(dest_dst))
+ rt = (struct rtable *) dest_dst->dst_cache;
+ else {
+ dest_dst = ip_vs_dest_dst_alloc();
+ spin_lock_bh(&dest->dst_lock);
+ if (!dest_dst) {
+ __ip_vs_dst_set(dest, NULL, NULL, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ goto err_unreach;
+ }
+ rt = do_output_route4(net, dest->addr.ip, rt_mode,
+ &dest_dst->dst_saddr.ip);
if (!rt) {
- spin_unlock(&dest->dst_lock);
- return NULL;
+ __ip_vs_dst_set(dest, NULL, NULL, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ ip_vs_dest_dst_free(dest_dst);
+ goto err_unreach;
}
- __ip_vs_dst_set(dest, rtos, dst_clone(&rt->dst), 0);
- IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d, "
- "rtos=%X\n",
- &dest->addr.ip, &dest->dst_saddr.ip,
- atomic_read(&rt->dst.__refcnt), rtos);
+ __ip_vs_dst_set(dest, dest_dst, &rt->dst, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d\n",
+ &dest->addr.ip, &dest_dst->dst_saddr.ip,
+ atomic_read(&rt->dst.__refcnt));
}
daddr = dest->addr.ip;
if (ret_saddr)
- *ret_saddr = dest->dst_saddr.ip;
- spin_unlock(&dest->dst_lock);
+ *ret_saddr = dest_dst->dst_saddr.ip;
} else {
__be32 saddr = htonl(INADDR_ANY);
+ noref = 0;
+
/* For such unconfigured boxes avoid many route lookups
* for performance reasons because we do not remember saddr
*/
rt_mode &= ~IP_VS_RT_MODE_CONNECT;
- rt = do_output_route4(net, daddr, rtos, rt_mode, &saddr);
+ rt = do_output_route4(net, daddr, rt_mode, &saddr);
if (!rt)
- return NULL;
+ goto err_unreach;
if (ret_saddr)
*ret_saddr = saddr;
}
- local = rt->rt_flags & RTCF_LOCAL;
+ local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0;
if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) &
rt_mode)) {
IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n",
(rt->rt_flags & RTCF_LOCAL) ?
"local":"non-local", &daddr);
- ip_rt_put(rt);
- return NULL;
- }
- if (local && !(rt_mode & IP_VS_RT_MODE_RDR) &&
- !((ort = skb_rtable(skb)) && ort->rt_flags & RTCF_LOCAL)) {
- IP_VS_DBG_RL("Redirect from non-local address %pI4 to local "
- "requires NAT method, dest: %pI4\n",
- &ip_hdr(skb)->daddr, &daddr);
- ip_rt_put(rt);
- return NULL;
+ goto err_put;
}
- if (unlikely(!local && ipv4_is_loopback(ip_hdr(skb)->saddr))) {
- IP_VS_DBG_RL("Stopping traffic from loopback address %pI4 "
- "to non-local address, dest: %pI4\n",
- &ip_hdr(skb)->saddr, &daddr);
- ip_rt_put(rt);
- return NULL;
+ iph = ip_hdr(skb);
+ if (likely(!local)) {
+ if (unlikely(ipv4_is_loopback(iph->saddr))) {
+ IP_VS_DBG_RL("Stopping traffic from loopback address "
+ "%pI4 to non-local address, dest: %pI4\n",
+ &iph->saddr, &daddr);
+ goto err_put;
+ }
+ } else {
+ ort = skb_rtable(skb);
+ if (!(rt_mode & IP_VS_RT_MODE_RDR) &&
+ !(ort->rt_flags & RTCF_LOCAL)) {
+ IP_VS_DBG_RL("Redirect from non-local address %pI4 to "
+ "local requires NAT method, dest: %pI4\n",
+ &iph->daddr, &daddr);
+ goto err_put;
+ }
+ /* skb to local stack, preserve old route */
+ if (!noref)
+ ip_rt_put(rt);
+ return local;
}
- return rt;
-}
-
-/* Reroute packet to local IPv4 stack after DNAT */
-static int
-__ip_vs_reroute_locally(struct sk_buff *skb)
-{
- struct rtable *rt = skb_rtable(skb);
- struct net_device *dev = rt->dst.dev;
- struct net *net = dev_net(dev);
- struct iphdr *iph = ip_hdr(skb);
-
- if (rt_is_input_route(rt)) {
- unsigned long orefdst = skb->_skb_refdst;
-
- if (ip_route_input(skb, iph->daddr, iph->saddr,
- iph->tos, skb->dev))
- return 0;
- refdst_drop(orefdst);
+ if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) {
+ mtu = dst_mtu(&rt->dst);
+ df = iph->frag_off & htons(IP_DF);
} else {
- struct flowi4 fl4 = {
- .daddr = iph->daddr,
- .saddr = iph->saddr,
- .flowi4_tos = RT_TOS(iph->tos),
- .flowi4_mark = skb->mark,
- };
-
- rt = ip_route_output_key(net, &fl4);
- if (IS_ERR(rt))
- return 0;
- if (!(rt->rt_flags & RTCF_LOCAL)) {
- ip_rt_put(rt);
- return 0;
+ struct sock *sk = skb->sk;
+
+ mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
+ if (mtu < 68) {
+ IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
+ goto err_put;
}
- /* Drop old route. */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
+ ort = skb_rtable(skb);
+ if (!skb->dev && sk && sk->sk_state != TCP_TIME_WAIT)
+ ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu);
+ /* MTU check allowed? */
+ df = sysctl_pmtu_disc(ipvs) ? iph->frag_off & htons(IP_DF) : 0;
}
- return 1;
+
+ /* MTU checking */
+ if (unlikely(df && skb->len > mtu && !skb_is_gso(skb))) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ IP_VS_DBG(1, "frag needed for %pI4\n", &iph->saddr);
+ goto err_put;
+ }
+
+ skb_dst_drop(skb);
+ if (noref) {
+ if (!local)
+ skb_dst_set_noref_force(skb, &rt->dst);
+ else
+ skb_dst_set(skb, dst_clone(&rt->dst));
+ } else
+ skb_dst_set(skb, &rt->dst);
+
+ return local;
+
+err_put:
+ if (!noref)
+ ip_rt_put(rt);
+ return -1;
+
+err_unreach:
+ dst_link_failure(skb);
+ return -1;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -294,44 +337,57 @@ out_err:
/*
* Get route to destination or remote server
*/
-static struct rt6_info *
+static int
__ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
struct in6_addr *daddr, struct in6_addr *ret_saddr,
- int do_xfrm, int rt_mode)
+ struct ip_vs_iphdr *ipvsh, int do_xfrm, int rt_mode)
{
struct net *net = dev_net(skb_dst(skb)->dev);
+ struct ip_vs_dest_dst *dest_dst;
struct rt6_info *rt; /* Route to the other host */
struct rt6_info *ort; /* Original route */
struct dst_entry *dst;
- int local;
+ int mtu;
+ int local, noref = 1;
if (dest) {
- spin_lock(&dest->dst_lock);
- rt = (struct rt6_info *)__ip_vs_dst_check(dest, 0);
- if (!rt) {
+ dest_dst = __ip_vs_dst_check(dest);
+ if (likely(dest_dst))
+ rt = (struct rt6_info *) dest_dst->dst_cache;
+ else {
u32 cookie;
+ dest_dst = ip_vs_dest_dst_alloc();
+ spin_lock_bh(&dest->dst_lock);
+ if (!dest_dst) {
+ __ip_vs_dst_set(dest, NULL, NULL, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ goto err_unreach;
+ }
dst = __ip_vs_route_output_v6(net, &dest->addr.in6,
- &dest->dst_saddr.in6,
+ &dest_dst->dst_saddr.in6,
do_xfrm);
if (!dst) {
- spin_unlock(&dest->dst_lock);
- return NULL;
+ __ip_vs_dst_set(dest, NULL, NULL, 0);
+ spin_unlock_bh(&dest->dst_lock);
+ ip_vs_dest_dst_free(dest_dst);
+ goto err_unreach;
}
rt = (struct rt6_info *) dst;
cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
- __ip_vs_dst_set(dest, 0, dst_clone(&rt->dst), cookie);
+ __ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
+ spin_unlock_bh(&dest->dst_lock);
IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
- &dest->addr.in6, &dest->dst_saddr.in6,
+ &dest->addr.in6, &dest_dst->dst_saddr.in6,
atomic_read(&rt->dst.__refcnt));
}
if (ret_saddr)
- *ret_saddr = dest->dst_saddr.in6;
- spin_unlock(&dest->dst_lock);
+ *ret_saddr = dest_dst->dst_saddr.in6;
} else {
+ noref = 0;
dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
if (!dst)
- return NULL;
+ goto err_unreach;
rt = (struct rt6_info *) dst;
}
@@ -340,86 +396,137 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
rt_mode)) {
IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6c\n",
local ? "local":"non-local", daddr);
- dst_release(&rt->dst);
- return NULL;
+ goto err_put;
}
- if (local && !(rt_mode & IP_VS_RT_MODE_RDR) &&
- !((ort = (struct rt6_info *) skb_dst(skb)) &&
- __ip_vs_is_local_route6(ort))) {
- IP_VS_DBG_RL("Redirect from non-local address %pI6c to local "
- "requires NAT method, dest: %pI6c\n",
- &ipv6_hdr(skb)->daddr, daddr);
- dst_release(&rt->dst);
- return NULL;
+ if (likely(!local)) {
+ if (unlikely((!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
+ ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
+ IPV6_ADDR_LOOPBACK)) {
+ IP_VS_DBG_RL("Stopping traffic from loopback address "
+ "%pI6c to non-local address, "
+ "dest: %pI6c\n",
+ &ipv6_hdr(skb)->saddr, daddr);
+ goto err_put;
+ }
+ } else {
+ ort = (struct rt6_info *) skb_dst(skb);
+ if (!(rt_mode & IP_VS_RT_MODE_RDR) &&
+ !__ip_vs_is_local_route6(ort)) {
+ IP_VS_DBG_RL("Redirect from non-local address %pI6c "
+ "to local requires NAT method, "
+ "dest: %pI6c\n",
+ &ipv6_hdr(skb)->daddr, daddr);
+ goto err_put;
+ }
+ /* skb to local stack, preserve old route */
+ if (!noref)
+ dst_release(&rt->dst);
+ return local;
}
- if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
- ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
- IPV6_ADDR_LOOPBACK)) {
- IP_VS_DBG_RL("Stopping traffic from loopback address %pI6c "
- "to non-local address, dest: %pI6c\n",
- &ipv6_hdr(skb)->saddr, daddr);
- dst_release(&rt->dst);
- return NULL;
+
+ /* MTU checking */
+ if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL)))
+ mtu = dst_mtu(&rt->dst);
+ else {
+ struct sock *sk = skb->sk;
+
+ mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
+ if (mtu < IPV6_MIN_MTU) {
+ IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__,
+ IPV6_MIN_MTU);
+ goto err_put;
+ }
+ ort = (struct rt6_info *) skb_dst(skb);
+ if (!skb->dev && sk && sk->sk_state != TCP_TIME_WAIT)
+ ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu);
}
- return rt;
+ if (unlikely(__mtu_check_toobig_v6(skb, mtu))) {
+ if (!skb->dev)
+ skb->dev = net->loopback_dev;
+ /* only send ICMP too big on first fragment */
+ if (!ipvsh->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ IP_VS_DBG(1, "frag needed for %pI6c\n", &ipv6_hdr(skb)->saddr);
+ goto err_put;
+ }
+
+ skb_dst_drop(skb);
+ if (noref) {
+ if (!local)
+ skb_dst_set_noref_force(skb, &rt->dst);
+ else
+ skb_dst_set(skb, dst_clone(&rt->dst));
+ } else
+ skb_dst_set(skb, &rt->dst);
+
+ return local;
+
+err_put:
+ if (!noref)
+ dst_release(&rt->dst);
+ return -1;
+
+err_unreach:
+ dst_link_failure(skb);
+ return -1;
}
#endif
-/*
- * Release dest->dst_cache before a dest is removed
- */
-void
-ip_vs_dst_reset(struct ip_vs_dest *dest)
+/* return NF_ACCEPT to allow forwarding or other NF_xxx on error */
+static inline int ip_vs_tunnel_xmit_prepare(struct sk_buff *skb,
+ struct ip_vs_conn *cp)
{
- struct dst_entry *old_dst;
+ int ret = NF_ACCEPT;
+
+ skb->ipvs_property = 1;
+ if (unlikely(cp->flags & IP_VS_CONN_F_NFCT))
+ ret = ip_vs_confirm_conntrack(skb);
+ if (ret == NF_ACCEPT) {
+ nf_reset(skb);
+ skb_forward_csum(skb);
+ }
+ return ret;
+}
+
+/* return NF_STOLEN (sent) or NF_ACCEPT if local=1 (not sent) */
+static inline int ip_vs_nat_send_or_cont(int pf, struct sk_buff *skb,
+ struct ip_vs_conn *cp, int local)
+{
+ int ret = NF_STOLEN;
- old_dst = dest->dst_cache;
- dest->dst_cache = NULL;
- dst_release(old_dst);
- dest->dst_saddr.ip = 0;
+ skb->ipvs_property = 1;
+ if (likely(!(cp->flags & IP_VS_CONN_F_NFCT)))
+ ip_vs_notrack(skb);
+ else
+ ip_vs_update_conntrack(skb, cp, 1);
+ if (!local) {
+ skb_forward_csum(skb);
+ NF_HOOK(pf, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
+ dst_output);
+ } else
+ ret = NF_ACCEPT;
+ return ret;
}
-#define IP_VS_XMIT_TUNNEL(skb, cp) \
-({ \
- int __ret = NF_ACCEPT; \
- \
- (skb)->ipvs_property = 1; \
- if (unlikely((cp)->flags & IP_VS_CONN_F_NFCT)) \
- __ret = ip_vs_confirm_conntrack(skb); \
- if (__ret == NF_ACCEPT) { \
- nf_reset(skb); \
- skb_forward_csum(skb); \
- } \
- __ret; \
-})
-
-#define IP_VS_XMIT_NAT(pf, skb, cp, local) \
-do { \
- (skb)->ipvs_property = 1; \
- if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT))) \
- ip_vs_notrack(skb); \
- else \
- ip_vs_update_conntrack(skb, cp, 1); \
- if (local) \
- return NF_ACCEPT; \
- skb_forward_csum(skb); \
- NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
- skb_dst(skb)->dev, dst_output); \
-} while (0)
-
-#define IP_VS_XMIT(pf, skb, cp, local) \
-do { \
- (skb)->ipvs_property = 1; \
- if (likely(!((cp)->flags & IP_VS_CONN_F_NFCT))) \
- ip_vs_notrack(skb); \
- if (local) \
- return NF_ACCEPT; \
- skb_forward_csum(skb); \
- NF_HOOK(pf, NF_INET_LOCAL_OUT, (skb), NULL, \
- skb_dst(skb)->dev, dst_output); \
-} while (0)
+/* return NF_STOLEN (sent) or NF_ACCEPT if local=1 (not sent) */
+static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb,
+ struct ip_vs_conn *cp, int local)
+{
+ int ret = NF_STOLEN;
+
+ skb->ipvs_property = 1;
+ if (likely(!(cp->flags & IP_VS_CONN_F_NFCT)))
+ ip_vs_notrack(skb);
+ if (!local) {
+ skb_forward_csum(skb);
+ NF_HOOK(pf, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
+ dst_output);
+ } else
+ ret = NF_ACCEPT;
+ return ret;
+}
/*
@@ -430,7 +537,7 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
/* we do not touch skb and do not need pskb ptr */
- IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
+ return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
}
@@ -443,52 +550,29 @@ int
ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
- struct rtable *rt; /* Route to the other host */
struct iphdr *iph = ip_hdr(skb);
- int mtu;
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt(skb, NULL, iph->daddr, RT_TOS(iph->tos),
- IP_VS_RT_MODE_NON_LOCAL, NULL)))
- goto tx_error_icmp;
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
- !skb_is_gso(skb)) {
- ip_rt_put(rt);
- icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
+ rcu_read_lock();
+ if (__ip_vs_get_out_rt(skb, NULL, iph->daddr, IP_VS_RT_MODE_NON_LOCAL,
+ NULL) < 0)
goto tx_error;
- }
- /*
- * Call ip_send_check because we are not sure it is called
- * after ip_defrag. Is copy-on-write needed?
- */
- if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
- ip_rt_put(rt);
- return NF_STOLEN;
- }
- ip_send_check(ip_hdr(skb));
-
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
+ ip_send_check(iph);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 0);
+ ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
}
@@ -496,60 +580,27 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6
int
ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
- struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
+ struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
- struct rt6_info *rt; /* Route to the other host */
- int mtu;
-
EnterFunction(10);
- rt = __ip_vs_get_out_rt_v6(skb, NULL, &iph->daddr.in6, NULL, 0,
- IP_VS_RT_MODE_NON_LOCAL);
- if (!rt)
- goto tx_error_icmp;
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if (__mtu_check_toobig_v6(skb, mtu)) {
- if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- skb->dev = net->loopback_dev;
- }
- /* only send ICMP too big on first fragment */
- if (!iph->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- dst_release(&rt->dst);
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
+ rcu_read_lock();
+ if (__ip_vs_get_out_rt_v6(skb, NULL, &ipvsh->daddr.in6, NULL,
+ ipvsh, 0, IP_VS_RT_MODE_NON_LOCAL) < 0)
goto tx_error;
- }
-
- /*
- * Call ip_send_check because we are not sure it is called
- * after ip_defrag. Is copy-on-write needed?
- */
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (unlikely(skb == NULL)) {
- dst_release(&rt->dst);
- return NF_STOLEN;
- }
-
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 0);
+ ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
}
@@ -564,29 +615,30 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
struct rtable *rt; /* Route to the other host */
- int mtu;
- struct iphdr *iph = ip_hdr(skb);
- int local;
+ int local, rc, was_input;
EnterFunction(10);
+ rcu_read_lock();
/* check if it is a connection of no-client-port */
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
__be16 _pt, *p;
- p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
+
+ p = skb_header_pointer(skb, ipvsh->len, sizeof(_pt), &_pt);
if (p == NULL)
goto tx_error;
ip_vs_conn_fill_cport(cp, *p);
IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
}
- if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
- RT_TOS(iph->tos),
- IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_RDR, NULL)))
- goto tx_error_icmp;
- local = rt->rt_flags & RTCF_LOCAL;
+ was_input = rt_is_input_route(skb_rtable(skb));
+ local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_RDR, NULL);
+ if (local < 0)
+ goto tx_error;
+ rt = skb_rtable(skb);
/*
* Avoid duplicate tuple in reply direction for NAT traffic
* to local address when connection is sync-ed
@@ -600,57 +652,31 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0,
"ip_vs_nat_xmit(): "
"stopping DNAT to local address");
- goto tx_error_put;
+ goto tx_error;
}
}
#endif
/* From world but DNAT to loopback address? */
- if (local && ipv4_is_loopback(cp->daddr.ip) &&
- rt_is_input_route(skb_rtable(skb))) {
+ if (local && ipv4_is_loopback(cp->daddr.ip) && was_input) {
IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): "
"stopping DNAT to loopback address");
- goto tx_error_put;
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) &&
- !skb_is_gso(skb)) {
- icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0,
- "ip_vs_nat_xmit(): frag needed for");
- goto tx_error_put;
+ goto tx_error;
}
/* copy-on-write the packet before mangling it */
if (!skb_make_writable(skb, sizeof(struct iphdr)))
- goto tx_error_put;
+ goto tx_error;
if (skb_cow(skb, rt->dst.dev->hard_header_len))
- goto tx_error_put;
+ goto tx_error;
/* mangle the packet */
if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, ipvsh))
- goto tx_error_put;
+ goto tx_error;
ip_hdr(skb)->daddr = cp->daddr.ip;
ip_send_check(ip_hdr(skb));
- if (!local) {
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
- } else {
- ip_rt_put(rt);
- /*
- * Some IPv4 replies get local address from routes,
- * not from iph, so while we DNAT after routing
- * we need this second input/output route.
- */
- if (!__ip_vs_reroute_locally(skb))
- goto tx_error;
- }
-
IP_VS_DBG_PKT(10, AF_INET, pp, skb, 0, "After DNAT");
/* FIXME: when application helper enlarges the packet and the length
@@ -660,49 +686,48 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local);
+ rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
+ rcu_read_unlock();
LeaveFunction(10);
- return NF_STOLEN;
+ return rc;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
- tx_error_put:
- ip_rt_put(rt);
- goto tx_error;
}
#ifdef CONFIG_IP_VS_IPV6
int
ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
- struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
+ struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
struct rt6_info *rt; /* Route to the other host */
- int mtu;
- int local;
+ int local, rc;
EnterFunction(10);
+ rcu_read_lock();
/* check if it is a connection of no-client-port */
- if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph->fragoffs)) {
+ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !ipvsh->fragoffs)) {
__be16 _pt, *p;
- p = skb_header_pointer(skb, iph->len, sizeof(_pt), &_pt);
+ p = skb_header_pointer(skb, ipvsh->len, sizeof(_pt), &_pt);
if (p == NULL)
goto tx_error;
ip_vs_conn_fill_cport(cp, *p);
IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
}
- if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
- 0, (IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_RDR))))
- goto tx_error_icmp;
- local = __ip_vs_is_local_route6(rt);
+ local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ ipvsh, 0,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_RDR);
+ if (local < 0)
+ goto tx_error;
+ rt = (struct rt6_info *) skb_dst(skb);
/*
* Avoid duplicate tuple in reply direction for NAT traffic
* to local address when connection is sync-ed
@@ -716,7 +741,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
"ip_vs_nat_xmit_v6(): "
"stopping DNAT to local address");
- goto tx_error_put;
+ goto tx_error;
}
}
#endif
@@ -727,46 +752,21 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0,
"ip_vs_nat_xmit_v6(): "
"stopping DNAT to loopback address");
- goto tx_error_put;
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if (__mtu_check_toobig_v6(skb, mtu)) {
- if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- skb->dev = net->loopback_dev;
- }
- /* only send ICMP too big on first fragment */
- if (!iph->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
- "ip_vs_nat_xmit_v6(): frag needed for");
- goto tx_error_put;
+ goto tx_error;
}
/* copy-on-write the packet before mangling it */
if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
- goto tx_error_put;
+ goto tx_error;
if (skb_cow(skb, rt->dst.dev->hard_header_len))
- goto tx_error_put;
+ goto tx_error;
/* mangle the packet */
- if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, iph))
+ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, ipvsh))
goto tx_error;
ipv6_hdr(skb)->daddr = cp->daddr.in6;
- if (!local || !skb->dev) {
- /* drop the old route when skb is not shared */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
- } else {
- /* destined to loopback, do we need to change route? */
- dst_release(&rt->dst);
- }
-
IP_VS_DBG_PKT(10, AF_INET6, pp, skb, 0, "After DNAT");
/* FIXME: when application helper enlarges the packet and the length
@@ -776,20 +776,17 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local);
+ rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
+ rcu_read_unlock();
LeaveFunction(10);
- return NF_STOLEN;
+ return rc;
-tx_error_icmp:
- dst_link_failure(skb);
tx_error:
LeaveFunction(10);
kfree_skb(skb);
+ rcu_read_unlock();
return NF_STOLEN;
-tx_error_put:
- dst_release(&rt->dst);
- goto tx_error;
}
#endif
@@ -826,56 +823,40 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
__be16 df;
struct iphdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
- int mtu;
- int ret;
+ int ret, local;
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
- RT_TOS(tos), IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_CONNECT,
- &saddr)))
- goto tx_error_icmp;
- if (rt->rt_flags & RTCF_LOCAL) {
- ip_rt_put(rt);
- IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_CONNECT |
+ IP_VS_RT_MODE_TUNNEL, &saddr);
+ if (local < 0)
+ goto tx_error;
+ if (local) {
+ rcu_read_unlock();
+ return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
}
+ rt = skb_rtable(skb);
tdev = rt->dst.dev;
- mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr);
- if (mtu < 68) {
- IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__);
- goto tx_error_put;
- }
- if (rt_is_output_route(skb_rtable(skb)))
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-
/* Copy DF, reset fragment offset and MF */
df = sysctl_pmtu_disc(ipvs) ? old_iph->frag_off & htons(IP_DF) : 0;
- if (df && mtu < ntohs(old_iph->tot_len) && !skb_is_gso(skb)) {
- icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error_put;
- }
-
/*
* Okay, now see if we can stuff it in the buffer as-is.
*/
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr);
- if (skb_headroom(skb) < max_headroom
- || skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
struct sk_buff *new_skb =
skb_realloc_headroom(skb, max_headroom);
- if (!new_skb) {
- ip_rt_put(rt);
- kfree_skb(skb);
- IP_VS_ERR_RL("%s(): no memory\n", __func__);
- return NF_STOLEN;
- }
+
+ if (!new_skb)
+ goto tx_error;
consume_skb(skb);
skb = new_skb;
old_iph = ip_hdr(skb);
@@ -890,10 +871,6 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
skb_reset_network_header(skb);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/*
* Push down and install the IPIP header.
*/
@@ -911,25 +888,22 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- ret = IP_VS_XMIT_TUNNEL(skb, cp);
+ ret = ip_vs_tunnel_xmit_prepare(skb, cp);
if (ret == NF_ACCEPT)
ip_local_out(skb);
else if (ret == NF_DROP)
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
-tx_error_put:
- ip_rt_put(rt);
- goto tx_error;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -943,60 +917,37 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ipv6hdr *old_iph = ipv6_hdr(skb);
struct ipv6hdr *iph; /* Our new IP header */
unsigned int max_headroom; /* The extra header space needed */
- int mtu;
- int ret;
+ int ret, local;
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
- &saddr, 1, (IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL))))
- goto tx_error_icmp;
- if (__ip_vs_is_local_route6(rt)) {
- dst_release(&rt->dst);
- IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1);
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
+ &saddr, ipvsh, 1,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_TUNNEL);
+ if (local < 0)
+ goto tx_error;
+ if (local) {
+ rcu_read_unlock();
+ return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
}
+ rt = (struct rt6_info *) skb_dst(skb);
tdev = rt->dst.dev;
- mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr);
- if (mtu < IPV6_MIN_MTU) {
- IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__,
- IPV6_MIN_MTU);
- goto tx_error_put;
- }
- if (skb_dst(skb))
- skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
-
- /* MTU checking: Notice that 'mtu' have been adjusted before hand */
- if (__mtu_check_toobig_v6(skb, mtu)) {
- if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- skb->dev = net->loopback_dev;
- }
- /* only send ICMP too big on first fragment */
- if (!ipvsh->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error_put;
- }
-
/*
* Okay, now see if we can stuff it in the buffer as-is.
*/
max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
- if (skb_headroom(skb) < max_headroom
- || skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) {
struct sk_buff *new_skb =
skb_realloc_headroom(skb, max_headroom);
- if (!new_skb) {
- dst_release(&rt->dst);
- kfree_skb(skb);
- IP_VS_ERR_RL("%s(): no memory\n", __func__);
- return NF_STOLEN;
- }
+
+ if (!new_skb)
+ goto tx_error;
consume_skb(skb);
skb = new_skb;
old_iph = ipv6_hdr(skb);
@@ -1008,10 +959,6 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb_reset_network_header(skb);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/*
* Push down and install the IPIP header.
*/
@@ -1029,25 +976,22 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- ret = IP_VS_XMIT_TUNNEL(skb, cp);
+ ret = ip_vs_tunnel_xmit_prepare(skb, cp);
if (ret == NF_ACCEPT)
ip6_local_out(skb);
else if (ret == NF_DROP)
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
-tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
-tx_error_put:
- dst_release(&rt->dst);
- goto tx_error;
}
#endif
@@ -1060,59 +1004,36 @@ int
ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
- struct rtable *rt; /* Route to the other host */
- struct iphdr *iph = ip_hdr(skb);
- int mtu;
+ int local;
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
- RT_TOS(iph->tos),
- IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL |
- IP_VS_RT_MODE_KNOWN_NH, NULL)))
- goto tx_error_icmp;
- if (rt->rt_flags & RTCF_LOCAL) {
- ip_rt_put(rt);
- IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1);
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if ((iph->frag_off & htons(IP_DF)) && skb->len > mtu &&
- !skb_is_gso(skb)) {
- icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
- ip_rt_put(rt);
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL |
+ IP_VS_RT_MODE_KNOWN_NH, NULL);
+ if (local < 0)
goto tx_error;
+ if (local) {
+ rcu_read_unlock();
+ return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
}
- /*
- * Call ip_send_check because we are not sure it is called
- * after ip_defrag. Is copy-on-write needed?
- */
- if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
- ip_rt_put(rt);
- return NF_STOLEN;
- }
ip_send_check(ip_hdr(skb));
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 0);
+ ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
}
@@ -1120,64 +1041,36 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#ifdef CONFIG_IP_VS_IPV6
int
ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
- struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph)
+ struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh)
{
- struct rt6_info *rt; /* Route to the other host */
- int mtu;
+ int local;
EnterFunction(10);
- if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
- 0, (IP_VS_RT_MODE_LOCAL |
- IP_VS_RT_MODE_NON_LOCAL))))
- goto tx_error_icmp;
- if (__ip_vs_is_local_route6(rt)) {
- dst_release(&rt->dst);
- IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1);
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if (__mtu_check_toobig_v6(skb, mtu)) {
- if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- skb->dev = net->loopback_dev;
- }
- /* only send ICMP too big on first fragment */
- if (!iph->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- dst_release(&rt->dst);
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ ipvsh, 0,
+ IP_VS_RT_MODE_LOCAL |
+ IP_VS_RT_MODE_NON_LOCAL);
+ if (local < 0)
goto tx_error;
+ if (local) {
+ rcu_read_unlock();
+ return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
}
- /*
- * Call ip_send_check because we are not sure it is called
- * after ip_defrag. Is copy-on-write needed?
- */
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (unlikely(skb == NULL)) {
- dst_release(&rt->dst);
- return NF_STOLEN;
- }
-
- /* drop old route */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 0);
+ ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
-tx_error_icmp:
- dst_link_failure(skb);
tx_error:
kfree_skb(skb);
+ rcu_read_unlock();
LeaveFunction(10);
return NF_STOLEN;
}
@@ -1194,10 +1087,9 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_iphdr *iph)
{
struct rtable *rt; /* Route to the other host */
- int mtu;
int rc;
int local;
- int rt_mode;
+ int rt_mode, was_input;
EnterFunction(10);
@@ -1217,16 +1109,17 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/*
* mangle and send the packet here (only for VS/NAT)
*/
+ was_input = rt_is_input_route(skb_rtable(skb));
/* LOCALNODE from FORWARD hook is not supported */
rt_mode = (hooknum != NF_INET_FORWARD) ?
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
- if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
- RT_TOS(ip_hdr(skb)->tos),
- rt_mode, NULL)))
- goto tx_error_icmp;
- local = rt->rt_flags & RTCF_LOCAL;
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, rt_mode, NULL);
+ if (local < 0)
+ goto tx_error;
+ rt = skb_rtable(skb);
/*
* Avoid duplicate tuple in reply direction for NAT traffic
@@ -1241,82 +1134,51 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG(10, "%s(): "
"stopping DNAT to local address %pI4\n",
__func__, &cp->daddr.ip);
- goto tx_error_put;
+ goto tx_error;
}
}
#endif
/* From world but DNAT to loopback address? */
- if (local && ipv4_is_loopback(cp->daddr.ip) &&
- rt_is_input_route(skb_rtable(skb))) {
+ if (local && ipv4_is_loopback(cp->daddr.ip) && was_input) {
IP_VS_DBG(1, "%s(): "
"stopping DNAT to loopback %pI4\n",
__func__, &cp->daddr.ip);
- goto tx_error_put;
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF)) &&
- !skb_is_gso(skb)) {
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error_put;
+ goto tx_error;
}
/* copy-on-write the packet before mangling it */
if (!skb_make_writable(skb, offset))
- goto tx_error_put;
+ goto tx_error;
if (skb_cow(skb, rt->dst.dev->hard_header_len))
- goto tx_error_put;
+ goto tx_error;
ip_vs_nat_icmp(skb, pp, cp, 0);
- if (!local) {
- /* drop the old route when skb is not shared */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
- } else {
- ip_rt_put(rt);
- /*
- * Some IPv4 replies get local address from routes,
- * not from iph, so while we DNAT after routing
- * we need this second input/output route.
- */
- if (!__ip_vs_reroute_locally(skb))
- goto tx_error;
- }
-
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local);
-
- rc = NF_STOLEN;
+ rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
+ rcu_read_unlock();
goto out;
- tx_error_icmp:
- dst_link_failure(skb);
tx_error:
- dev_kfree_skb(skb);
+ kfree_skb(skb);
+ rcu_read_unlock();
rc = NF_STOLEN;
out:
LeaveFunction(10);
return rc;
- tx_error_put:
- ip_rt_put(rt);
- goto tx_error;
}
#ifdef CONFIG_IP_VS_IPV6
int
ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
struct ip_vs_protocol *pp, int offset, unsigned int hooknum,
- struct ip_vs_iphdr *iph)
+ struct ip_vs_iphdr *ipvsh)
{
struct rt6_info *rt; /* Route to the other host */
- int mtu;
int rc;
int local;
int rt_mode;
@@ -1328,7 +1190,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
translate address/port back */
if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
if (cp->packet_xmit)
- rc = cp->packet_xmit(skb, cp, pp, iph);
+ rc = cp->packet_xmit(skb, cp, pp, ipvsh);
else
rc = NF_ACCEPT;
/* do not touch skb anymore */
@@ -1344,11 +1206,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
rt_mode = (hooknum != NF_INET_FORWARD) ?
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
- if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
- 0, rt_mode)))
- goto tx_error_icmp;
-
- local = __ip_vs_is_local_route6(rt);
+ rcu_read_lock();
+ local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
+ ipvsh, 0, rt_mode);
+ if (local < 0)
+ goto tx_error;
+ rt = (struct rt6_info *) skb_dst(skb);
/*
* Avoid duplicate tuple in reply direction for NAT traffic
* to local address when connection is sync-ed
@@ -1362,7 +1225,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG(10, "%s(): "
"stopping DNAT to local address %pI6\n",
__func__, &cp->daddr.in6);
- goto tx_error_put;
+ goto tx_error;
}
}
#endif
@@ -1373,60 +1236,31 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
IP_VS_DBG(1, "%s(): "
"stopping DNAT to loopback %pI6\n",
__func__, &cp->daddr.in6);
- goto tx_error_put;
- }
-
- /* MTU checking */
- mtu = dst_mtu(&rt->dst);
- if (__mtu_check_toobig_v6(skb, mtu)) {
- if (!skb->dev) {
- struct net *net = dev_net(skb_dst(skb)->dev);
-
- skb->dev = net->loopback_dev;
- }
- /* only send ICMP too big on first fragment */
- if (!iph->fragoffs)
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- IP_VS_DBG_RL("%s(): frag needed\n", __func__);
- goto tx_error_put;
+ goto tx_error;
}
/* copy-on-write the packet before mangling it */
if (!skb_make_writable(skb, offset))
- goto tx_error_put;
+ goto tx_error;
if (skb_cow(skb, rt->dst.dev->hard_header_len))
- goto tx_error_put;
+ goto tx_error;
ip_vs_nat_icmp_v6(skb, pp, cp, 0);
- if (!local || !skb->dev) {
- /* drop the old route when skb is not shared */
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
- } else {
- /* destined to loopback, do we need to change route? */
- dst_release(&rt->dst);
- }
-
/* Another hack: avoid icmp_send in ip_fragment */
skb->local_df = 1;
- IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local);
-
- rc = NF_STOLEN;
+ rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
+ rcu_read_unlock();
goto out;
-tx_error_icmp:
- dst_link_failure(skb);
tx_error:
- dev_kfree_skb(skb);
+ kfree_skb(skb);
+ rcu_read_unlock();
rc = NF_STOLEN;
out:
LeaveFunction(10);
return rc;
-tx_error_put:
- dst_release(&rt->dst);
- goto tx_error;
}
#endif
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index dbdaa1149260..b8b95f4027ca 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -2,6 +2,7 @@
*
* (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
* based on HW's ip_conntrack_irc.c as well as other modules
+ * (C) 2006 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index c8e001a9c45b..0283baedcdfb 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -5,6 +5,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (C) 2005-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -48,6 +49,7 @@
#include <net/netfilter/nf_conntrack_labels.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
+#include <net/netfilter/nf_nat_helper.h>
#define NF_CONNTRACK_VERSION "0.5.0"
@@ -264,7 +266,7 @@ static void death_by_event(unsigned long ul_conntrack)
if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
/* bad luck, let's retry again */
ecache->timeout.expires = jiffies +
- (random32() % net->ct.sysctl_events_retry_timeout);
+ (prandom_u32() % net->ct.sysctl_events_retry_timeout);
add_timer(&ecache->timeout);
return;
}
@@ -283,7 +285,7 @@ void nf_ct_dying_timeout(struct nf_conn *ct)
/* set a new timer to retry event delivery */
setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
ecache->timeout.expires = jiffies +
- (random32() % net->ct.sysctl_events_retry_timeout);
+ (prandom_u32() % net->ct.sysctl_events_retry_timeout);
add_timer(&ecache->timeout);
}
EXPORT_SYMBOL_GPL(nf_ct_dying_timeout);
@@ -1259,7 +1261,7 @@ void nf_ct_iterate_cleanup(struct net *net,
EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
struct __nf_ct_flush_report {
- u32 pid;
+ u32 portid;
int report;
};
@@ -1274,7 +1276,7 @@ static int kill_report(struct nf_conn *i, void *data)
/* If we fail to deliver the event, death_by_timeout() will retry */
if (nf_conntrack_event_report(IPCT_DESTROY, i,
- fr->pid, fr->report) < 0)
+ fr->portid, fr->report) < 0)
return 1;
/* Avoid the delivery of the destroy event in death_by_timeout(). */
@@ -1297,10 +1299,10 @@ void nf_ct_free_hashtable(void *hash, unsigned int size)
}
EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
-void nf_conntrack_flush_report(struct net *net, u32 pid, int report)
+void nf_conntrack_flush_report(struct net *net, u32 portid, int report)
{
struct __nf_ct_flush_report fr = {
- .pid = pid,
+ .portid = portid,
.report = report,
};
nf_ct_iterate_cleanup(net, kill_report, &fr);
@@ -1364,30 +1366,48 @@ void nf_conntrack_cleanup_end(void)
*/
void nf_conntrack_cleanup_net(struct net *net)
{
+ LIST_HEAD(single);
+
+ list_add(&net->exit_list, &single);
+ nf_conntrack_cleanup_net_list(&single);
+}
+
+void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list)
+{
+ int busy;
+ struct net *net;
+
/*
* This makes sure all current packets have passed through
* netfilter framework. Roll on, two-stage module
* delete...
*/
synchronize_net();
- i_see_dead_people:
- nf_ct_iterate_cleanup(net, kill_all, NULL);
- nf_ct_release_dying_list(net);
- if (atomic_read(&net->ct.count) != 0) {
+i_see_dead_people:
+ busy = 0;
+ list_for_each_entry(net, net_exit_list, exit_list) {
+ nf_ct_iterate_cleanup(net, kill_all, NULL);
+ nf_ct_release_dying_list(net);
+ if (atomic_read(&net->ct.count) != 0)
+ busy = 1;
+ }
+ if (busy) {
schedule();
goto i_see_dead_people;
}
- nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
- nf_conntrack_proto_pernet_fini(net);
- nf_conntrack_helper_pernet_fini(net);
- nf_conntrack_ecache_pernet_fini(net);
- nf_conntrack_tstamp_pernet_fini(net);
- nf_conntrack_acct_pernet_fini(net);
- nf_conntrack_expect_pernet_fini(net);
- kmem_cache_destroy(net->ct.nf_conntrack_cachep);
- kfree(net->ct.slabname);
- free_percpu(net->ct.stat);
+ list_for_each_entry(net, net_exit_list, exit_list) {
+ nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+ nf_conntrack_proto_pernet_fini(net);
+ nf_conntrack_helper_pernet_fini(net);
+ nf_conntrack_ecache_pernet_fini(net);
+ nf_conntrack_tstamp_pernet_fini(net);
+ nf_conntrack_acct_pernet_fini(net);
+ nf_conntrack_expect_pernet_fini(net);
+ kmem_cache_destroy(net->ct.nf_conntrack_cachep);
+ kfree(net->ct.slabname);
+ free_percpu(net->ct.stat);
+ }
}
void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index b5d2eb8bf0d5..1df176146567 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -1,8 +1,10 @@
/* Event cache for netfilter. */
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
- * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+/*
+ * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ * (C) 2005 Patrick McHardy <kaber@trash.net>
+ * (C) 2005-2006 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2005 USAGI/WIDE Project <http://www.linux-ipv6.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
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 8c10e3db3d9b..c63b618cd619 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -3,6 +3,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (c) 2005-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -40,7 +41,7 @@ static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
/* nf_conntrack_expect helper functions */
void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
- u32 pid, int report)
+ u32 portid, int report)
{
struct nf_conn_help *master_help = nfct_help(exp->master);
struct net *net = nf_ct_exp_net(exp);
@@ -54,7 +55,7 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
hlist_del(&exp->lnode);
master_help->expecting[exp->class]--;
- nf_ct_expect_event_report(IPEXP_DESTROY, exp, pid, report);
+ nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
nf_ct_expect_put(exp);
NF_CT_STAT_INC(net, expect_delete);
@@ -412,7 +413,7 @@ out:
}
int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
- u32 pid, int report)
+ u32 portid, int report)
{
int ret;
@@ -425,7 +426,7 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
if (ret < 0)
goto out;
spin_unlock_bh(&nf_conntrack_lock);
- nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report);
+ nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
return ret;
out:
spin_unlock_bh(&nf_conntrack_lock);
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 62fb8faedb80..6b217074237b 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -3,6 +3,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 7df7b36d2e24..bdebd03bc8cd 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -2,6 +2,7 @@
* H.323 connection tracking helper
*
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
+ * Copyright (c) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* This source code is licensed under General Public License version 2.
*
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 94b4b9853f60..974a2a4adefa 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -3,6 +3,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -353,7 +354,7 @@ void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
/* rcu_read_lock()ed by nf_hook_slow */
helper = rcu_dereference(help->helper);
- nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
+ nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
"nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
va_end(args);
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 70985c5d0ffa..0fd2976db7ee 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -1,6 +1,7 @@
/* IRC extension for IP connection tracking, Version 1.21
* (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
* based on RR's ip_conntrack_ftp.c
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 9904b15f600e..6d0f8a17c5b7 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2409,6 +2409,92 @@ out:
return skb->len;
}
+static int
+ctnetlink_exp_ct_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct nf_conntrack_expect *exp, *last;
+ struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
+ struct nf_conn *ct = cb->data;
+ struct nf_conn_help *help = nfct_help(ct);
+ u_int8_t l3proto = nfmsg->nfgen_family;
+
+ if (cb->args[0])
+ return 0;
+
+ rcu_read_lock();
+ last = (struct nf_conntrack_expect *)cb->args[1];
+restart:
+ hlist_for_each_entry(exp, &help->expectations, lnode) {
+ if (l3proto && exp->tuple.src.l3num != l3proto)
+ continue;
+ if (cb->args[1]) {
+ if (exp != last)
+ continue;
+ cb->args[1] = 0;
+ }
+ if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ IPCTNL_MSG_EXP_NEW,
+ exp) < 0) {
+ if (!atomic_inc_not_zero(&exp->use))
+ continue;
+ cb->args[1] = (unsigned long)exp;
+ goto out;
+ }
+ }
+ if (cb->args[1]) {
+ cb->args[1] = 0;
+ goto restart;
+ }
+ cb->args[0] = 1;
+out:
+ rcu_read_unlock();
+ if (last)
+ nf_ct_expect_put(last);
+
+ return skb->len;
+}
+
+static int ctnetlink_dump_exp_ct(struct sock *ctnl, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const cda[])
+{
+ int err;
+ struct net *net = sock_net(ctnl);
+ struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_hash *h;
+ struct nf_conn *ct;
+ u16 zone = 0;
+ struct netlink_dump_control c = {
+ .dump = ctnetlink_exp_ct_dump_table,
+ .done = ctnetlink_exp_done,
+ };
+
+ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
+ if (err < 0)
+ return err;
+
+ if (cda[CTA_EXPECT_ZONE]) {
+ err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
+ if (err < 0)
+ return err;
+ }
+
+ h = nf_conntrack_find_get(net, zone, &tuple);
+ if (!h)
+ return -ENOENT;
+
+ ct = nf_ct_tuplehash_to_ctrack(h);
+ c.data = ct;
+
+ err = netlink_dump_start(ctnl, skb, nlh, &c);
+ nf_ct_put(ct);
+
+ return err;
+}
+
static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
[CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
[CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
@@ -2439,11 +2525,15 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = ctnetlink_exp_dump_table,
- .done = ctnetlink_exp_done,
- };
- return netlink_dump_start(ctnl, skb, nlh, &c);
+ if (cda[CTA_EXPECT_MASTER])
+ return ctnetlink_dump_exp_ct(ctnl, skb, nlh, cda);
+ else {
+ struct netlink_dump_control c = {
+ .dump = ctnetlink_exp_dump_table,
+ .done = ctnetlink_exp_done,
+ };
+ return netlink_dump_start(ctnl, skb, nlh, &c);
+ }
}
err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index e6678d2b624e..7bd03decd36c 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -11,6 +11,8 @@
*
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
+ *
* Limitations:
* - We blindly assume that control connections are always
* established in PNS->PAC direction. This is a violation
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 58ab4050830c..0ab9636ac57e 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -3,6 +3,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index ba65b2041eb4..a99b6c3427b0 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -456,7 +456,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
out_invalid:
if (LOG_INVALID(net, IPPROTO_DCCP))
- nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL, msg);
+ nf_log_packet(net, nf_ct_l3num(ct), 0, skb, NULL, NULL,
+ NULL, msg);
return false;
}
@@ -542,13 +543,13 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
spin_unlock_bh(&ct->lock);
if (LOG_INVALID(net, IPPROTO_DCCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_dccp: invalid packet ignored ");
return NF_ACCEPT;
case CT_DCCP_INVALID:
spin_unlock_bh(&ct->lock);
if (LOG_INVALID(net, IPPROTO_DCCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_dccp: invalid state transition ");
return -NF_ACCEPT;
}
@@ -613,7 +614,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
out_invalid:
if (LOG_INVALID(net, IPPROTO_DCCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg);
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, msg);
return -NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 155ce9f8a0db..9d9c0dade602 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -21,6 +21,7 @@
*
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*/
#include <linux/module.h>
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index ec83536def9a..1314d33f6bcf 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -1,6 +1,9 @@
/*
* Connection tracking protocol helper module for SCTP.
*
+ * Copyright (c) 2004 Kiran Kumar Immidi <immidi_kiran@yahoo.com>
+ * Copyright (c) 2004-2012 Patrick McHardy <kaber@trash.net>
+ *
* SCTP is defined in RFC 2960. References to various sections in this code
* are to this RFC.
*
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 83876e9877f1..4d4d8f1d01fc 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -1,5 +1,7 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2002-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -720,7 +722,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
tn->tcp_be_liberal)
res = true;
if (!res && LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: %s ",
before(seq, sender->td_maxend + 1) ?
after(end, sender->td_end - receiver->td_maxwin - 1) ?
@@ -772,7 +774,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
if (th == NULL) {
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: short packet ");
return -NF_ACCEPT;
}
@@ -780,7 +782,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
/* Not whole TCP header or malformed packet */
if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: truncated/malformed packet ");
return -NF_ACCEPT;
}
@@ -793,7 +795,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: bad TCP checksum ");
return -NF_ACCEPT;
}
@@ -802,7 +804,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH));
if (!tcp_valid_flags[tcpflags]) {
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: invalid TCP flag combination ");
return -NF_ACCEPT;
}
@@ -949,7 +951,7 @@ static int tcp_packet(struct nf_conn *ct,
}
spin_unlock_bh(&ct->lock);
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: invalid packet ignored in "
"state %s ", tcp_conntrack_names[old_state]);
return NF_ACCEPT;
@@ -959,7 +961,7 @@ static int tcp_packet(struct nf_conn *ct,
dir, get_conntrack_index(th), old_state);
spin_unlock_bh(&ct->lock);
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: invalid state ");
return -NF_ACCEPT;
case TCP_CONNTRACK_CLOSE:
@@ -969,8 +971,8 @@ static int tcp_packet(struct nf_conn *ct,
/* Invalid RST */
spin_unlock_bh(&ct->lock);
if (LOG_INVALID(net, IPPROTO_TCP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
- "nf_ct_tcp: invalid RST ");
+ nf_log_packet(net, pf, 0, skb, NULL, NULL,
+ NULL, "nf_ct_tcp: invalid RST ");
return -NF_ACCEPT;
}
if (index == TCP_RST_SET
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 59623cc56e8d..9d7721cbce4b 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -1,5 +1,6 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -119,7 +120,7 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hdr == NULL) {
if (LOG_INVALID(net, IPPROTO_UDP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udp: short packet ");
return -NF_ACCEPT;
}
@@ -127,7 +128,7 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
/* Truncated/malformed packets */
if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
if (LOG_INVALID(net, IPPROTO_UDP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udp: truncated/malformed packet ");
return -NF_ACCEPT;
}
@@ -143,7 +144,7 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
if (LOG_INVALID(net, IPPROTO_UDP))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udp: bad UDP checksum ");
return -NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index ca969f6273f7..2750e6c69f82 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -131,7 +131,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hdr == NULL) {
if (LOG_INVALID(net, IPPROTO_UDPLITE))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udplite: short packet ");
return -NF_ACCEPT;
}
@@ -141,7 +141,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
cscov = udplen;
else if (cscov < sizeof(*hdr) || cscov > udplen) {
if (LOG_INVALID(net, IPPROTO_UDPLITE))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udplite: invalid checksum coverage ");
return -NF_ACCEPT;
}
@@ -149,7 +149,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
/* UDPLITE mandates checksums */
if (!hdr->check) {
if (LOG_INVALID(net, IPPROTO_UDPLITE))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udplite: checksum missing ");
return -NF_ACCEPT;
}
@@ -159,7 +159,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
pf)) {
if (LOG_INVALID(net, IPPROTO_UDPLITE))
- nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udplite: bad UDPLite checksum ");
return -NF_ACCEPT;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 0e7d423324c3..e0c4373b4747 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -1593,10 +1593,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
end += strlen("\r\n\r\n") + clen;
msglen = origlen = end - dptr;
- if (msglen > datalen) {
- nf_ct_helper_log(skb, ct, "incomplete/bad SIP message");
- return NF_DROP;
- }
+ if (msglen > datalen)
+ return NF_ACCEPT;
ret = process_sip_msg(skb, ct, protoff, dataoff,
&dptr, &msglen);
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 6bcce401fd1c..bd700b4013c1 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -1,5 +1,6 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2005-2012 Patrick McHardy <kaber@trash.net>
*
* 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
@@ -545,16 +546,20 @@ out_init:
return ret;
}
-static void nf_conntrack_pernet_exit(struct net *net)
+static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
{
- nf_conntrack_standalone_fini_sysctl(net);
- nf_conntrack_standalone_fini_proc(net);
- nf_conntrack_cleanup_net(net);
+ struct net *net;
+
+ list_for_each_entry(net, net_exit_list, exit_list) {
+ nf_conntrack_standalone_fini_sysctl(net);
+ nf_conntrack_standalone_fini_proc(net);
+ }
+ nf_conntrack_cleanup_net_list(net_exit_list);
}
static struct pernet_operations nf_conntrack_net_ops = {
- .init = nf_conntrack_pernet_init,
- .exit = nf_conntrack_pernet_exit,
+ .init = nf_conntrack_pernet_init,
+ .exit_batch = nf_conntrack_pernet_exit,
};
static int __init nf_conntrack_standalone_init(void)
@@ -568,6 +573,7 @@ static int __init nf_conntrack_standalone_init(void)
register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
if (!nf_ct_netfilter_header) {
pr_err("nf_conntrack: can't register to sysctl.\n");
+ ret = -ENOMEM;
goto out_sysctl;
}
#endif
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index e9936c830208..e68ab4fbd71f 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -1,5 +1,5 @@
/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
- *
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
* 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.
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 9e312695c818..388656d5a9ec 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -16,7 +16,6 @@
#define NF_LOG_PREFIXLEN 128
#define NFLOGGER_NAME_LEN 64
-static const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
static DEFINE_MUTEX(nf_log_mutex);
@@ -32,13 +31,46 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger)
return NULL;
}
+void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
+{
+ const struct nf_logger *log;
+
+ if (pf == NFPROTO_UNSPEC)
+ return;
+
+ mutex_lock(&nf_log_mutex);
+ log = rcu_dereference_protected(net->nf.nf_loggers[pf],
+ lockdep_is_held(&nf_log_mutex));
+ if (log == NULL)
+ rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
+
+ mutex_unlock(&nf_log_mutex);
+}
+EXPORT_SYMBOL(nf_log_set);
+
+void nf_log_unset(struct net *net, const struct nf_logger *logger)
+{
+ int i;
+ const struct nf_logger *log;
+
+ mutex_lock(&nf_log_mutex);
+ for (i = 0; i < NFPROTO_NUMPROTO; i++) {
+ log = rcu_dereference_protected(net->nf.nf_loggers[i],
+ lockdep_is_held(&nf_log_mutex));
+ if (log == logger)
+ RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
+ }
+ mutex_unlock(&nf_log_mutex);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL(nf_log_unset);
+
/* return EEXIST if the same logger is registered, 0 on success. */
int nf_log_register(u_int8_t pf, struct nf_logger *logger)
{
- const struct nf_logger *llog;
int i;
- if (pf >= ARRAY_SIZE(nf_loggers))
+ if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(logger->list); i++)
@@ -52,10 +84,6 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
} else {
/* register at end of list to honor first register win */
list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
- llog = rcu_dereference_protected(nf_loggers[pf],
- lockdep_is_held(&nf_log_mutex));
- if (llog == NULL)
- rcu_assign_pointer(nf_loggers[pf], logger);
}
mutex_unlock(&nf_log_mutex);
@@ -66,49 +94,43 @@ EXPORT_SYMBOL(nf_log_register);
void nf_log_unregister(struct nf_logger *logger)
{
- const struct nf_logger *c_logger;
int i;
mutex_lock(&nf_log_mutex);
- for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
- c_logger = rcu_dereference_protected(nf_loggers[i],
- lockdep_is_held(&nf_log_mutex));
- if (c_logger == logger)
- RCU_INIT_POINTER(nf_loggers[i], NULL);
+ for (i = 0; i < NFPROTO_NUMPROTO; i++)
list_del(&logger->list[i]);
- }
mutex_unlock(&nf_log_mutex);
-
- synchronize_rcu();
}
EXPORT_SYMBOL(nf_log_unregister);
-int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
+int nf_log_bind_pf(struct net *net, u_int8_t pf,
+ const struct nf_logger *logger)
{
- if (pf >= ARRAY_SIZE(nf_loggers))
+ if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
return -EINVAL;
mutex_lock(&nf_log_mutex);
if (__find_logger(pf, logger->name) == NULL) {
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
- rcu_assign_pointer(nf_loggers[pf], logger);
+ rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
mutex_unlock(&nf_log_mutex);
return 0;
}
EXPORT_SYMBOL(nf_log_bind_pf);
-void nf_log_unbind_pf(u_int8_t pf)
+void nf_log_unbind_pf(struct net *net, u_int8_t pf)
{
- if (pf >= ARRAY_SIZE(nf_loggers))
+ if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
return;
mutex_lock(&nf_log_mutex);
- RCU_INIT_POINTER(nf_loggers[pf], NULL);
+ RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
mutex_unlock(&nf_log_mutex);
}
EXPORT_SYMBOL(nf_log_unbind_pf);
-void nf_log_packet(u_int8_t pf,
+void nf_log_packet(struct net *net,
+ u_int8_t pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
@@ -121,7 +143,7 @@ void nf_log_packet(u_int8_t pf,
const struct nf_logger *logger;
rcu_read_lock();
- logger = rcu_dereference(nf_loggers[pf]);
+ logger = rcu_dereference(net->nf.nf_loggers[pf]);
if (logger) {
va_start(args, fmt);
vsnprintf(prefix, sizeof(prefix), fmt, args);
@@ -135,9 +157,11 @@ EXPORT_SYMBOL(nf_log_packet);
#ifdef CONFIG_PROC_FS
static void *seq_start(struct seq_file *seq, loff_t *pos)
{
+ struct net *net = seq_file_net(seq);
+
mutex_lock(&nf_log_mutex);
- if (*pos >= ARRAY_SIZE(nf_loggers))
+ if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
return NULL;
return pos;
@@ -145,9 +169,11 @@ static void *seq_start(struct seq_file *seq, loff_t *pos)
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
+ struct net *net = seq_file_net(s);
+
(*pos)++;
- if (*pos >= ARRAY_SIZE(nf_loggers))
+ if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
return NULL;
return pos;
@@ -164,8 +190,9 @@ static int seq_show(struct seq_file *s, void *v)
const struct nf_logger *logger;
struct nf_logger *t;
int ret;
+ struct net *net = seq_file_net(s);
- logger = rcu_dereference_protected(nf_loggers[*pos],
+ logger = rcu_dereference_protected(net->nf.nf_loggers[*pos],
lockdep_is_held(&nf_log_mutex));
if (!logger)
@@ -199,7 +226,8 @@ static const struct seq_operations nflog_seq_ops = {
static int nflog_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &nflog_seq_ops);
+ return seq_open_net(inode, file, &nflog_seq_ops,
+ sizeof(struct seq_net_private));
}
static const struct file_operations nflog_file_ops = {
@@ -207,7 +235,7 @@ static const struct file_operations nflog_file_ops = {
.open = nflog_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_net,
};
@@ -216,7 +244,6 @@ static const struct file_operations nflog_file_ops = {
#ifdef CONFIG_SYSCTL
static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
-static struct ctl_table_header *nf_log_dir_header;
static int nf_log_proc_dostring(ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -226,6 +253,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
size_t size = *lenp;
int r = 0;
int tindex = (unsigned long)table->extra1;
+ struct net *net = current->nsproxy->net_ns;
if (write) {
if (size > sizeof(buf))
@@ -234,7 +262,7 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
return -EFAULT;
if (!strcmp(buf, "NONE")) {
- nf_log_unbind_pf(tindex);
+ nf_log_unbind_pf(net, tindex);
return 0;
}
mutex_lock(&nf_log_mutex);
@@ -243,11 +271,11 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
mutex_unlock(&nf_log_mutex);
return -ENOENT;
}
- rcu_assign_pointer(nf_loggers[tindex], logger);
+ rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
mutex_unlock(&nf_log_mutex);
} else {
mutex_lock(&nf_log_mutex);
- logger = rcu_dereference_protected(nf_loggers[tindex],
+ logger = rcu_dereference_protected(net->nf.nf_loggers[tindex],
lockdep_is_held(&nf_log_mutex));
if (!logger)
table->data = "NONE";
@@ -260,49 +288,111 @@ static int nf_log_proc_dostring(ctl_table *table, int write,
return r;
}
-static __init int netfilter_log_sysctl_init(void)
+static int netfilter_log_sysctl_init(struct net *net)
{
int i;
-
- for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
- snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
- nf_log_sysctl_table[i].procname =
- nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
- nf_log_sysctl_table[i].data = NULL;
- nf_log_sysctl_table[i].maxlen =
- NFLOGGER_NAME_LEN * sizeof(char);
- nf_log_sysctl_table[i].mode = 0644;
- nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
- nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
+ struct ctl_table *table;
+
+ table = nf_log_sysctl_table;
+ if (!net_eq(net, &init_net)) {
+ table = kmemdup(nf_log_sysctl_table,
+ sizeof(nf_log_sysctl_table),
+ GFP_KERNEL);
+ if (!table)
+ goto err_alloc;
+ } else {
+ for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
+ snprintf(nf_log_sysctl_fnames[i],
+ 3, "%d", i);
+ nf_log_sysctl_table[i].procname =
+ nf_log_sysctl_fnames[i];
+ nf_log_sysctl_table[i].data = NULL;
+ nf_log_sysctl_table[i].maxlen =
+ NFLOGGER_NAME_LEN * sizeof(char);
+ nf_log_sysctl_table[i].mode = 0644;
+ nf_log_sysctl_table[i].proc_handler =
+ nf_log_proc_dostring;
+ nf_log_sysctl_table[i].extra1 =
+ (void *)(unsigned long) i;
+ }
}
- nf_log_dir_header = register_net_sysctl(&init_net, "net/netfilter/nf_log",
- nf_log_sysctl_table);
- if (!nf_log_dir_header)
- return -ENOMEM;
+ net->nf.nf_log_dir_header = register_net_sysctl(net,
+ "net/netfilter/nf_log",
+ table);
+ if (!net->nf.nf_log_dir_header)
+ goto err_reg;
return 0;
+
+err_reg:
+ if (!net_eq(net, &init_net))
+ kfree(table);
+err_alloc:
+ return -ENOMEM;
+}
+
+static void netfilter_log_sysctl_exit(struct net *net)
+{
+ struct ctl_table *table;
+
+ table = net->nf.nf_log_dir_header->ctl_table_arg;
+ unregister_net_sysctl_table(net->nf.nf_log_dir_header);
+ if (!net_eq(net, &init_net))
+ kfree(table);
}
#else
-static __init int netfilter_log_sysctl_init(void)
+static int netfilter_log_sysctl_init(struct net *net)
{
return 0;
}
+
+static void netfilter_log_sysctl_exit(struct net *net)
+{
+}
#endif /* CONFIG_SYSCTL */
-int __init netfilter_log_init(void)
+static int __net_init nf_log_net_init(struct net *net)
{
- int i, r;
+ int ret = -ENOMEM;
+
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
- proc_net_netfilter, &nflog_file_ops))
- return -1;
+ net->nf.proc_netfilter, &nflog_file_ops))
+ return ret;
#endif
+ ret = netfilter_log_sysctl_init(net);
+ if (ret < 0)
+ goto out_sysctl;
+
+ return 0;
- /* Errors will trigger panic, unroll on error is unnecessary. */
- r = netfilter_log_sysctl_init();
- if (r < 0)
- return r;
+out_sysctl:
+ /* For init_net: errors will trigger panic, don't unroll on error. */
+ if (!net_eq(net, &init_net))
+ remove_proc_entry("nf_log", net->nf.proc_netfilter);
+
+ return ret;
+}
+
+static void __net_exit nf_log_net_exit(struct net *net)
+{
+ netfilter_log_sysctl_exit(net);
+ remove_proc_entry("nf_log", net->nf.proc_netfilter);
+}
+
+static struct pernet_operations nf_log_net_ops = {
+ .init = nf_log_net_init,
+ .exit = nf_log_net_exit,
+};
+
+int __init netfilter_log_init(void)
+{
+ int i, ret;
+
+ ret = register_pernet_subsys(&nf_log_net_ops);
+ if (ret < 0)
+ return ret;
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
INIT_LIST_HEAD(&(nf_loggers_l[i]));
diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c
index 3b67c9d11273..eb772380a202 100644
--- a/net/netfilter/nf_nat_amanda.c
+++ b/net/netfilter/nf_nat_amanda.c
@@ -1,6 +1,7 @@
/* Amanda extension for TCP NAT alteration.
* (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
* based on a copy of HW's ip_nat_irc.c as well as other modules
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 8d5769c6d16e..038eee5c8f85 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -87,9 +87,11 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
struct flowi fl;
unsigned int hh_len;
struct dst_entry *dst;
+ int err;
- if (xfrm_decode_session(skb, &fl, family) < 0)
- return -1;
+ err = xfrm_decode_session(skb, &fl, family);
+ if (err < 0)
+ return err;
dst = skb_dst(skb);
if (dst->xfrm)
@@ -98,7 +100,7 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
if (IS_ERR(dst))
- return -1;
+ return PTR_ERR(dst);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
@@ -107,7 +109,7 @@ int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family)
hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
- return -1;
+ return -ENOMEM;
return 0;
}
EXPORT_SYMBOL(nf_xfrm_me_harder);
@@ -467,33 +469,22 @@ EXPORT_SYMBOL_GPL(nf_nat_packet);
struct nf_nat_proto_clean {
u8 l3proto;
u8 l4proto;
- bool hash;
};
-/* Clear NAT section of all conntracks, in case we're loaded again. */
-static int nf_nat_proto_clean(struct nf_conn *i, void *data)
+/* kill conntracks with affected NAT section */
+static int nf_nat_proto_remove(struct nf_conn *i, void *data)
{
const struct nf_nat_proto_clean *clean = data;
struct nf_conn_nat *nat = nfct_nat(i);
if (!nat)
return 0;
- if (!(i->status & IPS_SRC_NAT_DONE))
- return 0;
+
if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
(clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
return 0;
- if (clean->hash) {
- spin_lock_bh(&nf_nat_lock);
- hlist_del_rcu(&nat->bysource);
- spin_unlock_bh(&nf_nat_lock);
- } else {
- memset(nat, 0, sizeof(*nat));
- i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK |
- IPS_SEQ_ADJUST);
- }
- return 0;
+ return i->status & IPS_NAT_MASK ? 1 : 0;
}
static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
@@ -505,16 +496,8 @@ static void nf_nat_l4proto_clean(u8 l3proto, u8 l4proto)
struct net *net;
rtnl_lock();
- /* Step 1 - remove from bysource hash */
- clean.hash = true;
for_each_net(net)
- nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
- synchronize_rcu();
-
- /* Step 2 - clean NAT section */
- clean.hash = false;
- for_each_net(net)
- nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
+ nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean);
rtnl_unlock();
}
@@ -526,16 +509,9 @@ static void nf_nat_l3proto_clean(u8 l3proto)
struct net *net;
rtnl_lock();
- /* Step 1 - remove from bysource hash */
- clean.hash = true;
- for_each_net(net)
- nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
- synchronize_rcu();
- /* Step 2 - clean NAT section */
- clean.hash = false;
for_each_net(net)
- nf_ct_iterate_cleanup(net, nf_nat_proto_clean, &clean);
+ nf_ct_iterate_cleanup(net, nf_nat_proto_remove, &clean);
rtnl_unlock();
}
@@ -773,7 +749,7 @@ static void __net_exit nf_nat_net_exit(struct net *net)
{
struct nf_nat_proto_clean clean = {};
- nf_ct_iterate_cleanup(net, &nf_nat_proto_clean, &clean);
+ nf_ct_iterate_cleanup(net, &nf_nat_proto_remove, &clean);
synchronize_rcu();
nf_ct_free_hashtable(net->ct.nat_bysource, net->ct.nat_htable_size);
}
diff --git a/net/netfilter/nf_nat_helper.c b/net/netfilter/nf_nat_helper.c
index 23c2b38676a6..5fea563afe30 100644
--- a/net/netfilter/nf_nat_helper.c
+++ b/net/netfilter/nf_nat_helper.c
@@ -2,6 +2,7 @@
*
* (C) 2000-2002 Harald Welte <laforge@netfilter.org>
* (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2007-2012 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/netfilter/nf_nat_proto_sctp.c b/net/netfilter/nf_nat_proto_sctp.c
index e64faa5ca893..396e55d46f90 100644
--- a/net/netfilter/nf_nat_proto_sctp.c
+++ b/net/netfilter/nf_nat_proto_sctp.c
@@ -36,7 +36,7 @@ sctp_manip_pkt(struct sk_buff *skb,
{
struct sk_buff *frag;
sctp_sctphdr_t *hdr;
- __be32 crc32;
+ __u32 crc32;
if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
return false;
@@ -55,8 +55,7 @@ sctp_manip_pkt(struct sk_buff *skb,
skb_walk_frags(skb, frag)
crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
crc32);
- crc32 = sctp_end_cksum(crc32);
- hdr->checksum = crc32;
+ hdr->checksum = sctp_end_cksum(crc32);
return true;
}
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index d812c1235b30..5d24b1fdb593 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -1,3 +1,8 @@
+/*
+ * Rusty Russell (C)2000 -- This code is GPL.
+ * Patrick McHardy (c) 2006-2012
+ */
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -40,7 +45,7 @@ void nf_unregister_queue_handler(void)
}
EXPORT_SYMBOL(nf_unregister_queue_handler);
-static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
+void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
{
/* Release those devices we held, or Alexey will kill me. */
if (entry->indev)
@@ -60,12 +65,41 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
/* Drop reference to owner of hook which queued us. */
module_put(entry->elem->owner);
}
+EXPORT_SYMBOL_GPL(nf_queue_entry_release_refs);
+
+/* Bump dev refs so they don't vanish while packet is out */
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
+{
+ if (!try_module_get(entry->elem->owner))
+ return false;
+
+ if (entry->indev)
+ dev_hold(entry->indev);
+ if (entry->outdev)
+ dev_hold(entry->outdev);
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (entry->skb->nf_bridge) {
+ struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
+ struct net_device *physdev;
+
+ physdev = nf_bridge->physindev;
+ if (physdev)
+ dev_hold(physdev);
+ physdev = nf_bridge->physoutdev;
+ if (physdev)
+ dev_hold(physdev);
+ }
+#endif
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
/*
* Any packet that leaves via this function must come back
* through nf_reinject().
*/
-static int __nf_queue(struct sk_buff *skb,
+int nf_queue(struct sk_buff *skb,
struct nf_hook_ops *elem,
u_int8_t pf, unsigned int hook,
struct net_device *indev,
@@ -75,10 +109,6 @@ static int __nf_queue(struct sk_buff *skb,
{
int status = -ENOENT;
struct nf_queue_entry *entry = NULL;
-#ifdef CONFIG_BRIDGE_NETFILTER
- struct net_device *physindev;
- struct net_device *physoutdev;
-#endif
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
@@ -109,28 +139,13 @@ static int __nf_queue(struct sk_buff *skb,
.indev = indev,
.outdev = outdev,
.okfn = okfn,
+ .size = sizeof(*entry) + afinfo->route_key_size,
};
- /* If it's going away, ignore hook. */
- if (!try_module_get(entry->elem->owner)) {
+ if (!nf_queue_entry_get_refs(entry)) {
status = -ECANCELED;
goto err_unlock;
}
- /* Bump dev refs so they don't vanish while packet is out */
- if (indev)
- dev_hold(indev);
- if (outdev)
- dev_hold(outdev);
-#ifdef CONFIG_BRIDGE_NETFILTER
- if (skb->nf_bridge) {
- physindev = skb->nf_bridge->physindev;
- if (physindev)
- dev_hold(physindev);
- physoutdev = skb->nf_bridge->physoutdev;
- if (physoutdev)
- dev_hold(physoutdev);
- }
-#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
status = qh->outfn(entry, queuenum);
@@ -151,87 +166,6 @@ err:
return status;
}
-#ifdef CONFIG_BRIDGE_NETFILTER
-/* When called from bridge netfilter, skb->data must point to MAC header
- * before calling skb_gso_segment(). Else, original MAC header is lost
- * and segmented skbs will be sent to wrong destination.
- */
-static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
-{
- if (skb->nf_bridge)
- __skb_push(skb, skb->network_header - skb->mac_header);
-}
-
-static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
-{
- if (skb->nf_bridge)
- __skb_pull(skb, skb->network_header - skb->mac_header);
-}
-#else
-#define nf_bridge_adjust_skb_data(s) do {} while (0)
-#define nf_bridge_adjust_segmented_data(s) do {} while (0)
-#endif
-
-int nf_queue(struct sk_buff *skb,
- struct nf_hook_ops *elem,
- u_int8_t pf, unsigned int hook,
- struct net_device *indev,
- struct net_device *outdev,
- int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
-{
- struct sk_buff *segs;
- int err = -EINVAL;
- unsigned int queued;
-
- if (!skb_is_gso(skb))
- return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
- queuenum);
-
- switch (pf) {
- case NFPROTO_IPV4:
- skb->protocol = htons(ETH_P_IP);
- break;
- case NFPROTO_IPV6:
- skb->protocol = htons(ETH_P_IPV6);
- break;
- }
-
- nf_bridge_adjust_skb_data(skb);
- segs = skb_gso_segment(skb, 0);
- /* Does not use PTR_ERR to limit the number of error codes that can be
- * returned by nf_queue. For instance, callers rely on -ECANCELED to mean
- * 'ignore this hook'.
- */
- if (IS_ERR(segs))
- goto out_err;
- queued = 0;
- err = 0;
- do {
- struct sk_buff *nskb = segs->next;
-
- segs->next = NULL;
- if (err == 0) {
- nf_bridge_adjust_segmented_data(segs);
- err = __nf_queue(segs, elem, pf, hook, indev,
- outdev, okfn, queuenum);
- }
- if (err == 0)
- queued++;
- else
- kfree_skb(segs);
- segs = nskb;
- } while (segs);
-
- if (queued) {
- kfree_skb(skb);
- return 0;
- }
- out_err:
- nf_bridge_adjust_segmented_data(skb);
- return err;
-}
-
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
{
struct sk_buff *skb = entry->skb;
@@ -271,9 +205,9 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
local_bh_enable();
break;
case NF_QUEUE:
- err = __nf_queue(skb, elem, entry->pf, entry->hook,
- entry->indev, entry->outdev, entry->okfn,
- verdict >> NF_VERDICT_QBITS);
+ err = nf_queue(skb, elem, entry->pf, entry->hook,
+ entry->indev, entry->outdev, entry->okfn,
+ verdict >> NF_VERDICT_QBITS);
if (err < 0) {
if (err == -ECANCELED)
goto next_hook;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 0b1b32cda307..572d87dc116f 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -24,10 +24,9 @@
#include <linux/skbuff.h>
#include <asm/uaccess.h>
#include <net/sock.h>
-#include <net/netlink.h>
#include <linux/init.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netfilter/nfnetlink.h>
MODULE_LICENSE("GPL");
@@ -113,22 +112,30 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group)
}
EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
-int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid,
+struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
+ u32 dst_portid, gfp_t gfp_mask)
+{
+ return netlink_alloc_skb(net->nfnl, size, dst_portid, gfp_mask);
+}
+EXPORT_SYMBOL_GPL(nfnetlink_alloc_skb);
+
+int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
unsigned int group, int echo, gfp_t flags)
{
- return nlmsg_notify(net->nfnl, skb, pid, group, echo, flags);
+ return nlmsg_notify(net->nfnl, skb, portid, group, echo, flags);
}
EXPORT_SYMBOL_GPL(nfnetlink_send);
-int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error)
+int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
{
- return netlink_set_err(net->nfnl, pid, group, error);
+ return netlink_set_err(net->nfnl, portid, group, error);
}
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
-int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags)
+int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
+ int flags)
{
- return netlink_unicast(net->nfnl, skb, pid, flags);
+ return netlink_unicast(net->nfnl, skb, portid, flags);
}
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
@@ -144,7 +151,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EPERM;
/* All the messages must at least contain nfgenmsg */
- if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg)))
+ if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
return 0;
type = nlh->nlmsg_type;
@@ -172,7 +179,7 @@ replay:
}
{
- int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
+ int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
struct nlattr *attr = (void *)nlh + min_len;
diff --git a/net/netfilter/nfnetlink_acct.c b/net/netfilter/nfnetlink_acct.c
index 589d686f0b4c..dc3fd5d44464 100644
--- a/net/netfilter/nfnetlink_acct.c
+++ b/net/netfilter/nfnetlink_acct.c
@@ -49,6 +49,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
return -EINVAL;
acct_name = nla_data(tb[NFACCT_NAME]);
+ if (strlen(acct_name) == 0)
+ return -EINVAL;
list_for_each_entry(nfacct, &nfnl_acct_list, head) {
if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index f248db572972..faf1e9300d8a 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -3,6 +3,7 @@
* nfetlink.
*
* (C) 2005 by Harald Welte <laforge@netfilter.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* Based on the old ipv4-only ipt_ULOG.c:
* (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
@@ -19,7 +20,7 @@
#include <linux/ipv6.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h>
#include <linux/spinlock.h>
@@ -32,6 +33,7 @@
#include <linux/slab.h>
#include <net/sock.h>
#include <net/netfilter/nf_log.h>
+#include <net/netns/generic.h>
#include <net/netfilter/nfnetlink_log.h>
#include <linux/atomic.h>
@@ -56,6 +58,7 @@ struct nfulnl_instance {
unsigned int qlen; /* number of nlmsgs in skb */
struct sk_buff *skb; /* pre-allocatd skb */
struct timer_list timer;
+ struct net *net;
struct user_namespace *peer_user_ns; /* User namespace of the peer process */
int peer_portid; /* PORTID of the peer process */
@@ -71,25 +74,34 @@ struct nfulnl_instance {
struct rcu_head rcu;
};
-static DEFINE_SPINLOCK(instances_lock);
-static atomic_t global_seq;
-
#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS];
static unsigned int hash_init;
+static int nfnl_log_net_id __read_mostly;
+
+struct nfnl_log_net {
+ spinlock_t instances_lock;
+ struct hlist_head instance_table[INSTANCE_BUCKETS];
+ atomic_t global_seq;
+};
+
+static struct nfnl_log_net *nfnl_log_pernet(struct net *net)
+{
+ return net_generic(net, nfnl_log_net_id);
+}
+
static inline u_int8_t instance_hashfn(u_int16_t group_num)
{
return ((group_num & 0xff) % INSTANCE_BUCKETS);
}
static struct nfulnl_instance *
-__instance_lookup(u_int16_t group_num)
+__instance_lookup(struct nfnl_log_net *log, u_int16_t group_num)
{
struct hlist_head *head;
struct nfulnl_instance *inst;
- head = &instance_table[instance_hashfn(group_num)];
+ head = &log->instance_table[instance_hashfn(group_num)];
hlist_for_each_entry_rcu(inst, head, hlist) {
if (inst->group_num == group_num)
return inst;
@@ -104,12 +116,12 @@ instance_get(struct nfulnl_instance *inst)
}
static struct nfulnl_instance *
-instance_lookup_get(u_int16_t group_num)
+instance_lookup_get(struct nfnl_log_net *log, u_int16_t group_num)
{
struct nfulnl_instance *inst;
rcu_read_lock_bh();
- inst = __instance_lookup(group_num);
+ inst = __instance_lookup(log, group_num);
if (inst && !atomic_inc_not_zero(&inst->use))
inst = NULL;
rcu_read_unlock_bh();
@@ -119,7 +131,11 @@ instance_lookup_get(u_int16_t group_num)
static void nfulnl_instance_free_rcu(struct rcu_head *head)
{
- kfree(container_of(head, struct nfulnl_instance, rcu));
+ struct nfulnl_instance *inst =
+ container_of(head, struct nfulnl_instance, rcu);
+
+ put_net(inst->net);
+ kfree(inst);
module_put(THIS_MODULE);
}
@@ -133,13 +149,15 @@ instance_put(struct nfulnl_instance *inst)
static void nfulnl_timer(unsigned long data);
static struct nfulnl_instance *
-instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns)
+instance_create(struct net *net, u_int16_t group_num,
+ int portid, struct user_namespace *user_ns)
{
struct nfulnl_instance *inst;
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
int err;
- spin_lock_bh(&instances_lock);
- if (__instance_lookup(group_num)) {
+ spin_lock_bh(&log->instances_lock);
+ if (__instance_lookup(log, group_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -163,6 +181,7 @@ instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns)
setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);
+ inst->net = get_net(net);
inst->peer_user_ns = user_ns;
inst->peer_portid = portid;
inst->group_num = group_num;
@@ -174,14 +193,15 @@ instance_create(u_int16_t group_num, int portid, struct user_namespace *user_ns)
inst->copy_range = NFULNL_COPY_RANGE_MAX;
hlist_add_head_rcu(&inst->hlist,
- &instance_table[instance_hashfn(group_num)]);
+ &log->instance_table[instance_hashfn(group_num)]);
+
- spin_unlock_bh(&instances_lock);
+ spin_unlock_bh(&log->instances_lock);
return inst;
out_unlock:
- spin_unlock_bh(&instances_lock);
+ spin_unlock_bh(&log->instances_lock);
return ERR_PTR(err);
}
@@ -210,11 +230,12 @@ __instance_destroy(struct nfulnl_instance *inst)
}
static inline void
-instance_destroy(struct nfulnl_instance *inst)
+instance_destroy(struct nfnl_log_net *log,
+ struct nfulnl_instance *inst)
{
- spin_lock_bh(&instances_lock);
+ spin_lock_bh(&log->instances_lock);
__instance_destroy(inst);
- spin_unlock_bh(&instances_lock);
+ spin_unlock_bh(&log->instances_lock);
}
static int
@@ -298,7 +319,7 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
}
static struct sk_buff *
-nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
+nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size)
{
struct sk_buff *skb;
unsigned int n;
@@ -307,13 +328,14 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
* message. WARNING: has to be <= 128k due to slab restrictions */
n = max(inst_size, pkt_size);
- skb = alloc_skb(n, GFP_ATOMIC);
+ skb = nfnetlink_alloc_skb(&init_net, n, peer_portid, GFP_ATOMIC);
if (!skb) {
if (n > pkt_size) {
/* try to allocate only as much as we need for current
* packet */
- skb = alloc_skb(pkt_size, GFP_ATOMIC);
+ skb = nfnetlink_alloc_skb(&init_net, pkt_size,
+ peer_portid, GFP_ATOMIC);
if (!skb)
pr_err("nfnetlink_log: can't even alloc %u bytes\n",
pkt_size);
@@ -336,7 +358,7 @@ __nfulnl_send(struct nfulnl_instance *inst)
if (!nlh)
goto out;
}
- status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_portid,
+ status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
MSG_DONTWAIT);
inst->qlen = 0;
@@ -370,7 +392,8 @@ nfulnl_timer(unsigned long data)
/* This is an inline function, we don't really care about a long
* list of arguments */
static inline int
-__build_packet_message(struct nfulnl_instance *inst,
+__build_packet_message(struct nfnl_log_net *log,
+ struct nfulnl_instance *inst,
const struct sk_buff *skb,
unsigned int data_len,
u_int8_t pf,
@@ -536,7 +559,7 @@ __build_packet_message(struct nfulnl_instance *inst,
/* global sequence number */
if ((inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) &&
nla_put_be32(inst->skb, NFULA_SEQ_GLOBAL,
- htonl(atomic_inc_return(&global_seq))))
+ htonl(atomic_inc_return(&log->global_seq))))
goto nla_put_failure;
if (data_len) {
@@ -592,13 +615,15 @@ nfulnl_log_packet(u_int8_t pf,
const struct nf_loginfo *li;
unsigned int qthreshold;
unsigned int plen;
+ struct net *net = dev_net(in ? in : out);
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
li = li_user;
else
li = &default_loginfo;
- inst = instance_lookup_get(li->u.ulog.group);
+ inst = instance_lookup_get(log, li->u.ulog.group);
if (!inst)
return;
@@ -609,7 +634,7 @@ nfulnl_log_packet(u_int8_t pf,
/* FIXME: do we want to make the size calculation conditional based on
* what is actually present? way more branches and checks, but more
* memory efficient... */
- size = NLMSG_SPACE(sizeof(struct nfgenmsg))
+ size = nlmsg_total_size(sizeof(struct nfgenmsg))
+ nla_total_size(sizeof(struct nfulnl_msg_packet_hdr))
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
@@ -673,14 +698,15 @@ nfulnl_log_packet(u_int8_t pf,
}
if (!inst->skb) {
- inst->skb = nfulnl_alloc_skb(inst->nlbufsiz, size);
+ inst->skb = nfulnl_alloc_skb(inst->peer_portid, inst->nlbufsiz,
+ size);
if (!inst->skb)
goto alloc_failure;
}
inst->qlen++;
- __build_packet_message(inst, skb, data_len, pf,
+ __build_packet_message(log, inst, skb, data_len, pf,
hooknum, in, out, prefix, plen);
if (inst->qlen >= qthreshold)
@@ -709,24 +735,24 @@ nfulnl_rcv_nl_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
+ struct nfnl_log_net *log = nfnl_log_pernet(n->net);
if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
int i;
/* destroy all instances for this portid */
- spin_lock_bh(&instances_lock);
+ spin_lock_bh(&log->instances_lock);
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct hlist_node *t2;
struct nfulnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &log->instance_table[i];
hlist_for_each_entry_safe(inst, t2, head, hlist) {
- if ((net_eq(n->net, &init_net)) &&
- (n->portid == inst->peer_portid))
+ if (n->portid == inst->peer_portid)
__instance_destroy(inst);
}
}
- spin_unlock_bh(&instances_lock);
+ spin_unlock_bh(&log->instances_lock);
}
return NOTIFY_DONE;
}
@@ -767,6 +793,8 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
u_int16_t group_num = ntohs(nfmsg->res_id);
struct nfulnl_instance *inst;
struct nfulnl_msg_config_cmd *cmd = NULL;
+ struct net *net = sock_net(ctnl);
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
int ret = 0;
if (nfula[NFULA_CFG_CMD]) {
@@ -776,14 +804,14 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
/* Commands without queue context */
switch (cmd->command) {
case NFULNL_CFG_CMD_PF_BIND:
- return nf_log_bind_pf(pf, &nfulnl_logger);
+ return nf_log_bind_pf(net, pf, &nfulnl_logger);
case NFULNL_CFG_CMD_PF_UNBIND:
- nf_log_unbind_pf(pf);
+ nf_log_unbind_pf(net, pf);
return 0;
}
}
- inst = instance_lookup_get(group_num);
+ inst = instance_lookup_get(log, group_num);
if (inst && inst->peer_portid != NETLINK_CB(skb).portid) {
ret = -EPERM;
goto out_put;
@@ -797,9 +825,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
goto out_put;
}
- inst = instance_create(group_num,
+ inst = instance_create(net, group_num,
NETLINK_CB(skb).portid,
- sk_user_ns(NETLINK_CB(skb).ssk));
+ sk_user_ns(NETLINK_CB(skb).sk));
if (IS_ERR(inst)) {
ret = PTR_ERR(inst);
goto out;
@@ -811,7 +839,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
goto out;
}
- instance_destroy(inst);
+ instance_destroy(log, inst);
goto out_put;
default:
ret = -ENOTSUPP;
@@ -894,55 +922,68 @@ static const struct nfnetlink_subsystem nfulnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
-static struct hlist_node *get_first(struct iter_state *st)
+static struct hlist_node *get_first(struct net *net, struct iter_state *st)
{
+ struct nfnl_log_net *log;
if (!st)
return NULL;
+ log = nfnl_log_pernet(net);
+
for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket]));
+ struct hlist_head *head = &log->instance_table[st->bucket];
+
+ if (!hlist_empty(head))
+ return rcu_dereference_bh(hlist_first_rcu(head));
}
return NULL;
}
-static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h)
+static struct hlist_node *get_next(struct net *net, struct iter_state *st,
+ struct hlist_node *h)
{
h = rcu_dereference_bh(hlist_next_rcu(h));
while (!h) {
+ struct nfnl_log_net *log;
+ struct hlist_head *head;
+
if (++st->bucket >= INSTANCE_BUCKETS)
return NULL;
- h = rcu_dereference_bh(hlist_first_rcu(&instance_table[st->bucket]));
+ log = nfnl_log_pernet(net);
+ head = &log->instance_table[st->bucket];
+ h = rcu_dereference_bh(hlist_first_rcu(head));
}
return h;
}
-static struct hlist_node *get_idx(struct iter_state *st, loff_t pos)
+static struct hlist_node *get_idx(struct net *net, struct iter_state *st,
+ loff_t pos)
{
struct hlist_node *head;
- head = get_first(st);
+ head = get_first(net, st);
if (head)
- while (pos && (head = get_next(st, head)))
+ while (pos && (head = get_next(net, st, head)))
pos--;
return pos ? NULL : head;
}
-static void *seq_start(struct seq_file *seq, loff_t *pos)
+static void *seq_start(struct seq_file *s, loff_t *pos)
__acquires(rcu_bh)
{
rcu_read_lock_bh();
- return get_idx(seq->private, *pos);
+ return get_idx(seq_file_net(s), s->private, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
- return get_next(s->private, v);
+ return get_next(seq_file_net(s), s->private, v);
}
static void seq_stop(struct seq_file *s, void *v)
@@ -971,8 +1012,8 @@ static const struct seq_operations nful_seq_ops = {
static int nful_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nful_seq_ops,
- sizeof(struct iter_state));
+ return seq_open_net(inode, file, &nful_seq_ops,
+ sizeof(struct iter_state));
}
static const struct file_operations nful_file_ops = {
@@ -980,17 +1021,43 @@ static const struct file_operations nful_file_ops = {
.open = nful_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
-static int __init nfnetlink_log_init(void)
+static int __net_init nfnl_log_net_init(struct net *net)
{
- int i, status = -ENOMEM;
+ unsigned int i;
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
+ INIT_HLIST_HEAD(&log->instance_table[i]);
+ spin_lock_init(&log->instances_lock);
+
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_log", 0440,
+ net->nf.proc_netfilter, &nful_file_ops))
+ return -ENOMEM;
+#endif
+ return 0;
+}
+
+static void __net_exit nfnl_log_net_exit(struct net *net)
+{
+ remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
+}
+
+static struct pernet_operations nfnl_log_net_ops = {
+ .init = nfnl_log_net_init,
+ .exit = nfnl_log_net_exit,
+ .id = &nfnl_log_net_id,
+ .size = sizeof(struct nfnl_log_net),
+};
+
+static int __init nfnetlink_log_init(void)
+{
+ int status = -ENOMEM;
/* it's not really all that important to have a random value, so
* we can do this from the init function, even if there hasn't
@@ -1000,29 +1067,25 @@ static int __init nfnetlink_log_init(void)
netlink_register_notifier(&nfulnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfulnl_subsys);
if (status < 0) {
- printk(KERN_ERR "log: failed to create netlink socket\n");
+ pr_err("log: failed to create netlink socket\n");
goto cleanup_netlink_notifier;
}
status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger);
if (status < 0) {
- printk(KERN_ERR "log: failed to register logger\n");
+ pr_err("log: failed to register logger\n");
goto cleanup_subsys;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_log", 0440,
- proc_net_netfilter, &nful_file_ops)) {
- status = -ENOMEM;
+ status = register_pernet_subsys(&nfnl_log_net_ops);
+ if (status < 0) {
+ pr_err("log: failed to register pernet ops\n");
goto cleanup_logger;
}
-#endif
return status;
-#ifdef CONFIG_PROC_FS
cleanup_logger:
nf_log_unregister(&nfulnl_logger);
-#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
@@ -1032,10 +1095,8 @@ cleanup_netlink_notifier:
static void __exit nfnetlink_log_fini(void)
{
+ unregister_pernet_subsys(&nfnl_log_net_ops);
nf_log_unregister(&nfulnl_logger);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 1cb48540f86a..2e0e835baf72 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -30,6 +30,7 @@
#include <linux/list.h>
#include <net/sock.h>
#include <net/netfilter/nf_queue.h>
+#include <net/netns/generic.h>
#include <net/netfilter/nfnetlink_queue.h>
#include <linux/atomic.h>
@@ -66,23 +67,31 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-static DEFINE_SPINLOCK(instances_lock);
+static int nfnl_queue_net_id __read_mostly;
#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
+struct nfnl_queue_net {
+ spinlock_t instances_lock;
+ struct hlist_head instance_table[INSTANCE_BUCKETS];
+};
+
+static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net)
+{
+ return net_generic(net, nfnl_queue_net_id);
+}
static inline u_int8_t instance_hashfn(u_int16_t queue_num)
{
- return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+ return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
}
static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
+instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num)
{
struct hlist_head *head;
struct nfqnl_instance *inst;
- head = &instance_table[instance_hashfn(queue_num)];
+ head = &q->instance_table[instance_hashfn(queue_num)];
hlist_for_each_entry_rcu(inst, head, hlist) {
if (inst->queue_num == queue_num)
return inst;
@@ -91,14 +100,15 @@ instance_lookup(u_int16_t queue_num)
}
static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int portid)
+instance_create(struct nfnl_queue_net *q, u_int16_t queue_num,
+ int portid)
{
struct nfqnl_instance *inst;
unsigned int h;
int err;
- spin_lock(&instances_lock);
- if (instance_lookup(queue_num)) {
+ spin_lock(&q->instances_lock);
+ if (instance_lookup(q, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -123,16 +133,16 @@ instance_create(u_int16_t queue_num, int portid)
}
h = instance_hashfn(queue_num);
- hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+ hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]);
- spin_unlock(&instances_lock);
+ spin_unlock(&q->instances_lock);
return inst;
out_free:
kfree(inst);
out_unlock:
- spin_unlock(&instances_lock);
+ spin_unlock(&q->instances_lock);
return ERR_PTR(err);
}
@@ -158,11 +168,11 @@ __instance_destroy(struct nfqnl_instance *inst)
}
static void
-instance_destroy(struct nfqnl_instance *inst)
+instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst)
{
- spin_lock(&instances_lock);
+ spin_lock(&q->instances_lock);
__instance_destroy(inst);
- spin_unlock(&instances_lock);
+ spin_unlock(&q->instances_lock);
}
static inline void
@@ -217,14 +227,71 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
spin_unlock_bh(&queue->lock);
}
+static void
+nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+{
+ int i, j = 0;
+ int plen = 0; /* length of skb->head fragment */
+ struct page *page;
+ unsigned int offset;
+
+ /* dont bother with small payloads */
+ if (len <= skb_tailroom(to)) {
+ skb_copy_bits(from, 0, skb_put(to, len), len);
+ return;
+ }
+
+ if (hlen) {
+ skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+ len -= hlen;
+ } else {
+ plen = min_t(int, skb_headlen(from), len);
+ if (plen) {
+ page = virt_to_head_page(from->head);
+ offset = from->data - (unsigned char *)page_address(page);
+ __skb_fill_page_desc(to, 0, page, offset, plen);
+ get_page(page);
+ j = 1;
+ len -= plen;
+ }
+ }
+
+ to->truesize += len + plen;
+ to->len += len + plen;
+ to->data_len += len + plen;
+
+ for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
+ if (!len)
+ break;
+ skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
+ skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
+ len -= skb_shinfo(to)->frags[j].size;
+ skb_frag_ref(to, j);
+ j++;
+ }
+ skb_shinfo(to)->nr_frags = j;
+}
+
+static int nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet)
+{
+ __u32 flags = 0;
+
+ if (packet->ip_summed == CHECKSUM_PARTIAL)
+ flags = NFQA_SKB_CSUMNOTREADY;
+ if (skb_is_gso(packet))
+ flags |= NFQA_SKB_GSO;
+
+ return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0;
+}
+
static struct sk_buff *
nfqnl_build_packet_message(struct nfqnl_instance *queue,
struct nf_queue_entry *entry,
__be32 **packet_id_ptr)
{
- sk_buff_data_t old_tail;
size_t size;
size_t data_len = 0, cap_len = 0;
+ int hlen = 0;
struct sk_buff *skb;
struct nlattr *nla;
struct nfqnl_msg_packet_hdr *pmsg;
@@ -236,7 +303,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
struct nf_conn *ct = NULL;
enum ip_conntrack_info uninitialized_var(ctinfo);
- size = NLMSG_SPACE(sizeof(struct nfgenmsg))
+ size = nlmsg_total_size(sizeof(struct nfgenmsg))
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr))
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
@@ -246,8 +313,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
#endif
+ nla_total_size(sizeof(u_int32_t)) /* mark */
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
- + nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)
- + nla_total_size(sizeof(u_int32_t))); /* cap_len */
+ + nla_total_size(sizeof(u_int32_t)) /* skbinfo */
+ + nla_total_size(sizeof(u_int32_t)); /* cap_len */
+
+ if (entskb->tstamp.tv64)
+ size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp));
outdev = entry->outdev;
@@ -257,7 +327,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
break;
case NFQNL_COPY_PACKET:
- if (entskb->ip_summed == CHECKSUM_PARTIAL &&
+ if (!(queue->flags & NFQA_CFG_F_GSO) &&
+ entskb->ip_summed == CHECKSUM_PARTIAL &&
skb_checksum_help(entskb))
return NULL;
@@ -265,7 +336,16 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
if (data_len == 0 || data_len > entskb->len)
data_len = entskb->len;
- size += nla_total_size(data_len);
+
+ if (!entskb->head_frag ||
+ skb_headlen(entskb) < L1_CACHE_BYTES ||
+ skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS)
+ hlen = skb_headlen(entskb);
+
+ if (skb_has_frag_list(entskb))
+ hlen = entskb->len;
+ hlen = min_t(int, data_len, hlen);
+ size += sizeof(struct nlattr) + hlen;
cap_len = entskb->len;
break;
}
@@ -273,11 +353,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
if (queue->flags & NFQA_CFG_F_CONNTRACK)
ct = nfqnl_ct_get(entskb, &size, &ctinfo);
- skb = alloc_skb(size, GFP_ATOMIC);
+ skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid,
+ GFP_ATOMIC);
if (!skb)
return NULL;
- old_tail = skb->tail;
nlh = nlmsg_put(skb, 0, 0,
NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
sizeof(struct nfgenmsg), 0);
@@ -382,31 +462,29 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
goto nla_put_failure;
}
+ if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
+ goto nla_put_failure;
+
+ if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
+ goto nla_put_failure;
+
+ if (nfqnl_put_packet_info(skb, entskb))
+ goto nla_put_failure;
+
if (data_len) {
struct nlattr *nla;
- int sz = nla_attr_size(data_len);
- if (skb_tailroom(skb) < nla_total_size(data_len)) {
- printk(KERN_WARNING "nf_queue: no tailroom!\n");
- kfree_skb(skb);
- return NULL;
- }
+ if (skb_tailroom(skb) < sizeof(*nla) + hlen)
+ goto nla_put_failure;
- nla = (struct nlattr *)skb_put(skb, nla_total_size(data_len));
+ nla = (struct nlattr *)skb_put(skb, sizeof(*nla));
nla->nla_type = NFQA_PAYLOAD;
- nla->nla_len = sz;
+ nla->nla_len = nla_attr_size(data_len);
- if (skb_copy_bits(entskb, 0, nla_data(nla), data_len))
- BUG();
+ nfqnl_zcopy(skb, entskb, data_len, hlen);
}
- if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
- goto nla_put_failure;
-
- if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
- goto nla_put_failure;
-
- nlh->nlmsg_len = skb->tail - old_tail;
+ nlh->nlmsg_len = skb->len;
return skb;
nla_put_failure:
@@ -416,26 +494,14 @@ nla_put_failure:
}
static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+__nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
+ struct nf_queue_entry *entry)
{
struct sk_buff *nskb;
- struct nfqnl_instance *queue;
int err = -ENOBUFS;
__be32 *packet_id_ptr;
int failopen = 0;
- /* rcu_read_lock()ed by nf_hook_slow() */
- queue = instance_lookup(queuenum);
- if (!queue) {
- err = -ESRCH;
- goto err_out;
- }
-
- if (queue->copy_mode == NFQNL_COPY_NONE) {
- err = -EINVAL;
- goto err_out;
- }
-
nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
if (nskb == NULL) {
err = -ENOMEM;
@@ -462,7 +528,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
*packet_id_ptr = htonl(entry->id);
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, &init_net, queue->peer_portid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
@@ -483,6 +549,141 @@ err_out:
return err;
}
+static struct nf_queue_entry *
+nf_queue_entry_dup(struct nf_queue_entry *e)
+{
+ struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
+ if (entry) {
+ if (nf_queue_entry_get_refs(entry))
+ return entry;
+ kfree(entry);
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+/* When called from bridge netfilter, skb->data must point to MAC header
+ * before calling skb_gso_segment(). Else, original MAC header is lost
+ * and segmented skbs will be sent to wrong destination.
+ */
+static void nf_bridge_adjust_skb_data(struct sk_buff *skb)
+{
+ if (skb->nf_bridge)
+ __skb_push(skb, skb->network_header - skb->mac_header);
+}
+
+static void nf_bridge_adjust_segmented_data(struct sk_buff *skb)
+{
+ if (skb->nf_bridge)
+ __skb_pull(skb, skb->network_header - skb->mac_header);
+}
+#else
+#define nf_bridge_adjust_skb_data(s) do {} while (0)
+#define nf_bridge_adjust_segmented_data(s) do {} while (0)
+#endif
+
+static void free_entry(struct nf_queue_entry *entry)
+{
+ nf_queue_entry_release_refs(entry);
+ kfree(entry);
+}
+
+static int
+__nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue,
+ struct sk_buff *skb, struct nf_queue_entry *entry)
+{
+ int ret = -ENOMEM;
+ struct nf_queue_entry *entry_seg;
+
+ nf_bridge_adjust_segmented_data(skb);
+
+ if (skb->next == NULL) { /* last packet, no need to copy entry */
+ struct sk_buff *gso_skb = entry->skb;
+ entry->skb = skb;
+ ret = __nfqnl_enqueue_packet(net, queue, entry);
+ if (ret)
+ entry->skb = gso_skb;
+ return ret;
+ }
+
+ skb->next = NULL;
+
+ entry_seg = nf_queue_entry_dup(entry);
+ if (entry_seg) {
+ entry_seg->skb = skb;
+ ret = __nfqnl_enqueue_packet(net, queue, entry_seg);
+ if (ret)
+ free_entry(entry_seg);
+ }
+ return ret;
+}
+
+static int
+nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+{
+ unsigned int queued;
+ struct nfqnl_instance *queue;
+ struct sk_buff *skb, *segs;
+ int err = -ENOBUFS;
+ struct net *net = dev_net(entry->indev ?
+ entry->indev : entry->outdev);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+ /* rcu_read_lock()ed by nf_hook_slow() */
+ queue = instance_lookup(q, queuenum);
+ if (!queue)
+ return -ESRCH;
+
+ if (queue->copy_mode == NFQNL_COPY_NONE)
+ return -EINVAL;
+
+ if ((queue->flags & NFQA_CFG_F_GSO) || !skb_is_gso(entry->skb))
+ return __nfqnl_enqueue_packet(net, queue, entry);
+
+ skb = entry->skb;
+
+ switch (entry->pf) {
+ case NFPROTO_IPV4:
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case NFPROTO_IPV6:
+ skb->protocol = htons(ETH_P_IPV6);
+ break;
+ }
+
+ nf_bridge_adjust_skb_data(skb);
+ segs = skb_gso_segment(skb, 0);
+ /* Does not use PTR_ERR to limit the number of error codes that can be
+ * returned by nf_queue. For instance, callers rely on -ECANCELED to
+ * mean 'ignore this hook'.
+ */
+ if (IS_ERR(segs))
+ goto out_err;
+ queued = 0;
+ err = 0;
+ do {
+ struct sk_buff *nskb = segs->next;
+ if (err == 0)
+ err = __nfqnl_enqueue_packet_gso(net, queue,
+ segs, entry);
+ if (err == 0)
+ queued++;
+ else
+ kfree_skb(segs);
+ segs = nskb;
+ } while (segs);
+
+ if (queued) {
+ if (err) /* some segments are already queued */
+ free_entry(entry);
+ kfree_skb(skb);
+ return 0;
+ }
+ out_err:
+ nf_bridge_adjust_segmented_data(skb);
+ return err;
+}
+
static int
nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
{
@@ -575,15 +776,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
/* drop all packets with either indev or outdev == ifindex from all queue
* instances */
static void
-nfqnl_dev_drop(int ifindex)
+nfqnl_dev_drop(struct net *net, int ifindex)
{
int i;
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
rcu_read_lock();
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &q->instance_table[i];
hlist_for_each_entry_rcu(inst, head, hlist)
nfqnl_flush(inst, dev_cmp, ifindex);
@@ -600,12 +802,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
- nfqnl_dev_drop(dev->ifindex);
+ nfqnl_dev_drop(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
@@ -618,24 +817,24 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
+ struct nfnl_queue_net *q = nfnl_queue_pernet(n->net);
if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) {
int i;
/* destroy all instances for this portid */
- spin_lock(&instances_lock);
+ spin_lock(&q->instances_lock);
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct hlist_node *t2;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &q->instance_table[i];
hlist_for_each_entry_safe(inst, t2, head, hlist) {
- if ((n->net == &init_net) &&
- (n->portid == inst->peer_portid))
+ if (n->portid == inst->peer_portid)
__instance_destroy(inst);
}
}
- spin_unlock(&instances_lock);
+ spin_unlock(&q->instances_lock);
}
return NOTIFY_DONE;
}
@@ -656,11 +855,12 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
[NFQA_MARK] = { .type = NLA_U32 },
};
-static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlportid)
+static struct nfqnl_instance *
+verdict_instance_lookup(struct nfnl_queue_net *q, u16 queue_num, int nlportid)
{
struct nfqnl_instance *queue;
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(q, queue_num);
if (!queue)
return ERR_PTR(-ENODEV);
@@ -704,7 +904,11 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
LIST_HEAD(batch_list);
u16 queue_num = ntohs(nfmsg->res_id);
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid);
+ struct net *net = sock_net(ctnl);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+
+ queue = verdict_instance_lookup(q, queue_num,
+ NETLINK_CB(skb).portid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -752,10 +956,13 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
enum ip_conntrack_info uninitialized_var(ctinfo);
struct nf_conn *ct = NULL;
- queue = instance_lookup(queue_num);
- if (!queue)
+ struct net *net = sock_net(ctnl);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid);
+ queue = instance_lookup(q, queue_num);
+ if (!queue)
+ queue = verdict_instance_lookup(q, queue_num,
+ NETLINK_CB(skb).portid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -819,6 +1026,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
u_int16_t queue_num = ntohs(nfmsg->res_id);
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
+ struct net *net = sock_net(ctnl);
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
int ret = 0;
if (nfqa[NFQA_CFG_CMD]) {
@@ -832,7 +1041,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(q, queue_num);
if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
ret = -EPERM;
goto err_out_unlock;
@@ -845,7 +1054,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -EBUSY;
goto err_out_unlock;
}
- queue = instance_create(queue_num, NETLINK_CB(skb).portid);
+ queue = instance_create(q, queue_num,
+ NETLINK_CB(skb).portid);
if (IS_ERR(queue)) {
ret = PTR_ERR(queue);
goto err_out_unlock;
@@ -856,7 +1066,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -ENODEV;
goto err_out_unlock;
}
- instance_destroy(queue);
+ instance_destroy(q, queue);
break;
case NFQNL_CFG_CMD_PF_BIND:
case NFQNL_CFG_CMD_PF_UNBIND:
@@ -950,19 +1160,24 @@ static const struct nfnetlink_subsystem nfqnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
static struct hlist_node *get_first(struct seq_file *seq)
{
struct iter_state *st = seq->private;
+ struct net *net;
+ struct nfnl_queue_net *q;
if (!st)
return NULL;
+ net = seq_file_net(seq);
+ q = nfnl_queue_pernet(net);
for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ if (!hlist_empty(&q->instance_table[st->bucket]))
+ return q->instance_table[st->bucket].first;
}
return NULL;
}
@@ -970,13 +1185,17 @@ static struct hlist_node *get_first(struct seq_file *seq)
static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
{
struct iter_state *st = seq->private;
+ struct net *net = seq_file_net(seq);
h = h->next;
while (!h) {
+ struct nfnl_queue_net *q;
+
if (++st->bucket >= INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ q = nfnl_queue_pernet(net);
+ h = q->instance_table[st->bucket].first;
}
return h;
}
@@ -992,11 +1211,11 @@ static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
return pos ? NULL : head;
}
-static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
+static void *seq_start(struct seq_file *s, loff_t *pos)
+ __acquires(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
{
- spin_lock(&instances_lock);
- return get_idx(seq, *pos);
+ spin_lock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
+ return get_idx(s, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
@@ -1006,9 +1225,9 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
+ __releases(nfnl_queue_pernet(seq_file_net(s))->instances_lock)
{
- spin_unlock(&instances_lock);
+ spin_unlock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
@@ -1032,7 +1251,7 @@ static const struct seq_operations nfqnl_seq_ops = {
static int nfqnl_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nfqnl_seq_ops,
+ return seq_open_net(inode, file, &nfqnl_seq_ops,
sizeof(struct iter_state));
}
@@ -1041,39 +1260,63 @@ static const struct file_operations nfqnl_file_ops = {
.open = nfqnl_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
-static int __init nfnetlink_queue_init(void)
+static int __net_init nfnl_queue_net_init(struct net *net)
{
- int i, status = -ENOMEM;
+ unsigned int i;
+ struct nfnl_queue_net *q = nfnl_queue_pernet(net);
for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
+ INIT_HLIST_HEAD(&q->instance_table[i]);
+
+ spin_lock_init(&q->instances_lock);
+
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_queue", 0440,
+ net->nf.proc_netfilter, &nfqnl_file_ops))
+ return -ENOMEM;
+#endif
+ return 0;
+}
+
+static void __net_exit nfnl_queue_net_exit(struct net *net)
+{
+ remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
+}
+
+static struct pernet_operations nfnl_queue_net_ops = {
+ .init = nfnl_queue_net_init,
+ .exit = nfnl_queue_net_exit,
+ .id = &nfnl_queue_net_id,
+ .size = sizeof(struct nfnl_queue_net),
+};
+
+static int __init nfnetlink_queue_init(void)
+{
+ int status = -ENOMEM;
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
- printk(KERN_ERR "nf_queue: failed to create netlink socket\n");
+ pr_err("nf_queue: failed to create netlink socket\n");
goto cleanup_netlink_notifier;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
+ status = register_pernet_subsys(&nfnl_queue_net_ops);
+ if (status < 0) {
+ pr_err("nf_queue: failed to register pernet ops\n");
goto cleanup_subsys;
-#endif
-
+ }
register_netdevice_notifier(&nfqnl_dev_notifier);
nf_register_queue_handler(&nfqh);
return status;
-#ifdef CONFIG_PROC_FS
cleanup_subsys:
nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
@@ -1083,9 +1326,7 @@ static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handler();
unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
+ unregister_pernet_subsys(&nfnl_queue_net_ops);
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 67fb7bff9bbc..8b03028cca69 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -2,6 +2,7 @@
* x_tables core - Backend for {ip,ip6,arp}_tables
*
* Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
+ * Copyright (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* Based on existing ip_tables code which is
* Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
diff --git a/net/netfilter/xt_LOG.c b/net/netfilter/xt_LOG.c
index fa40096940a1..fe573f6c9e91 100644
--- a/net/netfilter/xt_LOG.c
+++ b/net/netfilter/xt_LOG.c
@@ -474,7 +474,14 @@ ipt_log_packet(u_int8_t pf,
const struct nf_loginfo *loginfo,
const char *prefix)
{
- struct sbuff *m = sb_open();
+ struct sbuff *m;
+ struct net *net = dev_net(in ? in : out);
+
+ /* FIXME: Disabled from containers until syslog ns is supported */
+ if (!net_eq(net, &init_net))
+ return;
+
+ m = sb_open();
if (!loginfo)
loginfo = &default_loginfo;
@@ -798,7 +805,14 @@ ip6t_log_packet(u_int8_t pf,
const struct nf_loginfo *loginfo,
const char *prefix)
{
- struct sbuff *m = sb_open();
+ struct sbuff *m;
+ struct net *net = dev_net(in ? in : out);
+
+ /* FIXME: Disabled from containers until syslog ns is supported */
+ if (!net_eq(net, &init_net))
+ return;
+
+ m = sb_open();
if (!loginfo)
loginfo = &default_loginfo;
@@ -893,23 +907,55 @@ static struct nf_logger ip6t_log_logger __read_mostly = {
};
#endif
+static int __net_init log_net_init(struct net *net)
+{
+ nf_log_set(net, NFPROTO_IPV4, &ipt_log_logger);
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+ nf_log_set(net, NFPROTO_IPV6, &ip6t_log_logger);
+#endif
+ return 0;
+}
+
+static void __net_exit log_net_exit(struct net *net)
+{
+ nf_log_unset(net, &ipt_log_logger);
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+ nf_log_unset(net, &ip6t_log_logger);
+#endif
+}
+
+static struct pernet_operations log_net_ops = {
+ .init = log_net_init,
+ .exit = log_net_exit,
+};
+
static int __init log_tg_init(void)
{
int ret;
+ ret = register_pernet_subsys(&log_net_ops);
+ if (ret < 0)
+ goto err_pernet;
+
ret = xt_register_targets(log_tg_regs, ARRAY_SIZE(log_tg_regs));
if (ret < 0)
- return ret;
+ goto err_target;
nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
nf_log_register(NFPROTO_IPV6, &ip6t_log_logger);
#endif
return 0;
+
+err_target:
+ unregister_pernet_subsys(&log_net_ops);
+err_pernet:
+ return ret;
}
static void __exit log_tg_exit(void)
{
+ unregister_pernet_subsys(&log_net_ops);
nf_log_unregister(&ipt_log_logger);
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
nf_log_unregister(&ip6t_log_logger);
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 817f9e9f2b16..1e2fae32f81b 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -76,22 +76,31 @@ static u32 hash_v6(const struct sk_buff *skb)
}
#endif
-static unsigned int
-nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
+static u32
+nfqueue_hash(const struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_NFQ_info_v1 *info = par->targinfo;
u32 queue = info->queuenum;
- if (info->queues_total > 1) {
- if (par->family == NFPROTO_IPV4)
- queue = (((u64) hash_v4(skb) * info->queues_total) >>
- 32) + queue;
+ if (par->family == NFPROTO_IPV4)
+ queue += ((u64) hash_v4(skb) * info->queues_total) >> 32;
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
- else if (par->family == NFPROTO_IPV6)
- queue = (((u64) hash_v6(skb) * info->queues_total) >>
- 32) + queue;
+ else if (par->family == NFPROTO_IPV6)
+ queue += ((u64) hash_v6(skb) * info->queues_total) >> 32;
#endif
- }
+
+ return queue;
+}
+
+static unsigned int
+nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_NFQ_info_v1 *info = par->targinfo;
+ u32 queue = info->queuenum;
+
+ if (info->queues_total > 1)
+ queue = nfqueue_hash(skb, par);
+
return NF_QUEUE_NR(queue);
}
@@ -108,7 +117,7 @@ nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
static int nfqueue_tg_check(const struct xt_tgchk_param *par)
{
- const struct xt_NFQ_info_v2 *info = par->targinfo;
+ const struct xt_NFQ_info_v3 *info = par->targinfo;
u32 maxid;
if (unlikely(!rnd_inited)) {
@@ -125,11 +134,32 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par)
info->queues_total, maxid);
return -ERANGE;
}
- if (par->target->revision == 2 && info->bypass > 1)
+ if (par->target->revision == 2 && info->flags > 1)
return -EINVAL;
+ if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK)
+ return -EINVAL;
+
return 0;
}
+static unsigned int
+nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
+{
+ const struct xt_NFQ_info_v3 *info = par->targinfo;
+ u32 queue = info->queuenum;
+
+ if (info->queues_total > 1) {
+ if (info->flags & NFQ_FLAG_CPU_FANOUT) {
+ int cpu = smp_processor_id();
+
+ queue = info->queuenum + cpu % info->queues_total;
+ } else
+ queue = nfqueue_hash(skb, par);
+ }
+
+ return NF_QUEUE_NR(queue);
+}
+
static struct xt_target nfqueue_tg_reg[] __read_mostly = {
{
.name = "NFQUEUE",
@@ -156,6 +186,15 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = {
.targetsize = sizeof(struct xt_NFQ_info_v2),
.me = THIS_MODULE,
},
+ {
+ .name = "NFQUEUE",
+ .revision = 3,
+ .family = NFPROTO_UNSPEC,
+ .checkentry = nfqueue_tg_check,
+ .target = nfqueue_tg_v3,
+ .targetsize = sizeof(struct xt_NFQ_info_v3),
+ .me = THIS_MODULE,
+ },
};
static int __init nfqueue_tg_init(void)
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 71a266de5fb4..a75240f0d42b 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -2,6 +2,7 @@
* This is a module which is used for setting the MSS option in TCP packets.
*
* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ * Copyright (C) 2007 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 61805d7b38aa..188404b9b002 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -3,6 +3,7 @@
* information. (Superset of Rusty's minimalistic state match.)
*
* (C) 2001 Marc Boucher (marc@mbsi.ca).
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
*
* This program is free software; you can redistribute it and/or modify
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 905c328ed5a8..9ff035c71403 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -3,6 +3,7 @@
* separately for each hashbucket (sourceip/sourceport/dstip/dstport)
*
* (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
*
* Development of this code was funded by Astaro AG, http://www.astaro.com/
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index a4c1e4528cac..bef850596558 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -1,5 +1,6 @@
/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
* (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
*
* 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
diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c
index a5e673d32bda..647d989a01e6 100644
--- a/net/netfilter/xt_osf.c
+++ b/net/netfilter/xt_osf.c
@@ -201,6 +201,7 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
unsigned char opts[MAX_IPOPTLEN];
const struct xt_osf_finger *kf;
const struct xt_osf_user_finger *f;
+ struct net *net = dev_net(p->in ? p->in : p->out);
if (!info)
return false;
@@ -325,7 +326,7 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
fcount++;
if (info->flags & XT_OSF_LOG)
- nf_log_packet(p->family, p->hooknum, skb,
+ nf_log_packet(net, p->family, p->hooknum, skb,
p->in, p->out, NULL,
"%s [%s:%s] : %pI4:%d -> %pI4:%d hops=%d\n",
f->genre, f->version, f->subtype,
@@ -341,7 +342,8 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
rcu_read_unlock();
if (!fcount && (info->flags & XT_OSF_LOG))
- nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL,
+ nf_log_packet(net, p->family, p->hooknum, skb, p->in,
+ p->out, NULL,
"Remote OS is not known: %pI4:%u -> %pI4:%u\n",
&ip->saddr, ntohs(tcp->source),
&ip->daddr, ntohs(tcp->dest));
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
index 865a9e54f3ad..31790e789e22 100644
--- a/net/netfilter/xt_set.c
+++ b/net/netfilter/xt_set.c
@@ -1,7 +1,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
@@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_SET");
static inline int
match_set(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par,
- const struct ip_set_adt_opt *opt, int inv)
+ struct ip_set_adt_opt *opt, int inv)
{
if (ip_set_test(index, skb, par, opt))
inv = !inv;
@@ -38,20 +38,12 @@ match_set(ip_set_id_t index, const struct sk_buff *skb,
}
#define ADT_OPT(n, f, d, fs, cfs, t) \
-const struct ip_set_adt_opt n = { \
- .family = f, \
- .dim = d, \
- .flags = fs, \
- .cmdflags = cfs, \
- .timeout = t, \
-}
-#define ADT_MOPT(n, f, d, fs, cfs, t) \
struct ip_set_adt_opt n = { \
.family = f, \
.dim = d, \
.flags = fs, \
.cmdflags = cfs, \
- .timeout = t, \
+ .ext.timeout = t, \
}
/* Revision 0 interface: backward compatible with netfilter/iptables */
@@ -197,6 +189,9 @@ set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
ADT_OPT(opt, par->family, info->match_set.dim,
info->match_set.flags, 0, UINT_MAX);
+ if (opt.flags & IPSET_RETURN_NOMATCH)
+ opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
+
return match_set(info->match_set.index, skb, par, &opt,
info->match_set.flags & IPSET_INV_MATCH);
}
@@ -305,15 +300,15 @@ static unsigned int
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_set_info_target_v2 *info = par->targinfo;
- ADT_MOPT(add_opt, par->family, info->add_set.dim,
- info->add_set.flags, info->flags, info->timeout);
+ ADT_OPT(add_opt, par->family, info->add_set.dim,
+ info->add_set.flags, info->flags, info->timeout);
ADT_OPT(del_opt, par->family, info->del_set.dim,
info->del_set.flags, 0, UINT_MAX);
/* Normalize to fit into jiffies */
- if (add_opt.timeout != IPSET_NO_TIMEOUT &&
- add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
- add_opt.timeout = UINT_MAX/MSEC_PER_SEC;
+ if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
+ add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
+ add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
@@ -325,6 +320,52 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
#define set_target_v2_checkentry set_target_v1_checkentry
#define set_target_v2_destroy set_target_v1_destroy
+/* Revision 3 match */
+
+static bool
+match_counter(u64 counter, const struct ip_set_counter_match *info)
+{
+ switch (info->op) {
+ case IPSET_COUNTER_NONE:
+ return true;
+ case IPSET_COUNTER_EQ:
+ return counter == info->value;
+ case IPSET_COUNTER_NE:
+ return counter != info->value;
+ case IPSET_COUNTER_LT:
+ return counter < info->value;
+ case IPSET_COUNTER_GT:
+ return counter > info->value;
+ }
+ return false;
+}
+
+static bool
+set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_set_info_match_v3 *info = par->matchinfo;
+ ADT_OPT(opt, par->family, info->match_set.dim,
+ info->match_set.flags, info->flags, UINT_MAX);
+ int ret;
+
+ if (info->packets.op != IPSET_COUNTER_NONE ||
+ info->bytes.op != IPSET_COUNTER_NONE)
+ opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
+
+ ret = match_set(info->match_set.index, skb, par, &opt,
+ info->match_set.flags & IPSET_INV_MATCH);
+
+ if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
+ return ret;
+
+ if (!match_counter(opt.ext.packets, &info->packets))
+ return 0;
+ return match_counter(opt.ext.bytes, &info->bytes);
+}
+
+#define set_match_v3_checkentry set_match_v1_checkentry
+#define set_match_v3_destroy set_match_v1_destroy
+
static struct xt_match set_matches[] __read_mostly = {
{
.name = "set",
@@ -377,6 +418,27 @@ static struct xt_match set_matches[] __read_mostly = {
.destroy = set_match_v1_destroy,
.me = THIS_MODULE
},
+ /* counters support: update, match */
+ {
+ .name = "set",
+ .family = NFPROTO_IPV4,
+ .revision = 3,
+ .match = set_match_v3,
+ .matchsize = sizeof(struct xt_set_info_match_v3),
+ .checkentry = set_match_v3_checkentry,
+ .destroy = set_match_v3_destroy,
+ .me = THIS_MODULE
+ },
+ {
+ .name = "set",
+ .family = NFPROTO_IPV6,
+ .revision = 3,
+ .match = set_match_v3,
+ .matchsize = sizeof(struct xt_set_info_match_v3),
+ .checkentry = set_match_v3_checkentry,
+ .destroy = set_match_v3_destroy,
+ .me = THIS_MODULE
+ },
};
static struct xt_target set_targets[] __read_mostly = {
diff --git a/net/netlink/Kconfig b/net/netlink/Kconfig
new file mode 100644
index 000000000000..2c5e95e9bfbd
--- /dev/null
+++ b/net/netlink/Kconfig
@@ -0,0 +1,19 @@
+#
+# Netlink Sockets
+#
+
+config NETLINK_MMAP
+ bool "NETLINK: mmaped IO"
+ ---help---
+ This option enables support for memory mapped netlink IO. This
+ reduces overhead by avoiding copying data between kernel- and
+ userspace.
+
+ If unsure, say N.
+
+config NETLINK_DIAG
+ tristate "NETLINK: socket monitoring interface"
+ default n
+ ---help---
+ Support for NETLINK socket monitoring interface used by the ss tool.
+ If unsure, say Y.
diff --git a/net/netlink/Makefile b/net/netlink/Makefile
index bdd6ddf4e95b..e837917f6c03 100644
--- a/net/netlink/Makefile
+++ b/net/netlink/Makefile
@@ -3,3 +3,6 @@
#
obj-y := af_netlink.o genetlink.o
+
+obj-$(CONFIG_NETLINK_DIAG) += netlink_diag.o
+netlink_diag-y := diag.o
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1e3fd5bfcd86..12ac6b47a35c 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -3,6 +3,7 @@
*
* Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ * Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -55,87 +56,45 @@
#include <linux/types.h>
#include <linux/audit.h>
#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+#include <asm/cacheflush.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/scm.h>
#include <net/netlink.h>
-#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
-#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
-
-struct netlink_sock {
- /* struct sock has to be the first member of netlink_sock */
- struct sock sk;
- u32 portid;
- u32 dst_portid;
- u32 dst_group;
- u32 flags;
- u32 subscriptions;
- u32 ngroups;
- unsigned long *groups;
- unsigned long state;
- wait_queue_head_t wait;
- struct netlink_callback *cb;
- struct mutex *cb_mutex;
- struct mutex cb_def_mutex;
- void (*netlink_rcv)(struct sk_buff *skb);
- void (*netlink_bind)(int group);
- struct module *module;
-};
+#include "af_netlink.h"
struct listeners {
struct rcu_head rcu;
unsigned long masks[0];
};
+/* state bits */
+#define NETLINK_CONGESTED 0x0
+
+/* flags */
#define NETLINK_KERNEL_SOCKET 0x1
#define NETLINK_RECV_PKTINFO 0x2
#define NETLINK_BROADCAST_SEND_ERROR 0x4
#define NETLINK_RECV_NO_ENOBUFS 0x8
-static inline struct netlink_sock *nlk_sk(struct sock *sk)
-{
- return container_of(sk, struct netlink_sock, sk);
-}
-
static inline int netlink_is_kernel(struct sock *sk)
{
return nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET;
}
-struct nl_portid_hash {
- struct hlist_head *table;
- unsigned long rehash_time;
-
- unsigned int mask;
- unsigned int shift;
-
- unsigned int entries;
- unsigned int max_shift;
-
- u32 rnd;
-};
-
-struct netlink_table {
- struct nl_portid_hash hash;
- struct hlist_head mc_list;
- struct listeners __rcu *listeners;
- unsigned int flags;
- unsigned int groups;
- struct mutex *cb_mutex;
- struct module *module;
- void (*bind)(int group);
- int registered;
-};
-
-static struct netlink_table *nl_table;
+struct netlink_table *nl_table;
+EXPORT_SYMBOL_GPL(nl_table);
static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
static int netlink_dump(struct sock *sk);
+static void netlink_skb_destructor(struct sk_buff *skb);
-static DEFINE_RWLOCK(nl_table_lock);
+DEFINE_RWLOCK(nl_table_lock);
+EXPORT_SYMBOL_GPL(nl_table_lock);
static atomic_t nl_table_users = ATOMIC_INIT(0);
#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
@@ -152,6 +111,599 @@ static inline struct hlist_head *nl_portid_hashfn(struct nl_portid_hash *hash, u
return &hash->table[jhash_1word(portid, hash->rnd) & hash->mask];
}
+static void netlink_overrun(struct sock *sk)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+
+ if (!(nlk->flags & NETLINK_RECV_NO_ENOBUFS)) {
+ if (!test_and_set_bit(NETLINK_CONGESTED, &nlk_sk(sk)->state)) {
+ sk->sk_err = ENOBUFS;
+ sk->sk_error_report(sk);
+ }
+ }
+ atomic_inc(&sk->sk_drops);
+}
+
+static void netlink_rcv_wake(struct sock *sk)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+
+ if (skb_queue_empty(&sk->sk_receive_queue))
+ clear_bit(NETLINK_CONGESTED, &nlk->state);
+ if (!test_bit(NETLINK_CONGESTED, &nlk->state))
+ wake_up_interruptible(&nlk->wait);
+}
+
+#ifdef CONFIG_NETLINK_MMAP
+static bool netlink_skb_is_mmaped(const struct sk_buff *skb)
+{
+ return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
+}
+
+static bool netlink_rx_is_mmaped(struct sock *sk)
+{
+ return nlk_sk(sk)->rx_ring.pg_vec != NULL;
+}
+
+static bool netlink_tx_is_mmaped(struct sock *sk)
+{
+ return nlk_sk(sk)->tx_ring.pg_vec != NULL;
+}
+
+static __pure struct page *pgvec_to_page(const void *addr)
+{
+ if (is_vmalloc_addr(addr))
+ return vmalloc_to_page(addr);
+ else
+ return virt_to_page(addr);
+}
+
+static void free_pg_vec(void **pg_vec, unsigned int order, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (pg_vec[i] != NULL) {
+ if (is_vmalloc_addr(pg_vec[i]))
+ vfree(pg_vec[i]);
+ else
+ free_pages((unsigned long)pg_vec[i], order);
+ }
+ }
+ kfree(pg_vec);
+}
+
+static void *alloc_one_pg_vec_page(unsigned long order)
+{
+ void *buffer;
+ gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | __GFP_ZERO |
+ __GFP_NOWARN | __GFP_NORETRY;
+
+ buffer = (void *)__get_free_pages(gfp_flags, order);
+ if (buffer != NULL)
+ return buffer;
+
+ buffer = vzalloc((1 << order) * PAGE_SIZE);
+ if (buffer != NULL)
+ return buffer;
+
+ gfp_flags &= ~__GFP_NORETRY;
+ return (void *)__get_free_pages(gfp_flags, order);
+}
+
+static void **alloc_pg_vec(struct netlink_sock *nlk,
+ struct nl_mmap_req *req, unsigned int order)
+{
+ unsigned int block_nr = req->nm_block_nr;
+ unsigned int i;
+ void **pg_vec, *ptr;
+
+ pg_vec = kcalloc(block_nr, sizeof(void *), GFP_KERNEL);
+ if (pg_vec == NULL)
+ return NULL;
+
+ for (i = 0; i < block_nr; i++) {
+ pg_vec[i] = ptr = alloc_one_pg_vec_page(order);
+ if (pg_vec[i] == NULL)
+ goto err1;
+ }
+
+ return pg_vec;
+err1:
+ free_pg_vec(pg_vec, order, block_nr);
+ return NULL;
+}
+
+static int netlink_set_ring(struct sock *sk, struct nl_mmap_req *req,
+ bool closing, bool tx_ring)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+ struct netlink_ring *ring;
+ struct sk_buff_head *queue;
+ void **pg_vec = NULL;
+ unsigned int order = 0;
+ int err;
+
+ ring = tx_ring ? &nlk->tx_ring : &nlk->rx_ring;
+ queue = tx_ring ? &sk->sk_write_queue : &sk->sk_receive_queue;
+
+ if (!closing) {
+ if (atomic_read(&nlk->mapped))
+ return -EBUSY;
+ if (atomic_read(&ring->pending))
+ return -EBUSY;
+ }
+
+ if (req->nm_block_nr) {
+ if (ring->pg_vec != NULL)
+ return -EBUSY;
+
+ if ((int)req->nm_block_size <= 0)
+ return -EINVAL;
+ if (!IS_ALIGNED(req->nm_block_size, PAGE_SIZE))
+ return -EINVAL;
+ if (req->nm_frame_size < NL_MMAP_HDRLEN)
+ return -EINVAL;
+ if (!IS_ALIGNED(req->nm_frame_size, NL_MMAP_MSG_ALIGNMENT))
+ return -EINVAL;
+
+ ring->frames_per_block = req->nm_block_size /
+ req->nm_frame_size;
+ if (ring->frames_per_block == 0)
+ return -EINVAL;
+ if (ring->frames_per_block * req->nm_block_nr !=
+ req->nm_frame_nr)
+ return -EINVAL;
+
+ order = get_order(req->nm_block_size);
+ pg_vec = alloc_pg_vec(nlk, req, order);
+ if (pg_vec == NULL)
+ return -ENOMEM;
+ } else {
+ if (req->nm_frame_nr)
+ return -EINVAL;
+ }
+
+ err = -EBUSY;
+ mutex_lock(&nlk->pg_vec_lock);
+ if (closing || atomic_read(&nlk->mapped) == 0) {
+ err = 0;
+ spin_lock_bh(&queue->lock);
+
+ ring->frame_max = req->nm_frame_nr - 1;
+ ring->head = 0;
+ ring->frame_size = req->nm_frame_size;
+ ring->pg_vec_pages = req->nm_block_size / PAGE_SIZE;
+
+ swap(ring->pg_vec_len, req->nm_block_nr);
+ swap(ring->pg_vec_order, order);
+ swap(ring->pg_vec, pg_vec);
+
+ __skb_queue_purge(queue);
+ spin_unlock_bh(&queue->lock);
+
+ WARN_ON(atomic_read(&nlk->mapped));
+ }
+ mutex_unlock(&nlk->pg_vec_lock);
+
+ if (pg_vec)
+ free_pg_vec(pg_vec, order, req->nm_block_nr);
+ return err;
+}
+
+static void netlink_mm_open(struct vm_area_struct *vma)
+{
+ struct file *file = vma->vm_file;
+ struct socket *sock = file->private_data;
+ struct sock *sk = sock->sk;
+
+ if (sk)
+ atomic_inc(&nlk_sk(sk)->mapped);
+}
+
+static void netlink_mm_close(struct vm_area_struct *vma)
+{
+ struct file *file = vma->vm_file;
+ struct socket *sock = file->private_data;
+ struct sock *sk = sock->sk;
+
+ if (sk)
+ atomic_dec(&nlk_sk(sk)->mapped);
+}
+
+static const struct vm_operations_struct netlink_mmap_ops = {
+ .open = netlink_mm_open,
+ .close = netlink_mm_close,
+};
+
+static int netlink_mmap(struct file *file, struct socket *sock,
+ struct vm_area_struct *vma)
+{
+ struct sock *sk = sock->sk;
+ struct netlink_sock *nlk = nlk_sk(sk);
+ struct netlink_ring *ring;
+ unsigned long start, size, expected;
+ unsigned int i;
+ int err = -EINVAL;
+
+ if (vma->vm_pgoff)
+ return -EINVAL;
+
+ mutex_lock(&nlk->pg_vec_lock);
+
+ expected = 0;
+ for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
+ if (ring->pg_vec == NULL)
+ continue;
+ expected += ring->pg_vec_len * ring->pg_vec_pages * PAGE_SIZE;
+ }
+
+ if (expected == 0)
+ goto out;
+
+ size = vma->vm_end - vma->vm_start;
+ if (size != expected)
+ goto out;
+
+ start = vma->vm_start;
+ for (ring = &nlk->rx_ring; ring <= &nlk->tx_ring; ring++) {
+ if (ring->pg_vec == NULL)
+ continue;
+
+ for (i = 0; i < ring->pg_vec_len; i++) {
+ struct page *page;
+ void *kaddr = ring->pg_vec[i];
+ unsigned int pg_num;
+
+ for (pg_num = 0; pg_num < ring->pg_vec_pages; pg_num++) {
+ page = pgvec_to_page(kaddr);
+ err = vm_insert_page(vma, start, page);
+ if (err < 0)
+ goto out;
+ start += PAGE_SIZE;
+ kaddr += PAGE_SIZE;
+ }
+ }
+ }
+
+ atomic_inc(&nlk->mapped);
+ vma->vm_ops = &netlink_mmap_ops;
+ err = 0;
+out:
+ mutex_unlock(&nlk->pg_vec_lock);
+ return 0;
+}
+
+static void netlink_frame_flush_dcache(const struct nl_mmap_hdr *hdr)
+{
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
+ struct page *p_start, *p_end;
+
+ /* First page is flushed through netlink_{get,set}_status */
+ p_start = pgvec_to_page(hdr + PAGE_SIZE);
+ p_end = pgvec_to_page((void *)hdr + NL_MMAP_HDRLEN + hdr->nm_len - 1);
+ while (p_start <= p_end) {
+ flush_dcache_page(p_start);
+ p_start++;
+ }
+#endif
+}
+
+static enum nl_mmap_status netlink_get_status(const struct nl_mmap_hdr *hdr)
+{
+ smp_rmb();
+ flush_dcache_page(pgvec_to_page(hdr));
+ return hdr->nm_status;
+}
+
+static void netlink_set_status(struct nl_mmap_hdr *hdr,
+ enum nl_mmap_status status)
+{
+ hdr->nm_status = status;
+ flush_dcache_page(pgvec_to_page(hdr));
+ smp_wmb();
+}
+
+static struct nl_mmap_hdr *
+__netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos)
+{
+ unsigned int pg_vec_pos, frame_off;
+
+ pg_vec_pos = pos / ring->frames_per_block;
+ frame_off = pos % ring->frames_per_block;
+
+ return ring->pg_vec[pg_vec_pos] + (frame_off * ring->frame_size);
+}
+
+static struct nl_mmap_hdr *
+netlink_lookup_frame(const struct netlink_ring *ring, unsigned int pos,
+ enum nl_mmap_status status)
+{
+ struct nl_mmap_hdr *hdr;
+
+ hdr = __netlink_lookup_frame(ring, pos);
+ if (netlink_get_status(hdr) != status)
+ return NULL;
+
+ return hdr;
+}
+
+static struct nl_mmap_hdr *
+netlink_current_frame(const struct netlink_ring *ring,
+ enum nl_mmap_status status)
+{
+ return netlink_lookup_frame(ring, ring->head, status);
+}
+
+static struct nl_mmap_hdr *
+netlink_previous_frame(const struct netlink_ring *ring,
+ enum nl_mmap_status status)
+{
+ unsigned int prev;
+
+ prev = ring->head ? ring->head - 1 : ring->frame_max;
+ return netlink_lookup_frame(ring, prev, status);
+}
+
+static void netlink_increment_head(struct netlink_ring *ring)
+{
+ ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0;
+}
+
+static void netlink_forward_ring(struct netlink_ring *ring)
+{
+ unsigned int head = ring->head, pos = head;
+ const struct nl_mmap_hdr *hdr;
+
+ do {
+ hdr = __netlink_lookup_frame(ring, pos);
+ if (hdr->nm_status == NL_MMAP_STATUS_UNUSED)
+ break;
+ if (hdr->nm_status != NL_MMAP_STATUS_SKIP)
+ break;
+ netlink_increment_head(ring);
+ } while (ring->head != head);
+}
+
+static bool netlink_dump_space(struct netlink_sock *nlk)
+{
+ struct netlink_ring *ring = &nlk->rx_ring;
+ struct nl_mmap_hdr *hdr;
+ unsigned int n;
+
+ hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
+ if (hdr == NULL)
+ return false;
+
+ n = ring->head + ring->frame_max / 2;
+ if (n > ring->frame_max)
+ n -= ring->frame_max;
+
+ hdr = __netlink_lookup_frame(ring, n);
+
+ return hdr->nm_status == NL_MMAP_STATUS_UNUSED;
+}
+
+static unsigned int netlink_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+ struct netlink_sock *nlk = nlk_sk(sk);
+ unsigned int mask;
+ int err;
+
+ if (nlk->rx_ring.pg_vec != NULL) {
+ /* Memory mapped sockets don't call recvmsg(), so flow control
+ * for dumps is performed here. A dump is allowed to continue
+ * if at least half the ring is unused.
+ */
+ while (nlk->cb != NULL && netlink_dump_space(nlk)) {
+ err = netlink_dump(sk);
+ if (err < 0) {
+ sk->sk_err = err;
+ sk->sk_error_report(sk);
+ break;
+ }
+ }
+ netlink_rcv_wake(sk);
+ }
+
+ mask = datagram_poll(file, sock, wait);
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ if (nlk->rx_ring.pg_vec) {
+ netlink_forward_ring(&nlk->rx_ring);
+ if (!netlink_previous_frame(&nlk->rx_ring, NL_MMAP_STATUS_UNUSED))
+ mask |= POLLIN | POLLRDNORM;
+ }
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+
+ spin_lock_bh(&sk->sk_write_queue.lock);
+ if (nlk->tx_ring.pg_vec) {
+ if (netlink_current_frame(&nlk->tx_ring, NL_MMAP_STATUS_UNUSED))
+ mask |= POLLOUT | POLLWRNORM;
+ }
+ spin_unlock_bh(&sk->sk_write_queue.lock);
+
+ return mask;
+}
+
+static struct nl_mmap_hdr *netlink_mmap_hdr(struct sk_buff *skb)
+{
+ return (struct nl_mmap_hdr *)(skb->head - NL_MMAP_HDRLEN);
+}
+
+static void netlink_ring_setup_skb(struct sk_buff *skb, struct sock *sk,
+ struct netlink_ring *ring,
+ struct nl_mmap_hdr *hdr)
+{
+ unsigned int size;
+ void *data;
+
+ size = ring->frame_size - NL_MMAP_HDRLEN;
+ data = (void *)hdr + NL_MMAP_HDRLEN;
+
+ skb->head = data;
+ skb->data = data;
+ skb_reset_tail_pointer(skb);
+ skb->end = skb->tail + size;
+ skb->len = 0;
+
+ skb->destructor = netlink_skb_destructor;
+ NETLINK_CB(skb).flags |= NETLINK_SKB_MMAPED;
+ NETLINK_CB(skb).sk = sk;
+}
+
+static int netlink_mmap_sendmsg(struct sock *sk, struct msghdr *msg,
+ u32 dst_portid, u32 dst_group,
+ struct sock_iocb *siocb)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+ struct netlink_ring *ring;
+ struct nl_mmap_hdr *hdr;
+ struct sk_buff *skb;
+ unsigned int maxlen;
+ bool excl = true;
+ int err = 0, len = 0;
+
+ /* Netlink messages are validated by the receiver before processing.
+ * In order to avoid userspace changing the contents of the message
+ * after validation, the socket and the ring may only be used by a
+ * single process, otherwise we fall back to copying.
+ */
+ if (atomic_long_read(&sk->sk_socket->file->f_count) > 2 ||
+ atomic_read(&nlk->mapped) > 1)
+ excl = false;
+
+ mutex_lock(&nlk->pg_vec_lock);
+
+ ring = &nlk->tx_ring;
+ maxlen = ring->frame_size - NL_MMAP_HDRLEN;
+
+ do {
+ hdr = netlink_current_frame(ring, NL_MMAP_STATUS_VALID);
+ if (hdr == NULL) {
+ if (!(msg->msg_flags & MSG_DONTWAIT) &&
+ atomic_read(&nlk->tx_ring.pending))
+ schedule();
+ continue;
+ }
+ if (hdr->nm_len > maxlen) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ netlink_frame_flush_dcache(hdr);
+
+ if (likely(dst_portid == 0 && dst_group == 0 && excl)) {
+ skb = alloc_skb_head(GFP_KERNEL);
+ if (skb == NULL) {
+ err = -ENOBUFS;
+ goto out;
+ }
+ sock_hold(sk);
+ netlink_ring_setup_skb(skb, sk, ring, hdr);
+ NETLINK_CB(skb).flags |= NETLINK_SKB_TX;
+ __skb_put(skb, hdr->nm_len);
+ netlink_set_status(hdr, NL_MMAP_STATUS_RESERVED);
+ atomic_inc(&ring->pending);
+ } else {
+ skb = alloc_skb(hdr->nm_len, GFP_KERNEL);
+ if (skb == NULL) {
+ err = -ENOBUFS;
+ goto out;
+ }
+ __skb_put(skb, hdr->nm_len);
+ memcpy(skb->data, (void *)hdr + NL_MMAP_HDRLEN, hdr->nm_len);
+ netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED);
+ }
+
+ netlink_increment_head(ring);
+
+ NETLINK_CB(skb).portid = nlk->portid;
+ NETLINK_CB(skb).dst_group = dst_group;
+ NETLINK_CB(skb).creds = siocb->scm->creds;
+
+ err = security_netlink_send(sk, skb);
+ if (err) {
+ kfree_skb(skb);
+ goto out;
+ }
+
+ if (unlikely(dst_group)) {
+ atomic_inc(&skb->users);
+ netlink_broadcast(sk, skb, dst_portid, dst_group,
+ GFP_KERNEL);
+ }
+ err = netlink_unicast(sk, skb, dst_portid,
+ msg->msg_flags & MSG_DONTWAIT);
+ if (err < 0)
+ goto out;
+ len += err;
+
+ } while (hdr != NULL ||
+ (!(msg->msg_flags & MSG_DONTWAIT) &&
+ atomic_read(&nlk->tx_ring.pending)));
+
+ if (len > 0)
+ err = len;
+out:
+ mutex_unlock(&nlk->pg_vec_lock);
+ return err;
+}
+
+static void netlink_queue_mmaped_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct nl_mmap_hdr *hdr;
+
+ hdr = netlink_mmap_hdr(skb);
+ hdr->nm_len = skb->len;
+ hdr->nm_group = NETLINK_CB(skb).dst_group;
+ hdr->nm_pid = NETLINK_CB(skb).creds.pid;
+ hdr->nm_uid = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid);
+ hdr->nm_gid = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid);
+ netlink_frame_flush_dcache(hdr);
+ netlink_set_status(hdr, NL_MMAP_STATUS_VALID);
+
+ NETLINK_CB(skb).flags |= NETLINK_SKB_DELIVERED;
+ kfree_skb(skb);
+}
+
+static void netlink_ring_set_copied(struct sock *sk, struct sk_buff *skb)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+ struct netlink_ring *ring = &nlk->rx_ring;
+ struct nl_mmap_hdr *hdr;
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
+ if (hdr == NULL) {
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ kfree_skb(skb);
+ netlink_overrun(sk);
+ return;
+ }
+ netlink_increment_head(ring);
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+
+ hdr->nm_len = skb->len;
+ hdr->nm_group = NETLINK_CB(skb).dst_group;
+ hdr->nm_pid = NETLINK_CB(skb).creds.pid;
+ hdr->nm_uid = from_kuid(sk_user_ns(sk), NETLINK_CB(skb).creds.uid);
+ hdr->nm_gid = from_kgid(sk_user_ns(sk), NETLINK_CB(skb).creds.gid);
+ netlink_set_status(hdr, NL_MMAP_STATUS_COPY);
+}
+
+#else /* CONFIG_NETLINK_MMAP */
+#define netlink_skb_is_mmaped(skb) false
+#define netlink_rx_is_mmaped(sk) false
+#define netlink_tx_is_mmaped(sk) false
+#define netlink_mmap sock_no_mmap
+#define netlink_poll datagram_poll
+#define netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group, siocb) 0
+#endif /* CONFIG_NETLINK_MMAP */
+
static void netlink_destroy_callback(struct netlink_callback *cb)
{
kfree_skb(cb->skb);
@@ -164,6 +716,53 @@ static void netlink_consume_callback(struct netlink_callback *cb)
kfree(cb);
}
+static void netlink_skb_destructor(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETLINK_MMAP
+ struct nl_mmap_hdr *hdr;
+ struct netlink_ring *ring;
+ struct sock *sk;
+
+ /* If a packet from the kernel to userspace was freed because of an
+ * error without being delivered to userspace, the kernel must reset
+ * the status. In the direction userspace to kernel, the status is
+ * always reset here after the packet was processed and freed.
+ */
+ if (netlink_skb_is_mmaped(skb)) {
+ hdr = netlink_mmap_hdr(skb);
+ sk = NETLINK_CB(skb).sk;
+
+ if (NETLINK_CB(skb).flags & NETLINK_SKB_TX) {
+ netlink_set_status(hdr, NL_MMAP_STATUS_UNUSED);
+ ring = &nlk_sk(sk)->tx_ring;
+ } else {
+ if (!(NETLINK_CB(skb).flags & NETLINK_SKB_DELIVERED)) {
+ hdr->nm_len = 0;
+ netlink_set_status(hdr, NL_MMAP_STATUS_VALID);
+ }
+ ring = &nlk_sk(sk)->rx_ring;
+ }
+
+ WARN_ON(atomic_read(&ring->pending) == 0);
+ atomic_dec(&ring->pending);
+ sock_put(sk);
+
+ skb->data = NULL;
+ }
+#endif
+ if (skb->sk != NULL)
+ sock_rfree(skb);
+}
+
+static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
+{
+ WARN_ON(skb->sk != NULL);
+ skb->sk = sk;
+ skb->destructor = netlink_skb_destructor;
+ atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+ sk_mem_charge(sk, skb->truesize);
+}
+
static void netlink_sock_destruct(struct sock *sk)
{
struct netlink_sock *nlk = nlk_sk(sk);
@@ -177,6 +776,18 @@ static void netlink_sock_destruct(struct sock *sk)
}
skb_queue_purge(&sk->sk_receive_queue);
+#ifdef CONFIG_NETLINK_MMAP
+ if (1) {
+ struct nl_mmap_req req;
+
+ memset(&req, 0, sizeof(req));
+ if (nlk->rx_ring.pg_vec)
+ netlink_set_ring(sk, &req, true, false);
+ memset(&req, 0, sizeof(req));
+ if (nlk->tx_ring.pg_vec)
+ netlink_set_ring(sk, &req, true, true);
+ }
+#endif /* CONFIG_NETLINK_MMAP */
if (!sock_flag(sk, SOCK_DEAD)) {
printk(KERN_ERR "Freeing alive netlink socket %p\n", sk);
@@ -440,6 +1051,9 @@ static int __netlink_create(struct net *net, struct socket *sock,
mutex_init(nlk->cb_mutex);
}
init_waitqueue_head(&nlk->wait);
+#ifdef CONFIG_NETLINK_MMAP
+ mutex_init(&nlk->pg_vec_lock);
+#endif
sk->sk_destruct = netlink_sock_destruct;
sk->sk_protocol = protocol;
@@ -771,19 +1385,6 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr,
return 0;
}
-static void netlink_overrun(struct sock *sk)
-{
- struct netlink_sock *nlk = nlk_sk(sk);
-
- if (!(nlk->flags & NETLINK_RECV_NO_ENOBUFS)) {
- if (!test_and_set_bit(0, &nlk_sk(sk)->state)) {
- sk->sk_err = ENOBUFS;
- sk->sk_error_report(sk);
- }
- }
- atomic_inc(&sk->sk_drops);
-}
-
static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid)
{
struct sock *sock;
@@ -836,8 +1437,9 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
nlk = nlk_sk(sk);
- if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
- test_bit(0, &nlk->state)) {
+ if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
+ test_bit(NETLINK_CONGESTED, &nlk->state)) &&
+ !netlink_skb_is_mmaped(skb)) {
DECLARE_WAITQUEUE(wait, current);
if (!*timeo) {
if (!ssk || netlink_is_kernel(ssk))
@@ -851,7 +1453,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
add_wait_queue(&nlk->wait, &wait);
if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
- test_bit(0, &nlk->state)) &&
+ test_bit(NETLINK_CONGESTED, &nlk->state)) &&
!sock_flag(sk, SOCK_DEAD))
*timeo = schedule_timeout(*timeo);
@@ -865,7 +1467,7 @@ int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
}
return 1;
}
- skb_set_owner_r(skb, sk);
+ netlink_skb_set_owner_r(skb, sk);
return 0;
}
@@ -873,7 +1475,14 @@ static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
{
int len = skb->len;
- skb_queue_tail(&sk->sk_receive_queue, skb);
+#ifdef CONFIG_NETLINK_MMAP
+ if (netlink_skb_is_mmaped(skb))
+ netlink_queue_mmaped_skb(sk, skb);
+ else if (netlink_rx_is_mmaped(sk))
+ netlink_ring_set_copied(sk, skb);
+ else
+#endif /* CONFIG_NETLINK_MMAP */
+ skb_queue_tail(&sk->sk_receive_queue, skb);
sk->sk_data_ready(sk, len);
return len;
}
@@ -896,7 +1505,9 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
{
int delta;
- skb_orphan(skb);
+ WARN_ON(skb->sk != NULL);
+ if (netlink_skb_is_mmaped(skb))
+ return skb;
delta = skb->end - skb->tail;
if (delta * 2 < skb->truesize)
@@ -916,16 +1527,6 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
return skb;
}
-static void netlink_rcv_wake(struct sock *sk)
-{
- struct netlink_sock *nlk = nlk_sk(sk);
-
- if (skb_queue_empty(&sk->sk_receive_queue))
- clear_bit(0, &nlk->state);
- if (!test_bit(0, &nlk->state))
- wake_up_interruptible(&nlk->wait);
-}
-
static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
struct sock *ssk)
{
@@ -935,8 +1536,8 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
ret = -ECONNREFUSED;
if (nlk->netlink_rcv != NULL) {
ret = skb->len;
- skb_set_owner_r(skb, sk);
- NETLINK_CB(skb).ssk = ssk;
+ netlink_skb_set_owner_r(skb, sk);
+ NETLINK_CB(skb).sk = ssk;
nlk->netlink_rcv(skb);
consume_skb(skb);
} else {
@@ -982,6 +1583,69 @@ retry:
}
EXPORT_SYMBOL(netlink_unicast);
+struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
+ u32 dst_portid, gfp_t gfp_mask)
+{
+#ifdef CONFIG_NETLINK_MMAP
+ struct sock *sk = NULL;
+ struct sk_buff *skb;
+ struct netlink_ring *ring;
+ struct nl_mmap_hdr *hdr;
+ unsigned int maxlen;
+
+ sk = netlink_getsockbyportid(ssk, dst_portid);
+ if (IS_ERR(sk))
+ goto out;
+
+ ring = &nlk_sk(sk)->rx_ring;
+ /* fast-path without atomic ops for common case: non-mmaped receiver */
+ if (ring->pg_vec == NULL)
+ goto out_put;
+
+ skb = alloc_skb_head(gfp_mask);
+ if (skb == NULL)
+ goto err1;
+
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ /* check again under lock */
+ if (ring->pg_vec == NULL)
+ goto out_free;
+
+ maxlen = ring->frame_size - NL_MMAP_HDRLEN;
+ if (maxlen < size)
+ goto out_free;
+
+ netlink_forward_ring(ring);
+ hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED);
+ if (hdr == NULL)
+ goto err2;
+ netlink_ring_setup_skb(skb, sk, ring, hdr);
+ netlink_set_status(hdr, NL_MMAP_STATUS_RESERVED);
+ atomic_inc(&ring->pending);
+ netlink_increment_head(ring);
+
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ return skb;
+
+err2:
+ kfree_skb(skb);
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ netlink_overrun(sk);
+err1:
+ sock_put(sk);
+ return NULL;
+
+out_free:
+ kfree_skb(skb);
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+out_put:
+ sock_put(sk);
+out:
+#endif
+ return alloc_skb(size, gfp_mask);
+}
+EXPORT_SYMBOL_GPL(netlink_alloc_skb);
+
int netlink_has_listeners(struct sock *sk, unsigned int group)
{
int res = 0;
@@ -1006,8 +1670,8 @@ static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
struct netlink_sock *nlk = nlk_sk(sk);
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
- !test_bit(0, &nlk->state)) {
- skb_set_owner_r(skb, sk);
+ !test_bit(NETLINK_CONGESTED, &nlk->state)) {
+ netlink_skb_set_owner_r(skb, sk);
__netlink_sendskb(sk, skb);
return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
}
@@ -1242,7 +1906,8 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
if (level != SOL_NETLINK)
return -ENOPROTOOPT;
- if (optlen >= sizeof(int) &&
+ if (optname != NETLINK_RX_RING && optname != NETLINK_TX_RING &&
+ optlen >= sizeof(int) &&
get_user(val, (unsigned int __user *)optval))
return -EFAULT;
@@ -1284,13 +1949,32 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
case NETLINK_NO_ENOBUFS:
if (val) {
nlk->flags |= NETLINK_RECV_NO_ENOBUFS;
- clear_bit(0, &nlk->state);
+ clear_bit(NETLINK_CONGESTED, &nlk->state);
wake_up_interruptible(&nlk->wait);
} else {
nlk->flags &= ~NETLINK_RECV_NO_ENOBUFS;
}
err = 0;
break;
+#ifdef CONFIG_NETLINK_MMAP
+ case NETLINK_RX_RING:
+ case NETLINK_TX_RING: {
+ struct nl_mmap_req req;
+
+ /* Rings might consume more memory than queue limits, require
+ * CAP_NET_ADMIN.
+ */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (optlen < sizeof(req))
+ return -EINVAL;
+ if (copy_from_user(&req, optval, sizeof(req)))
+ return -EFAULT;
+ err = netlink_set_ring(sk, &req, false,
+ optname == NETLINK_TX_RING);
+ break;
+ }
+#endif /* CONFIG_NETLINK_MMAP */
default:
err = -ENOPROTOOPT;
}
@@ -1401,6 +2085,13 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto out;
}
+ if (netlink_tx_is_mmaped(sk) &&
+ msg->msg_iov->iov_base == NULL) {
+ err = netlink_mmap_sendmsg(sk, msg, dst_portid, dst_group,
+ siocb);
+ goto out;
+ }
+
err = -EMSGSIZE;
if (len > sk->sk_sndbuf - 32)
goto out;
@@ -1695,7 +2386,7 @@ struct nlmsghdr *
__nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags)
{
struct nlmsghdr *nlh;
- int size = NLMSG_LENGTH(len);
+ int size = nlmsg_msg_size(len);
nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
nlh->nlmsg_type = type;
@@ -1704,7 +2395,7 @@ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int fla
nlh->nlmsg_pid = portid;
nlh->nlmsg_seq = seq;
if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)
- memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
+ memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size);
return nlh;
}
EXPORT_SYMBOL(__nlmsg_put);
@@ -1733,9 +2424,13 @@ static int netlink_dump(struct sock *sk)
alloc_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE);
- skb = sock_rmalloc(sk, alloc_size, 0, GFP_KERNEL);
+ if (!netlink_rx_is_mmaped(sk) &&
+ atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
+ goto errout_skb;
+ skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL);
if (!skb)
goto errout_skb;
+ netlink_skb_set_owner_r(skb, sk);
len = cb->dump(skb, cb);
@@ -1790,13 +2485,25 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
if (cb == NULL)
return -ENOBUFS;
+ /* Memory mapped dump requests need to be copied to avoid looping
+ * on the pending state in netlink_mmap_sendmsg() while the CB hold
+ * a reference to the skb.
+ */
+ if (netlink_skb_is_mmaped(skb)) {
+ skb = skb_copy(skb, GFP_KERNEL);
+ if (skb == NULL) {
+ kfree(cb);
+ return -ENOBUFS;
+ }
+ } else
+ atomic_inc(&skb->users);
+
cb->dump = control->dump;
cb->done = control->done;
cb->nlh = nlh;
cb->data = control->data;
cb->module = control->module;
cb->min_dump_alloc = control->min_dump_alloc;
- atomic_inc(&skb->users);
cb->skb = skb;
sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid);
@@ -1850,7 +2557,8 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
if (err)
payload += nlmsg_len(nlh);
- skb = nlmsg_new(payload, GFP_KERNEL);
+ skb = netlink_alloc_skb(in_skb->sk, nlmsg_total_size(payload),
+ NETLINK_CB(in_skb).portid, GFP_KERNEL);
if (!skb) {
struct sock *sk;
@@ -2116,7 +2824,7 @@ static const struct proto_ops netlink_ops = {
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = netlink_getname,
- .poll = datagram_poll,
+ .poll = netlink_poll,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
@@ -2124,7 +2832,7 @@ static const struct proto_ops netlink_ops = {
.getsockopt = netlink_getsockopt,
.sendmsg = netlink_sendmsg,
.recvmsg = netlink_recvmsg,
- .mmap = sock_no_mmap,
+ .mmap = netlink_mmap,
.sendpage = sock_no_sendpage,
};
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
new file mode 100644
index 000000000000..ed8522265f4e
--- /dev/null
+++ b/net/netlink/af_netlink.h
@@ -0,0 +1,82 @@
+#ifndef _AF_NETLINK_H
+#define _AF_NETLINK_H
+
+#include <net/sock.h>
+
+#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
+#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
+
+struct netlink_ring {
+ void **pg_vec;
+ unsigned int head;
+ unsigned int frames_per_block;
+ unsigned int frame_size;
+ unsigned int frame_max;
+
+ unsigned int pg_vec_order;
+ unsigned int pg_vec_pages;
+ unsigned int pg_vec_len;
+
+ atomic_t pending;
+};
+
+struct netlink_sock {
+ /* struct sock has to be the first member of netlink_sock */
+ struct sock sk;
+ u32 portid;
+ u32 dst_portid;
+ u32 dst_group;
+ u32 flags;
+ u32 subscriptions;
+ u32 ngroups;
+ unsigned long *groups;
+ unsigned long state;
+ wait_queue_head_t wait;
+ struct netlink_callback *cb;
+ struct mutex *cb_mutex;
+ struct mutex cb_def_mutex;
+ void (*netlink_rcv)(struct sk_buff *skb);
+ void (*netlink_bind)(int group);
+ struct module *module;
+#ifdef CONFIG_NETLINK_MMAP
+ struct mutex pg_vec_lock;
+ struct netlink_ring rx_ring;
+ struct netlink_ring tx_ring;
+ atomic_t mapped;
+#endif /* CONFIG_NETLINK_MMAP */
+};
+
+static inline struct netlink_sock *nlk_sk(struct sock *sk)
+{
+ return container_of(sk, struct netlink_sock, sk);
+}
+
+struct nl_portid_hash {
+ struct hlist_head *table;
+ unsigned long rehash_time;
+
+ unsigned int mask;
+ unsigned int shift;
+
+ unsigned int entries;
+ unsigned int max_shift;
+
+ u32 rnd;
+};
+
+struct netlink_table {
+ struct nl_portid_hash hash;
+ struct hlist_head mc_list;
+ struct listeners __rcu *listeners;
+ unsigned int flags;
+ unsigned int groups;
+ struct mutex *cb_mutex;
+ struct module *module;
+ void (*bind)(int group);
+ int registered;
+};
+
+extern struct netlink_table *nl_table;
+extern rwlock_t nl_table_lock;
+
+#endif
diff --git a/net/netlink/diag.c b/net/netlink/diag.c
new file mode 100644
index 000000000000..1af29624b92f
--- /dev/null
+++ b/net/netlink/diag.c
@@ -0,0 +1,227 @@
+#include <linux/module.h>
+
+#include <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/sock_diag.h>
+#include <linux/netlink_diag.h>
+
+#include "af_netlink.h"
+
+#ifdef CONFIG_NETLINK_MMAP
+static int sk_diag_put_ring(struct netlink_ring *ring, int nl_type,
+ struct sk_buff *nlskb)
+{
+ struct netlink_diag_ring ndr;
+
+ ndr.ndr_block_size = ring->pg_vec_pages << PAGE_SHIFT;
+ ndr.ndr_block_nr = ring->pg_vec_len;
+ ndr.ndr_frame_size = ring->frame_size;
+ ndr.ndr_frame_nr = ring->frame_max + 1;
+
+ return nla_put(nlskb, nl_type, sizeof(ndr), &ndr);
+}
+
+static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+ int ret;
+
+ mutex_lock(&nlk->pg_vec_lock);
+ ret = sk_diag_put_ring(&nlk->rx_ring, NETLINK_DIAG_RX_RING, nlskb);
+ if (!ret)
+ ret = sk_diag_put_ring(&nlk->tx_ring, NETLINK_DIAG_TX_RING,
+ nlskb);
+ mutex_unlock(&nlk->pg_vec_lock);
+
+ return ret;
+}
+#else
+static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
+{
+ return 0;
+}
+#endif
+
+static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
+{
+ struct netlink_sock *nlk = nlk_sk(sk);
+
+ if (nlk->groups == NULL)
+ return 0;
+
+ return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups),
+ nlk->groups);
+}
+
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+ struct netlink_diag_req *req,
+ u32 portid, u32 seq, u32 flags, int sk_ino)
+{
+ struct nlmsghdr *nlh;
+ struct netlink_diag_msg *rep;
+ struct netlink_sock *nlk = nlk_sk(sk);
+
+ nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
+ flags);
+ if (!nlh)
+ return -EMSGSIZE;
+
+ rep = nlmsg_data(nlh);
+ rep->ndiag_family = AF_NETLINK;
+ rep->ndiag_type = sk->sk_type;
+ rep->ndiag_protocol = sk->sk_protocol;
+ rep->ndiag_state = sk->sk_state;
+
+ rep->ndiag_ino = sk_ino;
+ rep->ndiag_portid = nlk->portid;
+ rep->ndiag_dst_portid = nlk->dst_portid;
+ rep->ndiag_dst_group = nlk->dst_group;
+ sock_diag_save_cookie(sk, rep->ndiag_cookie);
+
+ if ((req->ndiag_show & NDIAG_SHOW_GROUPS) &&
+ sk_diag_dump_groups(sk, skb))
+ goto out_nlmsg_trim;
+
+ if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
+ sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
+ goto out_nlmsg_trim;
+
+ if ((req->ndiag_show & NDIAG_SHOW_RING_CFG) &&
+ sk_diag_put_rings_cfg(sk, skb))
+ goto out_nlmsg_trim;
+
+ return nlmsg_end(skb, nlh);
+
+out_nlmsg_trim:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
+ int protocol, int s_num)
+{
+ struct netlink_table *tbl = &nl_table[protocol];
+ struct nl_portid_hash *hash = &tbl->hash;
+ struct net *net = sock_net(skb->sk);
+ struct netlink_diag_req *req;
+ struct sock *sk;
+ int ret = 0, num = 0, i;
+
+ req = nlmsg_data(cb->nlh);
+
+ for (i = 0; i <= hash->mask; i++) {
+ sk_for_each(sk, &hash->table[i]) {
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (num < s_num) {
+ num++;
+ continue;
+ }
+
+ if (sk_diag_fill(sk, skb, req,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI,
+ sock_i_ino(sk)) < 0) {
+ ret = 1;
+ goto done;
+ }
+
+ num++;
+ }
+ }
+
+ sk_for_each_bound(sk, &tbl->mc_list) {
+ if (sk_hashed(sk))
+ continue;
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (num < s_num) {
+ num++;
+ continue;
+ }
+
+ if (sk_diag_fill(sk, skb, req,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI,
+ sock_i_ino(sk)) < 0) {
+ ret = 1;
+ goto done;
+ }
+ num++;
+ }
+done:
+ cb->args[0] = num;
+ cb->args[1] = protocol;
+
+ return ret;
+}
+
+static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct netlink_diag_req *req;
+ int s_num = cb->args[0];
+
+ req = nlmsg_data(cb->nlh);
+
+ read_lock(&nl_table_lock);
+
+ if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
+ int i;
+
+ for (i = cb->args[1]; i < MAX_LINKS; i++) {
+ if (__netlink_diag_dump(skb, cb, i, s_num))
+ break;
+ s_num = 0;
+ }
+ } else {
+ if (req->sdiag_protocol >= MAX_LINKS) {
+ read_unlock(&nl_table_lock);
+ return -ENOENT;
+ }
+
+ __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
+ }
+
+ read_unlock(&nl_table_lock);
+
+ return skb->len;
+}
+
+static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+{
+ int hdrlen = sizeof(struct netlink_diag_req);
+ struct net *net = sock_net(skb->sk);
+
+ if (nlmsg_len(h) < hdrlen)
+ return -EINVAL;
+
+ if (h->nlmsg_flags & NLM_F_DUMP) {
+ struct netlink_dump_control c = {
+ .dump = netlink_diag_dump,
+ };
+ return netlink_dump_start(net->diag_nlsk, skb, h, &c);
+ } else
+ return -EOPNOTSUPP;
+}
+
+static const struct sock_diag_handler netlink_diag_handler = {
+ .family = AF_NETLINK,
+ .dump = netlink_diag_handler_dump,
+};
+
+static int __init netlink_diag_init(void)
+{
+ return sock_diag_register(&netlink_diag_handler);
+}
+
+static void __exit netlink_diag_exit(void)
+{
+ sock_diag_unregister(&netlink_diag_handler);
+}
+
+module_init(netlink_diag_init);
+module_exit(netlink_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 5a55be3f17a5..2fd6dbea327a 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -16,10 +16,12 @@
#include <linux/skbuff.h>
#include <linux/mutex.h>
#include <linux/bitmap.h>
+#include <linux/rwsem.h>
#include <net/sock.h>
#include <net/genetlink.h>
static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
+static DECLARE_RWSEM(cb_lock);
void genl_lock(void)
{
@@ -41,6 +43,18 @@ int lockdep_genl_is_held(void)
EXPORT_SYMBOL(lockdep_genl_is_held);
#endif
+static void genl_lock_all(void)
+{
+ down_write(&cb_lock);
+ genl_lock();
+}
+
+static void genl_unlock_all(void)
+{
+ genl_unlock();
+ up_write(&cb_lock);
+}
+
#define GENL_FAM_TAB_SIZE 16
#define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1)
@@ -144,7 +158,7 @@ int genl_register_mc_group(struct genl_family *family,
BUG_ON(grp->name[0] == '\0');
BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL);
- genl_lock();
+ genl_lock_all();
/* special-case our own group */
if (grp == &notify_grp)
@@ -213,7 +227,7 @@ int genl_register_mc_group(struct genl_family *family,
genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
out:
- genl_unlock();
+ genl_unlock_all();
return err;
}
EXPORT_SYMBOL(genl_register_mc_group);
@@ -255,9 +269,9 @@ static void __genl_unregister_mc_group(struct genl_family *family,
void genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp)
{
- genl_lock();
+ genl_lock_all();
__genl_unregister_mc_group(family, grp);
- genl_unlock();
+ genl_unlock_all();
}
EXPORT_SYMBOL(genl_unregister_mc_group);
@@ -303,9 +317,9 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
if (ops->policy)
ops->flags |= GENL_CMD_CAP_HASPOL;
- genl_lock();
+ genl_lock_all();
list_add_tail(&ops->ops_list, &family->ops_list);
- genl_unlock();
+ genl_unlock_all();
genl_ctrl_event(CTRL_CMD_NEWOPS, ops);
err = 0;
@@ -334,16 +348,16 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
{
struct genl_ops *rc;
- genl_lock();
+ genl_lock_all();
list_for_each_entry(rc, &family->ops_list, ops_list) {
if (rc == ops) {
list_del(&ops->ops_list);
- genl_unlock();
+ genl_unlock_all();
genl_ctrl_event(CTRL_CMD_DELOPS, ops);
return 0;
}
}
- genl_unlock();
+ genl_unlock_all();
return -ENOENT;
}
@@ -373,7 +387,7 @@ int genl_register_family(struct genl_family *family)
INIT_LIST_HEAD(&family->ops_list);
INIT_LIST_HEAD(&family->mcast_groups);
- genl_lock();
+ genl_lock_all();
if (genl_family_find_byname(family->name)) {
err = -EEXIST;
@@ -394,7 +408,7 @@ int genl_register_family(struct genl_family *family)
goto errout_locked;
}
- if (family->maxattr) {
+ if (family->maxattr && !family->parallel_ops) {
family->attrbuf = kmalloc((family->maxattr+1) *
sizeof(struct nlattr *), GFP_KERNEL);
if (family->attrbuf == NULL) {
@@ -405,14 +419,14 @@ int genl_register_family(struct genl_family *family)
family->attrbuf = NULL;
list_add_tail(&family->family_list, genl_family_chain(family->id));
- genl_unlock();
+ genl_unlock_all();
genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
return 0;
errout_locked:
- genl_unlock();
+ genl_unlock_all();
errout:
return err;
}
@@ -476,7 +490,7 @@ int genl_unregister_family(struct genl_family *family)
{
struct genl_family *rc;
- genl_lock();
+ genl_lock_all();
genl_unregister_mc_groups(family);
@@ -486,14 +500,14 @@ int genl_unregister_family(struct genl_family *family)
list_del(&rc->family_list);
INIT_LIST_HEAD(&family->ops_list);
- genl_unlock();
+ genl_unlock_all();
kfree(family->attrbuf);
genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
return 0;
}
- genl_unlock();
+ genl_unlock_all();
return -ENOENT;
}
@@ -530,19 +544,17 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
}
EXPORT_SYMBOL(genlmsg_put);
-static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+static int genl_family_rcv_msg(struct genl_family *family,
+ struct sk_buff *skb,
+ struct nlmsghdr *nlh)
{
struct genl_ops *ops;
- struct genl_family *family;
struct net *net = sock_net(skb->sk);
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
+ struct nlattr **attrbuf;
int hdrlen, err;
- family = genl_family_find_byid(nlh->nlmsg_type);
- if (family == NULL)
- return -ENOENT;
-
/* this family doesn't exist in this netns */
if (!family->netnsok && !net_eq(net, &init_net))
return -ENOENT;
@@ -560,29 +572,33 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
+ struct netlink_dump_control c = {
+ .dump = ops->dumpit,
+ .done = ops->done,
+ };
+
if (ops->dumpit == NULL)
return -EOPNOTSUPP;
- genl_unlock();
- {
- struct netlink_dump_control c = {
- .dump = ops->dumpit,
- .done = ops->done,
- };
- err = netlink_dump_start(net->genl_sock, skb, nlh, &c);
- }
- genl_lock();
- return err;
+ return netlink_dump_start(net->genl_sock, skb, nlh, &c);
}
if (ops->doit == NULL)
return -EOPNOTSUPP;
- if (family->attrbuf) {
- err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
+ if (family->maxattr && family->parallel_ops) {
+ attrbuf = kmalloc((family->maxattr+1) *
+ sizeof(struct nlattr *), GFP_KERNEL);
+ if (attrbuf == NULL)
+ return -ENOMEM;
+ } else
+ attrbuf = family->attrbuf;
+
+ if (attrbuf) {
+ err = nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
ops->policy);
if (err < 0)
- return err;
+ goto out;
}
info.snd_seq = nlh->nlmsg_seq;
@@ -590,14 +606,14 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
info.nlhdr = nlh;
info.genlhdr = nlmsg_data(nlh);
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
- info.attrs = family->attrbuf;
+ info.attrs = attrbuf;
genl_info_net_set(&info, net);
memset(&info.user_ptr, 0, sizeof(info.user_ptr));
if (family->pre_doit) {
err = family->pre_doit(ops, skb, &info);
if (err)
- return err;
+ goto out;
}
err = ops->doit(skb, &info);
@@ -605,14 +621,38 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (family->post_doit)
family->post_doit(ops, skb, &info);
+out:
+ if (family->parallel_ops)
+ kfree(attrbuf);
+
+ return err;
+}
+
+static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+ struct genl_family *family;
+ int err;
+
+ family = genl_family_find_byid(nlh->nlmsg_type);
+ if (family == NULL)
+ return -ENOENT;
+
+ if (!family->parallel_ops)
+ genl_lock();
+
+ err = genl_family_rcv_msg(family, skb, nlh);
+
+ if (!family->parallel_ops)
+ genl_unlock();
+
return err;
}
static void genl_rcv(struct sk_buff *skb)
{
- genl_lock();
+ down_read(&cb_lock);
netlink_rcv_skb(skb, &genl_rcv_msg);
- genl_unlock();
+ up_read(&cb_lock);
}
/**************************************************************************
@@ -918,7 +958,6 @@ static int __net_init genl_pernet_init(struct net *net)
{
struct netlink_kernel_cfg cfg = {
.input = genl_rcv,
- .cb_mutex = &genl_mutex,
.flags = NL_CFG_F_NONROOT_RECV,
};
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index d1fa1d9ffd2e..ec0c80fde69f 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -834,6 +834,8 @@ static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
struct sock *sk = sock->sk;
struct nr_sock *nr = nr_sk(sk);
+ memset(&sax->fsa_ax25, 0, sizeof(struct sockaddr_ax25));
+
lock_sock(sk);
if (peer != 0) {
if (sk->sk_state != TCP_ESTABLISHED) {
@@ -1173,6 +1175,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
}
if (sax != NULL) {
+ memset(sax, 0, sizeof(*sax));
sax->sax25_family = AF_NETROM;
skb_copy_from_linear_data_offset(skb, 7, sax->sax25_call.ax25_call,
AX25_ADDR_LEN);
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig
index 60c3bbb63e8e..5948b2fc72f6 100644
--- a/net/nfc/Kconfig
+++ b/net/nfc/Kconfig
@@ -4,6 +4,7 @@
menuconfig NFC
depends on NET
+ depends on RFKILL || !RFKILL
tristate "NFC subsystem support"
default n
help
@@ -15,6 +16,5 @@ menuconfig NFC
source "net/nfc/nci/Kconfig"
source "net/nfc/hci/Kconfig"
-source "net/nfc/llcp/Kconfig"
source "drivers/nfc/Kconfig"
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index d1a117c2c401..fb799deaed4f 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -5,6 +5,8 @@
obj-$(CONFIG_NFC) += nfc.o
obj-$(CONFIG_NFC_NCI) += nci/
obj-$(CONFIG_NFC_HCI) += hci/
+#obj-$(CONFIG_NFC_LLCP) += llcp/
+
+nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \
+ llcp_sock.o
-nfc-objs := core.o netlink.o af_nfc.o rawsock.o
-nfc-$(CONFIG_NFC_LLCP) += llcp/llcp.o llcp/commands.o llcp/sock.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 6ceee8e181ca..40d2527693da 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/rfkill.h>
#include <linux/nfc.h>
#include <net/genetlink.h>
@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
device_lock(&dev->dev);
+ if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
+ rc = -ERFKILL;
+ goto error;
+ }
+
if (!device_is_registered(&dev->dev)) {
rc = -ENODEV;
goto error;
@@ -117,6 +123,24 @@ error:
return rc;
}
+static int nfc_rfkill_set_block(void *data, bool blocked)
+{
+ struct nfc_dev *dev = data;
+
+ pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
+
+ if (!blocked)
+ return 0;
+
+ nfc_dev_down(dev);
+
+ return 0;
+}
+
+static const struct rfkill_ops nfc_rfkill_ops = {
+ .set_block = nfc_rfkill_set_block,
+};
+
/**
* nfc_start_poll - start polling for nfc targets
*
@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
goto error;
}
+ if (!dev->dev_up) {
+ rc = -ENODEV;
+ goto error;
+ }
+
if (dev->polling) {
rc = -EBUSY;
goto error;
@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
pr_debug("The userspace won't be notified that the device %s was added\n",
dev_name(&dev->dev));
+ dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
+ RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
+ if (dev->rfkill) {
+ if (rfkill_register(dev->rfkill) < 0) {
+ rfkill_destroy(dev->rfkill);
+ dev->rfkill = NULL;
+ }
+ }
+
return 0;
}
EXPORT_SYMBOL(nfc_register_device);
@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
id = dev->idx;
+ if (dev->rfkill) {
+ rfkill_unregister(dev->rfkill);
+ rfkill_destroy(dev->rfkill);
+ }
+
if (dev->ops->check_presence) {
device_lock(&dev->dev);
dev->shutting_down = true;
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp.h
index 0eae5c509504..ff8c434f7df8 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp.h
@@ -31,6 +31,7 @@ enum llcp_state {
#define LLCP_MAX_LTO 0xff
#define LLCP_MAX_RW 15
#define LLCP_MAX_MIUX 0x7ff
+#define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128)
#define LLCP_WKS_NUM_SAP 16
#define LLCP_SDP_NUM_SAP 16
@@ -46,6 +47,19 @@ struct llcp_sock_list {
rwlock_t lock;
};
+struct nfc_llcp_sdp_tlv {
+ u8 *tlv;
+ u8 tlv_len;
+
+ char *uri;
+ u8 tid;
+ u8 sap;
+
+ unsigned long time;
+
+ struct hlist_node node;
+};
+
struct nfc_llcp_local {
struct list_head list;
struct nfc_dev *dev;
@@ -86,6 +100,12 @@ struct nfc_llcp_local {
u8 remote_opt;
u16 remote_wks;
+ struct mutex sdreq_lock;
+ struct hlist_head pending_sdreqs;
+ struct timer_list sdreq_timer;
+ struct work_struct sdreq_timeout_work;
+ u8 sdreq_next_tid;
+
/* sockets array */
struct llcp_sock_list sockets;
struct llcp_sock_list connecting_sockets;
@@ -105,7 +125,12 @@ struct nfc_llcp_sock {
char *service_name;
size_t service_name_len;
u8 rw;
- u16 miu;
+ __be16 miux;
+
+
+ /* Remote link parameters */
+ u8 remote_rw;
+ u16 remote_miu;
/* Link variables */
u8 send_n;
@@ -138,6 +163,7 @@ struct nfc_llcp_ui_cb {
#define LLCP_HEADER_SIZE 2
#define LLCP_SEQUENCE_SIZE 1
+#define LLCP_AGF_PDU_HEADER_SIZE 2
/* LLCP versions: 1.1 is 1.0 plus SDP */
#define LLCP_VERSION_10 0x10
@@ -186,6 +212,7 @@ struct nfc_llcp_ui_cb {
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
+void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
int nfc_llcp_local_put(struct nfc_llcp_local *local);
@@ -213,12 +240,20 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
/* Commands API */
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length);
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap);
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
+ size_t uri_len);
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head);
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_symm(struct nfc_dev *dev);
int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
-int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap);
+int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
+ struct hlist_head *tlv_list, size_t tlvs_len);
+int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
+ struct hlist_head *tlv_list, size_t tlvs_len);
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
diff --git a/net/nfc/llcp/Kconfig b/net/nfc/llcp/Kconfig
deleted file mode 100644
index a1a41cd68255..000000000000
--- a/net/nfc/llcp/Kconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-config NFC_LLCP
- depends on NFC
- bool "NFC LLCP support"
- default n
- help
- Say Y here if you want to build support for a kernel NFC LLCP
- implementation. \ No newline at end of file
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp_commands.c
index c6bc3bd95052..c1b23eef83ca 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp_commands.c
@@ -26,7 +26,7 @@
#include <net/nfc/nfc.h>
-#include "../nfc.h"
+#include "nfc.h"
#include "llcp.h"
static u8 llcp_tlv_length[LLCP_TLV_MAX] = {
@@ -117,6 +117,88 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
return tlv;
}
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap)
+{
+ struct nfc_llcp_sdp_tlv *sdres;
+ u8 value[2];
+
+ sdres = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
+ if (sdres == NULL)
+ return NULL;
+
+ value[0] = tid;
+ value[1] = sap;
+
+ sdres->tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, value, 2,
+ &sdres->tlv_len);
+ if (sdres->tlv == NULL) {
+ kfree(sdres);
+ return NULL;
+ }
+
+ sdres->tid = tid;
+ sdres->sap = sap;
+
+ INIT_HLIST_NODE(&sdres->node);
+
+ return sdres;
+}
+
+struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
+ size_t uri_len)
+{
+ struct nfc_llcp_sdp_tlv *sdreq;
+
+ pr_debug("uri: %s, len: %zu\n", uri, uri_len);
+
+ sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
+ if (sdreq == NULL)
+ return NULL;
+
+ sdreq->tlv_len = uri_len + 3;
+
+ if (uri[uri_len - 1] == 0)
+ sdreq->tlv_len--;
+
+ sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL);
+ if (sdreq->tlv == NULL) {
+ kfree(sdreq);
+ return NULL;
+ }
+
+ sdreq->tlv[0] = LLCP_TLV_SDREQ;
+ sdreq->tlv[1] = sdreq->tlv_len - 2;
+ sdreq->tlv[2] = tid;
+
+ sdreq->tid = tid;
+ sdreq->uri = sdreq->tlv + 3;
+ memcpy(sdreq->uri, uri, uri_len);
+
+ sdreq->time = jiffies;
+
+ INIT_HLIST_NODE(&sdreq->node);
+
+ return sdreq;
+}
+
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
+{
+ kfree(sdp->tlv);
+ kfree(sdp);
+}
+
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head)
+{
+ struct nfc_llcp_sdp_tlv *sdp;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_safe(sdp, n, head, node) {
+ hlist_del(&sdp->node);
+
+ nfc_llcp_free_sdp_tlv(sdp);
+ }
+}
+
int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
u8 *tlv_array, u16 tlv_array_len)
{
@@ -184,10 +266,10 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
switch (type) {
case LLCP_TLV_MIUX:
- sock->miu = llcp_tlv_miux(tlv) + 128;
+ sock->remote_miu = llcp_tlv_miux(tlv) + 128;
break;
case LLCP_TLV_RW:
- sock->rw = llcp_tlv_rw(tlv);
+ sock->remote_rw = llcp_tlv_rw(tlv);
break;
case LLCP_TLV_SN:
break;
@@ -200,7 +282,8 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
tlv += length + 2;
}
- pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
+ pr_debug("sock %p rw %d miu %d\n", sock,
+ sock->remote_rw, sock->remote_miu);
return 0;
}
@@ -318,9 +401,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
struct sk_buff *skb;
u8 *service_name_tlv = NULL, service_name_tlv_length;
u8 *miux_tlv = NULL, miux_tlv_length;
- u8 *rw_tlv = NULL, rw_tlv_length;
+ u8 *rw_tlv = NULL, rw_tlv_length, rw;
int err;
- u16 size = 0;
+ u16 size = 0, miux;
pr_debug("Sending CONNECT\n");
@@ -336,11 +419,16 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
size += service_name_tlv_length;
}
- miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
+ /* If the socket parameters are not set, use the local ones */
+ miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
+ local->miux : sock->miux;
+ rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
+
+ miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
&miux_tlv_length);
size += miux_tlv_length;
- rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
+ rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
size += rw_tlv_length;
pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
@@ -377,9 +465,9 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
struct nfc_llcp_local *local;
struct sk_buff *skb;
u8 *miux_tlv = NULL, miux_tlv_length;
- u8 *rw_tlv = NULL, rw_tlv_length;
+ u8 *rw_tlv = NULL, rw_tlv_length, rw;
int err;
- u16 size = 0;
+ u16 size = 0, miux;
pr_debug("Sending CC\n");
@@ -387,11 +475,16 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
if (local == NULL)
return -ENODEV;
- miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0,
+ /* If the socket parameters are not set, use the local ones */
+ miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
+ local->miux : sock->miux;
+ rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
+
+ miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
&miux_tlv_length);
size += miux_tlv_length;
- rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length);
+ rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
size += rw_tlv_length;
skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
@@ -416,48 +509,90 @@ error_tlv:
return err;
}
-int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap)
+static struct sk_buff *nfc_llcp_allocate_snl(struct nfc_llcp_local *local,
+ size_t tlv_length)
{
struct sk_buff *skb;
struct nfc_dev *dev;
- u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2];
u16 size = 0;
- pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap);
-
if (local == NULL)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
dev = local->dev;
if (dev == NULL)
- return -ENODEV;
-
- sdres[0] = tid;
- sdres[1] = sap;
- sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0,
- &sdres_tlv_length);
- if (sdres_tlv == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENODEV);
size += LLCP_HEADER_SIZE;
size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
- size += sdres_tlv_length;
+ size += tlv_length;
skb = alloc_skb(size, GFP_KERNEL);
- if (skb == NULL) {
- kfree(sdres_tlv);
- return -ENOMEM;
- }
+ if (skb == NULL)
+ return ERR_PTR(-ENOMEM);
skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL);
- memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length);
+ return skb;
+}
+
+int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
+ struct hlist_head *tlv_list, size_t tlvs_len)
+{
+ struct nfc_llcp_sdp_tlv *sdp;
+ struct hlist_node *n;
+ struct sk_buff *skb;
+
+ skb = nfc_llcp_allocate_snl(local, tlvs_len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hlist_for_each_entry_safe(sdp, n, tlv_list, node) {
+ memcpy(skb_put(skb, sdp->tlv_len), sdp->tlv, sdp->tlv_len);
+
+ hlist_del(&sdp->node);
+
+ nfc_llcp_free_sdp_tlv(sdp);
+ }
skb_queue_tail(&local->tx_queue, skb);
- kfree(sdres_tlv);
+ return 0;
+}
+
+int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
+ struct hlist_head *tlv_list, size_t tlvs_len)
+{
+ struct nfc_llcp_sdp_tlv *sdreq;
+ struct hlist_node *n;
+ struct sk_buff *skb;
+
+ skb = nfc_llcp_allocate_snl(local, tlvs_len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mutex_lock(&local->sdreq_lock);
+
+ if (hlist_empty(&local->pending_sdreqs))
+ mod_timer(&local->sdreq_timer,
+ jiffies + msecs_to_jiffies(3 * local->remote_lto));
+
+ hlist_for_each_entry_safe(sdreq, n, tlv_list, node) {
+ pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri);
+
+ memcpy(skb_put(skb, sdreq->tlv_len), sdreq->tlv,
+ sdreq->tlv_len);
+
+ hlist_del(&sdreq->node);
+
+ hlist_add_head(&sdreq->node, &local->pending_sdreqs);
+ }
+
+ mutex_unlock(&local->sdreq_lock);
+
+ skb_queue_tail(&local->tx_queue, skb);
return 0;
}
@@ -523,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len;
u8 *msg_data, *msg_ptr;
+ u16 remote_miu;
pr_debug("Send I frame len %zd\n", len);
@@ -532,8 +668,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
/* Remote is ready but has not acknowledged our frames */
if((sock->remote_ready &&
- skb_queue_len(&sock->tx_pending_queue) >= sock->rw &&
- skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) {
+ skb_queue_len(&sock->tx_pending_queue) >= sock->remote_rw &&
+ skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
pr_err("Pending queue is full %d frames\n",
skb_queue_len(&sock->tx_pending_queue));
return -ENOBUFS;
@@ -541,7 +677,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
/* Remote is not ready and we've been queueing enough frames */
if ((!sock->remote_ready &&
- skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) {
+ skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
pr_err("Tx queue is full %d frames\n",
skb_queue_len(&sock->tx_queue));
return -ENOBUFS;
@@ -559,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len = len;
msg_ptr = msg_data;
- while (remaining_len > 0) {
+ do {
+ remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
+ local->remote_miu : sock->remote_miu;
- frag_len = min_t(size_t, sock->miu, remaining_len);
+ frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
@@ -573,7 +711,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
skb_put(pdu, LLCP_SEQUENCE_SIZE);
- memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+ if (likely(frag_len > 0))
+ memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
skb_queue_tail(&sock->tx_queue, pdu);
@@ -585,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
remaining_len -= frag_len;
msg_ptr += frag_len;
- }
+ } while (remaining_len > 0);
kfree(msg_data);
@@ -599,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
struct nfc_llcp_local *local;
size_t frag_len = 0, remaining_len;
u8 *msg_ptr, *msg_data;
+ u16 remote_miu;
int err;
pr_debug("Send UI frame len %zd\n", len);
@@ -619,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
remaining_len = len;
msg_ptr = msg_data;
- while (remaining_len > 0) {
+ do {
+ remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
+ local->remote_miu : sock->remote_miu;
- frag_len = min_t(size_t, sock->miu, remaining_len);
+ frag_len = min_t(size_t, remote_miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
@@ -635,14 +777,15 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
- memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+ if (likely(frag_len > 0))
+ memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
/* No need to check for the peer RW for UI frames */
skb_queue_tail(&local->tx_queue, pdu);
remaining_len -= frag_len;
msg_ptr += frag_len;
- }
+ } while (remaining_len > 0);
kfree(msg_data);
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp_core.c
index b530afadd76c..158bdbf668cc 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp_core.c
@@ -24,13 +24,15 @@
#include <linux/list.h>
#include <linux/nfc.h>
-#include "../nfc.h"
+#include "nfc.h"
#include "llcp.h"
static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
static struct list_head llcp_devices;
+static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
+
void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
write_unlock(&l->lock);
}
+void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock)
+{
+ sock->remote_rw = LLCP_DEFAULT_RW;
+ sock->remote_miu = LLCP_MAX_MIU + 1;
+}
+
static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
{
struct nfc_llcp_local *local = sock->local;
@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
}
}
-static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
+static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
int err)
{
struct sock *sk;
@@ -107,26 +115,9 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
accept_sk->sk_state_change(sk);
bh_unlock_sock(accept_sk);
-
- sock_orphan(accept_sk);
- }
-
- if (listen == true) {
- bh_unlock_sock(sk);
- continue;
}
}
- /*
- * If we have a connection less socket bound, we keep it alive
- * if the device is still present.
- */
- if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
- listen == true) {
- bh_unlock_sock(sk);
- continue;
- }
-
if (err)
sk->sk_err = err;
sk->sk_state = LLCP_CLOSED;
@@ -134,18 +125,13 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(sk);
- sock_orphan(sk);
-
sk_del_node_init(sk);
}
write_unlock(&local->sockets.lock);
- /*
- * If we want to keep the listening sockets alive,
- * we don't touch the RAW ones.
- */
- if (listen == true)
+ /* If we still have a device, we keep the RAW sockets alive */
+ if (device == true)
return;
write_lock(&local->raw_sockets.lock);
@@ -164,8 +150,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
bh_unlock_sock(sk);
- sock_orphan(sk);
-
sk_del_node_init(sk);
}
@@ -179,15 +163,18 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
return local;
}
-static void local_cleanup(struct nfc_llcp_local *local, bool listen)
+static void local_cleanup(struct nfc_llcp_local *local)
{
- nfc_llcp_socket_release(local, listen, ENXIO);
+ nfc_llcp_socket_release(local, false, ENXIO);
del_timer_sync(&local->link_timer);
skb_queue_purge(&local->tx_queue);
cancel_work_sync(&local->tx_work);
cancel_work_sync(&local->rx_work);
cancel_work_sync(&local->timeout_work);
kfree_skb(local->rx_pending);
+ del_timer_sync(&local->sdreq_timer);
+ cancel_work_sync(&local->sdreq_timeout_work);
+ nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs);
}
static void local_release(struct kref *ref)
@@ -197,7 +184,7 @@ static void local_release(struct kref *ref)
local = container_of(ref, struct nfc_llcp_local, ref);
list_del(&local->list);
- local_cleanup(local, false);
+ local_cleanup(local);
kfree(local);
}
@@ -265,6 +252,47 @@ static void nfc_llcp_symm_timer(unsigned long data)
schedule_work(&local->timeout_work);
}
+static void nfc_llcp_sdreq_timeout_work(struct work_struct *work)
+{
+ unsigned long time;
+ HLIST_HEAD(nl_sdres_list);
+ struct hlist_node *n;
+ struct nfc_llcp_sdp_tlv *sdp;
+ struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+ sdreq_timeout_work);
+
+ mutex_lock(&local->sdreq_lock);
+
+ time = jiffies - msecs_to_jiffies(3 * local->remote_lto);
+
+ hlist_for_each_entry_safe(sdp, n, &local->pending_sdreqs, node) {
+ if (time_after(sdp->time, time))
+ continue;
+
+ sdp->sap = LLCP_SDP_UNBOUND;
+
+ hlist_del(&sdp->node);
+
+ hlist_add_head(&sdp->node, &nl_sdres_list);
+ }
+
+ if (!hlist_empty(&local->pending_sdreqs))
+ mod_timer(&local->sdreq_timer,
+ jiffies + msecs_to_jiffies(3 * local->remote_lto));
+
+ mutex_unlock(&local->sdreq_lock);
+
+ if (!hlist_empty(&nl_sdres_list))
+ nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
+}
+
+static void nfc_llcp_sdreq_timer(unsigned long data)
+{
+ struct nfc_llcp_local *local = (struct nfc_llcp_local *) data;
+
+ schedule_work(&local->sdreq_timeout_work);
+}
+
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
{
struct nfc_llcp_local *local, *n;
@@ -808,8 +836,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
ui_cb->dsap = dsap;
ui_cb->ssap = ssap;
- printk("%s %d %d\n", __func__, dsap, ssap);
-
pr_debug("%d %d\n", dsap, ssap);
/* We're looking for a bound socket, not a client one */
@@ -827,7 +853,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
skb_get(skb);
} else {
pr_err("Receive queue is full\n");
- kfree_skb(skb);
}
nfc_llcp_sock_put(llcp_sock);
@@ -907,7 +932,9 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
new_sock = nfc_llcp_sock(new_sk);
new_sock->dev = local->dev;
new_sock->local = nfc_llcp_local_get(local);
- new_sock->miu = local->remote_miu;
+ new_sock->rw = sock->rw;
+ new_sock->miux = sock->miux;
+ new_sock->remote_miu = local->remote_miu;
new_sock->nfc_protocol = sock->nfc_protocol;
new_sock->dsap = ssap;
new_sock->target_idx = local->target_idx;
@@ -961,11 +988,11 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
pr_debug("Remote ready %d tx queue len %d remote rw %d",
sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
- sock->rw);
+ sock->remote_rw);
/* Try to queue some I frames for transmission */
while (sock->remote_ready &&
- skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
+ skb_queue_len(&sock->tx_pending_queue) < sock->remote_rw) {
struct sk_buff *pdu;
pdu = skb_dequeue(&sock->tx_queue);
@@ -1028,7 +1055,6 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
skb_get(skb);
} else {
pr_err("Receive queue is full\n");
- kfree_skb(skb);
}
}
@@ -1080,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
+ if ((dsap == 0) && (ssap == 0)) {
+ pr_debug("Connection termination");
+ nfc_dep_link_down(local->dev);
+ return;
+ }
+
llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
if (llcp_sock == NULL) {
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -1186,6 +1218,10 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
u16 tlv_len, offset;
char *service_name;
size_t service_name_len;
+ struct nfc_llcp_sdp_tlv *sdp;
+ HLIST_HEAD(llc_sdres_list);
+ size_t sdres_tlvs_len;
+ HLIST_HEAD(nl_sdres_list);
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
@@ -1200,6 +1236,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
tlv = &skb->data[LLCP_HEADER_SIZE];
tlv_len = skb->len - LLCP_HEADER_SIZE;
offset = 0;
+ sdres_tlvs_len = 0;
while (offset < tlv_len) {
type = tlv[0];
@@ -1217,14 +1254,14 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
!strncmp(service_name, "urn:nfc:sn:sdp",
service_name_len)) {
sap = 1;
- goto send_snl;
+ goto add_snl;
}
llcp_sock = nfc_llcp_sock_from_sn(local, service_name,
service_name_len);
if (!llcp_sock) {
sap = 0;
- goto send_snl;
+ goto add_snl;
}
/*
@@ -1241,7 +1278,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
if (sap == LLCP_SAP_MAX) {
sap = 0;
- goto send_snl;
+ goto add_snl;
}
client_count =
@@ -1258,8 +1295,37 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local,
pr_debug("%p %d\n", llcp_sock, sap);
-send_snl:
- nfc_llcp_send_snl(local, tid, sap);
+add_snl:
+ sdp = nfc_llcp_build_sdres_tlv(tid, sap);
+ if (sdp == NULL)
+ goto exit;
+
+ sdres_tlvs_len += sdp->tlv_len;
+ hlist_add_head(&sdp->node, &llc_sdres_list);
+ break;
+
+ case LLCP_TLV_SDRES:
+ mutex_lock(&local->sdreq_lock);
+
+ pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]);
+
+ hlist_for_each_entry(sdp, &local->pending_sdreqs, node) {
+ if (sdp->tid != tlv[2])
+ continue;
+
+ sdp->sap = tlv[3];
+
+ pr_debug("Found: uri=%s, sap=%d\n",
+ sdp->uri, sdp->sap);
+
+ hlist_del(&sdp->node);
+
+ hlist_add_head(&sdp->node, &nl_sdres_list);
+
+ break;
+ }
+
+ mutex_unlock(&local->sdreq_lock);
break;
default:
@@ -1270,21 +1336,63 @@ send_snl:
offset += length + 2;
tlv += length + 2;
}
+
+exit:
+ if (!hlist_empty(&nl_sdres_list))
+ nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list);
+
+ if (!hlist_empty(&llc_sdres_list))
+ nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
}
-static void nfc_llcp_rx_work(struct work_struct *work)
+static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
{
- struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
- rx_work);
- u8 dsap, ssap, ptype;
- struct sk_buff *skb;
+ u8 ptype;
+ u16 pdu_len;
+ struct sk_buff *new_skb;
- skb = local->rx_pending;
- if (skb == NULL) {
- pr_debug("No pending SKB\n");
+ if (skb->len <= LLCP_HEADER_SIZE) {
+ pr_err("Malformed AGF PDU\n");
return;
}
+ skb_pull(skb, LLCP_HEADER_SIZE);
+
+ while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
+ pdu_len = skb->data[0] << 8 | skb->data[1];
+
+ skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
+
+ if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
+ pr_err("Malformed AGF PDU\n");
+ return;
+ }
+
+ ptype = nfc_llcp_ptype(skb);
+
+ if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
+ goto next;
+
+ new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
+ if (new_skb == NULL) {
+ pr_err("Could not allocate PDU\n");
+ return;
+ }
+
+ memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
+
+ nfc_llcp_rx_skb(local, new_skb);
+
+ kfree_skb(new_skb);
+next:
+ skb_pull(skb, pdu_len);
+ }
+}
+
+static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
+{
+ u8 dsap, ssap, ptype;
+
ptype = nfc_llcp_ptype(skb);
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
@@ -1295,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
16, 1, skb->data, skb->len, true);
- __net_timestamp(skb);
-
- nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
-
switch (ptype) {
case LLCP_PDU_SYMM:
pr_debug("SYMM\n");
@@ -1341,8 +1445,31 @@ static void nfc_llcp_rx_work(struct work_struct *work)
nfc_llcp_recv_hdlc(local, skb);
break;
+ case LLCP_PDU_AGF:
+ pr_debug("AGF frame\n");
+ nfc_llcp_recv_agf(local, skb);
+ break;
+ }
+}
+
+static void nfc_llcp_rx_work(struct work_struct *work)
+{
+ struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+ rx_work);
+ struct sk_buff *skb;
+
+ skb = local->rx_pending;
+ if (skb == NULL) {
+ pr_debug("No pending SKB\n");
+ return;
}
+ __net_timestamp(skb);
+
+ nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
+
+ nfc_llcp_rx_skb(local, skb);
+
schedule_work(&local->tx_work);
kfree_skb(local->rx_pending);
local->rx_pending = NULL;
@@ -1389,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
if (local == NULL)
return;
+ local->remote_miu = LLCP_DEFAULT_MIU;
+ local->remote_lto = LLCP_DEFAULT_LTO;
+
/* Close and purge all existing sockets */
nfc_llcp_socket_release(local, true, 0);
}
@@ -1455,6 +1585,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
+ mutex_init(&local->sdreq_lock);
+ INIT_HLIST_HEAD(&local->pending_sdreqs);
+ init_timer(&local->sdreq_timer);
+ local->sdreq_timer.data = (unsigned long) local;
+ local->sdreq_timer.function = nfc_llcp_sdreq_timer;
+ INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work);
+
list_add(&local->list, &llcp_devices);
return 0;
@@ -1469,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
return;
}
- local_cleanup(local, false);
+ local_cleanup(local);
nfc_llcp_local_put(local);
}
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp_sock.c
index 5c7cdf3f2a83..380253eccb74 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp_sock.c
@@ -24,7 +24,7 @@
#include <linux/module.h>
#include <linux/nfc.h>
-#include "../nfc.h"
+#include "nfc.h"
#include "llcp.h"
static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
@@ -223,6 +223,156 @@ error:
return ret;
}
+static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
+ char __user *optval, unsigned int optlen)
+{
+ struct sock *sk = sock->sk;
+ struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+ u32 opt;
+ int err = 0;
+
+ pr_debug("%p optname %d\n", sk, optname);
+
+ if (level != SOL_NFC)
+ return -ENOPROTOOPT;
+
+ lock_sock(sk);
+
+ switch (optname) {
+ case NFC_LLCP_RW:
+ if (sk->sk_state == LLCP_CONNECTED ||
+ sk->sk_state == LLCP_BOUND ||
+ sk->sk_state == LLCP_LISTEN) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (opt > LLCP_MAX_RW) {
+ err = -EINVAL;
+ break;
+ }
+
+ llcp_sock->rw = (u8) opt;
+
+ break;
+
+ case NFC_LLCP_MIUX:
+ if (sk->sk_state == LLCP_CONNECTED ||
+ sk->sk_state == LLCP_BOUND ||
+ sk->sk_state == LLCP_LISTEN) {
+ err = -EINVAL;
+ break;
+ }
+
+ if (get_user(opt, (u32 __user *) optval)) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (opt > LLCP_MAX_MIUX) {
+ err = -EINVAL;
+ break;
+ }
+
+ llcp_sock->miux = cpu_to_be16((u16) opt);
+
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ release_sock(sk);
+
+ pr_debug("%p rw %d miux %d\n", llcp_sock,
+ llcp_sock->rw, llcp_sock->miux);
+
+ return err;
+}
+
+static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ struct nfc_llcp_local *local;
+ struct sock *sk = sock->sk;
+ struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+ int len, err = 0;
+ u16 miux, remote_miu;
+ u8 rw;
+
+ pr_debug("%p optname %d\n", sk, optname);
+
+ if (level != SOL_NFC)
+ return -ENOPROTOOPT;
+
+ if (get_user(len, optlen))
+ return -EFAULT;
+
+ local = llcp_sock->local;
+ if (!local)
+ return -ENODEV;
+
+ len = min_t(u32, len, sizeof(u32));
+
+ lock_sock(sk);
+
+ switch (optname) {
+ case NFC_LLCP_RW:
+ rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
+ if (put_user(rw, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ case NFC_LLCP_MIUX:
+ miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
+ be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
+
+ if (put_user(miux, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ case NFC_LLCP_REMOTE_MIU:
+ remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
+ local->remote_miu : llcp_sock->remote_miu;
+
+ if (put_user(remote_miu, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ case NFC_LLCP_REMOTE_LTO:
+ if (put_user(local->remote_lto / 10, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ case NFC_LLCP_REMOTE_RW:
+ if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
+ err = -EFAULT;
+
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ release_sock(sk);
+
+ if (put_user(len, optlen))
+ return -EFAULT;
+
+ return err;
+}
+
void nfc_llcp_accept_unlink(struct sock *sk)
{
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -270,7 +420,9 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
}
if (sk->sk_state == LLCP_CONNECTED || !newsock) {
- nfc_llcp_accept_unlink(sk);
+ list_del_init(&lsk->accept_queue);
+ sock_put(sk);
+
if (newsock)
sock_graft(sk, newsock);
@@ -356,12 +508,13 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr,
pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx,
llcp_sock->dsap, llcp_sock->ssap);
- uaddr->sa_family = AF_NFC;
-
+ memset(llcp_addr, 0, sizeof(*llcp_addr));
*len = sizeof(struct sockaddr_nfc_llcp);
+ llcp_addr->sa_family = AF_NFC;
llcp_addr->dev_idx = llcp_sock->dev->idx;
llcp_addr->target_idx = llcp_sock->target_idx;
+ llcp_addr->nfc_protocol = llcp_sock->nfc_protocol;
llcp_addr->dsap = llcp_sock->dsap;
llcp_addr->ssap = llcp_sock->ssap;
llcp_addr->service_name_len = llcp_sock->service_name_len;
@@ -403,7 +556,8 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
return llcp_accept_poll(sk);
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
if (!skb_queue_empty(&sk->sk_receive_queue))
mask |= POLLIN | POLLRDNORM;
@@ -464,8 +618,6 @@ static int llcp_sock_release(struct socket *sock)
nfc_llcp_accept_unlink(accept_sk);
release_sock(accept_sk);
-
- sock_orphan(accept_sk);
}
}
@@ -543,7 +695,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
llcp_sock->dev = dev;
llcp_sock->local = nfc_llcp_local_get(local);
- llcp_sock->miu = llcp_sock->local->remote_miu;
+ llcp_sock->remote_miu = llcp_sock->local->remote_miu;
llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
if (llcp_sock->ssap == LLCP_SAP_MAX) {
ret = -ENOMEM;
@@ -646,6 +798,8 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
pr_debug("%p %zu\n", sk, len);
+ msg->msg_namelen = 0;
+
lock_sock(sk);
if (sk->sk_state == LLCP_CLOSED &&
@@ -691,6 +845,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
pr_debug("Datagram socket %d %d\n", ui_cb->dsap, ui_cb->ssap);
+ memset(sockaddr, 0, sizeof(*sockaddr));
sockaddr->sa_family = AF_NFC;
sockaddr->nfc_protocol = NFC_PROTO_NFC_DEP;
sockaddr->dsap = ui_cb->dsap;
@@ -737,8 +892,8 @@ static const struct proto_ops llcp_sock_ops = {
.ioctl = sock_no_ioctl,
.listen = llcp_sock_listen,
.shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
+ .setsockopt = nfc_llcp_setsockopt,
+ .getsockopt = nfc_llcp_getsockopt,
.sendmsg = llcp_sock_sendmsg,
.recvmsg = llcp_sock_recvmsg,
.mmap = sock_no_mmap,
@@ -802,12 +957,13 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
llcp_sock->ssap = 0;
llcp_sock->dsap = LLCP_SAP_SDP;
- llcp_sock->rw = LLCP_DEFAULT_RW;
- llcp_sock->miu = LLCP_DEFAULT_MIU;
+ llcp_sock->rw = LLCP_MAX_RW + 1;
+ llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
llcp_sock->send_n = llcp_sock->send_ack_n = 0;
llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
llcp_sock->remote_ready = 1;
llcp_sock->reserved_ssap = LLCP_SAP_MAX;
+ nfc_llcp_socket_remote_param_init(llcp_sock);
skb_queue_head_init(&llcp_sock->tx_queue);
skb_queue_head_init(&llcp_sock->tx_pending_queue);
INIT_LIST_HEAD(&llcp_sock->accept_queue);
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 504b883439f1..f0c4d61f37c0 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -28,8 +28,7 @@
#include <linux/slab.h>
#include "nfc.h"
-
-#include "llcp/llcp.h"
+#include "llcp.h"
static struct genl_multicast_group nfc_genl_event_mcgrp = {
.name = NFC_GENL_MCAST_EVENT_NAME,
@@ -53,6 +52,15 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
[NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
[NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
[NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
+ [NFC_ATTR_LLC_PARAM_LTO] = { .type = NLA_U8 },
+ [NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },
+ [NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },
+ [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
+ [NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
+ [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
};
static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -348,6 +356,74 @@ free_msg:
return -EMSGSIZE;
}
+int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
+{
+ struct sk_buff *msg;
+ struct nlattr *sdp_attr, *uri_attr;
+ struct nfc_llcp_sdp_tlv *sdres;
+ struct hlist_node *n;
+ void *hdr;
+ int rc = -EMSGSIZE;
+ int i;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+ NFC_EVENT_LLC_SDRES);
+ if (!hdr)
+ goto free_msg;
+
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
+
+ sdp_attr = nla_nest_start(msg, NFC_ATTR_LLC_SDP);
+ if (sdp_attr == NULL) {
+ rc = -ENOMEM;
+ goto nla_put_failure;
+ }
+
+ i = 1;
+ hlist_for_each_entry_safe(sdres, n, sdres_list, node) {
+ pr_debug("uri: %s, sap: %d\n", sdres->uri, sdres->sap);
+
+ uri_attr = nla_nest_start(msg, i++);
+ if (uri_attr == NULL) {
+ rc = -ENOMEM;
+ goto nla_put_failure;
+ }
+
+ if (nla_put_u8(msg, NFC_SDP_ATTR_SAP, sdres->sap))
+ goto nla_put_failure;
+
+ if (nla_put_string(msg, NFC_SDP_ATTR_URI, sdres->uri))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, uri_attr);
+
+ hlist_del(&sdres->node);
+
+ nfc_llcp_free_sdp_tlv(sdres);
+ }
+
+ nla_nest_end(msg, sdp_attr);
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+
+free_msg:
+ nlmsg_free(msg);
+
+ nfc_llcp_free_sdp_tlv_list(sdres_list);
+
+ return rc;
+}
+
static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
u32 portid, u32 seq,
struct netlink_callback *cb,
@@ -859,6 +935,96 @@ exit:
return rc;
}
+static int nfc_genl_llc_sdreq(struct sk_buff *skb, struct genl_info *info)
+{
+ struct nfc_dev *dev;
+ struct nfc_llcp_local *local;
+ struct nlattr *attr, *sdp_attrs[NFC_SDP_ATTR_MAX+1];
+ u32 idx;
+ u8 tid;
+ char *uri;
+ int rc = 0, rem;
+ size_t uri_len, tlvs_len;
+ struct hlist_head sdreq_list;
+ struct nfc_llcp_sdp_tlv *sdreq;
+
+ if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+ !info->attrs[NFC_ATTR_LLC_SDP])
+ return -EINVAL;
+
+ idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+ dev = nfc_get_device(idx);
+ if (!dev) {
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ device_lock(&dev->dev);
+
+ if (dev->dep_link_up == false) {
+ rc = -ENOLINK;
+ goto exit;
+ }
+
+ local = nfc_llcp_find_local(dev);
+ if (!local) {
+ nfc_put_device(dev);
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ INIT_HLIST_HEAD(&sdreq_list);
+
+ tlvs_len = 0;
+
+ nla_for_each_nested(attr, info->attrs[NFC_ATTR_LLC_SDP], rem) {
+ rc = nla_parse_nested(sdp_attrs, NFC_SDP_ATTR_MAX, attr,
+ nfc_sdp_genl_policy);
+
+ if (rc != 0) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (!sdp_attrs[NFC_SDP_ATTR_URI])
+ continue;
+
+ uri_len = nla_len(sdp_attrs[NFC_SDP_ATTR_URI]);
+ if (uri_len == 0)
+ continue;
+
+ uri = nla_data(sdp_attrs[NFC_SDP_ATTR_URI]);
+ if (uri == NULL || *uri == 0)
+ continue;
+
+ tid = local->sdreq_next_tid++;
+
+ sdreq = nfc_llcp_build_sdreq_tlv(tid, uri, uri_len);
+ if (sdreq == NULL) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ tlvs_len += sdreq->tlv_len;
+
+ hlist_add_head(&sdreq->node, &sdreq_list);
+ }
+
+ if (hlist_empty(&sdreq_list)) {
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ rc = nfc_llcp_send_snl_sdreq(local, &sdreq_list, tlvs_len);
+exit:
+ device_unlock(&dev->dev);
+
+ nfc_put_device(dev);
+
+ return rc;
+}
+
static struct genl_ops nfc_genl_ops[] = {
{
.cmd = NFC_CMD_GET_DEVICE,
@@ -913,6 +1079,11 @@ static struct genl_ops nfc_genl_ops[] = {
.doit = nfc_genl_llc_set_params,
.policy = nfc_genl_policy,
},
+ {
+ .cmd = NFC_CMD_LLC_SDREQ,
+ .doit = nfc_genl_llc_sdreq,
+ .policy = nfc_genl_policy,
+ },
};
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 87d914d2876a..afa1f84ba040 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -46,7 +46,7 @@ struct nfc_rawsock {
#define to_rawsock_sk(_tx_work) \
((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work))
-#ifdef CONFIG_NFC_LLCP
+struct nfc_llcp_sdp_tlv;
void nfc_llcp_mac_is_down(struct nfc_dev *dev);
void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
@@ -59,60 +59,8 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
int __init nfc_llcp_init(void);
void nfc_llcp_exit(void);
-
-#else
-
-static inline void nfc_llcp_mac_is_down(struct nfc_dev *dev)
-{
-}
-
-static inline void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
- u8 comm_mode, u8 rf_mode)
-{
-}
-
-static inline int nfc_llcp_register_device(struct nfc_dev *dev)
-{
- return 0;
-}
-
-static inline void nfc_llcp_unregister_device(struct nfc_dev *dev)
-{
-}
-
-static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev,
- u8 *gb, u8 gb_len)
-{
- return 0;
-}
-
-static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
-{
- *gb_len = 0;
- return NULL;
-}
-
-static inline int nfc_llcp_data_received(struct nfc_dev *dev,
- struct sk_buff *skb)
-{
- return 0;
-}
-
-static inline struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev)
-{
- return NULL;
-}
-
-static inline int nfc_llcp_init(void)
-{
- return 0;
-}
-
-static inline void nfc_llcp_exit(void)
-{
-}
-
-#endif
+void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
+void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head);
int __init rawsock_init(void);
void rawsock_exit(void);
@@ -144,6 +92,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
int nfc_genl_tm_deactivated(struct nfc_dev *dev);
+int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list);
+
struct nfc_dev *nfc_get_device(unsigned int idx);
static inline void nfc_put_device(struct nfc_dev *dev)
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index d4d5363c7ba7..894b6cbdd929 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -98,7 +98,7 @@ static int pop_vlan(struct sk_buff *skb)
if (unlikely(err))
return err;
- __vlan_hwaccel_put_tag(skb, ntohs(tci));
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci));
return 0;
}
@@ -110,7 +110,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
/* push down current VLAN tag */
current_tag = vlan_tx_tag_get(skb);
- if (!__vlan_put_tag(skb, current_tag))
+ if (!__vlan_put_tag(skb, skb->vlan_proto, current_tag))
return -ENOMEM;
if (skb->ip_summed == CHECKSUM_COMPLETE)
@@ -118,7 +118,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
+ (2 * ETH_ALEN), VLAN_HLEN, 0));
}
- __vlan_hwaccel_put_tag(skb, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
+ __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
return 0;
}
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index a4b724708a1a..d12d6b8b5e8b 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -44,6 +44,7 @@
#include <linux/netfilter_ipv4.h>
#include <linux/inetdevice.h>
#include <linux/list.h>
+#include <linux/lockdep.h>
#include <linux/openvswitch.h>
#include <linux/rculist.h>
#include <linux/dmi.h>
@@ -55,39 +56,61 @@
#include "datapath.h"
#include "flow.h"
#include "vport-internal_dev.h"
+#include "vport-netdev.h"
-/**
- * struct ovs_net - Per net-namespace data for ovs.
- * @dps: List of datapaths to enable dumping them all out.
- * Protected by genl_mutex.
- */
-struct ovs_net {
- struct list_head dps;
-};
-
-static int ovs_net_id __read_mostly;
#define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
static void rehash_flow_table(struct work_struct *work);
static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table);
+int ovs_net_id __read_mostly;
+
+static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
+ struct genl_multicast_group *grp)
+{
+ genl_notify(skb, genl_info_net(info), info->snd_portid,
+ grp->id, info->nlhdr, GFP_KERNEL);
+}
+
/**
* DOC: Locking:
*
- * Writes to device state (add/remove datapath, port, set operations on vports,
- * etc.) are protected by RTNL.
- *
- * Writes to other state (flow table modifications, set miscellaneous datapath
- * parameters, etc.) are protected by genl_mutex. The RTNL lock nests inside
- * genl_mutex.
+ * All writes e.g. Writes to device state (add/remove datapath, port, set
+ * operations on vports, etc.), Writes to other state (flow table
+ * modifications, set miscellaneous datapath parameters, etc.) are protected
+ * by ovs_lock.
*
* Reads are protected by RCU.
*
* There are a few special cases (mostly stats) that have their own
* synchronization but they nest under all of above and don't interact with
* each other.
+ *
+ * The RTNL lock nests inside ovs_mutex.
*/
+static DEFINE_MUTEX(ovs_mutex);
+
+void ovs_lock(void)
+{
+ mutex_lock(&ovs_mutex);
+}
+
+void ovs_unlock(void)
+{
+ mutex_unlock(&ovs_mutex);
+}
+
+#ifdef CONFIG_LOCKDEP
+int lockdep_ovsl_is_held(void)
+{
+ if (debug_locks)
+ return lockdep_is_held(&ovs_mutex);
+ else
+ return 1;
+}
+#endif
+
static struct vport *new_vport(const struct vport_parms *);
static int queue_gso_packets(struct net *, int dp_ifindex, struct sk_buff *,
const struct dp_upcall_info *);
@@ -95,7 +118,7 @@ static int queue_userspace_packet(struct net *, int dp_ifindex,
struct sk_buff *,
const struct dp_upcall_info *);
-/* Must be called with rcu_read_lock, genl_mutex, or RTNL lock. */
+/* Must be called with rcu_read_lock or ovs_mutex. */
static struct datapath *get_dp(struct net *net, int dp_ifindex)
{
struct datapath *dp = NULL;
@@ -113,10 +136,10 @@ static struct datapath *get_dp(struct net *net, int dp_ifindex)
return dp;
}
-/* Must be called with rcu_read_lock or RTNL lock. */
+/* Must be called with rcu_read_lock or ovs_mutex. */
const char *ovs_dp_name(const struct datapath *dp)
{
- struct vport *vport = ovs_vport_rtnl_rcu(dp, OVSP_LOCAL);
+ struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
return vport->ops->get_name(vport);
}
@@ -129,7 +152,7 @@ static int get_dpifindex(struct datapath *dp)
local = ovs_vport_rcu(dp, OVSP_LOCAL);
if (local)
- ifindex = local->ops->get_ifindex(local);
+ ifindex = netdev_vport_priv(local)->dev->ifindex;
else
ifindex = 0;
@@ -168,7 +191,7 @@ struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
return NULL;
}
-/* Called with RTNL lock and genl_lock. */
+/* Called with ovs_mutex. */
static struct vport *new_vport(const struct vport_parms *parms)
{
struct vport *vport;
@@ -180,14 +203,12 @@ static struct vport *new_vport(const struct vport_parms *parms)
hlist_add_head_rcu(&vport->dp_hash_node, head);
}
-
return vport;
}
-/* Called with RTNL lock. */
void ovs_dp_detach_port(struct vport *p)
{
- ASSERT_RTNL();
+ ASSERT_OVSL();
/* First drop references to device. */
hlist_del_rcu(&p->dp_hash_node);
@@ -250,7 +271,8 @@ static struct genl_family dp_packet_genl_family = {
.name = OVS_PACKET_FAMILY,
.version = OVS_PACKET_VERSION,
.maxattr = OVS_PACKET_ATTR_MAX,
- .netnsok = true
+ .netnsok = true,
+ .parallel_ops = true,
};
int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
@@ -337,6 +359,35 @@ static int queue_gso_packets(struct net *net, int dp_ifindex,
return err;
}
+static size_t key_attr_size(void)
+{
+ return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
+ + nla_total_size(4) /* OVS_KEY_ATTR_IN_PORT */
+ + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
+ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ + nla_total_size(4) /* OVS_KEY_ATTR_8021Q */
+ + nla_total_size(0) /* OVS_KEY_ATTR_ENCAP */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ + nla_total_size(40) /* OVS_KEY_ATTR_IPV6 */
+ + nla_total_size(2) /* OVS_KEY_ATTR_ICMPV6 */
+ + nla_total_size(28); /* OVS_KEY_ATTR_ND */
+}
+
+static size_t upcall_msg_size(const struct sk_buff *skb,
+ const struct nlattr *userdata)
+{
+ size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+ + nla_total_size(skb->len) /* OVS_PACKET_ATTR_PACKET */
+ + nla_total_size(key_attr_size()); /* OVS_PACKET_ATTR_KEY */
+
+ /* OVS_PACKET_ATTR_USERDATA */
+ if (userdata)
+ size += NLA_ALIGN(userdata->nla_len);
+
+ return size;
+}
+
static int queue_userspace_packet(struct net *net, int dp_ifindex,
struct sk_buff *skb,
const struct dp_upcall_info *upcall_info)
@@ -345,7 +396,6 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
struct sk_buff *nskb = NULL;
struct sk_buff *user_skb; /* to be queued to userspace */
struct nlattr *nla;
- unsigned int len;
int err;
if (vlan_tx_tag_present(skb)) {
@@ -353,7 +403,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
if (!nskb)
return -ENOMEM;
- nskb = __vlan_put_tag(nskb, vlan_tx_tag_get(nskb));
+ nskb = __vlan_put_tag(nskb, nskb->vlan_proto, vlan_tx_tag_get(nskb));
if (!nskb)
return -ENOMEM;
@@ -366,13 +416,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
goto out;
}
- len = sizeof(struct ovs_header);
- len += nla_total_size(skb->len);
- len += nla_total_size(FLOW_BUFSIZE);
- if (upcall_info->cmd == OVS_PACKET_CMD_ACTION)
- len += nla_total_size(8);
-
- user_skb = genlmsg_new(len, GFP_ATOMIC);
+ user_skb = genlmsg_new(upcall_msg_size(skb, upcall_info->userdata), GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
goto out;
@@ -387,8 +431,9 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
nla_nest_end(user_skb, nla);
if (upcall_info->userdata)
- nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA,
- nla_get_u64(upcall_info->userdata));
+ __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
+ nla_len(upcall_info->userdata),
+ nla_data(upcall_info->userdata));
nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len);
@@ -402,13 +447,13 @@ out:
return err;
}
-/* Called with genl_mutex. */
+/* Called with ovs_mutex. */
static int flush_flows(struct datapath *dp)
{
struct flow_table *old_table;
struct flow_table *new_table;
- old_table = genl_dereference(dp->table);
+ old_table = ovsl_dereference(dp->table);
new_table = ovs_flow_tbl_alloc(TBL_MIN_BUCKETS);
if (!new_table)
return -ENOMEM;
@@ -544,7 +589,7 @@ static int validate_userspace(const struct nlattr *attr)
{
static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] = {
[OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
- [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_U64 },
+ [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
};
struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
int error;
@@ -661,8 +706,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
- !a[OVS_PACKET_ATTR_ACTIONS] ||
- nla_len(a[OVS_PACKET_ATTR_PACKET]) < ETH_HLEN)
+ !a[OVS_PACKET_ATTR_ACTIONS])
goto err;
len = nla_len(a[OVS_PACKET_ATTR_PACKET]);
@@ -672,7 +716,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
goto err;
skb_reserve(packet, NET_IP_ALIGN);
- memcpy(__skb_put(packet, len), nla_data(a[OVS_PACKET_ATTR_PACKET]), len);
+ nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
skb_reset_mac_header(packet);
eth = eth_hdr(packet);
@@ -680,7 +724,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
/* Normally, setting the skb 'protocol' field would be handled by a
* call to eth_type_trans(), but it assumes there's a sending
* device, which we may not have. */
- if (ntohs(eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
packet->protocol = eth->h_proto;
else
packet->protocol = htons(ETH_P_802_2);
@@ -743,7 +787,7 @@ err:
}
static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
- [OVS_PACKET_ATTR_PACKET] = { .type = NLA_UNSPEC },
+ [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
[OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
[OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
};
@@ -759,7 +803,7 @@ static struct genl_ops dp_packet_genl_ops[] = {
static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats)
{
int i;
- struct flow_table *table = genl_dereference(dp->table);
+ struct flow_table *table = ovsl_dereference(dp->table);
stats->n_flows = ovs_flow_tbl_count(table);
@@ -794,14 +838,25 @@ static struct genl_family dp_flow_genl_family = {
.name = OVS_FLOW_FAMILY,
.version = OVS_FLOW_VERSION,
.maxattr = OVS_FLOW_ATTR_MAX,
- .netnsok = true
+ .netnsok = true,
+ .parallel_ops = true,
};
static struct genl_multicast_group ovs_dp_flow_multicast_group = {
.name = OVS_FLOW_MCGROUP
};
-/* Called with genl_lock. */
+static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
+{
+ return NLMSG_ALIGN(sizeof(struct ovs_header))
+ + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */
+ + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
+ + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
+ + nla_total_size(8) /* OVS_FLOW_ATTR_USED */
+ + nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
+}
+
+/* Called with ovs_mutex. */
static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
struct sk_buff *skb, u32 portid,
u32 seq, u32 flags, u8 cmd)
@@ -815,8 +870,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
u8 tcp_flags;
int err;
- sf_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
+ sf_acts = ovsl_dereference(flow->sf_acts);
ovs_header = genlmsg_put(skb, portid, seq, &dp_flow_genl_family, flags, cmd);
if (!ovs_header)
@@ -879,25 +933,10 @@ error:
static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow)
{
const struct sw_flow_actions *sf_acts;
- int len;
-
- sf_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
-
- /* OVS_FLOW_ATTR_KEY */
- len = nla_total_size(FLOW_BUFSIZE);
- /* OVS_FLOW_ATTR_ACTIONS */
- len += nla_total_size(sf_acts->actions_len);
- /* OVS_FLOW_ATTR_STATS */
- len += nla_total_size(sizeof(struct ovs_flow_stats));
- /* OVS_FLOW_ATTR_TCP_FLAGS */
- len += nla_total_size(1);
- /* OVS_FLOW_ATTR_USED */
- len += nla_total_size(8);
- len += NLMSG_ALIGN(sizeof(struct ovs_header));
+ sf_acts = ovsl_dereference(flow->sf_acts);
- return genlmsg_new(len, GFP_KERNEL);
+ return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
}
static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
@@ -946,12 +985,13 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
goto error;
}
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
error = -ENODEV;
if (!dp)
- goto error;
+ goto err_unlock_ovs;
- table = genl_dereference(dp->table);
+ table = ovsl_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
if (!flow) {
struct sw_flow_actions *acts;
@@ -959,7 +999,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
/* Bail out if we're not allowed to create a new flow. */
error = -ENOENT;
if (info->genlhdr->cmd == OVS_FLOW_CMD_SET)
- goto error;
+ goto err_unlock_ovs;
/* Expand table, if necessary, to make room. */
if (ovs_flow_tbl_need_to_expand(table)) {
@@ -969,7 +1009,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
if (!IS_ERR(new_table)) {
rcu_assign_pointer(dp->table, new_table);
ovs_flow_tbl_deferred_destroy(table);
- table = genl_dereference(dp->table);
+ table = ovsl_dereference(dp->table);
}
}
@@ -977,7 +1017,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
flow = ovs_flow_alloc();
if (IS_ERR(flow)) {
error = PTR_ERR(flow);
- goto error;
+ goto err_unlock_ovs;
}
flow->key = key;
clear_stats(flow);
@@ -1010,11 +1050,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
error = -EEXIST;
if (info->genlhdr->cmd == OVS_FLOW_CMD_NEW &&
info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL))
- goto error;
+ goto err_unlock_ovs;
/* Update actions. */
- old_acts = rcu_dereference_protected(flow->sf_acts,
- lockdep_genl_is_held());
+ old_acts = ovsl_dereference(flow->sf_acts);
acts_attrs = a[OVS_FLOW_ATTR_ACTIONS];
if (acts_attrs &&
(old_acts->actions_len != nla_len(acts_attrs) ||
@@ -1025,7 +1064,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
new_acts = ovs_flow_actions_alloc(acts_attrs);
error = PTR_ERR(new_acts);
if (IS_ERR(new_acts))
- goto error;
+ goto err_unlock_ovs;
rcu_assign_pointer(flow->sf_acts, new_acts);
ovs_flow_deferred_free_acts(old_acts);
@@ -1041,11 +1080,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
spin_unlock_bh(&flow->lock);
}
}
+ ovs_unlock();
if (!IS_ERR(reply))
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_flow_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
else
netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
@@ -1053,6 +1091,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
error_free_flow:
ovs_flow_free(flow);
+err_unlock_ovs:
+ ovs_unlock();
error:
return error;
}
@@ -1075,21 +1115,32 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
if (err)
return err;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
- return -ENODEV;
+ if (!dp) {
+ err = -ENODEV;
+ goto unlock;
+ }
- table = genl_dereference(dp->table);
+ table = ovsl_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
- if (!flow)
- return -ENOENT;
+ if (!flow) {
+ err = -ENOENT;
+ goto unlock;
+ }
reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
info->snd_seq, OVS_FLOW_CMD_NEW);
- if (IS_ERR(reply))
- return PTR_ERR(reply);
+ if (IS_ERR(reply)) {
+ err = PTR_ERR(reply);
+ goto unlock;
+ }
+ ovs_unlock();
return genlmsg_reply(reply, info);
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
@@ -1104,25 +1155,33 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
int err;
int key_len;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
- return -ENODEV;
-
- if (!a[OVS_FLOW_ATTR_KEY])
- return flush_flows(dp);
+ if (!dp) {
+ err = -ENODEV;
+ goto unlock;
+ }
+ if (!a[OVS_FLOW_ATTR_KEY]) {
+ err = flush_flows(dp);
+ goto unlock;
+ }
err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
if (err)
- return err;
+ goto unlock;
- table = genl_dereference(dp->table);
+ table = ovsl_dereference(dp->table);
flow = ovs_flow_tbl_lookup(table, &key, key_len);
- if (!flow)
- return -ENOENT;
+ if (!flow) {
+ err = -ENOENT;
+ goto unlock;
+ }
reply = ovs_flow_cmd_alloc_info(flow);
- if (!reply)
- return -ENOMEM;
+ if (!reply) {
+ err = -ENOMEM;
+ goto unlock;
+ }
ovs_flow_tbl_remove(table, flow);
@@ -1131,10 +1190,13 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
BUG_ON(err < 0);
ovs_flow_deferred_free(flow);
+ ovs_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_flow_multicast_group.id, info->nlhdr, GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@ -1143,11 +1205,14 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
struct datapath *dp;
struct flow_table *table;
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
- if (!dp)
+ if (!dp) {
+ ovs_unlock();
return -ENODEV;
+ }
- table = genl_dereference(dp->table);
+ table = ovsl_dereference(dp->table);
for (;;) {
struct sw_flow *flow;
@@ -1168,6 +1233,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[0] = bucket;
cb->args[1] = obj;
}
+ ovs_unlock();
return skb->len;
}
@@ -1206,13 +1272,24 @@ static struct genl_family dp_datapath_genl_family = {
.name = OVS_DATAPATH_FAMILY,
.version = OVS_DATAPATH_VERSION,
.maxattr = OVS_DP_ATTR_MAX,
- .netnsok = true
+ .netnsok = true,
+ .parallel_ops = true,
};
static struct genl_multicast_group ovs_dp_datapath_multicast_group = {
.name = OVS_DATAPATH_MCGROUP
};
+static size_t ovs_dp_cmd_msg_size(void)
+{
+ size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
+
+ msgsize += nla_total_size(IFNAMSIZ);
+ msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
+
+ return msgsize;
+}
+
static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd)
{
@@ -1251,7 +1328,7 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
struct sk_buff *skb;
int retval;
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ skb = genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOMEM);
@@ -1263,7 +1340,7 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
return skb;
}
-/* Called with genl_mutex and optionally with RTNL lock also. */
+/* Called with ovs_mutex. */
static struct datapath *lookup_datapath(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_DP_ATTR_MAX + 1])
@@ -1297,12 +1374,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (!a[OVS_DP_ATTR_NAME] || !a[OVS_DP_ATTR_UPCALL_PID])
goto err;
- rtnl_lock();
+ ovs_lock();
err = -ENOMEM;
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (dp == NULL)
- goto err_unlock_rtnl;
+ goto err_unlock_ovs;
ovs_dp_set_net(dp, hold_net(sock_net(skb->sk)));
@@ -1353,37 +1430,34 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
ovs_net = net_generic(ovs_dp_get_net(dp), ovs_net_id);
list_add_tail(&dp->list_node, &ovs_net->dps);
- rtnl_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_unlock();
+
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
err_destroy_local_port:
- ovs_dp_detach_port(ovs_vport_rtnl(dp, OVSP_LOCAL));
+ ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
err_destroy_ports_array:
kfree(dp->ports);
err_destroy_percpu:
free_percpu(dp->stats_percpu);
err_destroy_table:
- ovs_flow_tbl_destroy(genl_dereference(dp->table));
+ ovs_flow_tbl_destroy(ovsl_dereference(dp->table));
err_free_dp:
release_net(ovs_dp_get_net(dp));
kfree(dp);
-err_unlock_rtnl:
- rtnl_unlock();
+err_unlock_ovs:
+ ovs_unlock();
err:
return err;
}
-/* Called with genl_mutex. */
+/* Called with ovs_mutex. */
static void __dp_destroy(struct datapath *dp)
{
int i;
- rtnl_lock();
-
for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
struct vport *vport;
struct hlist_node *n;
@@ -1394,14 +1468,11 @@ static void __dp_destroy(struct datapath *dp)
}
list_del(&dp->list_node);
- ovs_dp_detach_port(ovs_vport_rtnl(dp, OVSP_LOCAL));
- /* rtnl_unlock() will wait until all the references to devices that
- * are pending unregistration have been dropped. We do it here to
- * ensure that any internal devices (which contain DP pointers) are
- * fully destroyed before freeing the datapath.
+ /* OVSP_LOCAL is datapath internal port. We need to make sure that
+ * all port in datapath are destroyed first before freeing datapath.
*/
- rtnl_unlock();
+ ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
call_rcu(&dp->rcu, destroy_dp_rcu);
}
@@ -1412,24 +1483,27 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
struct datapath *dp;
int err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
err = PTR_ERR(dp);
if (IS_ERR(dp))
- return err;
+ goto unlock;
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_DEL);
err = PTR_ERR(reply);
if (IS_ERR(reply))
- return err;
+ goto unlock;
__dp_destroy(dp);
+ ovs_unlock();
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
@@ -1438,9 +1512,11 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
struct datapath *dp;
int err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
+ err = PTR_ERR(dp);
if (IS_ERR(dp))
- return PTR_ERR(dp);
+ goto unlock;
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
@@ -1448,31 +1524,45 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
err = PTR_ERR(reply);
netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
ovs_dp_datapath_multicast_group.id, err);
- return 0;
+ err = 0;
+ goto unlock;
}
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_datapath_multicast_group.id, info->nlhdr,
- GFP_KERNEL);
+ ovs_unlock();
+ ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
return 0;
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *reply;
struct datapath *dp;
+ int err;
+ ovs_lock();
dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
- if (IS_ERR(dp))
- return PTR_ERR(dp);
+ if (IS_ERR(dp)) {
+ err = PTR_ERR(dp);
+ goto unlock;
+ }
reply = ovs_dp_cmd_build_info(dp, info->snd_portid,
info->snd_seq, OVS_DP_CMD_NEW);
- if (IS_ERR(reply))
- return PTR_ERR(reply);
+ if (IS_ERR(reply)) {
+ err = PTR_ERR(reply);
+ goto unlock;
+ }
+ ovs_unlock();
return genlmsg_reply(reply, info);
+
+unlock:
+ ovs_unlock();
+ return err;
}
static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
@@ -1482,6 +1572,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
int skip = cb->args[0];
int i = 0;
+ ovs_lock();
list_for_each_entry(dp, &ovs_net->dps, list_node) {
if (i >= skip &&
ovs_dp_cmd_fill_info(dp, skb, NETLINK_CB(cb->skb).portid,
@@ -1490,6 +1581,7 @@ static int ovs_dp_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
break;
i++;
}
+ ovs_unlock();
cb->args[0] = i;
@@ -1535,14 +1627,15 @@ static struct genl_family dp_vport_genl_family = {
.name = OVS_VPORT_FAMILY,
.version = OVS_VPORT_VERSION,
.maxattr = OVS_VPORT_ATTR_MAX,
- .netnsok = true
+ .netnsok = true,
+ .parallel_ops = true,
};
struct genl_multicast_group ovs_dp_vport_multicast_group = {
.name = OVS_VPORT_MCGROUP
};
-/* Called with RTNL lock or RCU read lock. */
+/* Called with ovs_mutex or RCU read lock. */
static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
u32 portid, u32 seq, u32 flags, u8 cmd)
{
@@ -1581,7 +1674,7 @@ error:
return err;
}
-/* Called with RTNL lock or RCU read lock. */
+/* Called with ovs_mutex or RCU read lock. */
struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
u32 seq, u8 cmd)
{
@@ -1593,14 +1686,12 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
return ERR_PTR(-ENOMEM);
retval = ovs_vport_cmd_fill_info(vport, skb, portid, seq, 0, cmd);
- if (retval < 0) {
- kfree_skb(skb);
- return ERR_PTR(retval);
- }
+ BUG_ON(retval < 0);
+
return skb;
}
-/* Called with RTNL lock or RCU read lock. */
+/* Called with ovs_mutex or RCU read lock. */
static struct vport *lookup_vport(struct net *net,
struct ovs_header *ovs_header,
struct nlattr *a[OVS_VPORT_ATTR_MAX + 1])
@@ -1626,9 +1717,9 @@ static struct vport *lookup_vport(struct net *net,
if (!dp)
return ERR_PTR(-ENODEV);
- vport = ovs_vport_rtnl_rcu(dp, port_no);
+ vport = ovs_vport_ovsl_rcu(dp, port_no);
if (!vport)
- return ERR_PTR(-ENOENT);
+ return ERR_PTR(-ENODEV);
return vport;
} else
return ERR_PTR(-EINVAL);
@@ -1650,7 +1741,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
!a[OVS_VPORT_ATTR_UPCALL_PID])
goto exit;
- rtnl_lock();
+ ovs_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
@@ -1663,7 +1754,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if (port_no >= DP_MAX_PORTS)
goto exit_unlock;
- vport = ovs_vport_rtnl_rcu(dp, port_no);
+ vport = ovs_vport_ovsl(dp, port_no);
err = -EBUSY;
if (vport)
goto exit_unlock;
@@ -1673,7 +1764,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
err = -EFBIG;
goto exit_unlock;
}
- vport = ovs_vport_rtnl(dp, port_no);
+ vport = ovs_vport_ovsl(dp, port_no);
if (!vport)
break;
}
@@ -1699,11 +1790,11 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
ovs_dp_detach_port(vport);
goto exit_unlock;
}
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+
+ ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
exit_unlock:
- rtnl_unlock();
+ ovs_unlock();
exit:
return err;
}
@@ -1715,7 +1806,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
struct vport *vport;
int err;
- rtnl_lock();
+ ovs_lock();
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
@@ -1726,26 +1817,35 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type)
err = -EINVAL;
+ reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!reply) {
+ err = -ENOMEM;
+ goto exit_unlock;
+ }
+
if (!err && a[OVS_VPORT_ATTR_OPTIONS])
err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
if (err)
- goto exit_unlock;
+ goto exit_free;
+
if (a[OVS_VPORT_ATTR_UPCALL_PID])
vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]);
- reply = ovs_vport_cmd_build_info(vport, info->snd_portid, info->snd_seq,
- OVS_VPORT_CMD_NEW);
- if (IS_ERR(reply)) {
- netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
- ovs_dp_vport_multicast_group.id, PTR_ERR(reply));
- goto exit_unlock;
- }
+ err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
+ info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+ BUG_ON(err < 0);
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+ ovs_unlock();
+ ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+ return 0;
-exit_unlock:
rtnl_unlock();
+ return 0;
+
+exit_free:
+ kfree_skb(reply);
+exit_unlock:
+ ovs_unlock();
return err;
}
@@ -1756,7 +1856,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
struct vport *vport;
int err;
- rtnl_lock();
+ ovs_lock();
vport = lookup_vport(sock_net(skb->sk), info->userhdr, a);
err = PTR_ERR(vport);
if (IS_ERR(vport))
@@ -1776,11 +1876,10 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
err = 0;
ovs_dp_detach_port(vport);
- genl_notify(reply, genl_info_net(info), info->snd_portid,
- ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+ ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
exit_unlock:
- rtnl_unlock();
+ ovs_unlock();
return err;
}
@@ -1940,13 +2039,13 @@ static void rehash_flow_table(struct work_struct *work)
struct datapath *dp;
struct net *net;
- genl_lock();
+ ovs_lock();
rtnl_lock();
for_each_net(net) {
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
list_for_each_entry(dp, &ovs_net->dps, list_node) {
- struct flow_table *old_table = genl_dereference(dp->table);
+ struct flow_table *old_table = ovsl_dereference(dp->table);
struct flow_table *new_table;
new_table = ovs_flow_tbl_rehash(old_table);
@@ -1957,8 +2056,7 @@ static void rehash_flow_table(struct work_struct *work)
}
}
rtnl_unlock();
- genl_unlock();
-
+ ovs_unlock();
schedule_delayed_work(&rehash_flow_wq, REHASH_FLOW_INTERVAL);
}
@@ -1967,18 +2065,21 @@ static int __net_init ovs_init_net(struct net *net)
struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
INIT_LIST_HEAD(&ovs_net->dps);
+ INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
return 0;
}
static void __net_exit ovs_exit_net(struct net *net)
{
- struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
struct datapath *dp, *dp_next;
+ struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
- genl_lock();
+ ovs_lock();
list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
__dp_destroy(dp);
- genl_unlock();
+ ovs_unlock();
+
+ cancel_work_sync(&ovs_net->dp_notify_work);
}
static struct pernet_operations ovs_net_ops = {
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 031dfbf37c93..16b840695216 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -57,10 +57,9 @@ struct dp_stats_percpu {
* struct datapath - datapath for flow-based packet switching
* @rcu: RCU callback head for deferred destruction.
* @list_node: Element in global 'dps' list.
- * @n_flows: Number of flows currently in flow table.
- * @table: Current flow table. Protected by genl_lock and RCU.
+ * @table: Current flow table. Protected by ovs_mutex and RCU.
* @ports: Hash table for ports. %OVSP_LOCAL port always exists. Protected by
- * RTNL and RCU.
+ * ovs_mutex and RCU.
* @stats_percpu: Per-CPU datapath statistics.
* @net: Reference to net namespace.
*
@@ -86,26 +85,6 @@ struct datapath {
#endif
};
-struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no);
-
-static inline struct vport *ovs_vport_rcu(const struct datapath *dp, int port_no)
-{
- WARN_ON_ONCE(!rcu_read_lock_held());
- return ovs_lookup_vport(dp, port_no);
-}
-
-static inline struct vport *ovs_vport_rtnl_rcu(const struct datapath *dp, int port_no)
-{
- WARN_ON_ONCE(!rcu_read_lock_held() && !rtnl_is_locked());
- return ovs_lookup_vport(dp, port_no);
-}
-
-static inline struct vport *ovs_vport_rtnl(const struct datapath *dp, int port_no)
-{
- ASSERT_RTNL();
- return ovs_lookup_vport(dp, port_no);
-}
-
/**
* struct ovs_skb_cb - OVS data in skb CB
* @flow: The flow associated with this packet. May be %NULL if no flow.
@@ -119,7 +98,7 @@ struct ovs_skb_cb {
* struct dp_upcall - metadata to include with a packet to send to userspace
* @cmd: One of %OVS_PACKET_CMD_*.
* @key: Becomes %OVS_PACKET_ATTR_KEY. Must be nonnull.
- * @userdata: If nonnull, its u64 value is extracted and passed to userspace as
+ * @userdata: If nonnull, its variable-length value is passed to userspace as
* %OVS_PACKET_ATTR_USERDATA.
* @pid: Netlink PID to which packet should be sent. If @pid is 0 then no
* packet is sent and the packet is accounted in the datapath's @n_lost
@@ -132,6 +111,30 @@ struct dp_upcall_info {
u32 portid;
};
+/**
+ * struct ovs_net - Per net-namespace data for ovs.
+ * @dps: List of datapaths to enable dumping them all out.
+ * Protected by genl_mutex.
+ */
+struct ovs_net {
+ struct list_head dps;
+ struct work_struct dp_notify_work;
+};
+
+extern int ovs_net_id;
+void ovs_lock(void);
+void ovs_unlock(void);
+
+#ifdef CONFIG_LOCKDEP
+int lockdep_ovsl_is_held(void);
+#else
+#define lockdep_ovsl_is_held() 1
+#endif
+
+#define ASSERT_OVSL() WARN_ON(unlikely(!lockdep_ovsl_is_held()))
+#define ovsl_dereference(p) \
+ rcu_dereference_protected(p, lockdep_ovsl_is_held())
+
static inline struct net *ovs_dp_get_net(struct datapath *dp)
{
return read_pnet(&dp->net);
@@ -142,6 +145,26 @@ static inline void ovs_dp_set_net(struct datapath *dp, struct net *net)
write_pnet(&dp->net, net);
}
+struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no);
+
+static inline struct vport *ovs_vport_rcu(const struct datapath *dp, int port_no)
+{
+ WARN_ON_ONCE(!rcu_read_lock_held());
+ return ovs_lookup_vport(dp, port_no);
+}
+
+static inline struct vport *ovs_vport_ovsl_rcu(const struct datapath *dp, int port_no)
+{
+ WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_ovsl_is_held());
+ return ovs_lookup_vport(dp, port_no);
+}
+
+static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_no)
+{
+ ASSERT_OVSL();
+ return ovs_lookup_vport(dp, port_no);
+}
+
extern struct notifier_block ovs_dp_device_notifier;
extern struct genl_multicast_group ovs_dp_vport_multicast_group;
@@ -155,4 +178,5 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *, u32 pid, u32 seq,
u8 cmd);
int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb);
+void ovs_dp_notify_wq(struct work_struct *work);
#endif /* datapath.h */
diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c
index 5558350e0d33..ef4feec6cd84 100644
--- a/net/openvswitch/dp_notify.c
+++ b/net/openvswitch/dp_notify.c
@@ -18,46 +18,78 @@
#include <linux/netdevice.h>
#include <net/genetlink.h>
+#include <net/netns/generic.h>
#include "datapath.h"
#include "vport-internal_dev.h"
#include "vport-netdev.h"
+static void dp_detach_port_notify(struct vport *vport)
+{
+ struct sk_buff *notify;
+ struct datapath *dp;
+
+ dp = vport->dp;
+ notify = ovs_vport_cmd_build_info(vport, 0, 0,
+ OVS_VPORT_CMD_DEL);
+ ovs_dp_detach_port(vport);
+ if (IS_ERR(notify)) {
+ netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
+ ovs_dp_vport_multicast_group.id,
+ PTR_ERR(notify));
+ return;
+ }
+
+ genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0,
+ ovs_dp_vport_multicast_group.id,
+ GFP_KERNEL);
+}
+
+void ovs_dp_notify_wq(struct work_struct *work)
+{
+ struct ovs_net *ovs_net = container_of(work, struct ovs_net, dp_notify_work);
+ struct datapath *dp;
+
+ ovs_lock();
+ list_for_each_entry(dp, &ovs_net->dps, list_node) {
+ int i;
+
+ for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
+ struct vport *vport;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) {
+ struct netdev_vport *netdev_vport;
+
+ if (vport->ops->type != OVS_VPORT_TYPE_NETDEV)
+ continue;
+
+ netdev_vport = netdev_vport_priv(vport);
+ if (netdev_vport->dev->reg_state == NETREG_UNREGISTERED ||
+ netdev_vport->dev->reg_state == NETREG_UNREGISTERING)
+ dp_detach_port_notify(vport);
+ }
+ }
+ }
+ ovs_unlock();
+}
+
static int dp_device_event(struct notifier_block *unused, unsigned long event,
void *ptr)
{
+ struct ovs_net *ovs_net;
struct net_device *dev = ptr;
- struct vport *vport;
+ struct vport *vport = NULL;
- if (ovs_is_internal_dev(dev))
- vport = ovs_internal_dev_get_vport(dev);
- else
+ if (!ovs_is_internal_dev(dev))
vport = ovs_netdev_get_vport(dev);
if (!vport)
return NOTIFY_DONE;
- switch (event) {
- case NETDEV_UNREGISTER:
- if (!ovs_is_internal_dev(dev)) {
- struct sk_buff *notify;
- struct datapath *dp = vport->dp;
-
- notify = ovs_vport_cmd_build_info(vport, 0, 0,
- OVS_VPORT_CMD_DEL);
- ovs_dp_detach_port(vport);
- if (IS_ERR(notify)) {
- netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
- ovs_dp_vport_multicast_group.id,
- PTR_ERR(notify));
- break;
- }
-
- genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0,
- ovs_dp_vport_multicast_group.id,
- GFP_KERNEL);
- }
- break;
+ if (event == NETDEV_UNREGISTER) {
+ ovs_net = net_generic(dev_net(dev), ovs_net_id);
+ queue_work(system_wq, &ovs_net->dp_notify_work);
}
return NOTIFY_DONE;
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index fe0e4215c73d..b15321a2228c 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -211,7 +211,7 @@ struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *actions)
return ERR_PTR(-ENOMEM);
sfa->actions_len = actions_len;
- memcpy(sfa->actions, nla_data(actions), actions_len);
+ nla_memcpy(sfa->actions, actions, actions_len);
return sfa;
}
@@ -466,7 +466,7 @@ static __be16 parse_ethertype(struct sk_buff *skb)
proto = *(__be16 *) skb->data;
__skb_pull(skb, sizeof(__be16));
- if (ntohs(proto) >= 1536)
+ if (ntohs(proto) >= ETH_P_802_3_MIN)
return proto;
if (skb->len < sizeof(struct llc_snap_hdr))
@@ -483,7 +483,7 @@ static __be16 parse_ethertype(struct sk_buff *skb)
__skb_pull(skb, sizeof(struct llc_snap_hdr));
- if (ntohs(llc->ethertype) >= 1536)
+ if (ntohs(llc->ethertype) >= ETH_P_802_3_MIN)
return llc->ethertype;
return htons(ETH_P_802_2);
@@ -795,9 +795,9 @@ void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
{
+ BUG_ON(table->count == 0);
hlist_del_rcu(&flow->hash_node[table->node_ver]);
table->count--;
- BUG_ON(table->count < 0);
}
/* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */
@@ -1038,7 +1038,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
swkey->eth.type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
- if (ntohs(swkey->eth.type) < 1536)
+ if (ntohs(swkey->eth.type) < ETH_P_802_3_MIN)
return -EINVAL;
attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
} else {
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index a7bb60ff3b5b..0875fde65b9c 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -138,27 +138,6 @@ int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
void ovs_flow_used(struct sw_flow *, struct sk_buff *);
u64 ovs_flow_used_time(unsigned long flow_jiffies);
-/* Upper bound on the length of a nlattr-formatted flow key. The longest
- * nlattr-formatted flow key would be:
- *
- * struct pad nl hdr total
- * ------ --- ------ -----
- * OVS_KEY_ATTR_PRIORITY 4 -- 4 8
- * OVS_KEY_ATTR_IN_PORT 4 -- 4 8
- * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
- * OVS_KEY_ATTR_ETHERNET 12 -- 4 16
- * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
- * OVS_KEY_ATTR_8021Q 4 -- 4 8
- * OVS_KEY_ATTR_ENCAP 0 -- 4 4 (VLAN encapsulation)
- * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (inner VLAN ethertype)
- * OVS_KEY_ATTR_IPV6 40 -- 4 44
- * OVS_KEY_ATTR_ICMPV6 2 2 4 8
- * OVS_KEY_ATTR_ND 28 -- 4 32
- * -------------------------------------------------
- * total 152
- */
-#define FLOW_BUFSIZE 152
-
int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
const struct nlattr *);
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 0531de6c7a4a..84e0a0379186 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -63,16 +63,6 @@ static struct rtnl_link_stats64 *internal_dev_get_stats(struct net_device *netde
return stats;
}
-static int internal_dev_mac_addr(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- return 0;
-}
-
/* Called with rcu_read_lock_bh. */
static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
{
@@ -126,7 +116,7 @@ static const struct net_device_ops internal_dev_netdev_ops = {
.ndo_open = internal_dev_open,
.ndo_stop = internal_dev_stop,
.ndo_start_xmit = internal_dev_xmit,
- .ndo_set_mac_address = internal_dev_mac_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = internal_dev_change_mtu,
.ndo_get_stats64 = internal_dev_get_stats,
};
@@ -138,6 +128,7 @@ static void do_setup(struct net_device *netdev)
netdev->netdev_ops = &internal_dev_netdev_ops;
netdev->priv_flags &= ~IFF_TX_SKB_SHARING;
+ netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
netdev->destructor = internal_dev_destructor;
SET_ETHTOOL_OPS(netdev, &internal_dev_ethtool_ops);
netdev->tx_queue_len = 0;
@@ -146,7 +137,7 @@ static void do_setup(struct net_device *netdev)
NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_TSO;
netdev->vlan_features = netdev->features;
- netdev->features |= NETIF_F_HW_VLAN_TX;
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX;
netdev->hw_features = netdev->features & ~NETIF_F_LLTX;
eth_hw_addr_random(netdev);
}
@@ -182,16 +173,19 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
if (vport->port_no == OVSP_LOCAL)
netdev_vport->dev->features |= NETIF_F_NETNS_LOCAL;
+ rtnl_lock();
err = register_netdevice(netdev_vport->dev);
if (err)
goto error_free_netdev;
dev_set_promiscuity(netdev_vport->dev, 1);
+ rtnl_unlock();
netif_start_queue(netdev_vport->dev);
return vport;
error_free_netdev:
+ rtnl_unlock();
free_netdev(netdev_vport->dev);
error_free_vport:
ovs_vport_free(vport);
@@ -204,10 +198,13 @@ static void internal_dev_destroy(struct vport *vport)
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
netif_stop_queue(netdev_vport->dev);
+ rtnl_lock();
dev_set_promiscuity(netdev_vport->dev, -1);
/* unregister_netdevice() waits for an RCU grace period. */
unregister_netdevice(netdev_vport->dev);
+
+ rtnl_unlock();
}
static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
@@ -235,7 +232,6 @@ const struct vport_ops ovs_internal_vport_ops = {
.create = internal_dev_create,
.destroy = internal_dev_destroy,
.get_name = ovs_netdev_get_name,
- .get_ifindex = ovs_netdev_get_ifindex,
.send = internal_dev_recv,
};
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index 2130d61c384a..4f01c6d2ffa4 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -100,16 +100,20 @@ static struct vport *netdev_create(const struct vport_parms *parms)
goto error_put;
}
+ rtnl_lock();
err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook,
vport);
if (err)
- goto error_put;
+ goto error_unlock;
dev_set_promiscuity(netdev_vport->dev, 1);
netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH;
+ rtnl_unlock();
return vport;
+error_unlock:
+ rtnl_unlock();
error_put:
dev_put(netdev_vport->dev);
error_free_vport:
@@ -131,9 +135,11 @@ static void netdev_destroy(struct vport *vport)
{
struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
+ rtnl_lock();
netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH;
netdev_rx_handler_unregister(netdev_vport->dev);
dev_set_promiscuity(netdev_vport->dev, -1);
+ rtnl_unlock();
call_rcu(&netdev_vport->rcu, free_port_rcu);
}
@@ -144,12 +150,6 @@ const char *ovs_netdev_get_name(const struct vport *vport)
return netdev_vport->dev->name;
}
-int ovs_netdev_get_ifindex(const struct vport *vport)
-{
- const struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
- return netdev_vport->dev->ifindex;
-}
-
static unsigned int packet_length(const struct sk_buff *skb)
{
unsigned int length = skb->len - ETH_HLEN;
@@ -200,6 +200,5 @@ const struct vport_ops ovs_netdev_vport_ops = {
.create = netdev_create,
.destroy = netdev_destroy,
.get_name = ovs_netdev_get_name,
- .get_ifindex = ovs_netdev_get_ifindex,
.send = netdev_send,
};
diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h
index 6478079b3417..a3cb3a32cd77 100644
--- a/net/openvswitch/vport-netdev.h
+++ b/net/openvswitch/vport-netdev.h
@@ -40,6 +40,5 @@ netdev_vport_priv(const struct vport *vport)
const char *ovs_netdev_get_name(const struct vport *);
const char *ovs_netdev_get_config(const struct vport *);
-int ovs_netdev_get_ifindex(const struct vport *);
#endif /* vport_netdev.h */
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index f6b8132ce4cb..720623190eaa 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -40,7 +40,7 @@ static const struct vport_ops *vport_ops_list[] = {
&ovs_internal_vport_ops,
};
-/* Protected by RCU read lock for reading, RTNL lock for writing. */
+/* Protected by RCU read lock for reading, ovs_mutex for writing. */
static struct hlist_head *dev_table;
#define VPORT_HASH_BUCKETS 1024
@@ -80,7 +80,7 @@ static struct hlist_head *hash_bucket(struct net *net, const char *name)
*
* @name: name of port to find
*
- * Must be called with RTNL or RCU read lock.
+ * Must be called with ovs or RCU read lock.
*/
struct vport *ovs_vport_locate(struct net *net, const char *name)
{
@@ -128,7 +128,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
vport->ops = ops;
INIT_HLIST_NODE(&vport->dp_hash_node);
- vport->percpu_stats = alloc_percpu(struct vport_percpu_stats);
+ vport->percpu_stats = alloc_percpu(struct pcpu_tstats);
if (!vport->percpu_stats) {
kfree(vport);
return ERR_PTR(-ENOMEM);
@@ -161,7 +161,7 @@ void ovs_vport_free(struct vport *vport)
* @parms: Information about new vport.
*
* Creates a new vport with the specified configuration (which is dependent on
- * device type). RTNL lock must be held.
+ * device type). ovs_mutex must be held.
*/
struct vport *ovs_vport_add(const struct vport_parms *parms)
{
@@ -169,8 +169,6 @@ struct vport *ovs_vport_add(const struct vport_parms *parms)
int err = 0;
int i;
- ASSERT_RTNL();
-
for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) {
if (vport_ops_list[i]->type == parms->type) {
struct hlist_head *bucket;
@@ -201,12 +199,10 @@ out:
* @port: New configuration.
*
* Modifies an existing device with the specified configuration (which is
- * dependent on device type). RTNL lock must be held.
+ * dependent on device type). ovs_mutex must be held.
*/
int ovs_vport_set_options(struct vport *vport, struct nlattr *options)
{
- ASSERT_RTNL();
-
if (!vport->ops->set_options)
return -EOPNOTSUPP;
return vport->ops->set_options(vport, options);
@@ -218,11 +214,11 @@ int ovs_vport_set_options(struct vport *vport, struct nlattr *options)
* @vport: vport to delete.
*
* Detaches @vport from its datapath and destroys it. It is possible to fail
- * for reasons such as lack of memory. RTNL lock must be held.
+ * for reasons such as lack of memory. ovs_mutex must be held.
*/
void ovs_vport_del(struct vport *vport)
{
- ASSERT_RTNL();
+ ASSERT_OVSL();
hlist_del_rcu(&vport->hash_node);
@@ -237,7 +233,7 @@ void ovs_vport_del(struct vport *vport)
*
* Retrieves transmit, receive, and error stats for the given device.
*
- * Must be called with RTNL lock or rcu_read_lock.
+ * Must be called with ovs_mutex or rcu_read_lock.
*/
void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
{
@@ -264,16 +260,16 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
spin_unlock_bh(&vport->stats_lock);
for_each_possible_cpu(i) {
- const struct vport_percpu_stats *percpu_stats;
- struct vport_percpu_stats local_stats;
+ const struct pcpu_tstats *percpu_stats;
+ struct pcpu_tstats local_stats;
unsigned int start;
percpu_stats = per_cpu_ptr(vport->percpu_stats, i);
do {
- start = u64_stats_fetch_begin_bh(&percpu_stats->sync);
+ start = u64_stats_fetch_begin_bh(&percpu_stats->syncp);
local_stats = *percpu_stats;
- } while (u64_stats_fetch_retry_bh(&percpu_stats->sync, start));
+ } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start));
stats->rx_bytes += local_stats.rx_bytes;
stats->rx_packets += local_stats.rx_packets;
@@ -296,22 +292,24 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
* negative error code if a real error occurred. If an error occurs, @skb is
* left unmodified.
*
- * Must be called with RTNL lock or rcu_read_lock.
+ * Must be called with ovs_mutex or rcu_read_lock.
*/
int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
{
struct nlattr *nla;
+ int err;
+
+ if (!vport->ops->get_options)
+ return 0;
nla = nla_nest_start(skb, OVS_VPORT_ATTR_OPTIONS);
if (!nla)
return -EMSGSIZE;
- if (vport->ops->get_options) {
- int err = vport->ops->get_options(vport, skb);
- if (err) {
- nla_nest_cancel(skb, nla);
- return err;
- }
+ err = vport->ops->get_options(vport, skb);
+ if (err) {
+ nla_nest_cancel(skb, nla);
+ return err;
}
nla_nest_end(skb, nla);
@@ -329,13 +327,13 @@ int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
*/
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
{
- struct vport_percpu_stats *stats;
+ struct pcpu_tstats *stats;
stats = this_cpu_ptr(vport->percpu_stats);
- u64_stats_update_begin(&stats->sync);
+ u64_stats_update_begin(&stats->syncp);
stats->rx_packets++;
stats->rx_bytes += skb->len;
- u64_stats_update_end(&stats->sync);
+ u64_stats_update_end(&stats->syncp);
ovs_dp_process_received_packet(vport, skb);
}
@@ -346,7 +344,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
* @vport: vport on which to send the packet
* @skb: skb to send
*
- * Sends the given packet and returns the length of data sent. Either RTNL
+ * Sends the given packet and returns the length of data sent. Either ovs
* lock or rcu_read_lock must be held.
*/
int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
@@ -354,14 +352,14 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
int sent = vport->ops->send(vport, skb);
if (likely(sent)) {
- struct vport_percpu_stats *stats;
+ struct pcpu_tstats *stats;
stats = this_cpu_ptr(vport->percpu_stats);
- u64_stats_update_begin(&stats->sync);
+ u64_stats_update_begin(&stats->syncp);
stats->tx_packets++;
stats->tx_bytes += sent;
- u64_stats_update_end(&stats->sync);
+ u64_stats_update_end(&stats->syncp);
}
return sent;
}
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index 3f7961ea3c56..68a377bc0841 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -19,6 +19,7 @@
#ifndef VPORT_H
#define VPORT_H 1
+#include <linux/if_tunnel.h>
#include <linux/list.h>
#include <linux/netlink.h>
#include <linux/openvswitch.h>
@@ -50,14 +51,6 @@ int ovs_vport_send(struct vport *, struct sk_buff *);
/* The following definitions are for implementers of vport devices: */
-struct vport_percpu_stats {
- u64 rx_bytes;
- u64 rx_packets;
- u64 tx_bytes;
- u64 tx_packets;
- struct u64_stats_sync sync;
-};
-
struct vport_err_stats {
u64 rx_dropped;
u64 rx_errors;
@@ -68,10 +61,10 @@ struct vport_err_stats {
/**
* struct vport - one port within a datapath
* @rcu: RCU callback head for deferred destruction.
- * @port_no: Index into @dp's @ports array.
* @dp: Datapath to which this port belongs.
* @upcall_portid: The Netlink port to use for packets received on this port that
* miss the flow table.
+ * @port_no: Index into @dp's @ports array.
* @hash_node: Element in @dev_table hash table in vport.c.
* @dp_hash_node: Element in @datapath->ports hash table in datapath.c.
* @ops: Class structure.
@@ -81,15 +74,15 @@ struct vport_err_stats {
*/
struct vport {
struct rcu_head rcu;
- u16 port_no;
struct datapath *dp;
u32 upcall_portid;
+ u16 port_no;
struct hlist_node hash_node;
struct hlist_node dp_hash_node;
const struct vport_ops *ops;
- struct vport_percpu_stats __percpu *percpu_stats;
+ struct pcpu_tstats __percpu *percpu_stats;
spinlock_t stats_lock;
struct vport_err_stats err_stats;
@@ -131,24 +124,22 @@ struct vport_parms {
* have any configuration.
* @get_name: Get the device's name.
* @get_config: Get the device's configuration.
- * @get_ifindex: Get the system interface index associated with the device.
* May be null if the device does not have an ifindex.
* @send: Send a packet on the device. Returns the length of the packet sent.
*/
struct vport_ops {
enum ovs_vport_type type;
- /* Called with RTNL lock. */
+ /* Called with ovs_mutex. */
struct vport *(*create)(const struct vport_parms *);
void (*destroy)(struct vport *);
int (*set_options)(struct vport *, struct nlattr *);
int (*get_options)(const struct vport *, struct sk_buff *);
- /* Called with rcu_read_lock or RTNL lock. */
+ /* Called with rcu_read_lock or ovs_mutex. */
const char *(*get_name)(const struct vport *);
void (*get_config)(const struct vport *, void *);
- int (*get_ifindex)(const struct vport *);
int (*send)(struct vport *, struct sk_buff *);
};
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1d6793dbfbae..dd5cd49b0e09 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -158,10 +158,16 @@ struct packet_mreq_max {
unsigned char mr_address[MAX_ADDR_LEN];
};
+union tpacket_uhdr {
+ struct tpacket_hdr *h1;
+ struct tpacket2_hdr *h2;
+ struct tpacket3_hdr *h3;
+ void *raw;
+};
+
static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
int closing, int tx_ring);
-
#define V3_ALIGNMENT (8)
#define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
@@ -181,6 +187,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
struct packet_sock;
static int tpacket_snd(struct packet_sock *po, struct msghdr *msg);
+static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev);
static void *packet_previous_frame(struct packet_sock *po,
struct packet_ring_buffer *rb,
@@ -288,11 +296,7 @@ static inline __pure struct page *pgv_to_page(void *addr)
static void __packet_set_status(struct packet_sock *po, void *frame, int status)
{
- union {
- struct tpacket_hdr *h1;
- struct tpacket2_hdr *h2;
- void *raw;
- } h;
+ union tpacket_uhdr h;
h.raw = frame;
switch (po->tp_version) {
@@ -315,11 +319,7 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
static int __packet_get_status(struct packet_sock *po, void *frame)
{
- union {
- struct tpacket_hdr *h1;
- struct tpacket2_hdr *h2;
- void *raw;
- } h;
+ union tpacket_uhdr h;
smp_rmb();
@@ -339,17 +339,66 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
}
}
+static __u32 tpacket_get_timestamp(struct sk_buff *skb, struct timespec *ts,
+ unsigned int flags)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+
+ if (shhwtstamps) {
+ if ((flags & SOF_TIMESTAMPING_SYS_HARDWARE) &&
+ ktime_to_timespec_cond(shhwtstamps->syststamp, ts))
+ return TP_STATUS_TS_SYS_HARDWARE;
+ if ((flags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
+ ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts))
+ return TP_STATUS_TS_RAW_HARDWARE;
+ }
+
+ if (ktime_to_timespec_cond(skb->tstamp, ts))
+ return TP_STATUS_TS_SOFTWARE;
+
+ return 0;
+}
+
+static __u32 __packet_set_timestamp(struct packet_sock *po, void *frame,
+ struct sk_buff *skb)
+{
+ union tpacket_uhdr h;
+ struct timespec ts;
+ __u32 ts_status;
+
+ if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
+ return 0;
+
+ h.raw = frame;
+ switch (po->tp_version) {
+ case TPACKET_V1:
+ h.h1->tp_sec = ts.tv_sec;
+ h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC;
+ break;
+ case TPACKET_V2:
+ h.h2->tp_sec = ts.tv_sec;
+ h.h2->tp_nsec = ts.tv_nsec;
+ break;
+ case TPACKET_V3:
+ default:
+ WARN(1, "TPACKET version not supported.\n");
+ BUG();
+ }
+
+ /* one flush is safe, as both fields always lie on the same cacheline */
+ flush_dcache_page(pgv_to_page(&h.h1->tp_sec));
+ smp_wmb();
+
+ return ts_status;
+}
+
static void *packet_lookup_frame(struct packet_sock *po,
struct packet_ring_buffer *rb,
unsigned int position,
int status)
{
unsigned int pg_vec_pos, frame_offset;
- union {
- struct tpacket_hdr *h1;
- struct tpacket2_hdr *h2;
- void *raw;
- } h;
+ union tpacket_uhdr h;
pg_vec_pos = position / rb->frames_per_block;
frame_offset = position % rb->frames_per_block;
@@ -479,7 +528,7 @@ static void init_prb_bdqc(struct packet_sock *po,
p1->hdrlen = po->tp_hdrlen;
p1->version = po->tp_version;
p1->last_kactive_blk_num = 0;
- po->stats_u.stats3.tp_freeze_q_cnt = 0;
+ po->stats.stats3.tp_freeze_q_cnt = 0;
if (req_u->req3.tp_retire_blk_tov)
p1->retire_blk_tov = req_u->req3.tp_retire_blk_tov;
else
@@ -647,7 +696,7 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
struct tpacket3_hdr *last_pkt;
struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
- if (po->stats.tp_drops)
+ if (po->stats.stats3.tp_drops)
status |= TP_STATUS_LOSING;
last_pkt = (struct tpacket3_hdr *)pkc1->prev;
@@ -752,7 +801,7 @@ static void prb_freeze_queue(struct tpacket_kbdq_core *pkc,
struct packet_sock *po)
{
pkc->reset_pending_on_curr_blk = 1;
- po->stats_u.stats3.tp_freeze_q_cnt++;
+ po->stats.stats3.tp_freeze_q_cnt++;
}
#define TOTAL_PKT_LEN_INCL_ALIGN(length) (ALIGN((length), V3_ALIGNMENT))
@@ -973,11 +1022,11 @@ static void *packet_current_rx_frame(struct packet_sock *po,
static void *prb_lookup_block(struct packet_sock *po,
struct packet_ring_buffer *rb,
- unsigned int previous,
+ unsigned int idx,
int status)
{
struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb);
- struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, previous);
+ struct tpacket_block_desc *pbd = GET_PBLOCK_DESC(pkc, idx);
if (status != BLOCK_STATUS(pbd))
return NULL;
@@ -1041,6 +1090,29 @@ static void packet_increment_head(struct packet_ring_buffer *buff)
buff->head = buff->head != buff->frame_max ? buff->head+1 : 0;
}
+static bool packet_rcv_has_room(struct packet_sock *po, struct sk_buff *skb)
+{
+ struct sock *sk = &po->sk;
+ bool has_room;
+
+ if (po->prot_hook.func != tpacket_rcv)
+ return (atomic_read(&sk->sk_rmem_alloc) + skb->truesize)
+ <= sk->sk_rcvbuf;
+
+ spin_lock(&sk->sk_receive_queue.lock);
+ if (po->tp_version == TPACKET_V3)
+ has_room = prb_lookup_block(po, &po->rx_ring,
+ po->rx_ring.prb_bdqc.kactive_blk_num,
+ TP_STATUS_KERNEL);
+ else
+ has_room = packet_lookup_frame(po, &po->rx_ring,
+ po->rx_ring.head,
+ TP_STATUS_KERNEL);
+ spin_unlock(&sk->sk_receive_queue.lock);
+
+ return has_room;
+}
+
static void packet_sock_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_error_queue);
@@ -1066,16 +1138,16 @@ static int fanout_rr_next(struct packet_fanout *f, unsigned int num)
return x;
}
-static struct sock *fanout_demux_hash(struct packet_fanout *f, struct sk_buff *skb, unsigned int num)
+static unsigned int fanout_demux_hash(struct packet_fanout *f,
+ struct sk_buff *skb,
+ unsigned int num)
{
- u32 idx, hash = skb->rxhash;
-
- idx = ((u64)hash * num) >> 32;
-
- return f->arr[idx];
+ return (((u64)skb->rxhash) * num) >> 32;
}
-static struct sock *fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb, unsigned int num)
+static unsigned int fanout_demux_lb(struct packet_fanout *f,
+ struct sk_buff *skb,
+ unsigned int num)
{
int cur, old;
@@ -1083,14 +1155,40 @@ static struct sock *fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb
while ((old = atomic_cmpxchg(&f->rr_cur, cur,
fanout_rr_next(f, num))) != cur)
cur = old;
- return f->arr[cur];
+ return cur;
}
-static struct sock *fanout_demux_cpu(struct packet_fanout *f, struct sk_buff *skb, unsigned int num)
+static unsigned int fanout_demux_cpu(struct packet_fanout *f,
+ struct sk_buff *skb,
+ unsigned int num)
{
- unsigned int cpu = smp_processor_id();
+ return smp_processor_id() % num;
+}
- return f->arr[cpu % num];
+static unsigned int fanout_demux_rollover(struct packet_fanout *f,
+ struct sk_buff *skb,
+ unsigned int idx, unsigned int skip,
+ unsigned int num)
+{
+ unsigned int i, j;
+
+ i = j = min_t(int, f->next[idx], num - 1);
+ do {
+ if (i != skip && packet_rcv_has_room(pkt_sk(f->arr[i]), skb)) {
+ if (i != j)
+ f->next[idx] = i;
+ return i;
+ }
+ if (++i == num)
+ i = 0;
+ } while (i != j);
+
+ return idx;
+}
+
+static bool fanout_has_flag(struct packet_fanout *f, u16 flag)
+{
+ return f->flags & (flag >> 8);
}
static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
@@ -1099,7 +1197,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
struct packet_fanout *f = pt->af_packet_priv;
unsigned int num = f->num_members;
struct packet_sock *po;
- struct sock *sk;
+ unsigned int idx;
if (!net_eq(dev_net(dev), read_pnet(&f->net)) ||
!num) {
@@ -1110,23 +1208,31 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
switch (f->type) {
case PACKET_FANOUT_HASH:
default:
- if (f->defrag) {
+ if (fanout_has_flag(f, PACKET_FANOUT_FLAG_DEFRAG)) {
skb = ip_check_defrag(skb, IP_DEFRAG_AF_PACKET);
if (!skb)
return 0;
}
skb_get_rxhash(skb);
- sk = fanout_demux_hash(f, skb, num);
+ idx = fanout_demux_hash(f, skb, num);
break;
case PACKET_FANOUT_LB:
- sk = fanout_demux_lb(f, skb, num);
+ idx = fanout_demux_lb(f, skb, num);
break;
case PACKET_FANOUT_CPU:
- sk = fanout_demux_cpu(f, skb, num);
+ idx = fanout_demux_cpu(f, skb, num);
+ break;
+ case PACKET_FANOUT_ROLLOVER:
+ idx = fanout_demux_rollover(f, skb, 0, (unsigned int) -1, num);
break;
}
- po = pkt_sk(sk);
+ po = pkt_sk(f->arr[idx]);
+ if (fanout_has_flag(f, PACKET_FANOUT_FLAG_ROLLOVER) &&
+ unlikely(!packet_rcv_has_room(po, skb))) {
+ idx = fanout_demux_rollover(f, skb, idx, idx, num);
+ po = pkt_sk(f->arr[idx]);
+ }
return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
}
@@ -1175,10 +1281,13 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
struct packet_sock *po = pkt_sk(sk);
struct packet_fanout *f, *match;
u8 type = type_flags & 0xff;
- u8 defrag = (type_flags & PACKET_FANOUT_FLAG_DEFRAG) ? 1 : 0;
+ u8 flags = type_flags >> 8;
int err;
switch (type) {
+ case PACKET_FANOUT_ROLLOVER:
+ if (type_flags & PACKET_FANOUT_FLAG_ROLLOVER)
+ return -EINVAL;
case PACKET_FANOUT_HASH:
case PACKET_FANOUT_LB:
case PACKET_FANOUT_CPU:
@@ -1203,7 +1312,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
}
}
err = -EINVAL;
- if (match && match->defrag != defrag)
+ if (match && match->flags != flags)
goto out;
if (!match) {
err = -ENOMEM;
@@ -1213,7 +1322,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
write_pnet(&match->net, sock_net(sk));
match->id = id;
match->type = type;
- match->defrag = defrag;
+ match->flags = flags;
atomic_set(&match->rr_cur, 0);
INIT_LIST_HEAD(&match->list);
spin_lock_init(&match->lock);
@@ -1443,13 +1552,14 @@ retry:
skb->dev = dev;
skb->priority = sk->sk_priority;
skb->mark = sk->sk_mark;
- err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
- if (err < 0)
- goto out_unlock;
+
+ sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
+ skb_probe_transport_header(skb, 0);
+
dev_queue_xmit(skb);
rcu_read_unlock();
return len;
@@ -1577,7 +1687,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
nf_reset(skb);
spin_lock(&sk->sk_receive_queue.lock);
- po->stats.tp_packets++;
+ po->stats.stats1.tp_packets++;
skb->dropcount = atomic_read(&sk->sk_drops);
__skb_queue_tail(&sk->sk_receive_queue, skb);
spin_unlock(&sk->sk_receive_queue.lock);
@@ -1586,7 +1696,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
drop_n_acct:
spin_lock(&sk->sk_receive_queue.lock);
- po->stats.tp_drops++;
+ po->stats.stats1.tp_drops++;
atomic_inc(&sk->sk_drops);
spin_unlock(&sk->sk_receive_queue.lock);
@@ -1606,21 +1716,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
struct sock *sk;
struct packet_sock *po;
struct sockaddr_ll *sll;
- union {
- struct tpacket_hdr *h1;
- struct tpacket2_hdr *h2;
- struct tpacket3_hdr *h3;
- void *raw;
- } h;
+ union tpacket_uhdr h;
u8 *skb_head = skb->data;
int skb_len = skb->len;
unsigned int snaplen, res;
unsigned long status = TP_STATUS_USER;
unsigned short macoff, netoff, hdrlen;
struct sk_buff *copy_skb = NULL;
- struct timeval tv;
struct timespec ts;
- struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ __u32 ts_status;
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
@@ -1692,10 +1796,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
* Anyways, moving it for V1/V2 only as V3 doesn't need this
* at packet level.
*/
- if (po->stats.tp_drops)
+ if (po->stats.stats1.tp_drops)
status |= TP_STATUS_LOSING;
}
- po->stats.tp_packets++;
+ po->stats.stats1.tp_packets++;
if (copy_skb) {
status |= TP_STATUS_COPY;
__skb_queue_tail(&sk->sk_receive_queue, copy_skb);
@@ -1704,24 +1808,19 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
skb_copy_bits(skb, 0, h.raw + macoff, snaplen);
+ if (!(ts_status = tpacket_get_timestamp(skb, &ts, po->tp_tstamp)))
+ getnstimeofday(&ts);
+
+ status |= ts_status;
+
switch (po->tp_version) {
case TPACKET_V1:
h.h1->tp_len = skb->len;
h.h1->tp_snaplen = snaplen;
h.h1->tp_mac = macoff;
h.h1->tp_net = netoff;
- if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
- && shhwtstamps->syststamp.tv64)
- tv = ktime_to_timeval(shhwtstamps->syststamp);
- else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
- && shhwtstamps->hwtstamp.tv64)
- tv = ktime_to_timeval(shhwtstamps->hwtstamp);
- else if (skb->tstamp.tv64)
- tv = ktime_to_timeval(skb->tstamp);
- else
- do_gettimeofday(&tv);
- h.h1->tp_sec = tv.tv_sec;
- h.h1->tp_usec = tv.tv_usec;
+ h.h1->tp_sec = ts.tv_sec;
+ h.h1->tp_usec = ts.tv_nsec / NSEC_PER_USEC;
hdrlen = sizeof(*h.h1);
break;
case TPACKET_V2:
@@ -1729,16 +1828,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_snaplen = snaplen;
h.h2->tp_mac = macoff;
h.h2->tp_net = netoff;
- if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
- && shhwtstamps->syststamp.tv64)
- ts = ktime_to_timespec(shhwtstamps->syststamp);
- else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
- && shhwtstamps->hwtstamp.tv64)
- ts = ktime_to_timespec(shhwtstamps->hwtstamp);
- else if (skb->tstamp.tv64)
- ts = ktime_to_timespec(skb->tstamp);
- else
- getnstimeofday(&ts);
h.h2->tp_sec = ts.tv_sec;
h.h2->tp_nsec = ts.tv_nsec;
if (vlan_tx_tag_present(skb)) {
@@ -1759,16 +1848,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h3->tp_snaplen = snaplen;
h.h3->tp_mac = macoff;
h.h3->tp_net = netoff;
- if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
- && shhwtstamps->syststamp.tv64)
- ts = ktime_to_timespec(shhwtstamps->syststamp);
- else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
- && shhwtstamps->hwtstamp.tv64)
- ts = ktime_to_timespec(shhwtstamps->hwtstamp);
- else if (skb->tstamp.tv64)
- ts = ktime_to_timespec(skb->tstamp);
- else
- getnstimeofday(&ts);
h.h3->tp_sec = ts.tv_sec;
h.h3->tp_nsec = ts.tv_nsec;
hdrlen = sizeof(*h.h3);
@@ -1819,7 +1898,7 @@ drop:
return 0;
ring_is_full:
- po->stats.tp_drops++;
+ po->stats.stats1.tp_drops++;
spin_unlock(&sk->sk_receive_queue.lock);
sk->sk_data_ready(sk, 0);
@@ -1833,10 +1912,14 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
void *ph;
if (likely(po->tx_ring.pg_vec)) {
+ __u32 ts;
+
ph = skb_shinfo(skb)->destructor_arg;
BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
atomic_dec(&po->tx_ring.pending);
- __packet_set_status(po, ph, TP_STATUS_AVAILABLE);
+
+ ts = __packet_set_timestamp(po, ph, skb);
+ __packet_set_status(po, ph, TP_STATUS_AVAILABLE | ts);
}
sock_wfree(skb);
@@ -1846,11 +1929,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
void *frame, struct net_device *dev, int size_max,
__be16 proto, unsigned char *addr, int hlen)
{
- union {
- struct tpacket_hdr *h1;
- struct tpacket2_hdr *h2;
- void *raw;
- } ph;
+ union tpacket_uhdr ph;
int to_write, offset, len, tp_len, nr_frags, len_max;
struct socket *sock = po->sk.sk_socket;
struct page *page;
@@ -1863,6 +1942,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->dev = dev;
skb->priority = po->sk.sk_priority;
skb->mark = po->sk.sk_mark;
+ sock_tx_timestamp(&po->sk, &skb_shinfo(skb)->tx_flags);
skb_shinfo(skb)->destructor_arg = ph.raw;
switch (po->tp_version) {
@@ -1880,6 +1960,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
+ skb_probe_transport_header(skb, 0);
if (po->tp_tx_has_off) {
int off_min, off_max, off;
@@ -2247,9 +2328,8 @@ static int packet_snd(struct socket *sock,
err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
if (err)
goto out_free;
- err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
- if (err < 0)
- goto out_free;
+
+ sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
/* Earlier code assumed this would be a VLAN pkt,
@@ -2289,6 +2369,8 @@ static int packet_snd(struct socket *sock,
len += vnet_hdr_len;
}
+ skb_probe_transport_header(skb, reserve);
+
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
@@ -3165,8 +3247,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
struct sock *sk = sock->sk;
struct packet_sock *po = pkt_sk(sk);
void *data = &val;
- struct tpacket_stats st;
- union tpacket_stats_u st_u;
+ union tpacket_stats_u st;
if (level != SOL_PACKET)
return -ENOPROTOOPT;
@@ -3180,22 +3261,18 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case PACKET_STATISTICS:
spin_lock_bh(&sk->sk_receive_queue.lock);
+ memcpy(&st, &po->stats, sizeof(st));
+ memset(&po->stats, 0, sizeof(po->stats));
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+
if (po->tp_version == TPACKET_V3) {
lv = sizeof(struct tpacket_stats_v3);
- memcpy(&st_u.stats3, &po->stats,
- sizeof(struct tpacket_stats));
- st_u.stats3.tp_freeze_q_cnt =
- po->stats_u.stats3.tp_freeze_q_cnt;
- st_u.stats3.tp_packets += po->stats.tp_drops;
- data = &st_u.stats3;
+ data = &st.stats3;
} else {
lv = sizeof(struct tpacket_stats);
- st = po->stats;
- st.tp_packets += st.tp_drops;
- data = &st;
+ data = &st.stats1;
}
- memset(&po->stats, 0, sizeof(st));
- spin_unlock_bh(&sk->sk_receive_queue.lock);
+
break;
case PACKET_AUXDATA:
val = po->auxdata;
@@ -3240,7 +3317,8 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
case PACKET_FANOUT:
val = (po->fanout ?
((u32)po->fanout->id |
- ((u32)po->fanout->type << 16)) :
+ ((u32)po->fanout->type << 16) |
+ ((u32)po->fanout->flags << 24)) :
0);
break;
case PACKET_TX_HAS_OFF:
diff --git a/net/packet/diag.c b/net/packet/diag.c
index d3fcd1ebef7e..a9584a2f6d69 100644
--- a/net/packet/diag.c
+++ b/net/packet/diag.c
@@ -125,8 +125,10 @@ static int pdiag_put_fanout(struct packet_sock *po, struct sk_buff *nlskb)
return ret;
}
-static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req,
- u32 portid, u32 seq, u32 flags, int sk_ino)
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
+ struct packet_diag_req *req,
+ struct user_namespace *user_ns,
+ u32 portid, u32 seq, u32 flags, int sk_ino)
{
struct nlmsghdr *nlh;
struct packet_diag_msg *rp;
@@ -147,6 +149,11 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag
pdiag_put_info(po, skb))
goto out_nlmsg_trim;
+ if ((req->pdiag_show & PACKET_SHOW_INFO) &&
+ nla_put_u32(skb, PACKET_DIAG_UID,
+ from_kuid_munged(user_ns, sock_i_uid(sk))))
+ goto out_nlmsg_trim;
+
if ((req->pdiag_show & PACKET_SHOW_MCLIST) &&
pdiag_put_mclist(po, skb))
goto out_nlmsg_trim;
@@ -159,6 +166,14 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag
pdiag_put_fanout(po, skb))
goto out_nlmsg_trim;
+ if ((req->pdiag_show & PACKET_SHOW_MEMINFO) &&
+ sock_diag_put_meminfo(sk, skb, PACKET_DIAG_MEMINFO))
+ goto out_nlmsg_trim;
+
+ if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
+ sock_diag_put_filterinfo(user_ns, sk, skb, PACKET_DIAG_FILTER))
+ goto out_nlmsg_trim;
+
return nlmsg_end(skb, nlh);
out_nlmsg_trim:
@@ -183,9 +198,11 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (num < s_num)
goto next;
- if (sk_diag_fill(sk, skb, req, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, NLM_F_MULTI,
- sock_i_ino(sk)) < 0)
+ if (sk_diag_fill(sk, skb, req,
+ sk_user_ns(NETLINK_CB(cb->skb).sk),
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ sock_i_ino(sk)) < 0)
goto done;
next:
num++;
diff --git a/net/packet/internal.h b/net/packet/internal.h
index e84cab8cb7a9..c4e4b4561207 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -54,6 +54,7 @@ struct pgv {
struct packet_ring_buffer {
struct pgv *pg_vec;
+
unsigned int head;
unsigned int frames_per_block;
unsigned int frame_size;
@@ -63,8 +64,9 @@ struct packet_ring_buffer {
unsigned int pg_vec_pages;
unsigned int pg_vec_len;
- struct tpacket_kbdq_core prb_bdqc;
atomic_t pending;
+
+ struct tpacket_kbdq_core prb_bdqc;
};
extern struct mutex fanout_mutex;
@@ -77,10 +79,11 @@ struct packet_fanout {
unsigned int num_members;
u16 id;
u8 type;
- u8 defrag;
+ u8 flags;
atomic_t rr_cur;
struct list_head list;
struct sock *arr[PACKET_FANOUT_MAX];
+ int next[PACKET_FANOUT_MAX];
spinlock_t lock;
atomic_t sk_ref;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
@@ -90,8 +93,7 @@ struct packet_sock {
/* struct sock has to be the first member of packet_sock */
struct sock sk;
struct packet_fanout *fanout;
- struct tpacket_stats stats;
- union tpacket_stats_u stats_u;
+ union tpacket_stats_u stats;
struct packet_ring_buffer rx_ring;
struct packet_ring_buffer tx_ring;
int copy_thresh;
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
index 0193630d3061..dc15f4300808 100644
--- a/net/phonet/pn_netlink.c
+++ b/net/phonet/pn_netlink.c
@@ -61,7 +61,7 @@ static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = {
[IFA_LOCAL] = { .type = NLA_U8 },
};
-static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
+static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[IFA_MAX+1];
@@ -224,7 +224,7 @@ static const struct nla_policy rtm_phonet_policy[RTA_MAX+1] = {
[RTA_OIF] = { .type = NLA_U32 },
};
-static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
+static int route_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tb[RTA_MAX+1];
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 9b9be5279f5d..1cec5e4f3a5e 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -587,7 +587,7 @@ static ssize_t rfkill_name_show(struct device *dev,
static const char *rfkill_get_type_str(enum rfkill_type type)
{
- BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1);
+ BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
switch (type) {
case RFKILL_TYPE_WLAN:
@@ -604,6 +604,8 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
return "gps";
case RFKILL_TYPE_FM:
return "fm";
+ case RFKILL_TYPE_NFC:
+ return "nfc";
default:
BUG();
}
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 78fc0937948d..fb076cd6f808 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -131,6 +131,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name);
if (IS_ERR(rfkill->pwr_clk)) {
pr_warn("%s: can't find pwr_clk.\n", __func__);
+ ret = PTR_ERR(rfkill->pwr_clk);
goto fail_shutdown_name;
}
}
@@ -152,9 +153,11 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
}
rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
- &rfkill_gpio_ops, rfkill);
- if (!rfkill->rfkill_dev)
+ &rfkill_gpio_ops, rfkill);
+ if (!rfkill->rfkill_dev) {
+ ret = -ENOMEM;
goto fail_shutdown;
+ }
ret = rfkill_register(rfkill->rfkill_dev);
if (ret < 0)
diff --git a/net/rfkill/rfkill-regulator.c b/net/rfkill/rfkill-regulator.c
index 4b5ab21ecb24..d11ac79246e4 100644
--- a/net/rfkill/rfkill-regulator.c
+++ b/net/rfkill/rfkill-regulator.c
@@ -51,7 +51,7 @@ static int rfkill_regulator_set_block(void *data, bool blocked)
return 0;
}
-struct rfkill_ops rfkill_regulator_ops = {
+static struct rfkill_ops rfkill_regulator_ops = {
.set_block = rfkill_regulator_set_block,
};
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index cf68e6e4054a..9c8347451597 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1253,6 +1253,7 @@ static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (srose != NULL) {
+ memset(srose, 0, msg->msg_namelen);
srose->srose_family = AF_ROSE;
srose->srose_addr = rose->dest_addr;
srose->srose_call = rose->dest_call;
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 8579c4bb20c9..fd7072827a40 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -982,7 +982,7 @@ done:
return ret;
}
-static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
+static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tca[TCA_ACT_MAX + 1];
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 08fa1e8a4ca4..3a4c0caa1f7d 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -166,15 +166,17 @@ static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
return 1;
}
-static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+static int tcf_csum_ipv6_icmp(struct sk_buff *skb,
unsigned int ihl, unsigned int ipl)
{
struct icmp6hdr *icmp6h;
+ const struct ipv6hdr *ip6h;
icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
if (icmp6h == NULL)
return 0;
+ ip6h = ipv6_hdr(skb);
icmp6h->icmp6_cksum = 0;
skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -186,15 +188,17 @@ static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
return 1;
}
-static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
+static int tcf_csum_ipv4_tcp(struct sk_buff *skb,
unsigned int ihl, unsigned int ipl)
{
struct tcphdr *tcph;
+ const struct iphdr *iph;
tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
if (tcph == NULL)
return 0;
+ iph = ip_hdr(skb);
tcph->check = 0;
skb->csum = csum_partial(tcph, ipl - ihl, 0);
tcph->check = tcp_v4_check(ipl - ihl,
@@ -205,15 +209,17 @@ static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
return 1;
}
-static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+static int tcf_csum_ipv6_tcp(struct sk_buff *skb,
unsigned int ihl, unsigned int ipl)
{
struct tcphdr *tcph;
+ const struct ipv6hdr *ip6h;
tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
if (tcph == NULL)
return 0;
+ ip6h = ipv6_hdr(skb);
tcph->check = 0;
skb->csum = csum_partial(tcph, ipl - ihl, 0);
tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -225,10 +231,11 @@ static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
return 1;
}
-static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
+static int tcf_csum_ipv4_udp(struct sk_buff *skb,
unsigned int ihl, unsigned int ipl, int udplite)
{
struct udphdr *udph;
+ const struct iphdr *iph;
u16 ul;
/*
@@ -242,6 +249,7 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
if (udph == NULL)
return 0;
+ iph = ip_hdr(skb);
ul = ntohs(udph->len);
if (udplite || udph->check) {
@@ -276,10 +284,11 @@ ignore_obscure_skb:
return 1;
}
-static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
+static int tcf_csum_ipv6_udp(struct sk_buff *skb,
unsigned int ihl, unsigned int ipl, int udplite)
{
struct udphdr *udph;
+ const struct ipv6hdr *ip6h;
u16 ul;
/*
@@ -293,6 +302,7 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
if (udph == NULL)
return 0;
+ ip6h = ipv6_hdr(skb);
ul = ntohs(udph->len);
udph->check = 0;
@@ -328,7 +338,7 @@ ignore_obscure_skb:
static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
{
- struct iphdr *iph;
+ const struct iphdr *iph;
int ntkoff;
ntkoff = skb_network_offset(skb);
@@ -353,19 +363,19 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
break;
case IPPROTO_TCP:
if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
- if (!tcf_csum_ipv4_tcp(skb, iph, iph->ihl * 4,
+ if (!tcf_csum_ipv4_tcp(skb, iph->ihl * 4,
ntohs(iph->tot_len)))
goto fail;
break;
case IPPROTO_UDP:
if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
- if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+ if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
ntohs(iph->tot_len), 0))
goto fail;
break;
case IPPROTO_UDPLITE:
if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
- if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4,
+ if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
ntohs(iph->tot_len), 1))
goto fail;
break;
@@ -377,7 +387,7 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
goto fail;
- ip_send_check(iph);
+ ip_send_check(ip_hdr(skb));
}
return 1;
@@ -456,6 +466,7 @@ static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
ixhl = ipv6_optlen(ip6xh);
if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
goto fail;
+ ip6xh = (void *)(skb_network_header(skb) + hl);
if ((nexthdr == NEXTHDR_HOP) &&
!(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
goto fail;
@@ -464,25 +475,25 @@ static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
break;
case IPPROTO_ICMPV6:
if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
- if (!tcf_csum_ipv6_icmp(skb, ip6h,
+ if (!tcf_csum_ipv6_icmp(skb,
hl, pl + sizeof(*ip6h)))
goto fail;
goto done;
case IPPROTO_TCP:
if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
- if (!tcf_csum_ipv6_tcp(skb, ip6h,
+ if (!tcf_csum_ipv6_tcp(skb,
hl, pl + sizeof(*ip6h)))
goto fail;
goto done;
case IPPROTO_UDP:
if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
- if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+ if (!tcf_csum_ipv6_udp(skb, hl,
pl + sizeof(*ip6h), 0))
goto fail;
goto done;
case IPPROTO_UDPLITE:
if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
- if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
+ if (!tcf_csum_ipv6_udp(skb, hl,
pl + sizeof(*ip6h), 1))
goto fail;
goto done;
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index e0f6de64afec..60d88b6b9560 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -8,7 +8,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Copyright: Jamal Hadi Salim (2002-4)
+ * Copyright: Jamal Hadi Salim (2002-13)
*/
#include <linux/types.h>
@@ -303,17 +303,44 @@ static struct tc_action_ops act_ipt_ops = {
.walk = tcf_generic_walker
};
-MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
+static struct tc_action_ops act_xt_ops = {
+ .kind = "xt",
+ .hinfo = &ipt_hash_info,
+ .type = TCA_ACT_IPT,
+ .capab = TCA_CAP_NONE,
+ .owner = THIS_MODULE,
+ .act = tcf_ipt,
+ .dump = tcf_ipt_dump,
+ .cleanup = tcf_ipt_cleanup,
+ .lookup = tcf_hash_search,
+ .init = tcf_ipt_init,
+ .walk = tcf_generic_walker
+};
+
+MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
MODULE_DESCRIPTION("Iptables target actions");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("act_xt");
static int __init ipt_init_module(void)
{
- return tcf_register_action(&act_ipt_ops);
+ int ret1, ret2;
+ ret1 = tcf_register_action(&act_xt_ops);
+ if (ret1 < 0)
+ printk("Failed to load xt action\n");
+ ret2 = tcf_register_action(&act_ipt_ops);
+ if (ret2 < 0)
+ printk("Failed to load ipt action\n");
+
+ if (ret1 < 0 && ret2 < 0)
+ return ret1;
+ else
+ return 0;
}
static void __exit ipt_cleanup_module(void)
{
+ tcf_unregister_action(&act_xt_ops);
tcf_unregister_action(&act_ipt_ops);
}
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 964f5e4f4b8a..8e118af90973 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -22,7 +22,6 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
-#include <linux/netlink.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
@@ -118,7 +117,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
/* Add/change/delete/get a filter node */
-static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
+static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n)
{
struct net *net = sock_net(skb->sk);
struct nlattr *tca[TCA_MAX + 1];
@@ -141,7 +140,12 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
if ((n->nlmsg_type != RTM_GETTFILTER) && !capable(CAP_NET_ADMIN))
return -EPERM;
+
replay:
+ err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL);
+ if (err < 0)
+ return err;
+
t = nlmsg_data(n);
protocol = TC_H_MIN(t->tcm_info);
prio = TC_H_MAJ(t->tcm_info);
@@ -164,10 +168,6 @@ replay:
if (dev == NULL)
return -ENODEV;
- err = nlmsg_parse(n, sizeof(*t), tca, TCA_MAX, NULL);
- if (err < 0)
- return err;
-
/* Find qdisc */
if (!parent) {
q = dev->qdisc;
@@ -427,7 +427,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
const struct Qdisc_class_ops *cops;
struct tcf_dump_args arg;
- if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
+ if (nlmsg_len(cb->nlh) < sizeof(*tcm))
return skb->len;
dev = __dev_get_by_index(net, tcm->tcm_ifindex);
if (!dev)
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index aa36a8c8b33b..7881e2fccbc2 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -393,7 +393,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
return -EOPNOTSUPP;
if ((keymask & (FLOW_KEY_SKUID|FLOW_KEY_SKGID)) &&
- sk_user_ns(NETLINK_CB(in_skb).ssk) != &init_user_ns)
+ sk_user_ns(NETLINK_CB(in_skb).sk) != &init_user_ns)
return -EOPNOTSUPP;
}
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index 1135d8227f9b..9b97172db84a 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -204,7 +204,6 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
if (err < 0)
return err;
- err = -EINVAL;
if (tb[TCA_FW_CLASSID]) {
f->res.classid = nla_get_u32(tb[TCA_FW_CLASSID]);
tcf_bind_filter(tp, &f->res, base);
@@ -218,6 +217,7 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
}
#endif /* CONFIG_NET_CLS_IND */
+ err = -EINVAL;
if (tb[TCA_FW_MASK]) {
mask = nla_get_u32(tb[TCA_FW_MASK]);
if (mask != head->mask)
diff --git a/net/sched/em_ipset.c b/net/sched/em_ipset.c
index 3130320997e2..938b7cbf5627 100644
--- a/net/sched/em_ipset.c
+++ b/net/sched/em_ipset.c
@@ -83,7 +83,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
opt.dim = set->dim;
opt.flags = set->flags;
opt.cmdflags = 0;
- opt.timeout = ~0u;
+ opt.ext.timeout = ~0u;
network_offset = skb_network_offset(skb);
skb_pull(skb, network_offset);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index c297e2a8e2a1..2b935e7cfe7b 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -971,13 +971,13 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
* Delete/get qdisc.
*/
-static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
+static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
{
struct net *net = sock_net(skb->sk);
struct tcmsg *tcm = nlmsg_data(n);
struct nlattr *tca[TCA_MAX + 1];
struct net_device *dev;
- u32 clid = tcm->tcm_parent;
+ u32 clid;
struct Qdisc *q = NULL;
struct Qdisc *p = NULL;
int err;
@@ -985,14 +985,15 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
if ((n->nlmsg_type != RTM_GETQDISC) && !capable(CAP_NET_ADMIN))
return -EPERM;
- dev = __dev_get_by_index(net, tcm->tcm_ifindex);
- if (!dev)
- return -ENODEV;
-
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
if (err < 0)
return err;
+ dev = __dev_get_by_index(net, tcm->tcm_ifindex);
+ if (!dev)
+ return -ENODEV;
+
+ clid = tcm->tcm_parent;
if (clid) {
if (clid != TC_H_ROOT) {
if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) {
@@ -1038,7 +1039,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
* Create/change qdisc.
*/
-static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
+static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n)
{
struct net *net = sock_net(skb->sk);
struct tcmsg *tcm;
@@ -1053,6 +1054,10 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
replay:
/* Reinit, just in case something touches this. */
+ err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
+ if (err < 0)
+ return err;
+
tcm = nlmsg_data(n);
clid = tcm->tcm_parent;
q = p = NULL;
@@ -1061,9 +1066,6 @@ replay:
if (!dev)
return -ENODEV;
- err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
- if (err < 0)
- return err;
if (clid) {
if (clid != TC_H_ROOT) {
@@ -1372,7 +1374,7 @@ done:
-static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
+static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n)
{
struct net *net = sock_net(skb->sk);
struct tcmsg *tcm = nlmsg_data(n);
@@ -1382,22 +1384,22 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
const struct Qdisc_class_ops *cops;
unsigned long cl = 0;
unsigned long new_cl;
- u32 portid = tcm->tcm_parent;
- u32 clid = tcm->tcm_handle;
- u32 qid = TC_H_MAJ(clid);
+ u32 portid;
+ u32 clid;
+ u32 qid;
int err;
if ((n->nlmsg_type != RTM_GETTCLASS) && !capable(CAP_NET_ADMIN))
return -EPERM;
- dev = __dev_get_by_index(net, tcm->tcm_ifindex);
- if (!dev)
- return -ENODEV;
-
err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
if (err < 0)
return err;
+ dev = __dev_get_by_index(net, tcm->tcm_ifindex);
+ if (!dev)
+ return -ENODEV;
+
/*
parent == TC_H_UNSPEC - unspecified parent.
parent == TC_H_ROOT - class is root, which has no parent.
@@ -1413,6 +1415,10 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
/* Step 1. Determine qdisc handle X:0 */
+ portid = tcm->tcm_parent;
+ clid = tcm->tcm_handle;
+ qid = TC_H_MAJ(clid);
+
if (portid != TC_H_ROOT) {
u32 qid1 = TC_H_MAJ(portid);
@@ -1636,7 +1642,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
int t, s_t;
- if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
+ if (nlmsg_len(cb->nlh) < sizeof(*tcm))
return 0;
dev = dev_get_by_index(net, tcm->tcm_ifindex);
if (!dev)
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 13aa47aa2ffb..1bc210ffcba2 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -962,8 +962,11 @@ cbq_dequeue(struct Qdisc *sch)
cbq_update(q);
if ((incr -= incr2) < 0)
incr = 0;
+ q->now += incr;
+ } else {
+ if (now > q->now)
+ q->now = now;
}
- q->now += incr;
q->now_rt = now;
for (;;) {
diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c
index cc37dd52ecf9..ef53ab8d0aae 100644
--- a/net/sched/sch_choke.c
+++ b/net/sched/sch_choke.c
@@ -80,7 +80,7 @@ struct choke_sched_data {
/* deliver a random number between 0 and N - 1 */
static u32 random_N(unsigned int N)
{
- return reciprocal_divide(random32(), N);
+ return reciprocal_divide(prandom_u32(), N);
}
/* number of elements in queue including holes */
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 4e606fcb2534..55786283a3df 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -195,7 +195,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
flow->deficit = q->quantum;
flow->dropped = 0;
}
- if (++sch->q.qlen < sch->limit)
+ if (++sch->q.qlen <= sch->limit)
return NET_XMIT_SUCCESS;
q->drop_overlimit++;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index ffad48109a22..eac7e0ee23c1 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -904,7 +904,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r, u32 rate)
u64 mult;
int shift;
- r->rate_bps = rate << 3;
+ r->rate_bps = (u64)rate << 3;
r->shift = 0;
r->mult = 1;
/*
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 571f1d211f4d..79b1876b6cd2 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -981,6 +981,7 @@ static const struct nla_policy htb_policy[TCA_HTB_MAX + 1] = {
[TCA_HTB_INIT] = { .len = sizeof(struct tc_htb_glob) },
[TCA_HTB_CTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
[TCA_HTB_RTAB] = { .type = NLA_BINARY, .len = TC_RTAB_SIZE },
+ [TCA_HTB_DIRECT_QLEN] = { .type = NLA_U32 },
};
static void htb_work_func(struct work_struct *work)
@@ -994,7 +995,7 @@ static void htb_work_func(struct work_struct *work)
static int htb_init(struct Qdisc *sch, struct nlattr *opt)
{
struct htb_sched *q = qdisc_priv(sch);
- struct nlattr *tb[TCA_HTB_INIT + 1];
+ struct nlattr *tb[TCA_HTB_MAX + 1];
struct tc_htb_glob *gopt;
int err;
int i;
@@ -1002,20 +1003,16 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
if (!opt)
return -EINVAL;
- err = nla_parse_nested(tb, TCA_HTB_INIT, opt, htb_policy);
+ err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy);
if (err < 0)
return err;
- if (tb[TCA_HTB_INIT] == NULL) {
- pr_err("HTB: hey probably you have bad tc tool ?\n");
+ if (!tb[TCA_HTB_INIT])
return -EINVAL;
- }
+
gopt = nla_data(tb[TCA_HTB_INIT]);
- if (gopt->version != HTB_VER >> 16) {
- pr_err("HTB: need tc/htb version %d (minor is %d), you have %d\n",
- HTB_VER >> 16, HTB_VER & 0xffff, gopt->version);
+ if (gopt->version != HTB_VER >> 16)
return -EINVAL;
- }
err = qdisc_class_hash_init(&q->clhash);
if (err < 0)
@@ -1027,10 +1024,13 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
INIT_WORK(&q->work, htb_work_func);
skb_queue_head_init(&q->direct_queue);
- q->direct_qlen = qdisc_dev(sch)->tx_queue_len;
- if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
- q->direct_qlen = 2;
-
+ if (tb[TCA_HTB_DIRECT_QLEN])
+ q->direct_qlen = nla_get_u32(tb[TCA_HTB_DIRECT_QLEN]);
+ else {
+ q->direct_qlen = qdisc_dev(sch)->tx_queue_len;
+ if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
+ q->direct_qlen = 2;
+ }
if ((q->rate2quantum = gopt->rate2quantum) < 1)
q->rate2quantum = 1;
q->defcls = gopt->defcls;
@@ -1056,7 +1056,8 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
nest = nla_nest_start(skb, TCA_OPTIONS);
if (nest == NULL)
goto nla_put_failure;
- if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt))
+ if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt) ||
+ nla_put_u32(skb, TCA_HTB_DIRECT_QLEN, q->direct_qlen))
goto nla_put_failure;
nla_nest_end(skb, nest);
@@ -1311,7 +1312,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
struct htb_sched *q = qdisc_priv(sch);
struct htb_class *cl = (struct htb_class *)*arg, *parent;
struct nlattr *opt = tca[TCA_OPTIONS];
- struct nlattr *tb[__TCA_HTB_MAX];
+ struct nlattr *tb[TCA_HTB_MAX + 1];
struct tc_htb_opt *hopt;
/* extract all subattrs from opt attr */
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index d2709e2b7be6..91cfd8f94a19 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -66,13 +66,6 @@ static void sctp_assoc_bh_rcv(struct work_struct *work);
static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
-/* Keep track of the new idr low so that we don't re-use association id
- * numbers too fast. It is protected by they idr spin lock is in the
- * range of 1 - INT_MAX.
- */
-static u32 idr_low = 1;
-
-
/* 1st Level Abstractions. */
/* Initialize a new association from provided memory. */
@@ -104,8 +97,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
/* Initialize the object handling fields. */
atomic_set(&asoc->base.refcnt, 1);
- asoc->base.dead = 0;
- asoc->base.malloced = 0;
+ asoc->base.dead = false;
/* Initialize the bind addr area. */
sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
@@ -371,7 +363,6 @@ struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
if (!sctp_association_init(asoc, ep, sk, scope, gfp))
goto fail_init;
- asoc->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(assoc);
SCTP_DEBUG_PRINTK("Created asoc %p\n", asoc);
@@ -409,7 +400,7 @@ void sctp_association_free(struct sctp_association *asoc)
/* Mark as dead, so other users can know this structure is
* going away.
*/
- asoc->base.dead = 1;
+ asoc->base.dead = true;
/* Dispose of any data lying around in the outqueue. */
sctp_outq_free(&asoc->outqueue);
@@ -484,10 +475,8 @@ static void sctp_association_destroy(struct sctp_association *asoc)
WARN_ON(atomic_read(&asoc->rmem_alloc));
- if (asoc->base.malloced) {
- kfree(asoc);
- SCTP_DBG_OBJCNT_DEC(assoc);
- }
+ kfree(asoc);
+ SCTP_DBG_OBJCNT_DEC(assoc);
}
/* Change the primary destination address for the peer. */
@@ -1601,13 +1590,8 @@ int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
if (preload)
idr_preload(gfp);
spin_lock_bh(&sctp_assocs_id_lock);
- /* 0 is not a valid id, idr_low is always >= 1 */
- ret = idr_alloc(&sctp_assocs_id, asoc, idr_low, 0, GFP_NOWAIT);
- if (ret >= 0) {
- idr_low = ret + 1;
- if (idr_low == INT_MAX)
- idr_low = 1;
- }
+ /* 0 is not a valid assoc_id, must be >= 1 */
+ ret = idr_alloc_cyclic(&sctp_assocs_id, asoc, 1, 0, GFP_NOWAIT);
spin_unlock_bh(&sctp_assocs_id_lock);
if (preload)
idr_preload_end();
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index d886b3bf84f5..41145fe31813 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -131,8 +131,6 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest,
*/
void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
{
- bp->malloced = 0;
-
INIT_LIST_HEAD(&bp->address_list);
bp->port = port;
}
@@ -155,11 +153,6 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp)
{
/* Empty the bind address list. */
sctp_bind_addr_clean(bp);
-
- if (bp->malloced) {
- kfree(bp);
- SCTP_DBG_OBJCNT_DEC(bind_addr);
- }
}
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 12ed45dbe75d..5fbd7bc6bb11 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -121,8 +121,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Initialize the basic object fields. */
atomic_set(&ep->base.refcnt, 1);
- ep->base.dead = 0;
- ep->base.malloced = 1;
+ ep->base.dead = false;
/* Create an input queue. */
sctp_inq_init(&ep->base.inqueue);
@@ -198,7 +197,7 @@ struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, gfp_t gfp)
goto fail;
if (!sctp_endpoint_init(ep, sk, gfp))
goto fail_init;
- ep->base.malloced = 1;
+
SCTP_DBG_OBJCNT_INC(ep);
return ep;
@@ -234,7 +233,7 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
*/
void sctp_endpoint_free(struct sctp_endpoint *ep)
{
- ep->base.dead = 1;
+ ep->base.dead = true;
ep->base.sk->sk_state = SCTP_SS_CLOSED;
@@ -279,11 +278,8 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
if (ep->base.sk)
sock_put(ep->base.sk);
- /* Finally, free up our memory. */
- if (ep->base.malloced) {
- kfree(ep);
- SCTP_DBG_OBJCNT_DEC(ep);
- }
+ kfree(ep);
+ SCTP_DBG_OBJCNT_DEC(ep);
}
/* Hold a reference to an endpoint. */
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 2d5ad280de38..3221d073448c 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -58,8 +58,6 @@ void sctp_inq_init(struct sctp_inq *queue)
/* Create a task for delivering data. */
INIT_WORK(&queue->immediate, NULL);
-
- queue->malloced = 0;
}
/* Release the memory associated with an SCTP inqueue. */
@@ -80,11 +78,6 @@ void sctp_inq_free(struct sctp_inq *queue)
sctp_chunk_free(queue->in_progress);
queue->in_progress = NULL;
}
-
- if (queue->malloced) {
- /* Dump the master memory segment. */
- kfree(queue);
- }
}
/* Put a new packet in an SCTP inqueue.
diff --git a/net/sctp/output.c b/net/sctp/output.c
index f5200a2ad852..bbef4a7a9b56 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -136,7 +136,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->overhead = overhead;
sctp_packet_reset(packet);
packet->vtag = 0;
- packet->malloced = 0;
+
return packet;
}
@@ -151,9 +151,6 @@ void sctp_packet_free(struct sctp_packet *packet)
list_del_init(&chunk->list);
sctp_chunk_free(chunk);
}
-
- if (packet->malloced)
- kfree(packet);
}
/* This routine tries to append the chunk to the offered packet. If adding
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 01dca753db16..32a4625fef77 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -217,8 +217,6 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
q->outstanding_bytes = 0;
q->empty = 1;
q->cork = 0;
-
- q->malloced = 0;
q->out_qlen = 0;
}
@@ -295,10 +293,6 @@ void sctp_outq_free(struct sctp_outq *q)
{
/* Throw away leftover chunks. */
__sctp_outq_teardown(q);
-
- /* If we were kmalloc()'d, free the memory. */
- if (q->malloced)
- kfree(q);
}
/* Put a new chunk in an sctp_outq. */
@@ -707,11 +701,10 @@ redo:
/* Cork the outqueue so queued chunks are really queued. */
int sctp_outq_uncork(struct sctp_outq *q)
{
- int error = 0;
if (q->cork)
q->cork = 0;
- error = sctp_outq_flush(q, 0);
- return error;
+
+ return sctp_outq_flush(q, 0);
}
diff --git a/net/sctp/probe.c b/net/sctp/probe.c
index ad0dba870341..e62c22535be4 100644
--- a/net/sctp/probe.c
+++ b/net/sctp/probe.c
@@ -63,7 +63,7 @@ static struct {
struct timespec tstart;
} sctpw;
-static void printl(const char *fmt, ...)
+static __printf(1, 2) void printl(const char *fmt, ...)
{
va_list args;
int len;
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index ab3bba8cb0a8..4e45ee35d0db 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -295,7 +295,8 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT "
"ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
"RPORT LADDRS <-> RADDRS "
- "HBINT INS OUTS MAXRT T1X T2X RTXC\n");
+ "HBINT INS OUTS MAXRT T1X T2X RTXC "
+ "wmema wmemq sndbuf rcvbuf\n");
return (void *)pos;
}
@@ -349,11 +350,16 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "<-> ");
sctp_seq_dump_remote_addrs(seq, assoc);
- seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ",
+ seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
+ "%8d %8d %8d %8d",
assoc->hbinterval, assoc->c.sinit_max_instreams,
assoc->c.sinit_num_ostreams, assoc->max_retrans,
assoc->init_retries, assoc->shutdown_retries,
- assoc->rtx_data_chunks);
+ assoc->rtx_data_chunks,
+ atomic_read(&sk->sk_wmem_alloc),
+ sk->sk_wmem_queued,
+ sk->sk_sndbuf,
+ sk->sk_rcvbuf);
seq_printf(seq, "\n");
}
read_unlock(&head->lock);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 1c2e46cb9191..eaee00c61139 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1403,7 +1403,7 @@ SCTP_STATIC __init int sctp_init(void)
/* Allocate and initialize the endpoint hash table. */
sctp_ep_hashsize = 64;
- sctp_ep_hashtable = (struct sctp_hashbucket *)
+ sctp_ep_hashtable =
kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
if (!sctp_ep_hashtable) {
pr_err("Failed endpoint_hash alloc\n");
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b9070736b8d9..f631c5ff4dbf 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1119,9 +1119,10 @@ static int __sctp_connect(struct sock* sk,
/* Make sure the destination port is correctly set
* in all addresses.
*/
- if (asoc && asoc->peer.port && asoc->peer.port != port)
+ if (asoc && asoc->peer.port && asoc->peer.port != port) {
+ err = -EINVAL;
goto out_free;
-
+ }
/* Check if there already is a matching association on the
* endpoint (other than the one created here).
@@ -6185,7 +6186,8 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
/* Is there any exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c
index 825ea94415b3..da8603523808 100644
--- a/net/sctp/ssnmap.c
+++ b/net/sctp/ssnmap.c
@@ -74,7 +74,6 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
if (!sctp_ssnmap_init(retval, in, out))
goto fail_map;
- retval->malloced = 1;
SCTP_DBG_OBJCNT_INC(ssnmap);
return retval;
@@ -118,14 +117,16 @@ void sctp_ssnmap_clear(struct sctp_ssnmap *map)
/* Dispose of a ssnmap. */
void sctp_ssnmap_free(struct sctp_ssnmap *map)
{
- if (map && map->malloced) {
- int size;
-
- size = sctp_ssnmap_size(map->in.len, map->out.len);
- if (size <= KMALLOC_MAX_SIZE)
- kfree(map);
- else
- free_pages((unsigned long)map, get_order(size));
- SCTP_DBG_OBJCNT_DEC(ssnmap);
- }
+ int size;
+
+ if (unlikely(!map))
+ return;
+
+ size = sctp_ssnmap_size(map->in.len, map->out.len);
+ if (size <= KMALLOC_MAX_SIZE)
+ kfree(map);
+ else
+ free_pages((unsigned long)map, get_order(size));
+
+ SCTP_DBG_OBJCNT_DEC(ssnmap);
}
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index fafd2a461ba0..098f1d5f769e 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -123,7 +123,6 @@ struct sctp_transport *sctp_transport_new(struct net *net,
if (!sctp_transport_init(net, transport, addr, gfp))
goto fail_init;
- transport->malloced = 1;
SCTP_DBG_OBJCNT_INC(transport);
return transport;
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 0fd5b3d2df03..04e3d470f877 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -68,7 +68,6 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
skb_queue_head_init(&ulpq->reasm);
skb_queue_head_init(&ulpq->lobby);
ulpq->pd_mode = 0;
- ulpq->malloced = 0;
return ulpq;
}
@@ -96,8 +95,6 @@ void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
void sctp_ulpq_free(struct sctp_ulpq *ulpq)
{
sctp_ulpq_flush(ulpq);
- if (ulpq->malloced)
- kfree(ulpq);
}
/* Process an incoming DATA chunk. */
diff --git a/net/socket.c b/net/socket.c
index 9663df63e3d1..b416093997da 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -600,7 +600,7 @@ void sock_release(struct socket *sock)
}
EXPORT_SYMBOL(sock_release);
-int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
+void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
{
*tx_flags = 0;
if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
@@ -609,7 +609,6 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
*tx_flags |= SKBTX_SW_TSTAMP;
if (sock_flag(sk, SOCK_WIFI_STATUS))
*tx_flags |= SKBTX_WIFI_STATUS;
- return 0;
}
EXPORT_SYMBOL(sock_tx_timestamp);
@@ -682,16 +681,6 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
}
EXPORT_SYMBOL(kernel_sendmsg);
-static int ktime2ts(ktime_t kt, struct timespec *ts)
-{
- if (kt.tv64) {
- *ts = ktime_to_timespec(kt);
- return 1;
- } else {
- return 0;
- }
-}
-
/*
* called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
*/
@@ -724,17 +713,15 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
memset(ts, 0, sizeof(ts));
- if (skb->tstamp.tv64 &&
- sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) {
- skb_get_timestampns(skb, ts + 0);
+ if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) &&
+ ktime_to_timespec_cond(skb->tstamp, ts + 0))
empty = 0;
- }
if (shhwtstamps) {
if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) &&
- ktime2ts(shhwtstamps->syststamp, ts + 1))
+ ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1))
empty = 0;
if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) &&
- ktime2ts(shhwtstamps->hwtstamp, ts + 2))
+ ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2))
empty = 0;
}
if (!empty)
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index 516fe2caac2c..241b54f30204 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -3,6 +3,7 @@ config SUNRPC
config SUNRPC_GSS
tristate
+ select OID_REGISTRY
config SUNRPC_BACKCHANNEL
bool
@@ -24,7 +25,6 @@ config SUNRPC_XPRT_RDMA
config SUNRPC_SWAP
bool
depends on SUNRPC
- select NETVM
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism"
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index f5294047df77..ed2fdd210c0b 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size");
static u32
pseudoflavor_to_flavor(u32 flavor) {
- if (flavor >= RPC_AUTH_MAXFLAVOR)
+ if (flavor > RPC_AUTH_MAXFLAVOR)
return RPC_AUTH_GSS;
return flavor;
}
@@ -124,6 +124,79 @@ rpcauth_unregister(const struct rpc_authops *ops)
EXPORT_SYMBOL_GPL(rpcauth_unregister);
/**
+ * rpcauth_get_pseudoflavor - check if security flavor is supported
+ * @flavor: a security flavor
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Verifies that an appropriate kernel module is available or already loaded.
+ * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
+ * not supported locally.
+ */
+rpc_authflavor_t
+rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
+{
+ const struct rpc_authops *ops;
+ rpc_authflavor_t pseudoflavor;
+
+ ops = auth_flavors[flavor];
+ if (ops == NULL)
+ request_module("rpc-auth-%u", flavor);
+ spin_lock(&rpc_authflavor_lock);
+ ops = auth_flavors[flavor];
+ if (ops == NULL || !try_module_get(ops->owner)) {
+ spin_unlock(&rpc_authflavor_lock);
+ return RPC_AUTH_MAXFLAVOR;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+
+ pseudoflavor = flavor;
+ if (ops->info2flavor != NULL)
+ pseudoflavor = ops->info2flavor(info);
+
+ module_put(ops->owner);
+ return pseudoflavor;
+}
+EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
+
+/**
+ * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor
+ * @pseudoflavor: GSS pseudoflavor to match
+ * @info: rpcsec_gss_info structure to fill in
+ *
+ * Returns zero and fills in "info" if pseudoflavor matches a
+ * supported mechanism.
+ */
+int
+rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info)
+{
+ rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor);
+ const struct rpc_authops *ops;
+ int result;
+
+ if (flavor >= RPC_AUTH_MAXFLAVOR)
+ return -EINVAL;
+
+ ops = auth_flavors[flavor];
+ if (ops == NULL)
+ request_module("rpc-auth-%u", flavor);
+ spin_lock(&rpc_authflavor_lock);
+ ops = auth_flavors[flavor];
+ if (ops == NULL || !try_module_get(ops->owner)) {
+ spin_unlock(&rpc_authflavor_lock);
+ return -ENOENT;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+
+ result = -ENOENT;
+ if (ops->flavor2info != NULL)
+ result = ops->flavor2info(pseudoflavor, info);
+
+ module_put(ops->owner);
+ return result;
+}
+EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo);
+
+/**
* rpcauth_list_flavors - discover registered flavors and pseudoflavors
* @array: array to fill in
* @size: size of "array"
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 5257d2982ba5..51415b07174e 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = {
.pipes_create = gss_pipes_dentries_create,
.pipes_destroy = gss_pipes_dentries_destroy,
.list_pseudoflavors = gss_mech_list_pseudoflavors,
+ .info2flavor = gss_mech_info2flavor,
+ .flavor2info = gss_mech_flavor2info,
};
static const struct rpc_credops gss_credops = {
@@ -1733,6 +1735,7 @@ static void __exit exit_rpcsec_gss(void)
rcu_barrier(); /* Wait for completion of call_rcu()'s */
}
+MODULE_ALIAS("rpc-auth-6");
MODULE_LICENSE("GPL");
module_param_named(expired_cred_retry_delay,
gss_expired_cred_retry_delay,
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index d3611f11a8df..33255ff889c0 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -729,16 +729,19 @@ static const struct gss_api_ops gss_kerberos_ops = {
static struct pf_desc gss_kerberos_pfs[] = {
[0] = {
.pseudoflavor = RPC_AUTH_GSS_KRB5,
+ .qop = GSS_C_QOP_DEFAULT,
.service = RPC_GSS_SVC_NONE,
.name = "krb5",
},
[1] = {
.pseudoflavor = RPC_AUTH_GSS_KRB5I,
+ .qop = GSS_C_QOP_DEFAULT,
.service = RPC_GSS_SVC_INTEGRITY,
.name = "krb5i",
},
[2] = {
.pseudoflavor = RPC_AUTH_GSS_KRB5P,
+ .qop = GSS_C_QOP_DEFAULT,
.service = RPC_GSS_SVC_PRIVACY,
.name = "krb5p",
},
@@ -750,11 +753,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p");
MODULE_ALIAS("rpc-auth-gss-390003");
MODULE_ALIAS("rpc-auth-gss-390004");
MODULE_ALIAS("rpc-auth-gss-390005");
+MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2");
static struct gss_api_mech gss_kerberos_mech = {
.gm_name = "krb5",
.gm_owner = THIS_MODULE,
- .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
+ .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" },
.gm_ops = &gss_kerberos_ops,
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
.gm_pfs = gss_kerberos_pfs,
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 88edec929d73..1da52d1406fc 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -130,8 +130,8 @@ gss_krb5_make_confounder(char *p, u32 conflen)
/* initialize to random value */
if (i == 0) {
- i = random32();
- i = (i << 32) | random32();
+ i = prandom_u32();
+ i = (i << 32) | prandom_u32();
}
switch (conflen) {
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index f0f4eee63a35..79881d6e68a1 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -36,6 +36,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/oid_registry.h>
#include <linux/sunrpc/msg_prot.h>
#include <linux/sunrpc/gss_asn1.h>
#include <linux/sunrpc/auth_gss.h>
@@ -102,8 +103,13 @@ out:
return status;
}
-int
-gss_mech_register(struct gss_api_mech *gm)
+/**
+ * gss_mech_register - register a GSS mechanism
+ * @gm: GSS mechanism handle
+ *
+ * Returns zero if successful, or a negative errno.
+ */
+int gss_mech_register(struct gss_api_mech *gm)
{
int status;
@@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm)
dprintk("RPC: registered gss mechanism %s\n", gm->gm_name);
return 0;
}
-
EXPORT_SYMBOL_GPL(gss_mech_register);
-void
-gss_mech_unregister(struct gss_api_mech *gm)
+/**
+ * gss_mech_unregister - release a GSS mechanism
+ * @gm: GSS mechanism handle
+ *
+ */
+void gss_mech_unregister(struct gss_api_mech *gm)
{
spin_lock(&registered_mechs_lock);
list_del(&gm->gm_list);
@@ -128,18 +137,14 @@ gss_mech_unregister(struct gss_api_mech *gm)
dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name);
gss_mech_free(gm);
}
-
EXPORT_SYMBOL_GPL(gss_mech_unregister);
-struct gss_api_mech *
-gss_mech_get(struct gss_api_mech *gm)
+static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm)
{
__module_get(gm->gm_owner);
return gm;
}
-EXPORT_SYMBOL_GPL(gss_mech_get);
-
static struct gss_api_mech *
_gss_mech_get_by_name(const char *name)
{
@@ -169,12 +174,16 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)
}
return gm;
}
-EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
-struct gss_api_mech *
-gss_mech_get_by_OID(struct xdr_netobj *obj)
+static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
{
struct gss_api_mech *pos, *gm = NULL;
+ char buf[32];
+
+ if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
+ return NULL;
+ dprintk("RPC: %s(%s)\n", __func__, buf);
+ request_module("rpc-auth-gss-%s", buf);
spin_lock(&registered_mechs_lock);
list_for_each_entry(pos, &registered_mechs, gm_list) {
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
}
spin_unlock(&registered_mechs_lock);
return gm;
-
}
-EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
-
static inline int
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
{
@@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
return gm;
}
-EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor);
-
/**
* gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors
* @array: array to fill in
@@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size)
return i;
}
-u32
-gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
+/**
+ * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor
+ * @gm: GSS mechanism handle
+ * @qop: GSS quality-of-protection value
+ * @service: GSS service value
+ *
+ * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found.
+ */
+rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop,
+ u32 service)
{
int i;
for (i = 0; i < gm->gm_pf_num; i++) {
- if (gm->gm_pfs[i].service == service) {
+ if (gm->gm_pfs[i].qop == qop &&
+ gm->gm_pfs[i].service == service) {
return gm->gm_pfs[i].pseudoflavor;
}
}
- return RPC_AUTH_MAXFLAVOR; /* illegal value */
+ return RPC_AUTH_MAXFLAVOR;
+}
+
+/**
+ * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
+ * @info: a GSS mech OID, quality of protection, and service value
+ *
+ * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
+ * not supported.
+ */
+rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
+{
+ rpc_authflavor_t pseudoflavor;
+ struct gss_api_mech *gm;
+
+ gm = gss_mech_get_by_OID(&info->oid);
+ if (gm == NULL)
+ return RPC_AUTH_MAXFLAVOR;
+
+ pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service);
+
+ gss_mech_put(gm);
+ return pseudoflavor;
+}
+
+/**
+ * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor
+ * @pseudoflavor: GSS pseudoflavor to match
+ * @info: rpcsec_gss_info structure to fill in
+ *
+ * Returns zero and fills in "info" if pseudoflavor matches a
+ * supported mechanism. Otherwise a negative errno is returned.
+ */
+int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor,
+ struct rpcsec_gss_info *info)
+{
+ struct gss_api_mech *gm;
+ int i;
+
+ gm = gss_mech_get_by_pseudoflavor(pseudoflavor);
+ if (gm == NULL)
+ return -ENOENT;
+
+ for (i = 0; i < gm->gm_pf_num; i++) {
+ if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) {
+ memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len);
+ info->oid.len = gm->gm_oid.len;
+ info->qop = gm->gm_pfs[i].qop;
+ info->service = gm->gm_pfs[i].service;
+ gss_mech_put(gm);
+ return 0;
+ }
+ }
+
+ gss_mech_put(gm);
+ return -ENOENT;
}
-EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
u32
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
@@ -294,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
return 0;
}
-EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service);
-
char *
gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
{
@@ -308,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service)
return NULL;
}
-EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name);
-
void
gss_mech_put(struct gss_api_mech * gm)
{
@@ -317,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm)
module_put(gm->gm_owner);
}
-EXPORT_SYMBOL_GPL(gss_mech_put);
-
/* The mech could probably be determined from the token instead, but it's just
* as easy for now to pass it in. */
int
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 5ead60550895..c3ba570222dc 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -1220,7 +1220,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
svcdata->rsci = rsci;
cache_get(&rsci->h);
rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
- rsci->mechctx->mech_type, gc->gc_svc);
+ rsci->mechctx->mech_type,
+ GSS_C_QOP_DEFAULT,
+ gc->gc_svc);
ret = SVC_OK;
goto out;
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index d9828b6799a3..f1889be80912 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1208,7 +1208,6 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
* key and content are both parsed by cache
*/
-#define isodigit(c) (isdigit(c) && c <= '7')
int qword_get(char **bpp, char *dest, int bufsize)
{
/* return bytes copied, or -1 on error */
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index dcc446e7fbf6..d259fa966927 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -304,10 +304,8 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
err = rpciod_up();
if (err)
goto out_no_rpciod;
- err = -EINVAL;
- if (!xprt)
- goto out_no_xprt;
+ err = -EINVAL;
if (args->version >= program->nrvers)
goto out_err;
version = program->version[args->version];
@@ -382,10 +380,9 @@ out_no_principal:
out_no_stats:
kfree(clnt);
out_err:
- xprt_put(xprt);
-out_no_xprt:
rpciod_down();
out_no_rpciod:
+ xprt_put(xprt);
return ERR_PTR(err);
}
@@ -414,6 +411,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
};
char servername[48];
+ if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
+ xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
/*
* If the caller chooses not to specify a hostname, whip
* up a string representation of the passed-in address.
@@ -512,7 +511,7 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
new = rpc_new_client(args, xprt);
if (IS_ERR(new)) {
err = PTR_ERR(new);
- goto out_put;
+ goto out_err;
}
atomic_inc(&clnt->cl_count);
@@ -525,8 +524,6 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
new->cl_chatty = clnt->cl_chatty;
return new;
-out_put:
- xprt_put(xprt);
out_err:
dprintk("RPC: %s: returned error %d\n", __func__, err);
return ERR_PTR(err);
@@ -1306,6 +1303,8 @@ call_reserve(struct rpc_task *task)
xprt_reserve(task);
}
+static void call_retry_reserve(struct rpc_task *task);
+
/*
* 1b. Grok the result of xprt_reserve()
*/
@@ -1347,7 +1346,7 @@ call_reserveresult(struct rpc_task *task)
case -ENOMEM:
rpc_delay(task, HZ >> 2);
case -EAGAIN: /* woken up; retry */
- task->tk_action = call_reserve;
+ task->tk_action = call_retry_reserve;
return;
case -EIO: /* probably a shutdown */
break;
@@ -1360,6 +1359,19 @@ call_reserveresult(struct rpc_task *task)
}
/*
+ * 1c. Retry reserving an RPC call slot
+ */
+static void
+call_retry_reserve(struct rpc_task *task)
+{
+ dprint_status(task);
+
+ task->tk_status = 0;
+ task->tk_action = call_reserveresult;
+ xprt_retry_reserve(task);
+}
+
+/*
* 2. Bind and/or refresh the credentials
*/
static void
@@ -1644,22 +1656,26 @@ call_connect_status(struct rpc_task *task)
dprint_status(task);
- task->tk_status = 0;
- if (status >= 0 || status == -EAGAIN) {
- clnt->cl_stats->netreconn++;
- task->tk_action = call_transmit;
- return;
- }
-
trace_rpc_connect_status(task, status);
switch (status) {
/* if soft mounted, test if we've timed out */
case -ETIMEDOUT:
task->tk_action = call_timeout;
- break;
- default:
- rpc_exit(task, -EIO);
+ return;
+ case -ECONNREFUSED:
+ case -ECONNRESET:
+ case -ENETUNREACH:
+ if (RPC_IS_SOFTCONN(task))
+ break;
+ /* retry with existing socket, after a delay */
+ case 0:
+ case -EAGAIN:
+ task->tk_status = 0;
+ clnt->cl_stats->netreconn++;
+ task->tk_action = call_transmit;
+ return;
}
+ rpc_exit(task, status);
}
/*
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index b7478d5e7ffd..745fca3cfd36 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -948,6 +948,34 @@ void xprt_transmit(struct rpc_task *task)
spin_unlock_bh(&xprt->transport_lock);
}
+static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+ set_bit(XPRT_CONGESTED, &xprt->state);
+ rpc_sleep_on(&xprt->backlog, task, NULL);
+}
+
+static void xprt_wake_up_backlog(struct rpc_xprt *xprt)
+{
+ if (rpc_wake_up_next(&xprt->backlog) == NULL)
+ clear_bit(XPRT_CONGESTED, &xprt->state);
+}
+
+static bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+ bool ret = false;
+
+ if (!test_bit(XPRT_CONGESTED, &xprt->state))
+ goto out;
+ spin_lock(&xprt->reserve_lock);
+ if (test_bit(XPRT_CONGESTED, &xprt->state)) {
+ rpc_sleep_on(&xprt->backlog, task, NULL);
+ ret = true;
+ }
+ spin_unlock(&xprt->reserve_lock);
+out:
+ return ret;
+}
+
static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags)
{
struct rpc_rqst *req = ERR_PTR(-EAGAIN);
@@ -992,7 +1020,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)
task->tk_status = -ENOMEM;
break;
case -EAGAIN:
- rpc_sleep_on(&xprt->backlog, task, NULL);
+ xprt_add_backlog(xprt, task);
dprintk("RPC: waiting for request slot\n");
default:
task->tk_status = -EAGAIN;
@@ -1028,7 +1056,7 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req)
memset(req, 0, sizeof(*req)); /* mark unused */
list_add(&req->rq_list, &xprt->free);
}
- rpc_wake_up_next(&xprt->backlog);
+ xprt_wake_up_backlog(xprt);
spin_unlock(&xprt->reserve_lock);
}
@@ -1092,7 +1120,8 @@ EXPORT_SYMBOL_GPL(xprt_free);
* xprt_reserve - allocate an RPC request slot
* @task: RPC task requesting a slot allocation
*
- * If no more slots are available, place the task on the transport's
+ * If the transport is marked as being congested, or if no more
+ * slots are available, place the task on the transport's
* backlog queue.
*/
void xprt_reserve(struct rpc_task *task)
@@ -1107,6 +1136,32 @@ void xprt_reserve(struct rpc_task *task)
task->tk_status = -EAGAIN;
rcu_read_lock();
xprt = rcu_dereference(task->tk_client->cl_xprt);
+ if (!xprt_throttle_congested(xprt, task))
+ xprt->ops->alloc_slot(xprt, task);
+ rcu_read_unlock();
+}
+
+/**
+ * xprt_retry_reserve - allocate an RPC request slot
+ * @task: RPC task requesting a slot allocation
+ *
+ * If no more slots are available, place the task on the transport's
+ * backlog queue.
+ * Note that the only difference with xprt_reserve is that we now
+ * ignore the value of the XPRT_CONGESTED flag.
+ */
+void xprt_retry_reserve(struct rpc_task *task)
+{
+ struct rpc_xprt *xprt;
+
+ task->tk_status = 0;
+ if (task->tk_rqstp != NULL)
+ return;
+
+ task->tk_timeout = 0;
+ task->tk_status = -EAGAIN;
+ rcu_read_lock();
+ xprt = rcu_dereference(task->tk_client->cl_xprt);
xprt->ops->alloc_slot(xprt, task);
rcu_read_unlock();
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 3d02130828da..9c2825827dec 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2207,10 +2207,6 @@ static void xs_tcp_setup_socket(struct work_struct *work)
*/
xs_tcp_force_close(xprt);
break;
- case -ECONNREFUSED:
- case -ECONNRESET:
- case -ENETUNREACH:
- /* retry with existing socket, after a delay */
case 0:
case -EINPROGRESS:
case -EALREADY:
@@ -2221,6 +2217,10 @@ static void xs_tcp_setup_socket(struct work_struct *work)
/* Happens, for instance, if the user specified a link
* local IPv6 address without a scope-id.
*/
+ case -ECONNREFUSED:
+ case -ECONNRESET:
+ case -ENETUNREACH:
+ /* retry with existing socket, after a delay */
goto out;
}
out_eagain:
@@ -2767,9 +2767,13 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
struct rpc_xprt *xprt;
struct sock_xprt *transport;
struct rpc_xprt *ret;
+ unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries;
+
+ if (args->flags & XPRT_CREATE_INFINITE_SLOTS)
+ max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT;
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
- xprt_max_tcp_slot_table_entries);
+ max_slot_table_size);
if (IS_ERR(xprt))
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
index 4f99600a5fed..c890848f9d56 100644
--- a/net/tipc/Kconfig
+++ b/net/tipc/Kconfig
@@ -31,3 +31,10 @@ config TIPC_PORTS
Setting this to a smaller value saves some memory,
setting it to higher allows for more ports.
+
+config TIPC_MEDIA_IB
+ bool "InfiniBand media type support"
+ depends on TIPC && INFINIBAND_IPOIB
+ help
+ Saying Y here will enable support for running TIPC on
+ IP-over-InfiniBand devices.
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index 6cd55d671d3a..4df8e02d9008 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -9,3 +9,5 @@ tipc-y += addr.o bcast.o bearer.o config.o \
name_distr.o subscr.o name_table.o net.o \
netlink.o node.o node_subscr.o port.o ref.o \
socket.o log.o eth_media.o
+
+tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 2655c9f4ecad..25e159c2feb4 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -620,10 +620,10 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
continue; /* bearer pair doesn't add anything */
if (!tipc_bearer_blocked(p))
- tipc_bearer_send(p, buf, &p->media->bcast_addr);
+ tipc_bearer_send(p, buf, &p->bcast_addr);
else if (s && !tipc_bearer_blocked(s))
/* unable to send on primary bearer */
- tipc_bearer_send(s, buf, &s->media->bcast_addr);
+ tipc_bearer_send(s, buf, &s->bcast_addr);
else
/* unable to send on either bearer */
continue;
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index aa62f93a9127..cb29ef7ba2f0 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -39,7 +39,7 @@
#include "bearer.h"
#include "discover.h"
-#define MAX_ADDR_STR 32
+#define MAX_ADDR_STR 60
static struct tipc_media *media_list[MAX_MEDIA];
static u32 media_count;
@@ -89,9 +89,6 @@ int tipc_register_media(struct tipc_media *m_ptr)
if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME)
goto exit;
- if ((m_ptr->bcast_addr.media_id != m_ptr->type_id) ||
- !m_ptr->bcast_addr.broadcast)
- goto exit;
if (m_ptr->priority > TIPC_MAX_LINK_PRI)
goto exit;
if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
@@ -407,7 +404,7 @@ restart:
INIT_LIST_HEAD(&b_ptr->links);
spin_lock_init(&b_ptr->lock);
- res = tipc_disc_create(b_ptr, &m_ptr->bcast_addr, disc_domain);
+ res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain);
if (res) {
bearer_disable(b_ptr);
pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 39f1192d04bf..09c869adcfcf 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -56,6 +56,7 @@
* Identifiers of supported TIPC media types
*/
#define TIPC_MEDIA_TYPE_ETH 1
+#define TIPC_MEDIA_TYPE_IB 2
/**
* struct tipc_media_addr - destination address used by TIPC bearers
@@ -77,7 +78,6 @@ struct tipc_bearer;
* @enable_bearer: routine which enables a bearer
* @disable_bearer: routine which disables a bearer
* @addr2str: routine which converts media address to string
- * @str2addr: routine which converts media address from string
* @addr2msg: routine which converts media address to protocol message area
* @msg2addr: routine which converts media address from protocol message area
* @bcast_addr: media address used in broadcasting
@@ -94,10 +94,9 @@ struct tipc_media {
int (*enable_bearer)(struct tipc_bearer *b_ptr);
void (*disable_bearer)(struct tipc_bearer *b_ptr);
int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size);
- int (*str2addr)(struct tipc_media_addr *a, char *str_buf);
int (*addr2msg)(struct tipc_media_addr *a, char *msg_area);
- int (*msg2addr)(struct tipc_media_addr *a, char *msg_area);
- struct tipc_media_addr bcast_addr;
+ int (*msg2addr)(const struct tipc_bearer *b_ptr,
+ struct tipc_media_addr *a, char *msg_area);
u32 priority;
u32 tolerance;
u32 window;
@@ -136,6 +135,7 @@ struct tipc_bearer {
char name[TIPC_MAX_BEARER_NAME];
spinlock_t lock;
struct tipc_media *media;
+ struct tipc_media_addr bcast_addr;
u32 priority;
u32 window;
u32 tolerance;
@@ -175,6 +175,14 @@ int tipc_disable_bearer(const char *name);
int tipc_eth_media_start(void);
void tipc_eth_media_stop(void);
+#ifdef CONFIG_TIPC_MEDIA_IB
+int tipc_ib_media_start(void);
+void tipc_ib_media_stop(void);
+#else
+static inline int tipc_ib_media_start(void) { return 0; }
+static inline void tipc_ib_media_stop(void) { return; }
+#endif
+
int tipc_media_set_priority(const char *name, u32 new_value);
int tipc_media_set_window(const char *name, u32 new_value);
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
diff --git a/net/tipc/core.c b/net/tipc/core.c
index fc05cecd7481..7ec2c1eb94f1 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -82,6 +82,7 @@ static void tipc_core_stop_net(void)
{
tipc_net_stop();
tipc_eth_media_stop();
+ tipc_ib_media_stop();
}
/**
@@ -93,8 +94,15 @@ int tipc_core_start_net(unsigned long addr)
tipc_net_start(addr);
res = tipc_eth_media_start();
- if (res)
- tipc_core_stop_net();
+ if (res < 0)
+ goto err;
+ res = tipc_ib_media_start();
+ if (res < 0)
+ goto err;
+ return res;
+
+err:
+ tipc_core_stop_net();
return res;
}
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index 1074b9587e81..eedff58d0387 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -129,7 +129,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
int link_fully_up;
media_addr.broadcast = 1;
- b_ptr->media->msg2addr(&media_addr, msg_media_addr(msg));
+ b_ptr->media->msg2addr(b_ptr, &media_addr, msg_media_addr(msg));
kfree_skb(buf);
/* Ensure message from node is valid and communication is permitted */
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 2132c1ef2951..120a676a3360 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -77,12 +77,13 @@ static struct notifier_block notifier = {
* Media-dependent "value" field stores MAC address in first 6 bytes
* and zeroes out the remaining bytes.
*/
-static void eth_media_addr_set(struct tipc_media_addr *a, char *mac)
+static void eth_media_addr_set(const struct tipc_bearer *tb_ptr,
+ struct tipc_media_addr *a, char *mac)
{
memcpy(a->value, mac, ETH_ALEN);
memset(a->value + ETH_ALEN, 0, sizeof(a->value) - ETH_ALEN);
a->media_id = TIPC_MEDIA_TYPE_ETH;
- a->broadcast = !memcmp(mac, eth_media_info.bcast_addr.value, ETH_ALEN);
+ a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, ETH_ALEN);
}
/**
@@ -110,6 +111,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
skb_reset_network_header(clone);
clone->dev = dev;
+ clone->protocol = htons(ETH_P_TIPC);
dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
dev->dev_addr, clone->len);
dev_queue_xmit(clone);
@@ -201,9 +203,13 @@ static int enable_bearer(struct tipc_bearer *tb_ptr)
/* Associate TIPC bearer with Ethernet bearer */
eb_ptr->bearer = tb_ptr;
tb_ptr->usr_handle = (void *)eb_ptr;
+ memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
+ memcpy(tb_ptr->bcast_addr.value, dev->broadcast, ETH_ALEN);
+ tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_ETH;
+ tb_ptr->bcast_addr.broadcast = 1;
tb_ptr->mtu = dev->mtu;
tb_ptr->blocked = 0;
- eth_media_addr_set(&tb_ptr->addr, (char *)dev->dev_addr);
+ eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
return 0;
}
@@ -302,25 +308,6 @@ static int eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
}
/**
- * eth_str2addr - convert string to Ethernet address
- */
-static int eth_str2addr(struct tipc_media_addr *a, char *str_buf)
-{
- char mac[ETH_ALEN];
- int r;
-
- r = sscanf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x",
- (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2],
- (u32 *)&mac[3], (u32 *)&mac[4], (u32 *)&mac[5]);
-
- if (r != ETH_ALEN)
- return 1;
-
- eth_media_addr_set(a, mac);
- return 0;
-}
-
-/**
* eth_str2addr - convert Ethernet address format to message header format
*/
static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area)
@@ -334,12 +321,13 @@ static int eth_addr2msg(struct tipc_media_addr *a, char *msg_area)
/**
* eth_str2addr - convert message header address format to Ethernet format
*/
-static int eth_msg2addr(struct tipc_media_addr *a, char *msg_area)
+static int eth_msg2addr(const struct tipc_bearer *tb_ptr,
+ struct tipc_media_addr *a, char *msg_area)
{
if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH)
return 1;
- eth_media_addr_set(a, msg_area + ETH_ADDR_OFFSET);
+ eth_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET);
return 0;
}
@@ -351,11 +339,8 @@ static struct tipc_media eth_media_info = {
.enable_bearer = enable_bearer,
.disable_bearer = disable_bearer,
.addr2str = eth_addr2str,
- .str2addr = eth_str2addr,
.addr2msg = eth_addr2msg,
.msg2addr = eth_msg2addr,
- .bcast_addr = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
- TIPC_MEDIA_TYPE_ETH, 1 },
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.window = TIPC_DEF_LINK_WIN,
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
new file mode 100644
index 000000000000..2a2864c25e15
--- /dev/null
+++ b/net/tipc/ib_media.c
@@ -0,0 +1,387 @@
+/*
+ * net/tipc/ib_media.c: Infiniband bearer support for TIPC
+ *
+ * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
+ *
+ * Based on eth_media.c, which carries the following copyright notice:
+ *
+ * Copyright (c) 2001-2007, Ericsson AB
+ * Copyright (c) 2005-2008, 2011, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/if_infiniband.h>
+#include "core.h"
+#include "bearer.h"
+
+#define MAX_IB_BEARERS MAX_BEARERS
+
+/**
+ * struct ib_bearer - Infiniband bearer data structure
+ * @bearer: ptr to associated "generic" bearer structure
+ * @dev: ptr to associated Infiniband network device
+ * @tipc_packet_type: used in binding TIPC to Infiniband driver
+ * @cleanup: work item used when disabling bearer
+ */
+
+struct ib_bearer {
+ struct tipc_bearer *bearer;
+ struct net_device *dev;
+ struct packet_type tipc_packet_type;
+ struct work_struct setup;
+ struct work_struct cleanup;
+};
+
+static struct tipc_media ib_media_info;
+static struct ib_bearer ib_bearers[MAX_IB_BEARERS];
+static int ib_started;
+
+/**
+ * ib_media_addr_set - initialize Infiniband media address structure
+ *
+ * Media-dependent "value" field stores MAC address in first 6 bytes
+ * and zeroes out the remaining bytes.
+ */
+static void ib_media_addr_set(const struct tipc_bearer *tb_ptr,
+ struct tipc_media_addr *a, char *mac)
+{
+ BUILD_BUG_ON(sizeof(a->value) < INFINIBAND_ALEN);
+ memcpy(a->value, mac, INFINIBAND_ALEN);
+ a->media_id = TIPC_MEDIA_TYPE_IB;
+ a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, INFINIBAND_ALEN);
+}
+
+/**
+ * send_msg - send a TIPC message out over an InfiniBand interface
+ */
+static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
+ struct tipc_media_addr *dest)
+{
+ struct sk_buff *clone;
+ struct net_device *dev;
+ int delta;
+
+ clone = skb_clone(buf, GFP_ATOMIC);
+ if (!clone)
+ return 0;
+
+ dev = ((struct ib_bearer *)(tb_ptr->usr_handle))->dev;
+ delta = dev->hard_header_len - skb_headroom(buf);
+
+ if ((delta > 0) &&
+ pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
+ kfree_skb(clone);
+ return 0;
+ }
+
+ skb_reset_network_header(clone);
+ clone->dev = dev;
+ clone->protocol = htons(ETH_P_TIPC);
+ dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
+ dev->dev_addr, clone->len);
+ dev_queue_xmit(clone);
+ return 0;
+}
+
+/**
+ * recv_msg - handle incoming TIPC message from an InfiniBand interface
+ *
+ * Accept only packets explicitly sent to this node, or broadcast packets;
+ * ignores packets sent using InfiniBand multicast, and traffic sent to other
+ * nodes (which can happen if interface is running in promiscuous mode).
+ */
+static int recv_msg(struct sk_buff *buf, struct net_device *dev,
+ struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct ib_bearer *ib_ptr = (struct ib_bearer *)pt->af_packet_priv;
+
+ if (!net_eq(dev_net(dev), &init_net)) {
+ kfree_skb(buf);
+ return 0;
+ }
+
+ if (likely(ib_ptr->bearer)) {
+ if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
+ buf->next = NULL;
+ tipc_recv_msg(buf, ib_ptr->bearer);
+ return 0;
+ }
+ }
+ kfree_skb(buf);
+ return 0;
+}
+
+/**
+ * setup_bearer - setup association between InfiniBand bearer and interface
+ */
+static void setup_bearer(struct work_struct *work)
+{
+ struct ib_bearer *ib_ptr =
+ container_of(work, struct ib_bearer, setup);
+
+ dev_add_pack(&ib_ptr->tipc_packet_type);
+}
+
+/**
+ * enable_bearer - attach TIPC bearer to an InfiniBand interface
+ */
+static int enable_bearer(struct tipc_bearer *tb_ptr)
+{
+ struct net_device *dev = NULL;
+ struct net_device *pdev = NULL;
+ struct ib_bearer *ib_ptr = &ib_bearers[0];
+ struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
+ char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
+ int pending_dev = 0;
+
+ /* Find unused InfiniBand bearer structure */
+ while (ib_ptr->dev) {
+ if (!ib_ptr->bearer)
+ pending_dev++;
+ if (++ib_ptr == stop)
+ return pending_dev ? -EAGAIN : -EDQUOT;
+ }
+
+ /* Find device with specified name */
+ read_lock(&dev_base_lock);
+ for_each_netdev(&init_net, pdev) {
+ if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) {
+ dev = pdev;
+ dev_hold(dev);
+ break;
+ }
+ }
+ read_unlock(&dev_base_lock);
+ if (!dev)
+ return -ENODEV;
+
+ /* Create InfiniBand bearer for device */
+ ib_ptr->dev = dev;
+ ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
+ ib_ptr->tipc_packet_type.dev = dev;
+ ib_ptr->tipc_packet_type.func = recv_msg;
+ ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr;
+ INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list));
+ INIT_WORK(&ib_ptr->setup, setup_bearer);
+ schedule_work(&ib_ptr->setup);
+
+ /* Associate TIPC bearer with InfiniBand bearer */
+ ib_ptr->bearer = tb_ptr;
+ tb_ptr->usr_handle = (void *)ib_ptr;
+ memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
+ memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN);
+ tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB;
+ tb_ptr->bcast_addr.broadcast = 1;
+ tb_ptr->mtu = dev->mtu;
+ tb_ptr->blocked = 0;
+ ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
+ return 0;
+}
+
+/**
+ * cleanup_bearer - break association between InfiniBand bearer and interface
+ *
+ * This routine must be invoked from a work queue because it can sleep.
+ */
+static void cleanup_bearer(struct work_struct *work)
+{
+ struct ib_bearer *ib_ptr =
+ container_of(work, struct ib_bearer, cleanup);
+
+ dev_remove_pack(&ib_ptr->tipc_packet_type);
+ dev_put(ib_ptr->dev);
+ ib_ptr->dev = NULL;
+}
+
+/**
+ * disable_bearer - detach TIPC bearer from an InfiniBand interface
+ *
+ * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away,
+ * then get worker thread to complete bearer cleanup. (Can't do cleanup
+ * here because cleanup code needs to sleep and caller holds spinlocks.)
+ */
+static void disable_bearer(struct tipc_bearer *tb_ptr)
+{
+ struct ib_bearer *ib_ptr = (struct ib_bearer *)tb_ptr->usr_handle;
+
+ ib_ptr->bearer = NULL;
+ INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
+ schedule_work(&ib_ptr->cleanup);
+}
+
+/**
+ * recv_notification - handle device updates from OS
+ *
+ * Change the state of the InfiniBand bearer (if any) associated with the
+ * specified device.
+ */
+static int recv_notification(struct notifier_block *nb, unsigned long evt,
+ void *dv)
+{
+ struct net_device *dev = (struct net_device *)dv;
+ struct ib_bearer *ib_ptr = &ib_bearers[0];
+ struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
+
+ if (!net_eq(dev_net(dev), &init_net))
+ return NOTIFY_DONE;
+
+ while ((ib_ptr->dev != dev)) {
+ if (++ib_ptr == stop)
+ return NOTIFY_DONE; /* couldn't find device */
+ }
+ if (!ib_ptr->bearer)
+ return NOTIFY_DONE; /* bearer had been disabled */
+
+ ib_ptr->bearer->mtu = dev->mtu;
+
+ switch (evt) {
+ case NETDEV_CHANGE:
+ if (netif_carrier_ok(dev))
+ tipc_continue(ib_ptr->bearer);
+ else
+ tipc_block_bearer(ib_ptr->bearer->name);
+ break;
+ case NETDEV_UP:
+ tipc_continue(ib_ptr->bearer);
+ break;
+ case NETDEV_DOWN:
+ tipc_block_bearer(ib_ptr->bearer->name);
+ break;
+ case NETDEV_CHANGEMTU:
+ case NETDEV_CHANGEADDR:
+ tipc_block_bearer(ib_ptr->bearer->name);
+ tipc_continue(ib_ptr->bearer);
+ break;
+ case NETDEV_UNREGISTER:
+ case NETDEV_CHANGENAME:
+ tipc_disable_bearer(ib_ptr->bearer->name);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block notifier = {
+ .notifier_call = recv_notification,
+ .priority = 0,
+};
+
+/**
+ * ib_addr2str - convert InfiniBand address to string
+ */
+static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
+{
+ if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
+ return 1;
+
+ sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ a->value[0], a->value[1], a->value[2], a->value[3],
+ a->value[4], a->value[5], a->value[6], a->value[7],
+ a->value[8], a->value[9], a->value[10], a->value[11],
+ a->value[12], a->value[13], a->value[14], a->value[15],
+ a->value[16], a->value[17], a->value[18], a->value[19]);
+
+ return 0;
+}
+
+/**
+ * ib_addr2msg - convert InfiniBand address format to message header format
+ */
+static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area)
+{
+ memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE);
+ msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB;
+ memcpy(msg_area, a->value, INFINIBAND_ALEN);
+ return 0;
+}
+
+/**
+ * ib_msg2addr - convert message header address format to InfiniBand format
+ */
+static int ib_msg2addr(const struct tipc_bearer *tb_ptr,
+ struct tipc_media_addr *a, char *msg_area)
+{
+ ib_media_addr_set(tb_ptr, a, msg_area);
+ return 0;
+}
+
+/*
+ * InfiniBand media registration info
+ */
+static struct tipc_media ib_media_info = {
+ .send_msg = send_msg,
+ .enable_bearer = enable_bearer,
+ .disable_bearer = disable_bearer,
+ .addr2str = ib_addr2str,
+ .addr2msg = ib_addr2msg,
+ .msg2addr = ib_msg2addr,
+ .priority = TIPC_DEF_LINK_PRI,
+ .tolerance = TIPC_DEF_LINK_TOL,
+ .window = TIPC_DEF_LINK_WIN,
+ .type_id = TIPC_MEDIA_TYPE_IB,
+ .name = "ib"
+};
+
+/**
+ * tipc_ib_media_start - activate InfiniBand bearer support
+ *
+ * Register InfiniBand media type with TIPC bearer code. Also register
+ * with OS for notifications about device state changes.
+ */
+int tipc_ib_media_start(void)
+{
+ int res;
+
+ if (ib_started)
+ return -EINVAL;
+
+ res = tipc_register_media(&ib_media_info);
+ if (res)
+ return res;
+
+ res = register_netdevice_notifier(&notifier);
+ if (!res)
+ ib_started = 1;
+ return res;
+}
+
+/**
+ * tipc_ib_media_stop - deactivate InfiniBand bearer support
+ */
+void tipc_ib_media_stop(void)
+{
+ if (!ib_started)
+ return;
+
+ flush_scheduled_work();
+ unregister_netdevice_notifier(&notifier);
+ ib_started = 0;
+}
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 6675914dc592..8bcd4985d0fb 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -44,7 +44,7 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
struct nlmsghdr *rep_nlh;
struct nlmsghdr *req_nlh = info->nlhdr;
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
- int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
u16 cmd;
if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
@@ -53,8 +53,8 @@ static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
cmd = req_userhdr->cmd;
rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
- NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
- NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+ nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+ nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
hdr_space);
if (rep_buf) {
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index a9622b6cd916..515ce38e4f4c 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -790,6 +790,7 @@ static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
if (addr) {
addr->family = AF_TIPC;
addr->addrtype = TIPC_ADDR_ID;
+ memset(&addr->addr, 0, sizeof(addr->addr));
addr->addr.id.ref = msg_origport(msg);
addr->addr.id.node = msg_orignode(msg);
addr->addr.name.domain = 0; /* could leave uninitialized */
@@ -904,6 +905,9 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ /* will be updated in set_orig_addr() if needed */
+ m->msg_namelen = 0;
+
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
restart:
@@ -1013,6 +1017,9 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ /* will be updated in set_orig_addr() if needed */
+ m->msg_namelen = 0;
+
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 971282b6f6a3..826e09938bff 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1340,7 +1340,6 @@ static void unix_destruct_scm(struct sk_buff *skb)
struct scm_cookie scm;
memset(&scm, 0, sizeof(scm));
scm.pid = UNIXCB(skb).pid;
- scm.cred = UNIXCB(skb).cred;
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1391,8 +1390,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
int err = 0;
UNIXCB(skb).pid = get_pid(scm->pid);
- if (scm->cred)
- UNIXCB(skb).cred = get_cred(scm->cred);
+ UNIXCB(skb).uid = scm->creds.uid;
+ UNIXCB(skb).gid = scm->creds.gid;
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);
@@ -1409,13 +1408,13 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
const struct sock *other)
{
- if (UNIXCB(skb).cred)
+ if (UNIXCB(skb).pid)
return;
if (test_bit(SOCK_PASSCRED, &sock->flags) ||
- (other->sk_socket &&
- test_bit(SOCK_PASSCRED, &other->sk_socket->flags))) {
+ !other->sk_socket ||
+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
- UNIXCB(skb).cred = get_current_cred();
+ current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
}
}
@@ -1819,7 +1818,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
siocb->scm = &tmp_scm;
memset(&tmp_scm, 0, sizeof(tmp_scm));
}
- scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
+ scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
unix_set_secdata(siocb->scm, skb);
if (!(flags & MSG_PEEK)) {
@@ -1859,10 +1858,10 @@ out:
}
/*
- * Sleep until data has arrive. But check for races..
+ * Sleep until more data has arrived. But check for races..
*/
-
-static long unix_stream_data_wait(struct sock *sk, long timeo)
+static long unix_stream_data_wait(struct sock *sk, long timeo,
+ struct sk_buff *last)
{
DEFINE_WAIT(wait);
@@ -1871,7 +1870,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
for (;;) {
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- if (!skb_queue_empty(&sk->sk_receive_queue) ||
+ if (skb_peek_tail(&sk->sk_receive_queue) != last ||
sk->sk_err ||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
signal_pending(current) ||
@@ -1890,8 +1889,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
return timeo;
}
-
-
static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size,
int flags)
@@ -1936,14 +1933,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- skip = sk_peek_offset(sk, flags);
-
do {
int chunk;
- struct sk_buff *skb;
+ struct sk_buff *skb, *last;
unix_state_lock(sk);
- skb = skb_peek(&sk->sk_receive_queue);
+ last = skb = skb_peek(&sk->sk_receive_queue);
again:
if (skb == NULL) {
unix_sk(sk)->recursion_level = 0;
@@ -1966,7 +1961,7 @@ again:
break;
mutex_unlock(&u->readlock);
- timeo = unix_stream_data_wait(sk, timeo);
+ timeo = unix_stream_data_wait(sk, timeo, last);
if (signal_pending(current)
|| mutex_lock_interruptible(&u->readlock)) {
@@ -1980,10 +1975,13 @@ again:
break;
}
- if (skip >= skb->len) {
+ skip = sk_peek_offset(sk, flags);
+ while (skip >= skb->len) {
skip -= skb->len;
+ last = skb;
skb = skb_peek_next(skb, &sk->sk_receive_queue);
- goto again;
+ if (!skb)
+ goto again;
}
unix_state_unlock(sk);
@@ -1991,11 +1989,12 @@ again:
if (check_creds) {
/* Never glue messages from different writers */
if ((UNIXCB(skb).pid != siocb->scm->pid) ||
- (UNIXCB(skb).cred != siocb->scm->cred))
+ !uid_eq(UNIXCB(skb).uid, siocb->scm->creds.uid) ||
+ !gid_eq(UNIXCB(skb).gid, siocb->scm->creds.gid))
break;
- } else {
+ } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
- scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
+ scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
check_creds = 1;
}
@@ -2196,7 +2195,9 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
/* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
- mask |= POLLERR;
+ mask |= POLLERR |
+ (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
+
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
if (sk->sk_shutdown == SHUTDOWN_MASK)
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index d0f6545b0010..9bc73f87f64a 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -185,7 +185,7 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
* have been added to the queues after
* starting the garbage collection
*/
- if (u->gc_candidate) {
+ if (test_bit(UNIX_GC_CANDIDATE, &u->gc_flags)) {
hit = true;
func(u);
}
@@ -254,7 +254,7 @@ static void inc_inflight_move_tail(struct unix_sock *u)
* of the list, so that it's checked even if it was already
* passed over
*/
- if (u->gc_maybe_cycle)
+ if (test_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags))
list_move_tail(&u->link, &gc_candidates);
}
@@ -315,8 +315,8 @@ void unix_gc(void)
BUG_ON(total_refs < inflight_refs);
if (total_refs == inflight_refs) {
list_move_tail(&u->link, &gc_candidates);
- u->gc_candidate = 1;
- u->gc_maybe_cycle = 1;
+ __set_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
+ __set_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
}
}
@@ -344,7 +344,7 @@ void unix_gc(void)
if (atomic_long_read(&u->inflight) > 0) {
list_move_tail(&u->link, &not_cycle_list);
- u->gc_maybe_cycle = 0;
+ __clear_bit(UNIX_GC_MAYBE_CYCLE, &u->gc_flags);
scan_children(&u->sk, inc_inflight_move_tail, NULL);
}
}
@@ -356,7 +356,7 @@ void unix_gc(void)
*/
while (!list_empty(&not_cycle_list)) {
u = list_entry(not_cycle_list.next, struct unix_sock, link);
- u->gc_candidate = 0;
+ __clear_bit(UNIX_GC_CANDIDATE, &u->gc_flags);
list_move_tail(&u->link, &gc_inflight_list);
}
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index ca511c4f388a..3f77f42a3b58 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -165,7 +165,7 @@ static struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1];
static struct list_head vsock_connected_table[VSOCK_HASH_SIZE];
static DEFINE_SPINLOCK(vsock_table_lock);
-static __init void vsock_init_tables(void)
+static void vsock_init_tables(void)
{
int i;
@@ -207,7 +207,7 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr)
struct vsock_sock *vsk;
list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table)
- if (vsock_addr_equals_addr_any(addr, &vsk->local_addr))
+ if (addr->svm_port == vsk->local_addr.svm_port)
return sk_vsock(vsk);
return NULL;
@@ -220,8 +220,8 @@ static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src,
list_for_each_entry(vsk, vsock_connected_sockets(src, dst),
connected_table) {
- if (vsock_addr_equals_addr(src, &vsk->remote_addr)
- && vsock_addr_equals_addr(dst, &vsk->local_addr)) {
+ if (vsock_addr_equals_addr(src, &vsk->remote_addr) &&
+ dst->svm_port == vsk->local_addr.svm_port) {
return sk_vsock(vsk);
}
}
@@ -1670,6 +1670,8 @@ vsock_stream_recvmsg(struct kiocb *kiocb,
vsk = vsock_sk(sk);
err = 0;
+ msg->msg_namelen = 0;
+
lock_sock(sk);
if (sk->sk_state != SS_CONNECTED) {
@@ -1930,7 +1932,6 @@ static const struct file_operations vsock_device_ops = {
static struct miscdevice vsock_device = {
.name = "vsock",
- .minor = MISC_DYNAMIC_MINOR,
.fops = &vsock_device_ops,
};
@@ -1940,6 +1941,7 @@ static int __vsock_core_init(void)
vsock_init_tables();
+ vsock_device.minor = MISC_DYNAMIC_MINOR;
err = misc_register(&vsock_device);
if (err) {
pr_err("Failed to register misc device\n");
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index a70ace83a153..daff75200e25 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -123,6 +123,14 @@ static s32 vmci_transport_error_to_vsock_error(s32 vmci_error)
return err > 0 ? -err : err;
}
+static u32 vmci_transport_peer_rid(u32 peer_cid)
+{
+ if (VMADDR_CID_HYPERVISOR == peer_cid)
+ return VMCI_TRANSPORT_HYPERVISOR_PACKET_RID;
+
+ return VMCI_TRANSPORT_PACKET_RID;
+}
+
static inline void
vmci_transport_packet_init(struct vmci_transport_packet *pkt,
struct sockaddr_vm *src,
@@ -140,7 +148,7 @@ vmci_transport_packet_init(struct vmci_transport_packet *pkt,
pkt->dg.src = vmci_make_handle(VMADDR_CID_ANY,
VMCI_TRANSPORT_PACKET_RID);
pkt->dg.dst = vmci_make_handle(dst->svm_cid,
- VMCI_TRANSPORT_PACKET_RID);
+ vmci_transport_peer_rid(dst->svm_cid));
pkt->dg.payload_size = sizeof(*pkt) - sizeof(pkt->dg);
pkt->version = VMCI_TRANSPORT_PACKET_VERSION;
pkt->type = type;
@@ -464,19 +472,16 @@ static struct sock *vmci_transport_get_pending(
struct vsock_sock *vlistener;
struct vsock_sock *vpending;
struct sock *pending;
+ struct sockaddr_vm src;
+
+ vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
vlistener = vsock_sk(listener);
list_for_each_entry(vpending, &vlistener->pending_links,
pending_links) {
- struct sockaddr_vm src;
- struct sockaddr_vm dst;
-
- vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
- vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port);
-
if (vsock_addr_equals_addr(&src, &vpending->remote_addr) &&
- vsock_addr_equals_addr(&dst, &vpending->local_addr)) {
+ pkt->dst_port == vpending->local_addr.svm_port) {
pending = sk_vsock(vpending);
sock_hold(pending);
goto found;
@@ -511,6 +516,9 @@ static bool vmci_transport_is_trusted(struct vsock_sock *vsock, u32 peer_cid)
static bool vmci_transport_allow_dgram(struct vsock_sock *vsock, u32 peer_cid)
{
+ if (VMADDR_CID_HYPERVISOR == peer_cid)
+ return true;
+
if (vsock->cached_peer != peer_cid) {
vsock->cached_peer = peer_cid;
if (!vmci_transport_is_trusted(vsock, peer_cid) &&
@@ -631,7 +639,6 @@ static int vmci_transport_recv_dgram_cb(void *data, struct vmci_datagram *dg)
static bool vmci_transport_stream_allow(u32 cid, u32 port)
{
static const u32 non_socket_contexts[] = {
- VMADDR_CID_HYPERVISOR,
VMADDR_CID_RESERVED,
};
int i;
@@ -670,7 +677,7 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg)
*/
if (!vmci_transport_stream_allow(dg->src.context, -1)
- || VMCI_TRANSPORT_PACKET_RID != dg->src.resource)
+ || vmci_transport_peer_rid(dg->src.context) != dg->src.resource)
return VMCI_ERROR_NO_ACCESS;
if (VMCI_DG_SIZE(dg) < sizeof(*pkt))
@@ -739,10 +746,15 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg)
*/
bh_lock_sock(sk);
- if (!sock_owned_by_user(sk) && sk->sk_state == SS_CONNECTED)
- vmci_trans(vsk)->notify_ops->handle_notify_pkt(
- sk, pkt, true, &dst, &src,
- &bh_process_pkt);
+ if (!sock_owned_by_user(sk)) {
+ /* The local context ID may be out of date, update it. */
+ vsk->local_addr.svm_cid = dst.svm_cid;
+
+ if (sk->sk_state == SS_CONNECTED)
+ vmci_trans(vsk)->notify_ops->handle_notify_pkt(
+ sk, pkt, true, &dst, &src,
+ &bh_process_pkt);
+ }
bh_unlock_sock(sk);
@@ -902,6 +914,9 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work)
lock_sock(sk);
+ /* The local context ID may be out of date. */
+ vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context;
+
switch (sk->sk_state) {
case SS_LISTEN:
vmci_transport_recv_listen(sk, pkt);
@@ -958,6 +973,10 @@ static int vmci_transport_recv_listen(struct sock *sk,
pending = vmci_transport_get_pending(sk, pkt);
if (pending) {
lock_sock(pending);
+
+ /* The local context ID may be out of date. */
+ vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context;
+
switch (pending->sk_state) {
case SS_CONNECTING:
err = vmci_transport_recv_connecting_server(sk,
@@ -1727,6 +1746,8 @@ static int vmci_transport_dgram_dequeue(struct kiocb *kiocb,
if (flags & MSG_OOB || flags & MSG_ERRQUEUE)
return -EOPNOTSUPP;
+ msg->msg_namelen = 0;
+
/* Retrieve the head sk_buff from the socket's receive queue. */
err = 0;
skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err);
@@ -1759,7 +1780,6 @@ static int vmci_transport_dgram_dequeue(struct kiocb *kiocb,
if (err)
goto out;
- msg->msg_namelen = 0;
if (msg->msg_name) {
struct sockaddr_vm *vm_addr;
diff --git a/net/vmw_vsock/vmci_transport.h b/net/vmw_vsock/vmci_transport.h
index 1bf991803ec0..fd88ea8924e4 100644
--- a/net/vmw_vsock/vmci_transport.h
+++ b/net/vmw_vsock/vmci_transport.h
@@ -28,6 +28,9 @@
/* The resource ID on which control packets are sent. */
#define VMCI_TRANSPORT_PACKET_RID 1
+/* The resource ID on which control packets are sent to the hypervisor. */
+#define VMCI_TRANSPORT_HYPERVISOR_PACKET_RID 15
+
#define VSOCK_PROTO_INVALID 0
#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0)
#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY)
diff --git a/net/vmw_vsock/vsock_addr.c b/net/vmw_vsock/vsock_addr.c
index b7df1aea7c59..ec2611b4ea0e 100644
--- a/net/vmw_vsock/vsock_addr.c
+++ b/net/vmw_vsock/vsock_addr.c
@@ -64,16 +64,6 @@ bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
}
EXPORT_SYMBOL_GPL(vsock_addr_equals_addr);
-bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
- const struct sockaddr_vm *other)
-{
- return (addr->svm_cid == VMADDR_CID_ANY ||
- other->svm_cid == VMADDR_CID_ANY ||
- addr->svm_cid == other->svm_cid) &&
- addr->svm_port == other->svm_port;
-}
-EXPORT_SYMBOL_GPL(vsock_addr_equals_addr_any);
-
int vsock_addr_cast(const struct sockaddr *addr,
size_t len, struct sockaddr_vm **out_addr)
{
diff --git a/net/vmw_vsock/vsock_addr.h b/net/vmw_vsock/vsock_addr.h
index cdfbcefdf843..9ccd5316eac0 100644
--- a/net/vmw_vsock/vsock_addr.h
+++ b/net/vmw_vsock/vsock_addr.h
@@ -24,8 +24,6 @@ bool vsock_addr_bound(const struct sockaddr_vm *addr);
void vsock_addr_unbind(struct sockaddr_vm *addr);
bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
const struct sockaddr_vm *other);
-bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
- const struct sockaddr_vm *other);
int vsock_addr_cast(const struct sockaddr *addr, size_t len,
struct sockaddr_vm **out_addr);
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index a4a14e8f55cc..324e8d851dc4 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -46,65 +46,3 @@ int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
return err;
}
-
-void cfg80211_ch_switch_notify(struct net_device *dev,
- struct cfg80211_chan_def *chandef)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_ch_switch_notify(dev, chandef);
-
- wdev_lock(wdev);
-
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO))
- goto out;
-
- wdev->channel = chandef->chan;
- nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
-out:
- wdev_unlock(wdev);
- return;
-}
-EXPORT_SYMBOL(cfg80211_ch_switch_notify);
-
-bool cfg80211_rx_spurious_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- bool ret;
-
- trace_cfg80211_rx_spurious_frame(dev, addr);
-
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
- trace_cfg80211_return_bool(false);
- return false;
- }
- ret = nl80211_unexpected_frame(dev, addr, gfp);
- trace_cfg80211_return_bool(ret);
- return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
-
-bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- bool ret;
-
- trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
-
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
- wdev->iftype != NL80211_IFTYPE_P2P_GO &&
- wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
- trace_cfg80211_return_bool(false);
- return false;
- }
- ret = nl80211_unexpected_4addr_frame(dev, addr, gfp);
- trace_cfg80211_return_bool(ret);
- return ret;
-}
-EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ea4155fe9733..84c9ad7e1dca 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
rdev_rfkill_poll(rdev);
}
+void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ lockdep_assert_held(&rdev->devlist_mtx);
+ lockdep_assert_held(&rdev->sched_scan_mtx);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
+ return;
+
+ if (!wdev->p2p_started)
+ return;
+
+ rdev_stop_p2p_device(rdev, wdev);
+ wdev->p2p_started = false;
+
+ rdev->opencount--;
+
+ if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
+ bool busy = work_busy(&rdev->scan_done_wk);
+
+ /*
+ * If the work isn't pending or running (in which case it would
+ * be waiting for the lock we hold) the driver didn't properly
+ * cancel the scan when the interface was removed. In this case
+ * warn and leak the scan request object to not crash later.
+ */
+ WARN_ON(!busy);
+
+ rdev->scan_req->aborted = true;
+ ___cfg80211_scan_done(rdev, !busy);
+ }
+}
+
static int cfg80211_rfkill_set_block(void *data, bool blocked)
{
struct cfg80211_registered_device *rdev = data;
@@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
return 0;
rtnl_lock();
- mutex_lock(&rdev->devlist_mtx);
+
+ /* read-only iteration need not hold the devlist_mtx */
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (wdev->netdev) {
@@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
/* otherwise, check iftype */
switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
- if (!wdev->p2p_started)
- break;
- rdev_stop_p2p_device(rdev, wdev);
- wdev->p2p_started = false;
- rdev->opencount--;
+ /* but this requires it */
+ mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
+ cfg80211_stop_p2p_device(rdev, wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
+ mutex_unlock(&rdev->devlist_mtx);
break;
default:
break;
}
}
- mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();
return 0;
@@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)
wdev = container_of(work, struct wireless_dev, cleanup_work);
rdev = wiphy_to_dev(wdev->wiphy);
- cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->sched_scan_mtx);
if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, true);
}
- cfg80211_unlock_rdev(rdev);
-
- mutex_lock(&rdev->sched_scan_mtx);
-
if (WARN_ON(rdev->sched_scan_req &&
rdev->sched_scan_req->dev == wdev->netdev)) {
__cfg80211_stop_sched_scan(rdev, false);
@@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
return;
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
list_del_rcu(&wdev->list);
rdev->devlist_generation++;
switch (wdev->iftype) {
case NL80211_IFTYPE_P2P_DEVICE:
- if (!wdev->p2p_started)
- break;
- rdev_stop_p2p_device(rdev, wdev);
- wdev->p2p_started = false;
- rdev->opencount--;
+ cfg80211_stop_p2p_device(rdev, wdev);
break;
default:
WARN_ON_ONCE(1);
break;
}
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
}
EXPORT_SYMBOL(cfg80211_unregister_wdev);
@@ -814,6 +842,46 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
rdev->num_running_monitor_ifaces += num;
}
+void cfg80211_leave(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ struct net_device *dev = wdev->netdev;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ cfg80211_leave_ibss(rdev, dev, true);
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_STATION:
+ mutex_lock(&rdev->sched_scan_mtx);
+ __cfg80211_stop_sched_scan(rdev, false);
+ mutex_unlock(&rdev->sched_scan_mtx);
+
+ wdev_lock(wdev);
+#ifdef CONFIG_CFG80211_WEXT
+ kfree(wdev->wext.ie);
+ wdev->wext.ie = NULL;
+ wdev->wext.ie_len = 0;
+ wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
+#endif
+ __cfg80211_disconnect(rdev, dev,
+ WLAN_REASON_DEAUTH_LEAVING, true);
+ cfg80211_mlme_down(rdev, dev);
+ wdev_unlock(wdev);
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ cfg80211_leave_mesh(rdev, dev);
+ break;
+ case NL80211_IFTYPE_AP:
+ cfg80211_stop_ap(rdev, dev);
+ break;
+ default:
+ break;
+ }
+
+ wdev->beacon_interval = 0;
+}
+
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state,
void *ndev)
@@ -882,38 +950,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
dev->priv_flags |= IFF_DONT_BRIDGE;
break;
case NETDEV_GOING_DOWN:
- switch (wdev->iftype) {
- case NL80211_IFTYPE_ADHOC:
- cfg80211_leave_ibss(rdev, dev, true);
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- case NL80211_IFTYPE_STATION:
- mutex_lock(&rdev->sched_scan_mtx);
- __cfg80211_stop_sched_scan(rdev, false);
- mutex_unlock(&rdev->sched_scan_mtx);
-
- wdev_lock(wdev);
-#ifdef CONFIG_CFG80211_WEXT
- kfree(wdev->wext.ie);
- wdev->wext.ie = NULL;
- wdev->wext.ie_len = 0;
- wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
-#endif
- __cfg80211_disconnect(rdev, dev,
- WLAN_REASON_DEAUTH_LEAVING, true);
- cfg80211_mlme_down(rdev, dev);
- wdev_unlock(wdev);
- break;
- case NL80211_IFTYPE_MESH_POINT:
- cfg80211_leave_mesh(rdev, dev);
- break;
- case NL80211_IFTYPE_AP:
- cfg80211_stop_ap(rdev, dev);
- break;
- default:
- break;
- }
- wdev->beacon_interval = 0;
+ cfg80211_leave(rdev, wdev);
break;
case NETDEV_DOWN:
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
@@ -936,6 +973,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
switch (wdev->iftype) {
#ifdef CONFIG_CFG80211_WEXT
@@ -967,6 +1005,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
break;
}
wdev_unlock(wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
rdev->opencount++;
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
@@ -1087,8 +1126,10 @@ static int __init cfg80211_init(void)
goto out_fail_reg;
cfg80211_wq = create_singlethread_workqueue("cfg80211");
- if (!cfg80211_wq)
+ if (!cfg80211_wq) {
+ err = -ENOMEM;
goto out_fail_wq;
+ }
return 0;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3aec0e429d8a..fd35dae547c4 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -88,6 +88,9 @@ struct cfg80211_registered_device {
struct delayed_work dfs_update_channels_wk;
+ /* netlink port which started critical protocol (0 means not started) */
+ u32 crit_proto_nlportid;
+
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __aligned(NETDEV_ALIGN);
@@ -330,20 +333,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
- const u8 *bssid, const u8 *prev_bssid,
+ const u8 *bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt,
- u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
- struct ieee80211_ht_cap *ht_capa_mask);
+ struct cfg80211_assoc_request *req);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
- struct net_device *dev, struct ieee80211_channel *chan,
- const u8 *bssid, const u8 *prev_bssid,
+ struct net_device *dev,
+ struct ieee80211_channel *chan,
+ const u8 *bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt,
- u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
- struct ieee80211_ht_cap *ht_capa_mask);
+ struct cfg80211_assoc_request *req);
int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
struct net_device *dev, const u8 *bssid,
const u8 *ie, int ie_len, u16 reason,
@@ -375,6 +373,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
bool no_cck, bool dont_wait_for_ack, u64 *cookie);
void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
const struct ieee80211_ht_cap *ht_capa_mask);
+void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
+ const struct ieee80211_vht_cap *vht_capa_mask);
/* SME */
int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -503,6 +503,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num);
+void cfg80211_leave(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
+void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev);
+
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 55957a284f6c..0bb93f3061a4 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -85,6 +85,7 @@ const struct mesh_setup default_mesh_setup = {
.ie = NULL,
.ie_len = 0,
.is_secure = false,
+ .user_mpm = false,
.beacon_interval = MESH_DEFAULT_BEACON_INTERVAL,
.dtim_period = MESH_DEFAULT_DTIM_PERIOD,
};
@@ -233,20 +234,6 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
return 0;
}
-void cfg80211_notify_new_peer_candidate(struct net_device *dev,
- const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
-
- trace_cfg80211_notify_new_peer_candidate(dev, macaddr);
- if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
- return;
-
- nl80211_send_new_peer_candidate(wiphy_to_dev(wdev->wiphy), dev,
- macaddr, ie, ie_len, gfp);
-}
-EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
-
static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev)
{
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index caddca35d686..0c7b7dd855f6 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -187,30 +187,6 @@ void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
}
EXPORT_SYMBOL(cfg80211_send_disassoc);
-void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
- size_t len)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_send_unprot_deauth(dev);
- nl80211_send_unprot_deauth(rdev, dev, buf, len, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
-
-void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
- size_t len)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_send_unprot_disassoc(dev);
- nl80211_send_unprot_disassoc(rdev, dev, buf, len, GFP_ATOMIC);
-}
-EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
-
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -367,27 +343,38 @@ void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
p1[i] &= p2[i];
}
+/* Do a logical ht_capa &= ht_capa_mask. */
+void cfg80211_oper_and_vht_capa(struct ieee80211_vht_cap *vht_capa,
+ const struct ieee80211_vht_cap *vht_capa_mask)
+{
+ int i;
+ u8 *p1, *p2;
+ if (!vht_capa_mask) {
+ memset(vht_capa, 0, sizeof(*vht_capa));
+ return;
+ }
+
+ p1 = (u8*)(vht_capa);
+ p2 = (u8*)(vht_capa_mask);
+ for (i = 0; i < sizeof(*vht_capa); i++)
+ p1[i] &= p2[i];
+}
+
int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
- const u8 *bssid, const u8 *prev_bssid,
+ const u8 *bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt,
- u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
- struct ieee80211_ht_cap *ht_capa_mask)
+ struct cfg80211_assoc_request *req)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_assoc_request req;
int err;
bool was_connected = false;
ASSERT_WDEV_LOCK(wdev);
- memset(&req, 0, sizeof(req));
-
- if (wdev->current_bss && prev_bssid &&
- ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) {
+ if (wdev->current_bss && req->prev_bssid &&
+ ether_addr_equal(wdev->current_bss->pub.bssid, req->prev_bssid)) {
/*
* Trying to reassociate: Allow this to proceed and let the old
* association to be dropped when the new one is completed.
@@ -399,40 +386,30 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
} else if (wdev->current_bss)
return -EALREADY;
- req.ie = ie;
- req.ie_len = ie_len;
- memcpy(&req.crypto, crypt, sizeof(req.crypto));
- req.use_mfp = use_mfp;
- req.prev_bssid = prev_bssid;
- req.flags = assoc_flags;
- if (ht_capa)
- memcpy(&req.ht_capa, ht_capa, sizeof(req.ht_capa));
- if (ht_capa_mask)
- memcpy(&req.ht_capa_mask, ht_capa_mask,
- sizeof(req.ht_capa_mask));
- cfg80211_oper_and_ht_capa(&req.ht_capa_mask,
+ cfg80211_oper_and_ht_capa(&req->ht_capa_mask,
rdev->wiphy.ht_capa_mod_mask);
+ cfg80211_oper_and_vht_capa(&req->vht_capa_mask,
+ rdev->wiphy.vht_capa_mod_mask);
- req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
- WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
- if (!req.bss) {
+ req->bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
+ WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+ if (!req->bss) {
if (was_connected)
wdev->sme_state = CFG80211_SME_CONNECTED;
return -ENOENT;
}
- err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
- CHAN_MODE_SHARED);
+ err = cfg80211_can_use_chan(rdev, wdev, chan, CHAN_MODE_SHARED);
if (err)
goto out;
- err = rdev_assoc(rdev, dev, &req);
+ err = rdev_assoc(rdev, dev, req);
out:
if (err) {
if (was_connected)
wdev->sme_state = CFG80211_SME_CONNECTED;
- cfg80211_put_bss(&rdev->wiphy, req.bss);
+ cfg80211_put_bss(&rdev->wiphy, req->bss);
}
return err;
@@ -441,21 +418,17 @@ out:
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
- const u8 *bssid, const u8 *prev_bssid,
+ const u8 *bssid,
const u8 *ssid, int ssid_len,
- const u8 *ie, int ie_len, bool use_mfp,
- struct cfg80211_crypto_settings *crypt,
- u32 assoc_flags, struct ieee80211_ht_cap *ht_capa,
- struct ieee80211_ht_cap *ht_capa_mask)
+ struct cfg80211_assoc_request *req)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
int err;
mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
- err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
- ssid, ssid_len, ie, ie_len, use_mfp, crypt,
- assoc_flags, ht_capa, ht_capa_mask);
+ err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid,
+ ssid, ssid_len, req);
wdev_unlock(wdev);
mutex_unlock(&rdev->devlist_mtx);
@@ -577,62 +550,6 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
}
}
-void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
- struct ieee80211_channel *chan,
- unsigned int duration, gfp_t gfp)
-{
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
- nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp);
-}
-EXPORT_SYMBOL(cfg80211_ready_on_channel);
-
-void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
- struct ieee80211_channel *chan,
- gfp_t gfp)
-{
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
- nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp);
-}
-EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
-
-void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
- struct station_info *sinfo, gfp_t gfp)
-{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_new_sta(dev, mac_addr, sinfo);
- nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
-}
-EXPORT_SYMBOL(cfg80211_new_sta);
-
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
-{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_del_sta(dev, mac_addr);
- nl80211_send_sta_del_event(rdev, dev, mac_addr, gfp);
-}
-EXPORT_SYMBOL(cfg80211_del_sta);
-
-void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
- enum nl80211_connect_failed_reason reason,
- gfp_t gfp)
-{
- struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- nl80211_send_conn_failed_event(rdev, dev, mac_addr, reason, gfp);
-}
-EXPORT_SYMBOL(cfg80211_conn_failed);
-
struct cfg80211_mgmt_registration {
struct list_head list;
@@ -731,6 +648,11 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid)
spin_unlock_bh(&wdev->mgmt_registrations_lock);
+ if (nlportid && rdev->crit_proto_nlportid == nlportid) {
+ rdev->crit_proto_nlportid = 0;
+ rdev_crit_proto_stop(rdev, wdev);
+ }
+
if (nlportid == wdev->ap_unexpected_nlportid)
wdev->ap_unexpected_nlportid = 0;
}
@@ -909,85 +831,6 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
}
EXPORT_SYMBOL(cfg80211_rx_mgmt);
-void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
- const u8 *buf, size_t len, bool ack, gfp_t gfp)
-{
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
-
- /* Indicate TX status of the Action frame to user space */
- nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
-}
-EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
-
-void cfg80211_cqm_rssi_notify(struct net_device *dev,
- enum nl80211_cqm_rssi_threshold_event rssi_event,
- gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
-
- /* Indicate roaming trigger event to user space */
- nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
-
-void cfg80211_cqm_pktloss_notify(struct net_device *dev,
- const u8 *peer, u32 num_packets, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
-
- /* Indicate roaming trigger event to user space */
- nl80211_send_cqm_pktloss_notify(rdev, dev, peer, num_packets, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
-
-void cfg80211_cqm_txe_notify(struct net_device *dev,
- const u8 *peer, u32 num_packets,
- u32 rate, u32 intvl, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets,
- rate, intvl, gfp);
-}
-EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
-
-void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
- const u8 *replay_ctr, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_gtk_rekey_notify(dev, bssid);
- nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
-}
-EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
-
-void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
- const u8 *bssid, bool preauth, gfp_t gfp)
-{
- struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct wiphy *wiphy = wdev->wiphy;
- struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-
- trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
- nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
-}
-EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
-
void cfg80211_dfs_channels_update_work(struct work_struct *work)
{
struct delayed_work *delayed_work;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d44ab216c0ec..afa283841e8c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -370,6 +370,14 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_MAC_ADDRS] = { .type = NLA_NESTED },
[NL80211_ATTR_STA_CAPABILITY] = { .type = NLA_U16 },
[NL80211_ATTR_STA_EXT_CAPABILITY] = { .type = NLA_BINARY, },
+ [NL80211_ATTR_SPLIT_WIPHY_DUMP] = { .type = NLA_FLAG, },
+ [NL80211_ATTR_DISABLE_VHT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_VHT_CAPABILITY_MASK] = {
+ .len = NL80211_VHT_CAPABILITY_LEN,
+ },
+ [NL80211_ATTR_MDID] = { .type = NLA_U16 },
+ [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};
/* policy for the key attributes */
@@ -439,62 +447,69 @@ nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
};
-/* ifidx get helper */
-static int nl80211_get_ifidx(struct netlink_callback *cb)
+static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct cfg80211_registered_device **rdev,
+ struct wireless_dev **wdev)
{
- int res;
-
- res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
- nl80211_fam.attrbuf, nl80211_fam.maxattr,
- nl80211_policy);
- if (res)
- return res;
-
- if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
- return -EINVAL;
+ int err;
- res = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
- if (!res)
- return -EINVAL;
- return res;
-}
+ rtnl_lock();
+ mutex_lock(&cfg80211_mutex);
-static int nl80211_prepare_netdev_dump(struct sk_buff *skb,
- struct netlink_callback *cb,
- struct cfg80211_registered_device **rdev,
- struct net_device **dev)
-{
- int ifidx = cb->args[0];
- int err;
+ if (!cb->args[0]) {
+ err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+ nl80211_fam.attrbuf, nl80211_fam.maxattr,
+ nl80211_policy);
+ if (err)
+ goto out_unlock;
- if (!ifidx)
- ifidx = nl80211_get_ifidx(cb);
- if (ifidx < 0)
- return ifidx;
+ *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk),
+ nl80211_fam.attrbuf);
+ if (IS_ERR(*wdev)) {
+ err = PTR_ERR(*wdev);
+ goto out_unlock;
+ }
+ *rdev = wiphy_to_dev((*wdev)->wiphy);
+ cb->args[0] = (*rdev)->wiphy_idx;
+ cb->args[1] = (*wdev)->identifier;
+ } else {
+ struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]);
+ struct wireless_dev *tmp;
- cb->args[0] = ifidx;
+ if (!wiphy) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+ *rdev = wiphy_to_dev(wiphy);
+ *wdev = NULL;
- rtnl_lock();
+ mutex_lock(&(*rdev)->devlist_mtx);
+ list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+ if (tmp->identifier == cb->args[1]) {
+ *wdev = tmp;
+ break;
+ }
+ }
+ mutex_unlock(&(*rdev)->devlist_mtx);
- *dev = __dev_get_by_index(sock_net(skb->sk), ifidx);
- if (!*dev) {
- err = -ENODEV;
- goto out_rtnl;
+ if (!*wdev) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
}
- *rdev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
- if (IS_ERR(*rdev)) {
- err = PTR_ERR(*rdev);
- goto out_rtnl;
- }
+ cfg80211_lock_rdev(*rdev);
+ mutex_unlock(&cfg80211_mutex);
return 0;
- out_rtnl:
+ out_unlock:
+ mutex_unlock(&cfg80211_mutex);
rtnl_unlock();
return err;
}
-static void nl80211_finish_netdev_dump(struct cfg80211_registered_device *rdev)
+static void nl80211_finish_wdev_dump(struct cfg80211_registered_device *rdev)
{
cfg80211_unlock_rdev(rdev);
rtnl_unlock();
@@ -539,7 +554,8 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
}
static int nl80211_msg_put_channel(struct sk_buff *msg,
- struct ieee80211_channel *chan)
+ struct ieee80211_channel *chan,
+ bool large)
{
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_FREQ,
chan->center_freq))
@@ -554,9 +570,37 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
goto nla_put_failure;
- if ((chan->flags & IEEE80211_CHAN_RADAR) &&
- nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
- goto nla_put_failure;
+ if (chan->flags & IEEE80211_CHAN_RADAR) {
+ if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
+ goto nla_put_failure;
+ if (large) {
+ u32 time;
+
+ time = elapsed_jiffies_msecs(chan->dfs_state_entered);
+
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
+ chan->dfs_state))
+ goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME,
+ time))
+ goto nla_put_failure;
+ }
+ }
+
+ if (large) {
+ if ((chan->flags & IEEE80211_CHAN_NO_HT40MINUS) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_MINUS))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_HT40PLUS) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_HT40_PLUS))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_80MHZ) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_80MHZ))
+ goto nla_put_failure;
+ if ((chan->flags & IEEE80211_CHAN_NO_160MHZ) &&
+ nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_160MHZ))
+ goto nla_put_failure;
+ }
if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
DBM_TO_MBM(chan->max_power)))
@@ -832,7 +876,8 @@ nla_put_failure:
}
static int nl80211_put_iface_combinations(struct wiphy *wiphy,
- struct sk_buff *msg)
+ struct sk_buff *msg,
+ bool large)
{
struct nlattr *nl_combis;
int i, j;
@@ -881,6 +926,10 @@ static int nl80211_put_iface_combinations(struct wiphy *wiphy,
nla_put_u32(msg, NL80211_IFACE_COMB_MAXNUM,
c->max_interfaces))
goto nla_put_failure;
+ if (large &&
+ nla_put_u32(msg, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS,
+ c->radar_detect_widths))
+ goto nla_put_failure;
nla_nest_end(msg, nl_combi);
}
@@ -892,412 +941,615 @@ nla_put_failure:
return -ENOBUFS;
}
-static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flags,
- struct cfg80211_registered_device *dev)
+#ifdef CONFIG_PM
+static int nl80211_send_wowlan_tcp_caps(struct cfg80211_registered_device *rdev,
+ struct sk_buff *msg)
{
- void *hdr;
- struct nlattr *nl_bands, *nl_band;
- struct nlattr *nl_freqs, *nl_freq;
- struct nlattr *nl_rates, *nl_rate;
- struct nlattr *nl_cmds;
- enum ieee80211_band band;
- struct ieee80211_channel *chan;
- struct ieee80211_rate *rate;
- int i;
- const struct ieee80211_txrx_stypes *mgmt_stypes =
- dev->wiphy.mgmt_stypes;
+ const struct wiphy_wowlan_tcp_support *tcp = rdev->wiphy.wowlan.tcp;
+ struct nlattr *nl_tcp;
- hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
- if (!hdr)
- return -1;
+ if (!tcp)
+ return 0;
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
- nla_put_string(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)) ||
- nla_put_u32(msg, NL80211_ATTR_GENERATION,
- cfg80211_rdev_list_generation) ||
- nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
- dev->wiphy.retry_short) ||
- nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
- dev->wiphy.retry_long) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
- dev->wiphy.frag_threshold) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
- dev->wiphy.rts_threshold) ||
- nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
- dev->wiphy.coverage_class) ||
- nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
- dev->wiphy.max_scan_ssids) ||
- nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
- dev->wiphy.max_sched_scan_ssids) ||
- nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
- dev->wiphy.max_scan_ie_len) ||
- nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
- dev->wiphy.max_sched_scan_ie_len) ||
- nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
- dev->wiphy.max_match_sets))
- goto nla_put_failure;
+ nl_tcp = nla_nest_start(msg, NL80211_WOWLAN_TRIG_TCP_CONNECTION);
+ if (!nl_tcp)
+ return -ENOBUFS;
- if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
- nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
- goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
- nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
- goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
- nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
- goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
- nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
- goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
- nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
- goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
- nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
- goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+ tcp->data_payload_max))
+ return -ENOBUFS;
- if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
- sizeof(u32) * dev->wiphy.n_cipher_suites,
- dev->wiphy.cipher_suites))
- goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD,
+ tcp->data_payload_max))
+ return -ENOBUFS;
- if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
- dev->wiphy.max_num_pmkids))
- goto nla_put_failure;
+ if (tcp->seq && nla_put_flag(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_SEQ))
+ return -ENOBUFS;
- if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
- nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
- goto nla_put_failure;
+ if (tcp->tok && nla_put(msg, NL80211_WOWLAN_TCP_DATA_PAYLOAD_TOKEN,
+ sizeof(*tcp->tok), tcp->tok))
+ return -ENOBUFS;
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
- dev->wiphy.available_antennas_tx) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
- dev->wiphy.available_antennas_rx))
- goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_WOWLAN_TCP_DATA_INTERVAL,
+ tcp->data_interval_max))
+ return -ENOBUFS;
- if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
- nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
- dev->wiphy.probe_resp_offload))
- goto nla_put_failure;
+ if (nla_put_u32(msg, NL80211_WOWLAN_TCP_WAKE_PAYLOAD,
+ tcp->wake_payload_max))
+ return -ENOBUFS;
- if ((dev->wiphy.available_antennas_tx ||
- dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
- u32 tx_ant = 0, rx_ant = 0;
- int res;
- res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
- if (!res) {
- if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX,
- tx_ant) ||
- nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX,
- rx_ant))
- goto nla_put_failure;
- }
+ nla_nest_end(msg, nl_tcp);
+ return 0;
+}
+
+static int nl80211_send_wowlan(struct sk_buff *msg,
+ struct cfg80211_registered_device *dev,
+ bool large)
+{
+ struct nlattr *nl_wowlan;
+
+ if (!dev->wiphy.wowlan.flags && !dev->wiphy.wowlan.n_patterns)
+ return 0;
+
+ nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
+ if (!nl_wowlan)
+ return -ENOBUFS;
+
+ if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+ ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
+ nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
+ return -ENOBUFS;
+
+ if (dev->wiphy.wowlan.n_patterns) {
+ struct nl80211_wowlan_pattern_support pat = {
+ .max_patterns = dev->wiphy.wowlan.n_patterns,
+ .min_pattern_len = dev->wiphy.wowlan.pattern_min_len,
+ .max_pattern_len = dev->wiphy.wowlan.pattern_max_len,
+ .max_pkt_offset = dev->wiphy.wowlan.max_pkt_offset,
+ };
+
+ if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ sizeof(pat), &pat))
+ return -ENOBUFS;
}
- if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
- dev->wiphy.interface_modes))
- goto nla_put_failure;
+ if (large && nl80211_send_wowlan_tcp_caps(dev, msg))
+ return -ENOBUFS;
- nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
- if (!nl_bands)
- goto nla_put_failure;
+ nla_nest_end(msg, nl_wowlan);
- for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
- if (!dev->wiphy.bands[band])
- continue;
+ return 0;
+}
+#endif
- nl_band = nla_nest_start(msg, band);
- if (!nl_band)
- goto nla_put_failure;
+static int nl80211_send_band_rateinfo(struct sk_buff *msg,
+ struct ieee80211_supported_band *sband)
+{
+ struct nlattr *nl_rates, *nl_rate;
+ struct ieee80211_rate *rate;
+ int i;
- /* add HT info */
- if (dev->wiphy.bands[band]->ht_cap.ht_supported &&
- (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
- sizeof(dev->wiphy.bands[band]->ht_cap.mcs),
- &dev->wiphy.bands[band]->ht_cap.mcs) ||
- nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
- dev->wiphy.bands[band]->ht_cap.cap) ||
- nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
- dev->wiphy.bands[band]->ht_cap.ampdu_factor) ||
- nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
- dev->wiphy.bands[band]->ht_cap.ampdu_density)))
- goto nla_put_failure;
+ /* add HT info */
+ if (sband->ht_cap.ht_supported &&
+ (nla_put(msg, NL80211_BAND_ATTR_HT_MCS_SET,
+ sizeof(sband->ht_cap.mcs),
+ &sband->ht_cap.mcs) ||
+ nla_put_u16(msg, NL80211_BAND_ATTR_HT_CAPA,
+ sband->ht_cap.cap) ||
+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ sband->ht_cap.ampdu_factor) ||
+ nla_put_u8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+ sband->ht_cap.ampdu_density)))
+ return -ENOBUFS;
- /* add VHT info */
- if (dev->wiphy.bands[band]->vht_cap.vht_supported &&
- (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
- sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs),
- &dev->wiphy.bands[band]->vht_cap.vht_mcs) ||
- nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
- dev->wiphy.bands[band]->vht_cap.cap)))
- goto nla_put_failure;
+ /* add VHT info */
+ if (sband->vht_cap.vht_supported &&
+ (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
+ sizeof(sband->vht_cap.vht_mcs),
+ &sband->vht_cap.vht_mcs) ||
+ nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
+ sband->vht_cap.cap)))
+ return -ENOBUFS;
- /* add frequencies */
- nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
- if (!nl_freqs)
- goto nla_put_failure;
+ /* add bitrates */
+ nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+ if (!nl_rates)
+ return -ENOBUFS;
- for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
- nl_freq = nla_nest_start(msg, i);
- if (!nl_freq)
- goto nla_put_failure;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ nl_rate = nla_nest_start(msg, i);
+ if (!nl_rate)
+ return -ENOBUFS;
- chan = &dev->wiphy.bands[band]->channels[i];
+ rate = &sband->bitrates[i];
+ if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
+ rate->bitrate))
+ return -ENOBUFS;
+ if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
+ nla_put_flag(msg,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
+ return -ENOBUFS;
- if (nl80211_msg_put_channel(msg, chan))
- goto nla_put_failure;
+ nla_nest_end(msg, nl_rate);
+ }
- nla_nest_end(msg, nl_freq);
- }
+ nla_nest_end(msg, nl_rates);
- nla_nest_end(msg, nl_freqs);
+ return 0;
+}
- /* add bitrates */
- nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
- if (!nl_rates)
- goto nla_put_failure;
+static int
+nl80211_send_mgmt_stypes(struct sk_buff *msg,
+ const struct ieee80211_txrx_stypes *mgmt_stypes)
+{
+ u16 stypes;
+ struct nlattr *nl_ftypes, *nl_ifs;
+ enum nl80211_iftype ift;
+ int i;
- for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
- nl_rate = nla_nest_start(msg, i);
- if (!nl_rate)
- goto nla_put_failure;
+ if (!mgmt_stypes)
+ return 0;
- rate = &dev->wiphy.bands[band]->bitrates[i];
- if (nla_put_u32(msg, NL80211_BITRATE_ATTR_RATE,
- rate->bitrate))
- goto nla_put_failure;
- if ((rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
- nla_put_flag(msg,
- NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE))
- goto nla_put_failure;
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
+ if (!nl_ifs)
+ return -ENOBUFS;
- nla_nest_end(msg, nl_rate);
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+ nl_ftypes = nla_nest_start(msg, ift);
+ if (!nl_ftypes)
+ return -ENOBUFS;
+ i = 0;
+ stypes = mgmt_stypes[ift].tx;
+ while (stypes) {
+ if ((stypes & 1) &&
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT))
+ return -ENOBUFS;
+ stypes >>= 1;
+ i++;
}
+ nla_nest_end(msg, nl_ftypes);
+ }
+
+ nla_nest_end(msg, nl_ifs);
- nla_nest_end(msg, nl_rates);
+ nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
+ if (!nl_ifs)
+ return -ENOBUFS;
- nla_nest_end(msg, nl_band);
+ for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
+ nl_ftypes = nla_nest_start(msg, ift);
+ if (!nl_ftypes)
+ return -ENOBUFS;
+ i = 0;
+ stypes = mgmt_stypes[ift].rx;
+ while (stypes) {
+ if ((stypes & 1) &&
+ nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
+ (i << 4) | IEEE80211_FTYPE_MGMT))
+ return -ENOBUFS;
+ stypes >>= 1;
+ i++;
+ }
+ nla_nest_end(msg, nl_ftypes);
}
- nla_nest_end(msg, nl_bands);
+ nla_nest_end(msg, nl_ifs);
- nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
- if (!nl_cmds)
- goto nla_put_failure;
+ return 0;
+}
- i = 0;
-#define CMD(op, n) \
- do { \
- if (dev->ops->op) { \
- i++; \
- if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
- goto nla_put_failure; \
- } \
- } while (0)
-
- CMD(add_virtual_intf, NEW_INTERFACE);
- CMD(change_virtual_intf, SET_INTERFACE);
- CMD(add_key, NEW_KEY);
- CMD(start_ap, START_AP);
- CMD(add_station, NEW_STATION);
- CMD(add_mpath, NEW_MPATH);
- CMD(update_mesh_config, SET_MESH_CONFIG);
- CMD(change_bss, SET_BSS);
- CMD(auth, AUTHENTICATE);
- CMD(assoc, ASSOCIATE);
- CMD(deauth, DEAUTHENTICATE);
- CMD(disassoc, DISASSOCIATE);
- CMD(join_ibss, JOIN_IBSS);
- CMD(join_mesh, JOIN_MESH);
- CMD(set_pmksa, SET_PMKSA);
- CMD(del_pmksa, DEL_PMKSA);
- CMD(flush_pmksa, FLUSH_PMKSA);
- if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
- CMD(remain_on_channel, REMAIN_ON_CHANNEL);
- CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
- CMD(mgmt_tx, FRAME);
- CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
- if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
- i++;
- if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
- goto nla_put_failure;
+static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
+ struct sk_buff *msg, u32 portid, u32 seq,
+ int flags, bool split, long *split_start,
+ long *band_start, long *chan_start)
+{
+ void *hdr;
+ struct nlattr *nl_bands, *nl_band;
+ struct nlattr *nl_freqs, *nl_freq;
+ struct nlattr *nl_cmds;
+ enum ieee80211_band band;
+ struct ieee80211_channel *chan;
+ int i;
+ const struct ieee80211_txrx_stypes *mgmt_stypes =
+ dev->wiphy.mgmt_stypes;
+ long start = 0, start_chan = 0, start_band = 0;
+ u32 features;
+
+ hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_WIPHY);
+ if (!hdr)
+ return -ENOBUFS;
+
+ /* allow always using the variables */
+ if (!split) {
+ split_start = &start;
+ band_start = &start_band;
+ chan_start = &start_chan;
}
- if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
- dev->ops->join_mesh) {
- i++;
- if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx) ||
+ nla_put_string(msg, NL80211_ATTR_WIPHY_NAME,
+ wiphy_name(&dev->wiphy)) ||
+ nla_put_u32(msg, NL80211_ATTR_GENERATION,
+ cfg80211_rdev_list_generation))
+ goto nla_put_failure;
+
+ switch (*split_start) {
+ case 0:
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT,
+ dev->wiphy.retry_short) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_RETRY_LONG,
+ dev->wiphy.retry_long) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ dev->wiphy.frag_threshold) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+ dev->wiphy.rts_threshold) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS,
+ dev->wiphy.coverage_class) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+ dev->wiphy.max_scan_ssids) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+ dev->wiphy.max_sched_scan_ssids) ||
+ nla_put_u16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+ dev->wiphy.max_scan_ie_len) ||
+ nla_put_u16(msg, NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+ dev->wiphy.max_sched_scan_ie_len) ||
+ nla_put_u8(msg, NL80211_ATTR_MAX_MATCH_SETS,
+ dev->wiphy.max_match_sets))
goto nla_put_failure;
- }
- CMD(set_wds_peer, SET_WDS_PEER);
- if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
- CMD(tdls_mgmt, TDLS_MGMT);
- CMD(tdls_oper, TDLS_OPER);
- }
- if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
- CMD(sched_scan_start, START_SCHED_SCAN);
- CMD(probe_client, PROBE_CLIENT);
- CMD(set_noack_map, SET_NOACK_MAP);
- if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
- i++;
- if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
+
+ if ((dev->wiphy.flags & WIPHY_FLAG_IBSS_RSN) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_IBSS_RSN))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_MESH_AUTH) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_MESH_AUTH))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
+ nla_put_flag(msg, NL80211_ATTR_SUPPORT_AP_UAPSD))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_FW_ROAM) &&
+ nla_put_flag(msg, NL80211_ATTR_ROAM_SUPPORT))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_SUPPORT))
+ goto nla_put_failure;
+ if ((dev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP) &&
+ nla_put_flag(msg, NL80211_ATTR_TDLS_EXTERNAL_SETUP))
goto nla_put_failure;
- }
- CMD(start_p2p_device, START_P2P_DEVICE);
- CMD(set_mcast_rate, SET_MCAST_RATE);
-#ifdef CONFIG_NL80211_TESTMODE
- CMD(testmode_cmd, TESTMODE);
-#endif
+ (*split_start)++;
+ if (split)
+ break;
+ case 1:
+ if (nla_put(msg, NL80211_ATTR_CIPHER_SUITES,
+ sizeof(u32) * dev->wiphy.n_cipher_suites,
+ dev->wiphy.cipher_suites))
+ goto nla_put_failure;
-#undef CMD
+ if (nla_put_u8(msg, NL80211_ATTR_MAX_NUM_PMKIDS,
+ dev->wiphy.max_num_pmkids))
+ goto nla_put_failure;
- if (dev->ops->connect || dev->ops->auth) {
- i++;
- if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
+ if ((dev->wiphy.flags & WIPHY_FLAG_CONTROL_PORT_PROTOCOL) &&
+ nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE))
goto nla_put_failure;
- }
- if (dev->ops->disconnect || dev->ops->deauth) {
- i++;
- if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+ dev->wiphy.available_antennas_tx) ||
+ nla_put_u32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+ dev->wiphy.available_antennas_rx))
goto nla_put_failure;
- }
- nla_nest_end(msg, nl_cmds);
+ if ((dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) &&
+ nla_put_u32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+ dev->wiphy.probe_resp_offload))
+ goto nla_put_failure;
- if (dev->ops->remain_on_channel &&
- (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
- nla_put_u32(msg, NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
- dev->wiphy.max_remain_on_channel_duration))
- goto nla_put_failure;
+ if ((dev->wiphy.available_antennas_tx ||
+ dev->wiphy.available_antennas_rx) &&
+ dev->ops->get_antenna) {
+ u32 tx_ant = 0, rx_ant = 0;
+ int res;
+ res = rdev_get_antenna(dev, &tx_ant, &rx_ant);
+ if (!res) {
+ if (nla_put_u32(msg,
+ NL80211_ATTR_WIPHY_ANTENNA_TX,
+ tx_ant) ||
+ nla_put_u32(msg,
+ NL80211_ATTR_WIPHY_ANTENNA_RX,
+ rx_ant))
+ goto nla_put_failure;
+ }
+ }
- if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
- nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
- goto nla_put_failure;
+ (*split_start)++;
+ if (split)
+ break;
+ case 2:
+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
+ dev->wiphy.interface_modes))
+ goto nla_put_failure;
+ (*split_start)++;
+ if (split)
+ break;
+ case 3:
+ nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+ if (!nl_bands)
+ goto nla_put_failure;
- if (mgmt_stypes) {
- u16 stypes;
- struct nlattr *nl_ftypes, *nl_ifs;
- enum nl80211_iftype ift;
+ for (band = *band_start; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
- nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
- if (!nl_ifs)
- goto nla_put_failure;
+ sband = dev->wiphy.bands[band];
- for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
- nl_ftypes = nla_nest_start(msg, ift);
- if (!nl_ftypes)
+ if (!sband)
+ continue;
+
+ nl_band = nla_nest_start(msg, band);
+ if (!nl_band)
goto nla_put_failure;
- i = 0;
- stypes = mgmt_stypes[ift].tx;
- while (stypes) {
- if ((stypes & 1) &&
- nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
- (i << 4) | IEEE80211_FTYPE_MGMT))
+
+ switch (*chan_start) {
+ case 0:
+ if (nl80211_send_band_rateinfo(msg, sband))
goto nla_put_failure;
- stypes >>= 1;
- i++;
+ (*chan_start)++;
+ if (split)
+ break;
+ default:
+ /* add frequencies */
+ nl_freqs = nla_nest_start(
+ msg, NL80211_BAND_ATTR_FREQS);
+ if (!nl_freqs)
+ goto nla_put_failure;
+
+ for (i = *chan_start - 1;
+ i < sband->n_channels;
+ i++) {
+ nl_freq = nla_nest_start(msg, i);
+ if (!nl_freq)
+ goto nla_put_failure;
+
+ chan = &sband->channels[i];
+
+ if (nl80211_msg_put_channel(msg, chan,
+ split))
+ goto nla_put_failure;
+
+ nla_nest_end(msg, nl_freq);
+ if (split)
+ break;
+ }
+ if (i < sband->n_channels)
+ *chan_start = i + 2;
+ else
+ *chan_start = 0;
+ nla_nest_end(msg, nl_freqs);
+ }
+
+ nla_nest_end(msg, nl_band);
+
+ if (split) {
+ /* start again here */
+ if (*chan_start)
+ band--;
+ break;
}
- nla_nest_end(msg, nl_ftypes);
}
+ nla_nest_end(msg, nl_bands);
- nla_nest_end(msg, nl_ifs);
+ if (band < IEEE80211_NUM_BANDS)
+ *band_start = band + 1;
+ else
+ *band_start = 0;
- nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
- if (!nl_ifs)
+ /* if bands & channels are done, continue outside */
+ if (*band_start == 0 && *chan_start == 0)
+ (*split_start)++;
+ if (split)
+ break;
+ case 4:
+ nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS);
+ if (!nl_cmds)
goto nla_put_failure;
- for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
- nl_ftypes = nla_nest_start(msg, ift);
- if (!nl_ftypes)
+ i = 0;
+#define CMD(op, n) \
+ do { \
+ if (dev->ops->op) { \
+ i++; \
+ if (nla_put_u32(msg, i, NL80211_CMD_ ## n)) \
+ goto nla_put_failure; \
+ } \
+ } while (0)
+
+ CMD(add_virtual_intf, NEW_INTERFACE);
+ CMD(change_virtual_intf, SET_INTERFACE);
+ CMD(add_key, NEW_KEY);
+ CMD(start_ap, START_AP);
+ CMD(add_station, NEW_STATION);
+ CMD(add_mpath, NEW_MPATH);
+ CMD(update_mesh_config, SET_MESH_CONFIG);
+ CMD(change_bss, SET_BSS);
+ CMD(auth, AUTHENTICATE);
+ CMD(assoc, ASSOCIATE);
+ CMD(deauth, DEAUTHENTICATE);
+ CMD(disassoc, DISASSOCIATE);
+ CMD(join_ibss, JOIN_IBSS);
+ CMD(join_mesh, JOIN_MESH);
+ CMD(set_pmksa, SET_PMKSA);
+ CMD(del_pmksa, DEL_PMKSA);
+ CMD(flush_pmksa, FLUSH_PMKSA);
+ if (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)
+ CMD(remain_on_channel, REMAIN_ON_CHANNEL);
+ CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
+ CMD(mgmt_tx, FRAME);
+ CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
+ if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
- i = 0;
- stypes = mgmt_stypes[ift].rx;
- while (stypes) {
- if ((stypes & 1) &&
- nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE,
- (i << 4) | IEEE80211_FTYPE_MGMT))
- goto nla_put_failure;
- stypes >>= 1;
- i++;
- }
- nla_nest_end(msg, nl_ftypes);
}
- nla_nest_end(msg, nl_ifs);
- }
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
+ dev->ops->join_mesh) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+ goto nla_put_failure;
+ }
+ CMD(set_wds_peer, SET_WDS_PEER);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+ CMD(tdls_mgmt, TDLS_MGMT);
+ CMD(tdls_oper, TDLS_OPER);
+ }
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+ CMD(sched_scan_start, START_SCHED_SCAN);
+ CMD(probe_client, PROBE_CLIENT);
+ CMD(set_noack_map, SET_NOACK_MAP);
+ if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_REGISTER_BEACONS))
+ goto nla_put_failure;
+ }
+ CMD(start_p2p_device, START_P2P_DEVICE);
+ CMD(set_mcast_rate, SET_MCAST_RATE);
+ if (split) {
+ CMD(crit_proto_start, CRIT_PROTOCOL_START);
+ CMD(crit_proto_stop, CRIT_PROTOCOL_STOP);
+ }
-#ifdef CONFIG_PM
- if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
- struct nlattr *nl_wowlan;
+#ifdef CONFIG_NL80211_TESTMODE
+ CMD(testmode_cmd, TESTMODE);
+#endif
- nl_wowlan = nla_nest_start(msg,
- NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
- if (!nl_wowlan)
- goto nla_put_failure;
+#undef CMD
- if (((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_4WAY_HANDSHAKE) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
- ((dev->wiphy.wowlan.flags & WIPHY_WOWLAN_RFKILL_RELEASE) &&
- nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
- goto nla_put_failure;
- if (dev->wiphy.wowlan.n_patterns) {
- struct nl80211_wowlan_pattern_support pat = {
- .max_patterns = dev->wiphy.wowlan.n_patterns,
- .min_pattern_len =
- dev->wiphy.wowlan.pattern_min_len,
- .max_pattern_len =
- dev->wiphy.wowlan.pattern_max_len,
- .max_pkt_offset =
- dev->wiphy.wowlan.max_pkt_offset,
- };
- if (nla_put(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
- sizeof(pat), &pat))
+ if (dev->ops->connect || dev->ops->auth) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_CONNECT))
goto nla_put_failure;
}
- nla_nest_end(msg, nl_wowlan);
- }
+ if (dev->ops->disconnect || dev->ops->deauth) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_DISCONNECT))
+ goto nla_put_failure;
+ }
+
+ nla_nest_end(msg, nl_cmds);
+ (*split_start)++;
+ if (split)
+ break;
+ case 5:
+ if (dev->ops->remain_on_channel &&
+ (dev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL) &&
+ nla_put_u32(msg,
+ NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
+ dev->wiphy.max_remain_on_channel_duration))
+ goto nla_put_failure;
+
+ if ((dev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX) &&
+ nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK))
+ goto nla_put_failure;
+
+ if (nl80211_send_mgmt_stypes(msg, mgmt_stypes))
+ goto nla_put_failure;
+ (*split_start)++;
+ if (split)
+ break;
+ case 6:
+#ifdef CONFIG_PM
+ if (nl80211_send_wowlan(msg, dev, split))
+ goto nla_put_failure;
+ (*split_start)++;
+ if (split)
+ break;
+#else
+ (*split_start)++;
#endif
+ case 7:
+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
+ dev->wiphy.software_iftypes))
+ goto nla_put_failure;
- if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
- dev->wiphy.software_iftypes))
- goto nla_put_failure;
+ if (nl80211_put_iface_combinations(&dev->wiphy, msg, split))
+ goto nla_put_failure;
- if (nl80211_put_iface_combinations(&dev->wiphy, msg))
- goto nla_put_failure;
+ (*split_start)++;
+ if (split)
+ break;
+ case 8:
+ if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
+ nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
+ dev->wiphy.ap_sme_capa))
+ goto nla_put_failure;
- if ((dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME) &&
- nla_put_u32(msg, NL80211_ATTR_DEVICE_AP_SME,
- dev->wiphy.ap_sme_capa))
- goto nla_put_failure;
+ features = dev->wiphy.features;
+ /*
+ * We can only add the per-channel limit information if the
+ * dump is split, otherwise it makes it too big. Therefore
+ * only advertise it in that case.
+ */
+ if (split)
+ features |= NL80211_FEATURE_ADVERTISE_CHAN_LIMITS;
+ if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS, features))
+ goto nla_put_failure;
- if (nla_put_u32(msg, NL80211_ATTR_FEATURE_FLAGS,
- dev->wiphy.features))
- goto nla_put_failure;
+ if (dev->wiphy.ht_capa_mod_mask &&
+ nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
+ sizeof(*dev->wiphy.ht_capa_mod_mask),
+ dev->wiphy.ht_capa_mod_mask))
+ goto nla_put_failure;
- if (dev->wiphy.ht_capa_mod_mask &&
- nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK,
- sizeof(*dev->wiphy.ht_capa_mod_mask),
- dev->wiphy.ht_capa_mod_mask))
- goto nla_put_failure;
+ if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
+ dev->wiphy.max_acl_mac_addrs &&
+ nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
+ dev->wiphy.max_acl_mac_addrs))
+ goto nla_put_failure;
- if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME &&
- dev->wiphy.max_acl_mac_addrs &&
- nla_put_u32(msg, NL80211_ATTR_MAC_ACL_MAX,
- dev->wiphy.max_acl_mac_addrs))
- goto nla_put_failure;
+ /*
+ * Any information below this point is only available to
+ * applications that can deal with it being split. This
+ * helps ensure that newly added capabilities don't break
+ * older tools by overrunning their buffers.
+ *
+ * We still increment split_start so that in the split
+ * case we'll continue with more data in the next round,
+ * but break unconditionally so unsplit data stops here.
+ */
+ (*split_start)++;
+ break;
+ case 9:
+ if (dev->wiphy.extended_capabilities &&
+ (nla_put(msg, NL80211_ATTR_EXT_CAPA,
+ dev->wiphy.extended_capabilities_len,
+ dev->wiphy.extended_capabilities) ||
+ nla_put(msg, NL80211_ATTR_EXT_CAPA_MASK,
+ dev->wiphy.extended_capabilities_len,
+ dev->wiphy.extended_capabilities_mask)))
+ goto nla_put_failure;
+
+ if (dev->wiphy.vht_capa_mod_mask &&
+ nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK,
+ sizeof(*dev->wiphy.vht_capa_mod_mask),
+ dev->wiphy.vht_capa_mod_mask))
+ goto nla_put_failure;
+ /* done */
+ *split_start = 0;
+ break;
+ }
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -1310,39 +1562,80 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
int idx = 0, ret;
int start = cb->args[0];
struct cfg80211_registered_device *dev;
+ s64 filter_wiphy = -1;
+ bool split = false;
+ struct nlattr **tb = nl80211_fam.attrbuf;
+ int res;
mutex_lock(&cfg80211_mutex);
+ res = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+ tb, nl80211_fam.maxattr, nl80211_policy);
+ if (res == 0) {
+ split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
+ if (tb[NL80211_ATTR_WIPHY])
+ filter_wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+ if (tb[NL80211_ATTR_WDEV])
+ filter_wiphy = nla_get_u64(tb[NL80211_ATTR_WDEV]) >> 32;
+ if (tb[NL80211_ATTR_IFINDEX]) {
+ struct net_device *netdev;
+ int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+
+ netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
+ if (!netdev) {
+ mutex_unlock(&cfg80211_mutex);
+ return -ENODEV;
+ }
+ if (netdev->ieee80211_ptr) {
+ dev = wiphy_to_dev(
+ netdev->ieee80211_ptr->wiphy);
+ filter_wiphy = dev->wiphy_idx;
+ }
+ dev_put(netdev);
+ }
+ }
+
list_for_each_entry(dev, &cfg80211_rdev_list, list) {
if (!net_eq(wiphy_net(&dev->wiphy), sock_net(skb->sk)))
continue;
if (++idx <= start)
continue;
- ret = nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, NLM_F_MULTI,
- dev);
- if (ret < 0) {
- /*
- * If sending the wiphy data didn't fit (ENOBUFS or
- * EMSGSIZE returned), this SKB is still empty (so
- * it's not too big because another wiphy dataset is
- * already in the skb) and we've not tried to adjust
- * the dump allocation yet ... then adjust the alloc
- * size to be bigger, and return 1 but with the empty
- * skb. This results in an empty message being RX'ed
- * in userspace, but that is ignored.
- *
- * We can then retry with the larger buffer.
- */
- if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
- !skb->len &&
- cb->min_dump_alloc < 4096) {
- cb->min_dump_alloc = 4096;
- mutex_unlock(&cfg80211_mutex);
- return 1;
+ if (filter_wiphy != -1 && dev->wiphy_idx != filter_wiphy)
+ continue;
+ /* attempt to fit multiple wiphy data chunks into the skb */
+ do {
+ ret = nl80211_send_wiphy(dev, skb,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ NLM_F_MULTI,
+ split, &cb->args[1],
+ &cb->args[2],
+ &cb->args[3]);
+ if (ret < 0) {
+ /*
+ * If sending the wiphy data didn't fit (ENOBUFS
+ * or EMSGSIZE returned), this SKB is still
+ * empty (so it's not too big because another
+ * wiphy dataset is already in the skb) and
+ * we've not tried to adjust the dump allocation
+ * yet ... then adjust the alloc size to be
+ * bigger, and return 1 but with the empty skb.
+ * This results in an empty message being RX'ed
+ * in userspace, but that is ignored.
+ *
+ * We can then retry with the larger buffer.
+ */
+ if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
+ !skb->len &&
+ cb->min_dump_alloc < 4096) {
+ cb->min_dump_alloc = 4096;
+ mutex_unlock(&cfg80211_mutex);
+ return 1;
+ }
+ idx--;
+ break;
}
- idx--;
- break;
- }
+ } while (cb->args[1] > 0);
+ break;
}
mutex_unlock(&cfg80211_mutex);
@@ -1360,7 +1653,8 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
if (!msg)
return -ENOMEM;
- if (nl80211_send_wiphy(msg, info->snd_portid, info->snd_seq, 0, dev) < 0) {
+ if (nl80211_send_wiphy(dev, msg, info->snd_portid, info->snd_seq, 0,
+ false, NULL, NULL, NULL) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -2967,6 +3261,7 @@ static int parse_station_flags(struct genl_info *info,
sta_flags = nla_data(nla);
params->sta_flags_mask = sta_flags->mask;
params->sta_flags_set = sta_flags->set;
+ params->sta_flags_set &= params->sta_flags_mask;
if ((params->sta_flags_mask |
params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
return -EINVAL;
@@ -3241,15 +3536,20 @@ static int nl80211_dump_station(struct sk_buff *skb,
{
struct station_info sinfo;
struct cfg80211_registered_device *dev;
- struct net_device *netdev;
+ struct wireless_dev *wdev;
u8 mac_addr[ETH_ALEN];
- int sta_idx = cb->args[1];
+ int sta_idx = cb->args[2];
int err;
- err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
if (err)
return err;
+ if (!wdev->netdev) {
+ err = -EINVAL;
+ goto out_err;
+ }
+
if (!dev->ops->dump_station) {
err = -EOPNOTSUPP;
goto out_err;
@@ -3257,7 +3557,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
while (1) {
memset(&sinfo, 0, sizeof(sinfo));
- err = rdev_dump_station(dev, netdev, sta_idx,
+ err = rdev_dump_station(dev, wdev->netdev, sta_idx,
mac_addr, &sinfo);
if (err == -ENOENT)
break;
@@ -3267,7 +3567,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
if (nl80211_send_station(skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- dev, netdev, mac_addr,
+ dev, wdev->netdev, mac_addr,
&sinfo) < 0)
goto out;
@@ -3276,10 +3576,10 @@ static int nl80211_dump_station(struct sk_buff *skb,
out:
- cb->args[1] = sta_idx;
+ cb->args[2] = sta_idx;
err = skb->len;
out_err:
- nl80211_finish_netdev_dump(dev);
+ nl80211_finish_wdev_dump(dev);
return err;
}
@@ -3320,6 +3620,136 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
return genlmsg_reply(msg, info);
}
+int cfg80211_check_station_change(struct wiphy *wiphy,
+ struct station_parameters *params,
+ enum cfg80211_station_type statype)
+{
+ if (params->listen_interval != -1)
+ return -EINVAL;
+ if (params->aid)
+ return -EINVAL;
+
+ /* When you run into this, adjust the code below for the new flag */
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
+
+ switch (statype) {
+ case CFG80211_STA_MESH_PEER_KERNEL:
+ case CFG80211_STA_MESH_PEER_USER:
+ /*
+ * No ignoring the TDLS flag here -- the userspace mesh
+ * code doesn't have the bug of including TDLS in the
+ * mask everywhere.
+ */
+ if (params->sta_flags_mask &
+ ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_MFP) |
+ BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return -EINVAL;
+ break;
+ case CFG80211_STA_TDLS_PEER_SETUP:
+ case CFG80211_STA_TDLS_PEER_ACTIVE:
+ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
+ return -EINVAL;
+ /* ignore since it can't change */
+ params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+ break;
+ default:
+ /* disallow mesh-specific things */
+ if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+ return -EINVAL;
+ if (params->local_pm)
+ return -EINVAL;
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
+ return -EINVAL;
+ }
+
+ if (statype != CFG80211_STA_TDLS_PEER_SETUP &&
+ statype != CFG80211_STA_TDLS_PEER_ACTIVE) {
+ /* TDLS can't be set, ... */
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+ return -EINVAL;
+ /*
+ * ... but don't bother the driver with it. This works around
+ * a hostapd/wpa_supplicant issue -- it always includes the
+ * TLDS_PEER flag in the mask even for AP mode.
+ */
+ params->sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
+ }
+
+ if (statype != CFG80211_STA_TDLS_PEER_SETUP) {
+ /* reject other things that can't change */
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD)
+ return -EINVAL;
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_CAPABILITY)
+ return -EINVAL;
+ if (params->supported_rates)
+ return -EINVAL;
+ if (params->ext_capab || params->ht_capa || params->vht_capa)
+ return -EINVAL;
+ }
+
+ if (statype != CFG80211_STA_AP_CLIENT) {
+ if (params->vlan)
+ return -EINVAL;
+ }
+
+ switch (statype) {
+ case CFG80211_STA_AP_MLME_CLIENT:
+ /* Use this only for authorizing/unauthorizing a station */
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return -EOPNOTSUPP;
+ break;
+ case CFG80211_STA_AP_CLIENT:
+ /* accept only the listed bits */
+ if (params->sta_flags_mask &
+ ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
+ BIT(NL80211_STA_FLAG_WME) |
+ BIT(NL80211_STA_FLAG_MFP)))
+ return -EINVAL;
+
+ /* but authenticated/associated only if driver handles it */
+ if (!(wiphy->features & NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
+ params->sta_flags_mask &
+ (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_ASSOCIATED)))
+ return -EINVAL;
+ break;
+ case CFG80211_STA_IBSS:
+ case CFG80211_STA_AP_STA:
+ /* reject any changes other than AUTHORIZED */
+ if (params->sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
+ return -EINVAL;
+ break;
+ case CFG80211_STA_TDLS_PEER_SETUP:
+ /* reject any changes other than AUTHORIZED or WME */
+ if (params->sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
+ BIT(NL80211_STA_FLAG_WME)))
+ return -EINVAL;
+ /* force (at least) rates when authorizing */
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
+ !params->supported_rates)
+ return -EINVAL;
+ break;
+ case CFG80211_STA_TDLS_PEER_ACTIVE:
+ /* reject any changes */
+ return -EINVAL;
+ case CFG80211_STA_MESH_PEER_KERNEL:
+ if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE)
+ return -EINVAL;
+ break;
+ case CFG80211_STA_MESH_PEER_USER:
+ if (params->plink_action != NL80211_PLINK_ACTION_NO_ACTION)
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_check_station_change);
+
/*
* Get vlan interface making sure it is running and on the right wiphy.
*/
@@ -3342,6 +3772,13 @@ static struct net_device *get_vlan(struct genl_info *info,
goto error;
}
+ if (v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+ v->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ v->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+ ret = -EINVAL;
+ goto error;
+ }
+
if (!netif_running(v)) {
ret = -ENETDOWN;
goto error;
@@ -3359,21 +3796,13 @@ nl80211_sta_wme_policy[NL80211_STA_WME_MAX + 1] __read_mostly = {
[NL80211_STA_WME_MAX_SP] = { .type = NLA_U8 },
};
-static int nl80211_set_station_tdls(struct genl_info *info,
- struct station_parameters *params)
+static int nl80211_parse_sta_wme(struct genl_info *info,
+ struct station_parameters *params)
{
struct nlattr *tb[NL80211_STA_WME_MAX + 1];
struct nlattr *nla;
int err;
- /* Dummy STA entry gets updated once the peer capabilities are known */
- if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
- params->ht_capa =
- nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
- if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- params->vht_capa =
- nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
-
/* parse WME attributes if present */
if (!info->attrs[NL80211_ATTR_STA_WME])
return 0;
@@ -3401,18 +3830,34 @@ static int nl80211_set_station_tdls(struct genl_info *info,
return 0;
}
+static int nl80211_set_station_tdls(struct genl_info *info,
+ struct station_parameters *params)
+{
+ /* Dummy STA entry gets updated once the peer capabilities are known */
+ if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
+ params->ht_capa =
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY])
+ params->vht_capa =
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
+
+ return nl80211_parse_sta_wme(info, params);
+}
+
static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
- int err;
struct net_device *dev = info->user_ptr[1];
struct station_parameters params;
- u8 *mac_addr = NULL;
+ u8 *mac_addr;
+ int err;
memset(&params, 0, sizeof(params));
params.listen_interval = -1;
- params.plink_state = -1;
+
+ if (!rdev->ops->change_station)
+ return -EOPNOTSUPP;
if (info->attrs[NL80211_ATTR_STA_AID])
return -EINVAL;
@@ -3445,19 +3890,23 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
return -EINVAL;
- if (!rdev->ops->change_station)
- return -EOPNOTSUPP;
-
if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
return -EINVAL;
- if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
params.plink_action =
- nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
+ return -EINVAL;
+ }
- if (info->attrs[NL80211_ATTR_STA_PLINK_STATE])
+ if (info->attrs[NL80211_ATTR_STA_PLINK_STATE]) {
params.plink_state =
- nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
+ if (params.plink_state >= NUM_NL80211_PLINK_STATES)
+ return -EINVAL;
+ params.sta_modify_mask |= STATION_PARAM_APPLY_PLINK_STATE;
+ }
if (info->attrs[NL80211_ATTR_LOCAL_MESH_POWER_MODE]) {
enum nl80211_mesh_power_mode pm = nla_get_u32(
@@ -3470,127 +3919,33 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.local_pm = pm;
}
+ /* Include parameters for TDLS peer (will check later) */
+ err = nl80211_set_station_tdls(info, &params);
+ if (err)
+ return err;
+
+ params.vlan = get_vlan(info, rdev);
+ if (IS_ERR(params.vlan))
+ return PTR_ERR(params.vlan);
+
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
- /* disallow mesh-specific things */
- if (params.plink_action)
- return -EINVAL;
- if (params.local_pm)
- return -EINVAL;
-
- /* TDLS can't be set, ... */
- if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
- return -EINVAL;
- /*
- * ... but don't bother the driver with it. This works around
- * a hostapd/wpa_supplicant issue -- it always includes the
- * TLDS_PEER flag in the mask even for AP mode.
- */
- params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
-
- /* accept only the listed bits */
- if (params.sta_flags_mask &
- ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
- BIT(NL80211_STA_FLAG_AUTHENTICATED) |
- BIT(NL80211_STA_FLAG_ASSOCIATED) |
- BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
- BIT(NL80211_STA_FLAG_WME) |
- BIT(NL80211_STA_FLAG_MFP)))
- return -EINVAL;
-
- /* but authenticated/associated only if driver handles it */
- if (!(rdev->wiphy.features &
- NL80211_FEATURE_FULL_AP_CLIENT_STATE) &&
- params.sta_flags_mask &
- (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
- BIT(NL80211_STA_FLAG_ASSOCIATED)))
- return -EINVAL;
-
- /* reject other things that can't change */
- if (params.supported_rates)
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
- info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- return -EINVAL;
-
- /* must be last in here for error handling */
- params.vlan = get_vlan(info, rdev);
- if (IS_ERR(params.vlan))
- return PTR_ERR(params.vlan);
- break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
- /*
- * Don't allow userspace to change the TDLS_PEER flag,
- * but silently ignore attempts to change it since we
- * don't have state here to verify that it doesn't try
- * to change the flag.
- */
- params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_TDLS_PEER);
- /* Include parameters for TDLS peer (driver will check) */
- err = nl80211_set_station_tdls(info, &params);
- if (err)
- return err;
- /* disallow things sta doesn't support */
- if (params.plink_action)
- return -EINVAL;
- if (params.local_pm)
- return -EINVAL;
- /* reject any changes other than AUTHORIZED or WME (for TDLS) */
- if (params.sta_flags_mask & ~(BIT(NL80211_STA_FLAG_AUTHORIZED) |
- BIT(NL80211_STA_FLAG_WME)))
- return -EINVAL;
- break;
case NL80211_IFTYPE_ADHOC:
- /* disallow things sta doesn't support */
- if (params.plink_action)
- return -EINVAL;
- if (params.local_pm)
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
- info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- return -EINVAL;
- /* reject any changes other than AUTHORIZED */
- if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED))
- return -EINVAL;
- break;
case NL80211_IFTYPE_MESH_POINT:
- /* disallow things mesh doesn't support */
- if (params.vlan)
- return -EINVAL;
- if (params.supported_rates)
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_STA_CAPABILITY])
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_STA_EXT_CAPABILITY])
- return -EINVAL;
- if (info->attrs[NL80211_ATTR_HT_CAPABILITY] ||
- info->attrs[NL80211_ATTR_VHT_CAPABILITY])
- return -EINVAL;
- /*
- * No special handling for TDLS here -- the userspace
- * mesh code doesn't have this bug.
- */
- if (params.sta_flags_mask &
- ~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
- BIT(NL80211_STA_FLAG_MFP) |
- BIT(NL80211_STA_FLAG_AUTHORIZED)))
- return -EINVAL;
break;
default:
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto out_put_vlan;
}
- /* be aware of params.vlan when changing code here */
-
+ /* driver will call cfg80211_check_station_change() */
err = rdev_change_station(rdev, dev, mac_addr, &params);
+ out_put_vlan:
if (params.vlan)
dev_put(params.vlan);
@@ -3607,6 +3962,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
memset(&params, 0, sizeof(params));
+ if (!rdev->ops->add_station)
+ return -EOPNOTSUPP;
+
if (!info->attrs[NL80211_ATTR_MAC])
return -EINVAL;
@@ -3652,50 +4010,32 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.vht_capa =
nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]);
- if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+ if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) {
params.plink_action =
- nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ if (params.plink_action >= NUM_NL80211_PLINK_ACTIONS)
+ return -EINVAL;
+ }
- if (!rdev->ops->add_station)
- return -EOPNOTSUPP;
+ err = nl80211_parse_sta_wme(info, &params);
+ if (err)
+ return err;
if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
return -EINVAL;
+ /* When you run into this, adjust the code below for the new flag */
+ BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
+
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
- /* parse WME attributes if sta is WME capable */
- if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
- (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
- info->attrs[NL80211_ATTR_STA_WME]) {
- struct nlattr *tb[NL80211_STA_WME_MAX + 1];
- struct nlattr *nla;
-
- nla = info->attrs[NL80211_ATTR_STA_WME];
- err = nla_parse_nested(tb, NL80211_STA_WME_MAX, nla,
- nl80211_sta_wme_policy);
- if (err)
- return err;
+ /* ignore WME attributes if iface/sta is not capable */
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) ||
+ !(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)))
+ params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
- if (tb[NL80211_STA_WME_UAPSD_QUEUES])
- params.uapsd_queues =
- nla_get_u8(tb[NL80211_STA_WME_UAPSD_QUEUES]);
- if (params.uapsd_queues &
- ~IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK)
- return -EINVAL;
-
- if (tb[NL80211_STA_WME_MAX_SP])
- params.max_sp =
- nla_get_u8(tb[NL80211_STA_WME_MAX_SP]);
-
- if (params.max_sp &
- ~IEEE80211_WMM_IE_STA_QOSINFO_SP_MASK)
- return -EINVAL;
-
- params.sta_modify_mask |= STATION_PARAM_APPLY_UAPSD;
- }
/* TDLS peers cannot be added */
if (params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
return -EINVAL;
@@ -3716,6 +4056,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return PTR_ERR(params.vlan);
break;
case NL80211_IFTYPE_MESH_POINT:
+ /* ignore uAPSD data */
+ params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
+
/* associated is disallowed */
if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
return -EINVAL;
@@ -3724,8 +4067,14 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
break;
case NL80211_IFTYPE_STATION:
- /* associated is disallowed */
- if (params.sta_flags_mask & BIT(NL80211_STA_FLAG_ASSOCIATED))
+ case NL80211_IFTYPE_P2P_CLIENT:
+ /* ignore uAPSD data */
+ params.sta_modify_mask &= ~STATION_PARAM_APPLY_UAPSD;
+
+ /* these are disallowed */
+ if (params.sta_flags_mask &
+ (BIT(NL80211_STA_FLAG_ASSOCIATED) |
+ BIT(NL80211_STA_FLAG_AUTHENTICATED)))
return -EINVAL;
/* Only TDLS peers can be added */
if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)))
@@ -3736,6 +4085,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
/* ... with external setup is supported */
if (!(rdev->wiphy.flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
return -EOPNOTSUPP;
+ /*
+ * Older wpa_supplicant versions always mark the TDLS peer
+ * as authorized, but it shouldn't yet be.
+ */
+ params.sta_flags_mask &= ~BIT(NL80211_STA_FLAG_AUTHORIZED);
break;
default:
return -EOPNOTSUPP;
@@ -3829,13 +4183,13 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
{
struct mpath_info pinfo;
struct cfg80211_registered_device *dev;
- struct net_device *netdev;
+ struct wireless_dev *wdev;
u8 dst[ETH_ALEN];
u8 next_hop[ETH_ALEN];
- int path_idx = cb->args[1];
+ int path_idx = cb->args[2];
int err;
- err = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ err = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
if (err)
return err;
@@ -3844,14 +4198,14 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
goto out_err;
}
- if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
+ if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
err = -EOPNOTSUPP;
goto out_err;
}
while (1) {
- err = rdev_dump_mpath(dev, netdev, path_idx, dst, next_hop,
- &pinfo);
+ err = rdev_dump_mpath(dev, wdev->netdev, path_idx, dst,
+ next_hop, &pinfo);
if (err == -ENOENT)
break;
if (err)
@@ -3859,7 +4213,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- netdev, dst, next_hop,
+ wdev->netdev, dst, next_hop,
&pinfo) < 0)
goto out;
@@ -3868,10 +4222,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
out:
- cb->args[1] = path_idx;
+ cb->args[2] = path_idx;
err = skb->len;
out_err:
- nl80211_finish_netdev_dump(dev);
+ nl80211_finish_wdev_dump(dev);
return err;
}
@@ -4280,6 +4634,7 @@ static const struct nla_policy
[NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 },
[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
+ [NL80211_MESH_SETUP_USERSPACE_MPM] = { .type = NLA_FLAG },
[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
[NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
@@ -4418,6 +4773,7 @@ do { \
static int nl80211_parse_mesh_setup(struct genl_info *info,
struct mesh_setup *setup)
{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct nlattr *tb[NL80211_MESH_SETUP_ATTR_MAX + 1];
if (!info->attrs[NL80211_ATTR_MESH_SETUP])
@@ -4454,8 +4810,14 @@ static int nl80211_parse_mesh_setup(struct genl_info *info,
setup->ie = nla_data(ieattr);
setup->ie_len = nla_len(ieattr);
}
+ if (tb[NL80211_MESH_SETUP_USERSPACE_MPM] &&
+ !(rdev->wiphy.features & NL80211_FEATURE_USERSPACE_MPM))
+ return -EINVAL;
+ setup->user_mpm = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_MPM]);
setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
+ if (setup->is_secure)
+ setup->user_mpm = true;
return 0;
}
@@ -4702,14 +5064,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->scan)
return -EOPNOTSUPP;
- if (rdev->scan_req)
- return -EBUSY;
+ mutex_lock(&rdev->sched_scan_mtx);
+ if (rdev->scan_req) {
+ err = -EBUSY;
+ goto unlock;
+ }
if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
n_channels = validate_scan_freqs(
info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
- if (!n_channels)
- return -EINVAL;
+ if (!n_channels) {
+ err = -EINVAL;
+ goto unlock;
+ }
} else {
enum ieee80211_band band;
n_channels = 0;
@@ -4723,23 +5090,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
n_ssids++;
- if (n_ssids > wiphy->max_scan_ssids)
- return -EINVAL;
+ if (n_ssids > wiphy->max_scan_ssids) {
+ err = -EINVAL;
+ goto unlock;
+ }
if (info->attrs[NL80211_ATTR_IE])
ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
else
ie_len = 0;
- if (ie_len > wiphy->max_scan_ie_len)
- return -EINVAL;
+ if (ie_len > wiphy->max_scan_ie_len) {
+ err = -EINVAL;
+ goto unlock;
+ }
request = kzalloc(sizeof(*request)
+ sizeof(*request->ssids) * n_ssids
+ sizeof(*request->channels) * n_channels
+ ie_len, GFP_KERNEL);
- if (!request)
- return -ENOMEM;
+ if (!request) {
+ err = -ENOMEM;
+ goto unlock;
+ }
if (n_ssids)
request->ssids = (void *)&request->channels[n_channels];
@@ -4876,6 +5249,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
kfree(request);
}
+ unlock:
+ mutex_unlock(&rdev->sched_scan_mtx);
return err;
}
@@ -5206,9 +5581,13 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
genl_dump_check_consistent(cb, hdr, &nl80211_fam);
- if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation) ||
+ if (nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->bss_generation))
+ goto nla_put_failure;
+ if (wdev->netdev &&
nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex))
goto nla_put_failure;
+ if (nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+ goto nla_put_failure;
bss = nla_nest_start(msg, NL80211_ATTR_BSS);
if (!bss)
@@ -5288,22 +5667,18 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
return -EMSGSIZE;
}
-static int nl80211_dump_scan(struct sk_buff *skb,
- struct netlink_callback *cb)
+static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
{
struct cfg80211_registered_device *rdev;
- struct net_device *dev;
struct cfg80211_internal_bss *scan;
struct wireless_dev *wdev;
- int start = cb->args[1], idx = 0;
+ int start = cb->args[2], idx = 0;
int err;
- err = nl80211_prepare_netdev_dump(skb, cb, &rdev, &dev);
+ err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (err)
return err;
- wdev = dev->ieee80211_ptr;
-
wdev_lock(wdev);
spin_lock_bh(&rdev->bss_lock);
cfg80211_bss_expire(rdev);
@@ -5324,8 +5699,8 @@ static int nl80211_dump_scan(struct sk_buff *skb,
spin_unlock_bh(&rdev->bss_lock);
wdev_unlock(wdev);
- cb->args[1] = idx;
- nl80211_finish_netdev_dump(rdev);
+ cb->args[2] = idx;
+ nl80211_finish_wdev_dump(rdev);
return skb->len;
}
@@ -5394,14 +5769,19 @@ static int nl80211_dump_survey(struct sk_buff *skb,
{
struct survey_info survey;
struct cfg80211_registered_device *dev;
- struct net_device *netdev;
- int survey_idx = cb->args[1];
+ struct wireless_dev *wdev;
+ int survey_idx = cb->args[2];
int res;
- res = nl80211_prepare_netdev_dump(skb, cb, &dev, &netdev);
+ res = nl80211_prepare_wdev_dump(skb, cb, &dev, &wdev);
if (res)
return res;
+ if (!wdev->netdev) {
+ res = -EINVAL;
+ goto out_err;
+ }
+
if (!dev->ops->dump_survey) {
res = -EOPNOTSUPP;
goto out_err;
@@ -5410,7 +5790,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
while (1) {
struct ieee80211_channel *chan;
- res = rdev_dump_survey(dev, netdev, survey_idx, &survey);
+ res = rdev_dump_survey(dev, wdev->netdev, survey_idx, &survey);
if (res == -ENOENT)
break;
if (res)
@@ -5432,17 +5812,16 @@ static int nl80211_dump_survey(struct sk_buff *skb,
if (nl80211_send_survey(skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
- netdev,
- &survey) < 0)
+ wdev->netdev, &survey) < 0)
goto out;
survey_idx++;
}
out:
- cb->args[1] = survey_idx;
+ cb->args[2] = survey_idx;
res = skb->len;
out_err:
- nl80211_finish_netdev_dump(dev);
+ nl80211_finish_wdev_dump(dev);
return res;
}
@@ -5650,14 +6029,10 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
- struct cfg80211_crypto_settings crypto;
struct ieee80211_channel *chan;
- const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
- int err, ssid_len, ie_len = 0;
- bool use_mfp = false;
- u32 flags = 0;
- struct ieee80211_ht_cap *ht_capa = NULL;
- struct ieee80211_ht_cap *ht_capa_mask = NULL;
+ struct cfg80211_assoc_request req = {};
+ const u8 *bssid, *ssid;
+ int err, ssid_len = 0;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
return -EINVAL;
@@ -5685,41 +6060,58 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
if (info->attrs[NL80211_ATTR_IE]) {
- ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
if (info->attrs[NL80211_ATTR_USE_MFP]) {
enum nl80211_mfp mfp =
nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
if (mfp == NL80211_MFP_REQUIRED)
- use_mfp = true;
+ req.use_mfp = true;
else if (mfp != NL80211_MFP_NO)
return -EINVAL;
}
if (info->attrs[NL80211_ATTR_PREV_BSSID])
- prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
+ req.prev_bssid = nla_data(info->attrs[NL80211_ATTR_PREV_BSSID]);
if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_HT]))
- flags |= ASSOC_REQ_DISABLE_HT;
+ req.flags |= ASSOC_REQ_DISABLE_HT;
if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
- ht_capa_mask =
- nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]);
+ memcpy(&req.ht_capa_mask,
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]),
+ sizeof(req.ht_capa_mask));
if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
- if (!ht_capa_mask)
+ if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
return -EINVAL;
- ht_capa = nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
+ memcpy(&req.ht_capa,
+ nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
+ sizeof(req.ht_capa));
}
- err = nl80211_crypto_settings(rdev, info, &crypto, 1);
+ if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
+ req.flags |= ASSOC_REQ_DISABLE_VHT;
+
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+ memcpy(&req.vht_capa_mask,
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
+ sizeof(req.vht_capa_mask));
+
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
+ if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+ return -EINVAL;
+ memcpy(&req.vht_capa,
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
+ sizeof(req.vht_capa));
+ }
+
+ err = nl80211_crypto_settings(rdev, info, &req.crypto, 1);
if (!err)
- err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
- ssid, ssid_len, ie, ie_len, use_mfp,
- &crypto, flags, ht_capa,
- ht_capa_mask);
+ err = cfg80211_mlme_assoc(rdev, dev, chan, bssid,
+ ssid, ssid_len, &req);
return err;
}
@@ -6299,6 +6691,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
sizeof(connect.ht_capa));
}
+ if (nla_get_flag(info->attrs[NL80211_ATTR_DISABLE_VHT]))
+ connect.flags |= ASSOC_REQ_DISABLE_VHT;
+
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK])
+ memcpy(&connect.vht_capa_mask,
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]),
+ sizeof(connect.vht_capa_mask));
+
+ if (info->attrs[NL80211_ATTR_VHT_CAPABILITY]) {
+ if (!info->attrs[NL80211_ATTR_VHT_CAPABILITY_MASK]) {
+ kfree(connkeys);
+ return -EINVAL;
+ }
+ memcpy(&connect.vht_capa,
+ nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]),
+ sizeof(connect.vht_capa));
+ }
+
err = cfg80211_connect(rdev, dev, &connect, connkeys);
if (err)
kfree(connkeys);
@@ -7072,6 +7482,9 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
return err;
}
+ if (setup.user_mpm)
+ cfg.auto_open_plinks = false;
+
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
err = nl80211_parse_chandef(rdev, info, &setup.chandef);
if (err)
@@ -7271,7 +7684,8 @@ static int nl80211_parse_wowlan_tcp(struct cfg80211_registered_device *rdev,
return -EINVAL;
if (nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) >
- rdev->wiphy.wowlan.tcp->data_interval_max)
+ rdev->wiphy.wowlan.tcp->data_interval_max ||
+ nla_get_u32(tb[NL80211_WOWLAN_TCP_DATA_INTERVAL]) == 0)
return -EINVAL;
wake_size = nla_len(tb[NL80211_WOWLAN_TCP_WAKE_PAYLOAD]);
@@ -7749,21 +8163,118 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->stop_p2p_device)
return -EOPNOTSUPP;
- if (!wdev->p2p_started)
- return 0;
-
- rdev_stop_p2p_device(rdev, wdev);
- wdev->p2p_started = false;
-
mutex_lock(&rdev->devlist_mtx);
- rdev->opencount--;
+ mutex_lock(&rdev->sched_scan_mtx);
+ cfg80211_stop_p2p_device(rdev, wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
- if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
- rdev->scan_req->aborted = true;
- ___cfg80211_scan_done(rdev, true);
- }
+ return 0;
+}
+
+static int nl80211_get_protocol_features(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ void *hdr;
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
+ NL80211_CMD_GET_PROTOCOL_FEATURES);
+ if (!hdr)
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL80211_ATTR_PROTOCOL_FEATURES,
+ NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+ return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+ kfree_skb(msg);
+ return -ENOBUFS;
+}
+
+static int nl80211_update_ft_ies(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct cfg80211_update_ft_ies_params ft_params;
+ struct net_device *dev = info->user_ptr[1];
+
+ if (!rdev->ops->update_ft_ies)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MDID] ||
+ !is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ memset(&ft_params, 0, sizeof(ft_params));
+ ft_params.md = nla_get_u16(info->attrs[NL80211_ATTR_MDID]);
+ ft_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ ft_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+
+ return rdev_update_ft_ies(rdev, dev, &ft_params);
+}
+
+static int nl80211_crit_protocol_start(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+ enum nl80211_crit_proto_id proto = NL80211_CRIT_PROTO_UNSPEC;
+ u16 duration;
+ int ret;
+
+ if (!rdev->ops->crit_proto_start)
+ return -EOPNOTSUPP;
+
+ if (WARN_ON(!rdev->ops->crit_proto_stop))
+ return -EINVAL;
+
+ if (rdev->crit_proto_nlportid)
+ return -EBUSY;
+
+ /* determine protocol if provided */
+ if (info->attrs[NL80211_ATTR_CRIT_PROT_ID])
+ proto = nla_get_u16(info->attrs[NL80211_ATTR_CRIT_PROT_ID]);
+
+ if (proto >= NUM_NL80211_CRIT_PROTO)
+ return -EINVAL;
+
+ /* timeout must be provided */
+ if (!info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION])
+ return -EINVAL;
+
+ duration =
+ nla_get_u16(info->attrs[NL80211_ATTR_MAX_CRIT_PROT_DURATION]);
+ if (duration > NL80211_CRIT_PROTO_MAX_DURATION)
+ return -ERANGE;
+
+ ret = rdev_crit_proto_start(rdev, wdev, proto, duration);
+ if (!ret)
+ rdev->crit_proto_nlportid = info->snd_portid;
+
+ return ret;
+}
+
+static int nl80211_crit_protocol_stop(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct wireless_dev *wdev = info->user_ptr[1];
+
+ if (!rdev->ops->crit_proto_stop)
+ return -EOPNOTSUPP;
+
+ if (rdev->crit_proto_nlportid) {
+ rdev->crit_proto_nlportid = 0;
+ rdev_crit_proto_stop(rdev, wdev);
+ }
return 0;
}
@@ -8443,6 +8954,35 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
+ .doit = nl80211_get_protocol_features,
+ .policy = nl80211_policy,
+ },
+ {
+ .cmd = NL80211_CMD_UPDATE_FT_IES,
+ .doit = nl80211_update_ft_ies,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_CRIT_PROTOCOL_START,
+ .doit = nl80211_crit_protocol_start,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_CRIT_PROTOCOL_STOP,
+ .doit = nl80211_crit_protocol_stop,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ }
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -8470,7 +9010,8 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
if (!msg)
return;
- if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
+ if (nl80211_send_wiphy(rdev, msg, 0, 0, 0,
+ false, NULL, NULL, NULL) < 0) {
nlmsg_free(msg);
return;
}
@@ -8486,7 +9027,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
struct nlattr *nest;
int i;
- ASSERT_RDEV_LOCK(rdev);
+ lockdep_assert_held(&rdev->sched_scan_mtx);
if (WARN_ON(!req))
return 0;
@@ -8794,21 +9335,31 @@ void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
NL80211_CMD_DISASSOCIATE, gfp);
}
-void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+void cfg80211_send_unprot_deauth(struct net_device *dev, const u8 *buf,
+ size_t len)
{
- nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_UNPROT_DEAUTHENTICATE, gfp);
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_send_unprot_deauth(dev);
+ nl80211_send_mlme_event(rdev, dev, buf, len,
+ NL80211_CMD_UNPROT_DEAUTHENTICATE, GFP_ATOMIC);
}
+EXPORT_SYMBOL(cfg80211_send_unprot_deauth);
-void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *buf,
- size_t len, gfp_t gfp)
+void cfg80211_send_unprot_disassoc(struct net_device *dev, const u8 *buf,
+ size_t len)
{
- nl80211_send_mlme_event(rdev, netdev, buf, len,
- NL80211_CMD_UNPROT_DISASSOCIATE, gfp);
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_send_unprot_disassoc(dev);
+ nl80211_send_mlme_event(rdev, dev, buf, len,
+ NL80211_CMD_UNPROT_DISASSOCIATE, GFP_ATOMIC);
}
+EXPORT_SYMBOL(cfg80211_send_unprot_disassoc);
static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev, int cmd,
@@ -9011,14 +9562,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
-void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *macaddr, const u8* ie, u8 ie_len,
- gfp_t gfp)
+void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
+ const u8* ie, u8 ie_len, gfp_t gfp)
{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct sk_buff *msg;
void *hdr;
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
+ return;
+
+ trace_cfg80211_notify_new_peer_candidate(dev, addr);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9030,8 +9586,8 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
- nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
- nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, macaddr) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
(ie_len && ie &&
nla_put(msg, NL80211_ATTR_IE, ie_len , ie)))
goto nla_put_failure;
@@ -9046,6 +9602,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_notify_new_peer_candidate);
void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
@@ -9114,7 +9671,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
if (!nl_freq)
goto nla_put_failure;
- if (nl80211_msg_put_channel(msg, channel_before))
+ if (nl80211_msg_put_channel(msg, channel_before, false))
goto nla_put_failure;
nla_nest_end(msg, nl_freq);
@@ -9122,7 +9679,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
if (!nl_freq)
goto nla_put_failure;
- if (nl80211_msg_put_channel(msg, channel_after))
+ if (nl80211_msg_put_channel(msg, channel_after, false))
goto nla_put_failure;
nla_nest_end(msg, nl_freq);
@@ -9184,31 +9741,42 @@ static void nl80211_send_remain_on_chan_event(
nlmsg_free(msg);
}
-void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, u64 cookie,
- struct ieee80211_channel *chan,
- unsigned int duration, gfp_t gfp)
+void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
+ struct ieee80211_channel *chan,
+ unsigned int duration, gfp_t gfp)
{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
rdev, wdev, cookie, chan,
duration, gfp);
}
+EXPORT_SYMBOL(cfg80211_ready_on_channel);
-void nl80211_send_remain_on_channel_cancel(
- struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev,
- u64 cookie, struct ieee80211_channel *chan, gfp_t gfp)
+void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
+ struct ieee80211_channel *chan,
+ gfp_t gfp)
{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
rdev, wdev, cookie, chan, 0, gfp);
}
+EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
-void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- struct station_info *sinfo, gfp_t gfp)
+void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
+ struct station_info *sinfo, gfp_t gfp)
{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
+ trace_cfg80211_new_sta(dev, mac_addr, sinfo);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9222,14 +9790,17 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
}
+EXPORT_SYMBOL(cfg80211_new_sta);
-void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- gfp_t gfp)
+void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
void *hdr;
+ trace_cfg80211_del_sta(dev, mac_addr);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9254,12 +9825,14 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_del_sta);
-void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- enum nl80211_connect_failed_reason reason,
- gfp_t gfp)
+void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
+ enum nl80211_connect_failed_reason reason,
+ gfp_t gfp)
{
+ struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
void *hdr;
@@ -9288,6 +9861,7 @@ void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_conn_failed);
static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
const u8 *addr, gfp_t gfp)
@@ -9332,19 +9906,47 @@ static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
return true;
}
-bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+ const u8 *addr, gfp_t gfp)
{
- return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
- addr, gfp);
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ bool ret;
+
+ trace_cfg80211_rx_spurious_frame(dev, addr);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
+ trace_cfg80211_return_bool(false);
+ return false;
+ }
+ ret = __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
+ addr, gfp);
+ trace_cfg80211_return_bool(ret);
+ return ret;
}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
-bool nl80211_unexpected_4addr_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp)
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+ const u8 *addr, gfp_t gfp)
{
- return __nl80211_unexpected_frame(dev,
- NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
- addr, gfp);
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ bool ret;
+
+ trace_cfg80211_rx_unexpected_4addr_frame(dev, addr);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+ wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
+ trace_cfg80211_return_bool(false);
+ return false;
+ }
+ ret = __nl80211_unexpected_frame(dev,
+ NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+ addr, gfp);
+ trace_cfg80211_return_bool(ret);
+ return ret;
}
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlportid,
@@ -9384,15 +9986,17 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
return -ENOBUFS;
}
-void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, u64 cookie,
- const u8 *buf, size_t len, bool ack,
- gfp_t gfp)
+void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
+ const u8 *buf, size_t len, bool ack, gfp_t gfp)
{
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
void *hdr;
+ trace_cfg80211_mgmt_tx_status(wdev, cookie, ack);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9420,17 +10024,21 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
-void
-nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- enum nl80211_cqm_rssi_threshold_event rssi_event,
- gfp_t gfp)
+void cfg80211_cqm_rssi_notify(struct net_device *dev,
+ enum nl80211_cqm_rssi_threshold_event rssi_event,
+ gfp_t gfp)
{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
struct nlattr *pinfoattr;
void *hdr;
+ trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9442,7 +10050,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
- nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
goto nla_put_failure;
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
@@ -9465,10 +10073,11 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
-void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *replay_ctr, gfp_t gfp)
+static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, const u8 *bssid,
+ const u8 *replay_ctr, gfp_t gfp)
{
struct sk_buff *msg;
struct nlattr *rekey_attr;
@@ -9510,9 +10119,22 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
-void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, int index,
- const u8 *bssid, bool preauth, gfp_t gfp)
+void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
+ const u8 *replay_ctr, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_gtk_rekey_notify(dev, bssid);
+ nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
+
+static void
+nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp)
{
struct sk_buff *msg;
struct nlattr *attr;
@@ -9555,9 +10177,22 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
-void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- struct cfg80211_chan_def *chandef, gfp_t gfp)
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+ const u8 *bssid, bool preauth, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_pmksa_candidate_notify(dev, index, bssid, preauth);
+ nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
+}
+EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ struct cfg80211_chan_def *chandef,
+ gfp_t gfp)
{
struct sk_buff *msg;
void *hdr;
@@ -9589,11 +10224,36 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
-void
-nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *peer,
- u32 num_packets, u32 rate, u32 intvl, gfp_t gfp)
+void cfg80211_ch_switch_notify(struct net_device *dev,
+ struct cfg80211_chan_def *chandef)
{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ trace_cfg80211_ch_switch_notify(dev, chandef);
+
+ wdev_lock(wdev);
+
+ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO))
+ goto out;
+
+ wdev->channel = chandef->chan;
+ nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
+out:
+ wdev_unlock(wdev);
+ return;
+}
+EXPORT_SYMBOL(cfg80211_ch_switch_notify);
+
+void cfg80211_cqm_txe_notify(struct net_device *dev,
+ const u8 *peer, u32 num_packets,
+ u32 rate, u32 intvl, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
struct nlattr *pinfoattr;
void *hdr;
@@ -9609,7 +10269,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
- nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
goto nla_put_failure;
@@ -9638,6 +10298,7 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@@ -9690,15 +10351,18 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
-void
-nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *peer,
- u32 num_packets, gfp_t gfp)
+void cfg80211_cqm_pktloss_notify(struct net_device *dev,
+ const u8 *peer, u32 num_packets, gfp_t gfp)
{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct sk_buff *msg;
struct nlattr *pinfoattr;
void *hdr;
+ trace_cfg80211_cqm_pktloss_notify(dev, peer, num_packets);
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
@@ -9710,7 +10374,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
- nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
goto nla_put_failure;
@@ -9733,6 +10397,7 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
+EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
u64 cookie, bool acked, gfp_t gfp)
@@ -10019,6 +10684,89 @@ static struct notifier_block nl80211_netlink_notifier = {
.notifier_call = nl80211_netlink_notify,
};
+void cfg80211_ft_event(struct net_device *netdev,
+ struct cfg80211_ft_event_params *ft_event)
+{
+ struct wiphy *wiphy = netdev->ieee80211_ptr->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+
+ trace_cfg80211_ft_event(wiphy, netdev, ft_event);
+
+ if (!ft_event->target_ap)
+ return;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FT_EVENT);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+ nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, ft_event->target_ap);
+ if (ft_event->ies)
+ nla_put(msg, NL80211_ATTR_IE, ft_event->ies_len, ft_event->ies);
+ if (ft_event->ric_ies)
+ nla_put(msg, NL80211_ATTR_IE_RIC, ft_event->ric_ies_len,
+ ft_event->ric_ies);
+
+ err = genlmsg_end(msg, hdr);
+ if (err < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, GFP_KERNEL);
+}
+EXPORT_SYMBOL(cfg80211_ft_event);
+
+void cfg80211_crit_proto_stopped(struct wireless_dev *wdev, gfp_t gfp)
+{
+ struct cfg80211_registered_device *rdev;
+ struct sk_buff *msg;
+ void *hdr;
+ u32 nlportid;
+
+ rdev = wiphy_to_dev(wdev->wiphy);
+ if (!rdev->crit_proto_nlportid)
+ return;
+
+ nlportid = rdev->crit_proto_nlportid;
+ rdev->crit_proto_nlportid = 0;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CRIT_PROTOCOL_STOP);
+ if (!hdr)
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+ nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
+ return;
+
+ nla_put_failure:
+ if (hdr)
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+
+}
+EXPORT_SYMBOL(cfg80211_crit_proto_stopped);
+
/* initialisation/exit functions */
int nl80211_init(void)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index b061da4919e1..a4073e808c13 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -29,12 +29,6 @@ void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_unprot_deauth(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_unprot_disassoc(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *buf, size_t len, gfp_t gfp);
void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
const u8 *addr, gfp_t gfp);
@@ -54,10 +48,6 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u16 reason,
const u8 *ie, size_t ie_len, bool from_ap);
-void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- const u8 *macaddr, const u8* ie, u8 ie_len,
- gfp_t gfp);
void
nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *addr,
@@ -73,41 +63,10 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
gfp_t gfp);
-void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, u64 cookie,
- struct ieee80211_channel *chan,
- unsigned int duration, gfp_t gfp);
-void nl80211_send_remain_on_channel_cancel(
- struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev,
- u64 cookie, struct ieee80211_channel *chan, gfp_t gfp);
-
-void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- struct station_info *sinfo, gfp_t gfp);
-void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- gfp_t gfp);
-
-void nl80211_send_conn_failed_event(struct cfg80211_registered_device *rdev,
- struct net_device *dev, const u8 *mac_addr,
- enum nl80211_connect_failed_reason reason,
- gfp_t gfp);
-
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp);
-void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, u64 cookie,
- const u8 *buf, size_t len, bool ack,
- gfp_t gfp);
-
-void
-nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev,
- enum nl80211_cqm_rssi_threshold_event rssi_event,
- gfp_t gfp);
void
nl80211_radar_notify(struct cfg80211_registered_device *rdev,
@@ -115,31 +74,4 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
enum nl80211_radar_event event,
struct net_device *netdev, gfp_t gfp);
-void
-nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *peer,
- u32 num_packets, gfp_t gfp);
-
-void
-nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *peer,
- u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
-
-void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, const u8 *bssid,
- const u8 *replay_ctr, gfp_t gfp);
-
-void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
- struct net_device *netdev, int index,
- const u8 *bssid, bool preauth, gfp_t gfp);
-
-void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
- struct net_device *dev,
- struct cfg80211_chan_def *chandef, gfp_t gfp);
-
-bool nl80211_unexpected_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp);
-bool nl80211_unexpected_4addr_frame(struct net_device *dev,
- const u8 *addr, gfp_t gfp);
-
#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 422d38291d66..9f15f0ac824d 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -6,11 +6,12 @@
#include "core.h"
#include "trace.h"
-static inline int rdev_suspend(struct cfg80211_registered_device *rdev)
+static inline int rdev_suspend(struct cfg80211_registered_device *rdev,
+ struct cfg80211_wowlan *wowlan)
{
int ret;
- trace_rdev_suspend(&rdev->wiphy, rdev->wowlan);
- ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+ trace_rdev_suspend(&rdev->wiphy, wowlan);
+ ret = rdev->ops->suspend(&rdev->wiphy, wowlan);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
@@ -874,7 +875,7 @@ static inline void rdev_stop_p2p_device(struct cfg80211_registered_device *rdev,
trace_rdev_stop_p2p_device(&rdev->wiphy, wdev);
rdev->ops->stop_p2p_device(&rdev->wiphy, wdev);
trace_rdev_return_void(&rdev->wiphy);
-}
+}
static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
struct net_device *dev,
@@ -887,4 +888,39 @@ static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev,
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
}
+
+static inline int rdev_update_ft_ies(struct cfg80211_registered_device *rdev,
+ struct net_device *dev,
+ struct cfg80211_update_ft_ies_params *ftie)
+{
+ int ret;
+
+ trace_rdev_update_ft_ies(&rdev->wiphy, dev, ftie);
+ ret = rdev->ops->update_ft_ies(&rdev->wiphy, dev, ftie);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline int rdev_crit_proto_start(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ enum nl80211_crit_proto_id protocol,
+ u16 duration)
+{
+ int ret;
+
+ trace_rdev_crit_proto_start(&rdev->wiphy, wdev, protocol, duration);
+ ret = rdev->ops->crit_proto_start(&rdev->wiphy, wdev,
+ protocol, duration);
+ trace_rdev_return_int(&rdev->wiphy, ret);
+ return ret;
+}
+
+static inline void rdev_crit_proto_stop(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev)
+{
+ trace_rdev_crit_proto_stop(&rdev->wiphy, wdev);
+ rdev->ops->crit_proto_stop(&rdev->wiphy, wdev);
+ trace_rdev_return_void(&rdev->wiphy);
+}
+
#endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 98532c00242d..cc35fbaa4578 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -184,14 +184,14 @@ static const struct ieee80211_regdomain world_regdom = {
NL80211_RRF_NO_IBSS |
NL80211_RRF_NO_OFDM),
/* IEEE 802.11a, channel 36..48 */
- REG_RULE(5180-10, 5240+10, 40, 6, 20,
+ REG_RULE(5180-10, 5240+10, 80, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
- /* NB: 5260 MHz - 5700 MHz requies DFS */
+ /* NB: 5260 MHz - 5700 MHz requires DFS */
/* IEEE 802.11a, channel 149..165 */
- REG_RULE(5745-10, 5825+10, 40, 6, 20,
+ REG_RULE(5745-10, 5825+10, 80, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
@@ -855,7 +855,7 @@ static void handle_channel(struct wiphy *wiphy,
return;
REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);
- chan->flags = IEEE80211_CHAN_DISABLED;
+ chan->flags |= IEEE80211_CHAN_DISABLED;
return;
}
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 674aadca0079..fd99ea495b7e 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
union iwreq_data wrqu;
#endif
- ASSERT_RDEV_LOCK(rdev);
+ lockdep_assert_held(&rdev->sched_scan_mtx);
request = rdev->scan_req;
@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk)
rdev = container_of(wk, struct cfg80211_registered_device,
scan_done_wk);
- cfg80211_lock_rdev(rdev);
+ mutex_lock(&rdev->sched_scan_mtx);
___cfg80211_scan_done(rdev, false);
- cfg80211_unlock_rdev(rdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
}
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
@@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
if (found) {
- found->pub.beacon_interval = tmp->pub.beacon_interval;
- found->pub.signal = tmp->pub.signal;
- found->pub.capability = tmp->pub.capability;
- found->ts = tmp->ts;
-
/* Update IEs */
if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
const struct cfg80211_bss_ies *old;
@@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
if (found->pub.hidden_beacon_bss &&
!list_empty(&found->hidden_list)) {
+ const struct cfg80211_bss_ies *f;
+
/*
* The found BSS struct is one of the probe
* response members of a group, but we're
@@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
* SSID to showing it, which is confusing so
* drop this information.
*/
+
+ f = rcu_access_pointer(tmp->pub.beacon_ies);
+ kfree_rcu((struct cfg80211_bss_ies *)f,
+ rcu_head);
goto drop;
}
@@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
kfree_rcu((struct cfg80211_bss_ies *)old,
rcu_head);
}
+
+ found->pub.beacon_interval = tmp->pub.beacon_interval;
+ found->pub.signal = tmp->pub.signal;
+ found->pub.capability = tmp->pub.capability;
+ found->ts = tmp->ts;
} else {
struct cfg80211_internal_bss *new;
struct cfg80211_internal_bss *hidden;
@@ -1056,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
if (IS_ERR(rdev))
return PTR_ERR(rdev);
+ mutex_lock(&rdev->sched_scan_mtx);
if (rdev->scan_req) {
err = -EBUSY;
goto out;
@@ -1162,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
dev_hold(dev);
}
out:
+ mutex_unlock(&rdev->sched_scan_mtx);
kfree(creq);
cfg80211_unlock_rdev(rdev);
return err;
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index f432bd3755b1..a9dc5c736df0 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
ASSERT_RTNL();
ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev);
+ lockdep_assert_held(&rdev->sched_scan_mtx);
if (rdev->scan_req)
return -EBUSY;
@@ -159,7 +160,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct cfg80211_connect_params *params;
- const u8 *prev_bssid = NULL;
+ struct cfg80211_assoc_request req = {};
int err;
ASSERT_WDEV_LOCK(wdev);
@@ -186,16 +187,20 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
BUG_ON(!rdev->ops->assoc);
wdev->conn->state = CFG80211_CONN_ASSOCIATING;
if (wdev->conn->prev_bssid_valid)
- prev_bssid = wdev->conn->prev_bssid;
- err = __cfg80211_mlme_assoc(rdev, wdev->netdev,
- params->channel, params->bssid,
- prev_bssid,
- params->ssid, params->ssid_len,
- params->ie, params->ie_len,
- params->mfp != NL80211_MFP_NO,
- &params->crypto,
- params->flags, &params->ht_capa,
- &params->ht_capa_mask);
+ req.prev_bssid = wdev->conn->prev_bssid;
+ req.ie = params->ie;
+ req.ie_len = params->ie_len;
+ req.use_mfp = params->mfp != NL80211_MFP_NO;
+ req.crypto = params->crypto;
+ req.flags = params->flags;
+ req.ht_capa = params->ht_capa;
+ req.ht_capa_mask = params->ht_capa_mask;
+ req.vht_capa = params->vht_capa;
+ req.vht_capa_mask = params->vht_capa_mask;
+
+ err = __cfg80211_mlme_assoc(rdev, wdev->netdev, params->channel,
+ params->bssid, params->ssid,
+ params->ssid_len, &req);
if (err)
__cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
NULL, 0,
@@ -223,6 +228,7 @@ void cfg80211_conn_work(struct work_struct *work)
rtnl_lock();
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev);
@@ -230,7 +236,7 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev);
continue;
}
- if (wdev->sme_state != CFG80211_SME_CONNECTING) {
+ if (wdev->sme_state != CFG80211_SME_CONNECTING || !wdev->conn) {
wdev_unlock(wdev);
continue;
}
@@ -247,6 +253,7 @@ void cfg80211_conn_work(struct work_struct *work)
wdev_unlock(wdev);
}
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
rtnl_unlock();
@@ -320,11 +327,9 @@ void cfg80211_sme_scan_done(struct net_device *dev)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
wdev_lock(wdev);
__cfg80211_sme_scan_done(dev);
wdev_unlock(wdev);
- mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
}
void cfg80211_sme_rx_auth(struct net_device *dev,
@@ -924,9 +929,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
int err;
mutex_lock(&rdev->devlist_mtx);
+ /* might request scan - scan_mtx -> wdev_mtx dependency */
+ mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(dev->ieee80211_ptr);
err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
wdev_unlock(dev->ieee80211_ptr);
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
return err;
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 238ee49b3868..8f28b9f798d8 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -83,6 +83,14 @@ static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
+static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
+{
+ struct wireless_dev *wdev;
+
+ list_for_each_entry(wdev, &rdev->wdev_list, list)
+ cfg80211_leave(rdev, wdev);
+}
+
static int wiphy_suspend(struct device *dev, pm_message_t state)
{
struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
@@ -90,12 +98,19 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
rdev->suspend_at = get_seconds();
- if (rdev->ops->suspend) {
- rtnl_lock();
- if (rdev->wiphy.registered)
- ret = rdev_suspend(rdev);
- rtnl_unlock();
+ rtnl_lock();
+ if (rdev->wiphy.registered) {
+ if (!rdev->wowlan)
+ cfg80211_leave_all(rdev);
+ if (rdev->ops->suspend)
+ ret = rdev_suspend(rdev, rdev->wowlan);
+ if (ret == 1) {
+ /* Driver refuse to configure wowlan */
+ cfg80211_leave_all(rdev);
+ ret = rdev_suspend(rdev, NULL);
+ }
}
+ rtnl_unlock();
return ret;
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index b7a531380e19..ecd4fcec3c94 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -27,7 +27,8 @@
#define WIPHY_PR_ARG __entry->wiphy_name
#define WDEV_ENTRY __field(u32, id)
-#define WDEV_ASSIGN (__entry->id) = (wdev ? wdev->identifier : 0)
+#define WDEV_ASSIGN (__entry->id) = (!IS_ERR_OR_NULL(wdev) \
+ ? wdev->identifier : 0)
#define WDEV_PR_FMT "wdev(%u)"
#define WDEV_PR_ARG (__entry->id)
@@ -1778,13 +1779,68 @@ TRACE_EVENT(rdev_set_mac_acl,
),
TP_fast_assign(
WIPHY_ASSIGN;
- WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
__entry->acl_policy = params->acl_policy;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->acl_policy)
);
+TRACE_EVENT(rdev_update_ft_ies,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_update_ft_ies_params *ftie),
+ TP_ARGS(wiphy, netdev, ftie),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u16, md)
+ __dynamic_array(u8, ie, ftie->ie_len)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->md = ftie->md;
+ memcpy(__get_dynamic_array(ie), ftie->ie, ftie->ie_len);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", md: 0x%x",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->md)
+);
+
+TRACE_EVENT(rdev_crit_proto_start,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+ enum nl80211_crit_proto_id protocol, u16 duration),
+ TP_ARGS(wiphy, wdev, protocol, duration),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ __field(u16, proto)
+ __field(u16, duration)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ __entry->proto = protocol;
+ __entry->duration = duration;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", proto=%x, duration=%u",
+ WIPHY_PR_ARG, WDEV_PR_ARG, __entry->proto, __entry->duration)
+);
+
+TRACE_EVENT(rdev_crit_proto_stop,
+ TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+ TP_ARGS(wiphy, wdev),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ WDEV_ENTRY
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ WDEV_ASSIGN;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT,
+ WIPHY_PR_ARG, WDEV_PR_ARG)
+);
+
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
@@ -2413,6 +2469,32 @@ TRACE_EVENT(cfg80211_report_wowlan_wakeup,
TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
);
+TRACE_EVENT(cfg80211_ft_event,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ struct cfg80211_ft_event_params *ft_event),
+ TP_ARGS(wiphy, netdev, ft_event),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __dynamic_array(u8, ies, ft_event->ies_len)
+ MAC_ENTRY(target_ap)
+ __dynamic_array(u8, ric_ies, ft_event->ric_ies_len)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ if (ft_event->ies)
+ memcpy(__get_dynamic_array(ies), ft_event->ies,
+ ft_event->ies_len);
+ MAC_ASSIGN(target_ap, ft_event->target_ap);
+ if (ft_event->ric_ies)
+ memcpy(__get_dynamic_array(ric_ies), ft_event->ric_ies,
+ ft_event->ric_ies_len);
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", target_ap: " MAC_PR_FMT,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(target_ap))
+);
+
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 37a56ee1e1ed..f5ad4d94ba88 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -511,7 +511,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
encaps_data = bridge_tunnel_header;
encaps_len = sizeof(bridge_tunnel_header);
skip_header_bytes -= 2;
- } else if (ethertype > 0x600) {
+ } else if (ethertype >= ETH_P_802_3_MIN) {
encaps_data = rfc1042_header;
encaps_len = sizeof(rfc1042_header);
skip_header_bytes -= 2;
@@ -1155,6 +1155,26 @@ int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
}
EXPORT_SYMBOL(cfg80211_get_p2p_attr);
+bool ieee80211_operating_class_to_band(u8 operating_class,
+ enum ieee80211_band *band)
+{
+ switch (operating_class) {
+ case 112:
+ case 115 ... 127:
+ *band = IEEE80211_BAND_5GHZ;
+ return true;
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ *band = IEEE80211_BAND_2GHZ;
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(ieee80211_operating_class_to_band);
+
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
u32 beacon_int)
{
@@ -1258,12 +1278,12 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
if (wdev_iter == wdev)
continue;
- if (wdev_iter->netdev) {
- if (!netif_running(wdev_iter->netdev))
- continue;
- } else if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
+ if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
if (!wdev_iter->p2p_started)
continue;
+ } else if (wdev_iter->netdev) {
+ if (!netif_running(wdev_iter->netdev))
+ continue;
} else {
WARN_ON(1);
}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index fb9622f6d99c..e79cb5c0655a 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
@@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
err = 0;
@@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
@@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
+ mutex_lock(&rdev->sched_scan_mtx);
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
err = cfg80211_mgd_wext_connect(rdev, wdev);
out:
wdev_unlock(wdev);
+ mutex_unlock(&rdev->sched_scan_mtx);
mutex_unlock(&rdev->devlist_mtx);
cfg80211_unlock_rdev(rdev);
return err;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 167c67d46c6a..23cea0f74336 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1037,6 +1037,24 @@ __xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir
return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
}
+static int flow_to_policy_dir(int dir)
+{
+ if (XFRM_POLICY_IN == FLOW_DIR_IN &&
+ XFRM_POLICY_OUT == FLOW_DIR_OUT &&
+ XFRM_POLICY_FWD == FLOW_DIR_FWD)
+ return dir;
+
+ switch (dir) {
+ default:
+ case FLOW_DIR_IN:
+ return XFRM_POLICY_IN;
+ case FLOW_DIR_OUT:
+ return XFRM_POLICY_OUT;
+ case FLOW_DIR_FWD:
+ return XFRM_POLICY_FWD;
+ }
+}
+
static struct flow_cache_object *
xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family,
u8 dir, struct flow_cache_object *old_obj, void *ctx)
@@ -1046,7 +1064,7 @@ xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family,
if (old_obj)
xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo));
- pol = __xfrm_policy_lookup(net, fl, family, dir);
+ pol = __xfrm_policy_lookup(net, fl, family, flow_to_policy_dir(dir));
if (IS_ERR_OR_NULL(pol))
return ERR_CAST(pol);
@@ -1932,7 +1950,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
* previous cache entry */
if (xdst == NULL) {
num_pols = 1;
- pols[0] = __xfrm_policy_lookup(net, fl, family, dir);
+ pols[0] = __xfrm_policy_lookup(net, fl, family,
+ flow_to_policy_dir(dir));
err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms);
if (err < 0)
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index 35754cc8a9e5..8dafe6d3c6e4 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -334,6 +334,70 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
x->xflags &= ~XFRM_TIME_DEFER;
}
+static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
+{
+ u32 seq_diff, oseq_diff;
+ struct km_event c;
+ struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+ struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
+
+ /* we send notify messages in case
+ * 1. we updated on of the sequence numbers, and the seqno difference
+ * is at least x->replay_maxdiff, in this case we also update the
+ * timeout of our timer function
+ * 2. if x->replay_maxage has elapsed since last update,
+ * and there were changes
+ *
+ * The state structure must be locked!
+ */
+
+ switch (event) {
+ case XFRM_REPLAY_UPDATE:
+ if (!x->replay_maxdiff)
+ break;
+
+ if (replay_esn->seq_hi == preplay_esn->seq_hi)
+ seq_diff = replay_esn->seq - preplay_esn->seq;
+ else
+ seq_diff = ~preplay_esn->seq + replay_esn->seq + 1;
+
+ if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
+ oseq_diff = replay_esn->oseq - preplay_esn->oseq;
+ else
+ oseq_diff = ~preplay_esn->oseq + replay_esn->oseq + 1;
+
+ if (seq_diff < x->replay_maxdiff &&
+ oseq_diff < x->replay_maxdiff) {
+
+ if (x->xflags & XFRM_TIME_DEFER)
+ event = XFRM_REPLAY_TIMEOUT;
+ else
+ return;
+ }
+
+ break;
+
+ case XFRM_REPLAY_TIMEOUT:
+ if (memcmp(x->replay_esn, x->preplay_esn,
+ xfrm_replay_state_esn_len(replay_esn)) == 0) {
+ x->xflags |= XFRM_TIME_DEFER;
+ return;
+ }
+
+ break;
+ }
+
+ memcpy(x->preplay_esn, x->replay_esn,
+ xfrm_replay_state_esn_len(replay_esn));
+ c.event = XFRM_MSG_NEWAE;
+ c.data.aevent = event;
+ km_state_notify(x, &c);
+
+ if (x->replay_maxage &&
+ !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+ x->xflags &= ~XFRM_TIME_DEFER;
+}
+
static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
{
int err = 0;
@@ -510,7 +574,7 @@ static struct xfrm_replay xfrm_replay_esn = {
.advance = xfrm_replay_advance_esn,
.check = xfrm_replay_check_esn,
.recheck = xfrm_replay_recheck_esn,
- .notify = xfrm_replay_notify_bmp,
+ .notify = xfrm_replay_notify_esn,
.overflow = xfrm_replay_overflow_esn,
};
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 2c341bdaf47c..78f66fa92449 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1187,6 +1187,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
goto error;
x->props.flags = orig->props.flags;
+ x->props.extra_flags = orig->props.extra_flags;
x->curlft.add_time = orig->curlft.add_time;
x->km.state = orig->km.state;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index fbd9e6cd0fd7..aa778748c565 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -515,6 +515,9 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
copy_from_user_state(x, p);
+ if (attrs[XFRMA_SA_EXTRA_FLAGS])
+ x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
+
if ((err = attach_aead(&x->aead, &x->props.ealgo,
attrs[XFRMA_ALG_AEAD])))
goto error;
@@ -779,6 +782,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x,
copy_to_user_state(x, p);
+ if (x->props.extra_flags) {
+ ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
+ x->props.extra_flags);
+ if (ret)
+ goto out;
+ }
+
if (x->coaddr) {
ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
if (ret)
@@ -2302,9 +2312,10 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
[XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
[XFRMA_TFCPAD] = { .type = NLA_U32 },
[XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) },
+ [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 },
};
-static struct xfrm_link {
+static const struct xfrm_link {
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
int (*dump)(struct sk_buff *, struct netlink_callback *);
int (*done)(struct netlink_callback *);
@@ -2338,7 +2349,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
struct nlattr *attrs[XFRMA_MAX+1];
- struct xfrm_link *link;
+ const struct xfrm_link *link;
int type, err;
type = nlh->nlmsg_type;
@@ -2495,6 +2506,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x)
x->security->ctx_len);
if (x->coaddr)
l += nla_total_size(sizeof(*x->coaddr));
+ if (x->props.extra_flags)
+ l += nla_total_size(sizeof(x->props.extra_flags));
/* Must count x->lastused as it may become non-zero behind our back. */
l += nla_total_size(sizeof(u64));
diff --git a/samples/hidraw/hid-example.c b/samples/hidraw/hid-example.c
index 816e2dcda7ca..512a7e50bcae 100644
--- a/samples/hidraw/hid-example.c
+++ b/samples/hidraw/hid-example.c
@@ -17,10 +17,9 @@
/*
* Ugly hack to work around failing compilation on systems that don't
* yet populate new version of hidraw.h to userspace.
- *
- * If you need this, please have your distro update the kernel headers.
*/
#ifndef HIDIOCSFEATURE
+#warning Please have your distro update the userspace kernel headers
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#endif
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index b28cc384a5bc..b954de58304f 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -281,6 +281,7 @@ our $signature_tags = qr{(?xi:
Tested-by:|
Reviewed-by:|
Reported-by:|
+ Suggested-by:|
To:|
Cc:
)};
@@ -628,6 +629,13 @@ sub sanitise_line {
return $res;
}
+sub get_quoted_string {
+ my ($line, $rawline) = @_;
+
+ return "" if ($line !~ m/(\"[X]+\")/g);
+ return substr($rawline, $-[0], $+[0] - $-[0]);
+}
+
sub ctx_statement_block {
my ($linenr, $remain, $off) = @_;
my $line = $linenr - 1;
@@ -1576,7 +1584,8 @@ sub process {
# Check for incorrect file permissions
if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
my $permhere = $here . "FILE: $realfile\n";
- if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+ if ($realfile !~ m@scripts/@ &&
+ $realfile !~ /\.(py|pl|awk|sh)$/) {
ERROR("EXECUTE_PERMISSIONS",
"do not set execute permissions for source files\n" . $permhere);
}
@@ -2514,8 +2523,8 @@ sub process {
# check for whitespace before a non-naked semicolon
if ($line =~ /^\+.*\S\s+;/) {
- CHK("SPACING",
- "space prohibited before semicolon\n" . $herecurr);
+ WARN("SPACING",
+ "space prohibited before semicolon\n" . $herecurr);
}
# Check operator spacing.
@@ -3016,6 +3025,7 @@ sub process {
$dstat !~ /^'X'$/ && # character constants
$dstat !~ /$exceptions/ &&
$dstat !~ /^\.$Ident\s*=/ && # .foo =
+ $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo
$dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
$dstat !~ /^for\s*$Constant$/ && # for (...)
$dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar()
@@ -3220,7 +3230,7 @@ sub process {
}
# check for unnecessary blank lines around braces
- if (($line =~ /^..*}\s*$/ && $prevline =~ /^.\s*$/)) {
+ if (($line =~ /^.\s*}\s*$/ && $prevline =~ /^.\s*$/)) {
CHK("BRACES",
"Blank lines aren't necessary before a close brace '}'\n" . $hereprev);
}
@@ -3372,6 +3382,15 @@ sub process {
"struct spinlock should be spinlock_t\n" . $herecurr);
}
+# check for seq_printf uses that could be seq_puts
+ if ($line =~ /\bseq_printf\s*\(/) {
+ my $fmt = get_quoted_string($line, $rawline);
+ if ($fmt !~ /[^\\]\%/) {
+ WARN("PREFER_SEQ_PUTS",
+ "Prefer seq_puts to seq_printf\n" . $herecurr);
+ }
+ }
+
# Check for misused memsets
if ($^V && $^V ge 5.10.0 &&
defined $stat &&
@@ -3476,6 +3495,13 @@ sub process {
"unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
}
+# check for krealloc arg reuse
+ if ($^V && $^V ge 5.10.0 &&
+ $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) {
+ WARN("KREALLOC_ARG_REUSE",
+ "Reusing the krealloc arg is almost always a bug\n" . $herecurr);
+ }
+
# check for alloc argument mismatch
if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
WARN("ALLOC_ARRAY_ARGS",
diff --git a/scripts/decodecode b/scripts/decodecode
index 4f8248d5a11f..d8824f37acce 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -89,10 +89,16 @@ echo $code >> $T.s
disas $T
cat $T.dis >> $T.aa
+# (lines of whole $T.oo) - (lines of $T.aa, i.e. "Code starting") + 3,
+# i.e. the title + the "===..=" line (sed is counting from 1, 0 address is
+# special)
+faultlinenum=$(( $(wc -l $T.oo | cut -d" " -f1) - \
+ $(wc -l $T.aa | cut -d" " -f1) + 3))
+
faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
-cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g"
+cat $T.oo | sed -e "${faultlinenum}s/^\(.*:\)\(.*\)/\1\*\2\t\t<-- trapping instruction/"
echo
cat $T.aa
cleanup
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index ce4cc837b748..5e4fb144a04f 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -611,7 +611,7 @@ sub get_maintainers {
$hash{$tvi} = $value_pd;
}
}
- } elsif ($type eq 'K') {
+ } elsif ($type eq 'N') {
if ($file =~ m/$value/x) {
$hash{$tvi} = 0;
}
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index f3bffa309333..826da662886d 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -515,13 +515,6 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
struct jump_key *jump;
str_printf(r, _("Prompt: %s\n"), _(prop->text));
- str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
- prop->menu->lineno);
- if (!expr_is_yes(prop->visible.expr)) {
- str_append(r, _(" Depends on: "));
- expr_gstr_print(prop->visible.expr, r);
- str_append(r, "\n");
- }
menu = prop->menu->parent;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
bool accessible = menu_is_visible(menu);
@@ -572,6 +565,18 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
}
/*
+ * get peoperty of type P_SYMBOL
+ */
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+ struct property *prop = NULL;
+
+ for_all_properties(sym, prop, P_SYMBOL)
+ break;
+ return prop;
+}
+
+/*
* head is optional and may be NULL
*/
void get_symbol_str(struct gstr *r, struct symbol *sym,
@@ -595,6 +600,14 @@ void get_symbol_str(struct gstr *r, struct symbol *sym,
}
for_all_prompts(sym, prop)
get_prompt_str(r, prop, head);
+ prop = get_symbol_prop(sym);
+ str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
+ prop->menu->lineno);
+ if (!expr_is_yes(prop->visible.expr)) {
+ str_append(r, _(" Depends on: "));
+ expr_gstr_print(prop->visible.expr, r);
+ str_append(r, "\n");
+ }
hit = false;
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl
index 33689396953a..4606cdfb859d 100644
--- a/scripts/kconfig/streamline_config.pl
+++ b/scripts/kconfig/streamline_config.pl
@@ -156,7 +156,6 @@ sub read_kconfig {
my $state = "NONE";
my $config;
- my @kconfigs;
my $cont = 0;
my $line;
@@ -190,7 +189,13 @@ sub read_kconfig {
# collect any Kconfig sources
if (/^source\s*"(.*)"/) {
- $kconfigs[$#kconfigs+1] = $1;
+ my $kconfig = $1;
+ # prevent reading twice.
+ if (!defined($read_kconfigs{$kconfig})) {
+ $read_kconfigs{$kconfig} = 1;
+ read_kconfig($kconfig);
+ }
+ next;
}
# configs found
@@ -250,14 +255,6 @@ sub read_kconfig {
}
}
close($kinfile);
-
- # read in any configs that were found.
- foreach my $kconfig (@kconfigs) {
- if (!defined($read_kconfigs{$kconfig})) {
- $read_kconfigs{$kconfig} = 1;
- read_kconfig($kconfig);
- }
- }
}
if ($kconfig) {
@@ -396,6 +393,15 @@ foreach my $module (keys(%modules)) {
foreach my $conf (@arr) {
$configs{$conf} = $module;
dprint "$conf added by direct ($module)\n";
+ if ($debugprint) {
+ my $c=$conf;
+ $c =~ s/^CONFIG_//;
+ if (defined($depends{$c})) {
+ dprint " deps = $depends{$c}\n";
+ } else {
+ dprint " no deps\n";
+ }
+ }
}
} else {
# Most likely, someone has a custom (binary?) module loaded.
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index b45260bfeaa0..e66d4d258e1a 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -174,5 +174,8 @@ int main(void)
DEVID_FIELD(x86_cpu_id, model);
DEVID_FIELD(x86_cpu_id, vendor);
+ DEVID(mei_cl_device_id);
+ DEVID_FIELD(mei_cl_device_id, name);
+
return 0;
}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 771ac17f635d..45f9a3377dcd 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1133,6 +1133,18 @@ static int do_x86cpu_entry(const char *filename, void *symval,
}
ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry);
+/* Looks like: mei:S */
+static int do_mei_entry(const char *filename, void *symval,
+ char *alias)
+{
+ DEF_FIELD_ADDR(symval, mei_cl_device_id, name);
+
+ sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name);
+
+ return 1;
+}
+ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry);
+
/* Does namelen bytes of name exactly match the symbol? */
static bool sym_is(const char *name, unsigned namelen, const char *symbol)
{
diff --git a/security/capability.c b/security/capability.c
index 579775088967..1728d4e375db 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -98,9 +98,10 @@ static int cap_sb_set_mnt_opts(struct super_block *sb,
return 0;
}
-static void cap_sb_clone_mnt_opts(const struct super_block *oldsb,
+static int cap_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
+ return 0;
}
static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
@@ -737,6 +738,11 @@ static int cap_tun_dev_open(void *security)
{
return 0;
}
+
+static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
+{
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1071,6 +1077,7 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, tun_dev_open);
set_to_cap_if_null(ops, tun_dev_attach_queue);
set_to_cap_if_null(ops, tun_dev_attach);
+ set_to_cap_if_null(ops, skb_owned_by);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_cap_if_null(ops, xfrm_policy_alloc_security);
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 1c69e38e3a2c..dd0dc574d78d 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -25,6 +25,12 @@
static DEFINE_MUTEX(devcgroup_mutex);
+enum devcg_behavior {
+ DEVCG_DEFAULT_NONE,
+ DEVCG_DEFAULT_ALLOW,
+ DEVCG_DEFAULT_DENY,
+};
+
/*
* exception list locking rules:
* hold devcgroup_mutex for update/read.
@@ -42,10 +48,9 @@ struct dev_exception_item {
struct dev_cgroup {
struct cgroup_subsys_state css;
struct list_head exceptions;
- enum {
- DEVCG_DEFAULT_ALLOW,
- DEVCG_DEFAULT_DENY,
- } behavior;
+ enum devcg_behavior behavior;
+ /* temporary list for pending propagation operations */
+ struct list_head propagate_pending;
};
static inline struct dev_cgroup *css_to_devcgroup(struct cgroup_subsys_state *s)
@@ -182,35 +187,62 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
__dev_exception_clean(dev_cgroup);
}
+static inline bool is_devcg_online(const struct dev_cgroup *devcg)
+{
+ return (devcg->behavior != DEVCG_DEFAULT_NONE);
+}
+
+/**
+ * devcgroup_online - initializes devcgroup's behavior and exceptions based on
+ * parent's
+ * @cgroup: cgroup getting online
+ * returns 0 in case of success, error code otherwise
+ */
+static int devcgroup_online(struct cgroup *cgroup)
+{
+ struct dev_cgroup *dev_cgroup, *parent_dev_cgroup = NULL;
+ int ret = 0;
+
+ mutex_lock(&devcgroup_mutex);
+ dev_cgroup = cgroup_to_devcgroup(cgroup);
+ if (cgroup->parent)
+ parent_dev_cgroup = cgroup_to_devcgroup(cgroup->parent);
+
+ if (parent_dev_cgroup == NULL)
+ dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
+ else {
+ ret = dev_exceptions_copy(&dev_cgroup->exceptions,
+ &parent_dev_cgroup->exceptions);
+ if (!ret)
+ dev_cgroup->behavior = parent_dev_cgroup->behavior;
+ }
+ mutex_unlock(&devcgroup_mutex);
+
+ return ret;
+}
+
+static void devcgroup_offline(struct cgroup *cgroup)
+{
+ struct dev_cgroup *dev_cgroup = cgroup_to_devcgroup(cgroup);
+
+ mutex_lock(&devcgroup_mutex);
+ dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
+ mutex_unlock(&devcgroup_mutex);
+}
+
/*
* called from kernel/cgroup.c with cgroup_lock() held.
*/
static struct cgroup_subsys_state *devcgroup_css_alloc(struct cgroup *cgroup)
{
- struct dev_cgroup *dev_cgroup, *parent_dev_cgroup;
- struct cgroup *parent_cgroup;
- int ret;
+ struct dev_cgroup *dev_cgroup;
dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
if (!dev_cgroup)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&dev_cgroup->exceptions);
- parent_cgroup = cgroup->parent;
-
- if (parent_cgroup == NULL)
- dev_cgroup->behavior = DEVCG_DEFAULT_ALLOW;
- else {
- parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
- mutex_lock(&devcgroup_mutex);
- ret = dev_exceptions_copy(&dev_cgroup->exceptions,
- &parent_dev_cgroup->exceptions);
- dev_cgroup->behavior = parent_dev_cgroup->behavior;
- mutex_unlock(&devcgroup_mutex);
- if (ret) {
- kfree(dev_cgroup);
- return ERR_PTR(ret);
- }
- }
+ INIT_LIST_HEAD(&dev_cgroup->propagate_pending);
+ dev_cgroup->behavior = DEVCG_DEFAULT_NONE;
return &dev_cgroup->css;
}
@@ -304,9 +336,11 @@ static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
* verify if a certain access is allowed.
* @dev_cgroup: dev cgroup to be tested against
* @refex: new exception
+ * @behavior: behavior of the exception
*/
-static int may_access(struct dev_cgroup *dev_cgroup,
- struct dev_exception_item *refex)
+static bool may_access(struct dev_cgroup *dev_cgroup,
+ struct dev_exception_item *refex,
+ enum devcg_behavior behavior)
{
struct dev_exception_item *ex;
bool match = false;
@@ -330,18 +364,29 @@ static int may_access(struct dev_cgroup *dev_cgroup,
break;
}
- /*
- * In two cases we'll consider this new exception valid:
- * - the dev cgroup has its default policy to allow + exception list:
- * the new exception should *not* match any of the exceptions
- * (behavior == DEVCG_DEFAULT_ALLOW, !match)
- * - the dev cgroup has its default policy to deny + exception list:
- * the new exception *should* match the exceptions
- * (behavior == DEVCG_DEFAULT_DENY, match)
- */
- if ((dev_cgroup->behavior == DEVCG_DEFAULT_DENY) == match)
- return 1;
- return 0;
+ if (dev_cgroup->behavior == DEVCG_DEFAULT_ALLOW) {
+ if (behavior == DEVCG_DEFAULT_ALLOW) {
+ /* the exception will deny access to certain devices */
+ return true;
+ } else {
+ /* the exception will allow access to certain devices */
+ if (match)
+ /*
+ * a new exception allowing access shouldn't
+ * match an parent's exception
+ */
+ return false;
+ return true;
+ }
+ } else {
+ /* only behavior == DEVCG_DEFAULT_DENY allowed here */
+ if (match)
+ /* parent has an exception that matches the proposed */
+ return true;
+ else
+ return false;
+ }
+ return false;
}
/*
@@ -358,7 +403,7 @@ static int parent_has_perm(struct dev_cgroup *childcg,
if (!pcg)
return 1;
parent = cgroup_to_devcgroup(pcg);
- return may_access(parent, ex);
+ return may_access(parent, ex, childcg->behavior);
}
/**
@@ -374,6 +419,111 @@ static inline int may_allow_all(struct dev_cgroup *parent)
return parent->behavior == DEVCG_DEFAULT_ALLOW;
}
+/**
+ * revalidate_active_exceptions - walks through the active exception list and
+ * revalidates the exceptions based on parent's
+ * behavior and exceptions. The exceptions that
+ * are no longer valid will be removed.
+ * Called with devcgroup_mutex held.
+ * @devcg: cgroup which exceptions will be checked
+ *
+ * This is one of the three key functions for hierarchy implementation.
+ * This function is responsible for re-evaluating all the cgroup's active
+ * exceptions due to a parent's exception change.
+ * Refer to Documentation/cgroups/devices.txt for more details.
+ */
+static void revalidate_active_exceptions(struct dev_cgroup *devcg)
+{
+ struct dev_exception_item *ex;
+ struct list_head *this, *tmp;
+
+ list_for_each_safe(this, tmp, &devcg->exceptions) {
+ ex = container_of(this, struct dev_exception_item, list);
+ if (!parent_has_perm(devcg, ex))
+ dev_exception_rm(devcg, ex);
+ }
+}
+
+/**
+ * get_online_devcg - walks the cgroup tree and fills a list with the online
+ * groups
+ * @root: cgroup used as starting point
+ * @online: list that will be filled with online groups
+ *
+ * Must be called with devcgroup_mutex held. Grabs RCU lock.
+ * Because devcgroup_mutex is held, no devcg will become online or offline
+ * during the tree walk (see devcgroup_online, devcgroup_offline)
+ * A separated list is needed because propagate_behavior() and
+ * propagate_exception() need to allocate memory and can block.
+ */
+static void get_online_devcg(struct cgroup *root, struct list_head *online)
+{
+ struct cgroup *pos;
+ struct dev_cgroup *devcg;
+
+ lockdep_assert_held(&devcgroup_mutex);
+
+ rcu_read_lock();
+ cgroup_for_each_descendant_pre(pos, root) {
+ devcg = cgroup_to_devcgroup(pos);
+ if (is_devcg_online(devcg))
+ list_add_tail(&devcg->propagate_pending, online);
+ }
+ rcu_read_unlock();
+}
+
+/**
+ * propagate_exception - propagates a new exception to the children
+ * @devcg_root: device cgroup that added a new exception
+ * @ex: new exception to be propagated
+ *
+ * returns: 0 in case of success, != 0 in case of error
+ */
+static int propagate_exception(struct dev_cgroup *devcg_root,
+ struct dev_exception_item *ex)
+{
+ struct cgroup *root = devcg_root->css.cgroup;
+ struct dev_cgroup *devcg, *parent, *tmp;
+ int rc = 0;
+ LIST_HEAD(pending);
+
+ get_online_devcg(root, &pending);
+
+ list_for_each_entry_safe(devcg, tmp, &pending, propagate_pending) {
+ parent = cgroup_to_devcgroup(devcg->css.cgroup->parent);
+
+ /*
+ * in case both root's behavior and devcg is allow, a new
+ * restriction means adding to the exception list
+ */
+ if (devcg_root->behavior == DEVCG_DEFAULT_ALLOW &&
+ devcg->behavior == DEVCG_DEFAULT_ALLOW) {
+ rc = dev_exception_add(devcg, ex);
+ if (rc)
+ break;
+ } else {
+ /*
+ * in the other possible cases:
+ * root's behavior: allow, devcg's: deny
+ * root's behavior: deny, devcg's: deny
+ * the exception will be removed
+ */
+ dev_exception_rm(devcg, ex);
+ }
+ revalidate_active_exceptions(devcg);
+
+ list_del_init(&devcg->propagate_pending);
+ }
+ return rc;
+}
+
+static inline bool has_children(struct dev_cgroup *devcgroup)
+{
+ struct cgroup *cgrp = devcgroup->css.cgroup;
+
+ return !list_empty(&cgrp->children);
+}
+
/*
* Modify the exception list using allow/deny rules.
* CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD
@@ -392,7 +542,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
{
const char *b;
char temp[12]; /* 11 + 1 characters needed for a u32 */
- int count, rc;
+ int count, rc = 0;
struct dev_exception_item ex;
struct cgroup *p = devcgroup->css.cgroup;
struct dev_cgroup *parent = NULL;
@@ -410,6 +560,9 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
case 'a':
switch (filetype) {
case DEVCG_ALLOW:
+ if (has_children(devcgroup))
+ return -EINVAL;
+
if (!may_allow_all(parent))
return -EPERM;
dev_exception_clean(devcgroup);
@@ -423,6 +576,9 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
return rc;
break;
case DEVCG_DENY:
+ if (has_children(devcgroup))
+ return -EINVAL;
+
dev_exception_clean(devcgroup);
devcgroup->behavior = DEVCG_DEFAULT_DENY;
break;
@@ -517,22 +673,28 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
dev_exception_rm(devcgroup, &ex);
return 0;
}
- return dev_exception_add(devcgroup, &ex);
+ rc = dev_exception_add(devcgroup, &ex);
+ break;
case DEVCG_DENY:
/*
* If the default policy is to deny by default, try to remove
* an matching exception instead. And be silent about it: we
* don't want to break compatibility
*/
- if (devcgroup->behavior == DEVCG_DEFAULT_DENY) {
+ if (devcgroup->behavior == DEVCG_DEFAULT_DENY)
dev_exception_rm(devcgroup, &ex);
- return 0;
- }
- return dev_exception_add(devcgroup, &ex);
+ else
+ rc = dev_exception_add(devcgroup, &ex);
+
+ if (rc)
+ break;
+ /* we only propagate new restrictions */
+ rc = propagate_exception(devcgroup, &ex);
+ break;
default:
- return -EINVAL;
+ rc = -EINVAL;
}
- return 0;
+ return rc;
}
static int devcgroup_access_write(struct cgroup *cgrp, struct cftype *cft,
@@ -571,17 +733,10 @@ struct cgroup_subsys devices_subsys = {
.can_attach = devcgroup_can_attach,
.css_alloc = devcgroup_css_alloc,
.css_free = devcgroup_css_free,
+ .css_online = devcgroup_online,
+ .css_offline = devcgroup_offline,
.subsys_id = devices_subsys_id,
.base_cftypes = dev_cgroup_files,
-
- /*
- * While devices cgroup has the rudimentary hierarchy support which
- * checks the parent's restriction, it doesn't properly propagates
- * config changes in ancestors to their descendents. A child
- * should only be allowed to add more restrictions to the parent's
- * configuration. Fix it and remove the following.
- */
- .broken_hierarchy = true,
};
/**
@@ -609,7 +764,7 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor,
rcu_read_lock();
dev_cgroup = task_devcgroup(current);
- rc = may_access(dev_cgroup, &ex);
+ rc = may_access(dev_cgroup, &ex, dev_cgroup->behavior);
rcu_read_unlock();
if (!rc)
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 3b3b7e6bf8da..6c491a63128e 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -189,11 +189,9 @@ static int process_measurement(struct file *file, const char *filename,
if (rc != 0)
goto out_digsig;
- if (function != BPRM_CHECK)
- pathname = ima_d_path(&file->f_path, &pathbuf);
-
+ pathname = !filename ? ima_d_path(&file->f_path, &pathbuf) : filename;
if (!pathname)
- pathname = filename;
+ pathname = (const char *)file->f_dentry->d_name.name;
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname);
@@ -226,8 +224,7 @@ out:
int ima_file_mmap(struct file *file, unsigned long prot)
{
if (file && (prot & PROT_EXEC))
- return process_measurement(file, file->f_dentry->d_name.name,
- MAY_EXEC, MMAP_CHECK);
+ return process_measurement(file, NULL, MAY_EXEC, MMAP_CHECK);
return 0;
}
@@ -265,7 +262,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
int ima_file_check(struct file *file, int mask)
{
ima_rdwr_violation_check(file);
- return process_measurement(file, file->f_dentry->d_name.name,
+ return process_measurement(file, NULL,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
FILE_CHECK);
}
@@ -290,8 +287,7 @@ int ima_module_check(struct file *file)
#endif
return 0; /* We rely on module signature checking */
}
- return process_measurement(file, file->f_dentry->d_name.name,
- MAY_EXEC, MODULE_CHECK);
+ return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK);
}
static int __init init_ima(void)
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 4bd6bdb74193..c411f9bb156b 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -93,9 +93,16 @@ static void umh_keys_cleanup(struct subprocess_info *info)
static int call_usermodehelper_keys(char *path, char **argv, char **envp,
struct key *session_keyring, int wait)
{
- return call_usermodehelper_fns(path, argv, envp, wait,
- umh_keys_init, umh_keys_cleanup,
- key_get(session_keyring));
+ struct subprocess_info *info;
+
+ info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL,
+ umh_keys_init, umh_keys_cleanup,
+ session_keyring);
+ if (!info)
+ return -ENOMEM;
+
+ key_get(session_keyring);
+ return call_usermodehelper_exec(info, wait);
}
/*
diff --git a/security/security.c b/security/security.c
index 7b88c6aeaed4..a3dce87d1aef 100644
--- a/security/security.c
+++ b/security/security.c
@@ -299,10 +299,10 @@ int security_sb_set_mnt_opts(struct super_block *sb,
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);
-void security_sb_clone_mnt_opts(const struct super_block *oldsb,
+int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
- security_ops->sb_clone_mnt_opts(oldsb, newsb);
+ return security_ops->sb_clone_mnt_opts(oldsb, newsb);
}
EXPORT_SYMBOL(security_sb_clone_mnt_opts);
@@ -1290,6 +1290,11 @@ int security_tun_dev_open(void *security)
}
EXPORT_SYMBOL(security_tun_dev_open);
+void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
+{
+ security_ops->skb_owned_by(skb, sk);
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2fa28c88900c..5c6f2cd2d095 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -51,6 +51,7 @@
#include <linux/tty.h>
#include <net/icmp.h>
#include <net/ip.h> /* for local_port_range[] */
+#include <net/sock.h>
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <net/net_namespace.h>
#include <net/netlabel.h>
@@ -60,7 +61,7 @@
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h> /* for network interface checks */
-#include <linux/netlink.h>
+#include <net/netlink.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/dccp.h>
@@ -750,7 +751,37 @@ out_double_mount:
goto out;
}
-static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
+static int selinux_cmp_sb_context(const struct super_block *oldsb,
+ const struct super_block *newsb)
+{
+ struct superblock_security_struct *old = oldsb->s_security;
+ struct superblock_security_struct *new = newsb->s_security;
+ char oldflags = old->flags & SE_MNTMASK;
+ char newflags = new->flags & SE_MNTMASK;
+
+ if (oldflags != newflags)
+ goto mismatch;
+ if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
+ goto mismatch;
+ if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
+ goto mismatch;
+ if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
+ goto mismatch;
+ if (oldflags & ROOTCONTEXT_MNT) {
+ struct inode_security_struct *oldroot = oldsb->s_root->d_inode->i_security;
+ struct inode_security_struct *newroot = newsb->s_root->d_inode->i_security;
+ if (oldroot->sid != newroot->sid)
+ goto mismatch;
+ }
+ return 0;
+mismatch:
+ printk(KERN_WARNING "SELinux: mount invalid. Same superblock, "
+ "different security settings for (dev %s, "
+ "type %s)\n", newsb->s_id, newsb->s_type->name);
+ return -EBUSY;
+}
+
+static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
const struct superblock_security_struct *oldsbsec = oldsb->s_security;
@@ -765,14 +796,14 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
* mount options. thus we can safely deal with this superblock later
*/
if (!ss_initialized)
- return;
+ return 0;
/* how can we clone if the old one wasn't set up?? */
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
- /* if fs is reusing a sb, just let its options stand... */
+ /* if fs is reusing a sb, make sure that the contexts match */
if (newsbsec->flags & SE_SBINITIALIZED)
- return;
+ return selinux_cmp_sb_context(oldsb, newsb);
mutex_lock(&newsbsec->lock);
@@ -805,6 +836,7 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
sb_finish_set_opts(newsb);
mutex_unlock(&newsbsec->lock);
+ return 0;
}
static int selinux_parse_opts_str(char *options,
@@ -4363,6 +4395,11 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
}
+static void selinux_skb_owned_by(struct sk_buff *skb, struct sock *sk)
+{
+ skb_set_owner_w(skb, sk);
+}
+
static int selinux_secmark_relabel_packet(u32 sid)
{
const struct task_security_struct *__tsec;
@@ -4475,7 +4512,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
struct nlmsghdr *nlh;
struct sk_security_struct *sksec = sk->sk_security;
- if (skb->len < NLMSG_SPACE(0)) {
+ if (skb->len < NLMSG_HDRLEN) {
err = -EINVAL;
goto out;
}
@@ -5664,6 +5701,7 @@ static struct security_operations selinux_ops = {
.tun_dev_attach_queue = selinux_tun_dev_attach_queue,
.tun_dev_attach = selinux_tun_dev_attach,
.tun_dev_open = selinux_tun_dev_open,
+ .skb_owned_by = selinux_skb_owned_by,
#ifdef CONFIG_SECURITY_NETWORK_XFRM
.xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 14d810ead420..828fb6a4e941 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/skbuff.h>
-#include <linux/netlink.h>
#include <linux/selinux_netlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
@@ -77,7 +76,7 @@ static void selnl_notify(int msgtype, void *data)
len = selnl_msglen(msgtype);
- skb = alloc_skb(NLMSG_SPACE(len), GFP_USER);
+ skb = nlmsg_new(len, GFP_USER);
if (!skb)
goto oom;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 99b36124f712..8ad30955e15d 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -149,11 +149,6 @@ struct smack_known {
#define SMACK_CIPSO_SOCKET 1
/*
- * smackfs magic number
- */
-#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
-
-/*
* CIPSO defaults.
*/
#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index db14689a21e0..2e397a88d410 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -252,6 +252,8 @@ static inline void smack_str_from_perm(char *string, int access)
string[i++] = 'x';
if (access & MAY_APPEND)
string[i++] = 'a';
+ if (access & MAY_TRANSMUTE)
+ string[i++] = 't';
string[i] = '\0';
}
/**
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fa64740abb59..d52c780bdb78 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -654,7 +654,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
/*
* You also need write access to the containing directory
*/
- smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
}
@@ -685,7 +685,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
/*
* You also need write access to the containing directory
*/
- smk_ad_setfield_u_fs_path_dentry(&ad, NULL);
+ smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
smk_ad_setfield_u_fs_inode(&ad, dir);
rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);
}
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 76a5dca46404..53a08b85bda4 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -26,6 +26,7 @@
#include <linux/seq_file.h>
#include <linux/ctype.h>
#include <linux/audit.h>
+#include <linux/magic.h>
#include "smack.h"
/*
@@ -50,12 +51,12 @@ enum smk_inos {
SMK_ACCESS2 = 16, /* make an access check with long labels */
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
+ SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
};
/*
* List locks
*/
-static DEFINE_MUTEX(smack_list_lock);
static DEFINE_MUTEX(smack_cipso_lock);
static DEFINE_MUTEX(smack_ambient_lock);
static DEFINE_MUTEX(smk_netlbladdr_lock);
@@ -110,6 +111,13 @@ struct smack_master_list {
LIST_HEAD(smack_rule_list);
+struct smack_parsed_rule {
+ char *smk_subject;
+ char *smk_object;
+ int smk_access1;
+ int smk_access2;
+};
+
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
@@ -167,25 +175,28 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap)
#define SMK_NETLBLADDRMIN 9
/**
- * smk_set_access - add a rule to the rule list
- * @srp: the new rule to add
+ * smk_set_access - add a rule to the rule list or replace an old rule
+ * @srp: the rule to add or replace
* @rule_list: the list of rules
* @rule_lock: the rule list lock
+ * @global: if non-zero, indicates a global rule
*
* Looks through the current subject/object/access list for
* the subject/object pair and replaces the access that was
* there. If the pair isn't found add it with the specified
* access.
*
- * Returns 1 if a rule was found to exist already, 0 if it is new
* Returns 0 if nothing goes wrong or -ENOMEM if it fails
* during the allocation of the new pair to add.
*/
-static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
- struct mutex *rule_lock)
+static int smk_set_access(struct smack_parsed_rule *srp,
+ struct list_head *rule_list,
+ struct mutex *rule_lock, int global)
{
struct smack_rule *sp;
+ struct smack_master_list *smlp;
int found = 0;
+ int rc = 0;
mutex_lock(rule_lock);
@@ -197,23 +208,89 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
if (sp->smk_object == srp->smk_object &&
sp->smk_subject == srp->smk_subject) {
found = 1;
- sp->smk_access = srp->smk_access;
+ sp->smk_access |= srp->smk_access1;
+ sp->smk_access &= ~srp->smk_access2;
break;
}
}
- if (found == 0)
- list_add_rcu(&srp->list, rule_list);
+ if (found == 0) {
+ sp = kzalloc(sizeof(*sp), GFP_KERNEL);
+ if (sp == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ sp->smk_subject = srp->smk_subject;
+ sp->smk_object = srp->smk_object;
+ sp->smk_access = srp->smk_access1 & ~srp->smk_access2;
+
+ list_add_rcu(&sp->list, rule_list);
+ /*
+ * If this is a global as opposed to self and a new rule
+ * it needs to get added for reporting.
+ */
+ if (global) {
+ smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
+ if (smlp != NULL) {
+ smlp->smk_rule = sp;
+ list_add_rcu(&smlp->list, &smack_rule_list);
+ } else
+ rc = -ENOMEM;
+ }
+ }
+
+out:
mutex_unlock(rule_lock);
+ return rc;
+}
+
+/**
+ * smk_perm_from_str - parse smack accesses from a text string
+ * @string: a text string that contains a Smack accesses code
+ *
+ * Returns an integer with respective bits set for specified accesses.
+ */
+static int smk_perm_from_str(const char *string)
+{
+ int perm = 0;
+ const char *cp;
- return found;
+ for (cp = string; ; cp++)
+ switch (*cp) {
+ case '-':
+ break;
+ case 'r':
+ case 'R':
+ perm |= MAY_READ;
+ break;
+ case 'w':
+ case 'W':
+ perm |= MAY_WRITE;
+ break;
+ case 'x':
+ case 'X':
+ perm |= MAY_EXEC;
+ break;
+ case 'a':
+ case 'A':
+ perm |= MAY_APPEND;
+ break;
+ case 't':
+ case 'T':
+ perm |= MAY_TRANSMUTE;
+ break;
+ default:
+ return perm;
+ }
}
/**
* smk_fill_rule - Fill Smack rule from strings
* @subject: subject label string
* @object: object label string
- * @access: access string
+ * @access1: access string
+ * @access2: string with permissions to be removed
* @rule: Smack rule
* @import: if non-zero, import labels
* @len: label length limit
@@ -221,8 +298,9 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list,
* Returns 0 on success, -1 on failure
*/
static int smk_fill_rule(const char *subject, const char *object,
- const char *access, struct smack_rule *rule,
- int import, int len)
+ const char *access1, const char *access2,
+ struct smack_parsed_rule *rule, int import,
+ int len)
{
const char *cp;
struct smack_known *skp;
@@ -255,36 +333,11 @@ static int smk_fill_rule(const char *subject, const char *object,
rule->smk_object = skp->smk_known;
}
- rule->smk_access = 0;
-
- for (cp = access; *cp != '\0'; cp++) {
- switch (*cp) {
- case '-':
- break;
- case 'r':
- case 'R':
- rule->smk_access |= MAY_READ;
- break;
- case 'w':
- case 'W':
- rule->smk_access |= MAY_WRITE;
- break;
- case 'x':
- case 'X':
- rule->smk_access |= MAY_EXEC;
- break;
- case 'a':
- case 'A':
- rule->smk_access |= MAY_APPEND;
- break;
- case 't':
- case 'T':
- rule->smk_access |= MAY_TRANSMUTE;
- break;
- default:
- return 0;
- }
- }
+ rule->smk_access1 = smk_perm_from_str(access1);
+ if (access2)
+ rule->smk_access2 = smk_perm_from_str(access2);
+ else
+ rule->smk_access2 = ~rule->smk_access1;
return 0;
}
@@ -297,30 +350,33 @@ static int smk_fill_rule(const char *subject, const char *object,
*
* Returns 0 on success, -1 on errors.
*/
-static int smk_parse_rule(const char *data, struct smack_rule *rule, int import)
+static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
+ int import)
{
int rc;
rc = smk_fill_rule(data, data + SMK_LABELLEN,
- data + SMK_LABELLEN + SMK_LABELLEN, rule, import,
- SMK_LABELLEN);
+ data + SMK_LABELLEN + SMK_LABELLEN, NULL, rule,
+ import, SMK_LABELLEN);
return rc;
}
/**
* smk_parse_long_rule - parse Smack rule from rule string
* @data: string to be parsed, null terminated
- * @rule: Smack rule
+ * @rule: Will be filled with Smack parsed rule
* @import: if non-zero, import labels
+ * @change: if non-zero, data is from /smack/change-rule
*
* Returns 0 on success, -1 on failure
*/
-static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
- int import)
+static int smk_parse_long_rule(const char *data, struct smack_parsed_rule *rule,
+ int import, int change)
{
char *subject;
char *object;
- char *access;
+ char *access1;
+ char *access2;
int datalen;
int rc = -1;
@@ -334,14 +390,27 @@ static int smk_parse_long_rule(const char *data, struct smack_rule *rule,
object = kzalloc(datalen, GFP_KERNEL);
if (object == NULL)
goto free_out_s;
- access = kzalloc(datalen, GFP_KERNEL);
- if (access == NULL)
+ access1 = kzalloc(datalen, GFP_KERNEL);
+ if (access1 == NULL)
goto free_out_o;
+ access2 = kzalloc(datalen, GFP_KERNEL);
+ if (access2 == NULL)
+ goto free_out_a;
+
+ if (change) {
+ if (sscanf(data, "%s %s %s %s",
+ subject, object, access1, access2) == 4)
+ rc = smk_fill_rule(subject, object, access1, access2,
+ rule, import, 0);
+ } else {
+ if (sscanf(data, "%s %s %s", subject, object, access1) == 3)
+ rc = smk_fill_rule(subject, object, access1, NULL,
+ rule, import, 0);
+ }
- if (sscanf(data, "%s %s %s", subject, object, access) == 3)
- rc = smk_fill_rule(subject, object, access, rule, import, 0);
-
- kfree(access);
+ kfree(access2);
+free_out_a:
+ kfree(access1);
free_out_o:
kfree(object);
free_out_s:
@@ -351,6 +420,7 @@ free_out_s:
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
#define SMK_LONG_FMT 1 /* Variable long label format */
+#define SMK_CHANGE_FMT 2 /* Rule modification format */
/**
* smk_write_rules_list - write() for any /smack rule file
* @file: file pointer, not actually used
@@ -359,22 +429,24 @@ free_out_s:
* @ppos: where to start - must be 0
* @rule_list: the list of rules to write to
* @rule_lock: lock for the rule list
- * @format: /smack/load or /smack/load2 format.
+ * @format: /smack/load or /smack/load2 or /smack/change-rule format.
*
* Get one smack access rule from above.
* The format for SMK_LONG_FMT is:
* "subject<whitespace>object<whitespace>access[<whitespace>...]"
* The format for SMK_FIXED24_FMT is exactly:
* "subject object rwxat"
+ * The format for SMK_CHANGE_FMT is:
+ * "subject<whitespace>object<whitespace>
+ * acc_enable<whitespace>acc_disable[<whitespace>...]"
*/
static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
size_t count, loff_t *ppos,
struct list_head *rule_list,
struct mutex *rule_lock, int format)
{
- struct smack_master_list *smlp;
struct smack_known *skp;
- struct smack_rule *rule;
+ struct smack_parsed_rule *rule;
char *data;
int datalen;
int rc = -EINVAL;
@@ -417,7 +489,11 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
* Be sure the data string is terminated.
*/
data[count] = '\0';
- if (smk_parse_long_rule(data, rule, 1))
+ if (smk_parse_long_rule(data, rule, 1, 0))
+ goto out_free_rule;
+ } else if (format == SMK_CHANGE_FMT) {
+ data[count] = '\0';
+ if (smk_parse_long_rule(data, rule, 1, 1))
goto out_free_rule;
} else {
/*
@@ -437,22 +513,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
rule_lock = &skp->smk_rules_lock;
}
- rc = count;
- /*
- * If this is a global as opposed to self and a new rule
- * it needs to get added for reporting.
- * smk_set_access returns true if there was already a rule
- * for the subject/object pair, and false if it was new.
- */
- if (!smk_set_access(rule, rule_list, rule_lock)) {
- if (load) {
- smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
- if (smlp != NULL) {
- smlp->smk_rule = rule;
- list_add_rcu(&smlp->list, &smack_rule_list);
- } else
- rc = -ENOMEM;
- }
+ rc = smk_set_access(rule, rule_list, rule_lock, load);
+ if (rc == 0) {
+ rc = count;
goto out;
}
@@ -1774,7 +1837,7 @@ static const struct file_operations smk_load_self_ops = {
static ssize_t smk_user_access(struct file *file, const char __user *buf,
size_t count, loff_t *ppos, int format)
{
- struct smack_rule rule;
+ struct smack_parsed_rule rule;
char *data;
char *cod;
int res;
@@ -1796,14 +1859,14 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
return -ENOMEM;
memcpy(cod, data, count);
cod[count] = '\0';
- res = smk_parse_long_rule(cod, &rule, 0);
+ res = smk_parse_long_rule(cod, &rule, 0, 0);
kfree(cod);
}
if (res)
return -EINVAL;
- res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access,
+ res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access1,
NULL);
data[0] = res == 0 ? '1' : '0';
data[1] = '\0';
@@ -2035,10 +2098,8 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
}
skp = smk_find_entry(cp);
- if (skp == NULL) {
- rc = -EINVAL;
+ if (skp == NULL)
goto free_out;
- }
rule_list = &skp->smk_rules;
rule_lock = &skp->smk_rules_lock;
@@ -2077,6 +2138,33 @@ static int smk_init_sysfs(void)
}
/**
+ * smk_write_change_rule - write() for /smack/change-rule
+ * @file: file pointer
+ * @buf: data from user space
+ * @count: bytes sent
+ * @ppos: where to start - must be 0
+ */
+static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /*
+ * Must have privilege.
+ */
+ if (!capable(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
+ SMK_CHANGE_FMT);
+}
+
+static const struct file_operations smk_change_rule_ops = {
+ .write = smk_write_change_rule,
+ .read = simple_transaction_read,
+ .release = simple_transaction_release,
+ .llseek = generic_file_llseek,
+};
+
+/**
* smk_fill_super - fill the /smackfs superblock
* @sb: the empty superblock
* @data: unused
@@ -2125,6 +2213,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
[SMK_REVOKE_SUBJ] = {
"revoke-subject", &smk_revoke_subj_ops,
S_IRUGO|S_IWUSR},
+ [SMK_CHANGE_RULE] = {
+ "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
/* last one */
{""}
};
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index a2ee362546ab..f0b756e27fed 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -536,7 +536,7 @@ static struct security_operations tomoyo_security_ops = {
};
/* Lock for GC. */
-struct srcu_struct tomoyo_ss;
+DEFINE_SRCU(tomoyo_ss);
/**
* tomoyo_init - Register TOMOYO Linux as a LSM module.
@@ -550,8 +550,7 @@ static int __init tomoyo_init(void)
if (!security_module_enable(&tomoyo_security_ops))
return 0;
/* register ourselves with the security framework */
- if (register_security(&tomoyo_security_ops) ||
- init_srcu_struct(&tomoyo_ss))
+ if (register_security(&tomoyo_security_ops))
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 23414b93771f..13c88fbcf037 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -347,10 +347,8 @@ int yama_ptrace_traceme(struct task_struct *parent)
/* Only disallow PTRACE_TRACEME on more aggressive settings. */
switch (ptrace_scope) {
case YAMA_SCOPE_CAPABILITY:
- rcu_read_lock();
- if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE))
+ if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE))
rc = -EPERM;
- rcu_read_unlock();
break;
case YAMA_SCOPE_NO_ATTACH:
rc = -EPERM;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 71ae86ca64ac..eb560fa32321 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3222,18 +3222,10 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
- long size;
- unsigned long offset;
+ struct snd_pcm_runtime *runtime = substream->runtime;;
area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
- area->vm_flags |= VM_IO;
- size = area->vm_end - area->vm_start;
- offset = area->vm_pgoff << PAGE_SHIFT;
- if (io_remap_pfn_range(area, area->vm_start,
- (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
- size, area->vm_page_prot))
- return -EAGAIN;
- return 0;
+ return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
}
EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index 3c6c1e3226f3..8a36a1d9803f 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -306,7 +306,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+ const struct v4l2_tuner *v)
{
struct snd_tea575x *tea = video_drvdata(file);
u32 orig_val = tea->val;
@@ -336,7 +336,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct snd_tea575x *tea = video_drvdata(file);
@@ -350,7 +350,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
else
tea->band = BAND_FM;
- tea->freq = clamp(f->frequency, bands[tea->band].rangelow,
+ tea->freq = clamp_t(u32, f->frequency, bands[tea->band].rangelow,
bands[tea->band].rangehigh);
snd_tea575x_set_freq(tea);
return 0;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index ecdf30eb5879..4aba7646dd9c 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -173,7 +173,7 @@ const char *snd_hda_get_jack_type(u32 cfg)
"Line Out", "Speaker", "HP Out", "CD",
"SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
"Line In", "Aux", "Mic", "Telephony",
- "SPDIF In", "Digitial In", "Reserved", "Other"
+ "SPDIF In", "Digital In", "Reserved", "Other"
};
return jack_types[(cfg & AC_DEFCFG_DEVICE)
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 7dd846380a50..d0d7ac1e99d2 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -320,7 +320,7 @@ int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size)
{
int i;
- int ret;
+ int ret = 0;
int size;
/*
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 43c2ea539561..2dbe767be16b 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -740,7 +740,7 @@ EXPORT_SYMBOL_HDA(snd_hda_activate_path);
static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
{
struct hda_gen_spec *spec = codec->spec;
- bool changed;
+ bool changed = false;
int i;
if (!spec->power_down_unused || path->active)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 418bfc0eb0a3..bcd40ee488e3 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
* this may give more power-saving, but will take longer time to
* wake up.
*/
-static int power_save_controller = -1;
-module_param(power_save_controller, bint, 0644);
+static bool power_save_controller = 1;
+module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif /* CONFIG_PM */
@@ -2931,8 +2931,6 @@ static int azx_runtime_idle(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
- if (power_save_controller > 0)
- return 0;
if (!power_save_controller ||
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EBUSY;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 78e1827d0a95..de8ac5c07fd0 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1196,7 +1196,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
_snd_printd(SND_PR_VERBOSE,
"HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n",
- codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
+ codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid);
if (eld->eld_valid) {
if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 563c24df4d6f..f15c36bde540 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3440,7 +3440,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
const hda_nid_t *ssids;
if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
- codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
+ codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 ||
+ codec->vendor_id == 0x10ec0671)
ssids = alc663_ssids;
else
ssids = alc662_ssids;
@@ -3894,6 +3895,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0665, .name = "ALC665", .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 = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 01f7f37a8410..934dec98e2ce 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1175,7 +1175,7 @@ static void snd_mixart_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "\tstreaming : %d\n", streaming);
snd_iprintf(buffer, "\tmailbox : %d\n", mailbox);
- snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr);
+ snd_iprintf(buffer, "\tinterrupts handling : %d\n\n", interr);
}
} /* endif elf loaded */
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index f9b5229b2723..8f489de5c4c6 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -295,18 +295,5 @@ static struct pcmcia_driver pdacf_cs_driver = {
.suspend = pdacf_suspend,
.resume = pdacf_resume,
#endif
-
};
-
-static int __init init_pdacf(void)
-{
- return pcmcia_register_driver(&pdacf_cs_driver);
-}
-
-static void __exit exit_pdacf(void)
-{
- pcmcia_unregister_driver(&pdacf_cs_driver);
-}
-
-module_init(init_pdacf);
-module_exit(exit_pdacf);
+module_pcmcia_driver(pdacf_cs_driver);
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 8f9350475c7b..d4db7ecaa6bf 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -367,16 +367,4 @@ static struct pcmcia_driver vxp_cs_driver = {
.resume = vxp_resume,
#endif
};
-
-static int __init init_vxpocket(void)
-{
- return pcmcia_register_driver(&vxp_cs_driver);
-}
-
-static void __exit exit_vxpocket(void)
-{
- pcmcia_unregister_driver(&vxp_cs_driver);
-}
-
-module_init(init_vxpocket);
-module_exit(exit_vxpocket);
+module_pcmcia_driver(vxp_cs_driver);
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index ac948a671ea6..e7d34711412c 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -364,6 +364,39 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
}
EXPORT_SYMBOL_GPL(arizona_out_ev);
+int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+ unsigned int mask = 1 << w->shift;
+ unsigned int val;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ val = mask;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Store the desired state for the HP outputs */
+ priv->arizona->hp_ena &= ~mask;
+ priv->arizona->hp_ena |= val;
+
+ /* Force off if HPDET magic is active */
+ if (priv->arizona->hpdet_magic)
+ val = 0;
+
+ snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+
+ return arizona_out_ev(w, kcontrol, event);
+}
+EXPORT_SYMBOL_GPL(arizona_hp_ev);
+
static unsigned int arizona_sysclk_48k_rates[] = {
6144000,
12288000,
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 116372c91f5d..13dd2916b721 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -184,6 +184,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event);
+extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event);
extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index fc176044994d..fc176044994d 100755..100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index 7e103f249053..7e103f249053 100755..100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index f2d61a187830..566ea3256e2d 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -159,6 +159,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
width = SI476X_PCM_FORMAT_S8;
+ break;
case SNDRV_PCM_FORMAT_S16_LE:
width = SI476X_PCM_FORMAT_S16_LE;
break;
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index b82bbf584146..15bc31f1abb1 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -584,7 +584,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct arizona *arizona = dev_get_drvdata(codec->dev);
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
struct regmap *regmap = codec->control_data;
const struct reg_default *patch = NULL;
int i, patch_size;
@@ -1131,11 +1131,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index cdeb301da1f6..7841b42a819c 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -551,11 +551,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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", ARIZONA_OUTPUT_ENABLES_1,
- ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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,
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 134e41c870b9..f8a31ad0b203 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1083,6 +1083,8 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = {
{ "ROP", NULL, "Right Speaker PGA" },
{ "RON", NULL, "Right Speaker PGA" },
+ { "Charge Pump", NULL, "CLK_DSP" },
+
{ "Left Headphone Output PGA", NULL, "Charge Pump" },
{ "Right Headphone Output PGA", NULL, "Charge Pump" },
{ "Left Line Output PGA", NULL, "Charge Pump" },
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index b47c252ef901..a2d01d10a5dd 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -125,7 +125,7 @@ SOC_ENUM("Equaliser EQ4 Bandwidth", wm8974_enum[9]),
SOC_ENUM("EQ4 Cut Off", wm8974_enum[10]),
SOC_SINGLE_TLV("EQ4 Volume", WM8974_EQ4, 0, 24, 1, eq_tlv),
-SOC_ENUM("Equaliser EQ5 Bandwith", wm8974_enum[11]),
+SOC_ENUM("Equaliser EQ5 Bandwidth", wm8974_enum[11]),
SOC_ENUM("EQ5 Cut Off", wm8974_enum[12]),
SOC_SINGLE_TLV("EQ5 Volume", WM8974_EQ5, 0, 24, 1, eq_tlv),
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index f3f7e75f8628..9af1bddc4c62 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -828,7 +828,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
&buf_list);
if (!buf) {
adsp_err(dsp, "Out of memory\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_fw;
}
adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n",
@@ -865,7 +866,7 @@ out_fw:
wm_adsp_buf_free(&buf_list);
out:
kfree(file);
- return 0;
+ return ret;
}
int wm_adsp1_init(struct wm_adsp *adsp)
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 55464a5b0706..810c7eeb7b03 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -496,6 +496,8 @@ static void imx_ssi_ac97_reset(struct snd_ac97 *ac97)
if (imx_ssi->ac97_reset)
imx_ssi->ac97_reset(ac97);
+ /* First read sometimes fails, do a dummy read */
+ imx_ssi_ac97_read(ac97, 0);
}
static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
@@ -504,6 +506,9 @@ static void imx_ssi_ac97_warm_reset(struct snd_ac97 *ac97)
if (imx_ssi->ac97_warm_reset)
imx_ssi->ac97_warm_reset(ac97);
+
+ /* First read sometimes fails, do a dummy read */
+ imx_ssi_ac97_read(ac97, 0);
}
struct snd_ac97_bus_ops soc_ac97_ops = {
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index 8e52c1485df3..eb4373840bb6 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -51,7 +51,7 @@ static struct snd_soc_card pcm030_card = {
.num_links = ARRAY_SIZE(pcm030_fabric_dai),
};
-static int __init pcm030_fabric_probe(struct platform_device *op)
+static int pcm030_fabric_probe(struct platform_device *op)
{
struct device_node *np = op->dev.of_node;
struct device_node *platform_np;
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index d7231e336a7c..6bbeb0bf1a73 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -972,6 +972,7 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
{
struct i2s_dai *i2s;
+ int ret;
i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL);
if (i2s == NULL)
@@ -996,15 +997,17 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
i2s->i2s_dai_drv.capture.channels_max = 2;
i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
+ dev_set_drvdata(&i2s->pdev->dev, i2s);
} else { /* Create a new platform_device for Secondary */
- i2s->pdev = platform_device_register_resndata(NULL,
- "samsung-i2s-sec", -1, NULL, 0, NULL, 0);
+ i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1);
if (IS_ERR(i2s->pdev))
return NULL;
- }
- /* Pre-assign snd_soc_dai_set_drvdata */
- dev_set_drvdata(&i2s->pdev->dev, i2s);
+ platform_set_drvdata(i2s->pdev, i2s);
+ ret = platform_device_add(i2s->pdev);
+ if (ret < 0)
+ return NULL;
+ }
return i2s;
}
@@ -1107,6 +1110,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
if (samsung_dai_type == TYPE_SEC) {
sec_dai = dev_get_drvdata(&pdev->dev);
+ if (!sec_dai) {
+ dev_err(&pdev->dev, "Unable to get drvdata\n");
+ return -EFAULT;
+ }
snd_soc_register_dai(&sec_dai->pdev->dev,
&sec_dai->i2s_dai_drv);
asoc_dma_platform_register(&pdev->dev);
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 19eff8fc4fdd..1a8b03e4b41b 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -342,8 +342,8 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static struct snd_soc_platform sh7760_soc_platform = {
- .pcm_ops = &camelot_pcm_ops,
+static struct snd_soc_platform_driver sh7760_soc_platform = {
+ .ops = &camelot_pcm_ops,
.pcm_new = camelot_pcm_new,
.pcm_free = camelot_pcm_free,
};
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index b5b3db71e253..ed0bfb0ddb96 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -211,19 +211,27 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
ret = platform->driver->compr_ops->set_params(cstream, params);
if (ret < 0)
- goto out;
+ goto err;
}
if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
ret = rtd->dai_link->compr_ops->set_params(cstream);
if (ret < 0)
- goto out;
+ goto err;
}
snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_START);
-out:
+ /* cancel any delayed stream shutdown that is pending */
+ rtd->pop_wait = 0;
+ mutex_unlock(&rtd->pcm_mutex);
+
+ cancel_delayed_work_sync(&rtd->delayed_work);
+
+ return ret;
+
+err:
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b7e84a7cd9ee..ff4b45a5d796 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2963,7 +2963,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
val = val << shift;
ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
- if (ret != 0)
+ if (ret < 0)
return ret;
if (snd_soc_volsw_is_stereo(mc)) {
@@ -3140,7 +3140,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
if (params->mask) {
ret = regmap_read(codec->control_data, params->base, &val);
if (ret != 0)
- return ret;
+ goto out;
val &= params->mask;
@@ -3158,13 +3158,15 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
((u32 *)data)[0] |= cpu_to_be32(val);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
ret = regmap_raw_write(codec->control_data, params->base,
data, len);
+out:
kfree(data);
return ret;
@@ -4197,7 +4199,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
dev_err(card->dev,
"ASoC: Property '%s' index %d could not be read: %d\n",
propname, 2 * i, ret);
- kfree(routes);
return -EINVAL;
}
ret = of_property_read_string_index(np, propname,
@@ -4206,7 +4207,6 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
dev_err(card->dev,
"ASoC: Property '%s' index %d could not be read: %d\n",
propname, (2 * i) + 1, ret);
- kfree(routes);
return -EINVAL;
}
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1d6a9b3ceb27..d6d9ba2e6916 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -831,6 +831,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
if (path->weak)
continue;
+ if (path->walking)
+ return 1;
+
if (path->walked)
continue;
@@ -838,6 +841,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
if (path->sink && path->connect) {
path->walked = 1;
+ path->walking = 1;
/* do we need to add this widget to the list ? */
if (list) {
@@ -847,11 +851,14 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
dev_err(widget->dapm->dev,
"ASoC: could not add widget %s\n",
widget->name);
+ path->walking = 0;
return con;
}
}
con += is_connected_output_ep(path->sink, list);
+
+ path->walking = 0;
}
}
@@ -931,6 +938,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
if (path->weak)
continue;
+ if (path->walking)
+ return 1;
+
if (path->walked)
continue;
@@ -938,6 +948,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
if (path->source && path->connect) {
path->walked = 1;
+ path->walking = 1;
/* do we need to add this widget to the list ? */
if (list) {
@@ -947,11 +958,14 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
dev_err(widget->dapm->dev,
"ASoC: could not add widget %s\n",
widget->name);
+ path->walking = 0;
return con;
}
}
con += is_connected_input_ep(path->source, list);
+
+ path->walking = 0;
}
}
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index 9b76cc5a1148..5e7aebe1e664 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -149,9 +149,9 @@ static void spear_pcm_free(struct snd_pcm *pcm)
static u64 spear_pcm_dmamask = DMA_BIT_MASK(32);
-static int spear_pcm_new(struct snd_card *card,
- struct snd_soc_dai *dai, struct snd_pcm *pcm)
+static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
int ret;
if (!card->dev->dma_mask)
@@ -159,16 +159,16 @@ static int spear_pcm_new(struct snd_card *card,
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
- if (dai->driver->playback.channels_min) {
- ret = spear_pcm_preallocate_dma_buffer(pcm,
+ if (rtd->cpu_dai->driver->playback.channels_min) {
+ ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
SNDRV_PCM_STREAM_PLAYBACK,
spear_pcm_hardware.buffer_bytes_max);
if (ret)
return ret;
}
- if (dai->driver->capture.channels_min) {
- ret = spear_pcm_preallocate_dma_buffer(pcm,
+ if (rtd->cpu_dai->driver->capture.channels_min) {
+ ret = spear_pcm_preallocate_dma_buffer(rtd->pcm,
SNDRV_PCM_STREAM_CAPTURE,
spear_pcm_hardware.buffer_bytes_max);
if (ret)
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index c925ab0adeb6..5e2c55c5b255 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -43,8 +43,6 @@
static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 2,
@@ -127,26 +125,6 @@ static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- return snd_dmaengine_pcm_trigger(substream,
- SNDRV_PCM_TRIGGER_START);
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- return snd_dmaengine_pcm_trigger(substream,
- SNDRV_PCM_TRIGGER_STOP);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
@@ -164,7 +142,7 @@ static struct snd_pcm_ops tegra_pcm_ops = {
.ioctl = snd_pcm_lib_ioctl,
.hw_params = tegra_pcm_hw_params,
.hw_free = tegra_pcm_hw_free,
- .trigger = tegra_pcm_trigger,
+ .trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer,
.mmap = tegra_pcm_mmap,
};
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
index 069330d82be5..6b799c0e88df 100644
--- a/sound/soc/ux500/Kconfig
+++ b/sound/soc/ux500/Kconfig
@@ -20,8 +20,8 @@ config SND_SOC_UX500_PLAT_DMA
help
Say Y if you want to enable the Ux500 platform-driver.
-+config SND_SOC_UX500_MACH_MOP500
-+ tristate "Machine - MOP500 (Ux500 + AB8500)"
+config SND_SOC_UX500_MACH_MOP500
+ tristate "Machine - MOP500 (Ux500 + AB8500)"
depends on AB8500_CORE && AB8500_GPADC && SND_SOC_UX500
select SND_SOC_AB8500_CODEC
select SND_SOC_UX500_PLAT_MSP_I2S
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 5e634a2eb282..9e2703a25156 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -253,7 +253,7 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
{
struct usb_device *dev = chip->dev;
unsigned char data[4];
- int err, crate;
+ int err, cur_rate, prev_rate;
int clock = snd_usb_clock_find_source(chip, fmt->clock);
if (clock < 0)
@@ -266,6 +266,19 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
return -ENXIO;
}
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+ snd_usb_ctrl_intf(chip) | (clock << 8),
+ data, sizeof(data));
+ if (err < 0) {
+ snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
+ dev->devnum, iface, fmt->altsetting);
+ prev_rate = 0;
+ } else {
+ prev_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ }
+
data[0] = rate;
data[1] = rate >> 8;
data[2] = rate >> 16;
@@ -280,19 +293,31 @@ static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
return err;
}
- if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
- snd_usb_ctrl_intf(chip) | (clock << 8),
- data, sizeof(data))) < 0) {
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8,
+ snd_usb_ctrl_intf(chip) | (clock << 8),
+ data, sizeof(data));
+ if (err < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
dev->devnum, iface, fmt->altsetting);
- return err;
+ cur_rate = 0;
+ } else {
+ cur_rate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
}
- crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
- if (crate != rate)
- snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+ if (cur_rate != rate) {
+ snd_printd(KERN_WARNING
+ "current rate %d is different from the runtime rate %d\n",
+ cur_rate, rate);
+ }
+
+ /* Some devices doesn't respond to sample rate changes while the
+ * interface is active. */
+ if (rate != prev_rate) {
+ usb_set_interface(dev, iface, 0);
+ usb_set_interface(dev, iface, fmt->altsetting);
+ }
return 0;
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 497d2741d119..ebe91440a068 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -509,7 +509,7 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
else
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, cpu_to_le16(wIndex),
+ 0, wIndex,
&tmp, sizeof(tmp), 1000);
up_read(&mixer->chip->shutdown_rwsem);
@@ -540,7 +540,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
else
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- cpu_to_le16(wValue), cpu_to_le16(wIndex),
+ wValue, wIndex,
NULL, 0, 1000);
up_read(&mixer->chip->shutdown_rwsem);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 5325a3869bb7..9c5ab22358b1 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -486,7 +486,7 @@ static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
{
int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- cpu_to_le16(1), 0, NULL, 0, 1000);
+ 1, 0, NULL, 0, 1000);
if (ret < 0)
return ret;
diff --git a/tools/Makefile b/tools/Makefile
index fa36565b209d..41067f304215 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,6 +12,7 @@ help:
@echo ' turbostat - Intel CPU idle stats and freq reporting tool'
@echo ' usb - USB testing tools'
@echo ' virtio - vhost test module'
+ @echo ' net - misc networking tools'
@echo ' vm - misc vm tools'
@echo ' x86_energy_perf_policy - Intel energy policy tool'
@echo ''
@@ -34,7 +35,13 @@ help:
cpupower: FORCE
$(call descend,power/$@)
-cgroup firewire lguest perf usb virtio vm: FORCE
+cgroup firewire guest usb virtio vm net: FORCE
+ $(call descend,$@)
+
+liblk: FORCE
+ $(call descend,lib/lk)
+
+perf: liblk FORCE
$(call descend,$@)
selftests: FORCE
@@ -46,7 +53,7 @@ turbostat x86_energy_perf_policy: FORCE
cpupower_install:
$(call descend,power/$(@:_install=),install)
-cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install:
+cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install net_install:
$(call descend,$(@:_install=),install)
selftests_install:
@@ -57,12 +64,18 @@ turbostat_install x86_energy_perf_policy_install:
install: cgroup_install cpupower_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \
- virtio_install vm_install x86_energy_perf_policy_install
+ virtio_install vm_install net_install x86_energy_perf_policy_install
cpupower_clean:
$(call descend,power/cpupower,clean)
-cgroup_clean firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
+cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean:
+ $(call descend,$(@:_clean=),clean)
+
+liblk_clean:
+ $(call descend,lib/lk,clean)
+
+perf_clean: liblk_clean
$(call descend,$(@:_clean=),clean)
selftests_clean:
@@ -73,6 +86,6 @@ turbostat_clean x86_energy_perf_policy_clean:
clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \
selftests_clean turbostat_clean usb_clean virtio_clean \
- vm_clean x86_energy_perf_policy_clean
+ vm_clean net_clean x86_energy_perf_policy_clean
.PHONY: FORCE
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index c800ea4c8bf9..5a1f6489d185 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -102,6 +102,10 @@ static struct utsname uts_buf;
#define MAX_FILE_NAME 100
#define ENTRIES_PER_BLOCK 50
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
struct kvp_record {
char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
@@ -1407,7 +1411,7 @@ netlink_send(int fd, struct cn_msg *msg)
int main(void)
{
- int fd, len, sock_opt;
+ int fd, len, nl_group;
int error;
struct cn_msg *message;
struct pollfd pfd;
@@ -1443,7 +1447,7 @@ int main(void)
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = 0;
- addr.nl_groups = CN_KVP_IDX;
+ addr.nl_groups = 0;
error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
@@ -1452,8 +1456,8 @@ int main(void)
close(fd);
exit(EXIT_FAILURE);
}
- sock_opt = addr.nl_groups;
- setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
+ nl_group = CN_KVP_IDX;
+ setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
/*
* Register ourselves with the kernel.
*/
@@ -1499,6 +1503,10 @@ int main(void)
}
incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
+
+ if (incoming_msg->nlmsg_type != NLMSG_DONE)
+ continue;
+
incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c
new file mode 100644
index 000000000000..fea03a3edaf4
--- /dev/null
+++ b/tools/hv/hv_vss_daemon.c
@@ -0,0 +1,249 @@
+/*
+ * An implementation of the host initiated guest snapshot for Hyper-V.
+ *
+ *
+ * Copyright (C) 2013, Microsoft, Inc.
+ * Author : K. Y. Srinivasan <kys@microsoft.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <linux/fs.h>
+#include <linux/connector.h>
+#include <linux/hyperv.h>
+#include <linux/netlink.h>
+#include <syslog.h>
+
+static char vss_recv_buffer[4096];
+static char vss_send_buffer[4096];
+static struct sockaddr_nl addr;
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+
+static int vss_do_freeze(char *dir, unsigned int cmd, char *fs_op)
+{
+ int ret, fd = open(dir, O_RDONLY);
+
+ if (fd < 0)
+ return 1;
+ ret = ioctl(fd, cmd, 0);
+ syslog(LOG_INFO, "VSS: %s of %s: %s\n", fs_op, dir, strerror(errno));
+ close(fd);
+ return !!ret;
+}
+
+static int vss_operate(int operation)
+{
+ char *fs_op;
+ char match[] = "/dev/";
+ FILE *mounts;
+ struct mntent *ent;
+ unsigned int cmd;
+ int error = 0, root_seen = 0;
+
+ switch (operation) {
+ case VSS_OP_FREEZE:
+ cmd = FIFREEZE;
+ fs_op = "freeze";
+ break;
+ case VSS_OP_THAW:
+ cmd = FITHAW;
+ fs_op = "thaw";
+ break;
+ default:
+ return -1;
+ }
+
+ mounts = setmntent("/proc/mounts", "r");
+ if (mounts == NULL)
+ return -1;
+
+ while ((ent = getmntent(mounts))) {
+ if (strncmp(ent->mnt_fsname, match, strlen(match)))
+ continue;
+ if (strcmp(ent->mnt_type, "iso9660") == 0)
+ continue;
+ if (strcmp(ent->mnt_dir, "/") == 0) {
+ root_seen = 1;
+ continue;
+ }
+ error |= vss_do_freeze(ent->mnt_dir, cmd, fs_op);
+ }
+ endmntent(mounts);
+
+ if (root_seen) {
+ error |= vss_do_freeze("/", cmd, fs_op);
+ }
+
+ return error;
+}
+
+static int netlink_send(int fd, struct cn_msg *msg)
+{
+ struct nlmsghdr *nlh;
+ unsigned int size;
+ struct msghdr message;
+ char buffer[64];
+ struct iovec iov[2];
+
+ size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
+
+ nlh = (struct nlmsghdr *)buffer;
+ nlh->nlmsg_seq = 0;
+ nlh->nlmsg_pid = getpid();
+ nlh->nlmsg_type = NLMSG_DONE;
+ nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
+ nlh->nlmsg_flags = 0;
+
+ iov[0].iov_base = nlh;
+ iov[0].iov_len = sizeof(*nlh);
+
+ iov[1].iov_base = msg;
+ iov[1].iov_len = size;
+
+ memset(&message, 0, sizeof(message));
+ message.msg_name = &addr;
+ message.msg_namelen = sizeof(addr);
+ message.msg_iov = iov;
+ message.msg_iovlen = 2;
+
+ return sendmsg(fd, &message, 0);
+}
+
+int main(void)
+{
+ int fd, len, nl_group;
+ int error;
+ struct cn_msg *message;
+ struct pollfd pfd;
+ struct nlmsghdr *incoming_msg;
+ struct cn_msg *incoming_cn_msg;
+ int op;
+ struct hv_vss_msg *vss_msg;
+
+ if (daemon(1, 0))
+ return 1;
+
+ openlog("Hyper-V VSS", 0, LOG_USER);
+ syslog(LOG_INFO, "VSS starting; pid is:%d", getpid());
+
+ fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+ if (fd < 0) {
+ syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
+ exit(EXIT_FAILURE);
+ }
+ addr.nl_family = AF_NETLINK;
+ addr.nl_pad = 0;
+ addr.nl_pid = 0;
+ addr.nl_groups = 0;
+
+
+ error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (error < 0) {
+ syslog(LOG_ERR, "bind failed; error:%d", error);
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+ nl_group = CN_VSS_IDX;
+ setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl_group, sizeof(nl_group));
+ /*
+ * Register ourselves with the kernel.
+ */
+ message = (struct cn_msg *)vss_send_buffer;
+ message->id.idx = CN_VSS_IDX;
+ message->id.val = CN_VSS_VAL;
+ message->ack = 0;
+ vss_msg = (struct hv_vss_msg *)message->data;
+ vss_msg->vss_hdr.operation = VSS_OP_REGISTER;
+
+ message->len = sizeof(struct hv_vss_msg);
+
+ len = netlink_send(fd, message);
+ if (len < 0) {
+ syslog(LOG_ERR, "netlink_send failed; error:%d", len);
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+
+ pfd.fd = fd;
+
+ while (1) {
+ struct sockaddr *addr_p = (struct sockaddr *) &addr;
+ socklen_t addr_l = sizeof(addr);
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ poll(&pfd, 1, -1);
+
+ len = recvfrom(fd, vss_recv_buffer, sizeof(vss_recv_buffer), 0,
+ addr_p, &addr_l);
+
+ if (len < 0) {
+ syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
+ addr.nl_pid, errno, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (addr.nl_pid) {
+ syslog(LOG_WARNING,
+ "Received packet from untrusted pid:%u",
+ addr.nl_pid);
+ continue;
+ }
+
+ incoming_msg = (struct nlmsghdr *)vss_recv_buffer;
+
+ if (incoming_msg->nlmsg_type != NLMSG_DONE)
+ continue;
+
+ incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+ vss_msg = (struct hv_vss_msg *)incoming_cn_msg->data;
+ op = vss_msg->vss_hdr.operation;
+ error = HV_S_OK;
+
+ switch (op) {
+ case VSS_OP_FREEZE:
+ case VSS_OP_THAW:
+ error = vss_operate(op);
+ if (error)
+ error = HV_E_FAIL;
+ break;
+ default:
+ syslog(LOG_ERR, "Illegal op:%d\n", op);
+ }
+ vss_msg->error = error;
+ len = netlink_send(fd, incoming_cn_msg);
+ if (len < 0) {
+ syslog(LOG_ERR, "net_link send failed; error:%d", len);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+}
diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile
new file mode 100644
index 000000000000..926cbf3efc7f
--- /dev/null
+++ b/tools/lib/lk/Makefile
@@ -0,0 +1,35 @@
+include ../../scripts/Makefile.include
+
+# guard against environment variables
+LIB_H=
+LIB_OBJS=
+
+LIB_H += debugfs.h
+
+LIB_OBJS += $(OUTPUT)debugfs.o
+
+LIBFILE = liblk.a
+
+CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC
+EXTLIBS = -lpthread -lrt -lelf -lm
+ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+ALL_LDFLAGS = $(LDFLAGS)
+
+RM = rm -f
+
+$(LIBFILE): $(LIB_OBJS)
+ $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS)
+
+$(LIB_OBJS): $(LIB_H)
+
+$(OUTPUT)%.o: %.c
+ $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+$(OUTPUT)%.s: %.c
+ $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
+$(OUTPUT)%.o: %.S
+ $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
+
+clean:
+ $(RM) $(LIB_OBJS) $(LIBFILE)
+
+.PHONY: clean
diff --git a/tools/perf/util/debugfs.c b/tools/lib/lk/debugfs.c
index dd8b19319c03..099e7cd022e4 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/lib/lk/debugfs.c
@@ -1,36 +1,39 @@
-#include "util.h"
-#include "debugfs.h"
-#include "cache.h"
-
-#include <linux/kernel.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/vfs.h>
#include <sys/mount.h>
+#include <linux/magic.h>
+#include <linux/kernel.h>
+
+#include "debugfs.h"
-static int debugfs_premounted;
char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug";
-char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
-static const char *debugfs_known_mountpoints[] = {
+static const char * const debugfs_known_mountpoints[] = {
"/sys/kernel/debug/",
"/debug/",
0,
};
-static int debugfs_found;
+static bool debugfs_found;
/* find the path to the mounted debugfs */
const char *debugfs_find_mountpoint(void)
{
- const char **ptr;
+ const char * const *ptr;
char type[100];
FILE *fp;
if (debugfs_found)
- return (const char *) debugfs_mountpoint;
+ return (const char *)debugfs_mountpoint;
ptr = debugfs_known_mountpoints;
while (*ptr) {
if (debugfs_valid_mountpoint(*ptr) == 0) {
- debugfs_found = 1;
+ debugfs_found = true;
strcpy(debugfs_mountpoint, *ptr);
return debugfs_mountpoint;
}
@@ -52,7 +55,7 @@ const char *debugfs_find_mountpoint(void)
if (strcmp(type, "debugfs") != 0)
return NULL;
- debugfs_found = 1;
+ debugfs_found = true;
return debugfs_mountpoint;
}
@@ -71,21 +74,12 @@ int debugfs_valid_mountpoint(const char *debugfs)
return 0;
}
-static void debugfs_set_tracing_events_path(const char *mountpoint)
-{
- snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
- mountpoint, "tracing/events");
-}
-
/* mount the debugfs somewhere if it's not mounted */
-
char *debugfs_mount(const char *mountpoint)
{
/* see if it's already mounted */
- if (debugfs_find_mountpoint()) {
- debugfs_premounted = 1;
+ if (debugfs_find_mountpoint())
goto out;
- }
/* if not mounted and no argument */
if (mountpoint == NULL) {
@@ -100,15 +94,8 @@ char *debugfs_mount(const char *mountpoint)
return NULL;
/* save the mountpoint */
- debugfs_found = 1;
+ debugfs_found = true;
strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
out:
- debugfs_set_tracing_events_path(debugfs_mountpoint);
return debugfs_mountpoint;
}
-
-void debugfs_set_path(const char *mountpoint)
-{
- snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint);
- debugfs_set_tracing_events_path(mountpoint);
-}
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/lk/debugfs.h
new file mode 100644
index 000000000000..935c59bdb442
--- /dev/null
+++ b/tools/lib/lk/debugfs.h
@@ -0,0 +1,29 @@
+#ifndef __LK_DEBUGFS_H__
+#define __LK_DEBUGFS_H__
+
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+/*
+ * On most systems <limits.h> would have given us this, but not on some systems
+ * (e.g. GNU/Hurd).
+ */
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#ifndef DEBUGFS_MAGIC
+#define DEBUGFS_MAGIC 0x64626720
+#endif
+
+#ifndef PERF_DEBUGFS_ENVIRONMENT
+#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
+#endif
+
+const char *debugfs_find_mountpoint(void);
+int debugfs_valid_mountpoint(const char *debugfs);
+char *debugfs_mount(const char *mountpoint);
+
+extern char debugfs_mountpoint[];
+
+#endif /* __LK_DEBUGFS_H__ */
diff --git a/tools/net/Makefile b/tools/net/Makefile
new file mode 100644
index 000000000000..b4444d53b73f
--- /dev/null
+++ b/tools/net/Makefile
@@ -0,0 +1,15 @@
+prefix = /usr
+
+CC = gcc
+
+all : bpf_jit_disasm
+
+bpf_jit_disasm : CFLAGS = -Wall -O2
+bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
+bpf_jit_disasm : bpf_jit_disasm.o
+
+clean :
+ rm -rf *.o bpf_jit_disasm
+
+install :
+ install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c
new file mode 100644
index 000000000000..cfe0cdcda3de
--- /dev/null
+++ b/tools/net/bpf_jit_disasm.c
@@ -0,0 +1,199 @@
+/*
+ * Minimal BPF JIT image disassembler
+ *
+ * Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
+ * debugging or verification purposes.
+ *
+ * To get the disassembly of the JIT code, do the following:
+ *
+ * 1) `echo 2 > /proc/sys/net/core/bpf_jit_enable`
+ * 2) Load a BPF filter (e.g. `tcpdump -p -n -s 0 -i eth1 host 192.168.20.0/24`)
+ * 3) Run e.g. `bpf_jit_disasm -o` to read out the last JIT code
+ *
+ * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
+ * Licensed under the GNU General Public License, version 2.0 (GPLv2)
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <bfd.h>
+#include <dis-asm.h>
+#include <sys/klog.h>
+#include <sys/types.h>
+#include <regex.h>
+
+static void get_exec_path(char *tpath, size_t size)
+{
+ char *path;
+ ssize_t len;
+
+ snprintf(tpath, size, "/proc/%d/exe", (int) getpid());
+ tpath[size - 1] = 0;
+
+ path = strdup(tpath);
+ assert(path);
+
+ len = readlink(path, tpath, size);
+ tpath[len] = 0;
+
+ free(path);
+}
+
+static void get_asm_insns(uint8_t *image, size_t len, unsigned long base,
+ int opcodes)
+{
+ int count, i, pc = 0;
+ char tpath[256];
+ struct disassemble_info info;
+ disassembler_ftype disassemble;
+ bfd *bfdf;
+
+ memset(tpath, 0, sizeof(tpath));
+ get_exec_path(tpath, sizeof(tpath));
+
+ bfdf = bfd_openr(tpath, NULL);
+ assert(bfdf);
+ assert(bfd_check_format(bfdf, bfd_object));
+
+ init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
+ info.arch = bfd_get_arch(bfdf);
+ info.mach = bfd_get_mach(bfdf);
+ info.buffer = image;
+ info.buffer_length = len;
+
+ disassemble_init_for_target(&info);
+
+ disassemble = disassembler(bfdf);
+ assert(disassemble);
+
+ do {
+ printf("%4x:\t", pc);
+
+ count = disassemble(pc, &info);
+
+ if (opcodes) {
+ printf("\n\t");
+ for (i = 0; i < count; ++i)
+ printf("%02x ", (uint8_t) image[pc + i]);
+ }
+ printf("\n");
+
+ pc += count;
+ } while(count > 0 && pc < len);
+
+ bfd_close(bfdf);
+}
+
+static char *get_klog_buff(int *klen)
+{
+ int ret, len = klogctl(10, NULL, 0);
+ char *buff = malloc(len);
+
+ assert(buff && klen);
+ ret = klogctl(3, buff, len);
+ assert(ret >= 0);
+ *klen = ret;
+
+ return buff;
+}
+
+static void put_klog_buff(char *buff)
+{
+ free(buff);
+}
+
+static int get_last_jit_image(char *haystack, size_t hlen,
+ uint8_t *image, size_t ilen,
+ unsigned long *base)
+{
+ char *ptr, *pptr, *tmp;
+ off_t off = 0;
+ int ret, flen, proglen, pass, ulen = 0;
+ regmatch_t pmatch[1];
+ regex_t regex;
+
+ if (hlen == 0)
+ return 0;
+
+ ret = regcomp(&regex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ "
+ "pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED);
+ assert(ret == 0);
+
+ ptr = haystack;
+ while (1) {
+ ret = regexec(&regex, ptr, 1, pmatch, 0);
+ if (ret == 0) {
+ ptr += pmatch[0].rm_eo;
+ off += pmatch[0].rm_eo;
+ assert(off < hlen);
+ } else
+ break;
+ }
+
+ ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
+ ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
+ &flen, &proglen, &pass, base);
+ if (ret != 4)
+ return 0;
+
+ tmp = ptr = haystack + off;
+ while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
+ tmp = NULL;
+ if (!strstr(ptr, "JIT code"))
+ continue;
+ pptr = ptr;
+ while ((ptr = strstr(pptr, ":")))
+ pptr = ptr + 1;
+ ptr = pptr;
+ do {
+ image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16);
+ if (ptr == pptr || ulen >= ilen) {
+ ulen--;
+ break;
+ }
+ ptr = pptr;
+ } while (1);
+ }
+
+ assert(ulen == proglen);
+ printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n",
+ proglen, pass, flen);
+ printf("%lx + <x>:\n", *base);
+
+ regfree(&regex);
+ return ulen;
+}
+
+int main(int argc, char **argv)
+{
+ int len, klen, opcodes = 0;
+ char *kbuff;
+ unsigned long base;
+ uint8_t image[4096];
+
+ if (argc > 1) {
+ if (!strncmp("-o", argv[argc - 1], 2)) {
+ opcodes = 1;
+ } else {
+ printf("usage: bpf_jit_disasm [-o: show opcodes]\n");
+ exit(0);
+ }
+ }
+
+ bfd_init();
+ memset(image, 0, sizeof(image));
+
+ kbuff = get_klog_buff(&klen);
+
+ len = get_last_jit_image(kbuff, klen, image, sizeof(image), &base);
+ if (len > 0 && base > 0)
+ get_asm_insns(image, len, base, opcodes);
+
+ put_klog_buff(kbuff);
+
+ return 0;
+}
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index 5ad07ef417f0..e9cd39a92dc2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -93,6 +93,9 @@ OPTIONS
--skip-missing::
Skip symbols that cannot be annotated.
+--group::
+ Show event group information together
+
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt
new file mode 100644
index 000000000000..888d51137fbe
--- /dev/null
+++ b/tools/perf/Documentation/perf-mem.txt
@@ -0,0 +1,48 @@
+perf-mem(1)
+===========
+
+NAME
+----
+perf-mem - Profile memory accesses
+
+SYNOPSIS
+--------
+[verse]
+'perf mem' [<options>] (record [<command>] | report)
+
+DESCRIPTION
+-----------
+"perf mem -t <TYPE> record" runs a command and gathers memory operation data
+from it, into perf.data. Perf record options are accepted and are passed through.
+
+"perf mem -t <TYPE> report" displays the result. It invokes perf report with the
+right set of options to display a memory access profile.
+
+OPTIONS
+-------
+<command>...::
+ Any command you can specify in a shell.
+
+-t::
+--type=::
+ Select the memory operation type: load or store (default: load)
+
+-D::
+--dump-raw-samples=::
+ Dump the raw decoded samples on the screen in a format that is easy to parse with
+ one sample per line.
+
+-x::
+--field-separator::
+ Specify the field separator used when dump raw samples (-D option). By default,
+ The separator is the space character.
+
+-C::
+--cpu-list::
+ Restrict dump of raw samples to those provided via this option. Note that the same
+ option can be passed in record mode. It will be interpreted the same way as perf
+ record.
+
+SEE ALSO
+--------
+linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 938e8904f64d..d4da111ef53d 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -182,6 +182,12 @@ is enabled for all the sampling events. The sampled branch type is the same for
The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
Note that this feature may not be available on all processors.
+-W::
+--weight::
+Enable weightened sampling. An additional weight is recorded per sample and can be
+displayed with the weight and local_weight sort keys. This currently works for TSX
+abort events and some memory events in precise mode on modern Intel CPUs.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 02284a0067f0..7d5f4f38aa52 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -59,7 +59,7 @@ OPTIONS
--sort=::
Sort histogram entries by given key(s) - multiple keys can be specified
in CSV format. Following sort keys are available:
- pid, comm, dso, symbol, parent, cpu, srcline.
+ pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight.
Each key has following meaning:
@@ -206,6 +206,10 @@ OPTIONS
--group::
Show event group information together.
+--demangle::
+ Demangle symbol names to human readable form. It's enabled by default,
+ disable with --no-demangle.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index faf4f4feebcc..2fe87fb558f0 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -52,7 +52,7 @@ OPTIONS
-r::
--repeat=<n>::
- repeat command and print average + stddev (max: 100)
+ repeat command and print average + stddev (max: 100). 0 means forever.
-B::
--big-num::
@@ -119,13 +119,19 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m
Print count deltas every N milliseconds (minimum: 100ms)
example: perf stat -I 1000 -e cycles -a sleep 5
---aggr-socket::
+--per-socket::
Aggregate counts per processor socket for system-wide mode measurements. This
is a useful mode to detect imbalance between sockets. To enable this mode,
-use --aggr-socket in addition to -a. (system-wide). The output includes the
+use --per-socket in addition to -a. (system-wide). The output includes the
socket number and the number of online processors on that socket. This is
useful to gauge the amount of aggregation.
+--per-core::
+Aggregate counts per physical processor for system-wide mode measurements. This
+is a useful mode to detect imbalance between physical cores. To enable this mode,
+use --per-core in addition to -a. (system-wide). The output includes the
+core number and the number of online logical processors on that physical processor.
+
EXAMPLES
--------
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index a414bc95fd52..9f1a2fe54757 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -112,7 +112,7 @@ Default is to monitor all CPUS.
-s::
--sort::
- Sort by key(s): pid, comm, dso, symbol, parent, srcline.
+ Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, local_weight.
-n::
--show-nr-samples::
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 39d41068484f..025de796067c 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
tools/perf
tools/scripts
tools/lib/traceevent
+tools/lib/lk
include/linux/const.h
include/linux/perf_event.h
include/linux/rbtree.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index bb74c79cd16e..b0f164b133d9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -35,7 +35,9 @@ include config/utilities.mak
#
# Define WERROR=0 to disable treating any warnings as errors.
#
-# Define NO_NEWT if you do not want TUI support.
+# Define NO_NEWT if you do not want TUI support. (deprecated)
+#
+# Define NO_SLANG if you do not want TUI support.
#
# Define NO_GTK2 if you do not want GTK+ GUI support.
#
@@ -104,6 +106,10 @@ ifdef PARSER_DEBUG
PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
endif
+ifdef NO_NEWT
+ NO_SLANG=1
+endif
+
CFLAGS = -fno-omit-frame-pointer -ggdb3 -funwind-tables -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
EXTLIBS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
@@ -215,6 +221,7 @@ BASIC_CFLAGS = \
-Iutil \
-I. \
-I$(TRACE_EVENT_DIR) \
+ -I../lib/ \
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
BASIC_LDFLAGS =
@@ -240,19 +247,28 @@ SCRIPT_SH += perf-archive.sh
grep-libs = $(filter -l%,$(1))
strip-libs = $(filter-out -l%,$(1))
+LK_DIR = ../lib/lk/
TRACE_EVENT_DIR = ../lib/traceevent/
+LK_PATH=$(LK_DIR)
+
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
+ifneq ($(subdir),)
+ LK_PATH=$(OUTPUT)$(LK_DIR)
+else
+ LK_PATH=$(OUTPUT)
+endif
else
TE_PATH=$(TRACE_EVENT_DIR)
endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
-TE_LIB := -L$(TE_PATH) -ltraceevent
-
export LIBTRACEEVENT
+LIBLK = $(LK_PATH)liblk.a
+export LIBLK
+
# python extension build directories
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -262,7 +278,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
-PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
+PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT)
$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
$(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
@@ -355,7 +371,6 @@ LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
LIB_H += util/debug.h
-LIB_H += util/debugfs.h
LIB_H += util/sysfs.h
LIB_H += util/pmu.h
LIB_H += util/event.h
@@ -416,7 +431,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
-LIB_OBJS += $(OUTPUT)util/debugfs.o
LIB_OBJS += $(OUTPUT)util/sysfs.o
LIB_OBJS += $(OUTPUT)util/pmu.o
LIB_OBJS += $(OUTPUT)util/environment.o
@@ -503,6 +517,10 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
LIB_OBJS += $(OUTPUT)tests/pmu.o
LIB_OBJS += $(OUTPUT)tests/hists_link.o
LIB_OBJS += $(OUTPUT)tests/python-use.o
+LIB_OBJS += $(OUTPUT)tests/bp_signal.o
+LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
+LIB_OBJS += $(OUTPUT)tests/task-exit.o
+LIB_OBJS += $(OUTPUT)tests/sw-clock.o
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -535,8 +553,9 @@ BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
+BUILTIN_OBJS += $(OUTPUT)builtin-mem.o
-PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
#
# Platform specific tweaks
@@ -667,15 +686,15 @@ ifndef NO_LIBAUDIT
endif
endif
-ifndef NO_NEWT
- FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
- ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y)
- msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
+ifndef NO_SLANG
+ FLAGS_SLANG=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -I/usr/include/slang -lslang
+ ifneq ($(call try-cc,$(SOURCE_SLANG),$(FLAGS_SLANG),libslang),y)
+ msg := $(warning slang not found, disables TUI support. Please install slang-devel or libslang-dev);
else
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
BASIC_CFLAGS += -I/usr/include/slang
- BASIC_CFLAGS += -DNEWT_SUPPORT
- EXTLIBS += -lnewt -lslang
+ BASIC_CFLAGS += -DSLANG_SUPPORT
+ EXTLIBS += -lslang
LIB_OBJS += $(OUTPUT)ui/browser.o
LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
@@ -1051,6 +1070,18 @@ $(LIBTRACEEVENT):
$(LIBTRACEEVENT)-clean:
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
+# if subdir is set, we've been called from above so target has been built
+# already
+$(LIBLK):
+ifeq ($(subdir),)
+ $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a
+endif
+
+$(LIBLK)-clean:
+ifeq ($(subdir),)
+ $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean
+endif
+
help:
@echo 'Perf make targets:'
@echo ' doc - make *all* documentation (see below)'
@@ -1171,7 +1202,7 @@ $(INSTALL_DOC_TARGETS):
### Cleaning rules
-clean: $(LIBTRACEEVENT)-clean
+clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean
$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
$(RM) $(ALL_PROGRAMS) perf
$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
@@ -1181,6 +1212,6 @@ clean: $(LIBTRACEEVENT)-clean
$(RM) $(OUTPUT)util/*-flex*
$(python-clean)
-.PHONY: all install clean strip $(LIBTRACEEVENT)
+.PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK)
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index e8d5c551c69c..33ec5b339da8 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,10 +8,7 @@
* published by the Free Software Foundation.
*/
-#include <stdlib.h>
-#ifndef __UCLIBC__
-#include <libio.h>
-#endif
+#include <stddef.h>
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
index 7cdd61d0e27c..733151cdf46e 100644
--- a/tools/perf/arch/powerpc/util/dwarf-regs.c
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -9,10 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <stdlib.h>
-#ifndef __UCLIBC__
-#include <libio.h>
-#endif
+#include <stddef.h>
#include <dwarf-regs.h>
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
index e19653e025fa..0469df02ee62 100644
--- a/tools/perf/arch/s390/util/dwarf-regs.c
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -6,7 +6,7 @@
*
*/
-#include <libio.h>
+#include <stddef.h>
#include <dwarf-regs.h>
#define NUM_GPRS 16
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c
index a11edb007a6c..0d0897f57a10 100644
--- a/tools/perf/arch/sh/util/dwarf-regs.c
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -19,7 +19,7 @@
*
*/
-#include <libio.h>
+#include <stddef.h>
#include <dwarf-regs.h>
/*
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c
index 0ab88483720c..92eda412fed3 100644
--- a/tools/perf/arch/sparc/util/dwarf-regs.c
+++ b/tools/perf/arch/sparc/util/dwarf-regs.c
@@ -9,7 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <libio.h>
+#include <stddef.h>
#include <dwarf-regs.h>
#define SPARC_MAX_REGS 96
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
index a794d3081928..be22dd463232 100644
--- a/tools/perf/arch/x86/util/dwarf-regs.c
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -20,7 +20,7 @@
*
*/
-#include <libio.h>
+#include <stddef.h>
#include <dwarf-regs.h>
/*
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 2e6961ea3184..db491e9a812b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -63,7 +63,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
return 0;
}
- he = __hists__add_entry(&evsel->hists, al, NULL, 1);
+ he = __hists__add_entry(&evsel->hists, al, NULL, 1, 1);
if (he == NULL)
return -ENOMEM;
@@ -109,14 +109,16 @@ static int process_sample_event(struct perf_tool *tool,
return 0;
}
-static int hist_entry__tty_annotate(struct hist_entry *he, int evidx,
+static int hist_entry__tty_annotate(struct hist_entry *he,
+ struct perf_evsel *evsel,
struct perf_annotate *ann)
{
- return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
+ return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel,
ann->print_line, ann->full_paths, 0, 0);
}
-static void hists__find_annotations(struct hists *self, int evidx,
+static void hists__find_annotations(struct hists *self,
+ struct perf_evsel *evsel,
struct perf_annotate *ann)
{
struct rb_node *nd = rb_first(&self->entries), *next;
@@ -142,14 +144,14 @@ find_next:
if (use_browser == 2) {
int ret;
- ret = hist_entry__gtk_annotate(he, evidx, NULL);
+ ret = hist_entry__gtk_annotate(he, evsel, NULL);
if (!ret || !ann->skip_missing)
return;
/* skip missing symbols */
nd = rb_next(nd);
} else if (use_browser == 1) {
- key = hist_entry__tui_annotate(he, evidx, NULL);
+ key = hist_entry__tui_annotate(he, evsel, NULL);
switch (key) {
case -1:
if (!ann->skip_missing)
@@ -168,7 +170,7 @@ find_next:
if (next != NULL)
nd = next;
} else {
- hist_entry__tty_annotate(he, evidx, ann);
+ hist_entry__tty_annotate(he, evsel, ann);
nd = rb_next(nd);
/*
* Since we have a hist_entry per IP for the same
@@ -230,7 +232,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
total_nr_samples += nr_samples;
hists__collapse_resort(hists);
hists__output_resort(hists);
- hists__find_annotations(hists, pos->idx, ann);
+
+ if (symbol_conf.event_group &&
+ !perf_evsel__is_group_leader(pos))
+ continue;
+
+ hists__find_annotations(hists, pos, ann);
}
}
@@ -312,6 +319,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
+ OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
+ "Show event group information together"),
OPT_END()
};
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index d207a97a2db1..2d0462d89a97 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -231,9 +231,10 @@ int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
}
static int hists__add_entry(struct hists *self,
- struct addr_location *al, u64 period)
+ struct addr_location *al, u64 period,
+ u64 weight)
{
- if (__hists__add_entry(self, al, NULL, period) != NULL)
+ if (__hists__add_entry(self, al, NULL, period, weight) != NULL)
return 0;
return -ENOMEM;
}
@@ -255,7 +256,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
if (al.filtered)
return 0;
- if (hists__add_entry(&evsel->hists, &al, sample->period)) {
+ if (hists__add_entry(&evsel->hists, &al, sample->period, sample->weight)) {
pr_warning("problem incrementing symbol period, skipping event\n");
return -1;
}
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 37a769d7f9fe..533501e2b07c 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -12,7 +12,7 @@
#include "util/parse-options.h"
#include "util/trace-event.h"
#include "util/debug.h"
-#include "util/debugfs.h"
+#include <lk/debugfs.h>
#include "util/tool.h"
#include "util/stat.h"
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
new file mode 100644
index 000000000000..a8ff6d264e50
--- /dev/null
+++ b/tools/perf/builtin-mem.c
@@ -0,0 +1,242 @@
+#include "builtin.h"
+#include "perf.h"
+
+#include "util/parse-options.h"
+#include "util/trace-event.h"
+#include "util/tool.h"
+#include "util/session.h"
+
+#define MEM_OPERATION_LOAD "load"
+#define MEM_OPERATION_STORE "store"
+
+static const char *mem_operation = MEM_OPERATION_LOAD;
+
+struct perf_mem {
+ struct perf_tool tool;
+ char const *input_name;
+ symbol_filter_t annotate_init;
+ bool hide_unresolved;
+ bool dump_raw;
+ const char *cpu_list;
+ DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+};
+
+static const char * const mem_usage[] = {
+ "perf mem [<options>] {record <command> |report}",
+ NULL
+};
+
+static int __cmd_record(int argc, const char **argv)
+{
+ int rec_argc, i = 0, j;
+ const char **rec_argv;
+ char event[64];
+ int ret;
+
+ rec_argc = argc + 4;
+ rec_argv = calloc(rec_argc + 1, sizeof(char *));
+ if (!rec_argv)
+ return -1;
+
+ rec_argv[i++] = strdup("record");
+ if (!strcmp(mem_operation, MEM_OPERATION_LOAD))
+ rec_argv[i++] = strdup("-W");
+ rec_argv[i++] = strdup("-d");
+ rec_argv[i++] = strdup("-e");
+
+ if (strcmp(mem_operation, MEM_OPERATION_LOAD))
+ sprintf(event, "cpu/mem-stores/pp");
+ else
+ sprintf(event, "cpu/mem-loads/pp");
+
+ rec_argv[i++] = strdup(event);
+ for (j = 1; j < argc; j++, i++)
+ rec_argv[i] = argv[j];
+
+ ret = cmd_record(i, rec_argv, NULL);
+ free(rec_argv);
+ return ret;
+}
+
+static int
+dump_raw_samples(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_evsel *evsel __maybe_unused,
+ struct machine *machine)
+{
+ struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
+ struct addr_location al;
+ const char *fmt;
+
+ if (perf_event__preprocess_sample(event, machine, &al, sample,
+ mem->annotate_init) < 0) {
+ fprintf(stderr, "problem processing %d event, skipping it.\n",
+ event->header.type);
+ return -1;
+ }
+
+ if (al.filtered || (mem->hide_unresolved && al.sym == NULL))
+ return 0;
+
+ if (al.map != NULL)
+ al.map->dso->hit = 1;
+
+ if (symbol_conf.field_sep) {
+ fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64
+ "%s0x%"PRIx64"%s%s:%s\n";
+ } else {
+ fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
+ "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n";
+ symbol_conf.field_sep = " ";
+ }
+
+ printf(fmt,
+ sample->pid,
+ symbol_conf.field_sep,
+ sample->tid,
+ symbol_conf.field_sep,
+ event->ip.ip,
+ symbol_conf.field_sep,
+ sample->addr,
+ symbol_conf.field_sep,
+ sample->weight,
+ symbol_conf.field_sep,
+ sample->data_src,
+ symbol_conf.field_sep,
+ al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
+ al.sym ? al.sym->name : "???");
+
+ return 0;
+}
+
+static int process_sample_event(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_evsel *evsel,
+ struct machine *machine)
+{
+ return dump_raw_samples(tool, event, sample, evsel, machine);
+}
+
+static int report_raw_events(struct perf_mem *mem)
+{
+ int err = -EINVAL;
+ int ret;
+ struct perf_session *session = perf_session__new(input_name, O_RDONLY,
+ 0, false, &mem->tool);
+
+ if (session == NULL)
+ return -ENOMEM;
+
+ if (mem->cpu_list) {
+ ret = perf_session__cpu_bitmap(session, mem->cpu_list,
+ mem->cpu_bitmap);
+ if (ret)
+ goto out_delete;
+ }
+
+ if (symbol__init() < 0)
+ return -1;
+
+ printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
+
+ err = perf_session__process_events(session, &mem->tool);
+ if (err)
+ return err;
+
+ return 0;
+
+out_delete:
+ perf_session__delete(session);
+ return err;
+}
+
+static int report_events(int argc, const char **argv, struct perf_mem *mem)
+{
+ const char **rep_argv;
+ int ret, i = 0, j, rep_argc;
+
+ if (mem->dump_raw)
+ return report_raw_events(mem);
+
+ rep_argc = argc + 3;
+ rep_argv = calloc(rep_argc + 1, sizeof(char *));
+ if (!rep_argv)
+ return -1;
+
+ rep_argv[i++] = strdup("report");
+ rep_argv[i++] = strdup("--mem-mode");
+ rep_argv[i++] = strdup("-n"); /* display number of samples */
+
+ /*
+ * there is no weight (cost) associated with stores, so don't print
+ * the column
+ */
+ if (strcmp(mem_operation, MEM_OPERATION_LOAD))
+ rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr,"
+ "dso_daddr,tlb,locked");
+
+ for (j = 1; j < argc; j++, i++)
+ rep_argv[i] = argv[j];
+
+ ret = cmd_report(i, rep_argv, NULL);
+ free(rep_argv);
+ return ret;
+}
+
+int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+ struct stat st;
+ struct perf_mem mem = {
+ .tool = {
+ .sample = process_sample_event,
+ .mmap = perf_event__process_mmap,
+ .comm = perf_event__process_comm,
+ .lost = perf_event__process_lost,
+ .fork = perf_event__process_fork,
+ .build_id = perf_event__process_build_id,
+ .ordered_samples = true,
+ },
+ .input_name = "perf.data",
+ };
+ const struct option mem_options[] = {
+ OPT_STRING('t', "type", &mem_operation,
+ "type", "memory operations(load/store)"),
+ OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
+ "dump raw samples in ASCII"),
+ OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
+ "Only display entries resolved to a symbol"),
+ OPT_STRING('i', "input", &input_name, "file",
+ "input file name"),
+ OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
+ "list of cpus to profile"),
+ OPT_STRING('x', "field-separator", &symbol_conf.field_sep,
+ "separator",
+ "separator for columns, no spaces will be added"
+ " between columns '.' is reserved."),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, mem_options, mem_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
+ usage_with_options(mem_usage, mem_options);
+
+ if (!mem.input_name || !strlen(mem.input_name)) {
+ if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
+ mem.input_name = "-";
+ else
+ mem.input_name = "perf.data";
+ }
+
+ if (!strncmp(argv[0], "rec", 3))
+ return __cmd_record(argc, argv);
+ else if (!strncmp(argv[0], "rep", 3))
+ return report_events(argc, argv, &mem);
+ else
+ usage_with_options(mem_usage, mem_options);
+
+ return 0;
+}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index de38a034b129..e8a66f9a6715 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
#include "util/strfilter.h"
#include "util/symbol.h"
#include "util/debug.h"
-#include "util/debugfs.h"
+#include <lk/debugfs.h>
#include "util/parse-options.h"
#include "util/probe-finder.h"
#include "util/probe-event.h"
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index f1a939ebc19c..cdf58ecc04b1 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,8 +5,6 @@
* (or a CPU, or a PID) into the perf.data output file - for
* later analysis via perf report.
*/
-#define _FILE_OFFSET_BITS 64
-
#include "builtin.h"
#include "perf.h"
@@ -474,7 +472,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
}
if (forks) {
- err = perf_evlist__prepare_workload(evsel_list, opts, argv);
+ err = perf_evlist__prepare_workload(evsel_list, &opts->target,
+ argv, opts->pipe_output,
+ true);
if (err < 0) {
pr_err("Couldn't run the workload!\n");
goto out_delete_session;
@@ -953,6 +953,8 @@ const struct option record_options[] = {
OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
"branch filter mask", "branch stack filter modes",
parse_branch_stack),
+ OPT_BOOLEAN('W', "weight", &record.opts.sample_weight,
+ "sample by weight (on special events only)"),
OPT_END()
};
@@ -964,7 +966,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
struct perf_record *rec = &record;
char errbuf[BUFSIZ];
- evsel_list = perf_evlist__new(NULL, NULL);
+ evsel_list = perf_evlist__new();
if (evsel_list == NULL)
return -ENOMEM;
@@ -1026,7 +1028,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
ui__error("%s", errbuf);
err = -saved_errno;
- goto out_free_fd;
+ goto out_symbol_exit;
}
err = -ENOMEM;
@@ -1057,6 +1059,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
}
err = __cmd_record(&record, argc, argv);
+
+ perf_evlist__munmap(evsel_list);
+ perf_evlist__close(evsel_list);
out_free_fd:
perf_evlist__delete_maps(evsel_list);
out_symbol_exit:
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 96b5a7fee4bb..bd0ca81eeaca 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -13,7 +13,6 @@
#include "util/annotate.h"
#include "util/color.h"
#include <linux/list.h>
-#include "util/cache.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
#include "util/callchain.h"
@@ -47,6 +46,7 @@ struct perf_report {
bool show_full_info;
bool show_threads;
bool inverted_callchain;
+ bool mem_mode;
struct perf_read_values show_threads_values;
const char *pretty_printing_style;
symbol_filter_t annotate_init;
@@ -65,6 +65,99 @@ static int perf_report_config(const char *var, const char *value, void *cb)
return perf_default_config(var, value, cb);
}
+static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
+ struct addr_location *al,
+ struct perf_sample *sample,
+ struct perf_evsel *evsel,
+ struct machine *machine,
+ union perf_event *event)
+{
+ struct perf_report *rep = container_of(tool, struct perf_report, tool);
+ struct symbol *parent = NULL;
+ u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+ int err = 0;
+ struct hist_entry *he;
+ struct mem_info *mi, *mx;
+ uint64_t cost;
+
+ if ((sort__has_parent || symbol_conf.use_callchain) &&
+ sample->callchain) {
+ err = machine__resolve_callchain(machine, evsel, al->thread,
+ sample, &parent);
+ if (err)
+ return err;
+ }
+
+ mi = machine__resolve_mem(machine, al->thread, sample, cpumode);
+ if (!mi)
+ return -ENOMEM;
+
+ if (rep->hide_unresolved && !al->sym)
+ return 0;
+
+ cost = sample->weight;
+ if (!cost)
+ cost = 1;
+
+ /*
+ * must pass period=weight in order to get the correct
+ * sorting from hists__collapse_resort() which is solely
+ * based on periods. We want sorting be done on nr_events * weight
+ * and this is indirectly achieved by passing period=weight here
+ * and the he_stat__add_period() function.
+ */
+ he = __hists__add_mem_entry(&evsel->hists, al, parent, mi, cost, cost);
+ if (!he)
+ return -ENOMEM;
+
+ /*
+ * In the TUI browser, we are doing integrated annotation,
+ * so we don't allocate the extra space needed because the stdio
+ * code will not use it.
+ */
+ if (sort__has_sym && he->ms.sym && use_browser > 0) {
+ struct annotation *notes = symbol__annotation(he->ms.sym);
+
+ assert(evsel != NULL);
+
+ if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0)
+ goto out;
+
+ err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+ if (err)
+ goto out;
+ }
+
+ if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) {
+ struct annotation *notes;
+
+ mx = he->mem_info;
+
+ notes = symbol__annotation(mx->daddr.sym);
+ if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0)
+ goto out;
+
+ err = symbol__inc_addr_samples(mx->daddr.sym,
+ mx->daddr.map,
+ evsel->idx,
+ mx->daddr.al_addr);
+ if (err)
+ goto out;
+ }
+
+ evsel->hists.stats.total_period += cost;
+ hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
+ err = 0;
+
+ if (symbol_conf.use_callchain) {
+ err = callchain_append(he->callchain,
+ &callchain_cursor,
+ sample->period);
+ }
+out:
+ return err;
+}
+
static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
struct addr_location *al,
struct perf_sample *sample,
@@ -99,7 +192,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
* and not events sampled. Thus we use a pseudo period of 1.
*/
he = __hists__add_branch_entry(&evsel->hists, al, parent,
- &bi[i], 1);
+ &bi[i], 1, 1);
if (he) {
struct annotation *notes;
err = -ENOMEM;
@@ -157,7 +250,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
return err;
}
- he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
+ he = __hists__add_entry(&evsel->hists, al, parent, sample->period,
+ sample->weight);
if (he == NULL)
return -ENOMEM;
@@ -169,7 +263,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
return err;
}
/*
- * Only in the newt browser we are doing integrated annotation,
+ * Only in the TUI browser we are doing integrated annotation,
* so we don't allocated the extra space needed because the stdio
* code will not use it.
*/
@@ -220,6 +314,12 @@ static int process_sample_event(struct perf_tool *tool,
pr_debug("problem adding lbr entry, skipping event\n");
return -1;
}
+ } else if (rep->mem_mode == 1) {
+ if (perf_report__add_mem_hist_entry(tool, &al, sample,
+ evsel, machine, event)) {
+ pr_debug("problem adding mem entry, skipping event\n");
+ return -1;
+ }
} else {
if (al.map != NULL)
al.map->dso->hit = 1;
@@ -303,7 +403,8 @@ static void sig_handler(int sig __maybe_unused)
session_done = 1;
}
-static size_t hists__fprintf_nr_sample_events(struct hists *self,
+static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
+ struct hists *self,
const char *evname, FILE *fp)
{
size_t ret;
@@ -314,7 +415,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
char buf[512];
size_t size = sizeof(buf);
- if (symbol_conf.event_group && evsel->nr_members > 1) {
+ if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos;
perf_evsel__group_desc(evsel, buf, size);
@@ -331,7 +432,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
if (evname != NULL)
ret += fprintf(fp, " of event '%s'", evname);
- ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
+ if (rep->mem_mode) {
+ ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
+ ret += fprintf(fp, "\n# Sort order : %s", sort_order);
+ } else
+ ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
return ret + fprintf(fp, "\n#\n");
}
@@ -349,7 +454,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
!perf_evsel__is_group_leader(pos))
continue;
- hists__fprintf_nr_sample_events(hists, evname, stdout);
+ hists__fprintf_nr_sample_events(rep, hists, evname, stdout);
hists__fprintf(hists, true, 0, 0, stdout);
fprintf(stdout, "\n\n");
}
@@ -645,7 +750,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Use the stdio interface"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
- " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
+ " dso_to, dso_from, symbol_to, symbol_from, mispredict,"
+ " weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
+ "snoop, locked"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -693,6 +800,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"use branch records for histogram filling", parse_branch_mode),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
+ OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
+ "Disable symbol demangling"),
+ OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
OPT_END()
};
@@ -750,12 +860,24 @@ repeat:
"dso_to,symbol_to";
}
+ if (report.mem_mode) {
+ if (sort__branch_mode == 1) {
+ fprintf(stderr, "branch and mem mode incompatible\n");
+ goto error;
+ }
+ /*
+ * if no sort_order is provided, then specify
+ * branch-mode specific order
+ */
+ if (sort_order == default_sort_order)
+ sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
+ }
if (setup_sorting() < 0)
usage_with_options(report_usage, options);
/*
- * Only in the newt browser we are doing integrated annotation,
+ * Only in the TUI browser we are doing integrated annotation,
* so don't allocate extra space that won't be used in the stdio
* implementation.
*/
@@ -815,6 +937,14 @@ repeat:
sort_entry__setup_elide(&sort_sym_from, symbol_conf.sym_from_list, "sym_from", stdout);
sort_entry__setup_elide(&sort_sym_to, symbol_conf.sym_to_list, "sym_to", stdout);
} else {
+ if (report.mem_mode) {
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "symbol_daddr", stdout);
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso_daddr", stdout);
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "mem", stdout);
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "local_weight", stdout);
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "tlb", stdout);
+ sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "snoop", stdout);
+ }
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 138229439a93..2da2a6ca22bf 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1671,7 +1671,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
- .exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.ordered_samples = true,
},
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 99848761f573..7e910bab1097 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -68,7 +68,7 @@
static void print_stat(int argc, const char **argv);
static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
static void print_counter(struct perf_evsel *counter, char *prefix);
-static void print_aggr_socket(char *prefix);
+static void print_aggr(char *prefix);
static struct perf_evlist *evsel_list;
@@ -76,11 +76,17 @@ static struct perf_target target = {
.uid = UINT_MAX,
};
+enum aggr_mode {
+ AGGR_NONE,
+ AGGR_GLOBAL,
+ AGGR_SOCKET,
+ AGGR_CORE,
+};
+
static int run_count = 1;
static bool no_inherit = false;
static bool scale = true;
-static bool no_aggr = false;
-static bool aggr_socket = false;
+static enum aggr_mode aggr_mode = AGGR_GLOBAL;
static pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
@@ -94,8 +100,10 @@ static const char *pre_cmd = NULL;
static const char *post_cmd = NULL;
static bool sync_run = false;
static unsigned int interval = 0;
+static bool forever = false;
static struct timespec ref_time;
-static struct cpu_map *sock_map;
+static struct cpu_map *aggr_map;
+static int (*aggr_get_id)(struct cpu_map *m, int cpu);
static volatile int done = 0;
@@ -125,6 +133,11 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
return perf_evsel__cpus(evsel)->nr;
}
+static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
+{
+ memset(evsel->priv, 0, sizeof(struct perf_stat));
+}
+
static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
{
evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -160,6 +173,35 @@ static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
evsel->prev_raw_counts = NULL;
}
+static void perf_evlist__free_stats(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ perf_evsel__free_stat_priv(evsel);
+ perf_evsel__free_counts(evsel);
+ perf_evsel__free_prev_raw_counts(evsel);
+ }
+}
+
+static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
+ perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
+ (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
+ goto out_free;
+ }
+
+ return 0;
+
+out_free:
+ perf_evlist__free_stats(evlist);
+ return -1;
+}
+
static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
static struct stats runtime_cycles_stats[MAX_NR_CPUS];
static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
@@ -173,6 +215,29 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
static struct stats walltime_nsecs_stats;
+static void perf_stat__reset_stats(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ perf_evsel__reset_stat_priv(evsel);
+ perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
+ }
+
+ memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats));
+ memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats));
+ memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats));
+ memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats));
+ memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats));
+ memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats));
+ memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats));
+ memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats));
+ memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats));
+ memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats));
+ memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats));
+ memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
+}
+
static int create_perf_stat_counter(struct perf_evsel *evsel)
{
struct perf_event_attr *attr = &evsel->attr;
@@ -249,7 +314,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
int i;
if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
- evsel_list->threads->nr, scale) < 0)
+ thread_map__nr(evsel_list->threads), scale) < 0)
return -1;
for (i = 0; i < 3; i++)
@@ -297,56 +362,68 @@ static void print_interval(void)
struct timespec ts, rs;
char prefix[64];
- if (no_aggr) {
+ if (aggr_mode == AGGR_GLOBAL) {
list_for_each_entry(counter, &evsel_list->entries, node) {
ps = counter->priv;
memset(ps->res_stats, 0, sizeof(ps->res_stats));
- read_counter(counter);
+ read_counter_aggr(counter);
}
- } else {
+ } else {
list_for_each_entry(counter, &evsel_list->entries, node) {
ps = counter->priv;
memset(ps->res_stats, 0, sizeof(ps->res_stats));
- read_counter_aggr(counter);
+ read_counter(counter);
}
}
+
clock_gettime(CLOCK_MONOTONIC, &ts);
diff_timespec(&rs, &ts, &ref_time);
sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
if (num_print_interval == 0 && !csv_output) {
- if (aggr_socket)
+ switch (aggr_mode) {
+ case AGGR_SOCKET:
fprintf(output, "# time socket cpus counts events\n");
- else if (no_aggr)
+ break;
+ case AGGR_CORE:
+ fprintf(output, "# time core cpus counts events\n");
+ break;
+ case AGGR_NONE:
fprintf(output, "# time CPU counts events\n");
- else
+ break;
+ case AGGR_GLOBAL:
+ default:
fprintf(output, "# time counts events\n");
+ }
}
if (++num_print_interval == 25)
num_print_interval = 0;
- if (aggr_socket)
- print_aggr_socket(prefix);
- else if (no_aggr) {
+ switch (aggr_mode) {
+ case AGGR_CORE:
+ case AGGR_SOCKET:
+ print_aggr(prefix);
+ break;
+ case AGGR_NONE:
list_for_each_entry(counter, &evsel_list->entries, node)
print_counter(counter, prefix);
- } else {
+ break;
+ case AGGR_GLOBAL:
+ default:
list_for_each_entry(counter, &evsel_list->entries, node)
print_counter_aggr(counter, prefix);
}
}
-static int __run_perf_stat(int argc __maybe_unused, const char **argv)
+static int __run_perf_stat(int argc, const char **argv)
{
char msg[512];
unsigned long long t0, t1;
struct perf_evsel *counter;
struct timespec ts;
int status = 0;
- int child_ready_pipe[2], go_pipe[2];
const bool forks = (argc > 0);
- char buf;
if (interval) {
ts.tv_sec = interval / 1000;
@@ -356,61 +433,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
ts.tv_nsec = 0;
}
- if (aggr_socket
- && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
- perror("cannot build socket map");
- return -1;
- }
-
- if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
- perror("failed to create pipes");
- return -1;
- }
-
if (forks) {
- if ((child_pid = fork()) < 0)
- perror("failed to fork");
-
- if (!child_pid) {
- close(child_ready_pipe[0]);
- close(go_pipe[1]);
- fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
-
- /*
- * Do a dummy execvp to get the PLT entry resolved,
- * so we avoid the resolver overhead on the real
- * execvp call.
- */
- execvp("", (char **)argv);
-
- /*
- * Tell the parent we're ready to go
- */
- close(child_ready_pipe[1]);
-
- /*
- * Wait until the parent tells us to go.
- */
- if (read(go_pipe[0], &buf, 1) == -1)
- perror("unable to read pipe");
-
- execvp(argv[0], (char **)argv);
-
- perror(argv[0]);
- exit(-1);
+ if (perf_evlist__prepare_workload(evsel_list, &target, argv,
+ false, false) < 0) {
+ perror("failed to prepare workload");
+ return -1;
}
-
- if (perf_target__none(&target))
- evsel_list->threads->map[0] = child_pid;
-
- /*
- * Wait for the child to be ready to exec.
- */
- close(child_ready_pipe[1]);
- close(go_pipe[0]);
- if (read(child_ready_pipe[0], &buf, 1) == -1)
- perror("unable to read pipe");
- close(child_ready_pipe[0]);
}
if (group)
@@ -457,7 +485,8 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
clock_gettime(CLOCK_MONOTONIC, &ref_time);
if (forks) {
- close(go_pipe[1]);
+ perf_evlist__start_workload(evsel_list);
+
if (interval) {
while (!waitpid(child_pid, &status, WNOHANG)) {
nanosleep(&ts, NULL);
@@ -479,16 +508,16 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
update_stats(&walltime_nsecs_stats, t1 - t0);
- if (no_aggr) {
+ if (aggr_mode == AGGR_GLOBAL) {
list_for_each_entry(counter, &evsel_list->entries, node) {
- read_counter(counter);
- perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
+ read_counter_aggr(counter);
+ perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
+ thread_map__nr(evsel_list->threads));
}
} else {
list_for_each_entry(counter, &evsel_list->entries, node) {
- read_counter_aggr(counter);
- perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
- evsel_list->threads->nr);
+ read_counter(counter);
+ perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
}
}
@@ -542,26 +571,47 @@ static void print_noise(struct perf_evsel *evsel, double avg)
print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
}
-static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
{
- double msecs = avg / 1e6;
- char cpustr[16] = { '\0', };
- const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
-
- if (aggr_socket)
- sprintf(cpustr, "S%*d%s%*d%s",
+ switch (aggr_mode) {
+ case AGGR_CORE:
+ fprintf(output, "S%d-C%*d%s%*d%s",
+ cpu_map__id_to_socket(id),
+ csv_output ? 0 : -8,
+ cpu_map__id_to_cpu(id),
+ csv_sep,
+ csv_output ? 0 : 4,
+ nr,
+ csv_sep);
+ break;
+ case AGGR_SOCKET:
+ fprintf(output, "S%*d%s%*d%s",
csv_output ? 0 : -5,
- cpu,
+ id,
csv_sep,
csv_output ? 0 : 4,
nr,
csv_sep);
- else if (no_aggr)
- sprintf(cpustr, "CPU%*d%s",
+ break;
+ case AGGR_NONE:
+ fprintf(output, "CPU%*d%s",
csv_output ? 0 : -4,
- perf_evsel__cpus(evsel)->map[cpu], csv_sep);
+ perf_evsel__cpus(evsel)->map[id], csv_sep);
+ break;
+ case AGGR_GLOBAL:
+ default:
+ break;
+ }
+}
+
+static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
+{
+ double msecs = avg / 1e6;
+ const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
+
+ aggr_printout(evsel, cpu, nr);
- fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
+ fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel));
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -758,32 +808,21 @@ static void print_ll_cache_misses(int cpu,
static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
{
double total, ratio = 0.0;
- char cpustr[16] = { '\0', };
const char *fmt;
if (csv_output)
- fmt = "%s%.0f%s%s";
+ fmt = "%.0f%s%s";
else if (big_num)
- fmt = "%s%'18.0f%s%-25s";
+ fmt = "%'18.0f%s%-25s";
else
- fmt = "%s%18.0f%s%-25s";
+ fmt = "%18.0f%s%-25s";
- if (aggr_socket)
- sprintf(cpustr, "S%*d%s%*d%s",
- csv_output ? 0 : -5,
- cpu,
- csv_sep,
- csv_output ? 0 : 4,
- nr,
- csv_sep);
- else if (no_aggr)
- sprintf(cpustr, "CPU%*d%s",
- csv_output ? 0 : -4,
- perf_evsel__cpus(evsel)->map[cpu], csv_sep);
- else
+ aggr_printout(evsel, cpu, nr);
+
+ if (aggr_mode == AGGR_GLOBAL)
cpu = 0;
- fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel));
+ fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel));
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -882,23 +921,23 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
}
}
-static void print_aggr_socket(char *prefix)
+static void print_aggr(char *prefix)
{
struct perf_evsel *counter;
+ int cpu, s, s2, id, nr;
u64 ena, run, val;
- int cpu, s, s2, sock, nr;
- if (!sock_map)
+ if (!(aggr_map || aggr_get_id))
return;
- for (s = 0; s < sock_map->nr; s++) {
- sock = cpu_map__socket(sock_map, s);
+ for (s = 0; s < aggr_map->nr; s++) {
+ id = aggr_map->map[s];
list_for_each_entry(counter, &evsel_list->entries, node) {
val = ena = run = 0;
nr = 0;
for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
- s2 = cpu_map__get_socket(evsel_list->cpus, cpu);
- if (s2 != sock)
+ s2 = aggr_get_id(evsel_list->cpus, cpu);
+ if (s2 != id)
continue;
val += counter->counts->cpu[cpu].val;
ena += counter->counts->cpu[cpu].ena;
@@ -909,18 +948,15 @@ static void print_aggr_socket(char *prefix)
fprintf(output, "%s", prefix);
if (run == 0 || ena == 0) {
- fprintf(output, "S%*d%s%*d%s%*s%s%*s",
- csv_output ? 0 : -5,
- s,
- csv_sep,
- csv_output ? 0 : 4,
- nr,
- csv_sep,
+ aggr_printout(counter, cpu, nr);
+
+ fprintf(output, "%*s%s%*s",
csv_output ? 0 : 18,
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep,
csv_output ? 0 : -24,
perf_evsel__name(counter));
+
if (counter->cgrp)
fprintf(output, "%s%s",
csv_sep, counter->cgrp->name);
@@ -930,9 +966,9 @@ static void print_aggr_socket(char *prefix)
}
if (nsec_counter(counter))
- nsec_printout(sock, nr, counter, val);
+ nsec_printout(id, nr, counter, val);
else
- abs_printout(sock, nr, counter, val);
+ abs_printout(id, nr, counter, val);
if (!csv_output) {
print_noise(counter, 1.0);
@@ -1073,14 +1109,21 @@ static void print_stat(int argc, const char **argv)
fprintf(output, ":\n\n");
}
- if (aggr_socket)
- print_aggr_socket(NULL);
- else if (no_aggr) {
- list_for_each_entry(counter, &evsel_list->entries, node)
- print_counter(counter, NULL);
- } else {
+ switch (aggr_mode) {
+ case AGGR_CORE:
+ case AGGR_SOCKET:
+ print_aggr(NULL);
+ break;
+ case AGGR_GLOBAL:
list_for_each_entry(counter, &evsel_list->entries, node)
print_counter_aggr(counter, NULL);
+ break;
+ case AGGR_NONE:
+ list_for_each_entry(counter, &evsel_list->entries, node)
+ print_counter(counter, NULL);
+ break;
+ default:
+ break;
}
if (!csv_output) {
@@ -1126,6 +1169,32 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
return 0;
}
+static int perf_stat_init_aggr_mode(void)
+{
+ switch (aggr_mode) {
+ case AGGR_SOCKET:
+ if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
+ perror("cannot build socket map");
+ return -1;
+ }
+ aggr_get_id = cpu_map__get_socket;
+ break;
+ case AGGR_CORE:
+ if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) {
+ perror("cannot build core map");
+ return -1;
+ }
+ aggr_get_id = cpu_map__get_core;
+ break;
+ case AGGR_NONE:
+ case AGGR_GLOBAL:
+ default:
+ break;
+ }
+ return 0;
+}
+
+
/*
* Add default attributes, if there were no attributes specified or
* if -d/--detailed, -d -d or -d -d -d is used:
@@ -1296,7 +1365,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_INTEGER('r', "repeat", &run_count,
- "repeat command and print average + stddev (max: 100)"),
+ "repeat command and print average + stddev (max: 100, forever: 0)"),
OPT_BOOLEAN('n', "null", &null_run,
"null run - dont start any counters"),
OPT_INCR('d', "detailed", &detailed_run,
@@ -1308,7 +1377,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
stat__set_big_num),
OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
- OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"),
+ OPT_SET_UINT('A', "no-aggr", &aggr_mode,
+ "disable CPU count aggregation", AGGR_NONE),
OPT_STRING('x', "field-separator", &csv_sep, "separator",
"print counts with custom separator"),
OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -1323,20 +1393,22 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run after to the measured command"),
OPT_UINTEGER('I', "interval-print", &interval,
"print counts at regular interval in ms (>= 100)"),
- OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"),
+ OPT_SET_UINT(0, "per-socket", &aggr_mode,
+ "aggregate counts per processor socket", AGGR_SOCKET),
+ OPT_SET_UINT(0, "per-core", &aggr_mode,
+ "aggregate counts per physical processor core", AGGR_CORE),
OPT_END()
};
const char * const stat_usage[] = {
"perf stat [<options>] [<command>]",
NULL
};
- struct perf_evsel *pos;
int status = -ENOMEM, run_idx;
const char *mode;
setlocale(LC_ALL, "");
- evsel_list = perf_evlist__new(NULL, NULL);
+ evsel_list = perf_evlist__new();
if (evsel_list == NULL)
return -ENOMEM;
@@ -1399,23 +1471,21 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (!argc && !perf_target__has_task(&target))
usage_with_options(stat_usage, options);
- if (run_count <= 0)
+ if (run_count < 0) {
usage_with_options(stat_usage, options);
+ } else if (run_count == 0) {
+ forever = true;
+ run_count = 1;
+ }
/* no_aggr, cgroup are for system-wide only */
- if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
+ if ((aggr_mode != AGGR_GLOBAL || nr_cgroups)
+ && !perf_target__has_cpu(&target)) {
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
usage_with_options(stat_usage, options);
- }
-
- if (aggr_socket) {
- if (!perf_target__has_cpu(&target)) {
- fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
- usage_with_options(stat_usage, options);
- }
- no_aggr = true;
+ return -1;
}
if (add_default_attributes())
@@ -1438,17 +1508,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
return -1;
}
- list_for_each_entry(pos, &evsel_list->entries, node) {
- if (perf_evsel__alloc_stat_priv(pos) < 0 ||
- perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
- goto out_free_fd;
- }
- if (interval) {
- list_for_each_entry(pos, &evsel_list->entries, node) {
- if (perf_evsel__alloc_prev_raw_counts(pos) < 0)
- goto out_free_fd;
- }
- }
+ if (perf_evlist__alloc_stats(evsel_list, interval))
+ goto out_free_maps;
+
+ if (perf_stat_init_aggr_mode())
+ goto out;
/*
* We dont want to block the signals - that would cause
@@ -1457,28 +1521,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
* task, but being ignored by perf stat itself:
*/
atexit(sig_atexit);
- signal(SIGINT, skip_signal);
+ if (!forever)
+ signal(SIGINT, skip_signal);
signal(SIGCHLD, skip_signal);
signal(SIGALRM, skip_signal);
signal(SIGABRT, skip_signal);
status = 0;
- for (run_idx = 0; run_idx < run_count; run_idx++) {
+ for (run_idx = 0; forever || run_idx < run_count; run_idx++) {
if (run_count != 1 && verbose)
fprintf(output, "[ perf stat: executing run #%d ... ]\n",
run_idx + 1);
status = run_perf_stat(argc, argv);
+ if (forever && status != -1) {
+ print_stat(argc, argv);
+ perf_stat__reset_stats(evsel_list);
+ }
}
- if (status != -1 && !interval)
+ if (!forever && status != -1 && !interval)
print_stat(argc, argv);
-out_free_fd:
- list_for_each_entry(pos, &evsel_list->entries, node) {
- perf_evsel__free_stat_priv(pos);
- perf_evsel__free_counts(pos);
- perf_evsel__free_prev_raw_counts(pos);
- }
+
+ perf_evlist__free_stats(evsel_list);
+out_free_maps:
perf_evlist__delete_maps(evsel_list);
out:
perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 72f6eb7b4173..67bdb9f14ad6 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -231,7 +231,7 @@ static void perf_top__show_details(struct perf_top *top)
printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name);
printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
- more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
+ more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel,
0, top->sym_pcnt_filter, top->print_entries, 4);
if (top->zero)
symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
@@ -251,7 +251,8 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
{
struct hist_entry *he;
- he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
+ he = __hists__add_entry(&evsel->hists, al, NULL, sample->period,
+ sample->weight);
if (he == NULL)
return NULL;
@@ -1088,7 +1089,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
- "sort by key(s): pid, comm, dso, symbol, parent"),
+ "sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
"Show a column with the number of samples"),
OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
@@ -1116,7 +1117,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
NULL
};
- top.evlist = perf_evlist__new(NULL, NULL);
+ top.evlist = perf_evlist__new();
if (top.evlist == NULL)
return -ENOMEM;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index d222d7fc7e96..ab3ed4af1466 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -419,7 +419,7 @@ out_dump:
static int trace__run(struct trace *trace, int argc, const char **argv)
{
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
struct perf_evsel *evsel;
int err = -1, i;
unsigned long before;
@@ -452,7 +452,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
err = trace__symbols_init(trace, evlist);
if (err < 0) {
printf("Problems initializing symbol libraries!\n");
- goto out_delete_evlist;
+ goto out_delete_maps;
}
perf_evlist__config(evlist, &trace->opts);
@@ -461,23 +461,24 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
signal(SIGINT, sig_handler);
if (forks) {
- err = perf_evlist__prepare_workload(evlist, &trace->opts, argv);
+ err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
+ argv, false, false);
if (err < 0) {
printf("Couldn't run the workload!\n");
- goto out_delete_evlist;
+ goto out_delete_maps;
}
}
err = perf_evlist__open(evlist);
if (err < 0) {
printf("Couldn't create the events: %s\n", strerror(errno));
- goto out_delete_evlist;
+ goto out_delete_maps;
}
err = perf_evlist__mmap(evlist, UINT_MAX, false);
if (err < 0) {
printf("Couldn't mmap the events: %s\n", strerror(errno));
- goto out_delete_evlist;
+ goto out_close_evlist;
}
perf_evlist__enable(evlist);
@@ -526,13 +527,6 @@ again:
continue;
}
- if (sample.raw_data == NULL) {
- printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
- perf_evsel__name(evsel), sample.tid,
- sample.cpu, sample.raw_size);
- continue;
- }
-
handler = evsel->handler.func;
handler(trace, evsel, &sample);
}
@@ -540,7 +534,7 @@ again:
if (trace->nr_events == before) {
if (done)
- goto out_delete_evlist;
+ goto out_unmap_evlist;
poll(evlist->pollfd, evlist->nr_fds, -1);
}
@@ -550,6 +544,12 @@ again:
goto again;
+out_unmap_evlist:
+ perf_evlist__munmap(evlist);
+out_close_evlist:
+ perf_evlist__close(evlist);
+out_delete_maps:
+ perf_evlist__delete_maps(evlist);
out_delete_evlist:
perf_evlist__delete(evlist);
out:
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 08143bd854c7..b210d62907e4 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -36,6 +36,7 @@ extern int cmd_kvm(int argc, const char **argv, const char *prefix);
extern int cmd_test(int argc, const char **argv, const char *prefix);
extern int cmd_trace(int argc, const char **argv, const char *prefix);
extern int cmd_inject(int argc, const char **argv, const char *prefix);
+extern int cmd_mem(int argc, const char **argv, const char *prefix);
extern int find_scripts(char **scripts_array, char **scripts_path_array);
#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 3e86bbd8c2d5..0906fc401c52 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -10,17 +10,18 @@ perf-buildid-list mainporcelain common
perf-diff mainporcelain common
perf-evlist mainporcelain common
perf-inject mainporcelain common
+perf-kmem mainporcelain common
+perf-kvm mainporcelain common
perf-list mainporcelain common
-perf-sched mainporcelain common
+perf-lock mainporcelain common
+perf-mem mainporcelain common
+perf-probe mainporcelain full
perf-record mainporcelain common
perf-report mainporcelain common
+perf-sched mainporcelain common
+perf-script mainporcelain common
perf-stat mainporcelain common
+perf-test mainporcelain common
perf-timechart mainporcelain common
perf-top mainporcelain common
perf-trace mainporcelain common
-perf-script mainporcelain common
-perf-probe mainporcelain full
-perf-kmem mainporcelain common
-perf-lock mainporcelain common
-perf-kvm mainporcelain common
-perf-test mainporcelain common
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index b4eabb44e381..708fb8e9822a 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -61,15 +61,13 @@ int main(void)
}
endef
-ifndef NO_NEWT
-define SOURCE_NEWT
-#include <newt.h>
+ifndef NO_SLANG
+define SOURCE_SLANG
+#include <slang.h>
int main(void)
{
- newtInit();
- newtCls();
- return newtFinished();
+ return SLsmg_init_smg();
}
endef
endif
@@ -235,4 +233,4 @@ int main(void)
numa_available();
return 0;
}
-endef \ No newline at end of file
+endef
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 095b88207cd3..85e1aed95204 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,7 +13,7 @@
#include "util/quote.h"
#include "util/run-command.h"
#include "util/parse-events.h"
-#include "util/debugfs.h"
+#include <lk/debugfs.h>
#include <pthread.h>
const char perf_usage_string[] =
@@ -60,6 +60,7 @@ static struct cmd_struct commands[] = {
{ "trace", cmd_trace, 0 },
#endif
{ "inject", cmd_inject, 0 },
+ { "mem", cmd_mem, 0 },
};
struct pager_config {
@@ -193,13 +194,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
fprintf(stderr, "No directory given for --debugfs-dir.\n");
usage(perf_usage_string);
}
- debugfs_set_path((*argv)[1]);
+ perf_debugfs_set_path((*argv)[1]);
if (envchanged)
*envchanged = 1;
(*argv)++;
(*argc)--;
} else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
- debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
+ perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
if (envchanged)
*envchanged = 1;
@@ -461,7 +462,7 @@ int main(int argc, const char **argv)
if (!cmd)
cmd = "perf-help";
/* get debugfs mount point from /proc/mounts */
- debugfs_mount(NULL);
+ perf_debugfs_mount(NULL);
/*
* "perf-xxxx" is the same as "perf xxxx", but we obviously:
*
@@ -517,9 +518,8 @@ int main(int argc, const char **argv)
while (1) {
static int done_help;
- static int was_alias;
+ int was_alias = run_argv(&argc, &argv);
- was_alias = run_argv(&argc, &argv);
if (errno != ENOENT)
break;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 74659ecf93e0..32bd102c32b6 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -218,6 +218,7 @@ struct perf_record_opts {
bool pipe_output;
bool raw_samples;
bool sample_address;
+ bool sample_weight;
bool sample_time;
bool period;
unsigned int freq;
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index bdcceb886f77..00218f503b2e 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -147,10 +147,15 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
static int run_dir(const char *d, const char *perf)
{
+ char v[] = "-vvvvv";
+ int vcnt = min(verbose, (int) sizeof(v) - 1);
char cmd[3*PATH_MAX];
- snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
- d, d, perf, verbose ? "-v" : "");
+ if (verbose)
+ vcnt++;
+
+ snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
+ d, d, perf, vcnt, v);
return system(cmd);
}
@@ -173,6 +178,6 @@ int test__attr(void)
!lstat(path_perf, &st))
return run_dir(path_dir, path_perf);
- fprintf(stderr, " (ommitted)");
+ fprintf(stderr, " (omitted)");
return 0;
}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
index 2f629ca485bc..c9b4b6269b51 100644
--- a/tools/perf/tests/attr.py
+++ b/tools/perf/tests/attr.py
@@ -24,6 +24,7 @@ class Unsup(Exception):
class Event(dict):
terms = [
+ 'cpu',
'flags',
'type',
'size',
@@ -121,7 +122,7 @@ class Test(object):
parser = ConfigParser.SafeConfigParser()
parser.read(path)
- log.debug("running '%s'" % path)
+ log.warning("running '%s'" % path)
self.path = path
self.test_dir = options.test_dir
@@ -172,7 +173,7 @@ class Test(object):
self.perf, self.command, tempdir, self.args)
ret = os.WEXITSTATUS(os.system(cmd))
- log.warning(" running '%s' ret %d " % (cmd, ret))
+ log.info(" '%s' ret %d " % (cmd, ret))
if ret != int(self.ret):
raise Unsup(self)
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
index 5bc3880f7be5..b4fc835de607 100644
--- a/tools/perf/tests/attr/base-record
+++ b/tools/perf/tests/attr/base-record
@@ -2,6 +2,7 @@
fd=1
group_fd=-1
flags=0
+cpu=*
type=0|1
size=96
config=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
index 4bd79a82784f..748ee949a204 100644
--- a/tools/perf/tests/attr/base-stat
+++ b/tools/perf/tests/attr/base-stat
@@ -2,6 +2,7 @@
fd=1
group_fd=-1
flags=0
+cpu=*
type=0
size=96
config=0
diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0
new file mode 100644
index 000000000000..d6a7e43f61b3
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-C0
@@ -0,0 +1,13 @@
+[config]
+command = record
+args = -C 0 kill >/dev/null 2>&1
+
+[event:base-record]
+cpu=0
+
+# no enable on exec for CPU attached
+enable_on_exec=0
+
+# PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD
+# + PERF_SAMPLE_CPU added by -C 0
+sample_type=391
diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/attr/test-stat-C0
new file mode 100644
index 000000000000..aa835950751f
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-C0
@@ -0,0 +1,9 @@
+[config]
+command = stat
+args = -e cycles -C 0 kill >/dev/null 2>&1
+ret = 1
+
+[event:base-stat]
+# events are enabled by default when attached to cpu
+disabled=0
+enable_on_exec=0
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
new file mode 100644
index 000000000000..68daa289e94c
--- /dev/null
+++ b/tools/perf/tests/bp_signal.c
@@ -0,0 +1,186 @@
+/*
+ * Inspired by breakpoint overflow test done by
+ * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests
+ * (git://github.com/deater/perf_event_tests)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <linux/compiler.h>
+#include <linux/hw_breakpoint.h>
+
+#include "tests.h"
+#include "debug.h"
+#include "perf.h"
+
+static int fd1;
+static int fd2;
+static int overflows;
+
+__attribute__ ((noinline))
+static int test_function(void)
+{
+ return time(NULL);
+}
+
+static void sig_handler(int signum __maybe_unused,
+ siginfo_t *oh __maybe_unused,
+ void *uc __maybe_unused)
+{
+ overflows++;
+
+ if (overflows > 10) {
+ /*
+ * This should be executed only once during
+ * this test, if we are here for the 10th
+ * time, consider this the recursive issue.
+ *
+ * We can get out of here by disable events,
+ * so no new SIGIO is delivered.
+ */
+ ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+ ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+ }
+}
+
+static int bp_event(void *fn, int setup_signal)
+{
+ struct perf_event_attr pe;
+ int fd;
+
+ memset(&pe, 0, sizeof(struct perf_event_attr));
+ pe.type = PERF_TYPE_BREAKPOINT;
+ pe.size = sizeof(struct perf_event_attr);
+
+ pe.config = 0;
+ pe.bp_type = HW_BREAKPOINT_X;
+ pe.bp_addr = (unsigned long) fn;
+ pe.bp_len = sizeof(long);
+
+ pe.sample_period = 1;
+ pe.sample_type = PERF_SAMPLE_IP;
+ pe.wakeup_events = 1;
+
+ pe.disabled = 1;
+ pe.exclude_kernel = 1;
+ pe.exclude_hv = 1;
+
+ fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
+ if (fd < 0) {
+ pr_debug("failed opening event %llx\n", pe.config);
+ return TEST_FAIL;
+ }
+
+ if (setup_signal) {
+ fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+ fcntl(fd, F_SETSIG, SIGIO);
+ fcntl(fd, F_SETOWN, getpid());
+ }
+
+ ioctl(fd, PERF_EVENT_IOC_RESET, 0);
+
+ return fd;
+}
+
+static long long bp_count(int fd)
+{
+ long long count;
+ int ret;
+
+ ret = read(fd, &count, sizeof(long long));
+ if (ret != sizeof(long long)) {
+ pr_debug("failed to read: %d\n", ret);
+ return TEST_FAIL;
+ }
+
+ return count;
+}
+
+int test__bp_signal(void)
+{
+ struct sigaction sa;
+ long long count1, count2;
+
+ /* setup SIGIO signal handler */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_sigaction = (void *) sig_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ pr_debug("failed setting up signal handler\n");
+ return TEST_FAIL;
+ }
+
+ /*
+ * We create following events:
+ *
+ * fd1 - breakpoint event on test_function with SIGIO
+ * signal configured. We should get signal
+ * notification each time the breakpoint is hit
+ *
+ * fd2 - breakpoint event on sig_handler without SIGIO
+ * configured.
+ *
+ * Following processing should happen:
+ * - execute test_function
+ * - fd1 event breakpoint hit -> count1 == 1
+ * - SIGIO is delivered -> overflows == 1
+ * - fd2 event breakpoint hit -> count2 == 1
+ *
+ * The test case check following error conditions:
+ * - we get stuck in signal handler because of debug
+ * exception being triggered receursively due to
+ * the wrong RF EFLAG management
+ *
+ * - we never trigger the sig_handler breakpoint due
+ * to the rong RF EFLAG management
+ *
+ */
+
+ fd1 = bp_event(test_function, 1);
+ fd2 = bp_event(sig_handler, 0);
+
+ ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
+ ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
+
+ /*
+ * Kick off the test by trigering 'fd1'
+ * breakpoint.
+ */
+ test_function();
+
+ ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
+ ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
+
+ count1 = bp_count(fd1);
+ count2 = bp_count(fd2);
+
+ close(fd1);
+ close(fd2);
+
+ pr_debug("count1 %lld, count2 %lld, overflow %d\n",
+ count1, count2, overflows);
+
+ if (count1 != 1) {
+ if (count1 == 11)
+ pr_debug("failed: RF EFLAG recursion issue detected\n");
+ else
+ pr_debug("failed: wrong count for bp1%lld\n", count1);
+ }
+
+ if (overflows != 1)
+ pr_debug("failed: wrong overflow hit\n");
+
+ if (count2 != 1)
+ pr_debug("failed: wrong count for bp2\n");
+
+ return count1 == 1 && overflows == 1 && count2 == 1 ?
+ TEST_OK : TEST_FAIL;
+}
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
new file mode 100644
index 000000000000..fe7ed28815f8
--- /dev/null
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -0,0 +1,126 @@
+/*
+ * Originally done by Vince Weaver <vincent.weaver@maine.edu> for
+ * perf_event_tests (git://github.com/deater/perf_event_tests)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <time.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <linux/compiler.h>
+#include <linux/hw_breakpoint.h>
+
+#include "tests.h"
+#include "debug.h"
+#include "perf.h"
+
+static int overflows;
+
+__attribute__ ((noinline))
+static int test_function(void)
+{
+ return time(NULL);
+}
+
+static void sig_handler(int signum __maybe_unused,
+ siginfo_t *oh __maybe_unused,
+ void *uc __maybe_unused)
+{
+ overflows++;
+}
+
+static long long bp_count(int fd)
+{
+ long long count;
+ int ret;
+
+ ret = read(fd, &count, sizeof(long long));
+ if (ret != sizeof(long long)) {
+ pr_debug("failed to read: %d\n", ret);
+ return TEST_FAIL;
+ }
+
+ return count;
+}
+
+#define EXECUTIONS 10000
+#define THRESHOLD 100
+
+int test__bp_signal_overflow(void)
+{
+ struct perf_event_attr pe;
+ struct sigaction sa;
+ long long count;
+ int fd, i, fails = 0;
+
+ /* setup SIGIO signal handler */
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_sigaction = (void *) sig_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ pr_debug("failed setting up signal handler\n");
+ return TEST_FAIL;
+ }
+
+ memset(&pe, 0, sizeof(struct perf_event_attr));
+ pe.type = PERF_TYPE_BREAKPOINT;
+ pe.size = sizeof(struct perf_event_attr);
+
+ pe.config = 0;
+ pe.bp_type = HW_BREAKPOINT_X;
+ pe.bp_addr = (unsigned long) test_function;
+ pe.bp_len = sizeof(long);
+
+ pe.sample_period = THRESHOLD;
+ pe.sample_type = PERF_SAMPLE_IP;
+ pe.wakeup_events = 1;
+
+ pe.disabled = 1;
+ pe.exclude_kernel = 1;
+ pe.exclude_hv = 1;
+
+ fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
+ if (fd < 0) {
+ pr_debug("failed opening event %llx\n", pe.config);
+ return TEST_FAIL;
+ }
+
+ fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
+ fcntl(fd, F_SETSIG, SIGIO);
+ fcntl(fd, F_SETOWN, getpid());
+
+ ioctl(fd, PERF_EVENT_IOC_RESET, 0);
+ ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
+
+ for (i = 0; i < EXECUTIONS; i++)
+ test_function();
+
+ ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
+
+ count = bp_count(fd);
+
+ close(fd);
+
+ pr_debug("count %lld, overflow %d\n",
+ count, overflows);
+
+ if (count != EXECUTIONS) {
+ pr_debug("\tWrong number of executions %lld != %d\n",
+ count, EXECUTIONS);
+ fails++;
+ }
+
+ if (overflows != EXECUTIONS / THRESHOLD) {
+ pr_debug("\tWrong number of overflows %d != %d\n",
+ overflows, EXECUTIONS / THRESHOLD);
+ fails++;
+ }
+
+ return fails ? TEST_FAIL : TEST_OK;
+}
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index acb98e0e39f2..0918ada4cc41 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -78,6 +78,22 @@ static struct test {
.func = test__python_use,
},
{
+ .desc = "Test breakpoint overflow signal handler",
+ .func = test__bp_signal,
+ },
+ {
+ .desc = "Test breakpoint overflow sampling",
+ .func = test__bp_signal_overflow,
+ },
+ {
+ .desc = "Test number of exit event of a simple workload",
+ .func = test__task_exit,
+ },
+ {
+ .desc = "Test software clock events have valid period values",
+ .func = test__sw_clock_freq,
+ },
+ {
.func = NULL,
},
};
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 0fd99a9adb91..0197bda9c461 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -8,7 +8,7 @@ static int perf_evsel__roundtrip_cache_name_test(void)
char name[128];
int type, op, err = 0, ret = 0, i, idx;
struct perf_evsel *evsel;
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
if (evlist == NULL)
return -ENOMEM;
@@ -64,7 +64,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names)
{
int i, err;
struct perf_evsel *evsel;
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
if (evlist == NULL)
return -ENOMEM;
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 1be64a6c5daf..89085a9615e2 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -223,7 +223,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample, 0) < 0)
goto out;
- he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+ he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
if (he == NULL)
goto out;
@@ -247,7 +247,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample, 0) < 0)
goto out;
- he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
+ he = __hists__add_entry(&evsel->hists, &al, NULL, 1, 1);
if (he == NULL)
goto out;
@@ -436,7 +436,7 @@ int test__hists_link(void)
struct machines machines;
struct machine *machine = NULL;
struct perf_evsel *evsel, *first;
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
if (evlist == NULL)
return -ENOMEM;
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index cdd50755af51..5b1b5aba722b 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -53,12 +53,14 @@ int test__basic_mmap(void)
goto out_free_cpus;
}
- evlist = perf_evlist__new(cpus, threads);
+ evlist = perf_evlist__new();
if (evlist == NULL) {
pr_debug("perf_evlist__new\n");
goto out_free_cpus;
}
+ perf_evlist__set_maps(evlist, cpus, threads);
+
for (i = 0; i < nsyscalls; ++i) {
char name[64];
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
index 1c52fdc1164e..fc5b9fca8b47 100644
--- a/tools/perf/tests/open-syscall-tp-fields.c
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -18,7 +18,7 @@ int test__syscall_open_tp_fields(void)
};
const char *filename = "/etc/passwd";
int flags = O_RDONLY | O_DIRECTORY;
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
struct perf_evsel *evsel;
int err = -1, i, nr_events = 0, nr_polls = 0;
@@ -48,13 +48,13 @@ int test__syscall_open_tp_fields(void)
err = perf_evlist__open(evlist);
if (err < 0) {
pr_debug("perf_evlist__open: %s\n", strerror(errno));
- goto out_delete_evlist;
+ goto out_delete_maps;
}
err = perf_evlist__mmap(evlist, UINT_MAX, false);
if (err < 0) {
pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
- goto out_delete_evlist;
+ goto out_close_evlist;
}
perf_evlist__enable(evlist);
@@ -110,6 +110,10 @@ out_ok:
err = 0;
out_munmap:
perf_evlist__munmap(evlist);
+out_close_evlist:
+ perf_evlist__close(evlist);
+out_delete_maps:
+ perf_evlist__delete_maps(evlist);
out_delete_evlist:
perf_evlist__delete(evlist);
out:
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index c5636f36fe31..0275bab4ea9e 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,7 +3,7 @@
#include "evsel.h"
#include "evlist.h"
#include "sysfs.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include "tests.h"
#include <linux/hw_breakpoint.h>
@@ -1218,7 +1218,7 @@ static int test_event(struct evlist_test *e)
struct perf_evlist *evlist;
int ret;
- evlist = perf_evlist__new(NULL, NULL);
+ evlist = perf_evlist__new();
if (evlist == NULL)
return -ENOMEM;
@@ -1321,7 +1321,7 @@ static int test_pmu_events(void)
ret = stat(path, &st);
if (ret) {
- pr_debug("ommiting PMU cpu events tests\n");
+ pr_debug("omitting PMU cpu events tests\n");
return 0;
}
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 1e8e5128d0da..72d8881873b0 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -45,7 +45,7 @@ int test__PERF_RECORD(void)
};
cpu_set_t cpu_mask;
size_t cpu_mask_size = sizeof(cpu_mask);
- struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
+ struct perf_evlist *evlist = perf_evlist__new();
struct perf_evsel *evsel;
struct perf_sample sample;
const char *cmd = "sleep";
@@ -93,7 +93,8 @@ int test__PERF_RECORD(void)
* so that we have time to open the evlist (calling sys_perf_event_open
* on all the fds) and then mmap them.
*/
- err = perf_evlist__prepare_workload(evlist, &opts, argv);
+ err = perf_evlist__prepare_workload(evlist, &opts.target, argv,
+ false, false);
if (err < 0) {
pr_debug("Couldn't run the workload!\n");
goto out_delete_maps;
@@ -142,7 +143,7 @@ int test__PERF_RECORD(void)
err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
if (err < 0) {
pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
- goto out_delete_maps;
+ goto out_close_evlist;
}
/*
@@ -305,6 +306,8 @@ found_exit:
}
out_err:
perf_evlist__munmap(evlist);
+out_close_evlist:
+ perf_evlist__close(evlist);
out_delete_maps:
perf_evlist__delete_maps(evlist);
out_delete_evlist:
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
new file mode 100644
index 000000000000..2e41e2d32ccc
--- /dev/null
+++ b/tools/perf/tests/sw-clock.c
@@ -0,0 +1,119 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+#include "tests.h"
+#include "util/evsel.h"
+#include "util/evlist.h"
+#include "util/cpumap.h"
+#include "util/thread_map.h"
+
+#define NR_LOOPS 1000000
+
+/*
+ * This test will open software clock events (cpu-clock, task-clock)
+ * then check their frequency -> period conversion has no artifact of
+ * setting period to 1 forcefully.
+ */
+static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
+{
+ int i, err = -1;
+ volatile int tmp = 0;
+ u64 total_periods = 0;
+ int nr_samples = 0;
+ union perf_event *event;
+ struct perf_evsel *evsel;
+ struct perf_evlist *evlist;
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_SOFTWARE,
+ .config = clock_id,
+ .sample_type = PERF_SAMPLE_PERIOD,
+ .exclude_kernel = 1,
+ .disabled = 1,
+ .freq = 1,
+ };
+
+ attr.sample_freq = 10000;
+
+ evlist = perf_evlist__new();
+ if (evlist == NULL) {
+ pr_debug("perf_evlist__new\n");
+ return -1;
+ }
+
+ evsel = perf_evsel__new(&attr, 0);
+ if (evsel == NULL) {
+ pr_debug("perf_evsel__new\n");
+ goto out_free_evlist;
+ }
+ perf_evlist__add(evlist, evsel);
+
+ evlist->cpus = cpu_map__dummy_new();
+ evlist->threads = thread_map__new_by_tid(getpid());
+ if (!evlist->cpus || !evlist->threads) {
+ err = -ENOMEM;
+ pr_debug("Not enough memory to create thread/cpu maps\n");
+ goto out_delete_maps;
+ }
+
+ perf_evlist__open(evlist);
+
+ err = perf_evlist__mmap(evlist, 128, true);
+ if (err < 0) {
+ pr_debug("failed to mmap event: %d (%s)\n", errno,
+ strerror(errno));
+ goto out_close_evlist;
+ }
+
+ perf_evlist__enable(evlist);
+
+ /* collect samples */
+ for (i = 0; i < NR_LOOPS; i++)
+ tmp++;
+
+ perf_evlist__disable(evlist);
+
+ while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
+ struct perf_sample sample;
+
+ if (event->header.type != PERF_RECORD_SAMPLE)
+ continue;
+
+ err = perf_evlist__parse_sample(evlist, event, &sample);
+ if (err < 0) {
+ pr_debug("Error during parse sample\n");
+ goto out_unmap_evlist;
+ }
+
+ total_periods += sample.period;
+ nr_samples++;
+ }
+
+ if ((u64) nr_samples == total_periods) {
+ pr_debug("All (%d) samples have period value of 1!\n",
+ nr_samples);
+ err = -1;
+ }
+
+out_unmap_evlist:
+ perf_evlist__munmap(evlist);
+out_close_evlist:
+ perf_evlist__close(evlist);
+out_delete_maps:
+ perf_evlist__delete_maps(evlist);
+out_free_evlist:
+ perf_evlist__delete(evlist);
+ return err;
+}
+
+int test__sw_clock_freq(void)
+{
+ int ret;
+
+ ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK);
+ if (!ret)
+ ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK);
+
+ return ret;
+}
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
new file mode 100644
index 000000000000..28fe5894b061
--- /dev/null
+++ b/tools/perf/tests/task-exit.c
@@ -0,0 +1,123 @@
+#include "evlist.h"
+#include "evsel.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "tests.h"
+
+#include <signal.h>
+
+static int exited;
+static int nr_exit;
+
+static void sig_handler(int sig)
+{
+ exited = 1;
+
+ if (sig == SIGUSR1)
+ nr_exit = -1;
+}
+
+/*
+ * This test will start a workload that does nothing then it checks
+ * if the number of exit event reported by the kernel is 1 or not
+ * in order to check the kernel returns correct number of event.
+ */
+int test__task_exit(void)
+{
+ int err = -1;
+ union perf_event *event;
+ struct perf_evsel *evsel;
+ struct perf_evlist *evlist;
+ struct perf_target target = {
+ .uid = UINT_MAX,
+ .uses_mmap = true,
+ };
+ const char *argv[] = { "true", NULL };
+
+ signal(SIGCHLD, sig_handler);
+ signal(SIGUSR1, sig_handler);
+
+ evlist = perf_evlist__new();
+ if (evlist == NULL) {
+ pr_debug("perf_evlist__new\n");
+ return -1;
+ }
+ /*
+ * We need at least one evsel in the evlist, use the default
+ * one: "cycles".
+ */
+ err = perf_evlist__add_default(evlist);
+ if (err < 0) {
+ pr_debug("Not enough memory to create evsel\n");
+ goto out_free_evlist;
+ }
+
+ /*
+ * Create maps of threads and cpus to monitor. In this case
+ * we start with all threads and cpus (-1, -1) but then in
+ * perf_evlist__prepare_workload we'll fill in the only thread
+ * we're monitoring, the one forked there.
+ */
+ evlist->cpus = cpu_map__dummy_new();
+ evlist->threads = thread_map__new_by_tid(-1);
+ if (!evlist->cpus || !evlist->threads) {
+ err = -ENOMEM;
+ pr_debug("Not enough memory to create thread/cpu maps\n");
+ goto out_delete_maps;
+ }
+
+ err = perf_evlist__prepare_workload(evlist, &target, argv, false, true);
+ if (err < 0) {
+ pr_debug("Couldn't run the workload!\n");
+ goto out_delete_maps;
+ }
+
+ evsel = perf_evlist__first(evlist);
+ evsel->attr.task = 1;
+ evsel->attr.sample_freq = 0;
+ evsel->attr.inherit = 0;
+ evsel->attr.watermark = 0;
+ evsel->attr.wakeup_events = 1;
+ evsel->attr.exclude_kernel = 1;
+
+ err = perf_evlist__open(evlist);
+ if (err < 0) {
+ pr_debug("Couldn't open the evlist: %s\n", strerror(-err));
+ goto out_delete_maps;
+ }
+
+ if (perf_evlist__mmap(evlist, 128, true) < 0) {
+ pr_debug("failed to mmap events: %d (%s)\n", errno,
+ strerror(errno));
+ goto out_close_evlist;
+ }
+
+ perf_evlist__start_workload(evlist);
+
+retry:
+ while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
+ if (event->header.type != PERF_RECORD_EXIT)
+ continue;
+
+ nr_exit++;
+ }
+
+ if (!exited || !nr_exit) {
+ poll(evlist->pollfd, evlist->nr_fds, -1);
+ goto retry;
+ }
+
+ if (nr_exit != 1) {
+ pr_debug("received %d EXIT records\n", nr_exit);
+ err = -1;
+ }
+
+ perf_evlist__munmap(evlist);
+out_close_evlist:
+ perf_evlist__close(evlist);
+out_delete_maps:
+ perf_evlist__delete_maps(evlist);
+out_free_evlist:
+ perf_evlist__delete(evlist);
+ return err;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 5de0be1ff4b6..dd7feae2d37b 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -23,5 +23,9 @@ int test__dso_data(void);
int test__parse_events(void);
int test__hists_link(void);
int test__python_use(void);
+int test__bp_signal(void);
+int test__bp_signal_overflow(void);
+int test__task_exit(void);
+int test__sw_clock_freq(void);
#endif /* TESTS_H */
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 809ea4632a34..bbc782e364b0 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -2,7 +2,6 @@
#include "../cache.h"
#include "../../perf.h"
#include "libslang.h"
-#include <newt.h>
#include "ui.h"
#include "util.h"
#include <linux/compiler.h>
@@ -234,7 +233,7 @@ void ui_browser__reset_index(struct ui_browser *browser)
void __ui_browser__show_title(struct ui_browser *browser, const char *title)
{
SLsmg_gotorc(0, 0);
- ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
+ ui_browser__set_color(browser, HE_COLORSET_ROOT);
slsmg_write_nstring(title, browser->width + 1);
}
@@ -514,6 +513,12 @@ static struct ui_browser_colorset {
.bg = "default",
},
{
+ .colorset = HE_COLORSET_ROOT,
+ .name = "root",
+ .fg = "white",
+ .bg = "blue",
+ },
+ {
.name = NULL,
}
};
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index af70314605e5..404ff66a3e36 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -11,6 +11,7 @@
#define HE_COLORSET_SELECTED 53
#define HE_COLORSET_CODE 54
#define HE_COLORSET_ADDR 55
+#define HE_COLORSET_ROOT 56
struct ui_browser {
u64 index, top_idx;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 7dca1555c610..cc64d3f7fc36 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -8,15 +8,19 @@
#include "../../util/hist.h"
#include "../../util/sort.h"
#include "../../util/symbol.h"
+#include "../../util/evsel.h"
#include <pthread.h>
-#include <newt.h>
struct browser_disasm_line {
struct rb_node rb_node;
- double percent;
u32 idx;
int idx_asm;
int jump_sources;
+ /*
+ * actual length of this array is saved on the nr_events field
+ * of the struct annotate_browser
+ */
+ double percent[1];
};
static struct annotate_browser_opt {
@@ -33,8 +37,9 @@ struct annotate_browser {
struct ui_browser b;
struct rb_root entries;
struct rb_node *curr_hot;
- struct disasm_line *selection;
+ struct disasm_line *selection;
struct disasm_line **offsets;
+ int nr_events;
u64 start;
int nr_asm_entries;
int nr_entries;
@@ -94,14 +99,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
(!current_entry || (browser->use_navkeypressed &&
!browser->navkeypressed)));
int width = browser->width, printed;
+ int i, pcnt_width = 7 * ab->nr_events;
+ double percent_max = 0.0;
char bf[256];
- if (dl->offset != -1 && bdl->percent != 0.0) {
- ui_browser__set_percent_color(browser, bdl->percent, current_entry);
- slsmg_printf("%6.2f ", bdl->percent);
+ for (i = 0; i < ab->nr_events; i++) {
+ if (bdl->percent[i] > percent_max)
+ percent_max = bdl->percent[i];
+ }
+
+ if (dl->offset != -1 && percent_max != 0.0) {
+ for (i = 0; i < ab->nr_events; i++) {
+ ui_browser__set_percent_color(browser, bdl->percent[i],
+ current_entry);
+ slsmg_printf("%6.2f ", bdl->percent[i]);
+ }
} else {
ui_browser__set_percent_color(browser, 0, current_entry);
- slsmg_write_nstring(" ", 7);
+ slsmg_write_nstring(" ", pcnt_width);
}
SLsmg_write_char(' ');
@@ -111,12 +126,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
width += 1;
if (!*dl->line)
- slsmg_write_nstring(" ", width - 7);
+ slsmg_write_nstring(" ", width - pcnt_width);
else if (dl->offset == -1) {
printed = scnprintf(bf, sizeof(bf), "%*s ",
ab->addr_width, " ");
slsmg_write_nstring(bf, printed);
- slsmg_write_nstring(dl->line, width - printed - 6);
+ slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
} else {
u64 addr = dl->offset;
int color = -1;
@@ -175,7 +190,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
}
disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
- slsmg_write_nstring(bf, width - 10 - printed);
+ slsmg_write_nstring(bf, width - pcnt_width - 3 - printed);
}
if (current_entry)
@@ -200,6 +215,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
unsigned int from, to;
struct map_symbol *ms = ab->b.priv;
struct symbol *sym = ms->sym;
+ u8 pcnt_width = 7;
/* PLT symbols contain external offsets */
if (strstr(sym->name, "@plt"))
@@ -223,57 +239,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
to = (u64)btarget->idx;
}
+ pcnt_width *= ab->nr_events;
+
ui_browser__set_color(browser, HE_COLORSET_CODE);
- __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
+ __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
+ from, to);
}
static unsigned int annotate_browser__refresh(struct ui_browser *browser)
{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
int ret = ui_browser__list_head_refresh(browser);
+ int pcnt_width;
+
+ pcnt_width = 7 * ab->nr_events;
if (annotate_browser__opts.jump_arrows)
annotate_browser__draw_current_jump(browser);
ui_browser__set_color(browser, HE_COLORSET_NORMAL);
- __ui_browser__vline(browser, 7, 0, browser->height - 1);
+ __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
return ret;
}
-static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
+static int disasm__cmp(struct browser_disasm_line *a,
+ struct browser_disasm_line *b, int nr_pcnt)
{
- double percent = 0.0;
-
- if (dl->offset != -1) {
- int len = sym->end - sym->start;
- unsigned int hits = 0;
- struct annotation *notes = symbol__annotation(sym);
- struct source_line *src_line = notes->src->lines;
- struct sym_hist *h = annotation__histogram(notes, evidx);
- s64 offset = dl->offset;
- struct disasm_line *next;
+ int i;
- next = disasm__get_next_ip_line(&notes->src->source, dl);
- while (offset < (s64)len &&
- (next == NULL || offset < next->offset)) {
- if (src_line) {
- percent += src_line[offset].percent;
- } else
- hits += h->addr[offset];
-
- ++offset;
- }
- /*
- * If the percentage wasn't already calculated in
- * symbol__get_source_line, do it now:
- */
- if (src_line == NULL && h->sum)
- percent = 100.0 * hits / h->sum;
+ for (i = 0; i < nr_pcnt; i++) {
+ if (a->percent[i] == b->percent[i])
+ continue;
+ return a->percent[i] < b->percent[i];
}
-
- return percent;
+ return 0;
}
-static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
+static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
+ int nr_events)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -282,7 +285,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l
while (*p != NULL) {
parent = *p;
l = rb_entry(parent, struct browser_disasm_line, rb_node);
- if (bdl->percent < l->percent)
+
+ if (disasm__cmp(bdl, l, nr_events))
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -331,12 +335,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
}
static void annotate_browser__calc_percent(struct annotate_browser *browser,
- int evidx)
+ struct perf_evsel *evsel)
{
struct map_symbol *ms = browser->b.priv;
struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
- struct disasm_line *pos;
+ struct disasm_line *pos, *next;
+ s64 len = symbol__size(sym);
browser->entries = RB_ROOT;
@@ -344,12 +349,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
list_for_each_entry(pos, &notes->src->source, node) {
struct browser_disasm_line *bpos = disasm_line__browser(pos);
- bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
- if (bpos->percent < 0.01) {
+ const char *path = NULL;
+ double max_percent = 0.0;
+ int i;
+
+ if (pos->offset == -1) {
+ RB_CLEAR_NODE(&bpos->rb_node);
+ continue;
+ }
+
+ next = disasm__get_next_ip_line(&notes->src->source, pos);
+
+ for (i = 0; i < browser->nr_events; i++) {
+ bpos->percent[i] = disasm__calc_percent(notes,
+ evsel->idx + i,
+ pos->offset,
+ next ? next->offset : len,
+ &path);
+
+ if (max_percent < bpos->percent[i])
+ max_percent = bpos->percent[i];
+ }
+
+ if (max_percent < 0.01) {
RB_CLEAR_NODE(&bpos->rb_node);
continue;
}
- disasm_rb_tree__insert(&browser->entries, bpos);
+ disasm_rb_tree__insert(&browser->entries, bpos,
+ browser->nr_events);
}
pthread_mutex_unlock(&notes->lock);
@@ -401,7 +428,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
browser->b.nr_entries = browser->nr_asm_entries;
}
-static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
+static bool annotate_browser__callq(struct annotate_browser *browser,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct map_symbol *ms = browser->b.priv;
@@ -432,7 +460,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
}
pthread_mutex_unlock(&notes->lock);
- symbol__tui_annotate(target, ms->map, evidx, hbt);
+ symbol__tui_annotate(target, ms->map, evsel, hbt);
ui_browser__show_title(&browser->b, sym->name);
return true;
}
@@ -615,7 +643,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
browser->addr_width += browser->jumps_width + 1;
}
-static int annotate_browser__run(struct annotate_browser *browser, int evidx,
+static int annotate_browser__run(struct annotate_browser *browser,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct rb_node *nd = NULL;
@@ -628,7 +657,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
if (ui_browser__show(&browser->b, sym->name, help) < 0)
return -1;
- annotate_browser__calc_percent(browser, evidx);
+ annotate_browser__calc_percent(browser, evsel);
if (browser->curr_hot) {
annotate_browser__set_rb_top(browser, browser->curr_hot);
@@ -641,7 +670,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
key = ui_browser__run(&browser->b, delay_secs);
if (delay_secs != 0) {
- annotate_browser__calc_percent(browser, evidx);
+ annotate_browser__calc_percent(browser, evsel);
/*
* Current line focus got out of the list of most active
* lines, NULL it so that if TAB|UNTAB is pressed, we
@@ -657,7 +686,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
hbt->timer(hbt->arg);
if (delay_secs != 0)
- symbol__annotate_decay_histogram(sym, evidx);
+ symbol__annotate_decay_histogram(sym, evsel->idx);
continue;
case K_TAB:
if (nd != NULL) {
@@ -754,7 +783,7 @@ show_help:
goto show_sup_ins;
goto out;
} else if (!(annotate_browser__jump(browser) ||
- annotate_browser__callq(browser, evidx, hbt))) {
+ annotate_browser__callq(browser, evsel, hbt))) {
show_sup_ins:
ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
}
@@ -776,10 +805,10 @@ out:
return key;
}
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
- return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt);
+ return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt);
}
static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
@@ -826,7 +855,8 @@ static inline int width_jumps(int n)
return 1;
}
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+int symbol__tui_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
struct disasm_line *pos, *n;
@@ -847,6 +877,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
},
};
int ret = -1;
+ int nr_pcnt = 1;
+ size_t sizeof_bdl = sizeof(struct browser_disasm_line);
if (sym == NULL)
return -1;
@@ -862,7 +894,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
return -1;
}
- if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
+ if (perf_evsel__is_group_event(evsel)) {
+ nr_pcnt = evsel->nr_members;
+ sizeof_bdl += sizeof(double) * (nr_pcnt - 1);
+ }
+
+ if (symbol__annotate(sym, map, sizeof_bdl) < 0) {
ui__error("%s", ui_helpline__last_msg);
goto out_free_offsets;
}
@@ -900,6 +937,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
browser.max_addr_width = hex_width(sym->end);
browser.jumps_width = width_jumps(browser.max_jump_sources);
+ browser.nr_events = nr_pcnt;
browser.b.nr_entries = browser.nr_entries;
browser.b.entries = &notes->src->source,
browser.b.width += 18; /* Percentage */
@@ -909,7 +947,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
annotate_browser__update_addr_width(&browser);
- ret = annotate_browser__run(&browser, evidx, hbt);
+ ret = annotate_browser__run(&browser, evsel, hbt);
list_for_each_entry_safe(pos, n, &notes->src->source, node) {
list_del(&pos->node);
disasm_line__free(pos);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index aa22704047d6..d88a2d0acb6d 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2,7 +2,6 @@
#include "../libslang.h"
#include <stdlib.h>
#include <string.h>
-#include <newt.h>
#include <linux/rbtree.h>
#include "../../util/evsel.h"
@@ -1193,7 +1192,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
char buf[512];
size_t buflen = sizeof(buf);
- if (symbol_conf.event_group && evsel->nr_members > 1) {
+ if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos;
perf_evsel__group_desc(evsel, buf, buflen);
@@ -1599,7 +1598,7 @@ do_annotate:
* Don't let this be freed, say, by hists__decay_entry.
*/
he->used = true;
- err = hist_entry__tui_annotate(he, evsel->idx, hbt);
+ err = hist_entry__tui_annotate(he, evsel, hbt);
he->used = false;
/*
* offer option to annotate the other branch source or target
@@ -1709,7 +1708,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
HE_COLORSET_NORMAL);
- if (symbol_conf.event_group && evsel->nr_members > 1) {
+ if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos;
ev_name = perf_evsel__group_name(evsel);
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index 98851d55a53e..95c7cfb8f2c6 100644
--- a/tools/perf/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -1,6 +1,5 @@
#include "../libslang.h"
#include <elf.h>
-#include <newt.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <string.h>
@@ -10,41 +9,9 @@
#include "../../util/symbol.h"
#include "../browser.h"
#include "../helpline.h"
+#include "../keysyms.h"
#include "map.h"
-static int ui_entry__read(const char *title, char *bf, size_t size, int width)
-{
- struct newtExitStruct es;
- newtComponent form, entry;
- const char *result;
- int err = -1;
-
- newtCenteredWindow(width, 1, title);
- form = newtForm(NULL, NULL, 0);
- if (form == NULL)
- return -1;
-
- entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
- if (entry == NULL)
- goto out_free_form;
-
- newtFormAddComponent(form, entry);
- newtFormAddHotKey(form, NEWT_KEY_ENTER);
- newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
- newtFormAddHotKey(form, NEWT_KEY_LEFT);
- newtFormAddHotKey(form, CTRL('c'));
- newtFormRun(form, &es);
-
- if (result != NULL) {
- strncpy(bf, result, size);
- err = 0;
- }
-out_free_form:
- newtPopWindow();
- newtFormDestroy(form);
- return err;
-}
-
struct map_browser {
struct ui_browser b;
struct map *map;
@@ -78,10 +45,11 @@ static int map_browser__search(struct map_browser *self)
{
char target[512];
struct symbol *sym;
- int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
-
- if (err)
- return err;
+ int err = ui_browser__input_window("Search by name/addr",
+ "Prefix with 0x to search by address",
+ target, "ENTER: OK, ESC: Cancel", 0);
+ if (err != K_ENTER)
+ return -1;
if (target[0] == '0' && tolower(target[1]) == 'x') {
u64 addr = strtoull(target, NULL, 16);
@@ -112,12 +80,20 @@ static int map_browser__run(struct map_browser *self)
while (1) {
key = ui_browser__run(&self->b, 0);
- if (verbose && key == '/')
- map_browser__search(self);
- else
+ switch (key) {
+ case '/':
+ if (verbose)
+ map_browser__search(self);
+ default:
break;
+ case K_LEFT:
+ case K_ESC:
+ case 'q':
+ case CTRL('c'):
+ goto out;
+ }
}
-
+out:
ui_browser__hide(&self->b);
return key;
}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
index cbbd44b0d93e..12f009e61e94 100644
--- a/tools/perf/ui/browsers/scripts.c
+++ b/tools/perf/ui/browsers/scripts.c
@@ -1,5 +1,4 @@
#include <elf.h>
-#include <newt.h>
#include <inttypes.h>
#include <sys/ttydefaults.h>
#include <string.h>
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
index 7d8dc581a545..f538794615db 100644
--- a/tools/perf/ui/gtk/annotate.c
+++ b/tools/perf/ui/gtk/annotate.c
@@ -1,6 +1,7 @@
#include "gtk.h"
#include "util/debug.h"
#include "util/annotate.h"
+#include "util/evsel.h"
#include "ui/helpline.h"
@@ -32,7 +33,7 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
return 0;
symhist = annotation__histogram(symbol__annotation(sym), evidx);
- if (!symhist->addr[dl->offset])
+ if (!symbol_conf.event_group && !symhist->addr[dl->offset])
return 0;
percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
@@ -85,7 +86,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
}
static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
- struct map *map, int evidx,
+ struct map *map, struct perf_evsel *evsel,
struct hist_browser_timer *hbt __maybe_unused)
{
struct disasm_line *pos, *n;
@@ -118,10 +119,24 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
list_for_each_entry(pos, &notes->src->source, node) {
GtkTreeIter iter;
+ int ret = 0;
gtk_list_store_append(store, &iter);
- if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx))
+ if (perf_evsel__is_group_event(evsel)) {
+ for (i = 0; i < evsel->nr_members; i++) {
+ ret += perf_gtk__get_percent(s + ret,
+ sizeof(s) - ret,
+ sym, pos,
+ evsel->idx + i);
+ ret += scnprintf(s + ret, sizeof(s) - ret, " ");
+ }
+ } else {
+ ret = perf_gtk__get_percent(s, sizeof(s), sym, pos,
+ evsel->idx);
+ }
+
+ if (ret)
gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
@@ -139,7 +154,8 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
return 0;
}
-int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
+int symbol__gtk_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
GtkWidget *window;
@@ -206,7 +222,7 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
tab_label);
- perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt);
+ perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt);
return 0;
}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 1e764a8ad259..6f259b3d14e2 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -32,21 +32,18 @@ static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
int ret;
double percent = 0.0;
struct hists *hists = he->hists;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
if (hists->stats.total_period)
percent = 100.0 * get_field(he) / hists->stats.total_period;
ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
- if (symbol_conf.event_group) {
+ if (perf_evsel__is_group_event(evsel)) {
int prev_idx, idx_delta;
- struct perf_evsel *evsel = hists_to_evsel(hists);
struct hist_entry *pair;
int nr_members = evsel->nr_members;
- if (nr_members <= 1)
- return ret;
-
prev_idx = perf_evsel__group_idx(evsel);
list_for_each_entry(pair, &he->pairs.head, pairs.node) {
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index d671e63aa351..4bf91b09d62d 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -16,6 +16,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
{
int ret;
struct hists *hists = he->hists;
+ struct perf_evsel *evsel = hists_to_evsel(hists);
if (fmt_percent) {
double percent = 0.0;
@@ -28,15 +29,11 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
} else
ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
- if (symbol_conf.event_group) {
+ if (perf_evsel__is_group_event(evsel)) {
int prev_idx, idx_delta;
- struct perf_evsel *evsel = hists_to_evsel(hists);
struct hist_entry *pair;
int nr_members = evsel->nr_members;
- if (nr_members <= 1)
- return ret;
-
prev_idx = perf_evsel__group_idx(evsel);
list_for_each_entry(pair, &he->pairs.head, pairs.node) {
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 81efa192e86c..b9401482d110 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -1,4 +1,3 @@
-#include <newt.h>
#include <signal.h>
#include <stdbool.h>
@@ -88,13 +87,6 @@ int ui__getch(int delay_secs)
return SLkp_getkey();
}
-static void newt_suspend(void *d __maybe_unused)
-{
- newtSuspend();
- raise(SIGTSTP);
- newtResume();
-}
-
static void ui__signal(int sig)
{
ui__exit(false);
@@ -106,7 +98,17 @@ int ui__init(void)
{
int err;
- newtInit();
+ SLutf8_enable(-1);
+ SLtt_get_terminfo();
+ SLtt_get_screen_size();
+
+ err = SLsmg_init_smg();
+ if (err < 0)
+ goto out;
+ err = SLang_init_tty(0, 0, 0);
+ if (err < 0)
+ goto out;
+
err = SLkp_init();
if (err < 0) {
pr_err("TUI initialization failed.\n");
@@ -115,7 +117,6 @@ int ui__init(void)
SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
- newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
ui_progress__init();
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index d86359c99907..70cb0d4eb8aa 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -12,7 +12,7 @@ extern int use_browser;
void setup_browser(bool fallback_to_pager);
void exit_browser(bool wait_for_ok);
-#ifdef NEWT_SUPPORT
+#ifdef SLANG_SUPPORT
int ui__init(void);
void ui__exit(bool wait_for_ok);
#else
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index d33fe937e6f1..d102716c43a1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -14,6 +14,7 @@
#include "symbol.h"
#include "debug.h"
#include "annotate.h"
+#include "evsel.h"
#include <pthread.h>
#include <linux/bitops.h>
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa
return NULL;
}
+double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
+ s64 end, const char **path)
+{
+ struct source_line *src_line = notes->src->lines;
+ double percent = 0.0;
+
+ if (src_line) {
+ size_t sizeof_src_line = sizeof(*src_line) +
+ sizeof(src_line->p) * (src_line->nr_pcnt - 1);
+
+ while (offset < end) {
+ src_line = (void *)notes->src->lines +
+ (sizeof_src_line * offset);
+
+ if (*path == NULL)
+ *path = src_line->path;
+
+ percent += src_line->p[evidx].percent;
+ offset++;
+ }
+ } else {
+ struct sym_hist *h = annotation__histogram(notes, evidx);
+ unsigned int hits = 0;
+
+ while (offset < end)
+ hits += h->addr[offset++];
+
+ if (h->sum)
+ percent = 100.0 * hits / h->sum;
+ }
+
+ return percent;
+}
+
static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
- int evidx, u64 len, int min_pcnt, int printed,
+ struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
int max_lines, struct disasm_line *queue)
{
static const char *prev_line;
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
if (dl->offset != -1) {
const char *path = NULL;
- unsigned int hits = 0;
- double percent = 0.0;
+ double percent, max_percent = 0.0;
+ double *ppercents = &percent;
+ int i, nr_percent = 1;
const char *color;
struct annotation *notes = symbol__annotation(sym);
- struct source_line *src_line = notes->src->lines;
- struct sym_hist *h = annotation__histogram(notes, evidx);
s64 offset = dl->offset;
const u64 addr = start + offset;
struct disasm_line *next;
next = disasm__get_next_ip_line(&notes->src->source, dl);
- while (offset < (s64)len &&
- (next == NULL || offset < next->offset)) {
- if (src_line) {
- if (path == NULL)
- path = src_line[offset].path;
- percent += src_line[offset].percent;
- } else
- hits += h->addr[offset];
-
- ++offset;
+ if (perf_evsel__is_group_event(evsel)) {
+ nr_percent = evsel->nr_members;
+ ppercents = calloc(nr_percent, sizeof(double));
+ if (ppercents == NULL)
+ return -1;
}
- if (src_line == NULL && h->sum)
- percent = 100.0 * hits / h->sum;
+ for (i = 0; i < nr_percent; i++) {
+ percent = disasm__calc_percent(notes,
+ notes->src->lines ? i : evsel->idx + i,
+ offset,
+ next ? next->offset : (s64) len,
+ &path);
+
+ ppercents[i] = percent;
+ if (percent > max_percent)
+ max_percent = percent;
+ }
- if (percent < min_pcnt)
+ if (max_percent < min_pcnt)
return -1;
if (max_lines && printed >= max_lines)
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
list_for_each_entry_from(queue, &notes->src->source, node) {
if (queue == dl)
break;
- disasm_line__print(queue, sym, start, evidx, len,
+ disasm_line__print(queue, sym, start, evsel, len,
0, 0, 1, NULL);
}
}
- color = get_percent_color(percent);
+ color = get_percent_color(max_percent);
/*
* Also color the filename and line if needed, with
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
}
}
- color_fprintf(stdout, color, " %7.2f", percent);
+ for (i = 0; i < nr_percent; i++) {
+ percent = ppercents[i];
+ color = get_percent_color(percent);
+ color_fprintf(stdout, color, " %7.2f", percent);
+ }
+
printf(" : ");
color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
+
+ if (ppercents != &percent)
+ free(ppercents);
+
} else if (max_lines && printed >= max_lines)
return 1;
else {
+ int width = 8;
+
if (queue)
return -1;
+ if (perf_evsel__is_group_event(evsel))
+ width *= evsel->nr_members;
+
if (!*dl->line)
- printf(" :\n");
+ printf(" %*s:\n", width, " ");
else
- printf(" : %s\n", dl->line);
+ printf(" %*s: %s\n", width, " ", dl->line);
}
return 0;
}
+/*
+ * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
+ * which looks like following
+ *
+ * 0000000000415500 <_init>:
+ * 415500: sub $0x8,%rsp
+ * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8>
+ * 41550b: test %rax,%rax
+ * 41550e: je 415515 <_init+0x15>
+ * 415510: callq 416e70 <__gmon_start__@plt>
+ * 415515: add $0x8,%rsp
+ * 415519: retq
+ *
+ * it will be parsed and saved into struct disasm_line as
+ * <offset> <name> <ops.raw>
+ *
+ * The offset will be a relative offset from the start of the symbol and -1
+ * means that it's not a disassembly line so should be treated differently.
+ * The ops.raw part will be parsed further according to type of the instruction.
+ */
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
FILE *file, size_t privsize)
{
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
struct source_line *iter;
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
- int ret;
+ int i, ret;
while (*p != NULL) {
parent = *p;
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
ret = strcmp(iter->path, src_line->path);
if (ret == 0) {
- iter->percent_sum += src_line->percent;
+ for (i = 0; i < src_line->nr_pcnt; i++)
+ iter->p[i].percent_sum += src_line->p[i].percent;
return;
}
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
p = &(*p)->rb_right;
}
- src_line->percent_sum = src_line->percent;
+ for (i = 0; i < src_line->nr_pcnt; i++)
+ src_line->p[i].percent_sum = src_line->p[i].percent;
rb_link_node(&src_line->node, parent, p);
rb_insert_color(&src_line->node, root);
}
+static int cmp_source_line(struct source_line *a, struct source_line *b)
+{
+ int i;
+
+ for (i = 0; i < a->nr_pcnt; i++) {
+ if (a->p[i].percent_sum == b->p[i].percent_sum)
+ continue;
+ return a->p[i].percent_sum > b->p[i].percent_sum;
+ }
+
+ return 0;
+}
+
static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
{
struct source_line *iter;
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l
parent = *p;
iter = rb_entry(parent, struct source_line, node);
- if (src_line->percent_sum > iter->percent_sum)
+ if (cmp_source_line(src_line, iter))
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len)
{
struct annotation *notes = symbol__annotation(sym);
struct source_line *src_line = notes->src->lines;
+ size_t sizeof_src_line;
int i;
- for (i = 0; i < len; i++)
- free(src_line[i].path);
+ sizeof_src_line = sizeof(*src_line) +
+ (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
+
+ for (i = 0; i < len; i++) {
+ free(src_line->path);
+ src_line = (void *)src_line + sizeof_src_line;
+ }
- free(src_line);
+ free(notes->src->lines);
notes->src->lines = NULL;
}
/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
- int evidx, struct rb_root *root, int len,
+ struct perf_evsel *evsel,
+ struct rb_root *root, int len,
const char *filename)
{
u64 start;
- int i;
+ int i, k;
+ int evidx = evsel->idx;
char cmd[PATH_MAX * 2];
struct source_line *src_line;
struct annotation *notes = symbol__annotation(sym);
struct sym_hist *h = annotation__histogram(notes, evidx);
struct rb_root tmp_root = RB_ROOT;
+ int nr_pcnt = 1;
+ u64 h_sum = h->sum;
+ size_t sizeof_src_line = sizeof(struct source_line);
+
+ if (perf_evsel__is_group_event(evsel)) {
+ for (i = 1; i < evsel->nr_members; i++) {
+ h = annotation__histogram(notes, evidx + i);
+ h_sum += h->sum;
+ }
+ nr_pcnt = evsel->nr_members;
+ sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
+ }
- if (!h->sum)
+ if (!h_sum)
return 0;
- src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
+ src_line = notes->src->lines = calloc(len, sizeof_src_line);
if (!notes->src->lines)
return -1;
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
size_t line_len;
u64 offset;
FILE *fp;
+ double percent_max = 0.0;
- src_line[i].percent = 100.0 * h->addr[i] / h->sum;
- if (src_line[i].percent <= 0.5)
- continue;
+ src_line->nr_pcnt = nr_pcnt;
+
+ for (k = 0; k < nr_pcnt; k++) {
+ h = annotation__histogram(notes, evidx + k);
+ src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
+
+ if (src_line->p[k].percent > percent_max)
+ percent_max = src_line->p[k].percent;
+ }
+
+ if (percent_max <= 0.5)
+ goto next;
offset = start + i;
sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
fp = popen(cmd, "r");
if (!fp)
- continue;
+ goto next;
if (getline(&path, &line_len, fp) < 0 || !line_len)
- goto next;
+ goto next_close;
- src_line[i].path = malloc(sizeof(char) * line_len + 1);
- if (!src_line[i].path)
- goto next;
+ src_line->path = malloc(sizeof(char) * line_len + 1);
+ if (!src_line->path)
+ goto next_close;
- strcpy(src_line[i].path, path);
- insert_source_line(&tmp_root, &src_line[i]);
+ strcpy(src_line->path, path);
+ insert_source_line(&tmp_root, src_line);
- next:
+ next_close:
pclose(fp);
+ next:
+ src_line = (void *)src_line + sizeof_src_line;
}
resort_source_line(root, &tmp_root);
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename)
node = rb_first(root);
while (node) {
- double percent;
+ double percent, percent_max = 0.0;
const char *color;
char *path;
+ int i;
src_line = rb_entry(node, struct source_line, node);
- percent = src_line->percent_sum;
- color = get_percent_color(percent);
+ for (i = 0; i < src_line->nr_pcnt; i++) {
+ percent = src_line->p[i].percent_sum;
+ color = get_percent_color(percent);
+ color_fprintf(stdout, color, " %7.2f", percent);
+
+ if (percent > percent_max)
+ percent_max = percent;
+ }
+
path = src_line->path;
+ color = get_percent_color(percent_max);
+ color_fprintf(stdout, color, " %s", path);
- color_fprintf(stdout, color, " %7.2f %s", percent, path);
node = rb_next(node);
}
}
-static void symbol__annotate_hits(struct symbol *sym, int evidx)
+static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
{
struct annotation *notes = symbol__annotation(sym);
- struct sym_hist *h = annotation__histogram(notes, evidx);
+ struct sym_hist *h = annotation__histogram(notes, evsel->idx);
u64 len = symbol__size(sym), offset;
for (offset = 0; offset < len; ++offset)
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}
-int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
- bool full_paths, int min_pcnt, int max_lines,
- int context)
+int symbol__annotate_printf(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel, bool full_paths,
+ int min_pcnt, int max_lines, int context)
{
struct dso *dso = map->dso;
char *filename;
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
int printed = 2, queue_len = 0;
int more = 0;
u64 len;
+ int width = 8;
+ int namelen;
filename = strdup(dso->long_name);
if (!filename)
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
d_filename = basename(filename);
len = symbol__size(sym);
+ namelen = strlen(d_filename);
+
+ if (perf_evsel__is_group_event(evsel))
+ width *= evsel->nr_members;
- printf(" Percent | Source code & Disassembly of %s\n", d_filename);
- printf("------------------------------------------------\n");
+ printf(" %-*.*s| Source code & Disassembly of %s\n",
+ width, width, "Percent", d_filename);
+ printf("-%-*.*s-------------------------------------\n",
+ width+namelen, width+namelen, graph_dotted_line);
if (verbose)
- symbol__annotate_hits(sym, evidx);
+ symbol__annotate_hits(sym, evsel);
list_for_each_entry(pos, &notes->src->source, node) {
if (context && queue == NULL) {
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
queue_len = 0;
}
- switch (disasm_line__print(pos, sym, start, evidx, len,
+ switch (disasm_line__print(pos, sym, start, evsel, len,
min_pcnt, printed, max_lines,
queue)) {
case 0:
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
return printed;
}
-int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
- bool print_lines, bool full_paths, int min_pcnt,
- int max_lines)
+int symbol__tty_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel, bool print_lines,
+ bool full_paths, int min_pcnt, int max_lines)
{
struct dso *dso = map->dso;
const char *filename = dso->long_name;
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
len = symbol__size(sym);
if (print_lines) {
- symbol__get_source_line(sym, map, evidx, &source_line,
+ symbol__get_source_line(sym, map, evsel, &source_line,
len, filename);
print_summary(&source_line, filename);
}
- symbol__annotate_printf(sym, map, evidx, full_paths,
+ symbol__annotate_printf(sym, map, evsel, full_paths,
min_pcnt, max_lines, 0);
if (print_lines)
symbol__free_source_line(sym, len);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index c422440fe611..af755156d278 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -50,6 +50,8 @@ bool ins__is_jump(const struct ins *ins);
bool ins__is_call(const struct ins *ins);
int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
+struct annotation;
+
struct disasm_line {
struct list_head node;
s64 offset;
@@ -68,17 +70,24 @@ void disasm_line__free(struct disasm_line *dl);
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
size_t disasm__fprintf(struct list_head *head, FILE *fp);
+double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
+ s64 end, const char **path);
struct sym_hist {
u64 sum;
u64 addr[0];
};
-struct source_line {
- struct rb_node node;
+struct source_line_percent {
double percent;
double percent_sum;
+};
+
+struct source_line {
+ struct rb_node node;
char *path;
+ int nr_pcnt;
+ struct source_line_percent p[1];
};
/** struct annotated_source - symbols with hits have this attached as in sannotation
@@ -130,47 +139,49 @@ void symbol__annotate_zero_histograms(struct symbol *sym);
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym);
-int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
- bool full_paths, int min_pcnt, int max_lines,
- int context);
+int symbol__annotate_printf(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel, bool full_paths,
+ int min_pcnt, int max_lines, int context);
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
void disasm__purge(struct list_head *head);
-int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
- bool print_lines, bool full_paths, int min_pcnt,
- int max_lines);
+int symbol__tty_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel, bool print_lines,
+ bool full_paths, int min_pcnt, int max_lines);
-#ifdef NEWT_SUPPORT
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+#ifdef SLANG_SUPPORT
+int symbol__tui_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
#else
static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
- struct map *map __maybe_unused,
- int evidx __maybe_unused,
- struct hist_browser_timer *hbt
- __maybe_unused)
+ struct map *map __maybe_unused,
+ struct perf_evsel *evsel __maybe_unused,
+ struct hist_browser_timer *hbt
+ __maybe_unused)
{
return 0;
}
#endif
#ifdef GTK2_SUPPORT
-int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
+int symbol__gtk_annotate(struct symbol *sym, struct map *map,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
-static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
+static inline int hist_entry__gtk_annotate(struct hist_entry *he,
+ struct perf_evsel *evsel,
struct hist_browser_timer *hbt)
{
- return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
+ return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
}
void perf_gtk__show_annotations(void);
#else
static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
- int evidx __maybe_unused,
- struct hist_browser_timer *hbt
- __maybe_unused)
+ struct perf_evsel *evsel __maybe_unused,
+ struct hist_browser_timer *hbt __maybe_unused)
{
return 0;
}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index f817046e22b1..beb8cf9f9976 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -4,6 +4,7 @@
#include "cpumap.h"
#include <assert.h>
#include <stdio.h>
+#include <stdlib.h>
static struct cpu_map *cpu_map__default_new(void)
{
@@ -219,7 +220,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
if (!mnt)
return -1;
- sprintf(path,
+ snprintf(path, PATH_MAX,
"%s/devices/system/cpu/cpu%d/topology/physical_package_id",
mnt, cpu);
@@ -231,27 +232,88 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
return ret == 1 ? cpu : -1;
}
-int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
+static int cmp_ids(const void *a, const void *b)
{
- struct cpu_map *sock;
+ return *(int *)a - *(int *)b;
+}
+
+static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
+ int (*f)(struct cpu_map *map, int cpu))
+{
+ struct cpu_map *c;
int nr = cpus->nr;
int cpu, s1, s2;
- sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
- if (!sock)
+ /* allocate as much as possible */
+ c = calloc(1, sizeof(*c) + nr * sizeof(int));
+ if (!c)
return -1;
for (cpu = 0; cpu < nr; cpu++) {
- s1 = cpu_map__get_socket(cpus, cpu);
- for (s2 = 0; s2 < sock->nr; s2++) {
- if (s1 == sock->map[s2])
+ s1 = f(cpus, cpu);
+ for (s2 = 0; s2 < c->nr; s2++) {
+ if (s1 == c->map[s2])
break;
}
- if (s2 == sock->nr) {
- sock->map[sock->nr] = s1;
- sock->nr++;
+ if (s2 == c->nr) {
+ c->map[c->nr] = s1;
+ c->nr++;
}
}
- *sockp = sock;
+ /* ensure we process id in increasing order */
+ qsort(c->map, c->nr, sizeof(int), cmp_ids);
+
+ *res = c;
return 0;
}
+
+int cpu_map__get_core(struct cpu_map *map, int idx)
+{
+ FILE *fp;
+ const char *mnt;
+ char path[PATH_MAX];
+ int cpu, ret, s;
+
+ if (idx > map->nr)
+ return -1;
+
+ cpu = map->map[idx];
+
+ mnt = sysfs_find_mountpoint();
+ if (!mnt)
+ return -1;
+
+ snprintf(path, PATH_MAX,
+ "%s/devices/system/cpu/cpu%d/topology/core_id",
+ mnt, cpu);
+
+ fp = fopen(path, "r");
+ if (!fp)
+ return -1;
+ ret = fscanf(fp, "%d", &cpu);
+ fclose(fp);
+ if (ret != 1)
+ return -1;
+
+ s = cpu_map__get_socket(map, idx);
+ if (s == -1)
+ return -1;
+
+ /*
+ * encode socket in upper 16 bits
+ * core_id is relative to socket, and
+ * we need a global id. So we combine
+ * socket+ core id
+ */
+ return (s << 16) | (cpu & 0xffff);
+}
+
+int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
+{
+ return cpu_map__build_map(cpus, sockp, cpu_map__get_socket);
+}
+
+int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
+{
+ return cpu_map__build_map(cpus, corep, cpu_map__get_core);
+}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 161b00756a12..9bed02e5fb3d 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -15,7 +15,9 @@ void cpu_map__delete(struct cpu_map *map);
struct cpu_map *cpu_map__read(FILE *file);
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
int cpu_map__get_socket(struct cpu_map *map, int idx);
+int cpu_map__get_core(struct cpu_map *map, int idx);
int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
+int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
static inline int cpu_map__socket(struct cpu_map *sock, int s)
{
@@ -24,6 +26,16 @@ static inline int cpu_map__socket(struct cpu_map *sock, int s)
return sock->map[s];
}
+static inline int cpu_map__id_to_socket(int id)
+{
+ return id >> 16;
+}
+
+static inline int cpu_map__id_to_cpu(int id)
+{
+ return id & 0xffff;
+}
+
static inline int cpu_map__nr(const struct cpu_map *map)
{
return map ? map->nr : 1;
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
deleted file mode 100644
index 68f3e87ec57f..000000000000
--- a/tools/perf/util/debugfs.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __DEBUGFS_H__
-#define __DEBUGFS_H__
-
-const char *debugfs_find_mountpoint(void);
-int debugfs_valid_mountpoint(const char *debugfs);
-char *debugfs_mount(const char *mountpoint);
-void debugfs_set_path(const char *mountpoint);
-
-extern char debugfs_mountpoint[];
-extern char tracing_events_path[];
-
-#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 0d573ff4771a..181389535c0c 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -88,8 +88,10 @@ struct perf_sample {
u64 id;
u64 stream_id;
u64 period;
+ u64 weight;
u32 cpu;
u32 raw_size;
+ u64 data_src;
void *raw_data;
struct ip_callchain *callchain;
struct branch_stack *branch_stack;
@@ -97,6 +99,13 @@ struct perf_sample {
struct stack_dump user_stack;
};
+#define PERF_MEM_DATA_SRC_NONE \
+ (PERF_MEM_S(OP, NA) |\
+ PERF_MEM_S(LVL, NA) |\
+ PERF_MEM_S(SNOOP, NA) |\
+ PERF_MEM_S(LOCK, NA) |\
+ PERF_MEM_S(TLB, NA))
+
struct build_id_event {
struct perf_event_header header;
pid_t pid;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c8be0fbc5145..f7c727801aab 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -7,7 +7,7 @@
* Released under the GPL v2. (and only v2, not any later version)
*/
#include "util.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include <poll.h>
#include "cpumap.h"
#include "thread_map.h"
@@ -38,13 +38,12 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
evlist->workload.pid = -1;
}
-struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
- struct thread_map *threads)
+struct perf_evlist *perf_evlist__new(void)
{
struct perf_evlist *evlist = zalloc(sizeof(*evlist));
if (evlist != NULL)
- perf_evlist__init(evlist, cpus, threads);
+ perf_evlist__init(evlist, NULL, NULL);
return evlist;
}
@@ -228,12 +227,14 @@ void perf_evlist__disable(struct perf_evlist *evlist)
{
int cpu, thread;
struct perf_evsel *pos;
+ int nr_cpus = cpu_map__nr(evlist->cpus);
+ int nr_threads = thread_map__nr(evlist->threads);
- for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
list_for_each_entry(pos, &evlist->entries, node) {
if (!perf_evsel__is_group_leader(pos))
continue;
- for (thread = 0; thread < evlist->threads->nr; thread++)
+ for (thread = 0; thread < nr_threads; thread++)
ioctl(FD(pos, cpu, thread),
PERF_EVENT_IOC_DISABLE, 0);
}
@@ -244,12 +245,14 @@ void perf_evlist__enable(struct perf_evlist *evlist)
{
int cpu, thread;
struct perf_evsel *pos;
+ int nr_cpus = cpu_map__nr(evlist->cpus);
+ int nr_threads = thread_map__nr(evlist->threads);
- for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
list_for_each_entry(pos, &evlist->entries, node) {
if (!perf_evsel__is_group_leader(pos))
continue;
- for (thread = 0; thread < evlist->threads->nr; thread++)
+ for (thread = 0; thread < nr_threads; thread++)
ioctl(FD(pos, cpu, thread),
PERF_EVENT_IOC_ENABLE, 0);
}
@@ -258,7 +261,9 @@ void perf_evlist__enable(struct perf_evlist *evlist)
static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
{
- int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries;
+ int nr_cpus = cpu_map__nr(evlist->cpus);
+ int nr_threads = thread_map__nr(evlist->threads);
+ int nfds = nr_cpus * nr_threads * evlist->nr_entries;
evlist->pollfd = malloc(sizeof(struct pollfd) * nfds);
return evlist->pollfd != NULL ? 0 : -ENOMEM;
}
@@ -417,7 +422,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
{
evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
if (cpu_map__all(evlist->cpus))
- evlist->nr_mmaps = evlist->threads->nr;
+ evlist->nr_mmaps = thread_map__nr(evlist->threads);
evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
return evlist->mmap != NULL ? 0 : -ENOMEM;
}
@@ -442,11 +447,13 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
{
struct perf_evsel *evsel;
int cpu, thread;
+ int nr_cpus = cpu_map__nr(evlist->cpus);
+ int nr_threads = thread_map__nr(evlist->threads);
- for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
int output = -1;
- for (thread = 0; thread < evlist->threads->nr; thread++) {
+ for (thread = 0; thread < nr_threads; thread++) {
list_for_each_entry(evsel, &evlist->entries, node) {
int fd = FD(evsel, cpu, thread);
@@ -470,7 +477,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
return 0;
out_unmap:
- for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
+ for (cpu = 0; cpu < nr_cpus; cpu++) {
if (evlist->mmap[cpu].base != NULL) {
munmap(evlist->mmap[cpu].base, evlist->mmap_len);
evlist->mmap[cpu].base = NULL;
@@ -483,8 +490,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
{
struct perf_evsel *evsel;
int thread;
+ int nr_threads = thread_map__nr(evlist->threads);
- for (thread = 0; thread < evlist->threads->nr; thread++) {
+ for (thread = 0; thread < nr_threads; thread++) {
int output = -1;
list_for_each_entry(evsel, &evlist->entries, node) {
@@ -509,7 +517,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
return 0;
out_unmap:
- for (thread = 0; thread < evlist->threads->nr; thread++) {
+ for (thread = 0; thread < nr_threads; thread++) {
if (evlist->mmap[thread].base != NULL) {
munmap(evlist->mmap[thread].base, evlist->mmap_len);
evlist->mmap[thread].base = NULL;
@@ -610,7 +618,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist)
struct perf_evsel *evsel;
int err = 0;
const int ncpus = cpu_map__nr(evlist->cpus),
- nthreads = evlist->threads->nr;
+ nthreads = thread_map__nr(evlist->threads);
list_for_each_entry(evsel, &evlist->entries, node) {
if (evsel->filter == NULL)
@@ -629,7 +637,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
struct perf_evsel *evsel;
int err = 0;
const int ncpus = cpu_map__nr(evlist->cpus),
- nthreads = evlist->threads->nr;
+ nthreads = thread_map__nr(evlist->threads);
list_for_each_entry(evsel, &evlist->entries, node) {
err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter);
@@ -712,10 +720,20 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
evlist->selected = evsel;
}
+void perf_evlist__close(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+ int ncpus = cpu_map__nr(evlist->cpus);
+ int nthreads = thread_map__nr(evlist->threads);
+
+ list_for_each_entry_reverse(evsel, &evlist->entries, node)
+ perf_evsel__close(evsel, ncpus, nthreads);
+}
+
int perf_evlist__open(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
- int err, ncpus, nthreads;
+ int err;
list_for_each_entry(evsel, &evlist->entries, node) {
err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
@@ -725,19 +743,15 @@ int perf_evlist__open(struct perf_evlist *evlist)
return 0;
out_err:
- ncpus = evlist->cpus ? evlist->cpus->nr : 1;
- nthreads = evlist->threads ? evlist->threads->nr : 1;
-
- list_for_each_entry_reverse(evsel, &evlist->entries, node)
- perf_evsel__close(evsel, ncpus, nthreads);
-
+ perf_evlist__close(evlist);
errno = -err;
return err;
}
int perf_evlist__prepare_workload(struct perf_evlist *evlist,
- struct perf_record_opts *opts,
- const char *argv[])
+ struct perf_target *target,
+ const char *argv[], bool pipe_output,
+ bool want_signal)
{
int child_ready_pipe[2], go_pipe[2];
char bf;
@@ -759,7 +773,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
}
if (!evlist->workload.pid) {
- if (opts->pipe_output)
+ if (pipe_output)
dup2(2, 1);
close(child_ready_pipe[0]);
@@ -787,11 +801,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
execvp(argv[0], (char **)argv);
perror(argv[0]);
- kill(getppid(), SIGUSR1);
+ if (want_signal)
+ kill(getppid(), SIGUSR1);
exit(-1);
}
- if (perf_target__none(&opts->target))
+ if (perf_target__none(target))
evlist->threads->map[0] = evlist->workload.pid;
close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 2dd07bd60b4f..0583d36252be 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,8 +49,7 @@ struct perf_evsel_str_handler {
void *handler;
};
-struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
- struct thread_map *threads);
+struct perf_evlist *perf_evlist__new(void);
void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
struct thread_map *threads);
void perf_evlist__exit(struct perf_evlist *evlist);
@@ -82,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
int perf_evlist__open(struct perf_evlist *evlist);
+void perf_evlist__close(struct perf_evlist *evlist);
void perf_evlist__config(struct perf_evlist *evlist,
struct perf_record_opts *opts);
int perf_evlist__prepare_workload(struct perf_evlist *evlist,
- struct perf_record_opts *opts,
- const char *argv[]);
+ struct perf_target *target,
+ const char *argv[], bool pipe_output,
+ bool want_signal);
int perf_evlist__start_workload(struct perf_evlist *evlist);
int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9c82f98f26de..07b1a3ad3e24 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -10,7 +10,7 @@
#include <byteswap.h>
#include <linux/bitops.h>
#include "asm/bug.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include "event-parse.h"
#include "evsel.h"
#include "evlist.h"
@@ -554,6 +554,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
perf_evsel__set_sample_bit(evsel, CPU);
}
+ if (opts->sample_address)
+ attr->sample_type |= PERF_SAMPLE_DATA_SRC;
+
if (opts->no_delay) {
attr->watermark = 0;
attr->wakeup_events = 1;
@@ -563,6 +566,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
attr->branch_sample_type = opts->branch_stack;
}
+ if (opts->sample_weight)
+ attr->sample_type |= PERF_SAMPLE_WEIGHT;
+
attr->mmap = track;
attr->comm = track;
@@ -633,6 +639,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
return 0;
}
+void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
+{
+ memset(evsel->counts, 0, (sizeof(*evsel->counts) +
+ (ncpus * sizeof(struct perf_counts_values))));
+}
+
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
{
evsel->counts = zalloc((sizeof(*evsel->counts) +
@@ -673,9 +685,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
void perf_evsel__exit(struct perf_evsel *evsel)
{
assert(list_empty(&evsel->node));
- xyarray__delete(evsel->fd);
- xyarray__delete(evsel->sample_id);
- free(evsel->id);
+ perf_evsel__free_fd(evsel);
+ perf_evsel__free_id(evsel);
}
void perf_evsel__delete(struct perf_evsel *evsel)
@@ -1012,6 +1023,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
data->cpu = data->pid = data->tid = -1;
data->stream_id = data->id = data->time = -1ULL;
data->period = 1;
+ data->weight = 0;
if (event->header.type != PERF_RECORD_SAMPLE) {
if (!evsel->attr.sample_id_all)
@@ -1162,6 +1174,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
}
}
+ data->weight = 0;
+ if (type & PERF_SAMPLE_WEIGHT) {
+ data->weight = *array;
+ array++;
+ }
+
+ data->data_src = PERF_MEM_DATA_SRC_NONE;
+ if (type & PERF_SAMPLE_DATA_SRC) {
+ data->data_src = *array;
+ array++;
+ }
+
return 0;
}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 52021c3087df..3f156ccc1acb 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -9,6 +9,7 @@
#include "xyarray.h"
#include "cgroup.h"
#include "hist.h"
+#include "symbol.h"
struct perf_counts_values {
union {
@@ -120,6 +121,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
+void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
void perf_evsel__free_fd(struct perf_evsel *evsel);
void perf_evsel__free_id(struct perf_evsel *evsel);
void perf_evsel__free_counts(struct perf_evsel *evsel);
@@ -246,11 +248,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
return list_entry(evsel->node.next, struct perf_evsel, node);
}
+/**
+ * perf_evsel__is_group_leader - Return whether given evsel is a leader event
+ *
+ * @evsel - evsel selector to be tested
+ *
+ * Return %true if @evsel is a group leader or a stand-alone event
+ */
static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
{
return evsel->leader == evsel;
}
+/**
+ * perf_evsel__is_group_event - Return whether given evsel is a group event
+ *
+ * @evsel - evsel selector to be tested
+ *
+ * Return %true iff event group view is enabled and @evsel is a actual group
+ * leader which has other members in the group
+ */
+static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel)
+{
+ if (!symbol_conf.event_group)
+ return false;
+
+ return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1;
+}
+
struct perf_attr_details {
bool freq;
bool verbose;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f4bfd79ef6a7..326068a593a5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,5 +1,3 @@
-#define _FILE_OFFSET_BITS 64
-
#include "util.h"
#include <sys/types.h>
#include <byteswap.h>
@@ -1672,8 +1670,8 @@ static int process_tracing_data(struct perf_file_section *section __maybe_unused
struct perf_header *ph __maybe_unused,
int fd, void *data)
{
- trace_report(fd, data, false);
- return 0;
+ ssize_t ret = trace_report(fd, data, false);
+ return ret < 0 ? -1 : 0;
}
static int process_build_id(struct perf_file_section *section,
@@ -2752,6 +2750,11 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel,
if (evsel->tp_format)
return 0;
+ if (pevent == NULL) {
+ pr_debug("broken or missing trace data\n");
+ return -1;
+ }
+
event = pevent_find_event(pevent, evsel->attr.config);
if (event == NULL)
return -1;
@@ -2789,7 +2792,7 @@ int perf_session__read_header(struct perf_session *session, int fd)
u64 f_id;
int nr_attrs, nr_ids, i, j;
- session->evlist = perf_evlist__new(NULL, NULL);
+ session->evlist = perf_evlist__new();
if (session->evlist == NULL)
return -ENOMEM;
@@ -2940,7 +2943,7 @@ int perf_event__process_attr(union perf_event *event,
struct perf_evlist *evlist = *pevlist;
if (evlist == NULL) {
- *pevlist = evlist = perf_evlist__new(NULL, NULL);
+ *pevlist = evlist = perf_evlist__new();
if (evlist == NULL)
return -ENOMEM;
}
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f855941bebea..6b32721f829a 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -67,12 +67,16 @@ static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
{
const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
+ int symlen;
u16 len;
if (h->ms.sym)
hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
- else
+ else {
+ symlen = unresolved_col_width + 4 + 2;
+ hists__new_col_len(hists, HISTC_SYMBOL, symlen);
hists__set_unres_dso_col_len(hists, HISTC_DSO);
+ }
len = thread__comm_len(h->thread);
if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -87,7 +91,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
if (h->branch_info) {
- int symlen;
/*
* +4 accounts for '[x] ' priv level info
* +2 account of 0x prefix on raw addresses
@@ -116,6 +119,42 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
}
}
+
+ if (h->mem_info) {
+ /*
+ * +4 accounts for '[x] ' priv level info
+ * +2 account of 0x prefix on raw addresses
+ */
+ if (h->mem_info->daddr.sym) {
+ symlen = (int)h->mem_info->daddr.sym->namelen + 4
+ + unresolved_col_width + 2;
+ hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
+ symlen);
+ } else {
+ symlen = unresolved_col_width + 4 + 2;
+ hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
+ symlen);
+ }
+ if (h->mem_info->daddr.map) {
+ symlen = dso__name_len(h->mem_info->daddr.map->dso);
+ hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
+ symlen);
+ } else {
+ symlen = unresolved_col_width + 4 + 2;
+ hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
+ }
+ } else {
+ symlen = unresolved_col_width + 4 + 2;
+ hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
+ hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
+ }
+
+ hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
+ hists__new_col_len(hists, HISTC_MEM_TLB, 22);
+ hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
+ hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
+ hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
+ hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
}
void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -155,9 +194,12 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
}
}
-static void he_stat__add_period(struct he_stat *he_stat, u64 period)
+static void he_stat__add_period(struct he_stat *he_stat, u64 period,
+ u64 weight)
{
+
he_stat->period += period;
+ he_stat->weight += weight;
he_stat->nr_events += 1;
}
@@ -169,12 +211,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
dest->period_guest_sys += src->period_guest_sys;
dest->period_guest_us += src->period_guest_us;
dest->nr_events += src->nr_events;
+ dest->weight += src->weight;
}
static void hist_entry__decay(struct hist_entry *he)
{
he->stat.period = (he->stat.period * 7) / 8;
he->stat.nr_events = (he->stat.nr_events * 7) / 8;
+ /* XXX need decay for weight too? */
}
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@@ -239,7 +283,7 @@ void hists__decay_entries_threaded(struct hists *hists,
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
- struct hist_entry *he = malloc(sizeof(*he) + callchain_size);
+ struct hist_entry *he = zalloc(sizeof(*he) + callchain_size);
if (he != NULL) {
*he = *template;
@@ -254,6 +298,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
he->branch_info->to.map->referenced = true;
}
+ if (he->mem_info) {
+ if (he->mem_info->iaddr.map)
+ he->mem_info->iaddr.map->referenced = true;
+ if (he->mem_info->daddr.map)
+ he->mem_info->daddr.map->referenced = true;
+ }
+
if (symbol_conf.use_callchain)
callchain_init(he->callchain);
@@ -282,7 +333,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
static struct hist_entry *add_hist_entry(struct hists *hists,
struct hist_entry *entry,
struct addr_location *al,
- u64 period)
+ u64 period,
+ u64 weight)
{
struct rb_node **p;
struct rb_node *parent = NULL;
@@ -306,7 +358,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
cmp = hist_entry__cmp(he, entry);
if (!cmp) {
- he_stat__add_period(&he->stat, period);
+ he_stat__add_period(&he->stat, period, weight);
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
@@ -341,11 +393,42 @@ out_unlock:
return he;
}
+struct hist_entry *__hists__add_mem_entry(struct hists *self,
+ struct addr_location *al,
+ struct symbol *sym_parent,
+ struct mem_info *mi,
+ u64 period,
+ u64 weight)
+{
+ struct hist_entry entry = {
+ .thread = al->thread,
+ .ms = {
+ .map = al->map,
+ .sym = al->sym,
+ },
+ .stat = {
+ .period = period,
+ .weight = weight,
+ .nr_events = 1,
+ },
+ .cpu = al->cpu,
+ .ip = al->addr,
+ .level = al->level,
+ .parent = sym_parent,
+ .filtered = symbol__parent_filter(sym_parent),
+ .hists = self,
+ .mem_info = mi,
+ .branch_info = NULL,
+ };
+ return add_hist_entry(self, &entry, al, period, weight);
+}
+
struct hist_entry *__hists__add_branch_entry(struct hists *self,
struct addr_location *al,
struct symbol *sym_parent,
struct branch_info *bi,
- u64 period)
+ u64 period,
+ u64 weight)
{
struct hist_entry entry = {
.thread = al->thread,
@@ -359,19 +442,22 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.stat = {
.period = period,
.nr_events = 1,
+ .weight = weight,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.branch_info = bi,
.hists = self,
+ .mem_info = NULL,
};
- return add_hist_entry(self, &entry, al, period);
+ return add_hist_entry(self, &entry, al, period, weight);
}
struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al,
- struct symbol *sym_parent, u64 period)
+ struct symbol *sym_parent, u64 period,
+ u64 weight)
{
struct hist_entry entry = {
.thread = al->thread,
@@ -385,13 +471,16 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.stat = {
.period = period,
.nr_events = 1,
+ .weight = weight,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent),
.hists = self,
+ .branch_info = NULL,
+ .mem_info = NULL,
};
- return add_hist_entry(self, &entry, al, period);
+ return add_hist_entry(self, &entry, al, period, weight);
}
int64_t
@@ -431,6 +520,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
void hist_entry__free(struct hist_entry *he)
{
free(he->branch_info);
+ free(he->mem_info);
free(he);
}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 226a4ae2f936..14c2fe20aa62 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -49,6 +49,14 @@ enum hist_column {
HISTC_DSO_FROM,
HISTC_DSO_TO,
HISTC_SRCLINE,
+ HISTC_LOCAL_WEIGHT,
+ HISTC_GLOBAL_WEIGHT,
+ HISTC_MEM_DADDR_SYMBOL,
+ HISTC_MEM_DADDR_DSO,
+ HISTC_MEM_LOCKED,
+ HISTC_MEM_TLB,
+ HISTC_MEM_LVL,
+ HISTC_MEM_SNOOP,
HISTC_NR_COLS, /* Last entry */
};
@@ -73,7 +81,8 @@ struct hists {
struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al,
- struct symbol *parent, u64 period);
+ struct symbol *parent, u64 period,
+ u64 weight);
int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
@@ -84,7 +93,15 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
struct addr_location *al,
struct symbol *sym_parent,
struct branch_info *bi,
- u64 period);
+ u64 period,
+ u64 weight);
+
+struct hist_entry *__hists__add_mem_entry(struct hists *self,
+ struct addr_location *al,
+ struct symbol *sym_parent,
+ struct mem_info *mi,
+ u64 period,
+ u64 weight);
void hists__output_resort(struct hists *self);
void hists__output_resort_threaded(struct hists *hists);
@@ -175,9 +192,9 @@ struct hist_browser_timer {
int refresh;
};
-#ifdef NEWT_SUPPORT
+#ifdef SLANG_SUPPORT
#include "../ui/keysyms.h"
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
struct hist_browser_timer *hbt);
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
@@ -196,7 +213,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
static inline int hist_entry__tui_annotate(struct hist_entry *self
__maybe_unused,
- int evidx __maybe_unused,
+ struct perf_evsel *evsel
+ __maybe_unused,
struct hist_browser_timer *hbt
__maybe_unused)
{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index efdb38e65a92..b2ecad6ec46b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -955,6 +955,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct thread *thread;
struct map *map;
+ enum map_type type;
int ret = 0;
if (dump_trace)
@@ -971,10 +972,17 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
thread = machine__findnew_thread(machine, event->mmap.pid);
if (thread == NULL)
goto out_problem;
+
+ if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
+ type = MAP__VARIABLE;
+ else
+ type = MAP__FUNCTION;
+
map = map__new(&machine->user_dsos, event->mmap.start,
event->mmap.len, event->mmap.pgoff,
event->mmap.pid, event->mmap.filename,
- MAP__FUNCTION);
+ type);
+
if (map == NULL)
goto out_problem;
@@ -1003,6 +1011,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
return 0;
}
+static void machine__remove_thread(struct machine *machine, struct thread *th)
+{
+ machine->last_match = NULL;
+ rb_erase(&th->rb_node, &machine->threads);
+ /*
+ * We may have references to this thread, for instance in some hist_entry
+ * instances, so just move them to a separate list.
+ */
+ list_add_tail(&th->node, &machine->dead_threads);
+}
+
int machine__process_exit_event(struct machine *machine, union perf_event *event)
{
struct thread *thread = machine__find_thread(machine, event->fork.tid);
@@ -1039,17 +1058,6 @@ int machine__process_event(struct machine *machine, union perf_event *event)
return ret;
}
-void machine__remove_thread(struct machine *machine, struct thread *th)
-{
- machine->last_match = NULL;
- rb_erase(&th->rb_node, &machine->threads);
- /*
- * We may have references to this thread, for instance in some hist_entry
- * instances, so just move them to a separate list.
- */
- list_add_tail(&th->node, &machine->dead_threads);
-}
-
static bool symbol__match_parent_regex(struct symbol *sym)
{
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -1097,6 +1105,38 @@ found:
ams->map = al.map;
}
+static void ip__resolve_data(struct machine *machine, struct thread *thread,
+ u8 m, struct addr_map_symbol *ams, u64 addr)
+{
+ struct addr_location al;
+
+ memset(&al, 0, sizeof(al));
+
+ thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, &al,
+ NULL);
+ ams->addr = addr;
+ ams->al_addr = al.addr;
+ ams->sym = al.sym;
+ ams->map = al.map;
+}
+
+struct mem_info *machine__resolve_mem(struct machine *machine,
+ struct thread *thr,
+ struct perf_sample *sample,
+ u8 cpumode)
+{
+ struct mem_info *mi = zalloc(sizeof(*mi));
+
+ if (!mi)
+ return NULL;
+
+ ip__resolve_ams(machine, thr, &mi->iaddr, sample->ip);
+ ip__resolve_data(machine, thr, cpumode, &mi->daddr, sample->addr);
+ mi->data_src.val = sample->data_src;
+
+ return mi;
+}
+
struct branch_info *machine__resolve_bstack(struct machine *machine,
struct thread *thr,
struct branch_stack *bs)
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 5ac5892f2326..77940680f1fc 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -76,6 +76,9 @@ void machine__delete(struct machine *machine);
struct branch_info *machine__resolve_bstack(struct machine *machine,
struct thread *thread,
struct branch_stack *bs);
+struct mem_info *machine__resolve_mem(struct machine *machine,
+ struct thread *thread,
+ struct perf_sample *sample, u8 cpumode);
int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
@@ -97,7 +100,6 @@ static inline bool machine__is_host(struct machine *machine)
}
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
-void machine__remove_thread(struct machine *machine, struct thread *th);
size_t machine__fprintf(struct machine *machine, FILE *fp);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c84f48cf9678..6c8bb0fb189b 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -10,7 +10,7 @@
#include "symbol.h"
#include "cache.h"
#include "header.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include "parse-events-bison.h"
#define YY_EXTRA_TYPE int
#include "parse-events-flex.h"
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 49a256e6e0a2..aa04bf9c9ad7 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -40,7 +40,7 @@
#include "color.h"
#include "symbol.h"
#include "thread.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include "trace-event.h" /* For __maybe_unused */
#include "probe-event.h"
#include "probe-finder.h"
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 64536a993f4a..f75ae1b9900c 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -15,7 +15,6 @@ util/thread_map.c
util/util.c
util/xyarray.c
util/cgroup.c
-util/debugfs.c
util/rblist.c
util/strlist.c
util/sysfs.c
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index bd85280bb6e8..cf1fe01b7e89 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,3 @@
-#define _FILE_OFFSET_BITS 64
-
#include <linux/kernel.h>
#include <byteswap.h>
@@ -800,6 +798,12 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
+
+ if (sample_type & PERF_SAMPLE_WEIGHT)
+ printf("... weight: %" PRIu64 "\n", sample->weight);
+
+ if (sample_type & PERF_SAMPLE_DATA_SRC)
+ printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
}
static struct machine *
@@ -1365,18 +1369,6 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
return machine__fprintf(&session->machines.host, fp);
}
-void perf_session__remove_thread(struct perf_session *session,
- struct thread *th)
-{
- /*
- * FIXME: This one makes no sense, we need to remove the thread from
- * the machine it belongs to, perf_session can have many machines, so
- * doing it always on ->machines.host is wrong. Fix when auditing all
- * the 'perf kvm' code.
- */
- machine__remove_thread(&session->machines.host, th);
-}
-
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type)
{
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index b5c0847edfa9..6b51d47acdba 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -72,7 +72,6 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
int perf_session__create_kernel_maps(struct perf_session *self);
void perf_session__set_id_hdr_size(struct perf_session *session);
-void perf_session__remove_thread(struct perf_session *self, struct thread *th);
static inline
struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 73d510269784..6b0ed322907e 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -24,6 +24,7 @@ cflags += getenv('CFLAGS', '').split()
build_lib = getenv('PYTHON_EXTBUILD_LIB')
build_tmp = getenv('PYTHON_EXTBUILD_TMP')
libtraceevent = getenv('LIBTRACEEVENT')
+liblk = getenv('LIBLK')
ext_sources = [f.strip() for f in file('util/python-ext-sources')
if len(f.strip()) > 0 and f[0] != '#']
@@ -32,7 +33,7 @@ perf = Extension('perf',
sources = ext_sources,
include_dirs = ['util/include'],
extra_compile_args = cflags,
- extra_objects = [libtraceevent],
+ extra_objects = [libtraceevent, liblk],
)
setup(name='perf',
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index d41926cb9e3f..5f52d492590c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -198,11 +198,19 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
}
ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
- if (sym)
- ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
- width - ret,
- sym->name);
- else {
+ if (sym && map) {
+ if (map->type == MAP__VARIABLE) {
+ ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
+ ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
+ ip - map->unmap_ip(map, sym->start));
+ ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
+ width - ret, "");
+ } else {
+ ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
+ width - ret,
+ sym->name);
+ }
+ } else {
size_t len = BITS_PER_LONG / 4;
ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
len, ip);
@@ -457,6 +465,304 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
return repsep_snprintf(bf, size, "%-*s", width, out);
}
+/* --sort daddr_sym */
+static int64_t
+sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ uint64_t l = 0, r = 0;
+
+ if (left->mem_info)
+ l = left->mem_info->daddr.addr;
+ if (right->mem_info)
+ r = right->mem_info->daddr.addr;
+
+ return (int64_t)(r - l);
+}
+
+static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ uint64_t addr = 0;
+ struct map *map = NULL;
+ struct symbol *sym = NULL;
+
+ if (self->mem_info) {
+ addr = self->mem_info->daddr.addr;
+ map = self->mem_info->daddr.map;
+ sym = self->mem_info->daddr.sym;
+ }
+ return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
+ width);
+}
+
+static int64_t
+sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ struct map *map_l = NULL;
+ struct map *map_r = NULL;
+
+ if (left->mem_info)
+ map_l = left->mem_info->daddr.map;
+ if (right->mem_info)
+ map_r = right->mem_info->daddr.map;
+
+ return _sort__dso_cmp(map_l, map_r);
+}
+
+static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ struct map *map = NULL;
+
+ if (self->mem_info)
+ map = self->mem_info->daddr.map;
+
+ return _hist_entry__dso_snprintf(map, bf, size, width);
+}
+
+static int64_t
+sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ union perf_mem_data_src data_src_l;
+ union perf_mem_data_src data_src_r;
+
+ if (left->mem_info)
+ data_src_l = left->mem_info->data_src;
+ else
+ data_src_l.mem_lock = PERF_MEM_LOCK_NA;
+
+ if (right->mem_info)
+ data_src_r = right->mem_info->data_src;
+ else
+ data_src_r.mem_lock = PERF_MEM_LOCK_NA;
+
+ return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
+}
+
+static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ const char *out;
+ u64 mask = PERF_MEM_LOCK_NA;
+
+ if (self->mem_info)
+ mask = self->mem_info->data_src.mem_lock;
+
+ if (mask & PERF_MEM_LOCK_NA)
+ out = "N/A";
+ else if (mask & PERF_MEM_LOCK_LOCKED)
+ out = "Yes";
+ else
+ out = "No";
+
+ return repsep_snprintf(bf, size, "%-*s", width, out);
+}
+
+static int64_t
+sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ union perf_mem_data_src data_src_l;
+ union perf_mem_data_src data_src_r;
+
+ if (left->mem_info)
+ data_src_l = left->mem_info->data_src;
+ else
+ data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
+
+ if (right->mem_info)
+ data_src_r = right->mem_info->data_src;
+ else
+ data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
+
+ return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
+}
+
+static const char * const tlb_access[] = {
+ "N/A",
+ "HIT",
+ "MISS",
+ "L1",
+ "L2",
+ "Walker",
+ "Fault",
+};
+#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
+
+static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ char out[64];
+ size_t sz = sizeof(out) - 1; /* -1 for null termination */
+ size_t l = 0, i;
+ u64 m = PERF_MEM_TLB_NA;
+ u64 hit, miss;
+
+ out[0] = '\0';
+
+ if (self->mem_info)
+ m = self->mem_info->data_src.mem_dtlb;
+
+ hit = m & PERF_MEM_TLB_HIT;
+ miss = m & PERF_MEM_TLB_MISS;
+
+ /* already taken care of */
+ m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
+
+ for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
+ if (!(m & 0x1))
+ continue;
+ if (l) {
+ strcat(out, " or ");
+ l += 4;
+ }
+ strncat(out, tlb_access[i], sz - l);
+ l += strlen(tlb_access[i]);
+ }
+ if (*out == '\0')
+ strcpy(out, "N/A");
+ if (hit)
+ strncat(out, " hit", sz - l);
+ if (miss)
+ strncat(out, " miss", sz - l);
+
+ return repsep_snprintf(bf, size, "%-*s", width, out);
+}
+
+static int64_t
+sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ union perf_mem_data_src data_src_l;
+ union perf_mem_data_src data_src_r;
+
+ if (left->mem_info)
+ data_src_l = left->mem_info->data_src;
+ else
+ data_src_l.mem_lvl = PERF_MEM_LVL_NA;
+
+ if (right->mem_info)
+ data_src_r = right->mem_info->data_src;
+ else
+ data_src_r.mem_lvl = PERF_MEM_LVL_NA;
+
+ return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
+}
+
+static const char * const mem_lvl[] = {
+ "N/A",
+ "HIT",
+ "MISS",
+ "L1",
+ "LFB",
+ "L2",
+ "L3",
+ "Local RAM",
+ "Remote RAM (1 hop)",
+ "Remote RAM (2 hops)",
+ "Remote Cache (1 hop)",
+ "Remote Cache (2 hops)",
+ "I/O",
+ "Uncached",
+};
+#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
+
+static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ char out[64];
+ size_t sz = sizeof(out) - 1; /* -1 for null termination */
+ size_t i, l = 0;
+ u64 m = PERF_MEM_LVL_NA;
+ u64 hit, miss;
+
+ if (self->mem_info)
+ m = self->mem_info->data_src.mem_lvl;
+
+ out[0] = '\0';
+
+ hit = m & PERF_MEM_LVL_HIT;
+ miss = m & PERF_MEM_LVL_MISS;
+
+ /* already taken care of */
+ m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
+
+ for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
+ if (!(m & 0x1))
+ continue;
+ if (l) {
+ strcat(out, " or ");
+ l += 4;
+ }
+ strncat(out, mem_lvl[i], sz - l);
+ l += strlen(mem_lvl[i]);
+ }
+ if (*out == '\0')
+ strcpy(out, "N/A");
+ if (hit)
+ strncat(out, " hit", sz - l);
+ if (miss)
+ strncat(out, " miss", sz - l);
+
+ return repsep_snprintf(bf, size, "%-*s", width, out);
+}
+
+static int64_t
+sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ union perf_mem_data_src data_src_l;
+ union perf_mem_data_src data_src_r;
+
+ if (left->mem_info)
+ data_src_l = left->mem_info->data_src;
+ else
+ data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
+
+ if (right->mem_info)
+ data_src_r = right->mem_info->data_src;
+ else
+ data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
+
+ return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
+}
+
+static const char * const snoop_access[] = {
+ "N/A",
+ "None",
+ "Miss",
+ "Hit",
+ "HitM",
+};
+#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
+
+static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ char out[64];
+ size_t sz = sizeof(out) - 1; /* -1 for null termination */
+ size_t i, l = 0;
+ u64 m = PERF_MEM_SNOOP_NA;
+
+ out[0] = '\0';
+
+ if (self->mem_info)
+ m = self->mem_info->data_src.mem_snoop;
+
+ for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
+ if (!(m & 0x1))
+ continue;
+ if (l) {
+ strcat(out, " or ");
+ l += 4;
+ }
+ strncat(out, snoop_access[i], sz - l);
+ l += strlen(snoop_access[i]);
+ }
+
+ if (*out == '\0')
+ strcpy(out, "N/A");
+
+ return repsep_snprintf(bf, size, "%-*s", width, out);
+}
+
struct sort_entry sort_mispredict = {
.se_header = "Branch Mispredicted",
.se_cmp = sort__mispredict_cmp,
@@ -464,6 +770,91 @@ struct sort_entry sort_mispredict = {
.se_width_idx = HISTC_MISPREDICT,
};
+static u64 he_weight(struct hist_entry *he)
+{
+ return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
+}
+
+static int64_t
+sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return he_weight(left) - he_weight(right);
+}
+
+static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
+}
+
+struct sort_entry sort_local_weight = {
+ .se_header = "Local Weight",
+ .se_cmp = sort__local_weight_cmp,
+ .se_snprintf = hist_entry__local_weight_snprintf,
+ .se_width_idx = HISTC_LOCAL_WEIGHT,
+};
+
+static int64_t
+sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ return left->stat.weight - right->stat.weight;
+}
+
+static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
+ size_t size, unsigned int width)
+{
+ return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
+}
+
+struct sort_entry sort_global_weight = {
+ .se_header = "Weight",
+ .se_cmp = sort__global_weight_cmp,
+ .se_snprintf = hist_entry__global_weight_snprintf,
+ .se_width_idx = HISTC_GLOBAL_WEIGHT,
+};
+
+struct sort_entry sort_mem_daddr_sym = {
+ .se_header = "Data Symbol",
+ .se_cmp = sort__daddr_cmp,
+ .se_snprintf = hist_entry__daddr_snprintf,
+ .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
+};
+
+struct sort_entry sort_mem_daddr_dso = {
+ .se_header = "Data Object",
+ .se_cmp = sort__dso_daddr_cmp,
+ .se_snprintf = hist_entry__dso_daddr_snprintf,
+ .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
+};
+
+struct sort_entry sort_mem_locked = {
+ .se_header = "Locked",
+ .se_cmp = sort__locked_cmp,
+ .se_snprintf = hist_entry__locked_snprintf,
+ .se_width_idx = HISTC_MEM_LOCKED,
+};
+
+struct sort_entry sort_mem_tlb = {
+ .se_header = "TLB access",
+ .se_cmp = sort__tlb_cmp,
+ .se_snprintf = hist_entry__tlb_snprintf,
+ .se_width_idx = HISTC_MEM_TLB,
+};
+
+struct sort_entry sort_mem_lvl = {
+ .se_header = "Memory access",
+ .se_cmp = sort__lvl_cmp,
+ .se_snprintf = hist_entry__lvl_snprintf,
+ .se_width_idx = HISTC_MEM_LVL,
+};
+
+struct sort_entry sort_mem_snoop = {
+ .se_header = "Snoop",
+ .se_cmp = sort__snoop_cmp,
+ .se_snprintf = hist_entry__snoop_snprintf,
+ .se_width_idx = HISTC_MEM_SNOOP,
+};
+
struct sort_dimension {
const char *name;
struct sort_entry *entry;
@@ -480,6 +871,14 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_SRCLINE, "srcline", sort_srcline),
+ DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
+ DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
+ DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
+ DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
+ DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
+ DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
+ DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
+ DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
};
#undef DIM
@@ -516,7 +915,10 @@ int sort_dimension__add(const char *tok)
return -EINVAL;
}
sort__has_parent = 1;
- } else if (sd->entry == &sort_sym) {
+ } else if (sd->entry == &sort_sym ||
+ sd->entry == &sort_sym_from ||
+ sd->entry == &sort_sym_to ||
+ sd->entry == &sort_mem_daddr_sym) {
sort__has_sym = 1;
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b13e56f6ccbe..f24bdf64238c 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,6 +49,7 @@ struct he_stat {
u64 period_us;
u64 period_guest_sys;
u64 period_guest_us;
+ u64 weight;
u32 nr_events;
};
@@ -100,7 +101,8 @@ struct hist_entry {
struct rb_root sorted_chain;
struct branch_info *branch_info;
struct hists *hists;
- struct callchain_root callchain[0];
+ struct mem_info *mem_info;
+ struct callchain_root callchain[0]; /* must be last member */
};
static inline bool hist_entry__has_pairs(struct hist_entry *he)
@@ -130,6 +132,14 @@ enum sort_type {
SORT_PARENT,
SORT_CPU,
SORT_SRCLINE,
+ SORT_LOCAL_WEIGHT,
+ SORT_GLOBAL_WEIGHT,
+ SORT_MEM_DADDR_SYMBOL,
+ SORT_MEM_DADDR_DSO,
+ SORT_MEM_LOCKED,
+ SORT_MEM_TLB,
+ SORT_MEM_LVL,
+ SORT_MEM_SNOOP,
/* branch stack specific sort keys */
__SORT_BRANCH_STACK,
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 54efcb5659ac..4b12bf850325 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -806,9 +806,12 @@ int dso__load_sym(struct dso *dso, struct map *map,
* DWARF DW_compile_unit has this, but we don't always have access
* to it...
*/
- demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
- if (demangled != NULL)
- elf_name = demangled;
+ if (symbol_conf.demangle) {
+ demangled = bfd_demangle(NULL, elf_name,
+ DMGL_PARAMS | DMGL_ANSI);
+ if (demangled != NULL)
+ elf_name = demangled;
+ }
new_symbol:
f = symbol__new(sym.st_value, sym.st_size,
GELF_ST_BIND(sym.st_info), elf_name);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e6432d85b43d..8cf3b5426a9a 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -36,6 +36,7 @@ struct symbol_conf symbol_conf = {
.use_modules = true,
.try_vmlinux_path = true,
.annotate_src = true,
+ .demangle = true,
.symfs = "",
};
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b62ca37c4b77..5f720dc076da 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -97,7 +97,8 @@ struct symbol_conf {
kptr_restrict,
annotate_asm_raw,
annotate_src,
- event_group;
+ event_group,
+ demangle;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
@@ -155,6 +156,12 @@ struct branch_info {
struct branch_flags flags;
};
+struct mem_info {
+ struct addr_map_symbol iaddr;
+ struct addr_map_symbol daddr;
+ union perf_mem_data_src data_src;
+};
+
struct addr_location {
struct thread *thread;
struct map *map;
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index f718df8a3c59..0cd8b3108084 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -21,4 +21,9 @@ void thread_map__delete(struct thread_map *threads);
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
+static inline int thread_map__nr(struct thread_map *threads)
+{
+ return threads ? threads->nr : 1;
+}
+
#endif /* __PERF_THREAD_MAP_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index a8d81c35ef66..3917eb9a8479 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -38,52 +38,20 @@
#include "../perf.h"
#include "trace-event.h"
-#include "debugfs.h"
+#include <lk/debugfs.h>
#include "evsel.h"
#define VERSION "0.5"
-#define TRACE_CTRL "tracing_on"
-#define TRACE "trace"
-#define AVAILABLE "available_tracers"
-#define CURRENT "current_tracer"
-#define ITER_CTRL "trace_options"
-#define MAX_LATENCY "tracing_max_latency"
-
-unsigned int page_size;
-
-static const char *output_file = "trace.info";
static int output_fd;
-struct event_list {
- struct event_list *next;
- const char *event;
-};
-
-struct events {
- struct events *sibling;
- struct events *children;
- struct events *next;
- char *name;
-};
-
-
-static void *malloc_or_die(unsigned int size)
-{
- void *data;
-
- data = malloc(size);
- if (!data)
- die("malloc");
- return data;
-}
static const char *find_debugfs(void)
{
- const char *path = debugfs_mount(NULL);
+ const char *path = perf_debugfs_mount(NULL);
if (!path)
- die("Your kernel not support debugfs filesystem");
+ pr_debug("Your kernel does not support the debugfs filesystem");
return path;
}
@@ -102,8 +70,12 @@ static const char *find_tracing_dir(void)
return tracing;
debugfs = find_debugfs();
+ if (!debugfs)
+ return NULL;
- tracing = malloc_or_die(strlen(debugfs) + 9);
+ tracing = malloc(strlen(debugfs) + 9);
+ if (!tracing)
+ return NULL;
sprintf(tracing, "%s/tracing", debugfs);
@@ -120,7 +92,9 @@ static char *get_tracing_file(const char *name)
if (!tracing)
return NULL;
- file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
+ file = malloc(strlen(tracing) + strlen(name) + 2);
+ if (!file)
+ return NULL;
sprintf(file, "%s/%s", tracing, name);
return file;
@@ -131,24 +105,6 @@ static void put_tracing_file(char *file)
free(file);
}
-static ssize_t calc_data_size;
-
-static ssize_t write_or_die(const void *buf, size_t len)
-{
- int ret;
-
- if (calc_data_size) {
- calc_data_size += len;
- return len;
- }
-
- ret = write(output_fd, buf, len);
- if (ret < 0)
- die("writing to '%s'", output_file);
-
- return ret;
-}
-
int bigendian(void)
{
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
@@ -159,59 +115,106 @@ int bigendian(void)
}
/* unfortunately, you can not stat debugfs or proc files for size */
-static void record_file(const char *file, size_t hdr_sz)
+static int record_file(const char *file, ssize_t hdr_sz)
{
unsigned long long size = 0;
char buf[BUFSIZ], *sizep;
off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
int r, fd;
+ int err = -EIO;
fd = open(file, O_RDONLY);
- if (fd < 0)
- die("Can't read '%s'", file);
+ if (fd < 0) {
+ pr_debug("Can't read '%s'", file);
+ return -errno;
+ }
/* put in zeros for file size, then fill true size later */
- if (hdr_sz)
- write_or_die(&size, hdr_sz);
+ if (hdr_sz) {
+ if (write(output_fd, &size, hdr_sz) != hdr_sz)
+ goto out;
+ }
do {
r = read(fd, buf, BUFSIZ);
if (r > 0) {
size += r;
- write_or_die(buf, r);
+ if (write(output_fd, buf, r) != r)
+ goto out;
}
} while (r > 0);
- close(fd);
/* ugh, handle big-endian hdr_size == 4 */
sizep = (char*)&size;
if (bigendian())
sizep += sizeof(u64) - hdr_sz;
- if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0)
- die("writing to %s", output_file);
+ if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
+ pr_debug("writing file size failed\n");
+ goto out;
+ }
+
+ err = 0;
+out:
+ close(fd);
+ return err;
}
-static void read_header_files(void)
+static int read_header_files(void)
{
char *path;
struct stat st;
+ int err = -EIO;
path = get_tracing_file("events/header_page");
- if (stat(path, &st) < 0)
- die("can't read '%s'", path);
+ if (!path) {
+ pr_debug("can't get tracing/events/header_page");
+ return -ENOMEM;
+ }
+
+ if (stat(path, &st) < 0) {
+ pr_debug("can't read '%s'", path);
+ goto out;
+ }
+
+ if (write(output_fd, "header_page", 12) != 12) {
+ pr_debug("can't write header_page\n");
+ goto out;
+ }
+
+ if (record_file(path, 8) < 0) {
+ pr_debug("can't record header_page file\n");
+ goto out;
+ }
- write_or_die("header_page", 12);
- record_file(path, 8);
put_tracing_file(path);
path = get_tracing_file("events/header_event");
- if (stat(path, &st) < 0)
- die("can't read '%s'", path);
+ if (!path) {
+ pr_debug("can't get tracing/events/header_event");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (stat(path, &st) < 0) {
+ pr_debug("can't read '%s'", path);
+ goto out;
+ }
- write_or_die("header_event", 13);
- record_file(path, 8);
+ if (write(output_fd, "header_event", 13) != 13) {
+ pr_debug("can't write header_event\n");
+ goto out;
+ }
+
+ if (record_file(path, 8) < 0) {
+ pr_debug("can't record header_event file\n");
+ goto out;
+ }
+
+ err = 0;
+out:
put_tracing_file(path);
+ return err;
}
static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -225,7 +228,7 @@ static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
return false;
}
-static void copy_event_system(const char *sys, struct tracepoint_path *tps)
+static int copy_event_system(const char *sys, struct tracepoint_path *tps)
{
struct dirent *dent;
struct stat st;
@@ -233,10 +236,13 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
DIR *dir;
int count = 0;
int ret;
+ int err;
dir = opendir(sys);
- if (!dir)
- die("can't read directory '%s'", sys);
+ if (!dir) {
+ pr_debug("can't read directory '%s'", sys);
+ return -errno;
+ }
while ((dent = readdir(dir))) {
if (dent->d_type != DT_DIR ||
@@ -244,7 +250,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
strcmp(dent->d_name, "..") == 0 ||
!name_in_tp_list(dent->d_name, tps))
continue;
- format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
+ format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
+ if (!format) {
+ err = -ENOMEM;
+ goto out;
+ }
sprintf(format, "%s/%s/format", sys, dent->d_name);
ret = stat(format, &st);
free(format);
@@ -253,7 +263,11 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
count++;
}
- write_or_die(&count, 4);
+ if (write(output_fd, &count, 4) != 4) {
+ err = -EIO;
+ pr_debug("can't write count\n");
+ goto out;
+ }
rewinddir(dir);
while ((dent = readdir(dir))) {
@@ -262,27 +276,45 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
strcmp(dent->d_name, "..") == 0 ||
!name_in_tp_list(dent->d_name, tps))
continue;
- format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
+ format = malloc(strlen(sys) + strlen(dent->d_name) + 10);
+ if (!format) {
+ err = -ENOMEM;
+ goto out;
+ }
sprintf(format, "%s/%s/format", sys, dent->d_name);
ret = stat(format, &st);
- if (ret >= 0)
- record_file(format, 8);
-
+ if (ret >= 0) {
+ err = record_file(format, 8);
+ if (err) {
+ free(format);
+ goto out;
+ }
+ }
free(format);
}
+ err = 0;
+out:
closedir(dir);
+ return err;
}
-static void read_ftrace_files(struct tracepoint_path *tps)
+static int read_ftrace_files(struct tracepoint_path *tps)
{
char *path;
+ int ret;
path = get_tracing_file("events/ftrace");
+ if (!path) {
+ pr_debug("can't get tracing/events/ftrace");
+ return -ENOMEM;
+ }
- copy_event_system(path, tps);
+ ret = copy_event_system(path, tps);
put_tracing_file(path);
+
+ return ret;
}
static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -296,7 +328,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
return false;
}
-static void read_event_files(struct tracepoint_path *tps)
+static int read_event_files(struct tracepoint_path *tps)
{
struct dirent *dent;
struct stat st;
@@ -305,12 +337,20 @@ static void read_event_files(struct tracepoint_path *tps)
DIR *dir;
int count = 0;
int ret;
+ int err;
path = get_tracing_file("events");
+ if (!path) {
+ pr_debug("can't get tracing/events");
+ return -ENOMEM;
+ }
dir = opendir(path);
- if (!dir)
- die("can't read directory '%s'", path);
+ if (!dir) {
+ err = -errno;
+ pr_debug("can't read directory '%s'", path);
+ goto out;
+ }
while ((dent = readdir(dir))) {
if (dent->d_type != DT_DIR ||
@@ -322,7 +362,11 @@ static void read_event_files(struct tracepoint_path *tps)
count++;
}
- write_or_die(&count, 4);
+ if (write(output_fd, &count, 4) != 4) {
+ err = -EIO;
+ pr_debug("can't write count\n");
+ goto out;
+ }
rewinddir(dir);
while ((dent = readdir(dir))) {
@@ -332,56 +376,90 @@ static void read_event_files(struct tracepoint_path *tps)
strcmp(dent->d_name, "ftrace") == 0 ||
!system_in_tp_list(dent->d_name, tps))
continue;
- sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
+ sys = malloc(strlen(path) + strlen(dent->d_name) + 2);
+ if (!sys) {
+ err = -ENOMEM;
+ goto out;
+ }
sprintf(sys, "%s/%s", path, dent->d_name);
ret = stat(sys, &st);
if (ret >= 0) {
- write_or_die(dent->d_name, strlen(dent->d_name) + 1);
- copy_event_system(sys, tps);
+ ssize_t size = strlen(dent->d_name) + 1;
+
+ if (write(output_fd, dent->d_name, size) != size ||
+ copy_event_system(sys, tps) < 0) {
+ err = -EIO;
+ free(sys);
+ goto out;
+ }
}
free(sys);
}
-
+ err = 0;
+out:
closedir(dir);
put_tracing_file(path);
+
+ return err;
}
-static void read_proc_kallsyms(void)
+static int read_proc_kallsyms(void)
{
unsigned int size;
const char *path = "/proc/kallsyms";
struct stat st;
- int ret;
+ int ret, err = 0;
ret = stat(path, &st);
if (ret < 0) {
/* not found */
size = 0;
- write_or_die(&size, 4);
- return;
+ if (write(output_fd, &size, 4) != 4)
+ err = -EIO;
+ return err;
}
- record_file(path, 4);
+ return record_file(path, 4);
}
-static void read_ftrace_printk(void)
+static int read_ftrace_printk(void)
{
unsigned int size;
char *path;
struct stat st;
- int ret;
+ int ret, err = 0;
path = get_tracing_file("printk_formats");
+ if (!path) {
+ pr_debug("can't get tracing/printk_formats");
+ return -ENOMEM;
+ }
+
ret = stat(path, &st);
if (ret < 0) {
/* not found */
size = 0;
- write_or_die(&size, 4);
+ if (write(output_fd, &size, 4) != 4)
+ err = -EIO;
goto out;
}
- record_file(path, 4);
+ err = record_file(path, 4);
out:
put_tracing_file(path);
+ return err;
+}
+
+static void
+put_tracepoints_path(struct tracepoint_path *tps)
+{
+ while (tps) {
+ struct tracepoint_path *t = tps;
+
+ tps = tps->next;
+ free(t->name);
+ free(t->system);
+ free(t);
+ }
}
static struct tracepoint_path *
@@ -396,27 +474,17 @@ get_tracepoints_path(struct list_head *pattrs)
continue;
++nr_tracepoints;
ppath->next = tracepoint_id_to_path(pos->attr.config);
- if (!ppath->next)
- die("%s\n", "No memory to alloc tracepoints list");
+ if (!ppath->next) {
+ pr_debug("No memory to alloc tracepoints list\n");
+ put_tracepoints_path(&path);
+ return NULL;
+ }
ppath = ppath->next;
}
return nr_tracepoints > 0 ? path.next : NULL;
}
-static void
-put_tracepoints_path(struct tracepoint_path *tps)
-{
- while (tps) {
- struct tracepoint_path *t = tps;
-
- tps = tps->next;
- free(t->name);
- free(t->system);
- free(t);
- }
-}
-
bool have_tracepoints(struct list_head *pattrs)
{
struct perf_evsel *pos;
@@ -428,9 +496,10 @@ bool have_tracepoints(struct list_head *pattrs)
return false;
}
-static void tracing_data_header(void)
+static int tracing_data_header(void)
{
char buf[20];
+ ssize_t size;
/* just guessing this is someone's birthday.. ;) */
buf[0] = 23;
@@ -438,9 +507,12 @@ static void tracing_data_header(void)
buf[2] = 68;
memcpy(buf + 3, "tracing", 7);
- write_or_die(buf, 10);
+ if (write(output_fd, buf, 10) != 10)
+ return -1;
- write_or_die(VERSION, strlen(VERSION) + 1);
+ size = strlen(VERSION) + 1;
+ if (write(output_fd, VERSION, size) != size)
+ return -1;
/* save endian */
if (bigendian())
@@ -450,15 +522,19 @@ static void tracing_data_header(void)
read_trace_init(buf[0], buf[0]);
- write_or_die(buf, 1);
+ if (write(output_fd, buf, 1) != 1)
+ return -1;
/* save size of long */
buf[0] = sizeof(long);
- write_or_die(buf, 1);
+ if (write(output_fd, buf, 1) != 1)
+ return -1;
/* save page_size */
- page_size = sysconf(_SC_PAGESIZE);
- write_or_die(&page_size, 4);
+ if (write(output_fd, &page_size, 4) != 4)
+ return -1;
+
+ return 0;
}
struct tracing_data *tracing_data_get(struct list_head *pattrs,
@@ -466,6 +542,7 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
{
struct tracepoint_path *tps;
struct tracing_data *tdata;
+ int err;
output_fd = fd;
@@ -473,7 +550,10 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
if (!tps)
return NULL;
- tdata = malloc_or_die(sizeof(*tdata));
+ tdata = malloc(sizeof(*tdata));
+ if (!tdata)
+ return NULL;
+
tdata->temp = temp;
tdata->size = 0;
@@ -482,12 +562,16 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
snprintf(tdata->temp_file, sizeof(tdata->temp_file),
"/tmp/perf-XXXXXX");
- if (!mkstemp(tdata->temp_file))
- die("Can't make temp file");
+ if (!mkstemp(tdata->temp_file)) {
+ pr_debug("Can't make temp file");
+ return NULL;
+ }
temp_fd = open(tdata->temp_file, O_RDWR);
- if (temp_fd < 0)
- die("Can't read '%s'", tdata->temp_file);
+ if (temp_fd < 0) {
+ pr_debug("Can't read '%s'", tdata->temp_file);
+ return NULL;
+ }
/*
* Set the temp file the default output, so all the
@@ -496,13 +580,24 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
output_fd = temp_fd;
}
- tracing_data_header();
- read_header_files();
- read_ftrace_files(tps);
- read_event_files(tps);
- read_proc_kallsyms();
- read_ftrace_printk();
+ err = tracing_data_header();
+ if (err)
+ goto out;
+ err = read_header_files();
+ if (err)
+ goto out;
+ err = read_ftrace_files(tps);
+ if (err)
+ goto out;
+ err = read_event_files(tps);
+ if (err)
+ goto out;
+ err = read_proc_kallsyms();
+ if (err)
+ goto out;
+ err = read_ftrace_printk();
+out:
/*
* All tracing data are stored by now, we can restore
* the default output file in case we used temp file.
@@ -513,22 +608,31 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
output_fd = fd;
}
+ if (err) {
+ free(tdata);
+ tdata = NULL;
+ }
+
put_tracepoints_path(tps);
return tdata;
}
-void tracing_data_put(struct tracing_data *tdata)
+int tracing_data_put(struct tracing_data *tdata)
{
+ int err = 0;
+
if (tdata->temp) {
- record_file(tdata->temp_file, 0);
+ err = record_file(tdata->temp_file, 0);
unlink(tdata->temp_file);
}
free(tdata);
+ return err;
}
int read_tracing_data(int fd, struct list_head *pattrs)
{
+ int err;
struct tracing_data *tdata;
/*
@@ -539,6 +643,6 @@ int read_tracing_data(int fd, struct list_head *pattrs)
if (!tdata)
return -ENOMEM;
- tracing_data_put(tdata);
- return 0;
+ err = tracing_data_put(tdata);
+ return err;
}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 3aabcd687cd5..4454835a9ebc 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -183,43 +183,6 @@ void event_format__print(struct event_format *event,
trace_seq_do_printf(&s);
}
-void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
-{
- int type = trace_parse_common_type(pevent, data);
- struct event_format *event = pevent_find_event(pevent, type);
-
- if (!event) {
- warning("ug! no event found for type %d", type);
- return;
- }
-
- event_format__print(event, cpu, data, size);
-}
-
-void print_event(struct pevent *pevent, int cpu, void *data, int size,
- unsigned long long nsecs, char *comm)
-{
- struct pevent_record record;
- struct trace_seq s;
- int pid;
-
- pevent->latency_format = latency_format;
-
- record.ts = nsecs;
- record.cpu = cpu;
- record.size = size;
- record.data = data;
- pid = pevent_data_pid(pevent, &record);
-
- if (!pevent_pid_is_registered(pevent, pid))
- pevent_register_comm(pevent, comm, pid);
-
- trace_seq_init(&s);
- pevent_print_event(pevent, &s, &record);
- trace_seq_do_printf(&s);
- printf("\n");
-}
-
void parse_proc_kallsyms(struct pevent *pevent,
char *file, unsigned int size __maybe_unused)
{
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 3741572696af..af215c0d2379 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,8 +18,6 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-#define _FILE_OFFSET_BITS 64
-
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,26 +39,14 @@
static int input_fd;
-static int read_page;
-
int file_bigendian;
int host_bigendian;
static int long_size;
-static ssize_t calc_data_size;
+static ssize_t trace_data_size;
static bool repipe;
-static void *malloc_or_die(int size)
-{
- void *ret;
-
- ret = malloc(size);
- if (!ret)
- die("malloc");
- return ret;
-}
-
-static int do_read(int fd, void *buf, int size)
+static int __do_read(int fd, void *buf, int size)
{
int rsize = size;
@@ -73,8 +59,10 @@ static int do_read(int fd, void *buf, int size)
if (repipe) {
int retw = write(STDOUT_FILENO, buf, ret);
- if (retw <= 0 || retw != ret)
- die("repiping input file");
+ if (retw <= 0 || retw != ret) {
+ pr_debug("repiping input file");
+ return -1;
+ }
}
size -= ret;
@@ -84,17 +72,18 @@ static int do_read(int fd, void *buf, int size)
return rsize;
}
-static int read_or_die(void *data, int size)
+static int do_read(void *data, int size)
{
int r;
- r = do_read(input_fd, data, size);
- if (r <= 0)
- die("reading input file (size expected=%d received=%d)",
- size, r);
+ r = __do_read(input_fd, data, size);
+ if (r <= 0) {
+ pr_debug("reading input file (size expected=%d received=%d)",
+ size, r);
+ return -1;
+ }
- if (calc_data_size)
- calc_data_size += r;
+ trace_data_size += r;
return r;
}
@@ -107,7 +96,7 @@ static void skip(int size)
while (size) {
r = size > BUFSIZ ? BUFSIZ : size;
- read_or_die(buf, r);
+ do_read(buf, r);
size -= r;
};
}
@@ -116,7 +105,8 @@ static unsigned int read4(struct pevent *pevent)
{
unsigned int data;
- read_or_die(&data, 4);
+ if (do_read(&data, 4) < 0)
+ return 0;
return __data2host4(pevent, data);
}
@@ -124,7 +114,8 @@ static unsigned long long read8(struct pevent *pevent)
{
unsigned long long data;
- read_or_die(&data, 8);
+ if (do_read(&data, 8) < 0)
+ return 0;
return __data2host8(pevent, data);
}
@@ -138,17 +129,23 @@ static char *read_string(void)
for (;;) {
r = read(input_fd, &c, 1);
- if (r < 0)
- die("reading input file");
+ if (r < 0) {
+ pr_debug("reading input file");
+ goto out;
+ }
- if (!r)
- die("no data");
+ if (!r) {
+ pr_debug("no data");
+ goto out;
+ }
if (repipe) {
int retw = write(STDOUT_FILENO, &c, 1);
- if (retw <= 0 || retw != r)
- die("repiping input file string");
+ if (retw <= 0 || retw != r) {
+ pr_debug("repiping input file string");
+ goto out;
+ }
}
buf[size++] = c;
@@ -157,60 +154,79 @@ static char *read_string(void)
break;
}
- if (calc_data_size)
- calc_data_size += size;
-
- str = malloc_or_die(size);
- memcpy(str, buf, size);
+ trace_data_size += size;
+ str = malloc(size);
+ if (str)
+ memcpy(str, buf, size);
+out:
return str;
}
-static void read_proc_kallsyms(struct pevent *pevent)
+static int read_proc_kallsyms(struct pevent *pevent)
{
unsigned int size;
char *buf;
size = read4(pevent);
if (!size)
- return;
+ return 0;
+
+ buf = malloc(size + 1);
+ if (buf == NULL)
+ return -1;
- buf = malloc_or_die(size + 1);
- read_or_die(buf, size);
+ if (do_read(buf, size) < 0) {
+ free(buf);
+ return -1;
+ }
buf[size] = '\0';
parse_proc_kallsyms(pevent, buf, size);
free(buf);
+ return 0;
}
-static void read_ftrace_printk(struct pevent *pevent)
+static int read_ftrace_printk(struct pevent *pevent)
{
unsigned int size;
char *buf;
+ /* it can have 0 size */
size = read4(pevent);
if (!size)
- return;
+ return 0;
+
+ buf = malloc(size);
+ if (buf == NULL)
+ return -1;
- buf = malloc_or_die(size);
- read_or_die(buf, size);
+ if (do_read(buf, size) < 0) {
+ free(buf);
+ return -1;
+ }
parse_ftrace_printk(pevent, buf, size);
free(buf);
+ return 0;
}
-static void read_header_files(struct pevent *pevent)
+static int read_header_files(struct pevent *pevent)
{
unsigned long long size;
char *header_event;
char buf[BUFSIZ];
+ int ret = 0;
- read_or_die(buf, 12);
+ if (do_read(buf, 12) < 0)
+ return -1;
- if (memcmp(buf, "header_page", 12) != 0)
- die("did not read header page");
+ if (memcmp(buf, "header_page", 12) != 0) {
+ pr_debug("did not read header page");
+ return -1;
+ }
size = read8(pevent);
skip(size);
@@ -221,269 +237,107 @@ static void read_header_files(struct pevent *pevent)
*/
long_size = header_page_size_size;
- read_or_die(buf, 13);
- if (memcmp(buf, "header_event", 13) != 0)
- die("did not read header event");
+ if (do_read(buf, 13) < 0)
+ return -1;
+
+ if (memcmp(buf, "header_event", 13) != 0) {
+ pr_debug("did not read header event");
+ return -1;
+ }
size = read8(pevent);
- header_event = malloc_or_die(size);
- read_or_die(header_event, size);
+ header_event = malloc(size);
+ if (header_event == NULL)
+ return -1;
+
+ if (do_read(header_event, size) < 0)
+ ret = -1;
+
free(header_event);
+ return ret;
}
-static void read_ftrace_file(struct pevent *pevent, unsigned long long size)
+static int read_ftrace_file(struct pevent *pevent, unsigned long long size)
{
char *buf;
- buf = malloc_or_die(size);
- read_or_die(buf, size);
+ buf = malloc(size);
+ if (buf == NULL)
+ return -1;
+
+ if (do_read(buf, size) < 0) {
+ free(buf);
+ return -1;
+ }
+
parse_ftrace_file(pevent, buf, size);
free(buf);
+ return 0;
}
-static void read_event_file(struct pevent *pevent, char *sys,
+static int read_event_file(struct pevent *pevent, char *sys,
unsigned long long size)
{
char *buf;
- buf = malloc_or_die(size);
- read_or_die(buf, size);
+ buf = malloc(size);
+ if (buf == NULL)
+ return -1;
+
+ if (do_read(buf, size) < 0) {
+ free(buf);
+ return -1;
+ }
+
parse_event_file(pevent, buf, size, sys);
free(buf);
+ return 0;
}
-static void read_ftrace_files(struct pevent *pevent)
+static int read_ftrace_files(struct pevent *pevent)
{
unsigned long long size;
int count;
int i;
+ int ret;
count = read4(pevent);
for (i = 0; i < count; i++) {
size = read8(pevent);
- read_ftrace_file(pevent, size);
+ ret = read_ftrace_file(pevent, size);
+ if (ret)
+ return ret;
}
+ return 0;
}
-static void read_event_files(struct pevent *pevent)
+static int read_event_files(struct pevent *pevent)
{
unsigned long long size;
char *sys;
int systems;
int count;
int i,x;
+ int ret;
systems = read4(pevent);
for (i = 0; i < systems; i++) {
sys = read_string();
+ if (sys == NULL)
+ return -1;
count = read4(pevent);
+
for (x=0; x < count; x++) {
size = read8(pevent);
- read_event_file(pevent, sys, size);
+ ret = read_event_file(pevent, sys, size);
+ if (ret)
+ return ret;
}
}
-}
-
-struct cpu_data {
- unsigned long long offset;
- unsigned long long size;
- unsigned long long timestamp;
- struct pevent_record *next;
- char *page;
- int cpu;
- int index;
- int page_size;
-};
-
-static struct cpu_data *cpu_data;
-
-static void update_cpu_data_index(int cpu)
-{
- cpu_data[cpu].offset += page_size;
- cpu_data[cpu].size -= page_size;
- cpu_data[cpu].index = 0;
-}
-
-static void get_next_page(int cpu)
-{
- off_t save_seek;
- off_t ret;
-
- if (!cpu_data[cpu].page)
- return;
-
- if (read_page) {
- if (cpu_data[cpu].size <= page_size) {
- free(cpu_data[cpu].page);
- cpu_data[cpu].page = NULL;
- return;
- }
-
- update_cpu_data_index(cpu);
-
- /* other parts of the code may expect the pointer to not move */
- save_seek = lseek(input_fd, 0, SEEK_CUR);
-
- ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
- if (ret == (off_t)-1)
- die("failed to lseek");
- ret = read(input_fd, cpu_data[cpu].page, page_size);
- if (ret < 0)
- die("failed to read page");
-
- /* reset the file pointer back */
- lseek(input_fd, save_seek, SEEK_SET);
-
- return;
- }
-
- munmap(cpu_data[cpu].page, page_size);
- cpu_data[cpu].page = NULL;
-
- if (cpu_data[cpu].size <= page_size)
- return;
-
- update_cpu_data_index(cpu);
-
- cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
- input_fd, cpu_data[cpu].offset);
- if (cpu_data[cpu].page == MAP_FAILED)
- die("failed to mmap cpu %d at offset 0x%llx",
- cpu, cpu_data[cpu].offset);
-}
-
-static unsigned int type_len4host(unsigned int type_len_ts)
-{
- if (file_bigendian)
- return (type_len_ts >> 27) & ((1 << 5) - 1);
- else
- return type_len_ts & ((1 << 5) - 1);
-}
-
-static unsigned int ts4host(unsigned int type_len_ts)
-{
- if (file_bigendian)
- return type_len_ts & ((1 << 27) - 1);
- else
- return type_len_ts >> 5;
-}
-
-static int calc_index(void *ptr, int cpu)
-{
- return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
-}
-
-struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
-{
- struct pevent_record *data;
- void *page = cpu_data[cpu].page;
- int idx = cpu_data[cpu].index;
- void *ptr = page + idx;
- unsigned long long extend;
- unsigned int type_len_ts;
- unsigned int type_len;
- unsigned int delta;
- unsigned int length = 0;
-
- if (cpu_data[cpu].next)
- return cpu_data[cpu].next;
-
- if (!page)
- return NULL;
-
- if (!idx) {
- /* FIXME: handle header page */
- if (header_page_ts_size != 8)
- die("expected a long long type for timestamp");
- cpu_data[cpu].timestamp = data2host8(pevent, ptr);
- ptr += 8;
- switch (header_page_size_size) {
- case 4:
- cpu_data[cpu].page_size = data2host4(pevent, ptr);
- ptr += 4;
- break;
- case 8:
- cpu_data[cpu].page_size = data2host8(pevent, ptr);
- ptr += 8;
- break;
- default:
- die("bad long size");
- }
- ptr = cpu_data[cpu].page + header_page_data_offset;
- }
-
-read_again:
- idx = calc_index(ptr, cpu);
-
- if (idx >= cpu_data[cpu].page_size) {
- get_next_page(cpu);
- return trace_peek_data(pevent, cpu);
- }
-
- type_len_ts = data2host4(pevent, ptr);
- ptr += 4;
-
- type_len = type_len4host(type_len_ts);
- delta = ts4host(type_len_ts);
-
- switch (type_len) {
- case RINGBUF_TYPE_PADDING:
- if (!delta)
- die("error, hit unexpected end of page");
- length = data2host4(pevent, ptr);
- ptr += 4;
- length *= 4;
- ptr += length;
- goto read_again;
-
- case RINGBUF_TYPE_TIME_EXTEND:
- extend = data2host4(pevent, ptr);
- ptr += 4;
- extend <<= TS_SHIFT;
- extend += delta;
- cpu_data[cpu].timestamp += extend;
- goto read_again;
-
- case RINGBUF_TYPE_TIME_STAMP:
- ptr += 12;
- break;
- case 0:
- length = data2host4(pevent, ptr);
- ptr += 4;
- die("here! length=%d", length);
- break;
- default:
- length = type_len * 4;
- break;
- }
-
- cpu_data[cpu].timestamp += delta;
-
- data = malloc_or_die(sizeof(*data));
- memset(data, 0, sizeof(*data));
-
- data->ts = cpu_data[cpu].timestamp;
- data->size = length;
- data->data = ptr;
- ptr += length;
-
- cpu_data[cpu].index = calc_index(ptr, cpu);
- cpu_data[cpu].next = data;
-
- return data;
-}
-
-struct pevent_record *trace_read_data(struct pevent *pevent, int cpu)
-{
- struct pevent_record *data;
-
- data = trace_peek_data(pevent, cpu);
- cpu_data[cpu].next = NULL;
-
- return data;
+ return 0;
}
ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
@@ -494,58 +348,85 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
int show_version = 0;
int show_funcs = 0;
int show_printk = 0;
- ssize_t size;
+ ssize_t size = -1;
+ struct pevent *pevent;
+ int err;
- calc_data_size = 1;
- repipe = __repipe;
+ *ppevent = NULL;
+ repipe = __repipe;
input_fd = fd;
- read_or_die(buf, 3);
- if (memcmp(buf, test, 3) != 0)
- die("no trace data in the file");
+ if (do_read(buf, 3) < 0)
+ return -1;
+ if (memcmp(buf, test, 3) != 0) {
+ pr_debug("no trace data in the file");
+ return -1;
+ }
- read_or_die(buf, 7);
- if (memcmp(buf, "tracing", 7) != 0)
- die("not a trace file (missing 'tracing' tag)");
+ if (do_read(buf, 7) < 0)
+ return -1;
+ if (memcmp(buf, "tracing", 7) != 0) {
+ pr_debug("not a trace file (missing 'tracing' tag)");
+ return -1;
+ }
version = read_string();
+ if (version == NULL)
+ return -1;
if (show_version)
printf("version = %s\n", version);
free(version);
- read_or_die(buf, 1);
+ if (do_read(buf, 1) < 0)
+ return -1;
file_bigendian = buf[0];
host_bigendian = bigendian();
- *ppevent = read_trace_init(file_bigendian, host_bigendian);
- if (*ppevent == NULL)
- die("read_trace_init failed");
+ pevent = read_trace_init(file_bigendian, host_bigendian);
+ if (pevent == NULL) {
+ pr_debug("read_trace_init failed");
+ goto out;
+ }
- read_or_die(buf, 1);
+ if (do_read(buf, 1) < 0)
+ goto out;
long_size = buf[0];
- page_size = read4(*ppevent);
-
- read_header_files(*ppevent);
-
- read_ftrace_files(*ppevent);
- read_event_files(*ppevent);
- read_proc_kallsyms(*ppevent);
- read_ftrace_printk(*ppevent);
-
- size = calc_data_size - 1;
- calc_data_size = 0;
+ page_size = read4(pevent);
+ if (!page_size)
+ goto out;
+
+ err = read_header_files(pevent);
+ if (err)
+ goto out;
+ err = read_ftrace_files(pevent);
+ if (err)
+ goto out;
+ err = read_event_files(pevent);
+ if (err)
+ goto out;
+ err = read_proc_kallsyms(pevent);
+ if (err)
+ goto out;
+ err = read_ftrace_printk(pevent);
+ if (err)
+ goto out;
+
+ size = trace_data_size;
repipe = false;
if (show_funcs) {
- pevent_print_funcs(*ppevent);
- return size;
- }
- if (show_printk) {
- pevent_print_printk(*ppevent);
- return size;
+ pevent_print_funcs(pevent);
+ } else if (show_printk) {
+ pevent_print_printk(pevent);
}
+ *ppevent = pevent;
+ pevent = NULL;
+
+out:
+ if (pevent)
+ pevent_free(pevent);
return size;
}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index a55fd37ffea1..1978c398ad87 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -30,13 +30,9 @@ enum {
int bigendian(void);
struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
-void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
void event_format__print(struct event_format *event,
int cpu, void *data, int size);
-void print_event(struct pevent *pevent, int cpu, void *data, int size,
- unsigned long long nsecs, char *comm);
-
int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
int parse_event_file(struct pevent *pevent,
char *buf, unsigned long size, char *sys);
@@ -72,7 +68,7 @@ struct tracing_data {
struct tracing_data *tracing_data_get(struct list_head *pattrs,
int fd, bool temp);
-void tracing_data_put(struct tracing_data *tdata);
+int tracing_data_put(struct tracing_data *tdata);
struct addr_location;
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 805d1f52c5b4..59d868add275 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,8 @@ bool test_attr__enabled;
bool perf_host = true;
bool perf_guest = false;
+char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
+
void event_attr_init(struct perf_event_attr *attr)
{
if (!perf_host)
@@ -242,3 +244,28 @@ void get_term_dimensions(struct winsize *ws)
ws->ws_row = 25;
ws->ws_col = 80;
}
+
+static void set_tracing_events_path(const char *mountpoint)
+{
+ snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s",
+ mountpoint, "tracing/events");
+}
+
+const char *perf_debugfs_mount(const char *mountpoint)
+{
+ const char *mnt;
+
+ mnt = debugfs_mount(mountpoint);
+ if (!mnt)
+ return NULL;
+
+ set_tracing_events_path(mnt);
+
+ return mnt;
+}
+
+void perf_debugfs_set_path(const char *mntpt)
+{
+ snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
+ set_tracing_events_path(mntpt);
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 09b4c26b71aa..a45710b70a55 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -1,8 +1,6 @@
#ifndef GIT_COMPAT_UTIL_H
#define GIT_COMPAT_UTIL_H
-#define _FILE_OFFSET_BITS 64
-
#ifndef FLEX_ARRAY
/*
* See if our compiler is known to support flexible array members.
@@ -73,10 +71,14 @@
#include <linux/magic.h>
#include "types.h"
#include <sys/ttydefaults.h>
+#include <lk/debugfs.h>
extern const char *graph_line;
extern const char *graph_dotted_line;
extern char buildid_dir[];
+extern char tracing_events_path[];
+extern void perf_debugfs_set_path(const char *mountpoint);
+const char *perf_debugfs_mount(const char *mountpoint);
/* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd).
@@ -274,5 +276,4 @@ extern unsigned int page_size;
struct winsize;
void get_term_dimensions(struct winsize *ws);
-
-#endif
+#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c
index 53f5293c9c9a..d032c826d42e 100644
--- a/tools/power/cpupower/debug/i386/intel_gsic.c
+++ b/tools/power/cpupower/debug/i386/intel_gsic.c
@@ -66,7 +66,7 @@ int main (void)
printf("ecx = 0x%.8x\n", r.ecx);
printf("edx = 0x%.8x\n", r.edx);
printf("Note also that some BIOS do not support the initial "
- "GSIC call, but the newer\nspeeedstep-smi driver may "
+ "GSIC call, but the newer\nspeedstep-smi driver may "
"work.\nFor this, you need to pass some arguments to "
"the speedstep-smi driver:\n");
printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n");
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 6f3214ed4444..321e066a0753 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1421,6 +1421,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
case 0x3C: /* HSW */
case 0x3F: /* HSW */
case 0x45: /* HSW */
+ case 0x46: /* HSW */
return 1;
case 0x2E: /* Nehalem-EX Xeon - Beckton */
case 0x2F: /* Westmere-EX Xeon - Eagleton */
@@ -1515,6 +1516,7 @@ void rapl_probe(unsigned int family, unsigned int model)
case 0x3C: /* HSW */
case 0x3F: /* HSW */
case 0x45: /* HSW */
+ case 0x46: /* HSW */
do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
break;
case 0x2D:
@@ -1754,6 +1756,7 @@ int is_snb(unsigned int family, unsigned int model)
case 0x3C: /* HSW */
case 0x3F: /* HSW */
case 0x45: /* HSW */
+ case 0x46: /* HSW */
return 1;
}
return 0;
@@ -2276,7 +2279,7 @@ int main(int argc, char **argv)
cmdline(argc, argv);
if (verbose)
- fprintf(stderr, "turbostat v3.2 February 11, 2013"
+ fprintf(stderr, "turbostat v3.3 March 15, 2013"
" - Len Brown <lenb@kernel.org>\n");
turbostat_init();
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 2964b96aa55f..f03e681f8891 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -1,3 +1,4 @@
+ifneq ($(O),)
ifeq ($(origin O), command line)
dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
ABSOLUTE_O := $(shell cd $(O) ; pwd)
@@ -7,9 +8,10 @@ ifeq ($(objtree),)
objtree := $(O)
endif
endif
+endif
-ifneq ($(OUTPUT),)
# check that the output directory actually exists
+ifneq ($(OUTPUT),)
OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
endif
@@ -70,7 +72,7 @@ ifndef V
QUIET_BISON = @echo ' ' BISON $@;
descend = \
- @echo ' ' DESCEND $(1); \
+ +@echo ' ' DESCEND $(1); \
mkdir -p $(OUTPUT)$(1) && \
$(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
endif
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 4e67d52eb3a2..0d7fd8b51544 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -73,6 +73,7 @@ my $ktest_config;
my $version;
my $have_version = 0;
my $machine;
+my $last_machine;
my $ssh_user;
my $tmpdir;
my $builddir;
@@ -108,6 +109,7 @@ my $scp_to_target;
my $scp_to_target_install;
my $power_off;
my $grub_menu;
+my $last_grub_menu;
my $grub_file;
my $grub_number;
my $grub_reboot;
@@ -1538,7 +1540,9 @@ sub run_scp_mod {
sub get_grub2_index {
- return if (defined($grub_number));
+ return if (defined($grub_number) && defined($last_grub_menu) &&
+ $last_grub_menu eq $grub_menu && defined($last_machine) &&
+ $last_machine eq $machine);
doprint "Find grub2 menu ... ";
$grub_number = -1;
@@ -1565,6 +1569,8 @@ sub get_grub2_index {
die "Could not find '$grub_menu' in $grub_file on $machine"
if (!$found);
doprint "$grub_number\n";
+ $last_grub_menu = $grub_menu;
+ $last_machine = $machine;
}
sub get_grub_index {
@@ -1577,7 +1583,9 @@ sub get_grub_index {
if ($reboot_type ne "grub") {
return;
}
- return if (defined($grub_number));
+ return if (defined($grub_number) && defined($last_grub_menu) &&
+ $last_grub_menu eq $grub_menu && defined($last_machine) &&
+ $last_machine eq $machine);
doprint "Find grub menu ... ";
$grub_number = -1;
@@ -1604,6 +1612,8 @@ sub get_grub_index {
die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
if (!$found);
doprint "$grub_number\n";
+ $last_grub_menu = $grub_menu;
+ $last_machine = $machine;
}
sub wait_for_input
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 3cc0ad7ae863..d4abc59ce1d9 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,10 +1,13 @@
TARGETS = breakpoints
+TARGETS += cpu-hotplug
+TARGETS += efivarfs
TARGETS += kcmp
+TARGETS += memory-hotplug
TARGETS += mqueue
+TARGETS += net
+TARGETS += ptrace
+TARGETS += soft-dirty
TARGETS += vm
-TARGETS += cpu-hotplug
-TARGETS += memory-hotplug
-TARGETS += efivarfs
all:
for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
new file mode 100644
index 000000000000..00326629d4af
--- /dev/null
+++ b/tools/testing/selftests/net/.gitignore
@@ -0,0 +1,3 @@
+socket
+psock_fanout
+psock_tpacket
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
new file mode 100644
index 000000000000..750512ba2c88
--- /dev/null
+++ b/tools/testing/selftests/net/Makefile
@@ -0,0 +1,19 @@
+# Makefile for net selftests
+
+CC = $(CROSS_COMPILE)gcc
+CFLAGS = -Wall -O2 -g
+
+CFLAGS += -I../../../../usr/include/
+
+NET_PROGS = socket psock_fanout psock_tpacket
+
+all: $(NET_PROGS)
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+run_tests: all
+ @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]"
+ @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]"
+
+clean:
+ $(RM) $(NET_PROGS)
diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c
new file mode 100644
index 000000000000..57b9c2b7c4ff
--- /dev/null
+++ b/tools/testing/selftests/net/psock_fanout.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Author: Willem de Bruijn (willemb@google.com)
+ *
+ * A basic test of packet socket fanout behavior.
+ *
+ * Control:
+ * - create fanout fails as expected with illegal flag combinations
+ * - join fanout fails as expected with diverging types or flags
+ *
+ * Datapath:
+ * Open a pair of packet sockets and a pair of INET sockets, send a known
+ * number of packets across the two INET sockets and count the number of
+ * packets enqueued onto the two packet sockets.
+ *
+ * The test currently runs for
+ * - PACKET_FANOUT_HASH
+ * - PACKET_FANOUT_HASH with PACKET_FANOUT_FLAG_ROLLOVER
+ * - PACKET_FANOUT_LB
+ * - PACKET_FANOUT_CPU
+ * - PACKET_FANOUT_ROLLOVER
+ *
+ * Todo:
+ * - functionality: PACKET_FANOUT_FLAG_DEFRAG
+ *
+ * License (GPLv2):
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE /* for sched_setaffinity */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/filter.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <poll.h>
+#include <sched.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "psock_lib.h"
+
+#define RING_NUM_FRAMES 20
+
+/* Open a socket in a given fanout mode.
+ * @return -1 if mode is bad, a valid socket otherwise */
+static int sock_fanout_open(uint16_t typeflags, int num_packets)
+{
+ int fd, val;
+
+ fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
+ if (fd < 0) {
+ perror("socket packet");
+ exit(1);
+ }
+
+ /* fanout group ID is always 0: tests whether old groups are deleted */
+ val = ((int) typeflags) << 16;
+ if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) {
+ if (close(fd)) {
+ perror("close packet");
+ exit(1);
+ }
+ return -1;
+ }
+
+ pair_udp_setfilter(fd);
+ return fd;
+}
+
+static char *sock_fanout_open_ring(int fd)
+{
+ struct tpacket_req req = {
+ .tp_block_size = getpagesize(),
+ .tp_frame_size = getpagesize(),
+ .tp_block_nr = RING_NUM_FRAMES,
+ .tp_frame_nr = RING_NUM_FRAMES,
+ };
+ char *ring;
+ int val = TPACKET_V2;
+
+ if (setsockopt(fd, SOL_PACKET, PACKET_VERSION, (void *) &val,
+ sizeof(val))) {
+ perror("packetsock ring setsockopt version");
+ exit(1);
+ }
+ if (setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req,
+ sizeof(req))) {
+ perror("packetsock ring setsockopt");
+ exit(1);
+ }
+
+ ring = mmap(0, req.tp_block_size * req.tp_block_nr,
+ PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (!ring) {
+ fprintf(stderr, "packetsock ring mmap\n");
+ exit(1);
+ }
+
+ return ring;
+}
+
+static int sock_fanout_read_ring(int fd, void *ring)
+{
+ struct tpacket2_hdr *header = ring;
+ int count = 0;
+
+ while (header->tp_status & TP_STATUS_USER && count < RING_NUM_FRAMES) {
+ count++;
+ header = ring + (count * getpagesize());
+ }
+
+ return count;
+}
+
+static int sock_fanout_read(int fds[], char *rings[], const int expect[])
+{
+ int ret[2];
+
+ ret[0] = sock_fanout_read_ring(fds[0], rings[0]);
+ ret[1] = sock_fanout_read_ring(fds[1], rings[1]);
+
+ fprintf(stderr, "info: count=%d,%d, expect=%d,%d\n",
+ ret[0], ret[1], expect[0], expect[1]);
+
+ if ((!(ret[0] == expect[0] && ret[1] == expect[1])) &&
+ (!(ret[0] == expect[1] && ret[1] == expect[0]))) {
+ fprintf(stderr, "ERROR: incorrect queue lengths\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Test illegal mode + flag combination */
+static void test_control_single(void)
+{
+ fprintf(stderr, "test: control single socket\n");
+
+ if (sock_fanout_open(PACKET_FANOUT_ROLLOVER |
+ PACKET_FANOUT_FLAG_ROLLOVER, 0) != -1) {
+ fprintf(stderr, "ERROR: opened socket with dual rollover\n");
+ exit(1);
+ }
+}
+
+/* Test illegal group with different modes or flags */
+static void test_control_group(void)
+{
+ int fds[2];
+
+ fprintf(stderr, "test: control multiple sockets\n");
+
+ fds[0] = sock_fanout_open(PACKET_FANOUT_HASH, 20);
+ if (fds[0] == -1) {
+ fprintf(stderr, "ERROR: failed to open HASH socket\n");
+ exit(1);
+ }
+ if (sock_fanout_open(PACKET_FANOUT_HASH |
+ PACKET_FANOUT_FLAG_DEFRAG, 10) != -1) {
+ fprintf(stderr, "ERROR: joined group with wrong flag defrag\n");
+ exit(1);
+ }
+ if (sock_fanout_open(PACKET_FANOUT_HASH |
+ PACKET_FANOUT_FLAG_ROLLOVER, 10) != -1) {
+ fprintf(stderr, "ERROR: joined group with wrong flag ro\n");
+ exit(1);
+ }
+ if (sock_fanout_open(PACKET_FANOUT_CPU, 10) != -1) {
+ fprintf(stderr, "ERROR: joined group with wrong mode\n");
+ exit(1);
+ }
+ fds[1] = sock_fanout_open(PACKET_FANOUT_HASH, 20);
+ if (fds[1] == -1) {
+ fprintf(stderr, "ERROR: failed to join group\n");
+ exit(1);
+ }
+ if (close(fds[1]) || close(fds[0])) {
+ fprintf(stderr, "ERROR: closing sockets\n");
+ exit(1);
+ }
+}
+
+static int test_datapath(uint16_t typeflags, int port_off,
+ const int expect1[], const int expect2[])
+{
+ const int expect0[] = { 0, 0 };
+ char *rings[2];
+ int fds[2], fds_udp[2][2], ret;
+
+ fprintf(stderr, "test: datapath 0x%hx\n", typeflags);
+
+ fds[0] = sock_fanout_open(typeflags, 20);
+ fds[1] = sock_fanout_open(typeflags, 20);
+ if (fds[0] == -1 || fds[1] == -1) {
+ fprintf(stderr, "ERROR: failed open\n");
+ exit(1);
+ }
+ rings[0] = sock_fanout_open_ring(fds[0]);
+ rings[1] = sock_fanout_open_ring(fds[1]);
+ pair_udp_open(fds_udp[0], PORT_BASE);
+ pair_udp_open(fds_udp[1], PORT_BASE + port_off);
+ sock_fanout_read(fds, rings, expect0);
+
+ /* Send data, but not enough to overflow a queue */
+ pair_udp_send(fds_udp[0], 15);
+ pair_udp_send(fds_udp[1], 5);
+ ret = sock_fanout_read(fds, rings, expect1);
+
+ /* Send more data, overflow the queue */
+ pair_udp_send(fds_udp[0], 15);
+ /* TODO: ensure consistent order between expect1 and expect2 */
+ ret |= sock_fanout_read(fds, rings, expect2);
+
+ if (munmap(rings[1], RING_NUM_FRAMES * getpagesize()) ||
+ munmap(rings[0], RING_NUM_FRAMES * getpagesize())) {
+ fprintf(stderr, "close rings\n");
+ exit(1);
+ }
+ if (close(fds_udp[1][1]) || close(fds_udp[1][0]) ||
+ close(fds_udp[0][1]) || close(fds_udp[0][0]) ||
+ close(fds[1]) || close(fds[0])) {
+ fprintf(stderr, "close datapath\n");
+ exit(1);
+ }
+
+ return ret;
+}
+
+static int set_cpuaffinity(int cpuid)
+{
+ cpu_set_t mask;
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpuid, &mask);
+ if (sched_setaffinity(0, sizeof(mask), &mask)) {
+ if (errno != EINVAL) {
+ fprintf(stderr, "setaffinity %d\n", cpuid);
+ exit(1);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const int expect_hash[2][2] = { { 15, 5 }, { 20, 5 } };
+ const int expect_hash_rb[2][2] = { { 15, 5 }, { 20, 15 } };
+ const int expect_lb[2][2] = { { 10, 10 }, { 18, 17 } };
+ const int expect_rb[2][2] = { { 20, 0 }, { 20, 15 } };
+ const int expect_cpu0[2][2] = { { 20, 0 }, { 20, 0 } };
+ const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } };
+ int port_off = 2, tries = 5, ret;
+
+ test_control_single();
+ test_control_group();
+
+ /* find a set of ports that do not collide onto the same socket */
+ ret = test_datapath(PACKET_FANOUT_HASH, port_off,
+ expect_hash[0], expect_hash[1]);
+ while (ret && tries--) {
+ fprintf(stderr, "info: trying alternate ports (%d)\n", tries);
+ ret = test_datapath(PACKET_FANOUT_HASH, ++port_off,
+ expect_hash[0], expect_hash[1]);
+ }
+
+ ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER,
+ port_off, expect_hash_rb[0], expect_hash_rb[1]);
+ ret |= test_datapath(PACKET_FANOUT_LB,
+ port_off, expect_lb[0], expect_lb[1]);
+ ret |= test_datapath(PACKET_FANOUT_ROLLOVER,
+ port_off, expect_rb[0], expect_rb[1]);
+
+ set_cpuaffinity(0);
+ ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
+ expect_cpu0[0], expect_cpu0[1]);
+ if (!set_cpuaffinity(1))
+ /* TODO: test that choice alternates with previous */
+ ret |= test_datapath(PACKET_FANOUT_CPU, port_off,
+ expect_cpu1[0], expect_cpu1[1]);
+
+ if (ret)
+ return 1;
+
+ printf("OK. All tests passed\n");
+ return 0;
+}
diff --git a/tools/testing/selftests/net/psock_lib.h b/tools/testing/selftests/net/psock_lib.h
new file mode 100644
index 000000000000..37da54ac85a9
--- /dev/null
+++ b/tools/testing/selftests/net/psock_lib.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013 Google Inc.
+ * Author: Willem de Bruijn <willemb@google.com>
+ * Daniel Borkmann <dborkman@redhat.com>
+ *
+ * License (GPLv2):
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PSOCK_LIB_H
+#define PSOCK_LIB_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#define DATA_LEN 100
+#define DATA_CHAR 'a'
+
+#define PORT_BASE 8000
+
+#ifndef __maybe_unused
+# define __maybe_unused __attribute__ ((__unused__))
+#endif
+
+static __maybe_unused void pair_udp_setfilter(int fd)
+{
+ struct sock_filter bpf_filter[] = {
+ { 0x80, 0, 0, 0x00000000 }, /* LD pktlen */
+ { 0x35, 0, 5, DATA_LEN }, /* JGE DATA_LEN [f goto nomatch]*/
+ { 0x30, 0, 0, 0x00000050 }, /* LD ip[80] */
+ { 0x15, 0, 3, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/
+ { 0x30, 0, 0, 0x00000051 }, /* LD ip[81] */
+ { 0x15, 0, 1, DATA_CHAR }, /* JEQ DATA_CHAR [f goto nomatch]*/
+ { 0x06, 0, 0, 0x00000060 }, /* RET match */
+ { 0x06, 0, 0, 0x00000000 }, /* RET no match */
+ };
+ struct sock_fprog bpf_prog;
+
+ bpf_prog.filter = bpf_filter;
+ bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog,
+ sizeof(bpf_prog))) {
+ perror("setsockopt SO_ATTACH_FILTER");
+ exit(1);
+ }
+}
+
+static __maybe_unused void pair_udp_open(int fds[], uint16_t port)
+{
+ struct sockaddr_in saddr, daddr;
+
+ fds[0] = socket(PF_INET, SOCK_DGRAM, 0);
+ fds[1] = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ fprintf(stderr, "ERROR: socket dgram\n");
+ exit(1);
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(port);
+ saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ memset(&daddr, 0, sizeof(daddr));
+ daddr.sin_family = AF_INET;
+ daddr.sin_port = htons(port + 1);
+ daddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ /* must bind both to get consistent hash result */
+ if (bind(fds[1], (void *) &daddr, sizeof(daddr))) {
+ perror("bind");
+ exit(1);
+ }
+ if (bind(fds[0], (void *) &saddr, sizeof(saddr))) {
+ perror("bind");
+ exit(1);
+ }
+ if (connect(fds[0], (void *) &daddr, sizeof(daddr))) {
+ perror("connect");
+ exit(1);
+ }
+}
+
+static __maybe_unused void pair_udp_send(int fds[], int num)
+{
+ char buf[DATA_LEN], rbuf[DATA_LEN];
+
+ memset(buf, DATA_CHAR, sizeof(buf));
+ while (num--) {
+ /* Should really handle EINTR and EAGAIN */
+ if (write(fds[0], buf, sizeof(buf)) != sizeof(buf)) {
+ fprintf(stderr, "ERROR: send failed left=%d\n", num);
+ exit(1);
+ }
+ if (read(fds[1], rbuf, sizeof(rbuf)) != sizeof(rbuf)) {
+ fprintf(stderr, "ERROR: recv failed left=%d\n", num);
+ exit(1);
+ }
+ if (memcmp(buf, rbuf, sizeof(buf))) {
+ fprintf(stderr, "ERROR: data failed left=%d\n", num);
+ exit(1);
+ }
+ }
+}
+
+static __maybe_unused void pair_udp_close(int fds[])
+{
+ close(fds[0]);
+ close(fds[1]);
+}
+
+#endif /* PSOCK_LIB_H */
diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c
new file mode 100644
index 000000000000..c41b58640a05
--- /dev/null
+++ b/tools/testing/selftests/net/psock_tpacket.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright 2013 Red Hat, Inc.
+ * Author: Daniel Borkmann <dborkman@redhat.com>
+ *
+ * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior.
+ *
+ * Control:
+ * Test the setup of the TPACKET socket with different patterns that are
+ * known to fail (TODO) resp. succeed (OK).
+ *
+ * Datapath:
+ * Open a pair of packet sockets and send resp. receive an a priori known
+ * packet pattern accross the sockets and check if it was received resp.
+ * sent correctly. Fanout in combination with RX_RING is currently not
+ * tested here.
+ *
+ * The test currently runs for
+ * - TPACKET_V1: RX_RING, TX_RING
+ * - TPACKET_V2: RX_RING, TX_RING
+ * - TPACKET_V3: RX_RING
+ *
+ * License (GPLv2):
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <bits/wordsize.h>
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <net/if.h>
+#include <inttypes.h>
+#include <poll.h>
+
+#include "psock_lib.h"
+
+#ifndef bug_on
+# define bug_on(cond) assert(!(cond))
+#endif
+
+#ifndef __aligned_tpacket
+# define __aligned_tpacket __attribute__((aligned(TPACKET_ALIGNMENT)))
+#endif
+
+#ifndef __align_tpacket
+# define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x))))
+#endif
+
+#define BLOCK_STATUS(x) ((x)->h1.block_status)
+#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts)
+#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt)
+#define BLOCK_LEN(x) ((x)->h1.blk_len)
+#define BLOCK_SNUM(x) ((x)->h1.seq_num)
+#define BLOCK_O2PRIV(x) ((x)->offset_to_priv)
+#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x)))
+#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc)))
+#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
+#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri)))
+
+#define NUM_PACKETS 100
+
+struct ring {
+ struct iovec *rd;
+ uint8_t *mm_space;
+ size_t mm_len, rd_len;
+ struct sockaddr_ll ll;
+ void (*walk)(int sock, struct ring *ring);
+ int type, rd_num, flen, version;
+ union {
+ struct tpacket_req req;
+ struct tpacket_req3 req3;
+ };
+};
+
+struct block_desc {
+ uint32_t version;
+ uint32_t offset_to_priv;
+ struct tpacket_hdr_v1 h1;
+};
+
+union frame_map {
+ struct {
+ struct tpacket_hdr tp_h __aligned_tpacket;
+ struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket_hdr));
+ } *v1;
+ struct {
+ struct tpacket2_hdr tp_h __aligned_tpacket;
+ struct sockaddr_ll s_ll __align_tpacket(sizeof(struct tpacket2_hdr));
+ } *v2;
+ void *raw;
+};
+
+static unsigned int total_packets, total_bytes;
+
+static int pfsocket(int ver)
+{
+ int ret, sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (sock == -1) {
+ perror("socket");
+ exit(1);
+ }
+
+ ret = setsockopt(sock, SOL_PACKET, PACKET_VERSION, &ver, sizeof(ver));
+ if (ret == -1) {
+ perror("setsockopt");
+ exit(1);
+ }
+
+ return sock;
+}
+
+static void status_bar_update(void)
+{
+ if (total_packets % 10 == 0) {
+ fprintf(stderr, ".");
+ fflush(stderr);
+ }
+}
+
+static void test_payload(void *pay, size_t len)
+{
+ struct ethhdr *eth = pay;
+
+ if (len < sizeof(struct ethhdr)) {
+ fprintf(stderr, "test_payload: packet too "
+ "small: %zu bytes!\n", len);
+ exit(1);
+ }
+
+ if (eth->h_proto != htons(ETH_P_IP)) {
+ fprintf(stderr, "test_payload: wrong ethernet "
+ "type: 0x%x!\n", ntohs(eth->h_proto));
+ exit(1);
+ }
+}
+
+static void create_payload(void *pay, size_t *len)
+{
+ int i;
+ struct ethhdr *eth = pay;
+ struct iphdr *ip = pay + sizeof(*eth);
+
+ /* Lets create some broken crap, that still passes
+ * our BPF filter.
+ */
+
+ *len = DATA_LEN + 42;
+
+ memset(pay, 0xff, ETH_ALEN * 2);
+ eth->h_proto = htons(ETH_P_IP);
+
+ for (i = 0; i < sizeof(*ip); ++i)
+ ((uint8_t *) pay)[i + sizeof(*eth)] = (uint8_t) rand();
+
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->protocol = 0x11;
+ ip->frag_off = 0;
+ ip->ttl = 64;
+ ip->tot_len = htons((uint16_t) *len - sizeof(*eth));
+
+ ip->saddr = htonl(INADDR_LOOPBACK);
+ ip->daddr = htonl(INADDR_LOOPBACK);
+
+ memset(pay + sizeof(*eth) + sizeof(*ip),
+ DATA_CHAR, DATA_LEN);
+}
+
+static inline int __v1_rx_kernel_ready(struct tpacket_hdr *hdr)
+{
+ return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);
+}
+
+static inline void __v1_rx_user_ready(struct tpacket_hdr *hdr)
+{
+ hdr->tp_status = TP_STATUS_KERNEL;
+ __sync_synchronize();
+}
+
+static inline int __v2_rx_kernel_ready(struct tpacket2_hdr *hdr)
+{
+ return ((hdr->tp_status & TP_STATUS_USER) == TP_STATUS_USER);
+}
+
+static inline void __v2_rx_user_ready(struct tpacket2_hdr *hdr)
+{
+ hdr->tp_status = TP_STATUS_KERNEL;
+ __sync_synchronize();
+}
+
+static inline int __v1_v2_rx_kernel_ready(void *base, int version)
+{
+ switch (version) {
+ case TPACKET_V1:
+ return __v1_rx_kernel_ready(base);
+ case TPACKET_V2:
+ return __v2_rx_kernel_ready(base);
+ default:
+ bug_on(1);
+ return 0;
+ }
+}
+
+static inline void __v1_v2_rx_user_ready(void *base, int version)
+{
+ switch (version) {
+ case TPACKET_V1:
+ __v1_rx_user_ready(base);
+ break;
+ case TPACKET_V2:
+ __v2_rx_user_ready(base);
+ break;
+ }
+}
+
+static void walk_v1_v2_rx(int sock, struct ring *ring)
+{
+ struct pollfd pfd;
+ int udp_sock[2];
+ union frame_map ppd;
+ unsigned int frame_num = 0;
+
+ bug_on(ring->type != PACKET_RX_RING);
+
+ pair_udp_open(udp_sock, PORT_BASE);
+ pair_udp_setfilter(sock);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ pair_udp_send(udp_sock, NUM_PACKETS);
+
+ while (total_packets < NUM_PACKETS * 2) {
+ while (__v1_v2_rx_kernel_ready(ring->rd[frame_num].iov_base,
+ ring->version)) {
+ ppd.raw = ring->rd[frame_num].iov_base;
+
+ switch (ring->version) {
+ case TPACKET_V1:
+ test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac,
+ ppd.v1->tp_h.tp_snaplen);
+ total_bytes += ppd.v1->tp_h.tp_snaplen;
+ break;
+
+ case TPACKET_V2:
+ test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac,
+ ppd.v2->tp_h.tp_snaplen);
+ total_bytes += ppd.v2->tp_h.tp_snaplen;
+ break;
+ }
+
+ status_bar_update();
+ total_packets++;
+
+ __v1_v2_rx_user_ready(ppd.raw, ring->version);
+
+ frame_num = (frame_num + 1) % ring->rd_num;
+ }
+
+ poll(&pfd, 1, 1);
+ }
+
+ pair_udp_close(udp_sock);
+
+ if (total_packets != 2 * NUM_PACKETS) {
+ fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n",
+ ring->version, total_packets, NUM_PACKETS);
+ exit(1);
+ }
+
+ fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1);
+}
+
+static inline int __v1_tx_kernel_ready(struct tpacket_hdr *hdr)
+{
+ return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
+}
+
+static inline void __v1_tx_user_ready(struct tpacket_hdr *hdr)
+{
+ hdr->tp_status = TP_STATUS_SEND_REQUEST;
+ __sync_synchronize();
+}
+
+static inline int __v2_tx_kernel_ready(struct tpacket2_hdr *hdr)
+{
+ return !(hdr->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING));
+}
+
+static inline void __v2_tx_user_ready(struct tpacket2_hdr *hdr)
+{
+ hdr->tp_status = TP_STATUS_SEND_REQUEST;
+ __sync_synchronize();
+}
+
+static inline int __v1_v2_tx_kernel_ready(void *base, int version)
+{
+ switch (version) {
+ case TPACKET_V1:
+ return __v1_tx_kernel_ready(base);
+ case TPACKET_V2:
+ return __v2_tx_kernel_ready(base);
+ default:
+ bug_on(1);
+ return 0;
+ }
+}
+
+static inline void __v1_v2_tx_user_ready(void *base, int version)
+{
+ switch (version) {
+ case TPACKET_V1:
+ __v1_tx_user_ready(base);
+ break;
+ case TPACKET_V2:
+ __v2_tx_user_ready(base);
+ break;
+ }
+}
+
+static void __v1_v2_set_packet_loss_discard(int sock)
+{
+ int ret, discard = 1;
+
+ ret = setsockopt(sock, SOL_PACKET, PACKET_LOSS, (void *) &discard,
+ sizeof(discard));
+ if (ret == -1) {
+ perror("setsockopt");
+ exit(1);
+ }
+}
+
+static void walk_v1_v2_tx(int sock, struct ring *ring)
+{
+ struct pollfd pfd;
+ int rcv_sock, ret;
+ size_t packet_len;
+ union frame_map ppd;
+ char packet[1024];
+ unsigned int frame_num = 0, got = 0;
+ struct sockaddr_ll ll = {
+ .sll_family = PF_PACKET,
+ .sll_halen = ETH_ALEN,
+ };
+
+ bug_on(ring->type != PACKET_TX_RING);
+ bug_on(ring->rd_num < NUM_PACKETS);
+
+ rcv_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (rcv_sock == -1) {
+ perror("socket");
+ exit(1);
+ }
+
+ pair_udp_setfilter(rcv_sock);
+
+ ll.sll_ifindex = if_nametoindex("lo");
+ ret = bind(rcv_sock, (struct sockaddr *) &ll, sizeof(ll));
+ if (ret == -1) {
+ perror("bind");
+ exit(1);
+ }
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT | POLLERR;
+ pfd.revents = 0;
+
+ total_packets = NUM_PACKETS;
+ create_payload(packet, &packet_len);
+
+ while (total_packets > 0) {
+ while (__v1_v2_tx_kernel_ready(ring->rd[frame_num].iov_base,
+ ring->version) &&
+ total_packets > 0) {
+ ppd.raw = ring->rd[frame_num].iov_base;
+
+ switch (ring->version) {
+ case TPACKET_V1:
+ ppd.v1->tp_h.tp_snaplen = packet_len;
+ ppd.v1->tp_h.tp_len = packet_len;
+
+ memcpy((uint8_t *) ppd.raw + TPACKET_HDRLEN -
+ sizeof(struct sockaddr_ll), packet,
+ packet_len);
+ total_bytes += ppd.v1->tp_h.tp_snaplen;
+ break;
+
+ case TPACKET_V2:
+ ppd.v2->tp_h.tp_snaplen = packet_len;
+ ppd.v2->tp_h.tp_len = packet_len;
+
+ memcpy((uint8_t *) ppd.raw + TPACKET2_HDRLEN -
+ sizeof(struct sockaddr_ll), packet,
+ packet_len);
+ total_bytes += ppd.v2->tp_h.tp_snaplen;
+ break;
+ }
+
+ status_bar_update();
+ total_packets--;
+
+ __v1_v2_tx_user_ready(ppd.raw, ring->version);
+
+ frame_num = (frame_num + 1) % ring->rd_num;
+ }
+
+ poll(&pfd, 1, 1);
+ }
+
+ bug_on(total_packets != 0);
+
+ ret = sendto(sock, NULL, 0, 0, NULL, 0);
+ if (ret == -1) {
+ perror("sendto");
+ exit(1);
+ }
+
+ while ((ret = recvfrom(rcv_sock, packet, sizeof(packet),
+ 0, NULL, NULL)) > 0 &&
+ total_packets < NUM_PACKETS) {
+ got += ret;
+ test_payload(packet, ret);
+
+ status_bar_update();
+ total_packets++;
+ }
+
+ close(rcv_sock);
+
+ if (total_packets != NUM_PACKETS) {
+ fprintf(stderr, "walk_v%d_rx: received %u out of %u pkts\n",
+ ring->version, total_packets, NUM_PACKETS);
+ exit(1);
+ }
+
+ fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, got);
+}
+
+static void walk_v1_v2(int sock, struct ring *ring)
+{
+ if (ring->type == PACKET_RX_RING)
+ walk_v1_v2_rx(sock, ring);
+ else
+ walk_v1_v2_tx(sock, ring);
+}
+
+static uint64_t __v3_prev_block_seq_num = 0;
+
+void __v3_test_block_seq_num(struct block_desc *pbd)
+{
+ if (__v3_prev_block_seq_num + 1 != BLOCK_SNUM(pbd)) {
+ fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected "
+ "seq:%"PRIu64" != actual seq:%"PRIu64"\n",
+ __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1,
+ (uint64_t) BLOCK_SNUM(pbd));
+ exit(1);
+ }
+
+ __v3_prev_block_seq_num = BLOCK_SNUM(pbd);
+}
+
+static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
+{
+ if (BLOCK_NUM_PKTS(pbd)) {
+ if (bytes != BLOCK_LEN(pbd)) {
+ fprintf(stderr, "\nblock:%u with %upackets, expected "
+ "len:%u != actual len:%u\n", block_num,
+ BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd));
+ exit(1);
+ }
+ } else {
+ if (BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(13)) {
+ fprintf(stderr, "\nblock:%u, expected len:%lu != "
+ "actual len:%u\n", block_num, BLOCK_HDR_LEN,
+ BLOCK_LEN(pbd));
+ exit(1);
+ }
+ }
+}
+
+static void __v3_test_block_header(struct block_desc *pbd, const int block_num)
+{
+ uint32_t block_status = BLOCK_STATUS(pbd);
+
+ if ((block_status & TP_STATUS_USER) == 0) {
+ fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num);
+ exit(1);
+ }
+
+ __v3_test_block_seq_num(pbd);
+}
+
+static void __v3_walk_block(struct block_desc *pbd, const int block_num)
+{
+ int num_pkts = BLOCK_NUM_PKTS(pbd), i;
+ unsigned long bytes = 0;
+ unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(13);
+ struct tpacket3_hdr *ppd;
+
+ __v3_test_block_header(pbd, block_num);
+
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd));
+ for (i = 0; i < num_pkts; ++i) {
+ bytes += ppd->tp_snaplen;
+
+ if (ppd->tp_next_offset)
+ bytes_with_padding += ppd->tp_next_offset;
+ else
+ bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
+
+ test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen);
+
+ status_bar_update();
+ total_packets++;
+
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset);
+ __sync_synchronize();
+ }
+
+ __v3_test_block_len(pbd, bytes_with_padding, block_num);
+ total_bytes += bytes;
+}
+
+void __v3_flush_block(struct block_desc *pbd)
+{
+ BLOCK_STATUS(pbd) = TP_STATUS_KERNEL;
+ __sync_synchronize();
+}
+
+static void walk_v3_rx(int sock, struct ring *ring)
+{
+ unsigned int block_num = 0;
+ struct pollfd pfd;
+ struct block_desc *pbd;
+ int udp_sock[2];
+
+ bug_on(ring->type != PACKET_RX_RING);
+
+ pair_udp_open(udp_sock, PORT_BASE);
+ pair_udp_setfilter(sock);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLIN | POLLERR;
+ pfd.revents = 0;
+
+ pair_udp_send(udp_sock, NUM_PACKETS);
+
+ while (total_packets < NUM_PACKETS * 2) {
+ pbd = (struct block_desc *) ring->rd[block_num].iov_base;
+
+ while ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0)
+ poll(&pfd, 1, 1);
+
+ __v3_walk_block(pbd, block_num);
+ __v3_flush_block(pbd);
+
+ block_num = (block_num + 1) % ring->rd_num;
+ }
+
+ pair_udp_close(udp_sock);
+
+ if (total_packets != 2 * NUM_PACKETS) {
+ fprintf(stderr, "walk_v3_rx: received %u out of %u pkts\n",
+ total_packets, NUM_PACKETS);
+ exit(1);
+ }
+
+ fprintf(stderr, " %u pkts (%u bytes)", NUM_PACKETS, total_bytes >> 1);
+}
+
+static void walk_v3(int sock, struct ring *ring)
+{
+ if (ring->type == PACKET_RX_RING)
+ walk_v3_rx(sock, ring);
+ else
+ bug_on(1);
+}
+
+static void __v1_v2_fill(struct ring *ring, unsigned int blocks)
+{
+ ring->req.tp_block_size = getpagesize() << 2;
+ ring->req.tp_frame_size = TPACKET_ALIGNMENT << 7;
+ ring->req.tp_block_nr = blocks;
+
+ ring->req.tp_frame_nr = ring->req.tp_block_size /
+ ring->req.tp_frame_size *
+ ring->req.tp_block_nr;
+
+ ring->mm_len = ring->req.tp_block_size * ring->req.tp_block_nr;
+ ring->walk = walk_v1_v2;
+ ring->rd_num = ring->req.tp_frame_nr;
+ ring->flen = ring->req.tp_frame_size;
+}
+
+static void __v3_fill(struct ring *ring, unsigned int blocks)
+{
+ ring->req3.tp_retire_blk_tov = 64;
+ ring->req3.tp_sizeof_priv = 13;
+ ring->req3.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH;
+
+ ring->req3.tp_block_size = getpagesize() << 2;
+ ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7;
+ ring->req3.tp_block_nr = blocks;
+
+ ring->req3.tp_frame_nr = ring->req3.tp_block_size /
+ ring->req3.tp_frame_size *
+ ring->req3.tp_block_nr;
+
+ ring->mm_len = ring->req3.tp_block_size * ring->req3.tp_block_nr;
+ ring->walk = walk_v3;
+ ring->rd_num = ring->req3.tp_block_nr;
+ ring->flen = ring->req3.tp_block_size;
+}
+
+static void setup_ring(int sock, struct ring *ring, int version, int type)
+{
+ int ret = 0;
+ unsigned int blocks = 256;
+
+ ring->type = type;
+ ring->version = version;
+
+ switch (version) {
+ case TPACKET_V1:
+ case TPACKET_V2:
+ if (type == PACKET_TX_RING)
+ __v1_v2_set_packet_loss_discard(sock);
+ __v1_v2_fill(ring, blocks);
+ ret = setsockopt(sock, SOL_PACKET, type, &ring->req,
+ sizeof(ring->req));
+ break;
+
+ case TPACKET_V3:
+ __v3_fill(ring, blocks);
+ ret = setsockopt(sock, SOL_PACKET, type, &ring->req3,
+ sizeof(ring->req3));
+ break;
+ }
+
+ if (ret == -1) {
+ perror("setsockopt");
+ exit(1);
+ }
+
+ ring->rd_len = ring->rd_num * sizeof(*ring->rd);
+ ring->rd = malloc(ring->rd_len);
+ if (ring->rd == NULL) {
+ perror("malloc");
+ exit(1);
+ }
+
+ total_packets = 0;
+ total_bytes = 0;
+}
+
+static void mmap_ring(int sock, struct ring *ring)
+{
+ int i;
+
+ ring->mm_space = mmap(0, ring->mm_len, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_LOCKED | MAP_POPULATE, sock, 0);
+ if (ring->mm_space == MAP_FAILED) {
+ perror("mmap");
+ exit(1);
+ }
+
+ memset(ring->rd, 0, ring->rd_len);
+ for (i = 0; i < ring->rd_num; ++i) {
+ ring->rd[i].iov_base = ring->mm_space + (i * ring->flen);
+ ring->rd[i].iov_len = ring->flen;
+ }
+}
+
+static void bind_ring(int sock, struct ring *ring)
+{
+ int ret;
+
+ ring->ll.sll_family = PF_PACKET;
+ ring->ll.sll_protocol = htons(ETH_P_ALL);
+ ring->ll.sll_ifindex = if_nametoindex("lo");
+ ring->ll.sll_hatype = 0;
+ ring->ll.sll_pkttype = 0;
+ ring->ll.sll_halen = 0;
+
+ ret = bind(sock, (struct sockaddr *) &ring->ll, sizeof(ring->ll));
+ if (ret == -1) {
+ perror("bind");
+ exit(1);
+ }
+}
+
+static void walk_ring(int sock, struct ring *ring)
+{
+ ring->walk(sock, ring);
+}
+
+static void unmap_ring(int sock, struct ring *ring)
+{
+ munmap(ring->mm_space, ring->mm_len);
+ free(ring->rd);
+}
+
+static int test_kernel_bit_width(void)
+{
+ char in[512], *ptr;
+ int num = 0, fd;
+ ssize_t ret;
+
+ fd = open("/proc/kallsyms", O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ exit(1);
+ }
+
+ ret = read(fd, in, sizeof(in));
+ if (ret <= 0) {
+ perror("read");
+ exit(1);
+ }
+
+ close(fd);
+
+ ptr = in;
+ while(!isspace(*ptr)) {
+ num++;
+ ptr++;
+ }
+
+ return num * 4;
+}
+
+static int test_user_bit_width(void)
+{
+ return __WORDSIZE;
+}
+
+static const char *tpacket_str[] = {
+ [TPACKET_V1] = "TPACKET_V1",
+ [TPACKET_V2] = "TPACKET_V2",
+ [TPACKET_V3] = "TPACKET_V3",
+};
+
+static const char *type_str[] = {
+ [PACKET_RX_RING] = "PACKET_RX_RING",
+ [PACKET_TX_RING] = "PACKET_TX_RING",
+};
+
+static int test_tpacket(int version, int type)
+{
+ int sock;
+ struct ring ring;
+
+ fprintf(stderr, "test: %s with %s ", tpacket_str[version],
+ type_str[type]);
+ fflush(stderr);
+
+ if (version == TPACKET_V1 &&
+ test_kernel_bit_width() != test_user_bit_width()) {
+ fprintf(stderr, "test: skip %s %s since user and kernel "
+ "space have different bit width\n",
+ tpacket_str[version], type_str[type]);
+ return 0;
+ }
+
+ sock = pfsocket(version);
+ memset(&ring, 0, sizeof(ring));
+ setup_ring(sock, &ring, version, type);
+ mmap_ring(sock, &ring);
+ bind_ring(sock, &ring);
+ walk_ring(sock, &ring);
+ unmap_ring(sock, &ring);
+ close(sock);
+
+ fprintf(stderr, "\n");
+ return 0;
+}
+
+int main(void)
+{
+ int ret = 0;
+
+ ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING);
+ ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING);
+
+ ret |= test_tpacket(TPACKET_V2, PACKET_RX_RING);
+ ret |= test_tpacket(TPACKET_V2, PACKET_TX_RING);
+
+ ret |= test_tpacket(TPACKET_V3, PACKET_RX_RING);
+
+ if (ret)
+ return 1;
+
+ printf("OK. All tests passed\n");
+ return 0;
+}
diff --git a/tools/testing/selftests/net/run_afpackettests b/tools/testing/selftests/net/run_afpackettests
new file mode 100644
index 000000000000..5246e782d6e8
--- /dev/null
+++ b/tools/testing/selftests/net/run_afpackettests
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+if [ $(id -u) != 0 ]; then
+ echo $msg must be run as root >&2
+ exit 0
+fi
+
+echo "--------------------"
+echo "running psock_fanout test"
+echo "--------------------"
+./psock_fanout
+if [ $? -ne 0 ]; then
+ echo "[FAIL]"
+else
+ echo "[PASS]"
+fi
+
+echo "--------------------"
+echo "running psock_tpacket test"
+echo "--------------------"
+./psock_tpacket
+if [ $? -ne 0 ]; then
+ echo "[FAIL]"
+else
+ echo "[PASS]"
+fi
diff --git a/tools/testing/selftests/net/run_netsocktests b/tools/testing/selftests/net/run_netsocktests
new file mode 100644
index 000000000000..c09a682df56a
--- /dev/null
+++ b/tools/testing/selftests/net/run_netsocktests
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+echo "--------------------"
+echo "running socket test"
+echo "--------------------"
+./socket
+if [ $? -ne 0 ]; then
+ echo "[FAIL]"
+else
+ echo "[PASS]"
+fi
+
diff --git a/tools/testing/selftests/net/socket.c b/tools/testing/selftests/net/socket.c
new file mode 100644
index 000000000000..0f227f2f9be9
--- /dev/null
+++ b/tools/testing/selftests/net/socket.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+struct socket_testcase {
+ int domain;
+ int type;
+ int protocol;
+
+ /* 0 = valid file descriptor
+ * -foo = error foo
+ */
+ int expect;
+
+ /* If non-zero, accept EAFNOSUPPORT to handle the case
+ * of the protocol not being configured into the kernel.
+ */
+ int nosupport_ok;
+};
+
+static struct socket_testcase tests[] = {
+ { AF_MAX, 0, 0, -EAFNOSUPPORT, 0 },
+ { AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 1 },
+ { AF_INET, SOCK_DGRAM, IPPROTO_TCP, -EPROTONOSUPPORT, 1 },
+ { AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 1 },
+ { AF_INET, SOCK_STREAM, IPPROTO_UDP, -EPROTONOSUPPORT, 1 },
+};
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#define ERR_STRING_SZ 64
+
+static int run_tests(void)
+{
+ char err_string1[ERR_STRING_SZ];
+ char err_string2[ERR_STRING_SZ];
+ int i, err;
+
+ err = 0;
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ struct socket_testcase *s = &tests[i];
+ int fd;
+
+ fd = socket(s->domain, s->type, s->protocol);
+ if (fd < 0) {
+ if (s->nosupport_ok &&
+ errno == EAFNOSUPPORT)
+ continue;
+
+ if (s->expect < 0 &&
+ errno == -s->expect)
+ continue;
+
+ strerror_r(-s->expect, err_string1, ERR_STRING_SZ);
+ strerror_r(errno, err_string2, ERR_STRING_SZ);
+
+ fprintf(stderr, "socket(%d, %d, %d) expected "
+ "err (%s) got (%s)\n",
+ s->domain, s->type, s->protocol,
+ err_string1, err_string2);
+
+ err = -1;
+ break;
+ } else {
+ close(fd);
+
+ if (s->expect < 0) {
+ strerror_r(errno, err_string1, ERR_STRING_SZ);
+
+ fprintf(stderr, "socket(%d, %d, %d) expected "
+ "success got err (%s)\n",
+ s->domain, s->type, s->protocol,
+ err_string1);
+
+ err = -1;
+ break;
+ }
+ }
+ }
+
+ return err;
+}
+
+int main(void)
+{
+ int err = run_tests();
+
+ return err;
+}
diff --git a/tools/testing/selftests/ptrace/Makefile b/tools/testing/selftests/ptrace/Makefile
new file mode 100644
index 000000000000..47ae2d385ce8
--- /dev/null
+++ b/tools/testing/selftests/ptrace/Makefile
@@ -0,0 +1,10 @@
+CFLAGS += -iquote../../../../include/uapi -Wall
+peeksiginfo: peeksiginfo.c
+
+all: peeksiginfo
+
+clean:
+ rm -f peeksiginfo
+
+run_tests: all
+ @./peeksiginfo || echo "peeksiginfo selftests: [FAIL]"
diff --git a/tools/testing/selftests/ptrace/peeksiginfo.c b/tools/testing/selftests/ptrace/peeksiginfo.c
new file mode 100644
index 000000000000..d46558b1f58d
--- /dev/null
+++ b/tools/testing/selftests/ptrace/peeksiginfo.c
@@ -0,0 +1,214 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/types.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <sys/user.h>
+#include <sys/mman.h>
+
+#include "linux/ptrace.h"
+
+static int sys_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *uinfo)
+{
+ return syscall(SYS_rt_sigqueueinfo, tgid, sig, uinfo);
+}
+
+static int sys_rt_tgsigqueueinfo(pid_t tgid, pid_t tid,
+ int sig, siginfo_t *uinfo)
+{
+ return syscall(SYS_rt_tgsigqueueinfo, tgid, tid, sig, uinfo);
+}
+
+static int sys_ptrace(int request, pid_t pid, void *addr, void *data)
+{
+ return syscall(SYS_ptrace, request, pid, addr, data);
+}
+
+#define SIGNR 10
+#define TEST_SICODE_PRIV -1
+#define TEST_SICODE_SHARE -2
+
+#define err(fmt, ...) \
+ fprintf(stderr, \
+ "Error (%s:%d): " fmt, \
+ __FILE__, __LINE__, ##__VA_ARGS__)
+
+static int check_error_paths(pid_t child)
+{
+ struct ptrace_peeksiginfo_args arg;
+ int ret, exit_code = -1;
+ void *addr_rw, *addr_ro;
+
+ /*
+ * Allocate two contiguous pages. The first one is for read-write,
+ * another is for read-only.
+ */
+ addr_rw = mmap(NULL, 2 * PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (addr_rw == MAP_FAILED) {
+ err("mmap() failed: %m\n");
+ return 1;
+ }
+
+ addr_ro = mmap(addr_rw + PAGE_SIZE, PAGE_SIZE, PROT_READ,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if (addr_ro == MAP_FAILED) {
+ err("mmap() failed: %m\n");
+ goto out;
+ }
+
+ arg.nr = SIGNR;
+ arg.off = 0;
+
+ /* Unsupported flags */
+ arg.flags = ~0;
+ ret = sys_ptrace(PTRACE_PEEKSIGINFO, child, &arg, addr_rw);
+ if (ret != -1 || errno != EINVAL) {
+ err("sys_ptrace() returns %d (expected -1),"
+ " errno %d (expected %d): %m\n",
+ ret, errno, EINVAL);
+ goto out;
+ }
+ arg.flags = 0;
+
+ /* A part of the buffer is read-only */
+ ret = sys_ptrace(PTRACE_PEEKSIGINFO, child, &arg,
+ addr_ro - sizeof(siginfo_t) * 2);
+ if (ret != 2) {
+ err("sys_ptrace() returns %d (expected 2): %m\n", ret);
+ goto out;
+ }
+
+ /* Read-only buffer */
+ ret = sys_ptrace(PTRACE_PEEKSIGINFO, child, &arg, addr_ro);
+ if (ret != -1 && errno != EFAULT) {
+ err("sys_ptrace() returns %d (expected -1),"
+ " errno %d (expected %d): %m\n",
+ ret, errno, EFAULT);
+ goto out;
+ }
+
+ exit_code = 0;
+out:
+ munmap(addr_rw, 2 * PAGE_SIZE);
+ return exit_code;
+}
+
+int check_direct_path(pid_t child, int shared, int nr)
+{
+ struct ptrace_peeksiginfo_args arg = {.flags = 0, .nr = nr, .off = 0};
+ int i, j, ret, exit_code = -1;
+ siginfo_t siginfo[SIGNR];
+ int si_code;
+
+ if (shared == 1) {
+ arg.flags = PTRACE_PEEKSIGINFO_SHARED;
+ si_code = TEST_SICODE_SHARE;
+ } else {
+ arg.flags = 0;
+ si_code = TEST_SICODE_PRIV;
+ }
+
+ for (i = 0; i < SIGNR; ) {
+ arg.off = i;
+ ret = sys_ptrace(PTRACE_PEEKSIGINFO, child, &arg, siginfo);
+ if (ret == -1) {
+ err("ptrace() failed: %m\n");
+ goto out;
+ }
+
+ if (ret == 0)
+ break;
+
+ for (j = 0; j < ret; j++, i++) {
+ if (siginfo[j].si_code == si_code &&
+ siginfo[j].si_int == i)
+ continue;
+
+ err("%d: Wrong siginfo i=%d si_code=%d si_int=%d\n",
+ shared, i, siginfo[j].si_code, siginfo[j].si_int);
+ goto out;
+ }
+ }
+
+ if (i != SIGNR) {
+ err("Only %d signals were read\n", i);
+ goto out;
+ }
+
+ exit_code = 0;
+out:
+ return exit_code;
+}
+
+int main(int argc, char *argv[])
+{
+ siginfo_t siginfo[SIGNR];
+ int i, exit_code = 1;
+ sigset_t blockmask;
+ pid_t child;
+
+ sigemptyset(&blockmask);
+ sigaddset(&blockmask, SIGRTMIN);
+ sigprocmask(SIG_BLOCK, &blockmask, NULL);
+
+ child = fork();
+ if (child == -1) {
+ err("fork() failed: %m");
+ return 1;
+ } else if (child == 0) {
+ pid_t ppid = getppid();
+ while (1) {
+ if (ppid != getppid())
+ break;
+ sleep(1);
+ }
+ return 1;
+ }
+
+ /* Send signals in process-wide and per-thread queues */
+ for (i = 0; i < SIGNR; i++) {
+ siginfo->si_code = TEST_SICODE_SHARE;
+ siginfo->si_int = i;
+ sys_rt_sigqueueinfo(child, SIGRTMIN, siginfo);
+
+ siginfo->si_code = TEST_SICODE_PRIV;
+ siginfo->si_int = i;
+ sys_rt_tgsigqueueinfo(child, child, SIGRTMIN, siginfo);
+ }
+
+ if (sys_ptrace(PTRACE_ATTACH, child, NULL, NULL) == -1)
+ return 1;
+
+ waitpid(child, NULL, 0);
+
+ /* Dump signals one by one*/
+ if (check_direct_path(child, 0, 1))
+ goto out;
+ /* Dump all signals for one call */
+ if (check_direct_path(child, 0, SIGNR))
+ goto out;
+
+ /*
+ * Dump signal from the process-wide queue.
+ * The number of signals is not multible to the buffer size
+ */
+ if (check_direct_path(child, 1, 3))
+ goto out;
+
+ if (check_error_paths(child))
+ goto out;
+
+ printf("PASS\n");
+ exit_code = 0;
+out:
+ if (sys_ptrace(PTRACE_KILL, child, NULL, NULL) == -1)
+ return 1;
+
+ waitpid(child, NULL, 0);
+
+ return exit_code;
+}
diff --git a/tools/testing/selftests/soft-dirty/Makefile b/tools/testing/selftests/soft-dirty/Makefile
new file mode 100644
index 000000000000..a9cdc823d6e0
--- /dev/null
+++ b/tools/testing/selftests/soft-dirty/Makefile
@@ -0,0 +1,10 @@
+CFLAGS += -iquote../../../../include/uapi -Wall
+soft-dirty: soft-dirty.c
+
+all: soft-dirty
+
+clean:
+ rm -f soft-dirty
+
+run_tests: all
+ @./soft-dirty || echo "soft-dirty selftests: [FAIL]"
diff --git a/tools/testing/selftests/soft-dirty/soft-dirty.c b/tools/testing/selftests/soft-dirty/soft-dirty.c
new file mode 100644
index 000000000000..aba4f87f87f0
--- /dev/null
+++ b/tools/testing/selftests/soft-dirty/soft-dirty.c
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+typedef unsigned long long u64;
+
+#define PME_PRESENT (1ULL << 63)
+#define PME_SOFT_DIRTY (1Ull << 55)
+
+#define PAGES_TO_TEST 3
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+static void get_pagemap2(char *mem, u64 *map)
+{
+ int fd;
+
+ fd = open("/proc/self/pagemap2", O_RDONLY);
+ if (fd < 0) {
+ perror("Can't open pagemap2");
+ exit(1);
+ }
+
+ lseek(fd, (unsigned long)mem / PAGE_SIZE * sizeof(u64), SEEK_SET);
+ read(fd, map, sizeof(u64) * PAGES_TO_TEST);
+ close(fd);
+}
+
+static inline char map_p(u64 map)
+{
+ return map & PME_PRESENT ? 'p' : '-';
+}
+
+static inline char map_sd(u64 map)
+{
+ return map & PME_SOFT_DIRTY ? 'd' : '-';
+}
+
+static int check_pte(int step, int page, u64 *map, u64 want)
+{
+ if ((map[page] & want) != want) {
+ printf("Step %d Page %d has %c%c, want %c%c\n",
+ step, page,
+ map_p(map[page]), map_sd(map[page]),
+ map_p(want), map_sd(want));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void clear_refs(void)
+{
+ int fd;
+ char *v = "4";
+
+ fd = open("/proc/self/clear_refs", O_WRONLY);
+ if (write(fd, v, 3) < 3) {
+ perror("Can't clear soft-dirty bit");
+ exit(1);
+ }
+ close(fd);
+}
+
+int main(void)
+{
+ char *mem, x;
+ u64 map[PAGES_TO_TEST];
+
+ mem = mmap(NULL, PAGES_TO_TEST * PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0);
+
+ x = mem[0];
+ mem[2 * PAGE_SIZE] = 'c';
+ get_pagemap2(mem, map);
+
+ if (check_pte(1, 0, map, PME_PRESENT))
+ return 1;
+ if (check_pte(1, 1, map, 0))
+ return 1;
+ if (check_pte(1, 2, map, PME_PRESENT | PME_SOFT_DIRTY))
+ return 1;
+
+ clear_refs();
+ get_pagemap2(mem, map);
+
+ if (check_pte(2, 0, map, PME_PRESENT))
+ return 1;
+ if (check_pte(2, 1, map, 0))
+ return 1;
+ if (check_pte(2, 2, map, PME_PRESENT))
+ return 1;
+
+ mem[0] = 'a';
+ mem[PAGE_SIZE] = 'b';
+ x = mem[2 * PAGE_SIZE];
+ get_pagemap2(mem, map);
+
+ if (check_pte(3, 0, map, PME_PRESENT | PME_SOFT_DIRTY))
+ return 1;
+ if (check_pte(3, 1, map, PME_PRESENT | PME_SOFT_DIRTY))
+ return 1;
+ if (check_pte(3, 2, map, PME_PRESENT))
+ return 1;
+
+ (void)x; /* gcc warn */
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/tools/vm/Makefile b/tools/vm/Makefile
index 8e30e5c40f8a..24e9ddd93fa4 100644
--- a/tools/vm/Makefile
+++ b/tools/vm/Makefile
@@ -1,11 +1,22 @@
# Makefile for vm tools
+#
+TARGETS=page-types slabinfo
+
+LK_DIR = ../lib/lk
+LIBLK = $(LK_DIR)/liblk.a
CC = $(CROSS_COMPILE)gcc
-CFLAGS = -Wall -Wextra
+CFLAGS = -Wall -Wextra -I../lib/
+LDFLAGS = $(LIBLK)
+
+$(TARGETS): liblk
+
+liblk:
+ make -C $(LK_DIR)
-all: page-types slabinfo
%: %.c
- $(CC) $(CFLAGS) -o $@ $^
+ $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
clean:
$(RM) page-types slabinfo
+ make -C ../lib/lk clean
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index b76edf2f8333..71c9c2511ee7 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -36,7 +36,7 @@
#include <sys/statfs.h>
#include "../../include/uapi/linux/magic.h"
#include "../../include/uapi/linux/kernel-page-flags.h"
-
+#include <lk/debugfs.h>
#ifndef MAX_PATH
# define MAX_PATH 256
@@ -178,7 +178,7 @@ static int kpageflags_fd;
static int opt_hwpoison;
static int opt_unpoison;
-static char hwpoison_debug_fs[MAX_PATH+1];
+static char *hwpoison_debug_fs;
static int hwpoison_inject_fd;
static int hwpoison_forget_fd;
@@ -458,81 +458,6 @@ static uint64_t kpageflags_flags(uint64_t flags)
return flags;
}
-/* verify that a mountpoint is actually a debugfs instance */
-static int debugfs_valid_mountpoint(const char *debugfs)
-{
- struct statfs st_fs;
-
- if (statfs(debugfs, &st_fs) < 0)
- return -ENOENT;
- else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
- return -ENOENT;
-
- return 0;
-}
-
-/* find the path to the mounted debugfs */
-static const char *debugfs_find_mountpoint(void)
-{
- const char *const *ptr;
- char type[100];
- FILE *fp;
-
- ptr = debugfs_known_mountpoints;
- while (*ptr) {
- if (debugfs_valid_mountpoint(*ptr) == 0) {
- strcpy(hwpoison_debug_fs, *ptr);
- return hwpoison_debug_fs;
- }
- ptr++;
- }
-
- /* give up and parse /proc/mounts */
- fp = fopen("/proc/mounts", "r");
- if (fp == NULL)
- perror("Can't open /proc/mounts for read");
-
- while (fscanf(fp, "%*s %"
- STR(MAX_PATH)
- "s %99s %*s %*d %*d\n",
- hwpoison_debug_fs, type) == 2) {
- if (strcmp(type, "debugfs") == 0)
- break;
- }
- fclose(fp);
-
- if (strcmp(type, "debugfs") != 0)
- return NULL;
-
- return hwpoison_debug_fs;
-}
-
-/* mount the debugfs somewhere if it's not mounted */
-
-static void debugfs_mount(void)
-{
- const char *const *ptr;
-
- /* see if it's already mounted */
- if (debugfs_find_mountpoint())
- return;
-
- ptr = debugfs_known_mountpoints;
- while (*ptr) {
- if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) {
- /* save the mountpoint */
- strcpy(hwpoison_debug_fs, *ptr);
- break;
- }
- ptr++;
- }
-
- if (*ptr == NULL) {
- perror("mount debugfs");
- exit(EXIT_FAILURE);
- }
-}
-
/*
* page actions
*/
@@ -541,7 +466,11 @@ static void prepare_hwpoison_fd(void)
{
char buf[MAX_PATH + 1];
- debugfs_mount();
+ hwpoison_debug_fs = debugfs_mount(NULL);
+ if (!hwpoison_debug_fs) {
+ perror("mount debugfs");
+ exit(EXIT_FAILURE);
+ }
if (opt_hwpoison && !hwpoison_inject_fd) {
snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn",
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index adc68feb5c5a..f18013f09e68 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1541,21 +1541,38 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
}
int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
- gpa_t gpa)
+ gpa_t gpa, unsigned long len)
{
struct kvm_memslots *slots = kvm_memslots(kvm);
int offset = offset_in_page(gpa);
- gfn_t gfn = gpa >> PAGE_SHIFT;
+ gfn_t start_gfn = gpa >> PAGE_SHIFT;
+ gfn_t end_gfn = (gpa + len - 1) >> PAGE_SHIFT;
+ gfn_t nr_pages_needed = end_gfn - start_gfn + 1;
+ gfn_t nr_pages_avail;
ghc->gpa = gpa;
ghc->generation = slots->generation;
- ghc->memslot = gfn_to_memslot(kvm, gfn);
- ghc->hva = gfn_to_hva_many(ghc->memslot, gfn, NULL);
- if (!kvm_is_error_hva(ghc->hva))
+ ghc->len = len;
+ ghc->memslot = gfn_to_memslot(kvm, start_gfn);
+ ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, &nr_pages_avail);
+ if (!kvm_is_error_hva(ghc->hva) && nr_pages_avail >= nr_pages_needed) {
ghc->hva += offset;
- else
- return -EFAULT;
-
+ } else {
+ /*
+ * If the requested region crosses two memslots, we still
+ * verify that the entire region is valid here.
+ */
+ while (start_gfn <= end_gfn) {
+ ghc->memslot = gfn_to_memslot(kvm, start_gfn);
+ ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn,
+ &nr_pages_avail);
+ if (kvm_is_error_hva(ghc->hva))
+ return -EFAULT;
+ start_gfn += nr_pages_avail;
+ }
+ /* Use the slow path for cross page reads and writes. */
+ ghc->memslot = NULL;
+ }
return 0;
}
EXPORT_SYMBOL_GPL(kvm_gfn_to_hva_cache_init);
@@ -1566,8 +1583,13 @@ int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
struct kvm_memslots *slots = kvm_memslots(kvm);
int r;
+ BUG_ON(len > ghc->len);
+
if (slots->generation != ghc->generation)
- kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa);
+ kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len);
+
+ if (unlikely(!ghc->memslot))
+ return kvm_write_guest(kvm, ghc->gpa, data, len);
if (kvm_is_error_hva(ghc->hva))
return -EFAULT;
@@ -1587,8 +1609,13 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
struct kvm_memslots *slots = kvm_memslots(kvm);
int r;
+ BUG_ON(len > ghc->len);
+
if (slots->generation != ghc->generation)
- kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa);
+ kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len);
+
+ if (unlikely(!ghc->memslot))
+ return kvm_read_guest(kvm, ghc->gpa, data, len);
if (kvm_is_error_hva(ghc->hva))
return -EFAULT;